From 46f9e669d001624cb8b7a594bfed3a9aafb139f1 Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Sat, 3 Oct 2026 14:13:04 +0530 Subject: [PATCH 01/68] docs(agw): add SDK planning and contract review package --- plan/agw/.gitattributes | 3 + plan/agw/README.md | 30 + plan/agw/SOURCES.md | 49 + plan/agw/agw-tutorial.html | 195 ++ plan/agw/contract-integrator-obligations.md | 31 + plan/agw/current-baseline.md | 75 + plan/agw/gaps.md | 47 + plan/agw/implementation-plan.md | 49 + plan/agw/latest-refresh.json | 124 + plan/agw/notion/1-agw-contract-changes.md | 362 +++ plan/agw/notion/2-universal-marketplace.md | 90 + plan/agw/notion/3-8183-job-kernel-and-hook.md | 59 + plan/agw/notion/4-universal-evaluation.md | 86 + plan/agw/notion/5-sdk-agw.md | 732 ++++++ .../agw/notion/6-sdk-universal-marketplace.md | 146 ++ plan/agw/notion/7-sdk-8183-job.md | 120 + plan/agw/notion/8-sdk-universal-evaluation.md | 127 + .../notion/agentic-wallet-flow-2026-09-07.md | 362 +++ .../agw-address-book-donut-2026-09-04.md | 30 + .../20261003T075310278902Z/export-1.zip | Bin 0 -> 50254 bytes .../20261003T075310278902Z/export-2.zip | Bin 0 -> 26729 bytes .../20261003T075310278902Z/export-3.zip | Bin 0 -> 1105 bytes .../20261003T075310278902Z/export-4.zip | Bin 0 -> 9356 bytes .../1-agw-contract-changes.diff | 82 + .../1-agw-contract-changes.md | 289 +++ .../20261003T075310278902Z/5-sdk-agw.diff | 106 + .../20261003T075310278902Z/5-sdk-agw.md | 730 ++++++ .../manifest-before.json | 176 ++ .../20261003T075310278902Z/refresh.json | 124 + plan/agw/notion/legacy-agw-sdk-v1.md | 1097 +++++++++ plan/agw/notion/overview.md | 153 ++ plan/agw/questions-harsh.md | 43 + plan/agw/questions-zaryab.md | 37 + plan/agw/research/donut-probe-2026-10-02.json | 33 + .../agw/research/notion-refresh-2026-10-03.md | 34 + .../agw/research/validation-e704d5b/README.md | 34 + .../research/validation-e704d5b/abi/AGW.json | 1550 +++++++++++++ .../validation-e704d5b/abi/AGWFactory.json | 1105 +++++++++ .../abi/AgentValidator.json | 141 ++ .../validation-e704d5b/abi/SmartSession.json | 1957 ++++++++++++++++ .../abi/UniversalRulesPolicy.json | 2066 +++++++++++++++++ .../agw/research/validation-e704d5b/build.log | 1656 +++++++++++++ .../validation-e704d5b/check-execute.log | 2 + .../validation-e704d5b/evidence-manifest.json | 17 + .../validation-e704d5b/offline-results.json | 10 + .../review-tests-offline.log | 13 + .../review-tests/IndependentReviewHead.t.sol | 261 +++ .../validation-e704d5b/tests-offline.log | 677 ++++++ plan/agw/review-summary.md | 30 + plan/agw/scripts/import-notion-exports.py | 121 + plan/agw/sdk-design-review.md | 106 + plan/agw/source-manifest.json | 178 ++ plan/agw/source-status-2026-10-03.json | 14 + 53 files changed, 15559 insertions(+) create mode 100644 plan/agw/.gitattributes create mode 100644 plan/agw/README.md create mode 100644 plan/agw/SOURCES.md create mode 100644 plan/agw/agw-tutorial.html create mode 100644 plan/agw/contract-integrator-obligations.md create mode 100644 plan/agw/current-baseline.md create mode 100644 plan/agw/gaps.md create mode 100644 plan/agw/implementation-plan.md create mode 100644 plan/agw/latest-refresh.json create mode 100644 plan/agw/notion/1-agw-contract-changes.md create mode 100644 plan/agw/notion/2-universal-marketplace.md create mode 100644 plan/agw/notion/3-8183-job-kernel-and-hook.md create mode 100644 plan/agw/notion/4-universal-evaluation.md create mode 100644 plan/agw/notion/5-sdk-agw.md create mode 100644 plan/agw/notion/6-sdk-universal-marketplace.md create mode 100644 plan/agw/notion/7-sdk-8183-job.md create mode 100644 plan/agw/notion/8-sdk-universal-evaluation.md create mode 100644 plan/agw/notion/agentic-wallet-flow-2026-09-07.md create mode 100644 plan/agw/notion/agw-address-book-donut-2026-09-04.md create mode 100644 plan/agw/notion/exports/20261003T075310278902Z/export-1.zip create mode 100644 plan/agw/notion/exports/20261003T075310278902Z/export-2.zip create mode 100644 plan/agw/notion/exports/20261003T075310278902Z/export-3.zip create mode 100644 plan/agw/notion/exports/20261003T075310278902Z/export-4.zip create mode 100644 plan/agw/notion/history/20261003T075310278902Z/1-agw-contract-changes.diff create mode 100644 plan/agw/notion/history/20261003T075310278902Z/1-agw-contract-changes.md create mode 100644 plan/agw/notion/history/20261003T075310278902Z/5-sdk-agw.diff create mode 100644 plan/agw/notion/history/20261003T075310278902Z/5-sdk-agw.md create mode 100644 plan/agw/notion/history/20261003T075310278902Z/manifest-before.json create mode 100644 plan/agw/notion/history/20261003T075310278902Z/refresh.json create mode 100644 plan/agw/notion/legacy-agw-sdk-v1.md create mode 100644 plan/agw/notion/overview.md create mode 100644 plan/agw/questions-harsh.md create mode 100644 plan/agw/questions-zaryab.md create mode 100644 plan/agw/research/donut-probe-2026-10-02.json create mode 100644 plan/agw/research/notion-refresh-2026-10-03.md create mode 100644 plan/agw/research/validation-e704d5b/README.md create mode 100644 plan/agw/research/validation-e704d5b/abi/AGW.json create mode 100644 plan/agw/research/validation-e704d5b/abi/AGWFactory.json create mode 100644 plan/agw/research/validation-e704d5b/abi/AgentValidator.json create mode 100644 plan/agw/research/validation-e704d5b/abi/SmartSession.json create mode 100644 plan/agw/research/validation-e704d5b/abi/UniversalRulesPolicy.json create mode 100644 plan/agw/research/validation-e704d5b/build.log create mode 100644 plan/agw/research/validation-e704d5b/check-execute.log create mode 100644 plan/agw/research/validation-e704d5b/evidence-manifest.json create mode 100644 plan/agw/research/validation-e704d5b/offline-results.json create mode 100644 plan/agw/research/validation-e704d5b/review-tests-offline.log create mode 100644 plan/agw/research/validation-e704d5b/review-tests/IndependentReviewHead.t.sol create mode 100644 plan/agw/research/validation-e704d5b/tests-offline.log create mode 100644 plan/agw/review-summary.md create mode 100644 plan/agw/scripts/import-notion-exports.py create mode 100644 plan/agw/sdk-design-review.md create mode 100644 plan/agw/source-manifest.json create mode 100644 plan/agw/source-status-2026-10-03.json diff --git a/plan/agw/.gitattributes b/plan/agw/.gitattributes new file mode 100644 index 00000000..e55dec4d --- /dev/null +++ b/plan/agw/.gitattributes @@ -0,0 +1,3 @@ +# Preserve native exports and raw tool output, including original whitespace. +notion/** -whitespace +research/validation-e704d5b/*.log -whitespace diff --git a/plan/agw/README.md b/plan/agw/README.md new file mode 100644 index 00000000..1bf2c602 --- /dev/null +++ b/plan/agw/README.md @@ -0,0 +1,30 @@ +# AGW SDK planning + +This package contains the current SDK plan, source snapshots, open decisions and contract validation evidence. Production implementation has not started. Question drafts are unsent. + +The target API is [Notion page 5](notion/5-sdk-agw.md), exported October 3, 2026 at 13:23 IST. The tested contract baseline is pushAgenticWallet_v3@e704d5b: sender-authorized execution and checkpoints exist in source, while the new multi-asset format, grant reference, editable label and envelope version still require matching artifacts and deployment verification. + +## Start here + +| Document | Purpose | +| --- | --- | +| [Current baseline](current-baseline.md) | Source revisions, capabilities and remaining differences | +| [SDK design review](sdk-design-review.md) | Proposed internal architecture and execution flows | +| [Gap register](gaps.md) | Current G01–G24 findings and closure criteria | +| [Implementation plan](implementation-plan.md) | Work order and acceptance gates | +| [Interactive tutorial](agw-tutorial.html) | Account, rule, funding and execution diagrams; open in a browser | +| [Integrator obligations](contract-integrator-obligations.md) | Contract-delegated SDK/product requirements | +| [Questions for Harsh](questions-harsh.md) | Product decisions and recommendations | +| [Questions for Zaryab](questions-zaryab.md) | Contract surface, funding and deployment questions | +| [Review summary](review-summary.md) | Consequential independent-review corrections | + +## Sources and evidence + +- [Notion links and refresh instructions](SOURCES.md); [source manifest](source-manifest.json). +- Latest copies of all 12 registered pages under notion/. September references are labeled historical in the index. +- [October 3 refresh report](research/notion-refresh-2026-10-03.md): pages 1 and 5 changed; ten are unchanged. Latest raw exports and changed-page diffs are retained. +- [e704d5b validation](research/validation-e704d5b/README.md): build and revised source pin pass; 563 passed, 0 failed, 6 skipped, plus seven passing review tests. Generated ABIs describe that tested revision, not the new multi-asset target. + +Older planning revisions, duplicated exports, superseded validation runs and the full independent-review working package were archived locally outside this repository. The review summary preserves the key corrections. Historical paths in the retained prior manifest describe the earlier pull and may refer to pruned archives. + +Before sharing questions, refresh remote refs and Notion again, record exact revisions and remove questions answered by newer evidence. No messages, deployments or testnet transactions have been sent by this planning work. diff --git a/plan/agw/SOURCES.md b/plan/agw/SOURCES.md new file mode 100644 index 00000000..112f9473 --- /dev/null +++ b/plan/agw/SOURCES.md @@ -0,0 +1,49 @@ +# AGW source links and refresh procedure + +Latest complete Notion export: October 3, 2026 at 13:23 IST. All 12 pages were imported; pages 1 and 5 changed. Page 5 defines the target public SDK API. Native exports omit comment threads. + +## Notion inventory + +| Document | Source | Local snapshot | Authority | +| --- | --- | --- | --- | +| AGW design overview | [Notion](https://app.notion.com/p/pushprotocol/AGW-UniversalMarketplace-8183-UniversalEvaluator-3e9188aea7f481c8b38ccba332b0afa2) | [Snapshot](notion/overview.md) | Supporting design | +| 1 AGW Contract Changes | [Notion](https://app.notion.com/p/pushprotocol/1-AGW-Contract-Changes-nomenclature-standard-change-set-3e9188aea7f4813aa31fc95ceb4e684d) | [Snapshot](notion/1-agw-contract-changes.md) | WIP contract target | +| 2 Universal Marketplace | [Notion](https://app.notion.com/p/pushprotocol/2-Universal-Marketplace-3e9188aea7f48118b90ac9b267496295) | [Snapshot](notion/2-universal-marketplace.md) | Supporting WIP design | +| 3 ERC-8183 job kernel and hook | [Notion](https://app.notion.com/p/pushprotocol/3-8183-job-kernel-and-hook-3e9188aea7f48188a838c3a740d8c858) | [Snapshot](notion/3-8183-job-kernel-and-hook.md) | Supporting WIP design | +| 4 Universal Evaluation | [Notion](https://app.notion.com/p/pushprotocol/4-Universal-Evaluation-3e9188aea7f4817bb03ef4c78c883f8b) | [Snapshot](notion/4-universal-evaluation.md) | Supporting WIP design | +| 5 SDK AGW | [Notion](https://app.notion.com/p/pushprotocol/5-SDK-AGW-3e9188aea7f481cf8e8de324956549b9) | [Snapshot](notion/5-sdk-agw.md) | Primary SDK API target | +| 6 SDK Universal Marketplace | [Notion](https://app.notion.com/p/pushprotocol/6-SDK-Universal-Marketplace-3ea188aea7f481e2961ed97129f3a4e6) | [Snapshot](notion/6-sdk-universal-marketplace.md) | Supporting WIP SDK | +| 7 SDK ERC-8183 Job | [Notion](https://app.notion.com/p/pushprotocol/7-SDK-8183-Job-3ea188aea7f481e0a137f5a896723376) | [Snapshot](notion/7-sdk-8183-job.md) | Supporting WIP SDK | +| 8 SDK Universal Evaluation | [Notion](https://app.notion.com/p/pushprotocol/8-SDK-Universal-Evaluation-3ea188aea7f48197a3b3cfdedfa74fee) | [Snapshot](notion/8-sdk-universal-evaluation.md) | Supporting WIP SDK | +| Legacy PUSH AGW SDK Doc v1 | [Notion](https://app.notion.com/p/pushprotocol/PUSH-AGW-SDK-Doc-v1-d2d188aea7f4825cbcea81ef86eca607) | [Snapshot](notion/legacy-agw-sdk-v1.md) | Historical encoding and deployment reference | +| AGW Address Book PC Donut | [Notion](https://app.notion.com/p/pushprotocol/AGW-Address-Book-PC-Donut-3d1188aea7f480ddbb4af6d0efb211e6) | [Snapshot](notion/agw-address-book-donut-2026-09-04.md) | Historical deployment | +| Agentic wallet flow updated | [Notion](https://app.notion.com/p/pushprotocol/agentic_wallet_flow-updated-3d1188aea7f4801f9cb3fbd9318ec536) | [Snapshot](notion/agentic-wallet-flow-2026-09-07.md) | Historical validator-based flow | + +The [manifest](source-manifest.json) stores stable page IDs, pull times and hashes. Latest raw ZIPs are under the timestamped notion/exports folder referenced by the manifest. The latest comparison, previous changed-page bodies and diffs are retained under notion/history. Older duplicate pulls were archived locally; paths inside manifest-before.json are historical metadata and may point to pruned archives. + +## Contract sources + +- [AGW e704d5b](https://github.com/pushchain/push-agentic-wallets/tree/e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9), branch pushAgenticWallet_v3. nomenclature-changes was merged and deleted. +- [AGW design](https://github.com/pushchain/push-agentic-wallets/blob/e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9/docs/1_AGW.md) and [policy design](https://github.com/pushchain/push-agentic-wallets/blob/e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9/docs/2_UniversalRulesPolicy.md). +- [Core marketplace cb69e0b](https://github.com/pushchain/push-chain-core-contracts/tree/cb69e0ba101bef1bb4440e54b2c45396be3e92ce). +- [Gateway eight-field baseline bcbf7df](https://github.com/pushchain/push-chain-gateway-contracts/tree/bcbf7df42e8e6dd11088a43bcc0b056a54ea0a18). +- [Historical deployed AGW 67929f2](https://github.com/pushchain/push-agentic-wallets/tree/67929f208886187ec7bab5479d4036d45394cfb1). + +Source revisions describe inspected code, not a guarantee of current remote head or live deployment. Recheck before sharing questions. See [current baseline](current-baseline.md) and [review summary](review-summary.md). + +## Repeatable refresh + +1. Export the overview as Markdown and CSV with Include subpages enabled. Export the three historical references individually. +2. Supply all four downloaded ZIPs to the importer. Use --dry-run first to inspect the comparison. +3. Match pages by stable ID; retain raw exports, previous changed snapshots, diffs and manifest history. +4. Review changed requirements and update affected plans/questions; do not declare source features deployed without evidence. +5. Re-fetch contract refs and record exact SHAs before sharing. + +```sh +python3 plan/agw/scripts/import-notion-exports.py overview.zip legacy-sdk.zip address-book.zip flow.zip --dry-run +python3 plan/agw/scripts/import-notion-exports.py overview.zip legacy-sdk.zip address-book.zip flow.zip +``` + +Use actual ZIP paths. The script does not download or authenticate to Notion. It rejects conflicting inputs or locally edited snapshots, requires all registered pages unless --partial is explicitly used, and reports unexpected page IDs. Last-edited observations are not inferred from download time. No scheduled refresh is configured. + +The historical SDK refers to AGW-SDK-v1-agent.md, 05-universal-marketplace-startjob.md and SDK_HELPER.md. Their source URLs/files were not included in its export; those original unresolved references remain as written. diff --git a/plan/agw/agw-tutorial.html b/plan/agw/agw-tutorial.html new file mode 100644 index 00000000..88bb9693 --- /dev/null +++ b/plan/agw/agw-tutorial.html @@ -0,0 +1,195 @@ + + + + + +How an Agentic Wallet works · Push Chain + + + +
+
Push Chain · AGW learning guide
+

How an Agentic Wallet works

+

Revision note: D3 sender authorization and stored checkpoints are implemented in source at pushAgenticWallet_v3@e704d5b. The documented Donut deployment is older. Editable labels, grant references, versioned envelopes and the new multi-asset terms remain target features. create no longer includes funding. Current baseline and corrections.

+

The owner funds a wallet and sets rules. An agent acts through that wallet. The contracts enforce what the agent can do, while the owner retains control.

+
Target SDK designContracts and integration are WIPReview · 3 October 2026
+ +
+
+
+
01 · Start with ownership

Three accounts, one control chain

+

An external owner, such as an Ethereum or Solana user, controls a Universal Executor Account (UEA) on Push. That account owns the AGW. When the AGW acts on another chain, its Chain Executor Account (CEA) performs the destination call. A native Push owner uses its EOA directly.

+
+
Identity on Push
Owner EOA or UEA

Creates the wallet, funds it separately and manages its rules.

+
owns
+
Wallet on Push
AGW

Holds assets and originates wallet actions. SmartSession and URP store the rules and policy state.

+
via gateway
+
Account on the destination
AGW’s CEA

Receives bridged assets and executes calls for this wallet.

+
+
+

The agent has its own identity

A native Push agent is an EOA. An agent with a key on another chain is represented by that key’s UEA on Push. Each rule names this Push address as its agent.

+

The destination account belongs to the AGW

The gateway sees the AGW as its caller and derives the AGW’s CEA. Keeping this identity intact is how the wallet holds the resulting destination position.

+
+
The same EVM key initialized against two different origin chains produces two different UEAs. Grant the rule to the UEA for the chain the agent will actually use.
+
+
+
02 · Follow the SDK flow

From wallet creation to a receipt

+

Step through the target flow. Switch between the owner and agent to see where authorization changes. These controls illustrate the design locally; they do not connect to a wallet or send transactions.

+
+
+
+
+
+ +
+
+

Derive the wallet before deploying it

STEP 01 / 06
+

The owner asks the SDK for the next wallet address. Within a fixed factory and implementation generation, owner and index determine the address.

+
+
+
+ +
+ + +
+
+
03 · Keep the balances straight

The agent and the wallet pay for different things

+
+

Signer’s PC balance

Pays for the transaction that invokes the AGW on Push. An external agent uses its UEA’s PC balance.

For an external agent’s first action, deployment and funding of an undeployed UEA can use an origin-chain fee lock. Later actions require PC in that deployed UEA, as specified by agentic-mode gas checks.

+

AGW’s assets and PC balance

PRC20 tokens are the wallet’s working funds. Its PC covers wallet-originated outbound fees and any applicable native value sent by the wallet.

PC in the AGW does not pay the separate transaction gas of the agent’s EOA or UEA. Rules cap PC per action, not over the rule lifetime. Repeated zero-amount actions can consume the funded PC balance without consuming token spend.

+
+
    +
  1. Owner funds the AGW

    For an external owner, assets can enter Push through the existing gateway and UEA flow before being transferred to the wallet.

  2. +
  3. Owner establishes gateway allowance

    The gateway pulls PRC20 from the AGW. An owner-authorized approval is needed before positive-amount outbound execution; the agent’s universal rule does not authorize Push-side approvals.

  4. +
  5. Agent invokes the wallet

    The agent’s Push identity pays invocation gas. URP checks the requested action against the selected rule.

  6. +
  7. AGW sends outbound

    For a cross-chain action, the AGW calls the gateway with its assets and PC. The destination CEA belongs to the AGW.

  8. +
  9. Destination CEA performs the work

    A protocol call executes from the CEA. Beneficiary checks constrain configured calldata arguments; they do not prove the protocol’s resulting outputs or asset movement.

  10. +
+
+
+
04 · Understand the two execution paths

Owner control and agent permission

+
+ + + + + +
QuestionOwnerAgent
Wallet entry pointexecuteexecuteAsAgent
Who is authorized?The wallet’s ownerThe Push address named by the rule
Are rules checked?Owner execution bypasses policyURP checks every call on-chain
What does the SDK select?The owner execution pathAn enabled rule for this agent and destination, on every send
What is recorded?Owner action checkpoints (implemented in current source)Rule authorization and relevant spending counters
+
+

A rule says what is allowed

Each rule names an agent, a destination and an expiry. Native rules constrain a target and selector; universal rules define an asset list with per-token caps, a per-outbound PC ceiling (maxGasPerCall) and allowed destination calls.

The target SDK rejects duplicate rules for an agent and chain; the contract itself can grant multiple active rules for the same pair. Lookup must handle that ambiguity explicitly. Rules for Push omit chainNamespace; external rules supply it.

+

Changing a rule creates a new rule

rules.update asserts the old spend, revokes the old rule and grants its replacement atomically. The new rule receives a new ID and fresh counters. A successful owner replacement batch adds five checkpoints. Evaluators compare snapshot counts, not only block numbers.

Revocation stops future authorization on Push. An outbound already dispatched may still complete on its destination.

+
+
Approval safety: a universal rule that allows destination approve(address,uint256) without a spender constraint can expose existing CEA balances. The newer marketplace rejects this configuration; use an agreed owner-controlled approval flow. The headline Notion example needs correction.
+
A destination failure does not currently have a guaranteed spend-credit path in the reviewed contract documents. Treat refunding funds, restoring spending allowance and paying gas as separate outcomes. See G07 in the gap register.
+
+
+
05 · Use the two SDK surfaces

Manage a wallet, or act through it

+

These examples show the planned API. Application signers, chain constants, rule definitions, token values and transaction calldata must be supplied by the application.

+
+

Manage as the owner

const owner = await PushChain.initialize(
+  ownerSigner, { network }
+);
+
+const { wallet, rulesIds } =
+  await owner.agentic.create('lending', {
+    rules: [ruleOnSepolia],
+  });
+
+// Fund tokens and PC separately with normal account tooling.
+// Establish required owner gateway allowances separately.
+const w = owner.agentic.wallet(wallet);
+const info = await w.info();
+const { rules } = await w.rules.list();
+

Send as the agent

const agent = await PushChain.initialize(
+  agentSigner,
+  { network, agenticWallet: wallet }
+);
+
+const tx = await agent.universal.sendTransaction({
+  to: { address: pool, chain: CHAIN.ETHEREUM_SEPOLIA },
+  data: supplyData,
+});
+
+const receipt = await tx.wait();
+// SDK from: AGW
+// SDK origin: agent's origin account
+
+
To execute as the owner, initialize with ownerSigner and the same agenticWallet option. The signer determines the execution path. The wallet handle itself is for management.
+

Agentic mode rejects any transaction from. The spec also disables payGasWith, migrateCEA, rescueFunds, prepareTransaction and executeTransactions in this mode.

+
+
+
06 · Where the other pieces fit

An AGW can work alone or participate in a job

+

The broader design adds discovery, escrow and evaluation around the wallet. These are separate namespaces and WIP components.

+
+
01 · client.market

Choose a card

A card describes the agent’s service, required access, fee and promised outcome. Compilation produces wallet rules and evaluation criteria.

+
02 · client.agentic

Authorize work

The owner creates or selects a wallet, funds it and grants rules. The agent executes within those rules.

+
03 · client.job

Bind and fund

The AGW is the job client. The job hook binds rules to a provider; the job kernel holds the fee in escrow.

+
04 · client.evaluation

Verify and settle

START reads establish a baseline. After work is submitted, END reads and criteria determine completion or rejection.

+
+

The intended lifecycle is select card → create and fund wallet/job → record baseline → agent works → submit → evaluate → settle. A passing evaluation pays the provider; rejection returns the fee to the client. Expiry provides a refund path under the job kernel’s conditions.

+
The design gives checkpoints a settlement consequence: an owner-side change after the baseline can cause the provider to be paid without END reads. Label changes are cosmetic and are excluded. The hook and evaluator implementation must match this rule. Checkpoints observe owner calls, not every balance change: pulling a pre-existing allowance can change balances without a new checkpoint.
+
+
+
07 · Before implementation

Follow the SDK spec and make the dependencies explicit

+

The target API is agreed. The contract and SDK gap register records the work needed to connect it to a compatible deployment.

+
    +
  • Contract entry and encoding: sender-gated execution, rule IDs, envelope encoding and compatible gateway versions need matched artifacts.
  • +
  • Atomicity: rule replacement must not inherit a non-atomic native fallback.
  • +
  • Shared definitions: rule expiry, job bindings and card identity need consistent definitions across SDK and contracts.
  • +
  • Compatibility: existing clients, Web2 reads, gas checks and transaction tracking need regression coverage.
  • +
+ +

Source priority: page 5 defines the target SDK behavior; source/spec conflicts are recorded for resolution, not silently overridden. September 4–22 documents describe historical UCEP/URP deployments and the earlier signature-key validation flow. The current engine retains a sender-checking adapter rather than validating an agent’s cryptographic session signature. The saved source index keeps these revisions distinct.

+
+
+ + + + diff --git a/plan/agw/contract-integrator-obligations.md b/plan/agw/contract-integrator-obligations.md new file mode 100644 index 00000000..999124ea --- /dev/null +++ b/plan/agw/contract-integrator-obligations.md @@ -0,0 +1,31 @@ +# Contract-delegated SDK and product obligations + +Source: [AGW design chapter 10 at 0f279ca](https://github.com/pushchain/push-agentic-wallets/blob/0f279ca02242dfd8067ff716d24cad4b97bf29cb/docs/1_AGW.md#10--what-the-product-must-do-that-the-contracts-cannot). These requirements complement the public SDK spec. UI obligations need SDK metadata and examples even when the SDK itself owns no grant screen. + +| Source item | Required SDK/product acceptance work | +| --- | --- | +| 1 | Generate beneficiary positions from ABI information; reject layouts the encoder cannot represent safely. | +| 2 | For each supported protocol, test wrong beneficiary and oversized amount rejection. | +| 3 | Derive and display the wallet's destination account and deployment status. | +| 4 | Display expiry as prominently as the caps. | +| 5 | Expose destination idle balance so permission previews include existing exposure. | +| 6 | Render unlimited sentinels as unlimited, not huge numeric values. | +| 7 | Show old consumption before replacement. | +| 8 | Do not silently subtract prior spend from the user's replacement cap. | +| 9 | Explain that revocation cannot recall already-dispatched outbounds. | +| 10 | Document agent-address rotation, regrant and counter-reset consequences. | +| 11 | Expose the agent's separate PC gas balance and funding requirement. | +| 12 | Explain and support migration of balances across every destination when changing wallet generations. | +| 13 | Provide data for monitoring committed CEA versus current derivation; define the operational owner. | +| 14 | Show derived destination accounts during creation. Derivation is deployment-specific. | +| 15 | Show wallet PC funding and per-action ceiling; repeated zero-amount actions can spend the PC budget without consuming token spend. Any action-count estimate must state its assumptions. | +| 16 | Generate native argument pins and reject known approval functions with unpinned spenders. | +| 17 | Preserve exact asset-reported chain strings; use connected Push chain identity for native rules. | +| 18 | Preview native actions, pins, value/amount/call limits; explain that any successful call consumes call count. | +| 19 | Compile SVM rules from the program interface, preserve interface hash, pin all relevant accounts/data, and reject unrepresentable layouts; revalidate after upgrades. | +| 20 | Restrict aggregator instruction variants and test substituted downstream programs. | +| 21 | Model SVM swap ratio floors, slippage, zero fees and regrant cadence. | +| 22 | Derive SVM CEA/token accounts from wallet and trusted registry gateway; no pasted gateway identity. | +| 23 | Arrange output token accounts before execution; constrain any permitted ATA creation to exact owner/mint/layout. | + +Items 19–23 apply when SVM destinations are enabled. They are not automatically deferred merely because the first SDK implementation may focus on EVM. Destination approval safety also needs the public decision described in the revised Harsh draft; native pinning rules alone do not solve universal approval hazards. diff --git a/plan/agw/current-baseline.md b/plan/agw/current-baseline.md new file mode 100644 index 00000000..f1ae5818 --- /dev/null +++ b/plan/agw/current-baseline.md @@ -0,0 +1,75 @@ +# Current validated AGW baseline + +Updated October 3, 2026 after reviewing checkpoint commit 6b7dbf4 and current head e704d5b. This page supersedes earlier recommendations; consequential corrections are retained in the [review summary](review-summary.md). The SDK Notion page remains the target API; conflicts below are recorded for resolution, not silently resolved in favor of code. + +## Pinned sources + +| Repository | Current inspected branch and commit | +| --- | --- | +| AGW | `pushAgenticWallet_v3@e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9` | +| Core | `universalMarketplace_v1@cb69e0ba101bef1bb4440e54b2c45396be3e92ce` | +| Gateway | Eight-field `pc20-3rd-iteration@bcbf7df42e8e6dd11088a43bcc0b056a54ea0a18`; six-field older `main@d02070d` | +| SDK | `167fdc6243ecfe5d97735a6124662c7d2084d126` | +| Notion | October 03, 2026 at 13:23 IST full export; page 1 and page 5 changed, 10 pages unchanged | + +AGW remote branches were checked through GitHub API on October 3: nomenclature-changes was deleted after merging and pushAgenticWallet_v3 points to e704d5b. Core remains pinned at cb69e0b from the existing evidence; no fresh core fetch was performed in this pass. The head adapter keeps the SmartSession source unchanged. It replaces cryptographic session-key validation with a sender-checking adapter. The wallet binds the sender before calling the engine and constructs `USE || rulesId || msg.sender` itself. Engine account binding and disabled alternate paths are essential invariants. **No engine fork is recommended.** + +## Compatibility status + +| Surface | Current status | Remaining work | +| --- | --- | --- | +| `executeAsAgent`, `agentOf`, authorization event | Implemented in AGW source | Verify selected new deployment and preserve adapter invariants; G02 source dependency satisfied | +| Agent config | Exact `abi.encode(address agent)` | SDK codec and generation-specific validator context | +| Rule ID | `keccak256(abi.encode(validator, abi.encode(agent), bytes32(grantNonce)))` | Page 5 helper signature/constants need alignment. Chain is not hashed; key records by wallet plus rule ID | +| Owner batching | Documented design; local tests support atomic replacement | SDK implementation and final-generation regression tests; no need to ask whether batching is intended | +| Agent arrays | Wallet dispatch remains single/default. EVM destination multicall supports 1–10 calls | Define native arrays separately; supporting multiple native actions in a rule is a public type choice, not the same as atomic multi-call dispatch | +| Duplicate agent-chain rules | Accepted by contract with independent IDs/budgets | SDK preflight rejection and explicit ambiguity error are proposed; hard on-chain uniqueness is not assumed necessary | +| Checkpoints | Implemented in source at 6b7dbf4, included in e704d5b; count and last-block views plus Checkpointed event | Compare snapshot counts, account for per-call and lifecycle ticks, and verify selected new deployment | +| Grant job ref, labels, envelope version | Still absent | Agree next-generation surface and spec consequences | +| Historical rules | Revoke removes agent config and enabled actions, while URP terms persist | Event agent attribution or nested-call reconstruction needed if revoked rules are returned | +| expectedCEA | Required universal wire term, derived from AGW plus destination context and committed at grant | SDK must derive it, show it in previews, include it in encodeRules context, and monitor derivation drift | +| Binder | Never present in reviewed code; live Notion page checked October 3 says dropped for v1 | No binder/setBinder implementation required unless a new explicit product decision reverses this | +| Funding approval | Push gateway requires allowance for PRC20 pulls | Explicit owner setup approval, bounded recovery/update semantics, real pulling/burning test | +| Destination approvals | Page 5 example permits an unpinned spender; current marketplace rejects approve/increaseAllowance | Product policy and owner-controlled approvals; selector filtering alone is not a general guarantee against malicious/custom approval methods | +| Gateway shape | Eight fields in current branch and observed live dispatcher; main's six fields are older | Ask only whether a future removal is actually planned | +| Agent outbound composer | Existing Route 2 request cannot be used unchanged | Empty recipient, AGW revert recipient, nonzero maxPCForGas, policy-compatible multicall and AGW PC accounting | +| Outbound tracking | Existing tracker uses tx hash/events/UTX ID | Reuse provisionally; verify live wrapped outbound. Response `from` and progress route integration still need adaptation | +| Marketplace expiry | Core terms require exact equality with job expiry | Reconcile Notion's <= and >= statements; equality applies to this marketplace compile path, not every standalone AGW rule | +| SVM destination | Source and policy tests available | Typed SDK representation, obligations 19–23, deployment capability; do not claim an agreed deferral | +| Generation detection | Wallet clones immutable; factory implementation frozen by intended design | New generation/address context, supported factory registry, version identification and migration disclosures | + +## Chain observations + +Historical read-only probes on October 2 at Donut block **23818643** confirmed the documented factory still points to `0xD7FEF338572f96edBeF89E720f1F0fF1284ec79C`, that implementation reports `push.agentwallet.1.0.0`, and the documented URP reports `1.0.0`. Gateway implementation `0x1e412939780f2b834dc42c7ac58d9f99888da659` contains the eight-field PUSH4 selector and not the six-field selector. See [probe](research/donut-probe-2026-10-02.json). + +These observations validate the named historical deployment, not a global claim that nobody has deployed head elsewhere. No matching new-generation deployment manifest is available. A PUSH4 scan supports dispatch identification but is not complete ABI verification. + +## SDK-owned decisions + +Implement existing namespace structure, signer reuse, receipt identity adaptation, typed failure metadata, Web2 compatibility, generation guards and internal read reconstruction in the SDK. Document the chosen list/read-only/reinitialize behavior in an SDK decision record. Product consultation is needed only when that choice changes an explicit public promise or introduces a new public parameter. + +Do not silently change per-send lookup to filter expired rules: page 5 says lookup selects enabled agent/chain rules and leaves policy checks on-chain. Any expiry precheck is a behavior change to document. A JSON-RPC batch is not necessarily one logical read: IDs must be enumerated before their agent/config reads can be constructed. Avoid promising a single round trip without an index or contract view. + +Retries for stale spend must be bounded and must not repeat wallet signatures without user-visible control. Revoking first is an available alternative with different atomicity and permission-interruption semantics, not a transparent retry. + +## Next live acceptance test + +After a compatible deployment and authorized test funding are available, send a positive-amount EVM agent outbound with owner-established gateway allowance, empty recipient, AGW refund recipient and a policy-compliant multicall. Verify real burn, node/TSS handling, destination execution, receipt identity and unchanged hash-based tracking. No such transaction has been broadcast by this review. + +## Checkpoint revision and current source freshness + +The no-persistent-storage invariant was deliberately revised: owner execution may touch the single packed checkpoint slot, while remaining independent of engine/policy health. `check-execute` now pins the B2 checkpoint revision. A grant starts one tick; every owner call ticks before dispatch; each revoked ID ticks once; successful grants tick once. `executeWithSig` has the same per-call behavior. Failed transactions unwind the ticks; agent execution does not tick. + +For assert/revoke/grant inside one owner batch, the delta is five: OWNER_ACTION(assert), OWNER_ACTION(revoke), RULES_REVOKED, OWNER_ACTION(grant), RULES_GRANTED. Checkpoint ref is a call hash or rulesId; it is not the missing job/card ref parameter on grant. + +The new accepted limit 34 states that pre-existing allowances can be pulled without a wallet call/checkpoint. Checkpoints detect owner-door activity, not every possible balance change. The evaluator must define how allowance-driven changes affect its verdict. A baseline count and correct funding-call ordering are required; a sinceBlock filter alone cannot detect all same-block changes. + +Fresh Notion page 1 was inspected on October 3 and still says binder was dropped for v1. The complete export succeeded. All 12 saved page bodies now reflect the October 3 export. Pages 1 and 5 changed; see the refresh report. Binder is recorded as dropped in the source index and review summary. + +## Latest SDK target after successful refresh + +Page 5 is still authoritative: create deploys/grants only, funding is separate, UniversalRule uses assets[] and maxGasPerCall, and AGENTIC-TX-103 is removed. New page 1 section 4c proposes per-token accounting and 0–8 assets. The tested e704d5b ABI does not implement that new wire format; retain its single-asset fixtures as historical baseline, not the future codec. + +Define per-asset Spent and replacement assertion semantics, empty-asset routing, destination-token/native-marker resolution and the proposed bytes32 expectedCEA encoding. The prior universal defaults/maxAmountTotal naming cannot simply carry forward. Proposed AssetCap.maxTotal zero means unlimited; native defaults remain a separate question. + +See [successful refresh report](research/notion-refresh-2026-10-03.md). All earlier download failures remain historical evidence; download permission was sufficient for this run. diff --git a/plan/agw/gaps.md b/plan/agw/gaps.md new file mode 100644 index 00000000..afe8eba5 --- /dev/null +++ b/plan/agw/gaps.md @@ -0,0 +1,47 @@ +# AGW contract and SDK gap register + +Current source: pushAgenticWallet_v3@e704d5b; target API: October 3 Notion export. [Baseline](current-baseline.md), [review summary](review-summary.md) and [integrator obligations](contract-integrator-obligations.md) provide context. The IDs track remaining integration work, not 24 missing contract features. + +P0 blocks safe integration or agreed authorization/accounting semantics. P1 affects correctness, compatibility or downstream delivery. P2 covers optional capability or documentation. D3 and checkpoints are implemented in source; live generation verification is outstanding. + +## Current findings + +| ID | Priority | Kind | Finding | Closure criterion | +| --- | --- | --- | --- | --- | +| G01 | P1 deployment dependency | Source/build evidence available | Current advertised branch is pushAgenticWallet_v3@e704d5b. Build, revised source pin, 563/0/6 suite and 7/0 review tests are reproduced. D3 and checkpoints exist in source. | Obtain and verify the selected generation deployment; keep remaining spec/ABI differences explicit. | +| G02 | P0 deployment dependency | Implemented in source | D3 landed in `0f279ca`: executeAsAgent, agentOf and sender adapter are present; engine unchanged. Prior engine-extension recommendation withdrawn. | Verify compatible deployment and retain sender-binding/alternate-path regression coverage. | +| G03 | P1 | Spec/code mismatch | Head ID formula is validator + abi.encode(agent) + grantNonce salt; chain-free and wallet-scoped. SDK helper/constants omit validator context. | Agree helper/context wording; use event-returned IDs and wallet-scoped indexing. | +| G04 | P1 | Deployment/version alignment | Six-field main is older; eight fields are in current gateway branch and observed Donut dispatcher. Planned future removal is unconfirmed. | Confirm release intent and pin a matching gateway/policy deployment, without assuming an eight-to-six upgrade. | +| G05 | P1 | Downstream spec/code mismatch | Notion says <= in one page and >= in another; core cb69e0b marketplace verifySession requires exact equality. | Use equality for this marketplace compile path and align downstream specs; do not impose it on standalone rules universally. | +| G06 | P2 stale downstream documentation | Binder dropped | Live page 1 on October 3 says dropped for v1; supplied Zaryab message says it was never implemented. The pasted binder proposal is historical/conflicting. | Remove old binder-dependent hook requirement; no binder implementation unless newly approved. | +| G07 | P1 documented platform dependency | Push-core executor work | creditRevert accounting exists but the core executor does not call it on outbound failure, per current contract docs. | Track platform delivery and document current spend behavior; do not reopen it as an unknown Zaryab design question. | +| G08 | P1 SDK reads/remaining metadata | Checkpoints implemented in source | e704d5b has stored count, last-block view and Checkpointed events. Label mutation/storage and grant job ref remain absent; revoked agent history is cleared. | Build count/event reads, define revoked-history scope, add agreed metadata fields and verify deployment. | +| G09 | P1 | Shared schema gap | Page 2's card carries `executionKey.scheme/key`; page 6 and page 5 use a Push `agent` address. Card canonical encoding, signing and compilation remain open. | Publish a single versioned card schema and deterministic compilation vectors shared by SDK and hook. Use the intended Push identity consistently. | +| G10 | P1 downstream scope mismatch | Core marketplace has one binding | cb69e0b marketplace handles one EVM execution chain and one rulesId; page 6 describes multi-chain cards. | Align downstream supported cardinality; do not invent multi-rule job binding in standalone AGW. | +| G11 | P1 | WIP dependency | Page 7 requires client-chosen payment tokens. Actual `8183-v1` has one token per deployment; page 3's open wording still suggests PUSD by default. | Implement the selected K-12 design or a documented deployment mapping. Align job ABI, funding, fee accounting and SDK `TOKEN_MISMATCH` checks. | +| G12 | P1 downstream delivery | Partial hook plus marketplace guards | cb69e0b marketplace performs provider/chain/expiry/terms checks at startJob; RulesBindingHook retains membership/live-rule/one-live-job checks at fund. Evaluator baseline/submit integration remains outstanding. | Map each check to actual start/fund/submit path and test bypasses, plain jobs and evaluator readiness. | +| G13 | P1 | Confirmed stale statement | Page 5 says core rejects Push-native multicalls. Current `sendPushTx` supports EIP-7702 and a sequential fallback; all six existing tests pass. | Align creation behavior with actual signer capability and report atomicity, committed hashes and partial failure correctly. Correct the stale documentation statement when requested. | +| G14 | P1 | SDK integration | Atomic assert/revoke/grant through owner execute is documented contract behavior. Four original and seven stronger head experiments support it. | Implement wallet-level batching; repeat tests for final generation and checkpoints. No EIP-7702 dependence for existing-wallet management. | +| G15 | P2 optional creation capability | Create scope updated | Page 5 now makes create deployment/grants only, with no funds or pc option. Factory batch remains proposed but absent; normal funding is separate. | Implement actual creation strategy and partial-failure metadata without inventing a required factory method or restoring removed inputs. | +| G16 | P1 | Compatibility gap | New `READ.CHAIN.WEB2` is `'web2'`; current `CHAIN.WEB2` and `READ.WEB2` are `'web2:https'`. | Implement the target constant and normalize legacy inputs during the compatibility window. Cover read types, serialization, helpers and transaction rejection; do not silently break old literal callers. | +| G17 | P1 | Undefined lifecycle | Existing SDK supports read-only initialization and `reinitialize`. Page 5 does not specify how `agenticWallet` is inherited, cleared or changed, or how read-only agentic management behaves. | Define lifecycle semantics and compatibility cases. Ensure writes are unavailable in read-only mode and role checks rerun for a changed signer or wallet. | +| G18 | P1 | Undefined role behavior | Initialization accepts an address named in a wallet rule; sends resolve enabled rules. Handling of a signer whose only rules are expired or revoked is unstated. | Define initialization eligibility, per-send failures and role refresh after ownership or permission changes, with exact errors. Keep rule lookup uncached as specified. | +| G19 | P0/P1 | Product safety and encoding | Destination approve still cannot constrain the spender. New asset caps use maxTotal=0 for unlimited; native defaults remain separate. Destination token/native-marker resolution and ABI offset context need fixtures. | Agree approval policy, native defaults, resolved PRC20 context and safe ABI representations. | +| G20 | P1 | SDK composition and response mapping | Existing outbound tracking is hash/UTX-ID based. Route 2 request recipient, refund recipient and default maxPCForGas conflict with URP; Push-side allowance must be established by owner. | Dedicated composer, logical AGW from override, preserved signer origin and live tracking/settlement verification. | +| G21 | P1 | Product scope | Contract grants up to eight native actions but dispatches a single agent call. SDK NativeRule has one action and transaction arrays are broadly promised. | Decide public native action type and explicit native-array behavior; keep destination multicalls distinct. | +| G22 | P1 | Capability integration | SVM policy source exists; head agent identity is Push address and no longer verifies Ed25519 locally. SVM origin goes through UEA. | Verify deployed destination capability and implement obligations 19–23 when enabled. | +| G23 | P0 contract integration dependency | New multi-asset target | Page 5 uses assets[] and maxGasPerCall. Page 1 section 4c proposes per-token counters, 0–8 assets, maxTotal zero unlimited and bytes32 expectedCEA. Tested e704d5b still uses single-asset terms and amount counters. | Matched contract artifacts/fixtures for native marker and foreign-token resolution, per-asset enforcement, empty-assets call-only routing, expectedCEA representation, duplicate asset handling and token-carrying events. | +| G24 | P1 public read/update mismatch | Per-token spend shape unresolved | SDK Spent remains scalar amountSpent. Proposed assertSpent(configId,account) returns totals without expected snapshots, while rules.update still promises a race assertion. | Agree per-asset Spent and expected-total assertion inputs/semantics; prove stale state rejects atomically across all affected assets. Do not aggregate unlike units. | + +## Cross-cutting requirements + +- expectedCEA is SDK-derived context: derive the AGW destination account, commit it in every universal rule, display it and monitor derivation drift. Do not use the signer CEA or an arbitrary pasted address. +- Checkpoint consumers compare counts, not only blocks. Replacement adds five ticks. Pre-existing allowance pulls can change balances without a new checkpoint, so evaluator policy needs explicit scope. +- create deploys/grants only; funding and approvals are separate. AGENTIC-TX-103 is removed. +- Assets[]/maxGasPerCall require new matching artifacts. Proposed asset maxTotal zero is unlimited; native defaults are separate. Per-token Spent and stale-spend assertions remain unresolved. +- Binder is dropped for v1. Historical hook cleanup text is not authorization to add it. +- Preserve explicit zero/omission semantics, supported native arrays and deterministic duplicate-rule behavior; do not silently alter policy failure timing. + +## Closure records + +Record accepted behavior, exact source/spec revision, test evidence and remaining limits when closing an item. Source implementation and deployment readiness are separate statuses. Use [Harsh questions](questions-harsh.md) and [Zaryab questions](questions-zaryab.md) for unresolved decisions. No questions have been sent. diff --git a/plan/agw/implementation-plan.md b/plan/agw/implementation-plan.md new file mode 100644 index 00000000..1b24dd23 --- /dev/null +++ b/plan/agw/implementation-plan.md @@ -0,0 +1,49 @@ +# AGW SDK implementation plan + +Target: [SDK spec](notion/5-sdk-agw.md), October 3 export. Source/test baseline: [e704d5b](current-baseline.md). Current gaps and questions are in [gaps.md](gaps.md), [Harsh draft](questions-harsh.md) and [Zaryab draft](questions-zaryab.md). No production implementation is included. + +## Phase 0 Agree the integration contract + +Completed: source access, sender-adapter review, checkpoint/source-invariant review, local builds/tests, atomic replacement experiments and latest Notion import. + +Remaining: approval safety, native action/array scope, defaults, per-asset Spent and assertion semantics, multi-asset fixtures, labels/ref/versioned envelope, empty-assets routing and compatible deployment generation. Keep standalone AGW and downstream marketplace/job/evaluator requirements distinct. + +Exit: critical authorization, encoding, accounting and atomicity behavior has recorded decisions and exact artifacts. Source implementations are distinguished from live capabilities. + +## Phase 1 Public surface and structure + +Add types, namespace, wallet handle, errors, progress, exports and initialize options. Preserve existing defaults, read-only mode and reinitialize behavior. Introduce internal contract/read/execution adapters. + +Verify public usage, signer versus wallet identity, forbidden operations and ordinary-client compatibility. + +## Phase 2 Encoding and management + +Implement selectors, safe ABI positions, chain/token/native-marker resolution, expectedCEA derivation, codecs, IDs and wallet prediction against matching vectors. Add derive/list/create, summaries, checkpoints, labels and lifecycle operations. + +create deploys/grants only. Funding and owner approvals are separate. Replacement uses one owner wallet assert/revoke/grant batch; never a sequential fallback. + +Verify ID ordering, unknown/revoked states, duplicate candidates, nonce/index races, per-asset caps, zero/unlimited conventions and assertion rollback. Snapshot checkpoint counts and account for five ticks in a replacement batch. AGENTIC-TX-103 is absent from creation. + +## Phase 3 Wallet execution + +Implement role checks, uncached rule lookup and owner/agent wrappers. Keep signer transport/gas separate from AGW assets/outbound PC. Build a dedicated composer satisfying URP; do not reuse signer-based Route 2 unchanged. + +Verify unauthorized/revoked/expired cases, rejected from, forbidden methods, deployment/gas exceptions, native arrays, allowance prerequisites, zero-amount calls, beneficiary fixtures and rollback. + +## Phase 4 Responses and compatibility + +Map logical from to AGW and preserve signer origin. Reuse hash/UTX tracking provisionally and verify wrapped execution. Preserve hooks through send/wait and structured errors. Add READ.CHAIN and legacy Web2 normalization. + +Run relevant route, gas, response, read and compatibility checks. Do not silently change failure timing through expiry filtering. + +## Phase 5 Matched deployment validation + +Verify source/build revisions, generation identity, proxy/implementation addresses, start blocks and capabilities. With separately authorized funding and transactions, test native and external owners/agents. + +The first positive-amount EVM agent outbound should prove allowance, real burn, empty recipient, AGW refund recipient, policy-compliant multicall, node/TSS acceptance, settlement and tracking. Enable SVM destination work with obligations 19–23 and agreed fixtures. + +## Phase 6 Optional ecosystem integration + +Align canonical cards, multi-rule binding, marketplace expiry equality, payment-token scope, evaluator gating and checkpoint verdicts. The partial hook alone does not establish complete job lifecycle behavior. + +Exit: supported capabilities documented, relevant tests pass and remaining gaps have explicit accepted scope. Assign each [integrator obligation](contract-integrator-obligations.md) to SDK, UI or operations. diff --git a/plan/agw/latest-refresh.json b/plan/agw/latest-refresh.json new file mode 100644 index 00000000..b0897513 --- /dev/null +++ b/plan/agw/latest-refresh.json @@ -0,0 +1,124 @@ +{ + "run_id": "20261003T075310278902Z", + "pulled_at": "2026-10-03T07:53:10.278902+00:00", + "complete": true, + "missing_page_ids": [], + "unknown_export_entries": [], + "archives": [ + "notion/exports/20261003T075310278902Z/export-1.zip", + "notion/exports/20261003T075310278902Z/export-2.zip", + "notion/exports/20261003T075310278902Z/export-3.zip", + "notion/exports/20261003T075310278902Z/export-4.zip" + ], + "pages": [ + { + "page_id": "3e9188aea7f481c8b38ccba332b0afa2", + "title": "AGW design overview", + "local_file": "notion/overview.md", + "changed": false, + "previous_sha256": "f2d7954e018324a937282ca190f397cc12a27973a07c891f3edfd6e89383c53e", + "sha256": "f2d7954e018324a937282ca190f397cc12a27973a07c891f3edfd6e89383c53e", + "raw_export_sha256": "99b727bd58cf588b2c766dc1b93eff402c47e918718b69c2a456b119ad43435b" + }, + { + "page_id": "3e9188aea7f4813aa31fc95ceb4e684d", + "title": "1 AGW Contract Changes", + "local_file": "notion/1-agw-contract-changes.md", + "changed": true, + "previous_sha256": "22fa37bdd52e903c632760f4b7fa77cd7be89a7c5a124eba3f6866c00b5632c6", + "sha256": "f1301d8ff1cf370968b90a3d53037ece8fa4c6783c45a402f9be6998928e3631", + "raw_export_sha256": "f1301d8ff1cf370968b90a3d53037ece8fa4c6783c45a402f9be6998928e3631" + }, + { + "page_id": "3e9188aea7f48118b90ac9b267496295", + "title": "2 Universal Marketplace", + "local_file": "notion/2-universal-marketplace.md", + "changed": false, + "previous_sha256": "5ddfd9e8980faae9eec85e3959cc99edbb3b115565af289c5603a91df0b78d18", + "sha256": "5ddfd9e8980faae9eec85e3959cc99edbb3b115565af289c5603a91df0b78d18", + "raw_export_sha256": "5ddfd9e8980faae9eec85e3959cc99edbb3b115565af289c5603a91df0b78d18" + }, + { + "page_id": "3e9188aea7f48188a838c3a740d8c858", + "title": "3 ERC-8183 job kernel and hook", + "local_file": "notion/3-8183-job-kernel-and-hook.md", + "changed": false, + "previous_sha256": "3c805db465f2d39db8d34179ac1dd864db1abf7b1b3e93f38074fbf393093f90", + "sha256": "3c805db465f2d39db8d34179ac1dd864db1abf7b1b3e93f38074fbf393093f90", + "raw_export_sha256": "3c805db465f2d39db8d34179ac1dd864db1abf7b1b3e93f38074fbf393093f90" + }, + { + "page_id": "3e9188aea7f4817bb03ef4c78c883f8b", + "title": "4 Universal Evaluation", + "local_file": "notion/4-universal-evaluation.md", + "changed": false, + "previous_sha256": "a2f1c93a75b8631c9628c06f1be135fa0198f00f096a765ce808dd5e544b2d6f", + "sha256": "a2f1c93a75b8631c9628c06f1be135fa0198f00f096a765ce808dd5e544b2d6f", + "raw_export_sha256": "a2f1c93a75b8631c9628c06f1be135fa0198f00f096a765ce808dd5e544b2d6f" + }, + { + "page_id": "3e9188aea7f481cf8e8de324956549b9", + "title": "5 SDK AGW", + "local_file": "notion/5-sdk-agw.md", + "changed": true, + "previous_sha256": "9ce90fb84826c989b4fec22066da0776121f9195e27bc6679aaac538995f4653", + "sha256": "e407ee77cdf874db7ef4697f84e9945ff3a12a2f2e07e8a7f90bd24e93ea32f1", + "raw_export_sha256": "9a16f8aed79fac09818ec216fb4c69dc79f2fa0cffe0af611af956eb0e69f33f" + }, + { + "page_id": "3ea188aea7f481e2961ed97129f3a4e6", + "title": "6 SDK Universal Marketplace", + "local_file": "notion/6-sdk-universal-marketplace.md", + "changed": false, + "previous_sha256": "e7298952f2ba9adb218b4ef0459b8fa696a2072167dc5f655060b69788cf528c", + "sha256": "e7298952f2ba9adb218b4ef0459b8fa696a2072167dc5f655060b69788cf528c", + "raw_export_sha256": "e7298952f2ba9adb218b4ef0459b8fa696a2072167dc5f655060b69788cf528c" + }, + { + "page_id": "3ea188aea7f481e0a137f5a896723376", + "title": "7 SDK ERC-8183 Job", + "local_file": "notion/7-sdk-8183-job.md", + "changed": false, + "previous_sha256": "dbf1ff539f5df944e5f5f55710f5f6d3359469a141038cec2604e7c33392752c", + "sha256": "dbf1ff539f5df944e5f5f55710f5f6d3359469a141038cec2604e7c33392752c", + "raw_export_sha256": "dbf1ff539f5df944e5f5f55710f5f6d3359469a141038cec2604e7c33392752c" + }, + { + "page_id": "3ea188aea7f48197a3b3cfdedfa74fee", + "title": "8 SDK Universal Evaluation", + "local_file": "notion/8-sdk-universal-evaluation.md", + "changed": false, + "previous_sha256": "eb2e584bd76aeea06c0dd03b3c8802b2340acf955e1ea75bf7768ebf9d2ab34e", + "sha256": "eb2e584bd76aeea06c0dd03b3c8802b2340acf955e1ea75bf7768ebf9d2ab34e", + "raw_export_sha256": "eb2e584bd76aeea06c0dd03b3c8802b2340acf955e1ea75bf7768ebf9d2ab34e" + }, + { + "page_id": "d2d188aea7f4825cbcea81ef86eca607", + "title": "Legacy PUSH AGW SDK Doc v1", + "local_file": "notion/legacy-agw-sdk-v1.md", + "changed": false, + "previous_sha256": "9e6569ef9b76d59cb411d65305d67333c6766abc2e9c80a35ae6f56f12f70916", + "sha256": "9e6569ef9b76d59cb411d65305d67333c6766abc2e9c80a35ae6f56f12f70916", + "raw_export_sha256": "9e6569ef9b76d59cb411d65305d67333c6766abc2e9c80a35ae6f56f12f70916" + }, + { + "page_id": "3d1188aea7f480ddbb4af6d0efb211e6", + "title": "AGW Address Book PC Donut", + "local_file": "notion/agw-address-book-donut-2026-09-04.md", + "changed": false, + "previous_sha256": "5c5017d6b4a58af0fa8854ef550b054c1f33d57a812ea51a16f31f7c33e79742", + "sha256": "5c5017d6b4a58af0fa8854ef550b054c1f33d57a812ea51a16f31f7c33e79742", + "raw_export_sha256": "5c5017d6b4a58af0fa8854ef550b054c1f33d57a812ea51a16f31f7c33e79742" + }, + { + "page_id": "3d1188aea7f4801f9cb3fbd9318ec536", + "title": "Agentic wallet flow updated", + "local_file": "notion/agentic-wallet-flow-2026-09-07.md", + "changed": false, + "previous_sha256": "d4a922fd1d33da5a7042f26053e8df0e496c3ccd4cb0044b0892948ac509c3a0", + "sha256": "d4a922fd1d33da5a7042f26053e8df0e496c3ccd4cb0044b0892948ac509c3a0", + "raw_export_sha256": "d4a922fd1d33da5a7042f26053e8df0e496c3ccd4cb0044b0892948ac509c3a0" + } + ], + "review_status": "Review required" +} diff --git a/plan/agw/notion/1-agw-contract-changes.md b/plan/agw/notion/1-agw-contract-changes.md new file mode 100644 index 00000000..029e3e82 --- /dev/null +++ b/plan/agw/notion/1-agw-contract-changes.md @@ -0,0 +1,362 @@ +# 1. AGW Contract Changes (nomenclature standard + change set) + + + +# 0. Before the naming: AGW will break when the gateway is upgraded + +**What happened.** The gateway team changed the outbound request struct on GitHub main. Two fields are gone (`gasPrice`, `maxPCForGas`). AGW copied the old struct into its own repo and URP checks one of the removed fields (gate 9: `maxPCForGas` must be non-zero). + +**Why it still works today.** Donut is still running the old gateway (implementation `0x1e41...a659` has the old eight fields). + +**What breaks.** The day the new gateway is deployed on Donut, every cross-chain rule set stops working: URP rejects every request. + +**Fix, two rules.** + +1. AGW never copies a gateway or core struct. It imports them from the gateway and core packages, so a change upstream fails the build instead of failing on-chain. +2. The URP upgrade and the gateway upgrade go out together, not separately. + +Same rule for the selector: derive `sendUniversalTxOutbound.selector` from the interface, do not hardcode `0x77b86bec`. + +# 1. How core and gateway name things (the standard AGW follows) + +These conventions already exist in `push-chain-core-contracts` and `push-chain-gateway-contracts`. AGW adopts them as is. Where the two repos disagree, the AGW column says which one wins. + +| Area | Convention | Example | AGW | +| --- | --- | --- | --- | +| Contract names | Chain-agnostic components spell out Universal. Push-side variants add PC. Accounts are 3-letter acronyms. | `UniversalCore`, `UniversalGatewayPC`, `UEA`, `CEAFactory` | `AGW`, `AGWFactory`, `UniversalRulesPolicy` | +| Errors | One `libraries/Errors.sol` per repo, one error library per contract, PascalCase, arguments only when the caller needs them. Caller checks are `CallerIsNotX`. | `UEAErrors.InvalidCall()`, `CommonErrors.ZeroAddress()`, `CallerIsNotUEModule()` | `AGWErrors`, `AGWFactoryErrors`, `UniversalRulesPolicyErrors` | +| Types and constants | One `libraries/Types.sol`, plain file-level structs, `UPPER_SNAKE` constants, selectors derived not hardcoded. | `struct Multicall`, `MULTICALL_SELECTOR = bytes4(keccak256("UEA_MULTICALL"))` | `libraries/Types.sol`; gateway and core structs imported, never copied | +| Request shape | One `XRequest` struct as the single argument; the contract infers the kind. Users never state a type. | `sendUniversalTxOutbound(UniversalOutboundTxRequest req)` infers `TX_TYPE` | `grantRules(Session)` infers `NATIVE` vs `UNIVERSAL` from `chainNamespace` | +| Interface sections | Tag plus number banners, events first, NatSpec on everything. | `UGPC_1: EVENTS`, `UGPC_2: OUTBOUND TX`, `UGPC_3: VIEW FUNCTIONS` | `AGW_1: EVENTS` ... `AGW_5: VIEWS`, `URP_1` ... `URP_3` | +| Functions | `setX`, `getX`, `isX`. Set-once wiring is read through `UPPER_CASE()` getters. | `isSupportedToken()`, `UNIVERSAL_CORE()` | `SESSION_ENGINE()`, `RULES_POLICY()`, `UNIVERSAL_GATEWAY_PC()` | +| Storage | Internal state is underscore-prefixed. | `_walletCount` | `_` everywhere; drop URP's `$` prefix | +| Roles | `UPPER_SNAKE_ROLE`. | `DEFAULT_ADMIN_ROLE`, `PAUSER_ROLE`, `TSS_ROLE` | same; `PAUSER` and `OPERATOR` split kept, documented | +| Chain identity | Full CAIP-2 string, field named `chainNamespace`. | `"eip155:1"` | envelope field renamed `chain` to `chainNamespace` | +| Events | No consistent rule upstream. | `SetChainMeta` (imperative), `VaultPCUpdated` (past) | past tense: `RulesGranted`, `WalletDeployed` | +| Layout | `src/` with `interfaces/` and `libraries/`; numbered docs and tests; addresses per network; `CLAUDE.md` in every package. | `docs/1_PUSH_CHAIN.md`, `test/gateway/1_adminActions.t.sol`, `docs/addresses/sepolia.md` | same, see rename map | + +#### Where each convention was seen (open only if you want the receipts) + +Core repo, folder layout: + +``` +src/ + Interfaces/ IUniversalCore.sol, IUEA.sol, ICEA.sol + libraries/ Errors.sol, Types.sol, Utils.sol + uea/ UEAFactory.sol, UEA_EVM.sol, UEA_SVM.sol + cea/ CEAFactory.sol, CEA.sol + UniversalCore.sol, PRC20.sol, WPC.sol +``` + +Gateway repo, folder layout: + +``` +contracts/evm-gateway/ + src/ UniversalGateway.sol, UniversalGatewayPC.sol, Vault.sol, VaultPC.sol + src/interfaces/ IUniversalGatewayPC.sol, IVault.sol + src/libraries/ Errors.sol, Types.sol, TypesUG.sol, TypesUGPC.sol + docs/ 1_PUSH_CHAIN.md, 2_UniversalGateway.md, 3_UniversalGatewayPC.md + docs/addresses/ sepolia.md, bsc-testnet.md + test/gateway/ 1_adminActions.t.sol ... 14_gatewayPC.t.sol + script/ 1_DeployGatewayWithProxy.sol, 3_UpgradeGatewayNewImpl.sol + CLAUDE.md +``` + +Errors (core, `libraries/Errors.sol`): + +```solidity +library CommonErrors { error ZeroAddress(); error Unauthorized(); error InvalidInput(); } +library UniversalCoreErrors { error CallerIsNotUEModule(); error GasLimitBelowBase(uint256 provided, uint256 minimum); } +library UEAErrors { error InvalidCall(); error ExecutionFailed(); } +``` + +Types (core, `libraries/Types.sol`): + +```solidity +struct UniversalAccountId { string chainNamespace; string chainId; bytes owner; } +struct Multicall { address to; uint256 value; bytes data; } +bytes4 constant MULTICALL_SELECTOR = bytes4(keccak256("UEA_MULTICALL")); +``` + +Request shape (gateway, `TypesUGPC.sol` and `IUniversalGatewayPC.sol`): + +```solidity +struct UniversalOutboundTxRequest { bytes recipient; address token; uint256 amount; uint256 gasLimit; bytes payload; address revertRecipient; } +function sendUniversalTxOutbound(UniversalOutboundTxRequest calldata req) external payable; // TX_TYPE inferred inside +``` + +Interface sections and wiring getters (gateway, `IUniversalGatewayPC.sol`): + +```solidity +// UGPC_1: EVENTS +// UGPC_2: OUTBOUND TX +// UGPC_3: VIEW FUNCTIONS +function UNIVERSAL_CORE() external view returns (address); +``` + +Events (both repos, no single rule): + +```solidity +event SetChainMeta(...); // core, imperative +event PauserRoleGranted(...); // core, past tense +event UniversalTxOutbound(...); // gateway, noun +event VaultPCUpdated(...); // gateway, past tense +``` + +Chain identity, the same field name with two meanings: + +```solidity +gasPriceByChainNamespace("eip155:1") // UniversalCore: full CAIP-2 string +UniversalAccountId({ chainNamespace: "eip155", chainId: "1" }) // Read State: split +``` + +# 2. Decisions + +| # | Decision | Outcome | +| --- | --- | --- | +| D1 | Wallet contract name | **AGW.sol** (account acronym like UEA, CEA). Full form "Agentic Wallet" in the NatSpec title only. Factory stays `AGWFactory.sol`. | +| D2 | Policy contract name | **UniversalRulesPolicy.sol**. `URP` stays as the short form in comments, events and the SDK constant, the way `UGPC` stands for `UniversalGatewayPC`. | +| D3 | Validator contract name | PROPOSED 2026-09-29: **no validator.** The agent is a Push address: a native key is its own EOA, any external key (EVM, Solana, anything) is its UEA, deterministic from (chain, owner). Cross-VM signature verification already happens inside the UEA, so the agent door checks `msg.sender == rules.agent` and hands the calls to URP. `PushSessionValidator.sol` is removed rather than renamed. Pending one check against the v3 branch: how deep SmartSession's signature path is wired into the engine calls URP relies on, and whether the policy engine can be driven from a sender check without forking it. | +| D4 | Vocabulary for the granted object | **rules, one word everywhere.** On-chain: `grantRules`, `revokeRules`, `revokeAllRules`, `rulesId`, `RulesGranted`, `RulesRevoked`, `RulesActionAuthorized`. Layer: Universal Rules. SDK: `client.agentic.rules`. `permissionId` remains the SmartSession-internal name and is exposed as `rulesId`. `mandate` is retired from code, docs and copy. +**Rename boundary (2026-09-29).** Three vocabularies live in the fork; only ours is renamed. ERC-7579 names stay (`execute(mode, executionCalldata)`, `ModeCode`, module types, `installModule`). SmartSession names stay inside the engine and on the interfaces URP implements (`Session`, `permissionId`, `PolicyData`, `ActionData`, `ConfigId`, `enableSessions`, `isPermissionEnabled`, `IPolicy.checkAction`, `initializeWithMultiplexer`): audit history and upstream diffs attach to those names. Push's own words (`mandate`, `PushAgentWallet`, our events, envelope, docs, SDK) become rules. The seam is the AGW ABI: `rulesId` is computed by the engine's `getPermissionId(Session)` and the NatSpec states `rulesId == permissionId`. If the engine is vendored with edits, it lives in `src/vendor/smartsession/` with a note naming the upstream commit and every local change. If D3 ends with the engine dropped, SmartSession vocabulary leaves with it. | +| D5 | Door functions | Keep `execute` (owner door). Agent door becomes `executeAsAgent(bytes32 rulesId, bytes32 mode, bytes executionCalldata)`, gated on `msg.sender == rules.agent`, replacing `executeWithSession` and its signature blob (follows D3). "Owner door" and "agent door" stay as NatSpec language. | +| D6 | Chain field in the envelope | Rename `chain` to `chainNamespace`, full CAIP-2 string, matching `UniversalCore` and gateway events. Read State keeps its split fields; the SDK converts. | +| D7 | Mode names | `NATIVE` and `UNIVERSAL` stay. The SVM rulebook is selected by the `solana` namespace inside `UNIVERSAL`; no new mode name. | + +# 3. Rename map (current to proposed) + +| Area | Today | Proposed | +| --- | --- | --- | +| Inherited names (7579, SmartSession) | `execute(mode, executionCalldata)`, `Session`, `permissionId`, `PolicyData`, `ActionData`, `ConfigId`, `checkAction`, `initializeWithMultiplexer` | unchanged (see D4 rename boundary) | +| Wallet | `PushAgentWallet.sol` | `AGW.sol` | +| Factory | `AGWFactory.sol` | `AGWFactory.sol` (unchanged) | +| Policy | `policies/URP.sol` | `UniversalRulesPolicy.sol` | +| Validator | `validators/PushSessionValidator.sol` | removed (D3): agent identity is a Push address, verification lives in the UEA | +| Interfaces | `IPushAgentWallet`, `IURP`, `IPushSessionValidator`, local `IUniversalGatewayPC`, `IPRC20Source` | `IAGW`, `IUniversalRulesPolicy`; gateway and core interfaces imported (`IUEAFactory` for `computeUEA` in tests and tooling) | +| Errors | `libraries/PushWalletErrors.sol` plus errors declared in `IURP` and `IAGWFactory` | `libraries/Errors.sol` with `AGWErrors`, `AGWFactoryErrors`, `UniversalRulesPolicyErrors`; reuse `CommonErrors` names (`ZeroAddress`, `Unauthorized`, `AlreadyInitialized`); `AGWErrors.CallerIsNotAgent()` | +| Types | `libraries/PushWalletTypes.sol` re-declares `UniversalOutboundTxRequest`, `Multicall` | `libraries/Types.sol` with AGW-owned structs only (`RulesEnvelope`, `NativeTerms`, `UniversalTerms`, `AllowedCall`, `ArgPin`, `AmountRule`); gateway and core types imported | +| Grant / revoke | `grantMandate`, `stopMandate`, `stopAll` | `grantRules`, `revokeRules`, `revokeAllRules` | +| Events | `MandateGranted`, `MandateRevoked`, `MandateActionAuthorized`, `URPPolicySet` | `RulesGranted`, `RulesRevoked`, `RulesActionAuthorized`, `RulesConfigured` | +| Ids | `permissionId` in wallet ABI | `rulesId` in wallet ABI (engine keeps `permissionId` internally) | +| Wiring getters | `sessionEngine()`, `urp()`, `sessionValidator()`, `universalGateway()` | `SESSION_ENGINE()`, `RULES_POLICY()`, `UNIVERSAL_GATEWAY_PC()` (no validator getter, D3) | +| Storage prefix | `_` in wallet and factory, `$` in URP | `_` everywhere | +| Envelope | `abi.encode(string chain, bytes body)` | `abi.encode(uint16 version, string chainNamespace, bytes body)` | +| Interface banners | none | `AGW_1: EVENTS`, `AGW_2: OWNER DOOR`, `AGW_3: AGENT DOOR`, `AGW_4: RULES LIFECYCLE`, `AGW_5: VIEWS`; `URP_1: EVENTS`, `URP_2: POLICY`, `URP_3: VIEWS`; `AGWF_1: EVENTS`, `AGWF_2: DEPLOY`, `AGWF_3: VIEWS` | +| Selector constant | `SEND_OUTBOUND_SELECTOR = 0x77b86bec` | derived from `IUniversalGatewayPC` | +| Roles | `PAUSER_ROLE` pauses, `OPERATOR_ROLE` unpauses | keep the split, document it as a deliberate deviation from gateway | +| Event tense | past tense | past tense, written down as the rule | +| Docs | `docs/v3-architecture.md`, `agentic_wallet_flow.md`, `push_native_agentic_wallet_flow.md` | `docs/1_AGW.md`, `2_UniversalRulesPolicy.md`, `3_Universal_Flow.md`, `4_Native_Flow.md` | +| Addresses | `deployments/address-book-v3/ADDRESSES.md` | `docs/addresses/donut.md` | +| Tests | `test/unit/*.t.sol`, `test/integration/*.t.sol` | numbered by area: `1_factory`, `2_ownerDoor`, `3_rulesLifecycle`, `4_agentDoor`, `5_universalRulebook`, `6_nativeRulebook`, `7_externalAgentViaUEA`, `8_e2e` | + +# 4. Structural changes that ride along with the rename + +Agreed on 2026-09-28. Listed here so the rename and the additions land in one change set and one audit, before the permanent deployment. + +1. **Signature-authorized variants**: `deployWalletWithSig`, `grantRulesWithSig`, `executeWithSig`. One EIP-712 domain per contract. Digest includes chainid, contract, nonce (the wallet's grant nonce for grants; a per-owner nonce on the factory), deadline. Verify ECDSA, and ERC-1271 when the owner has code (a UEA). +2. **Checkpoints**: the wallet records owner-side changes an evaluator needs: principal moved out (owner-door value or token transfer out, and every outbound), rules granted, revoked or replaced, key changed. Per-wallet monotonic counter plus `Checkpointed(kind, ref, blockNumber)`, so an evaluator can ask "any checkpoint after block N" with one read. +3. **`bytes32 ref` on `grantRules`**, emitted in `RulesGranted`, so a job binds to a rules id and an indexer goes rules to job without the hook. +4. **Stop-only role: dropped for v1** (2026-10-01). A binder address that could call `revokeRules` and nothing else was considered so a job hook could end rules at job end. Not needed: rules expire by `validUntil`, which the fund hook requires to be at or after the job's `expiredAt`, caps bound the gap, and the hook keeps its own one-live-job slot. Additive to bring back later. +5. **Envelope version word**: `abi.encode(uint16 version, string chainNamespace, bytes body)`. +6. **`creditRevert` reachability**: wire the real executor module or replace the credit path. Today spend never decreases on Donut. +7. **SVM rulebook** in the policy, keyed by the `solana` namespace: 32-byte `expectedCEA` and targets, program plus instruction discriminator allow-list, beneficiary check over the accounts array, SVM payload gate. +8. **Import gateway and core types**, derive the outbound selector, sequence the URP upgrade with the gateway's struct change. +9. **Agent identity is a Push address** (2026-09-29). The rules name an address: an EOA, or the UEA of an external key. The agent door checks the sender instead of verifying a session signature; the validator contract goes. One identity for rules, card and 8183 provider, so the fund hook matches by equality. Sizing against the v3 branch pending (D3). +10. **Editable label** (2026-10-01). `setLabel(string label)` on AGW, owner only, emits `LabelSet(string label)`. Today the label is only passed at `deployWallet` and emitted in `WalletDeployed`. Not a checkpoint kind: cosmetic metadata, evaluators ignore it. SDK: `w.setLabel(label)` on page 5. + +# 4b. Contract surface, as a diff + +Read `+` as added, `-` as removed, `~` as changed in place, `=` as unchanged. Names are the post-rename names. Storage slots never move; renames are labels only. + +**AGWFactory** + +```diff += deployWallet(string label) returns (address wallet) // caller is the owner ++ deployWalletWithSig(address owner, uint96 index, string label, ++ uint48 deadline, bytes ownerSig) returns (address) // EIP-712; index must equal walletCount(owner) ++ // ownerSig: ECDSA, or ERC-1271 when owner has code (UEA) ++ DOMAIN_SEPARATOR() view returns (bytes32) += predictWallet(address owner, uint256 index) view returns (address, bool deployed) += walletCount / ownerOf / isWallet / indexOf / walletImplementation += pause() PAUSER_ROLE, unpause() OPERATOR_ROLE += event WalletDeployed(owner, index, wallet, label) +``` + +**AGW** (was PushAgentWallet) + +```diff +// owner door += execute(bytes32 mode, bytes executionCalldata) payable // owner only, no policy +~ execute now emits Checkpointed(seq, OWNER_ACTION, keccak(calldata), block) ++ executeWithSig(bytes32 mode, bytes executionCalldata, ++ uint64 ownerNonce, uint48 deadline, bytes ownerSig) // owner door by signature, same effects as execute ++ ownerNonce() view returns (uint64) ++ setLabel(string label) // owner only; emits LabelSet; not a checkpoint + +// rules lifecycle +- grantMandate(Session) returns (bytes32 permissionId) ++ grantRules(Session session, bytes32 ref) returns (bytes32 rulesId) // ref: job or card reference, emitted, not interpreted ++ grantRulesWithSig(Session session, bytes32 ref, uint48 deadline, bytes ownerSig) returns (bytes32 rulesId) ++ // digest includes grantNonce, so a signed grant cannot replay +- stopMandate(bytes32 permissionId) ++ revokeRules(bytes32 rulesId) // owner or self +- stopAll() ++ revokeAllRules() // owner or self + +// agent door (D3, D5) +- executeWithSession(address validator, bytes32 mode, bytes executionCalldata, +- bytes signature, uint192 nonceKey, uint64 nonceSeq, uint48 requestExpiry) ++ executeAsAgent(bytes32 rulesId, bytes32 mode, bytes executionCalldata) ++ requires msg.sender == agentOf(rulesId); replay and expiry come from the sender's own tx (EOA nonce, or the UEA's) ++ URP checks every call exactly as before; no signature blob, no validator address ++ agentOf(bytes32 rulesId) view returns (address) + +// checkpoints ++ checkpointCount() view returns (uint64) ++ lastCheckpointBlock() view returns (uint64) ++ event Checkpointed(uint64 indexed seq, uint8 kind, bytes32 ref, uint64 blockNumber) ++ kind: 0 OWNER_ACTION (any owner-door execute), 1 RULES_GRANTED, 2 RULES_REVOKED ++ emitted from execute, executeWithSig, grantRules*, revokeRules, revokeAllRules + +// views (wiring, renamed to UPPER_CASE) +- sessionEngine() urp() sessionValidator() universalGateway() ++ SESSION_ENGINE() RULES_POLICY() UNIVERSAL_GATEWAY_PC() += owner() factory() grantNonce() getNonce(uint192) accountId() ++ DOMAIN_SEPARATOR() view returns (bytes32) + +// events +- MandateGranted(permissionId, mandateType, chainHash, chain) ++ RulesGranted(bytes32 indexed rulesId, uint8 mode, bytes32 indexed chainHash, string chainNamespace, bytes32 ref) +- MandateRevoked(permissionId) ++ RulesRevoked(bytes32 indexed rulesId, address by) +- MandateActionAuthorized(permissionId, nonceKey, nonceSeq, opHash) ++ RulesActionAuthorized(bytes32 indexed rulesId, address indexed agent, bytes32 callsHash) ++ event LabelSet(string label) +``` + +**UniversalRulesPolicy** (was URP) + +```diff +~ initializeWithMultiplexer(address account, ConfigId id, bytes initData) +~ initData = abi.encode(uint16 version, string chainNamespace, bytes body) // was (string chain, bytes body) +~ rulebook chosen by namespace: this chain => native; eip155:* => universal EVM; solana:* => universal SVM ++ SVM rulebook ++ struct SvmTerms { uint48 validUntil; bytes32 expectedCEA; address asset; uint256 maxAmountPerCall; ++ uint256 maxAmountTotal; uint256 maxPCPerCall; SvmAllowedCall[] allowedCalls; } ++ struct SvmAllowedCall { bytes32 program; bytes8 discriminator; uint8 beneficiaryAccountIndex; bool hasBeneficiary; uint64 maxLamports; } ++ gates mirror the EVM list; beneficiary checked in the accounts array, payload gate for the SVM outbound format +~ checkAction: UniversalOutboundTxRequest imported from the gateway package +~ gate 4c MIN_OUTBOUND_BODY_LEN recomputed from the imported struct +~ gate 9 (maxPCForGas != 0) removed when the six-field gateway struct lands; deploy in the same window +~ creditRevert(id, account, outboundTxId, amount): caller is the real executor module, set at initialize += or removed if the credit path is replaced (decision pending) += assertSpent (both overloads), getConfig, getNativeConfig, getMode, pushChainHash, isCredited ++ getSvmConfig(ConfigId, address) view +- event URPPolicySet(...) ++ event RulesConfigured(bytes32 indexed configId, address indexed multiplexer, address indexed account, uint8 mode, bytes32 chainHash) += OutboundMetered, NativeCallMetered, RevertCredited +~ storage variables renamed $configs, $credited, $mode, $native to _configs, _credited, _mode, _native (labels only, slots unchanged) ++ _svm mapping appended after _native; __gap shrinks by one +~ version() returns "2.0.0" +``` + +**PushSessionValidator** + +```diff +- validateConfig(bytes keyConfig) +- validateSignatureWithData(bytes32 hash, bytes sig, bytes keyConfig) +- contract removed (D3). Session.sessionValidator and keyConfig are replaced by a single address in the rules: the agent. +``` + +**Not in this change set** (belongs to 8183, listed so nobody looks for it here): the fund hook's key-match and expiry checks, the marketplace, the evaluator. + +# 4c. What the SDK rule shape changes in the contracts (PROPOSED 2026-10-02) + +Page 5 (SDK: AGW) settled the shape of a cross-chain rule in `client.agentic.create`. Three of those SDK changes touch the contracts. Nothing else on page 5 does. Names are the post-rename names from section 3; struct changes are to the universal terms URP decodes from the rules envelope. + +**1. One rule can move several tokens: `assets: AssetCap[]` replaces `asset`, `maxAmountPerCall`, `maxAmountTotal`.** + +The SDK takes each asset as the token's address on the rule's chain (`MOVEABLE.TOKEN..` or the native marker) and resolves it to the PRC20 on Push before encoding, so the contract keeps storing PRC20 addresses. The spend counter becomes per asset. + +```diff +// universal EVM terms (and SvmTerms, same change) +- address asset; uint256 maxAmountPerCall; uint256 maxAmountTotal; ++ AssetCap[] assets; // 0..MAX_ASSETS; empty = call contracts, move nothing ++ struct AssetCap { address token; uint256 maxPerCall; uint256 maxTotal; } // token: PRC20 on Push; maxTotal 0 = no total cap ++ uint8 constant MAX_ASSETS = 8; + +// metering +~ amount gate: the token being moved must be one of assets[]; per-call and running total checked against that entry +~ _spent[configId] becomes per token: mapping(address token => uint256 spent) +~ assertSpent(configId, account) returns the per-token totals; the existing single-amount overload goes +~ OutboundMetered carries the token +``` + +**2. `maxGasPerCall` replaces `maxPCPerCall`.** + +Rename only. Same meaning: the PC (wei) the wallet may pass as `msg.value` on one outbound for the destination leg. The gate that checks it does not change. + +```diff +- uint256 maxPCPerCall; ++ uint256 maxGasPerCall; +``` + +**3. The struct, as it ends up.** + +SDK side, what `create` takes per rule (page 5, 3.b). `agent` and `ref` go to `grantRules`, the rest is encoded into the rules envelope. + +```tsx +interface UniversalRule { + agent: Address; // Push address: EOA, or the UEA of an external key + ref?: Hex; // emitted in RulesGranted, not interpreted + chainNamespace: ForeignChainNamespace; + assets: AssetCap[]; // tokens the agent may move on chainNamespace; 0..8 + maxGasPerCall: bigint; // PC (wei) per outbound for the destination leg + validUntil: number; + allowedCalls: AllowedCall[]; +} + +interface AssetCap { + token: MoveableToken | Address; // the other chain's token address (MOVEABLE.TOKEN..) or the native marker + maxPerCall: bigint; + maxTotal?: bigint; +} +``` + +Contract side, what URP decodes from the envelope body for an `eip155` namespace (`SvmTerms` takes the same `assets` and `maxGasPerCall` fields). + +```solidity +struct AssetCap { + address token; // PRC20 on Push, resolved by the SDK from the other chain's address + uint256 maxPerCall; + uint256 maxTotal; // 0 = no running cap +} + +struct UniversalTerms { + uint48 validUntil; + bytes32 expectedCEA; + AssetCap[] assets; // 0..MAX_ASSETS; empty = call contracts, move nothing + uint256 maxGasPerCall; // PC (wei) per outbound + AllowedCall[] allowedCalls; // unchanged +} + +uint8 constant MAX_ASSETS = 8; +``` + +# 5. Open for review on this page + +1. D3: removing the validator. Needs the v3 branch check on how SmartSession's engine is entered (signature path vs a sender-gated call into the same policy checks). If the engine cannot be entered without a signature, the fallback is a validator that accepts a trivial signature from the sender, which keeps the identity model and loses nothing but elegance. +2. Checkpoint kinds, since they are the evaluator's contract with the wallet. +3. `creditRevert`: wire the executor module, or replace the credit path. +4. Anything in the rename map or the diff that should stay as is. + +The SDK surface lives on page 5 (SDK: AGW). \ No newline at end of file diff --git a/plan/agw/notion/2-universal-marketplace.md b/plan/agw/notion/2-universal-marketplace.md new file mode 100644 index 00000000..7bd55c00 --- /dev/null +++ b/plan/agw/notion/2-universal-marketplace.md @@ -0,0 +1,90 @@ +# 2. Universal Marketplace + + + +Status: DESIGN. No contract, no repo, no owner assigned. Blocking Zaryab since 2026-09-17 on one decision (section 3). + +# What it is + +The discovery layer. Agents list what they do and what access they need. Users pick a card and start a job in one signature. It is also the place a human-verified badge lives, so unverified cards are shown with a caution. + +Phase 2 (not now): users post a job and agents bid. Every design choice below must not block it, but nothing is built for it. + +# What it does, in four responsibilities + +| Responsibility | What it means | On-chain or off-chain | +| --- | --- | --- | +| Registry | Stores agent cards, signed by the agent's execution key. Versioned. Carries the verified badge. | On-chain hash plus signature; card content on-chain or off-chain (open) | +| Compiler | `compile(card, userInput)` turns a card plus the user's principal, duration and choices into: the rules for the AGW, the evaluation criteria for the job, and a `criteriaHash`. Pure and deterministic. | On-chain pure view, so the SDK, the preview and the 8183 hook all get the same answer | +| Start job | Deploy or reuse the AGW, fund it, grant the compiled rules, create the 8183 job with the criteria in the description. One signature. | See section 3 | +| Preview | Shows the user, in words, exactly what the agent may do (every contract, function, pinned argument, cap, expiry) and what the evaluator will check. | Off-chain, from the compiler's output | + +# The agent card + +What the agent publishes. Field names follow the O9 draft; the criteria block is new (2026-09-28). + +```json +{ + "cardVersion": 1, + "provider": { "account": "0xProviderUEA", "executionKey": { "scheme": 0, "key": "0xAgentKey" }, "signature": "0x..." }, + "offer": { + "title": "Aave v3 yield optimiser", + "fee": { "asset": "0xPaymentToken", "amount": "5000000" }, + "principal": { "min": "100000000", "max": "50000000000" }, + "durationDays": { "min": 7, "max": 90, "default": 30 } + }, + "rulesTemplate": { + "chainNamespace": "eip155:11155111", + "asset": "0xUsdcOnPush", + "actions": [ { "contract": "0xAavePool", "function": "supply(address,uint256,address,uint16)", + "args": { "asset": { "role": "fixed", "value": "0xUSDC" }, "amount": { "role": "amount" }, + "onBehalfOf": { "role": "beneficiary" }, "referralCode": { "role": "fixed", "value": 0 } } } ], + "gas": { "pcPerAction": "4000000000000000000", "expectedActions": 12 } + }, + "criteriaTemplate": { + "minDuration": 2592000, + "conditions": [ { "read": { "chainNamespace": "eip155:11155111", "target": "0xaUSDC", "call": "balanceOf(ACCOUNT)" }, + "sample": "START_AND_END", "compare": { "op": "GTE", "basis": "PCT", "value": 400 } } ] + } +} +``` + +Roles on arguments: `beneficiary` (the user's account, filled by the compiler), `amount` (metered against the user's principal), `fixed` (a constant the provider requires), `userChoice` (picked by the user from a list), `free` (the agent decides at run time). Placeholders `ACCOUNT` and `PRINCIPAL` in the criteria are filled by the compiler. + +The user supplies only: principal, duration, any `userChoice` values, and which AGW (new or existing). + +# The decision that unblocks everything: where startJob runs + +The facts (from the code): `deployWallet` makes the caller the owner; `grantRules` is owner-only; `execute` drops return data so a jobId cannot feed a later call in the same batch; `fund` needs `setBudget` from the provider first. + +| | A. SDK-orchestrated | B. Marketplace-orchestrated | +| --- | --- | --- | +| How | The user's UEA signs one multicall: deployWallet, fund, grantRules, execute(createJob). The marketplace is registry, compiler and preview only. | `UniversalMarketplace.startJob(auth, cardId, userInput)` verifies one EIP-712 authorization from the owner and calls the WithSig variants on factory and wallet. | +| Contract changes | None on the AGW | Needs `deployWalletWithSig`, `grantRulesWithSig`, `executeWithSig` (page 1, section 4b) | +| Push-native users | Several transactions (no UEA to batch) | One signature | +| External-origin users | One signature | One signature; the WithSig variants must accept ERC-1271 because the UEA is a contract | +| Audit surface | Smaller now | One canonical path, one place for the one-live-job-per-AGW check | + +Recommendation: B is the end state and Harsh's stated requirement. A is the faster first ship if the demo user is external-origin. If the demo user is Push-native, go straight to B. + +# Provider acceptance + +With a fixed fee there is no moment where the provider says yes to a specific job. Rule: the provider accepts by signing the card, which carries the criteria template and the bounds on principal and duration. At fund, the 8183 hook recomputes `compile(card, userInput)` and refuses the job if the `criteriaHash` in the description does not match. This is why `compile` must be an on-chain view. Vanilla jobs without a card use `setBudget` as the acceptance step. + +# Open + +1. Start job: A first or B from day one (depends on the demo user). +2. Card storage: fully on-chain, or hash on-chain with content off-chain. +3. Canonical encoding of the card for hashing and signing (ABI vs JSON). SDK, marketplace and hook must agree. +4. Vetting: curated list of contracts and functions, warning tier, or badge only. +5. Bid mode in v1 at all. If not, `setProvider` leaves the flow. +6. Which repo, which owner. \ No newline at end of file diff --git a/plan/agw/notion/3-8183-job-kernel-and-hook.md b/plan/agw/notion/3-8183-job-kernel-and-hook.md new file mode 100644 index 00000000..eb401de5 --- /dev/null +++ b/plan/agw/notion/3-8183-job-kernel-and-hook.md @@ -0,0 +1,59 @@ +# 3. 8183 (job kernel and hook) + + + +Status: BUILT on `push-chain-core-contracts` branch `8183-v1` (commit 01439d1) with tests. Not deployed. Hook is PARTIAL. + +# What exists (verified in source) + +**Kernel `AgenticCommerce.sol`**: Base V3 shape with the K-01 to K-11 changes. + +- Transparent proxy. One payment token, set at initialize. Platform fee and evaluator fee in bps, start at 0. +- Hooks fire on setProvider, setBudget, fund, submit, complete, reject. Not on createJob, not on claimRefund. +- claimRefund is never pausable. 1-hour grace after expiry for Submitted jobs. 5-minute minimum expiry window. +- Evaluator may equal the client. Evaluator fee is paid to whoever calls complete. + +**Hook `MandateBindingHook.sol`**: acts only in `beforeAction(fund)`. `optParams` must be exactly 32 bytes (the rules id). Checks three things: the client is a factory wallet, the rules are enabled on the engine, the AGW has no Funded or Submitted job. Stores `mandateOf[jobId]` and `liveJobOf[agw]`. + +# What the hook must also do (not implemented yet) + +| Check | Why | Where | +| --- | --- | --- | +| Rules key equals the provider's registered execution key | Otherwise a different agent works while the job's provider is paid. Harsh: the one hard restriction for using 8183 with AGW. | beforeAction(fund) | +| Rules `validUntil` at or before job `expiredAt` | Rules must outlive the job. | beforeAction(fund) | +| Rules chain matches the criteria's execution chain | A job on Base cannot run under Sepolia rules. | beforeAction(fund) | +| Criteria hash matches `compile(card, userInput)` for card jobs | Provider acceptance (page 2). | beforeAction(fund) | +| Register criteria with the evaluator and fire START reads | Job start is fund. | afterAction(fund) | +| Refuse submit before START reads landed and before `minDuration` | No baseline, no grade. Blocks early-submit gaming. | beforeAction(submit) | +| Free the rules when the job ends | Needs the binder role on the AGW (page 1). | afterAction(complete or reject) | + +The hook uses exactly these kernel touchpoints: afterAction(fund), beforeAction(submit), afterAction(complete or reject). Nothing else. + +# Flow decisions (2026-09-28) + +- Job start is fund, not createJob. Provider may be zero at createJob. +- Criteria travel in the kernel's `description` as the hex of `abi.encode(Criteria)`. One carrier. The hook reads `getJob(jobId).description` at fund, decodes, validates, registers. Portable to Base and any other 8183 kernel. +- Started is an evaluator fact, not a kernel state: the evaluator emits `PreRecorded(jobId)` when the last START read lands. The hook refuses submit until then. The agent SDK waits for the event. +- Checkpoint rule: before any END read, the evaluator checks the AGW's checkpoints. Any owner-side change after PreRecorded (principal moved, rules changed, key changed) means complete, provider paid, no reads. This is also the answer to "rules changed mid-job": no rebind, the fee ends in the agent's favour. +- setProvider is only for bid mode. In direct mode createJob carries the provider. +- Reputation writes only for jobs judged by the UniversalEvaluator from a registered card. + +# Fits the standard + +Push implements the Evaluator role in ERC-8183. The kernel ABI is Base V3's with the K changes. Nothing here changes the standard's function signatures. + +# Open + +1. Fee token: PUSD by default (gas is always PC). The kernel is single-token per deployment; USDC.eth or others mean a second kernel deployment or a multi-token kernel change. Decide which. +2. Fixed fee on the card (no setBudget) or provider quote after createJob. If quote: pre-signed quote inside the user's signature, or fundIfQuoted. +3. Who pays reads and whether the evaluator takes a fee (parked, not needed for the POC). +4. Portability constraint for Base later: the evaluator keys jobs by (chainNamespace, kernel, jobId), not local jobId, and its entry points are callable by a wrapper contract through the universal gateway. \ No newline at end of file diff --git a/plan/agw/notion/4-universal-evaluation.md b/plan/agw/notion/4-universal-evaluation.md new file mode 100644 index 00000000..c4949edb --- /dev/null +++ b/plan/agw/notion/4-universal-evaluation.md @@ -0,0 +1,86 @@ +# 4. Universal Evaluation + + + +Status: DESIGN. Converged on 2026-09-28 to one generic evaluator. No code. Supersedes UniversalEvaluator 1st and 2nd Architecture and the Hook Design where they differ. + +# In one paragraph + +The evaluator is dumb on purpose. A job's success test is data: an array of conditions, each one "read this value, at these points, and compare it like this". Reads come from Read State (validators attest at a pinned block). The evaluator compares and calls complete or reject. A new job type is new data, never a new contract. In v1 this is the deterministic lane only: validator-attested facts plus on-chain comparison. No committee, no staking, no commit-reveal. Say so externally. + +# The schema (draft v0) + +```solidity +struct Criteria { + uint16 version; // 1 + uint32 minDuration; // seconds after fund before submit is accepted + Condition[] conditions; // 1..8, all must hold +} +struct Condition { Read read; Sample sample; Compare cmp; } + +struct Read { + string chainNamespace; // "eip155:1" | "solana:..." | "push" (local, no fee) | "web2" + uint8 queryType; // 0 ACCOUNT_BALANCE, 1 CONTRACT_CALL, 2 STORAGE_SLOT + bytes target; // 20 bytes EVM, 32 bytes SVM + bytes callData; // CONTRACT_CALL only; ACCOUNT and PRINCIPAL placeholders resolved at compile + uint16 word; // which 32-byte word of the return to keep + uint8 resultType; // 0 UINT, 1 INT, 2 BOOL, 3 ADDRESS, 4 BYTES32 +} +enum Sample { END, START_AND_END, PERIODIC } // PERIODIC reserved, refused in v1 + +struct Compare { + uint8 op; // EQ NEQ GT GTE LT LTE IS_TRUE IS_FALSE + uint8 basis; // ABSOLUTE (end vs value) | DELTA (end - start vs value) | PCT (bps of start) | REF (vs another condition) + int256 value; + uint8 ref; + uint32 period; // reserved for PERIODIC + uint16 minPassBps; // reserved for PERIODIC +} +``` + +# The four families named, as data + +| Family | Example | Condition | +| --- | --- | --- | +| True or false | Position is in range | read tick or state, sample END, op IS_TRUE (or REF between two reads) | +| Greater or less than | At least 1 WETH out | read WETH.balanceOf(ACCOUNT), START_AND_END, basis DELTA, op GTE, value 1e18 | +| Percentage | 4% on principal | read position balance, START_AND_END, basis PCT, op GTE, value 400 (bps, for the job's duration) | +| Absolute number | Deliver 100 USDC | read USDC.balanceOf(ACCOUNT), START_AND_END, basis DELTA, op GTE, value 100e6 | + +# Rules of evaluation + +- START reads fire at fund. The job is started when the last one lands (`PreRecorded`). END reads fire at submit. The verdict runs in the last END callback. +- The card author picks where each sample is taken. A PCT condition whose START value is zero fails; it does not revert. That is the author's mistake, not the evaluator's. +- Percentages are for the job's duration, not annualised. `minDuration` blocks early submit. +- END reads take three consecutive blocks, and the condition must hold at all three (from the 2nd Architecture). Cheap protection against one-block manipulation of protocol state. +- Before any END read: check the AGW's checkpoints. Any owner-side change after PreRecorded means complete, no reads. +- Push-local reads (`push` namespace) are direct staticcalls, no fee, no callback. +- A START read that errors or expires can be refired by anyone, paying the fee. If START never completes, the job cannot be submitted and expires to claimRefund. + +# Not in v1, reserved + +- PERIODIC sampling (rebalanced every day, true 90% of the time). Needs a scheduler. Fields are reserved so it slots in without a schema break. +- Solana reads that need `RAW_ACCOUNT_DATA` (fields inside program-owned accounts). Needs a slice query type in Read State. `LAMPORT_BALANCE` and `SPL_TOKEN_ACCOUNT` work today. +- Judging causation or quality. The evaluator proves numbers, not work. A prompt-based read in Universal Callback is the future path. + +# Depends on + +- Read State answers: archive depth validators serve (U1), gas cap on contract-call reads (U2), how often tracked heights update (U3). Block-pinned reads cannot be specified without them. +- Kernel deployment and the hook (page 3). +- Checkpoints on the AGW (page 1). + +# Open + +1. Where the registered criteria live: evaluator (default, one address holds all job state) or hook. +2. Read budget: who pays, how much, refund of unused (parked). +3. Evaluator fee (parked). +4. The evaluator entry points must be callable through a gateway wrapper later (Base). Job key = (chainNamespace, kernel, jobId). \ No newline at end of file diff --git a/plan/agw/notion/5-sdk-agw.md b/plan/agw/notion/5-sdk-agw.md new file mode 100644 index 00000000..823222c1 --- /dev/null +++ b/plan/agw/notion/5-sdk-agw.md @@ -0,0 +1,732 @@ +# 5. SDK: AGW + + + +# List of changes + +New + +- `client.agentic.derive` +- `client.agentic.create` +- `client.agentic.list` +- `client.agentic.wallet`, + - a management handle with + - `info`, + - `owner`, + - `setLabel` (PROPOSED), + - `checkpoints`, + - `rules.list`, + - `rules.get`, + - `rules.add`, + - `rules.update`, + - `rules.revoke` +- `PushChain.CONSTANTS.AGENTIC` +- `PushChain.utils.agentic` + +Updated + +- `PushChain.initialize`, new option `agenticWallet` +- `PushChain.CONSTANTS.READ.CHAIN`, outside change confirmed 2026-09-28 + +Initialize is unchanged on the owner side: + +```tsx +const client = await PushChain.initialize(universalSigner, { network: PushChain.CONSTANTS.PUSH_NETWORK.TESTNET }); +``` + +| Signer | Door | Rules checked | +| --- | --- | --- | +| The wallet's owner | Owner door (`execute`) | No. Every send is recorded as a checkpoint | +| An address named as `agent` in one of the wallet's rules | Agent door (`executeAsAgent`) | Yes, by URP (UniversalRulesPolicy, the on-chain rule checker) | +| Anyone else | None | Never reached: `initialize` throws `NOT_OWNER_OR_AGENT` | + +An agentic wallet involves three parties, and it helps to have them straight before reading the functions. + +The **owner** is whoever created the wallet. When the owner sends through the wallet, no rules are checked; this is called the owner door, and the contract records every such action as a checkpoint so that an evaluator can later tell whether the owner touched anything mid-job. + +The **agent** is the address the owner allows to act on its behalf. It is always a Push address. If the agent's key is a Push EOA, that EOA is the agent. If the key lives on another chain (an EVM key on Ethereum, a Solana key, anything else), the agent is that key's UEA on Push, which exists deterministically for every external key. The SDK never asks for a curve, a chain or a key type. When the agent sends through the wallet, the rules are checked; this is the agent door. + +The **rules** say what an agent may do. Each rule names its agent and its destination chain, and there is one rule per chain per agent, so a wallet can have one agent for Ethereum and a different one for Solana. The `chainNamespace` on a rule decides which rulebook applies: leave it out and the rule governs calls on Push itself; set it to an `eip155` or `solana` chain and the rule governs cross-chain calls to that chain. + +Two ways to touch a wallet from the SDK. `PushChain.initialize(signer, { agenticWallet })` returns a client that acts as the wallet, and whether it goes through the owner door or the agent door depends on who the signer is. `client.agentic.wallet(address)` returns a handle for managing the wallet (rules, label, checkpoints) and never sends as it. + +# 1. Owner side, by example + +The owner side is everything the person who owns the wallet does: create it, fund it, write and revoke the rules, look at what happened. The agent side (section 2) is what the agent does: act through the wallet within those rules. + +### 1.a Derive an agentic wallet address - `client.agentic.derive` + +Gives you the address a wallet will have before it is deployed. The address depends only on the owner and an index. + +```tsx +// Function +const first = await client.agentic.derive({ options? }) + +// Usage and Params +const next = await client.agentic.derive(); // the owner's next wallet +const first = await client.agentic.derive({ index: 0 }); // a specific slot +// options.index number, optional which wallet slot to derive; default is the owner's next unused index + +// Returns +// { address, index, deployed } +{ + address: '0x2Fd904d6f2C0b34d58426C8Ae9c5267E845CE98f', + index: 0, + deployed: false +} +``` + +Because the address depends only on the owner and an index, it is the same whether you deploy first or later. That lets you send funds to it first (from any chain) and deploy afterwards, or show the address in a UI before anything is on-chain. Same idea as `deriveExecutorAccount` for a UEA. + +### 1.b Create an agentic wallet - `client.agentic.create` + +Deploys the wallet and grants the rules. The label is the only wallet-level input; the agent and an optional `ref` are named on each rule, because that is where the contract binds them. + +```tsx +// Function +const created = await client.agentic.create(label, { options }) + +// Usage and Params +const created = await client.agentic.create('aave-optimiser', { // wallet with one cross-chain rule + rules: [{ // one entry per chain per agent + agent: '0xAgentOnPush', // a Push address: the agent's EOA, or its UEA if the key lives on another chain. Never the owner + ref: jobRef, // emitted in RulesGranted, not interpreted + chainNamespace: CHAIN.ETHEREUM_SEPOLIA, // foreign chain => universal rulebook + assets: [ + { token: MOVEABLE.TOKEN.ETHEREUM_SEPOLIA.USDC, maxPerCall: parseUnits('100', 6), maxTotal: parseUnits('1000', 6) }, + { token: MOVEABLE.TOKEN.ETHEREUM_SEPOLIA.WETH, maxPerCall: parseUnits('0.5', 18) }, + ], + maxGasPerCall: parseUnits('1', 18), // PC (wei) per outbound for the destination leg + validUntil: now + 30 * 86400, + allowedCalls: [ + { target: aavePool, selector: 'supply(address,uint256,address,uint16)', beneficiary: 2 }, // arg index, not offset: onBehalfOf must be the AGW's CEA + { target: usdcSepolia, selector: 'approve(address,uint256)' }, + ], + }], + progressHook: (p) => console.log(p.id, p.message), // AGENTIC-TX-1xx +}); +const bare = await client.agentic.create('scratch', { rules: [] }); // wallet first, rules later with rules.add +// label string, required shown in list() and info(); the contract stores it +// options.rules Rule[], required one per chain per agent, may be empty; each rule carries its own agent and optional ref +// options.progressHook function, optional progress events, AGENTIC-TX-1xx; default none +// rules[].agent Address, required the Push address allowed to act under this rule; never the owner +// rules[].ref Hex, optional emitted in RulesGranted, not interpreted; default zero +// rules[].assets AssetCap[], required on a universal rule tokens the agent may move, as the other chain's address (MOVEABLE constants); the SDK resolves each to its PRC20 on Push; each cap is { token, maxPerCall, maxTotal? } +// rules[].maxGasPerCall bigint, required on a universal rule PC (wei) the wallet may spend per outbound for the destination leg + +// Returns +// { wallet, index, rulesIds, tx } +{ + wallet: '0x2Fd904d6f2C0b34d58426C8Ae9c5267E845CE98f', + index: 0, + rulesIds: ['0x9c1e...'], // in the order of the rules you passed; empty for rules: [] + tx: { // UniversalTxResponse + hash: '0xb527...', + origin: 'eip155:11155111:0x31dC...', // the owner's key, CAIP-10 + from: '0xFd6C2fE69bE13d8bE379CCB6c9306e74193EC1A9', // the owner's Push account + blockNumber: 1290n, + wait // await tx.wait() for the receipt; status lives on the receipt + } +} +``` + +One rule per chain per agent. A wallet may have different agents on different chains. If an agent needs to act on two chains, `rules` has two entries with the same `agent`; two agents on one chain are two entries with the same `chainNamespace`. Nobody states a rule type; the SDK reads it from `chainNamespace`. `rules: []` is allowed: create the wallet first and grant rules later with `rules.add` (1.k). + +Before asking for a signature the SDK checks that no rule's agent is the owner (`AGENT_IS_OWNER`), that no two rules share both agent and chain (`DUPLICATE_RULE`), that every `allowedCalls[].target` is on the rule's chain (`TARGET_NOT_ON_RULE_CHAIN`), and that every `assets[].token` resolves to a PRC20 whose `SOURCE_CHAIN_NAMESPACE` matches the rule's chain (`ASSET_CHAIN_MISMATCH`). + +Under the hood this is `deployWallet` (or reuse of a derived address) and one `grantRules` per rule. For an external owner they go as one UEA multicall under one signature. Funding is not part of `create`: the wallet is a normal Push account, so send tokens and PC to its address the way you would to any account (1.a shows the address before deployment). + +For a Push EOA owner the same thing needs a batching entry on the factory, because core rejects multicall from a Push-native sender: [1. AGW Contract Changes (nomenclature standard + change set)](1-agw-contract-changes.md) item 11, **PROPOSED** (`createWallet(label, rules[])` on the factory). Until it lands the SDK sends deploy and grant as separate transactions and says so through progress events (AGENTIC-TX-102 and 104); `tx` is then the last of them. + +A `progressHook` passed to `PushChain.initialize` receives the same events alongside the per-call one, as in core. + +Warning for an agent whose key lives on another chain: the same EVM key initialized against two chains yields two UEAs, because a UEA is derived from namespace, chainId and owner. Grant the rule to the UEA of the chain the agent will run against. `PushChain.utils.account.deriveExecutorAccount(PushChain.utils.account.toUniversal(address, { chain }))` gives it. + +### 1.c List an owner's wallets - `client.agentic.list` + +Lists the wallets owned by the connected signer. It takes no arguments and only reads the connected account. + +```tsx +// Function +const res = await client.agentic.list() + +// Usage and Params +const { wallets } = await client.agentic.list(); // the connected signer's wallets +// no params + +// Returns +// { wallets: Array<{ address, index, label, deployed, rulesCount }> } +{ + wallets: [ + { address: '0x2Fd9...', index: 0, label: 'aave-optimiser', deployed: true, rulesCount: 1 }, + { address: '0x81aB...', index: 1, label: '', deployed: false, rulesCount: 0 }, + ] +} +``` + +Client methods act on the connected account; reads about any other account live in `PushChain.utils`. If a read-only view is needed later (a marketplace or explorer page showing the wallets of an address with no signer), it becomes `PushChain.utils.agentic.wallets(owner: Address)` taking a Push address; an external owner passes its UEA. Not in v1. + +### 1.d Get a wallet handle - `client.agentic.wallet` + +Returns a handle for one wallet: the reads that are specific to an agentic wallet, plus the rule writes only an owner can do. It is not a client and never sends as the wallet. + +```tsx +// Function +const w = client.agentic.wallet(address) + +// Usage and Params +const w = client.agentic.wallet('0xWallet'); // handle for one wallet; nothing is sent +// address Address, required the AGW to manage, a Push address + +// Returns +// { address, info(), owner(), setLabel(), checkpoints(), rules.* } +{ + address: '0xWallet', + info, owner, setLabel, checkpoints, // 1.e to 1.h + rules: { list, get, add, update, revoke } // 1.i to 1.m +} +``` + +There is one way to send as the wallet: `PushChain.initialize(signer, { agenticWallet })` (section 2). The handle only manages. To send as the wallet, move funds, reach the wallet's CEA on another chain, or read balances, initialize with `agenticWallet` and use the normal account tooling: `sendTransaction`, `universal.read`, or viem and ethers against `client.universal.account`. That gives the owner the full `sendTransaction` with every route the SDK already has, the same receipts, and the wallet's CEA reachable exactly as it is for any other account. + +Balance reads are deliberately not on the handle: they are not agentic, and every account is read the same way. There is no `w.execute` for the same reason. The handle stays what its name says: management. + +### 1.e Read wallet info - `w.info` + +Returns the wallet's summary in one read: the fields `list()` shows for each wallet, plus the owner. It is how you read the label from the handle. + +```tsx +// Function +const info = await w.info() + +// Usage and Params +const { label, deployed } = await w.info(); // one wallet's summary +// no params + +// Returns +// { address, label, index, owner, deployed, rulesCount } +{ + address: '0x2Fd904d6f2C0b34d58426C8Ae9c5267E845CE98f', + label: 'aave-optimiser', + index: 0, + owner: '0xFd6C2fE69bE13d8bE379CCB6c9306e74193EC1A9', + deployed: true, + rulesCount: 1 +} +``` + +### 1.f Read the owner - `w.owner` + +Returns the owner's Push address, as the contract stores it. + +```tsx +// Function +const res = await w.owner() + +// Usage and Params +const { owner } = await w.owner(); // the Push address stored as owner +// no params + +// Returns +// { owner } +{ + owner: '0xFd6C2fE69bE13d8bE379CCB6c9306e74193EC1A9' +} +``` + +If the owner is a UEA and you need the controlling origin behind it (the chain and the external key), use `resolveControllerAccount` on the returned address. + +Page rule: identities going in and out of the agentic namespace are Push addresses (owner, agent, wallet). + +### 1.g Set the wallet label - `w.setLabel` + +**PROPOSED**, contract change, see [1. AGW Contract Changes (nomenclature standard + change set)](1-agw-contract-changes.md) item 10. Changes the label shown in `list()` and `info()`; owner only. + +```tsx +// Function +const tx = await w.setLabel(label, { options? }) + +// Usage and Params +const tx = await w.setLabel('aave-optimiser-v2'); // rename the wallet +const tracked = await w.setLabel('aave-optimiser-v2', { progressHook: (p) => console.log(p.id) }); // with progress events +// label string, required the new label; stored by the contract and emitted in LabelSet +// options.progressHook function, optional progress events, AGENTIC-TX-106; default none + +// Returns +// { hash, origin, from, to, blockNumber, wait() } +{ + hash: '0x3b8d...', + origin: 'eip155:11155111:0x31dC...', // the owner's key, CAIP-10 + from: '0xFd6C2fE69bE13d8bE379CCB6c9306e74193EC1A9', // the owner's Push account + to: '0x2Fd904d6f2C0b34d58426C8Ae9c5267E845CE98f', // the wallet + blockNumber: 1488n, + wait // await tx.wait() for the receipt; status lives on the receipt +} +``` + +Emits `LabelSet(string label)`. It is not a checkpoint: the label is cosmetic metadata and evaluators ignore it. Today the label can only be set once, at `deployWallet`, and is emitted in `WalletDeployed`. + +### 1.h Read checkpoints - `w.checkpoints` + +Every owner-side change the wallet has recorded: owner-door sends, rules granted, rules revoked. An evaluator reads these to know whether the owner changed anything after a job started (page 4). + +```tsx +// Function +const res = await w.checkpoints({ options? }) + +// Usage and Params +const all = await w.checkpoints(); // every checkpoint +const recent = await w.checkpoints({ sinceBlock: 1234n }); // from a block onward +// options.sinceBlock bigint, optional only checkpoints at or after this block; default all + +// Returns +// { checkpoints: Array<{ seq, kind, ref, blockNumber, txHash }> } +{ + checkpoints: [ + { seq: 3, kind: 'RULES_GRANTED', ref: '0x9c1e...', blockNumber: 1290n, txHash: '0x...' }, + { seq: 4, kind: 'OWNER_ACTION', ref: '0x5a7b...', blockNumber: 1402n, txHash: '0x...' }, + ] +} +``` + +### 1.i List rules - `w.rules.list` + +Returns every rule on the wallet as a decoded record, including what each rule has spent so far. + +```tsx +// Function +const res = await w.rules.list() + +// Usage and Params +const { rules } = await w.rules.list(); // the wallet's rules +// no params + +// Returns +// { rules: RulesRecord[] } +{ + rules: [ + { + rulesId: '0x9c1e...', + enabled: true, + chainNamespace: 'eip155:11155111', + agent: '0xAgentOnPush', + validUntil: 1767225600, + ref: '0x4a2f...', + rule: { /* decoded UniversalRule, as passed to create */ }, + spent: { kind: 'universal', amountSpent: 25000000n } // shape PROPOSED, see 3.b + } + ] +} +``` + +### 1.j Get one rule - `w.rules.get` + +Returns one rule by id, decoded, with what it has spent. + +```tsx +// Function +const record = await w.rules.get(rulesId) + +// Usage and Params +const record = await w.rules.get('0x9c1e...'); // one rule by id +// rulesId Hex, required the id returned by create or rules.add + +// Returns +// RulesRecord +{ + rulesId: '0x9c1e...', + enabled: true, + chainNamespace: 'eip155:11155111', + agent: '0xAgentOnPush', + validUntil: 1767225600, + ref: '0x4a2f...', + rule: { /* decoded UniversalRule */ }, + spent: { kind: 'universal', amountSpent: 25000000n } // shape PROPOSED, see 3.b +} +``` + +`spent` is a field on the record, so `get` and `list` both carry it. There is no separate spent call. + +### 1.k Add rules - `w.rules.add` + +Grants new rules on an existing wallet under one signature. The rules array comes first; `agent` and `ref` live on each rule. + +```tsx +// Function +const res = await w.rules.add(rules, { options? }) + +// Usage and Params +const one = await w.rules.add([nativeRule]); // one rule +const many = await w.rules.add([ruleOnSepolia, ruleOnPush]); // several rules, one signature +const tracked = await w.rules.add([nativeRule], { progressHook: (p) => console.log(p.id, p.message) }); // with progress events +// rules Rule[], required one per chain per agent; each rule carries its own agent and optional ref +// options.progressHook function, optional progress events, AGENTIC-TX-104; default none + +// Returns +// { rulesIds, tx } +{ + rulesIds: ['0x7d3a...'], // in the order of the rules you passed + tx: { // UniversalTxResponse + hash: '0x4c19...', + origin: 'eip155:11155111:0x31dC...', + from: '0xFd6C2fE69bE13d8bE379CCB6c9306e74193EC1A9', + blockNumber: 1501n, + wait + } +} +``` + +Records a `RULES_GRANTED` checkpoint. + +### 1.l Update rules - `w.rules.update` + +Replaces rules in a batch: each pair names one old rule and the one new rule that takes its place. + +```tsx +// Function +const res = await w.rules.update({ rules, progressHook? }) + +// Usage and Params +const one = await w.rules.update({ rules: [{ rulesId: '0x9c1e...', rule: newRule }] }); // replace one rule +const many = await w.rules.update({ rules: [{ rulesId: idA, rule: ruleA }, { rulesId: idB, rule: ruleB }] }); // replace several, one signature +const tracked = await w.rules.update({ rules: [{ rulesId: idA, rule: ruleA }], progressHook: (p) => console.log(p.id) }); // with progress events +// rules Array<{ rulesId, rule }>, required one old rule to one new rule per pair +// rules[].rulesId Hex, required the rule being replaced +// rules[].rule Rule, required the replacement; one rule per agent per chain still applies +// progressHook function, optional progress events, AGENTIC-TX-105 and 104; default none + +// Returns +// { rules: Array<{ rulesId, replaced }>, tx } +{ + rules: [ + { rulesId: '0x51c0...', replaced: '0x9c1e...' }, // new id, old id + ], + tx: { // UniversalTxResponse + hash: '0x7a02...', + origin: 'eip155:11155111:0x31dC...', + from: '0xFd6C2fE69bE13d8bE379CCB6c9306e74193EC1A9', + blockNumber: 1507n, + wait + } +} +``` + +Rules are immutable on-chain, so an update is a revoke plus a grant: for each pair the SDK asserts the old rule's spend, revokes it and grants the new one, all pairs in one multicall. The result is a new `rulesId` per pair, and the spend counters reset on the new rule: what the old rule had spent does not carry over. This is accepted for v1 (open item 1); an in-place update would be a contract change and there is no demand for it yet. + +### 1.m Revoke rules - `w.rules.revoke` + +Revokes some rules by id, or all of them in one atomic call. + +```tsx +// Function +const tx = await w.rules.revoke(rulesIds, { options? }) +const tx = await w.rules.revoke({ all, progressHook? }) + +// Usage and Params +const some = await w.rules.revoke(['0x9c1e...', '0x7d3a...']); // revoke these rules +const all = await w.rules.revoke({ all: true }); // revoke every rule, on-chain revokeAllRules +const tracked = await w.rules.revoke(['0x9c1e...'], { progressHook: (p) => console.log(p.id) }); // with progress events +// rulesIds Hex[], required unless all is set the rules to revoke +// options.progressHook function, optional progress events, AGENTIC-TX-105; default none +// all true, required unless rulesIds given revoke every rule on the wallet in one atomic call +// progressHook function, optional same events, in the { all: true } form; default none + +// Returns +// { hash, origin, from, to, blockNumber, wait() } +{ + hash: '0x8e01...', + origin: 'eip155:11155111:0x31dC...', // the owner's key, CAIP-10 + from: '0xFd6C2fE69bE13d8bE379CCB6c9306e74193EC1A9', // the owner's Push account + to: '0x2Fd904d6f2C0b34d58426C8Ae9c5267E845CE98f', // the wallet + blockNumber: 1512n, + wait // await tx.wait() for the receipt; status lives on the receipt +} +``` + +A bare `revoke()` is not allowed and throws `REVOKE_NEEDS_TARGET`: a call with no argument that wipes every rule is too easy to make by mistake. Records `RULES_REVOKED` checkpoints. + +# 2. Agent side, by example + +There is no new method on the agent side. The agent uses its own signer and tells `initialize` which wallet to act through. It does not name a rule: which rule applies is decided per transaction, from the destination chain. + +### 2.a Act as the wallet - `PushChain.initialize` with `agenticWallet` (updated) + +Returns a client whose account is the wallet. Whether its sends go through the owner door or the agent door depends on who the signer is. + +```tsx +// Function +const client = await PushChain.initialize(signer, { options }) + +// Usage and Params +const agentClient = await PushChain.initialize(agentSigner, { // agent door: the signer is named as agent in a rule + network: PushChain.CONSTANTS.PUSH_NETWORK.TESTNET, + agenticWallet: '0xWallet', +}); +const ownerClient = await PushChain.initialize(ownerSigner, { // owner door: the signer owns the wallet + network: PushChain.CONSTANTS.PUSH_NETWORK.TESTNET, + agenticWallet: '0xWallet', +}); +``` + +`agentSigner` is any signer `initialize` accepts today. If the key lives on another chain, the SDK derives its UEA and everything goes through that, as it does for every external user. + +Which door the client uses depends on who the signer is. If the signer is the wallet's owner, sends go through the owner door: no rules, and every send is recorded as a checkpoint. If the signer is an address named as agent in one of the wallet's rules, sends go through the agent door and the rules apply. If it is neither, `initialize` throws `NOT_OWNER_OR_AGENT`. If the address has no wallet deployed yet it throws `WALLET_NOT_DEPLOYED`, and if the address is not an agentic wallet it throws `NOT_AGENTIC_WALLET`. This is also how an owner acts as the wallet with the full client: `PushChain.initialize(ownerSigner, { agenticWallet })`. There is one way to send as a wallet and the signer decides the door. + +On the agent door the SDK sends; URP on-chain is the only rule checker. Before sending, the SDK only looks up the `rulesId` for the destination chain: the rule that is enabled, whose `agent` equals the signer, and whose `chainNamespace` equals the destination. The lookup is one read on every send, not cached at initialize. If none is found it throws `NO_RULES_FOR_CHAIN` before any signature, so it costs nothing; otherwise it calls `executeAsAgent(rulesId, ...)` on the wallet. That is the agent door from D3 on [1. AGW Contract Changes (nomenclature standard + change set)](1-agw-contract-changes.md): there is no session validator, and the wallet only checks that `msg.sender` is the rule's agent. There is one rule per (agent, chain), so a signer and a destination match at most one rule. If the action breaks a rule, it reverts on-chain and the agent pays that gas. `sendTransaction` then throws `AgenticRevertError`, which extends core's `PushChainExecutionError` and carries URP's custom error in `decodedError`, so the agent sees which gate failed (3.f). + +From an external key, the call arrives through the agent's UEA. If the agent's UEA is not yet deployed, the first action takes the origin-chain fee lock once (minimum $1), which deploys the UEA and funds it with PC. Every later action requires PC in the UEA and is a direct Push transaction paid from that balance, with no origin transaction and no cross-chain wait. + +Two things for whoever runs the agent. The agent's UEA is a second balance to keep funded: the AGW's PC covers the wallet's outbound fees, not the agent's gas. And in `agenticWallet` mode the SDK turns `enforceGasCheck` on for every action except that one first action while the agent's UEA is not yet deployed, so an empty UEA fails loudly instead of silently falling back to a $1 origin lock and a confirmation wait on every action. + +Routing. In `agenticWallet` mode every send is wrapped as `executeAsAgent` (agent door) or `execute` (owner door), and for cross-chain legs the AGW itself calls the gateway. So the AGW's CEA executes on the destination and the AGW's PC pays as `msg.value`. The SDK never uses the signer's own Route 2, which would run through the agent's CEA instead of the wallet's. Any `from` (Routes 3 and 4) is rejected in `agenticWallet` mode with `FROM_NOT_ALLOWED`: it makes `msg.sender` a CEA, and the agent door check fails. + +What changes on the client in this mode: + +- `universal.account` is the wallet address string, so receipts show the AGW as `from`. `universal.origin` stays the signer's origin account. +- `getAccountStatus()` reports the signer's own UEA, not the wallet. +- The signer is whatever was passed to `initialize`. To top up the agent's UEA, find it with `PushChain.utils.account.deriveExecutorAccount(signer.account)` and send PC to it from a client initialized without `agenticWallet`. +- A Solana-keyed agent can act on Push and `eip155` destinations now, and on `solana:` destinations once the SVM rulebook ships. +- Agents read their own rules through `client.agentic.wallet(addr).rules.list()`. +- `tx.data` arrays and `tx.funds` (moving the AGW's PRC20) work as they do for any account. +- `payGasWith`, `migrateCEA`, `rescueFunds`, `prepareTransaction` and `executeTransactions` throw `NOT_ALLOWED_IN_AGENTIC_MODE`. + +```tsx +const tx = await agentClient.universal.sendTransaction({ // agent door, rule picked by the destination chain + to: { address: aavePool, chain: CHAIN.ETHEREUM_SEPOLIA }, + data: supplyData, +}); + +// tx: UniversalTxResponse +{ + hash: '0x6f2a...', + origin: 'eip155:11155111:0x7Be1...', // the agent's key, CAIP-10 + from: '0xWallet', // the AGW, not the signer + blockNumber: 1530n, + wait +} + +const receipt = await tx.wait(); +// receipt: UniversalTxReceipt +{ + status: 1, + hash: '0x6f2a...', + from: '0xWallet', + blockNumber: 1530n, + externalTxHash: '0x91c4...' // the leg executed by the AGW's CEA on Sepolia +} +``` + +The same EVM key initialized against two chains yields two UEAs (derived from namespace, chainId and owner), so the rule must name the UEA of the chain this client initializes against (see 1.b). + +# 3. Types + +### 3.a Client, options and namespace + +```tsx +type Address = `0x${string}`; +type Hex = `0x${string}`; +type ForeignChainNamespace = `eip155:${string}` | `solana:${string}`; +type ProgressHook = (p: ProgressEvent) => void; // ProgressEvent is core's shape: { id, title, message, level, response, timestamp } + +interface PushChainClient { + universal: UniversalNamespace; // in agenticWallet mode: account is the wallet + agentic: AgenticNamespace; // this page + market: MarketNamespace; // page 6 + job: JobNamespace; // page 7 + evaluation: EvaluationNamespace; // page 8 +} + +interface InitializeOptions { + network?: PUSH_NETWORK; + rpcUrls?: Partial>; + agenticWallet?: Address; // NEW: act as the wallet; door chosen by the signer's Push address + // enforceGasCheck is on when agenticWallet is set, except for the first action while the agent's UEA is not yet deployed (2.a) +} + +interface AgenticNamespace { + derive(opts?: { index?: number }): Promise<{ address: Address; index: number; deployed: boolean }>; + create(label: string, options: CreateOptions): Promise; + list(): Promise<{ wallets: WalletSummary[] }>; // connected signer only + wallet(address: Address): AgenticWallet; +} + +interface CreateOptions { + rules: Rule[]; // one entry per chain per agent, may be empty; each rule names its agent and optional ref + progressHook?: ProgressHook; // AGENTIC-TX-1xx +} + +// No AgentKey type, no curve, no chain. The agent is a Push address. A native key is its own EOA; any external key +// (EVM, Solana, anything) is its UEA, deterministic from (chain, owner), deployed lazily on first use. The AGW's agent +// door checks msg.sender == rules.agent; cross-VM signature verification already happened inside the UEA (page 1, D3). + +interface CreateResult { wallet: Address; index: number; rulesIds: Hex[]; tx: UniversalTxResponse } +interface WalletSummary { address: Address; index: number; label: string; deployed: boolean; rulesCount: number } +``` + +### 3.b Rules + +```tsx +type Rule = NativeRule | UniversalRule; // chainNamespace decides the rulebook: omitted = native, foreign = universal + +interface NativeRule { + agent: Address; // Push address: EOA, or the UEA of an external key (PushChain.utils.account.deriveExecutorAccount) + ref?: Hex; // emitted in RulesGranted, not interpreted + chainNamespace?: never; // omitted = the connected Push chain + target: Address; + selector: Selector | 'value-only'; + validUntil: number; + maxValuePerCall?: bigint; maxValueTotal?: bigint; maxCalls?: number; + pins?: { arg: number; expected: Hex | Address | bigint }[]; + amount?: { arg: number; maxPerCall: bigint; maxTotal?: bigint }; +} + +interface UniversalRule { + agent: Address; // same as NativeRule.agent + ref?: Hex; // same as NativeRule.ref + chainNamespace: ForeignChainNamespace; // "eip155:..." now; "solana:..." once the SVM rulebook ships + assets: AssetCap[]; // tokens the agent may move on chainNamespace; SDK resolves each to its PRC20 and asserts SOURCE_CHAIN_NAMESPACE + maxGasPerCall: bigint; // PC (wei) per outbound for the destination leg + validUntil: number; + allowedCalls: AllowedCall[]; // 1..32, all on chainNamespace +} + +interface AssetCap { + token: MoveableToken | Address; // the other chain's token address (MOVEABLE.TOKEN..) or the native marker; the contract stores the PRC20 + maxPerCall: bigint; + maxTotal?: bigint; +} + +type Selector = Hex | `${string}(${string})`; // '0x617ba037' or 'supply(address,uint256,address,uint16)' + +interface AllowedCall { target: Address; selector: Selector; beneficiary?: number; maxValue?: bigint } // beneficiary = arg index + +interface RulesRecord { + rulesId: Hex; + enabled: boolean; + chainNamespace: string; + agent: Address; // the Push address granted + validUntil: number; + ref: Hex; + rule: Rule; // decoded terms; NativeRule or UniversalRule + spent: Spent; // carried by rules.get and rules.list; no separate call +} + +type Spent = { kind: 'universal'; amountSpent: bigint } | { kind: 'native'; valueSpent: bigint; amountSpent: bigint; callsUsed: number }; // PROPOSED: one self-describing object, readable without knowing the rulebook +``` + +### 3.c Wallet handle and checkpoints + +```tsx +interface AgenticWallet { + address: Address; + info(): Promise; + owner(): Promise<{ owner: Address }>; // Push address as stored + setLabel(label: string, opts?: { progressHook?: ProgressHook }): Promise; // PROPOSED, page 1 item 10 + checkpoints(opts?: { sinceBlock?: bigint }): Promise<{ checkpoints: Checkpoint[] }>; + rules: { + list(): Promise<{ rules: RulesRecord[] }>; + get(rulesId: Hex): Promise; + add(rules: Rule[], opts?: { progressHook?: ProgressHook }): Promise<{ rulesIds: Hex[]; tx: UniversalTxResponse }>; + update(params: { rules: { rulesId: Hex; rule: Rule }[]; progressHook?: ProgressHook }): Promise<{ rules: { rulesId: Hex; replaced: Hex }[]; tx: UniversalTxResponse }>; // revoke plus grant; spend counters reset + revoke(rulesIds: Hex[], opts?: { progressHook?: ProgressHook }): Promise; + revoke(params: { all: true; progressHook?: ProgressHook }): Promise; + }; +} + +interface WalletInfo { address: Address; label: string; index: number; owner: Address; deployed: boolean; rulesCount: number } + +interface Checkpoint { seq: number; kind: 'OWNER_ACTION' | 'RULES_GRANTED' | 'RULES_REVOKED'; ref: Hex; blockNumber: bigint; txHash: Hex } +``` + +### 3.d Constants, PushChain.CONSTANTS.AGENTIC (new) + +```tsx +PushChain.CONSTANTS.AGENTIC[PUSH_NETWORK.TESTNET_DONUT] = { + FACTORY, RULES_POLICY, // RULES_POLICY is URP; no validator address (page 1, D3) + MAX_PINS: 8, MAX_ALLOWED_CALLS: 32, ENVELOPE_VERSION: 1, +}; +``` + +### 3.e Helpers, PushChain.utils.agentic (new) + +Pure functions with the same output as the on-chain views. + +```tsx +PushChain.utils.agentic = { + rulesId(agent, chainNamespace, grantNonce), // the id a grant produces, same as the contract assigns + actionId(target, selector), // id of one allowed call: hash of its target and selector + configId(wallet, rulesId, actionId), // key of one allowed call's stored config, under one rule on one wallet + encodeRules(rules, ctx), // ctx = wallet and chain context needed to resolve beneficiary offsets + decodeRules(bytes), + deriveWallet(owner, index), // any-owner variant of client.agentic.derive + compileCard(card, userInput, ctx), // used by page 6; lives here because it produces Rule[] +}; +``` + +### 3.f Errors and progress + +```tsx +class AgenticError extends Error { code: string; hint?: string } +class AgenticRevertError extends PushChainExecutionError {} +// decoded custom error from the AGW, URP or the factory; uses core's fields: +// code string +// decodedError { name, hint, selector, decoded } + +// codes +// create: AGENT_IS_OWNER, DUPLICATE_RULE, TARGET_NOT_ON_RULE_CHAIN, ASSET_CHAIN_MISMATCH +// initialize (agenticWallet): NOT_OWNER_OR_AGENT, WALLET_NOT_DEPLOYED, NOT_AGENTIC_WALLET +// rules.revoke: REVOKE_NEEDS_TARGET (bare revoke) +// sendTransaction: NO_RULES_FOR_CHAIN, FROM_NOT_ALLOWED (any from, Routes 3 and 4) +// agentic mode: NOT_ALLOWED_IN_AGENTIC_MODE (prepareTransaction, executeTransactions, payGasWith, migrateCEA, rescueFunds) + +// progress events, AGENTIC-TX (PROPOSED) +// AGENTIC-TX-101 wallet derived { address, index, deployed } +// AGENTIC-TX-102 deploy step added +// AGENTIC-TX-104 rules granted { rulesIds } +// AGENTIC-TX-105 rules revoked { rulesIds | all } +// AGENTIC-TX-106 label set +// AGENTIC-TX-107 rule resolved for a send { rulesId, chainNamespace, door } +// AGENTIC-TX-199-01 done +// AGENTIC-TX-199-02 failed { code, decodedError } +// The Push leg of any agentic send also emits core's SEND-TX-1xx events. +// A cross-chain leg sent by the AGW emits 209-xx and 299-xx, never 201 to 204 (the signer's own Route 2 is never used). +``` + +**PROPOSED:** the AGENTIC-TX event list. Every write (`create`, `setLabel`, `rules.add`, `rules.update`, `rules.revoke`) takes a per-call `progressHook`; a `progressHook` passed to `PushChain.initialize` runs alongside it, as in core. + +`NO_RULES_FOR_CHAIN` is thrown before any signature and costs nothing. The rules lookup is one read on every send, not cached at initialize. A URP revert is thrown from `sendTransaction` as `AgenticRevertError` and also lands as `decodedError` on AGENTIC-TX-199-02. A destination-chain revert after URP passed still counts the spend, because the spend is counted when the outbound leaves Push; whether it is credited back depends on [1. AGW Contract Changes (nomenclature standard + change set)](1-agw-contract-changes.md) item 6 (`creditRevert`). + +# 4. Outside change: [PushChain.CONSTANTS.READ](http://PushChain.CONSTANTS.READ).CHAIN (confirmed 2026-09-28) + +Problem: `read()` takes `chain: PushChain.CONSTANTS.CHAIN.X`, but `CHAIN` is the set of blockchains the SDK signs for and routes to. Web2 is not one, so `CHAIN.WEB2` exists as a hidden (non-enumerable) member: it works if you know it is there and never appears in any listing. Reads have a wider domain than transactions: anything validators can observe. + +Change: a read-specific constant that is a superset of `CHAIN`. The field name stays `chain`, so nothing breaks, and `CHAIN` values remain valid because the strings are identical. + +```tsx +PushChain.CONSTANTS.READ.CHAIN = { + ...PushChain.CONSTANTS.CHAIN, // every real chain, same string values + WEB2: 'web2', // non-chain source, first-class here, enumerable +}; +type ReadChain = CHAIN | 'web2'; // ReadParams.chain: ReadChain + +read({ chain: PushChain.CONSTANTS.READ.CHAIN.WEB2, ... }) +read({ chain: PushChain.CONSTANTS.CHAIN.ETHEREUM_SEPOLIA, ... }) // still compiles +``` + +- `CHAIN.WEB2` becomes a deprecated alias of `READ.CHAIN.WEB2` for one release (the docs listed it on 2026-09-22), then goes. +- Anything that iterates `CHAIN` stops seeing a fake chain; anything that iterates `READ.CHAIN` sees every read source. +- The evaluator's `Read.chain` (page 8) takes the same values, so `READ.CHAIN` is the one constant the read SDK and the criteria compiler share. + +# 5. Open for review + +1. `rules.update` resets spend counters because it is revoke plus grant. Accepted for v1 and stated in 1.l; an in-place update is a contract change with no demand yet. +2. `setLabel` assumes [1. AGW Contract Changes (nomenclature standard + change set)](1-agw-contract-changes.md) item 10 lands. Pointer for the team. \ No newline at end of file diff --git a/plan/agw/notion/6-sdk-universal-marketplace.md b/plan/agw/notion/6-sdk-universal-marketplace.md new file mode 100644 index 00000000..b19e5207 --- /dev/null +++ b/plan/agw/notion/6-sdk-universal-marketplace.md @@ -0,0 +1,146 @@ +# 6. SDK: Universal Marketplace + + + +# 1. User side, by example + +Browse and compile. Nothing is sent until `start`. + +```tsx +const cards = await client.market.cards({ skill: 'yield', chain: CHAIN.ETHEREUM_SEPOLIA }); +const card = await client.market.card(cards[0].id); + +const plan = await client.market.compile(card, { + principal: { amount: parseUnits('1000', 6), token: MOVEABLE.TOKEN.ETHEREUM_SEPOLIA.USDC }, + duration: 30 * 86400, + choices: { pool: aavePool }, // card-declared choices, validated against the card +}); + +plan.wallet; // derived AGW address (client.agentic.derive under the hood) +plan.rules; // Rule[] the card requires, placeholders resolved (beneficiary = the AGW's account on that chain) +plan.criteria; // encoded Criteria bytes + hash, placeholders resolved (ACCOUNT, PRINCIPAL) +plan.fee; // { amount, token } from the card (PROPOSED: fixed fee on the card) +plan.calls; // MultiCall[]: deployWallet, fund, grantRules, createJob, approve, fund(job) +plan.preview; // human-readable: what the agent may do, what it may not, what "done" means +``` + +Start: one signature. + +```tsx +const { wallet, rulesId, jobId, txHash } = await client.market.start(plan, { + progressHook: (p) => console.log(p.id, p.message), // MARKET-TX-1xx +}); +// External user: UEA multicall. Push-native user: one tx from the EOA. Same call either way. (PROPOSED: path A) +``` + +After start, everything is on the primitives: + +```tsx +await client.job.status(jobId); // page 7 +await client.evaluation.status(jobId); // page 8 +client.agentic.wallet(wallet).rules.list(); // page 5 +``` + +# 2. Provider side, by example + +A card is a signed document. The signature is over the card hash, by the provider's agent key, so `compile` and the fund hook can both recompute it. + +```tsx +const card = await client.market.publish({ + skill: 'yield', + title: 'Aave USDC optimiser', + version: '1.0.0', + chains: [CHAIN.ETHEREUM_SEPOLIA], + agent: '0xAgentOnPush', // the Push address that will act: an EOA, or the UEA of an external key + requiredCalls: [ + { chain: CHAIN.ETHEREUM_SEPOLIA, target: aavePool, selector: 'supply(address,uint256,address,uint16)', beneficiary: 2 }, + { chain: CHAIN.ETHEREUM_SEPOLIA, target: usdcSepolia, selector: 'approve(address,uint256)' }, + ], + limits: { maxAmountPerCall: 'PRINCIPAL', maxAmountTotal: 'PRINCIPAL', maxPCPerCall: parseUnits('0.5', 18) }, + fee: { amount: parseUnits('5', 6), tokens: [USDC_ETH, USDT_ETH] }, // fixed (PROPOSED); tokens the provider accepts, client picks one at start + duration: { min: 7 * 86400, max: 90 * 86400 }, + criteriaTemplate, // page 8: Criteria with placeholders, unresolved + choices: [{ key: 'pool', type: 'address', allowed: [aavePool] }], +}); +// signs with the connected signer (must be the agent or the provider's owner key), stores, returns { id, hash, signature } + +await client.market.mine(); // cards published by this signer +await client.market.retire(card.id); // stops new starts; live jobs unaffected +``` + +# 3. Types + +```tsx +interface MarketNamespace { + cards(filter?: CardFilter): Promise; + card(id: string): Promise; + compile(card: AgentCard, input: UserInput): Promise; + start(plan: StartJobPlan, opts?: { progressHook? }): Promise; + publish(card: AgentCardDraft): Promise; // provider side + mine(): Promise; + retire(id: string): Promise; + prepare: { start(plan: StartJobPlan): Promise }; // the calls without sending, to add your own +} + +interface AgentCard { + id: string; // keccak of the canonical card, hex + provider: Address; // who signed the card, as a Push address + agent: Address; // the Push address that will act: becomes rules.agent and the kernel's provider + skill: string; title: string; version: string; + chains: CHAIN[]; + requiredCalls: RequiredCall[]; // become AllowedCall[] per chain + limits: { maxAmountPerCall: bigint | 'PRINCIPAL'; maxAmountTotal?: bigint | 'PRINCIPAL'; maxPCPerCall: bigint }; + fee: { amount: bigint; tokens: Address[] }; // PROPOSED fixed; tokens the provider accepts; client chooses one in UserInput + duration: { min: number; max: number }; + criteriaTemplate: Criteria; // page 8, unresolved placeholders + choices?: Choice[]; + signature: Hex; +} + +interface RequiredCall { chain: CHAIN; target: Address; selector: Selector; beneficiary?: number; maxValue?: bigint } +interface Choice { key: string; type: 'address' | 'uint' | 'enum'; allowed?: unknown[]; default?: unknown } + +interface UserInput { + principal: { amount: bigint; token: MoveableToken | Address }; + feeToken: Address; // one of card.fee.tokens; becomes Job.paymentToken (K-12) + duration: number; + choices?: Record; + pc?: bigint; // native PC for outbound fees, default from card + walletIndex?: number; // reuse a derived slot, default next +} + +interface StartJobPlan { + card: AgentCard; + wallet: Address; + rules: Rule[]; + criteria: { bytes: Hex; hash: Hex; resolved: Criteria }; + fee: { amount: bigint; token: Address }; + expiredAt: number; + calls: MultiCall[]; + preview: PlanPreview; +} + +interface StartResult { wallet: Address; rulesId: Hex; jobId: bigint; txHash: Hex } + +class MarketError extends AgenticError {} // CARD_SIGNATURE, CHOICE_INVALID, DURATION_OUT_OF_RANGE, CHAIN_UNSUPPORTED +// progress family: MARKET-TX-1xx +``` + +# 4. Open for review + +1. Path A vs B. On A (PROPOSED) `start` is an SDK multicall and `prepare.start` exists. On B `start` is one call to an on-chain `startJob` with the WithSig variants from page 1; the surface stays identical, only what is under `start` changes. +2. Fixed fee vs quote. Fixed (PROPOSED) keeps the provider out of the user's signature. Quote means `start` splits into `start` (create, no fund) and `fundQuoted(jobId)` after `setBudget`, and the user signs twice. +3. Card storage. Off-chain index signed by the provider (fast, POC) vs on-chain registry (slow, verifiable). `publish` hides the choice; `id` is the card hash in both. +4. Card versioning. A new version is a new card and a new id; live jobs keep the hash they funded with. +5. Who may `publish`. Provider owner key vs agent key vs either. Fund hook recomputes the card hash and checks the signature against `card.provider`. \ No newline at end of file diff --git a/plan/agw/notion/7-sdk-8183-job.md b/plan/agw/notion/7-sdk-8183-job.md new file mode 100644 index 00000000..731f7765 --- /dev/null +++ b/plan/agw/notion/7-sdk-8183-job.md @@ -0,0 +1,120 @@ +# 7. SDK: 8183 Job + + + +# 1. Client side (AGW owner), by example + +Without the marketplace: the owner creates and funds a job from an AGW that already exists. + +```tsx +const owner = await PushChain.initialize(ownerSigner, { network: PushChain.CONSTANTS.PUSH_NETWORK.TESTNET }); +const w = owner.agentic.wallet('0xWallet'); + +const { jobId, txHash } = await owner.job.create({ + client: w.address, // the AGW is the client on the kernel + provider: '0xAgentOnPush', // same Push address as rules.agent: an EOA, or the UEA of an external key + evaluator: PushChain.CONSTANTS.EVALUATION[TESTNET_DONUT].UNIVERSAL_EVALUATOR, + expiredAt: now + 30 * 86400, + hook: PushChain.CONSTANTS.JOB[TESTNET_DONUT].RULES_BINDING_HOOK, + criteria: criteriaBytes, // page 8; carried in description as hex (single carrier) +}); +// goes through w.execute: the AGW calls createJob + +await owner.job.fund(jobId, { amount: parseUnits('5', 6), token: USDC_ETH }, { rulesId }); // token chosen by the client at createJob (K-12) +// approve(kernel) + fund(jobId, amount, optParams = rulesId) in one execute; the hook binds rulesId to jobId + +await owner.job.status(jobId); // Job +owner.job.watch(jobId, (e) => console.log(e.status)); // Funded, Started (from evaluation), Submitted, Completed, Rejected +await owner.job.claimRefund(jobId); // after expiredAt + grace, never pausable +``` + +# 2. Provider side, by example + +No AGW, no rules: the provider is an ordinary signer talking to the kernel. + +```tsx +const provider = await PushChain.initialize(agentSigner, { network: PushChain.CONSTANTS.PUSH_NETWORK.TESTNET }); + +await provider.job.list({ provider: provider.universal.account, status: 'Funded' }); // the signer's Push address, UEA for an external key +await provider.evaluation.waitForStart(jobId); // page 8: PreRecorded exists, START reads landed + +// ... do the work through the AGW as the agent (page 5, section 2) ... + +await provider.job.submit(jobId, { deliverable: 'ipfs://...' }); +// hook afterAction(submit) fires END reads; the verdict lands via evaluation.watch (page 8) + +// quote path only (open on page 3): await provider.job.setBudget(jobId, parseUnits('5', 6)); +``` + +# 3. Types + +```tsx +interface JobNamespace { + create(params: CreateJobParams): Promise<{ jobId: bigint; txHash: Hex }>; + fund(jobId: bigint, fee: { amount: bigint; token: Address }, opts: { rulesId: Hex; progressHook? }): Promise; + submit(jobId: bigint, params: { deliverable: Hex | string; optParams?: Hex }): Promise; // string is hashed to bytes32 + claimRefund(jobId: bigint): Promise; + setBudget?(jobId: bigint, amount: bigint): Promise; // only if the quote path wins + status(jobId: bigint): Promise; + list(filter: { client?: Address; provider?: Address; status?: JobStatus }): Promise; + watch(jobId: bigint, cb: (e: JobEvent) => void): () => void; + evaluatorOnly: { // escape hatch for non-card jobs where the evaluator is a signer + complete(jobId: bigint, reason: string): Promise; + reject(jobId: bigint, reason: string): Promise; + }; + prepare: { + create(params: CreateJobParams): Promise; + fund(jobId: bigint, fee, opts): Promise; + }; +} + +interface CreateJobParams { + client: Address; // AGW address; the SDK routes through its execute door + provider: Address; // must equal rules.agent; the hook checks equality + evaluator: Address; + expiredAt: number; + hook: Address; + paymentToken: Address; // K-12: client's choice, any PRC20 + criteria?: Hex; // encoded Criteria; written to description as hex + description?: string; // only when criteria is absent (plain 8183 job, no evaluator) + progressHook?: (p: ProgressEvent) => void; +} + +type JobStatus = 'Open' | 'Funded' | 'Submitted' | 'Completed' | 'Rejected' | 'Expired'; + +interface Job { + id: bigint; client: Address; provider: Address; evaluator: Address; + status: JobStatus; budget: bigint; paymentToken: Address; + expiredAt: number; hook: Address; + criteria?: { bytes: Hex; hash: Hex }; // decoded from description when present + paymentToken: Address; // K-12 + deliverable?: Hex; // bytes32 on the kernel: hash or digest of the deliverable + rulesId?: Hex; // from the binding hook +} + +interface JobEvent { jobId: bigint; status: JobStatus | 'Started'; txHash: Hex; blockNumber: bigint; reason?: string } + +PushChain.CONSTANTS.JOB[PUSH_NETWORK.TESTNET_DONUT] = { KERNEL, RULES_BINDING_HOOK, GRACE: 3600 }; // no payment token constant: the client picks it per job + +class JobError extends AgenticError {} // TOKEN_MISMATCH (kernel is single-token), NOT_STARTED, RULES_NOT_BOUND, EXPIRED +// progress family: JOB-TX-1xx +``` + +# 4. Open for review + +1. Payment token is chosen by the client per job (USDC, USDT.eth, USDT.sol, any PRC20). The kernel on the branch is single-token (`paymentToken` set in `initialize`), so this needs K-12: `createJob(..., address paymentToken)`, `Job.paymentToken`, `totalEscrowed` per token, fees paid in the job's token. `fund` then takes no token argument; the SDK reads it from the job and throws `TOKEN_MISMATCH` if the caller passes a different one. +2. `evaluatorOnly.complete/reject`: keep as a named escape hatch or leave out of the SDK entirely (call the kernel raw). Leaving it in makes plain 8183 jobs usable without the evaluator. +3. `setBudget` exists only on the quote path. Decide with page 2 open item 2. +4. `watch` emits `Started` from the evaluator's `PreRecorded`, not from the kernel. One stream for the reader, two sources underneath. +5. `create` from an EOA client (no AGW) for plain 8183 jobs: allow, or require an AGW always. Allowing it keeps the namespace honest to the standard. \ No newline at end of file diff --git a/plan/agw/notion/8-sdk-universal-evaluation.md b/plan/agw/notion/8-sdk-universal-evaluation.md new file mode 100644 index 00000000..a047946c --- /dev/null +++ b/plan/agw/notion/8-sdk-universal-evaluation.md @@ -0,0 +1,127 @@ +# 8. SDK: Universal Evaluation + + + +# 1. Card author side, by example + +A template with placeholders. `ACCOUNT` is the user's account on the read's chain (the AGW's CEA on EVM); `PRINCIPAL` is the funded amount. + +```tsx +const { criteria } = PushChain.CONSTANTS.EVALUATION; + +const template = client.evaluation.criteria.build({ + minDuration: 7 * 86400, + conditions: [ + // 4% on principal over the job, measured on the aToken balance + { read: { chain: READ.CHAIN.ETHEREUM_SEPOLIA, type: 'CONTRACT_CALL', target: aUSDC, call: 'balanceOf(address)', args: ['ACCOUNT'], result: 'UINT' }, + sample: 'START_AND_END', + cmp: { op: 'GTE', basis: 'PCT', value: 400n } }, + // nothing left idle on the destination chain + { read: { chain: READ.CHAIN.ETHEREUM_SEPOLIA, type: 'CONTRACT_CALL', target: usdcSepolia, call: 'balanceOf(address)', args: ['ACCOUNT'], result: 'UINT' }, + sample: 'END', + cmp: { op: 'LTE', basis: 'ABSOLUTE', value: parseUnits('1', 6) } }, + ], +}); + +client.evaluation.criteria.validate(template); // limits: 8 conditions, 512 bytes calldata, PERIODIC refused, solana result types +client.evaluation.criteria.encode(resolved); // Hex, abi.encode(Criteria) +client.evaluation.criteria.hash(resolved); // keccak of the encoding +client.evaluation.criteria.decode(bytes); // Criteria, from a job's description +``` + +Preview before anyone signs: resolve placeholders and dry-run the reads today, locally, so the author sees what the evaluator will see. + +```tsx +const resolved = client.evaluation.criteria.resolve(template, { account: ceaOnSepolia, principal: parseUnits('1000', 6) }); +const dry = await client.evaluation.criteria.simulate(resolved); // uses universal.readState now; not the verdict, a sanity check +dry.conditions[0]; // { start?: value, end: value, pass: boolean, note?: 'PCT with zero START fails' } +``` + +# 2. Job side, by example + +```tsx +const s = await client.evaluation.status(jobId); +// { registered: true, started: true, startValues: [...], endValues?: [...], verdict?: 'PASS' | 'FAIL', reason? } + +await client.evaluation.waitForStart(jobId, { timeoutMs }); // resolves on PreRecorded(jobId) +const stop = client.evaluation.watch(jobId, (e) => { /* StartRead, PreRecorded, EndRead, Verdict */ }); + +await client.evaluation.refireStart(jobId, { condition: 0 }); // a START read errored or expired; caller pays the read fee +await client.evaluation.verdict(jobId); // { result, reason, txHash } once complete or reject landed +``` + +# 3. Types + +```tsx +interface EvaluationNamespace { + criteria: { + build(input: CriteriaInput): Criteria; // typed sugar over the raw struct; selectors as signature strings, args by name + validate(c: Criteria): void; // throws EvaluationError with the offending condition index + resolve(c: Criteria, ctx: { account: Address | Hex; principal: bigint }): Criteria; + encode(c: Criteria): Hex; + decode(bytes: Hex): Criteria; + hash(c: Criteria): Hex; + simulate(c: Criteria, opts?: { atBlock? }): Promise; + }; + status(jobId: bigint): Promise; + verdict(jobId: bigint): Promise; + waitForStart(jobId: bigint, opts?: { timeoutMs?: number }): Promise; + refireStart(jobId: bigint, opts: { condition: number }): Promise; + watch(jobId: bigint, cb: (e: EvaluationEvent) => void): () => void; +} + +// mirrors page 4 one to one +interface Criteria { version: 1; minDuration: number; conditions: Condition[] } +interface Condition { read: Read; sample: Sample; cmp: Compare } +interface Read { + chain: ReadChain; // READ.CHAIN.*: eip155 chains, solana chains, PUSH (local, no fee), WEB2 + type: 'ACCOUNT_BALANCE' | 'CONTRACT_CALL' | 'STORAGE_SLOT'; + target: Address | Hex; // 20 bytes EVM, 32 bytes SVM + callData?: Hex; // CONTRACT_CALL; placeholders resolved at compile + word?: number; // which 32-byte word of the return + result: 'UINT' | 'INT' | 'BOOL' | 'ADDRESS' | 'BYTES32'; +} +type Sample = 'END' | 'START_AND_END' | 'PERIODIC'; // PERIODIC refused by the v1 evaluator +interface Compare { + op: 'EQ' | 'NEQ' | 'GT' | 'GTE' | 'LT' | 'LTE' | 'IS_TRUE' | 'IS_FALSE'; + basis: 'ABSOLUTE' | 'DELTA' | 'PCT' | 'REF'; + value: bigint; // bps when basis is PCT + ref?: number; // condition index when basis is REF +} + +type Placeholder = 'ACCOUNT' | 'PRINCIPAL'; + +interface EvaluationStatus { + registered: boolean; started: boolean; + startValues?: (bigint | boolean)[]; endValues?: (bigint | boolean)[]; + verdict?: 'PASS' | 'FAIL'; reason?: string; +} +interface Verdict { result: 'PASS' | 'FAIL'; reason: string; txHash: Hex; perCondition: { pass: boolean; start?: bigint; end: bigint }[] } +interface SimulationResult { conditions: { start?: bigint | boolean; end: bigint | boolean; pass: boolean; note?: string }[]; pass: boolean } +interface EvaluationEvent { jobId: bigint; kind: 'StartRead' | 'PreRecorded' | 'EndRead' | 'Verdict'; condition?: number; txHash: Hex } + +PushChain.CONSTANTS.EVALUATION[PUSH_NETWORK.TESTNET_DONUT] = { + UNIVERSAL_EVALUATOR, MAX_CONDITIONS: 8, MAX_CALLDATA: 512, MAX_CHAIN_STRING: 32, SCHEMA_VERSION: 1, +}; + +class EvaluationError extends AgenticError { condition?: number } // PERIODIC_UNSUPPORTED, TOO_MANY_CONDITIONS, UNRESOLVED_PLACEHOLDER, SOLANA_RESULT_TYPE +``` + +# 4. Open for review + +1. `simulate` runs the reads through `universal.readState` today. That is the real read path, so it costs read fees unless we add a free local eth_call fallback for the preview. Decide: paid but faithful, or free but approximate. +2. `refireStart` pays the read fee from the caller. Who should be allowed: anyone (page 4 says anyone) or client and provider only. +3. `build` sugar (named args, signature strings) means the SDK carries ABI encoding for criteria the same way it does for rules. Same dependency, one implementation. +4. `status.started` reads the evaluator's `PreRecorded`; if storage moves to the hook (page 4 open item 1) the read target changes, the surface does not. +5. Annualisation of PCT is a card-level convention in v1. If the evaluator learns to annualise later, `Compare` gains a flag; `build` can accept `annualised: true` now and refuse until then. \ No newline at end of file diff --git a/plan/agw/notion/agentic-wallet-flow-2026-09-07.md b/plan/agw/notion/agentic-wallet-flow-2026-09-07.md new file mode 100644 index 00000000..6fdcdd36 --- /dev/null +++ b/plan/agw/notion/agentic-wallet-flow-2026-09-07.md @@ -0,0 +1,362 @@ +# agentic_wallet_flow ( updated ) + +# Bob Lends 100 USDC — End-to-End Flow on Push Chain (Architecture v3) + +**Bob’s intent:** *“Find the best-yielding stablecoin lending vault and deploy 100 USDC into it.”* + +--- + +## Cast + +| Handle | What it is | Where | +| --- | --- | --- | +| `0xbob` | Bob’s EOA — holds USDC | Ethereum | +| `0xbobuea` | Bob’s Universal Executor Account — his identity | Push Chain | +| `0xbobagw` | Bob’s **agent wallet** — holds the budgeted funds, owned by `0xbobuea`. **One of several Bob may own** | Push Chain | +| `0xbobagwcea` | `0xbobagw`’s Chain Executor Account — the execution hand | Ethereum | +| `0xagentkey` | The agent’s signing key (ECDSA **or** Ed25519) — **a key, not an account** | off-chain | +| `AGWFactory` | Deploys agent wallets at predictable addresses; the registry of record | Push Chain | +| `SmartSession` | The adopted permission engine — the wallet’s only installed module | Push Chain | +| `UCEP` | Universal CrossChain Execution Policy — **the only contract that inspects what the agent really does on the far chain** | Push Chain | +| `PushSessionValidator` | Stateless signature checker (secp256k1 / Ed25519). **Never installed** — named inside each permission | Push Chain | +| `UniversalGatewayPC` | The frozen outbound gateway — the only thing an agent action may call | Push Chain | + +All of Bob’s addresses are **deterministic and computable before anything is deployed.** + +**Not in v3, and deliberately absent from this flow:** any executor module (module type 2 is refused by the wallet), any hook or fallback module, any job/escrow/evaluator layer, any fee split. Those are separate product concerns with no contract in the v3 set. + +--- + +## STAGE 1 — Intent capture *(off-chain, zero transactions)* + +- Bob types his intent. The tooling resolves `0xbobuea`, and — critically — **asks Bob a v3-specific question**: + + > *“Put this in a **new** agent wallet, or add it as another mandate on an **existing** one?”* + > + + A new wallet is a new blast-radius boundary and a new account on every external chain. An extra mandate on an existing wallet shares the pool and the accounts. **This choice is Bob’s, and it exists only in v3** (Rule 1). + +- Bob chooses a new wallet. The tooling derives `0xbobagw` from `(owner, index)` via `AGWFactory.predictWallet`, then derives `0xbobagwcea` from it — **before either exists**. +- The tooling composes the mandate. Every line below becomes an on-chain policy parameter inside UCEP: + + + | Capital | 100 USDC into a wallet only Bob can withdraw from | + | --- | --- | + | Agent may call | `supply()` on Aave v3 / Morpho Blue / Spark — Ethereum only | + | Ceiling | 100 USDC lifetime, 100 USDC per action | + | Gas ceiling | a bounded amount of PC per action | + | Expires | 60 minutes — **an explicit, non-zero value**; UCEP rejects a zero or past expiry at grant | + | Beneficiary | forced to `0xbobagwcea` — derived, never typed | + | Revoke | instantly, one signature, unblockable | +- **Argument offsets are generated from each protocol’s ABI by tooling, never hand-typed** — a wrong offset silently disarms the beneficiary check. +- The tooling calls `PushSessionValidator.validateConfig` on the key config, and shows Bob the resolved `0xbobagwcea` and whether it is deployed yet. +- Bob reviews and approves. **This is the last human decision point.** + +--- + +## STAGE 2 — One signature on Ethereum + +**💰 FUND MOVEMENT #1 — USDC leaves Bob’s wallet** + +- Bob signs a single EIP-712 payload in his own wallet. +- `UniversalGateway.sendUniversalTx()` on Ethereum locks **100 USDC** into the Vault, takes a small extra amount auto-swapped to $PC for gas, and carries the Push Chain payload. + +``` +0xbob ──100 USDC──▶ UniversalGateway (Ethereum) [LOCKED] +``` + +- **Bob needs no $PC, never visits Push Chain, and signs exactly once.** + +--- + +## STAGE 3 — Inbound: identity, wallet, mandate — one atomic multicall + +- Universal Validators observe the Ethereum event → ballot reaches quorum → `x/uexecutor` dispatches: + - `UEAFactory.deployUEA()` → **`0xbobuea` created** (first time only) + - gas auto-swapped to $PC, UEA credited + - **100 pUSDC minted to `0xbobuea`** + - `0xbobuea.executeUniversalTx(payload, sig)` → signature verified → multicall runs + +**💰 FUND MOVEMENT #2 — 100 USDC arrives as 100 pUSDC** + +### The multicall, step by step + +| # | Call | Effect | +| --- | --- | --- | +| 1 | `AGWFactory.deployWallet("lending")` | **`0xbobagw` deployed** at the predicted address; owner = `0xbobuea`, baked into bytecode. **Inside the same call the factory invokes `initializeAccount()`, which installs SmartSession** — atomic, no uninitialised state | +| 2 | `0xbobagw.grantMandate(session)` | 🔑 **MANDATE GRANTED** — see below | +| 3 | `pUSDC.transfer(0xbobagw, 100e6)` | 💰 funds → the agent wallet | +| 4 | `PC.transfer(0xbobagw, …)` | ⛽ the wallet needs its own PC — it pays for the outbound gas swap | + +**There is no `installModule(2, OutboundExecutor)` step.** v3 supports **module type 1 only**. The wallet calls the gateway itself; nothing else is installed, ever. + +### 🔑 The mandate grant (step 2) in detail + +`grantMandate` does exactly two things: it **overwrites the salt** with the wallet’s own monotonic `grantNonce`, and it **enforces the canonical session shape**. Anything else reverts `MalformedSessionShape`. + +``` +sessionValidator = PushSessionValidator +sessionValidatorInitData = abi.encode(scheme, 0xagentkey) ← ECDSA or Ed25519 +salt = bytes32(grantNonce++) ← WALLET-SUPPLIED, never the caller's + +userOpPolicies: [ ] ← ALWAYS EMPTY (that class has a floor of zero) +erc7739Policies: [ ] ← ALWAYS EMPTY +permitERC4337Paymaster: false ← ALWAYS FALSE + +actions: [ EXACTLY ONE ] + actionTarget = UniversalGatewayPC + actionTargetSelector = sendUniversalTxOutbound.selector + actionPolicies: [ UCEP AND ONLY UCEP ] + validUntil = now + 60 min ← THE EXPIRY LIVES INSIDE UCEP + asset = PRC20_USDC ← pins the destination chain transitively + expectedCEA = 0xbobagwcea ← DERIVED at grant, committed forever + maxAmountPerCall = 100e6 + maxAmountTotal = 100e6 + maxPCPerCall = + allowedCalls = { Aave v3, Morpho Blue, Spark } × { supply } + beneficiary offsets +``` + +**Why UCEP is the *only* action policy.** The engine requires at least one action policy per action. With UCEP as the only one, **removing UCEP leaves zero policies and every request dies**. Add a second policy — a separate time-window policy, say — and that property is gone: stripping UCEP would leave one policy standing and the request would pass. **This is why the expiry lives inside UCEP and not in a policy of its own.** + +**The mandate identity.** `permissionId = keccak256(sessionValidator, initData, salt)`. Because the wallet supplies the salt, granting byte-identical terms twice yields two independent mandates. Because the signer config is in the hash, **the agent key cannot be swapped inside a mandate — a different key is a different mandate** (Rule 4). + +**What the agent key can do:** exactly one function, on exactly one Push contract, for one asset, up to two ceilings, into three possible pools, until the expiry, with the beneficiary forced to Bob’s own CEA. + +**What it cannot do:** move funds anywhere else · call any other contract · redirect the position · exceed either cap · act after expiry · install or remove modules · call the wallet, UCEP, the gateway, **or `0xbobagwcea` itself** · touch `0xbobuea` · grant or extend anything. + +### State after Stage 3 + +``` +0xbobuea : 0 pUSDC ← identity only, clean +0xbobagw : 100 pUSDC + PC ← owned by 0xbobuea; one mandate live +UCEP.spent : 0 +``` + +**Bob signed once. He has an identity, an agent wallet, a bounded mandate, and zero exposure beyond 100 USDC.** + +--- + +## STAGE 4 — The agent works *(off-chain, no funds move)* + +- The agent’s runtime researches yields off-chain → **Morpho Blue USDC vault, 5.2% APY**. +- It composes the request as **four nested layers**, innermost first: + +``` +Layer 4 the far-chain call supply(USDC, 100e6, 0xbobagwcea, 0) +Layer 3 the instruction list Multicall[] — 1 to 10 entries, mandatory envelope +Layer 2 the gateway request token, amount, EMPTY recipient, revertRecipient = 0xbobagw, + non-zero maxPCForGas, payload = layer 3 +Layer 1 the wallet operation mode, executionCalldata, lane + position, requestExpiry +``` + +- It signs the **ten-field operation hash**. **It composes instructions; it does not move money.** + +--- + +## STAGE 5 — Execution via the agent door + +**🔑 THE AGENT KEY IS USED — the only time it is used in the entire lifecycle** + +- The agent **cannot** call `UniversalGatewayPC` itself. If it did, `msg.sender` would be the agent, the Vault would derive the *agent’s* CEA, and the agent would hold Bob’s position. Structurally blocked. +- Instead it calls **Bob’s wallet** — or hands the signed request to any relayer. + +> **The caller does not matter — the signature does.**`executeWithSession` has no caller check. **Anyone can submit.** Authorisation lives inside the function: the transaction is inert without a signature over the op hash from the key Bob named. In practice the agent service relays its own requests and pays the Push gas from its own PC balance — a separate balance from the wallet’s. +> + +``` +0xagentkey signs opHash (10 bound fields) + └─▶ 0xbobagw.executeWithSession(validator, mode, execCalldata, sig, nonceKey, nonceSeq, requestExpiry) + │ + │ ── THE WALLET DOES THE ENTRYPOINT'S JOBS ITSELF (Push Chain has none) ── + ├─ 1. requestExpiry passed? revert (0 = no expiry; no ceiling either) + ├─ 2. validator installed? ✓ + ├─ 3. consume nonce lane BEFORE validation — nothing can run twice + ├─ 4. recompute the ten-field opHash from what arrived + ├─ 5. build PackedUserOperation in memory (ABI shape only) + │ sender = address(this) · paymasterAndData = "" · gas fields zeroed + │ + └─▶ SmartSession.validateUserOp + ├─ permission enabled? + ├─ UCEP.checkAction ── the 16-gate gauntlet, in order ── + │ 1 configured · 2 NOT EXPIRED · 3 gateway only · 4 send selector + │ 5 token == USDC · 6 per-call cap · 7 lifetime cap · 8 PC value cap + │ 9 maxPCForGas != 0 · 10 revertRecipient == wallet · 11 recipient EMPTY + │ 12 multicall envelope · 13 1..10 entries + │ per entry: 14 not wallet/UCEP/gateway/CEA ← beats the allow-list + │ 15 (target, selector) allow-listed + beneficiary == 0xbobagwcea + │ 16 per-entry value cap + │ EFFECTS LAST: spent += amount · emit OutboundMetered + │ + └─ PushSessionValidator.validateSignatureWithData ← LAST, after every policy + ECDSA: ecrecover Ed25519: raw staticcall to the USV precompile + │ + ├─ 6. the wallet enforces the verdict itself (authorizer, validAfter/validUntil) + └─▶ 7. dispatch THE EXACT VALIDATED BYTES ──▶ UniversalGatewayPC.sendUniversalTxOutbound + ▲ + msg.sender == 0xbobagw + ← decides which CEA executes +``` + +- **Any single gate failing reverts the whole transaction** — nonce, counters, everything. A failed action costs the relayer gas and changes nothing else. The agent’s runtime is never trusted; UCEP is the trust boundary. +- **Ordering note that looks wrong and is not:** the signature is verified **after** the policies. Policies therefore run on calldata that has not yet been authenticated — so every policy, forever, must be safe against arbitrary calldata from any caller. UCEP is safe by construction: no external calls, effects last, revert on every failure. + +### 💰 FUND MOVEMENT #3 — 100 pUSDC burns on Push Chain + +``` +0xbobagw [100 pUSDC] ──BURN──▶ ∅ emit UniversalTxOutbound(sender = 0xbobagw, …) +UCEP.spent: 0 → 100e6 emit OutboundMetered(...) ← the correlation record +``` + +--- + +## STAGE 6 — Cross-chain settlement + +- `PostTxProcessing` creates a pending outbound; Universal Validators produce a **DKLS23 threshold signature**; TSS calls `Vault.finalizeUniversalTx(pushAccount = 0xbobagw, …)` on Ethereum. + +### 💰 FUND MOVEMENT #4 — 100 USDC released to the wallet’s CEA + +- Vault: `getCEAForPushAccount(0xbobagw)` → not deployed → **deploys `0xbobagwcea`** (first contact) +- Vault: `USDC.safeTransfer(0xbobagwcea, 100e6)` +- Vault: `CEA.executeUniversalTx(..., originCaller = 0xbobagw, payload)` → checks `originCaller == pushAccount` ✓ → runs the instruction list: + +| # | Call | Result | +| --- | --- | --- | +| 1 | `USDC.approve(MORPHO_BLUE, 100e6)` | allowance set | +| 2 | `MORPHO_BLUE.supply(USDC, 100e6, 0xbobagwcea, 0)` | **deposit executed** | + +### 🎯 What Morpho sees + +``` +msg.sender = 0xbobagwcea · onBehalfOf = 0xbobagwcea · shares → 0xbobagwcea +``` + +**The agent appears nowhere.** It never held a cent, never appeared as depositor, and cannot withdraw. + +### If the far side fails + +- Funds return to `0xbobagw` — because UCEP pinned `revertRecipient` to the wallet, gate 10. +- Push’s Universal Executor Module then calls `UCEP.creditRevert(...)`, which reduces `spent` — **module-only, once per outbound id, saturating**. +- **STATUS: designed and shipped, NOT YET FUNCTIONAL** — the Push-core callback has not landed. Until it does, a failed far leg leaves `spent` inflated and the remedy is revoke-and-regrant. **Gas is never credited back; it was genuinely consumed.** + +--- + +## STAGE 7 — After the action + +### The control chain — transitive, and single-parent at every hop + +``` +0xbobuea ──owns──▶ 0xbobagw ──is pushAccount of──▶ 0xbobagwcea + (identity) (agent wallet) (Ethereum hand) +``` + +- **The UEA cannot command the CEA directly.** To withdraw from Morpho, `0xbobuea` calls `0xbobagw.execute(...)`, which originates an outbound, which the TSS routes to `0xbobagwcea`. Always two hops. +- **The agent key cannot withdraw** — `withdraw()` is not in the allow-list, so the owner path is the only exit by construction. +- **The CEA has no independent security.** It is a projection of the agent wallet, not a second line of defence. + +| Actor | Can do | Cannot do | +| --- | --- | --- | +| **`0xbobuea`** (Bob) | anything, unconditionally — withdraw anywhere, revoke, replace a mandate, install/uninstall a validator | — | +| **`0xagentkey`** | exactly what the mandate permits, until expiry | everything else | +| **Push governance** | — | reach `0xbobagwcea`; the only path in is a TSS outbound originating from `0xbobagw` | + +### The owner’s three operations, in full + +- **Withdraw** — `execute([...])`. **There is no `withdraw()` function**; the owner path *is* withdrawal, with no destination restriction and no policy in the path. It must succeed in every degraded state — zero mandates, engine uninstalled, hostile validator installed. +- **Revoke** — `stopMandate(pid)` (existence-checked, so a typo reverts loudly instead of silently “succeeding”) or `stopAll()`. Immediate on Push, unblockable, no callbacks on the path. **One honest limit:** an instruction already dispatched across the bridge still completes. +- **Change a mandate** — **it cannot be edited.** A change is one owner transaction batching: `UCEP.assertSpent(expected)` → `stopMandate(old)` → `grantMandate(new)`. If the agent spent in the composition window, the assertion reverts the whole change. **Counters restart at zero on the new mandate**, and any request the agent signed against the old id is dead, because the op hash binds the permission id. + +### STAGE 7b — the second action, and why it may carry zero USDC + +- Bob’s agent later wants to move the position from Morpho into Aave. **No new USDC is bridged** — the capital is already at `0xbobagwcea`. +- So the outbound carries `amount == 0` with a payload of allow-listed instructions. **v3 permits this**; `spent` does not move, because the lifetime cap counts what is **bridged**, not what is **redeployed**. +- The exposure is bounded elsewhere: the per-call PC ceiling, the requirement that every instruction be allow-listed, and the wallet’s own small PC balance. + +--- + +## Fund movement — the whole ledger + +| # | Stage | Movement | Amount | +| --- | --- | --- | --- | +| 1 | 2 | `0xbob` → UniversalGateway (Ethereum) | 100 USDC locked | +| 2 | 3 | mint on Push Chain → `0xbobuea` | 100 pUSDC | +| 3 | 3 | `0xbobuea` → `0xbobagw` | 100 pUSDC + PC for gas | +| 4 | 5 | `0xbobagw` burn | −100 pUSDC | +| 5 | 6 | Ethereum Vault → `0xbobagwcea` | 100 USDC | +| 6 | 6 | `0xbobagwcea` → Morpho Blue | 100 USDC → vault shares | + +**The agent never appears as a holder in any row.** + +--- + +## Diagram + +``` + ┌─────────────────────────────────────────┐ + STAGE 1 intent │ Bob: "best stablecoin yield, 100 USDC" │ + (off-chain) └──────────────────┬──────────────────────┘ + │ NEW wallet or EXISTING? ← v3 choice + │ derive addresses · compose mandate + ▼ + ┌───────────────────┐ + │ Bob approves │ ← last human decision + │ ONE SIGNATURE │ + └─────────┬─────────┘ +═══════ ETHEREUM ═══════════════════════════════════════│═══════════════════════════════ + STAGE 2 ▼ + 0xbob ──────100 USDC──────▶ UniversalGateway ────[LOCKED in Vault] + │ emit UniversalTx +═══════ PUSH CHAIN ═════════════════════│═══════════════════════════════════════════════ + STAGE 3 ▼ + Universal Validators ──vote──▶ quorum ──▶ x/uexecutor + │ + ┌─────────────────────────────────────┘ + ▼ + deploy 0xbobuea + mint 100 pUSDC + credit gas + │ + │ ONE ATOMIC MULTICALL + ├──1─▶ AGWFactory.deployWallet → 0xbobagw (owner baked in) + │ └─ factory calls initializeAccount() → SmartSession installed + │ NO executor module · NO hook · NO fallback + ├──2─▶ 🔑 grantMandate — salt from grantNonce, shape enforced + │ UCEP: expiry · asset · caps · allow-list · expectedCEA + ├──3─▶ 💰 100 pUSDC ──▶ 0xbobagw + └──4─▶ ⛽ PC ──▶ 0xbobagw (pays its own outbound gas swap) + + STAGE 4 agent researches off-chain · composes 4 nested layers · signs opHash + │ + STAGE 5 ▼ + anyone relays ──▶ 0xbobagw.executeWithSession(...) + │ + ┌───────────┴────────────────────────┐ + │ WALLET: expiry · validator · nonce │ + │ · opHash · build userOp │ + ├────────────────────────────────────┤ + │ UCEP: 16 gates, fail closed │ + │ gateway only · asset · caps │ + │ recipient EMPTY · refund → wallet │ + │ ≤10 entries · NOT the CEA │ + │ allow-list · beneficiary == CEA │ + ├────────────────────────────────────┤ + │ SIGNATURE CHECKED LAST │ + └───────────┬────────────────────────┘ + ▼ + UniversalGatewayPC.sendUniversalTxOutbound + 💰 BURN 100 pUSDC (msg.sender = 0xbobagw) + │ + Universal Validators ──▶ DKLS23 TSS signature +═══════ ETHEREUM ═══════════════│═══════════════════════════════════════════════════════ + STAGE 6 ▼ + Vault.finalizeUniversalTx(pushAccount = 0xbobagw) + ├─▶ deploy 0xbobagwcea (first contact) + ├─▶ 💰 100 USDC ──▶ 0xbobagwcea + └─▶ CEA multicall: approve + supply + │ + ┌───────────────▼────────────────┐ + │ MORPHO BLUE │ + │ msg.sender = 0xbobagwcea │ + │ shares → 0xbobagwcea │ + │ the agent appears NOWHERE │ + └────────────────────────────────┘ +``` + +--- \ No newline at end of file diff --git a/plan/agw/notion/agw-address-book-donut-2026-09-04.md b/plan/agw/notion/agw-address-book-donut-2026-09-04.md new file mode 100644 index 00000000..8ef60404 --- /dev/null +++ b/plan/agw/notion/agw-address-book-donut-2026-09-04.md @@ -0,0 +1,30 @@ +# AGW Address Book - PC Donut + +## Contracts we deploy + +| Contract | Address | Size | Verified | +| --- | --- | --- | --- | +| **`factoryProxy`** — **use this one** | [`0xF1A131571f89fD06890576e6cD0154114ACBBc8b`](https://donut.push.network/address/0xF1A131571f89fD06890576e6cD0154114ACBBc8b) | — | ✅ | +| `factoryLogic` (AGWFactory) | [`0x4b1dC2bcF9de73d60e7c38E864730866439A368F`](https://donut.push.network/address/0x4b1dC2bcF9de73d60e7c38E864730866439A368F) | 8,300 | ✅ | +| `walletImplementation` (PushAgentWallet) | [`0x959ED7f6943bdd56B3a359BAE0115fef4aa07e17`](https://donut.push.network/address/0x959ED7f6943bdd56B3a359BAE0115fef4aa07e17) | 10,515 | ✅ | +| `ucep` (UCEP) | [`0x79F07D379BdC26468E48025a61bC955909522c1D`](https://donut.push.network/address/0x79F07D379BdC26468E48025a61bC955909522c1D) | 6,833 | ✅ | +| `sessionValidator` (PushSessionValidator) | [`0x5A59a5Ac94d5190553821307F98e4673BF3c4a1D`](https://donut.push.network/address/0x5A59a5Ac94d5190553821307F98e4673BF3c4a1D) | 1,720 | ✅ | +| `sessionEngine` (SmartSession, fork `7dc20e4`) | [`0x7540f9a59693d51CFB4A3727141eAE4836F96749`](https://donut.push.network/address/0x7540f9a59693d51CFB4A3727141eAE4836F96749) | 22,581 | ✅ | + +## External dependencies — not deployed by this repo + +| Dependency | Address | Used by | Verified | +| --- | --- | --- | --- | +| `universalGateway` | [`0x00000000000000000000000000000000000000C1`](https://donut.push.network/address/0x00000000000000000000000000000000000000C1) | UCEP, wallet | ✅ | +| `universalExecutorModule` | [`0x14191Ea54B4c176fCf86f51b0FAc7CB1E71Df7d7`](https://donut.push.network/address/0x14191Ea54B4c176fCf86f51b0FAc7CB1E71Df7d7) | UCEP | ⚠️ no code | +| `ed25519Precompile` | `0xEC00000000000000000000000000000000000001` | validator | ✅ | + +## Admin + +| Deployer | `0xa89523351BE1e2De64937AA9AF61Ae06eAd199C7` | +| --- | --- | +| Factory default admin | `0xa89523351BE1e2De64937AA9AF61Ae06eAd199C7` (deployer) | +| Admin transfer delay | 172,800 s (2 days) | +| Paused | no | + +## \ No newline at end of file diff --git a/plan/agw/notion/exports/20261003T075310278902Z/export-1.zip b/plan/agw/notion/exports/20261003T075310278902Z/export-1.zip new file mode 100644 index 0000000000000000000000000000000000000000..d8b55a133db98ce6b9ae5af5fc28ba657c349a27 GIT binary patch literal 50254 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 literal 0 HcmV?d00001 diff --git a/plan/agw/notion/exports/20261003T075310278902Z/export-2.zip b/plan/agw/notion/exports/20261003T075310278902Z/export-2.zip new file mode 100644 index 0000000000000000000000000000000000000000..d52a1df522e283b7f3df438f7b0d79993e26de63 GIT binary patch literal 26729 zcmV((K;XYnO9KQH00;mG0DV3~T>t<8000000000007?J=08nyic42g7ASNJFXkl_? zWG_%vQ%E2|M^_+IL`xtZ%%ugp{0;NHs~Nx<<|sKwwisiv&0T zs6%CDMBUgCeKlc6ha>D5htrO+=MiSE^HK5z#*g6Nf35ZHy#a!fvZkx2FIu6HNMP^p zu)cLZeZR_{JwN$6YdwCEo$UWU+aL9^wd`GEX=!b3ZE5NIY;SaVIhbbOXD>Tj+q=!( z^JeGUfoqoK^PkQ6Q)l|QA-VO50?B6tN&FxOM+|RG_VLu=CKH8(5>H9pN4!gYzz8hUl z2cu#4BD>1-@!hQ5Z*FcjcI~;p%_r0B*IDP)tGt=NdgUNH7-o~+=qd+p4*IM&&bu1p zZgze>><@;o?`EU-!+f0OAM)O{e{pZ}--B};Fz<*UI3qb?uqGSg`Mo+s8WMx(dPxMHVybUn>R=f(1} z?B_rI-`Uyq;KCO*8N43yY{pWu$@Ll7GPPfY87$!6UbEdvw!FG(E6Dnz-s-BsVaZ2o zAMdU0GX|2E0M+0py8ivg!Gm}Kp5o~}*abg%OM{j6DEJNw9x zo&3X9-kawAy>_c}H@m#PfHZh5yXt#kJ~3F?UUMN|BJ}f(5J$g&Mro0#y+G0*oIlpV*kfJd&bKI-+8)mYzd zHG13qey`r!+34;xn_DgC9;>S$b$T^#^>=sM&CQM0-u~7`v$5N+Z*FhY>%IP7v(;SR zt)J~}Z>(=O^(y-}e4D-z4!%zZy1J?r|33d%U3B(MJ|3J8^8Wn#3r^oT_f0$lY9AT? z7j7i``QQJKHg+24$>{Z<7vpR;w!4k`Uh`42y}h%wx3|;WhQ;r1?Cka*wVT`h_Rgd2 zhwUx+^7rL9&Poqv4kO0f-+t77w7$Nxx!pY9-OBq9^G7?o?d@j$yz!`h{;1L1*~oj_ zyL&U^U5~He?LrDzzHRRp0J~fk!z^4=Z+G*&vAw&$-ra9Ech=jD#@?gd`uX~!opycW z;iLA>=K99@`NpI9H5t5H{ma2HHrLu(-{{tR4>umIZ*T1H>^^MvdcCuLZ+m+kJlJXV z)&bwcM;kK(!AK^^n{T=o1BA+G9AiD&-rm}(@2v0as&fSfJ)f;VVaL6Maww`bs**_j^)<9G$*szWQEW zkB_dWXCqXD>^#r2e|yaiCr&-rc{jMpFB&x$GhwY)6I6_VdZ>Y>GCXg$Cer_&q4(90 zt-utPqirJ|vmkww*E*eUHoiuaWV6M|!A;;Q<-Xgd$c)BMNB!%I1c3%juhH&qZam!R zHMY0T_s(~=&Nmxp^+&DV_TIxrd%LlJzTG!EUtJxJGUR8@I+i=VF7ijeb!@pDAA%PV zC?!bi-X9IoWSaHn)>?gct+BK6AbZVuPqGfGR(~)(789R#c=Y1q-E1W~eZxG@j`y1NyPRWJyf2gdp2keutxY7$PJMl=S>HN) zxU;)cuOnX09`3hxHn(=S_a8R$&HmPw;m*m?^W(kttG%yV2Zyf?TTk03&sux!<&^;O zSNY(ovAKD_(coYH`HGiJN0E}!#0D8o$B2YUwx3VCgNun9CjKF~c09U3Nkz92-CRgd z!CDwykI_U*VHp@_TdWusb4Er7L#TrE`=*yn3SIhw8PH{>0(^haoBGKmasB`_d5s>3 z-i4wY`nR-XSGcjECga|{a)#Pubn)jHQ@5)uH^-0D`f@#>5KE#l(WvP~FU&I2S$;jb z=uga+K%Mc8^+%(zlw8>pImD7Q^vb6%&|*(qFh~Oqd!u6pM+Z}*Ba@@}p>=`n6X2R# z!e0hv3nmG`eYt#Jo>kT!WTM`W2@Rn3Zq^h22sZ|zA^{kEOFNbFcs05h^giBC3bViM zpbYZ|z@ovMcAO^|ngsy2xWqoY%#Cdr7r_Vi2^|AWH7O0;3C_uhm#D1xQi6P zS;KemN(9#EZT`TZ=A6uJO@tbpb}|(|=x4Mj7pR5C*`$1jt}9bsqddQYAN3J)*I1?F!StgX8G?+1K@KPv$uiz2 z5Har@A+rBbtXG2XOb5?^@ddD7fZ#YvG+okJ|{cX|31f8BdlZ|5>e zYhDDAwjI(x-U*cR`A(cv=N4Ms_X0`x=g{Y;Rglk2IJ?w$xIPxZ)U|pH$tQ!ezcf7O z=kf(k@MWO%-pkIqQ@n1j->{&++kUl|q^LB`5d(9Eje|@ie5bXxJT(4KL;X zoZzX-kFG+S=b@sFooE9K7%HSBppe3&8dB zlloRfw`-FD(rNjyb;?d|>_W&_x>0X9O8=a-e*!0OpUKx-c#7|0k-ZD;3>Nwx$1bW` zcleqEI3JHLvv*C=&2hW6|Fr!Njv~dd7AknT_oVfF{~vyqV%R{t(NIhcR)NxwK|dJ2 z>y8J6R*cP|U`_8m#GtQD|Ka)C+~B?*(P*zb91Rt9KpLBW4!)MN%nJpJi1-w0v_)j_ zKH$~J2@@$KVv#pRo8Gw?_j6;^Nv@+43OkWmXpJz#@SdC{YiNnnT%WCBlJvgtY|9v( zaU_q?-9BWwLtkb0()84;@c<2~7mfpLaDA&)NR_jIMGxgpksIl8m`UZ4X-nAXYrL`c zuHlhPTYF8W`~1h{{BEkf>0X>`g!<-M;h0-P8-ANlEtn>tjHkq?V#qIf&T*IZy!yKR zV?97q);PnHK~W);YSSKq-mXiaXHT6 z$$=#((-1b-Pvk1C4?Qd{Q*52&)R*IgLX8EU#ely$GJFzc=f z#~WX+EwRhh)s_Ncadznp-kA5NTQHHg#CDcTlRLP6)%3o)KI5Sk&H~0SHWS;s%HDJ* zZ|)M6yq0T3&;U#Vcoqj3uUIUYa}NJf)stjUCWxvb8GZV}4w~JShjj|BC@d$R`I*9v zc{Y*joHfEWb#K=y>TW>Xmm z(+lD=oN7d08#p$#xXH)KG{2PYc!X~#^!MMGE3wMS?f#xNFTu$BT4% zc^xju@oS}P}LgAWxvWWLo^|4tAf+~L|}0`sz{T%O-Z64=A! zC7jb;fvjvA^KU;ON*sT20dce!0tZ zax%CdRP1u*vXd;N)~{KJBG13h$Xsy5;(?)z_hKy?#8&N#dFoC`5Zs|%^_$>DaVcrb z2#2O{{ns#}+D_J4_V5g761FX_Y$qmAM?QT*-1zv>Fnd!-OZ#yD-d*>!ytlA-M?vy^ zpxR-F$O;$L~%$1s1t;5(ujqn<^db-=6vzqfP(@we^;*8T+a?)3ATZXI)r2 z#}em-n}hI1KEPM<`o0njEL^NDyYTFbw~53qN2rXKuuR~=uX-XV!x&IOLhD9C(>G-E zC{{iiPnEzj=wpj@Ivw2W0|GK1mrB|`=yTd{^Ios}7AN6y_iRwJ)QKD>HXF9o(awHy z5QoJ#-HYkU%F;dbCVpZ>BgysV@->#P#`VS446uhn%;l98m(Wkzk51RF;FC&(VDefZ z?m95ifF3OT`A`2Zah&zL;cwzY0$kwDZ1Y`k86ibem z>|B2q@BSG{PFz@C#st-aAWmQ+>Yxv7R&-uUBj{8gAv}cM zpwkb;CaEHEN}kI+eh^e58oIb}=nOzk!a>IR+>_~=c;eY1h{B&PQrjmf;hp%S)S(h1 zMe_~;NWVlwmot_v<$Om`9*i^PyrCf(0lQ>p$m#n5B=B*NLwx)mS2)*O!~UKfc=1HM(Xz9e_{TB)V*x;e5xPP-&%YCYUOmoM? zdl(97i1_F@7xni$U@qv8aKuqTd~_l2z3L9efgF!X=;>ZSIz*2_l1M?6N}}H`o$KFc zm{#{45^i!WT0_-M&h)vLPrJ(CU!nQe&?K_X)^@X#AWo)PM6yE1xM!O#}qTJW+TN z0LwQZeLTtegttgVw3LUZ3YZ19#xSsu;#0UOHamFu^Z)+ifBDb_Fk(dHP8ilzaOC}X z#M6SkAH^SYyjy5jy|>P^r0OJNY{P8!(b?Z(u)Dpsw6yOb{xLZc=qMge(EQ?RlQ&8} z>{pU1YO5V0h?j$lj}~z_Vv$NYnOxzc7p~|nH$EVxutJPay#RtF0voG6x)LGW0ZY6E@j5bqb>{4x87!#KF#{aKgNynDcYe zA^1T=5yk|=7(gTwaPe|8)on5@Z_|0czRN6J#HVKzIxGm z@}zzGa+qT@jo*F?Q(4PA$Y4sSLR6@57ostCC>@tmwQL!H)RLfb1h98HoE(WO%R-jU zGg3+7Q}SPc#8B4BFx<1fYvk5t1TJhU@?N0%ibTfQpzKxO4+%LU8d6^|wW<>%fuMey zDErQE7DYqm(GRv4a@@?f5y;J}_;gPHX07o-X+CBeqP1P(M6rQS+K2mmE#8WPGM#*o zj`s84|B1f}x4#*&KBJQO(7*bp{O{5NVvTH;WpbtS55HS6Me*i8+Bs^@cL~W9FP1NZ zGy1`wUUrS^H^CWh`earX&F-TtUv$s%i`(YTvYWHpYN4qQU*kx~epocLva*+NA2aqC zL${oEUVeLX>rTphO3XqJ3~)K3FV}0e;aX$i&iu9IAj;d;5!3r{Fv?;7B41kacWYrm zO_nY9YI5u0lxr>kb=3nnXk&O>en`WG6J=SP6-M-(BKX(&?_ibX0JA?aoS&-9b|?gP zNKh=<^=Vu@NMp3NNPP6gLU)&f*y5oX*Su>M(_l5D_hu=|t61s?ZiF1WTa|A7FwN*c0%U_PmUu7``Bk6R8lDFIyKE%f&LHLSh-aT7xAa zVY)|f`?=+@4A)PLmdq#@QQ3Z^goS5w&D>HZ_tKUVEWqb-Me*U>iqqy}&rd-q+3d?w z99$hJc3|cUv^UJL^@5B2n(L{n7XC!xWuN)feRAowhZfcTp>hVd=mIJbdv(}8eQ|XB z``T&yqr+FZ4GcYo6QZmn>}s)4auSkcD`Z?20ii5o*ks0P*#p!wD(`_ z@k4wWPrf2f^6I$#*Uwom?9aRl6utZ^J9=^0KF&@K_S@O%AD*>O76^9dcgC2c?_jx@ z!2c)v?~)}BNpZIGaM$GhR3?H$T0H)KcBXL0^g$@fU*{jPA090EyN1%g$Je3roRCR( z$@BF>oh-&e(0^Zfq9M9E@O*$0W0&;HM*wG~2D56qy+O}Xzx8uee<5QF}2Eiff! z1TPt43bJ$U(x+f5V}2a27$>LrfR8Mr?>T;~3s!J_dA4W?%#MiufPay3Wym-G&Bo4J z12EW{HL!b&C?B(Q3U^ez{B~wHj3Qq;tbI7Zd4iQ-#hs<$va$qz8fsTZ5sEUyJd*QK za>W}m&P-JTk4ZNiLm%L3eH4Ef(`aN(Is4gietAXipHw7^crf&3_ro_LA{=QVvyzs| zk)>cf+p9c#IwDxQ@JW+}&-Mg2oW%yX>!BHFdEW=nB-o(09e@o`XVul$u1L$g4{^F# zTE3i=5~tB0=1!rqf%uVq{QP(SA=_akuD^kcH%A2`H-N!sGnXl#2oy%c)h>^_P;Q9#kzx!I*D=!`8~;tb&6nY!%KdT>pemYJ}Qt zr5V|8euEt+P%~M=Au4phhA@=o=F}lOPqLlK&*IEl85RWL(2KsRj3Z@CHKnSl>E&M$ zoK=b#bAd%Ivm55|tNPsxp3N?Vb=*o<&-UgAojX%OY!6@Eln@?EyTa#^7{3+lO-H@a zg;h%Z+M?)__uZ=%orVk;3VfYzTjg&Ra${^5-g>iOYn8`@=r?%UJV!etA?F-lFZI1g z=6foMoRH_k@>{shh?#SSa(!kUg@HTS8{DLF zkRL-p$EWRm_pbL8#3Vi;LFB$PN#lyccDdAH-LzQY(9Nsk?lQxCw+}>vlHulLR6;`D z9V-__pMy%XQa9Lwk6FP-j;pZSLJH&_@F*c7EMiahvpcR@-hn9Z6uE(SaNY~&l_oFG zU;HW$gAb^)mbk1)%|$X(k0lxSU7^ayn&xHK{5i`;ftAllz1y@2bHuY6GdVMH_X55A zBh%>Q3okLibT|`u_DK2yy~pTo?nBAJiTv>i+k`@F@VNkm7Mbo9(Ct&CB-rwH}TPhM#%M>hE* z{F+O6)Q{F}DV6>P`O*d-Z|LKP>NUX2mthXe)levX>A2L6!5#3CX1TP<`xaSS^!~i2 zSiD_e)XLHp18ivlY-R2ILg4`0joJK5+kCsNZ)G#FRg6=8p^FM zgq5XTQg_JjVhA#L`h>qZ67&$#9QHiri@B?&vbofYSyrjIk7MOviI+ToRv1VgV24k+ zjoCUIJnP~rwW6bBRC?4S{l>8v5h%r>5*IexmZSn4;ax=VbY!-OGoU+ajdAC}QZZTK zBDm|)oQx?VK|0l86$<&iA7@}-#c^t zL|6jMi=4-_-O~@+1&{xx6zJiEf0JK;;*<1-I}muT`@RcnEH+S!mI#AC=F8~3X!k_w zlOF+BwY%K!S6(O$^4o22Tz9BYzSaN(GVM3noi8u`FZL<}%m3K>Us|+PykFS-KL3{% zE*0;)gFq{=`M+pC*U=19rTO7xH&WN%|$aW z_U8EZx3|xBw$Aci0pSG%=*PX7I;GjMf8lbkM=OP9{|*CNw#~+Jna1W23R2H|bxH zZ>*m;DO2ukH_mp>&bPOA&U1%VWj&&Kv#MWkawyqHSG9NRUlAiPmI9ePZ@)5&!|*(r zp#_wlA3iyFdVrp#vuqCGjehl2mcM%-&s9Xywq+B^jJlB`y}CM3BPFSPHi7y3+|D3z#^*#?bPb~>>tCwN zeEPNm12%@3BtLo@&w#qkb_-vUw_h;CdmpLCzTQX?Mp4f!p@PFw`h`uabcm>8RB)c9 zEB5S0&^cI^D=sak;7c^nV-hMLKxNw;iQw#IRzZ?9CPWV{$75z>{aNCd*%wsZj_9q3wa3tk~9BvKS>lll%ls$RAMMvIk#or;S%0YQD6ak;oLQHba*}tLGEj-hC#N8A+x$21pFP1yv zrNIL6!f*;CIKLy|cgbhD8uyy@nk7NiD7Y9-$p2h^nZ|dE`*xvLOvxlFM{sxEy-eNi zn)Q%!SG|Xv)|^zpO5#(+)Fp@t2$!|u0;OYB+P zaDw{rY!6<}aYFg#T2KQVyg90-Ot$rd>Q|1lh3xvgo6Yj9lzpTGNx7esFHcntr_hA? zWh~8c`oWxY;4OKf(bx%^@vee7SqzRR*6=B1mMhVT{%6T9OI`wX;bG3MiF_}>M9z4! zf?B+Fl!#Wmbt+P`)IzBJ8o!BAvLBiyOLYzGjc*jg3D#$ zRMA{Y)r0pN>l=5o=FX0QAYLaK26a1h4I*Hq=cf7s9OJUzW;B0FbP0Ep|3!>Nt&GU( z#|>f1qY~USUL+{mBStq=AS)e2zFP@6@_NP4G(xynNE<9OrhIQTB-(;3k;36?PF*7U zKmXnTmAN3Uq(R&dgq4_=gm{VME?uVP%Pz>ZK1AKKbU=4i%qnEiPP6_B&-)F1EY?@5 zVqs9;&FVubVc8FNogkq`6fruHx}LU7%cN7p@JD#BXWYmq{ExS~SqR2Tmv99-3kvAZ zR8jbmIuX`opckix66+0^>vACB1@^yD|s?;sKUERr}92$diEcjr*@ZmFb zK0Y>WQs#tZ=Gx;=lUosSpfliKib}Pixp`%*pc0pdrS#5pD`4 zuq1s6oFh7jxyK{z2 zVw+cnIAA4cy~nfCJ3t&~GLAcra-P<)!1J3Jki*o~W0vhaA@s_ZcS1Ho^mjth(vRk2 zxbyAZ>}3i|+diDHND|JFmW%g9U@t3fprrjXQY70|9d@4BoR)-%Sb9{KIl7my5Zpdk ziqmWQuf6=1l_@QXU@FlWOvU2+auW)m=miw%e0oP5t9Yo~UOZ%5ntjIijfC`J#BJsG z)kha5%TfMT?pKrW3$gM`wE!g<+m$jtRKRvut{>- zX-Hd^GA-V4YQO{sU5!1vK9iQsFYIe@shZx4T(~dDK=Mjs8T9x;o#3=JuYEv-7ix4d z?^DIsYz~#B^H*%oIFz_+e+-&kSie9$a{wc~z)nc@C8|@V7qjUZqxotmSdZ9XiMq;kj#>qF(jxgC8PXz-`OVz{U6Zjf59IxCA9^l`E0%Ml^DDA zUKA2}0OWoJRV<3IY;#d+r{J|ysKSw^&t9d}c?I)O&qJSx1hdoj@zWEQT@Z^=+&sOx zRCkgTHErzhL`h5oG(j?FW-026NYh=K&^4SRY_F~cTvWnD_Vak}Q=5`TuGnPheVJ*qGgmU^U{Vb?1$bRb95+cP>simXi zVI*dhPuK@Oj$@R@4Nv((8Y3nvs+f<4kHxYOViJ=c{y{>G4t?zLiD6qJptLD}QR?yoD;RVZ zP4SksJg3ZyQULYwT|UHOJ={e0SPKF#qQa8K^1$tfO-p5#$7BUcDfF(!OU_9JK%)xq zAgV3V3a3{rI5 z1cQ!n@a4C)#3_nO)N>pNtlJeC`3O05rgvA4#=XeTr%_AJ67VjjN)zdPGDYqyAD1dP zgSCkX&v5jkl8-h)@;8-iNG;w{>E+s>5OF3Ol8j%L%R=ypShfh~3S0~qfE)*icBgHb z4S|ko{Stga5W_MHeTWj-tcye+4VUx=PP}t76Vx;$%%`&fh4XmKjd?M6hstB%}=6y21wXGh3bVOo?~t&*S}~68*7R`(ULA#RL+4N3+obQBL2xvN^_?#*K}G5ynWlE}br8P-CO^%z zlH!9XzRbL*JG(zLHcC=_4&7>d6ZZt(!;r)jp#>~EOVN?_#=sH(eI$zCeT!3)o@gA=uL_HFnG{tlMEvA(|jto!kj{_SL~SC(mt19C5+Rk<)z zr?N;Wh+%z^vw}E*jzOsf&r-=s_UPc4@)8AF$ZNbHR;g$mt~6{;Pm#RI%4`>jiQAOb z38jQ&+004$*Yl^~i)B3tPD-$b^^U1B7IOws(i!6{t8Bg;J2s!za-}{3AJa~K{F#55 zEXYbD>Z?RWNyE7PW!|ljkPAuoT_qBdlH@e>l~6yaNMC8`mTmZb_Q<+ie4o8g)i@hO z1nL(GKf+5rcWG34p~yUOtLL_65zyWh?8GWUydM+VOfSDuF9)J7e2#09o@cql#!o*Y z4ld3|V_M+^Z=rwh6`{579X_r_su7K~_@19TF%~_)x~f$e!yx(#%OIq{_!Use=vc&U zIzRm=wDVdW^TwsyhT=R?ldO)1)@{Ejw20IX+naLLGTcq_r!u8ck@59|K7tD;0{~Vl zo(Po?J_!e%-Nc0;oo$rjTZOY}TT&btGo-X7FZBB<5A;f)+vX{ zi(8JYS){HBO6?Gw<)MM8fDapLe&Ng=bJ%)j`5z$r=|Azt9A8TxFXkiKPG4n{sYH;2 z2X#O_pGdmPaLsijIeaK&`3#PvXVd@2og7u1)KLZcfbvcv>NfcsdWe=LpSI8K# zNg8tj-m!g=T>OmO5iep`4q4C-fLWmx*HQ?P(}M3zW}X&1k+nh|`+NM~7#dPzsIxYW zQA|YRr4`yQzB11_?pv!3x7{;$NUgaqP)KK70;@xP8Praf6UuusNVKJF&nh*lVT@B{ zk&_X&@LgU@i8RiJ=Q?JE0#>mOF)42Q19LCHYQj)(04>8LG*RK+G8@4dt~tsU$qNP} zC|oHnlLy?Ct_}Q^Xuz;D<4N;^)Qy5gLuyurov~LrTgQ3$uK(Z?zm#hmw%BALEgttv zM@6f()~N+3aCvF?r1U>?@7>%af@>;9vAhn!RBHHb!l6 zksw-FA~tl(EITC|g^_n-OoNRLUEEM;iQvL$+HUD8uaCoH2{XX7BR_ zZdukEzkW8rRnP3QLKnZOrRi<;>EkIG@`a%;D|%8pkHlvI`5y`u(^hIw`fh%x5Q`9?-wODE`sDOp5ruT>{mw?X@ekWe?8@k^ zq65O{O+b|ftYdcpeX>O3PlXQc+oTBk*J*X6*U!V5>BYxf02=-DtTP5oMW0v7@SL|S z7~Nux^W*x&F?#TjNbi{`V=ML&RK$B6i=Sn2II&5?g|qRXuYS{RMjLBdL`KzdZjut~ zO5>EY#JupMS?Wn>;VTfrq)e5$4Krdv->gp5T^y^fLAkBi3__?Dn9UTQ-JHT|&Z>u! zI_}6LZU^QDtJDkWT2=BWrSQXq~F1LVk3+Kwk1YIT)_ z+$e;yE~U;KZWKMK{Tno`JHO!OBygZy32rDT3;>`$cJlgkfUpaPDiBOPa3qN`eVJm!7nox0Y9SyYgeL zhLd1-Mf@X03}>fKgUSbA)<_c2HO2|jI_WKqhv_ypKy#cvO`=x zD&N$+0O2Q@V255UQwYQ@*(QNo<~~^_Hd%7Gl~iaW-*)&gEhw|PD$B|*P;dh~^YFH_sk!WRV&p9e-MJ11EVsX>TvgO zqOs`$3Se2R&d4#Mnx$h&+4yD^CMay7Jt}9-&(UNK1^hmGrPIJlW>!ep631%n~Vd* z@Q(<+beJLnom>vyt@y}O39$C1ajpKDxdf}LH?j%X(*S&od;)$e6AIA2{>+qu8V#_% zB&C4q+zpCj{EKo53N_DN7nn9euB#Ew3Xx40<#qU)zO7z$Bvnx;1mC*0T*r=}TTMqu zeo(>mMoPl!D*Gst5>m+N%QF*{S9_QT#t5jUAij{6+AEKjpUAJUYNm+%xLx8glhxJa%dzl)22VC< zkt?FjS$w60gEDc7>D~ZRgmy_ftBmmS12xh&eh8i8niHgPIE}Oj69)4*Wq$?RwNI- z0e9as$&E92P}=v*bXKOsPd^qe7CKw7f~3-$l8$sPvn6gk>QGvoJ8|P-@FG&~7}QFv znOkN&auko)fXtEQGfHgKeA}=Cc?3;y_Q`&WfYt$belb+r-cbS$$U_n3r)=-S_h*;S zuddD+;9_zZ-)8K|*{|q=VQ<1EwR19Gg8dW4H}WFP+U722OB_AZiYi28*6&d%^D6|OH z3H3$?bBYY#vz%pAF+)OwgK$urle>UNqZ-04O%}tggj%&IPiKGw`ra+BDKgM^m#mRI zEz~jh7|0t6exI3Rh^QPa%pKdfj$si9RCSdJe00>HB~nhhYvn;}tl~&A)88eoQi(zr zQ>o=IV(3Sxm1J`1asd4{8q4j{^1Hv{t+-W$JVUMfi~ZG3WGea2KcL6zAnXnwi*i|P zJUN14jAY1BWod=nVt%P)*w@BXjV^Q@fuCQ6p z-n^5oh;z&@#JpzJJbSRXXqSiQZN`^mT&i#t+}NpGA+zB4lxJ{u$yMJ}g=E}xh-Fv& zm$O9mIWpxZSHW<4j@f+p^skw-REx=0I@k_kQ-+yF8_j zQ_{+36W@J{K9*Gw`;W6-X(b{T{Xym=%^ZV35Y*jg3*0(i?8K=I7aMdVd~s?St_pZn z*jMn>DU6<+f|v;q-yo8=kM}7KoG% zv>>O7fC(}{vOzsDR0%KJ&BLY&vvHRT&4MLY${Xp(VemAsmMG~76C9O2Hq27H!ChFr z4BOi)93);{$}fnVvJ;f9u4HauM5Xcvy0BQgpu%4JO}62wl*zg;({pC5$ytV`Rz>7E zvQBAw6fH2PTgT2w+Lcdq|&Tu`t|BW z;$m2udAWLBZsOUVdX)^%BIBeI&ignVuhxHkWNMo$^2oqHtpRT-dn#nTCcVG5S6K?06AA#jr}&K{V}G0?g@ zMk3L<7Pn7vWDIiaQGM_J6WmGBCl}38Zjy?Qir-cHEEo9Gk6@b+0Axz}6LNg2+Ll0M zL7;Fs&P^e1!#}Csg;rQ-@a!?#ljvcA$c{aA4-h%4`?e~{{iZVSKYY|QJN%@lORufr zwz%~^edKkjGQW}oOMRI!vEMcBb6&Gd%dl)N+17M>RChFBX|7qL$%3rKw69LXT_zr#8;e`byhW~Q|6`8K4384UnF(9>mMW+j?E00Y@j<&cynw)0~>%=_sg~Mpm^*lUBuWJ^Nku5)tWNgzEV%RfsR?edr(h zeFsG~Uo&0DdrzfSrU9kG;>i1!y2D)Y8!DmKuH4UxW|`4bWRccU`3wcbvhNp+l`_gz z4jr&jKwNbubONY{o*=plBQK9OSuJd9K`lxM)-RcBKEoHIHV{budWrXH%uPz$SwH6Fc%OSto^I3jOa5WnWm@s?i}1pe(x zjbh2(n`N$pA`ETY!Hp@m=)bTLtB%mnty6$ciQ(=Ez4NfO|H?1^`+fTlSmJ6vMS(gS zwquAsZpM!dx1&NNmR?eSvHoz&!1nty*B_^TV=-dReObIy>GWYY8?|OSpp@oj@&bsM z3)euhH|Ia1{9dUAkmJh=k1Zf)U8k45T|~J7IO0sr?6-vP4GvbI*dKpf!&_%?a7_ay zxfM><~833FN&=-*64#YUQ<(EOn zraqU1nB#$8Sf9$H!a<`RefKaF1rjr>!UL0x{$vmpc3==ho5h z)zIAT37FS_rB}{kuJqGx*4Xu8X3oM%$l$N5>0wUNC#=>-N}~BZWehkSr@+2~{b(6R zPBv-m4FM+~l9-j|Av$#-<)%Dd1y31YB_Grdb-4nPD~`~h&S<)wW3`Bt!sp1?b3ITG zi;Z|0u`&;|r*tUVjeBKXY0}ejo%r>YQm%gbj~lghn^Hef@E%M>V@gb7X1<0MSayQa z4$?mK{h)6ZKBom2OKyECVkLC(;^GT14$87Ij)Z*LiU4D)wtbshni^^3gE~~&7oidg zSHtA($!aGyXWH)s%~8Bruc(KjhMmbr6z2#zF#?h8Drm$94}HW65YXJYBX|<2z;XEZ3+K8i zQg-VimzlUhF~a!8iT>xWhONSQ>EaQ548#^$&h?ZtD|g;WSyf5_&{30tVD@w{PTPg2 z=pwV!-cNa---_)STbd0sBt23DWx)vrb?lO5knwX+MqLRBzv$uMyF8R49YRs_nUqyk zYooEQTQg!e3rxLz{UI-w3TqvtozZ@*5z`B)7ou%W!$LE{Ofr+Ka~7?gLvSWQw}xZR z1QXl&V%z2y+fF8)*qqq5ZQHhO+cy6BSNGoi?OybvtGc>+aq67zexLVSOCf;j{fYR( zyBwPM=B8FQS!{~Au6M1fY&&UHa#UN{*{*~^odx~tUGupdT~2&uwTm%2KO3Rk?nvb< zR*FoOGRq58)Xl$++b;pS~yYU#y$>Q-$Ax&T0WDD=K&nVfy`UxbOXiY zpeEwuwc0%Y<3X7*Hq@pzEZDYR9W8}L8~L|5b=&+kF^2n$!mololb(e|5z3&Z@Cq!~ z9!5ZcEHdompB2a!gJ{v2p_xs7y_!Vi!!UUY=un1xA|EMgVXnU)DFhjgC+sNt9t*&< zd{lKS_~fKRh3rpeF0Admu$4(5UgaWRY3P1mF^IrM`xY0H^j*_%K1u1eIQrjVY$^IT zU&fSy*~~KP$t|_xYdKiOgojCXv}vmo)6;+s8=fHjJ!qX#vi7AV7%uW1&FA{1Q%PXCC;1O?EEVuJHWom%d<}i@bfDe zN7mkPztf;J?gcCOU4PUyZC$IR{k6SvY<6ki2%V{1W@lTz_vB`UR#Su*i*10X9dkcQ zY`NjaGobdGkQH67DsX)e$q=ADwE}OeK{l0umW~%G_z~ON3q1!O$5s^mE00kZmyFAIZY%v*b0xGV|;Zcx`mTAH{cH_I?t{i(5QWN&0lLR?LSizQC5$ZPzmRH({~- z{rPG{*}BgBW4WiqQOB2-%tn0V0eZ@)>ei_y>vpf%sV*DAsLCI<7Y=BOo9njMcqdX? zy8)DQ1^#x`idq0G6_Le3S}w*a=W@RrVech54L-ERLgkT)aXRBZN2fpF1I`GX*<9FMrrDjob8$Vt zE1%`(epM8A{Q7ClHJf0|P*}E#&z5HP`RLhfb4t%7DixZ|)Az(RO!0HougoEGjf}AD z9Tx@HXLt71GF(>f#}nlb)Z7r(I0OVK?i~J_#s*VXvWf5BV|IK6IzlAq2}El;T7R3x z?CVmTOJlr1g0$~(-!^|?UD@)KV-6qjd*dtGS-Q)%hnGFOlU`u;c+=r!+$_t#KkxBn z-W(2brWOI0zb)Dx0F2IbH2(_WkJ1{#M^{oC4*%@Q(i3|CN5x@c_fFV@oGx*;e?XR< znJR0pv3jef95rZ}KE=KE94`i=in>v5lhKn61G|zJreA?r zZm$$#%B@Dou#}G~is#@kW*r9=y&12pTUIU2zjw-6?E5@g^?m~HZRSFT0@`kZypvA& zZkp_*g)T!?UB%zl28xa=brYEnZoi&bbt?Y_@VfpuDon=1V5Gi*DAEyM$&OMVRGRp# zU4T*MTYUOQVDe?zet)2GYO{>#k45a07jnXM&)TXj zAba7c0tgFD-gHFks8HlMe{%oJu7hg+;h5Ji)GZB?R2gx0O0hrgoWRCdG82@J+$5t{ z>a*jH*-2Vxw9CP0FCf@MV!Cw$2CbpGTk(E6e7A-A;l%`5foLS7mX)zmh}0yc<*zAn zSGTJ^h7Gmu7oA(eqTn4A1*7WwWhYgE&%Wf z^`Xb4o2O+aVvB=l^yij?qgmX|AsuBf&aID_R85nW{4`_0Zqz@F$Ns10?uFxz!-Nf^ zKmuqSfZ*{;4WXFJ=3#Xd@tQ})xDM*oDlz*6-fH#owF2-|UPQ=yNXE$xRB~zyVsSXc zwVg_zIoNYki(N5QHE_!lG;>hlm;CND!mk#oLSu->_jL7K8W}Yl)FrNjkCN*eBM+zz zH1w%u8+!bC4Q7ON?va2Dl-H+KlHfz*^yO@h$Y9=lp4Z_RBk%(E%lNZKiAgUFQ%8yfK%{n5=zxEO z9xQl(ZDzsTZoIzG;;kR-zBC*<0K+jjAJM`Ff=|hyy^cySbKE65OzPo}c3blc}Ps?fr<;D_|L8TTP~e8rnnXgwW$(oMw60cyw)NXGL1PD8Y?1%{^8-(|@O zpBYgP?vzw3uc)Ns2N0af!F}c!ERiK6I{p_o zIvo<|ap2HrtDj!q<$@x;D*0s9%`5r%qAs$U@#8j`8GbW1ask74m7D4z%y+JlCajy) zoL~=NUZe$}Jsh~wpbT8oC|(823$3I}i5?Ii@+AsHf42mSJQ`sHHFuY#66ht94J+X$ zZN)TUJ^Xk**_*P*B%DUVJB^EiP;FhJ!)Q`V$z4mdb0PiL9^t8)Y8!Mue4e zb5vYJNzial$)ijSmvF=CS+Z*e5vu=P~sTRBb`G z+xPJD^50P$h?!}hx923fhx_a=#OLIDzkWZtf>t3O3wPB-8{CX^8E2XNw4Ykm)EXA< z%y;~t&E{dwds~T$nmHH9sT_A`dU@$R^}KSb)&4M~t&)RGq9SB}S(MB+gPf@orE^-j z5YaXus?WlK$&zi0wWlgClQjU0U~dG++H7q_E{%^nLYqUq+_w5*uX0C05D^4XIK38- z$DL?wMA4M~@8bxibUPXFgN)RiHn-W_?ORG`6^T`r9R5?7<+~i<;Ir2{)6ua*l!5qX#ENbulV47s^9`^=L!Z_OYu8 z+UMFD$hgi=Dx;wM@^r!~x`kwL6bh0*_c3&>hdjE<#18DSEC~gBR(v?A(nP$&Wi1Ei zrB%o}ASpf}qM>scUTb!o03bNGzP~Vu?AIJTW7bvAo4-?FQ%qj<=|~wsD@y_-NhU98 zFnzdHh?=aA);qrJ`I$T%P*YjP0MupSc1257bpBIn z20?^vAG-FZB^vmXdcv(ib{UH?lhWgweTp>lGNg&N(sM6ruN5BqL}(zj48D9yhDN3q zD&$}he0tTJa4!Vl%9xU+hA{8IladbuJn^}UlxdZI6iW}U?aqO5JkjY%)=1iCMxB~M z^G+z?=N>=1ZZ8$cz?TG(p%lx)gEqTho4!7b#U8zT7XqlZJMO*W&Oh@)CW~Sw`GxQ#QRJ-{bZZ?5gYeOOkr8{^SpNLbBlkE6zvZ zqr0gwdm%N3*rb~2^^W9oMnI9-?C3$=xZxJD6}hyDSB*W6{4>i;_<(h$g_1gQNA#3St zFUAk$9SX!l`E}D<6Dy}J^ z?_@=#r9W)bV{>KV3VqTLr6OSFp;)qhH^u5aJD2Kt(+U|+6=RzNR#%RLSfXtEC#mX5 z=&5P%m}D{sUb7haRl-g((r#uHAh(T1$f$wumn?6Ys3QvU_m6zlf{ev#Km|~}BdqkyXdD)K2@zifGB#qw^7pA=lH?H|~- z$nrgbrJpW2Q%Q=T2`iDvd@_cQv-V;uHL98#;T3kwp|!O(vF7m(pryf2*xCuEmX5W} z`PgjiCA(^|UpRXuGby!Itk*8D9rDw@C%TGDP4sq&ED+f^gX91Eeke6}Q6HpW?u{Wq z5yuqr3Rn2-Beadtb4rdEifdioNy}y9_{5`Yn)GLbDT%Kx>$|0A*dIeki1)4^e|T=; zaVur~)ZjtfyS$C|#B+{JyRMB&3s){2=y5&U3z>D4aQjlD+$POlqOg>f`s0u7Lwf{M zT~lXkC;aAkCLM^vhlx)>z#PpbMt{WbM1QM;zp$Ka^>*Uy;XAS)Fff zPIr&xpZUd=fBRj@r_UcR>us8w*HQ{YyZ$b+%VavTr@Q zT6MO!F0O5C9^Y^x>mwhBY`Uk^UZGCbQF9XZ4>y?h{kxHWXsfk>TUxWx>#JBWQTNUhE8s<37)ZKYdYWw(~~8)W^@r63FC!r6;qmf&xjuaS`CjbL|K#s*pJT(-*e2tC6d0L(i`yVN(g0b@oZr5bl~JAJS8-lb8Lp5hzO7#;;o$QJhn{O_&wGrDQJ* z2s1s;AVG=d@9^b~VY(=*TrC#*QRD8=xeAZT%|996>bU%3>&^y9w6AY&#h=zZpzPoo z_p3RbbrjX)(flb2B~71I@jN|+?WV6@3`2irrLpbiWmY^p*=)L8?75V}2&<@f=05)& z?K60c4C(Uty%h90tb)t<;J&rFwZXX_kxSibIQS%-v>JYra5|ar@OWrjgnZ#s;6OuU zqHCVRaVDdKw)-zcpA8FEn^c~33fzU&mHj>6zeDQ^y@oHH88bQ0M|Dq6gro?}U$=D~ z`u!m3xLI&fxH=U>*D&UsSS9ls7|Q6K<376v;wcB8i=m8+d9uNPc7yj0xA~71Mj}Ed zn%YWnov)*3yI|ObWP6JG_QyEc^7&482P-wNq~0U&6m>(ss3&cpJjsnx?#-jj%&|Xs z;dBJ_R7c)pZ5ZkxGFlR6$0s~oeqInrI+wUTulYCQ>wvlXMPp;#I@u@=ai$Zqv#SU; zc*Gf;ew^WEB&<|lQG{$IPZOJ6+u8G8WUsb?iRXTSDZil2HxnS%|s6*rx_Uc4V zTzq9Mf7gGvTYxDv(9#X6R zC|XcW^{kxHq>)Z6QXOk>9a^C&^f!hEc^BOnaYM5x`e`v+MDYODV&wjx5AsYw2x{gZ zLMrh(&~R1>GFlUg34@kVSBk=F9cx&Vz=AgL^cN1r7&E%8$&bny_&R1^Aqvyhje% z%SPgn-{Q!wQ8B7WR)DNCvq_)f+K@Z6u_Cz%r&sYas!h>3KI!gPcWG)vjb)dL+Z%Ls%wiD#j(6oQQYM_8&95U#CMl&|aon%ue-itCg2TJ-}hnCF-$S{_2SVe7w@x=Bi&?o1B+NF=XIExP@VR_HdL6pB)VT%3*dsZOEo zhF&=+dGynkYjuqi*dp6mvdlEv1;A+otqGu=qheP6{>#)Td9V2*hY)NTuz6&Z!AyMp z(7_aBvZ-Kx#u=fGPYH8&Y!aA1w4d;JE?x@1w7KioBwJ-6HSk!bD7{pJ!MlhW2!+Rq z$Gd!`?TQwwXJ@>!S$gBJY|1s&s*ooPVXKa*K%H!1AR}2p5c(!8EuNrj^Ef1Gzx#6$ z<$50Udh8U0&f~abgxtAu%E!)OKoibtH$-08&zg;fQT0UqV!Pb37kSj)%XSbZ$mCCC zDLfwlgaPvxTf^i+5!_~~gH$eom*m;(Nv9GQ>8U$jLP!TxOh{)gy^Pn^g%Gg#bJ^+z z?tLgNgV0*|xJ`r0P3_2QwYsM?^l>ELjJnFx+$!OE?VuiSVUS-^OKG^KapU#y}H z`_!a3$e_W*)1Yxi~1ojR;C3<3T@@hXSTyc zoGBsWX|9Z0F9&Qul&bmzoHF|&4R2>>LN(dnoyk#Vrk38kzEpeL{^+k+n2%L2v1g<+ z@;qGuBV38yyzLq?Pb&72k#SgG$0sBWZqK3)vBtja&KE)etSpIHIDap&sB5aqym^w0 zR%%_@EY?b4Xz=omrKhX!%=dms~b!C`_X}(Rij;>tPsT?D#H#W=grX>dc_R~Za zUEpBdl-ks2zGeYi`t+GDKq7W-15=!K;ImhRE)4#*RF8X1F~w50G^dywvOqQ!`eDQ` zZj@xJdjKg4nI5=uy%Ik}@&h3VJ-+sNmD(U~sH6}lN2qR7xi;tK-mArrr7C=$O1`Z; z=lPBq*543GJ)^KD_wTD~KdC}6pDGyR&WxbrhZRQUAN>dBYs@qC6*(^t|6reF#bI$J zxCkJ-b8oJ;|I;4|XUg7b*#SgVzvYMgFMzggohsV)xMDK^=vapy-9OLPyP>NU?uHZd zfp47H?WzIxAaX8xWmW>0T4_HJ1)xf*eL-(2Jg7LR4WIY+u?tnlRAt4)70ki!MH^1g z%_{yOZK`B`>j;rW6kUZg?Q{VxPrcf;+r_EBSbu~xxsMt;;4nP& z-Jc+3hrSV8cpoI8&u?4^p>ivNMP0=XUOVm_kyWeR3ThmF!CXh3w)8UWJ~try2jfj8 z?8;m1cw-Ex8+r^v`<~%(rHz{{i*m_3qMj*3M~)1`+O$+*N4<27xi5B)EiDTJ`@RPT zYseY}93&wQ2hnFE2xe0&HguL`UK`7VU;ja=XVhqG)cM?V7Uws|l@%lc91F z5~$Cv%@1+5+3KE@dRA)(!bd7ErCUx+?tBSzfo&3+ zx_3MjQfCYdfm+;;J5mYRo zMn5QA?;uAuMv|nDIo`nI`dJb38AqTMBIw7{@3EZI4e?>dIQ*SGts%_ya5$HkoUVfA zCh)`9P&CPjAcq#*|87+{<+JP`FxM+n^X{MgoUp9 ze(~UO0~D3y{vw(hJPQtGEYh=`YbV;Hef-k(pQTZfg1_>Wuj`c25Ez7#d#nWtG5dLy z>p=7%`9!=!!?!c1xz$juL_OJ@AzC!BBa>WNbZAd<0pEsTo9&!!^TmCI zolyx>jU#`)7uKGF4BeMlhD=%%|2ATJVNhY`^H5#H#gyt~O!jH*ktc9@wtH)v+b@$T z%pe)waFEj?|YT% z==C|OheC9Ys4lz`Fwu1&%N{OamdtYj?5dTcs&tTe%$zjMg>z@XaA!XiY_g&Et^>X{_gYUw3Uvtpr zIeF8qP{hOj@>}@C`&@c8nCi`n(8s|P#Qh5X|FC70&aQS&IbE|lKff|yh_fR3Qe6Po z?P^;(9Wg739X#%WK~~SC*TfdcU?(A$l{D6N@;m~6O&^!j=>|` zKv>+lwLKk@NV6?Myf^o>ywxuYDTINs<~yH2huGozQSqN7DEG73^1ER8_?ZMQ!PT8{ z>?VYNy1}*NhB6UgwjfC1KwTI_+_VHtegTN)uTpQ?%sfR4inxW~xF;CahH1c{*-VLr zx8qa=yxN!$sYqWyOf4Cm3!wNE?hdR1#R%OAW>O%v%5V+T+&~5l2|CtxXZP|leQP3b z83>M!Q#?0shxNoP+E^7MOAXyJHX>;m)TWrQv>PP*pXh<~;KX5^PtHdHgeDk>Z zslf27gj`nW9HEst1{;Ako}qg;@Eo7JV5*3u%-k{k(|_!JMs9BJmtxmp=P1i6(!;HK zrH1=)#1DCDA~=fb8Ae_YoHs&!Fu*aVMbU8(WlEHA$*SXTOp9Ga%ngOqW2QzqQj|^5 zx$n>H`T_HT7~&WG*z}b=noM(Ne_1fL;y;w?ZGPX+to+fG_@zHXC8nPyj**ToeA2fz zAiW4S3j||Z#O^*y)ZiGwK=zfWzG?CcsW#QuT!{-Fn!=zNnH*~#_BAGyB6YMBMb6c4MJTWCcfJsak-nz+%zN6<~G3BHhFKR^nSxg>}N5r-H@RG&u;EZm3oA%F>v%2p)fnqF_J`+8}_CZagAStz&jWBxso60l!rYE@2}V_!n-yCv_I-g$N}H45FVe0%1a}RKL#q%KcfkY1=fRVU ze!pW?AM=svOmxT>bd0&MaF~Ey)OHfjyU2a_!Gh|PJ1K_hyc&|K;859jA6w4i(UBHfh+82yXQojDJ7R-<0C#Uu#P!tSi1cYBxmRo#Qp{sV zlZ4k^gW?%%Qu(Z5SZeI1xPzaHh?U5tJ`xXpKE&QgQd5--mjisctDv{k_A$>v_E6qa zyc!4$Q)lJJX2uCC$n&Cxbqkh12-1`ZUSoT%i39 zLRg2p-tsza^V9^y3zDg@1Dr(rOjS<=>|Tok{bh=DLXA2W;XrziN~iR$Ct(#6ZmOtb z>eX>>nM%}Bl3HMhbMhg^9s_Pwe(huBJl}>NGxlE^%nC^(wKCx_2*q0Ib}4lq36{vE zUj3tfqkRRQb?{--w}%<-Tjki`V6WY2*8ogz1=)adT1OBdP4rf>gBI16y%bm*E|4cu zv({WE43{!Xc}|Ft2#OBEsRSZ2mP}q64ynifmKR5iQ0SA$Asuc|c;X zsyphuP+4p|UxxSVv$YXJy-_n7g#xN7JU^=N0QQ`ZY-(f@H66rya=aj36t}ee&4`sM zhN;YinsETXq#!s%&)!XEtl_i+CxVU!)*ok!7Hvvf5Z9@eogZ9CFpei6WY~JA`469>Hn$_Rh&S9 zr{p*>59O`grzyMfk$nF+z>C+)Dz4jJ zI+69-z#x}=PP)kg=5h9=w{O63{HhiItc)R$@TNHo*uP*5}mf-M*f?Yo0#O=Wq4 z7kh4%$jlsXaqsp=LoQyy0KiJVtMJ32{)Q!su>4oLZF2RA6JnlZ8IoJi<9_GNNB|FtYbPaMsVD!@=UgBCvz1E;ydprTa^|>S2&asOW z1l!ETr)9a~67|q-T-Yutn^n7`0wooW;PpobO@^*Khwz!rhGYw)C;TZQZZSE-S0OVnZ#u@+Aq zHVmv%fHG1v845rhNlFcbXN8JO2#nuS*hFZiQ!qDR_D`eEDZy$~h}q527xHf=vb-&hJrMKlU2vC9R^uxGF0 z$DTBY-wg?RN$Qo17Y72P4}W(V`-mm^RHhj(SYLtF=oWeGVRc|G$dU=&?g84@Eo&NC zR?;FHi)xp4@IoDwhuV5Yo$nuMU(9Wd%6+<4ua{6TMw6O;!)b2P6em7u9whNxMr|J{ zS$1kLUmtX1XWFqQ*C}iRi`C-apRdpet3ZRdv{;hHJvJF59ZuPOY^%FEKiLtrw7Px1 z9y`m2o~Evrme?krT%2(pGdFkYy8FsR?TDj=K&83wQQQljA)oov)G-2Arwjm7Emx-U z>zftofMW%khi_c4A){_C#)#`S;u0Rj0BN5AtU literal 0 HcmV?d00001 diff --git a/plan/agw/notion/exports/20261003T075310278902Z/export-3.zip b/plan/agw/notion/exports/20261003T075310278902Z/export-3.zip new file mode 100644 index 0000000000000000000000000000000000000000..bc2a007dbbfa19f7ab2a10c47f5cc53664be696a GIT binary patch literal 1105 zcmWIWW@Zs#-~hs2JLgyiBoF{(2NY$NC6=Trs3`$a46r~myD>&un zXDjF`1UM_WW<08d_K+rY4%FnOGR4q$DMoB&M0A7^J2p85tU;n(5`HOr3f< z@3EOk+xJQ?rkhI|jTMj1zA<-QGm~zD!i<@&feu?Lrf?{Gx2gC)I@Eo$)4@zdAJl`HC5Vk-D+W3N6qA!vT@?%ju%>gWA<_HEmW zfE};-U+=576xqK0$@%m9AAG7~FtWSK{4(mmQRSce7U)}cOQZ*F)-nn83e8w?g)3xc zkQ!^UlGmdhJmyFF&HW$mklwd%f4N0TzAS6~xbwCBz1y0Xem|{>fA~|5d;b2v zC0!ZI{%xyXbGqryg65wh?e||t9&OvHa%0NQ!Ua2nMM_Q{)(LScmeNw)(Yb@`^U^im zU;q4k*cJS1*0-Bxygm1G%6W4Z%D#;#*9}^KaoP((al1M9&cAS*rE_(vQB(e$$y(2* zc?-Ksruu{haAvP$TQ+@>{?*UVjdxA**_U>I`UdA~<(}K-F>XD%(r>4kVbq!yE@Qz< z4pB$VIwxKVP;Oq3@-pba(yD(oTe&Rj&zdJ(T`>23Zm@Ot%$jdsAI6_H-rcigqmfo` z!KB20UUF1?=-bjN_2O`=A4>Y?-bDV6*xvAfKl*lm`X|wq8=^cG z#!3bV9F=L9))Xeu6xf!`;VIYM@!G-opu(Z<2U_M{+?#LwX|4MAMpq;4@1`Gn$Mdpx^3av#4L5&H&*v|U#k4hc=g%6a+UXOneQL5g}u4` zOZZE3?!8-r^WH9Wu#Nv;a#26gJ2y(jUHDn&cmf-lCOv6@sLu~}T>`;681OY`nO zIO>0*qPZeeNzWLS@Z(n>x5_j||2|w*}br5ywlboC(@~>#e!~LH{4jftiW}jr|SNA{hH)m%abLv00 z;2G!S2P}E*T#~XT*V1(_AJjTxXFp+fgGIH(vb)*cn}wgRGynMF`1kt(-s~K=YERqP uGczzeU6v21NEnkwePL5GJ)VbAUH18^~lvAglw@dx5TEU;qH?_wa%M literal 0 HcmV?d00001 diff --git a/plan/agw/notion/exports/20261003T075310278902Z/export-4.zip b/plan/agw/notion/exports/20261003T075310278902Z/export-4.zip new file mode 100644 index 0000000000000000000000000000000000000000..7a01de3bb22199fbe2d9fb6a5c4d75e69835d843 GIT binary patch literal 9356 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 literal 0 HcmV?d00001 diff --git a/plan/agw/notion/history/20261003T075310278902Z/1-agw-contract-changes.diff b/plan/agw/notion/history/20261003T075310278902Z/1-agw-contract-changes.diff new file mode 100644 index 00000000..bd387e6a --- /dev/null +++ b/plan/agw/notion/history/20261003T075310278902Z/1-agw-contract-changes.diff @@ -0,0 +1,82 @@ +--- notion/1-agw-contract-changes.md (previous) ++++ notion/1-agw-contract-changes.md (refreshed) +@@ -279,6 +279,79 @@ + + **Not in this change set** (belongs to 8183, listed so nobody looks for it here): the fund hook's key-match and expiry checks, the marketplace, the evaluator. + ++# 4c. What the SDK rule shape changes in the contracts (PROPOSED 2026-10-02) ++ ++Page 5 (SDK: AGW) settled the shape of a cross-chain rule in `client.agentic.create`. Three of those SDK changes touch the contracts. Nothing else on page 5 does. Names are the post-rename names from section 3; struct changes are to the universal terms URP decodes from the rules envelope. ++ ++**1. One rule can move several tokens: `assets: AssetCap[]` replaces `asset`, `maxAmountPerCall`, `maxAmountTotal`.** ++ ++The SDK takes each asset as the token's address on the rule's chain (`MOVEABLE.TOKEN..` or the native marker) and resolves it to the PRC20 on Push before encoding, so the contract keeps storing PRC20 addresses. The spend counter becomes per asset. ++ ++```diff ++// universal EVM terms (and SvmTerms, same change) ++- address asset; uint256 maxAmountPerCall; uint256 maxAmountTotal; +++ AssetCap[] assets; // 0..MAX_ASSETS; empty = call contracts, move nothing +++ struct AssetCap { address token; uint256 maxPerCall; uint256 maxTotal; } // token: PRC20 on Push; maxTotal 0 = no total cap +++ uint8 constant MAX_ASSETS = 8; ++ ++// metering ++~ amount gate: the token being moved must be one of assets[]; per-call and running total checked against that entry ++~ _spent[configId] becomes per token: mapping(address token => uint256 spent) ++~ assertSpent(configId, account) returns the per-token totals; the existing single-amount overload goes ++~ OutboundMetered carries the token ++``` ++ ++**2. `maxGasPerCall` replaces `maxPCPerCall`.** ++ ++Rename only. Same meaning: the PC (wei) the wallet may pass as `msg.value` on one outbound for the destination leg. The gate that checks it does not change. ++ ++```diff ++- uint256 maxPCPerCall; +++ uint256 maxGasPerCall; ++``` ++ ++**3. The struct, as it ends up.** ++ ++SDK side, what `create` takes per rule (page 5, 3.b). `agent` and `ref` go to `grantRules`, the rest is encoded into the rules envelope. ++ ++```tsx ++interface UniversalRule { ++ agent: Address; // Push address: EOA, or the UEA of an external key ++ ref?: Hex; // emitted in RulesGranted, not interpreted ++ chainNamespace: ForeignChainNamespace; ++ assets: AssetCap[]; // tokens the agent may move on chainNamespace; 0..8 ++ maxGasPerCall: bigint; // PC (wei) per outbound for the destination leg ++ validUntil: number; ++ allowedCalls: AllowedCall[]; ++} ++ ++interface AssetCap { ++ token: MoveableToken | Address; // the other chain's token address (MOVEABLE.TOKEN..) or the native marker ++ maxPerCall: bigint; ++ maxTotal?: bigint; ++} ++``` ++ ++Contract side, what URP decodes from the envelope body for an `eip155` namespace (`SvmTerms` takes the same `assets` and `maxGasPerCall` fields). ++ ++```solidity ++struct AssetCap { ++ address token; // PRC20 on Push, resolved by the SDK from the other chain's address ++ uint256 maxPerCall; ++ uint256 maxTotal; // 0 = no running cap ++} ++ ++struct UniversalTerms { ++ uint48 validUntil; ++ bytes32 expectedCEA; ++ AssetCap[] assets; // 0..MAX_ASSETS; empty = call contracts, move nothing ++ uint256 maxGasPerCall; // PC (wei) per outbound ++ AllowedCall[] allowedCalls; // unchanged ++} ++ ++uint8 constant MAX_ASSETS = 8; ++``` ++ + # 5. Open for review on this page + + 1. D3: removing the validator. Needs the v3 branch check on how SmartSession's engine is entered (signature path vs a sender-gated call into the same policy checks). If the engine cannot be entered without a signature, the fallback is a validator that accepts a trivial signature from the sender, which keeps the identity model and loses nothing but elegance. diff --git a/plan/agw/notion/history/20261003T075310278902Z/1-agw-contract-changes.md b/plan/agw/notion/history/20261003T075310278902Z/1-agw-contract-changes.md new file mode 100644 index 00000000..e27029e8 --- /dev/null +++ b/plan/agw/notion/history/20261003T075310278902Z/1-agw-contract-changes.md @@ -0,0 +1,289 @@ +# 1. AGW Contract Changes (nomenclature standard + change set) + + + +# 0. Before the naming: AGW will break when the gateway is upgraded + +**What happened.** The gateway team changed the outbound request struct on GitHub main. Two fields are gone (`gasPrice`, `maxPCForGas`). AGW copied the old struct into its own repo and URP checks one of the removed fields (gate 9: `maxPCForGas` must be non-zero). + +**Why it still works today.** Donut is still running the old gateway (implementation `0x1e41...a659` has the old eight fields). + +**What breaks.** The day the new gateway is deployed on Donut, every cross-chain rule set stops working: URP rejects every request. + +**Fix, two rules.** + +1. AGW never copies a gateway or core struct. It imports them from the gateway and core packages, so a change upstream fails the build instead of failing on-chain. +2. The URP upgrade and the gateway upgrade go out together, not separately. + +Same rule for the selector: derive `sendUniversalTxOutbound.selector` from the interface, do not hardcode `0x77b86bec`. + +# 1. How core and gateway name things (the standard AGW follows) + +These conventions already exist in `push-chain-core-contracts` and `push-chain-gateway-contracts`. AGW adopts them as is. Where the two repos disagree, the AGW column says which one wins. + +| Area | Convention | Example | AGW | +| --- | --- | --- | --- | +| Contract names | Chain-agnostic components spell out Universal. Push-side variants add PC. Accounts are 3-letter acronyms. | `UniversalCore`, `UniversalGatewayPC`, `UEA`, `CEAFactory` | `AGW`, `AGWFactory`, `UniversalRulesPolicy` | +| Errors | One `libraries/Errors.sol` per repo, one error library per contract, PascalCase, arguments only when the caller needs them. Caller checks are `CallerIsNotX`. | `UEAErrors.InvalidCall()`, `CommonErrors.ZeroAddress()`, `CallerIsNotUEModule()` | `AGWErrors`, `AGWFactoryErrors`, `UniversalRulesPolicyErrors` | +| Types and constants | One `libraries/Types.sol`, plain file-level structs, `UPPER_SNAKE` constants, selectors derived not hardcoded. | `struct Multicall`, `MULTICALL_SELECTOR = bytes4(keccak256("UEA_MULTICALL"))` | `libraries/Types.sol`; gateway and core structs imported, never copied | +| Request shape | One `XRequest` struct as the single argument; the contract infers the kind. Users never state a type. | `sendUniversalTxOutbound(UniversalOutboundTxRequest req)` infers `TX_TYPE` | `grantRules(Session)` infers `NATIVE` vs `UNIVERSAL` from `chainNamespace` | +| Interface sections | Tag plus number banners, events first, NatSpec on everything. | `UGPC_1: EVENTS`, `UGPC_2: OUTBOUND TX`, `UGPC_3: VIEW FUNCTIONS` | `AGW_1: EVENTS` ... `AGW_5: VIEWS`, `URP_1` ... `URP_3` | +| Functions | `setX`, `getX`, `isX`. Set-once wiring is read through `UPPER_CASE()` getters. | `isSupportedToken()`, `UNIVERSAL_CORE()` | `SESSION_ENGINE()`, `RULES_POLICY()`, `UNIVERSAL_GATEWAY_PC()` | +| Storage | Internal state is underscore-prefixed. | `_walletCount` | `_` everywhere; drop URP's `$` prefix | +| Roles | `UPPER_SNAKE_ROLE`. | `DEFAULT_ADMIN_ROLE`, `PAUSER_ROLE`, `TSS_ROLE` | same; `PAUSER` and `OPERATOR` split kept, documented | +| Chain identity | Full CAIP-2 string, field named `chainNamespace`. | `"eip155:1"` | envelope field renamed `chain` to `chainNamespace` | +| Events | No consistent rule upstream. | `SetChainMeta` (imperative), `VaultPCUpdated` (past) | past tense: `RulesGranted`, `WalletDeployed` | +| Layout | `src/` with `interfaces/` and `libraries/`; numbered docs and tests; addresses per network; `CLAUDE.md` in every package. | `docs/1_PUSH_CHAIN.md`, `test/gateway/1_adminActions.t.sol`, `docs/addresses/sepolia.md` | same, see rename map | + +#### Where each convention was seen (open only if you want the receipts) + +Core repo, folder layout: + +``` +src/ + Interfaces/ IUniversalCore.sol, IUEA.sol, ICEA.sol + libraries/ Errors.sol, Types.sol, Utils.sol + uea/ UEAFactory.sol, UEA_EVM.sol, UEA_SVM.sol + cea/ CEAFactory.sol, CEA.sol + UniversalCore.sol, PRC20.sol, WPC.sol +``` + +Gateway repo, folder layout: + +``` +contracts/evm-gateway/ + src/ UniversalGateway.sol, UniversalGatewayPC.sol, Vault.sol, VaultPC.sol + src/interfaces/ IUniversalGatewayPC.sol, IVault.sol + src/libraries/ Errors.sol, Types.sol, TypesUG.sol, TypesUGPC.sol + docs/ 1_PUSH_CHAIN.md, 2_UniversalGateway.md, 3_UniversalGatewayPC.md + docs/addresses/ sepolia.md, bsc-testnet.md + test/gateway/ 1_adminActions.t.sol ... 14_gatewayPC.t.sol + script/ 1_DeployGatewayWithProxy.sol, 3_UpgradeGatewayNewImpl.sol + CLAUDE.md +``` + +Errors (core, `libraries/Errors.sol`): + +```solidity +library CommonErrors { error ZeroAddress(); error Unauthorized(); error InvalidInput(); } +library UniversalCoreErrors { error CallerIsNotUEModule(); error GasLimitBelowBase(uint256 provided, uint256 minimum); } +library UEAErrors { error InvalidCall(); error ExecutionFailed(); } +``` + +Types (core, `libraries/Types.sol`): + +```solidity +struct UniversalAccountId { string chainNamespace; string chainId; bytes owner; } +struct Multicall { address to; uint256 value; bytes data; } +bytes4 constant MULTICALL_SELECTOR = bytes4(keccak256("UEA_MULTICALL")); +``` + +Request shape (gateway, `TypesUGPC.sol` and `IUniversalGatewayPC.sol`): + +```solidity +struct UniversalOutboundTxRequest { bytes recipient; address token; uint256 amount; uint256 gasLimit; bytes payload; address revertRecipient; } +function sendUniversalTxOutbound(UniversalOutboundTxRequest calldata req) external payable; // TX_TYPE inferred inside +``` + +Interface sections and wiring getters (gateway, `IUniversalGatewayPC.sol`): + +```solidity +// UGPC_1: EVENTS +// UGPC_2: OUTBOUND TX +// UGPC_3: VIEW FUNCTIONS +function UNIVERSAL_CORE() external view returns (address); +``` + +Events (both repos, no single rule): + +```solidity +event SetChainMeta(...); // core, imperative +event PauserRoleGranted(...); // core, past tense +event UniversalTxOutbound(...); // gateway, noun +event VaultPCUpdated(...); // gateway, past tense +``` + +Chain identity, the same field name with two meanings: + +```solidity +gasPriceByChainNamespace("eip155:1") // UniversalCore: full CAIP-2 string +UniversalAccountId({ chainNamespace: "eip155", chainId: "1" }) // Read State: split +``` + +# 2. Decisions + +| # | Decision | Outcome | +| --- | --- | --- | +| D1 | Wallet contract name | **AGW.sol** (account acronym like UEA, CEA). Full form "Agentic Wallet" in the NatSpec title only. Factory stays `AGWFactory.sol`. | +| D2 | Policy contract name | **UniversalRulesPolicy.sol**. `URP` stays as the short form in comments, events and the SDK constant, the way `UGPC` stands for `UniversalGatewayPC`. | +| D3 | Validator contract name | PROPOSED 2026-09-29: **no validator.** The agent is a Push address: a native key is its own EOA, any external key (EVM, Solana, anything) is its UEA, deterministic from (chain, owner). Cross-VM signature verification already happens inside the UEA, so the agent door checks `msg.sender == rules.agent` and hands the calls to URP. `PushSessionValidator.sol` is removed rather than renamed. Pending one check against the v3 branch: how deep SmartSession's signature path is wired into the engine calls URP relies on, and whether the policy engine can be driven from a sender check without forking it. | +| D4 | Vocabulary for the granted object | **rules, one word everywhere.** On-chain: `grantRules`, `revokeRules`, `revokeAllRules`, `rulesId`, `RulesGranted`, `RulesRevoked`, `RulesActionAuthorized`. Layer: Universal Rules. SDK: `client.agentic.rules`. `permissionId` remains the SmartSession-internal name and is exposed as `rulesId`. `mandate` is retired from code, docs and copy. +**Rename boundary (2026-09-29).** Three vocabularies live in the fork; only ours is renamed. ERC-7579 names stay (`execute(mode, executionCalldata)`, `ModeCode`, module types, `installModule`). SmartSession names stay inside the engine and on the interfaces URP implements (`Session`, `permissionId`, `PolicyData`, `ActionData`, `ConfigId`, `enableSessions`, `isPermissionEnabled`, `IPolicy.checkAction`, `initializeWithMultiplexer`): audit history and upstream diffs attach to those names. Push's own words (`mandate`, `PushAgentWallet`, our events, envelope, docs, SDK) become rules. The seam is the AGW ABI: `rulesId` is computed by the engine's `getPermissionId(Session)` and the NatSpec states `rulesId == permissionId`. If the engine is vendored with edits, it lives in `src/vendor/smartsession/` with a note naming the upstream commit and every local change. If D3 ends with the engine dropped, SmartSession vocabulary leaves with it. | +| D5 | Door functions | Keep `execute` (owner door). Agent door becomes `executeAsAgent(bytes32 rulesId, bytes32 mode, bytes executionCalldata)`, gated on `msg.sender == rules.agent`, replacing `executeWithSession` and its signature blob (follows D3). "Owner door" and "agent door" stay as NatSpec language. | +| D6 | Chain field in the envelope | Rename `chain` to `chainNamespace`, full CAIP-2 string, matching `UniversalCore` and gateway events. Read State keeps its split fields; the SDK converts. | +| D7 | Mode names | `NATIVE` and `UNIVERSAL` stay. The SVM rulebook is selected by the `solana` namespace inside `UNIVERSAL`; no new mode name. | + +# 3. Rename map (current to proposed) + +| Area | Today | Proposed | +| --- | --- | --- | +| Inherited names (7579, SmartSession) | `execute(mode, executionCalldata)`, `Session`, `permissionId`, `PolicyData`, `ActionData`, `ConfigId`, `checkAction`, `initializeWithMultiplexer` | unchanged (see D4 rename boundary) | +| Wallet | `PushAgentWallet.sol` | `AGW.sol` | +| Factory | `AGWFactory.sol` | `AGWFactory.sol` (unchanged) | +| Policy | `policies/URP.sol` | `UniversalRulesPolicy.sol` | +| Validator | `validators/PushSessionValidator.sol` | removed (D3): agent identity is a Push address, verification lives in the UEA | +| Interfaces | `IPushAgentWallet`, `IURP`, `IPushSessionValidator`, local `IUniversalGatewayPC`, `IPRC20Source` | `IAGW`, `IUniversalRulesPolicy`; gateway and core interfaces imported (`IUEAFactory` for `computeUEA` in tests and tooling) | +| Errors | `libraries/PushWalletErrors.sol` plus errors declared in `IURP` and `IAGWFactory` | `libraries/Errors.sol` with `AGWErrors`, `AGWFactoryErrors`, `UniversalRulesPolicyErrors`; reuse `CommonErrors` names (`ZeroAddress`, `Unauthorized`, `AlreadyInitialized`); `AGWErrors.CallerIsNotAgent()` | +| Types | `libraries/PushWalletTypes.sol` re-declares `UniversalOutboundTxRequest`, `Multicall` | `libraries/Types.sol` with AGW-owned structs only (`RulesEnvelope`, `NativeTerms`, `UniversalTerms`, `AllowedCall`, `ArgPin`, `AmountRule`); gateway and core types imported | +| Grant / revoke | `grantMandate`, `stopMandate`, `stopAll` | `grantRules`, `revokeRules`, `revokeAllRules` | +| Events | `MandateGranted`, `MandateRevoked`, `MandateActionAuthorized`, `URPPolicySet` | `RulesGranted`, `RulesRevoked`, `RulesActionAuthorized`, `RulesConfigured` | +| Ids | `permissionId` in wallet ABI | `rulesId` in wallet ABI (engine keeps `permissionId` internally) | +| Wiring getters | `sessionEngine()`, `urp()`, `sessionValidator()`, `universalGateway()` | `SESSION_ENGINE()`, `RULES_POLICY()`, `UNIVERSAL_GATEWAY_PC()` (no validator getter, D3) | +| Storage prefix | `_` in wallet and factory, `$` in URP | `_` everywhere | +| Envelope | `abi.encode(string chain, bytes body)` | `abi.encode(uint16 version, string chainNamespace, bytes body)` | +| Interface banners | none | `AGW_1: EVENTS`, `AGW_2: OWNER DOOR`, `AGW_3: AGENT DOOR`, `AGW_4: RULES LIFECYCLE`, `AGW_5: VIEWS`; `URP_1: EVENTS`, `URP_2: POLICY`, `URP_3: VIEWS`; `AGWF_1: EVENTS`, `AGWF_2: DEPLOY`, `AGWF_3: VIEWS` | +| Selector constant | `SEND_OUTBOUND_SELECTOR = 0x77b86bec` | derived from `IUniversalGatewayPC` | +| Roles | `PAUSER_ROLE` pauses, `OPERATOR_ROLE` unpauses | keep the split, document it as a deliberate deviation from gateway | +| Event tense | past tense | past tense, written down as the rule | +| Docs | `docs/v3-architecture.md`, `agentic_wallet_flow.md`, `push_native_agentic_wallet_flow.md` | `docs/1_AGW.md`, `2_UniversalRulesPolicy.md`, `3_Universal_Flow.md`, `4_Native_Flow.md` | +| Addresses | `deployments/address-book-v3/ADDRESSES.md` | `docs/addresses/donut.md` | +| Tests | `test/unit/*.t.sol`, `test/integration/*.t.sol` | numbered by area: `1_factory`, `2_ownerDoor`, `3_rulesLifecycle`, `4_agentDoor`, `5_universalRulebook`, `6_nativeRulebook`, `7_externalAgentViaUEA`, `8_e2e` | + +# 4. Structural changes that ride along with the rename + +Agreed on 2026-09-28. Listed here so the rename and the additions land in one change set and one audit, before the permanent deployment. + +1. **Signature-authorized variants**: `deployWalletWithSig`, `grantRulesWithSig`, `executeWithSig`. One EIP-712 domain per contract. Digest includes chainid, contract, nonce (the wallet's grant nonce for grants; a per-owner nonce on the factory), deadline. Verify ECDSA, and ERC-1271 when the owner has code (a UEA). +2. **Checkpoints**: the wallet records owner-side changes an evaluator needs: principal moved out (owner-door value or token transfer out, and every outbound), rules granted, revoked or replaced, key changed. Per-wallet monotonic counter plus `Checkpointed(kind, ref, blockNumber)`, so an evaluator can ask "any checkpoint after block N" with one read. +3. **`bytes32 ref` on `grantRules`**, emitted in `RulesGranted`, so a job binds to a rules id and an indexer goes rules to job without the hook. +4. **Stop-only role: dropped for v1** (2026-10-01). A binder address that could call `revokeRules` and nothing else was considered so a job hook could end rules at job end. Not needed: rules expire by `validUntil`, which the fund hook requires to be at or after the job's `expiredAt`, caps bound the gap, and the hook keeps its own one-live-job slot. Additive to bring back later. +5. **Envelope version word**: `abi.encode(uint16 version, string chainNamespace, bytes body)`. +6. **`creditRevert` reachability**: wire the real executor module or replace the credit path. Today spend never decreases on Donut. +7. **SVM rulebook** in the policy, keyed by the `solana` namespace: 32-byte `expectedCEA` and targets, program plus instruction discriminator allow-list, beneficiary check over the accounts array, SVM payload gate. +8. **Import gateway and core types**, derive the outbound selector, sequence the URP upgrade with the gateway's struct change. +9. **Agent identity is a Push address** (2026-09-29). The rules name an address: an EOA, or the UEA of an external key. The agent door checks the sender instead of verifying a session signature; the validator contract goes. One identity for rules, card and 8183 provider, so the fund hook matches by equality. Sizing against the v3 branch pending (D3). +10. **Editable label** (2026-10-01). `setLabel(string label)` on AGW, owner only, emits `LabelSet(string label)`. Today the label is only passed at `deployWallet` and emitted in `WalletDeployed`. Not a checkpoint kind: cosmetic metadata, evaluators ignore it. SDK: `w.setLabel(label)` on page 5. + +# 4b. Contract surface, as a diff + +Read `+` as added, `-` as removed, `~` as changed in place, `=` as unchanged. Names are the post-rename names. Storage slots never move; renames are labels only. + +**AGWFactory** + +```diff += deployWallet(string label) returns (address wallet) // caller is the owner ++ deployWalletWithSig(address owner, uint96 index, string label, ++ uint48 deadline, bytes ownerSig) returns (address) // EIP-712; index must equal walletCount(owner) ++ // ownerSig: ECDSA, or ERC-1271 when owner has code (UEA) ++ DOMAIN_SEPARATOR() view returns (bytes32) += predictWallet(address owner, uint256 index) view returns (address, bool deployed) += walletCount / ownerOf / isWallet / indexOf / walletImplementation += pause() PAUSER_ROLE, unpause() OPERATOR_ROLE += event WalletDeployed(owner, index, wallet, label) +``` + +**AGW** (was PushAgentWallet) + +```diff +// owner door += execute(bytes32 mode, bytes executionCalldata) payable // owner only, no policy +~ execute now emits Checkpointed(seq, OWNER_ACTION, keccak(calldata), block) ++ executeWithSig(bytes32 mode, bytes executionCalldata, ++ uint64 ownerNonce, uint48 deadline, bytes ownerSig) // owner door by signature, same effects as execute ++ ownerNonce() view returns (uint64) ++ setLabel(string label) // owner only; emits LabelSet; not a checkpoint + +// rules lifecycle +- grantMandate(Session) returns (bytes32 permissionId) ++ grantRules(Session session, bytes32 ref) returns (bytes32 rulesId) // ref: job or card reference, emitted, not interpreted ++ grantRulesWithSig(Session session, bytes32 ref, uint48 deadline, bytes ownerSig) returns (bytes32 rulesId) ++ // digest includes grantNonce, so a signed grant cannot replay +- stopMandate(bytes32 permissionId) ++ revokeRules(bytes32 rulesId) // owner or self +- stopAll() ++ revokeAllRules() // owner or self + +// agent door (D3, D5) +- executeWithSession(address validator, bytes32 mode, bytes executionCalldata, +- bytes signature, uint192 nonceKey, uint64 nonceSeq, uint48 requestExpiry) ++ executeAsAgent(bytes32 rulesId, bytes32 mode, bytes executionCalldata) ++ requires msg.sender == agentOf(rulesId); replay and expiry come from the sender's own tx (EOA nonce, or the UEA's) ++ URP checks every call exactly as before; no signature blob, no validator address ++ agentOf(bytes32 rulesId) view returns (address) + +// checkpoints ++ checkpointCount() view returns (uint64) ++ lastCheckpointBlock() view returns (uint64) ++ event Checkpointed(uint64 indexed seq, uint8 kind, bytes32 ref, uint64 blockNumber) ++ kind: 0 OWNER_ACTION (any owner-door execute), 1 RULES_GRANTED, 2 RULES_REVOKED ++ emitted from execute, executeWithSig, grantRules*, revokeRules, revokeAllRules + +// views (wiring, renamed to UPPER_CASE) +- sessionEngine() urp() sessionValidator() universalGateway() ++ SESSION_ENGINE() RULES_POLICY() UNIVERSAL_GATEWAY_PC() += owner() factory() grantNonce() getNonce(uint192) accountId() ++ DOMAIN_SEPARATOR() view returns (bytes32) + +// events +- MandateGranted(permissionId, mandateType, chainHash, chain) ++ RulesGranted(bytes32 indexed rulesId, uint8 mode, bytes32 indexed chainHash, string chainNamespace, bytes32 ref) +- MandateRevoked(permissionId) ++ RulesRevoked(bytes32 indexed rulesId, address by) +- MandateActionAuthorized(permissionId, nonceKey, nonceSeq, opHash) ++ RulesActionAuthorized(bytes32 indexed rulesId, address indexed agent, bytes32 callsHash) ++ event LabelSet(string label) +``` + +**UniversalRulesPolicy** (was URP) + +```diff +~ initializeWithMultiplexer(address account, ConfigId id, bytes initData) +~ initData = abi.encode(uint16 version, string chainNamespace, bytes body) // was (string chain, bytes body) +~ rulebook chosen by namespace: this chain => native; eip155:* => universal EVM; solana:* => universal SVM ++ SVM rulebook ++ struct SvmTerms { uint48 validUntil; bytes32 expectedCEA; address asset; uint256 maxAmountPerCall; ++ uint256 maxAmountTotal; uint256 maxPCPerCall; SvmAllowedCall[] allowedCalls; } ++ struct SvmAllowedCall { bytes32 program; bytes8 discriminator; uint8 beneficiaryAccountIndex; bool hasBeneficiary; uint64 maxLamports; } ++ gates mirror the EVM list; beneficiary checked in the accounts array, payload gate for the SVM outbound format +~ checkAction: UniversalOutboundTxRequest imported from the gateway package +~ gate 4c MIN_OUTBOUND_BODY_LEN recomputed from the imported struct +~ gate 9 (maxPCForGas != 0) removed when the six-field gateway struct lands; deploy in the same window +~ creditRevert(id, account, outboundTxId, amount): caller is the real executor module, set at initialize += or removed if the credit path is replaced (decision pending) += assertSpent (both overloads), getConfig, getNativeConfig, getMode, pushChainHash, isCredited ++ getSvmConfig(ConfigId, address) view +- event URPPolicySet(...) ++ event RulesConfigured(bytes32 indexed configId, address indexed multiplexer, address indexed account, uint8 mode, bytes32 chainHash) += OutboundMetered, NativeCallMetered, RevertCredited +~ storage variables renamed $configs, $credited, $mode, $native to _configs, _credited, _mode, _native (labels only, slots unchanged) ++ _svm mapping appended after _native; __gap shrinks by one +~ version() returns "2.0.0" +``` + +**PushSessionValidator** + +```diff +- validateConfig(bytes keyConfig) +- validateSignatureWithData(bytes32 hash, bytes sig, bytes keyConfig) +- contract removed (D3). Session.sessionValidator and keyConfig are replaced by a single address in the rules: the agent. +``` + +**Not in this change set** (belongs to 8183, listed so nobody looks for it here): the fund hook's key-match and expiry checks, the marketplace, the evaluator. + +# 5. Open for review on this page + +1. D3: removing the validator. Needs the v3 branch check on how SmartSession's engine is entered (signature path vs a sender-gated call into the same policy checks). If the engine cannot be entered without a signature, the fallback is a validator that accepts a trivial signature from the sender, which keeps the identity model and loses nothing but elegance. +2. Checkpoint kinds, since they are the evaluator's contract with the wallet. +3. `creditRevert`: wire the executor module, or replace the credit path. +4. Anything in the rename map or the diff that should stay as is. + +The SDK surface lives on page 5 (SDK: AGW). \ No newline at end of file diff --git a/plan/agw/notion/history/20261003T075310278902Z/5-sdk-agw.diff b/plan/agw/notion/history/20261003T075310278902Z/5-sdk-agw.diff new file mode 100644 index 00000000..47ab2a2e --- /dev/null +++ b/plan/agw/notion/history/20261003T075310278902Z/5-sdk-agw.diff @@ -0,0 +1,106 @@ +--- notion/5-sdk-agw.md (previous) ++++ notion/5-sdk-agw.md (refreshed) +@@ -89,40 +89,39 @@ + + ### 1.b Create an agentic wallet - `client.agentic.create` + +-Deploys the wallet, moves funds into it and grants the rules. The label is the only wallet-level input; the agent and an optional `ref` are named on each rule, because that is where the contract binds them. ++Deploys the wallet and grants the rules. The label is the only wallet-level input; the agent and an optional `ref` are named on each rule, because that is where the contract binds them. + + ```tsx + // Function + const created = await client.agentic.create(label, { options }) + + // Usage and Params +-const created = await client.agentic.create('aave-optimiser', { // wallet with one cross-chain rule, funded ++const created = await client.agentic.create('aave-optimiser', { // wallet with one cross-chain rule + rules: [{ // one entry per chain per agent + agent: '0xAgentOnPush', // a Push address: the agent's EOA, or its UEA if the key lives on another chain. Never the owner + ref: jobRef, // emitted in RulesGranted, not interpreted + chainNamespace: CHAIN.ETHEREUM_SEPOLIA, // foreign chain => universal rulebook +- asset: usdcOnPush, +- maxAmountPerCall: parseUnits('100', 6), +- maxAmountTotal: parseUnits('100', 6), +- maxPCPerCall: parseUnits('0.5', 18), ++ assets: [ ++ { token: MOVEABLE.TOKEN.ETHEREUM_SEPOLIA.USDC, maxPerCall: parseUnits('100', 6), maxTotal: parseUnits('1000', 6) }, ++ { token: MOVEABLE.TOKEN.ETHEREUM_SEPOLIA.WETH, maxPerCall: parseUnits('0.5', 18) }, ++ ], ++ maxGasPerCall: parseUnits('1', 18), // PC (wei) per outbound for the destination leg + validUntil: now + 30 * 86400, + allowedCalls: [ +- { target: aavePool, selector: 'supply(address,uint256,address,uint16)', beneficiary: 2 }, // arg index, not offset ++ { target: aavePool, selector: 'supply(address,uint256,address,uint16)', beneficiary: 2 }, // arg index, not offset: onBehalfOf must be the AGW's CEA + { target: usdcSepolia, selector: 'approve(address,uint256)' }, + ], + }], +- funds: [{ amount: parseUnits('100', 6), token: MOVEABLE.TOKEN.ETHEREUM_SEPOLIA.USDC }], +- pc: parseUnits('5', 18), // native PC for outbound fees + progressHook: (p) => console.log(p.id, p.message), // AGENTIC-TX-1xx + }); + const bare = await client.agentic.create('scratch', { rules: [] }); // wallet first, rules later with rules.add + // label string, required shown in list() and info(); the contract stores it + // options.rules Rule[], required one per chain per agent, may be empty; each rule carries its own agent and optional ref +-// options.funds Array<{ amount, token }>, optional same shape as tx.funds, always an array; default none +-// options.pc bigint, optional native PC for outbound fees; default none + // options.progressHook function, optional progress events, AGENTIC-TX-1xx; default none + // rules[].agent Address, required the Push address allowed to act under this rule; never the owner + // rules[].ref Hex, optional emitted in RulesGranted, not interpreted; default zero ++// rules[].assets AssetCap[], required on a universal rule tokens the agent may move, as the other chain's address (MOVEABLE constants); the SDK resolves each to its PRC20 on Push; each cap is { token, maxPerCall, maxTotal? } ++// rules[].maxGasPerCall bigint, required on a universal rule PC (wei) the wallet may spend per outbound for the destination leg + + // Returns + // { wallet, index, rulesIds, tx } +@@ -142,11 +141,11 @@ + + One rule per chain per agent. A wallet may have different agents on different chains. If an agent needs to act on two chains, `rules` has two entries with the same `agent`; two agents on one chain are two entries with the same `chainNamespace`. Nobody states a rule type; the SDK reads it from `chainNamespace`. `rules: []` is allowed: create the wallet first and grant rules later with `rules.add` (1.k). + +-Before asking for a signature the SDK checks that no rule's agent is the owner (`AGENT_IS_OWNER`), that no two rules share both agent and chain (`DUPLICATE_RULE`), that every `allowedCalls[].target` is on the rule's chain (`TARGET_NOT_ON_RULE_CHAIN`), and that the asset is a PRC20 whose `SOURCE_CHAIN_NAMESPACE` matches the rule's chain (`ASSET_CHAIN_MISMATCH`). +- +-Under the hood this is `deployWallet` (or reuse of a derived address), the funds moved in, and one `grantRules` per rule. For an external owner they go as one UEA multicall under one signature. `funds` stays an array; an external owner moving several tokens may need one signature per token, and the SDK sequences them and reports each through progress events. +- +-For a Push EOA owner the same thing needs a batching entry on the factory, because core rejects multicall from a Push-native sender: [1. AGW Contract Changes (nomenclature standard + change set)](1-agw-contract-changes.md) item 11, **PROPOSED** (`createWallet(label, rules[], funds)` on the factory). Until it lands the SDK sends deploy, fund and grant as separate transactions and says so through progress events (AGENTIC-TX-102 to 104); `tx` is then the last of them. ++Before asking for a signature the SDK checks that no rule's agent is the owner (`AGENT_IS_OWNER`), that no two rules share both agent and chain (`DUPLICATE_RULE`), that every `allowedCalls[].target` is on the rule's chain (`TARGET_NOT_ON_RULE_CHAIN`), and that every `assets[].token` resolves to a PRC20 whose `SOURCE_CHAIN_NAMESPACE` matches the rule's chain (`ASSET_CHAIN_MISMATCH`). ++ ++Under the hood this is `deployWallet` (or reuse of a derived address) and one `grantRules` per rule. For an external owner they go as one UEA multicall under one signature. Funding is not part of `create`: the wallet is a normal Push account, so send tokens and PC to its address the way you would to any account (1.a shows the address before deployment). ++ ++For a Push EOA owner the same thing needs a batching entry on the factory, because core rejects multicall from a Push-native sender: [1. AGW Contract Changes (nomenclature standard + change set)](1-agw-contract-changes.md) item 11, **PROPOSED** (`createWallet(label, rules[])` on the factory). Until it lands the SDK sends deploy and grant as separate transactions and says so through progress events (AGENTIC-TX-102 and 104); `tx` is then the last of them. + + A `progressHook` passed to `PushChain.initialize` receives the same events alongside the per-call one, as in core. + +@@ -562,8 +561,6 @@ + + interface CreateOptions { + rules: Rule[]; // one entry per chain per agent, may be empty; each rule names its agent and optional ref +- funds?: { amount: bigint; token: MoveableToken | Address }[]; // same shape as tx.funds, always an array +- pc?: bigint; // native PC for outbound fees + progressHook?: ProgressHook; // AGENTIC-TX-1xx + } + +@@ -596,10 +593,16 @@ + agent: Address; // same as NativeRule.agent + ref?: Hex; // same as NativeRule.ref + chainNamespace: ForeignChainNamespace; // "eip155:..." now; "solana:..." once the SVM rulebook ships +- asset: Address; // PRC20 on Push; SDK asserts its SOURCE_CHAIN_NAMESPACE ++ assets: AssetCap[]; // tokens the agent may move on chainNamespace; SDK resolves each to its PRC20 and asserts SOURCE_CHAIN_NAMESPACE ++ maxGasPerCall: bigint; // PC (wei) per outbound for the destination leg + validUntil: number; +- maxAmountPerCall: bigint; maxAmountTotal?: bigint; maxPCPerCall: bigint; + allowedCalls: AllowedCall[]; // 1..32, all on chainNamespace ++} ++ ++interface AssetCap { ++ token: MoveableToken | Address; // the other chain's token address (MOVEABLE.TOKEN..) or the native marker; the contract stores the PRC20 ++ maxPerCall: bigint; ++ maxTotal?: bigint; + } + + type Selector = Hex | `${string}(${string})`; // '0x617ba037' or 'supply(address,uint256,address,uint16)' +@@ -688,7 +691,6 @@ + // progress events, AGENTIC-TX (PROPOSED) + // AGENTIC-TX-101 wallet derived { address, index, deployed } + // AGENTIC-TX-102 deploy step added +-// AGENTIC-TX-103 funds and PC step added + // AGENTIC-TX-104 rules granted { rulesIds } + // AGENTIC-TX-105 rules revoked { rulesIds | all } + // AGENTIC-TX-106 label set diff --git a/plan/agw/notion/history/20261003T075310278902Z/5-sdk-agw.md b/plan/agw/notion/history/20261003T075310278902Z/5-sdk-agw.md new file mode 100644 index 00000000..2de6c4de --- /dev/null +++ b/plan/agw/notion/history/20261003T075310278902Z/5-sdk-agw.md @@ -0,0 +1,730 @@ +# 5. SDK: AGW + + + +# List of changes + +New + +- `client.agentic.derive` +- `client.agentic.create` +- `client.agentic.list` +- `client.agentic.wallet`, + - a management handle with + - `info`, + - `owner`, + - `setLabel` (PROPOSED), + - `checkpoints`, + - `rules.list`, + - `rules.get`, + - `rules.add`, + - `rules.update`, + - `rules.revoke` +- `PushChain.CONSTANTS.AGENTIC` +- `PushChain.utils.agentic` + +Updated + +- `PushChain.initialize`, new option `agenticWallet` +- `PushChain.CONSTANTS.READ.CHAIN`, outside change confirmed 2026-09-28 + +Initialize is unchanged on the owner side: + +```tsx +const client = await PushChain.initialize(universalSigner, { network: PushChain.CONSTANTS.PUSH_NETWORK.TESTNET }); +``` + +| Signer | Door | Rules checked | +| --- | --- | --- | +| The wallet's owner | Owner door (`execute`) | No. Every send is recorded as a checkpoint | +| An address named as `agent` in one of the wallet's rules | Agent door (`executeAsAgent`) | Yes, by URP (UniversalRulesPolicy, the on-chain rule checker) | +| Anyone else | None | Never reached: `initialize` throws `NOT_OWNER_OR_AGENT` | + +An agentic wallet involves three parties, and it helps to have them straight before reading the functions. + +The **owner** is whoever created the wallet. When the owner sends through the wallet, no rules are checked; this is called the owner door, and the contract records every such action as a checkpoint so that an evaluator can later tell whether the owner touched anything mid-job. + +The **agent** is the address the owner allows to act on its behalf. It is always a Push address. If the agent's key is a Push EOA, that EOA is the agent. If the key lives on another chain (an EVM key on Ethereum, a Solana key, anything else), the agent is that key's UEA on Push, which exists deterministically for every external key. The SDK never asks for a curve, a chain or a key type. When the agent sends through the wallet, the rules are checked; this is the agent door. + +The **rules** say what an agent may do. Each rule names its agent and its destination chain, and there is one rule per chain per agent, so a wallet can have one agent for Ethereum and a different one for Solana. The `chainNamespace` on a rule decides which rulebook applies: leave it out and the rule governs calls on Push itself; set it to an `eip155` or `solana` chain and the rule governs cross-chain calls to that chain. + +Two ways to touch a wallet from the SDK. `PushChain.initialize(signer, { agenticWallet })` returns a client that acts as the wallet, and whether it goes through the owner door or the agent door depends on who the signer is. `client.agentic.wallet(address)` returns a handle for managing the wallet (rules, label, checkpoints) and never sends as it. + +# 1. Owner side, by example + +The owner side is everything the person who owns the wallet does: create it, fund it, write and revoke the rules, look at what happened. The agent side (section 2) is what the agent does: act through the wallet within those rules. + +### 1.a Derive an agentic wallet address - `client.agentic.derive` + +Gives you the address a wallet will have before it is deployed. The address depends only on the owner and an index. + +```tsx +// Function +const first = await client.agentic.derive({ options? }) + +// Usage and Params +const next = await client.agentic.derive(); // the owner's next wallet +const first = await client.agentic.derive({ index: 0 }); // a specific slot +// options.index number, optional which wallet slot to derive; default is the owner's next unused index + +// Returns +// { address, index, deployed } +{ + address: '0x2Fd904d6f2C0b34d58426C8Ae9c5267E845CE98f', + index: 0, + deployed: false +} +``` + +Because the address depends only on the owner and an index, it is the same whether you deploy first or later. That lets you send funds to it first (from any chain) and deploy afterwards, or show the address in a UI before anything is on-chain. Same idea as `deriveExecutorAccount` for a UEA. + +### 1.b Create an agentic wallet - `client.agentic.create` + +Deploys the wallet, moves funds into it and grants the rules. The label is the only wallet-level input; the agent and an optional `ref` are named on each rule, because that is where the contract binds them. + +```tsx +// Function +const created = await client.agentic.create(label, { options }) + +// Usage and Params +const created = await client.agentic.create('aave-optimiser', { // wallet with one cross-chain rule, funded + rules: [{ // one entry per chain per agent + agent: '0xAgentOnPush', // a Push address: the agent's EOA, or its UEA if the key lives on another chain. Never the owner + ref: jobRef, // emitted in RulesGranted, not interpreted + chainNamespace: CHAIN.ETHEREUM_SEPOLIA, // foreign chain => universal rulebook + asset: usdcOnPush, + maxAmountPerCall: parseUnits('100', 6), + maxAmountTotal: parseUnits('100', 6), + maxPCPerCall: parseUnits('0.5', 18), + validUntil: now + 30 * 86400, + allowedCalls: [ + { target: aavePool, selector: 'supply(address,uint256,address,uint16)', beneficiary: 2 }, // arg index, not offset + { target: usdcSepolia, selector: 'approve(address,uint256)' }, + ], + }], + funds: [{ amount: parseUnits('100', 6), token: MOVEABLE.TOKEN.ETHEREUM_SEPOLIA.USDC }], + pc: parseUnits('5', 18), // native PC for outbound fees + progressHook: (p) => console.log(p.id, p.message), // AGENTIC-TX-1xx +}); +const bare = await client.agentic.create('scratch', { rules: [] }); // wallet first, rules later with rules.add +// label string, required shown in list() and info(); the contract stores it +// options.rules Rule[], required one per chain per agent, may be empty; each rule carries its own agent and optional ref +// options.funds Array<{ amount, token }>, optional same shape as tx.funds, always an array; default none +// options.pc bigint, optional native PC for outbound fees; default none +// options.progressHook function, optional progress events, AGENTIC-TX-1xx; default none +// rules[].agent Address, required the Push address allowed to act under this rule; never the owner +// rules[].ref Hex, optional emitted in RulesGranted, not interpreted; default zero + +// Returns +// { wallet, index, rulesIds, tx } +{ + wallet: '0x2Fd904d6f2C0b34d58426C8Ae9c5267E845CE98f', + index: 0, + rulesIds: ['0x9c1e...'], // in the order of the rules you passed; empty for rules: [] + tx: { // UniversalTxResponse + hash: '0xb527...', + origin: 'eip155:11155111:0x31dC...', // the owner's key, CAIP-10 + from: '0xFd6C2fE69bE13d8bE379CCB6c9306e74193EC1A9', // the owner's Push account + blockNumber: 1290n, + wait // await tx.wait() for the receipt; status lives on the receipt + } +} +``` + +One rule per chain per agent. A wallet may have different agents on different chains. If an agent needs to act on two chains, `rules` has two entries with the same `agent`; two agents on one chain are two entries with the same `chainNamespace`. Nobody states a rule type; the SDK reads it from `chainNamespace`. `rules: []` is allowed: create the wallet first and grant rules later with `rules.add` (1.k). + +Before asking for a signature the SDK checks that no rule's agent is the owner (`AGENT_IS_OWNER`), that no two rules share both agent and chain (`DUPLICATE_RULE`), that every `allowedCalls[].target` is on the rule's chain (`TARGET_NOT_ON_RULE_CHAIN`), and that the asset is a PRC20 whose `SOURCE_CHAIN_NAMESPACE` matches the rule's chain (`ASSET_CHAIN_MISMATCH`). + +Under the hood this is `deployWallet` (or reuse of a derived address), the funds moved in, and one `grantRules` per rule. For an external owner they go as one UEA multicall under one signature. `funds` stays an array; an external owner moving several tokens may need one signature per token, and the SDK sequences them and reports each through progress events. + +For a Push EOA owner the same thing needs a batching entry on the factory, because core rejects multicall from a Push-native sender: [1. AGW Contract Changes (nomenclature standard + change set)](1-agw-contract-changes.md) item 11, **PROPOSED** (`createWallet(label, rules[], funds)` on the factory). Until it lands the SDK sends deploy, fund and grant as separate transactions and says so through progress events (AGENTIC-TX-102 to 104); `tx` is then the last of them. + +A `progressHook` passed to `PushChain.initialize` receives the same events alongside the per-call one, as in core. + +Warning for an agent whose key lives on another chain: the same EVM key initialized against two chains yields two UEAs, because a UEA is derived from namespace, chainId and owner. Grant the rule to the UEA of the chain the agent will run against. `PushChain.utils.account.deriveExecutorAccount(PushChain.utils.account.toUniversal(address, { chain }))` gives it. + +### 1.c List an owner's wallets - `client.agentic.list` + +Lists the wallets owned by the connected signer. It takes no arguments and only reads the connected account. + +```tsx +// Function +const res = await client.agentic.list() + +// Usage and Params +const { wallets } = await client.agentic.list(); // the connected signer's wallets +// no params + +// Returns +// { wallets: Array<{ address, index, label, deployed, rulesCount }> } +{ + wallets: [ + { address: '0x2Fd9...', index: 0, label: 'aave-optimiser', deployed: true, rulesCount: 1 }, + { address: '0x81aB...', index: 1, label: '', deployed: false, rulesCount: 0 }, + ] +} +``` + +Client methods act on the connected account; reads about any other account live in `PushChain.utils`. If a read-only view is needed later (a marketplace or explorer page showing the wallets of an address with no signer), it becomes `PushChain.utils.agentic.wallets(owner: Address)` taking a Push address; an external owner passes its UEA. Not in v1. + +### 1.d Get a wallet handle - `client.agentic.wallet` + +Returns a handle for one wallet: the reads that are specific to an agentic wallet, plus the rule writes only an owner can do. It is not a client and never sends as the wallet. + +```tsx +// Function +const w = client.agentic.wallet(address) + +// Usage and Params +const w = client.agentic.wallet('0xWallet'); // handle for one wallet; nothing is sent +// address Address, required the AGW to manage, a Push address + +// Returns +// { address, info(), owner(), setLabel(), checkpoints(), rules.* } +{ + address: '0xWallet', + info, owner, setLabel, checkpoints, // 1.e to 1.h + rules: { list, get, add, update, revoke } // 1.i to 1.m +} +``` + +There is one way to send as the wallet: `PushChain.initialize(signer, { agenticWallet })` (section 2). The handle only manages. To send as the wallet, move funds, reach the wallet's CEA on another chain, or read balances, initialize with `agenticWallet` and use the normal account tooling: `sendTransaction`, `universal.read`, or viem and ethers against `client.universal.account`. That gives the owner the full `sendTransaction` with every route the SDK already has, the same receipts, and the wallet's CEA reachable exactly as it is for any other account. + +Balance reads are deliberately not on the handle: they are not agentic, and every account is read the same way. There is no `w.execute` for the same reason. The handle stays what its name says: management. + +### 1.e Read wallet info - `w.info` + +Returns the wallet's summary in one read: the fields `list()` shows for each wallet, plus the owner. It is how you read the label from the handle. + +```tsx +// Function +const info = await w.info() + +// Usage and Params +const { label, deployed } = await w.info(); // one wallet's summary +// no params + +// Returns +// { address, label, index, owner, deployed, rulesCount } +{ + address: '0x2Fd904d6f2C0b34d58426C8Ae9c5267E845CE98f', + label: 'aave-optimiser', + index: 0, + owner: '0xFd6C2fE69bE13d8bE379CCB6c9306e74193EC1A9', + deployed: true, + rulesCount: 1 +} +``` + +### 1.f Read the owner - `w.owner` + +Returns the owner's Push address, as the contract stores it. + +```tsx +// Function +const res = await w.owner() + +// Usage and Params +const { owner } = await w.owner(); // the Push address stored as owner +// no params + +// Returns +// { owner } +{ + owner: '0xFd6C2fE69bE13d8bE379CCB6c9306e74193EC1A9' +} +``` + +If the owner is a UEA and you need the controlling origin behind it (the chain and the external key), use `resolveControllerAccount` on the returned address. + +Page rule: identities going in and out of the agentic namespace are Push addresses (owner, agent, wallet). + +### 1.g Set the wallet label - `w.setLabel` + +**PROPOSED**, contract change, see [1. AGW Contract Changes (nomenclature standard + change set)](1-agw-contract-changes.md) item 10. Changes the label shown in `list()` and `info()`; owner only. + +```tsx +// Function +const tx = await w.setLabel(label, { options? }) + +// Usage and Params +const tx = await w.setLabel('aave-optimiser-v2'); // rename the wallet +const tracked = await w.setLabel('aave-optimiser-v2', { progressHook: (p) => console.log(p.id) }); // with progress events +// label string, required the new label; stored by the contract and emitted in LabelSet +// options.progressHook function, optional progress events, AGENTIC-TX-106; default none + +// Returns +// { hash, origin, from, to, blockNumber, wait() } +{ + hash: '0x3b8d...', + origin: 'eip155:11155111:0x31dC...', // the owner's key, CAIP-10 + from: '0xFd6C2fE69bE13d8bE379CCB6c9306e74193EC1A9', // the owner's Push account + to: '0x2Fd904d6f2C0b34d58426C8Ae9c5267E845CE98f', // the wallet + blockNumber: 1488n, + wait // await tx.wait() for the receipt; status lives on the receipt +} +``` + +Emits `LabelSet(string label)`. It is not a checkpoint: the label is cosmetic metadata and evaluators ignore it. Today the label can only be set once, at `deployWallet`, and is emitted in `WalletDeployed`. + +### 1.h Read checkpoints - `w.checkpoints` + +Every owner-side change the wallet has recorded: owner-door sends, rules granted, rules revoked. An evaluator reads these to know whether the owner changed anything after a job started (page 4). + +```tsx +// Function +const res = await w.checkpoints({ options? }) + +// Usage and Params +const all = await w.checkpoints(); // every checkpoint +const recent = await w.checkpoints({ sinceBlock: 1234n }); // from a block onward +// options.sinceBlock bigint, optional only checkpoints at or after this block; default all + +// Returns +// { checkpoints: Array<{ seq, kind, ref, blockNumber, txHash }> } +{ + checkpoints: [ + { seq: 3, kind: 'RULES_GRANTED', ref: '0x9c1e...', blockNumber: 1290n, txHash: '0x...' }, + { seq: 4, kind: 'OWNER_ACTION', ref: '0x5a7b...', blockNumber: 1402n, txHash: '0x...' }, + ] +} +``` + +### 1.i List rules - `w.rules.list` + +Returns every rule on the wallet as a decoded record, including what each rule has spent so far. + +```tsx +// Function +const res = await w.rules.list() + +// Usage and Params +const { rules } = await w.rules.list(); // the wallet's rules +// no params + +// Returns +// { rules: RulesRecord[] } +{ + rules: [ + { + rulesId: '0x9c1e...', + enabled: true, + chainNamespace: 'eip155:11155111', + agent: '0xAgentOnPush', + validUntil: 1767225600, + ref: '0x4a2f...', + rule: { /* decoded UniversalRule, as passed to create */ }, + spent: { kind: 'universal', amountSpent: 25000000n } // shape PROPOSED, see 3.b + } + ] +} +``` + +### 1.j Get one rule - `w.rules.get` + +Returns one rule by id, decoded, with what it has spent. + +```tsx +// Function +const record = await w.rules.get(rulesId) + +// Usage and Params +const record = await w.rules.get('0x9c1e...'); // one rule by id +// rulesId Hex, required the id returned by create or rules.add + +// Returns +// RulesRecord +{ + rulesId: '0x9c1e...', + enabled: true, + chainNamespace: 'eip155:11155111', + agent: '0xAgentOnPush', + validUntil: 1767225600, + ref: '0x4a2f...', + rule: { /* decoded UniversalRule */ }, + spent: { kind: 'universal', amountSpent: 25000000n } // shape PROPOSED, see 3.b +} +``` + +`spent` is a field on the record, so `get` and `list` both carry it. There is no separate spent call. + +### 1.k Add rules - `w.rules.add` + +Grants new rules on an existing wallet under one signature. The rules array comes first; `agent` and `ref` live on each rule. + +```tsx +// Function +const res = await w.rules.add(rules, { options? }) + +// Usage and Params +const one = await w.rules.add([nativeRule]); // one rule +const many = await w.rules.add([ruleOnSepolia, ruleOnPush]); // several rules, one signature +const tracked = await w.rules.add([nativeRule], { progressHook: (p) => console.log(p.id, p.message) }); // with progress events +// rules Rule[], required one per chain per agent; each rule carries its own agent and optional ref +// options.progressHook function, optional progress events, AGENTIC-TX-104; default none + +// Returns +// { rulesIds, tx } +{ + rulesIds: ['0x7d3a...'], // in the order of the rules you passed + tx: { // UniversalTxResponse + hash: '0x4c19...', + origin: 'eip155:11155111:0x31dC...', + from: '0xFd6C2fE69bE13d8bE379CCB6c9306e74193EC1A9', + blockNumber: 1501n, + wait + } +} +``` + +Records a `RULES_GRANTED` checkpoint. + +### 1.l Update rules - `w.rules.update` + +Replaces rules in a batch: each pair names one old rule and the one new rule that takes its place. + +```tsx +// Function +const res = await w.rules.update({ rules, progressHook? }) + +// Usage and Params +const one = await w.rules.update({ rules: [{ rulesId: '0x9c1e...', rule: newRule }] }); // replace one rule +const many = await w.rules.update({ rules: [{ rulesId: idA, rule: ruleA }, { rulesId: idB, rule: ruleB }] }); // replace several, one signature +const tracked = await w.rules.update({ rules: [{ rulesId: idA, rule: ruleA }], progressHook: (p) => console.log(p.id) }); // with progress events +// rules Array<{ rulesId, rule }>, required one old rule to one new rule per pair +// rules[].rulesId Hex, required the rule being replaced +// rules[].rule Rule, required the replacement; one rule per agent per chain still applies +// progressHook function, optional progress events, AGENTIC-TX-105 and 104; default none + +// Returns +// { rules: Array<{ rulesId, replaced }>, tx } +{ + rules: [ + { rulesId: '0x51c0...', replaced: '0x9c1e...' }, // new id, old id + ], + tx: { // UniversalTxResponse + hash: '0x7a02...', + origin: 'eip155:11155111:0x31dC...', + from: '0xFd6C2fE69bE13d8bE379CCB6c9306e74193EC1A9', + blockNumber: 1507n, + wait + } +} +``` + +Rules are immutable on-chain, so an update is a revoke plus a grant: for each pair the SDK asserts the old rule's spend, revokes it and grants the new one, all pairs in one multicall. The result is a new `rulesId` per pair, and the spend counters reset on the new rule: what the old rule had spent does not carry over. This is accepted for v1 (open item 1); an in-place update would be a contract change and there is no demand for it yet. + +### 1.m Revoke rules - `w.rules.revoke` + +Revokes some rules by id, or all of them in one atomic call. + +```tsx +// Function +const tx = await w.rules.revoke(rulesIds, { options? }) +const tx = await w.rules.revoke({ all, progressHook? }) + +// Usage and Params +const some = await w.rules.revoke(['0x9c1e...', '0x7d3a...']); // revoke these rules +const all = await w.rules.revoke({ all: true }); // revoke every rule, on-chain revokeAllRules +const tracked = await w.rules.revoke(['0x9c1e...'], { progressHook: (p) => console.log(p.id) }); // with progress events +// rulesIds Hex[], required unless all is set the rules to revoke +// options.progressHook function, optional progress events, AGENTIC-TX-105; default none +// all true, required unless rulesIds given revoke every rule on the wallet in one atomic call +// progressHook function, optional same events, in the { all: true } form; default none + +// Returns +// { hash, origin, from, to, blockNumber, wait() } +{ + hash: '0x8e01...', + origin: 'eip155:11155111:0x31dC...', // the owner's key, CAIP-10 + from: '0xFd6C2fE69bE13d8bE379CCB6c9306e74193EC1A9', // the owner's Push account + to: '0x2Fd904d6f2C0b34d58426C8Ae9c5267E845CE98f', // the wallet + blockNumber: 1512n, + wait // await tx.wait() for the receipt; status lives on the receipt +} +``` + +A bare `revoke()` is not allowed and throws `REVOKE_NEEDS_TARGET`: a call with no argument that wipes every rule is too easy to make by mistake. Records `RULES_REVOKED` checkpoints. + +# 2. Agent side, by example + +There is no new method on the agent side. The agent uses its own signer and tells `initialize` which wallet to act through. It does not name a rule: which rule applies is decided per transaction, from the destination chain. + +### 2.a Act as the wallet - `PushChain.initialize` with `agenticWallet` (updated) + +Returns a client whose account is the wallet. Whether its sends go through the owner door or the agent door depends on who the signer is. + +```tsx +// Function +const client = await PushChain.initialize(signer, { options }) + +// Usage and Params +const agentClient = await PushChain.initialize(agentSigner, { // agent door: the signer is named as agent in a rule + network: PushChain.CONSTANTS.PUSH_NETWORK.TESTNET, + agenticWallet: '0xWallet', +}); +const ownerClient = await PushChain.initialize(ownerSigner, { // owner door: the signer owns the wallet + network: PushChain.CONSTANTS.PUSH_NETWORK.TESTNET, + agenticWallet: '0xWallet', +}); +``` + +`agentSigner` is any signer `initialize` accepts today. If the key lives on another chain, the SDK derives its UEA and everything goes through that, as it does for every external user. + +Which door the client uses depends on who the signer is. If the signer is the wallet's owner, sends go through the owner door: no rules, and every send is recorded as a checkpoint. If the signer is an address named as agent in one of the wallet's rules, sends go through the agent door and the rules apply. If it is neither, `initialize` throws `NOT_OWNER_OR_AGENT`. If the address has no wallet deployed yet it throws `WALLET_NOT_DEPLOYED`, and if the address is not an agentic wallet it throws `NOT_AGENTIC_WALLET`. This is also how an owner acts as the wallet with the full client: `PushChain.initialize(ownerSigner, { agenticWallet })`. There is one way to send as a wallet and the signer decides the door. + +On the agent door the SDK sends; URP on-chain is the only rule checker. Before sending, the SDK only looks up the `rulesId` for the destination chain: the rule that is enabled, whose `agent` equals the signer, and whose `chainNamespace` equals the destination. The lookup is one read on every send, not cached at initialize. If none is found it throws `NO_RULES_FOR_CHAIN` before any signature, so it costs nothing; otherwise it calls `executeAsAgent(rulesId, ...)` on the wallet. That is the agent door from D3 on [1. AGW Contract Changes (nomenclature standard + change set)](1-agw-contract-changes.md): there is no session validator, and the wallet only checks that `msg.sender` is the rule's agent. There is one rule per (agent, chain), so a signer and a destination match at most one rule. If the action breaks a rule, it reverts on-chain and the agent pays that gas. `sendTransaction` then throws `AgenticRevertError`, which extends core's `PushChainExecutionError` and carries URP's custom error in `decodedError`, so the agent sees which gate failed (3.f). + +From an external key, the call arrives through the agent's UEA. If the agent's UEA is not yet deployed, the first action takes the origin-chain fee lock once (minimum $1), which deploys the UEA and funds it with PC. Every later action requires PC in the UEA and is a direct Push transaction paid from that balance, with no origin transaction and no cross-chain wait. + +Two things for whoever runs the agent. The agent's UEA is a second balance to keep funded: the AGW's PC covers the wallet's outbound fees, not the agent's gas. And in `agenticWallet` mode the SDK turns `enforceGasCheck` on for every action except that one first action while the agent's UEA is not yet deployed, so an empty UEA fails loudly instead of silently falling back to a $1 origin lock and a confirmation wait on every action. + +Routing. In `agenticWallet` mode every send is wrapped as `executeAsAgent` (agent door) or `execute` (owner door), and for cross-chain legs the AGW itself calls the gateway. So the AGW's CEA executes on the destination and the AGW's PC pays as `msg.value`. The SDK never uses the signer's own Route 2, which would run through the agent's CEA instead of the wallet's. Any `from` (Routes 3 and 4) is rejected in `agenticWallet` mode with `FROM_NOT_ALLOWED`: it makes `msg.sender` a CEA, and the agent door check fails. + +What changes on the client in this mode: + +- `universal.account` is the wallet address string, so receipts show the AGW as `from`. `universal.origin` stays the signer's origin account. +- `getAccountStatus()` reports the signer's own UEA, not the wallet. +- The signer is whatever was passed to `initialize`. To top up the agent's UEA, find it with `PushChain.utils.account.deriveExecutorAccount(signer.account)` and send PC to it from a client initialized without `agenticWallet`. +- A Solana-keyed agent can act on Push and `eip155` destinations now, and on `solana:` destinations once the SVM rulebook ships. +- Agents read their own rules through `client.agentic.wallet(addr).rules.list()`. +- `tx.data` arrays and `tx.funds` (moving the AGW's PRC20) work as they do for any account. +- `payGasWith`, `migrateCEA`, `rescueFunds`, `prepareTransaction` and `executeTransactions` throw `NOT_ALLOWED_IN_AGENTIC_MODE`. + +```tsx +const tx = await agentClient.universal.sendTransaction({ // agent door, rule picked by the destination chain + to: { address: aavePool, chain: CHAIN.ETHEREUM_SEPOLIA }, + data: supplyData, +}); + +// tx: UniversalTxResponse +{ + hash: '0x6f2a...', + origin: 'eip155:11155111:0x7Be1...', // the agent's key, CAIP-10 + from: '0xWallet', // the AGW, not the signer + blockNumber: 1530n, + wait +} + +const receipt = await tx.wait(); +// receipt: UniversalTxReceipt +{ + status: 1, + hash: '0x6f2a...', + from: '0xWallet', + blockNumber: 1530n, + externalTxHash: '0x91c4...' // the leg executed by the AGW's CEA on Sepolia +} +``` + +The same EVM key initialized against two chains yields two UEAs (derived from namespace, chainId and owner), so the rule must name the UEA of the chain this client initializes against (see 1.b). + +# 3. Types + +### 3.a Client, options and namespace + +```tsx +type Address = `0x${string}`; +type Hex = `0x${string}`; +type ForeignChainNamespace = `eip155:${string}` | `solana:${string}`; +type ProgressHook = (p: ProgressEvent) => void; // ProgressEvent is core's shape: { id, title, message, level, response, timestamp } + +interface PushChainClient { + universal: UniversalNamespace; // in agenticWallet mode: account is the wallet + agentic: AgenticNamespace; // this page + market: MarketNamespace; // page 6 + job: JobNamespace; // page 7 + evaluation: EvaluationNamespace; // page 8 +} + +interface InitializeOptions { + network?: PUSH_NETWORK; + rpcUrls?: Partial>; + agenticWallet?: Address; // NEW: act as the wallet; door chosen by the signer's Push address + // enforceGasCheck is on when agenticWallet is set, except for the first action while the agent's UEA is not yet deployed (2.a) +} + +interface AgenticNamespace { + derive(opts?: { index?: number }): Promise<{ address: Address; index: number; deployed: boolean }>; + create(label: string, options: CreateOptions): Promise; + list(): Promise<{ wallets: WalletSummary[] }>; // connected signer only + wallet(address: Address): AgenticWallet; +} + +interface CreateOptions { + rules: Rule[]; // one entry per chain per agent, may be empty; each rule names its agent and optional ref + funds?: { amount: bigint; token: MoveableToken | Address }[]; // same shape as tx.funds, always an array + pc?: bigint; // native PC for outbound fees + progressHook?: ProgressHook; // AGENTIC-TX-1xx +} + +// No AgentKey type, no curve, no chain. The agent is a Push address. A native key is its own EOA; any external key +// (EVM, Solana, anything) is its UEA, deterministic from (chain, owner), deployed lazily on first use. The AGW's agent +// door checks msg.sender == rules.agent; cross-VM signature verification already happened inside the UEA (page 1, D3). + +interface CreateResult { wallet: Address; index: number; rulesIds: Hex[]; tx: UniversalTxResponse } +interface WalletSummary { address: Address; index: number; label: string; deployed: boolean; rulesCount: number } +``` + +### 3.b Rules + +```tsx +type Rule = NativeRule | UniversalRule; // chainNamespace decides the rulebook: omitted = native, foreign = universal + +interface NativeRule { + agent: Address; // Push address: EOA, or the UEA of an external key (PushChain.utils.account.deriveExecutorAccount) + ref?: Hex; // emitted in RulesGranted, not interpreted + chainNamespace?: never; // omitted = the connected Push chain + target: Address; + selector: Selector | 'value-only'; + validUntil: number; + maxValuePerCall?: bigint; maxValueTotal?: bigint; maxCalls?: number; + pins?: { arg: number; expected: Hex | Address | bigint }[]; + amount?: { arg: number; maxPerCall: bigint; maxTotal?: bigint }; +} + +interface UniversalRule { + agent: Address; // same as NativeRule.agent + ref?: Hex; // same as NativeRule.ref + chainNamespace: ForeignChainNamespace; // "eip155:..." now; "solana:..." once the SVM rulebook ships + asset: Address; // PRC20 on Push; SDK asserts its SOURCE_CHAIN_NAMESPACE + validUntil: number; + maxAmountPerCall: bigint; maxAmountTotal?: bigint; maxPCPerCall: bigint; + allowedCalls: AllowedCall[]; // 1..32, all on chainNamespace +} + +type Selector = Hex | `${string}(${string})`; // '0x617ba037' or 'supply(address,uint256,address,uint16)' + +interface AllowedCall { target: Address; selector: Selector; beneficiary?: number; maxValue?: bigint } // beneficiary = arg index + +interface RulesRecord { + rulesId: Hex; + enabled: boolean; + chainNamespace: string; + agent: Address; // the Push address granted + validUntil: number; + ref: Hex; + rule: Rule; // decoded terms; NativeRule or UniversalRule + spent: Spent; // carried by rules.get and rules.list; no separate call +} + +type Spent = { kind: 'universal'; amountSpent: bigint } | { kind: 'native'; valueSpent: bigint; amountSpent: bigint; callsUsed: number }; // PROPOSED: one self-describing object, readable without knowing the rulebook +``` + +### 3.c Wallet handle and checkpoints + +```tsx +interface AgenticWallet { + address: Address; + info(): Promise; + owner(): Promise<{ owner: Address }>; // Push address as stored + setLabel(label: string, opts?: { progressHook?: ProgressHook }): Promise; // PROPOSED, page 1 item 10 + checkpoints(opts?: { sinceBlock?: bigint }): Promise<{ checkpoints: Checkpoint[] }>; + rules: { + list(): Promise<{ rules: RulesRecord[] }>; + get(rulesId: Hex): Promise; + add(rules: Rule[], opts?: { progressHook?: ProgressHook }): Promise<{ rulesIds: Hex[]; tx: UniversalTxResponse }>; + update(params: { rules: { rulesId: Hex; rule: Rule }[]; progressHook?: ProgressHook }): Promise<{ rules: { rulesId: Hex; replaced: Hex }[]; tx: UniversalTxResponse }>; // revoke plus grant; spend counters reset + revoke(rulesIds: Hex[], opts?: { progressHook?: ProgressHook }): Promise; + revoke(params: { all: true; progressHook?: ProgressHook }): Promise; + }; +} + +interface WalletInfo { address: Address; label: string; index: number; owner: Address; deployed: boolean; rulesCount: number } + +interface Checkpoint { seq: number; kind: 'OWNER_ACTION' | 'RULES_GRANTED' | 'RULES_REVOKED'; ref: Hex; blockNumber: bigint; txHash: Hex } +``` + +### 3.d Constants, PushChain.CONSTANTS.AGENTIC (new) + +```tsx +PushChain.CONSTANTS.AGENTIC[PUSH_NETWORK.TESTNET_DONUT] = { + FACTORY, RULES_POLICY, // RULES_POLICY is URP; no validator address (page 1, D3) + MAX_PINS: 8, MAX_ALLOWED_CALLS: 32, ENVELOPE_VERSION: 1, +}; +``` + +### 3.e Helpers, PushChain.utils.agentic (new) + +Pure functions with the same output as the on-chain views. + +```tsx +PushChain.utils.agentic = { + rulesId(agent, chainNamespace, grantNonce), // the id a grant produces, same as the contract assigns + actionId(target, selector), // id of one allowed call: hash of its target and selector + configId(wallet, rulesId, actionId), // key of one allowed call's stored config, under one rule on one wallet + encodeRules(rules, ctx), // ctx = wallet and chain context needed to resolve beneficiary offsets + decodeRules(bytes), + deriveWallet(owner, index), // any-owner variant of client.agentic.derive + compileCard(card, userInput, ctx), // used by page 6; lives here because it produces Rule[] +}; +``` + +### 3.f Errors and progress + +```tsx +class AgenticError extends Error { code: string; hint?: string } +class AgenticRevertError extends PushChainExecutionError {} +// decoded custom error from the AGW, URP or the factory; uses core's fields: +// code string +// decodedError { name, hint, selector, decoded } + +// codes +// create: AGENT_IS_OWNER, DUPLICATE_RULE, TARGET_NOT_ON_RULE_CHAIN, ASSET_CHAIN_MISMATCH +// initialize (agenticWallet): NOT_OWNER_OR_AGENT, WALLET_NOT_DEPLOYED, NOT_AGENTIC_WALLET +// rules.revoke: REVOKE_NEEDS_TARGET (bare revoke) +// sendTransaction: NO_RULES_FOR_CHAIN, FROM_NOT_ALLOWED (any from, Routes 3 and 4) +// agentic mode: NOT_ALLOWED_IN_AGENTIC_MODE (prepareTransaction, executeTransactions, payGasWith, migrateCEA, rescueFunds) + +// progress events, AGENTIC-TX (PROPOSED) +// AGENTIC-TX-101 wallet derived { address, index, deployed } +// AGENTIC-TX-102 deploy step added +// AGENTIC-TX-103 funds and PC step added +// AGENTIC-TX-104 rules granted { rulesIds } +// AGENTIC-TX-105 rules revoked { rulesIds | all } +// AGENTIC-TX-106 label set +// AGENTIC-TX-107 rule resolved for a send { rulesId, chainNamespace, door } +// AGENTIC-TX-199-01 done +// AGENTIC-TX-199-02 failed { code, decodedError } +// The Push leg of any agentic send also emits core's SEND-TX-1xx events. +// A cross-chain leg sent by the AGW emits 209-xx and 299-xx, never 201 to 204 (the signer's own Route 2 is never used). +``` + +**PROPOSED:** the AGENTIC-TX event list. Every write (`create`, `setLabel`, `rules.add`, `rules.update`, `rules.revoke`) takes a per-call `progressHook`; a `progressHook` passed to `PushChain.initialize` runs alongside it, as in core. + +`NO_RULES_FOR_CHAIN` is thrown before any signature and costs nothing. The rules lookup is one read on every send, not cached at initialize. A URP revert is thrown from `sendTransaction` as `AgenticRevertError` and also lands as `decodedError` on AGENTIC-TX-199-02. A destination-chain revert after URP passed still counts the spend, because the spend is counted when the outbound leaves Push; whether it is credited back depends on [1. AGW Contract Changes (nomenclature standard + change set)](1-agw-contract-changes.md) item 6 (`creditRevert`). + +# 4. Outside change: [PushChain.CONSTANTS.READ](http://PushChain.CONSTANTS.READ).CHAIN (confirmed 2026-09-28) + +Problem: `read()` takes `chain: PushChain.CONSTANTS.CHAIN.X`, but `CHAIN` is the set of blockchains the SDK signs for and routes to. Web2 is not one, so `CHAIN.WEB2` exists as a hidden (non-enumerable) member: it works if you know it is there and never appears in any listing. Reads have a wider domain than transactions: anything validators can observe. + +Change: a read-specific constant that is a superset of `CHAIN`. The field name stays `chain`, so nothing breaks, and `CHAIN` values remain valid because the strings are identical. + +```tsx +PushChain.CONSTANTS.READ.CHAIN = { + ...PushChain.CONSTANTS.CHAIN, // every real chain, same string values + WEB2: 'web2', // non-chain source, first-class here, enumerable +}; +type ReadChain = CHAIN | 'web2'; // ReadParams.chain: ReadChain + +read({ chain: PushChain.CONSTANTS.READ.CHAIN.WEB2, ... }) +read({ chain: PushChain.CONSTANTS.CHAIN.ETHEREUM_SEPOLIA, ... }) // still compiles +``` + +- `CHAIN.WEB2` becomes a deprecated alias of `READ.CHAIN.WEB2` for one release (the docs listed it on 2026-09-22), then goes. +- Anything that iterates `CHAIN` stops seeing a fake chain; anything that iterates `READ.CHAIN` sees every read source. +- The evaluator's `Read.chain` (page 8) takes the same values, so `READ.CHAIN` is the one constant the read SDK and the criteria compiler share. + +# 5. Open for review + +1. `rules.update` resets spend counters because it is revoke plus grant. Accepted for v1 and stated in 1.l; an in-place update is a contract change with no demand yet. +2. `setLabel` assumes [1. AGW Contract Changes (nomenclature standard + change set)](1-agw-contract-changes.md) item 10 lands. Pointer for the team. \ No newline at end of file diff --git a/plan/agw/notion/history/20261003T075310278902Z/manifest-before.json b/plan/agw/notion/history/20261003T075310278902Z/manifest-before.json new file mode 100644 index 00000000..14756b2c --- /dev/null +++ b/plan/agw/notion/history/20261003T075310278902Z/manifest-before.json @@ -0,0 +1,176 @@ +{ + "schema_version": 1, + "snapshot_date": "2026-10-02", + "notes": "Page content preserved; known intra-export links normalized to local filenames. Comment threads excluded by Notion export. Null edit dates mean not observed. Original bundle retained.", + "sources": [ + { + "title": "AGW design overview", + "page_id": "3e9188aea7f481c8b38ccba332b0afa2", + "notion_url": "https://app.notion.com/p/pushprotocol/AGW-UniversalMarketplace-8183-UniversalEvaluator-3e9188aea7f481c8b38ccba332b0afa2", + "local_file": "notion/overview.md", + "pulled_on": "2026-10-02", + "observed_last_edited_date": "2026-10-01", + "authority": "Supporting design", + "sha256": "f2d7954e018324a937282ca190f397cc12a27973a07c891f3edfd6e89383c53e", + "export_entry": "Private & Shared/AGW + UniversalMarketplace + 8183 + UniversalEvalu 3e9188aea7f481c8b38ccba332b0afa2.md", + "raw_export_sha256": "99b727bd58cf588b2c766dc1b93eff402c47e918718b69c2a456b119ad43435b", + "archive": "notion/exports/20261002T133806744498Z/export-1.zip", + "pulled_at": "2026-10-02T13:38:06.744498+00:00" + }, + { + "title": "1 AGW Contract Changes", + "page_id": "3e9188aea7f4813aa31fc95ceb4e684d", + "notion_url": "https://app.notion.com/p/pushprotocol/1-AGW-Contract-Changes-nomenclature-standard-change-set-3e9188aea7f4813aa31fc95ceb4e684d", + "local_file": "notion/1-agw-contract-changes.md", + "pulled_on": "2026-10-02", + "observed_last_edited_date": "2026-10-01", + "authority": "WIP contract target", + "sha256": "22fa37bdd52e903c632760f4b7fa77cd7be89a7c5a124eba3f6866c00b5632c6", + "export_entry": "Private & Shared/AGW + UniversalMarketplace + 8183 + UniversalEvalu/1 AGW Contract Changes (nomenclature standard + ch 3e9188aea7f4813aa31fc95ceb4e684d.md", + "raw_export_sha256": "22fa37bdd52e903c632760f4b7fa77cd7be89a7c5a124eba3f6866c00b5632c6", + "archive": "notion/exports/20261002T133806744498Z/export-1.zip", + "pulled_at": "2026-10-02T13:38:06.744498+00:00" + }, + { + "title": "2 Universal Marketplace", + "page_id": "3e9188aea7f48118b90ac9b267496295", + "notion_url": "https://app.notion.com/p/pushprotocol/2-Universal-Marketplace-3e9188aea7f48118b90ac9b267496295", + "local_file": "notion/2-universal-marketplace.md", + "pulled_on": "2026-10-02", + "observed_last_edited_date": null, + "authority": "Supporting WIP design", + "sha256": "5ddfd9e8980faae9eec85e3959cc99edbb3b115565af289c5603a91df0b78d18", + "export_entry": "Private & Shared/AGW + UniversalMarketplace + 8183 + UniversalEvalu/2 Universal Marketplace 3e9188aea7f48118b90ac9b267496295.md", + "raw_export_sha256": "5ddfd9e8980faae9eec85e3959cc99edbb3b115565af289c5603a91df0b78d18", + "archive": "notion/exports/20261002T133806744498Z/export-1.zip", + "pulled_at": "2026-10-02T13:38:06.744498+00:00" + }, + { + "title": "3 ERC-8183 job kernel and hook", + "page_id": "3e9188aea7f48188a838c3a740d8c858", + "notion_url": "https://app.notion.com/p/pushprotocol/3-8183-job-kernel-and-hook-3e9188aea7f48188a838c3a740d8c858", + "local_file": "notion/3-8183-job-kernel-and-hook.md", + "pulled_on": "2026-10-02", + "observed_last_edited_date": null, + "authority": "Supporting WIP design", + "sha256": "3c805db465f2d39db8d34179ac1dd864db1abf7b1b3e93f38074fbf393093f90", + "export_entry": "Private & Shared/AGW + UniversalMarketplace + 8183 + UniversalEvalu/3 8183 (job kernel and hook) 3e9188aea7f48188a838c3a740d8c858.md", + "raw_export_sha256": "3c805db465f2d39db8d34179ac1dd864db1abf7b1b3e93f38074fbf393093f90", + "archive": "notion/exports/20261002T133806744498Z/export-1.zip", + "pulled_at": "2026-10-02T13:38:06.744498+00:00" + }, + { + "title": "4 Universal Evaluation", + "page_id": "3e9188aea7f4817bb03ef4c78c883f8b", + "notion_url": "https://app.notion.com/p/pushprotocol/4-Universal-Evaluation-3e9188aea7f4817bb03ef4c78c883f8b", + "local_file": "notion/4-universal-evaluation.md", + "pulled_on": "2026-10-02", + "observed_last_edited_date": null, + "authority": "Supporting WIP design", + "sha256": "a2f1c93a75b8631c9628c06f1be135fa0198f00f096a765ce808dd5e544b2d6f", + "export_entry": "Private & Shared/AGW + UniversalMarketplace + 8183 + UniversalEvalu/4 Universal Evaluation 3e9188aea7f4817bb03ef4c78c883f8b.md", + "raw_export_sha256": "a2f1c93a75b8631c9628c06f1be135fa0198f00f096a765ce808dd5e544b2d6f", + "archive": "notion/exports/20261002T133806744498Z/export-1.zip", + "pulled_at": "2026-10-02T13:38:06.744498+00:00" + }, + { + "title": "5 SDK AGW", + "page_id": "3e9188aea7f481cf8e8de324956549b9", + "notion_url": "https://app.notion.com/p/pushprotocol/5-SDK-AGW-3e9188aea7f481cf8e8de324956549b9", + "local_file": "notion/5-sdk-agw.md", + "pulled_on": "2026-10-02", + "observed_last_edited_date": "2026-10-01", + "authority": "Primary SDK API target", + "sha256": "9ce90fb84826c989b4fec22066da0776121f9195e27bc6679aaac538995f4653", + "export_entry": "Private & Shared/AGW + UniversalMarketplace + 8183 + UniversalEvalu/5 SDK AGW 3e9188aea7f481cf8e8de324956549b9.md", + "raw_export_sha256": "25293396ec37f3a48cd47178030d7d6eaa93094dc74ff80ffda3284bdd78021b", + "archive": "notion/exports/20261002T133806744498Z/export-1.zip", + "pulled_at": "2026-10-02T13:38:06.744498+00:00" + }, + { + "title": "6 SDK Universal Marketplace", + "page_id": "3ea188aea7f481e2961ed97129f3a4e6", + "notion_url": "https://app.notion.com/p/pushprotocol/6-SDK-Universal-Marketplace-3ea188aea7f481e2961ed97129f3a4e6", + "local_file": "notion/6-sdk-universal-marketplace.md", + "pulled_on": "2026-10-02", + "observed_last_edited_date": "2026-09-30", + "authority": "Supporting WIP SDK", + "sha256": "e7298952f2ba9adb218b4ef0459b8fa696a2072167dc5f655060b69788cf528c", + "export_entry": "Private & Shared/AGW + UniversalMarketplace + 8183 + UniversalEvalu/6 SDK Universal Marketplace 3ea188aea7f481e2961ed97129f3a4e6.md", + "raw_export_sha256": "e7298952f2ba9adb218b4ef0459b8fa696a2072167dc5f655060b69788cf528c", + "archive": "notion/exports/20261002T133806744498Z/export-1.zip", + "pulled_at": "2026-10-02T13:38:06.744498+00:00" + }, + { + "title": "7 SDK ERC-8183 Job", + "page_id": "3ea188aea7f481e0a137f5a896723376", + "notion_url": "https://app.notion.com/p/pushprotocol/7-SDK-8183-Job-3ea188aea7f481e0a137f5a896723376", + "local_file": "notion/7-sdk-8183-job.md", + "pulled_on": "2026-10-02", + "observed_last_edited_date": null, + "authority": "Supporting WIP SDK", + "sha256": "dbf1ff539f5df944e5f5f55710f5f6d3359469a141038cec2604e7c33392752c", + "export_entry": "Private & Shared/AGW + UniversalMarketplace + 8183 + UniversalEvalu/7 SDK 8183 Job 3ea188aea7f481e0a137f5a896723376.md", + "raw_export_sha256": "dbf1ff539f5df944e5f5f55710f5f6d3359469a141038cec2604e7c33392752c", + "archive": "notion/exports/20261002T133806744498Z/export-1.zip", + "pulled_at": "2026-10-02T13:38:06.744498+00:00" + }, + { + "title": "8 SDK Universal Evaluation", + "page_id": "3ea188aea7f48197a3b3cfdedfa74fee", + "notion_url": "https://app.notion.com/p/pushprotocol/8-SDK-Universal-Evaluation-3ea188aea7f48197a3b3cfdedfa74fee", + "local_file": "notion/8-sdk-universal-evaluation.md", + "pulled_on": "2026-10-02", + "observed_last_edited_date": null, + "authority": "Supporting WIP SDK", + "sha256": "eb2e584bd76aeea06c0dd03b3c8802b2340acf955e1ea75bf7768ebf9d2ab34e", + "export_entry": "Private & Shared/AGW + UniversalMarketplace + 8183 + UniversalEvalu/8 SDK Universal Evaluation 3ea188aea7f48197a3b3cfdedfa74fee.md", + "raw_export_sha256": "eb2e584bd76aeea06c0dd03b3c8802b2340acf955e1ea75bf7768ebf9d2ab34e", + "archive": "notion/exports/20261002T133806744498Z/export-1.zip", + "pulled_at": "2026-10-02T13:38:06.744498+00:00" + }, + { + "title": "Legacy PUSH AGW SDK Doc v1", + "page_id": "d2d188aea7f4825cbcea81ef86eca607", + "notion_url": "https://app.notion.com/p/pushprotocol/PUSH-AGW-SDK-Doc-v1-d2d188aea7f4825cbcea81ef86eca607", + "local_file": "notion/legacy-agw-sdk-v1.md", + "pulled_on": "2026-10-02", + "observed_last_edited_date": "2026-09-22", + "authority": "Historical encoding and deployment reference", + "sha256": "9e6569ef9b76d59cb411d65305d67333c6766abc2e9c80a35ae6f56f12f70916", + "raw_export_sha256": "9e6569ef9b76d59cb411d65305d67333c6766abc2e9c80a35ae6f56f12f70916", + "pulled_at": "2026-10-02T13:38:06.744498+00:00", + "archive": "notion/exports/20261002T133806744498Z/export-2.zip", + "export_entry": "Private & Shared/PUSH AGW SDK Doc - v1 d2d188aea7f4825cbcea81ef86eca607.md" + }, + { + "title": "AGW Address Book PC Donut", + "page_id": "3d1188aea7f480ddbb4af6d0efb211e6", + "notion_url": "https://app.notion.com/p/pushprotocol/AGW-Address-Book-PC-Donut-3d1188aea7f480ddbb4af6d0efb211e6", + "local_file": "notion/agw-address-book-donut-2026-09-04.md", + "pulled_on": "2026-10-02", + "observed_last_edited_date": "2026-09-04", + "authority": "Historical deployment", + "sha256": "5c5017d6b4a58af0fa8854ef550b054c1f33d57a812ea51a16f31f7c33e79742", + "raw_export_sha256": "5c5017d6b4a58af0fa8854ef550b054c1f33d57a812ea51a16f31f7c33e79742", + "pulled_at": "2026-10-02T13:38:06.744498+00:00", + "archive": "notion/exports/20261002T133806744498Z/export-3.zip", + "export_entry": "Private & Shared/AGW Address Book - PC Donut 3d1188aea7f480ddbb4af6d0efb211e6.md" + }, + { + "title": "Agentic wallet flow updated", + "page_id": "3d1188aea7f4801f9cb3fbd9318ec536", + "notion_url": "https://app.notion.com/p/pushprotocol/agentic_wallet_flow-updated-3d1188aea7f4801f9cb3fbd9318ec536", + "local_file": "notion/agentic-wallet-flow-2026-09-07.md", + "pulled_on": "2026-10-02", + "observed_last_edited_date": "2026-09-07", + "authority": "Historical validator-based flow", + "sha256": "d4a922fd1d33da5a7042f26053e8df0e496c3ccd4cb0044b0892948ac509c3a0", + "raw_export_sha256": "d4a922fd1d33da5a7042f26053e8df0e496c3ccd4cb0044b0892948ac509c3a0", + "pulled_at": "2026-10-02T13:38:06.744498+00:00", + "archive": "notion/exports/20261002T133806744498Z/export-4.zip", + "export_entry": "Private & Shared/agentic_wallet_flow ( updated ) 3d1188aea7f4801f9cb3fbd9318ec536.md" + } + ], + "last_refresh_at": "2026-10-02T13:38:06.744498+00:00" +} diff --git a/plan/agw/notion/history/20261003T075310278902Z/refresh.json b/plan/agw/notion/history/20261003T075310278902Z/refresh.json new file mode 100644 index 00000000..b0897513 --- /dev/null +++ b/plan/agw/notion/history/20261003T075310278902Z/refresh.json @@ -0,0 +1,124 @@ +{ + "run_id": "20261003T075310278902Z", + "pulled_at": "2026-10-03T07:53:10.278902+00:00", + "complete": true, + "missing_page_ids": [], + "unknown_export_entries": [], + "archives": [ + "notion/exports/20261003T075310278902Z/export-1.zip", + "notion/exports/20261003T075310278902Z/export-2.zip", + "notion/exports/20261003T075310278902Z/export-3.zip", + "notion/exports/20261003T075310278902Z/export-4.zip" + ], + "pages": [ + { + "page_id": "3e9188aea7f481c8b38ccba332b0afa2", + "title": "AGW design overview", + "local_file": "notion/overview.md", + "changed": false, + "previous_sha256": "f2d7954e018324a937282ca190f397cc12a27973a07c891f3edfd6e89383c53e", + "sha256": "f2d7954e018324a937282ca190f397cc12a27973a07c891f3edfd6e89383c53e", + "raw_export_sha256": "99b727bd58cf588b2c766dc1b93eff402c47e918718b69c2a456b119ad43435b" + }, + { + "page_id": "3e9188aea7f4813aa31fc95ceb4e684d", + "title": "1 AGW Contract Changes", + "local_file": "notion/1-agw-contract-changes.md", + "changed": true, + "previous_sha256": "22fa37bdd52e903c632760f4b7fa77cd7be89a7c5a124eba3f6866c00b5632c6", + "sha256": "f1301d8ff1cf370968b90a3d53037ece8fa4c6783c45a402f9be6998928e3631", + "raw_export_sha256": "f1301d8ff1cf370968b90a3d53037ece8fa4c6783c45a402f9be6998928e3631" + }, + { + "page_id": "3e9188aea7f48118b90ac9b267496295", + "title": "2 Universal Marketplace", + "local_file": "notion/2-universal-marketplace.md", + "changed": false, + "previous_sha256": "5ddfd9e8980faae9eec85e3959cc99edbb3b115565af289c5603a91df0b78d18", + "sha256": "5ddfd9e8980faae9eec85e3959cc99edbb3b115565af289c5603a91df0b78d18", + "raw_export_sha256": "5ddfd9e8980faae9eec85e3959cc99edbb3b115565af289c5603a91df0b78d18" + }, + { + "page_id": "3e9188aea7f48188a838c3a740d8c858", + "title": "3 ERC-8183 job kernel and hook", + "local_file": "notion/3-8183-job-kernel-and-hook.md", + "changed": false, + "previous_sha256": "3c805db465f2d39db8d34179ac1dd864db1abf7b1b3e93f38074fbf393093f90", + "sha256": "3c805db465f2d39db8d34179ac1dd864db1abf7b1b3e93f38074fbf393093f90", + "raw_export_sha256": "3c805db465f2d39db8d34179ac1dd864db1abf7b1b3e93f38074fbf393093f90" + }, + { + "page_id": "3e9188aea7f4817bb03ef4c78c883f8b", + "title": "4 Universal Evaluation", + "local_file": "notion/4-universal-evaluation.md", + "changed": false, + "previous_sha256": "a2f1c93a75b8631c9628c06f1be135fa0198f00f096a765ce808dd5e544b2d6f", + "sha256": "a2f1c93a75b8631c9628c06f1be135fa0198f00f096a765ce808dd5e544b2d6f", + "raw_export_sha256": "a2f1c93a75b8631c9628c06f1be135fa0198f00f096a765ce808dd5e544b2d6f" + }, + { + "page_id": "3e9188aea7f481cf8e8de324956549b9", + "title": "5 SDK AGW", + "local_file": "notion/5-sdk-agw.md", + "changed": true, + "previous_sha256": "9ce90fb84826c989b4fec22066da0776121f9195e27bc6679aaac538995f4653", + "sha256": "e407ee77cdf874db7ef4697f84e9945ff3a12a2f2e07e8a7f90bd24e93ea32f1", + "raw_export_sha256": "9a16f8aed79fac09818ec216fb4c69dc79f2fa0cffe0af611af956eb0e69f33f" + }, + { + "page_id": "3ea188aea7f481e2961ed97129f3a4e6", + "title": "6 SDK Universal Marketplace", + "local_file": "notion/6-sdk-universal-marketplace.md", + "changed": false, + "previous_sha256": "e7298952f2ba9adb218b4ef0459b8fa696a2072167dc5f655060b69788cf528c", + "sha256": "e7298952f2ba9adb218b4ef0459b8fa696a2072167dc5f655060b69788cf528c", + "raw_export_sha256": "e7298952f2ba9adb218b4ef0459b8fa696a2072167dc5f655060b69788cf528c" + }, + { + "page_id": "3ea188aea7f481e0a137f5a896723376", + "title": "7 SDK ERC-8183 Job", + "local_file": "notion/7-sdk-8183-job.md", + "changed": false, + "previous_sha256": "dbf1ff539f5df944e5f5f55710f5f6d3359469a141038cec2604e7c33392752c", + "sha256": "dbf1ff539f5df944e5f5f55710f5f6d3359469a141038cec2604e7c33392752c", + "raw_export_sha256": "dbf1ff539f5df944e5f5f55710f5f6d3359469a141038cec2604e7c33392752c" + }, + { + "page_id": "3ea188aea7f48197a3b3cfdedfa74fee", + "title": "8 SDK Universal Evaluation", + "local_file": "notion/8-sdk-universal-evaluation.md", + "changed": false, + "previous_sha256": "eb2e584bd76aeea06c0dd03b3c8802b2340acf955e1ea75bf7768ebf9d2ab34e", + "sha256": "eb2e584bd76aeea06c0dd03b3c8802b2340acf955e1ea75bf7768ebf9d2ab34e", + "raw_export_sha256": "eb2e584bd76aeea06c0dd03b3c8802b2340acf955e1ea75bf7768ebf9d2ab34e" + }, + { + "page_id": "d2d188aea7f4825cbcea81ef86eca607", + "title": "Legacy PUSH AGW SDK Doc v1", + "local_file": "notion/legacy-agw-sdk-v1.md", + "changed": false, + "previous_sha256": "9e6569ef9b76d59cb411d65305d67333c6766abc2e9c80a35ae6f56f12f70916", + "sha256": "9e6569ef9b76d59cb411d65305d67333c6766abc2e9c80a35ae6f56f12f70916", + "raw_export_sha256": "9e6569ef9b76d59cb411d65305d67333c6766abc2e9c80a35ae6f56f12f70916" + }, + { + "page_id": "3d1188aea7f480ddbb4af6d0efb211e6", + "title": "AGW Address Book PC Donut", + "local_file": "notion/agw-address-book-donut-2026-09-04.md", + "changed": false, + "previous_sha256": "5c5017d6b4a58af0fa8854ef550b054c1f33d57a812ea51a16f31f7c33e79742", + "sha256": "5c5017d6b4a58af0fa8854ef550b054c1f33d57a812ea51a16f31f7c33e79742", + "raw_export_sha256": "5c5017d6b4a58af0fa8854ef550b054c1f33d57a812ea51a16f31f7c33e79742" + }, + { + "page_id": "3d1188aea7f4801f9cb3fbd9318ec536", + "title": "Agentic wallet flow updated", + "local_file": "notion/agentic-wallet-flow-2026-09-07.md", + "changed": false, + "previous_sha256": "d4a922fd1d33da5a7042f26053e8df0e496c3ccd4cb0044b0892948ac509c3a0", + "sha256": "d4a922fd1d33da5a7042f26053e8df0e496c3ccd4cb0044b0892948ac509c3a0", + "raw_export_sha256": "d4a922fd1d33da5a7042f26053e8df0e496c3ccd4cb0044b0892948ac509c3a0" + } + ], + "review_status": "Review required" +} diff --git a/plan/agw/notion/legacy-agw-sdk-v1.md b/plan/agw/notion/legacy-agw-sdk-v1.md new file mode 100644 index 00000000..da35470a --- /dev/null +++ b/plan/agw/notion/legacy-agw-sdk-v1.md @@ -0,0 +1,1097 @@ +# PUSH AGW SDK Doc - v1 + +--- + +| Commit | [`67929f2`](https://github.com/pushchain/push-agentic-wallets/commit/67929f2) on branch `pushAgenticWallet_v3` | +| --- | --- | +| SDK target | [`@pushchain/core`](https://github.com/pushchain/push-chain-sdk/tree/main/packages/core) `6.0.25` at [`bf1dbff`](https://github.com/pushchain/push-chain-sdk/commit/bf1dbff) · TypeScript · `viem ^2.27` (dependency) · `tweetnacl` (optional peer, Ed25519) · jest + `__e2e__` | +| In scope | wallet creation, funding, owner execution, mandate grant / stop / replace, reads, the agent-card → mandate compiler (O9, forward-looking) | +| Out of scope | • building, signing and submitting agent requests (**agent doc**) · + • ERC-8183 job creation, binding and settlement · + • TAP, Read State + • mandates to **SVM destinations** (URP’s allow-list is EVM-shaped: 20-byte `expectedCEA`, multicall payload) | + +Snippets are TypeScript with `viem`, which is the SDK’s own encoding library. Every encoding is plain ABI. + +### 0.1 AGW Addresses Addresses + +> note: NO Pre-define addresses deployment is done yet. Once SDK initial checks are passed, I will make those deployments post that. +> + + [`deployments/address-book-v3/ADDRESSES.md`](https://github.com/pushchain/push-agentic-wallets/blob/pushAgenticWallet_v3/deployments/address-book-v3/ADDRESSES.md). + +**The two you need.** Both are proxies; both addresses are permanent. Never address an implementation. + +| | Address | +| --- | --- | +| **Factory** | `0x2578041963f692f8b51A137A1c7ddc0c84a8226A` | +| **URP** | `0xeAd99E254ACD64219d057400cdC2A2390bC74372` | + +**Everything we deploy** + +| Key | Address | Verified | +| --- | --- | --- | +| `factoryProxy` | `0x2578041963f692f8b51A137A1c7ddc0c84a8226A` | ✅ | +| `factoryLogic` | `0x517a10C2F2E786CC8271dbD489dFE27dE8F7BE67` | ✅ | +| `walletImplementation` | `0xD7FEF338572f96edBeF89E720f1F0fF1284ec79C` | ✅ | +| `urp` (proxy) | `0xeAd99E254ACD64219d057400cdC2A2390bC74372` | ✅ | +| `urpImplementation` | `0xc95f179D3aDE283E11CF90f3F8E04BFE8534ff4F` | ✅ | +| `urpProxyAdmin` | `0xA634a0cB4F374D89B2cccbdc77300c8Ac3827BF4` | ✅ | +| `sessionValidator` | `0xF77660838Cebb65BD6357FDe71d19f97CC65E829` | ✅ | +| `sessionEngine` | `0x046B2874Fc9F920ad53A317b3cf9d3d1974466f3` | ✅ | + +**External dependencies (not deployed by this repo)** + +| Key | Address | Note | +| --- | --- | --- | +| `universalGatewayPC` | `0x00000000000000000000000000000000000000C1` | the one target a universal mandate may name | +| `universalCore` | `0x00000000000000000000000000000000000000C0` | outbound fee quotes | +| `ueaFactory` | `0x00000000000000000000000000000000000000eA` | maps external wallets → UEAs on Push. **Not** the CEA factory and not a runtime dependency | +| `universalExecutorModule` | `0x14191Ea54B4c176fCf86f51b0FAc7CB1E71Df7d7` | **no code** (`cast code` → `0x`, re-read on Donut 2026-09-18); gates `creditRevert` only, so the revert-credit path is unreachable and spend counters never decrease | +| `usv` (Ed25519 precompile) | `0xEC00000000000000000000000000000000000001` | codeless by design | +| `USDC.eth` (PRC20, example asset) | `0x7A58048036206bB898008b5bBDA85697DB1e5d66` | `SOURCE_CHAIN_NAMESPACE()` → `"eip155:11155111"` | + +#### 0.2 Contracts Details + +| Contract | Role, in one line | Source | Address on Push | +| --- | --- | --- | --- | +| `AGWFactory` | Deploys wallet clones at predictable addresses; registry of wallet → owner | [src/AGWFactory.sol](https://github.com/pushchain/push-agentic-wallets/blob/pushAgenticWallet_v3/src/AGWFactory.sol) | `0x2578041963f692f8b51A137A1c7ddc0c84a8226A` (proxy) | +| `PushAgentWallet` | Holds funds; owner door `execute`, agent door `executeWithSession`, mandate `grant` / `stop` / `stopAll` | [src/PushAgentWallet.sol](https://github.com/pushchain/push-agentic-wallets/blob/pushAgenticWallet_v3/src/PushAgentWallet.sol) | `0xD7FEF338572f96edBeF89E720f1F0fF1284ec79C` (implementation; every wallet is a clone of it) | +| `URP` | The policy: checks every agent request against the mandate’s terms, meters spend, fails closed | [src/policies/URP.sol](https://github.com/pushchain/push-agentic-wallets/blob/pushAgenticWallet_v3/src/policies/URP.sol) | `0xeAd99E254ACD64219d057400cdC2A2390bC74372` (proxy) | +| `PushSessionValidator` | Stateless signature check: secp256k1 or Ed25519 via the USV precompile | [src/validators/PushSessionValidator.sol](https://github.com/pushchain/push-agentic-wallets/blob/pushAgenticWallet_v3/src/validators/PushSessionValidator.sol) | `0xF77660838Cebb65BD6357FDe71d19f97CC65E829` | +| `SmartSession` | Session engine: stores mandates, runs URP, deletes on revoke; the wallet’s only installed validator module | [lib/smartsessions](https://github.com/pushchain/push-agentic-wallets/tree/pushAgenticWallet_v3/lib/smartsessions) | `0x046B2874Fc9F920ad53A317b3cf9d3d1974466f3` | +| `ProxyAdmin` (URP) | Upgrade authority for URP; the SDK never calls it | OpenZeppelin 5.7.0 | `0xA634a0cB4F374D89B2cccbdc77300c8Ac3827BF4` | + +Shared type and error files the SDK mirrors: + +- [src/libraries/PushWalletTypes.sol](https://github.com/pushchain/push-agentic-wallets/blob/pushAgenticWallet_v3/src/libraries/PushWalletTypes.sol) — gateway struct mirrors, selectors, `OP_HASH_DOMAIN` +- [src/interfaces/IURP.sol](https://github.com/pushchain/push-agentic-wallets/blob/pushAgenticWallet_v3/src/interfaces/IURP.sol) — `UniversalTerms`, `NativeTerms`, views, errors +- [src/libraries/PushWalletErrors.sol](https://github.com/pushchain/push-agentic-wallets/blob/pushAgenticWallet_v3/src/libraries/PushWalletErrors.sol) — wallet errors +- [src/interfaces/IPushAgentWallet.sol](https://github.com/pushchain/push-agentic-wallets/blob/pushAgenticWallet_v3/src/interfaces/IPushAgentWallet.sol) — wallet events +- [src/libraries/ExecutionLib.sol](https://github.com/pushchain/push-agentic-wallets/blob/pushAgenticWallet_v3/src/libraries/ExecutionLib.sol) — single / batch execution encoding + +#### 0.3 Docs + +- [docs/](https://github.com/pushchain/push-agentic-wallets/tree/pushAgenticWallet_v3/docs) — narrative docs + - [v3-architecture.md](https://github.com/pushchain/push-agentic-wallets/blob/pushAgenticWallet_v3/docs/v3-architecture.md) — the architecture + - [agentic_wallet_flow.md](https://github.com/pushchain/push-agentic-wallets/blob/pushAgenticWallet_v3/docs/agentic_wallet_flow.md) — cross-chain (UNIVERSAL) worked example + - [push_native_agentic_wallet_flow.md](https://github.com/pushchain/push-agentic-wallets/blob/pushAgenticWallet_v3/docs/push_native_agentic_wallet_flow.md) — Push-side (NATIVE) worked example +- [deployments/address-book-v3/](https://github.com/pushchain/push-agentic-wallets/tree/pushAgenticWallet_v3/deployments/address-book-v3) — addresses, live checks, what changed from v2 +- [README.md](https://github.com/pushchain/push-agentic-wallets/blob/pushAgenticWallet_v3/README.md) · [CLAUDE.md](https://github.com/pushchain/push-agentic-wallets/blob/pushAgenticWallet_v3/CLAUDE.md) — conventions and invariants +- [test/Base.t.sol](https://github.com/pushchain/push-agentic-wallets/blob/pushAgenticWallet_v3/test/Base.t.sol) — the canonical session / envelope / signature builders; generate SDK test vectors from these +- [push-chain-sdk/plan/read-state-sdk-spec.md](https://github.com/pushchain/push-chain-sdk/blob/main/plan/read-state-sdk-spec.md) — the SDK team’s prior contract→SDK spec; this doc follows its conventions +- [AGW-SDK-v1-agent.md](./AGW-SDK-v1-agent.md) — the agent half +- [05-universal-marketplace-startjob.md](./05-universal-marketplace-startjob.md) · [SDK_HELPER.md](./SDK_HELPER.md) — the marketplace vision and card design O9 compiles from (both work in progress) + +--- + +## 1 · Mental models for AGW + +### 1.1 Actors + +1. **Wallet_Owner** — any `UniversalSigner` (Sepolia, Solana or Push-native). + 1. On chain the owner is `client.universal.account`: the user’s UEA for external-origin signers, the EOA itself for Push-native. + 2. It is `msg.sender` of `deployWallet` and is recorded forever. Deploys, funds, grants, stops, uses the owner door; every write goes through `client.universal.sendTransaction`, so UEA routing and gas abstraction apply unchanged. +2. **Agent** — + 1. holds a session key (secp256k1 address or Ed25519 pubkey) that signs the op hash, plus a funded Push account that submits `executeWithSession` and pays that tx’s gas. + 2. The two may be the same key. The door is permissionless, so any funded account can submit an agent-signed request; v1 has the Agent submit its own. + +### 1.2 The system + +- One wallet = one EIP-1167 clone with 40 bytes of immutable args (`owner`, `factory`). Owner is fixed forever. +- **Owner door** + - `execute(mode, executionCalldata)`: owner only; no policy is consulted. Single or batch. +- **Agent door** + - `executeWithSession(...)`: anyone may call; authority is the signature + nonce + op hash, then URP. Single call only. +- **Mandate** = one SmartSession `Session`: an agent key + 1..8 `(target, selector)` actions, each with exactly one policy, URP, whose `initData` carries the terms. +- Mandates are immutable. + - **For now changing mandate means:** + - stop old mandate + - grant new mandate + - Revocation is immediate and always succeeds. +- The wallet’s balance is the hard ceiling: nothing the agent does can move more than the wallet holds. + +### 1.3 The three important ids + +```solidity +permissionId = keccak256(abi.encode(sessionValidator, sessionValidatorInitData, salt)) +// salt = bytes32(uint256(wallet.grantNonce())) — LEFT-padded, i.e. nonce 3 is +// 0x0000…0003, never 0x0300…0000. The wallet overwrites whatever salt you sent. + +actionId = keccak256(abi.encodePacked(target, selector)) + +configId = keccak256(abi.encodePacked(wallet, keccak256(abi.encodePacked(permissionId, actionId)))) +``` + +**`permissionId` — the mandate.** + +- One per `grantMandate` call. The id an owner revokes and an agent signs against. +- Derived from the agent key config + the wallet’s grant nonce → identical terms granted twice yield different ids; a revoked id never recurs. +- Used in: agent signature prefix · op hash field 5 · `stopMandate` · `isPermissionEnabled` · `getSessionValidatorAndConfig` · `getEnabledActions` · `MandateGranted` / `MandateRevoked` / `MandateActionAuthorized` · `SessionCreated` / `SessionRemoved`. + +**`actionId` — one `(target, selector)` pair.** + +- Global, not per-wallet or per-mandate: `(Aave, supply)` is the same actionId for every user. +- Says which function a request hits; carries no terms. +- Used in: input to `configId` · returned by `getEnabledActions` · argument to `getActionPolicies`. + +**`configId` — one action’s URP terms, in one mandate, on one wallet.** + +- The row URP reads caps and spend counters from. Native mandate with 3 actions → 3 configIds; universal → exactly 1. +- Used in: `urp.getMode` / `getConfig` / `getNativeConfig` / `assertSpent` · `URPPolicySet` / `OutboundMetered` / `NativeCallMetered` events. + +⚠️ `abi.encode` (padded) at level 1, `abi.encodePacked` (tight) at levels 2 and 3. Using one throughout derives every `configId` wrong and reads zeros back from URP. + +### 1.4 SDK object model + +Design rules, mirroring the shipped `universal.*` family: + +- One namespace on the client: `client.agentWallet.*`. Every write has a `prepare*` twin that returns `MultiCall[]`, so callers batch it into one `sendTransaction({ data: MultiCall[] })` signature. +- The SDK computes what the dev cannot guess: chain string, `expectedCEA`, ids, offsets, caps. The dev supplies wallet, agent key, terms, principal. +- Pure encoders and id derivations live under `PushChain.utils.agentWallet.*`; addresses, selectors and limits under `PushChain.CONSTANTS.AGENT_WALLET[network]`. +- Errors are typed classes with a `code`, `AgentWalletError` base (the `PC20Error` pattern). On-chain custom errors are decoded from the AGW ABIs and re-thrown as `AgentWalletRevertError { name, args }`. +- Progress family `AGW-TX-1xx`, same grammar as `SEND-TX`. + +```tsx +// ── method family ──────────────────────────────────────────────────────── +client.agentWallet.predict(index?) // → { address, deployed } (owner = client.universal.account) +client.agentWallet.deploy(label) // → { address, index, txHash } +client.agentWallet.list() // → Address[] walletCount + predictWallet(0..n-1) +client.agentWallet.wallet(address) // → Wallet handle + +wallet.balances(assets?) // → { pc, tokens } +wallet.execute(calls, { value? }) // owner door, single or batch +wallet.approveGateway(asset, amount) // Push-side allowance for universal mandates (see O2) +wallet.grant(terms) // → { permissionId, txHash } +wallet.stop(permissionId) · wallet.stopAll() +wallet.replace(oldId, expectedSpent, terms) // assert → stop → grant, one owner-door batch +wallet.mandates() · wallet.mandate(permissionId) // → Mandate (read model) +wallet.nonce(lane) + +wallet.prepareDeploy / prepareApproveGateway / prepareGrant / prepareStop / prepareReplace // → MultiCall[] + +PushChain.utils.agentWallet.compile(card, userInput, chainContext) // agent card → Session (O9); pure, deterministic + +// agent surface — client.agentWallet.request(...), AgentSigner, AgentRequest — see the AGENT DOC + +PushChain.utils.agentWallet.{ permissionId, actionId, configId, envelope, encodeSession, encodeNativeTerms, encodeUniversalTerms, encodeSingle, encodeBatch } +PushChain.CONSTANTS.AGENT_WALLET[PUSH_NETWORK.TESTNET_DONUT] = { FACTORY, URP, SESSION_VALIDATOR, SESSION_ENGINE, SEND_OUTBOUND_SELECTOR, OP_HASH_DOMAIN, MAX_NATIVE_ACTIONS, MAX_PINS, MAX_ALLOWED_CALLS, MAX_ACTIONS_PER_REQUEST } +``` + +#### OWNER SIDE TYPES + +```tsx +// ── owner side types ───────────────────────────────────────────────────── +type Call = { target: Address; value: bigint; data: Hex }; + +type AgentKey = { scheme: 0; address: Address } | { scheme: 1; pubKey: Hex /* 32 bytes */ }; + +// THE CALLER NEVER STATES A MANDATE KIND. It states a chain; the wallet and URP derive the rest. +// The two shapes are told apart by `chain`: omitted (or this chain) → Push-side; a foreign chain → outbound. +type MandateTerms = NativeMandateTerms | UniversalMandateTerms; + +type NativeMandateTerms = { + chain?: never; // omit it; SDK emits `eip155:` of the connected Push chain + agent: AgentKey; + validUntil: number; // unix seconds; 2^48-1 = never + actions: NativeAction[]; // 1..8, unique (target, selector) +}; +type NativeAction = { + target: Address; + selector: Hex; // 4 bytes; 0xFFFFFFFF = value-only (empty calldata) + maxValuePerCall: bigint; // PC + maxValueTotal: bigint; // PC; 2^256-1 = unlimited + maxCalls: number; // 0 = unlimited + pins: { offset: number; expected: Hex }[]; // ≤ 8 + amount?: { offset: number; maxPerCall: bigint; maxTotal: bigint }; // one metered uint256 arg +}; + +type UniversalMandateTerms = { + chain: ForeignChain; // destination, e.g. CHAIN.ETHEREUM_SEPOLIA. Required, and the ONLY kind signal. + // `ForeignChain` = Exclude — EVM only in v1 + agent: AgentKey; + validUntil: number; + asset: Address; // PRC20 on Push; SDK asserts asset.SOURCE_CHAIN_NAMESPACE() === chain + expectedCEA?: Address; // omit it — SDK derives it. See "expectedCEA, defined once" below. + maxAmountPerCall: bigint; + maxAmountTotal: bigint; // 2^256-1 = unlimited + maxPCPerCall: bigint; // PC attached per outbound (protocol fee + gas swap) + allowedCalls: AllowedCall[]; // 1..32 +}; +type AllowedCall = { target: Address; selector: Hex; beneficiaryOffset: number; hasBeneficiary: boolean; maxValue: bigint }; + +// read model, built from views + events. `mode` here is REPORTED, not chosen: it is what +// urp.getMode(configId, wallet) decoded. The only place the two names appear in the SDK. +type Mandate = { + wallet: Address; permissionId: Hex; enabled: boolean; + mode: 'NATIVE' | 'UNIVERSAL'; chain: string; chainHash: Hex; + agent: AgentKey; validUntil: number; + actions: { configId: Hex; target: Address; selector: Hex; terms: NativeAction | UniversalMandateTerms; spent: Spent }[]; +}; +type Spent = { spent: bigint } | { valueSpent: bigint; amountSpent: bigint; callsUsed: number }; +``` + +--- + +## 2 · Operations + +The following operations are part of WALLET-OWNER Side of the SDK + +1. O1 · Predict and deploy a wallet +2. O2 · Fund +3. O3 · Owner execute +4. O4 · Build a mandate for Push-side actions (derives NATIVE) +5. O5 · Build a mandate for a foreign chain (derives UNIVERSAL) +6. O6 · Pre-flight and grant +7. O7 · Stop +8. O8 · Replace a mandate atomically (assert → stop → grant) +9. *O9 · **Additional:** Compile an agent card into a mandate* + +--- + +#### SetUP + +```tsx +import { encodeAbiParameters, encodePacked, encodeFunctionData, keccak256, concat, pad, toHex } from 'viem'; +import { PushChain, CHAIN, getCEAAddress, CEA_FACTORY_ADDRESSES, VAULT_ADDRESSES, UEA_MULTICALL_SELECTOR } from '@pushchain/core'; +const { encodeTxData } = PushChain.utils.helpers; +const client = await PushChain.initialize(universalSigner, { network: PushChain.CONSTANTS.PUSH_NETWORK.TESTNET_DONUT }); + +const FACTORY = '0x2578041963f692f8b51A137A1c7ddc0c84a8226A'; +const URP = '0xeAd99E254ACD64219d057400cdC2A2390bC74372'; +const VALIDATOR = '0xF77660838Cebb65BD6357FDe71d19f97CC65E829'; +const ENGINE = '0x046B2874Fc9F920ad53A317b3cf9d3d1974466f3'; +const GATEWAY = '0x00000000000000000000000000000000000000C1'; +const CORE = '0x00000000000000000000000000000000000000C0'; + +const MODE_SINGLE = '0x0000000000000000000000000000000000000000000000000000000000000000'; // callType 0x00, execType 0x00 +const MODE_BATCH = '0x0100000000000000000000000000000000000000000000000000000000000000'; // callType 0x01, execType 0x00 +const SEND_OUTBOUND_SELECTOR = '0x77b86bec'; +const MULTICALL_SELECTOR = UEA_MULTICALL_SELECTOR; // '0x2cc2842d' = bytes4(keccak256("UEA_MULTICALL")), already in the SDK +const OP_HASH_DOMAIN = '0xee007baac915cb5cecf254fbc38928446424413e2083e43f2155c71b8bf768fe'; // keccak256("PushAgentWallet.Op.v3") +const VALUE_ONLY = '0xFFFFFFFF'; +const UNLIMITED = 2n ** 256n - 1n; +const NEVER = 2 ** 48 - 1; +``` + +### Owner operations + +#### O1 · Predict and deploy a wallet + +```tsx +const owner = client.universal.account; // UEA or Push EOA +const index = await factory.read.walletCount([owner]); // next index +const [predicted, deployed] = await factory.read.predictWallet([owner, index]); + +const data = PushChain.utils.helpers.encodeTxData({ abi: factoryAbi, functionName: 'deployWallet', args: ['my first wallet'] }); +const res = await client.universal.sendTransaction({ to: FACTORY, data }); // msg.sender = owner +// event WalletDeployed(owner indexed, index indexed, wallet indexed, label) +``` + +1. Caller of `deployWallet` **is** the owner; there is no owner parameter. For an external-origin user the caller is their UEA, so the UEA owns the wallet. + + read about ownership structure of AGW here if needed → [2. Rule 2 — Ownership is a strict, single-parent chain, rooted in the user's EOA](https://app.notion.com/p/2-Rule-2-Ownership-is-a-strict-single-parent-chain-rooted-in-the-user-s-EOA-3b9188aea7f48012b934e3598ec929a5?pvs=21) + +2. Local address mirror (for offline prediction): `salt = keccak256(abi.encode(owner, uint96(index)))`, `args = abi.encodePacked(owner, FACTORY)`, OZ `Clones.predictDeterministicAddressWithImmutableArgs(impl, args, salt, FACTORY)`. +3. Verify the mirror against `predictWallet` before showing a funding address. (`abi.encode` pads `uint96` to a full word, so encoding the index as `uint256` gives the same salt for every reachable index — `IndexOutOfRange` caps it far below 2^96.) +4. Counterfactual funding is supported: fund `predicted` before deploying. `predictWallet` reverts `IndexOutOfRange` for `index > walletCount`; never fund beyond that. +5. `label` is emitted only, never stored. + +#### O2 · Fund + +```tsx +await owner.sendTransaction({ to: wallet, value: pc }); // wallet has receive() +await prc20.write.transfer([wallet, amount]); // any PRC20 / ERC-20 +const pcBal = await client.getBalance({ address: wallet }); +const tokBal = await prc20.read.balanceOf([wallet]); +``` + +- The wallet needs **PC** for: `value` on native actions; `value` on every universal outbound (protocol fee + gas swap, capped by `maxPCPerCall`). The agent’s tx gas is paid by the submitter, never by the wallet. +- **Universal mandates need a Push-side allowance.** `sendUniversalTxOutbound` pulls the PRC20 with `transferFrom(msg.sender = wallet, …)` before burning (`UniversalGatewayPC.sol:134, 288`). Without it every agent request with `amount > 0` reverts inside the gateway. Owner sets it through the owner door, once, sized to the mandate: + +```tsx +// wallet.approveGateway(asset, maxAmountTotal) ≡ owner-door batch: +const calls = [ + { target: asset, value: 0n, data: encodeTxData({ abi: ERC20_EVM, functionName: 'approve', args: [GATEWAY, 0n] }) }, // reset first (USDT-style tokens) + { target: asset, value: 0n, data: encodeTxData({ abi: ERC20_EVM, functionName: 'approve', args: [GATEWAY, maxAmountTotal] }) }, +]; +await wallet.execute(calls); // or prepareApproveGateway() → MultiCall[] batched with the grant +``` + +- The allowance is not a policy: it is the wallet’s spending ceiling at the gateway, independent of URP’s caps. Reset it to 0 on `stop` if the mandate was the only reason for it. +- Universal quote (the SDK’s outbound path already does this; reuse `sizeOutboundGas` / `quoteMaxPCForGasCapFromNativeValue`): + +```tsx +const [gasToken, gasFee, protocolFee, gasPrice, chainNamespace, gasLimitUsed] = + await core.read.getOutboundTxGasAndFees([asset, gasLimit]); // gasLimit 0 = chain default +// gateway requires msg.value >= protocolFee; the remainder is swapped to gasToken; unused PC refunds to the wallet +``` + +#### O3 · Owner execute + +```tsx +const single = encodePacked(['address', 'uint256', 'bytes'], [target, value, data]); +await wallet.write.execute([MODE_SINGLE, single], { value }); + +const batch = encodeAbiParameters( + [{ type: 'tuple[]', components: [{ type: 'address', name: 'target' }, { type: 'uint256', name: 'value' }, { type: 'bytes', name: 'callData' }] }], + [calls], +); +await wallet.write.execute([MODE_BATCH, batch]); +// event OwnerExecuted(mode indexed, keccak256(executionCalldata)) +``` + +- SINGLE is `abi.encodePacked` (52-byte header), +- BATCH is `abi.encode(Execution[])`. Not interchangeable. +- Target reverts bubble verbatim. Delegatecall / static / try modes → `UnsupportedExecutionMode`. +- This is the only withdrawal path. +- It also carries self-calls to `grantMandate` / `stopMandate` / `stopAll` (see O8). + +#### O4 · Build a mandate for Push-side actions (derives NATIVE) + +```tsx +const chain = `eip155:${chainId}`; // "eip155:42101" on Donut +// assert: keccak256(toHex(chain)) === await urp.read.pushChainHash() + +const NATIVE_TERMS = { type: 'tuple', components: [ + { type: 'uint48', name: 'validUntil' }, { type: 'address', name: 'target' }, { type: 'bytes4', name: 'selector' }, + { type: 'uint256', name: 'maxValuePerCall' }, { type: 'uint256', name: 'maxValueTotal' }, + { type: 'tuple', name: 'amount', components: [{ type: 'bool', name: 'enabled' }, { type: 'uint16', name: 'offset' }, { type: 'uint256', name: 'maxPerCall' }, { type: 'uint256', name: 'maxTotal' }] }, + { type: 'uint32', name: 'maxCalls' }, + { type: 'tuple[]', name: 'pins', components: [{ type: 'uint16', name: 'offset' }, { type: 'bytes32', name: 'expected' }] }, +]}; + +function nativeAction(a: NativeAction, validUntil: number) { + const body = encodeAbiParameters([NATIVE_TERMS], [{ + validUntil, target: a.target, selector: a.selector, + maxValuePerCall: a.maxValuePerCall, maxValueTotal: a.maxValueTotal, + amount: a.amount ? { enabled: true, ...a.amount } : { enabled: false, offset: 0, maxPerCall: 0n, maxTotal: 0n }, + maxCalls: a.maxCalls, pins: a.pins, + }]); + const initData = encodeAbiParameters([{ type: 'string' }, { type: 'bytes' }], [chain, body]); // the envelope + return { actionTargetSelector: a.selector, actionTarget: a.target, actionPolicies: [{ policy: URP, initData }] }; +} +``` + +- One `NativeTerms` per action. `terms.target` / `terms.selector` must equal the action’s; URP asserts both at runtime (N4, N5). +- **Offsets** are absolute from byte 0 of the calldata, selector included: static argument `i` sits at `4 + 32*i`. Only static-position arguments can be pinned or metered; a role on a dynamic argument (`bytes`, `string`, arrays) is a compile error in the SDK. +- `pins[].expected` is the full 32-byte word: an address is left-padded (`pad(address, { size: 32 })`). +- Value-only action: `selector = 0xFFFFFFFF`, agent sends empty calldata; pins and amount rule must be absent. +- Limits: 1..8 actions; ≤ 8 pins per action; no duplicate `(target, selector)`. +- Forbidden targets: `0x0`, `0x1`, the wallet, engine, URP, validator, factory → `ForbiddenActionTarget`; the gateway → `MandateTypeMismatch`. Forbidden selectors `0x00000001`, `0x00000002`. +- `maxCalls = 0` unlimited; `maxValueTotal = UNLIMITED`; `amount.maxTotal = UNLIMITED`. + +### O5 · Mandates + +#### Mandates from Smart Contract POV + +```solidity +function grantMandate(Session calldata session) external returns (bytes32 permissionId); +// selector 0xa3e13323 · onlyOwnerOrSelf + +struct Session { + ISessionValidator sessionValidator; // fixed: PushSessionValidator + bytes sessionValidatorInitData; // abi.encode(uint8 scheme, bytes key) — the agent key + bytes32 salt; // IGNORED — the wallet overwrites it with its grant nonce + PolicyData[] userOpPolicies; // must be empty + ERC7739Data erc7739Policies; // must be empty (both inner arrays) + ActionData[] actions; // 1..8 Push-side · exactly 1 outbound + bool permitERC4337Paymaster;// must be false +} + +struct ActionData { + bytes4 actionTargetSelector; // ⚠ SELECTOR FIRST — declaration order, not (target, selector) + address actionTarget; + PolicyData[] actionPolicies; // exactly one entry, and it must be URP +} + +struct PolicyData { + address policy; // fixed: URP + bytes initData; // abi.encode(string chain, bytes body) — "the envelope" +} + +``` + +| Field | What it is | Who sets it | +| --- | --- | --- | +| `sessionValidator` | the one validator this system accepts; anything else → `MalformedSessionShape` | fixed constant | +| `sessionValidatorInitData` | **the agent's key.** `abi.encode(uint8 scheme, bytes key)` — scheme 0 = 20-byte address, scheme 1 = 32-byte Ed25519 pubkey. Part of `permissionId`, so it can never be swapped | SDK, from the agent | +| `salt` | send `bytes32(0)`. The wallet replaces it with `grantNonce`, which is what makes every grant a distinct `permissionId` | wallet | +| `userOpPolicies` · `erc7739Policies` · `permitERC4337Paymaster` | dead surface for this wallet; non-empty / true → `MalformedSessionShape` | empty / empty / false | +| `actions[]` | **what the agent may call.** One entry per `(target, selector)` pair | SDK, from the terms | +| `actions[].actionPolicies` | exactly `[{ policy: URP, initData: envelope }]`. One policy, and it must be URP | SDK | +| `initData` (the envelope) | `abi.encode(string chain, bytes body)`. **`chain` decides the rulebook** — this chain → Push-side, any other → outbound. `body` is the terms | SDK | + +The envelope's `body` is one of two wire structs, matching the rulebook the chain derived: + +- NATIVE TERMS - only for agentic workflow exec on Push Chain +- Universal Terms - for agentic workflow on external chains + +```solidity +struct NativeTerms { // Push-side — one per action + uint48 validUntil; // unix seconds; type(uint48).max = never + address target; // must equal this action's actionTarget + bytes4 selector; // must equal this action's actionTargetSelector + uint256 maxValuePerCall; // PC attachable per call + uint256 maxValueTotal; // PC lifetime; type(uint256).max = unlimited + AmountRule amount; // optional metering of ONE uint256 argument + uint32 maxCalls; // 0 = unlimited + ArgPin[] pins; // 0..8 pinned argument words +} + +struct AmountRule { bool enabled; uint16 offset; uint256 maxPerCall; uint256 maxTotal; } +struct ArgPin { uint16 offset; bytes32 expected; } + +struct UniversalTerms { // outbound — exactly one, for the gateway action + uint48 validUntil; + address expectedCEA; // the wallet's account on the destination chain + address asset; // the one permitted PRC20 on Push + uint256 maxAmountPerCall; // bridged amount per call + uint256 maxAmountTotal; // bridged lifetime; max = unlimited + uint256 maxPCPerCall; // PC attached per outbound (protocol fee + gas swap) + AllowedCall[] allowedCalls; // 1..32 destination-chain calls the agent may make +} + +struct AllowedCall { + address target; // destination-chain contract + bytes4 selector; // destination-chain function + uint16 beneficiaryOffset; // where the beneficiary word sits in the INNER calldata + bool hasBeneficiary; // false for calls with no beneficiary argument + uint256 maxValue; // per-entry native ceiling, DESTINATION-chain units +} + +``` + +**1. Build each action (derives NATIVE)** + +couple of notes here: + +1. on chain id + +```tsx +const chain = `eip155:${chainId}`; +// "eip155:42101" on Donut +// assert: keccak256(toHex(chain)) === await urp.read.pushChainHash() +``` + +- must Byte-exact or nothing. +- `"EIP155:42101"`, `"eip155:042101"` and a leading space all hash to not-Push, derive the *outbound* rulebook, and are then refused against the targets with `MandateTypeMismatch`. +- The contracts do not parse or normalise — the hash comparison is the whole rule. + +```tsx +const NATIVE_TERMS = { type: 'tuple', components: [ + { type: 'uint48', name: 'validUntil' }, { type: 'address', name: 'target' }, { type: 'bytes4', name: 'selector' }, + { type: 'uint256', name: 'maxValuePerCall' }, { type: 'uint256', name: 'maxValueTotal' }, + { type: 'tuple', name: 'amount', components: [{ type: 'bool', name: 'enabled' }, { type: 'uint16', name: 'offset' }, { type: 'uint256', name: 'maxPerCall' }, { type: 'uint256', name: 'maxTotal' }] }, + { type: 'uint32', name: 'maxCalls' }, + { type: 'tuple[]', name: 'pins', components: [{ type: 'uint16', name: 'offset' }, { type: 'bytes32', name: 'expected' }] }, +]}; + +function nativeAction(a: NativeAction, validUntil: number) { + const body = encodeAbiParameters([NATIVE_TERMS], [{ + validUntil, target: a.target, selector: a.selector, + maxValuePerCall: a.maxValuePerCall, maxValueTotal: a.maxValueTotal, + amount: a.amount ? { enabled: true, ...a.amount } : { enabled: false, offset: 0, maxPerCall: 0n, maxTotal: 0n }, + maxCalls: a.maxCalls, pins: a.pins, + }]); + const initData = encodeAbiParameters([{ type: 'string' }, { type: 'bytes' }], [chain, body]); // the envelope + return { actionTargetSelector: a.selector, actionTarget: a.target, actionPolicies: [{ policy: URP, initData }] }; +} + +const actions = terms.actions.map(a => nativeAction(a, validUntil)); // 1..8 + +``` + +#### **Rules for Native Action** + +| Rule | Violation | +| --- | --- | +| 1..8 actions | `TooManyActions(count)` | +| no duplicate `(target, selector)` | `DuplicateAction(target, selector)` | +| every action names the same chain | `InconsistentChain(actionIndex)` | +| `terms.target` / `terms.selector` equal the action's | passes at grant, fails every request at N4 / N5 | + +**Targets and selectors** + +| Forbidden | Why | Error | +| --- | --- | --- | +| `0x0`, `0x1`, the wallet, engine, URP, validator, factory | an agent reaching these could re-grant itself | `ForbiddenActionTarget(target)` | +| the gateway `0x…C1` | that is an outbound call, not a Push-side one | `MandateTypeMismatch(derived, i, target)` | +| selectors `0x00000001`, `0x00000002` | engine wildcard sentinels | `ForbiddenActionSelector(selector)` | + +**Arguments — pins and metering** + +- Offsets are **absolute from byte 0 of the calldata, selector included**: static argument `i` sits at `4 + 32*i`. +- Only static-position arguments can be pinned or metered. A role on a dynamic argument (`bytes`, `string`, arrays) is a compile error in the SDK — the offset would point at a length word, not the value. +- `pins[].expected` is the **full 32-byte word**. An address must be left-padded (`pad(address, { size: 32 })`); a dirty high half is a mismatch, deliberately. +- `amount` meters **one** `uint256` argument. A function with two value-moving arguments has one bounded and one free. + +**Value-only actions** (a bare PC transfer) + +- `selector = 0xFFFFFFFF`, and the agent must send **exactly empty** calldata. +- `pins` and `amount` must be absent — `ValueOnlyWithPins` / `ValueOnlyWithAmountRule` at init. +- A no-argument function like `unstake()` still carries its four bytes and is a normal selector action, not this. + +**Defaults** + +`maxCalls = 0` unlimited · `maxValueTotal = UNLIMITED` unlimited · `amount.maxTotal = UNLIMITED` unlimited · `validUntil = NEVER` for no expiry (but zero and past are refused with `InvalidExpiry`). + +**2. Build each action (derives Universal)** + +**couple of notes** + +1. The chain string and the asset + + ```tsx + const chain = terms.chain; // CHAIN.ETHEREUM_SEPOLIA === 'eip155:11155111' + const assetChain = await prc20.read.SOURCE_CHAIN_NAMESPACE(); // add to the PRC20 ABI + if (assetChain !== chain) throw new AssetChainMismatchError(chain, assetChain); + ``` + + - Read the chain string **from the asset**, never type it. \ + - At grant URP asks the same PRC20 the same question and refuses on a mismatch (`ChainMismatch`) or an asset that cannot answer (`InvalidAsset`). + - That single check is what makes the declared chain true for the mandate's whole life. + +b. on **`*expectedCEA()`**:* + +```tsx +const { cea: expectedCEA } = await getCEAAddress(wallet, chain); +// CEAFactory.getCEAForPushAccount(wallet) +``` + +- *the wallet's account on the destination chain. The AGW exists only on Push, so bridged funds land in its mirror account over there, and that account runs the multicall. URP records it and every inner call must name it as the beneficiary, which is what keeps the output of the work coming back to the user.* +- Derived from the **AGW address**, not the owner's UEA — the AGW is `msg.sender` of `sendUniversalTxOutbound`, so the gateway resolves the CEA from the wallet. Returned whether or not it is deployed yet; the Vault deploys it on first delivery. + +```solidity +const UNIVERSAL_TERMS = { type: 'tuple', components: [ + { type: 'uint48', name: 'validUntil' }, { type: 'address', name: 'expectedCEA' }, { type: 'address', name: 'asset' }, + { type: 'uint256', name: 'maxAmountPerCall' }, { type: 'uint256', name: 'maxAmountTotal' }, { type: 'uint256', name: 'maxPCPerCall' }, + { type: 'tuple[]', name: 'allowedCalls', components: [ + { type: 'address', name: 'target' }, { type: 'bytes4', name: 'selector' }, { type: 'uint16', name: 'beneficiaryOffset' }, + { type: 'bool', name: 'hasBeneficiary' }, { type: 'uint256', name: 'maxValue' } ] }, +]}; + +const body = encodeAbiParameters([UNIVERSAL_TERMS], [{ validUntil, expectedCEA, asset, maxAmountPerCall, maxAmountTotal, maxPCPerCall, allowedCalls }]); +const initData = encodeAbiParameters([{ type: 'string' }, { type: 'bytes' }], [chain, body]); +const action = { actionTargetSelector: SEND_OUTBOUND_SELECTOR, actionTarget: GATEWAY, actionPolicies: [{ policy: URP, initData }] }; +const actions = [action]; // exactly one, always + +``` + +#### **Rules** + +| Rule | Violation | +| --- | --- | +| exactly one action | `MalformedSessionShape` | +| it must be `(GATEWAY, 0x77b86bec)` | `MandateTypeMismatch(derived, 0, target)` | +| `asset` non-zero, has code, answers `SOURCE_CHAIN_NAMESPACE()` | `InvalidConfigField` / `InvalidAsset` | +| `expectedCEA` non-zero | `InvalidConfigField` | +| `validUntil` non-zero and future | `InvalidExpiry` | + +**The allow-list** — what the agent may do on the far side + +- 1..32 entries; 0 or more than 32 → `AllowListOutOfRange`. +- `beneficiaryOffset` is absolute from byte 0 of the **inner destination-chain calldata**, selector included (first argument = 4) — not the Push-side calldata. +- `hasBeneficiary: false` for a call with no beneficiary argument; the offset is then ignored. +- `maxValue` is in **destination-chain native units** (ETH on Sepolia), never Push-side PC. Conflating the two is a real bug this design once carried. `0` = non-payable. + +**Two budgets, not one** + +| Cap | Denominated in | Bounds | +| --- | --- | --- | +| `maxAmountPerCall` / `maxAmountTotal` | the PRC20 asset | how much the agent may bridge | +| `maxPCPerCall` | native PC | protocol fee + gas swap per outbound | +| `allowedCalls[].maxValue` | destination-chain native | value attached to one inner call | + +`maxPCPerCall` has **no lifetime counterpart** — it is per-call only, so the wallet's PC balance is the real ceiling on total gas spend. See O2. + +**Scope limit** + +Destination must be EVM in v1: `expectedCEA` is a 20-byte address and URP's gate 12 requires the EVM multicall payload. Reject `CHAIN.SOLANA_*` client-side. + +--- + +#### **O6 · Grant the mandate** + +Once we create mandate, then we wraps them in the `Session` shape the wallet enforces, checks it off-chain, and sends it. + +the following are the breakdown of steps post that. + +#### **O6.1 · Assemble the Session** + +```tsx +const keyConfig = encodeAbiParameters([{ type: 'uint8' }, { type: 'bytes' }], + agent.scheme === 0 ? [0, agent.address] : [1, agent.pubKey]); // 20 bytes / 32 bytes + +const session = { + sessionValidator: VALIDATOR, // fixed + sessionValidatorInitData: keyConfig, + salt: '0x' + '00'.repeat(32), // ignored; wallet overwrites with grantNonce + userOpPolicies: [], // must be empty + erc7739Policies: { allowedERC7739Content: [], erc1271Policies: [] }, // must be empty + actions, // from O4 or O5 + permitERC4337Paymaster: false, // must be false +}; +``` + +Four fields are not yours to choose: `sessionValidator` is the one validator this wallet accepts, and the other three are dead surface — anything else is `MalformedSessionShape`. `salt` is overwritten, so send zero. + +#### **O6.2 · Pre-flight — three checks, in this order** + +```tsx +// 1 · the agent key. THREE-VALUED: true | false | revert. It decodes before it checks, +// so a blob that is not abi.encode(uint8, bytes) reverts. A revert means invalid. +const keyOk = await validator.read.validateConfig([keyConfig]).catch(() => false); +if (!keyOk) throw new InvalidMandateTermsError('BAD_AGENT_KEY', …); + +// 2 · predict the permissionId +const grantNonce = await wallet.read.grantNonce(); +const predictedId = keccak256(encodeAbiParameters([{ type: 'address' }, { type: 'bytes' }, { type: 'bytes32' }], + [VALIDATOR, keyConfig, pad(toHex(grantNonce), { size: 32 })])); + +// 3 · dry-run the real call; the returned id must equal the predicted one +const { result: permissionId } = await wallet.simulate.grantMandate([session], { account: owner }); +if (permissionId !== predictedId) throw new InvalidMandateTermsError('GRANT_NONCE_STALE', …); +``` + +| Check | Prevents | +| --- | --- | +| `validateConfig` | a 19-byte key that grants fine and makes **every** agent request fail forever | +| predict + compare | a stale `grantNonce`, and any disagreement between your derivation and the engine's | +| `simulate` | every shape and init error in §4.3 and §4.4, before the user signs | + +**Why predict the id.** The agent cannot act without it, so you need it before the grant lands: to show the mandate id on the confirmation screen, to store it against the terms, and to reference it downstream in the same batch. `grantNonce` is **0 on a freshly deployed wallet**, so a UEA multicall that deploys and grants in one signature can still compute it up front. + +#### **O6.3 · Send** + +```tsx +const data = encodeTxData({ abi: walletAbi, functionName: 'grantMandate', args: [session] }); + +// A · on its own +await client.universal.sendTransaction({ to: wallet, data }); + +// B · one signature, cross-chain mandate: gateway allowance + grant together +await client.universal.sendTransaction({ to: wallet, data: [ + ...wallet.prepareApproveGateway(asset, maxAmountTotal), // O2 + { to: wallet, value: 0n, data }, +]}); +``` + +`msg.sender` must be the owner. Through `client.universal.sendTransaction` that is `client.universal.account` — the UEA for an external-origin user, the EOA for a Push-native one. + +#### **O6.4 · What you get back** + +| Event | Emitter | Carries | +| --- | --- | --- | +| `MandateGranted(permissionId indexed, uint8 mandateType, bytes32 chainHash indexed, string chain)` | wallet | the id, and the rulebook the contracts **derived** — read it back rather than assuming | +| `SessionCreated(permissionId, account)` | engine | the mandate is live | +| `URPPolicySet(configId indexed, multiplexer indexed, account indexed, uint8 mode, bytes32 chainHash)` | URP | one per action — the `configId`s you read spend counters from | + +Store `(wallet, permissionId, terms, chain)`. The agent needs `permissionId`; you need the terms to render remaining budget later. + +--- + +#### O7 · Replace a mandate atomically (assert → stop → grant) + +**Note: As per current structure:** + +- **A mandate cannot be modified.** +- There is no `updateMandate`, no setter on URP, and no path that rewrites a live config — `initializeWithMultiplexer` refuses re-initialisation outright (`AlreadyInitialized`). +- This is ACTIVE R&D TASK , see here 👉 [**Problem: why we cannot MODIFY the mandate**](https://app.notion.com/p/Problem-why-we-cannot-MODIFY-the-mandate-3dc188aea7f48058a79aecfa00453ee7?pvs=21) + +**so how we change a mandate?** + +A change is therefore always **stop the old one, grant a new one**, and the new mandate is a genuinely different object: + +- New `permissionId` — the wallet's `grantNonce` moves on every grant, so ids never recur. +- New `configId`s — every downstream key the SDK cached is stale. +- **Spend counters restart at zero.** The old mandate's `spent` / `valueSpent` / `callsUsed` do not carry over. A user who has spent 400 of a 500 cap and "raises the cap to 800" is granting a fresh 800, not adding 300. +- Every banked signed request against the old id dies instantly, because `permissionId` is field 5 of the op hash. + + > THIS COULD CHANGE AFTER R&D TASK IS DONE and WE HAVE A SOLUTION/DECISION on how to edit mandates with JOBs. + > + +```tsx +// 1 · freeze the numbers the new terms were computed from +const assertCall = mandate.mode === 'UNIVERSAL' + ? { target: URP, value: 0n, callData: encodeFunctionData({ abi: urpAbi, functionName: 'assertSpent', + args: [configId, wallet, spent] }) } // 0x85859f51 + : { target: URP, value: 0n, callData: encodeFunctionData({ abi: urpAbi, functionName: 'assertSpent', + args: [configId, wallet, valueSpent, amountSpent, callsUsed] }) }; // 0x42bd3e90 — one per action + +const calls = [ + assertCall, + { target: wallet, value: 0n, callData: encodeFunctionData({ abi: walletAbi, functionName: 'stopMandate', args: [oldId] }) }, + { target: wallet, value: 0n, callData: encodeFunctionData({ abi: walletAbi, functionName: 'grantMandate', args: [newSession] }) }, +]; + +await wallet.write.execute([MODE_BATCH, encodeBatch(calls)]); +// MandateRevoked(oldId) · MandateGranted(newId, …) · SessionCreated · URPPolicySet per action + +``` + +#### **What the SDK implements** + +| Function | Does | +| --- | --- | +| `wallet.replace(oldId, expectedSpent, terms)` | the whole batch above; returns the new `permissionId` | +| `wallet.prepareReplace(oldId, expectedSpent, terms)` | the same as `MultiCall[]`, for callers batching it into a larger signature | +| `wallet.mandate(oldId)` | read the live counters to pass as `expectedSpent`, and the old terms to diff against the new | + +Sequence to implement: + +1. Read the mandate (`getMode` → `getConfig` / `getNativeConfig` per action) for current terms **and** current counters. +2. Build `newSession` exactly as in O4 / O5 / O6.1 — same agent key if the agent is unchanged, a different key if it is not. +3. Pre-flight the new session (O6.2). A replace that fails at `grantMandate` would have revoked the old mandate for nothing if the batch were not atomic — it is atomic, so it reverts whole, but catching it in `simulate` gives the better error. +4. Submit the batch. On `SpentMismatch`, re-read and re-present the numbers; do not retry silently, because the terms the user approved were derived from the old ones. +5. Read the new id from `MandateGranted`, replace the stored record, and **hand the new id to the agent** — it has no way to discover it. + +#### **O8.4 · Revoking without replacing** + +For a plain stop, see O8. Revocation never fails: `stopMandate` and `stopAll` carry no guard, no probe and no external call, by design. + +--- + +#### O7 · Stop + +```tsx +await wallet.write.stopMandate([permissionId]); // UnknownPermission if not enabled +await wallet.write.stopAll(); // one MandateRevoked per id +``` + +- Immediate. Every banked signed request for that id is dead. +- URP counters for the old `configId`s persist harmlessly; a regrant produces new ids. + +--- + +### Read operations + +#### R1 · Wallet views + +| Call | Returns | +| --- | --- | +| `owner()` | immutable owner | +| `factory()` | immutable factory | +| `grantNonce()` | salt the next grant will use | +| `getNonce(uint192 lane)` | next `nonceSeq` for that lane | +| `sessionEngine()` `urp()` `sessionValidator()` `universalGateway()` | wiring | +| `accountId()` | `"push.agentwallet.1.0.0"` | +| `isModuleInstalled(1, ENGINE, "")` | `true` on a healthy wallet | + +#### R2 · Factory views + +| Call | Returns | +| --- | --- | +| `walletCount(owner)` | n; next index | +| `predictWallet(owner, index)` | `(address, deployed)` | +| `isWallet(addr)` / `ownerOf(addr)` / `indexOf(addr)` | registry | +| `walletImplementation()` | for mirror checks | + +#### R3 · Mandate views + +| Call | On | Returns | +| --- | --- | --- | +| `getPermissionIDs(wallet)` | engine | all live `permissionId`s | +| `isPermissionEnabled(permissionId, wallet)` | engine | bool | +| `getSessionValidatorAndConfig(wallet, permissionId)` | engine | `(validator, keyConfig)` | +| `getEnabledActions(wallet, permissionId)` | engine | `bytes32[] actionIds` | +| `getActionPolicies(wallet, permissionId, actionId)` | engine | `[URP]` | +| `getMode(configId, wallet)` | URP | `{initialized, mode, chainHash}` — **never reverts; call it first** | +| `getConfig(configId, wallet)` | URP | universal terms + `spent`. Reverts only on an *initialised* native config; a zeroed struct otherwise | +| `getNativeConfig(configId, wallet)` | URP | native terms + `valueSpent, amountSpent, callsUsed`. Same asymmetry | +| `pushChainHash()` | URP | `keccak256("eip155:" ‖ chainid)` | + +⚠️ Neither getter distinguishes “empty” from “zeroed”. A mistyped `configId` returns a struct full of zeros, not an error — which reads as a live mandate with zero caps and no expiry. `getMode().initialized` is the only guard. + +#### R4 · Events + +| Event | Emitter | Index on | +| --- | --- | --- | +| `WalletDeployed(address indexed owner, uint256 indexed index, address indexed wallet, string label)` | factory | owner, wallet | +| `AccountInitialized(address indexed owner, address indexed engine)` | wallet | — | +| `OwnerExecuted(bytes32 indexed mode, bytes32 executionCalldataHash)` | wallet | — | +| `MandateGranted(bytes32 indexed permissionId, uint8 mandateType, bytes32 indexed chainHash, string chain)` | wallet | permissionId, chainHash | +| `MandateRevoked(bytes32 indexed permissionId)` | wallet | permissionId | +| `MandateActionAuthorized(bytes32 indexed permissionId, uint192 indexed nonceKey, uint64 nonceSeq, bytes32 opHash)` | wallet | permissionId | +| `URPPolicySet(bytes32 indexed configId, address indexed multiplexer, address indexed account, uint8 mode, bytes32 chainHash)` | URP | account | +| `OutboundMetered(bytes32 indexed configId, address indexed multiplexer, address indexed account, uint256 amount)` | URP | configId | +| `NativeCallMetered(bytes32 indexed configId, address indexed multiplexer, address indexed account, uint256 value, uint256 amount)` | URP | configId | +| `SessionCreated(bytes32 permissionId, address account)` / `SessionRemoved(bytes32 permissionId, address smartAccount)` | engine | — | +- `mandateType`: `0 = UNIVERSAL`, `1 = NATIVE`. +- `multiplexer` in URP events is always the engine. + +--- + +## 3 · Encoding appendix + +### 3.1 Structs as ABI tuples + +``` +Session (address sessionValidator, bytes sessionValidatorInitData, bytes32 salt, + (address policy, bytes initData)[] userOpPolicies, + ((bytes32 appDomainSeparator, string[] contentNames)[] allowedERC7739Content, + (address policy, bytes initData)[] erc1271Policies) erc7739Policies, + (bytes4 actionTargetSelector, address actionTarget, (address policy, bytes initData)[] actionPolicies)[] actions, + bool permitERC4337Paymaster) + +sessionValidatorInitData abi.encode(uint8 scheme, bytes key) scheme 0 → 20-byte address · scheme 1 → 32-byte Ed25519 pubkey +policy initData (envelope) abi.encode(string chain, bytes body) same shape for both kinds +UniversalTerms (body) (uint48 validUntil, address expectedCEA, address asset, uint256 maxAmountPerCall, uint256 maxAmountTotal, + uint256 maxPCPerCall, (address target, bytes4 selector, uint16 beneficiaryOffset, bool hasBeneficiary, uint256 maxValue)[] allowedCalls) +NativeTerms (body) (uint48 validUntil, address target, bytes4 selector, uint256 maxValuePerCall, uint256 maxValueTotal, + (bool enabled, uint16 offset, uint256 maxPerCall, uint256 maxTotal) amount, uint32 maxCalls, + (uint16 offset, bytes32 expected)[] pins) + +execution SINGLE abi.encodePacked(address target, uint256 value, bytes callData) // 20 + 32 + n bytes +execution BATCH abi.encode((address target, uint256 value, bytes callData)[]) +UniversalOutboundTxRequest (bytes recipient, address token, uint256 amount, uint256 gasLimit, uint256 gasPrice, uint256 maxPCForGas, bytes payload, address revertRecipient) +multicall payload 0x2cc2842d ‖ abi.encode((address to, uint256 value, bytes data)[]) +session signature 0x00 ‖ permissionId (32) ‖ sig (65 ECDSA | 64 Ed25519) +op hash pre-image abi.encode(bytes32 domain, uint256 chainid, address wallet, address engine, bytes32 permissionId, + bytes32 mode, bytes32 keccak256(executionCalldata), uint192 nonceKey, uint64 nonceSeq, uint48 requestExpiry) +``` + +- `Config` and `NativeConfig` (the storage structs returned by `getConfig` / `getNativeConfig`) are **read** types only. Never encode them. + +### 3.2 Mode word (ERC-7579) + +``` +byte 0 callType 0x00 single · 0x01 batch +byte 1 execType 0x00 default (only value accepted) +bytes 2-5 unused +bytes 6-9 modeSelector 0x00000000 +bytes 10-31 payload zero +``` + +### 3.3 Constants + +| Name | Value | +| --- | --- | +| `SEND_OUTBOUND_SELECTOR` | `0x77b86bec` | +| `MULTICALL_SELECTOR` | `0x2cc2842d` | +| `OP_HASH_DOMAIN` | `0xee007baac915cb5cecf254fbc38928446424413e2083e43f2155c71b8bf768fe` | +| `VALUE_SELECTOR` | `0xFFFFFFFF` | +| `SmartSessionMode.USE` | `0x00` | +| Donut chain string / hash | `"eip155:42101"` / `0x3d6bc1f1d3fb03065860265a8e93840b586e57075d956cd41b4319d040be87f9` | +| Sepolia chain string / hash | `"eip155:11155111"` / `0xafa90c317deacd3d68f330a30f96e4fa7736e35e8d1426b2e1b2c04bce1c2fb7` | +| `MAX_NATIVE_ACTIONS` | 8 | +| `MAX_PINS` | 8 | +| `MAX_ALLOWED_CALLS` | 32 | +| `MAX_ACTIONS_PER_REQUEST` (multicall entries) | 10 | +| `MIN_OUTBOUND_BODY_LEN` | 352 — the **body** minimum; the gate is `data.length < 4 + 352`, selector included | + +### 3.4 Function selectors + +| Function | Selector | +| --- | --- | +| `deployWallet(string)` | `0x37ba532c` | +| `execute(bytes32,bytes)` | `0xe9ae5c53` | +| `grantMandate(Session)` | `0xa3e13323` | +| `stopMandate(bytes32)` | `0xa0dbb1e9` | +| `stopAll()` | `0xf0881ae6` | +| `executeWithSession(address,bytes32,bytes,bytes,uint192,uint64,uint48)` | `0x3ea758b5` | +| `assertSpent(bytes32,address,uint256)` | `0x85859f51` | +| `assertSpent(bytes32,address,uint256,uint256,uint32)` | `0x42bd3e90` | + +### 3.5 Argument offsets + +- Absolute, from byte 0 of the calldata being inspected, selector included. Static argument `i` → `4 + 32*i`. +- Native pins and amount rule inspect the **Push-side** calldata. Universal `beneficiaryOffset` inspects the **inner** multicall entry’s `data`. +- Derive offsets from the ABI in tooling; never hand-type them. A wrong offset fails closed (every request reverts), it cannot widen a mandate. + +--- + +## 4 · Error catalogue + +### 4.1 Decoding rule + +- Wallet, factory and validator errors revert **directly** with full arguments. +- URP **init** errors (`grantMandate` path) bubble with full arguments. +- URP **checkAction** errors (`executeWithSession` path) are truncated by the engine to `PolicyCheckReverted(bytes32)`: the 4-byte selector + the first 28 bytes of the first argument. Decode the selector, treat the rest as diagnostic. +- Target reverts from `execute` and from the agent’s dispatched call bubble verbatim. + +### 4.2 Factory + +| Error | When | +| --- | --- | +| `ImplementationNotSet()` | factory not initialised | +| `IndexOutOfRange(uint256 index, uint256 next)` | `predictWallet` beyond next index | +| `NotAWallet(address)` | `indexOf` on a foreign address | +| `EnforcedPause()` | factory paused | + +### 4.3 Wallet — grant + +| Error | When | +| --- | --- | +| `NotOwner()` | caller is not owner or self | +| `MalformedSessionShape()` | any shape rule (see O6) | +| `TooManyActions(uint256 count)` | 0 actions, or > 8 | +| `EmptyChain()` | envelope chain string empty | +| `InconsistentChain(uint256 actionIndex)` | action `i` names a different chain than action 0 | +| `MandateTypeMismatch(uint8 derived, uint256 actionIndex, address target)` | gateway target under this chain’s string, or a non-gateway target under a foreign one. See the note below — `derived` is only informative in one of the two cases | +| `ForbiddenActionTarget(address)` | zero, `0x1`, wallet, engine, URP, validator, factory | +| `ForbiddenActionSelector(bytes4)` | `0x00000001`, `0x00000002` | +| `DuplicateAction(address, bytes4)` | same pair twice | +| `UnknownPermission(bytes32)` | `stopMandate` on a non-live id | +| `MalformedBatchCalldata()` | `execute` in BATCH mode with calldata that is not `abi.encode(Execution[])` — e.g. SINGLE-encoded bytes sent with `MODE_BATCH`. From `ExecutionLib` | +| `EngineStillHoldsPermissions()` | `uninstallModule` on the engine while mandates are live — `stopAll` first | + +⚠️ **`MandateTypeMismatch.derived` carries information in only one direction.** + +- **Foreign chain, non-gateway target** → `derived = 0 (UNIVERSAL)`, and it is real. The usual cause: you meant a Push-side mandate but the chain string is not byte-exact. `"EIP155:42101"`, `"eip155:042101"` and a leading space all hash to not-Push. The SDK’s §5 pre-check exists to catch this before the user sees it. +- **This chain’s string, gateway target** → `derived = 1 (NATIVE)` is **hardcoded at the revert site** (`PushAgentWallet.sol:519`). It is not wrong — that branch only runs when NATIVE was derived — but it is a constant, so do not read it as a derivation result. The useful fields here are `actionIndex` and `target`. + +### 4.4 URP — init, in order (bubbles through grant with full arguments) + +Init has no gate numbers: the numbering in §4.6 / §4.7 comes from the contracts’ own comments and test names, and there is no equivalent scheme here. Rows are in execution order, unnumbered. + +The first group runs in `initializeWithMultiplexer`, **before the chain is read and before the mode is derived**, so it is shared by both rulebooks — which is why `EmptyChain` appears above a universal table. The second group runs inside the mode’s own initialiser. + +⚠️ **`AlreadyInitialized` precedes the envelope decode.** On a config that already exists, *every* malformed shape reports `AlreadyInitialized` instead of its own error. A developer debugging a bad envelope against a reused `configId` will chase the wrong problem. Reuse is not normal — the wallet supplies a fresh salt per grant — so if you see this, the `permissionId` is stale. + +**Envelope, both modes** + +| Error | When | +| --- | --- | +| `AlreadyInitialized(bytes32 configId)` | config already exists; **runs before everything below** | +| unnamed revert | outer `(string, bytes)` decode fails: a `(uint8, bytes32, bytes)` header, `(uint8 ≥ 2, bytes)`, or under 64 bytes | +| `EmptyChain()` | chain string empty — also what a v2 `(uint8 0, bytes)` envelope and any bare struct decode to | + +**Body — universal** (chain ≠ this chain) + +| Error | When | +| --- | --- | +| unnamed revert | body is not `UniversalTerms` | +| `AllowListOutOfRange(uint256)` | 0 or > 32 entries — **checked first, before expiry** | +| `InvalidExpiry(uint48)` | `validUntil` zero or not in the future | +| `InvalidConfigField()` | zero `asset` or zero `expectedCEA` | +| `InvalidAsset(address)` | asset has no code (explicit `code.length` guard), or reverted on `SOURCE_CHAIN_NAMESPACE()` | +| `ChainMismatch(bytes32 declared, bytes32 assetChain)` | asset answered with a different chain than the envelope declared | +| unnamed revert | asset answered `SOURCE_CHAIN_NAMESPACE()` with a non-string — decode fails outside the `try/catch` | + +**Body — native** (chain == this chain) + +| Error | When | +| --- | --- | +| unnamed revert | body is not `NativeTerms` | +| `InvalidExpiry(uint48)` | `validUntil` zero or not in the future — **checked first here** | +| `NativeTargetZero()` | zero target | +| `NativeTargetIsGateway(address)` | target is the gateway | +| `TooManyPins(uint256)` | > 8 pins | +| `ValueOnlyWithPins()` | `selector == 0xFFFFFFFF` with pins | +| `ValueOnlyWithAmountRule()` | `selector == 0xFFFFFFFF` with an amount rule | + +### 4.5 Wallet — agent door + +The owner never calls this door, but these are what a badly-scoped mandate produces at runtime. Full agent-side context in the [agent doc](./AGW-SDK-v1-agent.md) §4. + +| Error | When | +| --- | --- | +| `RequestExpired()` | `requestExpiry ≠ 0` and past | +| `ValidatorNotInstalled(address)` | `validator` arg ≠ engine | +| `InvalidNonce(uint192 key, uint64 expected, uint64 provided)` | wrong `nonceSeq` | +| `InvalidSessionSignature()` | signature < 33 bytes or byte 0 ≠ `0x00` | +| `ValidationFailed(address authorizer)` | signature does not recover / verify (after URP passes) | +| `OutsideTimeWindow(uint48 validAfter, uint48 validUntil)` | engine time window | +| `UnsupportedExecutionMode()` | mode ≠ single/default | +| `ForbiddenDispatchTarget(address)` | target is the wallet or the engine | + +### 4.6 URP — universal gates, in order (truncated to 32 bytes) + +These fire on the agent’s requests, not on the owner’s calls. Listed here because they are the runtime meaning of the terms the owner granted: every gate is a cap or a pin the owner chose. + +The gate numbers come from the contracts’ own comments and test names — use them when reading `URP.sol` or a failing test. They are a **narrative numbering, not a count of checks**: gate 4 is three separate reverts (4a/4b/4c) and gates 14 and 15 are two each, so “sixteen gates” describes the list below, not sixteen discrete `if`s. Don’t go looking for a gate that isn’t a row here. + +| # | Error | Rule | +| --- | --- | --- | +| 1 | `NotInitialized(bytes32 id, address)` | config exists | +| 2 | `MandateExpired(uint48)` | `now ≤ validUntil` | +| 3 | `InvalidTarget(address)` | target is the gateway | +| 4a | `CalldataTooShort(uint256)` | ≥ 4 bytes | +| 4b | `InvalidSelector(bytes4)` | `0x77b86bec` | +| 4c | `MalformedOutboundRequest(uint256)` | body ≥ 352 bytes | +| 5 | `AssetMismatch(address expected, address actual)` | `req.token == asset` | +| 6 | `AmountExceedsCap(uint256 amount, uint256 cap)` | per-call | +| 7 | `TotalSpendCapExceeded(uint256 wouldBe, uint256 cap)` | lifetime | +| 8 | `PCValueExceedsCap(uint256 value, uint256 cap)` | Push-side `value ≤ maxPCPerCall` | +| 9 | `UncappedGasSwapRejected()` | `maxPCForGas ≠ 0` | +| 10 | `InvalidRevertRecipient(address expected, address actual)` | `== wallet` | +| 11 | `RecipientMustBeEmpty()` | `recipient.length == 0` | +| 12 | `PayloadNotMulticall()` | payload starts with `0x2cc2842d` | +| 13 | `BatchSizeOutOfRange(uint256)` | 1..10 entries | +| 14 | `ForbiddenInnerTarget(address)` | not wallet / URP / gateway / expectedCEA | +| 14 | `MalformedInnerCalldata()` | entry data ≥ 4 bytes; offset in range | +| 15 | `CallNotAllowed(address, bytes4)` | pair in `allowedCalls` | +| 15 | `BeneficiaryMismatch(address expected, address actual)` | word at offset == expectedCEA | +| 16 | `InnerValueExceedsAllowance(uint256 index, uint256 value, uint256 max)` | destination units | + +### 4.7 URP — native gates, in order (truncated to 32 bytes) + +| # | Error | Rule | +| --- | --- | --- | +| N1 | `NotInitialized` | | +| N2 | `MandateExpired(uint48)` | | +| N3 | `NativeTargetIsGateway(address)` | never the gateway | +| N4 | `TargetMismatch(address actual, address expected)` | | +| N5 | `SelectorMismatch(bytes4 actual, bytes4 expected)` / `ValueOnlyCalldataNotEmpty(uint256)` | | +| N6 | `ValueExceedsCap(uint256, uint256)` / `TotalValueExceeded(uint256, uint256)` | PC value | +| N7 | `CalldataTooShortForPin(uint256 len, uint256 i, uint256 needed)` / `ArgPinMismatch(bytes32 actual, uint256 i, bytes32 expected)` | pins | +| N8 | `CalldataTooShortForAmount(uint256, uint256)` / `NativeAmountExceedsCap(uint256, uint256)` / `TotalNativeAmountExceeded(uint256, uint256)` | amount rule | +| N9 | `CallLimitReached(uint32 used, uint32 max)` | | + +### 4.8 Validator + +`validateConfig` and `validateSignatureWithData` fail differently, and **neither named validator error can come from `validateConfig`**. + +| Surface | Bad scheme | Bad key length | Not `abi.encode(uint8, bytes)` | +| --- | --- | --- | --- | +| `validateConfig` (pre-check) | returns `false` | returns `false` | **reverts**, unnamed, at the decode | +| `validateSignatureWithData` (runtime, inside the engine) | `UnsupportedScheme(uint8)` | `MalformedConfig()` | reverts, unnamed | +- **Treat any revert from `validateConfig` as an invalid config** — the contract’s own instruction. Wrap it; see §O6. +- A config that passes `validateConfig` can still fail at runtime: a valid key with a wrong signature returns `false`, which the wallet surfaces as `ValidationFailed(authorizer)`. Neither named error above reaches the SDK as itself. + +### 4.9 Views + +| Error | When | +| --- | --- | +| `WrongModeForCall(uint8 actual)` | `getConfig` / `assertSpent` on a config **initialised** under the other rulebook. An **uninitialised** config reverts nothing — both getters return a zeroed struct. Read `getMode().initialized` first. | +| `SpentMismatch(uint256 expected, uint256 actual)` | `assertSpent` — counters moved since you read them | +| `NotInitialized(bytes32 id, address)` | `assertSpent` on a config that was never initialised | + +### 4.10 Errors the SDK will not meet + +Listed so nobody maps them: `ZeroAddress()` (URP constructor) · `NotExecutorModule(address)`, `AlreadyCredited(bytes32)` (`creditRevert`, callable only by the executor module, which has no code on Donut) · `ImplementationNotSet()` (factory misdeployment). + +### 4.11 SDK error classes + +All extend `AgentWalletError { code, hint, ...context }` (the `PC20Error` pattern). Client-side checks throw before any signature is requested; on-chain reverts are decoded from the AGW ABIs. + +| Class | Thrown by | When | +| --- | --- | --- | +| `InvalidMandateTermsError` | `grant`, `prepareGrant` | any §5 grant pre-check fails; carries `violations[]` naming the on-chain error it would have hit | +| `AssetChainMismatchError` | `grant` | `asset.SOURCE_CHAIN_NAMESPACE() !== terms.chain` | +| `CEAFactoryDriftError` | `grant` | `CEA_FACTORY_ADDRESSES[chain] !== Vault.CEAFactory()` | +| `UnsupportedDestinationError` | `grant` | SVM destination for a cross-chain mandate | +| `MandateNotLiveError` | `stop`, `replace` | `isPermissionEnabled` false | +| `AgentWalletRevertError { name, args }` | any write | decoded custom error from wallet / factory / URP / validator; `PolicyCheckReverted` is unwrapped to the inner URP selector | + +--- + +--- + +[O9 · Compile an agent card into a mandate](https://app.notion.com/p/O9-Compile-an-agent-card-into-a-mandate-3df188aea7f480c98f5be5018d268659?pvs=21) + +--- + +## Open questions (team) + +1. **Namespace name.** `client.agentWallet` proposed; alternatives `client.agent`, `client.aw`. Decide before the first PR since it is public API. +2. **Owner batching on Push-native EOAs.** UEA owners get one-signature deploy + approve + grant via `data: MultiCall[]`. A Push-native EOA cannot; accept two txs, or add a factory `deployAndGrant`? (Contract change, out of the SDK’s hands.) +3. **Gateway allowance policy.** Approve `maxAmountTotal` at grant (simple; one allowance per asset, shared across mandates on the same asset) versus approve per request (impossible from the agent side without a native `approve` mandate). Recommend at-grant, reset on `stop`. +4. **`SOURCE_CHAIN_NAMESPACE` on the PRC20 ABI and `getOutboundTxGasAndFees` on a core ABI** are missing from `@pushchain/core`; confirm which team adds them. +5. open questions regarding AGENT CARD to Mandate Translation → [ **Open Question: Agent Card to mandate translation**](https://app.notion.com/p/Open-Question-Agent-Card-to-mandate-translation-3df188aea7f480c99e36decc46df5da0?pvs=21) +6. Open question regarding UniversalMarketplace.startJob() → https://pushchain.slack.com/archives/C077XBA6KUH/p1789667453891089 + +--- + +# Nomenclature and Standardization of Agentic Wallet, SDK, Universal Marketplace \ No newline at end of file diff --git a/plan/agw/notion/overview.md b/plan/agw/notion/overview.md new file mode 100644 index 00000000..ba9d9694 --- /dev/null +++ b/plan/agw/notion/overview.md @@ -0,0 +1,153 @@ +# AGW + UniversalMarketplace + 8183 + UniversalEvaluator + + + +# The flow as a picture + +Six phases, top to bottom. The user signs once at the start; the agent works under the rules; the evaluator settles. + +```mermaid +sequenceDiagram + autonumber + actor Agent + participant Market as Universal Marketplace + actor User + participant AGW as AGW (wallet + rules) + participant Kernel as 8183 Kernel + Hook + participant Eval as UniversalEvaluator + participant Chains as Other chains (validators read) + + Note over Agent,Market: Phase 1. Listing + Agent->>Market: publish card: skill, access needed, fee, evaluation criteria + + Note over User,Kernel: Phase 2. Start job, one signature + User->>Market: pick card, set principal and duration + Market->>AGW: deploy or reuse wallet, fund it, grant rules + Market->>Kernel: create job (client = AGW, criteria in description) + + Note over User,Eval: Phase 3. Fund and start + User->>Kernel: fund: fee into escrow + Kernel->>Kernel: hook: agent key matches, rules outlive job, one live job per wallet + Kernel->>Eval: register criteria + Eval->>Chains: START reads + Chains-->>Eval: baseline recorded, job has started + + Note over Agent,Chains: Phase 4. Execute (repeats) + Agent->>AGW: act under the rules + AGW->>Chains: only what the rules allow + + Note over Agent,Chains: Phase 5. Submit and verify + Agent->>Kernel: submit (refused before baseline or minDuration) + Kernel->>Eval: evaluate + Eval->>AGW: any checkpoint since start? (did the user change anything) + Eval->>Chains: END reads, three blocks + Chains-->>Eval: facts + + Note over User,Eval: Phase 6. Settle + alt promise kept, or user changed things mid-job + Eval->>Kernel: complete: fee to agent + else promise not kept + Eval->>Kernel: reject: fee back to user + else no verdict by expiry + User->>Kernel: claimRefund + end +``` + +# The four pieces, in one line each + +| Piece | What it is | Status today | +| --- | --- | --- | +| AGW (Agentic Wallet) | A user's wallet on Push that an agent key may act from, only inside rules the user set. A primitive: works alone, or as the client of an 8183 job. | BUILT on branch `pushAgenticWallet_v3`, deployed on Donut at provisional addresses. Permanent deployment waits on the contract change set. | +| Universal Marketplace | Where agents list what they do and what access they need (the agent card, including the evaluation criteria they promise). Where a user picks a card and starts a job in one signature. | DESIGN only. No contract, no repo. | +| 8183 (job kernel) | The ERC-8183 escrow: create job, quote, fund, submit, complete or reject, refund. The AGW is the client. A hook binds the job to the AGW's rules. | BUILT on `push-chain-core-contracts` branch `8183-v1` with tests. Not deployed. Hook is partial. | +| UniversalEvaluator | The job's judge. Reads facts through Read State at fixed points, compares them to the criteria, calls complete or reject. Generic: criteria are data, not code. | DESIGN. Three earlier drafts; converged on 2026-09-28 to one generic evaluator. No code. | + +# How they connect, phase by phase + +| Phase | What happens | Which piece | +| --- | --- | --- | +| 1. Listing | Provider publishes an agent card: skill, contracts and functions it needs, fee, execution key, evaluation criteria template. | Marketplace | +| 2. Start job | User picks a card, gives principal and duration. One signature: deploy (or reuse) the AGW, fund it, grant rules compiled from the card, create the 8183 job with the compiled criteria in the description. | Marketplace, AGW, 8183 | +| 3. Fund and start | Fee goes to escrow. The hook checks the rules belong to this provider and outlive the job, registers the criteria with the evaluator, and fires the START reads. When they land, the job has started. | 8183, Evaluator | +| 4. Execute | Agent acts through the AGW's agent door. UniversalRulesPolicy checks every call before it leaves Push. Cross-chain legs run through the gateway and the AGW's CEA. | AGW | +| 5. Submit and verify | Provider submits (refused before minDuration or before START landed). END reads fire. Evaluator compares START, END and the criteria. Checkpoints on the AGW are read first: if the user changed anything mid-job, the provider is paid regardless. | 8183, Evaluator, AGW | +| 6. Settle | Pass: complete, fee to provider. Fail: reject, fee back to the AGW. No verdict by expiry: claimRefund. Reputation write only for evaluator-judged jobs from registered cards. | 8183, Evaluator | + +# Locked so far (2026-09-28) + +- AGW is a primitive; 8183 is one consumer of it. +- One word on-chain and in the SDK: rules (not mandate). Contract names: `AGW.sol`, `AGWFactory.sol`, `UniversalRulesPolicy.sol`. +- The marketplace must be able to run the whole start-job sequence in one contract call, so factory and wallet get signature-authorized variants. +- The evaluator is generic. Criteria are an array of conditions (read plus comparison), authored by the agent on the card, copied into the job at createJob. +- Job start is fund. START reads fire at fund; the job is started when they land. END reads fire at submit. +- Checkpoints on the AGW replace any gate on the owner: any owner-side change mid-job (principal moved, rules changed, key changed) pays the provider. This also settles "rules changed mid-job": there is no rebind; the change is a checkpoint and the fee goes to the agent. +- Gas is always PC. The job fee token is chosen by the client per job (USDC, USDT.eth, USDT.sol and other PRC20s); PUSD is not required. The kernel today is single-token per deployment, so this needs either one kernel per token or a kernel change that puts `paymentToken` on the job (K-12, recommended). +- Solana is required work, not deferred: a third rulebook inside UniversalRulesPolicy keyed by the `solana` namespace. + +# Decisions still open, in the order they unblock people + +1. Start job: SDK-orchestrated multicall first, or marketplace contract from day one? Depends on whether the demo user is Push-native. +2. Fee fixed on the card (provider accepts by signing the card, hook recomputes compile at fund) or provider quotes via setBudget after the job exists. +3. Who pays reads, and whether the evaluator takes a fee. Not needed for the POC, needed before any business-model claim. +4. Client-chosen fee token: K-12 kernel change (token per job, `totalEscrowed` per token, fees in the job's token) vs one kernel deployment per token. Recommendation: K-12. + +# Timeline + +POC before the investor window (important meetings from Oct 10; window Oct 15 to Nov 10). Scope: marketplace listing, card selection, rules creation, job creation, one evaluated job type. + +# Pages + +Read in order. Each page is self-contained and opens with where it is going. Pages 5 to 8 are the SDK, one namespace per piece: `client.agentic`, `client.market`, `client.job`, `client.evaluation`. + +### 1. AGW Contract Changes + +[1. AGW Contract Changes (nomenclature standard + change set)](1-agw-contract-changes.md) + +### 2. Universal Marketplace + +Registry, compiler, one-signature start job, the agent card, and the SDK-vs-marketplace orchestration decision. + +[2. Universal Marketplace](2-universal-marketplace.md) + +### 3. 8183 + +[3. 8183 (job kernel and hook)](3-8183-job-kernel-and-hook.md) + +### 4. Universal Evaluation + +[4. Universal Evaluation](4-universal-evaluation.md) + +### 5. SDK: AGW + +`client.agentic` on the owner side; `initialize(agentSigner, { agenticWallet: '0xWallet' })` on the agent side. Rules, derive, create, list, wallet handle, prepare. + +[5. SDK: AGW](5-sdk-agw.md) + +### 6. SDK: Universal Marketplace + +`client.market`: cards, compile, one-signature start (composes agentic, job, evaluation); publish and retire on the provider side. + +[6. SDK: Universal Marketplace](6-sdk-universal-marketplace.md) + +### 7. SDK: 8183 Job + +`client.job`: create, fund, submit, status, watch, claimRefund. Client side through the AGW, provider side with a plain signer. + +[7. SDK: 8183 Job](7-sdk-8183-job.md) + +### 8. SDK: Universal Evaluation + +`client.evaluation`: criteria build, validate, resolve, encode, simulate; job status, waitForStart, verdict. + +[8. SDK: Universal Evaluation](8-sdk-universal-evaluation.md) \ No newline at end of file diff --git a/plan/agw/questions-harsh.md b/plan/agw/questions-harsh.md new file mode 100644 index 00000000..4ea47610 --- /dev/null +++ b/plan/agw/questions-harsh.md @@ -0,0 +1,43 @@ +# Product questions for Harsh + +Revised October 3, 2026 after checkpoint follow-up. Local draft, not sent. Baseline: AGW `pushAgenticWallet_v3@e704d5b`, core `cb69e0b`, full Notion export October 03, 2026 at 13:23 IST. SDK page 5 remains the public target; proposed API changes below require agreement. + +## H1 Destination approval safety + +The headline example allows destination `approve(address,uint256)` without a spender constraint. Universal AllowedCall can pin a beneficiary to the CEA, but cannot pin an arbitrary spender. This can authorize an agent-controlled spender against existing CEA balances. Current marketplace code rejects approve/increaseAllowance and uses owner Approval[] instead. + +Recommendation: reject these known approval selectors in universal agent rules and add an explicit owner-controlled destination approval flow. This is a public validation/API change, not merely internal implementation. Native approvals can use spender pins. Selector filtering alone cannot make arbitrary untrusted contracts safe. + +Decision: which owner approval surface should the SDK expose, and should the unsafe example be replaced accordingly? + +## H2 Native scope and arrays + +The contract can grant up to eight native actions in a rule set, but page 5 NativeRule describes one action and permits one rule per agent/chain. The agent door accepts only single/default execution. EVM destination arrays can fit one bounded CEA multicall; Push-native arrays cannot become atomic through the present agent door. + +Decision: keep one native action per public rule, or explicitly extend its type to an action list? For native arrays, should the SDK reject them initially, offer explicitly sequential behavior, or wait for an agreed contract change? We recommend rejecting unsupported arrays rather than silently weakening atomicity. + +## H3 Optional limit defaults + +The new contract proposal explicitly makes AssetCap.maxTotal=0 unlimited; we propose mapping an omitted asset maxTotal to zero as well, with an unlimited preview. Please confirm omission semantics and the still-undefined native defaults: maxValuePerCall, maxValueTotal, amount.maxTotal, maxCalls and allowedCalls.maxValue. Native explicit zero must not accidentally inherit the new asset sentinel convention. + +## H4 Reconcile the SDK spec with the delivered D3 model + +Please approve a small spec correction set, with the exact API wording reviewed before implementation: + +- Rules IDs use validator address, encoded Push agent and grant nonce; chain is not hashed and IDs are wallet-scoped. The helper needs deployment/validator context, and constants currently claim no validator address. +- Wallet prediction is stable within a factory/implementation generation, not globally from owner/index alone. +- The existing native SDK supports EIP-7702 batching with a sequential fallback; creation must describe actual atomicity. +- Agent duplicate-rule ambiguity must have documented behavior. SDK preflight can reject duplicates, while direct contract grants can still create more than one active candidate. + +- Universal Spent still returns scalar amountSpent while the new rule has per-token caps. Please agree a per-asset spent shape rather than aggregating unlike token units. +- Should rules.list() return revoked rules as well as active rules? If historical rules are promised, the grant event needs agent attribution or the SDK needs reliable calldata reconstruction; current revoke clears agent config. + +Creation now deploys/grants only; funding and PC top-ups are separate as the updated spec directs. We will own partial-failure metadata, list/info implementation, read-only/reinitialize details, receipt mapping and Web2 migration. We will document any observable choice and flag only departures from explicit API requirements. + +## Separate downstream note + +Multi-chain card binding, expiry equality, dropped binder role, single-token versus K-12, and old job examples belong in the marketplace/job alignment discussion. They do not require reopening standalone AGW implementation decisions. + +## Current source freshness + +Successful full Notion export: October 03, 2026 at 13:23 IST; 12 pages checked, pages 1 and 5 changed. AGW remains pinned to reviewed e704d5b; no new Git refresh was part of this pull. Core/gateway retain cb69e0b/bcbf7df evidence. Drafts remain unsent. diff --git a/plan/agw/questions-zaryab.md b/plan/agw/questions-zaryab.md new file mode 100644 index 00000000..66c05f72 --- /dev/null +++ b/plan/agw/questions-zaryab.md @@ -0,0 +1,37 @@ +# Contract questions for Zaryab + +Revised October 3, 2026 after checkpoint implementation. Local draft, not sent. AGW baseline `pushAgenticWallet_v3@e704d5b`, core `cb69e0b`. D3 is implemented in source and owner batching is already the documented design; those questions have been removed. Refresh the sources before sharing. + +## Z1 Next wallet generation surface + +Checkpoints are now implemented in source, including count views, per-call ticks and WithSig behavior. Which of grant ref, label storage/setLabel, envelope version and the new multi-asset/maxGasPerCall terms are planned together for the next generation? Please include agent attribution in RulesGranted if the SDK must return revoked-rule history; the engine clears that agent config on revoke. If ref is added to signed grants, confirm it is bound by the owner's signed digest. + +The checkpoint implementation has chosen storage and deliberately revised the owner-door invariant; we have removed that design question. Replacement batches add five ticks. We will consume the implemented event/count semantics and separately align evaluator snapshot timing and the documented allowance blind spot. + +The new section 4c also needs exact per-asset spent and replacement assertion ABIs. Its no-expected-value assertSpent returning totals is not by itself the current stale-spend race guard. Please define that guard, empty-assets call routing, zero/unlimited maxTotal behavior and whether bytes32 expectedCEA is intended for EVM terms. + +## Z2 Push-side gateway allowance + +Gateway PRC20 outbound pulls from the AGW with transferFrom, but the documented setup has no approve step. The universal agent rule only permits the gateway action. We propose an owner-door bounded approve(gateway, amount) during a separate funding/owner setup flow, with explicit replenishment and recovery behavior. Funding is no longer part of create in the updated SDK spec; multi-asset rules require per-token allowance handling. + +Please confirm the intended allowance mechanism and add it to the flow and an integration test that actually pulls/burns tokens. Destination approvals are a separate owner operation. + +## Z3 Deployment and generation plan + +Please provide the next generation's factory, wallet implementation, validator, engine and policy addresses, source commits and deployment start block when available. Will engine/URP be reused, or will this be isolated from historical configs? How will accountId/version distinguish ABI generations? Is SVM destination support enabled there? + +Existing clones cannot acquire the new wallet ABI. The recorded Donut factory still points to the old implementation in our probes. We will add SDK generation guards and handle historical addresses separately. + +## Z4 Gateway struct intent + +The available evidence shows six-field gateway main is older, while the current September branch and live Donut dispatcher use eight fields. Is any future removal of gasPrice/maxPCForGas actually planned? If not, page 1's coordinated-removal warning should be corrected. We will encode the matched deployed ABI. + +## Heads-up and downstream alignment + +Our dedicated agent composer must send a nonzero maxPCForGas, empty EVM recipient and AGW revertRecipient. The first authorized live test will verify positive-amount multicall settlement with this shape; an existing successful transaction hash would help. This is not a request to change URP's empty-recipient guard. + +creditRevert is already documented as waiting on Push-core executor support; we will document that limitation rather than ask you to redesign it. The old Ed25519 session-validator issue is obsolete at head. Separate downstream alignment remains for marketplace expiry equality, rule binding, payment tokens and hook lifecycle. + +## Current source freshness + +Successful full Notion export: October 03, 2026 at 13:23 IST; 12 pages checked, pages 1 and 5 changed. AGW remains pinned to reviewed e704d5b; no new Git refresh was part of this pull. Core/gateway retain cb69e0b/bcbf7df evidence. Drafts remain unsent. diff --git a/plan/agw/research/donut-probe-2026-10-02.json b/plan/agw/research/donut-probe-2026-10-02.json new file mode 100644 index 00000000..52986500 --- /dev/null +++ b/plan/agw/research/donut-probe-2026-10-02.json @@ -0,0 +1,33 @@ +{ + "block": "23818643", + "rpc": "https://evm.donut.rpc.push.org/", + "checks": { + "factory": { + "exit": 0, + "output": "0xD7FEF338572f96edBeF89E720f1F0fF1284ec79C", + "error": "" + }, + "policy": { + "exit": 0, + "output": "\"1.0.0\"", + "error": "" + }, + "wallet": { + "exit": 0, + "output": "\"push.agentwallet.1.0.0\"", + "error": "" + }, + "gateway_slot": { + "exit": 0, + "output": "0x0000000000000000000000001e412939780f2b834dc42c7ac58d9f99888da659", + "error": "" + }, + "gateway_dispatch": { + "implementation": "0x1e412939780f2b834dc42c7ac58d9f99888da659", + "read_exit": 0, + "eight_field_push4_present": true, + "six_field_push4_present": false + } + }, + "caveat": "PUSH4 scan is supporting evidence, not full ABI proof; probes only cover named deployment." +} diff --git a/plan/agw/research/notion-refresh-2026-10-03.md b/plan/agw/research/notion-refresh-2026-10-03.md new file mode 100644 index 00000000..232157d6 --- /dev/null +++ b/plan/agw/research/notion-refresh-2026-10-03.md @@ -0,0 +1,34 @@ +# Successful Notion refresh on October 3 2026 + +Downloaded and imported all **12 registered pages** on October 03, 2026 at 13:23 IST (2026-10-03T07:53:10.278902+00:00). The earlier browser download block is resolved for this run. Two page bodies changed: **1 AGW Contract Changes** and **5 SDK AGW**. Ten are unchanged. No registered pages are missing and no unexpected page IDs appeared. + +## SDK target changes + +- `create` now deploys the wallet and grants rules; it no longer funds it. `CreateOptions.funds` and `pc` were removed. Funding uses ordinary account tooling separately. +- Universal rules now use `assets: AssetCap[]`, with per-token `token`, `maxPerCall` and optional `maxTotal`, replacing single `asset` and amount caps. +- Asset inputs are destination-chain token addresses/Moveable constants or the native marker; the SDK resolves them to Push PRC20 addresses and checks source-chain identity. +- `maxGasPerCall` replaces `maxPCPerCall`. It still caps PC wei attached to one outbound, not a lifetime gas budget. +- Creation progress event `AGENTIC-TX-103` was removed. + +## New contract proposal section 4c + +The proposal adds 0–8 asset caps, per-token spend accounting, a token on OutboundMetered, the gas-field rename, and a changed assertSpent surface. Asset maxTotal zero means no total cap in this proposal. Empty assets means calls that move no tokens. These changes are proposed; the tested e704d5b source still has the previous single-asset terms and assertion overloads. + +## New alignment items + +1. Page 5's universal Spent remains a scalar amountSpent despite per-token accounting. A per-asset return shape and corresponding error/event fields are needed. +2. Section 4c describes `assertSpent(configId, account)` as returning totals. A read alone cannot enforce the existing replacement race guard. Define the expected per-token assertion input/behavior separately from the spend getter. +3. Empty-asset execution needs an agreed routing token/destination mechanism: the existing gateway derives its destination from token context, and current URP requires a configured asset. Do not assume the new call-only mode works without new fixtures. +4. The new EVM UniversalTerms sketch uses bytes32 expectedCEA; current source uses address. Confirm canonical EVM/SVM representation and codec validation. +5. Pages 6–8 are unchanged, so their card/compiler limits and funding orchestration still need reconciliation with the new multi-asset and separate-funding target. + +The headline destination approve remains unpinned. Binder still says dropped for v1. D3 wording and gateway-removal narrative remain older than verified contract evidence. Existing questions remain relevant after the updates recorded in the drafts. + +## Evidence + +- [Per-page comparison](../notion/history/20261003T075310278902Z/refresh.json) +- [Manifest](../source-manifest.json) +- [Contract page diff](../notion/history/20261003T075310278902Z/1-agw-contract-changes.diff) +- [SDK page diff](../notion/history/20261003T075310278902Z/5-sdk-agw.diff) + +Raw exports, previous manifest, previous changed snapshots and unified diffs are retained. Known links were normalized by page ID. Comment threads are not included in exports. Notion itself was not edited, and no questions were sent. diff --git a/plan/agw/research/validation-e704d5b/README.md b/plan/agw/research/validation-e704d5b/README.md new file mode 100644 index 00000000..4c2b9869 --- /dev/null +++ b/plan/agw/research/validation-e704d5b/README.md @@ -0,0 +1,34 @@ +# Checkpoint revision validation at e704d5b + +October 3, 2026. GitHub API confirmed `pushAgenticWallet_v3` at `e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9`; `nomenclature-changes` is no longer an advertised branch. Local Git objects include the checkpoint commit `6b7dbf4`. An isolated source archive was built under `/private/tmp`, using the pinned dependency trees and the seven independent review tests. No sibling working checkout or production source was changed. + +| Check | Result | Evidence | +| --- | --- | --- | +| Build and sizes | Passed | [build.log](build.log) | +| Revised execute source pin | Passed, B2 checkpoint revision | [check-execute.log](check-execute.log) | +| Default suite, offline | 563 passed, 0 failed, 6 skipped; 27 suites | [tests-offline.log](tests-offline.log) | +| Seven review tests, offline | 7 passed, 0 failed, 0 skipped | [review-tests-offline.log](review-tests-offline.log) | + +The first normal test attempts crashed before test execution in Foundry's macOS proxy-discovery code (`system-configuration`, NULL object). Those failed-attempt logs were archived locally during package cleanup; the successful offline logs are retained here. Retrying with the supported `--offline` option succeeded without changing assertions. The initial crash is not a contract failure or a successful test run. + +Six skips are the RPC-dependent PRC20 checks and deployment-record checks; this pass did not run live forks or verify a new deployment. The seven tests use the existing recording gateway, so they do not prove real allowance consumption, token burn or destination settlement. + +| Contract | Runtime bytes | EIP-170 remaining bytes | +| --- | ---: | ---: | +| AGW | 16,549 | 8,027 | +| AgentValidator | 806 | 23,770 | +| SmartSession | 22,581 | 1,995 | +| UniversalRulesPolicy | 23,673 | 903 | + +These results reproduce the independent follow-up. Generated [ABIs](abi/) reflect this source revision only. See [offline command results](offline-results.json). The isolated copy includes only the [review test](review-tests/IndependentReviewHead.t.sol) as extra source; no deployment was broadcast. + +Reproduction after initializing dependencies: + +```sh +forge build --sizes +make check-execute +forge test --offline --no-match-path 'test/review/*' -vv +forge test --offline --match-contract IndependentReviewHeadTest --match-test test_ReviewHead_ -vv +``` + +Forge 1.5.1-stable, solc 0.8.26, optimizer 833, via IR, Cancun. Full results and checksums are retained beside this report. diff --git a/plan/agw/research/validation-e704d5b/abi/AGW.json b/plan/agw/research/validation-e704d5b/abi/AGW.json new file mode 100644 index 00000000..8c82adbc --- /dev/null +++ b/plan/agw/research/validation-e704d5b/abi/AGW.json @@ -0,0 +1,1550 @@ +[ + { + "type": "constructor", + "inputs": [ + { + "name": "sessionEngine_", + "type": "address", + "internalType": "address" + }, + { + "name": "rulesPolicy_", + "type": "address", + "internalType": "address" + }, + { + "name": "sessionValidator_", + "type": "address", + "internalType": "address" + }, + { + "name": "universalGatewayPC_", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "receive", + "stateMutability": "payable" + }, + { + "type": "function", + "name": "RULES_POLICY", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "SESSION_ENGINE", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "SESSION_VALIDATOR", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "UNIVERSAL_GATEWAY_PC", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "accountId", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "agentOf", + "inputs": [ + { + "name": "rulesId", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "checkpointCount", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint64", + "internalType": "uint64" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "domainSeparator", + "inputs": [ + { + "name": "signerChainId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "execute", + "inputs": [ + { + "name": "mode", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "executionCalldata", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "executeAsAgent", + "inputs": [ + { + "name": "rulesId", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "mode", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "executionCalldata", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "executeWithSig", + "inputs": [ + { + "name": "mode", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "executionCalldata", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "intent", + "type": "tuple", + "internalType": "struct OwnerIntent", + "components": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "wallet", + "type": "address", + "internalType": "address" + }, + { + "name": "executor", + "type": "address", + "internalType": "address" + }, + { + "name": "index", + "type": "uint96", + "internalType": "uint96" + }, + { + "name": "sessionHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "mode", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "execCalldataHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "nonceKey", + "type": "uint192", + "internalType": "uint192" + }, + { + "name": "nonceSeq", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "grantNonce", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "deadline", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "signerChainId", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "sig", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "factory", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getNonce", + "inputs": [ + { + "name": "nonceKey", + "type": "uint192", + "internalType": "uint192" + } + ], + "outputs": [ + { + "name": "", + "type": "uint64", + "internalType": "uint64" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "grantNonce", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint64", + "internalType": "uint64" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "grantRules", + "inputs": [ + { + "name": "session", + "type": "tuple", + "internalType": "struct Session", + "components": [ + { + "name": "sessionValidator", + "type": "address", + "internalType": "contract ISessionValidator" + }, + { + "name": "sessionValidatorInitData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "erc7739Policies", + "type": "tuple", + "internalType": "struct ERC7739Data", + "components": [ + { + "name": "allowedERC7739Content", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNames", + "type": "string[]", + "internalType": "string[]" + } + ] + }, + { + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "actions", + "type": "tuple[]", + "internalType": "struct ActionData[]", + "components": [ + { + "name": "actionTargetSelector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "actionTarget", + "type": "address", + "internalType": "address" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "permitERC4337Paymaster", + "type": "bool", + "internalType": "bool" + } + ] + } + ], + "outputs": [ + { + "name": "rulesId", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "grantRulesWithSig", + "inputs": [ + { + "name": "session", + "type": "tuple", + "internalType": "struct Session", + "components": [ + { + "name": "sessionValidator", + "type": "address", + "internalType": "contract ISessionValidator" + }, + { + "name": "sessionValidatorInitData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "erc7739Policies", + "type": "tuple", + "internalType": "struct ERC7739Data", + "components": [ + { + "name": "allowedERC7739Content", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNames", + "type": "string[]", + "internalType": "string[]" + } + ] + }, + { + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "actions", + "type": "tuple[]", + "internalType": "struct ActionData[]", + "components": [ + { + "name": "actionTargetSelector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "actionTarget", + "type": "address", + "internalType": "address" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "permitERC4337Paymaster", + "type": "bool", + "internalType": "bool" + } + ] + }, + { + "name": "intent", + "type": "tuple", + "internalType": "struct OwnerIntent", + "components": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "wallet", + "type": "address", + "internalType": "address" + }, + { + "name": "executor", + "type": "address", + "internalType": "address" + }, + { + "name": "index", + "type": "uint96", + "internalType": "uint96" + }, + { + "name": "sessionHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "mode", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "execCalldataHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "nonceKey", + "type": "uint192", + "internalType": "uint192" + }, + { + "name": "nonceSeq", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "grantNonce", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "deadline", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "signerChainId", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "sig", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "rulesId", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "initializeAccount", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "installModule", + "inputs": [ + { + "name": "moduleTypeId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "module", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "isModuleInstalled", + "inputs": [ + { + "name": "moduleTypeId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "module", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isValidSignature", + "inputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "lastCheckpointBlock", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint64", + "internalType": "uint64" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "onERC1155BatchReceived", + "inputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "onERC1155Received", + "inputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "onERC721Received", + "inputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "owner", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "revokeAllRules", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "revokeRules", + "inputs": [ + { + "name": "rulesId", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "supportsExecutionMode", + "inputs": [ + { + "name": "mode", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "supportsInterface", + "inputs": [ + { + "name": "interfaceId", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "supportsModule", + "inputs": [ + { + "name": "moduleTypeId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "uninstallModule", + "inputs": [ + { + "name": "moduleTypeId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "module", + "type": "address", + "internalType": "address" + }, + { + "name": "deInitData", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "AccountInitialized", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "engine", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Checkpointed", + "inputs": [ + { + "name": "seq", + "type": "uint64", + "indexed": true, + "internalType": "uint64" + }, + { + "name": "kind", + "type": "uint8", + "indexed": false, + "internalType": "enum CheckpointKind" + }, + { + "name": "ref", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + }, + { + "name": "blockNumber", + "type": "uint64", + "indexed": false, + "internalType": "uint64" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ModuleInstalled", + "inputs": [ + { + "name": "moduleTypeId", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "module", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ModuleUninstalled", + "inputs": [ + { + "name": "moduleTypeId", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "module", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "OwnerExecuted", + "inputs": [ + { + "name": "mode", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "executionCalldataHash", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "OwnerExecutedWithSig", + "inputs": [ + { + "name": "mode", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "executionCalldataHash", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + }, + { + "name": "nonceKey", + "type": "uint192", + "indexed": false, + "internalType": "uint192" + }, + { + "name": "nonceSeq", + "type": "uint64", + "indexed": false, + "internalType": "uint64" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RulesActionAuthorized", + "inputs": [ + { + "name": "rulesId", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "agent", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "callsHash", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RulesGranted", + "inputs": [ + { + "name": "rulesId", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "mode", + "type": "uint8", + "indexed": false, + "internalType": "enum RulesType" + }, + { + "name": "chainHash", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "chainNamespace", + "type": "string", + "indexed": false, + "internalType": "string" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RulesRevoked", + "inputs": [ + { + "name": "rulesId", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "UninstallCallbackFailed", + "inputs": [ + { + "name": "module", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "AlreadyInitialized", + "inputs": [] + }, + { + "type": "error", + "name": "CallerIsNotAgent", + "inputs": [ + { + "name": "rulesId", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "caller", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "CallerIsNotFactory", + "inputs": [] + }, + { + "type": "error", + "name": "CallerIsNotOwner", + "inputs": [] + }, + { + "type": "error", + "name": "DuplicateAction", + "inputs": [ + { + "name": "target", + "type": "address", + "internalType": "address" + }, + { + "name": "selector", + "type": "bytes4", + "internalType": "bytes4" + } + ] + }, + { + "type": "error", + "name": "EmptyChain", + "inputs": [] + }, + { + "type": "error", + "name": "EngineStillHoldsPermissions", + "inputs": [] + }, + { + "type": "error", + "name": "ExecutorMismatch", + "inputs": [ + { + "name": "expected", + "type": "address", + "internalType": "address" + }, + { + "name": "actual", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ForbiddenActionSelector", + "inputs": [ + { + "name": "selector", + "type": "bytes4", + "internalType": "bytes4" + } + ] + }, + { + "type": "error", + "name": "ForbiddenActionTarget", + "inputs": [ + { + "name": "target", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ForbiddenDispatchTarget", + "inputs": [ + { + "name": "target", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "InconsistentChain", + "inputs": [ + { + "name": "actionIndex", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "IntentExecMismatch", + "inputs": [ + { + "name": "actualCalldataHash", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "IntentGrantNonceMismatch", + "inputs": [ + { + "name": "expected", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "provided", + "type": "uint64", + "internalType": "uint64" + } + ] + }, + { + "type": "error", + "name": "IntentSessionMismatch", + "inputs": [ + { + "name": "actual", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "IntentWalletMismatch", + "inputs": [ + { + "name": "expected", + "type": "address", + "internalType": "address" + }, + { + "name": "provided", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "InvalidModuleAddress", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidNonce", + "inputs": [ + { + "name": "nonceKey", + "type": "uint192", + "internalType": "uint192" + }, + { + "name": "expected", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "provided", + "type": "uint64", + "internalType": "uint64" + } + ] + }, + { + "type": "error", + "name": "InvalidOwnerSignature", + "inputs": [] + }, + { + "type": "error", + "name": "MalformedBatchCalldata", + "inputs": [] + }, + { + "type": "error", + "name": "MalformedSessionShape", + "inputs": [] + }, + { + "type": "error", + "name": "ModuleAlreadyInstalled", + "inputs": [ + { + "name": "module", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "OutsideTimeWindow", + "inputs": [ + { + "name": "validAfter", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "validUntil", + "type": "uint48", + "internalType": "uint48" + } + ] + }, + { + "type": "error", + "name": "OwnerLaneRequired", + "inputs": [ + { + "name": "nonceKey", + "type": "uint192", + "internalType": "uint192" + } + ] + }, + { + "type": "error", + "name": "OwnerSigExpired", + "inputs": [ + { + "name": "deadline", + "type": "uint48", + "internalType": "uint48" + } + ] + }, + { + "type": "error", + "name": "ReentrancyGuardReentrantCall", + "inputs": [] + }, + { + "type": "error", + "name": "RulesTypeMismatch", + "inputs": [ + { + "name": "derived", + "type": "uint8", + "internalType": "enum RulesType" + }, + { + "name": "actionIndex", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "target", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "TooManyActions", + "inputs": [ + { + "name": "count", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "UnknownPermission", + "inputs": [ + { + "name": "rulesId", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "UnsupportedExecutionMode", + "inputs": [] + }, + { + "type": "error", + "name": "UnsupportedModuleType", + "inputs": [ + { + "name": "moduleTypeId", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "ValidationFailed", + "inputs": [ + { + "name": "authorizer", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ValidatorNotInstalled", + "inputs": [ + { + "name": "validator", + "type": "address", + "internalType": "address" + } + ] + } +] diff --git a/plan/agw/research/validation-e704d5b/abi/AGWFactory.json b/plan/agw/research/validation-e704d5b/abi/AGWFactory.json new file mode 100644 index 00000000..30435540 --- /dev/null +++ b/plan/agw/research/validation-e704d5b/abi/AGWFactory.json @@ -0,0 +1,1105 @@ +[ + { + "type": "constructor", + "inputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "DEFAULT_ADMIN_ROLE", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "OPERATOR_ROLE", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "PAUSER_ROLE", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "UPGRADE_INTERFACE_VERSION", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "acceptDefaultAdminTransfer", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "beginDefaultAdminTransfer", + "inputs": [ + { + "name": "newAdmin", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "cancelDefaultAdminTransfer", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "changeDefaultAdminDelay", + "inputs": [ + { + "name": "newDelay", + "type": "uint48", + "internalType": "uint48" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "defaultAdmin", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "defaultAdminDelay", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint48", + "internalType": "uint48" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "defaultAdminDelayIncreaseWait", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint48", + "internalType": "uint48" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "deployWallet", + "inputs": [ + { + "name": "label", + "type": "string", + "internalType": "string" + } + ], + "outputs": [ + { + "name": "wallet", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "deployWalletWithSig", + "inputs": [ + { + "name": "intent", + "type": "tuple", + "internalType": "struct OwnerIntent", + "components": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "wallet", + "type": "address", + "internalType": "address" + }, + { + "name": "executor", + "type": "address", + "internalType": "address" + }, + { + "name": "index", + "type": "uint96", + "internalType": "uint96" + }, + { + "name": "sessionHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "mode", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "execCalldataHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "nonceKey", + "type": "uint192", + "internalType": "uint192" + }, + { + "name": "nonceSeq", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "grantNonce", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "deadline", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "signerChainId", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "sig", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "label", + "type": "string", + "internalType": "string" + } + ], + "outputs": [ + { + "name": "wallet", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "domainSeparator", + "inputs": [ + { + "name": "signerChainId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getRoleAdmin", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "grantRole", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "hasRole", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "indexOf", + "inputs": [ + { + "name": "wallet", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "initialize", + "inputs": [ + { + "name": "admin", + "type": "address", + "internalType": "address" + }, + { + "name": "walletImplementation_", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "isWallet", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "owner", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "ownerOf", + "inputs": [ + { + "name": "wallet", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "pause", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "paused", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "pendingDefaultAdmin", + "inputs": [], + "outputs": [ + { + "name": "newAdmin", + "type": "address", + "internalType": "address" + }, + { + "name": "schedule", + "type": "uint48", + "internalType": "uint48" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "pendingDefaultAdminDelay", + "inputs": [], + "outputs": [ + { + "name": "newDelay", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "schedule", + "type": "uint48", + "internalType": "uint48" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "predictWallet", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "index", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "wallet", + "type": "address", + "internalType": "address" + }, + { + "name": "deployed", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "proxiableUUID", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "renounceRole", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "revokeRole", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "rollbackDefaultAdminDelay", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "supportsInterface", + "inputs": [ + { + "name": "interfaceId", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "unpause", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "upgradeToAndCall", + "inputs": [ + { + "name": "newImplementation", + "type": "address", + "internalType": "address" + }, + { + "name": "data", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "walletCount", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "walletImplementation", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "event", + "name": "DefaultAdminDelayChangeCanceled", + "inputs": [], + "anonymous": false + }, + { + "type": "event", + "name": "DefaultAdminDelayChangeScheduled", + "inputs": [ + { + "name": "newDelay", + "type": "uint48", + "indexed": false, + "internalType": "uint48" + }, + { + "name": "effectSchedule", + "type": "uint48", + "indexed": false, + "internalType": "uint48" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "DefaultAdminTransferCanceled", + "inputs": [], + "anonymous": false + }, + { + "type": "event", + "name": "DefaultAdminTransferScheduled", + "inputs": [ + { + "name": "newAdmin", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "acceptSchedule", + "type": "uint48", + "indexed": false, + "internalType": "uint48" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Initialized", + "inputs": [ + { + "name": "version", + "type": "uint64", + "indexed": false, + "internalType": "uint64" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Paused", + "inputs": [ + { + "name": "account", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RoleAdminChanged", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "previousAdminRole", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "newAdminRole", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RoleGranted", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RoleRevoked", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Unpaused", + "inputs": [ + { + "name": "account", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Upgraded", + "inputs": [ + { + "name": "implementation", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "WalletDeployed", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "index", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "wallet", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "label", + "type": "string", + "indexed": false, + "internalType": "string" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "AccessControlBadConfirmation", + "inputs": [] + }, + { + "type": "error", + "name": "AccessControlEnforcedDefaultAdminDelay", + "inputs": [ + { + "name": "schedule", + "type": "uint48", + "internalType": "uint48" + } + ] + }, + { + "type": "error", + "name": "AccessControlEnforcedDefaultAdminRules", + "inputs": [] + }, + { + "type": "error", + "name": "AccessControlInvalidDefaultAdmin", + "inputs": [ + { + "name": "defaultAdmin", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "AccessControlUnauthorizedAccount", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "neededRole", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "AddressEmptyCode", + "inputs": [ + { + "name": "target", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "CloneArgumentsTooLong", + "inputs": [] + }, + { + "type": "error", + "name": "Create2EmptyBytecode", + "inputs": [] + }, + { + "type": "error", + "name": "ERC1967InvalidImplementation", + "inputs": [ + { + "name": "implementation", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ERC1967NonPayable", + "inputs": [] + }, + { + "type": "error", + "name": "EnforcedPause", + "inputs": [] + }, + { + "type": "error", + "name": "ExecutorMismatch", + "inputs": [ + { + "name": "expected", + "type": "address", + "internalType": "address" + }, + { + "name": "actual", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ExpectedPause", + "inputs": [] + }, + { + "type": "error", + "name": "FailedCall", + "inputs": [] + }, + { + "type": "error", + "name": "FailedDeployment", + "inputs": [] + }, + { + "type": "error", + "name": "ImplementationNotSet", + "inputs": [] + }, + { + "type": "error", + "name": "IndexMismatch", + "inputs": [ + { + "name": "expected", + "type": "uint96", + "internalType": "uint96" + }, + { + "name": "provided", + "type": "uint96", + "internalType": "uint96" + } + ] + }, + { + "type": "error", + "name": "IndexOutOfRange", + "inputs": [ + { + "name": "index", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "next", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "InsufficientBalance", + "inputs": [ + { + "name": "balance", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "needed", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "IntentWalletMismatch", + "inputs": [ + { + "name": "expected", + "type": "address", + "internalType": "address" + }, + { + "name": "provided", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "InvalidInitialization", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidOwnerSignature", + "inputs": [] + }, + { + "type": "error", + "name": "NotAWallet", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "NotInitializing", + "inputs": [] + }, + { + "type": "error", + "name": "SafeCastOverflowedUintDowncast", + "inputs": [ + { + "name": "bits", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "SignatureExpired", + "inputs": [ + { + "name": "deadline", + "type": "uint48", + "internalType": "uint48" + } + ] + }, + { + "type": "error", + "name": "UUPSUnauthorizedCallContext", + "inputs": [] + }, + { + "type": "error", + "name": "UUPSUnsupportedProxiableUUID", + "inputs": [ + { + "name": "slot", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "ZeroAddress", + "inputs": [] + } +] diff --git a/plan/agw/research/validation-e704d5b/abi/AgentValidator.json b/plan/agw/research/validation-e704d5b/abi/AgentValidator.json new file mode 100644 index 00000000..86830881 --- /dev/null +++ b/plan/agw/research/validation-e704d5b/abi/AgentValidator.json @@ -0,0 +1,141 @@ +[ + { + "type": "function", + "name": "isInitialized", + "inputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "isModuleType", + "inputs": [ + { + "name": "moduleTypeId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "onInstall", + "inputs": [ + { + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "onUninstall", + "inputs": [ + { + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "validateConfig", + "inputs": [ + { + "name": "data", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "validateSignatureWithData", + "inputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "sig", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "data", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "validSig", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "pure" + }, + { + "type": "error", + "name": "AlreadyInitialized", + "inputs": [ + { + "name": "smartAccount", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "MalformedConfig", + "inputs": [] + }, + { + "type": "error", + "name": "NotInitialized", + "inputs": [ + { + "name": "smartAccount", + "type": "address", + "internalType": "address" + } + ] + } +] diff --git a/plan/agw/research/validation-e704d5b/abi/SmartSession.json b/plan/agw/research/validation-e704d5b/abi/SmartSession.json new file mode 100644 index 00000000..bdf678eb --- /dev/null +++ b/plan/agw/research/validation-e704d5b/abi/SmartSession.json @@ -0,0 +1,1957 @@ +[ + { + "type": "function", + "name": "areActionsEnabled", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "actions", + "type": "tuple[]", + "internalType": "struct ActionData[]", + "components": [ + { + "name": "actionTargetSelector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "actionTarget", + "type": "address", + "internalType": "address" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "areERC1271PoliciesEnabled", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "areUserOpPoliciesEnabled", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "disableActionId", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "actionId", + "type": "bytes32", + "internalType": "ActionId" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "disableActionPolicies", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "actionId", + "type": "bytes32", + "internalType": "ActionId" + }, + { + "name": "policies", + "type": "address[]", + "internalType": "address[]" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "disableERC1271Policies", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "policies", + "type": "address[]", + "internalType": "address[]" + }, + { + "name": "contexts", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNames", + "type": "string[]", + "internalType": "string[]" + } + ] + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "disableUserOpPolicies", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "policies", + "type": "address[]", + "internalType": "address[]" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "enableActionPolicies", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct ActionData[]", + "components": [ + { + "name": "actionTargetSelector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "actionTarget", + "type": "address", + "internalType": "address" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "enableERC1271Policies", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "erc1271Policies", + "type": "tuple", + "internalType": "struct ERC7739Data", + "components": [ + { + "name": "allowedERC7739Content", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNames", + "type": "string[]", + "internalType": "string[]" + } + ] + }, + { + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "enableSessions", + "inputs": [ + { + "name": "sessions", + "type": "tuple[]", + "internalType": "struct Session[]", + "components": [ + { + "name": "sessionValidator", + "type": "address", + "internalType": "contract ISessionValidator" + }, + { + "name": "sessionValidatorInitData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "erc7739Policies", + "type": "tuple", + "internalType": "struct ERC7739Data", + "components": [ + { + "name": "allowedERC7739Content", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNames", + "type": "string[]", + "internalType": "string[]" + } + ] + }, + { + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "actions", + "type": "tuple[]", + "internalType": "struct ActionData[]", + "components": [ + { + "name": "actionTargetSelector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "actionTarget", + "type": "address", + "internalType": "address" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "permitERC4337Paymaster", + "type": "bool", + "internalType": "bool" + } + ] + } + ], + "outputs": [ + { + "name": "permissionIds", + "type": "bytes32[]", + "internalType": "PermissionId[]" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "enableUserOpPolicies", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "getActionPolicies", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "actionId", + "type": "bytes32", + "internalType": "ActionId" + } + ], + "outputs": [ + { + "name": "", + "type": "address[]", + "internalType": "address[]" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getERC1271Policies", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ], + "outputs": [ + { + "name": "", + "type": "address[]", + "internalType": "address[]" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getEnabledActions", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes32[]", + "internalType": "bytes32[]" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getEnabledERC7739Content", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ], + "outputs": [ + { + "name": "enabledERC7739ContentHashes", + "type": "tuple[]", + "internalType": "struct ERC7739ContextHashes[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNameHashes", + "type": "bytes32[]", + "internalType": "bytes32[]" + } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getNonce", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getPermissionIDs", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "permissionIds", + "type": "bytes32[]", + "internalType": "PermissionId[]" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getPermissionId", + "inputs": [ + { + "name": "session", + "type": "tuple", + "internalType": "struct Session", + "components": [ + { + "name": "sessionValidator", + "type": "address", + "internalType": "contract ISessionValidator" + }, + { + "name": "sessionValidatorInitData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "erc7739Policies", + "type": "tuple", + "internalType": "struct ERC7739Data", + "components": [ + { + "name": "allowedERC7739Content", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNames", + "type": "string[]", + "internalType": "string[]" + } + ] + }, + { + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "actions", + "type": "tuple[]", + "internalType": "struct ActionData[]", + "components": [ + { + "name": "actionTargetSelector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "actionTarget", + "type": "address", + "internalType": "address" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "permitERC4337Paymaster", + "type": "bool", + "internalType": "bool" + } + ] + } + ], + "outputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "getSessionDigest", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "data", + "type": "tuple", + "internalType": "struct Session", + "components": [ + { + "name": "sessionValidator", + "type": "address", + "internalType": "contract ISessionValidator" + }, + { + "name": "sessionValidatorInitData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "erc7739Policies", + "type": "tuple", + "internalType": "struct ERC7739Data", + "components": [ + { + "name": "allowedERC7739Content", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNames", + "type": "string[]", + "internalType": "string[]" + } + ] + }, + { + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "actions", + "type": "tuple[]", + "internalType": "struct ActionData[]", + "components": [ + { + "name": "actionTargetSelector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "actionTarget", + "type": "address", + "internalType": "address" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "permitERC4337Paymaster", + "type": "bool", + "internalType": "bool" + } + ] + }, + { + "name": "mode", + "type": "uint8", + "internalType": "enum SmartSessionMode" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getSessionValidatorAndConfig", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ], + "outputs": [ + { + "name": "sessionValidator", + "type": "address", + "internalType": "address" + }, + { + "name": "sessionValidatorData", + "type": "bytes", + "internalType": "bytes" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getUserOpPolicies", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ], + "outputs": [ + { + "name": "", + "type": "address[]", + "internalType": "address[]" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isActionIdEnabled", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "actionId", + "type": "bytes32", + "internalType": "ActionId" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isActionPolicyEnabled", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "actionId", + "type": "bytes32", + "internalType": "ActionId" + }, + { + "name": "policy", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isERC1271PolicyEnabled", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "policy", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isERC7739ContentEnabled", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "content", + "type": "string", + "internalType": "string" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isISessionValidatorSet", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isInitialized", + "inputs": [ + { + "name": "smartAccount", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isModuleType", + "inputs": [ + { + "name": "typeID", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "isPermissionEnabled", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isUserOpPolicyEnabled", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "policy", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isValidSignatureWithSender", + "inputs": [ + { + "name": "sender", + "type": "address", + "internalType": "address" + }, + { + "name": "hash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "signature", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "result", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "onInstall", + "inputs": [ + { + "name": "data", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "onUninstall", + "inputs": [ + { + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "removeSession", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "revokeEnableSignature", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setPermit4337Paymaster", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "enabled", + "type": "bool", + "internalType": "bool" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "validateUserOp", + "inputs": [ + { + "name": "userOp", + "type": "tuple", + "internalType": "struct PackedUserOperation", + "components": [ + { + "name": "sender", + "type": "address", + "internalType": "address" + }, + { + "name": "nonce", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "initCode", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "callData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "accountGasLimits", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "preVerificationGas", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "gasFees", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "paymasterAndData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "signature", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "userOpHash", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [ + { + "name": "vd", + "type": "uint256", + "internalType": "ValidationData" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "ActionIdDisabled", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" + }, + { + "name": "actionId", + "type": "bytes32", + "indexed": false, + "internalType": "ActionId" + }, + { + "name": "smartAccount", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "NonceIterated", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" + }, + { + "name": "account", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "newValue", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "PermissionIdPermit4337Paymaster", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" + }, + { + "name": "smartAccount", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "enabled", + "type": "bool", + "indexed": false, + "internalType": "bool" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "PolicyDisabled", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" + }, + { + "name": "policyType", + "type": "uint8", + "indexed": false, + "internalType": "enum PolicyType" + }, + { + "name": "policy", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "smartAccount", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "PolicyEnabled", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" + }, + { + "name": "policyType", + "type": "uint8", + "indexed": false, + "internalType": "enum PolicyType" + }, + { + "name": "policy", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "smartAccount", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "SessionCreated", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" + }, + { + "name": "account", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "SessionRemoved", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" + }, + { + "name": "smartAccount", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "SessionValidatorDisabled", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" + }, + { + "name": "sessionValidator", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "smartAccount", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "SessionValidatorEnabled", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" + }, + { + "name": "sessionValidator", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "smartAccount", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "AssociatedArray_OutOfBounds", + "inputs": [ + { + "name": "index", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "ChainIdMismatch", + "inputs": [ + { + "name": "providedChainId", + "type": "uint64", + "internalType": "uint64" + } + ] + }, + { + "type": "error", + "name": "ChainIdMismatch", + "inputs": [ + { + "name": "providedChainId", + "type": "uint64", + "internalType": "uint64" + } + ] + }, + { + "type": "error", + "name": "ForbiddenValidationData", + "inputs": [] + }, + { + "type": "error", + "name": "HashIndexOutOfBounds", + "inputs": [ + { + "name": "index", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "HashMismatch", + "inputs": [ + { + "name": "providedHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "computedHash", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "HashMismatch", + "inputs": [ + { + "name": "providedHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "computedHash", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "InvalidActionId", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidCallTarget", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidData", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidEnableSignature", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "hash", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "InvalidISessionValidator", + "inputs": [ + { + "name": "sessionValidator", + "type": "address", + "internalType": "contract ISessionValidator" + } + ] + }, + { + "type": "error", + "name": "InvalidMode", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidPermissionId", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ] + }, + { + "type": "error", + "name": "InvalidSelfCall", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidSession", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ] + }, + { + "type": "error", + "name": "InvalidSessionKeySignature", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "sessionValidator", + "type": "address", + "internalType": "address" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "userOpHash", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "InvalidTarget", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidUserOpSender", + "inputs": [ + { + "name": "sender", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "NoExecutionsInBatch", + "inputs": [] + }, + { + "type": "error", + "name": "NoPoliciesSet", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ] + }, + { + "type": "error", + "name": "PartlyEnabledActions", + "inputs": [] + }, + { + "type": "error", + "name": "PartlyEnabledPolicies", + "inputs": [] + }, + { + "type": "error", + "name": "PaymasterValidationNotEnabled", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ] + }, + { + "type": "error", + "name": "PolicyViolation", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "policy", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "SignerNotFound", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "SignerNotFound", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "SmartSessionModuleAlreadyInstalled", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "UnsupportedCallType", + "inputs": [ + { + "name": "callType", + "type": "bytes1", + "internalType": "CallType" + } + ] + }, + { + "type": "error", + "name": "UnsupportedExecutionType", + "inputs": [] + }, + { + "type": "error", + "name": "UnsupportedPolicy", + "inputs": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "UnsupportedSmartSessionMode", + "inputs": [ + { + "name": "mode", + "type": "uint8", + "internalType": "enum SmartSessionMode" + } + ] + } +] diff --git a/plan/agw/research/validation-e704d5b/abi/UniversalRulesPolicy.json b/plan/agw/research/validation-e704d5b/abi/UniversalRulesPolicy.json new file mode 100644 index 00000000..4029c375 --- /dev/null +++ b/plan/agw/research/validation-e704d5b/abi/UniversalRulesPolicy.json @@ -0,0 +1,2066 @@ +[ + { + "type": "constructor", + "inputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "SEND_OUTBOUND_SELECTOR", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "SESSION_ENGINE", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "UNIVERSAL_EXECUTOR_MODULE", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "UNIVERSAL_GATEWAY_PC", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "assertSpent", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "expectedValueSpent", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "expectedAmountSpent", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "expectedCalls", + "type": "uint32", + "internalType": "uint32" + } + ], + "outputs": [], + "stateMutability": "view" + }, + { + "type": "function", + "name": "assertSpent", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "expectedSpent", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "view" + }, + { + "type": "function", + "name": "checkAction", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "target", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "data", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "creditRevert", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "outboundTxId", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "getConfig", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "tuple", + "internalType": "struct Config", + "components": [ + { + "name": "initialized", + "type": "bool", + "internalType": "bool" + }, + { + "name": "validUntil", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "destChainHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "expectedCEA", + "type": "address", + "internalType": "address" + }, + { + "name": "asset", + "type": "address", + "internalType": "address" + }, + { + "name": "maxAmountPerCall", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxAmountTotal", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxPCPerCall", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "spent", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "allowedCalls", + "type": "tuple[]", + "internalType": "struct AllowedCall[]", + "components": [ + { + "name": "target", + "type": "address", + "internalType": "address" + }, + { + "name": "selector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "beneficiaryOffset", + "type": "uint16", + "internalType": "uint16" + }, + { + "name": "hasBeneficiary", + "type": "bool", + "internalType": "bool" + }, + { + "name": "maxValue", + "type": "uint256", + "internalType": "uint256" + } + ] + } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getMode", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "tuple", + "internalType": "struct ModeSlot", + "components": [ + { + "name": "initialized", + "type": "bool", + "internalType": "bool" + }, + { + "name": "mode", + "type": "uint8", + "internalType": "enum RulesType" + }, + { + "name": "vm", + "type": "uint8", + "internalType": "enum VmFamily" + }, + { + "name": "chainHash", + "type": "bytes32", + "internalType": "bytes32" + } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getNativeConfig", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "tuple", + "internalType": "struct NativeConfig", + "components": [ + { + "name": "initialized", + "type": "bool", + "internalType": "bool" + }, + { + "name": "validUntil", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "target", + "type": "address", + "internalType": "address" + }, + { + "name": "selector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "maxValuePerCall", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxValueTotal", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "valueSpent", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amount", + "type": "tuple", + "internalType": "struct AmountRule", + "components": [ + { + "name": "enabled", + "type": "bool", + "internalType": "bool" + }, + { + "name": "offset", + "type": "uint16", + "internalType": "uint16" + }, + { + "name": "maxPerCall", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxTotal", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "amountSpent", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxCalls", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "callsUsed", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "pins", + "type": "tuple[]", + "internalType": "struct ArgPin[]", + "components": [ + { + "name": "offset", + "type": "uint16", + "internalType": "uint16" + }, + { + "name": "expected", + "type": "bytes32", + "internalType": "bytes32" + } + ] + } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getSvmConfig", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "tuple", + "internalType": "struct SvmConfig", + "components": [ + { + "name": "initialized", + "type": "bool", + "internalType": "bool" + }, + { + "name": "validUntil", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "expectedCEA", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "gatewayProgram", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "asset", + "type": "address", + "internalType": "address" + }, + { + "name": "maxAmountPerCall", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxAmountTotal", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxPCPerCall", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "spent", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "ceaAccounts", + "type": "bytes32[]", + "internalType": "bytes32[]" + }, + { + "name": "programs", + "type": "tuple[]", + "internalType": "struct AllowedProgram[]", + "components": [ + { + "name": "program", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "discriminator", + "type": "bytes8", + "internalType": "bytes8" + }, + { + "name": "discriminatorLen", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "dataless", + "type": "bool", + "internalType": "bool" + }, + { + "name": "maxAccounts", + "type": "uint8", + "internalType": "uint8" + } + ] + }, + { + "name": "pins", + "type": "tuple[]", + "internalType": "struct SvmAccountPin[]", + "components": [ + { + "name": "ruleIndex", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "accountIndex", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "expected", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "name": "dataPins", + "type": "tuple[]", + "internalType": "struct SvmDataPin[]", + "components": [ + { + "name": "ruleIndex", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "fromEnd", + "type": "bool", + "internalType": "bool" + }, + { + "name": "offset", + "type": "uint16", + "internalType": "uint16" + }, + { + "name": "offsetB", + "type": "uint16", + "internalType": "uint16" + }, + { + "name": "len", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "mode", + "type": "uint8", + "internalType": "enum SvmDataPinMode" + }, + { + "name": "expected", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "num", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "den", + "type": "uint64", + "internalType": "uint64" + } + ] + } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "initialize", + "inputs": [ + { + "name": "universalGatewayPC", + "type": "address", + "internalType": "address" + }, + { + "name": "universalExecutorModule", + "type": "address", + "internalType": "address" + }, + { + "name": "sessionEngine", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "initializeWithMultiplexer", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "configId", + "type": "bytes32", + "internalType": "ConfigId" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "isCredited", + "inputs": [ + { + "name": "outboundTxId", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "pushChainHash", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "supportsInterface", + "inputs": [ + { + "name": "iid", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "version", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "pure" + }, + { + "type": "event", + "name": "Initialized", + "inputs": [ + { + "name": "version", + "type": "uint64", + "indexed": false, + "internalType": "uint64" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "NativeCallMetered", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "indexed": true, + "internalType": "ConfigId" + }, + { + "name": "multiplexer", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "OutboundMetered", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "indexed": true, + "internalType": "ConfigId" + }, + { + "name": "multiplexer", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "PolicySet", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "indexed": false, + "internalType": "ConfigId" + }, + { + "name": "multiplexer", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "account", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RevertCredited", + "inputs": [ + { + "name": "outboundTxId", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "id", + "type": "bytes32", + "indexed": true, + "internalType": "ConfigId" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "amountApplied", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RulesConfigured", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "indexed": true, + "internalType": "ConfigId" + }, + { + "name": "multiplexer", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "mode", + "type": "uint8", + "indexed": false, + "internalType": "enum RulesType" + }, + { + "name": "vm", + "type": "uint8", + "indexed": false, + "internalType": "enum VmFamily" + }, + { + "name": "chainHash", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "AllowListOutOfRange", + "inputs": [ + { + "name": "length", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "AlreadyCredited", + "inputs": [ + { + "name": "outboundTxId", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "AlreadyInitialized", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" + } + ] + }, + { + "type": "error", + "name": "AmbiguousRule", + "inputs": [ + { + "name": "i", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "j", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "AmountExceedsCap", + "inputs": [ + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "cap", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "AmountExceedsU64", + "inputs": [ + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "ArgPinMismatch", + "inputs": [ + { + "name": "actual", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "index", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "expected", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "AssetMismatch", + "inputs": [ + { + "name": "expected", + "type": "address", + "internalType": "address" + }, + { + "name": "actual", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "BatchSizeOutOfRange", + "inputs": [ + { + "name": "count", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "BeneficiaryMismatch", + "inputs": [ + { + "name": "expected", + "type": "address", + "internalType": "address" + }, + { + "name": "actual", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "CallLimitReached", + "inputs": [ + { + "name": "callsUsed", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "maxCalls", + "type": "uint32", + "internalType": "uint32" + } + ] + }, + { + "type": "error", + "name": "CallNotAllowed", + "inputs": [ + { + "name": "target", + "type": "address", + "internalType": "address" + }, + { + "name": "selector", + "type": "bytes4", + "internalType": "bytes4" + } + ] + }, + { + "type": "error", + "name": "CalldataTooShort", + "inputs": [ + { + "name": "length", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "CalldataTooShortForAmount", + "inputs": [ + { + "name": "actualLength", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "needed", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "CalldataTooShortForPin", + "inputs": [ + { + "name": "actualLength", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "index", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "needed", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "CallerIsNotUEModule", + "inputs": [ + { + "name": "caller", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "CeaAccountAtUnpinnedIndex", + "inputs": [ + { + "name": "accountIndex", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "account", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "CeaAccountsMissExpectedCEA", + "inputs": [] + }, + { + "type": "error", + "name": "ChainMismatch", + "inputs": [ + { + "name": "declared", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "assetChain", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "DiscriminatorLenOutOfRange", + "inputs": [ + { + "name": "rule", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "len", + "type": "uint8", + "internalType": "uint8" + } + ] + }, + { + "type": "error", + "name": "DuplicateSvmPin", + "inputs": [ + { + "name": "first", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "second", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "EmptyChain", + "inputs": [] + }, + { + "type": "error", + "name": "ForbiddenInnerTarget", + "inputs": [ + { + "name": "target", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ForbiddenProgramInAllowList", + "inputs": [ + { + "name": "rule", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "program", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "ForbiddenTargetProgram", + "inputs": [ + { + "name": "program", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "InnerValueExceedsAllowance", + "inputs": [ + { + "name": "index", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxValue", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "InvalidAsset", + "inputs": [ + { + "name": "asset", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "InvalidCeaAccount", + "inputs": [ + { + "name": "index", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "InvalidConfigField", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidExpiry", + "inputs": [ + { + "name": "validUntil", + "type": "uint48", + "internalType": "uint48" + } + ] + }, + { + "type": "error", + "name": "InvalidInitialization", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidRevertRecipient", + "inputs": [ + { + "name": "expected", + "type": "address", + "internalType": "address" + }, + { + "name": "actual", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "InvalidSelector", + "inputs": [ + { + "name": "selector", + "type": "bytes4", + "internalType": "bytes4" + } + ] + }, + { + "type": "error", + "name": "InvalidSvmConfigField", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidTarget", + "inputs": [ + { + "name": "target", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "MalformedInnerCalldata", + "inputs": [] + }, + { + "type": "error", + "name": "MalformedOutboundRequest", + "inputs": [ + { + "name": "length", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "MalformedSvmPayload", + "inputs": [ + { + "name": "code", + "type": "uint8", + "internalType": "uint8" + } + ] + }, + { + "type": "error", + "name": "NativeAmountExceedsCap", + "inputs": [ + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "cap", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "NativeTargetIsGateway", + "inputs": [ + { + "name": "target", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "NativeTargetZero", + "inputs": [] + }, + { + "type": "error", + "name": "NotInitialized", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "NotInitializing", + "inputs": [] + }, + { + "type": "error", + "name": "PCValueExceedsCap", + "inputs": [ + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "cap", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "PayloadNotMulticall", + "inputs": [] + }, + { + "type": "error", + "name": "PolicyNotInitialized", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" + }, + { + "name": "multiplexer", + "type": "address", + "internalType": "address" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ProgramListOutOfRange", + "inputs": [ + { + "name": "length", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "ProgramNotAllowed", + "inputs": [ + { + "name": "program", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "discriminator", + "type": "bytes8", + "internalType": "bytes8" + } + ] + }, + { + "type": "error", + "name": "RecipientMustBeEmpty", + "inputs": [] + }, + { + "type": "error", + "name": "RecipientNotPubkey", + "inputs": [ + { + "name": "length", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "RecipientTargetMismatch", + "inputs": [ + { + "name": "recipient", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "target", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "RuleWithoutPin", + "inputs": [ + { + "name": "rule", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "RulesExpired", + "inputs": [ + { + "name": "validUntil", + "type": "uint48", + "internalType": "uint48" + } + ] + }, + { + "type": "error", + "name": "SelectorMismatch", + "inputs": [ + { + "name": "actual", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "expected", + "type": "bytes4", + "internalType": "bytes4" + } + ] + }, + { + "type": "error", + "name": "SpentMismatch", + "inputs": [ + { + "name": "expected", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "actual", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "SvmAccountCountBelowPin", + "inputs": [ + { + "name": "pin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "count", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "needed", + "type": "uint8", + "internalType": "uint8" + } + ] + }, + { + "type": "error", + "name": "SvmAccountCountMismatch", + "inputs": [ + { + "name": "count", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "expected", + "type": "uint8", + "internalType": "uint8" + } + ] + }, + { + "type": "error", + "name": "SvmAccountPinMismatch", + "inputs": [ + { + "name": "pin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "accountIndex", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "expected", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "actual", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "SvmAccountsOutOfRange", + "inputs": [ + { + "name": "count", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "SvmDataCeilingExceeded", + "inputs": [ + { + "name": "pin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "actual", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "ceiling", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "SvmDataFloorNotMet", + "inputs": [ + { + "name": "pin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "actual", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "floor", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "SvmDataPinInvalid", + "inputs": [ + { + "name": "pin", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "SvmDataPinMismatch", + "inputs": [ + { + "name": "pin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "expected", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "actual", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "SvmDataRatioNotMet", + "inputs": [ + { + "name": "pin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "a", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "b", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "num", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "den", + "type": "uint64", + "internalType": "uint64" + } + ] + }, + { + "type": "error", + "name": "SvmDataTooShortForPin", + "inputs": [ + { + "name": "pin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "ixLen", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "SvmInstructionNotExecute", + "inputs": [ + { + "name": "instructionId", + "type": "uint8", + "internalType": "uint8" + } + ] + }, + { + "type": "error", + "name": "SvmIxDataTooLong", + "inputs": [ + { + "name": "length", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "SvmMaxAccountsOutOfRange", + "inputs": [ + { + "name": "rule", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxAccounts", + "type": "uint8", + "internalType": "uint8" + } + ] + }, + { + "type": "error", + "name": "SvmPayloadEmpty", + "inputs": [] + }, + { + "type": "error", + "name": "SvmPinIndexOutOfRange", + "inputs": [ + { + "name": "pin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "accountIndex", + "type": "uint8", + "internalType": "uint8" + } + ] + }, + { + "type": "error", + "name": "SvmPinRuleOutOfRange", + "inputs": [ + { + "name": "pin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "rule", + "type": "uint8", + "internalType": "uint8" + } + ] + }, + { + "type": "error", + "name": "TargetMismatch", + "inputs": [ + { + "name": "actual", + "type": "address", + "internalType": "address" + }, + { + "name": "expected", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "TooManyCeaAccounts", + "inputs": [ + { + "name": "count", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "TooManyPins", + "inputs": [ + { + "name": "count", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "TooManySvmDataPins", + "inputs": [ + { + "name": "count", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "TooManySvmPins", + "inputs": [ + { + "name": "count", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "TotalNativeAmountExceeded", + "inputs": [ + { + "name": "newSpent", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "cap", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "TotalSpendCapExceeded", + "inputs": [ + { + "name": "wouldBeTotal", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "cap", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "TotalValueExceeded", + "inputs": [ + { + "name": "newSpent", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "cap", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "UncappedGasSwapRejected", + "inputs": [] + }, + { + "type": "error", + "name": "UnsupportedNamespace", + "inputs": [ + { + "name": "chainHash", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "ValueExceedsCap", + "inputs": [ + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "cap", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "ValueOnlyCalldataNotEmpty", + "inputs": [ + { + "name": "length", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "ValueOnlyWithAmountRule", + "inputs": [] + }, + { + "type": "error", + "name": "ValueOnlyWithPins", + "inputs": [] + }, + { + "type": "error", + "name": "WrongModeForCall", + "inputs": [ + { + "name": "actual", + "type": "uint8", + "internalType": "enum RulesType" + } + ] + }, + { + "type": "error", + "name": "WrongVmForCall", + "inputs": [ + { + "name": "actual", + "type": "uint8", + "internalType": "enum VmFamily" + } + ] + }, + { + "type": "error", + "name": "ZeroAddress", + "inputs": [] + } +] diff --git a/plan/agw/research/validation-e704d5b/build.log b/plan/agw/research/validation-e704d5b/build.log new file mode 100644 index 00000000..a4419ae8 --- /dev/null +++ b/plan/agw/research/validation-e704d5b/build.log @@ -0,0 +1,1656 @@ +Compiling 167 files with Solc 0.8.26 +Solc 0.8.26 finished in 188.81s +Compiler run successful with warnings: +Warning (5667): Unused function parameter. Remove or comment out the variable name to silence this warning. + --> lib/smartsessions/contracts/lib/ConfigLib.sol:77:9: + | +77 | bool useRegistry + | ^^^^^^^^^^^^^^^^ + +Warning (5667): Unused function parameter. Remove or comment out the variable name to silence this warning. + --> lib/smartsessions/contracts/lib/ConfigLib.sol:123:9: + | +123 | bool useRegistry + | ^^^^^^^^^^^^^^^^ + +Warning (5667): Unused function parameter. Remove or comment out the variable name to silence this warning. + --> lib/smartsessions/contracts/lib/ConfigLib.sol:203:9: + | +203 | bool useRegistry + | ^^^^^^^^^^^^^^^^ + +Warning (5667): Unused function parameter. Remove or comment out the variable name to silence this warning. + --> lib/smartsessions/contracts/core/SmartSessionBase.sol:270:9: + | +270 | bool useRegistry + | ^^^^^^^^^^^^^^^^ + +Warning (2018): Function state mutability can be restricted to view + --> src/AGWFactory.sol:352:5: + | +352 | function _authorizeUpgrade(address newImplementation) internal override onlyRole(DEFAULT_ADMIN_ROLE) { + | ^ (Relevant source part starts here and spans across multiple lines). + + +╭-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------╮ +| Contract | Runtime Size (B) | Initcode Size (B) | Runtime Margin (B) | Initcode Margin (B) | ++===================================================================================================================================================+ +| AGW | 16,549 | 16,999 | 8,027 | 32,153 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| AGWErrors | 57 | 85 | 24,519 | 49,067 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| AGWFactory | 9,992 | 10,229 | 14,584 | 38,923 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| AGWFactoryErrors | 57 | 85 | 24,519 | 49,067 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| AGWFactoryV2 | 10,068 | 10,305 | 14,508 | 38,847 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| Address | 57 | 85 | 24,519 | 49,067 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| AgentConfigLib | 57 | 85 | 24,519 | 49,067 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| AgentConfigLibHarness | 338 | 364 | 24,238 | 48,788 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| AgentValidator | 806 | 832 | 23,770 | 48,320 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| AgentValidatorErrors | 57 | 85 | 24,519 | 49,067 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| AlwaysInitializedValidator | 242 | 267 | 24,334 | 48,885 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| AssociatedArrayLib | 57 | 85 | 24,519 | 49,067 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| Bytes | 57 | 85 | 24,519 | 49,067 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| CallRecorder | 165 | 189 | 24,411 | 48,963 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| CallerProbe | 362 | 388 | 24,214 | 48,764 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| ChainLibHarness | 849 | 875 | 23,727 | 48,277 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| CheckpointHostileValidator | 561 | 587 | 24,015 | 48,565 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| CheckpointProbe | 531 | 557 | 24,045 | 48,595 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| Clones | 57 | 85 | 24,519 | 49,067 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| ConfigLib | 57 | 85 | 24,519 | 49,067 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| Create2 | 57 | 85 | 24,519 | 49,067 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| DeployerContract | 467 | 595 | 24,109 | 48,557 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| DummyModule | 212 | 236 | 24,364 | 48,916 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| ECDSA | 57 | 85 | 24,519 | 49,067 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| ERC165Checker | 57 | 85 | 24,519 | 49,067 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| ERC1967Proxy | 141 | 685 | 24,435 | 48,467 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| ERC1967Utils | 57 | 85 | 24,519 | 49,067 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| EfficientHashLib | 57 | 85 | 24,519 | 49,067 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| EmptyReturnPRC20Source | 63 | 87 | 24,513 | 49,065 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| EmptyReturnProbeEngine | 63 | 87 | 24,513 | 49,065 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| EncodeLib | 57 | 85 | 24,519 | 49,067 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| EntryPoint | 12,762 | 13,287 | 11,814 | 35,865 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| EntryPointSimulations | 17,681 | 18,289 | 6,895 | 30,863 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| EnumerableMap | 57 | 85 | 24,519 | 49,067 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| EnumerableSet | 57 | 85 | 24,519 | 49,067 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| Errors | 57 | 85 | 24,519 | 49,067 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| ExcessivelySafeCall | 57 | 85 | 24,519 | 49,067 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| Exec | 57 | 85 | 24,519 | 49,067 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| ExecutionLib (lib/smartsessions/contracts/lib/ExecutionLib.sol) | 57 | 85 | 24,519 | 49,067 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| ExecutionLib (src/libraries/ExecutionLib.sol) | 57 | 85 | 24,519 | 49,067 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| FixedVerdictPolicy | 748 | 866 | 23,828 | 48,286 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| FlatBytesLib | 57 | 85 | 24,519 | 49,067 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| ForkChainLibHarness | 669 | 695 | 23,907 | 48,457 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| GarbageEngine | 127 | 151 | 24,449 | 49,001 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| GasBurnerProbeEngine | 175 | 199 | 24,401 | 48,953 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| GasBurnerUninstall | 243 | 268 | 24,333 | 48,884 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| GasDebug | 169 | 193 | 24,407 | 48,959 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| HashLib | 57 | 85 | 24,519 | 49,067 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| HostileValidator | 561 | 587 | 24,015 | 48,565 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| IdLib | 57 | 85 | 24,519 | 49,067 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| LibZip | 57 | 85 | 24,519 | 49,067 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| LowLevelCall | 57 | 85 | 24,519 | 49,067 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| Math | 57 | 85 | 24,519 | 49,067 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| MessageHashUtils | 57 | 85 | 24,519 | 49,067 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| Mock1271Owner | 775 | 908 | 23,801 | 48,244 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| MockERC20 | 1,313 | 1,339 | 23,263 | 47,813 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| MockEchoOwner | 71 | 95 | 24,505 | 49,057 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| MockEmptyReturnOwner | 63 | 87 | 24,513 | 49,065 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| MockPRC20 | 1,952 | 2,142 | 22,624 | 47,010 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| MockPRC20Source | 867 | 1,409 | 23,709 | 47,743 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| MockRevertingOwner | 106 | 130 | 24,470 | 49,022 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| MockUEA | 1,096 | 1,237 | 23,480 | 47,915 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| MockUniversalGateway | 1,488 | 1,514 | 23,088 | 47,638 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| MockWrongLengthOwner | 75 | 99 | 24,501 | 49,053 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| ModeLib (lib/vendor/erc7579/src/lib/ModeLib.sol) | 57 | 85 | 24,519 | 49,067 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| ModeLib (src/libraries/ModeLib.sol) | 57 | 85 | 24,519 | 49,067 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| NativeTarget | 178 | 202 | 24,398 | 48,950 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| NonStringPRC20Source | 70 | 94 | 24,506 | 49,058 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| OwnerAuthHarness | 1,937 | 1,963 | 22,639 | 47,189 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| OwnerAuthLib | 57 | 85 | 24,519 | 49,067 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| Panic | 57 | 85 | 24,519 | 49,067 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| PermissivePolicy | 647 | 673 | 23,929 | 48,479 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| PolicyLib | 57 | 85 | 24,519 | 49,067 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| ProxyAdmin | 926 | 1,135 | 23,650 | 48,017 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| PushChainLib | 57 | 85 | 24,519 | 49,067 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| PushChainLibHarness | 462 | 488 | 24,114 | 48,664 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| ReenteringOwner | 627 | 755 | 23,949 | 48,397 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| ReenteringTarget | 359 | 385 | 24,217 | 48,767 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| ReenteringWallet | 755 | 881 | 23,821 | 48,271 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| ReentrantTarget | 716 | 742 | 23,860 | 48,410 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| ReentryLatch | 193 | 217 | 24,383 | 48,935 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| Reverter (test/unit/18_checkpoints.t.sol) | 148 | 172 | 24,428 | 48,980 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| Reverter (test/unit/2_ownerDoor.t.sol) | 116 | 140 | 24,460 | 49,012 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| RevertingApproval | 76 | 100 | 24,500 | 49,052 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| RevertingGateway | 88 | 112 | 24,488 | 49,040 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| RevertingInitWallet | 116 | 140 | 24,460 | 49,012 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| RevertingPRC20Source | 116 | 140 | 24,460 | 49,012 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| RevertingProbeEngine | 204 | 228 | 24,372 | 48,924 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| RevertingUninstall | 244 | 269 | 24,332 | 48,883 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| SafeCast | 57 | 85 | 24,519 | 49,067 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| SenderCreator | 345 | 371 | 24,231 | 48,781 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| ShortReturnProbeEngine | 123 | 147 | 24,453 | 49,005 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| SignedMath | 57 | 85 | 24,519 | 49,067 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| SignerLib | 57 | 85 | 24,519 | 49,067 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| SmartSession | 22,581 | 22,607 | 1,995 | 26,545 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| SmartSessionModeLib | 57 | 85 | 24,519 | 49,067 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| StakeDummy | 1,257 | 1,397 | 23,319 | 47,755 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| StorageSlot | 57 | 85 | 24,519 | 49,067 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| Strings | 57 | 85 | 24,519 | 49,067 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| SudoPolicy | 775 | 801 | 23,801 | 48,351 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| TransientSlot | 57 | 85 | 24,519 | 49,067 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| TransparentUpgradeableProxy | 830 | 2,803 | 23,746 | 46,349 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| URPExposed | 24,085 | 24,298 | 491 | 24,854 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| UniversalRulesPolicy | 23,673 | 23,886 | 903 | 25,266 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| UniversalRulesPolicyErrors | 57 | 85 | 24,519 | 49,067 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| UserOperationLib | 176 | 204 | 24,400 | 48,948 | +|-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------| +| ValidationDataLib | 57 | 85 | 24,519 | 49,067 | +╰-----------------------------------------------------------------+------------------+-------------------+--------------------+---------------------╯ + +note[mixed-case-variable]: mutable variables should use mixedCase + --> src/libraries/Types.sol:15:13 + | +15 | uint256 maxPCForGas; // max native PC for gas swap; 0 = no cap + | ^^^^^^^^^^^ help: consider using: `maxPcForGas` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/10_ownerIntent.t.sol:59:22 + | +59 | address internal EXECUTOR; + | ^^^^^^^^ help: consider using: `executor` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/10_ownerIntent.t.sol:61:22 + | +61 | address internal ASSET; + | ^^^^^ help: consider using: `asset` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/10_ownerIntent.t.sol:62:22 + | +62 | address internal PROTOCOL; + | ^^^^^^^^ help: consider using: `protocol` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/10_ownerIntent.t.sol:63:22 + | +63 | address internal CEA; + | ^^^ help: consider using: `cea` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[asm-keccak256]: use of inefficient hashing mechanism; consider using inline assembly + --> src/libraries/PushChainLib.sol:45:16 + | +45 | return keccak256(bytes(string.concat("eip155:", Strings.toString(block.chainid)))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#asm-keccak256 + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/mocks/MockPRC20Source.sol:27:19 + | +27 | string public SOURCE_CHAIN_NAMESPACE; + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `sourceChainNamespace` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/2_ownerDoor.t.sol:49:22 + | +49 | address internal WALLET_OWNER; + | ^^^^^^^^^^^^ help: consider using: `walletOwner` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/2_ownerDoor.t.sol:53:22 + | +53 | address internal PRC20; + | ^^^^^ help: consider using: `prc20` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> src/libraries/Types.sol:219:13 + | +219 | address expectedCEA; + | ^^^^^^^^^^^ help: consider using: `expectedCea` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> src/libraries/Types.sol:223:13 + | +223 | uint256 maxPCPerCall; + | ^^^^^^^^^^^^ help: consider using: `maxPcPerCall` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[asm-keccak256]: use of inefficient hashing mechanism; consider using inline assembly + --> src/libraries/OwnerAuthLib.sol:46:16 + | +46 | return keccak256( + | ________________^ +47 | | abi.encode( +48 | | OWNER_INTENT_DOMAIN_TYPEHASH, +49 | | OWNER_INTENT_DOMAIN_NAME_HASH, +... | +55 | | ); + | |_________^ + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#asm-keccak256 + +note[asm-keccak256]: use of inefficient hashing mechanism; consider using inline assembly + --> src/libraries/OwnerAuthLib.sol:65:16 + | +65 | return keccak256(abi.encode(OWNER_INTENT_TYPEHASH, i)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#asm-keccak256 + +note[asm-keccak256]: use of inefficient hashing mechanism; consider using inline assembly + --> src/libraries/OwnerAuthLib.sol:70:16 + | +70 | return keccak256(abi.encodePacked("\x19\x01", domainSeparator(factory, i.signerChainId), hashIntent(i))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#asm-keccak256 + +note[unsafe-cheatcode]: usage of unsafe cheatcodes that can perform dangerous operations + --> test/unit/16_agentValidator.t.sol:126:37 + | +126 | string memory artifact = vm.readFile("out/AgentValidator.sol/AgentValidator.json"); + | ^^^^^^^^ + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-cheatcode + +note[mixed-case-function]: function names should use mixedCase + --> test/mocks/MockPRC20Source.sol:45:14 + | +45 | function SOURCE_CHAIN_NAMESPACE() external pure returns (string memory) { + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `sourceChainNamespace` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-function + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/9_svmRulebook.t.sol:88:22 + | +88 | address internal ACCOUNT; + | ^^^^^^^ help: consider using: `account` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/5_universalRulebook.t.sol:50:22 + | +50 | address internal PROTOCOL; + | ^^^^^^^^ help: consider using: `protocol` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> src/libraries/Types.sol:243:13 + | +243 | address expectedCEA; + | ^^^^^^^^^^^ help: consider using: `expectedCea` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/9_svmRulebook.t.sol:89:22 + | +89 | address internal ASSET; + | ^^^^^ help: consider using: `asset` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/9_svmRulebook.t.sol:92:22 + | +92 | bytes32 internal CEA = keccak256("push_identity pda for ACCOUNT"); + | ^^^ help: consider using: `cea` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/9_svmRulebook.t.sol:93:22 + | +93 | bytes32 internal ATA_IN = keccak256("ata(CEA, USDC)"); + | ^^^^^^ help: consider using: `ataIn` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/9_svmRulebook.t.sol:94:22 + | +94 | bytes32 internal ATA_OUT = keccak256("ata(CEA, WETH)"); + | ^^^^^^^ help: consider using: `ataOut` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/9_svmRulebook.t.sol:95:22 + | +95 | bytes32 internal MINT_IN = keccak256("USDC mint"); + | ^^^^^^^ help: consider using: `mintIn` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/integration/8_e2e.t.sol:63:24 + | +63 | MockPRC20 internal pUSDC; + | ^^^^^ help: consider using: `pUsdc` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/integration/8_e2e.t.sol:66:22 + | +66 | address internal BOB_UEA; + | ^^^^^^^ help: consider using: `bobUea` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> src/libraries/Types.sol:247:13 + | +247 | uint256 maxPCPerCall; + | ^^^^^^^^^^^^ help: consider using: `maxPcPerCall` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[screaming-snake-case-const]: constants should use SCREAMING_SNAKE_CASE + --> test/mocks/MockERC20.sol:19:28 + | +19 | string public constant name = "Mock USD"; + | ^^^^ help: consider using: `NAME` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#screaming-snake-case-const + +note[mixed-case-variable]: mutable variables should use mixedCase + --> src/libraries/Types.sol:470:13 + | +470 | bytes32 expectedCEA; + | ^^^^^^^^^^^ help: consider using: `expectedCea` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[unsafe-cheatcode]: usage of unsafe cheatcodes that can perform dangerous operations + --> test/unit/2_ownerDoor.t.sol:823:37 + | +823 | string memory artifact = vm.readFile("out/AGW.sol/AGW.json"); + | ^^^^^^^^ + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-cheatcode + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/9_svmRulebook.t.sol:96:22 + | +96 | bytes32 internal MINT_OUT = keccak256("WETH mint"); + | ^^^^^^^^ help: consider using: `mintOut` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/9_svmRulebook.t.sol:97:22 + | +97 | bytes32 internal GATEWAY_PROG = keccak256("push svm gateway program"); + | ^^^^^^^^^^^^ help: consider using: `gatewayProg` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/9_svmRulebook.t.sol:98:22 + | +98 | bytes32 internal PROG = keccak256("aggregator program"); + | ^^^^ help: consider using: `prog` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/9_svmRulebook.t.sol:99:22 + | +99 | bytes32 internal PROG2 = keccak256("some other program"); + | ^^^^^ help: consider using: `prog2` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/9_svmRulebook.t.sol:100:22 + | +100 | bytes32 internal TOKEN_PROG_ACC = keccak256("token program (as an account)"); + | ^^^^^^^^^^^^^^ help: consider using: `tokenProgAcc` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> src/libraries/Types.sol:475:13 + | +475 | uint256 maxPCPerCall; + | ^^^^^^^^^^^^ help: consider using: `maxPcPerCall` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/integration/8_e2e.t.sol:70:22 + | +70 | address internal BOB_AGW_CEA; + | ^^^^^^^^^^^ help: consider using: `bobAgwCea` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> src/AGW.sol:131:98 + | +131 | constructor(address sessionEngine_, address rulesPolicy_, address sessionValidator_, address universalGatewayPC_) { + | ^^^^^^^^^^^^^^^^^^^ help: consider using: `universalGatewayPc_` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[unused-import]: unused imports should be removed + --> test/unit/2_ownerDoor.t.sol:10:61 + | +10 | import { AllowedCall, Config, OWNER_LANE_FLAG, OwnerIntent, RulesType } from "../../src/libraries/Types.sol"; + | ^^^^^^^^^ + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#unused-import + +note[unused-import]: unused imports should be removed + --> test/unit/2_ownerDoor.t.sol:21:5 + | +21 | ModePayload, + | ^^^^^^^^^^^ + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#unused-import + +note[unused-import]: unused imports should be removed + --> test/unit/2_ownerDoor.t.sol:22:5 + | +22 | CALLTYPE_SINGLE, + | ^^^^^^^^^^^^^^^ + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#unused-import + +note[unused-import]: unused imports should be removed + --> test/unit/2_ownerDoor.t.sol:23:5 + | +23 | CALLTYPE_BATCH, + | ^^^^^^^^^^^^^^ + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#unused-import + +note[unused-import]: unused imports should be removed + --> test/unit/2_ownerDoor.t.sol:24:5 + | +24 | CALLTYPE_STATIC, + | ^^^^^^^^^^^^^^^ + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#unused-import + +note[unused-import]: unused imports should be removed + --> test/unit/2_ownerDoor.t.sol:25:5 + | +25 | CALLTYPE_DELEGATECALL, + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#unused-import + +note[unused-import]: unused imports should be removed + --> test/unit/2_ownerDoor.t.sol:26:5 + | +26 | EXECTYPE_DEFAULT, + | ^^^^^^^^^^^^^^^^ + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#unused-import + +note[unused-import]: unused imports should be removed + --> test/unit/2_ownerDoor.t.sol:27:5 + | +27 | EXECTYPE_TRY, + | ^^^^^^^^^^^^ + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#unused-import + +note[unused-import]: unused imports should be removed + --> test/unit/2_ownerDoor.t.sol:28:5 + | +28 | MODE_DEFAULT + | ^^^^^^^^^^^^ + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#unused-import + +note[unused-import]: unused imports should be removed + --> test/unit/2_ownerDoor.t.sol:35:10 + | +35 | import { Session, PermissionId } from "smartsessions/DataTypes.sol"; + | ^^^^^^^ + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#unused-import + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/5_universalRulebook.t.sol:51:22 + | +51 | address internal CEA; + | ^^^ help: consider using: `cea` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/5_universalRulebook.t.sol:71:22 + | +71 | address internal ACCOUNT; + | ^^^^^^^ help: consider using: `account` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/5_universalRulebook.t.sol:72:22 + | +72 | address internal ASSET; + | ^^^^^ help: consider using: `asset` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> src/libraries/Types.sol:490:13 + | +490 | bytes32 expectedCEA; + | ^^^^^^^^^^^ help: consider using: `expectedCea` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> src/libraries/Types.sol:495:13 + | +495 | uint256 maxPCPerCall; + | ^^^^^^^^^^^^ help: consider using: `maxPcPerCall` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/13_chainDerivation.t.sol:54:22 + | +54 | address internal WALLET_OWNER; + | ^^^^^^^^^^^^ help: consider using: `walletOwner` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/13_chainDerivation.t.sol:58:22 + | +58 | address internal PRC20; + | ^^^^^ help: consider using: `prc20` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/13_chainDerivation.t.sol:60:22 + | +60 | address internal CEA; + | ^^^ help: consider using: `cea` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/13_chainDerivation.t.sol:61:22 + | +61 | address internal PROTOCOL; + | ^^^^^^^^ help: consider using: `protocol` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[unwrapped-modifier-logic]: wrap modifier logic to reduce code size + --> src/AGW.sol:147:5 + | +147 | / modifier onlyOwner() { +148 | | if (msg.sender != _owner()) revert AGWErrors.CallerIsNotOwner(); +149 | | _; +150 | | } + | |_____^ + | +help: wrap modifier logic to reduce code size + | +147 ~ modifier onlyOwner() { +148 + _onlyOwner(); +149 + _; +150 + } +151 + +152 + function _onlyOwner() internal { +153 + if (msg.sender != _owner()) revert AGWErrors.CallerIsNotOwner(); +154 + } + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#unwrapped-modifier-logic + +note[screaming-snake-case-const]: constants should use SCREAMING_SNAKE_CASE + --> test/mocks/MockERC20.sol:20:28 + | +20 | string public constant symbol = "mUSD"; + | ^^^^^^ help: consider using: `SYMBOL` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#screaming-snake-case-const + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/integration/8_e2e.t.sol:73:22 + | +73 | address internal MORPHO_BLUE; + | ^^^^^^^^^^^ help: consider using: `morphoBlue` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[unsafe-cheatcode]: usage of unsafe cheatcodes that can perform dangerous operations + --> test/unit/27_naming.t.sol:154:28 + | +154 | return vm.split(vm.readFile(path), "\"bytecode\"")[0]; + | ^^^^^^^^ + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-cheatcode + +note[unwrapped-modifier-logic]: wrap modifier logic to reduce code size + --> src/AGW.sol:171:5 + | +171 | / modifier onlyOwnerOrSelf() { +172 | | if (msg.sender != _owner() && msg.sender != address(this)) revert AGWErrors.CallerIsNotOwner(); +173 | | _; +174 | | } + | |_____^ + | +help: wrap modifier logic to reduce code size + | +171 ~ modifier onlyOwnerOrSelf() { +172 + _onlyOwnerOrSelf(); +173 + _; +174 + } +175 + +176 + function _onlyOwnerOrSelf() internal { +177 + if (msg.sender != _owner() && msg.sender != address(this)) revert AGWErrors.CallerIsNotOwner(); +178 + } + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#unwrapped-modifier-logic + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/9_svmRulebook.t.sol:101:22 + | +101 | bytes32 internal PROGRAM_AUTHORITY = keccak256("aggregator program authority"); + | ^^^^^^^^^^^^^^^^^ help: consider using: `programAuthority` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/9_svmRulebook.t.sol:102:22 + | +102 | bytes32 internal PROG_SRC = keccak256("program source token account"); + | ^^^^^^^^ help: consider using: `progSrc` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/9_svmRulebook.t.sol:103:22 + | +103 | bytes32 internal PROG_DST = keccak256("program destination token account"); + | ^^^^^^^^ help: consider using: `progDst` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/9_svmRulebook.t.sol:104:22 + | +104 | bytes32 internal ATTACKER = keccak256("attacker account"); + | ^^^^^^^^ help: consider using: `attacker` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[unsafe-cheatcode]: usage of unsafe cheatcodes that can perform dangerous operations + --> test/unit/5_universalRulebook.t.sol:468:37 + | +468 | string memory artifact = vm.readFile("out/UniversalRulesPolicy.sol/UniversalRulesPolicy.json"); + | ^^^^^^^^ + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-cheatcode + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/6_nativeRulebook.t.sol:41:22 + | +41 | address internal ACCOUNT; + | ^^^^^^^ help: consider using: `account` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/6_nativeRulebook.t.sol:42:22 + | +42 | address internal STAKE; + | ^^^^^ help: consider using: `stake` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[asm-keccak256]: use of inefficient hashing mechanism; consider using inline assembly + --> src/AGW.sol:380:32 + | +380 | bytes32 calldataHash = keccak256(executionCalldata); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#asm-keccak256 + +note[screaming-snake-case-const]: constants should use SCREAMING_SNAKE_CASE + --> test/mocks/MockERC20.sol:21:27 + | +21 | uint8 public constant decimals = 6; + | ^^^^^^^^ help: consider using: `DECIMALS` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#screaming-snake-case-const + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/5_universalRulebook.t.sol:836:23 + | +836 | Config memory noCEA = _defaultConfig(); + | ^^^^^ help: consider using: `noCea` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> src/policies/UniversalRulesPolicy.sol:161:20 + | +161 | address public UNIVERSAL_GATEWAY_PC; + | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `universalGatewayPc` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[screaming-snake-case-const]: constants should use SCREAMING_SNAKE_CASE + --> test/mocks/MockUniversalGateway.sol:73:28 + | +73 | string public constant name = "Push USDC"; + | ^^^^ help: consider using: `NAME` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#screaming-snake-case-const + +note[screaming-snake-case-const]: constants should use SCREAMING_SNAKE_CASE + --> test/mocks/MockUniversalGateway.sol:74:28 + | +74 | string public constant symbol = "pUSDC"; + | ^^^^^^ help: consider using: `SYMBOL` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#screaming-snake-case-const + +note[mixed-case-variable]: mutable variables should use mixedCase + --> src/policies/UniversalRulesPolicy.sol:166:20 + | +166 | address public UNIVERSAL_EXECUTOR_MODULE; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `universalExecutorModule` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[unused-import]: unused imports should be removed + --> test/unit/6_nativeRulebook.t.sol:8:10 + | +8 | import { UniversalRulesPolicy } from "../../src/policies/UniversalRulesPolicy.sol"; + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#unused-import + +note[asm-keccak256]: use of inefficient hashing mechanism; consider using inline assembly + --> src/AGW.sol:515:31 + | +515 | bytes32 sessionHash = keccak256(abi.encode(session)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#asm-keccak256 + +note[unused-import]: unused imports should be removed + --> test/integration/8_e2e.t.sol:6:10 + | +6 | import { Vm } from "forge-std/Vm.sol"; + | ^^ + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#unused-import + +note[unsafe-cheatcode]: usage of unsafe cheatcodes that can perform dangerous operations + --> test/integration/25_deploymentRecord.t.sol:40:35 + | +40 | string memory record = vm.readFile(path); + | ^^^^^^^^ + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-cheatcode + +note[screaming-snake-case-immutable]: immutables should use SCREAMING_SNAKE_CASE + --> test/mocks/StakeDummy.sol:30:32 + | +30 | MockERC20 public immutable token; + | ^^^^^ help: consider using: `TOKEN` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#screaming-snake-case-immutable + +warning[unsafe-typecast]: typecasts that can truncate values should be checked + --> test/unit/6_nativeRulebook.t.sol:209:44 + | +209 | cfg.pins[i] = ArgPin({ offset: uint16(4 + i * 32), expected: bytes32(i) }); + | ^^^^^^^^^^^^^^^^^^ + | + = note: consider disabling this lint if you're certain the cast is safe + + // casting to 'uint16' is safe because [explain why] + // forge-lint: disable-next-line(unsafe-typecast) + + + = help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast + +note[asm-keccak256]: use of inefficient hashing mechanism; consider using inline assembly + --> src/AGW.sol:829:29 + | +829 | bytes32 callsHash = keccak256(executionCalldata); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#asm-keccak256 + +note[screaming-snake-case-const]: constants should use SCREAMING_SNAKE_CASE + --> test/mocks/MockUniversalGateway.sol:75:27 + | +75 | uint8 public constant decimals = 6; + | ^^^^^^^^ help: consider using: `DECIMALS` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#screaming-snake-case-const + +note[mixed-case-variable]: mutable variables should use mixedCase + --> src/policies/UniversalRulesPolicy.sol:171:20 + | +171 | address public SESSION_ENGINE; + | ^^^^^^^^^^^^^^ help: consider using: `sessionEngine` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +warning[erc20-unchecked-transfer]: ERC20 'transfer' and 'transferFrom' calls should check the return value + --> test/mocks/StakeDummy.sol:59:9 + | +59 | token.transferFrom(msg.sender, address(this), amount); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#erc20-unchecked-transfer + +warning[unsafe-typecast]: typecasts that can truncate values should be checked + --> src/AGW.sol:916:38 + | +916 | address authorizer = address(uint160(vd)); + | ^^^^^^^^^^^ + | + = note: consider disabling this lint if you're certain the cast is safe + + // casting to 'uint160' is safe because [explain why] + // forge-lint: disable-next-line(unsafe-typecast) + + + = help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/19_ownerAuthLib.t.sol:234:17 + | +234 | address predictedUEA = makeAddr("notYetDeployedUEA"); + | ^^^^^^^^^^^^ help: consider using: `predictedUea` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[unused-import]: unused imports should be removed + --> test/unit/5_universalRulebook.t.sol:20:5 + | +20 | VALUE_SELECTOR, + | ^^^^^^^^^^^^^^ + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#unused-import + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/mocks/MockUniversalGateway.sol:83:19 + | +83 | string public SOURCE_CHAIN_NAMESPACE = "eip155:11155111"; + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `sourceChainNamespace` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +warning[unsafe-typecast]: typecasts that can truncate values should be checked + --> src/AGW.sol:917:29 + | +917 | uint48 validUntil = uint48(vd >> 160); // 0 = unbounded + | ^^^^^^^^^^^^^^^^^ + | + = note: consider disabling this lint if you're certain the cast is safe + + // casting to 'uint48' is safe because [explain why] + // forge-lint: disable-next-line(unsafe-typecast) + + + = help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast + +note[unsafe-cheatcode]: usage of unsafe cheatcodes that can perform dangerous operations + --> test/integration/25_deploymentRecord.t.sol:138:16 + | +138 | vm.removeFile(path); + | ^^^^^^^^^^ + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-cheatcode + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/4_agentDoor.t.sol:61:22 + | +61 | address internal WALLET_OWNER; + | ^^^^^^^^^^^^ help: consider using: `walletOwner` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/4_agentDoor.t.sol:69:22 + | +69 | address internal CEA; + | ^^^ help: consider using: `cea` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/4_agentDoor.t.sol:70:22 + | +70 | address internal PROTOCOL; + | ^^^^^^^^ help: consider using: `protocol` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[unsafe-cheatcode]: usage of unsafe cheatcodes that can perform dangerous operations + --> test/integration/25_deploymentRecord.t.sol:143:12 + | +143 | vm.removeFile(path); + | ^^^^^^^^^^ + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-cheatcode + +warning[unsafe-typecast]: typecasts that can truncate values should be checked + --> test/unit/21_constantMirrors.t.sol:150:47 + | +150 | ActionId.unwrap(target.toActionId(bytes4(hex"aabbccdd"))) != valueOnlyId, + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: consider disabling this lint if you're certain the cast is safe + + // casting to 'bytes4' is safe because [explain why] + // forge-lint: disable-next-line(unsafe-typecast) + + + = help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/4_agentDoor.t.sol:71:22 + | +71 | address internal ASSET; + | ^^^^^ help: consider using: `asset` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +warning[erc20-unchecked-transfer]: ERC20 'transfer' and 'transferFrom' calls should check the return value + --> test/mocks/StakeDummy.sol:82:9 + | +82 | token.transfer(msg.sender, amount); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#erc20-unchecked-transfer + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/integration/23_engine.t.sol:60:24 + | +60 | MockPRC20 internal pUSDC; + | ^^^^^ help: consider using: `pUsdc` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/integration/23_engine.t.sol:63:22 + | +63 | address internal WALLET_OWNER; + | ^^^^^^^^^^^^ help: consider using: `walletOwner` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/integration/23_engine.t.sol:65:22 + | +65 | address internal CEA; + | ^^^ help: consider using: `cea` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/15_assetTeeth.t.sol:44:22 + | +44 | address internal ACCOUNT; + | ^^^^^^^ help: consider using: `account` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/12_nativeGrant.t.sol:45:22 + | +45 | address internal WALLET_OWNER; + | ^^^^^^^^^^^^ help: consider using: `walletOwner` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> src/policies/UniversalRulesPolicy.sol:214:25 + | +214 | uint256[42] private __gap; + | ^^^^^ help: consider using: `_gap` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[unused-import]: unused imports should be removed + --> test/unit/12_nativeGrant.t.sol:18:10 + | +18 | import { ISmartSession } from "smartsessions/ISmartSession.sol"; + | ^^^^^^^^^^^^^ + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#unused-import + +note[mixed-case-variable]: mutable variables should use mixedCase + --> src/policies/UniversalRulesPolicy.sol:241:33 + | +241 | function initialize(address universalGatewayPC, address universalExecutorModule, address sessionEngine) + | ^^^^^^^^^^^^^^^^^^ help: consider using: `universalGatewayPc` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +warning[unsafe-typecast]: typecasts that can truncate values should be checked + --> test/unit/12_nativeGrant.t.sol:67:40 + | +67 | pins[i] = ArgPin({ offset: uint16(4 + i * 32), expected: bytes32(uint256(i + 1)) }); + | ^^^^^^^^^^^^^^^^^^ + | + = note: consider disabling this lint if you're certain the cast is safe + + // casting to 'uint16' is safe because [explain why] + // forge-lint: disable-next-line(unsafe-typecast) + + + = help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast + +warning[unsafe-typecast]: typecasts that can truncate values should be checked + --> src/AGW.sol:918:29 + | +918 | uint48 validAfter = uint48(vd >> 208); + | ^^^^^^^^^^^^^^^^^ + | + = note: consider disabling this lint if you're certain the cast is safe + + // casting to 'uint48' is safe because [explain why] + // forge-lint: disable-next-line(unsafe-typecast) + + + = help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/15_assetTeeth.t.sol:45:22 + | +45 | address internal CEA; + | ^^^ help: consider using: `cea` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/15_assetTeeth.t.sol:46:22 + | +46 | address internal PROTOCOL; + | ^^^^^^^^ help: consider using: `protocol` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +warning[unsafe-typecast]: typecasts that can truncate values should be checked + --> test/unit/12_nativeGrant.t.sol:109:56 + | +109 | a[i] = _action(address(stakeDummy), bytes4(uint32(0x33000000 + i)), MAX_PINS); + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: consider disabling this lint if you're certain the cast is safe + + // casting to 'uint32' is safe because [explain why] + // forge-lint: disable-next-line(unsafe-typecast) + + + = help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast + +note[mixed-case-variable]: mutable variables should use mixedCase + --> src/policies/UniversalRulesPolicy.sol:1005:17 + | +1005 | address expectedCEA = cfg.expectedCEA; + | ^^^^^^^^^^^ help: consider using: `expectedCea` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[unsafe-cheatcode]: usage of unsafe cheatcodes that can perform dangerous operations + --> test/integration/25_deploymentRecord.t.sol:149:33 + | +149 | vm.parseJsonUint(vm.readFile(path), ".chainId"), + | ^^^^^^^^ + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-cheatcode + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/11_nativeDoor.t.sol:57:22 + | +57 | address internal WALLET_OWNER; + | ^^^^^^^^^^^^ help: consider using: `walletOwner` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/3_rulesLifecycle.t.sol:42:22 + | +42 | address internal WALLET_OWNER; + | ^^^^^^^^^^^^ help: consider using: `walletOwner` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/3_rulesLifecycle.t.sol:46:22 + | +46 | address internal PRC20; + | ^^^^^ help: consider using: `prc20` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/integration/23_engine.t.sol:66:22 + | +66 | address internal PROTOCOL; + | ^^^^^^^^ help: consider using: `protocol` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[unused-import]: unused imports should be removed + --> test/review/IndependentReviewHead.t.sol:19:10 + | +19 | import { MockERC20 } from "../mocks/MockERC20.sol"; + | ^^^^^^^^^ + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#unused-import + +note[mixed-case-function]: function names should use mixedCase + --> src/policies/UniversalRulesPolicy.sol:1373:14 + | +1373 | function _uintLE(bytes memory b, uint256 off, uint256 len) internal pure returns (uint256 v) { + | ^^^^^^^ help: consider using: `_uintLe` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-function + +note[unused-import]: unused imports should be removed + --> test/unit/11_nativeDoor.t.sol:12:10 + | +12 | import { UniversalRulesPolicy } from "../../src/policies/UniversalRulesPolicy.sol"; + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#unused-import + +note[unused-import]: unused imports should be removed + --> test/integration/23_engine.t.sol:10:31 + | +10 | import { AllowedCall, Config, RulesType } from "../../src/libraries/Types.sol"; + | ^^^^^^^^^ + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#unused-import + +note[unused-import]: unused imports should be removed + --> test/integration/23_engine.t.sol:29:5 + | +29 | ConfigId, + | ^^^^^^^^ + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#unused-import + +warning[unsafe-typecast]: typecasts that can truncate values should be checked + --> test/unit/11_nativeDoor.t.sol:622:33 + | +622 | c.selector = bytes4(uint32(0x22000000 + i)); + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: consider disabling this lint if you're certain the cast is safe + + // casting to 'uint32' is safe because [explain why] + // forge-lint: disable-next-line(unsafe-typecast) + + + = help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/14_rulesEnvelope.t.sol:36:22 + | +36 | address internal ACCOUNT; + | ^^^^^^^ help: consider using: `account` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/14_rulesEnvelope.t.sol:37:22 + | +37 | address internal CEA; + | ^^^ help: consider using: `cea` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/14_rulesEnvelope.t.sol:38:22 + | +38 | address internal PROTOCOL; + | ^^^^^^^^ help: consider using: `protocol` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/14_rulesEnvelope.t.sol:39:22 + | +39 | address internal ASSET; + | ^^^^^ help: consider using: `asset` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/1_factory.t.sol:52:22 + | +52 | address internal PAUSER; + | ^^^^^^ help: consider using: `pauser` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/1_factory.t.sol:53:22 + | +53 | address internal OPERATOR; + | ^^^^^^^^ help: consider using: `operator` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[unsafe-cheatcode]: usage of unsafe cheatcodes that can perform dangerous operations + --> test/unit/1_factory.t.sol:81:37 + | +81 | string memory artifact = vm.readFile("out/AGWFactory.sol/AGWFactory.json"); + | ^^^^^^^^ + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-cheatcode + +note[asm-keccak256]: use of inefficient hashing mechanism; consider using inline assembly + --> src/AGWFactory.sol:215:24 + | +215 | bytes32 salt = keccak256(abi.encode(owner, index)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#asm-keccak256 + +note[asm-keccak256]: use of inefficient hashing mechanism; consider using inline assembly + --> src/AGWFactory.sol:233:24 + | +233 | bytes32 salt = keccak256(abi.encode(owner, index)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#asm-keccak256 + +warning[unsafe-typecast]: typecasts that can truncate values should be checked + --> src/AGWFactory.sol:261:50 + | +261 | wallet = _predict(implementation, owner, uint96(index)); + | ^^^^^^^^^^^^^ + | + = note: consider disabling this lint if you're certain the cast is safe + + // casting to 'uint96' is safe because [explain why] + // forge-lint: disable-next-line(unsafe-typecast) + + + = help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast + +note[asm-keccak256]: use of inefficient hashing mechanism; consider using inline assembly + --> src/policies/UniversalRulesPolicy.sol:338:29 + | +338 | bytes32 chainHash = keccak256(bytes(chainNamespace)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#asm-keccak256 + +note[named-struct-fields]: prefer initializing structs with named fields + --> test/review/IndependentReviewHead.t.sol:38:20 + | +38 | calls[0] = Execution(address(urp), 0, assertCall); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using named fields: `Execution({ target: address(urp), value: 0, callData: assertCall })` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#named-struct-fields + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/Base.t.sol:71:22 + | +71 | address internal FACTORY; + | ^^^^^^^ help: consider using: `factory` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/Base.t.sol:73:22 + | +73 | address internal FACTORY_ADMIN; + | ^^^^^^^^^^^^^ help: consider using: `factoryAdmin` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/Base.t.sol:76:22 + | +76 | address internal URP_ADMIN_OWNER; + | ^^^^^^^^^^^^^^^ help: consider using: `urpAdminOwner` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> script/Deploy.s.sol:62:17 + | +62 | address gatewayPC = vm.envAddress("UNIVERSAL_GATEWAY_PC"); + | ^^^^^^^^^ help: consider using: `gatewayPc` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/unit/1_factory.t.sol:838:22 + | +838 | address internal EXECUTOR; + | ^^^^^^^^ help: consider using: `executor` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/Base.t.sol:80:22 + | +80 | address internal GATEWAY; + | ^^^^^^^ help: consider using: `gateway` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/Base.t.sol:81:22 + | +81 | address internal EXECUTOR_MODULE; + | ^^^^^^^^^^^^^^^ help: consider using: `executorModule` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/Base.t.sol:82:22 + | +82 | address internal RELAYER; + | ^^^^^^^ help: consider using: `relayer` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +warning[unsafe-typecast]: typecasts that can truncate values should be checked + --> test/unit/3_rulesLifecycle.t.sol:218:86 + | +218 | a[i] = _nativeAction(_addr(string(abi.encodePacked("proto", i))), bytes4(uint32(0x11000000 + i))); + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: consider disabling this lint if you're certain the cast is safe + + // casting to 'uint32' is safe because [explain why] + // forge-lint: disable-next-line(unsafe-typecast) + + + = help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast + +note[asm-keccak256]: use of inefficient hashing mechanism; consider using inline assembly + --> src/policies/UniversalRulesPolicy.sol:434:34 + | +434 | bytes32 assetChain = keccak256(bytes(ns)); + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#asm-keccak256 + +note[named-struct-fields]: prefer initializing structs with named fields + --> test/review/IndependentReviewHead.t.sol:39:20 + | +39 | calls[1] = Execution(address(w), 0, abi.encodeCall(AGW.revokeRules, (oldId))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using named fields: `Execution({ target: address(w), value: 0, callData: abi.encodeCall(AGW.revokeRules, (oldId)) })` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#named-struct-fields + +note[named-struct-fields]: prefer initializing structs with named fields + --> test/review/IndependentReviewHead.t.sol:40:20 + | +40 | calls[2] = Execution(address(w), 0, abi.encodeCall(AGW.grantRules, (s))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using named fields: `Execution({ target: address(w), value: 0, callData: abi.encodeCall(AGW.grantRules, (s)) })` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#named-struct-fields + +note[named-struct-fields]: prefer initializing structs with named fields + --> src/policies/UniversalRulesPolicy.sol:1687:21 + | +1687 | AllowedCall(rule.target, rule.selector, rule.beneficiaryOffset, rule.hasBeneficiary, rule.maxValue); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using named fields: `AllowedCall({ target: rule.target, selector: rule.selector, beneficiaryOffset: rule.beneficiaryOffset, hasBeneficiary: rule.hasBeneficiary, maxValue: rule.maxValue })` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#named-struct-fields + +note[unsafe-cheatcode]: usage of unsafe cheatcodes that can perform dangerous operations + --> script/Deploy.s.sol:206:16 + | +206 | try vm.ffi(cmd) returns (bytes memory out) { + | ^^^ + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-cheatcode + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/Base.t.sol:83:22 + | +83 | address internal OWNER; + | ^^^^^ help: consider using: `owner` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/Base.t.sol:84:22 + | +84 | address internal AGENT; + | ^^^^^ help: consider using: `agent` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> script/Deploy.s.sol:257:49 + | +257 | (UniversalAccountId memory origin, bool isUEA) = IUEAFactoryOrigin(ueaFactory).getOriginForUEA(address(0xdEaD)); + | ^^^^^ help: consider using: `isUea` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-function]: function names should use mixedCase + --> script/Deploy.s.sol:282:14 + | +282 | function getOriginForUEA(address addr) external view returns (UniversalAccountId memory, bool); + | ^^^^^^^^^^^^^^^ help: consider using: `getOriginForUea` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-function + +warning[unsafe-typecast]: typecasts that can truncate values should be checked + --> test/unit/3_rulesLifecycle.t.sol:234:86 + | +234 | a[i] = _nativeAction(_addr(string(abi.encodePacked("proto", i))), bytes4(uint32(0x11000000 + i))); + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: consider disabling this lint if you're certain the cast is safe + + // casting to 'uint32' is safe because [explain why] + // forge-lint: disable-next-line(unsafe-typecast) + + + = help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast + +note[unsafe-cheatcode]: usage of unsafe cheatcodes that can perform dangerous operations + --> test/Base.t.sol:223:37 + | +223 | string memory artifact = vm.readFile(path); + | ^^^^^^^^ + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-cheatcode + +note[unused-import]: unused imports should be removed + --> test/unit/1_factory.t.sol:22:10 + | +22 | import { OwnerAuthLib } from "../../src/libraries/OwnerAuthLib.sol"; + | ^^^^^^^^^^^^ + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#unused-import + +note[unsafe-cheatcode]: usage of unsafe cheatcodes that can perform dangerous operations + --> test/Base.t.sol:292:37 + | +292 | string memory artifact = vm.readFile(path); + | ^^^^^^^^ + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-cheatcode + +note[unsafe-cheatcode]: usage of unsafe cheatcodes that can perform dangerous operations + --> test/Base.t.sol:323:37 + | +323 | string memory artifact = vm.readFile(path); + | ^^^^^^^^ + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-cheatcode + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/Base.t.sol:480:17 + | +480 | uint256 maxPCForGas, + | ^^^^^^^^^^^ help: consider using: `maxPcForGas` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + --> test/Base.t.sol:543:17 + | +543 | uint256 maxPCForGas, + | ^^^^^^^^^^^ help: consider using: `maxPcForGas` + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[unused-import]: unused imports should be removed + --> test/Base.t.sol:12:10 + | +12 | import { Clones } from "@openzeppelin/contracts/proxy/Clones.sol"; + | ^^^^^^ + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#unused-import + +note[unused-import]: unused imports should be removed + --> test/Base.t.sol:34:5 + | +34 | RulesType, + | ^^^^^^^^^ + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#unused-import + diff --git a/plan/agw/research/validation-e704d5b/check-execute.log b/plan/agw/research/validation-e704d5b/check-execute.log new file mode 100644 index 00000000..0b7b8a22 --- /dev/null +++ b/plan/agw/research/validation-e704d5b/check-execute.log @@ -0,0 +1,2 @@ +./script/check-execute.sh +check-execute: OK — execute() is byte-identical to its pinned text (the B2 checkpoint revision) diff --git a/plan/agw/research/validation-e704d5b/evidence-manifest.json b/plan/agw/research/validation-e704d5b/evidence-manifest.json new file mode 100644 index 00000000..7802669f --- /dev/null +++ b/plan/agw/research/validation-e704d5b/evidence-manifest.json @@ -0,0 +1,17 @@ +{ + "commit": "e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9", + "sha256": { + "offline-results.json": "99efbf0c745f7f79e6caad9309507a0a23699449bb0af4b9a3961804f1d2f85e", + "tests-offline.log": "c2a4609c6e32a349e8ed2377eaa06b47c275524c0a5a3150d66bd1fd95217370", + "README.md": "ad374fd06a7573216576b7addb3f961b93a20c2f01175281b3d19601213e1bde", + "check-execute.log": "af6d29316b18c91823cc08bab29ce45bd72121c5a4082165982430e213c47053", + "review-tests-offline.log": "694c7fe8fc426860527a73cb6e50a9bbd99d94f40aea1cd6a87e5f8521efa7a0", + "build.log": "d06ce6f6ca208ad4862c029b8e55d8640dd4e071cf432f5910aae3e865daf09f", + "review-tests/IndependentReviewHead.t.sol": "8a3625629263047173a905cab08227d400b66a25d8af00fc292fcad24bbab71d", + "abi/AGWFactory.json": "b65f66a1556d2a9ddf9aabe9f595c685c2aada436772892f5a40fb1eec846397", + "abi/UniversalRulesPolicy.json": "8301b452b035d12d03ff1861940b895128a40eaf280fb6d3ae30ffc46c5ae86d", + "abi/AGW.json": "ca41d463fac3f7ec8c4399402f2afe41678f43d75baf2ad0220a804699e1fd7b", + "abi/AgentValidator.json": "a4570ddc373241580de8742cbb3d9f2c837094c65bfd1cdd52243ca0c38196fd", + "abi/SmartSession.json": "6e5d9cea4dbed01f06af913c1e093743b86b7432195f4a4bf90fb94b282c51b2" + } +} diff --git a/plan/agw/research/validation-e704d5b/offline-results.json b/plan/agw/research/validation-e704d5b/offline-results.json new file mode 100644 index 00000000..e6ccdc4f --- /dev/null +++ b/plan/agw/research/validation-e704d5b/offline-results.json @@ -0,0 +1,10 @@ +[ + { + "check": "tests-offline", + "exit_code": 0 + }, + { + "check": "review-tests-offline", + "exit_code": 0 + } +] diff --git a/plan/agw/research/validation-e704d5b/review-tests-offline.log b/plan/agw/research/validation-e704d5b/review-tests-offline.log new file mode 100644 index 00000000..987768f0 --- /dev/null +++ b/plan/agw/research/validation-e704d5b/review-tests-offline.log @@ -0,0 +1,13 @@ +No files changed, compilation skipped + +Ran 7 tests for test/review/IndependentReviewHead.t.sol:IndependentReviewHeadTest +[PASS] test_ReviewHead_DuplicateAgentChainGrants_BothLive() (gas: 2603134) +[PASS] test_ReviewHead_InterveningAgentSpend_BlocksReplacement() (gas: 1504772) +[PASS] test_ReviewHead_NativeReplace_ThreeCounterAssertion() (gas: 1995229) +[PASS] test_ReviewHead_Replace_NewIdUsable_OldIdDead() (gas: 2480632) +[PASS] test_ReviewHead_Revoke_ErasesAgentKeepsTerms() (gas: 756042) +[PASS] test_ReviewHead_RulesId_NotGloballyUnique_ChainNotAnInput() (gas: 2251300) +[PASS] test_ReviewHead_UrpInitFailure_RollsBackRevokeAndNonce() (gas: 1664308) +Suite result: ok. 7 passed; 0 failed; 0 skipped; finished in 3.32ms (6.35ms CPU time) + +Ran 1 test suite in 3.77ms (3.32ms CPU time): 7 tests passed, 0 failed, 0 skipped (7 total tests) diff --git a/plan/agw/research/validation-e704d5b/review-tests/IndependentReviewHead.t.sol b/plan/agw/research/validation-e704d5b/review-tests/IndependentReviewHead.t.sol new file mode 100644 index 00000000..4eaf0695 --- /dev/null +++ b/plan/agw/research/validation-e704d5b/review-tests/IndependentReviewHead.t.sol @@ -0,0 +1,261 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +// REVIEW-ONLY EXPERIMENT. Not part of the contract repository. Written for the independent review of the +// AGW SDK planning package (push-chain-sdk/plan/agw/independent-review/). Runs against +// push-agentic-wallets@0f279ca02242dfd8067ff716d24cad4b97bf29cb (nomenclature-changes head, 2026-10-02), +// in an isolated scratch copy. Inherits the repository's E2E harness; the gateway is the repository's +// recording mock, so nothing here proves token pull/burn, settlement, or a real UEA transport. + +import { E2ETest } from "../integration/8_e2e.t.sol"; +import { AGW } from "../../src/AGW.sol"; +import { IAGW } from "../../src/interfaces/IAGW.sol"; +import { AGWErrors, UniversalRulesPolicyErrors } from "../../src/libraries/Errors.sol"; +import { Execution, ExecutionLib } from "../../src/libraries/ExecutionLib.sol"; +import { ModeCode, ModeLib } from "../../src/libraries/ModeLib.sol"; +import { AllowedCall, Config, RulesType } from "../../src/libraries/Types.sol"; +import { Session, PermissionId, ConfigId } from "smartsessions/DataTypes.sol"; +import { StakeDummy } from "../mocks/StakeDummy.sol"; +import { MockERC20 } from "../mocks/MockERC20.sol"; + +contract IndependentReviewHeadTest is E2ETest { + string internal constant SEPOLIA = "eip155:11155111"; + + // ───────────────────────────── helpers ───────────────────────────── + + function _replacement() internal view returns (Session memory) { + return canonicalSession(agentConfig(agentAddr), _urpConfig()); + } + + /// @dev The rules id derived WITHOUT the engine: keccak256(abi.encode(validator, abi.encode(agent), salt)), + /// salt = bytes32(grantNonce). Independent of the wallet and of the chain. + function _formulaId(address agent, uint256 nonce) internal view returns (bytes32) { + return keccak256(abi.encode(address(validator), abi.encode(agent), bytes32(nonce))); + } + + function _replace(AGW w, bytes memory assertCall, bytes32 oldId, Session memory s) internal { + Execution[] memory calls = new Execution[](3); + calls[0] = Execution(address(urp), 0, assertCall); + calls[1] = Execution(address(w), 0, abi.encodeCall(AGW.revokeRules, (oldId))); + calls[2] = Execution(address(w), 0, abi.encodeCall(AGW.grantRules, (s))); + vm.prank(BOB_UEA); + w.execute(ModeCode.unwrap(ModeLib.encodeSimpleBatch()), ExecutionLib.encodeBatch(calls)); + } + + function _assertUniversal(bytes32 pid, uint256 expected) internal view returns (bytes memory) { + return abi.encodeWithSignature("assertSpent(bytes32,address,uint256)", _configId(pid), address(bobAgw), expected); + } + + function _urpConfigWithExpiry(uint48 validUntil) internal view returns (bytes memory) { + AllowedCall[] memory rules = new AllowedCall[](1); + rules[0] = AllowedCall({ + target: MORPHO_BLUE, + selector: SUPPLY_SELECTOR, + beneficiaryOffset: BENEFICIARY_OFFSET, + hasBeneficiary: true, + maxValue: 0 + }); + return universalInitData( + Config({ + initialized: false, + validUntil: validUntil, + destChainHash: bytes32(0), + expectedCEA: BOB_AGW_CEA, + asset: address(pUSDC), + maxAmountPerCall: HUNDRED_USDC, + maxAmountTotal: HUNDRED_USDC, + maxPCPerCall: 1 ether, + spent: 0, + allowedCalls: rules + }) + ); + } + + // ───────────────────── 1. successful replacement (new door) ───────────────────── + + /// Owner batch assert → revoke → grant. Beyond the 610a640 experiment: the predicted id is derived from + /// the formula (not the engine), events are checked in order, the new id is USABLE by the agent, and + /// the replaced id is DEAD at the sender-gated door. + function test_ReviewHead_Replace_NewIdUsable_OldIdDead() public { + _deployAndGrant(); + bytes32 oldId = permissionId; + assertEq(oldId, _formulaId(agentAddr, 0), "grant 0 id matches the off-chain formula"); + + _submitRequest(_executionCalldata(10e6, 0)); + assertEq(_spent(oldId), 10e6); + + bytes32 next = _formulaId(agentAddr, 1); + + vm.expectEmit(true, false, false, true, address(bobAgw)); + emit IAGW.RulesRevoked(oldId); + vm.expectEmit(true, true, false, true, address(bobAgw)); + emit IAGW.RulesGranted(next, RulesType.UNIVERSAL, keccak256(bytes(SEPOLIA)), SEPOLIA); + _replace(bobAgw, _assertUniversal(oldId, 10e6), oldId, _replacement()); + + assertFalse(engine.isPermissionEnabled(PermissionId.wrap(oldId), address(bobAgw)), "old disabled"); + assertTrue(engine.isPermissionEnabled(PermissionId.wrap(next), address(bobAgw)), "new enabled"); + assertEq(bobAgw.agentOf(oldId), address(0), "old id names no agent"); + assertEq(bobAgw.agentOf(next), agentAddr, "new id names the agent"); + assertTrue(urp.getMode(_configId(next), address(bobAgw)).initialized, "new config really initialised"); + assertEq(_spent(next), 0, "new counter starts at zero"); + assertEq(_spent(oldId), 10e6, "old counter retained in URP storage"); + assertEq(bobAgw.grantNonce(), 2); + + // Stale id after replacement: refused at the door, before the engine. + vm.prank(agentAddr); + vm.expectRevert(abi.encodeWithSelector(AGWErrors.CallerIsNotAgent.selector, oldId, agentAddr)); + bobAgw.executeAsAgent(oldId, _singleMode(), _executionCalldata(1e6, 0)); + + // New id works and meters from zero. + vm.prank(agentAddr); + bobAgw.executeAsAgent(next, _singleMode(), _executionCalldata(10e6, 0)); + assertEq(_spent(next), 10e6, "new id meters"); + } + + // ───────────── 2. failure INSIDE the engine/URP rolls back revoke and nonce ───────────── + + /// The 610a640 experiment failed at the wallet's shape check, before `_grantNonce++` and before the + /// engine was touched. Here the replacement fails inside URP's init (expiry not in the future), i.e. + /// AFTER the wallet advanced its nonce and mid-way through the engine's enable. grantNonce == 1 is + /// therefore a real rollback witness, not a value that would hold anyway. + function test_ReviewHead_UrpInitFailure_RollsBackRevokeAndNonce() public { + _deployAndGrant(); + bytes32 oldId = permissionId; + + Session memory bad = canonicalSession(agentConfig(agentAddr), _urpConfigWithExpiry(uint48(block.timestamp))); + bytes memory assertion = _assertUniversal(oldId, 0); + vm.expectRevert( + abi.encodeWithSelector(UniversalRulesPolicyErrors.InvalidExpiry.selector, uint48(block.timestamp)) + ); + _replace(bobAgw, assertion, oldId, bad); + + assertTrue(engine.isPermissionEnabled(PermissionId.wrap(oldId), address(bobAgw)), "old still enabled"); + assertEq(bobAgw.agentOf(oldId), agentAddr, "old still names the agent"); + assertEq(bobAgw.grantNonce(), 1, "nonce advance rolled back"); + assertEq(engine.getPermissionIDs(address(bobAgw)).length, 1, "no half-enabled session left"); + + _submitRequest(_executionCalldata(10e6, 0)); + assertEq(_spent(oldId), 10e6, "old rule still usable"); + } + + // ─────────────── 3. stale spend assertion after an intervening agent action ─────────────── + + function test_ReviewHead_InterveningAgentSpend_BlocksReplacement() public { + _deployAndGrant(); + bytes32 oldId = permissionId; + uint256 observed = _spent(oldId); + + Session memory s = _replacement(); + bytes memory assertion = _assertUniversal(oldId, observed); // composed against the observed spend + + _submitRequest(_executionCalldata(10e6, 0)); // lands between composition and submission + + vm.expectRevert(abi.encodeWithSelector(UniversalRulesPolicyErrors.SpentMismatch.selector, observed, 10e6)); + _replace(bobAgw, assertion, oldId, s); + + assertTrue(engine.isPermissionEnabled(PermissionId.wrap(oldId), address(bobAgw))); + assertFalse(engine.isPermissionEnabled(PermissionId.wrap(_formulaId(agentAddr, 1)), address(bobAgw))); + assertEq(_spent(oldId), 10e6); + assertEq(bobAgw.grantNonce(), 1); + } + + // ───────────── 4. what survives revocation (read-model evidence) ───────────── + + /// After revoke: enumeration drops the id, the engine clears the agent config, `agentOf` is zero, but + /// URP terms and counters remain readable. The agent of a revoked rule is therefore NOT recoverable + /// from state, and `RulesGranted` does not carry it either. + function test_ReviewHead_Revoke_ErasesAgentKeepsTerms() public { + _deployAndGrant(); + bytes32 id = permissionId; + (address v0, bytes memory cfg0) = engine.getSessionValidatorAndConfig(address(bobAgw), PermissionId.wrap(id)); + assertEq(v0, address(validator)); + assertEq(keccak256(cfg0), keccak256(abi.encode(agentAddr))); + assertEq(engine.getEnabledActions(address(bobAgw), PermissionId.wrap(id)).length, 1); + + vm.prank(BOB_UEA); + bobAgw.revokeRules(id); + + assertEq(engine.getPermissionIDs(address(bobAgw)).length, 0, "enumeration drops it"); + assertEq(engine.getEnabledActions(address(bobAgw), PermissionId.wrap(id)).length, 0, "actions dropped"); + (address v1, bytes memory cfg1) = engine.getSessionValidatorAndConfig(address(bobAgw), PermissionId.wrap(id)); + assertEq(v1, address(0), "validator cleared"); + assertEq(cfg1.length, 0, "agent config cleared"); + assertEq(bobAgw.agentOf(id), address(0), "agentOf erased"); + assertTrue(urp.getMode(_configId(id), address(bobAgw)).initialized, "URP config persists"); + assertEq(urp.getConfig(_configId(id), address(bobAgw)).asset, address(pUSDC), "terms still readable"); + } + + // ─────────────── 5. one-rule-per-(agent, chain) is NOT enforced on-chain ─────────────── + + function test_ReviewHead_DuplicateAgentChainGrants_BothLive() public { + _deployAndGrant(); + bytes32 first = permissionId; + + vm.prank(BOB_UEA); + bytes32 second = bobAgw.grantRules(_replacement()); // same agent, same chain, same terms + + assertTrue(first != second); + assertEq(engine.getPermissionIDs(address(bobAgw)).length, 2, "both enabled"); + assertEq(bobAgw.agentOf(first), agentAddr); + assertEq(bobAgw.agentOf(second), agentAddr); + + // The agent can act under either; each has its own budget. + vm.prank(agentAddr); + bobAgw.executeAsAgent(first, _singleMode(), _executionCalldata(HUNDRED_USDC, 0)); + vm.prank(agentAddr); + bobAgw.executeAsAgent(second, _singleMode(), _executionCalldata(HUNDRED_USDC, 0)); + assertEq(_spent(first), HUNDRED_USDC); + assertEq(_spent(second), HUNDRED_USDC); + } + + // ─────────────── 6. rules id: wallet-independent and chain-free ─────────────── + + /// The same agent at the same grant nonce yields the SAME rules id on two different wallets, and the + /// chain is not an input. So `rulesId` is unique only per wallet, and a helper keyed on + /// (agent, chainNamespace, grantNonce) cannot be the contract's formula. + function test_ReviewHead_RulesId_NotGloballyUnique_ChainNotAnInput() public { + _deployAndGrant(); // bobAgw (BOB_UEA, index 0), universal on Sepolia, nonce 0 + (AGW w2,,, bytes32 nativeId) = _deployAndGrantNative(); // BOB_UEA index 1, NATIVE rule, nonce 0 + + assertTrue(address(w2) != address(bobAgw)); + assertEq(permissionId, nativeId, "same id across wallets and across chains"); + assertEq(nativeId, _formulaId(agentAddr, 0)); + assertEq( + nativeId, + PermissionId.unwrap(engine.getPermissionId(_replacement())), + "engine view agrees when salt = 0 (wallet overwrites salt with its grant nonce)" + ); + } + + // ─────────────── 7. native replacement with the three-counter assertion ─────────────── + + function test_ReviewHead_NativeReplace_ThreeCounterAssertion() public { + (AGW w, StakeDummy stake,, bytes32 oldId) = _deployAndGrantNative(); + + vm.prank(agentAddr); + w.executeAsAgent( + oldId, + _singleMode(), + ExecutionLib.encodeSingle(address(stake), 0, abi.encodeCall(StakeDummy.stakeFor, (address(w), 10e6))) + ); + + ConfigId cid = _configIdNative(oldId, address(stake), address(w)); + bytes memory staleAssert = abi.encodeWithSignature( + "assertSpent(bytes32,address,uint256,uint256,uint32)", cid, address(w), uint256(0), uint256(10e6), uint32(0) + ); + Session memory s = _nativeSessionFor(stake, address(w)); + vm.expectRevert(abi.encodeWithSelector(UniversalRulesPolicyErrors.SpentMismatch.selector, uint256(0), uint256(1))); + _replace(w, staleAssert, oldId, s); + + bytes memory goodAssert = abi.encodeWithSignature( + "assertSpent(bytes32,address,uint256,uint256,uint32)", cid, address(w), uint256(0), uint256(10e6), uint32(1) + ); + _replace(w, goodAssert, oldId, s); + + bytes32 next = _formulaId(agentAddr, 1); + assertFalse(engine.isPermissionEnabled(PermissionId.wrap(oldId), address(w))); + assertTrue(engine.isPermissionEnabled(PermissionId.wrap(next), address(w))); + assertEq(urp.getNativeConfig(_configIdNative(next, address(stake), address(w)), address(w)).callsUsed, 0); + assertEq(urp.getNativeConfig(cid, address(w)).amountSpent, 10e6, "old counters retained"); + } +} diff --git a/plan/agw/research/validation-e704d5b/tests-offline.log b/plan/agw/research/validation-e704d5b/tests-offline.log new file mode 100644 index 00000000..715004d5 --- /dev/null +++ b/plan/agw/research/validation-e704d5b/tests-offline.log @@ -0,0 +1,677 @@ +No files changed, compilation skipped + +Ran 7 tests for test/unit/20_pushChainLib.t.sol:PushChainLibTest +[PASS] test_ChainLib_deriveMode_followsTheChain() (gas: 14136) +[PASS] test_ChainLib_deriveMode_pushIsNative_othersUniversal() (gas: 16451) +[PASS] test_ChainLib_gas() (gas: 10018) +[PASS] test_ChainLib_nearMissStringsAreNotThisChain() (gas: 16462) +[PASS] test_ChainLib_notTheTwoStringFormula() (gas: 12200) +[PASS] test_ChainLib_selfChainHash_matchesDonutPin() (gas: 9624) +[PASS] test_ChainLib_selfChainHash_sepoliaAndMainnet() (gas: 12276) +Suite result: ok. 7 passed; 0 failed; 0 skipped; finished in 4.21ms (893.04µs CPU time) + +Ran 11 tests for test/unit/21_constantMirrors.t.sol:ConstantMirrorsTest +[PASS] test_CP_kindOrdinalsAreFrozen() (gas: 678) +[PASS] test_OwnerIntent_TypehashesMatchLiterals() (gas: 174) +[PASS] test_OwnerLaneFlag_IsTopBitOfUint192() (gas: 659) +[PASS] test_mandateTypeZeroValueIsUniversal() (gas: 594) +[PASS] test_mirror_engineFallbackSelector() (gas: 567) +[PASS] test_mirror_engineFallbackSelectorSmartSession() (gas: 369) +[PASS] test_mirror_engineFallbackTarget() (gas: 435) +[PASS] test_mirror_getSessionValidatorAndConfigReturnsTheGrantedConfig() (gas: 1007495) +[PASS] test_mirror_getSessionValidatorAndConfigSelector() (gas: 457) +[PASS] test_mirror_valueSelector_boundaryIsFourBytes() (gas: 4847) +[PASS] test_mirror_valueSelector_isWhatTheEngineUsesForShortCalldata() (gas: 2536) +Suite result: ok. 11 passed; 0 failed; 0 skipped; finished in 5.92ms (413.38µs CPU time) + +Ran 13 tests for test/unit/13_chainDerivation.t.sol:PushAgentWalletChainDerivationTest +[PASS] test_Grant_caseVariantPushStringDerivesUniversal() (gas: 38759) +[PASS] test_Grant_emptyChainRefused() (gas: 35142) +[PASS] test_Grant_foreignChainMultiAction_isShapeNotTypeError() (gas: 42483) +[PASS] test_Grant_foreignChainOnNativeTarget() (gas: 38029) +[PASS] test_Grant_inconsistentChainNamesTheAction() (gas: 49231) +[PASS] test_Grant_inconsistentChainRefused() (gas: 60354) +[PASS] test_Grant_nonUrpPolicyOnLaterActionRefused() (gas: 4860421) +[PASS] test_Grant_nonUrpPolicyRefusedBeforeDecode() (gas: 29509) +[PASS] test_Grant_pushChainOnGatewayTarget() (gas: 45946) +[PASS] test_Grant_twoPoliciesRefusedBeforeDecode() (gas: 34191) +[PASS] test_Grant_walletAndUrpAgreeOnMode_native() (gas: 575966) +[PASS] test_Grant_walletAndUrpAgreeOnMode_universal() (gas: 659109) +[PASS] test_Grant_zeroActionsRefusedBeforeDecode() (gas: 23178) +Suite result: ok. 13 passed; 0 failed; 0 skipped; finished in 7.66ms (1.83ms CPU time) + +Ran 7 tests for test/unit/22_harness.t.sol:BaseSmokeTest +[PASS] test_agentConfigShape() (gas: 9400) +[PASS] test_callRecorder_semantics() (gas: 1056946479) +[PASS] test_canonicalSessionDerivesPermissionId() (gas: 12661) +[PASS] test_engineDeploys() (gas: 6686) +[PASS] test_minBodyLenMatchesStruct() (gas: 1378) +[PASS] test_sendOutboundSelectorMatchesInterface() (gas: 435) +[PASS] test_validatorDeploys() (gas: 5945) +Suite result: ok. 7 passed; 0 failed; 0 skipped; finished in 1.98ms (222.75µs CPU time) + +Ran 16 tests for test/unit/14_rulesEnvelope.t.sol:URPEnvelopeTest +[PASS] test_Envelope_bareNativeStructIsNamedEmptyChain() (gas: 28900) +[PASS] test_Envelope_bareUniversalStructIsNamedEmptyChain() (gas: 33652) +[PASS] test_Envelope_doubleWrappedRevertsUnnamed() (gas: 34992) +[PASS] test_Envelope_emptyChainIsNamed() (gas: 34702) +[PASS] test_Envelope_emptyRevertsUnnamed() (gas: 23991) +[PASS] test_Envelope_foreignChainNativeBodyRevertsUnnamed() (gas: 32604) +[PASS] test_Envelope_nativeAccepted() (gas: 174312) +[PASS] test_Envelope_nativeChainUniversalBodyRevertsUnnamed() (gas: 37781) +[PASS] test_Envelope_reinitAcrossModesRefused() (gas: 281287) +[PASS] test_Envelope_reinitGuardPrecedesTheDecoder() (gas: 277014) +[PASS] test_Envelope_scopeDHeaderRevertsUnnamed() (gas: 33603) +[PASS] test_Envelope_tooShortRevertsUnnamed() (gas: 24346) +[PASS] test_Envelope_universalAccepted() (gas: 279649) +[PASS] test_Envelope_v2OutOfRangeModeRevertsUnnamed() (gas: 33021) +[PASS] test_Envelope_v2UniversalWrapperIsNamedEmptyChain() (gas: 34238) +[PASS] test_Envelope_zeroWordsAreNamedEmptyChain() (gas: 24965) +Suite result: ok. 16 passed; 0 failed; 0 skipped; finished in 3.11ms (991.04µs CPU time) + +Ran 19 tests for test/unit/19_ownerAuthLib.t.sol:OwnerAuthLibTest +[PASS] test_A01_eoaOwner_validSig_true() (gas: 20017) +[PASS] test_A02_eoaOwner_wrongSigner_false() (gas: 19580) +[PASS] test_A03_eoaOwner_malformedSig_false() (gas: 34802) +[PASS] test_A04_ueaOwner_validSig_true() (gas: 271386) +[PASS] test_A05_ueaOwner_returnsFalse_false() (gas: 271062) +[PASS] test_A06_contractOwner_noUEASelector_1271_true() (gas: 207272) +[PASS] test_A07_contractOwner_bothRevert_false() (gas: 66658) +[PASS] test_A08_hashIntent_matchesReferenceEncoding() (gas: 8815) +[PASS] test_A09_intentDigest_matches0x1901Reference() (gas: 12406) +[PASS] test_A10_domainSeparator_differsAcrossPushChainId() (gas: 12465) +[PASS] test_A11_domainSeparator_differsAcrossFactory() (gas: 9589) +[PASS] test_A12_typehashes_matchLiteralStrings() (gas: 558) +[PASS] test_A13_contractOwner_emptyReturnOnBoth_false() (gas: 58078) +[PASS] test_A14_domainSeparator_usesSignerChainId_notBlockChainid() (gas: 10819) +[PASS] test_A15_domainSeparator_saltIsPushChainId() (gas: 11748) +[PASS] test_A16_contractOwner_returnsWrongLength_false() (gas: 60584) +[PASS] test_A18_signedIntent_verifiesForEoaAndUea() (gas: 307549) +[PASS] test_A19_contractOwner_echoesCalldata_false() (gas: 62586) +[PASS] test_A20_counterfactualUEAOwner_secp256k1BranchRejects() (gas: 282378) +Suite result: ok. 19 passed; 0 failed; 0 skipped; finished in 11.78ms (6.07ms CPU time) + +Ran 20 tests for test/unit/1_factory.t.sol:AGWFactoryIntentTest +[PASS] test_F_deployWithIntent_addressEqualsPredictWallet_andLegacyDerivation() (gas: 389794) +[PASS] test_F_deployWithIntent_eoaOwner_deploysAndOwnerIsSigner() (gas: 232683) +[PASS] test_F_deployWithIntent_expired_reverts() (gas: 63206) +[PASS] test_F_deployWithIntent_grantAndExecFieldsIgnoredHere() (gas: 225844) +[PASS] test_F_deployWithIntent_ownerIsSender_ignoresSigDeadlineAndExecutor() (gas: 200567) +[PASS] test_F_deployWithIntent_paused_reverts() (gas: 84913) +[PASS] test_F_deployWithIntent_replay_revertsIndexMismatch() (gas: 227962) +[PASS] test_F_deployWithIntent_thirdPartyCannotAdvanceCountWithoutSig() (gas: 73791) +[PASS] test_F_deployWithIntent_ueaOwner_viaVerifySelector() (gas: 476235) +[PASS] test_F_deployWithIntent_wrongExecutor_revertsExecutorMismatch() (gas: 65400) +[PASS] test_F_deployWithIntent_wrongFactoryDomain_reverts() (gas: 68186) +[PASS] test_F_deployWithIntent_wrongIndex_revertsIndexMismatch() (gas: 233167) +[PASS] test_F_deployWithIntent_wrongPushChainSalt_reverts() (gas: 70985) +[PASS] test_F_deployWithIntent_wrongSignerChainId_reverts() (gas: 70249) +[PASS] test_F_deployWithIntent_wrongSigner_reverts() (gas: 69496) +[PASS] test_F_deployWithIntent_wrongWalletField_revertsIntentWalletMismatch() (gas: 62519) +[PASS] test_F_deployWithIntent_zeroExecutor_revertsExecutorMismatch() (gas: 62427) +[PASS] test_F_deployWithIntent_zeroOwner_revertsZeroAddress() (gas: 22308) +[PASS] test_F_domainSeparator_matchesOwnerAuthLib() (gas: 13574) +[PASS] test_F_legacyDeployWallet_unchanged() (gas: 183219) +Suite result: ok. 20 passed; 0 failed; 0 skipped; finished in 7.32ms (5.75ms CPU time) + +Ran 2 tests for test/integration/25_deploymentRecord.t.sol:DeploymentRecordTest +[SKIP: S-05 requires DEPLOYMENT_RPC and CHAIN_ID pointing at a live deployment] test_S05_DeploymentRecord() (gas: 0) +[SKIP: S-05 requires DEPLOYMENT_RPC pointing at a live deployment] test_S05_MismatchedChainIdIsRejected() (gas: 0) +Suite result: ok. 0 passed; 0 failed; 2 skipped; finished in 498.63µs (440.63µs CPU time) + +Ran 4 tests for test/integration/26_prc20SourceFork.t.sol:PRC20SourceForkTest +[SKIP: requires PUSH_TESTNET_RPC - not set] test_Fork_liveAssetDerivesUniversal() (gas: 0) +[SKIP: requires PUSH_TESTNET_RPC - not set] test_Fork_pethReportsSepolia() (gas: 0) +[SKIP: requires PUSH_TESTNET_RPC - not set] test_Fork_selfChainHashOnDonut() (gas: 0) +[SKIP: requires PUSH_TESTNET_RPC - not set] test_Fork_usdcEthReportsSepolia() (gas: 0) +Suite result: ok. 0 passed; 0 failed; 4 skipped; finished in 66.17µs (27.17µs CPU time) + +Ran 9 tests for test/unit/15_assetTeeth.t.sol:URPTeethTest +[PASS] test_Teeth_assetReturningGarbageRevertsUnnamed() (gas: 83865) +[PASS] test_Teeth_assetReturningNothingRevertsUnnamed() (gas: 82162) +[PASS] test_Teeth_assetThatRevertsRefused() (gas: 92916) +[PASS] test_Teeth_assetWithNoCodeRefused() (gas: 41475) +[PASS] test_Teeth_emptyChainRefused() (gas: 261630) +[PASS] test_Teeth_eoaAssetRefused() (gas: 41453) +[PASS] test_Teeth_matchingAssetChainAccepted() (gas: 511998) +[PASS] test_Teeth_mismatchedAssetChainRefused() (gas: 268264) +[PASS] test_Teeth_nativeInitMakesNoExternalCall() (gas: 188335) +Suite result: ok. 9 passed; 0 failed; 0 skipped; finished in 3.21ms (624.58µs CPU time) + +Ran 6 tests for test/integration/23_engine.t.sol:EngineTest +[PASS] test_S01_EnableMode_DeadOnV3Wallets() (gas: 1609993) +[PASS] test_S02_CanonicalShape_Enforced() (gas: 5560958) +[PASS] test_S03_SignatureVerifiedLast() (gas: 736370) +[PASS] test_S04_EngineFloors() (gas: 334049) +[PASS] test_S07_OwnerDoor_DirectOnUninstall_NoDesync() (gas: 1990369) +[PASS] test_S08_MultiAgent_Independence() (gas: 4190743) +Suite result: ok. 6 passed; 0 failed; 0 skipped; finished in 7.12ms (5.92ms CPU time) + +Ran 37 tests for test/unit/3_rulesLifecycle.t.sol:PushAgentWalletLifecycleTest +[PASS] test_StopAll_IsOwnerOnly() (gas: 14808) +[PASS] test_StopMandate_IsOwnerOnly() (gas: 657974) +[PASS] test_U19_ConfigOrphan_Harmless() (gas: 615915) +[PASS] test_W10_FailingApprovalLeg_UnwindsTheWholeChange() (gas: 1352180) +[PASS] test_W10_OwnerBatch_CanonicalChangeFlow() (gas: 1117240) +[PASS] test_W10_SelfCallPath_IsNotOpenToAnyoneElse() (gas: 662483) +[PASS] test_W10_StaleAssertSpent_RevertsTheWholeBatch() (gas: 697706) +[PASS] test_W15_OtherWalletsIdIsAGhost() (gas: 807310) +[PASS] test_W15_StopMandate_GhostReverts() (gas: 679469) +[PASS] test_W16_StopAll_Empties() (gas: 2109870) +[PASS] test_W16_StopAll_EmptyIsNoop() (gas: 27587) +[PASS] test_W17_GrantSalt_Monotonic() (gas: 1850946) +[PASS] test_W17_ReplacedIdNeverRecurs() (gas: 1053146) +[PASS] test_W23_Events_Attribution_Lifecycle() (gas: 571081) +[PASS] test_W24_CanonicalSessionGrants() (gas: 657949) +[PASS] test_W24_Deviation_ExtraUserOpPolicy() (gas: 37386) +[PASS] test_W24_Deviation_MalformedKeyConfig_BothVariants() (gas: 204156) +[PASS] test_W24_Deviation_NonEmpty7739Content() (gas: 37092) +[PASS] test_W24_Deviation_NonEmpty7739Policies() (gas: 38075) +[PASS] test_W24_Deviation_PaymasterTrue() (gas: 36810) +[PASS] test_W24_Deviation_TwoActionPolicies() (gas: 38993) +[PASS] test_W24_Deviation_TwoActions() (gas: 42881) +[PASS] test_W24_Deviation_WrongPolicyAddress() (gas: 4837287) +[PASS] test_W24_Deviation_WrongSelector() (gas: 42284) +[PASS] test_W24_Deviation_WrongTarget() (gas: 42578) +[PASS] test_W24_Deviation_WrongValidator() (gas: 41769) +[PASS] test_W24_Deviation_ZeroActionPolicies() (gas: 36658) +[PASS] test_W24_Deviation_ZeroActions() (gas: 36384) +[PASS] test_W24_GrantIsOwnerOnly() (gas: 33675) +[PASS] test_W24_Native_CommonRulesStillApply() (gas: 42376) +[PASS] test_W24_Native_DuplicateActionRejected() (gas: 59814) +[PASS] test_W24_Native_EightActionsGrant() (gas: 2178480) +[PASS] test_W24_Native_NineActionsRejected() (gas: 102725) +[PASS] test_W24_Native_OneActionGrants() (gas: 503476) +[PASS] test_W24_Native_WrongPolicyIsMalformed() (gas: 4844935) +[PASS] test_W24_Native_ZeroActionsRejected() (gas: 36160) +[PASS] test_W24_ShapeCheckDoesNotValidateUrpContents() (gas: 156075) +Suite result: ok. 37 passed; 0 failed; 0 skipped; finished in 17.83ms (12.08ms CPU time) + +Ran 15 tests for test/unit/11_nativeDoor.t.sol:PushAgentWalletNativeDoorTest +[PASS] test_DispatchRefusesEngineTarget() (gas: 608596) +[PASS] test_DispatchRefusesSelfTarget() (gas: 614473) +[PASS] test_GatewayTargetRefusedAsNative() (gas: 55118) +[PASS] test_GrantRefusesFallbackAction() (gas: 94625) +[PASS] test_GrantRefusesSelfTarget() (gas: 43151) +[PASS] test_NonGatewayTargetRefusedAsUniversal() (gas: 41579) +[PASS] test_W29_Native_SelfTargetRefusedWithEightActions() (gas: 2233720) +[PASS] test_native_endToEnd_allFiveActions() (gas: 2163008) +[PASS] test_native_gauntlet_amountExceedsPerCallCap() (gas: 1803435) +[PASS] test_native_gauntlet_argPinMismatch() (gas: 1802782) +[PASS] test_native_gauntlet_callLimitReached() (gas: 2103171) +[PASS] test_native_gauntlet_lifetimeAmountCap() (gas: 1941189) +[PASS] test_native_gauntlet_valueExceedsCap() (gas: 1801578) +[PASS] test_native_nonAgentCannotSubmit() (gas: 1949782) +[PASS] test_native_pinnedApproveIsSafe_unpinnedIsNot() (gas: 1420015) +Suite result: ok. 15 passed; 0 failed; 0 skipped; finished in 24.11ms (13.79ms CPU time) + +Ran 41 tests for test/unit/10_ownerIntent.t.sol:PushAgentWalletOwnerIntentTest +[PASS] test_G01_grantWithIntent_relayerSubmits_mandateGranted() (gas: 693101) +[PASS] test_G02_grantWithIntent_ueaOwner() (gas: 1097643) +[PASS] test_G03_replay_revertsIntentGrantNonceMismatch() (gas: 700024) +[PASS] test_G04_tamperedSession_revertsIntentSessionMismatch() (gas: 86543) +[PASS] test_G05_zeroSessionHash_reverts() (gas: 84901) +[PASS] test_G06_expired() (gas: 77001) +[PASS] test_G07_wrongWalletField() (gas: 77288) +[PASS] test_G08_wrongOwnerField_revertsNotOwner() (gas: 76595) +[PASS] test_G09_wrongSigner() (gas: 91154) +[PASS] test_G10_signedUnderWalletDomain_reverts() (gas: 89330) +[PASS] test_G11_runsSameShapeChecks() (gas: 284374) +[PASS] test_G12_permissionIdEqualsOwnerPath() (gas: 1302028) +[PASS] test_G13_execFieldsIgnoredHere() (gas: 689691) +[PASS] test_G14_ownerBatchViaSelf_stillWorks() (gas: 1034495) +[PASS] test_G15_wrongExecutor_revertsExecutorMismatch() (gas: 80279) +[PASS] test_G15b_zeroExecutor_revertsExecutorMismatch() (gas: 78352) +[PASS] test_G16_wrongSignerChainId() (gas: 90932) +[PASS] test_X01_single() (gas: 149521) +[PASS] test_X02_batch_inOrder() (gas: 154440) +[PASS] test_X03_batch_selfCall_grantMandate_works() (gas: 721140) +[PASS] test_X04_nonOwnerLane() (gas: 57368) +[PASS] test_X05_wrongSeq() (gas: 58141) +[PASS] test_X06_replay() (gas: 151761) +[PASS] test_X07_expired() (gas: 56137) +[PASS] test_X08_wrongSigner() (gas: 86981) +[PASS] test_X09_tamperedCalldata() (gas: 58571) +[PASS] test_X10_tamperedMode() (gas: 57282) +[PASS] test_X11_zeroExecHash() (gas: 57250) +[PASS] test_X12_wrongWalletField() (gas: 55830) +[PASS] test_X13_wrongPushChainSalt() (gas: 87192) +[PASS] test_X14_signedUnderWalletDomain() (gas: 84488) +[PASS] test_X15_unsupportedExecType() (gas: 129252) +[PASS] test_X16_targetRevert_bubbles_andNonceUnwinds() (gas: 99555) +[PASS] test_X18_sessionSigNeverValidatesAsOwnerIntent() (gas: 62165) +[PASS] test_X19_grantFieldsIgnoredHere() (gas: 144912) +[PASS] test_X20_sameIntent_servesGrantThenExec() (gas: 799968) +[PASS] test_X21_reentrancyGuarded() (gas: 283144) +[PASS] test_X22_wrongExecutor_revertsExecutorMismatch() (gas: 59011) +[PASS] test_X23_wrongSignerChainId() (gas: 87336) +[PASS] test_X24_ueaOwner_executes() (gas: 552967) +[PASS] test_intentDomainSeparator_equalsFactory() (gas: 20944) +Suite result: ok. 41 passed; 0 failed; 0 skipped; finished in 26.99ms (20.85ms CPU time) + +Ran 6 tests for test/unit/27_naming.t.sol:NamingTest +[PASS] test_naming_IAGWIsTheWholeSurface() (gas: 4421) +[PASS] test_naming_eventTopics() (gas: 306) +[PASS] test_naming_identityStrings() (gas: 190583) +[PASS] test_naming_noLegacyVocabularyInABIs() (gas: 425814670) +[PASS] test_naming_renamedErrorSelectors() (gas: 174) +[PASS] test_naming_renamedFunctionSelectors() (gas: 2183) +Suite result: ok. 6 passed; 0 failed; 0 skipped; finished in 19.98ms (19.08ms CPU time) + +Ran 45 tests for test/unit/6_nativeRulebook.t.sol:URPNativeTest +[PASS] test_URP_NativeConfigOnGatewayFailsClosed() (gas: 260772) +[PASS] test_native_N1_uninitialisedRoutesToUniversalAndReverts() (gas: 27400) +[PASS] test_native_N2_expired() (gas: 259411) +[PASS] test_native_N4_targetMismatch() (gas: 260149) +[PASS] test_native_N5_selectorMismatch() (gas: 258837) +[PASS] test_native_N5_shortCalldataBecomesValueSelector() (gas: 258579) +[PASS] test_native_N6_valueExceedsLifetimeCap() (gas: 222765) +[PASS] test_native_N6_valueExceedsPerCallCap() (gas: 174731) +[PASS] test_native_N7_calldataTooShortForPin() (gas: 260769) +[PASS] test_native_N7_dirtyHighHalfIsAMismatch() (gas: 260100) +[PASS] test_native_N7_pinMismatch() (gas: 261614) +[PASS] test_native_N8_amountExceedsLifetimeCap() (gas: 311635) +[PASS] test_native_N8_amountExceedsPerCallCap() (gas: 261664) +[PASS] test_native_N8_calldataTooShortForAmount() (gas: 195269) +[PASS] test_native_N9_callLimitReached() (gas: 321265) +[PASS] test_native_N9_zeroMaxCallsIsUnlimited() (gas: 354885) +[PASS] test_native_assertSpent_exactEqualityOnAllThree() (gas: 388733) +[PASS] test_native_assertSpent_ghostReverts() (gas: 23997) +[PASS] test_native_assertSpent_wrongModeBothWays() (gas: 958045) +[PASS] test_native_creditRevert_notInitialisedOnNativeSlot() (gas: 268133) +[PASS] test_native_effectsLast_failedN9LeavesCountersUntouched() (gas: 331852) +[PASS] test_native_emitsNativeCallMetered() (gas: 307105) +[PASS] test_native_getConfig_revertsOnNativeSlot() (gas: 262015) +[PASS] test_native_getMode_neverReverts() (gas: 962185) +[PASS] test_native_getNativeConfig_revertsOnUniversalSlot() (gas: 720379) +[PASS] test_native_getters_emptySlotReturnsZeroed() (gas: 68369) +[PASS] test_native_happyPath_returnsSuccessAndMeters() (gas: 315419) +[PASS] test_native_initStoresModeAndConfig() (gas: 270538) +[PASS] test_native_init_acceptsExactlyMaxPins() (gas: 573601) +[PASS] test_native_init_forcesCountersToZero() (gas: 265013) +[PASS] test_native_init_legacyBareEncodingReverts() (gas: 26249) +[PASS] test_native_init_refusesReinitAsNative() (gas: 263448) +[PASS] test_native_init_refusesReinitAsUniversalAfterNative() (gas: 708154) +[PASS] test_native_init_rejectsGatewayTarget() (gas: 40755) +[PASS] test_native_init_rejectsPastExpiry() (gas: 36365) +[PASS] test_native_init_rejectsTooManyPins() (gas: 44741) +[PASS] test_native_init_rejectsValueOnlyWithAmountRule() (gas: 40086) +[PASS] test_native_init_rejectsValueOnlyWithPins() (gas: 40968) +[PASS] test_native_init_rejectsZeroExpiry() (gas: 36062) +[PASS] test_native_init_rejectsZeroTarget() (gas: 36053) +[PASS] test_native_legacyUniversalSlot_isGuardedByTheViews() (gas: 728424) +[PASS] test_native_valueOnly_emptyCalldataPasses() (gas: 228009) +[PASS] test_native_valueOnly_rejectsShortNonEmptyCalldata() (gas: 232976) +[PASS] test_native_zeroValueCallsExhaustMaxCalls() (gas: 302121) +[PASS] test_native_zeroValueZeroAmountStillMetersACall() (gas: 294907) +Suite result: ok. 45 passed; 0 failed; 0 skipped; finished in 7.95ms (5.68ms CPU time) + +Ran 1 test for test/unit/7_externalAgentViaUEA.t.sol:ExternalAgentViaUEATest +[PASS] test_UEAAgent_actsThroughItsUEA() (gas: 999384) +Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.91ms (883.63µs CPU time) + +Ran 9 tests for test/integration/8_e2e.t.sol:E2ETest +[PASS] test_BeneficiaryPin_BindsEndToEnd() (gas: 925621) +[PASS] test_BobFlow_EOAAgent() (gas: 3220726) +[PASS] test_BobFlow_UEAAgent() (gas: 3501116) +[PASS] test_BothModes_CoexistOnOneWallet() (gas: 2643467) +[PASS] test_GatewayRevert_UnwindsEverything() (gas: 1537682) +[PASS] test_LifetimeCap_BindsEndToEnd() (gas: 1488043) +[PASS] test_NativeFlow_EndToEnd() (gas: 1374130) +[PASS] test_OwnerWithdraws_MidMandate() (gas: 886373) +[PASS] test_UniversalFlow_UnchangedByNativeMode() (gas: 3242425) +Suite result: ok. 9 passed; 0 failed; 0 skipped; finished in 17.60ms (15.11ms CPU time) + +Ran 12 tests for test/unit/12_nativeGrant.t.sol:PushAgentWalletNativeGrantTest +[PASS] test_forbidden_engineFallbackFlag() (gas: 35421) +[PASS] test_forbidden_theEngine() (gas: 38107) +[PASS] test_forbidden_theFactory() (gas: 37990) +[PASS] test_forbidden_theValidator() (gas: 35991) +[PASS] test_forbidden_theWalletItself() (gas: 35925) +[PASS] test_forbidden_urp() (gas: 36211) +[PASS] test_forbidden_zeroAddress() (gas: 35458) +[PASS] test_gasGate_maximalGrantUnder8M() (gas: 6252249) +Logs: + GAS GATE - maximal 8x8 native grant: 6135957 + GAS GATE - budget: 8000000 + +[PASS] test_gasGate_stopMandateOnMaximalMandateUnder2M() (gas: 5381329) +Logs: + GAS GATE - revokeRules on a maximal native mandate: 79539 + GAS GATE - budget: 2000000 + +[PASS] test_gasReport_stopAllOverFiveMaximalMandates() (gas: 26789418) +Logs: + GAS REPORT - revokeAllRules over five maximal native mandates: 389183 + +[PASS] test_grantEmitsMandateType() (gas: 626547) +[PASS] test_valueSelectorIsPermitted() (gas: 552403) +Suite result: ok. 12 passed; 0 failed; 0 skipped; finished in 51.56ms (13.40ms CPU time) + +Ran 7 tests for test/unit/17_agentConfigLib.t.sol:AgentConfigLibTest +[PASS] testFuzz_decode_anyLengthOtherThan32IsZero(bytes) (runs: 1024, μ: 9377, ~: 9379) +[PASS] testFuzz_decode_dirtyUpperBytesAreZero(uint96,address) (runs: 1024, μ: 9377, ~: 9377) +[PASS] testFuzz_decode_roundTripsEveryNonZeroAddress(address) (runs: 1024, μ: 9653, ~: 9653) +[PASS] test_decode_oldEcdsaConfigIsRejected() (gas: 8899) +[PASS] test_decode_wellFormedConfigReturnsAgent() (gas: 8551) +[PASS] test_decode_wrongLengthIsZero() (gas: 15370) +[PASS] test_decode_zeroAddressIsZero() (gas: 6339) +Suite result: ok. 7 passed; 0 failed; 0 skipped; finished in 75.92ms (114.40ms CPU time) + +Ran 36 tests for test/unit/2_ownerDoor.t.sol:PushAgentWalletTest +[PASS] testFuzz_CloneArgs_OwnerAndFactory(address,address) (runs: 1024, μ: 63730, ~: 63730) +[PASS] testFuzz_SupportsInterface_ExactlyThree(bytes4) (runs: 1024, μ: 9282, ~: 9282) +[PASS] testFuzz_W21_ERC1271_AlwaysInvalid(bytes32,bytes) (runs: 1024, μ: 9498, ~: 9489) +[PASS] test_AccountId() (gas: 13983) +[PASS] test_AgentDoor_IsLive_AndRefusesMalformedRequests() (gas: 697091) +[PASS] test_CloneArgs_OwnerAndFactory() (gas: 16610) +[PASS] test_DecodeBatch_MalformedCalldata_AllThreeGuards() (gas: 39613) +[PASS] test_DecodeBatch_SingleEncodedInBatchMode_RevertsNotSilentNoop() (gas: 65388) +[PASS] test_InstallModule_Guards() (gas: 143858) +[PASS] test_NonceViews_StartAtZero() (gas: 18051) +[PASS] test_OwnerDoor_RejectsNonDefaultExecAndExoticCallTypes() (gas: 41275) +[PASS] test_OwnerPath_BubblesInnerRevert() (gas: 80891) +[PASS] test_OwnerPath_RejectsNonOwner() (gas: 26832) +[PASS] test_OwnerPath_SurvivesDegradedMatrix() (gas: 1900565) +[PASS] test_Receive_AcceptsPC() (gas: 21915) +[PASS] test_StorageLayout_ExactlySixDeclarations() (gas: 14839333) +[PASS] test_SupportsInterface_DoesNotClaimERC7579Account() (gas: 17539) +[PASS] test_TokenReceiverHooks() (gas: 14441) +[PASS] test_UninstallModule_RequiresInstalled() (gas: 20698) +[PASS] test_W11_ModuleTypes_2_3_4_Rejected() (gas: 124381) +[PASS] test_W12_StipendIsCapped() (gas: 211462) +Logs: + uninstall gas with a burning callback: 106524 + +[PASS] test_W12_Uninstall_StipendSemantics() (gas: 313371) +[PASS] test_W13_EngineUninstall_WedgeGuard() (gas: 580100) +[PASS] test_W13_ThirdPartyValidator_NotProtected() (gas: 111188) +[PASS] test_W14_EngineGuard_FailsOpen() (gas: 604881) +[PASS] test_W20_InitializeAccount_FactoryOnlyOnce() (gas: 143778) +[PASS] test_W21_ERC1271_AlwaysInvalid() (gas: 13131) +[PASS] test_W22_EmptyWallet_RejectsAgents() (gas: 226310) +[PASS] test_W23_Events_Attribution_OwnerDoor() (gas: 65702) +[PASS] test_W23_NoEventOnFailedDispatch() (gas: 83695) +[PASS] test_W25_Clone_NoUpgradeSurface_ExactSelectorSet() (gas: 13649608) +[PASS] test_W25_ImplementationCannotBeInitialized() (gas: 47714) +[PASS] test_W25_ImplementationIsInertOnEveryDoor() (gas: 40418) +[PASS] test_W27_Immutables_SetAndReadableByClones() (gas: 3613882) +[PASS] test_W_execute_touchesOnlyTheCheckpointSlot() (gas: 355758) +[PASS] test_supportsExecutionMode() (gas: 18651) +Suite result: ok. 36 passed; 0 failed; 0 skipped; finished in 97.62ms (152.49ms CPU time) + +Ran 34 tests for test/unit/4_agentDoor.t.sol:PushAgentWalletAgentDoorTest +[PASS] testFuzz_W19_anyNonAgentRefused(address) (runs: 1024, μ: 92042, ~: 92042) +[PASS] test_AgentRequestMovesPCFromTheWalletsOwnBalance() (gas: 173565) +[PASS] test_HappyPath_ValidatesAndDispatches() (gas: 180435) +[PASS] test_PCValueAboveGate8IsRefused() (gas: 98387) +[PASS] test_U04_ZeroAmountThroughTheRealPath() (gas: 159010) +[PASS] test_U12_MeteringThroughTheRealPath() (gas: 187207) +[PASS] test_W02_BankedRequest_FailsAfterRegrant() (gas: 809363) +[PASS] test_W03_OpHash_Field6_MalformedBatchShapeIsRejected() (gas: 65132) +[PASS] test_W03_PermissionIdBindsTheAgent() (gas: 916773) +[PASS] test_W04_SameCallTwiceIsTwoActions() (gas: 233440) +[PASS] test_W05_ReentryIntoTheAgentDoorRefused() (gas: 700516) +[PASS] test_W07_Verdict_Enforced() (gas: 3211847) +[PASS] test_W08_Paymaster_AlwaysEmpty() (gas: 172295) +[PASS] test_W09_AgentDoor_SingleCallTypeOnly() (gas: 202414) +[PASS] test_W09_ExoticModes_RejectedByTheEngineWithNamedErrors() (gas: 134282) +[PASS] test_W18_ExecutionRevert_UnwindsAll() (gas: 311761) +[PASS] test_W19_OnlyTheAgentMayCall() (gas: 371950) +[PASS] test_W22_EmptyWallet_RejectsAgents_AgentHalf() (gas: 208096) +[PASS] test_W23_Events_Attribution_AgentDoor() (gas: 167920) +[PASS] test_W26_EngineBranch_SingleExecOnly() (gas: 173353) +[PASS] test_W26_UnconfiguredActionDiesAtThePolicyFloor() (gas: 58168) +[PASS] test_W28_AgentDoor_AlwaysBuildsUseMode() (gas: 182478) +[PASS] test_W29_AgentDoor_CannotSelfCall() (gas: 699080) +[PASS] test_W_agentDoorCannotReach_grantMandateWithSig() (gas: 1064003) +[PASS] test_W_agentDoor_engineUninstalled_refused() (gas: 130387) +[PASS] test_W_agentDoor_foreignValidatorSessionHasNoAgent() (gas: 845195) +[PASS] test_W_agentDoor_malformedConfigSessionHasNoAgent() (gas: 703877) +[PASS] test_W_agentDoor_neverTouchesOwnerLanes() (gas: 416436) +[PASS] test_W_agentDoor_revokedPermission_refused() (gas: 1154336) +[PASS] test_W_agentDoor_unknownPermission_refused() (gas: 42627) +[PASS] test_X17_ownerIntentSigNeverValidatesAsSessionSig() (gas: 122833) +[PASS] test_agentOf_lifecycle() (gas: 722119) +[PASS] test_agentOf_viaGrantMandateWithSig() (gas: 806167) +[PASS] test_gas_executeAsAgent_universalHappyPath() (gas: 214230) +Logs: + executeAsAgent universal steady-state gas: 41060 + +Suite result: ok. 34 passed; 0 failed; 0 skipped; finished in 111.17ms (128.72ms CPU time) + +Ran 20 tests for test/unit/1_factory.t.sol:AGWFactoryTest +[PASS] testFuzz_T02_PredictEqualsDeploy(address,uint8) (runs: 1024, μ: 410554, ~: 323057) +[PASS] test_T01_UpgradeIsAdminOnly() (gas: 2105333) +[PASS] test_T01a_StorageLayout_IsFrozen() (gas: 2394999) +[PASS] test_T01b_AddressStability_AcrossFactoryUpgrade() (gas: 2604443) +[PASS] test_T03_OwnerIsAlwaysCaller() (gas: 465186) +[PASS] test_T04a_IndexMonotonic_UnderDirectReentrancy() (gas: 2781886) +[PASS] test_T04b_IndexMonotonic_UnderForwardedReentrancy() (gas: 2746457) +[PASS] test_T05_Registry_Consistency() (gas: 815600) +[PASS] test_T06_Label_NeverAffectsAddress() (gas: 500367) +[PASS] test_T07_Pause_BlocksDeployOnly() (gas: 224216) +[PASS] test_T08_AtomicInit_NoUninitialisedWallet() (gas: 2612582) +[PASS] test_T09_InitializeIsOneShot() (gas: 20865) +[PASS] test_T09_NoImplementationSetter_ABI() (gas: 2363789) +[PASS] test_T10_EmptyWallet_IsValid() (gas: 242422) +[PASS] test_T11_ImplementationNotSet_Guard() (gas: 2276860) +[PASS] test_T11_InitializeGuards() (gas: 2237869) +[PASS] test_T12_SecondFactory_NewAddressSpace() (gas: 6000340) +[PASS] test_T13_PredictWallet_IndexBound() (gas: 461820) +[PASS] test_T14_AdminTransferIsDelayed() (gas: 86017) +[PASS] test_T14_OrdinaryRolesAreNotDelayed() (gas: 65954) +Suite result: ok. 20 passed; 0 failed; 0 skipped; finished in 161.55ms (182.60ms CPU time) + +Ran 20 tests for test/unit/18_checkpoints.t.sol:CheckpointsTest +[PASS] testFuzz_CP13_noNonOwnerPathTicks(address) (runs: 1024, μ: 714673, ~: 714673) +[PASS] test_CP01_freshWalletStartsAtZero() (gas: 12084) +[PASS] test_CP02_executeSingleTicksOnce() (gas: 75469) +[PASS] test_CP03_executeBatchTicksPerCall() (gas: 162502) +[PASS] test_CP04_tickPrecedesEachCall() (gas: 574052) +[PASS] test_CP05_sameBatchWithdrawalIsVisible() (gas: 982005) +[PASS] test_CP06_emptyBatchTicksNothing() (gas: 26619) +[PASS] test_CP07_revertedOwnerCallLeavesNoCheckpoint() (gas: 94760) +[PASS] test_CP08_executeWithSigTicksPerCall() (gas: 220515) +[PASS] test_CP09_grantTicksRulesGranted() (gas: 1341354) +[PASS] test_CP10_failedGrantTicksNothing() (gas: 54478) +[PASS] test_CP11_revokeRulesTicksRulesRevoked() (gas: 573120) +[PASS] test_CP12_revokeAllTicksOncePerId() (gas: 1614992) +[PASS] test_CP14_agentActionsNeverTick() (gas: 1326693) +[PASS] test_CP15_selfLifecycleCallTicksTwice() (gas: 576633) +[PASS] test_CP16_directEngineGrantTicksAsOwnerAction() (gas: 675610) +[PASS] test_CP17_lastCheckpointBlockTracksTheBlock() (gas: 158204) +[PASS] test_CP18_countersArePerWallet() (gas: 240135) +[PASS] test_CP19_ownerDoorStillTicksInDegradedStates() (gas: 554218) +[PASS] test_gas_ownerDoorCheckpointOverhead() (gas: 158870) +Logs: + owner execute single (steady state) gas: 15071 + owner execute batch of 5 (steady state) gas: 62736 + +Suite result: ok. 20 passed; 0 failed; 0 skipped; finished in 327.48ms (343.31ms CPU time) + +Ran 82 tests for test/unit/9_svmRulebook.t.sol:URPSvmTest +[PASS] testFuzz_svm_amountsAboveU64Refused(uint256) (runs: 1024, μ: 842627, ~: 842852) +[PASS] testFuzz_svm_anyPinnedPositionSubstituted(uint8,bytes32) (runs: 1024, μ: 852356, ~: 852560) +[PASS] testFuzz_svm_ratioPin(uint64,uint64) (runs: 1024, μ: 879981, ~: 900129) +[PASS] test_deriveVm_classifiesOnThePrefix() (gas: 11197) +[PASS] test_deriveVm_refusesEverythingElse() (gas: 24006) +[PASS] test_fixture_discriminatorsAreTheAnchorTags() (gas: 2796) +[PASS] test_svmInit_accountPinGuards() (gas: 149899) +[PASS] test_svmInit_ambiguousRulesRefused() (gas: 201104) +[PASS] test_svmInit_assetFromAnotherChainReverts() (gas: 524770) +[PASS] test_svmInit_ceaAccountEntriesValidated() (gas: 180359) +[PASS] test_svmInit_ceaAccountsMustContainTheCea() (gas: 882609) +[PASS] test_svmInit_codelessAssetReverts() (gas: 81263) +[PASS] test_svmInit_dataPinGuards() (gas: 1170777) +[PASS] test_svmInit_dataPinOnDatalessRuleRefused() (gas: 71673) +[PASS] test_svmInit_datalessBesideTaggedIsNotAmbiguous() (gas: 783712) +[PASS] test_svmInit_discriminatorLenGuards() (gas: 143543) +[PASS] test_svmInit_distinctRulesOnOneProgramAccepted() (gas: 783844) +[PASS] test_svmInit_duplicatePinRefused() (gas: 854702) +[PASS] test_svmInit_eip155GrantReportsEvm() (gas: 727471) +[PASS] test_svmInit_expiryGuards() (gas: 94064) +[PASS] test_svmInit_forbiddenProgramsRefusedInAllowList() (gas: 365238) +[PASS] test_svmInit_gatewaySelfWithdrawDiscriminatorIsStillRefused() (gas: 64328) +[PASS] test_svmInit_identityFieldsMustBeSet() (gas: 142763) +[PASS] test_svmInit_listBoundsNamed() (gas: 169676) +[PASS] test_svmInit_maxAccountsAboveTheBoundRefused() (gas: 831143) +[PASS] test_svmInit_oneUselessPinIsAccepted() (gas: 683552) +[PASS] test_svmInit_programListOutOfRange() (gas: 143234) +[PASS] test_svmInit_reinitRefusedAcrossEverything() (gas: 820135) +[PASS] test_svmInit_revertingAssetReverts() (gas: 79665) +[PASS] test_svmInit_ruleWithoutPinRefused() (gas: 73115) +[PASS] test_svmInit_shortTagThatIsNotAPrefixAccepted() (gas: 784673) +[PASS] test_svmInit_storesTermsAndRoutesToSvm() (gas: 841533) +[PASS] test_svmInit_unsupportedNamespaceRevertsNamed() (gas: 72192) +[PASS] test_svmInit_vacuousOrImpossibleDataPinValuesRefused() (gas: 1007114) +[PASS] test_svm_S10_revertRecipient() (gas: 845824) +[PASS] test_svm_S11_recipientShapes() (gas: 931908) +[PASS] test_svm_S12_emptyPayloadIsNotAWithdraw() (gas: 815117) +[PASS] test_svm_S12_malformedPayloadCodes() (gas: 883889) +[PASS] test_svm_S13_bounds() (gas: 932649) +[PASS] test_svm_S13_withdrawInstructionRefused() (gas: 816975) +[PASS] test_svm_S14_recipientMustEqualPayloadTarget() (gas: 847241) +[PASS] test_svm_S15_forbiddenTargets() (gas: 1058496) +[PASS] test_svm_S16_fixedAccountCountMismatch() (gas: 854461) +[PASS] test_svm_S16_programNotAllowed() (gas: 933802) +[PASS] test_svm_S16_shortIxDataNeverReadsPastItself() (gas: 683945) +[PASS] test_svm_S17_accountPinBelowCount() (gas: 861602) +[PASS] test_svm_S17_dataTooShortForPin() (gas: 848943) +[PASS] test_svm_S17_destinationRedirectedRefused() (gas: 852092) +[PASS] test_svm_S17_feeFieldPinned() (gas: 850913) +[PASS] test_svm_S17_fromEndDataTooShortByOne() (gas: 832164) +[PASS] test_svm_S17_fromStartDataTooShort() (gas: 843389) +[PASS] test_svm_S17_ratioFloorRelativeToInput() (gas: 1002727) +[PASS] test_svm_S17_slippageCeiling() (gas: 936673) +[PASS] test_svm_S17_sourceSubstitutionRefused() (gas: 849173) +[PASS] test_svm_S18_ceaAccountAtUnpinnedIndexRefused() (gas: 970323) +[PASS] test_svm_S18_unpinnedFeeAccountIsWhatTheRuleCatches() (gas: 830674) +[PASS] test_svm_S2_expired() (gas: 838899) +[PASS] test_svm_S3_wrongTarget() (gas: 840329) +[PASS] test_svm_S4_calldataShape() (gas: 826218) +[PASS] test_svm_S5_assetMismatch() (gas: 845591) +[PASS] test_svm_S6_perCallCap() (gas: 842272) +[PASS] test_svm_S6b_amountAboveU64() (gas: 954653) +[PASS] test_svm_S8_pcValueCap() (gas: 843790) +[PASS] test_svm_S9_uncappedGasSwap() (gas: 843914) +[PASS] test_svm_assertSpentReadsTheSvmCounter() (gas: 908527) +[PASS] test_svm_creditRevertCreditsTheSvmCounter() (gas: 1006875) +[PASS] test_svm_datalessRuleMatchesOnlyEmptyIxData() (gas: 758172) +[PASS] test_svm_fixedAccountCountAcceptsExactCount() (gas: 899689) +[PASS] test_svm_forbiddenProgramConstantsMatchBase58() (gas: 1920703) +[PASS] test_svm_fromStartPinsAndRawBytesEq() (gas: 873444) +[PASS] test_svm_getSvmConfigOnEmptySlotIsZeroed() (gas: 52526) +[PASS] test_svm_getSvmConfigOnNativeSlotReverts() (gas: 139378) +[PASS] test_svm_gettersRouteByFamily() (gas: 844474) +[PASS] test_svm_goodRequestPassesAndMetersSpend() (gas: 929443) +[PASS] test_svm_gteFloorPin() (gas: 847694) +[PASS] test_svm_leftAlignedEqPinMatchesTheLittleEndianField() (gas: 844327) +[PASS] test_svm_lifetimeCapAccumulates() (gas: 1519703) +[PASS] test_svm_wallet_grantLandsAsSvmConfigWithNoWalletChange() (gas: 1354445) +[PASS] test_svm_wallet_unsupportedNamespaceGrantFailsNamed() (gas: 336175) +[PASS] test_svm_wallet_validRequestReachesTheGateway() (gas: 1497206) +[PASS] test_svm_wallet_violationSurfacesAsTheUrpGate() (gas: 1422349) +[PASS] test_svm_zeroAmountPassesAndWritesNothing() (gas: 903865) +Suite result: ok. 82 passed; 0 failed; 0 skipped; finished in 619.69ms (664.90ms CPU time) + +Ran 75 tests for test/unit/5_universalRulebook.t.sol:URPTest +[PASS] test_DeadOffset_FailsClosed() (gas: 295351) +[PASS] test_U01_ForbiddenCEA_BeatsAllowlist() (gas: 383850) +[PASS] test_U01_ForbiddenInnerTargets_walletUrpGateway() (gas: 361015) +[PASS] test_U02_AgentCannotReset() (gas: 394641) +[PASS] test_U03_gate10_InvalidRevertRecipient() (gas: 324678) +[PASS] test_U03_gate11_RecipientMustBeEmpty() (gas: 321961) +[PASS] test_U03_gate12_MalformedMulticallBodyRevertsUnnamed() (gas: 355636) +[PASS] test_U03_gate12_PayloadNotMulticall() (gas: 370251) +[PASS] test_U03_gate13_BatchSizeOutOfRange() (gas: 322503) +[PASS] test_U03_gate14_ForbiddenInnerTarget() (gas: 327167) +[PASS] test_U03_gate14_MalformedInnerCalldata_shortEntry() (gas: 326376) +[PASS] test_U03_gate15_CallNotAllowed() (gas: 347160) +[PASS] test_U03_gate16_InnerValueExceedsAllowance() (gas: 327962) +[PASS] test_U03_gate1_NotInitialized() (gas: 37227) +[PASS] test_U03_gate2_MandateExpired() (gas: 319199) +[PASS] test_U03_gate3_InvalidTarget() (gas: 319520) +[PASS] test_U03_gate4a_CalldataTooShort() (gas: 316486) +[PASS] test_U03_gate4a_ZeroSelectorIsNotConflated() (gas: 305216) +[PASS] test_U03_gate4b_InvalidSelector() (gas: 317978) +[PASS] test_U03_gate4c_MalformedOutboundRequest() (gas: 318201) +[PASS] test_U03_gate4d_MalformedBodyRevertsUnnamed() (gas: 316659) +[PASS] test_U03_gate5_AssetMismatch() (gas: 323271) +[PASS] test_U03_gate6_AmountExceedsCap() (gas: 322925) +[PASS] test_U03_gate7_TotalSpendCapExceeded() (gas: 368869) +[PASS] test_U03_gate8_PCValueExceedsCap() (gas: 323272) +[PASS] test_U03_gate9_UncappedGasSwapRejected() (gas: 322471) +[PASS] test_U04_ZeroAmount_RedeployPath() (gas: 328197) +[PASS] test_U04_ZeroAmount_StillGated() (gas: 316864) +[PASS] test_U05_LastEntryPoisonsBatch() (gas: 375821) +[PASS] test_U06_BatchBounds() (gas: 454924) +[PASS] test_U07_LifetimeCap_AtTheCrossing() (gas: 396550) +[PASS] test_U07_UnlimitedNeverTrips() (gas: 349853) +[PASS] test_U07_ZeroPerCallCap_RedeploysOnly() (gas: 318839) +[PASS] test_U08_Expiry_Semantics() (gas: 434801) +[PASS] test_U08_NeverExpires_IsExplicit() (gas: 338862) +[PASS] test_U09_RoutingPins() (gas: 338495) +[PASS] test_U10_UncappedGasField() (gas: 350922) +[PASS] test_U11_Beneficiary_BoundsAndPin() (gas: 349848) +[PASS] test_U11_NoBeneficiaryRuleSkipsTheCheck() (gas: 316269) +[PASS] test_U12_EffectsLast_MeteringEvent() (gas: 352591) +[PASS] test_U12_SpendAccumulates() (gas: 368153) +[PASS] test_U13_Credit_ModuleOnly() (gas: 402424) +[PASS] test_U14_Credit_OncePerId() (gas: 434878) +[PASS] test_U14_MisroutedCredit_IsRetryable() (gas: 400784) +[PASS] test_U15_CreditAfterExpiry_LandsHarmlessly() (gas: 390430) +[PASS] test_U15_Credit_Saturates() (gas: 366043) +[PASS] test_U16_AssertSpent_CreditForcesRecomposition() (gas: 378760) +[PASS] test_U16_AssertSpent_ExactEquality() (gas: 351336) +[PASS] test_U16_AssertSpent_GhostConfigHasNoSilentPass() (gas: 25750) +[PASS] test_U17_KeyedIsolation() (gas: 637244) +[PASS] test_U17_NoMultiplexerArgumentReachesTheStrangerSlice() (gas: 662950) +[PASS] test_U18_ExecutionRevert_UnwindsSpend() (gas: 362157) +[PASS] test_U20_AllowList_Bounds() (gas: 2238633) +[PASS] test_U20_WorstCaseGas() (gas: 2002138) +Logs: + U-20 worst-case checkAction gas: 210314 + +[PASS] test_U21_MinBodyLen_IsPinnedToTheStruct() (gas: 1253) +[PASS] test_U22_TrailingGarbage_Decodes() (gas: 351131) +[PASS] test_URP_exactSelectorSet() (gas: 44542734) +[PASS] test_constructor_rejectsZeroAddresses() (gas: 5060155) +[PASS] test_constructor_setsImmutables() (gas: 28097) +[PASS] test_getConfig_roundTripsIncludingAllowList() (gas: 314636) +[PASS] test_init_acceptsZeroPerCallCap() (gas: 286771) +[PASS] test_init_emitsBothPolicySetEvents() (gas: 301392) +[PASS] test_init_ignoresSuppliedSpent() (gas: 307854) +[PASS] test_init_rejectsZeroAssetAndZeroCEA() (gas: 62360) +[PASS] test_sendOutboundSelector_matchesHarness() (gas: 11846) +[PASS] test_supportsInterface() (gas: 15602) +[PASS] test_upgradeable_anchorsLiveInProxyStorage() (gas: 25494) +[PASS] test_upgradeable_configStructLayoutIsFrozen() (gas: 426962394) +[PASS] test_upgradeable_implementationCannotBeInitialised() (gas: 19265) +[PASS] test_upgradeable_onlyAdminOwnerCanUpgrade() (gas: 4820496) +[PASS] test_upgradeable_preUpgradeConfigRefusesReinit() (gas: 386193) +[PASS] test_upgradeable_preUpgradeUniversalConfigStillValidates() (gas: 5209538) +[PASS] test_upgradeable_proxyCannotBeReinitialised() (gas: 23537) +[PASS] test_upgradeable_storageLayoutIsFrozen() (gas: 47609500) +[PASS] test_upgradeable_storageSurvivesUpgrade() (gas: 5185834) +Suite result: ok. 75 passed; 0 failed; 0 skipped; finished in 941.41ms (1.10s CPU time) + +Ran 15 tests for test/unit/16_agentValidator.t.sol:PushSessionValidatorTest +[PASS] testFuzz_P01_ValidateConfig_MatchesRuntime(bytes,uint256,uint8,bytes) (runs: 1024, μ: 9421, ~: 9598) +[PASS] testFuzz_SV02_anySenderButTheAgentReturnsFalse(address) (runs: 1024, μ: 12685, ~: 12685) +[PASS] testFuzz_SV04_malformedConfigAlwaysReverts(bytes,bytes) (runs: 1024, μ: 11016, ~: 11015) +[PASS] testFuzz_SV05_hashIsIgnored(bytes32) (runs: 1024, μ: 9513, ~: 9513) +[PASS] testFuzz_SV06_validateConfigNeverReverts(bytes) (runs: 1024, μ: 6893, ~: 6877) +[PASS] test_P01_LawOnKnownInputs() (gas: 40651) +[PASS] test_SV01_agentSenderValidates() (gas: 9494) +[PASS] test_SV02_wrongSenderReturnsFalse() (gas: 13242) +[PASS] test_SV03_sigLengthNot20ReturnsFalse() (gas: 18122) +[PASS] test_SV04_malformedConfigReverts() (gas: 31739) +[PASS] test_SV07_validatorCallsNothing() (gas: 292856) +[PASS] test_SV08_exactSelectorSet() (gas: 107606) +[PASS] test_V10_isModuleType() (gas: 12820) +[PASS] test_holdsNoStorage() (gas: 99331) +[PASS] test_statelessLifecycleIsNoop() (gas: 12982) +Suite result: ok. 15 passed; 0 failed; 0 skipped; finished in 999.39ms (1.45s CPU time) + +Ran 27 test suites in 1.00s (3.56s CPU time): 563 tests passed, 0 failed, 6 skipped (569 total tests) diff --git a/plan/agw/review-summary.md b/plan/agw/review-summary.md new file mode 100644 index 00000000..404bb9f1 --- /dev/null +++ b/plan/agw/review-summary.md @@ -0,0 +1,30 @@ +# AGW review corrections and evidence + +This concise record replaces duplicate historical plans and logs, which were archived locally before preparing the Git package. + +## Consequential corrections + +- The first review used 610a640. A fetch completed during drafting but was not consumed before handoff, so the recommendation missed D3 at 0f279ca. The engine-extension recommendation is withdrawn. Observe an exact fetched SHA before analysis and recheck freshness before sharing. +- The delivered sender adapter preserves SmartSession. Wallet-authored USE bytes, sender/account binding and closed alternate paths are essential invariants. +- Contract chapters 9 and 10 define accepted limits and 23 delegated requirements, now mapped in [integrator obligations](contract-integrator-obligations.md). +- Gateway main's six fields are older; newer source and named Donut evidence support eight fields. A future removal is a release-intent question. +- Core cb69e0b marketplace requires expiry equality, not a universal standalone rule constraint. +- Owner batching is the documented replacement design. Stronger tests cover initialized config, events, old/new ID usability, mid-initialization rollback and native counters. +- Duplicate rules are owner-authorized; SDK ambiguity behavior must be explicit. Mandatory contract uniqueness was not established as a security necessity. +- Tracking is hash/UTX based. Dedicated request composition, logical sender fields and progress integration remain SDK work. +- Historical clones cannot acquire new ABIs. Addresses and counterfactual funding are generation-specific. Named historical deployment observations do not prove no separate new deployment exists. +- Checkpoints landed in 6b7dbf4, included in e704d5b. Stored counts and per-call ordering deliberately revise the owner invariant. Compare counts, not only blocks; allowance pulls can occur without a checkpoint. +- Binder was never in reviewed code and current Notion drops it for v1. Older proposals or a screenshot question do not authorize adding it. +- The latest Notion target makes create deployment/grant only and uses assets[]/maxGasPerCall. G23/G24 track new wire, read and assertion gaps. + +## Validation history + +| Revision | Baseline | Review evidence | +| --- | --- | --- | +| 610a640 | 547 passed, 0 failed, 7 skipped | Four review tests passed; independently reproduced | +| 0f279ca | 542 passed, 0 failed, 6 skipped | Seven stronger review tests passed; independently reproduced | +| e704d5b | 563 passed, 0 failed, 6 skipped | Seven review tests pass; build/pin checked; [retained evidence](research/validation-e704d5b/README.md) | + +Old Ed25519 fork behavior is historical; that crypto path is removed from the sender adapter. Direct node vectors did not prove complete wallet execution. Local tests use a recording gateway and do not prove real burn or settlement. Current skips remain unverified live/deployment checks. + +Use the [gap register](gaps.md), [Harsh draft](questions-harsh.md), [Zaryab draft](questions-zaryab.md) and [baseline](current-baseline.md) for current decisions. No message or production implementation change has been made. diff --git a/plan/agw/scripts/import-notion-exports.py b/plan/agw/scripts/import-notion-exports.py new file mode 100644 index 00000000..d9ef2f6a --- /dev/null +++ b/plan/agw/scripts/import-notion-exports.py @@ -0,0 +1,121 @@ +#!/usr/bin/env python3 +"""Import downloaded Notion ZIPs by page ID; preserve snapshots and diffs. + +This script does not authenticate to Notion or download pages. Export using +the saved source links, then supply the ZIPs. Default requires all known pages. +""" +import argparse +import difflib +import hashlib +import json +import re +import shutil +from datetime import datetime, timezone +from pathlib import Path +from urllib.parse import quote +from zipfile import ZipFile + + +def digest(data): + return hashlib.sha256(data).hexdigest() + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('archives', nargs='+', type=Path) + parser.add_argument('--partial', action='store_true', help='Explicitly allow a subset of known pages') + parser.add_argument('--dry-run', action='store_true') + args = parser.parse_args() + root = Path(__file__).resolve().parents[1] + manifest_path = root / 'source-manifest.json' + manifest = json.loads(manifest_path.read_text()) + known = {s['page_id']: s for s in manifest['sources']} + incoming = {} + unknown = [] + replacements = {} + for archive in args.archives: + with ZipFile(archive) as z: + for entry in z.namelist(): + match = re.search(r'([a-f0-9]{32})\.md$', entry) + if not match: + continue + page_id = match[1] + if page_id not in known: + unknown.append(entry) + continue + data = z.read(entry) + if page_id in incoming and incoming[page_id]['raw'] != data: + raise SystemExit(f'Conflicting exports for {page_id}; supply one revision per page') + incoming[page_id] = {'archive_path': archive, 'entry': entry, 'raw': data} + parts = Path(entry).parts + # Match both sibling and nested Notion export link forms. + for start in range(len(parts)): + name = '/'.join(parts[start:]) + replacements[quote(name, safe='/()+,')] = Path(known[page_id]['local_file']).name + missing = set(known) - set(incoming) + if missing and not args.partial: + raise SystemExit('Missing known pages: ' + ', '.join(known[p]['title'] for p in sorted(missing))) + if not incoming: + raise SystemExit('No known Notion pages found') + now = datetime.now(timezone.utc) + run_id = now.strftime('%Y%m%dT%H%M%S%fZ') + run_dir = root / 'notion/history' / run_id + rows = [] + for page_id, payload in incoming.items(): + source = known[page_id] + local = root / source['local_file'] + old = local.read_bytes() + if digest(old) != source['sha256']: + raise SystemExit(f'Local snapshot edited since last import: {local}; reconcile it first') + body = payload['raw'].decode('utf-8') + for old_link, new_link in sorted(replacements.items(), key=lambda x: len(x[0]), reverse=True): + body = body.replace(old_link, new_link) + new = body.encode('utf-8') + payload['normalized'] = new + changed = old != new + diff = ''.join(difflib.unified_diff(old.decode().splitlines(True), body.splitlines(True), + fromfile=source['local_file'] + ' (previous)', + tofile=source['local_file'] + ' (refreshed)')) + payload['diff'] = diff + rows.append({'page_id': page_id, 'title': source['title'], 'local_file': source['local_file'], + 'changed': changed, 'previous_sha256': digest(old), 'sha256': digest(new), + 'raw_export_sha256': digest(payload['raw'])}) + print(json.dumps({'checked': len(rows), 'changed': sum(r['changed'] for r in rows), + 'missing': sorted(missing), 'unknown_export_entries': unknown, 'pages': rows}, indent=2)) + if args.dry_run: + return + run_dir.mkdir(parents=True) + shutil.copy2(manifest_path, run_dir / 'manifest-before.json') + archive_dir = root / 'notion/exports' / run_id + archive_dir.mkdir(parents=True) + archive_map = {} + for index, archive in enumerate(args.archives, 1): + dest = archive_dir / f'export-{index}.zip' + shutil.copy2(archive, dest) + archive_map[archive] = str(dest.relative_to(root)) + for row in rows: + source = known[row['page_id']] + payload = incoming[row['page_id']] + local = root / source['local_file'] + if row['changed']: + shutil.copy2(local, run_dir / local.name) + (run_dir / (local.stem + '.diff')).write_text(payload['diff']) + local.write_bytes(payload['normalized']) + source.update(sha256=row['sha256'], raw_export_sha256=row['raw_export_sha256'], + pulled_on=now.date().isoformat(), pulled_at=now.isoformat(), + archive=archive_map[payload['archive_path']], export_entry=payload['entry']) + manifest['last_refresh_at'] = now.isoformat() + if not missing: + manifest['snapshot_date'] = now.date().isoformat() + manifest_path.write_text(json.dumps(manifest, indent=2) + '\n') + report = {'run_id': run_id, 'pulled_at': now.isoformat(), 'complete': not missing, + 'missing_page_ids': sorted(missing), 'unknown_export_entries': unknown, + 'archives': list(archive_map.values()), 'pages': rows, + 'review_status': 'No content changes' if not any(r['changed'] for r in rows) else 'Review required'} + (run_dir / 'refresh.json').write_text(json.dumps(report, indent=2) + '\n') + (root / 'latest-refresh.json').write_text(json.dumps(report, indent=2) + '\n') + print(f'Saved refresh history: {run_dir.relative_to(root)}') + + +if __name__ == '__main__': + main() diff --git a/plan/agw/sdk-design-review.md b/plan/agw/sdk-design-review.md new file mode 100644 index 00000000..05780258 --- /dev/null +++ b/plan/agw/sdk-design-review.md @@ -0,0 +1,106 @@ +# AGW SDK design review + +The proposed design adds AGW management and execution to `@pushchain/core` through the API in [page 5](notion/5-sdk-agw.md). It keeps the existing signer and transaction machinery, while introducing a separate wallet execution context. The public API is the agreed target; this review proposes internal boundaries and identifies the evidence needed to implement them correctly. + +Review status: proposed architecture, pending [gap resolutions](gaps.md) and matching multi-asset artifacts/deployment. This document does not claim that the new contract methods are deployed. + +## Core design + +There are two accounts to keep separate. The connected signer's Push identity is the native EOA or the external key's UEA. The execution account is normally that identity, but becomes the AGW when `agenticWallet` is supplied. The signer authorizes the transaction and pays its Push execution gas; the AGW owns its assets and pays wallet outbound fees. + +`client.agentic.wallet(address)` is a management handle. It reads and manages that wallet through the connected signer. It never becomes a sender. `PushChain.initialize(signer, { agenticWallet })` creates a client that executes through the wallet. The owner goes through `execute`; an agent goes through `executeAsAgent` under on-chain rules. + +`agentic.derive`, `agentic.list` and wallet creation must use the connected signer's Push identity even when `universal.account` exposes an AGW. Deriving a new owner wallet from the displayed execution account would create the wrong ownership model. + +## Suggested internal modules + +Names in this table describe proposed modules, not files that already exist. + +| Module | Responsibility | Boundary | +| --- | --- | --- | +| Agentic namespace | `derive`, `create`, `list`, `wallet` and owner-scoped coordination | Uses connected signer identity and network configuration | +| Wallet management | Info, owner, label, checkpoints and rules lifecycle | Reads arbitrary wallets; writes require owner authorization | +| Contract adapter | Factory, wallet, policy and engine ABIs, capabilities, views and log decoding | Contains version-sensitive contract surface | +| Rules codec | Selectors, terms, envelope, IDs, beneficiary offsets and decode | Pure operations where all required context is supplied; verified against contract vectors | +| Execution context | Wallet address, connected Push identity, origin and selected door | Preserves identity separation; rechecks authorization as required | +| Wallet transaction composer | ERC-7579 calls and wallet-originated gateway requests | Does not route outbound through the signer's CEA | +| Response adapter | AGW `from`, signer `origin`, destination hashes, progress and errors | Reuses core receipt tracking with explicit AGW context | +| Read reconstruction | Factory slots, labels, rules, references, spend and checkpoints | Uses defined views or bounded event reconstruction | + +Extend `PushChain` initialization and namespace wiring in `packages/core/src/lib/push-chain/push-chain.ts`. Integrate transaction composition and tracking with the orchestrator modules under packages/core/src/lib/orchestrator. Centralize contract version handling rather than distributing ABI checks across public methods. + +## Creation path + +1. Resolve the connected signer's Push identity and target network. +2. Derive the wallet and index through the factory; verify any pure mirror against contract vectors. +3. Validate structural inputs, agent ownership restrictions, unique agent-chain pairs, destination-chain assets, targets and encoding context before requesting signatures. Resolve each assets[].token to its Push PRC20 using trusted chain context. +4. Compose deployment and rule grants only. Updated CreateOptions has no funds or pc inputs. Funding and bounded owner gateway approvals are a separate normal-account operation; they must not be silently performed by create. +5. Select a supported creation strategy. Current native batching can be atomic through EIP-7702 or sequential through core's fallback; expose the actual strategy and any partial failure. +6. Resolve assigned rule IDs from matched contract behavior and receipt events, preserving input order. Return the specified wallet, index, rules IDs and transaction response. + +Concurrent creations and grants can invalidate a predicted index or grant nonce. Define simulation, re-read and retry behavior without signing or returning stale IDs. The factory's proposed batch entry is missing from the reviewed change-set diff (G15). + +## Management writes + +Rule updates follow the specified assert-spend, revoke, grant order. The replacement creates a new ID and resets counters. All pairs must use an atomic path; a sequential core fallback cannot satisfy that guarantee. Missing atomic capability should be an explicit failure until an accepted alternative is defined (G14). + +Revocation accepts explicit IDs or `{ all: true }`. Bare revocation fails with `REVOKE_NEEDS_TARGET`. Keep spend reads and existence checks consistent with policy initialization flags so an unknown configuration is not decoded as an active zero-valued rule. + +Label changes remain a proposed cosmetic feature. Current e704d5b records one checkpoint before each owner call, plus one per successful grant/revoked ID; owner replacement batches therefore add five. Compare evaluator baseline counts rather than only blocks. This accounting does not observe allowance pulls that require no wallet call. Define reads and log reconstruction with the matching contract events before implementing `info`, `list` and `checkpoints` (G08). + +## Sending through the wallet + +1. Reject forbidden operations and any `from` before signing. +2. Resolve the destination chain from the transaction, normalizing a Push destination to the connected Push network. +3. On the owner door, compose `execute`; on the agent door, fetch the matching enabled rule for this signer and destination on every send. +4. If no rule exists, throw `NO_RULES_FOR_CHAIN` before requesting a signature. The SDK does not reproduce URP's authorization policy in the send path. +5. Compose native calls or policy-compatible outbound calls executed from the AGW. Owner gateway approvals are separate setup operations; do not inject unrestricted approvals into the agent path. The destination account is the AGW's CEA, derived from the AGW address. +6. Apply signer gas checks with the specified first-use external UEA exception. Keep wallet outbound PC separate from signer gas. +7. Send through the existing signer transport. Decode wallet and policy errors into `AgenticRevertError`, retaining core's structured error information. +8. Return a response with AGW `from` and signer `origin`. Track the destination leg and propagate per-call hooks into `wait()`. + +Do not pass an AGW outbound directly into the current signer-based Route 2 implementation: it composes calls from the signer's UEA and would derive the wrong destination CEA. Reuse encoding and tracking primitives with an explicit wallet context instead. + +## Identity and authorization invariants + +- A native Push agent is its EOA; an external agent is its UEA for the actual origin chain. The same external EVM key on different chains has different UEAs. +- Agent authorization checks the connected Push sender. The old session-key validator scheme is historical context, not the new SDK API. +- Owner management and owner execution remain distinct. An owner can manage the wallet from an ordinary client and execute as it from an agentic client. +- Revocation takes effect for future Push execution; an outbound already dispatched can still finish on its destination. +- The gas payer, wallet asset owner and destination CEA must stay consistent in payloads, receipts, tracking and progress events. + +## Compatibility and capability handling + +Preserve existing clients that initialize without `agenticWallet`. Specify read-only and `reinitialize` behavior before changing the option types (G17). Do not accidentally let a read-only identity reach a signing path. + +Add `READ.CHAIN` as required by the spec. Normalize the existing `'web2:https'` input during the compatibility window while exposing the new `'web2'` constant (G16). Review the existing `READ.WEB2` alias as part of that migration. + +Capabilities depend on the selected contract deployment: sender-gated execution, label mutation, checkpoints, batch creation, gateway layout and SVM destination rulebook. Missing deployment support should be explicit before signing. Do not substitute a legacy contract call merely because its name resembles the required operation. + +## Optional marketplace and job integration + +`utils.agentic.compileCard` produces `Rule[]`, but the canonical card encoding and shared SDK/hook compiler need agreed vectors (G09). A multi-chain card can create several rule IDs while the job hook currently binds one; define that mapping before integrating `market.start` (G10). + +The job provider is the same Push identity named in the rules. The hook must enforce provider identity, expiry and execution chain. START reads establish the baseline; any owner-side checkpoint after that baseline causes settlement in the provider's favor under the design. These responsibilities belong to the hook and evaluator, while the AGW supplies trustworthy identities and checkpoints. + +Standalone AGW can be reviewed and delivered independently. Full marketplace/job/evaluation readiness depends on their WIP implementations. + +## Review and verification checklist + +- [ ] Exact matched artifacts identified; all G01–G24 entries have a disposition. +- [ ] Rule and wallet derivation match contract-generated vectors, including nonce and index races. +- [ ] Owner, agent, unknown sender, revoked rule and expired rule behavior is covered. +- [ ] Native and external signers retain their correct account and gas identity. +- [ ] Atomic replacement cannot use sequential fallback. +- [ ] Native and cross-chain receipts show the intended SDK fields and track the AGW's destination account. +- [ ] Create, update and revoke events return correctly ordered IDs and checkpoint records. +- [ ] Init-time and per-call hooks remain additive through send and wait; errors retain decoded data. +- [ ] Existing initialization, read-only mode, Web2 reads and regular routes remain compatible. +- [ ] Solana-origin support is verified separately from Solana destination capability. +- [ ] Selected deployment passes contract tests and authorized SDK end-to-end coverage. + +## Current integration requirements + +Use owner wallet batching for atomic updates. Stored checkpoints are implemented at e704d5b; grant job refs, label mutation and envelope version remain pending. Universal assets[]/maxGasPerCall require a new matched wire ABI. Public Spent remains scalar in the new snapshot; agree per-token returns and expected-total assertions. Empty-assets routing and native-marker resolution need fixtures. + +Derive expectedCEA from AGW and destination context, commit it in universal terms, expose it in previews and monitor drift. Apply all [integrator obligations](contract-integrator-obligations.md). [Validation evidence](research/validation-e704d5b/README.md) verifies the pinned single-asset source; it does not establish multi-asset or live deployment support. diff --git a/plan/agw/source-manifest.json b/plan/agw/source-manifest.json new file mode 100644 index 00000000..2d3a634a --- /dev/null +++ b/plan/agw/source-manifest.json @@ -0,0 +1,178 @@ +{ + "schema_version": 1, + "snapshot_date": "2026-10-03", + "notes": "Page content preserved; known intra-export links normalized to local filenames. Comment threads excluded by Notion export. Null edit dates mean not observed. Original bundle retained.", + "sources": [ + { + "title": "AGW design overview", + "page_id": "3e9188aea7f481c8b38ccba332b0afa2", + "notion_url": "https://app.notion.com/p/pushprotocol/AGW-UniversalMarketplace-8183-UniversalEvaluator-3e9188aea7f481c8b38ccba332b0afa2", + "local_file": "notion/overview.md", + "pulled_on": "2026-10-03", + "observed_last_edited_date": "2026-10-01", + "authority": "Supporting design", + "sha256": "f2d7954e018324a937282ca190f397cc12a27973a07c891f3edfd6e89383c53e", + "export_entry": "Private & Shared/AGW + UniversalMarketplace + 8183 + UniversalEvalu 3e9188aea7f481c8b38ccba332b0afa2.md", + "raw_export_sha256": "99b727bd58cf588b2c766dc1b93eff402c47e918718b69c2a456b119ad43435b", + "archive": "notion/exports/20261003T075310278902Z/export-1.zip", + "pulled_at": "2026-10-03T07:53:10.278902+00:00" + }, + { + "title": "1 AGW Contract Changes", + "page_id": "3e9188aea7f4813aa31fc95ceb4e684d", + "notion_url": "https://app.notion.com/p/pushprotocol/1-AGW-Contract-Changes-nomenclature-standard-change-set-3e9188aea7f4813aa31fc95ceb4e684d", + "local_file": "notion/1-agw-contract-changes.md", + "pulled_on": "2026-10-03", + "observed_last_edited_date": "2026-10-02", + "authority": "WIP contract target", + "sha256": "f1301d8ff1cf370968b90a3d53037ece8fa4c6783c45a402f9be6998928e3631", + "export_entry": "Private & Shared/AGW + UniversalMarketplace + 8183 + UniversalEvalu/1 AGW Contract Changes (nomenclature standard + ch 3e9188aea7f4813aa31fc95ceb4e684d.md", + "raw_export_sha256": "f1301d8ff1cf370968b90a3d53037ece8fa4c6783c45a402f9be6998928e3631", + "archive": "notion/exports/20261003T075310278902Z/export-1.zip", + "pulled_at": "2026-10-03T07:53:10.278902+00:00", + "observed_last_edited_at": "2026-10-02T20:50:00+05:30" + }, + { + "title": "2 Universal Marketplace", + "page_id": "3e9188aea7f48118b90ac9b267496295", + "notion_url": "https://app.notion.com/p/pushprotocol/2-Universal-Marketplace-3e9188aea7f48118b90ac9b267496295", + "local_file": "notion/2-universal-marketplace.md", + "pulled_on": "2026-10-03", + "observed_last_edited_date": null, + "authority": "Supporting WIP design", + "sha256": "5ddfd9e8980faae9eec85e3959cc99edbb3b115565af289c5603a91df0b78d18", + "export_entry": "Private & Shared/AGW + UniversalMarketplace + 8183 + UniversalEvalu/2 Universal Marketplace 3e9188aea7f48118b90ac9b267496295.md", + "raw_export_sha256": "5ddfd9e8980faae9eec85e3959cc99edbb3b115565af289c5603a91df0b78d18", + "archive": "notion/exports/20261003T075310278902Z/export-1.zip", + "pulled_at": "2026-10-03T07:53:10.278902+00:00" + }, + { + "title": "3 ERC-8183 job kernel and hook", + "page_id": "3e9188aea7f48188a838c3a740d8c858", + "notion_url": "https://app.notion.com/p/pushprotocol/3-8183-job-kernel-and-hook-3e9188aea7f48188a838c3a740d8c858", + "local_file": "notion/3-8183-job-kernel-and-hook.md", + "pulled_on": "2026-10-03", + "observed_last_edited_date": null, + "authority": "Supporting WIP design", + "sha256": "3c805db465f2d39db8d34179ac1dd864db1abf7b1b3e93f38074fbf393093f90", + "export_entry": "Private & Shared/AGW + UniversalMarketplace + 8183 + UniversalEvalu/3 8183 (job kernel and hook) 3e9188aea7f48188a838c3a740d8c858.md", + "raw_export_sha256": "3c805db465f2d39db8d34179ac1dd864db1abf7b1b3e93f38074fbf393093f90", + "archive": "notion/exports/20261003T075310278902Z/export-1.zip", + "pulled_at": "2026-10-03T07:53:10.278902+00:00" + }, + { + "title": "4 Universal Evaluation", + "page_id": "3e9188aea7f4817bb03ef4c78c883f8b", + "notion_url": "https://app.notion.com/p/pushprotocol/4-Universal-Evaluation-3e9188aea7f4817bb03ef4c78c883f8b", + "local_file": "notion/4-universal-evaluation.md", + "pulled_on": "2026-10-03", + "observed_last_edited_date": null, + "authority": "Supporting WIP design", + "sha256": "a2f1c93a75b8631c9628c06f1be135fa0198f00f096a765ce808dd5e544b2d6f", + "export_entry": "Private & Shared/AGW + UniversalMarketplace + 8183 + UniversalEvalu/4 Universal Evaluation 3e9188aea7f4817bb03ef4c78c883f8b.md", + "raw_export_sha256": "a2f1c93a75b8631c9628c06f1be135fa0198f00f096a765ce808dd5e544b2d6f", + "archive": "notion/exports/20261003T075310278902Z/export-1.zip", + "pulled_at": "2026-10-03T07:53:10.278902+00:00" + }, + { + "title": "5 SDK AGW", + "page_id": "3e9188aea7f481cf8e8de324956549b9", + "notion_url": "https://app.notion.com/p/pushprotocol/5-SDK-AGW-3e9188aea7f481cf8e8de324956549b9", + "local_file": "notion/5-sdk-agw.md", + "pulled_on": "2026-10-03", + "observed_last_edited_date": null, + "authority": "Primary SDK API target", + "sha256": "e407ee77cdf874db7ef4697f84e9945ff3a12a2f2e07e8a7f90bd24e93ea32f1", + "export_entry": "Private & Shared/AGW + UniversalMarketplace + 8183 + UniversalEvalu/5 SDK AGW 3e9188aea7f481cf8e8de324956549b9.md", + "raw_export_sha256": "9a16f8aed79fac09818ec216fb4c69dc79f2fa0cffe0af611af956eb0e69f33f", + "archive": "notion/exports/20261003T075310278902Z/export-1.zip", + "pulled_at": "2026-10-03T07:53:10.278902+00:00", + "previous_observed_last_edited_date": "2026-10-01" + }, + { + "title": "6 SDK Universal Marketplace", + "page_id": "3ea188aea7f481e2961ed97129f3a4e6", + "notion_url": "https://app.notion.com/p/pushprotocol/6-SDK-Universal-Marketplace-3ea188aea7f481e2961ed97129f3a4e6", + "local_file": "notion/6-sdk-universal-marketplace.md", + "pulled_on": "2026-10-03", + "observed_last_edited_date": "2026-09-30", + "authority": "Supporting WIP SDK", + "sha256": "e7298952f2ba9adb218b4ef0459b8fa696a2072167dc5f655060b69788cf528c", + "export_entry": "Private & Shared/AGW + UniversalMarketplace + 8183 + UniversalEvalu/6 SDK Universal Marketplace 3ea188aea7f481e2961ed97129f3a4e6.md", + "raw_export_sha256": "e7298952f2ba9adb218b4ef0459b8fa696a2072167dc5f655060b69788cf528c", + "archive": "notion/exports/20261003T075310278902Z/export-1.zip", + "pulled_at": "2026-10-03T07:53:10.278902+00:00" + }, + { + "title": "7 SDK ERC-8183 Job", + "page_id": "3ea188aea7f481e0a137f5a896723376", + "notion_url": "https://app.notion.com/p/pushprotocol/7-SDK-8183-Job-3ea188aea7f481e0a137f5a896723376", + "local_file": "notion/7-sdk-8183-job.md", + "pulled_on": "2026-10-03", + "observed_last_edited_date": null, + "authority": "Supporting WIP SDK", + "sha256": "dbf1ff539f5df944e5f5f55710f5f6d3359469a141038cec2604e7c33392752c", + "export_entry": "Private & Shared/AGW + UniversalMarketplace + 8183 + UniversalEvalu/7 SDK 8183 Job 3ea188aea7f481e0a137f5a896723376.md", + "raw_export_sha256": "dbf1ff539f5df944e5f5f55710f5f6d3359469a141038cec2604e7c33392752c", + "archive": "notion/exports/20261003T075310278902Z/export-1.zip", + "pulled_at": "2026-10-03T07:53:10.278902+00:00" + }, + { + "title": "8 SDK Universal Evaluation", + "page_id": "3ea188aea7f48197a3b3cfdedfa74fee", + "notion_url": "https://app.notion.com/p/pushprotocol/8-SDK-Universal-Evaluation-3ea188aea7f48197a3b3cfdedfa74fee", + "local_file": "notion/8-sdk-universal-evaluation.md", + "pulled_on": "2026-10-03", + "observed_last_edited_date": null, + "authority": "Supporting WIP SDK", + "sha256": "eb2e584bd76aeea06c0dd03b3c8802b2340acf955e1ea75bf7768ebf9d2ab34e", + "export_entry": "Private & Shared/AGW + UniversalMarketplace + 8183 + UniversalEvalu/8 SDK Universal Evaluation 3ea188aea7f48197a3b3cfdedfa74fee.md", + "raw_export_sha256": "eb2e584bd76aeea06c0dd03b3c8802b2340acf955e1ea75bf7768ebf9d2ab34e", + "archive": "notion/exports/20261003T075310278902Z/export-1.zip", + "pulled_at": "2026-10-03T07:53:10.278902+00:00" + }, + { + "title": "Legacy PUSH AGW SDK Doc v1", + "page_id": "d2d188aea7f4825cbcea81ef86eca607", + "notion_url": "https://app.notion.com/p/pushprotocol/PUSH-AGW-SDK-Doc-v1-d2d188aea7f4825cbcea81ef86eca607", + "local_file": "notion/legacy-agw-sdk-v1.md", + "pulled_on": "2026-10-03", + "observed_last_edited_date": "2026-09-22", + "authority": "Historical encoding and deployment reference", + "sha256": "9e6569ef9b76d59cb411d65305d67333c6766abc2e9c80a35ae6f56f12f70916", + "raw_export_sha256": "9e6569ef9b76d59cb411d65305d67333c6766abc2e9c80a35ae6f56f12f70916", + "pulled_at": "2026-10-03T07:53:10.278902+00:00", + "archive": "notion/exports/20261003T075310278902Z/export-2.zip", + "export_entry": "Private & Shared/PUSH AGW SDK Doc - v1 d2d188aea7f4825cbcea81ef86eca607.md" + }, + { + "title": "AGW Address Book PC Donut", + "page_id": "3d1188aea7f480ddbb4af6d0efb211e6", + "notion_url": "https://app.notion.com/p/pushprotocol/AGW-Address-Book-PC-Donut-3d1188aea7f480ddbb4af6d0efb211e6", + "local_file": "notion/agw-address-book-donut-2026-09-04.md", + "pulled_on": "2026-10-03", + "observed_last_edited_date": "2026-09-04", + "authority": "Historical deployment", + "sha256": "5c5017d6b4a58af0fa8854ef550b054c1f33d57a812ea51a16f31f7c33e79742", + "raw_export_sha256": "5c5017d6b4a58af0fa8854ef550b054c1f33d57a812ea51a16f31f7c33e79742", + "pulled_at": "2026-10-03T07:53:10.278902+00:00", + "archive": "notion/exports/20261003T075310278902Z/export-3.zip", + "export_entry": "Private & Shared/AGW Address Book - PC Donut 3d1188aea7f480ddbb4af6d0efb211e6.md" + }, + { + "title": "Agentic wallet flow updated", + "page_id": "3d1188aea7f4801f9cb3fbd9318ec536", + "notion_url": "https://app.notion.com/p/pushprotocol/agentic_wallet_flow-updated-3d1188aea7f4801f9cb3fbd9318ec536", + "local_file": "notion/agentic-wallet-flow-2026-09-07.md", + "pulled_on": "2026-10-03", + "observed_last_edited_date": "2026-09-07", + "authority": "Historical validator-based flow", + "sha256": "d4a922fd1d33da5a7042f26053e8df0e496c3ccd4cb0044b0892948ac509c3a0", + "raw_export_sha256": "d4a922fd1d33da5a7042f26053e8df0e496c3ccd4cb0044b0892948ac509c3a0", + "pulled_at": "2026-10-03T07:53:10.278902+00:00", + "archive": "notion/exports/20261003T075310278902Z/export-4.zip", + "export_entry": "Private & Shared/agentic_wallet_flow ( updated ) 3d1188aea7f4801f9cb3fbd9318ec536.md" + } + ], + "last_refresh_at": "2026-10-03T07:53:10.278902+00:00" +} diff --git a/plan/agw/source-status-2026-10-03.json b/plan/agw/source-status-2026-10-03.json new file mode 100644 index 00000000..9f1d3a14 --- /dev/null +++ b/plan/agw/source-status-2026-10-03.json @@ -0,0 +1,14 @@ +{ + "date": "2026-10-03", + "agw_branch": "pushAgenticWallet_v3", + "agw_commit": "e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9", + "agw_remote_checked": "GitHub branch API", + "notion_last_full_export": "2026-10-03T07:53:10.278902+00:00", + "notion_new_export": "success: 12 checked, 2 changed", + "core_gateway_new_remote_refresh": "unavailable; retain prior pins", + "messages_sent": false, + "notion_changed_pages": [ + "3e9188aea7f4813aa31fc95ceb4e684d", + "3e9188aea7f481cf8e8de324956549b9" + ] +} From 349635b2254823488603b37f4b44c4f5c929feb9 Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Sat, 3 Oct 2026 16:47:11 +0530 Subject: [PATCH 02/68] docs(agw): clarify open decisions and complete implementation roadmap --- plan/agw/README.md | 4 +- plan/agw/current-baseline.md | 4 +- plan/agw/external-blockers.md | 44 +++ plan/agw/gaps.md | 16 +- plan/agw/implementation-plan.md | 368 ++++++++++++++++-- plan/agw/questions-harsh.md | 159 ++++++-- plan/agw/questions-zaryab.md | 118 +++++- .../AllowanceReview.t.sol | 119 ++++++ .../sdk-owned-review-2026-10-03/README.md | 28 ++ .../sdk-owned-review-2026-10-03/allowance.log | 42 ++ .../sdk-owned-review-2026-10-03/jest.log | 13 + .../remote-refs.json | 16 + .../sdk-owned-review-2026-10-03/response.log | 11 + .../test-summary.json | 43 ++ plan/agw/sdk-design-review.md | 6 +- plan/agw/sdk-owned-review.md | 101 +++++ 16 files changed, 1017 insertions(+), 75 deletions(-) create mode 100644 plan/agw/external-blockers.md create mode 100644 plan/agw/research/sdk-owned-review-2026-10-03/AllowanceReview.t.sol create mode 100644 plan/agw/research/sdk-owned-review-2026-10-03/README.md create mode 100644 plan/agw/research/sdk-owned-review-2026-10-03/allowance.log create mode 100644 plan/agw/research/sdk-owned-review-2026-10-03/jest.log create mode 100644 plan/agw/research/sdk-owned-review-2026-10-03/remote-refs.json create mode 100644 plan/agw/research/sdk-owned-review-2026-10-03/response.log create mode 100644 plan/agw/research/sdk-owned-review-2026-10-03/test-summary.json create mode 100644 plan/agw/sdk-owned-review.md diff --git a/plan/agw/README.md b/plan/agw/README.md index 1bf2c602..b2c90bf8 100644 --- a/plan/agw/README.md +++ b/plan/agw/README.md @@ -11,9 +11,11 @@ The target API is [Notion page 5](notion/5-sdk-agw.md), exported October 3, 2026 | [Current baseline](current-baseline.md) | Source revisions, capabilities and remaining differences | | [SDK design review](sdk-design-review.md) | Proposed internal architecture and execution flows | | [Gap register](gaps.md) | Current G01–G24 findings and closure criteria | -| [Implementation plan](implementation-plan.md) | Work order and acceptance gates | +| [SDK owned review](sdk-owned-review.md) | Internal decisions, existing-code evidence and 183 passing unit tests | +| [Implementation plan](implementation-plan.md) | Complete 17-step roadmap, module layout, assumptions, API coverage and PR sequence | | [Interactive tutorial](agw-tutorial.html) | Account, rule, funding and execution diagrams; open in a browser | | [Integrator obligations](contract-integrator-obligations.md) | Contract-delegated SDK/product requirements | +| [External blockers](external-blockers.md) | Seven remaining decision/dependency areas after local closure | | [Questions for Harsh](questions-harsh.md) | Product decisions and recommendations | | [Questions for Zaryab](questions-zaryab.md) | Contract surface, funding and deployment questions | | [Review summary](review-summary.md) | Consequential independent-review corrections | diff --git a/plan/agw/current-baseline.md b/plan/agw/current-baseline.md index f1ae5818..df619517 100644 --- a/plan/agw/current-baseline.md +++ b/plan/agw/current-baseline.md @@ -29,7 +29,7 @@ AGW remote branches were checked through GitHub API on October 3: nomenclature-c | Historical rules | Revoke removes agent config and enabled actions, while URP terms persist | Event agent attribution or nested-call reconstruction needed if revoked rules are returned | | expectedCEA | Required universal wire term, derived from AGW plus destination context and committed at grant | SDK must derive it, show it in previews, include it in encodeRules context, and monitor derivation drift | | Binder | Never present in reviewed code; live Notion page checked October 3 says dropped for v1 | No binder/setBinder implementation required unless a new explicit product decision reverses this | -| Funding approval | Push gateway requires allowance for PRC20 pulls | Explicit owner setup approval, bounded recovery/update semantics, real pulling/burning test | +| Funding approval | Push gateway requires allowance for PRC20 pulls | Existing owner execute mechanism validated in four local fixture tests; implement setup/replenishment and verify production pull/burn/settlement | | Destination approvals | Page 5 example permits an unpinned spender; current marketplace rejects approve/increaseAllowance | Product policy and owner-controlled approvals; selector filtering alone is not a general guarantee against malicious/custom approval methods | | Gateway shape | Eight fields in current branch and observed live dispatcher; main's six fields are older | Ask only whether a future removal is actually planned | | Agent outbound composer | Existing Route 2 request cannot be used unchanged | Empty recipient, AGW revert recipient, nonzero maxPCForGas, policy-compatible multicall and AGW PC accounting | @@ -73,3 +73,5 @@ Page 5 is still authoritative: create deploys/grants only, funding is separate, Define per-asset Spent and replacement assertion semantics, empty-asset routing, destination-token/native-marker resolution and the proposed bytes32 expectedCEA encoding. The prior universal defaults/maxAmountTotal naming cannot simply carry forward. Proposed AssetCap.maxTotal zero means unlimited; native defaults remain a separate question. See [successful refresh report](research/notion-refresh-2026-10-03.md). All earlier download failures remain historical evidence; download permission was sufficient for this run. + +The follow-up [external blocker register](external-blockers.md) records what still needs team input after SDK-owned closure. Remote refs were rechecked unchanged; the Notion snapshot date above is unchanged. diff --git a/plan/agw/external-blockers.md b/plan/agw/external-blockers.md new file mode 100644 index 00000000..91735a5c --- /dev/null +++ b/plan/agw/external-blockers.md @@ -0,0 +1,44 @@ +# External decisions before AGW implementation and release + +October 3, 2026. The 24 gap-register entries cover implementation work, historical findings and downstream dependencies. For the standalone target SDK, this review isolates **seven decision/dependency areas**, presented as **four Harsh question groups and two active Zaryab requests**. A separate shared-compiler request, Harsh H5/Zaryab Z5, covers assumption A08. This is a release-planning count, not a count of confirmed contract defects. + +## What needs an external answer + +| ID | Owner and draft | Required answer or artifact | What it blocks | +| --- | --- | --- | --- | +| E01 | Harsh H1 | Approval-safety policy and corrected universal example; owner-controlled approval can use the existing owner client | Public rule validation and safe examples | +| E02 | Harsh H2 | Reject native agent arrays in v1, or require a batching contract change | Full transaction-array promise; single native calls and supported EVM destination multicalls can proceed | +| E03 | Harsh H3 | Accept or change the explicit omission/default table | Final authorization defaults and encoder expectations | +| E04 | Harsh H4.1 | Approve generation/validator context in pure helper signatures | Public helper types; internal derivation can proceed with explicit context | +| E05 | Harsh H4.2 and Zaryab Z1 | Per-token Spent shape, matching multi-asset terms/read/assertion ABI and vectors | Final universal codec, metering reads and safe replacement integration | +| E06 | Harsh H4.3 and conditionally Zaryab Z1 | Define revoked-rule history; provide reliable metadata if promised | Complete rules.list/get behavior, not basic agent execution | +| E07 | Zaryab Z1/Z3 | Target ref/envelope/metadata surface and verified compatible deployment manifest | Required target features and live release acceptance; proposed setLabel is separately capability-gated pending scope | + +Highest-impact integration dependencies are the approval policy, multi-asset accounting/encoding and compatible target generation. Defaults and native-array scope also need answers before their public behavior is finalized. SDK structure and independent work can proceed before all seven are closed. + +## Shared compiler dependency + +A08 is outside the seven standalone areas: Harsh H5 must establish the canonical card/userInput schema and supported binding scope; Zaryab Z5 must supply matching encoding/verification artifacts and shared vectors. This blocks compileCard completion, not the standalone foundation. Product answers settle design; missing artifacts and deployments remain delivery dependencies until verified. + +## Removed from external blockers + +- **Gateway allowance mechanism:** resolved locally. Owner execute can approve and remove a bounded allowance. Four new local tests pass. Production integration remains to be tested; no new AGW method is required. +- **How to approve on the destination:** use the existing owner agentic client and sendTransaction. Harsh decides the agent permission policy, not a new helper architecture. +- **Whether NativeRule needs multiple actions:** follow the existing one-action public type. Only the incompatible array promise needs a scope decision. +- **Creation batching and recovery:** SDK capability selection, partial hashes and retry handling. No required factory createWallet method. +- **Owner replacement batching:** established contract path. Only the new multi-asset expected-spend assertion remains external. +- **Duplicate candidate selection:** fail before signing with DUPLICATE_RULE and a hint; never pick arbitrarily. Document this use of the existing error code. +- **Gateway six-versus-eight-field history:** encode the known selected generation. Any future migration belongs in deployment compatibility, not a speculative blocker. +- **Version string alone:** the SDK can use an explicit factory/implementation registry and verified wiring; unchanged accountId does not force a contract redesign. +- **Read-only lifecycle, Web2 normalization, receipts, errors and progress:** SDK-owned decisions in [SDK review](sdk-owned-review.md). +- **D3, checkpoints, binder and creditRevert:** implemented source, dropped proposal or known platform dependency, as recorded in the gap register. + +## Work we can do before answers arrive + +The design decisions, read reconstruction strategy, source mapping, test acceptance cases and creation/recovery strategy are recorded. Future implementation can start with namespace/context separation, read-only guards, Web2 compatibility, error exports and receipt/hook adapters. Keep final universal encoding, defaults and disputed public types behind the unresolved decisions. Production implementation has not begun in this planning package. + +## Evidence and freshness + +The 183 existing SDK unit tests passed, plus four new allowance experiments at pinned e704d5b. These support local mechanisms only; no live transaction was broadcast. [Review evidence](research/sdk-owned-review-2026-10-03/README.md) records commands, hashes, source pins and limits. + +Remote AGW/core/gateway branch refs were rechecked and are unchanged. Notion remains the October 3 13:23 IST export; edits after that time are unknown. Refresh the Notion bodies before sending the [Harsh](questions-harsh.md) and [Zaryab](questions-zaryab.md) drafts. diff --git a/plan/agw/gaps.md b/plan/agw/gaps.md index afe8eba5..8b224e42 100644 --- a/plan/agw/gaps.md +++ b/plan/agw/gaps.md @@ -24,15 +24,23 @@ P0 blocks safe integration or agreed authorization/accounting semantics. P1 affe | G14 | P1 | SDK integration | Atomic assert/revoke/grant through owner execute is documented contract behavior. Four original and seven stronger head experiments support it. | Implement wallet-level batching; repeat tests for final generation and checkpoints. No EIP-7702 dependence for existing-wallet management. | | G15 | P2 optional creation capability | Create scope updated | Page 5 now makes create deployment/grants only, with no funds or pc option. Factory batch remains proposed but absent; normal funding is separate. | Implement actual creation strategy and partial-failure metadata without inventing a required factory method or restoring removed inputs. | | G16 | P1 | Compatibility gap | New `READ.CHAIN.WEB2` is `'web2'`; current `CHAIN.WEB2` and `READ.WEB2` are `'web2:https'`. | Implement the target constant and normalize legacy inputs during the compatibility window. Cover read types, serialization, helpers and transaction rejection; do not silently break old literal callers. | -| G17 | P1 | Undefined lifecycle | Existing SDK supports read-only initialization and `reinitialize`. Page 5 does not specify how `agenticWallet` is inherited, cleared or changed, or how read-only agentic management behaves. | Define lifecycle semantics and compatibility cases. Ensure writes are unavailable in read-only mode and role checks rerun for a changed signer or wallet. | -| G18 | P1 | Undefined role behavior | Initialization accepts an address named in a wallet rule; sends resolve enabled rules. Handling of a signer whose only rules are expired or revoked is unstated. | Define initialization eligibility, per-send failures and role refresh after ownership or permission changes, with exact errors. Keep rule lookup uncached as specified. | +| G17 | P1 | SDK lifecycle decision recorded | Existing SDK supports read-only initialization and `reinitialize`. Page 5 does not specify how `agenticWallet` is inherited, cleared or changed, or how read-only agentic management behaves. | Implement the SDK-owned review decision: explicit wallet selection on reinitialize, read-only write guards, fresh generation/role checks; verify compatibility cases. | +| G18 | P1 | SDK eligibility decision recorded | Initialization accepts an address named in a wallet rule; sends resolve enabled rules. Handling of a signer whose only rules are expired or revoked is unstated. | Implement enabled-rule eligibility without expiry filtering and uncached, consistent per-send lookup as recorded in the SDK-owned review. Agree public ambiguity wording and verify role changes. | | G19 | P0/P1 | Product safety and encoding | Destination approve still cannot constrain the spender. New asset caps use maxTotal=0 for unlimited; native defaults remain separate. Destination token/native-marker resolution and ABI offset context need fixtures. | Agree approval policy, native defaults, resolved PRC20 context and safe ABI representations. | -| G20 | P1 | SDK composition and response mapping | Existing outbound tracking is hash/UTX-ID based. Route 2 request recipient, refund recipient and default maxPCForGas conflict with URP; Push-side allowance must be established by owner. | Dedicated composer, logical AGW from override, preserved signer origin and live tracking/settlement verification. | -| G21 | P1 | Product scope | Contract grants up to eight native actions but dispatches a single agent call. SDK NativeRule has one action and transaction arrays are broadly promised. | Decide public native action type and explicit native-array behavior; keep destination multicalls distinct. | +| G20 | P1 | SDK composition and response mapping | Existing outbound tracking is hash/UTX-ID based. Route 2 request recipient, refund recipient and default maxPCForGas conflict with URP; Push-side allowance must be established by owner; four local pull/burn-fixture tests verify the existing owner execute mechanism. | Dedicated composer, logical AGW from override, preserved signer origin and live tracking/settlement verification. | +| G21 | P1 | Product scope | Contract grants up to eight native actions but dispatches a single agent call. SDK NativeRule has one action and transaction arrays are broadly promised. | Keep the specified single-action NativeRule. Decide native-array behavior; keep destination multicalls distinct. | | G22 | P1 | Capability integration | SVM policy source exists; head agent identity is Push address and no longer verifies Ed25519 locally. SVM origin goes through UEA. | Verify deployed destination capability and implement obligations 19–23 when enabled. | | G23 | P0 contract integration dependency | New multi-asset target | Page 5 uses assets[] and maxGasPerCall. Page 1 section 4c proposes per-token counters, 0–8 assets, maxTotal zero unlimited and bytes32 expectedCEA. Tested e704d5b still uses single-asset terms and amount counters. | Matched contract artifacts/fixtures for native marker and foreign-token resolution, per-asset enforcement, empty-assets call-only routing, expectedCEA representation, duplicate asset handling and token-carrying events. | | G24 | P1 public read/update mismatch | Per-token spend shape unresolved | SDK Spent remains scalar amountSpent. Proposed assertSpent(configId,account) returns totals without expected snapshots, while rules.update still promises a race assertion. | Agree per-asset Spent and expected-total assertion inputs/semantics; prove stale state rejects atomically across all affected assets. Do not aggregate unlike units. | +## External blockers after local closure + +[External blockers](external-blockers.md) reduces the standalone scope to seven decision/dependency areas, sent as four Harsh question groups and two active Zaryab requests. Z2 is now SDK owner-setup work supported by four local allowance tests; Z4 is a release note, not a speculative blocker. H2 keeps NativeRule single-action and asks only about native arrays. No production implementation gap is closed by these design decisions. + +## SDK owned work reviewed + +The [SDK owned review](sdk-owned-review.md) records internal decisions for creation/recovery (G13/G15), wallet-level replacement (G14), Web2 normalization (G16), read-only/reinitialize behavior (G17), enabled-rule eligibility (G18), and composition/responses/errors/transaction-creating reads (G20). SDK portions of G03/G08/G19/G22/G23 are also scoped. Ten existing unit suites pass, 183 tests total, plus four new allowance experiments. These decisions are ready for implementation; no gap is marked closed on that basis. Multi-asset accounting, native scope/defaults, approval policy and deployment remain external dependencies. + ## Cross-cutting requirements - expectedCEA is SDK-derived context: derive the AGW destination account, commit it in every universal rule, display it and monitor derivation drift. Do not use the signer CEA or an arbitrary pasted address. diff --git a/plan/agw/implementation-plan.md b/plan/agw/implementation-plan.md index 1b24dd23..e29aee0a 100644 --- a/plan/agw/implementation-plan.md +++ b/plan/agw/implementation-plan.md @@ -1,49 +1,367 @@ -# AGW SDK implementation plan +# Complete AGW SDK implementation plan -Target: [SDK spec](notion/5-sdk-agw.md), October 3 export. Source/test baseline: [e704d5b](current-baseline.md). Current gaps and questions are in [gaps.md](gaps.md), [Harsh draft](questions-harsh.md) and [Zaryab draft](questions-zaryab.md). No production implementation is included. +This is the step-by-step plan for the complete AGW surface in Notion page 5 inside `@pushchain/core`. It covers management, rules, execution, responses, helpers, compatibility, documentation and release validation. Marketplace, job and evaluator clients are separate projects; their shared `compileCard` dependency is included here. No production implementation has started. -## Phase 0 Agree the integration contract +Target: [SDK spec](notion/5-sdk-agw.md), exported October 3, 2026 at 13:23 IST. Tested contract source: AGW `e704d5b`. SDK production baseline: `167fdc6`. See [current baseline](current-baseline.md), [SDK design](sdk-design-review.md), [SDK-owned decisions](sdk-owned-review.md) and [external blockers](external-blockers.md). Remote refs were rechecked unchanged; subsequent Notion edits remain unverified. -Completed: source access, sender-adapter review, checkpoint/source-invariant review, local builds/tests, atomic replacement experiments and latest Notion import. +## How to execute this plan -Remaining: approval safety, native action/array scope, defaults, per-asset Spent and assertion semantics, multi-asset fixtures, labels/ref/versioned envelope, empty-assets routing and compatible deployment generation. Keep standalone AGW and downstream marketplace/job/evaluator requirements distinct. +Proceed in numbered order, taking the independent Web2 work alongside the foundation if useful. A step marked **Start now** has settled internal boundaries. **Partial** means implementation can proceed behind a contract adapter or provisional type, but the listed dependency must be resolved before that feature is complete. **Waiting** identifies a feature whose final behavior cannot be honestly implemented from available artifacts. -Exit: critical authorization, encoding, accounting and atomicity behavior has recorded decisions and exact artifacts. Source implementations are distinguished from live capabilities. +Implementation and verification are listed separately so development progress can be measured independently. A placeholder is scaffolding, not completed behavior. All new files listed below are proposed paths, not existing implementation. -## Phase 1 Public surface and structure +| Step | Deliverable | Start status | Depends on | +| --- | --- | --- | --- | +| 1 | Source and capability contract | Start now | Existing snapshots and evidence | +| 2 | Module skeleton, public types, exports and errors | Partial | 1; disputed types isolated under A04–A06 | +| 3 | Signer/wallet context, initialization and lifecycle | Start now | 2; final deployment validation in 14 | +| 4 | Generation registry and contract adapter | Partial | 1–3; A07 for real deployment entries | +| 5 | Wallet and checkpoint reads | Partial | 4; A06/A07 for full history/metadata | +| 6 | Rule normalization, identities and codecs | Partial | 4; A01/A03/A04/A05 | +| 7 | Create, add and revoke | Partial | 3–6; matching grant ABI | +| 8 | Atomic rule replacement | Partial | 6–7; A05 expected-spend assertion | +| 9 | Owner execution and allowance setup | Start now through pinned adapters | 3–4; 11 for destination approval transport | +| 10 | Agent rule selection and native execution | Partial | 3–6; A02 for array scope | +| 11 | EVM universal execution and gas handling | Partial | 6, 9–10; A05/A07 | +| 12 | SVM destination support | Partial | 6, 10; final schema and advertised capabilities (A05/A07) | +| 13 | Responses, tracking, progress and transaction-creating reads | Partial | 3, 9–12; final wire adapters | +| 14 | Deployment onboarding and full acceptance | Waiting for matching deployment | 4–13; A07 | +| 15 | Web2 compatibility | Start now; independent | Existing read-state modules | +| 16 | Card compiler and ecosystem boundary | Waiting for canonical card schema | 6; G09/G10 downstream decisions | +| 17 | Documentation, examples and release | Draft now, finish after acceptance | 1–16 or explicit accepted feature scope | -Add types, namespace, wallet handle, errors, progress, exports and initialize options. Preserve existing defaults, read-only mode and reinitialize behavior. Introduce internal contract/read/execution adapters. +Do not interpret this table as an equal-effort percentage. Steps 6, 11–14 carry substantially more integration risk than namespace and export work. -Verify public usage, signer versus wallet identity, forbidden operations and ordinary-client compatibility. +## Assumptions and placeholder rules -## Phase 2 Encoding and management +These are working assumptions for development, not accepted product changes. Replace each with an owner decision and source reference when answered. -Implement selectors, safe ABI positions, chain/token/native-marker resolution, expectedCEA derivation, codecs, IDs and wallet prediction against matching vectors. Add derive/list/create, summaries, checkpoints, labels and lifecycle operations. +| ID | Working assumption or placeholder | Confirmation | Replacement point | +| --- | --- | --- | --- | +| A01 | Known approval-granting selectors are rejected in universal agent rules. Owners use existing owner-mode sendTransaction for bounded approvals. Filtering is not a complete target-safety boundary. | Harsh H1 / E01 | Rule validation and examples | +| A02 | NativeRule remains one action; native agent arrays fail before signing. Owner batches and bounded EVM destination multicalls remain supported. | Harsh H2 / E02 | Native dispatch validation | +| A03 | Omitted universal asset maxTotal maps to proposed zero-unlimited; native value caps and allowed-call maxValue default to zero; native amount.maxTotal defaults to uint256 maximum; maxCalls defaults to zero-unlimited. | Harsh H3 / E03 | One defaults module, never scattered fallbacks | +| A04 | Pure rulesId and deriveWallet helpers accept explicit validator/factory/implementation context. Signer-bound methods resolve it internally. | Harsh H4.1 / E04 | Public helper signatures; internal context already explicit | +| A05 | Universal Spent is per token. Replacement compares caller-supplied expected totals for all old-rule assets atomically. Multi-asset wire format, empty-assets routing and EVM expectedCEA width are unresolved. | Harsh H4.2, SVM scope clarification, and Zaryab Z1 / E05 | Multi-asset codec/read/assertion adapter | +| A06 | Active-rule reads can be implemented first internally. Public list/get historical scope stays provisional; do not silently return only active rules if full history is promised. | Harsh H4.3 / E06 | History adapter and RulesRecord completeness | +| A07 | A verified new deployment supplies the matching grant ref/envelope/metadata ABI, addresses and start blocks. Historical Donut remains a distinct generation. | Zaryab Z1/Z3 / E07 | Deployment manifest and capability adapter | +| A08 | compileCard consumes a versioned canonical card shared with the marketplace hook. No canonical bytes are invented locally. | Harsh H5 and Zaryab Z5; downstream G09/G10 | Card compiler module | -create deploys/grants only. Funding and owner approvals are separate. Replacement uses one owner wallet assert/revoke/grant batch; never a sequential fallback. +### What closes each assumption -Verify ID ordering, unknown/revoked states, duplicate candidates, nonce/index races, per-asset caps, zero/unlimited conventions and assertion rollback. Snapshot checkpoint counts and account for five ticks in a replacement batch. AGENTIC-TX-103 is absent from creation. +- A01–A04: explicit product decisions and agreed API/default wording from Harsh settle the design. SDK implementation and tests follow. +- A05: Harsh agrees the public representation; Zaryab supplies matching terms, read/assertion ABIs and vectors. Clarification alone does not supply missing contract code. +- A06: Harsh defines history scope. If full history is required, reliable metadata/artifacts must also be available before that implementation dependency closes. +- A07: Zaryab identifies the selected feature scope and delivers the actual compatible deployment manifest/artifacts. A planned address or deployment date does not close it; we verify deployment and integration. +- A08: Harsh H5 and Zaryab Z5 align the shared card schema/encoding and vectors. This is a downstream compiler dependency, separate from the standalone execution foundation. -## Phase 3 Wallet execution +Record design decisions and artifact/deployment readiness separately. All eight have an explicit question owner, but answers alone do not mean all eight are implemented or verified. -Implement role checks, uncached rule lookup and owner/agent wrappers. Keep signer transport/gas separate from AGW assets/outbound PC. Build a dedicated composer satisfying URP; do not reuse signer-based Route 2 unchanged. +Placeholder implementation rules: -Verify unauthorized/revoked/expired cases, rejected from, forbidden methods, deployment/gas exceptions, native arrays, allowance prerequisites, zero-amount calls, beneficiary fixtures and rollback. +- Use explicit internal capabilities and typed failures. A missing codec or unsupported generation must fail before signature/broadcast; never return empty success records, zero addresses, fabricated IDs or dummy transactions. +- Keep pinned e704d5b single-asset artifacts as review fixtures. They must not silently encode the public assets[] target by choosing the first asset or splitting it into unrelated rules. +- Keep provisional wire types internal. Do not publish `any`, guessed envelope versions, guessed deployment addresses or fixed ABI tuples as the final SDK contract. +- Do not implement both sides of a product choice speculatively. Isolate the boundary and implement the selected behavior after confirmation. +- `setLabel`, full historical reads, SVM destination encoding and compileCard may be explicitly unsupported in development builds while their dependencies are incomplete. A complete release must implement the promised surface or record an approved scope change. -## Phase 4 Responses and compatibility +## Proposed module layout -Map logical from to AGW and preserve signer origin. Reuse hash/UTX tracking provisionally and verify wrapped execution. Preserve hooks through send/wait and structured errors. Add READ.CHAIN and legacy Web2 normalization. +All paths below are relative to `packages/core/src/lib/`. -Run relevant route, gas, response, read and compatibility checks. Do not silently change failure timing through expiry filtering. +| Proposed location | Responsibility | +| --- | --- | +| `agentic/index.ts`, `agentic.types.ts`, `errors.ts` | Public namespace/types and error surface | +| `agentic/agentic.ts`, `wallet.ts`, `rules.ts` | derive/create/list/wallet and lifecycle coordination | +| `agentic/context.ts`, `deployments.ts` | Separate signer/execution identity; generation capabilities | +| `agentic/contracts/` | Verified ABIs, view/event adapters, owner-intent encoding | +| `agentic/codec/` | Native/universal/SVM terms, IDs, ABI argument positions, defaults and token resolution | +| `agentic/reads/` | Snapshot reads, wallet enumeration, checkpoints and historical reconstruction | +| `agentic/execution/` | Owner/agent wrappers, rule selection, native/universal composition | +| `agentic/response.ts` | Logical identity and AGW metadata adaptation over core responses | +| `agentic/card.ts` | Canonical card compiler once the shared schema is approved | -## Phase 5 Matched deployment validation +Existing integration points: `push-chain/push-chain.ts`, `utils.ts`, `index.ts`, `constants/index.ts`, `orchestrator/orchestrator.ts`, `orchestrator/internals/context.ts`, `response-builder.ts`, `read-state.ts`, `errors.ts`, `progress-hook/*` and the `read-state/*` public parser/types. Keep generic core behavior generic; AGW-specific ABI logic belongs in the adapter. Avoid broad route rewrites merely to add this execution context. -Verify source/build revisions, generation identity, proxy/implementation addresses, start blocks and capabilities. With separately authorized funding and transactions, test native and external owners/agents. +## Step 1 Pin the implementation contract -The first positive-amount EVM agent outbound should prove allowance, real burn, empty recipient, AGW refund recipient, policy-compliant multicall, node/TSS acceptance, settlement and tracking. Enable SVM destination work with obligations 19–23 and agreed fixtures. +Implementation: -## Phase 6 Optional ecosystem integration +1. Record exact SDK, AGW, core, gateway and spec revisions in the development issue/PR. +2. Inventory every public page-5 method, its contract dependency and capability. Use the coverage table below. +3. Register A01–A08 with explicit unresolved status. Store contract-generated vectors with their originating revision. +4. Define supported-generation lookup by Push network and verified factory/implementation/wiring. AccountId is supporting evidence, not the sole discriminator. -Align canonical cards, multi-rule binding, marketplace expiry equality, payment-token scope, evaluator gating and checkpoint verdicts. The partial hook alone does not establish complete job lifecycle behavior. +Verification: inspect source hashes and ABI selectors, including imported gateway request layout. Refresh sources again when an external answer arrives. Existing 183 SDK unit tests and four allowance experiments are the baseline, not tests of future SDK behavior. -Exit: supported capabilities documented, relevant tests pass and remaining gaps have explicit accepted scope. Assign each [integrator obligation](contract-integrator-obligations.md) to SDK, UI or operations. +Done when: implementation has a pinned target and unresolved features cannot be mistaken for supported runtime capabilities. + +## Step 2 Add the namespace and type boundaries + +Implementation: + +1. Add `client.agentic`, the management handle, `PushChain.utils.agentic` and AGENTIC constants through the existing exports. +2. Model create results, wallet summaries, checkpoint records, rules, spend, errors and progress. Separate internal wire terms from the public Rule input. +3. Add `agenticWallet` to the shared initialize/reinitialize option path without changing ordinary-client defaults. +4. Add AgenticError and AgenticRevertError using core's structured failure model. Preserve cause/decoded error data and batch-recovery hashes; expose the base execution error if required for public instanceof checks. +5. Isolate A04/A05/A06 in small interfaces. A registered method with no implementation throws a clear unsupported-capability error; the final public error names are documented before release. + +Verification: package type checks, import/export checks and consumer snippets for ordinary, agentic and read-only clients. Ensure the new namespace does not make market/job/evaluation appear implemented. + +Done when: the settled public surface compiles and incomplete features fail explicitly. + +## Step 3 Implement execution context and lifecycle + +Implementation: + +1. Resolve and store signer origin, signer Push identity, optional AGW execution account, Push network and selected generation separately. +2. Expose AGW as universal.account only in agentic execution mode. Keep universal.origin and getAccountStatus signer-scoped. +3. Validate deployed wallet and factory membership/capabilities. Determine owner versus agent from connected Push identity. External keys resolve to the UEA for their actual origin chain. +4. For agents, require an enabled rule naming that identity. Do not filter enabled rules by expiry at initialization or replace on-chain expiry checks. +5. Preserve read-only behavior across every signing entry point. A management handle remains a handle, never a hidden account switch. +6. On reinitialize, require explicit agenticWallet selection to retain/switch AGW mode, as our recorded SDK decision. Rebuild role/capability state; preserve inheritance of existing ordinary options. +7. Enforce FROM_NOT_ALLOWED and the spec's prohibited methods before signing. Audit auxiliary entry points, including transaction-creating reads, for bypasses. + +Verification: native owner/agent, EVM-origin agent, SVM-origin agent, unknown identity, changed signer/network/wallet, read-only writes and ordinary-client compatibility. Role checks must not grant signing authority to a read-only address. + +Done when: changing displayed account cannot change gas-payer or ownership derivation accidentally. + +## Step 4 Build the contract and deployment adapter + +Implementation: + +1. Centralize ABI selection, wiring reads, supported features, start blocks and cached immutable data per generation. +2. Add reads for owner, factory registry/count/prediction, enabled permission IDs, agent config, policy mode/config and checkpoints. +3. Add encoders for owner execute, agent executeAsAgent, grants/revokes and owner-authorized signature variants where used by the chosen transport. +4. Generate any OwnerIntent typed data from the exact contract ABI/domain/nonce scheme. Never copy the simplified signatures in a proposal over the delivered ABI; bind ref if the final signed-grant design includes it. +5. Validate proxy/implementation/wiring information supplied by the selected manifest. Include network, factory and implementation identity in caches; invalidate on incompatible configuration changes. +6. Leave A07 deployment entries absent until verified. Do not use old Donut addresses as placeholders for new capabilities. + +Verification: mocked mismatched wiring and unsupported generations, ABI encode/decode vectors, intent domain/nonce/deadline tests. Final artifact comparisons occur again in step 14. + +Done when: other modules can operate against a typed adapter without knowing contract-version details. + +## Step 5 Implement wallet and checkpoint reads + +Implementation: + +1. Implement client-bound derive from signer identity and factory next index; honor the contract's index range. Implement pure derive internally with explicit generation context pending A04 public signature. +2. Implement list using walletCount and predicted indices; include the next undeployed slot shown in the spec as our documented interpretation, with zero rules and deployed=false. +3. Implement wallet(address), owner and info with snapshot-consistent reads. Reconstruct current deployment label from the event when required by the selected generation. +4. Implement checkpoints from bounded/paginated logs, ordered by block/transaction/log index. Preserve seq, kind, ref, blockNumber and txHash. Account for reorgs and sinceBlock inclusion. +5. Implement active rules.get/list internals using enabled IDs followed by agent/action/policy reads at one block. Distinguish unknown, revoked, expired and zero-valued configurations. +6. Add historical records only through the A06-approved mechanism. A failed metadata reconstruction is not an empty rule list. Do not claim info/rule lookup is one RPC request if it requires dependent reads. +7. Add setLabel only for a matching supported capability. Respect the chosen cosmetic/checkpoint semantics from the final contract. + +Verification: empty owner, next slot, index races, multiple wallets/generations, paginated logs, same-block changes, unknown IDs, revoked-history limits and RPC failures. + +Done when: supported management reads return honest, complete records for their declared capability. + +## Step 6 Implement rule normalization and codecs + +Implementation: + +1. Normalize destination: omitted chainNamespace means connected Push; foreign rules retain their verified CAIP-2 chain identity. Reject owner-as-agent and duplicate agent/chain grants as specified. +2. Resolve destination token/native marker to the intended Push PRC20 with trusted chain context and exact SOURCE_CHAIN_NAMESPACE checks. Treat token amounts in their own units; reject ambiguous/duplicate asset resolution. +3. Derive expectedCEA from AGW and destination deployment, not from the agent. Supply it to the encoder and preview data; document and detect derivation drift. Separate asynchronous registry/RPC resolution from pure encodeRules/decodeRules helpers: pure helpers receive pre-resolved token, ABI and deployment context and perform no hidden network calls. +4. Derive selectors, actionId/configId and rulesId against contract vectors. Wallet-scope record keys. Use explicit validator context internally; receipt-assigned IDs remain authoritative. +5. Generate native argument pins and beneficiary positions from ABI layout. Static tuples can occupy multiple words; dynamic arguments require layout-aware handling. Reject unsupported layouts or a bare selector with insufficient ABI context for required pins. +6. Implement native terms with explicit values first. Centralize provisional A03 omission defaults and A01 approval validation behind one policy boundary. +7. Add a versioned universal multi-asset codec only after A05 artifacts arrive. Keep encode/decode inverse behavior and validation for 0–8 assets, per-token limits and call lists. +8. Define empty-assets call routing, expectedCEA byte width, zero/unlimited semantics and envelope-version behavior from fixtures. Do not guess these to make a test pass. + +Verification: contract-generated round trips, wrong token chain, wrong beneficiary, oversized values, dynamic ABI layouts, duplicate assets, native marker, boundary values and generation mismatch. Existing pinned single-asset vectors remain explicitly historical. + +Done when: every supported public rule has a deterministic, verified wire representation and decode result. + +## Step 7 Implement create, add and revoke + +Implementation: + +1. create validates all inputs before signing, resolves the next wallet, then deploys and grants in input order. Empty rules are valid. It never adds funding or PC top-ups. +2. Select supported UEA batching, native EIP-7702 batching or the documented native sequential fallback. Return the actual atomicity and transaction history through existing core metadata. +3. Parse matching wallet/rule events, preserve input ordering and distinguish predicted from confirmed IDs. Return the specified wallet/index/rulesIds/tx. +4. If a sequential step fails, retain deployed wallet identity, confirmed hashes and any pending hash. Re-read chain state before retry; do not silently deploy another wallet or repeat successful grants. +5. rules.add batches grants through the existing owner wallet. Recheck owner, nonce and duplicate candidates before signing. +6. rules.revoke accepts explicit IDs or all=true; reject bare revoke. Use one owner-wallet batch where needed and preserve failure atomicity. +7. Use signature-authorized contract variants only with matching verified intent encoding from step 4; a native execution path is not permission to invent a relay flow. + +Verification: partial creation, pending transaction, nonce/index races, zero/multiple rules, ID ordering, wrong owner, mixed-success prevention and all-rules revocation. + +Done when: a failed operation tells the caller exactly what committed and what can safely be retried. + +## Step 8 Implement atomic rules.update + +Implementation: + +1. Read old rules and all relevant spend counters at a consistent block, and validate every replacement before signing. +2. Encode assert(expected spend) → revoke(old ID) → grant(new rule) for every pair inside one owner execute batch. +3. Require an adapter with A05 expected-value assertions. A getter returning current totals is not a substitute. Never use the core sequential fallback for this operation. +4. Return old/new ID pairs in input order. New counters start at zero; do not silently subtract prior consumption from new caps. +5. Surface stale-spend failures clearly. A retry requires refreshed state and a new owner authorization; do not loop signatures automatically. +6. Decode checkpoint effects using final generation semantics; current single replacement adds five ticks. + +Verification: intervening spend, failed new grant, multiple assets/pairs, complete rollback, unusable old rule, usable new rule and same-block checkpoints. + +Done when: replacement preserves all-or-nothing behavior and cannot accept stale budget assumptions. + +## Step 9 Implement owner execution and setup + +Implementation: + +1. Wrap normal owner sends through AGW execute with single/batch ERC-7579 encoding. Preserve owner authority without applying agent rules. +2. Document separate funding of AGW assets/outbound PC and signer gas balance. Creation remains deployment/grants only. +3. Support bounded per-token gateway approvals through ordinary owner sends to the token from AGW. Include explicit replenishment/removal and tokens requiring a zero-reset approval strategy where applicable. +4. Use the same owner execution client for destination approvals after universal composition exists. Keep its policy-free owner authority visible to callers. +5. Reflect checkpoint changes for owner operations; do not claim allowance-driven balance changes always produce checkpoints. + +Verification: owner identity, unauthorized caller, approval success/removal, failed token call, allowance consumption and checkpoint deltas. Four local allowance experiments already demonstrate the mechanism; production gateway validation is still step 14. + +Done when: existing owner operations suffice to prepare and manage wallet funds without a new approval-specific SDK API. + +## Step 10 Implement agent selection and native sends + +Implementation: + +1. Resolve the actual transaction destination and query matching enabled rules on every send at a consistent block. +2. Zero candidates: NO_RULES_FOR_CHAIN before signing. Multiple candidates: DUPLICATE_RULE with a clear hint. Do not choose the first result. +3. Encode executeAsAgent with the selected ID and exact native single call. Leave expiry, allowance, amount and policy execution to contracts; do not build a second authorization engine in the SDK. +4. Reuse the signer transport so a foreign key calls from its own UEA. Reject any from route override before transport selection. +5. Apply A02 at the native-array boundary. Keep one-action public rules even if contract internals support more actions. + +Verification: revoked/expired rules, ambiguous direct grants, changed grants after lookup, native value/data calls, foreign-key identity and policy revert decoding. A rule can change after lookup; the contract remains authoritative. + +Done when: an agent's normal sendTransaction executes from AGW under the correct rule without stale authorization caching. + +## Step 11 Implement EVM universal sends + +Implementation: + +1. Build a dedicated AGW outbound composer using shared low-level payload/gas/token helpers. Do not call the signer-based Route 2 unchanged. +2. Resolve AGW destination CEA and construct the allowed destination multicall with its beneficiary context and destination-value fields. +3. Under the pinned policy, set empty recipient bytes, AGW revertRecipient and a nonzero maxPCForGas; adapt exact fields to the matched final gateway ABI. +4. Resolve the token moved by this outbound against the multi-asset rule; a list of permitted assets does not by itself mean one gateway request transfers all of them. Do not invent multi-token request batching. +5. Quote wallet outbound PC and validate the structural request. Keep signer Push gas and wallet outbound fees separate. Avoid silently adding approvals or swapping tokens in the agent path. +6. Preserve the specified first-use external UEA exception. Later agentic sends enforce signer gas balance rather than silently triggering a new origin lock. Unsupported gas helpers fail as specified. +7. Handle zero-amount/empty-assets calls only through the approved A05 routing. Use adapter capabilities for EVM multicall limits and supported token kinds. + +Verification: correct CEA/refund identity, empty bytes versus zero-address bytes, fee value/caps, positive/zero amount, token resolution, insufficient signer gas, first-use UEA path and policy rejection. + +Done when: the encoded outbound satisfies the matching policy and transport; live settlement remains an additional gate. + +## Step 12 Implement SVM destination support + +Implementation: + +1. Treat Solana-origin signers separately from Solana destination rulebooks. A Solana signer can use its UEA without implying SVM outbound support. +2. Add the supported SVM codec/adapter using final contract terms and gateway payload fixtures. Resolve 32-byte accounts, trusted gateway identity, program/discriminator allow-lists and asset mapping. +3. Compile account/data constraints from the program interface with explicit layout and interface-hash context; reject unrepresentable rules. +4. Cover intermediary/aggregator program substitutions, amount ratios/slippage and output-token-account setup. Expose limitations to callers rather than assuming arbitrary instructions are safe. +5. Implement obligations 19–23 before advertising SVM destination support. The current public Rule type may need an explicit approved extension to represent these constraints; record that dependency rather than improvising a public type. + +Verification: golden instruction payloads, wrong authority/beneficiary/mint/program, invalid layouts, missing token accounts and generation-specific enablement. + +Done when: the advertised SVM surface is representable and tested. Do not silently call this deferred if the agreed release promises it. + +## Step 13 Integrate responses, tracking and reads + +Implementation: + +1. Preserve logical AGW from and signer origin on sends and waited receipts. Keep raw transaction metadata/hashes available. Management writes retain the owner from specified by the API. +2. Extend wallet/UEA calldata reconstruction for trackTransaction; a correct live response alone does not prove replay correctness. +3. Reuse hash/event-based UTX tracking. Preserve Push failure versus destination failure and do not mark success merely because a destination hash exists. +4. Add AGENTIC progress events from the refreshed spec; no removed AGENTIC-TX-103. Emit core Push events plus the specified outbound wait events, without signer Route-2 setup events. +5. Carry init/per-call hooks through send and wait once per event. Decode AGW, factory, policy and engine errors while retaining structured core metadata. +6. Audit universal.read/executeReads: these submit transactions through the execution layer. Use explicit request-budget/refund/funding context, and preserve read-only restrictions. Management RPC reads remain non-signing. +7. Ensure prohibited prepareTransaction/executeTransactions routes cannot bypass AGW restrictions; keep supported pure preparation of read specs distinct from transaction execution. + +Verification: EOA/UEA owner and agent responses, replayed tracking, failed Push without outbound polling, destination failure/timeout, hook deduplication, read request/refund context and compatibility with ordinary routes. + +Done when: every execution path reports the right account, lifecycle state and error, including asynchronous completion. + +## Step 14 Onboard a matched deployment and run acceptance + +Implementation: + +1. Obtain A07 manifest and final artifact revisions. Verify factory/implementation/wiring, proxy details, policy/engine compatibility, capabilities and start blocks. +2. Replace provisional adapters and close A05/A07 only against verified artifacts. Detect any new spec/source changes before proceeding. +3. With separately authorized funding and broadcasts, exercise native/external owners and agents. Start universal acceptance with bounded allowance, positive token amount, empty recipient, AGW refund recipient and permitted multicall. +4. Confirm actual gateway token pull/burn, fee accounting, node/TSS acceptance, correct destination CEA, receipt hashes and tracking. +5. Exercise cap/expiry/beneficiary failures, revocation, atomic replacement, allowance exhaustion and destination failure. Document currently inert creditRevert behavior rather than assuming a refund restores spend. +6. Verify supported SVM paths and ordinary SDK routes. Record network, block, deployment and transaction IDs for reproducibility. + +Done when: supported capabilities have real acceptance evidence, unresolved failures are explained, and the release does not rely solely on mocked success. + +## Step 15 Complete Web2 compatibility + +Implementation: + +1. Add enumerable READ.CHAIN containing real chains plus WEB2='web2'. Keep the specified deprecated CHAIN.WEB2 alias and compatibility for the existing READ.WEB2 surface. +2. Accept both new and legacy literal inputs, normalize to internal web2/https, and preserve wire identity web2:https. +3. Update ReadChain types, query discrimination, public parsers, prepared specs and response/tracker normalization consistently. +4. Ensure transaction destinations never accept the Web2 read-only marker. + +Verification: both literal spellings, enum iteration, compile-time read/transaction distinctions, serialized wire vectors and tracked legacy results. + +Done when: new public syntax works without breaking the existing read wire protocol. + +## Step 16 Implement compileCard when its schema is settled + +Implementation: + +1. Obtain canonical card schema/version, signing/encoding rules and shared compiler vectors from marketplace/hook work. +2. Compile user input into public Rule[] through the same normalization and codec preparation as direct grants. +3. Preserve provider Push identity, exact marketplace expiry and supported chain/rule cardinality. Do not invent a multi-rule job binding over the current one-ID hook. +4. Keep market/job/evaluation namespaces outside this AGW implementation. Their independent delivery is not implied by exporting compileCard. + +Verification: shared SDK/hook vectors, mismatched provider/chain/expiry, card tampering, unsupported multi-chain binding and compatibility across schema versions. + +Done when: compileCard produces the same authorized terms the corresponding hook validates. Otherwise retain an explicit development placeholder and a release scope dependency. + +## Step 17 Finish examples, obligations and release + +Implementation: + +1. Publish examples for create with no funding, separate funding/allowance, native agent sends, EVM destination sends, lifecycle updates and recovery from partial creation. +2. Show signer gas, wallet PC, destination idle balances, expiry and unlimited caps distinctly. Explain cap reset, outstanding outbound execution after revoke, allowance checkpoint blind spots and generation migration. +3. Map all 23 [integrator obligations](contract-integrator-obligations.md) to implementation, documentation or UI responsibilities. EVM/native items 1–18 primarily map to steps 5–11 and 17; SVM items 19–23 map to step 12 and destination acceptance. +4. Document unsupported capabilities and approved scope decisions. Remove or close all A01–A08 placeholders for advertised features, including public helper and history types. +5. Run relevant package type/build/lint and regression checks. Prepare changeset/version notes for public additions and Web2 alias migration, using repository release conventions. +6. Review public examples against actual exported methods and the selected deployment. Update tutorial/design/gap records to describe delivered behavior. + +Done when: the package can be used from its published exports as documented, supported routes have acceptance evidence and remaining scope limits are explicit. + +## Public surface coverage + +| Public surface | Implementation steps | +| --- | --- | +| agentic.derive, agentic.list | 4–5 | +| agentic.create | 6–7 | +| agentic.wallet, info, owner, checkpoints | 2, 5 | +| setLabel | 4–5, 14; matching capability required | +| rules.list/get | 5–6; A05/A06 | +| rules.add/revoke | 6–7 | +| rules.update | 8 | +| initialize/reinitialize with agenticWallet | 3–4 | +| owner/agent sendTransaction | 9–12 | +| response.wait, trackTransaction, errors/hooks | 13 | +| utils.agentic rulesId/actionId/configId/deriveWallet | 4, 6; A04 | +| utils.agentic encodeRules/decodeRules | 6, 12 | +| utils.agentic.compileCard | 16 | +| AGENTIC constants and READ.CHAIN | 2, 4, 15 | +| forbidden methods, gas behavior and transaction-creating reads | 3, 10–13 | + +## Suggested implementation increments + +Each increment can be a focused PR; incomplete runtime features stay capability-gated and are not advertised as released support. + +1. **Foundation:** steps 1–3, adapter interfaces and SDK lifecycle tests. Start here. +2. **Independent compatibility:** step 15 plus public error export cleanup where appropriate. +3. **Read and identity adapters:** steps 4–5 and settled ID/ABI utilities from 6. +4. **Management:** final rule codecs, create/add/revoke, atomic replacement and recovery (6–8), when their required answers arrive. +5. **Execution:** owner/native agent paths, then EVM universal composition and gas (9–11). +6. **Responses and SVM:** step 13 integrated as execution lands; step 12 when its schema/capabilities are confirmed. +7. **Matched-deployment acceptance:** step 14 and fixes driven by observed integration results. +8. **Card compiler and release:** step 16 when its downstream schema exists; step 17 for the explicitly approved release surface. + +Track each increment as not started, in progress, implemented, verified or externally blocked. “Implemented” excludes placeholders; “verified” includes the listed checks. The earlier 50–60% estimate is provisional and should be replaced with task-level effort estimates after the first implementation breakdown. diff --git a/plan/agw/questions-harsh.md b/plan/agw/questions-harsh.md index 4ea47610..1ace6e11 100644 --- a/plan/agw/questions-harsh.md +++ b/plan/agw/questions-harsh.md @@ -1,43 +1,154 @@ -# Product questions for Harsh +# AGW SDK open product decisions for Harsh -Revised October 3, 2026 after checkpoint follow-up. Local draft, not sent. Baseline: AGW `pushAgenticWallet_v3@e704d5b`, core `cb69e0b`, full Notion export October 03, 2026 at 13:23 IST. SDK page 5 remains the public target; proposed API changes below require agreement. +We are preparing the AGW SDK implementation and need the decisions below to finalize its public behavior. Each item gives the issue, our recommendation and the answer needed. Please reply using the item IDs; approve the recommendation or provide the replacement behavior/schema. -## H1 Destination approval safety +**Status:** open review draft. H1–H4 concern standalone AGW. H5 concerns `compileCard` and marketplace integration. Design approval settles the product choice; matching contract artifacts and deployment are separate dependencies. -The headline example allows destination `approve(address,uint256)` without a spender constraint. Universal AllowedCall can pin a beneficiary to the CEA, but cannot pin an arbitrary spender. This can authorize an agent-controlled spender against existing CEA balances. Current marketplace code rejects approve/increaseAllowance and uses owner Approval[] instead. +| Item | Decision needed | Affected SDK behavior | +| --- | --- | --- | +| [H1](#h1) | Agent approval policy | Which universal rules can be granted | +| [H2](#h2) | Native agent transaction arrays | Whether arrays are rejected or supported in v1 | +| [H3](#h3) | Defaults for omitted limits | Authority granted by optional fields | +| [H4](#h4) | Helper context, spend/history reads and SVM rule shape | Public signatures and returned records | +| [H5](#h5) | Canonical card schema and scope | `utils.agentic.compileCard` | -Recommendation: reject these known approval selectors in universal agent rules and add an explicit owner-controlled destination approval flow. This is a public validation/API change, not merely internal implementation. Native approvals can use spender pins. Selector filtering alone cannot make arbitrary untrusted contracts safe. +## Source baseline -Decision: which owner approval surface should the SDK expose, and should the unsafe example be replaced accordingly? +- **Target:** [SDK spec snapshot](notion/5-sdk-agw.md), exported October 3, 2026 at 13:23 IST; [live Notion page](https://app.notion.com/p/pushprotocol/5-SDK-AGW-3e9188aea7f481cf8e8de324956549b9). +- **Contract proposal:** [saved change set](notion/1-agw-contract-changes.md), especially section 4c; [live Notion page](https://app.notion.com/p/pushprotocol/1-AGW-Contract-Changes-nomenclature-standard-change-set-3e9188aea7f4813aa31fc95ceb4e684d). +- **Reviewed source:** [AGW e704d5b](https://github.com/pushchain/push-agentic-wallets/blob/e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9/src/AGW.sol). Remote refs were rechecked October 3 and were unchanged. Notion has not been re-exported since the time above; later edits may answer these items. -## H2 Native scope and arrays + -The contract can grant up to eight native actions in a rule set, but page 5 NativeRule describes one action and permits one rule per agent/chain. The agent door accepts only single/default execution. EVM destination arrays can fit one bounded CEA multicall; Push-native arrays cannot become atomic through the present agent door. +## H1 Agent permission to approve destination spending -Decision: keep one native action per public rule, or explicitly extend its type to an action list? For native arrays, should the SDK reject them initially, offer explicitly sequential behavior, or wait for an agreed contract change? We recommend rejecting unsupported arrays rather than silently weakening atomicity. +**Issue.** The SDK's creation example allows destination `approve(address,uint256)` without restricting the spender. An agent could approve an address it controls, allowing that address to withdraw existing CEA tokens outside the outbound token caps. The universal rule can pin a beneficiary to the CEA, but cannot pin an arbitrary approved spender. -## H3 Optional limit defaults +**Recommendation.** Reject known approval-granting selectors, including `approve` and `increaseAllowance`, in universal agent rules. Replace the example with bounded destination approval performed by the owner through the existing owner-mode `universal.sendTransaction`. Selector filtering is only one safeguard; it does not make arbitrary untrusted contracts safe. -The new contract proposal explicitly makes AssetCap.maxTotal=0 unlimited; we propose mapping an omitted asset maxTotal to zero as well, with an unlimited preview. Please confirm omission semantics and the still-undefined native defaults: maxValuePerCall, maxValueTotal, amount.maxTotal, maxCalls and allowedCalls.maxValue. Native explicit zero must not accidentally inherit the new asset sentinel convention. +**Answer needed:** approve this policy, or specify the alternative permissions/safeguards intended for agent-created destination approvals. -## H4 Reconcile the SDK spec with the delivered D3 model +**Evidence:** [SDK creation example, section 1.b](notion/5-sdk-agw.md); [universal beneficiary/value checks](https://github.com/pushchain/push-agentic-wallets/blob/e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9/src/policies/UniversalRulesPolicy.sol#L1005). -Please approve a small spec correction set, with the exact API wording reviewed before implementation: + -- Rules IDs use validator address, encoded Push agent and grant nonce; chain is not hashed and IDs are wallet-scoped. The helper needs deployment/validator context, and constants currently claim no validator address. -- Wallet prediction is stable within a factory/implementation generation, not globally from owner/index alone. -- The existing native SDK supports EIP-7702 batching with a sequential fallback; creation must describe actual atomicity. -- Agent duplicate-rule ambiguity must have documented behavior. SDK preflight can reject duplicates, while direct contract grants can still create more than one active candidate. +## H2 Native agent transaction arrays -- Universal Spent still returns scalar amountSpent while the new rule has per-token caps. Please agree a per-asset spent shape rather than aggregating unlike token units. -- Should rules.list() return revoked rules as well as active rules? If historical rules are promised, the grant event needs agent attribution or the SDK needs reliable calldata reconstruction; current revoke clears agent config. +**Issue.** The SDK says transaction arrays work in agentic mode. The current agent door dispatches one Push-native call. An EVM destination multicall is different: it is carried inside one outbound gateway call. -Creation now deploys/grants only; funding and PC top-ups are separate as the updated spec directs. We will own partial-failure metadata, list/info implementation, read-only/reinitialize details, receipt mapping and Web2 migration. We will document any observable choice and flag only departures from explicit API requirements. +**Recommendation.** Keep the specified single-action `NativeRule`. Reject native **agent** arrays before signing in v1, without a sequential fallback. Continue supporting owner wallet batches and bounded EVM destination multicalls. -## Separate downstream note +**Answer needed:** approve that v1 scope, or confirm that native agent batching must be added to the contracts before this SDK capability ships. -Multi-chain card binding, expiry equality, dropped binder role, single-token versus K-12, and old job examples belong in the marketplace/job alignment discussion. They do not require reopening standalone AGW implementation decisions. +**Evidence:** [SDK agent behavior and NativeRule, sections 2.a and 3.b](notion/5-sdk-agw.md); [agent dispatch restriction](https://github.com/pushchain/push-agentic-wallets/blob/e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9/src/AGW.sol#L849). -## Current source freshness + -Successful full Notion export: October 03, 2026 at 13:23 IST; 12 pages checked, pages 1 and 5 changed. AGW remains pinned to reviewed e704d5b; no new Git refresh was part of this pull. Core/gateway retain cb69e0b/bcbf7df evidence. Drafts remain unsent. +## H3 Defaults when a limit is omitted + +**Issue.** Optional fields need explicit defaults because omission changes the authority granted to an agent. + +**Recommendation:** + +| Omitted input | Proposed encoded value | Permission granted | +| --- | --- | --- | +| Universal `assets[].maxTotal` | `0` in the proposed multi-asset ABI | Unlimited total for that asset | +| Native `maxValuePerCall` | `0` | No native value transfer | +| Native `maxValueTotal` | `0` | No native value transfer | +| Native `amount.maxTotal`, when `amount` is present | `uint256` maximum | Unlimited metered total; required `maxPerCall` still applies | +| Native `maxCalls` | `0` | Unlimited calls until expiry | +| Universal `allowedCalls[].maxValue` | `0` | No native value attached to that destination call | + +Explicit zero remains zero. In the current native policy, zero value/amount caps prohibit positive value/amount; only `maxCalls` treats zero as unlimited. The proposed universal asset format adds its own zero-unlimited convention. + +**Answer needed:** approve the table or give the replacement default for each changed row. Unlimited permissions will be shown explicitly in documentation/previews. + +**Evidence:** [optional SDK fields, section 3.b](notion/5-sdk-agw.md); [proposed multi-asset sentinel, section 4c](notion/1-agw-contract-changes.md); [native terms and limit definitions](https://github.com/pushchain/push-agentic-wallets/blob/e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9/src/libraries/Types.sol#L300). + + + +## H4 Public helpers and rule reads + +Please answer each sub-item separately; they affect different public types. + + + +### H4.1 Generation context for pure helpers + +**Issue.** The specified helpers omit inputs needed to match contract results. Rule IDs depend on the validator address and grant nonce. Wallet prediction depends on the factory and wallet implementation generation. + +**Proposed signatures** — subject to approval: + +```ts +rulesId(agent, grantNonce, { validator }) +deriveWallet(owner, index, { factory, walletImplementation }) +``` + +Chain is not part of the delivered rule-ID hash. Client-bound methods resolve deployment context internally; pure helpers receive it explicitly. Rule records are indexed by wallet plus rule ID. + +**Answer needed:** approve these signatures or supply the preferred way to pass deployment context. + +**Evidence:** [current helper signatures, section 3.e](notion/5-sdk-agw.md); [grant nonce and ID assignment](https://github.com/pushchain/push-agentic-wallets/blob/e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9/src/AGW.sol#L626); [wallet prediction inputs](https://github.com/pushchain/push-agentic-wallets/blob/e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9/src/AGWFactory.sol#L232). + + + +### H4.2 Spend returned for a multi-asset rule + +**Issue.** Rules now contain `assets[]`, but the proposed `Spent` result still has one scalar `amountSpent`. Different token units cannot be added together. + +**Proposed universal result:** + +```ts +{ + kind: 'universal', + assets: [ + { token: destinationTokenAddress, amountSpent: 25000000n } + ] +} +``` + +`token` uses the same destination-chain identity/native-marker convention as the public rule. Native spend keeps its existing three counters. Contract-side PRC20 conversion stays inside the SDK. + +**Answer needed:** approve this result shape or provide an alternative. Coordinate the underlying read/assertion ABI with [Zaryab Z1.2](questions-zaryab.md#z1-2). + +**Evidence:** [Rule and Spent types, section 3.b](notion/5-sdk-agw.md); [per-token accounting proposal, section 4c](notion/1-agw-contract-changes.md). + + + +### H4.3 Revoked-rule history + +**Issue.** `rules.list()` promises “every rule,” while revocation clears agent configuration from the engine. Reliable historical records require additional event metadata or reconstruction of grant calls. + +**Answer needed:** does `rules.list()` include revoked rules? Also define `rules.get(revokedId)` behavior. If full history is required, we recommend metadata that can be reconstructed reliably for every supported grant path; [Zaryab Z1.3](questions-zaryab.md#z1-3) covers the contract dependency. + +**Evidence:** [SDK reads, sections 1.i–1.j](notion/5-sdk-agw.md); [removed configuration behavior](https://github.com/pushchain/push-agentic-wallets/blob/e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9/src/interfaces/ISmartSessionConfigReader.sol#L13). + + + +### H4.4 Public shape for SVM destinations + +**Issue.** The public `AllowedCall` is EVM-shaped. SVM destination rules require program/discriminator and account/data constraints that should not be invented by the SDK implementation. + +**Answer needed:** confirm whether SVM destinations are in this release and, if so, provide or approve their public rule representation. Solana-origin signers using a UEA are a separate capability from executing on a Solana destination. Align this answer with [Zaryab's destination capability manifest](questions-zaryab.md#z3). + +**Evidence:** [SDK universal rule types, section 3.b](notion/5-sdk-agw.md); [SVM integrator requirements 19–23](contract-integrator-obligations.md). + + + +## H5 Card schema for compileCard + +**Issue.** `utils.agentic.compileCard(card, userInput, ctx)` is part of the public target, but its canonical schema/version and binding scope need alignment with the marketplace/hook. The reviewed marketplace records one rules ID per job. + +**Answer needed:** identify the shared-schema owner and provide or approve: + +- The versioned `card` and `userInput` shapes, including required fields. +- Provider Push identity, expiry and `Rule[]` output semantics. +- Whether v1 supports one execution chain or requires multi-chain job binding. + +Coordinate encoding and shared vectors with [Zaryab Z5](questions-zaryab.md#z5). This blocks `compileCard` completion, while standalone AGW foundation work can proceed. + +**Evidence:** [SDK helpers, section 3.e](notion/5-sdk-agw.md); [marketplace SDK target](notion/6-sdk-universal-marketplace.md); [current job/rule binding](https://github.com/pushchain/push-chain-core-contracts/blob/cb69e0ba101bef1bb4440e54b2c45396be3e92ce/src/agentic-commerce-8183/UniversalMarketplace.sol#L301). + +## Supporting documents + +[Implementation plan](implementation-plan.md) · [External dependencies](external-blockers.md) · [SDK design](sdk-design-review.md) · [Zaryab's open requests](questions-zaryab.md) diff --git a/plan/agw/questions-zaryab.md b/plan/agw/questions-zaryab.md index 66c05f72..cfb633fd 100644 --- a/plan/agw/questions-zaryab.md +++ b/plan/agw/questions-zaryab.md @@ -1,37 +1,117 @@ -# Contract questions for Zaryab +# AGW SDK open contract requests for Zaryab -Revised October 3, 2026 after checkpoint implementation. Local draft, not sent. AGW baseline `pushAgenticWallet_v3@e704d5b`, core `cb69e0b`. D3 is implemented in source and owner batching is already the documented design; those questions have been removed. Refresh the sources before sharing. +We need the artifacts and compatibility details below to finish the AGW SDK against the intended contract generation. Please reply by item ID with the source/ABI/vector link when available, or the remaining work and expected delivery. Product choices that affect these requests are linked to Harsh's document. -## Z1 Next wallet generation surface +**Status:** open review draft. Z1/Z3 concern standalone AGW. Z5 concerns the shared card compiler. IDs retain their earlier numbering for cross-references. -Checkpoints are now implemented in source, including count views, per-call ticks and WithSig behavior. Which of grant ref, label storage/setLabel, envelope version and the new multi-asset/maxGasPerCall terms are planned together for the next generation? Please include agent attribution in RulesGranted if the SDK must return revoked-rule history; the engine clears that agent config on revoke. If ref is added to signed grants, confirm it is bound by the owner's signed digest. +| Item | Requested deliverable | What it enables | +| --- | --- | --- | +| [Z1](#z1) | Matching terms, accounting/assertion ABI and metadata surface | Final rule encoding, reads and safe replacement | +| [Z3](#z3) | Verified deployment and capability manifest | Generation onboarding and live acceptance | +| [Z5](#z5) | Canonical card encoding and shared vectors | SDK/hook-compatible `compileCard` | -The checkpoint implementation has chosen storage and deliberately revised the owner-door invariant; we have removed that design question. Replacement batches add five ticks. We will consume the implemented event/count semantics and separately align evaluator snapshot timing and the documented allowance blind spot. +## Source baseline -The new section 4c also needs exact per-asset spent and replacement assertion ABIs. Its no-expected-value assertSpent returning totals is not by itself the current stale-spend race guard. Please define that guard, empty-assets call routing, zero/unlimited maxTotal behavior and whether bytes32 expectedCEA is intended for EVM terms. +- **Target:** [saved contract change set](notion/1-agw-contract-changes.md), especially section 4c; [live Notion page](https://app.notion.com/p/pushprotocol/1-AGW-Contract-Changes-nomenclature-standard-change-set-3e9188aea7f4813aa31fc95ceb4e684d). +- **SDK:** [saved page 5](notion/5-sdk-agw.md); [live Notion page](https://app.notion.com/p/pushprotocol/5-SDK-AGW-3e9188aea7f481cf8e8de324956549b9). Both snapshots were exported October 3, 2026 at 13:23 IST; later page edits are not covered. +- **Reviewed code:** [AGW e704d5b](https://github.com/pushchain/push-agentic-wallets/blob/e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9/src/AGW.sol), core `cb69e0b`, gateway `bcbf7df`. Remote refs were rechecked October 3 and were unchanged. This does not verify a new live deployment. [Full source inventory](SOURCES.md). -## Z2 Push-side gateway allowance + -Gateway PRC20 outbound pulls from the AGW with transferFrom, but the documented setup has no approve step. The universal agent rule only permits the gateway action. We propose an owner-door bounded approve(gateway, amount) during a separate funding/owner setup flow, with explicit replenishment and recovery behavior. Funding is no longer part of create in the updated SDK spec; multi-asset rules require per-token allowance handling. +## Z1 Source and ABI for the target generation -Please confirm the intended allowance mechanism and add it to the flow and an integration test that actually pulls/burns tokens. Destination approvals are a separate owner operation. + -## Z3 Deployment and generation plan +### Z1.1 Universal rule encoding -Please provide the next generation's factory, wallet implementation, validator, engine and policy addresses, source commits and deployment start block when available. Will engine/URP be reused, or will this be isolated from historical configs? How will accountId/version distinguish ABI generations? Is SVM destination support enabled there? +**Current mismatch.** The proposal introduces multi-asset rules; tested `e704d5b` still has single-asset terms. The SDK needs an exact supported encoding before it can finalize the codec. -Existing clones cannot acquire the new wallet ABI. The recorded Donut factory still points to the old implementation in our probes. We will add SDK generation guards and handle historical addresses separately. +**Please provide the implementation revision, ABI and vectors covering:** -## Z4 Gateway struct intent +| Area | Detail needed | +| --- | --- | +| Assets and counters | `assets[]`, per-token counters, duplicate assets and zero/unlimited conventions | +| Call-only rules | Routing and token fields when `assets[]` is empty and no tokens move | +| Gas cap | Final `maxGasPerCall` field/layout | +| Destination account | EVM `expectedCEA` type/width and encoding | +| Envelope | Version field, accepted version and body layout | -The available evidence shows six-field gateway main is older, while the current September branch and live Donut dispatcher use eight fields. Is any future removal of gasPrice/maxPCForGas actually planned? If not, page 1's coordinated-removal warning should be corrected. We will encode the matched deployed ABI. +If the code is still pending, please identify the agreed target definitions and remaining implementation work. A proposal alone cannot establish the final wire ABI. -## Heads-up and downstream alignment +**Evidence:** [proposed section 4c](notion/1-agw-contract-changes.md); [pinned UniversalTerms](https://github.com/pushchain/push-agentic-wallets/blob/e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9/src/libraries/Types.sol#L217). -Our dedicated agent composer must send a nonzero maxPCForGas, empty EVM recipient and AGW revertRecipient. The first authorized live test will verify positive-amount multicall settlement with this shape; an existing successful transaction hash would help. This is not a request to change URP's empty-recipient guard. + -creditRevert is already documented as waiting on Push-core executor support; we will document that limitation rather than ask you to redesign it. The old Ed25519 session-validator issue is obsolete at head. Separate downstream alignment remains for marketplace expiry equality, rule binding, payment tokens and hook lifecycle. +### Z1.2 Per-token reads and safe replacement -## Current source freshness +**Issue.** Replacement must reject a stale spend snapshot. An `assertSpent` function that only returns current totals does not protect a later revoke/grant from an agent spending after the SDK prepared the transaction. -Successful full Notion export: October 03, 2026 at 13:23 IST; 12 pages checked, pages 1 and 5 changed. AGW remains pinned to reviewed e704d5b; no new Git refresh was part of this pull. Core/gateway retain cb69e0b/bcbf7df evidence. Drafts remain unsent. +**Requested behavior:** compare caller-supplied expected totals for all old-rule assets and revert if any differs, inside the same owner transaction as revoke and grant. + +**Please provide:** + +- Per-token spend-read and expected-spend assertion signatures. +- Token ordering/completeness rules for the expected snapshot. +- A vector/test where intervening spend makes the entire replacement revert. + +The SDK will implement the wrapper and atomic batch. Harsh's [H4.2](questions-harsh.md#h4-2) settles the public returned `Spent` shape. + +**Evidence:** [current expected-spend assertion](https://github.com/pushchain/push-agentic-wallets/blob/e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9/src/policies/UniversalRulesPolicy.sol#L1409); [proposed assertion change, section 4c](notion/1-agw-contract-changes.md). + + + +### Z1.3 References, labels and historical metadata + +**Please confirm the selected generation's surface:** + +| Feature | Open detail | +| --- | --- | +| Grant reference | `ref` parameter/event shape; include it in the owner signature digest when a signed grant is used | +| Editable labels | Whether proposed `setLabel`/label storage ships with this generation, with its ABI/event behavior | +| Revoked-rule history | If Harsh requires it, provide reliable historical agent/action attribution for supported grant paths; a grant-event improvement is one possible solution | + +Historical scope depends on [Harsh H4.3](questions-harsh.md#h4-3). Please distinguish committed features from proposals still awaiting agreement. + +**Evidence:** [target SDK lifecycle](notion/5-sdk-agw.md); [pinned grant signatures](https://github.com/pushchain/push-agentic-wallets/blob/e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9/src/AGW.sol#L483); [pinned grant event emission](https://github.com/pushchain/push-agentic-wallets/blob/e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9/src/AGW.sol#L636). + + + +## Z3 Deployment and capability manifest + +**Please provide the following for the selected release deployment:** + +| Manifest field | Required information | +| --- | --- | +| Network and addresses | Factory, wallet implementation, validator, engine and policy addresses | +| Source and ABI | Exact revisions/build artifacts, proxy implementations where applicable and wiring | +| Start blocks | Deployment/event start blocks for bounded discovery and reconstruction | +| Reused components | Whether engine/policy instances are shared with previous generations and their compatibility | +| Gateway | Matched gateway implementation/request ABI and any planned coordinated migration | +| Destination support | Supported EVM/SVM capabilities; matching SVM terms/payload fixtures if enabled | + +Existing wallet clones cannot acquire the target wallet ABI. We will use the manifest to build a generation registry, verify deployed wiring and run live acceptance. These addresses must correspond to the intended release generation. + +**If deployment is pending:** provide the intended feature scope and remaining delivery work. Clarification settles the plan; live acceptance remains pending until deployment exists. + +SVM public-rule scope also needs [Harsh H4.4](questions-harsh.md#h4-4). [Historical Donut addresses](notion/agw-address-book-donut-2026-09-04.md) are retained as historical evidence, not assumed to support this target. + + + +## Z5 Card encoding and shared compiler vectors + +**Issue.** The SDK's `compileCard` must produce terms that the marketplace/hook validates using the same schema and rules. + +**Please provide or identify:** + +- Canonical versioned card encoding/hash and the contract revision that consumes it. +- Contract-side compilation/verification rules, including provider identity, chain, expiry and rule binding. +- Shared valid/invalid input vectors for the SDK and hook. +- Missing binding support, if product requires a broader scope than the current one-rule job binding. + +[Harsh H5](questions-harsh.md#h5) requests the public schema and single-chain/multi-chain scope. This dependency blocks `compileCard` completion, while basic AGW execution can proceed independently. + +**Evidence:** [SDK helper target](notion/5-sdk-agw.md); [current terms verifier](https://github.com/pushchain/push-chain-core-contracts/blob/cb69e0ba101bef1bb4440e54b2c45396be3e92ce/src/agentic-commerce-8183/UniversalMarketplaceTerms.sol#L32); [current job/rule binding](https://github.com/pushchain/push-chain-core-contracts/blob/cb69e0ba101bef1bb4440e54b2c45396be3e92ce/src/agentic-commerce-8183/UniversalMarketplace.sol#L301). + +## Supporting documents + +[Implementation plan](implementation-plan.md) · [External dependencies](external-blockers.md) · [Current baseline](current-baseline.md) · [Harsh's open decisions](questions-harsh.md) diff --git a/plan/agw/research/sdk-owned-review-2026-10-03/AllowanceReview.t.sol b/plan/agw/research/sdk-owned-review-2026-10-03/AllowanceReview.t.sol new file mode 100644 index 00000000..bd32286f --- /dev/null +++ b/plan/agw/research/sdk-owned-review-2026-10-03/AllowanceReview.t.sol @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +// Review-only: copy into test/review of push-agentic-wallets@e704d5b. +// Real wallet/engine/policy; authored ERC20 and gateway pull/burn fixtures. +// This proves the owner approval mechanism, not production gateway/node settlement. +import { E2ETest } from "../integration/8_e2e.t.sol"; +import { MockPRC20 } from "../mocks/MockUniversalGateway.sol"; +import { UniversalOutboundTxRequest } from "../../src/libraries/Types.sol"; +import { ExecutionLib } from "../../src/libraries/ExecutionLib.sol"; +import { AGWErrors } from "../../src/libraries/Errors.sol"; +import { ISmartSession } from "smartsessions/ISmartSession.sol"; +import { PermissionId } from "smartsessions/DataTypes.sol"; + +contract ReviewPullToken is MockPRC20 { + error InsufficientAllowance(); + function transferFrom(address from, address to, uint256 amount) external returns (bool) { + uint256 allowed = allowance[from][msg.sender]; + if (allowed < amount) revert InsufficientAllowance(); + if (balanceOf[from] < amount) revert InsufficientBalance(); + allowance[from][msg.sender] = allowed - amount; + balanceOf[from] -= amount; + balanceOf[to] += amount; + return true; + } + function burn(uint256 amount) external returns (bool) { + if (balanceOf[msg.sender] < amount) revert InsufficientBalance(); + balanceOf[msg.sender] -= amount; + return true; + } +} + +contract ReviewPullGateway { + // Mirrors the transferFrom -> burn sequence at gateway bcbf7df, + // UniversalGatewayPC.sol:430-434. Other gateway behavior is not modeled. + function sendUniversalTxOutbound(UniversalOutboundTxRequest calldata req) external payable { + ReviewPullToken token = ReviewPullToken(req.token); + require(token.transferFrom(msg.sender, address(this), req.amount)); + require(token.burn(req.amount)); + } +} + +contract AllowanceReviewTest is E2ETest { + function _setupAllowance() internal { + pUSDC = new ReviewPullToken(); + vm.etch(GATEWAY, type(ReviewPullGateway).runtimeCode); + _deployAndGrant(); + } + + function _approval(uint256 amount) internal view returns (bytes memory) { + return ExecutionLib.encodeSingle(address(pUSDC), 0, + abi.encodeCall(MockPRC20.approve, (GATEWAY, amount))); + } + + function _ownerApprove(uint256 amount) internal { + bytes memory call = _approval(amount); + bytes32 mode = _singleMode(); + vm.prank(BOB_UEA); + bobAgw.execute(mode, call); + } + + function test_Allowance_MissingApprovalRevertsAndRollsBackSpend() public { + _setupAllowance(); + bytes memory call = _executionCalldata(10e6, 0); + bytes32 mode = _singleMode(); + uint64 beforeCount = bobAgw.checkpointCount(); + vm.prank(agentAddr); + vm.expectRevert(ReviewPullToken.InsufficientAllowance.selector); + bobAgw.executeAsAgent(permissionId, mode, call); + assertEq(_spent(permissionId), 0); + assertEq(pUSDC.balanceOf(address(bobAgw)), HUNDRED_USDC); + assertEq(bobAgw.checkpointCount(), beforeCount); + } + + function test_Allowance_OwnerApprovalEnablesPullBurnAndCanBeRemoved() public { + _setupAllowance(); + uint64 beforeCount = bobAgw.checkpointCount(); + _ownerApprove(20e6); + assertEq(bobAgw.checkpointCount(), beforeCount + 1); + assertEq(pUSDC.allowance(address(bobAgw), GATEWAY), 20e6); + _submitRequest(_executionCalldata(10e6, 0)); + assertEq(pUSDC.balanceOf(address(bobAgw)), 90e6); + assertEq(pUSDC.balanceOf(GATEWAY), 0, "pulled tokens burned"); + assertEq(pUSDC.allowance(address(bobAgw), GATEWAY), 10e6); + assertEq(_spent(permissionId), 10e6); + assertEq(bobAgw.checkpointCount(), beforeCount + 1, "agent spend adds no checkpoint"); + _ownerApprove(0); + assertEq(pUSDC.allowance(address(bobAgw), GATEWAY), 0); + bytes memory call = _executionCalldata(1e6, 0); + bytes32 mode = _singleMode(); + vm.prank(agentAddr); + vm.expectRevert(ReviewPullToken.InsufficientAllowance.selector); + bobAgw.executeAsAgent(permissionId, mode, call); + assertEq(_spent(permissionId), 10e6); + assertEq(pUSDC.balanceOf(address(bobAgw)), 90e6); + } + + function test_Allowance_AgentCannotUseOwnerDoor() public { + _setupAllowance(); + bytes memory call = _approval(20e6); + bytes32 mode = _singleMode(); + vm.prank(agentAddr); + vm.expectRevert(AGWErrors.CallerIsNotOwner.selector); + bobAgw.execute(mode, call); + assertEq(pUSDC.allowance(address(bobAgw), GATEWAY), 0); + } + + function test_Allowance_UniversalRuleCannotApproveThroughAgentDoor() public { + _setupAllowance(); + bytes memory call = _approval(20e6); + bytes32 mode = _singleMode(); + vm.prank(agentAddr); + vm.expectRevert(abi.encodeWithSelector(ISmartSession.NoPoliciesSet.selector, + PermissionId.wrap(permissionId))); + bobAgw.executeAsAgent(permissionId, mode, call); + assertEq(pUSDC.allowance(address(bobAgw), GATEWAY), 0); + assertEq(_spent(permissionId), 0); + } +} diff --git a/plan/agw/research/sdk-owned-review-2026-10-03/README.md b/plan/agw/research/sdk-owned-review-2026-10-03/README.md new file mode 100644 index 00000000..45eaa742 --- /dev/null +++ b/plan/agw/research/sdk-owned-review-2026-10-03/README.md @@ -0,0 +1,28 @@ +# SDK owned review evidence + +October 3, 2026. SDK production source is 167fdc6 (planning branch 46f9e66). The [test summary](test-summary.json) records the commands and checksums. Existing SDK unit suites: 183 passed, 0 failed, ten suites. These exercise existing behavior with mocks; they do not test a completed AGW SDK. + +## New allowance experiments + +Four review-only tests pass against AGW e704d5b in an isolated copy. [Source](AllowanceReview.t.sol), [Forge output](allowance.log). The AGW, factory, policy and E2E harness source files were byte-compared to the pinned Git objects before running. The initial fixture attempted to override the harness's non-virtual setUp; it was corrected to use a helper invoked by each test, without changing the harness or production source. + +| Test | What it proves locally | +| --- | --- | +| Missing approval | transferFrom fails; wallet balance and URP spend roll back | +| Owner approval, spend and removal | execute establishes allowance; agent outbound consumes it, burns the pulled tokens and increments spend; owner can zero it and prevent further pulls | +| Agent using owner door | Exact CallerIsNotOwner error; no allowance created | +| Agent approving through universal rule | Exact engine NoPoliciesSet error; no allowance created | + +The real gateway at bcbf7df calls transferFrom(from, gateway, amount), then burn(amount), in UniversalGatewayPC.sol:430–434. The fixture models that sequence with an authored token/gateway. It does not validate production fee logic, token peculiarities, routing, node/TSS acceptance or destination execution. A live compatible-deployment test remains required. + +To reproduce: initialize pinned contract dependencies in an isolated e704d5b copy, copy AllowanceReview.t.sol into test/review/, then run: + +```sh +forge test --offline --match-contract AllowanceReviewTest --match-test test_Allowance_ -vv +``` + +Forge 1.5.1-stable, solc 0.8.26, optimizer 833, via IR, Cancun, as in the existing e704d5b validation. No source checkout was changed and no transaction was broadcast. + +## Freshness + +[Remote refs](remote-refs.json) were rechecked with git ls-remote and remain at the recorded pins. The sibling AGW checkout is on old main; this was not mistaken for the active reviewed branch. Notion was not re-exported; its last complete snapshot remains October 3 at 13:23 IST. This report does not certify later page edits or current deployment state. diff --git a/plan/agw/research/sdk-owned-review-2026-10-03/allowance.log b/plan/agw/research/sdk-owned-review-2026-10-03/allowance.log new file mode 100644 index 00000000..afcf549c --- /dev/null +++ b/plan/agw/research/sdk-owned-review-2026-10-03/allowance.log @@ -0,0 +1,42 @@ +Compiling 1 files with Solc 0.8.26 +Solc 0.8.26 finished in 21.31s +Compiler run successful with warnings: +Warning (5667): Unused function parameter. Remove or comment out the variable name to silence this warning. + --> lib/smartsessions/contracts/lib/ConfigLib.sol:77:9: + | +77 | bool useRegistry + | ^^^^^^^^^^^^^^^^ + +Warning (5667): Unused function parameter. Remove or comment out the variable name to silence this warning. + --> lib/smartsessions/contracts/lib/ConfigLib.sol:123:9: + | +123 | bool useRegistry + | ^^^^^^^^^^^^^^^^ + +Warning (5667): Unused function parameter. Remove or comment out the variable name to silence this warning. + --> lib/smartsessions/contracts/lib/ConfigLib.sol:203:9: + | +203 | bool useRegistry + | ^^^^^^^^^^^^^^^^ + +Warning (5667): Unused function parameter. Remove or comment out the variable name to silence this warning. + --> lib/smartsessions/contracts/core/SmartSessionBase.sol:270:9: + | +270 | bool useRegistry + | ^^^^^^^^^^^^^^^^ + +Warning (2018): Function state mutability can be restricted to view + --> src/AGWFactory.sol:352:5: + | +352 | function _authorizeUpgrade(address newImplementation) internal override onlyRole(DEFAULT_ADMIN_ROLE) { + | ^ (Relevant source part starts here and spans across multiple lines). + + +Ran 4 tests for test/review/AllowanceReview.t.sol:AllowanceReviewTest +[PASS] test_Allowance_AgentCannotUseOwnerDoor() (gas: 1381739) +[PASS] test_Allowance_MissingApprovalRevertsAndRollsBackSpend() (gas: 1461500) +[PASS] test_Allowance_OwnerApprovalEnablesPullBurnAndCanBeRemoved() (gas: 1557294) +[PASS] test_Allowance_UniversalRuleCannotApproveThroughAgentDoor() (gas: 1418195) +Suite result: ok. 4 passed; 0 failed; 0 skipped; finished in 8.06ms (5.25ms CPU time) + +Ran 1 test suite in 16.14ms (8.06ms CPU time): 4 tests passed, 0 failed, 0 skipped (4 total tests) diff --git a/plan/agw/research/sdk-owned-review-2026-10-03/jest.log b/plan/agw/research/sdk-owned-review-2026-10-03/jest.log new file mode 100644 index 00000000..e177d77b --- /dev/null +++ b/plan/agw/research/sdk-owned-review-2026-10-03/jest.log @@ -0,0 +1,13 @@ +PASS core packages/core/src/lib/orchestrator/__tests__/context-helpers-tracker.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/send-transaction-progress-hook.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-params.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/errors.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/public-surface.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-native-multicall.spec.ts + +Test Suites: 6 passed, 6 total +Tests: 126 passed, 126 total +Snapshots: 0 total +Time: 6.207 s +Ran all test suites within paths "packages/core/src/lib/orchestrator/__tests__/push-chain-native-multicall.spec.ts", "packages/core/src/lib/orchestrator/__tests__/context-helpers-tracker.spec.ts", "packages/core/src/lib/orchestrator/__tests__/errors.spec.ts", "packages/core/src/lib/orchestrator/__tests__/send-transaction-progress-hook.spec.ts", "packages/core/src/lib/read-state/__tests__/public-surface.spec.ts", "packages/core/src/lib/read-state/__tests__/read-params.spec.ts". +Test results written to: plan/agw/research/sdk-owned-review-2026-10-03/jest-results.json diff --git a/plan/agw/research/sdk-owned-review-2026-10-03/remote-refs.json b/plan/agw/research/sdk-owned-review-2026-10-03/remote-refs.json new file mode 100644 index 00000000..9b0e9692 --- /dev/null +++ b/plan/agw/research/sdk-owned-review-2026-10-03/remote-refs.json @@ -0,0 +1,16 @@ +{ + "checked_at": "2026-10-03T09:30:23.568072+00:00", + "method": "git ls-remote origin with explicit branch refs; no checkout changes", + "agw": { + "pushAgenticWallet_v3": "e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9", + "main": "9ddd95402b9a2dbf494f6ebfdb477e9a0fb1408a" + }, + "core": { + "universalMarketplace_v1": "cb69e0ba101bef1bb4440e54b2c45396be3e92ce" + }, + "gateway": { + "pc20-3rd-iteration": "bcbf7df42e8e6dd11088a43bcc0b056a54ea0a18", + "main": "d02070dc11aeb3a081d5d6363aa0d75d63eb7c1c" + }, + "notion": "No new export in this pass; source-manifest retains 2026-10-03T07:53:10.278902+00:00." +} diff --git a/plan/agw/research/sdk-owned-review-2026-10-03/response.log b/plan/agw/research/sdk-owned-review-2026-10-03/response.log new file mode 100644 index 00000000..58666fb2 --- /dev/null +++ b/plan/agw/research/sdk-owned-review-2026-10-03/response.log @@ -0,0 +1,11 @@ +PASS core packages/core/src/lib/orchestrator/__tests__/gateway-uea-account.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-confirmation-gate.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/response-builder-push-revert.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/track-transaction-guard.spec.ts + +Test Suites: 4 passed, 4 total +Tests: 57 passed, 57 total +Snapshots: 0 total +Time: 4.238 s +Ran all test suites within paths "packages/core/src/lib/orchestrator/__tests__/gateway-uea-account.spec.ts", "packages/core/src/lib/orchestrator/__tests__/response-builder-push-revert.spec.ts", "packages/core/src/lib/orchestrator/__tests__/track-transaction-guard.spec.ts", "packages/core/src/lib/orchestrator/__tests__/outbound-confirmation-gate.spec.ts". +Test results written to: plan/agw/research/sdk-owned-review-2026-10-03/response-results.json diff --git a/plan/agw/research/sdk-owned-review-2026-10-03/test-summary.json b/plan/agw/research/sdk-owned-review-2026-10-03/test-summary.json new file mode 100644 index 00000000..6607df99 --- /dev/null +++ b/plan/agw/research/sdk-owned-review-2026-10-03/test-summary.json @@ -0,0 +1,43 @@ +{ + "review_date": "2026-10-03", + "sdk_production_revision": "167fdc6243ecfe5d97735a6124662c7d2084d126", + "planning_commit": "46f9e669d001624cb8b7a594bfed3a9aafb139f1", + "agw_source_pin": "e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9", + "runs": [ + { + "log": "jest.log", + "command": "node node_modules/jest/bin/jest.js --config packages/core/jest.config.ts --runInBand --runTestsByPath packages/core/src/lib/orchestrator/__tests__/context-helpers-tracker.spec.ts packages/core/src/lib/orchestrator/__tests__/send-transaction-progress-hook.spec.ts packages/core/src/lib/read-state/__tests__/read-params.spec.ts packages/core/src/lib/orchestrator/__tests__/errors.spec.ts packages/core/src/lib/read-state/__tests__/public-surface.spec.ts packages/core/src/lib/orchestrator/__tests__/push-chain-native-multicall.spec.ts", + "suites": 6, + "passed": 126, + "failed": 0, + "success": true, + "duration_seconds": 6.048, + "sha256": "2135a06ef43a05dff8c33e8e359c76bf64075eaabca57171b45fe75c929ee308" + }, + { + "log": "response.log", + "command": "node node_modules/jest/bin/jest.js --config packages/core/jest.config.ts --runInBand --runTestsByPath packages/core/src/lib/orchestrator/__tests__/gateway-uea-account.spec.ts packages/core/src/lib/orchestrator/__tests__/outbound-confirmation-gate.spec.ts packages/core/src/lib/orchestrator/__tests__/response-builder-push-revert.spec.ts packages/core/src/lib/orchestrator/__tests__/track-transaction-guard.spec.ts", + "suites": 4, + "passed": 57, + "failed": 0, + "success": true, + "duration_seconds": 4.191, + "sha256": "71e516304406ec21b9ae1939f1251a589ec1c15230838b6fab6aad7e072cc729" + } + ], + "total_tests": 183, + "passed": 183, + "failed": 0, + "scope": "Existing mock-based SDK unit tests; no AGW implementation or live settlement verified.", + "allowance_experiment": { + "command": "forge test --offline --root --match-contract AllowanceReviewTest --match-test test_Allowance_ -vv", + "passed": 4, + "failed": 0, + "skipped": 0, + "fixture": "AllowanceReview.t.sol", + "fixture_sha256": "06857f3941be26f73981682108e6a95c29caa64b4432156fbb53c2cfb8cc02bd", + "log": "allowance.log", + "log_sha256": "f80c94f78a2d829cd1eb35e2fcae1b75fa9e1fc0569a3370e7023f5d60764451", + "scope": "Real pinned AGW/engine/URP with authored token/gateway transferFrom and burn fixtures; not production gateway or live settlement." + } +} diff --git a/plan/agw/sdk-design-review.md b/plan/agw/sdk-design-review.md index 05780258..2a5ca699 100644 --- a/plan/agw/sdk-design-review.md +++ b/plan/agw/sdk-design-review.md @@ -71,7 +71,7 @@ Do not pass an AGW outbound directly into the current signer-based Route 2 imple ## Compatibility and capability handling -Preserve existing clients that initialize without `agenticWallet`. Specify read-only and `reinitialize` behavior before changing the option types (G17). Do not accidentally let a read-only identity reach a signing path. +Preserve existing clients that initialize without `agenticWallet`. Use the lifecycle choices in the [SDK owned review](sdk-owned-review.md): explicit wallet selection on each `reinitialize`, fresh role/capability checks, and read-only write guards (G17). Do not accidentally let a read-only identity reach a signing path. Add `READ.CHAIN` as required by the spec. Normalize the existing `'web2:https'` input during the compatibility window while exposing the new `'web2'` constant (G16). Review the existing `READ.WEB2` alias as part of that migration. @@ -104,3 +104,7 @@ Standalone AGW can be reviewed and delivered independently. Full marketplace/job Use owner wallet batching for atomic updates. Stored checkpoints are implemented at e704d5b; grant job refs, label mutation and envelope version remain pending. Universal assets[]/maxGasPerCall require a new matched wire ABI. Public Spent remains scalar in the new snapshot; agree per-token returns and expected-total assertions. Empty-assets routing and native-marker resolution need fixtures. Derive expectedCEA from AGW and destination context, commit it in universal terms, expose it in previews and monitor drift. Apply all [integrator obligations](contract-integrator-obligations.md). [Validation evidence](research/validation-e704d5b/README.md) verifies the pinned single-asset source; it does not establish multi-asset or live deployment support. + +Implementation details settled by local review are recorded in the [SDK owned review](sdk-owned-review.md). Existing machinery passed 183 unit tests; new AGW behavior still requires implementation-specific coverage. Include transaction-creating universal reads in the execution-context audit, while keeping management reads non-signing. + +Follow-up: keep NativeRule single-action as specified; reject ambiguous enabled-rule candidates with DUPLICATE_RULE and a hint. Bounded gateway approvals use the existing owner execute path, demonstrated by four local pull/burn-fixture tests. Remaining external decisions are in [external blockers](external-blockers.md). diff --git a/plan/agw/sdk-owned-review.md b/plan/agw/sdk-owned-review.md new file mode 100644 index 00000000..32bf71fc --- /dev/null +++ b/plan/agw/sdk-owned-review.md @@ -0,0 +1,101 @@ +# SDK owned AGW review + +Reviewed October 3, 2026 before sharing team questions. Several integration choices can be settled locally. Their design is recorded below; production SDK implementation and AGW acceptance testing are still outstanding. None of the affected gaps is closed merely because an existing unit test passes. + +Evidence baseline: SDK parent `167fdc6243ecfe5d97735a6124662c7d2084d126`, planning branch `46f9e669d001624cb8b7a594bfed3a9aafb139f1`, October 3 Notion snapshots, and AGW source `e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9`. Contract reads used `git show e704d5b:...`: the sibling checkout is on September main (`9ddd954`), not the reviewed branch. No remote fetch or Notion refresh was performed in this pass. + +## Disposition + +| Gaps | What we can settle ourselves | What remains external | +| --- | --- | --- | +| G03 | Wallet-scoped records and receipt-derived rule IDs | Public helper signature/constants and matching generation context | +| G08 | Checkpoint event reads, count snapshots and current-label event reconstruction | Editable labels/ref ABI, deployment and historical-rule scope | +| G13, G15 | Capability-based creation, committed/pending hashes and partial-failure recovery | No required new factory batch method; exact final artifacts still needed | +| G14 | One owner-wallet transaction for replacement; never sequential fallback | Multi-asset spend/assertion ABI and final-generation regression tests | +| G16 | Public Web2 normalization with unchanged wire identity | Implementation and compatibility checks; no contract change required | +| G17 | Read-only boundaries and explicit wallet selection on reinitialize | Implementation and mocked lifecycle tests | +| G18 | Enabled-rule eligibility, uncached send lookup and on-chain expiry enforcement | Public duplicate ambiguity wording remains part of H4 | +| G19, G22, G23 | ABI-aware encoding, trusted token/CEA context and generation guards | Approval policy, defaults, multi-asset fixtures and SVM capabilities | +| G20 | Dedicated AGW composition, separate identity/gas contexts, response/error/hook adaptation | Live production gateway/node/settlement acceptance; owner allowance mechanism now locally demonstrated | + +G01/G02 deployment, G04 gateway release intent, G05/G09–G12 ecosystem alignment and G07 executor work cannot be closed through SDK code review. G06 binder was already resolved as dropped. G21 native action/array scope and G24 multi-asset spend semantics remain team decisions. + +## Internal decisions for implementation + +### Account context + +Keep connected signer identity, execution wallet and origin as separate values. Derive/list/create owner wallets from the signer identity, never the displayed AGW account. Account status and Push gas checks remain signer-scoped; wallet assets and outbound PC remain AGW-scoped. + +Current `push-chain.ts:297–310` exposes `origin` from `getUOA()` and `account` from `computeUEAOffchain()`. Add an explicit execution context rather than replacing signer derivation throughout the orchestrator. Do not reuse `getAccountStatus` as a wallet capability check. + +### Read only and reinitialization + +For new AGW support, choose the wallet explicitly on each `reinitialize`: an omitted `agenticWallet` produces an ordinary client. An explicit wallet reruns deployment, supported-generation and identity checks, including when the signer or network changes. Do not copy the prior owner/agent role or rule lookup cache. Continue inheriting existing network/RPC/explorer/hook options as today. + +An ordinary read-only client may create a management handle for an arbitrary wallet and call its non-signing reads. Its writes fail before signing. If initialized with an AGW execution context, it remains read-only and must never gain execution authority from an address match. Preserve existing non-AGW behavior. These are selected SDK design choices for the new option, not implemented behavior or additional promises in the source spec. + +Evidence: `push-chain.ts:701–743` creates a dummy signer that rejects signing in read-only mode; `:816–848` creates a fresh client and inherits existing options. Existing integration-style lifecycle suites are excluded from the unit configuration and were not run. Add mocked lifecycle coverage during implementation. + +### Initialization and send eligibility + +Owner identity selects the owner door. Otherwise, initialization requires at least one enabled rule naming the connected Push identity. An enabled but expired rule may establish identity; expiry remains an on-chain send check. A revoked rule does not establish eligibility. This avoids silently changing the spec's enabled-rule lookup into an expiry filter. + +Each send discovers enabled IDs and resolves agent/destination at a consistent block. Zero matches gives the specified `NO_RULES_FOR_CHAIN`; multiple matches fail before signing rather than choosing an arbitrary rule. Use the existing DUPLICATE_RULE code with a descriptive hint and document its send-path use. Never cache send eligibility at initialization or infer rule enablement from retained URP terms alone. + +Pinned engine evidence: `lib/smartsessions/contracts/core/SmartSessionBase.sol:72` enumerates enabled IDs; `:444` tests membership. AGW `src/AGW.sol:935` resolves the agent and `:756–765` removes the engine session on revoke. Enumeration followed by dependent configuration reads does not guarantee one RPC round trip. Group reads by block and retry a bounded number of times if consistency cannot be maintained. + +### Creation and recovery + +Create only deploys/grants. Funding and approvals remain separate. Use the actual signer capability: supported atomic EIP-7702 for native batching, the existing sequential native fallback otherwise, and an external UEA batch where supported. Do not require a new `createWallet` contract entry point. + +Preserve atomicity metadata and every confirmed/pending hash on failures. Re-read the factory index and grant nonce before constructing a retry. If deployment succeeded but grants failed, recover that wallet instead of blindly creating another. IDs come from verified receipts in input order; predictions are not authoritative results. + +Evidence: `orchestrator/internals/push-chain-tx.ts` and the six native-multicall unit tests cover atomic routing, sequential fallback, committed/pending hashes and receipt failure. This resolves routing uncertainty, not AGW-specific batching, nonce races or recovery correctness. + +### Replacement and reads + +An existing-wallet update is one owner `execute` batch containing assert-spend, revoke and grant. No native EIP-7702 capability is required for that wallet-level batch. Current replacement records five checkpoints; a failed transaction rolls all of them back. Compare counts, including same-block changes, rather than treating last block as sufficient evidence. + +Use factory count/prediction views for deployed-wallet enumeration. Include the next predicted undeployed slot shown in the SDK example with `deployed: false` and zero rules, alongside deployed slots; never predict indices beyond the factory's next index. This is the planned interpretation of the public example, not an implemented read. At e704d5b, labels are deployment-event metadata, not stored mutable state. Decode events from the selected factory start block with pagination and reorg handling. Revoked history and new label/ref storage remain external dependencies. + +Evidence: AGWFactory `src/AGWFactory.sol:254–273` permits prediction only through the next index and defines count as deployed wallets. `:133` says labels are emitted and never stored. Current checkpoint and replacement evidence remains in [validation](research/validation-e704d5b/README.md). + +### Web2 public input and wire identity + +Add the specified enumerable `READ.CHAIN` with public `WEB2 = 'web2'`. Normalize both `'web2'` and legacy `'web2:https'` to the existing internal destination `{ chainNamespace: 'web2', chainId: 'https' }`. Keep the wire CAIP-2 `web2:https`; changing the public spelling does not authorize changing the node routing identity. Follow the specified deprecated `CHAIN.WEB2` alias and preserve compatibility for the existing `READ.WEB2` surface and old literal inputs. + +Cover public constants, types, query discrimination, prepared reads, tracking/decoded results and transaction rejection. Do not just rename the enum: `read-state/read-params.ts:198` recognizes only the current alias, and `read-state/destination.ts:18` rejects a joined destination without `:`. Existing tests verify the old spelling, not the new one. + +### Composer, responses and errors + +For pinned EVM universal rules, compose a wallet-originated outbound with empty bytes recipient, AGW revert recipient, a nonzero gas cap and policy-compatible destination multicall. Derive `expectedCEA` from the wallet plus trusted destination deployment. Never insert an unrestricted approval into an agent transaction. The new assets format still needs agreed fixtures before this becomes the final composer. + +Current Route 2 derives CEA from the signer (`route-handlers.ts:666,763`), uses the CEA as recipient for a payload and uses signer UEA for refunds (`:826–854`). It cannot be reused unchanged. `cea-utils.ts:109–120` already queries `getCEAForPushAccount(address)`; adapt with explicit AGW and network/factory context. Its current address cache does not include factory identity, so generation-aware caching requires review. + +Preserve logical AGW `from` on both send response and waited receipt; preserve signer `origin`, hashes and raw transport metadata. Management transaction responses retain their specified owner `from`. Hash/event tracking is reusable infrastructure: `outbound-tracker.ts:17–24` hashes network plus Push transaction hash. It does not establish that an AGW-wrapped transaction is reconstructed correctly. + +The current response builder derives signer/UEA identity (`response-builder.ts:645,740,859`) and reconstructs known UEA calls (`:655–682`). Add explicit wallet decoding/context for live sends and replayed tracking; do not overwrite only the first response. Carry init and per-call hooks through `wait` without duplication. + +Extend the existing structured `PushChainExecutionError` with the specified AGW error. Preserve `gatewayTxHash`, `decodedError` and partial-batch recovery metadata where relevant. Export the base error publicly if callers are expected to use it: it currently exists internally (`internals/errors.ts:40`) but is absent from `packages/core/src/lib/index.ts`. Default decoders also need the matching AGW/URP error ABIs. + +### Transaction creating reads + +`universal.read()` and `executeReads()` submit request transactions; they are not ordinary RPC reads. Route them through the same wallet execution/authorization layer and audit read budget, refund and balance context. `prepareRead` and tracking must remain non-signing. Management `info`, `rules.get/list` and checkpoint reads are separate RPC/log operations. + +Evidence: `push-chain.ts:346–363` invokes read execution; `read-state/read-executor.ts:84` calls the transaction executor; `orchestrator/internals/read-state.ts:23–28` currently derives the default refund from the signer. Neither the balance nor refund context should be changed by globally replacing the signer with the AGW. Native agent batch-read behavior depends on H2; do not silently bypass its single-call restriction. + +## Validation and limits + +Ten existing mock-based unit suites passed: **183 tests, zero failures**. The first group covers native batching, tracking helpers, per-call hooks, structured errors, public read exports and read grammar (126 tests). The second covers gateway/account/CEA helpers, failed Push response handling, tracking guards and outbound confirmation gates (57 tests). + +Commands and suite counts are in [test summary](research/sdk-owned-review-2026-10-03/test-summary.json); [first run](research/sdk-owned-review-2026-10-03/jest.log) and [response run](research/sdk-owned-review-2026-10-03/response.log) retain runner output. No production file changed, no new SDK implementation was tested, no contract suite was rerun and no transaction was broadcast. These results are evidence for existing behavior, not a complete audit or future AGW acceptance. + +## What still belongs in the team questions + +Keep H1 approval safety, H2 native-array scope, H3 defaults, and H4 helper context/history/per-token spend. Keep Z1 matching artifacts and Z3 compatible deployment. Z2 allowance setup is resolved locally; Z4 is a release note covered by generation compatibility. See the [external blocker register](external-blockers.md). Creation routing and partial failure, read-only/reinitialize semantics, response adaptation, Web2 normalization and checkpoint reconstruction are SDK tasks; do not ask the teams to design these internals. + +Independent module work can begin from the recorded choices; finalize affected types/codecs after the matching contract/API decisions are available, with targeted tests for the new behavior. Refresh sources again before sharing the drafts. Implementation is still a separate phase. + +## Follow-up closure + +Four new [allowance experiments](research/sdk-owned-review-2026-10-03/README.md) demonstrate bounded owner setup/removal and atomic failure behavior with a pulling/burning fixture. No new AGW allowance API is needed. Destination approval can use the existing owner execution client; only the agent approval policy needs a product decision. Keep NativeRule single-action as specified; ask only about native arrays. Remote AGW/core/gateway refs were rechecked unchanged; Notion was not refreshed. The remaining standalone external areas are enumerated in [external blockers](external-blockers.md). From 07d8adc27990cf4441d7fafc7d83a5454b861fa2 Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Sat, 3 Oct 2026 19:35:31 +0530 Subject: [PATCH 03/68] feat(agw): pinned e704d5b contract adapter, capability registry and rule codecs Foundation for client.agentic (plan/agw steps 1, 2, 4, 6): - Typed ABIs generated from the reviewed e704d5b evidence (sha256 in headers) and a single contract adapter for execute / executeAsAgent / grant / revoke / assertSpent encoding and event decoding. - Generation registry with on-chain wiring verification. It ships EMPTY: no compatible deployment is verified on any network (A07), so every AGW call fails with GENERATION_UNSUPPORTED before signing. - Capability flags that gate target-only features (multi-asset universal rules A05, SVM rules, grant ref / setLabel A07, rule history A06, compileCard A08) with typed CAPABILITY_UNAVAILABLE errors. - Pure ID helpers (rulesId, actionId, configId, deriveWallet), native rule codec with ABI-layout argument offsets, the single provisional A03 defaults table and the A01/A02 policy boundary. Universal rules are validated then refused; the historical single-asset terms stay internal and versioned. - AgenticError / AgenticRevertError (extends PushChainExecutionError) and AGW/URP/factory/engine revert decoding, including PolicyCheckReverted. --- packages/core/scripts/agw-local/gen-abi.mjs | 49 + .../core/src/lib/agentic/agentic.types.ts | 185 ++ packages/core/src/lib/agentic/capabilities.ts | 84 + packages/core/src/lib/agentic/chain.ts | 13 + .../core/src/lib/agentic/codec/abi-layout.ts | 131 ++ .../core/src/lib/agentic/codec/defaults.ts | 40 + .../codec/historical/e704d5b-universal.ts | 64 + packages/core/src/lib/agentic/codec/ids.ts | 97 + packages/core/src/lib/agentic/codec/native.ts | 233 ++ packages/core/src/lib/agentic/codec/policy.ts | 52 + packages/core/src/lib/agentic/codec/rules.ts | 136 ++ .../core/src/lib/agentic/codec/selectors.ts | 77 + .../core/src/lib/agentic/codec/session.ts | 95 + .../core/src/lib/agentic/codec/universal.ts | 97 + packages/core/src/lib/agentic/constants.ts | 17 + .../contracts/abi/e704d5b/agent-validator.ts | 145 ++ .../contracts/abi/e704d5b/agw-factory.ts | 1104 +++++++++ .../lib/agentic/contracts/abi/e704d5b/agw.ts | 1528 ++++++++++++ .../agentic/contracts/abi/e704d5b/index.ts | 8 + .../contracts/abi/e704d5b/smart-session.ts | 1961 ++++++++++++++++ .../abi/e704d5b/universal-rules-policy.ts | 2065 +++++++++++++++++ .../core/src/lib/agentic/contracts/e704d5b.ts | 294 +++ .../core/src/lib/agentic/contracts/reader.ts | 42 + packages/core/src/lib/agentic/deployments.ts | 233 ++ packages/core/src/lib/agentic/errors.ts | 123 + packages/core/src/lib/agentic/revert.ts | 100 + 26 files changed, 8973 insertions(+) create mode 100644 packages/core/scripts/agw-local/gen-abi.mjs create mode 100644 packages/core/src/lib/agentic/agentic.types.ts create mode 100644 packages/core/src/lib/agentic/capabilities.ts create mode 100644 packages/core/src/lib/agentic/chain.ts create mode 100644 packages/core/src/lib/agentic/codec/abi-layout.ts create mode 100644 packages/core/src/lib/agentic/codec/defaults.ts create mode 100644 packages/core/src/lib/agentic/codec/historical/e704d5b-universal.ts create mode 100644 packages/core/src/lib/agentic/codec/ids.ts create mode 100644 packages/core/src/lib/agentic/codec/native.ts create mode 100644 packages/core/src/lib/agentic/codec/policy.ts create mode 100644 packages/core/src/lib/agentic/codec/rules.ts create mode 100644 packages/core/src/lib/agentic/codec/selectors.ts create mode 100644 packages/core/src/lib/agentic/codec/session.ts create mode 100644 packages/core/src/lib/agentic/codec/universal.ts create mode 100644 packages/core/src/lib/agentic/constants.ts create mode 100644 packages/core/src/lib/agentic/contracts/abi/e704d5b/agent-validator.ts create mode 100644 packages/core/src/lib/agentic/contracts/abi/e704d5b/agw-factory.ts create mode 100644 packages/core/src/lib/agentic/contracts/abi/e704d5b/agw.ts create mode 100644 packages/core/src/lib/agentic/contracts/abi/e704d5b/index.ts create mode 100644 packages/core/src/lib/agentic/contracts/abi/e704d5b/smart-session.ts create mode 100644 packages/core/src/lib/agentic/contracts/abi/e704d5b/universal-rules-policy.ts create mode 100644 packages/core/src/lib/agentic/contracts/e704d5b.ts create mode 100644 packages/core/src/lib/agentic/contracts/reader.ts create mode 100644 packages/core/src/lib/agentic/deployments.ts create mode 100644 packages/core/src/lib/agentic/errors.ts create mode 100644 packages/core/src/lib/agentic/revert.ts diff --git a/packages/core/scripts/agw-local/gen-abi.mjs b/packages/core/scripts/agw-local/gen-abi.mjs new file mode 100644 index 00000000..e51f6866 --- /dev/null +++ b/packages/core/scripts/agw-local/gen-abi.mjs @@ -0,0 +1,49 @@ +#!/usr/bin/env node +// Regenerates packages/core/src/lib/agentic/contracts/abi/e704d5b/*.ts from the +// pinned ABI evidence in plan/agw/research/validation-e704d5b/abi/. The source +// JSON is the reviewed artifact set; this script only re-serialises it as +// `as const` TypeScript so viem can infer types. Run from the repo root: +// node packages/core/scripts/agw-local/gen-abi.mjs +import { createHash } from 'node:crypto'; +import { readFileSync, writeFileSync, mkdirSync } from 'node:fs'; +import { dirname, join, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const here = dirname(fileURLToPath(import.meta.url)); +const repo = resolve(here, '../../../..'); +const src = join(repo, 'plan/agw/research/validation-e704d5b/abi'); +const dst = join(repo, 'packages/core/src/lib/agentic/contracts/abi/e704d5b'); +const PIN = 'e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9'; + +const files = { + AGW: ['AGW_ABI', 'agw.ts'], + AGWFactory: ['AGW_FACTORY_ABI', 'agw-factory.ts'], + UniversalRulesPolicy: ['UNIVERSAL_RULES_POLICY_ABI', 'universal-rules-policy.ts'], + SmartSession: ['SMART_SESSION_ABI', 'smart-session.ts'], + AgentValidator: ['AGENT_VALIDATOR_ABI', 'agent-validator.ts'], +}; + +mkdirSync(dst, { recursive: true }); +const exports = []; +for (const [name, [constName, file]] of Object.entries(files)) { + const raw = readFileSync(join(src, `${name}.json`)); + const sha = createHash('sha256').update(raw).digest('hex'); + const abi = JSON.parse(raw.toString()).filter((e) => e.type !== 'constructor'); + const body = + `// GENERATED by packages/core/scripts/agw-local/gen-abi.mjs — do not edit.\n` + + `// Source: plan/agw/research/validation-e704d5b/abi/${name}.json\n` + + `// push-agentic-wallets@${PIN}\n` + + `// sha256(${name}.json) = ${sha}\n` + + `export const ${constName} = ${JSON.stringify(abi, null, 2)} as const;\n`; + writeFileSync(join(dst, file), body); + exports.push(`export { ${constName} } from './${file.replace(/\.ts$/, '')}';`); +} +writeFileSync( + join(dst, 'index.ts'), + `// GENERATED by packages/core/scripts/agw-local/gen-abi.mjs — do not edit.\n` + + `// Review generation e704d5b: no verified deployment exists for this ABI set.\n` + + `export const E704D5B_SOURCE_COMMIT = '${PIN}' as const;\n` + + exports.join('\n') + + '\n' +); +console.log(`wrote ${Object.keys(files).length} ABI modules to ${dst}`); diff --git a/packages/core/src/lib/agentic/agentic.types.ts b/packages/core/src/lib/agentic/agentic.types.ts new file mode 100644 index 00000000..0b93a1da --- /dev/null +++ b/packages/core/src/lib/agentic/agentic.types.ts @@ -0,0 +1,185 @@ +/** + * Public AGW types — AGW SDK page section 3 (Notion export 2026-10-03 13:23 IST). + * + * Provisional items are tagged with the plan assumption that must close before + * they are final (plan/agw/implementation-plan.md, A01–A08). + */ +import type { MoveableToken } from '../constants/tokens'; +import type { UniversalTxResponse } from '../orchestrator/orchestrator.types'; +import type { ProgressEvent } from '../progress-hook/progress-hook.types'; + +export type AgenticAddress = `0x${string}`; +export type AgenticHex = `0x${string}`; +export type ForeignChainNamespace = `eip155:${string}` | `solana:${string}`; +export type AgenticProgressHook = (event: ProgressEvent) => void; + +/** '0x617ba037' or 'supply(address,uint256,address,uint16)'. */ +export type Selector = AgenticHex | `${string}(${string})`; + +export interface NativeRule { + /** Push address: an EOA, or the UEA of an external key. Never the owner. */ + agent: AgenticAddress; + /** Emitted in RulesGranted when the generation supports it (A07). */ + ref?: AgenticHex; + /** Omitted = the connected Push chain. */ + chainNamespace?: never; + target: AgenticAddress; + selector: Selector | 'value-only'; + /** Unix seconds. */ + validUntil: number; + /** Default 0 (no native value) — provisional, A03. */ + maxValuePerCall?: bigint; + /** Default 0 (no native value) — provisional, A03. */ + maxValueTotal?: bigint; + /** Default 0 (unlimited calls until expiry) — provisional, A03. */ + maxCalls?: number; + /** `arg` is the argument index in the selector signature. */ + pins?: { arg: number; expected: AgenticHex | AgenticAddress | bigint }[]; + /** `maxTotal` default uint256 max (unlimited total) — provisional, A03. */ + amount?: { arg: number; maxPerCall: bigint; maxTotal?: bigint }; +} + +export interface AssetCap { + /** The destination chain's token (MOVEABLE constant) or native marker. */ + token: MoveableToken | AgenticAddress; + maxPerCall: bigint; + /** Omitted = 0 = unlimited in the proposed multi-asset ABI — provisional, A03/A05. */ + maxTotal?: bigint; +} + +export interface AllowedCall { + target: AgenticAddress; + selector: Selector; + /** Argument index whose address must be the wallet's destination account. */ + beneficiary?: number; + /** Default 0 — provisional, A03. */ + maxValue?: bigint; +} + +export interface UniversalRule { + agent: AgenticAddress; + ref?: AgenticHex; + chainNamespace: ForeignChainNamespace; + assets: AssetCap[]; + /** PC (wei) per outbound for the destination leg. */ + maxGasPerCall: bigint; + validUntil: number; + /** 1..32, all on chainNamespace. */ + allowedCalls: AllowedCall[]; +} + +export type Rule = NativeRule | UniversalRule; + +/** + * Spend counters for a rule. PROVISIONAL (A05, Harsh H4.2): the universal + * scalar `amountSpent` cannot represent multi-asset rules; the per-token + * shape is pending. + */ +export type Spent = + | { kind: 'universal'; amountSpent: bigint } + | { kind: 'native'; valueSpent: bigint; amountSpent: bigint; callsUsed: number }; + +export interface RulesRecord { + rulesId: AgenticHex; + enabled: boolean; + chainNamespace: string; + agent: AgenticAddress; + validUntil: number; + ref: AgenticHex; + rule: Rule; + spent: Spent; +} + +export interface CreateOptions { + rules: Rule[]; + progressHook?: AgenticProgressHook; +} + +export interface CreateResult { + wallet: AgenticAddress; + index: number; + rulesIds: AgenticHex[]; + tx: UniversalTxResponse; +} + +export interface WalletSummary { + address: AgenticAddress; + index: number; + label: string; + deployed: boolean; + rulesCount: number; +} + +export interface WalletInfo { + address: AgenticAddress; + label: string; + index: number; + owner: AgenticAddress; + deployed: boolean; + rulesCount: number; +} + +export type CheckpointKind = 'OWNER_ACTION' | 'RULES_GRANTED' | 'RULES_REVOKED'; + +export interface Checkpoint { + seq: number; + kind: CheckpointKind; + ref: AgenticHex; + blockNumber: bigint; + txHash: AgenticHex; +} + +export interface AgenticWallet { + address: AgenticAddress; + info(): Promise; + owner(): Promise<{ owner: AgenticAddress }>; + /** PROPOSED (page 1 item 10); capability-gated, A07. */ + setLabel( + label: string, + opts?: { progressHook?: AgenticProgressHook } + ): Promise; + checkpoints(opts?: { sinceBlock?: bigint }): Promise<{ checkpoints: Checkpoint[] }>; + rules: { + list(): Promise<{ rules: RulesRecord[] }>; + get(rulesId: AgenticHex): Promise; + add( + rules: Rule[], + opts?: { progressHook?: AgenticProgressHook } + ): Promise<{ rulesIds: AgenticHex[]; tx: UniversalTxResponse }>; + update(params: { + rules: { rulesId: AgenticHex; rule: Rule }[]; + progressHook?: AgenticProgressHook; + }): Promise<{ rules: { rulesId: AgenticHex; replaced: AgenticHex }[]; tx: UniversalTxResponse }>; + revoke( + rulesIds: AgenticHex[], + opts?: { progressHook?: AgenticProgressHook } + ): Promise; + revoke(params: { all: true; progressHook?: AgenticProgressHook }): Promise; + }; +} + +export interface AgenticNamespace { + derive(opts?: { index?: number }): Promise<{ address: AgenticAddress; index: number; deployed: boolean }>; + create(label: string, options: CreateOptions): Promise; + list(): Promise<{ wallets: WalletSummary[] }>; + wallet(address: AgenticAddress): AgenticWallet; +} + +/** Door the client uses in agenticWallet mode. */ +export type AgenticDoor = 'owner' | 'agent'; + +/** AGW metadata attached to responses produced by an agentic client. */ +export interface AgenticTxMetadata { + wallet: AgenticAddress; + door: AgenticDoor; + /** Rule selected for an agent-door send. */ + rulesId?: AgenticHex; + /** Destination CAIP-2 chain for the selected rule / outbound. */ + chainNamespace?: string; + /** The wallet's destination account (CEA) for an outbound. */ + destinationAccount?: AgenticAddress; + /** Account the signer's transaction actually called (the wallet). */ + rawTo: string; + /** Calldata the signer's transaction actually carried. */ + rawData: string; +} diff --git a/packages/core/src/lib/agentic/capabilities.ts b/packages/core/src/lib/agentic/capabilities.ts new file mode 100644 index 00000000..4d31236e --- /dev/null +++ b/packages/core/src/lib/agentic/capabilities.ts @@ -0,0 +1,84 @@ +import { capabilityUnavailable } from './errors'; + +/** + * Internal capability flags for an AGW contract generation. A method whose + * capability is absent fails before any signature. Each unresolved target + * feature names the plan assumption (A01–A08, plan/agw/implementation-plan.md) + * or artifact that must close before it can be advertised. + */ +export enum AgenticCapability { + /** Factory derive/list/deploy and wallet owner/info reads. */ + WALLET_READS = 'walletReads', + /** Active (enabled) rule enumeration and native-rule decoding. */ + ACTIVE_RULE_READS = 'activeRuleReads', + /** Owner door: execute(mode, executionCalldata). */ + OWNER_EXECUTE = 'ownerExecute', + /** Agent door: executeAsAgent(rulesId, mode, executionCalldata). */ + AGENT_EXECUTE = 'agentExecute', + /** Native (Push-chain) rule grants with NativeTerms encoding. */ + NATIVE_RULES = 'nativeRules', + /** Exact-equality native spend assertion used by rules.update. */ + ASSERT_SPENT_NATIVE = 'assertSpentNative', + /** checkpointCount + Checkpointed events. */ + CHECKPOINTS = 'checkpoints', + /** Agent-door EVM outbound composition against this generation's single-asset terms. */ + UNIVERSAL_EVM_OUTBOUND = 'universalEvmOutbound', + /** Target UniversalRule (assets[] / maxGasPerCall) encode/decode. A05/A07. */ + UNIVERSAL_EVM_RULES = 'universalEvmRules', + /** Per-token expected-spend assertion for universal replacement. A05. */ + ASSERT_SPENT_UNIVERSAL_MULTI = 'assertSpentUniversalMulti', + /** SVM destination rulebook through the public Rule type. A05/A07, Harsh H4.4. */ + UNIVERSAL_SVM_RULES = 'universalSvmRules', + /** Grant reference emitted in RulesGranted. A07. */ + GRANT_REF = 'grantRef', + /** Editable wallet label (setLabel / LabelSet). A07. */ + SET_LABEL = 'setLabel', + /** Revoked-rule history in rules.list/get. A06. */ + RULE_HISTORY = 'ruleHistory', + /** Canonical card compiler. A08. */ + COMPILE_CARD = 'compileCard', +} + +/** Why each target capability is unavailable when a generation lacks it. */ +export const CAPABILITY_DEPENDENCY: Record = { + [AgenticCapability.WALLET_READS]: 'no verified AGW deployment for this network (A07)', + [AgenticCapability.ACTIVE_RULE_READS]: 'no verified AGW deployment for this network (A07)', + [AgenticCapability.OWNER_EXECUTE]: 'no verified AGW deployment for this network (A07)', + [AgenticCapability.AGENT_EXECUTE]: 'no verified AGW deployment for this network (A07)', + [AgenticCapability.NATIVE_RULES]: 'no verified AGW deployment for this network (A07)', + [AgenticCapability.ASSERT_SPENT_NATIVE]: 'no verified AGW deployment for this network (A07)', + [AgenticCapability.CHECKPOINTS]: 'no verified AGW deployment for this network (A07)', + [AgenticCapability.UNIVERSAL_EVM_OUTBOUND]: + 'the selected generation has no verified multi-asset outbound token resolution (A05/A07)', + [AgenticCapability.UNIVERSAL_EVM_RULES]: + 'the assets[]/maxGasPerCall wire format has no matching contract artifacts or vectors (A05/A07)', + [AgenticCapability.ASSERT_SPENT_UNIVERSAL_MULTI]: + 'per-token expected-spend assertion ABI is not delivered (A05)', + [AgenticCapability.UNIVERSAL_SVM_RULES]: + 'SVM destination rule shape and capability are unconfirmed (A05/A07, H4.4)', + [AgenticCapability.GRANT_REF]: + 'the selected generation has no grant reference parameter/event (A07)', + [AgenticCapability.SET_LABEL]: + 'the selected generation has no editable label (A07; labels are deploy-time only)', + [AgenticCapability.RULE_HISTORY]: + 'revoked-rule history scope and reliable metadata are unresolved (A06)', + [AgenticCapability.COMPILE_CARD]: + 'canonical card schema, encoding and shared vectors are not agreed (A08)', +}; + +export function hasCapability( + capabilities: ReadonlySet, + capability: AgenticCapability +): boolean { + return capabilities.has(capability); +} + +/** Throws CAPABILITY_UNAVAILABLE (before signing) when the flag is absent. */ +export function requireCapability( + capabilities: ReadonlySet | undefined, + capability: AgenticCapability +): void { + if (!capabilities || !capabilities.has(capability)) { + throw capabilityUnavailable(capability, CAPABILITY_DEPENDENCY[capability]); + } +} diff --git a/packages/core/src/lib/agentic/chain.ts b/packages/core/src/lib/agentic/chain.ts new file mode 100644 index 00000000..cac1f6e2 --- /dev/null +++ b/packages/core/src/lib/agentic/chain.ts @@ -0,0 +1,13 @@ +import { CHAIN_INFO } from '../constants/chain'; +import { CHAIN, PUSH_NETWORK } from '../constants/enums'; + +/** 'eip155:' of the Push chain for a network — the native rule chain. */ +export function pushChainNamespaceFor(network: PUSH_NETWORK): string { + const chain = + network === PUSH_NETWORK.MAINNET + ? CHAIN.PUSH_MAINNET + : network === PUSH_NETWORK.TESTNET_DONUT || network === PUSH_NETWORK.TESTNET + ? CHAIN.PUSH_TESTNET_DONUT + : CHAIN.PUSH_LOCALNET; + return `eip155:${CHAIN_INFO[chain].chainId}`; +} diff --git a/packages/core/src/lib/agentic/codec/abi-layout.ts b/packages/core/src/lib/agentic/codec/abi-layout.ts new file mode 100644 index 00000000..862ebfc1 --- /dev/null +++ b/packages/core/src/lib/agentic/codec/abi-layout.ts @@ -0,0 +1,131 @@ +import { + encodeAbiParameters, + isAddress, + isHex, + type AbiParameter, +} from 'viem'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; +import type { AgenticHex } from '../agentic.types'; + +/** + * ABI head layout for argument-position terms (native pins/amount, universal + * beneficiary). Contracts take ABSOLUTE byte offsets into calldata with the + * 4-byte selector included and read exactly one 32-byte word there, so only a + * single-word static elementary argument can be addressed. Preceding + * arguments may be dynamic (one head word: the offset pointer) or static + * tuples / fixed arrays (several head words); both are accounted for here. + */ + +const UINT16_MAX = 0xffff; + +function components(p: AbiParameter): readonly AbiParameter[] { + return (p as { components?: readonly AbiParameter[] }).components ?? []; +} + +/** Parse a trailing fixed/dynamic array suffix: 'uint256[3]' → base 'uint256', length 3. */ +function arraySuffix(type: string): { base: string; length: number | null } | null { + const m = /^(.*)\[(\d*)\]$/.exec(type); + if (!m) return null; + return { base: m[1], length: m[2] === '' ? null : Number(m[2]) }; +} + +export function isDynamic(p: AbiParameter): boolean { + const arr = arraySuffix(p.type); + if (arr) { + if (arr.length === null) return true; + return isDynamic({ ...p, type: arr.base } as AbiParameter); + } + if (p.type === 'bytes' || p.type === 'string') return true; + if (p.type === 'tuple') return components(p).some(isDynamic); + return false; +} + +/** Bytes this parameter occupies in the head of an encoding. */ +export function headSize(p: AbiParameter): number { + if (isDynamic(p)) return 32; + const arr = arraySuffix(p.type); + if (arr && arr.length !== null) { + return arr.length * headSize({ ...p, type: arr.base } as AbiParameter); + } + if (p.type === 'tuple') { + return components(p).reduce((sum, c) => sum + headSize(c), 0); + } + return 32; +} + +const ELEMENTARY = /^(address|bool|u?int(8|16|24|32|40|48|56|64|72|80|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256)?|bytes([1-9]|[12][0-9]|3[0-2]))$/; + +export function isSingleWordStatic(p: AbiParameter): boolean { + return ELEMENTARY.test(p.type); +} + +/** + * Absolute calldata byte offset (selector included) of argument `arg`. + * Rejects out-of-range indexes and any argument that is not one static word. + */ +export function argumentOffset( + inputs: readonly AbiParameter[] | undefined, + arg: number, + what: string +): number { + if (!inputs) { + throw invalid( + `${what} needs the function signature (e.g. 'supply(address,uint256,address,uint16)'), not a bare 4-byte selector` + ); + } + if (!Number.isInteger(arg) || arg < 0 || arg >= inputs.length) { + throw invalid(`${what} argument index ${arg} is out of range (0..${inputs.length - 1})`); + } + const target = inputs[arg]; + if (!isSingleWordStatic(target)) { + throw invalid( + `${what} argument ${arg} has type ${target.type}; only single-word static arguments can be pinned` + ); + } + let offset = 4; + for (let i = 0; i < arg; i++) offset += headSize(inputs[i]); + if (offset + 32 > UINT16_MAX) { + throw invalid(`${what} argument ${arg} lies beyond the uint16 offset range`); + } + return offset; +} + +/** Encode a pin's expected value as the exact 32-byte calldata word. */ +export function encodeArgWord( + param: AbiParameter, + expected: AgenticHex | bigint | string | boolean, + what: string +): AgenticHex { + try { + if (param.type === 'address') { + if (typeof expected !== 'string' || !isAddress(expected, { strict: false })) { + throw new Error('expected an address'); + } + } else if (param.type.startsWith('bytes')) { + if (typeof expected !== 'string' || !isHex(expected)) throw new Error('expected hex'); + } + return encodeAbiParameters([param], [expected]) as AgenticHex; + } catch (cause) { + throw invalid( + `${what} expected value does not encode as ${param.type}: ${ + cause instanceof Error ? cause.message : String(cause) + }`, + cause + ); + } +} + +/** Head-word index for a decoded absolute offset. Exact only for all-single-word heads. */ +export function offsetToHeadWord(offset: number): number { + if (offset < 4 || (offset - 4) % 32 !== 0) { + throw new AgenticError( + AGENTIC_ERROR_CODE.RULE_READ_FAILED, + `stored argument offset ${offset} is not word-aligned after the selector` + ); + } + return (offset - 4) / 32; +} + +function invalid(message: string, cause?: unknown): AgenticError { + return new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, message, { cause }); +} diff --git a/packages/core/src/lib/agentic/codec/defaults.ts b/packages/core/src/lib/agentic/codec/defaults.ts new file mode 100644 index 00000000..4a1054fa --- /dev/null +++ b/packages/core/src/lib/agentic/codec/defaults.ts @@ -0,0 +1,40 @@ +/** + * THE single home for omitted-limit defaults. PROVISIONAL — assumption A03 + * (Harsh H3, plan/agw/questions-harsh.md). Nothing else in the SDK may invent + * a fallback for these fields; change a row here once the decision lands. + * + * Explicit zero always stays zero. In the native policy a zero value/amount + * cap forbids positive value/amount, while maxCalls = 0 means unlimited. + */ +export const UINT256_MAX = BigInt(2) ** BigInt(256) - BigInt(1); + +export interface DefaultRow { + value: bigint; + meaning: string; + source: 'A03'; +} + +export const AGENTIC_DEFAULTS = { + native: { + maxValuePerCall: { value: BigInt(0), meaning: 'no native value transfer', source: 'A03' }, + maxValueTotal: { value: BigInt(0), meaning: 'no native value transfer', source: 'A03' }, + amountMaxTotal: { value: UINT256_MAX, meaning: 'unlimited metered total', source: 'A03' }, + maxCalls: { value: BigInt(0), meaning: 'unlimited calls until expiry', source: 'A03' }, + }, + universal: { + assetMaxTotal: { + value: BigInt(0), + meaning: 'unlimited total in the proposed multi-asset ABI', + source: 'A03', + }, + allowedCallMaxValue: { + value: BigInt(0), + meaning: 'no native value attached to the destination call', + source: 'A03', + }, + }, +} as const satisfies Record>; + +export function withDefault(value: bigint | undefined, row: DefaultRow): bigint { + return value === undefined ? row.value : value; +} diff --git a/packages/core/src/lib/agentic/codec/historical/e704d5b-universal.ts b/packages/core/src/lib/agentic/codec/historical/e704d5b-universal.ts new file mode 100644 index 00000000..48f1a6ec --- /dev/null +++ b/packages/core/src/lib/agentic/codec/historical/e704d5b-universal.ts @@ -0,0 +1,64 @@ +import { + decodeAbiParameters, + encodeAbiParameters, + type AbiParameter, + type Address, + type Hex, +} from 'viem'; + +/** + * HISTORICAL, INTERNAL-ONLY single-asset UniversalTerms codec for the reviewed + * e704d5b generation (Types.sol:217-225). It operates on wire terms, never on + * the public `UniversalRule` (assets[]), and is not exported from the package. + * It exists so the local contract harness and the agent-door outbound composer + * can be exercised against real pinned contracts. Do not route the advertised + * public API through it (A05). + */ +export interface UniversalTermsE704d5b { + validUntil: number; + expectedCEA: Address; + asset: Address; + maxAmountPerCall: bigint; + /** type(uint256).max = unlimited at e704d5b (differs from the proposed 0-unlimited). */ + maxAmountTotal: bigint; + maxPCPerCall: bigint; + allowedCalls: readonly { + target: Address; + selector: Hex; + beneficiaryOffset: number; + hasBeneficiary: boolean; + maxValue: bigint; + }[]; +} + +export const UNIVERSAL_TERMS_E704D5B_PARAM: AbiParameter = { + type: 'tuple', + components: [ + { name: 'validUntil', type: 'uint48' }, + { name: 'expectedCEA', type: 'address' }, + { name: 'asset', type: 'address' }, + { name: 'maxAmountPerCall', type: 'uint256' }, + { name: 'maxAmountTotal', type: 'uint256' }, + { name: 'maxPCPerCall', type: 'uint256' }, + { + name: 'allowedCalls', + type: 'tuple[]', + components: [ + { name: 'target', type: 'address' }, + { name: 'selector', type: 'bytes4' }, + { name: 'beneficiaryOffset', type: 'uint16' }, + { name: 'hasBeneficiary', type: 'bool' }, + { name: 'maxValue', type: 'uint256' }, + ], + }, + ], +}; + +export function encodeUniversalTermsE704d5b(terms: UniversalTermsE704d5b): Hex { + return encodeAbiParameters([UNIVERSAL_TERMS_E704D5B_PARAM], [terms]); +} + +export function decodeUniversalTermsE704d5b(body: Hex): UniversalTermsE704d5b { + const [terms] = decodeAbiParameters([UNIVERSAL_TERMS_E704D5B_PARAM], body); + return terms as unknown as UniversalTermsE704d5b; +} diff --git a/packages/core/src/lib/agentic/codec/ids.ts b/packages/core/src/lib/agentic/codec/ids.ts new file mode 100644 index 00000000..c24bbf16 --- /dev/null +++ b/packages/core/src/lib/agentic/codec/ids.ts @@ -0,0 +1,97 @@ +import { + concat, + encodeAbiParameters, + encodePacked, + getAddress, + getContractAddress, + keccak256, + numberToHex, + type Address, + type Hex, +} from 'viem'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; + +/** + * Pure identity helpers mirroring the pinned AGW generation (e704d5b): + * smartsessions IdLib.toActionId / toConfigId / toPermissionId and + * AGWFactory._predict (OZ Clones immutable-args CREATE2). + * Every input that changes the result is explicit — validator, factory and + * implementation are generation context (provisional public signature A04). + */ + +/** keccak256(abi.encodePacked(address target, bytes4 selector)). */ +export function actionId(target: Address, selector: Hex): Hex { + return keccak256(encodePacked(['address', 'bytes4'], [target, selector])); +} + +/** keccak256(abi.encodePacked(wallet, keccak256(abi.encodePacked(rulesId, actionId)))). */ +export function configId(wallet: Address, rulesId: Hex, action: Hex): Hex { + const inner = keccak256(encodePacked(['bytes32', 'bytes32'], [rulesId, action])); + return keccak256(encodePacked(['address', 'bytes32'], [wallet, inner])); +} + +/** sessionValidatorInitData for the agent validator: abi.encode(address agent). */ +export function agentConfig(agent: Address): Hex { + return encodeAbiParameters([{ type: 'address' }], [agent]); +} + +/** + * The rules ID a grant produces: + * keccak256(abi.encode(validator, bytes abi.encode(agent), bytes32(grantNonce))). + * Chain is NOT part of the hash; records are keyed by wallet + rulesId. + */ +export function rulesId(ctx: { + validator: Address; + agent: Address; + grantNonce: bigint; +}): Hex { + if (ctx.grantNonce < BigInt(0) || ctx.grantNonce >= BigInt(2) ** BigInt(64)) { + throw new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, 'grantNonce must fit uint64'); + } + return keccak256( + encodeAbiParameters( + [{ type: 'address' }, { type: 'bytes' }, { type: 'bytes32' }], + [ctx.validator, agentConfig(ctx.agent), numberToHex(ctx.grantNonce, { size: 32 })] + ) + ); +} + +const UINT96_MAX = BigInt(2) ** BigInt(96) - BigInt(1); + +/** + * Counterfactual wallet address: CREATE2 by the factory proxy of an OZ clone + * of `walletImplementation` with immutable args (owner ‖ factory), salt + * keccak256(abi.encode(owner, uint96 index)). + */ +export function deriveWallet(ctx: { + factory: Address; + walletImplementation: Address; + owner: Address; + index: bigint | number; +}): Address { + const index = BigInt(ctx.index); + if (index < BigInt(0) || index > UINT96_MAX) { + throw new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, 'wallet index must fit uint96'); + } + const salt = keccak256( + encodeAbiParameters([{ type: 'address' }, { type: 'uint96' }], [ctx.owner, index]) + ); + const args = encodePacked(['address', 'address'], [ctx.owner, ctx.factory]); + const argsLength = (args.length - 2) / 2; + const initCode = concat([ + '0x61', + numberToHex(argsLength + 0x2d, { size: 2 }), + '0x3d81600a3d39f3363d3d373d3d3d363d73', + ctx.walletImplementation, + '0x5af43d82803e903d91602b57fd5bf3', + args, + ]); + return getAddress( + getContractAddress({ + opcode: 'CREATE2', + from: ctx.factory, + salt, + bytecodeHash: keccak256(initCode), + }) + ); +} diff --git a/packages/core/src/lib/agentic/codec/native.ts b/packages/core/src/lib/agentic/codec/native.ts new file mode 100644 index 00000000..b357418e --- /dev/null +++ b/packages/core/src/lib/agentic/codec/native.ts @@ -0,0 +1,233 @@ +import { + decodeAbiParameters, + encodeAbiParameters, + getAddress, + isAddress, + type AbiParameter, + type Address, + type Hex, +} from 'viem'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; +import type { AgenticHex, NativeRule } from '../agentic.types'; +import { argumentOffset, encodeArgWord, offsetToHeadWord } from './abi-layout'; +import { AGENTIC_DEFAULTS, UINT256_MAX, withDefault } from './defaults'; +import { APPROVAL_SELECTORS } from './policy'; +import { parseSelector, VALUE_ONLY_SELECTOR, type ParsedSelector } from './selectors'; + +/** URP native limits at e704d5b (Types.sol MAX_PINS, AGW MAX_NATIVE_ACTIONS). */ +export const MAX_PINS = 8; +const UINT32_MAX = 2 ** 32 - 1; +const UINT48_MAX = 2 ** 48 - 1; + +/** NativeTerms (Types.sol:354-363 at e704d5b). */ +export interface NativeTermsWire { + validUntil: number; + target: Address; + selector: Hex; + maxValuePerCall: bigint; + maxValueTotal: bigint; + amount: { enabled: boolean; offset: number; maxPerCall: bigint; maxTotal: bigint }; + maxCalls: number; + pins: readonly { offset: number; expected: Hex }[]; +} + +export const NATIVE_TERMS_PARAM: AbiParameter = { + type: 'tuple', + components: [ + { name: 'validUntil', type: 'uint48' }, + { name: 'target', type: 'address' }, + { name: 'selector', type: 'bytes4' }, + { name: 'maxValuePerCall', type: 'uint256' }, + { name: 'maxValueTotal', type: 'uint256' }, + { + name: 'amount', + type: 'tuple', + components: [ + { name: 'enabled', type: 'bool' }, + { name: 'offset', type: 'uint16' }, + { name: 'maxPerCall', type: 'uint256' }, + { name: 'maxTotal', type: 'uint256' }, + ], + }, + { name: 'maxCalls', type: 'uint32' }, + { + name: 'pins', + type: 'tuple[]', + components: [ + { name: 'offset', type: 'uint16' }, + { name: 'expected', type: 'bytes32' }, + ], + }, + ], +}; + +/** + * Spender argument index of known approval functions. Obligation 16 / A01: + * a native rule may allow one only when that argument is pinned. + */ +const APPROVAL_SPENDER_ARG: Readonly> = { + '0x095ea7b3': 0, + '0x39509351': 0, + '0xa22cb465': 0, + '0xd505accf': 1, + '0x87517c45': 1, + '0x2b67b570': null, // Permit2 permit: spender is inside a tuple — never representable +}; + +function invalid(message: string, details?: Record): AgenticError { + return new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, message, { details }); +} + +function assertUint(value: bigint, bits: number, field: string): void { + if (typeof value !== 'bigint' || value < BigInt(0) || value >= BigInt(2) ** BigInt(bits)) { + throw invalid(`${field} must be a uint${bits} bigint`); + } +} + +export interface NativeEncodeContext { + /** Current unix time in seconds; grants with validUntil <= now are rejected. */ + nowSeconds: number; +} + +/** Normalize and validate a public NativeRule into wire terms. Pure. */ +export function nativeRuleToTerms( + rule: NativeRule, + ctx: NativeEncodeContext +): { terms: NativeTermsWire; parsed: ParsedSelector } { + if (!isAddress(rule.target, { strict: false }) || /^0x0{40}$/i.test(rule.target)) { + throw invalid('native rule target must be a non-zero address'); + } + if ( + !Number.isInteger(rule.validUntil) || + rule.validUntil <= ctx.nowSeconds || + rule.validUntil > UINT48_MAX + ) { + throw invalid('validUntil must be a future unix timestamp in seconds (uint48)', { + validUntil: rule.validUntil, + }); + } + const parsed = parseSelector(rule.selector); + const pinsIn = rule.pins ?? []; + if (parsed.valueOnly && (pinsIn.length > 0 || rule.amount)) { + throw invalid('a value-only rule cannot carry pins or an amount rule'); + } + if (pinsIn.length > MAX_PINS) { + throw invalid(`at most ${MAX_PINS} pins are allowed`, { pins: pinsIn.length }); + } + + const pins = pinsIn.map((p, i) => { + const offset = argumentOffset(parsed.inputs, p.arg, `pins[${i}]`); + const param = (parsed.inputs as readonly AbiParameter[])[p.arg]; + return { offset, expected: encodeArgWord(param, p.expected, `pins[${i}]`) }; + }); + const offsets = new Set(pins.map((p) => p.offset)); + if (offsets.size !== pins.length) throw invalid('two pins address the same argument'); + + const spenderArg = APPROVAL_SPENDER_ARG[parsed.selector]; + if (spenderArg !== undefined) { + const pinnedSpender = + spenderArg !== null && pinsIn.some((p) => p.arg === spenderArg); + if (!pinnedSpender) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + `${APPROVAL_SELECTORS[parsed.selector]} needs its spender argument pinned`, + { + hint: 'Pin the spender, or set approvals from the owner door. Provisional policy A01 / obligation 16.', + details: { assumption: 'A01' }, + } + ); + } + } + + let amount: NativeTermsWire['amount'] = { + enabled: false, + offset: 0, + maxPerCall: BigInt(0), + maxTotal: BigInt(0), + }; + if (rule.amount) { + const offset = argumentOffset(parsed.inputs, rule.amount.arg, 'amount'); + const param = (parsed.inputs as readonly AbiParameter[])[rule.amount.arg]; + if (!/^uint\d*$/.test(param.type)) { + throw invalid(`amount argument must be an unsigned integer, got ${param.type}`); + } + if (offsets.has(offset)) throw invalid('amount argument is also pinned'); + assertUint(rule.amount.maxPerCall, 256, 'amount.maxPerCall'); + const maxTotal = withDefault(rule.amount.maxTotal, AGENTIC_DEFAULTS.native.amountMaxTotal); + assertUint(maxTotal, 256, 'amount.maxTotal'); + amount = { enabled: true, offset, maxPerCall: rule.amount.maxPerCall, maxTotal }; + } + + const maxValuePerCall = withDefault(rule.maxValuePerCall, AGENTIC_DEFAULTS.native.maxValuePerCall); + const maxValueTotal = withDefault(rule.maxValueTotal, AGENTIC_DEFAULTS.native.maxValueTotal); + assertUint(maxValuePerCall, 256, 'maxValuePerCall'); + assertUint(maxValueTotal, 256, 'maxValueTotal'); + const maxCalls = + rule.maxCalls === undefined ? Number(AGENTIC_DEFAULTS.native.maxCalls.value) : rule.maxCalls; + if (!Number.isInteger(maxCalls) || maxCalls < 0 || maxCalls > UINT32_MAX) { + throw invalid('maxCalls must be a uint32 integer'); + } + + return { + parsed, + terms: { + validUntil: rule.validUntil, + target: getAddress(rule.target), + selector: parsed.selector, + maxValuePerCall, + maxValueTotal, + amount, + maxCalls, + pins, + }, + }; +} + +export function encodeNativeTerms(terms: NativeTermsWire): Hex { + return encodeAbiParameters([NATIVE_TERMS_PARAM], [terms]); +} + +export function decodeNativeTerms(body: Hex): NativeTermsWire { + const [terms] = decodeAbiParameters([NATIVE_TERMS_PARAM], body); + return terms as unknown as NativeTermsWire; +} + +/** + * Wire terms back to the public NativeRule shape. Argument positions are + * reported as 32-byte head-word indexes ((offset - 4) / 32), which equal the + * argument index whenever every preceding argument is one head word. The + * stored terms do not carry the signature, so `selector` is the 4-byte hex. + */ +export function nativeTermsToRule(terms: NativeTermsWire, agent: Address, ref: AgenticHex): NativeRule { + const rule: NativeRule = { + agent: getAddress(agent), + target: getAddress(terms.target), + selector: + terms.selector.toLowerCase() === VALUE_ONLY_SELECTOR + ? 'value-only' + : (terms.selector.toLowerCase() as AgenticHex), + validUntil: Number(terms.validUntil), + maxValuePerCall: terms.maxValuePerCall, + maxValueTotal: terms.maxValueTotal, + maxCalls: Number(terms.maxCalls), + }; + if (!/^0x0{64}$/i.test(ref)) rule.ref = ref; + if (terms.pins.length > 0) { + rule.pins = terms.pins.map((p) => ({ + arg: offsetToHeadWord(Number(p.offset)), + expected: p.expected as AgenticHex, + })); + } + if (terms.amount.enabled) { + rule.amount = { + arg: offsetToHeadWord(Number(terms.amount.offset)), + maxPerCall: terms.amount.maxPerCall, + maxTotal: terms.amount.maxTotal, + }; + } + return rule; +} + +export function isUnlimited(value: bigint): boolean { + return value === UINT256_MAX; +} diff --git a/packages/core/src/lib/agentic/codec/policy.ts b/packages/core/src/lib/agentic/codec/policy.ts new file mode 100644 index 00000000..a2939bbf --- /dev/null +++ b/packages/core/src/lib/agentic/codec/policy.ts @@ -0,0 +1,52 @@ +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; +import type { AgenticHex } from '../agentic.types'; + +/** + * PROVISIONAL product-policy boundary (one place, both assumptions): + * + * A01 (Harsh H1): known approval-granting selectors are rejected in agent + * rules, because the rule cannot pin an arbitrary approved spender. Owners + * set bounded approvals through the owner door instead. Filtering known + * selectors is one safeguard, not a complete target-safety boundary. + * A02 (Harsh H2): NativeRule stays one action, and a native agent send must be + * a single call — no transaction arrays through the agent door, and no + * sequential fallback. Owner batches and bounded EVM destination + * multicalls are unaffected. + */ +export const APPROVAL_SELECTORS: Readonly> = { + '0x095ea7b3': 'approve(address,uint256)', + '0x39509351': 'increaseAllowance(address,uint256)', + '0xa22cb465': 'setApprovalForAll(address,bool)', + '0xd505accf': 'permit(address,address,uint256,uint256,uint8,bytes32,bytes32)', + '0x2b67b570': 'permit(address,((address,uint160,uint48,uint48),address,uint256),bytes)', + '0x87517c45': 'approve(address,address,uint160,uint48)', +}; + +export function assertNotApprovalSelector(selector: AgenticHex, where: string): void { + const name = APPROVAL_SELECTORS[selector.toLowerCase()]; + if (name) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + `${where}: ${name} grants token spending to an address the rule cannot pin`, + { + hint: + 'Set bounded approvals from the owner door (owner-mode sendTransaction) instead of granting them to an agent. Provisional policy A01.', + details: { selector, assumption: 'A01' }, + } + ); + } +} + +export function assertSingleAgentCall(calls: number): void { + if (calls !== 1) { + throw new AgenticError( + AGENTIC_ERROR_CODE.NOT_ALLOWED_IN_AGENTIC_MODE, + `the agent door dispatches exactly one native call; got ${calls}`, + { + hint: + 'Send each native action separately, or use an owner client for batches. Provisional scope A02.', + details: { assumption: 'A02' }, + } + ); + } +} diff --git a/packages/core/src/lib/agentic/codec/rules.ts b/packages/core/src/lib/agentic/codec/rules.ts new file mode 100644 index 00000000..368373a7 --- /dev/null +++ b/packages/core/src/lib/agentic/codec/rules.ts @@ -0,0 +1,136 @@ +import { getAddress, isAddress, keccak256, toBytes, type Address, type Hex } from 'viem'; +import { AgenticCapability, requireCapability } from '../capabilities'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; +import type { NativeRule, Rule, UniversalRule } from '../agentic.types'; +import { encodeNativeTerms, nativeRuleToTerms, type NativeTermsWire } from './native'; +import { buildSession, encodeEnvelope, type SessionWire } from './session'; +import { encodeUniversalRule } from './universal'; + +export function isUniversalRule(rule: Rule): rule is UniversalRule { + return (rule as UniversalRule).chainNamespace !== undefined; +} + +/** CAIP-2 chain a rule governs: omitted = the connected Push chain. */ +export function ruleChain(rule: Rule, pushChainNamespace: string): string { + return isUniversalRule(rule) ? rule.chainNamespace : pushChainNamespace; +} + +export function chainHash(chainNamespace: string): Hex { + return keccak256(toBytes(chainNamespace)); +} + +export interface RuleEncodeContext { + /** 'eip155:' of the connected network. */ + pushChainNamespace: string; + validator: Address; + rulesPolicy: Address; + capabilities: ReadonlySet; + nowSeconds: number; + /** + * Addresses a native rule may never target (AGW _requireGrantableTarget / + * URP NativeTargetIsGateway): wallet, engine, policy, validator, factory, + * gateway. 0x0 and 0x1 are always refused. + */ + forbiddenTargets?: readonly Address[]; +} + +export interface PreparedRule { + rule: Rule; + agent: Address; + chainNamespace: string; + session: SessionWire; + /** Native terms when the rule is native (used for previews and assertions). */ + nativeTerms?: NativeTermsWire; +} + +/** + * Validate and encode rules before any signature (spec 1.b checks plus + * codec validation). `owner` is the wallet owner's Push address and + * `existing` the currently enabled (agent, chain) pairs that are NOT being + * replaced — both feed the AGENT_IS_OWNER / DUPLICATE_RULE checks. + */ +export function prepareRules( + rules: readonly Rule[], + ctx: RuleEncodeContext & { + /** Wallet owner; when given, an agent equal to it is AGENT_IS_OWNER. */ + owner?: Address; + existing?: readonly { agent: Address; chainNamespace: string; rulesId: Hex }[]; + } +): PreparedRule[] { + if (!Array.isArray(rules)) { + throw new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, 'rules must be an array'); + } + const seen = new Map(); + for (const e of ctx.existing ?? []) { + seen.set(pairKey(e.agent, e.chainNamespace), `existing rule ${e.rulesId}`); + } + return rules.map((rule, i) => { + if (!rule || typeof rule !== 'object') { + throw new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, `rules[${i}] is not an object`); + } + if (!isAddress(rule.agent, { strict: false }) || /^0x0{40}$/i.test(rule.agent)) { + throw new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, `rules[${i}].agent must be a non-zero Push address`); + } + const agent = getAddress(rule.agent); + if (ctx.owner && agent === getAddress(ctx.owner)) { + throw new AgenticError( + AGENTIC_ERROR_CODE.AGENT_IS_OWNER, + `rules[${i}].agent is the wallet owner; the owner uses the owner door` + ); + } + const chainNamespace = ruleChain(rule, ctx.pushChainNamespace); + if (isUniversalRule(rule) && rule.chainNamespace === ctx.pushChainNamespace) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + `rules[${i}] names the connected Push chain; omit chainNamespace for a native rule` + ); + } + const key = pairKey(agent, chainNamespace); + const clash = seen.get(key); + if (clash) { + throw new AgenticError( + AGENTIC_ERROR_CODE.DUPLICATE_RULE, + `rules[${i}] repeats agent ${agent} on ${chainNamespace} (${clash})`, + { hint: 'One rule per agent per chain. Use rules.update to replace an existing rule.' } + ); + } + seen.set(key, `rules[${i}]`); + if (rule.ref !== undefined) { + requireCapability(ctx.capabilities, AgenticCapability.GRANT_REF); + } + + if (isUniversalRule(rule)) { + return encodeUniversalRule(rule, ctx); + } + requireCapability(ctx.capabilities, AgenticCapability.NATIVE_RULES); + const { terms } = nativeRuleToTerms(rule as NativeRule, ctx); + const forbidden = [ + '0x0000000000000000000000000000000000000000', + '0x0000000000000000000000000000000000000001', + ...(ctx.forbiddenTargets ?? []), + ].map((a) => a.toLowerCase()); + if (forbidden.includes(terms.target.toLowerCase())) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + `rules[${i}].target ${terms.target} is a wallet-infrastructure address the contracts refuse as a native target` + ); + } + const session = buildSession({ + validator: ctx.validator, + agent, + rulesPolicy: ctx.rulesPolicy, + actions: [ + { + target: terms.target, + selector: terms.selector, + initData: encodeEnvelope(chainNamespace, encodeNativeTerms(terms)), + }, + ], + }); + return { rule, agent, chainNamespace, session, nativeTerms: terms }; + }); +} + +function pairKey(agent: Address, chainNamespace: string): string { + return `${agent.toLowerCase()}|${chainNamespace}`; +} diff --git a/packages/core/src/lib/agentic/codec/selectors.ts b/packages/core/src/lib/agentic/codec/selectors.ts new file mode 100644 index 00000000..317575f7 --- /dev/null +++ b/packages/core/src/lib/agentic/codec/selectors.ts @@ -0,0 +1,77 @@ +import { + parseAbiItem, + toFunctionSelector, + type AbiFunction, + type AbiParameter, +} from 'viem'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; +import type { AgenticHex, Selector } from '../agentic.types'; + +/** Selector URP uses for a value-only native rule (empty calldata). */ +export const VALUE_ONLY_SELECTOR = '0xffffffff' as const; + +export interface ParsedSelector { + /** 4-byte selector, lowercase. */ + selector: AgenticHex; + /** Canonical signature when the caller supplied one. */ + signature?: string; + /** ABI inputs, only available when the caller supplied a signature. */ + inputs?: readonly AbiParameter[]; + valueOnly: boolean; +} + +const HEX_SELECTOR = /^0x[0-9a-fA-F]{8}$/; + +/** + * Parse a public selector (`'0x617ba037'`, `'supply(address,uint256,address,uint16)'` + * or `'value-only'`). A signature is required wherever pins, amounts or + * beneficiaries need argument positions; a bare hex selector carries none. + */ +export function parseSelector(input: Selector | 'value-only'): ParsedSelector { + if (input === 'value-only') { + return { selector: VALUE_ONLY_SELECTOR, valueOnly: true }; + } + if (typeof input !== 'string') { + throw invalid(`selector must be a string, got ${typeof input}`); + } + if (HEX_SELECTOR.test(input)) { + const selector = input.toLowerCase() as AgenticHex; + if (selector === VALUE_ONLY_SELECTOR) { + return { selector, valueOnly: true }; + } + return { selector, valueOnly: false }; + } + let item: AbiFunction; + try { + const parsed = parseAbiItem(`function ${input}`); + if (parsed.type !== 'function') throw new Error('not a function'); + item = parsed; + } catch (cause) { + throw invalid( + `selector "${input}" is neither a 4-byte hex selector nor a function signature`, + cause + ); + } + const selector = toFunctionSelector(item).toLowerCase() as AgenticHex; + if (selector === VALUE_ONLY_SELECTOR) { + throw invalid(`selector "${input}" collides with the reserved value-only selector`); + } + return { + selector, + signature: `${item.name}(${item.inputs.map(canonicalType).join(',')})`, + inputs: item.inputs, + valueOnly: false, + }; +} + +function canonicalType(p: AbiParameter): string { + if (p.type.startsWith('tuple')) { + const components = (p as { components?: readonly AbiParameter[] }).components ?? []; + return `(${components.map(canonicalType).join(',')})${p.type.slice(5)}`; + } + return p.type; +} + +function invalid(message: string, cause?: unknown): AgenticError { + return new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, message, { cause }); +} diff --git a/packages/core/src/lib/agentic/codec/session.ts b/packages/core/src/lib/agentic/codec/session.ts new file mode 100644 index 00000000..40f970f2 --- /dev/null +++ b/packages/core/src/lib/agentic/codec/session.ts @@ -0,0 +1,95 @@ +import { + decodeAbiParameters, + encodeAbiParameters, + getAbiItem, + type AbiParameter, + type Address, + type Hex, +} from 'viem'; +import { AGW_ABI } from '../contracts/abi/e704d5b'; +import { agentConfig } from './ids'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; + +/** + * The smartsessions `Session` a grant carries (DataTypes.sol:56-86, pinned + * e704d5b). The wallet overwrites `salt` with its grant nonce, so the value + * sent is irrelevant; it is always zero here. + */ +export interface SessionWire { + sessionValidator: Address; + sessionValidatorInitData: Hex; + salt: Hex; + userOpPolicies: readonly { policy: Address; initData: Hex }[]; + erc7739Policies: { + allowedERC7739Content: readonly { appDomainSeparator: Hex; contentNames: readonly string[] }[]; + erc1271Policies: readonly { policy: Address; initData: Hex }[]; + }; + actions: readonly { + actionTargetSelector: Hex; + actionTarget: Address; + actionPolicies: readonly { policy: Address; initData: Hex }[]; + }[]; + permitERC4337Paymaster: boolean; +} + +export const SESSION_PARAM: AbiParameter = getAbiItem({ + abi: AGW_ABI, + name: 'grantRules', +}).inputs[0] as AbiParameter; + +const ZERO_SALT = `0x${'00'.repeat(32)}` as Hex; + +/** URP envelope: abi.encode(string chainNamespace, bytes body). */ +export function encodeEnvelope(chainNamespace: string, body: Hex): Hex { + return encodeAbiParameters([{ type: 'string' }, { type: 'bytes' }], [chainNamespace, body]); +} + +export function decodeEnvelope(initData: Hex): { chainNamespace: string; body: Hex } { + try { + const [chainNamespace, body] = decodeAbiParameters( + [{ type: 'string' }, { type: 'bytes' }], + initData + ); + return { chainNamespace, body }; + } catch (cause) { + throw new AgenticError(AGENTIC_ERROR_CODE.RULE_READ_FAILED, 'malformed URP envelope', { + cause, + }); + } +} + +export function buildSession(ctx: { + validator: Address; + agent: Address; + rulesPolicy: Address; + actions: { target: Address; selector: Hex; initData: Hex }[]; +}): SessionWire { + return { + sessionValidator: ctx.validator, + sessionValidatorInitData: agentConfig(ctx.agent), + salt: ZERO_SALT, + userOpPolicies: [], + erc7739Policies: { allowedERC7739Content: [], erc1271Policies: [] }, + actions: ctx.actions.map((a) => ({ + actionTargetSelector: a.selector, + actionTarget: a.target, + actionPolicies: [{ policy: ctx.rulesPolicy, initData: a.initData }], + })), + permitERC4337Paymaster: false, + }; +} + +export function encodeSession(session: SessionWire): Hex { + return encodeAbiParameters([SESSION_PARAM], [session]); +} + +export function decodeSession(bytes: Hex): SessionWire { + try { + const [session] = decodeAbiParameters([SESSION_PARAM], bytes); + return session as unknown as SessionWire; + } catch (cause) { + throw new AgenticError(AGENTIC_ERROR_CODE.RULE_READ_FAILED, 'malformed Session encoding', { + cause, + }); + } +} diff --git a/packages/core/src/lib/agentic/codec/universal.ts b/packages/core/src/lib/agentic/codec/universal.ts new file mode 100644 index 00000000..b657cd16 --- /dev/null +++ b/packages/core/src/lib/agentic/codec/universal.ts @@ -0,0 +1,97 @@ +import { isAddress } from 'viem'; +import { AgenticCapability, requireCapability } from '../capabilities'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; +import type { UniversalRule } from '../agentic.types'; +import { argumentOffset } from './abi-layout'; +import { assertNotApprovalSelector } from './policy'; +import { parseSelector } from './selectors'; + +/** Proposed multi-asset limits (page 1 §4c) and the pinned allow-list limit. */ +export const MAX_ASSETS = 8; +export const MAX_ALLOWED_CALLS = 32; + +const CAIP2 = /^(eip155:[0-9]+|solana:[1-9A-HJ-NP-Za-km-z]{32,44})$/; + +/** + * Structural validation of a TARGET UniversalRule that does not depend on the + * unresolved wire format: chain id shape, call allow-list, selector/beneficiary + * positions and the A01 approval policy. Runs before the capability gate so + * callers get precise input errors. + */ +export function validateUniversalRuleShape(rule: UniversalRule, nowSeconds: number): void { + if (typeof rule.chainNamespace !== 'string' || !CAIP2.test(rule.chainNamespace)) { + throw invalid(`chainNamespace "${String(rule.chainNamespace)}" is not a CAIP-2 eip155/solana chain`); + } + if (!Number.isInteger(rule.validUntil) || rule.validUntil <= nowSeconds) { + throw invalid('validUntil must be a future unix timestamp in seconds'); + } + if (!Array.isArray(rule.assets) || rule.assets.length > MAX_ASSETS) { + throw invalid(`assets must be an array of at most ${MAX_ASSETS} caps`); + } + if (typeof rule.maxGasPerCall !== 'bigint' || rule.maxGasPerCall <= BigInt(0)) { + throw invalid('maxGasPerCall must be a positive bigint (PC wei per outbound)'); + } + if ( + !Array.isArray(rule.allowedCalls) || + rule.allowedCalls.length < 1 || + rule.allowedCalls.length > MAX_ALLOWED_CALLS + ) { + throw invalid(`allowedCalls must contain 1..${MAX_ALLOWED_CALLS} entries`); + } + const seen = new Set(); + rule.allowedCalls.forEach((call, i) => { + if (!isAddress(call.target, { strict: false })) { + throw invalid(`allowedCalls[${i}].target is not an EVM address`); + } + const parsed = parseSelector(call.selector); + if (parsed.valueOnly) throw invalid(`allowedCalls[${i}] cannot be value-only`); + assertNotApprovalSelector(parsed.selector, `allowedCalls[${i}]`); + if (call.beneficiary !== undefined) { + argumentOffset(parsed.inputs, call.beneficiary, `allowedCalls[${i}].beneficiary`); + const t = (parsed.inputs ?? [])[call.beneficiary]?.type; + if (t !== 'address') throw invalid(`allowedCalls[${i}].beneficiary must be an address argument`); + } + const key = `${call.target.toLowerCase()}:${parsed.selector}`; + if (seen.has(key)) throw invalid(`allowedCalls[${i}] duplicates an earlier target/selector`); + seen.add(key); + }); + const tokens = new Set(); + rule.assets.forEach((a, i) => { + const address = typeof a.token === 'string' ? a.token : a.token?.address; + if (typeof address !== 'string') throw invalid(`assets[${i}].token is missing an address`); + const key = address.toLowerCase(); + if (tokens.has(key)) throw invalid(`assets[${i}] duplicates an earlier token`); + tokens.add(key); + if (typeof a.maxPerCall !== 'bigint' || a.maxPerCall < BigInt(0)) { + throw invalid(`assets[${i}].maxPerCall must be a non-negative bigint`); + } + }); +} + +/** + * Encode a target UniversalRule. NOT IMPLEMENTED: the multi-asset wire format, + * empty-assets routing, expectedCEA width and envelope version have no + * matching contract artifacts (A05/A07). Never falls back to the historical + * single-asset terms. + */ +export function encodeUniversalRule( + rule: UniversalRule, + ctx: { capabilities: ReadonlySet; nowSeconds: number } +): never { + validateUniversalRuleShape(rule, ctx.nowSeconds); + const svm = rule.chainNamespace.startsWith('solana:'); + requireCapability( + ctx.capabilities, + svm ? AgenticCapability.UNIVERSAL_SVM_RULES : AgenticCapability.UNIVERSAL_EVM_RULES + ); + // A generation that advertises the capability must supply its own codec. + throw new AgenticError( + AGENTIC_ERROR_CODE.CAPABILITY_UNAVAILABLE, + 'no universal rule codec is implemented for this generation' + ); +} + +function invalid(message: string): AgenticError { + return new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, message); +} + diff --git a/packages/core/src/lib/agentic/constants.ts b/packages/core/src/lib/agentic/constants.ts new file mode 100644 index 00000000..d579df2a --- /dev/null +++ b/packages/core/src/lib/agentic/constants.ts @@ -0,0 +1,17 @@ +import type { PUSH_NETWORK } from '../constants/enums'; + +/** + * PushChain.CONSTANTS.AGENTIC[network] (spec 3.d). Populated only from + * verified release deployments — currently none (A07), so the map is empty. + * ENVELOPE_VERSION is omitted until a generation with a versioned envelope is + * delivered; no value is guessed. + */ +export interface AgenticNetworkConstants { + FACTORY: `0x${string}`; + RULES_POLICY: `0x${string}`; + MAX_PINS: number; + MAX_ALLOWED_CALLS: number; + ENVELOPE_VERSION?: number; +} + +export const AGENTIC: Readonly>> = Object.freeze({}); diff --git a/packages/core/src/lib/agentic/contracts/abi/e704d5b/agent-validator.ts b/packages/core/src/lib/agentic/contracts/abi/e704d5b/agent-validator.ts new file mode 100644 index 00000000..39d5abf5 --- /dev/null +++ b/packages/core/src/lib/agentic/contracts/abi/e704d5b/agent-validator.ts @@ -0,0 +1,145 @@ +// GENERATED by packages/core/scripts/agw-local/gen-abi.mjs — do not edit. +// Source: plan/agw/research/validation-e704d5b/abi/AgentValidator.json +// push-agentic-wallets@e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9 +// sha256(AgentValidator.json) = a4570ddc373241580de8742cbb3d9f2c837094c65bfd1cdd52243ca0c38196fd +export const AGENT_VALIDATOR_ABI = [ + { + "type": "function", + "name": "isInitialized", + "inputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "isModuleType", + "inputs": [ + { + "name": "moduleTypeId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "onInstall", + "inputs": [ + { + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "onUninstall", + "inputs": [ + { + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "validateConfig", + "inputs": [ + { + "name": "data", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "validateSignatureWithData", + "inputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "sig", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "data", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "validSig", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "pure" + }, + { + "type": "error", + "name": "AlreadyInitialized", + "inputs": [ + { + "name": "smartAccount", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "MalformedConfig", + "inputs": [] + }, + { + "type": "error", + "name": "NotInitialized", + "inputs": [ + { + "name": "smartAccount", + "type": "address", + "internalType": "address" + } + ] + } +] as const; diff --git a/packages/core/src/lib/agentic/contracts/abi/e704d5b/agw-factory.ts b/packages/core/src/lib/agentic/contracts/abi/e704d5b/agw-factory.ts new file mode 100644 index 00000000..ec4f3b07 --- /dev/null +++ b/packages/core/src/lib/agentic/contracts/abi/e704d5b/agw-factory.ts @@ -0,0 +1,1104 @@ +// GENERATED by packages/core/scripts/agw-local/gen-abi.mjs — do not edit. +// Source: plan/agw/research/validation-e704d5b/abi/AGWFactory.json +// push-agentic-wallets@e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9 +// sha256(AGWFactory.json) = b65f66a1556d2a9ddf9aabe9f595c685c2aada436772892f5a40fb1eec846397 +export const AGW_FACTORY_ABI = [ + { + "type": "function", + "name": "DEFAULT_ADMIN_ROLE", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "OPERATOR_ROLE", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "PAUSER_ROLE", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "UPGRADE_INTERFACE_VERSION", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "acceptDefaultAdminTransfer", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "beginDefaultAdminTransfer", + "inputs": [ + { + "name": "newAdmin", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "cancelDefaultAdminTransfer", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "changeDefaultAdminDelay", + "inputs": [ + { + "name": "newDelay", + "type": "uint48", + "internalType": "uint48" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "defaultAdmin", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "defaultAdminDelay", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint48", + "internalType": "uint48" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "defaultAdminDelayIncreaseWait", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint48", + "internalType": "uint48" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "deployWallet", + "inputs": [ + { + "name": "label", + "type": "string", + "internalType": "string" + } + ], + "outputs": [ + { + "name": "wallet", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "deployWalletWithSig", + "inputs": [ + { + "name": "intent", + "type": "tuple", + "internalType": "struct OwnerIntent", + "components": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "wallet", + "type": "address", + "internalType": "address" + }, + { + "name": "executor", + "type": "address", + "internalType": "address" + }, + { + "name": "index", + "type": "uint96", + "internalType": "uint96" + }, + { + "name": "sessionHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "mode", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "execCalldataHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "nonceKey", + "type": "uint192", + "internalType": "uint192" + }, + { + "name": "nonceSeq", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "grantNonce", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "deadline", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "signerChainId", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "sig", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "label", + "type": "string", + "internalType": "string" + } + ], + "outputs": [ + { + "name": "wallet", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "domainSeparator", + "inputs": [ + { + "name": "signerChainId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getRoleAdmin", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "grantRole", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "hasRole", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "indexOf", + "inputs": [ + { + "name": "wallet", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "initialize", + "inputs": [ + { + "name": "admin", + "type": "address", + "internalType": "address" + }, + { + "name": "walletImplementation_", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "isWallet", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "owner", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "ownerOf", + "inputs": [ + { + "name": "wallet", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "pause", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "paused", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "pendingDefaultAdmin", + "inputs": [], + "outputs": [ + { + "name": "newAdmin", + "type": "address", + "internalType": "address" + }, + { + "name": "schedule", + "type": "uint48", + "internalType": "uint48" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "pendingDefaultAdminDelay", + "inputs": [], + "outputs": [ + { + "name": "newDelay", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "schedule", + "type": "uint48", + "internalType": "uint48" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "predictWallet", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "index", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "wallet", + "type": "address", + "internalType": "address" + }, + { + "name": "deployed", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "proxiableUUID", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "renounceRole", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "revokeRole", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "rollbackDefaultAdminDelay", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "supportsInterface", + "inputs": [ + { + "name": "interfaceId", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "unpause", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "upgradeToAndCall", + "inputs": [ + { + "name": "newImplementation", + "type": "address", + "internalType": "address" + }, + { + "name": "data", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "walletCount", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "walletImplementation", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "event", + "name": "DefaultAdminDelayChangeCanceled", + "inputs": [], + "anonymous": false + }, + { + "type": "event", + "name": "DefaultAdminDelayChangeScheduled", + "inputs": [ + { + "name": "newDelay", + "type": "uint48", + "indexed": false, + "internalType": "uint48" + }, + { + "name": "effectSchedule", + "type": "uint48", + "indexed": false, + "internalType": "uint48" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "DefaultAdminTransferCanceled", + "inputs": [], + "anonymous": false + }, + { + "type": "event", + "name": "DefaultAdminTransferScheduled", + "inputs": [ + { + "name": "newAdmin", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "acceptSchedule", + "type": "uint48", + "indexed": false, + "internalType": "uint48" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Initialized", + "inputs": [ + { + "name": "version", + "type": "uint64", + "indexed": false, + "internalType": "uint64" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Paused", + "inputs": [ + { + "name": "account", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RoleAdminChanged", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "previousAdminRole", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "newAdminRole", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RoleGranted", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RoleRevoked", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Unpaused", + "inputs": [ + { + "name": "account", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Upgraded", + "inputs": [ + { + "name": "implementation", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "WalletDeployed", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "index", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "wallet", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "label", + "type": "string", + "indexed": false, + "internalType": "string" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "AccessControlBadConfirmation", + "inputs": [] + }, + { + "type": "error", + "name": "AccessControlEnforcedDefaultAdminDelay", + "inputs": [ + { + "name": "schedule", + "type": "uint48", + "internalType": "uint48" + } + ] + }, + { + "type": "error", + "name": "AccessControlEnforcedDefaultAdminRules", + "inputs": [] + }, + { + "type": "error", + "name": "AccessControlInvalidDefaultAdmin", + "inputs": [ + { + "name": "defaultAdmin", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "AccessControlUnauthorizedAccount", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "neededRole", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "AddressEmptyCode", + "inputs": [ + { + "name": "target", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "CloneArgumentsTooLong", + "inputs": [] + }, + { + "type": "error", + "name": "Create2EmptyBytecode", + "inputs": [] + }, + { + "type": "error", + "name": "ERC1967InvalidImplementation", + "inputs": [ + { + "name": "implementation", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ERC1967NonPayable", + "inputs": [] + }, + { + "type": "error", + "name": "EnforcedPause", + "inputs": [] + }, + { + "type": "error", + "name": "ExecutorMismatch", + "inputs": [ + { + "name": "expected", + "type": "address", + "internalType": "address" + }, + { + "name": "actual", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ExpectedPause", + "inputs": [] + }, + { + "type": "error", + "name": "FailedCall", + "inputs": [] + }, + { + "type": "error", + "name": "FailedDeployment", + "inputs": [] + }, + { + "type": "error", + "name": "ImplementationNotSet", + "inputs": [] + }, + { + "type": "error", + "name": "IndexMismatch", + "inputs": [ + { + "name": "expected", + "type": "uint96", + "internalType": "uint96" + }, + { + "name": "provided", + "type": "uint96", + "internalType": "uint96" + } + ] + }, + { + "type": "error", + "name": "IndexOutOfRange", + "inputs": [ + { + "name": "index", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "next", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "InsufficientBalance", + "inputs": [ + { + "name": "balance", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "needed", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "IntentWalletMismatch", + "inputs": [ + { + "name": "expected", + "type": "address", + "internalType": "address" + }, + { + "name": "provided", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "InvalidInitialization", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidOwnerSignature", + "inputs": [] + }, + { + "type": "error", + "name": "NotAWallet", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "NotInitializing", + "inputs": [] + }, + { + "type": "error", + "name": "SafeCastOverflowedUintDowncast", + "inputs": [ + { + "name": "bits", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "SignatureExpired", + "inputs": [ + { + "name": "deadline", + "type": "uint48", + "internalType": "uint48" + } + ] + }, + { + "type": "error", + "name": "UUPSUnauthorizedCallContext", + "inputs": [] + }, + { + "type": "error", + "name": "UUPSUnsupportedProxiableUUID", + "inputs": [ + { + "name": "slot", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "ZeroAddress", + "inputs": [] + } +] as const; diff --git a/packages/core/src/lib/agentic/contracts/abi/e704d5b/agw.ts b/packages/core/src/lib/agentic/contracts/abi/e704d5b/agw.ts new file mode 100644 index 00000000..470b61ca --- /dev/null +++ b/packages/core/src/lib/agentic/contracts/abi/e704d5b/agw.ts @@ -0,0 +1,1528 @@ +// GENERATED by packages/core/scripts/agw-local/gen-abi.mjs — do not edit. +// Source: plan/agw/research/validation-e704d5b/abi/AGW.json +// push-agentic-wallets@e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9 +// sha256(AGW.json) = ca41d463fac3f7ec8c4399402f2afe41678f43d75baf2ad0220a804699e1fd7b +export const AGW_ABI = [ + { + "type": "receive", + "stateMutability": "payable" + }, + { + "type": "function", + "name": "RULES_POLICY", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "SESSION_ENGINE", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "SESSION_VALIDATOR", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "UNIVERSAL_GATEWAY_PC", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "accountId", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "agentOf", + "inputs": [ + { + "name": "rulesId", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "checkpointCount", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint64", + "internalType": "uint64" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "domainSeparator", + "inputs": [ + { + "name": "signerChainId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "execute", + "inputs": [ + { + "name": "mode", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "executionCalldata", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "executeAsAgent", + "inputs": [ + { + "name": "rulesId", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "mode", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "executionCalldata", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "executeWithSig", + "inputs": [ + { + "name": "mode", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "executionCalldata", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "intent", + "type": "tuple", + "internalType": "struct OwnerIntent", + "components": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "wallet", + "type": "address", + "internalType": "address" + }, + { + "name": "executor", + "type": "address", + "internalType": "address" + }, + { + "name": "index", + "type": "uint96", + "internalType": "uint96" + }, + { + "name": "sessionHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "mode", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "execCalldataHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "nonceKey", + "type": "uint192", + "internalType": "uint192" + }, + { + "name": "nonceSeq", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "grantNonce", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "deadline", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "signerChainId", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "sig", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "factory", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getNonce", + "inputs": [ + { + "name": "nonceKey", + "type": "uint192", + "internalType": "uint192" + } + ], + "outputs": [ + { + "name": "", + "type": "uint64", + "internalType": "uint64" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "grantNonce", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint64", + "internalType": "uint64" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "grantRules", + "inputs": [ + { + "name": "session", + "type": "tuple", + "internalType": "struct Session", + "components": [ + { + "name": "sessionValidator", + "type": "address", + "internalType": "contract ISessionValidator" + }, + { + "name": "sessionValidatorInitData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "erc7739Policies", + "type": "tuple", + "internalType": "struct ERC7739Data", + "components": [ + { + "name": "allowedERC7739Content", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNames", + "type": "string[]", + "internalType": "string[]" + } + ] + }, + { + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "actions", + "type": "tuple[]", + "internalType": "struct ActionData[]", + "components": [ + { + "name": "actionTargetSelector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "actionTarget", + "type": "address", + "internalType": "address" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "permitERC4337Paymaster", + "type": "bool", + "internalType": "bool" + } + ] + } + ], + "outputs": [ + { + "name": "rulesId", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "grantRulesWithSig", + "inputs": [ + { + "name": "session", + "type": "tuple", + "internalType": "struct Session", + "components": [ + { + "name": "sessionValidator", + "type": "address", + "internalType": "contract ISessionValidator" + }, + { + "name": "sessionValidatorInitData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "erc7739Policies", + "type": "tuple", + "internalType": "struct ERC7739Data", + "components": [ + { + "name": "allowedERC7739Content", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNames", + "type": "string[]", + "internalType": "string[]" + } + ] + }, + { + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "actions", + "type": "tuple[]", + "internalType": "struct ActionData[]", + "components": [ + { + "name": "actionTargetSelector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "actionTarget", + "type": "address", + "internalType": "address" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "permitERC4337Paymaster", + "type": "bool", + "internalType": "bool" + } + ] + }, + { + "name": "intent", + "type": "tuple", + "internalType": "struct OwnerIntent", + "components": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "wallet", + "type": "address", + "internalType": "address" + }, + { + "name": "executor", + "type": "address", + "internalType": "address" + }, + { + "name": "index", + "type": "uint96", + "internalType": "uint96" + }, + { + "name": "sessionHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "mode", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "execCalldataHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "nonceKey", + "type": "uint192", + "internalType": "uint192" + }, + { + "name": "nonceSeq", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "grantNonce", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "deadline", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "signerChainId", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "sig", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "rulesId", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "initializeAccount", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "installModule", + "inputs": [ + { + "name": "moduleTypeId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "module", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "isModuleInstalled", + "inputs": [ + { + "name": "moduleTypeId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "module", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isValidSignature", + "inputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "lastCheckpointBlock", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint64", + "internalType": "uint64" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "onERC1155BatchReceived", + "inputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "onERC1155Received", + "inputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "onERC721Received", + "inputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "owner", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "revokeAllRules", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "revokeRules", + "inputs": [ + { + "name": "rulesId", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "supportsExecutionMode", + "inputs": [ + { + "name": "mode", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "supportsInterface", + "inputs": [ + { + "name": "interfaceId", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "supportsModule", + "inputs": [ + { + "name": "moduleTypeId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "uninstallModule", + "inputs": [ + { + "name": "moduleTypeId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "module", + "type": "address", + "internalType": "address" + }, + { + "name": "deInitData", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "AccountInitialized", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "engine", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Checkpointed", + "inputs": [ + { + "name": "seq", + "type": "uint64", + "indexed": true, + "internalType": "uint64" + }, + { + "name": "kind", + "type": "uint8", + "indexed": false, + "internalType": "enum CheckpointKind" + }, + { + "name": "ref", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + }, + { + "name": "blockNumber", + "type": "uint64", + "indexed": false, + "internalType": "uint64" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ModuleInstalled", + "inputs": [ + { + "name": "moduleTypeId", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "module", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ModuleUninstalled", + "inputs": [ + { + "name": "moduleTypeId", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "module", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "OwnerExecuted", + "inputs": [ + { + "name": "mode", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "executionCalldataHash", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "OwnerExecutedWithSig", + "inputs": [ + { + "name": "mode", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "executionCalldataHash", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + }, + { + "name": "nonceKey", + "type": "uint192", + "indexed": false, + "internalType": "uint192" + }, + { + "name": "nonceSeq", + "type": "uint64", + "indexed": false, + "internalType": "uint64" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RulesActionAuthorized", + "inputs": [ + { + "name": "rulesId", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "agent", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "callsHash", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RulesGranted", + "inputs": [ + { + "name": "rulesId", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "mode", + "type": "uint8", + "indexed": false, + "internalType": "enum RulesType" + }, + { + "name": "chainHash", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "chainNamespace", + "type": "string", + "indexed": false, + "internalType": "string" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RulesRevoked", + "inputs": [ + { + "name": "rulesId", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "UninstallCallbackFailed", + "inputs": [ + { + "name": "module", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "AlreadyInitialized", + "inputs": [] + }, + { + "type": "error", + "name": "CallerIsNotAgent", + "inputs": [ + { + "name": "rulesId", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "caller", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "CallerIsNotFactory", + "inputs": [] + }, + { + "type": "error", + "name": "CallerIsNotOwner", + "inputs": [] + }, + { + "type": "error", + "name": "DuplicateAction", + "inputs": [ + { + "name": "target", + "type": "address", + "internalType": "address" + }, + { + "name": "selector", + "type": "bytes4", + "internalType": "bytes4" + } + ] + }, + { + "type": "error", + "name": "EmptyChain", + "inputs": [] + }, + { + "type": "error", + "name": "EngineStillHoldsPermissions", + "inputs": [] + }, + { + "type": "error", + "name": "ExecutorMismatch", + "inputs": [ + { + "name": "expected", + "type": "address", + "internalType": "address" + }, + { + "name": "actual", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ForbiddenActionSelector", + "inputs": [ + { + "name": "selector", + "type": "bytes4", + "internalType": "bytes4" + } + ] + }, + { + "type": "error", + "name": "ForbiddenActionTarget", + "inputs": [ + { + "name": "target", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ForbiddenDispatchTarget", + "inputs": [ + { + "name": "target", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "InconsistentChain", + "inputs": [ + { + "name": "actionIndex", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "IntentExecMismatch", + "inputs": [ + { + "name": "actualCalldataHash", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "IntentGrantNonceMismatch", + "inputs": [ + { + "name": "expected", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "provided", + "type": "uint64", + "internalType": "uint64" + } + ] + }, + { + "type": "error", + "name": "IntentSessionMismatch", + "inputs": [ + { + "name": "actual", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "IntentWalletMismatch", + "inputs": [ + { + "name": "expected", + "type": "address", + "internalType": "address" + }, + { + "name": "provided", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "InvalidModuleAddress", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidNonce", + "inputs": [ + { + "name": "nonceKey", + "type": "uint192", + "internalType": "uint192" + }, + { + "name": "expected", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "provided", + "type": "uint64", + "internalType": "uint64" + } + ] + }, + { + "type": "error", + "name": "InvalidOwnerSignature", + "inputs": [] + }, + { + "type": "error", + "name": "MalformedBatchCalldata", + "inputs": [] + }, + { + "type": "error", + "name": "MalformedSessionShape", + "inputs": [] + }, + { + "type": "error", + "name": "ModuleAlreadyInstalled", + "inputs": [ + { + "name": "module", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "OutsideTimeWindow", + "inputs": [ + { + "name": "validAfter", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "validUntil", + "type": "uint48", + "internalType": "uint48" + } + ] + }, + { + "type": "error", + "name": "OwnerLaneRequired", + "inputs": [ + { + "name": "nonceKey", + "type": "uint192", + "internalType": "uint192" + } + ] + }, + { + "type": "error", + "name": "OwnerSigExpired", + "inputs": [ + { + "name": "deadline", + "type": "uint48", + "internalType": "uint48" + } + ] + }, + { + "type": "error", + "name": "ReentrancyGuardReentrantCall", + "inputs": [] + }, + { + "type": "error", + "name": "RulesTypeMismatch", + "inputs": [ + { + "name": "derived", + "type": "uint8", + "internalType": "enum RulesType" + }, + { + "name": "actionIndex", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "target", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "TooManyActions", + "inputs": [ + { + "name": "count", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "UnknownPermission", + "inputs": [ + { + "name": "rulesId", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "UnsupportedExecutionMode", + "inputs": [] + }, + { + "type": "error", + "name": "UnsupportedModuleType", + "inputs": [ + { + "name": "moduleTypeId", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "ValidationFailed", + "inputs": [ + { + "name": "authorizer", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ValidatorNotInstalled", + "inputs": [ + { + "name": "validator", + "type": "address", + "internalType": "address" + } + ] + } +] as const; diff --git a/packages/core/src/lib/agentic/contracts/abi/e704d5b/index.ts b/packages/core/src/lib/agentic/contracts/abi/e704d5b/index.ts new file mode 100644 index 00000000..7c81b83c --- /dev/null +++ b/packages/core/src/lib/agentic/contracts/abi/e704d5b/index.ts @@ -0,0 +1,8 @@ +// GENERATED by packages/core/scripts/agw-local/gen-abi.mjs — do not edit. +// Review generation e704d5b: no verified deployment exists for this ABI set. +export const E704D5B_SOURCE_COMMIT = 'e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9' as const; +export { AGW_ABI } from './agw'; +export { AGW_FACTORY_ABI } from './agw-factory'; +export { UNIVERSAL_RULES_POLICY_ABI } from './universal-rules-policy'; +export { SMART_SESSION_ABI } from './smart-session'; +export { AGENT_VALIDATOR_ABI } from './agent-validator'; diff --git a/packages/core/src/lib/agentic/contracts/abi/e704d5b/smart-session.ts b/packages/core/src/lib/agentic/contracts/abi/e704d5b/smart-session.ts new file mode 100644 index 00000000..b47e8b8b --- /dev/null +++ b/packages/core/src/lib/agentic/contracts/abi/e704d5b/smart-session.ts @@ -0,0 +1,1961 @@ +// GENERATED by packages/core/scripts/agw-local/gen-abi.mjs — do not edit. +// Source: plan/agw/research/validation-e704d5b/abi/SmartSession.json +// push-agentic-wallets@e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9 +// sha256(SmartSession.json) = 6e5d9cea4dbed01f06af913c1e093743b86b7432195f4a4bf90fb94b282c51b2 +export const SMART_SESSION_ABI = [ + { + "type": "function", + "name": "areActionsEnabled", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "actions", + "type": "tuple[]", + "internalType": "struct ActionData[]", + "components": [ + { + "name": "actionTargetSelector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "actionTarget", + "type": "address", + "internalType": "address" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "areERC1271PoliciesEnabled", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "areUserOpPoliciesEnabled", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "disableActionId", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "actionId", + "type": "bytes32", + "internalType": "ActionId" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "disableActionPolicies", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "actionId", + "type": "bytes32", + "internalType": "ActionId" + }, + { + "name": "policies", + "type": "address[]", + "internalType": "address[]" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "disableERC1271Policies", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "policies", + "type": "address[]", + "internalType": "address[]" + }, + { + "name": "contexts", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNames", + "type": "string[]", + "internalType": "string[]" + } + ] + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "disableUserOpPolicies", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "policies", + "type": "address[]", + "internalType": "address[]" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "enableActionPolicies", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct ActionData[]", + "components": [ + { + "name": "actionTargetSelector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "actionTarget", + "type": "address", + "internalType": "address" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "enableERC1271Policies", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "erc1271Policies", + "type": "tuple", + "internalType": "struct ERC7739Data", + "components": [ + { + "name": "allowedERC7739Content", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNames", + "type": "string[]", + "internalType": "string[]" + } + ] + }, + { + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "enableSessions", + "inputs": [ + { + "name": "sessions", + "type": "tuple[]", + "internalType": "struct Session[]", + "components": [ + { + "name": "sessionValidator", + "type": "address", + "internalType": "contract ISessionValidator" + }, + { + "name": "sessionValidatorInitData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "erc7739Policies", + "type": "tuple", + "internalType": "struct ERC7739Data", + "components": [ + { + "name": "allowedERC7739Content", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNames", + "type": "string[]", + "internalType": "string[]" + } + ] + }, + { + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "actions", + "type": "tuple[]", + "internalType": "struct ActionData[]", + "components": [ + { + "name": "actionTargetSelector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "actionTarget", + "type": "address", + "internalType": "address" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "permitERC4337Paymaster", + "type": "bool", + "internalType": "bool" + } + ] + } + ], + "outputs": [ + { + "name": "permissionIds", + "type": "bytes32[]", + "internalType": "PermissionId[]" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "enableUserOpPolicies", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "getActionPolicies", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "actionId", + "type": "bytes32", + "internalType": "ActionId" + } + ], + "outputs": [ + { + "name": "", + "type": "address[]", + "internalType": "address[]" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getERC1271Policies", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ], + "outputs": [ + { + "name": "", + "type": "address[]", + "internalType": "address[]" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getEnabledActions", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes32[]", + "internalType": "bytes32[]" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getEnabledERC7739Content", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ], + "outputs": [ + { + "name": "enabledERC7739ContentHashes", + "type": "tuple[]", + "internalType": "struct ERC7739ContextHashes[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNameHashes", + "type": "bytes32[]", + "internalType": "bytes32[]" + } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getNonce", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getPermissionIDs", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "permissionIds", + "type": "bytes32[]", + "internalType": "PermissionId[]" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getPermissionId", + "inputs": [ + { + "name": "session", + "type": "tuple", + "internalType": "struct Session", + "components": [ + { + "name": "sessionValidator", + "type": "address", + "internalType": "contract ISessionValidator" + }, + { + "name": "sessionValidatorInitData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "erc7739Policies", + "type": "tuple", + "internalType": "struct ERC7739Data", + "components": [ + { + "name": "allowedERC7739Content", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNames", + "type": "string[]", + "internalType": "string[]" + } + ] + }, + { + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "actions", + "type": "tuple[]", + "internalType": "struct ActionData[]", + "components": [ + { + "name": "actionTargetSelector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "actionTarget", + "type": "address", + "internalType": "address" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "permitERC4337Paymaster", + "type": "bool", + "internalType": "bool" + } + ] + } + ], + "outputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "getSessionDigest", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "data", + "type": "tuple", + "internalType": "struct Session", + "components": [ + { + "name": "sessionValidator", + "type": "address", + "internalType": "contract ISessionValidator" + }, + { + "name": "sessionValidatorInitData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "erc7739Policies", + "type": "tuple", + "internalType": "struct ERC7739Data", + "components": [ + { + "name": "allowedERC7739Content", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNames", + "type": "string[]", + "internalType": "string[]" + } + ] + }, + { + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "actions", + "type": "tuple[]", + "internalType": "struct ActionData[]", + "components": [ + { + "name": "actionTargetSelector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "actionTarget", + "type": "address", + "internalType": "address" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "permitERC4337Paymaster", + "type": "bool", + "internalType": "bool" + } + ] + }, + { + "name": "mode", + "type": "uint8", + "internalType": "enum SmartSessionMode" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getSessionValidatorAndConfig", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ], + "outputs": [ + { + "name": "sessionValidator", + "type": "address", + "internalType": "address" + }, + { + "name": "sessionValidatorData", + "type": "bytes", + "internalType": "bytes" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getUserOpPolicies", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ], + "outputs": [ + { + "name": "", + "type": "address[]", + "internalType": "address[]" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isActionIdEnabled", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "actionId", + "type": "bytes32", + "internalType": "ActionId" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isActionPolicyEnabled", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "actionId", + "type": "bytes32", + "internalType": "ActionId" + }, + { + "name": "policy", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isERC1271PolicyEnabled", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "policy", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isERC7739ContentEnabled", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "content", + "type": "string", + "internalType": "string" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isISessionValidatorSet", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isInitialized", + "inputs": [ + { + "name": "smartAccount", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isModuleType", + "inputs": [ + { + "name": "typeID", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "isPermissionEnabled", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isUserOpPolicyEnabled", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "policy", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isValidSignatureWithSender", + "inputs": [ + { + "name": "sender", + "type": "address", + "internalType": "address" + }, + { + "name": "hash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "signature", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "result", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "onInstall", + "inputs": [ + { + "name": "data", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "onUninstall", + "inputs": [ + { + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "removeSession", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "revokeEnableSignature", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setPermit4337Paymaster", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "enabled", + "type": "bool", + "internalType": "bool" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "validateUserOp", + "inputs": [ + { + "name": "userOp", + "type": "tuple", + "internalType": "struct PackedUserOperation", + "components": [ + { + "name": "sender", + "type": "address", + "internalType": "address" + }, + { + "name": "nonce", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "initCode", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "callData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "accountGasLimits", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "preVerificationGas", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "gasFees", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "paymasterAndData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "signature", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "userOpHash", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [ + { + "name": "vd", + "type": "uint256", + "internalType": "ValidationData" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "ActionIdDisabled", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" + }, + { + "name": "actionId", + "type": "bytes32", + "indexed": false, + "internalType": "ActionId" + }, + { + "name": "smartAccount", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "NonceIterated", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" + }, + { + "name": "account", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "newValue", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "PermissionIdPermit4337Paymaster", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" + }, + { + "name": "smartAccount", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "enabled", + "type": "bool", + "indexed": false, + "internalType": "bool" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "PolicyDisabled", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" + }, + { + "name": "policyType", + "type": "uint8", + "indexed": false, + "internalType": "enum PolicyType" + }, + { + "name": "policy", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "smartAccount", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "PolicyEnabled", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" + }, + { + "name": "policyType", + "type": "uint8", + "indexed": false, + "internalType": "enum PolicyType" + }, + { + "name": "policy", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "smartAccount", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "SessionCreated", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" + }, + { + "name": "account", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "SessionRemoved", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" + }, + { + "name": "smartAccount", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "SessionValidatorDisabled", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" + }, + { + "name": "sessionValidator", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "smartAccount", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "SessionValidatorEnabled", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" + }, + { + "name": "sessionValidator", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "smartAccount", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "AssociatedArray_OutOfBounds", + "inputs": [ + { + "name": "index", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "ChainIdMismatch", + "inputs": [ + { + "name": "providedChainId", + "type": "uint64", + "internalType": "uint64" + } + ] + }, + { + "type": "error", + "name": "ChainIdMismatch", + "inputs": [ + { + "name": "providedChainId", + "type": "uint64", + "internalType": "uint64" + } + ] + }, + { + "type": "error", + "name": "ForbiddenValidationData", + "inputs": [] + }, + { + "type": "error", + "name": "HashIndexOutOfBounds", + "inputs": [ + { + "name": "index", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "HashMismatch", + "inputs": [ + { + "name": "providedHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "computedHash", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "HashMismatch", + "inputs": [ + { + "name": "providedHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "computedHash", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "InvalidActionId", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidCallTarget", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidData", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidEnableSignature", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "hash", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "InvalidISessionValidator", + "inputs": [ + { + "name": "sessionValidator", + "type": "address", + "internalType": "contract ISessionValidator" + } + ] + }, + { + "type": "error", + "name": "InvalidMode", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidPermissionId", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ] + }, + { + "type": "error", + "name": "InvalidSelfCall", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidSession", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ] + }, + { + "type": "error", + "name": "InvalidSessionKeySignature", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "sessionValidator", + "type": "address", + "internalType": "address" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "userOpHash", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "InvalidTarget", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidUserOpSender", + "inputs": [ + { + "name": "sender", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "NoExecutionsInBatch", + "inputs": [] + }, + { + "type": "error", + "name": "NoPoliciesSet", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ] + }, + { + "type": "error", + "name": "PartlyEnabledActions", + "inputs": [] + }, + { + "type": "error", + "name": "PartlyEnabledPolicies", + "inputs": [] + }, + { + "type": "error", + "name": "PaymasterValidationNotEnabled", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ] + }, + { + "type": "error", + "name": "PolicyViolation", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "policy", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "SignerNotFound", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "SignerNotFound", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "SmartSessionModuleAlreadyInstalled", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "UnsupportedCallType", + "inputs": [ + { + "name": "callType", + "type": "bytes1", + "internalType": "CallType" + } + ] + }, + { + "type": "error", + "name": "UnsupportedExecutionType", + "inputs": [] + }, + { + "type": "error", + "name": "UnsupportedPolicy", + "inputs": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "UnsupportedSmartSessionMode", + "inputs": [ + { + "name": "mode", + "type": "uint8", + "internalType": "enum SmartSessionMode" + } + ] + } +] as const; diff --git a/packages/core/src/lib/agentic/contracts/abi/e704d5b/universal-rules-policy.ts b/packages/core/src/lib/agentic/contracts/abi/e704d5b/universal-rules-policy.ts new file mode 100644 index 00000000..8cf26e68 --- /dev/null +++ b/packages/core/src/lib/agentic/contracts/abi/e704d5b/universal-rules-policy.ts @@ -0,0 +1,2065 @@ +// GENERATED by packages/core/scripts/agw-local/gen-abi.mjs — do not edit. +// Source: plan/agw/research/validation-e704d5b/abi/UniversalRulesPolicy.json +// push-agentic-wallets@e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9 +// sha256(UniversalRulesPolicy.json) = 8301b452b035d12d03ff1861940b895128a40eaf280fb6d3ae30ffc46c5ae86d +export const UNIVERSAL_RULES_POLICY_ABI = [ + { + "type": "function", + "name": "SEND_OUTBOUND_SELECTOR", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "SESSION_ENGINE", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "UNIVERSAL_EXECUTOR_MODULE", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "UNIVERSAL_GATEWAY_PC", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "assertSpent", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "expectedValueSpent", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "expectedAmountSpent", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "expectedCalls", + "type": "uint32", + "internalType": "uint32" + } + ], + "outputs": [], + "stateMutability": "view" + }, + { + "type": "function", + "name": "assertSpent", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "expectedSpent", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "view" + }, + { + "type": "function", + "name": "checkAction", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "target", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "data", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "creditRevert", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "outboundTxId", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "getConfig", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "tuple", + "internalType": "struct Config", + "components": [ + { + "name": "initialized", + "type": "bool", + "internalType": "bool" + }, + { + "name": "validUntil", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "destChainHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "expectedCEA", + "type": "address", + "internalType": "address" + }, + { + "name": "asset", + "type": "address", + "internalType": "address" + }, + { + "name": "maxAmountPerCall", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxAmountTotal", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxPCPerCall", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "spent", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "allowedCalls", + "type": "tuple[]", + "internalType": "struct AllowedCall[]", + "components": [ + { + "name": "target", + "type": "address", + "internalType": "address" + }, + { + "name": "selector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "beneficiaryOffset", + "type": "uint16", + "internalType": "uint16" + }, + { + "name": "hasBeneficiary", + "type": "bool", + "internalType": "bool" + }, + { + "name": "maxValue", + "type": "uint256", + "internalType": "uint256" + } + ] + } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getMode", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "tuple", + "internalType": "struct ModeSlot", + "components": [ + { + "name": "initialized", + "type": "bool", + "internalType": "bool" + }, + { + "name": "mode", + "type": "uint8", + "internalType": "enum RulesType" + }, + { + "name": "vm", + "type": "uint8", + "internalType": "enum VmFamily" + }, + { + "name": "chainHash", + "type": "bytes32", + "internalType": "bytes32" + } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getNativeConfig", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "tuple", + "internalType": "struct NativeConfig", + "components": [ + { + "name": "initialized", + "type": "bool", + "internalType": "bool" + }, + { + "name": "validUntil", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "target", + "type": "address", + "internalType": "address" + }, + { + "name": "selector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "maxValuePerCall", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxValueTotal", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "valueSpent", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amount", + "type": "tuple", + "internalType": "struct AmountRule", + "components": [ + { + "name": "enabled", + "type": "bool", + "internalType": "bool" + }, + { + "name": "offset", + "type": "uint16", + "internalType": "uint16" + }, + { + "name": "maxPerCall", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxTotal", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "amountSpent", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxCalls", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "callsUsed", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "pins", + "type": "tuple[]", + "internalType": "struct ArgPin[]", + "components": [ + { + "name": "offset", + "type": "uint16", + "internalType": "uint16" + }, + { + "name": "expected", + "type": "bytes32", + "internalType": "bytes32" + } + ] + } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getSvmConfig", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "tuple", + "internalType": "struct SvmConfig", + "components": [ + { + "name": "initialized", + "type": "bool", + "internalType": "bool" + }, + { + "name": "validUntil", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "expectedCEA", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "gatewayProgram", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "asset", + "type": "address", + "internalType": "address" + }, + { + "name": "maxAmountPerCall", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxAmountTotal", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxPCPerCall", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "spent", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "ceaAccounts", + "type": "bytes32[]", + "internalType": "bytes32[]" + }, + { + "name": "programs", + "type": "tuple[]", + "internalType": "struct AllowedProgram[]", + "components": [ + { + "name": "program", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "discriminator", + "type": "bytes8", + "internalType": "bytes8" + }, + { + "name": "discriminatorLen", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "dataless", + "type": "bool", + "internalType": "bool" + }, + { + "name": "maxAccounts", + "type": "uint8", + "internalType": "uint8" + } + ] + }, + { + "name": "pins", + "type": "tuple[]", + "internalType": "struct SvmAccountPin[]", + "components": [ + { + "name": "ruleIndex", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "accountIndex", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "expected", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "name": "dataPins", + "type": "tuple[]", + "internalType": "struct SvmDataPin[]", + "components": [ + { + "name": "ruleIndex", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "fromEnd", + "type": "bool", + "internalType": "bool" + }, + { + "name": "offset", + "type": "uint16", + "internalType": "uint16" + }, + { + "name": "offsetB", + "type": "uint16", + "internalType": "uint16" + }, + { + "name": "len", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "mode", + "type": "uint8", + "internalType": "enum SvmDataPinMode" + }, + { + "name": "expected", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "num", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "den", + "type": "uint64", + "internalType": "uint64" + } + ] + } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "initialize", + "inputs": [ + { + "name": "universalGatewayPC", + "type": "address", + "internalType": "address" + }, + { + "name": "universalExecutorModule", + "type": "address", + "internalType": "address" + }, + { + "name": "sessionEngine", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "initializeWithMultiplexer", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "configId", + "type": "bytes32", + "internalType": "ConfigId" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "isCredited", + "inputs": [ + { + "name": "outboundTxId", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "pushChainHash", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "supportsInterface", + "inputs": [ + { + "name": "iid", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "version", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "pure" + }, + { + "type": "event", + "name": "Initialized", + "inputs": [ + { + "name": "version", + "type": "uint64", + "indexed": false, + "internalType": "uint64" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "NativeCallMetered", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "indexed": true, + "internalType": "ConfigId" + }, + { + "name": "multiplexer", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "OutboundMetered", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "indexed": true, + "internalType": "ConfigId" + }, + { + "name": "multiplexer", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "PolicySet", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "indexed": false, + "internalType": "ConfigId" + }, + { + "name": "multiplexer", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "account", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RevertCredited", + "inputs": [ + { + "name": "outboundTxId", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "id", + "type": "bytes32", + "indexed": true, + "internalType": "ConfigId" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "amountApplied", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RulesConfigured", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "indexed": true, + "internalType": "ConfigId" + }, + { + "name": "multiplexer", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "mode", + "type": "uint8", + "indexed": false, + "internalType": "enum RulesType" + }, + { + "name": "vm", + "type": "uint8", + "indexed": false, + "internalType": "enum VmFamily" + }, + { + "name": "chainHash", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "AllowListOutOfRange", + "inputs": [ + { + "name": "length", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "AlreadyCredited", + "inputs": [ + { + "name": "outboundTxId", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "AlreadyInitialized", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" + } + ] + }, + { + "type": "error", + "name": "AmbiguousRule", + "inputs": [ + { + "name": "i", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "j", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "AmountExceedsCap", + "inputs": [ + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "cap", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "AmountExceedsU64", + "inputs": [ + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "ArgPinMismatch", + "inputs": [ + { + "name": "actual", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "index", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "expected", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "AssetMismatch", + "inputs": [ + { + "name": "expected", + "type": "address", + "internalType": "address" + }, + { + "name": "actual", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "BatchSizeOutOfRange", + "inputs": [ + { + "name": "count", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "BeneficiaryMismatch", + "inputs": [ + { + "name": "expected", + "type": "address", + "internalType": "address" + }, + { + "name": "actual", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "CallLimitReached", + "inputs": [ + { + "name": "callsUsed", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "maxCalls", + "type": "uint32", + "internalType": "uint32" + } + ] + }, + { + "type": "error", + "name": "CallNotAllowed", + "inputs": [ + { + "name": "target", + "type": "address", + "internalType": "address" + }, + { + "name": "selector", + "type": "bytes4", + "internalType": "bytes4" + } + ] + }, + { + "type": "error", + "name": "CalldataTooShort", + "inputs": [ + { + "name": "length", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "CalldataTooShortForAmount", + "inputs": [ + { + "name": "actualLength", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "needed", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "CalldataTooShortForPin", + "inputs": [ + { + "name": "actualLength", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "index", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "needed", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "CallerIsNotUEModule", + "inputs": [ + { + "name": "caller", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "CeaAccountAtUnpinnedIndex", + "inputs": [ + { + "name": "accountIndex", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "account", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "CeaAccountsMissExpectedCEA", + "inputs": [] + }, + { + "type": "error", + "name": "ChainMismatch", + "inputs": [ + { + "name": "declared", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "assetChain", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "DiscriminatorLenOutOfRange", + "inputs": [ + { + "name": "rule", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "len", + "type": "uint8", + "internalType": "uint8" + } + ] + }, + { + "type": "error", + "name": "DuplicateSvmPin", + "inputs": [ + { + "name": "first", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "second", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "EmptyChain", + "inputs": [] + }, + { + "type": "error", + "name": "ForbiddenInnerTarget", + "inputs": [ + { + "name": "target", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ForbiddenProgramInAllowList", + "inputs": [ + { + "name": "rule", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "program", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "ForbiddenTargetProgram", + "inputs": [ + { + "name": "program", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "InnerValueExceedsAllowance", + "inputs": [ + { + "name": "index", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxValue", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "InvalidAsset", + "inputs": [ + { + "name": "asset", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "InvalidCeaAccount", + "inputs": [ + { + "name": "index", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "InvalidConfigField", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidExpiry", + "inputs": [ + { + "name": "validUntil", + "type": "uint48", + "internalType": "uint48" + } + ] + }, + { + "type": "error", + "name": "InvalidInitialization", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidRevertRecipient", + "inputs": [ + { + "name": "expected", + "type": "address", + "internalType": "address" + }, + { + "name": "actual", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "InvalidSelector", + "inputs": [ + { + "name": "selector", + "type": "bytes4", + "internalType": "bytes4" + } + ] + }, + { + "type": "error", + "name": "InvalidSvmConfigField", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidTarget", + "inputs": [ + { + "name": "target", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "MalformedInnerCalldata", + "inputs": [] + }, + { + "type": "error", + "name": "MalformedOutboundRequest", + "inputs": [ + { + "name": "length", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "MalformedSvmPayload", + "inputs": [ + { + "name": "code", + "type": "uint8", + "internalType": "uint8" + } + ] + }, + { + "type": "error", + "name": "NativeAmountExceedsCap", + "inputs": [ + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "cap", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "NativeTargetIsGateway", + "inputs": [ + { + "name": "target", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "NativeTargetZero", + "inputs": [] + }, + { + "type": "error", + "name": "NotInitialized", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "NotInitializing", + "inputs": [] + }, + { + "type": "error", + "name": "PCValueExceedsCap", + "inputs": [ + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "cap", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "PayloadNotMulticall", + "inputs": [] + }, + { + "type": "error", + "name": "PolicyNotInitialized", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" + }, + { + "name": "multiplexer", + "type": "address", + "internalType": "address" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ProgramListOutOfRange", + "inputs": [ + { + "name": "length", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "ProgramNotAllowed", + "inputs": [ + { + "name": "program", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "discriminator", + "type": "bytes8", + "internalType": "bytes8" + } + ] + }, + { + "type": "error", + "name": "RecipientMustBeEmpty", + "inputs": [] + }, + { + "type": "error", + "name": "RecipientNotPubkey", + "inputs": [ + { + "name": "length", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "RecipientTargetMismatch", + "inputs": [ + { + "name": "recipient", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "target", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "RuleWithoutPin", + "inputs": [ + { + "name": "rule", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "RulesExpired", + "inputs": [ + { + "name": "validUntil", + "type": "uint48", + "internalType": "uint48" + } + ] + }, + { + "type": "error", + "name": "SelectorMismatch", + "inputs": [ + { + "name": "actual", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "expected", + "type": "bytes4", + "internalType": "bytes4" + } + ] + }, + { + "type": "error", + "name": "SpentMismatch", + "inputs": [ + { + "name": "expected", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "actual", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "SvmAccountCountBelowPin", + "inputs": [ + { + "name": "pin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "count", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "needed", + "type": "uint8", + "internalType": "uint8" + } + ] + }, + { + "type": "error", + "name": "SvmAccountCountMismatch", + "inputs": [ + { + "name": "count", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "expected", + "type": "uint8", + "internalType": "uint8" + } + ] + }, + { + "type": "error", + "name": "SvmAccountPinMismatch", + "inputs": [ + { + "name": "pin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "accountIndex", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "expected", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "actual", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "SvmAccountsOutOfRange", + "inputs": [ + { + "name": "count", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "SvmDataCeilingExceeded", + "inputs": [ + { + "name": "pin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "actual", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "ceiling", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "SvmDataFloorNotMet", + "inputs": [ + { + "name": "pin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "actual", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "floor", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "SvmDataPinInvalid", + "inputs": [ + { + "name": "pin", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "SvmDataPinMismatch", + "inputs": [ + { + "name": "pin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "expected", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "actual", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "SvmDataRatioNotMet", + "inputs": [ + { + "name": "pin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "a", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "b", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "num", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "den", + "type": "uint64", + "internalType": "uint64" + } + ] + }, + { + "type": "error", + "name": "SvmDataTooShortForPin", + "inputs": [ + { + "name": "pin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "ixLen", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "SvmInstructionNotExecute", + "inputs": [ + { + "name": "instructionId", + "type": "uint8", + "internalType": "uint8" + } + ] + }, + { + "type": "error", + "name": "SvmIxDataTooLong", + "inputs": [ + { + "name": "length", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "SvmMaxAccountsOutOfRange", + "inputs": [ + { + "name": "rule", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxAccounts", + "type": "uint8", + "internalType": "uint8" + } + ] + }, + { + "type": "error", + "name": "SvmPayloadEmpty", + "inputs": [] + }, + { + "type": "error", + "name": "SvmPinIndexOutOfRange", + "inputs": [ + { + "name": "pin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "accountIndex", + "type": "uint8", + "internalType": "uint8" + } + ] + }, + { + "type": "error", + "name": "SvmPinRuleOutOfRange", + "inputs": [ + { + "name": "pin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "rule", + "type": "uint8", + "internalType": "uint8" + } + ] + }, + { + "type": "error", + "name": "TargetMismatch", + "inputs": [ + { + "name": "actual", + "type": "address", + "internalType": "address" + }, + { + "name": "expected", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "TooManyCeaAccounts", + "inputs": [ + { + "name": "count", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "TooManyPins", + "inputs": [ + { + "name": "count", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "TooManySvmDataPins", + "inputs": [ + { + "name": "count", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "TooManySvmPins", + "inputs": [ + { + "name": "count", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "TotalNativeAmountExceeded", + "inputs": [ + { + "name": "newSpent", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "cap", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "TotalSpendCapExceeded", + "inputs": [ + { + "name": "wouldBeTotal", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "cap", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "TotalValueExceeded", + "inputs": [ + { + "name": "newSpent", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "cap", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "UncappedGasSwapRejected", + "inputs": [] + }, + { + "type": "error", + "name": "UnsupportedNamespace", + "inputs": [ + { + "name": "chainHash", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "ValueExceedsCap", + "inputs": [ + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "cap", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "ValueOnlyCalldataNotEmpty", + "inputs": [ + { + "name": "length", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "ValueOnlyWithAmountRule", + "inputs": [] + }, + { + "type": "error", + "name": "ValueOnlyWithPins", + "inputs": [] + }, + { + "type": "error", + "name": "WrongModeForCall", + "inputs": [ + { + "name": "actual", + "type": "uint8", + "internalType": "enum RulesType" + } + ] + }, + { + "type": "error", + "name": "WrongVmForCall", + "inputs": [ + { + "name": "actual", + "type": "uint8", + "internalType": "enum VmFamily" + } + ] + }, + { + "type": "error", + "name": "ZeroAddress", + "inputs": [] + } +] as const; diff --git a/packages/core/src/lib/agentic/contracts/e704d5b.ts b/packages/core/src/lib/agentic/contracts/e704d5b.ts new file mode 100644 index 00000000..a5fed106 --- /dev/null +++ b/packages/core/src/lib/agentic/contracts/e704d5b.ts @@ -0,0 +1,294 @@ +import { + decodeAbiParameters, + decodeEventLog, + decodeFunctionData, + encodeAbiParameters, + encodeFunctionData, + encodePacked, + getAbiItem, + getAddress, + toEventSelector, + type AbiEvent, + type Address, + type Hex, + type Log, +} from 'viem'; +import { + AGW_ABI, + AGW_FACTORY_ABI, + SMART_SESSION_ABI, + UNIVERSAL_RULES_POLICY_ABI, +} from './abi/e704d5b'; +import type { SessionWire } from '../codec/session'; +import type { CheckpointKind } from '../agentic.types'; +import type { NativeTermsWire } from '../codec/native'; + +/** + * Contract adapter for the reviewed e704d5b ABI generation. All version- + * sensitive encoding, decoding and view names live here; callers never touch + * a raw ABI. A future generation gets its own adapter implementing the same + * interface. + */ + +export interface Call { + target: Address; + value: bigint; + data: Hex; +} + +export const MODE_SINGLE = `0x${'00'.repeat(32)}` as Hex; +export const MODE_BATCH = `0x01${'00'.repeat(31)}` as Hex; +export const SEND_OUTBOUND_SELECTOR = '0x77b86bec' as const; +export const UEA_MULTICALL_PREFIX = '0x2cc2842d' as const; + +const CHECKPOINT_KINDS: readonly CheckpointKind[] = [ + 'OWNER_ACTION', + 'RULES_GRANTED', + 'RULES_REVOKED', +]; + +export interface NativeConfigRead extends NativeTermsWire { + initialized: boolean; + valueSpent: bigint; + amountSpent: bigint; + callsUsed: number; +} + +export interface ModeRead { + initialized: boolean; + /** 0 = UNIVERSAL, 1 = NATIVE (RulesType). */ + mode: number; + /** 0 = EVM, 1 = SVM (VmFamily). */ + vm: number; + chainHash: Hex; +} + +/** Historical single-asset universal config (getConfig) — review generation only. */ +export interface UniversalConfigReadE704d5b { + initialized: boolean; + validUntil: number; + destChainHash: Hex; + expectedCEA: Address; + asset: Address; + maxAmountPerCall: bigint; + maxAmountTotal: bigint; + maxPCPerCall: bigint; + spent: bigint; +} + +export type DecodedWalletCall = + | { kind: 'execute'; mode: Hex; calls: Call[] } + | { kind: 'executeAsAgent'; rulesId: Hex; mode: Hex; calls: Call[] } + | { kind: 'grantRules'; session: SessionWire } + | { kind: 'revokeRules'; rulesId: Hex } + | { kind: 'revokeAllRules' }; + +const EXECUTION_TUPLE = [ + { + type: 'tuple[]', + components: [ + { name: 'target', type: 'address' }, + { name: 'value', type: 'uint256' }, + { name: 'callData', type: 'bytes' }, + ], + }, +] as const; + +export const e704d5b = { + id: 'e704d5b', + abis: { + wallet: AGW_ABI, + factory: AGW_FACTORY_ABI, + engine: SMART_SESSION_ABI, + policy: UNIVERSAL_RULES_POLICY_ABI, + }, + events: { + walletDeployed: getAbiItem({ abi: AGW_FACTORY_ABI, name: 'WalletDeployed' }) as AbiEvent, + checkpointed: getAbiItem({ abi: AGW_ABI, name: 'Checkpointed' }) as AbiEvent, + rulesGranted: getAbiItem({ abi: AGW_ABI, name: 'RulesGranted' }) as AbiEvent, + rulesRevoked: getAbiItem({ abi: AGW_ABI, name: 'RulesRevoked' }) as AbiEvent, + }, + + // ---------------------------------------------------------------- encoders + encodeDeployWallet(label: string): Hex { + return encodeFunctionData({ abi: AGW_FACTORY_ABI, functionName: 'deployWallet', args: [label] }); + }, + encodeGrantRules(session: SessionWire): Hex { + return encodeFunctionData({ + abi: AGW_ABI, + functionName: 'grantRules', + args: [session as never], + }); + }, + encodeRevokeRules(rulesId: Hex): Hex { + return encodeFunctionData({ abi: AGW_ABI, functionName: 'revokeRules', args: [rulesId] }); + }, + encodeRevokeAllRules(): Hex { + return encodeFunctionData({ abi: AGW_ABI, functionName: 'revokeAllRules', args: [] }); + }, + /** ERC-7579 single execution calldata: abi.encodePacked(target, value, callData). */ + packSingle(call: Call): Hex { + return encodePacked(['address', 'uint256', 'bytes'], [call.target, call.value, call.data]); + }, + encodeExecute(calls: Call[]): Hex { + if (calls.length === 0) throw new Error('execute needs at least one call'); + if (calls.length === 1) { + return encodeFunctionData({ + abi: AGW_ABI, + functionName: 'execute', + args: [MODE_SINGLE, e704d5b.packSingle(calls[0])], + }); + } + const batch = encodeAbiParameters(EXECUTION_TUPLE, [ + calls.map((c) => ({ target: c.target, value: c.value, callData: c.data })), + ]); + return encodeFunctionData({ abi: AGW_ABI, functionName: 'execute', args: [MODE_BATCH, batch] }); + }, + encodeExecuteAsAgent(rulesId: Hex, call: Call): Hex { + return encodeFunctionData({ + abi: AGW_ABI, + functionName: 'executeAsAgent', + args: [rulesId, MODE_SINGLE, e704d5b.packSingle(call)], + }); + }, + encodeAssertSpentNative( + configId: Hex, + wallet: Address, + expected: { valueSpent: bigint; amountSpent: bigint; callsUsed: number } + ): Hex { + return encodeFunctionData({ + abi: UNIVERSAL_RULES_POLICY_ABI, + functionName: 'assertSpent', + args: [configId, wallet, expected.valueSpent, expected.amountSpent, expected.callsUsed], + }); + }, + + // ---------------------------------------------------------------- decoders + decodeWalletCall(data: Hex): DecodedWalletCall | null { + let decoded; + try { + decoded = decodeFunctionData({ abi: AGW_ABI, data }); + } catch { + return null; + } + switch (decoded.functionName) { + case 'execute': { + const [mode, ecd] = decoded.args as readonly [Hex, Hex]; + return { kind: 'execute', mode, calls: unpackExecution(mode, ecd) }; + } + case 'executeAsAgent': { + const [rulesId, mode, ecd] = decoded.args as readonly [Hex, Hex, Hex]; + return { kind: 'executeAsAgent', rulesId, mode, calls: unpackExecution(mode, ecd) }; + } + case 'grantRules': + return { kind: 'grantRules', session: decoded.args[0] as unknown as SessionWire }; + case 'revokeRules': + return { kind: 'revokeRules', rulesId: decoded.args[0] as Hex }; + case 'revokeAllRules': + return { kind: 'revokeAllRules' }; + default: + return null; + } + }, + decodeCheckpointKind(kind: number): CheckpointKind { + const k = CHECKPOINT_KINDS[kind]; + if (!k) throw new Error(`unknown checkpoint kind ${kind}`); + return k; + }, + parseWalletDeployed(logs: readonly Log[], factory: Address) { + return decodeMatching(logs, factory, e704d5b.events.walletDeployed).map((args) => ({ + owner: getAddress(args['owner'] as Address), + index: BigInt(args['index'] as bigint), + wallet: getAddress(args['wallet'] as Address), + label: args['label'] as string, + })); + }, + parseRulesGranted(logs: readonly Log[], wallet: Address) { + return decodeMatching(logs, wallet, e704d5b.events.rulesGranted).map((args) => ({ + rulesId: args['rulesId'] as Hex, + mode: Number(args['mode']), + chainNamespace: args['chainNamespace'] as string, + })); + }, + parseRulesRevoked(logs: readonly Log[], wallet: Address) { + return decodeMatching(logs, wallet, e704d5b.events.rulesRevoked).map((args) => ({ + rulesId: args['rulesId'] as Hex, + })); + }, + parseCheckpointed(logs: readonly Log[], wallet: Address) { + return logs + .filter( + (l) => + sameAddress(l.address, wallet) && + l.topics[0]?.toLowerCase() === toEventSelector(e704d5b.events.checkpointed).toLowerCase() + ) + .flatMap((log) => { + try { + const ev = decodeEventLog({ abi: [e704d5b.events.checkpointed], ...log, strict: true }); + return [{ log, args: ev.args as unknown as Record }]; + } catch { + return []; + } + }) + .map(({ log, args }) => ({ + seq: Number(args['seq']), + kind: e704d5b.decodeCheckpointKind(Number(args['kind'])), + ref: args['ref'] as Hex, + blockNumber: BigInt(log.blockNumber ?? BigInt(0)), + txHash: log.transactionHash as Hex, + logIndex: Number(log.logIndex ?? 0), + transactionIndex: Number(log.transactionIndex ?? 0), + })); + }, +}; + +function unpackExecution(mode: Hex, ecd: Hex): Call[] { + const callType = mode.slice(2, 4); + if (callType === '00') { + const bytes = ecd.slice(2); + return [ + { + target: getAddress(`0x${bytes.slice(0, 40)}`), + value: BigInt(`0x${bytes.slice(40, 104) || '0'}`), + data: `0x${bytes.slice(104)}` as Hex, + }, + ]; + } + if (callType === '01') { + const [execs] = decodeAbiParameters(EXECUTION_TUPLE, ecd); + return execs.map((e) => ({ + target: getAddress(e.target), + value: e.value, + data: e.callData as Hex, + })); + } + return []; +} + +function sameAddress(a: string | null | undefined, b: string): boolean { + return !!a && a.toLowerCase() === b.toLowerCase(); +} + +function decodeMatching( + logs: readonly Log[], + emitter: Address, + event: AbiEvent +): Record[] { + // viem's decodeEventLog skips the topic0 check when given a one-event ABI, + // so the event signature is matched explicitly here. + const topic0 = toEventSelector(event).toLowerCase(); + const out: Record[] = []; + for (const log of logs) { + if (!sameAddress(log.address, emitter)) continue; + if (log.topics[0]?.toLowerCase() !== topic0) continue; + try { + const ev = decodeEventLog({ abi: [event], data: log.data, topics: log.topics, strict: true }); + out.push(ev.args as unknown as Record); + } catch { + // not this event + } + } + return out; +} + +export type AgwContracts = typeof e704d5b; diff --git a/packages/core/src/lib/agentic/contracts/reader.ts b/packages/core/src/lib/agentic/contracts/reader.ts new file mode 100644 index 00000000..7b978068 --- /dev/null +++ b/packages/core/src/lib/agentic/contracts/reader.ts @@ -0,0 +1,42 @@ +import type { Abi, AbiEvent, Address, Hex, Log, PublicClient, TransactionReceipt } from 'viem'; + +/** + * The narrow chain-read surface the AGW module needs. Tests mock it; the SDK + * adapts the Push client's viem PublicClient. Every snapshot read passes an + * explicit `blockNumber` so dependent reads observe one state. + */ +export interface ChainReader { + readContract(args: { + address: Address; + abi: Abi | readonly unknown[]; + functionName: string; + args?: readonly unknown[]; + blockNumber?: bigint; + }): Promise; + getBlockNumber(): Promise; + getCode(args: { address: Address; blockNumber?: bigint }): Promise; + getBalance(args: { address: Address; blockNumber?: bigint }): Promise; + getLogs(args: { + address: Address; + event: AbiEvent; + args?: Record; + fromBlock: bigint; + toBlock: bigint; + }): Promise; + getTransactionReceipt(args: { hash: Hex }): Promise; +} + +export function chainReaderFromPublicClient(client: PublicClient): ChainReader { + // viem's generics are narrower than this module's needs; the casts are + // confined to this adapter. + return { + readContract: (args) => + client.readContract(args as Parameters[0]), + getBlockNumber: () => client.getBlockNumber({ cacheTime: 0 }), + getCode: (args) => client.getCode(args), + getBalance: (args) => client.getBalance(args), + getLogs: (args) => + client.getLogs(args as Parameters[0]) as Promise, + getTransactionReceipt: (args) => client.getTransactionReceipt(args), + }; +} diff --git a/packages/core/src/lib/agentic/deployments.ts b/packages/core/src/lib/agentic/deployments.ts new file mode 100644 index 00000000..c2efe09b --- /dev/null +++ b/packages/core/src/lib/agentic/deployments.ts @@ -0,0 +1,233 @@ +import { getAddress, type Address } from 'viem'; +import { PUSH_NETWORK } from '../constants/enums'; +import { AgenticCapability } from './capabilities'; +import { e704d5b, type AgwContracts } from './contracts/e704d5b'; +import type { ChainReader } from './contracts/reader'; +import { AGENTIC_ERROR_CODE, AgenticError } from './errors'; + +/** + * A verified AGW contract generation on one Push network. The registry is the + * ONLY source of AGW addresses in the SDK: no address is hard-coded anywhere + * else, and historical Donut deployments (generation 67929f2, grantMandate) + * are NOT registered because they do not implement this ABI. + */ +export interface AgenticGeneration { + /** Stable identifier, e.g. 'e704d5b'. */ + id: string; + /** Contract source commit the ABI was generated from. */ + sourceCommit: string; + network: PUSH_NETWORK; + /** false = review fixture (local harness); never advertised as a release deployment. */ + advertised: boolean; + addresses: { + factory: Address; + walletImplementation: Address; + sessionEngine: Address; + rulesPolicy: Address; + sessionValidator: Address; + gateway: Address; + }; + /** First block to scan for factory/wallet events. */ + startBlock: bigint; + /** Expected wallet accountId(). */ + accountId: string; + capabilities: ReadonlySet; + contracts: AgwContracts; +} + +/** Capabilities the e704d5b ABI actually implements. Target-only features are absent. */ +export const E704D5B_CAPABILITIES: ReadonlySet = new Set([ + AgenticCapability.WALLET_READS, + AgenticCapability.ACTIVE_RULE_READS, + AgenticCapability.OWNER_EXECUTE, + AgenticCapability.AGENT_EXECUTE, + AgenticCapability.NATIVE_RULES, + AgenticCapability.ASSERT_SPENT_NATIVE, + AgenticCapability.CHECKPOINTS, + AgenticCapability.UNIVERSAL_EVM_OUTBOUND, +]); + +/** + * Verified release deployments. EMPTY: no deployment of a compatible + * generation has been verified on any Push network (assumption A07). + */ +const VERIFIED_DEPLOYMENTS: readonly AgenticGeneration[] = []; + +const registry: AgenticGeneration[] = [...VERIFIED_DEPLOYMENTS]; + +/** + * @internal Register a generation that is NOT a verified release deployment — + * the local contract harness and E2E manifest loader use this. Not exported + * from the package entry point. + */ +export function registerAgenticGeneration( + input: Omit & { + capabilities?: ReadonlySet; + } +): AgenticGeneration { + if (input.id !== e704d5b.id) { + throw new AgenticError( + AGENTIC_ERROR_CODE.GENERATION_UNSUPPORTED, + `no contract adapter for generation "${input.id}"` + ); + } + const gen: AgenticGeneration = { + ...input, + addresses: { + factory: getAddress(input.addresses.factory), + walletImplementation: getAddress(input.addresses.walletImplementation), + sessionEngine: getAddress(input.addresses.sessionEngine), + rulesPolicy: getAddress(input.addresses.rulesPolicy), + sessionValidator: getAddress(input.addresses.sessionValidator), + gateway: getAddress(input.addresses.gateway), + }, + capabilities: input.capabilities ?? E704D5B_CAPABILITIES, + contracts: e704d5b, + }; + const existing = registry.findIndex( + (g) => g.network === gen.network && g.addresses.factory === gen.addresses.factory + ); + if (existing >= 0) registry.splice(existing, 1); + registry.push(gen); + verifiedWiring.clear(); + return gen; +} + +/** @internal Test/harness cleanup. Restores the verified (empty) registry. */ +export function resetAgenticGenerations(): void { + registry.splice(0, registry.length, ...VERIFIED_DEPLOYMENTS); + verifiedWiring.clear(); +} + +export function generationsFor(network: PUSH_NETWORK): readonly AgenticGeneration[] { + return registry.filter((g) => g.network === network); +} + +/** The generation new wallets are created on for this network. */ +export function currentGeneration(network: PUSH_NETWORK): AgenticGeneration { + const gens = generationsFor(network); + const gen = gens[gens.length - 1]; + if (!gen) { + throw new AgenticError( + AGENTIC_ERROR_CODE.GENERATION_UNSUPPORTED, + `no verified AGW deployment is registered for ${network}`, + { + hint: 'AGW support needs a verified compatible deployment manifest (A07). Historical Donut AGW addresses use a different, unsupported ABI.', + details: { network, assumption: 'A07' }, + } + ); + } + return gen; +} + +/** Generation infrastructure a native rule may not target (the wallet itself is added per call). */ +export function forbiddenTargets(gen: AgenticGeneration, wallet?: Address): Address[] { + const a = gen.addresses; + return [a.factory, a.sessionEngine, a.rulesPolicy, a.sessionValidator, a.gateway, ...(wallet ? [wallet] : [])]; +} + +const verifiedWiring = new Map>(); + +/** Confirms the factory still points at the registered implementation (cached per generation). */ +export function verifyFactoryWiring(reader: ChainReader, gen: AgenticGeneration): Promise { + const key = `${gen.network}:${gen.addresses.factory}:${gen.addresses.walletImplementation}`; + let p = verifiedWiring.get(key); + if (!p) { + p = (async () => { + const impl = (await reader.readContract({ + address: gen.addresses.factory, + abi: gen.contracts.abis.factory, + functionName: 'walletImplementation', + })) as Address; + if (getAddress(impl) !== gen.addresses.walletImplementation) { + throw new AgenticError( + AGENTIC_ERROR_CODE.GENERATION_UNSUPPORTED, + `factory ${gen.addresses.factory} points at implementation ${impl}, not the registered ${gen.addresses.walletImplementation}` + ); + } + })(); + p.catch(() => verifiedWiring.delete(key)); + verifiedWiring.set(key, p); + } + return p; +} + +/** + * Resolve and verify the generation of a deployed wallet: + * code present → factory() is a registered factory → factory.isWallet(wallet) + * → immutable wiring and accountId match the registered generation. + */ +export async function resolveWalletGeneration( + reader: ChainReader, + network: PUSH_NETWORK, + wallet: Address +): Promise { + const gens = generationsFor(network); + if (gens.length === 0) currentGeneration(network); // throws GENERATION_UNSUPPORTED (A07) + + const code = await reader.getCode({ address: wallet }); + if (!code || code === '0x') { + throw new AgenticError( + AGENTIC_ERROR_CODE.WALLET_NOT_DEPLOYED, + `no contract is deployed at ${wallet}`, + { hint: 'Deploy it with client.agentic.create, or check the address and network.' } + ); + } + let factory: Address; + try { + factory = getAddress( + (await reader.readContract({ + address: wallet, + abi: e704d5b.abis.wallet, + functionName: 'factory', + })) as Address + ); + } catch (cause) { + throw new AgenticError( + AGENTIC_ERROR_CODE.NOT_AGENTIC_WALLET, + `${wallet} does not expose an AGW factory()`, + { cause } + ); + } + const gen = gens.find((g) => g.addresses.factory === factory); + if (!gen) { + throw new AgenticError( + AGENTIC_ERROR_CODE.GENERATION_UNSUPPORTED, + `${wallet} was created by factory ${factory}, which is not a verified AGW generation on ${network}`, + { details: { factory, assumption: 'A07' } } + ); + } + const isWallet = (await reader.readContract({ + address: gen.addresses.factory, + abi: gen.contracts.abis.factory, + functionName: 'isWallet', + args: [wallet], + })) as boolean; + if (!isWallet) { + throw new AgenticError( + AGENTIC_ERROR_CODE.NOT_AGENTIC_WALLET, + `${wallet} is not a wallet of factory ${factory}` + ); + } + const [engine, policy, validator, gateway, accountId] = await Promise.all( + (['SESSION_ENGINE', 'RULES_POLICY', 'SESSION_VALIDATOR', 'UNIVERSAL_GATEWAY_PC', 'accountId'] as const).map( + (functionName) => + reader.readContract({ address: wallet, abi: gen.contracts.abis.wallet, functionName }) + ) + ); + const mismatch = + getAddress(engine as Address) !== gen.addresses.sessionEngine || + getAddress(policy as Address) !== gen.addresses.rulesPolicy || + getAddress(validator as Address) !== gen.addresses.sessionValidator || + getAddress(gateway as Address) !== gen.addresses.gateway || + accountId !== gen.accountId; + if (mismatch) { + throw new AgenticError( + AGENTIC_ERROR_CODE.GENERATION_UNSUPPORTED, + `${wallet} wiring does not match registered generation ${gen.id}`, + { details: { engine, policy, validator, gateway, accountId } } + ); + } + await verifyFactoryWiring(reader, gen); + return gen; +} diff --git a/packages/core/src/lib/agentic/errors.ts b/packages/core/src/lib/agentic/errors.ts new file mode 100644 index 00000000..993be42d --- /dev/null +++ b/packages/core/src/lib/agentic/errors.ts @@ -0,0 +1,123 @@ +import { + PushChainExecutionError, + type DecodedErrorPayload, +} from '../orchestrator/internals/errors'; + +/** + * Stable AGW error codes. The first groups are specified by the AGW SDK page + * (section 3.f); the remainder are SDK-owned codes that keep unsupported or + * unverified capabilities from being mistaken for success. + */ +export const AGENTIC_ERROR_CODE = { + // create / rule validation (spec 3.f) + AGENT_IS_OWNER: 'AGENT_IS_OWNER', + DUPLICATE_RULE: 'DUPLICATE_RULE', + TARGET_NOT_ON_RULE_CHAIN: 'TARGET_NOT_ON_RULE_CHAIN', + ASSET_CHAIN_MISMATCH: 'ASSET_CHAIN_MISMATCH', + // initialize with agenticWallet (spec 3.f) + NOT_OWNER_OR_AGENT: 'NOT_OWNER_OR_AGENT', + WALLET_NOT_DEPLOYED: 'WALLET_NOT_DEPLOYED', + NOT_AGENTIC_WALLET: 'NOT_AGENTIC_WALLET', + // rules.revoke (spec 3.f) + REVOKE_NEEDS_TARGET: 'REVOKE_NEEDS_TARGET', + // sendTransaction (spec 3.f) + NO_RULES_FOR_CHAIN: 'NO_RULES_FOR_CHAIN', + FROM_NOT_ALLOWED: 'FROM_NOT_ALLOWED', + NOT_ALLOWED_IN_AGENTIC_MODE: 'NOT_ALLOWED_IN_AGENTIC_MODE', + // SDK-owned + INVALID_RULE: 'INVALID_RULE', + CAPABILITY_UNAVAILABLE: 'CAPABILITY_UNAVAILABLE', + GENERATION_UNSUPPORTED: 'GENERATION_UNSUPPORTED', + READ_ONLY: 'READ_ONLY', + NOT_WALLET_OWNER: 'NOT_WALLET_OWNER', + RULE_NOT_FOUND: 'RULE_NOT_FOUND', + RULE_READ_FAILED: 'RULE_READ_FAILED', + INCONSISTENT_READ: 'INCONSISTENT_READ', + INDEX_RACE: 'INDEX_RACE', + CREATE_PARTIAL: 'CREATE_PARTIAL', + RECEIPT_MISMATCH: 'RECEIPT_MISMATCH', + AGENT_GAS_INSUFFICIENT: 'AGENT_GAS_INSUFFICIENT', + WALLET_BALANCE_INSUFFICIENT: 'WALLET_BALANCE_INSUFFICIENT', + GATEWAY_ALLOWANCE_INSUFFICIENT: 'GATEWAY_ALLOWANCE_INSUFFICIENT', + RULE_LIMIT_EXCEEDED: 'RULE_LIMIT_EXCEEDED', +} as const; + +export type AgenticErrorCode = + (typeof AGENTIC_ERROR_CODE)[keyof typeof AGENTIC_ERROR_CODE]; + +/** + * Pre-signature AGW failure: invalid input, unsupported capability, failed + * eligibility or a read that cannot be trusted. Nothing was signed or sent + * unless `details` explicitly records committed hashes (CREATE_PARTIAL). + */ +export class AgenticError extends Error { + readonly code: AgenticErrorCode; + readonly hint?: string; + readonly details?: Readonly>; + override readonly cause?: unknown; + + constructor( + code: AgenticErrorCode, + message: string, + opts: { + hint?: string; + details?: Record; + cause?: unknown; + } = {} + ) { + super(message); + this.name = 'AgenticError'; + this.code = code; + this.hint = opts.hint; + this.details = opts.details; + this.cause = opts.cause; + } +} + +/** + * On-chain AGW, URP, factory or engine revert surfaced from an agentic send. + * Extends core's structured execution error so `instanceof + * PushChainExecutionError` keeps working, and keeps the underlying cause plus + * any batch recovery hashes. + */ +export class AgenticRevertError extends PushChainExecutionError { + readonly agenticCode?: string; + readonly transactionHashes?: `0x${string}`[]; + readonly pendingTransactionHash?: `0x${string}`; + + constructor( + message: string, + opts: { + decodedError?: DecodedErrorPayload; + gatewayTxHash?: string; + agenticCode?: string; + transactionHashes?: `0x${string}`[]; + pendingTransactionHash?: `0x${string}`; + cause?: unknown; + } = {} + ) { + super(message, { + decodedError: opts.decodedError, + gatewayTxHash: opts.gatewayTxHash, + cause: opts.cause, + }); + this.name = 'AgenticRevertError'; + this.agenticCode = opts.agenticCode; + this.transactionHashes = opts.transactionHashes + ? [...opts.transactionHashes] + : undefined; + this.pendingTransactionHash = opts.pendingTransactionHash; + } +} + +export function capabilityUnavailable( + capability: string, + dependency: string, + hint?: string +): AgenticError { + return new AgenticError( + AGENTIC_ERROR_CODE.CAPABILITY_UNAVAILABLE, + `AGW capability "${capability}" is not available: ${dependency}`, + { hint, details: { capability, dependency } } + ); +} diff --git a/packages/core/src/lib/agentic/revert.ts b/packages/core/src/lib/agentic/revert.ts new file mode 100644 index 00000000..70bf4e59 --- /dev/null +++ b/packages/core/src/lib/agentic/revert.ts @@ -0,0 +1,100 @@ +import { + decodeErrorResult, + toFunctionSelector, + type Abi, + type Hex, +} from 'viem'; +import { formatAbiItem } from 'viem/utils'; +import type { DecodedErrorPayload } from '../orchestrator/internals/errors'; +import { + AGW_ABI, + AGW_FACTORY_ABI, + SMART_SESSION_ABI, + UNIVERSAL_RULES_POLICY_ABI, +} from './contracts/abi/e704d5b'; + +/** URP reverts reached through the engine are truncated to this wrapper. */ +export const POLICY_CHECK_REVERTED_SELECTOR = '0xf4270752'; + +const ERROR_ABIS: readonly Abi[] = [ + AGW_ABI as unknown as Abi, + UNIVERSAL_RULES_POLICY_ABI as unknown as Abi, + AGW_FACTORY_ABI as unknown as Abi, + SMART_SESSION_ABI as unknown as Abi, +]; + +/** selector → error name across the AGW/URP/factory/engine ABIs. */ +const ERROR_NAMES: ReadonlyMap = new Map( + ERROR_ABIS.flatMap((abi) => + abi + .filter((item) => item.type === 'error') + .map((item) => { + const err = item as { type: 'error'; name: string; inputs: readonly { type: string }[] }; + return [toFunctionSelector(formatAbiItem(err as never)).toLowerCase(), err.name] as const; + }) + ) +); + +const HEX_DATA = /0x[0-9a-fA-F]{8,}/g; +const CUSTOM_ERROR_TEXT = /custom error (0x[0-9a-fA-F]{8}):?\s*([0-9a-fA-F]*)/g; + +/** Pull candidate revert data out of an error (viem chains, nested causes, messages). */ +function revertDataCandidates(err: unknown, depth = 0): Hex[] { + if (!err || depth > 6) return []; + const out: Hex[] = []; + const e = err as { data?: unknown; cause?: unknown; message?: unknown; details?: unknown }; + if (typeof e.data === 'string' && /^0x[0-9a-fA-F]{8,}$/.test(e.data)) out.push(e.data as Hex); + if (e.data && typeof e.data === 'object' && typeof (e.data as { data?: unknown }).data === 'string') { + out.push((e.data as { data: Hex }).data); + } + for (const text of [e.message, e.details]) { + if (typeof text !== 'string') continue; + // viem renders unknown custom errors as "custom error 0x: ". + for (const m of text.matchAll(CUSTOM_ERROR_TEXT)) out.push(`${m[1]}${m[2] ?? ''}` as Hex); + out.push(...((text.match(HEX_DATA) ?? []) as Hex[])); + } + out.push(...revertDataCandidates(e.cause, depth + 1)); + return out; +} + +/** Decode raw revert data against the AGW/URP/factory/engine error ABIs. */ +export function decodeAgwErrorData(data: Hex): DecodedErrorPayload | undefined { + const selector = data.slice(0, 10).toLowerCase(); + if (selector === POLICY_CHECK_REVERTED_SELECTOR && data.length >= 10 + 64) { + // bytes32 = 4-byte policy error selector ‖ 28 bytes of its first argument. + // The arguments are truncated, so the inner error is named by selector only. + const word = `0x${data.slice(10, 74)}` as Hex; + const innerName = ERROR_NAMES.get(word.slice(0, 10).toLowerCase()); + return { + name: innerName ? `PolicyCheckReverted(${innerName})` : 'PolicyCheckReverted', + selector, + decoded: word, + hint: 'URP rejected the action (truncated through the session engine). The inner selector names the gate; arguments are truncated to 28 bytes.', + }; + } + for (const abi of ERROR_ABIS) { + try { + const r = decodeErrorResult({ abi, data }); + return { + name: r.errorName, + selector, + decoded: r.args && r.args.length ? stringifyArgs(r.args) : undefined, + }; + } catch { + // try the next ABI + } + } + return undefined; +} + +export function decodeAgenticRevert(err: unknown): DecodedErrorPayload | undefined { + for (const data of revertDataCandidates(err)) { + const decoded = decodeAgwErrorData(data); + if (decoded) return decoded; + } + return undefined; +} + +function stringifyArgs(args: readonly unknown[]): string { + return JSON.stringify(args, (_k, v) => (typeof v === 'bigint' ? v.toString() : v)); +} From e87c47b7d7171e33952749a19f67003f16173069 Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Sat, 3 Oct 2026 19:35:41 +0530 Subject: [PATCH 04/68] feat(agw): client.agentic management, agentic execution mode and AGW responses Plan/agw steps 3, 5, 7-11 and 13, against the pinned adapter: - PushChain.initialize(signer, { agenticWallet }): verifies the wallet's generation and wiring, then picks the door from the signer's Push identity (owner -> execute, agent named in an enabled rule -> executeAsAgent, else NOT_OWNER_OR_AGENT). universal.account becomes the wallet; origin, account status and gas stay the signer's. reinitialize does not inherit the wallet. - client.agentic: derive / create / list / wallet(address) handle with info, owner, checkpoints, rules.list/get/add/update/revoke. create deploys and grants only (no funding), reports partial sequential failures as CREATE_PARTIAL with hashes and granted IDs. rules.update is one owner execute batch of assertSpent -> revoke -> grant per pair and never falls back to sequential sends. setLabel / history / universal rules are capability-gated. - Agentic sends: per-send uncached rule lookup (NO_RULES_FOR_CHAIN / DUPLICATE_RULE before signing), FROM_NOT_ALLOWED and NOT_ALLOWED_IN_AGENTIC_MODE guards on every transaction-producing entry point, native agent arrays refused (A02), signer gas enforced except the first-use UEA, and an AGW-originated EVM outbound composer (empty recipient, wallet revert recipient, nonzero gas cap, multicall payload, CEA of the wallet) that never injects an approval on the agent path. - Responses keep the signer origin and report the wallet as from on send, wait and trackTransaction replay; reads in agentic mode execute through the wallet and refund to it. AGENTIC-TX progress events (no 103). - PushChainExecutionError now keeps its cause so revert data survives, and is exported for instanceof checks. --- packages/core/src/lib/agentic/agentic.ts | 49 +++ packages/core/src/lib/agentic/context.ts | 78 +++++ .../core/src/lib/agentic/execution/guards.ts | 46 +++ .../src/lib/agentic/execution/outbound.ts | 192 +++++++++++ .../core/src/lib/agentic/execution/send.ts | 259 +++++++++++++++ packages/core/src/lib/agentic/index.ts | 30 ++ .../core/src/lib/agentic/management/common.ts | 125 ++++++++ .../core/src/lib/agentic/management/create.ts | 221 +++++++++++++ .../src/lib/agentic/management/rules-write.ts | 298 ++++++++++++++++++ .../core/src/lib/agentic/reads/checkpoints.ts | 85 +++++ packages/core/src/lib/agentic/reads/rules.ts | 260 +++++++++++++++ .../core/src/lib/agentic/reads/snapshot.ts | 92 ++++++ .../core/src/lib/agentic/reads/wallets.ts | 199 ++++++++++++ packages/core/src/lib/agentic/response.ts | 176 +++++++++++ packages/core/src/lib/agentic/runtime.ts | 107 +++++++ packages/core/src/lib/agentic/utils.ts | 114 +++++++ packages/core/src/lib/agentic/wallet.ts | 124 ++++++++ packages/core/src/lib/constants/index.ts | 3 + packages/core/src/lib/index.ts | 42 +++ .../src/lib/orchestrator/internals/errors.ts | 5 +- .../internals/execute-standard.ts | 2 +- .../lib/orchestrator/orchestrator.types.ts | 7 + .../__tests__/response-invariant.spec.ts | 9 + .../src/lib/progress-hook/progress-hook.ts | 75 +++++ .../lib/progress-hook/progress-hook.types.ts | 21 ++ .../core/src/lib/push-chain/push-chain.ts | 130 +++++--- packages/core/src/lib/utils.ts | 8 + 27 files changed, 2719 insertions(+), 38 deletions(-) create mode 100644 packages/core/src/lib/agentic/agentic.ts create mode 100644 packages/core/src/lib/agentic/context.ts create mode 100644 packages/core/src/lib/agentic/execution/guards.ts create mode 100644 packages/core/src/lib/agentic/execution/outbound.ts create mode 100644 packages/core/src/lib/agentic/execution/send.ts create mode 100644 packages/core/src/lib/agentic/index.ts create mode 100644 packages/core/src/lib/agentic/management/common.ts create mode 100644 packages/core/src/lib/agentic/management/create.ts create mode 100644 packages/core/src/lib/agentic/management/rules-write.ts create mode 100644 packages/core/src/lib/agentic/reads/checkpoints.ts create mode 100644 packages/core/src/lib/agentic/reads/rules.ts create mode 100644 packages/core/src/lib/agentic/reads/snapshot.ts create mode 100644 packages/core/src/lib/agentic/reads/wallets.ts create mode 100644 packages/core/src/lib/agentic/response.ts create mode 100644 packages/core/src/lib/agentic/runtime.ts create mode 100644 packages/core/src/lib/agentic/utils.ts create mode 100644 packages/core/src/lib/agentic/wallet.ts diff --git a/packages/core/src/lib/agentic/agentic.ts b/packages/core/src/lib/agentic/agentic.ts new file mode 100644 index 00000000..e15344c0 --- /dev/null +++ b/packages/core/src/lib/agentic/agentic.ts @@ -0,0 +1,49 @@ +import { AgenticCapability, requireCapability } from './capabilities'; +import { currentGeneration } from './deployments'; +import { createWallet } from './management/create'; +import { emitAgentic } from './management/common'; +import { deriveForOwner, listForOwner } from './reads/wallets'; +import { AgenticWalletHandle } from './wallet'; +import { PROGRESS_HOOK } from '../progress-hook/progress-hook.types'; +import type { AgenticRuntime } from './runtime'; +import type { + AgenticAddress, + AgenticNamespace, + AgenticWallet, + CreateOptions, + CreateResult, + WalletSummary, +} from './agentic.types'; + +/** + * client.agentic — owner-side AGW management (spec section 1). Ownership is + * always the connected signer's Push identity (EOA, or the UEA for its origin + * chain), never the AGW an agentic client exposes as universal.account. + */ +export class AgenticNamespaceImpl implements AgenticNamespace { + constructor(private readonly runtime: AgenticRuntime) {} + + async derive(opts?: { index?: number }): Promise<{ address: AgenticAddress; index: number; deployed: boolean }> { + const gen = currentGeneration(this.runtime.network); + requireCapability(gen.capabilities, AgenticCapability.WALLET_READS); + const owner = this.runtime.signerPushAccount(); + const r = await deriveForOwner(this.runtime.reader, gen, owner, opts?.index); + emitAgentic(this.runtime, undefined, PROGRESS_HOOK.AGENTIC_TX_101, r.address, r.index, r.deployed); + return { address: r.address as AgenticAddress, index: r.index, deployed: r.deployed }; + } + + create(label: string, options: CreateOptions): Promise { + return createWallet(this.runtime, label, options); + } + + async list(): Promise<{ wallets: WalletSummary[] }> { + const gen = currentGeneration(this.runtime.network); + requireCapability(gen.capabilities, AgenticCapability.WALLET_READS); + const wallets = await listForOwner(this.runtime.reader, gen, this.runtime.signerPushAccount()); + return { wallets }; + } + + wallet(address: AgenticAddress): AgenticWallet { + return new AgenticWalletHandle(this.runtime, address); + } +} diff --git a/packages/core/src/lib/agentic/context.ts b/packages/core/src/lib/agentic/context.ts new file mode 100644 index 00000000..fc1f8203 --- /dev/null +++ b/packages/core/src/lib/agentic/context.ts @@ -0,0 +1,78 @@ +import { getAddress, type Address } from 'viem'; +import { CHAIN } from '../constants/enums'; +import { AgenticCapability, requireCapability } from './capabilities'; +import { resolveWalletGeneration, type AgenticGeneration } from './deployments'; +import { AGENTIC_ERROR_CODE, AgenticError } from './errors'; +import { readActiveRules } from './reads/rules'; +import { Snapshot } from './reads/snapshot'; +import type { AgenticRuntime } from './runtime'; +import type { AgenticDoor } from './agentic.types'; + +/** + * Identity of an agentic client. Three values stay separate: + * - signerOrigin: the key that signs (universal.origin) + * - signerPushAccount: its Push identity — EOA or UEA for its origin chain; + * pays Push gas and is the identity ownership checks use + * - wallet: the AGW, the execution account (universal.account) + */ +export interface AgenticExecutionContext { + wallet: Address; + door: AgenticDoor; + signerPushAccount: Address; + signerOrigin: { chain: CHAIN; address: string }; + generation: AgenticGeneration; +} + +/** + * Initialization-time resolution for `initialize(signer, { agenticWallet })`. + * Owner → owner door. Otherwise at least one ENABLED rule must name the + * signer's Push identity (expired-but-enabled still qualifies; expiry is an + * on-chain send check). Nothing here is cached for later sends. + */ +export async function resolveAgenticContext( + runtime: AgenticRuntime, + walletInput: string +): Promise { + let wallet: Address; + try { + wallet = getAddress(walletInput); + } catch (cause) { + throw new AgenticError(AGENTIC_ERROR_CODE.NOT_AGENTIC_WALLET, `"${walletInput}" is not an address`, { + cause, + }); + } + const generation = await resolveWalletGeneration(runtime.reader, runtime.network, wallet); + const signerPushAccount = runtime.signerPushAccount(); + const snap = await Snapshot.at(runtime.reader); + const owner = getAddress( + await snap.read
(wallet, generation.contracts.abis.wallet, 'owner') + ); + let door: AgenticDoor; + if (owner === signerPushAccount) { + requireCapability(generation.capabilities, AgenticCapability.OWNER_EXECUTE); + door = 'owner'; + } else { + requireCapability(generation.capabilities, AgenticCapability.AGENT_EXECUTE); + const active = await readActiveRules(snap, generation, wallet); + if (!active.some((r) => r.agent === signerPushAccount)) { + throw new AgenticError( + AGENTIC_ERROR_CODE.NOT_OWNER_OR_AGENT, + `${signerPushAccount} is neither the owner of ${wallet} nor the agent of an enabled rule`, + { + hint: runtime.signerIsPushNative() + ? 'Grant a rule to this Push address, or initialize with the owner signer.' + : 'An external key acts through its UEA for the chain it was initialized on; grant the rule to that UEA (PushChain.utils.account.deriveExecutorAccount).', + details: { wallet, signerPushAccount, owner }, + } + ); + } + door = 'agent'; + } + return { + wallet, + door, + signerPushAccount, + signerOrigin: runtime.signerOrigin(), + generation, + }; +} diff --git a/packages/core/src/lib/agentic/execution/guards.ts b/packages/core/src/lib/agentic/execution/guards.ts new file mode 100644 index 00000000..2aa5f68e --- /dev/null +++ b/packages/core/src/lib/agentic/execution/guards.ts @@ -0,0 +1,46 @@ +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; + +/** Methods the spec forbids on an agentic client (spec 2.a). */ +export type ForbiddenAgenticMethod = + | 'prepareTransaction' + | 'executeTransactions' + | 'migrateCEA' + | 'rescueFunds' + | 'payGasWith'; + +export function notAllowedInAgenticMode(method: ForbiddenAgenticMethod | string): AgenticError { + return new AgenticError( + AGENTIC_ERROR_CODE.NOT_ALLOWED_IN_AGENTIC_MODE, + `${method} is not available on a client initialized with agenticWallet`, + { + hint: + method === 'prepareTransaction' || method === 'executeTransactions' + ? 'Use sendTransaction; cascades would run from the signer, not the wallet.' + : 'Use a client initialized without agenticWallet for signer-level operations.', + } + ); +} + +/** + * Reject inputs that would execute from somewhere other than the wallet, or + * that agentic mode does not support, before any signature or RPC call. + */ +export function guardAgenticSendParams(params: unknown): void { + if (!params || typeof params !== 'object') { + throw new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, 'sendTransaction needs a transaction object'); + } + const p = params as { + from?: unknown; + payGasWith?: unknown; + migration?: unknown; + }; + if (p.from !== undefined && p.from !== null) { + throw new AgenticError( + AGENTIC_ERROR_CODE.FROM_NOT_ALLOWED, + '`from` (Routes 3 and 4) is not allowed in agenticWallet mode', + { hint: 'A CEA-originated call makes msg.sender a CEA, so the wallet door check would fail.' } + ); + } + if (p.payGasWith !== undefined) throw notAllowedInAgenticMode('payGasWith'); + if (p.migration) throw notAllowedInAgenticMode('migrateCEA'); +} diff --git a/packages/core/src/lib/agentic/execution/outbound.ts b/packages/core/src/lib/agentic/execution/outbound.ts new file mode 100644 index 00000000..545850e7 --- /dev/null +++ b/packages/core/src/lib/agentic/execution/outbound.ts @@ -0,0 +1,192 @@ +import { + concat, + encodeAbiParameters, + encodeFunctionData, + getAddress, + type Address, + type Hex, +} from 'viem'; +import { CHAIN, VM } from '../../constants/enums'; +import { CHAIN_INFO } from '../../constants/chain'; +import type { MoveableToken } from '../../constants/tokens'; +import { ERC20_EVM, UNIVERSAL_GATEWAY_PC } from '../../constants/abi'; +import type { UniversalExecuteParams, UniversalOutboundTxRequest } from '../../orchestrator/orchestrator.types'; +import { isPC20Reference } from '../../orchestrator/orchestrator.types'; +import { AgenticCapability, requireCapability } from '../capabilities'; +import type { AgenticGeneration } from '../deployments'; +import type { Call } from '../contracts/e704d5b'; +import { UEA_MULTICALL_PREFIX } from '../contracts/e704d5b'; +import { AGENTIC_ERROR_CODE, AgenticError, capabilityUnavailable } from '../errors'; +import type { AgenticRuntime } from '../runtime'; + +/** URP MAX_ACTIONS_PER_REQUEST at e704d5b. */ +export const MAX_DESTINATION_CALLS = 10; + +const MULTICALL_TUPLE = [ + { + type: 'tuple[]', + components: [ + { name: 'to', type: 'address' }, + { name: 'value', type: 'uint256' }, + { name: 'data', type: 'bytes' }, + ], + }, +] as const; + +export interface ComposedOutbound { + chain: CHAIN; + destinationAccount: Address; + destinationAccountDeployed: boolean; + token: Address; + amount: bigint; + /** PC the wallet attaches: protocolFee + maxPCForGas. */ + value: bigint; + request: UniversalOutboundTxRequest; + /** The wallet's call into the gateway. */ + gatewayCall: Call; + destinationCalls: { to: Address; value: bigint; data: Hex }[]; +} + +/** Destination calls carried in the outbound multicall payload. */ +export function destinationCalls(params: UniversalExecuteParams): { to: Address; value: bigint; data: Hex }[] { + const target = params.to as { address: string; chain: CHAIN }; + if (Array.isArray(params.data)) { + return params.data.map((c) => ({ to: getAddress(c.to), value: c.value ?? BigInt(0), data: c.data })); + } + if (params.data && params.data !== '0x') { + return [{ to: getAddress(target.address), value: params.value ?? BigInt(0), data: params.data }]; + } + return []; +} + +/** + * Compose the AGW-originated EVM outbound (Route 2 shape, wallet context): + * - recipient = empty bytes, revertRecipient = the AGW, maxPCForGas > 0 + * - payload = UEA_MULTICALL ‖ abi.encode(Multicall[1..10]) executed by the AGW's CEA + * - value = protocolFee + maxPCForGas, paid from the AGW's PC + * The destination account is resolved from the AGW, never from the signer. + * No approval is added here: agent sends rely on an owner-set allowance. + */ +export async function composeOutbound( + runtime: AgenticRuntime, + gen: AgenticGeneration, + wallet: Address, + params: UniversalExecuteParams, + opts: { ruleAsset?: Address; requireCalls: boolean } +): Promise { + requireCapability(gen.capabilities, AgenticCapability.UNIVERSAL_EVM_OUTBOUND); + const target = params.to as { address: string; chain: CHAIN }; + const chain = target.chain; + const info = CHAIN_INFO[chain]; + if (!info) { + throw new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, `unknown destination chain ${String(chain)}`); + } + if (info.vm !== VM.EVM) { + throw capabilityUnavailable( + AgenticCapability.UNIVERSAL_SVM_RULES, + 'SVM destinations are not enabled for agentic wallets (A05/A07, H4.4)' + ); + } + const calls = destinationCalls(params); + if (opts.requireCalls && calls.length === 0) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'an agent outbound must carry at least one destination call (URP requires a multicall payload)' + ); + } + if (calls.length > MAX_DESTINATION_CALLS) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + `at most ${MAX_DESTINATION_CALLS} destination calls per outbound` + ); + } + const funds = params.funds; + if (funds && isPC20Reference(funds.token)) { + throw capabilityUnavailable('pc20Outbound', 'PC20 tokens are not supported through an agentic wallet'); + } + + let token: Address; + let amount = BigInt(0); + if (funds?.amount) { + token = runtime.resolvePrc20(funds.token as MoveableToken | undefined, chain); + amount = funds.amount; + } else if (opts.ruleAsset) { + token = getAddress(opts.ruleAsset); + } else { + token = runtime.resolvePrc20(undefined, chain); + } + if (opts.ruleAsset && getAddress(opts.ruleAsset) !== token) { + throw new AgenticError( + AGENTIC_ERROR_CODE.RULE_LIMIT_EXCEEDED, + `the selected rule only permits asset ${opts.ruleAsset}, not ${token}` + ); + } + + const resolved = await runtime.resolveCEA(wallet, chain); + const cea = getAddress(resolved.cea); + const isDeployed = resolved.isDeployed; + const quote = await runtime.quoteOutbound(token, params.gasLimit ?? BigInt(0), chain); + if (quote.nativeValueForGas <= BigInt(0)) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'outbound gas quote returned zero; URP rejects an uncapped gas swap' + ); + } + const maxPCForGas = quote.nativeValueForGas; + const value = quote.protocolFee + maxPCForGas; + const payload = + calls.length === 0 + ? ('0x' as Hex) + : concat([UEA_MULTICALL_PREFIX, encodeAbiParameters(MULTICALL_TUPLE, [calls])]); + const request: UniversalOutboundTxRequest = { + recipient: '0x', + token, + amount, + gasLimit: quote.gasLimitUsed, + gasPrice: BigInt(0), + maxPCForGas, + payload, + revertRecipient: wallet, + }; + const data = encodeFunctionData({ + abi: UNIVERSAL_GATEWAY_PC, + functionName: 'sendUniversalTxOutbound', + args: [request], + }); + return { + chain, + destinationAccount: cea, + destinationAccountDeployed: isDeployed, + token, + amount, + value, + request, + gatewayCall: { target: gen.addresses.gateway, value, data }, + destinationCalls: calls, + }; +} + +/** + * Owner door: approval and outbound in one atomic owner batch. The approval is + * `currentAllowance + amount`, so after the gateway pulls `amount` any standing + * allowance the owner set for agents is left exactly as it was. + */ +export function ownerOutboundCalls( + gen: AgenticGeneration, + out: ComposedOutbound, + currentAllowance: bigint +): Call[] { + if (out.amount === BigInt(0)) return [out.gatewayCall]; + return [ + { + target: out.token, + value: BigInt(0), + data: encodeFunctionData({ + abi: ERC20_EVM, + functionName: 'approve', + args: [gen.addresses.gateway, currentAllowance + out.amount], + }), + }, + out.gatewayCall, + ]; +} diff --git a/packages/core/src/lib/agentic/execution/send.ts b/packages/core/src/lib/agentic/execution/send.ts new file mode 100644 index 00000000..00cc99cb --- /dev/null +++ b/packages/core/src/lib/agentic/execution/send.ts @@ -0,0 +1,259 @@ +import { getAddress, type Address, type Hex } from 'viem'; +import type { CHAIN } from '../../constants/enums'; +import { ERC20_EVM } from '../../constants/abi'; +import { PROGRESS_HOOK } from '../../progress-hook/progress-hook.types'; +import type { + ExecuteParams, + TransactionExecutionOptions, + UniversalExecuteParams, + UniversalTxResponse, +} from '../../orchestrator/orchestrator.types'; +import { isChainTarget } from '../../orchestrator/route-detector'; +import { AgenticCapability, requireCapability } from '../capabilities'; +import type { AgenticExecutionContext } from '../context'; +import type { Call, UniversalConfigReadE704d5b } from '../contracts/e704d5b'; +import { SEND_OUTBOUND_SELECTOR } from '../contracts/e704d5b'; +import { actionId, configId } from '../codec/ids'; +import { assertSingleAgentCall } from '../codec/policy'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; +import { assertCanSign, emitAgentic, wrapSendError } from '../management/common'; +import { selectRuleForSend } from '../reads/rules'; +import { Snapshot } from '../reads/snapshot'; +import { adaptAgenticResponse } from '../response'; +import type { AgenticRuntime } from '../runtime'; +import type { AgenticHex, AgenticProgressHook } from '../agentic.types'; +import { guardAgenticSendParams } from './guards'; +import { composeOutbound, ownerOutboundCalls } from './outbound'; + +const MODE_UNIVERSAL = 0; +const VM_EVM = 0; +/** R1's own required-funds estimate when no gasLimit is given (execute-standard). */ +const DEFAULT_GAS_ESTIMATE = BigInt(1e7); + +/** Signer-level fields that legitimately carry over to the wrapped Push tx. */ +function signerFields(p: UniversalExecuteParams): Partial { + const out: Partial = {}; + if (p.gasLimit !== undefined && !isChainTarget(p.to)) out.gasLimit = p.gasLimit; + if (p.maxFeePerGas !== undefined) out.maxFeePerGas = p.maxFeePerGas; + if (p.maxPriorityFeePerGas !== undefined) out.maxPriorityFeePerGas = p.maxPriorityFeePerGas; + if (p.nonce !== undefined) out.nonce = p.nonce; + if (p.deadline !== undefined) out.deadline = p.deadline; + if (p.feeLockTxHash !== undefined) out.feeLockTxHash = p.feeLockTxHash; + return out; +} + +/** + * Spec 2.a gas rule: in agenticWallet mode an external signer's UEA must + * already hold the PC for its Push gas, except for the very first action + * while that UEA is undeployed (which takes the one-time origin fee lock). + * Mirrors R1's fee-lock condition so an underfunded UEA fails loudly here + * instead of silently locking origin funds on every action. + */ +async function enforceSignerGas(runtime: AgenticRuntime, gasLimit: bigint | undefined): Promise { + if (runtime.signerIsPushNative()) return; + if (!(await runtime.signerAccountDeployed())) return; + const [gasPrice, balance] = await Promise.all([runtime.getGasPrice(), runtime.signerBalance()]); + const required = (gasLimit ?? DEFAULT_GAS_ESTIMATE) * gasPrice; + if (balance < required) { + throw new AgenticError( + AGENTIC_ERROR_CODE.AGENT_GAS_INSUFFICIENT, + `the signer's UEA ${runtime.signerPushAccount()} holds ${balance} PC wei but needs ~${required} for Push gas`, + { + hint: + "The wallet's PC pays outbound fees, not the signer's gas. Top up the signer's UEA (PushChain.utils.account.deriveExecutorAccount) from a client without agenticWallet.", + details: { required, balance }, + } + ); + } +} + +function toCalls(params: UniversalExecuteParams): Call[] { + if (Array.isArray(params.data)) { + return params.data.map((c) => ({ target: getAddress(c.to), value: c.value ?? BigInt(0), data: c.data })); + } + return [ + { + target: getAddress(params.to as Address), + value: params.value ?? BigInt(0), + data: (params.data ?? '0x') as Hex, + }, + ]; +} + +/** + * sendTransaction in agenticWallet mode. Owner door → execute; agent door → + * executeAsAgent under the one enabled rule for (signer, destination), looked + * up on every send. Everything is validated before the signer is asked. + */ +export async function agenticSend( + runtime: AgenticRuntime, + actx: AgenticExecutionContext, + params: UniversalExecuteParams | ExecuteParams, + options?: TransactionExecutionOptions +): Promise { + assertCanSign(runtime, 'sendTransaction'); + guardAgenticSendParams(params); + const p = params as UniversalExecuteParams; + const hook: AgenticProgressHook | undefined = options?.progressHook ?? p.progressHook; + const gen = actx.generation; + const wallet = actx.wallet; + const outbound = isChainTarget(p.to); + const destination = outbound ? (p.to as { chain: string }).chain : runtime.pushChainNamespace; + + if (!outbound && p.funds) { + throw new AgenticError( + AGENTIC_ERROR_CODE.NOT_ALLOWED_IN_AGENTIC_MODE, + '`funds` on a Push-chain send would bridge from the signer; it does not move the wallet\'s tokens', + { hint: "Transfer the wallet's PRC20 with a token transfer call in `data`." } + ); + } + + let wrappedData: Hex; + let rulesId: AgenticHex | undefined; + let logical: { to: string; data: string; value: bigint }; + let meta: { route?: 'UOA_TO_CEA'; destinationAccount?: Address } = {}; + let outboundChain: CHAIN | undefined; + + if (actx.door === 'agent') { + requireCapability(gen.capabilities, AgenticCapability.AGENT_EXECUTE); + } else { + requireCapability(gen.capabilities, AgenticCapability.OWNER_EXECUTE); + } + + if (!outbound) { + const calls = toCalls(p); + if (actx.door === 'owner') { + wrappedData = gen.contracts.encodeExecute(calls); + } else { + assertSingleAgentCall(calls.length); + const snap = await Snapshot.at(runtime.reader); + const rule = await selectRuleForSend(snap, gen, wallet, actx.signerPushAccount, destination); + rulesId = rule.rulesId as AgenticHex; + wrappedData = gen.contracts.encodeExecuteAsAgent(rule.rulesId, calls[0]); + } + logical = + calls.length === 1 + ? { to: calls[0].target, data: calls[0].data, value: calls[0].value } + : { to: wallet, data: wrappedData, value: BigInt(0) }; + } else { + let ruleAsset: Address | undefined; + let maxPCPerCall: bigint | undefined; + let expectedCEA: Address | undefined; + const snap = await Snapshot.at(runtime.reader); + if (actx.door === 'agent') { + const rule = await selectRuleForSend(snap, gen, wallet, actx.signerPushAccount, destination); + if (rule.mode !== MODE_UNIVERSAL || rule.vm !== VM_EVM) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + `rule ${rule.rulesId} is not an EVM universal rule` + ); + } + rulesId = rule.rulesId as AgenticHex; + const cfg = await snap.read( + gen.addresses.rulesPolicy, + gen.contracts.abis.policy, + 'getConfig', + [configId(wallet, rule.rulesId, actionId(gen.addresses.gateway, SEND_OUTBOUND_SELECTOR)), wallet] + ); + ruleAsset = getAddress(cfg.asset); + maxPCPerCall = cfg.maxPCPerCall; + expectedCEA = getAddress(cfg.expectedCEA); + } + const out = await composeOutbound(runtime, gen, wallet, p, { + ruleAsset, + requireCalls: actx.door === 'agent', + }); + outboundChain = out.chain; + meta = { route: 'UOA_TO_CEA', destinationAccount: out.destinationAccount }; + const [walletPc, tokenBalance, allowance] = await Promise.all([ + runtime.reader.getBalance({ address: wallet, blockNumber: snap.blockNumber }), + out.amount > BigInt(0) + ? snap.read(out.token, ERC20_EVM as unknown as readonly unknown[], 'balanceOf', [wallet]) + : Promise.resolve(BigInt(0)), + snap.read(out.token, ERC20_EVM as unknown as readonly unknown[], 'allowance', [ + wallet, + gen.addresses.gateway, + ]), + ]); + if (walletPc < out.value) { + throw new AgenticError( + AGENTIC_ERROR_CODE.WALLET_BALANCE_INSUFFICIENT, + `wallet ${wallet} holds ${walletPc} PC wei; this outbound needs ${out.value} (protocol fee + gas cap)`, + { hint: "Fund the wallet's PC with an ordinary send to its address." } + ); + } + if (tokenBalance < out.amount) { + throw new AgenticError( + AGENTIC_ERROR_CODE.WALLET_BALANCE_INSUFFICIENT, + `wallet ${wallet} holds ${tokenBalance} of ${out.token}; this outbound burns ${out.amount}` + ); + } + if (actx.door === 'agent') { + if (expectedCEA && expectedCEA !== out.destinationAccount) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INCONSISTENT_READ, + `rule ${rulesId} committed destination account ${expectedCEA}, but the wallet's account on ${out.chain} now derives to ${out.destinationAccount}`, + { hint: 'Destination-account derivation drift (obligation 13). The owner must regrant the rule.' } + ); + } + if (maxPCPerCall !== undefined && out.value > maxPCPerCall) { + throw new AgenticError( + AGENTIC_ERROR_CODE.RULE_LIMIT_EXCEEDED, + `this outbound needs ${out.value} PC wei but the rule caps the wallet's PC per call at ${maxPCPerCall}` + ); + } + if (out.amount > allowance) { + throw new AgenticError( + AGENTIC_ERROR_CODE.GATEWAY_ALLOWANCE_INSUFFICIENT, + `the gateway may pull ${allowance} of ${out.token} from the wallet; this outbound needs ${out.amount}`, + { + hint: 'The owner sets a bounded allowance with an owner-door send: approve(gateway, cap) on the token. The agent path never approves.', + } + ); + } + wrappedData = gen.contracts.encodeExecuteAsAgent(rulesId as Hex, out.gatewayCall); + } else { + wrappedData = gen.contracts.encodeExecute(ownerOutboundCalls(gen, out, allowance)); + } + const first = out.destinationCalls[0]; + logical = first + ? { to: first.to, data: first.data, value: first.value } + : { to: (p.to as { address: string }).address, data: '0x', value: BigInt(0) }; + } + + await enforceSignerGas(runtime, signerFields(p).gasLimit); + emitAgentic(runtime, hook, PROGRESS_HOOK.AGENTIC_TX_107, rulesId, outboundChain ?? destination, actx.door); + + let resp: UniversalTxResponse; + try { + resp = await runtime.execute( + { ...signerFields(p), to: wallet, value: BigInt(0), data: wrappedData }, + hook ? { ...options, progressHook: hook } : options + ); + } catch (err) { + const wrapped = wrapSendError(err) as { code?: string; message?: string; decodedError?: unknown }; + emitAgentic( + runtime, + hook, + PROGRESS_HOOK.AGENTIC_TX_199_02, + 'sendTransaction', + wrapped?.code ?? 'UNKNOWN', + wrapped?.message ?? String(err), + wrapped?.decodedError + ); + throw wrapped; + } + adaptAgenticResponse(resp, { + wallet, + door: actx.door, + rulesId, + chainNamespace: outboundChain ?? destination, + destinationAccount: meta.destinationAccount as AgenticHex | undefined, + logical, + route: meta.route, + chain: outboundChain, + }); + emitAgentic(runtime, hook, PROGRESS_HOOK.AGENTIC_TX_199_01, 'sendTransaction', resp.hash); + return resp; +} + diff --git a/packages/core/src/lib/agentic/index.ts b/packages/core/src/lib/agentic/index.ts new file mode 100644 index 00000000..0ba0a0dc --- /dev/null +++ b/packages/core/src/lib/agentic/index.ts @@ -0,0 +1,30 @@ +export type { + AgenticAddress, + AgenticHex, + AgenticDoor, + AgenticNamespace, + AgenticProgressHook, + AgenticTxMetadata, + AgenticWallet, + AllowedCall, + AssetCap, + Checkpoint, + CheckpointKind, + CreateOptions, + CreateResult, + ForeignChainNamespace, + NativeRule, + Rule, + RulesRecord, + Selector, + Spent, + UniversalRule, + WalletInfo, + WalletSummary, +} from './agentic.types'; +export { AGENTIC_ERROR_CODE, AgenticError, AgenticRevertError } from './errors'; +export type { AgenticErrorCode } from './errors'; +export { AGENTIC } from './constants'; +export type { AgenticNetworkConstants } from './constants'; +export { agenticUtils } from './utils'; +export type { RulesEncodeContext } from './utils'; diff --git a/packages/core/src/lib/agentic/management/common.ts b/packages/core/src/lib/agentic/management/common.ts new file mode 100644 index 00000000..94974baf --- /dev/null +++ b/packages/core/src/lib/agentic/management/common.ts @@ -0,0 +1,125 @@ +import { getAddress, type Address, type Hex, type Log } from 'viem'; +import type { MultiCall, UniversalTxResponse } from '../../orchestrator/orchestrator.types'; +import { + PushChainBatchExecutionError, + PushChainExecutionError, + type DecodedErrorPayload, +} from '../../orchestrator/internals/errors'; +import PROGRESS_HOOKS from '../../progress-hook/progress-hook'; +import { PROGRESS_HOOK } from '../../progress-hook/progress-hook.types'; +import type { AgenticGeneration } from '../deployments'; +import { AGENTIC_ERROR_CODE, AgenticError, AgenticRevertError } from '../errors'; +import type { AgenticRuntime } from '../runtime'; +import type { AgenticProgressHook } from '../agentic.types'; +import { Snapshot } from '../reads/snapshot'; +import { decodeAgenticRevert } from '../revert'; + +export function emitAgentic( + runtime: AgenticRuntime, + perCall: AgenticProgressHook | undefined, + id: PROGRESS_HOOK, + ...args: unknown[] +): void { + runtime.emit(PROGRESS_HOOKS[id](...args), perCall); +} + +export function assertCanSign(runtime: AgenticRuntime, operation: string): void { + if (runtime.isReadOnly) { + throw new AgenticError( + AGENTIC_ERROR_CODE.READ_ONLY, + `${operation} needs a signer; this client was initialized read-only` + ); + } +} + +/** Owner-only management writes: the connected signer's Push identity must be the stored owner. */ +export async function assertOwner( + runtime: AgenticRuntime, + gen: AgenticGeneration, + wallet: Address, + snap: Snapshot +): Promise
{ + const owner = getAddress(await snap.read
(wallet, gen.contracts.abis.wallet, 'owner')); + const signer = runtime.signerPushAccount(); + if (owner !== signer) { + throw new AgenticError( + AGENTIC_ERROR_CODE.NOT_WALLET_OWNER, + `${signer} is not the owner of ${wallet} (owner is ${owner})`, + { hint: 'Rule and label writes are owner-only. Initialize with the owner signer.' } + ); + } + return owner; +} + +/** + * Send owner calls through the signer's ordinary transaction path: one call + * as a plain transaction, several as the signer's batch (UEA multicall, + * EIP-7702 atomic batch, or the documented sequential fallback for a Push EOA + * without 7702 — reported through `atomic` / `transactionHashes`). + */ +export async function sendOwnerCalls( + runtime: AgenticRuntime, + calls: MultiCall[], + progressHook: AgenticProgressHook | undefined +): Promise { + if (calls.length === 0) throw new Error('sendOwnerCalls needs at least one call'); + const options = progressHook ? { progressHook } : undefined; + if (calls.length === 1) { + return runtime.execute({ to: calls[0].to, value: calls[0].value, data: calls[0].data }, options); + } + return runtime.execute({ to: calls[0].to, value: BigInt(0), data: calls }, options); +} + +/** + * Wait for every Push transaction the operation produced and return their + * logs in submission order. A reverted transaction raises AgenticRevertError + * carrying all hashes. + */ +export async function confirmedLogs( + runtime: AgenticRuntime, + tx: UniversalTxResponse +): Promise<{ logs: Log[]; hashes: Hex[] }> { + const receipt = await tx.wait(); + const hashes = (tx.transactionHashes ?? [tx.hash as Hex]) as Hex[]; + if (hashes.length === 1) { + if (receipt.status !== 1) { + throw new AgenticRevertError(`Push transaction ${tx.hash} reverted`, { + transactionHashes: hashes, + }); + } + return { logs: receipt.logs as Log[], hashes }; + } + const logs: Log[] = []; + for (const hash of hashes) { + const r = await runtime.reader.getTransactionReceipt({ hash }); + if (r.status !== 'success') { + throw new AgenticRevertError(`Push transaction ${hash} reverted`, { transactionHashes: hashes }); + } + logs.push(...(r.logs as Log[])); + } + return { logs, hashes }; +} + +/** Normalize a send failure: keep batch hashes and decoded revert data. */ +export function wrapSendError(err: unknown): unknown { + if (err instanceof AgenticError || err instanceof AgenticRevertError) return err; + const decoded = decodeAgenticRevert(err); + if (err instanceof PushChainBatchExecutionError) { + return new AgenticRevertError(err.message, { + decodedError: decoded ?? err.decodedError, + transactionHashes: err.transactionHashes, + pendingTransactionHash: err.pendingTransactionHash, + cause: err, + }); + } + if (decoded || err instanceof PushChainExecutionError) { + const e = err as { message?: string; gatewayTxHash?: string; decodedError?: DecodedErrorPayload }; + return new AgenticRevertError(e?.message ?? decoded?.name ?? 'AGW revert', { + decodedError: decoded ?? e?.decodedError, + gatewayTxHash: e?.gatewayTxHash, + agenticCode: decoded?.name, + cause: err, + }); + } + return err; +} diff --git a/packages/core/src/lib/agentic/management/create.ts b/packages/core/src/lib/agentic/management/create.ts new file mode 100644 index 00000000..44b3ba75 --- /dev/null +++ b/packages/core/src/lib/agentic/management/create.ts @@ -0,0 +1,221 @@ +import { getAddress, type Address, type Hex } from 'viem'; +import { PROGRESS_HOOK } from '../../progress-hook/progress-hook.types'; +import type { MultiCall } from '../../orchestrator/orchestrator.types'; +import { PushChainBatchExecutionError } from '../../orchestrator/internals/errors'; +import { AgenticCapability, requireCapability } from '../capabilities'; +import { currentGeneration, forbiddenTargets, verifyFactoryWiring } from '../deployments'; +import { deriveWallet, rulesId as computeRulesId } from '../codec/ids'; +import { prepareRules } from '../codec/rules'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; +import type { AgenticRuntime } from '../runtime'; +import type { CreateOptions, CreateResult } from '../agentic.types'; +import { Snapshot } from '../reads/snapshot'; +import { walletCount } from '../reads/wallets'; +import { + assertCanSign, + confirmedLogs, + emitAgentic, + sendOwnerCalls, + wrapSendError, +} from './common'; + +/** + * client.agentic.create(label, { rules }): deploy + grants only. Funding and + * approvals are separate ordinary sends. Every input is validated and every + * prediction re-read immediately before signing; IDs are returned from + * receipts in input order. + * + * Strategy follows the signer: an external owner's UEA batches atomically, a + * Push EOA uses an EIP-7702 batch when available and otherwise the documented + * sequential fallback. A sequential failure raises CREATE_PARTIAL with the + * deployed wallet, confirmed/pending hashes and granted IDs so the caller can + * finish with `wallet(w).rules.add(remaining)` — the SDK never deploys another + * wallet on its own. + */ +export async function createWallet( + runtime: AgenticRuntime, + label: string, + options: CreateOptions +): Promise { + const hook = options?.progressHook; + if (typeof label !== 'string') { + throw new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, 'label must be a string'); + } + if (!options || !Array.isArray(options.rules)) { + throw new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, 'options.rules is required (use [] for a bare wallet)'); + } + assertCanSign(runtime, 'agentic.create'); + const gen = currentGeneration(runtime.network); + requireCapability(gen.capabilities, AgenticCapability.WALLET_READS); + await verifyFactoryWiring(runtime.reader, gen); + + const owner = runtime.signerPushAccount(); + const prepared = prepareRules(options.rules, { + owner, + pushChainNamespace: runtime.pushChainNamespace, + validator: gen.addresses.sessionValidator, + rulesPolicy: gen.addresses.rulesPolicy, + capabilities: gen.capabilities, + nowSeconds: runtime.nowSeconds(), + forbiddenTargets: forbiddenTargets(gen), + }); + + const snap = await Snapshot.at(runtime.reader); + const index = await walletCount(snap, gen, owner); + const [predicted, deployed] = await snap.read( + gen.addresses.factory, + gen.contracts.abis.factory, + 'predictWallet', + [owner, index] + ); + const wallet = getAddress(predicted); + const mirror = deriveWallet({ + factory: gen.addresses.factory, + walletImplementation: gen.addresses.walletImplementation, + owner, + index, + }); + if (wallet !== mirror || deployed || (await snap.code(wallet))) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INDEX_RACE, + `next wallet slot ${index} for ${owner} is not a fresh counterfactual address`, + { details: { wallet, mirror, deployed } } + ); + } + const selfTarget = prepared.findIndex((p) => p.nativeTerms?.target === wallet); + if (selfTarget >= 0) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + `rules[${selfTarget}].target is the wallet being created; the contracts refuse it as a native target` + ); + } + emitAgentic(runtime, hook, PROGRESS_HOOK.AGENTIC_TX_101, wallet, Number(index), false); + + // A fresh wallet's grant nonce starts at 0 and increments per grant. + const predictedIds = prepared.map((p, i) => + computeRulesId({ validator: gen.addresses.sessionValidator, agent: p.agent, grantNonce: BigInt(i) }) + ); + const calls: MultiCall[] = [ + { to: gen.addresses.factory, value: BigInt(0), data: gen.contracts.encodeDeployWallet(label) }, + ...prepared.map((p) => ({ + to: wallet, + value: BigInt(0), + data: gen.contracts.encodeGrantRules(p.session), + })), + ]; + const strategy = + calls.length === 1 ? 'single' : runtime.signerIsPushNative() ? 'push-eoa-batch' : 'uea-multicall'; + emitAgentic(runtime, hook, PROGRESS_HOOK.AGENTIC_TX_102, wallet, strategy); + + let tx; + try { + tx = await sendOwnerCalls(runtime, calls, hook); + } catch (err) { + const wrapped = await partialCreateError(runtime, gen, wallet, Number(index), err); + emitFailure(runtime, hook, wrapped); + throw wrapped; + } + + let logs; + try { + ({ logs } = await confirmedLogs(runtime, tx)); + } catch (err) { + const wrapped = await partialCreateError(runtime, gen, wallet, Number(index), err); + emitFailure(runtime, hook, wrapped); + throw wrapped; + } + const deployedEv = gen.contracts.parseWalletDeployed(logs, gen.addresses.factory); + const granted = gen.contracts.parseRulesGranted(logs, wallet).map((g) => g.rulesId); + if (deployedEv.length !== 1 || deployedEv[0].wallet !== wallet || deployedEv[0].index !== index) { + const err = new AgenticError( + AGENTIC_ERROR_CODE.INDEX_RACE, + `deployWallet produced ${deployedEv.map((d) => `${d.wallet}#${d.index}`).join(', ') || 'no wallet'}, expected ${wallet}#${index}; grants targeted ${wallet}`, + { + hint: 'Another deployment by this owner raced this call. Inspect both wallets with client.agentic.list() before retrying.', + details: { expected: wallet, deployed: deployedEv, grantedRulesIds: granted, txHash: tx.hash }, + } + ); + emitFailure(runtime, hook, err); + throw err; + } + if (!sameIds(granted, predictedIds)) { + const err = new AgenticError( + AGENTIC_ERROR_CODE.RECEIPT_MISMATCH, + 'RulesGranted events do not match the requested rules in order', + { details: { granted, predicted: predictedIds, txHash: tx.hash } } + ); + emitFailure(runtime, hook, err); + throw err; + } + if (granted.length > 0) emitAgentic(runtime, hook, PROGRESS_HOOK.AGENTIC_TX_104, granted); + emitAgentic(runtime, hook, PROGRESS_HOOK.AGENTIC_TX_199_01, 'create', tx.hash); + return { wallet, index: Number(index), rulesIds: granted as `0x${string}`[], tx }; +} + +function sameIds(a: readonly Hex[], b: readonly Hex[]): boolean { + return a.length === b.length && a.every((x, i) => x.toLowerCase() === b[i].toLowerCase()); +} + +async function partialCreateError( + runtime: AgenticRuntime, + gen: ReturnType, + wallet: Address, + index: number, + err: unknown +): Promise { + const wrapped = wrapSendError(err); + const batch = err instanceof PushChainBatchExecutionError ? err : undefined; + const hashes = (batch?.transactionHashes ?? + (wrapped as { transactionHashes?: Hex[] }).transactionHashes ?? + []) as Hex[]; + if (hashes.length === 0) return wrapped; + // Something committed. Re-read chain state rather than trusting the error. + let walletDeployed = false; + let grantedRulesIds: Hex[] = []; + try { + walletDeployed = !!(await runtime.reader.getCode({ address: wallet }))?.slice(2); + if (walletDeployed) { + const snap = await Snapshot.at(runtime.reader); + grantedRulesIds = [ + ...(await snap.read(gen.addresses.sessionEngine, gen.contracts.abis.engine, 'getPermissionIDs', [ + wallet, + ])), + ]; + } + } catch { + // keep what we know; the hashes below are authoritative for retry decisions + } + // A reverted atomic transaction committed nothing: report the revert itself. + if (!batch && !walletDeployed) return wrapped; + return new AgenticError( + AGENTIC_ERROR_CODE.CREATE_PARTIAL, + `agentic.create did not complete: ${(wrapped as Error)?.message ?? String(err)}`, + { + hint: walletDeployed + ? `Wallet ${wallet} is deployed. Do not call create again; finish with client.agentic.wallet('${wallet}').rules.add().` + : 'No wallet was deployed. Check the pending hash (if any) before retrying.', + details: { + wallet, + index, + walletDeployed, + grantedRulesIds, + confirmedHashes: hashes, + pendingHash: batch?.pendingTransactionHash, + }, + cause: wrapped, + } + ); +} + +function emitFailure(runtime: AgenticRuntime, hook: CreateOptions['progressHook'], err: unknown): void { + const e = err as { code?: string; message?: string; decodedError?: unknown }; + emitAgentic( + runtime, + hook, + PROGRESS_HOOK.AGENTIC_TX_199_02, + 'create', + e?.code ?? 'UNKNOWN', + e?.message ?? String(err), + e?.decodedError + ); +} diff --git a/packages/core/src/lib/agentic/management/rules-write.ts b/packages/core/src/lib/agentic/management/rules-write.ts new file mode 100644 index 00000000..7523bf09 --- /dev/null +++ b/packages/core/src/lib/agentic/management/rules-write.ts @@ -0,0 +1,298 @@ +import type { Address, Hex } from 'viem'; +import { PROGRESS_HOOK } from '../../progress-hook/progress-hook.types'; +import type { MultiCall, UniversalTxResponse } from '../../orchestrator/orchestrator.types'; +import { AgenticCapability, requireCapability } from '../capabilities'; +import { forbiddenTargets, type AgenticGeneration } from '../deployments'; +import { rulesId as computeRulesId } from '../codec/ids'; +import { isUniversalRule, prepareRules } from '../codec/rules'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; +import type { AgenticRuntime } from '../runtime'; +import type { AgenticHex, AgenticProgressHook, Rule } from '../agentic.types'; +import { chainFromHash, readActiveRules, readNativeSpend, type ActiveRule } from '../reads/rules'; +import { Snapshot } from '../reads/snapshot'; +import { + assertCanSign, + assertOwner, + confirmedLogs, + emitAgentic, + sendOwnerCalls, + wrapSendError, +} from './common'; + +const MODE_NATIVE = 1; + +function existingPairs(active: readonly ActiveRule[], pushChainNamespace: string, exclude: Set) { + return active + .filter((r) => !exclude.has(r.rulesId.toLowerCase())) + .map((r) => ({ + agent: r.agent, + rulesId: r.rulesId, + chainNamespace: chainFromHash(r.chainHash, pushChainNamespace) ?? `hash:${r.chainHash}`, + })); +} + +function encodeContext(runtime: AgenticRuntime, gen: AgenticGeneration, owner: Address, wallet: Address) { + return { + owner, + pushChainNamespace: runtime.pushChainNamespace, + validator: gen.addresses.sessionValidator, + rulesPolicy: gen.addresses.rulesPolicy, + capabilities: gen.capabilities, + nowSeconds: runtime.nowSeconds(), + forbiddenTargets: forbiddenTargets(gen, wallet), + }; +} + +async function finish( + runtime: AgenticRuntime, + hook: AgenticProgressHook | undefined, + operation: string, + run: () => Promise +): Promise { + try { + const result = await run(); + emitAgentic(runtime, hook, PROGRESS_HOOK.AGENTIC_TX_199_01, operation, result.tx.hash); + return result; + } catch (err) { + const wrapped = wrapSendError(err) as { code?: string; message?: string; decodedError?: unknown }; + emitAgentic( + runtime, + hook, + PROGRESS_HOOK.AGENTIC_TX_199_02, + operation, + wrapped?.code ?? 'UNKNOWN', + wrapped?.message ?? String(err), + wrapped?.decodedError + ); + throw wrapped; + } +} + +/** w.rules.add(rules): owner grants on an existing wallet, IDs in input order. */ +export async function addRules( + runtime: AgenticRuntime, + gen: AgenticGeneration, + wallet: Address, + rules: readonly Rule[], + hook?: AgenticProgressHook +): Promise<{ rulesIds: AgenticHex[]; tx: UniversalTxResponse }> { + assertCanSign(runtime, 'rules.add'); + if (!Array.isArray(rules) || rules.length === 0) { + throw new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, 'rules.add needs at least one rule'); + } + const snap = await Snapshot.at(runtime.reader); + const owner = await assertOwner(runtime, gen, wallet, snap); + const active = await readActiveRules(snap, gen, wallet); + const prepared = prepareRules(rules, { + ...encodeContext(runtime, gen, owner, wallet), + existing: existingPairs(active, runtime.pushChainNamespace, new Set()), + }); + const nonce = BigInt( + await snap.read(wallet, gen.contracts.abis.wallet, 'grantNonce') + ); + const predicted = prepared.map((p, i) => + computeRulesId({ validator: gen.addresses.sessionValidator, agent: p.agent, grantNonce: nonce + BigInt(i) }) + ); + const calls: MultiCall[] = prepared.map((p) => ({ + to: wallet, + value: BigInt(0), + data: gen.contracts.encodeGrantRules(p.session), + })); + return finish(runtime, hook, 'rules.add', async () => { + const tx = await sendOwnerCalls(runtime, calls, hook); + const { logs } = await confirmedLogs(runtime, tx); + const granted = gen.contracts.parseRulesGranted(logs, wallet).map((g) => g.rulesId as AgenticHex); + if (!sameIds(granted, predicted)) { + throw new AgenticError( + AGENTIC_ERROR_CODE.RECEIPT_MISMATCH, + 'RulesGranted events do not match the requested rules in order (a concurrent grant may have raced)', + { details: { granted, predicted, txHash: tx.hash } } + ); + } + emitAgentic(runtime, hook, PROGRESS_HOOK.AGENTIC_TX_104, granted); + return { rulesIds: granted, tx }; + }); +} + +/** Bare revoke (no IDs, empty list, or anything but { all: true }) is refused. */ +export function assertRevokeTarget(target: unknown): { all: boolean; ids?: AgenticHex[] } { + const all = !!target && !Array.isArray(target) && (target as { all?: unknown }).all === true; + const ids = Array.isArray(target) ? (target as AgenticHex[]) : undefined; + if (!all && (!ids || ids.length === 0)) { + throw new AgenticError( + AGENTIC_ERROR_CODE.REVOKE_NEEDS_TARGET, + 'rules.revoke needs explicit rule IDs or { all: true }', + { hint: 'A bare revoke that wipes every rule is too easy to make by mistake.' } + ); + } + return { all, ids }; +} + +/** w.rules.revoke(ids) / w.rules.revoke({ all: true }). Bare revoke is refused. */ +export async function revokeRules( + runtime: AgenticRuntime, + gen: AgenticGeneration, + wallet: Address, + target: AgenticHex[] | { all: true; progressHook?: AgenticProgressHook } | undefined, + hook?: AgenticProgressHook +): Promise { + const { all, ids } = assertRevokeTarget(target); + if (all) hook = (target as { progressHook?: AgenticProgressHook }).progressHook ?? hook; + assertCanSign(runtime, 'rules.revoke'); + const snap = await Snapshot.at(runtime.reader); + await assertOwner(runtime, gen, wallet, snap); + + let calls: MultiCall[]; + if (all) { + calls = [{ to: wallet, value: BigInt(0), data: gen.contracts.encodeRevokeAllRules() }]; + } else { + const unique = new Set((ids as Hex[]).map((i) => i.toLowerCase())); + if (unique.size !== (ids as Hex[]).length) { + throw new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, 'rules.revoke got the same rule ID twice'); + } + for (const id of ids as Hex[]) { + const enabled = await snap.read( + gen.addresses.sessionEngine, + gen.contracts.abis.engine, + 'isPermissionEnabled', + [id, wallet] + ); + if (!enabled) { + throw new AgenticError(AGENTIC_ERROR_CODE.RULE_NOT_FOUND, `rule ${id} is not enabled on ${wallet}`); + } + } + // Several IDs go through one owner `execute` batch so revocation is atomic + // regardless of signer batching support. + calls = + (ids as Hex[]).length === 1 + ? [{ to: wallet, value: BigInt(0), data: gen.contracts.encodeRevokeRules((ids as Hex[])[0]) }] + : [ + { + to: wallet, + value: BigInt(0), + data: gen.contracts.encodeExecute( + (ids as Hex[]).map((id) => ({ target: wallet, value: BigInt(0), data: gen.contracts.encodeRevokeRules(id) })) + ), + }, + ]; + } + const result = await finish(runtime, hook, 'rules.revoke', async () => { + const tx = await sendOwnerCalls(runtime, calls, hook); + const { logs } = await confirmedLogs(runtime, tx); + const revoked = gen.contracts.parseRulesRevoked(logs, wallet).map((r) => r.rulesId); + emitAgentic(runtime, hook, PROGRESS_HOOK.AGENTIC_TX_105, all ? { all: true } : { rulesIds: revoked }); + return { tx }; + }); + return result.tx; +} + +/** + * w.rules.update({ rules: [{ rulesId, rule }] }): for every pair, inside ONE + * owner `execute` batch: assertSpent(expected) → revokeRules(old) → + * grantRules(new). Never falls back to sequential sends. An agent spending + * between the read and inclusion makes the whole batch revert; retry needs a + * fresh read and a new owner signature. New counters start at zero. + */ +export async function updateRules( + runtime: AgenticRuntime, + gen: AgenticGeneration, + wallet: Address, + params: { rules: { rulesId: AgenticHex; rule: Rule }[]; progressHook?: AgenticProgressHook } +): Promise<{ rules: { rulesId: AgenticHex; replaced: AgenticHex }[]; tx: UniversalTxResponse }> { + const hook = params?.progressHook; + assertCanSign(runtime, 'rules.update'); + if (!params || !Array.isArray(params.rules) || params.rules.length === 0) { + throw new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, 'rules.update needs at least one { rulesId, rule } pair'); + } + requireCapability(gen.capabilities, AgenticCapability.OWNER_EXECUTE); + const oldIds = params.rules.map((p) => p.rulesId.toLowerCase()); + if (new Set(oldIds).size !== oldIds.length) { + throw new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, 'rules.update names the same old rule twice'); + } + + const snap = await Snapshot.at(runtime.reader); + const owner = await assertOwner(runtime, gen, wallet, snap); + const active = await readActiveRules(snap, gen, wallet); + const byId = new Map(active.map((r) => [r.rulesId.toLowerCase(), r])); + + const assertions: Awaited>[] = []; + for (const pair of params.rules) { + const old = byId.get(pair.rulesId.toLowerCase()); + if (!old) { + throw new AgenticError(AGENTIC_ERROR_CODE.RULE_NOT_FOUND, `rule ${pair.rulesId} is not enabled on ${wallet}`); + } + if (old.mode !== MODE_NATIVE || isUniversalRule(pair.rule)) { + requireCapability(gen.capabilities, AgenticCapability.ASSERT_SPENT_UNIVERSAL_MULTI); + } + requireCapability(gen.capabilities, AgenticCapability.ASSERT_SPENT_NATIVE); + if (old.actionIds.length !== 1) { + throw new AgenticError( + AGENTIC_ERROR_CODE.RULE_READ_FAILED, + `rule ${pair.rulesId} has ${old.actionIds.length} native actions; replacing it would need one assertion per action` + ); + } + assertions.push(await readNativeSpend(snap, gen, wallet, old)); + } + + const prepared = prepareRules( + params.rules.map((p) => p.rule), + { + ...encodeContext(runtime, gen, owner, wallet), + existing: existingPairs(active, runtime.pushChainNamespace, new Set(oldIds)), + } + ); + const nonce = BigInt(await snap.read(wallet, gen.contracts.abis.wallet, 'grantNonce')); + const predicted = prepared.map((p, i) => + computeRulesId({ validator: gen.addresses.sessionValidator, agent: p.agent, grantNonce: nonce + BigInt(i) }) + ); + + const batch = params.rules.flatMap((pair, i) => [ + { + target: gen.addresses.rulesPolicy, + value: BigInt(0), + data: gen.contracts.encodeAssertSpentNative(assertions[i].configId, wallet, assertions[i]), + }, + { target: wallet, value: BigInt(0), data: gen.contracts.encodeRevokeRules(pair.rulesId) }, + { target: wallet, value: BigInt(0), data: gen.contracts.encodeGrantRules(prepared[i].session) }, + ]); + const call: MultiCall = { to: wallet, value: BigInt(0), data: gen.contracts.encodeExecute(batch) }; + + return finish(runtime, hook, 'rules.update', async () => { + const tx = await sendOwnerCalls(runtime, [call], hook); + const { logs } = await confirmedLogs(runtime, tx); + const granted = gen.contracts.parseRulesGranted(logs, wallet).map((g) => g.rulesId as AgenticHex); + const revoked = gen.contracts.parseRulesRevoked(logs, wallet).map((r) => r.rulesId.toLowerCase()); + if (!sameIds(granted, predicted) || !sameIds(revoked as Hex[], oldIds as Hex[])) { + throw new AgenticError( + AGENTIC_ERROR_CODE.RECEIPT_MISMATCH, + 'rules.update receipt does not show the expected revoke/grant pairs', + { details: { granted, predicted, revoked, txHash: tx.hash } } + ); + } + emitAgentic(runtime, hook, PROGRESS_HOOK.AGENTIC_TX_105, { rulesIds: params.rules.map((p) => p.rulesId) }); + emitAgentic(runtime, hook, PROGRESS_HOOK.AGENTIC_TX_104, granted); + return { + tx, + rules: granted.map((id, i) => ({ rulesId: id, replaced: params.rules[i].rulesId })), + }; + }); +} + +function sameIds(a: readonly Hex[], b: readonly Hex[]): boolean { + return a.length === b.length && a.every((x, i) => x.toLowerCase() === b[i].toLowerCase()); +} + +/** w.setLabel — PROPOSED; no generation implements an editable label (A07). */ +export async function setLabel( + _runtime: AgenticRuntime, + gen: AgenticGeneration, + _wallet: Address, + label: string +): Promise { + if (typeof label !== 'string') { + throw new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, 'label must be a string'); + } + requireCapability(gen.capabilities, AgenticCapability.SET_LABEL); + throw new AgenticError(AGENTIC_ERROR_CODE.CAPABILITY_UNAVAILABLE, 'setLabel has no adapter implementation'); +} + diff --git a/packages/core/src/lib/agentic/reads/checkpoints.ts b/packages/core/src/lib/agentic/reads/checkpoints.ts new file mode 100644 index 00000000..71381920 --- /dev/null +++ b/packages/core/src/lib/agentic/reads/checkpoints.ts @@ -0,0 +1,85 @@ +import type { Address } from 'viem'; +import { AgenticCapability, requireCapability } from '../capabilities'; +import type { AgenticGeneration } from '../deployments'; +import type { ChainReader } from '../contracts/reader'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; +import type { Checkpoint } from '../agentic.types'; +import { Snapshot, scanLogs } from './snapshot'; + +const MAX_ATTEMPTS = 2; + +/** + * w.checkpoints(): Checkpointed events in (block, tx, log) order, checked + * against the wallet's checkpointCount() at the same snapshot block. + * `sinceBlock` is inclusive. Evaluators should compare counts — one block can + * hold several ticks, and allowance pulls change balances without any tick. + */ +export async function readCheckpoints( + reader: ChainReader, + gen: AgenticGeneration, + wallet: Address, + sinceBlock?: bigint +): Promise<{ checkpoints: Checkpoint[]; count: bigint; blockNumber: bigint }> { + requireCapability(gen.capabilities, AgenticCapability.CHECKPOINTS); + let lastError: AgenticError | undefined; + for (let attempt = 0; attempt < MAX_ATTEMPTS; attempt++) { + const snap = await Snapshot.at(reader); + const count = BigInt( + await snap.read(wallet, gen.contracts.abis.wallet, 'checkpointCount') + ); + const from = sinceBlock !== undefined && sinceBlock > gen.startBlock ? sinceBlock : gen.startBlock; + const logs = await scanLogs( + reader, + { address: wallet, event: gen.contracts.events.checkpointed }, + from, + snap.blockNumber + ); + const decoded = gen.contracts + .parseCheckpointed(logs, wallet) + .sort((a, b) => + a.blockNumber !== b.blockNumber + ? a.blockNumber < b.blockNumber + ? -1 + : 1 + : a.transactionIndex !== b.transactionIndex + ? a.transactionIndex - b.transactionIndex + : a.logIndex - b.logIndex + ); + const problem = validateSequence(decoded.map((c) => c.seq), count, sinceBlock === undefined || from === gen.startBlock); + if (!problem) { + return { + count, + blockNumber: snap.blockNumber, + checkpoints: decoded.map(({ seq, kind, ref, blockNumber, txHash }) => ({ + seq, + kind, + ref, + blockNumber, + txHash, + })), + }; + } + lastError = new AgenticError(AGENTIC_ERROR_CODE.INCONSISTENT_READ, problem, { + details: { wallet, count, blockNumber: snap.blockNumber }, + }); + } + throw lastError as AgenticError; +} + +/** Sequence must be contiguous, end at `count`, and start at 1 for a full scan. */ +export function validateSequence(seqs: number[], count: bigint, fullRange: boolean): string | null { + for (let i = 1; i < seqs.length; i++) { + if (seqs[i] !== seqs[i - 1] + 1) return `checkpoint sequence gap between ${seqs[i - 1]} and ${seqs[i]}`; + } + if (fullRange) { + if (BigInt(seqs.length) !== count) { + return `found ${seqs.length} Checkpointed events but checkpointCount() is ${count}`; + } + if (seqs.length > 0 && seqs[0] !== 1) return `first checkpoint seq is ${seqs[0]}, expected 1`; + return null; + } + if (seqs.length > 0 && BigInt(seqs[seqs.length - 1]) !== count) { + return `last checkpoint seq ${seqs[seqs.length - 1]} does not match checkpointCount() ${count}`; + } + return null; +} diff --git a/packages/core/src/lib/agentic/reads/rules.ts b/packages/core/src/lib/agentic/reads/rules.ts new file mode 100644 index 00000000..8219b0a4 --- /dev/null +++ b/packages/core/src/lib/agentic/reads/rules.ts @@ -0,0 +1,260 @@ +import { getAddress, type Address, type Hex } from 'viem'; +import { CHAIN } from '../../constants/enums'; +import { AgenticCapability, CAPABILITY_DEPENDENCY, requireCapability } from '../capabilities'; +import type { AgenticGeneration } from '../deployments'; +import type { NativeConfigRead, ModeRead } from '../contracts/e704d5b'; +import { configId } from '../codec/ids'; +import { nativeTermsToRule } from '../codec/native'; +import { chainHash } from '../codec/rules'; +import { AGENTIC_ERROR_CODE, AgenticError, capabilityUnavailable } from '../errors'; +import type { AgenticHex, RulesRecord } from '../agentic.types'; +import { Snapshot, scanLogs } from './snapshot'; + +const ZERO_REF = `0x${'00'.repeat(32)}` as AgenticHex; +const MODE_UNIVERSAL = 0; +const MODE_NATIVE = 1; + +export interface ActiveRule { + rulesId: Hex; + /** agentOf(rulesId); zero means the engine no longer resolves it. */ + agent: Address; + actionIds: readonly Hex[]; + mode: number; + vm: number; + chainHash: Hex; +} + +/** Enabled rule IDs with their agent and governed chain, all at one block. */ +export async function readActiveRules( + snap: Snapshot, + gen: AgenticGeneration, + wallet: Address +): Promise { + const ids = await snap.read( + gen.addresses.sessionEngine, + gen.contracts.abis.engine, + 'getPermissionIDs', + [wallet] + ); + return Promise.all(ids.map((id) => readActiveRule(snap, gen, wallet, id))); +} + +async function readActiveRule( + snap: Snapshot, + gen: AgenticGeneration, + wallet: Address, + rulesId: Hex +): Promise { + const [agent, actionIds] = await Promise.all([ + snap.read
(wallet, gen.contracts.abis.wallet, 'agentOf', [rulesId]), + snap.read(gen.addresses.sessionEngine, gen.contracts.abis.engine, 'getEnabledActions', [ + wallet, + rulesId, + ]), + ]); + if (actionIds.length === 0) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INCONSISTENT_READ, + `enabled rule ${rulesId} has no enabled actions` + ); + } + const modes = await Promise.all( + actionIds.map((a) => + snap.read(gen.addresses.rulesPolicy, gen.contracts.abis.policy, 'getMode', [ + configId(wallet, rulesId, a), + wallet, + ]) + ) + ); + const first = modes[0]; + if (!modes.every((m) => m.initialized && m.chainHash === first.chainHash && m.mode === first.mode)) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INCONSISTENT_READ, + `rule ${rulesId} has uninitialized or mixed-chain policy configs` + ); + } + return { + rulesId, + agent: getAddress(agent), + actionIds, + mode: Number(first.mode), + vm: Number(first.vm), + chainHash: first.chainHash, + }; +} + +/** Map a stored chain hash back to its CAIP-2 string from known chains. */ +export function chainFromHash(hash: Hex, pushChainNamespace: string): string | undefined { + const known = [pushChainNamespace, ...Object.values(CHAIN)]; + return known.find((c) => chainHash(c) === hash); +} + +/** + * Agent-door rule selection for one send (spec 2.a): enabled rules whose agent + * is the signer and whose chain is the destination, read uncached at one + * block. Expiry, caps and policy remain on-chain checks. + */ +export async function selectRuleForSend( + snap: Snapshot, + gen: AgenticGeneration, + wallet: Address, + agent: Address, + destinationChain: string +): Promise { + const active = await readActiveRules(snap, gen, wallet); + const want = chainHash(destinationChain); + const matches = active.filter( + (r) => r.agent === getAddress(agent) && r.chainHash === want + ); + if (matches.length === 0) { + throw new AgenticError( + AGENTIC_ERROR_CODE.NO_RULES_FOR_CHAIN, + `no enabled rule on ${wallet} names ${agent} for ${destinationChain}`, + { details: { wallet, agent, destinationChain, blockNumber: snap.blockNumber } } + ); + } + if (matches.length > 1) { + throw new AgenticError( + AGENTIC_ERROR_CODE.DUPLICATE_RULE, + `${matches.length} enabled rules on ${wallet} name ${agent} for ${destinationChain}`, + { + hint: 'The SDK will not pick one arbitrarily. Ask the owner to revoke all but one (rules.revoke) and retry.', + details: { rulesIds: matches.map((m) => m.rulesId) }, + } + ); + } + return matches[0]; +} + +/** Decode one active rule into the public record. */ +export async function decodeActiveRule( + snap: Snapshot, + gen: AgenticGeneration, + wallet: Address, + rule: ActiveRule, + pushChainNamespace: string +): Promise { + if (rule.mode === MODE_UNIVERSAL) { + throw capabilityUnavailable( + AgenticCapability.UNIVERSAL_EVM_RULES, + `rule ${rule.rulesId} is a universal rule; ${CAPABILITY_DEPENDENCY[AgenticCapability.UNIVERSAL_EVM_RULES]}` + ); + } + if (rule.mode !== MODE_NATIVE) { + throw new AgenticError(AGENTIC_ERROR_CODE.RULE_READ_FAILED, `rule ${rule.rulesId} has unknown mode ${rule.mode}`); + } + if (rule.actionIds.length !== 1) { + throw new AgenticError( + AGENTIC_ERROR_CODE.RULE_READ_FAILED, + `rule ${rule.rulesId} has ${rule.actionIds.length} native actions; the public NativeRule is single-action (A02)` + ); + } + const cfg = await snap.read( + gen.addresses.rulesPolicy, + gen.contracts.abis.policy, + 'getNativeConfig', + [configId(wallet, rule.rulesId, rule.actionIds[0]), wallet] + ); + if (!cfg.initialized) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INCONSISTENT_READ, + `native config for ${rule.rulesId} is not initialized` + ); + } + if (rule.agent === getAddress(`0x${'00'.repeat(20)}`)) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INCONSISTENT_READ, + `enabled rule ${rule.rulesId} does not resolve to an agent` + ); + } + return { + rulesId: rule.rulesId as AgenticHex, + enabled: true, + chainNamespace: pushChainNamespace, + agent: rule.agent, + validUntil: Number(cfg.validUntil), + ref: ZERO_REF, + rule: nativeTermsToRule(cfg, rule.agent, ZERO_REF), + spent: { + kind: 'native', + valueSpent: cfg.valueSpent, + amountSpent: cfg.amountSpent, + callsUsed: Number(cfg.callsUsed), + }, + }; +} + +/** Native spend counters for the update assertion. */ +export async function readNativeSpend( + snap: Snapshot, + gen: AgenticGeneration, + wallet: Address, + rule: ActiveRule +): Promise<{ configId: Hex; valueSpent: bigint; amountSpent: bigint; callsUsed: number }> { + const id = configId(wallet, rule.rulesId, rule.actionIds[0]); + const cfg = await snap.read( + gen.addresses.rulesPolicy, + gen.contracts.abis.policy, + 'getNativeConfig', + [id, wallet] + ); + return { + configId: id, + valueSpent: cfg.valueSpent, + amountSpent: cfg.amountSpent, + callsUsed: Number(cfg.callsUsed), + }; +} + +export async function listRules( + snap: Snapshot, + gen: AgenticGeneration, + wallet: Address, + pushChainNamespace: string +): Promise { + requireCapability(gen.capabilities, AgenticCapability.ACTIVE_RULE_READS); + const active = await readActiveRules(snap, gen, wallet); + const records: RulesRecord[] = []; + for (const r of active) records.push(await decodeActiveRule(snap, gen, wallet, r, pushChainNamespace)); + return records; +} + +/** + * rules.get: an enabled rule decodes; a revoked rule needs the history + * capability (A06); an ID that was never granted is RULE_NOT_FOUND. + */ +export async function getRule( + snap: Snapshot, + gen: AgenticGeneration, + wallet: Address, + rulesId: Hex, + pushChainNamespace: string +): Promise { + requireCapability(gen.capabilities, AgenticCapability.ACTIVE_RULE_READS); + const enabled = await snap.read( + gen.addresses.sessionEngine, + gen.contracts.abis.engine, + 'isPermissionEnabled', + [rulesId, wallet] + ); + if (enabled) { + const active = await readActiveRule(snap, gen, wallet, rulesId); + return decodeActiveRule(snap, gen, wallet, active, pushChainNamespace); + } + const revoked = await scanLogs( + snap.reader, + { address: wallet, event: gen.contracts.events.rulesRevoked, args: { rulesId } }, + gen.startBlock, + snap.blockNumber + ); + if (gen.contracts.parseRulesRevoked(revoked, wallet).length > 0) { + // No generation implements history reconstruction yet; a revoked rule is + // reported as such rather than as an empty or missing record. + const err = capabilityUnavailable( + AgenticCapability.RULE_HISTORY, + `rule ${rulesId} was revoked; ${CAPABILITY_DEPENDENCY[AgenticCapability.RULE_HISTORY]}` + ); + throw new AgenticError(err.code, err.message, { details: { rulesId, revoked: true } }); + } + throw new AgenticError(AGENTIC_ERROR_CODE.RULE_NOT_FOUND, `rule ${rulesId} was never granted on ${wallet}`); +} diff --git a/packages/core/src/lib/agentic/reads/snapshot.ts b/packages/core/src/lib/agentic/reads/snapshot.ts new file mode 100644 index 00000000..e22675c9 --- /dev/null +++ b/packages/core/src/lib/agentic/reads/snapshot.ts @@ -0,0 +1,92 @@ +import type { AbiEvent, Address, Log } from 'viem'; +import type { ChainReader } from '../contracts/reader'; +import { AGENTIC_ERROR_CODE, AgenticError, type AgenticErrorCode } from '../errors'; + +/** + * All reads of one logical operation are pinned to a single block so dependent + * reads (enumerate IDs → per-ID config) observe one state. An RPC failure is + * surfaced as an error; it is never treated as "empty". + */ +export class Snapshot { + constructor( + readonly reader: ChainReader, + readonly blockNumber: bigint, + private readonly failCode: AgenticErrorCode = AGENTIC_ERROR_CODE.RULE_READ_FAILED + ) {} + + static async at( + reader: ChainReader, + failCode: AgenticErrorCode = AGENTIC_ERROR_CODE.RULE_READ_FAILED + ): Promise { + let block: bigint; + try { + block = await reader.getBlockNumber(); + } catch (cause) { + throw new AgenticError(failCode, 'could not read the current Push block number', { cause }); + } + return new Snapshot(reader, block, failCode); + } + + async read( + address: Address, + abi: readonly unknown[], + functionName: string, + args: readonly unknown[] = [] + ): Promise { + try { + return (await this.reader.readContract({ + address, + abi, + functionName, + args, + blockNumber: this.blockNumber, + })) as T; + } catch (cause) { + throw new AgenticError( + this.failCode, + `${functionName} read on ${address} failed at block ${this.blockNumber}`, + { cause, details: { address, functionName, blockNumber: this.blockNumber } } + ); + } + } + + async code(address: Address): Promise { + try { + const code = await this.reader.getCode({ address, blockNumber: this.blockNumber }); + return !!code && code !== '0x'; + } catch (cause) { + throw new AgenticError(this.failCode, `getCode(${address}) failed`, { cause }); + } + } +} + +/** Max block span per eth_getLogs request. */ +export const LOG_PAGE_BLOCKS = BigInt(50_000); + +/** + * Paginated log scan [fromBlock, toBlock] inclusive. A failed page fails the + * whole scan; partial results are never returned. + */ +export async function scanLogs( + reader: ChainReader, + args: { address: Address; event: AbiEvent; args?: Record }, + fromBlock: bigint, + toBlock: bigint, + page: bigint = LOG_PAGE_BLOCKS +): Promise { + const out: Log[] = []; + if (fromBlock > toBlock) return out; + for (let start = fromBlock; start <= toBlock; start += page) { + const end = start + page - BigInt(1) > toBlock ? toBlock : start + page - BigInt(1); + try { + out.push(...(await reader.getLogs({ ...args, fromBlock: start, toBlock: end }))); + } catch (cause) { + throw new AgenticError( + AGENTIC_ERROR_CODE.RULE_READ_FAILED, + `log scan for ${args.event.name} failed for blocks ${start}-${end}`, + { cause } + ); + } + } + return out; +} diff --git a/packages/core/src/lib/agentic/reads/wallets.ts b/packages/core/src/lib/agentic/reads/wallets.ts new file mode 100644 index 00000000..4bd0941a --- /dev/null +++ b/packages/core/src/lib/agentic/reads/wallets.ts @@ -0,0 +1,199 @@ +import { getAddress, type Address } from 'viem'; +import type { AgenticGeneration } from '../deployments'; +import type { ChainReader } from '../contracts/reader'; +import { deriveWallet } from '../codec/ids'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; +import type { WalletInfo, WalletSummary } from '../agentic.types'; +import { Snapshot, scanLogs } from './snapshot'; + +/** Factory-predicted address for (owner, index), cross-checked against the pure mirror. */ +async function predict( + snap: Snapshot, + gen: AgenticGeneration, + owner: Address, + index: bigint +): Promise<{ address: Address; deployed: boolean }> { + const [address, deployed] = await snap.read( + gen.addresses.factory, + gen.contracts.abis.factory, + 'predictWallet', + [owner, index] + ); + const mirror = deriveWallet({ + factory: gen.addresses.factory, + walletImplementation: gen.addresses.walletImplementation, + owner, + index, + }); + if (getAddress(address) !== mirror) { + // Derivation drift between the SDK mirror and the factory (obligation 13). + throw new AgenticError( + AGENTIC_ERROR_CODE.INCONSISTENT_READ, + `factory predicted ${address} for (${owner}, ${index}) but the SDK derives ${mirror}`, + { details: { generation: gen.id } } + ); + } + return { address: getAddress(address), deployed }; +} + +export async function walletCount(snap: Snapshot, gen: AgenticGeneration, owner: Address): Promise { + return BigInt( + await snap.read(gen.addresses.factory, gen.contracts.abis.factory, 'walletCount', [owner]) + ); +} + +/** client.agentic.derive: default index is the owner's next unused slot. */ +export async function deriveForOwner( + reader: ChainReader, + gen: AgenticGeneration, + owner: Address, + index?: number +): Promise<{ address: Address; index: number; deployed: boolean }> { + const snap = await Snapshot.at(reader); + const next = await walletCount(snap, gen, owner); + let target = next; + if (index !== undefined) { + if (!Number.isInteger(index) || index < 0) { + throw new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, 'index must be a non-negative integer'); + } + target = BigInt(index); + if (target > next) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + `index ${index} is beyond the owner's next unused index ${next}; the factory only predicts up to the next slot` + ); + } + } + const p = await predict(snap, gen, owner, target); + return { address: p.address, index: Number(target), deployed: p.deployed }; +} + +/** Deploy-time labels for the owner's wallets from WalletDeployed events. */ +async function labelsFor( + reader: ChainReader, + gen: AgenticGeneration, + snap: Snapshot, + filter: { owner?: Address; wallet?: Address } +): Promise> { + const logs = await scanLogs( + reader, + { address: gen.addresses.factory, event: gen.contracts.events.walletDeployed, args: filter }, + gen.startBlock, + snap.blockNumber + ); + const map = new Map(); + for (const ev of gen.contracts.parseWalletDeployed(logs, gen.addresses.factory)) { + map.set(ev.wallet.toLowerCase(), ev.label); + } + return map; +} + +export async function rulesCount(snap: Snapshot, gen: AgenticGeneration, wallet: Address): Promise { + const ids = await snap.read( + gen.addresses.sessionEngine, + gen.contracts.abis.engine, + 'getPermissionIDs', + [wallet] + ); + return ids.length; +} + +/** + * client.agentic.list: every deployed slot plus the next undeployed slot + * (deployed=false, rulesCount=0), as in the spec example. + */ +export async function listForOwner( + reader: ChainReader, + gen: AgenticGeneration, + owner: Address +): Promise { + const snap = await Snapshot.at(reader); + const count = await walletCount(snap, gen, owner); + const labels = count > BigInt(0) ? await labelsFor(reader, gen, snap, { owner }) : new Map(); + const out: WalletSummary[] = []; + for (let i = BigInt(0); i <= count; i++) { + const p = await predict(snap, gen, owner, i); + const deployed = i < count; + if (deployed !== p.deployed) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INCONSISTENT_READ, + `factory reports slot ${i} deployed=${p.deployed} but walletCount is ${count}` + ); + } + const label = deployed ? labels.get(p.address.toLowerCase()) : ''; + if (deployed && label === undefined) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INCONSISTENT_READ, + `no WalletDeployed event found for ${p.address} since block ${gen.startBlock}` + ); + } + out.push({ + address: p.address, + index: Number(i), + label: label ?? '', + deployed, + rulesCount: deployed ? await rulesCount(snap, gen, p.address) : 0, + }); + } + return out; +} + +/** w.owner(): the owner as the wallet stores it. */ +export async function walletOwner(reader: ChainReader, gen: AgenticGeneration, wallet: Address): Promise
{ + const snap = await Snapshot.at(reader); + return getAddress(await snap.read
(wallet, gen.contracts.abis.wallet, 'owner')); +} + +/** + * w.info(). A deployed wallet is read from chain. An undeployed address is + * only describable when it is `signerIdentity`'s next predicted slot. + */ +export async function walletInfo( + reader: ChainReader, + gen: AgenticGeneration, + wallet: Address, + signerIdentity?: Address +): Promise { + const snap = await Snapshot.at(reader); + const deployed = await snap.code(wallet); + if (!deployed) { + if (signerIdentity) { + const next = await walletCount(snap, gen, signerIdentity); + const p = await predict(snap, gen, signerIdentity, next); + if (p.address === getAddress(wallet)) { + return { + address: p.address, + label: '', + index: Number(next), + owner: getAddress(signerIdentity), + deployed: false, + rulesCount: 0, + }; + } + } + throw new AgenticError( + AGENTIC_ERROR_CODE.WALLET_NOT_DEPLOYED, + `${wallet} is not deployed and is not the connected owner's next wallet slot` + ); + } + const [owner, index] = await Promise.all([ + snap.read
(wallet, gen.contracts.abis.wallet, 'owner'), + snap.read(gen.addresses.factory, gen.contracts.abis.factory, 'indexOf', [wallet]), + ]); + const labels = await labelsFor(reader, gen, snap, { wallet }); + const label = labels.get(wallet.toLowerCase()); + if (label === undefined) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INCONSISTENT_READ, + `no WalletDeployed event found for ${wallet} since block ${gen.startBlock}` + ); + } + return { + address: getAddress(wallet), + label, + index: Number(index), + owner: getAddress(owner), + deployed: true, + rulesCount: await rulesCount(snap, gen, wallet), + }; +} diff --git a/packages/core/src/lib/agentic/response.ts b/packages/core/src/lib/agentic/response.ts new file mode 100644 index 00000000..86f6a22e --- /dev/null +++ b/packages/core/src/lib/agentic/response.ts @@ -0,0 +1,176 @@ +import { + decodeAbiParameters, + decodeFunctionData, + getAddress, + type Address, + type Hex, +} from 'viem'; +import { CHAIN } from '../constants/enums'; +import { UNIVERSAL_GATEWAY_PC } from '../constants/abi'; +import type { + TransactionRouteType, + UniversalTxResponse, +} from '../orchestrator/orchestrator.types'; +import { e704d5b, SEND_OUTBOUND_SELECTOR, UEA_MULTICALL_PREFIX } from './contracts/e704d5b'; +import { generationsFor, resolveWalletGeneration } from './deployments'; +import type { AgenticRuntime } from './runtime'; +import type { AgenticAddress, AgenticHex, AgenticTxMetadata } from './agentic.types'; + +export interface LogicalCall { + to: string; + data: string; + value: bigint; +} + +/** + * Present an AGW send as the wallet's own transaction: `from` is the AGW and + * `to`/`data`/`value` are the logical call. The signer's `origin`, hashes, + * nonce, gas and the on-chain `raw` fields are kept untouched; the wrapped + * call the signer actually sent is recorded in `agentic.rawTo/rawData`. + * Mutates in place so `wait()` (which reads these fields) reports the same + * identity on the receipt. + */ +export function adaptAgenticResponse( + resp: UniversalTxResponse, + meta: Omit & { + logical: LogicalCall; + route?: TransactionRouteType; + chain?: CHAIN; + } +): UniversalTxResponse { + const rawTo = resp.to; + const rawData = resp.data; + if (!resp.raw) { + resp.raw = { from: resp.from, to: resp.to, nonce: resp.nonce, data: resp.data, value: resp.value }; + } + resp.from = getAddress(meta.wallet); + resp.to = meta.logical.to; + resp.data = meta.logical.data; + resp.value = meta.logical.value; + if (meta.route) resp.route = meta.route; + if (meta.chain) { + resp.chain = meta.chain; + resp.chainNamespace = meta.chain; + } + resp.agentic = { + wallet: getAddress(meta.wallet) as AgenticAddress, + door: meta.door, + ...(meta.rulesId ? { rulesId: meta.rulesId } : {}), + ...(meta.chainNamespace ? { chainNamespace: meta.chainNamespace } : {}), + ...(meta.destinationAccount ? { destinationAccount: meta.destinationAccount } : {}), + rawTo, + rawData, + }; + return resp; +} + +/** + * trackTransaction replay: if the tracked Push tx called execute/executeAsAgent + * on a wallet of a registered, verified generation, restore the same logical + * identity a live send reports. Anything unrecognised is returned unchanged. + */ +export async function adaptTrackedResponse( + runtime: Pick, + resp: UniversalTxResponse +): Promise { + if (resp.agentic || generationsFor(runtime.network).length === 0) return resp; + const decoded = e704d5b.decodeWalletCall(resp.data as Hex); + if (!decoded || (decoded.kind !== 'execute' && decoded.kind !== 'executeAsAgent')) return resp; + let wallet: Address; + try { + wallet = getAddress(resp.to); + } catch { + return resp; + } + let gen; + try { + gen = await resolveWalletGeneration(runtime.reader, runtime.network, wallet); + } catch { + return resp; + } + const door = decoded.kind === 'execute' ? 'owner' : 'agent'; + const rulesId = decoded.kind === 'executeAsAgent' ? (decoded.rulesId as AgenticHex) : undefined; + const calls = decoded.calls; + const outbound = calls.find( + (c) => getAddress(c.target) === gen.addresses.gateway && c.data.toLowerCase().startsWith(SEND_OUTBOUND_SELECTOR) + ); + if (outbound) { + const out = decodeOutbound(outbound.data); + const chain = await tokenChain(runtime, out.token); + const first = out.calls[0]; + return adaptAgenticResponse(resp, { + wallet, + door, + rulesId, + chainNamespace: chain, + logical: first + ? { to: first.to, data: first.data, value: first.value } + : { to: wallet, data: '0x', value: BigInt(0) }, + route: resp.route ?? 'UOA_TO_CEA', + chain: resp.chain ?? (chain as CHAIN | undefined), + }); + } + const single = calls.length === 1 ? calls[0] : undefined; + return adaptAgenticResponse(resp, { + wallet, + door, + rulesId, + chainNamespace: undefined, + logical: single + ? { to: single.target, data: single.data, value: single.value } + : { to: wallet, data: resp.data, value: BigInt(0) }, + }); +} + +function decodeOutbound(data: Hex): { + token: Address; + calls: { to: Address; value: bigint; data: Hex }[]; +} { + const { args } = decodeFunctionData({ abi: UNIVERSAL_GATEWAY_PC, data }); + const req = args?.[0] as { token: Address; payload: Hex }; + let calls: { to: Address; value: bigint; data: Hex }[] = []; + if (req.payload.toLowerCase().startsWith(UEA_MULTICALL_PREFIX)) { + try { + const [decodedCalls] = decodeAbiParameters( + [ + { + type: 'tuple[]', + components: [ + { name: 'to', type: 'address' }, + { name: 'value', type: 'uint256' }, + { name: 'data', type: 'bytes' }, + ], + }, + ], + `0x${req.payload.slice(10)}` + ); + calls = decodedCalls.map((c) => ({ to: getAddress(c.to), value: c.value, data: c.data })); + } catch { + calls = []; + } + } + return { token: getAddress(req.token), calls }; +} + +async function tokenChain( + runtime: Pick, + token: Address +): Promise { + try { + return (await runtime.reader.readContract({ + address: token, + abi: [ + { + type: 'function', + name: 'SOURCE_CHAIN_NAMESPACE', + inputs: [], + outputs: [{ type: 'string' }], + stateMutability: 'view', + }, + ], + functionName: 'SOURCE_CHAIN_NAMESPACE', + })) as string; + } catch { + return undefined; + } +} diff --git a/packages/core/src/lib/agentic/runtime.ts b/packages/core/src/lib/agentic/runtime.ts new file mode 100644 index 00000000..acee8142 --- /dev/null +++ b/packages/core/src/lib/agentic/runtime.ts @@ -0,0 +1,107 @@ +import { getAddress, type Address } from 'viem'; +import { CHAIN, PUSH_NETWORK } from '../constants/enums'; +import type { MoveableToken } from '../constants/tokens'; +import type { Orchestrator } from '../orchestrator/orchestrator'; +import type { + ExecuteParams, + TransactionExecutionOptions, + UniversalExecuteParams, + UniversalTxResponse, +} from '../orchestrator/orchestrator.types'; +import type { ProgressEvent } from '../progress-hook/progress-hook.types'; +import { getCEAAddress } from '../orchestrator/cea-utils'; +import type { OrchestratorContext } from '../orchestrator/internals/context'; +import { computeUEAOffchain } from '../orchestrator/internals/uea-manager'; +import { queryOutboundGasFee } from '../orchestrator/internals/gas-calculator'; +import { getNativePRC20ForChain, isPushChain } from '../orchestrator/internals/helpers'; +import { pushChainNamespaceFor } from './chain'; +import { Utils } from '../utils'; +import { chainReaderFromPublicClient, type ChainReader } from './contracts/reader'; +import type { AgenticProgressHook } from './agentic.types'; + +/** + * Everything the AGW module needs from the surrounding client. Tests supply a + * mock; PushChain builds the real one from its orchestrator. Keeping this + * explicit is what separates the signer's identity (gas, account status, + * ownership derivation) from the AGW execution account. + */ +export interface AgenticRuntime { + readonly network: PUSH_NETWORK; + /** 'eip155:' of the connected Push chain — the native rule chain. */ + readonly pushChainNamespace: string; + readonly reader: ChainReader; + readonly isReadOnly: boolean; + /** Connected signer's Push identity: its EOA, or its UEA for its actual origin chain. */ + signerPushAccount(): Address; + /** Connected signer's origin account (universal.origin). */ + signerOrigin(): { chain: CHAIN; address: string }; + signerIsPushNative(): boolean; + /** The signer's ordinary transaction path (orchestrator.execute). */ + execute( + params: ExecuteParams | UniversalExecuteParams, + options?: TransactionExecutionOptions + ): Promise; + /** Emit to the init-time hook and, if different, the per-call hook. */ + emit(event: ProgressEvent, perCallHook?: AgenticProgressHook): void; + /** Whether the signer's own UEA is deployed (always true for a Push EOA). */ + signerAccountDeployed(): Promise; + signerBalance(): Promise; + getGasPrice(): Promise; + quoteOutbound( + prc20: Address, + gasLimit: bigint, + chain: CHAIN + ): Promise<{ protocolFee: bigint; nativeValueForGas: bigint; gasLimitUsed: bigint }>; + resolveCEA(account: Address, chain: CHAIN): Promise<{ cea: Address; isDeployed: boolean }>; + resolvePrc20(token: MoveableToken | undefined, chain: CHAIN): Address; + nowSeconds(): number; +} + +/** Build the runtime over an orchestrator (the orchestrator IS the internal ctx). */ +export function createAgenticRuntime(orchestrator: Orchestrator, isReadOnly: boolean): AgenticRuntime { + const ctx = orchestrator as unknown as OrchestratorContext; + const network = orchestrator.getNetwork(); + return { + network, + pushChainNamespace: pushChainNamespaceFor(network), + get reader() { + return chainReaderFromPublicClient(ctx.pushClient.publicClient); + }, + isReadOnly, + signerPushAccount: () => getAddress(computeUEAOffchain(ctx)), + signerOrigin: () => orchestrator.getUOA(), + signerIsPushNative: () => isPushChain(ctx.universalSigner.account.chain), + execute: (params, options) => orchestrator.execute(params, options), + emit: (event, perCallHook) => { + const base = orchestrator.getProgressHook(); + base?.(event); + if (perCallHook && perCallHook !== base) perCallHook(event); + }, + signerAccountDeployed: async () => { + if (isPushChain(ctx.universalSigner.account.chain)) return true; + const status = await orchestrator.getAccountStatus(); + return status.uea.deployed; + }, + signerBalance: () => ctx.pushClient.getBalance(computeUEAOffchain(ctx)), + getGasPrice: () => ctx.pushClient.getGasPrice(), + quoteOutbound: async (prc20, gasLimit, chain) => { + const q = await queryOutboundGasFee(ctx, prc20, gasLimit, chain); + return { + protocolFee: q.protocolFee, + nativeValueForGas: q.nativeValueForGas, + gasLimitUsed: q.gasLimitUsed, + }; + }, + resolveCEA: async (account, chain) => { + const r = await getCEAAddress(account, chain, orchestrator.getRpcUrls()[chain]?.[0]); + return { cea: getAddress(r.cea), isDeployed: r.isDeployed }; + }, + resolvePrc20: (token, chain) => + getAddress( + token + ? Utils.tokens.getPRC20Address(token).address + : getNativePRC20ForChain(chain, network) + ), + nowSeconds: () => Math.floor(Date.now() / 1000), + }; +} diff --git a/packages/core/src/lib/agentic/utils.ts b/packages/core/src/lib/agentic/utils.ts new file mode 100644 index 00000000..be986a0b --- /dev/null +++ b/packages/core/src/lib/agentic/utils.ts @@ -0,0 +1,114 @@ +import { getAddress, isHex, type Address, type Hex } from 'viem'; +import { PUSH_NETWORK } from '../constants/enums'; +import { AgenticCapability, CAPABILITY_DEPENDENCY } from './capabilities'; +import { E704D5B_CAPABILITIES } from './deployments'; +import { actionId as actionIdRaw, configId as configIdRaw, deriveWallet as deriveWalletRaw, rulesId as rulesIdRaw } from './codec/ids'; +import { decodeNativeTerms, nativeTermsToRule } from './codec/native'; +import { prepareRules } from './codec/rules'; +import { parseSelector } from './codec/selectors'; +import { decodeEnvelope, decodeSession, encodeSession } from './codec/session'; +import { AGENTIC_ERROR_CODE, AgenticError, capabilityUnavailable } from './errors'; +import { pushChainNamespaceFor } from './chain'; +import type { AgenticHex, Rule, Selector } from './agentic.types'; + +/** + * Generation context for the pure helpers. PROVISIONAL public shape (A04, + * Harsh H4.1): the spec's helper signatures omit the validator / factory / + * implementation inputs the results depend on, so they are explicit here. + */ +export interface RulesEncodeContext { + /** Connected Push network, or an explicit 'eip155:' native chain. */ + network?: PUSH_NETWORK; + pushChainNamespace?: string; + validator: Address; + rulesPolicy: Address; + /** Wallet owner, for the AGENT_IS_OWNER check. */ + owner?: Address; + /** Defaults to the current time. */ + nowSeconds?: number; +} + +function nativeNamespace(ctx: { network?: PUSH_NETWORK; pushChainNamespace?: string }): string { + if (ctx.pushChainNamespace) return ctx.pushChainNamespace; + return pushChainNamespaceFor(ctx.network ?? PUSH_NETWORK.TESTNET_DONUT); +} + +/** PushChain.utils.agentic — pure; no RPC. */ +export const agenticUtils = { + /** The ID a grant with this grantNonce produces. Chain is not part of the hash. */ + rulesId(agent: Address, grantNonce: bigint | number, ctx: { validator: Address }): AgenticHex { + return rulesIdRaw({ + validator: getAddress(ctx.validator), + agent: getAddress(agent), + grantNonce: BigInt(grantNonce), + }) as AgenticHex; + }, + + /** Hash of one allowed call: keccak256(target ‖ selector). */ + actionId(target: Address, selector: Selector | 'value-only'): AgenticHex { + return actionIdRaw(getAddress(target), parseSelector(selector).selector) as AgenticHex; + }, + + /** Key of one allowed call's stored config under one rule on one wallet. */ + configId(wallet: Address, rulesId: Hex, actionId: Hex): AgenticHex { + return configIdRaw(getAddress(wallet), rulesId, actionId) as AgenticHex; + }, + + /** Any-owner wallet address. */ + deriveWallet( + owner: Address, + index: bigint | number, + ctx: { factory: Address; walletImplementation: Address } + ): Address { + return deriveWalletRaw({ + factory: getAddress(ctx.factory), + walletImplementation: getAddress(ctx.walletImplementation), + owner: getAddress(owner), + index, + }); + }, + + /** + * Encode rules into the grant `Session` bytes, one per rule, in order. + * Native rules only today; universal rules fail with CAPABILITY_UNAVAILABLE (A05). + */ + encodeRules(rules: readonly Rule[], ctx: RulesEncodeContext): AgenticHex[] { + return prepareRules(rules, { + owner: ctx.owner ? getAddress(ctx.owner) : undefined, + pushChainNamespace: nativeNamespace(ctx), + validator: getAddress(ctx.validator), + rulesPolicy: getAddress(ctx.rulesPolicy), + capabilities: E704D5B_CAPABILITIES, + nowSeconds: ctx.nowSeconds ?? Math.floor(Date.now() / 1000), + }).map((p) => encodeSession(p.session) as AgenticHex); + }, + + /** Inverse of encodeRules for one Session encoding. */ + decodeRules(bytes: Hex, ctx: { network?: PUSH_NETWORK; pushChainNamespace?: string } = {}): Rule { + if (!isHex(bytes)) throw new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, 'decodeRules expects hex bytes'); + const session = decodeSession(bytes); + if (session.actions.length !== 1 || session.actions[0].actionPolicies.length !== 1) { + throw new AgenticError( + AGENTIC_ERROR_CODE.RULE_READ_FAILED, + 'only single-action rules (one URP policy) are representable as a public Rule' + ); + } + const agent = getAddress(`0x${session.sessionValidatorInitData.slice(26, 66)}`); + const { chainNamespace, body } = decodeEnvelope(session.actions[0].actionPolicies[0].initData); + if (chainNamespace !== nativeNamespace(ctx)) { + throw capabilityUnavailable( + AgenticCapability.UNIVERSAL_EVM_RULES, + `${chainNamespace} is a universal rule; ${CAPABILITY_DEPENDENCY[AgenticCapability.UNIVERSAL_EVM_RULES]}` + ); + } + return nativeTermsToRule(decodeNativeTerms(body), agent, `0x${'00'.repeat(32)}`); + }, + + /** Canonical card compiler — not available until the shared schema exists (A08). */ + compileCard(_card: unknown, _userInput: unknown, _ctx: unknown): never { + throw capabilityUnavailable( + AgenticCapability.COMPILE_CARD, + CAPABILITY_DEPENDENCY[AgenticCapability.COMPILE_CARD] + ); + }, +}; diff --git a/packages/core/src/lib/agentic/wallet.ts b/packages/core/src/lib/agentic/wallet.ts new file mode 100644 index 00000000..e8b65f86 --- /dev/null +++ b/packages/core/src/lib/agentic/wallet.ts @@ -0,0 +1,124 @@ +import { getAddress, type Address } from 'viem'; +import { AgenticCapability, requireCapability } from './capabilities'; +import { resolveWalletGeneration, type AgenticGeneration } from './deployments'; +import { AGENTIC_ERROR_CODE, AgenticError } from './errors'; +import { + addRules, + assertRevokeTarget, + revokeRules, + setLabel, + updateRules, +} from './management/rules-write'; +import { readCheckpoints } from './reads/checkpoints'; +import { getRule, listRules } from './reads/rules'; +import { Snapshot } from './reads/snapshot'; +import { walletInfo, walletOwner } from './reads/wallets'; +import type { AgenticRuntime } from './runtime'; +import type { + AgenticAddress, + AgenticHex, + AgenticProgressHook, + AgenticWallet, + Checkpoint, + RulesRecord, + WalletInfo, +} from './agentic.types'; +import type { UniversalTxResponse } from '../orchestrator/orchestrator.types'; +import { currentGeneration } from './deployments'; + +/** + * Management handle for one wallet (spec 1.d). Reads work for any wallet; + * writes require the connected signer to be the owner. It never sends AS the + * wallet — that is PushChain.initialize(signer, { agenticWallet }). + */ +export class AgenticWalletHandle implements AgenticWallet { + readonly address: AgenticAddress; + readonly rules: AgenticWallet['rules']; + private generation?: Promise; + + constructor(private readonly runtime: AgenticRuntime, address: string) { + try { + this.address = getAddress(address) as AgenticAddress; + } catch (cause) { + throw new AgenticError(AGENTIC_ERROR_CODE.NOT_AGENTIC_WALLET, `"${address}" is not an address`, { cause }); + } + this.rules = { + list: () => this.listRules(), + get: (rulesId) => this.getRule(rulesId), + add: async (rules, opts) => addRules(this.runtime, await this.gen(), this.address, rules, opts?.progressHook), + update: async (params) => updateRules(this.runtime, await this.gen(), this.address, params), + revoke: (async ( + target: AgenticHex[] | { all: true; progressHook?: AgenticProgressHook }, + opts?: { progressHook?: AgenticProgressHook } + ) => { + // Validate the target shape before any RPC so a bare revoke costs nothing. + assertRevokeTarget(target); + return revokeRules(this.runtime, await this.gen(), this.address, target, opts?.progressHook); + }) as AgenticWallet['rules']['revoke'], + }; + } + + /** Deployed wallets resolve their own generation; undeployed ones use the network's current one. */ + private gen(): Promise { + if (!this.generation) { + this.generation = resolveWalletGeneration(this.runtime.reader, this.runtime.network, this.address); + this.generation.catch(() => { + this.generation = undefined; + }); + } + return this.generation; + } + + async info(): Promise { + let gen: AgenticGeneration; + try { + gen = await this.gen(); + } catch (err) { + if (err instanceof AgenticError && err.code === AGENTIC_ERROR_CODE.WALLET_NOT_DEPLOYED) { + gen = currentGeneration(this.runtime.network); + } else { + throw err; + } + } + requireCapability(gen.capabilities, AgenticCapability.WALLET_READS); + return walletInfo(this.runtime.reader, gen, this.address, this.signerIdentity()); + } + + async owner(): Promise<{ owner: AgenticAddress }> { + const gen = await this.gen(); + return { owner: (await walletOwner(this.runtime.reader, gen, this.address)) as AgenticAddress }; + } + + async setLabel(label: string, _opts?: { progressHook?: AgenticProgressHook }): Promise { + return setLabel(this.runtime, await this.gen(), this.address, label); + } + + async checkpoints(opts?: { sinceBlock?: bigint }): Promise<{ checkpoints: Checkpoint[] }> { + const gen = await this.gen(); + const { checkpoints } = await readCheckpoints(this.runtime.reader, gen, this.address, opts?.sinceBlock); + return { checkpoints }; + } + + private async listRules(): Promise<{ rules: RulesRecord[] }> { + const gen = await this.gen(); + const snap = await Snapshot.at(this.runtime.reader); + return { rules: await listRules(snap, gen, this.address, this.runtime.pushChainNamespace) }; + } + + private async getRule(rulesId: AgenticHex): Promise { + if (typeof rulesId !== 'string' || !/^0x[0-9a-fA-F]{64}$/.test(rulesId)) { + throw new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, 'rulesId must be a 32-byte hex string'); + } + const gen = await this.gen(); + const snap = await Snapshot.at(this.runtime.reader); + return getRule(snap, gen, this.address, rulesId, this.runtime.pushChainNamespace); + } + + private signerIdentity(): Address | undefined { + try { + return this.runtime.signerPushAccount(); + } catch { + return undefined; + } + } +} diff --git a/packages/core/src/lib/constants/index.ts b/packages/core/src/lib/constants/index.ts index dcc1523c..213d9ea0 100644 --- a/packages/core/src/lib/constants/index.ts +++ b/packages/core/src/lib/constants/index.ts @@ -17,6 +17,7 @@ import { WEB2_MAX_EXTRACT_ENTRIES, } from './read-state'; import { UNIVERSAL_READ_STATUS, READ_STATUS, READ_ERROR_CODE, READ_OUTCOME } from '../read-state/read-state.types'; +import { AGENTIC } from '../agentic/constants'; /** `PushChain.CONSTANTS.READ` — cross-chain read state. Values verified against the deployed UniversalCallback. */ export const READ_CONSTANTS = { @@ -57,6 +58,8 @@ export const CONSTANTS = { MOVEABLE: { TOKEN: MOVEABLE_TOKEN_CONSTANTS }, PAYABLE: { TOKEN: PAYABLE_TOKEN_CONSTANTS }, READ: READ_CONSTANTS, + /** Agentic wallet deployments by Push network. Empty until a verified deployment exists (A07). */ + AGENTIC, }; export type { TypedDataDomain, TypedData }; diff --git a/packages/core/src/lib/index.ts b/packages/core/src/lib/index.ts index e0906cfa..2615d969 100644 --- a/packages/core/src/lib/index.ts +++ b/packages/core/src/lib/index.ts @@ -175,4 +175,46 @@ export { export { UNIVERSAL_CALLBACK_EVM } from './constants/abi/universalCallback.evm'; export { UNIVERSAL_READ_REGISTRY_EVM } from './constants/abi/universalReadRegistry.evm'; +// Structured execution errors (base class of AgenticRevertError) +export { + PushChainExecutionError, + PushChainBatchExecutionError, +} from './orchestrator/internals/errors'; +export type { DecodedErrorPayload } from './orchestrator/internals/errors'; + +// Agentic wallet (AGW) +export type { PushChainInitializeOptions } from './push-chain/push-chain'; +export { + AGENTIC_ERROR_CODE, + AgenticError, + AgenticRevertError, +} from './agentic'; +export type { + AgenticAddress, + AgenticDoor, + AgenticErrorCode, + AgenticHex, + AgenticNamespace, + AgenticNetworkConstants, + AgenticProgressHook, + AgenticTxMetadata, + AgenticWallet, + AllowedCall, + AssetCap, + Checkpoint, + CheckpointKind, + CreateOptions, + CreateResult, + ForeignChainNamespace, + NativeRule, + Rule, + RulesEncodeContext, + RulesRecord, + Selector, + Spent, + UniversalRule, + WalletInfo, + WalletSummary, +} from './agentic'; + export { PushChain }; diff --git a/packages/core/src/lib/orchestrator/internals/errors.ts b/packages/core/src/lib/orchestrator/internals/errors.ts index 58f3ec78..362cd243 100644 --- a/packages/core/src/lib/orchestrator/internals/errors.ts +++ b/packages/core/src/lib/orchestrator/internals/errors.ts @@ -43,14 +43,17 @@ export class PushChainExecutionError extends Error { readonly code = 'PUSH_CHAIN_EXECUTION_FAILED' as const; readonly gatewayTxHash?: string; readonly decodedError?: DecodedErrorPayload; + /** Underlying transport/RPC error, kept so raw revert data is not lost. */ + override readonly cause?: unknown; constructor( message: string, - opts: { gatewayTxHash?: string; decodedError?: DecodedErrorPayload } = {} + opts: { gatewayTxHash?: string; decodedError?: DecodedErrorPayload; cause?: unknown } = {} ) { super(normalizePublicErrorMessage(message)); this.name = 'PushChainExecutionError'; this.gatewayTxHash = opts.gatewayTxHash; this.decodedError = opts.decodedError; + if (opts.cause !== undefined) this.cause = opts.cause; } } diff --git a/packages/core/src/lib/orchestrator/internals/execute-standard.ts b/packages/core/src/lib/orchestrator/internals/execute-standard.ts index a0d0a026..95c30b1f 100644 --- a/packages/core/src/lib/orchestrator/internals/execute-standard.ts +++ b/packages/core/src/lib/orchestrator/internals/execute-standard.ts @@ -184,7 +184,7 @@ export async function executeStandardPayload( // outer orchestrator catch doesn't emit a second 199-02 on top. ctx._routeTerminalEmitted = true; if (!isUserDecline && !(err instanceof PushChainExecutionError)) { - throw new PushChainExecutionError(errMsg); + throw new PushChainExecutionError(errMsg, { cause: err }); } throw err; } diff --git a/packages/core/src/lib/orchestrator/orchestrator.types.ts b/packages/core/src/lib/orchestrator/orchestrator.types.ts index 86b190ec..388bcc60 100644 --- a/packages/core/src/lib/orchestrator/orchestrator.types.ts +++ b/packages/core/src/lib/orchestrator/orchestrator.types.ts @@ -471,6 +471,13 @@ export interface UniversalTxResponse { /** Transaction route (UOA_TO_PUSH, UOA_TO_CEA, CEA_TO_PUSH, CEA_TO_CEA) */ route?: TransactionRouteType; + /** + * Agentic wallet (AGW) context, present when the transaction executed + * through an AGW. `from` is then the wallet and `origin` stays the signer; + * `agentic.rawTo` / `rawData` hold the wrapped call the signer sent. + */ + agentic?: import('../agentic/agentic.types').AgenticTxMetadata; + // 12. Internal flags /** * @internal True when this response was produced by `trackTransaction` and diff --git a/packages/core/src/lib/progress-hook/__tests__/response-invariant.spec.ts b/packages/core/src/lib/progress-hook/__tests__/response-invariant.spec.ts index b4d683ed..98feda7d 100644 --- a/packages/core/src/lib/progress-hook/__tests__/response-invariant.spec.ts +++ b/packages/core/src/lib/progress-hook/__tests__/response-invariant.spec.ts @@ -170,6 +170,15 @@ const STUB_ARGS: Record = { [PROGRESS_HOOK.UEA_MIG_9901]: ['v2.0.0'], [PROGRESS_HOOK.UEA_MIG_9902]: [], [PROGRESS_HOOK.UEA_MIG_9903]: [], + // Agentic wallet + [PROGRESS_HOOK.AGENTIC_TX_101]: ['0xwallet', 0, false], + [PROGRESS_HOOK.AGENTIC_TX_102]: ['0xwallet', 'atomic'], + [PROGRESS_HOOK.AGENTIC_TX_104]: [['0xrule']], + [PROGRESS_HOOK.AGENTIC_TX_105]: [{ rulesIds: ['0xrule'] }], + [PROGRESS_HOOK.AGENTIC_TX_106]: ['label'], + [PROGRESS_HOOK.AGENTIC_TX_107]: ['0xrule', 'eip155:42101', 'agent'], + [PROGRESS_HOOK.AGENTIC_TX_199_01]: ['create', '0xhash'], + [PROGRESS_HOOK.AGENTIC_TX_199_02]: ['create', 'NO_RULES_FOR_CHAIN', 'no rule', { name: 'X' }], // Read state (READ-TX 101–199, 001/999) — positional args as in progress-hook.ts [PROGRESS_HOOK.READ_TX_101]: ['eip155:11155111', 'eip155', 0], [PROGRESS_HOOK.READ_TX_102_01]: ['eip155:11155111'], diff --git a/packages/core/src/lib/progress-hook/progress-hook.ts b/packages/core/src/lib/progress-hook/progress-hook.ts index ccc977fc..821950fb 100644 --- a/packages/core/src/lib/progress-hook/progress-hook.ts +++ b/packages/core/src/lib/progress-hook/progress-hook.ts @@ -8,6 +8,7 @@ import { formatPc, normalizePcInsufficientFundsError } from '../formatters'; import { Utils } from '../utils'; import { PROGRESS_HOOK, + PROGRESS_HOOK_AGENTIC, PROGRESS_HOOK_MIG, PROGRESS_HOOK_READ, PROGRESS_HOOK_MULTICHAIN, @@ -1593,6 +1594,79 @@ const RAW_HOOKS_READ: { }), }; +// ============================================================================= +// Agentic wallet (AGW) — AGENTIC-TX (spec 3.f, PROPOSED). No AGENTIC-TX-103. +// ============================================================================= + +type AgenticDecodedError = { name?: string; hint?: string; selector?: string; decoded?: string }; + +const RAW_HOOKS_AGENTIC: { + [K in PROGRESS_HOOK_AGENTIC]: ProgressEventFunctionWithoutTimestamp; +} = { + [PROGRESS_HOOK.AGENTIC_TX_101]: (address: string, index: number, deployed: boolean) => ({ + id: PROGRESS_HOOK.AGENTIC_TX_101, + title: 'Agentic Wallet Derived', + message: `Wallet ${address} at index ${index} (${deployed ? 'deployed' : 'not deployed'}).`, + response: { address, index, deployed }, + level: 'INFO', + }), + [PROGRESS_HOOK.AGENTIC_TX_102]: (address: string, strategy: string) => ({ + id: PROGRESS_HOOK.AGENTIC_TX_102, + title: 'Deploy Step Added', + message: `Deploying agentic wallet ${address} (${strategy}).`, + response: { address, strategy }, + level: 'INFO', + }), + [PROGRESS_HOOK.AGENTIC_TX_104]: (rulesIds: string[]) => ({ + id: PROGRESS_HOOK.AGENTIC_TX_104, + title: 'Rules Granted', + message: `Granted ${rulesIds.length} rule${rulesIds.length === 1 ? '' : 's'}.`, + response: { rulesIds }, + level: 'INFO', + }), + [PROGRESS_HOOK.AGENTIC_TX_105]: (target: { rulesIds: string[] } | { all: true }) => ({ + id: PROGRESS_HOOK.AGENTIC_TX_105, + title: 'Rules Revoked', + message: + 'all' in target + ? 'Revoked every rule on the wallet.' + : `Revoked ${target.rulesIds.length} rule${target.rulesIds.length === 1 ? '' : 's'}.`, + response: target, + level: 'INFO', + }), + [PROGRESS_HOOK.AGENTIC_TX_106]: (label: string) => ({ + id: PROGRESS_HOOK.AGENTIC_TX_106, + title: 'Label Set', + message: `Wallet label set to "${label}".`, + response: { label }, + level: 'INFO', + }), + [PROGRESS_HOOK.AGENTIC_TX_107]: (rulesId: string | undefined, chainNamespace: string, door: 'owner' | 'agent') => ({ + id: PROGRESS_HOOK.AGENTIC_TX_107, + title: 'Rule Resolved', + message: + door === 'owner' + ? `Owner door on ${chainNamespace}; no rule applies.` + : `Agent door on ${chainNamespace} under rule ${rulesId}.`, + response: { rulesId: rulesId ?? null, chainNamespace, door }, + level: 'INFO', + }), + [PROGRESS_HOOK.AGENTIC_TX_199_01]: (operation: string, txHash?: string) => ({ + id: PROGRESS_HOOK.AGENTIC_TX_199_01, + title: 'Agentic Operation Done', + message: `${operation} completed.`, + response: { operation, txHash: txHash ?? null }, + level: 'SUCCESS', + }), + [PROGRESS_HOOK.AGENTIC_TX_199_02]: (operation: string, code: string, message: string, decodedError?: AgenticDecodedError) => ({ + id: PROGRESS_HOOK.AGENTIC_TX_199_02, + title: 'Agentic Operation Failed', + message: `${operation} failed: ${message}`, + response: { operation, code, decodedError: decodedError ?? null }, + level: 'ERROR', + }), +}; + // Combine all routes into the master record const RAW_HOOKS: { [K in PROGRESS_HOOK]: ProgressEventFunctionWithoutTimestamp; @@ -1603,6 +1677,7 @@ const RAW_HOOKS: { ...RAW_HOOKS_MULTICHAIN, ...RAW_HOOKS_MIG, ...RAW_HOOKS_READ, + ...RAW_HOOKS_AGENTIC, }; // Build final hooks with timestamp injection diff --git a/packages/core/src/lib/progress-hook/progress-hook.types.ts b/packages/core/src/lib/progress-hook/progress-hook.types.ts index 94954b7e..4935d1cd 100644 --- a/packages/core/src/lib/progress-hook/progress-hook.types.ts +++ b/packages/core/src/lib/progress-hook/progress-hook.types.ts @@ -176,6 +176,17 @@ export enum PROGRESS_HOOK { UEA_MIG_9901 = 'UEA-MIG-9901', UEA_MIG_9902 = 'UEA-MIG-9902', UEA_MIG_9903 = 'UEA-MIG-9903', + + // Agentic wallet (AGW) — AGENTIC-TX (PROPOSED in the AGW SDK spec 3.f). + // AGENTIC-TX-103 was removed by the spec (create no longer funds). + AGENTIC_TX_101 = 'AGENTIC-TX-101', + AGENTIC_TX_102 = 'AGENTIC-TX-102', + AGENTIC_TX_104 = 'AGENTIC-TX-104', + AGENTIC_TX_105 = 'AGENTIC-TX-105', + AGENTIC_TX_106 = 'AGENTIC-TX-106', + AGENTIC_TX_107 = 'AGENTIC-TX-107', + AGENTIC_TX_199_01 = 'AGENTIC-TX-199-01', + AGENTIC_TX_199_02 = 'AGENTIC-TX-199-02', } // Route-scoped TYPE aliases — compile-time narrowing for new emission code. @@ -319,3 +330,13 @@ export type PROGRESS_HOOK_READ = | PROGRESS_HOOK.READ_TX_999_01 | PROGRESS_HOOK.READ_TX_999_02 | PROGRESS_HOOK.READ_TX_999_03; + +export type PROGRESS_HOOK_AGENTIC = + | PROGRESS_HOOK.AGENTIC_TX_101 + | PROGRESS_HOOK.AGENTIC_TX_102 + | PROGRESS_HOOK.AGENTIC_TX_104 + | PROGRESS_HOOK.AGENTIC_TX_105 + | PROGRESS_HOOK.AGENTIC_TX_106 + | PROGRESS_HOOK.AGENTIC_TX_107 + | PROGRESS_HOOK.AGENTIC_TX_199_01 + | PROGRESS_HOOK.AGENTIC_TX_199_02; diff --git a/packages/core/src/lib/push-chain/push-chain.ts b/packages/core/src/lib/push-chain/push-chain.ts index 9dc13208..5939f461 100644 --- a/packages/core/src/lib/push-chain/push-chain.ts +++ b/packages/core/src/lib/push-chain/push-chain.ts @@ -47,7 +47,32 @@ import { type ReadTrackOptions, type ReadExecuteOptions, } from '../read-state/read-params'; -import { assertRequestEntrypoint, executeReads as executePreparedReads } from '../read-state/read-executor'; +import { assertRequestEntrypoint, executeReads as executePreparedReads, type ReadExecutorDeps } from '../read-state/read-executor'; +import { AgenticNamespaceImpl } from '../agentic/agentic'; +import { resolveAgenticContext, type AgenticExecutionContext } from '../agentic/context'; +import { agenticSend } from '../agentic/execution/send'; +import { notAllowedInAgenticMode } from '../agentic/execution/guards'; +import { adaptTrackedResponse } from '../agentic/response'; +import { createAgenticRuntime, type AgenticRuntime } from '../agentic/runtime'; +import type { AgenticNamespace } from '../agentic/agentic.types'; + +/** Options accepted by `PushChain.initialize` / `reinitialize`. */ +export interface PushChainInitializeOptions { + network: PUSH_NETWORK; + rpcUrls?: Partial>; + blockExplorers?: Partial>; + printTraces?: boolean; + progressHook?: (progress: ProgressEvent) => void; + /** + * Act as this agentic wallet (AGW). The signer decides the door: the owner + * sends through `execute`, an agent named in an enabled rule through + * `executeAsAgent`; anyone else fails with NOT_OWNER_OR_AGENT. + * `universal.account` becomes the wallet; `universal.origin`, + * `getAccountStatus()` and gas stay the signer's. Not inherited by + * `reinitialize` — pass it again to keep acting as the wallet. + */ + agenticWallet?: `0x${string}`; +} /** * @class PushChain @@ -258,6 +283,16 @@ export class PushChain { ) => Promise; }; + /** + * Agentic wallet management (AGW): derive, create, list and per-wallet + * handles. Ownership is the connected signer's Push identity. + */ + agentic: AgenticNamespace; + + /** @internal AGW execution context when initialized with `agenticWallet`. */ + private agenticContext?: AgenticExecutionContext; + private readonly agenticRuntime: AgenticRuntime; + /** * Account status including UEA deployment state and version info. * Initially unloaded — call getAccountStatus() to populate. @@ -293,12 +328,36 @@ export class PushChain { // Default — overwritten in createInstance() with the background fetch this.accountStatusReady = Promise.resolve(); + this.agenticRuntime = createAgenticRuntime(orchestrator, isReadMode); + this.agentic = new AgenticNamespaceImpl(this.agenticRuntime); + + // eslint-disable-next-line @typescript-eslint/no-this-alias -- getters below need the instance + const self = this; + // In agenticWallet mode, request transactions execute through the wallet + // and the wallet pays the request value, so its balance gates the read. + const readDeps = (): ReadExecutorDeps => { + const actx = self.agenticContext; + if (!actx) return orchestrator; + return { + execute: (params, options) => agenticSend(self.agenticRuntime, actx, params, options), + trackRead: orchestrator.trackRead.bind(orchestrator) as Orchestrator['trackRead'], + revalidateRead: orchestrator.revalidateRead.bind(orchestrator), + getProgressHook: orchestrator.getProgressHook.bind(orchestrator), + getReadBalance: () => self.agenticRuntime.reader.getBalance({ address: actx.wallet }), + }; + }; + // Unspent read budget returns to whoever paid it: the wallet in agentic mode. + const withReadRefund = (options: T): T => + self.agenticContext && options.refundTo === undefined + ? { ...options, refundTo: self.agenticContext.wallet } + : options; + this.universal = { get origin() { return orchestrator.getUOA(); }, get account() { - return orchestrator.computeUEAOffchain(); + return self.agenticContext?.wallet ?? orchestrator.computeUEAOffchain(); }, sendTransaction: (...args) => { if (this.isReadMode) { @@ -306,12 +365,16 @@ export class PushChain { 'Read only mode cannot call sendTransaction function' ); } + if (this.agenticContext) { + return agenticSend(this.agenticRuntime, this.agenticContext, ...args); + } return orchestrator.execute.bind(orchestrator)(...args); }, prepareTransaction: ( params: UniversalExecuteParams, options?: TransactionExecutionOptions ) => { + if (this.agenticContext) throw notAllowedInAgenticMode('prepareTransaction'); return orchestrator.prepareTransaction.bind(orchestrator)( params, options @@ -326,40 +389,44 @@ export class PushChain { 'Read only mode cannot call executeTransactions function' ); } + if (this.agenticContext) throw notAllowedInAgenticMode('executeTransactions'); return orchestrator.createCascadedBuilder(txs, options).send(); }, - trackTransaction: (txHash: string, options?: import('../orchestrator/orchestrator.types').TrackTransactionOptions) => { - return orchestrator.trackTransaction.bind(orchestrator)(txHash, options); + trackTransaction: async (txHash: string, options?: import('../orchestrator/orchestrator.types').TrackTransactionOptions) => { + const tracked = await orchestrator.trackTransaction.bind(orchestrator)(txHash, options); + return adaptTrackedResponse(this.agenticRuntime, tracked); }, migrateCEA: (chain: CHAIN) => { if (this.isReadMode) { throw new Error('Read only mode cannot call migrateCEA function'); } + if (this.agenticContext) throw notAllowedInAgenticMode('migrateCEA'); return orchestrator.migrateCEA.bind(orchestrator)(chain); }, rescueFunds: (params: RescueFundsParams) => { if (this.isReadMode) { throw new Error('Read only mode cannot call rescueFunds function'); } + if (this.agenticContext) throw notAllowedInAgenticMode('rescueFunds'); return orchestrator.rescueFunds.bind(orchestrator)(params); }, // Only read()/executeReads() send transactions; prepare/simulate/track remain read-only. read: async (subject: string, options: O) => { - const params = await resolveReadSpecParams(subject, options, orchestrator.getNetwork(), orchestrator.getRpcUrls()); + const params = await resolveReadSpecParams(subject, withReadRefund(options), orchestrator.getNetwork(), orchestrator.getRpcUrls()); assertRequestEntrypoint(params.callback, 'read'); if (this.isReadMode) throw new Error('Read only mode cannot call read function'); const prepared = await orchestrator.prepareRead(params, options.progressHook); - const { reads: [response] } = await executePreparedReads(orchestrator, [prepared] as const, options); + const { reads: [response] } = await executePreparedReads(readDeps(), [prepared] as const, options); return response as UniversalReadResponse>; }, prepareRead: async (subject: string, options: O & ValidateReadCall) => { - const params = await resolveReadSpecParams(subject, options, orchestrator.getNetwork(), orchestrator.getRpcUrls()); + const params = await resolveReadSpecParams(subject, withReadRefund(options), orchestrator.getNetwork(), orchestrator.getRpcUrls()); return orchestrator.prepareRead(params) as Promise>>; }, executeReads: (async (reads: readonly PreparedRead[], options?: ReadExecuteOptions) => { reads.forEach((r) => assertRequestEntrypoint(r.callback)); if (this.isReadMode) throw new Error('Read only mode cannot call executeReads function'); - return executePreparedReads(orchestrator, reads, options); + return executePreparedReads(readDeps(), reads, options); }) as PushChain['universal']['executeReads'], trackRead: ((ref: { txHash: Hex } | { requestId: Hex | bigint }, options?: ReadTrackOptions & { progressHook?: (e: ProgressEvent) => void }) => { const opts = { ...toLifecycleOptions(options), progressHook: options?.progressHook }; @@ -702,13 +769,7 @@ export class PushChain { */ private static async createInstance( universalSigner: UniversalSigner | UniversalAccount, - options?: { - network: PUSH_NETWORK; - rpcUrls?: Partial>; - blockExplorers?: Partial>; - printTraces?: boolean; - progressHook?: (progress: ProgressEvent) => void; - } + options?: PushChainInitializeOptions ): Promise { const isReadOnly = PushChain.isUniversalAccount(universalSigner); @@ -773,6 +834,16 @@ export class PushChain { // Let execute() await the background fetch instead of re-fetching orchestrator.accountStatusReadyPromise = instance.accountStatusReady; + // Agentic mode: validate the wallet, its generation and the signer's door + // before returning a client. A read-only client may hold the context (so + // universal.account shows the wallet) but every signing path stays closed. + if (options?.agenticWallet !== undefined) { + instance.agenticContext = await resolveAgenticContext( + instance.agenticRuntime, + options.agenticWallet + ); + } + return instance; } @@ -790,13 +861,7 @@ export class PushChain { */ static initialize = async ( universalSigner: UniversalSigner | UniversalAccount, - options?: { - network: PUSH_NETWORK; - rpcUrls?: Partial>; - blockExplorers?: Partial>; - printTraces?: boolean; - progressHook?: (progress: ProgressEvent) => void; - } + options?: PushChainInitializeOptions ): Promise => { return PushChain.createInstance(universalSigner, options); }; @@ -815,27 +880,20 @@ export class PushChain { */ reinitialize = async ( universalSigner: UniversalSigner | UniversalAccount, - options?: { - network: PUSH_NETWORK; - rpcUrls?: Partial>; - blockExplorers?: Partial>; - printTraces?: boolean; - progressHook?: (progress: ProgressEvent) => void; - } + options?: PushChainInitializeOptions ): Promise => { - const mergedOptions = { + // agenticWallet is NOT inherited: an omitted value yields an ordinary + // client, and a supplied one reruns every wallet/role check. + const mergedOptions: PushChainInitializeOptions = { network: options?.network ?? this.orchestrator.getNetwork(), rpcUrls: options?.rpcUrls ?? this.orchestrator.getRpcUrls(), blockExplorers: options?.blockExplorers ?? this.blockExplorers, printTraces: options?.printTraces ?? this.orchestrator.getPrintTraces(), progressHook: options?.progressHook ?? this.orchestrator.getProgressHook(), - } as { - network: PUSH_NETWORK; - rpcUrls?: Partial>; - blockExplorers?: Partial>; - printTraces?: boolean; - progressHook?: (progress: ProgressEvent) => void; + ...(options?.agenticWallet !== undefined + ? { agenticWallet: options.agenticWallet } + : {}), }; return PushChain.createInstance(universalSigner, mergedOptions); }; diff --git a/packages/core/src/lib/utils.ts b/packages/core/src/lib/utils.ts index 7670f2c3..5f6bfeb8 100644 --- a/packages/core/src/lib/utils.ts +++ b/packages/core/src/lib/utils.ts @@ -31,6 +31,7 @@ import { import { PC20WrapperNotRegisteredError } from './orchestrator/internals/pc20/errors'; import { getPushChainForNetwork } from './orchestrator/internals/helpers'; import { Buffer } from 'buffer'; +import { agenticUtils } from './agentic/utils'; import type { Idl } from '@coral-xyz/anchor'; import { encodeAnchorIxData, @@ -1042,6 +1043,13 @@ export class Utils { }, }; + /** + * Agentic wallet (AGW) pure helpers: rulesId, actionId, configId, + * deriveWallet, encodeRules, decodeRules, compileCard. Generation context is + * explicit (provisional signatures, A04); no RPC is performed. + */ + static agentic = agenticUtils; + /** * Internal: resolves a CHAIN enum from either a CHAIN value or a PushChain client instance. */ From 4488639b8f356fec1af4a14b4b5ee2d07e4f5bc5 Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Sat, 3 Oct 2026 19:36:18 +0530 Subject: [PATCH 05/68] test(agw): local real-contract harness and contract-generated vectors Review-only harness that runs the SDK against the REAL pinned e704d5b contracts (SmartSession, AgentValidator, UniversalRulesPolicy proxy, AGW implementation, AGWFactory proxy) on anvil, built from an isolated `git archive` with submodules fetched at their recorded commits (scripts/agw-local/prepare.sh). Only the gateway is a stub (pull + burn + fee arithmetic) installed at the UniversalGatewayPC address. Push-EOA signers only; no UEA, TSS, relay or destination settlement. 31 tests cover create/list/derive, owner and agent doors through the public PushChain client, maxCalls / pins / amount / expiry enforcement with decoded policy errors, atomic rules.update (five checkpoints) and its stale-spend rollback, revoke-all, read-only and reinitialize behaviour, CREATE_PARTIAL recovery on the sequential path, and an agent EVM outbound that passes every URP gate with an owner-set bounded allowance. vectors.spec.ts writes src/lib/agentic/__fixtures__/e704d5b-vectors.json from pure engine/factory views and real grants, so unit tests check the codecs against values the contracts computed. --- .../__agw-local__/agw-local-advanced.spec.ts | 364 ++++++++++++++++++ packages/core/__agw-local__/agw-local.spec.ts | 318 +++++++++++++++ packages/core/__agw-local__/harness.ts | 289 ++++++++++++++ packages/core/__agw-local__/vectors.spec.ts | 166 ++++++++ packages/core/jest.agw-local.config.ts | 19 + .../agw-local/contracts/HarnessFixtures.sol | 165 ++++++++ packages/core/scripts/agw-local/prepare.sh | 48 +++ .../agentic/__fixtures__/e704d5b-vectors.json | 181 +++++++++ packages/core/tsconfig.agw-local.json | 9 + 9 files changed, 1559 insertions(+) create mode 100644 packages/core/__agw-local__/agw-local-advanced.spec.ts create mode 100644 packages/core/__agw-local__/agw-local.spec.ts create mode 100644 packages/core/__agw-local__/harness.ts create mode 100644 packages/core/__agw-local__/vectors.spec.ts create mode 100644 packages/core/jest.agw-local.config.ts create mode 100644 packages/core/scripts/agw-local/contracts/HarnessFixtures.sol create mode 100755 packages/core/scripts/agw-local/prepare.sh create mode 100644 packages/core/src/lib/agentic/__fixtures__/e704d5b-vectors.json create mode 100644 packages/core/tsconfig.agw-local.json diff --git a/packages/core/__agw-local__/agw-local-advanced.spec.ts b/packages/core/__agw-local__/agw-local-advanced.spec.ts new file mode 100644 index 00000000..e05cf621 --- /dev/null +++ b/packages/core/__agw-local__/agw-local-advanced.spec.ts @@ -0,0 +1,364 @@ +/** + * Real-contract checks for the harder AGW paths (pinned e704d5b on anvil). + * The universal-outbound block drives the SDK's composer with a runtime whose + * CEA and fee quote are local stand-ins (no destination chain or price feeds + * exist here); URP still decides every gate on the composed request. + */ +import { + encodeAbiParameters, + encodeFunctionData, + getAddress, + keccak256, + parseAbi, + toBytes, + type Address, + type Hex, +} from 'viem'; +import { AgenticRevertError, CHAIN, type PushChain } from '../src'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../src/lib/agentic/errors'; +import { agenticSend } from '../src/lib/agentic/execution/send'; +import { updateRules } from '../src/lib/agentic/management/rules-write'; +import type { AgenticRuntime } from '../src/lib/agentic/runtime'; +import type { AgenticExecutionContext } from '../src/lib/agentic/context'; +import { buildSession, encodeEnvelope } from '../src/lib/agentic/codec/session'; +import { encodeUniversalTermsE704d5b } from '../src/lib/agentic/codec/historical/e704d5b-universal'; +import { startHarness, type Harness } from './harness'; + +const TARGET_ABI = parseAbi([ + 'function increment()', + 'function deposit(address beneficiary, uint256 amount) payable', + 'function lastBeneficiary() view returns (address)', + 'function counter() view returns (uint256)', +]); +const TOKEN_ABI = parseAbi([ + 'function mint(address to, uint256 amount)', + 'function balanceOf(address) view returns (uint256)', + 'function allowance(address,address) view returns (uint256)', + 'function approve(address,uint256) returns (bool)', + 'function totalSupply() view returns (uint256)', +]); +const GATEWAY_ABI = parseAbi([ + 'function outboundCount() view returns (uint256)', + 'function lastSender() view returns (address)', + 'function lastRequestHash() view returns (bytes32)', +]); +const CORE_ABI = parseAbi([ + 'function getOutboundTxGasAndFees(address,uint256) view returns (address,uint256,uint256,uint256,string,uint256)', +]); + +type Internals = { agenticRuntime: AgenticRuntime; agenticContext?: AgenticExecutionContext }; +const internals = (c: PushChain) => c as unknown as Internals; + +async function chainNow(h: Harness): Promise { + return Number((await h.publicClient.getBlock()).timestamp); +} +async function warp(h: Harness, seconds: number): Promise { + await h.publicClient.request({ method: 'evm_increaseTime' as never, params: [seconds] as never }); + await h.publicClient.request({ method: 'evm_mine' as never, params: [] as never }); +} +const fund = (h: Harness, to: Address, value: bigint) => + h.wallets[4].sendTransaction({ to, value, account: h.wallets[4].account!, chain: h.wallets[4].chain }); + +describe('AGW advanced paths against real e704d5b contracts', () => { + let h: Harness; + let owner: PushChain; + let agentAddr: Address; + + beforeAll(async () => { + h = await startHarness(18547); + owner = await h.client(0); + agentAddr = h.wallets[1].account!.address; + }); + afterAll(async () => { + await h?.stop(); + }); + + describe('native pins, amount and value caps', () => { + let wallet: Address; + let agent: PushChain; + const beneficiary = getAddress('0x00000000000000000000000000000000000b0b0b'); + + beforeAll(async () => { + const created = await owner.agentic.create('pins', { + rules: [ + { + agent: agentAddr, + target: h.addresses.target, + selector: 'deposit(address,uint256)', + validUntil: (await chainNow(h)) + 3600, + pins: [{ arg: 0, expected: beneficiary }], + amount: { arg: 1, maxPerCall: BigInt(10), maxTotal: BigInt(15) }, + maxValuePerCall: BigInt(1000), + maxValueTotal: BigInt(1000), + }, + ], + }); + wallet = created.wallet; + await h.publicClient.waitForTransactionReceipt({ hash: await fund(h, wallet, BigInt(10) ** BigInt(18)) }); + agent = await h.client(1, { agenticWallet: wallet }); + }); + + const deposit = (to: Address, amount: bigint, value = BigInt(0)) => + agent.universal.sendTransaction({ + to: h.addresses.target, + value, + data: encodeFunctionData({ abi: TARGET_ABI, functionName: 'deposit', args: [to, amount] }), + }); + + it('a pinned beneficiary and an in-cap amount pass', async () => { + await (await deposit(beneficiary, BigInt(5), BigInt(10))).wait(); + expect( + await h.publicClient.readContract({ address: h.addresses.target, abi: TARGET_ABI, functionName: 'lastBeneficiary' }) + ).toBe(beneficiary); + }); + + it('a wrong beneficiary is rejected by URP with a decoded error and no state change', async () => { + const err = await deposit(agentAddr, BigInt(5)).catch((e) => e); + expect(err).toBeInstanceOf(AgenticRevertError); + expect(err.decodedError?.name).toBe("PolicyCheckReverted(ArgPinMismatch)"); + const rec = await owner.agentic.wallet(wallet).rules.list(); + expect(rec.rules[0].spent).toMatchObject({ amountSpent: BigInt(5), callsUsed: 1 }); + }); + + it('per-call and lifetime amount caps are enforced on-chain', async () => { + await expect(deposit(beneficiary, BigInt(11))).rejects.toBeInstanceOf(AgenticRevertError); + await (await deposit(beneficiary, BigInt(10))).wait(); + await expect(deposit(beneficiary, BigInt(1))).rejects.toBeInstanceOf(AgenticRevertError); + }); + + it('the decoded native terms carry the pins and caps as stored', async () => { + const { rules } = await owner.agentic.wallet(wallet).rules.list(); + expect(rules[0].rule).toMatchObject({ + pins: [{ arg: 0, expected: `0x${'0'.repeat(24)}${beneficiary.slice(2).toLowerCase()}` }], + amount: { arg: 1, maxPerCall: BigInt(10), maxTotal: BigInt(15) }, + maxValuePerCall: BigInt(1000), + }); + }); + }); + + describe('stale-spend replacement race', () => { + it('an agent spend between the read and inclusion reverts the whole replacement atomically', async () => { + const created = await owner.agentic.create('race', { + rules: [{ agent: agentAddr, target: h.addresses.target, selector: 'increment()', validUntil: (await chainNow(h)) + 3600 }], + }); + const wallet = created.wallet; + const oldId = created.rulesIds[0]; + const agent = await h.client(1, { agenticWallet: wallet }); + const rt = internals(owner).agenticRuntime; + const cpBefore = await h.publicClient.readContract({ + address: wallet, + abi: parseAbi(['function checkpointCount() view returns (uint64)']), + functionName: 'checkpointCount', + }); + const racing: AgenticRuntime = { + ...rt, + reader: rt.reader, + execute: async (params, options) => { + // The agent spends after the SDK read the counters, before the owner's tx lands. + await ( + await agent.universal.sendTransaction({ + to: h.addresses.target, + data: encodeFunctionData({ abi: TARGET_ABI, functionName: 'increment' }), + }) + ).wait(); + return rt.execute(params, options); + }, + }; + const err = await updateRules(racing, h.generation, wallet, { + rules: [{ rulesId: oldId, rule: { agent: agentAddr, target: h.addresses.target, selector: 'increment()', validUntil: (await chainNow(h)) + 3600 } }], + }).catch((e) => e); + expect(err).toBeInstanceOf(AgenticRevertError); + // Nothing changed: the old rule is still the only enabled rule and no checkpoint landed. + const { rules } = await owner.agentic.wallet(wallet).rules.list(); + expect(rules.map((r) => r.rulesId)).toEqual([oldId]); + expect( + await h.publicClient.readContract({ + address: wallet, + abi: parseAbi(['function checkpointCount() view returns (uint64)']), + functionName: 'checkpointCount', + }) + ).toBe(cpBefore); + }); + }); + + describe('expiry', () => { + it('an expired-but-enabled rule still identifies the agent; the send fails on-chain', async () => { + const created = await owner.agentic.create('expiring', { + rules: [{ agent: agentAddr, target: h.addresses.target, selector: 'increment()', validUntil: (await chainNow(h)) + 600 }], + }); + await warp(h, 1200); + const agent = await h.client(1, { agenticWallet: created.wallet }); + const err = await agent.universal + .sendTransaction({ + to: h.addresses.target, + data: encodeFunctionData({ abi: TARGET_ABI, functionName: 'increment' }), + }) + .catch((e) => e); + expect(err).toBeInstanceOf(AgenticRevertError); + expect(err.decodedError?.name).toBe("PolicyCheckReverted(RulesExpired)"); + }); + }); + + describe('sequential create partial failure and recovery', () => { + it('reports CREATE_PARTIAL with the deployed wallet and granted IDs; rules.add finishes it', async () => { + // Chain time runs ahead of the local clock: the SDK accepts validUntil, the policy does not. + const skewedValidUntil = Math.floor(Date.now() / 1000) + 600; + await warp(h, 7200); + const err = await owner.agentic + .create('partial', { + rules: [ + { agent: agentAddr, target: h.addresses.target, selector: 'increment()', validUntil: (await chainNow(h)) + 3600 }, + { agent: h.wallets[3].account!.address, target: h.addresses.target, selector: 'increment()', validUntil: skewedValidUntil }, + ], + }) + .catch((e) => e); + expect(err).toBeInstanceOf(AgenticError); + expect(err.code).toBe(AGENTIC_ERROR_CODE.CREATE_PARTIAL); + expect(err.details.walletDeployed).toBe(true); + expect(err.details.grantedRulesIds).toHaveLength(1); + expect(err.details.confirmedHashes.length).toBeGreaterThanOrEqual(2); + const wallet = err.details.wallet as Address; + const added = await owner.agentic.wallet(wallet).rules.add([ + { agent: h.wallets[3].account!.address, target: h.addresses.target, selector: 'increment()', validUntil: (await chainNow(h)) + 3600 }, + ]); + expect(added.rulesIds).toHaveLength(1); + const { rules } = await owner.agentic.wallet(wallet).rules.list(); + expect(rules).toHaveLength(2); + }); + }); + + describe('agent EVM outbound (historical single-asset terms, stub gateway)', () => { + const SEPOLIA = CHAIN.ETHEREUM_SEPOLIA; + const CEA = getAddress('0x000000000000000000000000000000000000cea1'); + const destTarget = getAddress('0x00000000000000000000000000000000000d0d0d'); + let token: Address; + let wallet: Address; + let rulesId: Hex; + let runtime: AgenticRuntime; + let ctx: AgenticExecutionContext; + let ownerAgw: PushChain; + + beforeAll(async () => { + token = await h.deploy(0, 'HarnessPRC20', 'HarnessFixtures.sol', [SEPOLIA, 6]); + const created = await owner.agentic.create('outbound', { rules: [] }); + wallet = created.wallet; + await h.write(0, token, TOKEN_ABI, 'mint', [wallet, BigInt(1_000_000)]); + await h.publicClient.waitForTransactionReceipt({ hash: await fund(h, wallet, BigInt(10) ** BigInt(17)) }); + // Fixture setup (raw owner call): grant a historical single-asset universal rule. + const terms = encodeUniversalTermsE704d5b({ + validUntil: (await chainNow(h)) + 3600, + expectedCEA: CEA, + asset: token, + maxAmountPerCall: BigInt(1000), + maxAmountTotal: BigInt(1500), + maxPCPerCall: BigInt(10) ** BigInt(16), + allowedCalls: [{ target: destTarget, selector: '0xd09de08a', beneficiaryOffset: 0, hasBeneficiary: false, maxValue: BigInt(0) }], + }); + const session = buildSession({ + validator: h.addresses.validator, + agent: agentAddr, + rulesPolicy: h.addresses.rulesPolicy, + actions: [{ target: h.addresses.gateway, selector: '0x77b86bec', initData: encodeEnvelope(SEPOLIA, terms) }], + }); + await h.write(0, wallet, h.generation.contracts.abis.wallet as never, 'grantRules', [session]); + [rulesId] = (await h.publicClient.readContract({ + address: h.addresses.engine, + abi: h.generation.contracts.abis.engine, + functionName: 'getPermissionIDs', + args: [wallet], + })) as Hex[]; + + const agent = await h.client(1, { agenticWallet: wallet }); + ctx = internals(agent).agenticContext!; + const base = internals(agent).agenticRuntime; + runtime = { + ...base, + reader: base.reader, + resolveCEA: async () => ({ cea: CEA, isDeployed: false }), + resolvePrc20: () => token, + quoteOutbound: async (prc20, gasLimit) => { + const [, gasFee, protocolFee, , , gasLimitUsed] = (await h.publicClient.readContract({ + address: h.addresses.universalCore, + abi: CORE_ABI, + functionName: 'getOutboundTxGasAndFees', + args: [prc20, gasLimit], + })) as readonly [Address, bigint, bigint, bigint, string, bigint]; + return { protocolFee, nativeValueForGas: gasFee, gasLimitUsed }; + }, + }; + ownerAgw = await h.client(0, { agenticWallet: wallet }); + }); + + const send = (amount: bigint) => + agenticSend(runtime, ctx, { + to: { address: destTarget, chain: SEPOLIA }, + data: '0xd09de08a', + funds: { amount, token: { symbol: 'USDC', decimals: 6, address: token, mechanism: 'approve' } }, + }); + + it('fails before signing when the owner has not set a gateway allowance', async () => { + await expect(send(BigInt(100))).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.GATEWAY_ALLOWANCE_INSUFFICIENT, + }); + }); + + it('owner sets a bounded allowance with an ordinary owner-door send; the agent outbound passes URP, pulls and burns', async () => { + await ( + await ownerAgw.universal.sendTransaction({ + to: token, + data: encodeFunctionData({ abi: TOKEN_ABI, functionName: 'approve', args: [h.addresses.gateway, BigInt(300)] }), + }) + ).wait(); + const supplyBefore = (await h.publicClient.readContract({ address: token, abi: TOKEN_ABI, functionName: 'totalSupply' })) as bigint; + const tx = await send(BigInt(100)); + const receipt = await h.publicClient.waitForTransactionReceipt({ hash: tx.hash as Hex }); + expect(receipt.status).toBe('success'); + expect(await h.publicClient.readContract({ address: h.addresses.gateway, abi: GATEWAY_ABI, functionName: 'lastSender' })).toBe(wallet); + expect(await h.publicClient.readContract({ address: token, abi: TOKEN_ABI, functionName: 'totalSupply' })).toBe(supplyBefore - BigInt(100)); + expect(await h.publicClient.readContract({ address: token, abi: TOKEN_ABI, functionName: 'allowance', args: [wallet, h.addresses.gateway] })).toBe(BigInt(200)); + // The request the wallet sent: empty recipient, wallet refund, nonzero gas cap, multicall payload. + const payload = `0x2cc2842d${encodeAbiParameters( + [{ type: 'tuple[]', components: [{ name: 'to', type: 'address' }, { name: 'value', type: 'uint256' }, { name: 'data', type: 'bytes' }] }], + [[{ to: destTarget, value: BigInt(0), data: '0xd09de08a' }]] + ).slice(2)}` as Hex; + const expected = keccak256( + encodeAbiParameters( + [{ type: 'tuple', components: [ + { name: 'recipient', type: 'bytes' }, { name: 'token', type: 'address' }, { name: 'amount', type: 'uint256' }, + { name: 'gasLimit', type: 'uint256' }, { name: 'gasPrice', type: 'uint256' }, { name: 'maxPCForGas', type: 'uint256' }, + { name: 'payload', type: 'bytes' }, { name: 'revertRecipient', type: 'address' } ] }], + [{ recipient: '0x', token, amount: BigInt(100), gasLimit: BigInt(200_000), gasPrice: BigInt(0), maxPCForGas: BigInt(10) ** BigInt(15), payload, revertRecipient: wallet }] + ) + ); + expect(await h.publicClient.readContract({ address: h.addresses.gateway, abi: GATEWAY_ABI, functionName: 'lastRequestHash' })).toBe(expected); + expect(tx.from).toBe(wallet); + expect(tx.route).toBe('UOA_TO_CEA'); + expect(tx.agentic).toMatchObject({ door: 'agent', rulesId, destinationAccount: CEA, chainNamespace: SEPOLIA }); + expect(keccak256(toBytes(SEPOLIA))).toBeTruthy(); + }); + + it('owner can remove the allowance; the agent is stopped before signing again', async () => { + await ( + await ownerAgw.universal.sendTransaction({ + to: token, + data: encodeFunctionData({ abi: TOKEN_ABI, functionName: 'approve', args: [h.addresses.gateway, BigInt(0)] }), + }) + ).wait(); + await expect(send(BigInt(10))).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.GATEWAY_ALLOWANCE_INSUFFICIENT }); + }); + + it('a call outside the allow-list is rejected by URP on-chain', async () => { + await ( + await ownerAgw.universal.sendTransaction({ + to: token, + data: encodeFunctionData({ abi: TOKEN_ABI, functionName: 'approve', args: [h.addresses.gateway, BigInt(50)] }), + }) + ).wait(); + const err = await agenticSend(runtime, ctx, { + to: { address: destTarget, chain: SEPOLIA }, + data: '0x12345678', + }).catch((e) => e); + expect(err).toBeInstanceOf(AgenticRevertError); + }); + }); +}); diff --git a/packages/core/__agw-local__/agw-local.spec.ts b/packages/core/__agw-local__/agw-local.spec.ts new file mode 100644 index 00000000..15bc814d --- /dev/null +++ b/packages/core/__agw-local__/agw-local.spec.ts @@ -0,0 +1,318 @@ +/** + * Real-contract checks of the AGW SDK against the pinned e704d5b contracts on a + * local anvil chain (see harness.ts for scope and limits). Every assertion + * about authorization, atomicity, counters and checkpoints is decided by the + * real contracts; the only stubbed component is the gateway. + */ +import { encodeFunctionData, getAddress, parseAbi, type Address, type Hex } from 'viem'; +import { AgenticError, AgenticRevertError, CHAIN, type PushChain } from '../src'; +import { AGENTIC_ERROR_CODE } from '../src/lib/agentic/errors'; +import { startHarness, type Harness } from './harness'; + +const TARGET_ABI = parseAbi([ + 'function increment()', + 'function counter() view returns (uint256)', + 'function deposit(address beneficiary, uint256 amount) payable', + 'function lastBeneficiary() view returns (address)', +]); +const WALLET_ABI = parseAbi([ + 'function checkpointCount() view returns (uint64)', + 'function agentOf(bytes32) view returns (address)', + 'function owner() view returns (address)', +]); + +const inAnHour = () => Math.floor(Date.now() / 1000) + 3600; + +describe('AGW SDK against real e704d5b contracts (local anvil)', () => { + let h: Harness; + let owner: PushChain; + let ownerAddr: Address; + let agentAddr: Address; + + beforeAll(async () => { + h = await startHarness(); + owner = await h.client(0); + ownerAddr = h.wallets[0].account!.address; + agentAddr = h.wallets[1].account!.address; + }); + afterAll(async () => { + await h?.stop(); + }); + + const counter = () => + h.publicClient.readContract({ address: h.addresses.target, abi: TARGET_ABI, functionName: 'counter' }); + const checkpointCount = (wallet: Address) => + h.publicClient.readContract({ address: wallet, abi: WALLET_ABI, functionName: 'checkpointCount' }); + + it('derive() predicts slot 0 from the signer identity and matches the factory', async () => { + const d = await owner.agentic.derive(); + expect(d.index).toBe(0); + expect(d.deployed).toBe(false); + const [predicted] = (await h.publicClient.readContract({ + address: h.addresses.factory, + abi: h.generation.contracts.abis.factory, + functionName: 'predictWallet', + args: [ownerAddr, BigInt(0)], + })) as readonly [Address, boolean]; + expect(d.address).toBe(getAddress(predicted)); + }); + + let bare: Address; + it('create(label, { rules: [] }) deploys a bare wallet without funding it', async () => { + const created = await owner.agentic.create('scratch', { rules: [] }); + bare = created.wallet; + expect(created.index).toBe(0); + expect(created.rulesIds).toEqual([]); + expect(await h.publicClient.getBalance({ address: bare })).toBe(BigInt(0)); + const info = await owner.agentic.wallet(bare).info(); + expect(info).toMatchObject({ label: 'scratch', index: 0, owner: ownerAddr, deployed: true, rulesCount: 0 }); + }); + + let wallet: Address; + let rule1: Hex; + it('create with a native rule returns the receipt-confirmed ID; grant order and IDs match the contract', async () => { + const created = await owner.agentic.create('ops', { + rules: [ + { agent: agentAddr, target: h.addresses.target, selector: 'increment()', validUntil: inAnHour(), maxCalls: 2 }, + ], + }); + wallet = created.wallet; + rule1 = created.rulesIds[0]; + expect(created.index).toBe(1); + expect(created.rulesIds).toHaveLength(1); + const agentOf = await h.publicClient.readContract({ + address: wallet, + abi: WALLET_ABI, + functionName: 'agentOf', + args: [rule1], + }); + expect(agentOf).toBe(agentAddr); + // Sequential fallback on a 7702-less localnet is reported honestly. + expect(typeof created.tx.atomic).toBe('boolean'); + }); + + it('list() returns both deployed wallets plus the next undeployed slot', async () => { + const { wallets } = await owner.agentic.list(); + expect(wallets.map((w) => [w.index, w.label, w.deployed, w.rulesCount])).toEqual([ + [0, 'scratch', true, 0], + [1, 'ops', true, 1], + [2, '', false, 0], + ]); + }); + + it('rules.get / rules.list decode the stored native terms and spend', async () => { + const rec = await owner.agentic.wallet(wallet).rules.get(rule1); + expect(rec.agent).toBe(agentAddr); + expect(rec.rule).toMatchObject({ target: h.addresses.target, maxCalls: 2, maxValuePerCall: BigInt(0) }); + expect(rec.spent).toEqual({ kind: 'native', valueSpent: BigInt(0), amountSpent: BigInt(0), callsUsed: 0 }); + const { rules } = await owner.agentic.wallet(wallet).rules.list(); + expect(rules.map((r) => r.rulesId)).toEqual([rule1]); + }); + + let agent: PushChain; + it('agent client: universal.account is the wallet, origin stays the signer, sends go through executeAsAgent', async () => { + agent = await h.client(1, { agenticWallet: wallet }); + expect(agent.universal.account).toBe(wallet); + expect(agent.universal.origin.address.toLowerCase()).toBe(agentAddr.toLowerCase()); + const before = await counter(); + const tx = await agent.universal.sendTransaction({ + to: h.addresses.target, + data: encodeFunctionData({ abi: TARGET_ABI, functionName: 'increment' }), + }); + const receipt = await tx.wait(); + expect(receipt.status).toBe(1); + expect(await counter()).toBe(before + BigInt(1)); + expect(tx.from).toBe(wallet); + expect(receipt.from).toBe(wallet); + expect(tx.to).toBe(h.addresses.target); + expect(tx.agentic).toMatchObject({ wallet, door: 'agent', rulesId: rule1 }); + expect(tx.agentic?.rawTo?.toLowerCase()).toBe(wallet.toLowerCase()); + }); + + it('agent sends do not tick checkpoints; the policy enforces maxCalls on-chain', async () => { + const cpBefore = await checkpointCount(wallet); + await ( + await agent.universal.sendTransaction({ + to: h.addresses.target, + data: encodeFunctionData({ abi: TARGET_ABI, functionName: 'increment' }), + }) + ).wait(); + expect(await checkpointCount(wallet)).toBe(cpBefore); + const rec = await owner.agentic.wallet(wallet).rules.get(rule1); + expect(rec.spent).toMatchObject({ kind: 'native', callsUsed: 2 }); + const err = await agent.universal + .sendTransaction({ + to: h.addresses.target, + data: encodeFunctionData({ abi: TARGET_ABI, functionName: 'increment' }), + }) + .catch((e) => e); + expect(err).toBeInstanceOf(AgenticRevertError); + expect(err.decodedError?.name).toBe('PolicyCheckReverted(CallLimitReached)'); + }); + + it('a stranger cannot initialize against the wallet', async () => { + await expect(h.client(2, { agenticWallet: wallet })).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.NOT_OWNER_OR_AGENT, + }); + }); + + it('owner client goes through execute and ticks one OWNER_ACTION checkpoint per call', async () => { + const ownerAgw = await h.client(0, { agenticWallet: wallet }); + const before = await checkpointCount(wallet); + const data = encodeFunctionData({ abi: TARGET_ABI, functionName: 'increment' }); + const tx = await ownerAgw.universal.sendTransaction({ + to: h.addresses.target, + data: [ + { to: h.addresses.target, value: BigInt(0), data }, + { to: h.addresses.target, value: BigInt(0), data }, + ], + }); + await tx.wait(); + expect(await checkpointCount(wallet)).toBe(before + BigInt(2)); + expect(tx.agentic?.door).toBe('owner'); + const { checkpoints } = await owner.agentic.wallet(wallet).checkpoints({ sinceBlock: tx.blockNumber }); + expect(checkpoints.map((c) => c.kind)).toEqual(['OWNER_ACTION', 'OWNER_ACTION']); + }); + + it('agent native arrays are refused before signing (A02)', async () => { + const data = encodeFunctionData({ abi: TARGET_ABI, functionName: 'increment' }); + await expect( + agent.universal.sendTransaction({ + to: h.addresses.target, + data: [ + { to: h.addresses.target, value: BigInt(0), data }, + { to: h.addresses.target, value: BigInt(0), data }, + ], + }) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.NOT_ALLOWED_IN_AGENTIC_MODE }); + }); + + let rule2: Hex; + it('rules.update replaces atomically: five checkpoints, old disabled, new usable with reset counters', async () => { + const before = await checkpointCount(wallet); + const res = await owner.agentic.wallet(wallet).rules.update({ + rules: [ + { + rulesId: rule1, + rule: { agent: agentAddr, target: h.addresses.target, selector: 'increment()', validUntil: inAnHour(), maxCalls: 1 }, + }, + ], + }); + rule2 = res.rules[0].rulesId; + expect(res.rules[0].replaced).toBe(rule1); + expect(await checkpointCount(wallet)).toBe(before + BigInt(5)); + const { checkpoints } = await owner.agentic.wallet(wallet).checkpoints({ sinceBlock: res.tx.blockNumber }); + expect(checkpoints.map((c) => c.kind)).toEqual([ + 'OWNER_ACTION', + 'OWNER_ACTION', + 'RULES_REVOKED', + 'OWNER_ACTION', + 'RULES_GRANTED', + ]); + const rec = await owner.agentic.wallet(wallet).rules.get(rule2); + expect(rec.spent).toMatchObject({ callsUsed: 0 }); + await expect(owner.agentic.wallet(wallet).rules.get(rule1)).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.CAPABILITY_UNAVAILABLE, + details: { rulesId: rule1, revoked: true }, + }); + const tx = await agent.universal.sendTransaction({ + to: h.addresses.target, + data: encodeFunctionData({ abi: TARGET_ABI, functionName: 'increment' }), + }); + expect(tx.agentic?.rulesId).toBe(rule2); + }); + + it('full checkpoint history is contiguous and matches checkpointCount()', async () => { + const { checkpoints } = await owner.agentic.wallet(wallet).checkpoints(); + expect(checkpoints.map((c) => c.seq)).toEqual(checkpoints.map((_, i) => i + 1)); + expect(BigInt(checkpoints.length)).toBe(await checkpointCount(wallet)); + expect(checkpoints[0].kind).toBe('RULES_GRANTED'); + }); + + it('bare revoke is refused; revoke({ all: true }) disables every rule', async () => { + await expect( + owner.agentic.wallet(wallet).rules.revoke(undefined as unknown as Hex[]) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.REVOKE_NEEDS_TARGET }); + await expect(owner.agentic.wallet(wallet).rules.revoke([])).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.REVOKE_NEEDS_TARGET, + }); + await (await owner.agentic.wallet(wallet).rules.revoke({ all: true })).wait(); + const { rules } = await owner.agentic.wallet(wallet).rules.list(); + expect(rules).toEqual([]); + await expect( + agent.universal.sendTransaction({ + to: h.addresses.target, + data: encodeFunctionData({ abi: TARGET_ABI, functionName: 'increment' }), + }) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.NO_RULES_FOR_CHAIN }); + }); + + it('a non-owner cannot write rules (fails before signing)', async () => { + const stranger = await h.client(2); + await expect( + stranger.agentic.wallet(wallet).rules.add([ + { agent: agentAddr, target: h.addresses.target, selector: 'increment()', validUntil: inAnHour() }, + ]) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.NOT_WALLET_OWNER }); + }); + + it('a read-only client can read but never sign, even with the owner address', async () => { + const ro = await h.readOnlyClient(0, { agenticWallet: wallet }); + expect(ro.universal.account).toBe(wallet); + expect((await ro.agentic.wallet(wallet).owner()).owner).toBe(ownerAddr); + await expect( + ro.agentic.wallet(wallet).rules.add([ + { agent: agentAddr, target: h.addresses.target, selector: 'increment()', validUntil: inAnHour() }, + ]) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.READ_ONLY }); + expect(() => + ro.universal.sendTransaction({ to: h.addresses.target, data: '0x' }) + ).toThrow(/Read only/); + }); + + it('reinitialize without agenticWallet returns an ordinary client', async () => { + const ownerAgw = await h.client(0, { agenticWallet: wallet }); + const plain = await ownerAgw.reinitialize( + await import('../src').then((m) => + m.PushChain.utils.signer.toUniversalFromKeypair(h.wallets[0], { + chain: m.CHAIN.PUSH_LOCALNET, + library: m.PushChain.CONSTANTS.LIBRARY.ETHEREUM_VIEM, + }) + ) + ); + expect(plain.universal.account.toLowerCase()).toBe(ownerAddr.toLowerCase()); + }); + + it('signer-level and cascade entry points are closed in agentic mode', async () => { + const ownerAgw = await h.client(0, { agenticWallet: wallet }); + const code = AGENTIC_ERROR_CODE.NOT_ALLOWED_IN_AGENTIC_MODE; + expect(() => ownerAgw.universal.prepareTransaction({ to: h.addresses.target, data: '0x' })).toThrow( + expect.objectContaining({ code }) + ); + await expect(ownerAgw.universal.executeTransactions([])).rejects.toMatchObject({ code }); + expect(() => ownerAgw.universal.migrateCEA(CHAIN.ETHEREUM_SEPOLIA)).toThrow(expect.objectContaining({ code })); + expect(() => + ownerAgw.universal.rescueFunds({ universalTxId: `0x${'00'.repeat(32)}`, prc20: h.addresses.target }) + ).toThrow(expect.objectContaining({ code })); + await expect( + ownerAgw.universal.sendTransaction({ to: h.addresses.target, data: '0x', payGasWith: {} }) + ).rejects.toMatchObject({ code }); + await expect( + ownerAgw.universal.sendTransaction({ + to: { address: h.addresses.target, chain: CHAIN.PUSH_LOCALNET }, + from: { chain: CHAIN.ETHEREUM_SEPOLIA }, + }) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.FROM_NOT_ALLOWED }); + }); + + it('getAccountStatus stays signer-scoped in agentic mode', async () => { + const ownerAgw = await h.client(0, { agenticWallet: wallet }); + const status = await ownerAgw.getAccountStatus(); + expect(status.mode).toBe('signer'); + expect(ownerAgw.universal.account).toBe(wallet); + }); + + it('errors from the agentic surface are typed', () => { + expect(new AgenticError(AGENTIC_ERROR_CODE.DUPLICATE_RULE, 'x')).toBeInstanceOf(Error); + }); +}); diff --git a/packages/core/__agw-local__/harness.ts b/packages/core/__agw-local__/harness.ts new file mode 100644 index 00000000..184b9730 --- /dev/null +++ b/packages/core/__agw-local__/harness.ts @@ -0,0 +1,289 @@ +/** + * Local AGW contract harness — REVIEW ONLY. + * + * Starts anvil as a stand-in Push LOCALNET (chainId 9000, the SDK's + * CHAIN_INFO[PUSH_LOCALNET].chainId), deploys the REAL pinned e704d5b + * contracts (SmartSession, AgentValidator, UniversalRulesPolicy behind a + * TransparentUpgradeableProxy, AGW implementation, AGWFactory behind an + * ERC1967Proxy) from an isolated build prepared by + * scripts/agw-local/prepare.sh, and installs a stub gateway at the + * UniversalGatewayPC precompile address. It registers that deployment as a + * NON-advertised generation so the SDK can be driven end to end. + * + * Limits: no UEA factory / precompiles / Cosmos module, so only Push-EOA + * signers are exercised; the gateway is a stub (pull + burn + fee arithmetic); + * no TSS, relay or destination execution happens. + */ +import { spawn, type ChildProcess } from 'node:child_process'; +import { readFileSync, existsSync } from 'node:fs'; +import { join } from 'node:path'; +import { + createPublicClient, + createWalletClient, + defineChain, + encodeFunctionData, + getAddress, + http, + type Abi, + type Address, + type Hex, + type PublicClient, + type WalletClient, +} from 'viem'; +import { privateKeyToAccount } from 'viem/accounts'; +import { PushChain } from '../src'; +import { CHAIN, PUSH_NETWORK } from '../src/lib/constants/enums'; +import { LIBRARY } from '../src/lib/constants/enums'; +import { + registerAgenticGeneration, + resetAgenticGenerations, + type AgenticGeneration, +} from '../src/lib/agentic/deployments'; + +export const CHAIN_ID = 9000; +export const GATEWAY_PRECOMPILE = getAddress('0x00000000000000000000000000000000000000c1'); +export const EXECUTOR_MODULE = getAddress('0x00000000000000000000000000000000000000e1'); +export const ACCOUNT_ID = 'push.agw.1.0.0'; + +/** Anvil's well-known development keys (public test material, not secrets). */ +export const DEV_KEYS: Hex[] = [ + '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80', + '0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d', + '0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a', + '0x7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6', + '0x47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a', +]; + +export function buildDir(): string { + const dir = process.env['AGW_LOCAL_DIR']; + if (!dir || !existsSync(join(dir, 'out', 'AGW.sol', 'AGW.json'))) { + throw new Error( + 'AGW_LOCAL_DIR must point at a build produced by packages/core/scripts/agw-local/prepare.sh' + ); + } + return dir; +} + +function artifact(dir: string, file: string, name: string): { abi: Abi; bytecode: Hex } { + const json = JSON.parse(readFileSync(join(dir, 'out', file, `${name}.json`), 'utf8')); + return { abi: json.abi as Abi, bytecode: json.bytecode.object as Hex }; +} + +export interface Harness { + rpcUrl: string; + anvil: ChildProcess; + publicClient: PublicClient; + wallets: WalletClient[]; + generation: AgenticGeneration; + addresses: { + engine: Address; + validator: Address; + rulesPolicy: Address; + walletImplementation: Address; + factory: Address; + universalCore: Address; + gateway: Address; + target: Address; + }; + deploy(walletIndex: number, name: string, file: string, args?: readonly unknown[]): Promise
; + write(walletIndex: number, to: Address, abi: Abi, functionName: string, args: readonly unknown[], value?: bigint): Promise; + client(walletIndex: number, opts?: { agenticWallet?: Address; progressHook?: (e: unknown) => void }): Promise; + readOnlyClient(walletIndex: number, opts?: { agenticWallet?: Address }): Promise; + stop(): Promise; + dir: string; +} + +const localChain = (rpcUrl: string) => + defineChain({ + id: CHAIN_ID, + name: 'push-localnet-harness', + nativeCurrency: { name: 'PC', symbol: 'PC', decimals: 18 }, + rpcUrls: { default: { http: [rpcUrl] } }, + }); + +async function waitForRpc(url: string, timeoutMs = 20_000): Promise { + const start = Date.now(); + for (;;) { + try { + const res = await fetch(url, { + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'eth_chainId', params: [] }), + }); + if (res.ok) return; + } catch { + // not yet listening + } + if (Date.now() - start > timeoutMs) throw new Error(`anvil did not start at ${url}`); + await new Promise((r) => setTimeout(r, 200)); + } +} + +export async function startHarness(port = 18545): Promise { + const dir = buildDir(); + const rpcUrl = `http://127.0.0.1:${port}`; + const anvil = spawn( + 'anvil', + ['--port', String(port), '--chain-id', String(CHAIN_ID), '--hardfork', 'prague', '--silent'], + { stdio: 'ignore' } + ); + try { + return await deployHarness(dir, rpcUrl, anvil); + } catch (err) { + anvil.kill('SIGTERM'); + throw err; + } +} + +async function deployHarness(dir: string, rpcUrl: string, anvil: ChildProcess): Promise { + await waitForRpc(rpcUrl); + const chain = localChain(rpcUrl); + const publicClient = createPublicClient({ chain, transport: http(rpcUrl) }) as PublicClient; + const wallets = DEV_KEYS.map((k) => + createWalletClient({ account: privateKeyToAccount(k), chain, transport: http(rpcUrl) }) + ); + + const deploy = async (walletIndex: number, name: string, file: string, args: readonly unknown[] = []) => { + const art = artifact(dir, file, name); + const hash = await wallets[walletIndex].deployContract({ + abi: art.abi, + bytecode: art.bytecode, + args: args as unknown[], + account: wallets[walletIndex].account!, + chain, + }); + const receipt = await publicClient.waitForTransactionReceipt({ hash }); + if (!receipt.contractAddress) throw new Error(`deploy ${name} failed`); + return getAddress(receipt.contractAddress); + }; + const write = async ( + walletIndex: number, + to: Address, + abi: Abi, + functionName: string, + args: readonly unknown[], + value?: bigint + ) => { + const hash = await wallets[walletIndex].sendTransaction({ + to, + data: encodeFunctionData({ abi, functionName, args: args as unknown[] }), + value, + account: wallets[walletIndex].account!, + chain, + }); + const receipt = await publicClient.waitForTransactionReceipt({ hash }); + if (receipt.status !== 'success') throw new Error(`${functionName} reverted`); + return hash; + }; + + const admin = wallets[0].account!.address; + const engine = await deploy(0, 'SmartSession', 'SmartSession.sol'); + const validator = await deploy(0, 'AgentValidator', 'AgentValidator.sol'); + const urpLogic = await deploy(0, 'UniversalRulesPolicy', 'UniversalRulesPolicy.sol'); + const urpAbi = artifact(dir, 'UniversalRulesPolicy.sol', 'UniversalRulesPolicy').abi; + const rulesPolicy = await deploy(0, 'TransparentUpgradeableProxy', 'TransparentUpgradeableProxy.sol', [ + urpLogic, + admin, + encodeFunctionData({ + abi: urpAbi, + functionName: 'initialize', + args: [GATEWAY_PRECOMPILE, EXECUTOR_MODULE, engine], + }), + ]); + const universalCore = await deploy(0, 'HarnessUniversalCore', 'HarnessFixtures.sol'); + const gatewayImpl = await deploy(0, 'HarnessGatewayPC', 'HarnessFixtures.sol', [universalCore]); + const gatewayCode = await publicClient.getCode({ address: gatewayImpl }); + await publicClient.request({ + method: 'anvil_setCode' as never, + params: [GATEWAY_PRECOMPILE, gatewayCode] as never, + }); + const walletImplementation = await deploy(0, 'AGW', 'AGW.sol', [ + engine, + rulesPolicy, + validator, + GATEWAY_PRECOMPILE, + ]); + const factoryLogic = await deploy(0, 'AGWFactory', 'AGWFactory.sol'); + const factoryAbi = artifact(dir, 'AGWFactory.sol', 'AGWFactory').abi; + const factory = await deploy(0, 'ERC1967Proxy', 'ERC1967Proxy.sol', [ + factoryLogic, + encodeFunctionData({ abi: factoryAbi, functionName: 'initialize', args: [admin, walletImplementation] }), + ]); + const target = await deploy(0, 'HarnessTarget', 'HarnessFixtures.sol'); + + resetAgenticGenerations(); + const generation = registerAgenticGeneration({ + id: 'e704d5b', + sourceCommit: 'e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9', + network: PUSH_NETWORK.LOCALNET, + advertised: false, + addresses: { + factory, + walletImplementation, + sessionEngine: engine, + rulesPolicy, + sessionValidator: validator, + gateway: GATEWAY_PRECOMPILE, + }, + startBlock: BigInt(0), + accountId: ACCOUNT_ID, + }); + + const signerFor = (walletIndex: number) => + PushChain.utils.signer.toUniversalFromKeypair(wallets[walletIndex], { + chain: CHAIN.PUSH_LOCALNET, + library: LIBRARY.ETHEREUM_VIEM, + }); + + const client = async ( + walletIndex: number, + opts: { agenticWallet?: Address; progressHook?: (e: unknown) => void } = {} + ) => + PushChain.initialize(await signerFor(walletIndex), { + network: PUSH_NETWORK.LOCALNET, + rpcUrls: { [CHAIN.PUSH_LOCALNET]: [rpcUrl] }, + ...(opts.agenticWallet ? { agenticWallet: opts.agenticWallet } : {}), + ...(opts.progressHook ? { progressHook: opts.progressHook as never } : {}), + }); + + const readOnlyClient = async (walletIndex: number, opts: { agenticWallet?: Address } = {}) => + PushChain.initialize( + { address: wallets[walletIndex].account!.address, chain: CHAIN.PUSH_LOCALNET }, + { + network: PUSH_NETWORK.LOCALNET, + rpcUrls: { [CHAIN.PUSH_LOCALNET]: [rpcUrl] }, + ...(opts.agenticWallet ? { agenticWallet: opts.agenticWallet } : {}), + } + ); + + return { + rpcUrl, + anvil, + publicClient, + wallets, + generation, + addresses: { + engine, + validator, + rulesPolicy, + walletImplementation, + factory, + universalCore, + gateway: GATEWAY_PRECOMPILE, + target, + }, + deploy, + write, + client, + readOnlyClient, + dir, + stop: async () => { + resetAgenticGenerations(); + anvil.kill('SIGTERM'); + }, + }; +} + +export function artifactAbi(dir: string, file: string, name: string): Abi { + return artifact(dir, file, name).abi; +} diff --git a/packages/core/__agw-local__/vectors.spec.ts b/packages/core/__agw-local__/vectors.spec.ts new file mode 100644 index 00000000..5544c23e --- /dev/null +++ b/packages/core/__agw-local__/vectors.spec.ts @@ -0,0 +1,166 @@ +/** + * Contract-generated vectors for the pure AGW codecs. Every `expected` value + * below is computed BY THE PINNED CONTRACTS (pure engine/factory views, or + * state read back after a real grant), never by the SDK under test. + * + * AGW_WRITE_VECTORS=1 → (re)write src/lib/agentic/__fixtures__/e704d5b-vectors.json + * otherwise → assert the committed file still matches the contracts + */ +import { execSync } from 'node:child_process'; +import { readFileSync, writeFileSync, mkdirSync } from 'node:fs'; +import { join } from 'node:path'; +import { getAddress, numberToHex, type Address, type Hex } from 'viem'; +import { buildSession } from '../src/lib/agentic/codec/session'; +import { agentConfig } from '../src/lib/agentic/codec/ids'; +import { encodeNativeTerms, nativeRuleToTerms } from '../src/lib/agentic/codec/native'; +import { encodeEnvelope, encodeSession } from '../src/lib/agentic/codec/session'; +import type { NativeRule } from '../src/lib/agentic/agentic.types'; +import { startHarness, type Harness } from './harness'; + +const FIXTURE = join(__dirname, '..', 'src', 'lib', 'agentic', '__fixtures__', 'e704d5b-vectors.json'); +const bigintJson = (v: unknown) => + JSON.stringify(v, (_k, x) => (typeof x === 'bigint' ? { $bigint: x.toString() } : x), 2); + +describe('contract-generated AGW vectors (e704d5b)', () => { + let h: Harness; + beforeAll(async () => { + h = await startHarness(18548); + }); + afterAll(async () => { + await h?.stop(); + }); + + it('matches the committed fixture (or writes it)', async () => { + const pc = h.publicClient; + const gen = h.generation; + const validator = h.addresses.validator; + const agents: Address[] = [ + h.wallets[1].account!.address, + h.wallets[2].account!.address, + getAddress('0x00000000000000000000000000000000000000ff'), + ]; + + // rulesId: SmartSession.getPermissionId is pure over (validator, initData, salt). + const rulesId = []; + for (const agent of agents) { + for (const grantNonce of [BigInt(0), BigInt(1), BigInt(7), BigInt(2) ** BigInt(63)]) { + const session = { + ...buildSession({ validator, agent, rulesPolicy: h.addresses.rulesPolicy, actions: [] }), + salt: numberToHex(grantNonce, { size: 32 }), + }; + const expected = (await pc.readContract({ + address: h.addresses.engine, + abi: gen.contracts.abis.engine, + functionName: 'getPermissionId', + args: [session as never], + })) as Hex; + rulesId.push({ validator, agent, grantNonce, agentConfig: agentConfig(agent), expected }); + } + } + + // deriveWallet: factory.predictWallet for fresh owners (index 0) and a used owner (0..next). + const deriveWallet = []; + const owners: Address[] = [h.wallets[3].account!.address, getAddress('0x1111111111111111111111111111111111111111')]; + for (const owner of owners) { + const [expected] = (await pc.readContract({ + address: h.addresses.factory, + abi: gen.contracts.abis.factory, + functionName: 'predictWallet', + args: [owner, BigInt(0)], + })) as readonly [Address, boolean]; + deriveWallet.push({ + factory: h.addresses.factory, + walletImplementation: h.addresses.walletImplementation, + owner, + index: 0, + expected, + }); + } + + // Native session round trip: SDK-encoded grant, contract-stored terms and IDs. + const owner = await h.client(0); + const rule: NativeRule = { + agent: agents[0], + target: h.addresses.target, + selector: 'deposit(address,uint256)', + validUntil: 4102444800, // 2100-01-01, fixed so the vector is reproducible + pins: [{ arg: 0, expected: agents[1] }], + amount: { arg: 1, maxPerCall: BigInt(10), maxTotal: BigInt(100) }, + maxValuePerCall: BigInt(5), + maxValueTotal: BigInt(50), + maxCalls: 3, + }; + const created = await owner.agentic.create('vectors', { rules: [rule] }); + const wallet = created.wallet; + const rid = created.rulesIds[0]; + const [actionId] = (await pc.readContract({ + address: h.addresses.engine, + abi: gen.contracts.abis.engine, + functionName: 'getEnabledActions', + args: [wallet, rid], + })) as Hex[]; + const { terms } = nativeRuleToTerms(rule, { nowSeconds: 0 }); + const nativeChain = `eip155:${await pc.getChainId()}`; + const session = buildSession({ + validator, + agent: rule.agent, + rulesPolicy: h.addresses.rulesPolicy, + actions: [{ target: terms.target, selector: terms.selector, initData: encodeEnvelope(nativeChain, encodeNativeTerms(terms)) }], + }); + // configId is recovered by searching what the policy accepts: the stored config is only + // initialized under the correct key, so a successful read proves the derivation. + const { configId } = await import('../src/lib/agentic/codec/ids'); + const cid = configId(wallet, rid, actionId); + const stored = (await pc.readContract({ + address: h.addresses.rulesPolicy, + abi: gen.contracts.abis.policy, + functionName: 'getNativeConfig', + args: [cid, wallet], + })) as { initialized: boolean; target: Address; selector: Hex; pins: readonly { offset: number; expected: Hex }[]; amount: { offset: number } }; + const native = { + rule, + nativeChain, + wallet, + rulesId: rid, + actionId, + configId: cid, + configInitialized: stored.initialized, + storedTarget: stored.target, + storedSelector: stored.selector, + storedPins: stored.pins.map((p) => ({ offset: Number(p.offset), expected: p.expected })), + storedAmountOffset: Number(stored.amount.offset), + encodedSession: encodeSession(session), + }; + + const vectors = { + provenance: { + agwCommit: h.generation.sourceCommit, + generatedBy: 'packages/core/__agw-local__/vectors.spec.ts', + toolchain: safe(() => execSync('forge --version').toString().split('\n')[0]), + chainId: await pc.getChainId(), + note: 'Addresses are deterministic for a fresh anvil + the harness deploy order.', + }, + rulesId, + deriveWallet, + native, + }; + + if (process.env['AGW_WRITE_VECTORS'] === '1') { + mkdirSync(join(FIXTURE, '..'), { recursive: true }); + writeFileSync(FIXTURE, bigintJson(vectors) + '\n'); + } + const committed = JSON.parse(readFileSync(FIXTURE, 'utf8')); + const { provenance: _a, ...current } = JSON.parse(bigintJson(vectors)); + const { provenance: _b, ...saved } = committed; + expect(current).toEqual(saved); + expect(native.configInitialized).toBe(true); + }); +}); + +function safe(f: () => string): string { + try { + return f(); + } catch { + return 'unknown'; + } +} diff --git a/packages/core/jest.agw-local.config.ts b/packages/core/jest.agw-local.config.ts new file mode 100644 index 00000000..cf6748f6 --- /dev/null +++ b/packages/core/jest.agw-local.config.ts @@ -0,0 +1,19 @@ +/** + * Local AGW contract harness (review-only). Runs the SDK against the real + * pinned e704d5b contracts on anvil. Requires Foundry and AGW_LOCAL_DIR from + * scripts/agw-local/prepare.sh. Never part of the unit or E2E runs. + * + * AGW_LOCAL_DIR=$(packages/core/scripts/agw-local/prepare.sh | tail -1) \ + * node node_modules/jest/bin/jest.js --config packages/core/jest.agw-local.config.ts --runInBand + */ +export default { + displayName: 'core-agw-local', + preset: '../../jest.preset.js', + testEnvironment: 'node', + transform: { + '^.+\\.[tj]s$': ['ts-jest', { tsconfig: '/tsconfig.agw-local.json' }], + }, + moduleFileExtensions: ['ts', 'js', 'html'], + testTimeout: 120000, + testMatch: ['/__agw-local__/**/*.spec.ts'], +}; diff --git a/packages/core/scripts/agw-local/contracts/HarnessFixtures.sol b/packages/core/scripts/agw-local/contracts/HarnessFixtures.sol new file mode 100644 index 00000000..b33eeb3c --- /dev/null +++ b/packages/core/scripts/agw-local/contracts/HarnessFixtures.sol @@ -0,0 +1,165 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +// REVIEW-ONLY FIXTURES for the SDK's local AGW harness. None of this is production +// code and none of it is a model of a deployed Push contract beyond the narrow +// behaviour named on each contract. Live gateway/core/TSS/destination behaviour is +// NOT exercised by anything that uses these fixtures. + +/// @notice Minimal PRC20 stand-in: transfers, allowances, burn and the +/// SOURCE_CHAIN_NAMESPACE view URP interrogates at universal grant. +contract HarnessPRC20 { + string public SOURCE_CHAIN_NAMESPACE; + uint8 public immutable decimals; + mapping(address => uint256) public balanceOf; + mapping(address => mapping(address => uint256)) public allowance; + uint256 public totalSupply; + + error LowBalance(); + error LowAllowance(); + + event Transfer(address indexed from, address indexed to, uint256 value); + event Approval(address indexed owner, address indexed spender, uint256 value); + + constructor(string memory sourceChainNamespace, uint8 decimals_) { + SOURCE_CHAIN_NAMESPACE = sourceChainNamespace; + decimals = decimals_; + } + + function mint(address to, uint256 amount) external { + balanceOf[to] += amount; + totalSupply += amount; + emit Transfer(address(0), to, amount); + } + + function approve(address spender, uint256 amount) external returns (bool) { + allowance[msg.sender][spender] = amount; + emit Approval(msg.sender, spender, amount); + return true; + } + + function transfer(address to, uint256 amount) external returns (bool) { + _move(msg.sender, to, amount); + return true; + } + + function transferFrom(address from, address to, uint256 amount) external returns (bool) { + uint256 a = allowance[from][msg.sender]; + if (a < amount) revert LowAllowance(); + allowance[from][msg.sender] = a - amount; + _move(from, to, amount); + return true; + } + + function burn(uint256 amount) external returns (bool) { + if (balanceOf[msg.sender] < amount) revert LowBalance(); + balanceOf[msg.sender] -= amount; + totalSupply -= amount; + emit Transfer(msg.sender, address(0), amount); + return true; + } + + function _move(address from, address to, uint256 amount) internal { + if (balanceOf[from] < amount) revert LowBalance(); + balanceOf[from] -= amount; + balanceOf[to] += amount; + emit Transfer(from, to, amount); + } +} + +/// @notice Fixed-quote stand-in for UniversalCore.getOutboundTxGasAndFees. +contract HarnessUniversalCore { + uint256 public gasFee = 1e15; + uint256 public protocolFee = 1e14; + + function getOutboundTxGasAndFees(address prc20, uint256 gasLimit) + external + view + returns (address gasToken, uint256 gasFee_, uint256 protocolFee_, uint256 gasPrice, string memory chainNamespace, uint256 gasLimitUsed) + { + (bool ok, bytes memory ret) = prc20.staticcall(abi.encodeWithSignature("SOURCE_CHAIN_NAMESPACE()")); + chainNamespace = ok ? abi.decode(ret, (string)) : ""; + return (prc20, gasFee, protocolFee, 1 gwei, chainNamespace, gasLimit == 0 ? 200_000 : gasLimit); + } +} + +struct HarnessOutboundRequest { + bytes recipient; + address token; + uint256 amount; + uint256 gasLimit; + uint256 gasPrice; + uint256 maxPCForGas; + bytes payload; + address revertRecipient; +} + +/// @notice Stub of UniversalGatewayPC's outbound pull. Models ONLY: non-zero +/// token/revertRecipient, transferFrom(msg.sender) + burn of `amount`, +/// msg.value >= protocolFee, maxPCForGas <= msg.value - protocolFee with the +/// excess refunded, and a recorded request. No fee swap, routing, TSS or +/// destination execution. Mirrors gateway bcbf7df UniversalGatewayPC.sol:141-237,430-435. +contract HarnessGatewayPC { + HarnessUniversalCore public immutable universalCore; + uint256 public outboundCount; + bytes32 public lastRequestHash; + address public lastSender; + + error InvalidInput(); + error InsufficientFee(); + + event HarnessOutbound(address indexed sender, address indexed token, uint256 amount, uint256 value, bytes32 requestHash); + + constructor(HarnessUniversalCore core_) { + universalCore = core_; + } + + function sendUniversalTxOutbound(HarnessOutboundRequest calldata req) external payable { + if (req.token == address(0) || req.revertRecipient == address(0)) revert InvalidInput(); + if (req.amount == 0 && req.payload.length == 0) revert InvalidInput(); + uint256 protocolFee = universalCore.protocolFee(); + if (msg.value < protocolFee) revert InsufficientFee(); + uint256 pcForSwap = msg.value - protocolFee; + if (req.maxPCForGas != 0) { + if (req.maxPCForGas > pcForSwap) revert InsufficientFee(); + uint256 refund = pcForSwap - req.maxPCForGas; + if (refund > 0) { + (bool ok,) = msg.sender.call{ value: refund }(""); + require(ok, "refund"); + } + } + if (req.amount > 0) { + HarnessPRC20(req.token).transferFrom(msg.sender, address(this), req.amount); + HarnessPRC20(req.token).burn(req.amount); + } + outboundCount++; + lastSender = msg.sender; + lastRequestHash = keccak256(abi.encode(req)); + emit HarnessOutbound(msg.sender, req.token, req.amount, msg.value, lastRequestHash); + } + + receive() external payable { } +} + +/// @notice Native-rule target: records calls so authorization effects are observable. +contract HarnessTarget { + uint256 public counter; + address public lastBeneficiary; + uint256 public lastAmount; + uint256 public received; + + function increment() external { + counter++; + } + + function deposit(address beneficiary, uint256 amount) external payable { + lastBeneficiary = beneficiary; + lastAmount = amount; + received += msg.value; + counter++; + } + + receive() external payable { + received += msg.value; + } +} diff --git a/packages/core/scripts/agw-local/prepare.sh b/packages/core/scripts/agw-local/prepare.sh new file mode 100755 index 00000000..08c70400 --- /dev/null +++ b/packages/core/scripts/agw-local/prepare.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +# Prepare an ISOLATED build of the pinned AGW contracts for the SDK's local +# contract harness (review-only; never a deployment of record). +# +# AGW_REPO path to a push-agentic-wallets clone (default: ../../../../push-agentic-wallets +# relative to this script). Only `git archive` / `git ls-tree` are run against it, +# so the clone's working tree, branches and index are never touched. +# AGW_PIN commit to extract (default: the reviewed e704d5b). +# OUT destination directory (default: $TMPDIR/push-agw-local-). +# +# The script extracts the pinned tree, fetches each git submodule at the exact +# commit recorded in that tree, copies the harness-only contracts from +# ./contracts into OUT/sdk-harness, and runs `forge build`. It never broadcasts. +set -euo pipefail + +HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +AGW_REPO="${AGW_REPO:-$HERE/../../../../../push-agentic-wallets}" +AGW_PIN="${AGW_PIN:-e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9}" +OUT="${OUT:-${TMPDIR:-/tmp}/push-agw-local-${AGW_PIN:0:7}}" + +command -v forge >/dev/null || { echo "forge not found (install Foundry)" >&2; exit 1; } +git -C "$AGW_REPO" cat-file -e "${AGW_PIN}^{commit}" 2>/dev/null || { + echo "AGW pin $AGW_PIN is not present in $AGW_REPO; fetch it first" >&2; exit 1; } + +mkdir -p "$OUT" +if [ ! -f "$OUT/.agw-pin" ] || [ "$(cat "$OUT/.agw-pin")" != "$AGW_PIN" ]; then + echo "extracting $AGW_PIN -> $OUT" + git -C "$AGW_REPO" archive "$AGW_PIN" | tar -x -C "$OUT" + # Submodules are gitlinks in the archive; fetch each at its recorded commit. + git -C "$AGW_REPO" ls-tree "$AGW_PIN" lib/ | awk '$2 == "commit" { print $3, $4 }' | + while read -r commit path; do + url="$(git -C "$AGW_REPO" show "$AGW_PIN:.gitmodules" | + git config -f /dev/stdin --get "submodule.$path.url")" + echo "submodule $path @ $commit ($url)" + rm -rf "${OUT:?}/$path" + git init -q "$OUT/$path" + git -C "$OUT/$path" fetch -q --depth 1 "$url" "$commit" + git -C "$OUT/$path" checkout -q FETCH_HEAD + test "$(git -C "$OUT/$path" rev-parse HEAD)" = "$commit" + done + echo "$AGW_PIN" > "$OUT/.agw-pin" +fi + +mkdir -p "$OUT/sdk-harness" +cp "$HERE"/contracts/*.sol "$OUT/sdk-harness/" + +(cd "$OUT" && forge build --offline src sdk-harness lib/smartsessions/contracts/SmartSession.sol lib/openzeppelin-contracts/contracts/proxy >/dev/null) +echo "$OUT" diff --git a/packages/core/src/lib/agentic/__fixtures__/e704d5b-vectors.json b/packages/core/src/lib/agentic/__fixtures__/e704d5b-vectors.json new file mode 100644 index 00000000..5eca8d1b --- /dev/null +++ b/packages/core/src/lib/agentic/__fixtures__/e704d5b-vectors.json @@ -0,0 +1,181 @@ +{ + "provenance": { + "agwCommit": "e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9", + "generatedBy": "packages/core/__agw-local__/vectors.spec.ts", + "toolchain": "forge Version: 1.5.1-stable", + "chainId": 9000, + "note": "Addresses are deterministic for a fresh anvil + the harness deploy order." + }, + "rulesId": [ + { + "validator": "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512", + "agent": "0x70997970C51812dc3A010C7d01b50e0d17dc79C8", + "grantNonce": { + "$bigint": "0" + }, + "agentConfig": "0x00000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8", + "expected": "0xed16789aedd36446aa851df227d231dfdaab75ab95d022e251d179e27fdcee59" + }, + { + "validator": "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512", + "agent": "0x70997970C51812dc3A010C7d01b50e0d17dc79C8", + "grantNonce": { + "$bigint": "1" + }, + "agentConfig": "0x00000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8", + "expected": "0xb5cf1093fb5b4109923a54fc9a67eff369e01392403b645e8e0155a6cb4990fe" + }, + { + "validator": "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512", + "agent": "0x70997970C51812dc3A010C7d01b50e0d17dc79C8", + "grantNonce": { + "$bigint": "7" + }, + "agentConfig": "0x00000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8", + "expected": "0xc05ecd2b8ea27dcaff748d5027fcc6b7963b9bf5452ccc6e3016235a878a2da3" + }, + { + "validator": "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512", + "agent": "0x70997970C51812dc3A010C7d01b50e0d17dc79C8", + "grantNonce": { + "$bigint": "9223372036854775808" + }, + "agentConfig": "0x00000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8", + "expected": "0xc568da4c1ecd6f73d2609cba4bccba9108f9b3b43e13797e63aa25db68a6ea79" + }, + { + "validator": "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512", + "agent": "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC", + "grantNonce": { + "$bigint": "0" + }, + "agentConfig": "0x0000000000000000000000003c44cdddb6a900fa2b585dd299e03d12fa4293bc", + "expected": "0x0a7234266892a3ade6ba3f70c1a4c0b56aefb198e74a14a5d6d08c5f8587498e" + }, + { + "validator": "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512", + "agent": "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC", + "grantNonce": { + "$bigint": "1" + }, + "agentConfig": "0x0000000000000000000000003c44cdddb6a900fa2b585dd299e03d12fa4293bc", + "expected": "0x66c8518bd08fc86347cb20601b22df298d73794e99c6eb9250f52ce78c949674" + }, + { + "validator": "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512", + "agent": "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC", + "grantNonce": { + "$bigint": "7" + }, + "agentConfig": "0x0000000000000000000000003c44cdddb6a900fa2b585dd299e03d12fa4293bc", + "expected": "0x11be56b6d0b4b6ba03b6475bdbe4393f68e689d690a5428821664947c0e9df3a" + }, + { + "validator": "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512", + "agent": "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC", + "grantNonce": { + "$bigint": "9223372036854775808" + }, + "agentConfig": "0x0000000000000000000000003c44cdddb6a900fa2b585dd299e03d12fa4293bc", + "expected": "0x35257788092b8179db6e880a636bc3114dbe9b1b30445d3551218ccc682478df" + }, + { + "validator": "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512", + "agent": "0x00000000000000000000000000000000000000ff", + "grantNonce": { + "$bigint": "0" + }, + "agentConfig": "0x00000000000000000000000000000000000000000000000000000000000000ff", + "expected": "0x675a172b2a29803a43c4c478a43b68730a6d74aee6102750b59bc49d29b70b47" + }, + { + "validator": "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512", + "agent": "0x00000000000000000000000000000000000000ff", + "grantNonce": { + "$bigint": "1" + }, + "agentConfig": "0x00000000000000000000000000000000000000000000000000000000000000ff", + "expected": "0x1ba472d29a9d5f904acd8d6682ab6beb04026365da11ec4f7142231ac3eb592b" + }, + { + "validator": "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512", + "agent": "0x00000000000000000000000000000000000000ff", + "grantNonce": { + "$bigint": "7" + }, + "agentConfig": "0x00000000000000000000000000000000000000000000000000000000000000ff", + "expected": "0xb5e300538b76a563882467a58f2073ed1677234609d698d22bb441814355f12c" + }, + { + "validator": "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512", + "agent": "0x00000000000000000000000000000000000000ff", + "grantNonce": { + "$bigint": "9223372036854775808" + }, + "agentConfig": "0x00000000000000000000000000000000000000000000000000000000000000ff", + "expected": "0x7b190cef2be98a983c96b0c4653480549c1f7ce35232f400dff5c6ce7f551f11" + } + ], + "deriveWallet": [ + { + "factory": "0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6", + "walletImplementation": "0x0165878A594ca255338adfa4d48449f69242Eb8F", + "owner": "0x90F79bf6EB2c4f870365E785982E1f101E93b906", + "index": 0, + "expected": "0xE68bD7D2E9b2F21bA9e4e09cE2D20A3d681Ec6e1" + }, + { + "factory": "0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6", + "walletImplementation": "0x0165878A594ca255338adfa4d48449f69242Eb8F", + "owner": "0x1111111111111111111111111111111111111111", + "index": 0, + "expected": "0x3066c721A477afBF4c3732F39A0048684e4641cF" + } + ], + "native": { + "rule": { + "agent": "0x70997970C51812dc3A010C7d01b50e0d17dc79C8", + "target": "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318", + "selector": "deposit(address,uint256)", + "validUntil": 4102444800, + "pins": [ + { + "arg": 0, + "expected": "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC" + } + ], + "amount": { + "arg": 1, + "maxPerCall": { + "$bigint": "10" + }, + "maxTotal": { + "$bigint": "100" + } + }, + "maxValuePerCall": { + "$bigint": "5" + }, + "maxValueTotal": { + "$bigint": "50" + }, + "maxCalls": 3 + }, + "nativeChain": "eip155:9000", + "wallet": "0x3e8FE21F60352CE4e632537113451A6990b9b7e6", + "rulesId": "0xed16789aedd36446aa851df227d231dfdaab75ab95d022e251d179e27fdcee59", + "actionId": "0x95eb75f6723928adc7fd1b4edeec4a558cc76cef41e06b7a16448bf74364d791", + "configId": "0x939681af8de835b5dde52d6056defa47df21b9325892b5945f113a8112179e69", + "configInitialized": true, + "storedTarget": "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318", + "storedSelector": "0x47e7ef24", + "storedPins": [ + { + "offset": 4, + "expected": "0x0000000000000000000000003c44cdddb6a900fa2b585dd299e03d12fa4293bc" + } + ], + "storedAmountOffset": 36, + "encodedSession": "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000e7f1725e7734ce288f8367e1bb143e90bb3f051200000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002047e7ef24000000000000000000000000000000000000000000000000000000000000000000000000000000008a791620dd6260079bf849dc5567adc3f2fdc318000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000cf7ed3acca5a467e9e704c703e8d87f634fb0fc90000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000b6569703135353a3930303000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000f48657000000000000000000000000008a791620dd6260079bf849dc5567adc3f2fdc31847e7ef24000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000003200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000040000000000000000000000003c44cdddb6a900fa2b585dd299e03d12fa4293bc" + } +} diff --git a/packages/core/tsconfig.agw-local.json b/packages/core/tsconfig.agw-local.json new file mode 100644 index 00000000..e547653d --- /dev/null +++ b/packages/core/tsconfig.agw-local.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "module": "commonjs", + "types": ["jest", "node"] + }, + "include": ["__agw-local__/**/*.ts", "src/**/*.d.ts"] +} From 00b62d48d844d1a4c9211bc5ed0d99264c94ff9b Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Sat, 3 Oct 2026 19:36:18 +0530 Subject: [PATCH 06/68] test(agw): unit coverage for codecs, reads, selection, sends and management 122 mock-boundary tests in 6 suites (no network): contract-vector checks for IDs and the native session encoding, ABI-layout offsets, A01/A02/A03 boundaries, universal-rule validation and capability gating, door resolution and wiring checks, per-send rule selection (none / one / duplicate / revoked / RPC failure), wallet and checkpoint reads (ordering, sinceBlock, count mismatch, derivation drift), send guards that never reach the signer, outbound request composition, create / add / revoke / update call shapes and failure reporting, response replay and revert decoding. --- .../src/lib/agentic/__tests__/codec.spec.ts | 224 +++++++++++++ .../src/lib/agentic/__tests__/fake-chain.ts | 315 ++++++++++++++++++ .../lib/agentic/__tests__/management.spec.ts | 254 ++++++++++++++ .../src/lib/agentic/__tests__/mock-runtime.ts | 98 ++++++ .../agentic/__tests__/reads-context.spec.ts | 286 ++++++++++++++++ .../__tests__/response-surface.spec.ts | 119 +++++++ .../agentic/__tests__/rules-policy.spec.ts | 180 ++++++++++ .../src/lib/agentic/__tests__/send.spec.ts | 295 ++++++++++++++++ 8 files changed, 1771 insertions(+) create mode 100644 packages/core/src/lib/agentic/__tests__/codec.spec.ts create mode 100644 packages/core/src/lib/agentic/__tests__/fake-chain.ts create mode 100644 packages/core/src/lib/agentic/__tests__/management.spec.ts create mode 100644 packages/core/src/lib/agentic/__tests__/mock-runtime.ts create mode 100644 packages/core/src/lib/agentic/__tests__/reads-context.spec.ts create mode 100644 packages/core/src/lib/agentic/__tests__/response-surface.spec.ts create mode 100644 packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts create mode 100644 packages/core/src/lib/agentic/__tests__/send.spec.ts diff --git a/packages/core/src/lib/agentic/__tests__/codec.spec.ts b/packages/core/src/lib/agentic/__tests__/codec.spec.ts new file mode 100644 index 00000000..d9ade769 --- /dev/null +++ b/packages/core/src/lib/agentic/__tests__/codec.spec.ts @@ -0,0 +1,224 @@ +import { decodeFunctionData, getAddress, type Address, type Hex } from 'viem'; +import vectorsJson from '../__fixtures__/e704d5b-vectors.json'; +import { actionId, agentConfig, configId, deriveWallet, rulesId } from '../codec/ids'; +import { + decodeNativeTerms, + encodeNativeTerms, + nativeRuleToTerms, + nativeTermsToRule, +} from '../codec/native'; +import { buildSession, decodeEnvelope, decodeSession, encodeEnvelope, encodeSession } from '../codec/session'; +import { parseSelector, VALUE_ONLY_SELECTOR } from '../codec/selectors'; +import { argumentOffset, headSize } from '../codec/abi-layout'; +import { AGENTIC_DEFAULTS, UINT256_MAX } from '../codec/defaults'; +import { e704d5b } from '../contracts/e704d5b'; +import { AGW_ABI } from '../contracts/abi/e704d5b'; +import { AGENTIC_ERROR_CODE } from '../errors'; +import type { NativeRule } from '../agentic.types'; + +/** Restore {$bigint} markers written by the vector generator. */ +function revive(v: T): T { + return JSON.parse(JSON.stringify(v), (_k, x) => + x && typeof x === 'object' && '$bigint' in x ? BigInt(x.$bigint) : x + ); +} +const vectors = revive(vectorsJson) as unknown as { + rulesId: { validator: Address; agent: Address; grantNonce: bigint; agentConfig: Hex; expected: Hex }[]; + deriveWallet: { factory: Address; walletImplementation: Address; owner: Address; index: number; expected: Address }[]; + native: { + rule: NativeRule; + nativeChain: string; + wallet: Address; + rulesId: Hex; + actionId: Hex; + configId: Hex; + configInitialized: boolean; + storedTarget: Address; + storedSelector: Hex; + storedPins: { offset: number; expected: Hex }[]; + storedAmountOffset: number; + encodedSession: Hex; + }; +}; + +const NOW = 1_700_000_000; +const target = getAddress('0x0000000000000000000000000000000000007a76'); +const agent = getAddress('0x00000000000000000000000000000000000000a9'); + +describe('IDs against contract-generated vectors (e704d5b)', () => { + it.each(vectors.rulesId)('rulesId(agent, nonce) = engine.getPermissionId — nonce $grantNonce', (v) => { + expect(agentConfig(v.agent)).toBe(v.agentConfig); + expect(rulesId({ validator: v.validator, agent: v.agent, grantNonce: v.grantNonce })).toBe(v.expected); + }); + + it.each(vectors.deriveWallet)('deriveWallet mirrors factory.predictWallet for $owner', (v) => { + expect(deriveWallet(v)).toBe(getAddress(v.expected)); + }); + + it('actionId/configId: the policy holds an initialized config under exactly this key', () => { + const n = vectors.native; + expect(n.configInitialized).toBe(true); + expect(actionId(getAddress(n.storedTarget), n.storedSelector)).toBe(n.actionId); + expect(configId(n.wallet, n.rulesId, n.actionId)).toBe(n.configId); + }); + + it('rulesId rejects a grant nonce outside uint64', () => { + expect(() => rulesId({ validator: agent, agent, grantNonce: BigInt(2) ** BigInt(64) })).toThrow(/uint64/); + }); +}); + +describe('native rule codec', () => { + const v = vectors.native; + + it('encodes the session the contracts accepted and stored', () => { + const { terms } = nativeRuleToTerms(v.rule, { nowSeconds: NOW }); + const session = buildSession({ + validator: decodeSession(v.encodedSession).sessionValidator, + agent: v.rule.agent, + rulesPolicy: decodeSession(v.encodedSession).actions[0].actionPolicies[0].policy, + actions: [{ target: terms.target, selector: terms.selector, initData: encodeEnvelope(v.nativeChain, encodeNativeTerms(terms)) }], + }); + expect(encodeSession(session)).toBe(v.encodedSession); + expect(terms.pins).toEqual(v.storedPins); + expect(terms.amount.offset).toBe(v.storedAmountOffset); + expect(terms.selector).toBe(v.storedSelector); + }); + + it('round-trips terms through the envelope and back to a public rule', () => { + const { terms } = nativeRuleToTerms(v.rule, { nowSeconds: NOW }); + const env = decodeEnvelope(encodeEnvelope(v.nativeChain, encodeNativeTerms(terms))); + expect(env.chainNamespace).toBe(v.nativeChain); + const back = decodeNativeTerms(env.body); + expect(back).toEqual({ ...terms, validUntil: terms.validUntil }); + const rule = nativeTermsToRule(back, v.rule.agent, `0x${'00'.repeat(32)}`); + expect(rule.pins?.[0].arg).toBe(0); + expect(rule.amount).toEqual({ arg: 1, maxPerCall: BigInt(10), maxTotal: BigInt(100) }); + expect(rule.ref).toBeUndefined(); + }); + + it('applies the single provisional A03 defaults table for omitted limits', () => { + const { terms } = nativeRuleToTerms( + { agent, target, selector: 'f(uint256)', validUntil: NOW + 10, amount: { arg: 0, maxPerCall: BigInt(1) } }, + { nowSeconds: NOW } + ); + expect(terms.maxValuePerCall).toBe(AGENTIC_DEFAULTS.native.maxValuePerCall.value); + expect(terms.maxValueTotal).toBe(BigInt(0)); + expect(terms.maxCalls).toBe(0); + expect(terms.amount.maxTotal).toBe(UINT256_MAX); + }); + + it('keeps an explicit zero as zero', () => { + const { terms } = nativeRuleToTerms( + { agent, target, selector: 'f(uint256)', validUntil: NOW + 10, amount: { arg: 0, maxPerCall: BigInt(1), maxTotal: BigInt(0) } }, + { nowSeconds: NOW } + ); + expect(terms.amount.maxTotal).toBe(BigInt(0)); + }); + + it('value-only rules encode the reserved selector and refuse pins/amount', () => { + const { terms } = nativeRuleToTerms({ agent, target, selector: 'value-only', validUntil: NOW + 10 }, { nowSeconds: NOW }); + expect(terms.selector).toBe(VALUE_ONLY_SELECTOR); + expect(() => + nativeRuleToTerms( + { agent, target, selector: 'value-only', validUntil: NOW + 10, pins: [{ arg: 0, expected: agent }] }, + { nowSeconds: NOW } + ) + ).toThrow(/value-only/); + }); + + it.each([ + ['past expiry', { validUntil: NOW }], + ['zero target', { target: '0x0000000000000000000000000000000000000000' }], + ['too many pins', { selector: 'f(uint256)', pins: Array.from({ length: 9 }, () => ({ arg: 0, expected: BigInt(1) })) }], + ['pin needs a signature', { selector: '0x12345678', pins: [{ arg: 0, expected: BigInt(1) }] }], + ['pin on a dynamic argument', { selector: 'f(bytes)', pins: [{ arg: 0, expected: '0x01' }] }], + ['pin index out of range', { selector: 'f(uint256)', pins: [{ arg: 1, expected: BigInt(1) }] }], + ['pin value of the wrong type', { selector: 'f(address)', pins: [{ arg: 0, expected: BigInt(1) }] }], + ['amount on a non-uint', { selector: 'f(address)', amount: { arg: 0, maxPerCall: BigInt(1) } }], + ['amount also pinned', { selector: 'f(uint256)', pins: [{ arg: 0, expected: BigInt(1) }], amount: { arg: 0, maxPerCall: BigInt(1) } }], + ['negative cap', { maxValuePerCall: BigInt(-1) }], + ['maxCalls beyond uint32', { maxCalls: 2 ** 32 }], + ])('rejects %s before signing', (_name, patch) => { + const rule = { agent, target, selector: 'increment()', validUntil: NOW + 10, ...patch } as NativeRule; + expect(() => nativeRuleToTerms(rule, { nowSeconds: NOW })).toThrow( + expect.objectContaining({ code: AGENTIC_ERROR_CODE.INVALID_RULE }) + ); + }); + + it('approval functions need their spender pinned (A01 / obligation 16)', () => { + const base = { agent, target, validUntil: NOW + 10 }; + expect(() => nativeRuleToTerms({ ...base, selector: 'approve(address,uint256)' }, { nowSeconds: NOW })).toThrow(/spender/); + expect(() => + nativeRuleToTerms( + { ...base, selector: 'approve(address,uint256)', pins: [{ arg: 0, expected: agent }] }, + { nowSeconds: NOW } + ) + ).not.toThrow(); + expect(() => + nativeRuleToTerms( + { ...base, selector: 'permit(address,address,uint256,uint256,uint8,bytes32,bytes32)', pins: [{ arg: 0, expected: agent }] }, + { nowSeconds: NOW } + ) + ).toThrow(/spender/); + }); +}); + +describe('ABI layout offsets', () => { + it('accounts for dynamic heads and multi-word static tuples before the pinned argument', () => { + const dyn = parseSelector('f(bytes,address)'); + expect(argumentOffset(dyn.inputs, 1, 'pin')).toBe(4 + 32); + const tup = parseSelector('f((uint256,uint256),address)'); + expect(headSize(tup.inputs![0])).toBe(64); + expect(argumentOffset(tup.inputs, 1, 'pin')).toBe(4 + 64); + const arr = parseSelector('f(uint256[3],address)'); + expect(argumentOffset(arr.inputs, 1, 'pin')).toBe(4 + 96); + const dynTuple = parseSelector('f((uint256,bytes),address)'); + expect(argumentOffset(dynTuple.inputs, 1, 'pin')).toBe(4 + 32); + }); + + it('rejects pinning a tuple', () => { + const tup = parseSelector('f((uint256,uint256),address)'); + expect(() => argumentOffset(tup.inputs, 0, 'pin')).toThrow(/single-word/); + }); + + it('parses hex, signature and value-only selectors', () => { + expect(parseSelector('0x617BA037').selector).toBe('0x617ba037'); + expect(parseSelector('supply(address,uint256,address,uint16)').selector).toBe('0x617ba037'); + expect(parseSelector('value-only').valueOnly).toBe(true); + expect(() => parseSelector('not a selector' as never)).toThrow(); + }); +}); + +describe('wallet call encoders decode back to the same calls', () => { + const call = { target, value: BigInt(7), data: '0xd09de08a' as Hex }; + + it('execute single uses packed ERC-7579 calldata', () => { + const data = e704d5b.encodeExecute([call]); + const { functionName, args } = decodeFunctionData({ abi: AGW_ABI, data }); + expect(functionName).toBe('execute'); + expect(args[0]).toBe(`0x${'00'.repeat(32)}`); + expect((args[1] as Hex).length).toBe(2 + 2 * (20 + 32 + 4)); + expect(e704d5b.decodeWalletCall(data)).toEqual({ kind: 'execute', mode: args[0], calls: [call] }); + }); + + it('execute batch uses abi.encode(Execution[])', () => { + const data = e704d5b.encodeExecute([call, { ...call, value: BigInt(0) }]); + const decoded = e704d5b.decodeWalletCall(data); + expect(decoded).toMatchObject({ kind: 'execute', mode: `0x01${'00'.repeat(31)}` }); + expect((decoded as { calls: unknown[] }).calls).toEqual([call, { ...call, value: BigInt(0) }]); + }); + + it('executeAsAgent carries the rule ID and one packed call', () => { + const id = `0x${'42'.repeat(32)}` as Hex; + expect(e704d5b.decodeWalletCall(e704d5b.encodeExecuteAsAgent(id, call))).toEqual({ + kind: 'executeAsAgent', + rulesId: id, + mode: `0x${'00'.repeat(32)}`, + calls: [call], + }); + }); + + it('unknown calldata is not mistaken for a wallet call', () => { + expect(e704d5b.decodeWalletCall('0xdeadbeef')).toBeNull(); + }); +}); diff --git a/packages/core/src/lib/agentic/__tests__/fake-chain.ts b/packages/core/src/lib/agentic/__tests__/fake-chain.ts new file mode 100644 index 00000000..cbbc7559 --- /dev/null +++ b/packages/core/src/lib/agentic/__tests__/fake-chain.ts @@ -0,0 +1,315 @@ +/** + * In-memory stand-in for the AGW contract views used by unit tests. It models + * only what the SDK reads (factory registry/prediction, wallet wiring, + * engine enumeration, URP mode/native config, checkpoints and logs), so the + * SDK's own logic — selection, consistency, error mapping — is what is tested. + * Real-contract behaviour is covered by the local harness (__agw-local__). + */ +import { + encodeAbiParameters, + encodeEventTopics, + getAddress, + keccak256, + toBytes, + type AbiEvent, + type Address, + type Hex, + type Log, + type TransactionReceipt, +} from 'viem'; +import { PUSH_NETWORK } from '../../constants/enums'; +import { e704d5b } from '../contracts/e704d5b'; +import type { ChainReader } from '../contracts/reader'; +import { actionId, configId, deriveWallet } from '../codec/ids'; +import { registerAgenticGeneration, resetAgenticGenerations, type AgenticGeneration } from '../deployments'; +import type { NativeConfigRead } from '../contracts/e704d5b'; + +export const ADDR = { + factory: getAddress('0x00000000000000000000000000000000000fac70'), + impl: getAddress('0x00000000000000000000000000000000000001a1'), + engine: getAddress('0x00000000000000000000000000000000000e0e0e'), + policy: getAddress('0x0000000000000000000000000000000000000b01'), + validator: getAddress('0x0000000000000000000000000000000000000a1d'), + gateway: getAddress('0x00000000000000000000000000000000000000c1'), + owner: getAddress('0x00000000000000000000000000000000000000a0'), + agent: getAddress('0x00000000000000000000000000000000000000a9'), + other: getAddress('0x00000000000000000000000000000000000000b9'), + target: getAddress('0x0000000000000000000000000000000000007a76'), +}; + +export const PUSH_NS = 'eip155:42101'; +export const SEPOLIA_NS = 'eip155:11155111'; + +export interface FakeRule { + rulesId: Hex; + agent: Address; + mode: number; // 1 native, 0 universal + chain: string; + actionIds: Hex[]; + native?: Partial; + universal?: { + asset: Address; + expectedCEA: Address; + maxPCPerCall: bigint; + }; +} + +export interface FakeWallet { + address: Address; + owner: Address; + index: bigint; + label: string; + rules: FakeRule[]; + checkpointCount: bigint; + grantNonce: bigint; + accountId?: string; +} + +export class FakeChain implements ChainReader { + block = BigInt(100); + wallets = new Map(); + walletCounts = new Map(); + balances = new Map(); + checkpointLogs: Log[] = []; + extraLogs: Log[] = []; + failOn = new Set(); + calls: { functionName: string; blockNumber?: bigint }[] = []; + /** Override the factory's prediction (to simulate derivation drift). */ + predictOverride?: (owner: Address, index: bigint) => Address; + receipts = new Map(); + + addWallet(owner: Address, label: string, rules: FakeRule[] = []): FakeWallet { + const index = this.walletCounts.get(owner.toLowerCase()) ?? BigInt(0); + const address = deriveWallet({ factory: ADDR.factory, walletImplementation: ADDR.impl, owner, index }); + const w: FakeWallet = { address, owner, index, label, rules, checkpointCount: BigInt(0), grantNonce: BigInt(rules.length) }; + this.wallets.set(address.toLowerCase(), w); + this.walletCounts.set(owner.toLowerCase(), index + BigInt(1)); + this.extraLogs.push( + log(ADDR.factory, e704d5b.events.walletDeployed, { owner, index, wallet: address }, { label }, BigInt(10)) + ); + return w; + } + + nativeRule(agent: Address, rulesId: Hex, extra: Partial = {}): FakeRule { + return { + rulesId, + agent, + mode: 1, + chain: PUSH_NS, + actionIds: [actionId(ADDR.target, '0xd09de08a')], + native: extra, + }; + } + + async readContract(args: Parameters[0]): Promise { + const fn = args.functionName; + this.calls.push({ functionName: fn, blockNumber: args.blockNumber }); + if (this.failOn.has(fn)) throw new Error(`rpc failure: ${fn}`); + const a = (args.args ?? []) as readonly unknown[]; + const at = args.address.toLowerCase(); + const wallet = this.wallets.get(at); + switch (fn) { + // factory + case 'walletImplementation': + return ADDR.impl; + case 'walletCount': + return this.walletCounts.get(String(a[0]).toLowerCase()) ?? BigInt(0); + case 'predictWallet': { + const [owner, index] = a as [Address, bigint]; + const count = this.walletCounts.get(owner.toLowerCase()) ?? BigInt(0); + if (index > count) throw new Error('IndexOutOfRange'); + const addr = this.predictOverride + ? this.predictOverride(owner, index) + : deriveWallet({ factory: ADDR.factory, walletImplementation: ADDR.impl, owner, index }); + return [addr, index < count] as const; + } + case 'isWallet': + return this.wallets.has(String(a[0]).toLowerCase()); + case 'indexOf': + return this.wallets.get(String(a[0]).toLowerCase())?.index ?? BigInt(0); + // wallet + case 'factory': + if (!wallet) throw new Error('no factory()'); + return ADDR.factory; + case 'owner': + if (!wallet) throw new Error('not a wallet'); + return wallet.owner; + case 'SESSION_ENGINE': + return ADDR.engine; + case 'RULES_POLICY': + return ADDR.policy; + case 'SESSION_VALIDATOR': + return ADDR.validator; + case 'UNIVERSAL_GATEWAY_PC': + return ADDR.gateway; + case 'accountId': + return wallet?.accountId ?? 'push.agw.1.0.0'; + case 'grantNonce': + return wallet?.grantNonce ?? BigInt(0); + case 'checkpointCount': + return wallet?.checkpointCount ?? BigInt(0); + case 'agentOf': { + const r = wallet?.rules.find((x) => x.rulesId === a[0]); + return r?.agent ?? '0x0000000000000000000000000000000000000000'; + } + // engine + case 'getPermissionIDs': + return (this.wallets.get(String(a[0]).toLowerCase())?.rules ?? []).map((r) => r.rulesId); + case 'isPermissionEnabled': { + const w = this.wallets.get(String(a[1]).toLowerCase()); + return !!w?.rules.some((r) => r.rulesId === a[0]); + } + case 'getEnabledActions': { + const w = this.wallets.get(String(a[0]).toLowerCase()); + return w?.rules.find((r) => r.rulesId === a[1])?.actionIds ?? []; + } + // policy + case 'getMode': { + const found = this.findConfig(a[0] as Hex, a[1] as Address); + if (!found) return { initialized: false, mode: 0, vm: 0, chainHash: `0x${'00'.repeat(32)}` }; + return { initialized: true, mode: found.rule.mode, vm: 0, chainHash: keccak256(toBytes(found.rule.chain)) }; + } + case 'getNativeConfig': { + const found = this.findConfig(a[0] as Hex, a[1] as Address); + const n = found?.rule.native ?? {}; + return { + initialized: !!found, + validUntil: 2_000_000_000, + target: ADDR.target, + selector: '0xd09de08a', + maxValuePerCall: BigInt(0), + maxValueTotal: BigInt(0), + valueSpent: BigInt(0), + amount: { enabled: false, offset: 0, maxPerCall: BigInt(0), maxTotal: BigInt(0) }, + amountSpent: BigInt(0), + maxCalls: 0, + callsUsed: 0, + pins: [], + ...n, + }; + } + case 'getConfig': { + const found = this.findConfig(a[0] as Hex, a[1] as Address); + const u = found?.rule.universal; + return { + initialized: !!found, + validUntil: 2_000_000_000, + destChainHash: found ? keccak256(toBytes(found.rule.chain)) : `0x${'00'.repeat(32)}`, + expectedCEA: u?.expectedCEA ?? '0x0000000000000000000000000000000000000000', + asset: u?.asset ?? '0x0000000000000000000000000000000000000000', + maxAmountPerCall: BigInt(0), + maxAmountTotal: BigInt(0), + maxPCPerCall: u?.maxPCPerCall ?? BigInt(0), + spent: BigInt(0), + allowedCalls: [], + }; + } + case 'balanceOf': + case 'allowance': + return this.balances.get(`${fn}:${at}`) ?? BigInt(0); + default: + throw new Error(`FakeChain: unhandled ${fn}`); + } + } + + private findConfig(id: Hex, account: Address) { + const w = this.wallets.get(account.toLowerCase()); + if (!w) return undefined; + for (const rule of w.rules) { + for (const action of rule.actionIds) { + if (configId(w.address, rule.rulesId, action) === id) return { rule, action }; + } + } + return undefined; + } + + async getBlockNumber(): Promise { + if (this.failOn.has('getBlockNumber')) throw new Error('rpc failure: getBlockNumber'); + return this.block; + } + + async getCode(args: { address: Address }): Promise { + return this.wallets.has(args.address.toLowerCase()) ? '0x3d' : undefined; + } + + async getBalance(args: { address: Address }): Promise { + return this.balances.get(`pc:${args.address.toLowerCase()}`) ?? BigInt(0); + } + + async getLogs(args: Parameters[0]): Promise { + if (this.failOn.has('getLogs')) throw new Error('rpc failure: getLogs'); + return [...this.checkpointLogs, ...this.extraLogs].filter( + (l) => + l.address.toLowerCase() === args.address.toLowerCase() && + BigInt(l.blockNumber ?? BigInt(0)) >= args.fromBlock && + BigInt(l.blockNumber ?? BigInt(0)) <= args.toBlock + ); + } + + async getTransactionReceipt(args: { hash: Hex }): Promise { + const r = this.receipts.get(args.hash); + if (!r) throw new Error(`no receipt ${args.hash}`); + return r; + } +} + +let logIndex = 0; +export function log( + address: Address, + event: AbiEvent, + indexed: Record, + data: Record, + blockNumber: bigint, + txHash: Hex = `0x${'ab'.repeat(32)}`, + transactionIndex = 0 +): Log { + const topics = encodeEventTopics({ abi: [event], eventName: event.name, args: indexed } as never); + const nonIndexed = event.inputs.filter((i) => !('indexed' in i && i.indexed)); + return { + address, + topics: topics as [Hex, ...Hex[]], + data: encodeAbiParameters(nonIndexed, nonIndexed.map((i) => data[i.name as string]) as never), + blockNumber, + transactionHash: txHash, + transactionIndex, + logIndex: logIndex++, + blockHash: `0x${'cd'.repeat(32)}`, + removed: false, + } as Log; +} + +export function checkpointLog(wallet: Address, seq: number, kind: number, block: bigint, txIndex = 0): Log { + return log( + wallet, + e704d5b.events.checkpointed, + { seq: BigInt(seq) }, + { kind, ref: `0x${'11'.repeat(32)}`, blockNumber: block }, + block, + `0x${seq.toString(16).padStart(64, '0')}`, + txIndex + ); +} + +export function registerFakeGeneration(network: PUSH_NETWORK = PUSH_NETWORK.TESTNET_DONUT): AgenticGeneration { + resetAgenticGenerations(); + return registerAgenticGeneration({ + id: 'e704d5b', + sourceCommit: 'e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9', + network, + advertised: false, + addresses: { + factory: ADDR.factory, + walletImplementation: ADDR.impl, + sessionEngine: ADDR.engine, + rulesPolicy: ADDR.policy, + sessionValidator: ADDR.validator, + gateway: ADDR.gateway, + }, + startBlock: BigInt(1), + accountId: 'push.agw.1.0.0', + }); +} + +export function ruleId(n: number): Hex { + return `0x${n.toString(16).padStart(64, '0')}`; +} diff --git a/packages/core/src/lib/agentic/__tests__/management.spec.ts b/packages/core/src/lib/agentic/__tests__/management.spec.ts new file mode 100644 index 00000000..cafd96a8 --- /dev/null +++ b/packages/core/src/lib/agentic/__tests__/management.spec.ts @@ -0,0 +1,254 @@ +import { decodeFunctionData, type Hex, type Log } from 'viem'; +import { PUSH_NETWORK } from '../../constants/enums'; +import { PushChainBatchExecutionError } from '../../orchestrator/internals/errors'; +import type { MultiCall } from '../../orchestrator/orchestrator.types'; +import { PROGRESS_HOOK } from '../../progress-hook/progress-hook.types'; +import { AgenticCapability } from '../capabilities'; +import { currentGeneration, resetAgenticGenerations } from '../deployments'; +import { AGW_ABI, UNIVERSAL_RULES_POLICY_ABI } from '../contracts/abi/e704d5b'; +import { e704d5b } from '../contracts/e704d5b'; +import { deriveWallet, rulesId as computeRulesId } from '../codec/ids'; +import { AGENTIC_ERROR_CODE } from '../errors'; +import { createWallet } from '../management/create'; +import { addRules, revokeRules, updateRules } from '../management/rules-write'; +import type { NativeRule } from '../agentic.types'; +import { ADDR, FakeChain, PUSH_NS, log, registerFakeGeneration, ruleId } from './fake-chain'; +import { fakeResponse, mockRuntime } from './mock-runtime'; + +const NOW = 1_700_000_000; +const rule = (agent = ADDR.agent): NativeRule => ({ agent, target: ADDR.target, selector: 'increment()', validUntil: NOW + 100 }); +const granted = (wallet: `0x${string}`, id: Hex, block = BigInt(101)) => + log(wallet, e704d5b.events.rulesGranted, { rulesId: id, chainHash: `0x${'00'.repeat(32)}` }, { mode: 1, chainNamespace: PUSH_NS }, block); +const revoked = (wallet: `0x${string}`, id: Hex) => log(wallet, e704d5b.events.rulesRevoked, { rulesId: id }, {}, BigInt(101)); + +function withLogs(logs: Log[], over = {}) { + const r = fakeResponse(over); + const base = r.wait; + r.wait = async () => ({ ...(await base()), logs }); + return r; +} + +beforeEach(() => registerFakeGeneration()); +afterEach(() => resetAgenticGenerations()); + +describe('agentic.create', () => { + const nextWallet = deriveWallet({ factory: ADDR.factory, walletImplementation: ADDR.impl, owner: ADDR.owner, index: 0 }); + const ids = [ruleId(0), ruleId(1)].map((_, i) => + computeRulesId({ validator: ADDR.validator, agent: i === 0 ? ADDR.agent : ADDR.other, grantNonce: BigInt(i) }) + ); + + it('validates first, then sends deploy + grants in input order and returns receipt IDs', async () => { + const fake = new FakeChain(); + const rt = mockRuntime(fake, { + signer: ADDR.owner, + execute: (async () => + withLogs([ + log(ADDR.factory, e704d5b.events.walletDeployed, { owner: ADDR.owner, index: BigInt(0), wallet: nextWallet }, { label: 'ops' }, BigInt(101)), + granted(nextWallet, ids[0]), + granted(nextWallet, ids[1]), + ])) as never, + }); + const execute = jest.spyOn(rt, 'execute'); + const perCall = jest.fn(); + const res = await createWallet(rt, 'ops', { rules: [rule(), rule(ADDR.other)], progressHook: perCall }); + expect(res).toMatchObject({ wallet: nextWallet, index: 0, rulesIds: ids }); + const calls = (execute.mock.calls[0][0] as { data: MultiCall[] }).data; + expect(calls.map((c) => c.to)).toEqual([ADDR.factory, nextWallet, nextWallet]); + expect(decodeFunctionData({ abi: AGW_ABI, data: calls[1].data }).functionName).toBe('grantRules'); + expect(rt.events.map((e) => e.id)).toEqual([ + PROGRESS_HOOK.AGENTIC_TX_101, + PROGRESS_HOOK.AGENTIC_TX_102, + PROGRESS_HOOK.AGENTIC_TX_104, + PROGRESS_HOOK.AGENTIC_TX_199_01, + ]); + expect(rt.events.find((e) => e.id === 'AGENTIC-TX-103')).toBeUndefined(); + expect(perCall).toHaveBeenCalledTimes(4); + }); + + it('a bare wallet is one deployWallet call, no funding', async () => { + const fake = new FakeChain(); + const rt = mockRuntime(fake, { + signer: ADDR.owner, + execute: (async (p: { to: string; data: Hex; value: bigint }) => { + expect(p.to).toBe(ADDR.factory); + expect(p.value).toBe(BigInt(0)); + return withLogs([log(ADDR.factory, e704d5b.events.walletDeployed, { owner: ADDR.owner, index: BigInt(0), wallet: nextWallet }, { label: '' }, BigInt(101))]); + }) as never, + }); + expect((await createWallet(rt, '', { rules: [] })).rulesIds).toEqual([]); + }); + + it('invalid input never reaches the signer', async () => { + const fake = new FakeChain(); + const rt = mockRuntime(fake, { signer: ADDR.owner }); + await expect(createWallet(rt, 'x', { rules: [rule(ADDR.owner)] })).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.AGENT_IS_OWNER }); + await expect(createWallet(rt, 'x', { rules: [rule(), rule()] })).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.DUPLICATE_RULE }); + await expect(createWallet(rt, 'x', undefined as never)).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.INVALID_RULE }); + await expect(createWallet(mockRuntime(fake, { signer: ADDR.owner, readOnly: true }), 'x', { rules: [] })).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.READ_ONLY, + }); + expect(rt.executeMock).not.toHaveBeenCalled(); + }); + + it('a different wallet in the receipt is an INDEX_RACE with full details', async () => { + const fake = new FakeChain(); + const elsewhere = deriveWallet({ factory: ADDR.factory, walletImplementation: ADDR.impl, owner: ADDR.owner, index: 1 }); + const rt = mockRuntime(fake, { + signer: ADDR.owner, + execute: (async () => + withLogs([log(ADDR.factory, e704d5b.events.walletDeployed, { owner: ADDR.owner, index: BigInt(1), wallet: elsewhere }, { label: '' }, BigInt(101))])) as never, + }); + await expect(createWallet(rt, '', { rules: [] })).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.INDEX_RACE }); + }); + + it('IDs that differ from the input order are a RECEIPT_MISMATCH, not a silent reorder', async () => { + const fake = new FakeChain(); + const rt = mockRuntime(fake, { + signer: ADDR.owner, + execute: (async () => + withLogs([ + log(ADDR.factory, e704d5b.events.walletDeployed, { owner: ADDR.owner, index: BigInt(0), wallet: nextWallet }, { label: '' }, BigInt(101)), + granted(nextWallet, ids[1]), + granted(nextWallet, ids[0]), + ])) as never, + }); + await expect(createWallet(rt, '', { rules: [rule(), rule(ADDR.other)] })).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.RECEIPT_MISMATCH, + }); + }); + + it('a sequential failure after deployment is CREATE_PARTIAL with hashes and granted IDs, never a redeploy', async () => { + const fake = new FakeChain(); + const rt = mockRuntime(fake, { + signer: ADDR.owner, + execute: (async () => { + // Deployment and the first grant committed before the failure. + fake.addWallet(ADDR.owner, 'ops', [fake.nativeRule(ADDR.agent, ids[0])]); + throw new PushChainBatchExecutionError('grant 2 reverted', [`0x${'01'.repeat(32)}`, `0x${'02'.repeat(32)}`], `0x${'03'.repeat(32)}`); + }) as never, + }); + const err = await createWallet(rt, 'ops', { rules: [rule(), rule(ADDR.other)] }).catch((e) => e); + expect(err.code).toBe(AGENTIC_ERROR_CODE.CREATE_PARTIAL); + expect(err.details).toMatchObject({ + wallet: nextWallet, + walletDeployed: true, + grantedRulesIds: [ids[0]], + confirmedHashes: [`0x${'01'.repeat(32)}`, `0x${'02'.repeat(32)}`], + pendingHash: `0x${'03'.repeat(32)}`, + }); + expect(err.hint).toMatch(/rules\.add/); + expect(rt.events.at(-1)?.id).toBe(PROGRESS_HOOK.AGENTIC_TX_199_02); + }); + + it('a slot that is already deployed is refused before signing', async () => { + const fake = new FakeChain(); + fake.predictOverride = (owner, index) => deriveWallet({ factory: ADDR.factory, walletImplementation: ADDR.impl, owner, index }); + const w = fake.addWallet(ADDR.owner, 'a'); + fake.walletCounts.set(ADDR.owner.toLowerCase(), BigInt(0)); // stale count pointing at a deployed slot + void w; + const rt = mockRuntime(fake, { signer: ADDR.owner }); + await expect(createWallet(rt, '', { rules: [] })).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.INDEX_RACE }); + expect(rt.executeMock).not.toHaveBeenCalled(); + }); +}); + +describe('rules.add / rules.revoke', () => { + const gen = () => currentGeneration(PUSH_NETWORK.TESTNET_DONUT); + + it('add: owner-only, duplicate-aware against enabled rules, IDs from the grant nonce', async () => { + const fake = new FakeChain(); + const w = fake.addWallet(ADDR.owner, 'w', [fake.nativeRule(ADDR.agent, ruleId(1))]); + w.grantNonce = BigInt(4); + const expected = computeRulesId({ validator: ADDR.validator, agent: ADDR.other, grantNonce: BigInt(4) }); + const stranger = mockRuntime(fake, { signer: ADDR.other }); + await expect(addRules(stranger, gen(), w.address, [rule(ADDR.other)])).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.NOT_WALLET_OWNER, + }); + const rt = mockRuntime(fake, { signer: ADDR.owner, execute: (async () => withLogs([granted(w.address, expected)])) as never }); + await expect(addRules(rt, gen(), w.address, [rule(ADDR.agent)])).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.DUPLICATE_RULE, + }); + expect((await addRules(rt, gen(), w.address, [rule(ADDR.other)])).rulesIds).toEqual([expected]); + }); + + it('revoke: bare and empty are refused; unknown IDs fail before signing; several IDs are one atomic owner execute', async () => { + const fake = new FakeChain(); + const w = fake.addWallet(ADDR.owner, 'w', [fake.nativeRule(ADDR.agent, ruleId(1)), fake.nativeRule(ADDR.other, ruleId(2))]); + const rt = mockRuntime(fake, { + signer: ADDR.owner, + execute: (async () => withLogs([revoked(w.address, ruleId(1)), revoked(w.address, ruleId(2))])) as never, + }); + const exec = jest.spyOn(rt, 'execute'); + for (const bad of [undefined, [], {}, { all: false }]) { + await expect(revokeRules(rt, gen(), w.address, bad as never)).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.REVOKE_NEEDS_TARGET, + }); + } + await expect(revokeRules(rt, gen(), w.address, [ruleId(9)])).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.RULE_NOT_FOUND }); + expect(exec).not.toHaveBeenCalled(); + await revokeRules(rt, gen(), w.address, [ruleId(1), ruleId(2)]); + const sent = exec.mock.calls[0][0] as { to: string; data: Hex }; + expect(sent.to).toBe(w.address); + const decoded = e704d5b.decodeWalletCall(sent.data) as { kind: string; calls: { target: string; data: Hex }[] }; + expect(decoded.kind).toBe('execute'); + expect(decoded.calls.map((c) => decodeFunctionData({ abi: AGW_ABI, data: c.data }).functionName)).toEqual(['revokeRules', 'revokeRules']); + await revokeRules(rt, gen(), w.address, { all: true }); + expect(decodeFunctionData({ abi: AGW_ABI, data: (exec.mock.calls[1][0] as { data: Hex }).data }).functionName).toBe('revokeAllRules'); + }); +}); + +describe('rules.update — one owner batch: assert → revoke → grant', () => { + const gen = () => currentGeneration(PUSH_NETWORK.TESTNET_DONUT); + + it('builds exactly one execute(batch) with the observed spend asserted per pair', async () => { + const fake = new FakeChain(); + const w = fake.addWallet(ADDR.owner, 'w', [ + fake.nativeRule(ADDR.agent, ruleId(1), { valueSpent: BigInt(3), amountSpent: BigInt(4), callsUsed: 5 }), + ]); + w.grantNonce = BigInt(2); + const newId = computeRulesId({ validator: ADDR.validator, agent: ADDR.agent, grantNonce: BigInt(2) }); + const rt = mockRuntime(fake, { + signer: ADDR.owner, + execute: (async () => withLogs([revoked(w.address, ruleId(1)), granted(w.address, newId)])) as never, + }); + const exec = jest.spyOn(rt, 'execute'); + const res = await updateRules(rt, gen(), w.address, { rules: [{ rulesId: ruleId(1), rule: rule() }] }); + expect(res.rules).toEqual([{ rulesId: newId, replaced: ruleId(1) }]); + expect(exec).toHaveBeenCalledTimes(1); + const sent = exec.mock.calls[0][0] as { to: string; data: Hex }; + expect(Array.isArray(sent.data)).toBe(false); // never a sequential multi-tx batch + const outer = e704d5b.decodeWalletCall(sent.data) as { kind: string; mode: Hex; calls: { target: string; data: Hex }[] }; + expect(outer.kind).toBe('execute'); + expect(outer.calls.map((c) => c.target)).toEqual([ADDR.policy, w.address, w.address]); + const assertion = decodeFunctionData({ abi: UNIVERSAL_RULES_POLICY_ABI, data: outer.calls[0].data }); + expect(assertion.functionName).toBe('assertSpent'); + expect(assertion.args.slice(1)).toEqual([w.address, BigInt(3), BigInt(4), 5]); + expect(outer.calls.slice(1).map((c) => decodeFunctionData({ abi: AGW_ABI, data: c.data }).functionName)).toEqual([ + 'revokeRules', + 'grantRules', + ]); + }); + + it('replacing a universal rule needs the per-token assertion (A05) and fails before signing', async () => { + const fake = new FakeChain(); + const w = fake.addWallet(ADDR.owner, 'w', [{ ...fake.nativeRule(ADDR.agent, ruleId(1)), mode: 0, chain: 'eip155:11155111' }]); + const rt = mockRuntime(fake, { signer: ADDR.owner }); + await expect(updateRules(rt, gen(), w.address, { rules: [{ rulesId: ruleId(1), rule: rule() }] })).rejects.toMatchObject({ + details: { capability: AgenticCapability.ASSERT_SPENT_UNIVERSAL_MULTI }, + }); + expect(rt.executeMock).not.toHaveBeenCalled(); + }); + + it('a replacement may reuse the replaced pair but not collide with another enabled rule', async () => { + const fake = new FakeChain(); + const w = fake.addWallet(ADDR.owner, 'w', [fake.nativeRule(ADDR.agent, ruleId(1)), fake.nativeRule(ADDR.other, ruleId(2))]); + const rt = mockRuntime(fake, { signer: ADDR.owner }); + await expect( + updateRules(rt, gen(), w.address, { rules: [{ rulesId: ruleId(1), rule: rule(ADDR.other) }] }) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.DUPLICATE_RULE }); + await expect( + updateRules(rt, gen(), w.address, { rules: [{ rulesId: ruleId(1), rule: rule() }, { rulesId: ruleId(1), rule: rule() }] }) + ).rejects.toThrow(/same old rule twice/); + expect(rt.executeMock).not.toHaveBeenCalled(); + }); +}); diff --git a/packages/core/src/lib/agentic/__tests__/mock-runtime.ts b/packages/core/src/lib/agentic/__tests__/mock-runtime.ts new file mode 100644 index 00000000..420db37e --- /dev/null +++ b/packages/core/src/lib/agentic/__tests__/mock-runtime.ts @@ -0,0 +1,98 @@ +import type { Address, Hex } from 'viem'; +import { CHAIN, PUSH_NETWORK } from '../../constants/enums'; +import type { UniversalTxResponse } from '../../orchestrator/orchestrator.types'; +import type { ProgressEvent } from '../../progress-hook/progress-hook.types'; +import type { AgenticRuntime } from '../runtime'; +import { ADDR, FakeChain, PUSH_NS } from './fake-chain'; + +export interface MockRuntime extends AgenticRuntime { + executeMock: jest.Mock; + events: ProgressEvent[]; + perCallEvents: ProgressEvent[]; + fake: FakeChain; +} + +/** A response shaped like core's R1 response for a call to `to`. */ +export function fakeResponse(over: Partial = {}): UniversalTxResponse { + const resp = { + hash: `0x${'aa'.repeat(32)}`, + origin: `eip155:42101:${ADDR.agent}`, + blockNumber: BigInt(101), + blockHash: '0x', + transactionIndex: 0, + chainId: '42101', + from: ADDR.agent, + to: ADDR.target, + nonce: 1, + data: '0x', + value: BigInt(0), + gasLimit: BigInt(21000), + accessList: [], + wait: async () => ({ + hash: resp.hash, + blockNumber: BigInt(101), + blockHash: '0x', + transactionIndex: 0, + from: resp.from, + to: resp.to, + contractAddress: null, + gasPrice: BigInt(0), + gasUsed: BigInt(0), + cumulativeGasUsed: BigInt(0), + logs: [], + logsBloom: '0x', + status: 1 as const, + raw: { from: resp.from, to: resp.to }, + }), + progressHook: () => undefined, + type: '2', + typeVerbose: 'eip1559', + atomic: true, + signature: { r: '0x', s: '0x', v: 0 }, + ...over, + } as unknown as UniversalTxResponse; + return resp; +} + +export function mockRuntime( + fake: FakeChain, + over: Partial & { signer?: Address; readOnly?: boolean } = {} +): MockRuntime { + const events: ProgressEvent[] = []; + const perCallEvents: ProgressEvent[] = []; + const executeMock = jest.fn(async (params: { to: string; data?: Hex }) => + fakeResponse({ to: params.to, data: (params.data as string) ?? '0x' }) + ); + const signer = over.signer ?? ADDR.agent; + const rt: MockRuntime = { + network: PUSH_NETWORK.TESTNET_DONUT, + pushChainNamespace: PUSH_NS, + reader: fake, + isReadOnly: over.readOnly ?? false, + signerPushAccount: () => signer, + signerOrigin: () => ({ chain: CHAIN.PUSH_TESTNET_DONUT, address: signer }), + signerIsPushNative: () => true, + execute: executeMock as unknown as AgenticRuntime['execute'], + emit: (event, perCall) => { + events.push(event); + if (perCall) { + perCallEvents.push(event); + perCall(event); + } + }, + signerAccountDeployed: async () => true, + signerBalance: async () => BigInt(10) ** BigInt(20), + getGasPrice: async () => BigInt(1), + quoteOutbound: async () => ({ protocolFee: BigInt(100), nativeValueForGas: BigInt(1000), gasLimitUsed: BigInt(200_000) }), + resolveCEA: async () => ({ cea: '0x000000000000000000000000000000000000CeA1' as Address, isDeployed: true }), + resolvePrc20: () => '0x0000000000000000000000000000000000007070' as Address, + nowSeconds: () => 1_700_000_000, + ...over, + executeMock, + events, + perCallEvents, + fake, + }; + if (over.execute) rt.execute = over.execute; + return rt; +} diff --git a/packages/core/src/lib/agentic/__tests__/reads-context.spec.ts b/packages/core/src/lib/agentic/__tests__/reads-context.spec.ts new file mode 100644 index 00000000..4f342486 --- /dev/null +++ b/packages/core/src/lib/agentic/__tests__/reads-context.spec.ts @@ -0,0 +1,286 @@ +import { getAddress } from 'viem'; +import { PUSH_NETWORK } from '../../constants/enums'; +import { resolveAgenticContext } from '../context'; +import { resetAgenticGenerations, currentGeneration } from '../deployments'; +import { AGENTIC_ERROR_CODE } from '../errors'; +import { readCheckpoints, validateSequence } from '../reads/checkpoints'; +import { getRule, listRules, selectRuleForSend } from '../reads/rules'; +import { Snapshot } from '../reads/snapshot'; +import { deriveForOwner, listForOwner, walletInfo } from '../reads/wallets'; +import { ADDR, FakeChain, PUSH_NS, SEPOLIA_NS, checkpointLog, log, registerFakeGeneration, ruleId } from './fake-chain'; +import { mockRuntime } from './mock-runtime'; +import { e704d5b } from '../contracts/e704d5b'; + +describe('generation registry', () => { + afterEach(() => resetAgenticGenerations()); + + it('ships with no verified deployment: every network is GENERATION_UNSUPPORTED (A07)', () => { + resetAgenticGenerations(); + for (const n of Object.values(PUSH_NETWORK)) { + expect(() => currentGeneration(n)).toThrow( + expect.objectContaining({ code: AGENTIC_ERROR_CODE.GENERATION_UNSUPPORTED }) + ); + } + }); + + it('initialize against any wallet fails before signing when no generation is registered', async () => { + resetAgenticGenerations(); + const fake = new FakeChain(); + await expect(resolveAgenticContext(mockRuntime(fake), ADDR.target)).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.GENERATION_UNSUPPORTED, + }); + }); +}); + +describe('initialize with agenticWallet — door resolution', () => { + let fake: FakeChain; + beforeEach(() => { + registerFakeGeneration(); + fake = new FakeChain(); + }); + afterEach(() => resetAgenticGenerations()); + + it('owner → owner door; universal account context keeps signer identity separate', async () => { + const w = fake.addWallet(ADDR.owner, 'w'); + const ctx = await resolveAgenticContext(mockRuntime(fake, { signer: ADDR.owner }), w.address); + expect(ctx).toMatchObject({ wallet: w.address, door: 'owner', signerPushAccount: ADDR.owner }); + }); + + it('agent named in an enabled rule → agent door, even when that rule is expired', async () => { + const w = fake.addWallet(ADDR.owner, 'w', [fake.nativeRule(ADDR.agent, ruleId(1), { validUntil: 1 })]); + const ctx = await resolveAgenticContext(mockRuntime(fake), w.address); + expect(ctx.door).toBe('agent'); + }); + + it('anyone else → NOT_OWNER_OR_AGENT', async () => { + const w = fake.addWallet(ADDR.owner, 'w', [fake.nativeRule(ADDR.agent, ruleId(1))]); + await expect(resolveAgenticContext(mockRuntime(fake, { signer: ADDR.other }), w.address)).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.NOT_OWNER_OR_AGENT, + }); + }); + + it('no code → WALLET_NOT_DEPLOYED; a contract that is not an AGW → NOT_AGENTIC_WALLET', async () => { + await expect(resolveAgenticContext(mockRuntime(fake), ADDR.target)).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.WALLET_NOT_DEPLOYED, + }); + await expect(resolveAgenticContext(mockRuntime(fake), 'not-an-address')).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.NOT_AGENTIC_WALLET, + }); + }); + + it('wiring that does not match the registered generation is refused', async () => { + const w = fake.addWallet(ADDR.owner, 'w'); + w.accountId = 'push.agentwallet.1.0.0'; + await expect(resolveAgenticContext(mockRuntime(fake, { signer: ADDR.owner }), w.address)).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.GENERATION_UNSUPPORTED, + }); + }); +}); + +describe('per-send rule selection', () => { + let fake: FakeChain; + beforeEach(() => { + registerFakeGeneration(); + fake = new FakeChain(); + }); + afterEach(() => resetAgenticGenerations()); + const gen = () => currentGeneration(PUSH_NETWORK.TESTNET_DONUT); + + it('exactly one enabled (agent, chain) match is selected, at one block', async () => { + const w = fake.addWallet(ADDR.owner, 'w', [ + fake.nativeRule(ADDR.agent, ruleId(1)), + fake.nativeRule(ADDR.other, ruleId(2)), + { ...fake.nativeRule(ADDR.agent, ruleId(3)), mode: 0, chain: SEPOLIA_NS }, + ]); + const snap = await Snapshot.at(fake); + const r = await selectRuleForSend(snap, gen(), w.address, ADDR.agent, PUSH_NS); + expect(r.rulesId).toBe(ruleId(1)); + const u = await selectRuleForSend(snap, gen(), w.address, ADDR.agent, SEPOLIA_NS); + expect(u.rulesId).toBe(ruleId(3)); + expect(new Set(fake.calls.map((c) => c.blockNumber))).toEqual(new Set([fake.block])); + }); + + it('zero matches → NO_RULES_FOR_CHAIN', async () => { + const w = fake.addWallet(ADDR.owner, 'w', [fake.nativeRule(ADDR.other, ruleId(2))]); + await expect( + selectRuleForSend(await Snapshot.at(fake), gen(), w.address, ADDR.agent, PUSH_NS) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.NO_RULES_FOR_CHAIN }); + }); + + it('direct-grant duplicates → DUPLICATE_RULE listing every candidate, never an arbitrary pick', async () => { + const w = fake.addWallet(ADDR.owner, 'w', [fake.nativeRule(ADDR.agent, ruleId(1)), fake.nativeRule(ADDR.agent, ruleId(2))]); + await expect( + selectRuleForSend(await Snapshot.at(fake), gen(), w.address, ADDR.agent, PUSH_NS) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.DUPLICATE_RULE, details: { rulesIds: [ruleId(1), ruleId(2)] } }); + }); + + it('a revoked rule is not a candidate; lookups are not cached between sends', async () => { + const w = fake.addWallet(ADDR.owner, 'w', [fake.nativeRule(ADDR.agent, ruleId(1))]); + expect((await selectRuleForSend(await Snapshot.at(fake), gen(), w.address, ADDR.agent, PUSH_NS)).rulesId).toBe(ruleId(1)); + w.rules = []; + await expect( + selectRuleForSend(await Snapshot.at(fake), gen(), w.address, ADDR.agent, PUSH_NS) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.NO_RULES_FOR_CHAIN }); + }); + + it('an RPC failure is an error, never an empty rule set', async () => { + const w = fake.addWallet(ADDR.owner, 'w', [fake.nativeRule(ADDR.agent, ruleId(1))]); + fake.failOn.add('getPermissionIDs'); + await expect( + selectRuleForSend(await Snapshot.at(fake), gen(), w.address, ADDR.agent, PUSH_NS) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.RULE_READ_FAILED }); + }); +}); + +describe('rules.list / rules.get', () => { + let fake: FakeChain; + beforeEach(() => { + registerFakeGeneration(); + fake = new FakeChain(); + }); + afterEach(() => resetAgenticGenerations()); + const gen = () => currentGeneration(PUSH_NETWORK.TESTNET_DONUT); + + it('decodes native records with spend', async () => { + const w = fake.addWallet(ADDR.owner, 'w', [ + fake.nativeRule(ADDR.agent, ruleId(1), { callsUsed: 3, valueSpent: BigInt(5), maxCalls: 9 }), + ]); + const rules = await listRules(await Snapshot.at(fake), gen(), w.address, PUSH_NS); + expect(rules).toEqual([ + expect.objectContaining({ + rulesId: ruleId(1), + enabled: true, + chainNamespace: PUSH_NS, + agent: ADDR.agent, + spent: { kind: 'native', valueSpent: BigInt(5), amountSpent: BigInt(0), callsUsed: 3 }, + rule: expect.objectContaining({ maxCalls: 9, selector: '0xd09de08a' }), + }), + ]); + }); + + it('a universal rule cannot be decoded into the public type yet (A05) — the list fails, it is not truncated', async () => { + const w = fake.addWallet(ADDR.owner, 'w', [ + fake.nativeRule(ADDR.agent, ruleId(1)), + { ...fake.nativeRule(ADDR.other, ruleId(2)), mode: 0, chain: SEPOLIA_NS }, + ]); + await expect(listRules(await Snapshot.at(fake), gen(), w.address, PUSH_NS)).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.CAPABILITY_UNAVAILABLE, + }); + }); + + it('get: unknown → RULE_NOT_FOUND; revoked → history capability (A06), not an empty record', async () => { + const w = fake.addWallet(ADDR.owner, 'w'); + const snap = await Snapshot.at(fake); + await expect(getRule(snap, gen(), w.address, ruleId(9), PUSH_NS)).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.RULE_NOT_FOUND, + }); + fake.extraLogs.push(log(w.address, e704d5b.events.rulesRevoked, { rulesId: ruleId(9) }, {}, BigInt(50))); + await expect(getRule(snap, gen(), w.address, ruleId(9), PUSH_NS)).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.CAPABILITY_UNAVAILABLE, + details: { rulesId: ruleId(9), revoked: true }, + }); + }); +}); + +describe('wallet reads', () => { + let fake: FakeChain; + beforeEach(() => { + registerFakeGeneration(); + fake = new FakeChain(); + }); + afterEach(() => resetAgenticGenerations()); + const gen = () => currentGeneration(PUSH_NETWORK.TESTNET_DONUT); + + it('derive defaults to the next unused index; beyond it is refused', async () => { + fake.addWallet(ADDR.owner, 'a'); + expect(await deriveForOwner(fake, gen(), ADDR.owner)).toMatchObject({ index: 1, deployed: false }); + expect(await deriveForOwner(fake, gen(), ADDR.owner, 0)).toMatchObject({ index: 0, deployed: true }); + await expect(deriveForOwner(fake, gen(), ADDR.owner, 2)).rejects.toThrow(/beyond/); + }); + + it('derivation drift between the factory and the SDK mirror is detected (obligation 13)', async () => { + fake.predictOverride = () => getAddress('0x0000000000000000000000000000000000000bad'); + await expect(deriveForOwner(fake, gen(), ADDR.owner)).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.INCONSISTENT_READ, + }); + }); + + it('list returns deployed slots with labels and rule counts plus the next undeployed slot', async () => { + fake.addWallet(ADDR.owner, 'first', [fake.nativeRule(ADDR.agent, ruleId(1))]); + fake.addWallet(ADDR.owner, ''); + const wallets = await listForOwner(fake, gen(), ADDR.owner); + expect(wallets.map((w) => [w.index, w.label, w.deployed, w.rulesCount])).toEqual([ + [0, 'first', true, 1], + [1, '', true, 0], + [2, '', false, 0], + ]); + }); + + it('an empty owner lists only slot 0, undeployed', async () => { + expect(await listForOwner(fake, gen(), ADDR.other)).toEqual([ + expect.objectContaining({ index: 0, deployed: false, rulesCount: 0, label: '' }), + ]); + }); + + it('a missing deployment event is an inconsistency, not an empty label', async () => { + const w = fake.addWallet(ADDR.owner, 'x'); + fake.extraLogs = []; + await expect(walletInfo(fake, gen(), w.address)).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.INCONSISTENT_READ }); + }); + + it('info of the signer’s next slot describes it as undeployed; other undeployed addresses are refused', async () => { + const next = await deriveForOwner(fake, gen(), ADDR.owner); + expect(await walletInfo(fake, gen(), next.address, ADDR.owner)).toMatchObject({ deployed: false, index: 0, owner: ADDR.owner }); + await expect(walletInfo(fake, gen(), next.address, ADDR.other)).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.WALLET_NOT_DEPLOYED, + }); + }); +}); + +describe('checkpoints', () => { + let fake: FakeChain; + beforeEach(() => { + registerFakeGeneration(); + fake = new FakeChain(); + }); + afterEach(() => resetAgenticGenerations()); + const gen = () => currentGeneration(PUSH_NETWORK.TESTNET_DONUT); + + it('orders by block, tx and log index and counts five ticks for a replacement in one block', async () => { + const w = fake.addWallet(ADDR.owner, 'w'); + // A grant (seq 1), then a replacement batch (seq 2..6) in one tx; logs arrive reversed. + fake.checkpointLogs = [1, 2, 3, 4, 5, 6].map((seq) => + checkpointLog(w.address, seq, [1, 0, 0, 2, 0, 1][seq - 1], seq === 1 ? BigInt(20) : BigInt(60)) + ).reverse(); + w.checkpointCount = BigInt(6); + const { checkpoints } = await readCheckpoints(fake, gen(), w.address); + expect(checkpoints.map((c) => c.seq)).toEqual([1, 2, 3, 4, 5, 6]); + expect(checkpoints.slice(1).map((c) => c.kind)).toEqual([ + 'OWNER_ACTION', + 'OWNER_ACTION', + 'RULES_REVOKED', + 'OWNER_ACTION', + 'RULES_GRANTED', + ]); + const since = await readCheckpoints(fake, gen(), w.address, BigInt(60)); + expect(since.checkpoints).toHaveLength(5); + expect(since.checkpoints.every((c) => c.blockNumber === BigInt(60))).toBe(true); + }); + + it('a count/event mismatch is reported (after one retry) rather than returned', async () => { + const w = fake.addWallet(ADDR.owner, 'w'); + fake.checkpointLogs = [checkpointLog(w.address, 1, 1, BigInt(20))]; + w.checkpointCount = BigInt(2); + await expect(readCheckpoints(fake, gen(), w.address)).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.INCONSISTENT_READ, + }); + }); + + it('validateSequence checks contiguity and the count', () => { + expect(validateSequence([1, 2, 3], BigInt(3), true)).toBeNull(); + expect(validateSequence([1, 3], BigInt(3), true)).toMatch(/gap/); + expect(validateSequence([2, 3], BigInt(3), false)).toBeNull(); + expect(validateSequence([2, 3], BigInt(4), false)).toMatch(/does not match/); + expect(validateSequence([], BigInt(0), true)).toBeNull(); + }); +}); diff --git a/packages/core/src/lib/agentic/__tests__/response-surface.spec.ts b/packages/core/src/lib/agentic/__tests__/response-surface.spec.ts new file mode 100644 index 00000000..8ae5f95c --- /dev/null +++ b/packages/core/src/lib/agentic/__tests__/response-surface.spec.ts @@ -0,0 +1,119 @@ +import { encodeErrorResult, encodeFunctionData, getAddress, type Hex } from 'viem'; +import * as core from '../../index'; +import { CONSTANTS } from '../../constants'; +import { PUSH_NETWORK } from '../../constants/enums'; +import { UNIVERSAL_GATEWAY_PC } from '../../constants/abi'; +import { PushChainExecutionError } from '../../orchestrator/internals/errors'; +import { Utils } from '../../utils'; +import { AGW_ABI } from '../contracts/abi/e704d5b'; +import { e704d5b } from '../contracts/e704d5b'; +import { resetAgenticGenerations } from '../deployments'; +import { AgenticRevertError } from '../errors'; +import { adaptAgenticResponse, adaptTrackedResponse } from '../response'; +import { decodeAgenticRevert, decodeAgwErrorData } from '../revert'; +import { ADDR, FakeChain, registerFakeGeneration, ruleId } from './fake-chain'; +import { fakeResponse } from './mock-runtime'; + +afterEach(() => resetAgenticGenerations()); + +describe('response identity', () => { + it('live adaptation keeps origin/hash/raw and records the wrapped call', () => { + const resp = fakeResponse({ to: ADDR.target, data: '0xabcd', from: ADDR.agent }); + const origin = resp.origin; + adaptAgenticResponse(resp, { + wallet: ADDR.owner, + door: 'agent', + rulesId: ruleId(1), + logical: { to: ADDR.other, data: '0x01', value: BigInt(2) }, + }); + expect(resp).toMatchObject({ from: ADDR.owner, to: ADDR.other, data: '0x01', value: BigInt(2), origin }); + expect(resp.raw).toMatchObject({ from: ADDR.agent, to: ADDR.target, data: '0xabcd' }); + expect(resp.agentic).toMatchObject({ rawTo: ADDR.target, rawData: '0xabcd', door: 'agent' }); + }); + + it('replay: a tracked execute on a registered wallet is re-presented as the wallet’s call', async () => { + registerFakeGeneration(); + const fake = new FakeChain(); + const w = fake.addWallet(ADDR.owner, 'w'); + const data = e704d5b.encodeExecuteAsAgent(ruleId(4), { target: ADDR.target, value: BigInt(0), data: '0xd09de08a' }); + const tracked = await adaptTrackedResponse( + { reader: fake, network: PUSH_NETWORK.TESTNET_DONUT }, + fakeResponse({ to: w.address, data, from: ADDR.agent }) + ); + expect(tracked).toMatchObject({ from: w.address, to: ADDR.target, data: '0xd09de08a' }); + expect(tracked.agentic).toMatchObject({ door: 'agent', rulesId: ruleId(4) }); + }); + + it('replay: an outbound through the gateway restores the destination call and route', async () => { + registerFakeGeneration(); + const fake = new FakeChain(); + const w = fake.addWallet(ADDR.owner, 'w'); + const payload = ('0x2cc2842d' + + encodeFunctionData({ + abi: [{ type: 'function', name: 'x', inputs: [{ type: 'tuple[]', components: [{ name: 'to', type: 'address' }, { name: 'value', type: 'uint256' }, { name: 'data', type: 'bytes' }] }], outputs: [], stateMutability: 'nonpayable' }], + args: [[{ to: ADDR.target, value: BigInt(0), data: '0xd09de08a' }]], + }).slice(10)) as Hex; + const gatewayCall = encodeFunctionData({ + abi: UNIVERSAL_GATEWAY_PC, + functionName: 'sendUniversalTxOutbound', + args: [{ recipient: '0x', token: ADDR.other, amount: BigInt(1), gasLimit: BigInt(1), gasPrice: BigInt(0), maxPCForGas: BigInt(1), payload, revertRecipient: w.address }], + }); + const data = e704d5b.encodeExecuteAsAgent(ruleId(4), { target: ADDR.gateway, value: BigInt(5), data: gatewayCall }); + const tracked = await adaptTrackedResponse({ reader: fake, network: PUSH_NETWORK.TESTNET_DONUT }, fakeResponse({ to: w.address, data })); + expect(tracked).toMatchObject({ from: w.address, to: ADDR.target, data: '0xd09de08a', route: 'UOA_TO_CEA' }); + }); + + it('replay: anything not provably an AGW call is left untouched', async () => { + const fake = new FakeChain(); + const plain = fakeResponse({ to: ADDR.target, data: '0xd09de08a' }); + expect(await adaptTrackedResponse({ reader: fake, network: PUSH_NETWORK.TESTNET_DONUT }, plain)).toBe(plain); + registerFakeGeneration(); + const spoof = fakeResponse({ to: ADDR.target, data: e704d5b.encodeExecute([{ target: ADDR.other, value: BigInt(0), data: '0x' }]) }); + const out = await adaptTrackedResponse({ reader: fake, network: PUSH_NETWORK.TESTNET_DONUT }, spoof); + expect(out.from).toBe(spoof.from); + expect(out.agentic).toBeUndefined(); + }); +}); + +describe('revert decoding', () => { + it('decodes AGW errors with arguments', () => { + const data = encodeErrorResult({ abi: AGW_ABI, errorName: 'CallerIsNotAgent', args: [ruleId(1), ADDR.other] }); + expect(decodeAgwErrorData(data)).toMatchObject({ name: 'CallerIsNotAgent' }); + }); + + it('names a truncated PolicyCheckReverted by its inner selector', () => { + expect( + decodeAgwErrorData(`0xf4270752${'8bb88ba1'.padEnd(64, '0')}`) + ).toMatchObject({ name: 'PolicyCheckReverted(CallLimitReached)', selector: '0xf4270752' }); + }); + + it('finds revert data through error causes and viem-style messages', () => { + const inner = new Error('outer', { cause: { data: encodeErrorResult({ abi: AGW_ABI, errorName: 'UnsupportedExecutionMode' }) } }); + expect(decodeAgenticRevert(inner)?.name).toBe('UnsupportedExecutionMode'); + expect(decodeAgenticRevert(new Error('nothing here'))).toBeUndefined(); + }); +}); + +describe('public surface', () => { + it('exports the AGW errors, and the base execution error for instanceof checks', () => { + expect(core.AgenticError).toBeDefined(); + expect(new core.AgenticRevertError('x')).toBeInstanceOf(core.PushChainExecutionError); + expect(core.PushChainExecutionError).toBe(PushChainExecutionError); + expect(core.AGENTIC_ERROR_CODE.NO_RULES_FOR_CHAIN).toBe('NO_RULES_FOR_CHAIN'); + expect(new AgenticRevertError('x', { cause: 'c' }).cause).toBe('c'); + }); + + it('CONSTANTS.AGENTIC carries no unverified addresses (A07)', () => { + expect(CONSTANTS.AGENTIC).toEqual({}); + expect(Object.isFrozen(CONSTANTS.AGENTIC)).toBe(true); + }); + + it('PushChain.utils.agentic is the pure helper set', () => { + expect(Object.keys(Utils.agentic).sort()).toEqual( + ['actionId', 'compileCard', 'configId', 'decodeRules', 'deriveWallet', 'encodeRules', 'rulesId'].sort() + ); + expect( + Utils.agentic.deriveWallet(ADDR.owner, 0, { factory: ADDR.factory, walletImplementation: ADDR.impl }) + ).toBe(getAddress(Utils.agentic.deriveWallet(ADDR.owner, BigInt(0), { factory: ADDR.factory, walletImplementation: ADDR.impl }))); + }); +}); diff --git a/packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts b/packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts new file mode 100644 index 00000000..f938e0f1 --- /dev/null +++ b/packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts @@ -0,0 +1,180 @@ +import { getAddress, type Address } from 'viem'; +import { AgenticCapability } from '../capabilities'; +import { prepareRules } from '../codec/rules'; +import { validateUniversalRuleShape } from '../codec/universal'; +import { E704D5B_CAPABILITIES } from '../deployments'; +import { AGENTIC_ERROR_CODE } from '../errors'; +import { agenticUtils } from '../utils'; +import type { NativeRule, UniversalRule } from '../agentic.types'; +import { ADDR, PUSH_NS, SEPOLIA_NS } from './fake-chain'; + +const NOW = 1_700_000_000; +const ctx = { + owner: ADDR.owner, + pushChainNamespace: PUSH_NS, + validator: ADDR.validator, + rulesPolicy: ADDR.policy, + capabilities: E704D5B_CAPABILITIES, + nowSeconds: NOW, + forbiddenTargets: [ADDR.factory, ADDR.engine, ADDR.policy, ADDR.validator, ADDR.gateway], +}; +const native = (over: Partial = {}): NativeRule => ({ + agent: ADDR.agent, + target: ADDR.target, + selector: 'increment()', + validUntil: NOW + 100, + ...over, +}); +const universal = (over: Partial = {}): UniversalRule => ({ + agent: ADDR.agent, + chainNamespace: SEPOLIA_NS, + assets: [{ token: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238', maxPerCall: BigInt(100) }], + maxGasPerCall: BigInt(10) ** BigInt(18), + validUntil: NOW + 100, + allowedCalls: [{ target: ADDR.target, selector: 'supply(address,uint256,address,uint16)', beneficiary: 2 }], + ...over, +}); + +describe('prepareRules — spec 1.b checks before any signature', () => { + it('AGENT_IS_OWNER', () => { + expect(() => prepareRules([native({ agent: ADDR.owner })], ctx)).toThrow( + expect.objectContaining({ code: AGENTIC_ERROR_CODE.AGENT_IS_OWNER }) + ); + }); + + it('DUPLICATE_RULE within the input (same agent, same chain)', () => { + expect(() => prepareRules([native(), native({ target: ADDR.other })], ctx)).toThrow( + expect.objectContaining({ code: AGENTIC_ERROR_CODE.DUPLICATE_RULE }) + ); + }); + + it('DUPLICATE_RULE against an existing enabled rule, but not against one being replaced', () => { + const existing = [{ agent: ADDR.agent, chainNamespace: PUSH_NS, rulesId: `0x${'01'.repeat(32)}` as const }]; + expect(() => prepareRules([native()], { ...ctx, existing })).toThrow( + expect.objectContaining({ code: AGENTIC_ERROR_CODE.DUPLICATE_RULE }) + ); + expect(() => prepareRules([native()], { ...ctx, existing: [] })).not.toThrow(); + }); + + it('the same agent on two chains is two rules, not a duplicate', () => { + expect(() => prepareRules([native(), universal()], ctx)).toThrow( + expect.objectContaining({ code: AGENTIC_ERROR_CODE.CAPABILITY_UNAVAILABLE }) + ); + }); + + it('a ref is refused (never silently dropped) without the grant-ref capability (A07)', () => { + expect(() => prepareRules([native({ ref: `0x${'99'.repeat(32)}` })], ctx)).toThrow( + expect.objectContaining({ + code: AGENTIC_ERROR_CODE.CAPABILITY_UNAVAILABLE, + details: expect.objectContaining({ capability: AgenticCapability.GRANT_REF }), + }) + ); + }); + + it('refuses infrastructure targets the contracts would reject', () => { + for (const t of [ADDR.gateway, ADDR.policy, '0x0000000000000000000000000000000000000001' as Address]) { + expect(() => prepareRules([native({ target: t })], ctx)).toThrow(/infrastructure/); + } + }); + + it('a universal rule naming the Push chain is rejected', () => { + expect(() => prepareRules([universal({ chainNamespace: PUSH_NS as `eip155:${string}` })], ctx)).toThrow( + /omit chainNamespace/ + ); + }); + + it('valid native rules produce one Session each, agent bound in the validator config', () => { + const [p] = prepareRules([native()], ctx); + expect(p.chainNamespace).toBe(PUSH_NS); + expect(p.session.sessionValidator).toBe(ADDR.validator); + expect(p.session.actions).toHaveLength(1); + expect(p.session.actions[0].actionPolicies[0].policy).toBe(ADDR.policy); + expect(p.session.permitERC4337Paymaster).toBe(false); + }); +}); + +describe('universal rules — validated, then capability-gated (A01, A05)', () => { + it('structural validation runs before the capability gate', () => { + expect(() => validateUniversalRuleShape(universal({ allowedCalls: [] }), NOW)).toThrow(/1\.\.32/); + expect(() => validateUniversalRuleShape(universal({ maxGasPerCall: BigInt(0) }), NOW)).toThrow(/maxGasPerCall/); + expect(() => + validateUniversalRuleShape(universal({ chainNamespace: 'eip155:abc' as `eip155:${string}` }), NOW) + ).toThrow(/CAIP-2/); + expect(() => + validateUniversalRuleShape( + universal({ assets: Array.from({ length: 9 }, (_, i) => ({ token: getAddress(`0x${(i + 1).toString(16).padStart(40, '0')}`), maxPerCall: BigInt(1) })) }), + NOW + ) + ).toThrow(/at most 8/); + expect(() => + validateUniversalRuleShape( + universal({ + assets: [ + { token: ADDR.target, maxPerCall: BigInt(1) }, + { token: ADDR.target, maxPerCall: BigInt(2) }, + ], + }), + NOW + ) + ).toThrow(/duplicates/); + }); + + it('A01: approval selectors are refused in agent universal rules', () => { + expect(() => + validateUniversalRuleShape(universal({ allowedCalls: [{ target: ADDR.target, selector: 'approve(address,uint256)' }] }), NOW) + ).toThrow(expect.objectContaining({ details: expect.objectContaining({ assumption: 'A01' }) })); + expect(() => + validateUniversalRuleShape(universal({ allowedCalls: [{ target: ADDR.target, selector: '0x39509351' }] }), NOW) + ).toThrow(/increaseAllowance/); + }); + + it('a beneficiary must be an address argument of a known signature', () => { + expect(() => + validateUniversalRuleShape(universal({ allowedCalls: [{ target: ADDR.target, selector: 'supply(address,uint256,address,uint16)', beneficiary: 1 }] }), NOW) + ).toThrow(/address argument/); + expect(() => + validateUniversalRuleShape(universal({ allowedCalls: [{ target: ADDR.target, selector: '0x617ba037', beneficiary: 2 }] }), NOW) + ).toThrow(/signature/); + }); + + it('a structurally valid universal rule fails with CAPABILITY_UNAVAILABLE, never a guessed encoding', () => { + expect(() => prepareRules([universal()], ctx)).toThrow( + expect.objectContaining({ + code: AGENTIC_ERROR_CODE.CAPABILITY_UNAVAILABLE, + details: expect.objectContaining({ capability: AgenticCapability.UNIVERSAL_EVM_RULES }), + }) + ); + expect(() => + prepareRules([universal({ chainNamespace: 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1' })], ctx) + ).toThrow(expect.objectContaining({ details: expect.objectContaining({ capability: AgenticCapability.UNIVERSAL_SVM_RULES }) })); + }); +}); + +describe('PushChain.utils.agentic (pure)', () => { + const u = agenticUtils; + + it('encodeRules → decodeRules round-trips a native rule', () => { + const rule = native({ selector: 'deposit(address,uint256)', pins: [{ arg: 0, expected: ADDR.other }], maxCalls: 4 }); + const [bytes] = u.encodeRules([rule], { pushChainNamespace: PUSH_NS, validator: ADDR.validator, rulesPolicy: ADDR.policy, nowSeconds: NOW }); + const back = u.decodeRules(bytes, { pushChainNamespace: PUSH_NS }); + expect(back).toMatchObject({ agent: ADDR.agent, target: ADDR.target, maxCalls: 4, validUntil: NOW + 100 }); + expect((back as NativeRule).pins?.[0].arg).toBe(0); + }); + + it('decodeRules of a foreign-chain envelope is capability-gated', () => { + const [bytes] = u.encodeRules([native()], { pushChainNamespace: SEPOLIA_NS, validator: ADDR.validator, rulesPolicy: ADDR.policy, nowSeconds: NOW }); + expect(() => u.decodeRules(bytes, { pushChainNamespace: PUSH_NS })).toThrow( + expect.objectContaining({ code: AGENTIC_ERROR_CODE.CAPABILITY_UNAVAILABLE }) + ); + }); + + it('actionId accepts signatures and hex alike', () => { + expect(u.actionId(ADDR.target, 'increment()')).toBe(u.actionId(ADDR.target, '0xd09de08a')); + }); + + it('compileCard is explicitly unavailable (A08)', () => { + expect(() => u.compileCard({}, {}, {})).toThrow( + expect.objectContaining({ details: expect.objectContaining({ capability: AgenticCapability.COMPILE_CARD }) }) + ); + }); +}); diff --git a/packages/core/src/lib/agentic/__tests__/send.spec.ts b/packages/core/src/lib/agentic/__tests__/send.spec.ts new file mode 100644 index 00000000..f21df768 --- /dev/null +++ b/packages/core/src/lib/agentic/__tests__/send.spec.ts @@ -0,0 +1,295 @@ +import { decodeFunctionData, getAddress, type Address, type Hex } from 'viem'; +import { CHAIN, PUSH_NETWORK } from '../../constants/enums'; +import { UNIVERSAL_GATEWAY_PC, ERC20_EVM } from '../../constants/abi'; +import { PushChainExecutionError } from '../../orchestrator/internals/errors'; +import { PROGRESS_HOOK } from '../../progress-hook/progress-hook.types'; +import { AgenticCapability } from '../capabilities'; +import type { AgenticExecutionContext } from '../context'; +import { currentGeneration, resetAgenticGenerations } from '../deployments'; +import { e704d5b } from '../contracts/e704d5b'; +import { actionId } from '../codec/ids'; +import { AGENTIC_ERROR_CODE, AgenticRevertError } from '../errors'; +import { agenticSend } from '../execution/send'; +import { ADDR, FakeChain, SEPOLIA_NS, registerFakeGeneration, ruleId } from './fake-chain'; +import { mockRuntime } from './mock-runtime'; + +const data = '0xd09de08a' as Hex; + +function setup(door: 'owner' | 'agent', rules = (f: FakeChain) => [f.nativeRule(ADDR.agent, ruleId(1))]) { + registerFakeGeneration(); + const fake = new FakeChain(); + const w = fake.addWallet(ADDR.owner, 'w', rules(fake)); + const gen = currentGeneration(PUSH_NETWORK.TESTNET_DONUT); + const signer = door === 'owner' ? ADDR.owner : ADDR.agent; + const ctx: AgenticExecutionContext = { + wallet: w.address, + door, + signerPushAccount: signer, + signerOrigin: { chain: CHAIN.PUSH_TESTNET_DONUT, address: signer }, + generation: gen, + }; + return { fake, w, gen, ctx, rt: mockRuntime(fake, { signer }) }; +} + +afterEach(() => resetAgenticGenerations()); + +describe('guards fail before the signer is ever invoked', () => { + it.each([ + ['from (Routes 3/4)', { to: ADDR.target, data, from: { chain: CHAIN.ETHEREUM_SEPOLIA } }, AGENTIC_ERROR_CODE.FROM_NOT_ALLOWED], + ['payGasWith', { to: ADDR.target, data, payGasWith: {} }, AGENTIC_ERROR_CODE.NOT_ALLOWED_IN_AGENTIC_MODE], + ['migration', { to: { address: ADDR.target, chain: CHAIN.ETHEREUM_SEPOLIA }, migration: true }, AGENTIC_ERROR_CODE.NOT_ALLOWED_IN_AGENTIC_MODE], + ['funds on a Push send', { to: ADDR.target, funds: { amount: BigInt(1) } }, AGENTIC_ERROR_CODE.NOT_ALLOWED_IN_AGENTIC_MODE], + ])('%s', async (_name, params, code) => { + const { rt, ctx } = setup('agent'); + await expect(agenticSend(rt, ctx, params as never)).rejects.toMatchObject({ code }); + expect(rt.executeMock).not.toHaveBeenCalled(); + }); + + it('read-only clients never sign', async () => { + const { fake, ctx } = setup('owner'); + const rt = mockRuntime(fake, { signer: ADDR.owner, readOnly: true }); + await expect(agenticSend(rt, ctx, { to: ADDR.target, data })).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.READ_ONLY, + }); + expect(rt.executeMock).not.toHaveBeenCalled(); + }); + + it('agent native arrays are refused (A02)', async () => { + const { rt, ctx } = setup('agent'); + await expect( + agenticSend(rt, ctx, { + to: ADDR.target, + data: [ + { to: ADDR.target, value: BigInt(0), data }, + { to: ADDR.target, value: BigInt(0), data }, + ], + }) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.NOT_ALLOWED_IN_AGENTIC_MODE }); + expect(rt.executeMock).not.toHaveBeenCalled(); + }); + + it('NO_RULES_FOR_CHAIN and DUPLICATE_RULE are pre-signature', async () => { + const none = setup('agent', () => []); + await expect(agenticSend(none.rt, none.ctx, { to: ADDR.target, data })).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.NO_RULES_FOR_CHAIN, + }); + const dup = setup('agent', (f) => [f.nativeRule(ADDR.agent, ruleId(1)), f.nativeRule(ADDR.agent, ruleId(2))]); + await expect(agenticSend(dup.rt, dup.ctx, { to: ADDR.target, data })).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.DUPLICATE_RULE, + }); + expect(none.rt.executeMock).not.toHaveBeenCalled(); + expect(dup.rt.executeMock).not.toHaveBeenCalled(); + }); + + it('an external agent whose deployed UEA cannot pay Push gas fails loudly; an undeployed UEA takes the first-use path', async () => { + const { fake, ctx } = setup('agent'); + const poor = mockRuntime(fake, { + signer: ADDR.agent, + signerIsPushNative: () => false, + signerAccountDeployed: async () => true, + signerBalance: async () => BigInt(5), + getGasPrice: async () => BigInt(1), + }); + await expect(agenticSend(poor, ctx, { to: ADDR.target, data })).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.AGENT_GAS_INSUFFICIENT, + }); + expect(poor.executeMock).not.toHaveBeenCalled(); + const firstUse = mockRuntime(fake, { + signer: ADDR.agent, + signerIsPushNative: () => false, + signerAccountDeployed: async () => false, + signerBalance: async () => BigInt(0), + }); + await agenticSend(firstUse, ctx, { to: ADDR.target, data }); + expect(firstUse.executeMock).toHaveBeenCalledTimes(1); + }); +}); + +describe('native wrapping and logical identity', () => { + it('agent door: executeAsAgent(selected rule, exact call); response shows the wallet as from', async () => { + const { rt, ctx, w } = setup('agent'); + const perCall = jest.fn(); + const tx = await agenticSend(rt, ctx, { to: ADDR.target, data, value: BigInt(3) }, { progressHook: perCall }); + const sent = rt.executeMock.mock.calls[0][0]; + expect(sent.to).toBe(w.address); + expect(sent.value).toBe(BigInt(0)); + expect(e704d5b.decodeWalletCall(sent.data)).toEqual({ + kind: 'executeAsAgent', + rulesId: ruleId(1), + mode: `0x${'00'.repeat(32)}`, + calls: [{ target: ADDR.target, value: BigInt(3), data }], + }); + expect(tx).toMatchObject({ from: w.address, to: ADDR.target, data, value: BigInt(3) }); + expect(tx.origin).toContain(ADDR.agent); + expect(tx.agentic).toMatchObject({ wallet: w.address, door: 'agent', rulesId: ruleId(1), rawTo: w.address }); + const ids = rt.events.map((e) => e.id); + expect(ids).toEqual([PROGRESS_HOOK.AGENTIC_TX_107, PROGRESS_HOOK.AGENTIC_TX_199_01]); + expect(perCall).toHaveBeenCalledTimes(2); + expect(rt.executeMock.mock.calls[0][1]).toMatchObject({ progressHook: perCall }); + }); + + it('owner door: arrays become one atomic execute(batch)', async () => { + const { rt, ctx } = setup('owner'); + await agenticSend(rt, ctx, { + to: ADDR.target, + data: [ + { to: ADDR.target, value: BigInt(0), data }, + { to: ADDR.other, value: BigInt(1), data: '0x' }, + ], + }); + const decoded = e704d5b.decodeWalletCall(rt.executeMock.mock.calls[0][0].data); + expect(decoded).toMatchObject({ kind: 'execute', mode: `0x01${'00'.repeat(31)}` }); + expect((decoded as { calls: unknown[] }).calls).toHaveLength(2); + }); + + it('wallet waits report the wallet on the receipt too', async () => { + const { rt, ctx, w } = setup('agent'); + const tx = await agenticSend(rt, ctx, { to: ADDR.target, data }); + expect((await tx.wait()).from).toBe(w.address); + }); + + it('an on-chain policy revert becomes AgenticRevertError with the decoded gate and 199-02', async () => { + const { fake, ctx } = setup('agent'); + const rt = mockRuntime(fake, { + signer: ADDR.agent, + execute: async () => { + throw new PushChainExecutionError( + 'Execution reverted with reason: custom error 0xf4270752: 8bb88ba100000000000000000000000000000000000000000000000000000000.' + ); + }, + }); + const err = await agenticSend(rt, ctx, { to: ADDR.target, data }).catch((e) => e); + expect(err).toBeInstanceOf(AgenticRevertError); + expect(err).toBeInstanceOf(PushChainExecutionError); + expect(err.decodedError.name).toBe('PolicyCheckReverted(CallLimitReached)'); + const failed = rt.events.find((e) => e.id === PROGRESS_HOOK.AGENTIC_TX_199_02); + expect(failed?.response).toMatchObject({ decodedError: { name: 'PolicyCheckReverted(CallLimitReached)' } }); + }); +}); + +describe('EVM outbound composition from the wallet', () => { + const token = getAddress('0x0000000000000000000000000000000000007070'); + const universalSetup = () => { + const s = setup('agent', (f) => [ + { + ...f.nativeRule(ADDR.agent, ruleId(5)), + mode: 0, + chain: SEPOLIA_NS, + actionIds: [], + universal: { asset: token, expectedCEA: getAddress('0x000000000000000000000000000000000000cea1'), maxPCPerCall: BigInt(5000) }, + }, + ]); + // universal action id is (gateway, sendUniversalTxOutbound) + s.w.rules[0].actionIds = [actionId(ADDR.gateway, '0x77b86bec')]; + s.fake.balances.set(`pc:${s.w.address.toLowerCase()}`, BigInt(10) ** BigInt(18)); + s.fake.balances.set(`balanceOf:${token.toLowerCase()}`, BigInt(1000)); + s.fake.balances.set(`allowance:${token.toLowerCase()}`, BigInt(500)); + return s; + }; + const send = (amount?: bigint) => ({ + to: { address: ADDR.target, chain: CHAIN.ETHEREUM_SEPOLIA }, + data, + ...(amount ? { funds: { amount, token: { symbol: 'USDC', decimals: 6, address: token, mechanism: 'approve' as const } } } : {}), + }); + + it('builds the policy-compatible request: empty recipient, wallet refund, nonzero gas cap, multicall payload, CEA of the wallet', async () => { + const s = universalSetup(); + const resolveCEA = jest.fn(async () => ({ cea: getAddress('0x000000000000000000000000000000000000cea1'), isDeployed: true })); + const rt = mockRuntime(s.fake, { signer: ADDR.agent, resolveCEA, resolvePrc20: () => token }); + const tx = await agenticSend(rt, s.ctx, send(BigInt(100))); + expect(resolveCEA).toHaveBeenCalledWith(s.w.address, CHAIN.ETHEREUM_SEPOLIA); + const outer = e704d5b.decodeWalletCall(rt.executeMock.mock.calls[0][0].data) as { kind: string; rulesId: Hex; calls: { target: Address; value: bigint; data: Hex }[] }; + expect(outer.kind).toBe('executeAsAgent'); + expect(outer.rulesId).toBe(ruleId(5)); + expect(outer.calls[0].target).toBe(ADDR.gateway); + expect(outer.calls[0].value).toBe(BigInt(1100)); + const { args } = decodeFunctionData({ abi: UNIVERSAL_GATEWAY_PC, data: outer.calls[0].data }); + expect(args[0]).toMatchObject({ + recipient: '0x', + token, + amount: BigInt(100), + maxPCForGas: BigInt(1000), + revertRecipient: s.w.address, + }); + expect((args[0] as { payload: Hex }).payload.startsWith('0x2cc2842d')).toBe(true); + expect(tx).toMatchObject({ from: s.w.address, to: ADDR.target, route: 'UOA_TO_CEA', chain: CHAIN.ETHEREUM_SEPOLIA }); + expect(tx.agentic?.destinationAccount).toBe(getAddress('0x000000000000000000000000000000000000cea1')); + }); + + it('never injects an approval into the agent path; missing allowance fails before signing', async () => { + const s = universalSetup(); + s.fake.balances.set(`allowance:${token.toLowerCase()}`, BigInt(10)); + const rt = mockRuntime(s.fake, { signer: ADDR.agent, resolvePrc20: () => token }); + await expect(agenticSend(rt, s.ctx, send(BigInt(100)))).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.GATEWAY_ALLOWANCE_INSUFFICIENT, + }); + expect(rt.executeMock).not.toHaveBeenCalled(); + }); + + it('wallet PC below protocol fee + gas cap, or over the rule PC cap, fails before signing', async () => { + const s = universalSetup(); + s.fake.balances.set(`pc:${s.w.address.toLowerCase()}`, BigInt(10)); + const rt = mockRuntime(s.fake, { signer: ADDR.agent, resolvePrc20: () => token }); + await expect(agenticSend(rt, s.ctx, send())).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.WALLET_BALANCE_INSUFFICIENT }); + const s2 = universalSetup(); + const pricey = mockRuntime(s2.fake, { + signer: ADDR.agent, + resolvePrc20: () => token, + quoteOutbound: async () => ({ protocolFee: BigInt(100), nativeValueForGas: BigInt(10_000), gasLimitUsed: BigInt(1) }), + }); + await expect(agenticSend(pricey, s2.ctx, send())).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.RULE_LIMIT_EXCEEDED }); + }); + + it('a committed destination account that no longer matches derivation is drift, not a send', async () => { + const s = universalSetup(); + const rt = mockRuntime(s.fake, { + signer: ADDR.agent, + resolvePrc20: () => token, + resolveCEA: async () => ({ cea: getAddress('0x000000000000000000000000000000000000dead'), isDeployed: true }), + }); + await expect(agenticSend(rt, s.ctx, send())).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.INCONSISTENT_READ }); + }); + + it('a zero gas quote is refused (URP rejects an uncapped gas swap)', async () => { + const s = universalSetup(); + const rt = mockRuntime(s.fake, { + signer: ADDR.agent, + resolvePrc20: () => token, + quoteOutbound: async () => ({ protocolFee: BigInt(1), nativeValueForGas: BigInt(0), gasLimitUsed: BigInt(1) }), + }); + await expect(agenticSend(rt, s.ctx, send())).rejects.toThrow(/uncapped gas swap/); + }); + + it('SVM destinations are capability-gated', async () => { + const s = universalSetup(); + const rt = mockRuntime(s.fake, { signer: ADDR.agent }); + await expect( + agenticSend(rt, { ...s.ctx, door: 'owner' }, { to: { address: ADDR.target, chain: CHAIN.SOLANA_DEVNET }, data }) + ).rejects.toMatchObject({ details: { capability: AgenticCapability.UNIVERSAL_SVM_RULES } }); + }); + + it('owner door preserves any standing agent allowance: approve(current + amount) then the outbound, atomically', async () => { + const s = universalSetup(); + s.ctx.door = 'owner'; + s.ctx.signerPushAccount = ADDR.owner; + const rt = mockRuntime(s.fake, { signer: ADDR.owner, resolvePrc20: () => token }); + await agenticSend(rt, s.ctx, send(BigInt(100))); + const outer = e704d5b.decodeWalletCall(rt.executeMock.mock.calls[0][0].data) as { kind: string; calls: { target: Address; data: Hex }[] }; + expect(outer.kind).toBe('execute'); + expect(outer.calls.map((c) => c.target)).toEqual([token, ADDR.gateway]); + const approve = decodeFunctionData({ abi: ERC20_EVM, data: outer.calls[0].data }); + expect(approve.args).toEqual([ADDR.gateway, BigInt(600)]); + }); + + it('more than 10 destination calls are refused', async () => { + const s = universalSetup(); + const rt = mockRuntime(s.fake, { signer: ADDR.agent, resolvePrc20: () => token }); + await expect( + agenticSend(rt, s.ctx, { + to: { address: ADDR.target, chain: CHAIN.ETHEREUM_SEPOLIA }, + data: Array.from({ length: 11 }, () => ({ to: ADDR.target, value: BigInt(0), data })), + }) + ).rejects.toThrow(/at most 10/); + }); +}); + From ebc4167e566dd80a005aa92d78a167dd0a9ce62b Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Sat, 3 Oct 2026 19:39:52 +0530 Subject: [PATCH 07/68] feat(read): READ.CHAIN with enumerable WEB2 = 'web2', legacy web2:https accepted MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AGW SDK page §4 (outside change confirmed 2026-09-28), plan/agw step 15: - PushChain.CONSTANTS.READ.CHAIN = { ...CHAIN, WEB2: 'web2' }, enumerable. - CHAIN.WEB2 and READ.WEB2 become deprecated aliases with the same value 'web2'; CHAIN still enumerates blockchains only. - ReadChain accepts 'web2' and the legacy 'web2:https' literal; both normalize to the unchanged wire identity { web2, https } / caip2 'web2:https'. Prepared and tracked reads report chain 'web2'. - Transaction routing rejects both spellings. Behaviour change to review: the runtime value of CHAIN.WEB2 / READ.WEB2 is now 'web2' (was 'web2:https'). Comparisons against the constants keep working; code comparing against the old literal does not. --- packages/core/src/lib/constants/enums.ts | 9 ++- packages/core/src/lib/constants/index.ts | 17 ++++- packages/core/src/lib/constants/read-state.ts | 13 ++++ .../src/lib/orchestrator/route-detector.ts | 5 +- .../__tests__/public-surface.spec.ts | 10 +-- .../read-state/__tests__/web2-compat.spec.ts | 69 +++++++++++++++++++ .../core/src/lib/read-state/destination.ts | 8 ++- .../core/src/lib/read-state/read-params.ts | 13 ++-- .../src/lib/read-state/read-state.types.ts | 4 +- .../core/src/lib/read-state/read-tracker.ts | 6 +- .../core/src/lib/read-state/spec-builder.ts | 4 +- 11 files changed, 134 insertions(+), 24 deletions(-) create mode 100644 packages/core/src/lib/read-state/__tests__/web2-compat.spec.ts diff --git a/packages/core/src/lib/constants/enums.ts b/packages/core/src/lib/constants/enums.ts index da52330a..31ef1c3e 100644 --- a/packages/core/src/lib/constants/enums.ts +++ b/packages/core/src/lib/constants/enums.ts @@ -34,12 +34,15 @@ export enum CHAIN { } /** - * Read-only destination exposed with the OG `CHAIN.WEB2` spelling without - * widening the blockchain enum type accepted by transaction APIs. + * Read-only Web2 source kept on `CHAIN` for compatibility without widening the + * blockchain enum type accepted by transaction APIs. + * + * @deprecated Use `PushChain.CONSTANTS.READ.CHAIN.WEB2`. Same value (`'web2'`); + * the legacy literal `'web2:https'` is still accepted as read input. */ // eslint-disable-next-line @typescript-eslint/no-namespace -- declaration merging keeps Web2 out of the transaction enum union export namespace CHAIN { - export const WEB2 = 'web2:https' as const; + export const WEB2 = 'web2' as const; } // Namespace properties are normally enumerable after TypeScript emits them. // Keep blockchain enumeration (`Object.values(CHAIN)`) blockchain-only. diff --git a/packages/core/src/lib/constants/index.ts b/packages/core/src/lib/constants/index.ts index 213d9ea0..4048d4cb 100644 --- a/packages/core/src/lib/constants/index.ts +++ b/packages/core/src/lib/constants/index.ts @@ -15,14 +15,27 @@ import { READ_NAMESPACE, WEB2_DEFAULT_TIMEOUT_MS, WEB2_MAX_EXTRACT_ENTRIES, + WEB2_READ_CHAIN, } from './read-state'; import { UNIVERSAL_READ_STATUS, READ_STATUS, READ_ERROR_CODE, READ_OUTCOME } from '../read-state/read-state.types'; import { AGENTIC } from '../agentic/constants'; +/** + * `PushChain.CONSTANTS.READ.CHAIN` — every read source: all of `CHAIN` (same + * string values) plus the enumerable Web2 source. A superset of CHAIN, so + * `read({ chain: CHAIN.X })` keeps compiling. + */ +export const READ_CHAIN = Object.freeze({ + ...CHAIN, + WEB2: WEB2_READ_CHAIN, +}) as Readonly<{ [K in keyof typeof CHAIN]: (typeof CHAIN)[K] }> & { readonly WEB2: typeof WEB2_READ_CHAIN }; + /** `PushChain.CONSTANTS.READ` — cross-chain read state. Values verified against the deployed UniversalCallback. */ export const READ_CONSTANTS = { - /** Read-only Web2 destination. Equivalent to `CHAIN.WEB2`. */ - WEB2: CHAIN.WEB2, + /** Every read source, enumerable (spec page 5 §4). */ + CHAIN: READ_CHAIN, + /** @deprecated Use `READ.CHAIN.WEB2`. Same value (`'web2'`). */ + WEB2: WEB2_READ_CHAIN, NAMESPACE: READ_NAMESPACE, MAX_CALLBACK_GAS_LIMIT, MIN_CONFIRMATIONS_FLOOR, diff --git a/packages/core/src/lib/constants/read-state.ts b/packages/core/src/lib/constants/read-state.ts index 03ac47b8..5e596644 100644 --- a/packages/core/src/lib/constants/read-state.ts +++ b/packages/core/src/lib/constants/read-state.ts @@ -42,6 +42,19 @@ export const WEB2_MAX_TIMEOUT_MS = 15_000; * Web2 is not a blockchain and is not a `CHAIN` enum member. Reads target it via * an explicit destination; the node routes on namespace `web2`, id `https`. */ +/** Public Web2 read source (`READ.CHAIN.WEB2`). */ +export const WEB2_READ_CHAIN = 'web2' as const; +/** + * Legacy public spelling, and the unchanged CAIP-2 wire identity validators + * route on. Still accepted as read input. + */ +export const LEGACY_WEB2_READ_CHAIN = 'web2:https' as const; + +/** True for either public Web2 spelling. */ +export function isWeb2ReadChain(chain: unknown): chain is typeof WEB2_READ_CHAIN | typeof LEGACY_WEB2_READ_CHAIN { + return chain === WEB2_READ_CHAIN || chain === LEGACY_WEB2_READ_CHAIN; +} + export const WEB2_DESTINATION = { chainNamespace: 'web2', chainId: 'https', diff --git a/packages/core/src/lib/orchestrator/route-detector.ts b/packages/core/src/lib/orchestrator/route-detector.ts index 21d543a8..2ed0b15c 100644 --- a/packages/core/src/lib/orchestrator/route-detector.ts +++ b/packages/core/src/lib/orchestrator/route-detector.ts @@ -9,6 +9,7 @@ */ import { CHAIN } from '../constants/enums'; +import { isWeb2ReadChain } from '../constants/read-state'; import { MOVEABLE_TOKENS, type MoveableToken } from '../constants/tokens'; import type { UniversalExecuteParams, @@ -238,8 +239,8 @@ export function validateRouteParams( context?: { clientChain?: CHAIN } ): void { const toChain = isChainTarget(params.to) ? String(params.to.chain) : undefined; - if (String(params.from?.chain ?? '') === CHAIN.WEB2 || toChain === CHAIN.WEB2) { - throw new RouteValidationError('CHAIN.WEB2 is a read-only destination and cannot be used with transaction APIs'); + if (isWeb2ReadChain(String(params.from?.chain ?? '')) || isWeb2ReadChain(toChain)) { + throw new RouteValidationError('READ.CHAIN.WEB2 is a read-only destination and cannot be used with transaction APIs'); } const route = detectRoute(params); diff --git a/packages/core/src/lib/read-state/__tests__/public-surface.spec.ts b/packages/core/src/lib/read-state/__tests__/public-surface.spec.ts index d55a2c22..1beef01e 100644 --- a/packages/core/src/lib/read-state/__tests__/public-surface.spec.ts +++ b/packages/core/src/lib/read-state/__tests__/public-surface.spec.ts @@ -17,9 +17,10 @@ describe('read-state public surface', () => { ]) { expect(typeof (core as Record)[fn]).toBe('function'); } - expect(core.CHAIN.WEB2).toBe('web2:https'); - expect(PushChain.CONSTANTS.CHAIN.WEB2).toBe('web2:https'); - expect(Object.values(PushChain.CONSTANTS.CHAIN)).not.toContain('web2:https'); + // CHAIN.WEB2 is the deprecated alias of READ.CHAIN.WEB2 (AGW SDK page §4). + expect(core.CHAIN.WEB2).toBe('web2'); + expect(PushChain.CONSTANTS.CHAIN.WEB2).toBe(PushChain.CONSTANTS.READ.CHAIN.WEB2); + expect(Object.values(PushChain.CONSTANTS.CHAIN)).not.toContain('web2'); expect(core.UNIVERSAL_READ_STATUS.FULFILLED).toBe(3); expect(core.READ_STATUS.ERROR).toBe(2); expect(core.READ_ERROR_CODE.INVALID_QUERY).toBe(1); @@ -30,7 +31,8 @@ describe('read-state public surface', () => { it('PushChain.CONSTANTS.READ pins the contract-derived values', () => { const R = PushChain.CONSTANTS.READ; - expect(R.WEB2).toBe('web2:https'); + expect(R.WEB2).toBe('web2'); + expect(R.CHAIN.WEB2).toBe('web2'); expect(R.MAX_CALLBACK_GAS_LIMIT).toBe(1_000_000n); expect(R.MIN_CONFIRMATIONS_FLOOR).toBe(1); expect(R.DEFAULT_EXPIRY_BLOCKS).toBe(300n); diff --git a/packages/core/src/lib/read-state/__tests__/web2-compat.spec.ts b/packages/core/src/lib/read-state/__tests__/web2-compat.spec.ts new file mode 100644 index 00000000..e964bb7e --- /dev/null +++ b/packages/core/src/lib/read-state/__tests__/web2-compat.spec.ts @@ -0,0 +1,69 @@ +/** + * READ.CHAIN / Web2 compatibility (AGW SDK page §4, confirmed 2026-09-28): + * new enumerable READ.CHAIN.WEB2 = 'web2'; CHAIN.WEB2 and READ.WEB2 stay as + * deprecated aliases; the legacy 'web2:https' literal is still accepted; the + * wire identity the node routes on stays web2:https. + */ +import { PushChain } from '../../index'; +import { CHAIN } from '../../constants/enums'; +import { validateRouteParams } from '../../orchestrator/route-detector'; +import { resolveDestination } from '../destination'; +import { toBuildReadSpecParams, toReadDestination, toReadQuery } from '../read-params'; +import type { ReadChain } from '../read-state.types'; + +const R = PushChain.CONSTANTS.READ; +const web2 = { web2: { extract: [{ path: '$.a', valueType: 'string' as const }] } }; + +describe('READ.CHAIN', () => { + it('is an enumerable superset of CHAIN with WEB2 = "web2"', () => { + const values = Object.values(R.CHAIN); + for (const c of Object.values(CHAIN)) expect(values).toContain(c); + expect(values).toContain('web2'); + expect(Object.keys(R.CHAIN)).toContain('WEB2'); + expect(R.CHAIN.ETHEREUM_SEPOLIA).toBe(CHAIN.ETHEREUM_SEPOLIA); + }); + + it('CHAIN itself still enumerates only blockchains', () => { + expect(Object.keys(CHAIN)).not.toContain('WEB2'); + expect(CHAIN.WEB2).toBe(R.CHAIN.WEB2); + expect(R.WEB2).toBe(R.CHAIN.WEB2); + }); +}); + +describe.each([ + ['READ.CHAIN.WEB2', R.CHAIN.WEB2], + ['deprecated CHAIN.WEB2', CHAIN.WEB2], + ['legacy literal', 'web2:https'], +] as const)('%s', (_name, chain) => { + it('normalizes to the unchanged wire identity', () => { + const dest = resolveDestination(toReadDestination(chain as ReadChain)); + expect(dest).toMatchObject({ chainNamespace: 'web2', chainId: 'https', caip2: 'web2:https', namespace: 'web2' }); + expect(resolveDestination({ chain: chain as ReadChain })).toMatchObject({ caip2: 'web2:https' }); + }); + + it('builds an http query and spec params', () => { + expect(toReadQuery('https://x.test/a', { chain: chain as ReadChain, ...web2 })).toMatchObject({ type: 'http', url: 'https://x.test/a' }); + expect(toBuildReadSpecParams('https://x.test/a', { chain: chain as ReadChain, ...web2 }).destination).toEqual({ + chainNamespace: 'web2', + chainId: 'https', + }); + }); + + it('is rejected by transaction routing', () => { + expect(() => validateRouteParams({ to: { address: '0x0000000000000000000000000000000000000001', chain: chain as never } })).toThrow( + /read-only destination/ + ); + }); +}); + +describe('type-level separation', () => { + it('compiles', () => { + const a: ReadChain = 'web2'; + const b: ReadChain = 'web2:https'; + const c: ReadChain = CHAIN.ETHEREUM_SEPOLIA; + const d: ReadChain = R.CHAIN.WEB2; + // @ts-expect-error — a transaction ChainTarget never accepts the Web2 read source + const t: import('../../orchestrator/orchestrator.types').ChainTarget = { address: '0x', chain: R.CHAIN.WEB2 }; + expect([a, b, c, d, t].length).toBe(5); + }); +}); diff --git a/packages/core/src/lib/read-state/destination.ts b/packages/core/src/lib/read-state/destination.ts index 51b3b7a2..d7b9c268 100644 --- a/packages/core/src/lib/read-state/destination.ts +++ b/packages/core/src/lib/read-state/destination.ts @@ -1,4 +1,4 @@ -import { READ_NAMESPACE, type ReadNamespace } from '../constants/read-state'; +import { READ_NAMESPACE, WEB2_DESTINATION, WEB2_READ_CHAIN, type ReadNamespace } from '../constants/read-state'; import { UnsupportedReadDestinationError } from './errors'; import type { ReadDestination, ResolvedDestination } from './read-state.types'; @@ -17,7 +17,11 @@ const KNOWN: ReadonlySet = new Set(Object.values(READ_NAMESPACE)); export function resolveDestination(dest: ReadDestination): ResolvedDestination { let chainNamespace: string; let chainId: string; - if ('chain' in dest) { + if ('chain' in dest && dest.chain === WEB2_READ_CHAIN) { + // The public 'web2' spelling has no ':'; its wire identity is web2:https. + chainNamespace = WEB2_DESTINATION.chainNamespace; + chainId = WEB2_DESTINATION.chainId; + } else if ('chain' in dest) { const idx = dest.chain.indexOf(':'); if (idx <= 0) { throw new UnsupportedReadDestinationError(`chain is not CAIP-2: ${dest.chain}`); diff --git a/packages/core/src/lib/read-state/read-params.ts b/packages/core/src/lib/read-state/read-params.ts index ca8e5b65..65b18ab3 100644 --- a/packages/core/src/lib/read-state/read-params.ts +++ b/packages/core/src/lib/read-state/read-params.ts @@ -19,11 +19,11 @@ import { detectTokenProgram, resolveAccountName, validateIdl } from './svm-accou import { deriveIdlPda, isProgramSubject } from './svm-pda'; import { CHAIN, PUSH_NETWORK } from '../constants/enums'; import { computeReadQueryKey, resolveReadCallback } from './registry'; -import { READ_NAMESPACE, WEB2_DESTINATION } from '../constants/read-state'; +import { isWeb2ReadChain, READ_NAMESPACE, WEB2_DESTINATION } from '../constants/read-state'; import { resolveDestination } from './destination'; import { deriveAssociatedTokenAddress } from './envelopes/svm'; import { InvalidReadQueryError } from './errors'; -import type { BuildReadSpecParams, ReadChain, ReadDestination, ReadLifecycleOptions, ReadQuery, ReadResultShape, Web2Extract } from './read-state.types'; +import type { BuildReadSpecParams, ReadChain, ReadDestination, ReadLifecycleOptions, ReadQuery, ReadResultShape, Web2Extract, Web2ReadChain } from './read-state.types'; import type { ReadCallback } from './read-state.types'; import type { ProgressEvent } from '../progress-hook/progress-hook.types'; @@ -106,7 +106,7 @@ export type ReadQueryOptions = | ({ chain: SvmChain } & Query<'idl' | 'functionName' | 'args', { idl: Idl; functionName?: string; args?: readonly unknown[] }>) | ({ chain: EvmChain } & Query<'abi' | 'functionName' | 'args', { abi: Abi; functionName: string; args?: readonly unknown[] }>) | ({ chain: EvmChain } & Query<'storageSlot', { storageSlot: Hex | bigint }>) - | ({ chain: typeof CHAIN.WEB2 } & Query<'web2', { web2: ReadWeb2Options }>); + | ({ chain: Web2ReadChain } & Query<'web2', { web2: ReadWeb2Options }>); export type ReadCallbackOptions = { callback?: @@ -122,7 +122,7 @@ type FinalizedDestinationOptions = { blockNumber?: never; minConfirmations?: nev /** EVM reads expose pinning; SVM and Web2 choose their finalized/heightless references internally. */ export type ReadPrepareOptions = SharedPrepareOptions & ( | (Extract & EvmPinningOptions) - | (Extract & FinalizedDestinationOptions) + | (Extract & FinalizedDestinationOptions) ); export type ReadExecuteOptions = Pick; type WithExecutionOptions = T extends unknown @@ -196,7 +196,8 @@ function queryKind(o: ReadOptionsInput): (typeof QUERY_KEYS)[number] | 'native' } export function toReadDestination(chain: ReadChain): ReadDestination { - return chain === CHAIN.WEB2 ? WEB2_DESTINATION : { chain }; + // Both public spellings normalize to the unchanged wire identity web2:https. + return isWeb2ReadChain(chain) ? WEB2_DESTINATION : { chain }; } /** Build the internal query from the public grammar. Pure. */ @@ -209,7 +210,7 @@ export function toReadQuery(subject: string, o: ReadOptionsInput, resolvedTokenP if (!/^https:\/\//i.test(subject)) throw new InvalidReadQueryError('web2 subject must be an https:// URL'); return { type: 'http', url: subject, ...o.web2 }; } - if (kind === 'web2') throw new InvalidReadQueryError('`web2` is only valid with chain CHAIN.WEB2'); + if (kind === 'web2') throw new InvalidReadQueryError('`web2` is only valid with chain READ.CHAIN.WEB2'); if (dest.namespace === READ_NAMESPACE.EVM) { if (!isAddress(subject)) throw new InvalidReadQueryError(`EVM subject must be an address, got ${subject}`); diff --git a/packages/core/src/lib/read-state/read-state.types.ts b/packages/core/src/lib/read-state/read-state.types.ts index 6639c275..4f738085 100644 --- a/packages/core/src/lib/read-state/read-state.types.ts +++ b/packages/core/src/lib/read-state/read-state.types.ts @@ -11,7 +11,9 @@ import type { ReadNamespace } from '../constants/read-state'; * Where a read goes. `CHAIN` enum values are CAIP-2 and split cleanly; the * explicit form is the low-level escape hatch; the public API uses `CHAIN.WEB2`. */ -export type ReadChain = CHAIN | typeof CHAIN.WEB2; +/** Web2 read source: `READ.CHAIN.WEB2` (`'web2'`) or the legacy `'web2:https'` literal. */ +export type Web2ReadChain = 'web2' | 'web2:https'; +export type ReadChain = CHAIN | Web2ReadChain; export type ReadDestination = { chain: ReadChain } | { chainNamespace: string; chainId: string }; export type ResolvedDestination = { diff --git a/packages/core/src/lib/read-state/read-tracker.ts b/packages/core/src/lib/read-state/read-tracker.ts index 991c698d..79f891c0 100644 --- a/packages/core/src/lib/read-state/read-tracker.ts +++ b/packages/core/src/lib/read-state/read-tracker.ts @@ -26,6 +26,8 @@ import { READ_TRACK_MAX_TIMEOUT_MS, READ_TRACK_MIN_POLL_INTERVAL_MS, READ_TRACK_POLL_INTERVAL_MS, + WEB2_READ_CHAIN, + isWeb2ReadChain, } from '../constants/read-state'; import type { UniversalRead } from '../generated/ucallback/v1'; import { PROGRESS_HOOK } from '../progress-hook/progress-hook.types'; @@ -343,8 +345,8 @@ export function inferResultShape(namespace: string, query: Hex): ReadResultShape } } -function chainFromCaip2(caip2: string): CHAIN | typeof CHAIN.WEB2 | undefined { - if (caip2 === CHAIN.WEB2) return CHAIN.WEB2; +function chainFromCaip2(caip2: string): CHAIN | typeof WEB2_READ_CHAIN | undefined { + if (isWeb2ReadChain(caip2)) return WEB2_READ_CHAIN; return (Object.values(CHAIN) as string[]).includes(caip2) ? (caip2 as CHAIN) : undefined; } diff --git a/packages/core/src/lib/read-state/spec-builder.ts b/packages/core/src/lib/read-state/spec-builder.ts index 52641100..99b04efd 100644 --- a/packages/core/src/lib/read-state/spec-builder.ts +++ b/packages/core/src/lib/read-state/spec-builder.ts @@ -13,7 +13,7 @@ import { import { UNIVERSAL_CALLBACK_EVM } from '../constants/abi/universalCallback.evm'; import { UEA_FACTORY_ABI } from '../constants/abi/uea-factory'; import { UEA_FACTORY } from '../constants/chain'; -import { DEFAULT_EXPIRY_BLOCKS, MIN_CONFIRMATIONS_FLOOR, READ_NAMESPACE, READ_PREFLIGHT_STALE_MS } from '../constants/read-state'; +import { DEFAULT_EXPIRY_BLOCKS, MIN_CONFIRMATIONS_FLOOR, READ_NAMESPACE, READ_PREFLIGHT_STALE_MS, WEB2_READ_CHAIN } from '../constants/read-state'; import { sizeCallbackBudget } from './budget'; import { computeReadQueryKey } from './registry'; import { resolveDestination } from './destination'; @@ -137,7 +137,7 @@ export function buildReadSpecFromPreflight( return { callback: params.callback, queryKey: computeReadQueryKey(params.destination, params.query), - chain: dest.caip2 as ReadChain, + chain: (isWeb2 ? WEB2_READ_CHAIN : dest.caip2) as ReadChain, spec, specTuple: toTuple(spec), encodedSpec: encodeSpec(spec), From e63bcc9a4f866ba8bbf0aa8645b4130f937ab0af Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Sat, 3 Oct 2026 19:45:43 +0530 Subject: [PATCH 08/68] test(e2e): opt-in agw group with strict deployment gate Seven live AGW specs (21 scenarios) under __e2e__/agw covering create, funding and bounded allowance, native owner/agent execution and failures, add/update/revoke with checkpoint counts, positive-amount EVM outbound with destination verification and replay, external EVM / first-use / Solana-origin agents, and hook/identity behaviour through wait and trackTransaction. A pending spec records the multi-asset and SVM-destination cases as it.todo. Gating: specs run only with AGW_E2E=1 (set by the agw scenarios) and their beforeAll fails with AgwPrerequisiteError unless AGW_DEPLOYMENT_MANIFEST names a deployment whose wiring verifies on-chain, so a selected run cannot pass vacuously. No such deployment exists yet (A07). The group is excluded from `all` (still 76 scenarios), added to the workflow choices, and preflight verifies the manifest read-only and exits before any funding when it is missing. Budgets use the existing payer assets (Push master for owner gas, wallet PC and the bounded fresh-agent funding; EVM master UEA for external agent gas; pETH for the outbound). Not run live: there is no compatible deployment and no authorization. --- .github/workflows/e2e.yml | 1 + packages/core/__e2e__/agw/_fixture.ts | 135 +++++++++++++ packages/core/__e2e__/agw/_manifest.ts | 118 +++++++++++ packages/core/__e2e__/agw/create.spec.ts | 49 +++++ .../__e2e__/agw/funding-allowance.spec.ts | 47 +++++ .../core/__e2e__/agw/identity-gas.spec.ts | 93 +++++++++ packages/core/__e2e__/agw/lifecycle.spec.ts | 73 +++++++ .../core/__e2e__/agw/multi-asset-svm.spec.ts | 21 ++ packages/core/__e2e__/agw/native-exec.spec.ts | 101 ++++++++++ .../core/__e2e__/agw/responses-hooks.spec.ts | 51 +++++ .../core/__e2e__/agw/universal-evm.spec.ts | 136 +++++++++++++ packages/core/__e2e__/ci/preflight.ts | 16 ++ packages/core/__e2e__/ci/run.ts | 6 +- packages/core/__e2e__/ci/suite.ts | 190 +++++++++++++++++- 14 files changed, 1033 insertions(+), 4 deletions(-) create mode 100644 packages/core/__e2e__/agw/_fixture.ts create mode 100644 packages/core/__e2e__/agw/_manifest.ts create mode 100644 packages/core/__e2e__/agw/create.spec.ts create mode 100644 packages/core/__e2e__/agw/funding-allowance.spec.ts create mode 100644 packages/core/__e2e__/agw/identity-gas.spec.ts create mode 100644 packages/core/__e2e__/agw/lifecycle.spec.ts create mode 100644 packages/core/__e2e__/agw/multi-asset-svm.spec.ts create mode 100644 packages/core/__e2e__/agw/native-exec.spec.ts create mode 100644 packages/core/__e2e__/agw/responses-hooks.spec.ts create mode 100644 packages/core/__e2e__/agw/universal-evm.spec.ts diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index a4794fe4..e4e2eee7 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -25,6 +25,7 @@ on: - cross-chain - read - known-fail + - agw dry_run: description: 'Pre-flight only — report balances, fund nothing, run no tests' required: true diff --git a/packages/core/__e2e__/agw/_fixture.ts b/packages/core/__e2e__/agw/_fixture.ts new file mode 100644 index 00000000..4cf7b6e4 --- /dev/null +++ b/packages/core/__e2e__/agw/_fixture.ts @@ -0,0 +1,135 @@ +/** + * Shared AGW E2E fixture. Everything here is setup: the behaviour under test + * is always exercised through public SDK methods in the specs. + * + * Accounts (never logged): + * PUSH_PRIVATE_KEY Push-native owner (the Push master); pays owner gas, + * wallet PC and the bounded per-run agent funding. + * EVM_PRIVATE_KEY external EVM agent, acting through its Sepolia-origin UEA. + * SOLANA_PRIVATE_KEY Solana-origin agent through its UEA (Push-destination only). + * A fresh Push-native agent key is generated per run and funded with at most + * AGW_E2E_AGENT_PC (default 0.5 PC). Wallets are fresh per run; nothing shared + * is revoked or drained. + */ +import '@e2e/shared/setup'; +import { appendFileSync, mkdirSync } from 'node:fs'; +import { join } from 'node:path'; +import { createPublicClient, createWalletClient, defineChain, http, parseEther, type Address, type Hex, type PublicClient } from 'viem'; +import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts'; +import { PushChain } from '../../src'; +import { CHAIN_INFO } from '../../src/lib/constants/chain'; +import { CHAIN, PUSH_NETWORK } from '../../src/lib/constants/enums'; +import { registerAgenticGeneration, resetAgenticGenerations } from '../../src/lib/agentic/deployments'; +import { createEvmPushClient } from '@e2e/shared/evm-client'; +import { AgwPrerequisiteError, loadAgwManifest, verifyAgwManifest, type AgwManifest } from './_manifest'; + +export const AGW_E2E_ENABLED = process.env['AGW_E2E'] === '1'; + +export interface AgwFixture { + manifest: AgwManifest; + push: PublicClient; + owner: PushChain; + ownerAddress: Address; + agentKey: Hex; + agentAddress: Address; + agent(wallet: Address, progressHook?: (e: unknown) => void): Promise; + fundPC(to: Address, amount: bigint): Promise; + evidence(name: string, data: Record): void; + teardown(): void; +} + +const pushChainFor = (network: PUSH_NETWORK) => + network === PUSH_NETWORK.MAINNET ? CHAIN.PUSH_MAINNET : network === PUSH_NETWORK.LOCALNET ? CHAIN.PUSH_LOCALNET : CHAIN.PUSH_TESTNET_DONUT; + +/** + * Strict prerequisite gate: throws (failing beforeAll, hence every test) when + * the manifest, keys or wiring are missing. A selected agw run can never pass + * without exercising a verified deployment. + */ +export async function setupAgw(): Promise { + const manifest = loadAgwManifest(); + const pushKey = process.env['PUSH_PRIVATE_KEY'] as Hex | undefined; + if (!pushKey) throw new AgwPrerequisiteError('PUSH_PRIVATE_KEY is not set'); + const chain = pushChainFor(manifest.network); + const info = CHAIN_INFO[chain]; + const push = createPublicClient({ + chain: defineChain({ + id: Number(info.chainId), + name: 'push', + nativeCurrency: { name: 'PC', symbol: 'PC', decimals: 18 }, + rpcUrls: { default: { http: info.defaultRPC } }, + }), + transport: http(info.defaultRPC[0]), + }) as PublicClient; + await verifyAgwManifest(push, manifest); + resetAgenticGenerations(); + registerAgenticGeneration({ + id: manifest.generation, + sourceCommit: manifest.sourceCommit, + network: manifest.network, + advertised: false, + addresses: manifest.addresses, + startBlock: manifest.startBlock, + accountId: manifest.accountId, + capabilities: manifest.capabilities, + }); + + const { pushClient: owner, account } = await createEvmPushClient({ chain, privateKey: pushKey, network: manifest.network }); + const agentKey = generatePrivateKey(); + const agentAddress = privateKeyToAccount(agentKey).address; + const fundPC = async (to: Address, amount: bigint) => { + const tx = await owner.universal.sendTransaction({ to, value: amount }); + const r = await tx.wait(); + if (r.status !== 1) throw new Error(`funding ${to} failed`); + }; + await fundPC(agentAddress, parseEther(process.env['AGW_E2E_AGENT_PC'] ?? '0.5')); + + const logDir = join(__dirname, '..', '..', 'e2e-logs'); + mkdirSync(logDir, { recursive: true }); + const evidence = (name: string, data: Record) => + appendFileSync( + join(logDir, 'agw-evidence.jsonl'), + JSON.stringify( + { name, at: new Date().toISOString(), network: manifest.network, sourceCommit: manifest.sourceCommit, ...data }, + (_k, v) => (typeof v === 'bigint' ? v.toString() : v) + ) + '\n' + ); + + return { + manifest, + push, + owner, + ownerAddress: account.address, + agentKey, + agentAddress, + agent: (wallet, progressHook) => evmClient(agentKey, chain, manifest.network, wallet, progressHook), + fundPC, + evidence, + teardown: () => resetAgenticGenerations(), + }; +} + +export const inSeconds = (s: number) => Math.floor(Date.now() / 1000) + s; + +/** A client for an EVM key on `origin` (Push-native or external), optionally acting as an AGW. */ +export async function evmClient( + key: Hex, + origin: CHAIN, + network: PUSH_NETWORK, + agenticWallet?: Address, + progressHook?: (e: unknown) => void +): Promise { + const walletClient = createWalletClient({ + account: privateKeyToAccount(key), + transport: http(CHAIN_INFO[origin].defaultRPC[0]), + }); + const signer = await PushChain.utils.signer.toUniversalFromKeypair(walletClient, { + chain: origin, + library: PushChain.CONSTANTS.LIBRARY.ETHEREUM_VIEM, + }); + return PushChain.initialize(signer, { + network, + ...(agenticWallet ? { agenticWallet } : {}), + ...(progressHook ? { progressHook: progressHook as never } : {}), + }); +} diff --git a/packages/core/__e2e__/agw/_manifest.ts b/packages/core/__e2e__/agw/_manifest.ts new file mode 100644 index 00000000..ef7e11da --- /dev/null +++ b/packages/core/__e2e__/agw/_manifest.ts @@ -0,0 +1,118 @@ +/** + * AGW deployment manifest for live E2E — READ-ONLY. Loaded from the JSON file + * named by AGW_DEPLOYMENT_MANIFEST and verified against the chain before any + * test (or preflight funding) runs. No manifest exists today: no compatible + * AGW generation is deployed (plan/agw assumption A07), so the agw group + * fails this gate by design instead of reporting success. + * + * Manifest shape: + * { + * "network": "TESTNET_DONUT", + * "generation": "e704d5b", + * "sourceCommit": "<40-hex AGW commit>", + * "startBlock": "", + * "accountId": "push.agw.1.0.0", + * "addresses": { "factory", "walletImplementation", "sessionEngine", + * "rulesPolicy", "sessionValidator", "gateway" }, + * "capabilities": ["nativeRules", ...] // optional; defaults to the generation's + * } + */ +import { readFileSync } from 'node:fs'; +import { getAddress, isAddress, type Address, type PublicClient } from 'viem'; +import { PUSH_NETWORK } from '../../src/lib/constants/enums'; +import { AgenticCapability } from '../../src/lib/agentic/capabilities'; +import { E704D5B_CAPABILITIES } from '../../src/lib/agentic/deployments'; +import { e704d5b } from '../../src/lib/agentic/contracts/e704d5b'; + +export const AGW_PREREQ_HINT = + 'AGW live E2E needs AGW_DEPLOYMENT_MANIFEST pointing at a verified compatible deployment (plan/agw A07). ' + + 'None exists yet; historical Donut AGW addresses implement a different ABI.'; + +export interface AgwManifest { + network: PUSH_NETWORK; + generation: 'e704d5b'; + sourceCommit: string; + startBlock: bigint; + accountId: string; + addresses: { + factory: Address; + walletImplementation: Address; + sessionEngine: Address; + rulesPolicy: Address; + sessionValidator: Address; + gateway: Address; + }; + capabilities: ReadonlySet; +} + +export class AgwPrerequisiteError extends Error { + constructor(reason: string) { + super(`AGW prerequisite not met: ${reason}. ${AGW_PREREQ_HINT}`); + this.name = 'AgwPrerequisiteError'; + } +} + +export function loadAgwManifest(path = process.env['AGW_DEPLOYMENT_MANIFEST']): AgwManifest { + if (!path) throw new AgwPrerequisiteError('AGW_DEPLOYMENT_MANIFEST is not set'); + let raw: Record; + try { + raw = JSON.parse(readFileSync(path, 'utf8')); + } catch (cause) { + throw new AgwPrerequisiteError(`cannot read manifest ${path}: ${(cause as Error).message}`); + } + const network = raw['network'] as PUSH_NETWORK; + if (!Object.values(PUSH_NETWORK).includes(network)) throw new AgwPrerequisiteError(`unknown network ${String(network)}`); + if (raw['generation'] !== e704d5b.id) { + throw new AgwPrerequisiteError(`generation ${String(raw['generation'])} has no SDK adapter`); + } + if (typeof raw['sourceCommit'] !== 'string' || !/^[0-9a-f]{40}$/.test(raw['sourceCommit'])) { + throw new AgwPrerequisiteError('sourceCommit must be a 40-hex commit'); + } + const a = (raw['addresses'] ?? {}) as Record; + const keys = ['factory', 'walletImplementation', 'sessionEngine', 'rulesPolicy', 'sessionValidator', 'gateway'] as const; + for (const k of keys) { + if (!isAddress(a[k] ?? '', { strict: false })) throw new AgwPrerequisiteError(`addresses.${k} is missing or invalid`); + } + const caps = Array.isArray(raw['capabilities']) + ? new Set((raw['capabilities'] as string[]).map((c) => { + if (!(Object.values(AgenticCapability) as string[]).includes(c)) throw new AgwPrerequisiteError(`unknown capability ${c}`); + return c as AgenticCapability; + })) + : E704D5B_CAPABILITIES; + return { + network, + generation: 'e704d5b', + sourceCommit: raw['sourceCommit'], + startBlock: BigInt(String(raw['startBlock'] ?? '0')), + accountId: String(raw['accountId'] ?? 'push.agw.1.0.0'), + addresses: Object.fromEntries(keys.map((k) => [k, getAddress(a[k])])) as AgwManifest['addresses'], + capabilities: caps, + }; +} + +/** Read-only on-chain check that the manifest's wiring is what it claims. */ +export async function verifyAgwManifest(client: PublicClient, m: AgwManifest): Promise { + const read = (address: Address, abi: readonly unknown[], functionName: string) => + client.readContract({ address, abi: abi as never, functionName: functionName as never } as never) as Promise; + for (const [name, addr] of Object.entries(m.addresses)) { + if (name === 'gateway') continue; // a precompile may report no code + const code = await client.getCode({ address: addr }); + if (!code || code === '0x') throw new AgwPrerequisiteError(`${name} ${addr} has no code`); + } + const impl = getAddress((await read(m.addresses.factory, e704d5b.abis.factory, 'walletImplementation')) as string); + if (impl !== m.addresses.walletImplementation) { + throw new AgwPrerequisiteError(`factory implementation is ${impl}, manifest says ${m.addresses.walletImplementation}`); + } + const wiring: [string, Address][] = [ + ['SESSION_ENGINE', m.addresses.sessionEngine], + ['RULES_POLICY', m.addresses.rulesPolicy], + ['SESSION_VALIDATOR', m.addresses.sessionValidator], + ['UNIVERSAL_GATEWAY_PC', m.addresses.gateway], + ]; + for (const [fn, expected] of wiring) { + const got = getAddress((await read(impl, e704d5b.abis.wallet, fn)) as string); + if (got !== expected) throw new AgwPrerequisiteError(`implementation ${fn} is ${got}, manifest says ${expected}`); + } + const accountId = (await read(impl, e704d5b.abis.wallet, 'accountId')) as string; + if (accountId !== m.accountId) throw new AgwPrerequisiteError(`implementation accountId is ${accountId}`); +} diff --git a/packages/core/__e2e__/agw/create.spec.ts b/packages/core/__e2e__/agw/create.spec.ts new file mode 100644 index 00000000..7a4735b9 --- /dev/null +++ b/packages/core/__e2e__/agw/create.spec.ts @@ -0,0 +1,49 @@ +/** + * Scenario 1 — create: bare wallet and wallet with rules. Strictly gated on a + * verified AGW deployment manifest (see _manifest.ts); beforeAll throws when + * it is missing so a selected run cannot pass vacuously. + */ +import { getAddress, type Address } from 'viem'; +import { e704d5b } from '../../src/lib/agentic/contracts/e704d5b'; +import { AGW_E2E_ENABLED, inSeconds, setupAgw, type AgwFixture } from './_fixture'; + +const d = AGW_E2E_ENABLED ? describe : describe.skip; + +d('agw create', () => { + let f: AgwFixture; + beforeAll(async () => { + f = await setupAgw(); + }, 300_000); + afterAll(() => f?.teardown()); + + it('1. bare wallet: factory records the owner and index, no rules, no implicit funding', async () => { + const before = await f.owner.agentic.derive(); + const created = await f.owner.agentic.create('e2e-bare', { rules: [] }); + expect(created.wallet).toBe(before.address); + expect(created.index).toBe(before.index); + expect(created.rulesIds).toEqual([]); + const factoryAbi = e704d5b.abis.factory; + const [ownerOf, indexOf, balance] = await Promise.all([ + f.push.readContract({ address: f.manifest.addresses.factory, abi: factoryAbi, functionName: 'ownerOf', args: [created.wallet] }), + f.push.readContract({ address: f.manifest.addresses.factory, abi: factoryAbi, functionName: 'indexOf', args: [created.wallet] }), + f.push.getBalance({ address: created.wallet }), + ]); + expect(getAddress(ownerOf as Address)).toBe(f.ownerAddress); + expect(Number(indexOf)).toBe(created.index); + expect(balance).toBe(BigInt(0)); + const info = await f.owner.agentic.wallet(created.wallet).info(); + expect(info).toMatchObject({ label: 'e2e-bare', deployed: true, rulesCount: 0, owner: f.ownerAddress }); + f.evidence('create-bare', { wallet: created.wallet, index: created.index, tx: created.tx.hash, block: created.tx.blockNumber }); + }); + + it('2. wallet with a native rule returns the receipt-confirmed rule ID', async () => { + const created = await f.owner.agentic.create('e2e-rules', { + rules: [{ agent: f.agentAddress, target: f.ownerAddress, selector: 'value-only', validUntil: inSeconds(3600), maxValuePerCall: BigInt(1) }], + }); + expect(created.rulesIds).toHaveLength(1); + const { rules } = await f.owner.agentic.wallet(created.wallet).rules.list(); + expect(rules.map((r) => r.rulesId)).toEqual(created.rulesIds); + expect(rules[0].agent).toBe(getAddress(f.agentAddress)); + f.evidence('create-with-rule', { wallet: created.wallet, rulesIds: created.rulesIds, tx: created.tx.hash, atomic: created.tx.atomic }); + }); +}); diff --git a/packages/core/__e2e__/agw/funding-allowance.spec.ts b/packages/core/__e2e__/agw/funding-allowance.spec.ts new file mode 100644 index 00000000..064cd5bb --- /dev/null +++ b/packages/core/__e2e__/agw/funding-allowance.spec.ts @@ -0,0 +1,47 @@ +/** + * Scenario 2 — funding and bounded gateway allowance are ordinary sends, + * separate from create, and wallet PC is separate from signer gas. + */ +import { encodeFunctionData, erc20Abi, parseEther, type Address, type Hex } from 'viem'; +import { CHAIN } from '../../src/lib/constants/enums'; +import { getNativePRC20ForChain } from '../../src/lib/orchestrator/internals/helpers'; +import { AGW_E2E_ENABLED, evmClient, setupAgw, type AgwFixture } from './_fixture'; + +const d = AGW_E2E_ENABLED ? describe : describe.skip; + +d('agw funding', () => { + let f: AgwFixture; + let wallet: Address; + beforeAll(async () => { + f = await setupAgw(); + wallet = (await f.owner.agentic.create('e2e-funding', { rules: [] })).wallet; + }, 300_000); + afterAll(() => f?.teardown()); + + it('1. wallet PC is funded by an ordinary send and is separate from the signer balance', async () => { + const signerBefore = await f.push.getBalance({ address: f.ownerAddress }); + await f.fundPC(wallet, parseEther('0.01')); + expect(await f.push.getBalance({ address: wallet })).toBe(parseEther('0.01')); + expect(await f.push.getBalance({ address: f.ownerAddress })).toBeLessThan(signerBefore); + }); + + it('2. owner sets and removes a bounded gateway allowance through the owner door', async () => { + const token = getNativePRC20ForChain(CHAIN.ETHEREUM_SEPOLIA, f.manifest.network); + const ownerAgw = await evmClient(process.env['PUSH_PRIVATE_KEY'] as Hex, CHAIN.PUSH_TESTNET_DONUT, f.manifest.network, wallet); + const allowance = () => + f.push.readContract({ address: token, abi: erc20Abi, functionName: 'allowance', args: [wallet, f.manifest.addresses.gateway] }); + const approve = (amount: bigint) => + ownerAgw.universal.sendTransaction({ + to: token, + data: encodeFunctionData({ abi: erc20Abi, functionName: 'approve', args: [f.manifest.addresses.gateway, amount] }), + }); + const set = await approve(BigInt(1000)); + expect((await set.wait()).status).toBe(1); + expect(set.from).toBe(wallet); + expect(set.agentic?.door).toBe('owner'); + expect(await allowance()).toBe(BigInt(1000)); + await (await approve(BigInt(0))).wait(); + expect(await allowance()).toBe(BigInt(0)); + f.evidence('allowance-set-remove', { wallet, token, setTx: set.hash }); + }); +}); diff --git a/packages/core/__e2e__/agw/identity-gas.spec.ts b/packages/core/__e2e__/agw/identity-gas.spec.ts new file mode 100644 index 00000000..d2cdbef4 --- /dev/null +++ b/packages/core/__e2e__/agw/identity-gas.spec.ts @@ -0,0 +1,93 @@ +/** + * Scenario 9 — external-key agents act through the UEA for their actual + * origin chain; first-use vs subsequent gas. Solana-ORIGIN agents are covered + * here on a Push destination; Solana-DESTINATION rules are a separate, + * capability-gated feature (see multi-asset-svm.spec.ts). + */ +import { Keypair } from '@solana/web3.js'; +import bs58 from 'bs58'; +import { createWalletClient, getAddress, http, parseEther, type Address, type Hex } from 'viem'; +import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts'; +import { sepolia } from 'viem/chains'; +import { PushChain } from '../../src'; +import { CHAIN } from '../../src/lib/constants/enums'; +import { createProgressTracker } from '@e2e/shared/progress-tracker'; +import { AGW_E2E_ENABLED, evmClient, inSeconds, setupAgw, type AgwFixture } from './_fixture'; + +const d = AGW_E2E_ENABLED ? describe : describe.skip; +const SINK = getAddress('0x000000000000000000000000000000000000dEaD'); + +async function ueaOf(address: string, chain: CHAIN): Promise
{ + const r = await PushChain.utils.account.deriveExecutorAccount(PushChain.utils.account.toUniversal(address, { chain }), { + skipNetworkCheck: true, + }); + return getAddress(r.address); +} + +d('agw identity', () => { + let f: AgwFixture; + beforeAll(async () => { + f = await setupAgw(); + }, 300_000); + afterAll(() => f?.teardown()); + + const walletFor = async (agent: Address) => { + const created = await f.owner.agentic.create('e2e-identity', { + rules: [{ agent, target: SINK, selector: 'value-only', validUntil: inSeconds(3600), maxValuePerCall: BigInt(1000), maxValueTotal: BigInt(10_000) }], + }); + await f.fundPC(created.wallet, parseEther('0.001')); + return created.wallet; + }; + + it('1. an EVM key on Sepolia acts through its Sepolia UEA; origin and account status stay signer-scoped', async () => { + const key = process.env['EVM_PRIVATE_KEY'] as Hex; + if (!key) throw new Error('EVM_PRIVATE_KEY is required'); + const uea = await ueaOf(privateKeyToAccount(key).address, CHAIN.ETHEREUM_SEPOLIA); + const wallet = await walletFor(uea); + const agent = await evmClient(key, CHAIN.ETHEREUM_SEPOLIA, f.manifest.network, wallet); + expect(agent.universal.account).toBe(wallet); + expect(agent.universal.origin.chain).toBe(CHAIN.ETHEREUM_SEPOLIA); + expect((await agent.getAccountStatus()).uea.deployed).toBe(true); + const tx = await agent.universal.sendTransaction({ to: SINK, value: BigInt(1000) }); + expect((await tx.wait()).status).toBe(1); + expect(tx.from).toBe(wallet); + expect(tx.origin.startsWith('eip155:11155111:')).toBe(true); + f.evidence('external-evm-agent', { wallet, uea, tx: tx.hash }); + }, 600_000); + + it('2. first use of an undeployed external UEA takes the one-time fee lock; the next action pays from the UEA', async () => { + const key = generatePrivateKey(); + const addr = privateKeyToAccount(key).address; + const master = createWalletClient({ account: privateKeyToAccount(process.env['EVM_PRIVATE_KEY'] as Hex), chain: sepolia, transport: http() }); + await master.sendTransaction({ to: addr, value: parseEther(process.env['AGW_E2E_FIRST_USE_ETH'] ?? '0.003'), account: master.account!, chain: sepolia }); + const uea = await ueaOf(addr, CHAIN.ETHEREUM_SEPOLIA); + const wallet = await walletFor(uea); + const first = createProgressTracker(); + const agent = await evmClient(key, CHAIN.ETHEREUM_SEPOLIA, f.manifest.network, wallet, first.hook as (e: unknown) => void); + await (await agent.universal.sendTransaction({ to: SINK, value: BigInt(1) })).wait(); + expect(first.hasEvent('SEND-TX-105-01')).toBe(true); + const second = createProgressTracker(); + await (await agent.universal.sendTransaction({ to: SINK, value: BigInt(1) }, { progressHook: second.hook })).wait(); + expect(second.hasEvent('SEND-TX-105-01')).toBe(false); + f.evidence('first-use-uea', { wallet, uea }); + }, 900_000); + + it('3. a Solana-origin key acts through its Solana UEA on a Push destination', async () => { + const raw = process.env['SOLANA_PRIVATE_KEY']; + if (!raw) throw new Error('SOLANA_PRIVATE_KEY is required'); + const kp = Keypair.fromSecretKey(bs58.decode(raw)); + const uea = await ueaOf(kp.publicKey.toBase58(), CHAIN.SOLANA_DEVNET); + const wallet = await walletFor(uea); + const signer = await PushChain.utils.signer.toUniversalFromKeypair(kp, { + chain: CHAIN.SOLANA_DEVNET, + library: PushChain.CONSTANTS.LIBRARY.SOLANA_WEB3JS, + }); + const agent = await PushChain.initialize(signer, { network: f.manifest.network, agenticWallet: wallet }); + const tx = await agent.universal.sendTransaction({ to: SINK, value: BigInt(1) }); + expect((await tx.wait()).status).toBe(1); + expect(tx.from).toBe(wallet); + expect(tx.origin.startsWith('solana:')).toBe(true); + f.evidence('solana-origin-agent', { wallet, uea, tx: tx.hash }); + }, 600_000); +}); + diff --git a/packages/core/__e2e__/agw/lifecycle.spec.ts b/packages/core/__e2e__/agw/lifecycle.spec.ts new file mode 100644 index 00000000..42da2c05 --- /dev/null +++ b/packages/core/__e2e__/agw/lifecycle.spec.ts @@ -0,0 +1,73 @@ +/** + * Scenarios 5 and 6 — add / update / revoke lifecycle and checkpoint counts. + * A replacement is five checkpoint ticks; allowance pulls are not ticks. + * The stale-spend race (intervening agent spend) is verified against the + * real contracts in the local harness; it cannot be timed reliably live. + */ +import { e704d5b } from '../../src/lib/agentic/contracts/e704d5b'; +import { getAddress, parseEther, type Address, type Hex } from 'viem'; +import { AGENTIC_ERROR_CODE } from '../../src/lib/agentic/errors'; +import { AGW_E2E_ENABLED, inSeconds, setupAgw, type AgwFixture } from './_fixture'; + +const d = AGW_E2E_ENABLED ? describe : describe.skip; + +d('agw lifecycle', () => { + let f: AgwFixture; + let wallet: Address; + let original: Hex; + const sink = getAddress('0x000000000000000000000000000000000000dEaD'); + const rule = (maxValuePerCall: bigint) => ({ + agent: f.agentAddress, + target: sink, + selector: 'value-only' as const, + validUntil: inSeconds(3600), + maxValuePerCall, + maxValueTotal: maxValuePerCall * BigInt(10), + }); + const count = () => + f.push.readContract({ address: wallet, abi: e704d5b.abis.wallet, functionName: 'checkpointCount' }) as Promise; + + beforeAll(async () => { + f = await setupAgw(); + wallet = (await f.owner.agentic.create('e2e-lifecycle', { rules: [] })).wallet; + await f.fundPC(wallet, parseEther('0.01')); + }, 300_000); + afterAll(() => f?.teardown()); + + it('1. rules.add grants with one RULES_GRANTED checkpoint', async () => { + const before = await count(); + const added = await f.owner.agentic.wallet(wallet).rules.add([rule(BigInt(1000))]); + original = added.rulesIds[0]; + expect(await count()).toBe(before + BigInt(1)); + const { checkpoints } = await f.owner.agentic.wallet(wallet).checkpoints({ sinceBlock: added.tx.blockNumber }); + expect(checkpoints.at(-1)).toMatchObject({ kind: 'RULES_GRANTED', ref: original }); + }); + + it('2. rules.update: old ID disabled, new ID usable with reset counters, five checkpoint ticks', async () => { + const agent = await f.agent(wallet); + await (await agent.universal.sendTransaction({ to: sink, value: BigInt(10) })).wait(); + const spentBefore = (await f.owner.agentic.wallet(wallet).rules.get(original)).spent; + expect(spentBefore).toMatchObject({ kind: 'native', valueSpent: BigInt(10), callsUsed: 1 }); + const before = await count(); + const res = await f.owner.agentic.wallet(wallet).rules.update({ rules: [{ rulesId: original, rule: rule(BigInt(2000)) }] }); + expect(await count()).toBe(before + BigInt(5)); + const replacement = res.rules[0].rulesId; + expect(res.rules[0].replaced).toBe(original); + expect((await f.owner.agentic.wallet(wallet).rules.get(replacement)).spent).toMatchObject({ valueSpent: BigInt(0), callsUsed: 0 }); + await expect(f.owner.agentic.wallet(wallet).rules.get(original)).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.CAPABILITY_UNAVAILABLE }); + const tx = await agent.universal.sendTransaction({ to: sink, value: BigInt(1500) }); + expect(tx.agentic?.rulesId).toBe(replacement); + f.evidence('rules-update', { wallet, original, replacement, tx: res.tx.hash, checkpointDelta: 5 }); + }); + + it('3. checkpoint history is contiguous and matches checkpointCount()', async () => { + const { checkpoints } = await f.owner.agentic.wallet(wallet).checkpoints(); + expect(checkpoints.map((c) => c.seq)).toEqual(checkpoints.map((_, i) => i + 1)); + expect(BigInt(checkpoints.length)).toBe(await count()); + }); + + it('4. revoke({ all: true }) leaves no enabled rules', async () => { + await (await f.owner.agentic.wallet(wallet).rules.revoke({ all: true })).wait(); + expect((await f.owner.agentic.wallet(wallet).rules.list()).rules).toEqual([]); + }); +}); diff --git a/packages/core/__e2e__/agw/multi-asset-svm.spec.ts b/packages/core/__e2e__/agw/multi-asset-svm.spec.ts new file mode 100644 index 00000000..89ece828 --- /dev/null +++ b/packages/core/__e2e__/agw/multi-asset-svm.spec.ts @@ -0,0 +1,21 @@ +/** + * Scenario 11 — PENDING SPECIFICATION, not tests. These need artifacts that + * do not exist yet; they are recorded as `it.todo` (reported as todo, never as + * passes) and are not registered in the CI manifest. + * + * - Multi-asset universal rules: A05 (Harsh H4.2, Zaryab Z1.1/Z1.2) — wire + * format, per-token counters and expected-spend assertion ABI + vectors. + * - SVM destinations: A05/A07 + Harsh H4.4 — public rule shape, terms and + * payload fixtures, deployed capability; integrator obligations 19–23. + */ +const d = process.env['AGW_E2E'] === '1' ? describe : describe.skip; + +d('agw pending multi-asset and svm', () => { + it.todo('multi-asset: per-token maxPerCall/maxTotal enforced independently, in each token’s units'); + it.todo('multi-asset: omitted maxTotal is unlimited, explicit zero is zero'); + it.todo('multi-asset: duplicate assets rejected; empty assets[] routes call-only outbounds'); + it.todo('multi-asset: rules.update asserts every old-rule asset total atomically'); + it.todo('svm: wallet CEA PDA / token accounts derived from the wallet and registry gateway'); + it.todo('svm: program/discriminator allow-list and account/data pins enforced on a real destination'); + it.todo('svm: aggregator substitution and ratio floors rejected'); +}); diff --git a/packages/core/__e2e__/agw/native-exec.spec.ts b/packages/core/__e2e__/agw/native-exec.spec.ts new file mode 100644 index 00000000..7217c145 --- /dev/null +++ b/packages/core/__e2e__/agw/native-exec.spec.ts @@ -0,0 +1,101 @@ +/** + * Scenarios 3 and 4 — native owner and agent execution with independent + * state checks, and unauthorized / revoked / expired / over-cap failures with + * unchanged protected state. + */ +import { getAddress, parseEther, type Address, type Hex } from 'viem'; +import { privateKeyToAccount, generatePrivateKey } from 'viem/accounts'; +import { AgenticError, AgenticRevertError } from '../../src'; +import { CHAIN } from '../../src/lib/constants/enums'; +import { AGENTIC_ERROR_CODE } from '../../src/lib/agentic/errors'; +import { AGW_E2E_ENABLED, evmClient, inSeconds, setupAgw, type AgwFixture } from './_fixture'; + +const d = AGW_E2E_ENABLED ? describe : describe.skip; +const CAP = parseEther('0.001'); + +d('agw native', () => { + let f: AgwFixture; + let wallet: Address; + let rulesId: Hex; + const recipient = getAddress(privateKeyToAccount(generatePrivateKey()).address); + + beforeAll(async () => { + f = await setupAgw(); + const created = await f.owner.agentic.create('e2e-native', { + rules: [ + { + agent: f.agentAddress, + target: recipient, + selector: 'value-only', + validUntil: inSeconds(3600), + maxValuePerCall: CAP, + maxValueTotal: CAP * BigInt(3), + }, + ], + }); + wallet = created.wallet; + rulesId = created.rulesIds[0]; + await f.fundPC(wallet, parseEther('0.01')); + }, 300_000); + afterAll(() => f?.teardown()); + + it('1. agent door: value moves from the wallet under its rule; signer is origin, wallet is from', async () => { + const agent = await f.agent(wallet); + expect(agent.universal.account).toBe(wallet); + const before = await f.push.getBalance({ address: recipient }); + const tx = await agent.universal.sendTransaction({ to: recipient, value: CAP }); + const receipt = await tx.wait(); + expect(receipt.status).toBe(1); + expect(await f.push.getBalance({ address: recipient })).toBe(before + CAP); + expect(tx.from).toBe(wallet); + expect(receipt.from).toBe(wallet); + expect(tx.origin.toLowerCase()).toContain(f.agentAddress.toLowerCase()); + expect(tx.agentic).toMatchObject({ door: 'agent', rulesId }); + f.evidence('native-agent-send', { wallet, rulesId, tx: tx.hash, block: tx.blockNumber }); + }); + + it('2. owner door: value moves from the wallet without rules', async () => { + const owner = await evmClient(process.env['PUSH_PRIVATE_KEY'] as Hex, CHAIN.PUSH_TESTNET_DONUT, f.manifest.network, wallet); + const before = await f.push.getBalance({ address: recipient }); + const tx = await owner.universal.sendTransaction({ to: recipient, value: CAP * BigInt(2) }); + expect((await tx.wait()).status).toBe(1); + expect(await f.push.getBalance({ address: recipient })).toBe(before + CAP * BigInt(2)); + expect(tx.agentic?.door).toBe('owner'); + }); + + it('3. over-cap value reverts with the decoded policy gate and moves nothing', async () => { + const agent = await f.agent(wallet); + const before = await f.push.getBalance({ address: recipient }); + const err = await agent.universal.sendTransaction({ to: recipient, value: CAP + BigInt(1) }).catch((e) => e); + expect(err).toBeInstanceOf(AgenticRevertError); + expect(err.decodedError?.name).toMatch(/^PolicyCheckReverted/); + expect(await f.push.getBalance({ address: recipient })).toBe(before); + }); + + it('4. an unrelated signer cannot initialize against the wallet', async () => { + const stranger = generatePrivateKey(); + await expect(evmClient(stranger, CHAIN.PUSH_TESTNET_DONUT, f.manifest.network, wallet)).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.NOT_OWNER_OR_AGENT, + }); + }); + + it('5. after revocation the agent fails before signing with NO_RULES_FOR_CHAIN', async () => { + const agent = await f.agent(wallet); + await (await f.owner.agentic.wallet(wallet).rules.revoke([rulesId])).wait(); + const err = await agent.universal.sendTransaction({ to: recipient, value: BigInt(1) }).catch((e) => e); + expect(err).toBeInstanceOf(AgenticError); + expect(err.code).toBe(AGENTIC_ERROR_CODE.NO_RULES_FOR_CHAIN); + }); + + it('6. an expired rule still identifies the agent; the send is refused on-chain', async () => { + const created = await f.owner.agentic.create('e2e-expiry', { + rules: [{ agent: f.agentAddress, target: recipient, selector: 'value-only', validUntil: inSeconds(45), maxValuePerCall: CAP, maxValueTotal: CAP }], + }); + await f.fundPC(created.wallet, CAP * BigInt(2)); + await new Promise((r) => setTimeout(r, 60_000)); + const agent = await f.agent(created.wallet); + const err = await agent.universal.sendTransaction({ to: recipient, value: BigInt(1) }).catch((e) => e); + expect(err).toBeInstanceOf(AgenticRevertError); + expect(err.decodedError?.name).toBe('PolicyCheckReverted(RulesExpired)'); + }, 300_000); +}); diff --git a/packages/core/__e2e__/agw/responses-hooks.spec.ts b/packages/core/__e2e__/agw/responses-hooks.spec.ts new file mode 100644 index 00000000..b026a005 --- /dev/null +++ b/packages/core/__e2e__/agw/responses-hooks.spec.ts @@ -0,0 +1,51 @@ +/** + * Scenario 10 — init-time and per-call hooks through wait without + * duplicates, and AGW `from` / signer `origin` on live and replayed + * responses. + */ +import { getAddress, parseEther, type Address } from 'viem'; +import type { ProgressEvent } from '../../src/lib/progress-hook/progress-hook.types'; +import { AGW_E2E_ENABLED, inSeconds, setupAgw, type AgwFixture } from './_fixture'; + +const d = AGW_E2E_ENABLED ? describe : describe.skip; +const SINK = getAddress('0x000000000000000000000000000000000000dEaD'); + +d('agw responses', () => { + let f: AgwFixture; + let wallet: Address; + beforeAll(async () => { + f = await setupAgw(); + const created = await f.owner.agentic.create('e2e-hooks', { + rules: [{ agent: f.agentAddress, target: SINK, selector: 'value-only', validUntil: inSeconds(3600), maxValuePerCall: BigInt(10), maxValueTotal: BigInt(100) }], + }); + wallet = created.wallet; + await f.fundPC(wallet, parseEther('0.001')); + }, 300_000); + afterAll(() => f?.teardown()); + + it('1. init and per-call hooks each see every event once, through wait', async () => { + const init: ProgressEvent[] = []; + const perCall: ProgressEvent[] = []; + const agent = await f.agent(wallet, (e) => init.push(e as ProgressEvent)); + const tx = await agent.universal.sendTransaction({ to: SINK, value: BigInt(1) }, { progressHook: (e) => perCall.push(e) }); + await tx.wait(); + const ids = (xs: ProgressEvent[]) => xs.map((e) => e.id); + expect(ids(perCall)).toEqual(ids(init)); + expect(new Set(ids(perCall).filter((i) => i.startsWith('AGENTIC-TX'))).size).toBe(ids(perCall).filter((i) => i.startsWith('AGENTIC-TX')).length); + expect(ids(perCall)).toEqual(expect.arrayContaining(['AGENTIC-TX-107', 'AGENTIC-TX-199-01', 'SEND-TX-199-01'])); + expect(ids(perCall)).not.toContain('AGENTIC-TX-103'); + }); + + it('2. live and replayed responses agree on wallet from and signer origin', async () => { + const agent = await f.agent(wallet); + const tx = await agent.universal.sendTransaction({ to: SINK, value: BigInt(1) }); + await tx.wait(); + const replay = await f.owner.universal.trackTransaction(tx.hash); + expect(replay.from).toBe(tx.from); + expect(replay.from).toBe(wallet); + expect(replay.origin).toBe(tx.origin); + expect(replay.to).toBe(SINK); + expect((await replay.wait()).from).toBe(wallet); + f.evidence('replay-identity', { wallet, tx: tx.hash }); + }); +}); diff --git a/packages/core/__e2e__/agw/universal-evm.spec.ts b/packages/core/__e2e__/agw/universal-evm.spec.ts new file mode 100644 index 00000000..3d196be5 --- /dev/null +++ b/packages/core/__e2e__/agw/universal-evm.spec.ts @@ -0,0 +1,136 @@ +/** + * Scenarios 7 and 8 — positive-amount EVM universal execution from the + * wallet, and destination failure classification. + * + * SETUP NOTE: the public UniversalRule (assets[]) has no matching wire format + * yet (A05), so the universal rule is granted here as fixture setup through + * the owner's ordinary client with the generation's historical single-asset + * terms. The behaviour under test — the agent's sendTransaction, the gateway + * pull/burn, the AGW's CEA executing on Sepolia, receipts and replay — goes + * through public SDK methods only. + * + * creditRevert accounting is inert on the current executor (gap G07): a + * destination revert after URP passed still counts the spend. + */ +import { createPublicClient, encodeFunctionData, erc20Abi, http, parseEther, type Address, type Hex } from 'viem'; +import { sepolia } from 'viem/chains'; +import { CHAIN } from '../../src/lib/constants/enums'; +import { MOVEABLE_TOKEN_CONSTANTS } from '../../src/lib/constants/tokens'; +import { getCEAAddress } from '../../src/lib/orchestrator/cea-utils'; +import { getNativePRC20ForChain } from '../../src/lib/orchestrator/internals/helpers'; +import { e704d5b } from '../../src/lib/agentic/contracts/e704d5b'; +import { buildSession, encodeEnvelope } from '../../src/lib/agentic/codec/session'; +import { encodeUniversalTermsE704d5b } from '../../src/lib/agentic/codec/historical/e704d5b-universal'; +import { EVM_CHAIN_FIXTURES } from '@e2e/shared/chain-fixtures'; +import { COUNTER_ABI } from '@e2e/shared/outbound-helpers'; +import { verifyExternalTransaction } from '@e2e/shared/external-tx-verifier'; +import { AGW_E2E_ENABLED, evmClient, inSeconds, setupAgw, type AgwFixture } from './_fixture'; + +const d = AGW_E2E_ENABLED ? describe : describe.skip; +const SEPOLIA = CHAIN.ETHEREUM_SEPOLIA; +const counter = EVM_CHAIN_FIXTURES.find((x) => x.chain === SEPOLIA)!.contracts.counter as Address; +const INCREMENT = '0xd09de08a' as Hex; +const MISSING = '0xdeadbeef' as Hex; // not implemented by the counter → destination revert +const AMOUNT = BigInt(10) ** BigInt(12); // 0.000001 pETH +const MAX_PC = parseEther(process.env['AGW_E2E_MAX_PC_PER_CALL'] ?? '20'); + +d('agw universal evm', () => { + let f: AgwFixture; + let wallet: Address; + let token: Address; + let rulesId: Hex; + let cea: Address; + + beforeAll(async () => { + f = await setupAgw(); + wallet = (await f.owner.agentic.create('e2e-universal', { rules: [] })).wallet; + token = getNativePRC20ForChain(SEPOLIA, f.manifest.network); + cea = (await getCEAAddress(wallet, SEPOLIA)).cea as Address; + // Fixture: historical single-asset universal grant (see header). + const session = buildSession({ + validator: f.manifest.addresses.sessionValidator, + agent: f.agentAddress, + rulesPolicy: f.manifest.addresses.rulesPolicy, + actions: [ + { + target: f.manifest.addresses.gateway, + selector: '0x77b86bec', + initData: encodeEnvelope( + SEPOLIA, + encodeUniversalTermsE704d5b({ + validUntil: inSeconds(3600), + expectedCEA: cea, + asset: token, + maxAmountPerCall: AMOUNT * BigInt(2), + maxAmountTotal: AMOUNT * BigInt(10), + maxPCPerCall: MAX_PC, + allowedCalls: [ + { target: counter, selector: INCREMENT, beneficiaryOffset: 0, hasBeneficiary: false, maxValue: BigInt(0) }, + { target: counter, selector: MISSING, beneficiaryOffset: 0, hasBeneficiary: false, maxValue: BigInt(0) }, + ], + }) + ), + }, + ], + }); + await (await f.owner.universal.sendTransaction({ to: wallet, data: e704d5b.encodeGrantRules(session) })).wait(); + [rulesId] = (await f.push.readContract({ + address: f.manifest.addresses.sessionEngine, + abi: e704d5b.abis.engine, + functionName: 'getPermissionIDs', + args: [wallet], + })) as Hex[]; + // Separate funding: wallet PC for outbound fees and pETH to burn. + await f.fundPC(wallet, MAX_PC + parseEther('1')); + await ( + await f.owner.universal.sendTransaction({ + to: token, + data: encodeFunctionData({ abi: erc20Abi, functionName: 'transfer', args: [wallet, AMOUNT * BigInt(3)] }), + }) + ).wait(); + // Bounded allowance through the owner door. + const ownerAgw = await evmClient(process.env['PUSH_PRIVATE_KEY'] as Hex, CHAIN.PUSH_TESTNET_DONUT, f.manifest.network, wallet); + await ( + await ownerAgw.universal.sendTransaction({ + to: token, + data: encodeFunctionData({ abi: erc20Abi, functionName: 'approve', args: [f.manifest.addresses.gateway, AMOUNT * BigInt(2)] }), + }) + ).wait(); + }, 900_000); + afterAll(() => f?.teardown()); + + it('1. positive-amount outbound: allowance pull/burn, the wallet CEA executes on Sepolia, receipts and replay identity', async () => { + const sep = createPublicClient({ chain: sepolia, transport: http() }); + const countBefore = (await sep.readContract({ address: counter, abi: COUNTER_ABI, functionName: 'count' })) as bigint; + const balBefore = await f.push.readContract({ address: token, abi: erc20Abi, functionName: 'balanceOf', args: [wallet] }); + const agent = await f.agent(wallet); + const tx = await agent.universal.sendTransaction({ + to: { address: counter, chain: SEPOLIA }, + data: INCREMENT, + funds: { amount: AMOUNT, token: MOVEABLE_TOKEN_CONSTANTS.ETHEREUM_SEPOLIA.ETH }, + }); + expect(tx).toMatchObject({ from: wallet, route: 'UOA_TO_CEA' }); + expect(tx.agentic).toMatchObject({ door: 'agent', rulesId, destinationAccount: cea }); + const receipt = await tx.wait({ outboundTimeoutMs: 600_000 }); + expect(receipt.status).toBe(1); + expect(receipt.from).toBe(wallet); + expect(receipt.externalTxHash).toBeTruthy(); + await verifyExternalTransaction(receipt.externalTxHash as string, SEPOLIA); + expect(await f.push.readContract({ address: token, abi: erc20Abi, functionName: 'balanceOf', args: [wallet] })).toBe(balBefore - AMOUNT); + expect(await f.push.readContract({ address: token, abi: erc20Abi, functionName: 'allowance', args: [wallet, f.manifest.addresses.gateway] })).toBe(AMOUNT); + expect((await sep.readContract({ address: counter, abi: COUNTER_ABI, functionName: 'count' })) as bigint).toBeGreaterThan(countBefore); + const replay = await f.owner.universal.trackTransaction(tx.hash); + expect(replay.from).toBe(wallet); + expect(replay.agentic).toMatchObject({ door: 'agent', rulesId }); + f.evidence('universal-outbound', { wallet, cea, rulesId, pushTx: tx.hash, externalTx: receipt.externalTxHash, amount: AMOUNT }); + }, 900_000); + + it('2. destination revert is classified on the receipt; the Push leg succeeded', async () => { + const agent = await f.agent(wallet); + const tx = await agent.universal.sendTransaction({ to: { address: counter, chain: SEPOLIA }, data: MISSING }); + const receipt = await tx.wait({ outboundTimeoutMs: 600_000 }); + expect(receipt.status).toBe(1); + expect(receipt.externalStatus).toMatch(/fail|revert/i); + f.evidence('universal-destination-revert', { wallet, pushTx: tx.hash, externalStatus: receipt.externalStatus }); + }, 900_000); +}); diff --git a/packages/core/__e2e__/ci/preflight.ts b/packages/core/__e2e__/ci/preflight.ts index 405ea41f..757fd8a2 100644 --- a/packages/core/__e2e__/ci/preflight.ts +++ b/packages/core/__e2e__/ci/preflight.ts @@ -64,6 +64,7 @@ import { deriveAtaPubkey, } from '../../src/lib/orchestrator/internals/svm-rent'; import { scenariosFor, aggregateNeeds, type Asset } from './suite'; +import { loadAgwManifest, verifyAgwManifest } from '../agw/_manifest'; // --------------------------------------------------------------------------- // tunables @@ -326,6 +327,21 @@ function renderTable(rows: Row[]): void { chain: pushChainDef, transport: fallback(pushRpcs.map((u) => http(u))), }) as PublicClient; + + // -- AGW gate ------------------------------------------------------------ + // The agw group needs a verified compatible AGW deployment (plan/agw A07). + // Check it read-only BEFORE any balance work so nothing is ever funded for + // a run that cannot exercise a real deployment. + if (scenarios.some((s) => s.group === 'agw')) { + try { + await verifyAgwManifest(push, loadAgwManifest()); + console.log('AGW deployment manifest verified on-chain.'); + } catch (err) { + console.error(`\n${(err as Error).message}`); + console.error('No transactions were sent.'); + process.exit(1); + } + } const pushWallet = createWalletClient({ account: pushAcc, chain: pushChainDef, diff --git a/packages/core/__e2e__/ci/run.ts b/packages/core/__e2e__/ci/run.ts index 33d1ae10..25174e0a 100644 --- a/packages/core/__e2e__/ci/run.ts +++ b/packages/core/__e2e__/ci/run.ts @@ -6,8 +6,10 @@ * npx ts-node --transpile-only __e2e__/ci/run.ts [options] * * --group One of: all (default), smoke, evm-r1, evm-r2, evm-r3, - * svm-r1, svm-r2r3, pc20, push, cross-chain, known-fail - * (`all` excludes known-fail — ask for it by name) + * svm-r1, svm-r2r3, pc20, push, cross-chain, read, + * known-fail, agw + * (`all` excludes known-fail and agw — ask for them by name; + * agw needs AGW_DEPLOYMENT_MANIFEST, see __e2e__/agw/_manifest.ts) * --list Print the selection and the jest argv, run nothing * --verify Check every `grep` against the real spec titles and exit * non-zero if any fragment matches 0 or >1 tests in its file diff --git a/packages/core/__e2e__/ci/suite.ts b/packages/core/__e2e__/ci/suite.ts index 71ff5966..cb121fe8 100644 --- a/packages/core/__e2e__/ci/suite.ts +++ b/packages/core/__e2e__/ci/suite.ts @@ -34,6 +34,7 @@ export const GROUPS = [ 'cross-chain', 'read', 'known-fail', + 'agw', ] as const; export type Group = (typeof GROUPS)[number]; @@ -149,6 +150,13 @@ const F = { readSvmIdl: '__e2e__/read/svm/account-idl.spec.ts', readMutability: '__e2e__/read/evm/any-mutability.spec.ts', readTrackLookup: '__e2e__/read/lifecycle/track-lookup.spec.ts', + agwCreate: '__e2e__/agw/create.spec.ts', + agwFunding: '__e2e__/agw/funding-allowance.spec.ts', + agwNative: '__e2e__/agw/native-exec.spec.ts', + agwLifecycle: '__e2e__/agw/lifecycle.spec.ts', + agwUniversal: '__e2e__/agw/universal-evm.spec.ts', + agwIdentity: '__e2e__/agw/identity-gas.spec.ts', + agwResponses: '__e2e__/agw/responses-hooks.spec.ts', } as const; export const SCENARIOS: Scenario[] = [ @@ -753,15 +761,193 @@ export const SCENARIOS: Scenario[] = [ '(balance - reserve, the pre-fix behaviour) where the test expects the full ' + '~20.9 PC requirement. Real regression in the Route 2 dead-zone gas sizer.', }, + + // ------------------------------------------------------------------------- + // agw — agentic wallets. EXCLUDED from `all`: every spec's beforeAll fails + // its prerequisite gate until a verified compatible AGW deployment manifest + // (AGW_DEPLOYMENT_MANIFEST) exists — plan/agw assumption A07. Preflight + // refuses to fund the group without it. Budgets are per run: the Push master + // (owner) pays setup gas, wallet PC and the bounded fresh-agent funding; + // the EVM master's UEA pays external-agent gas; pETH funds the outbound. + // ------------------------------------------------------------------------- + { + id: 'agw-create-bare', + group: 'agw', + file: F.agwCreate, + grep: 'agw create 1\\. bare wallet', + needs: { masterPC: '2' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-create-rules', + group: 'agw', + file: F.agwCreate, + grep: 'agw create 2\\. wallet with a native rule', + needs: { masterPC: '2' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-funding-pc', + group: 'agw', + file: F.agwFunding, + grep: 'agw funding 1\\. wallet PC', + needs: { masterPC: '1' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-funding-allowance', + group: 'agw', + file: F.agwFunding, + grep: 'agw funding 2\\. owner sets and removes', + needs: { masterPC: '1' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-native-agent', + group: 'agw', + file: F.agwNative, + grep: 'agw native 1\\. agent door', + needs: { masterPC: '2' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-native-owner', + group: 'agw', + file: F.agwNative, + grep: 'agw native 2\\. owner door', + needs: { masterPC: '0.5' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-native-over-cap', + group: 'agw', + file: F.agwNative, + grep: 'agw native 3\\. over-cap', + needs: { masterPC: '0.5' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-native-stranger', + group: 'agw', + file: F.agwNative, + grep: 'agw native 4\\. an unrelated signer', + needs: { masterPC: '0.1' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-native-revoked', + group: 'agw', + file: F.agwNative, + grep: 'agw native 5\\. after revocation', + needs: { masterPC: '0.5' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-native-expired', + group: 'agw', + file: F.agwNative, + grep: 'agw native 6\\. an expired rule', + needs: { masterPC: '1' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-lifecycle-add', + group: 'agw', + file: F.agwLifecycle, + grep: 'agw lifecycle 1\\. rules\\.add', + needs: { masterPC: '2' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-lifecycle-update', + group: 'agw', + file: F.agwLifecycle, + grep: 'agw lifecycle 2\\. rules\\.update', + needs: { masterPC: '1' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-lifecycle-checkpoints', + group: 'agw', + file: F.agwLifecycle, + grep: 'agw lifecycle 3\\. checkpoint history', + needs: { masterPC: '0.1' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-lifecycle-revoke-all', + group: 'agw', + file: F.agwLifecycle, + grep: 'agw lifecycle 4\\. revoke', + needs: { masterPC: '0.5' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-universal-outbound', + group: 'agw', + file: F.agwUniversal, + grep: 'agw universal evm 1\\. positive-amount outbound', + needs: { masterPC: '25', masterPETH: '0.00001' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-universal-dest-revert', + group: 'agw', + file: F.agwUniversal, + grep: 'agw universal evm 2\\. destination revert', + needs: { masterPC: '5' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-identity-evm', + group: 'agw', + file: F.agwIdentity, + grep: 'agw identity 1\\. an EVM key on Sepolia', + needs: { masterPC: '1', ueaPC: '1' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-identity-first-use', + group: 'agw', + file: F.agwIdentity, + grep: 'agw identity 2\\. first use', + needs: { masterPC: '1', sepoliaEth: '0.003' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-identity-solana', + group: 'agw', + file: F.agwIdentity, + grep: 'agw identity 3\\. a Solana-origin key', + needs: { masterPC: '1' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-responses-hooks', + group: 'agw', + file: F.agwResponses, + grep: 'agw responses 1\\. init and per-call hooks', + needs: { masterPC: '1' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-responses-replay', + group: 'agw', + file: F.agwResponses, + grep: 'agw responses 2\\. live and replayed', + needs: { masterPC: '0.5' }, + env: { AGW_E2E: '1' }, + }, ]; /** * Scenarios for a group. `all` means "everything that should pass" — it deliberately - * excludes `known-fail`, which has to be asked for by name. + * excludes `known-fail` and `agw`, which have to be asked for by name. */ export function scenariosFor(group: string | undefined): Scenario[] { if (!group || group === 'all') { - return SCENARIOS.filter((s) => s.group !== 'known-fail'); + // `agw` is opt-in until a verified AGW deployment exists (plan/agw A07). + return SCENARIOS.filter((s) => s.group !== 'known-fail' && s.group !== 'agw'); } if (!(GROUPS as readonly string[]).includes(group)) { throw new Error( From fa90b2affd8079be108210296bd7a79f087de69e Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Sat, 3 Oct 2026 19:48:38 +0530 Subject: [PATCH 09/68] fix(agw): grant several rules in one atomic owner batch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rules.add with more than one rule went through the signer's batch, which on a Push EOA without EIP-7702 degrades to separate, non-atomic transactions — contradicting "grants new rules under one signature" (spec 1.k) and plan step 7.5 ("batches grants through the existing owner wallet"). Several rules now go through one owner execute batch of self-calls; a single rule stays a direct grant. Each batched grant ticks OWNER_ACTION before RULES_GRANTED, verified against the real contracts in the local harness. --- .../__agw-local__/agw-local-advanced.spec.ts | 19 ++++++++++++++++++ .../lib/agentic/__tests__/management.spec.ts | 19 ++++++++++++++++++ .../src/lib/agentic/management/rules-write.ts | 20 ++++++++++++++----- 3 files changed, 53 insertions(+), 5 deletions(-) diff --git a/packages/core/__agw-local__/agw-local-advanced.spec.ts b/packages/core/__agw-local__/agw-local-advanced.spec.ts index e05cf621..07fc7a86 100644 --- a/packages/core/__agw-local__/agw-local-advanced.spec.ts +++ b/packages/core/__agw-local__/agw-local-advanced.spec.ts @@ -225,6 +225,25 @@ describe('AGW advanced paths against real e704d5b contracts', () => { const { rules } = await owner.agentic.wallet(wallet).rules.list(); expect(rules).toHaveLength(2); }); + + it('rules.add with several rules is one atomic owner batch: OWNER_ACTION + RULES_GRANTED per rule', async () => { + const created = await owner.agentic.create('multi-add', { rules: [] }); + const before = await h.publicClient.readContract({ + address: created.wallet, + abi: parseAbi(['function checkpointCount() view returns (uint64)']), + functionName: 'checkpointCount', + }); + const added = await owner.agentic.wallet(created.wallet).rules.add([ + { agent: agentAddr, target: h.addresses.target, selector: 'increment()', validUntil: (await chainNow(h)) + 3600 }, + { agent: h.wallets[3].account!.address, target: h.addresses.target, selector: 'increment()', validUntil: (await chainNow(h)) + 3600 }, + ]); + expect(added.rulesIds).toHaveLength(2); + expect(added.tx.atomic).toBe(true); + const { checkpoints } = await owner.agentic.wallet(created.wallet).checkpoints({ sinceBlock: added.tx.blockNumber }); + expect(BigInt(checkpoints.length)).toBe(BigInt(4)); + expect(checkpoints.map((c) => c.kind)).toEqual(['OWNER_ACTION', 'RULES_GRANTED', 'OWNER_ACTION', 'RULES_GRANTED']); + expect(before).toBe(BigInt(0)); + }); }); describe('agent EVM outbound (historical single-asset terms, stub gateway)', () => { diff --git a/packages/core/src/lib/agentic/__tests__/management.spec.ts b/packages/core/src/lib/agentic/__tests__/management.spec.ts index cafd96a8..2cfe1fa9 100644 --- a/packages/core/src/lib/agentic/__tests__/management.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/management.spec.ts @@ -171,6 +171,25 @@ describe('rules.add / rules.revoke', () => { expect((await addRules(rt, gen(), w.address, [rule(ADDR.other)])).rulesIds).toEqual([expected]); }); + it('add: several rules are one atomic owner execute batch (one signature on any signer)', async () => { + const fake = new FakeChain(); + const w = fake.addWallet(ADDR.owner, 'w'); + const ids = [ADDR.agent, ADDR.other].map((agent, i) => + computeRulesId({ validator: ADDR.validator, agent, grantNonce: BigInt(i) }) + ); + const rt = mockRuntime(fake, { + signer: ADDR.owner, + execute: (async () => withLogs([granted(w.address, ids[0]), granted(w.address, ids[1])])) as never, + }); + const exec = jest.spyOn(rt, 'execute'); + expect((await addRules(rt, gen(), w.address, [rule(), rule(ADDR.other)])).rulesIds).toEqual(ids); + const sent = exec.mock.calls[0][0] as { to: string; data: Hex }; + expect(Array.isArray(sent.data)).toBe(false); + const outer = e704d5b.decodeWalletCall(sent.data) as { kind: string; calls: { target: string; data: Hex }[] }; + expect(outer.kind).toBe('execute'); + expect(outer.calls.map((c) => decodeFunctionData({ abi: AGW_ABI, data: c.data }).functionName)).toEqual(['grantRules', 'grantRules']); + }); + it('revoke: bare and empty are refused; unknown IDs fail before signing; several IDs are one atomic owner execute', async () => { const fake = new FakeChain(); const w = fake.addWallet(ADDR.owner, 'w', [fake.nativeRule(ADDR.agent, ruleId(1)), fake.nativeRule(ADDR.other, ruleId(2))]); diff --git a/packages/core/src/lib/agentic/management/rules-write.ts b/packages/core/src/lib/agentic/management/rules-write.ts index 7523bf09..2f1a01b2 100644 --- a/packages/core/src/lib/agentic/management/rules-write.ts +++ b/packages/core/src/lib/agentic/management/rules-write.ts @@ -93,11 +93,21 @@ export async function addRules( const predicted = prepared.map((p, i) => computeRulesId({ validator: gen.addresses.sessionValidator, agent: p.agent, grantNonce: nonce + BigInt(i) }) ); - const calls: MultiCall[] = prepared.map((p) => ({ - to: wallet, - value: BigInt(0), - data: gen.contracts.encodeGrantRules(p.session), - })); + // One rule: a direct owner grant (one RULES_GRANTED tick). Several: one + // owner `execute` batch of self-calls, so the grants are atomic and need a + // single signature on every signer type (each grant then also ticks one + // OWNER_ACTION before its RULES_GRANTED). + const grants = prepared.map((p) => gen.contracts.encodeGrantRules(p.session)); + const calls: MultiCall[] = + grants.length === 1 + ? [{ to: wallet, value: BigInt(0), data: grants[0] }] + : [ + { + to: wallet, + value: BigInt(0), + data: gen.contracts.encodeExecute(grants.map((data) => ({ target: wallet, value: BigInt(0), data }))), + }, + ]; return finish(runtime, hook, 'rules.add', async () => { const tx = await sendOwnerCalls(runtime, calls, hook); const { logs } = await confirmedLogs(runtime, tx); From 3008497b2492a6be78300011d4572076414505bf Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Sat, 3 Oct 2026 19:51:05 +0530 Subject: [PATCH 10/68] docs(agw): implementation status matrix and review handoff MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds the per-step status (unit / local real-contract / live) with A01–A08 design and artifact status, and the review handoff: revisions, changed modules, public behaviour with its authority, exact commands and counts, real-contract versus mock evidence, blockers and review hotspots. Commits the implementation agent prompt the work followed and links both documents from the planning README. No live AGW run occurred (A07). --- plan/agw/README.md | 5 +- plan/agw/implementation-agent-prompt.md | 214 ++++++++++++++++++++++ plan/agw/implementation-review-handoff.md | 161 ++++++++++++++++ plan/agw/implementation-status.md | 52 ++++++ 4 files changed, 431 insertions(+), 1 deletion(-) create mode 100644 plan/agw/implementation-agent-prompt.md create mode 100644 plan/agw/implementation-review-handoff.md create mode 100644 plan/agw/implementation-status.md diff --git a/plan/agw/README.md b/plan/agw/README.md index b2c90bf8..f3f0933b 100644 --- a/plan/agw/README.md +++ b/plan/agw/README.md @@ -1,6 +1,6 @@ # AGW SDK planning -This package contains the current SDK plan, source snapshots, open decisions and contract validation evidence. Production implementation has not started. Question drafts are unsent. +This package contains the current SDK plan, source snapshots, open decisions and contract validation evidence. Implementation of the unblocked steps is on branch `feat/agw-sdk-impl`; see [implementation status](implementation-status.md) and the [review handoff](implementation-review-handoff.md). No live AGW transaction has been sent: no compatible deployment exists (A07). Question drafts are unsent. The target API is [Notion page 5](notion/5-sdk-agw.md), exported October 3, 2026 at 13:23 IST. The tested contract baseline is pushAgenticWallet_v3@e704d5b: sender-authorized execution and checkpoints exist in source, while the new multi-asset format, grant reference, editable label and envelope version still require matching artifacts and deployment verification. @@ -13,6 +13,9 @@ The target API is [Notion page 5](notion/5-sdk-agw.md), exported October 3, 2026 | [Gap register](gaps.md) | Current G01–G24 findings and closure criteria | | [SDK owned review](sdk-owned-review.md) | Internal decisions, existing-code evidence and 183 passing unit tests | | [Implementation plan](implementation-plan.md) | Complete 17-step roadmap, module layout, assumptions, API coverage and PR sequence | +| [Implementation agent prompt](implementation-agent-prompt.md) | Handoff instructions, unit/E2E requirements and existing runner conventions | +| [Implementation status](implementation-status.md) | Per-step matrix (unit / local real-contract / live) and A01–A08 status | +| [Implementation review handoff](implementation-review-handoff.md) | Revisions, changed modules, commands and counts, real-vs-mock evidence, review hotspots | | [Interactive tutorial](agw-tutorial.html) | Account, rule, funding and execution diagrams; open in a browser | | [Integrator obligations](contract-integrator-obligations.md) | Contract-delegated SDK/product requirements | | [External blockers](external-blockers.md) | Seven remaining decision/dependency areas after local closure | diff --git a/plan/agw/implementation-agent-prompt.md b/plan/agw/implementation-agent-prompt.md new file mode 100644 index 00000000..45e8c7e5 --- /dev/null +++ b/plan/agw/implementation-agent-prompt.md @@ -0,0 +1,214 @@ +# AGW SDK implementation agent handoff + +Copy the prompt below into the implementation agent. It authorizes implementation and local validation of the settled work, plus E2E test development. Product/contract decisions remain tracked dependencies. Another agent will review the resulting implementation. + +--- + +You are implementing AGW support in the Push Chain SDK. Work through the implementation plan and complete as much verified, useful implementation as possible while product and contract answers are pending. Implement the code, add meaningful unit tests and E2E scenarios, run the appropriate available checks, and leave a precise review handoff. Do not stop after producing a plan or an empty namespace. + +## Workspace and starting point + +SDK repository: +`/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk` + +Sibling repositories: +- `/Users/shoaibmohammed/Desktop/work/PUSH/push-agentic-wallets` +- `/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-core-contracts` +- `/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-gateway-contracts` + +Planning branch: `feat/agw-sdk-planning`, last committed planning baseline `349635b2254823488603b37f4b44c4f5c929feb9`. This handoff file may be a subsequent local addition. Inspect status before changing branches. Preserve existing work and applicable repository instructions. Use a separate feature branch or isolated worktree based on the planning branch; do not reset or overwrite another agent's changes. Do not merge, publish packages or send team messages as part of this task. + +The sibling AGW working checkout may be on old main (`9ddd954`). Use the intended revision, not whatever happens to be checked out. Our reviewed AGW source is `pushAgenticWallet_v3@e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9`; core marketplace is `cb69e0ba101bef1bb4440e54b2c45396be3e92ce`; gateway is `bcbf7df42e8e6dd11088a43bcc0b056a54ea0a18`. Recheck remote refs and record any drift. Read changed source before revising conclusions. Historical Donut addresses are not a deployment of the target ABI. + +## Read before coding + +Read these in order under `plan/agw/`: + +1. `README.md`, `current-baseline.md`, `SOURCES.md`. +2. `notion/5-sdk-agw.md` — authoritative target public SDK API. +3. `implementation-plan.md` — full 17-step plan, proposed modules and acceptance criteria. +4. `sdk-design-review.md`, `sdk-owned-review.md`. +5. `external-blockers.md`, `questions-harsh.md`, `questions-zaryab.md`. +6. `contract-integrator-obligations.md`, `gaps.md`. +7. `research/sdk-owned-review-2026-10-03/README.md` and `research/validation-e704d5b/README.md`. + +Read pinned AGW `docs/1_AGW.md`, `docs/2_UniversalRulesPolicy.md` and exact source when implementing a consequential contract interaction. The public target wins over historical behavior, but a target feature cannot be presented as usable against an incompatible ABI. + +Notion snapshots were exported October 3, 2026 at 13:23 IST. Later edits are not included. Check whether answers or refreshed snapshots have been added to the workspace; consume confirmed answers and record their source. Do not invent product approval. + +## Implementation objective and stopping boundary + +Start with namespace/types, signer-versus-wallet context, lifecycle/read-only guards, contract adapter interfaces and generation handling. Continue through wallet reads, settled identity utilities, creation/recovery structure, native/owner wrappers, response/error/hook adaptation and independent Web2 compatibility where inputs are available. Use the plan's dependency ordering. + +For each unresolved feature, isolate the dependency and continue independent work. Do not stop the entire implementation because deployment or multi-asset encoding is pending. Conversely, scaffolding that throws an unsupported-feature error is not a completed codec or live feature. + +A01–A08 are explicitly tracked in the plan: + +- Product policy/default/type assumptions remain provisional until confirmed. +- A05 needs final multi-asset terms, per-token read and expected-spend assertion ABIs/vectors. +- A06 needs agreed historical-rule scope and reliable metadata. +- A07 needs matching source/metadata capabilities and an actual verified deployment manifest. +- A08 needs canonical card schema/encoding and shared compiler vectors; it is separate from basic AGW execution. +- SVM destination scope and representable public rules require explicit matching capabilities; Solana-origin identity is a different concern. + +Use explicit internal capabilities and fail before signing for missing artifacts or unsupported behavior. Do not insert fake addresses, guessed envelope layouts, success-shaped placeholder results or `any` escapes into the published surface. Do not convert assets[] to a single asset silently. Keep historical single-asset code/vectors explicitly versioned and out of the advertised target path. + +Implement all currently unblocked work, then report exact remaining dependencies. Full-feature release is not required while external artifacts are unavailable. Production contract changes are outside this SDK task; review-only local fixtures are permitted. + +## Architecture and invariants + +Follow the proposed modules in the implementation plan and the existing SDK conventions. Keep AGW contract/version logic centralized, and preserve ordinary-client behavior. + +1. Keep signer origin, signer Push identity and AGW execution address distinct. `universal.account` becomes AGW in agentic mode; `universal.origin` and account-status/gas identity remain signer-scoped. +2. `client.agentic.wallet(address)` is a management handle. It does not silently change the execution account. +3. Derive/list/create owner wallets from the connected signer's Push identity. External EVM or Solana keys use the UEA for their actual origin chain. +4. The owner uses execute. An agent uses executeAsAgent under a matching enabled rule. Do not implement the retired session-key signature model or fork SmartSession. +5. Resolve rules on every send. Zero candidates fails before signing; multiple enabled candidates fail explicitly. Do not filter expiry and thereby move the specified on-chain failure into an invented SDK policy engine. +6. Read-only clients never sign. Reinitialize requires explicit AGW selection under our recorded design and reruns role/capability checks. Audit all transaction-producing entry points, not just sendTransaction. +7. Create deploys/grants only; funding and approvals are separate. Preserve atomic/sequential strategy, confirmed hashes, pending hash and recoverable partial state. Do not automatically deploy another wallet after a grant failure. +8. Existing-wallet replacement must be one owner-wallet batch: assert expected spend → revoke → grant. Never fall back to sequential execution. Preserve counter-reset semantics and verify stale-spend rollback with the final ABI. +9. Gateway allowance setup uses bounded owner execute calls, with replenishment/removal. Do not inject an approval into the universal agent path. +10. Compose AGW outbounds explicitly. Under the pinned policy: empty EVM recipient bytes, AGW refund recipient, nonzero maxPCForGas and policy-compatible multicall. Resolve CEA from AGW, not from the signer. Keep wallet PC separate from signer gas. +11. Generate beneficiary/pin offsets from representable ABI layouts. Resolve destination tokens/native markers with trusted context and exact source-chain checks. Pure helpers receive pre-resolved context; they perform no hidden RPC calls. +12. Record checkpoint counts/events accurately. A current assert/revoke/grant replacement emits five ticks; allowance pulls can change balances without ticks. Do not substitute a block-only comparison for count comparison. +13. Preserve logical AGW from and signer origin in both live and reconstructed responses. Management responses remain owner-scoped. Preserve raw transport metadata, error causes/decoded fields and partial-failure hashes. +14. Preserve init/per-call progress hooks through wait without duplicates. Follow refreshed event IDs, including removal of AGENTIC-TX-103. +15. Normalize new Web2 public input to the existing web2/https wire identity; keep legacy input compatibility and transaction/read type separation. +16. Document exact capability limits. Do not treat passing mocks, source compilation or a skipped live scenario as deployed integration success. + +## Existing test architecture you must use + +This handoff was prepared after reading the current test runners and representative suites. + +| Existing file or directory | What to reuse or preserve | +| --- | --- | +| `packages/core/jest.config.ts` | Unit configuration: src specs/tests, ts-jest, 30-second default; excludes live integration-style suites and __e2e__ | +| `packages/core/jest.e2e.config.ts` | Separate live E2E config: __e2e__ specs, 300-second default, shared setup and file reporter | +| `packages/core/__e2e__/ci/suite.ts` | Curated scenarios with stable ID, group, file, full-name regex, asset needs and optional environment flags | +| `packages/core/__e2e__/ci/run.ts` | Offline --list/--verify; serial live Jest execution; Ethereum Sepolia fixture restriction; custom reporting | +| `packages/core/__e2e__/ci/preflight.ts` | Master/UEA/CEA balance budget checks; normal mode can fund accounts; --dry-run is read-only | +| `.github/workflows/e2e.yml` | Manual workflow_dispatch only, serial funded-key concurrency, verify → preflight → tests, always-uploaded logs | +| `packages/core/__e2e__/shared/setup.ts` | Existing environment loading convention; do not print credentials | +| `shared/evm-client.ts`, `svm-client.ts`, `chain-fixtures.ts` | Signer/client and chain fixture conventions | +| `shared/progress-tracker.ts`, `validators.ts` | Progress capture and baseline response checks; extend with AGW-specific identity/state assertions | +| `shared/external-tx-verifier.ts` | Independent external receipt verification | +| `shared/outbound-helpers.ts`, `fresh-wallet.ts` | Funding and fresh-account patterns; audit assumptions because current helpers are signer/UEA-oriented | +| `shared/e2e-file-reporter.js`, `ci/ci-reporter.js` | Logs and BigInt-safe result serialization | + +Paths abbreviated as `shared/...` or `ci/...` above are under `packages/core/__e2e__/`. + +Representative suites to read: +- `packages/core/__e2e__/push/native.spec.ts` +- `packages/core/__e2e__/push/pushpay-native-multicall.spec.ts` +- `packages/core/__e2e__/push/track-transaction.spec.ts` +- `packages/core/__e2e__/evm/outbound/uea-to-cea.spec.ts` +- `packages/core/__e2e__/read/_shared.ts` and `read/evm/api-coverage.spec.ts` + +The existing offline manifest verification passed: 76 selected scenarios, 40 spec files, 81 distinct tests for group all. This verifies selection consistency, not live E2E execution. Ten existing SDK unit suites previously passed 183 tests; four additional Solidity allowance experiments passed separately. Those are baselines, not coverage of your new implementation. + +Some older live tests use `if (skipE2E) return` inside tests. Do not copy that pattern: it can produce a passing test that executed no assertions. Missing deployment/keys/capabilities must be reported explicitly as unavailable, and an intentionally selected strict AGW run must fail its prerequisite gate rather than report success. + +## Required unit and local integration coverage + +Add meaningful tests beside the new modules under `packages/core/src/lib/agentic/` and at the existing orchestrator/push-chain integration boundaries. Mock RPC/signing/broadcast boundaries. Unit runs must not depend on funded keys or contact live networks. + +Cover the behavior implemented in each increment: + +| Area | Required cases | +| --- | --- | +| Initialization/context | Owner/agent/unknown identity; undeployed or foreign wallet; unsupported generation; signer origin versus AGW account; read-only; reinitialize changes | +| Rule selection | No match, one match, direct-grant duplicates, revoked and expired rules, per-send refresh, RPC failure not treated as empty state | +| Guards | Forbidden from/methods rejected before signer invocation; native agent arrays under the chosen scope; auxiliary transaction entry points | +| Codecs | Contract-generated vectors, exact IDs, generation inputs, native pins, ABI offsets/dynamic layout rejection, wrong beneficiary, token chain/native marker, round trips | +| Multi-asset behavior | Per-token units/counters, caps, omission versus zero, duplicates and empty-assets routing, only after matching artifacts exist | +| Reads | Empty owner, next index, deployment labels, consistent block reads, pagination/reorg handling, checkpoint ordering, unknown/revoked/history scope | +| Creation | Empty/multiple rules, grant order and returned IDs, atomic and sequential capability, failed/pending step, committed hashes, nonce/index races and safe recovery | +| Rule writes | Wrong owner, bare revoke failure, selected/all revocation, replacement stale spend, failed grant rollback, reset counters and checkpoint deltas | +| Composition/gas | AGW CEA/refund identity, bytes-empty recipient, nonzero gas cap, separate funding/gas balances, first-use UEA exception, no injected agent approval | +| Responses | Logical from and origin on response/wait/replay; Push revert versus destination revert/timeout; exact error identity/decoded data; no duplicate progress | +| Compatibility | Ordinary routes and exports, read-only behavior, Web2 new/legacy inputs and unchanged wire identity | + +Use real pinned contract artifacts in an isolated local EVM/Foundry integration harness where available to verify authorization and atomicity beyond mocks. Keep ABI/vector provenance. Any Push precompile mocking or stub gateway must be explicitly documented as a limit. Local execution does not prove node/TSS/destination settlement. + +For blocked cases, document the missing artifact and add a clearly labeled pending test specification if useful. Do not fill a suite with trivial skipped tests or assertions that only repeat your own helper output and count that as coverage. + +## Required E2E additions + +Proposed location: `packages/core/__e2e__/agw/`, with a shared fixture file for owner, agent, deployment manifest, wallet creation, controlled funding and cleanup. Use public SDK methods for the behavior under test. Raw RPC is appropriate for independent verification; raw calls may set up a fixture but must not replace the SDK operation being tested. + +Add scenarios for: + +1. Create a bare wallet and a wallet with rules; verify factory ownership/index, returned IDs and no implicit funding. +2. Separate funding and bounded gateway allowance; verify setup/removal and distinguish owner/agent gas from AGW PC. +3. Native owner and agent success with independent target-state verification. +4. Unauthorized sender, missing/revoked rule, expiry and cap/beneficiary failures; assert exact failure and unchanged protected state. +5. Add/revoke/update lifecycle; verify old ID disabled, new ID usable, counter reset and atomic rollback when spend changes. +6. Checkpoint count/event behavior, including the current five-tick replacement and no claim that all allowance pulls tick. +7. Positive-amount EVM universal execution: real allowance consumption/pull/burn, expected AGW CEA, correct destination target effects, wallet refund identity, Push/destination receipts and replayed tracking. +8. Destination failure and timeout classification; document inactive creditRevert accounting where applicable. +9. External EVM-agent UEA identity and first-use/subsequent gas behavior. Add Solana-origin coverage separately from SVM destination coverage. +10. Init/per-call hooks through wait and AGW logical from/signer origin across both sends and reconstructed transactions. +11. New multi-asset enforcement and supported SVM destination scenarios once their compatible contracts exist. + +Integration into the current runner: + +- Add an explicit curated `agw` group in suite.ts and the manual workflow choice. Register unique scenario IDs and narrowly scoped regexes; run --verify to catch missing, overlapping and collateral matches. +- Keep execution serial (`--runInBand`) and existing workflow concurrency. Shared funded accounts must not race nonces. +- Extend preflight budgeting for actual payers: owner setup gas, agent gas, wallet PC/assets, destination prerequisites and any fresh-account funding. The existing UEA budget alone does not cover AGW execution. Validate compatible deployment/capabilities before funding. +- Use fresh per-run wallets/rule IDs where possible, make funding bounded and explicit, and avoid destructive cleanup of shared accounts. +- Keep --list and --verify offline and side-effect-free. Additions must not fund/deploy from module import or title collection. +- Prevent incomplete AGW scenarios from being silently added to default all. Define explicit selection/prerequisite behavior while the compatible deployment is pending; retain existing group semantics for other tests. +- Preserve the custom BigInt-safe CI reporter. Do not replace it with raw Jest JSON serialization for live tests. Distinguish filtered tests, missing prerequisites, deliberately deferred capabilities and actual failures in your handoff. +- Capture deployment/source pins, public account addresses, network/blocks, transaction IDs, expected versus observed state and test counts. Never log private keys, seed phrases or full credential-bearing URLs. + +## Commands and execution boundaries + +From repository root, unit checks use the current config, for example: + +```sh +node node_modules/jest/bin/jest.js --config packages/core/jest.config.ts --runInBand --runTestsByPath +yarn nx run core:build +yarn nx run core:lint +``` + +Use actual spec paths and inspect the current Nx targets before invoking them. Run relevant existing regression suites in addition to new tests. Report baseline failures separately rather than weakening assertions or fixing unrelated modules indiscriminately. + +From `packages/core`, after registering the proposed agw group: + +```sh +yarn e2e:list --group agw +yarn e2e:verify --group agw +yarn e2e:verify --group all +``` + +These are offline selection checks. `--verify` parses test titles; it does not type-check or execute your tests. Add a no-broadcast type-check/compile check for new E2E code and report pre-existing type failures separately. + +The following are live operations or require live configuration: + +```sh +yarn e2e:preflight --group agw --dry-run +yarn e2e:preflight --group agw +yarn e2e:ci --group agw +``` + +Dry-run performs balance/RPC checks. Normal preflight may transfer funds. Live E2Es broadcast testnet transactions. This handoff requests adding E2Es and running local/offline validation; it does not by itself authorize spending configured funds, deploying contracts or triggering live CI. Run live tests only with separately established authorization, a compatible verified deployment and a bounded test budget. Keep implementing and validating independent work if live prerequisites are unavailable; record the precise blocker. + +Never run an unfiltered live suite just to see what happens. Do not read or print .env contents; use the repository's environment-loading conventions when an authorized run needs configured secrets. + +## Deliverables for the review agent + +1. Focused implementation changes with stable internal boundaries and matching unit tests. +2. Real E2E scenario implementations, manifest/preflight/runner integration as needed, and explicit readiness status for each scenario. +3. `plan/agw/implementation-status.md` with a per-step matrix: implemented, unit/local-verified, live-verified or blocked. Record A01–A08 decisions and artifact dependencies individually. +4. `plan/agw/implementation-review-handoff.md` containing: + - Branch/base/source/spec revisions and files/modules changed. + - Public behavior/signature changes and their authority or assumption ID. + - Exact commands, pass/fail/skip counts, test-selection verification and limits. + - Which test assertions exercise real contracts versus mocks. + - Live results with transaction IDs, or an explicit statement that no live run occurred. + - Remaining external blockers, placeholders and areas most needing review. +5. Keep source snapshots intact and update plan/gap statuses only when evidence warrants closure. Do not turn assumed behavior into an approved decision. + +Before finishing, inspect the diff, run formatting/type/build/lint and relevant tests, check that unsupported paths fail before signing, and verify no secrets or generated dependency trees were added. Do not claim the whole AGW SDK is complete if advertised methods still depend on placeholders or unverified deployments. + +Begin with the foundation and continue through every safely implementable step. Leave the work concrete and reviewable so a separate agent can validate correctness, scope and test quality. diff --git a/plan/agw/implementation-review-handoff.md b/plan/agw/implementation-review-handoff.md new file mode 100644 index 00000000..8f3f2d22 --- /dev/null +++ b/plan/agw/implementation-review-handoff.md @@ -0,0 +1,161 @@ +# AGW SDK implementation — review handoff + +October 3, 2026. For the reviewing agent. The per-step status is in [implementation-status.md](implementation-status.md). + +## Revisions + +| Item | Revision | +| --- | --- | +| Branch | `feat/agw-sdk-impl` (local only, not pushed) | +| Base | `feat/agw-sdk-planning@349635b2254823488603b37f4b44c4f5c929feb9` | +| Commits | `07d8adc` adapter/registry/codecs · `e87c47b` management/execution/responses · `4488639` local harness + vectors · `00b62d4` unit tests · `ebc4167` READ.CHAIN / Web2 · `e63bcc9` E2E agw group · `fa90b2a` atomic multi-rule add | +| AGW source | `pushAgenticWallet_v3@e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9` (remote ref rechecked, unchanged) | +| Core / gateway | `universalMarketplace_v1@cb69e0b` / `pc20-3rd-iteration@bcbf7df` (rechecked, unchanged) | +| Target spec | Notion page 5 export 2026-10-03 13:23 IST; no newer export or answers found | +| Toolchain | forge/anvil 1.5.1-stable (b0a9dd9), solc 0.8.26 via IR, viem 2.27.2 | + +The ABIs in `src/lib/agentic/contracts/abi/e704d5b` are generated from `plan/agw/research/validation-e704d5b/abi/*.json` (sha256 in each header). A fresh isolated build is ABI-identical to that evidence, and its runtime sizes match the validation report. + +## What changed + +New module `packages/core/src/lib/agentic/`: + +| Area | Files | +| --- | --- | +| Types, errors, capabilities, registry | `agentic.types.ts`, `errors.ts`, `capabilities.ts`, `deployments.ts`, `constants.ts`, `chain.ts`, `revert.ts` | +| Contract adapter | `contracts/e704d5b.ts`, `contracts/reader.ts`, generated `contracts/abi/e704d5b/*` | +| Codecs | `codec/{ids,selectors,abi-layout,defaults,policy,native,session,universal,rules}.ts`, `codec/historical/e704d5b-universal.ts` (internal) | +| Reads | `reads/{snapshot,wallets,rules,checkpoints}.ts` | +| Writes | `management/{common,create,rules-write}.ts` | +| Execution | `execution/{guards,outbound,send}.ts`, `context.ts`, `runtime.ts`, `response.ts` | +| Namespace | `agentic.ts`, `wallet.ts`, `utils.ts`, `index.ts` | + +Edited core files: +- `push-chain/push-chain.ts`: options type, `client.agentic`, agentic wiring, guards, reinitialize. +- `orchestrator/orchestrator.types.ts`: optional `agentic` response field. +- `orchestrator/internals/errors.ts` and `execute-standard.ts`: `cause` is kept. +- `progress-hook/*`: AGENTIC-TX family. +- `constants/{index,enums,read-state}.ts`, `read-state/{destination,read-params,read-state.types,read-tracker,spec-builder}.ts` and `orchestrator/route-detector.ts`: Web2. +- `utils.ts`, `lib/index.ts`: exports. + +Tooling and tests: +- `scripts/agw-local/` (prepare.sh, gen-abi.mjs, harness contracts) +- `__agw-local__/` and `jest.agw-local.config.ts`, `tsconfig.agw-local.json` +- `src/lib/agentic/__tests__/`, `__fixtures__/e704d5b-vectors.json` +- `read-state/__tests__/web2-compat.spec.ts` +- `__e2e__/agw/`, `__e2e__/ci/{suite,run,preflight}.ts` +- `.github/workflows/e2e.yml` + +## Public behaviour and its authority + +| Change | Authority / assumption | +| --- | --- | +| `PushChain.initialize(signer, { agenticWallet })`; `universal.account` = wallet, `origin`/`getAccountStatus`/gas signer-scoped | Spec 2.a | +| `reinitialize` does not inherit `agenticWallet` | SDK-owned decision (sdk-owned-review) | +| Read-only client with `agenticWallet` resolves the context but never signs | SDK-owned decision | +| `client.agentic.derive/create/list/wallet`; handle `info/owner/checkpoints/rules.*` | Spec 1.a–1.m | +| `list()` includes the next undeployed slot | SDK interpretation of the spec example | +| `setLabel`, revoked `rules.get`, universal rule encode/decode/update, SVM, `compileCard` throw `CAPABILITY_UNAVAILABLE` | A07, A06, A05, H4.4, A08 | +| `ref` on a rule is refused unless the generation supports it (never dropped) | A07 | +| Omitted-limit defaults | A03 (provisional) | +| Approval selectors refused in universal agent rules; native approvals need a pinned spender | A01 (provisional), obligation 16 | +| Native agent arrays refused | A02 (provisional) | +| `DUPLICATE_RULE` used for ambiguous send-time candidates | sdk-owned-review | +| Extra codes: `CAPABILITY_UNAVAILABLE`, `GENERATION_UNSUPPORTED`, `READ_ONLY`, `NOT_WALLET_OWNER`, `RULE_NOT_FOUND`, `RULE_READ_FAILED`, `INCONSISTENT_READ`, `INDEX_RACE`, `CREATE_PARTIAL`, `RECEIPT_MISMATCH`, `AGENT_GAS_INSUFFICIENT`, `WALLET_BALANCE_INSUFFICIENT`, `GATEWAY_ALLOWANCE_INSUFFICIENT`, `RULE_LIMIT_EXCEEDED`, `INVALID_RULE` | SDK-owned; names not final until reviewed | +| `utils.agentic.rulesId(agent, nonce, {validator})`, `deriveWallet(owner, index, {factory, walletImplementation})` | A04 (provisional signatures) | +| `CONSTANTS.AGENTIC` is `{}`; `ENVELOPE_VERSION` omitted | A07 | +| `READ.CHAIN` (enumerable, `WEB2 = 'web2'`); `CHAIN.WEB2`/`READ.WEB2` now `'web2'`; `'web2:https'` accepted | Spec §4; legacy compatibility per G16 | +| `PushChainExecutionError` and `PushChainBatchExecutionError` exported; error keeps `cause` | Spec 3.f (`AgenticRevertError extends PushChainExecutionError`) | +| AGENTIC-TX 101/102/104/105/106/107/199-01/199-02, no 103 | Spec 3.f (PROPOSED) | + +## Commands and results + +Run from the repository root unless noted. + +| Command | Result | +| --- | --- | +| `npx tsc -p packages/core/tsconfig.lib.json --noEmit` | clean | +| `npx tsc -p packages/core/tsconfig.spec.json --noEmit` (includes `__e2e__` and `ci/*.ts`) | clean | +| `yarn nx run core:build --skip-nx-cache` | success | +| `yarn nx run core:lint --skip-nx-cache` | 7 errors, 831 warnings; **all 7 errors pre-existing** in untouched files (`pc20/tracking.ts`, `pc20/__tests__/svm.spec.ts`, `__e2e__/docs-examples/13-read-state/*`); new code has warnings only (non-null assertions in tests) | +| `node node_modules/jest/bin/jest.js --config packages/core/jest.config.ts --runInBand` | 110 suites passed, 1 skipped (pre-existing); **1883 passed, 12 skipped, 0 failed** | +| …same, `packages/core/src/lib/agentic` | 6 suites, **123 passed** | +| …same, `read-state/__tests__/web2-compat.spec.ts` | **12 passed** | +| …the ten baseline suites from `research/sdk-owned-review-2026-10-03/test-summary.json` | **183 passed** (unchanged baseline) | +| `AGW_LOCAL_DIR=$(packages/core/scripts/agw-local/prepare.sh \| tail -1) node node_modules/jest/bin/jest.js --config packages/core/jest.agw-local.config.ts --runInBand --forceExit` | 3 suites, **32 passed** | +| `AGW_WRITE_VECTORS=1` + the vectors spec, then without it | vectors regenerated deterministically and re-verified | +| `cd packages/core && yarn e2e:list --group agw` | 21 scenarios, 7 spec files | +| `yarn e2e:verify --group agw` | 21 scenarios, 7 files, 21 distinct tests, consistent | +| `yarn e2e:verify --group all` | **76 scenarios, 40 files, 81 tests: unchanged** (agw excluded) | +| `AGW_E2E=1 AGW_DEPLOYMENT_MANIFEST= npx jest -c jest.e2e.config.ts --runTestsByPath __e2e__/agw/create.spec.ts` | 2 failed with `AgwPrerequisiteError` (strict gate, intended); no RPC or broadcast | +| Same spec without `AGW_E2E` | skipped (not reported as passed) | +| `multi-asset-svm.spec.ts` | 7 todo | + +Not run: `yarn e2e:preflight --group agw [--dry-run]` and `yarn e2e:ci --group agw`. Both need configured keys and a deployment manifest; no live run was authorized and no compatible deployment exists. + +## Real contracts versus mocks + +**Real contracts (local harness, pinned e704d5b on anvil chainId 9000).** SmartSession, AgentValidator, UniversalRulesPolicy (proxy), the AGW implementation and AGWFactory (proxy) decide every assertion about: +- authorization (owner door, agent door, stranger, `CallerIsNotAgent` path) +- policy enforcement: `CallLimitReached`, `ArgPinMismatch`, amount caps, `RulesExpired`, URP outbound gates 9–11 and the multicall allow-list +- IDs, wallet prediction and checkpoint sequencing (the five-tick replacement; OWNER_ACTION + RULES_GRANTED per batched grant) +- atomic `rules.update` and its rollback after an intervening agent spend +- revoke-all, sequential create partial failure and recovery +- allowance set/remove through the owner door, and allowance consumption + +Committed vectors are contract-computed (`getPermissionId`, `predictWallet`, a real grant). + +**Stubbed in the harness:** +- The gateway at `0x…C1`: models only pull + burn + fee arithmetic. +- The fee quote. +- The destination CEA address, for the outbound case. +- Only Push-EOA signers run; there is no UEA, precompile, Cosmos module, TSS, relay or destination execution. + +**Mocks (unit).** Chain reads (`__tests__/fake-chain.ts`, an in-memory model of the views) and the signer transport (`mock-runtime.ts`). These test SDK logic only: selection, error mapping, call shapes, ordering, consistency checks and pre-signature guards. + +**Live.** None. No transaction was broadcast to any testnet. + +## Blockers and placeholders + +- **A07 — no verified compatible deployment.** Every AGW call on a real network fails with `GENERATION_UNSUPPORTED`. The E2E group fails its gate, and preflight refuses to fund. To onboard: + 1. Write a manifest per `__e2e__/agw/_manifest.ts`. + 2. Add a verified entry to `VERIFIED_DEPLOYMENTS` in `deployments.ts`, and populate `CONSTANTS.AGENTIC` from it. + 3. Pass `AGW_DEPLOYMENT_MANIFEST` in `.github/workflows/e2e.yml`. It is not wired there yet. +- **A05.** Universal rules through the public `UniversalRule` (assets[]), universal `rules.update`, multi-asset `Spent`, and universal decoding in `rules.list`. That last one makes `list` fail outright on a wallet holding a universal rule, rather than truncate. +- **Universal E2E scenario 7.** It grants with the internal historical single-asset codec as fixture setup. This is valid only for an e704d5b-ABI deployment. +- **A06.** Revoked-rule history. +- **A08.** `compileCard`. +- **SVM destinations.** H4.4 and obligations 19–23. +- **A01–A04.** Implemented as provisional behaviour behind single modules (`codec/policy.ts`, `codec/defaults.ts`, `utils.ts`). +- **Step 17.** Release documentation, examples and a changeset are not written. + +## Areas most needing review + +1. **`CHAIN.WEB2` / `READ.WEB2` value change** from `'web2:https'` to `'web2'`. Spec alias semantics require it, and comparisons against the constants still work. Code comparing against the old literal would break. +2. **Owner-door outbound approval.** It approves `currentAllowance + amount`, then sends, in one owner batch. A standing agent allowance is preserved. The agent path never approves. +3. **Checkpoint semantics of batched writes.** + - Multi-ID revoke and multi-rule add use one owner `execute` batch, for atomicity and one signature. + - This adds one OWNER_ACTION tick per call on top of RULES_REVOKED / RULES_GRANTED. + - Single-ID revoke and single-rule add stay direct (one tick). + - `create` uses the signer's batch, which is sequential on a 7702-less Push EOA, reported as `CREATE_PARTIAL`. +4. **`create` index race.** It is detected after the fact (`INDEX_RACE`). Concurrent creates by the same owner can land grants on the raced wallet, and the error details say so. +5. **Decoded native pins/amount report `arg` as a head-word index** (`(offset - 4) / 32`). This is exact only when every preceding argument is one head word. The stored terms carry no signature. +6. **Agent gas guard.** + - It mirrors R1's fee-lock condition, using R1's default 1e7 gas estimate when no `gasLimit` is given. + - Formula: `balance < (gasLimit ?? 1e7) * gasPrice`. + - It applies to every agentic send by an external signer whose UEA is deployed. +7. **`universal.read`/`executeReads` in agentic mode.** They execute through the wallet, check the wallet's balance, and default `refundTo` to the wallet. An agent needs a native rule for the read registry entrypoint. +8. **`trackTransaction` replay adaptation.** It runs only for wallets of a registered generation. Otherwise the response is unchanged. One extra RPC per tracked AGW call. +9. **`PolicyCheckReverted` decoding.** The inner error is named by selector only, because its arguments are truncated by the engine. The SDK also extracts revert data from viem's "custom error 0x…: …" text, because the R1 path previously discarded the cause. +10. **viem `decodeEventLog` pitfall.** With a single-event ABI, viem skips the topic0 check. All AGW log parsers match topic0 explicitly. Other SDK modules were not audited for this. +11. **Pre-existing inconsistency.** `CHAIN.PUSH_LOCALNET` is `eip155:9001` but `CHAIN_INFO[PUSH_LOCALNET].chainId` is `9000`. The harness follows `CHAIN_INFO`, and native rule chains derive from `CHAIN_INFO`. +12. **E2E specs have never executed live.** Expect adjustment on first run: budgets, fee sizing (`AGW_E2E_MAX_PC_PER_CALL`), destination-revert classification text, and first-use event IDs. + +## Reproducing the local harness + +```sh +OUT=$(packages/core/scripts/agw-local/prepare.sh | tail -1) # isolated git archive + pinned submodules + forge build +AGW_LOCAL_DIR=$OUT node node_modules/jest/bin/jest.js --config packages/core/jest.agw-local.config.ts --runInBand --forceExit +``` + +`prepare.sh` reads the AGW repo with `git archive`/`ls-tree` only, and never touches its working tree. The harness uses anvil's public development keys and broadcasts only to the local anvil it spawns. diff --git a/plan/agw/implementation-status.md b/plan/agw/implementation-status.md new file mode 100644 index 00000000..0b7a3751 --- /dev/null +++ b/plan/agw/implementation-status.md @@ -0,0 +1,52 @@ +# AGW SDK implementation status + +October 3, 2026. Branch `feat/agw-sdk-impl` (base `feat/agw-sdk-planning@349635b`). This matrix records what the code does today against the [implementation plan](implementation-plan.md). "Implemented" excludes placeholders; a capability-gated method that throws `CAPABILITY_UNAVAILABLE` is listed as blocked, not implemented. Details, commands and review hotspots are in the [review handoff](implementation-review-handoff.md). + +## Evidence levels + +| Level | Meaning | +| --- | --- | +| Unit | Mock-boundary jest suites under `packages/core/src/lib/agentic/__tests__` and `read-state/__tests__/web2-compat.spec.ts`; no network | +| Local | Real pinned e704d5b contracts on anvil through the SDK (`packages/core/__agw-local__`); stub gateway only; Push-EOA signers only | +| Live | Testnet transactions against a verified deployment. **None has occurred** — no compatible deployment exists (A07) and no live run was authorized | + +## Per-step matrix + +| Step | Deliverable | Status | Unit | Local | Live | Remaining dependency | +| --- | --- | --- | --- | --- | --- | --- | +| 1 | Source and capability contract | Implemented | ✓ | ✓ rebuilt ABIs identical to evidence | — | Refresh pins when answers land | +| 2 | Namespace, types, exports, errors | Implemented; A04–A06 types provisional | ✓ | ✓ | — | Final public error names, A04/A05/A06 shapes | +| 3 | Signer/wallet context and lifecycle | Implemented | ✓ | ✓ owner, agent, stranger, read-only, reinitialize, guards | Blocked (A07) | UEA owner/agent paths only unit-tested (no UEA on anvil) | +| 4 | Generation registry and adapter | Implemented for e704d5b; registry ships empty | ✓ | ✓ wiring verified | Blocked (A07) | Verified manifest; OwnerIntent signing not implemented (no transport needs it) | +| 5 | Wallet and checkpoint reads | Implemented: derive, list, info, owner, checkpoints, active rules | ✓ | ✓ | Blocked (A07) | Revoked history (A06), `setLabel` (A07) gated | +| 6 | Rule normalization and codecs | Native implemented and vector-verified; universal validated then gated | ✓ | ✓ contract vectors | — | A05 multi-asset wire/vectors; A01/A03 confirmation | +| 7 | Create, add, revoke | Implemented (native rules) | ✓ | ✓ sequential create incl. partial recovery; atomic multi-rule add | Blocked (A07) | 7702/UEA create batch paths unit-only | +| 8 | Atomic rules.update | Implemented for native rules | ✓ | ✓ five ticks, stale-spend rollback | Blocked (A07) | A05 per-token assertion for universal rules | +| 9 | Owner execution and allowance setup | Implemented | ✓ | ✓ owner batches, approve/remove via owner door | Blocked (A07) | Production gateway pull/burn | +| 10 | Agent rule selection and native sends | Implemented | ✓ | ✓ maxCalls, pins, amount, expiry, A02 | Blocked (A07) | A02 confirmation | +| 11 | EVM universal sends and gas | Composer implemented for the e704d5b single-asset generation; signer gas guard implemented | ✓ | ✓ passes every URP gate with stub gateway | Blocked (A07) | A05 token resolution for assets[]; node/TSS/destination acceptance | +| 12 | SVM destination support | Not implemented; gated | ✓ gating | — | — | A05/A07, Harsh H4.4, obligations 19–23 | +| 13 | Responses, tracking, hooks, reads | Implemented | ✓ | ✓ live send/receipt identity | Blocked (A07) | Replay and outbound wait need a live run | +| 14 | Deployment onboarding and acceptance | E2E authored and gated; not run | — | — | Blocked (A07) | Verified manifest + authorized budget | +| 15 | Web2 compatibility | Implemented | ✓ | — | Not rerun | Review of CHAIN.WEB2 value change | +| 16 | compileCard | Not implemented; gated | ✓ gating | — | — | A08 | +| 17 | Documentation, examples, release | Planning docs only | — | — | — | Accepted feature scope | + +## Assumptions A01–A08 + +| ID | Design status | Artifact status | What the code does now | +| --- | --- | --- | --- | +| A01 | Provisional (Harsh H1 unanswered) | n/a | `codec/policy.ts`: approval selectors refused in universal agent rules; native approvals need a pinned spender. One boundary module | +| A02 | Provisional (Harsh H2) | n/a | Native agent arrays refused before signing; owner batches allowed | +| A03 | Provisional (Harsh H3) | n/a | `codec/defaults.ts` is the only defaults table, tagged A03 | +| A04 | Provisional (Harsh H4.1) | n/a | `utils.agentic.rulesId/deriveWallet` take explicit validator / factory / implementation context | +| A05 | Open (Harsh H4.2, Zaryab Z1.1/Z1.2) | Missing | Target universal encode/decode and universal update throw `CAPABILITY_UNAVAILABLE`; `Spent` kept as specified and tagged provisional | +| A06 | Open (Harsh H4.3) | Missing | `rules.get` of a revoked rule throws `CAPABILITY_UNAVAILABLE` with `revoked: true`; list returns active rules only | +| A07 | Open (Zaryab Z1/Z3) | **No verified deployment** | Registry and `CONSTANTS.AGENTIC` empty; every AGW call fails `GENERATION_UNSUPPORTED`; `ref` and `setLabel` gated | +| A08 | Open (Harsh H5, Zaryab Z5) | Missing | `utils.agentic.compileCard` throws `CAPABILITY_UNAVAILABLE` | + +No product decision was assumed approved. No Notion refresh or answers were found in the workspace; remote AGW/core/gateway refs were rechecked unchanged (`e704d5b`, `cb69e0b`, `bcbf7df`). + +## Gap register cross-reference + +Implementation evidence exists for G03 (explicit-context IDs, receipt IDs), G08 (checkpoint/label reads), G13/G15 (creation strategy and partial recovery), G14 (wallet-level replacement), G16 (Web2), G17 (read-only and reinitialize), G18 (eligibility and uncached selection) and G20 (dedicated composer and response identity). None is closed: each closure criterion also requires review and, where stated, a verified deployment or live acceptance. From 880e7ae5f6a04ea445fc7369a511fa0e282fa4be Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Sat, 3 Oct 2026 20:47:08 +0530 Subject: [PATCH 11/68] fix(agw): address implementation review R1-R7 R1 create() deploys with deployWalletWithSig(intent{owner,index,wallet}) sent by the owner itself: the factory reverts IndexMismatch if a concurrent creation took the slot, so no grant can land on a wallet this call did not deploy. Reported as INDEX_RACE with committed: false. R4 The SDK no longer writes gateway allowances on either door (a write from a stale read could restore revoked authority, and uint256.max overflowed). Both doors consume an allowance the owner set separately. R2 A ChainTarget on the connected Push chain is a native send; another Push network is refused instead of routed outbound. R3 Destination calls follow core Route 2 (ERC-20 transfer to the target, native value to the target, arrays as given, burn sized from value). Requests with no destination call are refused; agent selector-less destination calls are refused before signing. R5 Decoded native pins/amount use a raw { offset, expected } form, which the encoder accepts; argument form also accepts canonical 32-byte words. R6 A decoded AGW outbound sets route UOA_TO_CEA authoritatively on replay. R7 Partial-create state comes from this call's receipts; unknown outcomes are reported as 'unknown' and lost receipts keep the submitted hash (RECEIPT_UNAVAILABLE). Also: revert decoding names errors by selector when arguments are lost, and an omitted funds.token on an outbound means the destination native token. Race regressions ported to __agw-local__/agw-local-races.spec.ts; review regressions ported to the unit suites. Unit 1899 passed; harness 34 passed. --- .../__agw-local__/agw-local-advanced.spec.ts | 8 +- .../__agw-local__/agw-local-races.spec.ts | 93 ++++++++++++ .../core/__e2e__/agw/universal-evm.spec.ts | 8 +- .../src/lib/agentic/__tests__/codec.spec.ts | 35 ++++- .../lib/agentic/__tests__/management.spec.ts | 89 +++++++++-- .../__tests__/response-surface.spec.ts | 6 + .../agentic/__tests__/rules-policy.spec.ts | 2 +- .../src/lib/agentic/__tests__/send.spec.ts | 109 +++++++++++++- .../core/src/lib/agentic/agentic.types.ts | 18 ++- .../core/src/lib/agentic/codec/abi-layout.ts | 28 ++-- packages/core/src/lib/agentic/codec/native.ts | 41 ++++-- .../core/src/lib/agentic/contracts/e704d5b.ts | 34 +++++ packages/core/src/lib/agentic/errors.ts | 1 + .../src/lib/agentic/execution/outbound.ts | 139 +++++++++++------- .../core/src/lib/agentic/execution/send.ts | 62 +++++--- .../core/src/lib/agentic/management/common.ts | 24 ++- .../core/src/lib/agentic/management/create.ts | 93 ++++++++---- packages/core/src/lib/agentic/response.ts | 32 +++- packages/core/src/lib/agentic/revert.ts | 4 +- 19 files changed, 662 insertions(+), 164 deletions(-) create mode 100644 packages/core/__agw-local__/agw-local-races.spec.ts diff --git a/packages/core/__agw-local__/agw-local-advanced.spec.ts b/packages/core/__agw-local__/agw-local-advanced.spec.ts index 07fc7a86..1723cab1 100644 --- a/packages/core/__agw-local__/agw-local-advanced.spec.ts +++ b/packages/core/__agw-local__/agw-local-advanced.spec.ts @@ -129,8 +129,8 @@ describe('AGW advanced paths against real e704d5b contracts', () => { it('the decoded native terms carry the pins and caps as stored', async () => { const { rules } = await owner.agentic.wallet(wallet).rules.list(); expect(rules[0].rule).toMatchObject({ - pins: [{ arg: 0, expected: `0x${'0'.repeat(24)}${beneficiary.slice(2).toLowerCase()}` }], - amount: { arg: 1, maxPerCall: BigInt(10), maxTotal: BigInt(15) }, + pins: [{ offset: 4, expected: `0x${'0'.repeat(24)}${beneficiary.slice(2).toLowerCase()}` }], + amount: { offset: 36, maxPerCall: BigInt(10), maxTotal: BigInt(15) }, maxValuePerCall: BigInt(1000), }); }); @@ -308,10 +308,12 @@ describe('AGW advanced paths against real e704d5b contracts', () => { ownerAgw = await h.client(0, { agenticWallet: wallet }); }); + // Explicit call array: the funds land in the wallet's CEA and the listed + // call runs as given (a single `data` would also prepend transfer(target)). const send = (amount: bigint) => agenticSend(runtime, ctx, { to: { address: destTarget, chain: SEPOLIA }, - data: '0xd09de08a', + data: [{ to: destTarget, value: BigInt(0), data: '0xd09de08a' }], funds: { amount, token: { symbol: 'USDC', decimals: 6, address: token, mechanism: 'approve' } }, }); diff --git a/packages/core/__agw-local__/agw-local-races.spec.ts b/packages/core/__agw-local__/agw-local-races.spec.ts new file mode 100644 index 00000000..ad287004 --- /dev/null +++ b/packages/core/__agw-local__/agw-local-races.spec.ts @@ -0,0 +1,93 @@ +/** + * Race regressions from the implementation review (plan/agw/implementation-review), + * against the real pinned e704d5b contracts on local anvil. + * R1 — a concurrent creation must never let this create() grant on a wallet it + * did not deploy (the deploy is index-bound through deployWalletWithSig). + * R4 — an owner outbound must never restore an allowance revoked after the + * SDK read it (the SDK never writes allowances). + */ +import { encodeFunctionData, parseAbi, type Address } from 'viem'; +import { AgenticRevertError, CHAIN, type PushChain } from '../src'; +import type { AgenticRuntime } from '../src/lib/agentic/runtime'; +import { e704d5b } from '../src/lib/agentic/contracts/e704d5b'; +import { AGENTIC_ERROR_CODE } from '../src/lib/agentic/errors'; +import { startHarness, type Harness } from './harness'; + +const TOKEN = parseAbi([ + 'function mint(address,uint256)', + 'function approve(address,uint256) returns (bool)', + 'function allowance(address,address) view returns (uint256)', +]); +const internalsOf = (c: PushChain) => (c as unknown as { agenticRuntime: AgenticRuntime }).agenticRuntime; + +describe('AGW race regressions (real e704d5b contracts)', () => { + let h: Harness; + let owner: PushChain; + beforeAll(async () => { + h = await startHarness(18549); + owner = await h.client(0); + }); + afterAll(async () => { + await h?.stop(); + }); + + it('R1 a concurrent creation makes create() fail with nothing granted on either wallet', async () => { + const expected = await owner.agentic.derive(); + const rt = internalsOf(owner); + const execute = rt.execute; + rt.execute = async (params, options) => { + rt.execute = execute; + await h.write(0, h.addresses.factory, h.generation.contracts.abis.factory, 'deployWallet', ['other-purpose-wallet']); + return execute(params, options); + }; + const err = await owner.agentic + .create('intended', { + rules: [{ agent: h.wallets[1].account!.address, target: h.addresses.target, selector: 'increment()', validUntil: Number((await h.publicClient.getBlock()).timestamp) + 3600 }], + }) + .catch((e) => e) + .finally(() => { + rt.execute = execute; + }); + expect(err).toMatchObject({ code: AGENTIC_ERROR_CODE.INDEX_RACE, details: { committed: false } }); + const permissionIds = (address: Address) => + h.publicClient.readContract({ address: h.addresses.engine, abi: h.generation.contracts.abis.engine, functionName: 'getPermissionIDs', args: [address] }); + expect(await permissionIds(expected.address)).toHaveLength(0); + const next = await owner.agentic.derive(); + expect(next.index).toBe(expected.index + 1); + expect(await permissionIds(next.address)).toHaveLength(0); + // A retry re-reads the slot and succeeds. + const retried = await owner.agentic.create('intended', { rules: [] }); + expect(retried.index).toBe(next.index); + }); + + it('R4 an allowance revoked after the SDK read it stays revoked; the outbound fails on-chain', async () => { + const { wallet } = await owner.agentic.create('allowance-race', { rules: [] }); + const token = await h.deploy(0, 'HarnessPRC20', 'HarnessFixtures.sol', [CHAIN.ETHEREUM_SEPOLIA, 6]); + await h.write(0, token, TOKEN, 'mint', [wallet, BigInt(1000)]); + await h.publicClient.waitForTransactionReceipt({ + hash: await h.wallets[0].sendTransaction({ to: wallet, value: BigInt(10) ** BigInt(17), account: h.wallets[0].account!, chain: h.wallets[0].chain }), + }); + const c = await h.client(0, { agenticWallet: wallet }); + await (await c.universal.sendTransaction({ to: token, data: encodeFunctionData({ abi: TOKEN, functionName: 'approve', args: [h.addresses.gateway, BigInt(50)] }) })).wait(); + const rt = internalsOf(c); + rt.resolvePrc20 = () => token; + rt.resolveCEA = async () => ({ cea: h.wallets[2].account!.address, isDeployed: true }); + rt.quoteOutbound = async () => ({ protocolFee: BigInt(10) ** BigInt(14), nativeValueForGas: BigInt(10) ** BigInt(15), gasLimitUsed: BigInt(200000) }); + const execute = rt.execute; + rt.execute = async (params, options) => { + rt.execute = execute; + const revoke = e704d5b.encodeExecute([{ target: token, value: BigInt(0), data: encodeFunctionData({ abi: TOKEN, functionName: 'approve', args: [h.addresses.gateway, BigInt(0)] }) }]); + await (await execute({ to: wallet, data: revoke })).wait(); + return execute(params, options); + }; + const err = await c.universal + .sendTransaction({ to: { address: h.wallets[3].account!.address as Address, chain: CHAIN.ETHEREUM_SEPOLIA }, data: '0xd09de08a', funds: { amount: BigInt(10) } }) + .catch((e) => e) + .finally(() => { + rt.execute = execute; + }); + expect(err).toBeInstanceOf(AgenticRevertError); + expect(err.message).toContain('0x10bad147'); // LowAllowance() — the token refused the pull + expect(await h.publicClient.readContract({ address: token, abi: TOKEN, functionName: 'allowance', args: [wallet, h.addresses.gateway] })).toBe(BigInt(0)); + }); +}); diff --git a/packages/core/__e2e__/agw/universal-evm.spec.ts b/packages/core/__e2e__/agw/universal-evm.spec.ts index 3d196be5..253e34a7 100644 --- a/packages/core/__e2e__/agw/universal-evm.spec.ts +++ b/packages/core/__e2e__/agw/universal-evm.spec.ts @@ -104,9 +104,13 @@ d('agw universal evm', () => { const countBefore = (await sep.readContract({ address: counter, abi: COUNTER_ABI, functionName: 'count' })) as bigint; const balBefore = await f.push.readContract({ address: token, abi: erc20Abi, functionName: 'balanceOf', args: [wallet] }); const agent = await f.agent(wallet); + const ceaBefore = await sep.getBalance({ address: cea }); + // Explicit call array: the bridged ETH lands in the wallet's CEA and the + // allow-listed call runs as given (a single `data` would forward the value + // to the non-payable counter, as Route 2 does for ordinary accounts). const tx = await agent.universal.sendTransaction({ to: { address: counter, chain: SEPOLIA }, - data: INCREMENT, + data: [{ to: counter, value: BigInt(0), data: INCREMENT }], funds: { amount: AMOUNT, token: MOVEABLE_TOKEN_CONSTANTS.ETHEREUM_SEPOLIA.ETH }, }); expect(tx).toMatchObject({ from: wallet, route: 'UOA_TO_CEA' }); @@ -119,6 +123,8 @@ d('agw universal evm', () => { expect(await f.push.readContract({ address: token, abi: erc20Abi, functionName: 'balanceOf', args: [wallet] })).toBe(balBefore - AMOUNT); expect(await f.push.readContract({ address: token, abi: erc20Abi, functionName: 'allowance', args: [wallet, f.manifest.addresses.gateway] })).toBe(AMOUNT); expect((await sep.readContract({ address: counter, abi: COUNTER_ABI, functionName: 'count' })) as bigint).toBeGreaterThan(countBefore); + // Independent destination check: the wallet's own CEA received the bridged amount. + expect(await sep.getBalance({ address: cea })).toBe(ceaBefore + AMOUNT); const replay = await f.owner.universal.trackTransaction(tx.hash); expect(replay.from).toBe(wallet); expect(replay.agentic).toMatchObject({ door: 'agent', rulesId }); diff --git a/packages/core/src/lib/agentic/__tests__/codec.spec.ts b/packages/core/src/lib/agentic/__tests__/codec.spec.ts index d9ade769..e5fa99b6 100644 --- a/packages/core/src/lib/agentic/__tests__/codec.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/codec.spec.ts @@ -91,9 +91,40 @@ describe('native rule codec', () => { const back = decodeNativeTerms(env.body); expect(back).toEqual({ ...terms, validUntil: terms.validUntil }); const rule = nativeTermsToRule(back, v.rule.agent, `0x${'00'.repeat(32)}`); - expect(rule.pins?.[0].arg).toBe(0); - expect(rule.amount).toEqual({ arg: 1, maxPerCall: BigInt(10), maxTotal: BigInt(100) }); + // Stored terms carry offsets, not an ABI: decoded rules report the raw offset form. + expect(rule.pins).toEqual([{ offset: 4, expected: terms.pins[0].expected.toLowerCase() }]); + expect(rule.amount).toEqual({ offset: 36, maxPerCall: BigInt(10), maxTotal: BigInt(100) }); expect(rule.ref).toBeUndefined(); + // …and the decoded rule re-encodes to identical terms with only its 4-byte selector. + expect(nativeRuleToTerms(rule, { nowSeconds: NOW }).terms).toEqual(terms); + }); + + it('decoding never invents argument indexes: a static array before a pin stays a raw offset', () => { + const input: NativeRule = { agent, target, selector: 'deposit(uint256[2],address)', validUntil: NOW + 10, pins: [{ arg: 1, expected: agent }] }; + const { terms } = nativeRuleToTerms(input, { nowSeconds: NOW }); + expect(terms.pins[0].offset).toBe(4 + 64); + const decoded = nativeTermsToRule(terms, agent, `0x${'00'.repeat(32)}`); + expect(decoded.pins).toEqual([{ offset: 68, expected: terms.pins[0].expected }]); + expect(nativeRuleToTerms(decoded, { nowSeconds: NOW }).terms).toEqual(terms); + }); + + it('a decoded address pin re-encodes in argument form once the signature is restored', () => { + const input: NativeRule = { agent, target, selector: 'deposit(address,uint256)', validUntil: NOW + 10, pins: [{ arg: 0, expected: agent }] }; + const { terms } = nativeRuleToTerms(input, { nowSeconds: NOW }); + const word = terms.pins[0].expected; + expect(nativeRuleToTerms({ ...input, pins: [{ arg: 0, expected: word }] }, { nowSeconds: NOW }).terms).toEqual(terms); + expect(() => + nativeRuleToTerms({ ...input, pins: [{ arg: 0, expected: `0x${'ff'.repeat(32)}` }] }, { nowSeconds: NOW }) + ).toThrow(/does not encode/); + }); + + it('offset-form pins must be exact words at a valid offset', () => { + const base: NativeRule = { agent, target, selector: '0xd09de08a', validUntil: NOW + 10 }; + expect(() => nativeRuleToTerms({ ...base, pins: [{ offset: 3, expected: `0x${'00'.repeat(32)}` }] }, { nowSeconds: NOW })).toThrow(/offset/); + expect(() => nativeRuleToTerms({ ...base, pins: [{ offset: 4, expected: '0x01' }] }, { nowSeconds: NOW })).toThrow(/32-byte/); + expect(nativeRuleToTerms({ ...base, pins: [{ offset: 36, expected: `0x${'00'.repeat(31)}01` }] }, { nowSeconds: NOW }).terms.pins).toEqual([ + { offset: 36, expected: `0x${'00'.repeat(31)}01` }, + ]); }); it('applies the single provisional A03 defaults table for omitted limits', () => { diff --git a/packages/core/src/lib/agentic/__tests__/management.spec.ts b/packages/core/src/lib/agentic/__tests__/management.spec.ts index 2cfe1fa9..5de26a94 100644 --- a/packages/core/src/lib/agentic/__tests__/management.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/management.spec.ts @@ -1,11 +1,11 @@ -import { decodeFunctionData, type Hex, type Log } from 'viem'; +import { decodeFunctionData, encodeErrorResult, type Hex, type Log, type TransactionReceipt } from 'viem'; import { PUSH_NETWORK } from '../../constants/enums'; import { PushChainBatchExecutionError } from '../../orchestrator/internals/errors'; import type { MultiCall } from '../../orchestrator/orchestrator.types'; import { PROGRESS_HOOK } from '../../progress-hook/progress-hook.types'; import { AgenticCapability } from '../capabilities'; import { currentGeneration, resetAgenticGenerations } from '../deployments'; -import { AGW_ABI, UNIVERSAL_RULES_POLICY_ABI } from '../contracts/abi/e704d5b'; +import { AGW_ABI, AGW_FACTORY_ABI, UNIVERSAL_RULES_POLICY_ABI } from '../contracts/abi/e704d5b'; import { e704d5b } from '../contracts/e704d5b'; import { deriveWallet, rulesId as computeRulesId } from '../codec/ids'; import { AGENTIC_ERROR_CODE } from '../errors'; @@ -117,29 +117,92 @@ describe('agentic.create', () => { }); }); - it('a sequential failure after deployment is CREATE_PARTIAL with hashes and granted IDs, never a redeploy', async () => { + const receipt = (logs: Log[], status: 'success' | 'reverted' = 'success') => + ({ status, logs } as unknown as TransactionReceipt); + + it('a sequential failure after deployment is CREATE_PARTIAL; what committed comes from this call’s receipts', async () => { const fake = new FakeChain(); + const h1 = `0x${'01'.repeat(32)}` as Hex; + const h2 = `0x${'02'.repeat(32)}` as Hex; + fake.receipts.set(h1, receipt([log(ADDR.factory, e704d5b.events.walletDeployed, { owner: ADDR.owner, index: BigInt(0), wallet: nextWallet }, { label: 'ops' }, BigInt(101))])); + fake.receipts.set(h2, receipt([granted(nextWallet, ids[0])])); const rt = mockRuntime(fake, { signer: ADDR.owner, execute: (async () => { - // Deployment and the first grant committed before the failure. - fake.addWallet(ADDR.owner, 'ops', [fake.nativeRule(ADDR.agent, ids[0])]); - throw new PushChainBatchExecutionError('grant 2 reverted', [`0x${'01'.repeat(32)}`, `0x${'02'.repeat(32)}`], `0x${'03'.repeat(32)}`); + throw new PushChainBatchExecutionError('grant 2 reverted', [h1, h2]); }) as never, }); const err = await createWallet(rt, 'ops', { rules: [rule(), rule(ADDR.other)] }).catch((e) => e); expect(err.code).toBe(AGENTIC_ERROR_CODE.CREATE_PARTIAL); - expect(err.details).toMatchObject({ - wallet: nextWallet, - walletDeployed: true, - grantedRulesIds: [ids[0]], - confirmedHashes: [`0x${'01'.repeat(32)}`, `0x${'02'.repeat(32)}`], - pendingHash: `0x${'03'.repeat(32)}`, - }); + expect(err.details).toMatchObject({ wallet: nextWallet, walletDeployed: true, grantedRulesIds: [ids[0]], confirmedHashes: [h1, h2] }); expect(err.hint).toMatch(/rules\.add/); expect(rt.events.at(-1)?.id).toBe(PROGRESS_HOOK.AGENTIC_TX_199_02); }); + it('a pending hash keeps an unconfirmed deployment unknown', async () => { + const fake = new FakeChain(); + const rt = mockRuntime(fake, { + signer: ADDR.owner, + execute: (async () => { + throw new PushChainBatchExecutionError('timed out', [], `0x${'03'.repeat(32)}`); + }) as never, + }); + const err = await createWallet(rt, 'ops', { rules: [rule()] }).catch((e) => e); + expect(err.details).toMatchObject({ walletDeployed: 'unknown', pendingHash: `0x${'03'.repeat(32)}` }); + expect(err.hint).toMatch(/Do not retry/); + }); + + it('failed recovery reads report unknown state, never "not deployed"', async () => { + const fake = new FakeChain(); + const rt = mockRuntime(fake, { + signer: ADDR.owner, + execute: (async () => { + fake.addWallet(ADDR.owner, 'committed'); + throw new PushChainBatchExecutionError('grant failed', [`0x${'11'.repeat(32)}`]); + }) as never, + }); + const err = await createWallet(rt, 'review', { rules: [rule()] }).catch((e) => e); + expect(err.code).toBe('CREATE_PARTIAL'); + expect(err.details.walletDeployed).toBe('unknown'); + expect(err.details.recoveryError).toBeTruthy(); + expect(err.hint).toMatch(/Do not retry/); + }); + + it('a receipt that cannot be read after submission keeps the hash and reports unknown state', async () => { + const fake = new FakeChain(); + const rt = mockRuntime(fake, { + signer: ADDR.owner, + execute: (async () => { + const r = fakeResponse({ hash: `0x${'44'.repeat(32)}` }); + r.wait = async () => { + throw new Error('rpc down'); + }; + return r; + }) as never, + }); + const err = await createWallet(rt, 'x', { rules: [] }).catch((e) => e); + expect(err.code).toBe(AGENTIC_ERROR_CODE.CREATE_PARTIAL); + expect(err.details).toMatchObject({ walletDeployed: 'unknown', submitted: { txHash: `0x${'44'.repeat(32)}` } }); + }); + + it('the deploy is index-bound: a raced slot reverts and is reported as INDEX_RACE with nothing committed', async () => { + const fake = new FakeChain(); + const raceData = encodeErrorResult({ abi: AGW_FACTORY_ABI, errorName: 'IndexMismatch', args: [BigInt(1), BigInt(0)] }); + const rt = mockRuntime(fake, { + signer: ADDR.owner, + execute: (async (p: { data: MultiCall[] }) => { + const deploy = decodeFunctionData({ abi: AGW_FACTORY_ABI, data: p.data[0].data }); + expect(deploy.functionName).toBe('deployWalletWithSig'); + expect((deploy.args[0] as { index: bigint; wallet: string }).index).toBe(BigInt(0)); + expect((deploy.args[0] as { wallet: string }).wallet).toBe(nextWallet); + throw new Error(`Execution reverted with reason: custom error ${raceData.slice(0, 10)}: ${raceData.slice(10)}.`); + }) as never, + }); + const err = await createWallet(rt, 'x', { rules: [rule()] }).catch((e) => e); + expect(err.code).toBe(AGENTIC_ERROR_CODE.INDEX_RACE); + expect(err.details).toMatchObject({ committed: false }); + }); + it('a slot that is already deployed is refused before signing', async () => { const fake = new FakeChain(); fake.predictOverride = (owner, index) => deriveWallet({ factory: ADDR.factory, walletImplementation: ADDR.impl, owner, index }); diff --git a/packages/core/src/lib/agentic/__tests__/response-surface.spec.ts b/packages/core/src/lib/agentic/__tests__/response-surface.spec.ts index 8ae5f95c..b285b7af 100644 --- a/packages/core/src/lib/agentic/__tests__/response-surface.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/response-surface.spec.ts @@ -61,6 +61,12 @@ describe('response identity', () => { const data = e704d5b.encodeExecuteAsAgent(ruleId(4), { target: ADDR.gateway, value: BigInt(5), data: gatewayCall }); const tracked = await adaptTrackedResponse({ reader: fake, network: PUSH_NETWORK.TESTNET_DONUT }, fakeResponse({ to: w.address, data })); expect(tracked).toMatchObject({ from: w.address, to: ADDR.target, data: '0xd09de08a', route: 'UOA_TO_CEA' }); + // A Push-only route inferred from an incomplete Cosmos record is replaced. + const early = await adaptTrackedResponse( + { reader: fake, network: PUSH_NETWORK.TESTNET_DONUT }, + fakeResponse({ to: w.address, data, route: 'UOA_TO_PUSH' }) + ); + expect(early.route).toBe('UOA_TO_CEA'); }); it('replay: anything not provably an AGW call is left untouched', async () => { diff --git a/packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts b/packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts index f938e0f1..d5676150 100644 --- a/packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts @@ -158,7 +158,7 @@ describe('PushChain.utils.agentic (pure)', () => { const [bytes] = u.encodeRules([rule], { pushChainNamespace: PUSH_NS, validator: ADDR.validator, rulesPolicy: ADDR.policy, nowSeconds: NOW }); const back = u.decodeRules(bytes, { pushChainNamespace: PUSH_NS }); expect(back).toMatchObject({ agent: ADDR.agent, target: ADDR.target, maxCalls: 4, validUntil: NOW + 100 }); - expect((back as NativeRule).pins?.[0].arg).toBe(0); + expect((back as NativeRule).pins).toEqual([{ offset: 4, expected: `0x${'0'.repeat(24)}${ADDR.other.slice(2).toLowerCase()}` }]); }); it('decodeRules of a foreign-chain envelope is capability-gated', () => { diff --git a/packages/core/src/lib/agentic/__tests__/send.spec.ts b/packages/core/src/lib/agentic/__tests__/send.spec.ts index f21df768..5ec162b2 100644 --- a/packages/core/src/lib/agentic/__tests__/send.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/send.spec.ts @@ -1,4 +1,4 @@ -import { decodeFunctionData, getAddress, type Address, type Hex } from 'viem'; +import { decodeAbiParameters, decodeFunctionData, getAddress, maxUint256, type Address, type Hex } from 'viem'; import { CHAIN, PUSH_NETWORK } from '../../constants/enums'; import { UNIVERSAL_GATEWAY_PC, ERC20_EVM } from '../../constants/abi'; import { PushChainExecutionError } from '../../orchestrator/internals/errors'; @@ -105,6 +105,30 @@ describe('guards fail before the signer is ever invoked', () => { }); }); +describe('explicit Push destinations', () => { + it('a ChainTarget on the connected Push chain is a native send, same as a bare address', async () => { + const { rt, ctx } = setup('agent'); + const tx = await agenticSend(rt, ctx, { to: { address: ADDR.target, chain: CHAIN.PUSH_TESTNET_DONUT }, data }); + expect(e704d5b.decodeWalletCall(rt.executeMock.mock.calls[0][0].data)).toMatchObject({ kind: 'executeAsAgent', rulesId: ruleId(1) }); + expect(tx.route).not.toBe('UOA_TO_CEA'); + expect(tx.to).toBe(ADDR.target); + }); + + it('the owner door treats it the same way', async () => { + const { rt, ctx } = setup('owner'); + await agenticSend(rt, ctx, { to: { address: ADDR.target, chain: CHAIN.PUSH_TESTNET }, data }); + expect(e704d5b.decodeWalletCall(rt.executeMock.mock.calls[0][0].data)).toMatchObject({ kind: 'execute', calls: [{ target: ADDR.target }] }); + }); + + it('another Push network is refused, not routed outbound', async () => { + const { rt, ctx } = setup('owner'); + await expect(agenticSend(rt, ctx, { to: { address: ADDR.target, chain: CHAIN.PUSH_MAINNET }, data })).rejects.toThrow( + /other than the connected network/ + ); + expect(rt.executeMock).not.toHaveBeenCalled(); + }); +}); + describe('native wrapping and logical identity', () => { it('agent door: executeAsAgent(selected rule, exact call); response shows the wallet as from', async () => { const { rt, ctx, w } = setup('agent'); @@ -268,7 +292,7 @@ describe('EVM outbound composition from the wallet', () => { ).rejects.toMatchObject({ details: { capability: AgenticCapability.UNIVERSAL_SVM_RULES } }); }); - it('owner door preserves any standing agent allowance: approve(current + amount) then the outbound, atomically', async () => { + it('owner door never writes an allowance: it sends only the outbound and consumes the existing allowance', async () => { const s = universalSetup(); s.ctx.door = 'owner'; s.ctx.signerPushAccount = ADDR.owner; @@ -276,9 +300,84 @@ describe('EVM outbound composition from the wallet', () => { await agenticSend(rt, s.ctx, send(BigInt(100))); const outer = e704d5b.decodeWalletCall(rt.executeMock.mock.calls[0][0].data) as { kind: string; calls: { target: Address; data: Hex }[] }; expect(outer.kind).toBe('execute'); - expect(outer.calls.map((c) => c.target)).toEqual([token, ADDR.gateway]); - const approve = decodeFunctionData({ abi: ERC20_EVM, data: outer.calls[0].data }); - expect(approve.args).toEqual([ADDR.gateway, BigInt(600)]); + expect(outer.calls.map((c) => c.target)).toEqual([ADDR.gateway]); + }); + + it('owner door with too small an allowance fails before signing (no implicit approval)', async () => { + const s = universalSetup(); + s.ctx.door = 'owner'; + s.ctx.signerPushAccount = ADDR.owner; + s.fake.balances.set(`allowance:${token.toLowerCase()}`, BigInt(10)); + const rt = mockRuntime(s.fake, { signer: ADDR.owner, resolvePrc20: () => token }); + await expect(agenticSend(rt, s.ctx, send(BigInt(100)))).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.GATEWAY_ALLOWANCE_INSUFFICIENT, + }); + expect(rt.executeMock).not.toHaveBeenCalled(); + }); + + it('an existing unlimited allowance is consumed as-is', async () => { + const s = universalSetup(); + s.ctx.door = 'owner'; + s.ctx.signerPushAccount = ADDR.owner; + s.fake.balances.set(`allowance:${token.toLowerCase()}`, maxUint256); + const rt = mockRuntime(s.fake, { signer: ADDR.owner, resolvePrc20: () => token }); + await expect(agenticSend(rt, s.ctx, send(BigInt(100)))).resolves.toBeDefined(); + }); + + it('a transfer-only ERC-20 outbound instructs a transfer to the requested recipient', async () => { + const s = universalSetup(); + s.ctx.door = 'owner'; + s.ctx.signerPushAccount = ADDR.owner; + const rt = mockRuntime(s.fake, { signer: ADDR.owner, resolvePrc20: () => token }); + const recipient = getAddress('0x00000000000000000000000000000000000ab0b0'); + const usdc = { symbol: 'USDC', decimals: 6, address: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238', mechanism: 'approve' as const }; + const tx = await agenticSend(rt, s.ctx, { to: { address: recipient, chain: CHAIN.ETHEREUM_SEPOLIA }, funds: { amount: BigInt(100), token: usdc } }); + const outer = e704d5b.decodeWalletCall(rt.executeMock.mock.calls[0][0].data) as { calls: { data: Hex }[] }; + const { args } = decodeFunctionData({ abi: UNIVERSAL_GATEWAY_PC, data: outer.calls[0].data }); + const payload = (args[0] as { payload: Hex }).payload; + const [calls] = decodeAbiParameters( + [{ type: 'tuple[]', components: [{ name: 'to', type: 'address' }, { name: 'value', type: 'uint256' }, { name: 'data', type: 'bytes' }] }], + `0x${payload.slice(10)}` + ); + expect(calls).toHaveLength(1); + expect(getAddress(calls[0].to)).toBe(getAddress(usdc.address)); + expect(decodeFunctionData({ abi: ERC20_EVM, data: calls[0].data }).args).toEqual([recipient, BigInt(100)]); + expect(tx.to).toBe(recipient); + }); + + it('a value-only outbound burns the native PRC20 for that value and forwards it to the recipient', async () => { + const s = universalSetup(); + s.ctx.door = 'owner'; + s.ctx.signerPushAccount = ADDR.owner; + const native = getAddress('0x0000000000000000000000000000000000000e7e'); + s.fake.balances.set(`balanceOf:${native.toLowerCase()}`, BigInt(1000)); + s.fake.balances.set(`allowance:${native.toLowerCase()}`, BigInt(1000)); + const rt = mockRuntime(s.fake, { signer: ADDR.owner, resolvePrc20: () => native }); + await agenticSend(rt, s.ctx, { to: { address: ADDR.other, chain: CHAIN.ETHEREUM_SEPOLIA }, value: BigInt(7) }); + const outer = e704d5b.decodeWalletCall(rt.executeMock.mock.calls[0][0].data) as { calls: { data: Hex }[] }; + const req = decodeFunctionData({ abi: UNIVERSAL_GATEWAY_PC, data: outer.calls[0].data }).args[0] as { amount: bigint; payload: Hex }; + expect(req.amount).toBe(BigInt(7)); + expect(req.payload.toLowerCase()).toContain(ADDR.other.slice(2).toLowerCase()); + }); + + it('an outbound with no destination call (parking in the CEA) is refused before signing', async () => { + const s = universalSetup(); + s.ctx.door = 'owner'; + s.ctx.signerPushAccount = ADDR.owner; + const cea = getAddress('0x000000000000000000000000000000000000cea1'); + const rt = mockRuntime(s.fake, { signer: ADDR.owner, resolvePrc20: () => token, resolveCEA: async () => ({ cea, isDeployed: true }) }); + await expect( + agenticSend(rt, s.ctx, { to: { address: cea, chain: CHAIN.ETHEREUM_SEPOLIA }, value: BigInt(1) }) + ).rejects.toThrow(/no destination call/); + expect(rt.executeMock).not.toHaveBeenCalled(); + }); + + it('an agent value-only destination call is refused before signing (the policy admits only allow-listed calls)', async () => { + const s = universalSetup(); + const rt = mockRuntime(s.fake, { signer: ADDR.agent, resolvePrc20: () => token }); + await expect( + agenticSend(rt, s.ctx, { to: { address: ADDR.other, chain: CHAIN.ETHEREUM_SEPOLIA }, funds: { amount: BigInt(1), token: { symbol: 'X', decimals: 6, address: token, mechanism: 'native' } } }) + ).rejects.toThrow(/no function selector/); }); it('more than 10 destination calls are refused', async () => { diff --git a/packages/core/src/lib/agentic/agentic.types.ts b/packages/core/src/lib/agentic/agentic.types.ts index 0b93a1da..8216e2d7 100644 --- a/packages/core/src/lib/agentic/agentic.types.ts +++ b/packages/core/src/lib/agentic/agentic.types.ts @@ -33,12 +33,24 @@ export interface NativeRule { maxValueTotal?: bigint; /** Default 0 (unlimited calls until expiry) — provisional, A03. */ maxCalls?: number; - /** `arg` is the argument index in the selector signature. */ - pins?: { arg: number; expected: AgenticHex | AgenticAddress | bigint }[]; + pins?: ArgPin[]; /** `maxTotal` default uint256 max (unlimited total) — provisional, A03. */ - amount?: { arg: number; maxPerCall: bigint; maxTotal?: bigint }; + amount?: AmountLimit; } +/** + * Where a pin or amount sits in the calldata. `arg` is the argument index in + * the selector signature (requires the signature form of `selector`). + * `offset` is the raw calldata byte offset, selector included — the form the + * contracts store; decoded rules (rules.get/list, decodeRules) always use it + * because stored terms carry no ABI. SDK extension of the page-5 shape. + */ +export type ArgPin = + | { arg: number; expected: AgenticHex | AgenticAddress | bigint } + | { offset: number; expected: AgenticHex }; + +export type AmountLimit = ({ arg: number } | { offset: number }) & { maxPerCall: bigint; maxTotal?: bigint }; + export interface AssetCap { /** The destination chain's token (MOVEABLE constant) or native marker. */ token: MoveableToken | AgenticAddress; diff --git a/packages/core/src/lib/agentic/codec/abi-layout.ts b/packages/core/src/lib/agentic/codec/abi-layout.ts index 862ebfc1..2e1d4629 100644 --- a/packages/core/src/lib/agentic/codec/abi-layout.ts +++ b/packages/core/src/lib/agentic/codec/abi-layout.ts @@ -1,4 +1,5 @@ import { + decodeAbiParameters, encodeAbiParameters, isAddress, isHex, @@ -97,13 +98,23 @@ export function encodeArgWord( what: string ): AgenticHex { try { - if (param.type === 'address') { + const isWord = typeof expected === 'string' && isHex(expected) && expected.length === 66; + if (param.type === 'address' && !isWord) { if (typeof expected !== 'string' || !isAddress(expected, { strict: false })) { throw new Error('expected an address'); } - } else if (param.type.startsWith('bytes')) { + } else if (param.type.startsWith('bytes') && !isWord) { if (typeof expected !== 'string' || !isHex(expected)) throw new Error('expected hex'); } + // An already-encoded 32-byte word (as decoded rules return) is accepted + // when it is a canonical encoding of this argument type. + if (typeof expected === 'string' && isHex(expected) && expected.length === 66 && param.type !== 'bytes32') { + const [value] = decodeAbiParameters([param], expected as AgenticHex); + if (encodeAbiParameters([param], [value]).toLowerCase() !== expected.toLowerCase()) { + throw new Error('word is not a canonical encoding'); + } + return expected.toLowerCase() as AgenticHex; + } return encodeAbiParameters([param], [expected]) as AgenticHex; } catch (cause) { throw invalid( @@ -115,15 +126,12 @@ export function encodeArgWord( } } -/** Head-word index for a decoded absolute offset. Exact only for all-single-word heads. */ -export function offsetToHeadWord(offset: number): number { - if (offset < 4 || (offset - 4) % 32 !== 0) { - throw new AgenticError( - AGENTIC_ERROR_CODE.RULE_READ_FAILED, - `stored argument offset ${offset} is not word-aligned after the selector` - ); +/** Validate a raw calldata offset given directly (offset form). */ +export function rawOffset(offset: number, what: string): number { + if (!Number.isInteger(offset) || offset < 4 || offset + 32 > UINT16_MAX) { + throw invalid(`${what} offset ${offset} must be an integer in [4, ${UINT16_MAX - 32}] (selector included)`); } - return (offset - 4) / 32; + return offset; } function invalid(message: string, cause?: unknown): AgenticError { diff --git a/packages/core/src/lib/agentic/codec/native.ts b/packages/core/src/lib/agentic/codec/native.ts index b357418e..bdf5ae0f 100644 --- a/packages/core/src/lib/agentic/codec/native.ts +++ b/packages/core/src/lib/agentic/codec/native.ts @@ -3,13 +3,14 @@ import { encodeAbiParameters, getAddress, isAddress, + isHex, type AbiParameter, type Address, type Hex, } from 'viem'; import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; import type { AgenticHex, NativeRule } from '../agentic.types'; -import { argumentOffset, encodeArgWord, offsetToHeadWord } from './abi-layout'; +import { argumentOffset, encodeArgWord, rawOffset } from './abi-layout'; import { AGENTIC_DEFAULTS, UINT256_MAX, withDefault } from './defaults'; import { APPROVAL_SELECTORS } from './policy'; import { parseSelector, VALUE_ONLY_SELECTOR, type ParsedSelector } from './selectors'; @@ -116,6 +117,12 @@ export function nativeRuleToTerms( } const pins = pinsIn.map((p, i) => { + if ('offset' in p) { + if (typeof p.expected !== 'string' || !isHex(p.expected) || p.expected.length !== 66) { + throw invalid(`pins[${i}].expected must be the exact 32-byte calldata word in offset form`); + } + return { offset: rawOffset(p.offset, `pins[${i}]`), expected: p.expected.toLowerCase() as Hex }; + } const offset = argumentOffset(parsed.inputs, p.arg, `pins[${i}]`); const param = (parsed.inputs as readonly AbiParameter[])[p.arg]; return { offset, expected: encodeArgWord(param, p.expected, `pins[${i}]`) }; @@ -125,8 +132,9 @@ export function nativeRuleToTerms( const spenderArg = APPROVAL_SPENDER_ARG[parsed.selector]; if (spenderArg !== undefined) { - const pinnedSpender = - spenderArg !== null && pinsIn.some((p) => p.arg === spenderArg); + // Every argument of these approval functions before the spender is one + // static word, so the spender's calldata offset is exact. + const pinnedSpender = spenderArg !== null && offsets.has(4 + 32 * spenderArg); if (!pinnedSpender) { throw new AgenticError( AGENTIC_ERROR_CODE.INVALID_RULE, @@ -146,10 +154,15 @@ export function nativeRuleToTerms( maxTotal: BigInt(0), }; if (rule.amount) { - const offset = argumentOffset(parsed.inputs, rule.amount.arg, 'amount'); - const param = (parsed.inputs as readonly AbiParameter[])[rule.amount.arg]; - if (!/^uint\d*$/.test(param.type)) { - throw invalid(`amount argument must be an unsigned integer, got ${param.type}`); + let offset: number; + if ('offset' in rule.amount) { + offset = rawOffset(rule.amount.offset, 'amount'); + } else { + offset = argumentOffset(parsed.inputs, rule.amount.arg, 'amount'); + const param = (parsed.inputs as readonly AbiParameter[])[rule.amount.arg]; + if (!/^uint\d*$/.test(param.type)) { + throw invalid(`amount argument must be an unsigned integer, got ${param.type}`); + } } if (offsets.has(offset)) throw invalid('amount argument is also pinned'); assertUint(rule.amount.maxPerCall, 256, 'amount.maxPerCall'); @@ -193,10 +206,10 @@ export function decodeNativeTerms(body: Hex): NativeTermsWire { } /** - * Wire terms back to the public NativeRule shape. Argument positions are - * reported as 32-byte head-word indexes ((offset - 4) / 32), which equal the - * argument index whenever every preceding argument is one head word. The - * stored terms do not carry the signature, so `selector` is the 4-byte hex. + * Wire terms back to the public NativeRule shape. Stored terms carry calldata + * offsets and exact words but no ABI, so pins and amount are returned in the + * raw `offset` form (never a guessed argument index) and `selector` is the + * 4-byte hex. The result re-encodes to the same terms. */ export function nativeTermsToRule(terms: NativeTermsWire, agent: Address, ref: AgenticHex): NativeRule { const rule: NativeRule = { @@ -214,13 +227,13 @@ export function nativeTermsToRule(terms: NativeTermsWire, agent: Address, ref: A if (!/^0x0{64}$/i.test(ref)) rule.ref = ref; if (terms.pins.length > 0) { rule.pins = terms.pins.map((p) => ({ - arg: offsetToHeadWord(Number(p.offset)), - expected: p.expected as AgenticHex, + offset: Number(p.offset), + expected: p.expected.toLowerCase() as AgenticHex, })); } if (terms.amount.enabled) { rule.amount = { - arg: offsetToHeadWord(Number(terms.amount.offset)), + offset: Number(terms.amount.offset), maxPerCall: terms.amount.maxPerCall, maxTotal: terms.amount.maxTotal, }; diff --git a/packages/core/src/lib/agentic/contracts/e704d5b.ts b/packages/core/src/lib/agentic/contracts/e704d5b.ts index a5fed106..2a4a33af 100644 --- a/packages/core/src/lib/agentic/contracts/e704d5b.ts +++ b/packages/core/src/lib/agentic/contracts/e704d5b.ts @@ -113,6 +113,40 @@ export const e704d5b = { encodeDeployWallet(label: string): Hex { return encodeFunctionData({ abi: AGW_FACTORY_ABI, functionName: 'deployWallet', args: [label] }); }, + /** + * Index-bound deployment for an owner calling the factory itself. + * deployWalletWithSig skips signature checks when msg.sender == intent.owner + * but still reverts IndexMismatch / IntentWalletMismatch unless the owner's + * next slot is exactly `index` and predicts to `wallet`. A concurrent + * creation therefore makes this call revert instead of deploying another + * slot while later calls in the batch target the predicted address. + */ + encodeDeployWalletAt(owner: Address, index: bigint, wallet: Address, label: string): Hex { + const zero32 = `0x${'00'.repeat(32)}` as Hex; + const zeroAddress = '0x0000000000000000000000000000000000000000' as Address; + return encodeFunctionData({ + abi: AGW_FACTORY_ABI, + functionName: 'deployWalletWithSig', + args: [ + { + owner, + wallet, + executor: zeroAddress, + index, + sessionHash: zero32, + mode: zero32, + execCalldataHash: zero32, + nonceKey: BigInt(0), + nonceSeq: BigInt(0), + grantNonce: BigInt(0), + deadline: 0, + signerChainId: BigInt(0), + }, + '0x', + label, + ], + }); + }, encodeGrantRules(session: SessionWire): Hex { return encodeFunctionData({ abi: AGW_ABI, diff --git a/packages/core/src/lib/agentic/errors.ts b/packages/core/src/lib/agentic/errors.ts index 993be42d..1c7280b9 100644 --- a/packages/core/src/lib/agentic/errors.ts +++ b/packages/core/src/lib/agentic/errors.ts @@ -36,6 +36,7 @@ export const AGENTIC_ERROR_CODE = { INDEX_RACE: 'INDEX_RACE', CREATE_PARTIAL: 'CREATE_PARTIAL', RECEIPT_MISMATCH: 'RECEIPT_MISMATCH', + RECEIPT_UNAVAILABLE: 'RECEIPT_UNAVAILABLE', AGENT_GAS_INSUFFICIENT: 'AGENT_GAS_INSUFFICIENT', WALLET_BALANCE_INSUFFICIENT: 'WALLET_BALANCE_INSUFFICIENT', GATEWAY_ALLOWANCE_INSUFFICIENT: 'GATEWAY_ALLOWANCE_INSUFFICIENT', diff --git a/packages/core/src/lib/agentic/execution/outbound.ts b/packages/core/src/lib/agentic/execution/outbound.ts index 545850e7..c4ac283e 100644 --- a/packages/core/src/lib/agentic/execution/outbound.ts +++ b/packages/core/src/lib/agentic/execution/outbound.ts @@ -12,6 +12,7 @@ import type { MoveableToken } from '../../constants/tokens'; import { ERC20_EVM, UNIVERSAL_GATEWAY_PC } from '../../constants/abi'; import type { UniversalExecuteParams, UniversalOutboundTxRequest } from '../../orchestrator/orchestrator.types'; import { isPC20Reference } from '../../orchestrator/orchestrator.types'; +import { resolveR2DestinationFundsToken } from '../../orchestrator/internals/route-handlers'; import { AgenticCapability, requireCapability } from '../capabilities'; import type { AgenticGeneration } from '../deployments'; import type { Call } from '../contracts/e704d5b'; @@ -33,6 +34,12 @@ const MULTICALL_TUPLE = [ }, ] as const; +export interface DestinationCall { + to: Address; + value: bigint; + data: Hex; +} + export interface ComposedOutbound { chain: CHAIN; destinationAccount: Address; @@ -44,19 +51,51 @@ export interface ComposedOutbound { request: UniversalOutboundTxRequest; /** The wallet's call into the gateway. */ gatewayCall: Call; - destinationCalls: { to: Address; value: bigint; data: Hex }[]; + destinationCalls: DestinationCall[]; } -/** Destination calls carried in the outbound multicall payload. */ -export function destinationCalls(params: UniversalExecuteParams): { to: Address; value: bigint; data: Hex }[] { - const target = params.to as { address: string; chain: CHAIN }; +/** + * The calls the wallet's destination account (CEA) executes, built exactly as + * core's Route 2 builds them for an ordinary account (buildR2CeaPayloadEvm): + * - explicit call arrays are used as given (the caller handles transfers); + * - with ERC-20 funds, a transfer(target, amount) is prepended to a single + * call, or is the whole payload for a transfer-only send; + * - native value (and native funds) goes to the target with the call, or as + * a value-only call; a value transfer to the CEA itself is skipped. + * Every encoded call names the requested target, so a response never reports + * a delivery the request does not instruct. + */ +export function destinationCalls( + params: UniversalExecuteParams, + ctx: { cea: Address; fundsToken?: MoveableToken } +): DestinationCall[] { + const target = getAddress((params.to as { address: string }).address); if (Array.isArray(params.data)) { return params.data.map((c) => ({ to: getAddress(c.to), value: c.value ?? BigInt(0), data: c.data })); } - if (params.data && params.data !== '0x') { - return [{ to: getAddress(target.address), value: params.value ?? BigInt(0), data: params.data }]; + const amount = params.funds?.amount ?? BigInt(0); + const token = ctx.fundsToken; + const erc20 = amount > BigInt(0) && token && token.mechanism !== 'native'; + const nativeFunds = amount > BigInt(0) && token?.mechanism === 'native' ? amount : BigInt(0); + const value = params.value ?? BigInt(0); + const calls: DestinationCall[] = []; + if (erc20) { + calls.push({ + to: getAddress((token as MoveableToken).address), + value: BigInt(0), + data: encodeFunctionData({ abi: ERC20_EVM, functionName: 'transfer', args: [target, amount] }), + }); + } + const data = params.data && params.data !== '0x' ? params.data : undefined; + if (data) { + calls.push({ to: target, value: value + nativeFunds, data }); + } else { + const forward = value > BigInt(0) ? value : nativeFunds; + if (forward > BigInt(0) && target !== ctx.cea) { + calls.push({ to: target, value: forward, data: '0x' }); + } } - return []; + return calls; } /** @@ -65,14 +104,15 @@ export function destinationCalls(params: UniversalExecuteParams): { to: Address; * - payload = UEA_MULTICALL ‖ abi.encode(Multicall[1..10]) executed by the AGW's CEA * - value = protocolFee + maxPCForGas, paid from the AGW's PC * The destination account is resolved from the AGW, never from the signer. - * No approval is added here: agent sends rely on an owner-set allowance. + * The SDK never writes a gateway allowance on either door: the gateway pulls + * from an allowance the owner set separately with an ordinary send. */ export async function composeOutbound( runtime: AgenticRuntime, gen: AgenticGeneration, wallet: Address, params: UniversalExecuteParams, - opts: { ruleAsset?: Address; requireCalls: boolean } + opts: { ruleAsset?: Address; door: 'owner' | 'agent' } ): Promise { requireCapability(gen.capabilities, AgenticCapability.UNIVERSAL_EVM_OUTBOUND); const target = params.to as { address: string; chain: CHAIN }; @@ -87,29 +127,26 @@ export async function composeOutbound( 'SVM destinations are not enabled for agentic wallets (A05/A07, H4.4)' ); } - const calls = destinationCalls(params); - if (opts.requireCalls && calls.length === 0) { - throw new AgenticError( - AGENTIC_ERROR_CODE.INVALID_RULE, - 'an agent outbound must carry at least one destination call (URP requires a multicall payload)' - ); - } - if (calls.length > MAX_DESTINATION_CALLS) { - throw new AgenticError( - AGENTIC_ERROR_CODE.INVALID_RULE, - `at most ${MAX_DESTINATION_CALLS} destination calls per outbound` - ); - } const funds = params.funds; if (funds && isPC20Reference(funds.token)) { throw capabilityUnavailable('pc20Outbound', 'PC20 tokens are not supported through an agentic wallet'); } + // An omitted funds.token means the destination chain's native token, as in Route 2. + const fundsToken: MoveableToken | undefined = funds?.amount + ? funds.token + ? resolveR2DestinationFundsToken(funds.token as MoveableToken, chain, runtime.network) + : { symbol: 'native', decimals: 18, address: '0x0000000000000000000000000000000000000000', mechanism: 'native' } + : undefined; + // Burn token and amount, as Route 2 sizes them for an ordinary account. let token: Address; let amount = BigInt(0); if (funds?.amount) { token = runtime.resolvePrc20(funds.token as MoveableToken | undefined, chain); amount = funds.amount; + } else if ((params.value ?? BigInt(0)) > BigInt(0)) { + token = runtime.resolvePrc20(undefined, chain); + amount = params.value as bigint; } else if (opts.ruleAsset) { token = getAddress(opts.ruleAsset); } else { @@ -124,7 +161,31 @@ export async function composeOutbound( const resolved = await runtime.resolveCEA(wallet, chain); const cea = getAddress(resolved.cea); - const isDeployed = resolved.isDeployed; + const calls = destinationCalls(params, { cea, fundsToken }); + if (calls.length === 0) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'this outbound carries no destination call; parking funds in the wallet’s destination account is not supported', + { hint: 'Name a recipient other than the wallet’s own destination account, or add calldata.' } + ); + } + if (calls.length > MAX_DESTINATION_CALLS) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + `at most ${MAX_DESTINATION_CALLS} destination calls per outbound` + ); + } + if (opts.door === 'agent') { + const bare = calls.findIndex((c) => (c.data.length - 2) / 2 < 4); + if (bare >= 0) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + `destination call ${bare} has no function selector; the rules policy only admits allow-listed calls`, + { hint: 'A value-only destination transfer is not representable in an agent rule.' } + ); + } + } + const quote = await runtime.quoteOutbound(token, params.gasLimit ?? BigInt(0), chain); if (quote.nativeValueForGas <= BigInt(0)) { throw new AgenticError( @@ -134,10 +195,7 @@ export async function composeOutbound( } const maxPCForGas = quote.nativeValueForGas; const value = quote.protocolFee + maxPCForGas; - const payload = - calls.length === 0 - ? ('0x' as Hex) - : concat([UEA_MULTICALL_PREFIX, encodeAbiParameters(MULTICALL_TUPLE, [calls])]); + const payload = concat([UEA_MULTICALL_PREFIX, encodeAbiParameters(MULTICALL_TUPLE, [calls])]); const request: UniversalOutboundTxRequest = { recipient: '0x', token, @@ -156,7 +214,7 @@ export async function composeOutbound( return { chain, destinationAccount: cea, - destinationAccountDeployed: isDeployed, + destinationAccountDeployed: resolved.isDeployed, token, amount, value, @@ -165,28 +223,3 @@ export async function composeOutbound( destinationCalls: calls, }; } - -/** - * Owner door: approval and outbound in one atomic owner batch. The approval is - * `currentAllowance + amount`, so after the gateway pulls `amount` any standing - * allowance the owner set for agents is left exactly as it was. - */ -export function ownerOutboundCalls( - gen: AgenticGeneration, - out: ComposedOutbound, - currentAllowance: bigint -): Call[] { - if (out.amount === BigInt(0)) return [out.gatewayCall]; - return [ - { - target: out.token, - value: BigInt(0), - data: encodeFunctionData({ - abi: ERC20_EVM, - functionName: 'approve', - args: [gen.addresses.gateway, currentAllowance + out.amount], - }), - }, - out.gatewayCall, - ]; -} diff --git a/packages/core/src/lib/agentic/execution/send.ts b/packages/core/src/lib/agentic/execution/send.ts index 00cc99cb..0b9e749c 100644 --- a/packages/core/src/lib/agentic/execution/send.ts +++ b/packages/core/src/lib/agentic/execution/send.ts @@ -9,6 +9,7 @@ import type { UniversalTxResponse, } from '../../orchestrator/orchestrator.types'; import { isChainTarget } from '../../orchestrator/route-detector'; +import { getPushChainForNetwork, isPushChain } from '../../orchestrator/internals/helpers'; import { AgenticCapability, requireCapability } from '../capabilities'; import type { AgenticExecutionContext } from '../context'; import type { Call, UniversalConfigReadE704d5b } from '../contracts/e704d5b'; @@ -23,7 +24,7 @@ import { adaptAgenticResponse } from '../response'; import type { AgenticRuntime } from '../runtime'; import type { AgenticHex, AgenticProgressHook } from '../agentic.types'; import { guardAgenticSendParams } from './guards'; -import { composeOutbound, ownerOutboundCalls } from './outbound'; +import { composeOutbound } from './outbound'; const MODE_UNIVERSAL = 0; const VM_EVM = 0; @@ -67,6 +68,26 @@ async function enforceSignerGas(runtime: AgenticRuntime, gasLimit: bigint | unde } } +/** + * A ChainTarget naming the connected Push chain is a native send, exactly like + * a bare address (core's route detector treats it the same way). A ChainTarget + * naming a different Push network is refused rather than routed outbound. + */ +function normalizePushDestination(p: UniversalExecuteParams, runtime: AgenticRuntime): UniversalExecuteParams { + if (!isChainTarget(p.to)) return p; + const chain = p.to.chain; + if (chain === getPushChainForNetwork(runtime.network)) { + return { ...p, to: getAddress(p.to.address) }; + } + if (isPushChain(chain)) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + `destination ${chain} is a Push chain other than the connected network (${runtime.network})` + ); + } + return p; +} + function toCalls(params: UniversalExecuteParams): Call[] { if (Array.isArray(params.data)) { return params.data.map((c) => ({ target: getAddress(c.to), value: c.value ?? BigInt(0), data: c.data })); @@ -93,7 +114,7 @@ export async function agenticSend( ): Promise { assertCanSign(runtime, 'sendTransaction'); guardAgenticSendParams(params); - const p = params as UniversalExecuteParams; + const p = normalizePushDestination(params as UniversalExecuteParams, runtime); const hook: AgenticProgressHook | undefined = options?.progressHook ?? p.progressHook; const gen = actx.generation; const wallet = actx.wallet; @@ -159,10 +180,7 @@ export async function agenticSend( maxPCPerCall = cfg.maxPCPerCall; expectedCEA = getAddress(cfg.expectedCEA); } - const out = await composeOutbound(runtime, gen, wallet, p, { - ruleAsset, - requireCalls: actx.door === 'agent', - }); + const out = await composeOutbound(runtime, gen, wallet, p, { ruleAsset, door: actx.door }); outboundChain = out.chain; meta = { route: 'UOA_TO_CEA', destinationAccount: out.destinationAccount }; const [walletPc, tokenBalance, allowance] = await Promise.all([ @@ -188,6 +206,17 @@ export async function agenticSend( `wallet ${wallet} holds ${tokenBalance} of ${out.token}; this outbound burns ${out.amount}` ); } + // Both doors only consume an allowance the owner set separately; the SDK + // never writes one (a write from a stale read could restore revoked authority). + if (out.amount > allowance) { + throw new AgenticError( + AGENTIC_ERROR_CODE.GATEWAY_ALLOWANCE_INSUFFICIENT, + `the gateway may pull ${allowance} of ${out.token} from the wallet; this outbound needs ${out.amount}`, + { + hint: 'Set a bounded allowance first with an owner-door send: approve(gateway, cap) on the token (approve(gateway, 0) removes it).', + } + ); + } if (actx.door === 'agent') { if (expectedCEA && expectedCEA !== out.destinationAccount) { throw new AgenticError( @@ -202,23 +231,16 @@ export async function agenticSend( `this outbound needs ${out.value} PC wei but the rule caps the wallet's PC per call at ${maxPCPerCall}` ); } - if (out.amount > allowance) { - throw new AgenticError( - AGENTIC_ERROR_CODE.GATEWAY_ALLOWANCE_INSUFFICIENT, - `the gateway may pull ${allowance} of ${out.token} from the wallet; this outbound needs ${out.amount}`, - { - hint: 'The owner sets a bounded allowance with an owner-door send: approve(gateway, cap) on the token. The agent path never approves.', - } - ); - } wrappedData = gen.contracts.encodeExecuteAsAgent(rulesId as Hex, out.gatewayCall); } else { - wrappedData = gen.contracts.encodeExecute(ownerOutboundCalls(gen, out, allowance)); + wrappedData = gen.contracts.encodeExecute([out.gatewayCall]); } - const first = out.destinationCalls[0]; - logical = first - ? { to: first.to, data: first.data, value: first.value } - : { to: (p.to as { address: string }).address, data: '0x', value: BigInt(0) }; + // The requested target; the encoded destination calls always name it. + logical = { + to: getAddress((p.to as { address: string }).address), + data: typeof p.data === 'string' ? p.data : '0x', + value: p.value ?? BigInt(0), + }; } await enforceSignerGas(runtime, signerFields(p).gasLimit); diff --git a/packages/core/src/lib/agentic/management/common.ts b/packages/core/src/lib/agentic/management/common.ts index 94974baf..5a67bd01 100644 --- a/packages/core/src/lib/agentic/management/common.ts +++ b/packages/core/src/lib/agentic/management/common.ts @@ -79,8 +79,23 @@ export async function confirmedLogs( runtime: AgenticRuntime, tx: UniversalTxResponse ): Promise<{ logs: Log[]; hashes: Hex[] }> { - const receipt = await tx.wait(); const hashes = (tx.transactionHashes ?? [tx.hash as Hex]) as Hex[]; + const unavailable = (cause: unknown) => + new AgenticError( + AGENTIC_ERROR_CODE.RECEIPT_UNAVAILABLE, + `submitted ${tx.hash} but could not read its receipt: ${cause instanceof Error ? cause.message : String(cause)}`, + { + hint: 'The transaction may still land. Check these hashes before retrying.', + details: { txHash: tx.hash, transactionHashes: hashes }, + cause, + } + ); + let receipt; + try { + receipt = await tx.wait(); + } catch (cause) { + throw unavailable(cause); + } if (hashes.length === 1) { if (receipt.status !== 1) { throw new AgenticRevertError(`Push transaction ${tx.hash} reverted`, { @@ -91,7 +106,12 @@ export async function confirmedLogs( } const logs: Log[] = []; for (const hash of hashes) { - const r = await runtime.reader.getTransactionReceipt({ hash }); + let r; + try { + r = await runtime.reader.getTransactionReceipt({ hash }); + } catch (cause) { + throw unavailable(cause); + } if (r.status !== 'success') { throw new AgenticRevertError(`Push transaction ${hash} reverted`, { transactionHashes: hashes }); } diff --git a/packages/core/src/lib/agentic/management/create.ts b/packages/core/src/lib/agentic/management/create.ts index 44b3ba75..a48e0e91 100644 --- a/packages/core/src/lib/agentic/management/create.ts +++ b/packages/core/src/lib/agentic/management/create.ts @@ -1,4 +1,4 @@ -import { getAddress, type Address, type Hex } from 'viem'; +import { getAddress, type Address, type Hex, type Log } from 'viem'; import { PROGRESS_HOOK } from '../../progress-hook/progress-hook.types'; import type { MultiCall } from '../../orchestrator/orchestrator.types'; import { PushChainBatchExecutionError } from '../../orchestrator/internals/errors'; @@ -96,7 +96,8 @@ export async function createWallet( computeRulesId({ validator: gen.addresses.sessionValidator, agent: p.agent, grantNonce: BigInt(i) }) ); const calls: MultiCall[] = [ - { to: gen.addresses.factory, value: BigInt(0), data: gen.contracts.encodeDeployWallet(label) }, + // Index-bound: reverts (nothing committed) if another creation took this slot. + { to: gen.addresses.factory, value: BigInt(0), data: gen.contracts.encodeDeployWalletAt(owner, index, wallet, label) }, ...prepared.map((p) => ({ to: wallet, value: BigInt(0), @@ -111,7 +112,7 @@ export async function createWallet( try { tx = await sendOwnerCalls(runtime, calls, hook); } catch (err) { - const wrapped = await partialCreateError(runtime, gen, wallet, Number(index), err); + const wrapped = await createFailure(runtime, gen, wallet, Number(index), err); emitFailure(runtime, hook, wrapped); throw wrapped; } @@ -120,7 +121,7 @@ export async function createWallet( try { ({ logs } = await confirmedLogs(runtime, tx)); } catch (err) { - const wrapped = await partialCreateError(runtime, gen, wallet, Number(index), err); + const wrapped = await createFailure(runtime, gen, wallet, Number(index), err); emitFailure(runtime, hook, wrapped); throw wrapped; } @@ -156,7 +157,15 @@ function sameIds(a: readonly Hex[], b: readonly Hex[]): boolean { return a.length === b.length && a.every((x, i) => x.toLowerCase() === b[i].toLowerCase()); } -async function partialCreateError( +const RACE_ERRORS = new Set(['IndexMismatch', 'IntentWalletMismatch']); + +/** + * Turn a create failure into an exact report. What committed is derived from + * THIS operation's own receipts, never from a later state read; when those + * receipts cannot be fetched the outcome is reported as unknown so callers do + * not retry a creation that may have landed. + */ +async function createFailure( runtime: AgenticRuntime, gen: ReturnType, wallet: Address, @@ -165,42 +174,66 @@ async function partialCreateError( ): Promise { const wrapped = wrapSendError(err); const batch = err instanceof PushChainBatchExecutionError ? err : undefined; - const hashes = (batch?.transactionHashes ?? - (wrapped as { transactionHashes?: Hex[] }).transactionHashes ?? - []) as Hex[]; - if (hashes.length === 0) return wrapped; - // Something committed. Re-read chain state rather than trusting the error. - let walletDeployed = false; - let grantedRulesIds: Hex[] = []; - try { - walletDeployed = !!(await runtime.reader.getCode({ address: wallet }))?.slice(2); - if (walletDeployed) { - const snap = await Snapshot.at(runtime.reader); - grantedRulesIds = [ - ...(await snap.read(gen.addresses.sessionEngine, gen.contracts.abis.engine, 'getPermissionIDs', [ - wallet, - ])), - ]; + const confirmed = (batch?.transactionHashes ?? []) as Hex[]; + const pending = batch?.pendingTransactionHash; + const receiptUnavailable = + wrapped instanceof AgenticError && wrapped.code === AGENTIC_ERROR_CODE.RECEIPT_UNAVAILABLE; + + // The index-bound deploy reverted: another creation took the slot first and + // nothing from this call committed. + const decodedName = (wrapped as { decodedError?: { name?: string } }).decodedError?.name; + if (confirmed.length === 0 && !pending && decodedName && RACE_ERRORS.has(decodedName)) { + return new AgenticError( + AGENTIC_ERROR_CODE.INDEX_RACE, + `wallet slot ${index} (${wallet}) was taken by a concurrent creation; nothing was committed`, + { hint: 'Retry agentic.create; it re-reads the next slot.', details: { wallet, index, committed: false }, cause: wrapped } + ); + } + if (confirmed.length === 0 && !pending && !receiptUnavailable) { + // Nothing was confirmed (pre-broadcast failure or a reverted atomic batch). + return wrapped; + } + + let walletDeployed: boolean | 'unknown' = 'unknown'; + let grantedRulesIds: Hex[] | undefined; + let recoveryError: string | undefined; + if (!receiptUnavailable) { + try { + const logs: Log[] = []; + for (const hash of confirmed) { + const r = await runtime.reader.getTransactionReceipt({ hash }); + if (r.status === 'success') logs.push(...(r.logs as Log[])); + } + const deployed = gen.contracts + .parseWalletDeployed(logs, gen.addresses.factory) + .some((d) => d.wallet === wallet); + grantedRulesIds = gen.contracts.parseRulesGranted(logs, wallet).map((g) => g.rulesId); + // A pending hash may itself be the deployment; only a confirmed deploy is certain. + walletDeployed = deployed ? true : pending ? 'unknown' : false; + } catch (e) { + recoveryError = e instanceof Error ? e.message : String(e); } - } catch { - // keep what we know; the hashes below are authoritative for retry decisions } - // A reverted atomic transaction committed nothing: report the revert itself. - if (!batch && !walletDeployed) return wrapped; + const hint = + walletDeployed === true + ? `Wallet ${wallet} is deployed. Do not call create again; once any pending hash settles, finish with client.agentic.wallet('${wallet}').rules.add().` + : walletDeployed === false + ? 'No wallet was deployed by this call; it is safe to retry.' + : 'The outcome is unknown. Do not retry create until the listed hashes are reconciled (client.agentic.list() shows deployed wallets).'; return new AgenticError( AGENTIC_ERROR_CODE.CREATE_PARTIAL, `agentic.create did not complete: ${(wrapped as Error)?.message ?? String(err)}`, { - hint: walletDeployed - ? `Wallet ${wallet} is deployed. Do not call create again; finish with client.agentic.wallet('${wallet}').rules.add().` - : 'No wallet was deployed. Check the pending hash (if any) before retrying.', + hint, details: { wallet, index, walletDeployed, grantedRulesIds, - confirmedHashes: hashes, - pendingHash: batch?.pendingTransactionHash, + confirmedHashes: confirmed, + pendingHash: pending, + ...(receiptUnavailable ? { submitted: (wrapped as AgenticError).details } : {}), + ...(recoveryError ? { recoveryError } : {}), }, cause: wrapped, } diff --git a/packages/core/src/lib/agentic/response.ts b/packages/core/src/lib/agentic/response.ts index 86f6a22e..e0fe8348 100644 --- a/packages/core/src/lib/agentic/response.ts +++ b/packages/core/src/lib/agentic/response.ts @@ -97,17 +97,17 @@ export async function adaptTrackedResponse( if (outbound) { const out = decodeOutbound(outbound.data); const chain = await tokenChain(runtime, out.token); - const first = out.calls[0]; + // The decoded wallet call is authoritative: core may have inferred a + // Push-only route from an incomplete Cosmos record, which would stop + // wait() from polling the destination leg. return adaptAgenticResponse(resp, { wallet, door, rulesId, chainNamespace: chain, - logical: first - ? { to: first.to, data: first.data, value: first.value } - : { to: wallet, data: '0x', value: BigInt(0) }, - route: resp.route ?? 'UOA_TO_CEA', - chain: resp.chain ?? (chain as CHAIN | undefined), + logical: logicalOutboundCall(out.calls, wallet), + route: 'UOA_TO_CEA', + chain: (chain as CHAIN | undefined) ?? resp.chain, }); } const single = calls.length === 1 ? calls[0] : undefined; @@ -122,6 +122,26 @@ export async function adaptTrackedResponse( }); } +const ERC20_TRANSFER = '0xa9059cbb'; + +/** + * The requested destination call, recovered from the payload the wallet's CEA + * runs: the last call (a prepended token transfer precedes the user's call); + * for a transfer-only payload, the transfer's recipient. + */ +function logicalOutboundCall( + calls: { to: Address; value: bigint; data: Hex }[], + wallet: Address +): { to: string; data: string; value: bigint } { + const last = calls[calls.length - 1]; + if (!last) return { to: wallet, data: '0x', value: BigInt(0) }; + if (calls.length === 1 && last.data.toLowerCase().startsWith(ERC20_TRANSFER) && last.data.length === 2 + 8 + 128) { + const [recipient] = decodeAbiParameters([{ type: 'address' }, { type: 'uint256' }], `0x${last.data.slice(10)}`); + return { to: getAddress(recipient), data: '0x', value: BigInt(0) }; + } + return { to: last.to, data: last.data, value: last.value }; +} + function decodeOutbound(data: Hex): { token: Address; calls: { to: Address; value: bigint; data: Hex }[]; diff --git a/packages/core/src/lib/agentic/revert.ts b/packages/core/src/lib/agentic/revert.ts index 70bf4e59..c2ea4b1e 100644 --- a/packages/core/src/lib/agentic/revert.ts +++ b/packages/core/src/lib/agentic/revert.ts @@ -84,7 +84,9 @@ export function decodeAgwErrorData(data: Hex): DecodedErrorPayload | undefined { // try the next ABI } } - return undefined; + // Arguments lost (e.g. a node rendered them as text): name the error by its selector. + const name = ERROR_NAMES.get(selector); + return name ? { name, selector, hint: 'Error arguments were not available.' } : undefined; } export function decodeAgenticRevert(err: unknown): DecodedErrorPayload | undefined { From 9e16b23a76816176dca20793d74df5a5548a497e Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Sat, 3 Oct 2026 20:47:09 +0530 Subject: [PATCH 12/68] docs(agw): record implementation review and its resolution Adds the independent review package (findings, reproductions, evidence) and a review-response section in the handoff mapping R1-R7 to fixes and evidence, with the remaining limits. Status matrix updated; wording now says no compatible deployment has been verified or registered. --- plan/agw/implementation-review-handoff.md | 29 +- plan/agw/implementation-review/build.log | 13 + .../e2e-agw-manifest.log | 24 + .../e2e-all-manifest.log | 79 ++ plan/agw/implementation-review/evidence.json | 97 ++ plan/agw/implementation-review/lint.log | 1157 +++++++++++++++++ .../agw/implementation-review/local-races.log | 44 + .../implementation-review/local-races.spec.ts | 64 + .../agw/implementation-review/local-suite.log | 10 + .../agw/implementation-review/regressions.log | 151 +++ .../implementation-review/regressions.spec.ts | 82 ++ plan/agw/implementation-review/review.md | 113 ++ .../implementation-review/reviewer.config.cjs | 11 + plan/agw/implementation-review/types-lib.log | 0 plan/agw/implementation-review/types-spec.log | 0 plan/agw/implementation-review/unit-suite.log | 163 +++ plan/agw/implementation-status.md | 8 +- 17 files changed, 2037 insertions(+), 8 deletions(-) create mode 100644 plan/agw/implementation-review/build.log create mode 100644 plan/agw/implementation-review/e2e-agw-manifest.log create mode 100644 plan/agw/implementation-review/e2e-all-manifest.log create mode 100644 plan/agw/implementation-review/evidence.json create mode 100644 plan/agw/implementation-review/lint.log create mode 100644 plan/agw/implementation-review/local-races.log create mode 100644 plan/agw/implementation-review/local-races.spec.ts create mode 100644 plan/agw/implementation-review/local-suite.log create mode 100644 plan/agw/implementation-review/regressions.log create mode 100644 plan/agw/implementation-review/regressions.spec.ts create mode 100644 plan/agw/implementation-review/review.md create mode 100644 plan/agw/implementation-review/reviewer.config.cjs create mode 100644 plan/agw/implementation-review/types-lib.log create mode 100644 plan/agw/implementation-review/types-spec.log create mode 100644 plan/agw/implementation-review/unit-suite.log diff --git a/plan/agw/implementation-review-handoff.md b/plan/agw/implementation-review-handoff.md index 8f3f2d22..e85e92cf 100644 --- a/plan/agw/implementation-review-handoff.md +++ b/plan/agw/implementation-review-handoff.md @@ -113,11 +113,11 @@ Committed vectors are contract-computed (`getPermissionId`, `predictWallet`, a r **Mocks (unit).** Chain reads (`__tests__/fake-chain.ts`, an in-memory model of the views) and the signer transport (`mock-runtime.ts`). These test SDK logic only: selection, error mapping, call shapes, ordering, consistency checks and pre-signature guards. -**Live.** None. No transaction was broadcast to any testnet. +**Live.** None. No transaction was broadcast to any testnet. No compatible deployment has been verified or registered; that is evidence of unavailable support, not proof that none exists anywhere. ## Blockers and placeholders -- **A07 — no verified compatible deployment.** Every AGW call on a real network fails with `GENERATION_UNSUPPORTED`. The E2E group fails its gate, and preflight refuses to fund. To onboard: +- **A07 — no compatible deployment has been verified or registered.** Every AGW call on a real network fails with `GENERATION_UNSUPPORTED`. The E2E group fails its gate, and preflight refuses to fund. To onboard: 1. Write a manifest per `__e2e__/agw/_manifest.ts`. 2. Add a verified entry to `VERIFIED_DEPLOYMENTS` in `deployments.ts`, and populate `CONSTANTS.AGENTIC` from it. 3. Pass `AGW_DEPLOYMENT_MANIFEST` in `.github/workflows/e2e.yml`. It is not wired there yet. @@ -132,14 +132,14 @@ Committed vectors are contract-computed (`getPermissionId`, `predictWallet`, a r ## Areas most needing review 1. **`CHAIN.WEB2` / `READ.WEB2` value change** from `'web2:https'` to `'web2'`. Spec alias semantics require it, and comparisons against the constants still work. Code comparing against the old literal would break. -2. **Owner-door outbound approval.** It approves `currentAllowance + amount`, then sends, in one owner batch. A standing agent allowance is preserved. The agent path never approves. +2. **No SDK allowance writes.** Neither door approves the gateway; both consume an allowance the owner set with an ordinary owner-door send, and fail with `GATEWAY_ALLOWANCE_INSUFFICIENT` before signing otherwise (review R4). 3. **Checkpoint semantics of batched writes.** - Multi-ID revoke and multi-rule add use one owner `execute` batch, for atomicity and one signature. - This adds one OWNER_ACTION tick per call on top of RULES_REVOKED / RULES_GRANTED. - Single-ID revoke and single-rule add stay direct (one tick). - `create` uses the signer's batch, which is sequential on a 7702-less Push EOA, reported as `CREATE_PARTIAL`. 4. **`create` index race.** It is detected after the fact (`INDEX_RACE`). Concurrent creates by the same owner can land grants on the raced wallet, and the error details say so. -5. **Decoded native pins/amount report `arg` as a head-word index** (`(offset - 4) / 32`). This is exact only when every preceding argument is one head word. The stored terms carry no signature. +5. **Decoded native pins/amount use the raw `{ offset, expected }` form.** Stored terms carry no ABI, so decoding never invents an argument index; the encoder accepts that form, so decoded rules re-encode exactly. This extends the page-5 `NativeRule` type and needs product sign-off (review R5). 6. **Agent gas guard.** - It mirrors R1's fee-lock condition, using R1's default 1e7 gas estimate when no `gasLimit` is given. - Formula: `balance < (gasLimit ?? 1e7) * gasPrice`. @@ -159,3 +159,24 @@ AGW_LOCAL_DIR=$OUT node node_modules/jest/bin/jest.js --config packages/core/jes ``` `prepare.sh` reads the AGW repo with `git archive`/`ls-tree` only, and never touches its working tree. The harness uses anvil's public development keys and broadcasts only to the local anvil it spawns. + +## Review response (2026-10-03) + +The independent review in [implementation-review/review.md](implementation-review/review.md) reported seven issues against `3008497`. All seven were confirmed and fixed. Its two real-contract races pass unmodified against the fix (R1), or with the throw expected (R4); both are ported into `__agw-local__/agw-local-races.spec.ts`. Its SDK-boundary regressions are ported into the unit suites, adapted where the fix changed the API (`ownerOutboundCalls` removed, composer options, offset-form pins). + +| Finding | Resolution | Evidence | +| --- | --- | --- | +| R1 create race grants on the wrong wallet | The deploy call is `deployWalletWithSig(intent{owner, index, wallet}, 0x, label)` sent by the owner itself: no signature, but the factory reverts `IndexMismatch`/`IntentWalletMismatch` if the slot moved, so a batch that would grant on a raced address reverts first. Mapped to `INDEX_RACE` with `committed: false` | Real contracts (sequential path): no permissions on either wallet, retry succeeds. Unit: deploy call shape, race mapping. Atomic 7702/UEA paths rely on the same contract check; not locally exercised | +| R4 owner outbound restores revoked allowance; uint256.max overflow | Removed the read-modify-write approval. Both doors only consume an existing allowance | Real contracts: an allowance revoked after the read stays 0 and the pull reverts `LowAllowance`. Unit: no approve call, insufficient allowance refused, unlimited allowance accepted | +| R2 explicit Push ChainTarget routed outbound | A ChainTarget on the connected Push chain is normalized to the native path. Another Push network is refused | Unit: agent and owner, `PUSH_TESTNET_DONUT`/`PUSH_TESTNET` alias, `PUSH_MAINNET` refusal | +| R3 transfer-only outbound drops the recipient | Destination calls are built as core Route 2 builds them: ERC-20 `transfer(target)`, native value to the target, explicit arrays as given, and the burn sized from `value` when there are no funds. A request with no destination call (CEA parking) is refused, and the agent door refuses selector-less destination calls before signing | Unit: ERC-20 transfer payload names the recipient; value-only burn and forward; parking refused. Recipient-balance acceptance still needs a live run | +| R5 decoded pins misrepresented | Decoder returns `{ offset, expected }`. Encoder accepts it, plus canonical 32-byte words in argument form | Unit: static-array round trip, address-pin re-encode, offset validation; harness decode assertion updated | +| R6 replay keeps a Push-only route | A decoded AGW outbound sets `UOA_TO_CEA` and its chain authoritatively | Unit at the adapter boundary. The delayed-Cosmos path through response-builder/`wait()` is not exercised (needs a live or deeper mocked run) | +| R7 recovery reports unknown as not deployed | Committed state is derived from this call's own receipts. `walletDeployed` is `true`, `false` or `'unknown'` (pending hash or failed recovery reads, with `recoveryError`). A post-submit receipt failure keeps the hash (`RECEIPT_UNAVAILABLE`, surfaced inside `CREATE_PARTIAL`) | Unit: receipts-derived recovery, pending hash, failed recovery read, lost receipt | + +Also from this pass: +- Revert decoding now names an error by selector when its arguments were lost in a node's text rendering. That is how the R1 `IndexMismatch` is recognized on the sequential path. +- An omitted `funds.token` on an outbound means the destination's native token, as in Route 2. +- The E2E positive outbound uses the explicit call-array form and independently checks the wallet CEA's Sepolia balance. Caller/event correlation for the executing CEA is still to be added before a funded run. + +Counts after the fixes: unit **1,899 passed, 12 skipped** (110 suites passed, 1 skipped; agentic 139); local harness **34 passed in 4 suites**. Library/spec typecheck and build pass. Lint has no errors in changed code (7 pre-existing errors elsewhere). E2E manifests are unchanged (agw 21, all 76). diff --git a/plan/agw/implementation-review/build.log b/plan/agw/implementation-review/build.log new file mode 100644 index 00000000..cbb0d301 --- /dev/null +++ b/plan/agw/implementation-review/build.log @@ -0,0 +1,13 @@ + +> nx run core:build + +Compiling TypeScript files for project "core"... +Done compiling TypeScript files for project "core". +(node:62204) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. +(Use `node --trace-warnings ...` to show where the warning was created) + + + + NX Successfully ran target build for project core + + diff --git a/plan/agw/implementation-review/e2e-agw-manifest.log b/plan/agw/implementation-review/e2e-agw-manifest.log new file mode 100644 index 00000000..f173a92d --- /dev/null +++ b/plan/agw/implementation-review/e2e-agw-manifest.log @@ -0,0 +1,24 @@ +✓ agw-create-bare 1 test +✓ agw-create-rules 1 test +✓ agw-funding-pc 1 test +✓ agw-funding-allowance 1 test +✓ agw-native-agent 1 test +✓ agw-native-owner 1 test +✓ agw-native-over-cap 1 test +✓ agw-native-stranger 1 test +✓ agw-native-revoked 1 test +✓ agw-native-expired 1 test +✓ agw-lifecycle-add 1 test +✓ agw-lifecycle-update 1 test +✓ agw-lifecycle-checkpoints 1 test +✓ agw-lifecycle-revoke-all 1 test +✓ agw-universal-outbound 1 test +✓ agw-universal-dest-revert 1 test +✓ agw-identity-evm 1 test +✓ agw-identity-first-use 1 test +✓ agw-identity-solana 1 test +✓ agw-responses-hooks 1 test +✓ agw-responses-replay 1 test + +21 scenarios, 7 spec files, 21 distinct tests. +Manifest is consistent with the specs. diff --git a/plan/agw/implementation-review/e2e-all-manifest.log b/plan/agw/implementation-review/e2e-all-manifest.log new file mode 100644 index 00000000..dfa5f250 --- /dev/null +++ b/plan/agw/implementation-review/e2e-all-manifest.log @@ -0,0 +1,79 @@ +✓ smoke-uea-derive-evm 1 test +✓ smoke-read-track-lookup 1 test +✓ smoke-cea-derive-evm 1 test +✓ smoke-roundtrip-evm 1 test +✓ smoke-roundtrip-svm 1 test +✓ smoke-cea-pda-svm 1 test +✓ smoke-gasfee-reads 2 tests +✓ smoke-gas-sizer 2 tests +✓ smoke-pc20-registry 2 tests +✓ smoke-pc20-resolve 1 test +✓ evm-r1-transfer 1 test +✓ evm-r1-funds-usdt 1 test +✓ evm-r1-funds-native 1 test +✓ evm-r1-value-funds-data 1 test +✓ evm-r1-bridge-multicall 1 test +✓ evm-r1-fresh-value-native 1 test +✓ evm-r2-funds-erc20 1 test +✓ evm-r2-payload 1 test +✓ evm-r2-multicall 1 test +✓ evm-r2-funds-payload 1 test +✓ evm-r2-native-funds 1 test +✓ evm-r2-native-funds-payload 1 test +✓ evm-r3-funds-erc20 1 test +✓ evm-r3-payload 1 test +✓ evm-r3-multicall 1 test +✓ evm-r3-funds-payload 1 test +✓ evm-r3-native-funds 1 test +✓ evm-r3-eoa-native-funds 1 test +✓ svm-r1-transfer 1 test +✓ svm-r1-funds-sol-self 1 test +✓ svm-r1-value-self 1 test +✓ svm-r1-data-contract 1 test +✓ svm-r1-fresh-key-repro 1 test +✓ svm-r2-funds-sol 1 test +✓ svm-r2-funds-spl 1 test +✓ svm-r2-payload-cpi 1 test +✓ svm-r2-sol-cpi 1 test +✓ svm-r3-drain-sol 1 test +✓ svm-r3-drain-spl 1 test +✓ pc20-export-deployed-wrapper 1 test +✓ pc20-export-predicts-wrapper 1 test +✓ pc20-inbound-burn-unlock 1 test +✓ pc20-r3-cea-burn 1 test +✓ pc20-svm-r1-direct-burn 1 test +✓ pc20-svm-r3-cea-ata-burn 1 test +✓ push-send-transaction 1 test +✓ push-value-own-uea 1 test +✓ push-multicall-no-funds 1 test +✓ push-track-r1-sepolia-parity 1 test +✓ push-track-r3-funds-roundtrip 1 test +✓ push-track-source-leg-hashes 2 tests +✓ xc-multi-child-r3 1 test +✓ xc-fresh-wallet-r3 1 test +✓ xc-peth-bridge-back 1 test +✓ xc-cascade-6hop 1 test +✓ read-evm-balance-eoa 1 test +✓ read-canonical-registry 1 test +✓ read-evm-balance-uea 1 test +✓ read-evm-contract-call 1 test +✓ read-evm-callback-reverts 1 test +✓ read-expiry 1 test +✓ read-svm-lamports 1 test +✓ read-web2-json 1 test +✓ read-docs-example 1 test +✓ read-docs-evm-balance 1 test +✓ read-docs-batch 1 test +✓ read-docs-resume 2 tests +✓ read-app-batch-eoa 1 test +✓ read-app-batch-uea 1 test +✓ read-app-batch-recovery 1 test +✓ read-api-token 1 test +✓ read-api-mixed-outcomes 1 test +✓ read-svm-token-auto 1 test +✓ read-svm-idl 1 test +✓ read-evm-any-mutability 1 test +✓ read-svm-raw 1 test + +76 scenarios, 40 spec files, 81 distinct tests. +Manifest is consistent with the specs. diff --git a/plan/agw/implementation-review/evidence.json b/plan/agw/implementation-review/evidence.json new file mode 100644 index 00000000..b520883e --- /dev/null +++ b/plan/agw/implementation-review/evidence.json @@ -0,0 +1,97 @@ +{ + "reviewed_commit": "3008497b2492a6be78300011d4572076414505bf", + "base": "349635b2254823488603b37f4b44c4f5c929feb9", + "date": "2026-10-03", + "commands": [ + { + "command": "node node_modules/jest/bin/jest.js --config packages/core/jest.config.ts --runInBand", + "result": "1883 passed; 12 skipped" + }, + { + "command": "packages/core/scripts/agw-local/prepare.sh; then AGW_LOCAL_DIR= node node_modules/jest/bin/jest.js --config packages/core/jest.agw-local.config.ts --runInBand --forceExit", + "result": "32 passed; local Anvil only" + }, + { + "command": "node node_modules/typescript/bin/tsc -p packages/core/tsconfig.lib.json --noEmit", + "result": "passed" + }, + { + "command": "node node_modules/typescript/bin/tsc -p packages/core/tsconfig.spec.json --noEmit", + "result": "passed" + }, + { + "command": "yarn nx run core:build --skip-nx-cache", + "result": "passed" + }, + { + "command": "yarn nx run core:lint --skip-nx-cache", + "result": "7 errors in unchanged files" + }, + { + "command": "cd packages/core; node ../../node_modules/ts-node/dist/bin.js --transpile-only __e2e__/ci/run.ts --verify --group agw; repeat --group all", + "result": "21 and 76 scenarios respectively; manifest checks passed" + }, + { + "command": "node node_modules/jest/bin/jest.js --config plan/agw/implementation-review/reviewer.config.cjs --runInBand --runTestsByPath plan/agw/implementation-review/regressions.spec.ts", + "result": "7 expected regression failures" + }, + { + "command": "AGW_LOCAL_DIR= node node_modules/jest/bin/jest.js --config plan/agw/implementation-review/reviewer.config.cjs --runInBand --runTestsByPath plan/agw/implementation-review/local-races.spec.ts --forceExit", + "result": "2 expected regression failures; local Anvil only" + } + ], + "lint_errors": [ + { + "file": "packages/core/__e2e__/docs-examples/13-read-state/fixtures/universal_read_batch.js", + "diagnostic": "4:1 error Projects should use relative imports to import from other files within the same project. Use \"./path/to/file\" instead of import from \"@pushchain/core\" @nx/enforce-module-boundaries", + "changed_in_implementation": false + }, + { + "file": "packages/core/__e2e__/docs-examples/13-read-state/fixtures/universal_read_evm_balance.js", + "diagnostic": "4:1 error Projects should use relative imports to import from other files within the same project. Use \"./path/to/file\" instead of import from \"@pushchain/core\" @nx/enforce-module-boundaries", + "changed_in_implementation": false + }, + { + "file": "packages/core/__e2e__/docs-examples/13-read-state/fixtures/universal_read_resume.js", + "diagnostic": "4:1 error Projects should use relative imports to import from other files within the same project. Use \"./path/to/file\" instead of import from \"@pushchain/core\" @nx/enforce-module-boundaries", + "changed_in_implementation": false + }, + { + "file": "packages/core/__e2e__/docs-examples/13-read-state/playgrounds.spec.ts", + "diagnostic": "20:63 error Unexpected empty async function @typescript-eslint/no-empty-function", + "changed_in_implementation": false + }, + { + "file": "packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm.spec.ts", + "diagnostic": "286:28 error Require statement not part of import statement @typescript-eslint/no-var-requires", + "changed_in_implementation": false + }, + { + "file": "packages/core/src/lib/orchestrator/internals/pc20/tracking.ts", + "diagnostic": "128:40 error Require statement not part of import statement @typescript-eslint/no-var-requires", + "changed_in_implementation": false + }, + { + "file": "packages/core/src/lib/orchestrator/internals/pc20/tracking.ts", + "diagnostic": "131:28 error Require statement not part of import statement @typescript-eslint/no-var-requires", + "changed_in_implementation": false + } + ], + "limits": "No production source changed; no live-network broadcasts; local gateway/fee/CEA fixtures do not prove settlement.", + "sha256": { + "build.log": "ad1d0eb1a71fcdcf4169d571fbc3ba2e140eb6cc576d9c06de45499e65d97a78", + "e2e-agw-manifest.log": "547b3068ab4276f9c4e0bbacdff3e6e635a5e812c86ee18dcdc235cf3dca6052", + "e2e-all-manifest.log": "3d1649d660267693725f167772c8cfc6b0c51a385e1043d203efe1459798f6ff", + "lint.log": "f6ff5a01078bc1c97bb3157e0a2e31a48d2670191ee9e78bbbddbf0fbcd8bba0", + "local-races.log": "bdf2ff4ca17d9c6301359990a8259e19fe45bb4d155fa72194b031c23ab76edf", + "local-races.spec.ts": "19620c71a8c2c8699634ba080f19b673aabb87437858517a2fae1b662adabdb1", + "local-suite.log": "d4d40e9780a070949ab3a04e60ed8f8f43fc2839b831ca520d182994c61c0b71", + "regressions.log": "ffc8e1161c60177eac2c71843c68f4e5473d7585563923431d44753755d434a5", + "regressions.spec.ts": "41a4dd650950d647b7c5c4dbbb2074078283346ad0468743da6cf742c1b2f432", + "review.md": "a592ed63be12b556606fbf3fcf682175a7099020b5ef5f32e719190a34e649d2", + "reviewer.config.cjs": "77cf419682ced6b430f89997f2664622f14b1ba32488a284c3ce39c7b30195be", + "types-lib.log": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "types-spec.log": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "unit-suite.log": "f157b97943506508225f66bb858f822208c248d5d5b22d7391046f50eee8ee78" + } +} diff --git a/plan/agw/implementation-review/lint.log b/plan/agw/implementation-review/lint.log new file mode 100644 index 00000000..fd1936c8 --- /dev/null +++ b/plan/agw/implementation-review/lint.log @@ -0,0 +1,1157 @@ + +> nx run core:lint + +> eslint . + + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__agw-local__/agw-local-advanced.spec.ts + 60:54 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 70:17 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 211:22 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 222:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 238:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 291:13 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__agw-local__/agw-local.spec.ts + 35:17 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 36:17 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__agw-local__/harness.ts + 152:16 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 171:16 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 179:17 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 251:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__agw-local__/vectors.spec.ts + 38:7 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 39:7 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 63:32 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 153:25 warning '_a' is assigned a value but never used @typescript-eslint/no-unused-vars + 154:25 warning '_b' is assigned a value but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/agw/identity-gas.spec.ts + 62:123 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/agw/universal-evm.spec.ts + 31:17 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/cross-chain/cascade-amm.spec.ts + 1715:41 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 1897:41 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 2003:41 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 2096:41 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 2167:41 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 2256:41 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/cross-chain/cea-to-push-erc20.spec.ts + 92:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 95:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 102:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/cross-chain/forced-sizer.spec.ts + 36:17 warning 'PUSH_NETWORK' is defined but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/cross-chain/fresh-wallet.spec.ts + 92:16 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/cross-chain/multi-child-r3-sepolia.spec.ts + 83:7 warning 'VALUE_RECEIVER' is assigned a value but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/cross-chain/peth-bridge.spec.ts + 114:77 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 132:76 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 149:42 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 165:35 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 174:50 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 218:21 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 241:31 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 261:21 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 271:28 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 295:27 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/cross-chain/uoa-multi-hop.spec.ts + 43:7 warning 'SOL_COUNTER_PDA' is assigned a value but never used @typescript-eslint/no-unused-vars + 44:7 warning 'SOL_TARGET' is assigned a value but never used @typescript-eslint/no-unused-vars + 45:7 warning 'SOL_ZERO_ADDRESS' is assigned a value but never used @typescript-eslint/no-unused-vars + 51:7 warning 'bscPublicClient' is assigned a value but never used @typescript-eslint/no-unused-vars + 52:7 warning 'pushPublicClient' is assigned a value but never used @typescript-eslint/no-unused-vars + 68:27 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/docs-examples/07-transaction-scenarios/route1.spec.ts + 357:7 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 357:7 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 360:46 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 364:16 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 389:20 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/docs-examples/07-transaction-scenarios/route2.spec.ts + 297:30 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 386:7 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 389:46 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 412:60 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/docs-examples/07-transaction-scenarios/route3.spec.ts + 375:7 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 375:7 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 378:46 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 384:16 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 404:20 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/docs-examples/08-multichain-transactions/multichain-transactions.spec.ts + 218:30 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 232:25 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 398:25 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 455:25 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 523:30 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 536:25 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/docs-examples/13-read-state/fixtures/universal_read_batch.js + 4:1 error Projects should use relative imports to import from other files within the same project. Use "./path/to/file" instead of import from "@pushchain/core" @nx/enforce-module-boundaries + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/docs-examples/13-read-state/fixtures/universal_read_evm_balance.js + 4:1 error Projects should use relative imports to import from other files within the same project. Use "./path/to/file" instead of import from "@pushchain/core" @nx/enforce-module-boundaries + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/docs-examples/13-read-state/fixtures/universal_read_resume.js + 4:1 error Projects should use relative imports to import from other files within the same project. Use "./path/to/file" instead of import from "@pushchain/core" @nx/enforce-module-boundaries + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/docs-examples/13-read-state/playgrounds.spec.ts + 20:63 error Unexpected empty async function @typescript-eslint/no-empty-function + 69:43 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 74:16 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 102:23 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 104:30 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 115:19 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 116:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 132:23 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 146:19 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 149:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 174:43 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 180:36 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 184:27 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 184:69 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/docs-examples/13-read-state/read-state.spec.ts + 56:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 56:32 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/docs-examples/_helpers/docs-fund.ts + 95:12 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/evm/inbound/rescue-funds.spec.ts + 165:20 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 227:15 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/evm/outbound/cea-to-smart-contracts.spec.ts + 48:3 warning 'UGPC_PRECOMPILE' is defined but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/evm/outbound/cea-to-uea.spec.ts + 1411:15 warning 'tx' is assigned a value but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/evm/outbound/uea-to-cea.spec.ts + 2277:41 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 2330:43 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-(node:62151) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. +(Use `node --trace-warnings ...` to show where the warning was created) +sdk/packages/core/__e2e__/evm/pc20/pc20-inbound.spec.ts + 15:10 warning 'PUSH_NETWORK' is defined but never used @typescript-eslint/no-unused-vars + 21:3 warning 'waitToleratingFeeCreditBug' is defined but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/evm/pc20/pc20-roundtrip.spec.ts + 17:3 warning 'waitToleratingFeeCreditBug' is defined but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/push/account-conversion/eth.spec.ts + 176:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 177:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 181:55 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 181:80 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 192:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 193:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 244:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 245:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 246:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 250:50 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 250:75 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 277:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 278:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 314:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 315:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 320:108 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 350:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 351:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 352:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 355:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 356:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 378:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 379:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 380:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 408:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 409:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 410:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 411:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 415:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 416:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 417:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 420:50 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 420:76 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 420:97 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 442:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 443:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 470:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 471:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 474:73 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 474:99 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/push/account-conversion/solana.spec.ts + 78:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 79:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 81:58 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 81:83 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 92:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 93:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 121:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 122:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 136:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 137:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 138:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 139:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 140:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 160:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 161:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 162:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 183:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 184:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/push/fee-lock-cap-raise.spec.ts + 60:19 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 170:38 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/push/native.spec.ts + 389:7 warning 'mainPushClient' is assigned a value but never used @typescript-eslint/no-unused-vars + 428:16 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 517:16 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/push/pool-depth-diagnostic.spec.ts + 27:24 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/push/progress-hooks.spec.ts + 383:19 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 594:25 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/push/utilities.spec.ts + 128:79 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/read/_shared.ts + 54:70 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/read/evm/any-mutability.spec.ts + 34:48 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/read/evm/api-coverage.spec.ts + 18:48 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 30:48 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 53:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 53:31 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/read/evm/app-batch.spec.ts + 38:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 38:29 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 46:48 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 67:67 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 71:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 71:32 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 76:48 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 81:107 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/read/evm/balance-eoa.spec.ts + 23:57 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 59:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 59:32 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/read/evm/balance-uea.spec.ts + 25:116 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 52:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 52:32 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/read/evm/callback-reverts.spec.ts + 22:48 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 36:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 36:32 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/read/evm/contract-call.spec.ts + 28:48 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/read/evm/registry.spec.ts + 14:57 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 40:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 40:36 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/read/lifecycle/expiry.spec.ts + 25:57 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/read/lifecycle/track-lookup.spec.ts + 21:48 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/read/svm/account-idl.spec.ts + 20:53 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 25:59 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 27:48 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 45:48 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 62:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 62:31 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 63:102 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 70:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 70:52 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 79:44 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/read/svm/lamports.spec.ts + 19:53 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 22:48 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/read/svm/raw-account.spec.ts + 13:48 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/read/tools/live-read-uea.ts + 57:15 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 57:63 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 57:101 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 103:18 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 106:46 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 107:143 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/read/web2/json.spec.ts + 15:48 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/scripts/e2e-7702-multicall.ts + 93:44 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 132:28 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/shared/evm-client.ts + 14:24 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/shared/svm-client.ts + 10:24 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/svm/inbound/uea-to-push.spec.ts + 16:10 warning 'MOVEABLE_TOKENS' is defined but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/svm/outbound/cea-to-eoa.spec.ts + 15:61 warning 'encodeFunctionData' is defined but never used @typescript-eslint/no-unused-vars + 24:3 warning 'COUNTER_ADDRESS_PAYABLE' is defined but never used @typescript-eslint/no-unused-vars + 25:3 warning 'COUNTER_ABI_PAYABLE' is defined but never used @typescript-eslint/no-unused-vars + 27:10 warning 'COUNTER_ABI' is defined but never used @typescript-eslint/no-unused-vars + 37:7 warning 'pushPublicClient' is assigned a value but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/svm/outbound/cea-to-uea.spec.ts + 39:3 warning 'buildReceiveSolAccounts' is defined but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/svm/outbound/eoa-to-cea.spec.ts + 23:3 warning 'SOL_ZERO_ADDRESS' is defined but never used @typescript-eslint/no-unused-vars + 25:3 warning 'COUNTER_PDA' is defined but never used @typescript-eslint/no-unused-vars + 28:3 warning 'buildReceiveSolAccounts' is defined but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/svm/outbound/eoa-to-smart-contracts.spec.ts + 86:19 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/svm/outbound/uea-to-cea.spec.ts + 43:3 warning 'buildReceiveSolAccounts' is defined but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/scripts/poll-outbound.ts + 24:3 warning 'UniversalTxStatus' is defined but never used @typescript-eslint/no-unused-vars + 25:3 warning 'OutboundStatus' is defined but never used @typescript-eslint/no-unused-vars + 236:19 warning 'intervalMs' is assigned a value but never used @typescript-eslint/no-unused-vars + 236:31 warning 'timeoutMs' is assigned a value but never used @typescript-eslint/no-unused-vars + 260:30 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 292:29 warning 'childUtxIds' is assigned a value but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/scripts/probe-multihop-track.ts + 36:40 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 40:12 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 41:12 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 42:12 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 55:37 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/scripts/test-uea-migration.ts + 80:122 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 165:20 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 166:20 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 168:27 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 169:23 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 191:17 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/codec.spec.ts + 171:21 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/utils.ts + 108:15 warning '_card' is defined but never used @typescript-eslint/no-unused-vars + 108:31 warning '_userInput' is defined but never used @typescript-eslint/no-unused-vars + 108:52 warning '_ctx' is defined but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/wallet.ts + 92:33 warning '_opts' is defined but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/cache/cache.ts + 4:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 38:21 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 56:27 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/constants/__tests__/svm-gateway-idl.spec.ts + 13:22 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/internal/buffer.ts + 4:18 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/internal/global-buffer-polyfill.ts + 3:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/account-status.spec.ts + 274:15 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 286:15 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/cascade-composition.spec.ts + 363:13 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 431:13 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 447:13 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 480:13 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 552:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 618:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 686:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 758:13 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 774:13 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 811:13 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 887:13 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/context-helpers-tracker.spec.ts + 36:47 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 39:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 167:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/gas-usd-sizer.spec.ts + 26:25 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 32:7 warning 'PC_USD_1E8' is assigned a value but never used @typescript-eslint/no-unused-vars + 35:44 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 41:57 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 65:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 71:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 215:59 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 231:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 243:31 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 252:65 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 281:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 297:31 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/gateway-uea-account.spec.ts + 9:10 warning 'CHAIN_INFO' is defined but never used @typescript-eslint/no-unused-vars + 14:3 warning 'AccountStatus' is defined but never used @typescript-eslint/no-unused-vars + 62:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 68:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 86:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 223:12 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 231:12 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 243:12 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 251:12 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 264:12 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 441:11 warning 'first' is assigned a value but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/payload-builders.spec.ts + 11:44 warning 'MULTICALL_SELECTOR' is defined but never used @typescript-eslint/no-unused-vars + 152:24 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 152:24 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 175:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 176:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 325:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 326:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 365:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 373:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 374:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 516:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 517:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 575:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 576:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 577:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 578:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 599:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 600:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 620:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/preflight.spec.ts + 54:35 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 72:35 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 73:35 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 93:35 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 94:35 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 97:35 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 156:35 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 158:35 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 179:35 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 199:35 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 200:35 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 297:33 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 394:13 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 394:33 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 423:35 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 424:35 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 440:35 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 456:35 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/push-chain-tx-retry.spec.ts + 12:31 warning 'VM' is defined but never used @typescript-eslint/no-unused-vars + 49:85 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 102:72 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 239:64 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 261:72 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/rescue-svm-confirmation.spec.ts + 13:10 warning 'bytesToHex' is defined but never used @typescript-eslint/no-unused-vars + 13:22 warning 'hexToBytes' is defined but never used @typescript-eslint/no-unused-vars + 15:10 warning 'VM' is defined but never used @typescript-eslint/no-unused-vars + 29:33 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 30:26 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 34:43 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 39:32 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 43:7 warning 'mockEvmConfirmations' is assigned a value but never used @typescript-eslint/no-unused-vars + 44:7 warning 'mockSvmConfirmations' is assigned a value but never used @typescript-eslint/no-unused-vars + 148:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 154:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 155:37 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 167:36 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 188:49 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 194:48 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 203:55 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 209:47 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 218:81 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 227:56 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 231:51 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 255:54 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 263:61 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 347:30 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 349:30 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 351:30 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 356:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 357:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 367:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 368:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 375:52 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 435:25 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 566:43 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 612:41 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 702:25 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 705:12 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 706:39 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 751:13 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 751:61 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 765:23 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 794:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 816:25 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 819:12 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 820:39 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 835:25 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 838:12 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 839:39 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 852:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/response-builder-push-revert.spec.ts + 64:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 66:70 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/send-transaction-progress-hook.spec.ts + 79:20 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 199:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/signing-payload.spec.ts + 19:3 warning 'encodeAbiParameters' is defined but never used @typescript-eslint/no-unused-vars + 20:3 warning 'encodePacked' is defined but never used @typescript-eslint/no-unused-vars + 25:31 warning 'VM' is defined but never used @typescript-eslint/no-unused-vars + 144:46 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 148:46 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 157:46 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 161:49 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 232:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 239:51 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 248:48 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 252:54 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 261:78 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 265:83 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 606:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 619:58 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 651:48 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 659:54 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 666:59 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 677:51 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 690:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 711:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 740:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 750:51 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 767:68 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 772:82 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 922:37 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 932:37 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 941:37 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 950:37 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/source-hash-resolution.spec.ts + 24:8 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 34:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 58:70 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 74:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 91:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/terminal-suppression.spec.ts + 26:23 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 27:28 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 28:24 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/track-transaction-guard.spec.ts + 21:27 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 23:21 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 30:40 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 38:69 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 44:64 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/tx-transformer-gas.spec.ts + 10:15 warning 'UniversalTxReceipt' is defined but never used @typescript-eslint/no-unused-vars + 22:32 warning 'PayableToken' is defined but never used @typescript-eslint/no-unused-vars + 22:46 warning 'MoveableToken' is defined but never used @typescript-eslint/no-unused-vars + 28:52 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 44:60 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 65:47 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 110:64 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 115:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 121:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 122:37 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 144:63 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 165:63 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 174:63 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 183:63 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 193:63 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 202:63 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 215:63 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 224:63 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 505:14 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 529:14 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 614:12 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 663:12 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 693:12 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 709:12 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 839:58 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 850:27 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 850:27 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 866:27 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 866:27 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 880:27 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 880:27 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 955:87 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 994:27 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 994:27 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 1015:27 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 1015:27 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 1028:27 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 1028:27 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/tx-transformer-multichain.spec.ts + 10:10 warning 'encodeAbiParameters' is defined but never used @typescript-eslint/no-unused-vars + 15:10 warning 'UEA_MULTICALL_SELECTOR' is defined but never used @typescript-eslint/no-unused-vars + 15:34 warning 'ZERO_ADDRESS' is defined but never used @typescript-eslint/no-unused-vars + 107:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 108:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 128:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 149:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 168:13 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 241:15 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 279:15 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/account-manager.ts + 113:46 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 205:23 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/cascade.ts + 18:22 warning 'UNIVERSAL_GATEWAY_ADDRESSES' is defined but never used @typescript-eslint/no-unused-vars + 123:23 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 136:11 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 180:3 warning 'callbacks' is defined but never used @typescript-eslint/no-unused-vars + 613:27 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 636:15 warning 'gatewayProgramHex' is assigned a value but never used @typescript-eslint/no-unused-vars + 668:11 warning 'amount' is assigned a value but never used @typescript-eslint/no-unused-vars + 741:13 warning 'tokenAddress' is assigned a value but never used @typescript-eslint/no-unused-vars + 746:9 warning 'amount' is assigned a value but never used @typescript-eslint/no-unused-vars + 747:9 warning 'nativeValue' is assigned a value but never used @typescript-eslint/no-unused-vars + 802:11 warning 'chain' is assigned a value but never used @typescript-eslint/no-unused-vars + 1711:29 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 2678:45 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/confirmation.ts + 134:38 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 135:21 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/context.ts + 135:12 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/execute-funds-only.ts + 18:10 warning 'EvmClient' is defined but never used @typescript-eslint/no-unused-vars + 82:8 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 92:5 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 95:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 96:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 123:21 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 123:21 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 124:20 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 124:20 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 137:20 warning 'universalPayload' is assigned a value but never used @typescript-eslint/no-unused-vars + 262:55 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 262:78 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 262:78 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 270:7 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 270:7 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 271:75 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 272:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 272:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 297:77 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 297:77 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 326:69 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 326:69 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 365:11 warning 'nonce' is assigned a value but never used @typescript-eslint/no-unused-vars + 370:7 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 370:7 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 390:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 390:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 391:34 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 391:34 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 419:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 419:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 436:34 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 436:34 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 465:82 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 465:82 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 487:69 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 487:69 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/execute-funds-payload.ts + 77:8 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 88:5 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 91:21 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 105:45 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 210:18 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 236:24 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 237:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 239:69 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 242:23 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 255:13 warning 'tokenAddr' is assigned a value but never used @typescript-eslint/no-unused-vars + 255:25 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 261:13 warning 'payloadBytes' is assigned a value but never used @typescript-eslint/no-unused-vars + 277:62 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 319:77 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 372:69 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/gas-calculator.ts + 596:18 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/helpers.ts + 16:10 warning 'EvmClient' is defined but never used @typescript-eslint/no-unused-vars + 152:53 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 152:59 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 220:12 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/outbound-sync.ts + 131:40 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 132:9 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/payload-builder.ts + 75:43 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/pc20/__tests__/inbound-payload.spec.ts + 107:19 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 107:19 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 116:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 116:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 117:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm.spec.ts + 286:28 error Require statement not part of import statement @typescript-eslint/no-var-requires + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/pc20/tracking.ts + 128:40 error Require statement not part of import statement @typescript-eslint/no-var-requires + 131:28 error Require statement not part of import statement @typescript-eslint/no-var-requires + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/push-chain-tx.ts + 84:19 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 214:25 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 251:28 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 395:19 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 454:20 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 455:20 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 457:27 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 458:23 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 518:20 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 519:20 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 521:27 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 522:23 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 570:39 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/response-builder.ts + 30:10 warning 'PushChain' is defined but never used @typescript-eslint/no-unused-vars + 64:43 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 65:44 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 65:60 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 66:44 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 66:59 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 180:13 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 185:29 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 191:55 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 195:41 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 222:12 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 248:25 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/route-handlers.ts + 1154:21 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 2094:5 warning 'ueaBalance' is assigned a value but never used @typescript-eslint/no-unused-vars + 2404:3 warning 'ctx' is defined but never used @typescript-eslint/no-unused-vars + 2405:3 warning 'params' is defined but never used @typescript-eslint/no-unused-vars + 2406:3 warning 'executeFn' is defined but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/signing.ts + 427:32 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/svm-bridge.ts + 41:77 warning 'req' is assigned a value but never used @typescript-eslint/no-unused-vars + 212:34 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 212:34 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/svm-helpers.ts + 107:37 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 107:53 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 115:21 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 188:11 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/tx-transformer.ts + 97:7 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/orchestrator.spec.ts + 87:50 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 134:50 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 162:28 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 182:28 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/orchestrator.ts + 3:31 warning 'VM' is defined but never used @typescript-eslint/no-unused-vars + 37:76 warning '_transformToUniversalTxResponse' is defined but never used @typescript-eslint/no-unused-vars + 76:41 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 92:48 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 103:50 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 104:74 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 105:77 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/orchestrator.types.ts + 387:15 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 564:9 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/payload-builders.ts + 7:44 warning 'MULTICALL_SELECTOR' is defined but never used @typescript-eslint/no-unused-vars + 14:3 warning 'ChainTarget' is defined but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/route-detector.ts + 17:3 warning 'TransactionRouteType' is defined but never used @typescript-eslint/no-unused-vars + 378:25 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 378:25 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/svm-idl/resolve.spec.ts + 51:55 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 72:55 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 90:55 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/svm-idl/resolve.ts + 10:6 warning 'AccountItem' is defined but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/push-chain/push-chain.explorer.spec.ts + 192:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 199:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/push-chain/push-chain.reinitialize.spec.ts + 198:29 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 199:39 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/push-chain/push-chain.signing.spec.ts + 21:7 warning 'pushChainSVM' is assigned a value but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/push-chain/push-chain.spec.ts + 12:3 warning 'isAddress' is defined but never used @typescript-eslint/no-unused-vars + 13:3 warning 'verifyMessage' is defined but never used @typescript-eslint/no-unused-vars + 452:9 warning 'pushPublicClient' is assigned a value but never used @typescript-eslint/no-unused-vars + 1199:9 warning 'beforeCounterPCBalance' is assigned a value but never used @typescript-eslint/no-unused-vars + 1222:9 warning 'afterCounterPCBalance' is assigned a value but never used @typescript-eslint/no-unused-vars + 1317:9 warning 'balanceBeforePC_UEA' is assigned a value but never used @typescript-eslint/no-unused-vars + 1353:9 warning 'balanceAfterPC_UEA' is assigned a value but never used @typescript-eslint/no-unused-vars + 1434:9 warning 'balanceBeforePC_UEA' is assigned a value but never used @typescript-eslint/no-unused-vars + 1470:9 warning 'balanceAfterPC_UEA' is assigned a value but never used @typescript-eslint/no-unused-vars + 1682:9 warning 'balanceBeforePC_COUNTER' is assigned a value but never used @typescript-eslint/no-unused-vars + 1685:9 warning 'balanceBeforePC_UEA' is assigned a value but never used @typescript-eslint/no-unused-vars + 1717:9 warning 'balanceAfterPC_COUNTER' is assigned a value but never used @typescript-eslint/no-unused-vars + 1720:9 warning 'balanceAfterPC_UEA' is assigned a value but never used @typescript-eslint/no-unused-vars + 1879:35 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 1894:35 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 1910:35 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 1940:9 warning 'pushClientEVM' is assigned a value but never used @typescript-eslint/no-unused-vars + 2145:9 warning 'pcBeforeRecipient' is assigned a value but never used @typescript-eslint/no-unused-vars + 2170:9 warning 'pcAfterRecipient' is assigned a value but never used @typescript-eslint/no-unused-vars + 2487:41 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 2504:41 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 2523:41 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 2533:41 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 2556:41 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 2571:41 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 2592:41 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 2602:41 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 2612:41 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 2649:41 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 3328:18 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 3330:14 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 3537:15 warning 'recipient' is assigned a value but never used @typescript-eslint/no-unused-vars + 3832:13 warning 'WETH9' is assigned a value but never used @typescript-eslint/no-unused-vars + 3863:13 warning 'WETH9' is assigned a value but never used @typescript-eslint/no-unused-vars + 3865:13 warning 'USDC' is assigned a value but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/push-chain/push-chain.ts + 33:3 warning 'UniversalTxResponse' is defined but never used @typescript-eslint/no-unused-vars + 244:31 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/push-client/push-client.archive-fallback.spec.ts + 30:3 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 127:37 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 133:37 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 148:37 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 155:37 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 162:40 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/push-client/push-client.ts + 359:42 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/read-state/__integration__/read-state.integration.spec.ts + 45:38 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 45:38 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 45:77 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 45:77 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 45:117 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 48:68 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 225:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 225:29 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/read-state/__tests__/read-events.spec.ts + 95:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 95:24 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/read-state/__tests__/read-tracker.spec.ts + 26:3 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 104:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 104:29 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 274:5 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 282:5 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 385:20 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/read-state/__tests__/read-types.spec.ts + 30:9 warning 'removed' is assigned a value but never used @typescript-eslint/no-unused-vars + 48:8 warning '_typed' is defined but never used @typescript-eslint/no-unused-vars + 61:9 warning 'missingEntrypoint' is assigned a value but never used @typescript-eslint/no-unused-vars + 63:9 warning 'registryAbi' is assigned a value but never used @typescript-eslint/no-unused-vars + 65:9 warning 'legacy' is assigned a value but never used @typescript-eslint/no-unused-vars + 86:8 warning '_loose' is defined but never used @typescript-eslint/no-unused-vars + 135:6 warning 'ExportChecks' is defined but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/read-state/__tests__/registry.spec.ts + 91:94 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 97:46 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/read-state/__tests__/revalidate-read.spec.ts + 55:62 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/read-state/__tests__/svm-account.spec.ts + 101:25 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 101:25 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 102:23 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 102:23 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 103:27 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 103:27 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 104:25 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 104:25 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/read-state/__tests__/ucallback-codec.spec.ts + 35:15 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 51:23 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 84:17 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 87:23 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 88:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 91:23 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 116:22 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/read-state/read-params.ts + 254:15 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 295:46 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/universal-tx-detector/__tests__/cascade.spec.ts + 319:20 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 322:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 325:22 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 325:22 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 357:22 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/universal-tx-detector/__tests__/detector-svm-log-index.spec.ts + 90:7 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/universal-tx-detector/__tests__/detector.live.spec.ts + 180:25 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 317:29 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 317:29 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 324:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 326:9 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 328:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 329:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 333:27 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 357:33 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 357:33 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/universal-tx-detector/__tests__/normalize.spec.ts + 154:49 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 248:9 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 254:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/universal-tx-detector/cascade.ts + 16:51 warning 'PublicClient' is defined but never used @typescript-eslint/no-unused-vars + 23:3 warning 'deriveChildUniversalTxId' is defined but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/universal-tx-detector/detector-svm.ts + 242:30 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 243:9 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/universal-tx-detector/detector.ts + 88:30 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 89:9 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/universal-tx-detector/svm-events.ts + 30:11 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/universal/account/account.spec.ts + 12:3 warning 'resolveControllerAccount' is defined but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/universal/signer/signer.spec.ts + 38:18 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 68:23 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 82:38 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 136:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 200:49 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 334:7 warning 'domain' is defined but never used @typescript-eslint/no-unused-vars + 335:7 warning 'types' is defined but never used @typescript-eslint/no-unused-vars + 336:7 warning 'primaryType' is defined but never used @typescript-eslint/no-unused-vars + 337:7 warning 'message' is defined but never used @typescript-eslint/no-unused-vars + 339:15 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 340:14 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 342:16 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/universal/signer/signer.ts + 47:16 warning 'type' is assigned a value but never used @typescript-eslint/no-unused-vars + 49:5 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 54:58 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 73:11 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 102:11 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 213:29 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 228:36 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 229:36 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 230:36 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 265:47 warning 'primaryType' is defined but never used @typescript-eslint/no-unused-vars + 268:46 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 422:31 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 516:44 warning 'primaryType' is defined but never used @typescript-eslint/no-unused-vars + 519:44 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 552:44 warning 'primaryType' is defined but never used @typescript-eslint/no-unused-vars + 555:44 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 569:23 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 570:23 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/universal/universal.types.ts + 22:14 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 23:13 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 24:12 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 25:18 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 26:14 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 30:14 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 31:14 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 32:20 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 34:29 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 35:34 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 35:50 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 36:14 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 42:33 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 43:27 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 47:34 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 47:50 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 48:14 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 54:25 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 54:41 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 57:33 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 58:27 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 60:14 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 130:29 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 167:29 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/utils.spec.ts + 172:72 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 419:29 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 425:24 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 436:30 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 487:28 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 571:16 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 648:62 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 652:63 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 657:57 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 663:57 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 669:57 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 878:71 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 882:71 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 893:66 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 898:68 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 904:57 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 910:62 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 1215:54 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 1219:55 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 1223:60 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 1227:53 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 1233:62 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 1239:62 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 1245:67 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 1251:60 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 1554:65 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 1563:35 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/utils.ts + 24:43 warning 'getAddress' is defined but never used @typescript-eslint/no-unused-vars + 292:13 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 295:14 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 325:40 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/vm-client/evm-client.chain-symbol.spec.ts + 64:23 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/vm-client/svm-client.ts + 92:34 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 152:51 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 184:41 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 215:45 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 216:35 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 286:63 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 287:47 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/vm-client/vm-client.types.ts + 29:14 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 40:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +✖ 839 problems (7 errors, 832 warnings) + 3 errors and 0 warnings potentially fixable with the `--fix` option. + +Warning: command "eslint ." exited with non-zero status code + + + NX Running target lint for project core failed + +Failed tasks: + +- core:lint + +Hint: run the command with --verbose for more details. + diff --git a/plan/agw/implementation-review/local-races.log b/plan/agw/implementation-review/local-races.log new file mode 100644 index 00000000..53e61429 --- /dev/null +++ b/plan/agw/implementation-review/local-races.log @@ -0,0 +1,44 @@ +FAIL plan/agw/implementation-review/local-races.spec.ts (5.984 s) + ✕ R1 a raced creation must not grant permissions on the concurrently created wallet (618 ms) + ✕ R4 owner outbound must not restore an allowance revoked after composition (773 ms) + + ● R1 a raced creation must not grant permissions on the concurrently created wallet + + expect(received).toHaveLength(expected) + + Expected length: 0 + Received length: 1 + Received array: ["0xed16789aedd36446aa851df227d231dfdaab75ab95d022e251d179e27fdcee59"] + + 32 | const ids = await h.publicClient.readContract({ address: h.addresses.engine, abi: h.generation.contracts.abis.engine, functionName: 'getPermissionIDs', args: [expected.address] }); + 33 | // The SDK threw, but the old predicted wallet must not acquire the new permission. + > 34 | expect(ids).toHaveLength(0); + | ^ + 35 | }); + 36 | + 37 | it('R4 owner outbound must not restore an allowance revoked after composition', async () => { + + at Object. (plan/agw/implementation-review/local-races.spec.ts:34:15) + + ● R4 owner outbound must not restore an allowance revoked after composition + + expect(received).toBe(expected) // Object.is equality + + Expected: 0n + Received: 50n + + 61 | } finally { rt.execute = execute; } + 62 | const remaining = await h.publicClient.readContract({ address: token, abi: TOKEN, functionName: 'allowance', args: [wallet, h.addresses.gateway] }); + > 63 | expect(remaining).toBe(BigInt(0)); + | ^ + 64 | }); + 65 | + + at Object. (plan/agw/implementation-review/local-races.spec.ts:63:21) + +Test Suites: 1 failed, 1 total +Tests: 2 failed, 2 total +Snapshots: 0 total +Time: 6.111 s +Ran all test suites within paths "plan/agw/implementation-review/local-races.spec.ts". +Force exiting Jest: Have you considered using `--detectOpenHandles` to detect async operations that kept running after all tests finished? diff --git a/plan/agw/implementation-review/local-races.spec.ts b/plan/agw/implementation-review/local-races.spec.ts new file mode 100644 index 00000000..4627b366 --- /dev/null +++ b/plan/agw/implementation-review/local-races.spec.ts @@ -0,0 +1,64 @@ +// Reviewer regressions against real e704d5b contracts on local Anvil only. +import { encodeFunctionData, parseAbi, type Address } from 'viem'; +import { startHarness, type Harness } from '../../../packages/core/__agw-local__/harness'; +import type { AgenticRuntime } from '../../../packages/core/src/lib/agentic/runtime'; +import { CHAIN, type PushChain } from '../../../packages/core/src'; +import { e704d5b } from '../../../packages/core/src/lib/agentic/contracts/e704d5b'; + +const TOKEN = parseAbi(['function mint(address,uint256)', 'function approve(address,uint256) returns (bool)', 'function allowance(address,address) view returns (uint256)']); +let h: Harness; +let owner: PushChain; +beforeAll(async () => { h = await startHarness(); owner = await h.client(0); }); +afterAll(async () => { await h?.stop(); }); + +it('R1 a raced creation must not grant permissions on the concurrently created wallet', async () => { + const expected = await owner.agentic.derive(); + const rt = (owner as unknown as { agenticRuntime: AgenticRuntime }).agenticRuntime; + const execute = rt.execute; + let raced = false; + rt.execute = async (params, options) => { + if (!raced) { + raced = true; + await h.write(0, h.addresses.factory, h.generation.contracts.abis.factory, 'deployWallet', ['other-purpose-wallet']); + } + return execute(params, options); + }; + let error: unknown; + try { + await owner.agentic.create('intended-agent-wallet', { rules: [{ agent: h.wallets[1].account!.address, target: h.addresses.target, selector: 'increment()', validUntil: Number((await h.publicClient.getBlock()).timestamp) + 3600 }] }); + } catch (e) { error = e; } + finally { rt.execute = execute; } + expect(error).toMatchObject({ code: 'INDEX_RACE' }); + const ids = await h.publicClient.readContract({ address: h.addresses.engine, abi: h.generation.contracts.abis.engine, functionName: 'getPermissionIDs', args: [expected.address] }); + // The SDK threw, but the old predicted wallet must not acquire the new permission. + expect(ids).toHaveLength(0); +}); + +it('R4 owner outbound must not restore an allowance revoked after composition', async () => { + const { wallet } = await owner.agentic.create('allowance-race', { rules: [] }); + const token = await h.deploy(0, 'HarnessPRC20', 'HarnessFixtures.sol', [CHAIN.ETHEREUM_SEPOLIA, 6]); + await h.write(0, token, TOKEN, 'mint', [wallet, BigInt(1000)]); + const fundingHash = await h.wallets[0].sendTransaction({ to: wallet, value: BigInt(10) ** BigInt(17), account: h.wallets[0].account!, chain: h.wallets[0].chain }); + await h.publicClient.waitForTransactionReceipt({ hash: fundingHash }); + const c = await h.client(0, { agenticWallet: wallet }); + await c.universal.sendTransaction({ to: token, data: encodeFunctionData({ abi: TOKEN, functionName: 'approve', args: [h.addresses.gateway, BigInt(50)] }) }); + const rt = (c as unknown as { agenticRuntime: AgenticRuntime }).agenticRuntime; + rt.resolvePrc20 = () => token; + rt.resolveCEA = async () => ({ cea: h.wallets[2].account!.address, isDeployed: true }); + rt.quoteOutbound = async () => ({ protocolFee: BigInt(10) ** BigInt(14), nativeValueForGas: BigInt(10) ** BigInt(15), gasLimitUsed: BigInt(200000) }); + const execute = rt.execute; + let raced = false; + rt.execute = async (params, options) => { + if (!raced) { + raced = true; + const revoke = e704d5b.encodeExecute([{ target: token, value: BigInt(0), data: encodeFunctionData({ abi: TOKEN, functionName: 'approve', args: [h.addresses.gateway, BigInt(0)] }) }]); + await execute({ to: wallet, data: revoke }); + } + return execute(params, options); + }; + try { + await c.universal.sendTransaction({ to: { address: h.wallets[2].account!.address as Address, chain: CHAIN.ETHEREUM_SEPOLIA }, data: '0xd09de08a', funds: { amount: BigInt(10) } }); + } finally { rt.execute = execute; } + const remaining = await h.publicClient.readContract({ address: token, abi: TOKEN, functionName: 'allowance', args: [wallet, h.addresses.gateway] }); + expect(remaining).toBe(BigInt(0)); +}); diff --git a/plan/agw/implementation-review/local-suite.log b/plan/agw/implementation-review/local-suite.log new file mode 100644 index 00000000..dbced151 --- /dev/null +++ b/plan/agw/implementation-review/local-suite.log @@ -0,0 +1,10 @@ +PASS core-agw-local packages/core/__agw-local__/agw-local-advanced.spec.ts (5.378 s) +PASS core-agw-local packages/core/__agw-local__/agw-local.spec.ts +PASS core-agw-local packages/core/__agw-local__/vectors.spec.ts + +Test Suites: 3 passed, 3 total +Tests: 32 passed, 32 total +Snapshots: 0 total +Time: 7.575 s, estimated 17 s +Ran all test suites. +Force exiting Jest: Have you considered using `--detectOpenHandles` to detect async operations that kept running after all tests finished? diff --git a/plan/agw/implementation-review/regressions.log b/plan/agw/implementation-review/regressions.log new file mode 100644 index 00000000..e6cee32c --- /dev/null +++ b/plan/agw/implementation-review/regressions.log @@ -0,0 +1,151 @@ +FAIL plan/agw/implementation-review/regressions.spec.ts + ✕ R2 explicit connected Push destination behaves like the bare native address (5 ms) + ✕ R3 owner funds-only outbound encodes the requested destination address (1 ms) + ✕ R4 owner outbound accepts an existing unlimited gateway allowance (10 ms) + ✕ R5 decoded static-array pin keeps its argument index (1 ms) + ✕ R5 a decoded simple address-pin rule can be re-encoded after restoring its known signature (2 ms) + ✕ R6 replayed outbound must replace a preexisting Push route instead of preserving it (2 ms) + ✕ R7 failed recovery RPC must not claim that a confirmed deployment did not happen (3 ms) + + ● R2 explicit connected Push destination behaves like the bare native address + + expect(received).resolves.toBeDefined() + + Received promise rejected instead of resolved + Rejected to value: [AgenticError: rule 0x0000000000000000000000000000000000000000000000000000000000000001 is not an EVM universal rule] + + 27 | it('R2 explicit connected Push destination behaves like the bare native address', async () => { + 28 | const { rt, ctx } = setup(); + > 29 | await expect(agenticSend(rt, ctx, { to: { address: ADDR.target, chain: CHAIN.PUSH_TESTNET_DONUT }, data: '0xd09de08a' })).resolves.toBeDefined(); + | ^ + 30 | }); + 31 | + 32 | it('R3 owner funds-only outbound encodes the requested destination address', async () => { + + at expect (node_modules/expect/build/index.js:113:15) + at Object. (plan/agw/implementation-review/regressions.spec.ts:29:9) + + ● R3 owner funds-only outbound encodes the requested destination address + + expect(received).toContain(expected) // indexOf + + Expected substring: "0000000000000000000000000000000000007a76" + Received string: "0x77b86bec000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000007070000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000030d40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003e80000000000000000000000000000000000000000000000000000000000000120000000000000000000000000366e166f4c847a874ad54068e64d3cef77c8c02600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + + 33 | const { rt, gen, wallet } = setup('owner'); + 34 | const out = await composeOutbound(rt, gen, wallet.address, { to: { address: ADDR.target, chain: CHAIN.ETHEREUM_SEPOLIA }, funds: { amount: BigInt(10) } }, { requireCalls: false }); + > 35 | expect(out.gatewayCall.data.toLowerCase()).toContain(ADDR.target.slice(2).toLowerCase()); + | ^ + 36 | }); + 37 | + 38 | it('R4 owner outbound accepts an existing unlimited gateway allowance', async () => { + + at Object. (plan/agw/implementation-review/regressions.spec.ts:35:46) + + ● R4 owner outbound accepts an existing unlimited gateway allowance + + expect(received).not.toThrow() + + Error name: "IntegerOutOfRangeError" + Error message: "Number \"115792089237316195423570985008687907853269984665640564039457584007913129639945\" is not in safe 256-bit unsigned integer range (0 to 115792089237316195423570985008687907853269984665640564039457584007913129639935)· + Version: viem@2.27.2" + + 182 | target: out.token, + 183 | value: BigInt(0), + > 184 | data: encodeFunctionData({ + | ^ + 185 | abi: ERC20_EVM, + 186 | functionName: 'approve', + 187 | args: [gen.addresses.gateway, currentAllowance + out.amount], + + at encodeNumber (node_modules/viem/utils/abi/encodeAbiParameters.ts:340:13) + at prepareParam (node_modules/viem/utils/abi/encodeAbiParameters.ts:169:12) + at prepareParams (node_modules/viem/utils/abi/encodeAbiParameters.ts:126:25) + at encodeAbiParameters (node_modules/viem/utils/abi/encodeAbiParameters.ts:99:26) + at encodeFunctionData (node_modules/viem/utils/abi/encodeFunctionData.ts:93:28) + at ownerOutboundCalls (packages/core/src/lib/agentic/execution/outbound.ts:184:31) + at plan/agw/implementation-review/regressions.spec.ts:41:34 + at Object. (node_modules/expect/build/toThrowMatchers.js:74:11) + at Object.throwingMatcher [as toThrow] (node_modules/expect/build/index.js:320:21) + at Object. (plan/agw/implementation-review/regressions.spec.ts:41:62) + at Object. (plan/agw/implementation-review/regressions.spec.ts:41:62) + + ● R5 decoded static-array pin keeps its argument index + + expect(received).toBe(expected) // Object.is equality + + Expected: 1 + Received: 2 + + 46 | const { terms } = nativeRuleToTerms(input, { nowSeconds: 1700000000 }); + 47 | const decoded = nativeTermsToRule(terms, ADDR.agent, `0x${'00'.repeat(32)}`); + > 48 | expect(decoded.pins?.[0].arg).toBe(1); + | ^ + 49 | }); + 50 | + 51 | it('R5 a decoded simple address-pin rule can be re-encoded after restoring its known signature', () => { + + at Object. (plan/agw/implementation-review/regressions.spec.ts:48:33) + + ● R5 a decoded simple address-pin rule can be re-encoded after restoring its known signature + + expect(received).not.toThrow() + + Error name: "AgenticError" + Error message: "pins[0] expected value does not encode as address: expected an address" + + 128 | + 129 | function invalid(message: string, cause?: unknown): AgenticError { + > 130 | return new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, message, { cause }); + | ^ + 131 | } + 132 | + + at invalid (packages/core/src/lib/agentic/codec/abi-layout.ts:130:10) + at encodeArgWord (packages/core/src/lib/agentic/codec/abi-layout.ts:109:11) + at packages/core/src/lib/agentic/codec/native.ts:121:45 + at Array.map () + at nativeRuleToTerms (packages/core/src/lib/agentic/codec/native.ts:118:23) + at plan/agw/implementation-review/regressions.spec.ts:55:33 + at Object. (node_modules/expect/build/toThrowMatchers.js:74:11) + at Object.throwingMatcher [as toThrow] (node_modules/expect/build/index.js:320:21) + at Object. (plan/agw/implementation-review/regressions.spec.ts:55:109) + at Object. (plan/agw/implementation-review/regressions.spec.ts:55:109) + + ● R6 replayed outbound must replace a preexisting Push route instead of preserving it + + expect(received).toBe(expected) // Object.is equality + + Expected: "UOA_TO_CEA" + Received: "UOA_TO_PUSH" + + 61 | const resp = fakeResponse({ to: wallet.address, data: e704d5b.encodeExecute([out.gatewayCall]), route: 'UOA_TO_PUSH' }); + 62 | const adapted = await adaptTrackedResponse(rt, resp); + > 63 | expect(adapted.route).toBe('UOA_TO_CEA'); + | ^ + 64 | }); + 65 | + 66 | it('R7 failed recovery RPC must not claim that a confirmed deployment did not happen', async () => { + + at Object. (plan/agw/implementation-review/regressions.spec.ts:63:25) + + ● R7 failed recovery RPC must not claim that a confirmed deployment did not happen + + expect(received).not.toBe(expected) // Object.is equality + + Expected: not false + + 79 | const err = await createWallet(rt, 'review', { rules: [{ agent: ADDR.agent, target: ADDR.target, selector: 'increment()', validUntil: 1800000000 }] }).catch(e => e); + 80 | expect(err.code).toBe('CREATE_PARTIAL'); + > 81 | expect(err.details.walletDeployed).not.toBe(false); + | ^ + 82 | }); + 83 | + + at Object. (plan/agw/implementation-review/regressions.spec.ts:81:42) + +Test Suites: 1 failed, 1 total +Tests: 7 failed, 7 total +Snapshots: 0 total +Time: 2.654 s, estimated 7 s +Ran all test suites within paths "plan/agw/implementation-review/regressions.spec.ts". diff --git a/plan/agw/implementation-review/regressions.spec.ts b/plan/agw/implementation-review/regressions.spec.ts new file mode 100644 index 00000000..43da3c45 --- /dev/null +++ b/plan/agw/implementation-review/regressions.spec.ts @@ -0,0 +1,82 @@ +// Reviewer-authored regressions: desired behavior, expected to fail at 3008497. +import { decodeFunctionData, getAddress, maxUint256, type Address, type Hex } from 'viem'; +import { CHAIN, PUSH_NETWORK } from '../../../packages/core/src/lib/constants/enums'; +import { ERC20_EVM } from '../../../packages/core/src/lib/constants/abi'; +import { currentGeneration, resetAgenticGenerations } from '../../../packages/core/src/lib/agentic/deployments'; +import { ADDR, FakeChain, registerFakeGeneration, ruleId } from '../../../packages/core/src/lib/agentic/__tests__/fake-chain'; +import { mockRuntime, fakeResponse } from '../../../packages/core/src/lib/agentic/__tests__/mock-runtime'; +import { agenticSend } from '../../../packages/core/src/lib/agentic/execution/send'; +import { composeOutbound, ownerOutboundCalls } from '../../../packages/core/src/lib/agentic/execution/outbound'; +import { nativeRuleToTerms, nativeTermsToRule } from '../../../packages/core/src/lib/agentic/codec/native'; +import { adaptTrackedResponse } from '../../../packages/core/src/lib/agentic/response'; +import { e704d5b } from '../../../packages/core/src/lib/agentic/contracts/e704d5b'; +import type { AgenticExecutionContext } from '../../../packages/core/src/lib/agentic/context'; + +function setup(door: 'owner' | 'agent' = 'agent') { + registerFakeGeneration(); + const fake = new FakeChain(); + const wallet = fake.addWallet(ADDR.owner, 'review', [fake.nativeRule(ADDR.agent, ruleId(1))]); + const gen = currentGeneration(PUSH_NETWORK.TESTNET_DONUT); + const signer = door === 'owner' ? ADDR.owner : ADDR.agent; + const rt = mockRuntime(fake, { signer }); + const ctx: AgenticExecutionContext = { wallet: wallet.address, door, signerPushAccount: signer, signerOrigin: { chain: CHAIN.PUSH_TESTNET_DONUT, address: signer }, generation: gen }; + return { fake, wallet, gen, rt, ctx }; +} +afterEach(() => resetAgenticGenerations()); + +it('R2 explicit connected Push destination behaves like the bare native address', async () => { + const { rt, ctx } = setup(); + await expect(agenticSend(rt, ctx, { to: { address: ADDR.target, chain: CHAIN.PUSH_TESTNET_DONUT }, data: '0xd09de08a' })).resolves.toBeDefined(); +}); + +it('R3 owner funds-only outbound encodes the requested destination address', async () => { + const { rt, gen, wallet } = setup('owner'); + const out = await composeOutbound(rt, gen, wallet.address, { to: { address: ADDR.target, chain: CHAIN.ETHEREUM_SEPOLIA }, funds: { amount: BigInt(10) } }, { requireCalls: false }); + expect(out.gatewayCall.data.toLowerCase()).toContain(ADDR.target.slice(2).toLowerCase()); +}); + +it('R4 owner outbound accepts an existing unlimited gateway allowance', async () => { + const { rt, gen, wallet } = setup('owner'); + const out = await composeOutbound(rt, gen, wallet.address, { to: { address: ADDR.target, chain: CHAIN.ETHEREUM_SEPOLIA }, data: '0xd09de08a', funds: { amount: BigInt(10) } }, { requireCalls: false }); + expect(() => ownerOutboundCalls(gen, out, maxUint256)).not.toThrow(); +}); + +it('R5 decoded static-array pin keeps its argument index', () => { + const input = { agent: ADDR.agent, target: ADDR.target, selector: 'deposit(uint256[2],address)' as const, validUntil: 1800000000, pins: [{ arg: 1, expected: ADDR.other }] }; + const { terms } = nativeRuleToTerms(input, { nowSeconds: 1700000000 }); + const decoded = nativeTermsToRule(terms, ADDR.agent, `0x${'00'.repeat(32)}`); + expect(decoded.pins?.[0].arg).toBe(1); +}); + +it('R5 a decoded simple address-pin rule can be re-encoded after restoring its known signature', () => { + const input = { agent: ADDR.agent, target: ADDR.target, selector: 'deposit(address,uint256)' as const, validUntil: 1800000000, pins: [{ arg: 0, expected: ADDR.other }] }; + const { terms } = nativeRuleToTerms(input, { nowSeconds: 1700000000 }); + const decoded = nativeTermsToRule(terms, ADDR.agent, `0x${'00'.repeat(32)}`); + expect(() => nativeRuleToTerms({ ...decoded, selector: input.selector }, { nowSeconds: 1700000000 })).not.toThrow(); +}); + +it('R6 replayed outbound must replace a preexisting Push route instead of preserving it', async () => { + const { rt, gen, wallet } = setup('owner'); + const out = await composeOutbound(rt, gen, wallet.address, { to: { address: ADDR.target, chain: CHAIN.ETHEREUM_SEPOLIA }, data: '0xd09de08a' }, { requireCalls: false }); + const resp = fakeResponse({ to: wallet.address, data: e704d5b.encodeExecute([out.gatewayCall]), route: 'UOA_TO_PUSH' }); + const adapted = await adaptTrackedResponse(rt, resp); + expect(adapted.route).toBe('UOA_TO_CEA'); +}); + +it('R7 failed recovery RPC must not claim that a confirmed deployment did not happen', async () => { + registerFakeGeneration(); + const fake = new FakeChain(); + const getCode = fake.getCode.bind(fake); + let rpcUnavailable = false; + fake.getCode = async (args) => { if (rpcUnavailable) throw new Error('RPC unavailable'); return getCode(args); }; + const { PushChainBatchExecutionError } = await import('../../../packages/core/src/lib/orchestrator/internals/errors'); + const { createWallet } = await import('../../../packages/core/src/lib/agentic/management/create'); + const rt = mockRuntime(fake, { signer: ADDR.owner, execute: async () => { + fake.addWallet(ADDR.owner, 'committed'); + rpcUnavailable = true; + throw new PushChainBatchExecutionError('grant failed', [`0x${'11'.repeat(32)}`]); + } }); + const err = await createWallet(rt, 'review', { rules: [{ agent: ADDR.agent, target: ADDR.target, selector: 'increment()', validUntil: 1800000000 }] }).catch(e => e); + expect(err.code).toBe('CREATE_PARTIAL'); + expect(err.details.walletDeployed).not.toBe(false); +}); diff --git a/plan/agw/implementation-review/review.md b/plan/agw/implementation-review/review.md new file mode 100644 index 00000000..914424b3 --- /dev/null +++ b/plan/agw/implementation-review/review.md @@ -0,0 +1,113 @@ +# AGW implementation review + +**Verdict: changes requested before merging or enabling a deployment.** The implementation has useful boundaries and its reported passing suites reproduce, but additional tests expose seven correctness issues. Two reproduce with the actual pinned contracts on local Anvil and affect which permissions survive a transaction. + +Reviewed `feat/agw-sdk-impl@3008497b2492a6be78300011d4572076414505bf` against planning base `349635b2254823488603b37f4b44c4f5c929feb9`. Production files and existing tests were not edited. New review files are confined to this directory. No live-network transaction was sent. The generation registry is empty, so these findings concern implementation readiness rather than a currently enabled public deployment. + +## Findings + +### R1 High priority Granting on the wrong wallet after a create race + +**Source:** [create.ts](../../../packages/core/src/lib/agentic/management/create.ts#L98), construction of deploy/grant calls; the index mismatch is checked only after confirmation at line 129. + +The SDK predicts wallet N, encodes `deployWallet(label)` without binding the expected index, and encodes all grants against wallet N. If another creation for the same owner lands before this operation, the factory deploys N+1 while the grant calls still target N. The SDK then throws INDEX_RACE, but the grants on the other-purpose wallet are already committed. This is more than an inconvenient return value: the agent receives authority on a wallet this creation did not deploy. + +**Reproduced against real contracts:** inserted one owner deployment after composition and before the SDK transport executes. The SDK threw INDEX_RACE, and `getPermissionIDs(predictedWallet)` returned one enabled rule instead of zero. See [local test](local-races.spec.ts), test R1, and [output](local-races.log). + +**Required change:** for sequential creation, confirm the deployed wallet/event before building and signing grants for that actual wallet, revalidating inputs as needed. An atomic creation path needs a contract-enforced expected-index/address condition, such as a verified index-bound deployment intent, or must be gated until safe. An extra RPC read or per-process mutex alone cannot prevent cross-client races. Add a regression asserting that neither another wallet nor the wrong creation receives grants. + +### R2 Medium priority Explicit Push destinations are treated as outbound + +**Source:** [send.ts](../../../packages/core/src/lib/agentic/execution/send.ts#L100). + +`outbound = isChainTarget(p.to)` checks the input shape, not the chain. Therefore `{ to: { address: target, chain: CHAIN.PUSH_TESTNET_DONUT } }` enters the universal path. With a valid native rule it throws “not an EVM universal rule”; owner calls instead attempt destination CEA/outbound composition. The equivalent bare address succeeds. + +**Reproduced:** the explicit connected-Push agent call fails before sending in [regressions.spec.ts](regressions.spec.ts), R2. Core's ordinary [route detector](../../../packages/core/src/lib/orchestrator/route-detector.ts#L186) already distinguishes a Push ChainTarget from a foreign destination. + +**Required change:** normalize the connected Push destination before selecting rulebook, gas fields and call address. Reject incompatible Push network targets explicitly. Cover owner and agent, string and ChainTarget forms, and chain aliases/localnet identity. + +### R3 High priority Transfer-only owner outbounds discard the recipient + +**Source:** [outbound.ts](../../../packages/core/src/lib/agentic/execution/outbound.ts#L50), destinationCalls; [request construction](../../../packages/core/src/lib/agentic/execution/outbound.ts#L137). + +For an owner send with `to: { address: recipient, chain }`, `funds.amount > 0` and no data, the composer creates no destination calls, uses `payload = 0x`, and forces `recipient = 0x`. The requested address is absent from the encoded gateway call. Nevertheless, the response path reports that requested address as the logical `to`. An outbound without any encoded recipient/transfer instruction cannot perform the requested delivery; depending on the gateway/node path it parks value in the wallet's CEA or fails. + +The same empty-call branch ignores a transfer-only `value` request. This is not covered by the successful payload-bearing historical universal experiment. + +**Reproduced:** a positive-amount owner transfer-only request contains no bytes of the intended recipient in the encoded gateway call; R3 in [regressions.spec.ts](regressions.spec.ts). + +**Required change:** preserve owner transfer semantics using the appropriate request recipient or destination transfer payload, including native value behavior. If a shape is not supported yet, reject it explicitly before signing. Do not report a logical delivery that the encoded request never instructs. Add recipient-balance/target-effect acceptance tests when a deployment exists. + +### R4 High priority Automatic owner approval can restore revoked authority + +**Source:** [outbound.ts](../../../packages/core/src/lib/agentic/execution/outbound.ts#L170), ownerOutboundCalls; allowance is read earlier in [send.ts](../../../packages/core/src/lib/agentic/execution/send.ts#L168). + +The owner composer automatically approves `snapshotAllowance + outboundAmount`. That is an unconditional write based on stale state. If an owner revokes the standing allowance after the read but before this send, the batch restores the previous allowance. Likewise, agent spending in the interval can be replenished unintentionally. Atomic approval plus burn does not make the preceding off-chain snapshot atomic. + +**Reproduced against real contracts:** started with allowance 50, composed an outbound of 10, then mined an owner approval of zero before executing the outbound batch. The final allowance was 50, restoring the revoked permission. See R4 in [local-races.spec.ts](local-races.spec.ts) and [output](local-races.log). + +There is also a deterministic boundary failure: an existing `uint256.max` allowance plus any positive amount overflows ABI encoding. R4 in [regressions.spec.ts](regressions.spec.ts) fails before signing with IntegerOutOfRangeError. + +**Required change:** remove the implicit read-modify-write allowance preservation. Prefer the already planned separate bounded owner approval flow, consuming an existing sufficient allowance. If automated approval remains supported, define its explicit authorization and concurrency semantics without reinstating revoked/consumed authority. Handle unlimited and zero-reset token behavior deliberately. Retest both races and maximum allowance. + +### R5 Medium priority Decoded native rules contain misleading argument data + +**Source:** [native.ts](../../../packages/core/src/lib/agentic/codec/native.ts#L196). + +`nativeTermsToRule` converts calldata offsets into public `arg` indexes using `(offset - 4) / 32`, although the encoder supports preceding fixed arrays and static tuples occupying multiple words. For `deposit(uint256[2],address)` the correct pin argument is 1; the returned public record says 2. The on-chain terms do not carry enough ABI information to justify that conversion. + +It also returns every pin's expected word as raw bytes32. A simple address pin cannot be re-encoded even after the caller restores the known function signature: `encodeArgWord(address, bytes32)` rejects the returned expected value. Without restoring the signature, any pinned rule fails because the returned selector is only four bytes. + +**Reproduced:** both static-array indexing and simple address-pin re-encoding fail in R5's two tests in [regressions.spec.ts](regressions.spec.ts). + +**Required change:** recover/require verified ABI context for a faithful public NativeRule, or return an explicitly distinct raw representation/capability error while that metadata is unavailable. Do not label a wire-word index as an argument index. This needs an explicit read/codec contract if the public shape changes. Add encode → read/decode → edit/re-encode tests across addresses, integers, arrays and tuples. + +### R6 Medium priority Replay can retain a non-outbound route after decoding an outbound + +**Source:** [response.ts](../../../packages/core/src/lib/agentic/response.ts#L109). + +After successfully recognizing an AGW gateway outbound, replay uses `resp.route ?? 'UOA_TO_CEA'`. Core can already have assigned UOA_TO_PUSH when the Cosmos record exists but has not yet exposed an outbound leg/status; see [route inference](../../../packages/core/src/lib/orchestrator/internals/tx-transformer.ts#L565). The adapter keeps that route even though it has decoded the outbound calldata. `wait()` then sees a non-outbound route and does not enter destination polling. + +**Reproduced:** a valid decoded AGW outbound carrying a preexisting UOA_TO_PUSH route remains UOA_TO_PUSH in R6 of [regressions.spec.ts](regressions.spec.ts). This covers the adapter boundary; the delayed Cosmos scenario was not exercised live. + +**Required change:** make known AGW execution context authoritative for the route and destination when reconstructing a supported outbound. Test delayed/incomplete Cosmos data through the real response-builder/wait boundary, not only response objects without an existing route. + +### R7 Medium priority Partial-create recovery reports unknown state as absent + +**Source:** [create.ts](../../../packages/core/src/lib/agentic/management/create.ts#L173). + +Recovery starts with `walletDeployed = false` and an empty granted-ID list, then suppresses RPC errors. If deployment committed but the recovery getCode/read fails, CREATE_PARTIAL reports `walletDeployed: false` with the hint “No wallet was deployed.” That can cause an unsafe retry and contradicts the stated exact partial-commit reporting. + +**Reproduced:** simulate a confirmed deployment followed by a grant failure, then make recovery getCode unavailable. R7 returns CREATE_PARTIAL with walletDeployed=false. See [regression](regressions.spec.ts) and [output](regressions.log). + +**Required change:** represent unknown recovery state explicitly, preserve confirmed and pending hashes, and require receipt/state reconciliation before a retry. Derive committed grants from this operation's receipts rather than treating a later active-rule list as its exact outcome. Also preserve the known transaction hash when post-send receipt retrieval fails, instead of returning an unannotated transport error. + +## Verification reproduced + +| Check | Reviewer result | +| --- | --- | +| Full existing unit config | 1,883 passed, 12 skipped; 110 passed suites and 1 skipped | +| Existing local contract harness | 32 passed across 3 suites | +| Library type check | Passed | +| Spec/E2E type check | Passed | +| Core build, cache bypassed | Passed | +| Core lint, cache bypassed | 7 errors in files unchanged from the planning base; not a clean lint run | +| E2E agw manifest | 21 scenarios / 7 files / 21 distinct selected tests; consistent | +| E2E all manifest | 76 scenarios / 40 files / 81 selected tests; unchanged | +| New reviewer regressions | 7 failing SDK/helper-boundary cases and 2 failing real-contract race cases; failures reproduce the findings above | +| Live E2E | Not run | + +Commands and artifact checksums are in [evidence.json](evidence.json). Existing suite results support the implementation's covered behavior; they do not invalidate missing-case failures. Review tests deliberately assert the desired safety/behavior and fail on this revision. They are separate from production test discovery, and may need API-aware adaptation when fixes change the representation rather than preserving it. + +## Notes on the highlighted design choices + +- **Web2 aliases:** the new public alias value follows the saved spec. The old literal is accepted as input and wire identity remains web2:https. This does not preserve every caller's literal equality comparison against returned values. Document that observable migration and obtain the planned public review; it is not counted as a newly discovered algorithmic defect here. +- **Batched-write checkpoints:** extra OWNER_ACTION ticks follow the contract's actual execute semantics. Keep them documented and covered; do not change contracts simply to make batched and direct counts equal. +- **Error export/cause:** preserving the underlying error and exporting the base type is useful and compatible with the intended error hierarchy. +- **Source/deployment claims:** say “no compatible deployment has been verified or registered.” Empty registry and missing manifest are evidence of unavailable support, not proof that no deployment exists anywhere. +- **Active-only list:** A06 remains unresolved. The status matrix acknowledges active-only list behavior, but the public target still says every rule. Keep that restriction clearly provisional and prevent a release from advertising complete historical reads. +- **Live E2E assertions:** the positive outbound checks a shared counter increasing and the SDK-computed CEA metadata. That is not yet independent proof of the actual executing CEA. Strengthen destination caller/event correlation, and harden deployment verification with exact artifacts/capabilities before enabling/funding a live run. Manifest title verification does not exercise those checks. + +## Recommended next implementation pass + +Fix R1 and R4 first, then R2/R3, then the decoder, replay and recovery reporting. Move these regressions into the appropriate normal suites after fixes. Preserve the existing 1,883/32 passing coverage and rerun relevant tests plus the new cases. Continue tracking product/ABI/deployment dependencies separately; they do not explain the reproducible SDK bugs in this report. diff --git a/plan/agw/implementation-review/reviewer.config.cjs b/plan/agw/implementation-review/reviewer.config.cjs new file mode 100644 index 00000000..e826cedf --- /dev/null +++ b/plan/agw/implementation-review/reviewer.config.cjs @@ -0,0 +1,11 @@ +const path = require('path'); +const root = path.resolve(__dirname, '../../..'); +module.exports = { + rootDir: root, + ...require(path.join(root, 'jest.preset.js')), + testEnvironment: 'node', + transform: { '^.+\\.[tj]s$': ['ts-jest', { tsconfig: path.join(root, 'packages/core/tsconfig.agw-local.json') }] }, + moduleFileExtensions: ['ts', 'js', 'json'], + testMatch: ['/plan/agw/implementation-review/*.spec.ts'], + testTimeout: 120000, +}; diff --git a/plan/agw/implementation-review/types-lib.log b/plan/agw/implementation-review/types-lib.log new file mode 100644 index 00000000..e69de29b diff --git a/plan/agw/implementation-review/types-spec.log b/plan/agw/implementation-review/types-spec.log new file mode 100644 index 00000000..e69de29b diff --git a/plan/agw/implementation-review/unit-suite.log b/plan/agw/implementation-review/unit-suite.log new file mode 100644 index 00000000..d3075bdb --- /dev/null +++ b/plan/agw/implementation-review/unit-suite.log @@ -0,0 +1,163 @@ +PASS core packages/core/src/lib/universal/account/account.spec.ts + ● Console + + console.warn + [PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead. + + 207 | ): Promise { + 208 | if (!_convertOriginToExecutorWarned) { + > 209 | console.warn( + | ^ + 210 | '[PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead.' + 211 | ); + 212 | _convertOriginToExecutorWarned = true; + + at Object.convertOriginToExecutor (src/lib/universal/account/account.ts:209:13) + at Object. (src/lib/universal/account/account.spec.ts:80:52) + + console.warn + [PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead. + + 425 | ): Promise { + 426 | if (!options?._internal && !_convertExecutorToOriginWarned) { + > 427 | console.warn( + | ^ + 428 | '[PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead.' + 429 | ); + 430 | _convertExecutorToOriginWarned = true; + + at convertExecutorToOrigin (src/lib/universal/account/account.ts:427:13) + at Object. (src/lib/universal/account/account.spec.ts:106:38) + +PASS core packages/core/src/lib/read-state/__tests__/block-results-client.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-tx-retry.spec.ts +PASS core packages/core/src/lib/push-client/push-client.archive-fallback.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-confirmation-gate.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/response-invariant.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/multichain-hooks.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-evm-r3-native-eoa.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r2-outbound-revert-flow.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-timeout-clamp.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-native-multicall.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-event-hook-bridge.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r1-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-builder-progress-hook.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r2-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-svm-rent.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/inbound-tracker-derivation.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-gas.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/cascade.spec.ts +PASS core packages/core/src/lib/universal/signer/signer.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/source-hash-resolution.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/public-surface.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/context-helpers-tracker.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/registry.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-executor.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-tracker.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/response-builder-push-revert.spec.ts +PASS core packages/core/src/lib/utils.spec.ts + ● Console + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:973:17) + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:977:17) + + console.log + 1.23 + + at Object. (src/lib/utils.spec.ts:982:17) + +PASS core packages/core/src/lib/read-state/__tests__/web2-compat.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm-rent-pc20.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/inbound-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-multichain.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/send.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-emission.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/gate.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-calculator.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-detector.spec.ts +PASS core packages/core/src/lib/push-client/push-client.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/terminal-suppression.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/chain-namespace.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-svm-r3.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-composition.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/resolver.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/send-transaction-progress-hook.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/track-transaction-guard.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-request-recipient.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/rescue-svm-confirmation.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/read-tx-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/signing-payload.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/response-surface.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/payload-builders.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/management.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gateway-uea-account.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/svm-rent.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/scenarios.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/funds-only-burn-guard.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/export.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/resolve.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r3-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-usd-sizer.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/build-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/account-status.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/execute-standard-required-funds.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-evm.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/address-codec.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.chain-symbol.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/normalize.spec.ts +PASS core packages/core/src/lib/constants/__tests__/token-constants.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/svm-account.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/spec-builder.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-svm.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm-log-index.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/revalidate-read.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-params.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.dynamic-gas.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/child-inbounds.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/result-decoder.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/auto-detect.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/abi-selectors.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/__tests__/signing.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/codec.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/reads-context.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/ucallback-codec.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-web2.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/validate.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-events.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg-svm.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/registry.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-types.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/ix-encoder.spec.ts +PASS core packages/core/src/lib/constants/__tests__/svm-gateway-idl.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/max-pc-for-gas.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/classify.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/budget.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/tracking.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-execute-order.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/errors.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/normalize-address.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/error-decoder.spec.ts +PASS core packages/core/src/lib/formatters.spec.ts + +Test Suites: 1 skipped, 110 passed, 110 of 111 total +Tests: 12 skipped, 1883 passed, 1895 total +Snapshots: 0 total +Time: 25.014 s +Ran all test suites. diff --git a/plan/agw/implementation-status.md b/plan/agw/implementation-status.md index 0b7a3751..d412a417 100644 --- a/plan/agw/implementation-status.md +++ b/plan/agw/implementation-status.md @@ -1,6 +1,6 @@ # AGW SDK implementation status -October 3, 2026. Branch `feat/agw-sdk-impl` (base `feat/agw-sdk-planning@349635b`). This matrix records what the code does today against the [implementation plan](implementation-plan.md). "Implemented" excludes placeholders; a capability-gated method that throws `CAPABILITY_UNAVAILABLE` is listed as blocked, not implemented. Details, commands and review hotspots are in the [review handoff](implementation-review-handoff.md). +October 3, 2026, updated after the implementation review (R1–R7 fixed; see the [handoff](implementation-review-handoff.md#review-response-2026-10-03)). Branch `feat/agw-sdk-impl` (base `feat/agw-sdk-planning@349635b`). This matrix records what the code does today against the [implementation plan](implementation-plan.md). "Implemented" excludes placeholders; a capability-gated method that throws `CAPABILITY_UNAVAILABLE` is listed as blocked, not implemented. Details, commands and review hotspots are in the [review handoff](implementation-review-handoff.md). ## Evidence levels @@ -8,7 +8,7 @@ October 3, 2026. Branch `feat/agw-sdk-impl` (base `feat/agw-sdk-planning@349635b | --- | --- | | Unit | Mock-boundary jest suites under `packages/core/src/lib/agentic/__tests__` and `read-state/__tests__/web2-compat.spec.ts`; no network | | Local | Real pinned e704d5b contracts on anvil through the SDK (`packages/core/__agw-local__`); stub gateway only; Push-EOA signers only | -| Live | Testnet transactions against a verified deployment. **None has occurred** — no compatible deployment exists (A07) and no live run was authorized | +| Live | Testnet transactions against a verified deployment. **None has occurred** — no compatible deployment has been verified or registered (A07) and no live run was authorized | ## Per-step matrix @@ -20,11 +20,11 @@ October 3, 2026. Branch `feat/agw-sdk-impl` (base `feat/agw-sdk-planning@349635b | 4 | Generation registry and adapter | Implemented for e704d5b; registry ships empty | ✓ | ✓ wiring verified | Blocked (A07) | Verified manifest; OwnerIntent signing not implemented (no transport needs it) | | 5 | Wallet and checkpoint reads | Implemented: derive, list, info, owner, checkpoints, active rules | ✓ | ✓ | Blocked (A07) | Revoked history (A06), `setLabel` (A07) gated | | 6 | Rule normalization and codecs | Native implemented and vector-verified; universal validated then gated | ✓ | ✓ contract vectors | — | A05 multi-asset wire/vectors; A01/A03 confirmation | -| 7 | Create, add, revoke | Implemented (native rules) | ✓ | ✓ sequential create incl. partial recovery; atomic multi-rule add | Blocked (A07) | 7702/UEA create batch paths unit-only | +| 7 | Create, add, revoke | Implemented (native rules); index-bound deploy | ✓ | ✓ sequential create incl. partial recovery and the concurrent-creation race; atomic multi-rule add | Blocked (A07) | 7702/UEA create batch paths unit-only | | 8 | Atomic rules.update | Implemented for native rules | ✓ | ✓ five ticks, stale-spend rollback | Blocked (A07) | A05 per-token assertion for universal rules | | 9 | Owner execution and allowance setup | Implemented | ✓ | ✓ owner batches, approve/remove via owner door | Blocked (A07) | Production gateway pull/burn | | 10 | Agent rule selection and native sends | Implemented | ✓ | ✓ maxCalls, pins, amount, expiry, A02 | Blocked (A07) | A02 confirmation | -| 11 | EVM universal sends and gas | Composer implemented for the e704d5b single-asset generation; signer gas guard implemented | ✓ | ✓ passes every URP gate with stub gateway | Blocked (A07) | A05 token resolution for assets[]; node/TSS/destination acceptance | +| 11 | EVM universal sends and gas | Composer implemented for the e704d5b single-asset generation (Route-2-equivalent destination calls, no SDK allowance writes); signer gas guard implemented | ✓ | ✓ passes every URP gate with stub gateway; revoked-allowance race | Blocked (A07) | A05 token resolution for assets[]; node/TSS/destination acceptance | | 12 | SVM destination support | Not implemented; gated | ✓ gating | — | — | A05/A07, Harsh H4.4, obligations 19–23 | | 13 | Responses, tracking, hooks, reads | Implemented | ✓ | ✓ live send/receipt identity | Blocked (A07) | Replay and outbound wait need a live run | | 14 | Deployment onboarding and acceptance | E2E authored and gated; not run | — | — | Blocked (A07) | Verified manifest + authorized budget | From a8527778d1f50728fffc0f096b583da5b8c068dc Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Sat, 3 Oct 2026 21:11:39 +0530 Subject: [PATCH 13/68] fix(agw): keep outbound responses consistent across send and replay --- .../__tests__/outbound-response.spec.ts | 300 ++++++++++++++++++ .../src/lib/agentic/__tests__/send.spec.ts | 9 +- .../core/src/lib/agentic/agentic.types.ts | 7 + .../core/src/lib/agentic/execution/send.ts | 17 +- packages/core/src/lib/agentic/response.ts | 31 +- .../lib/orchestrator/orchestrator.types.ts | 2 + plan/agw/.gitattributes | 1 + plan/agw/implementation-review-handoff.md | 9 + plan/agw/implementation-review/README.md | 9 + .../followup-9e16b23/build.log | 13 + .../followup-9e16b23/e2e-agw.log | 24 ++ .../followup-9e16b23/e2e-all.log | 79 +++++ .../followup-9e16b23/evidence.json | 50 +++ .../followup-9e16b23/local.log | 11 + .../followup-9e16b23/replay.log | 32 ++ .../followup-9e16b23/replay.spec.ts | 62 ++++ .../followup-9e16b23/review.md | 65 ++++ .../followup-9e16b23/reviewer.config.cjs | 12 + .../followup-9e16b23/types-lib.log | 0 .../followup-9e16b23/types-spec.log | 0 .../followup-9e16b23/unit.log | 163 ++++++++++ .../outbound-response-resolution.md | 35 ++ plan/agw/implementation-status.md | 5 + 23 files changed, 907 insertions(+), 29 deletions(-) create mode 100644 packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts create mode 100644 plan/agw/implementation-review/README.md create mode 100644 plan/agw/implementation-review/followup-9e16b23/build.log create mode 100644 plan/agw/implementation-review/followup-9e16b23/e2e-agw.log create mode 100644 plan/agw/implementation-review/followup-9e16b23/e2e-all.log create mode 100644 plan/agw/implementation-review/followup-9e16b23/evidence.json create mode 100644 plan/agw/implementation-review/followup-9e16b23/local.log create mode 100644 plan/agw/implementation-review/followup-9e16b23/replay.log create mode 100644 plan/agw/implementation-review/followup-9e16b23/replay.spec.ts create mode 100644 plan/agw/implementation-review/followup-9e16b23/review.md create mode 100644 plan/agw/implementation-review/followup-9e16b23/reviewer.config.cjs create mode 100644 plan/agw/implementation-review/followup-9e16b23/types-lib.log create mode 100644 plan/agw/implementation-review/followup-9e16b23/types-spec.log create mode 100644 plan/agw/implementation-review/followup-9e16b23/unit.log create mode 100644 plan/agw/implementation-review/outbound-response-resolution.md diff --git a/packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts b/packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts new file mode 100644 index 00000000..88686294 --- /dev/null +++ b/packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts @@ -0,0 +1,300 @@ +import { encodeFunctionData, getAddress, type Hex } from 'viem'; +import { CHAIN, PUSH_NETWORK } from '../../constants/enums'; +import { ERC20_EVM } from '../../constants/abi'; +import { TransactionRoute } from '../../orchestrator/route-detector'; +import type { UniversalExecuteParams } from '../../orchestrator/orchestrator.types'; +import { transformToUniversalTxReceipt } from '../../orchestrator/internals/tx-transformer'; +import { transformToUniversalTxResponse } from '../../orchestrator/internals/response-builder'; +import { adaptTrackedResponse } from '../response'; +import { composeOutbound, type DestinationCall } from '../execution/outbound'; +import { agenticSend } from '../execution/send'; +import { e704d5b } from '../contracts/e704d5b'; +import { currentGeneration, resetAgenticGenerations } from '../deployments'; +import type { AgenticExecutionContext } from '../context'; +import { ADDR, FakeChain, registerFakeGeneration, ruleId } from './fake-chain'; +import { mockRuntime, fakeResponse } from './mock-runtime'; + +jest.mock('../../universal/account/account', () => ({ + convertExecutorToOrigin: jest + .fn() + .mockResolvedValue({ account: null, exists: false }), +})); + +afterEach(() => resetAgenticGenerations()); + +const USDC = { + symbol: 'USDC', + decimals: 6, + address: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238' as Hex, + mechanism: 'approve' as const, +}; +const TRANSFER = encodeFunctionData({ + abi: ERC20_EVM, + functionName: 'transfer', + args: [ADDR.target, BigInt(10)], +}); +const TOKEN_CALL: DestinationCall = { + to: getAddress(USDC.address), + data: TRANSFER, + value: BigInt(0), +}; +const APP_CALL: DestinationCall = { + to: ADDR.target, + data: '0xd09de08a', + value: BigInt(0), +}; +const PRC20 = ADDR.other; +const PUSH_HASH = `0x${'ab'.repeat(32)}` as Hex; +const EXTERNAL_HASH = `0x${'ef'.repeat(32)}` as Hex; + +function fixture() { + registerFakeGeneration(); + const fake = new FakeChain(); + const wallet = fake.addWallet(ADDR.owner, 'outbound-review'); + const gen = currentGeneration(PUSH_NETWORK.TESTNET_DONUT); + const read = fake.readContract.bind(fake); + fake.readContract = async (args) => + args.functionName === 'SOURCE_CHAIN_NAMESPACE' + ? CHAIN.ETHEREUM_SEPOLIA + : read(args); + fake.balances.set(`pc:${wallet.address.toLowerCase()}`, BigInt(100000)); + fake.balances.set(`balanceOf:${PRC20.toLowerCase()}`, BigInt(1000)); + fake.balances.set(`allowance:${PRC20.toLowerCase()}`, BigInt(1000)); + const runtime = mockRuntime(fake, { + signer: ADDR.owner, + resolvePrc20: () => PRC20, + }); + runtime.executeMock.mockImplementation( + async (params: { to: string; data?: Hex }) => + fakeResponse({ + to: params.to, + data: params.data ?? '0x', + from: ADDR.owner, + origin: `eip155:42101:${ADDR.owner}`, + }) + ); + const context: AgenticExecutionContext = { + wallet: wallet.address, + generation: gen, + door: 'owner', + signerPushAccount: ADDR.owner, + signerOrigin: { chain: CHAIN.PUSH_TESTNET_DONUT, address: ADDR.owner }, + }; + return { fake, wallet, gen, runtime, context }; +} + +const cases: { + name: string; + params: UniversalExecuteParams; + calls: DestinationCall[]; +}[] = [ + { + name: 'explicit ERC20 transfer preserves its token target and calldata', + params: { + to: { address: USDC.address, chain: CHAIN.ETHEREUM_SEPOLIA }, + data: TRANSFER, + }, + calls: [TOKEN_CALL], + }, + { + name: 'funds-only transfer describes the actual generated token call', + params: { + to: { address: ADDR.target, chain: CHAIN.ETHEREUM_SEPOLIA }, + funds: { amount: BigInt(10), token: USDC }, + }, + calls: [TOKEN_CALL], + }, + { + name: 'funds plus app call keeps the generated transfer and app call in order', + params: { + to: { address: ADDR.target, chain: CHAIN.ETHEREUM_SEPOLIA }, + funds: { amount: BigInt(10), token: USDC }, + data: APP_CALL.data, + }, + calls: [TOKEN_CALL, APP_CALL], + }, + { + name: 'explicit call array retains all calls without guessing a primary action', + params: { + to: { address: ADDR.other, chain: CHAIN.ETHEREUM_SEPOLIA }, + data: [TOKEN_CALL, APP_CALL], + }, + calls: [TOKEN_CALL, APP_CALL], + }, + { + name: 'native transfer preserves the actual destination value', + params: { + to: { address: ADDR.target, chain: CHAIN.ETHEREUM_SEPOLIA }, + value: BigInt(7), + }, + calls: [{ to: ADDR.target, value: BigInt(7), data: '0x' }], + }, +]; + +describe('canonical outbound response on send and replay', () => { + it.each(cases)('$name', async ({ params, calls }) => { + const { wallet, runtime, context } = fixture(); + const live = await agenticSend(runtime, context, params); + const submitted = runtime.executeMock.mock.calls[0][0]; + const replay = await adaptTrackedResponse( + runtime, + fakeResponse({ + to: submitted.to, + data: submitted.data, + origin: live.origin, + from: ADDR.owner, + route: TransactionRoute.UOA_TO_PUSH, + }) + ); + const summary = calls[0]; + for (const response of [live, replay]) { + expect(response).toMatchObject({ + from: wallet.address, + origin: live.origin, + ...summary, + route: TransactionRoute.UOA_TO_CEA, + chain: CHAIN.ETHEREUM_SEPOLIA, + }); + expect(response.agentic?.destinationCalls).toEqual(calls); + expect(response.agentic).toMatchObject({ + rawTo: wallet.address, + rawData: submitted.data, + }); + expect(await response.wait()).toMatchObject({ + from: wallet.address, + to: summary.to, + }); + } + }); +}); + +describe.each(['owner', 'agent'] as const)( + 'outbound replay wait on the %s door', + (door) => { + it.each(['success', 'reverted'] as const)( + 'handles an early Push-only route with a %s Push receipt', + async (status) => { + const { wallet, gen, runtime } = fixture(); + const out = await composeOutbound( + runtime, + gen, + wallet.address, + { + to: { address: ADDR.target, chain: CHAIN.ETHEREUM_SEPOLIA }, + data: APP_CALL.data, + }, + { door } + ); + const input = + door === 'owner' + ? e704d5b.encodeExecute([out.gatewayCall]) + : e704d5b.encodeExecuteAsAgent(ruleId(1), out.gatewayCall); + const signer = door === 'owner' ? ADDR.owner : ADDR.agent; + const tx = { + hash: PUSH_HASH, + from: signer, + to: wallet.address, + input, + value: BigInt(0), + nonce: 1, + gas: BigInt(160000), + gasPrice: BigInt(1), + blockNumber: BigInt(100), + blockHash: `0x${'cd'.repeat(32)}`, + transactionIndex: 0, + type: 'eip1559', + accessList: [], + r: '0x1', + s: '0x2', + v: BigInt(0), + wait: jest.fn().mockResolvedValue({ + transactionHash: PUSH_HASH, + blockNumber: BigInt(100), + blockHash: `0x${'cd'.repeat(32)}`, + transactionIndex: 0, + from: signer, + to: wallet.address, + contractAddress: null, + gasUsed: BigInt(80000), + cumulativeGasUsed: BigInt(80000), + logs: [], + logsBloom: '0x', + status, + }), + }; + const waitForOutboundTx = jest.fn().mockResolvedValue({ + externalTxHash: EXTERNAL_HASH, + destinationChain: CHAIN.ETHEREUM_SEPOLIA, + recipient: ADDR.target, + amount: '0', + assetAddr: PRC20, + explorerUrl: 'https://example.test/tx', + }); + const initHook = jest.fn(); + const perCallHook = jest.fn(); + const response = await transformToUniversalTxResponse( + { + universalSigner: { + account: { chain: CHAIN.PUSH_TESTNET_DONUT, address: signer }, + }, + progressHook: initHook, + } as unknown as Parameters[0], + tx as unknown as Parameters[1], + [], + { + trackTransaction: jest.fn(), + waitForOutboundTx, + transformToUniversalTxReceipt, + printLog: jest.fn(), + outboundConstants: { + initialWaitMs: 0, + pollingIntervalMs: 1, + maxTimeoutMs: 100, + }, + inboundConstants: { + initialWaitMs: 0, + pollingIntervalMs: 1, + maxTimeoutMs: 100, + }, + } + ); + response.route = TransactionRoute.UOA_TO_PUSH; + response.chain = CHAIN.PUSH_TESTNET_DONUT; + await adaptTrackedResponse(runtime, response); + response.progressHook(perCallHook); + const receipt = await response.wait(); + expect(response).toMatchObject({ + from: wallet.address, + route: TransactionRoute.UOA_TO_CEA, + chain: CHAIN.ETHEREUM_SEPOLIA, + }); + expect(response.agentic).toMatchObject({ + door, + destinationCalls: [APP_CALL], + }); + expect(receipt.from).toBe(wallet.address); + if (status === 'success') { + expect(waitForOutboundTx).toHaveBeenCalledTimes(1); + expect(waitForOutboundTx.mock.calls[0][0]).toBe(PUSH_HASH); + expect(receipt).toMatchObject({ + status: 1, + externalStatus: 'success', + externalChain: CHAIN.ETHEREUM_SEPOLIA, + externalTxHash: EXTERNAL_HASH, + }); + } else { + expect(waitForOutboundTx).not.toHaveBeenCalled(); + expect(receipt.status).toBe(0); + expect(receipt.externalStatus).toBeUndefined(); + } + const terminal = + status === 'success' ? 'SEND-TX-299-01' : 'SEND-TX-299-02'; + for (const hook of [initHook, perCallHook]) { + expect( + hook.mock.calls.filter(([event]) => event.id === terminal) + ).toHaveLength(1); + } + } + ); + } +); diff --git a/packages/core/src/lib/agentic/__tests__/send.spec.ts b/packages/core/src/lib/agentic/__tests__/send.spec.ts index 5ec162b2..142e3ca3 100644 --- a/packages/core/src/lib/agentic/__tests__/send.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/send.spec.ts @@ -1,4 +1,4 @@ -import { decodeAbiParameters, decodeFunctionData, getAddress, maxUint256, type Address, type Hex } from 'viem'; +import { decodeAbiParameters, decodeFunctionData, encodeFunctionData, getAddress, maxUint256, type Address, type Hex } from 'viem'; import { CHAIN, PUSH_NETWORK } from '../../constants/enums'; import { UNIVERSAL_GATEWAY_PC, ERC20_EVM } from '../../constants/abi'; import { PushChainExecutionError } from '../../orchestrator/internals/errors'; @@ -236,7 +236,8 @@ describe('EVM outbound composition from the wallet', () => { revertRecipient: s.w.address, }); expect((args[0] as { payload: Hex }).payload.startsWith('0x2cc2842d')).toBe(true); - expect(tx).toMatchObject({ from: s.w.address, to: ADDR.target, route: 'UOA_TO_CEA', chain: CHAIN.ETHEREUM_SEPOLIA }); + expect(tx).toMatchObject({ from: s.w.address, to: token, data: encodeFunctionData({ abi: ERC20_EVM, functionName: 'transfer', args: [ADDR.target, BigInt(100)] }), route: 'UOA_TO_CEA', chain: CHAIN.ETHEREUM_SEPOLIA }); + expect(tx.agentic?.destinationCalls).toHaveLength(2); expect(tx.agentic?.destinationAccount).toBe(getAddress('0x000000000000000000000000000000000000cea1')); }); @@ -342,7 +343,9 @@ describe('EVM outbound composition from the wallet', () => { expect(calls).toHaveLength(1); expect(getAddress(calls[0].to)).toBe(getAddress(usdc.address)); expect(decodeFunctionData({ abi: ERC20_EVM, data: calls[0].data }).args).toEqual([recipient, BigInt(100)]); - expect(tx.to).toBe(recipient); + expect(tx.to).toBe(getAddress(usdc.address)); + expect(tx.data).toBe(calls[0].data); + expect(tx.agentic?.destinationCalls).toEqual(calls.map((c) => ({ ...c, to: getAddress(c.to) }))); }); it('a value-only outbound burns the native PRC20 for that value and forwards it to the recipient', async () => { diff --git a/packages/core/src/lib/agentic/agentic.types.ts b/packages/core/src/lib/agentic/agentic.types.ts index 8216e2d7..19ec5352 100644 --- a/packages/core/src/lib/agentic/agentic.types.ts +++ b/packages/core/src/lib/agentic/agentic.types.ts @@ -190,6 +190,13 @@ export interface AgenticTxMetadata { chainNamespace?: string; /** The wallet's destination account (CEA) for an outbound. */ destinationAccount?: AgenticAddress; + /** + * Ordered calls encoded for the destination CEA. Outbound response + * to/data/value summarize the first call, including an SDK-generated token + * transfer. Replay uses the same representation; it cannot recover which + * calls were supplied explicitly versus generated from funds. + */ + destinationCalls?: readonly { to: AgenticAddress; data: AgenticHex; value: bigint }[]; /** Account the signer's transaction actually called (the wallet). */ rawTo: string; /** Calldata the signer's transaction actually carried. */ diff --git a/packages/core/src/lib/agentic/execution/send.ts b/packages/core/src/lib/agentic/execution/send.ts index 0b9e749c..f3060a85 100644 --- a/packages/core/src/lib/agentic/execution/send.ts +++ b/packages/core/src/lib/agentic/execution/send.ts @@ -20,11 +20,11 @@ import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; import { assertCanSign, emitAgentic, wrapSendError } from '../management/common'; import { selectRuleForSend } from '../reads/rules'; import { Snapshot } from '../reads/snapshot'; -import { adaptAgenticResponse } from '../response'; +import { adaptAgenticResponse, outboundResponseCall } from '../response'; import type { AgenticRuntime } from '../runtime'; import type { AgenticHex, AgenticProgressHook } from '../agentic.types'; import { guardAgenticSendParams } from './guards'; -import { composeOutbound } from './outbound'; +import { composeOutbound, type DestinationCall } from './outbound'; const MODE_UNIVERSAL = 0; const VM_EVM = 0; @@ -134,6 +134,7 @@ export async function agenticSend( let logical: { to: string; data: string; value: bigint }; let meta: { route?: 'UOA_TO_CEA'; destinationAccount?: Address } = {}; let outboundChain: CHAIN | undefined; + let destinationCalls: DestinationCall[] | undefined; if (actx.door === 'agent') { requireCapability(gen.capabilities, AgenticCapability.AGENT_EXECUTE); @@ -235,12 +236,10 @@ export async function agenticSend( } else { wrappedData = gen.contracts.encodeExecute([out.gatewayCall]); } - // The requested target; the encoded destination calls always name it. - logical = { - to: getAddress((p.to as { address: string }).address), - data: typeof p.data === 'string' ? p.data : '0x', - value: p.value ?? BigInt(0), - }; + destinationCalls = out.destinationCalls; + logical = outboundResponseCall(destinationCalls, { + to: out.gatewayCall.target, data: out.gatewayCall.data, value: out.gatewayCall.value, + }); } await enforceSignerGas(runtime, signerFields(p).gasLimit); @@ -271,6 +270,7 @@ export async function agenticSend( rulesId, chainNamespace: outboundChain ?? destination, destinationAccount: meta.destinationAccount as AgenticHex | undefined, + destinationCalls, logical, route: meta.route, chain: outboundChain, @@ -278,4 +278,3 @@ export async function agenticSend( emitAgentic(runtime, hook, PROGRESS_HOOK.AGENTIC_TX_199_01, 'sendTransaction', resp.hash); return resp; } - diff --git a/packages/core/src/lib/agentic/response.ts b/packages/core/src/lib/agentic/response.ts index e0fe8348..e0d7edea 100644 --- a/packages/core/src/lib/agentic/response.ts +++ b/packages/core/src/lib/agentic/response.ts @@ -58,6 +58,7 @@ export function adaptAgenticResponse( ...(meta.rulesId ? { rulesId: meta.rulesId } : {}), ...(meta.chainNamespace ? { chainNamespace: meta.chainNamespace } : {}), ...(meta.destinationAccount ? { destinationAccount: meta.destinationAccount } : {}), + ...(meta.destinationCalls ? { destinationCalls: meta.destinationCalls.map((call) => ({ ...call })) } : {}), rawTo, rawData, }; @@ -105,7 +106,8 @@ export async function adaptTrackedResponse( door, rulesId, chainNamespace: chain, - logical: logicalOutboundCall(out.calls, wallet), + logical: outboundResponseCall(out.calls, { to: outbound.target, data: outbound.data, value: outbound.value }), + ...(out.calls.length > 0 ? { destinationCalls: out.calls } : {}), route: 'UOA_TO_CEA', chain: (chain as CHAIN | undefined) ?? resp.chain, }); @@ -122,24 +124,19 @@ export async function adaptTrackedResponse( }); } -const ERC20_TRANSFER = '0xa9059cbb'; - /** - * The requested destination call, recovered from the payload the wallet's CEA - * runs: the last call (a prepended token transfer precedes the user's call); - * for a transfer-only payload, the transfer's recipient. + * Canonical outbound summary for both send and replay: the first actual + * destination call. The complete ordered calls live in agentic.destinationCalls. + * Identical calldata can come from explicit calls or generated transfers, so + * never infer the original input shape from a selector. For an unrecognized + * historical payload, retain the actual gateway call instead of inventing one. */ -function logicalOutboundCall( - calls: { to: Address; value: bigint; data: Hex }[], - wallet: Address -): { to: string; data: string; value: bigint } { - const last = calls[calls.length - 1]; - if (!last) return { to: wallet, data: '0x', value: BigInt(0) }; - if (calls.length === 1 && last.data.toLowerCase().startsWith(ERC20_TRANSFER) && last.data.length === 2 + 8 + 128) { - const [recipient] = decodeAbiParameters([{ type: 'address' }, { type: 'uint256' }], `0x${last.data.slice(10)}`); - return { to: getAddress(recipient), data: '0x', value: BigInt(0) }; - } - return { to: last.to, data: last.data, value: last.value }; +export function outboundResponseCall( + calls: readonly { to: Address; value: bigint; data: Hex }[], + fallback: LogicalCall +): LogicalCall { + const first = calls[0]; + return first ? { to: first.to, data: first.data, value: first.value } : fallback; } function decodeOutbound(data: Hex): { diff --git a/packages/core/src/lib/orchestrator/orchestrator.types.ts b/packages/core/src/lib/orchestrator/orchestrator.types.ts index 388bcc60..3a5b9f53 100644 --- a/packages/core/src/lib/orchestrator/orchestrator.types.ts +++ b/packages/core/src/lib/orchestrator/orchestrator.types.ts @@ -475,6 +475,8 @@ export interface UniversalTxResponse { * Agentic wallet (AGW) context, present when the transaction executed * through an AGW. `from` is then the wallet and `origin` stays the signer; * `agentic.rawTo` / `rawData` hold the wrapped call the signer sent. + * Outbound to/data/value summarize the first encoded destination call; + * `agentic.destinationCalls` retains the complete ordered call list. */ agentic?: import('../agentic/agentic.types').AgenticTxMetadata; diff --git a/plan/agw/.gitattributes b/plan/agw/.gitattributes index e55dec4d..3a1ab90f 100644 --- a/plan/agw/.gitattributes +++ b/plan/agw/.gitattributes @@ -1,3 +1,4 @@ # Preserve native exports and raw tool output, including original whitespace. notion/** -whitespace research/validation-e704d5b/*.log -whitespace +implementation-review/**/*.log -whitespace diff --git a/plan/agw/implementation-review-handoff.md b/plan/agw/implementation-review-handoff.md index e85e92cf..12e0a2bc 100644 --- a/plan/agw/implementation-review-handoff.md +++ b/plan/agw/implementation-review-handoff.md @@ -180,3 +180,12 @@ Also from this pass: - The E2E positive outbound uses the explicit call-array form and independently checks the wallet CEA's Sepolia balance. Caller/event correlation for the executing CEA is still to be added before a funded run. Counts after the fixes: unit **1,899 passed, 12 skipped** (110 suites passed, 1 skipped; agentic 139); local harness **34 passed in 4 suites**. Library/spec typecheck and build pass. Lint has no errors in changed code (7 pre-existing errors elsewhere). E2E manifests are unchanged (agw 21, all 76). + + +## Outbound response follow-up + +F1 from the follow-up review is fixed. Live and replayed outbound response `to/data/value` now describe the first encoded destination call, with the full ordered list in `agentic.destinationCalls`. This avoids guessing whether a token transfer was explicit or generated from funds. Wrapped raw metadata and signer origin are preserved. + +R6 now has regular tests through the real response-builder/wait closure with mocked RPC/polling, covering owner and agent doors, successful and reverted roots, and init/per-call terminal-hook counts. Live Cosmos/TSS/destination acceptance remains pending. + +Validation: 1,908 unit tests and 34 local-contract tests pass; library/spec typechecks and build pass. Lint retains seven errors in unchanged files. See [resolution and coverage](implementation-review/outbound-response-resolution.md). Product sign-off on raw-offset types and deployment gates are unchanged. diff --git a/plan/agw/implementation-review/README.md b/plan/agw/implementation-review/README.md new file mode 100644 index 00000000..d23da937 --- /dev/null +++ b/plan/agw/implementation-review/README.md @@ -0,0 +1,9 @@ +# AGW implementation review evidence + +The original [review](review.md), tests and logs in this directory describe implementation revision `3008497`. They are historical evidence, including deliberately failing regression assertions. Several tested helpers changed or were removed in the fixes, so the original regression file is not expected to compile against the current implementation. Reproduce it against its recorded revision. + +The [follow-up review at 9e16b23](followup-9e16b23/review.md) verifies fixes in `880e7ae`, reproduces 1,899 unit tests and 34 local-contract tests, adds a passing response-builder/wait check, and identifies the remaining explicit-transfer replay inconsistency. + +Normal acceptance tests live under `packages/core/src/lib/agentic/__tests__/` and `packages/core/__agw-local__/`. Review-specific configurations stay outside their discovery patterns. No review test here authorizes or performs a live-network broadcast. + +The [outbound response resolution](outbound-response-resolution.md) records the subsequent F1 fix and promoted R6 coverage. Current acceptance cases are in the regular SDK suite; historical logs in the follow-up folder still show the earlier failure by design. diff --git a/plan/agw/implementation-review/followup-9e16b23/build.log b/plan/agw/implementation-review/followup-9e16b23/build.log new file mode 100644 index 00000000..71af062d --- /dev/null +++ b/plan/agw/implementation-review/followup-9e16b23/build.log @@ -0,0 +1,13 @@ + +> nx run core:build + +Compiling TypeScript files for project "core"... +Done compiling TypeScript files for project "core". +(node:11617) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. +(Use `node --trace-warnings ...` to show where the warning was created) + + + + NX Successfully ran target build for project core + + diff --git a/plan/agw/implementation-review/followup-9e16b23/e2e-agw.log b/plan/agw/implementation-review/followup-9e16b23/e2e-agw.log new file mode 100644 index 00000000..f173a92d --- /dev/null +++ b/plan/agw/implementation-review/followup-9e16b23/e2e-agw.log @@ -0,0 +1,24 @@ +✓ agw-create-bare 1 test +✓ agw-create-rules 1 test +✓ agw-funding-pc 1 test +✓ agw-funding-allowance 1 test +✓ agw-native-agent 1 test +✓ agw-native-owner 1 test +✓ agw-native-over-cap 1 test +✓ agw-native-stranger 1 test +✓ agw-native-revoked 1 test +✓ agw-native-expired 1 test +✓ agw-lifecycle-add 1 test +✓ agw-lifecycle-update 1 test +✓ agw-lifecycle-checkpoints 1 test +✓ agw-lifecycle-revoke-all 1 test +✓ agw-universal-outbound 1 test +✓ agw-universal-dest-revert 1 test +✓ agw-identity-evm 1 test +✓ agw-identity-first-use 1 test +✓ agw-identity-solana 1 test +✓ agw-responses-hooks 1 test +✓ agw-responses-replay 1 test + +21 scenarios, 7 spec files, 21 distinct tests. +Manifest is consistent with the specs. diff --git a/plan/agw/implementation-review/followup-9e16b23/e2e-all.log b/plan/agw/implementation-review/followup-9e16b23/e2e-all.log new file mode 100644 index 00000000..dfa5f250 --- /dev/null +++ b/plan/agw/implementation-review/followup-9e16b23/e2e-all.log @@ -0,0 +1,79 @@ +✓ smoke-uea-derive-evm 1 test +✓ smoke-read-track-lookup 1 test +✓ smoke-cea-derive-evm 1 test +✓ smoke-roundtrip-evm 1 test +✓ smoke-roundtrip-svm 1 test +✓ smoke-cea-pda-svm 1 test +✓ smoke-gasfee-reads 2 tests +✓ smoke-gas-sizer 2 tests +✓ smoke-pc20-registry 2 tests +✓ smoke-pc20-resolve 1 test +✓ evm-r1-transfer 1 test +✓ evm-r1-funds-usdt 1 test +✓ evm-r1-funds-native 1 test +✓ evm-r1-value-funds-data 1 test +✓ evm-r1-bridge-multicall 1 test +✓ evm-r1-fresh-value-native 1 test +✓ evm-r2-funds-erc20 1 test +✓ evm-r2-payload 1 test +✓ evm-r2-multicall 1 test +✓ evm-r2-funds-payload 1 test +✓ evm-r2-native-funds 1 test +✓ evm-r2-native-funds-payload 1 test +✓ evm-r3-funds-erc20 1 test +✓ evm-r3-payload 1 test +✓ evm-r3-multicall 1 test +✓ evm-r3-funds-payload 1 test +✓ evm-r3-native-funds 1 test +✓ evm-r3-eoa-native-funds 1 test +✓ svm-r1-transfer 1 test +✓ svm-r1-funds-sol-self 1 test +✓ svm-r1-value-self 1 test +✓ svm-r1-data-contract 1 test +✓ svm-r1-fresh-key-repro 1 test +✓ svm-r2-funds-sol 1 test +✓ svm-r2-funds-spl 1 test +✓ svm-r2-payload-cpi 1 test +✓ svm-r2-sol-cpi 1 test +✓ svm-r3-drain-sol 1 test +✓ svm-r3-drain-spl 1 test +✓ pc20-export-deployed-wrapper 1 test +✓ pc20-export-predicts-wrapper 1 test +✓ pc20-inbound-burn-unlock 1 test +✓ pc20-r3-cea-burn 1 test +✓ pc20-svm-r1-direct-burn 1 test +✓ pc20-svm-r3-cea-ata-burn 1 test +✓ push-send-transaction 1 test +✓ push-value-own-uea 1 test +✓ push-multicall-no-funds 1 test +✓ push-track-r1-sepolia-parity 1 test +✓ push-track-r3-funds-roundtrip 1 test +✓ push-track-source-leg-hashes 2 tests +✓ xc-multi-child-r3 1 test +✓ xc-fresh-wallet-r3 1 test +✓ xc-peth-bridge-back 1 test +✓ xc-cascade-6hop 1 test +✓ read-evm-balance-eoa 1 test +✓ read-canonical-registry 1 test +✓ read-evm-balance-uea 1 test +✓ read-evm-contract-call 1 test +✓ read-evm-callback-reverts 1 test +✓ read-expiry 1 test +✓ read-svm-lamports 1 test +✓ read-web2-json 1 test +✓ read-docs-example 1 test +✓ read-docs-evm-balance 1 test +✓ read-docs-batch 1 test +✓ read-docs-resume 2 tests +✓ read-app-batch-eoa 1 test +✓ read-app-batch-uea 1 test +✓ read-app-batch-recovery 1 test +✓ read-api-token 1 test +✓ read-api-mixed-outcomes 1 test +✓ read-svm-token-auto 1 test +✓ read-svm-idl 1 test +✓ read-evm-any-mutability 1 test +✓ read-svm-raw 1 test + +76 scenarios, 40 spec files, 81 distinct tests. +Manifest is consistent with the specs. diff --git a/plan/agw/implementation-review/followup-9e16b23/evidence.json b/plan/agw/implementation-review/followup-9e16b23/evidence.json new file mode 100644 index 00000000..acc2be07 --- /dev/null +++ b/plan/agw/implementation-review/followup-9e16b23/evidence.json @@ -0,0 +1,50 @@ +{ + "reviewed_commit": "9e16b23a76816176dca20793d74df5a5548a497e", + "fix_commit": "880e7ae", + "original_review_commit": "3008497", + "commands": [ + { + "command": "node node_modules/jest/bin/jest.js --config packages/core/jest.config.ts --runInBand", + "result": "1899 passed, 12 skipped" + }, + { + "command": "AGW_LOCAL_DIR= node node_modules/jest/bin/jest.js --config packages/core/jest.agw-local.config.ts --runInBand --forceExit", + "result": "34 passed; local Anvil only" + }, + { + "command": "node node_modules/typescript/bin/tsc -p packages/core/tsconfig.lib.json --noEmit", + "result": "passed" + }, + { + "command": "node node_modules/typescript/bin/tsc -p packages/core/tsconfig.spec.json --noEmit", + "result": "passed" + }, + { + "command": "yarn nx run core:build --skip-nx-cache", + "result": "passed" + }, + { + "command": "cd packages/core; node ../../node_modules/ts-node/dist/bin.js --transpile-only __e2e__/ci/run.ts --verify --group agw; repeat for --group all", + "result": "21 and 76 scenarios; consistent" + }, + { + "command": "node node_modules/jest/bin/jest.js --config plan/agw/implementation-review/followup-9e16b23/reviewer.config.cjs --runInBand", + "result": "1 passed R6 wait path; 1 failed F1 replay metadata" + } + ], + "live_broadcasts": false, + "lint_rerun": false, + "sha256": { + "build.log": "09bf04fbbfdd931522cc613563d0b50228db346468e6b12d8bd3b0d8f0e83a39", + "e2e-agw.log": "547b3068ab4276f9c4e0bbacdff3e6e635a5e812c86ee18dcdc235cf3dca6052", + "e2e-all.log": "3d1649d660267693725f167772c8cfc6b0c51a385e1043d203efe1459798f6ff", + "local.log": "6943d541bc5a51a35088cc21e7b73a1421f649c4f7b499fa6f03f95300c77e4a", + "replay.log": "d529a83860759ef19a53219b174266295b1d1cf32a266de68c048d2be039a09e", + "replay.spec.ts": "a183d9cc10d66c088fa9831a581505e6d229bcbb7fe7496b9017b2fd05c82541", + "review.md": "7eda3e6aa95e6121bd21f41afd13045b5ee1a20b045f30f3e793ac7c78398d17", + "reviewer.config.cjs": "54ec14331588c36c0bd18582eb5be52a5d34f96d18474a9a54f67a9168ff0324", + "types-lib.log": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "types-spec.log": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "unit.log": "62e8f81038a8dd45bb0a681de215281e44c1901dc1c120894bc7ba6f8985dfbf" + } +} diff --git a/plan/agw/implementation-review/followup-9e16b23/local.log b/plan/agw/implementation-review/followup-9e16b23/local.log new file mode 100644 index 00000000..8c3f9656 --- /dev/null +++ b/plan/agw/implementation-review/followup-9e16b23/local.log @@ -0,0 +1,11 @@ +PASS core-agw-local packages/core/__agw-local__/agw-local-advanced.spec.ts (5.222 s) +PASS core-agw-local packages/core/__agw-local__/agw-local-races.spec.ts +PASS core-agw-local packages/core/__agw-local__/agw-local.spec.ts +PASS core-agw-local packages/core/__agw-local__/vectors.spec.ts + +Test Suites: 4 passed, 4 total +Tests: 34 passed, 34 total +Snapshots: 0 total +Time: 9.159 s, estimated 10 s +Ran all test suites. +Force exiting Jest: Have you considered using `--detectOpenHandles` to detect async operations that kept running after all tests finished? diff --git a/plan/agw/implementation-review/followup-9e16b23/replay.log b/plan/agw/implementation-review/followup-9e16b23/replay.log new file mode 100644 index 00000000..d87f4c4c --- /dev/null +++ b/plan/agw/implementation-review/followup-9e16b23/replay.log @@ -0,0 +1,32 @@ +FAIL plan/agw/implementation-review/followup-9e16b23/replay.spec.ts (9.298 s) + ✓ R6 recognized outbound triggers real response-builder wait after an early Push-only route (8 ms) + ✕ F1 replay of an explicitly supplied ERC20 transfer retains the token target and calldata (5 ms) + + ● F1 replay of an explicitly supplied ERC20 transfer retains the token target and calldata + + expect(received).toMatchObject(expected) + + - Expected - 2 + + Received + 2 + + Object { + - "data": "0xa9059cbb00000000000000000000000000000000000000000000000000000000000000b9000000000000000000000000000000000000000000000000000000000000000a", + - "to": "0x0000000000000000000000000000000000007a76", + + "data": "0x", + + "to": "0x00000000000000000000000000000000000000b9", + } + + 59 | const response = fakeResponse({ to: w.address, data: e704d5b.encodeExecute([out.gatewayCall]) }); + 60 | await adaptTrackedResponse(rt, response); + > 61 | expect(response).toMatchObject({ to: ADDR.target, data }); + | ^ + 62 | }); + 63 | + + at Object. (plan/agw/implementation-review/followup-9e16b23/replay.spec.ts:61:20) + +Test Suites: 1 failed, 1 total +Tests: 1 failed, 1 passed, 2 total +Snapshots: 0 total +Time: 9.419 s +Ran all test suites. diff --git a/plan/agw/implementation-review/followup-9e16b23/replay.spec.ts b/plan/agw/implementation-review/followup-9e16b23/replay.spec.ts new file mode 100644 index 00000000..bd90608d --- /dev/null +++ b/plan/agw/implementation-review/followup-9e16b23/replay.spec.ts @@ -0,0 +1,62 @@ +import { encodeFunctionData, type Hex } from 'viem'; +import { CHAIN, PUSH_NETWORK } from '../../../../packages/core/src/lib/constants/enums'; +import { ERC20_EVM } from '../../../../packages/core/src/lib/constants/abi'; +import { TransactionRoute } from '../../../../packages/core/src/lib/orchestrator/route-detector'; +import { transformToUniversalTxReceipt } from '../../../../packages/core/src/lib/orchestrator/internals/tx-transformer'; +import { transformToUniversalTxResponse } from '../../../../packages/core/src/lib/orchestrator/internals/response-builder'; +import { adaptTrackedResponse } from '../../../../packages/core/src/lib/agentic/response'; +import { composeOutbound } from '../../../../packages/core/src/lib/agentic/execution/outbound'; +import { e704d5b } from '../../../../packages/core/src/lib/agentic/contracts/e704d5b'; +import { currentGeneration, resetAgenticGenerations } from '../../../../packages/core/src/lib/agentic/deployments'; +import { ADDR, FakeChain, registerFakeGeneration } from '../../../../packages/core/src/lib/agentic/__tests__/fake-chain'; +import { mockRuntime, fakeResponse } from '../../../../packages/core/src/lib/agentic/__tests__/mock-runtime'; + +jest.mock('../../../../packages/core/src/lib/universal/account/account', () => ({ + convertExecutorToOrigin: jest.fn().mockResolvedValue({ account: null, exists: false }), +})); +afterEach(() => resetAgenticGenerations()); + +function fixture() { + registerFakeGeneration(); + const fake = new FakeChain(); + const w = fake.addWallet(ADDR.owner, 'followup'); + const gen = currentGeneration(PUSH_NETWORK.TESTNET_DONUT); + const read = fake.readContract.bind(fake); + fake.readContract = async (args) => args.functionName === 'SOURCE_CHAIN_NAMESPACE' ? CHAIN.ETHEREUM_SEPOLIA : read(args); + return { fake, w, gen, rt: mockRuntime(fake, { signer: ADDR.owner }) }; +} + +it('R6 recognized outbound triggers real response-builder wait after an early Push-only route', async () => { + const { w, gen, rt } = fixture(); + const out = await composeOutbound(rt, gen, w.address, { to: { address: ADDR.target, chain: CHAIN.ETHEREUM_SEPOLIA }, data: '0xd09de08a' }, { door: 'owner' }); + const hash = `0x${'ab'.repeat(32)}` as Hex; + const tx = { + hash, from: ADDR.owner, to: w.address, input: e704d5b.encodeExecute([out.gatewayCall]), value: BigInt(0), nonce: 1, + gas: BigInt(160000), gasPrice: BigInt(1), blockNumber: BigInt(100), blockHash: `0x${'cd'.repeat(32)}`, transactionIndex: 0, + type: 'eip1559', accessList: [], r: '0x1', s: '0x2', v: BigInt(0), + wait: jest.fn().mockResolvedValue({ transactionHash: hash, blockNumber: BigInt(100), blockHash: `0x${'cd'.repeat(32)}`, transactionIndex: 0, from: ADDR.owner, to: w.address, contractAddress: null, gasUsed: BigInt(80000), cumulativeGasUsed: BigInt(80000), logs: [], logsBloom: '0x', status: 'success' }), + }; + const waitForOutboundTx = jest.fn().mockResolvedValue({ externalTxHash: `0x${'ef'.repeat(32)}`, destinationChain: CHAIN.ETHEREUM_SEPOLIA, recipient: ADDR.target, amount: '0', assetAddr: ADDR.other, explorerUrl: 'https://example.test/tx' }); + const progressHook = jest.fn(); + const response = await transformToUniversalTxResponse({ universalSigner: { account: { chain: CHAIN.PUSH_TESTNET_DONUT, address: ADDR.owner } }, progressHook } as any, tx as any, [], { + trackTransaction: jest.fn(), waitForOutboundTx, transformToUniversalTxReceipt, printLog: jest.fn(), + outboundConstants: { initialWaitMs: 0, pollingIntervalMs: 1, maxTimeoutMs: 100 }, + inboundConstants: { initialWaitMs: 0, pollingIntervalMs: 1, maxTimeoutMs: 100 }, + }); + response.route = TransactionRoute.UOA_TO_PUSH; + response.chain = CHAIN.PUSH_TESTNET_DONUT; + await adaptTrackedResponse(rt, response); + const receipt = await response.wait(); + expect(waitForOutboundTx).toHaveBeenCalledTimes(1); + expect(response.chain).toBe(CHAIN.ETHEREUM_SEPOLIA); + expect(receipt).toMatchObject({ from: w.address, externalStatus: 'success', externalChain: CHAIN.ETHEREUM_SEPOLIA }); +}); + +it('F1 replay of an explicitly supplied ERC20 transfer retains the token target and calldata', async () => { + const { w, gen, rt } = fixture(); + const data = encodeFunctionData({ abi: ERC20_EVM, functionName: 'transfer', args: [ADDR.other, BigInt(10)] }); + const out = await composeOutbound(rt, gen, w.address, { to: { address: ADDR.target, chain: CHAIN.ETHEREUM_SEPOLIA }, data }, { door: 'owner' }); + const response = fakeResponse({ to: w.address, data: e704d5b.encodeExecute([out.gatewayCall]) }); + await adaptTrackedResponse(rt, response); + expect(response).toMatchObject({ to: ADDR.target, data }); +}); diff --git a/plan/agw/implementation-review/followup-9e16b23/review.md b/plan/agw/implementation-review/followup-9e16b23/review.md new file mode 100644 index 00000000..6fac7fee --- /dev/null +++ b/plan/agw/implementation-review/followup-9e16b23/review.md @@ -0,0 +1,65 @@ +# Follow-up review of the R1 through R7 fixes + +Reviewed `9e16b23a76816176dca20793d74df5a5548a497e`, including fixes in `880e7ae`, against the original `3008497` review. The two authorization races are addressed. The other original mechanisms have been corrected, with R5 still requiring public API approval and outbound settlement still requiring live acceptance. One new medium-priority replay inconsistency remains before merge. + +## F1 Explicit ERC20 calls are reinterpreted during replay + +**Priority:** medium. **Source:** [response.ts](../../../../packages/core/src/lib/agentic/response.ts#L138). + +`logicalOutboundCall` treats every one-call payload with selector `0xa9059cbb` and the expected length as an automatically generated funds-only transfer. But a user can explicitly call `transfer(recipient, amount)` on a destination token using `to = token` and `data = transferCalldata`, with no funds input. The live send reports the token and calldata; replay changes them to `to = recipient` and `data = 0x`. + +The serialized call does not distinguish a generated transfer from identical explicit calldata. The current heuristic therefore invents an original input shape and breaks send/track consistency. Amount-bearing receipt interpretation and display of what was actually called can be misleading even though wallet `from` remains correct. + +**Reproduced:** [replay.spec.ts](replay.spec.ts), F1. Expected the explicit token target/calldata; received the transfer beneficiary and empty data. [Output](replay.log). + +**Fix direction:** preserve the actual call representation or define a common canonical representation for both live and replayed responses. Do not infer whether calldata was generated from the selector alone. If requested-recipient conveniences are retained, keep them separate from authoritative execution data. Cover explicit transfer, funds-only transfer, transfer plus contract call, and explicit multicall arrays. + +## Original finding disposition + +| Finding | Follow-up result | Remaining work | +| --- | --- | --- | +| R1 create race | Fixed by index/address-bound factory call. Pinned AGWFactory.sol checks index and prediction before deploying, and skips signature verification only when msg.sender equals owner. Local race/retry coverage passes. | External-owner/UEA and atomic transport acceptance remain part of the existing coverage scope. | +| R2 explicit Push destination | Fixed by normalization of the connected Push chain and rejection of another Push network. | Keep alias/localnet coverage. | +| R3 lost outbound recipient | Composer now encodes transfer/native-value instructions or rejects unsupported empty-call shapes. Explicit call arrays remain caller-authored. | Actual recipient effects and executing CEA correlation still need a verified live deployment. | +| R4 revoked/unlimited allowance | Fixed by removing allowance writes on both paths. A concurrent revocation makes the pull fail; it is not restored. | Production token/gateway acceptance; retain the separate approval setup flow. | +| R5 misleading decode | Raw offsets and exact words now round-trip without pretending to recover ABI indexes. | This extends both input and output types. Product must approve the representation and whether raw authoring is permitted. | +| R6 wrong replay route | Route correction works. The deeper reviewer check below confirms response-builder wait enters outbound polling. | F1 is a separate logical-call reconstruction defect. Live indexing is still untested. | +| R7 false partial-create state | Recovery uses this operation's receipts, keeps unknown state explicit, and preserves submitted hashes when receipt retrieval fails. Updated unit cases pass. | Maintain distinct confirmed/pending/unknown states as recovery evolves. | + +Pinned contract check for R1: [AGWFactory at e704d5b](https://github.com/pushchain/push-agentic-wallets/blob/e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9/src/AGWFactory.sol#L164). Empty signature/deadline is valid on this direct-owner path because only the non-owner branch checks executor, deadline and signature; index and predicted-wallet checks always execute first. + +## Additional R6 verification + +The reviewer constructed a real `transformToUniversalTxResponse` result with an early UOA_TO_PUSH route and Push chain, applied the AGW adapter, then invoked the real `wait()` closure. Destination polling was mocked at the RPC boundary. The test confirms: + +- Route/chain change to the outbound context. +- Destination polling executes exactly once. +- The waited receipt retains AGW from and reports the destination result. + +This closes the previously untested adapter-to-wait linkage locally. It does not exercise the entire trackTransaction acquisition path, real Cosmos timing, node/TSS behavior or live settlement. Keep that limitation separate from the now-tested wait branch. + +## Verification reproduced + +| Check | Result | +| --- | --- | +| Full unit suite | 1,899 passed; 12 skipped; 110 suites passed and 1 skipped | +| Local real-contract harness | 34 passed in 4 suites, including create and allowance races | +| Library typecheck | Passed | +| Spec/E2E typecheck | Passed | +| Core build with cache bypassed | Passed | +| AGW E2E manifest verification | 21 scenarios, 7 files, 21 selected tests | +| Existing all manifest verification | 76 scenarios, 40 files, 81 selected tests | +| Additional replay follow-up | R6 wait-branch test passed; F1 explicit-transfer regression failed | +| Live E2E | Not run | + +Lint was not rerun in this follow-up; the earlier seven-error baseline remains recorded separately. No production file or original review evidence was edited. Only the new follow-up report, tests and logs were added. [Evidence and checksums](evidence.json). + +## Next steps + +1. Fix F1 and add the canonical live/replay cases to the regular suite. Promote the passing R6 response-builder/wait test into regular coverage as well. +2. Add the R5 public type question to the product decision list: should decoded rules expose `{ offset, expected }`, should that raw form be accepted for new grants, or should decoded wire records remain separate from ABI-based authoring? The contract-delegated ABI-position generation obligation needs an explicit answer if raw authoring is exposed. +3. Keep the current registry/capability gates while the existing product and contract answers are pending. Do not replace them with historical Donut addresses to obtain a green live test. +4. Before a funded run, complete destination caller/event correlation, verify exact deployment artifacts/capabilities and network, and check funding budgets and setup. Shared-counter growth plus a computed CEA address is not by itself proof of the actual executor. +5. After F1 and focused regression checks pass, prepare a draft PR for the gated implementation with A01–A08 and the raw-offset API decision clearly identified. Release/live enablement remains a separate gate. + +Keep the original review folder on the branch: it explains the fixes and preserves reproducible evidence. Its tests are tied to the old API and are not the current acceptance suite. The parent README now makes the revision boundaries explicit. diff --git a/plan/agw/implementation-review/followup-9e16b23/reviewer.config.cjs b/plan/agw/implementation-review/followup-9e16b23/reviewer.config.cjs new file mode 100644 index 00000000..235318ac --- /dev/null +++ b/plan/agw/implementation-review/followup-9e16b23/reviewer.config.cjs @@ -0,0 +1,12 @@ +const path = require('path'); +const root = path.resolve(__dirname, '../../../..'); +module.exports = { + ...require(path.join(root, 'jest.preset.js')), + rootDir: root, + testEnvironment: 'node', + modulePathIgnorePatterns: ['/dist/'], + transform: { '^.+\\.[tj]s$': ['ts-jest', { tsconfig: path.join(root, 'packages/core/tsconfig.agw-local.json') }] }, + moduleFileExtensions: ['ts', 'js', 'json'], + testMatch: ['/plan/agw/implementation-review/followup-9e16b23/*.spec.ts'], + testTimeout: 30000, +}; diff --git a/plan/agw/implementation-review/followup-9e16b23/types-lib.log b/plan/agw/implementation-review/followup-9e16b23/types-lib.log new file mode 100644 index 00000000..e69de29b diff --git a/plan/agw/implementation-review/followup-9e16b23/types-spec.log b/plan/agw/implementation-review/followup-9e16b23/types-spec.log new file mode 100644 index 00000000..e69de29b diff --git a/plan/agw/implementation-review/followup-9e16b23/unit.log b/plan/agw/implementation-review/followup-9e16b23/unit.log new file mode 100644 index 00000000..509aa2c8 --- /dev/null +++ b/plan/agw/implementation-review/followup-9e16b23/unit.log @@ -0,0 +1,163 @@ +PASS core packages/core/src/lib/universal/account/account.spec.ts + ● Console + + console.warn + [PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead. + + 207 | ): Promise { + 208 | if (!_convertOriginToExecutorWarned) { + > 209 | console.warn( + | ^ + 210 | '[PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead.' + 211 | ); + 212 | _convertOriginToExecutorWarned = true; + + at Object.convertOriginToExecutor (src/lib/universal/account/account.ts:209:13) + at Object. (src/lib/universal/account/account.spec.ts:80:52) + + console.warn + [PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead. + + 425 | ): Promise { + 426 | if (!options?._internal && !_convertExecutorToOriginWarned) { + > 427 | console.warn( + | ^ + 428 | '[PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead.' + 429 | ); + 430 | _convertExecutorToOriginWarned = true; + + at convertExecutorToOrigin (src/lib/universal/account/account.ts:427:13) + at Object. (src/lib/universal/account/account.spec.ts:106:38) + +PASS core packages/core/src/lib/read-state/__tests__/block-results-client.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-tx-retry.spec.ts +PASS core packages/core/src/lib/utils.spec.ts + ● Console + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:973:17) + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:977:17) + + console.log + 1.23 + + at Object. (src/lib/utils.spec.ts:982:17) + +PASS core packages/core/src/lib/push-client/push-client.archive-fallback.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-confirmation-gate.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-executor.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/response-surface.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-multichain.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-svm-rent.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-usd-sizer.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/send.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/rescue-svm-confirmation.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r2-outbound-revert-flow.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-timeout-clamp.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r3-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-gas.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/web2-compat.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-native-multicall.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-builder-progress-hook.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gateway-uea-account.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/payload-builders.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/signing-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/inbound-tracker-derivation.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/context-helpers-tracker.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/send-transaction-progress-hook.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/gate.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-request-recipient.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-composition.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-detector.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/response-invariant.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/inbound-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-svm-r3.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/build-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/terminal-suppression.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-evm-r3-native-eoa.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/chain-namespace.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/account-status.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r2-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/response-builder-push-revert.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-tracker.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/management.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/cascade.spec.ts +PASS core packages/core/src/lib/universal/signer/signer.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/source-hash-resolution.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/resolve.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/read-tx-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm-rent-pc20.spec.ts +PASS core packages/core/src/lib/push-client/push-client.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/resolver.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/registry.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/funds-only-burn-guard.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r1-spec-strings.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/revalidate-read.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-emission.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/scenarios.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/export.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-calculator.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/execute-standard-required-funds.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/public-surface.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/track-transaction-guard.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/svm-rent.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/multichain-hooks.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-event-hook-bridge.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/svm-account.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/spec-builder.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-svm.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/address-codec.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-params.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/result-decoder.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-evm.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm-log-index.spec.ts +PASS core packages/core/src/lib/constants/__tests__/token-constants.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/child-inbounds.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/codec.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/normalize.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/auto-detect.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.chain-symbol.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/__tests__/signing.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/reads-context.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/abi-selectors.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/registry.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg-svm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/validate.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/ucallback-codec.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-events.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-web2.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.dynamic-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/ix-encoder.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-types.spec.ts +PASS core packages/core/src/lib/constants/__tests__/svm-gateway-idl.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/error-decoder.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/normalize-address.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/errors.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/tracking.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/max-pc-for-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-execute-order.spec.ts +PASS core packages/core/src/lib/formatters.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/classify.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/budget.spec.ts + +Test Suites: 1 skipped, 110 passed, 110 of 111 total +Tests: 12 skipped, 1899 passed, 1911 total +Snapshots: 0 total +Time: 26.405 s, estimated 32 s +Ran all test suites. diff --git a/plan/agw/implementation-review/outbound-response-resolution.md b/plan/agw/implementation-review/outbound-response-resolution.md new file mode 100644 index 00000000..81378b44 --- /dev/null +++ b/plan/agw/implementation-review/outbound-response-resolution.md @@ -0,0 +1,35 @@ +# Outbound response consistency and wait regression resolution + +This change resolves F1 from the [follow-up review](followup-9e16b23/review.md) and promotes R6 wait-path coverage into the regular SDK unit suite. The earlier review evidence remains unchanged and identifies the revisions it tested. + +## Response convention + +Live sends and tracked AGW outbounds now share one canonical summary: `to`, `data` and `value` describe the first actual destination call. `agentic.destinationCalls` contains the complete ordered destination call list. `from` remains the AGW, `origin` remains the signer, and `agentic.rawTo/rawData` retain the wrapped Push call. + +An explicit token transfer therefore keeps the token target and transfer calldata. A funds-only ERC20 send has the same canonical representation: the actual generated token transfer, including its recipient and amount in calldata. A transfer followed by an app call reports the transfer first and preserves both calls in order. Arrays are not reduced to a guessed last or primary action. Native transfers retain their encoded destination value. + +Identical wire calls cannot reveal whether they came from explicit calldata or funds convenience inputs. The adapter no longer attempts that inference. Unrecognized historical destination payloads retain the actual gateway call rather than inventing an empty destination call. + +This is an additive response-metadata field and a correction to the unreleased AGW response summary. Receipts continue using the standard core shape; the full call list is attached to the response. + +## Regular regression coverage + +[Outbound response tests](../../../packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts) add nine cases: + +- Explicit ERC20 call, funds-only ERC20 transfer, transfer plus app call, explicit call array and native-value transfer: verify canonical fields and complete calls match on live send and replay. +- Owner and agent replay, with successful and reverted Push receipts: use the real response builder and wait closure. An early Push-only route becomes outbound; successful roots poll once; reverted roots never poll. Init and per-call terminal hooks each fire once. + +RPC/account lookup and the destination poller are mocked. This exercises the real SDK response/wait branch, not live Cosmos or TSS settlement. The separate historical F1/R6 reviewer tests also pass against the fix. + +## Validation + +- Focused response/send suites: 48 passed. +- Full unit suite: 1,908 passed, 12 skipped; 111 suites passed and 1 skipped. +- Local pinned-contract harness: 34 passed in 4 suites. +- Library/spec typechecks and core build: passed. +- Core lint: seven errors in unchanged files; no new errors from this change. +- No live-network transactions were sent. + +Commands: standard core Jest config with --runInBand, the local AGW Jest config with AGW_LOCAL_DIR set to the prepared e704d5b build, both core tsc --noEmit configs, and the separate commands `yarn nx run core:build --skip-nx-cache` and `yarn nx run core:lint --skip-nx-cache`. + +Raw-offset public types still require product agreement. Compatible deployment, live recipient/executor correlation, and the existing A01–A08 decisions remain separate gates. diff --git a/plan/agw/implementation-status.md b/plan/agw/implementation-status.md index d412a417..b2ca5287 100644 --- a/plan/agw/implementation-status.md +++ b/plan/agw/implementation-status.md @@ -50,3 +50,8 @@ No product decision was assumed approved. No Notion refresh or answers were foun ## Gap register cross-reference Implementation evidence exists for G03 (explicit-context IDs, receipt IDs), G08 (checkpoint/label reads), G13/G15 (creation strategy and partial recovery), G14 (wallet-level replacement), G16 (Web2), G17 (read-only and reinitialize), G18 (eligibility and uncached selection) and G20 (dedicated composer and response identity). None is closed: each closure criterion also requires review and, where stated, a verified deployment or live acceptance. + + +## Outbound response follow-up + +F1 is resolved with a shared canonical first-call summary and complete `agentic.destinationCalls` metadata on send/replay. R6 wait-path regressions are now in the regular unit suite. Current validation: 1,908 unit tests, 34 local-contract tests, both typechecks and build pass. No live acceptance was performed. See [resolution](implementation-review/outbound-response-resolution.md). From cae7206b4cbe9d0908702f7a3b17366594a14b36 Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Sun, 4 Oct 2026 08:00:57 +0530 Subject: [PATCH 14/68] feat(agw): align product scope and add atomic native agent batches --- .../__agw-local__/agw-local-advanced.spec.ts | 4 +- .../__agw-local__/agw-local-batch.spec.ts | 118 +++++++++++++ packages/core/__agw-local__/agw-local.spec.ts | 19 +- packages/core/__e2e__/agw/lifecycle.spec.ts | 7 +- .../core/__e2e__/agw/native-batch.spec.ts | 99 +++++++++++ packages/core/__e2e__/ci/suite.ts | 10 ++ packages/core/__e2e__/shared/agw-state.ts | 31 ++++ .../agw-local/contracts/HarnessFixtures.sol | 16 ++ .../src/lib/agentic/__tests__/codec.spec.ts | 6 +- .../src/lib/agentic/__tests__/mock-runtime.ts | 4 + .../__tests__/native-batch-response.spec.ts | 119 +++++++++++++ .../agentic/__tests__/reads-context.spec.ts | 14 +- .../__tests__/response-surface.spec.ts | 12 +- .../agentic/__tests__/rules-policy.spec.ts | 22 +-- .../src/lib/agentic/__tests__/send.spec.ts | 29 +-- .../core/src/lib/agentic/agentic.types.ts | 16 +- packages/core/src/lib/agentic/capabilities.ts | 10 +- packages/core/src/lib/agentic/codec/native.ts | 31 ---- packages/core/src/lib/agentic/codec/policy.ts | 52 ------ .../core/src/lib/agentic/codec/universal.ts | 4 +- .../core/src/lib/agentic/execution/send.ts | 23 ++- packages/core/src/lib/agentic/index.ts | 2 - packages/core/src/lib/agentic/reads/rules.ts | 31 +--- packages/core/src/lib/agentic/response.ts | 64 ++++++- packages/core/src/lib/agentic/runtime.ts | 14 ++ packages/core/src/lib/agentic/utils.ts | 23 ++- packages/core/src/lib/index.ts | 2 - .../push-chain-native-multicall.spec.ts | 44 +++++ .../src/lib/orchestrator/internals/errors.ts | 8 + .../internals/execute-standard.ts | 5 +- .../orchestrator/internals/push-chain-tx.ts | 17 +- .../core/src/lib/orchestrator/orchestrator.ts | 23 ++- plan/agw/.gitattributes | 1 + plan/agw/README.md | 6 +- plan/agw/SOURCES.md | 2 + plan/agw/contract-integrator-obligations.md | 2 +- plan/agw/current-baseline.md | 2 + plan/agw/external-blockers.md | 56 +++--- plan/agw/gaps.md | 2 + plan/agw/implementation-plan.md | 55 +++--- plan/agw/implementation-review-handoff.md | 9 + plan/agw/implementation-status.md | 30 ++-- plan/agw/product-decisions-2026-10-04.md | 55 ++++++ plan/agw/questions-harsh.md | 159 +++-------------- plan/agw/questions-zaryab.md | 27 +-- .../notion-check-2026-10-04/comparison.json | 18 ++ .../sdk-page-export.zip | Bin 0 -> 14965 bytes .../product-alignment-2026-10-04/README.md | 39 +++++ .../product-alignment-2026-10-04/build.log | 13 ++ .../product-alignment-2026-10-04/e2e-agw.log | 26 +++ .../product-alignment-2026-10-04/e2e-all.log | 79 +++++++++ .../evidence.json | 43 +++++ .../product-alignment-2026-10-04/local.log | 12 ++ .../types-lib.log | 0 .../types-local.log | 0 .../types-spec.log | 0 .../product-alignment-2026-10-04/unit.log | 165 ++++++++++++++++++ plan/agw/sdk-design-review.md | 2 + 58 files changed, 1236 insertions(+), 446 deletions(-) create mode 100644 packages/core/__agw-local__/agw-local-batch.spec.ts create mode 100644 packages/core/__e2e__/agw/native-batch.spec.ts create mode 100644 packages/core/__e2e__/shared/agw-state.ts create mode 100644 packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts delete mode 100644 packages/core/src/lib/agentic/codec/policy.ts create mode 100644 plan/agw/product-decisions-2026-10-04.md create mode 100644 plan/agw/research/notion-check-2026-10-04/comparison.json create mode 100644 plan/agw/research/notion-check-2026-10-04/sdk-page-export.zip create mode 100644 plan/agw/research/product-alignment-2026-10-04/README.md create mode 100644 plan/agw/research/product-alignment-2026-10-04/build.log create mode 100644 plan/agw/research/product-alignment-2026-10-04/e2e-agw.log create mode 100644 plan/agw/research/product-alignment-2026-10-04/e2e-all.log create mode 100644 plan/agw/research/product-alignment-2026-10-04/evidence.json create mode 100644 plan/agw/research/product-alignment-2026-10-04/local.log create mode 100644 plan/agw/research/product-alignment-2026-10-04/types-lib.log create mode 100644 plan/agw/research/product-alignment-2026-10-04/types-local.log create mode 100644 plan/agw/research/product-alignment-2026-10-04/types-spec.log create mode 100644 plan/agw/research/product-alignment-2026-10-04/unit.log diff --git a/packages/core/__agw-local__/agw-local-advanced.spec.ts b/packages/core/__agw-local__/agw-local-advanced.spec.ts index 1723cab1..cc38d4e1 100644 --- a/packages/core/__agw-local__/agw-local-advanced.spec.ts +++ b/packages/core/__agw-local__/agw-local-advanced.spec.ts @@ -1,3 +1,4 @@ +import { readNativeCounters } from '../__e2e__/shared/agw-state'; /** * Real-contract checks for the harder AGW paths (pinned e704d5b on anvil). * The universal-outbound block drives the SDK's composer with a runtime whose @@ -117,7 +118,8 @@ describe('AGW advanced paths against real e704d5b contracts', () => { expect(err).toBeInstanceOf(AgenticRevertError); expect(err.decodedError?.name).toBe("PolicyCheckReverted(ArgPinMismatch)"); const rec = await owner.agentic.wallet(wallet).rules.list(); - expect(rec.rules[0].spent).toMatchObject({ amountSpent: BigInt(5), callsUsed: 1 }); + expect(rec.rules[0]).not.toHaveProperty('spent'); + expect(await readNativeCounters(h.publicClient, h.generation.addresses, wallet, rec.rules[0].rulesId)).toMatchObject({ amountSpent: BigInt(5), callsUsed: 1 }); }); it('per-call and lifetime amount caps are enforced on-chain', async () => { diff --git a/packages/core/__agw-local__/agw-local-batch.spec.ts b/packages/core/__agw-local__/agw-local-batch.spec.ts new file mode 100644 index 00000000..378959a8 --- /dev/null +++ b/packages/core/__agw-local__/agw-local-batch.spec.ts @@ -0,0 +1,118 @@ +/** Real EIP-7702 self-delegation and real AGW/engine/policy; executor is a small + * test-only ERC-7821-shaped CALL dispatcher. No UEA relay or live network. */ +import { + encodeFunctionData, + getAddress, + parseAbi, + type Address, + type Hex, +} from 'viem'; +import { AgenticRevertError, CHAIN, type PushChain } from '../src'; +import { PUSH_BATCH_EXECUTOR_ADDRESS } from '../src/lib/constants/chain'; +import { startHarness, type Harness } from './harness'; +import { readNativeCounters } from '../__e2e__/shared/agw-state'; + +const ABI = parseAbi([ + 'function increment()', + 'function counter() view returns(uint256)', +]); +let h: Harness; +let owner: PushChain; +let previous: Address | undefined; + +beforeAll(async () => { + h = await startHarness(18552); + previous = PUSH_BATCH_EXECUTOR_ADDRESS[CHAIN.PUSH_LOCALNET]; + const executor = await h.deploy( + 0, + 'HarnessAtomicExecutor', + 'HarnessFixtures.sol' + ); + PUSH_BATCH_EXECUTOR_ADDRESS[CHAIN.PUSH_LOCALNET] = executor; + owner = await h.client(0); +}); +afterAll(async () => { + if (previous) PUSH_BATCH_EXECUTOR_ADDRESS[CHAIN.PUSH_LOCALNET] = previous; + else delete PUSH_BATCH_EXECUTOR_ADDRESS[CHAIN.PUSH_LOCALNET]; + await h?.stop(); +}); + +async function walletFor(maxCalls: number) { + const result = await owner.agentic.create('native-batch', { + rules: [ + { + agent: h.wallets[1].account!.address, + target: h.addresses.target, + selector: 'increment()', + validUntil: Number((await h.publicClient.getBlock()).timestamp) + 3600, + maxCalls, + }, + ], + }); + const agent = await h.client(1, { agenticWallet: result.wallet }); + return { ...result, agent }; +} +const calls = () => + Array.from({ length: 2 }, () => ({ + to: h.addresses.target, + value: BigInt(0), + data: encodeFunctionData({ abi: ABI, functionName: 'increment' }), + })); +const counter = () => + h.publicClient.readContract({ + address: h.addresses.target, + abi: ABI, + functionName: 'counter', + }); + +it('atomic native agent array preserves the agent sender and meters both actions', async () => { + const { wallet, rulesIds, agent } = await walletFor(3); + const before = await counter(); + const tx = await agent.universal.sendTransaction({ + to: h.addresses.target, + data: calls(), + }); + expect((await tx.wait()).status).toBe(1); + expect(tx.from).toBe(wallet); + expect(tx.agentic?.nativeCalls).toHaveLength(2); + expect(await counter()).toBe(before + BigInt(2)); + expect( + await readNativeCounters( + h.publicClient, + h.generation.addresses, + wallet, + rulesIds[0] + ) + ).toMatchObject({ callsUsed: 2 }); + // Verify actual type-4 outer transaction and its signer identity independently. + const raw = await h.publicClient.getTransaction({ hash: tx.hash as Hex }); + expect(raw.type).toBe('eip7702'); + expect(getAddress(raw.from)).toBe(h.wallets[1].account!.address); + expect(getAddress(raw.to as Address)).toBe(h.wallets[1].account!.address); +}); + +it('failure of a later native action rolls back the earlier call and its counters', async () => { + const { wallet, rulesIds, agent } = await walletFor(1); + const before = await counter(); + const nonceBefore = await h.publicClient.getTransactionCount({ + address: h.wallets[1].account!.address, + }); + await expect( + agent.universal.sendTransaction({ to: h.addresses.target, data: calls() }) + ).rejects.toBeInstanceOf(AgenticRevertError); + // Prove this was a mined transaction failure, not an early SDK rejection. + expect( + await h.publicClient.getTransactionCount({ + address: h.wallets[1].account!.address, + }) + ).toBeGreaterThan(nonceBefore); + expect(await counter()).toBe(before); + expect( + await readNativeCounters( + h.publicClient, + h.generation.addresses, + wallet, + rulesIds[0] + ) + ).toMatchObject({ callsUsed: 0 }); +}); diff --git a/packages/core/__agw-local__/agw-local.spec.ts b/packages/core/__agw-local__/agw-local.spec.ts index 15bc814d..f9541e34 100644 --- a/packages/core/__agw-local__/agw-local.spec.ts +++ b/packages/core/__agw-local__/agw-local.spec.ts @@ -1,3 +1,4 @@ +import { readNativeCounters } from '../__e2e__/shared/agw-state'; /** * Real-contract checks of the AGW SDK against the pinned e704d5b contracts on a * local anvil chain (see harness.ts for scope and limits). Every assertion @@ -100,11 +101,12 @@ describe('AGW SDK against real e704d5b contracts (local anvil)', () => { ]); }); - it('rules.get / rules.list decode the stored native terms and spend', async () => { + it('rules.get / rules.list decode active terms without exposing internal spend', async () => { const rec = await owner.agentic.wallet(wallet).rules.get(rule1); expect(rec.agent).toBe(agentAddr); expect(rec.rule).toMatchObject({ target: h.addresses.target, maxCalls: 2, maxValuePerCall: BigInt(0) }); - expect(rec.spent).toEqual({ kind: 'native', valueSpent: BigInt(0), amountSpent: BigInt(0), callsUsed: 0 }); + expect(rec).not.toHaveProperty('spent'); + expect(await readNativeCounters(h.publicClient, h.generation.addresses, wallet, rule1)).toEqual({ valueSpent: BigInt(0), amountSpent: BigInt(0), callsUsed: 0 }); const { rules } = await owner.agentic.wallet(wallet).rules.list(); expect(rules.map((r) => r.rulesId)).toEqual([rule1]); }); @@ -139,7 +141,8 @@ describe('AGW SDK against real e704d5b contracts (local anvil)', () => { ).wait(); expect(await checkpointCount(wallet)).toBe(cpBefore); const rec = await owner.agentic.wallet(wallet).rules.get(rule1); - expect(rec.spent).toMatchObject({ kind: 'native', callsUsed: 2 }); + expect(rec).not.toHaveProperty('spent'); + expect(await readNativeCounters(h.publicClient, h.generation.addresses, wallet, rule1)).toMatchObject({ callsUsed: 2 }); const err = await agent.universal .sendTransaction({ to: h.addresses.target, @@ -174,7 +177,7 @@ describe('AGW SDK against real e704d5b contracts (local anvil)', () => { expect(checkpoints.map((c) => c.kind)).toEqual(['OWNER_ACTION', 'OWNER_ACTION']); }); - it('agent native arrays are refused before signing (A02)', async () => { + it('native agent arrays require an available atomic executor instead of sequential fallback', async () => { const data = encodeFunctionData({ abi: TARGET_ABI, functionName: 'increment' }); await expect( agent.universal.sendTransaction({ @@ -184,7 +187,7 @@ describe('AGW SDK against real e704d5b contracts (local anvil)', () => { { to: h.addresses.target, value: BigInt(0), data }, ], }) - ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.NOT_ALLOWED_IN_AGENTIC_MODE }); + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.CAPABILITY_UNAVAILABLE }); }); let rule2: Hex; @@ -210,10 +213,10 @@ describe('AGW SDK against real e704d5b contracts (local anvil)', () => { 'RULES_GRANTED', ]); const rec = await owner.agentic.wallet(wallet).rules.get(rule2); - expect(rec.spent).toMatchObject({ callsUsed: 0 }); + expect(rec).not.toHaveProperty('spent'); + expect(await readNativeCounters(h.publicClient, h.generation.addresses, wallet, rule2)).toMatchObject({ callsUsed: 0 }); await expect(owner.agentic.wallet(wallet).rules.get(rule1)).rejects.toMatchObject({ - code: AGENTIC_ERROR_CODE.CAPABILITY_UNAVAILABLE, - details: { rulesId: rule1, revoked: true }, + code: AGENTIC_ERROR_CODE.RULE_NOT_FOUND, }); const tx = await agent.universal.sendTransaction({ to: h.addresses.target, diff --git a/packages/core/__e2e__/agw/lifecycle.spec.ts b/packages/core/__e2e__/agw/lifecycle.spec.ts index 42da2c05..5997f40f 100644 --- a/packages/core/__e2e__/agw/lifecycle.spec.ts +++ b/packages/core/__e2e__/agw/lifecycle.spec.ts @@ -1,3 +1,4 @@ +import { readNativeCounters } from '@e2e/shared/agw-state'; /** * Scenarios 5 and 6 — add / update / revoke lifecycle and checkpoint counts. * A replacement is five checkpoint ticks; allowance pulls are not ticks. @@ -46,15 +47,15 @@ d('agw lifecycle', () => { it('2. rules.update: old ID disabled, new ID usable with reset counters, five checkpoint ticks', async () => { const agent = await f.agent(wallet); await (await agent.universal.sendTransaction({ to: sink, value: BigInt(10) })).wait(); - const spentBefore = (await f.owner.agentic.wallet(wallet).rules.get(original)).spent; + const spentBefore = await readNativeCounters(f.push, f.manifest.addresses, wallet, original); expect(spentBefore).toMatchObject({ kind: 'native', valueSpent: BigInt(10), callsUsed: 1 }); const before = await count(); const res = await f.owner.agentic.wallet(wallet).rules.update({ rules: [{ rulesId: original, rule: rule(BigInt(2000)) }] }); expect(await count()).toBe(before + BigInt(5)); const replacement = res.rules[0].rulesId; expect(res.rules[0].replaced).toBe(original); - expect((await f.owner.agentic.wallet(wallet).rules.get(replacement)).spent).toMatchObject({ valueSpent: BigInt(0), callsUsed: 0 }); - await expect(f.owner.agentic.wallet(wallet).rules.get(original)).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.CAPABILITY_UNAVAILABLE }); + expect(await readNativeCounters(f.push, f.manifest.addresses, wallet, replacement)).toMatchObject({ valueSpent: BigInt(0), callsUsed: 0 }); + await expect(f.owner.agentic.wallet(wallet).rules.get(original)).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.RULE_NOT_FOUND }); const tx = await agent.universal.sendTransaction({ to: sink, value: BigInt(1500) }); expect(tx.agentic?.rulesId).toBe(replacement); f.evidence('rules-update', { wallet, original, replacement, tx: res.tx.hash, checkpointDelta: 5 }); diff --git a/packages/core/__e2e__/agw/native-batch.spec.ts b/packages/core/__e2e__/agw/native-batch.spec.ts new file mode 100644 index 00000000..5a8e06ac --- /dev/null +++ b/packages/core/__e2e__/agw/native-batch.spec.ts @@ -0,0 +1,99 @@ +/** Opt-in live cases: require the existing verified-manifest gate and native + * EIP-7702 transport. These never accept a sequential fallback as success. */ +import { getAddress, parseEther, type Hex } from 'viem'; +import { AgenticRevertError } from '../../src'; +import { readNativeCounters } from '@e2e/shared/agw-state'; +import { + AGW_E2E_ENABLED, + inSeconds, + setupAgw, + type AgwFixture, +} from './_fixture'; + +const d = AGW_E2E_ENABLED ? describe : describe.skip; +const SINK = getAddress('0x000000000000000000000000000000000000dEaD'); +const calls = () => + Array.from({ length: 2 }, () => ({ + to: SINK, + value: BigInt(1000), + data: '0x' as Hex, + })); + +d('agw native batch', () => { + let f: AgwFixture; + beforeAll(async () => { + f = await setupAgw(); + }, 300_000); + afterAll(() => f?.teardown()); + + const create = async (maxCalls: number) => { + const created = await f.owner.agentic.create('e2e-native-batch', { + rules: [ + { + agent: f.agentAddress, + target: SINK, + selector: 'value-only', + validUntil: inSeconds(3600), + maxValuePerCall: BigInt(1000), + maxValueTotal: BigInt(5000), + maxCalls, + }, + ], + }); + await f.fundPC(created.wallet, parseEther('0.001')); + return { ...created, agent: await f.agent(created.wallet) }; + }; + + it('1. sender-preserving atomic native batch meters both actions', async () => { + const { wallet, rulesIds, agent } = await create(3); + const before = await f.push.getBalance({ address: wallet }); + const tx = await agent.universal.sendTransaction({ + to: SINK, + data: calls(), + }); + expect((await tx.wait()).status).toBe(1); + expect(tx.agentic?.nativeCalls).toEqual(calls()); + expect(tx.from).toBe(wallet); + expect(await f.push.getBalance({ address: wallet })).toBe( + before - BigInt(2000) + ); + expect( + await readNativeCounters( + f.push, + f.manifest.addresses, + wallet, + rulesIds[0] + ) + ).toMatchObject({ callsUsed: 2, valueSpent: BigInt(2000) }); + const raw = await f.push.getTransaction({ hash: tx.hash as Hex }); + expect(raw.type).toBe('eip7702'); + expect(getAddress(raw.from)).toBe(f.agentAddress); + expect(getAddress(raw.to as Hex)).toBe(f.agentAddress); + const replay = await f.owner.universal.trackTransaction(tx.hash); + expect(replay.agentic?.nativeCalls).toEqual(calls()); + expect(replay.from).toBe(wallet); + f.evidence('native-agent-batch', { + wallet, + rulesId: rulesIds[0], + tx: tx.hash, + }); + }); + + it('2. a later policy failure rolls back earlier native actions', async () => { + const { wallet, rulesIds, agent } = await create(1); + const before = await f.push.getBalance({ address: wallet }); + await expect( + agent.universal.sendTransaction({ to: SINK, data: calls() }) + ).rejects.toBeInstanceOf(AgenticRevertError); + expect(await f.push.getBalance({ address: wallet })).toBe(before); + expect( + await readNativeCounters( + f.push, + f.manifest.addresses, + wallet, + rulesIds[0] + ) + ).toMatchObject({ callsUsed: 0, valueSpent: BigInt(0) }); + f.evidence('native-agent-batch-rollback', { wallet, rulesId: rulesIds[0] }); + }); +}); diff --git a/packages/core/__e2e__/ci/suite.ts b/packages/core/__e2e__/ci/suite.ts index cb121fe8..624f9c47 100644 --- a/packages/core/__e2e__/ci/suite.ts +++ b/packages/core/__e2e__/ci/suite.ts @@ -802,6 +802,16 @@ export const SCENARIOS: Scenario[] = [ needs: { masterPC: '1' }, env: { AGW_E2E: '1' }, }, + { + id: 'agw-native-batch', group: 'agw', file: '__e2e__/agw/native-batch.spec.ts', + grep: 'agw native batch 1\\. sender-preserving atomic', + needs: { masterPC: '2' }, env: { AGW_E2E: '1' }, + }, + { + id: 'agw-native-batch-rollback', group: 'agw', file: '__e2e__/agw/native-batch.spec.ts', + grep: 'agw native batch 2\\. a later policy failure', + needs: { masterPC: '2' }, env: { AGW_E2E: '1' }, + }, { id: 'agw-native-agent', group: 'agw', diff --git a/packages/core/__e2e__/shared/agw-state.ts b/packages/core/__e2e__/shared/agw-state.ts new file mode 100644 index 00000000..df4e0ec2 --- /dev/null +++ b/packages/core/__e2e__/shared/agw-state.ts @@ -0,0 +1,31 @@ +/** Independent contract-state assertions for AGW tests; never part of the public SDK. */ +import type { Address, Hex, PublicClient } from 'viem'; +import { e704d5b } from '../../src/lib/agentic/contracts/e704d5b'; +import { configId } from '../../src/lib/agentic/codec/ids'; + +export async function readNativeCounters( + client: PublicClient, + addresses: { sessionEngine: Address; rulesPolicy: Address }, + wallet: Address, + rulesId: Hex +) { + const actions = await client.readContract({ + address: addresses.sessionEngine, + abi: e704d5b.abis.engine, + functionName: 'getEnabledActions', + args: [wallet, rulesId], + }); + if (actions.length !== 1) + throw new Error('Native counter fixture expects one action'); + const cfg = await client.readContract({ + address: addresses.rulesPolicy, + abi: e704d5b.abis.policy, + functionName: 'getNativeConfig', + args: [configId(wallet, rulesId, actions[0]), wallet], + }); + return { + valueSpent: cfg.valueSpent, + amountSpent: cfg.amountSpent, + callsUsed: Number(cfg.callsUsed), + }; +} diff --git a/packages/core/scripts/agw-local/contracts/HarnessFixtures.sol b/packages/core/scripts/agw-local/contracts/HarnessFixtures.sol index b33eeb3c..0a72a91b 100644 --- a/packages/core/scripts/agw-local/contracts/HarnessFixtures.sol +++ b/packages/core/scripts/agw-local/contracts/HarnessFixtures.sol @@ -163,3 +163,19 @@ contract HarnessTarget { received += msg.value; } } + +/// @notice Test-only ERC-7821-shaped executor for real Anvil EIP-7702 transactions. +/// Models self-call authorization and atomic CALL dispatch, not the deployed OZ artifact. +contract HarnessAtomicExecutor { + struct Execution { address target; uint256 value; bytes callData; } + function execute(bytes32 mode, bytes calldata data) external payable { + require(msg.sender == address(this), "self call only"); + require(mode == bytes32(uint256(1) << 248), "batch/default only"); + Execution[] memory calls = abi.decode(data, (Execution[])); + for (uint256 i; i < calls.length; ++i) { + (bool ok, bytes memory ret) = calls[i].target.call{value: calls[i].value}(calls[i].callData); + if (!ok) assembly { revert(add(ret, 32), mload(ret)) } + } + } + receive() external payable {} +} diff --git a/packages/core/src/lib/agentic/__tests__/codec.spec.ts b/packages/core/src/lib/agentic/__tests__/codec.spec.ts index e5fa99b6..a7aab35b 100644 --- a/packages/core/src/lib/agentic/__tests__/codec.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/codec.spec.ts @@ -176,9 +176,9 @@ describe('native rule codec', () => { ); }); - it('approval functions need their spender pinned (A01 / obligation 16)', () => { + it('approval policy is external while caller-supplied pins remain ABI-validated', () => { const base = { agent, target, validUntil: NOW + 10 }; - expect(() => nativeRuleToTerms({ ...base, selector: 'approve(address,uint256)' }, { nowSeconds: NOW })).toThrow(/spender/); + expect(() => nativeRuleToTerms({ ...base, selector: 'approve(address,uint256)' }, { nowSeconds: NOW })).not.toThrow(); expect(() => nativeRuleToTerms( { ...base, selector: 'approve(address,uint256)', pins: [{ arg: 0, expected: agent }] }, @@ -190,7 +190,7 @@ describe('native rule codec', () => { { ...base, selector: 'permit(address,address,uint256,uint256,uint8,bytes32,bytes32)', pins: [{ arg: 0, expected: agent }] }, { nowSeconds: NOW } ) - ).toThrow(/spender/); + ).not.toThrow(); }); }); diff --git a/packages/core/src/lib/agentic/__tests__/mock-runtime.ts b/packages/core/src/lib/agentic/__tests__/mock-runtime.ts index 420db37e..63dec705 100644 --- a/packages/core/src/lib/agentic/__tests__/mock-runtime.ts +++ b/packages/core/src/lib/agentic/__tests__/mock-runtime.ts @@ -7,6 +7,7 @@ import { ADDR, FakeChain, PUSH_NS } from './fake-chain'; export interface MockRuntime extends AgenticRuntime { executeMock: jest.Mock; + atomicMock: jest.Mock; events: ProgressEvent[]; perCallEvents: ProgressEvent[]; fake: FakeChain; @@ -63,6 +64,7 @@ export function mockRuntime( const executeMock = jest.fn(async (params: { to: string; data?: Hex }) => fakeResponse({ to: params.to, data: (params.data as string) ?? '0x' }) ); + const atomicMock = jest.fn(async (params: { to: string }) => fakeResponse({ to: params.to })); const signer = over.signer ?? ADDR.agent; const rt: MockRuntime = { network: PUSH_NETWORK.TESTNET_DONUT, @@ -73,6 +75,7 @@ export function mockRuntime( signerOrigin: () => ({ chain: CHAIN.PUSH_TESTNET_DONUT, address: signer }), signerIsPushNative: () => true, execute: executeMock as unknown as AgenticRuntime['execute'], + executeAtomicBatch: atomicMock as unknown as AgenticRuntime['executeAtomicBatch'], emit: (event, perCall) => { events.push(event); if (perCall) { @@ -89,6 +92,7 @@ export function mockRuntime( nowSeconds: () => 1_700_000_000, ...over, executeMock, + atomicMock, events, perCallEvents, fake, diff --git a/packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts b/packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts new file mode 100644 index 00000000..b0acb668 --- /dev/null +++ b/packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts @@ -0,0 +1,119 @@ +import { encodeAbiParameters, type Hex } from 'viem'; +import { CHAIN, PUSH_NETWORK } from '../../constants/enums'; +import { PUSH_BATCH_EXECUTOR_ADDRESS } from '../../constants/chain'; +import { convertExecutorToOrigin } from '../../universal/account/account'; +import { adaptTrackedResponse } from '../response'; +import { e704d5b, UEA_MULTICALL_PREFIX } from '../contracts/e704d5b'; +import { resetAgenticGenerations } from '../deployments'; +import { ADDR, FakeChain, registerFakeGeneration, ruleId } from './fake-chain'; +import { fakeResponse, mockRuntime } from './mock-runtime'; + +jest.mock('../../universal/account/account', () => ({ + convertExecutorToOrigin: jest.fn(), +})); +afterEach(() => { + resetAgenticGenerations(); + jest.clearAllMocks(); +}); + +function fixture() { + registerFakeGeneration(); + const fake = new FakeChain(); + const wallet = fake.addWallet(ADDR.owner, 'batch'); + const actions = [ + { target: ADDR.target, value: BigInt(0), data: '0xd09de08a' as Hex }, + { target: ADDR.target, value: BigInt(2), data: '0xd09de08a' as Hex }, + ]; + const outer = actions.map((c) => ({ + target: wallet.address, + value: BigInt(0), + data: e704d5b.encodeExecuteAsAgent(ruleId(1), c), + })); + const runtime = mockRuntime(fake); + return { fake, wallet, actions, outer, runtime }; +} + +it('recognizes a verified 7702 self-call and retains every native agent action', async () => { + const { fake, wallet, actions, outer, runtime } = fixture(); + const getCode = fake.getCode.bind(fake); + fake.getCode = async (p) => + p.address === ADDR.agent + ? (`0xef0100${PUSH_BATCH_EXECUTOR_ADDRESS[ + CHAIN.PUSH_TESTNET_DONUT + ]!.slice(2)}` as Hex) + : getCode(p); + const result = await adaptTrackedResponse( + runtime, + fakeResponse({ + from: ADDR.agent, + to: ADDR.agent, + data: e704d5b.encodeExecute(outer), + }) + ); + expect(result).toMatchObject({ + from: wallet.address, + to: actions[0].target, + agentic: { + door: 'agent', + rulesId: ruleId(1), + rawTo: ADDR.agent, + nativeCalls: actions.map((c) => ({ + to: c.target, + value: c.value, + data: c.data, + })), + }, + }); +}); + +it('recognizes a verified UEA multicall carrying single agent-door entries', async () => { + const { wallet, actions, outer, runtime } = fixture(); + (convertExecutorToOrigin as jest.Mock).mockResolvedValue({ + exists: true, + account: { chain: CHAIN.ETHEREUM_SEPOLIA, address: ADDR.owner }, + }); + const data = (UEA_MULTICALL_PREFIX + + encodeAbiParameters( + [ + { + type: 'tuple[]', + components: [ + { name: 'to', type: 'address' }, + { name: 'value', type: 'uint256' }, + { name: 'data', type: 'bytes' }, + ], + }, + ], + [outer.map((c) => ({ to: c.target, value: c.value, data: c.data }))] + ).slice(2)) as Hex; + const result = await adaptTrackedResponse( + runtime, + fakeResponse({ + from: ADDR.agent, + to: wallet.address, + data, + raw: { + from: ADDR.other, + to: ADDR.agent, + nonce: 0, + data, + value: BigInt(0), + }, + }) + ); + expect(result.from).toBe(wallet.address); + expect(result.agentic?.nativeCalls).toEqual( + actions.map((c) => ({ to: c.target, value: c.value, data: c.data })) + ); +}); + +it('does not label an arbitrary forwarding contract as a trusted sender batch', async () => { + const { outer, runtime } = fixture(); + const response = fakeResponse({ + from: ADDR.agent, + to: ADDR.other, + data: e704d5b.encodeExecute(outer), + }); + expect(await adaptTrackedResponse(runtime, response)).toBe(response); + expect(response.agentic).toBeUndefined(); +}); diff --git a/packages/core/src/lib/agentic/__tests__/reads-context.spec.ts b/packages/core/src/lib/agentic/__tests__/reads-context.spec.ts index 4f342486..b5331a30 100644 --- a/packages/core/src/lib/agentic/__tests__/reads-context.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/reads-context.spec.ts @@ -141,7 +141,7 @@ describe('rules.list / rules.get', () => { afterEach(() => resetAgenticGenerations()); const gen = () => currentGeneration(PUSH_NETWORK.TESTNET_DONUT); - it('decodes native records with spend', async () => { + it('decodes active native records without exposing internal spend', async () => { const w = fake.addWallet(ADDR.owner, 'w', [ fake.nativeRule(ADDR.agent, ruleId(1), { callsUsed: 3, valueSpent: BigInt(5), maxCalls: 9 }), ]); @@ -152,12 +152,17 @@ describe('rules.list / rules.get', () => { enabled: true, chainNamespace: PUSH_NS, agent: ADDR.agent, - spent: { kind: 'native', valueSpent: BigInt(5), amountSpent: BigInt(0), callsUsed: 3 }, rule: expect.objectContaining({ maxCalls: 9, selector: '0xd09de08a' }), }), ]); }); + it('public records contain no spent field', async () => { + const w = fake.addWallet(ADDR.owner, 'w', [fake.nativeRule(ADDR.agent, ruleId(1))]); + const record = await getRule(await Snapshot.at(fake), gen(), w.address, ruleId(1), PUSH_NS); + expect(record).not.toHaveProperty('spent'); + }); + it('a universal rule cannot be decoded into the public type yet (A05) — the list fails, it is not truncated', async () => { const w = fake.addWallet(ADDR.owner, 'w', [ fake.nativeRule(ADDR.agent, ruleId(1)), @@ -168,7 +173,7 @@ describe('rules.list / rules.get', () => { }); }); - it('get: unknown → RULE_NOT_FOUND; revoked → history capability (A06), not an empty record', async () => { + it('unknown and revoked IDs both return RULE_NOT_FOUND without history reconstruction', async () => { const w = fake.addWallet(ADDR.owner, 'w'); const snap = await Snapshot.at(fake); await expect(getRule(snap, gen(), w.address, ruleId(9), PUSH_NS)).rejects.toMatchObject({ @@ -176,8 +181,7 @@ describe('rules.list / rules.get', () => { }); fake.extraLogs.push(log(w.address, e704d5b.events.rulesRevoked, { rulesId: ruleId(9) }, {}, BigInt(50))); await expect(getRule(snap, gen(), w.address, ruleId(9), PUSH_NS)).rejects.toMatchObject({ - code: AGENTIC_ERROR_CODE.CAPABILITY_UNAVAILABLE, - details: { rulesId: ruleId(9), revoked: true }, + code: AGENTIC_ERROR_CODE.RULE_NOT_FOUND, }); }); }); diff --git a/packages/core/src/lib/agentic/__tests__/response-surface.spec.ts b/packages/core/src/lib/agentic/__tests__/response-surface.spec.ts index b285b7af..537a63c6 100644 --- a/packages/core/src/lib/agentic/__tests__/response-surface.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/response-surface.spec.ts @@ -116,10 +116,14 @@ describe('public surface', () => { it('PushChain.utils.agentic is the pure helper set', () => { expect(Object.keys(Utils.agentic).sort()).toEqual( - ['actionId', 'compileCard', 'configId', 'decodeRules', 'deriveWallet', 'encodeRules', 'rulesId'].sort() + ['actionId', 'configId', 'decodeRules'].sort() ); - expect( - Utils.agentic.deriveWallet(ADDR.owner, 0, { factory: ADDR.factory, walletImplementation: ADDR.impl }) - ).toBe(getAddress(Utils.agentic.deriveWallet(ADDR.owner, BigInt(0), { factory: ADDR.factory, walletImplementation: ADDR.impl }))); + // @ts-expect-error generation context helpers are not public + expect(Utils.agentic.rulesId).toBeUndefined(); + // @ts-expect-error the marketplace compiler is outside AGW + expect(Utils.agentic.compileCard).toBeUndefined(); + for (const name of ['rulesId', 'deriveWallet', 'encodeRules', 'compileCard']) { + expect(Utils.agentic).not.toHaveProperty(name); + } }); }); diff --git a/packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts b/packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts index d5676150..0252889d 100644 --- a/packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts @@ -4,7 +4,7 @@ import { prepareRules } from '../codec/rules'; import { validateUniversalRuleShape } from '../codec/universal'; import { E704D5B_CAPABILITIES } from '../deployments'; import { AGENTIC_ERROR_CODE } from '../errors'; -import { agenticUtils } from '../utils'; +import { internalAgenticUtils } from '../utils'; import type { NativeRule, UniversalRule } from '../agentic.types'; import { ADDR, PUSH_NS, SEPOLIA_NS } from './fake-chain'; @@ -119,13 +119,10 @@ describe('universal rules — validated, then capability-gated (A01, A05)', () = ).toThrow(/duplicates/); }); - it('A01: approval selectors are refused in agent universal rules', () => { - expect(() => - validateUniversalRuleShape(universal({ allowedCalls: [{ target: ADDR.target, selector: 'approve(address,uint256)' }] }), NOW) - ).toThrow(expect.objectContaining({ details: expect.objectContaining({ assumption: 'A01' }) })); - expect(() => - validateUniversalRuleShape(universal({ allowedCalls: [{ target: ADDR.target, selector: '0x39509351' }] }), NOW) - ).toThrow(/increaseAllowance/); + it('approval policy belongs to UI/marketplace; structurally valid approval calls are accepted', () => { + for (const selector of ['approve(address,uint256)', 'increaseAllowance(address,uint256)'] as const) { + expect(() => validateUniversalRuleShape(universal({ allowedCalls: [{ target: ADDR.target, selector }] }), NOW)).not.toThrow(); + } }); it('a beneficiary must be an address argument of a known signature', () => { @@ -150,8 +147,8 @@ describe('universal rules — validated, then capability-gated (A01, A05)', () = }); }); -describe('PushChain.utils.agentic (pure)', () => { - const u = agenticUtils; +describe('internal generation codecs (pure)', () => { + const u = internalAgenticUtils; it('encodeRules → decodeRules round-trips a native rule', () => { const rule = native({ selector: 'deposit(address,uint256)', pins: [{ arg: 0, expected: ADDR.other }], maxCalls: 4 }); @@ -172,9 +169,4 @@ describe('PushChain.utils.agentic (pure)', () => { expect(u.actionId(ADDR.target, 'increment()')).toBe(u.actionId(ADDR.target, '0xd09de08a')); }); - it('compileCard is explicitly unavailable (A08)', () => { - expect(() => u.compileCard({}, {}, {})).toThrow( - expect.objectContaining({ details: expect.objectContaining({ capability: AgenticCapability.COMPILE_CARD }) }) - ); - }); }); diff --git a/packages/core/src/lib/agentic/__tests__/send.spec.ts b/packages/core/src/lib/agentic/__tests__/send.spec.ts index 142e3ca3..b49e51cd 100644 --- a/packages/core/src/lib/agentic/__tests__/send.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/send.spec.ts @@ -54,18 +54,27 @@ describe('guards fail before the signer is ever invoked', () => { expect(rt.executeMock).not.toHaveBeenCalled(); }); - it('agent native arrays are refused (A02)', async () => { + it.each([true, false])('agent native arrays require an atomic sender-preserving transport (Push EOA=%s)', async (native) => { const { rt, ctx } = setup('agent'); - await expect( - agenticSend(rt, ctx, { - to: ADDR.target, - data: [ - { to: ADDR.target, value: BigInt(0), data }, - { to: ADDR.target, value: BigInt(0), data }, - ], - }) - ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.NOT_ALLOWED_IN_AGENTIC_MODE }); + rt.signerIsPushNative = () => native; + const calls = [{ to: ADDR.target, value: BigInt(0), data }, { to: ADDR.target, value: BigInt(1), data }]; + const tx = await agenticSend(rt, ctx, { to: ADDR.target, data: calls }); + expect(rt.executeMock).not.toHaveBeenCalled(); + expect(rt.atomicMock).toHaveBeenCalledTimes(1); + const batch = rt.atomicMock.mock.calls[0][0].data as { to: Address; value: bigint; data: Hex }[]; + expect(batch.map((c) => c.to)).toEqual([ctx.wallet, ctx.wallet]); + expect(batch.map((c) => e704d5b.decodeWalletCall(c.data))).toEqual(calls.map((c) => ({ + kind: 'executeAsAgent', rulesId: ruleId(1), mode: `0x${'00'.repeat(32)}`, + calls: [{ target: c.to, value: c.value, data: c.data }], + }))); + expect(tx.agentic?.nativeCalls).toEqual(calls); + }); + + it('empty native arrays fail before any transport is called', async () => { + const { rt, ctx } = setup('agent'); + await expect(agenticSend(rt, ctx, { to: ADDR.target, data: [] })).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.INVALID_RULE }); expect(rt.executeMock).not.toHaveBeenCalled(); + expect(rt.atomicMock).not.toHaveBeenCalled(); }); it('NO_RULES_FOR_CHAIN and DUPLICATE_RULE are pre-signature', async () => { diff --git a/packages/core/src/lib/agentic/agentic.types.ts b/packages/core/src/lib/agentic/agentic.types.ts index 19ec5352..30d814a7 100644 --- a/packages/core/src/lib/agentic/agentic.types.ts +++ b/packages/core/src/lib/agentic/agentic.types.ts @@ -82,15 +82,6 @@ export interface UniversalRule { export type Rule = NativeRule | UniversalRule; -/** - * Spend counters for a rule. PROVISIONAL (A05, Harsh H4.2): the universal - * scalar `amountSpent` cannot represent multi-asset rules; the per-token - * shape is pending. - */ -export type Spent = - | { kind: 'universal'; amountSpent: bigint } - | { kind: 'native'; valueSpent: bigint; amountSpent: bigint; callsUsed: number }; - export interface RulesRecord { rulesId: AgenticHex; enabled: boolean; @@ -99,7 +90,6 @@ export interface RulesRecord { validUntil: number; ref: AgenticHex; rule: Rule; - spent: Spent; } export interface CreateOptions { @@ -152,7 +142,9 @@ export interface AgenticWallet { ): Promise; checkpoints(opts?: { sinceBlock?: bigint }): Promise<{ checkpoints: Checkpoint[] }>; rules: { + /** Enabled rules only; expired-but-enabled rules remain visible. No public spend counters. */ list(): Promise<{ rules: RulesRecord[] }>; + /** Unknown and revoked IDs both return RULE_NOT_FOUND; v1 has no historical records. */ get(rulesId: AgenticHex): Promise; add( rules: Rule[], @@ -197,7 +189,9 @@ export interface AgenticTxMetadata { * calls were supplied explicitly versus generated from funds. */ destinationCalls?: readonly { to: AgenticAddress; data: AgenticHex; value: bigint }[]; - /** Account the signer's transaction actually called (the wallet). */ + /** Ordered actions in a native agent batch; to/data/value summarize its first action. */ + nativeCalls?: readonly { to: AgenticAddress; data: AgenticHex; value: bigint }[]; + /** Account the signer's transaction actually called (wallet or outer sender account). */ rawTo: string; /** Calldata the signer's transaction actually carried. */ rawData: string; diff --git a/packages/core/src/lib/agentic/capabilities.ts b/packages/core/src/lib/agentic/capabilities.ts index 4d31236e..24e211a7 100644 --- a/packages/core/src/lib/agentic/capabilities.ts +++ b/packages/core/src/lib/agentic/capabilities.ts @@ -33,10 +33,7 @@ export enum AgenticCapability { GRANT_REF = 'grantRef', /** Editable wallet label (setLabel / LabelSet). A07. */ SET_LABEL = 'setLabel', - /** Revoked-rule history in rules.list/get. A06. */ - RULE_HISTORY = 'ruleHistory', - /** Canonical card compiler. A08. */ - COMPILE_CARD = 'compileCard', + } /** Why each target capability is unavailable when a generation lacks it. */ @@ -60,10 +57,7 @@ export const CAPABILITY_DEPENDENCY: Record = { 'the selected generation has no grant reference parameter/event (A07)', [AgenticCapability.SET_LABEL]: 'the selected generation has no editable label (A07; labels are deploy-time only)', - [AgenticCapability.RULE_HISTORY]: - 'revoked-rule history scope and reliable metadata are unresolved (A06)', - [AgenticCapability.COMPILE_CARD]: - 'canonical card schema, encoding and shared vectors are not agreed (A08)', + }; export function hasCapability( diff --git a/packages/core/src/lib/agentic/codec/native.ts b/packages/core/src/lib/agentic/codec/native.ts index bdf5ae0f..2b79d1c9 100644 --- a/packages/core/src/lib/agentic/codec/native.ts +++ b/packages/core/src/lib/agentic/codec/native.ts @@ -12,7 +12,6 @@ import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; import type { AgenticHex, NativeRule } from '../agentic.types'; import { argumentOffset, encodeArgWord, rawOffset } from './abi-layout'; import { AGENTIC_DEFAULTS, UINT256_MAX, withDefault } from './defaults'; -import { APPROVAL_SELECTORS } from './policy'; import { parseSelector, VALUE_ONLY_SELECTOR, type ParsedSelector } from './selectors'; /** URP native limits at e704d5b (Types.sol MAX_PINS, AGW MAX_NATIVE_ACTIONS). */ @@ -62,19 +61,6 @@ export const NATIVE_TERMS_PARAM: AbiParameter = { ], }; -/** - * Spender argument index of known approval functions. Obligation 16 / A01: - * a native rule may allow one only when that argument is pinned. - */ -const APPROVAL_SPENDER_ARG: Readonly> = { - '0x095ea7b3': 0, - '0x39509351': 0, - '0xa22cb465': 0, - '0xd505accf': 1, - '0x87517c45': 1, - '0x2b67b570': null, // Permit2 permit: spender is inside a tuple — never representable -}; - function invalid(message: string, details?: Record): AgenticError { return new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, message, { details }); } @@ -130,23 +116,6 @@ export function nativeRuleToTerms( const offsets = new Set(pins.map((p) => p.offset)); if (offsets.size !== pins.length) throw invalid('two pins address the same argument'); - const spenderArg = APPROVAL_SPENDER_ARG[parsed.selector]; - if (spenderArg !== undefined) { - // Every argument of these approval functions before the spender is one - // static word, so the spender's calldata offset is exact. - const pinnedSpender = spenderArg !== null && offsets.has(4 + 32 * spenderArg); - if (!pinnedSpender) { - throw new AgenticError( - AGENTIC_ERROR_CODE.INVALID_RULE, - `${APPROVAL_SELECTORS[parsed.selector]} needs its spender argument pinned`, - { - hint: 'Pin the spender, or set approvals from the owner door. Provisional policy A01 / obligation 16.', - details: { assumption: 'A01' }, - } - ); - } - } - let amount: NativeTermsWire['amount'] = { enabled: false, offset: 0, diff --git a/packages/core/src/lib/agentic/codec/policy.ts b/packages/core/src/lib/agentic/codec/policy.ts deleted file mode 100644 index a2939bbf..00000000 --- a/packages/core/src/lib/agentic/codec/policy.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; -import type { AgenticHex } from '../agentic.types'; - -/** - * PROVISIONAL product-policy boundary (one place, both assumptions): - * - * A01 (Harsh H1): known approval-granting selectors are rejected in agent - * rules, because the rule cannot pin an arbitrary approved spender. Owners - * set bounded approvals through the owner door instead. Filtering known - * selectors is one safeguard, not a complete target-safety boundary. - * A02 (Harsh H2): NativeRule stays one action, and a native agent send must be - * a single call — no transaction arrays through the agent door, and no - * sequential fallback. Owner batches and bounded EVM destination - * multicalls are unaffected. - */ -export const APPROVAL_SELECTORS: Readonly> = { - '0x095ea7b3': 'approve(address,uint256)', - '0x39509351': 'increaseAllowance(address,uint256)', - '0xa22cb465': 'setApprovalForAll(address,bool)', - '0xd505accf': 'permit(address,address,uint256,uint256,uint8,bytes32,bytes32)', - '0x2b67b570': 'permit(address,((address,uint160,uint48,uint48),address,uint256),bytes)', - '0x87517c45': 'approve(address,address,uint160,uint48)', -}; - -export function assertNotApprovalSelector(selector: AgenticHex, where: string): void { - const name = APPROVAL_SELECTORS[selector.toLowerCase()]; - if (name) { - throw new AgenticError( - AGENTIC_ERROR_CODE.INVALID_RULE, - `${where}: ${name} grants token spending to an address the rule cannot pin`, - { - hint: - 'Set bounded approvals from the owner door (owner-mode sendTransaction) instead of granting them to an agent. Provisional policy A01.', - details: { selector, assumption: 'A01' }, - } - ); - } -} - -export function assertSingleAgentCall(calls: number): void { - if (calls !== 1) { - throw new AgenticError( - AGENTIC_ERROR_CODE.NOT_ALLOWED_IN_AGENTIC_MODE, - `the agent door dispatches exactly one native call; got ${calls}`, - { - hint: - 'Send each native action separately, or use an owner client for batches. Provisional scope A02.', - details: { assumption: 'A02' }, - } - ); - } -} diff --git a/packages/core/src/lib/agentic/codec/universal.ts b/packages/core/src/lib/agentic/codec/universal.ts index b657cd16..ccd47551 100644 --- a/packages/core/src/lib/agentic/codec/universal.ts +++ b/packages/core/src/lib/agentic/codec/universal.ts @@ -3,7 +3,6 @@ import { AgenticCapability, requireCapability } from '../capabilities'; import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; import type { UniversalRule } from '../agentic.types'; import { argumentOffset } from './abi-layout'; -import { assertNotApprovalSelector } from './policy'; import { parseSelector } from './selectors'; /** Proposed multi-asset limits (page 1 §4c) and the pinned allow-list limit. */ @@ -15,7 +14,7 @@ const CAIP2 = /^(eip155:[0-9]+|solana:[1-9A-HJ-NP-Za-km-z]{32,44})$/; /** * Structural validation of a TARGET UniversalRule that does not depend on the * unresolved wire format: chain id shape, call allow-list, selector/beneficiary - * positions and the A01 approval policy. Runs before the capability gate so + * positions. Approval policy is left to UI/marketplace (Harsh H1). Runs before the capability gate so * callers get precise input errors. */ export function validateUniversalRuleShape(rule: UniversalRule, nowSeconds: number): void { @@ -45,7 +44,6 @@ export function validateUniversalRuleShape(rule: UniversalRule, nowSeconds: numb } const parsed = parseSelector(call.selector); if (parsed.valueOnly) throw invalid(`allowedCalls[${i}] cannot be value-only`); - assertNotApprovalSelector(parsed.selector, `allowedCalls[${i}]`); if (call.beneficiary !== undefined) { argumentOffset(parsed.inputs, call.beneficiary, `allowedCalls[${i}].beneficiary`); const t = (parsed.inputs ?? [])[call.beneficiary]?.type; diff --git a/packages/core/src/lib/agentic/execution/send.ts b/packages/core/src/lib/agentic/execution/send.ts index f3060a85..0972f385 100644 --- a/packages/core/src/lib/agentic/execution/send.ts +++ b/packages/core/src/lib/agentic/execution/send.ts @@ -4,6 +4,7 @@ import { ERC20_EVM } from '../../constants/abi'; import { PROGRESS_HOOK } from '../../progress-hook/progress-hook.types'; import type { ExecuteParams, + MultiCall, TransactionExecutionOptions, UniversalExecuteParams, UniversalTxResponse, @@ -15,7 +16,6 @@ import type { AgenticExecutionContext } from '../context'; import type { Call, UniversalConfigReadE704d5b } from '../contracts/e704d5b'; import { SEND_OUTBOUND_SELECTOR } from '../contracts/e704d5b'; import { actionId, configId } from '../codec/ids'; -import { assertSingleAgentCall } from '../codec/policy'; import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; import { assertCanSign, emitAgentic, wrapSendError } from '../management/common'; import { selectRuleForSend } from '../reads/rules'; @@ -130,6 +130,8 @@ export async function agenticSend( } let wrappedData: Hex; + let agentBatch: MultiCall[] | undefined; + let nativeCalls: Call[] | undefined; let rulesId: AgenticHex | undefined; let logical: { to: string; data: string; value: bigint }; let meta: { route?: 'UOA_TO_CEA'; destinationAccount?: Address } = {}; @@ -144,19 +146,25 @@ export async function agenticSend( if (!outbound) { const calls = toCalls(p); + if (calls.length === 0) throw new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, 'an empty call array cannot execute'); if (actx.door === 'owner') { wrappedData = gen.contracts.encodeExecute(calls); } else { - assertSingleAgentCall(calls.length); const snap = await Snapshot.at(runtime.reader); const rule = await selectRuleForSend(snap, gen, wallet, actx.signerPushAccount, destination); rulesId = rule.rulesId as AgenticHex; wrappedData = gen.contracts.encodeExecuteAsAgent(rule.rulesId, calls[0]); + if (calls.length > 1) { + agentBatch = calls.map((call) => ({ to: wallet, value: BigInt(0), data: gen.contracts.encodeExecuteAsAgent(rule.rulesId, call) })); + nativeCalls = calls; + } } logical = calls.length === 1 ? { to: calls[0].target, data: calls[0].data, value: calls[0].value } - : { to: wallet, data: wrappedData, value: BigInt(0) }; + : agentBatch + ? { to: calls[0].target, data: calls[0].data, value: calls[0].value } + : { to: wallet, data: wrappedData, value: BigInt(0) }; } else { let ruleAsset: Address | undefined; let maxPCPerCall: bigint | undefined; @@ -247,10 +255,10 @@ export async function agenticSend( let resp: UniversalTxResponse; try { - resp = await runtime.execute( - { ...signerFields(p), to: wallet, value: BigInt(0), data: wrappedData }, - hook ? { ...options, progressHook: hook } : options - ); + const sendOptions = hook ? { ...options, progressHook: hook } : options; + resp = agentBatch + ? await runtime.executeAtomicBatch({ ...signerFields(p), to: wallet, value: BigInt(0), data: agentBatch }, sendOptions) + : await runtime.execute({ ...signerFields(p), to: wallet, value: BigInt(0), data: wrappedData }, sendOptions); } catch (err) { const wrapped = wrapSendError(err) as { code?: string; message?: string; decodedError?: unknown }; emitAgentic( @@ -271,6 +279,7 @@ export async function agenticSend( chainNamespace: outboundChain ?? destination, destinationAccount: meta.destinationAccount as AgenticHex | undefined, destinationCalls, + ...(nativeCalls ? { nativeCalls: nativeCalls.map((c) => ({ to: c.target, data: c.data, value: c.value })) } : {}), logical, route: meta.route, chain: outboundChain, diff --git a/packages/core/src/lib/agentic/index.ts b/packages/core/src/lib/agentic/index.ts index 0ba0a0dc..7e1ca3c6 100644 --- a/packages/core/src/lib/agentic/index.ts +++ b/packages/core/src/lib/agentic/index.ts @@ -17,7 +17,6 @@ export type { Rule, RulesRecord, Selector, - Spent, UniversalRule, WalletInfo, WalletSummary, @@ -27,4 +26,3 @@ export type { AgenticErrorCode } from './errors'; export { AGENTIC } from './constants'; export type { AgenticNetworkConstants } from './constants'; export { agenticUtils } from './utils'; -export type { RulesEncodeContext } from './utils'; diff --git a/packages/core/src/lib/agentic/reads/rules.ts b/packages/core/src/lib/agentic/reads/rules.ts index 8219b0a4..eacb5ef3 100644 --- a/packages/core/src/lib/agentic/reads/rules.ts +++ b/packages/core/src/lib/agentic/reads/rules.ts @@ -8,7 +8,7 @@ import { nativeTermsToRule } from '../codec/native'; import { chainHash } from '../codec/rules'; import { AGENTIC_ERROR_CODE, AgenticError, capabilityUnavailable } from '../errors'; import type { AgenticHex, RulesRecord } from '../agentic.types'; -import { Snapshot, scanLogs } from './snapshot'; +import { Snapshot } from './snapshot'; const ZERO_REF = `0x${'00'.repeat(32)}` as AgenticHex; const MODE_UNIVERSAL = 0; @@ -175,12 +175,7 @@ export async function decodeActiveRule( validUntil: Number(cfg.validUntil), ref: ZERO_REF, rule: nativeTermsToRule(cfg, rule.agent, ZERO_REF), - spent: { - kind: 'native', - valueSpent: cfg.valueSpent, - amountSpent: cfg.amountSpent, - callsUsed: Number(cfg.callsUsed), - }, + }; } @@ -220,8 +215,8 @@ export async function listRules( } /** - * rules.get: an enabled rule decodes; a revoked rule needs the history - * capability (A06); an ID that was never granted is RULE_NOT_FOUND. + * rules.get returns enabled records only. Unknown/revoked IDs are deliberately + * indistinguishable without historical reconstruction, which is outside v1. */ export async function getRule( snap: Snapshot, @@ -241,20 +236,8 @@ export async function getRule( const active = await readActiveRule(snap, gen, wallet, rulesId); return decodeActiveRule(snap, gen, wallet, active, pushChainNamespace); } - const revoked = await scanLogs( - snap.reader, - { address: wallet, event: gen.contracts.events.rulesRevoked, args: { rulesId } }, - gen.startBlock, - snap.blockNumber + throw new AgenticError( + AGENTIC_ERROR_CODE.RULE_NOT_FOUND, + `rule ${rulesId} is not enabled on ${wallet} (unknown or revoked; v1 has no rule history)` ); - if (gen.contracts.parseRulesRevoked(revoked, wallet).length > 0) { - // No generation implements history reconstruction yet; a revoked rule is - // reported as such rather than as an empty or missing record. - const err = capabilityUnavailable( - AgenticCapability.RULE_HISTORY, - `rule ${rulesId} was revoked; ${CAPABILITY_DEPENDENCY[AgenticCapability.RULE_HISTORY]}` - ); - throw new AgenticError(err.code, err.message, { details: { rulesId, revoked: true } }); - } - throw new AgenticError(AGENTIC_ERROR_CODE.RULE_NOT_FOUND, `rule ${rulesId} was never granted on ${wallet}`); } diff --git a/packages/core/src/lib/agentic/response.ts b/packages/core/src/lib/agentic/response.ts index e0d7edea..bc1424c6 100644 --- a/packages/core/src/lib/agentic/response.ts +++ b/packages/core/src/lib/agentic/response.ts @@ -6,12 +6,16 @@ import { type Hex, } from 'viem'; import { CHAIN } from '../constants/enums'; +import { getBatchExecutorAddress } from '../constants/chain'; +import { getPushChainForNetwork } from '../orchestrator/internals/helpers'; +import { convertExecutorToOrigin } from '../universal/account/account'; +import { pushChainNamespaceFor } from './chain'; import { UNIVERSAL_GATEWAY_PC } from '../constants/abi'; import type { TransactionRouteType, UniversalTxResponse, } from '../orchestrator/orchestrator.types'; -import { e704d5b, SEND_OUTBOUND_SELECTOR, UEA_MULTICALL_PREFIX } from './contracts/e704d5b'; +import { e704d5b, SEND_OUTBOUND_SELECTOR, UEA_MULTICALL_PREFIX, type Call } from './contracts/e704d5b'; import { generationsFor, resolveWalletGeneration } from './deployments'; import type { AgenticRuntime } from './runtime'; import type { AgenticAddress, AgenticHex, AgenticTxMetadata } from './agentic.types'; @@ -59,6 +63,7 @@ export function adaptAgenticResponse( ...(meta.chainNamespace ? { chainNamespace: meta.chainNamespace } : {}), ...(meta.destinationAccount ? { destinationAccount: meta.destinationAccount } : {}), ...(meta.destinationCalls ? { destinationCalls: meta.destinationCalls.map((call) => ({ ...call })) } : {}), + ...(meta.nativeCalls ? { nativeCalls: meta.nativeCalls.map((call) => ({ ...call })) } : {}), rawTo, rawData, }; @@ -75,6 +80,8 @@ export async function adaptTrackedResponse( resp: UniversalTxResponse ): Promise { if (resp.agentic || generationsFor(runtime.network).length === 0) return resp; + const batch = await adaptNativeAgentBatch(runtime, resp); + if (batch) return batch; const decoded = e704d5b.decodeWalletCall(resp.data as Hex); if (!decoded || (decoded.kind !== 'execute' && decoded.kind !== 'executeAsAgent')) return resp; let wallet: Address; @@ -124,6 +131,61 @@ export async function adaptTrackedResponse( }); } +/** Decode only supported sender-account batches, never an arbitrary forwarding helper. */ +async function adaptNativeAgentBatch( + runtime: Pick, + resp: UniversalTxResponse +): Promise { + let outer: Call[]; + const isUea = resp.data.toLowerCase().startsWith(UEA_MULTICALL_PREFIX); + try { + if (isUea) { + const [entries] = decodeAbiParameters([ + { type: 'tuple[]', components: [{ name: 'to', type: 'address' }, { name: 'value', type: 'uint256' }, { name: 'data', type: 'bytes' }] }, + ], `0x${resp.data.slice(10)}`); + outer = entries.map((c) => ({ target: getAddress(c.to), value: c.value, data: c.data })); + } else { + const batch = e704d5b.decodeWalletCall(resp.data as Hex); + if (batch?.kind !== 'execute' || batch.mode !== `0x01${'00'.repeat(31)}`) return; + outer = batch.calls; + } + if (outer.length < 2 || outer.some((c) => c.value !== BigInt(0) || c.target !== outer[0].target)) return; + const inner = outer.map((c) => e704d5b.decodeWalletCall(c.data)); + const first = inner[0]; + if (first?.kind !== 'executeAsAgent' || first.calls.length !== 1) return; + const nativeCalls: { to: Address; value: bigint; data: Hex }[] = []; + for (const c of inner) { + if (c?.kind !== 'executeAsAgent' || c.calls.length !== 1 || c.rulesId !== first.rulesId || c.mode !== `0x${'00'.repeat(32)}`) return; + const call = c.calls[0]; + nativeCalls.push({ to: call.target, value: call.value, data: call.data }); + } + const senderAccount = getAddress(resp.from); + if (isUea) { + if (getAddress(resp.raw?.to ?? resp.to) !== senderAccount) return; + const origin = await convertExecutorToOrigin(senderAccount, { _internal: true }); + if (!origin.exists) return; + } else { + if (getAddress(resp.to) !== senderAccount) return; + const executor = getBatchExecutorAddress(getPushChainForNetwork(runtime.network)); + if (!executor) return; + const code = await runtime.reader.getCode({ address: senderAccount, blockNumber: resp.blockNumber }); + if (code?.toLowerCase() !== `0xef0100${executor.slice(2).toLowerCase()}`) return; + } + const wallet = outer[0].target; + const gen = await resolveWalletGeneration(runtime.reader, runtime.network, wallet); + // This recognizer is only for native arrays; keep mixed/outbound batches raw. + if (nativeCalls.some((c) => c.to === gen.addresses.gateway)) return; + return adaptAgenticResponse(resp, { + wallet, door: 'agent', rulesId: first.rulesId as AgenticHex, + chainNamespace: pushChainNamespaceFor(runtime.network), nativeCalls, + logical: { ...nativeCalls[0] }, + }); + } catch { + // Unsupported payload or unverified sender/wallet: preserve the original response. + return; + } +} + /** * Canonical outbound summary for both send and replay: the first actual * destination call. The complete ordered calls live in agentic.destinationCalls. diff --git a/packages/core/src/lib/agentic/runtime.ts b/packages/core/src/lib/agentic/runtime.ts index acee8142..ba27ee3b 100644 --- a/packages/core/src/lib/agentic/runtime.ts +++ b/packages/core/src/lib/agentic/runtime.ts @@ -1,6 +1,8 @@ import { getAddress, type Address } from 'viem'; import { CHAIN, PUSH_NETWORK } from '../constants/enums'; import type { MoveableToken } from '../constants/tokens'; +import { AtomicBatchUnavailableError } from '../orchestrator/internals/errors'; +import { capabilityUnavailable } from './errors'; import type { Orchestrator } from '../orchestrator/orchestrator'; import type { ExecuteParams, @@ -41,6 +43,8 @@ export interface AgenticRuntime { params: ExecuteParams | UniversalExecuteParams, options?: TransactionExecutionOptions ): Promise; + /** Sender-preserving UEA/7702 transport; native sequential fallback is forbidden. */ + executeAtomicBatch(params: ExecuteParams, options?: TransactionExecutionOptions): Promise; /** Emit to the init-time hook and, if different, the per-call hook. */ emit(event: ProgressEvent, perCallHook?: AgenticProgressHook): void; /** Whether the signer's own UEA is deployed (always true for a Push EOA). */ @@ -72,6 +76,16 @@ export function createAgenticRuntime(orchestrator: Orchestrator, isReadOnly: boo signerOrigin: () => orchestrator.getUOA(), signerIsPushNative: () => isPushChain(ctx.universalSigner.account.chain), execute: (params, options) => orchestrator.execute(params, options), + executeAtomicBatch: async (params, options) => { + try { + return await orchestrator.executeAtomicBatch(params, options); + } catch (error) { + if (error instanceof AtomicBatchUnavailableError) { + throw capabilityUnavailable('atomicNativeAgentBatch', error.message); + } + throw error; + } + }, emit: (event, perCallHook) => { const base = orchestrator.getProgressHook(); base?.(event); diff --git a/packages/core/src/lib/agentic/utils.ts b/packages/core/src/lib/agentic/utils.ts index be986a0b..cbb2b65d 100644 --- a/packages/core/src/lib/agentic/utils.ts +++ b/packages/core/src/lib/agentic/utils.ts @@ -12,9 +12,8 @@ import { pushChainNamespaceFor } from './chain'; import type { AgenticHex, Rule, Selector } from './agentic.types'; /** - * Generation context for the pure helpers. PROVISIONAL public shape (A04, - * Harsh H4.1): the spec's helper signatures omit the validator / factory / - * implementation inputs the results depend on, so they are explicit here. + * Internal generation context. Harsh H4.1 (October 4): deployment inputs + * are implementation details, not public helper parameters. */ export interface RulesEncodeContext { /** Connected Push network, or an explicit 'eip155:' native chain. */ @@ -33,8 +32,8 @@ function nativeNamespace(ctx: { network?: PUSH_NETWORK; pushChainNamespace?: str return pushChainNamespaceFor(ctx.network ?? PUSH_NETWORK.TESTNET_DONUT); } -/** PushChain.utils.agentic — pure; no RPC. */ -export const agenticUtils = { +/** Internal codecs and identities — not exported from the package entry point. */ +export const internalAgenticUtils = { /** The ID a grant with this grantNonce produces. Chain is not part of the hash. */ rulesId(agent: Address, grantNonce: bigint | number, ctx: { validator: Address }): AgenticHex { return rulesIdRaw({ @@ -104,11 +103,11 @@ export const agenticUtils = { return nativeTermsToRule(decodeNativeTerms(body), agent, `0x${'00'.repeat(32)}`); }, - /** Canonical card compiler — not available until the shared schema exists (A08). */ - compileCard(_card: unknown, _userInput: unknown, _ctx: unknown): never { - throw capabilityUnavailable( - AgenticCapability.COMPILE_CARD, - CAPABILITY_DEPENDENCY[AgenticCapability.COMPILE_CARD] - ); - }, +}; + +/** Public helpers requiring no contract deployment context. */ +export const agenticUtils = { + actionId: internalAgenticUtils.actionId, + configId: internalAgenticUtils.configId, + decodeRules: internalAgenticUtils.decodeRules, }; diff --git a/packages/core/src/lib/index.ts b/packages/core/src/lib/index.ts index 2615d969..688b72f0 100644 --- a/packages/core/src/lib/index.ts +++ b/packages/core/src/lib/index.ts @@ -208,10 +208,8 @@ export type { ForeignChainNamespace, NativeRule, Rule, - RulesEncodeContext, RulesRecord, Selector, - Spent, UniversalRule, WalletInfo, WalletSummary, diff --git a/packages/core/src/lib/orchestrator/__tests__/push-chain-native-multicall.spec.ts b/packages/core/src/lib/orchestrator/__tests__/push-chain-native-multicall.spec.ts index 626912dc..c90d3082 100644 --- a/packages/core/src/lib/orchestrator/__tests__/push-chain-native-multicall.spec.ts +++ b/packages/core/src/lib/orchestrator/__tests__/push-chain-native-multicall.spec.ts @@ -1,5 +1,6 @@ import { CHAIN, PUSH_NETWORK } from '../../constants/enums'; import { construct, toUniversal } from '../../universal/signer/signer'; +import { AtomicBatchUnavailableError } from '../internals/errors'; import { EIP7702NotSupportedError } from '../../vm-client/evm-client'; import type { OrchestratorContext } from '../internals/context'; import { sendPushTx } from '../internals/push-chain-tx'; @@ -51,6 +52,7 @@ function makeContext(signer: OrchestratorContext['universalSigner']) { getTransactionCount: jest.fn().mockResolvedValue(41), waitForTransactionReceipt, call: jest.fn(), + getCode: jest.fn().mockResolvedValue('0x6000'), }, }; @@ -260,3 +262,45 @@ describe('sendPushTx native multicall routing', () => { expect(transformFn).not.toHaveBeenCalled(); }); }); + + +describe('atomic-only native batches (AGW sender-preserving arrays)', () => { + async function context(supportsAuthorization = true) { + const signer = await toUniversal(construct( + { chain: CHAIN.PUSH_TESTNET_DONUT, address: '0x3333333333333333333333333333333333333333' }, + { signMessage: async (data) => data, signAndSendTransaction: async (data) => data, + ...(supportsAuthorization ? { signAuthorization: jest.fn() } : {}) } + )); + return makeContext(signer); + } + + it('rejects missing signer capability without sending any sequential call', async () => { + const { ctx, pushClient } = await context(false); + await expect(sendPushTx(ctx, execute, [], transformFn, true)).rejects.toBeInstanceOf(AtomicBatchUnavailableError); + expect(pushClient.sendTransaction).not.toHaveBeenCalled(); + expect(pushClient.sendBatch7702).not.toHaveBeenCalled(); + }); + + it('refuses a missing executor before authorization or broadcast', async () => { + const { ctx, pushClient } = await context(); + pushClient.publicClient.getCode.mockResolvedValue('0x'); + await expect(sendPushTx(ctx, execute, [], transformFn, true)).rejects.toBeInstanceOf(AtomicBatchUnavailableError); + expect(pushClient.sendTransaction).not.toHaveBeenCalled(); + expect(pushClient.sendBatch7702).not.toHaveBeenCalled(); + }); + + it('does not fall back when authorization is exposed but unsupported at runtime', async () => { + const { ctx, pushClient } = await context(); + pushClient.sendBatch7702.mockRejectedValueOnce(new EIP7702NotSupportedError()); + await expect(sendPushTx(ctx, execute, [], transformFn, true)).rejects.toBeInstanceOf(AtomicBatchUnavailableError); + expect(pushClient.sendTransaction).not.toHaveBeenCalled(); + expect(pushClient.sendBatch7702).toHaveBeenCalledTimes(1); + }); + + it('uses the atomic transport when signer and executor are available', async () => { + const { ctx, pushClient } = await context(); + await sendPushTx(ctx, execute, [], transformFn, true); + expect(pushClient.sendBatch7702).toHaveBeenCalledTimes(1); + expect(pushClient.sendTransaction).not.toHaveBeenCalled(); + }); +}); diff --git a/packages/core/src/lib/orchestrator/internals/errors.ts b/packages/core/src/lib/orchestrator/internals/errors.ts index 362cd243..871ddda3 100644 --- a/packages/core/src/lib/orchestrator/internals/errors.ts +++ b/packages/core/src/lib/orchestrator/internals/errors.ts @@ -57,6 +57,14 @@ export class PushChainExecutionError extends Error { } } +/** @internal A caller required an atomic native batch; sequential fallback is forbidden. */ +export class AtomicBatchUnavailableError extends PushChainExecutionError { + constructor(message: string, cause?: unknown) { + super(message, { cause }); + this.name = 'AtomicBatchUnavailableError'; + } +} + /** Recovery metadata for a non-atomic Push batch. A pending hash is broadcast but unconfirmed. */ export class PushChainBatchExecutionError extends PushChainExecutionError { readonly transactionHashes: `0x${string}`[]; diff --git a/packages/core/src/lib/orchestrator/internals/execute-standard.ts b/packages/core/src/lib/orchestrator/internals/execute-standard.ts index 95c30b1f..9195afcf 100644 --- a/packages/core/src/lib/orchestrator/internals/execute-standard.ts +++ b/packages/core/src/lib/orchestrator/internals/execute-standard.ts @@ -136,7 +136,8 @@ export async function executeStandardPayload( ctx: OrchestratorContext, execute: ExecuteParams, eventBuffer: ProgressEvent[], - getResponseCallbacks: () => ResponseBuilderCallbacks + getResponseCallbacks: () => ResponseBuilderCallbacks, + policy?: { requireAtomicBatch: boolean } ): Promise { const transformFn = (tx: TxResponse, buf: ProgressEvent[] = []) => transformToUniversalTxResponse(ctx, tx, buf, getResponseCallbacks()); @@ -169,7 +170,7 @@ export async function executeStandardPayload( fireProgressHook(ctx, PROGRESS_HOOK.SEND_TX_107); let tx: UniversalTxResponse; try { - tx = await sendPushTx(ctx, execute, eventBuffer, transformFn); + tx = await sendPushTx(ctx, execute, eventBuffer, transformFn, policy?.requireAtomicBatch); } catch (err) { // Push Chain broadcast failed. Wallet rejection surfaces as 104-04; // everything else (RPC fail, on-chain revert) as 199-02. diff --git a/packages/core/src/lib/orchestrator/internals/push-chain-tx.ts b/packages/core/src/lib/orchestrator/internals/push-chain-tx.ts index 551ae237..14005428 100644 --- a/packages/core/src/lib/orchestrator/internals/push-chain-tx.ts +++ b/packages/core/src/lib/orchestrator/internals/push-chain-tx.ts @@ -30,7 +30,7 @@ import type { import type { OrchestratorContext } from './context'; import { fireProgressHook, printLog } from './context'; import { decodeRevert, formatDecodedRevertForUser } from './error-decoder'; -import { PushChainExecutionError, PushChainBatchExecutionError } from './errors'; +import { PushChainExecutionError, PushChainBatchExecutionError, AtomicBatchUnavailableError } from './errors'; import { normalizePublicErrorMessage } from '../../formatters'; // ============================================================================ @@ -115,7 +115,8 @@ export async function sendPushTx( ctx: OrchestratorContext, execute: ExecuteParams, eventBuffer: ProgressEvent[], - transformFn: TransformToResponseFn + transformFn: TransformToResponseFn, + requireAtomicBatch = false ): Promise { if (Array.isArray(execute.data)) { const calls = execute.data as MultiCall[]; @@ -138,6 +139,15 @@ export async function sendPushTx( const executor = getBatchExecutorAddress( ctx.universalSigner.account.chain ); + if (requireAtomicBatch) { + if (!executor || !ctx.universalSigner.signAuthorization) { + throw new AtomicBatchUnavailableError('This operation requires a sender-preserving atomic batch; the signer/network does not support EIP-7702.'); + } + const code = await ctx.pushClient.publicClient.getCode({ address: executor }); + if (!code || code === '0x') { + throw new AtomicBatchUnavailableError(`Atomic batch executor ${executor} is not deployed on the connected network.`); + } + } if (executor && ctx.universalSigner.signAuthorization) { try { printLog( @@ -161,6 +171,9 @@ export async function sendPushTx( // to sequential execution cannot double-execute. Any other error // (e.g. a real revert) must surface. if (!(err instanceof EIP7702NotSupportedError)) throw err; + if (requireAtomicBatch) { + throw new AtomicBatchUnavailableError('The signer could not authorize EIP-7702; no sequential transactions were sent.', err); + } printLog( ctx, `sendPushTx — wallet cannot sign EIP-7702 authorization; falling back to sequential execution` diff --git a/packages/core/src/lib/orchestrator/orchestrator.ts b/packages/core/src/lib/orchestrator/orchestrator.ts index 0943e429..f6084c31 100644 --- a/packages/core/src/lib/orchestrator/orchestrator.ts +++ b/packages/core/src/lib/orchestrator/orchestrator.ts @@ -247,6 +247,25 @@ export class Orchestrator { async execute( params: ExecuteParams | UniversalExecuteParams, options?: TransactionExecutionOptions + ): Promise { + return this.executeWithPolicy(params, options, false); + } + + /** @internal Sender-preserving batch. Never uses the native sequential fallback. */ + async executeAtomicBatch( + params: ExecuteParams, + options?: TransactionExecutionOptions + ): Promise { + if (typeof params.to !== 'string' || !Array.isArray(params.data) || params.data.length < 2 || params.funds) { + throw new Error('executeAtomicBatch requires multiple Push calls and no signer funds'); + } + return this.executeWithPolicy(params, options, true); + } + + private async executeWithPolicy( + params: ExecuteParams | UniversalExecuteParams, + options: TransactionExecutionOptions | undefined, + requireAtomicBatch: boolean ): Promise { const inlineProgressHook = params.progressHook; if (options || inlineProgressHook) { @@ -449,7 +468,9 @@ export class Orchestrator { ); } return attachPerCallHookForWait( - await _executeStandardPayload(this.ctx, execute, eventBuffer, rcb) + await (requireAtomicBatch + ? _executeStandardPayload(this.ctx, execute, eventBuffer, rcb, { requireAtomicBatch: true }) + : _executeStandardPayload(this.ctx, execute, eventBuffer, rcb)) ); } catch (err) { const errMessage = normalizePublicErrorMessage(err); diff --git a/plan/agw/.gitattributes b/plan/agw/.gitattributes index 3a1ab90f..1ec16539 100644 --- a/plan/agw/.gitattributes +++ b/plan/agw/.gitattributes @@ -2,3 +2,4 @@ notion/** -whitespace research/validation-e704d5b/*.log -whitespace implementation-review/**/*.log -whitespace +research/product-alignment-2026-10-04/*.log -whitespace diff --git a/plan/agw/README.md b/plan/agw/README.md index f3f0933b..3b30aeb8 100644 --- a/plan/agw/README.md +++ b/plan/agw/README.md @@ -1,9 +1,11 @@ # AGW SDK planning -This package contains the current SDK plan, source snapshots, open decisions and contract validation evidence. Implementation of the unblocked steps is on branch `feat/agw-sdk-impl`; see [implementation status](implementation-status.md) and the [review handoff](implementation-review-handoff.md). No live AGW transaction has been sent: no compatible deployment exists (A07). Question drafts are unsent. +This package contains the current SDK plan, source snapshots, open decisions and contract validation evidence. Implementation of the unblocked steps is on branch `feat/agw-sdk-impl`; see [implementation status](implementation-status.md) and the [review handoff](implementation-review-handoff.md). No live AGW transaction has been sent; no compatible deployment has been verified or registered. Harsh has replied; remaining follow-ups are in the updated question docs. The target API is [Notion page 5](notion/5-sdk-agw.md), exported October 3, 2026 at 13:23 IST. The tested contract baseline is pushAgenticWallet_v3@e704d5b: sender-authorized execution and checkpoints exist in source, while the new multi-asset format, grant reference, editable label and envelope version still require matching artifacts and deployment verification. +Latest direction: [Harsh product decisions, October 4](product-decisions-2026-10-04.md). Page 5 was downloaded again and its body is unchanged after link normalization. These newer product replies supersede the older provisional recommendations; the clear scope changes are now implemented. H3 defaults and raw-offset API clarification remain pending. + ## Start here | Document | Purpose | @@ -18,7 +20,7 @@ The target API is [Notion page 5](notion/5-sdk-agw.md), exported October 3, 2026 | [Implementation review handoff](implementation-review-handoff.md) | Revisions, changed modules, commands and counts, real-vs-mock evidence, review hotspots | | [Interactive tutorial](agw-tutorial.html) | Account, rule, funding and execution diagrams; open in a browser | | [Integrator obligations](contract-integrator-obligations.md) | Contract-delegated SDK/product requirements | -| [External blockers](external-blockers.md) | Seven remaining decision/dependency areas after local closure | +| [External blockers](external-blockers.md) | Remaining defaults/type clarification and contract/deployment dependencies | | [Questions for Harsh](questions-harsh.md) | Product decisions and recommendations | | [Questions for Zaryab](questions-zaryab.md) | Contract surface, funding and deployment questions | | [Review summary](review-summary.md) | Consequential independent-review corrections | diff --git a/plan/agw/SOURCES.md b/plan/agw/SOURCES.md index 112f9473..f061304a 100644 --- a/plan/agw/SOURCES.md +++ b/plan/agw/SOURCES.md @@ -2,6 +2,8 @@ Latest complete Notion export: October 3, 2026 at 13:23 IST. All 12 pages were imported; pages 1 and 5 changed. Page 5 defines the target public SDK API. Native exports omit comment threads. +Focused October 4 recheck: page 5 was downloaded again; its body matches the saved snapshot after normalizing links. [Comparison evidence](research/notion-check-2026-10-04/comparison.json). This was not a full refresh and does not replace the full-import manifest. Harsh’s newer replies are recorded separately in [product decisions](product-decisions-2026-10-04.md). + ## Notion inventory | Document | Source | Local snapshot | Authority | diff --git a/plan/agw/contract-integrator-obligations.md b/plan/agw/contract-integrator-obligations.md index 999124ea..fd9d659b 100644 --- a/plan/agw/contract-integrator-obligations.md +++ b/plan/agw/contract-integrator-obligations.md @@ -19,7 +19,7 @@ Source: [AGW design chapter 10 at 0f279ca](https://github.com/pushchain/push-age | 13 | Provide data for monitoring committed CEA versus current derivation; define the operational owner. | | 14 | Show derived destination accounts during creation. Derivation is deployment-specific. | | 15 | Show wallet PC funding and per-action ceiling; repeated zero-amount actions can spend the PC budget without consuming token spend. Any action-count estimate must state its assumptions. | -| 16 | Generate native argument pins and reject known approval functions with unpinned spenders. | +| 16 | Generate caller-requested native pins from ABI. Per Harsh H1 (October 4), approval screening and mandatory spender policy belong to UI/marketplace, not SDK rejection. | | 17 | Preserve exact asset-reported chain strings; use connected Push chain identity for native rules. | | 18 | Preview native actions, pins, value/amount/call limits; explain that any successful call consumes call count. | | 19 | Compile SVM rules from the program interface, preserve interface hash, pin all relevant accounts/data, and reject unrepresentable layouts; revalidate after upgrades. | diff --git a/plan/agw/current-baseline.md b/plan/agw/current-baseline.md index df619517..b8cb9c14 100644 --- a/plan/agw/current-baseline.md +++ b/plan/agw/current-baseline.md @@ -1,5 +1,7 @@ # Current validated AGW baseline +> October 4 update: [Harsh’s replies](product-decisions-2026-10-04.md) supersede earlier provisional approval/default/helper/history/compiler recommendations below. Use [remaining dependencies](external-blockers.md) for current blockers. The clear scope changes and sender-preserving native batching are now implemented; H3 defaults remain unchanged pending clarification. See [alignment evidence](research/product-alignment-2026-10-04/README.md). + Updated October 3, 2026 after reviewing checkpoint commit 6b7dbf4 and current head e704d5b. This page supersedes earlier recommendations; consequential corrections are retained in the [review summary](review-summary.md). The SDK Notion page remains the target API; conflicts below are recorded for resolution, not silently resolved in favor of code. ## Pinned sources diff --git a/plan/agw/external-blockers.md b/plan/agw/external-blockers.md index 91735a5c..b8cb2948 100644 --- a/plan/agw/external-blockers.md +++ b/plan/agw/external-blockers.md @@ -1,44 +1,32 @@ -# External decisions before AGW implementation and release +# Remaining external dependencies for AGW -October 3, 2026. The 24 gap-register entries cover implementation work, historical findings and downstream dependencies. For the standalone target SDK, this review isolates **seven decision/dependency areas**, presented as **four Harsh question groups and two active Zaryab requests**. A separate shared-compiler request, Harsh H5/Zaryab Z5, covers assumption A08. This is a release-planning count, not a count of confirmed contract defects. +Updated October 4, 2026 from [Harsh’s supplied replies](product-decisions-2026-10-04.md). The earlier count of seven standalone decision areas is historical. Several product decisions are now settled; implementing them is SDK work, not a reason to keep asking the same questions. -## What needs an external answer +## Still needs external information or delivery -| ID | Owner and draft | Required answer or artifact | What it blocks | -| --- | --- | --- | --- | -| E01 | Harsh H1 | Approval-safety policy and corrected universal example; owner-controlled approval can use the existing owner client | Public rule validation and safe examples | -| E02 | Harsh H2 | Reject native agent arrays in v1, or require a batching contract change | Full transaction-array promise; single native calls and supported EVM destination multicalls can proceed | -| E03 | Harsh H3 | Accept or change the explicit omission/default table | Final authorization defaults and encoder expectations | -| E04 | Harsh H4.1 | Approve generation/validator context in pure helper signatures | Public helper types; internal derivation can proceed with explicit context | -| E05 | Harsh H4.2 and Zaryab Z1 | Per-token Spent shape, matching multi-asset terms/read/assertion ABI and vectors | Final universal codec, metering reads and safe replacement integration | -| E06 | Harsh H4.3 and conditionally Zaryab Z1 | Define revoked-rule history; provide reliable metadata if promised | Complete rules.list/get behavior, not basic agent execution | -| E07 | Zaryab Z1/Z3 | Target ref/envelope/metadata surface and verified compatible deployment manifest | Required target features and live release acceptance; proposed setLabel is separately capability-gated pending scope | +| Area | Owner | Remaining dependency | +| --- | --- | --- | +| Exact defaults and revised fields | Harsh H3 | Final omission/explicit-zero table and the referenced maxValueTotal change; fresh page-5 body still matches the older snapshot | +| Native decoded-rule representation | Harsh H4.5 | Decide whether raw offsets are public read/write inputs or an internal/separate decoded representation | +| Universal accounting and encoding | Zaryab Z1 | Final multi-asset terms, internal per-token reads, expected-spend assertion ABI/vectors, empty-assets routing and envelope/CEA representation | +| Target generation and destination capabilities | Zaryab Z1/Z3 | Ref/label scope, SVM artifacts and a verified compatible deployment manifest for live acceptance | -Highest-impact integration dependencies are the approval policy, multi-asset accounting/encoding and compatible target generation. Defaults and native-array scope also need answers before their public behavior is finalized. SDK structure and independent work can proceed before all seven are closed. +Hiding public spend does not remove internal spend assertions. Deferring public history does not remove the need to distinguish enabled, expired and revoked permissions for execution. -## Shared compiler dependency +## Resolved scope and SDK alignment work -A08 is outside the seven standalone areas: Harsh H5 must establish the canonical card/userInput schema and supported binding scope; Zaryab Z5 must supply matching encoding/verification artifacts and shared vectors. This blocks compileCard completion, not the standalone foundation. Product answers settle design; missing artifacts and deployments remain delivery dependencies until verified. +- Approval selector policy belongs to UI/marketplace. Remove the SDK's blanket policy rejection; retain structural validation and contract checks. +- Generation machinery stays internal; adjust public helper exposure instead of requiring public factory/validator parameters. +- Public multi-asset spend is unnecessary; align read records while retaining internal accounting. +- Revoked-rule history is deferred from v1. +- compileCard is outside standalone AGW. Its shared marketplace schema is no longer an AGW release blocker. +- Native arrays are desired. Our earlier claim that the single-call AGW door requires a contract batching change was too broad. Sender-preserving UEA/7702 outer batches can contain multiple single agent-door calls. Implement and validate that path; never silently label sequential fallback atomic. +- Gateway allowance setup already uses separate owner transactions. Creation index binding, atomic updates and response replay have local implementation/review evidence. -## Removed from external blockers +The clear product decisions are now implemented: approval-policy rejection and obsolete public exports are removed, reads are active-only, and native arrays require atomic transport. H3 defaults were deliberately not changed. [Implementation status](implementation-status.md) distinguishes current code from the new direction. -- **Gateway allowance mechanism:** resolved locally. Owner execute can approve and remove a bounded allowance. Four new local tests pass. Production integration remains to be tested; no new AGW method is required. -- **How to approve on the destination:** use the existing owner agentic client and sendTransaction. Harsh decides the agent permission policy, not a new helper architecture. -- **Whether NativeRule needs multiple actions:** follow the existing one-action public type. Only the incompatible array promise needs a scope decision. -- **Creation batching and recovery:** SDK capability selection, partial hashes and retry handling. No required factory createWallet method. -- **Owner replacement batching:** established contract path. Only the new multi-asset expected-spend assertion remains external. -- **Duplicate candidate selection:** fail before signing with DUPLICATE_RULE and a hint; never pick arbitrarily. Document this use of the existing error code. -- **Gateway six-versus-eight-field history:** encode the known selected generation. Any future migration belongs in deployment compatibility, not a speculative blocker. -- **Version string alone:** the SDK can use an explicit factory/implementation registry and verified wiring; unchanged accountId does not force a contract redesign. -- **Read-only lifecycle, Web2 normalization, receipts, errors and progress:** SDK-owned decisions in [SDK review](sdk-owned-review.md). -- **D3, checkpoints, binder and creditRevert:** implemented source, dropped proposal or known platform dependency, as recorded in the gap register. +## Freshness and delivery gates -## Work we can do before answers arrive +SDK page 5 was downloaded October 4 and matches the saved body after link normalization; other registered pages were not refreshed. [Evidence](research/notion-check-2026-10-04/comparison.json). AGW remote head remains e704d5b. No compatible deployment was verified in this pass. -The design decisions, read reconstruction strategy, source mapping, test acceptance cases and creation/recovery strategy are recorded. Future implementation can start with namespace/context separation, read-only guards, Web2 compatibility, error exports and receipt/hook adapters. Keep final universal encoding, defaults and disputed public types behind the unresolved decisions. Production implementation has not begun in this planning package. - -## Evidence and freshness - -The 183 existing SDK unit tests passed, plus four new allowance experiments at pinned e704d5b. These support local mechanisms only; no live transaction was broadcast. [Review evidence](research/sdk-owned-review-2026-10-03/README.md) records commands, hashes, source pins and limits. - -Remote AGW/core/gateway branch refs were rechecked and are unchanged. Notion remains the October 3 13:23 IST export; edits after that time are unknown. Refresh the Notion bodies before sending the [Harsh](questions-harsh.md) and [Zaryab](questions-zaryab.md) drafts. +Continue SDK work against explicit adapters and assumptions. A compatible manifest, internal multi-asset artifacts and authorized live acceptance remain necessary before enabling the final release. The source snapshots remain unedited evidence; the product decision record captures the newer scope direction. diff --git a/plan/agw/gaps.md b/plan/agw/gaps.md index 8b224e42..423679cf 100644 --- a/plan/agw/gaps.md +++ b/plan/agw/gaps.md @@ -1,5 +1,7 @@ # AGW contract and SDK gap register +> October 4 update: [Harsh’s replies](product-decisions-2026-10-04.md) supersede earlier provisional approval/default/helper/history/compiler recommendations below. Use [remaining dependencies](external-blockers.md) for current blockers. The clear scope changes and sender-preserving native batching are now implemented; H3 defaults remain unchanged pending clarification. See [alignment evidence](research/product-alignment-2026-10-04/README.md). + Current source: pushAgenticWallet_v3@e704d5b; target API: October 3 Notion export. [Baseline](current-baseline.md), [review summary](review-summary.md) and [integrator obligations](contract-integrator-obligations.md) provide context. The IDs track remaining integration work, not 24 missing contract features. P0 blocks safe integration or agreed authorization/accounting semantics. P1 affects correctness, compatibility or downstream delivery. P2 covers optional capability or documentation. D3 and checkpoints are implemented in source; live generation verification is outstanding. diff --git a/plan/agw/implementation-plan.md b/plan/agw/implementation-plan.md index e29aee0a..19440484 100644 --- a/plan/agw/implementation-plan.md +++ b/plan/agw/implementation-plan.md @@ -1,6 +1,8 @@ # Complete AGW SDK implementation plan -This is the step-by-step plan for the complete AGW surface in Notion page 5 inside `@pushchain/core`. It covers management, rules, execution, responses, helpers, compatibility, documentation and release validation. Marketplace, job and evaluator clients are separate projects; their shared `compileCard` dependency is included here. No production implementation has started. +> October 4 update: [Harsh’s replies](product-decisions-2026-10-04.md) supersede earlier provisional approval/default/helper/history/compiler recommendations below. Use [remaining dependencies](external-blockers.md) for current blockers. The clear scope changes and sender-preserving native batching are now implemented; H3 defaults remain unchanged pending clarification. See [alignment evidence](research/product-alignment-2026-10-04/README.md). + +This is the step-by-step plan for the complete AGW surface in Notion page 5 inside `@pushchain/core`. It covers management, rules, execution, responses, helpers, compatibility, documentation and release validation. Marketplace, job and evaluator clients are separate projects; `compileCard` is deferred to their later delivery and is not exposed by standalone AGW. Settled implementation is recorded in [implementation status](implementation-status.md); remaining contract capabilities stay gated. Target: [SDK spec](notion/5-sdk-agw.md), exported October 3, 2026 at 13:23 IST. Tested contract source: AGW `e704d5b`. SDK production baseline: `167fdc6`. See [current baseline](current-baseline.md), [SDK design](sdk-design-review.md), [SDK-owned decisions](sdk-owned-review.md) and [external blockers](external-blockers.md). Remote refs were rechecked unchanged; subsequent Notion edits remain unverified. @@ -27,7 +29,7 @@ Implementation and verification are listed separately so development progress ca | 13 | Responses, tracking, progress and transaction-creating reads | Partial | 3, 9–12; final wire adapters | | 14 | Deployment onboarding and full acceptance | Waiting for matching deployment | 4–13; A07 | | 15 | Web2 compatibility | Start now; independent | Existing read-state modules | -| 16 | Card compiler and ecosystem boundary | Waiting for canonical card schema | 6; G09/G10 downstream decisions | +| 16 | Card compiler and ecosystem boundary | Outside standalone AGW v1 | Future marketplace track | | 17 | Documentation, examples and release | Draft now, finish after acceptance | 1–16 or explicit accepted feature scope | Do not interpret this table as an equal-effort percentage. Steps 6, 11–14 carry substantially more integration risk than namespace and export work. @@ -38,22 +40,22 @@ These are working assumptions for development, not accepted product changes. Rep | ID | Working assumption or placeholder | Confirmation | Replacement point | | --- | --- | --- | --- | -| A01 | Known approval-granting selectors are rejected in universal agent rules. Owners use existing owner-mode sendTransaction for bounded approvals. Filtering is not a complete target-safety boundary. | Harsh H1 / E01 | Rule validation and examples | -| A02 | NativeRule remains one action; native agent arrays fail before signing. Owner batches and bounded EVM destination multicalls remain supported. | Harsh H2 / E02 | Native dispatch validation | -| A03 | Omitted universal asset maxTotal maps to proposed zero-unlimited; native value caps and allowed-call maxValue default to zero; native amount.maxTotal defaults to uint256 maximum; maxCalls defaults to zero-unlimited. | Harsh H3 / E03 | One defaults module, never scattered fallbacks | -| A04 | Pure rulesId and deriveWallet helpers accept explicit validator/factory/implementation context. Signer-bound methods resolve it internally. | Harsh H4.1 / E04 | Public helper signatures; internal context already explicit | -| A05 | Universal Spent is per token. Replacement compares caller-supplied expected totals for all old-rule assets atomically. Multi-asset wire format, empty-assets routing and EVM expectedCEA width are unresolved. | Harsh H4.2, SVM scope clarification, and Zaryab Z1 / E05 | Multi-asset codec/read/assertion adapter | -| A06 | Active-rule reads can be implemented first internally. Public list/get historical scope stays provisional; do not silently return only active rules if full history is promised. | Harsh H4.3 / E06 | History adapter and RulesRecord completeness | +| A01 | Approval policy is UI/marketplace-owned; SDK retains structural validation without selector deny-lists or mandatory spender policy | Harsh H1 resolved October 4; implemented | Native/universal validation | +| A02 | Multiple native actions use a sender-preserving UEA/7702 outer batch of single agent-door calls; never sequential fallback | Harsh H2 direction; implemented and locally validated | Atomic transport and batch response adapters | +| A03 | Exact revised default table remains open; existing defaults are unchanged until H3 is clarified | Harsh H3 / E03 | One defaults module | +| A04 | Generation-dependent IDs, derivation and encoding context remain internal; client.agentic.derive remains public | Harsh H4.1 resolved; implemented | Public utility exports and internal codecs | +| A05 | Spend is internal, not a public result. Final per-token wire/read/assertion ABI, empty-assets routing and CEA width remain unresolved | Harsh H4.2 scope resolved; Zaryab Z1 delivery pending | Internal accounting and codec adapter | +| A06 | V1 lists enabled rules only; unknown/revoked get returns RULE_NOT_FOUND. No historical record reconstruction | Harsh H4.3 deferred; implemented | Public read model | | A07 | A verified new deployment supplies the matching grant ref/envelope/metadata ABI, addresses and start blocks. Historical Donut remains a distinct generation. | Zaryab Z1/Z3 / E07 | Deployment manifest and capability adapter | -| A08 | compileCard consumes a versioned canonical card shared with the marketplace hook. No canonical bytes are invented locally. | Harsh H5 and Zaryab Z5; downstream G09/G10 | Card compiler module | +| A08 | No compileCard in standalone AGW; canonical cards belong to later marketplace work | Harsh H5: outside AGW v1 | No public compiler stub/export | ### What closes each assumption -- A01–A04: explicit product decisions and agreed API/default wording from Harsh settle the design. SDK implementation and tests follow. +- A01/A02/A04: clear product scope is implemented. A03 defaults still need exact agreed wording. - A05: Harsh agrees the public representation; Zaryab supplies matching terms, read/assertion ABIs and vectors. Clarification alone does not supply missing contract code. -- A06: Harsh defines history scope. If full history is required, reliable metadata/artifacts must also be available before that implementation dependency closes. +- A06: revoked history is outside v1; active-only reads and explicit RULE_NOT_FOUND behavior are implemented. - A07: Zaryab identifies the selected feature scope and delivers the actual compatible deployment manifest/artifacts. A planned address or deployment date does not close it; we verify deployment and integration. -- A08: Harsh H5 and Zaryab Z5 align the shared card schema/encoding and vectors. This is a downstream compiler dependency, separate from the standalone execution foundation. +- A08: closed for standalone AGW by deferring compileCard to the marketplace track. Record design decisions and artifact/deployment readiness separately. All eight have an explicit question owner, but answers alone do not mean all eight are implemented or verified. @@ -100,8 +102,8 @@ Done when: implementation has a pinned target and unresolved features cannot be Implementation: -1. Add `client.agentic`, the management handle, `PushChain.utils.agentic` and AGENTIC constants through the existing exports. -2. Model create results, wallet summaries, checkpoint records, rules, spend, errors and progress. Separate internal wire terms from the public Rule input. +1. Add client.agentic, the management handle, AGENTIC constants and public actionId/configId/decodeRules utilities. Keep generation-dependent utilities internal; no AGW compileCard. +2. Model create results, wallet summaries, checkpoint records, public rules without spend, internal counters, errors and progress. Separate internal wire terms from the public Rule input. 3. Add `agenticWallet` to the shared initialize/reinitialize option path without changing ordinary-client defaults. 4. Add AgenticError and AgenticRevertError using core's structured failure model. Preserve cause/decoded error data and batch-recovery hashes; expose the base execution error if required for public instanceof checks. 5. Isolate A04/A05/A06 in small interfaces. A registered method with no implementation throws a clear unsupported-capability error; the final public error names are documented before release. @@ -150,7 +152,7 @@ Implementation: 3. Implement wallet(address), owner and info with snapshot-consistent reads. Reconstruct current deployment label from the event when required by the selected generation. 4. Implement checkpoints from bounded/paginated logs, ordered by block/transaction/log index. Preserve seq, kind, ref, blockNumber and txHash. Account for reorgs and sinceBlock inclusion. 5. Implement active rules.get/list internals using enabled IDs followed by agent/action/policy reads at one block. Distinguish unknown, revoked, expired and zero-valued configurations. -6. Add historical records only through the A06-approved mechanism. A failed metadata reconstruction is not an empty rule list. Do not claim info/rule lookup is one RPC request if it requires dependent reads. +6. V1 has no historical records: list returns enabled rules and get rejects unknown/revoked IDs. Do not claim info/rule lookup is one RPC request if it requires dependent reads. 7. Add setLabel only for a matching supported capability. Respect the chosen cosmetic/checkpoint semantics from the final contract. Verification: empty owner, next slot, index races, multiple wallets/generations, paginated logs, same-block changes, unknown IDs, revoked-history limits and RPC failures. @@ -166,7 +168,7 @@ Implementation: 3. Derive expectedCEA from AGW and destination deployment, not from the agent. Supply it to the encoder and preview data; document and detect derivation drift. Separate asynchronous registry/RPC resolution from pure encodeRules/decodeRules helpers: pure helpers receive pre-resolved token, ABI and deployment context and perform no hidden network calls. 4. Derive selectors, actionId/configId and rulesId against contract vectors. Wallet-scope record keys. Use explicit validator context internally; receipt-assigned IDs remain authoritative. 5. Generate native argument pins and beneficiary positions from ABI layout. Static tuples can occupy multiple words; dynamic arguments require layout-aware handling. Reject unsupported layouts or a bare selector with insufficient ABI context for required pins. -6. Implement native terms with explicit values first. Centralize provisional A03 omission defaults and A01 approval validation behind one policy boundary. +6. Implement native terms with explicit values first. Centralize provisional A03 defaults; approval policy is external to the SDK. 7. Add a versioned universal multi-asset codec only after A05 artifacts arrive. Keep encode/decode inverse behavior and validation for 0–8 assets, per-token limits and call lists. 8. Define empty-assets call routing, expectedCEA byte width, zero/unlimited semantics and envelope-version behavior from fixtures. Do not guess these to make a test pass. @@ -227,7 +229,7 @@ Implementation: 2. Zero candidates: NO_RULES_FOR_CHAIN before signing. Multiple candidates: DUPLICATE_RULE with a clear hint. Do not choose the first result. 3. Encode executeAsAgent with the selected ID and exact native single call. Leave expiry, allowance, amount and policy execution to contracts; do not build a second authorization engine in the SDK. 4. Reuse the signer transport so a foreign key calls from its own UEA. Reject any from route override before transport selection. -5. Apply A02 at the native-array boundary. Keep one-action public rules even if contract internals support more actions. +5. For native arrays, encode one single-call executeAsAgent per item and use only an atomic sender-preserving UEA/7702 transport. A missing/deferred 7702 authorization must never trigger sequential fallback. Keep the one-action public rule; each action remains subject to that rule. Verification: revoked/expired rules, ambiguous direct grants, changed grants after lookup, native value/data calls, foreign-key identity and policy revert decoding. A rule can change after lookup; the contract remains authoritative. @@ -305,18 +307,9 @@ Verification: both literal spellings, enum iteration, compile-time read/transact Done when: new public syntax works without breaking the existing read wire protocol. -## Step 16 Implement compileCard when its schema is settled - -Implementation: - -1. Obtain canonical card schema/version, signing/encoding rules and shared compiler vectors from marketplace/hook work. -2. Compile user input into public Rule[] through the same normalization and codec preparation as direct grants. -3. Preserve provider Push identity, exact marketplace expiry and supported chain/rule cardinality. Do not invent a multi-rule job binding over the current one-ID hook. -4. Keep market/job/evaluation namespaces outside this AGW implementation. Their independent delivery is not implied by exporting compileCard. - -Verification: shared SDK/hook vectors, mismatched provider/chain/expiry, card tampering, unsupported multi-chain binding and compatibility across schema versions. +## Step 16 Deferred marketplace integration -Done when: compileCard produces the same authorized terms the corresponding hook validates. Otherwise retain an explicit development placeholder and a release scope dependency. +Harsh H5 removes compileCard from standalone AGW. Do not expose a public stub or block AGW release on card schema decisions. Canonical schema/encoding and SDK/hook vectors remain future marketplace work, with a separate scope and acceptance plan. ## Step 17 Finish examples, obligations and release @@ -345,9 +338,9 @@ Done when: the package can be used from its published exports as documented, sup | initialize/reinitialize with agenticWallet | 3–4 | | owner/agent sendTransaction | 9–12 | | response.wait, trackTransaction, errors/hooks | 13 | -| utils.agentic rulesId/actionId/configId/deriveWallet | 4, 6; A04 | -| utils.agentic encodeRules/decodeRules | 6, 12 | -| utils.agentic.compileCard | 16 | +| Public utils.agentic actionId/configId/decodeRules; internal generation IDs/derivation/encoding | 4, 6 | +| Internal encoding and public native decoding | 6, 12 | +| compileCard | Outside standalone AGW; future marketplace | | AGENTIC constants and READ.CHAIN | 2, 4, 15 | | forbidden methods, gas behavior and transaction-creating reads | 3, 10–13 | diff --git a/plan/agw/implementation-review-handoff.md b/plan/agw/implementation-review-handoff.md index 12e0a2bc..cc90f8a5 100644 --- a/plan/agw/implementation-review-handoff.md +++ b/plan/agw/implementation-review-handoff.md @@ -189,3 +189,12 @@ F1 from the follow-up review is fixed. Live and replayed outbound response `to/d R6 now has regular tests through the real response-builder/wait closure with mocked RPC/polling, covering owner and agent doors, successful and reverted roots, and init/per-call terminal-hook counts. Live Cosmos/TSS/destination acceptance remains pending. Validation: 1,908 unit tests and 34 local-contract tests pass; library/spec typechecks and build pass. Lint retains seven errors in unchanged files. See [resolution and coverage](implementation-review/outbound-response-resolution.md). Product sign-off on raw-offset types and deployment gates are unchanged. + + +## Harsh scope alignment October 4 + +The clear product replies are now implemented. No SDK approval-selector or mandatory-spender policy remains; caller-requested pins are still encoded/validated. RulesRecord no longer exposes spent; update assertions still read internal counters. Active-only reads return RULE_NOT_FOUND for unknown/revoked IDs. Public generation-context helpers and compileCard are removed; the remaining public utils are actionId/configId/decodeRules, and client.agentic.derive remains available. + +Native agent arrays wrap each action in a single-call executeAsAgent and use an internal atomic-only orchestrator path. UEA uses existing multicall; Push EOA requires a deployed 7702 executor and usable authorization. Lack of capability or authorization never falls back to separate calls. Replay recognizes verified UEA/delegated-EOA batches and exposes the ordered actions in agentic.nativeCalls. A local real-type-4 test with actual AGW/engine/policy and a fixture ERC-7821 executor proves sender preservation, cumulative limits and full rollback. Live native batch scenarios are registered but not run. + +H3 defaults remain byte-for-byte unchanged. Raw-offset API approval and final multi-asset/SVM/deployment artifacts remain pending. [Evidence](research/product-alignment-2026-10-04/README.md). diff --git a/plan/agw/implementation-status.md b/plan/agw/implementation-status.md index b2ca5287..453e4489 100644 --- a/plan/agw/implementation-status.md +++ b/plan/agw/implementation-status.md @@ -1,5 +1,7 @@ # AGW SDK implementation status +> October 4 product update: [new decisions](product-decisions-2026-10-04.md) are applied to the clear scope items. Public spend/generation context/compiler exposure is removed, history is active-only, and native arrays use an atomic outer batch. H3 defaults remain unchanged; raw-offset types still need clarification. + October 3, 2026, updated after the implementation review (R1–R7 fixed; see the [handoff](implementation-review-handoff.md#review-response-2026-10-03)). Branch `feat/agw-sdk-impl` (base `feat/agw-sdk-planning@349635b`). This matrix records what the code does today against the [implementation plan](implementation-plan.md). "Implemented" excludes placeholders; a capability-gated method that throws `CAPABILITY_UNAVAILABLE` is listed as blocked, not implemented. Details, commands and review hotspots are in the [review handoff](implementation-review-handoff.md). ## Evidence levels @@ -15,37 +17,37 @@ October 3, 2026, updated after the implementation review (R1–R7 fixed; see the | Step | Deliverable | Status | Unit | Local | Live | Remaining dependency | | --- | --- | --- | --- | --- | --- | --- | | 1 | Source and capability contract | Implemented | ✓ | ✓ rebuilt ABIs identical to evidence | — | Refresh pins when answers land | -| 2 | Namespace, types, exports, errors | Implemented; A04–A06 types provisional | ✓ | ✓ | — | Final public error names, A04/A05/A06 shapes | +| 2 | Namespace, types, exports, errors | Implemented; remaining raw-offset/API metadata provisional | ✓ | ✓ | — | Raw-offset type decision; final contract metadata | | 3 | Signer/wallet context and lifecycle | Implemented | ✓ | ✓ owner, agent, stranger, read-only, reinitialize, guards | Blocked (A07) | UEA owner/agent paths only unit-tested (no UEA on anvil) | | 4 | Generation registry and adapter | Implemented for e704d5b; registry ships empty | ✓ | ✓ wiring verified | Blocked (A07) | Verified manifest; OwnerIntent signing not implemented (no transport needs it) | -| 5 | Wallet and checkpoint reads | Implemented: derive, list, info, owner, checkpoints, active rules | ✓ | ✓ | Blocked (A07) | Revoked history (A06), `setLabel` (A07) gated | -| 6 | Rule normalization and codecs | Native implemented and vector-verified; universal validated then gated | ✓ | ✓ contract vectors | — | A05 multi-asset wire/vectors; A01/A03 confirmation | +| 5 | Wallet and checkpoint reads | Implemented: derive, list, info, owner, checkpoints, active rules | ✓ | ✓ | Blocked (A07) | History deferred; setLabel (A07) gated | +| 6 | Rule normalization and codecs | Native implemented and vector-verified; universal validated then gated | ✓ | ✓ contract vectors | — | A05 multi-asset wire/vectors; H3 defaults | | 7 | Create, add, revoke | Implemented (native rules); index-bound deploy | ✓ | ✓ sequential create incl. partial recovery and the concurrent-creation race; atomic multi-rule add | Blocked (A07) | 7702/UEA create batch paths unit-only | | 8 | Atomic rules.update | Implemented for native rules | ✓ | ✓ five ticks, stale-spend rollback | Blocked (A07) | A05 per-token assertion for universal rules | | 9 | Owner execution and allowance setup | Implemented | ✓ | ✓ owner batches, approve/remove via owner door | Blocked (A07) | Production gateway pull/burn | -| 10 | Agent rule selection and native sends | Implemented | ✓ | ✓ maxCalls, pins, amount, expiry, A02 | Blocked (A07) | A02 confirmation | +| 10 | Agent rule selection and native sends | Implemented | ✓ | ✓ maxCalls, pins, amount, expiry, atomic 7702 batches | Blocked (A07) | Live UEA/7702 acceptance | | 11 | EVM universal sends and gas | Composer implemented for the e704d5b single-asset generation (Route-2-equivalent destination calls, no SDK allowance writes); signer gas guard implemented | ✓ | ✓ passes every URP gate with stub gateway; revoked-allowance race | Blocked (A07) | A05 token resolution for assets[]; node/TSS/destination acceptance | | 12 | SVM destination support | Not implemented; gated | ✓ gating | — | — | A05/A07, Harsh H4.4, obligations 19–23 | -| 13 | Responses, tracking, hooks, reads | Implemented | ✓ | ✓ live send/receipt identity | Blocked (A07) | Replay and outbound wait need a live run | +| 13 | Responses, tracking, hooks, reads | Implemented | ✓ | ✓ live send/receipt identity | Blocked (A07) | Native batch replay and outbound wait covered locally; live settlement pending | | 14 | Deployment onboarding and acceptance | E2E authored and gated; not run | — | — | Blocked (A07) | Verified manifest + authorized budget | | 15 | Web2 compatibility | Implemented | ✓ | — | Not rerun | Review of CHAIN.WEB2 value change | -| 16 | compileCard | Not implemented; gated | ✓ gating | — | — | A08 | +| 16 | compileCard | Outside standalone AGW; stub removed | ✓ absent public export | — | — | Future marketplace work | | 17 | Documentation, examples, release | Planning docs only | — | — | — | Accepted feature scope | ## Assumptions A01–A08 | ID | Design status | Artifact status | What the code does now | | --- | --- | --- | --- | -| A01 | Provisional (Harsh H1 unanswered) | n/a | `codec/policy.ts`: approval selectors refused in universal agent rules; native approvals need a pinned spender. One boundary module | -| A02 | Provisional (Harsh H2) | n/a | Native agent arrays refused before signing; owner batches allowed | +| A01 | Resolved by Harsh H1 | n/a | SDK approval rejection removed; structural validation retained | +| A02 | Product wants batching | Local type-4 proof, fixture executor | Sender-preserving atomic UEA/7702 path; native fallback prohibited | | A03 | Provisional (Harsh H3) | n/a | `codec/defaults.ts` is the only defaults table, tagged A03 | -| A04 | Provisional (Harsh H4.1) | n/a | `utils.agentic.rulesId/deriveWallet` take explicit validator / factory / implementation context | -| A05 | Open (Harsh H4.2, Zaryab Z1.1/Z1.2) | Missing | Target universal encode/decode and universal update throw `CAPABILITY_UNAVAILABLE`; `Spent` kept as specified and tagged provisional | -| A06 | Open (Harsh H4.3) | Missing | `rules.get` of a revoked rule throws `CAPABILITY_UNAVAILABLE` with `revoked: true`; list returns active rules only | +| A04 | Internal generation details | n/a | rulesId/deriveWallet/encodeRules and RulesEncodeContext are not public; client.agentic.derive remains | +| A05 | Public spend not required | Final multi-asset artifacts missing | Public spent removed; internal reads/assertions retained; final universal wire stays gated | +| A06 | History deferred from v1 | Not required for v1 | list is enabled-only; unknown/revoked get returns RULE_NOT_FOUND | | A07 | Open (Zaryab Z1/Z3) | **No verified deployment** | Registry and `CONSTANTS.AGENTIC` empty; every AGW call fails `GENERATION_UNSUPPORTED`; `ref` and `setLabel` gated | -| A08 | Open (Harsh H5, Zaryab Z5) | Missing | `utils.agentic.compileCard` throws `CAPABILITY_UNAVAILABLE` | +| A08 | Outside standalone AGW | Future marketplace dependency | Public compileCard stub and capability removed | -No product decision was assumed approved. No Notion refresh or answers were found in the workspace; remote AGW/core/gateway refs were rechecked unchanged (`e704d5b`, `cb69e0b`, `bcbf7df`). +Harsh replies and the focused October 4 page-5 recheck are recorded in product-decisions-2026-10-04.md. The clear decisions above are implemented; defaults are still pending. ## Gap register cross-reference @@ -55,3 +57,5 @@ Implementation evidence exists for G03 (explicit-context IDs, receipt IDs), G08 ## Outbound response follow-up F1 is resolved with a shared canonical first-call summary and complete `agentic.destinationCalls` metadata on send/replay. R6 wait-path regressions are now in the regular unit suite. Current validation: 1,908 unit tests, 34 local-contract tests, both typechecks and build pass. No live acceptance was performed. See [resolution](implementation-review/outbound-response-resolution.md). + +Current alignment verification is recorded in [product alignment evidence](research/product-alignment-2026-10-04/README.md). Existing older counts below/above describe their named revisions. diff --git a/plan/agw/product-decisions-2026-10-04.md b/plan/agw/product-decisions-2026-10-04.md new file mode 100644 index 00000000..7fe9bd25 --- /dev/null +++ b/plan/agw/product-decisions-2026-10-04.md @@ -0,0 +1,55 @@ +# Harsh product replies and SDK impact + +Recorded October 4, 2026 from the screenshot supplied by Shoaib. The message is attributed to Harsh Rajat and displays 1:35 AM; no Slack permalink or explicit message timezone was supplied. These replies supersede the earlier recommendations where clear. This file records decisions and interpretation; no SDK source changes were made in this pass. + +## Source check + +We downloaded [SDK page 5](https://app.notion.com/p/pushprotocol/5-SDK-AGW-3e9188aea7f481cf8e8de324956549b9) again on October 4. Its body is byte-identical to the saved snapshot after normalizing five known page-1 links. It still contains maxValueTotal, public pure helpers, Spent and compileCard. The visible menu says last edited October 2 at 8:39 PM. The message therefore carries newer scope direction than the page body currently exposes. [Export comparison and hash evidence](research/notion-check-2026-10-04/comparison.json). Comments are excluded from the native export; this is not a full twelve-page refresh. + +AGW remote pushAgenticWallet_v3 was rechecked and remains e704d5b. No new deployment was verified. + +## Decisions and interpretations + +| Item | Harsh's reply | Disposition and implementation impact | +| --- | --- | --- | +| H1 / A01 | Approval safety belongs to UI/marketplace; SDK should not decide it | Product policy resolved: remove the SDK's blanket approval-selector rejection. Keep structural/ABI/chain validation and actual contract enforcement. Audit the related native mandatory-spender-pin policy under the same boundary; do not confuse it with the ability to encode a caller-requested pin. The approval exposure still exists and belongs in UI/marketplace guidance. | +| H2 / A02 | Multicall or EIP-7702 should handle multiple transactions | Product wants batching. Our earlier blanket rejection was too broad: a sender-preserving outer batch can contain multiple single-call executeAsAgent operations. Source review supports that mechanism; SDK implementation/local validation is pending. See the dedicated analysis below. | +| H3 / A03 | Omitted maxTotal should use uint256 rather than zero; maxValuePerCall “same I guess”; maxValueTotal has changed in the spec | Partial. Interpret “uint256” as an intended uint256 maximum/unlimited default, not a literal type value, and confirm the exact table against the revised spec. The downloaded page body does not expose the referenced maxValueTotal revision. Other optional defaults and explicit-zero semantics were not fully answered. | +| H4.1 / A04 | Generation context for pure helpers does not need to be public | Keep generation/validator/factory machinery internal; stop asking for approval of public context parameters. Adjust generation-dependent helper exposure accordingly. This is not removal of client.agentic.derive or internal generation validation. Do not infer that every unrelated utility must disappear. | +| H4.2 / A05 | Multi-asset spend does not need to be public | Drop the request for a public per-token Spent shape. Internal per-token counters and expected-spend assertions are still required for rules.update. Align RulesRecord exposure with the narrowed public surface; do not remove on-chain/internal accounting. | +| H4.3 / A06 | Revoked history is not public in v1; reconsider later | Closed as deferred v1 scope. Active rule reads remain; no complete historical reconstruction or new grant metadata is required solely for this feature. Define revoked-ID lookup as an explicit unavailable/not-active result in the revised SDK behavior. | +| H4.4 | Zaryab is working on SVM destinations | Contract dependency remains. Obtain matching terms, payloads, capability/deployment and representable SDK input before enabling it. This is not proof that SVM support is delivered. | +| H5 / A08 | Marketplace nomenclature is not ready; compileCard should not come with AGW | Closed for standalone AGW scope: remove the public AGW compileCard stub/export and move card schema/compiler work to the later marketplace track. It is no longer a standalone AGW release blocker. | + +The later raw-offset NativeRule extension from review R5 was not included in these replies. Its public input/output contract still needs agreement if those records remain public. + +## H2 Correction to our batching analysis + +The wallet's agent door rejects ERC-7579 batch mode inside one executeAsAgent call. That does not prohibit an outer transaction from making several single-call entries: + +```text +Agent UEA multicall or delegated EIP-7702 account + → AGW.executeAsAgent(ruleId, single, call1) + → AGW.executeAsAgent(ruleId, single, call2) +``` + +Each call still arrives from the authorized agent account and gets its own policy checks. This is separate from factory deployment/grant batching. It cannot be replaced with an arbitrary helper contract, whose address would become msg.sender. + +Source evidence: [UEA_EVM multicall and failure propagation at cb69e0b](https://github.com/pushchain/push-chain-core-contracts/blob/cb69e0ba101bef1bb4440e54b2c45396be3e92ce/src/uea/UEA_EVM.sol#L155) calls each target from the UEA and reverts the containing transaction on failure. The SDK's PushBatchExecutor uses delegated EIP-7702/ERC-7821 execution. Native rule expressiveness is separate: a single-action NativeRule cannot authorize different target/selector pairs merely because the transport can batch them. + +SDK work: encode one agent-door call per item, preserve signer identity, test cumulative counters and all-or-nothing rollback, and adapt response/progress reconstruction for the outer batch. Current core can fall back from 7702 to sequential sends. Require an atomic-capable transport for atomic AGW arrays or explicitly settle sequential behavior; never silently claim atomicity. This is a technical implementation/verification task, not evidence that a new AGW batch entry point is required. + +## Implementation queue + +1. Align the public surface: internal generation details; no public universal Spent proposal, no revoked-history promise in v1, and no AGW compileCard. +2. Remove approval-policy rejection from the SDK while retaining encoding and contract validation. +3. Resolve H3's exact field/default table. Do not guess the referenced maxValueTotal change from the screenshot. +4. Implement and test sender-preserving native agent batching using the existing transport capabilities; keep unsupported transport cases explicit. +5. Retain Zaryab dependencies for final multi-asset wire/read/assertion ABI, ref/envelope/metadata scope, SVM artifacts and compatible deployment. +6. Obtain the separate raw-offset public-type decision before release. + +Existing implementation at a852777 still contains provisional approval/default rules, public generation-context helpers, Spent fields and the compileCard stub. These are now recorded alignment work, not claims that the new decisions have already been implemented. No production files, external pages or messages were changed. + +## Implementation follow-through + +The subsequent alignment implements the clear decisions: generation-dependent helpers and spend counters are internal, active-only v1 reads use RULE_NOT_FOUND for unknown/revoked IDs, compileCard is removed, approval policy is external, and native agent arrays use sender-preserving atomic UEA/7702 transport. H3 defaults and the raw-offset public-type question remain unchanged/pending. See [validation and limits](research/product-alignment-2026-10-04/README.md). The earlier a852777 statements above record the pre-alignment state. diff --git a/plan/agw/questions-harsh.md b/plan/agw/questions-harsh.md index 1ace6e11..460ce350 100644 --- a/plan/agw/questions-harsh.md +++ b/plan/agw/questions-harsh.md @@ -1,154 +1,43 @@ -# AGW SDK open product decisions for Harsh +# Remaining AGW product follow-ups for Harsh -We are preparing the AGW SDK implementation and need the decisions below to finalize its public behavior. Each item gives the issue, our recommendation and the answer needed. Please reply using the item IDs; approve the recommendation or provide the replacement behavior/schema. +Updated October 4, 2026 after your replies. Accepted decisions and implementation impact are recorded in [product decisions](product-decisions-2026-10-04.md); this document contains only remaining questions. -**Status:** open review draft. H1–H4 concern standalone AGW. H5 concerns `compileCard` and marketplace integration. Design approval settles the product choice; matching contract artifacts and deployment are separate dependencies. +| Item | Answer needed | +| --- | --- | +| [H3](#h3) | Exact revised limit fields, omission defaults and explicit-zero behavior | +| [H4.5](#h4-5) | Raw-offset representation introduced by the SDK review fix | -| Item | Decision needed | Affected SDK behavior | -| --- | --- | --- | -| [H1](#h1) | Agent approval policy | Which universal rules can be granted | -| [H2](#h2) | Native agent transaction arrays | Whether arrays are rejected or supported in v1 | -| [H3](#h3) | Defaults for omitted limits | Authority granted by optional fields | -| [H4](#h4) | Helper context, spend/history reads and SVM rule shape | Public signatures and returned records | -| [H5](#h5) | Canonical card schema and scope | `utils.agentic.compileCard` | +## Source check -## Source baseline - -- **Target:** [SDK spec snapshot](notion/5-sdk-agw.md), exported October 3, 2026 at 13:23 IST; [live Notion page](https://app.notion.com/p/pushprotocol/5-SDK-AGW-3e9188aea7f481cf8e8de324956549b9). -- **Contract proposal:** [saved change set](notion/1-agw-contract-changes.md), especially section 4c; [live Notion page](https://app.notion.com/p/pushprotocol/1-AGW-Contract-Changes-nomenclature-standard-change-set-3e9188aea7f4813aa31fc95ceb4e684d). -- **Reviewed source:** [AGW e704d5b](https://github.com/pushchain/push-agentic-wallets/blob/e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9/src/AGW.sol). Remote refs were rechecked October 3 and were unchanged. Notion has not been re-exported since the time above; later edits may answer these items. - - - -## H1 Agent permission to approve destination spending - -**Issue.** The SDK's creation example allows destination `approve(address,uint256)` without restricting the spender. An agent could approve an address it controls, allowing that address to withdraw existing CEA tokens outside the outbound token caps. The universal rule can pin a beneficiary to the CEA, but cannot pin an arbitrary approved spender. - -**Recommendation.** Reject known approval-granting selectors, including `approve` and `increaseAllowance`, in universal agent rules. Replace the example with bounded destination approval performed by the owner through the existing owner-mode `universal.sendTransaction`. Selector filtering is only one safeguard; it does not make arbitrary untrusted contracts safe. - -**Answer needed:** approve this policy, or specify the alternative permissions/safeguards intended for agent-created destination approvals. - -**Evidence:** [SDK creation example, section 1.b](notion/5-sdk-agw.md); [universal beneficiary/value checks](https://github.com/pushchain/push-agentic-wallets/blob/e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9/src/policies/UniversalRulesPolicy.sol#L1005). - - - -## H2 Native agent transaction arrays - -**Issue.** The SDK says transaction arrays work in agentic mode. The current agent door dispatches one Push-native call. An EVM destination multicall is different: it is carried inside one outbound gateway call. - -**Recommendation.** Keep the specified single-action `NativeRule`. Reject native **agent** arrays before signing in v1, without a sequential fallback. Continue supporting owner wallet batches and bounded EVM destination multicalls. - -**Answer needed:** approve that v1 scope, or confirm that native agent batching must be added to the contracts before this SDK capability ships. - -**Evidence:** [SDK agent behavior and NativeRule, sections 2.a and 3.b](notion/5-sdk-agw.md); [agent dispatch restriction](https://github.com/pushchain/push-agentic-wallets/blob/e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9/src/AGW.sol#L849). +We downloaded [page 5](https://app.notion.com/p/pushprotocol/5-SDK-AGW-3e9188aea7f481cf8e8de324956549b9) again on October 4. Its exported body still matches our October 3 snapshot after link normalization, including maxValueTotal and the old public helper/Spent/compileCard entries. [Comparison evidence](research/notion-check-2026-10-04/comparison.json). We will apply your newer scope directions rather than repeat those answered questions. -## H3 Defaults when a limit is omitted - -**Issue.** Optional fields need explicit defaults because omission changes the authority granted to an agent. - -**Recommendation:** - -| Omitted input | Proposed encoded value | Permission granted | -| --- | --- | --- | -| Universal `assets[].maxTotal` | `0` in the proposed multi-asset ABI | Unlimited total for that asset | -| Native `maxValuePerCall` | `0` | No native value transfer | -| Native `maxValueTotal` | `0` | No native value transfer | -| Native `amount.maxTotal`, when `amount` is present | `uint256` maximum | Unlimited metered total; required `maxPerCall` still applies | -| Native `maxCalls` | `0` | Unlimited calls until expiry | -| Universal `allowedCalls[].maxValue` | `0` | No native value attached to that destination call | - -Explicit zero remains zero. In the current native policy, zero value/amount caps prohibit positive value/amount; only `maxCalls` treats zero as unlimited. The proposed universal asset format adds its own zero-unlimited convention. - -**Answer needed:** approve the table or give the replacement default for each changed row. Unlimited permissions will be shown explicitly in documentation/previews. - -**Evidence:** [optional SDK fields, section 3.b](notion/5-sdk-agw.md); [proposed multi-asset sentinel, section 4c](notion/1-agw-contract-changes.md); [native terms and limit definitions](https://github.com/pushchain/push-agentic-wallets/blob/e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9/src/libraries/Types.sol#L300). - - - -## H4 Public helpers and rule reads - -Please answer each sub-item separately; they affect different public types. - - - -### H4.1 Generation context for pure helpers - -**Issue.** The specified helpers omit inputs needed to match contract results. Rule IDs depend on the validator address and grant nonce. Wallet prediction depends on the factory and wallet implementation generation. - -**Proposed signatures** — subject to approval: - -```ts -rulesId(agent, grantNonce, { validator }) -deriveWallet(owner, index, { factory, walletImplementation }) -``` - -Chain is not part of the delivered rule-ID hash. Client-bound methods resolve deployment context internally; pure helpers receive it explicitly. Rule records are indexed by wallet plus rule ID. - -**Answer needed:** approve these signatures or supply the preferred way to pass deployment context. - -**Evidence:** [current helper signatures, section 3.e](notion/5-sdk-agw.md); [grant nonce and ID assignment](https://github.com/pushchain/push-agentic-wallets/blob/e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9/src/AGW.sol#L626); [wallet prediction inputs](https://github.com/pushchain/push-agentic-wallets/blob/e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9/src/AGWFactory.sol#L232). - - - -### H4.2 Spend returned for a multi-asset rule - -**Issue.** Rules now contain `assets[]`, but the proposed `Spent` result still has one scalar `amountSpent`. Different token units cannot be added together. - -**Proposed universal result:** - -```ts -{ - kind: 'universal', - assets: [ - { token: destinationTokenAddress, amountSpent: 25000000n } - ] -} -``` - -`token` uses the same destination-chain identity/native-marker convention as the public rule. Native spend keeps its existing three counters. Contract-side PRC20 conversion stays inside the SDK. - -**Answer needed:** approve this result shape or provide an alternative. Coordinate the underlying read/assertion ABI with [Zaryab Z1.2](questions-zaryab.md#z1-2). - -**Evidence:** [Rule and Spent types, section 3.b](notion/5-sdk-agw.md); [per-token accounting proposal, section 4c](notion/1-agw-contract-changes.md). - - - -### H4.3 Revoked-rule history - -**Issue.** `rules.list()` promises “every rule,” while revocation clears agent configuration from the engine. Reliable historical records require additional event metadata or reconstruction of grant calls. - -**Answer needed:** does `rules.list()` include revoked rules? Also define `rules.get(revokedId)` behavior. If full history is required, we recommend metadata that can be reconstructed reliably for every supported grant path; [Zaryab Z1.3](questions-zaryab.md#z1-3) covers the contract dependency. - -**Evidence:** [SDK reads, sections 1.i–1.j](notion/5-sdk-agw.md); [removed configuration behavior](https://github.com/pushchain/push-agentic-wallets/blob/e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9/src/interfaces/ISmartSessionConfigReader.sol#L13). - - - -### H4.4 Public shape for SVM destinations +## H3 Revised limits and exact defaults -**Issue.** The public `AllowedCall` is EVM-shaped. SVM destination rules require program/discriminator and account/data constraints that should not be invented by the SDK implementation. +We understand the direction as omitted maxTotal and maxValuePerCall meaning unlimited, encoded as `type(uint256).max`, rather than zero. Your reply says maxValueTotal changed in the SDK document, but the current page body still contains the earlier NativeRule declaration. -**Answer needed:** confirm whether SVM destinations are in this release and, if so, provide or approve their public rule representation. Solana-origin signers using a UEA are a separate capability from executing on a Solana destination. Align this answer with [Zaryab's destination capability manifest](questions-zaryab.md#z3). +Please point us to the revised section or provide the final field/default table, specifically: -**Evidence:** [SDK universal rule types, section 3.b](notion/5-sdk-agw.md); [SVM integrator requirements 19–23](contract-integrator-obligations.md). +- Which maxTotal inputs should default to uint256 maximum: universal assets[].maxTotal, native amount.maxTotal, or both? +- What replaces or changes native maxValueTotal, and what is its omitted default? +- Should native maxCalls still default to 0 (unlimited), and allowedCalls[].maxValue to 0 (no attached destination value)? These rows were not settled in the reply. +- What should explicit zero mean on each field? In particular, the older multi-asset contract proposal made maxTotal=0 unlimited, while native value/amount zero forbids positive amounts. - +The SDK can normalize omitted values independently from the wire representation, but we need one exact agreed table to avoid changing authority accidentally. -## H5 Card schema for compileCard + -**Issue.** `utils.agentic.compileCard(card, userInput, ctx)` is part of the public target, but its canonical schema/version and binding scope need alignment with the marketplace/hook. The reviewed marketplace records one rules ID per job. +## H4.5 Decoded native rules and raw offsets -**Answer needed:** identify the shared-schema owner and provide or approve: +This was added during implementation review and was not part of the earlier question set. Stored native rules contain calldata byte offsets, but do not contain the ABI needed to recover argument indexes. Returning a guessed arg index was incorrect for arrays/tuples. -- The versioned `card` and `userInput` shapes, including required fields. -- Provider Push identity, expiry and `Rule[]` output semantics. -- Whether v1 supports one execution chain or requires multi-chain job binding. +The current fix returns pins as `{ offset, expected }` and amount limits with `{ offset, maxPerCall, maxTotal }`. It also accepts these raw forms when granting/updating so decoded rules can round-trip without loss. -Coordinate encoding and shared vectors with [Zaryab Z5](questions-zaryab.md#z5). This blocks `compileCard` completion, while standalone AGW foundation work can proceed. +Please confirm whether this raw form should be public and accepted for new authoring, or whether decoded wire records should be separate from the ABI-based `{ arg, ... }` input. Accepting arbitrary raw offsets is a different public validation boundary from generating them from ABI information. We will keep internal accounting/codec needs separate from the reduced public spend/helper surface. -**Evidence:** [SDK helpers, section 3.e](notion/5-sdk-agw.md); [marketplace SDK target](notion/6-sdk-universal-marketplace.md); [current job/rule binding](https://github.com/pushchain/push-chain-core-contracts/blob/cb69e0ba101bef1bb4440e54b2c45396be3e92ce/src/agentic-commerce-8183/UniversalMarketplace.sol#L301). +**References:** [follow-up review](implementation-review/followup-9e16b23/review.md), [current public types](../../packages/core/src/lib/agentic/agentic.types.ts), [integrator obligations](contract-integrator-obligations.md). -## Supporting documents +## Supporting context -[Implementation plan](implementation-plan.md) · [External dependencies](external-blockers.md) · [SDK design](sdk-design-review.md) · [Zaryab's open requests](questions-zaryab.md) +Native array implementation is now an SDK validation task: use sender-preserving outer UEA/7702 batching of single executeAsAgent calls, and handle unsupported atomic transports explicitly. SVM and the final universal ABI/deployment remain with [Zaryab](questions-zaryab.md). compileCard and revoked history are outside standalone AGW v1 scope per your reply. diff --git a/plan/agw/questions-zaryab.md b/plan/agw/questions-zaryab.md index cfb633fd..ed1a4166 100644 --- a/plan/agw/questions-zaryab.md +++ b/plan/agw/questions-zaryab.md @@ -2,13 +2,12 @@ We need the artifacts and compatibility details below to finish the AGW SDK against the intended contract generation. Please reply by item ID with the source/ABI/vector link when available, or the remaining work and expected delivery. Product choices that affect these requests are linked to Harsh's document. -**Status:** open review draft. Z1/Z3 concern standalone AGW. Z5 concerns the shared card compiler. IDs retain their earlier numbering for cross-references. +**Status:** updated October 4 after [Harsh’s replies](product-decisions-2026-10-04.md). Only Z1/Z3 remain for standalone AGW. Public multi-asset spend, revoked history and compileCard are no longer requested as standalone v1 features; internal accounting still matters. | Item | Requested deliverable | What it enables | | --- | --- | --- | | [Z1](#z1) | Matching terms, accounting/assertion ABI and metadata surface | Final rule encoding, reads and safe replacement | | [Z3](#z3) | Verified deployment and capability manifest | Generation onboarding and live acceptance | -| [Z5](#z5) | Canonical card encoding and shared vectors | SDK/hook-compatible `compileCard` | ## Source baseline @@ -54,7 +53,7 @@ If the code is still pending, please identify the agreed target definitions and - Token ordering/completeness rules for the expected snapshot. - A vector/test where intervening spend makes the entire replacement revert. -The SDK will implement the wrapper and atomic batch. Harsh's [H4.2](questions-harsh.md#h4-2) settles the public returned `Spent` shape. +The SDK will implement the wrapper and atomic batch. Harsh has said per-token spend need not be public, but the SDK still needs these internal reads and assertions for safe replacement. Please align omitted/explicit-zero wire semantics with the final H3 defaults. **Evidence:** [current expected-spend assertion](https://github.com/pushchain/push-agentic-wallets/blob/e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9/src/policies/UniversalRulesPolicy.sol#L1409); [proposed assertion change, section 4c](notion/1-agw-contract-changes.md). @@ -68,9 +67,8 @@ The SDK will implement the wrapper and atomic batch. Harsh's [H4.2](questions-ha | --- | --- | | Grant reference | `ref` parameter/event shape; include it in the owner signature digest when a signed grant is used | | Editable labels | Whether proposed `setLabel`/label storage ships with this generation, with its ABI/event behavior | -| Revoked-rule history | If Harsh requires it, provide reliable historical agent/action attribution for supported grant paths; a grant-event improvement is one possible solution | -Historical scope depends on [Harsh H4.3](questions-harsh.md#h4-3). Please distinguish committed features from proposals still awaiting agreement. +Harsh deferred revoked-rule history for v1; no additional historical metadata is requested solely for that feature. Please distinguish committed ref/label features from proposals. **Evidence:** [target SDK lifecycle](notion/5-sdk-agw.md); [pinned grant signatures](https://github.com/pushchain/push-agentic-wallets/blob/e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9/src/AGW.sol#L483); [pinned grant event emission](https://github.com/pushchain/push-agentic-wallets/blob/e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9/src/AGW.sol#L636). @@ -93,24 +91,7 @@ Existing wallet clones cannot acquire the target wallet ABI. We will use the man **If deployment is pending:** provide the intended feature scope and remaining delivery work. Clarification settles the plan; live acceptance remains pending until deployment exists. -SVM public-rule scope also needs [Harsh H4.4](questions-harsh.md#h4-4). [Historical Donut addresses](notion/agw-address-book-donut-2026-09-04.md) are retained as historical evidence, not assumed to support this target. - - - -## Z5 Card encoding and shared compiler vectors - -**Issue.** The SDK's `compileCard` must produce terms that the marketplace/hook validates using the same schema and rules. - -**Please provide or identify:** - -- Canonical versioned card encoding/hash and the contract revision that consumes it. -- Contract-side compilation/verification rules, including provider identity, chain, expiry and rule binding. -- Shared valid/invalid input vectors for the SDK and hook. -- Missing binding support, if product requires a broader scope than the current one-rule job binding. - -[Harsh H5](questions-harsh.md#h5) requests the public schema and single-chain/multi-chain scope. This dependency blocks `compileCard` completion, while basic AGW execution can proceed independently. - -**Evidence:** [SDK helper target](notion/5-sdk-agw.md); [current terms verifier](https://github.com/pushchain/push-chain-core-contracts/blob/cb69e0ba101bef1bb4440e54b2c45396be3e92ce/src/agentic-commerce-8183/UniversalMarketplaceTerms.sol#L32); [current job/rule binding](https://github.com/pushchain/push-chain-core-contracts/blob/cb69e0ba101bef1bb4440e54b2c45396be3e92ce/src/agentic-commerce-8183/UniversalMarketplace.sol#L301). +Harsh referred SVM work to you. Please include its supported input constraints and matching artifacts when ready. [Historical Donut addresses](notion/agw-address-book-donut-2026-09-04.md) are retained as historical evidence, not assumed to support this target. ## Supporting documents diff --git a/plan/agw/research/notion-check-2026-10-04/comparison.json b/plan/agw/research/notion-check-2026-10-04/comparison.json new file mode 100644 index 00000000..9392d977 --- /dev/null +++ b/plan/agw/research/notion-check-2026-10-04/comparison.json @@ -0,0 +1,18 @@ +{ + "checked_at": "2026-10-04T01:41:32.593330+00:00", + "page_id": "3e9188aea7f481cf8e8de324956549b9", + "url": "https://app.notion.com/p/pushprotocol/5-SDK-AGW-3e9188aea7f481cf8e8de324956549b9", + "scope": "Only SDK page 5; other 11 registered pages not refreshed", + "method": "Browser native Markdown/CSV export; compare after normalizing known page-1 links", + "observed_last_edited_label": "Last edited by Harsh Rajat Oct 2, 2026, 8:39 PM", + "archive": "sdk-page-export.zip", + "export_entry": "Private & Shared/5 SDK AGW 3e9188aea7f481cf8e8de324956549b9.md", + "archive_sha256": "05829135e9174668e11a00ca3ac8700ce958f154001103a8a2c9f3c1a1050034", + "raw_export_sha256": "3fe718ac5610ffd00e6b9e5a35e0e4b96c6e7fc6d52c901c040813b6cb82cb89", + "normalized_sha256": "e407ee77cdf874db7ef4697f84e9945ff3a12a2f2e07e8a7f90bd24e93ea32f1", + "saved_snapshot_sha256": "e407ee77cdf874db7ef4697f84e9945ff3a12a2f2e07e8a7f90bd24e93ea32f1", + "normalized_links": 5, + "body_changed": false, + "comments": "Native export omits comment threads; this does not certify unchanged comments.", + "agw_remote_head": "e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9" +} diff --git a/plan/agw/research/notion-check-2026-10-04/sdk-page-export.zip b/plan/agw/research/notion-check-2026-10-04/sdk-page-export.zip new file mode 100644 index 0000000000000000000000000000000000000000..0d7514980567d14faf7e0883f9510020146a69f8 GIT binary patch literal 14965 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 literal 0 HcmV?d00001 diff --git a/plan/agw/research/product-alignment-2026-10-04/README.md b/plan/agw/research/product-alignment-2026-10-04/README.md new file mode 100644 index 00000000..b86ef7a2 --- /dev/null +++ b/plan/agw/research/product-alignment-2026-10-04/README.md @@ -0,0 +1,39 @@ +# Product scope alignment validation October 4 + +Implements the clear [Harsh decisions](../../product-decisions-2026-10-04.md) on the worktree based at a852777. H3 defaults are byte-for-byte unchanged. No live-network transactions or deployments were performed. + +## Changes + +- Removed SDK approval-selector deny-lists and mandatory spender-pin policy. Explicit pins still use ABI/type validation. +- Kept generation-dependent rulesId/deriveWallet/encodeRules and RulesEncodeContext internal. Public utils contain actionId/configId/decodeRules; client.agentic.derive is unchanged. +- Removed public Spent/RulesRecord.spent. Internal readNativeSpend and expected-spend assertions remain. Tests query real policy counters directly for independent verification. +- Active-only rules.list/get; unknown/revoked IDs return RULE_NOT_FOUND. Historical log reconstruction and its capability are removed. +- Removed compileCard and its capability from AGW. +- Native agent arrays encode one executeAsAgent per action under the selected rule. UEA uses its existing multicall; native EOA uses an atomic-only 7702 path. Missing signer/executor or failed authorization cannot trigger sequential fallback. Ordinary core batching retains its previous fallback behavior. +- Native batch replay recognizes verified UEA or delegated-EOA wrappers, preserves signer origin, and reports the ordered actions in agentic.nativeCalls. An arbitrary forwarding contract is not recognized as a trusted batch sender. + +## Results + +| Check | Result | +| --- | --- | +| Full unit config | 1,917 passed; 12 skipped; 112 suites passed and 1 skipped | +| Local AGW config | 36 passed in 5 suites | +| Library, spec/E2E and local test typechecks | Passed | +| Core build | Passed | +| Core lint | Seven pre-existing errors in unchanged read-example/PC20 files; no new errors | +| AGW manifest | 23 scenarios / 8 files / 23 selected tests | +| Default all manifest | 76 scenarios / 40 files / 81 selected tests, unchanged | + +Logs are retained in this directory. [Evidence metadata](evidence.json) records commands and checksums. Lint's seven-error baseline is recorded as such, not reported as a clean run. + +## Real-contract batch test scope + +The new local suite uses actual e704d5b wallet/factory/engine/policy contracts and real Anvil type-4 transactions signed by public development keys. It verifies the outer sender is the agent account, two calls consume two call counts, and a mined later-call failure rolls back both target state and counters. + +The ERC-7821-shaped executor is a small test-only self-call/CALL dispatcher, not a bytecode verification of the deployed OpenZeppelin executor. Existing gateway/fee fixtures remain stubbed. There is no Cosmos, UEA relay, TSS or destination chain in this harness. UEA shaping/replay is unit-tested and reuses the existing transport; live UEA acceptance is still required. + +Two opt-in live cases were added for atomic native success and rollback. They use the existing verified deployment gate and have not been executed. SVM destinations, final multi-asset artifacts, deployment, H3 defaults and public raw-offset type approval remain outstanding. + +## Reproduction + +From the SDK root, run the core Jest config with --runInBand, both standard tsc --noEmit configs and tsconfig.agw-local.json, then core:build/core:lint through Nx. For local contracts, run scripts/agw-local/prepare.sh and set AGW_LOCAL_DIR to its output before running jest.agw-local.config.ts. From packages/core, use e2e:verify --group agw and --group all; these inspect scenario selection without broadcasting. diff --git a/plan/agw/research/product-alignment-2026-10-04/build.log b/plan/agw/research/product-alignment-2026-10-04/build.log new file mode 100644 index 00000000..b07bc2a3 --- /dev/null +++ b/plan/agw/research/product-alignment-2026-10-04/build.log @@ -0,0 +1,13 @@ + +> nx run core:build + +Compiling TypeScript files for project "core"... +Done compiling TypeScript files for project "core". +(node:40634) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. +(Use `node --trace-warnings ...` to show where the warning was created) + + + + NX Successfully ran target build for project core + + diff --git a/plan/agw/research/product-alignment-2026-10-04/e2e-agw.log b/plan/agw/research/product-alignment-2026-10-04/e2e-agw.log new file mode 100644 index 00000000..faefb9d3 --- /dev/null +++ b/plan/agw/research/product-alignment-2026-10-04/e2e-agw.log @@ -0,0 +1,26 @@ +✓ agw-create-bare 1 test +✓ agw-create-rules 1 test +✓ agw-funding-pc 1 test +✓ agw-funding-allowance 1 test +✓ agw-native-batch 1 test +✓ agw-native-batch-rollback 1 test +✓ agw-native-agent 1 test +✓ agw-native-owner 1 test +✓ agw-native-over-cap 1 test +✓ agw-native-stranger 1 test +✓ agw-native-revoked 1 test +✓ agw-native-expired 1 test +✓ agw-lifecycle-add 1 test +✓ agw-lifecycle-update 1 test +✓ agw-lifecycle-checkpoints 1 test +✓ agw-lifecycle-revoke-all 1 test +✓ agw-universal-outbound 1 test +✓ agw-universal-dest-revert 1 test +✓ agw-identity-evm 1 test +✓ agw-identity-first-use 1 test +✓ agw-identity-solana 1 test +✓ agw-responses-hooks 1 test +✓ agw-responses-replay 1 test + +23 scenarios, 8 spec files, 23 distinct tests. +Manifest is consistent with the specs. diff --git a/plan/agw/research/product-alignment-2026-10-04/e2e-all.log b/plan/agw/research/product-alignment-2026-10-04/e2e-all.log new file mode 100644 index 00000000..dfa5f250 --- /dev/null +++ b/plan/agw/research/product-alignment-2026-10-04/e2e-all.log @@ -0,0 +1,79 @@ +✓ smoke-uea-derive-evm 1 test +✓ smoke-read-track-lookup 1 test +✓ smoke-cea-derive-evm 1 test +✓ smoke-roundtrip-evm 1 test +✓ smoke-roundtrip-svm 1 test +✓ smoke-cea-pda-svm 1 test +✓ smoke-gasfee-reads 2 tests +✓ smoke-gas-sizer 2 tests +✓ smoke-pc20-registry 2 tests +✓ smoke-pc20-resolve 1 test +✓ evm-r1-transfer 1 test +✓ evm-r1-funds-usdt 1 test +✓ evm-r1-funds-native 1 test +✓ evm-r1-value-funds-data 1 test +✓ evm-r1-bridge-multicall 1 test +✓ evm-r1-fresh-value-native 1 test +✓ evm-r2-funds-erc20 1 test +✓ evm-r2-payload 1 test +✓ evm-r2-multicall 1 test +✓ evm-r2-funds-payload 1 test +✓ evm-r2-native-funds 1 test +✓ evm-r2-native-funds-payload 1 test +✓ evm-r3-funds-erc20 1 test +✓ evm-r3-payload 1 test +✓ evm-r3-multicall 1 test +✓ evm-r3-funds-payload 1 test +✓ evm-r3-native-funds 1 test +✓ evm-r3-eoa-native-funds 1 test +✓ svm-r1-transfer 1 test +✓ svm-r1-funds-sol-self 1 test +✓ svm-r1-value-self 1 test +✓ svm-r1-data-contract 1 test +✓ svm-r1-fresh-key-repro 1 test +✓ svm-r2-funds-sol 1 test +✓ svm-r2-funds-spl 1 test +✓ svm-r2-payload-cpi 1 test +✓ svm-r2-sol-cpi 1 test +✓ svm-r3-drain-sol 1 test +✓ svm-r3-drain-spl 1 test +✓ pc20-export-deployed-wrapper 1 test +✓ pc20-export-predicts-wrapper 1 test +✓ pc20-inbound-burn-unlock 1 test +✓ pc20-r3-cea-burn 1 test +✓ pc20-svm-r1-direct-burn 1 test +✓ pc20-svm-r3-cea-ata-burn 1 test +✓ push-send-transaction 1 test +✓ push-value-own-uea 1 test +✓ push-multicall-no-funds 1 test +✓ push-track-r1-sepolia-parity 1 test +✓ push-track-r3-funds-roundtrip 1 test +✓ push-track-source-leg-hashes 2 tests +✓ xc-multi-child-r3 1 test +✓ xc-fresh-wallet-r3 1 test +✓ xc-peth-bridge-back 1 test +✓ xc-cascade-6hop 1 test +✓ read-evm-balance-eoa 1 test +✓ read-canonical-registry 1 test +✓ read-evm-balance-uea 1 test +✓ read-evm-contract-call 1 test +✓ read-evm-callback-reverts 1 test +✓ read-expiry 1 test +✓ read-svm-lamports 1 test +✓ read-web2-json 1 test +✓ read-docs-example 1 test +✓ read-docs-evm-balance 1 test +✓ read-docs-batch 1 test +✓ read-docs-resume 2 tests +✓ read-app-batch-eoa 1 test +✓ read-app-batch-uea 1 test +✓ read-app-batch-recovery 1 test +✓ read-api-token 1 test +✓ read-api-mixed-outcomes 1 test +✓ read-svm-token-auto 1 test +✓ read-svm-idl 1 test +✓ read-evm-any-mutability 1 test +✓ read-svm-raw 1 test + +76 scenarios, 40 spec files, 81 distinct tests. +Manifest is consistent with the specs. diff --git a/plan/agw/research/product-alignment-2026-10-04/evidence.json b/plan/agw/research/product-alignment-2026-10-04/evidence.json new file mode 100644 index 00000000..0be90d2c --- /dev/null +++ b/plan/agw/research/product-alignment-2026-10-04/evidence.json @@ -0,0 +1,43 @@ +{ + "base_commit": "a8527778d1f50728fffc0f096b583da5b8c068dc", + "date": "2026-10-04", + "defaults_unchanged": true, + "live_broadcasts": false, + "commands": [ + { + "command": "node node_modules/jest/bin/jest.js --config packages/core/jest.config.ts --runInBand", + "result": "1917 passed, 12 skipped" + }, + { + "command": "AGW_LOCAL_DIR= node node_modules/jest/bin/jest.js --config packages/core/jest.agw-local.config.ts --runInBand --forceExit", + "result": "36 passed; local only" + }, + { + "command": "node node_modules/typescript/bin/tsc -p packages/core/tsconfig.spec.json --noEmit (also lib and agw-local configs)", + "result": "passed" + }, + { + "command": "yarn nx run core:build --skip-nx-cache", + "result": "passed" + }, + { + "command": "yarn nx run core:lint --skip-nx-cache", + "result": "7 errors in unchanged files" + }, + { + "command": "cd packages/core; yarn e2e:verify --group agw; yarn e2e:verify --group all", + "result": "23 / 76 scenarios consistent" + } + ], + "sha256": { + "README.md": "8652e06f9a5dd2c2586ea5f7488adc020b82f5acb12f5a5448a1fdf028ece0a6", + "build.log": "93e5781b460036e4a44f98f9e48a141e8c196336ab6ddf563e49a2c09bc9c2cb", + "e2e-agw.log": "55cd2e786526bfeb13acc79e8b94c6fa6baa9b3b52bde105f8034c6638c6c77c", + "e2e-all.log": "3d1649d660267693725f167772c8cfc6b0c51a385e1043d203efe1459798f6ff", + "local.log": "1a68e623f593dccfea0dc7b48a3f4311f77a7fb0d5d18b15c2faee9e1df2baf0", + "types-lib.log": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "types-local.log": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "types-spec.log": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "unit.log": "42d2d759193a3b9f68e69e6b1ef0b1684be8045823832e2809866af01fcc0691" + } +} diff --git a/plan/agw/research/product-alignment-2026-10-04/local.log b/plan/agw/research/product-alignment-2026-10-04/local.log new file mode 100644 index 00000000..43bfa197 --- /dev/null +++ b/plan/agw/research/product-alignment-2026-10-04/local.log @@ -0,0 +1,12 @@ +PASS core-agw-local packages/core/__agw-local__/agw-local-batch.spec.ts +PASS core-agw-local packages/core/__agw-local__/agw-local-advanced.spec.ts +PASS core-agw-local packages/core/__agw-local__/agw-local.spec.ts +PASS core-agw-local packages/core/__agw-local__/agw-local-races.spec.ts +PASS core-agw-local packages/core/__agw-local__/vectors.spec.ts + +Test Suites: 5 passed, 5 total +Tests: 36 passed, 36 total +Snapshots: 0 total +Time: 11.364 s, estimated 12 s +Ran all test suites. +Force exiting Jest: Have you considered using `--detectOpenHandles` to detect async operations that kept running after all tests finished? diff --git a/plan/agw/research/product-alignment-2026-10-04/types-lib.log b/plan/agw/research/product-alignment-2026-10-04/types-lib.log new file mode 100644 index 00000000..e69de29b diff --git a/plan/agw/research/product-alignment-2026-10-04/types-local.log b/plan/agw/research/product-alignment-2026-10-04/types-local.log new file mode 100644 index 00000000..e69de29b diff --git a/plan/agw/research/product-alignment-2026-10-04/types-spec.log b/plan/agw/research/product-alignment-2026-10-04/types-spec.log new file mode 100644 index 00000000..e69de29b diff --git a/plan/agw/research/product-alignment-2026-10-04/unit.log b/plan/agw/research/product-alignment-2026-10-04/unit.log new file mode 100644 index 00000000..d11b37f2 --- /dev/null +++ b/plan/agw/research/product-alignment-2026-10-04/unit.log @@ -0,0 +1,165 @@ +PASS core packages/core/src/lib/universal/account/account.spec.ts + ● Console + + console.warn + [PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead. + + 207 | ): Promise { + 208 | if (!_convertOriginToExecutorWarned) { + > 209 | console.warn( + | ^ + 210 | '[PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead.' + 211 | ); + 212 | _convertOriginToExecutorWarned = true; + + at Object.convertOriginToExecutor (src/lib/universal/account/account.ts:209:13) + at Object. (src/lib/universal/account/account.spec.ts:80:52) + + console.warn + [PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead. + + 425 | ): Promise { + 426 | if (!options?._internal && !_convertExecutorToOriginWarned) { + > 427 | console.warn( + | ^ + 428 | '[PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead.' + 429 | ); + 430 | _convertExecutorToOriginWarned = true; + + at convertExecutorToOrigin (src/lib/universal/account/account.ts:427:13) + at Object. (src/lib/universal/account/account.spec.ts:106:38) + +PASS core packages/core/src/lib/read-state/__tests__/block-results-client.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-tx-retry.spec.ts +PASS core packages/core/src/lib/push-client/push-client.archive-fallback.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-confirmation-gate.spec.ts +PASS core packages/core/src/lib/utils.spec.ts + ● Console + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:973:17) + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:977:17) + + console.log + 1.23 + + at Object. (src/lib/utils.spec.ts:982:17) + +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-timeout-clamp.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/rescue-svm-confirmation.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-svm-r3.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/registry.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/payload-builders.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-executor.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/signing-payload.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/public-surface.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r2-outbound-revert-flow.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/context-helpers-tracker.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-multichain.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/send-transaction-progress-hook.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-composition.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-event-hook-bridge.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gateway-uea-account.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/account-status.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/inbound-tracker-derivation.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-evm-r3-native-eoa.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-types.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-detector.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/web2-compat.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-svm-rent.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-builder-progress-hook.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/inbound-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/gate.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-emission.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-usd-sizer.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-request-recipient.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/funds-only-burn-guard.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/execute-standard-required-funds.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/svm-rent.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/source-hash-resolution.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/management.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-native-multicall.spec.ts +PASS core packages/core/src/lib/universal/signer/signer.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r1-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/track-transaction-guard.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/cascade.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-tracker.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/send.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/response-invariant.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/scenarios.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/response-surface.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/errors.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/read-tx-spec-strings.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/resolver.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/export.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/resolve.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm-rent-pc20.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/chain-namespace.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/build-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/response-builder-push-revert.spec.ts +PASS core packages/core/src/lib/push-client/push-client.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r3-spec-strings.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/multichain-hooks.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/terminal-suppression.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-calculator.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r2-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/address-codec.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm-log-index.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/svm-account.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/result-decoder.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/spec-builder.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-params.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/revalidate-read.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-evm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-svm.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts +PASS core packages/core/src/lib/constants/__tests__/token-constants.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/auto-detect.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/__tests__/signing.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/normalize.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/abi-selectors.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/child-inbounds.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/codec.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/ucallback-codec.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.chain-symbol.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/reads-context.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg-svm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/validate.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-events.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-web2.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.dynamic-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/registry.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/ix-encoder.spec.ts +PASS core packages/core/src/lib/constants/__tests__/svm-gateway-idl.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-execute-order.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/error-decoder.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/normalize-address.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/tracking.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/classify.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/max-pc-for-gas.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/budget.spec.ts +PASS core packages/core/src/lib/formatters.spec.ts + +Test Suites: 1 skipped, 112 passed, 112 of 113 total +Tests: 12 skipped, 1917 passed, 1929 total +Snapshots: 0 total +Time: 23.357 s, estimated 27 s +Ran all test suites. diff --git a/plan/agw/sdk-design-review.md b/plan/agw/sdk-design-review.md index 2a5ca699..9c4efb46 100644 --- a/plan/agw/sdk-design-review.md +++ b/plan/agw/sdk-design-review.md @@ -1,5 +1,7 @@ # AGW SDK design review +> October 4 update: [Harsh’s replies](product-decisions-2026-10-04.md) supersede earlier provisional approval/default/helper/history/compiler recommendations below. Use [remaining dependencies](external-blockers.md) for current blockers. The clear scope changes and sender-preserving native batching are now implemented; H3 defaults remain unchanged pending clarification. See [alignment evidence](research/product-alignment-2026-10-04/README.md). + The proposed design adds AGW management and execution to `@pushchain/core` through the API in [page 5](notion/5-sdk-agw.md). It keeps the existing signer and transaction machinery, while introducing a separate wallet execution context. The public API is the agreed target; this review proposes internal boundaries and identifies the evidence needed to implement them correctly. Review status: proposed architecture, pending [gap resolutions](gaps.md) and matching multi-asset artifacts/deployment. This document does not claim that the new contract methods are deployed. From 8439918d285cf893d7b5e10cf082a1a42ca27a8a Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Sun, 4 Oct 2026 08:08:16 +0530 Subject: [PATCH 15/68] docs(agw): reconcile gap statuses with product decisions --- plan/agw/gaps.md | 109 +++++++++++++++++++++++++---------------------- 1 file changed, 59 insertions(+), 50 deletions(-) diff --git a/plan/agw/gaps.md b/plan/agw/gaps.md index 423679cf..be118940 100644 --- a/plan/agw/gaps.md +++ b/plan/agw/gaps.md @@ -1,57 +1,66 @@ # AGW contract and SDK gap register -> October 4 update: [Harsh’s replies](product-decisions-2026-10-04.md) supersede earlier provisional approval/default/helper/history/compiler recommendations below. Use [remaining dependencies](external-blockers.md) for current blockers. The clear scope changes and sender-preserving native batching are now implemented; H3 defaults remain unchanged pending clarification. See [alignment evidence](research/product-alignment-2026-10-04/README.md). +Updated October 4, 2026 after [Harsh’s replies](product-decisions-2026-10-04.md) and implementation commit `cae7206`. This register distinguishes unresolved dependencies, implemented SDK work, deferred scope and historical corrections. G01–G25 are tracking IDs, not a count of open defects. -Current source: pushAgenticWallet_v3@e704d5b; target API: October 3 Notion export. [Baseline](current-baseline.md), [review summary](review-summary.md) and [integrator obligations](contract-integrator-obligations.md) provide context. The IDs track remaining integration work, not 24 missing contract features. +Evidence: [current baseline](current-baseline.md), [implementation status](implementation-status.md), [product alignment validation](research/product-alignment-2026-10-04/README.md). The SDK implementation passes 1,917 unit tests and 36 local-contract tests. Local tests do not establish live deployment or settlement support. -P0 blocks safe integration or agreed authorization/accounting semantics. P1 affects correctness, compatibility or downstream delivery. P2 covers optional capability or documentation. D3 and checkpoints are implemented in source; live generation verification is outstanding. +Source baseline: AGW `pushAgenticWallet_v3@e704d5b`, core marketplace `cb69e0b`, gateway `bcbf7df`. Page 5 was downloaded again October 4 and its body matches the October 3 snapshot after link normalization. Harsh’s newer scope replies supersede conflicting recommendations in that snapshot. No compatible release deployment has been verified or registered. -## Current findings +## Remaining standalone external dependencies -| ID | Priority | Kind | Finding | Closure criterion | +| Dependency | Owner | Related IDs | +| --- | --- | --- | +| Exact limit/default table and the referenced maxValueTotal change | [Harsh H3](questions-harsh.md#h3) | G19 | +| Public raw-offset read/write representation | [Harsh H4.5](questions-harsh.md#h4-5) | G25 | +| Final multi-asset encoding, internal per-token reads and expected-spend assertions | [Zaryab Z1](questions-zaryab.md#z1) | G23, G24 | +| Target ref/label/envelope scope, SVM artifacts and compatible deployment | [Zaryab Z1/Z3](questions-zaryab.md#z3) | G01, G02, G08, G22 | + +Approval screening, public generation context, public spend shape, revoked-history reconstruction and compileCard are no longer unresolved standalone product questions. Native agent batching is implemented through a sender-preserving outer transport; it does not require a new batch-mode AGW agent entry point. + +## Current disposition + +P0 blocks agreed authorization/accounting or safe final integration. P1 affects correctness, compatibility or delivery. P2 covers optional scope or documentation. “Implemented locally” means source and local evidence exist; live acceptance is tracked separately. + +| ID | Priority | Status | Current finding or resolution | Remaining action | | --- | --- | --- | --- | --- | -| G01 | P1 deployment dependency | Source/build evidence available | Current advertised branch is pushAgenticWallet_v3@e704d5b. Build, revised source pin, 563/0/6 suite and 7/0 review tests are reproduced. D3 and checkpoints exist in source. | Obtain and verify the selected generation deployment; keep remaining spec/ABI differences explicit. | -| G02 | P0 deployment dependency | Implemented in source | D3 landed in `0f279ca`: executeAsAgent, agentOf and sender adapter are present; engine unchanged. Prior engine-extension recommendation withdrawn. | Verify compatible deployment and retain sender-binding/alternate-path regression coverage. | -| G03 | P1 | Spec/code mismatch | Head ID formula is validator + abi.encode(agent) + grantNonce salt; chain-free and wallet-scoped. SDK helper/constants omit validator context. | Agree helper/context wording; use event-returned IDs and wallet-scoped indexing. | -| G04 | P1 | Deployment/version alignment | Six-field main is older; eight fields are in current gateway branch and observed Donut dispatcher. Planned future removal is unconfirmed. | Confirm release intent and pin a matching gateway/policy deployment, without assuming an eight-to-six upgrade. | -| G05 | P1 | Downstream spec/code mismatch | Notion says <= in one page and >= in another; core cb69e0b marketplace verifySession requires exact equality. | Use equality for this marketplace compile path and align downstream specs; do not impose it on standalone rules universally. | -| G06 | P2 stale downstream documentation | Binder dropped | Live page 1 on October 3 says dropped for v1; supplied Zaryab message says it was never implemented. The pasted binder proposal is historical/conflicting. | Remove old binder-dependent hook requirement; no binder implementation unless newly approved. | -| G07 | P1 documented platform dependency | Push-core executor work | creditRevert accounting exists but the core executor does not call it on outbound failure, per current contract docs. | Track platform delivery and document current spend behavior; do not reopen it as an unknown Zaryab design question. | -| G08 | P1 SDK reads/remaining metadata | Checkpoints implemented in source | e704d5b has stored count, last-block view and Checkpointed events. Label mutation/storage and grant job ref remain absent; revoked agent history is cleared. | Build count/event reads, define revoked-history scope, add agreed metadata fields and verify deployment. | -| G09 | P1 | Shared schema gap | Page 2's card carries `executionKey.scheme/key`; page 6 and page 5 use a Push `agent` address. Card canonical encoding, signing and compilation remain open. | Publish a single versioned card schema and deterministic compilation vectors shared by SDK and hook. Use the intended Push identity consistently. | -| G10 | P1 downstream scope mismatch | Core marketplace has one binding | cb69e0b marketplace handles one EVM execution chain and one rulesId; page 6 describes multi-chain cards. | Align downstream supported cardinality; do not invent multi-rule job binding in standalone AGW. | -| G11 | P1 | WIP dependency | Page 7 requires client-chosen payment tokens. Actual `8183-v1` has one token per deployment; page 3's open wording still suggests PUSD by default. | Implement the selected K-12 design or a documented deployment mapping. Align job ABI, funding, fee accounting and SDK `TOKEN_MISMATCH` checks. | -| G12 | P1 downstream delivery | Partial hook plus marketplace guards | cb69e0b marketplace performs provider/chain/expiry/terms checks at startJob; RulesBindingHook retains membership/live-rule/one-live-job checks at fund. Evaluator baseline/submit integration remains outstanding. | Map each check to actual start/fund/submit path and test bypasses, plain jobs and evaluator readiness. | -| G13 | P1 | Confirmed stale statement | Page 5 says core rejects Push-native multicalls. Current `sendPushTx` supports EIP-7702 and a sequential fallback; all six existing tests pass. | Align creation behavior with actual signer capability and report atomicity, committed hashes and partial failure correctly. Correct the stale documentation statement when requested. | -| G14 | P1 | SDK integration | Atomic assert/revoke/grant through owner execute is documented contract behavior. Four original and seven stronger head experiments support it. | Implement wallet-level batching; repeat tests for final generation and checkpoints. No EIP-7702 dependence for existing-wallet management. | -| G15 | P2 optional creation capability | Create scope updated | Page 5 now makes create deployment/grants only, with no funds or pc option. Factory batch remains proposed but absent; normal funding is separate. | Implement actual creation strategy and partial-failure metadata without inventing a required factory method or restoring removed inputs. | -| G16 | P1 | Compatibility gap | New `READ.CHAIN.WEB2` is `'web2'`; current `CHAIN.WEB2` and `READ.WEB2` are `'web2:https'`. | Implement the target constant and normalize legacy inputs during the compatibility window. Cover read types, serialization, helpers and transaction rejection; do not silently break old literal callers. | -| G17 | P1 | SDK lifecycle decision recorded | Existing SDK supports read-only initialization and `reinitialize`. Page 5 does not specify how `agenticWallet` is inherited, cleared or changed, or how read-only agentic management behaves. | Implement the SDK-owned review decision: explicit wallet selection on reinitialize, read-only write guards, fresh generation/role checks; verify compatibility cases. | -| G18 | P1 | SDK eligibility decision recorded | Initialization accepts an address named in a wallet rule; sends resolve enabled rules. Handling of a signer whose only rules are expired or revoked is unstated. | Implement enabled-rule eligibility without expiry filtering and uncached, consistent per-send lookup as recorded in the SDK-owned review. Agree public ambiguity wording and verify role changes. | -| G19 | P0/P1 | Product safety and encoding | Destination approve still cannot constrain the spender. New asset caps use maxTotal=0 for unlimited; native defaults remain separate. Destination token/native-marker resolution and ABI offset context need fixtures. | Agree approval policy, native defaults, resolved PRC20 context and safe ABI representations. | -| G20 | P1 | SDK composition and response mapping | Existing outbound tracking is hash/UTX-ID based. Route 2 request recipient, refund recipient and default maxPCForGas conflict with URP; Push-side allowance must be established by owner; four local pull/burn-fixture tests verify the existing owner execute mechanism. | Dedicated composer, logical AGW from override, preserved signer origin and live tracking/settlement verification. | -| G21 | P1 | Product scope | Contract grants up to eight native actions but dispatches a single agent call. SDK NativeRule has one action and transaction arrays are broadly promised. | Keep the specified single-action NativeRule. Decide native-array behavior; keep destination multicalls distinct. | -| G22 | P1 | Capability integration | SVM policy source exists; head agent identity is Push address and no longer verifies Ed25519 locally. SVM origin goes through UEA. | Verify deployed destination capability and implement obligations 19–23 when enabled. | -| G23 | P0 contract integration dependency | New multi-asset target | Page 5 uses assets[] and maxGasPerCall. Page 1 section 4c proposes per-token counters, 0–8 assets, maxTotal zero unlimited and bytes32 expectedCEA. Tested e704d5b still uses single-asset terms and amount counters. | Matched contract artifacts/fixtures for native marker and foreign-token resolution, per-asset enforcement, empty-assets call-only routing, expectedCEA representation, duplicate asset handling and token-carrying events. | -| G24 | P1 public read/update mismatch | Per-token spend shape unresolved | SDK Spent remains scalar amountSpent. Proposed assertSpent(configId,account) returns totals without expected snapshots, while rules.update still promises a race assertion. | Agree per-asset Spent and expected-total assertion inputs/semantics; prove stale state rejects atomically across all affected assets. Do not aggregate unlike units. | - -## External blockers after local closure - -[External blockers](external-blockers.md) reduces the standalone scope to seven decision/dependency areas, sent as four Harsh question groups and two active Zaryab requests. Z2 is now SDK owner-setup work supported by four local allowance tests; Z4 is a release note, not a speculative blocker. H2 keeps NativeRule single-action and asks only about native arrays. No production implementation gap is closed by these design decisions. - -## SDK owned work reviewed - -The [SDK owned review](sdk-owned-review.md) records internal decisions for creation/recovery (G13/G15), wallet-level replacement (G14), Web2 normalization (G16), read-only/reinitialize behavior (G17), enabled-rule eligibility (G18), and composition/responses/errors/transaction-creating reads (G20). SDK portions of G03/G08/G19/G22/G23 are also scoped. Ten existing unit suites pass, 183 tests total, plus four new allowance experiments. These decisions are ready for implementation; no gap is marked closed on that basis. Multi-asset accounting, native scope/defaults, approval policy and deployment remain external dependencies. - -## Cross-cutting requirements - -- expectedCEA is SDK-derived context: derive the AGW destination account, commit it in every universal rule, display it and monitor derivation drift. Do not use the signer CEA or an arbitrary pasted address. -- Checkpoint consumers compare counts, not only blocks. Replacement adds five ticks. Pre-existing allowance pulls can change balances without a new checkpoint, so evaluator policy needs explicit scope. -- create deploys/grants only; funding and approvals are separate. AGENTIC-TX-103 is removed. -- Assets[]/maxGasPerCall require new matching artifacts. Proposed asset maxTotal zero is unlimited; native defaults are separate. Per-token Spent and stale-spend assertions remain unresolved. -- Binder is dropped for v1. Historical hook cleanup text is not authorization to add it. -- Preserve explicit zero/omission semantics, supported native arrays and deterministic duplicate-rule behavior; do not silently alter policy failure timing. - -## Closure records - -Record accepted behavior, exact source/spec revision, test evidence and remaining limits when closing an item. Source implementation and deployment readiness are separate statuses. Use [Harsh questions](questions-harsh.md) and [Zaryab questions](questions-zaryab.md) for unresolved decisions. No questions have been sent. +| G01 | P1 | Open deployment dependency | Reviewed source is e704d5b; build/source tests are available. SDK deployment registry remains empty. | Obtain and verify the selected generation’s manifest, wiring, source artifacts, capabilities and start blocks before live acceptance. | +| G02 | P0 | Source implemented; deployment pending | D3 executeAsAgent/agentOf and sender adapter exist; SmartSession is unchanged. SDK uses this model. | Verify the selected deployment and retain sender-binding/alternate-path coverage; do not reopen the withdrawn engine-fork proposal. | +| G03 | P1 | SDK question resolved and implemented | Validator/nonce ID calculation and generation-specific derivation are internal. Public generation-context helpers were removed per Harsh H4.1. IDs remain wallet-scoped and receipt-confirmed. | Revalidate vectors for the final generation under G01/G23; no public context-signature approval is needed. | +| G04 | P1 | ABI history corrected; release note | Six-field main is older; inspected current gateway and historical Donut dispatcher use eight fields. A hypothetical future field removal is not a present SDK blocker. | Encode the selected manifest’s gateway ABI and track any actual migration with that deployment. | +| G05 | P1 | Downstream marketplace alignment | Core cb69e0b requires rule/job expiry equality; supporting Notion pages have conflicting inequalities. | Align the marketplace/compiler track. Do not impose job equality on every standalone AGW rule. | +| G06 | P2 | Closed for v1 | Binder was never in the reviewed code and is dropped for v1. | No binder implementation or binder-dependent lifecycle requirement in standalone AGW. Preserve historical snapshots as evidence. | +| G07 | P1 | Known platform dependency | creditRevert depends on Push-core executor work. Until delivered, a far-side failure can leave spend inflated. | Track platform delivery and document/test the limitation. This is not an unanswered AGW redesign question. | +| G08 | P1 | Reads implemented; metadata pending | Stored checkpoint count/event reads are implemented. Editable labels and grant ref remain generation dependencies. Harsh deferred revoked history, so it is no longer a requirement here. | Deliver agreed ref/label capabilities and verify deployment. Do not request agent-event additions solely for deferred historical reads. | +| G09 | P1 | Deferred from standalone AGW | Canonical card schema/encoding remains a marketplace issue. Harsh H5 removes compileCard from standalone AGW; its public stub was removed. | Resume schema/compiler vectors under the future marketplace scope, not as an AGW release blocker. | +| G10 | P1 | Downstream marketplace scope | Current marketplace binds one EVM chain and one rulesId; broader card binding remains unresolved downstream. | Align future marketplace/job cardinality. Standalone AGW does not invent multi-rule job bindings. | +| G11 | P1 | Downstream job dependency | Payment-token selection differs between the target job SDK and the one-token-per-deployment kernel. | Align selected K-12/deployment design in the job track. | +| G12 | P1 | Downstream evaluator/hook delivery | Current start/fund guards exist; evaluator baseline/submit integration is incomplete. | Verify lifecycle placement and bypasses in the separate marketplace/job/evaluator work. | +| G13 | P1 | SDK implemented locally; spec wording stale | Core supports native 7702 batching with a sequential fallback. Creation uses actual capability, index-bound deployment and receipt/recovery metadata. | Correct the stale factory-batch requirement in source docs when maintained; verify final-generation/UEA creation on the release deployment. | +| G14 | P1 | Native update implemented locally; universal ABI pending | Existing-wallet assert → revoke → grant is one atomic owner batch. Native stale-spend rollback and five checkpoint ticks are tested. | Implement final universal per-token assertions after G23/G24 artifacts arrive; recheck on the selected deployment. | +| G15 | P2 | SDK implemented locally | create deploys/grants only; funding is separate. No required new createWallet factory method. Index binding prevents grants on a raced wallet; partial recovery preserves operation receipts and unknown state. | Verify final-generation events and native/UEA strategies; do not restore removed funding inputs. | +| G16 | P1 | Implemented; migration documentation pending | READ.CHAIN.WEB2 is web2. Legacy web2:https input is normalized to unchanged wire identity. Deprecated aliases now use the new public value. | Document the observable alias/literal-comparison migration and run relevant read acceptance before release. | +| G17 | P1 | SDK decision implemented locally | Read-only write guards and explicit agenticWallet selection on reinitialize are implemented. Signer/network/wallet changes rebuild role/capability context. | Preserve compatibility coverage and verify with the release deployment. | +| G18 | P1 | SDK behavior implemented locally | Initialization uses enabled-rule identity; sends perform uncached lookup without expiry filtering. Missing/ambiguous candidates fail before signing. Public list is enabled-only; unknown/revoked get returns RULE_NOT_FOUND. | Verify final-generation and live permission-change cases; public history is deferred, not an open v1 question. | +| G19 | P0/P1 | Approval policy resolved; H3 defaults open | Harsh assigns approval screening to UI/marketplace. SDK selector rejection and mandatory-spender policy were removed, while ABI/chain/caller-requested pin validation remains. Defaults are byte-for-byte unchanged pending the exact H3 table. | Clarify omitted values, explicit zero and maxValueTotal. Obtain final token/native-marker fixtures with G23. Do not keep approval-policy sign-off as an SDK blocker. | +| G20 | P1 | Composer/responses implemented locally; live acceptance pending | Dedicated AGW composer uses wallet CEA/refund context, explicit owner-established allowance and separate signer gas. Live/replay summaries are canonical with ordered call metadata; real response-builder wait is covered locally. | Prove actual production pull/burn, node/TSS acceptance, recipient/executor correlation and tracking against the compatible deployment. | +| G21 | P1 | Product direction resolved; batching implemented locally | NativeRule remains one action. Arrays use a sender-preserving UEA/7702 outer batch of single executeAsAgent calls, each checked by policy. Native sequential fallback is prohibited. Local real-type-4 tests prove sender identity, cumulative counters and mined rollback. | Run release-deployment UEA/7702 acceptance. The local executor is a fixture; arbitrary forwarding helpers are not a substitute for the agent account. | +| G22 | P1 | Open SVM contract/capability dependency | Solana-origin identity through UEA is distinct from Solana destination rules. Harsh refers destination work to Zaryab; SDK destination capability remains gated. | Obtain representable terms/payloads, supported capabilities and deployment, then implement/verify obligations 19–23. | +| G23 | P0 | Open final universal ABI dependency | Target assets[]/maxGasPerCall is not implemented by the tested single-asset source. New per-asset enforcement, zero/omission semantics, empty-assets routing and expectedCEA representation need matched artifacts. | Deliver final terms/read/event ABI and vectors; no silent single-asset substitution for the public multi-asset target. | +| G24 | P1 | Public spend question resolved; internal assertion ABI open | Public Spent and RulesRecord.spent were removed per Harsh H4.2. Internal per-token counters remain necessary. A getter returning totals cannot replace caller-supplied expected-value checks for atomic update. | Obtain per-token read/assertion ABI and prove stale state rejects across all old-rule assets. No public per-token result-shape approval is required. | +| G25 | P1 | Open raw-offset public API decision | R5 fix returns exact calldata offsets/words instead of invented argument indexes and accepts that form for round trips. This extends the public NativeRule shape; the later change was not covered by Harsh’s initial replies. | Decide public raw authoring versus a separate decoded/internal wire representation; preserve ABI-based validation at the agreed boundary. | + +## Validation and release boundaries + +The [October 4 alignment evidence](research/product-alignment-2026-10-04/README.md) records 1,917 passing unit tests, 36 passing local-contract tests, clean build/typechecks and seven existing lint errors in unchanged files. AGW E2E selection has 23 opt-in scenarios; default all remains 76. Live E2Es have not been run. + +Local batch proof uses actual AGW/factory/engine/policy and real Anvil EIP-7702 transactions, with a small fixture executor. UEA shaping/replay is unit-tested and reuses the existing transport; live UEA, production executor/gateway and destination acceptance remain outstanding. + +## Rules for closure + +- A product decision can close a question without completing a contract or deployment dependency. +- Implemented source/local behavior and live acceptance are separate statuses; do not count the same deployment dependency once per SDK method as independent defects. +- expectedCEA derives from AGW plus destination context. Signer CEA and arbitrary pasted addresses are not substitutes. +- Checkpoint consumers compare counts; allowance-driven balance changes are not always checkpointed. Current single replacement adds five ticks. +- Internal spend assertions remain required even when public spend records are removed. +- H3 defaults and raw-offset representation remain open. Keep current defaults until the former is explicitly clarified. +- Harsh’s replies have been received. The linked question documents now contain remaining follow-ups; no outbound team messages were sent by this agent. From b1597b91a25dbf7f691f589b4e1e154add604315 Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Mon, 5 Oct 2026 13:19:30 +0530 Subject: [PATCH 16/68] docs(agw): remove deployment request from contract questions --- plan/agw/current-baseline.md | 7 +++++++ plan/agw/external-blockers.md | 7 ++++++- plan/agw/gaps.md | 6 ++++-- plan/agw/implementation-plan.md | 4 ++-- plan/agw/implementation-status.md | 4 +++- plan/agw/questions-zaryab.md | 26 ++++++-------------------- 6 files changed, 28 insertions(+), 26 deletions(-) diff --git a/plan/agw/current-baseline.md b/plan/agw/current-baseline.md index b8cb9c14..f7f190c4 100644 --- a/plan/agw/current-baseline.md +++ b/plan/agw/current-baseline.md @@ -77,3 +77,10 @@ Define per-asset Spent and replacement assertion semantics, empty-asset routing, See [successful refresh report](research/notion-refresh-2026-10-03.md). All earlier download failures remain historical evidence; download permission was sufficient for this run. The follow-up [external blocker register](external-blockers.md) records what still needs team input after SDK-owned closure. Remote refs were rechecked unchanged; the Notion snapshot date above is unchanged. + + +## Deployment coordination October 5 + +Shoaib supplied the fixed deployment-address table and will receive Zaryab’s completion notice. The table exactly matches the [saved AGW address book](notion/agw-address-book-donut-2026-09-04.md): factory proxy `0xF1A131571f89fD06890576e6cD0154114ACBBc8b`, wallet implementation `0x959ED7f6943bdd56B3a359BAE0115fef4aa07e17`, UCEP `0x79F07D379BdC26468E48025a61bC955909522c1D`, PushSessionValidator `0x5A59a5Ac94d5190553821307F98e4673BF3c4a1D`, and engine `0x7540f9a59693d51CFB4A3727141eAE4836F96749`. Remaining dependencies/admin addresses are preserved in that source snapshot. + +The deployment question is removed from the team handoff. These are known address inputs, not a newly verified target-generation manifest: the table uses the earlier PushAgentWallet/UCEP/PushSessionValidator naming and sizes. Once Zaryab reports completion, verify factory wiring, deployed wallet/policy ABI, source revision and event start blocks against the intended release. No RPC probe or SDK registry change occurred in this documentation pass. diff --git a/plan/agw/external-blockers.md b/plan/agw/external-blockers.md index b8cb2948..a1665fc4 100644 --- a/plan/agw/external-blockers.md +++ b/plan/agw/external-blockers.md @@ -9,7 +9,8 @@ Updated October 4, 2026 from [Harsh’s supplied replies](product-decisions-2026 | Exact defaults and revised fields | Harsh H3 | Final omission/explicit-zero table and the referenced maxValueTotal change; fresh page-5 body still matches the older snapshot | | Native decoded-rule representation | Harsh H4.5 | Decide whether raw offsets are public read/write inputs or an internal/separate decoded representation | | Universal accounting and encoding | Zaryab Z1 | Final multi-asset terms, internal per-token reads, expected-spend assertion ABI/vectors, empty-assets routing and envelope/CEA representation | -| Target generation and destination capabilities | Zaryab Z1/Z3 | Ref/label scope, SVM artifacts and a verified compatible deployment manifest for live acceptance | +| Contract metadata and destination capabilities | Zaryab Z1 | Ref/label scope and matching SVM artifacts | +| Deployment readiness | Agreed coordination; SDK verifies after completion notice | Fixed addresses are known; Zaryab will notify Shoaib. This is a release dependency, not an open deployment question | Hiding public spend does not remove internal spend assertions. Deferring public history does not remove the need to distinguish enabled, expired and revoked permissions for execution. @@ -30,3 +31,7 @@ The clear product decisions are now implemented: approval-policy rejection and o SDK page 5 was downloaded October 4 and matches the saved body after link normalization; other registered pages were not refreshed. [Evidence](research/notion-check-2026-10-04/comparison.json). AGW remote head remains e704d5b. No compatible deployment was verified in this pass. Continue SDK work against explicit adapters and assumptions. A compatible manifest, internal multi-asset artifacts and authorized live acceptance remain necessary before enabling the final release. The source snapshots remain unedited evidence; the product decision record captures the newer scope direction. + +## Deployment coordination October 5 + +The deployment request was removed from Zaryab’s question document at Shoaib’s direction. The supplied fixed-address table matches the [saved address book](notion/agw-address-book-donut-2026-09-04.md). Keep it as known address input; after the completion notice, the SDK team verifies deployed code/wiring, matched ABI and event start blocks, then prepares the registry/E2E configuration. No registry entry was enabled by this documentation update. diff --git a/plan/agw/gaps.md b/plan/agw/gaps.md index be118940..7657d7bd 100644 --- a/plan/agw/gaps.md +++ b/plan/agw/gaps.md @@ -13,7 +13,7 @@ Source baseline: AGW `pushAgenticWallet_v3@e704d5b`, core marketplace `cb69e0b`, | Exact limit/default table and the referenced maxValueTotal change | [Harsh H3](questions-harsh.md#h3) | G19 | | Public raw-offset read/write representation | [Harsh H4.5](questions-harsh.md#h4-5) | G25 | | Final multi-asset encoding, internal per-token reads and expected-spend assertions | [Zaryab Z1](questions-zaryab.md#z1) | G23, G24 | -| Target ref/label/envelope scope, SVM artifacts and compatible deployment | [Zaryab Z1/Z3](questions-zaryab.md#z3) | G01, G02, G08, G22 | +| Target ref/label/envelope scope and SVM artifacts | [Zaryab Z1](questions-zaryab.md#z1) | G08, G22 | Approval screening, public generation context, public spend shape, revoked-history reconstruction and compileCard are no longer unresolved standalone product questions. Native agent batching is implemented through a sender-preserving outer transport; it does not require a new batch-mode AGW agent entry point. @@ -23,7 +23,7 @@ P0 blocks agreed authorization/accounting or safe final integration. P1 affects | ID | Priority | Status | Current finding or resolution | Remaining action | | --- | --- | --- | --- | --- | -| G01 | P1 | Open deployment dependency | Reviewed source is e704d5b; build/source tests are available. SDK deployment registry remains empty. | Obtain and verify the selected generation’s manifest, wiring, source artifacts, capabilities and start blocks before live acceptance. | +| G01 | P1 | Open deployment dependency | Reviewed source is e704d5b; build/source tests are available. SDK deployment registry remains empty pending compatibility verification; fixed addresses have been supplied. | Await the agreed completion notice from Zaryab; then verify the known fixed addresses, code/wiring, matched artifacts and event start blocks. Deployment is a release dependency, not an open question. | | G02 | P0 | Source implemented; deployment pending | D3 executeAsAgent/agentOf and sender adapter exist; SmartSession is unchanged. SDK uses this model. | Verify the selected deployment and retain sender-binding/alternate-path coverage; do not reopen the withdrawn engine-fork proposal. | | G03 | P1 | SDK question resolved and implemented | Validator/nonce ID calculation and generation-specific derivation are internal. Public generation-context helpers were removed per Harsh H4.1. IDs remain wallet-scoped and receipt-confirmed. | Revalidate vectors for the final generation under G01/G23; no public context-signature approval is needed. | | G04 | P1 | ABI history corrected; release note | Six-field main is older; inspected current gateway and historical Donut dispatcher use eight fields. A hypothetical future field removal is not a present SDK blocker. | Encode the selected manifest’s gateway ABI and track any actual migration with that deployment. | @@ -64,3 +64,5 @@ Local batch proof uses actual AGW/factory/engine/policy and real Anvil EIP-7702 - Internal spend assertions remain required even when public spend records are removed. - H3 defaults and raw-offset representation remain open. Keep current defaults until the former is explicitly clarified. - Harsh’s replies have been received. The linked question documents now contain remaining follow-ups; no outbound team messages were sent by this agent. + +Deployment coordination update October 5: the address request is retired. The supplied table matches the saved historical address book; its verification marks are source-reported, not new SDK compatibility checks. Zaryab will notify Shoaib when the intended deployment is complete. The SDK performs its registry and live-acceptance checks afterward. diff --git a/plan/agw/implementation-plan.md b/plan/agw/implementation-plan.md index 19440484..8f0fcdcb 100644 --- a/plan/agw/implementation-plan.md +++ b/plan/agw/implementation-plan.md @@ -46,7 +46,7 @@ These are working assumptions for development, not accepted product changes. Rep | A04 | Generation-dependent IDs, derivation and encoding context remain internal; client.agentic.derive remains public | Harsh H4.1 resolved; implemented | Public utility exports and internal codecs | | A05 | Spend is internal, not a public result. Final per-token wire/read/assertion ABI, empty-assets routing and CEA width remain unresolved | Harsh H4.2 scope resolved; Zaryab Z1 delivery pending | Internal accounting and codec adapter | | A06 | V1 lists enabled rules only; unknown/revoked get returns RULE_NOT_FOUND. No historical record reconstruction | Harsh H4.3 deferred; implemented | Public read model | -| A07 | A verified new deployment supplies the matching grant ref/envelope/metadata ABI, addresses and start blocks. Historical Donut remains a distinct generation. | Zaryab Z1/Z3 / E07 | Deployment manifest and capability adapter | +| A07 | A verified new deployment supplies the matching grant ref/envelope/metadata ABI, addresses and start blocks. Historical Donut remains a distinct generation. | Zaryab Z1 for contract surface; agreed deployment notice, then SDK verification | Deployment manifest and capability adapter | | A08 | No compileCard in standalone AGW; canonical cards belong to later marketplace work | Harsh H5: outside AGW v1 | No public compiler stub/export | ### What closes each assumption @@ -54,7 +54,7 @@ These are working assumptions for development, not accepted product changes. Rep - A01/A02/A04: clear product scope is implemented. A03 defaults still need exact agreed wording. - A05: Harsh agrees the public representation; Zaryab supplies matching terms, read/assertion ABIs and vectors. Clarification alone does not supply missing contract code. - A06: revoked history is outside v1; active-only reads and explicit RULE_NOT_FOUND behavior are implemented. -- A07: Zaryab identifies the selected feature scope and delivers the actual compatible deployment manifest/artifacts. A planned address or deployment date does not close it; we verify deployment and integration. +- A07: Zaryab identifies the selected contract surface and notifies Shoaib when deployment is complete. Fixed addresses are already available. The SDK then builds/verifies its deployment manifest, registry and integration evidence; no additional address request is needed. - A08: closed for standalone AGW by deferring compileCard to the marketplace track. Record design decisions and artifact/deployment readiness separately. All eight have an explicit question owner, but answers alone do not mean all eight are implemented or verified. diff --git a/plan/agw/implementation-status.md b/plan/agw/implementation-status.md index 453e4489..85cf6b09 100644 --- a/plan/agw/implementation-status.md +++ b/plan/agw/implementation-status.md @@ -44,7 +44,7 @@ October 3, 2026, updated after the implementation review (R1–R7 fixed; see the | A04 | Internal generation details | n/a | rulesId/deriveWallet/encodeRules and RulesEncodeContext are not public; client.agentic.derive remains | | A05 | Public spend not required | Final multi-asset artifacts missing | Public spent removed; internal reads/assertions retained; final universal wire stays gated | | A06 | History deferred from v1 | Not required for v1 | list is enabled-only; unknown/revoked get returns RULE_NOT_FOUND | -| A07 | Open (Zaryab Z1/Z3) | **No verified deployment** | Registry and `CONSTANTS.AGENTIC` empty; every AGW call fails `GENERATION_UNSUPPORTED`; `ref` and `setLabel` gated | +| A07 | Contract surface pending (Z1); deployment notice already coordinated | **No verified deployment** | Registry and `CONSTANTS.AGENTIC` empty; every AGW call fails `GENERATION_UNSUPPORTED`; `ref` and `setLabel` gated | | A08 | Outside standalone AGW | Future marketplace dependency | Public compileCard stub and capability removed | Harsh replies and the focused October 4 page-5 recheck are recorded in product-decisions-2026-10-04.md. The clear decisions above are implemented; defaults are still pending. @@ -59,3 +59,5 @@ Implementation evidence exists for G03 (explicit-context IDs, receipt IDs), G08 F1 is resolved with a shared canonical first-call summary and complete `agentic.destinationCalls` metadata on send/replay. R6 wait-path regressions are now in the regular unit suite. Current validation: 1,908 unit tests, 34 local-contract tests, both typechecks and build pass. No live acceptance was performed. See [resolution](implementation-review/outbound-response-resolution.md). Current alignment verification is recorded in [product alignment evidence](research/product-alignment-2026-10-04/README.md). Existing older counts below/above describe their named revisions. + +Deployment coordination October 5: fixed addresses are supplied and Zaryab will notify Shoaib when deployment is complete. Z3 is removed from the open questions. SDK compatibility verification and live acceptance remain required afterward; the registry is unchanged. diff --git a/plan/agw/questions-zaryab.md b/plan/agw/questions-zaryab.md index ed1a4166..609941bf 100644 --- a/plan/agw/questions-zaryab.md +++ b/plan/agw/questions-zaryab.md @@ -2,12 +2,11 @@ We need the artifacts and compatibility details below to finish the AGW SDK against the intended contract generation. Please reply by item ID with the source/ABI/vector link when available, or the remaining work and expected delivery. Product choices that affect these requests are linked to Harsh's document. -**Status:** updated October 4 after [Harsh’s replies](product-decisions-2026-10-04.md). Only Z1/Z3 remain for standalone AGW. Public multi-asset spend, revoked history and compileCard are no longer requested as standalone v1 features; internal accounting still matters. +**Status:** updated October 4 after [Harsh’s replies](product-decisions-2026-10-04.md). Only Z1 remains as an active contract question for standalone AGW. Public multi-asset spend, revoked history and compileCard are no longer requested as standalone v1 features; internal accounting still matters. | Item | Requested deliverable | What it enables | | --- | --- | --- | | [Z1](#z1) | Matching terms, accounting/assertion ABI and metadata surface | Final rule encoding, reads and safe replacement | -| [Z3](#z3) | Verified deployment and capability manifest | Generation onboarding and live acceptance | ## Source baseline @@ -59,7 +58,7 @@ The SDK will implement the wrapper and atomic batch. Harsh has said per-token sp -### Z1.3 References, labels and historical metadata +### Z1.3 Reference and label surface **Please confirm the selected generation's surface:** @@ -72,26 +71,13 @@ Harsh deferred revoked-rule history for v1; no additional historical metadata is **Evidence:** [target SDK lifecycle](notion/5-sdk-agw.md); [pinned grant signatures](https://github.com/pushchain/push-agentic-wallets/blob/e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9/src/AGW.sol#L483); [pinned grant event emission](https://github.com/pushchain/push-agentic-wallets/blob/e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9/src/AGW.sol#L636). - + -## Z3 Deployment and capability manifest +### Z1.4 SVM contract surface -**Please provide the following for the selected release deployment:** +Harsh referred SVM destination work to you. Please identify its supported rule constraints and matching terms/payload ABI or fixtures when ready, including program/discriminator and account/data checks. We need these to implement the SDK representation; Solana-origin signers through UEA are a separate capability. -| Manifest field | Required information | -| --- | --- | -| Network and addresses | Factory, wallet implementation, validator, engine and policy addresses | -| Source and ABI | Exact revisions/build artifacts, proxy implementations where applicable and wiring | -| Start blocks | Deployment/event start blocks for bounded discovery and reconstruction | -| Reused components | Whether engine/policy instances are shared with previous generations and their compatibility | -| Gateway | Matched gateway implementation/request ABI and any planned coordinated migration | -| Destination support | Supported EVM/SVM capabilities; matching SVM terms/payload fixtures if enabled | - -Existing wallet clones cannot acquire the target wallet ABI. We will use the manifest to build a generation registry, verify deployed wiring and run live acceptance. These addresses must correspond to the intended release generation. - -**If deployment is pending:** provide the intended feature scope and remaining delivery work. Clarification settles the plan; live acceptance remains pending until deployment exists. - -Harsh referred SVM work to you. Please include its supported input constraints and matching artifacts when ready. [Historical Donut addresses](notion/agw-address-book-donut-2026-09-04.md) are retained as historical evidence, not assumed to support this target. +Deployment coordination is already agreed: the addresses are known, and you will notify Shoaib when deployment is complete. There is no additional deployment/address request in this document. Compatibility checks and live acceptance remain SDK release work. ## Supporting documents From a66ff7d70f3c3fdca0dd3705797d66a1b1ecc768 Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Tue, 6 Oct 2026 03:26:37 +0530 Subject: [PATCH 17/68] feat(agw): integrate deployed v4 rules and internal SVM codecs --- .../__agw-local__/agw-local-advanced.spec.ts | 353 ++- .../__agw-local__/agw-local-races.spec.ts | 107 +- packages/core/__agw-local__/agw-local.spec.ts | 200 +- packages/core/__agw-local__/harness.ts | 196 +- .../core/__agw-local__/svm-internals.spec.ts | 328 ++ .../core/__agw-local__/v4-multiasset.spec.ts | 367 +++ packages/core/__agw-local__/vectors.spec.ts | 82 +- packages/core/__e2e__/agw/_manifest.ts | 141 +- packages/core/__e2e__/agw/create.spec.ts | 56 +- packages/core/__e2e__/agw/lifecycle.spec.ts | 89 +- .../core/__e2e__/agw/multi-asset-svm.spec.ts | 25 +- .../core/__e2e__/agw/universal-evm.spec.ts | 185 +- .../core/__e2e__/agw/v4-multiasset.spec.ts | 137 + packages/core/__e2e__/ci/run.ts | 46 +- packages/core/__e2e__/ci/suite.ts | 109 +- packages/core/__e2e__/shared/agw-state.ts | 6 +- packages/core/jest.agw-local.config.ts | 7 +- .../agw-local/contracts/HarnessFixtures.sol | 9 + packages/core/scripts/agw-local/gen-abi.mjs | 38 +- packages/core/scripts/agw-local/prepare.sh | 4 +- .../{e704d5b-vectors.json => v4-vectors.json} | 4 +- .../src/lib/agentic/__tests__/codec.spec.ts | 301 +- .../src/lib/agentic/__tests__/fake-chain.ts | 163 +- .../lib/agentic/__tests__/management.spec.ts | 480 ++- .../__tests__/native-batch-response.spec.ts | 8 +- .../__tests__/outbound-response.spec.ts | 6 +- .../agentic/__tests__/reads-context.spec.ts | 375 ++- .../__tests__/response-surface.spec.ts | 179 +- .../agentic/__tests__/rules-policy.spec.ts | 285 +- .../src/lib/agentic/__tests__/send.spec.ts | 473 ++- .../agentic/__tests__/svm-internals.spec.ts | 502 +++ .../core/src/lib/agentic/agentic.types.ts | 39 +- packages/core/src/lib/agentic/capabilities.ts | 31 +- .../core/src/lib/agentic/codec/defaults.ts | 37 +- .../codec/historical/e704d5b-universal.ts | 64 - packages/core/src/lib/agentic/codec/ids.ts | 27 +- packages/core/src/lib/agentic/codec/native.ts | 104 +- packages/core/src/lib/agentic/codec/rules.ts | 72 +- .../core/src/lib/agentic/codec/session.ts | 49 +- .../src/lib/agentic/codec/svm-accounts.ts | 104 + .../core/src/lib/agentic/codec/svm-terms.ts | 303 ++ .../src/lib/agentic/codec/universal-terms.ts | 60 + .../core/src/lib/agentic/codec/universal.ts | 223 +- packages/core/src/lib/agentic/constants.ts | 24 +- .../contracts/abi/e704d5b/agent-validator.ts | 145 - .../abi/e704d5b/universal-rules-policy.ts | 2065 ------------ .../contracts/abi/v4/agent-validator.ts | 145 + .../abi/{e704d5b => v4}/agw-factory.ts | 1456 ++++----- .../contracts/abi/{e704d5b => v4}/agw.ts | 2256 ++++++------- .../contracts/abi/{e704d5b => v4}/index.ts | 4 +- .../abi/{e704d5b => v4}/smart-session.ts | 2810 ++++++++--------- .../abi/v4/universal-rules-policy.ts | 2156 +++++++++++++ .../src/lib/agentic/contracts/donut-v4.ts | 13 + .../lib/agentic/contracts/prc20-metadata.ts | 64 + .../agentic/contracts/{e704d5b.ts => v4.ts} | 173 +- packages/core/src/lib/agentic/deployments.ts | 108 +- packages/core/src/lib/agentic/errors.ts | 2 +- .../src/lib/agentic/execution/outbound.ts | 94 +- .../core/src/lib/agentic/execution/send.ts | 206 +- .../src/lib/agentic/execution/svm-outbound.ts | 72 + .../src/lib/agentic/execution/svm-payload.ts | 146 + .../core/src/lib/agentic/management/create.ts | 170 +- .../src/lib/agentic/management/prepare.ts | 132 + .../src/lib/agentic/management/rules-write.ts | 301 +- packages/core/src/lib/agentic/reads/rules.ts | 171 +- .../core/src/lib/agentic/reads/snapshot.ts | 36 +- packages/core/src/lib/agentic/response.ts | 144 +- packages/core/src/lib/agentic/revert.ts | 51 +- packages/core/src/lib/agentic/runtime.ts | 49 +- packages/core/src/lib/agentic/utils.ts | 134 +- packages/core/src/lib/constants/index.ts | 2 +- .../core/src/lib/universal/prc20-address.ts | 168 + packages/core/src/lib/utils.ts | 179 +- 73 files changed, 12817 insertions(+), 7033 deletions(-) create mode 100644 packages/core/__agw-local__/svm-internals.spec.ts create mode 100644 packages/core/__agw-local__/v4-multiasset.spec.ts create mode 100644 packages/core/__e2e__/agw/v4-multiasset.spec.ts rename packages/core/src/lib/agentic/__fixtures__/{e704d5b-vectors.json => v4-vectors.json} (96%) create mode 100644 packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts delete mode 100644 packages/core/src/lib/agentic/codec/historical/e704d5b-universal.ts create mode 100644 packages/core/src/lib/agentic/codec/svm-accounts.ts create mode 100644 packages/core/src/lib/agentic/codec/svm-terms.ts create mode 100644 packages/core/src/lib/agentic/codec/universal-terms.ts delete mode 100644 packages/core/src/lib/agentic/contracts/abi/e704d5b/agent-validator.ts delete mode 100644 packages/core/src/lib/agentic/contracts/abi/e704d5b/universal-rules-policy.ts create mode 100644 packages/core/src/lib/agentic/contracts/abi/v4/agent-validator.ts rename packages/core/src/lib/agentic/contracts/abi/{e704d5b => v4}/agw-factory.ts (51%) rename packages/core/src/lib/agentic/contracts/abi/{e704d5b => v4}/agw.ts (52%) rename packages/core/src/lib/agentic/contracts/abi/{e704d5b => v4}/index.ts (66%) rename packages/core/src/lib/agentic/contracts/abi/{e704d5b => v4}/smart-session.ts (53%) create mode 100644 packages/core/src/lib/agentic/contracts/abi/v4/universal-rules-policy.ts create mode 100644 packages/core/src/lib/agentic/contracts/donut-v4.ts create mode 100644 packages/core/src/lib/agentic/contracts/prc20-metadata.ts rename packages/core/src/lib/agentic/contracts/{e704d5b.ts => v4.ts} (68%) create mode 100644 packages/core/src/lib/agentic/execution/svm-outbound.ts create mode 100644 packages/core/src/lib/agentic/execution/svm-payload.ts create mode 100644 packages/core/src/lib/agentic/management/prepare.ts create mode 100644 packages/core/src/lib/universal/prc20-address.ts diff --git a/packages/core/__agw-local__/agw-local-advanced.spec.ts b/packages/core/__agw-local__/agw-local-advanced.spec.ts index cc38d4e1..d9e26e3b 100644 --- a/packages/core/__agw-local__/agw-local-advanced.spec.ts +++ b/packages/core/__agw-local__/agw-local-advanced.spec.ts @@ -1,6 +1,6 @@ import { readNativeCounters } from '../__e2e__/shared/agw-state'; /** - * Real-contract checks for the harder AGW paths (pinned e704d5b on anvil). + * Real-contract checks for the harder AGW paths (pinned v4 on anvil). * The universal-outbound block drives the SDK's composer with a runtime whose * CEA and fee quote are local stand-ins (no destination chain or price feeds * exist here); URP still decides every gate on the composed request. @@ -22,7 +22,7 @@ import { updateRules } from '../src/lib/agentic/management/rules-write'; import type { AgenticRuntime } from '../src/lib/agentic/runtime'; import type { AgenticExecutionContext } from '../src/lib/agentic/context'; import { buildSession, encodeEnvelope } from '../src/lib/agentic/codec/session'; -import { encodeUniversalTermsE704d5b } from '../src/lib/agentic/codec/historical/e704d5b-universal'; +import { encodeUniversalTerms } from '../src/lib/agentic/codec/universal-terms'; import { startHarness, type Harness } from './harness'; const TARGET_ABI = parseAbi([ @@ -47,20 +47,34 @@ const CORE_ABI = parseAbi([ 'function getOutboundTxGasAndFees(address,uint256) view returns (address,uint256,uint256,uint256,string,uint256)', ]); -type Internals = { agenticRuntime: AgenticRuntime; agenticContext?: AgenticExecutionContext }; +type Internals = { + agenticRuntime: AgenticRuntime; + agenticContext?: AgenticExecutionContext; +}; const internals = (c: PushChain) => c as unknown as Internals; async function chainNow(h: Harness): Promise { return Number((await h.publicClient.getBlock()).timestamp); } async function warp(h: Harness, seconds: number): Promise { - await h.publicClient.request({ method: 'evm_increaseTime' as never, params: [seconds] as never }); - await h.publicClient.request({ method: 'evm_mine' as never, params: [] as never }); + await h.publicClient.request({ + method: 'evm_increaseTime' as never, + params: [seconds] as never, + }); + await h.publicClient.request({ + method: 'evm_mine' as never, + params: [] as never, + }); } const fund = (h: Harness, to: Address, value: bigint) => - h.wallets[4].sendTransaction({ to, value, account: h.wallets[4].account!, chain: h.wallets[4].chain }); + h.wallets[4].sendTransaction({ + to, + value, + account: h.wallets[4].account!, + chain: h.wallets[4].chain, + }); -describe('AGW advanced paths against real e704d5b contracts', () => { +describe('AGW advanced paths against real v4 contracts', () => { let h: Harness; let owner: PushChain; let agentAddr: Address; @@ -77,7 +91,9 @@ describe('AGW advanced paths against real e704d5b contracts', () => { describe('native pins, amount and value caps', () => { let wallet: Address; let agent: PushChain; - const beneficiary = getAddress('0x00000000000000000000000000000000000b0b0b'); + const beneficiary = getAddress( + '0x00000000000000000000000000000000000b0b0b' + ); beforeAll(async () => { const created = await owner.agentic.create('pins', { @@ -95,7 +111,9 @@ describe('AGW advanced paths against real e704d5b contracts', () => { ], }); wallet = created.wallet; - await h.publicClient.waitForTransactionReceipt({ hash: await fund(h, wallet, BigInt(10) ** BigInt(18)) }); + await h.publicClient.waitForTransactionReceipt({ + hash: await fund(h, wallet, BigInt(10) ** BigInt(18)), + }); agent = await h.client(1, { agenticWallet: wallet }); }); @@ -103,35 +121,63 @@ describe('AGW advanced paths against real e704d5b contracts', () => { agent.universal.sendTransaction({ to: h.addresses.target, value, - data: encodeFunctionData({ abi: TARGET_ABI, functionName: 'deposit', args: [to, amount] }), + data: encodeFunctionData({ + abi: TARGET_ABI, + functionName: 'deposit', + args: [to, amount], + }), }); it('a pinned beneficiary and an in-cap amount pass', async () => { await (await deposit(beneficiary, BigInt(5), BigInt(10))).wait(); expect( - await h.publicClient.readContract({ address: h.addresses.target, abi: TARGET_ABI, functionName: 'lastBeneficiary' }) + await h.publicClient.readContract({ + address: h.addresses.target, + abi: TARGET_ABI, + functionName: 'lastBeneficiary', + }) ).toBe(beneficiary); }); it('a wrong beneficiary is rejected by URP with a decoded error and no state change', async () => { const err = await deposit(agentAddr, BigInt(5)).catch((e) => e); expect(err).toBeInstanceOf(AgenticRevertError); - expect(err.decodedError?.name).toBe("PolicyCheckReverted(ArgPinMismatch)"); + expect(err.decodedError?.name).toBe( + 'PolicyCheckReverted(ArgPinMismatch)' + ); const rec = await owner.agentic.wallet(wallet).rules.list(); expect(rec.rules[0]).not.toHaveProperty('spent'); - expect(await readNativeCounters(h.publicClient, h.generation.addresses, wallet, rec.rules[0].rulesId)).toMatchObject({ amountSpent: BigInt(5), callsUsed: 1 }); + expect( + await readNativeCounters( + h.publicClient, + h.generation.addresses, + wallet, + rec.rules[0].rulesId + ) + ).toMatchObject({ amountSpent: BigInt(5), callsUsed: 1 }); }); it('per-call and lifetime amount caps are enforced on-chain', async () => { - await expect(deposit(beneficiary, BigInt(11))).rejects.toBeInstanceOf(AgenticRevertError); + await expect(deposit(beneficiary, BigInt(11))).rejects.toBeInstanceOf( + AgenticRevertError + ); await (await deposit(beneficiary, BigInt(10))).wait(); - await expect(deposit(beneficiary, BigInt(1))).rejects.toBeInstanceOf(AgenticRevertError); + await expect(deposit(beneficiary, BigInt(1))).rejects.toBeInstanceOf( + AgenticRevertError + ); }); it('the decoded native terms carry the pins and caps as stored', async () => { const { rules } = await owner.agentic.wallet(wallet).rules.list(); expect(rules[0].rule).toMatchObject({ - pins: [{ offset: 4, expected: `0x${'0'.repeat(24)}${beneficiary.slice(2).toLowerCase()}` }], + pins: [ + { + offset: 4, + expected: `0x${'0'.repeat(24)}${beneficiary + .slice(2) + .toLowerCase()}`, + }, + ], amount: { offset: 36, maxPerCall: BigInt(10), maxTotal: BigInt(15) }, maxValuePerCall: BigInt(1000), }); @@ -141,7 +187,14 @@ describe('AGW advanced paths against real e704d5b contracts', () => { describe('stale-spend replacement race', () => { it('an agent spend between the read and inclusion reverts the whole replacement atomically', async () => { const created = await owner.agentic.create('race', { - rules: [{ agent: agentAddr, target: h.addresses.target, selector: 'increment()', validUntil: (await chainNow(h)) + 3600 }], + rules: [ + { + agent: agentAddr, + target: h.addresses.target, + selector: 'increment()', + validUntil: (await chainNow(h)) + 3600, + }, + ], }); const wallet = created.wallet; const oldId = created.rulesIds[0]; @@ -160,14 +213,27 @@ describe('AGW advanced paths against real e704d5b contracts', () => { await ( await agent.universal.sendTransaction({ to: h.addresses.target, - data: encodeFunctionData({ abi: TARGET_ABI, functionName: 'increment' }), + data: encodeFunctionData({ + abi: TARGET_ABI, + functionName: 'increment', + }), }) ).wait(); return rt.execute(params, options); }, }; const err = await updateRules(racing, h.generation, wallet, { - rules: [{ rulesId: oldId, rule: { agent: agentAddr, target: h.addresses.target, selector: 'increment()', validUntil: (await chainNow(h)) + 3600 } }], + rules: [ + { + rulesId: oldId, + rule: { + agent: agentAddr, + target: h.addresses.target, + selector: 'increment()', + validUntil: (await chainNow(h)) + 3600, + }, + }, + ], }).catch((e) => e); expect(err).toBeInstanceOf(AgenticRevertError); // Nothing changed: the old rule is still the only enabled rule and no checkpoint landed. @@ -186,18 +252,28 @@ describe('AGW advanced paths against real e704d5b contracts', () => { describe('expiry', () => { it('an expired-but-enabled rule still identifies the agent; the send fails on-chain', async () => { const created = await owner.agentic.create('expiring', { - rules: [{ agent: agentAddr, target: h.addresses.target, selector: 'increment()', validUntil: (await chainNow(h)) + 600 }], + rules: [ + { + agent: agentAddr, + target: h.addresses.target, + selector: 'increment()', + validUntil: (await chainNow(h)) + 600, + }, + ], }); await warp(h, 1200); const agent = await h.client(1, { agenticWallet: created.wallet }); const err = await agent.universal .sendTransaction({ to: h.addresses.target, - data: encodeFunctionData({ abi: TARGET_ABI, functionName: 'increment' }), + data: encodeFunctionData({ + abi: TARGET_ABI, + functionName: 'increment', + }), }) .catch((e) => e); expect(err).toBeInstanceOf(AgenticRevertError); - expect(err.decodedError?.name).toBe("PolicyCheckReverted(RulesExpired)"); + expect(err.decodedError?.name).toBe('PolicyCheckReverted(RulesExpired)'); }); }); @@ -209,8 +285,18 @@ describe('AGW advanced paths against real e704d5b contracts', () => { const err = await owner.agentic .create('partial', { rules: [ - { agent: agentAddr, target: h.addresses.target, selector: 'increment()', validUntil: (await chainNow(h)) + 3600 }, - { agent: h.wallets[3].account!.address, target: h.addresses.target, selector: 'increment()', validUntil: skewedValidUntil }, + { + agent: agentAddr, + target: h.addresses.target, + selector: 'increment()', + validUntil: (await chainNow(h)) + 3600, + }, + { + agent: h.wallets[3].account!.address, + target: h.addresses.target, + selector: 'increment()', + validUntil: skewedValidUntil, + }, ], }) .catch((e) => e); @@ -221,7 +307,12 @@ describe('AGW advanced paths against real e704d5b contracts', () => { expect(err.details.confirmedHashes.length).toBeGreaterThanOrEqual(2); const wallet = err.details.wallet as Address; const added = await owner.agentic.wallet(wallet).rules.add([ - { agent: h.wallets[3].account!.address, target: h.addresses.target, selector: 'increment()', validUntil: (await chainNow(h)) + 3600 }, + { + agent: h.wallets[3].account!.address, + target: h.addresses.target, + selector: 'increment()', + validUntil: (await chainNow(h)) + 3600, + }, ]); expect(added.rulesIds).toHaveLength(1); const { rules } = await owner.agentic.wallet(wallet).rules.list(); @@ -236,19 +327,36 @@ describe('AGW advanced paths against real e704d5b contracts', () => { functionName: 'checkpointCount', }); const added = await owner.agentic.wallet(created.wallet).rules.add([ - { agent: agentAddr, target: h.addresses.target, selector: 'increment()', validUntil: (await chainNow(h)) + 3600 }, - { agent: h.wallets[3].account!.address, target: h.addresses.target, selector: 'increment()', validUntil: (await chainNow(h)) + 3600 }, + { + agent: agentAddr, + target: h.addresses.target, + selector: 'increment()', + validUntil: (await chainNow(h)) + 3600, + }, + { + agent: h.wallets[3].account!.address, + target: h.addresses.target, + selector: 'increment()', + validUntil: (await chainNow(h)) + 3600, + }, ]); expect(added.rulesIds).toHaveLength(2); expect(added.tx.atomic).toBe(true); - const { checkpoints } = await owner.agentic.wallet(created.wallet).checkpoints({ sinceBlock: added.tx.blockNumber }); + const { checkpoints } = await owner.agentic + .wallet(created.wallet) + .checkpoints({ sinceBlock: added.tx.blockNumber }); expect(BigInt(checkpoints.length)).toBe(BigInt(4)); - expect(checkpoints.map((c) => c.kind)).toEqual(['OWNER_ACTION', 'RULES_GRANTED', 'OWNER_ACTION', 'RULES_GRANTED']); + expect(checkpoints.map((c) => c.kind)).toEqual([ + 'OWNER_ACTION', + 'RULES_GRANTED', + 'OWNER_ACTION', + 'RULES_GRANTED', + ]); expect(before).toBe(BigInt(0)); }); }); - describe('agent EVM outbound (historical single-asset terms, stub gateway)', () => { + describe('agent EVM outbound (v4 multi-asset terms, stub gateway)', () => { const SEPOLIA = CHAIN.ETHEREUM_SEPOLIA; const CEA = getAddress('0x000000000000000000000000000000000000cea1'); const destTarget = getAddress('0x00000000000000000000000000000000000d0d0d'); @@ -260,28 +368,53 @@ describe('AGW advanced paths against real e704d5b contracts', () => { let ownerAgw: PushChain; beforeAll(async () => { - token = await h.deploy(0, 'HarnessPRC20', 'HarnessFixtures.sol', [SEPOLIA, 6]); + token = await h.deploy(0, 'HarnessPRC20', 'HarnessFixtures.sol', [ + SEPOLIA, + 6, + ]); const created = await owner.agentic.create('outbound', { rules: [] }); wallet = created.wallet; await h.write(0, token, TOKEN_ABI, 'mint', [wallet, BigInt(1_000_000)]); - await h.publicClient.waitForTransactionReceipt({ hash: await fund(h, wallet, BigInt(10) ** BigInt(17)) }); - // Fixture setup (raw owner call): grant a historical single-asset universal rule. - const terms = encodeUniversalTermsE704d5b({ + await h.publicClient.waitForTransactionReceipt({ + hash: await fund(h, wallet, BigInt(10) ** BigInt(17)), + }); + // Fixture setup (raw owner call): grant a v4 multi-asset universal rule. + const terms = encodeUniversalTerms({ validUntil: (await chainNow(h)) + 3600, expectedCEA: CEA, - asset: token, - maxAmountPerCall: BigInt(1000), - maxAmountTotal: BigInt(1500), - maxPCPerCall: BigInt(10) ** BigInt(16), - allowedCalls: [{ target: destTarget, selector: '0xd09de08a', beneficiaryOffset: 0, hasBeneficiary: false, maxValue: BigInt(0) }], + assets: [ + { token: token, maxPerCall: BigInt(1000), maxTotal: BigInt(1500) }, + ], + maxGasPerCall: BigInt(10) ** BigInt(16), + allowedCalls: [ + { + target: destTarget, + selector: '0xd09de08a', + beneficiaryOffset: 0, + hasBeneficiary: false, + maxValue: BigInt(0), + }, + ], }); const session = buildSession({ validator: h.addresses.validator, agent: agentAddr, rulesPolicy: h.addresses.rulesPolicy, - actions: [{ target: h.addresses.gateway, selector: '0x77b86bec', initData: encodeEnvelope(SEPOLIA, terms) }], + actions: [ + { + target: h.addresses.gateway, + selector: '0x77b86bec', + initData: encodeEnvelope(SEPOLIA, terms), + }, + ], }); - await h.write(0, wallet, h.generation.contracts.abis.wallet as never, 'grantRules', [session]); + await h.write( + 0, + wallet, + h.generation.contracts.abis.wallet as never, + 'grantRules', + [session] + ); [rulesId] = (await h.publicClient.readContract({ address: h.addresses.engine, abi: h.generation.contracts.abis.engine, @@ -298,12 +431,13 @@ describe('AGW advanced paths against real e704d5b contracts', () => { resolveCEA: async () => ({ cea: CEA, isDeployed: false }), resolvePrc20: () => token, quoteOutbound: async (prc20, gasLimit) => { - const [, gasFee, protocolFee, , , gasLimitUsed] = (await h.publicClient.readContract({ - address: h.addresses.universalCore, - abi: CORE_ABI, - functionName: 'getOutboundTxGasAndFees', - args: [prc20, gasLimit], - })) as readonly [Address, bigint, bigint, bigint, string, bigint]; + const [, gasFee, protocolFee, , , gasLimitUsed] = + (await h.publicClient.readContract({ + address: h.addresses.universalCore, + abi: CORE_ABI, + functionName: 'getOutboundTxGasAndFees', + args: [prc20, gasLimit], + })) as readonly [Address, bigint, bigint, bigint, string, bigint]; return { protocolFee, nativeValueForGas: gasFee, gasLimitUsed }; }, }; @@ -316,7 +450,15 @@ describe('AGW advanced paths against real e704d5b contracts', () => { agenticSend(runtime, ctx, { to: { address: destTarget, chain: SEPOLIA }, data: [{ to: destTarget, value: BigInt(0), data: '0xd09de08a' }], - funds: { amount, token: { symbol: 'USDC', decimals: 6, address: token, mechanism: 'approve' } }, + funds: { + amount, + token: { + symbol: 'USDC', + decimals: 6, + address: token, + mechanism: 'approve', + }, + }, }); it('fails before signing when the owner has not set a gateway allowance', async () => { @@ -329,34 +471,105 @@ describe('AGW advanced paths against real e704d5b contracts', () => { await ( await ownerAgw.universal.sendTransaction({ to: token, - data: encodeFunctionData({ abi: TOKEN_ABI, functionName: 'approve', args: [h.addresses.gateway, BigInt(300)] }), + data: encodeFunctionData({ + abi: TOKEN_ABI, + functionName: 'approve', + args: [h.addresses.gateway, BigInt(300)], + }), }) ).wait(); - const supplyBefore = (await h.publicClient.readContract({ address: token, abi: TOKEN_ABI, functionName: 'totalSupply' })) as bigint; + const supplyBefore = (await h.publicClient.readContract({ + address: token, + abi: TOKEN_ABI, + functionName: 'totalSupply', + })) as bigint; const tx = await send(BigInt(100)); - const receipt = await h.publicClient.waitForTransactionReceipt({ hash: tx.hash as Hex }); + const receipt = await h.publicClient.waitForTransactionReceipt({ + hash: tx.hash as Hex, + }); expect(receipt.status).toBe('success'); - expect(await h.publicClient.readContract({ address: h.addresses.gateway, abi: GATEWAY_ABI, functionName: 'lastSender' })).toBe(wallet); - expect(await h.publicClient.readContract({ address: token, abi: TOKEN_ABI, functionName: 'totalSupply' })).toBe(supplyBefore - BigInt(100)); - expect(await h.publicClient.readContract({ address: token, abi: TOKEN_ABI, functionName: 'allowance', args: [wallet, h.addresses.gateway] })).toBe(BigInt(200)); + expect( + await h.publicClient.readContract({ + address: h.addresses.gateway, + abi: GATEWAY_ABI, + functionName: 'lastSender', + }) + ).toBe(wallet); + expect( + await h.publicClient.readContract({ + address: token, + abi: TOKEN_ABI, + functionName: 'totalSupply', + }) + ).toBe(supplyBefore - BigInt(100)); + expect( + await h.publicClient.readContract({ + address: token, + abi: TOKEN_ABI, + functionName: 'allowance', + args: [wallet, h.addresses.gateway], + }) + ).toBe(BigInt(200)); // The request the wallet sent: empty recipient, wallet refund, nonzero gas cap, multicall payload. const payload = `0x2cc2842d${encodeAbiParameters( - [{ type: 'tuple[]', components: [{ name: 'to', type: 'address' }, { name: 'value', type: 'uint256' }, { name: 'data', type: 'bytes' }] }], + [ + { + type: 'tuple[]', + components: [ + { name: 'to', type: 'address' }, + { name: 'value', type: 'uint256' }, + { name: 'data', type: 'bytes' }, + ], + }, + ], [[{ to: destTarget, value: BigInt(0), data: '0xd09de08a' }]] ).slice(2)}` as Hex; const expected = keccak256( encodeAbiParameters( - [{ type: 'tuple', components: [ - { name: 'recipient', type: 'bytes' }, { name: 'token', type: 'address' }, { name: 'amount', type: 'uint256' }, - { name: 'gasLimit', type: 'uint256' }, { name: 'gasPrice', type: 'uint256' }, { name: 'maxPCForGas', type: 'uint256' }, - { name: 'payload', type: 'bytes' }, { name: 'revertRecipient', type: 'address' } ] }], - [{ recipient: '0x', token, amount: BigInt(100), gasLimit: BigInt(200_000), gasPrice: BigInt(0), maxPCForGas: BigInt(10) ** BigInt(15), payload, revertRecipient: wallet }] + [ + { + type: 'tuple', + components: [ + { name: 'recipient', type: 'bytes' }, + { name: 'token', type: 'address' }, + { name: 'amount', type: 'uint256' }, + { name: 'gasLimit', type: 'uint256' }, + { name: 'gasPrice', type: 'uint256' }, + { name: 'maxPCForGas', type: 'uint256' }, + { name: 'payload', type: 'bytes' }, + { name: 'revertRecipient', type: 'address' }, + ], + }, + ], + [ + { + recipient: '0x', + token, + amount: BigInt(100), + gasLimit: BigInt(200_000), + gasPrice: BigInt(0), + maxPCForGas: BigInt(10) ** BigInt(15), + payload, + revertRecipient: wallet, + }, + ] ) ); - expect(await h.publicClient.readContract({ address: h.addresses.gateway, abi: GATEWAY_ABI, functionName: 'lastRequestHash' })).toBe(expected); + expect( + await h.publicClient.readContract({ + address: h.addresses.gateway, + abi: GATEWAY_ABI, + functionName: 'lastRequestHash', + }) + ).toBe(expected); expect(tx.from).toBe(wallet); expect(tx.route).toBe('UOA_TO_CEA'); - expect(tx.agentic).toMatchObject({ door: 'agent', rulesId, destinationAccount: CEA, chainNamespace: SEPOLIA }); + expect(tx.agentic).toMatchObject({ + door: 'agent', + rulesId, + destinationAccount: CEA, + chainNamespace: SEPOLIA, + }); expect(keccak256(toBytes(SEPOLIA))).toBeTruthy(); }); @@ -364,17 +577,27 @@ describe('AGW advanced paths against real e704d5b contracts', () => { await ( await ownerAgw.universal.sendTransaction({ to: token, - data: encodeFunctionData({ abi: TOKEN_ABI, functionName: 'approve', args: [h.addresses.gateway, BigInt(0)] }), + data: encodeFunctionData({ + abi: TOKEN_ABI, + functionName: 'approve', + args: [h.addresses.gateway, BigInt(0)], + }), }) ).wait(); - await expect(send(BigInt(10))).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.GATEWAY_ALLOWANCE_INSUFFICIENT }); + await expect(send(BigInt(10))).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.GATEWAY_ALLOWANCE_INSUFFICIENT, + }); }); it('a call outside the allow-list is rejected by URP on-chain', async () => { await ( await ownerAgw.universal.sendTransaction({ to: token, - data: encodeFunctionData({ abi: TOKEN_ABI, functionName: 'approve', args: [h.addresses.gateway, BigInt(50)] }), + data: encodeFunctionData({ + abi: TOKEN_ABI, + functionName: 'approve', + args: [h.addresses.gateway, BigInt(50)], + }), }) ).wait(); const err = await agenticSend(runtime, ctx, { diff --git a/packages/core/__agw-local__/agw-local-races.spec.ts b/packages/core/__agw-local__/agw-local-races.spec.ts index ad287004..bbc3c9f0 100644 --- a/packages/core/__agw-local__/agw-local-races.spec.ts +++ b/packages/core/__agw-local__/agw-local-races.spec.ts @@ -1,6 +1,6 @@ /** * Race regressions from the implementation review (plan/agw/implementation-review), - * against the real pinned e704d5b contracts on local anvil. + * against the real pinned v4 contracts on local anvil. * R1 — a concurrent creation must never let this create() grant on a wallet it * did not deploy (the deploy is index-bound through deployWalletWithSig). * R4 — an owner outbound must never restore an allowance revoked after the @@ -9,7 +9,7 @@ import { encodeFunctionData, parseAbi, type Address } from 'viem'; import { AgenticRevertError, CHAIN, type PushChain } from '../src'; import type { AgenticRuntime } from '../src/lib/agentic/runtime'; -import { e704d5b } from '../src/lib/agentic/contracts/e704d5b'; +import { v4 } from '../src/lib/agentic/contracts/v4'; import { AGENTIC_ERROR_CODE } from '../src/lib/agentic/errors'; import { startHarness, type Harness } from './harness'; @@ -18,9 +18,10 @@ const TOKEN = parseAbi([ 'function approve(address,uint256) returns (bool)', 'function allowance(address,address) view returns (uint256)', ]); -const internalsOf = (c: PushChain) => (c as unknown as { agenticRuntime: AgenticRuntime }).agenticRuntime; +const internalsOf = (c: PushChain) => + (c as unknown as { agenticRuntime: AgenticRuntime }).agenticRuntime; -describe('AGW race regressions (real e704d5b contracts)', () => { +describe('AGW race regressions (real v4 contracts)', () => { let h: Harness; let owner: PushChain; beforeAll(async () => { @@ -37,20 +38,42 @@ describe('AGW race regressions (real e704d5b contracts)', () => { const execute = rt.execute; rt.execute = async (params, options) => { rt.execute = execute; - await h.write(0, h.addresses.factory, h.generation.contracts.abis.factory, 'deployWallet', ['other-purpose-wallet']); + await h.write( + 0, + h.addresses.factory, + h.generation.contracts.abis.factory, + 'deployWallet', + ['other-purpose-wallet'] + ); return execute(params, options); }; const err = await owner.agentic .create('intended', { - rules: [{ agent: h.wallets[1].account!.address, target: h.addresses.target, selector: 'increment()', validUntil: Number((await h.publicClient.getBlock()).timestamp) + 3600 }], + rules: [ + { + agent: h.wallets[1].account!.address, + target: h.addresses.target, + selector: 'increment()', + validUntil: + Number((await h.publicClient.getBlock()).timestamp) + 3600, + }, + ], }) .catch((e) => e) .finally(() => { rt.execute = execute; }); - expect(err).toMatchObject({ code: AGENTIC_ERROR_CODE.INDEX_RACE, details: { committed: false } }); + expect(err).toMatchObject({ + code: AGENTIC_ERROR_CODE.INDEX_RACE, + details: { committed: false }, + }); const permissionIds = (address: Address) => - h.publicClient.readContract({ address: h.addresses.engine, abi: h.generation.contracts.abis.engine, functionName: 'getPermissionIDs', args: [address] }); + h.publicClient.readContract({ + address: h.addresses.engine, + abi: h.generation.contracts.abis.engine, + functionName: 'getPermissionIDs', + args: [address], + }); expect(await permissionIds(expected.address)).toHaveLength(0); const next = await owner.agentic.derive(); expect(next.index).toBe(expected.index + 1); @@ -61,33 +84,83 @@ describe('AGW race regressions (real e704d5b contracts)', () => { }); it('R4 an allowance revoked after the SDK read it stays revoked; the outbound fails on-chain', async () => { - const { wallet } = await owner.agentic.create('allowance-race', { rules: [] }); - const token = await h.deploy(0, 'HarnessPRC20', 'HarnessFixtures.sol', [CHAIN.ETHEREUM_SEPOLIA, 6]); + const { wallet } = await owner.agentic.create('allowance-race', { + rules: [], + }); + const token = await h.deploy(0, 'HarnessPRC20', 'HarnessFixtures.sol', [ + CHAIN.ETHEREUM_SEPOLIA, + 6, + ]); await h.write(0, token, TOKEN, 'mint', [wallet, BigInt(1000)]); await h.publicClient.waitForTransactionReceipt({ - hash: await h.wallets[0].sendTransaction({ to: wallet, value: BigInt(10) ** BigInt(17), account: h.wallets[0].account!, chain: h.wallets[0].chain }), + hash: await h.wallets[0].sendTransaction({ + to: wallet, + value: BigInt(10) ** BigInt(17), + account: h.wallets[0].account!, + chain: h.wallets[0].chain, + }), }); const c = await h.client(0, { agenticWallet: wallet }); - await (await c.universal.sendTransaction({ to: token, data: encodeFunctionData({ abi: TOKEN, functionName: 'approve', args: [h.addresses.gateway, BigInt(50)] }) })).wait(); + await ( + await c.universal.sendTransaction({ + to: token, + data: encodeFunctionData({ + abi: TOKEN, + functionName: 'approve', + args: [h.addresses.gateway, BigInt(50)], + }), + }) + ).wait(); const rt = internalsOf(c); rt.resolvePrc20 = () => token; - rt.resolveCEA = async () => ({ cea: h.wallets[2].account!.address, isDeployed: true }); - rt.quoteOutbound = async () => ({ protocolFee: BigInt(10) ** BigInt(14), nativeValueForGas: BigInt(10) ** BigInt(15), gasLimitUsed: BigInt(200000) }); + rt.resolveCEA = async () => ({ + cea: h.wallets[2].account!.address, + isDeployed: true, + }); + rt.quoteOutbound = async () => ({ + protocolFee: BigInt(10) ** BigInt(14), + nativeValueForGas: BigInt(10) ** BigInt(15), + gasLimitUsed: BigInt(200000), + }); const execute = rt.execute; rt.execute = async (params, options) => { rt.execute = execute; - const revoke = e704d5b.encodeExecute([{ target: token, value: BigInt(0), data: encodeFunctionData({ abi: TOKEN, functionName: 'approve', args: [h.addresses.gateway, BigInt(0)] }) }]); + const revoke = v4.encodeExecute([ + { + target: token, + value: BigInt(0), + data: encodeFunctionData({ + abi: TOKEN, + functionName: 'approve', + args: [h.addresses.gateway, BigInt(0)], + }), + }, + ]); await (await execute({ to: wallet, data: revoke })).wait(); return execute(params, options); }; const err = await c.universal - .sendTransaction({ to: { address: h.wallets[3].account!.address as Address, chain: CHAIN.ETHEREUM_SEPOLIA }, data: '0xd09de08a', funds: { amount: BigInt(10) } }) + .sendTransaction({ + to: { + address: h.wallets[3].account!.address as Address, + chain: CHAIN.ETHEREUM_SEPOLIA, + }, + data: '0xd09de08a', + funds: { amount: BigInt(10) }, + }) .catch((e) => e) .finally(() => { rt.execute = execute; }); expect(err).toBeInstanceOf(AgenticRevertError); expect(err.message).toContain('0x10bad147'); // LowAllowance() — the token refused the pull - expect(await h.publicClient.readContract({ address: token, abi: TOKEN, functionName: 'allowance', args: [wallet, h.addresses.gateway] })).toBe(BigInt(0)); + expect( + await h.publicClient.readContract({ + address: token, + abi: TOKEN, + functionName: 'allowance', + args: [wallet, h.addresses.gateway], + }) + ).toBe(BigInt(0)); }); }); diff --git a/packages/core/__agw-local__/agw-local.spec.ts b/packages/core/__agw-local__/agw-local.spec.ts index f9541e34..5a9fd2a6 100644 --- a/packages/core/__agw-local__/agw-local.spec.ts +++ b/packages/core/__agw-local__/agw-local.spec.ts @@ -1,12 +1,23 @@ import { readNativeCounters } from '../__e2e__/shared/agw-state'; /** - * Real-contract checks of the AGW SDK against the pinned e704d5b contracts on a + * Real-contract checks of the AGW SDK against the pinned v4 contracts on a * local anvil chain (see harness.ts for scope and limits). Every assertion * about authorization, atomicity, counters and checkpoints is decided by the * real contracts; the only stubbed component is the gateway. */ -import { encodeFunctionData, getAddress, parseAbi, type Address, type Hex } from 'viem'; -import { AgenticError, AgenticRevertError, CHAIN, type PushChain } from '../src'; +import { + encodeFunctionData, + getAddress, + parseAbi, + type Address, + type Hex, +} from 'viem'; +import { + AgenticError, + AgenticRevertError, + CHAIN, + type PushChain, +} from '../src'; import { AGENTIC_ERROR_CODE } from '../src/lib/agentic/errors'; import { startHarness, type Harness } from './harness'; @@ -24,7 +35,7 @@ const WALLET_ABI = parseAbi([ const inAnHour = () => Math.floor(Date.now() / 1000) + 3600; -describe('AGW SDK against real e704d5b contracts (local anvil)', () => { +describe('AGW SDK against real v4 contracts (local anvil)', () => { let h: Harness; let owner: PushChain; let ownerAddr: Address; @@ -41,9 +52,17 @@ describe('AGW SDK against real e704d5b contracts (local anvil)', () => { }); const counter = () => - h.publicClient.readContract({ address: h.addresses.target, abi: TARGET_ABI, functionName: 'counter' }); + h.publicClient.readContract({ + address: h.addresses.target, + abi: TARGET_ABI, + functionName: 'counter', + }); const checkpointCount = (wallet: Address) => - h.publicClient.readContract({ address: wallet, abi: WALLET_ABI, functionName: 'checkpointCount' }); + h.publicClient.readContract({ + address: wallet, + abi: WALLET_ABI, + functionName: 'checkpointCount', + }); it('derive() predicts slot 0 from the signer identity and matches the factory', async () => { const d = await owner.agentic.derive(); @@ -66,7 +85,13 @@ describe('AGW SDK against real e704d5b contracts (local anvil)', () => { expect(created.rulesIds).toEqual([]); expect(await h.publicClient.getBalance({ address: bare })).toBe(BigInt(0)); const info = await owner.agentic.wallet(bare).info(); - expect(info).toMatchObject({ label: 'scratch', index: 0, owner: ownerAddr, deployed: true, rulesCount: 0 }); + expect(info).toMatchObject({ + label: 'scratch', + index: 0, + owner: ownerAddr, + deployed: true, + rulesCount: 0, + }); }); let wallet: Address; @@ -74,7 +99,13 @@ describe('AGW SDK against real e704d5b contracts (local anvil)', () => { it('create with a native rule returns the receipt-confirmed ID; grant order and IDs match the contract', async () => { const created = await owner.agentic.create('ops', { rules: [ - { agent: agentAddr, target: h.addresses.target, selector: 'increment()', validUntil: inAnHour(), maxCalls: 2 }, + { + agent: agentAddr, + target: h.addresses.target, + selector: 'increment()', + validUntil: inAnHour(), + maxCalls: 2, + }, ], }); wallet = created.wallet; @@ -94,7 +125,9 @@ describe('AGW SDK against real e704d5b contracts (local anvil)', () => { it('list() returns both deployed wallets plus the next undeployed slot', async () => { const { wallets } = await owner.agentic.list(); - expect(wallets.map((w) => [w.index, w.label, w.deployed, w.rulesCount])).toEqual([ + expect( + wallets.map((w) => [w.index, w.label, w.deployed, w.rulesCount]) + ).toEqual([ [0, 'scratch', true, 0], [1, 'ops', true, 1], [2, '', false, 0], @@ -104,9 +137,20 @@ describe('AGW SDK against real e704d5b contracts (local anvil)', () => { it('rules.get / rules.list decode active terms without exposing internal spend', async () => { const rec = await owner.agentic.wallet(wallet).rules.get(rule1); expect(rec.agent).toBe(agentAddr); - expect(rec.rule).toMatchObject({ target: h.addresses.target, maxCalls: 2, maxValuePerCall: BigInt(0) }); + expect(rec.rule).toMatchObject({ + target: h.addresses.target, + maxCalls: 2, + maxValuePerCall: BigInt(0), + }); expect(rec).not.toHaveProperty('spent'); - expect(await readNativeCounters(h.publicClient, h.generation.addresses, wallet, rule1)).toEqual({ valueSpent: BigInt(0), amountSpent: BigInt(0), callsUsed: 0 }); + expect( + await readNativeCounters( + h.publicClient, + h.generation.addresses, + wallet, + rule1 + ) + ).toEqual({ valueSpent: BigInt(0), amountSpent: BigInt(0), callsUsed: 0 }); const { rules } = await owner.agentic.wallet(wallet).rules.list(); expect(rules.map((r) => r.rulesId)).toEqual([rule1]); }); @@ -115,7 +159,9 @@ describe('AGW SDK against real e704d5b contracts (local anvil)', () => { it('agent client: universal.account is the wallet, origin stays the signer, sends go through executeAsAgent', async () => { agent = await h.client(1, { agenticWallet: wallet }); expect(agent.universal.account).toBe(wallet); - expect(agent.universal.origin.address.toLowerCase()).toBe(agentAddr.toLowerCase()); + expect(agent.universal.origin.address.toLowerCase()).toBe( + agentAddr.toLowerCase() + ); const before = await counter(); const tx = await agent.universal.sendTransaction({ to: h.addresses.target, @@ -136,21 +182,36 @@ describe('AGW SDK against real e704d5b contracts (local anvil)', () => { await ( await agent.universal.sendTransaction({ to: h.addresses.target, - data: encodeFunctionData({ abi: TARGET_ABI, functionName: 'increment' }), + data: encodeFunctionData({ + abi: TARGET_ABI, + functionName: 'increment', + }), }) ).wait(); expect(await checkpointCount(wallet)).toBe(cpBefore); const rec = await owner.agentic.wallet(wallet).rules.get(rule1); expect(rec).not.toHaveProperty('spent'); - expect(await readNativeCounters(h.publicClient, h.generation.addresses, wallet, rule1)).toMatchObject({ callsUsed: 2 }); + expect( + await readNativeCounters( + h.publicClient, + h.generation.addresses, + wallet, + rule1 + ) + ).toMatchObject({ callsUsed: 2 }); const err = await agent.universal .sendTransaction({ to: h.addresses.target, - data: encodeFunctionData({ abi: TARGET_ABI, functionName: 'increment' }), + data: encodeFunctionData({ + abi: TARGET_ABI, + functionName: 'increment', + }), }) .catch((e) => e); expect(err).toBeInstanceOf(AgenticRevertError); - expect(err.decodedError?.name).toBe('PolicyCheckReverted(CallLimitReached)'); + expect(err.decodedError?.name).toBe( + 'PolicyCheckReverted(CallLimitReached)' + ); }); it('a stranger cannot initialize against the wallet', async () => { @@ -162,7 +223,10 @@ describe('AGW SDK against real e704d5b contracts (local anvil)', () => { it('owner client goes through execute and ticks one OWNER_ACTION checkpoint per call', async () => { const ownerAgw = await h.client(0, { agenticWallet: wallet }); const before = await checkpointCount(wallet); - const data = encodeFunctionData({ abi: TARGET_ABI, functionName: 'increment' }); + const data = encodeFunctionData({ + abi: TARGET_ABI, + functionName: 'increment', + }); const tx = await ownerAgw.universal.sendTransaction({ to: h.addresses.target, data: [ @@ -173,12 +237,20 @@ describe('AGW SDK against real e704d5b contracts (local anvil)', () => { await tx.wait(); expect(await checkpointCount(wallet)).toBe(before + BigInt(2)); expect(tx.agentic?.door).toBe('owner'); - const { checkpoints } = await owner.agentic.wallet(wallet).checkpoints({ sinceBlock: tx.blockNumber }); - expect(checkpoints.map((c) => c.kind)).toEqual(['OWNER_ACTION', 'OWNER_ACTION']); + const { checkpoints } = await owner.agentic + .wallet(wallet) + .checkpoints({ sinceBlock: tx.blockNumber }); + expect(checkpoints.map((c) => c.kind)).toEqual([ + 'OWNER_ACTION', + 'OWNER_ACTION', + ]); }); it('native agent arrays require an available atomic executor instead of sequential fallback', async () => { - const data = encodeFunctionData({ abi: TARGET_ABI, functionName: 'increment' }); + const data = encodeFunctionData({ + abi: TARGET_ABI, + functionName: 'increment', + }); await expect( agent.universal.sendTransaction({ to: h.addresses.target, @@ -187,7 +259,9 @@ describe('AGW SDK against real e704d5b contracts (local anvil)', () => { { to: h.addresses.target, value: BigInt(0), data }, ], }) - ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.CAPABILITY_UNAVAILABLE }); + ).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.CAPABILITY_UNAVAILABLE, + }); }); let rule2: Hex; @@ -197,14 +271,22 @@ describe('AGW SDK against real e704d5b contracts (local anvil)', () => { rules: [ { rulesId: rule1, - rule: { agent: agentAddr, target: h.addresses.target, selector: 'increment()', validUntil: inAnHour(), maxCalls: 1 }, + rule: { + agent: agentAddr, + target: h.addresses.target, + selector: 'increment()', + validUntil: inAnHour(), + maxCalls: 1, + }, }, ], }); rule2 = res.rules[0].rulesId; expect(res.rules[0].replaced).toBe(rule1); expect(await checkpointCount(wallet)).toBe(before + BigInt(5)); - const { checkpoints } = await owner.agentic.wallet(wallet).checkpoints({ sinceBlock: res.tx.blockNumber }); + const { checkpoints } = await owner.agentic + .wallet(wallet) + .checkpoints({ sinceBlock: res.tx.blockNumber }); expect(checkpoints.map((c) => c.kind)).toEqual([ 'OWNER_ACTION', 'OWNER_ACTION', @@ -214,8 +296,17 @@ describe('AGW SDK against real e704d5b contracts (local anvil)', () => { ]); const rec = await owner.agentic.wallet(wallet).rules.get(rule2); expect(rec).not.toHaveProperty('spent'); - expect(await readNativeCounters(h.publicClient, h.generation.addresses, wallet, rule2)).toMatchObject({ callsUsed: 0 }); - await expect(owner.agentic.wallet(wallet).rules.get(rule1)).rejects.toMatchObject({ + expect( + await readNativeCounters( + h.publicClient, + h.generation.addresses, + wallet, + rule2 + ) + ).toMatchObject({ callsUsed: 0 }); + await expect( + owner.agentic.wallet(wallet).rules.get(rule1) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.RULE_NOT_FOUND, }); const tx = await agent.universal.sendTransaction({ @@ -227,7 +318,9 @@ describe('AGW SDK against real e704d5b contracts (local anvil)', () => { it('full checkpoint history is contiguous and matches checkpointCount()', async () => { const { checkpoints } = await owner.agentic.wallet(wallet).checkpoints(); - expect(checkpoints.map((c) => c.seq)).toEqual(checkpoints.map((_, i) => i + 1)); + expect(checkpoints.map((c) => c.seq)).toEqual( + checkpoints.map((_, i) => i + 1) + ); expect(BigInt(checkpoints.length)).toBe(await checkpointCount(wallet)); expect(checkpoints[0].kind).toBe('RULES_GRANTED'); }); @@ -236,16 +329,23 @@ describe('AGW SDK against real e704d5b contracts (local anvil)', () => { await expect( owner.agentic.wallet(wallet).rules.revoke(undefined as unknown as Hex[]) ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.REVOKE_NEEDS_TARGET }); - await expect(owner.agentic.wallet(wallet).rules.revoke([])).rejects.toMatchObject({ + await expect( + owner.agentic.wallet(wallet).rules.revoke([]) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.REVOKE_NEEDS_TARGET, }); - await (await owner.agentic.wallet(wallet).rules.revoke({ all: true })).wait(); + await ( + await owner.agentic.wallet(wallet).rules.revoke({ all: true }) + ).wait(); const { rules } = await owner.agentic.wallet(wallet).rules.list(); expect(rules).toEqual([]); await expect( agent.universal.sendTransaction({ to: h.addresses.target, - data: encodeFunctionData({ abi: TARGET_ABI, functionName: 'increment' }), + data: encodeFunctionData({ + abi: TARGET_ABI, + functionName: 'increment', + }), }) ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.NO_RULES_FOR_CHAIN }); }); @@ -254,7 +354,12 @@ describe('AGW SDK against real e704d5b contracts (local anvil)', () => { const stranger = await h.client(2); await expect( stranger.agentic.wallet(wallet).rules.add([ - { agent: agentAddr, target: h.addresses.target, selector: 'increment()', validUntil: inAnHour() }, + { + agent: agentAddr, + target: h.addresses.target, + selector: 'increment()', + validUntil: inAnHour(), + }, ]) ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.NOT_WALLET_OWNER }); }); @@ -265,7 +370,12 @@ describe('AGW SDK against real e704d5b contracts (local anvil)', () => { expect((await ro.agentic.wallet(wallet).owner()).owner).toBe(ownerAddr); await expect( ro.agentic.wallet(wallet).rules.add([ - { agent: agentAddr, target: h.addresses.target, selector: 'increment()', validUntil: inAnHour() }, + { + agent: agentAddr, + target: h.addresses.target, + selector: 'increment()', + validUntil: inAnHour(), + }, ]) ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.READ_ONLY }); expect(() => @@ -289,16 +399,30 @@ describe('AGW SDK against real e704d5b contracts (local anvil)', () => { it('signer-level and cascade entry points are closed in agentic mode', async () => { const ownerAgw = await h.client(0, { agenticWallet: wallet }); const code = AGENTIC_ERROR_CODE.NOT_ALLOWED_IN_AGENTIC_MODE; - expect(() => ownerAgw.universal.prepareTransaction({ to: h.addresses.target, data: '0x' })).toThrow( + expect(() => + ownerAgw.universal.prepareTransaction({ + to: h.addresses.target, + data: '0x', + }) + ).toThrow(expect.objectContaining({ code })); + await expect( + ownerAgw.universal.executeTransactions([]) + ).rejects.toMatchObject({ code }); + expect(() => ownerAgw.universal.migrateCEA(CHAIN.ETHEREUM_SEPOLIA)).toThrow( expect.objectContaining({ code }) ); - await expect(ownerAgw.universal.executeTransactions([])).rejects.toMatchObject({ code }); - expect(() => ownerAgw.universal.migrateCEA(CHAIN.ETHEREUM_SEPOLIA)).toThrow(expect.objectContaining({ code })); expect(() => - ownerAgw.universal.rescueFunds({ universalTxId: `0x${'00'.repeat(32)}`, prc20: h.addresses.target }) + ownerAgw.universal.rescueFunds({ + universalTxId: `0x${'00'.repeat(32)}`, + prc20: h.addresses.target, + }) ).toThrow(expect.objectContaining({ code })); await expect( - ownerAgw.universal.sendTransaction({ to: h.addresses.target, data: '0x', payGasWith: {} }) + ownerAgw.universal.sendTransaction({ + to: h.addresses.target, + data: '0x', + payGasWith: {}, + }) ).rejects.toMatchObject({ code }); await expect( ownerAgw.universal.sendTransaction({ @@ -316,6 +440,8 @@ describe('AGW SDK against real e704d5b contracts (local anvil)', () => { }); it('errors from the agentic surface are typed', () => { - expect(new AgenticError(AGENTIC_ERROR_CODE.DUPLICATE_RULE, 'x')).toBeInstanceOf(Error); + expect( + new AgenticError(AGENTIC_ERROR_CODE.AMBIGUOUS_RULE, 'x') + ).toBeInstanceOf(Error); }); }); diff --git a/packages/core/__agw-local__/harness.ts b/packages/core/__agw-local__/harness.ts index 184b9730..93c898ff 100644 --- a/packages/core/__agw-local__/harness.ts +++ b/packages/core/__agw-local__/harness.ts @@ -2,7 +2,7 @@ * Local AGW contract harness — REVIEW ONLY. * * Starts anvil as a stand-in Push LOCALNET (chainId 9000, the SDK's - * CHAIN_INFO[PUSH_LOCALNET].chainId), deploys the REAL pinned e704d5b + * CHAIN_INFO[PUSH_LOCALNET].chainId), deploys the REAL pinned v4 * contracts (SmartSession, AgentValidator, UniversalRulesPolicy behind a * TransparentUpgradeableProxy, AGW implementation, AGWFactory behind an * ERC1967Proxy) from an isolated build prepared by @@ -41,8 +41,12 @@ import { } from '../src/lib/agentic/deployments'; export const CHAIN_ID = 9000; -export const GATEWAY_PRECOMPILE = getAddress('0x00000000000000000000000000000000000000c1'); -export const EXECUTOR_MODULE = getAddress('0x00000000000000000000000000000000000000e1'); +export const GATEWAY_PRECOMPILE = getAddress( + '0x00000000000000000000000000000000000000c1' +); +export const EXECUTOR_MODULE = getAddress( + '0x00000000000000000000000000000000000000e1' +); export const ACCOUNT_ID = 'push.agw.1.0.0'; /** Anvil's well-known development keys (public test material, not secrets). */ @@ -64,8 +68,14 @@ export function buildDir(): string { return dir; } -function artifact(dir: string, file: string, name: string): { abi: Abi; bytecode: Hex } { - const json = JSON.parse(readFileSync(join(dir, 'out', file, `${name}.json`), 'utf8')); +function artifact( + dir: string, + file: string, + name: string +): { abi: Abi; bytecode: Hex } { + const json = JSON.parse( + readFileSync(join(dir, 'out', file, `${name}.json`), 'utf8') + ); return { abi: json.abi as Abi, bytecode: json.bytecode.object as Hex }; } @@ -85,10 +95,28 @@ export interface Harness { gateway: Address; target: Address; }; - deploy(walletIndex: number, name: string, file: string, args?: readonly unknown[]): Promise
; - write(walletIndex: number, to: Address, abi: Abi, functionName: string, args: readonly unknown[], value?: bigint): Promise; - client(walletIndex: number, opts?: { agenticWallet?: Address; progressHook?: (e: unknown) => void }): Promise; - readOnlyClient(walletIndex: number, opts?: { agenticWallet?: Address }): Promise; + deploy( + walletIndex: number, + name: string, + file: string, + args?: readonly unknown[] + ): Promise
; + write( + walletIndex: number, + to: Address, + abi: Abi, + functionName: string, + args: readonly unknown[], + value?: bigint + ): Promise; + client( + walletIndex: number, + opts?: { agenticWallet?: Address; progressHook?: (e: unknown) => void } + ): Promise; + readOnlyClient( + walletIndex: number, + opts?: { agenticWallet?: Address } + ): Promise; stop(): Promise; dir: string; } @@ -108,13 +136,19 @@ async function waitForRpc(url: string, timeoutMs = 20_000): Promise { const res = await fetch(url, { method: 'POST', headers: { 'content-type': 'application/json' }, - body: JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'eth_chainId', params: [] }), + body: JSON.stringify({ + jsonrpc: '2.0', + id: 1, + method: 'eth_chainId', + params: [], + }), }); if (res.ok) return; } catch { // not yet listening } - if (Date.now() - start > timeoutMs) throw new Error(`anvil did not start at ${url}`); + if (Date.now() - start > timeoutMs) + throw new Error(`anvil did not start at ${url}`); await new Promise((r) => setTimeout(r, 200)); } } @@ -124,7 +158,15 @@ export async function startHarness(port = 18545): Promise { const rpcUrl = `http://127.0.0.1:${port}`; const anvil = spawn( 'anvil', - ['--port', String(port), '--chain-id', String(CHAIN_ID), '--hardfork', 'prague', '--silent'], + [ + '--port', + String(port), + '--chain-id', + String(CHAIN_ID), + '--hardfork', + 'prague', + '--silent', + ], { stdio: 'ignore' } ); try { @@ -135,15 +177,31 @@ export async function startHarness(port = 18545): Promise { } } -async function deployHarness(dir: string, rpcUrl: string, anvil: ChildProcess): Promise { +async function deployHarness( + dir: string, + rpcUrl: string, + anvil: ChildProcess +): Promise { await waitForRpc(rpcUrl); const chain = localChain(rpcUrl); - const publicClient = createPublicClient({ chain, transport: http(rpcUrl) }) as PublicClient; + const publicClient = createPublicClient({ + chain, + transport: http(rpcUrl), + }) as PublicClient; const wallets = DEV_KEYS.map((k) => - createWalletClient({ account: privateKeyToAccount(k), chain, transport: http(rpcUrl) }) + createWalletClient({ + account: privateKeyToAccount(k), + chain, + transport: http(rpcUrl), + }) ); - const deploy = async (walletIndex: number, name: string, file: string, args: readonly unknown[] = []) => { + const deploy = async ( + walletIndex: number, + name: string, + file: string, + args: readonly unknown[] = [] + ) => { const art = artifact(dir, file, name); const hash = await wallets[walletIndex].deployContract({ abi: art.abi, @@ -172,26 +230,80 @@ async function deployHarness(dir: string, rpcUrl: string, anvil: ChildProcess): chain, }); const receipt = await publicClient.waitForTransactionReceipt({ hash }); - if (receipt.status !== 'success') throw new Error(`${functionName} reverted`); + if (receipt.status !== 'success') + throw new Error(`${functionName} reverted`); return hash; }; const admin = wallets[0].account!.address; const engine = await deploy(0, 'SmartSession', 'SmartSession.sol'); const validator = await deploy(0, 'AgentValidator', 'AgentValidator.sol'); - const urpLogic = await deploy(0, 'UniversalRulesPolicy', 'UniversalRulesPolicy.sol'); - const urpAbi = artifact(dir, 'UniversalRulesPolicy.sol', 'UniversalRulesPolicy').abi; - const rulesPolicy = await deploy(0, 'TransparentUpgradeableProxy', 'TransparentUpgradeableProxy.sol', [ - urpLogic, - admin, - encodeFunctionData({ - abi: urpAbi, - functionName: 'initialize', - args: [GATEWAY_PRECOMPILE, EXECUTOR_MODULE, engine], - }), - ]); - const universalCore = await deploy(0, 'HarnessUniversalCore', 'HarnessFixtures.sol'); - const gatewayImpl = await deploy(0, 'HarnessGatewayPC', 'HarnessFixtures.sol', [universalCore]); + const urpLogic = await deploy( + 0, + 'UniversalRulesPolicy', + 'UniversalRulesPolicy.sol' + ); + const urpAbi = artifact( + dir, + 'UniversalRulesPolicy.sol', + 'UniversalRulesPolicy' + ).abi; + const rulesPolicy = await deploy( + 0, + 'TransparentUpgradeableProxy', + 'TransparentUpgradeableProxy.sol', + [ + urpLogic, + admin, + encodeFunctionData({ + abi: urpAbi, + functionName: 'initialize', + args: [GATEWAY_PRECOMPILE, EXECUTOR_MODULE, engine], + }), + ] + ); + const coreLogic = await deploy( + 0, + 'HarnessUniversalCore', + 'HarnessFixtures.sol' + ); + const universalCore = getAddress( + '0x00000000000000000000000000000000000000c0' + ); + await publicClient.request({ + method: 'anvil_setCode' as never, + params: [ + universalCore, + await publicClient.getCode({ address: coreLogic }), + ] as never, + }); + // The stub's storage initializers are not installed by etching code. + await publicClient.request({ + method: 'anvil_setStorageAt' as never, + params: [ + universalCore, + `0x${'00'.repeat(32)}`, + `0x${BigInt(10 ** 15) + .toString(16) + .padStart(64, '0')}`, + ] as never, + }); + await publicClient.request({ + method: 'anvil_setStorageAt' as never, + params: [ + universalCore, + `0x${'00'.repeat(31)}01`, + `0x${BigInt(10 ** 14) + .toString(16) + .padStart(64, '0')}`, + ] as never, + }); + const gatewayImpl = await deploy( + 0, + 'HarnessGatewayPC', + 'HarnessFixtures.sol', + [universalCore] + ); const gatewayCode = await publicClient.getCode({ address: gatewayImpl }); await publicClient.request({ method: 'anvil_setCode' as never, @@ -207,14 +319,18 @@ async function deployHarness(dir: string, rpcUrl: string, anvil: ChildProcess): const factoryAbi = artifact(dir, 'AGWFactory.sol', 'AGWFactory').abi; const factory = await deploy(0, 'ERC1967Proxy', 'ERC1967Proxy.sol', [ factoryLogic, - encodeFunctionData({ abi: factoryAbi, functionName: 'initialize', args: [admin, walletImplementation] }), + encodeFunctionData({ + abi: factoryAbi, + functionName: 'initialize', + args: [admin, walletImplementation], + }), ]); const target = await deploy(0, 'HarnessTarget', 'HarnessFixtures.sol'); resetAgenticGenerations(); const generation = registerAgenticGeneration({ - id: 'e704d5b', - sourceCommit: 'e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9', + id: 'v4', + sourceCommit: 'e8db74815cfbbf5389593805e464fe8d85f7f735', network: PUSH_NETWORK.LOCALNET, advertised: false, addresses: { @@ -243,12 +359,20 @@ async function deployHarness(dir: string, rpcUrl: string, anvil: ChildProcess): network: PUSH_NETWORK.LOCALNET, rpcUrls: { [CHAIN.PUSH_LOCALNET]: [rpcUrl] }, ...(opts.agenticWallet ? { agenticWallet: opts.agenticWallet } : {}), - ...(opts.progressHook ? { progressHook: opts.progressHook as never } : {}), + ...(opts.progressHook + ? { progressHook: opts.progressHook as never } + : {}), }); - const readOnlyClient = async (walletIndex: number, opts: { agenticWallet?: Address } = {}) => + const readOnlyClient = async ( + walletIndex: number, + opts: { agenticWallet?: Address } = {} + ) => PushChain.initialize( - { address: wallets[walletIndex].account!.address, chain: CHAIN.PUSH_LOCALNET }, + { + address: wallets[walletIndex].account!.address, + chain: CHAIN.PUSH_LOCALNET, + }, { network: PUSH_NETWORK.LOCALNET, rpcUrls: { [CHAIN.PUSH_LOCALNET]: [rpcUrl] }, diff --git a/packages/core/__agw-local__/svm-internals.spec.ts b/packages/core/__agw-local__/svm-internals.spec.ts new file mode 100644 index 00000000..43bc6485 --- /dev/null +++ b/packages/core/__agw-local__/svm-internals.spec.ts @@ -0,0 +1,328 @@ +/** Actual v4 SVM URP checks on Anvil. No Solana execution/TSS is simulated. */ +import { encodeFunctionData, parseAbi, type Address, type Hex } from 'viem'; +import { CHAIN } from '../src/lib/constants/enums'; +import { buildSession, encodeEnvelope } from '../src/lib/agentic/codec/session'; +import { configId } from '../src/lib/agentic/codec/ids'; +import { + encodeSvmTerms, + SvmDataPinMode, + UINT64_MAX, + type SvmTermsWire, +} from '../src/lib/agentic/codec/svm-terms'; +import { deriveAgwSvmValueAccounts } from '../src/lib/agentic/codec/svm-accounts'; +import { encodeAgwSvmPayload } from '../src/lib/agentic/execution/svm-payload'; +import { composeAgwSvmAction } from '../src/lib/agentic/execution/svm-outbound'; +import { v4, type SvmConfigRead } from '../src/lib/agentic/contracts/v4'; +import { startHarness, type Harness } from './harness'; + +const key = (b: string) => `0x${b.repeat(32)}` as Hex; +const GATEWAY_PROGRAM = key('22'), + PROGRAM = key('33'), + MINT = key('44'); +const TOKEN = parseAbi([ + 'function mint(address,uint256)', + 'function approve(address,uint256) returns (bool)', +]); +const UINT256_MAX = BigInt(2) ** BigInt(256) - BigInt(1); + +describe('internal SVM codec/payloads against actual v4 contracts', () => { + let h: Harness, token: Address; + beforeAll(async () => { + h = await startHarness(18552); + token = await h.deploy(0, 'HarnessPRC20', 'HarnessFixtures.sol', [ + CHAIN.SOLANA_DEVNET, + 9, + ]); + }); + afterAll(async () => { + await h?.stop(); + }); + async function setup( + options: { dataless?: boolean; maxAccounts?: number } = {} + ) { + const owner = await h.client(0), + created = await owner.agentic.create('svm-internal', { rules: [] }); + const wallet = created.wallet; + const derived = deriveAgwSvmValueAccounts(wallet, GATEWAY_PROGRAM, [ + { mint: MINT }, + ]); + const t: SvmTermsWire = { + ...derived, + validUntil: Math.floor(Date.now() / 1000) + 3600, + assets: [{ token, maxPerCall: UINT256_MAX, maxTotal: UINT256_MAX }], + maxGasPerCall: BigInt(10) ** BigInt(16), + programs: [ + { + program: PROGRAM, + discriminator: '0x0100000000000000', + discriminatorLen: options.dataless ? 0 : 1, + dataless: options.dataless ?? false, + maxAccounts: options.maxAccounts ?? 0, + }, + ], + pins: [ + { ruleIndex: 0, accountIndex: 0, expected: derived.expectedCEA }, + { ruleIndex: 0, accountIndex: 1, expected: derived.ceaAccounts[1] }, + ], + dataPins: options.dataless + ? [] + : [ + { + ruleIndex: 0, + fromEnd: true, + offset: 4, + offsetB: 2, + len: 2, + mode: SvmDataPinMode.RATIO_GTE_LE, + expected: key('00'), + num: BigInt(9), + den: BigInt(10), + }, + ], + }; + const session = buildSession({ + validator: h.addresses.validator, + rulesPolicy: h.addresses.rulesPolicy, + agent: h.wallets[1].account!.address, + actions: [ + { + target: h.addresses.gateway, + selector: '0x77b86bec', + initData: encodeEnvelope(CHAIN.SOLANA_DEVNET, encodeSvmTerms(t, 0)), + }, + ], + }); + await h.write(0, wallet, v4.abis.wallet, 'grantRules', [session]); + const [id] = await h.publicClient.readContract({ + address: h.addresses.engine, + abi: v4.abis.engine, + functionName: 'getPermissionIDs', + args: [wallet], + }); + const [action] = await h.publicClient.readContract({ + address: h.addresses.engine, + abi: v4.abis.engine, + functionName: 'getEnabledActions', + args: [wallet, id], + }); + const cid = configId(wallet, id, action); + const cfg = (await h.publicClient.readContract({ + address: h.addresses.rulesPolicy, + abi: v4.abis.policy, + functionName: 'getSvmConfig', + args: [cid, wallet], + })) as SvmConfigRead; + await h.publicClient.waitForTransactionReceipt({ + hash: await h.wallets[4].sendTransaction({ + to: wallet, + value: BigInt(10) ** BigInt(18), + account: h.wallets[4].account!, + chain: h.wallets[4].chain, + }), + }); + await h.write(0, token, TOKEN, 'mint', [wallet, BigInt(100)]); + await h.write(0, wallet, v4.abis.wallet, 'execute', [ + key('00'), + v4.packSingle({ + target: token, + value: BigInt(0), + data: encodeFunctionData({ + abi: TOKEN, + functionName: 'approve', + args: [h.addresses.gateway, BigInt(100)], + }), + }), + ]); + const accounts = [ + { pubkey: t.expectedCEA, isWritable: true }, + { pubkey: t.ceaAccounts[1], isWritable: true }, + ]; + const payload = encodeAgwSvmPayload( + PROGRAM, + accounts, + options.dataless ? new Uint8Array() : new Uint8Array([1, 90, 0, 100, 0]) + ); + const input = { + wallet, + gateway: h.addresses.gateway, + token, + amount: BigInt(5), + recipient: PROGRAM, + payload, + gasLimit: BigInt(200_000), + protocolFee: BigInt(10) ** BigInt(14), + maxPCForGas: BigInt(10) ** BigInt(15), + }; + const call = composeAgwSvmAction(input, cfg, 0); + const simulate = (p: Hex, recipient = PROGRAM, amount = BigInt(5)) => { + const data = encodeFunctionData({ + abi: parseAbi([ + 'function sendUniversalTxOutbound((bytes recipient,address token,uint256 amount,uint256 gasLimit,uint256 gasPrice,uint256 maxPCForGas,bytes payload,address revertRecipient) req) payable', + ]), + functionName: 'sendUniversalTxOutbound', + args: [ + { + recipient, + token, + amount, + gasLimit: BigInt(200_000), + gasPrice: BigInt(0), + maxPCForGas: input.maxPCForGas, + payload: p, + revertRecipient: wallet, + }, + ], + }); + return h.publicClient.simulateContract({ + address: wallet, + abi: v4.abis.wallet, + functionName: 'executeAsAgent', + args: [ + id, + key('00'), + v4.packSingle({ + target: h.addresses.gateway, + value: call.value, + data, + }), + ], + account: h.wallets[1].account!.address, + }); + }; + async function reject( + p: Hex, + name: string, + recipient = PROGRAM, + amount = BigInt(5) + ) { + try { + await simulate(p, recipient, amount); + throw new Error('Expected policy rejection'); + } catch (error) { + const { decodeAgenticRevert } = await import( + '../src/lib/agentic/revert' + ); + expect(decodeAgenticRevert(error)?.name).toBe( + `PolicyCheckReverted(${name})` + ); + } + } + return { + wallet, + id, + cid, + t, + cfg, + accounts, + payload, + call, + simulate, + reject, + }; + } + it('grants SDK-encoded SVM terms and preserves every field/account', async () => { + const { cfg, t } = await setup(); + expect(cfg).toMatchObject({ + initialized: true, + expectedCEA: t.expectedCEA, + gatewayProgram: t.gatewayProgram, + ceaAccounts: t.ceaAccounts, + programs: t.programs, + pins: t.pins, + dataPins: t.dataPins, + assets: [ + { + token, + maxPerCall: UINT256_MAX, + maxTotal: UINT256_MAX, + spent: BigInt(0), + }, + ], + }); + }); + it('the internal composed call passes actual S1–S18 and meters its token', async () => { + const { wallet, id, cid, call } = await setup(); + await h.write(1, wallet, v4.abis.wallet, 'executeAsAgent', [ + id, + key('00'), + v4.packSingle(call), + ]); + const cfg = await h.publicClient.readContract({ + address: h.addresses.rulesPolicy, + abi: v4.abis.policy, + functionName: 'getSvmConfig', + args: [cid, wallet], + }); + expect(cfg.assets[0].spent).toBe(BigInt(5)); + }); + it('account substitution and CEA aliasing are rejected by URP', async () => { + const s = await setup(); + await s.reject( + encodeAgwSvmPayload( + PROGRAM, + [{ ...s.accounts[0], pubkey: key('77') }, s.accounts[1]], + new Uint8Array([1, 90, 0, 100, 0]) + ), + 'SvmAccountPinMismatch' + ); + await s.reject( + encodeAgwSvmPayload( + PROGRAM, + [...s.accounts, s.accounts[0]], + new Uint8Array([1, 90, 0, 100, 0]) + ), + 'CeaAccountAtUnpinnedIndex' + ); + }); + it('relative price floor and recipient/program identity are enforced on-chain', async () => { + const s = await setup(); + await s.reject( + encodeAgwSvmPayload( + PROGRAM, + s.accounts, + new Uint8Array([1, 89, 0, 100, 0]) + ), + 'SvmDataRatioNotMet' + ); + await s.reject(s.payload, 'RecipientTargetMismatch', key('66')); + }); + it('trailing bytes, non-execute IDs and u64 overflow are rejected', async () => { + const s = await setup(); + await s.reject(`${s.payload}00`, 'MalformedSvmPayload'); + const bytes = Buffer.from(s.payload.slice(2), 'hex'); + bytes[bytes.length - 33] = 1; + await s.reject(`0x${bytes.toString('hex')}`, 'SvmInstructionNotExecute'); + await s.reject( + s.payload, + 'AmountExceedsU64', + PROGRAM, + UINT64_MAX + BigInt(1) + ); + }); + it('dataless rules accept only empty instruction data', async () => { + const s = await setup({ dataless: true }); + await expect(s.simulate(s.payload)).resolves.toBeDefined(); + await s.reject( + encodeAgwSvmPayload(PROGRAM, s.accounts, new Uint8Array([1])), + 'ProgramNotAllowed' + ); + }); + it('fixed account counts reject appended accounts and failed calls do not change spend', async () => { + const s = await setup({ maxAccounts: 2 }); + await s.reject( + encodeAgwSvmPayload( + PROGRAM, + [...s.accounts, { pubkey: key('55'), isWritable: false }], + new Uint8Array([1, 90, 0, 100, 0]) + ), + 'SvmAccountCountMismatch' + ); + const cfg = await h.publicClient.readContract({ + address: h.addresses.rulesPolicy, + abi: v4.abis.policy, + functionName: 'getSvmConfig', + args: [s.cid, s.wallet], + }); + expect(cfg.assets[0].spent).toBe(BigInt(0)); + }); +}); diff --git a/packages/core/__agw-local__/v4-multiasset.spec.ts b/packages/core/__agw-local__/v4-multiasset.spec.ts new file mode 100644 index 00000000..d5ba28af --- /dev/null +++ b/packages/core/__agw-local__/v4-multiasset.spec.ts @@ -0,0 +1,367 @@ +/** Actual v4 AGW/URP/engine. Token/core/gateway and destination lookup are local fixtures; no bridge/TSS proof. */ +import { + encodeFunctionData, + getAddress, + parseAbi, + type Address, + type Hex, +} from 'viem'; +import { CHAIN, type PushChain, type UniversalRule } from '../src'; +import type { AgenticRuntime } from '../src/lib/agentic/runtime'; +import { updateRules } from '../src/lib/agentic/management/rules-write'; +import { createWallet } from '../src/lib/agentic/management/create'; +import { configId } from '../src/lib/agentic/codec/ids'; +import { UINT256_MAX } from '../src/lib/agentic/codec/defaults'; +import { buildSession } from '../src/lib/agentic/codec/session'; +import { + encodeNativeTerms, + nativeRuleToTerms, +} from '../src/lib/agentic/codec/native'; +import { startHarness, type Harness } from './harness'; + +const TOKEN = parseAbi([ + 'function mint(address,uint256)', + 'function approve(address,uint256) returns (bool)', +]); +const CORE = parseAbi([ + 'function setGasToken(string,address)', + 'function getOutboundTxGasAndFees(address,uint256) view returns (address,uint256,uint256,uint256,string,uint256)', +]); +const CHAIN_NS = CHAIN.ETHEREUM_SEPOLIA; +const CEA = getAddress('0x000000000000000000000000000000000000cea1'); +const DEST = getAddress('0x0000000000000000000000000000000000001234'); +const internal = (c: PushChain) => + (c as unknown as { agenticRuntime: AgenticRuntime }).agenticRuntime; + +describe('v4 multi-asset SDK management and execution', () => { + let h: Harness, owner: PushChain, a: Address, b: Address; + beforeAll(async () => { + h = await startHarness(18551); + owner = await h.client(0); + a = await h.deploy(0, 'HarnessPRC20', 'HarnessFixtures.sol', [CHAIN_NS, 6]); + b = await h.deploy(0, 'HarnessPRC20', 'HarnessFixtures.sol', [ + CHAIN_NS, + 18, + ]); + await h.write(0, h.addresses.universalCore, CORE, 'setGasToken', [ + CHAIN_NS, + a, + ]); + configure(internal(owner)); + }); + afterAll(async () => { + await h?.stop(); + }); + function configure(rt: AgenticRuntime) { + // Fixture source token addresses equal fixture PRC20s; production uses the token registry. + rt.resolvePrc20 = (token) => + getAddress(typeof token === 'string' ? token : token?.address ?? a); + rt.resolveCEA = async () => ({ cea: CEA, isDeployed: false }); + rt.quoteOutbound = async (token, limit) => { + const [, nativeValueForGas, protocolFee, , , gasLimitUsed] = + await h.publicClient.readContract({ + address: h.addresses.universalCore, + abi: CORE, + functionName: 'getOutboundTxGasAndFees', + args: [token, limit], + }); + return { nativeValueForGas, protocolFee, gasLimitUsed }; + }; + } + function rule( + assets: UniversalRule['assets'] = [ + { token: a, maxPerCall: BigInt(5), maxTotal: BigInt(7) }, + { token: b, maxPerCall: BigInt(9), maxTotal: BigInt(30) }, + ] + ): UniversalRule { + return { + agent: h.wallets[1].account!.address, + chainNamespace: CHAIN_NS, + assets, + validUntil: Math.floor(Date.now() / 1000) + 3600, + maxGasPerCall: BigInt(10) ** BigInt(16), + allowedCalls: [{ target: DEST, selector: 'increment()' }], + }; + } + async function setup(input = rule()) { + const created = await owner.agentic.create('v4', { rules: [input] }); + const wallet = created.wallet, + id = created.rulesIds[0]; + await h.publicClient.waitForTransactionReceipt({ + hash: await h.wallets[4].sendTransaction({ + account: h.wallets[4].account!, + chain: h.wallets[4].chain, + to: wallet, + value: BigInt(10) ** BigInt(18), + }), + }); + for (const token of [a, b]) { + await h.write(0, token, TOKEN, 'mint', [wallet, BigInt(1000)]); + const w = await h.client(0, { agenticWallet: wallet }); + await ( + await w.universal.sendTransaction({ + to: token, + data: encodeFunctionData({ + abi: TOKEN, + functionName: 'approve', + args: [h.addresses.gateway, BigInt(1000)], + }), + }) + ).wait(); + } + const agent = await h.client(1, { agenticWallet: wallet }); + configure(internal(agent)); + const send = (token: Address, amount: bigint) => + agent.universal.sendTransaction({ + to: { address: DEST, chain: CHAIN_NS }, + funds: { + amount, + token: { + symbol: 'fixture', + decimals: 6, + address: token, + mechanism: 'approve', + }, + }, + data: [{ to: DEST, data: '0xd09de08a', value: BigInt(0) }], + }); + return { wallet, id, agent, send }; + } + async function waitPush( + tx: ReturnType + ) { + const response = await tx; + return h.publicClient.waitForTransactionReceipt({ + hash: response.hash as Hex, + }); + } + async function stored(wallet: Address, id: Hex) { + const [action] = await h.publicClient.readContract({ + address: h.addresses.engine, + abi: h.generation.contracts.abis.engine, + functionName: 'getEnabledActions', + args: [wallet, id], + }); + return h.publicClient.readContract({ + address: h.addresses.rulesPolicy, + abi: h.generation.contracts.abis.policy, + functionName: 'getConfig', + args: [configId(wallet, id, action), wallet], + }); + } + it('public create encodes two ordered assets; public get reconstructs source-token caps', async () => { + const { wallet, id } = await setup(); + expect((await stored(wallet, id)).assets.map((x) => x.token)).toEqual([ + a, + b, + ]); + expect( + (await owner.agentic.wallet(wallet).rules.get(id)).rule + ).toMatchObject({ + assets: [ + { token: a, maxPerCall: BigInt(5), maxTotal: BigInt(7) }, + { token: b, maxPerCall: BigInt(9), maxTotal: BigInt(30) }, + ], + }); + }); + it('a token from the wrong chain fails before deployment', async () => { + const wrong = await h.deploy(0, 'HarnessPRC20', 'HarnessFixtures.sol', [ + 'eip155:1', + 6, + ]); + const count = await h.publicClient.readContract({ + address: h.addresses.factory, + abi: h.generation.contracts.abis.factory, + functionName: 'walletCount', + args: [h.wallets[0].account!.address], + }); + await expect( + owner.agentic.create('wrong-chain', { + rules: [rule([{ token: wrong, maxPerCall: BigInt(1) }])], + }) + ).rejects.toMatchObject({ code: 'ASSET_CHAIN_MISMATCH' }); + expect( + await h.publicClient.readContract({ + address: h.addresses.factory, + abi: h.generation.contracts.abis.factory, + functionName: 'walletCount', + args: [h.wallets[0].account!.address], + }) + ).toBe(count); + }); + it('a same-chain registry identity mismatch fails before deployment', async () => { + const rt = internal(owner); + const resolve = rt.resolvePrc20; + rt.resolvePrc20 = () => b; + try { + await expect( + owner.agentic.create('wrong-identity', { + rules: [rule([{ token: a, maxPerCall: BigInt(1) }])], + }) + ).rejects.toMatchObject({ code: 'INVALID_RULE' }); + } finally { + rt.resolvePrc20 = resolve; + } + }); + it('both tokens execute under one rule and keep independent counters/limits', async () => { + const { wallet, id, send } = await setup(); + await waitPush(send(a, BigInt(5))); + await expect(send(a, BigInt(3))).rejects.toMatchObject({ + decodedError: { name: 'PolicyCheckReverted(TotalSpendCapExceeded)' }, + }); + await waitPush(send(b, BigInt(9))); + expect((await stored(wallet, id)).assets.map((x) => x.spent)).toEqual([ + BigInt(5), + BigInt(9), + ]); + }); + it('omitted total encodes maxUint256; explicit zero prohibits movement', async () => { + const { wallet, id, send } = await setup( + rule([ + { token: a, maxPerCall: BigInt(5) }, + { token: b, maxPerCall: BigInt(9), maxTotal: BigInt(0) }, + ]) + ); + expect((await stored(wallet, id)).assets.map((x) => x.maxTotal)).toEqual([ + UINT256_MAX, + BigInt(0), + ]); + await expect(send(b, BigInt(1))).rejects.toMatchObject({ + decodedError: { name: 'PolicyCheckReverted(TotalSpendCapExceeded)' }, + }); + expect((await stored(wallet, id)).assets[1].spent).toBe(BigInt(0)); + }); + it('empty user assets grants one zero-cap gas token and executes a call-only request', async () => { + const { wallet, id, send } = await setup(rule([])); + expect((await stored(wallet, id)).assets).toEqual([ + { + token: a, + maxPerCall: BigInt(0), + maxTotal: BigInt(0), + spent: BigInt(0), + }, + ]); + await waitPush(send(a, BigInt(0))); + await expect(send(a, BigInt(1))).rejects.toMatchObject({ + decodedError: { name: 'PolicyCheckReverted(AmountExceedsCap)' }, + }); + }); + it('public update resets both counters in one batch and records five checkpoints', async () => { + const { wallet, id, send } = await setup(); + await waitPush(send(b, BigInt(4))); + const count = await h.publicClient.readContract({ + address: wallet, + abi: h.generation.contracts.abis.wallet, + functionName: 'checkpointCount', + }); + const result = await owner.agentic + .wallet(wallet) + .rules.update({ rules: [{ rulesId: id, rule: rule() }] }); + expect( + (await stored(wallet, result.rules[0].rulesId)).assets.map((x) => x.spent) + ).toEqual([BigInt(0), BigInt(0)]); + expect( + await h.publicClient.readContract({ + address: wallet, + abi: h.generation.contracts.abis.wallet, + functionName: 'checkpointCount', + }) + ).toBe(count + BigInt(5)); + }); + it('spend on the second asset after snapshot rolls back revoke/grant and checkpoint writes', async () => { + const { wallet, id, send } = await setup(); + const base = internal(owner); + const count = await h.publicClient.readContract({ + address: wallet, + abi: h.generation.contracts.abis.wallet, + functionName: 'checkpointCount', + }); + const racing = { + ...base, + execute: async (...args: Parameters) => { + await waitPush(send(b, BigInt(1))); + return base.execute(...args); + }, + }; + await expect( + updateRules(racing, h.generation, wallet, { + rules: [{ rulesId: id, rule: rule() }], + }) + ).rejects.toMatchObject({ decodedError: { name: 'AssetSpentMismatch' } }); + expect( + await h.publicClient.readContract({ + address: h.addresses.engine, + abi: h.generation.contracts.abis.engine, + functionName: 'getPermissionIDs', + args: [wallet], + }) + ).toEqual([id]); + expect( + await h.publicClient.readContract({ + address: wallet, + abi: h.generation.contracts.abis.wallet, + functionName: 'checkpointCount', + }) + ).toBe(count); + }); + it('duplicate grants are allowed, but an ambiguous send fails before any signature', async () => { + const created = await owner.agentic.create('multiple', { + rules: [rule(), rule()], + }); + expect(new Set(created.rulesIds).size).toBe(2); + const agent = await h.client(1, { agenticWallet: created.wallet }); + await expect( + agent.universal.sendTransaction({ + to: { address: DEST, chain: CHAIN_NS }, + data: '0xd09de08a', + }) + ).rejects.toMatchObject({ code: 'AMBIGUOUS_RULE' }); + }); + it('a legacy two-field envelope is refused by the actual v4 grant path', async () => { + const bare = await owner.agentic.create('old-envelope', { rules: [] }); + const { encodeAbiParameters } = await import('viem'); + const terms = nativeRuleToTerms( + { + agent: h.wallets[1].account!.address, + target: h.addresses.target, + selector: 'increment()', + validUntil: Math.floor(Date.now() / 1000) + 3600, + }, + { nowSeconds: 0 } + ).terms; + const session = buildSession({ + validator: h.addresses.validator, + rulesPolicy: h.addresses.rulesPolicy, + agent: h.wallets[1].account!.address, + actions: [ + { + target: terms.target, + selector: terms.selector, + initData: encodeAbiParameters( + [{ type: 'string' }, { type: 'bytes' }], + ['eip155:9000', encodeNativeTerms(terms)] + ), + }, + ], + }); + await expect( + h.publicClient.simulateContract({ + address: bare.wallet, + abi: h.generation.contracts.abis.wallet, + functionName: 'grantRules', + args: [session as never], + account: h.wallets[0].account!.address, + }) + ).rejects.toMatchObject({ + cause: { data: { errorName: 'Panic', args: [BigInt(65)] } }, + }); + expect( + await h.publicClient.readContract({ + address: h.addresses.engine, + abi: h.generation.contracts.abis.engine, + functionName: 'getPermissionIDs', + args: [bare.wallet], + }) + ).toEqual([]); + }); +}); diff --git a/packages/core/__agw-local__/vectors.spec.ts b/packages/core/__agw-local__/vectors.spec.ts index 5544c23e..d8e2cf57 100644 --- a/packages/core/__agw-local__/vectors.spec.ts +++ b/packages/core/__agw-local__/vectors.spec.ts @@ -3,7 +3,7 @@ * below is computed BY THE PINNED CONTRACTS (pure engine/factory views, or * state read back after a real grant), never by the SDK under test. * - * AGW_WRITE_VECTORS=1 → (re)write src/lib/agentic/__fixtures__/e704d5b-vectors.json + * AGW_WRITE_VECTORS=1 → (re)write src/lib/agentic/__fixtures__/v4-vectors.json * otherwise → assert the committed file still matches the contracts */ import { execSync } from 'node:child_process'; @@ -12,16 +12,34 @@ import { join } from 'node:path'; import { getAddress, numberToHex, type Address, type Hex } from 'viem'; import { buildSession } from '../src/lib/agentic/codec/session'; import { agentConfig } from '../src/lib/agentic/codec/ids'; -import { encodeNativeTerms, nativeRuleToTerms } from '../src/lib/agentic/codec/native'; -import { encodeEnvelope, encodeSession } from '../src/lib/agentic/codec/session'; +import { + encodeNativeTerms, + nativeRuleToTerms, +} from '../src/lib/agentic/codec/native'; +import { + encodeEnvelope, + encodeSession, +} from '../src/lib/agentic/codec/session'; import type { NativeRule } from '../src/lib/agentic/agentic.types'; import { startHarness, type Harness } from './harness'; -const FIXTURE = join(__dirname, '..', 'src', 'lib', 'agentic', '__fixtures__', 'e704d5b-vectors.json'); +const FIXTURE = join( + __dirname, + '..', + 'src', + 'lib', + 'agentic', + '__fixtures__', + 'v4-vectors.json' +); const bigintJson = (v: unknown) => - JSON.stringify(v, (_k, x) => (typeof x === 'bigint' ? { $bigint: x.toString() } : x), 2); + JSON.stringify( + v, + (_k, x) => (typeof x === 'bigint' ? { $bigint: x.toString() } : x), + 2 + ); -describe('contract-generated AGW vectors (e704d5b)', () => { +describe('contract-generated AGW vectors (v4)', () => { let h: Harness; beforeAll(async () => { h = await startHarness(18548); @@ -43,9 +61,19 @@ describe('contract-generated AGW vectors (e704d5b)', () => { // rulesId: SmartSession.getPermissionId is pure over (validator, initData, salt). const rulesId = []; for (const agent of agents) { - for (const grantNonce of [BigInt(0), BigInt(1), BigInt(7), BigInt(2) ** BigInt(63)]) { + for (const grantNonce of [ + BigInt(0), + BigInt(1), + BigInt(7), + BigInt(2) ** BigInt(63), + ]) { const session = { - ...buildSession({ validator, agent, rulesPolicy: h.addresses.rulesPolicy, actions: [] }), + ...buildSession({ + validator, + agent, + rulesPolicy: h.addresses.rulesPolicy, + actions: [], + }), salt: numberToHex(grantNonce, { size: 32 }), }; const expected = (await pc.readContract({ @@ -54,13 +82,22 @@ describe('contract-generated AGW vectors (e704d5b)', () => { functionName: 'getPermissionId', args: [session as never], })) as Hex; - rulesId.push({ validator, agent, grantNonce, agentConfig: agentConfig(agent), expected }); + rulesId.push({ + validator, + agent, + grantNonce, + agentConfig: agentConfig(agent), + expected, + }); } } // deriveWallet: factory.predictWallet for fresh owners (index 0) and a used owner (0..next). const deriveWallet = []; - const owners: Address[] = [h.wallets[3].account!.address, getAddress('0x1111111111111111111111111111111111111111')]; + const owners: Address[] = [ + h.wallets[3].account!.address, + getAddress('0x1111111111111111111111111111111111111111'), + ]; for (const owner of owners) { const [expected] = (await pc.readContract({ address: h.addresses.factory, @@ -105,7 +142,13 @@ describe('contract-generated AGW vectors (e704d5b)', () => { validator, agent: rule.agent, rulesPolicy: h.addresses.rulesPolicy, - actions: [{ target: terms.target, selector: terms.selector, initData: encodeEnvelope(nativeChain, encodeNativeTerms(terms)) }], + actions: [ + { + target: terms.target, + selector: terms.selector, + initData: encodeEnvelope(nativeChain, encodeNativeTerms(terms)), + }, + ], }); // configId is recovered by searching what the policy accepts: the stored config is only // initialized under the correct key, so a successful read proves the derivation. @@ -116,7 +159,13 @@ describe('contract-generated AGW vectors (e704d5b)', () => { abi: gen.contracts.abis.policy, functionName: 'getNativeConfig', args: [cid, wallet], - })) as { initialized: boolean; target: Address; selector: Hex; pins: readonly { offset: number; expected: Hex }[]; amount: { offset: number } }; + })) as { + initialized: boolean; + target: Address; + selector: Hex; + pins: readonly { offset: number; expected: Hex }[]; + amount: { offset: number }; + }; const native = { rule, nativeChain, @@ -127,7 +176,10 @@ describe('contract-generated AGW vectors (e704d5b)', () => { configInitialized: stored.initialized, storedTarget: stored.target, storedSelector: stored.selector, - storedPins: stored.pins.map((p) => ({ offset: Number(p.offset), expected: p.expected })), + storedPins: stored.pins.map((p) => ({ + offset: Number(p.offset), + expected: p.expected, + })), storedAmountOffset: Number(stored.amount.offset), encodedSession: encodeSession(session), }; @@ -136,7 +188,9 @@ describe('contract-generated AGW vectors (e704d5b)', () => { provenance: { agwCommit: h.generation.sourceCommit, generatedBy: 'packages/core/__agw-local__/vectors.spec.ts', - toolchain: safe(() => execSync('forge --version').toString().split('\n')[0]), + toolchain: safe( + () => execSync('forge --version').toString().split('\n')[0] + ), chainId: await pc.getChainId(), note: 'Addresses are deterministic for a fresh anvil + the harness deploy order.', }, diff --git a/packages/core/__e2e__/agw/_manifest.ts b/packages/core/__e2e__/agw/_manifest.ts index ef7e11da..e1be5691 100644 --- a/packages/core/__e2e__/agw/_manifest.ts +++ b/packages/core/__e2e__/agw/_manifest.ts @@ -1,14 +1,12 @@ /** * AGW deployment manifest for live E2E — READ-ONLY. Loaded from the JSON file - * named by AGW_DEPLOYMENT_MANIFEST and verified against the chain before any - * test (or preflight funding) runs. No manifest exists today: no compatible - * AGW generation is deployed (plan/agw assumption A07), so the agw group - * fails this gate by design instead of reporting success. + * optionally named by AGW_DEPLOYMENT_MANIFEST, otherwise the built-in Donut v4 + * manifest. Code/wiring/version are verified before tests or preflight funding. * * Manifest shape: * { * "network": "TESTNET_DONUT", - * "generation": "e704d5b", + * "generation": "v4", * "sourceCommit": "<40-hex AGW commit>", * "startBlock": "", * "accountId": "push.agw.1.0.0", @@ -21,16 +19,21 @@ import { readFileSync } from 'node:fs'; import { getAddress, isAddress, type Address, type PublicClient } from 'viem'; import { PUSH_NETWORK } from '../../src/lib/constants/enums'; import { AgenticCapability } from '../../src/lib/agentic/capabilities'; -import { E704D5B_CAPABILITIES } from '../../src/lib/agentic/deployments'; -import { e704d5b } from '../../src/lib/agentic/contracts/e704d5b'; +import { V4_CAPABILITIES } from '../../src/lib/agentic/deployments'; +import { v4 } from '../../src/lib/agentic/contracts/v4'; +import { + DONUT_V4_ADDRESSES, + DONUT_V4_START_BLOCK, + V4_SOURCE_COMMIT, +} from '../../src/lib/agentic/contracts/donut-v4'; export const AGW_PREREQ_HINT = - 'AGW live E2E needs AGW_DEPLOYMENT_MANIFEST pointing at a verified compatible deployment (plan/agw A07). ' + - 'None exists yet; historical Donut AGW addresses implement a different ABI.'; + 'AGW live E2E needs checked v4 wiring, signer keys and testnet funding. ' + + 'The default is the checked Donut v4 manifest; custom manifests must match the v4 source.'; export interface AgwManifest { network: PUSH_NETWORK; - generation: 'e704d5b'; + generation: 'v4'; sourceCommit: string; startBlock: bigint; accountId: string; @@ -52,56 +55,107 @@ export class AgwPrerequisiteError extends Error { } } -export function loadAgwManifest(path = process.env['AGW_DEPLOYMENT_MANIFEST']): AgwManifest { - if (!path) throw new AgwPrerequisiteError('AGW_DEPLOYMENT_MANIFEST is not set'); +export function loadAgwManifest( + path = process.env['AGW_DEPLOYMENT_MANIFEST'] +): AgwManifest { + if (!path) + return { + network: PUSH_NETWORK.TESTNET_DONUT, + generation: 'v4', + sourceCommit: V4_SOURCE_COMMIT, + startBlock: DONUT_V4_START_BLOCK, + accountId: 'push.agw.1.0.0', + addresses: DONUT_V4_ADDRESSES, + capabilities: V4_CAPABILITIES, + }; let raw: Record; try { raw = JSON.parse(readFileSync(path, 'utf8')); } catch (cause) { - throw new AgwPrerequisiteError(`cannot read manifest ${path}: ${(cause as Error).message}`); + throw new AgwPrerequisiteError( + `cannot read manifest ${path}: ${(cause as Error).message}` + ); } const network = raw['network'] as PUSH_NETWORK; - if (!Object.values(PUSH_NETWORK).includes(network)) throw new AgwPrerequisiteError(`unknown network ${String(network)}`); - if (raw['generation'] !== e704d5b.id) { - throw new AgwPrerequisiteError(`generation ${String(raw['generation'])} has no SDK adapter`); + if (!Object.values(PUSH_NETWORK).includes(network)) + throw new AgwPrerequisiteError(`unknown network ${String(network)}`); + if (raw['generation'] !== v4.id) { + throw new AgwPrerequisiteError( + `generation ${String(raw['generation'])} has no SDK adapter` + ); } - if (typeof raw['sourceCommit'] !== 'string' || !/^[0-9a-f]{40}$/.test(raw['sourceCommit'])) { - throw new AgwPrerequisiteError('sourceCommit must be a 40-hex commit'); + if (raw['sourceCommit'] !== V4_SOURCE_COMMIT) { + throw new AgwPrerequisiteError( + 'sourceCommit must match the supported v4 source pin' + ); } const a = (raw['addresses'] ?? {}) as Record; - const keys = ['factory', 'walletImplementation', 'sessionEngine', 'rulesPolicy', 'sessionValidator', 'gateway'] as const; + const keys = [ + 'factory', + 'walletImplementation', + 'sessionEngine', + 'rulesPolicy', + 'sessionValidator', + 'gateway', + ] as const; for (const k of keys) { - if (!isAddress(a[k] ?? '', { strict: false })) throw new AgwPrerequisiteError(`addresses.${k} is missing or invalid`); + if (!isAddress(a[k] ?? '', { strict: false })) + throw new AgwPrerequisiteError(`addresses.${k} is missing or invalid`); } const caps = Array.isArray(raw['capabilities']) - ? new Set((raw['capabilities'] as string[]).map((c) => { - if (!(Object.values(AgenticCapability) as string[]).includes(c)) throw new AgwPrerequisiteError(`unknown capability ${c}`); - return c as AgenticCapability; - })) - : E704D5B_CAPABILITIES; + ? new Set( + (raw['capabilities'] as string[]).map((c) => { + if (!V4_CAPABILITIES.has(c as AgenticCapability)) + throw new AgwPrerequisiteError(`unknown capability ${c}`); + return c as AgenticCapability; + }) + ) + : V4_CAPABILITIES; return { network, - generation: 'e704d5b', + generation: 'v4', sourceCommit: raw['sourceCommit'], startBlock: BigInt(String(raw['startBlock'] ?? '0')), accountId: String(raw['accountId'] ?? 'push.agw.1.0.0'), - addresses: Object.fromEntries(keys.map((k) => [k, getAddress(a[k])])) as AgwManifest['addresses'], + addresses: Object.fromEntries( + keys.map((k) => [k, getAddress(a[k])]) + ) as AgwManifest['addresses'], capabilities: caps, }; } /** Read-only on-chain check that the manifest's wiring is what it claims. */ -export async function verifyAgwManifest(client: PublicClient, m: AgwManifest): Promise { - const read = (address: Address, abi: readonly unknown[], functionName: string) => - client.readContract({ address, abi: abi as never, functionName: functionName as never } as never) as Promise; +export async function verifyAgwManifest( + client: PublicClient, + m: AgwManifest +): Promise { + const read = ( + address: Address, + abi: readonly unknown[], + functionName: string + ) => + client.readContract({ + address, + abi: abi as never, + functionName: functionName as never, + } as never) as Promise; for (const [name, addr] of Object.entries(m.addresses)) { if (name === 'gateway') continue; // a precompile may report no code const code = await client.getCode({ address: addr }); - if (!code || code === '0x') throw new AgwPrerequisiteError(`${name} ${addr} has no code`); + if (!code || code === '0x') + throw new AgwPrerequisiteError(`${name} ${addr} has no code`); } - const impl = getAddress((await read(m.addresses.factory, e704d5b.abis.factory, 'walletImplementation')) as string); + const impl = getAddress( + (await read( + m.addresses.factory, + v4.abis.factory, + 'walletImplementation' + )) as string + ); if (impl !== m.addresses.walletImplementation) { - throw new AgwPrerequisiteError(`factory implementation is ${impl}, manifest says ${m.addresses.walletImplementation}`); + throw new AgwPrerequisiteError( + `factory implementation is ${impl}, manifest says ${m.addresses.walletImplementation}` + ); } const wiring: [string, Address][] = [ ['SESSION_ENGINE', m.addresses.sessionEngine], @@ -110,9 +164,22 @@ export async function verifyAgwManifest(client: PublicClient, m: AgwManifest): P ['UNIVERSAL_GATEWAY_PC', m.addresses.gateway], ]; for (const [fn, expected] of wiring) { - const got = getAddress((await read(impl, e704d5b.abis.wallet, fn)) as string); - if (got !== expected) throw new AgwPrerequisiteError(`implementation ${fn} is ${got}, manifest says ${expected}`); + const got = getAddress((await read(impl, v4.abis.wallet, fn)) as string); + if (got !== expected) + throw new AgwPrerequisiteError( + `implementation ${fn} is ${got}, manifest says ${expected}` + ); } - const accountId = (await read(impl, e704d5b.abis.wallet, 'accountId')) as string; - if (accountId !== m.accountId) throw new AgwPrerequisiteError(`implementation accountId is ${accountId}`); + const policyVersion = await read( + m.addresses.rulesPolicy, + v4.abis.policy, + 'version' + ); + if (policyVersion !== '3.1.0') + throw new AgwPrerequisiteError( + `unsupported URP version ${String(policyVersion)}` + ); + const accountId = (await read(impl, v4.abis.wallet, 'accountId')) as string; + if (accountId !== m.accountId) + throw new AgwPrerequisiteError(`implementation accountId is ${accountId}`); } diff --git a/packages/core/__e2e__/agw/create.spec.ts b/packages/core/__e2e__/agw/create.spec.ts index 7a4735b9..5e778af3 100644 --- a/packages/core/__e2e__/agw/create.spec.ts +++ b/packages/core/__e2e__/agw/create.spec.ts @@ -4,8 +4,13 @@ * it is missing so a selected run cannot pass vacuously. */ import { getAddress, type Address } from 'viem'; -import { e704d5b } from '../../src/lib/agentic/contracts/e704d5b'; -import { AGW_E2E_ENABLED, inSeconds, setupAgw, type AgwFixture } from './_fixture'; +import { v4 } from '../../src/lib/agentic/contracts/v4'; +import { + AGW_E2E_ENABLED, + inSeconds, + setupAgw, + type AgwFixture, +} from './_fixture'; const d = AGW_E2E_ENABLED ? describe : describe.skip; @@ -22,28 +27,61 @@ d('agw create', () => { expect(created.wallet).toBe(before.address); expect(created.index).toBe(before.index); expect(created.rulesIds).toEqual([]); - const factoryAbi = e704d5b.abis.factory; + const factoryAbi = v4.abis.factory; const [ownerOf, indexOf, balance] = await Promise.all([ - f.push.readContract({ address: f.manifest.addresses.factory, abi: factoryAbi, functionName: 'ownerOf', args: [created.wallet] }), - f.push.readContract({ address: f.manifest.addresses.factory, abi: factoryAbi, functionName: 'indexOf', args: [created.wallet] }), + f.push.readContract({ + address: f.manifest.addresses.factory, + abi: factoryAbi, + functionName: 'ownerOf', + args: [created.wallet], + }), + f.push.readContract({ + address: f.manifest.addresses.factory, + abi: factoryAbi, + functionName: 'indexOf', + args: [created.wallet], + }), f.push.getBalance({ address: created.wallet }), ]); expect(getAddress(ownerOf as Address)).toBe(f.ownerAddress); expect(Number(indexOf)).toBe(created.index); expect(balance).toBe(BigInt(0)); const info = await f.owner.agentic.wallet(created.wallet).info(); - expect(info).toMatchObject({ label: 'e2e-bare', deployed: true, rulesCount: 0, owner: f.ownerAddress }); - f.evidence('create-bare', { wallet: created.wallet, index: created.index, tx: created.tx.hash, block: created.tx.blockNumber }); + expect(info).toMatchObject({ + label: 'e2e-bare', + deployed: true, + rulesCount: 0, + owner: f.ownerAddress, + }); + f.evidence('create-bare', { + wallet: created.wallet, + index: created.index, + tx: created.tx.hash, + block: created.tx.blockNumber, + }); }); it('2. wallet with a native rule returns the receipt-confirmed rule ID', async () => { const created = await f.owner.agentic.create('e2e-rules', { - rules: [{ agent: f.agentAddress, target: f.ownerAddress, selector: 'value-only', validUntil: inSeconds(3600), maxValuePerCall: BigInt(1) }], + rules: [ + { + agent: f.agentAddress, + target: f.ownerAddress, + selector: 'value-only', + validUntil: inSeconds(3600), + maxValuePerCall: BigInt(1), + }, + ], }); expect(created.rulesIds).toHaveLength(1); const { rules } = await f.owner.agentic.wallet(created.wallet).rules.list(); expect(rules.map((r) => r.rulesId)).toEqual(created.rulesIds); expect(rules[0].agent).toBe(getAddress(f.agentAddress)); - f.evidence('create-with-rule', { wallet: created.wallet, rulesIds: created.rulesIds, tx: created.tx.hash, atomic: created.tx.atomic }); + f.evidence('create-with-rule', { + wallet: created.wallet, + rulesIds: created.rulesIds, + tx: created.tx.hash, + atomic: created.tx.atomic, + }); }); }); diff --git a/packages/core/__e2e__/agw/lifecycle.spec.ts b/packages/core/__e2e__/agw/lifecycle.spec.ts index 5997f40f..492143ff 100644 --- a/packages/core/__e2e__/agw/lifecycle.spec.ts +++ b/packages/core/__e2e__/agw/lifecycle.spec.ts @@ -5,10 +5,15 @@ import { readNativeCounters } from '@e2e/shared/agw-state'; * The stale-spend race (intervening agent spend) is verified against the * real contracts in the local harness; it cannot be timed reliably live. */ -import { e704d5b } from '../../src/lib/agentic/contracts/e704d5b'; +import { v4 } from '../../src/lib/agentic/contracts/v4'; import { getAddress, parseEther, type Address, type Hex } from 'viem'; import { AGENTIC_ERROR_CODE } from '../../src/lib/agentic/errors'; -import { AGW_E2E_ENABLED, inSeconds, setupAgw, type AgwFixture } from './_fixture'; +import { + AGW_E2E_ENABLED, + inSeconds, + setupAgw, + type AgwFixture, +} from './_fixture'; const d = AGW_E2E_ENABLED ? describe : describe.skip; @@ -26,49 +31,97 @@ d('agw lifecycle', () => { maxValueTotal: maxValuePerCall * BigInt(10), }); const count = () => - f.push.readContract({ address: wallet, abi: e704d5b.abis.wallet, functionName: 'checkpointCount' }) as Promise; + f.push.readContract({ + address: wallet, + abi: v4.abis.wallet, + functionName: 'checkpointCount', + }) as Promise; beforeAll(async () => { f = await setupAgw(); - wallet = (await f.owner.agentic.create('e2e-lifecycle', { rules: [] })).wallet; + wallet = (await f.owner.agentic.create('e2e-lifecycle', { rules: [] })) + .wallet; await f.fundPC(wallet, parseEther('0.01')); }, 300_000); afterAll(() => f?.teardown()); it('1. rules.add grants with one RULES_GRANTED checkpoint', async () => { const before = await count(); - const added = await f.owner.agentic.wallet(wallet).rules.add([rule(BigInt(1000))]); + const added = await f.owner.agentic + .wallet(wallet) + .rules.add([rule(BigInt(1000))]); original = added.rulesIds[0]; expect(await count()).toBe(before + BigInt(1)); - const { checkpoints } = await f.owner.agentic.wallet(wallet).checkpoints({ sinceBlock: added.tx.blockNumber }); - expect(checkpoints.at(-1)).toMatchObject({ kind: 'RULES_GRANTED', ref: original }); + const { checkpoints } = await f.owner.agentic + .wallet(wallet) + .checkpoints({ sinceBlock: added.tx.blockNumber }); + expect(checkpoints.at(-1)).toMatchObject({ + kind: 'RULES_GRANTED', + ref: original, + }); }); it('2. rules.update: old ID disabled, new ID usable with reset counters, five checkpoint ticks', async () => { const agent = await f.agent(wallet); - await (await agent.universal.sendTransaction({ to: sink, value: BigInt(10) })).wait(); - const spentBefore = await readNativeCounters(f.push, f.manifest.addresses, wallet, original); - expect(spentBefore).toMatchObject({ kind: 'native', valueSpent: BigInt(10), callsUsed: 1 }); + await ( + await agent.universal.sendTransaction({ to: sink, value: BigInt(10) }) + ).wait(); + const spentBefore = await readNativeCounters( + f.push, + f.manifest.addresses, + wallet, + original + ); + expect(spentBefore).toMatchObject({ + valueSpent: BigInt(10), + callsUsed: 1, + }); const before = await count(); - const res = await f.owner.agentic.wallet(wallet).rules.update({ rules: [{ rulesId: original, rule: rule(BigInt(2000)) }] }); + const res = await f.owner.agentic.wallet(wallet).rules.update({ + rules: [{ rulesId: original, rule: rule(BigInt(2000)) }], + }); expect(await count()).toBe(before + BigInt(5)); const replacement = res.rules[0].rulesId; expect(res.rules[0].replaced).toBe(original); - expect(await readNativeCounters(f.push, f.manifest.addresses, wallet, replacement)).toMatchObject({ valueSpent: BigInt(0), callsUsed: 0 }); - await expect(f.owner.agentic.wallet(wallet).rules.get(original)).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.RULE_NOT_FOUND }); - const tx = await agent.universal.sendTransaction({ to: sink, value: BigInt(1500) }); + expect( + await readNativeCounters( + f.push, + f.manifest.addresses, + wallet, + replacement + ) + ).toMatchObject({ valueSpent: BigInt(0), callsUsed: 0 }); + await expect( + f.owner.agentic.wallet(wallet).rules.get(original) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.RULE_NOT_FOUND }); + const tx = await agent.universal.sendTransaction({ + to: sink, + value: BigInt(1500), + }); expect(tx.agentic?.rulesId).toBe(replacement); - f.evidence('rules-update', { wallet, original, replacement, tx: res.tx.hash, checkpointDelta: 5 }); + f.evidence('rules-update', { + wallet, + original, + replacement, + tx: res.tx.hash, + checkpointDelta: 5, + }); }); it('3. checkpoint history is contiguous and matches checkpointCount()', async () => { const { checkpoints } = await f.owner.agentic.wallet(wallet).checkpoints(); - expect(checkpoints.map((c) => c.seq)).toEqual(checkpoints.map((_, i) => i + 1)); + expect(checkpoints.map((c) => c.seq)).toEqual( + checkpoints.map((_, i) => i + 1) + ); expect(BigInt(checkpoints.length)).toBe(await count()); }); it('4. revoke({ all: true }) leaves no enabled rules', async () => { - await (await f.owner.agentic.wallet(wallet).rules.revoke({ all: true })).wait(); - expect((await f.owner.agentic.wallet(wallet).rules.list()).rules).toEqual([]); + await ( + await f.owner.agentic.wallet(wallet).rules.revoke({ all: true }) + ).wait(); + expect((await f.owner.agentic.wallet(wallet).rules.list()).rules).toEqual( + [] + ); }); }); diff --git a/packages/core/__e2e__/agw/multi-asset-svm.spec.ts b/packages/core/__e2e__/agw/multi-asset-svm.spec.ts index 89ece828..f7a9e281 100644 --- a/packages/core/__e2e__/agw/multi-asset-svm.spec.ts +++ b/packages/core/__e2e__/agw/multi-asset-svm.spec.ts @@ -1,21 +1,12 @@ -/** - * Scenario 11 — PENDING SPECIFICATION, not tests. These need artifacts that - * do not exist yet; they are recorded as `it.todo` (reported as todo, never as - * passes) and are not registered in the CI manifest. - * - * - Multi-asset universal rules: A05 (Harsh H4.2, Zaryab Z1.1/Z1.2) — wire - * format, per-token counters and expected-spend assertion ABI + vectors. - * - SVM destinations: A05/A07 + Harsh H4.4 — public rule shape, terms and - * payload fixtures, deployed capability; integrator obligations 19–23. - */ +/** SVM public mapping/cluster acceptance remains pending; wire structs are delivered. */ const d = process.env['AGW_E2E'] === '1' ? describe : describe.skip; -d('agw pending multi-asset and svm', () => { - it.todo('multi-asset: per-token maxPerCall/maxTotal enforced independently, in each token’s units'); - it.todo('multi-asset: omitted maxTotal is unlimited, explicit zero is zero'); - it.todo('multi-asset: duplicate assets rejected; empty assets[] routes call-only outbounds'); - it.todo('multi-asset: rules.update asserts every old-rule asset total atomically'); - it.todo('svm: wallet CEA PDA / token accounts derived from the wallet and registry gateway'); - it.todo('svm: program/discriminator allow-list and account/data pins enforced on a real destination'); +d('agw pending svm', () => { + it.todo( + 'svm: wallet CEA PDA / token accounts derived from the wallet and registry gateway' + ); + it.todo( + 'svm: program/discriminator allow-list and account/data pins enforced on a real destination' + ); it.todo('svm: aggregator substitution and ratio floors rejected'); }); diff --git a/packages/core/__e2e__/agw/universal-evm.spec.ts b/packages/core/__e2e__/agw/universal-evm.spec.ts index 253e34a7..57b5dff2 100644 --- a/packages/core/__e2e__/agw/universal-evm.spec.ts +++ b/packages/core/__e2e__/agw/universal-evm.spec.ts @@ -2,33 +2,44 @@ * Scenarios 7 and 8 — positive-amount EVM universal execution from the * wallet, and destination failure classification. * - * SETUP NOTE: the public UniversalRule (assets[]) has no matching wire format - * yet (A05), so the universal rule is granted here as fixture setup through - * the owner's ordinary client with the generation's historical single-asset - * terms. The behaviour under test — the agent's sendTransaction, the gateway - * pull/burn, the AGW's CEA executing on Sepolia, receipts and replay — goes - * through public SDK methods only. + * Rules are created through the public v4 UniversalRule SDK path. Destination + * receipt/replay checks remain opt-in funded live tests. * * creditRevert accounting is inert on the current executor (gap G07): a * destination revert after URP passed still counts the spend. */ -import { createPublicClient, encodeFunctionData, erc20Abi, http, parseEther, type Address, type Hex } from 'viem'; +import { + createPublicClient, + encodeFunctionData, + erc20Abi, + fallback, + http, + parseEther, + type Address, + type Hex, +} from 'viem'; import { sepolia } from 'viem/chains'; import { CHAIN } from '../../src/lib/constants/enums'; +import { CHAIN_INFO } from '../../src/lib/constants/chain'; import { MOVEABLE_TOKEN_CONSTANTS } from '../../src/lib/constants/tokens'; import { getCEAAddress } from '../../src/lib/orchestrator/cea-utils'; import { getNativePRC20ForChain } from '../../src/lib/orchestrator/internals/helpers'; -import { e704d5b } from '../../src/lib/agentic/contracts/e704d5b'; -import { buildSession, encodeEnvelope } from '../../src/lib/agentic/codec/session'; -import { encodeUniversalTermsE704d5b } from '../../src/lib/agentic/codec/historical/e704d5b-universal'; +import { v4 } from '../../src/lib/agentic/contracts/v4'; import { EVM_CHAIN_FIXTURES } from '@e2e/shared/chain-fixtures'; import { COUNTER_ABI } from '@e2e/shared/outbound-helpers'; import { verifyExternalTransaction } from '@e2e/shared/external-tx-verifier'; -import { AGW_E2E_ENABLED, evmClient, inSeconds, setupAgw, type AgwFixture } from './_fixture'; +import { + AGW_E2E_ENABLED, + evmClient, + inSeconds, + setupAgw, + type AgwFixture, +} from './_fixture'; const d = AGW_E2E_ENABLED ? describe : describe.skip; const SEPOLIA = CHAIN.ETHEREUM_SEPOLIA; -const counter = EVM_CHAIN_FIXTURES.find((x) => x.chain === SEPOLIA)!.contracts.counter as Address; +const counter = EVM_CHAIN_FIXTURES.find((x) => x.chain === SEPOLIA)!.contracts + .counter as Address; const INCREMENT = '0xd09de08a' as Hex; const MISSING = '0xdeadbeef' as Hex; // not implemented by the counter → destination revert const AMOUNT = BigInt(10) ** BigInt(12); // 0.000001 pETH @@ -43,66 +54,81 @@ d('agw universal evm', () => { beforeAll(async () => { f = await setupAgw(); - wallet = (await f.owner.agentic.create('e2e-universal', { rules: [] })).wallet; - token = getNativePRC20ForChain(SEPOLIA, f.manifest.network); - cea = (await getCEAAddress(wallet, SEPOLIA)).cea as Address; - // Fixture: historical single-asset universal grant (see header). - const session = buildSession({ - validator: f.manifest.addresses.sessionValidator, - agent: f.agentAddress, - rulesPolicy: f.manifest.addresses.rulesPolicy, - actions: [ + const created = await f.owner.agentic.create('e2e-universal', { + rules: [ { - target: f.manifest.addresses.gateway, - selector: '0x77b86bec', - initData: encodeEnvelope( - SEPOLIA, - encodeUniversalTermsE704d5b({ - validUntil: inSeconds(3600), - expectedCEA: cea, - asset: token, - maxAmountPerCall: AMOUNT * BigInt(2), - maxAmountTotal: AMOUNT * BigInt(10), - maxPCPerCall: MAX_PC, - allowedCalls: [ - { target: counter, selector: INCREMENT, beneficiaryOffset: 0, hasBeneficiary: false, maxValue: BigInt(0) }, - { target: counter, selector: MISSING, beneficiaryOffset: 0, hasBeneficiary: false, maxValue: BigInt(0) }, - ], - }) - ), + agent: f.agentAddress, + chainNamespace: SEPOLIA, + assets: [ + { + token: MOVEABLE_TOKEN_CONSTANTS.ETHEREUM_SEPOLIA.ETH, + maxPerCall: AMOUNT * BigInt(2), + maxTotal: AMOUNT * BigInt(10), + }, + ], + validUntil: inSeconds(3600), + maxGasPerCall: MAX_PC, + allowedCalls: [ + { target: counter, selector: INCREMENT }, + { target: counter, selector: MISSING }, + ], }, ], }); - await (await f.owner.universal.sendTransaction({ to: wallet, data: e704d5b.encodeGrantRules(session) })).wait(); - [rulesId] = (await f.push.readContract({ - address: f.manifest.addresses.sessionEngine, - abi: e704d5b.abis.engine, - functionName: 'getPermissionIDs', - args: [wallet], - })) as Hex[]; + wallet = created.wallet; + rulesId = created.rulesIds[0]; + token = getNativePRC20ForChain(SEPOLIA, f.manifest.network); + cea = (await getCEAAddress(wallet, SEPOLIA)).cea as Address; // Separate funding: wallet PC for outbound fees and pETH to burn. await f.fundPC(wallet, MAX_PC + parseEther('1')); await ( await f.owner.universal.sendTransaction({ to: token, - data: encodeFunctionData({ abi: erc20Abi, functionName: 'transfer', args: [wallet, AMOUNT * BigInt(3)] }), + data: encodeFunctionData({ + abi: erc20Abi, + functionName: 'transfer', + args: [wallet, AMOUNT * BigInt(3)], + }), }) ).wait(); // Bounded allowance through the owner door. - const ownerAgw = await evmClient(process.env['PUSH_PRIVATE_KEY'] as Hex, CHAIN.PUSH_TESTNET_DONUT, f.manifest.network, wallet); + const ownerAgw = await evmClient( + process.env['PUSH_PRIVATE_KEY'] as Hex, + CHAIN.PUSH_TESTNET_DONUT, + f.manifest.network, + wallet + ); await ( await ownerAgw.universal.sendTransaction({ to: token, - data: encodeFunctionData({ abi: erc20Abi, functionName: 'approve', args: [f.manifest.addresses.gateway, AMOUNT * BigInt(2)] }), + data: encodeFunctionData({ + abi: erc20Abi, + functionName: 'approve', + args: [f.manifest.addresses.gateway, AMOUNT * BigInt(2)], + }), }) ).wait(); }, 900_000); afterAll(() => f?.teardown()); it('1. positive-amount outbound: allowance pull/burn, the wallet CEA executes on Sepolia, receipts and replay identity', async () => { - const sep = createPublicClient({ chain: sepolia, transport: http() }); - const countBefore = (await sep.readContract({ address: counter, abi: COUNTER_ABI, functionName: 'count' })) as bigint; - const balBefore = await f.push.readContract({ address: token, abi: erc20Abi, functionName: 'balanceOf', args: [wallet] }); + const sep = createPublicClient({ + chain: sepolia, + transport: fallback( + CHAIN_INFO[SEPOLIA].defaultRPC.map((url) => http(url)) + ), + }); + const countBefore = (await sep.readContract({ + address: counter, + abi: COUNTER_ABI, + functionName: 'count', + })) as bigint; + const balBefore = await f.push.readContract({ + address: token, + abi: erc20Abi, + functionName: 'balanceOf', + args: [wallet], + }); const agent = await f.agent(wallet); const ceaBefore = await sep.getBalance({ address: cea }); // Explicit call array: the bridged ETH lands in the wallet's CEA and the @@ -111,32 +137,73 @@ d('agw universal evm', () => { const tx = await agent.universal.sendTransaction({ to: { address: counter, chain: SEPOLIA }, data: [{ to: counter, value: BigInt(0), data: INCREMENT }], - funds: { amount: AMOUNT, token: MOVEABLE_TOKEN_CONSTANTS.ETHEREUM_SEPOLIA.ETH }, + funds: { + amount: AMOUNT, + token: MOVEABLE_TOKEN_CONSTANTS.ETHEREUM_SEPOLIA.ETH, + }, }); expect(tx).toMatchObject({ from: wallet, route: 'UOA_TO_CEA' }); - expect(tx.agentic).toMatchObject({ door: 'agent', rulesId, destinationAccount: cea }); + expect(tx.agentic).toMatchObject({ + door: 'agent', + rulesId, + destinationAccount: cea, + }); const receipt = await tx.wait({ outboundTimeoutMs: 600_000 }); expect(receipt.status).toBe(1); expect(receipt.from).toBe(wallet); expect(receipt.externalTxHash).toBeTruthy(); await verifyExternalTransaction(receipt.externalTxHash as string, SEPOLIA); - expect(await f.push.readContract({ address: token, abi: erc20Abi, functionName: 'balanceOf', args: [wallet] })).toBe(balBefore - AMOUNT); - expect(await f.push.readContract({ address: token, abi: erc20Abi, functionName: 'allowance', args: [wallet, f.manifest.addresses.gateway] })).toBe(AMOUNT); - expect((await sep.readContract({ address: counter, abi: COUNTER_ABI, functionName: 'count' })) as bigint).toBeGreaterThan(countBefore); + expect( + await f.push.readContract({ + address: token, + abi: erc20Abi, + functionName: 'balanceOf', + args: [wallet], + }) + ).toBe(balBefore - AMOUNT); + expect( + await f.push.readContract({ + address: token, + abi: erc20Abi, + functionName: 'allowance', + args: [wallet, f.manifest.addresses.gateway], + }) + ).toBe(AMOUNT); + expect( + (await sep.readContract({ + address: counter, + abi: COUNTER_ABI, + functionName: 'count', + })) as bigint + ).toBeGreaterThan(countBefore); // Independent destination check: the wallet's own CEA received the bridged amount. expect(await sep.getBalance({ address: cea })).toBe(ceaBefore + AMOUNT); const replay = await f.owner.universal.trackTransaction(tx.hash); expect(replay.from).toBe(wallet); expect(replay.agentic).toMatchObject({ door: 'agent', rulesId }); - f.evidence('universal-outbound', { wallet, cea, rulesId, pushTx: tx.hash, externalTx: receipt.externalTxHash, amount: AMOUNT }); + f.evidence('universal-outbound', { + wallet, + cea, + rulesId, + pushTx: tx.hash, + externalTx: receipt.externalTxHash, + amount: AMOUNT, + }); }, 900_000); it('2. destination revert is classified on the receipt; the Push leg succeeded', async () => { const agent = await f.agent(wallet); - const tx = await agent.universal.sendTransaction({ to: { address: counter, chain: SEPOLIA }, data: MISSING }); + const tx = await agent.universal.sendTransaction({ + to: { address: counter, chain: SEPOLIA }, + data: MISSING, + }); const receipt = await tx.wait({ outboundTimeoutMs: 600_000 }); expect(receipt.status).toBe(1); expect(receipt.externalStatus).toMatch(/fail|revert/i); - f.evidence('universal-destination-revert', { wallet, pushTx: tx.hash, externalStatus: receipt.externalStatus }); + f.evidence('universal-destination-revert', { + wallet, + pushTx: tx.hash, + externalStatus: receipt.externalStatus, + }); }, 900_000); }); diff --git a/packages/core/__e2e__/agw/v4-multiasset.spec.ts b/packages/core/__e2e__/agw/v4-multiasset.spec.ts new file mode 100644 index 00000000..1d673b1c --- /dev/null +++ b/packages/core/__e2e__/agw/v4-multiasset.spec.ts @@ -0,0 +1,137 @@ +/** Opt-in funded Donut acceptance. Nothing in this file runs in unit/local validation. */ +import { parseEther } from 'viem'; +import { CHAIN } from '../../src/lib/constants/enums'; +import { MOVEABLE_TOKEN_CONSTANTS } from '../../src/lib/constants/tokens'; +import { v4 } from '../../src/lib/agentic/contracts/v4'; +import { EVM_CHAIN_FIXTURES } from '@e2e/shared/chain-fixtures'; +import { verifyExternalTransaction } from '@e2e/shared/external-tx-verifier'; +import { + AGW_E2E_ENABLED, + inSeconds, + setupAgw, + type AgwFixture, +} from './_fixture'; + +const d = AGW_E2E_ENABLED ? describe : describe.skip; +const chain = CHAIN.ETHEREUM_SEPOLIA; +const counter = EVM_CHAIN_FIXTURES.find((x) => x.chain === chain)!.contracts + .counter as `0x${string}`; + +d('agw v4 multi-asset', () => { + let f: AgwFixture; + beforeAll(async () => { + f = await setupAgw(); + }); + afterAll(() => f?.teardown()); + it('1. public create reads and replaces an ordered two-token rule', async () => { + const rule = { + agent: f.agentAddress, + chainNamespace: chain, + validUntil: inSeconds(3600), + maxGasPerCall: parseEther('20'), + assets: [ + { + token: MOVEABLE_TOKEN_CONSTANTS.ETHEREUM_SEPOLIA.ETH, + maxPerCall: BigInt(1000), + }, + { + token: MOVEABLE_TOKEN_CONSTANTS.ETHEREUM_SEPOLIA.USDC, + maxPerCall: BigInt(10), + maxTotal: BigInt(100), + }, + ], + allowedCalls: [{ target: counter, selector: 'increment()' as const }], + }; + const created = await f.owner.agentic.create('v4-two-token', { + rules: [rule], + }); + const w = f.owner.agentic.wallet(created.wallet); + const before = await w.rules.get(created.rulesIds[0]); + expect(before.rule).toMatchObject({ + assets: [ + { + maxPerCall: BigInt(1000), + maxTotal: BigInt(2) ** BigInt(256) - BigInt(1), + }, + { maxPerCall: BigInt(10), maxTotal: BigInt(100) }, + ], + }); + expect(before).not.toHaveProperty('spent'); + const count = await f.push.readContract({ + address: created.wallet, + abi: v4.abis.wallet, + functionName: 'checkpointCount', + }); + const replacement = await w.rules.update({ + rules: [{ rulesId: created.rulesIds[0], rule }], + }); + expect( + await f.push.readContract({ + address: created.wallet, + abi: v4.abis.wallet, + functionName: 'checkpointCount', + }) + ).toBe(count + BigInt(5)); + expect((await w.rules.list()).rules.map((x) => x.rulesId)).toEqual([ + replacement.rules[0].rulesId, + ]); + f.evidence('v4-two-token-replacement', { + wallet: created.wallet, + oldId: created.rulesIds[0], + newId: replacement.rules[0].rulesId, + txHash: replacement.tx.hash, + }); + }); + it('2. empty user assets routes a call-only outbound with zero token spend', async () => { + const created = await f.owner.agentic.create('v4-call-only', { + rules: [ + { + agent: f.agentAddress, + chainNamespace: chain, + assets: [], + validUntil: inSeconds(3600), + maxGasPerCall: parseEther('20'), + allowedCalls: [{ target: counter, selector: 'increment()' }], + }, + ], + }); + const record = await f.owner.agentic + .wallet(created.wallet) + .rules.get(created.rulesIds[0]); + expect(record.rule).toMatchObject({ + assets: [{ maxPerCall: BigInt(0), maxTotal: BigInt(0) }], + }); + await f.fundPC(created.wallet, parseEther('21')); + const agent = await f.agent(created.wallet); + const tx = await agent.universal.sendTransaction({ + to: { address: counter, chain }, + data: '0xd09de08a', + }); + const receipt = await tx.wait({ outboundTimeoutMs: 600_000 }); + expect(receipt.status).toBe(1); + expect(receipt.externalTxHash).toBeTruthy(); + await verifyExternalTransaction(receipt.externalTxHash as string, chain); + const [action] = await f.push.readContract({ + address: f.manifest.addresses.sessionEngine, + abi: v4.abis.engine, + functionName: 'getEnabledActions', + args: [created.wallet, created.rulesIds[0]], + }); + const { configId } = await import('../../src/lib/agentic/codec/ids'); + const cfg = await f.push.readContract({ + address: f.manifest.addresses.rulesPolicy, + abi: v4.abis.policy, + functionName: 'getConfig', + args: [ + configId(created.wallet, created.rulesIds[0], action), + created.wallet, + ], + }); + expect(cfg.assets.map((x) => x.spent)).toEqual([BigInt(0)]); + f.evidence('v4-call-only', { + wallet: created.wallet, + pushTx: tx.hash, + externalTx: receipt.externalTxHash, + }); + }, 900_000); +}); diff --git a/packages/core/__e2e__/ci/run.ts b/packages/core/__e2e__/ci/run.ts index 25174e0a..9dcd111c 100644 --- a/packages/core/__e2e__/ci/run.ts +++ b/packages/core/__e2e__/ci/run.ts @@ -9,7 +9,7 @@ * svm-r1, svm-r2r3, pc20, push, cross-chain, read, * known-fail, agw * (`all` excludes known-fail and agw — ask for them by name; - * agw needs AGW_DEPLOYMENT_MANIFEST, see __e2e__/agw/_manifest.ts) + * agw uses the checked Donut v4 manifest by default, see __e2e__/agw/_manifest.ts) * --list Print the selection and the jest argv, run nothing * --verify Check every `grep` against the real spec titles and exit * non-zero if any fragment matches 0 or >1 tests in its file @@ -57,7 +57,8 @@ function classify(prefix: string): 'describe' | 'it' | null { if (/\?[\s\S]*\b(it|test)\b[\s\S]*\)$/.test(p)) return 'it'; const m = p.match(/([A-Za-z_$][\w$]*)(?:\.(skip|only|failing|concurrent))?$/); if (!m) return null; - if (/^(describe|d|dWrapper|xdescribe|fdescribe)$/.test(m[1])) return 'describe'; + if (/^(describe|d|dWrapper|xdescribe|fdescribe)$/.test(m[1])) + return 'describe'; if (/^(it|test|xit|fit|itWrapper|itIf)$/.test(m[1])) return 'it'; return null; } @@ -85,7 +86,13 @@ function titlesOf(specPath: string): string[] { const depth = depthAt[at]; while (stack.length && stack[stack.length - 1].depth >= depth) stack.pop(); if (kind === 'describe') stack.push({ title: m[2], depth }); - else titles.push(stack.map((s) => s.title).concat(m[2]).join(' ')); + else + titles.push( + stack + .map((s) => s.title) + .concat(m[2]) + .join(' ') + ); } return titles; } @@ -160,13 +167,17 @@ if (has('verify')) { bad++; } else { for (const h of hits) seen.set(h, (seen.get(h) ?? []).concat(s.id)); - console.log(`✓ ${s.id.padEnd(32)} ${hits.length} test${hits.length > 1 ? 's' : ''}`); + console.log( + `✓ ${s.id.padEnd(32)} ${hits.length} test${hits.length > 1 ? 's' : ''}` + ); } } const dupes = [...seen.entries()].filter(([, ids]) => ids.length > 1); for (const [title, ids] of dupes) { - console.error(`✗ overlapping fragments — "${title}" claimed by ${ids.join(', ')}`); + console.error( + `✗ overlapping fragments — "${title}" claimed by ${ids.join(', ')}` + ); bad++; } @@ -195,7 +206,9 @@ if (has('verify')) { `\n${selected.length} scenarios, ${files.length} spec files, ${seen.size} distinct tests.` ); if (bad) { - console.error(`\n${bad} problem(s). The manifest has drifted from the specs.`); + console.error( + `\n${bad} problem(s). The manifest has drifted from the specs.` + ); process.exit(1); } console.log('Manifest is consistent with the specs.'); @@ -204,7 +217,8 @@ if (has('verify')) { if (has('list')) { const byGroup = new Map(); - for (const s of selected) byGroup.set(s.group, (byGroup.get(s.group) ?? []).concat(s)); + for (const s of selected) + byGroup.set(s.group, (byGroup.get(s.group) ?? []).concat(s)); for (const g of GROUPS) { const rows = byGroup.get(g); if (!rows) continue; @@ -216,8 +230,14 @@ if (has('list')) { console.log(` ${s.id.padEnd(32)} ${cost || '(free)'}`); } } - console.log(`\n${selected.length} scenarios across ${files.length} spec files.`); - console.log(`\nnpx ${jestArgs.map((a) => (/[\s|()]/.test(a) ? JSON.stringify(a) : a)).join(' ')}`); + console.log( + `\n${selected.length} scenarios across ${files.length} spec files.` + ); + console.log( + `\nnpx ${jestArgs + .map((a) => (/[\s|()]/.test(a) ? JSON.stringify(a) : a)) + .join(' ')}` + ); process.exit(0); } @@ -227,7 +247,9 @@ if (has('list')) { fs.mkdirSync(LOG_DIR, { recursive: true }); -console.log(`Running ${selected.length} scenarios (group: ${group}) across ${files.length} spec files.\n`); +console.log( + `Running ${selected.length} scenarios (group: ${group}) across ${files.length} spec files.\n` +); const result = spawnSync('npx', jestArgs, { cwd: CORE_ROOT, @@ -279,7 +301,9 @@ function writeSummary(): void { const skipped = all.length - passed - failed; // Skipped rows are the tests jest loaded but `-t` filtered out — noise here. - const shown = all.filter((a) => a.status !== 'pending' && a.status !== 'skipped'); + const shown = all.filter( + (a) => a.status !== 'pending' && a.status !== 'skipped' + ); const lines = [ `## E2E — group \`${group}\``, diff --git a/packages/core/__e2e__/ci/suite.ts b/packages/core/__e2e__/ci/suite.ts index 624f9c47..cafc9ff5 100644 --- a/packages/core/__e2e__/ci/suite.ts +++ b/packages/core/__e2e__/ci/suite.ts @@ -623,8 +623,11 @@ export const SCENARIOS: Scenario[] = [ note: 'prepareRead → simulateRead → sendTransaction → trackRead → value == Sepolia balance at pin.', }, { - id: 'read-canonical-registry', group: 'read', file: F.readRegistry, - grep: 'read state › canonical registry', needs: { masterPC: '0.2' }, + id: 'read-canonical-registry', + group: 'read', + file: F.readRegistry, + grep: 'read state › canonical registry', + needs: { masterPC: '0.2' }, note: 'Callback-free read plus a second pin: verifies per-request storage, stable-key latestResult and settlement.', }, { @@ -681,16 +684,25 @@ export const SCENARIOS: Scenario[] = [ note: 'Funds a fresh wallet with 0.5 PC, as the docs prompt will.', }, { - id: 'read-docs-evm-balance', group: 'read', file: F.readPlaygrounds, - grep: 'docs-examples › 13-read-state playgrounds universal_read_evm_balance', needs: { masterPC: '0.1' }, + id: 'read-docs-evm-balance', + group: 'read', + file: F.readPlaygrounds, + grep: 'docs-examples › 13-read-state playgrounds universal_read_evm_balance', + needs: { masterPC: '0.1' }, }, { - id: 'read-docs-batch', group: 'read', file: F.readPlaygrounds, - grep: 'docs-examples › 13-read-state playgrounds universal_read_batch', needs: { masterPC: '0.1' }, + id: 'read-docs-batch', + group: 'read', + file: F.readPlaygrounds, + grep: 'docs-examples › 13-read-state playgrounds universal_read_batch', + needs: { masterPC: '0.1' }, }, { - id: 'read-docs-resume', group: 'read', file: F.readPlaygrounds, - grep: 'docs-examples › 13-read-state playgrounds universal_read_resume', needs: { masterPC: '0.1' }, + id: 'read-docs-resume', + group: 'read', + file: F.readPlaygrounds, + grep: 'docs-examples › 13-read-state playgrounds universal_read_resume', + needs: { masterPC: '0.1' }, note: 'Read-only resume (own request ID, predefined request ID, tx hash); seeds a request if the balance example was not selected.', }, { @@ -710,37 +722,55 @@ export const SCENARIOS: Scenario[] = [ note: 'Same batch through the UEA — one atomic tx.', }, { - id: 'read-app-batch-recovery', group: 'read', file: F.readBatch, + id: 'read-app-batch-recovery', + group: 'read', + file: F.readBatch, grep: 'read state › custom app batch recovers the committed read', needs: { masterPC: '0.1' }, note: 'Force sequential wallet execution; recover the first read after the second request fails.', }, { - id: 'read-api-token', group: 'read', file: F.readApi, - grep: 'read state › public API coverage ERC20 shorthand', needs: { masterPC: '0.1' }, + id: 'read-api-token', + group: 'read', + file: F.readApi, + grep: 'read state › public API coverage ERC20 shorthand', + needs: { masterPC: '0.1' }, }, { - id: 'read-api-mixed-outcomes', group: 'read', file: F.readApi, - grep: 'read state › public API coverage mixed consensus outcomes', needs: { masterPC: '0.3' }, + id: 'read-api-mixed-outcomes', + group: 'read', + file: F.readApi, + grep: 'read state › public API coverage mixed consensus outcomes', + needs: { masterPC: '0.3' }, }, { - id: 'read-svm-token-auto', group: 'read', file: F.readSvmIdl, + id: 'read-svm-token-auto', + group: 'read', + file: F.readSvmIdl, grep: 'read state › Solana automatic token and IDL account reads detects the mint program', needs: { masterPC: '0.1' }, }, { - id: 'read-svm-idl', group: 'read', file: F.readSvmIdl, + id: 'read-svm-idl', + group: 'read', + file: F.readSvmIdl, grep: 'read state › Solana automatic token and IDL account reads decodes a real Anchor account', needs: { masterPC: '0.1' }, }, { - id: 'read-evm-any-mutability', group: 'read', file: F.readMutability, - grep: 'read state › EVM nonpayable and payable functions', needs: { masterPC: '0.1' }, + id: 'read-evm-any-mutability', + group: 'read', + file: F.readMutability, + grep: 'read state › EVM nonpayable and payable functions', + needs: { masterPC: '0.1' }, note: 'QuoterV2 (nonpayable) + Multicall3.aggregate (payable) simulated at the pinned block.', }, { - id: 'read-svm-raw', group: 'read', file: F.readSvmRaw, - grep: 'read state › SVM raw account', needs: { masterPC: '0.1' }, + id: 'read-svm-raw', + group: 'read', + file: F.readSvmRaw, + grep: 'read state › SVM raw account', + needs: { masterPC: '0.1' }, }, // --------------------------------------------------------------------------- @@ -803,14 +833,20 @@ export const SCENARIOS: Scenario[] = [ env: { AGW_E2E: '1' }, }, { - id: 'agw-native-batch', group: 'agw', file: '__e2e__/agw/native-batch.spec.ts', + id: 'agw-native-batch', + group: 'agw', + file: '__e2e__/agw/native-batch.spec.ts', grep: 'agw native batch 1\\. sender-preserving atomic', - needs: { masterPC: '2' }, env: { AGW_E2E: '1' }, + needs: { masterPC: '2' }, + env: { AGW_E2E: '1' }, }, { - id: 'agw-native-batch-rollback', group: 'agw', file: '__e2e__/agw/native-batch.spec.ts', + id: 'agw-native-batch-rollback', + group: 'agw', + file: '__e2e__/agw/native-batch.spec.ts', grep: 'agw native batch 2\\. a later policy failure', - needs: { masterPC: '2' }, env: { AGW_E2E: '1' }, + needs: { masterPC: '2' }, + env: { AGW_E2E: '1' }, }, { id: 'agw-native-agent', @@ -900,6 +936,22 @@ export const SCENARIOS: Scenario[] = [ needs: { masterPC: '25', masterPETH: '0.00001' }, env: { AGW_E2E: '1' }, }, + { + id: 'agw-v4-multi-asset', + group: 'agw', + file: '__e2e__/agw/v4-multiasset.spec.ts', + grep: 'agw v4 multi-asset 1\\. public create', + needs: { masterPC: '2' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-v4-call-only', + group: 'agw', + file: '__e2e__/agw/v4-multiasset.spec.ts', + grep: 'agw v4 multi-asset 2\\. empty user assets', + needs: { masterPC: '25' }, + env: { AGW_E2E: '1' }, + }, { id: 'agw-universal-dest-revert', group: 'agw', @@ -956,8 +1008,10 @@ export const SCENARIOS: Scenario[] = [ */ export function scenariosFor(group: string | undefined): Scenario[] { if (!group || group === 'all') { - // `agw` is opt-in until a verified AGW deployment exists (plan/agw A07). - return SCENARIOS.filter((s) => s.group !== 'known-fail' && s.group !== 'agw'); + // AGW stays opt-in: scenarios create/fund fresh wallets and consume testnet funds. + return SCENARIOS.filter( + (s) => s.group !== 'known-fail' && s.group !== 'agw' + ); } if (!(GROUPS as readonly string[]).includes(group)) { throw new Error( @@ -973,7 +1027,10 @@ export function aggregateNeeds( ): Partial> { const total: Partial> = {}; for (const s of scenarios) { - for (const [asset, amount] of Object.entries(s.needs) as [Asset, string][]) { + for (const [asset, amount] of Object.entries(s.needs) as [ + Asset, + string + ][]) { total[asset] = (total[asset] ?? 0) + Number(amount); } } diff --git a/packages/core/__e2e__/shared/agw-state.ts b/packages/core/__e2e__/shared/agw-state.ts index df4e0ec2..54033f7f 100644 --- a/packages/core/__e2e__/shared/agw-state.ts +++ b/packages/core/__e2e__/shared/agw-state.ts @@ -1,6 +1,6 @@ /** Independent contract-state assertions for AGW tests; never part of the public SDK. */ import type { Address, Hex, PublicClient } from 'viem'; -import { e704d5b } from '../../src/lib/agentic/contracts/e704d5b'; +import { v4 } from '../../src/lib/agentic/contracts/v4'; import { configId } from '../../src/lib/agentic/codec/ids'; export async function readNativeCounters( @@ -11,7 +11,7 @@ export async function readNativeCounters( ) { const actions = await client.readContract({ address: addresses.sessionEngine, - abi: e704d5b.abis.engine, + abi: v4.abis.engine, functionName: 'getEnabledActions', args: [wallet, rulesId], }); @@ -19,7 +19,7 @@ export async function readNativeCounters( throw new Error('Native counter fixture expects one action'); const cfg = await client.readContract({ address: addresses.rulesPolicy, - abi: e704d5b.abis.policy, + abi: v4.abis.policy, functionName: 'getNativeConfig', args: [configId(wallet, rulesId, actions[0]), wallet], }); diff --git a/packages/core/jest.agw-local.config.ts b/packages/core/jest.agw-local.config.ts index cf6748f6..fb2a6321 100644 --- a/packages/core/jest.agw-local.config.ts +++ b/packages/core/jest.agw-local.config.ts @@ -1,6 +1,6 @@ /** * Local AGW contract harness (review-only). Runs the SDK against the real - * pinned e704d5b contracts on anvil. Requires Foundry and AGW_LOCAL_DIR from + * pinned v4 contracts on anvil. Requires Foundry and AGW_LOCAL_DIR from * scripts/agw-local/prepare.sh. Never part of the unit or E2E runs. * * AGW_LOCAL_DIR=$(packages/core/scripts/agw-local/prepare.sh | tail -1) \ @@ -11,7 +11,10 @@ export default { preset: '../../jest.preset.js', testEnvironment: 'node', transform: { - '^.+\\.[tj]s$': ['ts-jest', { tsconfig: '/tsconfig.agw-local.json' }], + '^.+\\.[tj]s$': [ + 'ts-jest', + { tsconfig: '/tsconfig.agw-local.json' }, + ], }, moduleFileExtensions: ['ts', 'js', 'html'], testTimeout: 120000, diff --git a/packages/core/scripts/agw-local/contracts/HarnessFixtures.sol b/packages/core/scripts/agw-local/contracts/HarnessFixtures.sol index 0a72a91b..e349cb18 100644 --- a/packages/core/scripts/agw-local/contracts/HarnessFixtures.sol +++ b/packages/core/scripts/agw-local/contracts/HarnessFixtures.sol @@ -10,6 +10,13 @@ pragma solidity 0.8.26; /// SOURCE_CHAIN_NAMESPACE view URP interrogates at universal grant. contract HarnessPRC20 { string public SOURCE_CHAIN_NAMESPACE; + function SOURCE_TOKEN_ADDRESS() external view returns (string memory) { + bytes memory chars = "0123456789abcdef"; + bytes memory out = new bytes(42); out[0] = "0"; out[1] = "x"; + uint160 v = uint160(address(this)); + for (uint256 i; i < 40; ++i) out[41-i] = chars[(v >> (4*i)) & 15]; + return string(out); + } uint8 public immutable decimals; mapping(address => uint256) public balanceOf; mapping(address => mapping(address => uint256)) public allowance; @@ -71,6 +78,8 @@ contract HarnessPRC20 { contract HarnessUniversalCore { uint256 public gasFee = 1e15; uint256 public protocolFee = 1e14; + mapping(string => address) public gasTokenPRC20ByChainNamespace; + function setGasToken(string calldata chain, address token) external { gasTokenPRC20ByChainNamespace[chain] = token; } function getOutboundTxGasAndFees(address prc20, uint256 gasLimit) external diff --git a/packages/core/scripts/agw-local/gen-abi.mjs b/packages/core/scripts/agw-local/gen-abi.mjs index e51f6866..f663e3c7 100644 --- a/packages/core/scripts/agw-local/gen-abi.mjs +++ b/packages/core/scripts/agw-local/gen-abi.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -// Regenerates packages/core/src/lib/agentic/contracts/abi/e704d5b/*.ts from the -// pinned ABI evidence in plan/agw/research/validation-e704d5b/abi/. The source +// Regenerates packages/core/src/lib/agentic/contracts/abi/v4/*.ts from the +// pinned ABI evidence in plan/agw/research/deployment-review-2026-10-06/abis/. The source // JSON is the reviewed artifact set; this script only re-serialises it as // `as const` TypeScript so viem can infer types. Run from the repo root: // node packages/core/scripts/agw-local/gen-abi.mjs @@ -11,14 +11,24 @@ import { fileURLToPath } from 'node:url'; const here = dirname(fileURLToPath(import.meta.url)); const repo = resolve(here, '../../../..'); -const src = join(repo, 'plan/agw/research/validation-e704d5b/abi'); -const dst = join(repo, 'packages/core/src/lib/agentic/contracts/abi/e704d5b'); -const PIN = 'e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9'; +const src = join(repo, 'plan/agw/research/deployment-review-2026-10-06/abis'); +const dst = join(repo, 'packages/core/src/lib/agentic/contracts/abi/v4'); +const PIN = 'e8db74815cfbbf5389593805e464fe8d85f7f735'; +const sourceNames = { + AGW: 'wallet', + AGWFactory: 'factory', + UniversalRulesPolicy: 'policy', + SmartSession: 'engine', + AgentValidator: 'validator', +}; const files = { AGW: ['AGW_ABI', 'agw.ts'], AGWFactory: ['AGW_FACTORY_ABI', 'agw-factory.ts'], - UniversalRulesPolicy: ['UNIVERSAL_RULES_POLICY_ABI', 'universal-rules-policy.ts'], + UniversalRulesPolicy: [ + 'UNIVERSAL_RULES_POLICY_ABI', + 'universal-rules-policy.ts', + ], SmartSession: ['SMART_SESSION_ABI', 'smart-session.ts'], AgentValidator: ['AGENT_VALIDATOR_ABI', 'agent-validator.ts'], }; @@ -26,23 +36,27 @@ const files = { mkdirSync(dst, { recursive: true }); const exports = []; for (const [name, [constName, file]] of Object.entries(files)) { - const raw = readFileSync(join(src, `${name}.json`)); + const raw = readFileSync(join(src, `${sourceNames[name]}.json`)); const sha = createHash('sha256').update(raw).digest('hex'); - const abi = JSON.parse(raw.toString()).filter((e) => e.type !== 'constructor'); + const abi = JSON.parse(raw.toString()).filter( + (e) => e.type !== 'constructor' + ); const body = `// GENERATED by packages/core/scripts/agw-local/gen-abi.mjs — do not edit.\n` + - `// Source: plan/agw/research/validation-e704d5b/abi/${name}.json\n` + + `// Source: plan/agw/research/deployment-review-2026-10-06/abis/${name}.json\n` + `// push-agentic-wallets@${PIN}\n` + `// sha256(${name}.json) = ${sha}\n` + `export const ${constName} = ${JSON.stringify(abi, null, 2)} as const;\n`; writeFileSync(join(dst, file), body); - exports.push(`export { ${constName} } from './${file.replace(/\.ts$/, '')}';`); + exports.push( + `export { ${constName} } from './${file.replace(/\.ts$/, '')}';` + ); } writeFileSync( join(dst, 'index.ts'), `// GENERATED by packages/core/scripts/agw-local/gen-abi.mjs — do not edit.\n` + - `// Review generation e704d5b: no verified deployment exists for this ABI set.\n` + - `export const E704D5B_SOURCE_COMMIT = '${PIN}' as const;\n` + + `// Review generation v4: Donut v4 deployment; source e8db748.\n` + + `export const V4_SOURCE_COMMIT = '${PIN}' as const;\n` + exports.join('\n') + '\n' ); diff --git a/packages/core/scripts/agw-local/prepare.sh b/packages/core/scripts/agw-local/prepare.sh index 08c70400..806f09bd 100755 --- a/packages/core/scripts/agw-local/prepare.sh +++ b/packages/core/scripts/agw-local/prepare.sh @@ -5,7 +5,7 @@ # AGW_REPO path to a push-agentic-wallets clone (default: ../../../../push-agentic-wallets # relative to this script). Only `git archive` / `git ls-tree` are run against it, # so the clone's working tree, branches and index are never touched. -# AGW_PIN commit to extract (default: the reviewed e704d5b). +# AGW_PIN commit to extract (default: the reviewed v4). # OUT destination directory (default: $TMPDIR/push-agw-local-). # # The script extracts the pinned tree, fetches each git submodule at the exact @@ -15,7 +15,7 @@ set -euo pipefail HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" AGW_REPO="${AGW_REPO:-$HERE/../../../../../push-agentic-wallets}" -AGW_PIN="${AGW_PIN:-e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9}" +AGW_PIN="${AGW_PIN:-e8db74815cfbbf5389593805e464fe8d85f7f735}" OUT="${OUT:-${TMPDIR:-/tmp}/push-agw-local-${AGW_PIN:0:7}}" command -v forge >/dev/null || { echo "forge not found (install Foundry)" >&2; exit 1; } diff --git a/packages/core/src/lib/agentic/__fixtures__/e704d5b-vectors.json b/packages/core/src/lib/agentic/__fixtures__/v4-vectors.json similarity index 96% rename from packages/core/src/lib/agentic/__fixtures__/e704d5b-vectors.json rename to packages/core/src/lib/agentic/__fixtures__/v4-vectors.json index 5eca8d1b..1219a092 100644 --- a/packages/core/src/lib/agentic/__fixtures__/e704d5b-vectors.json +++ b/packages/core/src/lib/agentic/__fixtures__/v4-vectors.json @@ -1,6 +1,6 @@ { "provenance": { - "agwCommit": "e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9", + "agwCommit": "e8db74815cfbbf5389593805e464fe8d85f7f735", "generatedBy": "packages/core/__agw-local__/vectors.spec.ts", "toolchain": "forge Version: 1.5.1-stable", "chainId": 9000, @@ -176,6 +176,6 @@ } ], "storedAmountOffset": 36, - "encodedSession": "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000e7f1725e7734ce288f8367e1bb143e90bb3f051200000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002047e7ef24000000000000000000000000000000000000000000000000000000000000000000000000000000008a791620dd6260079bf849dc5567adc3f2fdc318000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000cf7ed3acca5a467e9e704c703e8d87f634fb0fc90000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000b6569703135353a3930303000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000f48657000000000000000000000000008a791620dd6260079bf849dc5567adc3f2fdc31847e7ef24000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000003200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000040000000000000000000000003c44cdddb6a900fa2b585dd299e03d12fa4293bc" + "encodedSession": "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000e7f1725e7734ce288f8367e1bb143e90bb3f051200000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002047e7ef24000000000000000000000000000000000000000000000000000000000000000000000000000000008a791620dd6260079bf849dc5567adc3f2fdc318000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000cf7ed3acca5a467e9e704c703e8d87f634fb0fc9000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000b6569703135353a3930303000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000f48657000000000000000000000000008a791620dd6260079bf849dc5567adc3f2fdc31847e7ef24000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000003200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000040000000000000000000000003c44cdddb6a900fa2b585dd299e03d12fa4293bc" } } diff --git a/packages/core/src/lib/agentic/__tests__/codec.spec.ts b/packages/core/src/lib/agentic/__tests__/codec.spec.ts index a7aab35b..5f715dcf 100644 --- a/packages/core/src/lib/agentic/__tests__/codec.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/codec.spec.ts @@ -1,18 +1,30 @@ import { decodeFunctionData, getAddress, type Address, type Hex } from 'viem'; -import vectorsJson from '../__fixtures__/e704d5b-vectors.json'; -import { actionId, agentConfig, configId, deriveWallet, rulesId } from '../codec/ids'; +import vectorsJson from '../__fixtures__/v4-vectors.json'; +import { + actionId, + agentConfig, + configId, + deriveWallet, + rulesId, +} from '../codec/ids'; import { decodeNativeTerms, encodeNativeTerms, nativeRuleToTerms, nativeTermsToRule, } from '../codec/native'; -import { buildSession, decodeEnvelope, decodeSession, encodeEnvelope, encodeSession } from '../codec/session'; +import { + buildSession, + decodeEnvelope, + decodeSession, + encodeEnvelope, + encodeSession, +} from '../codec/session'; import { parseSelector, VALUE_ONLY_SELECTOR } from '../codec/selectors'; import { argumentOffset, headSize } from '../codec/abi-layout'; import { AGENTIC_DEFAULTS, UINT256_MAX } from '../codec/defaults'; -import { e704d5b } from '../contracts/e704d5b'; -import { AGW_ABI } from '../contracts/abi/e704d5b'; +import { v4 } from '../contracts/v4'; +import { AGW_ABI } from '../contracts/abi/v4'; import { AGENTIC_ERROR_CODE } from '../errors'; import type { NativeRule } from '../agentic.types'; @@ -23,8 +35,20 @@ function revive(v: T): T { ); } const vectors = revive(vectorsJson) as unknown as { - rulesId: { validator: Address; agent: Address; grantNonce: bigint; agentConfig: Hex; expected: Hex }[]; - deriveWallet: { factory: Address; walletImplementation: Address; owner: Address; index: number; expected: Address }[]; + rulesId: { + validator: Address; + agent: Address; + grantNonce: bigint; + agentConfig: Hex; + expected: Hex; + }[]; + deriveWallet: { + factory: Address; + walletImplementation: Address; + owner: Address; + index: number; + expected: Address; + }[]; native: { rule: NativeRule; nativeChain: string; @@ -45,25 +69,41 @@ const NOW = 1_700_000_000; const target = getAddress('0x0000000000000000000000000000000000007a76'); const agent = getAddress('0x00000000000000000000000000000000000000a9'); -describe('IDs against contract-generated vectors (e704d5b)', () => { - it.each(vectors.rulesId)('rulesId(agent, nonce) = engine.getPermissionId — nonce $grantNonce', (v) => { - expect(agentConfig(v.agent)).toBe(v.agentConfig); - expect(rulesId({ validator: v.validator, agent: v.agent, grantNonce: v.grantNonce })).toBe(v.expected); - }); +describe('IDs against contract-generated vectors (v4)', () => { + it.each(vectors.rulesId)( + 'rulesId(agent, nonce) = engine.getPermissionId — nonce $grantNonce', + (v) => { + expect(agentConfig(v.agent)).toBe(v.agentConfig); + expect( + rulesId({ + validator: v.validator, + agent: v.agent, + grantNonce: v.grantNonce, + }) + ).toBe(v.expected); + } + ); - it.each(vectors.deriveWallet)('deriveWallet mirrors factory.predictWallet for $owner', (v) => { - expect(deriveWallet(v)).toBe(getAddress(v.expected)); - }); + it.each(vectors.deriveWallet)( + 'deriveWallet mirrors factory.predictWallet for $owner', + (v) => { + expect(deriveWallet(v)).toBe(getAddress(v.expected)); + } + ); it('actionId/configId: the policy holds an initialized config under exactly this key', () => { const n = vectors.native; expect(n.configInitialized).toBe(true); - expect(actionId(getAddress(n.storedTarget), n.storedSelector)).toBe(n.actionId); + expect(actionId(getAddress(n.storedTarget), n.storedSelector)).toBe( + n.actionId + ); expect(configId(n.wallet, n.rulesId, n.actionId)).toBe(n.configId); }); it('rulesId rejects a grant nonce outside uint64', () => { - expect(() => rulesId({ validator: agent, agent, grantNonce: BigInt(2) ** BigInt(64) })).toThrow(/uint64/); + expect(() => + rulesId({ validator: agent, agent, grantNonce: BigInt(2) ** BigInt(64) }) + ).toThrow(/uint64/); }); }); @@ -75,8 +115,15 @@ describe('native rule codec', () => { const session = buildSession({ validator: decodeSession(v.encodedSession).sessionValidator, agent: v.rule.agent, - rulesPolicy: decodeSession(v.encodedSession).actions[0].actionPolicies[0].policy, - actions: [{ target: terms.target, selector: terms.selector, initData: encodeEnvelope(v.nativeChain, encodeNativeTerms(terms)) }], + rulesPolicy: decodeSession(v.encodedSession).actions[0].actionPolicies[0] + .policy, + actions: [ + { + target: terms.target, + selector: terms.selector, + initData: encodeEnvelope(v.nativeChain, encodeNativeTerms(terms)), + }, + ], }); expect(encodeSession(session)).toBe(v.encodedSession); expect(terms.pins).toEqual(v.storedPins); @@ -86,53 +133,111 @@ describe('native rule codec', () => { it('round-trips terms through the envelope and back to a public rule', () => { const { terms } = nativeRuleToTerms(v.rule, { nowSeconds: NOW }); - const env = decodeEnvelope(encodeEnvelope(v.nativeChain, encodeNativeTerms(terms))); + const env = decodeEnvelope( + encodeEnvelope(v.nativeChain, encodeNativeTerms(terms)) + ); expect(env.chainNamespace).toBe(v.nativeChain); const back = decodeNativeTerms(env.body); expect(back).toEqual({ ...terms, validUntil: terms.validUntil }); const rule = nativeTermsToRule(back, v.rule.agent, `0x${'00'.repeat(32)}`); // Stored terms carry offsets, not an ABI: decoded rules report the raw offset form. - expect(rule.pins).toEqual([{ offset: 4, expected: terms.pins[0].expected.toLowerCase() }]); - expect(rule.amount).toEqual({ offset: 36, maxPerCall: BigInt(10), maxTotal: BigInt(100) }); + expect(rule.pins).toEqual([ + { offset: 4, expected: terms.pins[0].expected.toLowerCase() }, + ]); + expect(rule.amount).toEqual({ + offset: 36, + maxPerCall: BigInt(10), + maxTotal: BigInt(100), + }); expect(rule.ref).toBeUndefined(); // …and the decoded rule re-encodes to identical terms with only its 4-byte selector. expect(nativeRuleToTerms(rule, { nowSeconds: NOW }).terms).toEqual(terms); }); it('decoding never invents argument indexes: a static array before a pin stays a raw offset', () => { - const input: NativeRule = { agent, target, selector: 'deposit(uint256[2],address)', validUntil: NOW + 10, pins: [{ arg: 1, expected: agent }] }; + const input: NativeRule = { + agent, + target, + selector: 'deposit(uint256[2],address)', + validUntil: NOW + 10, + pins: [{ arg: 1, expected: agent }], + }; const { terms } = nativeRuleToTerms(input, { nowSeconds: NOW }); expect(terms.pins[0].offset).toBe(4 + 64); const decoded = nativeTermsToRule(terms, agent, `0x${'00'.repeat(32)}`); - expect(decoded.pins).toEqual([{ offset: 68, expected: terms.pins[0].expected }]); - expect(nativeRuleToTerms(decoded, { nowSeconds: NOW }).terms).toEqual(terms); + expect(decoded.pins).toEqual([ + { offset: 68, expected: terms.pins[0].expected }, + ]); + expect(nativeRuleToTerms(decoded, { nowSeconds: NOW }).terms).toEqual( + terms + ); }); it('a decoded address pin re-encodes in argument form once the signature is restored', () => { - const input: NativeRule = { agent, target, selector: 'deposit(address,uint256)', validUntil: NOW + 10, pins: [{ arg: 0, expected: agent }] }; + const input: NativeRule = { + agent, + target, + selector: 'deposit(address,uint256)', + validUntil: NOW + 10, + pins: [{ arg: 0, expected: agent }], + }; const { terms } = nativeRuleToTerms(input, { nowSeconds: NOW }); const word = terms.pins[0].expected; - expect(nativeRuleToTerms({ ...input, pins: [{ arg: 0, expected: word }] }, { nowSeconds: NOW }).terms).toEqual(terms); + expect( + nativeRuleToTerms( + { ...input, pins: [{ arg: 0, expected: word }] }, + { nowSeconds: NOW } + ).terms + ).toEqual(terms); expect(() => - nativeRuleToTerms({ ...input, pins: [{ arg: 0, expected: `0x${'ff'.repeat(32)}` }] }, { nowSeconds: NOW }) + nativeRuleToTerms( + { ...input, pins: [{ arg: 0, expected: `0x${'ff'.repeat(32)}` }] }, + { nowSeconds: NOW } + ) ).toThrow(/does not encode/); }); it('offset-form pins must be exact words at a valid offset', () => { - const base: NativeRule = { agent, target, selector: '0xd09de08a', validUntil: NOW + 10 }; - expect(() => nativeRuleToTerms({ ...base, pins: [{ offset: 3, expected: `0x${'00'.repeat(32)}` }] }, { nowSeconds: NOW })).toThrow(/offset/); - expect(() => nativeRuleToTerms({ ...base, pins: [{ offset: 4, expected: '0x01' }] }, { nowSeconds: NOW })).toThrow(/32-byte/); - expect(nativeRuleToTerms({ ...base, pins: [{ offset: 36, expected: `0x${'00'.repeat(31)}01` }] }, { nowSeconds: NOW }).terms.pins).toEqual([ - { offset: 36, expected: `0x${'00'.repeat(31)}01` }, - ]); + const base: NativeRule = { + agent, + target, + selector: '0xd09de08a', + validUntil: NOW + 10, + }; + expect(() => + nativeRuleToTerms( + { ...base, pins: [{ offset: 3, expected: `0x${'00'.repeat(32)}` }] }, + { nowSeconds: NOW } + ) + ).toThrow(/offset/); + expect(() => + nativeRuleToTerms( + { ...base, pins: [{ offset: 4, expected: '0x01' }] }, + { nowSeconds: NOW } + ) + ).toThrow(/32-byte/); + expect( + nativeRuleToTerms( + { ...base, pins: [{ offset: 36, expected: `0x${'00'.repeat(31)}01` }] }, + { nowSeconds: NOW } + ).terms.pins + ).toEqual([{ offset: 36, expected: `0x${'00'.repeat(31)}01` }]); }); it('applies the single provisional A03 defaults table for omitted limits', () => { const { terms } = nativeRuleToTerms( - { agent, target, selector: 'f(uint256)', validUntil: NOW + 10, amount: { arg: 0, maxPerCall: BigInt(1) } }, + { + agent, + target, + selector: 'f(uint256)', + validUntil: NOW + 10, + amount: { arg: 0, maxPerCall: BigInt(1) }, + }, { nowSeconds: NOW } ); - expect(terms.maxValuePerCall).toBe(AGENTIC_DEFAULTS.native.maxValuePerCall.value); + expect(terms.maxValuePerCall).toBe( + AGENTIC_DEFAULTS.native.maxValuePerCall.value + ); expect(terms.maxValueTotal).toBe(BigInt(0)); expect(terms.maxCalls).toBe(0); expect(terms.amount.maxTotal).toBe(UINT256_MAX); @@ -140,18 +245,33 @@ describe('native rule codec', () => { it('keeps an explicit zero as zero', () => { const { terms } = nativeRuleToTerms( - { agent, target, selector: 'f(uint256)', validUntil: NOW + 10, amount: { arg: 0, maxPerCall: BigInt(1), maxTotal: BigInt(0) } }, + { + agent, + target, + selector: 'f(uint256)', + validUntil: NOW + 10, + amount: { arg: 0, maxPerCall: BigInt(1), maxTotal: BigInt(0) }, + }, { nowSeconds: NOW } ); expect(terms.amount.maxTotal).toBe(BigInt(0)); }); it('value-only rules encode the reserved selector and refuse pins/amount', () => { - const { terms } = nativeRuleToTerms({ agent, target, selector: 'value-only', validUntil: NOW + 10 }, { nowSeconds: NOW }); + const { terms } = nativeRuleToTerms( + { agent, target, selector: 'value-only', validUntil: NOW + 10 }, + { nowSeconds: NOW } + ); expect(terms.selector).toBe(VALUE_ONLY_SELECTOR); expect(() => nativeRuleToTerms( - { agent, target, selector: 'value-only', validUntil: NOW + 10, pins: [{ arg: 0, expected: agent }] }, + { + agent, + target, + selector: 'value-only', + validUntil: NOW + 10, + pins: [{ arg: 0, expected: agent }], + }, { nowSeconds: NOW } ) ).toThrow(/value-only/); @@ -160,17 +280,54 @@ describe('native rule codec', () => { it.each([ ['past expiry', { validUntil: NOW }], ['zero target', { target: '0x0000000000000000000000000000000000000000' }], - ['too many pins', { selector: 'f(uint256)', pins: Array.from({ length: 9 }, () => ({ arg: 0, expected: BigInt(1) })) }], - ['pin needs a signature', { selector: '0x12345678', pins: [{ arg: 0, expected: BigInt(1) }] }], - ['pin on a dynamic argument', { selector: 'f(bytes)', pins: [{ arg: 0, expected: '0x01' }] }], - ['pin index out of range', { selector: 'f(uint256)', pins: [{ arg: 1, expected: BigInt(1) }] }], - ['pin value of the wrong type', { selector: 'f(address)', pins: [{ arg: 0, expected: BigInt(1) }] }], - ['amount on a non-uint', { selector: 'f(address)', amount: { arg: 0, maxPerCall: BigInt(1) } }], - ['amount also pinned', { selector: 'f(uint256)', pins: [{ arg: 0, expected: BigInt(1) }], amount: { arg: 0, maxPerCall: BigInt(1) } }], + [ + 'too many pins', + { + selector: 'f(uint256)', + pins: Array.from({ length: 9 }, () => ({ + arg: 0, + expected: BigInt(1), + })), + }, + ], + [ + 'pin needs a signature', + { selector: '0x12345678', pins: [{ arg: 0, expected: BigInt(1) }] }, + ], + [ + 'pin on a dynamic argument', + { selector: 'f(bytes)', pins: [{ arg: 0, expected: '0x01' }] }, + ], + [ + 'pin index out of range', + { selector: 'f(uint256)', pins: [{ arg: 1, expected: BigInt(1) }] }, + ], + [ + 'pin value of the wrong type', + { selector: 'f(address)', pins: [{ arg: 0, expected: BigInt(1) }] }, + ], + [ + 'amount on a non-uint', + { selector: 'f(address)', amount: { arg: 0, maxPerCall: BigInt(1) } }, + ], + [ + 'amount also pinned', + { + selector: 'f(uint256)', + pins: [{ arg: 0, expected: BigInt(1) }], + amount: { arg: 0, maxPerCall: BigInt(1) }, + }, + ], ['negative cap', { maxValuePerCall: BigInt(-1) }], ['maxCalls beyond uint32', { maxCalls: 2 ** 32 }], ])('rejects %s before signing', (_name, patch) => { - const rule = { agent, target, selector: 'increment()', validUntil: NOW + 10, ...patch } as NativeRule; + const rule = { + agent, + target, + selector: 'increment()', + validUntil: NOW + 10, + ...patch, + } as NativeRule; expect(() => nativeRuleToTerms(rule, { nowSeconds: NOW })).toThrow( expect.objectContaining({ code: AGENTIC_ERROR_CODE.INVALID_RULE }) ); @@ -178,16 +335,30 @@ describe('native rule codec', () => { it('approval policy is external while caller-supplied pins remain ABI-validated', () => { const base = { agent, target, validUntil: NOW + 10 }; - expect(() => nativeRuleToTerms({ ...base, selector: 'approve(address,uint256)' }, { nowSeconds: NOW })).not.toThrow(); expect(() => nativeRuleToTerms( - { ...base, selector: 'approve(address,uint256)', pins: [{ arg: 0, expected: agent }] }, + { ...base, selector: 'approve(address,uint256)' }, + { nowSeconds: NOW } + ) + ).not.toThrow(); + expect(() => + nativeRuleToTerms( + { + ...base, + selector: 'approve(address,uint256)', + pins: [{ arg: 0, expected: agent }], + }, { nowSeconds: NOW } ) ).not.toThrow(); expect(() => nativeRuleToTerms( - { ...base, selector: 'permit(address,address,uint256,uint256,uint8,bytes32,bytes32)', pins: [{ arg: 0, expected: agent }] }, + { + ...base, + selector: + 'permit(address,address,uint256,uint256,uint8,bytes32,bytes32)', + pins: [{ arg: 0, expected: agent }], + }, { nowSeconds: NOW } ) ).not.toThrow(); @@ -214,7 +385,9 @@ describe('ABI layout offsets', () => { it('parses hex, signature and value-only selectors', () => { expect(parseSelector('0x617BA037').selector).toBe('0x617ba037'); - expect(parseSelector('supply(address,uint256,address,uint16)').selector).toBe('0x617ba037'); + expect( + parseSelector('supply(address,uint256,address,uint16)').selector + ).toBe('0x617ba037'); expect(parseSelector('value-only').valueOnly).toBe(true); expect(() => parseSelector('not a selector' as never)).toThrow(); }); @@ -224,24 +397,34 @@ describe('wallet call encoders decode back to the same calls', () => { const call = { target, value: BigInt(7), data: '0xd09de08a' as Hex }; it('execute single uses packed ERC-7579 calldata', () => { - const data = e704d5b.encodeExecute([call]); + const data = v4.encodeExecute([call]); const { functionName, args } = decodeFunctionData({ abi: AGW_ABI, data }); expect(functionName).toBe('execute'); expect(args[0]).toBe(`0x${'00'.repeat(32)}`); expect((args[1] as Hex).length).toBe(2 + 2 * (20 + 32 + 4)); - expect(e704d5b.decodeWalletCall(data)).toEqual({ kind: 'execute', mode: args[0], calls: [call] }); + expect(v4.decodeWalletCall(data)).toEqual({ + kind: 'execute', + mode: args[0], + calls: [call], + }); }); it('execute batch uses abi.encode(Execution[])', () => { - const data = e704d5b.encodeExecute([call, { ...call, value: BigInt(0) }]); - const decoded = e704d5b.decodeWalletCall(data); - expect(decoded).toMatchObject({ kind: 'execute', mode: `0x01${'00'.repeat(31)}` }); - expect((decoded as { calls: unknown[] }).calls).toEqual([call, { ...call, value: BigInt(0) }]); + const data = v4.encodeExecute([call, { ...call, value: BigInt(0) }]); + const decoded = v4.decodeWalletCall(data); + expect(decoded).toMatchObject({ + kind: 'execute', + mode: `0x01${'00'.repeat(31)}`, + }); + expect((decoded as { calls: unknown[] }).calls).toEqual([ + call, + { ...call, value: BigInt(0) }, + ]); }); it('executeAsAgent carries the rule ID and one packed call', () => { const id = `0x${'42'.repeat(32)}` as Hex; - expect(e704d5b.decodeWalletCall(e704d5b.encodeExecuteAsAgent(id, call))).toEqual({ + expect(v4.decodeWalletCall(v4.encodeExecuteAsAgent(id, call))).toEqual({ kind: 'executeAsAgent', rulesId: id, mode: `0x${'00'.repeat(32)}`, @@ -250,6 +433,6 @@ describe('wallet call encoders decode back to the same calls', () => { }); it('unknown calldata is not mistaken for a wallet call', () => { - expect(e704d5b.decodeWalletCall('0xdeadbeef')).toBeNull(); + expect(v4.decodeWalletCall('0xdeadbeef')).toBeNull(); }); }); diff --git a/packages/core/src/lib/agentic/__tests__/fake-chain.ts b/packages/core/src/lib/agentic/__tests__/fake-chain.ts index cbbc7559..258fb646 100644 --- a/packages/core/src/lib/agentic/__tests__/fake-chain.ts +++ b/packages/core/src/lib/agentic/__tests__/fake-chain.ts @@ -18,11 +18,15 @@ import { type TransactionReceipt, } from 'viem'; import { PUSH_NETWORK } from '../../constants/enums'; -import { e704d5b } from '../contracts/e704d5b'; +import { v4 } from '../contracts/v4'; import type { ChainReader } from '../contracts/reader'; import { actionId, configId, deriveWallet } from '../codec/ids'; -import { registerAgenticGeneration, resetAgenticGenerations, type AgenticGeneration } from '../deployments'; -import type { NativeConfigRead } from '../contracts/e704d5b'; +import { + registerAgenticGeneration, + resetAgenticGenerations, + type AgenticGeneration, +} from '../deployments'; +import type { NativeConfigRead } from '../contracts/v4'; export const ADDR = { factory: getAddress('0x00000000000000000000000000000000000fac70'), @@ -48,9 +52,14 @@ export interface FakeRule { actionIds: Hex[]; native?: Partial; universal?: { - asset: Address; + assets: readonly { + token: Address; + maxPerCall?: bigint; + maxTotal?: bigint; + spent?: bigint; + }[]; expectedCEA: Address; - maxPCPerCall: bigint; + maxGasPerCall: bigint; }; } @@ -66,6 +75,8 @@ export interface FakeWallet { } export class FakeChain implements ChainReader { + policyVersion = '3.1.0'; + sourceTokens = new Map(); block = BigInt(100); wallets = new Map(); walletCounts = new Map(); @@ -80,17 +91,40 @@ export class FakeChain implements ChainReader { addWallet(owner: Address, label: string, rules: FakeRule[] = []): FakeWallet { const index = this.walletCounts.get(owner.toLowerCase()) ?? BigInt(0); - const address = deriveWallet({ factory: ADDR.factory, walletImplementation: ADDR.impl, owner, index }); - const w: FakeWallet = { address, owner, index, label, rules, checkpointCount: BigInt(0), grantNonce: BigInt(rules.length) }; + const address = deriveWallet({ + factory: ADDR.factory, + walletImplementation: ADDR.impl, + owner, + index, + }); + const w: FakeWallet = { + address, + owner, + index, + label, + rules, + checkpointCount: BigInt(0), + grantNonce: BigInt(rules.length), + }; this.wallets.set(address.toLowerCase(), w); this.walletCounts.set(owner.toLowerCase(), index + BigInt(1)); this.extraLogs.push( - log(ADDR.factory, e704d5b.events.walletDeployed, { owner, index, wallet: address }, { label }, BigInt(10)) + log( + ADDR.factory, + v4.events.walletDeployed, + { owner, index, wallet: address }, + { label }, + BigInt(10) + ) ); return w; } - nativeRule(agent: Address, rulesId: Hex, extra: Partial = {}): FakeRule { + nativeRule( + agent: Address, + rulesId: Hex, + extra: Partial = {} + ): FakeRule { return { rulesId, agent, @@ -101,7 +135,9 @@ export class FakeChain implements ChainReader { }; } - async readContract(args: Parameters[0]): Promise { + async readContract( + args: Parameters[0] + ): Promise { const fn = args.functionName; this.calls.push({ functionName: fn, blockNumber: args.blockNumber }); if (this.failOn.has(fn)) throw new Error(`rpc failure: ${fn}`); @@ -109,6 +145,8 @@ export class FakeChain implements ChainReader { const at = args.address.toLowerCase(); const wallet = this.wallets.get(at); switch (fn) { + case 'version': + return this.policyVersion; // factory case 'walletImplementation': return ADDR.impl; @@ -120,7 +158,12 @@ export class FakeChain implements ChainReader { if (index > count) throw new Error('IndexOutOfRange'); const addr = this.predictOverride ? this.predictOverride(owner, index) - : deriveWallet({ factory: ADDR.factory, walletImplementation: ADDR.impl, owner, index }); + : deriveWallet({ + factory: ADDR.factory, + walletImplementation: ADDR.impl, + owner, + index, + }); return [addr, index < count] as const; } case 'isWallet': @@ -154,7 +197,9 @@ export class FakeChain implements ChainReader { } // engine case 'getPermissionIDs': - return (this.wallets.get(String(a[0]).toLowerCase())?.rules ?? []).map((r) => r.rulesId); + return (this.wallets.get(String(a[0]).toLowerCase())?.rules ?? []).map( + (r) => r.rulesId + ); case 'isPermissionEnabled': { const w = this.wallets.get(String(a[1]).toLowerCase()); return !!w?.rules.some((r) => r.rulesId === a[0]); @@ -166,8 +211,19 @@ export class FakeChain implements ChainReader { // policy case 'getMode': { const found = this.findConfig(a[0] as Hex, a[1] as Address); - if (!found) return { initialized: false, mode: 0, vm: 0, chainHash: `0x${'00'.repeat(32)}` }; - return { initialized: true, mode: found.rule.mode, vm: 0, chainHash: keccak256(toBytes(found.rule.chain)) }; + if (!found) + return { + initialized: false, + mode: 0, + vm: 0, + chainHash: `0x${'00'.repeat(32)}`, + }; + return { + initialized: true, + mode: found.rule.mode, + vm: 0, + chainHash: keccak256(toBytes(found.rule.chain)), + }; } case 'getNativeConfig': { const found = this.findConfig(a[0] as Hex, a[1] as Address); @@ -180,7 +236,12 @@ export class FakeChain implements ChainReader { maxValuePerCall: BigInt(0), maxValueTotal: BigInt(0), valueSpent: BigInt(0), - amount: { enabled: false, offset: 0, maxPerCall: BigInt(0), maxTotal: BigInt(0) }, + amount: { + enabled: false, + offset: 0, + maxPerCall: BigInt(0), + maxTotal: BigInt(0), + }, amountSpent: BigInt(0), maxCalls: 0, callsUsed: 0, @@ -194,16 +255,33 @@ export class FakeChain implements ChainReader { return { initialized: !!found, validUntil: 2_000_000_000, - destChainHash: found ? keccak256(toBytes(found.rule.chain)) : `0x${'00'.repeat(32)}`, - expectedCEA: u?.expectedCEA ?? '0x0000000000000000000000000000000000000000', - asset: u?.asset ?? '0x0000000000000000000000000000000000000000', - maxAmountPerCall: BigInt(0), - maxAmountTotal: BigInt(0), - maxPCPerCall: u?.maxPCPerCall ?? BigInt(0), - spent: BigInt(0), - allowedCalls: [], + expectedCEA: u?.expectedCEA ?? ADDR.other, + assets: (u?.assets ?? [{ token: ADDR.target }]).map((a) => ({ + maxPerCall: BigInt(1000), + maxTotal: BigInt(10000), + spent: BigInt(0), + ...a, + })), + maxGasPerCall: u?.maxGasPerCall ?? BigInt(0), + allowedCalls: [ + { + target: ADDR.target, + selector: '0xd09de08a', + beneficiaryOffset: 0, + hasBeneficiary: false, + maxValue: BigInt(0), + }, + ], }; } + case 'SOURCE_CHAIN_NAMESPACE': + return SEPOLIA_NS; + case 'SOURCE_TOKEN_ADDRESS': + return ( + this.sourceTokens.get(args.address.toLowerCase()) ?? args.address + ); + case 'gasTokenPRC20ByChainNamespace': + return getAddress('0x0000000000000000000000000000000000007070'); case 'balanceOf': case 'allowance': return this.balances.get(`${fn}:${at}`) ?? BigInt(0); @@ -217,14 +295,16 @@ export class FakeChain implements ChainReader { if (!w) return undefined; for (const rule of w.rules) { for (const action of rule.actionIds) { - if (configId(w.address, rule.rulesId, action) === id) return { rule, action }; + if (configId(w.address, rule.rulesId, action) === id) + return { rule, action }; } } return undefined; } async getBlockNumber(): Promise { - if (this.failOn.has('getBlockNumber')) throw new Error('rpc failure: getBlockNumber'); + if (this.failOn.has('getBlockNumber')) + throw new Error('rpc failure: getBlockNumber'); return this.block; } @@ -246,7 +326,9 @@ export class FakeChain implements ChainReader { ); } - async getTransactionReceipt(args: { hash: Hex }): Promise { + async getTransactionReceipt(args: { + hash: Hex; + }): Promise { const r = this.receipts.get(args.hash); if (!r) throw new Error(`no receipt ${args.hash}`); return r; @@ -263,12 +345,19 @@ export function log( txHash: Hex = `0x${'ab'.repeat(32)}`, transactionIndex = 0 ): Log { - const topics = encodeEventTopics({ abi: [event], eventName: event.name, args: indexed } as never); + const topics = encodeEventTopics({ + abi: [event], + eventName: event.name, + args: indexed, + } as never); const nonIndexed = event.inputs.filter((i) => !('indexed' in i && i.indexed)); return { address, topics: topics as [Hex, ...Hex[]], - data: encodeAbiParameters(nonIndexed, nonIndexed.map((i) => data[i.name as string]) as never), + data: encodeAbiParameters( + nonIndexed, + nonIndexed.map((i) => data[i.name as string]) as never + ), blockNumber, transactionHash: txHash, transactionIndex, @@ -278,10 +367,16 @@ export function log( } as Log; } -export function checkpointLog(wallet: Address, seq: number, kind: number, block: bigint, txIndex = 0): Log { +export function checkpointLog( + wallet: Address, + seq: number, + kind: number, + block: bigint, + txIndex = 0 +): Log { return log( wallet, - e704d5b.events.checkpointed, + v4.events.checkpointed, { seq: BigInt(seq) }, { kind, ref: `0x${'11'.repeat(32)}`, blockNumber: block }, block, @@ -290,11 +385,13 @@ export function checkpointLog(wallet: Address, seq: number, kind: number, block: ); } -export function registerFakeGeneration(network: PUSH_NETWORK = PUSH_NETWORK.TESTNET_DONUT): AgenticGeneration { +export function registerFakeGeneration( + network: PUSH_NETWORK = PUSH_NETWORK.TESTNET_DONUT +): AgenticGeneration { resetAgenticGenerations(); return registerAgenticGeneration({ - id: 'e704d5b', - sourceCommit: 'e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9', + id: 'v4', + sourceCommit: 'e8db74815cfbbf5389593805e464fe8d85f7f735', network, advertised: false, addresses: { diff --git a/packages/core/src/lib/agentic/__tests__/management.spec.ts b/packages/core/src/lib/agentic/__tests__/management.spec.ts index 5de26a94..321ecff1 100644 --- a/packages/core/src/lib/agentic/__tests__/management.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/management.spec.ts @@ -1,25 +1,54 @@ -import { decodeFunctionData, encodeErrorResult, type Hex, type Log, type TransactionReceipt } from 'viem'; +import { + decodeFunctionData, + encodeErrorResult, + type Hex, + type Log, + type TransactionReceipt, +} from 'viem'; import { PUSH_NETWORK } from '../../constants/enums'; import { PushChainBatchExecutionError } from '../../orchestrator/internals/errors'; import type { MultiCall } from '../../orchestrator/orchestrator.types'; import { PROGRESS_HOOK } from '../../progress-hook/progress-hook.types'; import { AgenticCapability } from '../capabilities'; import { currentGeneration, resetAgenticGenerations } from '../deployments'; -import { AGW_ABI, AGW_FACTORY_ABI, UNIVERSAL_RULES_POLICY_ABI } from '../contracts/abi/e704d5b'; -import { e704d5b } from '../contracts/e704d5b'; +import { + AGW_ABI, + AGW_FACTORY_ABI, + UNIVERSAL_RULES_POLICY_ABI, +} from '../contracts/abi/v4'; +import { v4 } from '../contracts/v4'; import { deriveWallet, rulesId as computeRulesId } from '../codec/ids'; import { AGENTIC_ERROR_CODE } from '../errors'; import { createWallet } from '../management/create'; import { addRules, revokeRules, updateRules } from '../management/rules-write'; import type { NativeRule } from '../agentic.types'; -import { ADDR, FakeChain, PUSH_NS, log, registerFakeGeneration, ruleId } from './fake-chain'; +import { + ADDR, + FakeChain, + PUSH_NS, + log, + registerFakeGeneration, + ruleId, +} from './fake-chain'; import { fakeResponse, mockRuntime } from './mock-runtime'; const NOW = 1_700_000_000; -const rule = (agent = ADDR.agent): NativeRule => ({ agent, target: ADDR.target, selector: 'increment()', validUntil: NOW + 100 }); +const rule = (agent = ADDR.agent): NativeRule => ({ + agent, + target: ADDR.target, + selector: 'increment()', + validUntil: NOW + 100, +}); const granted = (wallet: `0x${string}`, id: Hex, block = BigInt(101)) => - log(wallet, e704d5b.events.rulesGranted, { rulesId: id, chainHash: `0x${'00'.repeat(32)}` }, { mode: 1, chainNamespace: PUSH_NS }, block); -const revoked = (wallet: `0x${string}`, id: Hex) => log(wallet, e704d5b.events.rulesRevoked, { rulesId: id }, {}, BigInt(101)); + log( + wallet, + v4.events.rulesGranted, + { rulesId: id, chainHash: `0x${'00'.repeat(32)}` }, + { mode: 1, chainNamespace: PUSH_NS }, + block + ); +const revoked = (wallet: `0x${string}`, id: Hex) => + log(wallet, v4.events.rulesRevoked, { rulesId: id }, {}, BigInt(101)); function withLogs(logs: Log[], over = {}) { const r = fakeResponse(over); @@ -32,9 +61,18 @@ beforeEach(() => registerFakeGeneration()); afterEach(() => resetAgenticGenerations()); describe('agentic.create', () => { - const nextWallet = deriveWallet({ factory: ADDR.factory, walletImplementation: ADDR.impl, owner: ADDR.owner, index: 0 }); + const nextWallet = deriveWallet({ + factory: ADDR.factory, + walletImplementation: ADDR.impl, + owner: ADDR.owner, + index: 0, + }); const ids = [ruleId(0), ruleId(1)].map((_, i) => - computeRulesId({ validator: ADDR.validator, agent: i === 0 ? ADDR.agent : ADDR.other, grantNonce: BigInt(i) }) + computeRulesId({ + validator: ADDR.validator, + agent: i === 0 ? ADDR.agent : ADDR.other, + grantNonce: BigInt(i), + }) ); it('validates first, then sends deploy + grants in input order and returns receipt IDs', async () => { @@ -43,18 +81,33 @@ describe('agentic.create', () => { signer: ADDR.owner, execute: (async () => withLogs([ - log(ADDR.factory, e704d5b.events.walletDeployed, { owner: ADDR.owner, index: BigInt(0), wallet: nextWallet }, { label: 'ops' }, BigInt(101)), + log( + ADDR.factory, + v4.events.walletDeployed, + { owner: ADDR.owner, index: BigInt(0), wallet: nextWallet }, + { label: 'ops' }, + BigInt(101) + ), granted(nextWallet, ids[0]), granted(nextWallet, ids[1]), ])) as never, }); const execute = jest.spyOn(rt, 'execute'); const perCall = jest.fn(); - const res = await createWallet(rt, 'ops', { rules: [rule(), rule(ADDR.other)], progressHook: perCall }); + const res = await createWallet(rt, 'ops', { + rules: [rule(), rule(ADDR.other)], + progressHook: perCall, + }); expect(res).toMatchObject({ wallet: nextWallet, index: 0, rulesIds: ids }); const calls = (execute.mock.calls[0][0] as { data: MultiCall[] }).data; - expect(calls.map((c) => c.to)).toEqual([ADDR.factory, nextWallet, nextWallet]); - expect(decodeFunctionData({ abi: AGW_ABI, data: calls[1].data }).functionName).toBe('grantRules'); + expect(calls.map((c) => c.to)).toEqual([ + ADDR.factory, + nextWallet, + nextWallet, + ]); + expect( + decodeFunctionData({ abi: AGW_ABI, data: calls[1].data }).functionName + ).toBe('grantRules'); expect(rt.events.map((e) => e.id)).toEqual([ PROGRESS_HOOK.AGENTIC_TX_101, PROGRESS_HOOK.AGENTIC_TX_102, @@ -72,7 +125,15 @@ describe('agentic.create', () => { execute: (async (p: { to: string; data: Hex; value: bigint }) => { expect(p.to).toBe(ADDR.factory); expect(p.value).toBe(BigInt(0)); - return withLogs([log(ADDR.factory, e704d5b.events.walletDeployed, { owner: ADDR.owner, index: BigInt(0), wallet: nextWallet }, { label: '' }, BigInt(101))]); + return withLogs([ + log( + ADDR.factory, + v4.events.walletDeployed, + { owner: ADDR.owner, index: BigInt(0), wallet: nextWallet }, + { label: '' }, + BigInt(101) + ), + ]); }) as never, }); expect((await createWallet(rt, '', { rules: [] })).rulesIds).toEqual([]); @@ -81,24 +142,59 @@ describe('agentic.create', () => { it('invalid input never reaches the signer', async () => { const fake = new FakeChain(); const rt = mockRuntime(fake, { signer: ADDR.owner }); - await expect(createWallet(rt, 'x', { rules: [rule(ADDR.owner)] })).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.AGENT_IS_OWNER }); - await expect(createWallet(rt, 'x', { rules: [rule(), rule()] })).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.DUPLICATE_RULE }); - await expect(createWallet(rt, 'x', undefined as never)).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.INVALID_RULE }); - await expect(createWallet(mockRuntime(fake, { signer: ADDR.owner, readOnly: true }), 'x', { rules: [] })).rejects.toMatchObject({ + await expect( + createWallet(rt, 'x', { rules: [rule(ADDR.owner)] }) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.AGENT_IS_OWNER }); + await expect( + createWallet(rt, 'x', undefined as never) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.INVALID_RULE }); + await expect( + createWallet( + mockRuntime(fake, { signer: ADDR.owner, readOnly: true }), + 'x', + { rules: [] } + ) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.READ_ONLY, }); expect(rt.executeMock).not.toHaveBeenCalled(); }); + it('refuses a changed URP version before grant signing', async () => { + const fake = new FakeChain(); + fake.policyVersion = '3.2.0'; + const rt = mockRuntime(fake, { signer: ADDR.owner }); + await expect( + createWallet(rt, 'version', { rules: [rule()] }) + ).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.GENERATION_UNSUPPORTED, + }); + expect(rt.executeMock).not.toHaveBeenCalled(); + }); it('a different wallet in the receipt is an INDEX_RACE with full details', async () => { const fake = new FakeChain(); - const elsewhere = deriveWallet({ factory: ADDR.factory, walletImplementation: ADDR.impl, owner: ADDR.owner, index: 1 }); + const elsewhere = deriveWallet({ + factory: ADDR.factory, + walletImplementation: ADDR.impl, + owner: ADDR.owner, + index: 1, + }); const rt = mockRuntime(fake, { signer: ADDR.owner, execute: (async () => - withLogs([log(ADDR.factory, e704d5b.events.walletDeployed, { owner: ADDR.owner, index: BigInt(1), wallet: elsewhere }, { label: '' }, BigInt(101))])) as never, + withLogs([ + log( + ADDR.factory, + v4.events.walletDeployed, + { owner: ADDR.owner, index: BigInt(1), wallet: elsewhere }, + { label: '' }, + BigInt(101) + ), + ])) as never, + }); + await expect(createWallet(rt, '', { rules: [] })).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.INDEX_RACE, }); - await expect(createWallet(rt, '', { rules: [] })).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.INDEX_RACE }); }); it('IDs that differ from the input order are a RECEIPT_MISMATCH, not a silent reorder', async () => { @@ -107,12 +203,20 @@ describe('agentic.create', () => { signer: ADDR.owner, execute: (async () => withLogs([ - log(ADDR.factory, e704d5b.events.walletDeployed, { owner: ADDR.owner, index: BigInt(0), wallet: nextWallet }, { label: '' }, BigInt(101)), + log( + ADDR.factory, + v4.events.walletDeployed, + { owner: ADDR.owner, index: BigInt(0), wallet: nextWallet }, + { label: '' }, + BigInt(101) + ), granted(nextWallet, ids[1]), granted(nextWallet, ids[0]), ])) as never, }); - await expect(createWallet(rt, '', { rules: [rule(), rule(ADDR.other)] })).rejects.toMatchObject({ + await expect( + createWallet(rt, '', { rules: [rule(), rule(ADDR.other)] }) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.RECEIPT_MISMATCH, }); }); @@ -124,7 +228,18 @@ describe('agentic.create', () => { const fake = new FakeChain(); const h1 = `0x${'01'.repeat(32)}` as Hex; const h2 = `0x${'02'.repeat(32)}` as Hex; - fake.receipts.set(h1, receipt([log(ADDR.factory, e704d5b.events.walletDeployed, { owner: ADDR.owner, index: BigInt(0), wallet: nextWallet }, { label: 'ops' }, BigInt(101))])); + fake.receipts.set( + h1, + receipt([ + log( + ADDR.factory, + v4.events.walletDeployed, + { owner: ADDR.owner, index: BigInt(0), wallet: nextWallet }, + { label: 'ops' }, + BigInt(101) + ), + ]) + ); fake.receipts.set(h2, receipt([granted(nextWallet, ids[0])])); const rt = mockRuntime(fake, { signer: ADDR.owner, @@ -132,9 +247,16 @@ describe('agentic.create', () => { throw new PushChainBatchExecutionError('grant 2 reverted', [h1, h2]); }) as never, }); - const err = await createWallet(rt, 'ops', { rules: [rule(), rule(ADDR.other)] }).catch((e) => e); + const err = await createWallet(rt, 'ops', { + rules: [rule(), rule(ADDR.other)], + }).catch((e) => e); expect(err.code).toBe(AGENTIC_ERROR_CODE.CREATE_PARTIAL); - expect(err.details).toMatchObject({ wallet: nextWallet, walletDeployed: true, grantedRulesIds: [ids[0]], confirmedHashes: [h1, h2] }); + expect(err.details).toMatchObject({ + wallet: nextWallet, + walletDeployed: true, + grantedRulesIds: [ids[0]], + confirmedHashes: [h1, h2], + }); expect(err.hint).toMatch(/rules\.add/); expect(rt.events.at(-1)?.id).toBe(PROGRESS_HOOK.AGENTIC_TX_199_02); }); @@ -144,11 +266,20 @@ describe('agentic.create', () => { const rt = mockRuntime(fake, { signer: ADDR.owner, execute: (async () => { - throw new PushChainBatchExecutionError('timed out', [], `0x${'03'.repeat(32)}`); + throw new PushChainBatchExecutionError( + 'timed out', + [], + `0x${'03'.repeat(32)}` + ); }) as never, }); - const err = await createWallet(rt, 'ops', { rules: [rule()] }).catch((e) => e); - expect(err.details).toMatchObject({ walletDeployed: 'unknown', pendingHash: `0x${'03'.repeat(32)}` }); + const err = await createWallet(rt, 'ops', { rules: [rule()] }).catch( + (e) => e + ); + expect(err.details).toMatchObject({ + walletDeployed: 'unknown', + pendingHash: `0x${'03'.repeat(32)}`, + }); expect(err.hint).toMatch(/Do not retry/); }); @@ -158,10 +289,14 @@ describe('agentic.create', () => { signer: ADDR.owner, execute: (async () => { fake.addWallet(ADDR.owner, 'committed'); - throw new PushChainBatchExecutionError('grant failed', [`0x${'11'.repeat(32)}`]); + throw new PushChainBatchExecutionError('grant failed', [ + `0x${'11'.repeat(32)}`, + ]); }) as never, }); - const err = await createWallet(rt, 'review', { rules: [rule()] }).catch((e) => e); + const err = await createWallet(rt, 'review', { rules: [rule()] }).catch( + (e) => e + ); expect(err.code).toBe('CREATE_PARTIAL'); expect(err.details.walletDeployed).toBe('unknown'); expect(err.details.recoveryError).toBeTruthy(); @@ -182,35 +317,62 @@ describe('agentic.create', () => { }); const err = await createWallet(rt, 'x', { rules: [] }).catch((e) => e); expect(err.code).toBe(AGENTIC_ERROR_CODE.CREATE_PARTIAL); - expect(err.details).toMatchObject({ walletDeployed: 'unknown', submitted: { txHash: `0x${'44'.repeat(32)}` } }); + expect(err.details).toMatchObject({ + walletDeployed: 'unknown', + submitted: { txHash: `0x${'44'.repeat(32)}` }, + }); }); it('the deploy is index-bound: a raced slot reverts and is reported as INDEX_RACE with nothing committed', async () => { const fake = new FakeChain(); - const raceData = encodeErrorResult({ abi: AGW_FACTORY_ABI, errorName: 'IndexMismatch', args: [BigInt(1), BigInt(0)] }); + const raceData = encodeErrorResult({ + abi: AGW_FACTORY_ABI, + errorName: 'IndexMismatch', + args: [BigInt(1), BigInt(0)], + }); const rt = mockRuntime(fake, { signer: ADDR.owner, execute: (async (p: { data: MultiCall[] }) => { - const deploy = decodeFunctionData({ abi: AGW_FACTORY_ABI, data: p.data[0].data }); + const deploy = decodeFunctionData({ + abi: AGW_FACTORY_ABI, + data: p.data[0].data, + }); expect(deploy.functionName).toBe('deployWalletWithSig'); - expect((deploy.args[0] as { index: bigint; wallet: string }).index).toBe(BigInt(0)); + expect( + (deploy.args[0] as { index: bigint; wallet: string }).index + ).toBe(BigInt(0)); expect((deploy.args[0] as { wallet: string }).wallet).toBe(nextWallet); - throw new Error(`Execution reverted with reason: custom error ${raceData.slice(0, 10)}: ${raceData.slice(10)}.`); + throw new Error( + `Execution reverted with reason: custom error ${raceData.slice( + 0, + 10 + )}: ${raceData.slice(10)}.` + ); }) as never, }); - const err = await createWallet(rt, 'x', { rules: [rule()] }).catch((e) => e); + const err = await createWallet(rt, 'x', { rules: [rule()] }).catch( + (e) => e + ); expect(err.code).toBe(AGENTIC_ERROR_CODE.INDEX_RACE); expect(err.details).toMatchObject({ committed: false }); }); it('a slot that is already deployed is refused before signing', async () => { const fake = new FakeChain(); - fake.predictOverride = (owner, index) => deriveWallet({ factory: ADDR.factory, walletImplementation: ADDR.impl, owner, index }); + fake.predictOverride = (owner, index) => + deriveWallet({ + factory: ADDR.factory, + walletImplementation: ADDR.impl, + owner, + index, + }); const w = fake.addWallet(ADDR.owner, 'a'); fake.walletCounts.set(ADDR.owner.toLowerCase(), BigInt(0)); // stale count pointing at a deployed slot void w; const rt = mockRuntime(fake, { signer: ADDR.owner }); - await expect(createWallet(rt, '', { rules: [] })).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.INDEX_RACE }); + await expect(createWallet(rt, '', { rules: [] })).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.INDEX_RACE, + }); expect(rt.executeMock).not.toHaveBeenCalled(); }); }); @@ -218,64 +380,115 @@ describe('agentic.create', () => { describe('rules.add / rules.revoke', () => { const gen = () => currentGeneration(PUSH_NETWORK.TESTNET_DONUT); - it('add: owner-only, duplicate-aware against enabled rules, IDs from the grant nonce', async () => { + it('add: owner-only, same-agent grants allowed, IDs from the grant nonce', async () => { const fake = new FakeChain(); - const w = fake.addWallet(ADDR.owner, 'w', [fake.nativeRule(ADDR.agent, ruleId(1))]); + const w = fake.addWallet(ADDR.owner, 'w', [ + fake.nativeRule(ADDR.agent, ruleId(1)), + ]); w.grantNonce = BigInt(4); - const expected = computeRulesId({ validator: ADDR.validator, agent: ADDR.other, grantNonce: BigInt(4) }); + const expected = computeRulesId({ + validator: ADDR.validator, + agent: ADDR.agent, + grantNonce: BigInt(4), + }); const stranger = mockRuntime(fake, { signer: ADDR.other }); - await expect(addRules(stranger, gen(), w.address, [rule(ADDR.other)])).rejects.toMatchObject({ + await expect( + addRules(stranger, gen(), w.address, [rule(ADDR.other)]) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.NOT_WALLET_OWNER, }); - const rt = mockRuntime(fake, { signer: ADDR.owner, execute: (async () => withLogs([granted(w.address, expected)])) as never }); - await expect(addRules(rt, gen(), w.address, [rule(ADDR.agent)])).rejects.toMatchObject({ - code: AGENTIC_ERROR_CODE.DUPLICATE_RULE, + const rt = mockRuntime(fake, { + signer: ADDR.owner, + execute: (async () => withLogs([granted(w.address, expected)])) as never, }); - expect((await addRules(rt, gen(), w.address, [rule(ADDR.other)])).rulesIds).toEqual([expected]); + expect( + (await addRules(rt, gen(), w.address, [rule(ADDR.agent)])).rulesIds + ).toEqual([expected]); }); it('add: several rules are one atomic owner execute batch (one signature on any signer)', async () => { const fake = new FakeChain(); const w = fake.addWallet(ADDR.owner, 'w'); const ids = [ADDR.agent, ADDR.other].map((agent, i) => - computeRulesId({ validator: ADDR.validator, agent, grantNonce: BigInt(i) }) + computeRulesId({ + validator: ADDR.validator, + agent, + grantNonce: BigInt(i), + }) ); const rt = mockRuntime(fake, { signer: ADDR.owner, - execute: (async () => withLogs([granted(w.address, ids[0]), granted(w.address, ids[1])])) as never, + execute: (async () => + withLogs([ + granted(w.address, ids[0]), + granted(w.address, ids[1]), + ])) as never, }); const exec = jest.spyOn(rt, 'execute'); - expect((await addRules(rt, gen(), w.address, [rule(), rule(ADDR.other)])).rulesIds).toEqual(ids); + expect( + (await addRules(rt, gen(), w.address, [rule(), rule(ADDR.other)])) + .rulesIds + ).toEqual(ids); const sent = exec.mock.calls[0][0] as { to: string; data: Hex }; expect(Array.isArray(sent.data)).toBe(false); - const outer = e704d5b.decodeWalletCall(sent.data) as { kind: string; calls: { target: string; data: Hex }[] }; + const outer = v4.decodeWalletCall(sent.data) as { + kind: string; + calls: { target: string; data: Hex }[]; + }; expect(outer.kind).toBe('execute'); - expect(outer.calls.map((c) => decodeFunctionData({ abi: AGW_ABI, data: c.data }).functionName)).toEqual(['grantRules', 'grantRules']); + expect( + outer.calls.map( + (c) => decodeFunctionData({ abi: AGW_ABI, data: c.data }).functionName + ) + ).toEqual(['grantRules', 'grantRules']); }); it('revoke: bare and empty are refused; unknown IDs fail before signing; several IDs are one atomic owner execute', async () => { const fake = new FakeChain(); - const w = fake.addWallet(ADDR.owner, 'w', [fake.nativeRule(ADDR.agent, ruleId(1)), fake.nativeRule(ADDR.other, ruleId(2))]); + const w = fake.addWallet(ADDR.owner, 'w', [ + fake.nativeRule(ADDR.agent, ruleId(1)), + fake.nativeRule(ADDR.other, ruleId(2)), + ]); const rt = mockRuntime(fake, { signer: ADDR.owner, - execute: (async () => withLogs([revoked(w.address, ruleId(1)), revoked(w.address, ruleId(2))])) as never, + execute: (async () => + withLogs([ + revoked(w.address, ruleId(1)), + revoked(w.address, ruleId(2)), + ])) as never, }); const exec = jest.spyOn(rt, 'execute'); for (const bad of [undefined, [], {}, { all: false }]) { - await expect(revokeRules(rt, gen(), w.address, bad as never)).rejects.toMatchObject({ + await expect( + revokeRules(rt, gen(), w.address, bad as never) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.REVOKE_NEEDS_TARGET, }); } - await expect(revokeRules(rt, gen(), w.address, [ruleId(9)])).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.RULE_NOT_FOUND }); + await expect( + revokeRules(rt, gen(), w.address, [ruleId(9)]) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.RULE_NOT_FOUND }); expect(exec).not.toHaveBeenCalled(); await revokeRules(rt, gen(), w.address, [ruleId(1), ruleId(2)]); const sent = exec.mock.calls[0][0] as { to: string; data: Hex }; expect(sent.to).toBe(w.address); - const decoded = e704d5b.decodeWalletCall(sent.data) as { kind: string; calls: { target: string; data: Hex }[] }; + const decoded = v4.decodeWalletCall(sent.data) as { + kind: string; + calls: { target: string; data: Hex }[]; + }; expect(decoded.kind).toBe('execute'); - expect(decoded.calls.map((c) => decodeFunctionData({ abi: AGW_ABI, data: c.data }).functionName)).toEqual(['revokeRules', 'revokeRules']); + expect( + decoded.calls.map( + (c) => decodeFunctionData({ abi: AGW_ABI, data: c.data }).functionName + ) + ).toEqual(['revokeRules', 'revokeRules']); await revokeRules(rt, gen(), w.address, { all: true }); - expect(decodeFunctionData({ abi: AGW_ABI, data: (exec.mock.calls[1][0] as { data: Hex }).data }).functionName).toBe('revokeAllRules'); + expect( + decodeFunctionData({ + abi: AGW_ABI, + data: (exec.mock.calls[1][0] as { data: Hex }).data, + }).functionName + ).toBe('revokeAllRules'); }); }); @@ -285,52 +498,151 @@ describe('rules.update — one owner batch: assert → revoke → grant', () => it('builds exactly one execute(batch) with the observed spend asserted per pair', async () => { const fake = new FakeChain(); const w = fake.addWallet(ADDR.owner, 'w', [ - fake.nativeRule(ADDR.agent, ruleId(1), { valueSpent: BigInt(3), amountSpent: BigInt(4), callsUsed: 5 }), + fake.nativeRule(ADDR.agent, ruleId(1), { + valueSpent: BigInt(3), + amountSpent: BigInt(4), + callsUsed: 5, + }), ]); w.grantNonce = BigInt(2); - const newId = computeRulesId({ validator: ADDR.validator, agent: ADDR.agent, grantNonce: BigInt(2) }); + const newId = computeRulesId({ + validator: ADDR.validator, + agent: ADDR.agent, + grantNonce: BigInt(2), + }); const rt = mockRuntime(fake, { signer: ADDR.owner, - execute: (async () => withLogs([revoked(w.address, ruleId(1)), granted(w.address, newId)])) as never, + execute: (async () => + withLogs([ + revoked(w.address, ruleId(1)), + granted(w.address, newId), + ])) as never, }); const exec = jest.spyOn(rt, 'execute'); - const res = await updateRules(rt, gen(), w.address, { rules: [{ rulesId: ruleId(1), rule: rule() }] }); + const res = await updateRules(rt, gen(), w.address, { + rules: [{ rulesId: ruleId(1), rule: rule() }], + }); expect(res.rules).toEqual([{ rulesId: newId, replaced: ruleId(1) }]); expect(exec).toHaveBeenCalledTimes(1); const sent = exec.mock.calls[0][0] as { to: string; data: Hex }; expect(Array.isArray(sent.data)).toBe(false); // never a sequential multi-tx batch - const outer = e704d5b.decodeWalletCall(sent.data) as { kind: string; mode: Hex; calls: { target: string; data: Hex }[] }; + const outer = v4.decodeWalletCall(sent.data) as { + kind: string; + mode: Hex; + calls: { target: string; data: Hex }[]; + }; expect(outer.kind).toBe('execute'); - expect(outer.calls.map((c) => c.target)).toEqual([ADDR.policy, w.address, w.address]); - const assertion = decodeFunctionData({ abi: UNIVERSAL_RULES_POLICY_ABI, data: outer.calls[0].data }); + expect(outer.calls.map((c) => c.target)).toEqual([ + ADDR.policy, + w.address, + w.address, + ]); + const assertion = decodeFunctionData({ + abi: UNIVERSAL_RULES_POLICY_ABI, + data: outer.calls[0].data, + }); expect(assertion.functionName).toBe('assertSpent'); - expect(assertion.args.slice(1)).toEqual([w.address, BigInt(3), BigInt(4), 5]); - expect(outer.calls.slice(1).map((c) => decodeFunctionData({ abi: AGW_ABI, data: c.data }).functionName)).toEqual([ - 'revokeRules', - 'grantRules', + expect(assertion.args.slice(1)).toEqual([ + w.address, + BigInt(3), + BigInt(4), + 5, ]); + expect( + outer.calls + .slice(1) + .map( + (c) => decodeFunctionData({ abi: AGW_ABI, data: c.data }).functionName + ) + ).toEqual(['revokeRules', 'grantRules']); }); - it('replacing a universal rule needs the per-token assertion (A05) and fails before signing', async () => { + it('universal replacement asserts every asset in stored order before revoke/grant', async () => { const fake = new FakeChain(); - const w = fake.addWallet(ADDR.owner, 'w', [{ ...fake.nativeRule(ADDR.agent, ruleId(1)), mode: 0, chain: 'eip155:11155111' }]); - const rt = mockRuntime(fake, { signer: ADDR.owner }); - await expect(updateRules(rt, gen(), w.address, { rules: [{ rulesId: ruleId(1), rule: rule() }] })).rejects.toMatchObject({ - details: { capability: AgenticCapability.ASSERT_SPENT_UNIVERSAL_MULTI }, + const w = fake.addWallet(ADDR.owner, 'w', [ + { + ...fake.nativeRule(ADDR.agent, ruleId(1)), + mode: 0, + chain: 'eip155:11155111', + universal: { + expectedCEA: ADDR.other, + maxGasPerCall: BigInt(10), + assets: [ + { token: ADDR.target, spent: BigInt(4) }, + { token: ADDR.other, spent: BigInt(7) }, + ], + }, + }, + ]); + const next = computeRulesId({ + validator: ADDR.validator, + agent: ADDR.agent, + grantNonce: BigInt(1), }); - expect(rt.executeMock).not.toHaveBeenCalled(); + const rt = mockRuntime(fake, { + signer: ADDR.owner, + execute: (async () => + withLogs([ + revoked(w.address, ruleId(1)), + granted(w.address, next), + ])) as never, + }); + const exec = jest.spyOn(rt, 'execute'); + await updateRules(rt, gen(), w.address, { + rules: [{ rulesId: ruleId(1), rule: rule() }], + }); + const data = (exec.mock.calls[0][0] as { data: Hex }).data; + const outer = v4.decodeWalletCall(data) as { calls: { data: Hex }[] }; + const assertion = decodeFunctionData({ + abi: UNIVERSAL_RULES_POLICY_ABI, + data: outer.calls[0].data, + }); + expect(assertion.args.slice(1)).toEqual([ + w.address, + [BigInt(4), BigInt(7)], + ]); + expect( + outer.calls + .slice(1) + .map( + (c) => decodeFunctionData({ abi: AGW_ABI, data: c.data }).functionName + ) + ).toEqual(['revokeRules', 'grantRules']); }); - it('a replacement may reuse the replaced pair but not collide with another enabled rule', async () => { + it('replacement may name another live agent, but may not repeat an old ID', async () => { const fake = new FakeChain(); - const w = fake.addWallet(ADDR.owner, 'w', [fake.nativeRule(ADDR.agent, ruleId(1)), fake.nativeRule(ADDR.other, ruleId(2))]); - const rt = mockRuntime(fake, { signer: ADDR.owner }); - await expect( - updateRules(rt, gen(), w.address, { rules: [{ rulesId: ruleId(1), rule: rule(ADDR.other) }] }) - ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.DUPLICATE_RULE }); + const w = fake.addWallet(ADDR.owner, 'w', [ + fake.nativeRule(ADDR.agent, ruleId(1)), + fake.nativeRule(ADDR.other, ruleId(2)), + ]); + const next = computeRulesId({ + validator: ADDR.validator, + agent: ADDR.other, + grantNonce: BigInt(2), + }); + const rt = mockRuntime(fake, { + signer: ADDR.owner, + execute: (async () => + withLogs([ + revoked(w.address, ruleId(1)), + granted(w.address, next), + ])) as never, + }); + expect( + ( + await updateRules(rt, gen(), w.address, { + rules: [{ rulesId: ruleId(1), rule: rule(ADDR.other) }], + }) + ).rules[0].rulesId + ).toBe(next); await expect( - updateRules(rt, gen(), w.address, { rules: [{ rulesId: ruleId(1), rule: rule() }, { rulesId: ruleId(1), rule: rule() }] }) + updateRules(rt, gen(), w.address, { + rules: [ + { rulesId: ruleId(1), rule: rule() }, + { rulesId: ruleId(1), rule: rule() }, + ], + }) ).rejects.toThrow(/same old rule twice/); - expect(rt.executeMock).not.toHaveBeenCalled(); }); }); diff --git a/packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts b/packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts index b0acb668..1bd6462c 100644 --- a/packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts @@ -3,7 +3,7 @@ import { CHAIN, PUSH_NETWORK } from '../../constants/enums'; import { PUSH_BATCH_EXECUTOR_ADDRESS } from '../../constants/chain'; import { convertExecutorToOrigin } from '../../universal/account/account'; import { adaptTrackedResponse } from '../response'; -import { e704d5b, UEA_MULTICALL_PREFIX } from '../contracts/e704d5b'; +import { v4, UEA_MULTICALL_PREFIX } from '../contracts/v4'; import { resetAgenticGenerations } from '../deployments'; import { ADDR, FakeChain, registerFakeGeneration, ruleId } from './fake-chain'; import { fakeResponse, mockRuntime } from './mock-runtime'; @@ -27,7 +27,7 @@ function fixture() { const outer = actions.map((c) => ({ target: wallet.address, value: BigInt(0), - data: e704d5b.encodeExecuteAsAgent(ruleId(1), c), + data: v4.encodeExecuteAsAgent(ruleId(1), c), })); const runtime = mockRuntime(fake); return { fake, wallet, actions, outer, runtime }; @@ -47,7 +47,7 @@ it('recognizes a verified 7702 self-call and retains every native agent action', fakeResponse({ from: ADDR.agent, to: ADDR.agent, - data: e704d5b.encodeExecute(outer), + data: v4.encodeExecute(outer), }) ); expect(result).toMatchObject({ @@ -112,7 +112,7 @@ it('does not label an arbitrary forwarding contract as a trusted sender batch', const response = fakeResponse({ from: ADDR.agent, to: ADDR.other, - data: e704d5b.encodeExecute(outer), + data: v4.encodeExecute(outer), }); expect(await adaptTrackedResponse(runtime, response)).toBe(response); expect(response.agentic).toBeUndefined(); diff --git a/packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts b/packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts index 88686294..6a4c9ab1 100644 --- a/packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts @@ -8,7 +8,7 @@ import { transformToUniversalTxResponse } from '../../orchestrator/internals/res import { adaptTrackedResponse } from '../response'; import { composeOutbound, type DestinationCall } from '../execution/outbound'; import { agenticSend } from '../execution/send'; -import { e704d5b } from '../contracts/e704d5b'; +import { v4 } from '../contracts/v4'; import { currentGeneration, resetAgenticGenerations } from '../deployments'; import type { AgenticExecutionContext } from '../context'; import { ADDR, FakeChain, registerFakeGeneration, ruleId } from './fake-chain'; @@ -187,8 +187,8 @@ describe.each(['owner', 'agent'] as const)( ); const input = door === 'owner' - ? e704d5b.encodeExecute([out.gatewayCall]) - : e704d5b.encodeExecuteAsAgent(ruleId(1), out.gatewayCall); + ? v4.encodeExecute([out.gatewayCall]) + : v4.encodeExecuteAsAgent(ruleId(1), out.gatewayCall); const signer = door === 'owner' ? ADDR.owner : ADDR.agent; const tx = { hash: PUSH_HASH, diff --git a/packages/core/src/lib/agentic/__tests__/reads-context.spec.ts b/packages/core/src/lib/agentic/__tests__/reads-context.spec.ts index b5331a30..619c1ffc 100644 --- a/packages/core/src/lib/agentic/__tests__/reads-context.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/reads-context.spec.ts @@ -5,20 +5,38 @@ import { resetAgenticGenerations, currentGeneration } from '../deployments'; import { AGENTIC_ERROR_CODE } from '../errors'; import { readCheckpoints, validateSequence } from '../reads/checkpoints'; import { getRule, listRules, selectRuleForSend } from '../reads/rules'; -import { Snapshot } from '../reads/snapshot'; +import { Snapshot, scanLogs } from '../reads/snapshot'; import { deriveForOwner, listForOwner, walletInfo } from '../reads/wallets'; -import { ADDR, FakeChain, PUSH_NS, SEPOLIA_NS, checkpointLog, log, registerFakeGeneration, ruleId } from './fake-chain'; +import { + ADDR, + FakeChain, + PUSH_NS, + SEPOLIA_NS, + checkpointLog, + log, + registerFakeGeneration, + ruleId, +} from './fake-chain'; import { mockRuntime } from './mock-runtime'; -import { e704d5b } from '../contracts/e704d5b'; +import { v4 } from '../contracts/v4'; +import { readOriginToken } from '../contracts/prc20-metadata'; describe('generation registry', () => { afterEach(() => resetAgenticGenerations()); - it('ships with no verified deployment: every network is GENERATION_UNSUPPORTED (A07)', () => { + it('ships Donut v4 only; other networks are unsupported', () => { resetAgenticGenerations(); - for (const n of Object.values(PUSH_NETWORK)) { + expect(currentGeneration(PUSH_NETWORK.TESTNET_DONUT)).toMatchObject({ + id: 'v4', + advertised: true, + }); + for (const n of Object.values(PUSH_NETWORK).filter( + (n) => n !== PUSH_NETWORK.TESTNET_DONUT + )) { expect(() => currentGeneration(n)).toThrow( - expect.objectContaining({ code: AGENTIC_ERROR_CODE.GENERATION_UNSUPPORTED }) + expect.objectContaining({ + code: AGENTIC_ERROR_CODE.GENERATION_UNSUPPORTED, + }) ); } }); @@ -26,12 +44,61 @@ describe('generation registry', () => { it('initialize against any wallet fails before signing when no generation is registered', async () => { resetAgenticGenerations(); const fake = new FakeChain(); - await expect(resolveAgenticContext(mockRuntime(fake), ADDR.target)).rejects.toMatchObject({ + await expect( + resolveAgenticContext( + mockRuntime(fake, { network: PUSH_NETWORK.MAINNET }), + ADDR.target + ) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.GENERATION_UNSUPPORTED, }); }); }); +describe('Donut log-range limit', () => { + it('covers the full range in contiguous pages of at most 1,000 blocks', async () => { + const fake = new FakeChain(); + const getLogs = jest.spyOn(fake, 'getLogs'); + await scanLogs( + fake, + { address: ADDR.factory, event: v4.events.walletDeployed }, + BigInt(10), + BigInt(2010) + ); + expect(getLogs.mock.calls.map(([a]) => [a.fromBlock, a.toBlock])).toEqual([ + [BigInt(10), BigInt(1009)], + [BigInt(1010), BigInt(2009)], + [BigInt(2010), BigInt(2010)], + ]); + }); +}); + +describe('native PRC20 metadata', () => { + it('accepts a zero address word only for the registered gas token', async () => { + const fake = new FakeChain(), + gas = getAddress('0x0000000000000000000000000000000000007070'); + const original = fake.readContract.bind(fake); + jest.spyOn(fake, 'readContract').mockImplementation(async (args) => { + if (args.functionName === 'SOURCE_TOKEN_ADDRESS') { + const abi = args.abi as readonly { + outputs?: readonly { type: string }[]; + }[]; + if (abi[0].outputs?.[0].type === 'address') + return '0x0000000000000000000000000000000000000000'; + throw new Error('native precompile returns a static word'); + } + return original(args); + }); + const snap = await Snapshot.at(fake); + expect(await readOriginToken(snap, gas, SEPOLIA_NS)).toBe( + '0x0000000000000000000000000000000000000000' + ); + await expect( + readOriginToken(snap, ADDR.target, SEPOLIA_NS) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.RULE_READ_FAILED }); + }); +}); + describe('initialize with agenticWallet — door resolution', () => { let fake: FakeChain; beforeEach(() => { @@ -42,28 +109,48 @@ describe('initialize with agenticWallet — door resolution', () => { it('owner → owner door; universal account context keeps signer identity separate', async () => { const w = fake.addWallet(ADDR.owner, 'w'); - const ctx = await resolveAgenticContext(mockRuntime(fake, { signer: ADDR.owner }), w.address); - expect(ctx).toMatchObject({ wallet: w.address, door: 'owner', signerPushAccount: ADDR.owner }); + const ctx = await resolveAgenticContext( + mockRuntime(fake, { signer: ADDR.owner }), + w.address + ); + expect(ctx).toMatchObject({ + wallet: w.address, + door: 'owner', + signerPushAccount: ADDR.owner, + }); }); it('agent named in an enabled rule → agent door, even when that rule is expired', async () => { - const w = fake.addWallet(ADDR.owner, 'w', [fake.nativeRule(ADDR.agent, ruleId(1), { validUntil: 1 })]); + const w = fake.addWallet(ADDR.owner, 'w', [ + fake.nativeRule(ADDR.agent, ruleId(1), { validUntil: 1 }), + ]); const ctx = await resolveAgenticContext(mockRuntime(fake), w.address); expect(ctx.door).toBe('agent'); }); it('anyone else → NOT_OWNER_OR_AGENT', async () => { - const w = fake.addWallet(ADDR.owner, 'w', [fake.nativeRule(ADDR.agent, ruleId(1))]); - await expect(resolveAgenticContext(mockRuntime(fake, { signer: ADDR.other }), w.address)).rejects.toMatchObject({ + const w = fake.addWallet(ADDR.owner, 'w', [ + fake.nativeRule(ADDR.agent, ruleId(1)), + ]); + await expect( + resolveAgenticContext( + mockRuntime(fake, { signer: ADDR.other }), + w.address + ) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.NOT_OWNER_OR_AGENT, }); }); it('no code → WALLET_NOT_DEPLOYED; a contract that is not an AGW → NOT_AGENTIC_WALLET', async () => { - await expect(resolveAgenticContext(mockRuntime(fake), ADDR.target)).rejects.toMatchObject({ + await expect( + resolveAgenticContext(mockRuntime(fake), ADDR.target) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.WALLET_NOT_DEPLOYED, }); - await expect(resolveAgenticContext(mockRuntime(fake), 'not-an-address')).rejects.toMatchObject({ + await expect( + resolveAgenticContext(mockRuntime(fake), 'not-an-address') + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.NOT_AGENTIC_WALLET, }); }); @@ -71,7 +158,12 @@ describe('initialize with agenticWallet — door resolution', () => { it('wiring that does not match the registered generation is refused', async () => { const w = fake.addWallet(ADDR.owner, 'w'); w.accountId = 'push.agentwallet.1.0.0'; - await expect(resolveAgenticContext(mockRuntime(fake, { signer: ADDR.owner }), w.address)).rejects.toMatchObject({ + await expect( + resolveAgenticContext( + mockRuntime(fake, { signer: ADDR.owner }), + w.address + ) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.GENERATION_UNSUPPORTED, }); }); @@ -93,41 +185,101 @@ describe('per-send rule selection', () => { { ...fake.nativeRule(ADDR.agent, ruleId(3)), mode: 0, chain: SEPOLIA_NS }, ]); const snap = await Snapshot.at(fake); - const r = await selectRuleForSend(snap, gen(), w.address, ADDR.agent, PUSH_NS); + const r = await selectRuleForSend( + snap, + gen(), + w.address, + ADDR.agent, + PUSH_NS + ); expect(r.rulesId).toBe(ruleId(1)); - const u = await selectRuleForSend(snap, gen(), w.address, ADDR.agent, SEPOLIA_NS); + const u = await selectRuleForSend( + snap, + gen(), + w.address, + ADDR.agent, + SEPOLIA_NS + ); expect(u.rulesId).toBe(ruleId(3)); - expect(new Set(fake.calls.map((c) => c.blockNumber))).toEqual(new Set([fake.block])); + expect(new Set(fake.calls.map((c) => c.blockNumber))).toEqual( + new Set([fake.block]) + ); }); it('zero matches → NO_RULES_FOR_CHAIN', async () => { - const w = fake.addWallet(ADDR.owner, 'w', [fake.nativeRule(ADDR.other, ruleId(2))]); + const w = fake.addWallet(ADDR.owner, 'w', [ + fake.nativeRule(ADDR.other, ruleId(2)), + ]); await expect( - selectRuleForSend(await Snapshot.at(fake), gen(), w.address, ADDR.agent, PUSH_NS) + selectRuleForSend( + await Snapshot.at(fake), + gen(), + w.address, + ADDR.agent, + PUSH_NS + ) ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.NO_RULES_FOR_CHAIN }); }); - it('direct-grant duplicates → DUPLICATE_RULE listing every candidate, never an arbitrary pick', async () => { - const w = fake.addWallet(ADDR.owner, 'w', [fake.nativeRule(ADDR.agent, ruleId(1)), fake.nativeRule(ADDR.agent, ruleId(2))]); + it('direct-grant duplicates → AMBIGUOUS_RULE listing every candidate, never an arbitrary pick', async () => { + const w = fake.addWallet(ADDR.owner, 'w', [ + fake.nativeRule(ADDR.agent, ruleId(1)), + fake.nativeRule(ADDR.agent, ruleId(2)), + ]); await expect( - selectRuleForSend(await Snapshot.at(fake), gen(), w.address, ADDR.agent, PUSH_NS) - ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.DUPLICATE_RULE, details: { rulesIds: [ruleId(1), ruleId(2)] } }); + selectRuleForSend( + await Snapshot.at(fake), + gen(), + w.address, + ADDR.agent, + PUSH_NS + ) + ).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.AMBIGUOUS_RULE, + details: { rulesIds: [ruleId(1), ruleId(2)] }, + }); }); it('a revoked rule is not a candidate; lookups are not cached between sends', async () => { - const w = fake.addWallet(ADDR.owner, 'w', [fake.nativeRule(ADDR.agent, ruleId(1))]); - expect((await selectRuleForSend(await Snapshot.at(fake), gen(), w.address, ADDR.agent, PUSH_NS)).rulesId).toBe(ruleId(1)); + const w = fake.addWallet(ADDR.owner, 'w', [ + fake.nativeRule(ADDR.agent, ruleId(1)), + ]); + expect( + ( + await selectRuleForSend( + await Snapshot.at(fake), + gen(), + w.address, + ADDR.agent, + PUSH_NS + ) + ).rulesId + ).toBe(ruleId(1)); w.rules = []; await expect( - selectRuleForSend(await Snapshot.at(fake), gen(), w.address, ADDR.agent, PUSH_NS) + selectRuleForSend( + await Snapshot.at(fake), + gen(), + w.address, + ADDR.agent, + PUSH_NS + ) ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.NO_RULES_FOR_CHAIN }); }); it('an RPC failure is an error, never an empty rule set', async () => { - const w = fake.addWallet(ADDR.owner, 'w', [fake.nativeRule(ADDR.agent, ruleId(1))]); + const w = fake.addWallet(ADDR.owner, 'w', [ + fake.nativeRule(ADDR.agent, ruleId(1)), + ]); fake.failOn.add('getPermissionIDs'); await expect( - selectRuleForSend(await Snapshot.at(fake), gen(), w.address, ADDR.agent, PUSH_NS) + selectRuleForSend( + await Snapshot.at(fake), + gen(), + w.address, + ADDR.agent, + PUSH_NS + ) ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.RULE_READ_FAILED }); }); }); @@ -143,9 +295,18 @@ describe('rules.list / rules.get', () => { it('decodes active native records without exposing internal spend', async () => { const w = fake.addWallet(ADDR.owner, 'w', [ - fake.nativeRule(ADDR.agent, ruleId(1), { callsUsed: 3, valueSpent: BigInt(5), maxCalls: 9 }), + fake.nativeRule(ADDR.agent, ruleId(1), { + callsUsed: 3, + valueSpent: BigInt(5), + maxCalls: 9, + }), ]); - const rules = await listRules(await Snapshot.at(fake), gen(), w.address, PUSH_NS); + const rules = await listRules( + await Snapshot.at(fake), + gen(), + w.address, + PUSH_NS + ); expect(rules).toEqual([ expect.objectContaining({ rulesId: ruleId(1), @@ -158,29 +319,84 @@ describe('rules.list / rules.get', () => { }); it('public records contain no spent field', async () => { - const w = fake.addWallet(ADDR.owner, 'w', [fake.nativeRule(ADDR.agent, ruleId(1))]); - const record = await getRule(await Snapshot.at(fake), gen(), w.address, ruleId(1), PUSH_NS); + const w = fake.addWallet(ADDR.owner, 'w', [ + fake.nativeRule(ADDR.agent, ruleId(1)), + ]); + const record = await getRule( + await Snapshot.at(fake), + gen(), + w.address, + ruleId(1), + PUSH_NS + ); expect(record).not.toHaveProperty('spent'); }); - it('a universal rule cannot be decoded into the public type yet (A05) — the list fails, it is not truncated', async () => { + it('lists native and universal rules without truncating', async () => { const w = fake.addWallet(ADDR.owner, 'w', [ fake.nativeRule(ADDR.agent, ruleId(1)), { ...fake.nativeRule(ADDR.other, ruleId(2)), mode: 0, chain: SEPOLIA_NS }, ]); - await expect(listRules(await Snapshot.at(fake), gen(), w.address, PUSH_NS)).rejects.toMatchObject({ - code: AGENTIC_ERROR_CODE.CAPABILITY_UNAVAILABLE, + const records = await listRules( + await Snapshot.at(fake), + gen(), + w.address, + PUSH_NS + ); + expect(records.map((r) => r.chainNamespace)).toEqual([PUSH_NS, SEPOLIA_NS]); + }); + it('an empty source-token address is native only for the chain registry gas token', async () => { + const token = getAddress('0x0000000000000000000000000000000000007070'); + fake.sourceTokens.set(token.toLowerCase(), ''); + const w = fake.addWallet(ADDR.owner, 'native-gas', [ + { + ...fake.nativeRule(ADDR.agent, ruleId(1)), + mode: 0, + chain: SEPOLIA_NS, + universal: { + expectedCEA: ADDR.other, + maxGasPerCall: BigInt(1), + assets: [{ token }], + }, + }, + ]); + const record = await getRule( + await Snapshot.at(fake), + gen(), + w.address, + ruleId(1), + PUSH_NS + ); + expect(record.rule).toMatchObject({ + assets: [{ token: '0x0000000000000000000000000000000000000000' }], }); + fake.sourceTokens.set(ADDR.target.toLowerCase(), ''); + w.rules[0].universal!.assets = [{ token: ADDR.target }]; + await expect( + getRule(await Snapshot.at(fake), gen(), w.address, ruleId(1), PUSH_NS) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.RULE_READ_FAILED }); }); it('unknown and revoked IDs both return RULE_NOT_FOUND without history reconstruction', async () => { const w = fake.addWallet(ADDR.owner, 'w'); const snap = await Snapshot.at(fake); - await expect(getRule(snap, gen(), w.address, ruleId(9), PUSH_NS)).rejects.toMatchObject({ + await expect( + getRule(snap, gen(), w.address, ruleId(9), PUSH_NS) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.RULE_NOT_FOUND, }); - fake.extraLogs.push(log(w.address, e704d5b.events.rulesRevoked, { rulesId: ruleId(9) }, {}, BigInt(50))); - await expect(getRule(snap, gen(), w.address, ruleId(9), PUSH_NS)).rejects.toMatchObject({ + fake.extraLogs.push( + log( + w.address, + v4.events.rulesRevoked, + { rulesId: ruleId(9) }, + {}, + BigInt(50) + ) + ); + await expect( + getRule(snap, gen(), w.address, ruleId(9), PUSH_NS) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.RULE_NOT_FOUND, }); }); @@ -197,23 +413,38 @@ describe('wallet reads', () => { it('derive defaults to the next unused index; beyond it is refused', async () => { fake.addWallet(ADDR.owner, 'a'); - expect(await deriveForOwner(fake, gen(), ADDR.owner)).toMatchObject({ index: 1, deployed: false }); - expect(await deriveForOwner(fake, gen(), ADDR.owner, 0)).toMatchObject({ index: 0, deployed: true }); - await expect(deriveForOwner(fake, gen(), ADDR.owner, 2)).rejects.toThrow(/beyond/); + expect(await deriveForOwner(fake, gen(), ADDR.owner)).toMatchObject({ + index: 1, + deployed: false, + }); + expect(await deriveForOwner(fake, gen(), ADDR.owner, 0)).toMatchObject({ + index: 0, + deployed: true, + }); + await expect(deriveForOwner(fake, gen(), ADDR.owner, 2)).rejects.toThrow( + /beyond/ + ); }); it('derivation drift between the factory and the SDK mirror is detected (obligation 13)', async () => { - fake.predictOverride = () => getAddress('0x0000000000000000000000000000000000000bad'); - await expect(deriveForOwner(fake, gen(), ADDR.owner)).rejects.toMatchObject({ - code: AGENTIC_ERROR_CODE.INCONSISTENT_READ, - }); + fake.predictOverride = () => + getAddress('0x0000000000000000000000000000000000000bad'); + await expect(deriveForOwner(fake, gen(), ADDR.owner)).rejects.toMatchObject( + { + code: AGENTIC_ERROR_CODE.INCONSISTENT_READ, + } + ); }); it('list returns deployed slots with labels and rule counts plus the next undeployed slot', async () => { - fake.addWallet(ADDR.owner, 'first', [fake.nativeRule(ADDR.agent, ruleId(1))]); + fake.addWallet(ADDR.owner, 'first', [ + fake.nativeRule(ADDR.agent, ruleId(1)), + ]); fake.addWallet(ADDR.owner, ''); const wallets = await listForOwner(fake, gen(), ADDR.owner); - expect(wallets.map((w) => [w.index, w.label, w.deployed, w.rulesCount])).toEqual([ + expect( + wallets.map((w) => [w.index, w.label, w.deployed, w.rulesCount]) + ).toEqual([ [0, 'first', true, 1], [1, '', true, 0], [2, '', false, 0], @@ -222,20 +453,31 @@ describe('wallet reads', () => { it('an empty owner lists only slot 0, undeployed', async () => { expect(await listForOwner(fake, gen(), ADDR.other)).toEqual([ - expect.objectContaining({ index: 0, deployed: false, rulesCount: 0, label: '' }), + expect.objectContaining({ + index: 0, + deployed: false, + rulesCount: 0, + label: '', + }), ]); }); it('a missing deployment event is an inconsistency, not an empty label', async () => { const w = fake.addWallet(ADDR.owner, 'x'); fake.extraLogs = []; - await expect(walletInfo(fake, gen(), w.address)).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.INCONSISTENT_READ }); + await expect(walletInfo(fake, gen(), w.address)).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.INCONSISTENT_READ, + }); }); it('info of the signer’s next slot describes it as undeployed; other undeployed addresses are refused', async () => { const next = await deriveForOwner(fake, gen(), ADDR.owner); - expect(await walletInfo(fake, gen(), next.address, ADDR.owner)).toMatchObject({ deployed: false, index: 0, owner: ADDR.owner }); - await expect(walletInfo(fake, gen(), next.address, ADDR.other)).rejects.toMatchObject({ + expect( + await walletInfo(fake, gen(), next.address, ADDR.owner) + ).toMatchObject({ deployed: false, index: 0, owner: ADDR.owner }); + await expect( + walletInfo(fake, gen(), next.address, ADDR.other) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.WALLET_NOT_DEPLOYED, }); }); @@ -253,9 +495,16 @@ describe('checkpoints', () => { it('orders by block, tx and log index and counts five ticks for a replacement in one block', async () => { const w = fake.addWallet(ADDR.owner, 'w'); // A grant (seq 1), then a replacement batch (seq 2..6) in one tx; logs arrive reversed. - fake.checkpointLogs = [1, 2, 3, 4, 5, 6].map((seq) => - checkpointLog(w.address, seq, [1, 0, 0, 2, 0, 1][seq - 1], seq === 1 ? BigInt(20) : BigInt(60)) - ).reverse(); + fake.checkpointLogs = [1, 2, 3, 4, 5, 6] + .map((seq) => + checkpointLog( + w.address, + seq, + [1, 0, 0, 2, 0, 1][seq - 1], + seq === 1 ? BigInt(20) : BigInt(60) + ) + ) + .reverse(); w.checkpointCount = BigInt(6); const { checkpoints } = await readCheckpoints(fake, gen(), w.address); expect(checkpoints.map((c) => c.seq)).toEqual([1, 2, 3, 4, 5, 6]); @@ -268,23 +517,29 @@ describe('checkpoints', () => { ]); const since = await readCheckpoints(fake, gen(), w.address, BigInt(60)); expect(since.checkpoints).toHaveLength(5); - expect(since.checkpoints.every((c) => c.blockNumber === BigInt(60))).toBe(true); + expect(since.checkpoints.every((c) => c.blockNumber === BigInt(60))).toBe( + true + ); }); it('a count/event mismatch is reported (after one retry) rather than returned', async () => { const w = fake.addWallet(ADDR.owner, 'w'); fake.checkpointLogs = [checkpointLog(w.address, 1, 1, BigInt(20))]; w.checkpointCount = BigInt(2); - await expect(readCheckpoints(fake, gen(), w.address)).rejects.toMatchObject({ - code: AGENTIC_ERROR_CODE.INCONSISTENT_READ, - }); + await expect(readCheckpoints(fake, gen(), w.address)).rejects.toMatchObject( + { + code: AGENTIC_ERROR_CODE.INCONSISTENT_READ, + } + ); }); it('validateSequence checks contiguity and the count', () => { expect(validateSequence([1, 2, 3], BigInt(3), true)).toBeNull(); expect(validateSequence([1, 3], BigInt(3), true)).toMatch(/gap/); expect(validateSequence([2, 3], BigInt(3), false)).toBeNull(); - expect(validateSequence([2, 3], BigInt(4), false)).toMatch(/does not match/); + expect(validateSequence([2, 3], BigInt(4), false)).toMatch( + /does not match/ + ); expect(validateSequence([], BigInt(0), true)).toBeNull(); }); }); diff --git a/packages/core/src/lib/agentic/__tests__/response-surface.spec.ts b/packages/core/src/lib/agentic/__tests__/response-surface.spec.ts index 537a63c6..9ae2fcaf 100644 --- a/packages/core/src/lib/agentic/__tests__/response-surface.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/response-surface.spec.ts @@ -1,12 +1,17 @@ -import { encodeErrorResult, encodeFunctionData, getAddress, type Hex } from 'viem'; +import { + encodeErrorResult, + encodeFunctionData, + getAddress, + type Hex, +} from 'viem'; import * as core from '../../index'; import { CONSTANTS } from '../../constants'; import { PUSH_NETWORK } from '../../constants/enums'; import { UNIVERSAL_GATEWAY_PC } from '../../constants/abi'; import { PushChainExecutionError } from '../../orchestrator/internals/errors'; import { Utils } from '../../utils'; -import { AGW_ABI } from '../contracts/abi/e704d5b'; -import { e704d5b } from '../contracts/e704d5b'; +import { AGW_ABI } from '../contracts/abi/v4'; +import { v4 } from '../contracts/v4'; import { resetAgenticGenerations } from '../deployments'; import { AgenticRevertError } from '../errors'; import { adaptAgenticResponse, adaptTrackedResponse } from '../response'; @@ -18,7 +23,11 @@ afterEach(() => resetAgenticGenerations()); describe('response identity', () => { it('live adaptation keeps origin/hash/raw and records the wrapped call', () => { - const resp = fakeResponse({ to: ADDR.target, data: '0xabcd', from: ADDR.agent }); + const resp = fakeResponse({ + to: ADDR.target, + data: '0xabcd', + from: ADDR.agent, + }); const origin = resp.origin; adaptAgenticResponse(resp, { wallet: ADDR.owner, @@ -26,22 +35,47 @@ describe('response identity', () => { rulesId: ruleId(1), logical: { to: ADDR.other, data: '0x01', value: BigInt(2) }, }); - expect(resp).toMatchObject({ from: ADDR.owner, to: ADDR.other, data: '0x01', value: BigInt(2), origin }); - expect(resp.raw).toMatchObject({ from: ADDR.agent, to: ADDR.target, data: '0xabcd' }); - expect(resp.agentic).toMatchObject({ rawTo: ADDR.target, rawData: '0xabcd', door: 'agent' }); + expect(resp).toMatchObject({ + from: ADDR.owner, + to: ADDR.other, + data: '0x01', + value: BigInt(2), + origin, + }); + expect(resp.raw).toMatchObject({ + from: ADDR.agent, + to: ADDR.target, + data: '0xabcd', + }); + expect(resp.agentic).toMatchObject({ + rawTo: ADDR.target, + rawData: '0xabcd', + door: 'agent', + }); }); it('replay: a tracked execute on a registered wallet is re-presented as the wallet’s call', async () => { registerFakeGeneration(); const fake = new FakeChain(); const w = fake.addWallet(ADDR.owner, 'w'); - const data = e704d5b.encodeExecuteAsAgent(ruleId(4), { target: ADDR.target, value: BigInt(0), data: '0xd09de08a' }); + const data = v4.encodeExecuteAsAgent(ruleId(4), { + target: ADDR.target, + value: BigInt(0), + data: '0xd09de08a', + }); const tracked = await adaptTrackedResponse( { reader: fake, network: PUSH_NETWORK.TESTNET_DONUT }, fakeResponse({ to: w.address, data, from: ADDR.agent }) ); - expect(tracked).toMatchObject({ from: w.address, to: ADDR.target, data: '0xd09de08a' }); - expect(tracked.agentic).toMatchObject({ door: 'agent', rulesId: ruleId(4) }); + expect(tracked).toMatchObject({ + from: w.address, + to: ADDR.target, + data: '0xd09de08a', + }); + expect(tracked.agentic).toMatchObject({ + door: 'agent', + rulesId: ruleId(4), + }); }); it('replay: an outbound through the gateway restores the destination call and route', async () => { @@ -50,17 +84,57 @@ describe('response identity', () => { const w = fake.addWallet(ADDR.owner, 'w'); const payload = ('0x2cc2842d' + encodeFunctionData({ - abi: [{ type: 'function', name: 'x', inputs: [{ type: 'tuple[]', components: [{ name: 'to', type: 'address' }, { name: 'value', type: 'uint256' }, { name: 'data', type: 'bytes' }] }], outputs: [], stateMutability: 'nonpayable' }], + abi: [ + { + type: 'function', + name: 'x', + inputs: [ + { + type: 'tuple[]', + components: [ + { name: 'to', type: 'address' }, + { name: 'value', type: 'uint256' }, + { name: 'data', type: 'bytes' }, + ], + }, + ], + outputs: [], + stateMutability: 'nonpayable', + }, + ], args: [[{ to: ADDR.target, value: BigInt(0), data: '0xd09de08a' }]], }).slice(10)) as Hex; const gatewayCall = encodeFunctionData({ abi: UNIVERSAL_GATEWAY_PC, functionName: 'sendUniversalTxOutbound', - args: [{ recipient: '0x', token: ADDR.other, amount: BigInt(1), gasLimit: BigInt(1), gasPrice: BigInt(0), maxPCForGas: BigInt(1), payload, revertRecipient: w.address }], + args: [ + { + recipient: '0x', + token: ADDR.other, + amount: BigInt(1), + gasLimit: BigInt(1), + gasPrice: BigInt(0), + maxPCForGas: BigInt(1), + payload, + revertRecipient: w.address, + }, + ], + }); + const data = v4.encodeExecuteAsAgent(ruleId(4), { + target: ADDR.gateway, + value: BigInt(5), + data: gatewayCall, + }); + const tracked = await adaptTrackedResponse( + { reader: fake, network: PUSH_NETWORK.TESTNET_DONUT }, + fakeResponse({ to: w.address, data }) + ); + expect(tracked).toMatchObject({ + from: w.address, + to: ADDR.target, + data: '0xd09de08a', + route: 'UOA_TO_CEA', }); - const data = e704d5b.encodeExecuteAsAgent(ruleId(4), { target: ADDR.gateway, value: BigInt(5), data: gatewayCall }); - const tracked = await adaptTrackedResponse({ reader: fake, network: PUSH_NETWORK.TESTNET_DONUT }, fakeResponse({ to: w.address, data })); - expect(tracked).toMatchObject({ from: w.address, to: ADDR.target, data: '0xd09de08a', route: 'UOA_TO_CEA' }); // A Push-only route inferred from an incomplete Cosmos record is replaced. const early = await adaptTrackedResponse( { reader: fake, network: PUSH_NETWORK.TESTNET_DONUT }, @@ -72,10 +146,23 @@ describe('response identity', () => { it('replay: anything not provably an AGW call is left untouched', async () => { const fake = new FakeChain(); const plain = fakeResponse({ to: ADDR.target, data: '0xd09de08a' }); - expect(await adaptTrackedResponse({ reader: fake, network: PUSH_NETWORK.TESTNET_DONUT }, plain)).toBe(plain); + expect( + await adaptTrackedResponse( + { reader: fake, network: PUSH_NETWORK.TESTNET_DONUT }, + plain + ) + ).toBe(plain); registerFakeGeneration(); - const spoof = fakeResponse({ to: ADDR.target, data: e704d5b.encodeExecute([{ target: ADDR.other, value: BigInt(0), data: '0x' }]) }); - const out = await adaptTrackedResponse({ reader: fake, network: PUSH_NETWORK.TESTNET_DONUT }, spoof); + const spoof = fakeResponse({ + to: ADDR.target, + data: v4.encodeExecute([ + { target: ADDR.other, value: BigInt(0), data: '0x' }, + ]), + }); + const out = await adaptTrackedResponse( + { reader: fake, network: PUSH_NETWORK.TESTNET_DONUT }, + spoof + ); expect(out.from).toBe(spoof.from); expect(out.agentic).toBeUndefined(); }); @@ -83,34 +170,67 @@ describe('response identity', () => { describe('revert decoding', () => { it('decodes AGW errors with arguments', () => { - const data = encodeErrorResult({ abi: AGW_ABI, errorName: 'CallerIsNotAgent', args: [ruleId(1), ADDR.other] }); - expect(decodeAgwErrorData(data)).toMatchObject({ name: 'CallerIsNotAgent' }); + const data = encodeErrorResult({ + abi: AGW_ABI, + errorName: 'CallerIsNotAgent', + args: [ruleId(1), ADDR.other], + }); + expect(decodeAgwErrorData(data)).toMatchObject({ + name: 'CallerIsNotAgent', + }); }); it('names a truncated PolicyCheckReverted by its inner selector', () => { expect( decodeAgwErrorData(`0xf4270752${'8bb88ba1'.padEnd(64, '0')}`) - ).toMatchObject({ name: 'PolicyCheckReverted(CallLimitReached)', selector: '0xf4270752' }); + ).toMatchObject({ + name: 'PolicyCheckReverted(CallLimitReached)', + selector: '0xf4270752', + }); }); it('finds revert data through error causes and viem-style messages', () => { - const inner = new Error('outer', { cause: { data: encodeErrorResult({ abi: AGW_ABI, errorName: 'UnsupportedExecutionMode' }) } }); + const inner = new Error('outer', { + cause: { + data: encodeErrorResult({ + abi: AGW_ABI, + errorName: 'UnsupportedExecutionMode', + }), + }, + }); expect(decodeAgenticRevert(inner)?.name).toBe('UnsupportedExecutionMode'); expect(decodeAgenticRevert(new Error('nothing here'))).toBeUndefined(); }); + it('decodes viem simulation errors whose full revert lives in raw', () => { + const raw = `0xf4270752${'8bb88ba1'.padEnd(64, '0')}` as Hex; + expect( + decodeAgenticRevert({ + message: 'Unknown signature 0xf4270752', + cause: { raw }, + })?.name + ).toBe('PolicyCheckReverted(CallLimitReached)'); + }); }); describe('public surface', () => { it('exports the AGW errors, and the base execution error for instanceof checks', () => { expect(core.AgenticError).toBeDefined(); - expect(new core.AgenticRevertError('x')).toBeInstanceOf(core.PushChainExecutionError); + expect(new core.AgenticRevertError('x')).toBeInstanceOf( + core.PushChainExecutionError + ); expect(core.PushChainExecutionError).toBe(PushChainExecutionError); - expect(core.AGENTIC_ERROR_CODE.NO_RULES_FOR_CHAIN).toBe('NO_RULES_FOR_CHAIN'); + expect(core.AGENTIC_ERROR_CODE.NO_RULES_FOR_CHAIN).toBe( + 'NO_RULES_FOR_CHAIN' + ); expect(new AgenticRevertError('x', { cause: 'c' }).cause).toBe('c'); }); - it('CONSTANTS.AGENTIC carries no unverified addresses (A07)', () => { - expect(CONSTANTS.AGENTIC).toEqual({}); + it('CONSTANTS.AGENTIC carries the checked Donut v4 proxies', () => { + expect(CONSTANTS.AGENTIC.TESTNET_DONUT).toMatchObject({ + FACTORY: '0xaF88D0FD947afAe7bBb8F34e8417DCfc165e1aaF', + RULES_POLICY: '0x603E7f0aF6e1aAFf46DDfb28b1e99364f8BC59af', + ENVELOPE_VERSION: 1, + }); expect(Object.isFrozen(CONSTANTS.AGENTIC)).toBe(true); }); @@ -122,7 +242,12 @@ describe('public surface', () => { expect(Utils.agentic.rulesId).toBeUndefined(); // @ts-expect-error the marketplace compiler is outside AGW expect(Utils.agentic.compileCard).toBeUndefined(); - for (const name of ['rulesId', 'deriveWallet', 'encodeRules', 'compileCard']) { + for (const name of [ + 'rulesId', + 'deriveWallet', + 'encodeRules', + 'compileCard', + ]) { expect(Utils.agentic).not.toHaveProperty(name); } }); diff --git a/packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts b/packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts index 0252889d..970a7f5a 100644 --- a/packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts @@ -1,8 +1,13 @@ import { getAddress, type Address } from 'viem'; +import { CHAIN, PUSH_NETWORK } from '../../constants/enums'; +import { MOVEABLE_TOKEN_CONSTANTS } from '../../constants/tokens'; +import { getPRC20Address } from '../../universal/prc20-address'; +import { encodeUniversalTerms } from '../codec/universal-terms'; +import { buildSession, encodeEnvelope, encodeSession } from '../codec/session'; import { AgenticCapability } from '../capabilities'; import { prepareRules } from '../codec/rules'; import { validateUniversalRuleShape } from '../codec/universal'; -import { E704D5B_CAPABILITIES } from '../deployments'; +import { V4_CAPABILITIES } from '../deployments'; import { AGENTIC_ERROR_CODE } from '../errors'; import { internalAgenticUtils } from '../utils'; import type { NativeRule, UniversalRule } from '../agentic.types'; @@ -14,9 +19,15 @@ const ctx = { pushChainNamespace: PUSH_NS, validator: ADDR.validator, rulesPolicy: ADDR.policy, - capabilities: E704D5B_CAPABILITIES, + capabilities: V4_CAPABILITIES, nowSeconds: NOW, - forbiddenTargets: [ADDR.factory, ADDR.engine, ADDR.policy, ADDR.validator, ADDR.gateway], + forbiddenTargets: [ + ADDR.factory, + ADDR.engine, + ADDR.policy, + ADDR.validator, + ADDR.gateway, + ], }; const native = (over: Partial = {}): NativeRule => ({ agent: ADDR.agent, @@ -28,10 +39,21 @@ const native = (over: Partial = {}): NativeRule => ({ const universal = (over: Partial = {}): UniversalRule => ({ agent: ADDR.agent, chainNamespace: SEPOLIA_NS, - assets: [{ token: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238', maxPerCall: BigInt(100) }], + assets: [ + { + token: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238', + maxPerCall: BigInt(100), + }, + ], maxGasPerCall: BigInt(10) ** BigInt(18), validUntil: NOW + 100, - allowedCalls: [{ target: ADDR.target, selector: 'supply(address,uint256,address,uint16)', beneficiary: 2 }], + allowedCalls: [ + { + target: ADDR.target, + selector: 'supply(address,uint256,address,uint16)', + beneficiary: 2, + }, + ], ...over, }); @@ -42,45 +64,78 @@ describe('prepareRules — spec 1.b checks before any signature', () => { ); }); - it('DUPLICATE_RULE within the input (same agent, same chain)', () => { - expect(() => prepareRules([native(), native({ target: ADDR.other })], ctx)).toThrow( - expect.objectContaining({ code: AGENTIC_ERROR_CODE.DUPLICATE_RULE }) + it('allows multiple rules for the same agent and chain', () => { + const prepared = prepareRules( + [native(), native({ target: ADDR.other })], + ctx ); + expect(prepared).toHaveLength(2); + expect(prepared.map((p) => p.agent)).toEqual([ADDR.agent, ADDR.agent]); + expect(prepared.map((p) => p.nativeTerms?.target)).toEqual([ + ADDR.target, + ADDR.other, + ]); }); - it('DUPLICATE_RULE against an existing enabled rule, but not against one being replaced', () => { - const existing = [{ agent: ADDR.agent, chainNamespace: PUSH_NS, rulesId: `0x${'01'.repeat(32)}` as const }]; - expect(() => prepareRules([native()], { ...ctx, existing })).toThrow( - expect.objectContaining({ code: AGENTIC_ERROR_CODE.DUPLICATE_RULE }) - ); - expect(() => prepareRules([native()], { ...ctx, existing: [] })).not.toThrow(); - }); - - it('the same agent on two chains is two rules, not a duplicate', () => { - expect(() => prepareRules([native(), universal()], ctx)).toThrow( - expect.objectContaining({ code: AGENTIC_ERROR_CODE.CAPABILITY_UNAVAILABLE }) - ); + it('native and universal rules coexist for the same agent', () => { + const u = universal(); + const prepared = prepareRules([native(), u], { + ...ctx, + gateway: ADDR.gateway, + universal: new Map([ + [ + u, + { + expectedCEA: ADDR.other, + assets: [ + { + token: ADDR.target, + maxPerCall: BigInt(100), + maxTotal: BigInt(1000), + }, + ], + }, + ], + ]), + }); + expect(prepared.map((p) => p.chainNamespace)).toEqual([ + PUSH_NS, + SEPOLIA_NS, + ]); }); it('a ref is refused (never silently dropped) without the grant-ref capability (A07)', () => { - expect(() => prepareRules([native({ ref: `0x${'99'.repeat(32)}` })], ctx)).toThrow( + expect(() => + prepareRules([native({ ref: `0x${'99'.repeat(32)}` })], ctx) + ).toThrow( expect.objectContaining({ code: AGENTIC_ERROR_CODE.CAPABILITY_UNAVAILABLE, - details: expect.objectContaining({ capability: AgenticCapability.GRANT_REF }), + details: expect.objectContaining({ + capability: AgenticCapability.GRANT_REF, + }), }) ); }); it('refuses infrastructure targets the contracts would reject', () => { - for (const t of [ADDR.gateway, ADDR.policy, '0x0000000000000000000000000000000000000001' as Address]) { - expect(() => prepareRules([native({ target: t })], ctx)).toThrow(/infrastructure/); + for (const t of [ + ADDR.gateway, + ADDR.policy, + '0x0000000000000000000000000000000000000001' as Address, + ]) { + expect(() => prepareRules([native({ target: t })], ctx)).toThrow( + /infrastructure/ + ); } }); it('a universal rule naming the Push chain is rejected', () => { - expect(() => prepareRules([universal({ chainNamespace: PUSH_NS as `eip155:${string}` })], ctx)).toThrow( - /omit chainNamespace/ - ); + expect(() => + prepareRules( + [universal({ chainNamespace: PUSH_NS as `eip155:${string}` })], + ctx + ) + ).toThrow(/omit chainNamespace/); }); it('valid native rules produce one Session each, agent bound in the validator config', () => { @@ -95,14 +150,26 @@ describe('prepareRules — spec 1.b checks before any signature', () => { describe('universal rules — validated, then capability-gated (A01, A05)', () => { it('structural validation runs before the capability gate', () => { - expect(() => validateUniversalRuleShape(universal({ allowedCalls: [] }), NOW)).toThrow(/1\.\.32/); - expect(() => validateUniversalRuleShape(universal({ maxGasPerCall: BigInt(0) }), NOW)).toThrow(/maxGasPerCall/); expect(() => - validateUniversalRuleShape(universal({ chainNamespace: 'eip155:abc' as `eip155:${string}` }), NOW) + validateUniversalRuleShape(universal({ allowedCalls: [] }), NOW) + ).toThrow(/1\.\.32/); + expect(() => + validateUniversalRuleShape(universal({ maxGasPerCall: BigInt(0) }), NOW) + ).toThrow(/maxGasPerCall/); + expect(() => + validateUniversalRuleShape( + universal({ chainNamespace: 'eip155:abc' as `eip155:${string}` }), + NOW + ) ).toThrow(/CAIP-2/); expect(() => validateUniversalRuleShape( - universal({ assets: Array.from({ length: 9 }, (_, i) => ({ token: getAddress(`0x${(i + 1).toString(16).padStart(40, '0')}`), maxPerCall: BigInt(1) })) }), + universal({ + assets: Array.from({ length: 9 }, (_, i) => ({ + token: getAddress(`0x${(i + 1).toString(16).padStart(40, '0')}`), + maxPerCall: BigInt(1), + })), + }), NOW ) ).toThrow(/at most 8/); @@ -120,30 +187,68 @@ describe('universal rules — validated, then capability-gated (A01, A05)', () = }); it('approval policy belongs to UI/marketplace; structurally valid approval calls are accepted', () => { - for (const selector of ['approve(address,uint256)', 'increaseAllowance(address,uint256)'] as const) { - expect(() => validateUniversalRuleShape(universal({ allowedCalls: [{ target: ADDR.target, selector }] }), NOW)).not.toThrow(); + for (const selector of [ + 'approve(address,uint256)', + 'increaseAllowance(address,uint256)', + ] as const) { + expect(() => + validateUniversalRuleShape( + universal({ allowedCalls: [{ target: ADDR.target, selector }] }), + NOW + ) + ).not.toThrow(); } }); it('a beneficiary must be an address argument of a known signature', () => { expect(() => - validateUniversalRuleShape(universal({ allowedCalls: [{ target: ADDR.target, selector: 'supply(address,uint256,address,uint16)', beneficiary: 1 }] }), NOW) + validateUniversalRuleShape( + universal({ + allowedCalls: [ + { + target: ADDR.target, + selector: 'supply(address,uint256,address,uint16)', + beneficiary: 1, + }, + ], + }), + NOW + ) ).toThrow(/address argument/); expect(() => - validateUniversalRuleShape(universal({ allowedCalls: [{ target: ADDR.target, selector: '0x617ba037', beneficiary: 2 }] }), NOW) + validateUniversalRuleShape( + universal({ + allowedCalls: [ + { target: ADDR.target, selector: '0x617ba037', beneficiary: 2 }, + ], + }), + NOW + ) ).toThrow(/signature/); }); - it('a structurally valid universal rule fails with CAPABILITY_UNAVAILABLE, never a guessed encoding', () => { + it('requires resolved wallet/token context; SVM mapping stays explicitly gated', () => { expect(() => prepareRules([universal()], ctx)).toThrow( expect.objectContaining({ - code: AGENTIC_ERROR_CODE.CAPABILITY_UNAVAILABLE, - details: expect.objectContaining({ capability: AgenticCapability.UNIVERSAL_EVM_RULES }), + code: AGENTIC_ERROR_CODE.INVALID_RULE, }) ); expect(() => - prepareRules([universal({ chainNamespace: 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1' })], ctx) - ).toThrow(expect.objectContaining({ details: expect.objectContaining({ capability: AgenticCapability.UNIVERSAL_SVM_RULES }) })); + prepareRules( + [ + universal({ + chainNamespace: 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1', + }), + ], + ctx + ) + ).toThrow( + expect.objectContaining({ + details: expect.objectContaining({ + capability: AgenticCapability.UNIVERSAL_SVM_RULES, + }), + }) + ); }); }); @@ -151,22 +256,104 @@ describe('internal generation codecs (pure)', () => { const u = internalAgenticUtils; it('encodeRules → decodeRules round-trips a native rule', () => { - const rule = native({ selector: 'deposit(address,uint256)', pins: [{ arg: 0, expected: ADDR.other }], maxCalls: 4 }); - const [bytes] = u.encodeRules([rule], { pushChainNamespace: PUSH_NS, validator: ADDR.validator, rulesPolicy: ADDR.policy, nowSeconds: NOW }); + const rule = native({ + selector: 'deposit(address,uint256)', + pins: [{ arg: 0, expected: ADDR.other }], + maxCalls: 4, + }); + const [bytes] = u.encodeRules([rule], { + pushChainNamespace: PUSH_NS, + validator: ADDR.validator, + rulesPolicy: ADDR.policy, + nowSeconds: NOW, + }); const back = u.decodeRules(bytes, { pushChainNamespace: PUSH_NS }); - expect(back).toMatchObject({ agent: ADDR.agent, target: ADDR.target, maxCalls: 4, validUntil: NOW + 100 }); - expect((back as NativeRule).pins).toEqual([{ offset: 4, expected: `0x${'0'.repeat(24)}${ADDR.other.slice(2).toLowerCase()}` }]); + expect(back).toMatchObject({ + agent: ADDR.agent, + target: ADDR.target, + maxCalls: 4, + validUntil: NOW + 100, + }); + expect((back as NativeRule).pins).toEqual([ + { + offset: 4, + expected: `0x${'0'.repeat(24)}${ADDR.other.slice(2).toLowerCase()}`, + }, + ]); }); - it('decodeRules of a foreign-chain envelope is capability-gated', () => { - const [bytes] = u.encodeRules([native()], { pushChainNamespace: SEPOLIA_NS, validator: ADDR.validator, rulesPolicy: ADDR.policy, nowSeconds: NOW }); + it('decodeRules rejects a foreign-chain envelope carrying native terms', () => { + const [bytes] = u.encodeRules([native()], { + pushChainNamespace: SEPOLIA_NS, + validator: ADDR.validator, + rulesPolicy: ADDR.policy, + nowSeconds: NOW, + }); expect(() => u.decodeRules(bytes, { pushChainNamespace: PUSH_NS })).toThrow( - expect.objectContaining({ code: AGENTIC_ERROR_CODE.CAPABILITY_UNAVAILABLE }) + expect.objectContaining({ + code: AGENTIC_ERROR_CODE.RULE_READ_FAILED, + }) ); }); - it('actionId accepts signatures and hex alike', () => { - expect(u.actionId(ADDR.target, 'increment()')).toBe(u.actionId(ADDR.target, '0xd09de08a')); + it('pure decoding resolves known v4 assets and preserves the exact beneficiary offset', () => { + const inputToken = MOVEABLE_TOKEN_CONSTANTS.ETHEREUM_SEPOLIA.USDC; + const prc20 = getPRC20Address(inputToken, { + network: PUSH_NETWORK.TESTNET_DONUT, + }).address; + const bytes = encodeSession( + buildSession({ + validator: ADDR.validator, + agent: ADDR.agent, + rulesPolicy: ADDR.policy, + actions: [ + { + target: ADDR.gateway, + selector: '0x77b86bec', + initData: encodeEnvelope( + CHAIN.ETHEREUM_SEPOLIA, + encodeUniversalTerms({ + validUntil: NOW + 100, + expectedCEA: ADDR.other, + assets: [ + { + token: prc20, + maxPerCall: BigInt(10), + maxTotal: BigInt(100), + }, + ], + maxGasPerCall: BigInt(20), + allowedCalls: [ + { + target: ADDR.target, + selector: '0x617ba037', + beneficiaryOffset: 68, + hasBeneficiary: true, + maxValue: BigInt(0), + }, + ], + }) + ), + }, + ], + }) + ); + expect(u.decodeRules(bytes)).toMatchObject({ + chainNamespace: CHAIN.ETHEREUM_SEPOLIA, + assets: [ + { + token: getAddress(inputToken.address), + maxPerCall: BigInt(10), + maxTotal: BigInt(100), + }, + ], + allowedCalls: [{ beneficiaryOffset: 68 }], + }); }); + it('actionId accepts signatures and hex alike', () => { + expect(u.actionId(ADDR.target, 'increment()')).toBe( + u.actionId(ADDR.target, '0xd09de08a') + ); + }); }); diff --git a/packages/core/src/lib/agentic/__tests__/send.spec.ts b/packages/core/src/lib/agentic/__tests__/send.spec.ts index b49e51cd..71b24327 100644 --- a/packages/core/src/lib/agentic/__tests__/send.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/send.spec.ts @@ -1,4 +1,12 @@ -import { decodeAbiParameters, decodeFunctionData, encodeFunctionData, getAddress, maxUint256, type Address, type Hex } from 'viem'; +import { + decodeAbiParameters, + decodeFunctionData, + encodeFunctionData, + getAddress, + maxUint256, + type Address, + type Hex, +} from 'viem'; import { CHAIN, PUSH_NETWORK } from '../../constants/enums'; import { UNIVERSAL_GATEWAY_PC, ERC20_EVM } from '../../constants/abi'; import { PushChainExecutionError } from '../../orchestrator/internals/errors'; @@ -6,16 +14,25 @@ import { PROGRESS_HOOK } from '../../progress-hook/progress-hook.types'; import { AgenticCapability } from '../capabilities'; import type { AgenticExecutionContext } from '../context'; import { currentGeneration, resetAgenticGenerations } from '../deployments'; -import { e704d5b } from '../contracts/e704d5b'; +import { v4 } from '../contracts/v4'; import { actionId } from '../codec/ids'; import { AGENTIC_ERROR_CODE, AgenticRevertError } from '../errors'; import { agenticSend } from '../execution/send'; -import { ADDR, FakeChain, SEPOLIA_NS, registerFakeGeneration, ruleId } from './fake-chain'; +import { + ADDR, + FakeChain, + SEPOLIA_NS, + registerFakeGeneration, + ruleId, +} from './fake-chain'; import { mockRuntime } from './mock-runtime'; const data = '0xd09de08a' as Hex; -function setup(door: 'owner' | 'agent', rules = (f: FakeChain) => [f.nativeRule(ADDR.agent, ruleId(1))]) { +function setup( + door: 'owner' | 'agent', + rules = (f: FakeChain) => [f.nativeRule(ADDR.agent, ruleId(1))] +) { registerFakeGeneration(); const fake = new FakeChain(); const w = fake.addWallet(ADDR.owner, 'w', rules(fake)); @@ -35,56 +52,102 @@ afterEach(() => resetAgenticGenerations()); describe('guards fail before the signer is ever invoked', () => { it.each([ - ['from (Routes 3/4)', { to: ADDR.target, data, from: { chain: CHAIN.ETHEREUM_SEPOLIA } }, AGENTIC_ERROR_CODE.FROM_NOT_ALLOWED], - ['payGasWith', { to: ADDR.target, data, payGasWith: {} }, AGENTIC_ERROR_CODE.NOT_ALLOWED_IN_AGENTIC_MODE], - ['migration', { to: { address: ADDR.target, chain: CHAIN.ETHEREUM_SEPOLIA }, migration: true }, AGENTIC_ERROR_CODE.NOT_ALLOWED_IN_AGENTIC_MODE], - ['funds on a Push send', { to: ADDR.target, funds: { amount: BigInt(1) } }, AGENTIC_ERROR_CODE.NOT_ALLOWED_IN_AGENTIC_MODE], + [ + 'from (Routes 3/4)', + { to: ADDR.target, data, from: { chain: CHAIN.ETHEREUM_SEPOLIA } }, + AGENTIC_ERROR_CODE.FROM_NOT_ALLOWED, + ], + [ + 'payGasWith', + { to: ADDR.target, data, payGasWith: {} }, + AGENTIC_ERROR_CODE.NOT_ALLOWED_IN_AGENTIC_MODE, + ], + [ + 'migration', + { + to: { address: ADDR.target, chain: CHAIN.ETHEREUM_SEPOLIA }, + migration: true, + }, + AGENTIC_ERROR_CODE.NOT_ALLOWED_IN_AGENTIC_MODE, + ], + [ + 'funds on a Push send', + { to: ADDR.target, funds: { amount: BigInt(1) } }, + AGENTIC_ERROR_CODE.NOT_ALLOWED_IN_AGENTIC_MODE, + ], ])('%s', async (_name, params, code) => { const { rt, ctx } = setup('agent'); - await expect(agenticSend(rt, ctx, params as never)).rejects.toMatchObject({ code }); + await expect(agenticSend(rt, ctx, params as never)).rejects.toMatchObject({ + code, + }); expect(rt.executeMock).not.toHaveBeenCalled(); }); it('read-only clients never sign', async () => { const { fake, ctx } = setup('owner'); const rt = mockRuntime(fake, { signer: ADDR.owner, readOnly: true }); - await expect(agenticSend(rt, ctx, { to: ADDR.target, data })).rejects.toMatchObject({ + await expect( + agenticSend(rt, ctx, { to: ADDR.target, data }) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.READ_ONLY, }); expect(rt.executeMock).not.toHaveBeenCalled(); }); - it.each([true, false])('agent native arrays require an atomic sender-preserving transport (Push EOA=%s)', async (native) => { - const { rt, ctx } = setup('agent'); - rt.signerIsPushNative = () => native; - const calls = [{ to: ADDR.target, value: BigInt(0), data }, { to: ADDR.target, value: BigInt(1), data }]; - const tx = await agenticSend(rt, ctx, { to: ADDR.target, data: calls }); - expect(rt.executeMock).not.toHaveBeenCalled(); - expect(rt.atomicMock).toHaveBeenCalledTimes(1); - const batch = rt.atomicMock.mock.calls[0][0].data as { to: Address; value: bigint; data: Hex }[]; - expect(batch.map((c) => c.to)).toEqual([ctx.wallet, ctx.wallet]); - expect(batch.map((c) => e704d5b.decodeWalletCall(c.data))).toEqual(calls.map((c) => ({ - kind: 'executeAsAgent', rulesId: ruleId(1), mode: `0x${'00'.repeat(32)}`, - calls: [{ target: c.to, value: c.value, data: c.data }], - }))); - expect(tx.agentic?.nativeCalls).toEqual(calls); - }); + it.each([true, false])( + 'agent native arrays require an atomic sender-preserving transport (Push EOA=%s)', + async (native) => { + const { rt, ctx } = setup('agent'); + rt.signerIsPushNative = () => native; + const calls = [ + { to: ADDR.target, value: BigInt(0), data }, + { to: ADDR.target, value: BigInt(1), data }, + ]; + const tx = await agenticSend(rt, ctx, { to: ADDR.target, data: calls }); + expect(rt.executeMock).not.toHaveBeenCalled(); + expect(rt.atomicMock).toHaveBeenCalledTimes(1); + const batch = rt.atomicMock.mock.calls[0][0].data as { + to: Address; + value: bigint; + data: Hex; + }[]; + expect(batch.map((c) => c.to)).toEqual([ctx.wallet, ctx.wallet]); + expect(batch.map((c) => v4.decodeWalletCall(c.data))).toEqual( + calls.map((c) => ({ + kind: 'executeAsAgent', + rulesId: ruleId(1), + mode: `0x${'00'.repeat(32)}`, + calls: [{ target: c.to, value: c.value, data: c.data }], + })) + ); + expect(tx.agentic?.nativeCalls).toEqual(calls); + } + ); it('empty native arrays fail before any transport is called', async () => { const { rt, ctx } = setup('agent'); - await expect(agenticSend(rt, ctx, { to: ADDR.target, data: [] })).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.INVALID_RULE }); + await expect( + agenticSend(rt, ctx, { to: ADDR.target, data: [] }) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.INVALID_RULE }); expect(rt.executeMock).not.toHaveBeenCalled(); expect(rt.atomicMock).not.toHaveBeenCalled(); }); - it('NO_RULES_FOR_CHAIN and DUPLICATE_RULE are pre-signature', async () => { + it('NO_RULES_FOR_CHAIN and AMBIGUOUS_RULE are pre-signature', async () => { const none = setup('agent', () => []); - await expect(agenticSend(none.rt, none.ctx, { to: ADDR.target, data })).rejects.toMatchObject({ + await expect( + agenticSend(none.rt, none.ctx, { to: ADDR.target, data }) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.NO_RULES_FOR_CHAIN, }); - const dup = setup('agent', (f) => [f.nativeRule(ADDR.agent, ruleId(1)), f.nativeRule(ADDR.agent, ruleId(2))]); - await expect(agenticSend(dup.rt, dup.ctx, { to: ADDR.target, data })).rejects.toMatchObject({ - code: AGENTIC_ERROR_CODE.DUPLICATE_RULE, + const dup = setup('agent', (f) => [ + f.nativeRule(ADDR.agent, ruleId(1)), + f.nativeRule(ADDR.agent, ruleId(2)), + ]); + await expect( + agenticSend(dup.rt, dup.ctx, { to: ADDR.target, data }) + ).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.AMBIGUOUS_RULE, }); expect(none.rt.executeMock).not.toHaveBeenCalled(); expect(dup.rt.executeMock).not.toHaveBeenCalled(); @@ -99,7 +162,9 @@ describe('guards fail before the signer is ever invoked', () => { signerBalance: async () => BigInt(5), getGasPrice: async () => BigInt(1), }); - await expect(agenticSend(poor, ctx, { to: ADDR.target, data })).rejects.toMatchObject({ + await expect( + agenticSend(poor, ctx, { to: ADDR.target, data }) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.AGENT_GAS_INSUFFICIENT, }); expect(poor.executeMock).not.toHaveBeenCalled(); @@ -117,23 +182,36 @@ describe('guards fail before the signer is ever invoked', () => { describe('explicit Push destinations', () => { it('a ChainTarget on the connected Push chain is a native send, same as a bare address', async () => { const { rt, ctx } = setup('agent'); - const tx = await agenticSend(rt, ctx, { to: { address: ADDR.target, chain: CHAIN.PUSH_TESTNET_DONUT }, data }); - expect(e704d5b.decodeWalletCall(rt.executeMock.mock.calls[0][0].data)).toMatchObject({ kind: 'executeAsAgent', rulesId: ruleId(1) }); + const tx = await agenticSend(rt, ctx, { + to: { address: ADDR.target, chain: CHAIN.PUSH_TESTNET_DONUT }, + data, + }); + expect( + v4.decodeWalletCall(rt.executeMock.mock.calls[0][0].data) + ).toMatchObject({ kind: 'executeAsAgent', rulesId: ruleId(1) }); expect(tx.route).not.toBe('UOA_TO_CEA'); expect(tx.to).toBe(ADDR.target); }); it('the owner door treats it the same way', async () => { const { rt, ctx } = setup('owner'); - await agenticSend(rt, ctx, { to: { address: ADDR.target, chain: CHAIN.PUSH_TESTNET }, data }); - expect(e704d5b.decodeWalletCall(rt.executeMock.mock.calls[0][0].data)).toMatchObject({ kind: 'execute', calls: [{ target: ADDR.target }] }); + await agenticSend(rt, ctx, { + to: { address: ADDR.target, chain: CHAIN.PUSH_TESTNET }, + data, + }); + expect( + v4.decodeWalletCall(rt.executeMock.mock.calls[0][0].data) + ).toMatchObject({ kind: 'execute', calls: [{ target: ADDR.target }] }); }); it('another Push network is refused, not routed outbound', async () => { const { rt, ctx } = setup('owner'); - await expect(agenticSend(rt, ctx, { to: { address: ADDR.target, chain: CHAIN.PUSH_MAINNET }, data })).rejects.toThrow( - /other than the connected network/ - ); + await expect( + agenticSend(rt, ctx, { + to: { address: ADDR.target, chain: CHAIN.PUSH_MAINNET }, + data, + }) + ).rejects.toThrow(/other than the connected network/); expect(rt.executeMock).not.toHaveBeenCalled(); }); }); @@ -142,23 +220,43 @@ describe('native wrapping and logical identity', () => { it('agent door: executeAsAgent(selected rule, exact call); response shows the wallet as from', async () => { const { rt, ctx, w } = setup('agent'); const perCall = jest.fn(); - const tx = await agenticSend(rt, ctx, { to: ADDR.target, data, value: BigInt(3) }, { progressHook: perCall }); + const tx = await agenticSend( + rt, + ctx, + { to: ADDR.target, data, value: BigInt(3) }, + { progressHook: perCall } + ); const sent = rt.executeMock.mock.calls[0][0]; expect(sent.to).toBe(w.address); expect(sent.value).toBe(BigInt(0)); - expect(e704d5b.decodeWalletCall(sent.data)).toEqual({ + expect(v4.decodeWalletCall(sent.data)).toEqual({ kind: 'executeAsAgent', rulesId: ruleId(1), mode: `0x${'00'.repeat(32)}`, calls: [{ target: ADDR.target, value: BigInt(3), data }], }); - expect(tx).toMatchObject({ from: w.address, to: ADDR.target, data, value: BigInt(3) }); + expect(tx).toMatchObject({ + from: w.address, + to: ADDR.target, + data, + value: BigInt(3), + }); expect(tx.origin).toContain(ADDR.agent); - expect(tx.agentic).toMatchObject({ wallet: w.address, door: 'agent', rulesId: ruleId(1), rawTo: w.address }); + expect(tx.agentic).toMatchObject({ + wallet: w.address, + door: 'agent', + rulesId: ruleId(1), + rawTo: w.address, + }); const ids = rt.events.map((e) => e.id); - expect(ids).toEqual([PROGRESS_HOOK.AGENTIC_TX_107, PROGRESS_HOOK.AGENTIC_TX_199_01]); + expect(ids).toEqual([ + PROGRESS_HOOK.AGENTIC_TX_107, + PROGRESS_HOOK.AGENTIC_TX_199_01, + ]); expect(perCall).toHaveBeenCalledTimes(2); - expect(rt.executeMock.mock.calls[0][1]).toMatchObject({ progressHook: perCall }); + expect(rt.executeMock.mock.calls[0][1]).toMatchObject({ + progressHook: perCall, + }); }); it('owner door: arrays become one atomic execute(batch)', async () => { @@ -170,8 +268,11 @@ describe('native wrapping and logical identity', () => { { to: ADDR.other, value: BigInt(1), data: '0x' }, ], }); - const decoded = e704d5b.decodeWalletCall(rt.executeMock.mock.calls[0][0].data); - expect(decoded).toMatchObject({ kind: 'execute', mode: `0x01${'00'.repeat(31)}` }); + const decoded = v4.decodeWalletCall(rt.executeMock.mock.calls[0][0].data); + expect(decoded).toMatchObject({ + kind: 'execute', + mode: `0x01${'00'.repeat(31)}`, + }); expect((decoded as { calls: unknown[] }).calls).toHaveLength(2); }); @@ -191,12 +292,18 @@ describe('native wrapping and logical identity', () => { ); }, }); - const err = await agenticSend(rt, ctx, { to: ADDR.target, data }).catch((e) => e); + const err = await agenticSend(rt, ctx, { to: ADDR.target, data }).catch( + (e) => e + ); expect(err).toBeInstanceOf(AgenticRevertError); expect(err).toBeInstanceOf(PushChainExecutionError); expect(err.decodedError.name).toBe('PolicyCheckReverted(CallLimitReached)'); - const failed = rt.events.find((e) => e.id === PROGRESS_HOOK.AGENTIC_TX_199_02); - expect(failed?.response).toMatchObject({ decodedError: { name: 'PolicyCheckReverted(CallLimitReached)' } }); + const failed = rt.events.find( + (e) => e.id === PROGRESS_HOOK.AGENTIC_TX_199_02 + ); + expect(failed?.response).toMatchObject({ + decodedError: { name: 'PolicyCheckReverted(CallLimitReached)' }, + }); }); }); @@ -209,12 +316,19 @@ describe('EVM outbound composition from the wallet', () => { mode: 0, chain: SEPOLIA_NS, actionIds: [], - universal: { asset: token, expectedCEA: getAddress('0x000000000000000000000000000000000000cea1'), maxPCPerCall: BigInt(5000) }, + universal: { + assets: [{ token }], + expectedCEA: getAddress('0x000000000000000000000000000000000000cea1'), + maxGasPerCall: BigInt(5000), + }, }, ]); // universal action id is (gateway, sendUniversalTxOutbound) s.w.rules[0].actionIds = [actionId(ADDR.gateway, '0x77b86bec')]; - s.fake.balances.set(`pc:${s.w.address.toLowerCase()}`, BigInt(10) ** BigInt(18)); + s.fake.balances.set( + `pc:${s.w.address.toLowerCase()}`, + BigInt(10) ** BigInt(18) + ); s.fake.balances.set(`balanceOf:${token.toLowerCase()}`, BigInt(1000)); s.fake.balances.set(`allowance:${token.toLowerCase()}`, BigInt(500)); return s; @@ -222,21 +336,50 @@ describe('EVM outbound composition from the wallet', () => { const send = (amount?: bigint) => ({ to: { address: ADDR.target, chain: CHAIN.ETHEREUM_SEPOLIA }, data, - ...(amount ? { funds: { amount, token: { symbol: 'USDC', decimals: 6, address: token, mechanism: 'approve' as const } } } : {}), + ...(amount + ? { + funds: { + amount, + token: { + symbol: 'USDC', + decimals: 6, + address: token, + mechanism: 'approve' as const, + }, + }, + } + : {}), }); it('builds the policy-compatible request: empty recipient, wallet refund, nonzero gas cap, multicall payload, CEA of the wallet', async () => { const s = universalSetup(); - const resolveCEA = jest.fn(async () => ({ cea: getAddress('0x000000000000000000000000000000000000cea1'), isDeployed: true })); - const rt = mockRuntime(s.fake, { signer: ADDR.agent, resolveCEA, resolvePrc20: () => token }); + const resolveCEA = jest.fn(async () => ({ + cea: getAddress('0x000000000000000000000000000000000000cea1'), + isDeployed: true, + })); + const rt = mockRuntime(s.fake, { + signer: ADDR.agent, + resolveCEA, + resolvePrc20: () => token, + }); const tx = await agenticSend(rt, s.ctx, send(BigInt(100))); - expect(resolveCEA).toHaveBeenCalledWith(s.w.address, CHAIN.ETHEREUM_SEPOLIA); - const outer = e704d5b.decodeWalletCall(rt.executeMock.mock.calls[0][0].data) as { kind: string; rulesId: Hex; calls: { target: Address; value: bigint; data: Hex }[] }; + expect(resolveCEA).toHaveBeenCalledWith( + s.w.address, + CHAIN.ETHEREUM_SEPOLIA + ); + const outer = v4.decodeWalletCall(rt.executeMock.mock.calls[0][0].data) as { + kind: string; + rulesId: Hex; + calls: { target: Address; value: bigint; data: Hex }[]; + }; expect(outer.kind).toBe('executeAsAgent'); expect(outer.rulesId).toBe(ruleId(5)); expect(outer.calls[0].target).toBe(ADDR.gateway); expect(outer.calls[0].value).toBe(BigInt(1100)); - const { args } = decodeFunctionData({ abi: UNIVERSAL_GATEWAY_PC, data: outer.calls[0].data }); + const { args } = decodeFunctionData({ + abi: UNIVERSAL_GATEWAY_PC, + data: outer.calls[0].data, + }); expect(args[0]).toMatchObject({ recipient: '0x', token, @@ -244,17 +387,36 @@ describe('EVM outbound composition from the wallet', () => { maxPCForGas: BigInt(1000), revertRecipient: s.w.address, }); - expect((args[0] as { payload: Hex }).payload.startsWith('0x2cc2842d')).toBe(true); - expect(tx).toMatchObject({ from: s.w.address, to: token, data: encodeFunctionData({ abi: ERC20_EVM, functionName: 'transfer', args: [ADDR.target, BigInt(100)] }), route: 'UOA_TO_CEA', chain: CHAIN.ETHEREUM_SEPOLIA }); + expect((args[0] as { payload: Hex }).payload.startsWith('0x2cc2842d')).toBe( + true + ); + expect(tx).toMatchObject({ + from: s.w.address, + to: token, + data: encodeFunctionData({ + abi: ERC20_EVM, + functionName: 'transfer', + args: [ADDR.target, BigInt(100)], + }), + route: 'UOA_TO_CEA', + chain: CHAIN.ETHEREUM_SEPOLIA, + }); expect(tx.agentic?.destinationCalls).toHaveLength(2); - expect(tx.agentic?.destinationAccount).toBe(getAddress('0x000000000000000000000000000000000000cea1')); + expect(tx.agentic?.destinationAccount).toBe( + getAddress('0x000000000000000000000000000000000000cea1') + ); }); it('never injects an approval into the agent path; missing allowance fails before signing', async () => { const s = universalSetup(); s.fake.balances.set(`allowance:${token.toLowerCase()}`, BigInt(10)); - const rt = mockRuntime(s.fake, { signer: ADDR.agent, resolvePrc20: () => token }); - await expect(agenticSend(rt, s.ctx, send(BigInt(100)))).rejects.toMatchObject({ + const rt = mockRuntime(s.fake, { + signer: ADDR.agent, + resolvePrc20: () => token, + }); + await expect( + agenticSend(rt, s.ctx, send(BigInt(100))) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.GATEWAY_ALLOWANCE_INSUFFICIENT, }); expect(rt.executeMock).not.toHaveBeenCalled(); @@ -263,15 +425,26 @@ describe('EVM outbound composition from the wallet', () => { it('wallet PC below protocol fee + gas cap, or over the rule PC cap, fails before signing', async () => { const s = universalSetup(); s.fake.balances.set(`pc:${s.w.address.toLowerCase()}`, BigInt(10)); - const rt = mockRuntime(s.fake, { signer: ADDR.agent, resolvePrc20: () => token }); - await expect(agenticSend(rt, s.ctx, send())).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.WALLET_BALANCE_INSUFFICIENT }); + const rt = mockRuntime(s.fake, { + signer: ADDR.agent, + resolvePrc20: () => token, + }); + await expect(agenticSend(rt, s.ctx, send())).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.WALLET_BALANCE_INSUFFICIENT, + }); const s2 = universalSetup(); const pricey = mockRuntime(s2.fake, { signer: ADDR.agent, resolvePrc20: () => token, - quoteOutbound: async () => ({ protocolFee: BigInt(100), nativeValueForGas: BigInt(10_000), gasLimitUsed: BigInt(1) }), + quoteOutbound: async () => ({ + protocolFee: BigInt(100), + nativeValueForGas: BigInt(10_000), + gasLimitUsed: BigInt(1), + }), + }); + await expect(agenticSend(pricey, s2.ctx, send())).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.RULE_LIMIT_EXCEEDED, }); - await expect(agenticSend(pricey, s2.ctx, send())).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.RULE_LIMIT_EXCEEDED }); }); it('a committed destination account that no longer matches derivation is drift, not a send', async () => { @@ -279,9 +452,14 @@ describe('EVM outbound composition from the wallet', () => { const rt = mockRuntime(s.fake, { signer: ADDR.agent, resolvePrc20: () => token, - resolveCEA: async () => ({ cea: getAddress('0x000000000000000000000000000000000000dead'), isDeployed: true }), + resolveCEA: async () => ({ + cea: getAddress('0x000000000000000000000000000000000000dead'), + isDeployed: true, + }), + }); + await expect(agenticSend(rt, s.ctx, send())).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.INCONSISTENT_READ, }); - await expect(agenticSend(rt, s.ctx, send())).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.INCONSISTENT_READ }); }); it('a zero gas quote is refused (URP rejects an uncapped gas swap)', async () => { @@ -289,26 +467,44 @@ describe('EVM outbound composition from the wallet', () => { const rt = mockRuntime(s.fake, { signer: ADDR.agent, resolvePrc20: () => token, - quoteOutbound: async () => ({ protocolFee: BigInt(1), nativeValueForGas: BigInt(0), gasLimitUsed: BigInt(1) }), + quoteOutbound: async () => ({ + protocolFee: BigInt(1), + nativeValueForGas: BigInt(0), + gasLimitUsed: BigInt(1), + }), }); - await expect(agenticSend(rt, s.ctx, send())).rejects.toThrow(/uncapped gas swap/); + await expect(agenticSend(rt, s.ctx, send())).rejects.toThrow( + /uncapped gas swap/ + ); }); it('SVM destinations are capability-gated', async () => { const s = universalSetup(); const rt = mockRuntime(s.fake, { signer: ADDR.agent }); await expect( - agenticSend(rt, { ...s.ctx, door: 'owner' }, { to: { address: ADDR.target, chain: CHAIN.SOLANA_DEVNET }, data }) - ).rejects.toMatchObject({ details: { capability: AgenticCapability.UNIVERSAL_SVM_RULES } }); + agenticSend( + rt, + { ...s.ctx, door: 'owner' }, + { to: { address: ADDR.target, chain: CHAIN.SOLANA_DEVNET }, data } + ) + ).rejects.toMatchObject({ + details: { capability: AgenticCapability.UNIVERSAL_SVM_RULES }, + }); }); it('owner door never writes an allowance: it sends only the outbound and consumes the existing allowance', async () => { const s = universalSetup(); s.ctx.door = 'owner'; s.ctx.signerPushAccount = ADDR.owner; - const rt = mockRuntime(s.fake, { signer: ADDR.owner, resolvePrc20: () => token }); + const rt = mockRuntime(s.fake, { + signer: ADDR.owner, + resolvePrc20: () => token, + }); await agenticSend(rt, s.ctx, send(BigInt(100))); - const outer = e704d5b.decodeWalletCall(rt.executeMock.mock.calls[0][0].data) as { kind: string; calls: { target: Address; data: Hex }[] }; + const outer = v4.decodeWalletCall(rt.executeMock.mock.calls[0][0].data) as { + kind: string; + calls: { target: Address; data: Hex }[]; + }; expect(outer.kind).toBe('execute'); expect(outer.calls.map((c) => c.target)).toEqual([ADDR.gateway]); }); @@ -318,8 +514,13 @@ describe('EVM outbound composition from the wallet', () => { s.ctx.door = 'owner'; s.ctx.signerPushAccount = ADDR.owner; s.fake.balances.set(`allowance:${token.toLowerCase()}`, BigInt(10)); - const rt = mockRuntime(s.fake, { signer: ADDR.owner, resolvePrc20: () => token }); - await expect(agenticSend(rt, s.ctx, send(BigInt(100)))).rejects.toMatchObject({ + const rt = mockRuntime(s.fake, { + signer: ADDR.owner, + resolvePrc20: () => token, + }); + await expect( + agenticSend(rt, s.ctx, send(BigInt(100))) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.GATEWAY_ALLOWANCE_INSUFFICIENT, }); expect(rt.executeMock).not.toHaveBeenCalled(); @@ -330,31 +531,65 @@ describe('EVM outbound composition from the wallet', () => { s.ctx.door = 'owner'; s.ctx.signerPushAccount = ADDR.owner; s.fake.balances.set(`allowance:${token.toLowerCase()}`, maxUint256); - const rt = mockRuntime(s.fake, { signer: ADDR.owner, resolvePrc20: () => token }); - await expect(agenticSend(rt, s.ctx, send(BigInt(100)))).resolves.toBeDefined(); + const rt = mockRuntime(s.fake, { + signer: ADDR.owner, + resolvePrc20: () => token, + }); + await expect( + agenticSend(rt, s.ctx, send(BigInt(100))) + ).resolves.toBeDefined(); }); it('a transfer-only ERC-20 outbound instructs a transfer to the requested recipient', async () => { const s = universalSetup(); s.ctx.door = 'owner'; s.ctx.signerPushAccount = ADDR.owner; - const rt = mockRuntime(s.fake, { signer: ADDR.owner, resolvePrc20: () => token }); + const rt = mockRuntime(s.fake, { + signer: ADDR.owner, + resolvePrc20: () => token, + }); const recipient = getAddress('0x00000000000000000000000000000000000ab0b0'); - const usdc = { symbol: 'USDC', decimals: 6, address: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238', mechanism: 'approve' as const }; - const tx = await agenticSend(rt, s.ctx, { to: { address: recipient, chain: CHAIN.ETHEREUM_SEPOLIA }, funds: { amount: BigInt(100), token: usdc } }); - const outer = e704d5b.decodeWalletCall(rt.executeMock.mock.calls[0][0].data) as { calls: { data: Hex }[] }; - const { args } = decodeFunctionData({ abi: UNIVERSAL_GATEWAY_PC, data: outer.calls[0].data }); + const usdc = { + symbol: 'USDC', + decimals: 6, + address: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238', + mechanism: 'approve' as const, + }; + const tx = await agenticSend(rt, s.ctx, { + to: { address: recipient, chain: CHAIN.ETHEREUM_SEPOLIA }, + funds: { amount: BigInt(100), token: usdc }, + }); + const outer = v4.decodeWalletCall(rt.executeMock.mock.calls[0][0].data) as { + calls: { data: Hex }[]; + }; + const { args } = decodeFunctionData({ + abi: UNIVERSAL_GATEWAY_PC, + data: outer.calls[0].data, + }); const payload = (args[0] as { payload: Hex }).payload; const [calls] = decodeAbiParameters( - [{ type: 'tuple[]', components: [{ name: 'to', type: 'address' }, { name: 'value', type: 'uint256' }, { name: 'data', type: 'bytes' }] }], + [ + { + type: 'tuple[]', + components: [ + { name: 'to', type: 'address' }, + { name: 'value', type: 'uint256' }, + { name: 'data', type: 'bytes' }, + ], + }, + ], `0x${payload.slice(10)}` ); expect(calls).toHaveLength(1); expect(getAddress(calls[0].to)).toBe(getAddress(usdc.address)); - expect(decodeFunctionData({ abi: ERC20_EVM, data: calls[0].data }).args).toEqual([recipient, BigInt(100)]); + expect( + decodeFunctionData({ abi: ERC20_EVM, data: calls[0].data }).args + ).toEqual([recipient, BigInt(100)]); expect(tx.to).toBe(getAddress(usdc.address)); expect(tx.data).toBe(calls[0].data); - expect(tx.agentic?.destinationCalls).toEqual(calls.map((c) => ({ ...c, to: getAddress(c.to) }))); + expect(tx.agentic?.destinationCalls).toEqual( + calls.map((c) => ({ ...c, to: getAddress(c.to) })) + ); }); it('a value-only outbound burns the native PRC20 for that value and forwards it to the recipient', async () => { @@ -364,12 +599,25 @@ describe('EVM outbound composition from the wallet', () => { const native = getAddress('0x0000000000000000000000000000000000000e7e'); s.fake.balances.set(`balanceOf:${native.toLowerCase()}`, BigInt(1000)); s.fake.balances.set(`allowance:${native.toLowerCase()}`, BigInt(1000)); - const rt = mockRuntime(s.fake, { signer: ADDR.owner, resolvePrc20: () => native }); - await agenticSend(rt, s.ctx, { to: { address: ADDR.other, chain: CHAIN.ETHEREUM_SEPOLIA }, value: BigInt(7) }); - const outer = e704d5b.decodeWalletCall(rt.executeMock.mock.calls[0][0].data) as { calls: { data: Hex }[] }; - const req = decodeFunctionData({ abi: UNIVERSAL_GATEWAY_PC, data: outer.calls[0].data }).args[0] as { amount: bigint; payload: Hex }; + const rt = mockRuntime(s.fake, { + signer: ADDR.owner, + resolvePrc20: () => native, + }); + await agenticSend(rt, s.ctx, { + to: { address: ADDR.other, chain: CHAIN.ETHEREUM_SEPOLIA }, + value: BigInt(7), + }); + const outer = v4.decodeWalletCall(rt.executeMock.mock.calls[0][0].data) as { + calls: { data: Hex }[]; + }; + const req = decodeFunctionData({ + abi: UNIVERSAL_GATEWAY_PC, + data: outer.calls[0].data, + }).args[0] as { amount: bigint; payload: Hex }; expect(req.amount).toBe(BigInt(7)); - expect(req.payload.toLowerCase()).toContain(ADDR.other.slice(2).toLowerCase()); + expect(req.payload.toLowerCase()).toContain( + ADDR.other.slice(2).toLowerCase() + ); }); it('an outbound with no destination call (parking in the CEA) is refused before signing', async () => { @@ -377,30 +625,57 @@ describe('EVM outbound composition from the wallet', () => { s.ctx.door = 'owner'; s.ctx.signerPushAccount = ADDR.owner; const cea = getAddress('0x000000000000000000000000000000000000cea1'); - const rt = mockRuntime(s.fake, { signer: ADDR.owner, resolvePrc20: () => token, resolveCEA: async () => ({ cea, isDeployed: true }) }); + const rt = mockRuntime(s.fake, { + signer: ADDR.owner, + resolvePrc20: () => token, + resolveCEA: async () => ({ cea, isDeployed: true }), + }); await expect( - agenticSend(rt, s.ctx, { to: { address: cea, chain: CHAIN.ETHEREUM_SEPOLIA }, value: BigInt(1) }) + agenticSend(rt, s.ctx, { + to: { address: cea, chain: CHAIN.ETHEREUM_SEPOLIA }, + value: BigInt(1), + }) ).rejects.toThrow(/no destination call/); expect(rt.executeMock).not.toHaveBeenCalled(); }); it('an agent value-only destination call is refused before signing (the policy admits only allow-listed calls)', async () => { const s = universalSetup(); - const rt = mockRuntime(s.fake, { signer: ADDR.agent, resolvePrc20: () => token }); + const rt = mockRuntime(s.fake, { + signer: ADDR.agent, + resolvePrc20: () => token, + }); await expect( - agenticSend(rt, s.ctx, { to: { address: ADDR.other, chain: CHAIN.ETHEREUM_SEPOLIA }, funds: { amount: BigInt(1), token: { symbol: 'X', decimals: 6, address: token, mechanism: 'native' } } }) + agenticSend(rt, s.ctx, { + to: { address: ADDR.other, chain: CHAIN.ETHEREUM_SEPOLIA }, + funds: { + amount: BigInt(1), + token: { + symbol: 'X', + decimals: 6, + address: token, + mechanism: 'native', + }, + }, + }) ).rejects.toThrow(/no function selector/); }); it('more than 10 destination calls are refused', async () => { const s = universalSetup(); - const rt = mockRuntime(s.fake, { signer: ADDR.agent, resolvePrc20: () => token }); + const rt = mockRuntime(s.fake, { + signer: ADDR.agent, + resolvePrc20: () => token, + }); await expect( agenticSend(rt, s.ctx, { to: { address: ADDR.target, chain: CHAIN.ETHEREUM_SEPOLIA }, - data: Array.from({ length: 11 }, () => ({ to: ADDR.target, value: BigInt(0), data })), + data: Array.from({ length: 11 }, () => ({ + to: ADDR.target, + value: BigInt(0), + data, + })), }) ).rejects.toThrow(/at most 10/); }); }); - diff --git a/packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts b/packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts new file mode 100644 index 00000000..aeaef84d --- /dev/null +++ b/packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts @@ -0,0 +1,502 @@ +import { PublicKey } from '@solana/web3.js'; +import { bytesToHex, hexToBytes, numberToHex, type Hex } from 'viem'; +import { + decodeSvmTerms, + encodeSvmTerms, + validateSvmTerms, + SvmDataPinMode, + type SvmTermsWire, +} from '../codec/svm-terms'; +import { + deriveAgwSvmAta, + deriveAgwSvmCea, + deriveAgwSvmValueAccounts, + svmKey, + resolveAgwSvmRuleContext, +} from '../codec/svm-accounts'; +import { + encodeAgwSvmPayload, + parseAgwSvmPayload, + validateAgwSvmPayload, +} from '../execution/svm-payload'; +import { composeAgwSvmAction } from '../execution/svm-outbound'; +import { decodeFunctionData } from 'viem'; +import { UNIVERSAL_GATEWAY_PC } from '../../constants/abi'; +import { encodeSvmExecutePayload } from '../../orchestrator/payload-builders'; +import { ADDR } from './fake-chain'; + +const key = (byte: string) => `0x${byte.repeat(32)}` as Hex; +const CEA = key('11'), + GATEWAY = key('22'), + PROGRAM = key('33'), + ATA = key('44'); +const NOW = 1_700_000_000; +const base = (): SvmTermsWire => ({ + validUntil: NOW + 60, + expectedCEA: CEA, + gatewayProgram: GATEWAY, + assets: [{ token: ADDR.target, maxPerCall: BigInt(5), maxTotal: BigInt(10) }], + maxGasPerCall: BigInt(20), + ceaAccounts: [CEA, ATA], + programs: [ + { + program: PROGRAM, + discriminator: '0x0100000000000000', + discriminatorLen: 1, + dataless: false, + maxAccounts: 2, + }, + ], + pins: [ + { ruleIndex: 0, accountIndex: 0, expected: CEA }, + { ruleIndex: 0, accountIndex: 1, expected: ATA }, + ], + dataPins: [], +}); +const accounts = [ + { pubkey: CEA, isWritable: true }, + { pubkey: ATA, isWritable: true }, +]; + +describe('v4 internal SVM wire codec', () => { + it('round-trips ordered per-token caps and all four data-pin modes', () => { + const t = base(); + t.dataPins = [ + { + ruleIndex: 0, + fromEnd: false, + offset: 0, + offsetB: 0, + len: 1, + mode: 0, + expected: key('00'), + num: BigInt(0), + den: BigInt(0), + }, + { + ruleIndex: 0, + fromEnd: true, + offset: 8, + offsetB: 0, + len: 8, + mode: 1, + expected: numberToHex(5, { size: 32 }), + num: BigInt(0), + den: BigInt(0), + }, + { + ruleIndex: 0, + fromEnd: false, + offset: 1, + offsetB: 0, + len: 2, + mode: 2, + expected: numberToHex(65535, { size: 32 }), + num: BigInt(0), + den: BigInt(0), + }, + { + ruleIndex: 0, + fromEnd: true, + offset: 16, + offsetB: 8, + len: 8, + mode: 3, + expected: key('00'), + num: BigInt(9), + den: BigInt(10), + }, + ]; + t.assets = [ + ...t.assets, + { token: ADDR.other, maxPerCall: BigInt(0), maxTotal: BigInt(0) }, + ]; + expect(decodeSvmTerms(encodeSvmTerms(t, NOW))).toEqual(t); + }); + it.each([ + [ + 'expired', + (t: SvmTermsWire) => { + t.validUntil = NOW; + }, + ], + [ + 'zero CEA', + (t: SvmTermsWire) => { + t.expectedCEA = key('00'); + }, + ], + [ + 'empty assets', + (t: SvmTermsWire) => { + t.assets = []; + }, + ], + [ + 'duplicate tokens', + (t: SvmTermsWire) => { + t.assets = [t.assets[0], t.assets[0]]; + }, + ], + [ + 'system program', + (t: SvmTermsWire) => { + t.programs = [{ ...t.programs[0], program: key('00') }]; + }, + ], + [ + 'ambiguous prefixes', + (t: SvmTermsWire) => { + t.programs = [ + ...t.programs, + { + ...t.programs[0], + discriminator: '0x0102000000000000', + discriminatorLen: 2, + }, + ]; + }, + ], + [ + 'missing pin', + (t: SvmTermsWire) => { + t.pins = []; + }, + ], + [ + 'duplicate pin', + (t: SvmTermsWire) => { + t.pins = [t.pins[0], t.pins[0]]; + }, + ], + [ + 'CEA absent', + (t: SvmTermsWire) => { + t.ceaAccounts = [ATA]; + }, + ], + [ + 'fixed count outside bound', + (t: SvmTermsWire) => { + t.programs = [{ ...t.programs[0], maxAccounts: 65 }]; + }, + ], + ])('rejects %s before encoding', (_name, change) => { + const t = base(); + change(t); + expect(() => encodeSvmTerms(t, NOW)).toThrow( + expect.objectContaining({ code: 'INVALID_RULE' }) + ); + }); + it('refuses misleading integer/raw alignment and zero ratio denominators', () => { + const t = base(); + const p = { + ruleIndex: 0, + fromEnd: false, + offset: 1, + offsetB: 3, + len: 2, + mode: SvmDataPinMode.EQ, + expected: numberToHex(5, { size: 32 }), + num: BigInt(0), + den: BigInt(0), + }; + t.dataPins = [p]; + expect(() => validateSvmTerms(t, NOW)).toThrow(/left-aligned/); + t.dataPins = [ + { + ...p, + mode: SvmDataPinMode.GTE_LE, + expected: numberToHex(65536, { size: 32 }), + }, + ]; + expect(() => validateSvmTerms(t, NOW)).toThrow(/width/); + t.dataPins = [ + { + ...p, + mode: SvmDataPinMode.RATIO_GTE_LE, + num: BigInt(1), + den: BigInt(0), + }, + ]; + expect(() => validateSvmTerms(t, NOW)).toThrow(/ratio/); + }); +}); + +describe('wallet-scoped SVM value accounts', () => { + it('derives the exact PDA from wallet20 and the selected gateway', () => { + const result = deriveAgwSvmCea(ADDR.owner, GATEWAY); + const [expected, bump] = PublicKey.findProgramAddressSync( + [Buffer.from('push_identity'), Buffer.from(hexToBytes(ADDR.owner))], + new PublicKey(hexToBytes(GATEWAY)) + ); + expect(result).toEqual({ address: bytesToHex(expected.toBytes()), bump }); + expect(deriveAgwSvmCea(ADDR.agent, GATEWAY).address).not.toBe( + result.address + ); + expect(deriveAgwSvmCea(ADDR.owner, PROGRAM).address).not.toBe( + result.address + ); + expect(PublicKey.isOnCurve(hexToBytes(result.address))).toBe(false); + }); + it('resolved token caps cannot omit their corresponding protected ATAs', () => { + const cap = { + token: ADDR.target, + maxPerCall: BigInt(1), + maxTotal: BigInt(2), + }; + const result = resolveAgwSvmRuleContext( + ADDR.owner, + GATEWAY, + [ + { kind: 'native', cap }, + { kind: 'spl', cap: { ...cap, token: ADDR.other }, mint: PROGRAM }, + ], + [{ mint: ATA }] + ); + expect(result.ceaAccounts).toHaveLength(3); + expect(result.assets.map((a) => a.token)).toEqual([ + ADDR.target, + ADDR.other, + ]); + expect(() => deriveAgwSvmCea(ADDR.owner, key('00'))).toThrow( + /gateway program/ + ); + }); + it('includes input/output ATAs, deduplicates, and separates Token-2022 accounts', () => { + const t = { mint: PROGRAM }, + output = { mint: ATA }; + const derived = deriveAgwSvmValueAccounts( + ADDR.owner, + GATEWAY, + [t, t], + [output] + ); + expect(derived.ceaAccounts).toEqual([ + derived.expectedCEA, + deriveAgwSvmAta(derived.expectedCEA, t), + deriveAgwSvmAta(derived.expectedCEA, output), + ]); + const legacy = deriveAgwSvmAta(derived.expectedCEA, t), + token2022 = deriveAgwSvmAta(derived.expectedCEA, { + ...t, + tokenProgram: 'TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb', + }); + expect(token2022).not.toBe(legacy); + expect(svmKey(new PublicKey(hexToBytes(PROGRAM)).toBase58())).toBe(PROGRAM); + expect(() => + deriveAgwSvmAta(derived.expectedCEA, { mint: key('00') }) + ).toThrow(/native SOL/); + }); +}); + +describe('S12–S18 payload checks', () => { + it('matches the existing node encoder and parses every byte including writable flags', () => { + const payload = encodeAgwSvmPayload( + PROGRAM, + accounts, + new Uint8Array([1, 2, 3]) + ); + expect(payload).toBe( + encodeSvmExecutePayload({ + targetProgram: PROGRAM, + accounts, + ixData: new Uint8Array([1, 2, 3]), + instructionId: 2, + }) + ); + expect(parseAgwSvmPayload(payload)).toMatchObject({ + program: PROGRAM, + instructionData: new Uint8Array([1, 2, 3]), + accounts: [ + { pubkey: CEA, writableFlag: 1 }, + { pubkey: ATA, writableFlag: 1 }, + ], + }); + expect(validateAgwSvmPayload(base(), PROGRAM, payload)).toBe(0); + const raw = hexToBytes(payload); + raw[36] = 7; + expect(parseAgwSvmPayload(bytesToHex(raw)).accounts[0].writableFlag).toBe( + 7 + ); + expect(validateAgwSvmPayload(base(), PROGRAM, bytesToHex(raw))).toBe(0); // URP deliberately ignores flags. + }); + it.each([ + ['trailing data', (p: Hex) => `${p}00` as Hex, 'MalformedSvmPayload'], + ['truncated', (p: Hex) => p.slice(0, -2) as Hex, 'MalformedSvmPayload'], + [ + 'oversized count', + (p: Hex) => `0x00000041${p.slice(10)}` as Hex, + 'SvmAccountsOutOfRange', + ], + ])( + 'rejects %s with the corresponding contract error', + (_name, mutate, error) => { + const p = encodeAgwSvmPayload(PROGRAM, accounts, new Uint8Array([1])); + expect(() => parseAgwSvmPayload(mutate(p))).toThrow( + expect.objectContaining({ details: { contractError: error } }) + ); + } + ); + it('pins prevent key substitution and protected-account aliasing', () => { + const t = base(); + expect(() => + validateAgwSvmPayload( + t, + PROGRAM, + encodeAgwSvmPayload( + PROGRAM, + [{ ...accounts[0], pubkey: GATEWAY }, accounts[1]], + new Uint8Array([1]) + ) + ) + ).toThrow(/SvmAccountPinMismatch/); + t.programs = [{ ...t.programs[0], maxAccounts: 0 }]; + expect(() => + validateAgwSvmPayload( + t, + PROGRAM, + encodeAgwSvmPayload( + PROGRAM, + [...accounts, accounts[0]], + new Uint8Array([1]) + ) + ) + ).toThrow(/CeaAccountAtUnpinnedIndex/); + expect(() => + validateAgwSvmPayload( + t, + GATEWAY, + encodeAgwSvmPayload(PROGRAM, accounts, new Uint8Array([1])) + ) + ).toThrow(/RecipientTargetMismatch/); + }); + it('enforces little-endian floors/ceilings, from-end offsets, ratios and exact byte pins', () => { + const t = base(); + t.dataPins = [ + { + ruleIndex: 0, + fromEnd: true, + offset: 4, + offsetB: 2, + len: 2, + mode: 3, + expected: key('00'), + num: BigInt(9), + den: BigInt(10), + }, + ]; + const make = (out: number, input: number) => + encodeAgwSvmPayload( + PROGRAM, + accounts, + new Uint8Array([1, out & 255, out >> 8, input & 255, input >> 8]) + ); + expect(validateAgwSvmPayload(t, PROGRAM, make(90, 100))).toBe(0); + expect(() => validateAgwSvmPayload(t, PROGRAM, make(89, 100))).toThrow( + /SvmDataRatioNotMet/ + ); + t.dataPins = [ + { + ...t.dataPins[0], + fromEnd: false, + offset: 1, + mode: 1, + expected: numberToHex(90, { size: 32 }), + }, + ]; + expect(() => validateAgwSvmPayload(t, PROGRAM, make(89, 100))).toThrow( + /SvmDataFloorNotMet/ + ); + t.dataPins = [{ ...t.dataPins[0], mode: 2 }]; + expect(() => validateAgwSvmPayload(t, PROGRAM, make(91, 100))).toThrow( + /SvmDataCeilingExceeded/ + ); + t.dataPins = [ + { ...t.dataPins[0], mode: 0, expected: `0x5a00${'00'.repeat(30)}` }, + ]; + expect(validateAgwSvmPayload(t, PROGRAM, make(90, 100))).toBe(0); + expect(() => + validateAgwSvmPayload( + t, + PROGRAM, + encodeAgwSvmPayload(PROGRAM, accounts, new Uint8Array([1])) + ) + ).toThrow(/SvmDataTooShortForPin/); + }); +}); + +describe('internal SVM outbound action', () => { + const config = () => ({ + ...base(), + initialized: true, + maxGasPerCall: BigInt(100), + assets: [ + { + token: ADDR.target, + maxPerCall: BigInt(5), + maxTotal: BigInt(10), + spent: BigInt(2), + }, + ], + }); + const input = () => ({ + wallet: ADDR.owner, + gateway: ADDR.gateway, + token: ADDR.target, + amount: BigInt(3), + recipient: PROGRAM, + payload: encodeAgwSvmPayload(PROGRAM, accounts, new Uint8Array([1])), + gasLimit: BigInt(200000), + protocolFee: BigInt(2), + maxPCForGas: BigInt(3), + }); + it('uses the program recipient, wallet refund and quoted PC while preserving the exact payload', () => { + const i = input(), + result = composeAgwSvmAction(i, config(), NOW); + const request = decodeFunctionData({ + abi: UNIVERSAL_GATEWAY_PC, + data: result.data, + }).args![0]; + expect(result.target).toBe(ADDR.gateway); + expect(result.value).toBe(BigInt(5)); + expect(request).toMatchObject({ + recipient: PROGRAM, + revertRecipient: ADDR.owner, + amount: BigInt(3), + payload: i.payload, + gasPrice: BigInt(0), + }); + }); + it('rejects caps, zero gas and unknown assets before signing', () => { + expect(() => + composeAgwSvmAction({ ...input(), amount: BigInt(6) }, config(), NOW) + ).toThrow(/AmountExceedsCap/); + expect(() => + composeAgwSvmAction({ ...input(), token: ADDR.other }, config(), NOW) + ).toThrow(/AssetNotAllowed/); + expect(() => + composeAgwSvmAction({ ...input(), maxPCForGas: BigInt(0) }, config(), NOW) + ).toThrow(/UncappedGasSwapRejected/); + expect(() => + composeAgwSvmAction( + { ...input(), maxPCForGas: BigInt(100) }, + config(), + NOW + ) + ).toThrow(/PCValueExceedsCap/); + const c = config(); + c.assets[0].spent = BigInt(9); + expect(() => composeAgwSvmAction(input(), c, NOW)).toThrow( + /TotalSpendCapExceeded/ + ); + c.assets[0].maxPerCall = BigInt(2) ** BigInt(256) - BigInt(1); + expect(() => + composeAgwSvmAction( + { ...input(), amount: BigInt(2) ** BigInt(64) }, + c, + NOW + ) + ).toThrow(/AmountExceedsU64/); + }); +}); diff --git a/packages/core/src/lib/agentic/agentic.types.ts b/packages/core/src/lib/agentic/agentic.types.ts index 30d814a7..c4c6a34d 100644 --- a/packages/core/src/lib/agentic/agentic.types.ts +++ b/packages/core/src/lib/agentic/agentic.types.ts @@ -49,13 +49,16 @@ export type ArgPin = | { arg: number; expected: AgenticHex | AgenticAddress | bigint } | { offset: number; expected: AgenticHex }; -export type AmountLimit = ({ arg: number } | { offset: number }) & { maxPerCall: bigint; maxTotal?: bigint }; +export type AmountLimit = ({ arg: number } | { offset: number }) & { + maxPerCall: bigint; + maxTotal?: bigint; +}; export interface AssetCap { /** The destination chain's token (MOVEABLE constant) or native marker. */ token: MoveableToken | AgenticAddress; maxPerCall: bigint; - /** Omitted = 0 = unlimited in the proposed multi-asset ABI — provisional, A03/A05. */ + /** Omitted = uint256 maximum (unlimited). Explicit zero forbids movement. */ maxTotal?: bigint; } @@ -64,6 +67,8 @@ export interface AllowedCall { selector: Selector; /** Argument index whose address must be the wallet's destination account. */ beneficiary?: number; + /** Exact stored calldata offset for lossless decoded rules; mutually exclusive with beneficiary. Public form pending H4.5. */ + beneficiaryOffset?: number; /** Default 0 — provisional, A03. */ maxValue?: bigint; } @@ -140,7 +145,9 @@ export interface AgenticWallet { label: string, opts?: { progressHook?: AgenticProgressHook } ): Promise; - checkpoints(opts?: { sinceBlock?: bigint }): Promise<{ checkpoints: Checkpoint[] }>; + checkpoints(opts?: { + sinceBlock?: bigint; + }): Promise<{ checkpoints: Checkpoint[] }>; rules: { /** Enabled rules only; expired-but-enabled rules remain visible. No public spend counters. */ list(): Promise<{ rules: RulesRecord[] }>; @@ -153,17 +160,25 @@ export interface AgenticWallet { update(params: { rules: { rulesId: AgenticHex; rule: Rule }[]; progressHook?: AgenticProgressHook; - }): Promise<{ rules: { rulesId: AgenticHex; replaced: AgenticHex }[]; tx: UniversalTxResponse }>; + }): Promise<{ + rules: { rulesId: AgenticHex; replaced: AgenticHex }[]; + tx: UniversalTxResponse; + }>; revoke( rulesIds: AgenticHex[], opts?: { progressHook?: AgenticProgressHook } ): Promise; - revoke(params: { all: true; progressHook?: AgenticProgressHook }): Promise; + revoke(params: { + all: true; + progressHook?: AgenticProgressHook; + }): Promise; }; } export interface AgenticNamespace { - derive(opts?: { index?: number }): Promise<{ address: AgenticAddress; index: number; deployed: boolean }>; + derive(opts?: { + index?: number; + }): Promise<{ address: AgenticAddress; index: number; deployed: boolean }>; create(label: string, options: CreateOptions): Promise; list(): Promise<{ wallets: WalletSummary[] }>; wallet(address: AgenticAddress): AgenticWallet; @@ -188,9 +203,17 @@ export interface AgenticTxMetadata { * transfer. Replay uses the same representation; it cannot recover which * calls were supplied explicitly versus generated from funds. */ - destinationCalls?: readonly { to: AgenticAddress; data: AgenticHex; value: bigint }[]; + destinationCalls?: readonly { + to: AgenticAddress; + data: AgenticHex; + value: bigint; + }[]; /** Ordered actions in a native agent batch; to/data/value summarize its first action. */ - nativeCalls?: readonly { to: AgenticAddress; data: AgenticHex; value: bigint }[]; + nativeCalls?: readonly { + to: AgenticAddress; + data: AgenticHex; + value: bigint; + }[]; /** Account the signer's transaction actually called (wallet or outer sender account). */ rawTo: string; /** Calldata the signer's transaction actually carried. */ diff --git a/packages/core/src/lib/agentic/capabilities.ts b/packages/core/src/lib/agentic/capabilities.ts index 24e211a7..f8564176 100644 --- a/packages/core/src/lib/agentic/capabilities.ts +++ b/packages/core/src/lib/agentic/capabilities.ts @@ -21,7 +21,7 @@ export enum AgenticCapability { ASSERT_SPENT_NATIVE = 'assertSpentNative', /** checkpointCount + Checkpointed events. */ CHECKPOINTS = 'checkpoints', - /** Agent-door EVM outbound composition against this generation's single-asset terms. */ + /** Agent-door EVM outbound composition against v4 per-token caps. */ UNIVERSAL_EVM_OUTBOUND = 'universalEvmOutbound', /** Target UniversalRule (assets[] / maxGasPerCall) encode/decode. A05/A07. */ UNIVERSAL_EVM_RULES = 'universalEvmRules', @@ -33,31 +33,36 @@ export enum AgenticCapability { GRANT_REF = 'grantRef', /** Editable wallet label (setLabel / LabelSet). A07. */ SET_LABEL = 'setLabel', - } /** Why each target capability is unavailable when a generation lacks it. */ export const CAPABILITY_DEPENDENCY: Record = { - [AgenticCapability.WALLET_READS]: 'no verified AGW deployment for this network (A07)', - [AgenticCapability.ACTIVE_RULE_READS]: 'no verified AGW deployment for this network (A07)', - [AgenticCapability.OWNER_EXECUTE]: 'no verified AGW deployment for this network (A07)', - [AgenticCapability.AGENT_EXECUTE]: 'no verified AGW deployment for this network (A07)', - [AgenticCapability.NATIVE_RULES]: 'no verified AGW deployment for this network (A07)', - [AgenticCapability.ASSERT_SPENT_NATIVE]: 'no verified AGW deployment for this network (A07)', - [AgenticCapability.CHECKPOINTS]: 'no verified AGW deployment for this network (A07)', + [AgenticCapability.WALLET_READS]: + 'no verified AGW deployment for this network (A07)', + [AgenticCapability.ACTIVE_RULE_READS]: + 'no verified AGW deployment for this network (A07)', + [AgenticCapability.OWNER_EXECUTE]: + 'no verified AGW deployment for this network (A07)', + [AgenticCapability.AGENT_EXECUTE]: + 'no verified AGW deployment for this network (A07)', + [AgenticCapability.NATIVE_RULES]: + 'no verified AGW deployment for this network (A07)', + [AgenticCapability.ASSERT_SPENT_NATIVE]: + 'no verified AGW deployment for this network (A07)', + [AgenticCapability.CHECKPOINTS]: + 'no verified AGW deployment for this network (A07)', [AgenticCapability.UNIVERSAL_EVM_OUTBOUND]: 'the selected generation has no verified multi-asset outbound token resolution (A05/A07)', [AgenticCapability.UNIVERSAL_EVM_RULES]: - 'the assets[]/maxGasPerCall wire format has no matching contract artifacts or vectors (A05/A07)', + 'EVM universal rules are unavailable for the selected SDK configuration', [AgenticCapability.ASSERT_SPENT_UNIVERSAL_MULTI]: - 'per-token expected-spend assertion ABI is not delivered (A05)', + 'universal expected-spend assertions are unavailable for this configuration', [AgenticCapability.UNIVERSAL_SVM_RULES]: - 'SVM destination rule shape and capability are unconfirmed (A05/A07, H4.4)', + 'SVM wire types are delivered; public SDK mapping/composition remains pending (H4.4)', [AgenticCapability.GRANT_REF]: 'the selected generation has no grant reference parameter/event (A07)', [AgenticCapability.SET_LABEL]: 'the selected generation has no editable label (A07; labels are deploy-time only)', - }; export function hasCapability( diff --git a/packages/core/src/lib/agentic/codec/defaults.ts b/packages/core/src/lib/agentic/codec/defaults.ts index 4a1054fa..aa915230 100644 --- a/packages/core/src/lib/agentic/codec/defaults.ts +++ b/packages/core/src/lib/agentic/codec/defaults.ts @@ -11,21 +11,37 @@ export const UINT256_MAX = BigInt(2) ** BigInt(256) - BigInt(1); export interface DefaultRow { value: bigint; meaning: string; - source: 'A03'; + source: 'A03' | 'v4'; } export const AGENTIC_DEFAULTS = { native: { - maxValuePerCall: { value: BigInt(0), meaning: 'no native value transfer', source: 'A03' }, - maxValueTotal: { value: BigInt(0), meaning: 'no native value transfer', source: 'A03' }, - amountMaxTotal: { value: UINT256_MAX, meaning: 'unlimited metered total', source: 'A03' }, - maxCalls: { value: BigInt(0), meaning: 'unlimited calls until expiry', source: 'A03' }, + maxValuePerCall: { + value: BigInt(0), + meaning: 'no native value transfer', + source: 'A03', + }, + maxValueTotal: { + value: BigInt(0), + meaning: 'no native value transfer', + source: 'A03', + }, + amountMaxTotal: { + value: UINT256_MAX, + meaning: 'unlimited metered total', + source: 'A03', + }, + maxCalls: { + value: BigInt(0), + meaning: 'unlimited calls until expiry', + source: 'A03', + }, }, universal: { assetMaxTotal: { - value: BigInt(0), - meaning: 'unlimited total in the proposed multi-asset ABI', - source: 'A03', + value: UINT256_MAX, + meaning: 'unlimited total; explicit zero forbids movement', + source: 'v4', }, allowedCallMaxValue: { value: BigInt(0), @@ -35,6 +51,9 @@ export const AGENTIC_DEFAULTS = { }, } as const satisfies Record>; -export function withDefault(value: bigint | undefined, row: DefaultRow): bigint { +export function withDefault( + value: bigint | undefined, + row: DefaultRow +): bigint { return value === undefined ? row.value : value; } diff --git a/packages/core/src/lib/agentic/codec/historical/e704d5b-universal.ts b/packages/core/src/lib/agentic/codec/historical/e704d5b-universal.ts deleted file mode 100644 index 48f1a6ec..00000000 --- a/packages/core/src/lib/agentic/codec/historical/e704d5b-universal.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { - decodeAbiParameters, - encodeAbiParameters, - type AbiParameter, - type Address, - type Hex, -} from 'viem'; - -/** - * HISTORICAL, INTERNAL-ONLY single-asset UniversalTerms codec for the reviewed - * e704d5b generation (Types.sol:217-225). It operates on wire terms, never on - * the public `UniversalRule` (assets[]), and is not exported from the package. - * It exists so the local contract harness and the agent-door outbound composer - * can be exercised against real pinned contracts. Do not route the advertised - * public API through it (A05). - */ -export interface UniversalTermsE704d5b { - validUntil: number; - expectedCEA: Address; - asset: Address; - maxAmountPerCall: bigint; - /** type(uint256).max = unlimited at e704d5b (differs from the proposed 0-unlimited). */ - maxAmountTotal: bigint; - maxPCPerCall: bigint; - allowedCalls: readonly { - target: Address; - selector: Hex; - beneficiaryOffset: number; - hasBeneficiary: boolean; - maxValue: bigint; - }[]; -} - -export const UNIVERSAL_TERMS_E704D5B_PARAM: AbiParameter = { - type: 'tuple', - components: [ - { name: 'validUntil', type: 'uint48' }, - { name: 'expectedCEA', type: 'address' }, - { name: 'asset', type: 'address' }, - { name: 'maxAmountPerCall', type: 'uint256' }, - { name: 'maxAmountTotal', type: 'uint256' }, - { name: 'maxPCPerCall', type: 'uint256' }, - { - name: 'allowedCalls', - type: 'tuple[]', - components: [ - { name: 'target', type: 'address' }, - { name: 'selector', type: 'bytes4' }, - { name: 'beneficiaryOffset', type: 'uint16' }, - { name: 'hasBeneficiary', type: 'bool' }, - { name: 'maxValue', type: 'uint256' }, - ], - }, - ], -}; - -export function encodeUniversalTermsE704d5b(terms: UniversalTermsE704d5b): Hex { - return encodeAbiParameters([UNIVERSAL_TERMS_E704D5B_PARAM], [terms]); -} - -export function decodeUniversalTermsE704d5b(body: Hex): UniversalTermsE704d5b { - const [terms] = decodeAbiParameters([UNIVERSAL_TERMS_E704D5B_PARAM], body); - return terms as unknown as UniversalTermsE704d5b; -} diff --git a/packages/core/src/lib/agentic/codec/ids.ts b/packages/core/src/lib/agentic/codec/ids.ts index c24bbf16..49448711 100644 --- a/packages/core/src/lib/agentic/codec/ids.ts +++ b/packages/core/src/lib/agentic/codec/ids.ts @@ -12,7 +12,7 @@ import { import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; /** - * Pure identity helpers mirroring the pinned AGW generation (e704d5b): + * Pure identity helpers mirroring the pinned AGW generation (v4): * smartsessions IdLib.toActionId / toConfigId / toPermissionId and * AGWFactory._predict (OZ Clones immutable-args CREATE2). * Every input that changes the result is explicit — validator, factory and @@ -26,7 +26,9 @@ export function actionId(target: Address, selector: Hex): Hex { /** keccak256(abi.encodePacked(wallet, keccak256(abi.encodePacked(rulesId, actionId)))). */ export function configId(wallet: Address, rulesId: Hex, action: Hex): Hex { - const inner = keccak256(encodePacked(['bytes32', 'bytes32'], [rulesId, action])); + const inner = keccak256( + encodePacked(['bytes32', 'bytes32'], [rulesId, action]) + ); return keccak256(encodePacked(['address', 'bytes32'], [wallet, inner])); } @@ -46,12 +48,19 @@ export function rulesId(ctx: { grantNonce: bigint; }): Hex { if (ctx.grantNonce < BigInt(0) || ctx.grantNonce >= BigInt(2) ** BigInt(64)) { - throw new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, 'grantNonce must fit uint64'); + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'grantNonce must fit uint64' + ); } return keccak256( encodeAbiParameters( [{ type: 'address' }, { type: 'bytes' }, { type: 'bytes32' }], - [ctx.validator, agentConfig(ctx.agent), numberToHex(ctx.grantNonce, { size: 32 })] + [ + ctx.validator, + agentConfig(ctx.agent), + numberToHex(ctx.grantNonce, { size: 32 }), + ] ) ); } @@ -71,10 +80,16 @@ export function deriveWallet(ctx: { }): Address { const index = BigInt(ctx.index); if (index < BigInt(0) || index > UINT96_MAX) { - throw new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, 'wallet index must fit uint96'); + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'wallet index must fit uint96' + ); } const salt = keccak256( - encodeAbiParameters([{ type: 'address' }, { type: 'uint96' }], [ctx.owner, index]) + encodeAbiParameters( + [{ type: 'address' }, { type: 'uint96' }], + [ctx.owner, index] + ) ); const args = encodePacked(['address', 'address'], [ctx.owner, ctx.factory]); const argsLength = (args.length - 2) / 2; diff --git a/packages/core/src/lib/agentic/codec/native.ts b/packages/core/src/lib/agentic/codec/native.ts index 2b79d1c9..81e5b160 100644 --- a/packages/core/src/lib/agentic/codec/native.ts +++ b/packages/core/src/lib/agentic/codec/native.ts @@ -12,21 +12,30 @@ import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; import type { AgenticHex, NativeRule } from '../agentic.types'; import { argumentOffset, encodeArgWord, rawOffset } from './abi-layout'; import { AGENTIC_DEFAULTS, UINT256_MAX, withDefault } from './defaults'; -import { parseSelector, VALUE_ONLY_SELECTOR, type ParsedSelector } from './selectors'; +import { + parseSelector, + VALUE_ONLY_SELECTOR, + type ParsedSelector, +} from './selectors'; -/** URP native limits at e704d5b (Types.sol MAX_PINS, AGW MAX_NATIVE_ACTIONS). */ +/** URP native limits at v4 (Types.sol MAX_PINS, AGW MAX_NATIVE_ACTIONS). */ export const MAX_PINS = 8; const UINT32_MAX = 2 ** 32 - 1; const UINT48_MAX = 2 ** 48 - 1; -/** NativeTerms (Types.sol:354-363 at e704d5b). */ +/** NativeTerms (Types.sol:354-363 at v4). */ export interface NativeTermsWire { validUntil: number; target: Address; selector: Hex; maxValuePerCall: bigint; maxValueTotal: bigint; - amount: { enabled: boolean; offset: number; maxPerCall: bigint; maxTotal: bigint }; + amount: { + enabled: boolean; + offset: number; + maxPerCall: bigint; + maxTotal: bigint; + }; maxCalls: number; pins: readonly { offset: number; expected: Hex }[]; } @@ -61,12 +70,21 @@ export const NATIVE_TERMS_PARAM: AbiParameter = { ], }; -function invalid(message: string, details?: Record): AgenticError { - return new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, message, { details }); +function invalid( + message: string, + details?: Record +): AgenticError { + return new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, message, { + details, + }); } function assertUint(value: bigint, bits: number, field: string): void { - if (typeof value !== 'bigint' || value < BigInt(0) || value >= BigInt(2) ** BigInt(bits)) { + if ( + typeof value !== 'bigint' || + value < BigInt(0) || + value >= BigInt(2) ** BigInt(bits) + ) { throw invalid(`${field} must be a uint${bits} bigint`); } } @@ -81,7 +99,10 @@ export function nativeRuleToTerms( rule: NativeRule, ctx: NativeEncodeContext ): { terms: NativeTermsWire; parsed: ParsedSelector } { - if (!isAddress(rule.target, { strict: false }) || /^0x0{40}$/i.test(rule.target)) { + if ( + !isAddress(rule.target, { strict: false }) || + /^0x0{40}$/i.test(rule.target) + ) { throw invalid('native rule target must be a non-zero address'); } if ( @@ -89,9 +110,12 @@ export function nativeRuleToTerms( rule.validUntil <= ctx.nowSeconds || rule.validUntil > UINT48_MAX ) { - throw invalid('validUntil must be a future unix timestamp in seconds (uint48)', { - validUntil: rule.validUntil, - }); + throw invalid( + 'validUntil must be a future unix timestamp in seconds (uint48)', + { + validUntil: rule.validUntil, + } + ); } const parsed = parseSelector(rule.selector); const pinsIn = rule.pins ?? []; @@ -99,22 +123,34 @@ export function nativeRuleToTerms( throw invalid('a value-only rule cannot carry pins or an amount rule'); } if (pinsIn.length > MAX_PINS) { - throw invalid(`at most ${MAX_PINS} pins are allowed`, { pins: pinsIn.length }); + throw invalid(`at most ${MAX_PINS} pins are allowed`, { + pins: pinsIn.length, + }); } const pins = pinsIn.map((p, i) => { if ('offset' in p) { - if (typeof p.expected !== 'string' || !isHex(p.expected) || p.expected.length !== 66) { - throw invalid(`pins[${i}].expected must be the exact 32-byte calldata word in offset form`); + if ( + typeof p.expected !== 'string' || + !isHex(p.expected) || + p.expected.length !== 66 + ) { + throw invalid( + `pins[${i}].expected must be the exact 32-byte calldata word in offset form` + ); } - return { offset: rawOffset(p.offset, `pins[${i}]`), expected: p.expected.toLowerCase() as Hex }; + return { + offset: rawOffset(p.offset, `pins[${i}]`), + expected: p.expected.toLowerCase() as Hex, + }; } const offset = argumentOffset(parsed.inputs, p.arg, `pins[${i}]`); const param = (parsed.inputs as readonly AbiParameter[])[p.arg]; return { offset, expected: encodeArgWord(param, p.expected, `pins[${i}]`) }; }); const offsets = new Set(pins.map((p) => p.offset)); - if (offsets.size !== pins.length) throw invalid('two pins address the same argument'); + if (offsets.size !== pins.length) + throw invalid('two pins address the same argument'); let amount: NativeTermsWire['amount'] = { enabled: false, @@ -130,22 +166,40 @@ export function nativeRuleToTerms( offset = argumentOffset(parsed.inputs, rule.amount.arg, 'amount'); const param = (parsed.inputs as readonly AbiParameter[])[rule.amount.arg]; if (!/^uint\d*$/.test(param.type)) { - throw invalid(`amount argument must be an unsigned integer, got ${param.type}`); + throw invalid( + `amount argument must be an unsigned integer, got ${param.type}` + ); } } if (offsets.has(offset)) throw invalid('amount argument is also pinned'); assertUint(rule.amount.maxPerCall, 256, 'amount.maxPerCall'); - const maxTotal = withDefault(rule.amount.maxTotal, AGENTIC_DEFAULTS.native.amountMaxTotal); + const maxTotal = withDefault( + rule.amount.maxTotal, + AGENTIC_DEFAULTS.native.amountMaxTotal + ); assertUint(maxTotal, 256, 'amount.maxTotal'); - amount = { enabled: true, offset, maxPerCall: rule.amount.maxPerCall, maxTotal }; + amount = { + enabled: true, + offset, + maxPerCall: rule.amount.maxPerCall, + maxTotal, + }; } - const maxValuePerCall = withDefault(rule.maxValuePerCall, AGENTIC_DEFAULTS.native.maxValuePerCall); - const maxValueTotal = withDefault(rule.maxValueTotal, AGENTIC_DEFAULTS.native.maxValueTotal); + const maxValuePerCall = withDefault( + rule.maxValuePerCall, + AGENTIC_DEFAULTS.native.maxValuePerCall + ); + const maxValueTotal = withDefault( + rule.maxValueTotal, + AGENTIC_DEFAULTS.native.maxValueTotal + ); assertUint(maxValuePerCall, 256, 'maxValuePerCall'); assertUint(maxValueTotal, 256, 'maxValueTotal'); const maxCalls = - rule.maxCalls === undefined ? Number(AGENTIC_DEFAULTS.native.maxCalls.value) : rule.maxCalls; + rule.maxCalls === undefined + ? Number(AGENTIC_DEFAULTS.native.maxCalls.value) + : rule.maxCalls; if (!Number.isInteger(maxCalls) || maxCalls < 0 || maxCalls > UINT32_MAX) { throw invalid('maxCalls must be a uint32 integer'); } @@ -180,7 +234,11 @@ export function decodeNativeTerms(body: Hex): NativeTermsWire { * raw `offset` form (never a guessed argument index) and `selector` is the * 4-byte hex. The result re-encodes to the same terms. */ -export function nativeTermsToRule(terms: NativeTermsWire, agent: Address, ref: AgenticHex): NativeRule { +export function nativeTermsToRule( + terms: NativeTermsWire, + agent: Address, + ref: AgenticHex +): NativeRule { const rule: NativeRule = { agent: getAddress(agent), target: getAddress(terms.target), diff --git a/packages/core/src/lib/agentic/codec/rules.ts b/packages/core/src/lib/agentic/codec/rules.ts index 368373a7..54b981c8 100644 --- a/packages/core/src/lib/agentic/codec/rules.ts +++ b/packages/core/src/lib/agentic/codec/rules.ts @@ -1,10 +1,22 @@ -import { getAddress, isAddress, keccak256, toBytes, type Address, type Hex } from 'viem'; +import { + getAddress, + isAddress, + keccak256, + toBytes, + type Address, + type Hex, +} from 'viem'; import { AgenticCapability, requireCapability } from '../capabilities'; import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; import type { NativeRule, Rule, UniversalRule } from '../agentic.types'; -import { encodeNativeTerms, nativeRuleToTerms, type NativeTermsWire } from './native'; +import { + encodeNativeTerms, + nativeRuleToTerms, + type NativeTermsWire, +} from './native'; import { buildSession, encodeEnvelope, type SessionWire } from './session'; -import { encodeUniversalRule } from './universal'; +import { encodeUniversalRule, type ResolvedUniversalRule } from './universal'; +import type { UniversalTermsWire } from './universal-terms'; export function isUniversalRule(rule: Rule): rule is UniversalRule { return (rule as UniversalRule).chainNamespace !== undefined; @@ -26,6 +38,8 @@ export interface RuleEncodeContext { rulesPolicy: Address; capabilities: ReadonlySet; nowSeconds: number; + gateway?: Address; + universal?: ReadonlyMap; /** * Addresses a native rule may never target (AGW _requireGrantableTarget / * URP NativeTargetIsGateway): wallet, engine, policy, validator, factory, @@ -41,35 +55,38 @@ export interface PreparedRule { session: SessionWire; /** Native terms when the rule is native (used for previews and assertions). */ nativeTerms?: NativeTermsWire; + universalTerms?: UniversalTermsWire; } -/** - * Validate and encode rules before any signature (spec 1.b checks plus - * codec validation). `owner` is the wallet owner's Push address and - * `existing` the currently enabled (agent, chain) pairs that are NOT being - * replaced — both feed the AGENT_IS_OWNER / DUPLICATE_RULE checks. - */ +/** Validate before signing. V4 permits several grants for the same agent/chain. */ export function prepareRules( rules: readonly Rule[], ctx: RuleEncodeContext & { /** Wallet owner; when given, an agent equal to it is AGENT_IS_OWNER. */ owner?: Address; - existing?: readonly { agent: Address; chainNamespace: string; rulesId: Hex }[]; } ): PreparedRule[] { if (!Array.isArray(rules)) { - throw new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, 'rules must be an array'); - } - const seen = new Map(); - for (const e of ctx.existing ?? []) { - seen.set(pairKey(e.agent, e.chainNamespace), `existing rule ${e.rulesId}`); + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'rules must be an array' + ); } return rules.map((rule, i) => { if (!rule || typeof rule !== 'object') { - throw new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, `rules[${i}] is not an object`); + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + `rules[${i}] is not an object` + ); } - if (!isAddress(rule.agent, { strict: false }) || /^0x0{40}$/i.test(rule.agent)) { - throw new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, `rules[${i}].agent must be a non-zero Push address`); + if ( + !isAddress(rule.agent, { strict: false }) || + /^0x0{40}$/i.test(rule.agent) + ) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + `rules[${i}].agent must be a non-zero Push address` + ); } const agent = getAddress(rule.agent); if (ctx.owner && agent === getAddress(ctx.owner)) { @@ -79,22 +96,15 @@ export function prepareRules( ); } const chainNamespace = ruleChain(rule, ctx.pushChainNamespace); - if (isUniversalRule(rule) && rule.chainNamespace === ctx.pushChainNamespace) { + if ( + isUniversalRule(rule) && + rule.chainNamespace === ctx.pushChainNamespace + ) { throw new AgenticError( AGENTIC_ERROR_CODE.INVALID_RULE, `rules[${i}] names the connected Push chain; omit chainNamespace for a native rule` ); } - const key = pairKey(agent, chainNamespace); - const clash = seen.get(key); - if (clash) { - throw new AgenticError( - AGENTIC_ERROR_CODE.DUPLICATE_RULE, - `rules[${i}] repeats agent ${agent} on ${chainNamespace} (${clash})`, - { hint: 'One rule per agent per chain. Use rules.update to replace an existing rule.' } - ); - } - seen.set(key, `rules[${i}]`); if (rule.ref !== undefined) { requireCapability(ctx.capabilities, AgenticCapability.GRANT_REF); } @@ -130,7 +140,3 @@ export function prepareRules( return { rule, agent, chainNamespace, session, nativeTerms: terms }; }); } - -function pairKey(agent: Address, chainNamespace: string): string { - return `${agent.toLowerCase()}|${chainNamespace}`; -} diff --git a/packages/core/src/lib/agentic/codec/session.ts b/packages/core/src/lib/agentic/codec/session.ts index 40f970f2..0cbe5d0a 100644 --- a/packages/core/src/lib/agentic/codec/session.ts +++ b/packages/core/src/lib/agentic/codec/session.ts @@ -6,13 +6,13 @@ import { type Address, type Hex, } from 'viem'; -import { AGW_ABI } from '../contracts/abi/e704d5b'; +import { AGW_ABI } from '../contracts/abi/v4'; import { agentConfig } from './ids'; import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; /** * The smartsessions `Session` a grant carries (DataTypes.sol:56-86, pinned - * e704d5b). The wallet overwrites `salt` with its grant nonce, so the value + * v4). The wallet overwrites `salt` with its grant nonce, so the value * sent is irrelevant; it is always zero here. */ export interface SessionWire { @@ -21,7 +21,10 @@ export interface SessionWire { salt: Hex; userOpPolicies: readonly { policy: Address; initData: Hex }[]; erc7739Policies: { - allowedERC7739Content: readonly { appDomainSeparator: Hex; contentNames: readonly string[] }[]; + allowedERC7739Content: readonly { + appDomainSeparator: Hex; + contentNames: readonly string[]; + }[]; erc1271Policies: readonly { policy: Address; initData: Hex }[]; }; actions: readonly { @@ -39,22 +42,36 @@ export const SESSION_PARAM: AbiParameter = getAbiItem({ const ZERO_SALT = `0x${'00'.repeat(32)}` as Hex; -/** URP envelope: abi.encode(string chainNamespace, bytes body). */ +export const ENVELOPE_VERSION = 1; + +/** V4 URP envelope: abi.encode(uint16(1), string chainNamespace, bytes body). */ export function encodeEnvelope(chainNamespace: string, body: Hex): Hex { - return encodeAbiParameters([{ type: 'string' }, { type: 'bytes' }], [chainNamespace, body]); + return encodeAbiParameters( + [{ type: 'uint16' }, { type: 'string' }, { type: 'bytes' }], + [ENVELOPE_VERSION, chainNamespace, body] + ); } -export function decodeEnvelope(initData: Hex): { chainNamespace: string; body: Hex } { +export function decodeEnvelope(initData: Hex): { + chainNamespace: string; + body: Hex; +} { try { - const [chainNamespace, body] = decodeAbiParameters( - [{ type: 'string' }, { type: 'bytes' }], + const [version, chainNamespace, body] = decodeAbiParameters( + [{ type: 'uint16' }, { type: 'string' }, { type: 'bytes' }], initData ); + if (version !== ENVELOPE_VERSION) + throw new Error(`unsupported rules envelope version ${version}`); return { chainNamespace, body }; } catch (cause) { - throw new AgenticError(AGENTIC_ERROR_CODE.RULE_READ_FAILED, 'malformed URP envelope', { - cause, - }); + throw new AgenticError( + AGENTIC_ERROR_CODE.RULE_READ_FAILED, + 'malformed URP envelope', + { + cause, + } + ); } } @@ -88,8 +105,12 @@ export function decodeSession(bytes: Hex): SessionWire { const [session] = decodeAbiParameters([SESSION_PARAM], bytes); return session as unknown as SessionWire; } catch (cause) { - throw new AgenticError(AGENTIC_ERROR_CODE.RULE_READ_FAILED, 'malformed Session encoding', { - cause, - }); + throw new AgenticError( + AGENTIC_ERROR_CODE.RULE_READ_FAILED, + 'malformed Session encoding', + { + cause, + } + ); } } diff --git a/packages/core/src/lib/agentic/codec/svm-accounts.ts b/packages/core/src/lib/agentic/codec/svm-accounts.ts new file mode 100644 index 00000000..75452b96 --- /dev/null +++ b/packages/core/src/lib/agentic/codec/svm-accounts.ts @@ -0,0 +1,104 @@ +import { PublicKey } from '@solana/web3.js'; +import { + bytesToHex, + getAddress, + hexToBytes, + type Address, + type Hex, +} from 'viem'; +import { exactHex, SVM_LIMITS, svmInvalid } from './svm-terms'; +import type { AssetCapWire } from './universal-terms'; + +const SPL_TOKEN = new PublicKey('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'); +const TOKEN_2022 = new PublicKey('TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb'); +const ASSOCIATED_TOKEN = new PublicKey( + 'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL' +); + +export function svmKey(value: string): Hex { + try { + if (value.startsWith('0x')) { + exactHex(value, 32, 'pubkey'); + return bytesToHex(new PublicKey(hexToBytes(value)).toBytes()); + } + return bytesToHex(new PublicKey(value).toBytes()); + } catch { + throw svmInvalid('invalid Solana public key'); + } +} +function key(value: string) { + return new PublicKey(hexToBytes(svmKey(value))); +} + +/** Gateway is supplied by the selected cluster registry, never a global hard-coded program. */ +export function deriveAgwSvmCea( + wallet: Address, + gatewayProgram: string +): { address: Hex; bump: number } { + if (key(gatewayProgram).equals(PublicKey.default)) + throw svmInvalid('gateway program cannot be zero'); + const [pda, bump] = PublicKey.findProgramAddressSync( + [Buffer.from('push_identity'), Buffer.from(hexToBytes(getAddress(wallet)))], + key(gatewayProgram) + ); + return { address: bytesToHex(pda.toBytes()), bump }; +} +export interface SvmTokenAccountInput { + mint: string; + tokenProgram?: string; +} +export type ResolvedSvmAsset = + | { kind: 'native'; cap: AssetCapWire } + | { kind: 'spl'; cap: AssetCapWire; mint: string; tokenProgram?: string }; + +/** Every resolved SPL cap contributes an ATA; caller cannot omit a listed mint. */ +export function resolveAgwSvmRuleContext( + wallet: Address, + gatewayProgram: string, + assets: readonly ResolvedSvmAsset[], + outputs: readonly SvmTokenAccountInput[] = [] +) { + if (!assets.length || assets.length > SVM_LIMITS.assets) + throw svmInvalid('resolved assets must contain 1..8 entries'); + const tokens = assets.flatMap((a) => + a.kind === 'spl' ? [{ mint: a.mint, tokenProgram: a.tokenProgram }] : [] + ); + return { + ...deriveAgwSvmValueAccounts(wallet, gatewayProgram, tokens, outputs), + assets: assets.map((a) => a.cap), + }; +} +export function deriveAgwSvmAta( + owner: string, + token: SvmTokenAccountInput +): Hex { + const mint = key(token.mint), + program = token.tokenProgram ? key(token.tokenProgram) : SPL_TOKEN; + if (mint.equals(PublicKey.default)) + throw svmInvalid('native SOL uses the CEA, not an ATA'); + if (!program.equals(SPL_TOKEN) && !program.equals(TOKEN_2022)) + throw svmInvalid('unsupported token program'); + const [ata] = PublicKey.findProgramAddressSync( + [key(owner).toBuffer(), program.toBuffer(), mint.toBuffer()], + ASSOCIATED_TOKEN + ); + return bytesToHex(ata.toBytes()); +} +/** Includes every listed mint and swap-output mint. Native SOL is already covered by the CEA. */ +export function deriveAgwSvmValueAccounts( + wallet: Address, + gatewayProgram: string, + tokens: readonly SvmTokenAccountInput[], + outputs: readonly SvmTokenAccountInput[] = [] +): { expectedCEA: Hex; gatewayProgram: Hex; ceaAccounts: Hex[] } { + const expectedCEA = deriveAgwSvmCea(wallet, gatewayProgram).address; + const ceaAccounts = [ + ...new Set([ + expectedCEA, + ...[...tokens, ...outputs].map((t) => deriveAgwSvmAta(expectedCEA, t)), + ]), + ]; + if (ceaAccounts.length > SVM_LIMITS.ceaAccounts) + throw svmInvalid('derived CEA value-account set exceeds 16'); + return { expectedCEA, gatewayProgram: svmKey(gatewayProgram), ceaAccounts }; +} diff --git a/packages/core/src/lib/agentic/codec/svm-terms.ts b/packages/core/src/lib/agentic/codec/svm-terms.ts new file mode 100644 index 00000000..2a096257 --- /dev/null +++ b/packages/core/src/lib/agentic/codec/svm-terms.ts @@ -0,0 +1,303 @@ +/** Internal v4 SVM wire representation; not a proposed public Rule API. */ +import { + decodeAbiParameters, + encodeAbiParameters, + isAddress, + type Hex, +} from 'viem'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; +import { UINT256_MAX } from './defaults'; +import type { AssetCapWire } from './universal-terms'; + +export enum SvmDataPinMode { + EQ, + GTE_LE, + LTE_LE, + RATIO_GTE_LE, +} +export interface AllowedProgramWire { + program: Hex; + discriminator: Hex; + discriminatorLen: number; + dataless: boolean; + maxAccounts: number; +} +export interface SvmAccountPinWire { + ruleIndex: number; + accountIndex: number; + expected: Hex; +} +export interface SvmDataPinWire { + ruleIndex: number; + fromEnd: boolean; + offset: number; + offsetB: number; + len: number; + mode: SvmDataPinMode; + expected: Hex; + num: bigint; + den: bigint; +} +export interface SvmTermsWire { + validUntil: number; + expectedCEA: Hex; + gatewayProgram: Hex; + assets: readonly AssetCapWire[]; + maxGasPerCall: bigint; + ceaAccounts: readonly Hex[]; + programs: readonly AllowedProgramWire[]; + pins: readonly SvmAccountPinWire[]; + dataPins: readonly SvmDataPinWire[]; +} +export const SVM_LIMITS = { + assets: 8, + programs: 32, + pins: 16, + dataPins: 8, + ceaAccounts: 16, + accounts: 64, + ixData: 1024, +} as const; +export const UINT64_MAX = BigInt(2) ** BigInt(64) - BigInt(1); +export const FORBIDDEN_SVM_PROGRAMS: readonly Hex[] = [ + `0x${'00'.repeat(32)}`, + '0x06ddf6e1d765a193d9cbe146ceeb79ac1cb485ed5f5b37913a8cf5857eff00a9', + '0x06ddf6e1ee758fde18425dbce46ccddab61afc4d83b90d27febdf928d8a18bfc', + '0x06a1d8179137542a983437bdfe2a7ab2557f535c8a78722b68a49dc000000000', + '0x02a8f6914e88a1b0e210153ef763ae2b00c2b93d16c124d2c0537a1004800000', + '0x0277a6af97339b7ac88d1892c90446f50002309266f62e53c118244982000000', +]; +export const SVM_TERMS_PARAM = { + type: 'tuple', + components: [ + { name: 'validUntil', type: 'uint48' }, + { name: 'expectedCEA', type: 'bytes32' }, + { name: 'gatewayProgram', type: 'bytes32' }, + { + name: 'assets', + type: 'tuple[]', + components: [ + { name: 'token', type: 'address' }, + { name: 'maxPerCall', type: 'uint256' }, + { name: 'maxTotal', type: 'uint256' }, + ], + }, + { name: 'maxGasPerCall', type: 'uint256' }, + { name: 'ceaAccounts', type: 'bytes32[]' }, + { + name: 'programs', + type: 'tuple[]', + components: [ + { name: 'program', type: 'bytes32' }, + { name: 'discriminator', type: 'bytes8' }, + { name: 'discriminatorLen', type: 'uint8' }, + { name: 'dataless', type: 'bool' }, + { name: 'maxAccounts', type: 'uint8' }, + ], + }, + { + name: 'pins', + type: 'tuple[]', + components: [ + { name: 'ruleIndex', type: 'uint8' }, + { name: 'accountIndex', type: 'uint8' }, + { name: 'expected', type: 'bytes32' }, + ], + }, + { + name: 'dataPins', + type: 'tuple[]', + components: [ + { name: 'ruleIndex', type: 'uint8' }, + { name: 'fromEnd', type: 'bool' }, + { name: 'offset', type: 'uint16' }, + { name: 'offsetB', type: 'uint16' }, + { name: 'len', type: 'uint8' }, + { name: 'mode', type: 'uint8' }, + { name: 'expected', type: 'bytes32' }, + { name: 'num', type: 'uint64' }, + { name: 'den', type: 'uint64' }, + ], + }, + ], +} as const; + +export function svmInvalid(message: string): AgenticError { + return new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, message); +} +export function exactHex( + value: unknown, + bytes: number, + field: string +): asserts value is Hex { + if ( + typeof value !== 'string' || + !new RegExp(`^0x[0-9a-fA-F]{${bytes * 2}}$`).test(value) + ) + throw svmInvalid(`${field} must contain exactly ${bytes} bytes`); +} +function integer(value: number, max: number, field: string) { + if (!Number.isInteger(value) || value < 0 || value > max) + throw svmInvalid(`${field} is out of range`); +} +function uint(value: bigint, max: bigint, field: string) { + if (typeof value !== 'bigint' || value < BigInt(0) || value > max) + throw svmInvalid(`${field} is out of range`); +} +export function isForbiddenSvmProgram( + program: Hex, + terms: Pick +): boolean { + return [ + ...FORBIDDEN_SVM_PROGRAMS, + terms.gatewayProgram, + terms.expectedCEA, + ].some((x) => x.toLowerCase() === program.toLowerCase()); +} +function offsetValid(fromEnd: boolean, offset: number, len: number): boolean { + return fromEnd + ? offset >= len && offset <= SVM_LIMITS.ixData + : offset + len <= SVM_LIMITS.ixData; +} + +/** Grant-time structural rules. Chain/token/mint correctness requires resolved on-chain inputs. */ +export function validateSvmTerms(t: SvmTermsWire, nowSeconds: number): void { + integer(t.validUntil, 2 ** 48 - 1, 'validUntil'); + if (t.validUntil <= nowSeconds) + throw svmInvalid('validUntil must be in the future'); + exactHex(t.expectedCEA, 32, 'expectedCEA'); + exactHex(t.gatewayProgram, 32, 'gatewayProgram'); + if ( + BigInt(t.expectedCEA) === BigInt(0) || + BigInt(t.gatewayProgram) === BigInt(0) + ) + throw svmInvalid('CEA/gateway cannot be zero'); + uint(t.maxGasPerCall, UINT256_MAX, 'maxGasPerCall'); + if (!t.assets.length || t.assets.length > SVM_LIMITS.assets) + throw svmInvalid('assets must contain 1..8 entries'); + const tokens = new Set(); + for (const a of t.assets) { + if (!isAddress(a.token, { strict: false }) || BigInt(a.token) === BigInt(0)) + throw svmInvalid('asset token must be a non-zero PRC20'); + if (tokens.has(a.token.toLowerCase())) throw svmInvalid('duplicate asset'); + tokens.add(a.token.toLowerCase()); + uint(a.maxPerCall, UINT256_MAX, 'maxPerCall'); + uint(a.maxTotal, UINT256_MAX, 'maxTotal'); + } + if (!t.programs.length || t.programs.length > SVM_LIMITS.programs) + throw svmInvalid('programs must contain 1..32 entries'); + t.programs.forEach((r, i) => { + exactHex(r.program, 32, 'program'); + exactHex(r.discriminator, 8, 'discriminator'); + if (typeof r.dataless !== 'boolean') + throw svmInvalid('dataless must be boolean'); + integer(r.discriminatorLen, 8, 'discriminatorLen'); + integer(r.maxAccounts, SVM_LIMITS.accounts, 'maxAccounts'); + if (r.dataless !== (r.discriminatorLen === 0)) + throw svmInvalid('dataless and discriminator length disagree'); + if (isForbiddenSvmProgram(r.program, t)) + throw svmInvalid('forbidden program'); + for (const earlier of t.programs.slice(0, i)) { + if (earlier.program.toLowerCase() !== r.program.toLowerCase()) continue; + const overlap = + earlier.dataless || r.dataless + ? earlier.dataless && r.dataless + : earlier.discriminator + .slice( + 0, + 2 + 2 * Math.min(earlier.discriminatorLen, r.discriminatorLen) + ) + .toLowerCase() === + r.discriminator + .slice( + 0, + 2 + 2 * Math.min(earlier.discriminatorLen, r.discriminatorLen) + ) + .toLowerCase(); + if (overlap) + throw svmInvalid('ambiguous instruction discriminator prefixes'); + } + }); + if (t.pins.length > SVM_LIMITS.pins) + throw svmInvalid('too many account pins'); + const positions = new Set(), + covered = new Set(); + for (const p of t.pins) { + integer(p.ruleIndex, t.programs.length - 1, 'pin ruleIndex'); + integer(p.accountIndex, SVM_LIMITS.accounts - 1, 'accountIndex'); + exactHex(p.expected, 32, 'pin expected'); + const count = t.programs[p.ruleIndex].maxAccounts; + if (count && p.accountIndex >= count) + throw svmInvalid('pin outside fixed account count'); + const key = `${p.ruleIndex}:${p.accountIndex}`; + if (positions.has(key)) throw svmInvalid('duplicate account pin'); + positions.add(key); + covered.add(p.ruleIndex); + } + if (covered.size !== t.programs.length) + throw svmInvalid('every program rule needs an account pin'); + if (t.dataPins.length > SVM_LIMITS.dataPins) + throw svmInvalid('too many data pins'); + for (const p of t.dataPins) { + integer(p.ruleIndex, t.programs.length - 1, 'data pin ruleIndex'); + integer(p.mode, 3, 'data pin mode'); + integer(p.len, p.mode === SvmDataPinMode.EQ ? 32 : 8, 'data pin len'); + integer(p.offset, 65535, 'offset'); + integer(p.offsetB, 65535, 'offsetB'); + exactHex(p.expected, 32, 'data pin expected'); + uint(p.num, UINT64_MAX, 'num'); + uint(p.den, UINT64_MAX, 'den'); + if ( + typeof p.fromEnd !== 'boolean' || + !p.len || + t.programs[p.ruleIndex].dataless || + !offsetValid(p.fromEnd, p.offset, p.len) + ) + throw svmInvalid('invalid data pin shape'); + if ( + p.mode === SvmDataPinMode.EQ && + !/^0*$/.test(p.expected.slice(2 + p.len * 2)) + ) + throw svmInvalid('EQ expected must be left-aligned'); + if ( + (p.mode === SvmDataPinMode.GTE_LE || p.mode === SvmDataPinMode.LTE_LE) && + BigInt(p.expected) >= BigInt(1) << BigInt(p.len * 8) + ) + throw svmInvalid('integer expected exceeds field width'); + if ( + p.mode === SvmDataPinMode.RATIO_GTE_LE && + (!p.num || !p.den || !offsetValid(p.fromEnd, p.offsetB, p.len)) + ) + throw svmInvalid('invalid ratio pin'); + } + if (t.ceaAccounts.length > SVM_LIMITS.ceaAccounts) + throw svmInvalid('too many CEA accounts'); + const accounts = new Set(); + for (const key of t.ceaAccounts) { + exactHex(key, 32, 'CEA account'); + if ( + BigInt(key) === BigInt(0) || + accounts.has(key.toLowerCase()) || + t.programs.some((p) => p.program.toLowerCase() === key.toLowerCase()) + ) + throw svmInvalid('invalid CEA account list'); + accounts.add(key.toLowerCase()); + } + if (!accounts.has(t.expectedCEA.toLowerCase())) + throw svmInvalid('CEA account list must include expectedCEA'); +} +export function encodeSvmTerms(terms: SvmTermsWire, nowSeconds: number): Hex { + validateSvmTerms(terms, nowSeconds); + return encodeAbiParameters([SVM_TERMS_PARAM], [terms]); +} +export function decodeSvmTerms(body: Hex): SvmTermsWire { + try { + return decodeAbiParameters([SVM_TERMS_PARAM], body)[0]; + } catch (cause) { + throw new AgenticError( + AGENTIC_ERROR_CODE.RULE_READ_FAILED, + 'malformed SVM terms', + { cause } + ); + } +} diff --git a/packages/core/src/lib/agentic/codec/universal-terms.ts b/packages/core/src/lib/agentic/codec/universal-terms.ts new file mode 100644 index 00000000..4ac26304 --- /dev/null +++ b/packages/core/src/lib/agentic/codec/universal-terms.ts @@ -0,0 +1,60 @@ +import { + decodeAbiParameters, + encodeAbiParameters, + type Address, + type Hex, +} from 'viem'; + +export interface AssetCapWire { + token: Address; + maxPerCall: bigint; + maxTotal: bigint; +} +export interface AllowedCallWire { + target: Address; + selector: Hex; + beneficiaryOffset: number; + hasBeneficiary: boolean; + maxValue: bigint; +} +export interface UniversalTermsWire { + validUntil: number; + expectedCEA: Address; + assets: readonly AssetCapWire[]; + maxGasPerCall: bigint; + allowedCalls: readonly AllowedCallWire[]; +} +export const UNIVERSAL_TERMS_PARAM = { + type: 'tuple', + components: [ + { name: 'validUntil', type: 'uint48' }, + { name: 'expectedCEA', type: 'address' }, + { + name: 'assets', + type: 'tuple[]', + components: [ + { name: 'token', type: 'address' }, + { name: 'maxPerCall', type: 'uint256' }, + { name: 'maxTotal', type: 'uint256' }, + ], + }, + { name: 'maxGasPerCall', type: 'uint256' }, + { + name: 'allowedCalls', + type: 'tuple[]', + components: [ + { name: 'target', type: 'address' }, + { name: 'selector', type: 'bytes4' }, + { name: 'beneficiaryOffset', type: 'uint16' }, + { name: 'hasBeneficiary', type: 'bool' }, + { name: 'maxValue', type: 'uint256' }, + ], + }, + ], +} as const; +export function encodeUniversalTerms(terms: UniversalTermsWire): Hex { + return encodeAbiParameters([UNIVERSAL_TERMS_PARAM], [terms]); +} +export function decodeUniversalTerms(body: Hex): UniversalTermsWire { + return decodeAbiParameters([UNIVERSAL_TERMS_PARAM], body)[0]; +} diff --git a/packages/core/src/lib/agentic/codec/universal.ts b/packages/core/src/lib/agentic/codec/universal.ts index ccd47551..2d20db24 100644 --- a/packages/core/src/lib/agentic/codec/universal.ts +++ b/packages/core/src/lib/agentic/codec/universal.ts @@ -1,95 +1,214 @@ -import { isAddress } from 'viem'; +import { getAddress, isAddress, type Address } from 'viem'; import { AgenticCapability, requireCapability } from '../capabilities'; import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; import type { UniversalRule } from '../agentic.types'; -import { argumentOffset } from './abi-layout'; +import type { RuleEncodeContext, PreparedRule } from './rules'; +import { argumentOffset, rawOffset } from './abi-layout'; import { parseSelector } from './selectors'; +import { AGENTIC_DEFAULTS, UINT256_MAX, withDefault } from './defaults'; +import { buildSession, encodeEnvelope } from './session'; +import { SEND_OUTBOUND_SELECTOR } from '../contracts/v4'; +import { + encodeUniversalTerms, + type AssetCapWire, + type UniversalTermsWire, +} from './universal-terms'; -/** Proposed multi-asset limits (page 1 §4c) and the pinned allow-list limit. */ export const MAX_ASSETS = 8; export const MAX_ALLOWED_CALLS = 32; +export interface ResolvedUniversalRule { + expectedCEA: Address; + assets: readonly AssetCapWire[]; +} const CAIP2 = /^(eip155:[0-9]+|solana:[1-9A-HJ-NP-Za-km-z]{32,44})$/; - -/** - * Structural validation of a TARGET UniversalRule that does not depend on the - * unresolved wire format: chain id shape, call allow-list, selector/beneficiary - * positions. Approval policy is left to UI/marketplace (Harsh H1). Runs before the capability gate so - * callers get precise input errors. - */ -export function validateUniversalRuleShape(rule: UniversalRule, nowSeconds: number): void { - if (typeof rule.chainNamespace !== 'string' || !CAIP2.test(rule.chainNamespace)) { - throw invalid(`chainNamespace "${String(rule.chainNamespace)}" is not a CAIP-2 eip155/solana chain`); - } - if (!Number.isInteger(rule.validUntil) || rule.validUntil <= nowSeconds) { - throw invalid('validUntil must be a future unix timestamp in seconds'); - } - if (!Array.isArray(rule.assets) || rule.assets.length > MAX_ASSETS) { +const UINT48_MAX = 2 ** 48 - 1; +function cap(value: unknown, what: string): asserts value is bigint { + if (typeof value !== 'bigint' || value < BigInt(0) || value > UINT256_MAX) + throw invalid(`${what} must be a uint256 bigint`); +} +export function validateUniversalRuleShape( + rule: UniversalRule, + nowSeconds: number +): void { + if ( + typeof rule.chainNamespace !== 'string' || + !CAIP2.test(rule.chainNamespace) + ) + throw invalid('chainNamespace must be a CAIP-2 eip155/solana chain'); + if ( + !Number.isSafeInteger(rule.validUntil) || + rule.validUntil <= nowSeconds || + rule.validUntil > UINT48_MAX + ) + throw invalid('validUntil must be a future uint48 unix timestamp'); + if (!Array.isArray(rule.assets) || rule.assets.length > MAX_ASSETS) throw invalid(`assets must be an array of at most ${MAX_ASSETS} caps`); - } - if (typeof rule.maxGasPerCall !== 'bigint' || rule.maxGasPerCall <= BigInt(0)) { - throw invalid('maxGasPerCall must be a positive bigint (PC wei per outbound)'); - } + cap(rule.maxGasPerCall, 'maxGasPerCall'); + if (rule.maxGasPerCall === BigInt(0)) + throw invalid('maxGasPerCall must be positive'); if ( !Array.isArray(rule.allowedCalls) || rule.allowedCalls.length < 1 || rule.allowedCalls.length > MAX_ALLOWED_CALLS - ) { + ) throw invalid(`allowedCalls must contain 1..${MAX_ALLOWED_CALLS} entries`); - } const seen = new Set(); rule.allowedCalls.forEach((call, i) => { - if (!isAddress(call.target, { strict: false })) { + if (!isAddress(call.target, { strict: false })) throw invalid(`allowedCalls[${i}].target is not an EVM address`); - } const parsed = parseSelector(call.selector); - if (parsed.valueOnly) throw invalid(`allowedCalls[${i}] cannot be value-only`); + if (parsed.valueOnly) + throw invalid(`allowedCalls[${i}] cannot be value-only`); + if (call.beneficiary !== undefined && call.beneficiaryOffset !== undefined) + throw invalid('beneficiary and beneficiaryOffset are mutually exclusive'); if (call.beneficiary !== undefined) { - argumentOffset(parsed.inputs, call.beneficiary, `allowedCalls[${i}].beneficiary`); - const t = (parsed.inputs ?? [])[call.beneficiary]?.type; - if (t !== 'address') throw invalid(`allowedCalls[${i}].beneficiary must be an address argument`); + argumentOffset( + parsed.inputs, + call.beneficiary, + `allowedCalls[${i}].beneficiary` + ); + if (parsed.inputs?.[call.beneficiary]?.type !== 'address') + throw invalid( + `allowedCalls[${i}].beneficiary must be an address argument` + ); } + if (call.beneficiaryOffset !== undefined) + rawOffset(call.beneficiaryOffset, `allowedCalls[${i}].beneficiary`); + cap( + call.maxValue ?? AGENTIC_DEFAULTS.universal.allowedCallMaxValue.value, + `allowedCalls[${i}].maxValue` + ); const key = `${call.target.toLowerCase()}:${parsed.selector}`; - if (seen.has(key)) throw invalid(`allowedCalls[${i}] duplicates an earlier target/selector`); + if (seen.has(key)) + throw invalid(`allowedCalls[${i}] duplicates an earlier target/selector`); seen.add(key); }); const tokens = new Set(); rule.assets.forEach((a, i) => { const address = typeof a.token === 'string' ? a.token : a.token?.address; - if (typeof address !== 'string') throw invalid(`assets[${i}].token is missing an address`); + if (typeof address !== 'string') + throw invalid(`assets[${i}].token is missing an address`); const key = address.toLowerCase(); - if (tokens.has(key)) throw invalid(`assets[${i}] duplicates an earlier token`); + if (tokens.has(key)) + throw invalid(`assets[${i}] duplicates an earlier token`); tokens.add(key); - if (typeof a.maxPerCall !== 'bigint' || a.maxPerCall < BigInt(0)) { - throw invalid(`assets[${i}].maxPerCall must be a non-negative bigint`); - } + cap(a.maxPerCall, `assets[${i}].maxPerCall`); + cap( + withDefault(a.maxTotal, AGENTIC_DEFAULTS.universal.assetMaxTotal), + `assets[${i}].maxTotal` + ); }); } -/** - * Encode a target UniversalRule. NOT IMPLEMENTED: the multi-asset wire format, - * empty-assets routing, expectedCEA width and envelope version have no - * matching contract artifacts (A05/A07). Never falls back to the historical - * single-asset terms. - */ export function encodeUniversalRule( rule: UniversalRule, - ctx: { capabilities: ReadonlySet; nowSeconds: number } -): never { + ctx: RuleEncodeContext +): PreparedRule { + if (rule.chainNamespace.startsWith('solana:')) + requireCapability(ctx.capabilities, AgenticCapability.UNIVERSAL_SVM_RULES); validateUniversalRuleShape(rule, ctx.nowSeconds); - const svm = rule.chainNamespace.startsWith('solana:'); requireCapability( ctx.capabilities, - svm ? AgenticCapability.UNIVERSAL_SVM_RULES : AgenticCapability.UNIVERSAL_EVM_RULES - ); - // A generation that advertises the capability must supply its own codec. - throw new AgenticError( - AGENTIC_ERROR_CODE.CAPABILITY_UNAVAILABLE, - 'no universal rule codec is implemented for this generation' + rule.chainNamespace.startsWith('solana:') + ? AgenticCapability.UNIVERSAL_SVM_RULES + : AgenticCapability.UNIVERSAL_EVM_RULES ); + const resolved = ctx.universal?.get(rule); + if (!resolved || !ctx.gateway) + throw invalid( + 'universal encoding requires resolved wallet CEA, PRC20 assets and gateway context' + ); + if ( + resolved.assets.length < 1 || + resolved.assets.length > MAX_ASSETS || + new Set(resolved.assets.map((a) => a.token.toLowerCase())).size !== + resolved.assets.length + ) + throw invalid('resolved assets must be 1..8 distinct PRC20s'); + if ( + !isAddress(resolved.expectedCEA) || + /^0x0{40}$/i.test(resolved.expectedCEA) + ) + throw invalid('expectedCEA must be a non-zero wallet destination account'); + const terms: UniversalTermsWire = { + validUntil: rule.validUntil, + expectedCEA: getAddress(resolved.expectedCEA), + assets: resolved.assets, + maxGasPerCall: rule.maxGasPerCall, + allowedCalls: rule.allowedCalls.map((call) => ({ + target: getAddress(call.target), + selector: parseSelector(call.selector).selector, + hasBeneficiary: + call.beneficiary !== undefined || call.beneficiaryOffset !== undefined, + beneficiaryOffset: + call.beneficiaryOffset ?? + (call.beneficiary === undefined + ? 0 + : argumentOffset( + parseSelector(call.selector).inputs, + call.beneficiary, + 'beneficiary' + )), + maxValue: withDefault( + call.maxValue, + AGENTIC_DEFAULTS.universal.allowedCallMaxValue + ), + })), + }; + const agent = getAddress(rule.agent); + return { + rule, + agent, + chainNamespace: rule.chainNamespace, + universalTerms: terms, + session: buildSession({ + validator: ctx.validator, + agent, + rulesPolicy: ctx.rulesPolicy, + actions: [ + { + target: ctx.gateway, + selector: SEND_OUTBOUND_SELECTOR, + initData: encodeEnvelope( + rule.chainNamespace, + encodeUniversalTerms(terms) + ), + }, + ], + }), + }; } +/** Source token addresses must be resolved from each PRC20 before calling this. */ +export function universalTermsToRule( + terms: UniversalTermsWire, + agent: Address, + chainNamespace: UniversalRule['chainNamespace'], + tokens: readonly Address[] +): UniversalRule { + if (tokens.length !== terms.assets.length) + throw invalid('origin-token list does not match stored asset order'); + return { + agent, + chainNamespace, + validUntil: Number(terms.validUntil), + maxGasPerCall: terms.maxGasPerCall, + assets: terms.assets.map((a, i) => ({ + token: tokens[i], + maxPerCall: a.maxPerCall, + maxTotal: a.maxTotal, + })), + allowedCalls: terms.allowedCalls.map((c) => ({ + target: c.target, + selector: c.selector, + maxValue: c.maxValue, + ...(c.hasBeneficiary + ? { beneficiaryOffset: Number(c.beneficiaryOffset) } + : {}), + })), + }; +} function invalid(message: string): AgenticError { return new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, message); } - diff --git a/packages/core/src/lib/agentic/constants.ts b/packages/core/src/lib/agentic/constants.ts index d579df2a..89d39e0b 100644 --- a/packages/core/src/lib/agentic/constants.ts +++ b/packages/core/src/lib/agentic/constants.ts @@ -1,17 +1,23 @@ -import type { PUSH_NETWORK } from '../constants/enums'; +import { PUSH_NETWORK } from '../constants/enums'; +import { DONUT_V4_ADDRESSES } from './contracts/donut-v4'; -/** - * PushChain.CONSTANTS.AGENTIC[network] (spec 3.d). Populated only from - * verified release deployments — currently none (A07), so the map is empty. - * ENVELOPE_VERSION is omitted until a generation with a versioned envelope is - * delivered; no value is guessed. - */ +/** Checked Donut v4 proxies. Unsupported networks are absent. */ export interface AgenticNetworkConstants { FACTORY: `0x${string}`; RULES_POLICY: `0x${string}`; MAX_PINS: number; MAX_ALLOWED_CALLS: number; - ENVELOPE_VERSION?: number; + ENVELOPE_VERSION: number; } -export const AGENTIC: Readonly>> = Object.freeze({}); +export const AGENTIC: Readonly< + Partial> +> = Object.freeze({ + [PUSH_NETWORK.TESTNET_DONUT]: Object.freeze({ + FACTORY: DONUT_V4_ADDRESSES.factory, + RULES_POLICY: DONUT_V4_ADDRESSES.rulesPolicy, + MAX_PINS: 8, + MAX_ALLOWED_CALLS: 32, + ENVELOPE_VERSION: 1, + }), +}); diff --git a/packages/core/src/lib/agentic/contracts/abi/e704d5b/agent-validator.ts b/packages/core/src/lib/agentic/contracts/abi/e704d5b/agent-validator.ts deleted file mode 100644 index 39d5abf5..00000000 --- a/packages/core/src/lib/agentic/contracts/abi/e704d5b/agent-validator.ts +++ /dev/null @@ -1,145 +0,0 @@ -// GENERATED by packages/core/scripts/agw-local/gen-abi.mjs — do not edit. -// Source: plan/agw/research/validation-e704d5b/abi/AgentValidator.json -// push-agentic-wallets@e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9 -// sha256(AgentValidator.json) = a4570ddc373241580de8742cbb3d9f2c837094c65bfd1cdd52243ca0c38196fd -export const AGENT_VALIDATOR_ABI = [ - { - "type": "function", - "name": "isInitialized", - "inputs": [ - { - "name": "", - "type": "address", - "internalType": "address" - } - ], - "outputs": [ - { - "name": "", - "type": "bool", - "internalType": "bool" - } - ], - "stateMutability": "pure" - }, - { - "type": "function", - "name": "isModuleType", - "inputs": [ - { - "name": "moduleTypeId", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [ - { - "name": "", - "type": "bool", - "internalType": "bool" - } - ], - "stateMutability": "pure" - }, - { - "type": "function", - "name": "onInstall", - "inputs": [ - { - "name": "", - "type": "bytes", - "internalType": "bytes" - } - ], - "outputs": [], - "stateMutability": "pure" - }, - { - "type": "function", - "name": "onUninstall", - "inputs": [ - { - "name": "", - "type": "bytes", - "internalType": "bytes" - } - ], - "outputs": [], - "stateMutability": "pure" - }, - { - "type": "function", - "name": "validateConfig", - "inputs": [ - { - "name": "data", - "type": "bytes", - "internalType": "bytes" - } - ], - "outputs": [ - { - "name": "", - "type": "bool", - "internalType": "bool" - } - ], - "stateMutability": "pure" - }, - { - "type": "function", - "name": "validateSignatureWithData", - "inputs": [ - { - "name": "", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "sig", - "type": "bytes", - "internalType": "bytes" - }, - { - "name": "data", - "type": "bytes", - "internalType": "bytes" - } - ], - "outputs": [ - { - "name": "validSig", - "type": "bool", - "internalType": "bool" - } - ], - "stateMutability": "pure" - }, - { - "type": "error", - "name": "AlreadyInitialized", - "inputs": [ - { - "name": "smartAccount", - "type": "address", - "internalType": "address" - } - ] - }, - { - "type": "error", - "name": "MalformedConfig", - "inputs": [] - }, - { - "type": "error", - "name": "NotInitialized", - "inputs": [ - { - "name": "smartAccount", - "type": "address", - "internalType": "address" - } - ] - } -] as const; diff --git a/packages/core/src/lib/agentic/contracts/abi/e704d5b/universal-rules-policy.ts b/packages/core/src/lib/agentic/contracts/abi/e704d5b/universal-rules-policy.ts deleted file mode 100644 index 8cf26e68..00000000 --- a/packages/core/src/lib/agentic/contracts/abi/e704d5b/universal-rules-policy.ts +++ /dev/null @@ -1,2065 +0,0 @@ -// GENERATED by packages/core/scripts/agw-local/gen-abi.mjs — do not edit. -// Source: plan/agw/research/validation-e704d5b/abi/UniversalRulesPolicy.json -// push-agentic-wallets@e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9 -// sha256(UniversalRulesPolicy.json) = 8301b452b035d12d03ff1861940b895128a40eaf280fb6d3ae30ffc46c5ae86d -export const UNIVERSAL_RULES_POLICY_ABI = [ - { - "type": "function", - "name": "SEND_OUTBOUND_SELECTOR", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "bytes4", - "internalType": "bytes4" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "SESSION_ENGINE", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "address", - "internalType": "address" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "UNIVERSAL_EXECUTOR_MODULE", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "address", - "internalType": "address" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "UNIVERSAL_GATEWAY_PC", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "address", - "internalType": "address" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "assertSpent", - "inputs": [ - { - "name": "id", - "type": "bytes32", - "internalType": "ConfigId" - }, - { - "name": "account", - "type": "address", - "internalType": "address" - }, - { - "name": "expectedValueSpent", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "expectedAmountSpent", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "expectedCalls", - "type": "uint32", - "internalType": "uint32" - } - ], - "outputs": [], - "stateMutability": "view" - }, - { - "type": "function", - "name": "assertSpent", - "inputs": [ - { - "name": "id", - "type": "bytes32", - "internalType": "ConfigId" - }, - { - "name": "account", - "type": "address", - "internalType": "address" - }, - { - "name": "expectedSpent", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [], - "stateMutability": "view" - }, - { - "type": "function", - "name": "checkAction", - "inputs": [ - { - "name": "id", - "type": "bytes32", - "internalType": "ConfigId" - }, - { - "name": "account", - "type": "address", - "internalType": "address" - }, - { - "name": "target", - "type": "address", - "internalType": "address" - }, - { - "name": "value", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "data", - "type": "bytes", - "internalType": "bytes" - } - ], - "outputs": [ - { - "name": "", - "type": "uint256", - "internalType": "uint256" - } - ], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "creditRevert", - "inputs": [ - { - "name": "id", - "type": "bytes32", - "internalType": "ConfigId" - }, - { - "name": "account", - "type": "address", - "internalType": "address" - }, - { - "name": "outboundTxId", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "amount", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "getConfig", - "inputs": [ - { - "name": "id", - "type": "bytes32", - "internalType": "ConfigId" - }, - { - "name": "account", - "type": "address", - "internalType": "address" - } - ], - "outputs": [ - { - "name": "", - "type": "tuple", - "internalType": "struct Config", - "components": [ - { - "name": "initialized", - "type": "bool", - "internalType": "bool" - }, - { - "name": "validUntil", - "type": "uint48", - "internalType": "uint48" - }, - { - "name": "destChainHash", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "expectedCEA", - "type": "address", - "internalType": "address" - }, - { - "name": "asset", - "type": "address", - "internalType": "address" - }, - { - "name": "maxAmountPerCall", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "maxAmountTotal", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "maxPCPerCall", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "spent", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "allowedCalls", - "type": "tuple[]", - "internalType": "struct AllowedCall[]", - "components": [ - { - "name": "target", - "type": "address", - "internalType": "address" - }, - { - "name": "selector", - "type": "bytes4", - "internalType": "bytes4" - }, - { - "name": "beneficiaryOffset", - "type": "uint16", - "internalType": "uint16" - }, - { - "name": "hasBeneficiary", - "type": "bool", - "internalType": "bool" - }, - { - "name": "maxValue", - "type": "uint256", - "internalType": "uint256" - } - ] - } - ] - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "getMode", - "inputs": [ - { - "name": "id", - "type": "bytes32", - "internalType": "ConfigId" - }, - { - "name": "account", - "type": "address", - "internalType": "address" - } - ], - "outputs": [ - { - "name": "", - "type": "tuple", - "internalType": "struct ModeSlot", - "components": [ - { - "name": "initialized", - "type": "bool", - "internalType": "bool" - }, - { - "name": "mode", - "type": "uint8", - "internalType": "enum RulesType" - }, - { - "name": "vm", - "type": "uint8", - "internalType": "enum VmFamily" - }, - { - "name": "chainHash", - "type": "bytes32", - "internalType": "bytes32" - } - ] - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "getNativeConfig", - "inputs": [ - { - "name": "id", - "type": "bytes32", - "internalType": "ConfigId" - }, - { - "name": "account", - "type": "address", - "internalType": "address" - } - ], - "outputs": [ - { - "name": "", - "type": "tuple", - "internalType": "struct NativeConfig", - "components": [ - { - "name": "initialized", - "type": "bool", - "internalType": "bool" - }, - { - "name": "validUntil", - "type": "uint48", - "internalType": "uint48" - }, - { - "name": "target", - "type": "address", - "internalType": "address" - }, - { - "name": "selector", - "type": "bytes4", - "internalType": "bytes4" - }, - { - "name": "maxValuePerCall", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "maxValueTotal", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "valueSpent", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "amount", - "type": "tuple", - "internalType": "struct AmountRule", - "components": [ - { - "name": "enabled", - "type": "bool", - "internalType": "bool" - }, - { - "name": "offset", - "type": "uint16", - "internalType": "uint16" - }, - { - "name": "maxPerCall", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "maxTotal", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "name": "amountSpent", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "maxCalls", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "callsUsed", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "pins", - "type": "tuple[]", - "internalType": "struct ArgPin[]", - "components": [ - { - "name": "offset", - "type": "uint16", - "internalType": "uint16" - }, - { - "name": "expected", - "type": "bytes32", - "internalType": "bytes32" - } - ] - } - ] - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "getSvmConfig", - "inputs": [ - { - "name": "id", - "type": "bytes32", - "internalType": "ConfigId" - }, - { - "name": "account", - "type": "address", - "internalType": "address" - } - ], - "outputs": [ - { - "name": "", - "type": "tuple", - "internalType": "struct SvmConfig", - "components": [ - { - "name": "initialized", - "type": "bool", - "internalType": "bool" - }, - { - "name": "validUntil", - "type": "uint48", - "internalType": "uint48" - }, - { - "name": "expectedCEA", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "gatewayProgram", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "asset", - "type": "address", - "internalType": "address" - }, - { - "name": "maxAmountPerCall", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "maxAmountTotal", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "maxPCPerCall", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "spent", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "ceaAccounts", - "type": "bytes32[]", - "internalType": "bytes32[]" - }, - { - "name": "programs", - "type": "tuple[]", - "internalType": "struct AllowedProgram[]", - "components": [ - { - "name": "program", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "discriminator", - "type": "bytes8", - "internalType": "bytes8" - }, - { - "name": "discriminatorLen", - "type": "uint8", - "internalType": "uint8" - }, - { - "name": "dataless", - "type": "bool", - "internalType": "bool" - }, - { - "name": "maxAccounts", - "type": "uint8", - "internalType": "uint8" - } - ] - }, - { - "name": "pins", - "type": "tuple[]", - "internalType": "struct SvmAccountPin[]", - "components": [ - { - "name": "ruleIndex", - "type": "uint8", - "internalType": "uint8" - }, - { - "name": "accountIndex", - "type": "uint8", - "internalType": "uint8" - }, - { - "name": "expected", - "type": "bytes32", - "internalType": "bytes32" - } - ] - }, - { - "name": "dataPins", - "type": "tuple[]", - "internalType": "struct SvmDataPin[]", - "components": [ - { - "name": "ruleIndex", - "type": "uint8", - "internalType": "uint8" - }, - { - "name": "fromEnd", - "type": "bool", - "internalType": "bool" - }, - { - "name": "offset", - "type": "uint16", - "internalType": "uint16" - }, - { - "name": "offsetB", - "type": "uint16", - "internalType": "uint16" - }, - { - "name": "len", - "type": "uint8", - "internalType": "uint8" - }, - { - "name": "mode", - "type": "uint8", - "internalType": "enum SvmDataPinMode" - }, - { - "name": "expected", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "num", - "type": "uint64", - "internalType": "uint64" - }, - { - "name": "den", - "type": "uint64", - "internalType": "uint64" - } - ] - } - ] - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "initialize", - "inputs": [ - { - "name": "universalGatewayPC", - "type": "address", - "internalType": "address" - }, - { - "name": "universalExecutorModule", - "type": "address", - "internalType": "address" - }, - { - "name": "sessionEngine", - "type": "address", - "internalType": "address" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "initializeWithMultiplexer", - "inputs": [ - { - "name": "account", - "type": "address", - "internalType": "address" - }, - { - "name": "configId", - "type": "bytes32", - "internalType": "ConfigId" - }, - { - "name": "initData", - "type": "bytes", - "internalType": "bytes" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "isCredited", - "inputs": [ - { - "name": "outboundTxId", - "type": "bytes32", - "internalType": "bytes32" - } - ], - "outputs": [ - { - "name": "", - "type": "bool", - "internalType": "bool" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "pushChainHash", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "bytes32", - "internalType": "bytes32" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "supportsInterface", - "inputs": [ - { - "name": "iid", - "type": "bytes4", - "internalType": "bytes4" - } - ], - "outputs": [ - { - "name": "", - "type": "bool", - "internalType": "bool" - } - ], - "stateMutability": "pure" - }, - { - "type": "function", - "name": "version", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "string", - "internalType": "string" - } - ], - "stateMutability": "pure" - }, - { - "type": "event", - "name": "Initialized", - "inputs": [ - { - "name": "version", - "type": "uint64", - "indexed": false, - "internalType": "uint64" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "NativeCallMetered", - "inputs": [ - { - "name": "id", - "type": "bytes32", - "indexed": true, - "internalType": "ConfigId" - }, - { - "name": "multiplexer", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "account", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "value", - "type": "uint256", - "indexed": false, - "internalType": "uint256" - }, - { - "name": "amount", - "type": "uint256", - "indexed": false, - "internalType": "uint256" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "OutboundMetered", - "inputs": [ - { - "name": "id", - "type": "bytes32", - "indexed": true, - "internalType": "ConfigId" - }, - { - "name": "multiplexer", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "account", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "amount", - "type": "uint256", - "indexed": false, - "internalType": "uint256" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "PolicySet", - "inputs": [ - { - "name": "id", - "type": "bytes32", - "indexed": false, - "internalType": "ConfigId" - }, - { - "name": "multiplexer", - "type": "address", - "indexed": false, - "internalType": "address" - }, - { - "name": "account", - "type": "address", - "indexed": false, - "internalType": "address" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "RevertCredited", - "inputs": [ - { - "name": "outboundTxId", - "type": "bytes32", - "indexed": true, - "internalType": "bytes32" - }, - { - "name": "id", - "type": "bytes32", - "indexed": true, - "internalType": "ConfigId" - }, - { - "name": "account", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "amountApplied", - "type": "uint256", - "indexed": false, - "internalType": "uint256" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "RulesConfigured", - "inputs": [ - { - "name": "id", - "type": "bytes32", - "indexed": true, - "internalType": "ConfigId" - }, - { - "name": "multiplexer", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "account", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "mode", - "type": "uint8", - "indexed": false, - "internalType": "enum RulesType" - }, - { - "name": "vm", - "type": "uint8", - "indexed": false, - "internalType": "enum VmFamily" - }, - { - "name": "chainHash", - "type": "bytes32", - "indexed": false, - "internalType": "bytes32" - } - ], - "anonymous": false - }, - { - "type": "error", - "name": "AllowListOutOfRange", - "inputs": [ - { - "name": "length", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "AlreadyCredited", - "inputs": [ - { - "name": "outboundTxId", - "type": "bytes32", - "internalType": "bytes32" - } - ] - }, - { - "type": "error", - "name": "AlreadyInitialized", - "inputs": [ - { - "name": "id", - "type": "bytes32", - "internalType": "ConfigId" - } - ] - }, - { - "type": "error", - "name": "AmbiguousRule", - "inputs": [ - { - "name": "i", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "j", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "AmountExceedsCap", - "inputs": [ - { - "name": "amount", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "cap", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "AmountExceedsU64", - "inputs": [ - { - "name": "amount", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "ArgPinMismatch", - "inputs": [ - { - "name": "actual", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "index", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "expected", - "type": "bytes32", - "internalType": "bytes32" - } - ] - }, - { - "type": "error", - "name": "AssetMismatch", - "inputs": [ - { - "name": "expected", - "type": "address", - "internalType": "address" - }, - { - "name": "actual", - "type": "address", - "internalType": "address" - } - ] - }, - { - "type": "error", - "name": "BatchSizeOutOfRange", - "inputs": [ - { - "name": "count", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "BeneficiaryMismatch", - "inputs": [ - { - "name": "expected", - "type": "address", - "internalType": "address" - }, - { - "name": "actual", - "type": "address", - "internalType": "address" - } - ] - }, - { - "type": "error", - "name": "CallLimitReached", - "inputs": [ - { - "name": "callsUsed", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "maxCalls", - "type": "uint32", - "internalType": "uint32" - } - ] - }, - { - "type": "error", - "name": "CallNotAllowed", - "inputs": [ - { - "name": "target", - "type": "address", - "internalType": "address" - }, - { - "name": "selector", - "type": "bytes4", - "internalType": "bytes4" - } - ] - }, - { - "type": "error", - "name": "CalldataTooShort", - "inputs": [ - { - "name": "length", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "CalldataTooShortForAmount", - "inputs": [ - { - "name": "actualLength", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "needed", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "CalldataTooShortForPin", - "inputs": [ - { - "name": "actualLength", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "index", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "needed", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "CallerIsNotUEModule", - "inputs": [ - { - "name": "caller", - "type": "address", - "internalType": "address" - } - ] - }, - { - "type": "error", - "name": "CeaAccountAtUnpinnedIndex", - "inputs": [ - { - "name": "accountIndex", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "account", - "type": "bytes32", - "internalType": "bytes32" - } - ] - }, - { - "type": "error", - "name": "CeaAccountsMissExpectedCEA", - "inputs": [] - }, - { - "type": "error", - "name": "ChainMismatch", - "inputs": [ - { - "name": "declared", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "assetChain", - "type": "bytes32", - "internalType": "bytes32" - } - ] - }, - { - "type": "error", - "name": "DiscriminatorLenOutOfRange", - "inputs": [ - { - "name": "rule", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "len", - "type": "uint8", - "internalType": "uint8" - } - ] - }, - { - "type": "error", - "name": "DuplicateSvmPin", - "inputs": [ - { - "name": "first", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "second", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "EmptyChain", - "inputs": [] - }, - { - "type": "error", - "name": "ForbiddenInnerTarget", - "inputs": [ - { - "name": "target", - "type": "address", - "internalType": "address" - } - ] - }, - { - "type": "error", - "name": "ForbiddenProgramInAllowList", - "inputs": [ - { - "name": "rule", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "program", - "type": "bytes32", - "internalType": "bytes32" - } - ] - }, - { - "type": "error", - "name": "ForbiddenTargetProgram", - "inputs": [ - { - "name": "program", - "type": "bytes32", - "internalType": "bytes32" - } - ] - }, - { - "type": "error", - "name": "InnerValueExceedsAllowance", - "inputs": [ - { - "name": "index", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "value", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "maxValue", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "InvalidAsset", - "inputs": [ - { - "name": "asset", - "type": "address", - "internalType": "address" - } - ] - }, - { - "type": "error", - "name": "InvalidCeaAccount", - "inputs": [ - { - "name": "index", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "InvalidConfigField", - "inputs": [] - }, - { - "type": "error", - "name": "InvalidExpiry", - "inputs": [ - { - "name": "validUntil", - "type": "uint48", - "internalType": "uint48" - } - ] - }, - { - "type": "error", - "name": "InvalidInitialization", - "inputs": [] - }, - { - "type": "error", - "name": "InvalidRevertRecipient", - "inputs": [ - { - "name": "expected", - "type": "address", - "internalType": "address" - }, - { - "name": "actual", - "type": "address", - "internalType": "address" - } - ] - }, - { - "type": "error", - "name": "InvalidSelector", - "inputs": [ - { - "name": "selector", - "type": "bytes4", - "internalType": "bytes4" - } - ] - }, - { - "type": "error", - "name": "InvalidSvmConfigField", - "inputs": [] - }, - { - "type": "error", - "name": "InvalidTarget", - "inputs": [ - { - "name": "target", - "type": "address", - "internalType": "address" - } - ] - }, - { - "type": "error", - "name": "MalformedInnerCalldata", - "inputs": [] - }, - { - "type": "error", - "name": "MalformedOutboundRequest", - "inputs": [ - { - "name": "length", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "MalformedSvmPayload", - "inputs": [ - { - "name": "code", - "type": "uint8", - "internalType": "uint8" - } - ] - }, - { - "type": "error", - "name": "NativeAmountExceedsCap", - "inputs": [ - { - "name": "amount", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "cap", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "NativeTargetIsGateway", - "inputs": [ - { - "name": "target", - "type": "address", - "internalType": "address" - } - ] - }, - { - "type": "error", - "name": "NativeTargetZero", - "inputs": [] - }, - { - "type": "error", - "name": "NotInitialized", - "inputs": [ - { - "name": "id", - "type": "bytes32", - "internalType": "ConfigId" - }, - { - "name": "account", - "type": "address", - "internalType": "address" - } - ] - }, - { - "type": "error", - "name": "NotInitializing", - "inputs": [] - }, - { - "type": "error", - "name": "PCValueExceedsCap", - "inputs": [ - { - "name": "value", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "cap", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "PayloadNotMulticall", - "inputs": [] - }, - { - "type": "error", - "name": "PolicyNotInitialized", - "inputs": [ - { - "name": "id", - "type": "bytes32", - "internalType": "ConfigId" - }, - { - "name": "multiplexer", - "type": "address", - "internalType": "address" - }, - { - "name": "account", - "type": "address", - "internalType": "address" - } - ] - }, - { - "type": "error", - "name": "ProgramListOutOfRange", - "inputs": [ - { - "name": "length", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "ProgramNotAllowed", - "inputs": [ - { - "name": "program", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "discriminator", - "type": "bytes8", - "internalType": "bytes8" - } - ] - }, - { - "type": "error", - "name": "RecipientMustBeEmpty", - "inputs": [] - }, - { - "type": "error", - "name": "RecipientNotPubkey", - "inputs": [ - { - "name": "length", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "RecipientTargetMismatch", - "inputs": [ - { - "name": "recipient", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "target", - "type": "bytes32", - "internalType": "bytes32" - } - ] - }, - { - "type": "error", - "name": "RuleWithoutPin", - "inputs": [ - { - "name": "rule", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "RulesExpired", - "inputs": [ - { - "name": "validUntil", - "type": "uint48", - "internalType": "uint48" - } - ] - }, - { - "type": "error", - "name": "SelectorMismatch", - "inputs": [ - { - "name": "actual", - "type": "bytes4", - "internalType": "bytes4" - }, - { - "name": "expected", - "type": "bytes4", - "internalType": "bytes4" - } - ] - }, - { - "type": "error", - "name": "SpentMismatch", - "inputs": [ - { - "name": "expected", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "actual", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "SvmAccountCountBelowPin", - "inputs": [ - { - "name": "pin", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "count", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "needed", - "type": "uint8", - "internalType": "uint8" - } - ] - }, - { - "type": "error", - "name": "SvmAccountCountMismatch", - "inputs": [ - { - "name": "count", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "expected", - "type": "uint8", - "internalType": "uint8" - } - ] - }, - { - "type": "error", - "name": "SvmAccountPinMismatch", - "inputs": [ - { - "name": "pin", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "accountIndex", - "type": "uint8", - "internalType": "uint8" - }, - { - "name": "expected", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "actual", - "type": "bytes32", - "internalType": "bytes32" - } - ] - }, - { - "type": "error", - "name": "SvmAccountsOutOfRange", - "inputs": [ - { - "name": "count", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "SvmDataCeilingExceeded", - "inputs": [ - { - "name": "pin", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "actual", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "ceiling", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "SvmDataFloorNotMet", - "inputs": [ - { - "name": "pin", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "actual", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "floor", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "SvmDataPinInvalid", - "inputs": [ - { - "name": "pin", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "SvmDataPinMismatch", - "inputs": [ - { - "name": "pin", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "expected", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "actual", - "type": "bytes32", - "internalType": "bytes32" - } - ] - }, - { - "type": "error", - "name": "SvmDataRatioNotMet", - "inputs": [ - { - "name": "pin", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "a", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "b", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "num", - "type": "uint64", - "internalType": "uint64" - }, - { - "name": "den", - "type": "uint64", - "internalType": "uint64" - } - ] - }, - { - "type": "error", - "name": "SvmDataTooShortForPin", - "inputs": [ - { - "name": "pin", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "ixLen", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "SvmInstructionNotExecute", - "inputs": [ - { - "name": "instructionId", - "type": "uint8", - "internalType": "uint8" - } - ] - }, - { - "type": "error", - "name": "SvmIxDataTooLong", - "inputs": [ - { - "name": "length", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "SvmMaxAccountsOutOfRange", - "inputs": [ - { - "name": "rule", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "maxAccounts", - "type": "uint8", - "internalType": "uint8" - } - ] - }, - { - "type": "error", - "name": "SvmPayloadEmpty", - "inputs": [] - }, - { - "type": "error", - "name": "SvmPinIndexOutOfRange", - "inputs": [ - { - "name": "pin", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "accountIndex", - "type": "uint8", - "internalType": "uint8" - } - ] - }, - { - "type": "error", - "name": "SvmPinRuleOutOfRange", - "inputs": [ - { - "name": "pin", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "rule", - "type": "uint8", - "internalType": "uint8" - } - ] - }, - { - "type": "error", - "name": "TargetMismatch", - "inputs": [ - { - "name": "actual", - "type": "address", - "internalType": "address" - }, - { - "name": "expected", - "type": "address", - "internalType": "address" - } - ] - }, - { - "type": "error", - "name": "TooManyCeaAccounts", - "inputs": [ - { - "name": "count", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "TooManyPins", - "inputs": [ - { - "name": "count", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "TooManySvmDataPins", - "inputs": [ - { - "name": "count", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "TooManySvmPins", - "inputs": [ - { - "name": "count", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "TotalNativeAmountExceeded", - "inputs": [ - { - "name": "newSpent", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "cap", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "TotalSpendCapExceeded", - "inputs": [ - { - "name": "wouldBeTotal", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "cap", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "TotalValueExceeded", - "inputs": [ - { - "name": "newSpent", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "cap", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "UncappedGasSwapRejected", - "inputs": [] - }, - { - "type": "error", - "name": "UnsupportedNamespace", - "inputs": [ - { - "name": "chainHash", - "type": "bytes32", - "internalType": "bytes32" - } - ] - }, - { - "type": "error", - "name": "ValueExceedsCap", - "inputs": [ - { - "name": "value", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "cap", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "ValueOnlyCalldataNotEmpty", - "inputs": [ - { - "name": "length", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "ValueOnlyWithAmountRule", - "inputs": [] - }, - { - "type": "error", - "name": "ValueOnlyWithPins", - "inputs": [] - }, - { - "type": "error", - "name": "WrongModeForCall", - "inputs": [ - { - "name": "actual", - "type": "uint8", - "internalType": "enum RulesType" - } - ] - }, - { - "type": "error", - "name": "WrongVmForCall", - "inputs": [ - { - "name": "actual", - "type": "uint8", - "internalType": "enum VmFamily" - } - ] - }, - { - "type": "error", - "name": "ZeroAddress", - "inputs": [] - } -] as const; diff --git a/packages/core/src/lib/agentic/contracts/abi/v4/agent-validator.ts b/packages/core/src/lib/agentic/contracts/abi/v4/agent-validator.ts new file mode 100644 index 00000000..56db7e9c --- /dev/null +++ b/packages/core/src/lib/agentic/contracts/abi/v4/agent-validator.ts @@ -0,0 +1,145 @@ +// GENERATED by packages/core/scripts/agw-local/gen-abi.mjs — do not edit. +// Source: plan/agw/research/deployment-review-2026-10-06/abis/AgentValidator.json +// push-agentic-wallets@e8db74815cfbbf5389593805e464fe8d85f7f735 +// sha256(AgentValidator.json) = d2555b2f54d56ed24268af650b19ad10f2d34906b2e0c4ff78dd6de54ba34cc2 +export const AGENT_VALIDATOR_ABI = [ + { + "inputs": [ + { + "internalType": "address", + "name": "smartAccount", + "type": "address" + } + ], + "name": "AlreadyInitialized", + "type": "error" + }, + { + "inputs": [], + "name": "MalformedConfig", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "smartAccount", + "type": "address" + } + ], + "name": "NotInitialized", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "isInitialized", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "moduleTypeId", + "type": "uint256" + } + ], + "name": "isModuleType", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "name": "onInstall", + "outputs": [], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "name": "onUninstall", + "outputs": [], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "validateConfig", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "sig", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "validateSignatureWithData", + "outputs": [ + { + "internalType": "bool", + "name": "validSig", + "type": "bool" + } + ], + "stateMutability": "pure", + "type": "function" + } +] as const; diff --git a/packages/core/src/lib/agentic/contracts/abi/e704d5b/agw-factory.ts b/packages/core/src/lib/agentic/contracts/abi/v4/agw-factory.ts similarity index 51% rename from packages/core/src/lib/agentic/contracts/abi/e704d5b/agw-factory.ts rename to packages/core/src/lib/agentic/contracts/abi/v4/agw-factory.ts index ec4f3b07..38da9c0b 100644 --- a/packages/core/src/lib/agentic/contracts/abi/e704d5b/agw-factory.ts +++ b/packages/core/src/lib/agentic/contracts/abi/v4/agw-factory.ts @@ -1,1104 +1,1104 @@ // GENERATED by packages/core/scripts/agw-local/gen-abi.mjs — do not edit. -// Source: plan/agw/research/validation-e704d5b/abi/AGWFactory.json -// push-agentic-wallets@e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9 -// sha256(AGWFactory.json) = b65f66a1556d2a9ddf9aabe9f595c685c2aada436772892f5a40fb1eec846397 +// Source: plan/agw/research/deployment-review-2026-10-06/abis/AGWFactory.json +// push-agentic-wallets@e8db74815cfbbf5389593805e464fe8d85f7f735 +// sha256(AGWFactory.json) = c58ac31b81a64b4ab5b89c5aef3f6d01a405607395af71b5466d55fe9c1d5b99 export const AGW_FACTORY_ABI = [ { - "type": "function", - "name": "DEFAULT_ADMIN_ROLE", "inputs": [], - "outputs": [ + "name": "AccessControlBadConfirmation", + "type": "error" + }, + { + "inputs": [ { - "name": "", - "type": "bytes32", - "internalType": "bytes32" + "internalType": "uint48", + "name": "schedule", + "type": "uint48" } ], - "stateMutability": "view" + "name": "AccessControlEnforcedDefaultAdminDelay", + "type": "error" }, { - "type": "function", - "name": "OPERATOR_ROLE", "inputs": [], - "outputs": [ + "name": "AccessControlEnforcedDefaultAdminRules", + "type": "error" + }, + { + "inputs": [ { - "name": "", - "type": "bytes32", - "internalType": "bytes32" + "internalType": "address", + "name": "defaultAdmin", + "type": "address" } ], - "stateMutability": "view" + "name": "AccessControlInvalidDefaultAdmin", + "type": "error" }, { - "type": "function", - "name": "PAUSER_ROLE", - "inputs": [], - "outputs": [ + "inputs": [ { - "name": "", - "type": "bytes32", - "internalType": "bytes32" + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "neededRole", + "type": "bytes32" } ], - "stateMutability": "view" + "name": "AccessControlUnauthorizedAccount", + "type": "error" }, { - "type": "function", - "name": "UPGRADE_INTERFACE_VERSION", - "inputs": [], - "outputs": [ + "inputs": [ { - "name": "", - "type": "string", - "internalType": "string" + "internalType": "address", + "name": "target", + "type": "address" } ], - "stateMutability": "view" + "name": "AddressEmptyCode", + "type": "error" }, { - "type": "function", - "name": "acceptDefaultAdminTransfer", "inputs": [], - "outputs": [], - "stateMutability": "nonpayable" + "name": "CloneArgumentsTooLong", + "type": "error" + }, + { + "inputs": [], + "name": "Create2EmptyBytecode", + "type": "error" }, { - "type": "function", - "name": "beginDefaultAdminTransfer", "inputs": [ { - "name": "newAdmin", - "type": "address", - "internalType": "address" + "internalType": "address", + "name": "implementation", + "type": "address" } ], - "outputs": [], - "stateMutability": "nonpayable" + "name": "ERC1967InvalidImplementation", + "type": "error" }, { - "type": "function", - "name": "cancelDefaultAdminTransfer", "inputs": [], - "outputs": [], - "stateMutability": "nonpayable" + "name": "ERC1967NonPayable", + "type": "error" + }, + { + "inputs": [], + "name": "EnforcedPause", + "type": "error" }, { - "type": "function", - "name": "changeDefaultAdminDelay", "inputs": [ { - "name": "newDelay", - "type": "uint48", - "internalType": "uint48" + "internalType": "address", + "name": "expected", + "type": "address" + }, + { + "internalType": "address", + "name": "actual", + "type": "address" } ], - "outputs": [], - "stateMutability": "nonpayable" + "name": "ExecutorMismatch", + "type": "error" }, { - "type": "function", - "name": "defaultAdmin", "inputs": [], - "outputs": [ - { - "name": "", - "type": "address", - "internalType": "address" - } - ], - "stateMutability": "view" + "name": "ExpectedPause", + "type": "error" }, { - "type": "function", - "name": "defaultAdminDelay", "inputs": [], - "outputs": [ - { - "name": "", - "type": "uint48", - "internalType": "uint48" - } - ], - "stateMutability": "view" + "name": "FailedCall", + "type": "error" }, { - "type": "function", - "name": "defaultAdminDelayIncreaseWait", "inputs": [], - "outputs": [ - { - "name": "", - "type": "uint48", - "internalType": "uint48" - } - ], - "stateMutability": "view" + "name": "FailedDeployment", + "type": "error" + }, + { + "inputs": [], + "name": "ImplementationNotSet", + "type": "error" }, { - "type": "function", - "name": "deployWallet", "inputs": [ { - "name": "label", - "type": "string", - "internalType": "string" - } - ], - "outputs": [ + "internalType": "uint96", + "name": "expected", + "type": "uint96" + }, { - "name": "wallet", - "type": "address", - "internalType": "address" + "internalType": "uint96", + "name": "provided", + "type": "uint96" } ], - "stateMutability": "nonpayable" + "name": "IndexMismatch", + "type": "error" }, { - "type": "function", - "name": "deployWalletWithSig", "inputs": [ { - "name": "intent", - "type": "tuple", - "internalType": "struct OwnerIntent", - "components": [ - { - "name": "owner", - "type": "address", - "internalType": "address" - }, - { - "name": "wallet", - "type": "address", - "internalType": "address" - }, - { - "name": "executor", - "type": "address", - "internalType": "address" - }, - { - "name": "index", - "type": "uint96", - "internalType": "uint96" - }, - { - "name": "sessionHash", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "mode", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "execCalldataHash", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "nonceKey", - "type": "uint192", - "internalType": "uint192" - }, - { - "name": "nonceSeq", - "type": "uint64", - "internalType": "uint64" - }, - { - "name": "grantNonce", - "type": "uint64", - "internalType": "uint64" - }, - { - "name": "deadline", - "type": "uint48", - "internalType": "uint48" - }, - { - "name": "signerChainId", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "name": "sig", - "type": "bytes", - "internalType": "bytes" + "internalType": "uint256", + "name": "index", + "type": "uint256" }, { - "name": "label", - "type": "string", - "internalType": "string" - } - ], - "outputs": [ - { - "name": "wallet", - "type": "address", - "internalType": "address" + "internalType": "uint256", + "name": "next", + "type": "uint256" } ], - "stateMutability": "nonpayable" + "name": "IndexOutOfRange", + "type": "error" }, { - "type": "function", - "name": "domainSeparator", "inputs": [ { - "name": "signerChainId", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [ + "internalType": "uint256", + "name": "balance", + "type": "uint256" + }, { - "name": "", - "type": "bytes32", - "internalType": "bytes32" + "internalType": "uint256", + "name": "needed", + "type": "uint256" } ], - "stateMutability": "view" + "name": "InsufficientBalance", + "type": "error" }, { - "type": "function", - "name": "getRoleAdmin", "inputs": [ { - "name": "role", - "type": "bytes32", - "internalType": "bytes32" - } - ], - "outputs": [ + "internalType": "address", + "name": "expected", + "type": "address" + }, { - "name": "", - "type": "bytes32", - "internalType": "bytes32" + "internalType": "address", + "name": "provided", + "type": "address" } ], - "stateMutability": "view" + "name": "IntentWalletMismatch", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidInitialization", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidOwnerSignature", + "type": "error" }, { - "type": "function", - "name": "grantRole", "inputs": [ { - "name": "role", - "type": "bytes32", - "internalType": "bytes32" - }, - { + "internalType": "address", "name": "account", - "type": "address", - "internalType": "address" + "type": "address" } ], - "outputs": [], - "stateMutability": "nonpayable" + "name": "NotAWallet", + "type": "error" + }, + { + "inputs": [], + "name": "NotInitializing", + "type": "error" }, { - "type": "function", - "name": "hasRole", "inputs": [ { - "name": "role", - "type": "bytes32", - "internalType": "bytes32" + "internalType": "uint8", + "name": "bits", + "type": "uint8" }, { - "name": "account", - "type": "address", - "internalType": "address" - } - ], - "outputs": [ - { - "name": "", - "type": "bool", - "internalType": "bool" + "internalType": "uint256", + "name": "value", + "type": "uint256" } ], - "stateMutability": "view" + "name": "SafeCastOverflowedUintDowncast", + "type": "error" }, { - "type": "function", - "name": "indexOf", "inputs": [ { - "name": "wallet", - "type": "address", - "internalType": "address" + "internalType": "uint48", + "name": "deadline", + "type": "uint48" } ], - "outputs": [ + "name": "SignatureExpired", + "type": "error" + }, + { + "inputs": [], + "name": "UUPSUnauthorizedCallContext", + "type": "error" + }, + { + "inputs": [ { - "name": "", - "type": "uint256", - "internalType": "uint256" + "internalType": "bytes32", + "name": "slot", + "type": "bytes32" } ], - "stateMutability": "view" + "name": "UUPSUnsupportedProxiableUUID", + "type": "error" }, { - "type": "function", - "name": "initialize", + "inputs": [], + "name": "ZeroAddress", + "type": "error" + }, + { + "anonymous": false, + "inputs": [], + "name": "DefaultAdminDelayChangeCanceled", + "type": "event" + }, + { + "anonymous": false, "inputs": [ { - "name": "admin", - "type": "address", - "internalType": "address" + "indexed": false, + "internalType": "uint48", + "name": "newDelay", + "type": "uint48" }, { - "name": "walletImplementation_", - "type": "address", - "internalType": "address" + "indexed": false, + "internalType": "uint48", + "name": "effectSchedule", + "type": "uint48" } ], - "outputs": [], - "stateMutability": "nonpayable" + "name": "DefaultAdminDelayChangeScheduled", + "type": "event" }, { - "type": "function", - "name": "isWallet", + "anonymous": false, + "inputs": [], + "name": "DefaultAdminTransferCanceled", + "type": "event" + }, + { + "anonymous": false, "inputs": [ { - "name": "account", - "type": "address", - "internalType": "address" - } - ], - "outputs": [ + "indexed": true, + "internalType": "address", + "name": "newAdmin", + "type": "address" + }, { - "name": "", - "type": "bool", - "internalType": "bool" + "indexed": false, + "internalType": "uint48", + "name": "acceptSchedule", + "type": "uint48" } ], - "stateMutability": "view" + "name": "DefaultAdminTransferScheduled", + "type": "event" }, { - "type": "function", - "name": "owner", - "inputs": [], - "outputs": [ + "anonymous": false, + "inputs": [ { - "name": "", - "type": "address", - "internalType": "address" + "indexed": false, + "internalType": "uint64", + "name": "version", + "type": "uint64" } ], - "stateMutability": "view" + "name": "Initialized", + "type": "event" }, { - "type": "function", - "name": "ownerOf", + "anonymous": false, "inputs": [ { - "name": "wallet", - "type": "address", - "internalType": "address" + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" } ], - "outputs": [ + "name": "Paused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ { - "name": "", - "type": "address", - "internalType": "address" + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "previousAdminRole", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "newAdminRole", + "type": "bytes32" } ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "pause", - "inputs": [], - "outputs": [], - "stateMutability": "nonpayable" + "name": "RoleAdminChanged", + "type": "event" }, { - "type": "function", - "name": "paused", - "inputs": [], - "outputs": [ + "anonymous": false, + "inputs": [ { - "name": "", - "type": "bool", - "internalType": "bool" + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" } ], - "stateMutability": "view" + "name": "RoleGranted", + "type": "event" }, { - "type": "function", - "name": "pendingDefaultAdmin", - "inputs": [], - "outputs": [ + "anonymous": false, + "inputs": [ { - "name": "newAdmin", - "type": "address", - "internalType": "address" + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" }, { - "name": "schedule", - "type": "uint48", - "internalType": "uint48" + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" } ], - "stateMutability": "view" + "name": "RoleRevoked", + "type": "event" }, { - "type": "function", - "name": "pendingDefaultAdminDelay", - "inputs": [], - "outputs": [ + "anonymous": false, + "inputs": [ { - "name": "newDelay", - "type": "uint48", - "internalType": "uint48" - }, + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Unpaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ { - "name": "schedule", - "type": "uint48", - "internalType": "uint48" + "indexed": true, + "internalType": "address", + "name": "implementation", + "type": "address" } ], - "stateMutability": "view" + "name": "Upgraded", + "type": "event" }, { - "type": "function", - "name": "predictWallet", + "anonymous": false, "inputs": [ { + "indexed": true, + "internalType": "address", "name": "owner", - "type": "address", - "internalType": "address" + "type": "address" }, { + "indexed": true, + "internalType": "uint256", "name": "index", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [ + "type": "uint256" + }, { + "indexed": true, + "internalType": "address", "name": "wallet", - "type": "address", - "internalType": "address" + "type": "address" }, { - "name": "deployed", - "type": "bool", - "internalType": "bool" + "indexed": false, + "internalType": "string", + "name": "label", + "type": "string" } ], - "stateMutability": "view" + "name": "WalletDeployed", + "type": "event" }, { - "type": "function", - "name": "proxiableUUID", "inputs": [], + "name": "DEFAULT_ADMIN_ROLE", "outputs": [ { + "internalType": "bytes32", "name": "", - "type": "bytes32", - "internalType": "bytes32" + "type": "bytes32" } ], - "stateMutability": "view" + "stateMutability": "view", + "type": "function" }, { - "type": "function", - "name": "renounceRole", - "inputs": [ - { - "name": "role", - "type": "bytes32", - "internalType": "bytes32" - }, + "inputs": [], + "name": "OPERATOR_ROLE", + "outputs": [ { - "name": "account", - "type": "address", - "internalType": "address" + "internalType": "bytes32", + "name": "", + "type": "bytes32" } ], - "outputs": [], - "stateMutability": "nonpayable" + "stateMutability": "view", + "type": "function" }, { - "type": "function", - "name": "revokeRole", - "inputs": [ - { - "name": "role", - "type": "bytes32", - "internalType": "bytes32" - }, + "inputs": [], + "name": "PAUSER_ROLE", + "outputs": [ { - "name": "account", - "type": "address", - "internalType": "address" + "internalType": "bytes32", + "name": "", + "type": "bytes32" } ], - "outputs": [], - "stateMutability": "nonpayable" + "stateMutability": "view", + "type": "function" }, { - "type": "function", - "name": "rollbackDefaultAdminDelay", "inputs": [], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "supportsInterface", - "inputs": [ - { - "name": "interfaceId", - "type": "bytes4", - "internalType": "bytes4" - } - ], + "name": "UPGRADE_INTERFACE_VERSION", "outputs": [ { + "internalType": "string", "name": "", - "type": "bool", - "internalType": "bool" + "type": "string" } ], - "stateMutability": "view" + "stateMutability": "view", + "type": "function" }, { - "type": "function", - "name": "unpause", "inputs": [], + "name": "acceptDefaultAdminTransfer", "outputs": [], - "stateMutability": "nonpayable" + "stateMutability": "nonpayable", + "type": "function" }, { - "type": "function", - "name": "upgradeToAndCall", "inputs": [ { - "name": "newImplementation", - "type": "address", - "internalType": "address" - }, - { - "name": "data", - "type": "bytes", - "internalType": "bytes" + "internalType": "address", + "name": "newAdmin", + "type": "address" } ], + "name": "beginDefaultAdminTransfer", "outputs": [], - "stateMutability": "payable" + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "cancelDefaultAdminTransfer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "type": "function", - "name": "walletCount", "inputs": [ { - "name": "owner", - "type": "address", - "internalType": "address" + "internalType": "uint48", + "name": "newDelay", + "type": "uint48" } ], + "name": "changeDefaultAdminDelay", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "defaultAdmin", "outputs": [ { + "internalType": "address", "name": "", - "type": "uint256", - "internalType": "uint256" + "type": "address" } ], - "stateMutability": "view" + "stateMutability": "view", + "type": "function" }, { - "type": "function", - "name": "walletImplementation", "inputs": [], + "name": "defaultAdminDelay", "outputs": [ { + "internalType": "uint48", "name": "", - "type": "address", - "internalType": "address" + "type": "uint48" } ], - "stateMutability": "view" + "stateMutability": "view", + "type": "function" }, { - "type": "event", - "name": "DefaultAdminDelayChangeCanceled", "inputs": [], - "anonymous": false + "name": "defaultAdminDelayIncreaseWait", + "outputs": [ + { + "internalType": "uint48", + "name": "", + "type": "uint48" + } + ], + "stateMutability": "view", + "type": "function" }, { - "type": "event", - "name": "DefaultAdminDelayChangeScheduled", "inputs": [ { - "name": "newDelay", - "type": "uint48", - "indexed": false, - "internalType": "uint48" - }, + "internalType": "string", + "name": "label", + "type": "string" + } + ], + "name": "deployWallet", + "outputs": [ { - "name": "effectSchedule", - "type": "uint48", - "indexed": false, - "internalType": "uint48" + "internalType": "address", + "name": "wallet", + "type": "address" } ], - "anonymous": false - }, - { - "type": "event", - "name": "DefaultAdminTransferCanceled", - "inputs": [], - "anonymous": false + "stateMutability": "nonpayable", + "type": "function" }, { - "type": "event", - "name": "DefaultAdminTransferScheduled", "inputs": [ { - "name": "newAdmin", - "type": "address", - "indexed": true, - "internalType": "address" + "components": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "wallet", + "type": "address" + }, + { + "internalType": "address", + "name": "executor", + "type": "address" + }, + { + "internalType": "uint96", + "name": "index", + "type": "uint96" + }, + { + "internalType": "bytes32", + "name": "sessionHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "mode", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "execCalldataHash", + "type": "bytes32" + }, + { + "internalType": "uint192", + "name": "nonceKey", + "type": "uint192" + }, + { + "internalType": "uint64", + "name": "nonceSeq", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "grantNonce", + "type": "uint64" + }, + { + "internalType": "uint48", + "name": "deadline", + "type": "uint48" + }, + { + "internalType": "uint256", + "name": "signerChainId", + "type": "uint256" + } + ], + "internalType": "struct OwnerIntent", + "name": "intent", + "type": "tuple" }, { - "name": "acceptSchedule", - "type": "uint48", - "indexed": false, - "internalType": "uint48" + "internalType": "bytes", + "name": "sig", + "type": "bytes" + }, + { + "internalType": "string", + "name": "label", + "type": "string" } ], - "anonymous": false - }, - { - "type": "event", - "name": "Initialized", - "inputs": [ + "name": "deployWalletWithSig", + "outputs": [ { - "name": "version", - "type": "uint64", - "indexed": false, - "internalType": "uint64" + "internalType": "address", + "name": "wallet", + "type": "address" } ], - "anonymous": false + "stateMutability": "nonpayable", + "type": "function" }, { - "type": "event", - "name": "Paused", "inputs": [ { - "name": "account", - "type": "address", - "indexed": false, - "internalType": "address" + "internalType": "uint256", + "name": "signerChainId", + "type": "uint256" + } + ], + "name": "domainSeparator", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" } ], - "anonymous": false + "stateMutability": "view", + "type": "function" }, { - "type": "event", - "name": "RoleAdminChanged", "inputs": [ { + "internalType": "bytes32", "name": "role", - "type": "bytes32", - "indexed": true, - "internalType": "bytes32" - }, - { - "name": "previousAdminRole", - "type": "bytes32", - "indexed": true, - "internalType": "bytes32" - }, + "type": "bytes32" + } + ], + "name": "getRoleAdmin", + "outputs": [ { - "name": "newAdminRole", - "type": "bytes32", - "indexed": true, - "internalType": "bytes32" + "internalType": "bytes32", + "name": "", + "type": "bytes32" } ], - "anonymous": false + "stateMutability": "view", + "type": "function" }, { - "type": "event", - "name": "RoleGranted", "inputs": [ { + "internalType": "bytes32", "name": "role", - "type": "bytes32", - "indexed": true, - "internalType": "bytes32" + "type": "bytes32" }, { + "internalType": "address", "name": "account", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "sender", - "type": "address", - "indexed": true, - "internalType": "address" + "type": "address" } ], - "anonymous": false + "name": "grantRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "type": "event", - "name": "RoleRevoked", "inputs": [ { + "internalType": "bytes32", "name": "role", - "type": "bytes32", - "indexed": true, - "internalType": "bytes32" + "type": "bytes32" }, { + "internalType": "address", "name": "account", - "type": "address", - "indexed": true, - "internalType": "address" - }, + "type": "address" + } + ], + "name": "hasRole", + "outputs": [ { - "name": "sender", - "type": "address", - "indexed": true, - "internalType": "address" + "internalType": "bool", + "name": "", + "type": "bool" } ], - "anonymous": false + "stateMutability": "view", + "type": "function" }, { - "type": "event", - "name": "Unpaused", "inputs": [ { - "name": "account", - "type": "address", - "indexed": false, - "internalType": "address" + "internalType": "address", + "name": "wallet", + "type": "address" } ], - "anonymous": false - }, - { - "type": "event", - "name": "Upgraded", - "inputs": [ + "name": "indexOf", + "outputs": [ { - "name": "implementation", - "type": "address", - "indexed": true, - "internalType": "address" + "internalType": "uint256", + "name": "", + "type": "uint256" } ], - "anonymous": false + "stateMutability": "view", + "type": "function" }, { - "type": "event", - "name": "WalletDeployed", "inputs": [ { - "name": "owner", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "index", - "type": "uint256", - "indexed": true, - "internalType": "uint256" - }, - { - "name": "wallet", - "type": "address", - "indexed": true, - "internalType": "address" + "internalType": "address", + "name": "admin", + "type": "address" }, { - "name": "label", - "type": "string", - "indexed": false, - "internalType": "string" + "internalType": "address", + "name": "walletImplementation_", + "type": "address" } ], - "anonymous": false - }, - { - "type": "error", - "name": "AccessControlBadConfirmation", - "inputs": [] + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "type": "error", - "name": "AccessControlEnforcedDefaultAdminDelay", "inputs": [ { - "name": "schedule", - "type": "uint48", - "internalType": "uint48" + "internalType": "address", + "name": "account", + "type": "address" } - ] - }, - { - "type": "error", - "name": "AccessControlEnforcedDefaultAdminRules", - "inputs": [] - }, - { - "type": "error", - "name": "AccessControlInvalidDefaultAdmin", - "inputs": [ + ], + "name": "isWallet", + "outputs": [ { - "name": "defaultAdmin", - "type": "address", - "internalType": "address" + "internalType": "bool", + "name": "", + "type": "bool" } - ] + ], + "stateMutability": "view", + "type": "function" }, { - "type": "error", - "name": "AccessControlUnauthorizedAccount", - "inputs": [ - { - "name": "account", - "type": "address", - "internalType": "address" - }, + "inputs": [], + "name": "owner", + "outputs": [ { - "name": "neededRole", - "type": "bytes32", - "internalType": "bytes32" + "internalType": "address", + "name": "", + "type": "address" } - ] + ], + "stateMutability": "view", + "type": "function" }, { - "type": "error", - "name": "AddressEmptyCode", "inputs": [ { - "name": "target", - "type": "address", - "internalType": "address" + "internalType": "address", + "name": "wallet", + "type": "address" } - ] - }, - { - "type": "error", - "name": "CloneArgumentsTooLong", - "inputs": [] - }, - { - "type": "error", - "name": "Create2EmptyBytecode", - "inputs": [] - }, - { - "type": "error", - "name": "ERC1967InvalidImplementation", - "inputs": [ + ], + "name": "ownerOf", + "outputs": [ { - "name": "implementation", - "type": "address", - "internalType": "address" + "internalType": "address", + "name": "", + "type": "address" } - ] + ], + "stateMutability": "view", + "type": "function" }, { - "type": "error", - "name": "ERC1967NonPayable", - "inputs": [] + "inputs": [], + "name": "pause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "type": "error", - "name": "EnforcedPause", - "inputs": [] + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" }, { - "type": "error", - "name": "ExecutorMismatch", - "inputs": [ + "inputs": [], + "name": "pendingDefaultAdmin", + "outputs": [ { - "name": "expected", - "type": "address", - "internalType": "address" + "internalType": "address", + "name": "newAdmin", + "type": "address" }, { - "name": "actual", - "type": "address", - "internalType": "address" + "internalType": "uint48", + "name": "schedule", + "type": "uint48" } - ] - }, - { - "type": "error", - "name": "ExpectedPause", - "inputs": [] - }, - { - "type": "error", - "name": "FailedCall", - "inputs": [] - }, - { - "type": "error", - "name": "FailedDeployment", - "inputs": [] - }, - { - "type": "error", - "name": "ImplementationNotSet", - "inputs": [] + ], + "stateMutability": "view", + "type": "function" }, { - "type": "error", - "name": "IndexMismatch", - "inputs": [ + "inputs": [], + "name": "pendingDefaultAdminDelay", + "outputs": [ { - "name": "expected", - "type": "uint96", - "internalType": "uint96" + "internalType": "uint48", + "name": "newDelay", + "type": "uint48" }, { - "name": "provided", - "type": "uint96", - "internalType": "uint96" + "internalType": "uint48", + "name": "schedule", + "type": "uint48" } - ] + ], + "stateMutability": "view", + "type": "function" }, { - "type": "error", - "name": "IndexOutOfRange", "inputs": [ { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "uint256", "name": "index", - "type": "uint256", - "internalType": "uint256" + "type": "uint256" + } + ], + "name": "predictWallet", + "outputs": [ + { + "internalType": "address", + "name": "wallet", + "type": "address" }, { - "name": "next", - "type": "uint256", - "internalType": "uint256" + "internalType": "bool", + "name": "deployed", + "type": "bool" } - ] + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proxiableUUID", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" }, { - "type": "error", - "name": "InsufficientBalance", "inputs": [ { - "name": "balance", - "type": "uint256", - "internalType": "uint256" + "internalType": "bytes32", + "name": "role", + "type": "bytes32" }, { - "name": "needed", - "type": "uint256", - "internalType": "uint256" + "internalType": "address", + "name": "account", + "type": "address" } - ] + ], + "name": "renounceRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "type": "error", - "name": "IntentWalletMismatch", "inputs": [ { - "name": "expected", - "type": "address", - "internalType": "address" + "internalType": "bytes32", + "name": "role", + "type": "bytes32" }, { - "name": "provided", - "type": "address", - "internalType": "address" + "internalType": "address", + "name": "account", + "type": "address" } - ] - }, - { - "type": "error", - "name": "InvalidInitialization", - "inputs": [] + ], + "name": "revokeRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "type": "error", - "name": "InvalidOwnerSignature", - "inputs": [] + "inputs": [], + "name": "rollbackDefaultAdminDelay", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "type": "error", - "name": "NotAWallet", "inputs": [ { - "name": "account", - "type": "address", - "internalType": "address" + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" } - ] + ], + "stateMutability": "view", + "type": "function" }, { - "type": "error", - "name": "NotInitializing", - "inputs": [] + "inputs": [], + "name": "unpause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "type": "error", - "name": "SafeCastOverflowedUintDowncast", "inputs": [ { - "name": "bits", - "type": "uint8", - "internalType": "uint8" + "internalType": "address", + "name": "newImplementation", + "type": "address" }, { - "name": "value", - "type": "uint256", - "internalType": "uint256" + "internalType": "bytes", + "name": "data", + "type": "bytes" } - ] + ], + "name": "upgradeToAndCall", + "outputs": [], + "stateMutability": "payable", + "type": "function" }, { - "type": "error", - "name": "SignatureExpired", "inputs": [ { - "name": "deadline", - "type": "uint48", - "internalType": "uint48" + "internalType": "address", + "name": "owner", + "type": "address" } - ] - }, - { - "type": "error", - "name": "UUPSUnauthorizedCallContext", - "inputs": [] - }, - { - "type": "error", - "name": "UUPSUnsupportedProxiableUUID", - "inputs": [ + ], + "name": "walletCount", + "outputs": [ { - "name": "slot", - "type": "bytes32", - "internalType": "bytes32" + "internalType": "uint256", + "name": "", + "type": "uint256" } - ] + ], + "stateMutability": "view", + "type": "function" }, { - "type": "error", - "name": "ZeroAddress", - "inputs": [] + "inputs": [], + "name": "walletImplementation", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" } ] as const; diff --git a/packages/core/src/lib/agentic/contracts/abi/e704d5b/agw.ts b/packages/core/src/lib/agentic/contracts/abi/v4/agw.ts similarity index 52% rename from packages/core/src/lib/agentic/contracts/abi/e704d5b/agw.ts rename to packages/core/src/lib/agentic/contracts/abi/v4/agw.ts index 470b61ca..3407d5ad 100644 --- a/packages/core/src/lib/agentic/contracts/abi/e704d5b/agw.ts +++ b/packages/core/src/lib/agentic/contracts/abi/v4/agw.ts @@ -1,1528 +1,1528 @@ // GENERATED by packages/core/scripts/agw-local/gen-abi.mjs — do not edit. -// Source: plan/agw/research/validation-e704d5b/abi/AGW.json -// push-agentic-wallets@e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9 -// sha256(AGW.json) = ca41d463fac3f7ec8c4399402f2afe41678f43d75baf2ad0220a804699e1fd7b +// Source: plan/agw/research/deployment-review-2026-10-06/abis/AGW.json +// push-agentic-wallets@e8db74815cfbbf5389593805e464fe8d85f7f735 +// sha256(AGW.json) = ba68ef8f86e7154df29c4bb3ec9b90ae0d8a5193cad6e34772276475a2846ebe export const AGW_ABI = [ { - "type": "receive", - "stateMutability": "payable" + "inputs": [], + "name": "AlreadyInitialized", + "type": "error" }, { - "type": "function", - "name": "RULES_POLICY", - "inputs": [], - "outputs": [ + "inputs": [ { - "name": "", - "type": "address", - "internalType": "address" + "internalType": "bytes32", + "name": "rulesId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "caller", + "type": "address" } ], - "stateMutability": "view" + "name": "CallerIsNotAgent", + "type": "error" }, { - "type": "function", - "name": "SESSION_ENGINE", "inputs": [], - "outputs": [ + "name": "CallerIsNotFactory", + "type": "error" + }, + { + "inputs": [], + "name": "CallerIsNotOwner", + "type": "error" + }, + { + "inputs": [ { - "name": "", - "type": "address", - "internalType": "address" + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "bytes4", + "name": "selector", + "type": "bytes4" } ], - "stateMutability": "view" + "name": "DuplicateAction", + "type": "error" }, { - "type": "function", - "name": "SESSION_VALIDATOR", "inputs": [], - "outputs": [ + "name": "EmptyChain", + "type": "error" + }, + { + "inputs": [], + "name": "EngineStillHoldsPermissions", + "type": "error" + }, + { + "inputs": [ { - "name": "", - "type": "address", - "internalType": "address" + "internalType": "address", + "name": "expected", + "type": "address" + }, + { + "internalType": "address", + "name": "actual", + "type": "address" } ], - "stateMutability": "view" + "name": "ExecutorMismatch", + "type": "error" }, { - "type": "function", - "name": "UNIVERSAL_GATEWAY_PC", - "inputs": [], - "outputs": [ + "inputs": [ { - "name": "", - "type": "address", - "internalType": "address" + "internalType": "bytes4", + "name": "selector", + "type": "bytes4" } ], - "stateMutability": "view" + "name": "ForbiddenActionSelector", + "type": "error" }, { - "type": "function", - "name": "accountId", - "inputs": [], - "outputs": [ + "inputs": [ { - "name": "", - "type": "string", - "internalType": "string" + "internalType": "address", + "name": "target", + "type": "address" } ], - "stateMutability": "pure" + "name": "ForbiddenActionTarget", + "type": "error" }, { - "type": "function", - "name": "agentOf", "inputs": [ { - "name": "rulesId", - "type": "bytes32", - "internalType": "bytes32" + "internalType": "address", + "name": "target", + "type": "address" } ], - "outputs": [ + "name": "ForbiddenDispatchTarget", + "type": "error" + }, + { + "inputs": [ { - "name": "", - "type": "address", - "internalType": "address" + "internalType": "uint256", + "name": "actionIndex", + "type": "uint256" } ], - "stateMutability": "view" + "name": "InconsistentChain", + "type": "error" }, { - "type": "function", - "name": "checkpointCount", - "inputs": [], - "outputs": [ + "inputs": [ { - "name": "", - "type": "uint64", - "internalType": "uint64" + "internalType": "bytes32", + "name": "actualCalldataHash", + "type": "bytes32" } ], - "stateMutability": "view" + "name": "IntentExecMismatch", + "type": "error" }, { - "type": "function", - "name": "domainSeparator", "inputs": [ { - "name": "signerChainId", - "type": "uint256", - "internalType": "uint256" + "internalType": "uint64", + "name": "expected", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "provided", + "type": "uint64" } ], - "outputs": [ + "name": "IntentGrantNonceMismatch", + "type": "error" + }, + { + "inputs": [ { - "name": "", - "type": "bytes32", - "internalType": "bytes32" + "internalType": "bytes32", + "name": "actual", + "type": "bytes32" } ], - "stateMutability": "view" + "name": "IntentSessionMismatch", + "type": "error" }, { - "type": "function", - "name": "execute", "inputs": [ { - "name": "mode", - "type": "bytes32", - "internalType": "bytes32" + "internalType": "address", + "name": "expected", + "type": "address" }, { - "name": "executionCalldata", - "type": "bytes", - "internalType": "bytes" + "internalType": "address", + "name": "provided", + "type": "address" } ], - "outputs": [], - "stateMutability": "payable" + "name": "IntentWalletMismatch", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidModuleAddress", + "type": "error" }, { - "type": "function", - "name": "executeAsAgent", "inputs": [ { - "name": "rulesId", - "type": "bytes32", - "internalType": "bytes32" + "internalType": "uint192", + "name": "nonceKey", + "type": "uint192" }, { - "name": "mode", - "type": "bytes32", - "internalType": "bytes32" + "internalType": "uint64", + "name": "expected", + "type": "uint64" }, { - "name": "executionCalldata", - "type": "bytes", - "internalType": "bytes" + "internalType": "uint64", + "name": "provided", + "type": "uint64" } ], - "outputs": [], - "stateMutability": "nonpayable" + "name": "InvalidNonce", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidOwnerSignature", + "type": "error" + }, + { + "inputs": [], + "name": "MalformedBatchCalldata", + "type": "error" + }, + { + "inputs": [], + "name": "MalformedSessionShape", + "type": "error" }, { - "type": "function", - "name": "executeWithSig", "inputs": [ { - "name": "mode", - "type": "bytes32", - "internalType": "bytes32" + "internalType": "address", + "name": "module", + "type": "address" + } + ], + "name": "ModuleAlreadyInstalled", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint48", + "name": "validAfter", + "type": "uint48" }, { - "name": "executionCalldata", - "type": "bytes", - "internalType": "bytes" + "internalType": "uint48", + "name": "validUntil", + "type": "uint48" + } + ], + "name": "OutsideTimeWindow", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint192", + "name": "nonceKey", + "type": "uint192" + } + ], + "name": "OwnerLaneRequired", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint48", + "name": "deadline", + "type": "uint48" + } + ], + "name": "OwnerSigExpired", + "type": "error" + }, + { + "inputs": [], + "name": "ReentrancyGuardReentrantCall", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "enum RulesType", + "name": "derived", + "type": "uint8" }, { - "name": "intent", - "type": "tuple", - "internalType": "struct OwnerIntent", - "components": [ - { - "name": "owner", - "type": "address", - "internalType": "address" - }, - { - "name": "wallet", - "type": "address", - "internalType": "address" - }, - { - "name": "executor", - "type": "address", - "internalType": "address" - }, - { - "name": "index", - "type": "uint96", - "internalType": "uint96" - }, - { - "name": "sessionHash", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "mode", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "execCalldataHash", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "nonceKey", - "type": "uint192", - "internalType": "uint192" - }, - { - "name": "nonceSeq", - "type": "uint64", - "internalType": "uint64" - }, - { - "name": "grantNonce", - "type": "uint64", - "internalType": "uint64" - }, - { - "name": "deadline", - "type": "uint48", - "internalType": "uint48" - }, - { - "name": "signerChainId", - "type": "uint256", - "internalType": "uint256" - } - ] + "internalType": "uint256", + "name": "actionIndex", + "type": "uint256" }, { - "name": "sig", - "type": "bytes", - "internalType": "bytes" + "internalType": "address", + "name": "target", + "type": "address" } ], - "outputs": [], - "stateMutability": "nonpayable" + "name": "RulesTypeMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "count", + "type": "uint256" + } + ], + "name": "TooManyActions", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "rulesId", + "type": "bytes32" + } + ], + "name": "UnknownPermission", + "type": "error" }, { - "type": "function", - "name": "factory", "inputs": [], - "outputs": [ + "name": "UnsupportedExecutionMode", + "type": "error" + }, + { + "inputs": [ { - "name": "", - "type": "address", - "internalType": "address" + "internalType": "uint256", + "name": "moduleTypeId", + "type": "uint256" } ], - "stateMutability": "view" + "name": "UnsupportedModuleType", + "type": "error" }, { - "type": "function", - "name": "getNonce", "inputs": [ { - "name": "nonceKey", - "type": "uint192", - "internalType": "uint192" + "internalType": "address", + "name": "authorizer", + "type": "address" } ], - "outputs": [ + "name": "ValidationFailed", + "type": "error" + }, + { + "inputs": [ { - "name": "", - "type": "uint64", - "internalType": "uint64" + "internalType": "address", + "name": "validator", + "type": "address" } ], - "stateMutability": "view" + "name": "ValidatorNotInstalled", + "type": "error" }, { - "type": "function", - "name": "grantNonce", - "inputs": [], - "outputs": [ + "anonymous": false, + "inputs": [ { - "name": "", - "type": "uint64", - "internalType": "uint64" + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "engine", + "type": "address" } ], - "stateMutability": "view" + "name": "AccountInitialized", + "type": "event" }, { - "type": "function", - "name": "grantRules", + "anonymous": false, "inputs": [ { - "name": "session", - "type": "tuple", - "internalType": "struct Session", - "components": [ - { - "name": "sessionValidator", - "type": "address", - "internalType": "contract ISessionValidator" - }, - { - "name": "sessionValidatorInitData", - "type": "bytes", - "internalType": "bytes" - }, - { - "name": "salt", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "userOpPolicies", - "type": "tuple[]", - "internalType": "struct PolicyData[]", - "components": [ - { - "name": "policy", - "type": "address", - "internalType": "address" - }, - { - "name": "initData", - "type": "bytes", - "internalType": "bytes" - } - ] - }, - { - "name": "erc7739Policies", - "type": "tuple", - "internalType": "struct ERC7739Data", - "components": [ - { - "name": "allowedERC7739Content", - "type": "tuple[]", - "internalType": "struct ERC7739Context[]", - "components": [ - { - "name": "appDomainSeparator", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "contentNames", - "type": "string[]", - "internalType": "string[]" - } - ] - }, - { - "name": "erc1271Policies", - "type": "tuple[]", - "internalType": "struct PolicyData[]", - "components": [ - { - "name": "policy", - "type": "address", - "internalType": "address" - }, - { - "name": "initData", - "type": "bytes", - "internalType": "bytes" - } - ] - } - ] - }, - { - "name": "actions", - "type": "tuple[]", - "internalType": "struct ActionData[]", - "components": [ - { - "name": "actionTargetSelector", - "type": "bytes4", - "internalType": "bytes4" - }, - { - "name": "actionTarget", - "type": "address", - "internalType": "address" - }, - { - "name": "actionPolicies", - "type": "tuple[]", - "internalType": "struct PolicyData[]", - "components": [ - { - "name": "policy", - "type": "address", - "internalType": "address" - }, - { - "name": "initData", - "type": "bytes", - "internalType": "bytes" - } - ] - } - ] - }, - { - "name": "permitERC4337Paymaster", - "type": "bool", - "internalType": "bool" - } - ] - } - ], - "outputs": [ - { - "name": "rulesId", - "type": "bytes32", - "internalType": "bytes32" - } - ], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "grantRulesWithSig", - "inputs": [ - { - "name": "session", - "type": "tuple", - "internalType": "struct Session", - "components": [ - { - "name": "sessionValidator", - "type": "address", - "internalType": "contract ISessionValidator" - }, - { - "name": "sessionValidatorInitData", - "type": "bytes", - "internalType": "bytes" - }, - { - "name": "salt", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "userOpPolicies", - "type": "tuple[]", - "internalType": "struct PolicyData[]", - "components": [ - { - "name": "policy", - "type": "address", - "internalType": "address" - }, - { - "name": "initData", - "type": "bytes", - "internalType": "bytes" - } - ] - }, - { - "name": "erc7739Policies", - "type": "tuple", - "internalType": "struct ERC7739Data", - "components": [ - { - "name": "allowedERC7739Content", - "type": "tuple[]", - "internalType": "struct ERC7739Context[]", - "components": [ - { - "name": "appDomainSeparator", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "contentNames", - "type": "string[]", - "internalType": "string[]" - } - ] - }, - { - "name": "erc1271Policies", - "type": "tuple[]", - "internalType": "struct PolicyData[]", - "components": [ - { - "name": "policy", - "type": "address", - "internalType": "address" - }, - { - "name": "initData", - "type": "bytes", - "internalType": "bytes" - } - ] - } - ] - }, - { - "name": "actions", - "type": "tuple[]", - "internalType": "struct ActionData[]", - "components": [ - { - "name": "actionTargetSelector", - "type": "bytes4", - "internalType": "bytes4" - }, - { - "name": "actionTarget", - "type": "address", - "internalType": "address" - }, - { - "name": "actionPolicies", - "type": "tuple[]", - "internalType": "struct PolicyData[]", - "components": [ - { - "name": "policy", - "type": "address", - "internalType": "address" - }, - { - "name": "initData", - "type": "bytes", - "internalType": "bytes" - } - ] - } - ] - }, - { - "name": "permitERC4337Paymaster", - "type": "bool", - "internalType": "bool" - } - ] + "indexed": true, + "internalType": "uint64", + "name": "seq", + "type": "uint64" }, { - "name": "intent", - "type": "tuple", - "internalType": "struct OwnerIntent", - "components": [ - { - "name": "owner", - "type": "address", - "internalType": "address" - }, - { - "name": "wallet", - "type": "address", - "internalType": "address" - }, - { - "name": "executor", - "type": "address", - "internalType": "address" - }, - { - "name": "index", - "type": "uint96", - "internalType": "uint96" - }, - { - "name": "sessionHash", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "mode", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "execCalldataHash", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "nonceKey", - "type": "uint192", - "internalType": "uint192" - }, - { - "name": "nonceSeq", - "type": "uint64", - "internalType": "uint64" - }, - { - "name": "grantNonce", - "type": "uint64", - "internalType": "uint64" - }, - { - "name": "deadline", - "type": "uint48", - "internalType": "uint48" - }, - { - "name": "signerChainId", - "type": "uint256", - "internalType": "uint256" - } - ] + "indexed": false, + "internalType": "enum CheckpointKind", + "name": "kind", + "type": "uint8" }, { - "name": "sig", - "type": "bytes", - "internalType": "bytes" - } - ], - "outputs": [ + "indexed": false, + "internalType": "bytes32", + "name": "ref", + "type": "bytes32" + }, { - "name": "rulesId", - "type": "bytes32", - "internalType": "bytes32" + "indexed": false, + "internalType": "uint64", + "name": "blockNumber", + "type": "uint64" } ], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "initializeAccount", - "inputs": [], - "outputs": [], - "stateMutability": "nonpayable" + "name": "Checkpointed", + "type": "event" }, { - "type": "function", - "name": "installModule", + "anonymous": false, "inputs": [ { + "indexed": false, + "internalType": "uint256", "name": "moduleTypeId", - "type": "uint256", - "internalType": "uint256" + "type": "uint256" }, { + "indexed": false, + "internalType": "address", "name": "module", - "type": "address", - "internalType": "address" - }, - { - "name": "initData", - "type": "bytes", - "internalType": "bytes" + "type": "address" } ], - "outputs": [], - "stateMutability": "nonpayable" + "name": "ModuleInstalled", + "type": "event" }, { - "type": "function", - "name": "isModuleInstalled", + "anonymous": false, "inputs": [ { + "indexed": false, + "internalType": "uint256", "name": "moduleTypeId", - "type": "uint256", - "internalType": "uint256" + "type": "uint256" }, { + "indexed": false, + "internalType": "address", "name": "module", - "type": "address", - "internalType": "address" - }, - { - "name": "", - "type": "bytes", - "internalType": "bytes" - } - ], - "outputs": [ - { - "name": "", - "type": "bool", - "internalType": "bool" + "type": "address" } ], - "stateMutability": "view" + "name": "ModuleUninstalled", + "type": "event" }, { - "type": "function", - "name": "isValidSignature", + "anonymous": false, "inputs": [ { - "name": "", - "type": "bytes32", - "internalType": "bytes32" + "indexed": true, + "internalType": "bytes32", + "name": "mode", + "type": "bytes32" }, { - "name": "", - "type": "bytes", - "internalType": "bytes" - } - ], - "outputs": [ - { - "name": "", - "type": "bytes4", - "internalType": "bytes4" + "indexed": false, + "internalType": "bytes32", + "name": "executionCalldataHash", + "type": "bytes32" } ], - "stateMutability": "pure" + "name": "OwnerExecuted", + "type": "event" }, { - "type": "function", - "name": "lastCheckpointBlock", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "uint64", - "internalType": "uint64" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "onERC1155BatchReceived", + "anonymous": false, "inputs": [ { - "name": "", - "type": "address", - "internalType": "address" - }, - { - "name": "", - "type": "address", - "internalType": "address" + "indexed": true, + "internalType": "bytes32", + "name": "mode", + "type": "bytes32" }, { - "name": "", - "type": "uint256[]", - "internalType": "uint256[]" + "indexed": false, + "internalType": "bytes32", + "name": "executionCalldataHash", + "type": "bytes32" }, { - "name": "", - "type": "uint256[]", - "internalType": "uint256[]" + "indexed": false, + "internalType": "uint192", + "name": "nonceKey", + "type": "uint192" }, { - "name": "", - "type": "bytes", - "internalType": "bytes" + "indexed": false, + "internalType": "uint64", + "name": "nonceSeq", + "type": "uint64" } ], - "outputs": [ + "name": "OwnerExecutedWithSig", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ { - "name": "", - "type": "bytes4", - "internalType": "bytes4" + "indexed": true, + "internalType": "bytes32", + "name": "rulesId", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "agent", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "callsHash", + "type": "bytes32" } ], - "stateMutability": "pure" + "name": "RulesActionAuthorized", + "type": "event" }, { - "type": "function", - "name": "onERC1155Received", + "anonymous": false, "inputs": [ { - "name": "", - "type": "address", - "internalType": "address" - }, - { - "name": "", - "type": "address", - "internalType": "address" + "indexed": true, + "internalType": "bytes32", + "name": "rulesId", + "type": "bytes32" }, { - "name": "", - "type": "uint256", - "internalType": "uint256" + "indexed": false, + "internalType": "enum RulesType", + "name": "mode", + "type": "uint8" }, { - "name": "", - "type": "uint256", - "internalType": "uint256" + "indexed": true, + "internalType": "bytes32", + "name": "chainHash", + "type": "bytes32" }, { - "name": "", - "type": "bytes", - "internalType": "bytes" + "indexed": false, + "internalType": "string", + "name": "chainNamespace", + "type": "string" } ], - "outputs": [ + "name": "RulesGranted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ { - "name": "", - "type": "bytes4", - "internalType": "bytes4" + "indexed": true, + "internalType": "bytes32", + "name": "rulesId", + "type": "bytes32" } ], - "stateMutability": "pure" + "name": "RulesRevoked", + "type": "event" }, { - "type": "function", - "name": "onERC721Received", + "anonymous": false, "inputs": [ { - "name": "", - "type": "address", - "internalType": "address" - }, - { - "name": "", - "type": "address", - "internalType": "address" - }, - { - "name": "", - "type": "uint256", - "internalType": "uint256" - }, + "indexed": false, + "internalType": "address", + "name": "module", + "type": "address" + } + ], + "name": "UninstallCallbackFailed", + "type": "event" + }, + { + "inputs": [], + "name": "RULES_POLICY", + "outputs": [ { + "internalType": "address", "name": "", - "type": "bytes", - "internalType": "bytes" + "type": "address" } ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "SESSION_ENGINE", "outputs": [ { + "internalType": "address", "name": "", - "type": "bytes4", - "internalType": "bytes4" + "type": "address" } ], - "stateMutability": "pure" + "stateMutability": "view", + "type": "function" }, { - "type": "function", - "name": "owner", "inputs": [], + "name": "SESSION_VALIDATOR", "outputs": [ { + "internalType": "address", "name": "", - "type": "address", - "internalType": "address" + "type": "address" } ], - "stateMutability": "view" + "stateMutability": "view", + "type": "function" }, { - "type": "function", - "name": "revokeAllRules", "inputs": [], - "outputs": [], - "stateMutability": "nonpayable" + "name": "UNIVERSAL_GATEWAY_PC", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" }, { - "type": "function", - "name": "revokeRules", - "inputs": [ + "inputs": [], + "name": "accountId", + "outputs": [ { - "name": "rulesId", - "type": "bytes32", - "internalType": "bytes32" + "internalType": "string", + "name": "", + "type": "string" } ], - "outputs": [], - "stateMutability": "nonpayable" + "stateMutability": "pure", + "type": "function" }, { - "type": "function", - "name": "supportsExecutionMode", "inputs": [ { - "name": "mode", - "type": "bytes32", - "internalType": "bytes32" + "internalType": "bytes32", + "name": "rulesId", + "type": "bytes32" } ], + "name": "agentOf", "outputs": [ { + "internalType": "address", "name": "", - "type": "bool", - "internalType": "bool" + "type": "address" } ], - "stateMutability": "pure" + "stateMutability": "view", + "type": "function" }, { - "type": "function", - "name": "supportsInterface", - "inputs": [ - { - "name": "interfaceId", - "type": "bytes4", - "internalType": "bytes4" - } - ], + "inputs": [], + "name": "checkpointCount", "outputs": [ { + "internalType": "uint64", "name": "", - "type": "bool", - "internalType": "bool" + "type": "uint64" } ], - "stateMutability": "pure" + "stateMutability": "view", + "type": "function" }, { - "type": "function", - "name": "supportsModule", "inputs": [ { - "name": "moduleTypeId", - "type": "uint256", - "internalType": "uint256" + "internalType": "uint256", + "name": "signerChainId", + "type": "uint256" } ], + "name": "domainSeparator", "outputs": [ { + "internalType": "bytes32", "name": "", - "type": "bool", - "internalType": "bool" + "type": "bytes32" } ], - "stateMutability": "pure" + "stateMutability": "view", + "type": "function" }, { - "type": "function", - "name": "uninstallModule", "inputs": [ { - "name": "moduleTypeId", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "module", - "type": "address", - "internalType": "address" + "internalType": "bytes32", + "name": "mode", + "type": "bytes32" }, { - "name": "deInitData", - "type": "bytes", - "internalType": "bytes" + "internalType": "bytes", + "name": "executionCalldata", + "type": "bytes" } ], + "name": "execute", "outputs": [], - "stateMutability": "nonpayable" + "stateMutability": "payable", + "type": "function" }, { - "type": "event", - "name": "AccountInitialized", "inputs": [ { - "name": "owner", - "type": "address", - "indexed": true, - "internalType": "address" + "internalType": "bytes32", + "name": "rulesId", + "type": "bytes32" }, { - "name": "engine", - "type": "address", - "indexed": true, - "internalType": "address" + "internalType": "bytes32", + "name": "mode", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "executionCalldata", + "type": "bytes" } ], - "anonymous": false + "name": "executeAsAgent", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "type": "event", - "name": "Checkpointed", "inputs": [ { - "name": "seq", - "type": "uint64", - "indexed": true, - "internalType": "uint64" + "internalType": "bytes32", + "name": "mode", + "type": "bytes32" }, { - "name": "kind", - "type": "uint8", - "indexed": false, - "internalType": "enum CheckpointKind" + "internalType": "bytes", + "name": "executionCalldata", + "type": "bytes" }, { - "name": "ref", - "type": "bytes32", - "indexed": false, - "internalType": "bytes32" + "components": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "wallet", + "type": "address" + }, + { + "internalType": "address", + "name": "executor", + "type": "address" + }, + { + "internalType": "uint96", + "name": "index", + "type": "uint96" + }, + { + "internalType": "bytes32", + "name": "sessionHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "mode", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "execCalldataHash", + "type": "bytes32" + }, + { + "internalType": "uint192", + "name": "nonceKey", + "type": "uint192" + }, + { + "internalType": "uint64", + "name": "nonceSeq", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "grantNonce", + "type": "uint64" + }, + { + "internalType": "uint48", + "name": "deadline", + "type": "uint48" + }, + { + "internalType": "uint256", + "name": "signerChainId", + "type": "uint256" + } + ], + "internalType": "struct OwnerIntent", + "name": "intent", + "type": "tuple" }, { - "name": "blockNumber", - "type": "uint64", - "indexed": false, - "internalType": "uint64" + "internalType": "bytes", + "name": "sig", + "type": "bytes" } ], - "anonymous": false + "name": "executeWithSig", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "type": "event", - "name": "ModuleInstalled", - "inputs": [ - { - "name": "moduleTypeId", - "type": "uint256", - "indexed": false, - "internalType": "uint256" - }, + "inputs": [], + "name": "factory", + "outputs": [ { - "name": "module", - "type": "address", - "indexed": false, - "internalType": "address" + "internalType": "address", + "name": "", + "type": "address" } ], - "anonymous": false + "stateMutability": "view", + "type": "function" }, { - "type": "event", - "name": "ModuleUninstalled", "inputs": [ { - "name": "moduleTypeId", - "type": "uint256", - "indexed": false, - "internalType": "uint256" - }, + "internalType": "uint192", + "name": "nonceKey", + "type": "uint192" + } + ], + "name": "getNonce", + "outputs": [ { - "name": "module", - "type": "address", - "indexed": false, - "internalType": "address" + "internalType": "uint64", + "name": "", + "type": "uint64" } ], - "anonymous": false + "stateMutability": "view", + "type": "function" }, { - "type": "event", - "name": "OwnerExecuted", - "inputs": [ - { - "name": "mode", - "type": "bytes32", - "indexed": true, - "internalType": "bytes32" - }, + "inputs": [], + "name": "grantNonce", + "outputs": [ { - "name": "executionCalldataHash", - "type": "bytes32", - "indexed": false, - "internalType": "bytes32" + "internalType": "uint64", + "name": "", + "type": "uint64" } ], - "anonymous": false + "stateMutability": "view", + "type": "function" }, { - "type": "event", - "name": "OwnerExecutedWithSig", "inputs": [ { - "name": "mode", - "type": "bytes32", - "indexed": true, - "internalType": "bytes32" - }, - { - "name": "executionCalldataHash", - "type": "bytes32", - "indexed": false, - "internalType": "bytes32" - }, - { - "name": "nonceKey", - "type": "uint192", - "indexed": false, - "internalType": "uint192" - }, - { - "name": "nonceSeq", - "type": "uint64", - "indexed": false, - "internalType": "uint64" + "components": [ + { + "internalType": "contract ISessionValidator", + "name": "sessionValidator", + "type": "address" + }, + { + "internalType": "bytes", + "name": "sessionValidatorInitData", + "type": "bytes" + }, + { + "internalType": "bytes32", + "name": "salt", + "type": "bytes32" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "userOpPolicies", + "type": "tuple[]" + }, + { + "components": [ + { + "components": [ + { + "internalType": "bytes32", + "name": "appDomainSeparator", + "type": "bytes32" + }, + { + "internalType": "string[]", + "name": "contentNames", + "type": "string[]" + } + ], + "internalType": "struct ERC7739Context[]", + "name": "allowedERC7739Content", + "type": "tuple[]" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "erc1271Policies", + "type": "tuple[]" + } + ], + "internalType": "struct ERC7739Data", + "name": "erc7739Policies", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "bytes4", + "name": "actionTargetSelector", + "type": "bytes4" + }, + { + "internalType": "address", + "name": "actionTarget", + "type": "address" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "actionPolicies", + "type": "tuple[]" + } + ], + "internalType": "struct ActionData[]", + "name": "actions", + "type": "tuple[]" + }, + { + "internalType": "bool", + "name": "permitERC4337Paymaster", + "type": "bool" + } + ], + "internalType": "struct Session", + "name": "session", + "type": "tuple" } ], - "anonymous": false - }, - { - "type": "event", - "name": "RulesActionAuthorized", - "inputs": [ + "name": "grantRules", + "outputs": [ { + "internalType": "bytes32", "name": "rulesId", - "type": "bytes32", - "indexed": true, - "internalType": "bytes32" - }, - { - "name": "agent", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "callsHash", - "type": "bytes32", - "indexed": false, - "internalType": "bytes32" + "type": "bytes32" } ], - "anonymous": false + "stateMutability": "nonpayable", + "type": "function" }, { - "type": "event", - "name": "RulesGranted", "inputs": [ { - "name": "rulesId", - "type": "bytes32", - "indexed": true, - "internalType": "bytes32" - }, - { - "name": "mode", - "type": "uint8", - "indexed": false, - "internalType": "enum RulesType" + "components": [ + { + "internalType": "contract ISessionValidator", + "name": "sessionValidator", + "type": "address" + }, + { + "internalType": "bytes", + "name": "sessionValidatorInitData", + "type": "bytes" + }, + { + "internalType": "bytes32", + "name": "salt", + "type": "bytes32" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "userOpPolicies", + "type": "tuple[]" + }, + { + "components": [ + { + "components": [ + { + "internalType": "bytes32", + "name": "appDomainSeparator", + "type": "bytes32" + }, + { + "internalType": "string[]", + "name": "contentNames", + "type": "string[]" + } + ], + "internalType": "struct ERC7739Context[]", + "name": "allowedERC7739Content", + "type": "tuple[]" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "erc1271Policies", + "type": "tuple[]" + } + ], + "internalType": "struct ERC7739Data", + "name": "erc7739Policies", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "bytes4", + "name": "actionTargetSelector", + "type": "bytes4" + }, + { + "internalType": "address", + "name": "actionTarget", + "type": "address" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "actionPolicies", + "type": "tuple[]" + } + ], + "internalType": "struct ActionData[]", + "name": "actions", + "type": "tuple[]" + }, + { + "internalType": "bool", + "name": "permitERC4337Paymaster", + "type": "bool" + } + ], + "internalType": "struct Session", + "name": "session", + "type": "tuple" }, { - "name": "chainHash", - "type": "bytes32", - "indexed": true, - "internalType": "bytes32" + "components": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "wallet", + "type": "address" + }, + { + "internalType": "address", + "name": "executor", + "type": "address" + }, + { + "internalType": "uint96", + "name": "index", + "type": "uint96" + }, + { + "internalType": "bytes32", + "name": "sessionHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "mode", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "execCalldataHash", + "type": "bytes32" + }, + { + "internalType": "uint192", + "name": "nonceKey", + "type": "uint192" + }, + { + "internalType": "uint64", + "name": "nonceSeq", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "grantNonce", + "type": "uint64" + }, + { + "internalType": "uint48", + "name": "deadline", + "type": "uint48" + }, + { + "internalType": "uint256", + "name": "signerChainId", + "type": "uint256" + } + ], + "internalType": "struct OwnerIntent", + "name": "intent", + "type": "tuple" }, { - "name": "chainNamespace", - "type": "string", - "indexed": false, - "internalType": "string" + "internalType": "bytes", + "name": "sig", + "type": "bytes" } ], - "anonymous": false - }, - { - "type": "event", - "name": "RulesRevoked", - "inputs": [ + "name": "grantRulesWithSig", + "outputs": [ { + "internalType": "bytes32", "name": "rulesId", - "type": "bytes32", - "indexed": true, - "internalType": "bytes32" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "UninstallCallbackFailed", - "inputs": [ - { - "name": "module", - "type": "address", - "indexed": false, - "internalType": "address" + "type": "bytes32" } ], - "anonymous": false + "stateMutability": "nonpayable", + "type": "function" }, { - "type": "error", - "name": "AlreadyInitialized", - "inputs": [] + "inputs": [], + "name": "initializeAccount", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "type": "error", - "name": "CallerIsNotAgent", "inputs": [ { - "name": "rulesId", - "type": "bytes32", - "internalType": "bytes32" + "internalType": "uint256", + "name": "moduleTypeId", + "type": "uint256" }, { - "name": "caller", - "type": "address", - "internalType": "address" - } - ] - }, - { - "type": "error", - "name": "CallerIsNotFactory", - "inputs": [] - }, - { - "type": "error", - "name": "CallerIsNotOwner", - "inputs": [] - }, - { - "type": "error", - "name": "DuplicateAction", - "inputs": [ - { - "name": "target", - "type": "address", - "internalType": "address" + "internalType": "address", + "name": "module", + "type": "address" }, { - "name": "selector", - "type": "bytes4", - "internalType": "bytes4" + "internalType": "bytes", + "name": "initData", + "type": "bytes" } - ] - }, - { - "type": "error", - "name": "EmptyChain", - "inputs": [] - }, - { - "type": "error", - "name": "EngineStillHoldsPermissions", - "inputs": [] + ], + "name": "installModule", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "type": "error", - "name": "ExecutorMismatch", "inputs": [ { - "name": "expected", - "type": "address", - "internalType": "address" + "internalType": "uint256", + "name": "moduleTypeId", + "type": "uint256" }, { - "name": "actual", - "type": "address", - "internalType": "address" - } - ] - }, - { - "type": "error", - "name": "ForbiddenActionSelector", - "inputs": [ + "internalType": "address", + "name": "module", + "type": "address" + }, { - "name": "selector", - "type": "bytes4", - "internalType": "bytes4" + "internalType": "bytes", + "name": "", + "type": "bytes" } - ] - }, - { - "type": "error", - "name": "ForbiddenActionTarget", - "inputs": [ + ], + "name": "isModuleInstalled", + "outputs": [ { - "name": "target", - "type": "address", - "internalType": "address" + "internalType": "bool", + "name": "", + "type": "bool" } - ] + ], + "stateMutability": "view", + "type": "function" }, { - "type": "error", - "name": "ForbiddenDispatchTarget", "inputs": [ { - "name": "target", - "type": "address", - "internalType": "address" + "internalType": "bytes32", + "name": "", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" } - ] - }, - { - "type": "error", - "name": "InconsistentChain", - "inputs": [ + ], + "name": "isValidSignature", + "outputs": [ { - "name": "actionIndex", - "type": "uint256", - "internalType": "uint256" + "internalType": "bytes4", + "name": "", + "type": "bytes4" } - ] + ], + "stateMutability": "pure", + "type": "function" }, { - "type": "error", - "name": "IntentExecMismatch", - "inputs": [ + "inputs": [], + "name": "lastCheckpointBlock", + "outputs": [ { - "name": "actualCalldataHash", - "type": "bytes32", - "internalType": "bytes32" + "internalType": "uint64", + "name": "", + "type": "uint64" } - ] + ], + "stateMutability": "view", + "type": "function" }, { - "type": "error", - "name": "IntentGrantNonceMismatch", "inputs": [ { - "name": "expected", - "type": "uint64", - "internalType": "uint64" + "internalType": "address", + "name": "", + "type": "address" }, { - "name": "provided", - "type": "uint64", - "internalType": "uint64" + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" } - ] - }, - { - "type": "error", - "name": "IntentSessionMismatch", - "inputs": [ + ], + "name": "onERC1155BatchReceived", + "outputs": [ { - "name": "actual", - "type": "bytes32", - "internalType": "bytes32" + "internalType": "bytes4", + "name": "", + "type": "bytes4" } - ] + ], + "stateMutability": "pure", + "type": "function" }, { - "type": "error", - "name": "IntentWalletMismatch", "inputs": [ { - "name": "expected", - "type": "address", - "internalType": "address" + "internalType": "address", + "name": "", + "type": "address" }, { - "name": "provided", - "type": "address", - "internalType": "address" - } - ] - }, - { - "type": "error", - "name": "InvalidModuleAddress", - "inputs": [] - }, - { - "type": "error", - "name": "InvalidNonce", - "inputs": [ + "internalType": "address", + "name": "", + "type": "address" + }, { - "name": "nonceKey", - "type": "uint192", - "internalType": "uint192" + "internalType": "uint256", + "name": "", + "type": "uint256" }, { - "name": "expected", - "type": "uint64", - "internalType": "uint64" + "internalType": "uint256", + "name": "", + "type": "uint256" }, { - "name": "provided", - "type": "uint64", - "internalType": "uint64" + "internalType": "bytes", + "name": "", + "type": "bytes" } - ] - }, - { - "type": "error", - "name": "InvalidOwnerSignature", - "inputs": [] - }, - { - "type": "error", - "name": "MalformedBatchCalldata", - "inputs": [] - }, - { - "type": "error", - "name": "MalformedSessionShape", - "inputs": [] - }, - { - "type": "error", - "name": "ModuleAlreadyInstalled", - "inputs": [ + ], + "name": "onERC1155Received", + "outputs": [ { - "name": "module", - "type": "address", - "internalType": "address" + "internalType": "bytes4", + "name": "", + "type": "bytes4" } - ] + ], + "stateMutability": "pure", + "type": "function" }, { - "type": "error", - "name": "OutsideTimeWindow", "inputs": [ { - "name": "validAfter", - "type": "uint48", - "internalType": "uint48" + "internalType": "address", + "name": "", + "type": "address" }, { - "name": "validUntil", - "type": "uint48", - "internalType": "uint48" + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" } - ] - }, - { - "type": "error", - "name": "OwnerLaneRequired", - "inputs": [ + ], + "name": "onERC721Received", + "outputs": [ { - "name": "nonceKey", - "type": "uint192", - "internalType": "uint192" + "internalType": "bytes4", + "name": "", + "type": "bytes4" } - ] + ], + "stateMutability": "pure", + "type": "function" }, { - "type": "error", - "name": "OwnerSigExpired", - "inputs": [ + "inputs": [], + "name": "owner", + "outputs": [ { - "name": "deadline", - "type": "uint48", - "internalType": "uint48" + "internalType": "address", + "name": "", + "type": "address" } - ] + ], + "stateMutability": "view", + "type": "function" }, { - "type": "error", - "name": "ReentrancyGuardReentrantCall", - "inputs": [] + "inputs": [], + "name": "revokeAllRules", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "type": "error", - "name": "RulesTypeMismatch", "inputs": [ { - "name": "derived", - "type": "uint8", - "internalType": "enum RulesType" - }, - { - "name": "actionIndex", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "target", - "type": "address", - "internalType": "address" + "internalType": "bytes32", + "name": "rulesId", + "type": "bytes32" } - ] + ], + "name": "revokeRules", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "type": "error", - "name": "TooManyActions", "inputs": [ { - "name": "count", - "type": "uint256", - "internalType": "uint256" + "internalType": "bytes32", + "name": "mode", + "type": "bytes32" + } + ], + "name": "supportsExecutionMode", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" } - ] + ], + "stateMutability": "pure", + "type": "function" }, { - "type": "error", - "name": "UnknownPermission", "inputs": [ { - "name": "rulesId", - "type": "bytes32", - "internalType": "bytes32" + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" } - ] - }, - { - "type": "error", - "name": "UnsupportedExecutionMode", - "inputs": [] + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "pure", + "type": "function" }, { - "type": "error", - "name": "UnsupportedModuleType", "inputs": [ { + "internalType": "uint256", "name": "moduleTypeId", - "type": "uint256", - "internalType": "uint256" + "type": "uint256" } - ] - }, - { - "type": "error", - "name": "ValidationFailed", - "inputs": [ + ], + "name": "supportsModule", + "outputs": [ { - "name": "authorizer", - "type": "address", - "internalType": "address" + "internalType": "bool", + "name": "", + "type": "bool" } - ] + ], + "stateMutability": "pure", + "type": "function" }, { - "type": "error", - "name": "ValidatorNotInstalled", "inputs": [ { - "name": "validator", - "type": "address", - "internalType": "address" + "internalType": "uint256", + "name": "moduleTypeId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "module", + "type": "address" + }, + { + "internalType": "bytes", + "name": "deInitData", + "type": "bytes" } - ] + ], + "name": "uninstallModule", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" } ] as const; diff --git a/packages/core/src/lib/agentic/contracts/abi/e704d5b/index.ts b/packages/core/src/lib/agentic/contracts/abi/v4/index.ts similarity index 66% rename from packages/core/src/lib/agentic/contracts/abi/e704d5b/index.ts rename to packages/core/src/lib/agentic/contracts/abi/v4/index.ts index 7c81b83c..05446292 100644 --- a/packages/core/src/lib/agentic/contracts/abi/e704d5b/index.ts +++ b/packages/core/src/lib/agentic/contracts/abi/v4/index.ts @@ -1,6 +1,6 @@ // GENERATED by packages/core/scripts/agw-local/gen-abi.mjs — do not edit. -// Review generation e704d5b: no verified deployment exists for this ABI set. -export const E704D5B_SOURCE_COMMIT = 'e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9' as const; +// Review generation v4: Donut v4 deployment; source e8db748. +export const V4_SOURCE_COMMIT = 'e8db74815cfbbf5389593805e464fe8d85f7f735' as const; export { AGW_ABI } from './agw'; export { AGW_FACTORY_ABI } from './agw-factory'; export { UNIVERSAL_RULES_POLICY_ABI } from './universal-rules-policy'; diff --git a/packages/core/src/lib/agentic/contracts/abi/e704d5b/smart-session.ts b/packages/core/src/lib/agentic/contracts/abi/v4/smart-session.ts similarity index 53% rename from packages/core/src/lib/agentic/contracts/abi/e704d5b/smart-session.ts rename to packages/core/src/lib/agentic/contracts/abi/v4/smart-session.ts index b47e8b8b..e1efc670 100644 --- a/packages/core/src/lib/agentic/contracts/abi/e704d5b/smart-session.ts +++ b/packages/core/src/lib/agentic/contracts/abi/v4/smart-session.ts @@ -1,1961 +1,1961 @@ // GENERATED by packages/core/scripts/agw-local/gen-abi.mjs — do not edit. -// Source: plan/agw/research/validation-e704d5b/abi/SmartSession.json -// push-agentic-wallets@e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9 -// sha256(SmartSession.json) = 6e5d9cea4dbed01f06af913c1e093743b86b7432195f4a4bf90fb94b282c51b2 +// Source: plan/agw/research/deployment-review-2026-10-06/abis/SmartSession.json +// push-agentic-wallets@e8db74815cfbbf5389593805e464fe8d85f7f735 +// sha256(SmartSession.json) = 32e7f3e48db6719306c436a0c81d80a2c5bcb3283b208ae043c460d483bc0180 export const SMART_SESSION_ABI = [ { - "type": "function", - "name": "areActionsEnabled", "inputs": [ { - "name": "account", - "type": "address", - "internalType": "address" - }, - { - "name": "permissionId", - "type": "bytes32", - "internalType": "PermissionId" - }, + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "AssociatedArray_OutOfBounds", + "type": "error" + }, + { + "inputs": [ { - "name": "actions", - "type": "tuple[]", - "internalType": "struct ActionData[]", - "components": [ - { - "name": "actionTargetSelector", - "type": "bytes4", - "internalType": "bytes4" - }, - { - "name": "actionTarget", - "type": "address", - "internalType": "address" - }, - { - "name": "actionPolicies", - "type": "tuple[]", - "internalType": "struct PolicyData[]", - "components": [ - { - "name": "policy", - "type": "address", - "internalType": "address" - }, - { - "name": "initData", - "type": "bytes", - "internalType": "bytes" - } - ] - } - ] + "internalType": "uint64", + "name": "providedChainId", + "type": "uint64" } ], - "outputs": [ + "name": "ChainIdMismatch", + "type": "error" + }, + { + "inputs": [ { - "name": "", - "type": "bool", - "internalType": "bool" + "internalType": "uint64", + "name": "providedChainId", + "type": "uint64" } ], - "stateMutability": "view" + "name": "ChainIdMismatch", + "type": "error" + }, + { + "inputs": [], + "name": "ForbiddenValidationData", + "type": "error" }, { - "type": "function", - "name": "areERC1271PoliciesEnabled", "inputs": [ { - "name": "account", - "type": "address", - "internalType": "address" - }, + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "HashIndexOutOfBounds", + "type": "error" + }, + { + "inputs": [ { - "name": "permissionId", - "type": "bytes32", - "internalType": "PermissionId" + "internalType": "bytes32", + "name": "providedHash", + "type": "bytes32" }, { - "name": "erc1271Policies", - "type": "tuple[]", - "internalType": "struct PolicyData[]", - "components": [ - { - "name": "policy", - "type": "address", - "internalType": "address" - }, - { - "name": "initData", - "type": "bytes", - "internalType": "bytes" - } - ] + "internalType": "bytes32", + "name": "computedHash", + "type": "bytes32" } ], - "outputs": [ + "name": "HashMismatch", + "type": "error" + }, + { + "inputs": [ { - "name": "", - "type": "bool", - "internalType": "bool" + "internalType": "bytes32", + "name": "providedHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "computedHash", + "type": "bytes32" } ], - "stateMutability": "view" + "name": "HashMismatch", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidActionId", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidCallTarget", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidData", + "type": "error" }, { - "type": "function", - "name": "areUserOpPoliciesEnabled", "inputs": [ { + "internalType": "address", "name": "account", - "type": "address", - "internalType": "address" + "type": "address" }, { - "name": "permissionId", - "type": "bytes32", - "internalType": "PermissionId" - }, - { - "name": "userOpPolicies", - "type": "tuple[]", - "internalType": "struct PolicyData[]", - "components": [ - { - "name": "policy", - "type": "address", - "internalType": "address" - }, - { - "name": "initData", - "type": "bytes", - "internalType": "bytes" - } - ] + "internalType": "bytes32", + "name": "hash", + "type": "bytes32" } ], - "outputs": [ + "name": "InvalidEnableSignature", + "type": "error" + }, + { + "inputs": [ { - "name": "", - "type": "bool", - "internalType": "bool" + "internalType": "contract ISessionValidator", + "name": "sessionValidator", + "type": "address" } ], - "stateMutability": "view" + "name": "InvalidISessionValidator", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidMode", + "type": "error" }, { - "type": "function", - "name": "disableActionId", "inputs": [ { + "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32", - "internalType": "PermissionId" - }, + "type": "bytes32" + } + ], + "name": "InvalidPermissionId", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidSelfCall", + "type": "error" + }, + { + "inputs": [ { - "name": "actionId", - "type": "bytes32", - "internalType": "ActionId" + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" } ], - "outputs": [], - "stateMutability": "nonpayable" + "name": "InvalidSession", + "type": "error" }, { - "type": "function", - "name": "disableActionPolicies", "inputs": [ { + "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32", - "internalType": "PermissionId" + "type": "bytes32" }, { - "name": "actionId", - "type": "bytes32", - "internalType": "ActionId" + "internalType": "address", + "name": "sessionValidator", + "type": "address" }, { - "name": "policies", - "type": "address[]", - "internalType": "address[]" + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "userOpHash", + "type": "bytes32" } ], - "outputs": [], - "stateMutability": "nonpayable" + "name": "InvalidSessionKeySignature", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidTarget", + "type": "error" }, { - "type": "function", - "name": "disableERC1271Policies", "inputs": [ { - "name": "permissionId", - "type": "bytes32", - "internalType": "PermissionId" - }, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "InvalidUserOpSender", + "type": "error" + }, + { + "inputs": [], + "name": "NoExecutionsInBatch", + "type": "error" + }, + { + "inputs": [ { - "name": "policies", - "type": "address[]", - "internalType": "address[]" - }, + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + } + ], + "name": "NoPoliciesSet", + "type": "error" + }, + { + "inputs": [], + "name": "PartlyEnabledActions", + "type": "error" + }, + { + "inputs": [], + "name": "PartlyEnabledPolicies", + "type": "error" + }, + { + "inputs": [ { - "name": "contexts", - "type": "tuple[]", - "internalType": "struct ERC7739Context[]", - "components": [ - { - "name": "appDomainSeparator", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "contentNames", - "type": "string[]", - "internalType": "string[]" - } - ] + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" } ], - "outputs": [], - "stateMutability": "nonpayable" + "name": "PaymasterValidationNotEnabled", + "type": "error" }, { - "type": "function", - "name": "disableUserOpPolicies", "inputs": [ { + "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32", - "internalType": "PermissionId" + "type": "bytes32" }, { - "name": "policies", - "type": "address[]", - "internalType": "address[]" + "internalType": "address", + "name": "policy", + "type": "address" } ], - "outputs": [], - "stateMutability": "nonpayable" + "name": "PolicyViolation", + "type": "error" }, { - "type": "function", - "name": "enableActionPolicies", "inputs": [ { + "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32", - "internalType": "PermissionId" + "type": "bytes32" }, { - "name": "actionPolicies", - "type": "tuple[]", - "internalType": "struct ActionData[]", - "components": [ - { - "name": "actionTargetSelector", - "type": "bytes4", - "internalType": "bytes4" - }, - { - "name": "actionTarget", - "type": "address", - "internalType": "address" - }, - { - "name": "actionPolicies", - "type": "tuple[]", - "internalType": "struct PolicyData[]", - "components": [ - { - "name": "policy", - "type": "address", - "internalType": "address" - }, - { - "name": "initData", - "type": "bytes", - "internalType": "bytes" - } - ] - } - ] + "internalType": "address", + "name": "account", + "type": "address" } ], - "outputs": [], - "stateMutability": "nonpayable" + "name": "SignerNotFound", + "type": "error" }, { - "type": "function", - "name": "enableERC1271Policies", "inputs": [ { + "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32", - "internalType": "PermissionId" + "type": "bytes32" }, { - "name": "erc1271Policies", - "type": "tuple", - "internalType": "struct ERC7739Data", - "components": [ - { - "name": "allowedERC7739Content", - "type": "tuple[]", - "internalType": "struct ERC7739Context[]", - "components": [ - { - "name": "appDomainSeparator", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "contentNames", - "type": "string[]", - "internalType": "string[]" - } - ] - }, - { - "name": "erc1271Policies", - "type": "tuple[]", - "internalType": "struct PolicyData[]", - "components": [ - { - "name": "policy", - "type": "address", - "internalType": "address" - }, - { - "name": "initData", - "type": "bytes", - "internalType": "bytes" - } - ] - } - ] + "internalType": "address", + "name": "account", + "type": "address" } ], - "outputs": [], - "stateMutability": "nonpayable" + "name": "SignerNotFound", + "type": "error" }, { - "type": "function", - "name": "enableSessions", "inputs": [ { - "name": "sessions", - "type": "tuple[]", - "internalType": "struct Session[]", - "components": [ - { - "name": "sessionValidator", - "type": "address", - "internalType": "contract ISessionValidator" - }, - { - "name": "sessionValidatorInitData", - "type": "bytes", - "internalType": "bytes" - }, - { - "name": "salt", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "userOpPolicies", - "type": "tuple[]", - "internalType": "struct PolicyData[]", - "components": [ - { - "name": "policy", - "type": "address", - "internalType": "address" - }, - { - "name": "initData", - "type": "bytes", - "internalType": "bytes" - } - ] - }, - { - "name": "erc7739Policies", - "type": "tuple", - "internalType": "struct ERC7739Data", - "components": [ - { - "name": "allowedERC7739Content", - "type": "tuple[]", - "internalType": "struct ERC7739Context[]", - "components": [ - { - "name": "appDomainSeparator", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "contentNames", - "type": "string[]", - "internalType": "string[]" - } - ] - }, - { - "name": "erc1271Policies", - "type": "tuple[]", - "internalType": "struct PolicyData[]", - "components": [ - { - "name": "policy", - "type": "address", - "internalType": "address" - }, - { - "name": "initData", - "type": "bytes", - "internalType": "bytes" - } - ] - } - ] - }, - { - "name": "actions", - "type": "tuple[]", - "internalType": "struct ActionData[]", - "components": [ - { - "name": "actionTargetSelector", - "type": "bytes4", - "internalType": "bytes4" - }, - { - "name": "actionTarget", - "type": "address", - "internalType": "address" - }, - { - "name": "actionPolicies", - "type": "tuple[]", - "internalType": "struct PolicyData[]", - "components": [ - { - "name": "policy", - "type": "address", - "internalType": "address" - }, - { - "name": "initData", - "type": "bytes", - "internalType": "bytes" - } - ] - } - ] - }, - { - "name": "permitERC4337Paymaster", - "type": "bool", - "internalType": "bool" - } - ] + "internalType": "address", + "name": "account", + "type": "address" } ], - "outputs": [ + "name": "SmartSessionModuleAlreadyInstalled", + "type": "error" + }, + { + "inputs": [ { - "name": "permissionIds", - "type": "bytes32[]", - "internalType": "PermissionId[]" + "internalType": "CallType", + "name": "callType", + "type": "bytes1" } ], - "stateMutability": "nonpayable" + "name": "UnsupportedCallType", + "type": "error" + }, + { + "inputs": [], + "name": "UnsupportedExecutionType", + "type": "error" }, { - "type": "function", - "name": "enableUserOpPolicies", "inputs": [ { - "name": "permissionId", - "type": "bytes32", - "internalType": "PermissionId" - }, - { - "name": "userOpPolicies", - "type": "tuple[]", - "internalType": "struct PolicyData[]", - "components": [ - { - "name": "policy", - "type": "address", - "internalType": "address" - }, - { - "name": "initData", - "type": "bytes", - "internalType": "bytes" - } - ] + "internalType": "address", + "name": "policy", + "type": "address" } ], - "outputs": [], - "stateMutability": "nonpayable" + "name": "UnsupportedPolicy", + "type": "error" }, { - "type": "function", - "name": "getActionPolicies", "inputs": [ { - "name": "account", - "type": "address", - "internalType": "address" - }, + "internalType": "enum SmartSessionMode", + "name": "mode", + "type": "uint8" + } + ], + "name": "UnsupportedSmartSessionMode", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ { + "indexed": false, + "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32", - "internalType": "PermissionId" + "type": "bytes32" }, { + "indexed": false, + "internalType": "ActionId", "name": "actionId", - "type": "bytes32", - "internalType": "ActionId" - } - ], - "outputs": [ + "type": "bytes32" + }, { - "name": "", - "type": "address[]", - "internalType": "address[]" + "indexed": false, + "internalType": "address", + "name": "smartAccount", + "type": "address" } ], - "stateMutability": "view" + "name": "ActionIdDisabled", + "type": "event" }, { - "type": "function", - "name": "getERC1271Policies", + "anonymous": false, "inputs": [ { + "indexed": false, + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "address", "name": "account", - "type": "address", - "internalType": "address" + "type": "address" }, { - "name": "permissionId", - "type": "bytes32", - "internalType": "PermissionId" + "indexed": false, + "internalType": "uint256", + "name": "newValue", + "type": "uint256" } ], - "outputs": [ + "name": "NonceIterated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ { - "name": "", - "type": "address[]", - "internalType": "address[]" + "indexed": false, + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "address", + "name": "smartAccount", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "enabled", + "type": "bool" } ], - "stateMutability": "view" + "name": "PermissionIdPermit4337Paymaster", + "type": "event" }, { - "type": "function", - "name": "getEnabledActions", + "anonymous": false, "inputs": [ { - "name": "account", - "type": "address", - "internalType": "address" + "indexed": false, + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" }, { - "name": "permissionId", - "type": "bytes32", - "internalType": "PermissionId" - } - ], - "outputs": [ + "indexed": false, + "internalType": "enum PolicyType", + "name": "policyType", + "type": "uint8" + }, { - "name": "", - "type": "bytes32[]", - "internalType": "bytes32[]" + "indexed": false, + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "smartAccount", + "type": "address" } ], - "stateMutability": "view" + "name": "PolicyDisabled", + "type": "event" }, { - "type": "function", - "name": "getEnabledERC7739Content", + "anonymous": false, "inputs": [ { - "name": "account", - "type": "address", - "internalType": "address" + "indexed": false, + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" }, { - "name": "permissionId", - "type": "bytes32", - "internalType": "PermissionId" - } - ], - "outputs": [ + "indexed": false, + "internalType": "enum PolicyType", + "name": "policyType", + "type": "uint8" + }, { - "name": "enabledERC7739ContentHashes", - "type": "tuple[]", - "internalType": "struct ERC7739ContextHashes[]", - "components": [ - { - "name": "appDomainSeparator", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "contentNameHashes", - "type": "bytes32[]", - "internalType": "bytes32[]" - } - ] + "indexed": false, + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "smartAccount", + "type": "address" } ], - "stateMutability": "view" + "name": "PolicyEnabled", + "type": "event" }, { - "type": "function", - "name": "getNonce", + "anonymous": false, "inputs": [ { + "indexed": false, + "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32", - "internalType": "PermissionId" + "type": "bytes32" }, { + "indexed": false, + "internalType": "address", "name": "account", - "type": "address", - "internalType": "address" + "type": "address" } ], - "outputs": [ + "name": "SessionCreated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ { - "name": "", - "type": "uint256", - "internalType": "uint256" + "indexed": false, + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "address", + "name": "smartAccount", + "type": "address" } ], - "stateMutability": "view" + "name": "SessionRemoved", + "type": "event" }, { - "type": "function", - "name": "getPermissionIDs", + "anonymous": false, "inputs": [ { - "name": "account", - "type": "address", - "internalType": "address" + "indexed": false, + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "address", + "name": "sessionValidator", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "smartAccount", + "type": "address" } ], - "outputs": [ + "name": "SessionValidatorDisabled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ { - "name": "permissionIds", - "type": "bytes32[]", - "internalType": "PermissionId[]" + "indexed": false, + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "address", + "name": "sessionValidator", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "smartAccount", + "type": "address" } ], - "stateMutability": "view" + "name": "SessionValidatorEnabled", + "type": "event" }, { - "type": "function", - "name": "getPermissionId", "inputs": [ { - "name": "session", - "type": "tuple", - "internalType": "struct Session", + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { "components": [ { - "name": "sessionValidator", - "type": "address", - "internalType": "contract ISessionValidator" - }, - { - "name": "sessionValidatorInitData", - "type": "bytes", - "internalType": "bytes" + "internalType": "bytes4", + "name": "actionTargetSelector", + "type": "bytes4" }, { - "name": "salt", - "type": "bytes32", - "internalType": "bytes32" + "internalType": "address", + "name": "actionTarget", + "type": "address" }, { - "name": "userOpPolicies", - "type": "tuple[]", - "internalType": "struct PolicyData[]", "components": [ { + "internalType": "address", "name": "policy", - "type": "address", - "internalType": "address" + "type": "address" }, { + "internalType": "bytes", "name": "initData", - "type": "bytes", - "internalType": "bytes" + "type": "bytes" } - ] - }, - { - "name": "erc7739Policies", - "type": "tuple", - "internalType": "struct ERC7739Data", - "components": [ - { - "name": "allowedERC7739Content", - "type": "tuple[]", - "internalType": "struct ERC7739Context[]", - "components": [ - { - "name": "appDomainSeparator", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "contentNames", - "type": "string[]", - "internalType": "string[]" - } - ] - }, - { - "name": "erc1271Policies", - "type": "tuple[]", - "internalType": "struct PolicyData[]", - "components": [ - { - "name": "policy", - "type": "address", - "internalType": "address" - }, - { - "name": "initData", - "type": "bytes", - "internalType": "bytes" - } - ] - } - ] - }, - { - "name": "actions", - "type": "tuple[]", - "internalType": "struct ActionData[]", - "components": [ - { - "name": "actionTargetSelector", - "type": "bytes4", - "internalType": "bytes4" - }, - { - "name": "actionTarget", - "type": "address", - "internalType": "address" - }, - { - "name": "actionPolicies", - "type": "tuple[]", - "internalType": "struct PolicyData[]", - "components": [ - { - "name": "policy", - "type": "address", - "internalType": "address" - }, - { - "name": "initData", - "type": "bytes", - "internalType": "bytes" - } - ] - } - ] - }, - { - "name": "permitERC4337Paymaster", - "type": "bool", - "internalType": "bool" + ], + "internalType": "struct PolicyData[]", + "name": "actionPolicies", + "type": "tuple[]" } - ] + ], + "internalType": "struct ActionData[]", + "name": "actions", + "type": "tuple[]" } ], + "name": "areActionsEnabled", "outputs": [ { - "name": "permissionId", - "type": "bytes32", - "internalType": "PermissionId" + "internalType": "bool", + "name": "", + "type": "bool" } ], - "stateMutability": "pure" + "stateMutability": "view", + "type": "function" }, { - "type": "function", - "name": "getSessionDigest", "inputs": [ { - "name": "permissionId", - "type": "bytes32", - "internalType": "PermissionId" + "internalType": "address", + "name": "account", + "type": "address" }, { - "name": "account", - "type": "address", - "internalType": "address" + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" }, { - "name": "data", - "type": "tuple", - "internalType": "struct Session", "components": [ { - "name": "sessionValidator", - "type": "address", - "internalType": "contract ISessionValidator" - }, - { - "name": "sessionValidatorInitData", - "type": "bytes", - "internalType": "bytes" - }, - { - "name": "salt", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "userOpPolicies", - "type": "tuple[]", - "internalType": "struct PolicyData[]", - "components": [ - { - "name": "policy", - "type": "address", - "internalType": "address" - }, - { - "name": "initData", - "type": "bytes", - "internalType": "bytes" - } - ] - }, - { - "name": "erc7739Policies", - "type": "tuple", - "internalType": "struct ERC7739Data", - "components": [ - { - "name": "allowedERC7739Content", - "type": "tuple[]", - "internalType": "struct ERC7739Context[]", - "components": [ - { - "name": "appDomainSeparator", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "contentNames", - "type": "string[]", - "internalType": "string[]" - } - ] - }, - { - "name": "erc1271Policies", - "type": "tuple[]", - "internalType": "struct PolicyData[]", - "components": [ - { - "name": "policy", - "type": "address", - "internalType": "address" - }, - { - "name": "initData", - "type": "bytes", - "internalType": "bytes" - } - ] - } - ] - }, - { - "name": "actions", - "type": "tuple[]", - "internalType": "struct ActionData[]", - "components": [ - { - "name": "actionTargetSelector", - "type": "bytes4", - "internalType": "bytes4" - }, - { - "name": "actionTarget", - "type": "address", - "internalType": "address" - }, - { - "name": "actionPolicies", - "type": "tuple[]", - "internalType": "struct PolicyData[]", - "components": [ - { - "name": "policy", - "type": "address", - "internalType": "address" - }, - { - "name": "initData", - "type": "bytes", - "internalType": "bytes" - } - ] - } - ] + "internalType": "address", + "name": "policy", + "type": "address" }, { - "name": "permitERC4337Paymaster", - "type": "bool", - "internalType": "bool" + "internalType": "bytes", + "name": "initData", + "type": "bytes" } - ] - }, - { - "name": "mode", - "type": "uint8", - "internalType": "enum SmartSessionMode" + ], + "internalType": "struct PolicyData[]", + "name": "erc1271Policies", + "type": "tuple[]" } ], + "name": "areERC1271PoliciesEnabled", "outputs": [ { + "internalType": "bool", "name": "", - "type": "bytes32", - "internalType": "bytes32" + "type": "bool" } ], - "stateMutability": "view" + "stateMutability": "view", + "type": "function" }, { - "type": "function", - "name": "getSessionValidatorAndConfig", "inputs": [ { + "internalType": "address", "name": "account", - "type": "address", - "internalType": "address" + "type": "address" }, { + "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32", - "internalType": "PermissionId" - } - ], - "outputs": [ - { - "name": "sessionValidator", - "type": "address", - "internalType": "address" - }, - { - "name": "sessionValidatorData", - "type": "bytes", - "internalType": "bytes" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "getUserOpPolicies", - "inputs": [ - { - "name": "account", - "type": "address", - "internalType": "address" + "type": "bytes32" }, { - "name": "permissionId", - "type": "bytes32", - "internalType": "PermissionId" + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "userOpPolicies", + "type": "tuple[]" } ], + "name": "areUserOpPoliciesEnabled", "outputs": [ { + "internalType": "bool", "name": "", - "type": "address[]", - "internalType": "address[]" + "type": "bool" } ], - "stateMutability": "view" + "stateMutability": "view", + "type": "function" }, { - "type": "function", - "name": "isActionIdEnabled", "inputs": [ { - "name": "account", - "type": "address", - "internalType": "address" - }, - { + "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32", - "internalType": "PermissionId" + "type": "bytes32" }, { + "internalType": "ActionId", "name": "actionId", - "type": "bytes32", - "internalType": "ActionId" - } - ], - "outputs": [ - { - "name": "", - "type": "bool", - "internalType": "bool" + "type": "bytes32" } ], - "stateMutability": "view" + "name": "disableActionId", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "type": "function", - "name": "isActionPolicyEnabled", "inputs": [ { - "name": "account", - "type": "address", - "internalType": "address" - }, - { + "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32", - "internalType": "PermissionId" + "type": "bytes32" }, { + "internalType": "ActionId", "name": "actionId", - "type": "bytes32", - "internalType": "ActionId" + "type": "bytes32" }, { - "name": "policy", - "type": "address", - "internalType": "address" - } - ], - "outputs": [ - { - "name": "", - "type": "bool", - "internalType": "bool" + "internalType": "address[]", + "name": "policies", + "type": "address[]" } ], - "stateMutability": "view" + "name": "disableActionPolicies", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "type": "function", - "name": "isERC1271PolicyEnabled", "inputs": [ { - "name": "account", - "type": "address", - "internalType": "address" - }, - { + "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32", - "internalType": "PermissionId" + "type": "bytes32" }, { - "name": "policy", - "type": "address", - "internalType": "address" - } - ], - "outputs": [ + "internalType": "address[]", + "name": "policies", + "type": "address[]" + }, { - "name": "", - "type": "bool", - "internalType": "bool" + "components": [ + { + "internalType": "bytes32", + "name": "appDomainSeparator", + "type": "bytes32" + }, + { + "internalType": "string[]", + "name": "contentNames", + "type": "string[]" + } + ], + "internalType": "struct ERC7739Context[]", + "name": "contexts", + "type": "tuple[]" } ], - "stateMutability": "view" + "name": "disableERC1271Policies", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "type": "function", - "name": "isERC7739ContentEnabled", "inputs": [ { - "name": "account", - "type": "address", - "internalType": "address" - }, - { + "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32", - "internalType": "PermissionId" - }, - { - "name": "appDomainSeparator", - "type": "bytes32", - "internalType": "bytes32" + "type": "bytes32" }, { - "name": "content", - "type": "string", - "internalType": "string" - } - ], - "outputs": [ - { - "name": "", - "type": "bool", - "internalType": "bool" + "internalType": "address[]", + "name": "policies", + "type": "address[]" } ], - "stateMutability": "view" + "name": "disableUserOpPolicies", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "type": "function", - "name": "isISessionValidatorSet", "inputs": [ { + "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32", - "internalType": "PermissionId" + "type": "bytes32" }, { - "name": "account", - "type": "address", - "internalType": "address" - } - ], - "outputs": [ - { - "name": "", - "type": "bool", - "internalType": "bool" + "components": [ + { + "internalType": "bytes4", + "name": "actionTargetSelector", + "type": "bytes4" + }, + { + "internalType": "address", + "name": "actionTarget", + "type": "address" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "actionPolicies", + "type": "tuple[]" + } + ], + "internalType": "struct ActionData[]", + "name": "actionPolicies", + "type": "tuple[]" } ], - "stateMutability": "view" + "name": "enableActionPolicies", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "type": "function", - "name": "isInitialized", "inputs": [ { - "name": "smartAccount", - "type": "address", - "internalType": "address" - } - ], - "outputs": [ + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, { - "name": "", - "type": "bool", - "internalType": "bool" - } - ], - "stateMutability": "view" + "components": [ + { + "components": [ + { + "internalType": "bytes32", + "name": "appDomainSeparator", + "type": "bytes32" + }, + { + "internalType": "string[]", + "name": "contentNames", + "type": "string[]" + } + ], + "internalType": "struct ERC7739Context[]", + "name": "allowedERC7739Content", + "type": "tuple[]" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "erc1271Policies", + "type": "tuple[]" + } + ], + "internalType": "struct ERC7739Data", + "name": "erc1271Policies", + "type": "tuple" + } + ], + "name": "enableERC1271Policies", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "type": "function", - "name": "isModuleType", "inputs": [ { - "name": "typeID", - "type": "uint256", - "internalType": "uint256" + "components": [ + { + "internalType": "contract ISessionValidator", + "name": "sessionValidator", + "type": "address" + }, + { + "internalType": "bytes", + "name": "sessionValidatorInitData", + "type": "bytes" + }, + { + "internalType": "bytes32", + "name": "salt", + "type": "bytes32" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "userOpPolicies", + "type": "tuple[]" + }, + { + "components": [ + { + "components": [ + { + "internalType": "bytes32", + "name": "appDomainSeparator", + "type": "bytes32" + }, + { + "internalType": "string[]", + "name": "contentNames", + "type": "string[]" + } + ], + "internalType": "struct ERC7739Context[]", + "name": "allowedERC7739Content", + "type": "tuple[]" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "erc1271Policies", + "type": "tuple[]" + } + ], + "internalType": "struct ERC7739Data", + "name": "erc7739Policies", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "bytes4", + "name": "actionTargetSelector", + "type": "bytes4" + }, + { + "internalType": "address", + "name": "actionTarget", + "type": "address" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "actionPolicies", + "type": "tuple[]" + } + ], + "internalType": "struct ActionData[]", + "name": "actions", + "type": "tuple[]" + }, + { + "internalType": "bool", + "name": "permitERC4337Paymaster", + "type": "bool" + } + ], + "internalType": "struct Session[]", + "name": "sessions", + "type": "tuple[]" } ], + "name": "enableSessions", "outputs": [ { - "name": "", - "type": "bool", - "internalType": "bool" + "internalType": "PermissionId[]", + "name": "permissionIds", + "type": "bytes32[]" } ], - "stateMutability": "pure" + "stateMutability": "nonpayable", + "type": "function" }, { - "type": "function", - "name": "isPermissionEnabled", "inputs": [ { + "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32", - "internalType": "PermissionId" + "type": "bytes32" }, { - "name": "account", - "type": "address", - "internalType": "address" - } - ], - "outputs": [ - { - "name": "", - "type": "bool", - "internalType": "bool" + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "userOpPolicies", + "type": "tuple[]" } ], - "stateMutability": "view" + "name": "enableUserOpPolicies", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "type": "function", - "name": "isUserOpPolicyEnabled", "inputs": [ { + "internalType": "address", "name": "account", - "type": "address", - "internalType": "address" + "type": "address" }, { + "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32", - "internalType": "PermissionId" + "type": "bytes32" }, { - "name": "policy", - "type": "address", - "internalType": "address" + "internalType": "ActionId", + "name": "actionId", + "type": "bytes32" } ], + "name": "getActionPolicies", "outputs": [ { + "internalType": "address[]", "name": "", - "type": "bool", - "internalType": "bool" + "type": "address[]" } ], - "stateMutability": "view" + "stateMutability": "view", + "type": "function" }, { - "type": "function", - "name": "isValidSignatureWithSender", "inputs": [ { - "name": "sender", - "type": "address", - "internalType": "address" - }, - { - "name": "hash", - "type": "bytes32", - "internalType": "bytes32" + "internalType": "address", + "name": "account", + "type": "address" }, { - "name": "signature", - "type": "bytes", - "internalType": "bytes" + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" } ], + "name": "getERC1271Policies", "outputs": [ { - "name": "result", - "type": "bytes4", - "internalType": "bytes4" + "internalType": "address[]", + "name": "", + "type": "address[]" } ], - "stateMutability": "view" + "stateMutability": "view", + "type": "function" }, { - "type": "function", - "name": "onInstall", "inputs": [ { - "name": "data", - "type": "bytes", - "internalType": "bytes" + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" } ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "onUninstall", - "inputs": [ + "name": "getEnabledActions", + "outputs": [ { + "internalType": "bytes32[]", "name": "", - "type": "bytes", - "internalType": "bytes" + "type": "bytes32[]" } ], - "outputs": [], - "stateMutability": "nonpayable" + "stateMutability": "view", + "type": "function" }, { - "type": "function", - "name": "removeSession", "inputs": [ { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32", - "internalType": "PermissionId" + "type": "bytes32" } ], - "outputs": [], - "stateMutability": "nonpayable" + "name": "getEnabledERC7739Content", + "outputs": [ + { + "components": [ + { + "internalType": "bytes32", + "name": "appDomainSeparator", + "type": "bytes32" + }, + { + "internalType": "bytes32[]", + "name": "contentNameHashes", + "type": "bytes32[]" + } + ], + "internalType": "struct ERC7739ContextHashes[]", + "name": "enabledERC7739ContentHashes", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" }, { - "type": "function", - "name": "revokeEnableSignature", "inputs": [ { + "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32", - "internalType": "PermissionId" + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" } ], - "outputs": [], - "stateMutability": "nonpayable" + "name": "getNonce", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" }, { - "type": "function", - "name": "setPermit4337Paymaster", "inputs": [ { - "name": "permissionId", - "type": "bytes32", - "internalType": "PermissionId" - }, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "getPermissionIDs", + "outputs": [ { - "name": "enabled", - "type": "bool", - "internalType": "bool" + "internalType": "PermissionId[]", + "name": "permissionIds", + "type": "bytes32[]" } ], - "outputs": [], - "stateMutability": "nonpayable" + "stateMutability": "view", + "type": "function" }, { - "type": "function", - "name": "validateUserOp", "inputs": [ { - "name": "userOp", - "type": "tuple", - "internalType": "struct PackedUserOperation", "components": [ { - "name": "sender", - "type": "address", - "internalType": "address" - }, - { - "name": "nonce", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "initCode", - "type": "bytes", - "internalType": "bytes" + "internalType": "contract ISessionValidator", + "name": "sessionValidator", + "type": "address" }, { - "name": "callData", - "type": "bytes", - "internalType": "bytes" + "internalType": "bytes", + "name": "sessionValidatorInitData", + "type": "bytes" }, { - "name": "accountGasLimits", - "type": "bytes32", - "internalType": "bytes32" + "internalType": "bytes32", + "name": "salt", + "type": "bytes32" }, { - "name": "preVerificationGas", - "type": "uint256", - "internalType": "uint256" + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "userOpPolicies", + "type": "tuple[]" }, { - "name": "gasFees", - "type": "bytes32", - "internalType": "bytes32" + "components": [ + { + "components": [ + { + "internalType": "bytes32", + "name": "appDomainSeparator", + "type": "bytes32" + }, + { + "internalType": "string[]", + "name": "contentNames", + "type": "string[]" + } + ], + "internalType": "struct ERC7739Context[]", + "name": "allowedERC7739Content", + "type": "tuple[]" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "erc1271Policies", + "type": "tuple[]" + } + ], + "internalType": "struct ERC7739Data", + "name": "erc7739Policies", + "type": "tuple" }, { - "name": "paymasterAndData", - "type": "bytes", - "internalType": "bytes" + "components": [ + { + "internalType": "bytes4", + "name": "actionTargetSelector", + "type": "bytes4" + }, + { + "internalType": "address", + "name": "actionTarget", + "type": "address" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "actionPolicies", + "type": "tuple[]" + } + ], + "internalType": "struct ActionData[]", + "name": "actions", + "type": "tuple[]" }, { - "name": "signature", - "type": "bytes", - "internalType": "bytes" + "internalType": "bool", + "name": "permitERC4337Paymaster", + "type": "bool" } - ] - }, - { - "name": "userOpHash", - "type": "bytes32", - "internalType": "bytes32" + ], + "internalType": "struct Session", + "name": "session", + "type": "tuple" } ], + "name": "getPermissionId", "outputs": [ { - "name": "vd", - "type": "uint256", - "internalType": "ValidationData" + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" } ], - "stateMutability": "nonpayable" + "stateMutability": "pure", + "type": "function" }, { - "type": "event", - "name": "ActionIdDisabled", "inputs": [ { + "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32", - "indexed": false, - "internalType": "PermissionId" + "type": "bytes32" }, { - "name": "actionId", - "type": "bytes32", - "indexed": false, - "internalType": "ActionId" + "internalType": "address", + "name": "account", + "type": "address" }, { - "name": "smartAccount", - "type": "address", - "indexed": false, - "internalType": "address" + "components": [ + { + "internalType": "contract ISessionValidator", + "name": "sessionValidator", + "type": "address" + }, + { + "internalType": "bytes", + "name": "sessionValidatorInitData", + "type": "bytes" + }, + { + "internalType": "bytes32", + "name": "salt", + "type": "bytes32" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "userOpPolicies", + "type": "tuple[]" + }, + { + "components": [ + { + "components": [ + { + "internalType": "bytes32", + "name": "appDomainSeparator", + "type": "bytes32" + }, + { + "internalType": "string[]", + "name": "contentNames", + "type": "string[]" + } + ], + "internalType": "struct ERC7739Context[]", + "name": "allowedERC7739Content", + "type": "tuple[]" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "erc1271Policies", + "type": "tuple[]" + } + ], + "internalType": "struct ERC7739Data", + "name": "erc7739Policies", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "bytes4", + "name": "actionTargetSelector", + "type": "bytes4" + }, + { + "internalType": "address", + "name": "actionTarget", + "type": "address" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "actionPolicies", + "type": "tuple[]" + } + ], + "internalType": "struct ActionData[]", + "name": "actions", + "type": "tuple[]" + }, + { + "internalType": "bool", + "name": "permitERC4337Paymaster", + "type": "bool" + } + ], + "internalType": "struct Session", + "name": "data", + "type": "tuple" + }, + { + "internalType": "enum SmartSessionMode", + "name": "mode", + "type": "uint8" } ], - "anonymous": false + "name": "getSessionDigest", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" }, { - "type": "event", - "name": "NonceIterated", "inputs": [ { - "name": "permissionId", - "type": "bytes32", - "indexed": false, - "internalType": "PermissionId" - }, - { + "internalType": "address", "name": "account", - "type": "address", - "indexed": false, - "internalType": "address" + "type": "address" }, { - "name": "newValue", - "type": "uint256", - "indexed": false, - "internalType": "uint256" + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" } ], - "anonymous": false - }, - { - "type": "event", - "name": "PermissionIdPermit4337Paymaster", - "inputs": [ - { - "name": "permissionId", - "type": "bytes32", - "indexed": false, - "internalType": "PermissionId" - }, + "name": "getSessionValidatorAndConfig", + "outputs": [ { - "name": "smartAccount", - "type": "address", - "indexed": false, - "internalType": "address" + "internalType": "address", + "name": "sessionValidator", + "type": "address" }, { - "name": "enabled", - "type": "bool", - "indexed": false, - "internalType": "bool" + "internalType": "bytes", + "name": "sessionValidatorData", + "type": "bytes" } ], - "anonymous": false + "stateMutability": "view", + "type": "function" }, { - "type": "event", - "name": "PolicyDisabled", "inputs": [ { - "name": "permissionId", - "type": "bytes32", - "indexed": false, - "internalType": "PermissionId" - }, - { - "name": "policyType", - "type": "uint8", - "indexed": false, - "internalType": "enum PolicyType" + "internalType": "address", + "name": "account", + "type": "address" }, { - "name": "policy", - "type": "address", - "indexed": false, - "internalType": "address" - }, + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + } + ], + "name": "getUserOpPolicies", + "outputs": [ { - "name": "smartAccount", - "type": "address", - "indexed": false, - "internalType": "address" + "internalType": "address[]", + "name": "", + "type": "address[]" } ], - "anonymous": false + "stateMutability": "view", + "type": "function" }, { - "type": "event", - "name": "PolicyEnabled", "inputs": [ { - "name": "permissionId", - "type": "bytes32", - "indexed": false, - "internalType": "PermissionId" + "internalType": "address", + "name": "account", + "type": "address" }, { - "name": "policyType", - "type": "uint8", - "indexed": false, - "internalType": "enum PolicyType" + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" }, { - "name": "policy", - "type": "address", - "indexed": false, - "internalType": "address" - }, + "internalType": "ActionId", + "name": "actionId", + "type": "bytes32" + } + ], + "name": "isActionIdEnabled", + "outputs": [ { - "name": "smartAccount", - "type": "address", - "indexed": false, - "internalType": "address" + "internalType": "bool", + "name": "", + "type": "bool" } ], - "anonymous": false + "stateMutability": "view", + "type": "function" }, { - "type": "event", - "name": "SessionCreated", "inputs": [ { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32", - "indexed": false, - "internalType": "PermissionId" + "type": "bytes32" }, { - "name": "account", - "type": "address", - "indexed": false, - "internalType": "address" + "internalType": "ActionId", + "name": "actionId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "policy", + "type": "address" } ], - "anonymous": false - }, - { - "type": "event", - "name": "SessionRemoved", - "inputs": [ - { - "name": "permissionId", - "type": "bytes32", - "indexed": false, - "internalType": "PermissionId" - }, + "name": "isActionPolicyEnabled", + "outputs": [ { - "name": "smartAccount", - "type": "address", - "indexed": false, - "internalType": "address" + "internalType": "bool", + "name": "", + "type": "bool" } ], - "anonymous": false + "stateMutability": "view", + "type": "function" }, { - "type": "event", - "name": "SessionValidatorDisabled", "inputs": [ { - "name": "permissionId", - "type": "bytes32", - "indexed": false, - "internalType": "PermissionId" + "internalType": "address", + "name": "account", + "type": "address" }, { - "name": "sessionValidator", - "type": "address", - "indexed": false, - "internalType": "address" + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" }, { - "name": "smartAccount", - "type": "address", - "indexed": false, - "internalType": "address" + "internalType": "address", + "name": "policy", + "type": "address" + } + ], + "name": "isERC1271PolicyEnabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" } ], - "anonymous": false + "stateMutability": "view", + "type": "function" }, { - "type": "event", - "name": "SessionValidatorEnabled", "inputs": [ { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32", - "indexed": false, - "internalType": "PermissionId" + "type": "bytes32" }, { - "name": "sessionValidator", - "type": "address", - "indexed": false, - "internalType": "address" + "internalType": "bytes32", + "name": "appDomainSeparator", + "type": "bytes32" }, { - "name": "smartAccount", - "type": "address", - "indexed": false, - "internalType": "address" + "internalType": "string", + "name": "content", + "type": "string" } ], - "anonymous": false - }, - { - "type": "error", - "name": "AssociatedArray_OutOfBounds", - "inputs": [ + "name": "isERC7739ContentEnabled", + "outputs": [ { - "name": "index", - "type": "uint256", - "internalType": "uint256" + "internalType": "bool", + "name": "", + "type": "bool" } - ] + ], + "stateMutability": "view", + "type": "function" }, { - "type": "error", - "name": "ChainIdMismatch", "inputs": [ { - "name": "providedChainId", - "type": "uint64", - "internalType": "uint64" - } - ] - }, - { - "type": "error", - "name": "ChainIdMismatch", - "inputs": [ + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, { - "name": "providedChainId", - "type": "uint64", - "internalType": "uint64" + "internalType": "address", + "name": "account", + "type": "address" } - ] - }, - { - "type": "error", - "name": "ForbiddenValidationData", - "inputs": [] - }, - { - "type": "error", - "name": "HashIndexOutOfBounds", - "inputs": [ + ], + "name": "isISessionValidatorSet", + "outputs": [ { - "name": "index", - "type": "uint256", - "internalType": "uint256" + "internalType": "bool", + "name": "", + "type": "bool" } - ] + ], + "stateMutability": "view", + "type": "function" }, { - "type": "error", - "name": "HashMismatch", "inputs": [ { - "name": "providedHash", - "type": "bytes32", - "internalType": "bytes32" - }, + "internalType": "address", + "name": "smartAccount", + "type": "address" + } + ], + "name": "isInitialized", + "outputs": [ { - "name": "computedHash", - "type": "bytes32", - "internalType": "bytes32" + "internalType": "bool", + "name": "", + "type": "bool" } - ] + ], + "stateMutability": "view", + "type": "function" }, { - "type": "error", - "name": "HashMismatch", "inputs": [ { - "name": "providedHash", - "type": "bytes32", - "internalType": "bytes32" - }, + "internalType": "uint256", + "name": "typeID", + "type": "uint256" + } + ], + "name": "isModuleType", + "outputs": [ { - "name": "computedHash", - "type": "bytes32", - "internalType": "bytes32" + "internalType": "bool", + "name": "", + "type": "bool" } - ] - }, - { - "type": "error", - "name": "InvalidActionId", - "inputs": [] - }, - { - "type": "error", - "name": "InvalidCallTarget", - "inputs": [] - }, - { - "type": "error", - "name": "InvalidData", - "inputs": [] + ], + "stateMutability": "pure", + "type": "function" }, { - "type": "error", - "name": "InvalidEnableSignature", "inputs": [ { - "name": "account", - "type": "address", - "internalType": "address" + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" }, { - "name": "hash", - "type": "bytes32", - "internalType": "bytes32" + "internalType": "address", + "name": "account", + "type": "address" } - ] - }, - { - "type": "error", - "name": "InvalidISessionValidator", - "inputs": [ + ], + "name": "isPermissionEnabled", + "outputs": [ { - "name": "sessionValidator", - "type": "address", - "internalType": "contract ISessionValidator" + "internalType": "bool", + "name": "", + "type": "bool" } - ] - }, - { - "type": "error", - "name": "InvalidMode", - "inputs": [] + ], + "stateMutability": "view", + "type": "function" }, { - "type": "error", - "name": "InvalidPermissionId", "inputs": [ { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32", - "internalType": "PermissionId" + "type": "bytes32" + }, + { + "internalType": "address", + "name": "policy", + "type": "address" } - ] - }, - { - "type": "error", - "name": "InvalidSelfCall", - "inputs": [] - }, - { - "type": "error", - "name": "InvalidSession", - "inputs": [ + ], + "name": "isUserOpPolicyEnabled", + "outputs": [ { - "name": "permissionId", - "type": "bytes32", - "internalType": "PermissionId" + "internalType": "bool", + "name": "", + "type": "bool" } - ] + ], + "stateMutability": "view", + "type": "function" }, { - "type": "error", - "name": "InvalidSessionKeySignature", "inputs": [ { - "name": "permissionId", - "type": "bytes32", - "internalType": "PermissionId" - }, - { - "name": "sessionValidator", - "type": "address", - "internalType": "address" + "internalType": "address", + "name": "sender", + "type": "address" }, { - "name": "account", - "type": "address", - "internalType": "address" + "internalType": "bytes32", + "name": "hash", + "type": "bytes32" }, { - "name": "userOpHash", - "type": "bytes32", - "internalType": "bytes32" + "internalType": "bytes", + "name": "signature", + "type": "bytes" } - ] - }, - { - "type": "error", - "name": "InvalidTarget", - "inputs": [] - }, - { - "type": "error", - "name": "InvalidUserOpSender", - "inputs": [ + ], + "name": "isValidSignatureWithSender", + "outputs": [ { - "name": "sender", - "type": "address", - "internalType": "address" + "internalType": "bytes4", + "name": "result", + "type": "bytes4" } - ] - }, - { - "type": "error", - "name": "NoExecutionsInBatch", - "inputs": [] + ], + "stateMutability": "view", + "type": "function" }, { - "type": "error", - "name": "NoPoliciesSet", "inputs": [ { - "name": "permissionId", - "type": "bytes32", - "internalType": "PermissionId" + "internalType": "bytes", + "name": "data", + "type": "bytes" } - ] - }, - { - "type": "error", - "name": "PartlyEnabledActions", - "inputs": [] - }, - { - "type": "error", - "name": "PartlyEnabledPolicies", - "inputs": [] + ], + "name": "onInstall", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "type": "error", - "name": "PaymasterValidationNotEnabled", "inputs": [ { - "name": "permissionId", - "type": "bytes32", - "internalType": "PermissionId" + "internalType": "bytes", + "name": "", + "type": "bytes" } - ] + ], + "name": "onUninstall", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "type": "error", - "name": "PolicyViolation", "inputs": [ { + "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32", - "internalType": "PermissionId" - }, - { - "name": "policy", - "type": "address", - "internalType": "address" + "type": "bytes32" } - ] + ], + "name": "removeSession", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "type": "error", - "name": "SignerNotFound", "inputs": [ { + "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32", - "internalType": "PermissionId" - }, - { - "name": "account", - "type": "address", - "internalType": "address" + "type": "bytes32" } - ] + ], + "name": "revokeEnableSignature", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "type": "error", - "name": "SignerNotFound", "inputs": [ { + "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32", - "internalType": "PermissionId" + "type": "bytes32" }, { - "name": "account", - "type": "address", - "internalType": "address" - } - ] - }, - { - "type": "error", - "name": "SmartSessionModuleAlreadyInstalled", - "inputs": [ - { - "name": "account", - "type": "address", - "internalType": "address" + "internalType": "bool", + "name": "enabled", + "type": "bool" } - ] + ], + "name": "setPermit4337Paymaster", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "type": "error", - "name": "UnsupportedCallType", "inputs": [ { - "name": "callType", - "type": "bytes1", - "internalType": "CallType" - } - ] - }, - { - "type": "error", - "name": "UnsupportedExecutionType", - "inputs": [] - }, - { - "type": "error", - "name": "UnsupportedPolicy", - "inputs": [ + "components": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "initCode", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "callData", + "type": "bytes" + }, + { + "internalType": "bytes32", + "name": "accountGasLimits", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "preVerificationGas", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "gasFees", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "paymasterAndData", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "internalType": "struct PackedUserOperation", + "name": "userOp", + "type": "tuple" + }, { - "name": "policy", - "type": "address", - "internalType": "address" + "internalType": "bytes32", + "name": "userOpHash", + "type": "bytes32" } - ] - }, - { - "type": "error", - "name": "UnsupportedSmartSessionMode", - "inputs": [ + ], + "name": "validateUserOp", + "outputs": [ { - "name": "mode", - "type": "uint8", - "internalType": "enum SmartSessionMode" + "internalType": "ValidationData", + "name": "vd", + "type": "uint256" } - ] + ], + "stateMutability": "nonpayable", + "type": "function" } ] as const; diff --git a/packages/core/src/lib/agentic/contracts/abi/v4/universal-rules-policy.ts b/packages/core/src/lib/agentic/contracts/abi/v4/universal-rules-policy.ts new file mode 100644 index 00000000..1ffd395a --- /dev/null +++ b/packages/core/src/lib/agentic/contracts/abi/v4/universal-rules-policy.ts @@ -0,0 +1,2156 @@ +// GENERATED by packages/core/scripts/agw-local/gen-abi.mjs — do not edit. +// Source: plan/agw/research/deployment-review-2026-10-06/abis/UniversalRulesPolicy.json +// push-agentic-wallets@e8db74815cfbbf5389593805e464fe8d85f7f735 +// sha256(UniversalRulesPolicy.json) = b40e2a91eaa9c09cbe214621259fb7d12def00d12c756e2fd659eff4e26277c0 +export const UNIVERSAL_RULES_POLICY_ABI = [ + { + "inputs": [ + { + "internalType": "uint256", + "name": "length", + "type": "uint256" + } + ], + "name": "AllowListOutOfRange", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "outboundTxId", + "type": "bytes32" + } + ], + "name": "AlreadyCredited", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "ConfigId", + "name": "id", + "type": "bytes32" + } + ], + "name": "AlreadyInitialized", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "i", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "j", + "type": "uint256" + } + ], + "name": "AmbiguousRule", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "cap", + "type": "uint256" + } + ], + "name": "AmountExceedsCap", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "AmountExceedsU64", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "actual", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "expected", + "type": "bytes32" + } + ], + "name": "ArgPinMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "length", + "type": "uint256" + } + ], + "name": "AssetListOutOfRange", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "name": "AssetNotAllowed", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "expected", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "actual", + "type": "uint256" + } + ], + "name": "AssetSpentMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "count", + "type": "uint256" + } + ], + "name": "BatchSizeOutOfRange", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "expected", + "type": "address" + }, + { + "internalType": "address", + "name": "actual", + "type": "address" + } + ], + "name": "BeneficiaryMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint32", + "name": "callsUsed", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "maxCalls", + "type": "uint32" + } + ], + "name": "CallLimitReached", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "bytes4", + "name": "selector", + "type": "bytes4" + } + ], + "name": "CallNotAllowed", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "length", + "type": "uint256" + } + ], + "name": "CalldataTooShort", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "actualLength", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "needed", + "type": "uint256" + } + ], + "name": "CalldataTooShortForAmount", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "actualLength", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "needed", + "type": "uint256" + } + ], + "name": "CalldataTooShortForPin", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "CallerIsNotUEModule", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "accountIndex", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "account", + "type": "bytes32" + } + ], + "name": "CeaAccountAtUnpinnedIndex", + "type": "error" + }, + { + "inputs": [], + "name": "CeaAccountsMissExpectedCEA", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "declared", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "assetChain", + "type": "bytes32" + } + ], + "name": "ChainMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "rule", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "len", + "type": "uint8" + } + ], + "name": "DiscriminatorLenOutOfRange", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "name": "DuplicateAsset", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "first", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "second", + "type": "uint256" + } + ], + "name": "DuplicateSvmPin", + "type": "error" + }, + { + "inputs": [], + "name": "EmptyChain", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "target", + "type": "address" + } + ], + "name": "ForbiddenInnerTarget", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "rule", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "program", + "type": "bytes32" + } + ], + "name": "ForbiddenProgramInAllowList", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "program", + "type": "bytes32" + } + ], + "name": "ForbiddenTargetProgram", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxValue", + "type": "uint256" + } + ], + "name": "InnerValueExceedsAllowance", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "asset", + "type": "address" + } + ], + "name": "InvalidAsset", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "InvalidCeaAccount", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidConfigField", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint48", + "name": "validUntil", + "type": "uint48" + } + ], + "name": "InvalidExpiry", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidInitialization", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "expected", + "type": "address" + }, + { + "internalType": "address", + "name": "actual", + "type": "address" + } + ], + "name": "InvalidRevertRecipient", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "selector", + "type": "bytes4" + } + ], + "name": "InvalidSelector", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidSvmConfigField", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "target", + "type": "address" + } + ], + "name": "InvalidTarget", + "type": "error" + }, + { + "inputs": [], + "name": "MalformedInnerCalldata", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "length", + "type": "uint256" + } + ], + "name": "MalformedOutboundRequest", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint8", + "name": "code", + "type": "uint8" + } + ], + "name": "MalformedSvmPayload", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "cap", + "type": "uint256" + } + ], + "name": "NativeAmountExceedsCap", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "target", + "type": "address" + } + ], + "name": "NativeTargetIsGateway", + "type": "error" + }, + { + "inputs": [], + "name": "NativeTargetZero", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "ConfigId", + "name": "id", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "NotInitialized", + "type": "error" + }, + { + "inputs": [], + "name": "NotInitializing", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "cap", + "type": "uint256" + } + ], + "name": "PCValueExceedsCap", + "type": "error" + }, + { + "inputs": [], + "name": "PayloadNotMulticall", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "ConfigId", + "name": "id", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "multiplexer", + "type": "address" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "PolicyNotInitialized", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "length", + "type": "uint256" + } + ], + "name": "ProgramListOutOfRange", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "program", + "type": "bytes32" + }, + { + "internalType": "bytes8", + "name": "discriminator", + "type": "bytes8" + } + ], + "name": "ProgramNotAllowed", + "type": "error" + }, + { + "inputs": [], + "name": "RecipientMustBeEmpty", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "length", + "type": "uint256" + } + ], + "name": "RecipientNotPubkey", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "recipient", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "target", + "type": "bytes32" + } + ], + "name": "RecipientTargetMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "rule", + "type": "uint256" + } + ], + "name": "RuleWithoutPin", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint48", + "name": "validUntil", + "type": "uint48" + } + ], + "name": "RulesExpired", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "actual", + "type": "bytes4" + }, + { + "internalType": "bytes4", + "name": "expected", + "type": "bytes4" + } + ], + "name": "SelectorMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "expected", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "actual", + "type": "uint256" + } + ], + "name": "SpentLengthMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "expected", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "actual", + "type": "uint256" + } + ], + "name": "SpentMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "pin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "count", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "needed", + "type": "uint8" + } + ], + "name": "SvmAccountCountBelowPin", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "count", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "expected", + "type": "uint8" + } + ], + "name": "SvmAccountCountMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "pin", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "accountIndex", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "expected", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "actual", + "type": "bytes32" + } + ], + "name": "SvmAccountPinMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "count", + "type": "uint256" + } + ], + "name": "SvmAccountsOutOfRange", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "pin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "actual", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "ceiling", + "type": "uint256" + } + ], + "name": "SvmDataCeilingExceeded", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "pin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "actual", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "floor", + "type": "uint256" + } + ], + "name": "SvmDataFloorNotMet", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "pin", + "type": "uint256" + } + ], + "name": "SvmDataPinInvalid", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "pin", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "expected", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "actual", + "type": "bytes32" + } + ], + "name": "SvmDataPinMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "pin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "a", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "b", + "type": "uint256" + }, + { + "internalType": "uint64", + "name": "num", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "den", + "type": "uint64" + } + ], + "name": "SvmDataRatioNotMet", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "pin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "ixLen", + "type": "uint256" + } + ], + "name": "SvmDataTooShortForPin", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint8", + "name": "instructionId", + "type": "uint8" + } + ], + "name": "SvmInstructionNotExecute", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "length", + "type": "uint256" + } + ], + "name": "SvmIxDataTooLong", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "rule", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "maxAccounts", + "type": "uint8" + } + ], + "name": "SvmMaxAccountsOutOfRange", + "type": "error" + }, + { + "inputs": [], + "name": "SvmPayloadEmpty", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "pin", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "accountIndex", + "type": "uint8" + } + ], + "name": "SvmPinIndexOutOfRange", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "pin", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "rule", + "type": "uint8" + } + ], + "name": "SvmPinRuleOutOfRange", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "actual", + "type": "address" + }, + { + "internalType": "address", + "name": "expected", + "type": "address" + } + ], + "name": "TargetMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "count", + "type": "uint256" + } + ], + "name": "TooManyCeaAccounts", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "count", + "type": "uint256" + } + ], + "name": "TooManyPins", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "count", + "type": "uint256" + } + ], + "name": "TooManySvmDataPins", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "count", + "type": "uint256" + } + ], + "name": "TooManySvmPins", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newSpent", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "cap", + "type": "uint256" + } + ], + "name": "TotalNativeAmountExceeded", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "wouldBeTotal", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "cap", + "type": "uint256" + } + ], + "name": "TotalSpendCapExceeded", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newSpent", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "cap", + "type": "uint256" + } + ], + "name": "TotalValueExceeded", + "type": "error" + }, + { + "inputs": [], + "name": "UncappedGasSwapRejected", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "version", + "type": "uint256" + } + ], + "name": "UnsupportedEnvelopeVersion", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "chainHash", + "type": "bytes32" + } + ], + "name": "UnsupportedNamespace", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "cap", + "type": "uint256" + } + ], + "name": "ValueExceedsCap", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "length", + "type": "uint256" + } + ], + "name": "ValueOnlyCalldataNotEmpty", + "type": "error" + }, + { + "inputs": [], + "name": "ValueOnlyWithAmountRule", + "type": "error" + }, + { + "inputs": [], + "name": "ValueOnlyWithPins", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "enum RulesType", + "name": "actual", + "type": "uint8" + } + ], + "name": "WrongModeForCall", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "enum VmFamily", + "name": "actual", + "type": "uint8" + } + ], + "name": "WrongVmForCall", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroAddress", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint64", + "name": "version", + "type": "uint64" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "ConfigId", + "name": "id", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "multiplexer", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "NativeCallMetered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "ConfigId", + "name": "id", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "multiplexer", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "OutboundMetered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "ConfigId", + "name": "id", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "address", + "name": "multiplexer", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "PolicySet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "outboundTxId", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "ConfigId", + "name": "id", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amountApplied", + "type": "uint256" + } + ], + "name": "RevertCredited", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "ConfigId", + "name": "id", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "multiplexer", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "enum RulesType", + "name": "mode", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "enum VmFamily", + "name": "vm", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "chainHash", + "type": "bytes32" + } + ], + "name": "RulesConfigured", + "type": "event" + }, + { + "inputs": [], + "name": "SEND_OUTBOUND_SELECTOR", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "SESSION_ENGINE", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "UNIVERSAL_EXECUTOR_MODULE", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "UNIVERSAL_GATEWAY_PC", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "ConfigId", + "name": "id", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "expectedValueSpent", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expectedAmountSpent", + "type": "uint256" + }, + { + "internalType": "uint32", + "name": "expectedCalls", + "type": "uint32" + } + ], + "name": "assertSpent", + "outputs": [], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "ConfigId", + "name": "id", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256[]", + "name": "expectedSpent", + "type": "uint256[]" + } + ], + "name": "assertSpent", + "outputs": [], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "ConfigId", + "name": "id", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "checkAction", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "ConfigId", + "name": "id", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "outboundTxId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "creditRevert", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "ConfigId", + "name": "id", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "getConfig", + "outputs": [ + { + "components": [ + { + "internalType": "bool", + "name": "initialized", + "type": "bool" + }, + { + "internalType": "uint48", + "name": "validUntil", + "type": "uint48" + }, + { + "internalType": "address", + "name": "expectedCEA", + "type": "address" + }, + { + "internalType": "uint256", + "name": "maxGasPerCall", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "maxPerCall", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxTotal", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "spent", + "type": "uint256" + } + ], + "internalType": "struct AssetCapState[]", + "name": "assets", + "type": "tuple[]" + }, + { + "components": [ + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "bytes4", + "name": "selector", + "type": "bytes4" + }, + { + "internalType": "uint16", + "name": "beneficiaryOffset", + "type": "uint16" + }, + { + "internalType": "bool", + "name": "hasBeneficiary", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "maxValue", + "type": "uint256" + } + ], + "internalType": "struct AllowedCall[]", + "name": "allowedCalls", + "type": "tuple[]" + } + ], + "internalType": "struct Config", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "ConfigId", + "name": "id", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "getMode", + "outputs": [ + { + "components": [ + { + "internalType": "bool", + "name": "initialized", + "type": "bool" + }, + { + "internalType": "enum RulesType", + "name": "mode", + "type": "uint8" + }, + { + "internalType": "enum VmFamily", + "name": "vm", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "chainHash", + "type": "bytes32" + } + ], + "internalType": "struct ModeSlot", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "ConfigId", + "name": "id", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "getNativeConfig", + "outputs": [ + { + "components": [ + { + "internalType": "bool", + "name": "initialized", + "type": "bool" + }, + { + "internalType": "uint48", + "name": "validUntil", + "type": "uint48" + }, + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "bytes4", + "name": "selector", + "type": "bytes4" + }, + { + "internalType": "uint256", + "name": "maxValuePerCall", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxValueTotal", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "valueSpent", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "bool", + "name": "enabled", + "type": "bool" + }, + { + "internalType": "uint16", + "name": "offset", + "type": "uint16" + }, + { + "internalType": "uint256", + "name": "maxPerCall", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxTotal", + "type": "uint256" + } + ], + "internalType": "struct AmountRule", + "name": "amount", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "amountSpent", + "type": "uint256" + }, + { + "internalType": "uint32", + "name": "maxCalls", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "callsUsed", + "type": "uint32" + }, + { + "components": [ + { + "internalType": "uint16", + "name": "offset", + "type": "uint16" + }, + { + "internalType": "bytes32", + "name": "expected", + "type": "bytes32" + } + ], + "internalType": "struct ArgPin[]", + "name": "pins", + "type": "tuple[]" + } + ], + "internalType": "struct NativeConfig", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "ConfigId", + "name": "id", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "getSvmConfig", + "outputs": [ + { + "components": [ + { + "internalType": "bool", + "name": "initialized", + "type": "bool" + }, + { + "internalType": "uint48", + "name": "validUntil", + "type": "uint48" + }, + { + "internalType": "bytes32", + "name": "expectedCEA", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "gatewayProgram", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "maxGasPerCall", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "maxPerCall", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxTotal", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "spent", + "type": "uint256" + } + ], + "internalType": "struct AssetCapState[]", + "name": "assets", + "type": "tuple[]" + }, + { + "internalType": "bytes32[]", + "name": "ceaAccounts", + "type": "bytes32[]" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "program", + "type": "bytes32" + }, + { + "internalType": "bytes8", + "name": "discriminator", + "type": "bytes8" + }, + { + "internalType": "uint8", + "name": "discriminatorLen", + "type": "uint8" + }, + { + "internalType": "bool", + "name": "dataless", + "type": "bool" + }, + { + "internalType": "uint8", + "name": "maxAccounts", + "type": "uint8" + } + ], + "internalType": "struct AllowedProgram[]", + "name": "programs", + "type": "tuple[]" + }, + { + "components": [ + { + "internalType": "uint8", + "name": "ruleIndex", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "accountIndex", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "expected", + "type": "bytes32" + } + ], + "internalType": "struct SvmAccountPin[]", + "name": "pins", + "type": "tuple[]" + }, + { + "components": [ + { + "internalType": "uint8", + "name": "ruleIndex", + "type": "uint8" + }, + { + "internalType": "bool", + "name": "fromEnd", + "type": "bool" + }, + { + "internalType": "uint16", + "name": "offset", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "offsetB", + "type": "uint16" + }, + { + "internalType": "uint8", + "name": "len", + "type": "uint8" + }, + { + "internalType": "enum SvmDataPinMode", + "name": "mode", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "expected", + "type": "bytes32" + }, + { + "internalType": "uint64", + "name": "num", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "den", + "type": "uint64" + } + ], + "internalType": "struct SvmDataPin[]", + "name": "dataPins", + "type": "tuple[]" + } + ], + "internalType": "struct SvmConfig", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "universalGatewayPC", + "type": "address" + }, + { + "internalType": "address", + "name": "universalExecutorModule", + "type": "address" + }, + { + "internalType": "address", + "name": "sessionEngine", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "ConfigId", + "name": "configId", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "name": "initializeWithMultiplexer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "outboundTxId", + "type": "bytes32" + } + ], + "name": "isCredited", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pushChainHash", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "iid", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "version", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "pure", + "type": "function" + } +] as const; diff --git a/packages/core/src/lib/agentic/contracts/donut-v4.ts b/packages/core/src/lib/agentic/contracts/donut-v4.ts new file mode 100644 index 00000000..63a75170 --- /dev/null +++ b/packages/core/src/lib/agentic/contracts/donut-v4.ts @@ -0,0 +1,13 @@ +import type { Address } from 'viem'; + +/** Source e8db748; code/proxy wiring checked at Donut block 23931055. */ +export const V4_SOURCE_COMMIT = 'e8db74815cfbbf5389593805e464fe8d85f7f735'; +export const DONUT_V4_START_BLOCK = BigInt(23923806); +export const DONUT_V4_ADDRESSES = { + factory: '0xaF88D0FD947afAe7bBb8F34e8417DCfc165e1aaF', + walletImplementation: '0x96D69ec7e6cDdaD414e656B5c9DCA24587DF713c', + sessionEngine: '0x165A5E6782f39D30B38c7D97e1303e4CB2aD102a', + rulesPolicy: '0x603E7f0aF6e1aAFf46DDfb28b1e99364f8BC59af', + sessionValidator: '0x068EE2388475A98EE1f5a434C58bFF3444fffFe6', + gateway: '0x00000000000000000000000000000000000000C1', +} as const satisfies Record; diff --git a/packages/core/src/lib/agentic/contracts/prc20-metadata.ts b/packages/core/src/lib/agentic/contracts/prc20-metadata.ts new file mode 100644 index 00000000..9f29dc62 --- /dev/null +++ b/packages/core/src/lib/agentic/contracts/prc20-metadata.ts @@ -0,0 +1,64 @@ +import { + getAddress, + isAddress, + parseAbi, + zeroAddress, + type Address, +} from 'viem'; +import { UNIVERSAL_CORE_EVM } from '../../constants/abi/prc20.evm'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; +import type { Snapshot } from '../reads/snapshot'; + +export const PRC20_SOURCE_ABI = parseAbi([ + 'function SOURCE_CHAIN_NAMESPACE() view returns (string)', + 'function SOURCE_TOKEN_ADDRESS() view returns (string)', +]); +const NATIVE_SOURCE_ABI = parseAbi([ + 'function SOURCE_TOKEN_ADDRESS() view returns (address)', +]); +export const CORE_ADDRESS = + '0x00000000000000000000000000000000000000C0' as Address; +export async function readGasPrc20( + snap: Snapshot, + chain: string +): Promise
{ + return getAddress( + await snap.read
( + CORE_ADDRESS, + UNIVERSAL_CORE_EVM, + 'gasTokenPRC20ByChainNamespace', + [chain] + ) + ); +} +/** Donut native precompile returns a zero word; ERC20 metadata is a dynamic string. */ +export async function readOriginToken( + snap: Snapshot, + token: Address, + chain: string +): Promise
{ + let source: string; + try { + source = await snap.read( + token, + PRC20_SOURCE_ABI, + 'SOURCE_TOKEN_ADDRESS' + ); + } catch (cause) { + if ((await readGasPrc20(snap, chain)) !== getAddress(token)) throw cause; + const native = await snap.read
( + token, + NATIVE_SOURCE_ABI, + 'SOURCE_TOKEN_ADDRESS' + ); + if (getAddress(native) === zeroAddress) return zeroAddress; + throw cause; + } + if (isAddress(source, { strict: false })) return getAddress(source); + if (source === '' && (await readGasPrc20(snap, chain)) === getAddress(token)) + return zeroAddress; + throw new AgenticError( + AGENTIC_ERROR_CODE.RULE_READ_FAILED, + `PRC20 ${token} has an invalid source token address` + ); +} diff --git a/packages/core/src/lib/agentic/contracts/e704d5b.ts b/packages/core/src/lib/agentic/contracts/v4.ts similarity index 68% rename from packages/core/src/lib/agentic/contracts/e704d5b.ts rename to packages/core/src/lib/agentic/contracts/v4.ts index 2a4a33af..7d6dc094 100644 --- a/packages/core/src/lib/agentic/contracts/e704d5b.ts +++ b/packages/core/src/lib/agentic/contracts/v4.ts @@ -18,13 +18,15 @@ import { AGW_FACTORY_ABI, SMART_SESSION_ABI, UNIVERSAL_RULES_POLICY_ABI, -} from './abi/e704d5b'; +} from './abi/v4'; import type { SessionWire } from '../codec/session'; import type { CheckpointKind } from '../agentic.types'; import type { NativeTermsWire } from '../codec/native'; +import type { UniversalTermsWire } from '../codec/universal-terms'; +import type { SvmTermsWire } from '../codec/svm-terms'; /** - * Contract adapter for the reviewed e704d5b ABI generation. All version- + * Contract adapter for the reviewed v4 ABI generation. All version- * sensitive encoding, decoding and view names live here; callers never touch * a raw ABI. A future generation gets its own adapter implementing the same * interface. @@ -63,17 +65,25 @@ export interface ModeRead { chainHash: Hex; } -/** Historical single-asset universal config (getConfig) — review generation only. */ -export interface UniversalConfigReadE704d5b { +export interface UniversalConfigRead + extends Omit { initialized: boolean; - validUntil: number; - destChainHash: Hex; - expectedCEA: Address; - asset: Address; - maxAmountPerCall: bigint; - maxAmountTotal: bigint; - maxPCPerCall: bigint; - spent: bigint; + assets: readonly { + token: Address; + maxPerCall: bigint; + maxTotal: bigint; + spent: bigint; + }[]; +} + +export interface SvmConfigRead extends Omit { + initialized: boolean; + assets: readonly { + token: Address; + maxPerCall: bigint; + maxTotal: bigint; + spent: bigint; + }[]; } export type DecodedWalletCall = @@ -94,8 +104,8 @@ const EXECUTION_TUPLE = [ }, ] as const; -export const e704d5b = { - id: 'e704d5b', +export const v4 = { + id: 'v4', abis: { wallet: AGW_ABI, factory: AGW_FACTORY_ABI, @@ -103,15 +113,31 @@ export const e704d5b = { policy: UNIVERSAL_RULES_POLICY_ABI, }, events: { - walletDeployed: getAbiItem({ abi: AGW_FACTORY_ABI, name: 'WalletDeployed' }) as AbiEvent, - checkpointed: getAbiItem({ abi: AGW_ABI, name: 'Checkpointed' }) as AbiEvent, - rulesGranted: getAbiItem({ abi: AGW_ABI, name: 'RulesGranted' }) as AbiEvent, - rulesRevoked: getAbiItem({ abi: AGW_ABI, name: 'RulesRevoked' }) as AbiEvent, + walletDeployed: getAbiItem({ + abi: AGW_FACTORY_ABI, + name: 'WalletDeployed', + }) as AbiEvent, + checkpointed: getAbiItem({ + abi: AGW_ABI, + name: 'Checkpointed', + }) as AbiEvent, + rulesGranted: getAbiItem({ + abi: AGW_ABI, + name: 'RulesGranted', + }) as AbiEvent, + rulesRevoked: getAbiItem({ + abi: AGW_ABI, + name: 'RulesRevoked', + }) as AbiEvent, }, // ---------------------------------------------------------------- encoders encodeDeployWallet(label: string): Hex { - return encodeFunctionData({ abi: AGW_FACTORY_ABI, functionName: 'deployWallet', args: [label] }); + return encodeFunctionData({ + abi: AGW_FACTORY_ABI, + functionName: 'deployWallet', + args: [label], + }); }, /** * Index-bound deployment for an owner calling the factory itself. @@ -121,7 +147,12 @@ export const e704d5b = { * creation therefore makes this call revert instead of deploying another * slot while later calls in the batch target the predicted address. */ - encodeDeployWalletAt(owner: Address, index: bigint, wallet: Address, label: string): Hex { + encodeDeployWalletAt( + owner: Address, + index: bigint, + wallet: Address, + label: string + ): Hex { const zero32 = `0x${'00'.repeat(32)}` as Hex; const zeroAddress = '0x0000000000000000000000000000000000000000' as Address; return encodeFunctionData({ @@ -155,14 +186,25 @@ export const e704d5b = { }); }, encodeRevokeRules(rulesId: Hex): Hex { - return encodeFunctionData({ abi: AGW_ABI, functionName: 'revokeRules', args: [rulesId] }); + return encodeFunctionData({ + abi: AGW_ABI, + functionName: 'revokeRules', + args: [rulesId], + }); }, encodeRevokeAllRules(): Hex { - return encodeFunctionData({ abi: AGW_ABI, functionName: 'revokeAllRules', args: [] }); + return encodeFunctionData({ + abi: AGW_ABI, + functionName: 'revokeAllRules', + args: [], + }); }, /** ERC-7579 single execution calldata: abi.encodePacked(target, value, callData). */ packSingle(call: Call): Hex { - return encodePacked(['address', 'uint256', 'bytes'], [call.target, call.value, call.data]); + return encodePacked( + ['address', 'uint256', 'bytes'], + [call.target, call.value, call.data] + ); }, encodeExecute(calls: Call[]): Hex { if (calls.length === 0) throw new Error('execute needs at least one call'); @@ -170,19 +212,27 @@ export const e704d5b = { return encodeFunctionData({ abi: AGW_ABI, functionName: 'execute', - args: [MODE_SINGLE, e704d5b.packSingle(calls[0])], + args: [MODE_SINGLE, v4.packSingle(calls[0])], }); } const batch = encodeAbiParameters(EXECUTION_TUPLE, [ - calls.map((c) => ({ target: c.target, value: c.value, callData: c.data })), + calls.map((c) => ({ + target: c.target, + value: c.value, + callData: c.data, + })), ]); - return encodeFunctionData({ abi: AGW_ABI, functionName: 'execute', args: [MODE_BATCH, batch] }); + return encodeFunctionData({ + abi: AGW_ABI, + functionName: 'execute', + args: [MODE_BATCH, batch], + }); }, encodeExecuteAsAgent(rulesId: Hex, call: Call): Hex { return encodeFunctionData({ abi: AGW_ABI, functionName: 'executeAsAgent', - args: [rulesId, MODE_SINGLE, e704d5b.packSingle(call)], + args: [rulesId, MODE_SINGLE, v4.packSingle(call)], }); }, encodeAssertSpentNative( @@ -193,7 +243,24 @@ export const e704d5b = { return encodeFunctionData({ abi: UNIVERSAL_RULES_POLICY_ABI, functionName: 'assertSpent', - args: [configId, wallet, expected.valueSpent, expected.amountSpent, expected.callsUsed], + args: [ + configId, + wallet, + expected.valueSpent, + expected.amountSpent, + expected.callsUsed, + ], + }); + }, + encodeAssertSpentUniversal( + configId: Hex, + wallet: Address, + expectedSpent: readonly bigint[] + ): Hex { + return encodeFunctionData({ + abi: UNIVERSAL_RULES_POLICY_ABI, + functionName: 'assertSpent', + args: [configId, wallet, expectedSpent], }); }, @@ -212,10 +279,18 @@ export const e704d5b = { } case 'executeAsAgent': { const [rulesId, mode, ecd] = decoded.args as readonly [Hex, Hex, Hex]; - return { kind: 'executeAsAgent', rulesId, mode, calls: unpackExecution(mode, ecd) }; + return { + kind: 'executeAsAgent', + rulesId, + mode, + calls: unpackExecution(mode, ecd), + }; } case 'grantRules': - return { kind: 'grantRules', session: decoded.args[0] as unknown as SessionWire }; + return { + kind: 'grantRules', + session: decoded.args[0] as unknown as SessionWire, + }; case 'revokeRules': return { kind: 'revokeRules', rulesId: decoded.args[0] as Hex }; case 'revokeAllRules': @@ -230,22 +305,24 @@ export const e704d5b = { return k; }, parseWalletDeployed(logs: readonly Log[], factory: Address) { - return decodeMatching(logs, factory, e704d5b.events.walletDeployed).map((args) => ({ - owner: getAddress(args['owner'] as Address), - index: BigInt(args['index'] as bigint), - wallet: getAddress(args['wallet'] as Address), - label: args['label'] as string, - })); + return decodeMatching(logs, factory, v4.events.walletDeployed).map( + (args) => ({ + owner: getAddress(args['owner'] as Address), + index: BigInt(args['index'] as bigint), + wallet: getAddress(args['wallet'] as Address), + label: args['label'] as string, + }) + ); }, parseRulesGranted(logs: readonly Log[], wallet: Address) { - return decodeMatching(logs, wallet, e704d5b.events.rulesGranted).map((args) => ({ + return decodeMatching(logs, wallet, v4.events.rulesGranted).map((args) => ({ rulesId: args['rulesId'] as Hex, mode: Number(args['mode']), chainNamespace: args['chainNamespace'] as string, })); }, parseRulesRevoked(logs: readonly Log[], wallet: Address) { - return decodeMatching(logs, wallet, e704d5b.events.rulesRevoked).map((args) => ({ + return decodeMatching(logs, wallet, v4.events.rulesRevoked).map((args) => ({ rulesId: args['rulesId'] as Hex, })); }, @@ -254,11 +331,16 @@ export const e704d5b = { .filter( (l) => sameAddress(l.address, wallet) && - l.topics[0]?.toLowerCase() === toEventSelector(e704d5b.events.checkpointed).toLowerCase() + l.topics[0]?.toLowerCase() === + toEventSelector(v4.events.checkpointed).toLowerCase() ) .flatMap((log) => { try { - const ev = decodeEventLog({ abi: [e704d5b.events.checkpointed], ...log, strict: true }); + const ev = decodeEventLog({ + abi: [v4.events.checkpointed], + ...log, + strict: true, + }); return [{ log, args: ev.args as unknown as Record }]; } catch { return []; @@ -266,7 +348,7 @@ export const e704d5b = { }) .map(({ log, args }) => ({ seq: Number(args['seq']), - kind: e704d5b.decodeCheckpointKind(Number(args['kind'])), + kind: v4.decodeCheckpointKind(Number(args['kind'])), ref: args['ref'] as Hex, blockNumber: BigInt(log.blockNumber ?? BigInt(0)), txHash: log.transactionHash as Hex, @@ -316,7 +398,12 @@ function decodeMatching( if (!sameAddress(log.address, emitter)) continue; if (log.topics[0]?.toLowerCase() !== topic0) continue; try { - const ev = decodeEventLog({ abi: [event], data: log.data, topics: log.topics, strict: true }); + const ev = decodeEventLog({ + abi: [event], + data: log.data, + topics: log.topics, + strict: true, + }); out.push(ev.args as unknown as Record); } catch { // not this event @@ -325,4 +412,4 @@ function decodeMatching( return out; } -export type AgwContracts = typeof e704d5b; +export type AgwContracts = typeof v4; diff --git a/packages/core/src/lib/agentic/deployments.ts b/packages/core/src/lib/agentic/deployments.ts index c2efe09b..779fb502 100644 --- a/packages/core/src/lib/agentic/deployments.ts +++ b/packages/core/src/lib/agentic/deployments.ts @@ -1,9 +1,14 @@ import { getAddress, type Address } from 'viem'; import { PUSH_NETWORK } from '../constants/enums'; import { AgenticCapability } from './capabilities'; -import { e704d5b, type AgwContracts } from './contracts/e704d5b'; +import { v4, type AgwContracts } from './contracts/v4'; import type { ChainReader } from './contracts/reader'; import { AGENTIC_ERROR_CODE, AgenticError } from './errors'; +import { + DONUT_V4_ADDRESSES, + DONUT_V4_START_BLOCK, + V4_SOURCE_COMMIT, +} from './contracts/donut-v4'; /** * A verified AGW contract generation on one Push network. The registry is the @@ -12,7 +17,7 @@ import { AGENTIC_ERROR_CODE, AgenticError } from './errors'; * are NOT registered because they do not implement this ABI. */ export interface AgenticGeneration { - /** Stable identifier, e.g. 'e704d5b'. */ + /** Stable identifier, e.g. 'v4'. */ id: string; /** Contract source commit the ABI was generated from. */ sourceCommit: string; @@ -35,8 +40,8 @@ export interface AgenticGeneration { contracts: AgwContracts; } -/** Capabilities the e704d5b ABI actually implements. Target-only features are absent. */ -export const E704D5B_CAPABILITIES: ReadonlySet = new Set([ +/** Capabilities the v4 ABI actually implements. Target-only features are absent. */ +export const V4_CAPABILITIES: ReadonlySet = new Set([ AgenticCapability.WALLET_READS, AgenticCapability.ACTIVE_RULE_READS, AgenticCapability.OWNER_EXECUTE, @@ -45,13 +50,26 @@ export const E704D5B_CAPABILITIES: ReadonlySet = new Set([ AgenticCapability.ASSERT_SPENT_NATIVE, AgenticCapability.CHECKPOINTS, AgenticCapability.UNIVERSAL_EVM_OUTBOUND, + AgenticCapability.UNIVERSAL_EVM_RULES, + AgenticCapability.ASSERT_SPENT_UNIVERSAL_MULTI, ]); /** - * Verified release deployments. EMPTY: no deployment of a compatible - * generation has been verified on any Push network (assumption A07). + * V4 only. Unsupported networks fail before signing; no legacy adapter fallback. */ -const VERIFIED_DEPLOYMENTS: readonly AgenticGeneration[] = []; +const VERIFIED_DEPLOYMENTS: readonly AgenticGeneration[] = [ + { + id: 'v4', + sourceCommit: V4_SOURCE_COMMIT, + network: PUSH_NETWORK.TESTNET_DONUT, + advertised: true, + addresses: DONUT_V4_ADDRESSES, + startBlock: DONUT_V4_START_BLOCK, + accountId: 'push.agw.1.0.0', + capabilities: V4_CAPABILITIES, + contracts: v4, + }, +]; const registry: AgenticGeneration[] = [...VERIFIED_DEPLOYMENTS]; @@ -65,7 +83,7 @@ export function registerAgenticGeneration( capabilities?: ReadonlySet; } ): AgenticGeneration { - if (input.id !== e704d5b.id) { + if (input.id !== v4.id || input.sourceCommit !== V4_SOURCE_COMMIT) { throw new AgenticError( AGENTIC_ERROR_CODE.GENERATION_UNSUPPORTED, `no contract adapter for generation "${input.id}"` @@ -81,11 +99,12 @@ export function registerAgenticGeneration( sessionValidator: getAddress(input.addresses.sessionValidator), gateway: getAddress(input.addresses.gateway), }, - capabilities: input.capabilities ?? E704D5B_CAPABILITIES, - contracts: e704d5b, + capabilities: input.capabilities ?? V4_CAPABILITIES, + contracts: v4, }; const existing = registry.findIndex( - (g) => g.network === gen.network && g.addresses.factory === gen.addresses.factory + (g) => + g.network === gen.network && g.addresses.factory === gen.addresses.factory ); if (existing >= 0) registry.splice(existing, 1); registry.push(gen); @@ -93,13 +112,32 @@ export function registerAgenticGeneration( return gen; } -/** @internal Test/harness cleanup. Restores the verified (empty) registry. */ +/** @internal Test/harness cleanup. Restores the checked Donut v4 registry. */ export function resetAgenticGenerations(): void { registry.splice(0, registry.length, ...VERIFIED_DEPLOYMENTS); verifiedWiring.clear(); } -export function generationsFor(network: PUSH_NETWORK): readonly AgenticGeneration[] { +/** Grant compatibility check; the unrestricted owner door does not consult URP. */ +export async function verifyPolicyVersion( + reader: ChainReader, + gen: AgenticGeneration +): Promise { + const version = await reader.readContract({ + address: gen.addresses.rulesPolicy, + abi: gen.contracts.abis.policy, + functionName: 'version', + }); + if (version !== '3.1.0') + throw new AgenticError( + AGENTIC_ERROR_CODE.GENERATION_UNSUPPORTED, + `URP version ${String(version)} is not supported by the v4 adapter` + ); +} + +export function generationsFor( + network: PUSH_NETWORK +): readonly AgenticGeneration[] { return registry.filter((g) => g.network === network); } @@ -112,7 +150,7 @@ export function currentGeneration(network: PUSH_NETWORK): AgenticGeneration { AGENTIC_ERROR_CODE.GENERATION_UNSUPPORTED, `no verified AGW deployment is registered for ${network}`, { - hint: 'AGW support needs a verified compatible deployment manifest (A07). Historical Donut AGW addresses use a different, unsupported ABI.', + hint: 'AGW v4 is configured on Donut only; this Push network has no registered v4 deployment.', details: { network, assumption: 'A07' }, } ); @@ -121,15 +159,28 @@ export function currentGeneration(network: PUSH_NETWORK): AgenticGeneration { } /** Generation infrastructure a native rule may not target (the wallet itself is added per call). */ -export function forbiddenTargets(gen: AgenticGeneration, wallet?: Address): Address[] { +export function forbiddenTargets( + gen: AgenticGeneration, + wallet?: Address +): Address[] { const a = gen.addresses; - return [a.factory, a.sessionEngine, a.rulesPolicy, a.sessionValidator, a.gateway, ...(wallet ? [wallet] : [])]; + return [ + a.factory, + a.sessionEngine, + a.rulesPolicy, + a.sessionValidator, + a.gateway, + ...(wallet ? [wallet] : []), + ]; } const verifiedWiring = new Map>(); /** Confirms the factory still points at the registered implementation (cached per generation). */ -export function verifyFactoryWiring(reader: ChainReader, gen: AgenticGeneration): Promise { +export function verifyFactoryWiring( + reader: ChainReader, + gen: AgenticGeneration +): Promise { const key = `${gen.network}:${gen.addresses.factory}:${gen.addresses.walletImplementation}`; let p = verifiedWiring.get(key); if (!p) { @@ -170,7 +221,9 @@ export async function resolveWalletGeneration( throw new AgenticError( AGENTIC_ERROR_CODE.WALLET_NOT_DEPLOYED, `no contract is deployed at ${wallet}`, - { hint: 'Deploy it with client.agentic.create, or check the address and network.' } + { + hint: 'Deploy it with client.agentic.create, or check the address and network.', + } ); } let factory: Address; @@ -178,7 +231,7 @@ export async function resolveWalletGeneration( factory = getAddress( (await reader.readContract({ address: wallet, - abi: e704d5b.abis.wallet, + abi: v4.abis.wallet, functionName: 'factory', })) as Address ); @@ -210,9 +263,20 @@ export async function resolveWalletGeneration( ); } const [engine, policy, validator, gateway, accountId] = await Promise.all( - (['SESSION_ENGINE', 'RULES_POLICY', 'SESSION_VALIDATOR', 'UNIVERSAL_GATEWAY_PC', 'accountId'] as const).map( - (functionName) => - reader.readContract({ address: wallet, abi: gen.contracts.abis.wallet, functionName }) + ( + [ + 'SESSION_ENGINE', + 'RULES_POLICY', + 'SESSION_VALIDATOR', + 'UNIVERSAL_GATEWAY_PC', + 'accountId', + ] as const + ).map((functionName) => + reader.readContract({ + address: wallet, + abi: gen.contracts.abis.wallet, + functionName, + }) ) ); const mismatch = diff --git a/packages/core/src/lib/agentic/errors.ts b/packages/core/src/lib/agentic/errors.ts index 1c7280b9..d66055dc 100644 --- a/packages/core/src/lib/agentic/errors.ts +++ b/packages/core/src/lib/agentic/errors.ts @@ -11,7 +11,7 @@ import { export const AGENTIC_ERROR_CODE = { // create / rule validation (spec 3.f) AGENT_IS_OWNER: 'AGENT_IS_OWNER', - DUPLICATE_RULE: 'DUPLICATE_RULE', + AMBIGUOUS_RULE: 'AMBIGUOUS_RULE', TARGET_NOT_ON_RULE_CHAIN: 'TARGET_NOT_ON_RULE_CHAIN', ASSET_CHAIN_MISMATCH: 'ASSET_CHAIN_MISMATCH', // initialize with agenticWallet (spec 3.f) diff --git a/packages/core/src/lib/agentic/execution/outbound.ts b/packages/core/src/lib/agentic/execution/outbound.ts index c4ac283e..479b9ff2 100644 --- a/packages/core/src/lib/agentic/execution/outbound.ts +++ b/packages/core/src/lib/agentic/execution/outbound.ts @@ -10,17 +10,24 @@ import { CHAIN, VM } from '../../constants/enums'; import { CHAIN_INFO } from '../../constants/chain'; import type { MoveableToken } from '../../constants/tokens'; import { ERC20_EVM, UNIVERSAL_GATEWAY_PC } from '../../constants/abi'; -import type { UniversalExecuteParams, UniversalOutboundTxRequest } from '../../orchestrator/orchestrator.types'; +import type { + UniversalExecuteParams, + UniversalOutboundTxRequest, +} from '../../orchestrator/orchestrator.types'; import { isPC20Reference } from '../../orchestrator/orchestrator.types'; import { resolveR2DestinationFundsToken } from '../../orchestrator/internals/route-handlers'; import { AgenticCapability, requireCapability } from '../capabilities'; import type { AgenticGeneration } from '../deployments'; -import type { Call } from '../contracts/e704d5b'; -import { UEA_MULTICALL_PREFIX } from '../contracts/e704d5b'; -import { AGENTIC_ERROR_CODE, AgenticError, capabilityUnavailable } from '../errors'; +import type { Call } from '../contracts/v4'; +import { UEA_MULTICALL_PREFIX } from '../contracts/v4'; +import { + AGENTIC_ERROR_CODE, + AgenticError, + capabilityUnavailable, +} from '../errors'; import type { AgenticRuntime } from '../runtime'; -/** URP MAX_ACTIONS_PER_REQUEST at e704d5b. */ +/** URP MAX_ACTIONS_PER_REQUEST at v4. */ export const MAX_DESTINATION_CALLS = 10; const MULTICALL_TUPLE = [ @@ -71,19 +78,28 @@ export function destinationCalls( ): DestinationCall[] { const target = getAddress((params.to as { address: string }).address); if (Array.isArray(params.data)) { - return params.data.map((c) => ({ to: getAddress(c.to), value: c.value ?? BigInt(0), data: c.data })); + return params.data.map((c) => ({ + to: getAddress(c.to), + value: c.value ?? BigInt(0), + data: c.data, + })); } const amount = params.funds?.amount ?? BigInt(0); const token = ctx.fundsToken; const erc20 = amount > BigInt(0) && token && token.mechanism !== 'native'; - const nativeFunds = amount > BigInt(0) && token?.mechanism === 'native' ? amount : BigInt(0); + const nativeFunds = + amount > BigInt(0) && token?.mechanism === 'native' ? amount : BigInt(0); const value = params.value ?? BigInt(0); const calls: DestinationCall[] = []; if (erc20) { calls.push({ to: getAddress((token as MoveableToken).address), value: BigInt(0), - data: encodeFunctionData({ abi: ERC20_EVM, functionName: 'transfer', args: [target, amount] }), + data: encodeFunctionData({ + abi: ERC20_EVM, + functionName: 'transfer', + args: [target, amount], + }), }); } const data = params.data && params.data !== '0x' ? params.data : undefined; @@ -112,14 +128,17 @@ export async function composeOutbound( gen: AgenticGeneration, wallet: Address, params: UniversalExecuteParams, - opts: { ruleAsset?: Address; door: 'owner' | 'agent' } + opts: { ruleAssets?: readonly Address[]; door: 'owner' | 'agent' } ): Promise { requireCapability(gen.capabilities, AgenticCapability.UNIVERSAL_EVM_OUTBOUND); const target = params.to as { address: string; chain: CHAIN }; const chain = target.chain; const info = CHAIN_INFO[chain]; if (!info) { - throw new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, `unknown destination chain ${String(chain)}`); + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + `unknown destination chain ${String(chain)}` + ); } if (info.vm !== VM.EVM) { throw capabilityUnavailable( @@ -129,33 +148,51 @@ export async function composeOutbound( } const funds = params.funds; if (funds && isPC20Reference(funds.token)) { - throw capabilityUnavailable('pc20Outbound', 'PC20 tokens are not supported through an agentic wallet'); + throw capabilityUnavailable( + 'pc20Outbound', + 'PC20 tokens are not supported through an agentic wallet' + ); } // An omitted funds.token means the destination chain's native token, as in Route 2. const fundsToken: MoveableToken | undefined = funds?.amount ? funds.token - ? resolveR2DestinationFundsToken(funds.token as MoveableToken, chain, runtime.network) - : { symbol: 'native', decimals: 18, address: '0x0000000000000000000000000000000000000000', mechanism: 'native' } + ? resolveR2DestinationFundsToken( + funds.token as MoveableToken, + chain, + runtime.network + ) + : { + symbol: 'native', + decimals: 18, + address: '0x0000000000000000000000000000000000000000', + mechanism: 'native', + } : undefined; // Burn token and amount, as Route 2 sizes them for an ordinary account. let token: Address; let amount = BigInt(0); - if (funds?.amount) { - token = runtime.resolvePrc20(funds.token as MoveableToken | undefined, chain); + if (funds) { + token = runtime.resolvePrc20( + funds.token as MoveableToken | undefined, + chain + ); amount = funds.amount; } else if ((params.value ?? BigInt(0)) > BigInt(0)) { token = runtime.resolvePrc20(undefined, chain); amount = params.value as bigint; - } else if (opts.ruleAsset) { - token = getAddress(opts.ruleAsset); + } else if (opts.ruleAssets?.length) { + token = getAddress(opts.ruleAssets[0]); } else { token = runtime.resolvePrc20(undefined, chain); } - if (opts.ruleAsset && getAddress(opts.ruleAsset) !== token) { + if ( + opts.ruleAssets && + !opts.ruleAssets.some((a) => getAddress(a) === token) + ) { throw new AgenticError( AGENTIC_ERROR_CODE.RULE_LIMIT_EXCEEDED, - `the selected rule only permits asset ${opts.ruleAsset}, not ${token}` + `the selected rule does not list asset ${token}` ); } @@ -166,7 +203,9 @@ export async function composeOutbound( throw new AgenticError( AGENTIC_ERROR_CODE.INVALID_RULE, 'this outbound carries no destination call; parking funds in the wallet’s destination account is not supported', - { hint: 'Name a recipient other than the wallet’s own destination account, or add calldata.' } + { + hint: 'Name a recipient other than the wallet’s own destination account, or add calldata.', + } ); } if (calls.length > MAX_DESTINATION_CALLS) { @@ -181,12 +220,18 @@ export async function composeOutbound( throw new AgenticError( AGENTIC_ERROR_CODE.INVALID_RULE, `destination call ${bare} has no function selector; the rules policy only admits allow-listed calls`, - { hint: 'A value-only destination transfer is not representable in an agent rule.' } + { + hint: 'A value-only destination transfer is not representable in an agent rule.', + } ); } } - const quote = await runtime.quoteOutbound(token, params.gasLimit ?? BigInt(0), chain); + const quote = await runtime.quoteOutbound( + token, + params.gasLimit ?? BigInt(0), + chain + ); if (quote.nativeValueForGas <= BigInt(0)) { throw new AgenticError( AGENTIC_ERROR_CODE.INVALID_RULE, @@ -195,7 +240,10 @@ export async function composeOutbound( } const maxPCForGas = quote.nativeValueForGas; const value = quote.protocolFee + maxPCForGas; - const payload = concat([UEA_MULTICALL_PREFIX, encodeAbiParameters(MULTICALL_TUPLE, [calls])]); + const payload = concat([ + UEA_MULTICALL_PREFIX, + encodeAbiParameters(MULTICALL_TUPLE, [calls]), + ]); const request: UniversalOutboundTxRequest = { recipient: '0x', token, diff --git a/packages/core/src/lib/agentic/execution/send.ts b/packages/core/src/lib/agentic/execution/send.ts index 0972f385..88dfb978 100644 --- a/packages/core/src/lib/agentic/execution/send.ts +++ b/packages/core/src/lib/agentic/execution/send.ts @@ -10,14 +10,21 @@ import type { UniversalTxResponse, } from '../../orchestrator/orchestrator.types'; import { isChainTarget } from '../../orchestrator/route-detector'; -import { getPushChainForNetwork, isPushChain } from '../../orchestrator/internals/helpers'; +import { + getPushChainForNetwork, + isPushChain, +} from '../../orchestrator/internals/helpers'; import { AgenticCapability, requireCapability } from '../capabilities'; import type { AgenticExecutionContext } from '../context'; -import type { Call, UniversalConfigReadE704d5b } from '../contracts/e704d5b'; -import { SEND_OUTBOUND_SELECTOR } from '../contracts/e704d5b'; +import type { Call, UniversalConfigRead } from '../contracts/v4'; +import { SEND_OUTBOUND_SELECTOR } from '../contracts/v4'; import { actionId, configId } from '../codec/ids'; import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; -import { assertCanSign, emitAgentic, wrapSendError } from '../management/common'; +import { + assertCanSign, + emitAgentic, + wrapSendError, +} from '../management/common'; import { selectRuleForSend } from '../reads/rules'; import { Snapshot } from '../reads/snapshot'; import { adaptAgenticResponse, outboundResponseCall } from '../response'; @@ -34,9 +41,11 @@ const DEFAULT_GAS_ESTIMATE = BigInt(1e7); /** Signer-level fields that legitimately carry over to the wrapped Push tx. */ function signerFields(p: UniversalExecuteParams): Partial { const out: Partial = {}; - if (p.gasLimit !== undefined && !isChainTarget(p.to)) out.gasLimit = p.gasLimit; + if (p.gasLimit !== undefined && !isChainTarget(p.to)) + out.gasLimit = p.gasLimit; if (p.maxFeePerGas !== undefined) out.maxFeePerGas = p.maxFeePerGas; - if (p.maxPriorityFeePerGas !== undefined) out.maxPriorityFeePerGas = p.maxPriorityFeePerGas; + if (p.maxPriorityFeePerGas !== undefined) + out.maxPriorityFeePerGas = p.maxPriorityFeePerGas; if (p.nonce !== undefined) out.nonce = p.nonce; if (p.deadline !== undefined) out.deadline = p.deadline; if (p.feeLockTxHash !== undefined) out.feeLockTxHash = p.feeLockTxHash; @@ -50,18 +59,23 @@ function signerFields(p: UniversalExecuteParams): Partial { * Mirrors R1's fee-lock condition so an underfunded UEA fails loudly here * instead of silently locking origin funds on every action. */ -async function enforceSignerGas(runtime: AgenticRuntime, gasLimit: bigint | undefined): Promise { +async function enforceSignerGas( + runtime: AgenticRuntime, + gasLimit: bigint | undefined +): Promise { if (runtime.signerIsPushNative()) return; if (!(await runtime.signerAccountDeployed())) return; - const [gasPrice, balance] = await Promise.all([runtime.getGasPrice(), runtime.signerBalance()]); + const [gasPrice, balance] = await Promise.all([ + runtime.getGasPrice(), + runtime.signerBalance(), + ]); const required = (gasLimit ?? DEFAULT_GAS_ESTIMATE) * gasPrice; if (balance < required) { throw new AgenticError( AGENTIC_ERROR_CODE.AGENT_GAS_INSUFFICIENT, `the signer's UEA ${runtime.signerPushAccount()} holds ${balance} PC wei but needs ~${required} for Push gas`, { - hint: - "The wallet's PC pays outbound fees, not the signer's gas. Top up the signer's UEA (PushChain.utils.account.deriveExecutorAccount) from a client without agenticWallet.", + hint: "The wallet's PC pays outbound fees, not the signer's gas. Top up the signer's UEA (PushChain.utils.account.deriveExecutorAccount) from a client without agenticWallet.", details: { required, balance }, } ); @@ -73,7 +87,10 @@ async function enforceSignerGas(runtime: AgenticRuntime, gasLimit: bigint | unde * a bare address (core's route detector treats it the same way). A ChainTarget * naming a different Push network is refused rather than routed outbound. */ -function normalizePushDestination(p: UniversalExecuteParams, runtime: AgenticRuntime): UniversalExecuteParams { +function normalizePushDestination( + p: UniversalExecuteParams, + runtime: AgenticRuntime +): UniversalExecuteParams { if (!isChainTarget(p.to)) return p; const chain = p.to.chain; if (chain === getPushChainForNetwork(runtime.network)) { @@ -90,7 +107,11 @@ function normalizePushDestination(p: UniversalExecuteParams, runtime: AgenticRun function toCalls(params: UniversalExecuteParams): Call[] { if (Array.isArray(params.data)) { - return params.data.map((c) => ({ target: getAddress(c.to), value: c.value ?? BigInt(0), data: c.data })); + return params.data.map((c) => ({ + target: getAddress(c.to), + value: c.value ?? BigInt(0), + data: c.data, + })); } return [ { @@ -115,17 +136,22 @@ export async function agenticSend( assertCanSign(runtime, 'sendTransaction'); guardAgenticSendParams(params); const p = normalizePushDestination(params as UniversalExecuteParams, runtime); - const hook: AgenticProgressHook | undefined = options?.progressHook ?? p.progressHook; + const hook: AgenticProgressHook | undefined = + options?.progressHook ?? p.progressHook; const gen = actx.generation; const wallet = actx.wallet; const outbound = isChainTarget(p.to); - const destination = outbound ? (p.to as { chain: string }).chain : runtime.pushChainNamespace; + const destination = outbound + ? (p.to as { chain: string }).chain + : runtime.pushChainNamespace; if (!outbound && p.funds) { throw new AgenticError( AGENTIC_ERROR_CODE.NOT_ALLOWED_IN_AGENTIC_MODE, - '`funds` on a Push-chain send would bridge from the signer; it does not move the wallet\'s tokens', - { hint: "Transfer the wallet's PRC20 with a token transfer call in `data`." } + "`funds` on a Push-chain send would bridge from the signer; it does not move the wallet's tokens", + { + hint: "Transfer the wallet's PRC20 with a token transfer call in `data`.", + } ); } @@ -146,16 +172,30 @@ export async function agenticSend( if (!outbound) { const calls = toCalls(p); - if (calls.length === 0) throw new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, 'an empty call array cannot execute'); + if (calls.length === 0) + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'an empty call array cannot execute' + ); if (actx.door === 'owner') { wrappedData = gen.contracts.encodeExecute(calls); } else { const snap = await Snapshot.at(runtime.reader); - const rule = await selectRuleForSend(snap, gen, wallet, actx.signerPushAccount, destination); + const rule = await selectRuleForSend( + snap, + gen, + wallet, + actx.signerPushAccount, + destination + ); rulesId = rule.rulesId as AgenticHex; wrappedData = gen.contracts.encodeExecuteAsAgent(rule.rulesId, calls[0]); if (calls.length > 1) { - agentBatch = calls.map((call) => ({ to: wallet, value: BigInt(0), data: gen.contracts.encodeExecuteAsAgent(rule.rulesId, call) })); + agentBatch = calls.map((call) => ({ + to: wallet, + value: BigInt(0), + data: gen.contracts.encodeExecuteAsAgent(rule.rulesId, call), + })); nativeCalls = calls; } } @@ -163,15 +203,21 @@ export async function agenticSend( calls.length === 1 ? { to: calls[0].target, data: calls[0].data, value: calls[0].value } : agentBatch - ? { to: calls[0].target, data: calls[0].data, value: calls[0].value } - : { to: wallet, data: wrappedData, value: BigInt(0) }; + ? { to: calls[0].target, data: calls[0].data, value: calls[0].value } + : { to: wallet, data: wrappedData, value: BigInt(0) }; } else { - let ruleAsset: Address | undefined; - let maxPCPerCall: bigint | undefined; + let ruleAssets: readonly Address[] | undefined; + let maxGasPerCall: bigint | undefined; let expectedCEA: Address | undefined; const snap = await Snapshot.at(runtime.reader); if (actx.door === 'agent') { - const rule = await selectRuleForSend(snap, gen, wallet, actx.signerPushAccount, destination); + const rule = await selectRuleForSend( + snap, + gen, + wallet, + actx.signerPushAccount, + destination + ); if (rule.mode !== MODE_UNIVERSAL || rule.vm !== VM_EVM) { throw new AgenticError( AGENTIC_ERROR_CODE.INVALID_RULE, @@ -179,28 +225,48 @@ export async function agenticSend( ); } rulesId = rule.rulesId as AgenticHex; - const cfg = await snap.read( + const cfg = await snap.read( gen.addresses.rulesPolicy, gen.contracts.abis.policy, 'getConfig', - [configId(wallet, rule.rulesId, actionId(gen.addresses.gateway, SEND_OUTBOUND_SELECTOR)), wallet] + [ + configId( + wallet, + rule.rulesId, + actionId(gen.addresses.gateway, SEND_OUTBOUND_SELECTOR) + ), + wallet, + ] ); - ruleAsset = getAddress(cfg.asset); - maxPCPerCall = cfg.maxPCPerCall; + ruleAssets = cfg.assets.map((a) => getAddress(a.token)); + maxGasPerCall = cfg.maxGasPerCall; expectedCEA = getAddress(cfg.expectedCEA); } - const out = await composeOutbound(runtime, gen, wallet, p, { ruleAsset, door: actx.door }); + const out = await composeOutbound(runtime, gen, wallet, p, { + ruleAssets, + door: actx.door, + }); outboundChain = out.chain; meta = { route: 'UOA_TO_CEA', destinationAccount: out.destinationAccount }; const [walletPc, tokenBalance, allowance] = await Promise.all([ - runtime.reader.getBalance({ address: wallet, blockNumber: snap.blockNumber }), + runtime.reader.getBalance({ + address: wallet, + blockNumber: snap.blockNumber, + }), out.amount > BigInt(0) - ? snap.read(out.token, ERC20_EVM as unknown as readonly unknown[], 'balanceOf', [wallet]) + ? snap.read( + out.token, + ERC20_EVM as unknown as readonly unknown[], + 'balanceOf', + [wallet] + ) : Promise.resolve(BigInt(0)), - snap.read(out.token, ERC20_EVM as unknown as readonly unknown[], 'allowance', [ - wallet, - gen.addresses.gateway, - ]), + snap.read( + out.token, + ERC20_EVM as unknown as readonly unknown[], + 'allowance', + [wallet, gen.addresses.gateway] + ), ]); if (walletPc < out.value) { throw new AgenticError( @@ -231,36 +297,70 @@ export async function agenticSend( throw new AgenticError( AGENTIC_ERROR_CODE.INCONSISTENT_READ, `rule ${rulesId} committed destination account ${expectedCEA}, but the wallet's account on ${out.chain} now derives to ${out.destinationAccount}`, - { hint: 'Destination-account derivation drift (obligation 13). The owner must regrant the rule.' } + { + hint: 'Destination-account derivation drift (obligation 13). The owner must regrant the rule.', + } ); } - if (maxPCPerCall !== undefined && out.value > maxPCPerCall) { + if (maxGasPerCall !== undefined && out.value > maxGasPerCall) { throw new AgenticError( AGENTIC_ERROR_CODE.RULE_LIMIT_EXCEEDED, - `this outbound needs ${out.value} PC wei but the rule caps the wallet's PC per call at ${maxPCPerCall}` + `this outbound needs ${out.value} PC wei but the rule caps the wallet's PC per call at ${maxGasPerCall}` ); } - wrappedData = gen.contracts.encodeExecuteAsAgent(rulesId as Hex, out.gatewayCall); + wrappedData = gen.contracts.encodeExecuteAsAgent( + rulesId as Hex, + out.gatewayCall + ); } else { wrappedData = gen.contracts.encodeExecute([out.gatewayCall]); } destinationCalls = out.destinationCalls; logical = outboundResponseCall(destinationCalls, { - to: out.gatewayCall.target, data: out.gatewayCall.data, value: out.gatewayCall.value, + to: out.gatewayCall.target, + data: out.gatewayCall.data, + value: out.gatewayCall.value, }); } await enforceSignerGas(runtime, signerFields(p).gasLimit); - emitAgentic(runtime, hook, PROGRESS_HOOK.AGENTIC_TX_107, rulesId, outboundChain ?? destination, actx.door); + emitAgentic( + runtime, + hook, + PROGRESS_HOOK.AGENTIC_TX_107, + rulesId, + outboundChain ?? destination, + actx.door + ); let resp: UniversalTxResponse; try { const sendOptions = hook ? { ...options, progressHook: hook } : options; resp = agentBatch - ? await runtime.executeAtomicBatch({ ...signerFields(p), to: wallet, value: BigInt(0), data: agentBatch }, sendOptions) - : await runtime.execute({ ...signerFields(p), to: wallet, value: BigInt(0), data: wrappedData }, sendOptions); + ? await runtime.executeAtomicBatch( + { + ...signerFields(p), + to: wallet, + value: BigInt(0), + data: agentBatch, + }, + sendOptions + ) + : await runtime.execute( + { + ...signerFields(p), + to: wallet, + value: BigInt(0), + data: wrappedData, + }, + sendOptions + ); } catch (err) { - const wrapped = wrapSendError(err) as { code?: string; message?: string; decodedError?: unknown }; + const wrapped = wrapSendError(err) as { + code?: string; + message?: string; + decodedError?: unknown; + }; emitAgentic( runtime, hook, @@ -279,11 +379,25 @@ export async function agenticSend( chainNamespace: outboundChain ?? destination, destinationAccount: meta.destinationAccount as AgenticHex | undefined, destinationCalls, - ...(nativeCalls ? { nativeCalls: nativeCalls.map((c) => ({ to: c.target, data: c.data, value: c.value })) } : {}), + ...(nativeCalls + ? { + nativeCalls: nativeCalls.map((c) => ({ + to: c.target, + data: c.data, + value: c.value, + })), + } + : {}), logical, route: meta.route, chain: outboundChain, }); - emitAgentic(runtime, hook, PROGRESS_HOOK.AGENTIC_TX_199_01, 'sendTransaction', resp.hash); + emitAgentic( + runtime, + hook, + PROGRESS_HOOK.AGENTIC_TX_199_01, + 'sendTransaction', + resp.hash + ); return resp; } diff --git a/packages/core/src/lib/agentic/execution/svm-outbound.ts b/packages/core/src/lib/agentic/execution/svm-outbound.ts new file mode 100644 index 00000000..d0435b9c --- /dev/null +++ b/packages/core/src/lib/agentic/execution/svm-outbound.ts @@ -0,0 +1,72 @@ +/** Internal SVM action builder. No public Rule/export or capability enablement. */ +import { encodeFunctionData, getAddress, type Address, type Hex } from 'viem'; +import { UNIVERSAL_GATEWAY_PC } from '../../constants/abi'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; +import type { Call, SvmConfigRead } from '../contracts/v4'; +import { UINT256_MAX } from '../codec/defaults'; +import { UINT64_MAX } from '../codec/svm-terms'; +import { validateAgwSvmPayload } from './svm-payload'; + +export interface SvmOutboundInput { + wallet: Address; + gateway: Address; + token: Address; + amount: bigint; + recipient: Hex; + payload: Hex; + gasLimit: bigint; + protocolFee: bigint; + maxPCForGas: bigint; +} +export function composeAgwSvmAction( + input: SvmOutboundInput, + config: SvmConfigRead, + nowSeconds: number +): Call { + function fail(name: string): never { + throw new AgenticError(AGENTIC_ERROR_CODE.RULE_LIMIT_EXCEEDED, name, { + details: { contractError: name }, + }); + } + if (!config.initialized) fail('NotInitialized'); + if (nowSeconds > config.validUntil) fail('RulesExpired'); + for (const [name, value] of Object.entries({ + amount: input.amount, + gasLimit: input.gasLimit, + protocolFee: input.protocolFee, + maxPCForGas: input.maxPCForGas, + })) { + if (typeof value !== 'bigint' || value < BigInt(0) || value > UINT256_MAX) + fail(`${name}OutOfRange`); + } + const token = getAddress(input.token), + cap = config.assets.find((a) => getAddress(a.token) === token); + if (!cap) fail('AssetNotAllowed'); + if (input.amount > UINT64_MAX) fail('AmountExceedsU64'); + if (input.amount > cap.maxPerCall) fail('AmountExceedsCap'); + if (cap.spent + input.amount > cap.maxTotal) fail('TotalSpendCapExceeded'); + const value = input.protocolFee + input.maxPCForGas; + if (value > UINT256_MAX || value > config.maxGasPerCall) + fail('PCValueExceedsCap'); + if (!input.maxPCForGas) fail('UncappedGasSwapRejected'); + validateAgwSvmPayload(config, input.recipient, input.payload); + const request = { + recipient: input.recipient, + token, + amount: input.amount, + gasLimit: input.gasLimit, + gasPrice: BigInt(0), + maxPCForGas: input.maxPCForGas, + payload: input.payload, + revertRecipient: getAddress(input.wallet), + }; + return { + target: getAddress(input.gateway), + value, + data: encodeFunctionData({ + abi: UNIVERSAL_GATEWAY_PC, + functionName: 'sendUniversalTxOutbound', + args: [request], + }), + }; +} diff --git a/packages/core/src/lib/agentic/execution/svm-payload.ts b/packages/core/src/lib/agentic/execution/svm-payload.ts new file mode 100644 index 00000000..d69fa4cc --- /dev/null +++ b/packages/core/src/lib/agentic/execution/svm-payload.ts @@ -0,0 +1,146 @@ +/** Internal parser/validator for the deployed S12–S18 grammar. Public SVM sends remain gated. */ +import { bytesToHex, hexToBytes, type Hex } from 'viem'; +import { encodeSvmExecutePayload } from '../../orchestrator/payload-builders'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; +import { + exactHex, + isForbiddenSvmProgram, + SVM_LIMITS, + SvmDataPinMode, + type SvmTermsWire, +} from '../codec/svm-terms'; + +export interface SvmPayloadAccount { + pubkey: Hex; + isWritable: boolean; +} +export interface ParsedSvmPayload { + program: Hex; + accounts: (SvmPayloadAccount & { writableFlag: number })[]; + instructionData: Uint8Array; +} +function fail(name: string): never { + throw new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, name, { + details: { contractError: name }, + }); +} +export function parseAgwSvmPayload(payload: Hex): ParsedSvmPayload { + if (!/^0x(?:[0-9a-fA-F]{2})*$/.test(payload)) fail('MalformedSvmPayload'); + const bytes = hexToBytes(payload); + if (!bytes.length) fail('SvmPayloadEmpty'); + if (bytes.length < 41) fail('MalformedSvmPayload'); + const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength), + count = view.getUint32(0, false); + if (count > SVM_LIMITS.accounts) fail('SvmAccountsOutOfRange'); + const lenOffset = 4 + count * 33; + if (bytes.length < lenOffset + 4) fail('MalformedSvmPayload'); + const length = view.getUint32(lenOffset, false); + if (length > SVM_LIMITS.ixData) fail('SvmIxDataTooLong'); + const dataOffset = lenOffset + 4; + if (bytes.length !== dataOffset + length + 33) fail('MalformedSvmPayload'); + if (bytes[dataOffset + length] !== 2) fail('SvmInstructionNotExecute'); + const accounts = Array.from({ length: count }, (_, i) => { + const offset = 4 + i * 33, + writableFlag = bytes[offset + 32]; + // URP does not judge this flag. Preserve the raw value for diagnostics. + return { + pubkey: bytesToHex(bytes.slice(offset, offset + 32)), + isWritable: writableFlag === 1, + writableFlag, + }; + }); + return { + program: bytesToHex(bytes.slice(dataOffset + length + 1)), + accounts, + instructionData: bytes.slice(dataOffset, dataOffset + length), + }; +} +export function encodeAgwSvmPayload( + program: Hex, + accounts: readonly SvmPayloadAccount[], + instructionData: Uint8Array +): Hex { + exactHex(program, 32, 'target program'); + if (accounts.length > SVM_LIMITS.accounts) fail('SvmAccountsOutOfRange'); + if (instructionData.length > SVM_LIMITS.ixData) fail('SvmIxDataTooLong'); + accounts.forEach((a) => { + exactHex(a.pubkey, 32, 'account'); + if (typeof a.isWritable !== 'boolean') fail('MalformedSvmPayload'); + }); + return encodeSvmExecutePayload({ + targetProgram: program, + accounts: [...accounts], + ixData: instructionData, + instructionId: 2, + }); +} +function uintLE(data: Uint8Array): bigint { + return data.reduceRight((v, b) => (v << BigInt(8)) + BigInt(b), BigInt(0)); +} +/** Terms must have passed grant-shape validation. On-chain URP remains the enforcement authority. */ +export function validateAgwSvmPayload( + terms: SvmTermsWire, + recipient: Hex, + payload: Hex +): number { + exactHex(recipient, 32, 'recipient'); + if (BigInt(recipient) === BigInt(0)) fail('RecipientNotPubkey'); + const v = parseAgwSvmPayload(payload), + data = v.instructionData; + if (v.program.toLowerCase() !== recipient.toLowerCase()) + fail('RecipientTargetMismatch'); + if (isForbiddenSvmProgram(v.program, terms)) fail('ForbiddenTargetProgram'); + const rule = terms.programs.findIndex( + (p) => + p.program.toLowerCase() === v.program.toLowerCase() && + (p.dataless + ? data.length === 0 + : data.length >= p.discriminatorLen && + bytesToHex(data.slice(0, p.discriminatorLen)).toLowerCase() === + p.discriminator.slice(0, 2 + p.discriminatorLen * 2).toLowerCase()) + ); + if (rule < 0) fail('ProgramNotAllowed'); + const fixed = terms.programs[rule].maxAccounts; + if (fixed && fixed !== v.accounts.length) fail('SvmAccountCountMismatch'); + const pins = terms.pins.filter((p) => p.ruleIndex === rule); + for (const p of pins) { + if (p.accountIndex >= v.accounts.length) fail('SvmAccountCountBelowPin'); + if ( + v.accounts[p.accountIndex].pubkey.toLowerCase() !== + p.expected.toLowerCase() + ) + fail('SvmAccountPinMismatch'); + } + function field(fromEnd: boolean, offset: number, len: number): Uint8Array { + const start = fromEnd ? data.length - offset : offset; + if (start < 0 || start + len > data.length) fail('SvmDataTooShortForPin'); + return data.slice(start, start + len); + } + for (const p of terms.dataPins.filter((p) => p.ruleIndex === rule)) { + const a = field(p.fromEnd, p.offset, p.len); + if (p.mode === SvmDataPinMode.EQ) { + if ( + bytesToHex(a).toLowerCase() !== + p.expected.slice(0, 2 + p.len * 2).toLowerCase() + ) + fail('SvmDataPinMismatch'); + } else if (p.mode === SvmDataPinMode.GTE_LE) { + if (uintLE(a) < BigInt(p.expected)) fail('SvmDataFloorNotMet'); + } else if (p.mode === SvmDataPinMode.LTE_LE) { + if (uintLE(a) > BigInt(p.expected)) fail('SvmDataCeilingExceeded'); + } else if ( + uintLE(a) * p.den < + uintLE(field(p.fromEnd, p.offsetB, p.len)) * p.num + ) + fail('SvmDataRatioNotMet'); + } + const protectedKeys = new Set(terms.ceaAccounts.map((k) => k.toLowerCase())); + v.accounts.forEach((a, i) => { + if ( + protectedKeys.has(a.pubkey.toLowerCase()) && + !pins.some((p) => p.accountIndex === i) + ) + fail('CeaAccountAtUnpinnedIndex'); + }); + return rule; +} diff --git a/packages/core/src/lib/agentic/management/create.ts b/packages/core/src/lib/agentic/management/create.ts index a48e0e91..6ab32770 100644 --- a/packages/core/src/lib/agentic/management/create.ts +++ b/packages/core/src/lib/agentic/management/create.ts @@ -3,9 +3,9 @@ import { PROGRESS_HOOK } from '../../progress-hook/progress-hook.types'; import type { MultiCall } from '../../orchestrator/orchestrator.types'; import { PushChainBatchExecutionError } from '../../orchestrator/internals/errors'; import { AgenticCapability, requireCapability } from '../capabilities'; -import { currentGeneration, forbiddenTargets, verifyFactoryWiring } from '../deployments'; +import { currentGeneration, verifyFactoryWiring } from '../deployments'; import { deriveWallet, rulesId as computeRulesId } from '../codec/ids'; -import { prepareRules } from '../codec/rules'; +import { prepareWalletRules } from './prepare'; import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; import type { AgenticRuntime } from '../runtime'; import type { CreateOptions, CreateResult } from '../agentic.types'; @@ -39,10 +39,16 @@ export async function createWallet( ): Promise { const hook = options?.progressHook; if (typeof label !== 'string') { - throw new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, 'label must be a string'); + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'label must be a string' + ); } if (!options || !Array.isArray(options.rules)) { - throw new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, 'options.rules is required (use [] for a bare wallet)'); + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'options.rules is required (use [] for a bare wallet)' + ); } assertCanSign(runtime, 'agentic.create'); const gen = currentGeneration(runtime.network); @@ -50,16 +56,6 @@ export async function createWallet( await verifyFactoryWiring(runtime.reader, gen); const owner = runtime.signerPushAccount(); - const prepared = prepareRules(options.rules, { - owner, - pushChainNamespace: runtime.pushChainNamespace, - validator: gen.addresses.sessionValidator, - rulesPolicy: gen.addresses.rulesPolicy, - capabilities: gen.capabilities, - nowSeconds: runtime.nowSeconds(), - forbiddenTargets: forbiddenTargets(gen), - }); - const snap = await Snapshot.at(runtime.reader); const index = await walletCount(snap, gen, owner); const [predicted, deployed] = await snap.read( @@ -82,22 +78,47 @@ export async function createWallet( { details: { wallet, mirror, deployed } } ); } - const selfTarget = prepared.findIndex((p) => p.nativeTerms?.target === wallet); + const prepared = await prepareWalletRules( + runtime, + gen, + owner, + wallet, + options.rules, + snap + ); + const selfTarget = prepared.findIndex( + (p) => p.nativeTerms?.target === wallet + ); if (selfTarget >= 0) { throw new AgenticError( AGENTIC_ERROR_CODE.INVALID_RULE, `rules[${selfTarget}].target is the wallet being created; the contracts refuse it as a native target` ); } - emitAgentic(runtime, hook, PROGRESS_HOOK.AGENTIC_TX_101, wallet, Number(index), false); + emitAgentic( + runtime, + hook, + PROGRESS_HOOK.AGENTIC_TX_101, + wallet, + Number(index), + false + ); // A fresh wallet's grant nonce starts at 0 and increments per grant. const predictedIds = prepared.map((p, i) => - computeRulesId({ validator: gen.addresses.sessionValidator, agent: p.agent, grantNonce: BigInt(i) }) + computeRulesId({ + validator: gen.addresses.sessionValidator, + agent: p.agent, + grantNonce: BigInt(i), + }) ); const calls: MultiCall[] = [ // Index-bound: reverts (nothing committed) if another creation took this slot. - { to: gen.addresses.factory, value: BigInt(0), data: gen.contracts.encodeDeployWalletAt(owner, index, wallet, label) }, + { + to: gen.addresses.factory, + value: BigInt(0), + data: gen.contracts.encodeDeployWalletAt(owner, index, wallet, label), + }, ...prepared.map((p) => ({ to: wallet, value: BigInt(0), @@ -105,14 +126,24 @@ export async function createWallet( })), ]; const strategy = - calls.length === 1 ? 'single' : runtime.signerIsPushNative() ? 'push-eoa-batch' : 'uea-multicall'; + calls.length === 1 + ? 'single' + : runtime.signerIsPushNative() + ? 'push-eoa-batch' + : 'uea-multicall'; emitAgentic(runtime, hook, PROGRESS_HOOK.AGENTIC_TX_102, wallet, strategy); let tx; try { tx = await sendOwnerCalls(runtime, calls, hook); } catch (err) { - const wrapped = await createFailure(runtime, gen, wallet, Number(index), err); + const wrapped = await createFailure( + runtime, + gen, + wallet, + Number(index), + err + ); emitFailure(runtime, hook, wrapped); throw wrapped; } @@ -121,19 +152,42 @@ export async function createWallet( try { ({ logs } = await confirmedLogs(runtime, tx)); } catch (err) { - const wrapped = await createFailure(runtime, gen, wallet, Number(index), err); + const wrapped = await createFailure( + runtime, + gen, + wallet, + Number(index), + err + ); emitFailure(runtime, hook, wrapped); throw wrapped; } - const deployedEv = gen.contracts.parseWalletDeployed(logs, gen.addresses.factory); - const granted = gen.contracts.parseRulesGranted(logs, wallet).map((g) => g.rulesId); - if (deployedEv.length !== 1 || deployedEv[0].wallet !== wallet || deployedEv[0].index !== index) { + const deployedEv = gen.contracts.parseWalletDeployed( + logs, + gen.addresses.factory + ); + const granted = gen.contracts + .parseRulesGranted(logs, wallet) + .map((g) => g.rulesId); + if ( + deployedEv.length !== 1 || + deployedEv[0].wallet !== wallet || + deployedEv[0].index !== index + ) { const err = new AgenticError( AGENTIC_ERROR_CODE.INDEX_RACE, - `deployWallet produced ${deployedEv.map((d) => `${d.wallet}#${d.index}`).join(', ') || 'no wallet'}, expected ${wallet}#${index}; grants targeted ${wallet}`, + `deployWallet produced ${ + deployedEv.map((d) => `${d.wallet}#${d.index}`).join(', ') || + 'no wallet' + }, expected ${wallet}#${index}; grants targeted ${wallet}`, { hint: 'Another deployment by this owner raced this call. Inspect both wallets with client.agentic.list() before retrying.', - details: { expected: wallet, deployed: deployedEv, grantedRulesIds: granted, txHash: tx.hash }, + details: { + expected: wallet, + deployed: deployedEv, + grantedRulesIds: granted, + txHash: tx.hash, + }, } ); emitFailure(runtime, hook, err); @@ -148,13 +202,28 @@ export async function createWallet( emitFailure(runtime, hook, err); throw err; } - if (granted.length > 0) emitAgentic(runtime, hook, PROGRESS_HOOK.AGENTIC_TX_104, granted); - emitAgentic(runtime, hook, PROGRESS_HOOK.AGENTIC_TX_199_01, 'create', tx.hash); - return { wallet, index: Number(index), rulesIds: granted as `0x${string}`[], tx }; + if (granted.length > 0) + emitAgentic(runtime, hook, PROGRESS_HOOK.AGENTIC_TX_104, granted); + emitAgentic( + runtime, + hook, + PROGRESS_HOOK.AGENTIC_TX_199_01, + 'create', + tx.hash + ); + return { + wallet, + index: Number(index), + rulesIds: granted as `0x${string}`[], + tx, + }; } function sameIds(a: readonly Hex[], b: readonly Hex[]): boolean { - return a.length === b.length && a.every((x, i) => x.toLowerCase() === b[i].toLowerCase()); + return ( + a.length === b.length && + a.every((x, i) => x.toLowerCase() === b[i].toLowerCase()) + ); } const RACE_ERRORS = new Set(['IndexMismatch', 'IntentWalletMismatch']); @@ -177,16 +246,27 @@ async function createFailure( const confirmed = (batch?.transactionHashes ?? []) as Hex[]; const pending = batch?.pendingTransactionHash; const receiptUnavailable = - wrapped instanceof AgenticError && wrapped.code === AGENTIC_ERROR_CODE.RECEIPT_UNAVAILABLE; + wrapped instanceof AgenticError && + wrapped.code === AGENTIC_ERROR_CODE.RECEIPT_UNAVAILABLE; // The index-bound deploy reverted: another creation took the slot first and // nothing from this call committed. - const decodedName = (wrapped as { decodedError?: { name?: string } }).decodedError?.name; - if (confirmed.length === 0 && !pending && decodedName && RACE_ERRORS.has(decodedName)) { + const decodedName = (wrapped as { decodedError?: { name?: string } }) + .decodedError?.name; + if ( + confirmed.length === 0 && + !pending && + decodedName && + RACE_ERRORS.has(decodedName) + ) { return new AgenticError( AGENTIC_ERROR_CODE.INDEX_RACE, `wallet slot ${index} (${wallet}) was taken by a concurrent creation; nothing was committed`, - { hint: 'Retry agentic.create; it re-reads the next slot.', details: { wallet, index, committed: false }, cause: wrapped } + { + hint: 'Retry agentic.create; it re-reads the next slot.', + details: { wallet, index, committed: false }, + cause: wrapped, + } ); } if (confirmed.length === 0 && !pending && !receiptUnavailable) { @@ -207,7 +287,9 @@ async function createFailure( const deployed = gen.contracts .parseWalletDeployed(logs, gen.addresses.factory) .some((d) => d.wallet === wallet); - grantedRulesIds = gen.contracts.parseRulesGranted(logs, wallet).map((g) => g.rulesId); + grantedRulesIds = gen.contracts + .parseRulesGranted(logs, wallet) + .map((g) => g.rulesId); // A pending hash may itself be the deployment; only a confirmed deploy is certain. walletDeployed = deployed ? true : pending ? 'unknown' : false; } catch (e) { @@ -218,11 +300,13 @@ async function createFailure( walletDeployed === true ? `Wallet ${wallet} is deployed. Do not call create again; once any pending hash settles, finish with client.agentic.wallet('${wallet}').rules.add().` : walletDeployed === false - ? 'No wallet was deployed by this call; it is safe to retry.' - : 'The outcome is unknown. Do not retry create until the listed hashes are reconciled (client.agentic.list() shows deployed wallets).'; + ? 'No wallet was deployed by this call; it is safe to retry.' + : 'The outcome is unknown. Do not retry create until the listed hashes are reconciled (client.agentic.list() shows deployed wallets).'; return new AgenticError( AGENTIC_ERROR_CODE.CREATE_PARTIAL, - `agentic.create did not complete: ${(wrapped as Error)?.message ?? String(err)}`, + `agentic.create did not complete: ${ + (wrapped as Error)?.message ?? String(err) + }`, { hint, details: { @@ -232,7 +316,9 @@ async function createFailure( grantedRulesIds, confirmedHashes: confirmed, pendingHash: pending, - ...(receiptUnavailable ? { submitted: (wrapped as AgenticError).details } : {}), + ...(receiptUnavailable + ? { submitted: (wrapped as AgenticError).details } + : {}), ...(recoveryError ? { recoveryError } : {}), }, cause: wrapped, @@ -240,7 +326,11 @@ async function createFailure( ); } -function emitFailure(runtime: AgenticRuntime, hook: CreateOptions['progressHook'], err: unknown): void { +function emitFailure( + runtime: AgenticRuntime, + hook: CreateOptions['progressHook'], + err: unknown +): void { const e = err as { code?: string; message?: string; decodedError?: unknown }; emitAgentic( runtime, diff --git a/packages/core/src/lib/agentic/management/prepare.ts b/packages/core/src/lib/agentic/management/prepare.ts new file mode 100644 index 00000000..7c797d52 --- /dev/null +++ b/packages/core/src/lib/agentic/management/prepare.ts @@ -0,0 +1,132 @@ +import { getAddress, zeroAddress, type Address } from 'viem'; +import { CHAIN, VM } from '../../constants/enums'; +import { CHAIN_INFO } from '../../constants/chain'; +import { AGENTIC_DEFAULTS, withDefault } from '../codec/defaults'; +import { isUniversalRule, prepareRules } from '../codec/rules'; +import { + validateUniversalRuleShape, + type ResolvedUniversalRule, +} from '../codec/universal'; +import { + forbiddenTargets, + verifyPolicyVersion, + type AgenticGeneration, +} from '../deployments'; +import { AgenticCapability, requireCapability } from '../capabilities'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; +import type { Rule, UniversalRule } from '../agentic.types'; +import type { AgenticRuntime } from '../runtime'; +import { Snapshot } from '../reads/snapshot'; + +import { + PRC20_SOURCE_ABI, + readGasPrc20, + readOriginToken, +} from '../contracts/prc20-metadata'; + +/** Resolve wallet-dependent wire inputs without signing or mutating authority. */ +export async function prepareWalletRules( + runtime: AgenticRuntime, + gen: AgenticGeneration, + owner: Address, + wallet: Address, + rules: readonly Rule[], + snap: Snapshot +) { + if (rules.length) await verifyPolicyVersion(runtime.reader, gen); + const universal = new Map(); + for (const rule of rules) { + if (!isUniversalRule(rule)) continue; + if (rule.chainNamespace.startsWith('solana:')) + requireCapability( + gen.capabilities, + AgenticCapability.UNIVERSAL_SVM_RULES + ); + validateUniversalRuleShape(rule, runtime.nowSeconds()); + requireCapability( + gen.capabilities, + rule.chainNamespace.startsWith('solana:') + ? AgenticCapability.UNIVERSAL_SVM_RULES + : AgenticCapability.UNIVERSAL_EVM_RULES + ); + const chain = rule.chainNamespace as CHAIN; + if (CHAIN_INFO[chain]?.vm !== VM.EVM) + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + `unsupported EVM rule chain ${chain}` + ); + const { cea } = await runtime.resolveCEA(wallet, chain); + const assets = rule.assets.length + ? rule.assets.map((a) => ({ + token: + typeof a.token === 'string' && getAddress(a.token) === zeroAddress + ? undefined + : a.token, + maxPerCall: a.maxPerCall, + maxTotal: withDefault( + a.maxTotal, + AGENTIC_DEFAULTS.universal.assetMaxTotal + ), + })) + : [{ token: undefined, maxPerCall: BigInt(0), maxTotal: BigInt(0) }]; + const resolved = []; + for (const asset of assets) { + const token = + asset.token === undefined + ? await readGasPrc20(snap, chain) + : runtime.resolvePrc20(asset.token, chain); + if (token === zeroAddress) + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + `no gas PRC20 registered for ${chain}` + ); + const namespace = await snap.read( + token, + PRC20_SOURCE_ABI, + 'SOURCE_CHAIN_NAMESPACE' + ); + if (namespace !== chain) + throw new AgenticError( + AGENTIC_ERROR_CODE.ASSET_CHAIN_MISMATCH, + `PRC20 ${token} belongs to ${namespace}, not ${chain}` + ); + if (asset.token !== undefined) { + const expected = + typeof asset.token === 'string' + ? getAddress(asset.token) + : getAddress(asset.token.address); + if (expected === zeroAddress) { + if ((await readGasPrc20(snap, chain)) !== getAddress(token)) + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'resolved token is not the registered native gas token' + ); + } else { + const source = await readOriginToken(snap, token, chain); + if (source !== expected) + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + `PRC20 ${token} represents ${source}, not requested token ${expected}` + ); + } + } + resolved.push({ + token: getAddress(token), + maxPerCall: asset.maxPerCall, + maxTotal: asset.maxTotal, + }); + } + universal.set(rule, { expectedCEA: getAddress(cea), assets: resolved }); + } + return prepareRules(rules, { + owner, + pushChainNamespace: runtime.pushChainNamespace, + validator: gen.addresses.sessionValidator, + rulesPolicy: gen.addresses.rulesPolicy, + gateway: gen.addresses.gateway, + capabilities: gen.capabilities, + nowSeconds: runtime.nowSeconds(), + forbiddenTargets: forbiddenTargets(gen, wallet), + universal, + }); +} diff --git a/packages/core/src/lib/agentic/management/rules-write.ts b/packages/core/src/lib/agentic/management/rules-write.ts index 2f1a01b2..4ff2e792 100644 --- a/packages/core/src/lib/agentic/management/rules-write.ts +++ b/packages/core/src/lib/agentic/management/rules-write.ts @@ -1,14 +1,21 @@ import type { Address, Hex } from 'viem'; import { PROGRESS_HOOK } from '../../progress-hook/progress-hook.types'; -import type { MultiCall, UniversalTxResponse } from '../../orchestrator/orchestrator.types'; +import type { + MultiCall, + UniversalTxResponse, +} from '../../orchestrator/orchestrator.types'; import { AgenticCapability, requireCapability } from '../capabilities'; -import { forbiddenTargets, type AgenticGeneration } from '../deployments'; +import { type AgenticGeneration } from '../deployments'; import { rulesId as computeRulesId } from '../codec/ids'; -import { isUniversalRule, prepareRules } from '../codec/rules'; +import { prepareWalletRules } from './prepare'; import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; import type { AgenticRuntime } from '../runtime'; import type { AgenticHex, AgenticProgressHook, Rule } from '../agentic.types'; -import { chainFromHash, readActiveRules, readNativeSpend, type ActiveRule } from '../reads/rules'; +import { + readActiveRules, + readNativeSpend, + readUniversalSpend, +} from '../reads/rules'; import { Snapshot } from '../reads/snapshot'; import { assertCanSign, @@ -21,28 +28,6 @@ import { const MODE_NATIVE = 1; -function existingPairs(active: readonly ActiveRule[], pushChainNamespace: string, exclude: Set) { - return active - .filter((r) => !exclude.has(r.rulesId.toLowerCase())) - .map((r) => ({ - agent: r.agent, - rulesId: r.rulesId, - chainNamespace: chainFromHash(r.chainHash, pushChainNamespace) ?? `hash:${r.chainHash}`, - })); -} - -function encodeContext(runtime: AgenticRuntime, gen: AgenticGeneration, owner: Address, wallet: Address) { - return { - owner, - pushChainNamespace: runtime.pushChainNamespace, - validator: gen.addresses.sessionValidator, - rulesPolicy: gen.addresses.rulesPolicy, - capabilities: gen.capabilities, - nowSeconds: runtime.nowSeconds(), - forbiddenTargets: forbiddenTargets(gen, wallet), - }; -} - async function finish( runtime: AgenticRuntime, hook: AgenticProgressHook | undefined, @@ -51,10 +36,20 @@ async function finish( ): Promise { try { const result = await run(); - emitAgentic(runtime, hook, PROGRESS_HOOK.AGENTIC_TX_199_01, operation, result.tx.hash); + emitAgentic( + runtime, + hook, + PROGRESS_HOOK.AGENTIC_TX_199_01, + operation, + result.tx.hash + ); return result; } catch (err) { - const wrapped = wrapSendError(err) as { code?: string; message?: string; decodedError?: unknown }; + const wrapped = wrapSendError(err) as { + code?: string; + message?: string; + decodedError?: unknown; + }; emitAgentic( runtime, hook, @@ -78,20 +73,30 @@ export async function addRules( ): Promise<{ rulesIds: AgenticHex[]; tx: UniversalTxResponse }> { assertCanSign(runtime, 'rules.add'); if (!Array.isArray(rules) || rules.length === 0) { - throw new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, 'rules.add needs at least one rule'); + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'rules.add needs at least one rule' + ); } const snap = await Snapshot.at(runtime.reader); const owner = await assertOwner(runtime, gen, wallet, snap); - const active = await readActiveRules(snap, gen, wallet); - const prepared = prepareRules(rules, { - ...encodeContext(runtime, gen, owner, wallet), - existing: existingPairs(active, runtime.pushChainNamespace, new Set()), - }); + const prepared = await prepareWalletRules( + runtime, + gen, + owner, + wallet, + rules, + snap + ); const nonce = BigInt( await snap.read(wallet, gen.contracts.abis.wallet, 'grantNonce') ); const predicted = prepared.map((p, i) => - computeRulesId({ validator: gen.addresses.sessionValidator, agent: p.agent, grantNonce: nonce + BigInt(i) }) + computeRulesId({ + validator: gen.addresses.sessionValidator, + agent: p.agent, + grantNonce: nonce + BigInt(i), + }) ); // One rule: a direct owner grant (one RULES_GRANTED tick). Several: one // owner `execute` batch of self-calls, so the grants are atomic and need a @@ -105,13 +110,17 @@ export async function addRules( { to: wallet, value: BigInt(0), - data: gen.contracts.encodeExecute(grants.map((data) => ({ target: wallet, value: BigInt(0), data }))), + data: gen.contracts.encodeExecute( + grants.map((data) => ({ target: wallet, value: BigInt(0), data })) + ), }, ]; return finish(runtime, hook, 'rules.add', async () => { const tx = await sendOwnerCalls(runtime, calls, hook); const { logs } = await confirmedLogs(runtime, tx); - const granted = gen.contracts.parseRulesGranted(logs, wallet).map((g) => g.rulesId as AgenticHex); + const granted = gen.contracts + .parseRulesGranted(logs, wallet) + .map((g) => g.rulesId as AgenticHex); if (!sameIds(granted, predicted)) { throw new AgenticError( AGENTIC_ERROR_CODE.RECEIPT_MISMATCH, @@ -125,14 +134,22 @@ export async function addRules( } /** Bare revoke (no IDs, empty list, or anything but { all: true }) is refused. */ -export function assertRevokeTarget(target: unknown): { all: boolean; ids?: AgenticHex[] } { - const all = !!target && !Array.isArray(target) && (target as { all?: unknown }).all === true; +export function assertRevokeTarget(target: unknown): { + all: boolean; + ids?: AgenticHex[]; +} { + const all = + !!target && + !Array.isArray(target) && + (target as { all?: unknown }).all === true; const ids = Array.isArray(target) ? (target as AgenticHex[]) : undefined; if (!all && (!ids || ids.length === 0)) { throw new AgenticError( AGENTIC_ERROR_CODE.REVOKE_NEEDS_TARGET, 'rules.revoke needs explicit rule IDs or { all: true }', - { hint: 'A bare revoke that wipes every rule is too easy to make by mistake.' } + { + hint: 'A bare revoke that wipes every rule is too easy to make by mistake.', + } ); } return { all, ids }; @@ -143,22 +160,36 @@ export async function revokeRules( runtime: AgenticRuntime, gen: AgenticGeneration, wallet: Address, - target: AgenticHex[] | { all: true; progressHook?: AgenticProgressHook } | undefined, + target: + | AgenticHex[] + | { all: true; progressHook?: AgenticProgressHook } + | undefined, hook?: AgenticProgressHook ): Promise { const { all, ids } = assertRevokeTarget(target); - if (all) hook = (target as { progressHook?: AgenticProgressHook }).progressHook ?? hook; + if (all) + hook = + (target as { progressHook?: AgenticProgressHook }).progressHook ?? hook; assertCanSign(runtime, 'rules.revoke'); const snap = await Snapshot.at(runtime.reader); await assertOwner(runtime, gen, wallet, snap); let calls: MultiCall[]; if (all) { - calls = [{ to: wallet, value: BigInt(0), data: gen.contracts.encodeRevokeAllRules() }]; + calls = [ + { + to: wallet, + value: BigInt(0), + data: gen.contracts.encodeRevokeAllRules(), + }, + ]; } else { const unique = new Set((ids as Hex[]).map((i) => i.toLowerCase())); if (unique.size !== (ids as Hex[]).length) { - throw new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, 'rules.revoke got the same rule ID twice'); + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'rules.revoke got the same rule ID twice' + ); } for (const id of ids as Hex[]) { const enabled = await snap.read( @@ -168,20 +199,33 @@ export async function revokeRules( [id, wallet] ); if (!enabled) { - throw new AgenticError(AGENTIC_ERROR_CODE.RULE_NOT_FOUND, `rule ${id} is not enabled on ${wallet}`); + throw new AgenticError( + AGENTIC_ERROR_CODE.RULE_NOT_FOUND, + `rule ${id} is not enabled on ${wallet}` + ); } } // Several IDs go through one owner `execute` batch so revocation is atomic // regardless of signer batching support. calls = (ids as Hex[]).length === 1 - ? [{ to: wallet, value: BigInt(0), data: gen.contracts.encodeRevokeRules((ids as Hex[])[0]) }] + ? [ + { + to: wallet, + value: BigInt(0), + data: gen.contracts.encodeRevokeRules((ids as Hex[])[0]), + }, + ] : [ { to: wallet, value: BigInt(0), data: gen.contracts.encodeExecute( - (ids as Hex[]).map((id) => ({ target: wallet, value: BigInt(0), data: gen.contracts.encodeRevokeRules(id) })) + (ids as Hex[]).map((id) => ({ + target: wallet, + value: BigInt(0), + data: gen.contracts.encodeRevokeRules(id), + })) ), }, ]; @@ -189,8 +233,15 @@ export async function revokeRules( const result = await finish(runtime, hook, 'rules.revoke', async () => { const tx = await sendOwnerCalls(runtime, calls, hook); const { logs } = await confirmedLogs(runtime, tx); - const revoked = gen.contracts.parseRulesRevoked(logs, wallet).map((r) => r.rulesId); - emitAgentic(runtime, hook, PROGRESS_HOOK.AGENTIC_TX_105, all ? { all: true } : { rulesIds: revoked }); + const revoked = gen.contracts + .parseRulesRevoked(logs, wallet) + .map((r) => r.rulesId); + emitAgentic( + runtime, + hook, + PROGRESS_HOOK.AGENTIC_TX_105, + all ? { all: true } : { rulesIds: revoked } + ); return { tx }; }); return result.tx; @@ -207,17 +258,29 @@ export async function updateRules( runtime: AgenticRuntime, gen: AgenticGeneration, wallet: Address, - params: { rules: { rulesId: AgenticHex; rule: Rule }[]; progressHook?: AgenticProgressHook } -): Promise<{ rules: { rulesId: AgenticHex; replaced: AgenticHex }[]; tx: UniversalTxResponse }> { + params: { + rules: { rulesId: AgenticHex; rule: Rule }[]; + progressHook?: AgenticProgressHook; + } +): Promise<{ + rules: { rulesId: AgenticHex; replaced: AgenticHex }[]; + tx: UniversalTxResponse; +}> { const hook = params?.progressHook; assertCanSign(runtime, 'rules.update'); if (!params || !Array.isArray(params.rules) || params.rules.length === 0) { - throw new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, 'rules.update needs at least one { rulesId, rule } pair'); + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'rules.update needs at least one { rulesId, rule } pair' + ); } requireCapability(gen.capabilities, AgenticCapability.OWNER_EXECUTE); const oldIds = params.rules.map((p) => p.rulesId.toLowerCase()); if (new Set(oldIds).size !== oldIds.length) { - throw new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, 'rules.update names the same old rule twice'); + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'rules.update names the same old rule twice' + ); } const snap = await Snapshot.at(runtime.reader); @@ -225,71 +288,130 @@ export async function updateRules( const active = await readActiveRules(snap, gen, wallet); const byId = new Map(active.map((r) => [r.rulesId.toLowerCase(), r])); - const assertions: Awaited>[] = []; + const assertions: { configId: Hex; data: Hex }[][] = []; for (const pair of params.rules) { const old = byId.get(pair.rulesId.toLowerCase()); - if (!old) { - throw new AgenticError(AGENTIC_ERROR_CODE.RULE_NOT_FOUND, `rule ${pair.rulesId} is not enabled on ${wallet}`); - } - if (old.mode !== MODE_NATIVE || isUniversalRule(pair.rule)) { - requireCapability(gen.capabilities, AgenticCapability.ASSERT_SPENT_UNIVERSAL_MULTI); - } - requireCapability(gen.capabilities, AgenticCapability.ASSERT_SPENT_NATIVE); - if (old.actionIds.length !== 1) { + if (!old) throw new AgenticError( - AGENTIC_ERROR_CODE.RULE_READ_FAILED, - `rule ${pair.rulesId} has ${old.actionIds.length} native actions; replacing it would need one assertion per action` + AGENTIC_ERROR_CODE.RULE_NOT_FOUND, + `rule ${pair.rulesId} is not enabled on ${wallet}` + ); + if (old.mode === MODE_NATIVE) { + requireCapability( + gen.capabilities, + AgenticCapability.ASSERT_SPENT_NATIVE ); + const guards = []; + for (const action of old.actionIds) { + const spend = await readNativeSpend(snap, gen, wallet, old, action); + guards.push({ + configId: spend.configId, + data: gen.contracts.encodeAssertSpentNative( + spend.configId, + wallet, + spend + ), + }); + } + assertions.push(guards); + } else { + requireCapability( + gen.capabilities, + AgenticCapability.ASSERT_SPENT_UNIVERSAL_MULTI + ); + const spend = await readUniversalSpend(snap, gen, wallet, old); + assertions.push([ + { + configId: spend.configId, + data: gen.contracts.encodeAssertSpentUniversal( + spend.configId, + wallet, + spend.expectedSpent + ), + }, + ]); } - assertions.push(await readNativeSpend(snap, gen, wallet, old)); } - - const prepared = prepareRules( + const prepared = await prepareWalletRules( + runtime, + gen, + owner, + wallet, params.rules.map((p) => p.rule), - { - ...encodeContext(runtime, gen, owner, wallet), - existing: existingPairs(active, runtime.pushChainNamespace, new Set(oldIds)), - } + snap + ); + const nonce = BigInt( + await snap.read(wallet, gen.contracts.abis.wallet, 'grantNonce') ); - const nonce = BigInt(await snap.read(wallet, gen.contracts.abis.wallet, 'grantNonce')); const predicted = prepared.map((p, i) => - computeRulesId({ validator: gen.addresses.sessionValidator, agent: p.agent, grantNonce: nonce + BigInt(i) }) + computeRulesId({ + validator: gen.addresses.sessionValidator, + agent: p.agent, + grantNonce: nonce + BigInt(i), + }) ); const batch = params.rules.flatMap((pair, i) => [ - { + ...assertions[i].map((a) => ({ target: gen.addresses.rulesPolicy, value: BigInt(0), - data: gen.contracts.encodeAssertSpentNative(assertions[i].configId, wallet, assertions[i]), + data: a.data, + })), + { + target: wallet, + value: BigInt(0), + data: gen.contracts.encodeRevokeRules(pair.rulesId), + }, + { + target: wallet, + value: BigInt(0), + data: gen.contracts.encodeGrantRules(prepared[i].session), }, - { target: wallet, value: BigInt(0), data: gen.contracts.encodeRevokeRules(pair.rulesId) }, - { target: wallet, value: BigInt(0), data: gen.contracts.encodeGrantRules(prepared[i].session) }, ]); - const call: MultiCall = { to: wallet, value: BigInt(0), data: gen.contracts.encodeExecute(batch) }; + const call: MultiCall = { + to: wallet, + value: BigInt(0), + data: gen.contracts.encodeExecute(batch), + }; return finish(runtime, hook, 'rules.update', async () => { const tx = await sendOwnerCalls(runtime, [call], hook); const { logs } = await confirmedLogs(runtime, tx); - const granted = gen.contracts.parseRulesGranted(logs, wallet).map((g) => g.rulesId as AgenticHex); - const revoked = gen.contracts.parseRulesRevoked(logs, wallet).map((r) => r.rulesId.toLowerCase()); - if (!sameIds(granted, predicted) || !sameIds(revoked as Hex[], oldIds as Hex[])) { + const granted = gen.contracts + .parseRulesGranted(logs, wallet) + .map((g) => g.rulesId as AgenticHex); + const revoked = gen.contracts + .parseRulesRevoked(logs, wallet) + .map((r) => r.rulesId.toLowerCase()); + if ( + !sameIds(granted, predicted) || + !sameIds(revoked as Hex[], oldIds as Hex[]) + ) { throw new AgenticError( AGENTIC_ERROR_CODE.RECEIPT_MISMATCH, 'rules.update receipt does not show the expected revoke/grant pairs', { details: { granted, predicted, revoked, txHash: tx.hash } } ); } - emitAgentic(runtime, hook, PROGRESS_HOOK.AGENTIC_TX_105, { rulesIds: params.rules.map((p) => p.rulesId) }); + emitAgentic(runtime, hook, PROGRESS_HOOK.AGENTIC_TX_105, { + rulesIds: params.rules.map((p) => p.rulesId), + }); emitAgentic(runtime, hook, PROGRESS_HOOK.AGENTIC_TX_104, granted); return { tx, - rules: granted.map((id, i) => ({ rulesId: id, replaced: params.rules[i].rulesId })), + rules: granted.map((id, i) => ({ + rulesId: id, + replaced: params.rules[i].rulesId, + })), }; }); } function sameIds(a: readonly Hex[], b: readonly Hex[]): boolean { - return a.length === b.length && a.every((x, i) => x.toLowerCase() === b[i].toLowerCase()); + return ( + a.length === b.length && + a.every((x, i) => x.toLowerCase() === b[i].toLowerCase()) + ); } /** w.setLabel — PROPOSED; no generation implements an editable label (A07). */ @@ -300,9 +422,14 @@ export async function setLabel( label: string ): Promise { if (typeof label !== 'string') { - throw new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, 'label must be a string'); + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'label must be a string' + ); } requireCapability(gen.capabilities, AgenticCapability.SET_LABEL); - throw new AgenticError(AGENTIC_ERROR_CODE.CAPABILITY_UNAVAILABLE, 'setLabel has no adapter implementation'); + throw new AgenticError( + AGENTIC_ERROR_CODE.CAPABILITY_UNAVAILABLE, + 'setLabel has no adapter implementation' + ); } - diff --git a/packages/core/src/lib/agentic/reads/rules.ts b/packages/core/src/lib/agentic/reads/rules.ts index eacb5ef3..6b55072e 100644 --- a/packages/core/src/lib/agentic/reads/rules.ts +++ b/packages/core/src/lib/agentic/reads/rules.ts @@ -1,12 +1,32 @@ -import { getAddress, type Address, type Hex } from 'viem'; +import { + getAddress, + isAddress, + zeroAddress, + type Address, + type Hex, +} from 'viem'; import { CHAIN } from '../../constants/enums'; -import { AgenticCapability, CAPABILITY_DEPENDENCY, requireCapability } from '../capabilities'; +import { + AgenticCapability, + CAPABILITY_DEPENDENCY, + requireCapability, +} from '../capabilities'; import type { AgenticGeneration } from '../deployments'; -import type { NativeConfigRead, ModeRead } from '../contracts/e704d5b'; +import type { + NativeConfigRead, + ModeRead, + UniversalConfigRead, +} from '../contracts/v4'; import { configId } from '../codec/ids'; import { nativeTermsToRule } from '../codec/native'; +import { universalTermsToRule } from '../codec/universal'; +import { readOriginToken } from '../contracts/prc20-metadata'; import { chainHash } from '../codec/rules'; -import { AGENTIC_ERROR_CODE, AgenticError, capabilityUnavailable } from '../errors'; +import { + AGENTIC_ERROR_CODE, + AgenticError, + capabilityUnavailable, +} from '../errors'; import type { AgenticHex, RulesRecord } from '../agentic.types'; import { Snapshot } from './snapshot'; @@ -47,10 +67,12 @@ async function readActiveRule( ): Promise { const [agent, actionIds] = await Promise.all([ snap.read
(wallet, gen.contracts.abis.wallet, 'agentOf', [rulesId]), - snap.read(gen.addresses.sessionEngine, gen.contracts.abis.engine, 'getEnabledActions', [ - wallet, - rulesId, - ]), + snap.read( + gen.addresses.sessionEngine, + gen.contracts.abis.engine, + 'getEnabledActions', + [wallet, rulesId] + ), ]); if (actionIds.length === 0) { throw new AgenticError( @@ -60,14 +82,23 @@ async function readActiveRule( } const modes = await Promise.all( actionIds.map((a) => - snap.read(gen.addresses.rulesPolicy, gen.contracts.abis.policy, 'getMode', [ - configId(wallet, rulesId, a), - wallet, - ]) + snap.read( + gen.addresses.rulesPolicy, + gen.contracts.abis.policy, + 'getMode', + [configId(wallet, rulesId, a), wallet] + ) ) ); const first = modes[0]; - if (!modes.every((m) => m.initialized && m.chainHash === first.chainHash && m.mode === first.mode)) { + if ( + !modes.every( + (m) => + m.initialized && + m.chainHash === first.chainHash && + m.mode === first.mode + ) + ) { throw new AgenticError( AGENTIC_ERROR_CODE.INCONSISTENT_READ, `rule ${rulesId} has uninitialized or mixed-chain policy configs` @@ -84,7 +115,10 @@ async function readActiveRule( } /** Map a stored chain hash back to its CAIP-2 string from known chains. */ -export function chainFromHash(hash: Hex, pushChainNamespace: string): string | undefined { +export function chainFromHash( + hash: Hex, + pushChainNamespace: string +): string | undefined { const known = [pushChainNamespace, ...Object.values(CHAIN)]; return known.find((c) => chainHash(c) === hash); } @@ -110,15 +144,22 @@ export async function selectRuleForSend( throw new AgenticError( AGENTIC_ERROR_CODE.NO_RULES_FOR_CHAIN, `no enabled rule on ${wallet} names ${agent} for ${destinationChain}`, - { details: { wallet, agent, destinationChain, blockNumber: snap.blockNumber } } + { + details: { + wallet, + agent, + destinationChain, + blockNumber: snap.blockNumber, + }, + } ); } if (matches.length > 1) { throw new AgenticError( - AGENTIC_ERROR_CODE.DUPLICATE_RULE, + AGENTIC_ERROR_CODE.AMBIGUOUS_RULE, `${matches.length} enabled rules on ${wallet} name ${agent} for ${destinationChain}`, { - hint: 'The SDK will not pick one arbitrarily. Ask the owner to revoke all but one (rules.revoke) and retry.', + hint: 'Multi-rule selection is pending H6. Candidate IDs are listed in details.rulesIds; the SDK will not pick one arbitrarily.', details: { rulesIds: matches.map((m) => m.rulesId) }, } ); @@ -135,13 +176,63 @@ export async function decodeActiveRule( pushChainNamespace: string ): Promise { if (rule.mode === MODE_UNIVERSAL) { - throw capabilityUnavailable( - AgenticCapability.UNIVERSAL_EVM_RULES, - `rule ${rule.rulesId} is a universal rule; ${CAPABILITY_DEPENDENCY[AgenticCapability.UNIVERSAL_EVM_RULES]}` + if (rule.vm !== 0) + throw capabilityUnavailable( + AgenticCapability.UNIVERSAL_SVM_RULES, + 'SVM public rule mapping is not settled (H4.4)' + ); + requireCapability(gen.capabilities, AgenticCapability.UNIVERSAL_EVM_RULES); + const chain = chainFromHash(rule.chainHash, pushChainNamespace); + if (!chain || !chain.startsWith('eip155:')) + throw new AgenticError( + AGENTIC_ERROR_CODE.RULE_READ_FAILED, + 'unknown EVM rule chain' + ); + const cfg = await snap.read( + gen.addresses.rulesPolicy, + gen.contracts.abis.policy, + 'getConfig', + [configId(wallet, rule.rulesId, rule.actionIds[0]), wallet] + ); + if (!cfg.initialized) + throw new AgenticError( + AGENTIC_ERROR_CODE.INCONSISTENT_READ, + 'uninitialized universal rule' + ); + if ( + !cfg.assets.length || + cfg.assets.length > 8 || + !cfg.allowedCalls.length || + cfg.allowedCalls.length > 32 || + cfg.expectedCEA === zeroAddress + ) + throw new AgenticError( + AGENTIC_ERROR_CODE.INCONSISTENT_READ, + 'invalid stored universal rule shape' + ); + const tokens = await Promise.all( + cfg.assets.map((a) => readOriginToken(snap, a.token, chain)) ); + return { + rulesId: rule.rulesId, + enabled: true, + chainNamespace: chain, + agent: rule.agent, + validUntil: Number(cfg.validUntil), + ref: ZERO_REF, + rule: universalTermsToRule( + cfg, + rule.agent, + chain as `eip155:${string}`, + tokens + ), + }; } if (rule.mode !== MODE_NATIVE) { - throw new AgenticError(AGENTIC_ERROR_CODE.RULE_READ_FAILED, `rule ${rule.rulesId} has unknown mode ${rule.mode}`); + throw new AgenticError( + AGENTIC_ERROR_CODE.RULE_READ_FAILED, + `rule ${rule.rulesId} has unknown mode ${rule.mode}` + ); } if (rule.actionIds.length !== 1) { throw new AgenticError( @@ -175,7 +266,6 @@ export async function decodeActiveRule( validUntil: Number(cfg.validUntil), ref: ZERO_REF, rule: nativeTermsToRule(cfg, rule.agent, ZERO_REF), - }; } @@ -184,9 +274,15 @@ export async function readNativeSpend( snap: Snapshot, gen: AgenticGeneration, wallet: Address, - rule: ActiveRule -): Promise<{ configId: Hex; valueSpent: bigint; amountSpent: bigint; callsUsed: number }> { - const id = configId(wallet, rule.rulesId, rule.actionIds[0]); + rule: ActiveRule, + action: Hex = rule.actionIds[0] +): Promise<{ + configId: Hex; + valueSpent: bigint; + amountSpent: bigint; + callsUsed: number; +}> { + const id = configId(wallet, rule.rulesId, action); const cfg = await snap.read( gen.addresses.rulesPolicy, gen.contracts.abis.policy, @@ -201,6 +297,26 @@ export async function readNativeSpend( }; } +export async function readUniversalSpend( + snap: Snapshot, + gen: AgenticGeneration, + wallet: Address, + rule: ActiveRule +): Promise<{ configId: Hex; expectedSpent: bigint[] }> { + const id = configId(wallet, rule.rulesId, rule.actionIds[0]); + const fn = rule.vm === 1 ? 'getSvmConfig' : 'getConfig'; + const cfg = await snap.read<{ + initialized: boolean; + assets: readonly { spent: bigint }[]; + }>(gen.addresses.rulesPolicy, gen.contracts.abis.policy, fn, [id, wallet]); + if (!cfg.initialized) + throw new AgenticError( + AGENTIC_ERROR_CODE.INCONSISTENT_READ, + 'uninitialized universal spend config' + ); + return { configId: id, expectedSpent: cfg.assets.map((a) => a.spent) }; +} + export async function listRules( snap: Snapshot, gen: AgenticGeneration, @@ -210,7 +326,10 @@ export async function listRules( requireCapability(gen.capabilities, AgenticCapability.ACTIVE_RULE_READS); const active = await readActiveRules(snap, gen, wallet); const records: RulesRecord[] = []; - for (const r of active) records.push(await decodeActiveRule(snap, gen, wallet, r, pushChainNamespace)); + for (const r of active) + records.push( + await decodeActiveRule(snap, gen, wallet, r, pushChainNamespace) + ); return records; } diff --git a/packages/core/src/lib/agentic/reads/snapshot.ts b/packages/core/src/lib/agentic/reads/snapshot.ts index e22675c9..a4fa6285 100644 --- a/packages/core/src/lib/agentic/reads/snapshot.ts +++ b/packages/core/src/lib/agentic/reads/snapshot.ts @@ -1,6 +1,10 @@ import type { AbiEvent, Address, Log } from 'viem'; import type { ChainReader } from '../contracts/reader'; -import { AGENTIC_ERROR_CODE, AgenticError, type AgenticErrorCode } from '../errors'; +import { + AGENTIC_ERROR_CODE, + AgenticError, + type AgenticErrorCode, +} from '../errors'; /** * All reads of one logical operation are pinned to a single block so dependent @@ -22,7 +26,11 @@ export class Snapshot { try { block = await reader.getBlockNumber(); } catch (cause) { - throw new AgenticError(failCode, 'could not read the current Push block number', { cause }); + throw new AgenticError( + failCode, + 'could not read the current Push block number', + { cause } + ); } return new Snapshot(reader, block, failCode); } @@ -45,23 +53,32 @@ export class Snapshot { throw new AgenticError( this.failCode, `${functionName} read on ${address} failed at block ${this.blockNumber}`, - { cause, details: { address, functionName, blockNumber: this.blockNumber } } + { + cause, + details: { address, functionName, blockNumber: this.blockNumber }, + } ); } } async code(address: Address): Promise { try { - const code = await this.reader.getCode({ address, blockNumber: this.blockNumber }); + const code = await this.reader.getCode({ + address, + blockNumber: this.blockNumber, + }); return !!code && code !== '0x'; } catch (cause) { - throw new AgenticError(this.failCode, `getCode(${address}) failed`, { cause }); + throw new AgenticError(this.failCode, `getCode(${address}) failed`, { + cause, + }); } } } /** Max block span per eth_getLogs request. */ -export const LOG_PAGE_BLOCKS = BigInt(50_000); +// Donut's public RPC limits eth_getLogs ranges to a distance of 1,000 blocks. +export const LOG_PAGE_BLOCKS = BigInt(1_000); /** * Paginated log scan [fromBlock, toBlock] inclusive. A failed page fails the @@ -77,9 +94,12 @@ export async function scanLogs( const out: Log[] = []; if (fromBlock > toBlock) return out; for (let start = fromBlock; start <= toBlock; start += page) { - const end = start + page - BigInt(1) > toBlock ? toBlock : start + page - BigInt(1); + const end = + start + page - BigInt(1) > toBlock ? toBlock : start + page - BigInt(1); try { - out.push(...(await reader.getLogs({ ...args, fromBlock: start, toBlock: end }))); + out.push( + ...(await reader.getLogs({ ...args, fromBlock: start, toBlock: end })) + ); } catch (cause) { throw new AgenticError( AGENTIC_ERROR_CODE.RULE_READ_FAILED, diff --git a/packages/core/src/lib/agentic/response.ts b/packages/core/src/lib/agentic/response.ts index bc1424c6..921ce8e0 100644 --- a/packages/core/src/lib/agentic/response.ts +++ b/packages/core/src/lib/agentic/response.ts @@ -15,10 +15,19 @@ import type { TransactionRouteType, UniversalTxResponse, } from '../orchestrator/orchestrator.types'; -import { e704d5b, SEND_OUTBOUND_SELECTOR, UEA_MULTICALL_PREFIX, type Call } from './contracts/e704d5b'; +import { + v4, + SEND_OUTBOUND_SELECTOR, + UEA_MULTICALL_PREFIX, + type Call, +} from './contracts/v4'; import { generationsFor, resolveWalletGeneration } from './deployments'; import type { AgenticRuntime } from './runtime'; -import type { AgenticAddress, AgenticHex, AgenticTxMetadata } from './agentic.types'; +import type { + AgenticAddress, + AgenticHex, + AgenticTxMetadata, +} from './agentic.types'; export interface LogicalCall { to: string; @@ -45,7 +54,13 @@ export function adaptAgenticResponse( const rawTo = resp.to; const rawData = resp.data; if (!resp.raw) { - resp.raw = { from: resp.from, to: resp.to, nonce: resp.nonce, data: resp.data, value: resp.value }; + resp.raw = { + from: resp.from, + to: resp.to, + nonce: resp.nonce, + data: resp.data, + value: resp.value, + }; } resp.from = getAddress(meta.wallet); resp.to = meta.logical.to; @@ -61,9 +76,15 @@ export function adaptAgenticResponse( door: meta.door, ...(meta.rulesId ? { rulesId: meta.rulesId } : {}), ...(meta.chainNamespace ? { chainNamespace: meta.chainNamespace } : {}), - ...(meta.destinationAccount ? { destinationAccount: meta.destinationAccount } : {}), - ...(meta.destinationCalls ? { destinationCalls: meta.destinationCalls.map((call) => ({ ...call })) } : {}), - ...(meta.nativeCalls ? { nativeCalls: meta.nativeCalls.map((call) => ({ ...call })) } : {}), + ...(meta.destinationAccount + ? { destinationAccount: meta.destinationAccount } + : {}), + ...(meta.destinationCalls + ? { destinationCalls: meta.destinationCalls.map((call) => ({ ...call })) } + : {}), + ...(meta.nativeCalls + ? { nativeCalls: meta.nativeCalls.map((call) => ({ ...call })) } + : {}), rawTo, rawData, }; @@ -82,8 +103,12 @@ export async function adaptTrackedResponse( if (resp.agentic || generationsFor(runtime.network).length === 0) return resp; const batch = await adaptNativeAgentBatch(runtime, resp); if (batch) return batch; - const decoded = e704d5b.decodeWalletCall(resp.data as Hex); - if (!decoded || (decoded.kind !== 'execute' && decoded.kind !== 'executeAsAgent')) return resp; + const decoded = v4.decodeWalletCall(resp.data as Hex); + if ( + !decoded || + (decoded.kind !== 'execute' && decoded.kind !== 'executeAsAgent') + ) + return resp; let wallet: Address; try { wallet = getAddress(resp.to); @@ -92,15 +117,24 @@ export async function adaptTrackedResponse( } let gen; try { - gen = await resolveWalletGeneration(runtime.reader, runtime.network, wallet); + gen = await resolveWalletGeneration( + runtime.reader, + runtime.network, + wallet + ); } catch { return resp; } const door = decoded.kind === 'execute' ? 'owner' : 'agent'; - const rulesId = decoded.kind === 'executeAsAgent' ? (decoded.rulesId as AgenticHex) : undefined; + const rulesId = + decoded.kind === 'executeAsAgent' + ? (decoded.rulesId as AgenticHex) + : undefined; const calls = decoded.calls; const outbound = calls.find( - (c) => getAddress(c.target) === gen.addresses.gateway && c.data.toLowerCase().startsWith(SEND_OUTBOUND_SELECTOR) + (c) => + getAddress(c.target) === gen.addresses.gateway && + c.data.toLowerCase().startsWith(SEND_OUTBOUND_SELECTOR) ); if (outbound) { const out = decodeOutbound(outbound.data); @@ -113,7 +147,11 @@ export async function adaptTrackedResponse( door, rulesId, chainNamespace: chain, - logical: outboundResponseCall(out.calls, { to: outbound.target, data: outbound.data, value: outbound.value }), + logical: outboundResponseCall(out.calls, { + to: outbound.target, + data: outbound.data, + value: outbound.value, + }), ...(out.calls.length > 0 ? { destinationCalls: out.calls } : {}), route: 'UOA_TO_CEA', chain: (chain as CHAIN | undefined) ?? resp.chain, @@ -140,44 +178,84 @@ async function adaptNativeAgentBatch( const isUea = resp.data.toLowerCase().startsWith(UEA_MULTICALL_PREFIX); try { if (isUea) { - const [entries] = decodeAbiParameters([ - { type: 'tuple[]', components: [{ name: 'to', type: 'address' }, { name: 'value', type: 'uint256' }, { name: 'data', type: 'bytes' }] }, - ], `0x${resp.data.slice(10)}`); - outer = entries.map((c) => ({ target: getAddress(c.to), value: c.value, data: c.data })); + const [entries] = decodeAbiParameters( + [ + { + type: 'tuple[]', + components: [ + { name: 'to', type: 'address' }, + { name: 'value', type: 'uint256' }, + { name: 'data', type: 'bytes' }, + ], + }, + ], + `0x${resp.data.slice(10)}` + ); + outer = entries.map((c) => ({ + target: getAddress(c.to), + value: c.value, + data: c.data, + })); } else { - const batch = e704d5b.decodeWalletCall(resp.data as Hex); - if (batch?.kind !== 'execute' || batch.mode !== `0x01${'00'.repeat(31)}`) return; + const batch = v4.decodeWalletCall(resp.data as Hex); + if (batch?.kind !== 'execute' || batch.mode !== `0x01${'00'.repeat(31)}`) + return; outer = batch.calls; } - if (outer.length < 2 || outer.some((c) => c.value !== BigInt(0) || c.target !== outer[0].target)) return; - const inner = outer.map((c) => e704d5b.decodeWalletCall(c.data)); + if ( + outer.length < 2 || + outer.some((c) => c.value !== BigInt(0) || c.target !== outer[0].target) + ) + return; + const inner = outer.map((c) => v4.decodeWalletCall(c.data)); const first = inner[0]; if (first?.kind !== 'executeAsAgent' || first.calls.length !== 1) return; const nativeCalls: { to: Address; value: bigint; data: Hex }[] = []; for (const c of inner) { - if (c?.kind !== 'executeAsAgent' || c.calls.length !== 1 || c.rulesId !== first.rulesId || c.mode !== `0x${'00'.repeat(32)}`) return; + if ( + c?.kind !== 'executeAsAgent' || + c.calls.length !== 1 || + c.rulesId !== first.rulesId || + c.mode !== `0x${'00'.repeat(32)}` + ) + return; const call = c.calls[0]; nativeCalls.push({ to: call.target, value: call.value, data: call.data }); } const senderAccount = getAddress(resp.from); if (isUea) { if (getAddress(resp.raw?.to ?? resp.to) !== senderAccount) return; - const origin = await convertExecutorToOrigin(senderAccount, { _internal: true }); + const origin = await convertExecutorToOrigin(senderAccount, { + _internal: true, + }); if (!origin.exists) return; } else { if (getAddress(resp.to) !== senderAccount) return; - const executor = getBatchExecutorAddress(getPushChainForNetwork(runtime.network)); + const executor = getBatchExecutorAddress( + getPushChainForNetwork(runtime.network) + ); if (!executor) return; - const code = await runtime.reader.getCode({ address: senderAccount, blockNumber: resp.blockNumber }); - if (code?.toLowerCase() !== `0xef0100${executor.slice(2).toLowerCase()}`) return; + const code = await runtime.reader.getCode({ + address: senderAccount, + blockNumber: resp.blockNumber, + }); + if (code?.toLowerCase() !== `0xef0100${executor.slice(2).toLowerCase()}`) + return; } const wallet = outer[0].target; - const gen = await resolveWalletGeneration(runtime.reader, runtime.network, wallet); + const gen = await resolveWalletGeneration( + runtime.reader, + runtime.network, + wallet + ); // This recognizer is only for native arrays; keep mixed/outbound batches raw. if (nativeCalls.some((c) => c.to === gen.addresses.gateway)) return; return adaptAgenticResponse(resp, { - wallet, door: 'agent', rulesId: first.rulesId as AgenticHex, - chainNamespace: pushChainNamespaceFor(runtime.network), nativeCalls, + wallet, + door: 'agent', + rulesId: first.rulesId as AgenticHex, + chainNamespace: pushChainNamespaceFor(runtime.network), + nativeCalls, logical: { ...nativeCalls[0] }, }); } catch { @@ -198,7 +276,9 @@ export function outboundResponseCall( fallback: LogicalCall ): LogicalCall { const first = calls[0]; - return first ? { to: first.to, data: first.data, value: first.value } : fallback; + return first + ? { to: first.to, data: first.data, value: first.value } + : fallback; } function decodeOutbound(data: Hex): { @@ -223,7 +303,11 @@ function decodeOutbound(data: Hex): { ], `0x${req.payload.slice(10)}` ); - calls = decodedCalls.map((c) => ({ to: getAddress(c.to), value: c.value, data: c.data })); + calls = decodedCalls.map((c) => ({ + to: getAddress(c.to), + value: c.value, + data: c.data, + })); } catch { calls = []; } diff --git a/packages/core/src/lib/agentic/revert.ts b/packages/core/src/lib/agentic/revert.ts index c2ea4b1e..d70f2aab 100644 --- a/packages/core/src/lib/agentic/revert.ts +++ b/packages/core/src/lib/agentic/revert.ts @@ -11,7 +11,7 @@ import { AGW_FACTORY_ABI, SMART_SESSION_ABI, UNIVERSAL_RULES_POLICY_ABI, -} from './contracts/abi/e704d5b'; +} from './contracts/abi/v4'; /** URP reverts reached through the engine are truncated to this wrapper. */ export const POLICY_CHECK_REVERTED_SELECTOR = '0xf4270752'; @@ -29,8 +29,15 @@ const ERROR_NAMES: ReadonlyMap = new Map( abi .filter((item) => item.type === 'error') .map((item) => { - const err = item as { type: 'error'; name: string; inputs: readonly { type: string }[] }; - return [toFunctionSelector(formatAbiItem(err as never)).toLowerCase(), err.name] as const; + const err = item as { + type: 'error'; + name: string; + inputs: readonly { type: string }[]; + }; + return [ + toFunctionSelector(formatAbiItem(err as never)).toLowerCase(), + err.name, + ] as const; }) ) ); @@ -42,15 +49,29 @@ const CUSTOM_ERROR_TEXT = /custom error (0x[0-9a-fA-F]{8}):?\s*([0-9a-fA-F]*)/g; function revertDataCandidates(err: unknown, depth = 0): Hex[] { if (!err || depth > 6) return []; const out: Hex[] = []; - const e = err as { data?: unknown; cause?: unknown; message?: unknown; details?: unknown }; - if (typeof e.data === 'string' && /^0x[0-9a-fA-F]{8,}$/.test(e.data)) out.push(e.data as Hex); - if (e.data && typeof e.data === 'object' && typeof (e.data as { data?: unknown }).data === 'string') { + const e = err as { + data?: unknown; + raw?: unknown; + cause?: unknown; + message?: unknown; + details?: unknown; + }; + if (typeof e.raw === 'string' && /^0x[0-9a-fA-F]{8,}$/.test(e.raw)) + out.push(e.raw as Hex); + if (typeof e.data === 'string' && /^0x[0-9a-fA-F]{8,}$/.test(e.data)) + out.push(e.data as Hex); + if ( + e.data && + typeof e.data === 'object' && + typeof (e.data as { data?: unknown }).data === 'string' + ) { out.push((e.data as { data: Hex }).data); } for (const text of [e.message, e.details]) { if (typeof text !== 'string') continue; // viem renders unknown custom errors as "custom error 0x: ". - for (const m of text.matchAll(CUSTOM_ERROR_TEXT)) out.push(`${m[1]}${m[2] ?? ''}` as Hex); + for (const m of text.matchAll(CUSTOM_ERROR_TEXT)) + out.push(`${m[1]}${m[2] ?? ''}` as Hex); out.push(...((text.match(HEX_DATA) ?? []) as Hex[])); } out.push(...revertDataCandidates(e.cause, depth + 1)); @@ -66,7 +87,9 @@ export function decodeAgwErrorData(data: Hex): DecodedErrorPayload | undefined { const word = `0x${data.slice(10, 74)}` as Hex; const innerName = ERROR_NAMES.get(word.slice(0, 10).toLowerCase()); return { - name: innerName ? `PolicyCheckReverted(${innerName})` : 'PolicyCheckReverted', + name: innerName + ? `PolicyCheckReverted(${innerName})` + : 'PolicyCheckReverted', selector, decoded: word, hint: 'URP rejected the action (truncated through the session engine). The inner selector names the gate; arguments are truncated to 28 bytes.', @@ -86,10 +109,14 @@ export function decodeAgwErrorData(data: Hex): DecodedErrorPayload | undefined { } // Arguments lost (e.g. a node rendered them as text): name the error by its selector. const name = ERROR_NAMES.get(selector); - return name ? { name, selector, hint: 'Error arguments were not available.' } : undefined; + return name + ? { name, selector, hint: 'Error arguments were not available.' } + : undefined; } -export function decodeAgenticRevert(err: unknown): DecodedErrorPayload | undefined { +export function decodeAgenticRevert( + err: unknown +): DecodedErrorPayload | undefined { for (const data of revertDataCandidates(err)) { const decoded = decodeAgwErrorData(data); if (decoded) return decoded; @@ -98,5 +125,7 @@ export function decodeAgenticRevert(err: unknown): DecodedErrorPayload | undefin } function stringifyArgs(args: readonly unknown[]): string { - return JSON.stringify(args, (_k, v) => (typeof v === 'bigint' ? v.toString() : v)); + return JSON.stringify(args, (_k, v) => + typeof v === 'bigint' ? v.toString() : v + ); } diff --git a/packages/core/src/lib/agentic/runtime.ts b/packages/core/src/lib/agentic/runtime.ts index ba27ee3b..19d63e4e 100644 --- a/packages/core/src/lib/agentic/runtime.ts +++ b/packages/core/src/lib/agentic/runtime.ts @@ -15,10 +15,16 @@ import { getCEAAddress } from '../orchestrator/cea-utils'; import type { OrchestratorContext } from '../orchestrator/internals/context'; import { computeUEAOffchain } from '../orchestrator/internals/uea-manager'; import { queryOutboundGasFee } from '../orchestrator/internals/gas-calculator'; -import { getNativePRC20ForChain, isPushChain } from '../orchestrator/internals/helpers'; +import { + getNativePRC20ForChain, + isPushChain, +} from '../orchestrator/internals/helpers'; import { pushChainNamespaceFor } from './chain'; -import { Utils } from '../utils'; -import { chainReaderFromPublicClient, type ChainReader } from './contracts/reader'; +import { getPRC20Address } from '../universal/prc20-address'; +import { + chainReaderFromPublicClient, + type ChainReader, +} from './contracts/reader'; import type { AgenticProgressHook } from './agentic.types'; /** @@ -44,7 +50,10 @@ export interface AgenticRuntime { options?: TransactionExecutionOptions ): Promise; /** Sender-preserving UEA/7702 transport; native sequential fallback is forbidden. */ - executeAtomicBatch(params: ExecuteParams, options?: TransactionExecutionOptions): Promise; + executeAtomicBatch( + params: ExecuteParams, + options?: TransactionExecutionOptions + ): Promise; /** Emit to the init-time hook and, if different, the per-call hook. */ emit(event: ProgressEvent, perCallHook?: AgenticProgressHook): void; /** Whether the signer's own UEA is deployed (always true for a Push EOA). */ @@ -55,14 +64,27 @@ export interface AgenticRuntime { prc20: Address, gasLimit: bigint, chain: CHAIN - ): Promise<{ protocolFee: bigint; nativeValueForGas: bigint; gasLimitUsed: bigint }>; - resolveCEA(account: Address, chain: CHAIN): Promise<{ cea: Address; isDeployed: boolean }>; - resolvePrc20(token: MoveableToken | undefined, chain: CHAIN): Address; + ): Promise<{ + protocolFee: bigint; + nativeValueForGas: bigint; + gasLimitUsed: bigint; + }>; + resolveCEA( + account: Address, + chain: CHAIN + ): Promise<{ cea: Address; isDeployed: boolean }>; + resolvePrc20( + token: MoveableToken | Address | undefined, + chain: CHAIN + ): Address; nowSeconds(): number; } /** Build the runtime over an orchestrator (the orchestrator IS the internal ctx). */ -export function createAgenticRuntime(orchestrator: Orchestrator, isReadOnly: boolean): AgenticRuntime { +export function createAgenticRuntime( + orchestrator: Orchestrator, + isReadOnly: boolean +): AgenticRuntime { const ctx = orchestrator as unknown as OrchestratorContext; const network = orchestrator.getNetwork(); return { @@ -107,13 +129,20 @@ export function createAgenticRuntime(orchestrator: Orchestrator, isReadOnly: boo }; }, resolveCEA: async (account, chain) => { - const r = await getCEAAddress(account, chain, orchestrator.getRpcUrls()[chain]?.[0]); + const r = await getCEAAddress( + account, + chain, + orchestrator.getRpcUrls()[chain]?.[0] + ); return { cea: getAddress(r.cea), isDeployed: r.isDeployed }; }, resolvePrc20: (token, chain) => getAddress( token - ? Utils.tokens.getPRC20Address(token).address + ? getPRC20Address( + typeof token === 'string' ? { chain, address: token } : token, + { network } + ).address : getNativePRC20ForChain(chain, network) ), nowSeconds: () => Math.floor(Date.now() / 1000), diff --git a/packages/core/src/lib/agentic/utils.ts b/packages/core/src/lib/agentic/utils.ts index cbb2b65d..7ec2070e 100644 --- a/packages/core/src/lib/agentic/utils.ts +++ b/packages/core/src/lib/agentic/utils.ts @@ -1,15 +1,30 @@ -import { getAddress, isHex, type Address, type Hex } from 'viem'; -import { PUSH_NETWORK } from '../constants/enums'; -import { AgenticCapability, CAPABILITY_DEPENDENCY } from './capabilities'; -import { E704D5B_CAPABILITIES } from './deployments'; -import { actionId as actionIdRaw, configId as configIdRaw, deriveWallet as deriveWalletRaw, rulesId as rulesIdRaw } from './codec/ids'; +import { getAddress, isHex, zeroAddress, type Address, type Hex } from 'viem'; +import { CHAIN, PUSH_NETWORK } from '../constants/enums'; +import { MOVEABLE_TOKENS } from '../constants/tokens'; +import { getPRC20Address } from '../universal/prc20-address'; +import { AgenticCapability } from './capabilities'; +import { V4_CAPABILITIES } from './deployments'; +import { + actionId as actionIdRaw, + configId as configIdRaw, + deriveWallet as deriveWalletRaw, + rulesId as rulesIdRaw, +} from './codec/ids'; import { decodeNativeTerms, nativeTermsToRule } from './codec/native'; import { prepareRules } from './codec/rules'; import { parseSelector } from './codec/selectors'; import { decodeEnvelope, decodeSession, encodeSession } from './codec/session'; -import { AGENTIC_ERROR_CODE, AgenticError, capabilityUnavailable } from './errors'; +import { + AGENTIC_ERROR_CODE, + AgenticError, + capabilityUnavailable, +} from './errors'; import { pushChainNamespaceFor } from './chain'; +import { decodeUniversalTerms } from './codec/universal-terms'; +import { universalTermsToRule } from './codec/universal'; import type { AgenticHex, Rule, Selector } from './agentic.types'; +import type { UniversalRule } from './agentic.types'; +import type { ResolvedUniversalRule } from './codec/universal'; /** * Internal generation context. Harsh H4.1 (October 4): deployment inputs @@ -21,13 +36,18 @@ export interface RulesEncodeContext { pushChainNamespace?: string; validator: Address; rulesPolicy: Address; + gateway?: Address; + universal?: ReadonlyMap; /** Wallet owner, for the AGENT_IS_OWNER check. */ owner?: Address; /** Defaults to the current time. */ nowSeconds?: number; } -function nativeNamespace(ctx: { network?: PUSH_NETWORK; pushChainNamespace?: string }): string { +function nativeNamespace(ctx: { + network?: PUSH_NETWORK; + pushChainNamespace?: string; +}): string { if (ctx.pushChainNamespace) return ctx.pushChainNamespace; return pushChainNamespaceFor(ctx.network ?? PUSH_NETWORK.TESTNET_DONUT); } @@ -35,7 +55,11 @@ function nativeNamespace(ctx: { network?: PUSH_NETWORK; pushChainNamespace?: str /** Internal codecs and identities — not exported from the package entry point. */ export const internalAgenticUtils = { /** The ID a grant with this grantNonce produces. Chain is not part of the hash. */ - rulesId(agent: Address, grantNonce: bigint | number, ctx: { validator: Address }): AgenticHex { + rulesId( + agent: Address, + grantNonce: bigint | number, + ctx: { validator: Address } + ): AgenticHex { return rulesIdRaw({ validator: getAddress(ctx.validator), agent: getAddress(agent), @@ -45,7 +69,10 @@ export const internalAgenticUtils = { /** Hash of one allowed call: keccak256(target ‖ selector). */ actionId(target: Address, selector: Selector | 'value-only'): AgenticHex { - return actionIdRaw(getAddress(target), parseSelector(selector).selector) as AgenticHex; + return actionIdRaw( + getAddress(target), + parseSelector(selector).selector + ) as AgenticHex; }, /** Key of one allowed call's stored config under one rule on one wallet. */ @@ -69,7 +96,7 @@ export const internalAgenticUtils = { /** * Encode rules into the grant `Session` bytes, one per rule, in order. - * Native rules only today; universal rules fail with CAPABILITY_UNAVAILABLE (A05). + * EVM universal rules require wallet/token resolution in the internal context. */ encodeRules(rules: readonly Rule[], ctx: RulesEncodeContext): AgenticHex[] { return prepareRules(rules, { @@ -77,32 +104,97 @@ export const internalAgenticUtils = { pushChainNamespace: nativeNamespace(ctx), validator: getAddress(ctx.validator), rulesPolicy: getAddress(ctx.rulesPolicy), - capabilities: E704D5B_CAPABILITIES, + gateway: ctx.gateway, + universal: ctx.universal, + capabilities: V4_CAPABILITIES, nowSeconds: ctx.nowSeconds ?? Math.floor(Date.now() / 1000), }).map((p) => encodeSession(p.session) as AgenticHex); }, /** Inverse of encodeRules for one Session encoding. */ - decodeRules(bytes: Hex, ctx: { network?: PUSH_NETWORK; pushChainNamespace?: string } = {}): Rule { - if (!isHex(bytes)) throw new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, 'decodeRules expects hex bytes'); + decodeRules( + bytes: Hex, + ctx: { network?: PUSH_NETWORK; pushChainNamespace?: string } = {} + ): Rule { + if (!isHex(bytes)) + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'decodeRules expects hex bytes' + ); const session = decodeSession(bytes); - if (session.actions.length !== 1 || session.actions[0].actionPolicies.length !== 1) { + if ( + session.actions.length !== 1 || + session.actions[0].actionPolicies.length !== 1 + ) { throw new AgenticError( AGENTIC_ERROR_CODE.RULE_READ_FAILED, 'only single-action rules (one URP policy) are representable as a public Rule' ); } - const agent = getAddress(`0x${session.sessionValidatorInitData.slice(26, 66)}`); - const { chainNamespace, body } = decodeEnvelope(session.actions[0].actionPolicies[0].initData); + const agent = getAddress( + `0x${session.sessionValidatorInitData.slice(26, 66)}` + ); + const { chainNamespace, body } = decodeEnvelope( + session.actions[0].actionPolicies[0].initData + ); if (chainNamespace !== nativeNamespace(ctx)) { - throw capabilityUnavailable( - AgenticCapability.UNIVERSAL_EVM_RULES, - `${chainNamespace} is a universal rule; ${CAPABILITY_DEPENDENCY[AgenticCapability.UNIVERSAL_EVM_RULES]}` + if (!chainNamespace.startsWith('eip155:')) + throw capabilityUnavailable( + AgenticCapability.UNIVERSAL_SVM_RULES, + 'SVM public decoding is pending' + ); + let terms; + try { + terms = decodeUniversalTerms(body); + } catch (cause) { + throw new AgenticError( + AGENTIC_ERROR_CODE.RULE_READ_FAILED, + 'malformed universal terms', + { cause } + ); + } + const chain = chainNamespace as CHAIN; + const network = ctx.network ?? PUSH_NETWORK.TESTNET_DONUT; + const tokens = terms.assets.map((asset) => { + const token = (MOVEABLE_TOKENS[chain] ?? []).find((candidate) => { + try { + return ( + getAddress( + getPRC20Address( + { chain, address: candidate.address }, + { network } + ).address + ) === getAddress(asset.token) + ); + } catch { + return false; + } + }); + if (!token) + throw new AgenticError( + AGENTIC_ERROR_CODE.RULE_READ_FAILED, + `PRC20 ${asset.token} is not in the static ${chain} token registry`, + { + hint: 'Use wallet.rules.get() for on-chain source-token resolution.', + } + ); + return token.mechanism === 'native' + ? zeroAddress + : getAddress(token.address); + }); + return universalTermsToRule( + terms, + agent, + chainNamespace as `eip155:${string}`, + tokens ); } - return nativeTermsToRule(decodeNativeTerms(body), agent, `0x${'00'.repeat(32)}`); + return nativeTermsToRule( + decodeNativeTerms(body), + agent, + `0x${'00'.repeat(32)}` + ); }, - }; /** Public helpers requiring no contract deployment context. */ diff --git a/packages/core/src/lib/constants/index.ts b/packages/core/src/lib/constants/index.ts index 4048d4cb..9eb7cdcf 100644 --- a/packages/core/src/lib/constants/index.ts +++ b/packages/core/src/lib/constants/index.ts @@ -71,7 +71,7 @@ export const CONSTANTS = { MOVEABLE: { TOKEN: MOVEABLE_TOKEN_CONSTANTS }, PAYABLE: { TOKEN: PAYABLE_TOKEN_CONSTANTS }, READ: READ_CONSTANTS, - /** Agentic wallet deployments by Push network. Empty until a verified deployment exists (A07). */ + /** Checked v4 agentic wallet deployments by Push network (Donut only). */ AGENTIC, }; diff --git a/packages/core/src/lib/universal/prc20-address.ts b/packages/core/src/lib/universal/prc20-address.ts new file mode 100644 index 00000000..693aa28e --- /dev/null +++ b/packages/core/src/lib/universal/prc20-address.ts @@ -0,0 +1,168 @@ +import { CHAIN, PUSH_NETWORK } from '../constants/enums'; +import { MOVEABLE_TOKENS, type MoveableToken } from '../constants/tokens'; +import { SYNTHETIC_PUSH_ERC20 } from '../constants/chain'; + +/** Shared pure origin-to-PRC20 mapping; no signer or network reads. */ +export function getPRC20Address( + token: MoveableToken | { chain: string; address: string }, + options?: { network?: PUSH_NETWORK } +): { + address: `0x${string}`; + chain: CHAIN; + symbol: string; + decimals: number; + network: PUSH_NETWORK; +} { + const network = options?.network ?? PUSH_NETWORK.TESTNET_DONUT; + + const assertDeployed = ( + addr: string | undefined, + ctx: string + ): `0x${string}` => { + if (!addr || addr === '0xTBD') { + throw new Error( + `PRC20 address not available for ${ctx} on network ${network}` + ); + } + return addr as `0x${string}`; + }; + + // PushChainMoveableToken (pETH, pSOL, pUSDT(BNB), …) carries its PRC-20 address + // and origin `sourceChain` directly — no registry lookup needed. + const pcToken = token as Partial<{ + prc20Address: `0x${string}`; + sourceChain: CHAIN; + symbol: string; + decimals: number; + }>; + if (pcToken.prc20Address) { + return { + address: assertDeployed( + pcToken.prc20Address, + `${pcToken.symbol ?? 'token'} (${pcToken.sourceChain ?? 'unknown'})` + ), + chain: pcToken.sourceChain as CHAIN, + symbol: pcToken.symbol as string, + decimals: pcToken.decimals as number, + network, + }; + } + + // Infer origin chain, symbol, decimals by matching against MOVEABLE_TOKENS + let originChain: CHAIN | undefined; + let tokenSymbol: string | undefined; + let tokenDecimals: number | undefined; + + if ('symbol' in token) { + // MoveableToken path: infer chain by symbol + address + for (const [key, list] of Object.entries(MOVEABLE_TOKENS)) { + const k = key as CHAIN; + const match = (list ?? []).find( + (t) => t.symbol === token.symbol && t.address === token.address + ); + if (match) { + originChain = k; + tokenSymbol = match.symbol; + tokenDecimals = match.decimals; + break; + } + } + } else { + // { chain, address } path: trust the provided chain and resolve symbol via registry + originChain = token.chain as CHAIN; + const list = MOVEABLE_TOKENS[originChain] ?? []; + const match = list.find((t) => t.address === token.address); + if (match) { + tokenSymbol = match.symbol; + tokenDecimals = match.decimals; + } + } + + if (!originChain || !tokenSymbol || tokenDecimals === undefined) { + throw new Error('Unable to infer origin chain or token symbol for token'); + } + + const map = SYNTHETIC_PUSH_ERC20[network]; + if (!map) { + throw new Error(`No PRC20 address map configured for network: ${network}`); + } + + // Map token → synthetic key by origin chain family + const isEthFamily = + originChain === CHAIN.ETHEREUM_MAINNET || + originChain === CHAIN.ETHEREUM_SEPOLIA; + const isArbFamily = originChain === CHAIN.ARBITRUM_SEPOLIA; + const isBaseFamily = originChain === CHAIN.BASE_SEPOLIA; + const isBnbFamily = originChain === CHAIN.BNB_TESTNET; + const isSolFamily = originChain === CHAIN.SOLANA_DEVNET; + + let key: + | 'pETH' + | 'pETH_ARB' + | 'pETH_BASE' + | 'pBNB' + | 'pSOL' + | 'USDT_ETH' + | 'USDT_ARB' + | 'USDT_SOL' + | 'USDT_BSC' + | 'USDT_BASE' + | 'USDC_ETH' + | 'USDC_ARB' + | 'USDC_SOL' + | 'USDC_BSC' + | 'USDC_BASE'; + + switch (tokenSymbol) { + case 'ETH': { + if (isEthFamily) key = 'pETH'; + else if (isArbFamily) key = 'pETH_ARB'; + else if (isBaseFamily) key = 'pETH_BASE'; + else + throw new Error('Unsupported ETH origin chain for synthetic mapping'); + break; + } + case 'SOL': { + if (!isSolFamily) + throw new Error('SOL token provided but origin is not Solana'); + key = 'pSOL'; + break; + } + case 'BNB': { + if (!isBnbFamily) + throw new Error('BNB token provided but origin is not BNB Testnet'); + key = 'pBNB'; + break; + } + case 'USDT': { + if (isEthFamily) key = 'USDT_ETH'; + else if (isArbFamily) key = 'USDT_ARB'; + else if (isBaseFamily) key = 'USDT_BASE'; + else if (isBnbFamily) key = 'USDT_BSC'; + else if (isSolFamily) key = 'USDT_SOL'; + else + throw new Error('Unsupported USDT origin chain for synthetic mapping'); + break; + } + case 'USDC': { + if (isEthFamily) key = 'USDC_ETH'; + else if (isArbFamily) key = 'USDC_ARB'; + else if (isBaseFamily) key = 'USDC_BASE'; + else if (isBnbFamily) key = 'USDC_BSC'; + else if (isSolFamily) key = 'USDC_SOL'; + else + throw new Error('Unsupported USDC origin chain for synthetic mapping'); + break; + } + default: + throw new Error(`Unsupported token symbol: ${tokenSymbol}`); + } + + return { + address: assertDeployed(map[key], `${tokenSymbol} on ${originChain}`), + chain: originChain, + symbol: tokenSymbol, + decimals: tokenDecimals, + network, + }; +} diff --git a/packages/core/src/lib/utils.ts b/packages/core/src/lib/utils.ts index 5f6bfeb8..3fa4d979 100644 --- a/packages/core/src/lib/utils.ts +++ b/packages/core/src/lib/utils.ts @@ -18,7 +18,7 @@ import { PAYABLE_TOKENS, type MoveableToken, } from './constants/tokens'; -import { SYNTHETIC_PUSH_ERC20 } from './constants/chain'; +import { getPRC20Address } from './universal/prc20-address'; import { UniversalAccount } from './universal/universal.types'; import type { PushChain } from './push-chain/push-chain'; import { encodeFunctionData, formatUnits, getAddress } from 'viem'; @@ -310,7 +310,8 @@ export class Utils { } // SVM path: explicit idl, or legacy abi-as-IDL for backward compat. - const svmIdl: Idl | undefined = idl ?? (isAnchorIdl(abi) ? abi : undefined); + const svmIdl: Idl | undefined = + idl ?? (isAnchorIdl(abi) ? abi : undefined); if (svmIdl) { registerSvmIdl(svmIdl); const bytes = encodeAnchorIxData(svmIdl, functionName, args); @@ -772,179 +773,7 @@ export class Utils { * }); * ``` */ - getPRC20Address( - token: MoveableToken | { chain: string; address: string }, - options?: { network?: PUSH_NETWORK } - ): { - address: `0x${string}`; - chain: CHAIN; - symbol: string; - decimals: number; - network: PUSH_NETWORK; - } { - const network = options?.network ?? PUSH_NETWORK.TESTNET_DONUT; - - const assertDeployed = ( - addr: string | undefined, - ctx: string - ): `0x${string}` => { - if (!addr || addr === '0xTBD') { - throw new Error( - `PRC20 address not available for ${ctx} on network ${network}` - ); - } - return addr as `0x${string}`; - }; - - // PushChainMoveableToken (pETH, pSOL, pUSDT(BNB), …) carries its PRC-20 address - // and origin `sourceChain` directly — no registry lookup needed. - const pcToken = token as Partial<{ - prc20Address: `0x${string}`; - sourceChain: CHAIN; - symbol: string; - decimals: number; - }>; - if (pcToken.prc20Address) { - return { - address: assertDeployed( - pcToken.prc20Address, - `${pcToken.symbol ?? 'token'} (${pcToken.sourceChain ?? 'unknown'})` - ), - chain: pcToken.sourceChain as CHAIN, - symbol: pcToken.symbol as string, - decimals: pcToken.decimals as number, - network, - }; - } - - // Infer origin chain, symbol, decimals by matching against MOVEABLE_TOKENS - let originChain: CHAIN | undefined; - let tokenSymbol: string | undefined; - let tokenDecimals: number | undefined; - - if ('symbol' in token) { - // MoveableToken path: infer chain by symbol + address - for (const [key, list] of Object.entries(MOVEABLE_TOKENS)) { - const k = key as CHAIN; - const match = (list ?? []).find( - (t) => t.symbol === token.symbol && t.address === token.address - ); - if (match) { - originChain = k; - tokenSymbol = match.symbol; - tokenDecimals = match.decimals; - break; - } - } - } else { - // { chain, address } path: trust the provided chain and resolve symbol via registry - originChain = token.chain as CHAIN; - const list = MOVEABLE_TOKENS[originChain] ?? []; - const match = list.find((t) => t.address === token.address); - if (match) { - tokenSymbol = match.symbol; - tokenDecimals = match.decimals; - } - } - - if (!originChain || !tokenSymbol || tokenDecimals === undefined) { - throw new Error( - 'Unable to infer origin chain or token symbol for token' - ); - } - - const map = SYNTHETIC_PUSH_ERC20[network]; - if (!map) { - throw new Error( - `No PRC20 address map configured for network: ${network}` - ); - } - - // Map token → synthetic key by origin chain family - const isEthFamily = - originChain === CHAIN.ETHEREUM_MAINNET || - originChain === CHAIN.ETHEREUM_SEPOLIA; - const isArbFamily = originChain === CHAIN.ARBITRUM_SEPOLIA; - const isBaseFamily = originChain === CHAIN.BASE_SEPOLIA; - const isBnbFamily = originChain === CHAIN.BNB_TESTNET; - const isSolFamily = originChain === CHAIN.SOLANA_DEVNET; - - let key: - | 'pETH' - | 'pETH_ARB' - | 'pETH_BASE' - | 'pBNB' - | 'pSOL' - | 'USDT_ETH' - | 'USDT_ARB' - | 'USDT_SOL' - | 'USDT_BSC' - | 'USDT_BASE' - | 'USDC_ETH' - | 'USDC_ARB' - | 'USDC_SOL' - | 'USDC_BSC' - | 'USDC_BASE'; - - switch (tokenSymbol) { - case 'ETH': { - if (isEthFamily) key = 'pETH'; - else if (isArbFamily) key = 'pETH_ARB'; - else if (isBaseFamily) key = 'pETH_BASE'; - else - throw new Error( - 'Unsupported ETH origin chain for synthetic mapping' - ); - break; - } - case 'SOL': { - if (!isSolFamily) - throw new Error('SOL token provided but origin is not Solana'); - key = 'pSOL'; - break; - } - case 'BNB': { - if (!isBnbFamily) - throw new Error('BNB token provided but origin is not BNB Testnet'); - key = 'pBNB'; - break; - } - case 'USDT': { - if (isEthFamily) key = 'USDT_ETH'; - else if (isArbFamily) key = 'USDT_ARB'; - else if (isBaseFamily) key = 'USDT_BASE'; - else if (isBnbFamily) key = 'USDT_BSC'; - else if (isSolFamily) key = 'USDT_SOL'; - else - throw new Error( - 'Unsupported USDT origin chain for synthetic mapping' - ); - break; - } - case 'USDC': { - if (isEthFamily) key = 'USDC_ETH'; - else if (isArbFamily) key = 'USDC_ARB'; - else if (isBaseFamily) key = 'USDC_BASE'; - else if (isBnbFamily) key = 'USDC_BSC'; - else if (isSolFamily) key = 'USDC_SOL'; - else - throw new Error( - 'Unsupported USDC origin chain for synthetic mapping' - ); - break; - } - default: - throw new Error(`Unsupported token symbol: ${tokenSymbol}`); - } - - return { - address: assertDeployed(map[key], `${tokenSymbol} on ${originChain}`), - chain: originChain, - symbol: tokenSymbol, - decimals: tokenDecimals, - network, - }; - }, + getPRC20Address, /** * Resolve a PC20 token against UniversalCore's on-chain registry, and list From b68bab71a6009af0dc1a99e40445e933a3e19105 Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Tue, 6 Oct 2026 03:26:46 +0530 Subject: [PATCH 18/68] fix(evm): add headroom to estimated contract transaction gas --- .../vm-client/evm-client.dynamic-gas.spec.ts | 51 +++++++++++++++++-- packages/core/src/lib/vm-client/evm-client.ts | 10 +++- 2 files changed, 54 insertions(+), 7 deletions(-) diff --git a/packages/core/src/lib/vm-client/evm-client.dynamic-gas.spec.ts b/packages/core/src/lib/vm-client/evm-client.dynamic-gas.spec.ts index 97ef53af..bfdf2191 100644 --- a/packages/core/src/lib/vm-client/evm-client.dynamic-gas.spec.ts +++ b/packages/core/src/lib/vm-client/evm-client.dynamic-gas.spec.ts @@ -25,7 +25,7 @@ describe('EvmClient dynamic gas estimation', () => { .fn() .mockImplementation(async (unsignedTx: Uint8Array) => { const parsed = parseTransaction(bytesToHex(unsignedTx)); - expect(parsed.gas).toBe(estimatedGas); + expect(parsed.gas).toBe(BigInt(969_600)); expect(parsed.nonce).toBe(9); return Uint8Array.from(Buffer.from(TX_HASH.slice(2), 'hex')); }); @@ -57,9 +57,9 @@ describe('EvmClient dynamic gas estimation', () => { const estimatedGas = BigInt(21_062); const client = new EvmClient({ rpcUrls: ['http://localhost:8545'] }); client.publicClient = { - getCode: jest.fn().mockResolvedValue( - '0xef01000106bf2f9b02f32203a83a3bdad79fe8818f3796' - ), + getCode: jest + .fn() + .mockResolvedValue('0xef01000106bf2f9b02f32203a83a3bdad79fe8818f3796'), estimateGas: jest.fn().mockResolvedValue(estimatedGas), estimateFeesPerGas: jest.fn().mockResolvedValue({ maxFeePerGas: BigInt(10), @@ -73,7 +73,7 @@ describe('EvmClient dynamic gas estimation', () => { .fn() .mockImplementation(async (unsignedTx: Uint8Array) => { const parsed = parseTransaction(bytesToHex(unsignedTx)); - expect(parsed.gas).toBe(estimatedGas); + expect(parsed.gas).toBe(BigInt(25_275)); return Uint8Array.from(Buffer.from(TX_HASH.slice(2), 'hex')); }); const signer: UniversalSigner = { @@ -137,4 +137,45 @@ describe('EvmClient dynamic gas estimation', () => { expect(client.publicClient.estimateGas).not.toHaveBeenCalled(); }); + + it.each([ + { explicitGas: undefined, expectedGas: BigInt(579_802) }, + { explicitGas: BigInt(500_000), expectedGas: BigInt(500_000) }, + ])( + 'adds headroom for the observed AGW outbound estimate unless gas is explicit ($explicitGas)', + async ({ explicitGas, expectedGas }) => { + // At the same Donut block, this estimate reverted while 500,000 gas passed. + const client = new EvmClient({ rpcUrls: ['http://localhost:8545'] }); + client.publicClient = { + estimateGas: jest.fn().mockResolvedValue(BigInt(483_168)), + estimateFeesPerGas: jest.fn().mockResolvedValue({ + maxFeePerGas: BigInt(10), + maxPriorityFeePerGas: BigInt(1), + }), + getChainId: jest.fn().mockResolvedValue(42101), + } as unknown as typeof client.publicClient; + const signer: UniversalSigner = { + account: { chain: CHAIN.PUSH_TESTNET_DONUT, address: ACCOUNT }, + signMessage: async (data) => data, + signAndSendTransaction: jest.fn(async (unsignedTx: Uint8Array) => { + expect(parseTransaction(bytesToHex(unsignedTx)).gas).toBe( + expectedGas + ); + return Uint8Array.from(Buffer.from(TX_HASH.slice(2), 'hex')); + }), + }; + + await client.sendTransaction({ + to: TARGET, + data: '0x12345678', + signer, + nonce: 12, + gas: explicitGas, + }); + + expect(client.publicClient.estimateGas).toHaveBeenCalledTimes( + explicitGas ? 0 : 1 + ); + } + ); }); diff --git a/packages/core/src/lib/vm-client/evm-client.ts b/packages/core/src/lib/vm-client/evm-client.ts index 772fcbaa..5d66c4b6 100644 --- a/packages/core/src/lib/vm-client/evm-client.ts +++ b/packages/core/src/lib/vm-client/evm-client.ts @@ -275,13 +275,19 @@ export class EvmClient { const resolveGas = async (): Promise => { if (explicitGas) return explicitGas; - const estimate = () => - this.publicClient.estimateGas({ + const estimate = async () => { + const estimatedGas = await this.publicClient.estimateGas({ account: signer.account.address as `0x${string}`, to, data, value, }); + // Leave headroom for nested calls and state changes before inclusion, + // as on the EIP-7702 batch path. Donut can return an estimate that + // reverts inside an AGW -> gateway -> token call even at the same state. + // This is the Push execution limit, separate from destination gas. + return (estimatedGas * BigInt(120) + BigInt(99)) / BigInt(100); + }; if (data !== '0x') return estimate(); From ab42b8451275d90cbe1fa488fb0b3741e70e7e9f Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Tue, 6 Oct 2026 03:35:03 +0530 Subject: [PATCH 19/68] test(agw): verify destination executor and confirm origin funding --- .../core/__e2e__/agw/identity-gas.spec.ts | 105 +++++++++++++++--- .../core/__e2e__/agw/universal-evm.spec.ts | 22 ++++ 2 files changed, 110 insertions(+), 17 deletions(-) diff --git a/packages/core/__e2e__/agw/identity-gas.spec.ts b/packages/core/__e2e__/agw/identity-gas.spec.ts index d2cdbef4..7d79af4e 100644 --- a/packages/core/__e2e__/agw/identity-gas.spec.ts +++ b/packages/core/__e2e__/agw/identity-gas.spec.ts @@ -6,21 +6,40 @@ */ import { Keypair } from '@solana/web3.js'; import bs58 from 'bs58'; -import { createWalletClient, getAddress, http, parseEther, type Address, type Hex } from 'viem'; +import { + createPublicClient, + createWalletClient, + fallback, + getAddress, + http, + parseEther, + type Address, + type Hex, +} from 'viem'; import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts'; import { sepolia } from 'viem/chains'; import { PushChain } from '../../src'; import { CHAIN } from '../../src/lib/constants/enums'; +import { CHAIN_INFO } from '../../src/lib/constants/chain'; import { createProgressTracker } from '@e2e/shared/progress-tracker'; -import { AGW_E2E_ENABLED, evmClient, inSeconds, setupAgw, type AgwFixture } from './_fixture'; +import { + AGW_E2E_ENABLED, + evmClient, + inSeconds, + setupAgw, + type AgwFixture, +} from './_fixture'; const d = AGW_E2E_ENABLED ? describe : describe.skip; const SINK = getAddress('0x000000000000000000000000000000000000dEaD'); async function ueaOf(address: string, chain: CHAIN): Promise
{ - const r = await PushChain.utils.account.deriveExecutorAccount(PushChain.utils.account.toUniversal(address, { chain }), { - skipNetworkCheck: true, - }); + const r = await PushChain.utils.account.deriveExecutorAccount( + PushChain.utils.account.toUniversal(address, { chain }), + { + skipNetworkCheck: true, + } + ); return getAddress(r.address); } @@ -33,7 +52,16 @@ d('agw identity', () => { const walletFor = async (agent: Address) => { const created = await f.owner.agentic.create('e2e-identity', { - rules: [{ agent, target: SINK, selector: 'value-only', validUntil: inSeconds(3600), maxValuePerCall: BigInt(1000), maxValueTotal: BigInt(10_000) }], + rules: [ + { + agent, + target: SINK, + selector: 'value-only', + validUntil: inSeconds(3600), + maxValuePerCall: BigInt(1000), + maxValueTotal: BigInt(10_000), + }, + ], }); await f.fundPC(created.wallet, parseEther('0.001')); return created.wallet; @@ -42,13 +70,24 @@ d('agw identity', () => { it('1. an EVM key on Sepolia acts through its Sepolia UEA; origin and account status stay signer-scoped', async () => { const key = process.env['EVM_PRIVATE_KEY'] as Hex; if (!key) throw new Error('EVM_PRIVATE_KEY is required'); - const uea = await ueaOf(privateKeyToAccount(key).address, CHAIN.ETHEREUM_SEPOLIA); + const uea = await ueaOf( + privateKeyToAccount(key).address, + CHAIN.ETHEREUM_SEPOLIA + ); const wallet = await walletFor(uea); - const agent = await evmClient(key, CHAIN.ETHEREUM_SEPOLIA, f.manifest.network, wallet); + const agent = await evmClient( + key, + CHAIN.ETHEREUM_SEPOLIA, + f.manifest.network, + wallet + ); expect(agent.universal.account).toBe(wallet); expect(agent.universal.origin.chain).toBe(CHAIN.ETHEREUM_SEPOLIA); expect((await agent.getAccountStatus()).uea.deployed).toBe(true); - const tx = await agent.universal.sendTransaction({ to: SINK, value: BigInt(1000) }); + const tx = await agent.universal.sendTransaction({ + to: SINK, + value: BigInt(1000), + }); expect((await tx.wait()).status).toBe(1); expect(tx.from).toBe(wallet); expect(tx.origin.startsWith('eip155:11155111:')).toBe(true); @@ -58,16 +97,43 @@ d('agw identity', () => { it('2. first use of an undeployed external UEA takes the one-time fee lock; the next action pays from the UEA', async () => { const key = generatePrivateKey(); const addr = privateKeyToAccount(key).address; - const master = createWalletClient({ account: privateKeyToAccount(process.env['EVM_PRIVATE_KEY'] as Hex), chain: sepolia, transport: http() }); - await master.sendTransaction({ to: addr, value: parseEther(process.env['AGW_E2E_FIRST_USE_ETH'] ?? '0.003'), account: master.account!, chain: sepolia }); + const transport = fallback( + CHAIN_INFO[CHAIN.ETHEREUM_SEPOLIA].defaultRPC.map((url) => http(url)) + ); + const master = createWalletClient({ + account: privateKeyToAccount(process.env['EVM_PRIVATE_KEY'] as Hex), + chain: sepolia, + transport, + }); + const origin = createPublicClient({ chain: sepolia, transport }); + const funded = await master.sendTransaction({ + to: addr, + value: parseEther(process.env['AGW_E2E_FIRST_USE_ETH'] ?? '0.003'), + account: master.account!, + chain: sepolia, + }); + await origin.waitForTransactionReceipt({ hash: funded }); const uea = await ueaOf(addr, CHAIN.ETHEREUM_SEPOLIA); const wallet = await walletFor(uea); const first = createProgressTracker(); - const agent = await evmClient(key, CHAIN.ETHEREUM_SEPOLIA, f.manifest.network, wallet, first.hook as (e: unknown) => void); - await (await agent.universal.sendTransaction({ to: SINK, value: BigInt(1) })).wait(); + const agent = await evmClient( + key, + CHAIN.ETHEREUM_SEPOLIA, + f.manifest.network, + wallet, + first.hook as (e: unknown) => void + ); + await ( + await agent.universal.sendTransaction({ to: SINK, value: BigInt(1) }) + ).wait(); expect(first.hasEvent('SEND-TX-105-01')).toBe(true); const second = createProgressTracker(); - await (await agent.universal.sendTransaction({ to: SINK, value: BigInt(1) }, { progressHook: second.hook })).wait(); + await ( + await agent.universal.sendTransaction( + { to: SINK, value: BigInt(1) }, + { progressHook: second.hook } + ) + ).wait(); expect(second.hasEvent('SEND-TX-105-01')).toBe(false); f.evidence('first-use-uea', { wallet, uea }); }, 900_000); @@ -82,12 +148,17 @@ d('agw identity', () => { chain: CHAIN.SOLANA_DEVNET, library: PushChain.CONSTANTS.LIBRARY.SOLANA_WEB3JS, }); - const agent = await PushChain.initialize(signer, { network: f.manifest.network, agenticWallet: wallet }); - const tx = await agent.universal.sendTransaction({ to: SINK, value: BigInt(1) }); + const agent = await PushChain.initialize(signer, { + network: f.manifest.network, + agenticWallet: wallet, + }); + const tx = await agent.universal.sendTransaction({ + to: SINK, + value: BigInt(1), + }); expect((await tx.wait()).status).toBe(1); expect(tx.from).toBe(wallet); expect(tx.origin.startsWith('solana:')).toBe(true); f.evidence('solana-origin-agent', { wallet, uea, tx: tx.hash }); }, 600_000); }); - diff --git a/packages/core/__e2e__/agw/universal-evm.spec.ts b/packages/core/__e2e__/agw/universal-evm.spec.ts index 57b5dff2..7e3fd39d 100644 --- a/packages/core/__e2e__/agw/universal-evm.spec.ts +++ b/packages/core/__e2e__/agw/universal-evm.spec.ts @@ -14,6 +14,8 @@ import { erc20Abi, fallback, http, + parseAbi, + parseEventLogs, parseEther, type Address, type Hex, @@ -153,6 +155,26 @@ d('agw universal evm', () => { expect(receipt.from).toBe(wallet); expect(receipt.externalTxHash).toBeTruthy(); await verifyExternalTransaction(receipt.externalTxHash as string, SEPOLIA); + const destinationReceipt = await sep.getTransactionReceipt({ + hash: receipt.externalTxHash as Hex, + }); + // Attribute the call to this wallet's CEA, independently of a shared + // counter increase. The event is emitted by CEA for each executed step. + const executed = parseEventLogs({ + abi: parseAbi([ + 'event UniversalTxExecuted(bytes32 indexed subTxId, bytes32 indexed universalTxId, address indexed originCaller, address target, bytes data)', + ]), + logs: destinationReceipt.logs, + }); + expect( + executed.some( + (event) => + event.address.toLowerCase() === cea.toLowerCase() && + event.args.originCaller.toLowerCase() === wallet.toLowerCase() && + event.args.target.toLowerCase() === counter.toLowerCase() && + event.args.data === INCREMENT + ) + ).toBe(true); expect( await f.push.readContract({ address: token, From 03e500ef659167129063b85053e0ff6f3c8e4854 Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Tue, 6 Oct 2026 03:40:15 +0530 Subject: [PATCH 20/68] docs(agw): record v4 migration and complete live acceptance evidence --- plan/agw/README.md | 14 +- plan/agw/SOURCES.md | 10 +- plan/agw/current-baseline.md | 129 +- plan/agw/external-blockers.md | 54 +- plan/agw/gaps.md | 54 +- plan/agw/implementation-plan.md | 18 +- plan/agw/implementation-review-handoff.md | 6 + plan/agw/implementation-status.md | 92 +- plan/agw/product-decisions-2026-10-04.md | 4 + plan/agw/questions-harsh.md | 40 +- plan/agw/questions-zaryab.md | 87 +- .../deployment-review-2026-10-06/README.md | 85 + .../abi-comparison.json | 48 + .../abis/engine.json | 1957 +++++++++++++++ .../abis/factory.json | 1105 +++++++++ .../abis/policy.json | 2157 +++++++++++++++++ .../abis/validator.json | 141 ++ .../abis/wallet.json | 1550 ++++++++++++ .../donut-probe.json | 157 ++ .../explorer-artifacts.json | 70 + .../previous-current-baseline.md | 88 + .../deployment-review-2026-10-06/probe.py | 76 + .../source-manifest.json | 89 + .../source/CLAUDE.md | 330 +++ .../source/docs/1_AGW.md | 570 +++++ .../source/docs/2_UniversalRulesPolicy.md | 326 +++ .../source/docs/5_SDK_Owner_Integration.md | 488 ++++ .../source/docs/addresses/donut.md | 83 + .../source/foundry.toml | 88 + .../source/src/AGW.sol | 1176 +++++++++ .../source/src/AGWFactory.sol | 355 +++ .../source/src/interfaces/IAGW.sol | 199 ++ .../src/interfaces/IUniversalRulesPolicy.sol | 111 + .../source/src/libraries/AgentConfigLib.sol | 38 + .../source/src/libraries/Errors.sol | 402 +++ .../source/src/libraries/Types.sol | 544 +++++ .../src/policies/UniversalRulesPolicy.sol | 1881 ++++++++++++++ .../source/src/validators/AgentValidator.sol | 103 + .../source/test/unit/28_multiAsset.t.sol | 590 +++++ .../supplemental-reads.json | 25 + .../verify-wire.cjs | 52 + .../wire-checks.json | 26 + .../live-acceptance-2026-10-06/README.md | 76 + .../live-evidence.json | 145 ++ .../logs/agw-final-build.log | 11 + .../logs/agw-final-e2e-tsc.log | 0 .../logs/agw-final-lib-tsc.log | 0 .../logs/agw-final-lint.log | 91 + .../logs/agw-final-live-lint.log | 9 + .../logs/agw-final-local-tsc.log | 0 .../logs/agw-final-selection-agw.log | 28 + .../logs/agw-final-selection-all.log | 79 + .../logs/agw-final-spec-tsc.log | 0 .../logs/agw-final-unit.log | 166 ++ .../logs/agw-gas-local.log | 16 + .../logs/agw-gas-unit.log | 8 + .../logs/agw-live-callonly.log | 26 + .../logs/agw-live-final-cases.log | 182 ++ .../logs/agw-live-management.log | 75 + .../logs/agw-live-multiasset.log | 11 + .../logs/agw-live-native-remaining.log | 34 + .../logs/agw-live-native-smoke.log | 65 + .../logs/agw-live-positive-buffered.log | 26 + .../logs/agw-live-positive.log | 45 + .../logs/agw-permissions-unit-final.log | 166 ++ .../origin-preflight.json | 9 + .../outbound-preflight.json | 7 + .../positive-destination-execution.json | 20 + .../positive-push-events.json | 50 + .../positive-revert-probe.json | 132 + .../live-acceptance-2026-10-06/preflight.json | 15 + .../live-acceptance-2026-10-06/preflight.ts | 30 + .../scenario-results.json | 183 ++ .../research/notion-comments-2026-10-05.md | 63 + .../svm-internals-2026-10-06/README.md | 57 + .../svm-internals-2026-10-06/SdkSvmWire.t.sol | 86 + .../generate-vectors.ts | 29 + .../logs/agentic-unit.log | 15 + .../logs/anvil-blocked.log | 134 + .../logs/forge-contracts.log | 48 + .../logs/full-unit-network-blocked.log | 600 +++++ .../logs/lib-typecheck.log | 0 .../svm-internals-2026-10-06/logs/lint.log | 10 + .../logs/local-typecheck.log | 0 .../logs/nx-build-blocked.log | 2 + .../logs/offline-unit.log | 155 ++ .../logs/spec-typecheck.log | 0 .../logs/svm-unit.log | 33 + .../logs/tsc-build.log | 0 .../network-status.json | 13 + .../svm-internals-2026-10-06/run-forge.sh | 20 + .../svm-internals-2026-10-06/sdk-vectors.json | 13 + .../v4-implementation-2026-10-06/README.md | 63 + .../abi-build-comparison.json | 36 + .../donut-readonly.ts | 23 + .../donut-sdk-readonly.json | 10 + .../logs/agw-e2e-typecheck.log | 0 .../logs/build.log | 11 + .../logs/donut-readonly-attempt.log | 1 + .../logs/e2e-agw-selection.log | 28 + .../logs/e2e-default-selection.log | 79 + .../logs/forge-build.log | 1 + .../logs/lib-typecheck.log | 0 .../logs/lint.log | 1194 +++++++++ .../logs/local-contracts.log | 15 + .../logs/local-typecheck.log | 0 .../logs/spec-typecheck.log | 0 .../logs/unit-full.log | 165 ++ .../tsconfig.agw-e2e.json | 23 + plan/agw/sdk-design-review.md | 4 + 110 files changed, 19794 insertions(+), 260 deletions(-) create mode 100644 plan/agw/research/deployment-review-2026-10-06/README.md create mode 100644 plan/agw/research/deployment-review-2026-10-06/abi-comparison.json create mode 100644 plan/agw/research/deployment-review-2026-10-06/abis/engine.json create mode 100644 plan/agw/research/deployment-review-2026-10-06/abis/factory.json create mode 100644 plan/agw/research/deployment-review-2026-10-06/abis/policy.json create mode 100644 plan/agw/research/deployment-review-2026-10-06/abis/validator.json create mode 100644 plan/agw/research/deployment-review-2026-10-06/abis/wallet.json create mode 100644 plan/agw/research/deployment-review-2026-10-06/donut-probe.json create mode 100644 plan/agw/research/deployment-review-2026-10-06/explorer-artifacts.json create mode 100644 plan/agw/research/deployment-review-2026-10-06/previous-current-baseline.md create mode 100644 plan/agw/research/deployment-review-2026-10-06/probe.py create mode 100644 plan/agw/research/deployment-review-2026-10-06/source-manifest.json create mode 100644 plan/agw/research/deployment-review-2026-10-06/source/CLAUDE.md create mode 100644 plan/agw/research/deployment-review-2026-10-06/source/docs/1_AGW.md create mode 100644 plan/agw/research/deployment-review-2026-10-06/source/docs/2_UniversalRulesPolicy.md create mode 100644 plan/agw/research/deployment-review-2026-10-06/source/docs/5_SDK_Owner_Integration.md create mode 100644 plan/agw/research/deployment-review-2026-10-06/source/docs/addresses/donut.md create mode 100644 plan/agw/research/deployment-review-2026-10-06/source/foundry.toml create mode 100644 plan/agw/research/deployment-review-2026-10-06/source/src/AGW.sol create mode 100644 plan/agw/research/deployment-review-2026-10-06/source/src/AGWFactory.sol create mode 100644 plan/agw/research/deployment-review-2026-10-06/source/src/interfaces/IAGW.sol create mode 100644 plan/agw/research/deployment-review-2026-10-06/source/src/interfaces/IUniversalRulesPolicy.sol create mode 100644 plan/agw/research/deployment-review-2026-10-06/source/src/libraries/AgentConfigLib.sol create mode 100644 plan/agw/research/deployment-review-2026-10-06/source/src/libraries/Errors.sol create mode 100644 plan/agw/research/deployment-review-2026-10-06/source/src/libraries/Types.sol create mode 100644 plan/agw/research/deployment-review-2026-10-06/source/src/policies/UniversalRulesPolicy.sol create mode 100644 plan/agw/research/deployment-review-2026-10-06/source/src/validators/AgentValidator.sol create mode 100644 plan/agw/research/deployment-review-2026-10-06/source/test/unit/28_multiAsset.t.sol create mode 100644 plan/agw/research/deployment-review-2026-10-06/supplemental-reads.json create mode 100644 plan/agw/research/deployment-review-2026-10-06/verify-wire.cjs create mode 100644 plan/agw/research/deployment-review-2026-10-06/wire-checks.json create mode 100644 plan/agw/research/live-acceptance-2026-10-06/README.md create mode 100644 plan/agw/research/live-acceptance-2026-10-06/live-evidence.json create mode 100644 plan/agw/research/live-acceptance-2026-10-06/logs/agw-final-build.log create mode 100644 plan/agw/research/live-acceptance-2026-10-06/logs/agw-final-e2e-tsc.log create mode 100644 plan/agw/research/live-acceptance-2026-10-06/logs/agw-final-lib-tsc.log create mode 100644 plan/agw/research/live-acceptance-2026-10-06/logs/agw-final-lint.log create mode 100644 plan/agw/research/live-acceptance-2026-10-06/logs/agw-final-live-lint.log create mode 100644 plan/agw/research/live-acceptance-2026-10-06/logs/agw-final-local-tsc.log create mode 100644 plan/agw/research/live-acceptance-2026-10-06/logs/agw-final-selection-agw.log create mode 100644 plan/agw/research/live-acceptance-2026-10-06/logs/agw-final-selection-all.log create mode 100644 plan/agw/research/live-acceptance-2026-10-06/logs/agw-final-spec-tsc.log create mode 100644 plan/agw/research/live-acceptance-2026-10-06/logs/agw-final-unit.log create mode 100644 plan/agw/research/live-acceptance-2026-10-06/logs/agw-gas-local.log create mode 100644 plan/agw/research/live-acceptance-2026-10-06/logs/agw-gas-unit.log create mode 100644 plan/agw/research/live-acceptance-2026-10-06/logs/agw-live-callonly.log create mode 100644 plan/agw/research/live-acceptance-2026-10-06/logs/agw-live-final-cases.log create mode 100644 plan/agw/research/live-acceptance-2026-10-06/logs/agw-live-management.log create mode 100644 plan/agw/research/live-acceptance-2026-10-06/logs/agw-live-multiasset.log create mode 100644 plan/agw/research/live-acceptance-2026-10-06/logs/agw-live-native-remaining.log create mode 100644 plan/agw/research/live-acceptance-2026-10-06/logs/agw-live-native-smoke.log create mode 100644 plan/agw/research/live-acceptance-2026-10-06/logs/agw-live-positive-buffered.log create mode 100644 plan/agw/research/live-acceptance-2026-10-06/logs/agw-live-positive.log create mode 100644 plan/agw/research/live-acceptance-2026-10-06/logs/agw-permissions-unit-final.log create mode 100644 plan/agw/research/live-acceptance-2026-10-06/origin-preflight.json create mode 100644 plan/agw/research/live-acceptance-2026-10-06/outbound-preflight.json create mode 100644 plan/agw/research/live-acceptance-2026-10-06/positive-destination-execution.json create mode 100644 plan/agw/research/live-acceptance-2026-10-06/positive-push-events.json create mode 100644 plan/agw/research/live-acceptance-2026-10-06/positive-revert-probe.json create mode 100644 plan/agw/research/live-acceptance-2026-10-06/preflight.json create mode 100644 plan/agw/research/live-acceptance-2026-10-06/preflight.ts create mode 100644 plan/agw/research/live-acceptance-2026-10-06/scenario-results.json create mode 100644 plan/agw/research/notion-comments-2026-10-05.md create mode 100644 plan/agw/research/svm-internals-2026-10-06/README.md create mode 100644 plan/agw/research/svm-internals-2026-10-06/SdkSvmWire.t.sol create mode 100644 plan/agw/research/svm-internals-2026-10-06/generate-vectors.ts create mode 100644 plan/agw/research/svm-internals-2026-10-06/logs/agentic-unit.log create mode 100644 plan/agw/research/svm-internals-2026-10-06/logs/anvil-blocked.log create mode 100644 plan/agw/research/svm-internals-2026-10-06/logs/forge-contracts.log create mode 100644 plan/agw/research/svm-internals-2026-10-06/logs/full-unit-network-blocked.log create mode 100644 plan/agw/research/svm-internals-2026-10-06/logs/lib-typecheck.log create mode 100644 plan/agw/research/svm-internals-2026-10-06/logs/lint.log create mode 100644 plan/agw/research/svm-internals-2026-10-06/logs/local-typecheck.log create mode 100644 plan/agw/research/svm-internals-2026-10-06/logs/nx-build-blocked.log create mode 100644 plan/agw/research/svm-internals-2026-10-06/logs/offline-unit.log create mode 100644 plan/agw/research/svm-internals-2026-10-06/logs/spec-typecheck.log create mode 100644 plan/agw/research/svm-internals-2026-10-06/logs/svm-unit.log create mode 100644 plan/agw/research/svm-internals-2026-10-06/logs/tsc-build.log create mode 100644 plan/agw/research/svm-internals-2026-10-06/network-status.json create mode 100644 plan/agw/research/svm-internals-2026-10-06/run-forge.sh create mode 100644 plan/agw/research/svm-internals-2026-10-06/sdk-vectors.json create mode 100644 plan/agw/research/v4-implementation-2026-10-06/README.md create mode 100644 plan/agw/research/v4-implementation-2026-10-06/abi-build-comparison.json create mode 100644 plan/agw/research/v4-implementation-2026-10-06/donut-readonly.ts create mode 100644 plan/agw/research/v4-implementation-2026-10-06/donut-sdk-readonly.json create mode 100644 plan/agw/research/v4-implementation-2026-10-06/logs/agw-e2e-typecheck.log create mode 100644 plan/agw/research/v4-implementation-2026-10-06/logs/build.log create mode 100644 plan/agw/research/v4-implementation-2026-10-06/logs/donut-readonly-attempt.log create mode 100644 plan/agw/research/v4-implementation-2026-10-06/logs/e2e-agw-selection.log create mode 100644 plan/agw/research/v4-implementation-2026-10-06/logs/e2e-default-selection.log create mode 100644 plan/agw/research/v4-implementation-2026-10-06/logs/forge-build.log create mode 100644 plan/agw/research/v4-implementation-2026-10-06/logs/lib-typecheck.log create mode 100644 plan/agw/research/v4-implementation-2026-10-06/logs/lint.log create mode 100644 plan/agw/research/v4-implementation-2026-10-06/logs/local-contracts.log create mode 100644 plan/agw/research/v4-implementation-2026-10-06/logs/local-typecheck.log create mode 100644 plan/agw/research/v4-implementation-2026-10-06/logs/spec-typecheck.log create mode 100644 plan/agw/research/v4-implementation-2026-10-06/logs/unit-full.log create mode 100644 plan/agw/research/v4-implementation-2026-10-06/tsconfig.agw-e2e.json diff --git a/plan/agw/README.md b/plan/agw/README.md index 3b30aeb8..414e0c33 100644 --- a/plan/agw/README.md +++ b/plan/agw/README.md @@ -1,10 +1,12 @@ # AGW SDK planning -This package contains the current SDK plan, source snapshots, open decisions and contract validation evidence. Implementation of the unblocked steps is on branch `feat/agw-sdk-impl`; see [implementation status](implementation-status.md) and the [review handoff](implementation-review-handoff.md). No live AGW transaction has been sent; no compatible deployment has been verified or registered. Harsh has replied; remaining follow-ups are in the updated question docs. +This package contains the SDK implementation plan, source snapshots, open decisions and validation evidence. Current work is on feat/agw-sdk-v4. Runtime commits are a66ff7d (v4/SVM foundations) and b68bab7 (gas headroom); current validation is linked below. Native/EVM support now uses the checked Donut v4 deployment; old runtime adapters/ABIs/fixtures were removed. All 25 registered AGW scenarios have passing bounded live coverage, including native/UEA identities and Sepolia outbound success/failure. -The target API is [Notion page 5](notion/5-sdk-agw.md), exported October 3, 2026 at 13:23 IST. The tested contract baseline is pushAgenticWallet_v3@e704d5b: sender-authorized execution and checkpoints exist in source, while the new multi-asset format, grant reference, editable label and envelope version still require matching artifacts and deployment verification. +Latest: [live acceptance and fixes](research/live-acceptance-2026-10-06/README.md), following the [v4 migration](research/v4-implementation-2026-10-06/README.md). The unrestricted full core unit run passes 1,947 tests; the actual-contract harness passes 53. Build and four typechecks pass. Native defaults/raw-offset API/multi-rule selection decisions, absent ref/labels, public SVM integration and release scope remain explicit. -Latest direction: [Harsh product decisions, October 4](product-decisions-2026-10-04.md). Page 5 was downloaded again and its body is unchanged after link normalization. These newer product replies supersede the older provisional recommendations; the clear scope changes are now implemented. H3 defaults and raw-offset API clarification remain pending. +The public target remains [Notion page 5](notion/5-sdk-agw.md), qualified by [Harsh's replies](product-decisions-2026-10-04.md) and [live comments](research/notion-comments-2026-10-05.md). The [v4 deployment/owner-guide review](research/deployment-review-2026-10-06/README.md) records the supplied deployed wire definitions. Historical adapter-absence statements in that review describe the pre-migration inspection, not current implementation. + +Latest SVM work: [internal codec/account/payload foundation](research/svm-internals-2026-10-06/README.md) now passes 23 unit and 10 in-process actual-contract checks. Public mapping/dispatch remains gated. Network permissions are restored. All seven SVM Anvil tests now pass and the unfiltered core unit suite passes, including the four previously network-blocked titles. Public Solana execution remains untested. ## Start here @@ -12,7 +14,7 @@ Latest direction: [Harsh product decisions, October 4](product-decisions-2026-10 | --- | --- | | [Current baseline](current-baseline.md) | Source revisions, capabilities and remaining differences | | [SDK design review](sdk-design-review.md) | Proposed internal architecture and execution flows | -| [Gap register](gaps.md) | Current G01–G24 findings and closure criteria | +| [Gap register](gaps.md) | Current G01–G26 findings and closure criteria | | [SDK owned review](sdk-owned-review.md) | Internal decisions, existing-code evidence and 183 passing unit tests | | [Implementation plan](implementation-plan.md) | Complete 17-step roadmap, module layout, assumptions, API coverage and PR sequence | | [Implementation agent prompt](implementation-agent-prompt.md) | Handoff instructions, unit/E2E requirements and existing runner conventions | @@ -22,7 +24,7 @@ Latest direction: [Harsh product decisions, October 4](product-decisions-2026-10 | [Integrator obligations](contract-integrator-obligations.md) | Contract-delegated SDK/product requirements | | [External blockers](external-blockers.md) | Remaining defaults/type clarification and contract/deployment dependencies | | [Questions for Harsh](questions-harsh.md) | Product decisions and recommendations | -| [Questions for Zaryab](questions-zaryab.md) | Contract surface, funding and deployment questions | +| [Questions for Zaryab](questions-zaryab.md) | Ref/label v1 scope and representative SVM integration fixtures | | [Review summary](review-summary.md) | Consequential independent-review corrections | ## Sources and evidence @@ -34,4 +36,4 @@ Latest direction: [Harsh product decisions, October 4](product-decisions-2026-10 Older planning revisions, duplicated exports, superseded validation runs and the full independent-review working package were archived locally outside this repository. The review summary preserves the key corrections. Historical paths in the retained prior manifest describe the earlier pull and may refer to pruned archives. -Before sharing questions, refresh remote refs and Notion again, record exact revisions and remove questions answered by newer evidence. No messages, deployments or testnet transactions have been sent by this planning work. +Before sharing questions, refresh remote refs and Notion again, record exact revisions and remove questions answered by newer evidence. No team messages or contract deployments have been sent by this work. Authorized, bounded testnet transactions are recorded in the live acceptance evidence. diff --git a/plan/agw/SOURCES.md b/plan/agw/SOURCES.md index f061304a..bbe04118 100644 --- a/plan/agw/SOURCES.md +++ b/plan/agw/SOURCES.md @@ -1,9 +1,13 @@ # AGW source links and refresh procedure +October 6 contract refresh: fetched deploy-agw@10a24f101e2e6e0a9b76517b29f5cdb1aa967796; address book/owner guide report deployed source e8db74815cfbbf5389593805e464fe8d85f7f735, with no src difference between those commits. [GitHub snapshots/hashes, verified ABIs, Donut read-only evidence and SDK review](research/deployment-review-2026-10-06/README.md). This does not replace the Notion full-export manifest or imply SDK v4 support is already registered. + Latest complete Notion export: October 3, 2026 at 13:23 IST. All 12 pages were imported; pages 1 and 5 changed. Page 5 defines the target public SDK API. Native exports omit comment threads. Focused October 4 recheck: page 5 was downloaded again; its body matches the saved snapshot after normalizing links. [Comparison evidence](research/notion-check-2026-10-04/comparison.json). This was not a full refresh and does not replace the full-import manifest. Harsh’s newer replies are recorded separately in [product decisions](product-decisions-2026-10-04.md). +Focused October 5 comment review: live All discussions on pages 5 and 1, plus the overview’s visible page state, were inspected through Chrome. [Comment evidence and SDK impact](research/notion-comments-2026-10-05.md). Harsh’s new multiple-rules direction needs same-agent scope/send-selection clarification; token-independence wording needs a final definition. This was not a body export or contract refresh. Comments are recorded separately; snapshot hashes/pull timestamps remain unchanged. + ## Notion inventory | Document | Source | Local snapshot | Authority | @@ -25,7 +29,9 @@ The [manifest](source-manifest.json) stores stable page IDs, pull times and hash ## Contract sources -- [AGW e704d5b](https://github.com/pushchain/push-agentic-wallets/tree/e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9), branch pushAgenticWallet_v3. nomenclature-changes was merged and deleted. +- **Current deployment source:** [AGW e8db748](https://github.com/pushchain/push-agentic-wallets/tree/e8db74815cfbbf5389593805e464fe8d85f7f735). +- **Current documentation:** [owner SDK guide](https://github.com/pushchain/push-agentic-wallets/blob/10a24f101e2e6e0a9b76517b29f5cdb1aa967796/docs/5_SDK_Owner_Integration.md), [v4 Donut address book](https://github.com/pushchain/push-agentic-wallets/blob/10a24f101e2e6e0a9b76517b29f5cdb1aa967796/docs/addresses/donut.md). Refreshable branch links: [guide](https://github.com/pushchain/push-agentic-wallets/blob/deploy-agw/docs/5_SDK_Owner_Integration.md), [addresses](https://github.com/pushchain/push-agentic-wallets/blob/deploy-agw/docs/addresses/donut.md). +- **Earlier SDK fixture source:** [AGW e704d5b](https://github.com/pushchain/push-agentic-wallets/tree/e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9); nomenclature-changes was merged and deleted. - [AGW design](https://github.com/pushchain/push-agentic-wallets/blob/e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9/docs/1_AGW.md) and [policy design](https://github.com/pushchain/push-agentic-wallets/blob/e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9/docs/2_UniversalRulesPolicy.md). - [Core marketplace cb69e0b](https://github.com/pushchain/push-chain-core-contracts/tree/cb69e0ba101bef1bb4440e54b2c45396be3e92ce). - [Gateway eight-field baseline bcbf7df](https://github.com/pushchain/push-chain-gateway-contracts/tree/bcbf7df42e8e6dd11088a43bcc0b056a54ea0a18). @@ -41,6 +47,8 @@ Source revisions describe inspected code, not a guarantee of current remote head 4. Review changed requirements and update affected plans/questions; do not declare source features deployed without evidence. 5. Re-fetch contract refs and record exact SHAs before sharing. +Also review **All discussions**, including resolved threads, on relevant live pages. Record author, displayed date/age, attached block and interpretation separately from exported bodies. A body-only comparison cannot establish that product decisions are unchanged. + ```sh python3 plan/agw/scripts/import-notion-exports.py overview.zip legacy-sdk.zip address-book.zip flow.zip --dry-run python3 plan/agw/scripts/import-notion-exports.py overview.zip legacy-sdk.zip address-book.zip flow.zip diff --git a/plan/agw/current-baseline.md b/plan/agw/current-baseline.md index f7f190c4..2b6166e2 100644 --- a/plan/agw/current-baseline.md +++ b/plan/agw/current-baseline.md @@ -1,86 +1,73 @@ # Current validated AGW baseline -> October 4 update: [Harsh’s replies](product-decisions-2026-10-04.md) supersede earlier provisional approval/default/helper/history/compiler recommendations below. Use [remaining dependencies](external-blockers.md) for current blockers. The clear scope changes and sender-preserving native batching are now implemented; H3 defaults remain unchanged pending clarification. See [alignment evidence](research/product-alignment-2026-10-04/README.md). +Updated October 6, 2026 after the v4 deployment notice, source/ABI inspection and read-only Donut probe. **The v4 deployment and native/EVM SDK adapter/codecs are now integrated locally. All 25 registered AGW live scenarios have passing selected-run coverage.** [Full review and evidence](research/deployment-review-2026-10-06/README.md). -Updated October 3, 2026 after reviewing checkpoint commit 6b7dbf4 and current head e704d5b. This page supersedes earlier recommendations; consequential corrections are retained in the [review summary](review-summary.md). The SDK Notion page remains the target API; conflicts below are recorded for resolution, not silently resolved in favor of code. +The public SDK target remains Notion page 5, qualified by Harsh's later replies/comments. The new owner guide establishes deployed wire behavior; mismatches in public ref/labels/defaults/selection remain explicit. [Prior October 3–5 baseline](research/deployment-review-2026-10-06/previous-current-baseline.md) is retained as historical evidence. ## Pinned sources -| Repository | Current inspected branch and commit | +| Source | Revision and role | | --- | --- | -| AGW | `pushAgenticWallet_v3@e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9` | -| Core | `universalMarketplace_v1@cb69e0ba101bef1bb4440e54b2c45396be3e92ce` | -| Gateway | Eight-field `pc20-3rd-iteration@bcbf7df42e8e6dd11088a43bcc0b056a54ea0a18`; six-field older `main@d02070d` | -| SDK | `167fdc6243ecfe5d97735a6124662c7d2084d126` | -| Notion | October 03, 2026 at 13:23 IST full export; page 1 and page 5 changed, 10 pages unchanged | +| AGW deployment source | e8db74815cfbbf5389593805e464fe8d85f7f735, reported by address book/owner guide | +| AGW documentation | deploy-agw@10a24f101e2e6e0a9b76517b29f5cdb1aa967796; src identical to e8db748 | +| SDK contract adapter | V4 only (e8db748); Donut registry populated; old runtime/test generation removed | +| Core marketplace | Prior pin cb69e0ba101bef1bb4440e54b2c45396be3e92ce; not freshly fetched | +| Gateway source | Prior eight-field pin bcbf7df42e8e6dd11088a43bcc0b056a54ea0a18; live implementation slot checked | +| Notion | Last full export October 3 at 13:23 IST; focused October 4 body comparison and October 5 comment review; no new export here | -AGW remote branches were checked through GitHub API on October 3: nomenclature-changes was deleted after merging and pushAgenticWallet_v3 points to e704d5b. Core remains pinned at cb69e0b from the existing evidence; no fresh core fetch was performed in this pass. The head adapter keeps the SmartSession source unchanged. It replaces cryptographic session-key validation with a sender-checking adapter. The wallet binds the sender before calling the engine and constructs `USE || rulesId || msg.sender` itself. Engine account binding and disabled alternate paths are essential invariants. **No engine fork is recommended.** +[Saved GitHub sources and hashes](research/deployment-review-2026-10-06/source-manifest.json) are separate from the Notion manifest. [Verified ABIs](research/deployment-review-2026-10-06/abis/) came from the explorer. This review did not locally rebuild runtime bytecode or rerun the full contract/SDK suites. -## Compatibility status +## Donut v4 deployment -| Surface | Current status | Remaining work | -| --- | --- | --- | -| `executeAsAgent`, `agentOf`, authorization event | Implemented in AGW source | Verify selected new deployment and preserve adapter invariants; G02 source dependency satisfied | -| Agent config | Exact `abi.encode(address agent)` | SDK codec and generation-specific validator context | -| Rule ID | `keccak256(abi.encode(validator, abi.encode(agent), bytes32(grantNonce)))` | Page 5 helper signature/constants need alignment. Chain is not hashed; key records by wallet plus rule ID | -| Owner batching | Documented design; local tests support atomic replacement | SDK implementation and final-generation regression tests; no need to ask whether batching is intended | -| Agent arrays | Wallet dispatch remains single/default. EVM destination multicall supports 1–10 calls | Define native arrays separately; supporting multiple native actions in a rule is a public type choice, not the same as atomic multi-call dispatch | -| Duplicate agent-chain rules | Accepted by contract with independent IDs/budgets | SDK preflight rejection and explicit ambiguity error are proposed; hard on-chain uniqueness is not assumed necessary | -| Checkpoints | Implemented in source at 6b7dbf4, included in e704d5b; count and last-block views plus Checkpointed event | Compare snapshot counts, account for per-call and lifecycle ticks, and verify selected new deployment | -| Grant job ref, labels, envelope version | Still absent | Agree next-generation surface and spec consequences | -| Historical rules | Revoke removes agent config and enabled actions, while URP terms persist | Event agent attribution or nested-call reconstruction needed if revoked rules are returned | -| expectedCEA | Required universal wire term, derived from AGW plus destination context and committed at grant | SDK must derive it, show it in previews, include it in encodeRules context, and monitor derivation drift | -| Binder | Never present in reviewed code; live Notion page checked October 3 says dropped for v1 | No binder/setBinder implementation required unless a new explicit product decision reverses this | -| Funding approval | Push gateway requires allowance for PRC20 pulls | Existing owner execute mechanism validated in four local fixture tests; implement setup/replenishment and verify production pull/burn/settlement | -| Destination approvals | Page 5 example permits an unpinned spender; current marketplace rejects approve/increaseAllowance | Product policy and owner-controlled approvals; selector filtering alone is not a general guarantee against malicious/custom approval methods | -| Gateway shape | Eight fields in current branch and observed live dispatcher; main's six fields are older | Ask only whether a future removal is actually planned | -| Agent outbound composer | Existing Route 2 request cannot be used unchanged | Empty recipient, AGW revert recipient, nonzero maxPCForGas, policy-compatible multicall and AGW PC accounting | -| Outbound tracking | Existing tracker uses tx hash/events/UTX ID | Reuse provisionally; verify live wrapped outbound. Response `from` and progress route integration still need adaptation | -| Marketplace expiry | Core terms require exact equality with job expiry | Reconcile Notion's <= and >= statements; equality applies to this marketplace compile path, not every standalone AGW rule | -| SVM destination | Source and policy tests available | Typed SDK representation, obligations 19–23, deployment capability; do not claim an agreed deferral | -| Generation detection | Wallet clones immutable; factory implementation frozen by intended design | New generation/address context, supported factory registry, version identification and migration disclosures | - -## Chain observations - -Historical read-only probes on October 2 at Donut block **23818643** confirmed the documented factory still points to `0xD7FEF338572f96edBeF89E720f1F0fF1284ec79C`, that implementation reports `push.agentwallet.1.0.0`, and the documented URP reports `1.0.0`. Gateway implementation `0x1e412939780f2b834dc42c7ac58d9f99888da659` contains the eight-field PUSH4 selector and not the six-field selector. See [probe](research/donut-probe-2026-10-02.json). - -These observations validate the named historical deployment, not a global claim that nobody has deployed head elsewhere. No matching new-generation deployment manifest is available. A PUSH4 scan supports dispatch identification but is not complete ABI verification. - -## SDK-owned decisions - -Implement existing namespace structure, signer reuse, receipt identity adaptation, typed failure metadata, Web2 compatibility, generation guards and internal read reconstruction in the SDK. Document the chosen list/read-only/reinitialize behavior in an SDK decision record. Product consultation is needed only when that choice changes an explicit public promise or introduces a new public parameter. - -Do not silently change per-send lookup to filter expired rules: page 5 says lookup selects enabled agent/chain rules and leaves policy checks on-chain. Any expiry precheck is a behavior change to document. A JSON-RPC batch is not necessarily one logical read: IDs must be enumerated before their agent/config reads can be constructed. Avoid promising a single round trip without an index or contract view. - -Retries for stale spend must be bounded and must not repeat wallet signatures without user-visible control. Revoking first is an available alternative with different atomicity and permission-interruption semantics, not a transparent retry. - -## Next live acceptance test - -After a compatible deployment and authorized test funding are available, send a positive-amount EVM agent outbound with owner-established gateway allowance, empty recipient, AGW refund recipient and a policy-compliant multicall. Verify real burn, node/TSS handling, destination execution, receipt identity and unchanged hash-based tracking. No such transaction has been broadcast by this review. - -## Checkpoint revision and current source freshness +Chain 42101, RPC https://evm.donut.rpc.push.org/, pinned block **23931055**. [Probe](research/deployment-review-2026-10-06/donut-probe.json). -The no-persistent-storage invariant was deliberately revised: owner execution may touch the single packed checkpoint slot, while remaining independent of engine/policy health. `check-execute` now pins the B2 checkpoint revision. A grant starts one tick; every owner call ticks before dispatch; each revoked ID ticks once; successful grants tick once. `executeWithSig` has the same per-call behavior. Failed transactions unwind the ticks; agent execution does not tick. - -For assert/revoke/grant inside one owner batch, the delta is five: OWNER_ACTION(assert), OWNER_ACTION(revoke), RULES_REVOKED, OWNER_ACTION(grant), RULES_GRANTED. Checkpoint ref is a call hash or rulesId; it is not the missing job/card ref parameter on grant. - -The new accepted limit 34 states that pre-existing allowances can be pulled without a wallet call/checkpoint. Checkpoints detect owner-door activity, not every possible balance change. The evaluator must define how allowance-driven changes affect its verdict. A baseline count and correct funding-call ordering are required; a sinceBlock filter alone cannot detect all same-block changes. - -Fresh Notion page 1 was inspected on October 3 and still says binder was dropped for v1. The complete export succeeded. All 12 saved page bodies now reflect the October 3 export. Pages 1 and 5 changed; see the refresh report. Binder is recorded as dropped in the source index and review summary. - -## Latest SDK target after successful refresh - -Page 5 is still authoritative: create deploys/grants only, funding is separate, UniversalRule uses assets[] and maxGasPerCall, and AGENTIC-TX-103 is removed. New page 1 section 4c proposes per-token accounting and 0–8 assets. The tested e704d5b ABI does not implement that new wire format; retain its single-asset fixtures as historical baseline, not the future codec. - -Define per-asset Spent and replacement assertion semantics, empty-asset routing, destination-token/native-marker resolution and the proposed bytes32 expectedCEA encoding. The prior universal defaults/maxAmountTotal naming cannot simply carry forward. Proposed AssetCap.maxTotal zero means unlimited; native defaults remain a separate question. - -See [successful refresh report](research/notion-refresh-2026-10-03.md). All earlier download failures remain historical evidence; download permission was sufficient for this run. - -The follow-up [external blocker register](external-blockers.md) records what still needs team input after SDK-owned closure. Remote refs were rechecked unchanged; the Notion snapshot date above is unchanged. +| Component | Address | +| --- | --- | +| Factory proxy | 0xaF88D0FD947afAe7bBb8F34e8417DCfc165e1aaF | +| URP proxy | 0x603E7f0aF6e1aAFf46DDfb28b1e99364f8BC59af | +| Wallet implementation | 0x96D69ec7e6cDdaD414e656B5c9DCA24587DF713c | +| AgentValidator | 0x068EE2388475A98EE1f5a434C58bFF3444fffFe6 | +| SmartSession | 0x165A5E6782f39D30B38c7D97e1303e4CB2aD102a | +| Gateway | 0x00000000000000000000000000000000000000C1 | +Code sizes, factory/policy implementation slots, policy admin and wallet/policy wiring match the new book. Factory is unpaused; URP version is 3.1.0; pushChainHash matches eip155:42101. Wallet accountId remains push.agw.1.0.0 and is insufficient to distinguish envelope generations. Address book reports deployment blocks 23923806–23923810; release manifest should preserve deployment/log provenance. -## Deployment coordination October 5 +The earlier supplied historical addresses are superseded for new v4 integrations. Wallet clones remain generation-specific and do not migrate; prediction is stable within its factory context, not globally across factories. -Shoaib supplied the fixed deployment-address table and will receive Zaryab’s completion notice. The table exactly matches the [saved AGW address book](notion/agw-address-book-donut-2026-09-04.md): factory proxy `0xF1A131571f89fD06890576e6cD0154114ACBBc8b`, wallet implementation `0x959ED7f6943bdd56B3a359BAE0115fef4aa07e17`, UCEP `0x79F07D379BdC26468E48025a61bC955909522c1D`, PushSessionValidator `0x5A59a5Ac94d5190553821307F98e4673BF3c4a1D`, and engine `0x7540f9a59693d51CFB4A3727141eAE4836F96749`. Remaining dependencies/admin addresses are preserved in that source snapshot. +## Compatibility and remaining work -The deployment question is removed from the team handoff. These are known address inputs, not a newly verified target-generation manifest: the table uses the earlier PushAgentWallet/UCEP/PushSessionValidator naming and sizes. Once Zaryab reports completion, verify factory wiring, deployed wallet/policy ABI, source revision and event start blocks against the intended release. No RPC probe or SDK registry change occurred in this documentation pass. +| Surface | Deployed definition | SDK status/action | +| --- | --- | --- | +| Owner/agent doors | execute and sender-gated executeAsAgent; unchanged SmartSession | Preserve model, adapt/test selected generation; no engine fork | +| Session/IDs | abi.encode(agent), salt overwritten by grantNonce; rulesId wallet-scoped | Existing identity logic retained, new validator context | +| All policy envelopes | uint16 version=1, chainNamespace, body | Envelope 1 implemented; old envelope rejected by actual contracts | +| Universal EVM | 1–8 ordered AssetCaps, maxGasPerCall, address expectedCEA | Implemented, including source-chain/token identity validation and v4 reads | +| No-movement rules | One destination gas PRC20 cap at 0/0 when user assets empty | Implemented; actual-contract call-only case passes | +| Total ceilings | maxUint256 unlimited, zero hard zero | Universal max default/explicit zero implemented; native omission choices partly open | +| Internal replacement guard | assertSpent(configId,wallet,uint256[]) compares all totals in asset order | SDK implemented; second-token intervening spend rolls back replacement | +| Native terms | Same body layout, one config per action; envelope changed | V4 native tests pass; ABI offset validation retained | +| Multiple rules | Several same-agent/same-chain grants supported | Management permits multiplicity; ambiguous sends fail; H6 selection remains | +| Checkpoints | Stored count/last block, three event kinds, per-owner-call/lifecycle ticks | Earlier read/update design retained; v4 acceptance pending | +| Grant ref / label | Grant has no ref; label is deployment event only; no setLabel | Explicit capability gates; Z1.3 asks v1 scope/delivery | +| SVM | Full multi-asset terms/program/account/data pins supplied | Public mapping, PDA/ATA/registry resolution, payload and acceptance remain | +| Gateway request | Eight-field live implementation, selector 0x77b86bec | Dedicated context, listed-token choice and maxGasPerCall implemented | +| Allowance | Consume separate owner-established allowance | Keep existing race-safe behavior; Live allowance/token debit passes; remaining identity coverage explicit | +| Refund spend credit | creditRevert gains token; executor still does not call it | Known Push-core dependency; ordinary returns do not lower spent | +| Tracking/events | Metered/revert events include token | ABIs/imports updated; live call-only, positive-amount and external-failure tracking pass | + +The ABI comparison found matching factory/wallet/engine function/event/error signatures and return shapes, but changed policy getters, assertions, credit and events. Same wallet ABI does not imply same semantics: its envelope decoder changed. [Comparison](research/deployment-review-2026-10-06/abi-comparison.json). + +## Focused verification + +Four checks passed: version-1 envelope round-trip/old first-word incompatibility; synthetic ordered two-asset tuple round-trip; live v4 getConfig decode with old-ABI rejection; array assertion encoding. [Results and limits](research/deployment-review-2026-10-06/wire-checks.json). This is not a rule-grant, stale-spend transaction or funded E2E proof. + +The unrestricted run passes 1,947 unit and 53 actual-contract tests. All five explorer ABI sets match the isolated build. Donut is registered and all 25 registered native/EVM/identity cases have passing coverage. [Current acceptance evidence](research/live-acceptance-2026-10-06/README.md). + +## Remaining decisions and acceptance + +- Harsh: native omission defaults/public maxValueTotal, raw-offset authoring/read model, multi-rule send selection. [Open draft](questions-harsh.md). +- Zaryab: ref/label v1 scope and representative SVM integration fixtures. Wire/accounting/deployment delivery requests are removed. [Open draft](questions-zaryab.md). +- SDK: native/EVM migration is implemented and locally validated. Public SVM mapping/composition and release scope decisions remain. No legacy runtime adapter is retained. +- Live: registered native/EVM/UEA/7702 and Sepolia success/failure scenarios pass, including independent CEA execution attribution. Public SVM destination acceptance remains after integration. Authorized testnet transactions are recorded in the live report. + +Checkpoint count semantics remain per action, not per transaction: assert/revoke/grant adds five ticks; failed transactions unwind ticks; agent calls do not tick. Pre-existing allowances may change balances without checkpoints. Preserve internal spend assertions even though public spent records are removed. diff --git a/plan/agw/external-blockers.md b/plan/agw/external-blockers.md index a1665fc4..481eafd0 100644 --- a/plan/agw/external-blockers.md +++ b/plan/agw/external-blockers.md @@ -1,37 +1,45 @@ # Remaining external dependencies for AGW -Updated October 4, 2026 from [Harsh’s supplied replies](product-decisions-2026-10-04.md). The earlier count of seven standalone decision areas is historical. Several product decisions are now settled; implementing them is SDK work, not a reason to keep asking the same questions. +Updated October 6, 2026 after the [v4 deployment and owner-guide review](research/deployment-review-2026-10-06/README.md). Contract wire/accounting definitions and deployment addresses are supplied; distinguish remaining decisions from SDK implementation and live acceptance. -## Still needs external information or delivery +## Remaining team input -| Area | Owner | Remaining dependency | +| Area | Owner | Remaining answer | | --- | --- | --- | -| Exact defaults and revised fields | Harsh H3 | Final omission/explicit-zero table and the referenced maxValueTotal change; fresh page-5 body still matches the older snapshot | -| Native decoded-rule representation | Harsh H4.5 | Decide whether raw offsets are public read/write inputs or an internal/separate decoded representation | -| Universal accounting and encoding | Zaryab Z1 | Final multi-asset terms, internal per-token reads, expected-spend assertion ABI/vectors, empty-assets routing and envelope/CEA representation | -| Contract metadata and destination capabilities | Zaryab Z1 | Ref/label scope and matching SVM artifacts | -| Deployment readiness | Agreed coordination; SDK verifies after completion notice | Fixed addresses are known; Zaryab will notify Shoaib. This is a release dependency, not an open deployment question | +| Native optional-input defaults/public fields | Harsh H3 | Native value omission defaults, referenced public maxValueTotal change, confirmation of remaining omission rows and token-independence wording | +| Native decoded-rule representation | Harsh H4.5 | Public raw-offset read/write authoring versus separate decoded/internal form | +| Multiple-rule execution | Harsh H6 | Explicit caller rule selection versus a defined automatic strategy, including arrays/overlapping rules; same-agent capacity is supplied | +| Metadata scope | Zaryab Z1.3 with Harsh | Whether absent grant ref/editable label will be delivered or explicitly deferred from v1 | +| Representative SVM integration fixture | Zaryab Z1.4, where available | Cluster gateway/registry and protected-account derivation inputs, valid envelope/outbound example and expected failure cases | -Hiding public spend does not remove internal spend assertions. Deferring public history does not remove the need to distinguish enabled, expired and revoked permissions for execution. +The owner guide retains assets[] on the rule, with each listed token usable by every allowed call. Harsh's token-independence comment is not treated as permission to remove token limits. SVM wire types are supplied; the remaining fixture request does not reopen struct delivery. -## Resolved scope and SDK alignment work +## Delivered — now SDK work -- Approval selector policy belongs to UI/marketplace. Remove the SDK's blanket policy rejection; retain structural validation and contract checks. -- Generation machinery stays internal; adjust public helper exposure instead of requiring public factory/validator parameters. -- Public multi-asset spend is unnecessary; align read records while retaining internal accounting. -- Revoked-rule history is deferred from v1. -- compileCard is outside standalone AGW. Its shared marketplace schema is no longer an AGW release blocker. -- Native arrays are desired. Our earlier claim that the single-call AGW door requires a contract batching change was too broad. Sender-preserving UEA/7702 outer batches can contain multiple single agent-door calls. Implement and validate that path; never silently label sequential fallback atomic. -- Gateway allowance setup already uses separate owner transactions. Creation index binding, atomic updates and response replay have local implementation/review evidence. +- V4 factory/URP addresses and implementation/engine/validator wiring: checked read-only on Donut block 23931055. The new book supersedes the earlier historical address table for new integrations. +- Multi-asset EVM/SVM wire layouts, envelope version 1, address EVM expectedCEA and per-asset spend reads/assertions: delivered and verified ABIs saved. +- Universal total encoding: maxUint256 means no total limit; explicit zero permits no movement. Empty user assets need one destination gas PRC20 routing cap at 0/0, not an empty wire array. +- Multiple same-agent/same-chain rules: contract guide explicitly permits them; product accepts multiplicity. Choosing the rule for a send remains H6. +- Separate owner allowance, immutable-wallet generations, internal accounting and sender-preserving native batching: preserve the existing design while migrating to v4. -The clear product decisions are now implemented: approval-policy rejection and obsolete public exports are removed, reads are active-only, and native arrays require atomic transport. H3 defaults were deliberately not changed. [Implementation status](implementation-status.md) distinguishes current code from the new direction. +Native/EVM v4 migration is now implemented: adapter/registry, envelopes, multi-asset reads/codecs, ordered assertions, outbound token choice and ABI integration. The actual-contract harness is ported; runtime/test legacy artifacts were removed. [Current evidence](research/v4-implementation-2026-10-06/README.md). SVM SDK mapping/composition and live acceptance remain. -## Freshness and delivery gates +## Previously settled scope -SDK page 5 was downloaded October 4 and matches the saved body after link normalization; other registered pages were not refreshed. [Evidence](research/notion-check-2026-10-04/comparison.json). AGW remote head remains e704d5b. No compatible deployment was verified in this pass. +Approval screening belongs to UI/marketplace; structural/ABI validation remains in the SDK. Generation details and spend stay internal, public revoked history is deferred, and compileCard remains outside standalone AGW. Native arrays use atomic sender-preserving UEA/7702 batching, with explicit failure when unavailable. No request for those answered choices is reopened. -Continue SDK work against explicit adapters and assumptions. A compatible manifest, internal multi-asset artifacts and authorized live acceptance remain necessary before enabling the final release. The source snapshots remain unedited evidence; the product decision record captures the newer scope direction. +## Platform and release gates -## Deployment coordination October 5 +creditRevert still depends on Push-core executor integration; the source explicitly says failures are not yet credited. Ordinary money returning does not lower spent. No-code at the module account is not by itself evidence of a defect. -The deployment request was removed from Zaryab’s question document at Shoaib’s direction. The supplied fixed-address table matches the [saved address book](notion/agw-address-book-donut-2026-09-04.md). Keep it as known address input; after the completion notice, the SDK team verifies deployed code/wiring, matched ABI and event start blocks, then prepares the registry/E2E configuration. No registry entry was enabled by this documentation update. +All 25 registered AGW live scenarios have passing bounded selected-run coverage, including UEA/7702 identities/batching, lifecycle, allowance, response hooks/replay and Sepolia outbound success/failure. This resolves the outstanding native/EVM acceptance tasks; public Solana destinations still need integration and live coverage. External product/scope decisions above remain separate. [Current evidence](research/live-acceptance-2026-10-06/README.md). + +## Freshness + +AGW deployment source e8db748; documentation head deploy-agw@10a24f1, with identical src. Explorer-verified ABIs and a pinned RPC probe are saved in the [review bundle](research/deployment-review-2026-10-06/README.md). No local runtime rebuild or full suite was run in this pass. Core/gateway source pins were not refreshed. + +Notion's last full export remains October 3, with focused October 4 body and October 5 comment checks. The GitHub guide is a separate deployed-wire source, not a silent replacement for the target public SDK API. + +## SVM foundation and current execution environment + +[SVM internals](research/svm-internals-2026-10-06/README.md) are implemented and tested offline; public mapping/dispatch remains pending. Shoaib authorized .env-backed funding for tests. The current sandbox blocks Donut DNS and Anvil's localhost RPC, so keys are not loaded and no funds are sent. Networking availability is an execution blocker, not a missing product answer. diff --git a/plan/agw/gaps.md b/plan/agw/gaps.md index 7657d7bd..516e8fbe 100644 --- a/plan/agw/gaps.md +++ b/plan/agw/gaps.md @@ -1,19 +1,21 @@ # AGW contract and SDK gap register -Updated October 4, 2026 after [Harsh’s replies](product-decisions-2026-10-04.md) and implementation commit `cae7206`. This register distinguishes unresolved dependencies, implemented SDK work, deferred scope and historical corrections. G01–G25 are tracking IDs, not a count of open defects. +Updated October 6, 2026 after the [v4 deployment/owner-guide review](research/deployment-review-2026-10-06/README.md), [Harsh’s replies](product-decisions-2026-10-04.md), v4 implementation on feat/agw-sdk-v4, and [live Notion comments](research/notion-comments-2026-10-05.md). This register distinguishes unresolved dependencies, implemented SDK work, deferred scope and historical corrections. G01–G26 are tracking IDs, not a count of open defects. -Evidence: [current baseline](current-baseline.md), [implementation status](implementation-status.md), [product alignment validation](research/product-alignment-2026-10-04/README.md). The SDK implementation passes 1,917 unit tests and 36 local-contract tests. Local tests do not establish live deployment or settlement support. +Evidence: [current baseline](current-baseline.md), [implementation status](implementation-status.md), [product alignment validation](research/product-alignment-2026-10-04/README.md). The unrestricted v4 SDK run passes 1,947 unit tests and 53 local-contract tests. Bounded live tests cover native management/execution, two-token replacement and call-only Sepolia delivery; remaining acceptance is tracked below. -Source baseline: AGW `pushAgenticWallet_v3@e704d5b`, core marketplace `cb69e0b`, gateway `bcbf7df`. Page 5 was downloaded again October 4 and its body matches the October 3 snapshot after link normalization. Harsh’s newer scope replies supersede conflicting recommendations in that snapshot. No compatible release deployment has been verified or registered. +Current contract baseline: reported deployed source `e8db748`, documentation head `deploy-agw@10a24f1` (src unchanged between them). Donut v4 addresses/code/wiring and URP 3.1.0 were checked at block 23931055; verified ABIs were saved. The SDK now uses v4 only, registers Donut and has a ported actual-contract harness. [Implementation evidence](research/v4-implementation-2026-10-06/README.md). Core marketplace cb69e0b and gateway bcbf7df remain prior source pins; they were not freshly fetched. Notion bodies were not refreshed in this pass. ## Remaining standalone external dependencies | Dependency | Owner | Related IDs | | --- | --- | --- | -| Exact limit/default table and the referenced maxValueTotal change | [Harsh H3](questions-harsh.md#h3) | G19 | +| Remaining native omission defaults/public maxValueTotal and token wording | [Harsh H3](questions-harsh.md#h3) | G19 | | Public raw-offset read/write representation | [Harsh H4.5](questions-harsh.md#h4-5) | G25 | -| Final multi-asset encoding, internal per-token reads and expected-spend assertions | [Zaryab Z1](questions-zaryab.md#z1) | G23, G24 | -| Target ref/label/envelope scope and SVM artifacts | [Zaryab Z1](questions-zaryab.md#z1) | G08, G22 | +| Multiple-rule send selection (same-agent capacity is supplied) | [Harsh H6](questions-harsh.md#h6) | G26 | +| V1 ref/label scope and representative SVM integration fixtures | [Zaryab Z1](questions-zaryab.md#z1) | G08, G22 | + +Multi-asset wire/read/assertion ABI, EVM CEA width, envelope version and SVM wire layouts are now supplied. G23/G24 and the native/EVM adapter/registry migration are implemented locally; SVM mapping/live acceptance remain SDK work; do not keep asking for those delivered definitions. Approval screening, public generation context, public spend shape, revoked-history reconstruction and compileCard are no longer unresolved standalone product questions. Native agent batching is implemented through a sender-preserving outer transport; it does not require a new batch-mode AGW agent entry point. @@ -23,37 +25,38 @@ P0 blocks agreed authorization/accounting or safe final integration. P1 affects | ID | Priority | Status | Current finding or resolution | Remaining action | | --- | --- | --- | --- | --- | -| G01 | P1 | Open deployment dependency | Reviewed source is e704d5b; build/source tests are available. SDK deployment registry remains empty pending compatibility verification; fixed addresses have been supplied. | Await the agreed completion notice from Zaryab; then verify the known fixed addresses, code/wiring, matched artifacts and event start blocks. Deployment is a release dependency, not an open question. | -| G02 | P0 | Source implemented; deployment pending | D3 executeAsAgent/agentOf and sender adapter exist; SmartSession is unchanged. SDK uses this model. | Verify the selected deployment and retain sender-binding/alternate-path coverage; do not reopen the withdrawn engine-fork proposal. | -| G03 | P1 | SDK question resolved and implemented | Validator/nonce ID calculation and generation-specific derivation are internal. Public generation-context helpers were removed per Harsh H4.1. IDs remain wallet-scoped and receipt-confirmed. | Revalidate vectors for the final generation under G01/G23; no public context-signature approval is needed. | +| G01 | P1 | V4 registered; live coverage passes | Checked new deployment and reproduced ABIs are integrated in the Donut-only registry; no legacy adapter fallback. | All 25 registered AGW scenarios have passing live coverage. Refresh wiring/source for future releases. | +| G02 | P0 | Source deployed; native/UEA acceptance passes | D3 executeAsAgent/agentOf and sender adapter exist in v4; documented wiring matches live reads. SmartSession is unchanged. | Sender-binding/alternate-path tests and live native/UEA/7702 acceptance pass; do not reopen the engine-fork proposal. | +| G03 | P1 | SDK question resolved and implemented | Validator/nonce ID calculation and generation-specific derivation are internal. Public generation-context helpers were removed per Harsh H4.1. IDs remain wallet-scoped and receipt-confirmed. | V4 vectors and receipt-confirmed IDs are verified; no public context-signature approval is needed. | | G04 | P1 | ABI history corrected; release note | Six-field main is older; inspected current gateway and historical Donut dispatcher use eight fields. A hypothetical future field removal is not a present SDK blocker. | Encode the selected manifest’s gateway ABI and track any actual migration with that deployment. | | G05 | P1 | Downstream marketplace alignment | Core cb69e0b requires rule/job expiry equality; supporting Notion pages have conflicting inequalities. | Align the marketplace/compiler track. Do not impose job equality on every standalone AGW rule. | | G06 | P2 | Closed for v1 | Binder was never in the reviewed code and is dropped for v1. | No binder implementation or binder-dependent lifecycle requirement in standalone AGW. Preserve historical snapshots as evidence. | | G07 | P1 | Known platform dependency | creditRevert depends on Push-core executor work. Until delivered, a far-side failure can leave spend inflated. | Track platform delivery and document/test the limitation. This is not an unanswered AGW redesign question. | -| G08 | P1 | Reads implemented; metadata pending | Stored checkpoint count/event reads are implemented. Editable labels and grant ref remain generation dependencies. Harsh deferred revoked history, so it is no longer a requirement here. | Deliver agreed ref/label capabilities and verify deployment. Do not request agent-event additions solely for deferred historical reads. | +| G08 | P1 | Metadata scope still open | V4 keeps checkpoints but still has no grant ref or setLabel; label is event-only at deployment. Revoked history is deferred. | Confirm ref/label v1 scope with Zaryab/Harsh. Keep absent capabilities explicit; do not fabricate storage/events or request additions solely for historical reads. | | G09 | P1 | Deferred from standalone AGW | Canonical card schema/encoding remains a marketplace issue. Harsh H5 removes compileCard from standalone AGW; its public stub was removed. | Resume schema/compiler vectors under the future marketplace scope, not as an AGW release blocker. | | G10 | P1 | Downstream marketplace scope | Current marketplace binds one EVM chain and one rulesId; broader card binding remains unresolved downstream. | Align future marketplace/job cardinality. Standalone AGW does not invent multi-rule job bindings. | | G11 | P1 | Downstream job dependency | Payment-token selection differs between the target job SDK and the one-token-per-deployment kernel. | Align selected K-12/deployment design in the job track. | | G12 | P1 | Downstream evaluator/hook delivery | Current start/fund guards exist; evaluator baseline/submit integration is incomplete. | Verify lifecycle placement and bypasses in the separate marketplace/job/evaluator work. | -| G13 | P1 | SDK implemented locally; spec wording stale | Core supports native 7702 batching with a sequential fallback. Creation uses actual capability, index-bound deployment and receipt/recovery metadata. | Correct the stale factory-batch requirement in source docs when maintained; verify final-generation/UEA creation on the release deployment. | -| G14 | P1 | Native update implemented locally; universal ABI pending | Existing-wallet assert → revoke → grant is one atomic owner batch. Native stale-spend rollback and five checkpoint ticks are tested. | Implement final universal per-token assertions after G23/G24 artifacts arrive; recheck on the selected deployment. | -| G15 | P2 | SDK implemented locally | create deploys/grants only; funding is separate. No required new createWallet factory method. Index binding prevents grants on a raced wallet; partial recovery preserves operation receipts and unknown state. | Verify final-generation events and native/UEA strategies; do not restore removed funding inputs. | +| G13 | P1 | SDK implemented locally; spec wording stale | Core supports native 7702 batching with a sequential fallback. Creation uses actual capability, index-bound deployment and receipt/recovery metadata. | Correct the stale factory-batch requirement in source docs when maintained; Native creation and UEA identity acceptance pass on the verified deployment. | +| G14 | P1 | V4 native/EVM update implemented locally | Ordered all-token assertions precede revoke/grant; actual second-token spend races roll back the entire update and checkpoints. Native per-action guards retained. | Native/EVM updates pass live. Public SVM wrapper remains. | +| G15 | P2 | SDK implemented locally | create deploys/grants only; funding is separate. No required new createWallet factory method. Index binding prevents grants on a raced wallet; partial recovery preserves operation receipts and unknown state. | Final-generation events/native batching and UEA identities are verified; do not restore removed funding inputs. | | G16 | P1 | Implemented; migration documentation pending | READ.CHAIN.WEB2 is web2. Legacy web2:https input is normalized to unchanged wire identity. Deprecated aliases now use the new public value. | Document the observable alias/literal-comparison migration and run relevant read acceptance before release. | | G17 | P1 | SDK decision implemented locally | Read-only write guards and explicit agenticWallet selection on reinitialize are implemented. Signer/network/wallet changes rebuild role/capability context. | Preserve compatibility coverage and verify with the release deployment. | -| G18 | P1 | SDK behavior implemented locally | Initialization uses enabled-rule identity; sends perform uncached lookup without expiry filtering. Missing/ambiguous candidates fail before signing. Public list is enabled-only; unknown/revoked get returns RULE_NOT_FOUND. | Verify final-generation and live permission-change cases; public history is deferred, not an open v1 question. | -| G19 | P0/P1 | Approval policy resolved; H3 defaults open | Harsh assigns approval screening to UI/marketplace. SDK selector rejection and mandatory-spender policy were removed, while ABI/chain/caller-requested pin validation remains. Defaults are byte-for-byte unchanged pending the exact H3 table. | Clarify omitted values, explicit zero and maxValueTotal. Obtain final token/native-marker fixtures with G23. Do not keep approval-policy sign-off as an SDK blocker. | -| G20 | P1 | Composer/responses implemented locally; live acceptance pending | Dedicated AGW composer uses wallet CEA/refund context, explicit owner-established allowance and separate signer gas. Live/replay summaries are canonical with ordered call metadata; real response-builder wait is covered locally. | Prove actual production pull/burn, node/TSS acceptance, recipient/executor correlation and tracking against the compatible deployment. | -| G21 | P1 | Product direction resolved; batching implemented locally | NativeRule remains one action. Arrays use a sender-preserving UEA/7702 outer batch of single executeAsAgent calls, each checked by policy. Native sequential fallback is prohibited. Local real-type-4 tests prove sender identity, cumulative counters and mined rollback. | Run release-deployment UEA/7702 acceptance. The local executor is a fixture; arbitrary forwarding helpers are not a substitute for the agent account. | -| G22 | P1 | Open SVM contract/capability dependency | Solana-origin identity through UEA is distinct from Solana destination rules. Harsh refers destination work to Zaryab; SDK destination capability remains gated. | Obtain representable terms/payloads, supported capabilities and deployment, then implement/verify obligations 19–23. | -| G23 | P0 | Open final universal ABI dependency | Target assets[]/maxGasPerCall is not implemented by the tested single-asset source. New per-asset enforcement, zero/omission semantics, empty-assets routing and expectedCEA representation need matched artifacts. | Deliver final terms/read/event ABI and vectors; no silent single-asset substitution for the public multi-asset target. | -| G24 | P1 | Public spend question resolved; internal assertion ABI open | Public Spent and RulesRecord.spent were removed per Harsh H4.2. Internal per-token counters remain necessary. A getter returning totals cannot replace caller-supplied expected-value checks for atomic update. | Obtain per-token read/assertion ABI and prove stale state rejects across all old-rule assets. No public per-token result-shape approval is required. | -| G25 | P1 | Open raw-offset public API decision | R5 fix returns exact calldata offsets/words instead of invented argument indexes and accepts that form for round trips. This extends the public NativeRule shape; the later change was not covered by Harsh’s initial replies. | Decide public raw authoring versus a separate decoded/internal wire representation; preserve ABI-based validation at the agreed boundary. | +| G18 | P1 | SDK behavior implemented locally; selection under review | Initialization uses enabled-rule identity; sends perform uncached lookup without expiry filtering. Missing/ambiguous candidates fail before signing. Public list is enabled-only; unknown/revoked get returns RULE_NOT_FOUND. The October 5 multiple-rules comment may change selection/cardinality assumptions. | Resolve G26 before treating uniqueness/ambiguous-candidate behavior as final. Verify final-generation and live permission-change cases; public history is deferred. | +| G19 | P0/P1 | Universal defaults implemented; H3 native choices open | Universal omission uses maxUint256 and explicit zero is hard zero; empty input gets a gas-token 0/0 route. Native defaults remain provisional. | Clarify H3 native/public fields and token wording; retain UI-owned approval policy. | +| G20 | P1 | V4 composer/response and live EVM acceptance pass | Uses selected listed token, maxGasPerCall, wallet CEA/refund context, separate allowance and signer gas. Local requests pass actual URP with fixture gateway. | Production token debit, node/TSS delivery, CEA execution attribution/balance, replay identity and destination-revert classification pass. Public SVM integration remains tracked under G22. | +| G21 | P1 | Product direction resolved; batching implemented locally | NativeRule remains one action. Arrays use a sender-preserving UEA/7702 outer batch of single executeAsAgent calls, each checked by policy. Native sequential fallback is prohibited. Local real-type-4 tests prove sender identity, cumulative counters and mined rollback. | Release-deployment UEA identities and native 7702 batch/rollback cases pass. The local executor is a fixture; arbitrary forwarding helpers are not a substitute for the agent account. | +| G22 | P1 | SVM internals implemented; public integration pending | Wire codec, wallet/ATA coverage, payload pins and internal outbound builder pass 23 unit cases, 10 actual-contract Foundry checks and 7 Anvil SDK cases. | Agree public mapping, connect registry/IDL inputs and dispatch/tracking; run live Solana acceptance after public integration. | +| G23 | P0 | V4 EVM integration verified locally and live | Multi-asset codecs/reads/outbound, envelope 1, source chain/token identity, hard-zero semantics and empty-input routing are implemented. Old adapter/ABIs/fixtures removed. | Registered EVM acceptance passes. Public SVM SDK mapping/composition remains. | +| G24 | P1 | Internal per-token update verified locally and live | Reads/stores every expected counter in asset order; array assertion catches intervening second-token spend. Public spent stays absent. | Live two-asset replacement passes; public SVM integration remains. | +| G25 | P1 | Public raw-offset decision open | Exact native pin/amount offsets and EVM beneficiaryOffset are returned/accepted losslessly; no invented argument indexes. This extends the target input shape. | H4.5: public raw authoring versus separate decoded wire records. | +| G26 | P1 | Management implemented; send selection open | Same-agent/same-chain grants are accepted. Multiple matching send candidates fail with AMBIGUOUS_RULE and their IDs. | H6: choose explicit versus automatic selection, including arrays/overlapping rules; never arbitrarily select or revoke. | ## Validation and release boundaries -The [October 4 alignment evidence](research/product-alignment-2026-10-04/README.md) records 1,917 passing unit tests, 36 passing local-contract tests, clean build/typechecks and seven existing lint errors in unchanged files. AGW E2E selection has 23 opt-in scenarios; default all remains 76. Live E2Es have not been run. +The [current acceptance evidence](research/live-acceptance-2026-10-06/README.md) records 1,947 passing unit tests, 53 actual-contract tests, build/four typechecks and seven existing lint errors. All 25 opt-in AGW scenarios have passing bounded selected-run coverage; default all remains 76. Native/UEA/7702, lifecycle, allowance, responses and Sepolia success/failure pass. The initial positive-amount Push transaction exposed insufficient gas headroom. A tested 20% headroom fix passes the bounded retry, including token debit, allowance reduction, destination receipt/CEA balance and replay checks. Destination-revert classification also passes. -Local batch proof uses actual AGW/factory/engine/policy and real Anvil EIP-7702 transactions, with a small fixture executor. UEA shaping/replay is unit-tested and reuses the existing transport; live UEA, production executor/gateway and destination acceptance remain outstanding. +Local batch proof uses actual AGW/factory/engine/policy and real Anvil EIP-7702 transactions, with a small fixture executor. UEA shaping/replay is unit-tested and reuses the existing transport; all registered native/EVM/UEA acceptance scenarios now pass. Public Solana destination coverage remains outstanding. ## Rules for closure @@ -62,7 +65,8 @@ Local batch proof uses actual AGW/factory/engine/policy and real Anvil EIP-7702 - expectedCEA derives from AGW plus destination context. Signer CEA and arbitrary pasted addresses are not substitutes. - Checkpoint consumers compare counts; allowance-driven balance changes are not always checkpointed. Current single replacement adds five ticks. - Internal spend assertions remain required even when public spend records are removed. -- H3 defaults and raw-offset representation remain open. Keep current defaults until the former is explicitly clarified. +- H3 native defaults and raw-offset representation remain open. Universal total semantics are now supplied; the old zero/unlimited row must not carry into v4. +- H6 remains a send-selection choice. Same-agent capacity is supplied; uniqueness validation is provisional/stale. Token-independence wording is a product follow-up, not permission to remove policy checks. - Harsh’s replies have been received. The linked question documents now contain remaining follow-ups; no outbound team messages were sent by this agent. -Deployment coordination update October 5: the address request is retired. The supplied table matches the saved historical address book; its verification marks are source-reported, not new SDK compatibility checks. Zaryab will notify Shoaib when the intended deployment is complete. The SDK performs its registry and live-acceptance checks afterward. +The October 5 historical table is superseded for new integrations by the October 6 v4 completion notice and address book. Contract delivery/code/wiring checks are recorded in the review; Native/EVM migration is complete locally; authorized funded acceptance remains separate. diff --git a/plan/agw/implementation-plan.md b/plan/agw/implementation-plan.md index 8f0fcdcb..505f4c87 100644 --- a/plan/agw/implementation-plan.md +++ b/plan/agw/implementation-plan.md @@ -1,10 +1,16 @@ # Complete AGW SDK implementation plan +Updated October 6, 2026. The v4-only native/EVM implementation uses deployed source e8db748 and the Donut manifest. Old runtime/test adapters and single-asset codecs are removed. The unfiltered unit suite passes 1,947 tests; all 53 actual-contract Anvil cases pass; build and four typechecks pass. All 25 registered AGW live scenarios pass across selected runs; remaining work is public SVM integration and release scope decisions. [Current acceptance and remaining coverage](research/live-acceptance-2026-10-06/README.md). + +SVM internal terms/accounts/payload/builder are implemented and validated. Public SVM mapping/dispatch remains gated. Remaining decisions are H3 native defaults, H4.5 raw-offset public shape, H6 send selection and ref/label v1 scope. Earlier plan recommendations below are qualified by those accepted decisions and the current implementation status. + +> October 5 comment update: [live review](research/notion-comments-2026-10-05.md) adds [H6](questions-harsh.md#h6) for same-agent multiple-rule scope and send selection. Any one-rule-per-agent/chain or DUPLICATE_RULE recommendation below describes the earlier implementation baseline and is provisional. Once clarified, revise steps 6–8 and 10–12 plus their tests together. Do not choose the first rule arbitrarily. Token-independence wording is included in H3/Z1.1; defaults remain unresolved. + > October 4 update: [Harsh’s replies](product-decisions-2026-10-04.md) supersede earlier provisional approval/default/helper/history/compiler recommendations below. Use [remaining dependencies](external-blockers.md) for current blockers. The clear scope changes and sender-preserving native batching are now implemented; H3 defaults remain unchanged pending clarification. See [alignment evidence](research/product-alignment-2026-10-04/README.md). This is the step-by-step plan for the complete AGW surface in Notion page 5 inside `@pushchain/core`. It covers management, rules, execution, responses, helpers, compatibility, documentation and release validation. Marketplace, job and evaluator clients are separate projects; `compileCard` is deferred to their later delivery and is not exposed by standalone AGW. Settled implementation is recorded in [implementation status](implementation-status.md); remaining contract capabilities stay gated. -Target: [SDK spec](notion/5-sdk-agw.md), exported October 3, 2026 at 13:23 IST. Tested contract source: AGW `e704d5b`. SDK production baseline: `167fdc6`. See [current baseline](current-baseline.md), [SDK design](sdk-design-review.md), [SDK-owned decisions](sdk-owned-review.md) and [external blockers](external-blockers.md). Remote refs were rechecked unchanged; subsequent Notion edits remain unverified. +Target: [SDK spec](notion/5-sdk-agw.md), exported October 3, 2026 at 13:23 IST. Tested contract source: AGW v4 `e8db748`. SDK production baseline: `167fdc6`. See [current baseline](current-baseline.md), [SDK design](sdk-design-review.md), [SDK-owned decisions](sdk-owned-review.md) and [external blockers](external-blockers.md). The October 6 deployment/owner guide and October 5 comment review qualify the older Notion snapshot; a newer full Notion export is not claimed. ## How to execute this plan @@ -44,17 +50,17 @@ These are working assumptions for development, not accepted product changes. Rep | A02 | Multiple native actions use a sender-preserving UEA/7702 outer batch of single agent-door calls; never sequential fallback | Harsh H2 direction; implemented and locally validated | Atomic transport and batch response adapters | | A03 | Exact revised default table remains open; existing defaults are unchanged until H3 is clarified | Harsh H3 / E03 | One defaults module | | A04 | Generation-dependent IDs, derivation and encoding context remain internal; client.agentic.derive remains public | Harsh H4.1 resolved; implemented | Public utility exports and internal codecs | -| A05 | Spend is internal, not a public result. Final per-token wire/read/assertion ABI, empty-assets routing and CEA width remain unresolved | Harsh H4.2 scope resolved; Zaryab Z1 delivery pending | Internal accounting and codec adapter | +| A05 | Spend stays internal. V4 supplies ordered per-token wire/read/assertion ABI, address EVM CEA and zero-cap gas-token routing for empty user assets | Native/EVM v4 integration and live outbound tests pass; public SVM pending | V4 accounting/codec/outbound adapter | | A06 | V1 lists enabled rules only; unknown/revoked get returns RULE_NOT_FOUND. No historical record reconstruction | Harsh H4.3 deferred; implemented | Public read model | -| A07 | A verified new deployment supplies the matching grant ref/envelope/metadata ABI, addresses and start blocks. Historical Donut remains a distinct generation. | Zaryab Z1 for contract surface; agreed deployment notice, then SDK verification | Deployment manifest and capability adapter | +| A07 | New v4 addresses/wiring/ABIs are supplied and checked; V4 adapter/manifest are implemented and verified. Envelope is version 1; grant ref/setLabel remain absent | Deployment delivered October 6; Z1.3 metadata scope remains | Deployment manifest, v4 migration and capability gates | | A08 | No compileCard in standalone AGW; canonical cards belong to later marketplace work | Harsh H5: outside AGW v1 | No public compiler stub/export | ### What closes each assumption - A01/A02/A04: clear product scope is implemented. A03 defaults still need exact agreed wording. -- A05: Harsh agrees the public representation; Zaryab supplies matching terms, read/assertion ABIs and vectors. Clarification alone does not supply missing contract code. +- A05: delivered v4 definitions unblock SDK codec/read/assertion work. Preserve internal accounting, correct zero semantics and prove all-asset replacement rollback. - A06: revoked history is outside v1; active-only reads and explicit RULE_NOT_FOUND behavior are implemented. -- A07: Zaryab identifies the selected contract surface and notifies Shoaib when deployment is complete. Fixed addresses are already available. The SDK then builds/verifies its deployment manifest, registry and integration evidence; no additional address request is needed. +- A07: deployment notice received; new addresses supersede the historical table. The v4 manifest/registry and native/EVM integration are verified; track remaining acceptance in the live report. Ref/label remain a scope/delivery question; no new address request is needed. - A08: closed for standalone AGW by deferring compileCard to the marketplace track. Record design decisions and artifact/deployment readiness separately. All eight have an explicit question owner, but answers alone do not mean all eight are implemented or verified. @@ -62,7 +68,7 @@ Record design decisions and artifact/deployment readiness separately. All eight Placeholder implementation rules: - Use explicit internal capabilities and typed failures. A missing codec or unsupported generation must fail before signature/broadcast; never return empty success records, zero addresses, fabricated IDs or dummy transactions. -- Keep pinned e704d5b single-asset artifacts as review fixtures. They must not silently encode the public assets[] target by choosing the first asset or splitting it into unrelated rules. +- Keep historical source snapshots only as planning evidence. Runtime and tests use v4 artifacts; assets[] must never become an arbitrary first asset or unrelated split rules. - Keep provisional wire types internal. Do not publish `any`, guessed envelope versions, guessed deployment addresses or fixed ABI tuples as the final SDK contract. - Do not implement both sides of a product choice speculatively. Isolate the boundary and implement the selected behavior after confirmation. - `setLabel`, full historical reads, SVM destination encoding and compileCard may be explicitly unsupported in development builds while their dependencies are incomplete. A complete release must implement the promised surface or record an approved scope change. diff --git a/plan/agw/implementation-review-handoff.md b/plan/agw/implementation-review-handoff.md index cc90f8a5..2896a63a 100644 --- a/plan/agw/implementation-review-handoff.md +++ b/plan/agw/implementation-review-handoff.md @@ -1,5 +1,11 @@ # AGW SDK implementation — review handoff +> Latest acceptance: [October 6 funded tests and fixes](research/live-acceptance-2026-10-06/README.md). Network restrictions are resolved; all 53 Anvil cases and the unfiltered unit suite pass. All 25 registered AGW scenarios have passing selected-run coverage; public SVM destination integration and scope decisions remain. Changes are on feat/agw-sdk-v4. Everything below the current banners describes historical implementation/review evidence. + +> Current implementation: [v4-only native/EVM migration and validation](research/v4-implementation-2026-10-06/README.md) supersede earlier missing-adapter/empty-registry statements below. Legacy runtime/test artifacts are removed. SVM mapping, H3/H4.5/H6, ref/label scope and funded acceptance remain. + +> October 6 update: [v4 deployment/wire review](research/deployment-review-2026-10-06/README.md) supersedes the deployment/artifact absence recorded below. Those definitions are supplied, but this implementation/review evidence still concerns e704d5b; v4 SDK migration and harness acceptance remain. No live transaction was sent. + October 3, 2026. For the reviewing agent. The per-step status is in [implementation-status.md](implementation-status.md). ## Revisions diff --git a/plan/agw/implementation-status.md b/plan/agw/implementation-status.md index 85cf6b09..2428dd8e 100644 --- a/plan/agw/implementation-status.md +++ b/plan/agw/implementation-status.md @@ -1,63 +1,49 @@ # AGW SDK implementation status -> October 4 product update: [new decisions](product-decisions-2026-10-04.md) are applied to the clear scope items. Public spend/generation context/compiler exposure is removed, history is active-only, and native arrays use an atomic outer batch. H3 defaults remain unchanged; raw-offset types still need clarification. +> Latest: [funded acceptance and fixes](research/live-acceptance-2026-10-06/README.md). Full permissions are restored: 1,947 unfiltered unit tests, all 53 Anvil cases, build and four typechecks pass. All 25 registered AGW scenarios pass across selected live runs, including UEA identities, native 7702 batches, lifecycle and Sepolia success/failure. Public SVM destinations remain gated. -October 3, 2026, updated after the implementation review (R1–R7 fixed; see the [handoff](implementation-review-handoff.md#review-response-2026-10-03)). Branch `feat/agw-sdk-impl` (base `feat/agw-sdk-planning@349635b`). This matrix records what the code does today against the [implementation plan](implementation-plan.md). "Implemented" excludes placeholders; a capability-gated method that throws `CAPABILITY_UNAVAILABLE` is listed as blocked, not implemented. Details, commands and review hotspots are in the [review handoff](implementation-review-handoff.md). +Updated October 6, 2026. Branch feat/agw-sdk-v4; runtime commits a66ff7d and b68bab7. The native/EVM migration uses deployed source e8db748. Runtime/test e704d5b adapters, ABIs and fixtures were removed at Shoaib's request; historical review documents are evidence only. [Full handoff, commands and validation](research/v4-implementation-2026-10-06/README.md). -## Evidence levels +## Validation -| Level | Meaning | +| Level | Current evidence | | --- | --- | -| Unit | Mock-boundary jest suites under `packages/core/src/lib/agentic/__tests__` and `read-state/__tests__/web2-compat.spec.ts`; no network | -| Local | Real pinned e704d5b contracts on anvil through the SDK (`packages/core/__agw-local__`); stub gateway only; Push-EOA signers only | -| Live | Testnet transactions against a verified deployment. **None has occurred** — no compatible deployment has been verified or registered (A07) and no live run was authorized | +| Unit | 1,947 passed, 0 failed; 12 skipped; 113 suites passed, 1 skipped | +| Local actual contracts | 53 passed, 0 failed; 7 suites against e8db748 on Anvil | +| ABI reproduction | All 5 explorer ABI entry sets match the isolated build, ignoring array order | +| Build/typechecks | Build and lib/spec/local/AGW-E2E typechecks pass | +| Lint | 7 pre-existing errors in unchanged files; no new errors | +| E2E selection | AGW: 25 scenarios/9 files/25 tests; default all unchanged at 76/40/81 | +| Funded live | All 25 registered scenarios have passing selected-run coverage; 0 outstanding native/EVM scenario failures | + +Local gateway/core/token/executor and CEA lookup are fixtures. Actual AGW/factory/engine/validator/URP enforce the rules; native type-4 tests use real transactions. This does not prove production gateway, Cosmos/TSS, UEA or destination execution. ## Per-step matrix -| Step | Deliverable | Status | Unit | Local | Live | Remaining dependency | -| --- | --- | --- | --- | --- | --- | --- | -| 1 | Source and capability contract | Implemented | ✓ | ✓ rebuilt ABIs identical to evidence | — | Refresh pins when answers land | -| 2 | Namespace, types, exports, errors | Implemented; remaining raw-offset/API metadata provisional | ✓ | ✓ | — | Raw-offset type decision; final contract metadata | -| 3 | Signer/wallet context and lifecycle | Implemented | ✓ | ✓ owner, agent, stranger, read-only, reinitialize, guards | Blocked (A07) | UEA owner/agent paths only unit-tested (no UEA on anvil) | -| 4 | Generation registry and adapter | Implemented for e704d5b; registry ships empty | ✓ | ✓ wiring verified | Blocked (A07) | Verified manifest; OwnerIntent signing not implemented (no transport needs it) | -| 5 | Wallet and checkpoint reads | Implemented: derive, list, info, owner, checkpoints, active rules | ✓ | ✓ | Blocked (A07) | History deferred; setLabel (A07) gated | -| 6 | Rule normalization and codecs | Native implemented and vector-verified; universal validated then gated | ✓ | ✓ contract vectors | — | A05 multi-asset wire/vectors; H3 defaults | -| 7 | Create, add, revoke | Implemented (native rules); index-bound deploy | ✓ | ✓ sequential create incl. partial recovery and the concurrent-creation race; atomic multi-rule add | Blocked (A07) | 7702/UEA create batch paths unit-only | -| 8 | Atomic rules.update | Implemented for native rules | ✓ | ✓ five ticks, stale-spend rollback | Blocked (A07) | A05 per-token assertion for universal rules | -| 9 | Owner execution and allowance setup | Implemented | ✓ | ✓ owner batches, approve/remove via owner door | Blocked (A07) | Production gateway pull/burn | -| 10 | Agent rule selection and native sends | Implemented | ✓ | ✓ maxCalls, pins, amount, expiry, atomic 7702 batches | Blocked (A07) | Live UEA/7702 acceptance | -| 11 | EVM universal sends and gas | Composer implemented for the e704d5b single-asset generation (Route-2-equivalent destination calls, no SDK allowance writes); signer gas guard implemented | ✓ | ✓ passes every URP gate with stub gateway; revoked-allowance race | Blocked (A07) | A05 token resolution for assets[]; node/TSS/destination acceptance | -| 12 | SVM destination support | Not implemented; gated | ✓ gating | — | — | A05/A07, Harsh H4.4, obligations 19–23 | -| 13 | Responses, tracking, hooks, reads | Implemented | ✓ | ✓ live send/receipt identity | Blocked (A07) | Native batch replay and outbound wait covered locally; live settlement pending | -| 14 | Deployment onboarding and acceptance | E2E authored and gated; not run | — | — | Blocked (A07) | Verified manifest + authorized budget | -| 15 | Web2 compatibility | Implemented | ✓ | — | Not rerun | Review of CHAIN.WEB2 value change | -| 16 | compileCard | Outside standalone AGW; stub removed | ✓ absent public export | — | — | Future marketplace work | -| 17 | Documentation, examples, release | Planning docs only | — | — | — | Accepted feature scope | - -## Assumptions A01–A08 - -| ID | Design status | Artifact status | What the code does now | +| Step | Deliverable | Current status | Remaining work | | --- | --- | --- | --- | -| A01 | Resolved by Harsh H1 | n/a | SDK approval rejection removed; structural validation retained | -| A02 | Product wants batching | Local type-4 proof, fixture executor | Sender-preserving atomic UEA/7702 path; native fallback prohibited | -| A03 | Provisional (Harsh H3) | n/a | `codec/defaults.ts` is the only defaults table, tagged A03 | -| A04 | Internal generation details | n/a | rulesId/deriveWallet/encodeRules and RulesEncodeContext are not public; client.agentic.derive remains | -| A05 | Public spend not required | Final multi-asset artifacts missing | Public spent removed; internal reads/assertions retained; final universal wire stays gated | -| A06 | History deferred from v1 | Not required for v1 | list is enabled-only; unknown/revoked get returns RULE_NOT_FOUND | -| A07 | Contract surface pending (Z1); deployment notice already coordinated | **No verified deployment** | Registry and `CONSTANTS.AGENTIC` empty; every AGW call fails `GENERATION_UNSUPPORTED`; `ref` and `setLabel` gated | -| A08 | Outside standalone AGW | Future marketplace dependency | Public compileCard stub and capability removed | - -Harsh replies and the focused October 4 page-5 recheck are recorded in product-decisions-2026-10-04.md. The clear decisions above are implemented; defaults are still pending. - -## Gap register cross-reference - -Implementation evidence exists for G03 (explicit-context IDs, receipt IDs), G08 (checkpoint/label reads), G13/G15 (creation strategy and partial recovery), G14 (wallet-level replacement), G16 (Web2), G17 (read-only and reinitialize), G18 (eligibility and uncached selection) and G20 (dedicated composer and response identity). None is closed: each closure criterion also requires review and, where stated, a verified deployment or live acceptance. - - -## Outbound response follow-up - -F1 is resolved with a shared canonical first-call summary and complete `agentic.destinationCalls` metadata on send/replay. R6 wait-path regressions are now in the regular unit suite. Current validation: 1,908 unit tests, 34 local-contract tests, both typechecks and build pass. No live acceptance was performed. See [resolution](implementation-review/outbound-response-resolution.md). - -Current alignment verification is recorded in [product alignment evidence](research/product-alignment-2026-10-04/README.md). Existing older counts below/above describe their named revisions. - -Deployment coordination October 5: fixed addresses are supplied and Zaryab will notify Shoaib when deployment is complete. Z3 is removed from the open questions. SDK compatibility verification and live acceptance remain required afterward; the registry is unchanged. +| 1 | Source/capability contract | V4 deployed source/ABIs pinned and reproduced | Refresh for future releases | +| 2 | Namespace/types/errors | Implemented; AMBIGUOUS_RULE replaces duplicate-authoring rejection | H4.5 public raw-offset boundary | +| 3 | Signer/wallet context | Owner/agent/read-only/identity guards retained | Release review; UEA identity cases pass | +| 4 | Registry/adapter | Donut v4 registered; unsupported networks fail | Release review; no legacy fallback | +| 5 | Wallet/checkpoint/rule reads | Native and EVM reads implemented; source tokens/beneficiary offsets reconstructed | Metadata scope; SVM reads/public mapping | +| 6 | Normalization/codecs | Native/EVM envelope 1, ordered caps, hard-zero/max total, empty-list routing | Native H3 defaults; SVM public mapping | +| 7 | Create/add/revoke | Index-bound create, partial recovery, atomic writes; same-agent multiples allowed | Release review; deployed create/identity/batching paths verified | +| 8 | Atomic update | Native per-action and universal all-token assertions before revoke/grant | Public SVM wrapper | +| 9 | Owner/allowance | Owner path unrestricted; explicit separate allowance retained | Release review; production allowance/token debit and delivery verified | +| 10 | Native agent sends | Sender-preserving atomic batches retained | H6 selection for multiple matching rules | +| 11 | EVM outbound | V4 asset membership, maxGasPerCall, wallet CEA/refunds, signer gas and responses | Release review; Sepolia success/failure and UEA cases verified | +| 12 | SVM destinations | Source wire types delivered; SDK capability remains gated | Internal codec/accounts/payload/builder delivered; public mapping/dispatch and cluster acceptance | +| 13 | Responses/progress/errors | V4 ABIs and prior canonical replay/wait fixes retained | Deliberate delayed-indexing acceptance remains unit-tested; funded destination and replay proof pass | +| 14 | E2E | 25 opt-in scenarios registered; public universal setup and new two-token/call-only cases | Completed native/EVM live coverage; public SVM acceptance after integration | +| 15 | Web2 | Prior implementation retained and included in full unit run | Release documentation/acceptance | +| 16 | compileCard | Outside standalone AGW; absent public export | Future marketplace scope | +| 17 | Documentation/release | Current status/gaps/handoff updated | Product scope decisions and funded acceptance | + +## Open product/contract choices + +A01 approval policy, A04 internal generation details, A06 history deferral and A08 compiler scope remain settled. A02 native batching is implemented locally. A05 wire/accounting is delivered and implemented for EVM. A07 deployment/registry is supplied; grant ref and editable label remain absent and capability-gated. + +H3 is narrowed to native omission defaults/public maxValueTotal and token wording; universal total semantics are implemented. H4.5 covers native pins/amount and the exact EVM beneficiaryOffset read/write form. H6 remains send selection, not management capacity. [Harsh draft](questions-harsh.md); [Zaryab metadata/SVM fixture draft](questions-zaryab.md). + +No public spent/history/compiler feature is reopened. Rule updates reset counters as agreed. Ordinary inflows do not restore spent; creditRevert remains a platform dependency. diff --git a/plan/agw/product-decisions-2026-10-04.md b/plan/agw/product-decisions-2026-10-04.md index 7fe9bd25..d1c8e125 100644 --- a/plan/agw/product-decisions-2026-10-04.md +++ b/plan/agw/product-decisions-2026-10-04.md @@ -1,5 +1,9 @@ # Harsh product replies and SDK impact +October 6 follow-up: [v4 owner guide/deployment review](research/deployment-review-2026-10-06/README.md) supplies universal hard-zero/maxUint256 semantics, wire/read/assertion layouts, SVM structs and same-agent multiplicity. These are no longer missing contract definitions. Native SDK omission defaults/public fields, raw-offset authoring and send selection remain product choices; see the narrowed question drafts. + +October 5 follow-up: [live Notion comments](research/notion-comments-2026-10-05.md) add multiple-rules direction and ambiguous token-independence wording. See [H6](questions-harsh.md#h6) for same-agent scope/send selection and H3 for final token/limit definitions. The October 4 decisions below remain recorded evidence; uniqueness is now provisional and defaults/raw offsets remain unresolved. + Recorded October 4, 2026 from the screenshot supplied by Shoaib. The message is attributed to Harsh Rajat and displays 1:35 AM; no Slack permalink or explicit message timezone was supplied. These replies supersede the earlier recommendations where clear. This file records decisions and interpretation; no SDK source changes were made in this pass. ## Source check diff --git a/plan/agw/questions-harsh.md b/plan/agw/questions-harsh.md index 460ce350..ddb2f526 100644 --- a/plan/agw/questions-harsh.md +++ b/plan/agw/questions-harsh.md @@ -1,43 +1,57 @@ # Remaining AGW product follow-ups for Harsh -Updated October 4, 2026 after your replies. Accepted decisions and implementation impact are recorded in [product decisions](product-decisions-2026-10-04.md); this document contains only remaining questions. +Updated October 6, 2026 after your replies, [live Notion comment review](research/notion-comments-2026-10-05.md) and the [v4 owner guide/deployment review](research/deployment-review-2026-10-06/README.md). Accepted decisions and implementation impact are recorded in [product decisions](product-decisions-2026-10-04.md); this document contains only remaining questions. | Item | Answer needed | | --- | --- | -| [H3](#h3) | Exact revised limit fields, omission defaults and explicit-zero behavior | +| [H3](#h3) | Remaining native omission defaults/public maxValueTotal and token wording | | [H4.5](#h4-5) | Raw-offset representation introduced by the SDK review fix | +| [H6](#h6) | Choosing a rule for a send when several match | ## Source check We downloaded [page 5](https://app.notion.com/p/pushprotocol/5-SDK-AGW-3e9188aea7f481cf8e8de324956549b9) again on October 4. Its exported body still matches our October 3 snapshot after link normalization, including maxValueTotal and the old public helper/Spent/compileCard entries. [Comparison evidence](research/notion-check-2026-10-04/comparison.json). We will apply your newer scope directions rather than repeat those answered questions. +On October 5 we read live discussions, including resolved threads. Your new multiple-rules comment is captured under H6. The token-independence comment is included in H3 below. Neither comment provides the missing default table or answers H4.5. + +The October 6 owner guide now settles universal total encoding: omitted/no-limit maxTotal uses uint256 maximum, explicit zero forbids movement. It supplies the versioned multi-asset wire layout and confirms same-agent multiplicity. These are no longer questions below. It does not determine every public SDK omission default or the rule-selection API. + -## H3 Revised limits and exact defaults +## H3 Remaining native defaults and public fields -We understand the direction as omitted maxTotal and maxValuePerCall meaning unlimited, encoded as `type(uint256).max`, rather than zero. Your reply says maxValueTotal changed in the SDK document, but the current page body still contains the earlier NativeRule declaration. +The delivered contracts distinguish hard zero from uint256 maximum, keep maxValueTotal, use maxCalls=0 for unlimited calls and destination maxValue=0 for non-payable calls. We will apply the guide's universal no-total-limit encoding and preserve explicit zeros. -Please point us to the revised section or provide the final field/default table, specifically: +Please confirm the remaining public SDK choices: -- Which maxTotal inputs should default to uint256 maximum: universal assets[].maxTotal, native amount.maxTotal, or both? -- What replaces or changes native maxValueTotal, and what is its omitted default? -- Should native maxCalls still default to 0 (unlimited), and allowedCalls[].maxValue to 0 (no attached destination value)? These rows were not settled in the reply. -- What should explicit zero mean on each field? In particular, the older multi-asset contract proposal made maxTotal=0 unlimited, while native value/amount zero forbids positive amounts. +- Should omitted native maxValuePerCall and maxValueTotal both mean uint256 maximum? Your earlier reply was tentative for the former and said the latter had changed. +- Is maxValueTotal retained in the public NativeRule, or replaced/removed? The new owner guide still includes it on the wire. +- May we use native amount.maxTotal=uint256 maximum, maxCalls=0 and destination allowedCalls[].maxValue=0 as the omission defaults? The wire meanings are clear; this confirms the public optional-input behavior. -The SDK can normalize omitted values independently from the wire representation, but we need one exact agreed table to avoid changing authority accidentally. +Your [token-independence comment](https://app.notion.com/p/pushprotocol/5-SDK-AGW-3e9188aea7f481cf8e8de324956549b9#af9c3fac35d94f2585cb27310271c1d8) needs one scope clarification: the delivered guide keeps assets[] on the rule and allows each listed token with every allowed call. Is that the intended SDK model, or does your comment request a different public model? -## H4.5 Decoded native rules and raw offsets +## H4.5 Decoded rules and raw offsets This was added during implementation review and was not part of the earlier question set. Stored native rules contain calldata byte offsets, but do not contain the ABI needed to recover argument indexes. Returning a guessed arg index was incorrect for arrays/tuples. -The current fix returns pins as `{ offset, expected }` and amount limits with `{ offset, maxPerCall, maxTotal }`. It also accepts these raw forms when granting/updating so decoded rules can round-trip without loss. +The current fix returns native pins as `{ offset, expected }` and amount limits with `{ offset, maxPerCall, maxTotal }`. V4 EVM allowed-call reads also return exact beneficiaryOffset because stored selectors do not include the ABI needed to recover beneficiary argument indexes. It also accepts these raw forms when granting/updating so decoded rules can round-trip without loss. Please confirm whether this raw form should be public and accepted for new authoring, or whether decoded wire records should be separate from the ABI-based `{ arg, ... }` input. Accepting arbitrary raw offsets is a different public validation boundary from generating them from ABI information. We will keep internal accounting/codec needs separate from the reduced public spend/helper surface. **References:** [follow-up review](implementation-review/followup-9e16b23/review.md), [current public types](../../packages/core/src/lib/agentic/agentic.types.ts), [integrator obligations](contract-integrator-obligations.md). + + +## H6 Multiple rules and choosing a rule for a send + +Your new [create-example comment](https://app.notion.com/p/pushprotocol/5-SDK-AGW-3e9188aea7f481cf8e8de324956549b9#f9712c13f75c4398aef2dbf7628450b2) says multiple rules per chain are accepted. We already support different agents sharing a chain. The page body still says one per agent and chain; the v4 SDK now permits multiple during create/add/update. + +The new owner guide explicitly permits multiple rules for the **same agent and chain**, so the capacity question is answered. How should sendTransaction select rulesId: an explicit caller choice, or a defined automatic selection rule? Please include native arrays whose calls need different rules and cross-chain calls with overlapping permissions. + +Lifecycle validation is already aligned with multiple rules. The SDK reports AMBIGUOUS_RULE with candidate IDs before signing; choosing the first rule would make grants, budgets and expiry determine execution accidentally. An explicit selector would add to the public API, so we will not introduce it without agreement. + ## Supporting context -Native array implementation is now an SDK validation task: use sender-preserving outer UEA/7702 batching of single executeAsAgent calls, and handle unsupported atomic transports explicitly. SVM and the final universal ABI/deployment remain with [Zaryab](questions-zaryab.md). compileCard and revoked history are outside standalone AGW v1 scope per your reply. +Native array implementation is now an SDK validation task: use sender-preserving outer UEA/7702 batching of single executeAsAgent calls, and handle unsupported atomic transports explicitly. Universal/SVM wire definitions and the deployment are supplied; Native/EVM adapter/codec work is implemented and locally validated; SVM mapping and funded acceptance remain. [Zaryab's draft](questions-zaryab.md) now asks only about missing metadata scope and representative SVM integration fixtures. compileCard and revoked history remain outside standalone AGW v1. diff --git a/plan/agw/questions-zaryab.md b/plan/agw/questions-zaryab.md index 609941bf..913ed379 100644 --- a/plan/agw/questions-zaryab.md +++ b/plan/agw/questions-zaryab.md @@ -1,84 +1,47 @@ -# AGW SDK open contract requests for Zaryab +# AGW SDK remaining contract follow-ups for Zaryab -We need the artifacts and compatibility details below to finish the AGW SDK against the intended contract generation. Please reply by item ID with the source/ABI/vector link when available, or the remaining work and expected delivery. Product choices that affect these requests are linked to Harsh's document. +Updated October 6, 2026 after the new Donut deployment and owner integration guide. Thank you: the multi-asset terms, versioned envelope, EVM CEA width, internal per-token reads/assertion ABI and SVM wire definitions are supplied. We have checked code/wiring read-only and saved the verified ABIs. Those delivery questions have been removed. -**Status:** updated October 4 after [Harsh’s replies](product-decisions-2026-10-04.md). Only Z1 remains as an active contract question for standalone AGW. Public multi-asset spend, revoked history and compileCard are no longer requested as standalone v1 features; internal accounting still matters. +Only the following items remain in Z1. Please reply by sub-item with the agreed scope or fixture link. Deployment/address coordination is complete; adapter integration and funded acceptance are SDK work. -| Item | Requested deliverable | What it enables | -| --- | --- | --- | -| [Z1](#z1) | Matching terms, accounting/assertion ABI and metadata surface | Final rule encoding, reads and safe replacement | +| Item | Remaining answer | +| --- | --- | +| [Z1.3](#z1-3) | Ref/label scope for this release | +| [Z1.4](#z1-4) | Representative SVM integration fixtures/registry inputs where available | ## Source baseline -- **Target:** [saved contract change set](notion/1-agw-contract-changes.md), especially section 4c; [live Notion page](https://app.notion.com/p/pushprotocol/1-AGW-Contract-Changes-nomenclature-standard-change-set-3e9188aea7f4813aa31fc95ceb4e684d). -- **SDK:** [saved page 5](notion/5-sdk-agw.md); [live Notion page](https://app.notion.com/p/pushprotocol/5-SDK-AGW-3e9188aea7f481cf8e8de324956549b9). Both snapshots were exported October 3, 2026 at 13:23 IST; later page edits are not covered. -- **Reviewed code:** [AGW e704d5b](https://github.com/pushchain/push-agentic-wallets/blob/e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9/src/AGW.sol), core `cb69e0b`, gateway `bcbf7df`. Remote refs were rechecked October 3 and were unchanged. This does not verify a new live deployment. [Full source inventory](SOURCES.md). +- [Owner integration guide](https://github.com/pushchain/push-agentic-wallets/blob/10a24f101e2e6e0a9b76517b29f5cdb1aa967796/docs/5_SDK_Owner_Integration.md). +- [V4 address book](https://github.com/pushchain/push-agentic-wallets/blob/10a24f101e2e6e0a9b76517b29f5cdb1aa967796/docs/addresses/donut.md). +- Reported deployed source e8db748; documentation head deploy-agw@10a24f1 has identical src. Donut probe block 23931055: factory/wallet/policy wiring matches, URP 3.1.0. [Evidence and remaining SDK work](research/deployment-review-2026-10-06/README.md). +- Target public API remains [page 5](notion/5-sdk-agw.md), qualified by Harsh's later replies/comments. New owner guide describes deployed wire behavior; it does not settle every public API/scope question. Notion was not re-exported in this pass. -## Z1 Source and ABI for the target generation - - - -### Z1.1 Universal rule encoding - -**Current mismatch.** The proposal introduces multi-asset rules; tested `e704d5b` still has single-asset terms. The SDK needs an exact supported encoding before it can finalize the codec. - -**Please provide the implementation revision, ABI and vectors covering:** - -| Area | Detail needed | -| --- | --- | -| Assets and counters | `assets[]`, per-token counters, duplicate assets and zero/unlimited conventions | -| Call-only rules | Routing and token fields when `assets[]` is empty and no tokens move | -| Gas cap | Final `maxGasPerCall` field/layout | -| Destination account | EVM `expectedCEA` type/width and encoding | -| Envelope | Version field, accepted version and body layout | - -If the code is still pending, please identify the agreed target definitions and remaining implementation work. A proposal alone cannot establish the final wire ABI. - -**Evidence:** [proposed section 4c](notion/1-agw-contract-changes.md); [pinned UniversalTerms](https://github.com/pushchain/push-agentic-wallets/blob/e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9/src/libraries/Types.sol#L217). - - - -### Z1.2 Per-token reads and safe replacement - -**Issue.** Replacement must reject a stale spend snapshot. An `assertSpent` function that only returns current totals does not protect a later revoke/grant from an agent spending after the SDK prepared the transaction. - -**Requested behavior:** compare caller-supplied expected totals for all old-rule assets and revert if any differs, inside the same owner transaction as revoke and grant. - -**Please provide:** - -- Per-token spend-read and expected-spend assertion signatures. -- Token ordering/completeness rules for the expected snapshot. -- A vector/test where intervening spend makes the entire replacement revert. - -The SDK will implement the wrapper and atomic batch. Harsh has said per-token spend need not be public, but the SDK still needs these internal reads and assertions for safe replacement. Please align omitted/explicit-zero wire semantics with the final H3 defaults. - -**Evidence:** [current expected-spend assertion](https://github.com/pushchain/push-agentic-wallets/blob/e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9/src/policies/UniversalRulesPolicy.sol#L1409); [proposed assertion change, section 4c](notion/1-agw-contract-changes.md). +## Z1 Remaining surface and integration details -### Z1.3 Reference and label surface +### Z1.3 Ref and editable labels: delivery or v1 scope change? -**Please confirm the selected generation's surface:** +The new generation still exposes grantRules(Session) without ref, and RulesGranted carries no job reference. Label is emitted by WalletDeployed only; setLabel and label storage are absent. The target SDK still promises rule ref and w.setLabel. -| Feature | Open detail | -| --- | --- | -| Grant reference | `ref` parameter/event shape; include it in the owner signature digest when a signed grant is used | -| Editable labels | Whether proposed `setLabel`/label storage ships with this generation, with its ABI/event behavior | +Please confirm whether those are follow-up contract changes for this release or should be explicitly deferred from v1 with Harsh. If they are coming, provide the selected parameter/event shape when ready, including signature binding for ref on signed grants. We will keep unsupported capabilities explicit until the public scope and delivered ABI agree. -Harsh deferred revoked-rule history for v1; no additional historical metadata is requested solely for that feature. Please distinguish committed ref/label features from proposals. + -**Evidence:** [target SDK lifecycle](notion/5-sdk-agw.md); [pinned grant signatures](https://github.com/pushchain/push-agentic-wallets/blob/e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9/src/AGW.sol#L483); [pinned grant event emission](https://github.com/pushchain/push-agentic-wallets/blob/e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9/src/AGW.sol#L636). +### Z1.4 SVM example to validate the SDK mapping - +SvmTerms/program/account/data-pin definitions are supplied; we are not asking for those structs again. If available, please share one representative Donut-to-Solana fixture covering: -### Z1.4 SVM contract surface +- Cluster CAIP-2 value and gateway program/registry source. +- Destination CEA and protected token/output accounts, with their derivation inputs. +- A valid encoded envelope and outbound payload for one allowed instruction; expected account/data-pin matches and corresponding failure cases. -Harsh referred SVM destination work to you. Please identify its supported rule constraints and matching terms/payload ABI or fixtures when ready, including program/discriminator and account/data checks. We need these to implement the SDK representation; Solana-origin signers through UEA are a separate capability. +We will implement SDK resolution/composition. This fixture helps verify that our PDA/ATA coverage and payload encoding match the contract/parser and actual cluster configuration. The owner guide explicitly excludes agent outbound composition; source-level SVM support alone does not prove a live destination route. -Deployment coordination is already agreed: the addresses are known, and you will notify Shoaib when deployment is complete. There is no additional deployment/address request in this document. Compatibility checks and live acceptance remain SDK release work. +## Product choices kept separate -## Supporting documents +[Harsh's draft](questions-harsh.md) retains native omission defaults/public fields, raw-offset authoring and multi-rule send selection. The new guide confirms that multiple rules may exist for the same agent and chain; it does not choose a sendTransaction selection API. No public multi-asset spend, revoked-history or compileCard request is reopened. -[Implementation plan](implementation-plan.md) · [External dependencies](external-blockers.md) · [Current baseline](current-baseline.md) · [Harsh's open decisions](questions-harsh.md) +[Implementation plan](implementation-plan.md) · [External dependencies](external-blockers.md) · [Current baseline](current-baseline.md) diff --git a/plan/agw/research/deployment-review-2026-10-06/README.md b/plan/agw/research/deployment-review-2026-10-06/README.md new file mode 100644 index 00000000..9494a1fb --- /dev/null +++ b/plan/agw/research/deployment-review-2026-10-06/README.md @@ -0,0 +1,85 @@ +# Donut v4 deployment and SDK integration review + +> Historical pre-migration inspection. Its missing-adapter/registry findings were implemented in a66ff7d. [Current migration](../v4-implementation-2026-10-06/README.md) and [live acceptance](../live-acceptance-2026-10-06/README.md) supersede those implementation-status statements; original source evidence is preserved below. + +Reviewed October 6, 2026. **The contract deployment/artifact dependency is substantially delivered; the current SDK adapter still cannot use it.** This is a source/ABI/read-only integration review, not a funded acceptance run or a security audit. + +## Revisions and evidence + +- [deploy-agw documentation head](https://github.com/pushchain/push-agentic-wallets/tree/10a24f101e2e6e0a9b76517b29f5cdb1aa967796): `10a24f101e2e6e0a9b76517b29f5cdb1aa967796`. +- [Reported deployed source](https://github.com/pushchain/push-agentic-wallets/tree/e8db74815cfbbf5389593805e464fe8d85f7f735): `e8db74815cfbbf5389593805e464fe8d85f7f735`. No src changes between it and the documentation head; the linked owner guide was added afterward. +- [Saved address book](source/docs/addresses/donut.md) and [owner guide](source/docs/5_SDK_Owner_Integration.md). [Source manifest](source-manifest.json) records hashes; these are GitHub snapshots, not a new Notion export. +- [Read-only probe](donut-probe.json): Donut chain 42101, block **23931055**, block hash `0x53bae3cfa28570dc06361ef91e33aa9a885e0d01284cf749d4fd5c018d72c83c`. Code, proxy slots and selected views were read at this block. +- [Explorer artifact metadata](explorer-artifacts.json): the five implementation/engine/validator contracts returned verified ABIs, solc 0.8.26, optimizer 833, Cancun. Saved under [abis/](abis/). Explorer verification is reported by the explorer; a local bytecode rebuild was not performed. +- [ABI comparison](abi-comparison.json) against the SDK e704d5b artifacts; [four focused compatibility checks](wire-checks.json) passed. + +## Deployment facts + +| Integration input | Verified at the probe block | +| --- | --- | +| Factory proxy | `0xaF88D0FD947afAe7bBb8F34e8417DCfc165e1aaF` | +| URP proxy | `0x603E7f0aF6e1aAFf46DDfb28b1e99364f8BC59af` | +| Wallet implementation | `0x96D69ec7e6cDdaD414e656B5c9DCA24587DF713c` | +| Engine | `0x165A5E6782f39D30B38c7D97e1303e4CB2aD102a` | +| Validator | `0x068EE2388475A98EE1f5a434C58bFF3444fffFe6` | +| URP version | `3.1.0` | +| Wallet accountId | `push.agw.1.0.0`, unchanged from the earlier source generation | +| Factory paused | false | +| Historical scan start | Address book reports deployment blocks 23923806–23923810; capture transaction receipts/log provenance when producing the release manifest | + +Factory/URP implementation slots and URP admin match the new book; wallet implementation getters point to the new engine, URP, validator and C1 gateway. Runtime sizes match the book. URP SESSION_ENGINE also returned the documented engine. Core's Sepolia gas-token getter returned `0x2971824Db68229D087931155C2b8bB820B275809` at the same block, matching the guide (see supplemental reads). + +These replace the earlier supplied address table for **new v4 integrations**. Existing wallets remain tied to their original factory/generation; their addresses, rules and balances do not migrate. Do not use an unchanged accountId as proof of envelope compatibility. + +## Contract questions now answered + +| Former uncertainty | Delivered answer | Remaining SDK work | +| --- | --- | --- | +| Z1.1 multi-asset body | UniversalTerms = `(uint48,address,(address,uint256,uint256)[],uint256,(address,bytes4,uint16,bool,uint256)[])`; 1–8 PRC20s, distinct and chain-checked | Resolve user tokens, encode/decode caps, retain order and select outbound token | +| Envelope | `abi.encode(uint16(1), string chainNamespace, bytes body)` for native, EVM and SVM | Migrate every grant and decode path; isolate old fixtures | +| EVM expectedCEA | `address`, not proposed bytes32; derived from the wallet on the destination chain | Resolve/check wallet CEA; preserve derivation-drift handling | +| Empty user assets | Empty wire list rejected; guide prescribes destination gas PRC20 at 0/0 for a no-movement rule | Add exactly one routing-only cap only when input is empty; amount remains zero | +| Universal total zero | Zero forbids movement; uint256 maximum represents no total cap | Replace the provisional zero/unlimited universal default; preserve explicit zero | +| Z1.2 assertion | `assertSpent(bytes32,address,uint256[])`; length and every expected value checked in listed-token order, EVM and SVM | Internal per-token snapshot → assertion → revoke → grant in one owner batch | +| SVM terms | Detailed assets/programs/account/data pins/CEA accounts supplied | Public SDK representation, registry/ATA/PDA resolution, payload composer, reads and acceptance | +| Multiple rules | Guide explicitly permits several rules for one agent and chain | Lifecycle validation must align with Harsh's acceptance; send selection still unspecified (H6) | + +Exact source: [Types.sol](source/src/libraries/Types.sol:208), [asset validation](source/src/policies/UniversalRulesPolicy.sol:439), [ordered assertion](source/src/policies/UniversalRulesPolicy.sol:1437). [Multi-asset source tests](source/test/unit/28_multiAsset.t.sol:142) include exact-counter, independent-token, zero-cap and no-movement cases. They were inspected, not rerun. The owner guide excludes the agent outbound path explicitly. + +## Why the SDK is not ready by adding addresses + +1. **All grants:** [session.ts](../../../../packages/core/src/lib/agentic/codec/session.ts:43) still encodes `(string,bytes)`. Its first word is 64, not version 1. New wallet code decodes three fields before URP; native grants are affected too. The exact revert on a grant depends on which decoder is reached; the wire check does not claim an on-chain grant was executed. +2. **New generation:** [deployments.ts](../../../../packages/core/src/lib/agentic/deployments.ts) only recognizes e704d5b and ships an empty registry. Add a separate v4 adapter/manifest after compatibility tests. Keep old local fixtures reproducible. +3. **Universal reads:** getConfig/getSvmConfig retain selectors but return different tuples. A real empty v4 getConfig response decoded with its verified ABI; the old ABI rejected the same bytes. +4. **Universal grants:** [universal.ts](../../../../packages/core/src/lib/agentic/codec/universal.ts:68) still gates encoding. Implement the delivered multi-asset schema, wallet CEA context and routing-only zero cap. +5. **Agent outbound:** [send.ts](../../../../packages/core/src/lib/agentic/execution/send.ts:170) still reads cfg.asset/maxPCPerCall. V4 requires selected token membership in cfg.assets and maxGasPerCall; each outbound still moves one request token, not all listed tokens together. +6. **Replacement:** implement the array-form internal assertion, preserving token order and checking every old-rule asset; do not replace it with a getter or only check the asset used last. +7. **Logs/errors:** OutboundMetered and RevertCredited now include token; creditRevert gains a token argument; the old scalar universal assertion disappears. Refresh policy ABI/error decoding and event consumers. +8. **Multiplicity:** create/add/update and send resolver still enforce one enabled agent/chain pair. Remove lifecycle restrictions in the agreed change, but settle rule selection first; arbitrary first-match execution is not an acceptable substitute. + +Factory, wallet and engine function/event/error signatures and return shapes match the older ABI comparison. **Wallet execution semantics still changed through envelope decoding despite that ABI similarity.** This is why selector/accountId checks alone are insufficient. + +## Still open and scope limits + +- **H3, narrowed:** universal omitted total is specified as uint256 maximum; explicit zero is a hard zero. Native wire totals also use max for unlimited, maxCalls zero is unlimited, destination maxValue zero is non-payable. The guide does not decide all *SDK omission defaults*, especially native maxValuePerCall/maxValueTotal, or explain Harsh's referenced public maxValueTotal change. Token-independence wording still needs product confirmation; the delivered schema retains assets[]. +- **H4.5:** raw offsets are confirmed wire data, but the public authoring/read model is still a product choice. The guide's `4+32*argIndex` shorthand is valid for simple one-word top-level ABI arguments, not arbitrary tuples/arrays; retain the SDK's ABI-layout validation. +- **H6:** same-agent multiplicity is supported; decide public explicit-rule selection versus a defined automatic strategy, including multi-call/overlapping rules. +- **Z1 metadata:** grantRules still takes Session only, RulesGranted has no job ref, label exists only in WalletDeployed, and setLabel is absent. Confirm intended v1 scope; do not fabricate storage/ref events. +- **SVM:** wire definitions are delivered, but usable SDK inputs/resolution and representative cluster fixtures/acceptance are outstanding. CEA plus every listed token/output value-holding account must be protected; URP cannot derive those accounts for the SDK. +- **creditRevert:** [source](source/src/policies/UniversalRulesPolicy.sol:1514) explicitly says the executor does not yet call it on failure. Its no-code account is an expected module-address property, not proof of a defect by itself. Platform integration remains pending. +- **Gateway allowance:** retain separate owner-established allowance. The SDK must not automatically restore an allowance from a stale read. The owner guide does not itself provide a complete approve/setup sequence. +- **Live acceptance:** no wallet was created, funded or granted by this review; no production pull/burn, agent transport, destination execution or settlement was exercised. Native/local SDK counts from e704d5b do not validate v4. + +## Next SDK steps + +1. Add the e8db748/v4 adapter, verified ABIs and candidate manifest; retain e704d5b as a fixture generation. +2. Make envelope encode/decode generation-aware for all rule kinds and replay utilities; add malformed/version regressions. +3. Implement EVM multi-asset codec, token/chain/CEA resolution, no-movement routing and corrected total semantics. +4. Implement v4 term reads and internal per-token spend/assertion adapter; prove all-asset stale-state rollback. +5. Adapt outbound token choice, maxGasPerCall, events/errors and live/replay summaries. Preserve explicit allowance and identity behavior. +6. Settle H6 and revise management/resolver/batch metadata/tests together. Keep ref/label gated until scope is decided. +7. Port the existing real-contract SDK harness to e8db748 and add multi-asset/call-only/version/multiplicity tests. The four checks here are not that harness. +8. Implement SVM SDK mapping/composition with explicit account coverage and cluster fixtures. +9. Finalize registry/manifest including verified event start provenance, then perform preflight and authorized funded E2Es. Do not silently fund or submit while checking docs. + +Reproduction: `python3 plan/agw/research/deployment-review-2026-10-06/probe.py` (new pinned block each run); `node plan/agw/research/deployment-review-2026-10-06/verify-wire.cjs` (uses the saved probe block). The SDK's full test suite and contracts' build/full suite were not rerun because no implementation was changed. diff --git a/plan/agw/research/deployment-review-2026-10-06/abi-comparison.json b/plan/agw/research/deployment-review-2026-10-06/abi-comparison.json new file mode 100644 index 00000000..c5de2281 --- /dev/null +++ b/plan/agw/research/deployment-review-2026-10-06/abi-comparison.json @@ -0,0 +1,48 @@ +{ + "wallet": { + "removed": [], + "added": [], + "output_changed": {} + }, + "factory": { + "removed": [], + "added": [], + "output_changed": {} + }, + "policy": { + "removed": [ + "error AssetMismatch(address,address)", + "event OutboundMetered(bytes32,address,address,uint256)", + "event RevertCredited(bytes32,bytes32,address,uint256)", + "function assertSpent(bytes32,address,uint256)", + "function creditRevert(bytes32,address,bytes32,uint256)" + ], + "added": [ + "error AssetListOutOfRange(uint256)", + "error AssetNotAllowed(address)", + "error AssetSpentMismatch(address,uint256,uint256)", + "error DuplicateAsset(address)", + "error SpentLengthMismatch(uint256,uint256)", + "error UnsupportedEnvelopeVersion(uint256)", + "event OutboundMetered(bytes32,address,address,address,uint256)", + "event RevertCredited(bytes32,bytes32,address,address,uint256)", + "function assertSpent(bytes32,address,uint256[])", + "function creditRevert(bytes32,address,bytes32,address,uint256)" + ], + "output_changed": { + "function getConfig(bytes32,address)": { + "old": "(bool,uint48,bytes32,address,address,uint256,uint256,uint256,uint256,(address,bytes4,uint16,bool,uint256)[])", + "new": "(bool,uint48,address,uint256,(address,uint256,uint256,uint256)[],(address,bytes4,uint16,bool,uint256)[])" + }, + "function getSvmConfig(bytes32,address)": { + "old": "(bool,uint48,bytes32,bytes32,address,uint256,uint256,uint256,uint256,bytes32[],(bytes32,bytes8,uint8,bool,uint8)[],(uint8,uint8,bytes32)[],(uint8,bool,uint16,uint16,uint8,uint8,bytes32,uint64,uint64)[])", + "new": "(bool,uint48,bytes32,bytes32,uint256,(address,uint256,uint256,uint256)[],bytes32[],(bytes32,bytes8,uint8,bool,uint8)[],(uint8,uint8,bytes32)[],(uint8,bool,uint16,uint16,uint8,uint8,bytes32,uint64,uint64)[])" + } + } + }, + "engine": { + "removed": [], + "added": [], + "output_changed": {} + } +} diff --git a/plan/agw/research/deployment-review-2026-10-06/abis/engine.json b/plan/agw/research/deployment-review-2026-10-06/abis/engine.json new file mode 100644 index 00000000..61100bd3 --- /dev/null +++ b/plan/agw/research/deployment-review-2026-10-06/abis/engine.json @@ -0,0 +1,1957 @@ +[ + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "AssociatedArray_OutOfBounds", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint64", + "name": "providedChainId", + "type": "uint64" + } + ], + "name": "ChainIdMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint64", + "name": "providedChainId", + "type": "uint64" + } + ], + "name": "ChainIdMismatch", + "type": "error" + }, + { + "inputs": [], + "name": "ForbiddenValidationData", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "HashIndexOutOfBounds", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "providedHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "computedHash", + "type": "bytes32" + } + ], + "name": "HashMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "providedHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "computedHash", + "type": "bytes32" + } + ], + "name": "HashMismatch", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidActionId", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidCallTarget", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidData", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "hash", + "type": "bytes32" + } + ], + "name": "InvalidEnableSignature", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "contract ISessionValidator", + "name": "sessionValidator", + "type": "address" + } + ], + "name": "InvalidISessionValidator", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidMode", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + } + ], + "name": "InvalidPermissionId", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidSelfCall", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + } + ], + "name": "InvalidSession", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "sessionValidator", + "type": "address" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "userOpHash", + "type": "bytes32" + } + ], + "name": "InvalidSessionKeySignature", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidTarget", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "InvalidUserOpSender", + "type": "error" + }, + { + "inputs": [], + "name": "NoExecutionsInBatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + } + ], + "name": "NoPoliciesSet", + "type": "error" + }, + { + "inputs": [], + "name": "PartlyEnabledActions", + "type": "error" + }, + { + "inputs": [], + "name": "PartlyEnabledPolicies", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + } + ], + "name": "PaymasterValidationNotEnabled", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "policy", + "type": "address" + } + ], + "name": "PolicyViolation", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "SignerNotFound", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "SignerNotFound", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "SmartSessionModuleAlreadyInstalled", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "CallType", + "name": "callType", + "type": "bytes1" + } + ], + "name": "UnsupportedCallType", + "type": "error" + }, + { + "inputs": [], + "name": "UnsupportedExecutionType", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + } + ], + "name": "UnsupportedPolicy", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "enum SmartSessionMode", + "name": "mode", + "type": "uint8" + } + ], + "name": "UnsupportedSmartSessionMode", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "ActionId", + "name": "actionId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "address", + "name": "smartAccount", + "type": "address" + } + ], + "name": "ActionIdDisabled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newValue", + "type": "uint256" + } + ], + "name": "NonceIterated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "address", + "name": "smartAccount", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "enabled", + "type": "bool" + } + ], + "name": "PermissionIdPermit4337Paymaster", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "enum PolicyType", + "name": "policyType", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "smartAccount", + "type": "address" + } + ], + "name": "PolicyDisabled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "enum PolicyType", + "name": "policyType", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "smartAccount", + "type": "address" + } + ], + "name": "PolicyEnabled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "SessionCreated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "address", + "name": "smartAccount", + "type": "address" + } + ], + "name": "SessionRemoved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "address", + "name": "sessionValidator", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "smartAccount", + "type": "address" + } + ], + "name": "SessionValidatorDisabled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "address", + "name": "sessionValidator", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "smartAccount", + "type": "address" + } + ], + "name": "SessionValidatorEnabled", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "components": [ + { + "internalType": "bytes4", + "name": "actionTargetSelector", + "type": "bytes4" + }, + { + "internalType": "address", + "name": "actionTarget", + "type": "address" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "actionPolicies", + "type": "tuple[]" + } + ], + "internalType": "struct ActionData[]", + "name": "actions", + "type": "tuple[]" + } + ], + "name": "areActionsEnabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "erc1271Policies", + "type": "tuple[]" + } + ], + "name": "areERC1271PoliciesEnabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "userOpPolicies", + "type": "tuple[]" + } + ], + "name": "areUserOpPoliciesEnabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "internalType": "ActionId", + "name": "actionId", + "type": "bytes32" + } + ], + "name": "disableActionId", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "internalType": "ActionId", + "name": "actionId", + "type": "bytes32" + }, + { + "internalType": "address[]", + "name": "policies", + "type": "address[]" + } + ], + "name": "disableActionPolicies", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "internalType": "address[]", + "name": "policies", + "type": "address[]" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "appDomainSeparator", + "type": "bytes32" + }, + { + "internalType": "string[]", + "name": "contentNames", + "type": "string[]" + } + ], + "internalType": "struct ERC7739Context[]", + "name": "contexts", + "type": "tuple[]" + } + ], + "name": "disableERC1271Policies", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "internalType": "address[]", + "name": "policies", + "type": "address[]" + } + ], + "name": "disableUserOpPolicies", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "components": [ + { + "internalType": "bytes4", + "name": "actionTargetSelector", + "type": "bytes4" + }, + { + "internalType": "address", + "name": "actionTarget", + "type": "address" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "actionPolicies", + "type": "tuple[]" + } + ], + "internalType": "struct ActionData[]", + "name": "actionPolicies", + "type": "tuple[]" + } + ], + "name": "enableActionPolicies", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "components": [ + { + "components": [ + { + "internalType": "bytes32", + "name": "appDomainSeparator", + "type": "bytes32" + }, + { + "internalType": "string[]", + "name": "contentNames", + "type": "string[]" + } + ], + "internalType": "struct ERC7739Context[]", + "name": "allowedERC7739Content", + "type": "tuple[]" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "erc1271Policies", + "type": "tuple[]" + } + ], + "internalType": "struct ERC7739Data", + "name": "erc1271Policies", + "type": "tuple" + } + ], + "name": "enableERC1271Policies", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "contract ISessionValidator", + "name": "sessionValidator", + "type": "address" + }, + { + "internalType": "bytes", + "name": "sessionValidatorInitData", + "type": "bytes" + }, + { + "internalType": "bytes32", + "name": "salt", + "type": "bytes32" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "userOpPolicies", + "type": "tuple[]" + }, + { + "components": [ + { + "components": [ + { + "internalType": "bytes32", + "name": "appDomainSeparator", + "type": "bytes32" + }, + { + "internalType": "string[]", + "name": "contentNames", + "type": "string[]" + } + ], + "internalType": "struct ERC7739Context[]", + "name": "allowedERC7739Content", + "type": "tuple[]" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "erc1271Policies", + "type": "tuple[]" + } + ], + "internalType": "struct ERC7739Data", + "name": "erc7739Policies", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "bytes4", + "name": "actionTargetSelector", + "type": "bytes4" + }, + { + "internalType": "address", + "name": "actionTarget", + "type": "address" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "actionPolicies", + "type": "tuple[]" + } + ], + "internalType": "struct ActionData[]", + "name": "actions", + "type": "tuple[]" + }, + { + "internalType": "bool", + "name": "permitERC4337Paymaster", + "type": "bool" + } + ], + "internalType": "struct Session[]", + "name": "sessions", + "type": "tuple[]" + } + ], + "name": "enableSessions", + "outputs": [ + { + "internalType": "PermissionId[]", + "name": "permissionIds", + "type": "bytes32[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "userOpPolicies", + "type": "tuple[]" + } + ], + "name": "enableUserOpPolicies", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "internalType": "ActionId", + "name": "actionId", + "type": "bytes32" + } + ], + "name": "getActionPolicies", + "outputs": [ + { + "internalType": "address[]", + "name": "", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + } + ], + "name": "getERC1271Policies", + "outputs": [ + { + "internalType": "address[]", + "name": "", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + } + ], + "name": "getEnabledActions", + "outputs": [ + { + "internalType": "bytes32[]", + "name": "", + "type": "bytes32[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + } + ], + "name": "getEnabledERC7739Content", + "outputs": [ + { + "components": [ + { + "internalType": "bytes32", + "name": "appDomainSeparator", + "type": "bytes32" + }, + { + "internalType": "bytes32[]", + "name": "contentNameHashes", + "type": "bytes32[]" + } + ], + "internalType": "struct ERC7739ContextHashes[]", + "name": "enabledERC7739ContentHashes", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "getNonce", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "getPermissionIDs", + "outputs": [ + { + "internalType": "PermissionId[]", + "name": "permissionIds", + "type": "bytes32[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "contract ISessionValidator", + "name": "sessionValidator", + "type": "address" + }, + { + "internalType": "bytes", + "name": "sessionValidatorInitData", + "type": "bytes" + }, + { + "internalType": "bytes32", + "name": "salt", + "type": "bytes32" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "userOpPolicies", + "type": "tuple[]" + }, + { + "components": [ + { + "components": [ + { + "internalType": "bytes32", + "name": "appDomainSeparator", + "type": "bytes32" + }, + { + "internalType": "string[]", + "name": "contentNames", + "type": "string[]" + } + ], + "internalType": "struct ERC7739Context[]", + "name": "allowedERC7739Content", + "type": "tuple[]" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "erc1271Policies", + "type": "tuple[]" + } + ], + "internalType": "struct ERC7739Data", + "name": "erc7739Policies", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "bytes4", + "name": "actionTargetSelector", + "type": "bytes4" + }, + { + "internalType": "address", + "name": "actionTarget", + "type": "address" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "actionPolicies", + "type": "tuple[]" + } + ], + "internalType": "struct ActionData[]", + "name": "actions", + "type": "tuple[]" + }, + { + "internalType": "bool", + "name": "permitERC4337Paymaster", + "type": "bool" + } + ], + "internalType": "struct Session", + "name": "session", + "type": "tuple" + } + ], + "name": "getPermissionId", + "outputs": [ + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "components": [ + { + "internalType": "contract ISessionValidator", + "name": "sessionValidator", + "type": "address" + }, + { + "internalType": "bytes", + "name": "sessionValidatorInitData", + "type": "bytes" + }, + { + "internalType": "bytes32", + "name": "salt", + "type": "bytes32" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "userOpPolicies", + "type": "tuple[]" + }, + { + "components": [ + { + "components": [ + { + "internalType": "bytes32", + "name": "appDomainSeparator", + "type": "bytes32" + }, + { + "internalType": "string[]", + "name": "contentNames", + "type": "string[]" + } + ], + "internalType": "struct ERC7739Context[]", + "name": "allowedERC7739Content", + "type": "tuple[]" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "erc1271Policies", + "type": "tuple[]" + } + ], + "internalType": "struct ERC7739Data", + "name": "erc7739Policies", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "bytes4", + "name": "actionTargetSelector", + "type": "bytes4" + }, + { + "internalType": "address", + "name": "actionTarget", + "type": "address" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "actionPolicies", + "type": "tuple[]" + } + ], + "internalType": "struct ActionData[]", + "name": "actions", + "type": "tuple[]" + }, + { + "internalType": "bool", + "name": "permitERC4337Paymaster", + "type": "bool" + } + ], + "internalType": "struct Session", + "name": "data", + "type": "tuple" + }, + { + "internalType": "enum SmartSessionMode", + "name": "mode", + "type": "uint8" + } + ], + "name": "getSessionDigest", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + } + ], + "name": "getSessionValidatorAndConfig", + "outputs": [ + { + "internalType": "address", + "name": "sessionValidator", + "type": "address" + }, + { + "internalType": "bytes", + "name": "sessionValidatorData", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + } + ], + "name": "getUserOpPolicies", + "outputs": [ + { + "internalType": "address[]", + "name": "", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "internalType": "ActionId", + "name": "actionId", + "type": "bytes32" + } + ], + "name": "isActionIdEnabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "internalType": "ActionId", + "name": "actionId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "policy", + "type": "address" + } + ], + "name": "isActionPolicyEnabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "policy", + "type": "address" + } + ], + "name": "isERC1271PolicyEnabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "appDomainSeparator", + "type": "bytes32" + }, + { + "internalType": "string", + "name": "content", + "type": "string" + } + ], + "name": "isERC7739ContentEnabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "isISessionValidatorSet", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "smartAccount", + "type": "address" + } + ], + "name": "isInitialized", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "typeID", + "type": "uint256" + } + ], + "name": "isModuleType", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "isPermissionEnabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "policy", + "type": "address" + } + ], + "name": "isUserOpPolicyEnabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "hash", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "name": "isValidSignatureWithSender", + "outputs": [ + { + "internalType": "bytes4", + "name": "result", + "type": "bytes4" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "onInstall", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "name": "onUninstall", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + } + ], + "name": "removeSession", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + } + ], + "name": "revokeEnableSignature", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "internalType": "bool", + "name": "enabled", + "type": "bool" + } + ], + "name": "setPermit4337Paymaster", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "initCode", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "callData", + "type": "bytes" + }, + { + "internalType": "bytes32", + "name": "accountGasLimits", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "preVerificationGas", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "gasFees", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "paymasterAndData", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "internalType": "struct PackedUserOperation", + "name": "userOp", + "type": "tuple" + }, + { + "internalType": "bytes32", + "name": "userOpHash", + "type": "bytes32" + } + ], + "name": "validateUserOp", + "outputs": [ + { + "internalType": "ValidationData", + "name": "vd", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/plan/agw/research/deployment-review-2026-10-06/abis/factory.json b/plan/agw/research/deployment-review-2026-10-06/abis/factory.json new file mode 100644 index 00000000..c2bf3eb7 --- /dev/null +++ b/plan/agw/research/deployment-review-2026-10-06/abis/factory.json @@ -0,0 +1,1105 @@ +[ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "AccessControlBadConfirmation", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint48", + "name": "schedule", + "type": "uint48" + } + ], + "name": "AccessControlEnforcedDefaultAdminDelay", + "type": "error" + }, + { + "inputs": [], + "name": "AccessControlEnforcedDefaultAdminRules", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "defaultAdmin", + "type": "address" + } + ], + "name": "AccessControlInvalidDefaultAdmin", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "neededRole", + "type": "bytes32" + } + ], + "name": "AccessControlUnauthorizedAccount", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "target", + "type": "address" + } + ], + "name": "AddressEmptyCode", + "type": "error" + }, + { + "inputs": [], + "name": "CloneArgumentsTooLong", + "type": "error" + }, + { + "inputs": [], + "name": "Create2EmptyBytecode", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "ERC1967InvalidImplementation", + "type": "error" + }, + { + "inputs": [], + "name": "ERC1967NonPayable", + "type": "error" + }, + { + "inputs": [], + "name": "EnforcedPause", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "expected", + "type": "address" + }, + { + "internalType": "address", + "name": "actual", + "type": "address" + } + ], + "name": "ExecutorMismatch", + "type": "error" + }, + { + "inputs": [], + "name": "ExpectedPause", + "type": "error" + }, + { + "inputs": [], + "name": "FailedCall", + "type": "error" + }, + { + "inputs": [], + "name": "FailedDeployment", + "type": "error" + }, + { + "inputs": [], + "name": "ImplementationNotSet", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint96", + "name": "expected", + "type": "uint96" + }, + { + "internalType": "uint96", + "name": "provided", + "type": "uint96" + } + ], + "name": "IndexMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "next", + "type": "uint256" + } + ], + "name": "IndexOutOfRange", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "needed", + "type": "uint256" + } + ], + "name": "InsufficientBalance", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "expected", + "type": "address" + }, + { + "internalType": "address", + "name": "provided", + "type": "address" + } + ], + "name": "IntentWalletMismatch", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidInitialization", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidOwnerSignature", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "NotAWallet", + "type": "error" + }, + { + "inputs": [], + "name": "NotInitializing", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint8", + "name": "bits", + "type": "uint8" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "SafeCastOverflowedUintDowncast", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint48", + "name": "deadline", + "type": "uint48" + } + ], + "name": "SignatureExpired", + "type": "error" + }, + { + "inputs": [], + "name": "UUPSUnauthorizedCallContext", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "slot", + "type": "bytes32" + } + ], + "name": "UUPSUnsupportedProxiableUUID", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroAddress", + "type": "error" + }, + { + "anonymous": false, + "inputs": [], + "name": "DefaultAdminDelayChangeCanceled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint48", + "name": "newDelay", + "type": "uint48" + }, + { + "indexed": false, + "internalType": "uint48", + "name": "effectSchedule", + "type": "uint48" + } + ], + "name": "DefaultAdminDelayChangeScheduled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "DefaultAdminTransferCanceled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "newAdmin", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint48", + "name": "acceptSchedule", + "type": "uint48" + } + ], + "name": "DefaultAdminTransferScheduled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint64", + "name": "version", + "type": "uint64" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Paused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "previousAdminRole", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "newAdminRole", + "type": "bytes32" + } + ], + "name": "RoleAdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleGranted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleRevoked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Unpaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "Upgraded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "index", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "wallet", + "type": "address" + }, + { + "indexed": false, + "internalType": "string", + "name": "label", + "type": "string" + } + ], + "name": "WalletDeployed", + "type": "event" + }, + { + "inputs": [], + "name": "DEFAULT_ADMIN_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "OPERATOR_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "PAUSER_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "UPGRADE_INTERFACE_VERSION", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "acceptDefaultAdminTransfer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "beginDefaultAdminTransfer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "cancelDefaultAdminTransfer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint48", + "name": "newDelay", + "type": "uint48" + } + ], + "name": "changeDefaultAdminDelay", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "defaultAdmin", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "defaultAdminDelay", + "outputs": [ + { + "internalType": "uint48", + "name": "", + "type": "uint48" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "defaultAdminDelayIncreaseWait", + "outputs": [ + { + "internalType": "uint48", + "name": "", + "type": "uint48" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "label", + "type": "string" + } + ], + "name": "deployWallet", + "outputs": [ + { + "internalType": "address", + "name": "wallet", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "wallet", + "type": "address" + }, + { + "internalType": "address", + "name": "executor", + "type": "address" + }, + { + "internalType": "uint96", + "name": "index", + "type": "uint96" + }, + { + "internalType": "bytes32", + "name": "sessionHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "mode", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "execCalldataHash", + "type": "bytes32" + }, + { + "internalType": "uint192", + "name": "nonceKey", + "type": "uint192" + }, + { + "internalType": "uint64", + "name": "nonceSeq", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "grantNonce", + "type": "uint64" + }, + { + "internalType": "uint48", + "name": "deadline", + "type": "uint48" + }, + { + "internalType": "uint256", + "name": "signerChainId", + "type": "uint256" + } + ], + "internalType": "struct OwnerIntent", + "name": "intent", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "sig", + "type": "bytes" + }, + { + "internalType": "string", + "name": "label", + "type": "string" + } + ], + "name": "deployWalletWithSig", + "outputs": [ + { + "internalType": "address", + "name": "wallet", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "signerChainId", + "type": "uint256" + } + ], + "name": "domainSeparator", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + } + ], + "name": "getRoleAdmin", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "grantRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "hasRole", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "wallet", + "type": "address" + } + ], + "name": "indexOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "admin", + "type": "address" + }, + { + "internalType": "address", + "name": "walletImplementation_", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "isWallet", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "wallet", + "type": "address" + } + ], + "name": "ownerOf", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pendingDefaultAdmin", + "outputs": [ + { + "internalType": "address", + "name": "newAdmin", + "type": "address" + }, + { + "internalType": "uint48", + "name": "schedule", + "type": "uint48" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pendingDefaultAdminDelay", + "outputs": [ + { + "internalType": "uint48", + "name": "newDelay", + "type": "uint48" + }, + { + "internalType": "uint48", + "name": "schedule", + "type": "uint48" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "predictWallet", + "outputs": [ + { + "internalType": "address", + "name": "wallet", + "type": "address" + }, + { + "internalType": "bool", + "name": "deployed", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proxiableUUID", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "renounceRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "revokeRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "rollbackDefaultAdminDelay", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "unpause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "upgradeToAndCall", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "walletCount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "walletImplementation", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } +] diff --git a/plan/agw/research/deployment-review-2026-10-06/abis/policy.json b/plan/agw/research/deployment-review-2026-10-06/abis/policy.json new file mode 100644 index 00000000..c8f2f576 --- /dev/null +++ b/plan/agw/research/deployment-review-2026-10-06/abis/policy.json @@ -0,0 +1,2157 @@ +[ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "length", + "type": "uint256" + } + ], + "name": "AllowListOutOfRange", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "outboundTxId", + "type": "bytes32" + } + ], + "name": "AlreadyCredited", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "ConfigId", + "name": "id", + "type": "bytes32" + } + ], + "name": "AlreadyInitialized", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "i", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "j", + "type": "uint256" + } + ], + "name": "AmbiguousRule", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "cap", + "type": "uint256" + } + ], + "name": "AmountExceedsCap", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "AmountExceedsU64", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "actual", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "expected", + "type": "bytes32" + } + ], + "name": "ArgPinMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "length", + "type": "uint256" + } + ], + "name": "AssetListOutOfRange", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "name": "AssetNotAllowed", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "expected", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "actual", + "type": "uint256" + } + ], + "name": "AssetSpentMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "count", + "type": "uint256" + } + ], + "name": "BatchSizeOutOfRange", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "expected", + "type": "address" + }, + { + "internalType": "address", + "name": "actual", + "type": "address" + } + ], + "name": "BeneficiaryMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint32", + "name": "callsUsed", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "maxCalls", + "type": "uint32" + } + ], + "name": "CallLimitReached", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "bytes4", + "name": "selector", + "type": "bytes4" + } + ], + "name": "CallNotAllowed", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "length", + "type": "uint256" + } + ], + "name": "CalldataTooShort", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "actualLength", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "needed", + "type": "uint256" + } + ], + "name": "CalldataTooShortForAmount", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "actualLength", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "needed", + "type": "uint256" + } + ], + "name": "CalldataTooShortForPin", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "CallerIsNotUEModule", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "accountIndex", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "account", + "type": "bytes32" + } + ], + "name": "CeaAccountAtUnpinnedIndex", + "type": "error" + }, + { + "inputs": [], + "name": "CeaAccountsMissExpectedCEA", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "declared", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "assetChain", + "type": "bytes32" + } + ], + "name": "ChainMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "rule", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "len", + "type": "uint8" + } + ], + "name": "DiscriminatorLenOutOfRange", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "name": "DuplicateAsset", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "first", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "second", + "type": "uint256" + } + ], + "name": "DuplicateSvmPin", + "type": "error" + }, + { + "inputs": [], + "name": "EmptyChain", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "target", + "type": "address" + } + ], + "name": "ForbiddenInnerTarget", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "rule", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "program", + "type": "bytes32" + } + ], + "name": "ForbiddenProgramInAllowList", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "program", + "type": "bytes32" + } + ], + "name": "ForbiddenTargetProgram", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxValue", + "type": "uint256" + } + ], + "name": "InnerValueExceedsAllowance", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "asset", + "type": "address" + } + ], + "name": "InvalidAsset", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "InvalidCeaAccount", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidConfigField", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint48", + "name": "validUntil", + "type": "uint48" + } + ], + "name": "InvalidExpiry", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidInitialization", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "expected", + "type": "address" + }, + { + "internalType": "address", + "name": "actual", + "type": "address" + } + ], + "name": "InvalidRevertRecipient", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "selector", + "type": "bytes4" + } + ], + "name": "InvalidSelector", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidSvmConfigField", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "target", + "type": "address" + } + ], + "name": "InvalidTarget", + "type": "error" + }, + { + "inputs": [], + "name": "MalformedInnerCalldata", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "length", + "type": "uint256" + } + ], + "name": "MalformedOutboundRequest", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint8", + "name": "code", + "type": "uint8" + } + ], + "name": "MalformedSvmPayload", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "cap", + "type": "uint256" + } + ], + "name": "NativeAmountExceedsCap", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "target", + "type": "address" + } + ], + "name": "NativeTargetIsGateway", + "type": "error" + }, + { + "inputs": [], + "name": "NativeTargetZero", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "ConfigId", + "name": "id", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "NotInitialized", + "type": "error" + }, + { + "inputs": [], + "name": "NotInitializing", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "cap", + "type": "uint256" + } + ], + "name": "PCValueExceedsCap", + "type": "error" + }, + { + "inputs": [], + "name": "PayloadNotMulticall", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "ConfigId", + "name": "id", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "multiplexer", + "type": "address" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "PolicyNotInitialized", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "length", + "type": "uint256" + } + ], + "name": "ProgramListOutOfRange", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "program", + "type": "bytes32" + }, + { + "internalType": "bytes8", + "name": "discriminator", + "type": "bytes8" + } + ], + "name": "ProgramNotAllowed", + "type": "error" + }, + { + "inputs": [], + "name": "RecipientMustBeEmpty", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "length", + "type": "uint256" + } + ], + "name": "RecipientNotPubkey", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "recipient", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "target", + "type": "bytes32" + } + ], + "name": "RecipientTargetMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "rule", + "type": "uint256" + } + ], + "name": "RuleWithoutPin", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint48", + "name": "validUntil", + "type": "uint48" + } + ], + "name": "RulesExpired", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "actual", + "type": "bytes4" + }, + { + "internalType": "bytes4", + "name": "expected", + "type": "bytes4" + } + ], + "name": "SelectorMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "expected", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "actual", + "type": "uint256" + } + ], + "name": "SpentLengthMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "expected", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "actual", + "type": "uint256" + } + ], + "name": "SpentMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "pin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "count", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "needed", + "type": "uint8" + } + ], + "name": "SvmAccountCountBelowPin", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "count", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "expected", + "type": "uint8" + } + ], + "name": "SvmAccountCountMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "pin", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "accountIndex", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "expected", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "actual", + "type": "bytes32" + } + ], + "name": "SvmAccountPinMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "count", + "type": "uint256" + } + ], + "name": "SvmAccountsOutOfRange", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "pin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "actual", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "ceiling", + "type": "uint256" + } + ], + "name": "SvmDataCeilingExceeded", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "pin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "actual", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "floor", + "type": "uint256" + } + ], + "name": "SvmDataFloorNotMet", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "pin", + "type": "uint256" + } + ], + "name": "SvmDataPinInvalid", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "pin", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "expected", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "actual", + "type": "bytes32" + } + ], + "name": "SvmDataPinMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "pin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "a", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "b", + "type": "uint256" + }, + { + "internalType": "uint64", + "name": "num", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "den", + "type": "uint64" + } + ], + "name": "SvmDataRatioNotMet", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "pin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "ixLen", + "type": "uint256" + } + ], + "name": "SvmDataTooShortForPin", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint8", + "name": "instructionId", + "type": "uint8" + } + ], + "name": "SvmInstructionNotExecute", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "length", + "type": "uint256" + } + ], + "name": "SvmIxDataTooLong", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "rule", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "maxAccounts", + "type": "uint8" + } + ], + "name": "SvmMaxAccountsOutOfRange", + "type": "error" + }, + { + "inputs": [], + "name": "SvmPayloadEmpty", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "pin", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "accountIndex", + "type": "uint8" + } + ], + "name": "SvmPinIndexOutOfRange", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "pin", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "rule", + "type": "uint8" + } + ], + "name": "SvmPinRuleOutOfRange", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "actual", + "type": "address" + }, + { + "internalType": "address", + "name": "expected", + "type": "address" + } + ], + "name": "TargetMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "count", + "type": "uint256" + } + ], + "name": "TooManyCeaAccounts", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "count", + "type": "uint256" + } + ], + "name": "TooManyPins", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "count", + "type": "uint256" + } + ], + "name": "TooManySvmDataPins", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "count", + "type": "uint256" + } + ], + "name": "TooManySvmPins", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newSpent", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "cap", + "type": "uint256" + } + ], + "name": "TotalNativeAmountExceeded", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "wouldBeTotal", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "cap", + "type": "uint256" + } + ], + "name": "TotalSpendCapExceeded", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newSpent", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "cap", + "type": "uint256" + } + ], + "name": "TotalValueExceeded", + "type": "error" + }, + { + "inputs": [], + "name": "UncappedGasSwapRejected", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "version", + "type": "uint256" + } + ], + "name": "UnsupportedEnvelopeVersion", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "chainHash", + "type": "bytes32" + } + ], + "name": "UnsupportedNamespace", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "cap", + "type": "uint256" + } + ], + "name": "ValueExceedsCap", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "length", + "type": "uint256" + } + ], + "name": "ValueOnlyCalldataNotEmpty", + "type": "error" + }, + { + "inputs": [], + "name": "ValueOnlyWithAmountRule", + "type": "error" + }, + { + "inputs": [], + "name": "ValueOnlyWithPins", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "enum RulesType", + "name": "actual", + "type": "uint8" + } + ], + "name": "WrongModeForCall", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "enum VmFamily", + "name": "actual", + "type": "uint8" + } + ], + "name": "WrongVmForCall", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroAddress", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint64", + "name": "version", + "type": "uint64" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "ConfigId", + "name": "id", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "multiplexer", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "NativeCallMetered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "ConfigId", + "name": "id", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "multiplexer", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "OutboundMetered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "ConfigId", + "name": "id", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "address", + "name": "multiplexer", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "PolicySet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "outboundTxId", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "ConfigId", + "name": "id", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amountApplied", + "type": "uint256" + } + ], + "name": "RevertCredited", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "ConfigId", + "name": "id", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "multiplexer", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "enum RulesType", + "name": "mode", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "enum VmFamily", + "name": "vm", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "chainHash", + "type": "bytes32" + } + ], + "name": "RulesConfigured", + "type": "event" + }, + { + "inputs": [], + "name": "SEND_OUTBOUND_SELECTOR", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "SESSION_ENGINE", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "UNIVERSAL_EXECUTOR_MODULE", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "UNIVERSAL_GATEWAY_PC", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "ConfigId", + "name": "id", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "expectedValueSpent", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expectedAmountSpent", + "type": "uint256" + }, + { + "internalType": "uint32", + "name": "expectedCalls", + "type": "uint32" + } + ], + "name": "assertSpent", + "outputs": [], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "ConfigId", + "name": "id", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256[]", + "name": "expectedSpent", + "type": "uint256[]" + } + ], + "name": "assertSpent", + "outputs": [], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "ConfigId", + "name": "id", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "checkAction", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "ConfigId", + "name": "id", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "outboundTxId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "creditRevert", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "ConfigId", + "name": "id", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "getConfig", + "outputs": [ + { + "components": [ + { + "internalType": "bool", + "name": "initialized", + "type": "bool" + }, + { + "internalType": "uint48", + "name": "validUntil", + "type": "uint48" + }, + { + "internalType": "address", + "name": "expectedCEA", + "type": "address" + }, + { + "internalType": "uint256", + "name": "maxGasPerCall", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "maxPerCall", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxTotal", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "spent", + "type": "uint256" + } + ], + "internalType": "struct AssetCapState[]", + "name": "assets", + "type": "tuple[]" + }, + { + "components": [ + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "bytes4", + "name": "selector", + "type": "bytes4" + }, + { + "internalType": "uint16", + "name": "beneficiaryOffset", + "type": "uint16" + }, + { + "internalType": "bool", + "name": "hasBeneficiary", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "maxValue", + "type": "uint256" + } + ], + "internalType": "struct AllowedCall[]", + "name": "allowedCalls", + "type": "tuple[]" + } + ], + "internalType": "struct Config", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "ConfigId", + "name": "id", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "getMode", + "outputs": [ + { + "components": [ + { + "internalType": "bool", + "name": "initialized", + "type": "bool" + }, + { + "internalType": "enum RulesType", + "name": "mode", + "type": "uint8" + }, + { + "internalType": "enum VmFamily", + "name": "vm", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "chainHash", + "type": "bytes32" + } + ], + "internalType": "struct ModeSlot", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "ConfigId", + "name": "id", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "getNativeConfig", + "outputs": [ + { + "components": [ + { + "internalType": "bool", + "name": "initialized", + "type": "bool" + }, + { + "internalType": "uint48", + "name": "validUntil", + "type": "uint48" + }, + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "bytes4", + "name": "selector", + "type": "bytes4" + }, + { + "internalType": "uint256", + "name": "maxValuePerCall", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxValueTotal", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "valueSpent", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "bool", + "name": "enabled", + "type": "bool" + }, + { + "internalType": "uint16", + "name": "offset", + "type": "uint16" + }, + { + "internalType": "uint256", + "name": "maxPerCall", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxTotal", + "type": "uint256" + } + ], + "internalType": "struct AmountRule", + "name": "amount", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "amountSpent", + "type": "uint256" + }, + { + "internalType": "uint32", + "name": "maxCalls", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "callsUsed", + "type": "uint32" + }, + { + "components": [ + { + "internalType": "uint16", + "name": "offset", + "type": "uint16" + }, + { + "internalType": "bytes32", + "name": "expected", + "type": "bytes32" + } + ], + "internalType": "struct ArgPin[]", + "name": "pins", + "type": "tuple[]" + } + ], + "internalType": "struct NativeConfig", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "ConfigId", + "name": "id", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "getSvmConfig", + "outputs": [ + { + "components": [ + { + "internalType": "bool", + "name": "initialized", + "type": "bool" + }, + { + "internalType": "uint48", + "name": "validUntil", + "type": "uint48" + }, + { + "internalType": "bytes32", + "name": "expectedCEA", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "gatewayProgram", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "maxGasPerCall", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "maxPerCall", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxTotal", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "spent", + "type": "uint256" + } + ], + "internalType": "struct AssetCapState[]", + "name": "assets", + "type": "tuple[]" + }, + { + "internalType": "bytes32[]", + "name": "ceaAccounts", + "type": "bytes32[]" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "program", + "type": "bytes32" + }, + { + "internalType": "bytes8", + "name": "discriminator", + "type": "bytes8" + }, + { + "internalType": "uint8", + "name": "discriminatorLen", + "type": "uint8" + }, + { + "internalType": "bool", + "name": "dataless", + "type": "bool" + }, + { + "internalType": "uint8", + "name": "maxAccounts", + "type": "uint8" + } + ], + "internalType": "struct AllowedProgram[]", + "name": "programs", + "type": "tuple[]" + }, + { + "components": [ + { + "internalType": "uint8", + "name": "ruleIndex", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "accountIndex", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "expected", + "type": "bytes32" + } + ], + "internalType": "struct SvmAccountPin[]", + "name": "pins", + "type": "tuple[]" + }, + { + "components": [ + { + "internalType": "uint8", + "name": "ruleIndex", + "type": "uint8" + }, + { + "internalType": "bool", + "name": "fromEnd", + "type": "bool" + }, + { + "internalType": "uint16", + "name": "offset", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "offsetB", + "type": "uint16" + }, + { + "internalType": "uint8", + "name": "len", + "type": "uint8" + }, + { + "internalType": "enum SvmDataPinMode", + "name": "mode", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "expected", + "type": "bytes32" + }, + { + "internalType": "uint64", + "name": "num", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "den", + "type": "uint64" + } + ], + "internalType": "struct SvmDataPin[]", + "name": "dataPins", + "type": "tuple[]" + } + ], + "internalType": "struct SvmConfig", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "universalGatewayPC", + "type": "address" + }, + { + "internalType": "address", + "name": "universalExecutorModule", + "type": "address" + }, + { + "internalType": "address", + "name": "sessionEngine", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "ConfigId", + "name": "configId", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "name": "initializeWithMultiplexer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "outboundTxId", + "type": "bytes32" + } + ], + "name": "isCredited", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pushChainHash", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "iid", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "version", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "pure", + "type": "function" + } +] diff --git a/plan/agw/research/deployment-review-2026-10-06/abis/validator.json b/plan/agw/research/deployment-review-2026-10-06/abis/validator.json new file mode 100644 index 00000000..d043841a --- /dev/null +++ b/plan/agw/research/deployment-review-2026-10-06/abis/validator.json @@ -0,0 +1,141 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "smartAccount", + "type": "address" + } + ], + "name": "AlreadyInitialized", + "type": "error" + }, + { + "inputs": [], + "name": "MalformedConfig", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "smartAccount", + "type": "address" + } + ], + "name": "NotInitialized", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "isInitialized", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "moduleTypeId", + "type": "uint256" + } + ], + "name": "isModuleType", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "name": "onInstall", + "outputs": [], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "name": "onUninstall", + "outputs": [], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "validateConfig", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "sig", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "validateSignatureWithData", + "outputs": [ + { + "internalType": "bool", + "name": "validSig", + "type": "bool" + } + ], + "stateMutability": "pure", + "type": "function" + } +] diff --git a/plan/agw/research/deployment-review-2026-10-06/abis/wallet.json b/plan/agw/research/deployment-review-2026-10-06/abis/wallet.json new file mode 100644 index 00000000..4f12c4b4 --- /dev/null +++ b/plan/agw/research/deployment-review-2026-10-06/abis/wallet.json @@ -0,0 +1,1550 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "sessionEngine_", + "type": "address" + }, + { + "internalType": "address", + "name": "rulesPolicy_", + "type": "address" + }, + { + "internalType": "address", + "name": "sessionValidator_", + "type": "address" + }, + { + "internalType": "address", + "name": "universalGatewayPC_", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "AlreadyInitialized", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "rulesId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "CallerIsNotAgent", + "type": "error" + }, + { + "inputs": [], + "name": "CallerIsNotFactory", + "type": "error" + }, + { + "inputs": [], + "name": "CallerIsNotOwner", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "bytes4", + "name": "selector", + "type": "bytes4" + } + ], + "name": "DuplicateAction", + "type": "error" + }, + { + "inputs": [], + "name": "EmptyChain", + "type": "error" + }, + { + "inputs": [], + "name": "EngineStillHoldsPermissions", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "expected", + "type": "address" + }, + { + "internalType": "address", + "name": "actual", + "type": "address" + } + ], + "name": "ExecutorMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "selector", + "type": "bytes4" + } + ], + "name": "ForbiddenActionSelector", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "target", + "type": "address" + } + ], + "name": "ForbiddenActionTarget", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "target", + "type": "address" + } + ], + "name": "ForbiddenDispatchTarget", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "actionIndex", + "type": "uint256" + } + ], + "name": "InconsistentChain", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "actualCalldataHash", + "type": "bytes32" + } + ], + "name": "IntentExecMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint64", + "name": "expected", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "provided", + "type": "uint64" + } + ], + "name": "IntentGrantNonceMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "actual", + "type": "bytes32" + } + ], + "name": "IntentSessionMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "expected", + "type": "address" + }, + { + "internalType": "address", + "name": "provided", + "type": "address" + } + ], + "name": "IntentWalletMismatch", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidModuleAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint192", + "name": "nonceKey", + "type": "uint192" + }, + { + "internalType": "uint64", + "name": "expected", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "provided", + "type": "uint64" + } + ], + "name": "InvalidNonce", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidOwnerSignature", + "type": "error" + }, + { + "inputs": [], + "name": "MalformedBatchCalldata", + "type": "error" + }, + { + "inputs": [], + "name": "MalformedSessionShape", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "module", + "type": "address" + } + ], + "name": "ModuleAlreadyInstalled", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint48", + "name": "validAfter", + "type": "uint48" + }, + { + "internalType": "uint48", + "name": "validUntil", + "type": "uint48" + } + ], + "name": "OutsideTimeWindow", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint192", + "name": "nonceKey", + "type": "uint192" + } + ], + "name": "OwnerLaneRequired", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint48", + "name": "deadline", + "type": "uint48" + } + ], + "name": "OwnerSigExpired", + "type": "error" + }, + { + "inputs": [], + "name": "ReentrancyGuardReentrantCall", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "enum RulesType", + "name": "derived", + "type": "uint8" + }, + { + "internalType": "uint256", + "name": "actionIndex", + "type": "uint256" + }, + { + "internalType": "address", + "name": "target", + "type": "address" + } + ], + "name": "RulesTypeMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "count", + "type": "uint256" + } + ], + "name": "TooManyActions", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "rulesId", + "type": "bytes32" + } + ], + "name": "UnknownPermission", + "type": "error" + }, + { + "inputs": [], + "name": "UnsupportedExecutionMode", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "moduleTypeId", + "type": "uint256" + } + ], + "name": "UnsupportedModuleType", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "authorizer", + "type": "address" + } + ], + "name": "ValidationFailed", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "validator", + "type": "address" + } + ], + "name": "ValidatorNotInstalled", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "engine", + "type": "address" + } + ], + "name": "AccountInitialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint64", + "name": "seq", + "type": "uint64" + }, + { + "indexed": false, + "internalType": "enum CheckpointKind", + "name": "kind", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "ref", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "uint64", + "name": "blockNumber", + "type": "uint64" + } + ], + "name": "Checkpointed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "moduleTypeId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "module", + "type": "address" + } + ], + "name": "ModuleInstalled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "moduleTypeId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "module", + "type": "address" + } + ], + "name": "ModuleUninstalled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "mode", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "executionCalldataHash", + "type": "bytes32" + } + ], + "name": "OwnerExecuted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "mode", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "executionCalldataHash", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "uint192", + "name": "nonceKey", + "type": "uint192" + }, + { + "indexed": false, + "internalType": "uint64", + "name": "nonceSeq", + "type": "uint64" + } + ], + "name": "OwnerExecutedWithSig", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "rulesId", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "agent", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "callsHash", + "type": "bytes32" + } + ], + "name": "RulesActionAuthorized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "rulesId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "enum RulesType", + "name": "mode", + "type": "uint8" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "chainHash", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "string", + "name": "chainNamespace", + "type": "string" + } + ], + "name": "RulesGranted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "rulesId", + "type": "bytes32" + } + ], + "name": "RulesRevoked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "module", + "type": "address" + } + ], + "name": "UninstallCallbackFailed", + "type": "event" + }, + { + "inputs": [], + "name": "RULES_POLICY", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "SESSION_ENGINE", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "SESSION_VALIDATOR", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "UNIVERSAL_GATEWAY_PC", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "accountId", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "rulesId", + "type": "bytes32" + } + ], + "name": "agentOf", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "checkpointCount", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "signerChainId", + "type": "uint256" + } + ], + "name": "domainSeparator", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "mode", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "executionCalldata", + "type": "bytes" + } + ], + "name": "execute", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "rulesId", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "mode", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "executionCalldata", + "type": "bytes" + } + ], + "name": "executeAsAgent", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "mode", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "executionCalldata", + "type": "bytes" + }, + { + "components": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "wallet", + "type": "address" + }, + { + "internalType": "address", + "name": "executor", + "type": "address" + }, + { + "internalType": "uint96", + "name": "index", + "type": "uint96" + }, + { + "internalType": "bytes32", + "name": "sessionHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "mode", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "execCalldataHash", + "type": "bytes32" + }, + { + "internalType": "uint192", + "name": "nonceKey", + "type": "uint192" + }, + { + "internalType": "uint64", + "name": "nonceSeq", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "grantNonce", + "type": "uint64" + }, + { + "internalType": "uint48", + "name": "deadline", + "type": "uint48" + }, + { + "internalType": "uint256", + "name": "signerChainId", + "type": "uint256" + } + ], + "internalType": "struct OwnerIntent", + "name": "intent", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "sig", + "type": "bytes" + } + ], + "name": "executeWithSig", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "factory", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint192", + "name": "nonceKey", + "type": "uint192" + } + ], + "name": "getNonce", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "grantNonce", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "contract ISessionValidator", + "name": "sessionValidator", + "type": "address" + }, + { + "internalType": "bytes", + "name": "sessionValidatorInitData", + "type": "bytes" + }, + { + "internalType": "bytes32", + "name": "salt", + "type": "bytes32" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "userOpPolicies", + "type": "tuple[]" + }, + { + "components": [ + { + "components": [ + { + "internalType": "bytes32", + "name": "appDomainSeparator", + "type": "bytes32" + }, + { + "internalType": "string[]", + "name": "contentNames", + "type": "string[]" + } + ], + "internalType": "struct ERC7739Context[]", + "name": "allowedERC7739Content", + "type": "tuple[]" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "erc1271Policies", + "type": "tuple[]" + } + ], + "internalType": "struct ERC7739Data", + "name": "erc7739Policies", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "bytes4", + "name": "actionTargetSelector", + "type": "bytes4" + }, + { + "internalType": "address", + "name": "actionTarget", + "type": "address" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "actionPolicies", + "type": "tuple[]" + } + ], + "internalType": "struct ActionData[]", + "name": "actions", + "type": "tuple[]" + }, + { + "internalType": "bool", + "name": "permitERC4337Paymaster", + "type": "bool" + } + ], + "internalType": "struct Session", + "name": "session", + "type": "tuple" + } + ], + "name": "grantRules", + "outputs": [ + { + "internalType": "bytes32", + "name": "rulesId", + "type": "bytes32" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "contract ISessionValidator", + "name": "sessionValidator", + "type": "address" + }, + { + "internalType": "bytes", + "name": "sessionValidatorInitData", + "type": "bytes" + }, + { + "internalType": "bytes32", + "name": "salt", + "type": "bytes32" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "userOpPolicies", + "type": "tuple[]" + }, + { + "components": [ + { + "components": [ + { + "internalType": "bytes32", + "name": "appDomainSeparator", + "type": "bytes32" + }, + { + "internalType": "string[]", + "name": "contentNames", + "type": "string[]" + } + ], + "internalType": "struct ERC7739Context[]", + "name": "allowedERC7739Content", + "type": "tuple[]" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "erc1271Policies", + "type": "tuple[]" + } + ], + "internalType": "struct ERC7739Data", + "name": "erc7739Policies", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "bytes4", + "name": "actionTargetSelector", + "type": "bytes4" + }, + { + "internalType": "address", + "name": "actionTarget", + "type": "address" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "actionPolicies", + "type": "tuple[]" + } + ], + "internalType": "struct ActionData[]", + "name": "actions", + "type": "tuple[]" + }, + { + "internalType": "bool", + "name": "permitERC4337Paymaster", + "type": "bool" + } + ], + "internalType": "struct Session", + "name": "session", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "wallet", + "type": "address" + }, + { + "internalType": "address", + "name": "executor", + "type": "address" + }, + { + "internalType": "uint96", + "name": "index", + "type": "uint96" + }, + { + "internalType": "bytes32", + "name": "sessionHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "mode", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "execCalldataHash", + "type": "bytes32" + }, + { + "internalType": "uint192", + "name": "nonceKey", + "type": "uint192" + }, + { + "internalType": "uint64", + "name": "nonceSeq", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "grantNonce", + "type": "uint64" + }, + { + "internalType": "uint48", + "name": "deadline", + "type": "uint48" + }, + { + "internalType": "uint256", + "name": "signerChainId", + "type": "uint256" + } + ], + "internalType": "struct OwnerIntent", + "name": "intent", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "sig", + "type": "bytes" + } + ], + "name": "grantRulesWithSig", + "outputs": [ + { + "internalType": "bytes32", + "name": "rulesId", + "type": "bytes32" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "initializeAccount", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "moduleTypeId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "module", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "name": "installModule", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "moduleTypeId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "module", + "type": "address" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "name": "isModuleInstalled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "name": "isValidSignature", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "lastCheckpointBlock", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "name": "onERC1155BatchReceived", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "name": "onERC1155Received", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "name": "onERC721Received", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "revokeAllRules", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "rulesId", + "type": "bytes32" + } + ], + "name": "revokeRules", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "mode", + "type": "bytes32" + } + ], + "name": "supportsExecutionMode", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "moduleTypeId", + "type": "uint256" + } + ], + "name": "supportsModule", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "moduleTypeId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "module", + "type": "address" + }, + { + "internalType": "bytes", + "name": "deInitData", + "type": "bytes" + } + ], + "name": "uninstallModule", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } +] diff --git a/plan/agw/research/deployment-review-2026-10-06/donut-probe.json b/plan/agw/research/deployment-review-2026-10-06/donut-probe.json new file mode 100644 index 00000000..56a6e805 --- /dev/null +++ b/plan/agw/research/deployment-review-2026-10-06/donut-probe.json @@ -0,0 +1,157 @@ +{ + "checked_at": "2026-10-05T18:33:27.508124+00:00", + "rpc": "https://evm.donut.rpc.push.org/", + "chain_id": 42101, + "block": 23931055, + "block_hash": "0x53bae3cfa28570dc06361ef91e33aa9a885e0d01284cf749d4fd5c018d72c83c", + "block_timestamp": 1791225195, + "code": { + "factory": { + "address": "0xaF88D0FD947afAe7bBb8F34e8417DCfc165e1aaF", + "bytes": 141, + "sha256": "c621e945a17be2361dfc247326991d732ede3e25c8ecd8b48ee2025c10ca17eb" + }, + "factoryLogic": { + "address": "0xe138Dc6EfC10233BE1e6c8aF1Caf8cABe599cfC2", + "bytes": 9992, + "sha256": "69cc6b0cfae87debb1da55ba152f0129a8f24e80a740199ab29277811b106ecf" + }, + "walletImplementation": { + "address": "0x96D69ec7e6cDdaD414e656B5c9DCA24587DF713c", + "bytes": 16564, + "sha256": "b26d74bdac5c936e25c694394be9b17bc350325d62ba103d262882b0605a0be1" + }, + "policy": { + "address": "0x603E7f0aF6e1aAFf46DDfb28b1e99364f8BC59af", + "bytes": 830, + "sha256": "039e9bca120a30980a0131552966575b30349654f23746f309fe98adfd2308ae" + }, + "policyImplementation": { + "address": "0xA2391eee4C9EA1B32AEB3A460B77296EA709F02F", + "bytes": 24326, + "sha256": "1694277b24a023615b3693730ea0581e7a6fc209f533e65416d5075ef927df76" + }, + "proxyAdmin": { + "address": "0x0b7a31ec85117892aEA90AA5cB6514e2F97c2295", + "bytes": 926, + "sha256": "3feda633be447e268d618b40cbfcd9dfe9346ebadec981f4f3efea0fbc07cd35" + }, + "validator": { + "address": "0x068EE2388475A98EE1f5a434C58bFF3444fffFe6", + "bytes": 806, + "sha256": "7a8e45814fd8a0a6c9b9e115d797da078718f9f6358fa576e1e218ffd93db59e" + }, + "engine": { + "address": "0x165A5E6782f39D30B38c7D97e1303e4CB2aD102a", + "bytes": 22581, + "sha256": "c4b9fc7b045d9f33953079a91fcb7ae883dd858d9cde827a9cc3df6043bc2d0b" + }, + "gateway": { + "address": "0x00000000000000000000000000000000000000C1", + "bytes": 1551, + "sha256": "3e78a5778be1383f2612556becde8019c22388d7157574c90fb40e1060d450ca" + }, + "core": { + "address": "0x00000000000000000000000000000000000000C0", + "bytes": 1551, + "sha256": "2036ba987ed029f1bc576d020ba11582934583c7eaaa7c00aefc2e0d53053486" + }, + "executor": { + "address": "0x14191Ea54B4c176fCf86f51b0FAc7CB1E71Df7d7", + "bytes": 0, + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + } + }, + "slots": { + "factory": { + "implementation": "0x000000000000000000000000e138dc6efc10233be1e6c8af1caf8cabe599cfc2" + }, + "policy": { + "implementation": "0x000000000000000000000000a2391eee4c9ea1b32aeb3a460b77296ea709f02f", + "admin": "0x0000000000000000000000000b7a31ec85117892aea90aa5cb6514e2f97c2295" + }, + "gateway": { + "implementation": "0x0000000000000000000000001e412939780f2b834dc42c7ac58d9f99888da659" + } + }, + "reads": [ + { + "contract": "factory", + "signature": "walletImplementation()(address)", + "exit_code": 0, + "output": "0x96D69ec7e6cDdaD414e656B5c9DCA24587DF713c", + "error": "" + }, + { + "contract": "factory", + "signature": "paused()(bool)", + "exit_code": 0, + "output": "false", + "error": "" + }, + { + "contract": "policy", + "signature": "version()(string)", + "exit_code": 0, + "output": "\"3.1.0\"", + "error": "" + }, + { + "contract": "policy", + "signature": "pushChainHash()(bytes32)", + "exit_code": 0, + "output": "0x3d6bc1f1d3fb03065860265a8e93840b586e57075d956cd41b4319d040be87f9", + "error": "" + }, + { + "contract": "policy", + "signature": "UNIVERSAL_GATEWAY_PC()(address)", + "exit_code": 0, + "output": "0x00000000000000000000000000000000000000C1", + "error": "" + }, + { + "contract": "policy", + "signature": "UNIVERSAL_EXECUTOR_MODULE()(address)", + "exit_code": 0, + "output": "0x14191Ea54B4c176fCf86f51b0FAc7CB1E71Df7d7", + "error": "" + }, + { + "contract": "walletImplementation", + "signature": "accountId()(string)", + "exit_code": 0, + "output": "\"push.agw.1.0.0\"", + "error": "" + }, + { + "contract": "walletImplementation", + "signature": "SESSION_ENGINE()(address)", + "exit_code": 0, + "output": "0x165A5E6782f39D30B38c7D97e1303e4CB2aD102a", + "error": "" + }, + { + "contract": "walletImplementation", + "signature": "RULES_POLICY()(address)", + "exit_code": 0, + "output": "0x603E7f0aF6e1aAFf46DDfb28b1e99364f8BC59af", + "error": "" + }, + { + "contract": "walletImplementation", + "signature": "SESSION_VALIDATOR()(address)", + "exit_code": 0, + "output": "0x068EE2388475A98EE1f5a434C58bFF3444fffFe6", + "error": "" + }, + { + "contract": "walletImplementation", + "signature": "UNIVERSAL_GATEWAY_PC()(address)", + "exit_code": 0, + "output": "0x00000000000000000000000000000000000000C1", + "error": "" + } + ], + "limits": "Code sizes, proxy slots and selected views only; no complete bytecode/source equivalence or transaction execution proof." +} diff --git a/plan/agw/research/deployment-review-2026-10-06/explorer-artifacts.json b/plan/agw/research/deployment-review-2026-10-06/explorer-artifacts.json new file mode 100644 index 00000000..966c64bb --- /dev/null +++ b/plan/agw/research/deployment-review-2026-10-06/explorer-artifacts.json @@ -0,0 +1,70 @@ +{ + "retrieved_at": "2026-10-05T18:34:24.706088+00:00", + "contracts": [ + { + "contract": "factory", + "address": "0xe138Dc6EfC10233BE1e6c8aF1Caf8cABe599cfC2", + "url": "https://donut.push.network/api/v2/smart-contracts/0xe138Dc6EfC10233BE1e6c8aF1Caf8cABe599cfC2", + "abi_entries": 78, + "name": "AGWFactory", + "is_verified": true, + "compiler_version": "v0.8.26+commit.8a97fa7a", + "optimization_enabled": true, + "optimization_runs": 833, + "evm_version": "cancun", + "verified_at": "2026-10-05T13:39:06.864566Z" + }, + { + "contract": "wallet", + "address": "0x96D69ec7e6cDdaD414e656B5c9DCA24587DF713c", + "url": "https://donut.push.network/api/v2/smart-contracts/0x96D69ec7e6cDdaD414e656B5c9DCA24587DF713c", + "abi_entries": 76, + "name": "AGW", + "is_verified": true, + "compiler_version": "v0.8.26+commit.8a97fa7a", + "optimization_enabled": true, + "optimization_runs": 833, + "evm_version": "cancun", + "verified_at": "2026-10-05T13:38:54.015751Z" + }, + { + "contract": "policy", + "address": "0xA2391eee4C9EA1B32AEB3A460B77296EA709F02F", + "url": "https://donut.push.network/api/v2/smart-contracts/0xA2391eee4C9EA1B32AEB3A460B77296EA709F02F", + "abi_entries": 118, + "name": "UniversalRulesPolicy", + "is_verified": true, + "compiler_version": "v0.8.26+commit.8a97fa7a", + "optimization_enabled": true, + "optimization_runs": 833, + "evm_version": "cancun", + "verified_at": "2026-10-05T13:37:25.346522Z" + }, + { + "contract": "validator", + "address": "0x068EE2388475A98EE1f5a434C58bFF3444fffFe6", + "url": "https://donut.push.network/api/v2/smart-contracts/0x068EE2388475A98EE1f5a434C58bFF3444fffFe6", + "abi_entries": 9, + "name": "AgentValidator", + "is_verified": true, + "compiler_version": "v0.8.26+commit.8a97fa7a", + "optimization_enabled": true, + "optimization_runs": 833, + "evm_version": "cancun", + "verified_at": "2026-10-05T13:36:34.683015Z" + }, + { + "contract": "engine", + "address": "0x165A5E6782f39D30B38c7D97e1303e4CB2aD102a", + "url": "https://donut.push.network/api/v2/smart-contracts/0x165A5E6782f39D30B38c7D97e1303e4CB2aD102a", + "abi_entries": 78, + "name": "SmartSession", + "is_verified": true, + "compiler_version": "v0.8.26+commit.8a97fa7a", + "optimization_enabled": true, + "optimization_runs": 833, + "evm_version": "cancun", + "verified_at": "2026-10-05T13:36:21.112501Z" + } + ] +} diff --git a/plan/agw/research/deployment-review-2026-10-06/previous-current-baseline.md b/plan/agw/research/deployment-review-2026-10-06/previous-current-baseline.md new file mode 100644 index 00000000..524ab54e --- /dev/null +++ b/plan/agw/research/deployment-review-2026-10-06/previous-current-baseline.md @@ -0,0 +1,88 @@ +> Historical baseline saved before the October 6 v4 review. Do not use its earlier deployment/artifact absence as current status. Relative links now resolve from this archive location. + +# Current validated AGW baseline + +> October 4 update: [Harsh’s replies](../../product-decisions-2026-10-04.md) supersede earlier provisional approval/default/helper/history/compiler recommendations below. Use [remaining dependencies](../../external-blockers.md) for current blockers. The clear scope changes and sender-preserving native batching are now implemented; H3 defaults remain unchanged pending clarification. See [alignment evidence](../../research/product-alignment-2026-10-04/README.md). + +Updated October 3, 2026 after reviewing checkpoint commit 6b7dbf4 and current head e704d5b. This page supersedes earlier recommendations; consequential corrections are retained in the [review summary](../../review-summary.md). The SDK Notion page remains the target API; conflicts below are recorded for resolution, not silently resolved in favor of code. + +## Pinned sources + +| Repository | Current inspected branch and commit | +| --- | --- | +| AGW | `pushAgenticWallet_v3@e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9` | +| Core | `universalMarketplace_v1@cb69e0ba101bef1bb4440e54b2c45396be3e92ce` | +| Gateway | Eight-field `pc20-3rd-iteration@bcbf7df42e8e6dd11088a43bcc0b056a54ea0a18`; six-field older `main@d02070d` | +| SDK | `167fdc6243ecfe5d97735a6124662c7d2084d126` | +| Notion | October 03, 2026 at 13:23 IST full export; page 1 and page 5 changed, 10 pages unchanged | + +AGW remote branches were checked through GitHub API on October 3: nomenclature-changes was deleted after merging and pushAgenticWallet_v3 points to e704d5b. Core remains pinned at cb69e0b from the existing evidence; no fresh core fetch was performed in this pass. The head adapter keeps the SmartSession source unchanged. It replaces cryptographic session-key validation with a sender-checking adapter. The wallet binds the sender before calling the engine and constructs `USE || rulesId || msg.sender` itself. Engine account binding and disabled alternate paths are essential invariants. **No engine fork is recommended.** + +## Compatibility status + +| Surface | Current status | Remaining work | +| --- | --- | --- | +| `executeAsAgent`, `agentOf`, authorization event | Implemented in AGW source | Verify selected new deployment and preserve adapter invariants; G02 source dependency satisfied | +| Agent config | Exact `abi.encode(address agent)` | SDK codec and generation-specific validator context | +| Rule ID | `keccak256(abi.encode(validator, abi.encode(agent), bytes32(grantNonce)))` | Page 5 helper signature/constants need alignment. Chain is not hashed; key records by wallet plus rule ID | +| Owner batching | Documented design; local tests support atomic replacement | SDK implementation and final-generation regression tests; no need to ask whether batching is intended | +| Agent arrays | Wallet dispatch remains single/default. EVM destination multicall supports 1–10 calls | Define native arrays separately; supporting multiple native actions in a rule is a public type choice, not the same as atomic multi-call dispatch | +| Duplicate agent-chain rules | Accepted by contract with independent IDs/budgets | SDK preflight rejection and explicit ambiguity error are proposed; hard on-chain uniqueness is not assumed necessary | +| Checkpoints | Implemented in source at 6b7dbf4, included in e704d5b; count and last-block views plus Checkpointed event | Compare snapshot counts, account for per-call and lifecycle ticks, and verify selected new deployment | +| Grant job ref, labels, envelope version | Still absent | Agree next-generation surface and spec consequences | +| Historical rules | Revoke removes agent config and enabled actions, while URP terms persist | Event agent attribution or nested-call reconstruction needed if revoked rules are returned | +| expectedCEA | Required universal wire term, derived from AGW plus destination context and committed at grant | SDK must derive it, show it in previews, include it in encodeRules context, and monitor derivation drift | +| Binder | Never present in reviewed code; live Notion page checked October 3 says dropped for v1 | No binder/setBinder implementation required unless a new explicit product decision reverses this | +| Funding approval | Push gateway requires allowance for PRC20 pulls | Existing owner execute mechanism validated in four local fixture tests; implement setup/replenishment and verify production pull/burn/settlement | +| Destination approvals | Page 5 example permits an unpinned spender; current marketplace rejects approve/increaseAllowance | Product policy and owner-controlled approvals; selector filtering alone is not a general guarantee against malicious/custom approval methods | +| Gateway shape | Eight fields in current branch and observed live dispatcher; main's six fields are older | Ask only whether a future removal is actually planned | +| Agent outbound composer | Existing Route 2 request cannot be used unchanged | Empty recipient, AGW revert recipient, nonzero maxPCForGas, policy-compatible multicall and AGW PC accounting | +| Outbound tracking | Existing tracker uses tx hash/events/UTX ID | Reuse provisionally; verify live wrapped outbound. Response `from` and progress route integration still need adaptation | +| Marketplace expiry | Core terms require exact equality with job expiry | Reconcile Notion's <= and >= statements; equality applies to this marketplace compile path, not every standalone AGW rule | +| SVM destination | Source and policy tests available | Typed SDK representation, obligations 19–23, deployment capability; do not claim an agreed deferral | +| Generation detection | Wallet clones immutable; factory implementation frozen by intended design | New generation/address context, supported factory registry, version identification and migration disclosures | + +## Chain observations + +Historical read-only probes on October 2 at Donut block **23818643** confirmed the documented factory still points to `0xD7FEF338572f96edBeF89E720f1F0fF1284ec79C`, that implementation reports `push.agentwallet.1.0.0`, and the documented URP reports `1.0.0`. Gateway implementation `0x1e412939780f2b834dc42c7ac58d9f99888da659` contains the eight-field PUSH4 selector and not the six-field selector. See [probe](../../research/donut-probe-2026-10-02.json). + +These observations validate the named historical deployment, not a global claim that nobody has deployed head elsewhere. No matching new-generation deployment manifest is available. A PUSH4 scan supports dispatch identification but is not complete ABI verification. + +## SDK-owned decisions + +Implement existing namespace structure, signer reuse, receipt identity adaptation, typed failure metadata, Web2 compatibility, generation guards and internal read reconstruction in the SDK. Document the chosen list/read-only/reinitialize behavior in an SDK decision record. Product consultation is needed only when that choice changes an explicit public promise or introduces a new public parameter. + +Do not silently change per-send lookup to filter expired rules: page 5 says lookup selects enabled agent/chain rules and leaves policy checks on-chain. Any expiry precheck is a behavior change to document. A JSON-RPC batch is not necessarily one logical read: IDs must be enumerated before their agent/config reads can be constructed. Avoid promising a single round trip without an index or contract view. + +Retries for stale spend must be bounded and must not repeat wallet signatures without user-visible control. Revoking first is an available alternative with different atomicity and permission-interruption semantics, not a transparent retry. + +## Next live acceptance test + +After a compatible deployment and authorized test funding are available, send a positive-amount EVM agent outbound with owner-established gateway allowance, empty recipient, AGW refund recipient and a policy-compliant multicall. Verify real burn, node/TSS handling, destination execution, receipt identity and unchanged hash-based tracking. No such transaction has been broadcast by this review. + +## Checkpoint revision and current source freshness + +The no-persistent-storage invariant was deliberately revised: owner execution may touch the single packed checkpoint slot, while remaining independent of engine/policy health. `check-execute` now pins the B2 checkpoint revision. A grant starts one tick; every owner call ticks before dispatch; each revoked ID ticks once; successful grants tick once. `executeWithSig` has the same per-call behavior. Failed transactions unwind the ticks; agent execution does not tick. + +For assert/revoke/grant inside one owner batch, the delta is five: OWNER_ACTION(assert), OWNER_ACTION(revoke), RULES_REVOKED, OWNER_ACTION(grant), RULES_GRANTED. Checkpoint ref is a call hash or rulesId; it is not the missing job/card ref parameter on grant. + +The new accepted limit 34 states that pre-existing allowances can be pulled without a wallet call/checkpoint. Checkpoints detect owner-door activity, not every possible balance change. The evaluator must define how allowance-driven changes affect its verdict. A baseline count and correct funding-call ordering are required; a sinceBlock filter alone cannot detect all same-block changes. + +Fresh Notion page 1 was inspected on October 3 and still says binder was dropped for v1. The complete export succeeded. All 12 saved page bodies now reflect the October 3 export. Pages 1 and 5 changed; see the refresh report. Binder is recorded as dropped in the source index and review summary. + +## Latest SDK target after successful refresh + +Page 5 is still authoritative: create deploys/grants only, funding is separate, UniversalRule uses assets[] and maxGasPerCall, and AGENTIC-TX-103 is removed. New page 1 section 4c proposes per-token accounting and 0–8 assets. The tested e704d5b ABI does not implement that new wire format; retain its single-asset fixtures as historical baseline, not the future codec. + +Define per-asset Spent and replacement assertion semantics, empty-asset routing, destination-token/native-marker resolution and the proposed bytes32 expectedCEA encoding. The prior universal defaults/maxAmountTotal naming cannot simply carry forward. Proposed AssetCap.maxTotal zero means unlimited; native defaults remain a separate question. + +See [successful refresh report](../../research/notion-refresh-2026-10-03.md). All earlier download failures remain historical evidence; download permission was sufficient for this run. + +The follow-up [external blocker register](../../external-blockers.md) records what still needs team input after SDK-owned closure. Remote refs were rechecked unchanged; the Notion snapshot date above is unchanged. + + +## Deployment coordination October 5 + +Shoaib supplied the fixed deployment-address table and will receive Zaryab’s completion notice. The table exactly matches the [saved AGW address book](../../notion/agw-address-book-donut-2026-09-04.md): factory proxy `0xF1A131571f89fD06890576e6cD0154114ACBBc8b`, wallet implementation `0x959ED7f6943bdd56B3a359BAE0115fef4aa07e17`, UCEP `0x79F07D379BdC26468E48025a61bC955909522c1D`, PushSessionValidator `0x5A59a5Ac94d5190553821307F98e4673BF3c4a1D`, and engine `0x7540f9a59693d51CFB4A3727141eAE4836F96749`. Remaining dependencies/admin addresses are preserved in that source snapshot. + +The deployment question is removed from the team handoff. These are known address inputs, not a newly verified target-generation manifest: the table uses the earlier PushAgentWallet/UCEP/PushSessionValidator naming and sizes. Once Zaryab reports completion, verify factory wiring, deployed wallet/policy ABI, source revision and event start blocks against the intended release. No RPC probe or SDK registry change occurred in this documentation pass. diff --git a/plan/agw/research/deployment-review-2026-10-06/probe.py b/plan/agw/research/deployment-review-2026-10-06/probe.py new file mode 100644 index 00000000..7068561d --- /dev/null +++ b/plan/agw/research/deployment-review-2026-10-06/probe.py @@ -0,0 +1,76 @@ +"""Read-only v4 Donut probe. No signing, funding or transaction submission.""" +import concurrent.futures +import datetime +import hashlib +import json +from pathlib import Path +import subprocess +import urllib.request + +RPC = 'https://evm.donut.rpc.push.org/' +OUT = Path(__file__).parent / 'donut-probe.json' +ADDRESSES = { + 'factory': '0xaF88D0FD947afAe7bBb8F34e8417DCfc165e1aaF', + 'factoryLogic': '0xe138Dc6EfC10233BE1e6c8aF1Caf8cABe599cfC2', + 'walletImplementation': '0x96D69ec7e6cDdaD414e656B5c9DCA24587DF713c', + 'policy': '0x603E7f0aF6e1aAFf46DDfb28b1e99364f8BC59af', + 'policyImplementation': '0xA2391eee4C9EA1B32AEB3A460B77296EA709F02F', + 'proxyAdmin': '0x0b7a31ec85117892aEA90AA5cB6514e2F97c2295', + 'validator': '0x068EE2388475A98EE1f5a434C58bFF3444fffFe6', + 'engine': '0x165A5E6782f39D30B38c7D97e1303e4CB2aD102a', + 'gateway': '0x00000000000000000000000000000000000000C1', + 'core': '0x00000000000000000000000000000000000000C0', + 'executor': '0x14191Ea54B4c176fCf86f51b0FAc7CB1E71Df7d7', +} + +def rpc(method, params): + data = json.dumps({'jsonrpc': '2.0', 'id': 1, 'method': method, 'params': params}).encode() + req = urllib.request.Request(RPC, data=data, headers={'Content-Type': 'application/json'}) + with urllib.request.urlopen(req, timeout=45) as response: + value = json.load(response) + if 'error' in value: + raise RuntimeError(value['error']) + return value['result'] + +chain = int(rpc('eth_chainId', []), 16) +assert chain == 42101, chain +block = rpc('eth_blockNumber', []) +header = rpc('eth_getBlockByNumber', [block, False]) + +def code(entry): + name, address = entry + raw = rpc('eth_getCode', [address, block]) + value = bytes.fromhex(raw[2:]) + return name, {'address': address, 'bytes': len(value), 'sha256': hashlib.sha256(value).hexdigest()} + +impl_slot = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc' +admin_slot = '0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103' +slots = {} +for name in ['factory', 'policy', 'gateway']: + slots[name] = {'implementation': rpc('eth_getStorageAt', [ADDRESSES[name], impl_slot, block])} +slots['policy']['admin'] = rpc('eth_getStorageAt', [ADDRESSES['policy'], admin_slot, block]) + +calls = [('factory', 'walletImplementation()(address)'), ('factory', 'paused()(bool)'), + ('policy', 'version()(string)'), ('policy', 'pushChainHash()(bytes32)'), + ('policy', 'UNIVERSAL_GATEWAY_PC()(address)'), ('policy', 'UNIVERSAL_EXECUTOR_MODULE()(address)'), + ('walletImplementation', 'accountId()(string)')] +calls.extend(('walletImplementation', f'{name}()(address)') for name in + ['SESSION_ENGINE', 'RULES_POLICY', 'SESSION_VALIDATOR', 'UNIVERSAL_GATEWAY_PC']) + +def call(entry): + name, signature = entry + result = subprocess.run(['cast', 'call', ADDRESSES[name], signature, '--rpc-url', RPC, + '--block', str(int(block, 16))], capture_output=True, text=True, timeout=60) + return {'contract': name, 'signature': signature, 'exit_code': result.returncode, + 'output': result.stdout.strip(), 'error': result.stderr.strip()} + +with concurrent.futures.ThreadPoolExecutor(max_workers=4) as pool: + codes = dict(pool.map(code, ADDRESSES.items())) + reads = list(pool.map(call, calls)) +result = {'checked_at': datetime.datetime.now(datetime.timezone.utc).isoformat(), 'rpc': RPC, + 'chain_id': chain, 'block': int(block, 16), 'block_hash': header['hash'], + 'block_timestamp': int(header['timestamp'], 16), 'code': codes, 'slots': slots, 'reads': reads, + 'limits': 'Code sizes, proxy slots and selected views only; no complete bytecode/source equivalence or transaction execution proof.'} +OUT.write_text(json.dumps(result, indent=2) + '\n') +print(json.dumps({'chain': chain, 'block': result['block'], 'code_sizes': {k: v['bytes'] for k, v in codes.items()}, + 'reads': reads, 'slots': slots, 'saved': str(OUT)}, indent=2)) diff --git a/plan/agw/research/deployment-review-2026-10-06/source-manifest.json b/plan/agw/research/deployment-review-2026-10-06/source-manifest.json new file mode 100644 index 00000000..b340741b --- /dev/null +++ b/plan/agw/research/deployment-review-2026-10-06/source-manifest.json @@ -0,0 +1,89 @@ +{ + "fetched_at": "2026-10-05T18:32:09.520781+00:00", + "repo": "https://github.com/pushchain/push-agentic-wallets", + "branch": "deploy-agw", + "documentation_head": "10a24f101e2e6e0a9b76517b29f5cdb1aa967796", + "deployment_reported_source": "e8db74815cfbbf5389593805e464fe8d85f7f735", + "files": [ + { + "path": "CLAUDE.md", + "sha256": "56d65e9f11394d0ee94080e8a01117d92e586044b2d0d8da9e272d5fcb0fc650", + "bytes": 25637 + }, + { + "path": "docs/1_AGW.md", + "sha256": "6b111652c2ce78b3e227b0838fc3ed2f32b6f0f7eb10146f2352730e327abe45", + "bytes": 103201 + }, + { + "path": "docs/2_UniversalRulesPolicy.md", + "sha256": "3a5d943dda72396b46d38ef72ea6b7c456368bfd8fee11334675457d4dc42b1b", + "bytes": 58915 + }, + { + "path": "docs/5_SDK_Owner_Integration.md", + "sha256": "a77c3cdc4dbbb791ed1c9df6bdaa9e01b85f221fb7173bfa7e73f89f9eeb4175", + "bytes": 28355 + }, + { + "path": "docs/addresses/donut.md", + "sha256": "aaab188fbc2bf52afc4aaf2f99ec02c99a34dd5ba006e1f55f7c922f85c6ad3c", + "bytes": 8178 + }, + { + "path": "foundry.toml", + "sha256": "172ef5d44d9cc6740f18d6ef25d6f3e62cfdc129d1bd45ddcecec24dbd698765", + "bytes": 3892 + }, + { + "path": "src/AGW.sol", + "sha256": "9d3fa4c96e7ed0fa74e155aa11c96ffaa0d80fe9a45683ba433a8ba49d30e821", + "bytes": 60814 + }, + { + "path": "src/AGWFactory.sol", + "sha256": "49f950e247923c71bd0abcfedc02d9b7f21d340b76454173293aa33763793e50", + "bytes": 17740 + }, + { + "path": "src/interfaces/IAGW.sol", + "sha256": "72ba3f081c5ad454fdee29aa313216f47d3a1759afccde0ad2360e3af03cf1bb", + "bytes": 11608 + }, + { + "path": "src/interfaces/IUniversalRulesPolicy.sol", + "sha256": "6443532c02ff15008faaf9cb8ba59d372d30baee2a3f3c1e82ced3124c95d310", + "bytes": 6978 + }, + { + "path": "src/libraries/AgentConfigLib.sol", + "sha256": "e2bb3478da66a3b510da7a27eb48e35ca8c4bb74b5d0cb844d3b8e99a15b2e20", + "bytes": 1866 + }, + { + "path": "src/libraries/Errors.sol", + "sha256": "e664a8a4496b1ebe2ad4def28ff914e8ea034bd366b3d26cf6a9e5e76ba46d66", + "bytes": 24953 + }, + { + "path": "src/libraries/Types.sol", + "sha256": "37ff942bd22e03e3868282381a030423773f16988f4463433e8068cf04ccb552", + "bytes": 27486 + }, + { + "path": "src/policies/UniversalRulesPolicy.sol", + "sha256": "0cb721d5ea77bbd8402b4909df7a21672c44abd3ca814c1cb139330c3d557e52", + "bytes": 97043 + }, + { + "path": "src/validators/AgentValidator.sol", + "sha256": "d0ada31e5cb516823421115f5568f9457d4edb6def64526784864761751c7964", + "bytes": 4941 + }, + { + "path": "test/unit/28_multiAsset.t.sol", + "sha256": "be653d4dc115b9d85d34223957e8b8fe3bdac0d5ea63da1cd51c574fcaacfea5", + "bytes": 27595 + } + ] +} diff --git a/plan/agw/research/deployment-review-2026-10-06/source/CLAUDE.md b/plan/agw/research/deployment-review-2026-10-06/source/CLAUDE.md new file mode 100644 index 00000000..e4471d40 --- /dev/null +++ b/plan/agw/research/deployment-review-2026-10-06/source/CLAUDE.md @@ -0,0 +1,330 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +**`docs-internal/v3-architecture-docs/README.md` is the single entry point for design intent.** Read it, and +the reading plan it sets out, before writing any code. This file is conventions, commands and orientation; +it does not restate the architecture. + +**Precedence, highest first:** `docs-internal/v3-architecture-docs/CORE_RULES_v3.md` → +`docs/1_AGW.md` and `docs/2_UniversalRulesPolicy.md` → `docs-internal/v3-architecture-docs/v3-decision-register.md` → +the five PRDs in `v3-prds/` → the worked examples in `docs/` +(`3_Universal_Flow.md` cross-chain, `4_Native_Flow.md` Push-side). +Everything else in the repository is history. **The PRD is the specification; the existing code is not.** + +**The narrative docs live in `docs/`, not `docs-internal/`** — `1_AGW.md` (the system), `2_UniversalRulesPolicy.md` +(the rules policy, split out of the system doc) and the two flow walkthroughs; addresses per network live in +`docs/addresses/`. `docs-internal/` holds the build specifications, the decision register and the PRDs. + +## Commands + +``` +make build # forge build +make test # check-execute, then forge test -vv +make sizes # the S-06 size gate — forge build --sizes, exits non-zero over 24,576 B +make check-execute # sha256 pin: execute() byte-identical to its reviewed text (the B2 checkpoint revision) +make snapshot-execute # WARNING only — owner-door test gas vs .gas-snapshot-execute (±1000 gas) +make e2e # PARKED: prints that the Marketplace E2E awaits its rewrite, exits 1 +forge fmt # line_length 120, tab_width 4 +``` + +**`execute()` is hash-pinned.** `script/check-execute.sh` hashes the source span of +`AGW.execute` (pinned at the B2 checkpoint revision) — not a byte, not a comment may change. +Owner-authority features go in *sibling* doors (`executeWithSig`, `grantRulesWithSig`), never in +`execute`; the per-call checkpoint is the one addition `execute` carries, and it consults nothing and +cannot revert. + +**The Marketplace E2E deploys the core repo's own artifacts** via `vm.deployCode` (core is +shanghai / 99,999 runs / OZ 5.3; this repo does not recompile it). Run `make e2e` — `test_E2E_13` fails on +a stale core artifact. **That suite is currently PARKED** as `test/integration/24_marketplaceE2E.t.sol.parked` (not compiled): the core +marketplace is migrating to a new surface that also needs D3's agent config, so the suite awaits a rewrite; `make e2e` +says so and exits. `lib/push-chain-core-contracts` is currently a **symlink** to the sibling checkout +(`../../push-chain-core-contracts`), which is why `foundry.toml` carries a temporary `allow_paths`. + +**The demos (`demo/`, `demo-native/`) are frozen against the deployed v1 contracts** and do not compile against +the renamed `src/`; they are listed in `.gitignore` and must not be edited. The two demos have their own Foundry +profiles so `forge test` runs only the v3 specification suite: +`FOUNDRY_PROFILE=demo forge test`, `FOUNDRY_PROFILE=demo-native forge test` (each wrapped by its `justfile`; +see `demo/README.md`, `demo-native/README.md`). + +`make sizes` runs `--sizes` twice — once for the build, once for the vendored engine explicitly. That is +deliberate: **which contracts the default table covers is forge-version-dependent** (1.5.1-stable includes +`lib/`; 1.6.0-nightly did not), and SmartSession has the smallest margin in the build. The gate must not +rest on a reporting default that has already changed once. + +Narrower runs: + +``` +forge test --match-path test/unit/5_universalRulebook.t.sol -vv +forge test --match-test test_U09_ -vvv # one test, full traces +forge test --match-contract URPTest # test contract names predate the rename and are kept +forge coverage --ir-minimum # via_ir is on; plain coverage will not compile +forge test --gas-report +``` + +One suite is env-gated and **skips silently when the variable is unset** — a skipped test is not a passing +test, so run it at least once against a real endpoint before reporting a phase done: + +- `DEPLOYMENT_RPC` + `CHAIN_ID` — gate S-05, which checks `deployments/.json` against a live chain. + +Deployment (all five contracts, dependency order, writes `deployments/.json`): + +``` +forge script script/Deploy.s.sol:Deploy --rpc-url $RPC --broadcast +``` + +Requires `UNIVERSAL_GATEWAY_PC`, `UNIVERSAL_EXECUTOR_MODULE`, `CHAIN_ID`, and `FACTORY_ADMIN` off local +chains. See `.env.example`. The script asks the chain for its id and reverts on a mismatch with `CHAIN_ID`. + +## The system in one pass + +A user funds a small, purpose-built wallet on Push Chain and grants it a **rules set**: a frozen bundle of +limits (which agent, which token, which destination protocol and functions, how much per call, how much +total, until when). The wallet's balance is the hard ceiling on everything the agent can lose. Every agent +action is checked by contracts at execution time; the agent's honesty is never assumed. + +**The one hard problem.** Push Chain reaches other chains through a single frozen gateway function, so every +agent action — a trade, a deposit, a theft — is the *same* Push-side call: the wallet calling +`sendUniversalTxOutbound`. To the permission engine they are indistinguishable. Everything the user cares +about lives inside the payload, two decode levels down. **URP is the contract that opens that payload.** + +### Five contracts + +| Contract | Role | +|---|---| +| `AGWFactory` (`src/`) | UUPS proxy. Deploys wallet clones at pre-computable addresses; the registry of record for "is this a real wallet, and who owns it?" There is no owner parameter: the owner is the caller, or the signer of an `OwnerIntent` (the `deployWalletWithSig(intent, sig, label)` form). | +| `AGW` (`src/`) | Holds funds. Minimal clone with 40 bytes of immutable args (owner 0–19, factory 20–39). Push Chain has no ERC-4337 EntryPoint, so the wallet does the EntryPoint's jobs itself. | +| `UniversalRulesPolicy` — URP (`src/policies/`) | The only novel contract and the security boundary. **Three rulebooks**, in normative order, fail closed: universal-EVM (gates 1–16), universal-SVM (S1–S18; S1–S10 restate gates 1–10, S11+ parse the Solana execute payload), and native/Push-side (nine gates). Which one runs is derived from the rules set's chain string, never from a flag anyone sets. Upgradeable behind a transparent proxy. | +| `AgentValidator` (`src/validators/`) | Stateless sender validator: the rules set's config is the agent's Push address; it confirms the sender the wallet wrote into the engine's signature field. Verifies no signature. | +| `SmartSession` (`lib/smartsessions/`) | Adopted unmodified. Stores rules sets, runs policies, deletes on revoke. The wallet's only installed module. | + +### Naming + +AGW follows the core/gateway naming standard (`docs-internal/sdk-first-changes/N-nomenclature_prd.md`): + +- **"Rules", one word everywhere** — `grantRules`, `revokeRules`, `revokeAllRules`, `rulesId`, `RulesGranted`, + `RulesRevoked`, `RulesActionAuthorized`, `RulesConfigured`, `RulesType`. `rulesId` is the engine's + `permissionId` (`rulesId == permissionId`). "Mandate" is retired from code and docs. +- **Rename boundary:** ERC-7579 names (`execute`, `ModeCode`, module functions) and SmartSession names + (`Session`, `PermissionId`, `PolicyData`, `ActionData`, `ConfigId`, `checkAction`, + `initializeWithMultiplexer`, …) never change. Test function and test contract names never change. +- **Errors** live in `src/libraries/Errors.sol` — `AGWErrors`, `AGWFactoryErrors`, `UniversalRulesPolicyErrors`, + `AgentValidatorErrors`; caller checks are `CallerIsNotX`. **Types** live in `src/libraries/Types.sol`. +- **Set-once wiring** is read through `UPPER_CASE()` getters: `SESSION_ENGINE()`, `RULES_POLICY()`, + `SESSION_VALIDATOR()`, `UNIVERSAL_GATEWAY_PC()`. The deployment JSON keys keep their old names for tooling. +- **Interfaces** use numbered banners (`AGW_1: EVENTS` … `AGW_5: VIEWS`, `URP_1`–`URP_3`, `AGWF_1`–`AGWF_3`); + `IAGW` declares the wallet's full external surface and `AGW is IAGW`. +- "URP" stays as the short form in comments and messages; test files are numbered by area (`test/unit/1_factory…`). + +### Load-bearing invariants (each has a permanent test) + +- **The two doors are the whole authority model.** `execute` (owner door) consults *exactly two things* — + the immutable-args owner and calldata — and its only side effect besides the calls is one checkpoint + write per call to the wallet's own slot 0, which cannot revert. No module, policy, engine state or flag + may ever be read there; it must succeed with the engine uninstalled, a hostile validator installed, or + ghost-rules state. Adding any check is the catastrophic regression. `executeAsAgent` (agent door) is + callable only by the rules set's agent: the wallet checks `msg.sender == agentOf(rulesId)` and writes the + sender into the engine's signature field, which the sender validator checks. The agent is a Push + address — an EOA, or the UEA of an external key; the wallet verifies no signature, and replay is the + sender's own nonce. +- **Checkpoints never tick from the agent door.** `_checkpoint` is called only from the two owner doors + (once per call, before the call), `_grantRules`, `revokeRules` and `revokeAllRules` — never from + `_execute`, which both doors share. Kinds are a frozen, append-only wire format. +- **Owner-intent doors are siblings, not extensions, of `execute`.** `executeWithSig` and + `grantRulesWithSig` let a relayer (`intent.executor`) present an EIP-712 `OwnerIntent` signed by the + owner — usually a UEA, which has no ERC-1271, so `OwnerAuthLib.isOwnerSig` tries + `verifyUniversalPayloadSignature` first, then ERC-1271, via raw staticcalls that never revert. The domain + is the **factory's**, shared by factory and wallets. These doors read storage (nonce lanes; the owner lane + requires `OWNER_LANE_FLAG`), which is exactly why they cannot live in `execute`; `executeWithSig` + duplicates `execute`'s mode switch deliberately rather than sharing it. +- **`execute(bytes32,bytes)` is a frozen signature.** The engine branches on this selector; any other shape + routes validation to a path where URP's value gate sees a hardcoded zero instead of the real value. +- **`grantRules` enforces the canonical session shape and nothing else** — the skeleton, not the organs. + Term validation is URP's own init guards. Its monotonic `_grantNonce` becomes the session salt, so every + grant yields a distinct permission id that never recurs. + **One exception, bounded:** the wallet decodes the policy envelope's `chain` string from each action's + `initData` — *after* the policy-shape check has proven the policy is URP — solely to derive the + rules set's mode and assert targets against it. It validates nothing else in the envelope; URP re-derives + the same value from the same bytes and remains the sole judge of the terms. + **The order is load-bearing and is pinned by two tests: count → shape → decode → derive.** Decoding + before the shape check would read an arbitrary policy's data as though URP had authored it, and reading + action 0 before the count check would index an empty array. The per-action shape check inside the native + loop matters as much as the one before it — a rules set whose *third* action names a foreign policy would + otherwise be granted with no URP gate on that action at all. +- **`revokeRules` / `revokeAllRules` must have nothing on them that can fail.** No guard, no probe, no extra + external call. Blockable revocation is the one regression these functions can develop. +- **URP's `checkAction` makes no external calls.** It runs *before* the session validator is consulted, and + must remain safe on arbitrary calldata (the wallet's own agent check precedes the engine, but URP does not + rely on it); its safety rests on having no external calls, all effects last, and reverting on every + failure. Do not wrap its `abi.decode` in `try/catch` to name an + error — that introduces the external call the argument forbids. +- **Gate 12 (payload must be a multicall) is not a format check.** It confines the agent to the one CEA + branch whose entries gates 13–16 can walk; the other branches bypass the allow-list, beneficiary pin and + value cap entirely. +- **Gate 16's per-entry cap is in destination-chain native units** and is never compared against the + Push-side `value` (gate 8). Conflating them is a real bug this design once carried. +- **A universal rules set lists 1..`MAX_ASSETS` tokens, and gate 5 checks the request's token on every + request, zero amount included** (multi-asset branch). The gateway routes by the token, so the token is + what pins the destination chain: every listed token is chain-checked at grant, an empty list is refused, + and a zero-amount request naming an unlisted token is refused. Each token has its own caps and its own + `spent`; "unlimited" is `type(uint256).max`, never 0. See `docs/multi-asset-review.md`. +- **The factory's derivation is frozen forever.** `_walletImplementation` is the append-only storage anchor + with no setter; the salt formula and the 40-byte immutable-args encoding may never change, because + counterfactual funding is a supported flow with no recovery path. + +### Where the layers meet + +- `SEND_OUTBOUND_SELECTOR` and `MULTICALL_SELECTOR` are declared **once**, in + `src/libraries/Types.sol`, beside the struct mirrors they derive from. The wallet's grant-shape + check and URP's request gate both read from there so they cannot disagree. `Types.sol` is the + authoritative mirror of the gateway's frozen structs — reordering a field silently breaks the selector. +- URP's config is keyed `configId => multiplexer => account`. `ConfigId` already binds account and + permission (see the derivation chain in URP's storage comment — note it mixes `abi.encode` and + `abi.encodePacked` across levels; an SDK that assumes one throughout derives every id wrong). The middle + level isolates *callers*: `msg.sender` on the two engine-driven entry points, the `SESSION_ENGINE` + immutable everywhere else. +- The engine truncates policy revert data to 32 bytes and rewraps it as `PolicyCheckReverted(bytes32)`. Use + `BaseTest.expectUrpGate(...)` so negative tests name *which* gate fired; never hand-encode this. + **This applies to `checkAction` only.** `initializeWithMultiplexer` is a plain call from `ConfigLib`, so + init reverts bubble with full data — assert `ChainMismatch`, `InvalidAsset` and `EmptyChain` with every + argument, never through `expectUrpGate`. +- **Which rulebook a rules set uses is DERIVED, by both contracts, from one string.** Each action's URP + `initData` is `abi.encode(uint16 version, string chainNamespace, bytes body)` — the same shape in every mode, + which is what lets the chain be read before the mode is known. URP reads the version from the first word + before decoding anything else and refuses anything but `ENVELOPE_VERSION` (`UnsupportedEnvelopeVersion`); + the wallet decodes the same three fields but judges only the chain. The wallet hashes it and the engine hands URP the + identical bytes, so both call `PushChainLib.deriveMode` and reach the same answer with nothing between + them that can drift. There is no mode byte, no `RulesType` argument and no `PUSH_CHAIN_HASH` constant: + `PushChainLib` computes this chain's identity from `block.chainid`, so there is nothing to configure and + therefore nothing to configure wrongly. A near-miss string (`"EIP155:42101"`) derives the *other* mode + and is refused against the action targets — the hash comparison is the whole rule, and the wallet + deliberately does not parse, normalise or length-check the string. + **For a UNIVERSAL rules set URP derives a second thing, the VM family:** `PushChainLib.deriveVm` reads the + 7-byte prefix (`eip155:` → EVM, `solana:` → SVM, anything else reverts `UnsupportedNamespace` at init). + The result is stored on `ModeSlot.vm` and routes `checkAction` to `_checkUniversal` or `_checkSvm`. Mode + still comes from the full hash; `deriveVm` is never asked about a native string. +- **Tests must pin `block.chainid`.** Foundry defaults to 31337, so the native chain string is + `eip155:31337` unless a test calls `vm.chainId(42101)`. Native helpers build the string from + `block.chainid`, never a literal. +- **`Config`, `SvmConfig` and `NativeConfig` are STORAGE types; `UniversalTerms`, `SvmTerms` and + `NativeTerms` are the wire types.** URP storage is append-only — `_svm` took slot 7 and one `__gap` slot. + The SDK encodes the latter. `Config` stores no chain — a rules set's chain lives on `ModeSlot.chainHash`, + where it has been checked against every listed asset. + `test_upgradeable_configStructLayoutIsFrozen` pins every member's label, slot, offset and type, because a + struct inside a mapping never appears in the contract-level layout and can otherwise be reordered + silently. + +## Standing build rules + +1. **One phase at a time.** Stop at the gate, report, wait for acknowledgement before proceeding. +2. **One contract per phase, its tests in the same phase.** No contract ships without its suite. +3. **The PRDs are locked.** A PRD error is *reported with evidence and waited on* — never fixed in place, + never coded around. Never "fix" anything on a PRD's DO NOT FIX list; raise it instead. +4. **`src/libraries/` and `src/interfaces/` may change only via a diff proposed at the start of the phase + that needs it.** Never edited opportunistically. +5. **Branch `pushAgenticWallet_v3`.** All build work lives there. **Zaryab alone commits and pushes** — + prepare the change, report what is ready, print the commands; never run `git commit` or `git push`. + Never commit `deployments/*.json`, `out/`, `cache/`, or `.env`. +6. **Never invent addresses, selectors or magic values.** Several are deploy-time inputs and marked as such. +7. **Say what you did not do.** Skipped, unverified or uncertain work is stated plainly, not presented as + complete. +8. **Gate report format:** what was built · what was verified and how · what deviated and why · what you are + unsure of · `forge test` and `forge build --sizes` output verbatim · the exact `forge --version` line. + +## Standing test rules + +1. **Every negative test names its expected error.** Two documented exceptions only: URP gate 4 case (d) + (correct-length, malformed-offset body), which asserts "reverts" because it fails at an un-named + `abi.decode` step, and the **malformed-envelope rejection test**. + + **The envelope exception, restated for `abi.encode(uint16 version, string chainNamespace, bytes body)`.** + URP reads the version from the **first word** before decoding anything else, so on an **uninitialised** + config almost every malformed or pre-version blob is refused **named** as + `UnsupportedEnvelopeVersion(firstWord)`: a two-field `(string, bytes)` envelope reports 64, a bare struct + 32, a `(uint8, …)` header its leading byte. What stays **unnamed** at URP: blobs shorter than one word, a + version-1 envelope whose body is the wrong `Terms` type for the derived mode (**owner-door-direct path + only**), and an asset that *answers* `SOURCE_CHAIN_NAMESPACE()` with a non-string. **Through the wallet** + the wallet decodes the envelope first and does not judge the version: an unsupported version reaches the + owner named from URP, but a pre-version two-field envelope panics in the wallet's decode (`0x41`) before + URP is reached — assert that panic, not a bare revert. On an **already-initialised** config every shape + reverts `AlreadyInitialized` first, because the re-init guard precedes the decode. The property the tests + assert is that each **reverts rather than mis-decoding**. + + **A bare `vm.expectRevert()` is permitted only where the revert genuinely carries no data, and + only with an in-line justification saying so.** Before writing one, **grep the repo for the same + assertion elsewhere** — twice now a bare form was written where the named form already existed in + the same file (`test_W29_Native`, Block A §2.2; the native revoke in `8_e2e.t.sol`, Block B §2.1). + A bare `expectRevert` on a revocation or authorisation claim passes on an out-of-gas, a signature + failure or a nonce collision — the weakest assertion in the suite sitting on the strongest claim. +2. **A mock may be the OBSERVER, never the ORACLE.** A mock that supplies the behaviour under test can make + a dead branch look live. That is how this repo's one shipped critical bug survived review: the Ed25519 + branch called the precompile through a typed interface, solc inserted an `extcodesize` check, precompiles + have no code — so the branch reverted on the real chain while every test passed, because the tests etched + bytecode at the precompile address. Whenever you etch or stub something, ask what the code would do + against the real thing. +3. **Gas assertions carry a number.** "Within a sane budget" is not assertable; a test that cannot fail is + worse than no test. +4. **Nothing marked ⚠️ NEVER-DELETE is deleted or weakened.** Test names are specification: keep the names + given, add tests freely, rename nothing. +5. **Prefer artifact assertions over `vm.load` for structural claims.** Solidity offers no runtime way to + prove "declares no storage"; `assertEmptyStorageLayout` and `assertSelectorSet` in `test/Base.t.sol` read + solc's own output instead. Use those helpers — do not write second copies. + +## Test harness + +Every suite extends `BaseTest` (`test/Base.t.sol`), which deploys the real engine, validator, URP, wallet +implementation and an ERC-1967 factory proxy, then hands out wallets via `newWallet(owner)` — the real +`deployWallet` path, not a simulated factory. It also carries the canonical session builder, the outbound +request builder, the gate-naming helper, the agent-config helper and the call recorder. Test ids (`T-`, `W-`, +`U-`, `P-`, `S-`) come from the PRDs and appear in test names and comments. + +## Toolchain pins (facts, not preferences) + +- `solc 0.8.26` · `optimizer_runs = 833` · `evm_version = "cancun"` · `via_ir = true` +- OpenZeppelin 5.7.0 · forge-std 1.16.2 · SmartSession fork `7dc20e4` +- **forge: use STABLE, never nightly** (`foundryup -i stable`). Runtime bytecode is a function of + solc + optimizer + via_ir + evm_version + metadata — all pinned in `foundry.toml` — so the forge binary + does not change the sizes S-06 gates on. It does change how `--sizes` reports, how remappings resolve, and + how `forge script` broadcasts, which is where a nightly actually bites. `foundry.toml` has no key for the + driver version: **record the exact `forge --version` in every gate report.** That is the reproducibility + mechanism — do not invent a config key for it. + + **Recorded at Gate 0 and still current:** `forge 1.5.1-stable` + (`b0a9dd9ceda36f63e2326ce530c10e6916f4b8a2`, 2025-12-22). SmartSession runtime 22,581 B / +1,995 margin — + byte-identical to the figure measured on 1.6.0-nightly, which is the evidence that the driver does not + move bytecode. + +**`optimizer_runs` and `evm_version` are load-bearing.** The vendored engine exceeds EIP-170 above ~833 runs +and becomes undeployable; `cancun` is required for `MCOPY` in URP's `_slice` helper. A local `anvil` deploy +will not catch the size problem — anvil does not enforce EIP-170. + +`fs_permissions` grants read access to `out/` and write access to `deployments/`. Both are required, not +conveniences: the artifact-based storage-layout and selector-set assertions depend on the former. + +## Layout + +| Path | Contents | +|---|---| +| `src/` (root) | `AGW.sol`, `AGWFactory.sol` | +| `src/policies/` | `UniversalRulesPolicy.sol` (URP) | +| `src/validators/` | `AgentValidator.sol` | +| `src/interfaces/` | `IUniversalRulesPolicy`, `IAgentValidator`, `IAGWFactory`, `IAGW`, `IAGWInit`, `ISmartSessionConfigReader` (the one engine view upstream omits), gateway + module interfaces | +| `src/libraries/` | `Types.sol` (the policy's terms/config types, `RulesType`, `VmFamily`, `OwnerIntent` + EIP-712 typehashes, and the temporary gateway/core mirrors), `Errors.sol` (one error library per contract), `PushChainLib` (mode/VM derivation), `OwnerAuthLib` (owner-signature check shared by factory and wallet), `AgentConfigLib` (the one decoder of the agent config, shared by validator and wallet), `ModeLib`, `ExecutionLib` | +| `test/Base.t.sol` | Shared harness — every suite extends `BaseTest` | +| `test/unit/`, `test/integration/`, `test/mocks/` | Suites numbered by area (`1_factory` … `27_naming`), end-to-end flows, observers | +| `script/check-execute.sh`, `script/snapshot-execute.sh` | The `execute()` source pin and its advisory gas check | +| `demo/`, `demo-native/` | Cross-chain and Push-native demos — **frozen** against the deployed v1 contracts; own `justfile`, Foundry profile and `state/` ledger | +| `script/Deploy.s.sol` | The five-contract deployment, in dependency order | +| `deployments/` | `.json` records — **never committed** | +| `_to_delete/` | v1/v2 code staged for deletion — **ignore entirely** | + +## Build order (all phases complete) + +| Phase | Deliverable | +|---|---| +| 0 | Baseline: build green, harness, size gate | +| 1 | `URP` | +| 2 | `AgentValidator` — `validateConfig` addition + full suite | +| 3 | `AGW` | +| 4 | `AGWFactory` | +| 5 | Integration + deploy script | diff --git a/plan/agw/research/deployment-review-2026-10-06/source/docs/1_AGW.md b/plan/agw/research/deployment-review-2026-10-06/source/docs/1_AGW.md new file mode 100644 index 00000000..a77beaac --- /dev/null +++ b/plan/agw/research/deployment-review-2026-10-06/source/docs/1_AGW.md @@ -0,0 +1,570 @@ +# AGW (Agentic Wallet) — v3 Architecture + +# 1 · What this is +## The problem +- A user wants to let an automated agent trade or move funds for them, with the user's money — on another blockchain, or on Push Chain itself — without handing over their account. +- The user needs three things at once: +\t- The agent can act **without asking the user each time**. +\t- The agent can never spend **more than the user allowed**, on anything the user did not allow, for longer than the user allowed. +\t- The user can **shut it off instantly**, and take their money out at any time, no matter what state anything else is in. +- All of this runs on Push Chain, which reaches other blockchains through its own cross-chain gateway. Push Chain has no shared "transaction entry point" contract of the kind other chains use for smart accounts — so our wallet must do that job itself. +## The shape of the answer +- The user gets a **dedicated agent wallet** — a small, cheap contract created just for one purpose. It is not the user's main account. It only ever holds the money the user chooses to put at risk. +- The user grants the wallet a **permission**: a fixed bundle of limits binding one agent. A permission is one of **two kinds**, and the user never states which: they name the **chain** the permission is for, and the kind follows from it — Push Chain itself means native, anywhere else means universal. It is fixed at grant and never changes. A **universal** permission bounds cross-chain actions: which token, which destination protocol and functions, how much per action, how much in total, and until when. The far chain may be an EVM chain or Solana; the chain's namespace decides which, and with it the format in which the far-chain action is written and checked. A **native** permission bounds actions on Push Chain itself: which Push contracts and functions, which arguments are pinned to which values, how much native value, how many calls, and until when. +- Every action the agent takes is checked against that permission **by contracts, at execution time**. The agent's honesty is never assumed and never needed. +- The single most important contract in the system is **URP — the Universal Rules Policy**. It carries three rulebooks: two for universal permissions — one for EVM destination chains, one for Solana, because the far-chain action inside the call is written in that chain's own format — and one for native permissions. For a universal permission, every agent action, whatever it claims to be, is one and the same kind of call on Push Chain — the wallet calling the cross-chain gateway — and only URP looks inside that call to check what the agent is *really* doing on the far chain. For a native permission the target and function are already visible to the engine, and URP checks the three things the engine cannot see: the arguments, the value, and the count. `2_UniversalRulesPolicy.md` is devoted to it. +## What we build, and what we adopt +| Piece | Build or adopt | What it is | +| -------------------------------------------- | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Wallet factory** (AGWFactory) | Build | Creates agent wallets at predictable addresses | +| **Agent wallet** (AGW) | Build | The account itself: holds funds, admits only the permission's agent, executes | +| **URP** | **Build — the only genuinely novel contract** | The policy that inspects and limits every agent action — cross-chain through its universal rulebooks (EVM chains, Solana), Push-native through its native rulebook | +| **Session validator** (AgentValidator) | Carry forward — stateless sender validator | Confirms the caller the wallet names is the permission's agent. Verifies no signature | +| **SmartSession** | Adopt, unmodified | An existing open-source permission engine that stores permissions and runs policies | +| **Cross-chain gateway** | Adopt (Push Chain's) | The contract that carries value and instructions to other chains | +| **Destination account** | Adopt (Push Chain's) | The user's account on the far chain, controlled from Push Chain. Universal permissions only | +| **Push-native protocol** | Adopt (whatever the owner names) | Any contract on Push Chain a native permission allows the agent to call — a staking pool, a vault, a token. Nothing is built or trusted; the wallet simply calls it | +## What this system deliberately does not have +Read this list before reading anything else. None of these is an oversight. +- **No editing of a granted permission.** A permission is frozen at grant. Any change means revoking it and granting a new one — in one combined step. +- **No upgrade of a deployed wallet.** A wallet's code is fixed forever at creation. A new wallet version means creating a fresh wallet. +- **No guardian, no recovery contact, and no pause on any wallet.** Nobody but the owner can act on a wallet, and nobody at all can freeze one. *(The **factory** has an operational pause that can stop **new wallets being created**. It cannot touch a wallet that exists, its funds, or its rules sets — see chapter 9, item 22.)* +- **No paymaster and no gas sponsorship.** The agent calls the wallet itself and pays its own gas — an EOA agent from its own balance, a UEA agent through its UEA's gas path. +- **No deny-list.** The permission names what is allowed; everything else is refused. There is no list of specially forbidden functions. *(The fixed targets URP refuses even when allow-listed — the loopbacks of gate 14, and on Solana the programs of gate S15 — are not a deny-list of functions: each is a target that would hand the agent the destination account itself.)* +- **No limit on how far in the future a permission may expire.** The user's choice of expiry is respected as given. +- **No mixed permission.** A permission is universal or native, never both. An owner who wants an agent to do both grants two permissions on the same wallet — they coexist, meter independently, and are revoked independently. +## Glossary +| Term | Meaning | +| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Owner** | The user's own key. Created the wallet, controls it absolutely. | +| **Agent** | An automated service identified by a Push address — its own EOA, or the UEA of an external key. It calls the agent door itself; it never holds the user's funds. | +| **Agent wallet** | The contract this document is about. Holds the budgeted funds on Push Chain. | +| **Permission** | One frozen bundle of limits binding one agent, of one **kind** — universal or native. A wallet can hold several, of either kind. | +| **Universal permission** | A permission whose every action travels through the gateway to a far chain. One token, one destination chain, an allow-list of far-chain calls, one destination account. The far chain is an EVM chain or Solana. | +| **Destination family** | Which kind of far chain a universal permission targets — EVM or Solana. Derived from the chain's namespace (`eip155:` or `solana:`); any other namespace is refused at grant. It decides which universal rulebook runs. | +| **Account pin** | A Solana limit: the account at a fixed position in an instruction's account list must equal a key frozen at grant. The Solana counterpart of the beneficiary check — how a source, a destination or an authority is locked. | +| **Data pin** | A Solana limit on an instruction's data: a little-endian integer at a fixed offset must equal, stay at or above, stay at or below a frozen value, or stand in a minimum ratio to another field. How a fee, a slippage ceiling or a price floor is locked. | +| **Native permission** | A permission whose actions are calls to contracts on Push Chain itself. One to eight (contract, function) pairs, each with its own pins, caps and call limit. Nothing leaves Push Chain. | +| **Action** | One (contract, function) pair the engine recognises as a unit. A universal permission has exactly one — the gateway's send. A native permission has one to eight. | +| **Argument pin** | A native limit: a 32-byte word at a fixed position in a call's data that must equal a value frozen at grant. This is how a beneficiary, a spender or a pool id is locked. | +| **Policy** | A contract that checks one aspect of a request. URP is the main one. | +| **SmartSession** | The adopted engine that stores permissions and calls each policy in turn. | +| **Gateway** | Push Chain's cross-chain transport. The only thing a **universal** action is ever allowed to call — and the one thing a **native** action never may. | +| **Destination account** | The user's account on the far chain. Its address is known in advance: on an EVM chain Push Chain computes it; on Solana it is a program-derived address of the gateway program, derived by tooling. | +| **PC** | Push Chain's native token, used for gas. | +--- +# 2 · The pieces +Six things make up the system. This chapter says what each one is, what it stores, and where it runs. How they interact comes in chapters 3 to 6. +## 2.1 The wallet factory +- A single contract on Push Chain that creates agent wallets. +- Whoever calls it becomes the owner of the wallet it creates. There is no way to create a wallet owned by someone else — the factory does not accept an owner as input; it uses the caller's address, full stop. +- Wallet addresses are **predictable before creation**. The factory uses deterministic deployment (CREATE2): the address is computed from the owner's address plus a per-owner counter. Creating two wallets in a row gives two different, but individually predictable, addresses. +- The factory itself sits behind an upgradeable proxy, so its logic can be improved — **but the address computation must never change**. If it changed, any address a user had computed in advance (and possibly already sent funds to) would become unreachable. A permanent regression test pins this. +- The factory stores: the wallet implementation address, and each owner's wallet counter. +## 2.2 The agent wallet +- A **minimal clone**: a tiny contract that delegates all logic to one fixed implementation. Cheap to create, and **not upgradeable — ever**. The owner's address is baked into the clone's own bytecode at creation and can never be reassigned. +- It is a modular smart account following an existing standard (ERC-7579), reduced to the minimum: it supports exactly **one kind of module — a validator** (a contract that checks signatures and permissions). Attempts to install any other module kind (executors, hooks, fallbacks) are refused by the wallet itself. +- It has two doors: +\t- **The owner door.** The owner can make the wallet do anything, send anything anywhere, with no checks at all. This is deliberate and is covered in chapter 3. +\t- **The agent door** — a function called `executeAsAgent`. Only the permission's agent may call it, and the call only passes if every check in chapters 5 and 6 passes. +- What the wallet stores: a grant counter used to make every permission unique (chapter 4), replay counters used only by the owner's own relayable signed-intent door, and a checkpoint counter that every owner-side change advances (chapter 4.5). The agent door keeps no state of its own. +- What it holds: the budgeted funds — the tokens the owner has decided to put under agent management, plus a little PC for gas on cross-chain calls. +## 2.3 The permission +- A permission is **not a single record in one place**. It is written across three storage locations in one grant transaction: +\t- **SmartSession's storage** holds: that the permission exists, which agent may act under it — the agent's Push address — and the list of policy contracts to run. +\t- **URP's storage** holds everything about what the agent may actually do, in one of three shapes chosen by the permission's kind and, for a universal permission, its destination family. For a universal permission to an EVM chain: the allowed protocol functions on the far chain, the token, the caps, the counters, and the destination account address. For a universal permission to Solana: the same token, caps and counters, the destination account and the gateway program, the allowed (program, instruction) rules with their account and data pins, and the list of destination-side accounts that hold value. For a native permission, one record **per action**: the Push contract and function, the argument pins, the value and amount caps, the call limit, and the counters. `2_UniversalRulesPolicy.md` lists every field of all three. +\t- **URP also records the kind itself**, in a small mode record written in the same transaction — and, for a universal permission, the destination family beside it. On every later request URP consults that record — not the shape of the data — to choose which rulebook runs. +\t- *(There is no separate time-window policy in v3: the expiry lives inside URP, so URP is the sole action policy — see `2_UniversalRulesPolicy.md` §1.1.)* +- A permission is identified by a unique id computed from its contents plus a salt the wallet supplies from its own grant counter. Granting the same terms twice therefore produces two distinct permissions — they never collide, and revoking one never touches the other. +- A permission is **immutable**. Nothing in the system can modify one after grant. The only operations that exist are: create one, and remove one. +## 2.4 The agent +- An agent is a **Push address**. A Push-native key is its own EOA; any external key — EVM, Solana, anything Push Chain supports — acts through its UEA, the account Push Chain derives for that key, which verifies the key's signature before it ever calls the wallet. The wallet itself verifies no signature: it checks only who the caller is. +- Any address may be an agent, including a smart contract such as a multisig. +- **An agent is attached to one permission, not to the wallet.** A wallet with three permissions can have three different agents, each locked to its own limits. There is no wallet-level "the agent" and no way to swap the agent inside an existing permission — a new agent means a new permission. +- The agent holds no funds of the user's and has no standing power. Its only ability is to call the agent door, naming one of its permissions, and have the wallet check that call. +## 2.5 URP — introduced +- URP is the contract where the user's real intent is enforced: *this protocol, these functions, this token, this much, for me, until then*. +- It exists because of a structural blind spot in the adopted engine, explained fully in `2_UniversalRulesPolicy.md`: from Push Chain's point of view, every agent action looks identical — a call to the gateway. URP is the contract that opens that call up and inspects what is inside — an EVM instruction list for an EVM chain, a single program instruction for Solana. +- For a native permission it does the complementary job: the engine already sees the target and function, so URP checks how the function is called — which arguments are pinned, how much value rides along, how much of a metered amount, and how many times. +- It is the one contract in the system that is **upgradeable** — it sits behind a proxy at a permanent address, so its rules can be corrected or extended without moving any wallet or reissuing any permission. That is a deliberate trade, and it is what limit 27 in chapter 9 is about: the address is fixed forever, the logic behind it is not. +- One paragraph is all it gets here. **`2_UniversalRulesPolicy.md` is its chapter.** +## 2.6 The destination account +- *(Universal permissions only. A native permission has no destination account: its actions never leave Push Chain, and whatever they produce is credited to the wallet itself.)* +- The user's account on the far chain (Ethereum, Solana, or any chain Push supports). Push Chain's existing infrastructure creates it and controls it; we adopt it as-is. +- **On an EVM chain** its address is **computable in advance** on Push Chain, before the account even exists on the far chain (`getCEAForPushAccount` forward, `ceaToPushAccount` reverse). +- **On Solana** it is a program-derived address of the gateway program, seeded by the wallet's own Push address (`["push_identity", wallet]`). A Solidity contract cannot run that derivation, so the tooling derives it — along with the destination account's token accounts for each mint the permission touches — and the owner commits the 32-byte keys at grant. A wrong key fails closed: the pins never match. +- At grant time, the tooling computes this address and freezes it into the permission. From then on, URP requires that everything the agent does on the far chain benefits **that address and no other**. The agent can trade with the user's money; everything it buys lands in the user's own far-chain account — on Solana, in that account's own token accounts. +- **On Solana the destination account is also the signer.** The gateway hands it the bridged funds and then makes one call into the target program with the destination account as the only signer — and that signing authority carries into whatever the target program itself calls. `2_UniversalRulesPolicy.md` §1.4c is how URP narrows what that authority can reach; chapter 9 states what it cannot narrow. +## 2.7 The Push-native protocol +- Any contract on Push Chain that a native permission names: a staking pool, a vault, a token, a registry. Nothing is built, adopted or trusted — it is whatever the owner chose to allow. +- The wallet calls it **directly, as itself**. The protocol sees the wallet as the caller, so whatever the call produces — a staked position, shares, a claim — is the wallet's, never the agent's. This is the native counterpart of the destination account's "for the user only" rule, one hop shorter. +- To the engine it is an (address, function) pair and nothing more. To URP it is that pair plus the pins, caps and counters the owner attached. Neither contract knows what the function *means*; both only know what the owner allowed. +## Diagram — the system map +```mermaid +flowchart TB + subgraph PUSH["Push Chain"] + OWNER["Owner\ +(the user's key)"] + FACTORY["Wallet factory\ +(upgradeable, frozen address math)"] + WALLET["Agent wallet\ +(minimal clone, never upgradeable)\ +owner door + agent door"] + SS["SmartSession\ +(adopted permission engine)"] + URP["URP\ +(the limits — 2_UniversalRulesPolicy.md)\ +upgradeable behind a proxy"] + VAL["Session validator\ +(confirms the caller is the agent)"] + GW["Cross-chain gateway\ +(adopted transport)"] + NP["Push-native protocol\ +(any contract a native permission names)"] + end + subgraph FAR["Destination chain"] + CEA["Destination account\ +(the user's far-chain account)"] + PROTO["Allowed protocol\ +(e.g. a market, a lending pool)"] + end + AGENT["Agent\ +(a Push address: an EOA,\ +or the UEA of an external key)"] + + OWNER -- "creates, one call" --> FACTORY + FACTORY -- "deploys" --> WALLET + OWNER -- "grants / revokes permissions\ +and can execute anything" --> WALLET + AGENT -- "calls the agent door itself" --> WALLET + WALLET -- "asks: is this allowed?" --> SS + SS --> URP + SS --> VAL + WALLET -- "universal action, only if every check passed" --> GW + WALLET -- "native action, only if every check passed\ +(the wallet is the caller)" --> NP + GW -- "bridges value + instruction" --> CEA + CEA -- "calls, for the user's benefit only" --> PROTO +``` +--- +# 3 · Who controls what +## The single chain of authority +There is exactly one chain of control in this system, and it starts and ends with the user. +- **The user's key owns the wallet.** Ownership is fixed at creation, inside the wallet's own bytecode. It cannot be transferred, stolen by code, or reassigned by any function — no function to do so exists. +- **The wallet owns its permissions.** Only the owner, through the wallet, can create or remove a permission. An agent cannot grant itself anything, extend anything, or remove anything. +- **A permission bounds one agent.** The agent can call the agent door within the permission's limits. That is the entirety of its power. +- **The wallet's Push-side identity owns the destination account.** The far-chain account obeys instructions that arrive through Push Chain's gateway from the wallet. The agent never controls the destination account; it can only cause the wallet to send it instructions that URP has already approved. +- **For a native permission the same rule holds one hop shorter.** The wallet calls the Push contract as itself, so the position, the shares, the claim — whatever the call produces — is credited to the wallet. The agent never controls the target contract; it can only cause the wallet to call it in exactly the way URP has already approved, with the arguments the owner pinned. +## The owner door has no checks — on purpose +- The owner can execute anything from the wallet at any time: withdraw every token, send to any address, call any contract, on Push or (via the gateway) beyond. +- **No policy, no cap, no expiry, no destination rule applies to the owner.** All of `2_UniversalRulesPolicy.md` applies to the agent door only. +- Why: every safety mechanism on the owner's own exit is also a way for the owner to be locked out of their own money. The design refuses that trade. The wallet must remain drainable *by its owner* in every degraded state the rest of the system could ever reach — engine misconfigured, policy bricked, permission wedged, bridge down. A standing test executes an owner withdrawal in each of these states and must always pass. +- The cost of this choice is stated plainly: **a stolen owner key drains the wallet completely.** There is no guardian and no delay to stop it. Defence against key theft belongs to the layer that holds keys — the user's identity and key-management setup — not to this wallet. This is the first entry in chapter 9's list of accepted limits. +- **The owner door records, but never asks.** Each call through it advances the wallet's checkpoint counter (chapter 4.5), so a job's evaluator can tell whether the owner touched the wallet during the job. The write consults nothing and cannot revert, so the door stays unblockable. +## What the agent's call is — and is not +- The agent's authority is **being the sender**. The wallet admits a call only from the address the named permission records as its agent, so there is no bearer request: nothing the agent produces can be submitted by anyone else. +- A call grants nothing durable. Each one spends from the permission's remaining budget once, as the transaction it is; replay is prevented by the sender's own nonce (chapter 5). +- The agent never touches custody. At no point in any flow do funds sit in an account the agent controls. Universally, they move from the wallet, through the gateway, to the user's own destination account, and anything bought lands in that same account. Natively, they move from the wallet straight into a Push contract as the wallet's own position, and come back to the wallet. +## Diagram — the chain of ownership +```mermaid +flowchart TB + KEY["The user's key\ +absolute control, no checks on its path"] + W["Agent wallet on Push Chain\ +owner fixed at creation, forever"] + P1["Permission 1\ +agent A · its own limits"] + P2["Permission 2\ +agent B · its own limits"] + CEA["Destination account on the far chain\ +obeys the wallet, via the gateway"] + NP["Push-native protocol\ +credits whoever calls it — the wallet"] + A1["Agent A — may only act\ +within Permission 1"] + A2["Agent B — may only act\ +within Permission 2"] + + KEY -- "owns, unconditionally" --> W + W -- "creates / removes" --> P1 + W -- "creates / removes" --> P2 + P1 -.-> A1 + P2 -.-> A2 + W -- "its Push identity controls" --> CEA + A1 -. "universal: can only trigger wallet→gateway calls\ +that URP approves, benefiting the\ +destination account only" .-> CEA + A2 -. "native: can only trigger wallet→contract calls\ +that URP approves, with the owner's pins,\ +credited to the wallet only" .-> NP +``` +--- +# 4 · The life of a permission +## 4.1 Birth — the grant +- The owner (or the tooling acting for the owner, with the owner signing) composes the terms. **The first term is the chain** — a CAIP-2 identifier such as `eip155:11155111` or `solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1` — and it decides the kind and, for a universal permission, the destination family, which together decide the shape of everything after it. Common to both kinds: +\t- the agent's Push address — its own EOA, or the UEA of its external key; +\t- the expiry — one value, held inside URP. +- **For a universal permission to an EVM chain:** +\t- the far-chain protocol: each allowed contract address and function, and — for each function — where in its arguments the *beneficiary* sits, so URP can later check that the beneficiary is the user's destination account. These argument positions are **generated from the protocol's interface by tooling, never typed by hand** (a promise the contracts cannot check — chapter 10); +\t- one token, and with it one destination chain — a permission never spans tokens or chains; +\t- the caps: a per-action maximum, a lifetime maximum, and a maximum of native PC per action; +\t- the destination account's computed address. +- **For a universal permission to Solana:** +\t- the same token, the same three caps, and the expiry — these terms do not depend on the far chain; +\t- the destination account and the **gateway program** on the declared cluster — both 32-byte keys, both supplied by tooling: the destination account derived from the wallet's address, the gateway program taken from the chain registry, never from user input; +\t- one to thirty-two **program rules**, each a far-chain program and one instruction on it, identified by its leading bytes — eight for an Anchor program, one for an SPL-style program — or marked as an instruction that carries no data. A rule may also fix the instruction's exact account count; +\t- up to sixteen **account pins**: for a given rule, the account at a given position in the instruction's account list must be a given key. This is how the destination account is locked in as the authority, its token account as the source, and its token accounts as every destination. Every rule must carry at least one; +\t- up to eight **data pins** on the instruction data: a little-endian integer at a fixed offset — from the start, or from the end, because Borsh puts variable-length fields first — compared for equality, a floor, a ceiling, or a minimum ratio against a second field. This is how a fee is locked at zero, slippage is capped, and a swap's output is held to a floor *relative to its input*; +\t- up to eight **destination-side accounts that hold value** — the destination account itself, which must be on the list, and its token accounts. At validation, any of these that appears in a request's account list must sit exactly where the matched rule pins it; +\t- **all of it is generated from the program's published interface by tooling, never typed by hand** (chapter 10). A wrong pin fails closed; a missing pin guards nothing. +- **For a native permission:** +\t- one to **eight** actions — eight is a fixed wallet constant, a sanity bound rather than a gas bound — each a Push contract and one function on it. A function may be *value-only*: a bare transfer of native PC with empty call data; +\t- per action, the **argument pins**: up to eight positions in the call data, each frozen to the exact 32-byte word that must appear there. This is how a beneficiary is locked to the wallet, a spender to one contract, a pool to one id. **Positions are generated from the contract's interface by tooling, never typed by hand** (chapter 10) — a wrong position fails closed, but a *missing* pin guards nothing; +\t- per action, the native-value caps: a per-call maximum and a lifetime maximum; +\t- per action, optionally, a **metered amount**: one argument position read as a number, with its own per-call and lifetime maximum — the native counterpart of the bridged-amount cap; +\t- per action, a **call limit**: how many times the action may run, where zero means unlimited; +\t- and nothing else. There is no token, no destination chain, and no destination account: a native permission has no far side. +- The owner sends one transaction through the wallet. The wallet supplies a salt from its internal grant counter — this is what makes every permission unique — and calls the engine's standard enable function. In the same transaction, URP's configuration — including the permission's expiry — is written: one record for a universal permission, one record **per action** for a native one, and beside them the record of which kind this is. +- **Before anything reaches the engine, the wallet derives the kind from the chain and asserts it against the actions.** Every action must name the same chain, or the grant is refused naming the action that differs — which is what makes a mixed permission unrepresentable rather than merely forbidden. A universal permission must name exactly one action, and it must be the gateway's outbound send — whatever its destination family; the wallet never tells an EVM permission from a Solana one, and does not need to. A native permission may name anything on Push Chain **except** the gateway — and except seven addresses that would turn the agent into the owner: the zero address, the engine's wildcard marker, the wallet itself, the engine, URP, the validator, and the factory. It may not name the engine's two wildcard function markers, and it may not name the same (contract, function) pair twice. Every one of these refusals carries its own named error, and the two that matter most — the wallet and the engine as targets — are pinned by permanent tests. +- The wallet exposes exactly **two** permission operations to the owner: *enable* and *remove*. The engine underneath offers more; the wallet deliberately does not surface them. *Enable* takes the session and nothing else; it records the **derived** kind and the chain in the grant event, so an indexer can tell a native permission from a universal one, and which chain it is for, without opening the session. +- A failed grant does not undo a wallet. A wallet with zero permissions is a valid, safe object: with no permission there is no agent authority of any kind, and every agent request fails before any policy even runs. +## 4.2 Life — what the counters mean +- **The lifetime cap counts what is bridged, not what is deployed.** When the agent moves 40 of an allowed 100 to the far chain, the counter reads 40. If it then trades those 40 into 80 and back again on the far chain, the counter still reads 40 — redeployment at the destination is not new spending from the wallet. The cap bounds the user's exposure *from the wallet*; the expiry bounds how long the agent can keep working with what is already across. +- **An unlimited cap is allowed and is expressed as the largest representable number.** There is no special "unlimited" flag; the comparison simply never trips. The product must display this honestly — "unlimited", never a huge number (chapter 10). The one exception is a native action's **call limit, where zero means unlimited** — a call limit of zero calls would be a permission that authorises nothing. +- **A native action keeps three counters, not one:** native value sent, the metered amount (if the action has one), and calls made. **Every successful call counts as a call, even one that sends no value and meters no amount.** A call limit that zero-value calls could slip past would be advisory, so the counter always moves — this is the one place the native rulebook deliberately differs from the universal one, whose counter does not move on a zero-amount request. +- *(Universal only.)* **If a cross-chain action fails on the far side, the spent amount is credited back** — the wallet's funds return and the counter should not stay inflated. This credit is issued by Push Chain's own executor module calling URP. It is **designed but not yet functional**: it needs a change on the Push core side that has not landed. Until it lands, a failed far-side action leaves the counter inflated, and the remedy is to revoke and regrant. Both halves of this are stated again in chapters 9 and 11. +## 4.3 Change — there is no change +- **A permission is never edited. Every "change" is: revoke the old one, grant a new one, in one atomic owner transaction.** If any part fails, the whole transaction fails, and the old permission remains exactly as it was. There is no window where the wallet is half-configured. +- One race is guarded explicitly. Between the owner composing the change and the transaction landing, the agent may spend. The owner's change transaction therefore begins with an **assertion of the expected spent amount**: "I am replacing this permission believing it has consumed X." If the agent moved money in the gap, the assertion fails, the whole change reverts, and the owner re-reads and retries with current numbers. Stale beliefs never silently become new budgets. For a native action the assertion names **all three counters** — value, amount, calls — and every one must match exactly; and it refuses to run against a permission of the other kind, or against one that does not exist, so a stale belief can never pass by reading zeros from the wrong place. +- **Counters restart from zero on the new permission.** This is a real, accepted sharp edge: replacing a 100-cap permission that had 80 spent with a "tighter" 50-cap permission yields 50 of *fresh* authority — more than the 20 that remained. The contracts do not compensate for prior spend, and the product is obliged to show the owner what the old permission had consumed before the new cap is chosen (chapter 10). +- Because no permission can ever be widened in place, an entire class of problems disappears structurally: there is no "widening inside the expiry window" to delay, timelock, or guard. The mechanism that would have needed guarding does not exist. +## 4.4 Death — revocation and expiry +- **Revocation is one owner call, effective immediately on Push Chain.** The permission's storage is removed; the very next agent request against it fails. Nothing the agent does can delay or contest this. Removal performs pure storage deletion — it calls out to nothing, so no external contract can make revocation fail (`SmartSessionBase.sol:329-355`, `ConfigLib.sol:274-284`). +- **One honest limit:** revocation stops new instructions. An instruction that already left through the gateway — already in flight across the bridge — still completes on the far chain. The window is bridge latency. The revoke screen must say this (chapter 10). +- **Expiry needs no transaction.** Past the expiry, URP's expiry gate — the second gate of every rulebook (2, N2, S2) — fails every request. The permission's storage still exists until removed, but it is inert. +- Removing a permission also ends its agent's power under it: removal clears the agent the permission named, so the very next call under that id is refused before any policy runs. A regrant produces a new id — the wallet's grant counter salts it — so a request built for the old id fails against the new permission too. A permanent test pins this. +## 4.5 Checkpoints — what the owner side did, for whoever needs to know +- The wallet keeps one **checkpoint counter**, read through `checkpointCount()`, with the block of the latest checkpoint beside it (`lastCheckpointBlock()`). A job records the count when it is funded; its evaluator compares later. Same number: the result is the agent's alone. Different number: the owner side touched the wallet. +- **What advances it:** every call made through an owner door — `execute` or `executeWithSig`, one tick per call, a batch of five ticks five times — every grant, and every revoked permission (once per id). **What never does:** the agent door and everything it dispatches, module install and uninstall, factory set-up, and any call that reverts. +- **One tick per call, taken before the call.** A job is funded from inside an owner-door call — the wallet itself calls the job contract — and the job's hook reads the counter during that call. Ticking before each call means a clean funding batch ends exactly at the hook's snapshot, while a withdrawal batched after the funding call moves the counter past it. A tick once per batch would either make every job look tampered with or hide that withdrawal. +- **Compare counts, not blocks.** Several checkpoints can share a block — including the funding call's own — so "anything after block N" misses them; a changed count never does. +- **It cannot block anything.** A tick is one write to the wallet's own storage and one event: no external call, no condition that can fail. The owner door and revocation stay unblockable. +- One counter for every kind of change. The event (`Checkpointed`) also carries the kind — `OWNER_ACTION`, `RULES_GRANTED` or `RULES_REVOKED` — and a reference (the call's hash, or the permission's id) for indexers. +## Diagram — the permission lifecycle +```mermaid +stateDiagram-v2 + [*] --> Composed: owner + tooling assemble terms + Composed --> Active: one grant transaction\ +(engine + URP + expiry written together) + Active --> Active: agent request passes\ +counters advance + Active --> Active: far-side failure\ +credit back (designed — not yet functional) + Active --> Expired: expiry passes\ +no transaction needed + Active --> Removed: owner revokes\ +immediate, unconditional + Active --> Replaced: CHANGE = revoke + regrant\ +one atomic transaction,\ +gated by the spent-amount assertion + Replaced --> [*]: old id dead — requests for it die with it\ +new permission starts at zero + Expired --> Removed: cleanup, optional + Removed --> [*] +``` +--- +# 5 · One action, end to end +This chapter walks a single agent action from the agent's call to funds moving. It is the spine of the whole system; `2_UniversalRulesPolicy.md` then zooms into the deepest step. +## 5.1 Why the wallet does so much itself +- On chains that follow the account-abstraction standard, a shared system contract (the "EntryPoint") receives signed account operations, checks replay protection, and dispatches them. **Push Chain has no such contract.** So our wallet performs those jobs itself, inside one function — the agent door, `executeAsAgent`. +- The wallet keeps the standard's *packaging* (the operation format), because the adopted permission engine speaks it. But the packaging is just a shape; there is no shared dispatcher behind it. The wallet is its own dispatcher and never leaves the call stack — which has one important consequence used later: **when the wallet finally calls the gateway, the gateway sees the wallet itself as the caller**, not the agent. +## 5.2 The request the agent sends +What the agent sends depends on the permission's kind — but only in the innermost part. The call around it is identical for both. +**A universal request has nested layers.** The agent composes the action innermost first: +- **Innermost — the far-chain call.** The actual thing the user wanted: for example, *buy these shares, for this much of the token, with the user's destination account as beneficiary*. +- **Around it — the instruction list.** The far-chain calls are packed as an instruction list for the destination account, between one and **ten** entries — ten is a fixed contract constant. Each entry is: a target address, a native-value amount, and call data. +- **Around that — the gateway request.** The message to Push Chain's gateway: which token and how much to bridge, the instruction list as payload, and two routing fields URP will pin (`2_UniversalRulesPolicy.md`): the bridged-funds recipient field, and the refund destination. +- **Outermost — the execution payload.** The gateway request as the single call the wallet will make: the gateway as target, the PC for far-side gas as value. +**A universal request to Solana has the same layers, with a different middle.** There is no instruction list: the gateway makes exactly one call into one program per request, so the payload is a **single Solana instruction** — the account list (each a key and a writable flag), the instruction data, and the target program — in the byte format Push Chain's validators decode, not ABI. The gateway request's recipient field, which must be empty for an EVM chain, carries the **target program** here, and must equal the program named inside the payload. A flow that needs two instructions is two requests, the later ones bridging nothing. +**A native request has one layer.** There is no far-chain call, no instruction list and no gateway request. The agent names a Push contract, a native-value amount, and the call data — and that flat call *is* the execution payload. Three nested envelopes become one call; nothing else changes. +Then the agent calls the agent door itself with three things: **the permission's id, the execution mode, and the execution payload.** There is no signature to attach — the agent's authority is being the sender. +## 5.3 Who may call — the sender check +- The wallet looks up the agent the named permission records — the address stored in it at grant — and compares it with the caller. Anyone else is refused, by name, before the engine is ever called: the owner, a stranger, another permission's agent. An id that is unknown, revoked, or names a session validator other than the canonical one records no agent, so a call under it is refused the same way. +- **An external key acts through its UEA.** The UEA verifies the key — secp256k1, Ed25519 or whatever that chain uses — and then calls the wallet; the UEA is the agent the permission names. The external key calling the wallet directly is just another stranger. +- The wallet then writes the caller's address into the operation it hands the engine, in the field the engine treats as the signature. Nobody outside the wallet can supply that field: the engine accepts an operation only from the account it is for, so only the wallet can obtain a verdict for the wallet. At the end of validation the session validator compares that address with the agent stored in the permission — a second, independent check behind the first. +## 5.4 Replay protection — the sender's own +- Each agent action is a transaction of the agent's own. An EOA agent's transaction carries its nonce; a UEA agent's action is a UEA payload with its own nonce and deadline. A transaction that has been mined cannot be mined again, so no request runs twice — and the wallet keeps no replay state for agents at all. +- The same call submitted twice is two actions: each is checked against the permission and each is metered. +- If execution reverts, the whole transaction unwinds — every counter, everything — leaving no half-spent state. A failed action costs the agent gas and changes nothing else. +- Expiry is the permission's own, checked inside URP. There is no separate per-request deadline at the wallet; a UEA payload carries one, an EOA transaction does not. +- One honest note: an EOA agent has a single sequential nonce, so a stuck transaction blocks that agent's next one until it is mined or replaced. Accepted, and an agent-side problem only. +## 5.5 The walk, in order +What happens when the agent calls, step by step. Every step is on Push Chain, inside one transaction, until the bridge. +1. **The agent calls the agent door**, naming the permission. **The wallet's first acts are to confirm the engine is still installed — the owner switches the agent door off entirely by revoking everything and uninstalling it — and that the caller is the agent the permission names.** Both are checked before anything else costs gas; a wrong caller is refused by name. +2. **The wallet builds the operation**: the execution as an `execute` call, and in the signature field the use-mode marker, the permission's id and the caller's address — written by the wallet, never supplied from outside. +3. **The wallet asks the permission engine to validate.** SmartSession looks up the permission by its id: does it exist on this wallet? Which policies are attached? +4. **The engine runs every attached policy, in order, on the raw request.** First it identifies the action by the call's target and function; a native request naming any pair the permission did not grant dies here, at the engine, before any policy runs. Then, for this system, exactly one policy: **URP — the whole of `2_UniversalRulesPolicy.md`**, which reads the permission's kind and runs the matching rulebook, and which carries the expiry check itself. Every policy must pass; any failure ends everything with nothing spent. Two engine facts matter here: +\t- **Action policies have a minimum count of one, but the engine's other policy class (checks on the outer operation) has a minimum of zero** (`SmartSession.sol:237-247, 285-299`). Rule for this system: **no mandatory guarantee may live only in that zero-minimum class**, because a configuration with none of them is legal. Everything mandatory lives in URP. +\t- **Policies run before the session validator is consulted** — an engine ordering we adopt, not choose (`SmartSession.sol:340-352`). The wallet has already checked the caller at step 1, but the rule stands for every policy: it must be safe to run on arbitrary calldata the engine has not yet authenticated. URP holds no state that validation mutates, so a bad request can waste gas and nothing else. +5. **The session validator is consulted last.** It compares the address the wallet wrote into the signature field with the agent stored in the permission. Wrong address, no execution. +6. **The wallet enforces the verdict explicitly.** Because there is no EntryPoint to do it, the wallet itself unpacks the engine's answer and enforces both the pass/fail result and the validity window it returns. +7. **The wallet refuses two targets whatever the engine said.** After validation and before dispatch, if the approved call targets the wallet itself or the engine, the wallet reverts. Neither can ever be granted (chapter 4.1), so on a permission the wallet created this never fires — it exists for a permission the owner enabled on the engine *directly*, bypassing the wallet's grant check, which the owner door permits. It is the last of four independent refusals of a self-call, it runs deliberately **after** validation and not before (chapter 11), and two permanent tests pin it — one of them reaching the engine as a target through the engine's own wildcard. +8. **The wallet makes the approved call, with the exact validated bytes.** For a universal permission that is **the gateway**: it sees the wallet as the caller, pulls the bridged token amount from the wallet's balance, takes the PC provided for far-side gas, and emits the cross-chain message. For a native permission it is **the named Push contract**, called by the wallet as itself, carrying the approved value and call data: the contract sees the wallet as the caller, and whatever the call produces is the wallet's. **A native action is complete here** — one Push transaction, no bridge, nothing in flight. The two steps below are universal only. +9. **On the far chain**, the destination account receives the message and runs the instruction list, entry by entry, each call made *by the user's own account* — which is why anything bought lands as the user's. **On Solana** the gateway moves the bridged funds to the destination account and makes the one approved call into the target program, with the destination account as signer; whatever the instruction produces lands in the token accounts the pins named. +10. **If the far side fails**, the funds return through Push Chain's infrastructure, and the credit path of chapter 4.2 applies (designed — not yet functional). Gas is never refunded: it was genuinely consumed. **A refund credit must not move any gas counter** — a permanent rule. +## Diagram — one agent action +```mermaid +sequenceDiagram + participant AG as Agent (EOA, or UEA of an external key) + participant W as Agent wallet + participant SS as SmartSession (engine) + participant U as URP + participant V as Session validator + participant GW as Gateway + participant DA as Destination account (far chain) + participant NP as Push-native protocol + + AG->>AG: universal (EVM): build nested layers:
far-chain call → instruction list (≤10) → gateway request → payload
universal (Solana): one program instruction → gateway request → payload
native: one flat call (contract, value, data) = payload + AG->>W: executeAsAgent(permission id, mode, payload) — the agent is the sender + W->>W: 1. engine still installed? caller == the permission's agent?
(refused by name otherwise, before the engine runs) + W->>W: 2. build the operation; write USE ‖ id ‖ caller into the signature field + W->>SS: 3. validate against the named permission + SS->>SS: identify the action by (target, function);
an ungranted pair dies here + SS->>U: 4. the whole of 2_UniversalRulesPolicy.md —
read the kind, run its rulebook, check every limit + U-->>SS: pass / fail (nothing spent on fail) + SS->>V: 5. LAST: is the address in the signature field the permission's agent? + V-->>SS: agent confirmed / rejected + SS-->>W: verdict + W->>W: 6. enforce the verdict and its validity window itself + W->>W: 7. refuse the wallet or the engine as target, whatever the verdict + alt universal permission + W->>GW: 8. call with the exact approved payload
(gateway sees the WALLET as caller) + GW->>DA: bridge token + instruction list + DA->>DA: EVM: run each instruction as the user's own account
Solana: one call into the target program, the user's account signing + Note over U,DA: far-side failure → funds return, spend credited back
(designed — not yet functional) · gas never refunded + else native permission + W->>NP: 8. call the named Push contract with the exact approved bytes
(the WALLET is the caller) + NP-->>W: whatever the call produced is the wallet's — done, one transaction + end +``` +--- +# 6 · The rules policy +URP — the Universal Rules Policy (`UniversalRulesPolicy`) — has its own document: [`2_UniversalRulesPolicy.md`](2_UniversalRulesPolicy.md). It covers why the contract exists, what it stores for each kind of rules set, what it opens, every gate of the universal EVM, Solana and native rulebooks, what it counts, what it deliberately does not do, and how a rules set's kind is fixed — with the flow diagrams. +--- +# 7 · What we adopted, and what that costs +Four external systems are load-bearing. For each: what we rely on it for, and the exact exposure that reliance creates. Nothing here is hidden as a footnote. +## 7.1 The permission engine (SmartSession) +- **Relied on for:** storing permissions and each one's agent, deriving their ids, running every policy, and consulting the session validator — the whole of chapter 5, steps 3–5. +- **What we get for free:** battle-tested storage and lifecycle code; removal that is pure storage deletion and cannot be blocked by any external call (`SmartSessionBase.sol:329-355`, `ConfigLib.sol:274-284`). +- **The costs, each one carried knowingly:** +\t- **Policies run before authentication** (`SmartSession.sol:340-352`). Every policy we ever attach must be safe on arbitrary calldata from anyone. This is a standing constraint on all future policy work, not just on URP. The wallet authenticates the sender before the engine runs, but the engine's own ordering is unchanged. +\t- **One policy class may legally be empty** (`SmartSession.sol:237-247`) — hence the wiring rule that nothing mandatory lives there. +\t- **The engine ships an owner-only function that resets a policy's counters in place.** v3 tooling never calls it, and the agent structurally cannot (it is owner-path only) — a named test proves the agent cannot reach it. But it survives upstream, and a future tool that called it would silently refill a budget. +\t- **At grant, the engine refuses only two targets: the zero address and itself** (`ConfigLib.sol:139-143`). It does **not** refuse its own wildcard marker at grant — only at validation. The wallet is therefore the only grant-time layer keeping that marker, and the two wildcard function markers, out of a native permission. The wallet refuses all three by name; a constant-mirror test pins each value against the vendored engine so a fork bump cannot silently move them. +\t- **The engine identifies an action by (contract, function) alone**, so two entries naming the same pair collapse to one configuration, and the second initialisation would be refused by URP with an error naming an opaque id. The wallet refuses duplicates first, naming the pair. +\t- **The engine truncates a policy's revert data to 32 bytes** before re-wrapping it — a selector and 28 bytes of the first argument. Every native-rulebook error is therefore ordered with its diagnostic value first (`2_UniversalRulesPolicy.md` §1.4b). Wallet errors do not pass through the engine and are not truncated. +## 7.2 The cross-chain gateway +- **Relied on for:** carrying value and instructions to the far chain, and being the *only* thing a universal agent action can touch (gate 3) — and the one thing a native action never may (gate N3, and the wallet's grant check). +- **The costs:** +\t- We inherit the gateway's availability and its bridge latency — the revocation window of chapter 4.4 is exactly this latency. +\t- The gateway's refund behaviour for our outbound direction is documented for the *inbound* direction only (`Revert_Handling.md:14` covers inbound; outbound is handled by Push core's own modules). Our exposure analysis of refund edge-cases is complete except for this one gap, recorded as an open question (chapter 11). It blocks nothing we build. +\t- **On Solana the far side is Push Chain's gateway program**, whose id differs per cluster. URP has no registry for it, so it is committed by the owner at grant from the chain registry (chapter 10). A wrong value weakens only that owner's permission, and fails closed on the pins. +\t- **On Solana the gateway makes one call per outbound.** A flow that needs two instructions — create a token account, then swap — is two outbounds, the later ones bridging nothing. A limit of the gateway, not of URP. +\t- **On Solana URP must parse exactly what Push Chain's validators parse.** The payload grammar of `2_UniversalRulesPolicy.md` §1.3 is theirs; a change to it on their side is a change URP must follow, and until it does every Solana request fails closed at S12. +## 7.3 The destination-account system +- **Relied on for:** the user's far-chain account — its creation, its address computation in both directions, and its obedience to gateway messages. +- **The costs, inherited not owned:** +\t- **Its factory is upgradeable by Push governance,** and the account templates can be rotated. Our guarantee that "the committed destination address is the user's account" is therefore inherited from Push's own governance discipline. We accept this on admin trust — Push's governance is our platform, not our adversary. One operational duty watches it (chapter 10): monitoring compares each permission's committed destination address against the current prediction, so a rotation that changes derivations is *detected* even though nothing on-chain prevents it. +\t- **A paused destination-account factory blocks a first outbound to a chain where the user's account does not yet exist.** Availability only; no funds at risk. +\t- **The account's own instruction loop is unbounded** in Push's code — our ten-entry bound (gate 13) is enforced on our side, and a note is open with Push core about theirs (chapter 11). +\t- **On Solana the destination account is a signer, not a caller.** Whatever program it is handed may act with its signature on every account in the list, including through that program's own inner calls. This is the one way the Solana rulebook is structurally weaker than the EVM one; `2_UniversalRulesPolicy.md` §1.4c's S17 and S18 narrow it, and chapter 9 states the remainder. +\t- **On Solana only the bridged token's account is created for the user automatically.** The gateway creates the destination account's token account for the bridged mint on first use; any other token account — a swap's output, say — must exist beforehand (chapter 10). +## 7.4 Push Chain's executor module +- **Relied on for:** the credit-back path — it is the one caller URP will believe about far-side failure. +- **The costs:** +\t- The whole credit-back feature is **gated on Push core work that has not landed** — the module does not yet call URP on failure. Until it does, the feature is inert and the counter-inflation limit of chapter 9 applies. +\t- Its on-chain address is written in Push's platform code (`UniversalCore.sol:50`) but **unconfirmed against a live deployment** — one of the two facts that must be confirmed before URP hardcodes anything (chapter 11). +\t- URP cannot verify the amounts it reports — trusted, with damage bounded by once-per-id and never-below-zero. +--- +# 8 · Guarantees +Every promise the system makes, with the mechanism behind it and the test that proves it. A promise with no mechanism is marketing; each of these names its enforcement. +| The promise | The mechanism | Proven by | +| ---------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | +| Nobody but you can ever own your wallet | Owner = creator, baked into the clone's bytecode; no function to change it | No code path accepts another owner — deployment attempts prove it | +| The agent can never spend a token you did not name | Gate 5: the one-token pin | A request naming any other token reverts | +| …never more per action than you set | Gate 6 | An over-cap request reverts | +| …never more in total than you set | Gate 7 + spend recorded before dispatch | Requests summing past the cap revert at the crossing point | +| …never for anyone's benefit but yours | Gate 15's beneficiary pin; on Solana, gate S17's account pins | A request naming any other beneficiary — on Solana, any other destination token account — reverts | +| …never touching any protocol you did not allow | Gate 15: the allow-list — on Solana, gate S16's exact (program, instruction) match | A request to an unlisted target or function — on Solana, an unlisted program or instruction — reverts | +| …never after the end date | Gate 2 — the expiry inside URP (N2 native, S2 on Solana) | A request after expiry reverts with no state change | +| …never instructing your far-chain account directly | Gate 14, including the destination account, checked before the allow-list; on Solana, gate S15, which adds the token, system, stake, loader and lookup-table programs and the gateway program | **Must revert even when that address is in the allow-list** — permanent tests, at grant and at validation on Solana | +| *Solana:* …never handing your account's other balances to the program | Gate S18: every value-holding account appears only where the matched rule pins it; the list always contains the destination account | A value-holding account at an unpinned position reverts — permanent test; a list without the destination account is refused at grant — permanent test | +| *Solana:* …never swapping below the floor you set | Gate S17's data pins — a floor relative to the input, a slippage ceiling, a zero fee | A swap whose output falls short of the ratio reverts, including one that raises the input to beat a static floor — permanent test | +| *Solana:* …never more per action than Solana can carry | Gate S6b | An amount above 64 bits reverts | +| A "failed" action can never deliver funds to the agent | Gate 10 (refunds come home) + gate 11 (no side recipient); on Solana, S10 + S11 and S14 (the recipient is the target program, nothing else) | A request with any of these fields wrong reverts | +| Only the permission's agent can act under it | The wallet checks the caller against the agent the permission names before the engine runs; the session validator checks the address the wallet wrote, last | Every other caller — the owner included — is refused by name | +| No request runs twice | Each agent action is the agent's own transaction — an EOA's nonce, or the UEA payload's nonce; the wallet keeps no agent replay state | A mined transaction cannot be mined again; the same call sent twice is two actions, each checked and metered | +| A request dies with its permission | Removal clears the permission's agent; a regrant gets a new id from the wallet's grant counter | **A request for the old id fails after revoke-and-regrant** — permanent test | +| One permission's request can never be charged to another | The call names its permission, whose agent must be the caller; URP keys every counter on that id | An agent acting under another agent's permission reverts | +| Revocation is immediate and unblockable | One owner call; removal is pure storage deletion, no external calls | Revocation succeeds with a hostile policy installed; next request fails | +| A change never mixes old and new states | Atomic revoke + regrant; spent-amount assertion gates it | The change reverts when the agent spent in the composition window | +| A failed action costs gas and nothing else | Whole-transaction revert unwinds every counter | Counters identical before and after a failed action | +| You can always withdraw everything | The owner door has no checks | Owner withdrawal succeeds in every degraded state we can construct | +| A module can never block its own removal | The uninstall callback runs defensively with a fixed 100,000-gas stipend; on revert or burn-out an event is emitted and removal proceeds anyway | A callback that reverts and one that burns all its gas are both still removed | +| The agent can never refill its own budget | The engine's reset is owner-path only; v3 tooling never invokes it | **The agent-cannot-reset negative test** — permanent | +| Your wallet address, once computed, stays valid | Address math frozen across factory upgrades | **The address-stability regression test** — permanent | +| *Native:* the agent can never call a Push contract or function you did not name | The engine's action identity, plus gates N4 and N5 asserting URP's own copies | A request to an ungranted pair dies at the engine; a mismatched copy reverts at URP | +| *Native:* …never with a pinned argument set to anything else | Gate N7 — full 32-byte equality at the frozen position | A request with any pinned word different reverts, including a correct address with dirty padding | +| *Native:* …never more native value, per call or in total | Gate N6 | An over-cap call reverts; calls summing past the lifetime cap revert at the crossing point | +| *Native:* …never more of a metered amount, per call or in total | Gate N8 | The same, on the metered argument | +| *Native:* …never more calls than you allowed | Gate N9, with every successful call counted | The (n+1)th call reverts; a zero-value call still consumes one | +| The agent can never make your wallet call itself or its engine | Refused at grant — never grantable — and refused again at dispatch, after validation, whatever the engine said | **Two permanent tests**, one of which reaches the engine as a target through the engine's own wildcard, enabled through the owner door | +| A native permission can never reach the gateway; a universal one can never reach anything else | The kind is derived from the chain and asserted against every target at grant; gate 3 and gate N3 mirror it at validation | A gateway target under this chain, and a non-gateway target under a foreign chain, both revert at grant — **permanent tests** | +| Two permissions of different kinds on one wallet never touch each other's counters | Separate storage per kind, keyed by action id | A native call moves no universal counter — asserted on the raw storage slot, not through a getter | +| A permission for a chain URP cannot check is never granted | The destination family is derived from the chain's namespace at grant; any namespace but `eip155:` and `solana:` is refused | A grant naming any other namespace reverts at initialisation | +| An 8183 evaluator can tell whether the owner touched the wallet during a job | Checkpoint counter: every owner-door call, grant and revoke advances it, before the call; agent actions never do | The checkpoint suite, including three permanent tests | +## The permanent tests +Thirty-one tests across the build documents and suites are marked permanent — **never to be deleted or weakened**. The four below are the ones this table's universal promises rest on directly. The other twenty-seven pin promises made elsewhere in this document: the owner path surviving every degraded state; the two routing pins; the session validator calling nothing — both of its entry points are pure, so no external call can reach the agent check; the agent door never touching the owner's replay lanes; the owner door touching only the checkpoint slot; the checkpoint taken before each owner call; a withdrawal batched after a snapshot made visible; agent actions never moving the checkpoint; the enable-mode-is-dead test; the request-body length constant; the seven native-permission tests (the wallet and the engine refused as targets at grant, the wallet and the engine refused at dispatch, a gateway target refused as native, a non-gateway target refused as universal, the wildcard markers refused, and gate N3 proven live); URP's exact external-function set; the refusal to re-initialise a universal configuration that has no mode record; and the eight Solana-rulebook tests (forbidden programs refused at grant, and again at validation; the value-holding list must contain the destination account; vacuous or impossible data-pin values refused; a redirected destination token account refused; the price floor relative to the input; a value-holding account at an unpinned position refused; and the forbidden program ids pinned against their published base58 forms). Each is the only thing pinning a promise that some future refactor will be tempted to break: +1. **Address stability** — the factory's address math never changes. Breaking it strands counterfactually funded addresses, with no migration remedy in existence. +2. **The forbidden destination-account rule beats the allow-list** — remove this and one owner mistake (allow-listing their own far-chain account) hands the agent everything that account holds. On Solana the same rule covers the forbidden programs of gate S15. +3. **A request for a revoked permission fails after regrant** — remove this and a revoke-and-regrant could leave the old id usable against the new budget. +4. **The agent cannot reset counters** — remove this and the lifetime cap is advisory. +--- +# 9 · What this system does not protect against +Thirty-four accepted limits. Each is a deliberate choice, stated without softening. A builder who "fixes" one of these is reverting a decision, not fixing a bug. Where an open question could change one, it is named in plain words. +## Keys and people +1. **A stolen owner key drains the wallet completely.** Deliberate: any brake on the owner is also a lock-out of the owner. Defence belongs to the user's key-management and identity layer — and what that layer actually guarantees is itself still an open question (chapter 11). +2. **Nobody can act while the owner is unreachable.** No guardian, no emergency contact. Deliberate. The open question "should an emergency contact return?" would change this. +3. ~~Whoever holds a signed request may submit it.~~ **CLOSED.** The agent door admits only the permission's agent as the caller; there is no signed request for anyone else to hold. +## Timing +4. **Revocation cannot recall an instruction already in flight.** The window is bridge latency. Deliberate — physics of bridging. The revoke screen must disclose it. +5. **There is no ceiling on how far ahead a permission may expire.** The user's choice is respected as given. The residual is the agent acting late within the authorised window — never theft, never an amount or target the user did not allow. Deliberate. +## Budgets +6. **Replacing a permission starts its counters at zero — tightening a cap can increase remaining authority.** Deliberate: silent compensation was judged worse than an honest reset. The product must show prior consumption before a new cap is set. +7. **The lifetime cap bounds bridging, not redeployment.** Money already across can be redeployed endlessly until expiry. Deliberate — the cap is exposure-from-the-wallet; the expiry is the time bound. +8. **The adopted engine contains an owner-only counter reset that survives upstream.** Our tooling never calls it; the agent structurally cannot. Deliberate adoption cost, held by a permanent test. +9. **There is no deny-list, so an owner may allow-list a token-approval function** — which hands the agent spending power outside every cap. Deliberate: the model is allow-list-only, and the owner's list is the owner's responsibility. The open question "should the contract refuse approval-granting functions?" would change this. +10. **Until Push core's failure-reporting lands, a failed far-side action leaves the spent counter inflated.** Deliberate and *temporary*. Remedy meanwhile: revoke and regrant. +11. **A refund credit's amount cannot be verified by URP.** Trusted from Push core; damage bounded by once-per-id and never-below-zero. +12. **Gas is never credited back on failure.** The gas was genuinely consumed. Deliberate, with a rule that no credit path may ever touch a gas counter. +## Mechanics +13. **An EOA agent has one sequential nonce and no per-request expiry.** A stuck transaction blocks that agent's next one, and a broadcast transaction stays valid until it is mined or replaced. Bounded by the permission's own expiry and by revocation; a UEA agent's payloads carry the UEA's own nonce and a deadline. Deliberate: replay protection is the sender's own, and the wallet keeps none for agents. +14. ~~Two relayers racing the same request: the loser wastes its gas.~~ **CLOSED.** There are no relayers on the agent door: only the agent submits its own call. +15. **Policies run before the engine consults the session validator** — an adopted-engine ordering. The wallet has already checked the caller, but the standing constraint holds: every policy, forever, must be safe on arbitrary calldata from any caller. +## Platform inheritance +16. **The destination-account templates can be rotated by Push governance.** Accepted on admin trust; monitoring detects derivation changes; nothing on-chain prevents them. +17. **The destination-account factory is upgradeable — our address-verifiability guarantee is inherited, not owned.** Accepted: Push governance is our platform. +18. **A paused destination-account factory blocks a first outbound to a new chain.** Availability only; funds are never at risk. +## Permanence +19. **If the wallet's creation bytecode ever drifted, every pre-computed and pre-funded address would be stranded, with no remedy.** That is why the address-stability test is permanent and the address math is frozen forever. +20. **Deployed v3 wallets can never be migrated.** No upgrade path exists by construction. The open question "when does that stop being acceptable?" records the revisit trigger — nothing more. +21. **Adding any wallet-wide guard later means every user moves to a fresh wallet.** The direct consequence of shipping a validator-only wallet. The product obligation to walk users through far-chain balances exists for exactly this future. + +## Operations + +22. **The factory can be paused, which temporarily blocks new wallet creation.** A user who computed and funded a wallet address in advance cannot deploy it while the pause is on, so those funds are unreachable until it is lifted. **Availability only** — nothing is lost, no existing wallet is affected, and no deployed wallet can be frozen by anyone. Deliberate: it is the system's only incident lever, and its blast radius is limited to signups. + +23. **A misbehaving agent can burn the wallet's native gas balance in fees, within its caps.** Every action costs the wallet native gas up to the per-action ceiling, and a redeploy-only rules set lets an agent act repeatedly without ever moving the spend counter. Bounded by exactly two things: **the gas balance the owner funded, and the expiry.** Deliberate — the alternative is a second counter on a second asset, and the wallet's own funding is already the honest limit. Obligation 15 makes the number visible before the user commits. + +## The limits contract itself + +27. **URP is upgradeable, so whoever holds its proxy admin can rewrite every limit in this document.** This is the most powerful role in the system, and it is stated here rather than left to be discovered. What that role *can* do: replace URP's logic, and with it every gate, cap and pin described in `2_UniversalRulesPolicy.md`. What it *cannot* do: reach into a permission's stored configuration or its counters directly, or touch a wallet's funds — an existing permission keeps its caps until new logic says otherwise, and the owner door never consults URP at all. The trust anchors URP was initialised with (the gateway, the credit-back caller, the engine) have no setter; the only route to changing them is a full implementation swap. **Deliberate, and a genuine trade:** URP previously held those anchors in bytecode and needed no admin trust at all, but a policy that cannot be corrected is a policy whose first mistake is permanent — and its storage layout is frozen and append-only precisely so that a correction cannot silently reinterpret permissions already granted. The mitigation is procedural, not structural: the admin should be a multisig behind a timelock, so a change is visible before it lands. Until it is, this item reads exactly as written. + +## Native permissions + +24. **An unpinned argument guards nothing.** The native rulebook locks the words the owner pinned and nothing else; an argument the owner did not pin is the agent's to choose. Allow-listing a token approval without pinning the spender hands the agent that approval — the native form of the no-deny-list rule (item 9). Deliberate: the contract compares words, it does not understand functions. Obligation 16 makes the SDK refuse to emit the unpinned form. +25. ~~The kind the wallet was told and the kind URP recorded can disagree.~~ **CLOSED.** The premise was that the wallet never decodes URP's initialisation data. It now decodes exactly one field of it — the chain — and both contracts derive the kind from that same value, so there is nothing for them to disagree about and the grant event reports a derived fact rather than a claim. The narrow exception this required is bounded and stated in `2_UniversalRulesPolicy.md` §1.7: one field, read only after the policy has been proven to be URP's, used only to choose which shape rules apply. The terms themselves remain URP's sole business. +26. **A native call limit counts calls, not effects.** An action with a call limit of ten lets the agent spend those ten on calls that move nothing. Deliberate — the alternative, not counting a zero-value call, makes the limit bypassable by exactly such calls. Obligation 18 says so on the grant screen. + +## Solana permissions + +28. **An account pin bounds where value is delivered, not what an allow-listed program may take.** On Solana the destination account signs the whole call, and that authority carries into every call the target program makes on the accounts it is handed. The forbidden set guards the top-level target only. S18, the data pins and a fixed account count narrow what the program is handed; obligation 20 narrows which programs are allowed at all. The remainder is trust in the allow-listed program's code — and Solana programs are commonly upgradeable, the same class of trust as an EVM proxy. +29. **The loss ceiling on Solana is not the lifetime cap.** The caps meter what is bridged per request. Swap outputs, leftovers, and anything anyone sends to the destination account or its token accounts are reachable by any allow-listed program handed those accounts. The honest ceiling is the wallet's balance plus everything the destination account holds. Accounts the owner did not list as value-holding are not judged by S18 at all — deliberately: the list is the owner's statement of what is worth protecting. +30. **A price floor is policy without an oracle.** A ratio floor set at grant goes stale as the market moves — refusing honest trades in one direction, permitting worse ones in the other. Deliberate: URP holds no price feed and makes no external call at validation. The remedy is a regrant, and obligation 21 makes the cadence part of the grant. +31. **Rent is a leak.** A program that creates accounts with the destination account as payer spends its SOL. Not preventable by pins; bounded only by which programs the owner allows. +32. **Swap outputs stay on Solana until the owner brings them home.** Gate S5 pins the outbound token to the permission's listed assets, so the agent can repatriate only a listed asset, never what it bought. The owner door can repatriate anything. Deliberate. Whether listing the output token as a second asset is a safe remedy is open — see `docs/multi-asset-review.md`. + +## Checkpoints + +33. **The checkpoint counter is coarse.** Any owner-door call advances it, harmless or not; the wallet cannot tell whether an arbitrary call moved value. Deliberate. +34. **The checkpoint counter is blind to what needs no wallet call.** An allowance the wallet granted before a job's snapshot can be pulled without the owner touching the wallet, and plain transfers in never tick. The evaluator decides how to treat balances. Deliberate. +--- +# 10 · What the product must do that the contracts cannot +Twenty-three obligations. The contracts cannot check any of them; each names what goes wrong if it is skipped. **Twenty-one of the twenty-three currently have no test anywhere — this is the largest untested surface in the design, and it is the surface users actually experience.** +## The grant and change screens +1. **Argument positions for beneficiary checks are generated from each protocol's interface by tooling — never typed by hand.** A wrong position makes gate 15's beneficiary pin check the wrong bytes: the beneficiary pin silently guards nothing. +2. **Every newly supported protocol ships a rejection test** — a wrong beneficiary and an oversized amount must be shown to revert before that protocol is offered to users. This obligation is itself the test for the previous one. +3. **The destination account address is derived by tooling, never pasted, and the grant screen shows it — and whether it is deployed yet.** A pasted address puts the beneficiary pin under a typo's control. +4. **The grant screen gives the expiry the same prominence as the cap.** Users who see "100" but not "90 days" are authorising more time than they know. +5. **The grant screen shows the destination account's current idle balance.** The agent's instructions can use whatever sits there — the user should see the real exposure, not just the new budget. +6. **An unlimited cap is displayed unmistakably as unlimited — never as a huge number.** A number that means "no limit" printed as digits is a deception. +7. **On a change, show what the old permission consumed before the owner picks the new cap.** Without it, the counters-reset edge (chapter 9, item 6) catches owners silently. The change flow's stale-state assertion forces the tooling to read the old value anyway — showing it costs nothing. +8. **The change flow must never silently shrink the owner's chosen new cap to compensate for prior spend.** The reset is honest; a hidden adjustment would be a lie in the other direction. +9. **The revoke screen states that an already-dispatched instruction still completes.** Otherwise revocation reads as a guarantee it is not (chapter 9, item 4). +## Partners and operations +10. **Launch partners are told, before integration, that rotating an agent's key means a new agent address — revoking and regranting every permission naming the old one, counters resetting with it.** A partner who rotates keys casually will burn its users' budgets. +11. **The agent funds its own gas** — an EOA agent holds PC, a UEA agent's gas path is funded — separate from any wallet balance. If it runs dry, every user's agent stops at once: an outage, not a security event, but an outage the product owns. +12. **A user moving to a new wallet version is told their far-chain balances do not move automatically, and is walked through each one.** No tooling for this exists yet; until it does, this is a support-ticket generator (and chapter 9, item 21, is why it will happen). +13. **Monitoring compares each permission's committed destination address against the current derivation.** This is the detection half of the admin-trust acceptances (chapter 9, items 16–17): drift is caught by operations, or not at all. + +## Wallet creation + +14. **At wallet creation, the interface shows the destination-chain account address this wallet will have on each supported chain.** Every new wallet the user creates means a new account on every chain they may reach. If that cost is not shown before they commit, they discover it later — usually when they find balances stranded on a wallet they stopped using. + +## Gas funding + +15. **The grant screen states how much native gas token the wallet holds, and how many actions that funds at the chosen per-action gas ceiling.** The wallet spends its own gas balance on every cross-chain action — **including actions that bridge nothing**, which is the redeployment path. So the gas balance is a second, independent budget that no cap in the rules set bounds. A user who funds a wallet generously with gas and grants a long expiry has authorised more agent activity than the token caps alone suggest. + +## Native permissions + +16. **Argument pins are generated from the Push contract's interface by tooling — never typed by hand — and an approval-granting function is refused unless its spender argument is pinned.** A wrong pin position fails closed: the word will not match and every call reverts. A *missing* pin fails open: the argument is unchecked (chapter 9, item 24). The SDK is the layer that knows what a function means; the contract only knows what was pinned. +17. **The chain is stated once, and the tooling states it exactly as the asset reports it.** The kind is no longer a variable tooling can carry two copies of — it is derived, by both contracts, from the one chain string in the policy blob (`2_UniversalRulesPolicy.md` §1.7). What remains is a *transcription* obligation: for a universal permission the string must be byte-exact what the asset's own chain view returns, or the grant is refused at initialisation; for a native one it is this chain's own identifier. A near-miss such as a different letter case is not corrected — it derives the other kind and is refused against the targets. +18. **The native grant screen shows, per action, the contract, the function, every pinned argument in human terms, the value and amount caps, and the call limit — and states that a call limit is consumed by any successful call, including one that moves nothing.** Eight actions with eight pins each is the ceiling on what a user may be asked to approve at once; the ceiling exists so that this screen stays readable, not for gas. + +## Solana permissions + +19. **Program rules, account pins and data pins are compiled from the program's interface, fetched at grant — never typed by hand — and the interface's hash is recorded on the grant.** Rules are exact to one instruction and never share a data-pin set with a sibling instruction: two instructions with fields of the same widths at the same offsets can mean opposite things. Every value-carrying account — the authority, the source, every destination, every fee account — is pinned, and every fixed-layout instruction has its exact account count set. An instruction whose value-carrying accounts, input amount or minimum output cannot be identified from the interface, or whose scalar fields sit between two variable-length fields, is refused rather than approximated. A program upgrade that shifts an instruction's layout silently moves every pin measured from the end; the pins are re-verified after any upgrade of an allow-listed program. A missing pin fails open (chapter 9, item 28); URP's "every rule has a pin" check is hygiene, not completeness. +20. **An aggregator is allowed only through its shared-accounts instruction**, so that the inner legs run under the aggregator's own authority and the destination account is never handed to a downstream exchange as signer. The variants that put the user's intermediate token accounts in the account list are never allowed. Each aggregator card is gated on a fork test showing the aggregator refuses a substituted downstream program. +21. **Every swap rule carries a price floor relative to its input, a slippage ceiling, and a zero fee** — a ratio floor (or an exact input plus a floor), an at-most pin on slippage, an equal-zero pin on every fee field. A static floor on the output alone is beaten by raising the input. The grant screen states the floor as a price and the regrant cadence it implies (chapter 9, item 30). +22. **The destination account and its token accounts are derived by tooling from the wallet's address and the gateway program, and the gateway program is taken from the chain registry — never from user input.** The value-holding list is the destination account plus its token account for the asset and for every output token the permission allows. A pasted key puts every pin under a typo's control. +23. **Output token accounts exist before the agent needs them.** The gateway creates only the bridged token's account. Others are created off-band, or by allowing the associated-token program's idempotent create instruction in one exact shape — fixed account count, the owner position pinned to the destination account and the mint position pinned to one allowed output token, one rule per token. Never as an instruction-less rule, which would match the program's other instructions too. +--- +# 11 · Open questions, and what must not be "fixed" +## 11.1 The two items that gate implementation +These are facts to confirm, not decisions to make. Nothing else in this chapter blocks code — only the executor module's address still gates implementation. +- **RESOLVED — the Ed25519 precompile is no longer used by this system.** A Solana-keyed agent acts through its UEA, which verifies the key itself; the wallet verifies no signature. +- **The executor module's address.** Written in Push's platform code but unconfirmed against a live deployment. Confirm before URP hardcodes its one trusted caller. +## 11.2 Design questions for the team — none blocks v3 +- **Should the contract refuse approval-granting functions outright?** Would close chapter 9, items 9 and 24 — for a native permission, the unpinned-spender form. Today: allow-list-only, owner's responsibility, with the SDK refusing the unpinned form (obligation 16). +- **Should an emergency contact return to the design?** Would close chapter 9, item 2. +- **Should the destination and refund locks also exist at the gateway layer?** Our layer locks both regardless; a second lock would be belt-and-braces. +- **When does "no wallet migration, ever" stop being acceptable?** The recorded revisit trigger for chapter 9, item 20. +## 11.3 With Push core +- **The executor module must call URP on outbound failure.** The one piece of Push-core work the credit-back feature waits on. Not agentic-wallet work. +- **The destination account's own instruction loop is unbounded** in Push's code. Ours is bounded at ten; theirs should be bounded too. +- **The gateway's refund behaviour for the outbound direction** is undocumented in the public revert-handling notes (inbound only). Completeness of our exposure analysis, nothing more. +- **Two admin-only paths can pay an agent-chosen refund destination for funds coming back from a destination account.** Push Chain never issues an automatic refund for an inbound that originates at a destination account, so on every automatic path the agent's choice of refund destination is never used. But the stuck-inbound revert and the rescue path, both of which need an admin action, pay that destination without checking where the inbound came from. The agent cannot trigger either alone. The fix is node-side — for such inbounds, refund to the destination account of the originating Push account, or refuse — and is not URP work. +## 11.4 Conventions and text +- **A UEA agent's payload deadline: 15 minutes recommended.** A convention of the agent's own tooling, not a wallet rule — the wallet sees only the sender. +- **The identity layer's recovery guarantees are not yet enumerated.** They are the only defence against chapter 9, item 1. Not this system's work, but this system's users' exposure. +- **One sentence in the internal rules document still overclaims** that no counter reset exists anywhere; it must be narrowed to "no agent-reachable reset" (chapter 7.1 has the truth). +## 11.5 Do not "fix" these +Sixteen things in this design look like mistakes to a fresh reader. Each is a decision. Every implementation task touching one of these must carry this list. +1. **Gas is never credited back on a failed action** — and no refund path may touch a gas counter. The asymmetry is correct: the gas was consumed. +2. **There is no paymaster and none is planned.** Agents submit their own calls and pay their own gas. Do not add sponsorship. +3. **The empty-recipient pin (gate 11) guards a path the current far-side code does not even read.** It is defence in depth against that code changing. Do not remove it as "dead". On Solana the same field is required and is the target program (S11, S14) — the opposite rule for the same field is correct for each family. +4. **The forbidden-target rule compares against the destination account, and it beats the allow-list.** Not a bug that it overrides the owner's own list — the permanent test demands exactly that. +5. **Widening and narrowing a permission share one path: revoke and regrant.** There is no separate, "safer" narrow-only edit. Do not add one. +6. **The configured destination chain is stored but never compared at validation.** The chain is pinned transitively by the token. The unused field is known and documented (`2_UniversalRulesPolicy.md` §1.6), not forgotten. +7. **The wallet's refusal of itself and the engine as dispatch targets runs after validation, not before.** Placed earlier it would pre-empt the engine's own refusals and change which error surfaces, and the engine-as-target case is only reachable at all through the engine's wildcard, which validation has to resolve first. Two permanent tests pin its position; do not move it. +8. **A native call limit is consumed by a call that sends no value and meters nothing.** Not a metering bug. The universal counter ignores a zero-amount request because it counts bridging; the native call counter counts calls, and a limit zero-value calls could slip past would be advisory. +9. **A value-only native action accepts empty call data and nothing else.** The engine buckets one to three bytes under the same action id; URP refuses them by name. That is what value-only means, not overreach. +10. **URP's kind-specific getters revert on a record of the other kind, and return zeros on an empty slot.** Both halves are deliberate: an empty slot is a state, a wrong-kind read is a caller bug. The mode getter never reverts and is the first call for anything that does not already know the kind. +11. **Eight actions, eight pins, thirty-two allow-list entries are sanity bounds, not gas bounds** — and so are a Solana permission's thirty-two program rules, sixteen account pins, eight data pins and eight value-holding accounts. They cap what a human is asked to approve and audit at once. Raising any of them is a design change, not a tuning. +12. **The gateway program is a forbidden Solana target, although calling it is not a drain.** It returns the permission's asset to the owner's own wallet, and the agent's refund destination is never paid on that path. It stays forbidden because under a one-asset permission it can bring home only leftover input — never what the agent bought — while spending the owner's gas and inbound capacity for nothing. Outputs come home through the owner door. A permanent test refuses it at grant and at validation. +13. **URP refuses a Solana rule with no account pin, though a single pin proves nothing.** One authority pin always passes. The check is hygiene; completeness is the tooling's job (obligation 19). A test deliberately grants a rule with one useless pin and shows URP accepts it, so nobody reads the check as a guarantee. +14. **A Solana permission's value-holding list must contain the destination account.** That is what keeps gate S18 always on. Do not relax it to allow an empty list "for simple permissions" — an empty list switches the defence off silently. Permanent test. +15. **Two Solana rules that could match the same instruction are refused at grant, though first-match would simply pick one.** It would pick the first, and the second rule's pins would never run — an owner would believe they had granted limits that do not exist. +16. **The owner door writes one storage slot — the checkpoint.** That is the only exception to "the owner door touches nothing"; it consults nothing and cannot revert, and a permanent test pins that it touches slot 0 and nothing else. +--- +*End of the architecture document. The decision register holds the checkable form of every ruling above; the phase planning document holds the reasoning. Changes to this document follow the same rule as the system it describes: nothing is edited silently — a change names the ruling it implements.* diff --git a/plan/agw/research/deployment-review-2026-10-06/source/docs/2_UniversalRulesPolicy.md b/plan/agw/research/deployment-review-2026-10-06/source/docs/2_UniversalRulesPolicy.md new file mode 100644 index 00000000..b1909996 --- /dev/null +++ b/plan/agw/research/deployment-review-2026-10-06/source/docs/2_UniversalRulesPolicy.md @@ -0,0 +1,326 @@ +# UniversalRulesPolicy (URP) + +*The rules-policy chapter of the AGW architecture, kept as its own document. References to other chapters point to [`1_AGW.md`](1_AGW.md).* + +# 1 · URP — where the limits live +*URP — the Universal Rules Policy. One contract, three rulebooks: the **universal EVM** rulebook (§1.2–§1.4) descends from a v2 contract that has since been removed from the repository; the line references in those sections point into that removed file and are kept only as provenance for the reviewed logic URP reproduces. The **native** rulebook (§1.2b, §1.4b) and the **universal Solana** rulebook (§1.2c, §1.4c) are referenced by function name into `src/policies/UniversalRulesPolicy.sol`. **The authoritative specification is the contract itself, `src/policies/UniversalRulesPolicy.sol`, together with its test suite.** Every v3 extension to the universal rulebook is marked below.* +## 1.1 Why this contract exists +- The adopted permission engine identifies "what action is this?" by hashing **the target contract and the function being called on Push Chain**. +- But every agent action in this system is the *same* Push-side call: the wallet calling the gateway's send function. A market trade, a lending deposit, a transfer to a thief's address — **identical**, from the engine's point of view. +- The things the user actually cares about — which protocol, which function, whose benefit, how much — live *inside the call's data*, nested two layers deep, where the engine never looks. +- **URP is the contract that looks.** It is registered as the action policy for the one action that exists, and it unwraps the call data and checks everything inside — in the far chain's own format: an EVM instruction list for an EVM chain, a Solana instruction for Solana. Remove URP and the user's real limits are not enforced anywhere. That is why the engine's own floor — **at least one action policy per action** (`SmartSession.sol:285-299`) — combined with URP being that one policy, means the system fails closed: strip URP from a permission and the permission validates nothing at all, so every request dies. +- **For a native permission the blind spot is different, and smaller.** Here the engine's identity — the Push contract and the function — is exactly what the user cares about, so the engine itself already refuses a call to any contract or function the permission did not name. What the engine still cannot see is *how* the function is called: the arguments, the value attached, and how many times. URP's native rulebook checks those three. It is registered as the action policy on **each** of the permission's one to eight actions, and the fail-closed property is identical and per action: strip URP from any action and that action validates nothing. +- **URP decides which rulebook to run from a record it wrote at grant, not from the request.** §1.7 explains how that record is set, and why a request can never reach the wrong rulebook. +- Two wiring rules protect the fail-closed property. **Both are enforced in code, by the wallet's grant-shape check — a grant violating either one reverts:** +\t- **Never configure a fallback action policy** on an agent wallet. The engine supports a wildcard policy that catches unmatched actions; installing one would absorb requests that should die. For a universal permission this follows from the one-action shape; for a native permission the wallet refuses the engine's wildcard target and its two wildcard function markers **by name**, because the engine itself does not refuse the wildcard target at grant time (`1_AGW.md` chapter 7.1). +\t- **Never rely on the engine's other policy class** (checks on the outer operation) for anything mandatory — that class is allowed to be empty (`SmartSession.sol:237-247`). Everything mandatory lives in URP. +## 1.2 What URP stores — a universal permission's configuration (EVM chains) +Frozen at grant, per permission, written at initialisation: +| Field | Meaning | +| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| the tokens | One to eight PRC20s on Push (`assets`, at most `MAX_ASSETS`), each with its own caps and its own spent counter. No token twice. Every request must name one of them, **even at zero amount**: the token is what pins the destination chain — see §1.5. A permission with no token is refused at grant, on every grant path; a permission that should move nothing lists one token (the chain's gas token) with both limits at zero | +| per-action cap, per token | The most that one request may bridge in that token. Zero is legal: the token may route a request but never moves (the move-nothing permission) | +| lifetime cap, per token | The most that all requests together may bridge in that token. The largest representable number means unlimited; zero means nothing may move | +| PC-per-action cap | `maxGasPerCall`: the most native PC one request may carry — it pays the protocol fee and the gas swap, despite the name | +| the spent counters | One per token: the running total bridged in that token. Starts at zero. Money coming back to the wallet never lowers it | +| the expiry | The permission's end. Held **inside URP** so this one contract carries the complete mandatory set — no other policy needs to exist for the user to be safe | +| the destination account address | Computed and committed at grant. Everything must benefit this address | +| the allowed-calls list | Per entry: a far-chain contract address, a function on it, where that function's beneficiary argument sits, whether it has one, and a per-entry native-value cap. One to thirty-two entries | +## 1.2b What URP stores — a native permission's configuration, per action +A native permission holds one of these records **per action** — a permission with eight actions holds eight, each under its own action id. Frozen at grant, written at initialisation: +| Field | Meaning | +| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| the target | A defensive copy of the action's Push contract. The engine already routes by it; URP asserts it again at N4 so a mis-wired engine entry cannot pair one contract's rules with another's call | +| the function | A defensive copy of the action's function selector, asserted at N5. The value `0xFFFFFFFF` means **value-only**: a bare transfer of PC with **empty** call data — a function that merely takes no arguments is a normal four-byte selector, not value-only | +| the argument pins | Zero to eight. Each is a byte position in the call data — counted from byte zero, selector included, so 4 is the first argument — and the exact 32-byte word that must sit there. **Full-word equality**, so an address argument with anything in its upper twelve bytes is a mismatch, deliberately: the pin proves the padding is clean as well as the value | +| per-call value cap | The most native PC one call may carry | +| lifetime value cap | The most all calls together may carry. Largest number means unlimited | +| the value-spent counter | Running total of native PC sent. Starts at zero | +| the metered amount | Optional: on/off, a position in the call data read as a number, a per-call cap and a lifetime cap. Off is a flag, not "position zero" — position zero is a legal position, inside the selector | +| the amount-spent counter | Running total of the metered amount. Starts at zero | +| the call limit | How many successful calls the action permits. **Zero means unlimited** — the one cap in the system where zero is not "nothing" | +| the calls-used counter | Successful calls so far. **Moves on every successful call**, including one that sends no value and meters nothing | +| the expiry | The permission's end, held inside URP for the same reason as in the universal rulebook | +Two refusals happen at grant, not at validation: a native record may never name the gateway as its target, and a value-only record may carry neither pins nor a metered amount — such a record could never authorise anything, so it is a misconfiguration the owner believes they granted, not a valid strict one. +## 1.2c What URP stores — a universal permission's configuration (Solana) +Frozen at grant, per permission, written at initialisation. The first five fields mean exactly what they mean in §1.2; everything after them replaces §1.2's destination account and allowed-calls list: +| Field | Meaning | +| ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| the tokens | One to eight, with per-token caps and counters, exactly as in §1.2. Each pins the destination chain | +| per-action and lifetime caps | In the token's base units — on Solana, lamports or the SPL token's base units | +| PC-per-action cap | The most native gas value one request may carry | +| the spent counters | One per token, as in §1.2 | +| the expiry | The permission's end, held inside URP | +| the destination account | The 32-byte key of the wallet's Solana account, derived by tooling and committed by the owner. Never a valid target | +| the gateway program | The 32-byte id of the gateway program on the declared cluster, from the chain registry. Never a valid target | +| the program rules | One to thirty-two. Per rule: a program, an instruction tag (its leading one to eight bytes) or the marker that the instruction carries no data, and optionally the exact account count the instruction must have | +| the account pins | Up to sixteen. Per pin: which rule, which position in the account list, and the key that must sit there. Every rule must carry at least one, and a position may be pinned only once per rule | +| the data pins | Up to eight. Per pin: which rule, an offset — from the start or from the end of the instruction data — a width of one to eight bytes (up to thirty-two for equality), and a comparison: equal, at least, at most, or a minimum ratio to a second field at its own offset | +| the value-holding accounts | Up to sixteen destination-side accounts the owner declares worth protecting: the destination account itself, which must be present, one token account per listed token and up to seven swap-output accounts. Each may appear in a request only where the matched rule pins it; a listed account no rule pins can never be passed. URP cannot check that every listed token's account is here (it cannot derive Solana token accounts), so tooling must list them. Gas grows with the number listed: about 6,000 per extra account on a ten-account request | +Refusals at grant, each with its own named error: no program rule may name a program the rulebook forbids as a target (§1.4c, gate S15); two rules on one program may not both be able to match the same instruction — an instruction-less rule against another instruction-less rule, or one tag a prefix of the other — so the first-match lookup is always exact; a fixed account count may not exceed the request bound, and no pin may sit beyond it; a data pin may not sit on an instruction-less rule, and its comparison value must be one the field can actually fail — a ceiling above the field's range, a ratio with a zero numerator, or an equality value encoded in the wrong alignment is refused; and the value-holding list may not contain the zero key, a duplicate, or an allow-listed program, and must contain the destination account. + +**One input per instruction.** Because two rules may not match the same instruction, each (program, instruction) has exactly one rule, and each position one pinned key. If a swap rule pins its input to the USDC account, USDT can never be that instruction's input. Using several listed tokens through one instruction means leaving the input position unpinned and those token accounts off the value-holding list, so only the output and price pins protect them. Several tokens in one Solana permission work best when different tokens are used by different instructions. +**And, beside any of the three configurations, the mode record**: whether this permission's URP record exists at all, which kind it is, and — for a universal permission — which destination family. §1.7. +## 1.3 What URP opens +Each validation performs a **two-level unwrap**: +- **Level one — the gateway request.** URP decodes the wallet's call to the gateway: the token, the amount, the native value, the routing fields, and the payload. +- **Level two — the instruction list.** Inside the payload sits the destination account's instruction list: up to **ten** entries of *(target, value, data)*. URP walks **every** entry. One bad entry — even the last — kills the whole request. +- **For Solana, level two is one instruction, not a list.** URP parses the payload in exactly the byte grammar Push Chain's validators decode — a four-byte account count, that many 33-byte account entries, a four-byte data length, the instruction data, an instruction id and the target program — and requires it to be **consumed exactly**: a short field or a trailing byte is refused, so URP and the validators can never read the same bytes two ways. Every length is checked before the read it guards; the parse is bounded at sixty-four accounts and 1,024 bytes of instruction data. Writable flags are read past, never judged — a wrong flag fails on Solana, not here. +- **A native validation opens nothing.** The call is already flat. URP reads 32-byte words out of the call data at the positions the permission froze, and never decodes it as a structure — it does not know, and does not need to know, what the function's arguments mean. Every read is bounds-checked in 256-bit arithmetic, so a crafted position can neither wrap nor read past the end. +## 1.4 The universal gauntlet — every gate, in order (EVM chains) +Run for a universal permission whose destination family is EVM (`_checkUniversal`). Each gate: what it demands, and what it stops. Any failure reverts the whole request with nothing spent. +| # | Gate | Demands | Stops | +| --- | ----------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| 1 | **Configured** | This permission's configuration exists and is initialised (`:141`) | Requests against ghosts — ids never granted on this wallet | +| 2 | **Not expired** | The permission's own end date has not passed — **the expiry lives here, in URP** | Everything, after the deadline the user set. This is why URP alone is the complete mandatory set | +| 3 | **Gateway only** | The Push-side call target is the gateway, nothing else (`:143`) | The agent calling any Push contract directly — a token, the wallet, anything. The entire far-chain rulebook below is only sound because *everything* must pass through the gateway | +| 4 | **Send function only** | The gateway function is the outbound send, nothing else (`:145-147`) | Reaching any other gateway capability | +| 5 | **A listed token** | The bridged token is one of the permission's tokens — on **every** request, zero amount included | Spending any asset the user did not budget, and — because the gateway routes by the token — sending the permission's calls to a chain the user never approved | +| 6 | **Per-action cap** | Amount within **that token's** per-action cap | One oversized request | +| 7 | **Lifetime cap** | Amount plus everything already spent **in that token** within that token's lifetime cap | Death by a thousand cuts — many small requests. One token running out never limits another | +| 8 | **Gas-value cap** | Native PC attached within its cap (`:177`) | Draining the wallet's gas balance through the value field | +| 9 | **No uncapped gas swap** | The request's own gas-swap ceiling is non-zero *(v3 addition)* | An agent authoring the field's "no cap" value. The **owner** may set unlimited caps in the rules set; an **agent** may not author an unlimited request field | +| 10 | **Refunds come home** | The refund destination is the wallet itself (`:178-180`) | A "failed" transfer whose refund lands at the agent's address — failure as an exfiltration route | +| 11 | **No side recipient** | The bridged-funds recipient field is empty — funds may only travel with the instruction payload *(v3 addition)* | Any use of the gateway's direct-transfer mode. Defence in depth: the current far-side code ignores this field on the payload path, but URP does not lean on that staying true | +| 12 | **Instruction list only** | The payload is exactly a destination-account instruction list | Smuggling any other payload shape past the gates below | +| 13 | **At most ten** | Between one and ten instructions *(v3 constant)* | Unbounded lists that could exhaust validation gas | +| 14 | **No loopbacks** | No instruction may target the wallet, URP itself, the gateway — **or the destination account** (`:253-255`; the last is a v3 addition). **Checked before gate 15** | Self-calls and re-entry tricks; and — the v3 addition — the agent instructing the user's own account directly, which would hand it arbitrary control of everything that account holds. **This gate wins even if the owner allow-listed that address** — a permanent test pins exactly that | +| 15 | **The allow-list, and for the user only** | Every instruction's far-chain target *and* function appear in the allowed-calls list; and where the matched rule names a beneficiary argument, that argument equals the destination account (`:264-265`) | Everything. This is the only place in the entire system that checks the far-chain destination — and the beneficiary pin is what stops the agent trading honestly but making *itself* the beneficiary | +| 16 | **Per-entry value cap** | Each instruction's native value within its own cap | Value-draining through individual entries | + +> **There is no zero-amount gate.** v2 rejected a bridged amount of zero; v3 permits it, because that is the *redeployment* path — instructions travelling to capital already at the destination, with nothing new bridged. The counter correctly does not move. Without it an agent could buy but never sell. + +After every gate passes, URP **records the spend before the bridge is called** — effects first, so no ordering trick can spend twice against a stale counter. +## 1.4b The native gates — every gate, in order +Run only for a native permission (`_checkNative`). The same discipline as the universal gauntlet, for the same reason: this runs before the engine consults the session validator, on call data the engine has not yet authenticated. The wallet has already checked that the caller is the permission's agent, but URP does not rely on that. No external calls; every counter written last; any failure reverts the whole request with nothing spent. +| # | Gate | Demands | Stops | +| --- | ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| N1 | **Configured** | This action's native record exists and is initialised | Requests against ghosts — action ids never granted on this wallet | +| N2 | **Not expired** | The permission's end date has not passed — the expiry lives here, as in the universal rulebook | Everything, after the deadline the user set | +| N3 | **Never the gateway** | The call's target is not the gateway | The mirror of gate 3. A native permission cannot be written against the gateway (§1.2b), so on a permission the wallet created this cannot fire — it is defence in depth against a mis-wired grant, and a named test manufactures the state the wallet forbids to prove the gate is live | +| N4 | **The named contract** | The call's target equals the record's own copy of the target | A record reached through any action id but its own | +| N5 | **The named function** | The call's function equals the record's copy. Call data under four bytes counts as value-only — matching how the engine itself buckets short calls — and **a value-only call must carry empty call data, not one to three stray bytes** | Reaching any function but the one granted; and smuggling bytes under a value-only action | +| N6 | **Value caps** | Native PC attached within the per-call cap; attached plus everything already sent within the lifetime cap | Draining the wallet's PC through one large or many small calls | +| N7 | **The argument pins** | For every pin: the call data is long enough to hold the word at that position, and the word there equals the frozen value exactly | A beneficiary that is not the wallet; a spender that is not the intended contract; a pool id the owner did not choose; a correct address with dirty padding. **This is the only place a native call's arguments are checked**, and a missing pin is an unchecked argument (`1_AGW.md` chapter 9) | +| N8 | **The metered amount** | If the action meters an amount: the call data reaches it, the amount is within the per-call cap, and amount plus everything already metered is within the lifetime cap | Staking, approving, transferring or depositing more than the user allowed, per call or over the permission's life | +| N9 | **The call limit** | If the action has a limit: calls used so far are below it | The (n+1)th call — including a zero-value one, because every successful call counts | +After every gate passes, URP writes all three counters — value, amount, calls — **and only then**, so a request that fails at N9 has moved nothing at N6 or N8. It emits a metering event on every success, even when both value and amount are zero, because the call counter still moved. +**Every native error puts the value you debug with first.** The engine truncates a policy's revert data to 32 bytes — a selector plus 28 bytes of the first argument (`1_AGW.md` chapter 7.1). A native error therefore leads with the offending value (the word that did not match, the amount that was too large) rather than an index or a length, which would surface as zeros and tell nobody anything. The universal rulebook's errors predate this ordering and keep their reviewed shape; wallet errors are not truncated at all and do not follow it. +## 1.4c The Solana gauntlet — every gate, in order +Run for a universal permission whose destination family is Solana (`_checkSvm`). The same discipline as the other two: no external calls, the spend written last, any failure reverts the whole request with nothing spent. **Gates S1–S10 are gates 1–10 of §1.4, unchanged in meaning** — configured, not expired, gateway only, send function only, a listed token, the per-action cap, the lifetime cap, the gas-value cap, no uncapped gas swap, refunds come home — run against the Solana configuration. They do not depend on the far chain. From S11 on, the gates replace §1.4's 11–16: +| # | Gate | Demands | Stops | +| --- | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| S6b | **Fits Solana's amount** | The bridged amount fits in 64 bits — Solana's amount type | An amount the far side would truncate. Runs beside S6 | +| S11 | **Recipient is a program** | The recipient field is exactly 32 bytes and not zero | The inverse of gate 11: on Solana the recipient is required, and is the program to call. An address in any other form — including a base58 string — fails closed | +| S12 | **One well-formed instruction** | The payload is non-empty and parses exactly in the validators' grammar (§1.3) — no short field, no trailing byte | A funds-only outbound, and any payload URP and the validators could read differently | +| S13 | **Execute only, within bounds** | The instruction id is *execute*; at most sixty-four accounts and 1,024 bytes of instruction data | The *withdraw* form, which no rule below can inspect — the Solana counterpart of gate 12 — and unbounded parsing | +| S14 | **Recipient and target agree** | The program named in the payload equals the recipient field | An ambiguity in the far-side path: the validators sign over one and build the transaction from the other. Two different values fail on Solana at the owner's gas cost; URP refuses the shape instead | +| S15 | **Never a forbidden program** | The target is not the System program, SPL Token, Token-2022, Stake, the upgradeable BPF loader, the address lookup table program, **the gateway program, or the destination account**. **Checked before S16** | Direct drains: each of these, called with the destination account as signer, can move or burn what it holds. The gateway program routes funds back to Push and is refused for the reason in 11.5. **This gate wins even if the owner allow-listed the program** — grant refuses it too, and a permanent test pins both | +| S16 | **The allow-list — exact match** | The (program, instruction tag) matches a rule; an instruction-less rule matches only empty instruction data; and if the rule fixes an account count, the request has exactly that many | Every program and instruction the owner did not name. Because grant forbids two rules that could match the same instruction, the first match is the only match — a rule can never be reached by an instruction its pins were not written for | +| S17 | **Account pins and data pins** | Every account pin of the matched rule: the position exists and holds the frozen key. Every data pin: the instruction data reaches the field, and the field equals, meets the floor, stays under the ceiling, or meets the ratio | A destination that is not the user's token account, an authority that is not the destination account; a non-zero fee, an over-wide slippage, a price floor not met. **The ratio form is what a swap needs**: a static floor on the output is beaten by raising the input to the whole balance | +| S18 | **Value-holding accounts only where pinned** | Any account on the permission's value-holding list that appears anywhere in the account list sits at a position the matched rule pins | Handing the program the destination account's *other* balances as extra accounts. On Solana the destination account signs the whole call, so an account passed is an account the program may spend from. The list must contain the destination account, so this gate is never off | +> **There is no zero-amount gate here either.** A zero-amount request is the Solana counterpart of the redeployment path — one instruction acting on capital already at the destination — and the counter does not move. + +After every gate passes, URP **records the spend** — the same counter discipline as §1.4. +## 1.5 What URP counts +- **The spent counters** — one per listed token — advance by the bridged amount, before dispatch, and only count bridging — `1_AGW.md` chapter 4.2's "bridged, not deployed" rule lives here. **They count what was sent out, never what came back**: URP cannot see money arriving at the wallet, and could not tell an agent's return from the owner's top-up, so a limit of 1000 with 600 sent and 300 returned leaves 400. Everything in this section applies to EVM and Solana alike. +- **The credit-back** *(v3 addition — designed, not yet functional)*: when a far-side execution fails and Push Chain's executor module reports it, URP reduces the named token's spent counter by the failed amount (the module passes the token; a credit can never touch another token's counter). Three properties bound this path: +\t- **module-only** — a single fixed caller, Push Chain's own executor module, may invoke it; the agent cannot fabricate a failure; +\t- **idempotent** — each failed cross-chain transaction id credits at most once; a second credit for the same id reverts (a named test); +\t- **saturating** — the counter never goes below zero. +\t- One honest limit: URP cannot verify the *amount* the module hands it; it trusts Push core. Idempotency and saturation bound the damage of a wrong amount. This is an accepted limit (`1_AGW.md` chapter 9). +- **Gas is never credited.** A failed action's gas was genuinely consumed. **A refund credit must not move any gas counter** — a permanent rule with its own test. +- **A native action counts three things**, all written after every gate passes: native value sent, the metered amount if the action has one, and calls. There is no credit-back and nothing to credit: a native call either succeeds or reverts inside one Push transaction, and a revert unwinds every counter with it. The credit-back path refuses to run against a native record. +## 1.6 What URP deliberately does not do +- **No expiry-distance ceiling.** It rejects the expired; it never rejects the distant-future. The user's chosen horizon is respected as given. +- **No deny-list.** Nothing rejects a function by name. If an owner allow-lists a token-approval function, that is permitted — and hands the agent spending power outside every cap. The product must warn; the contract will not refuse. Gate S15's forbidden programs are the Solana form of gate 14's loopbacks, not an exception: on Solana the token programs *are* the destination account's balances, so calling them directly with its signature is instructing that account directly. (An open question records whether this should change — `1_AGW.md` chapter 11.) +- **No direct destination-chain check.** The configured chain is stored but not compared at validation. The chain is pinned *transitively*: the one allowed token is a Push-side mirror specific to one origin chain, so fixing the token fixes the chain. A builder who notices the stored-but-unchecked field has found a known fact, not a bug. +- **No opinion about the owner.** URP runs only on the agent door. The owner's door never meets it. +- **No verification of Solana keys.** The destination account, its token accounts and the gateway program are 32-byte keys the owner commits; URP cannot run Solana's address derivation and does not try. A wrong key fails closed — the pins never match. +- **No bound on what an allow-listed Solana program does inside its own call.** Account pins bound *where value is delivered*; they cannot bound what a program the owner allow-listed takes from the accounts it is handed, because the destination account's signature carries into every call that program makes. The forbidden set guards the top-level target only. S18, the data pins and the fixed account count narrow this; the rest is trust in the allow-listed program's code — the same trust an EVM allow-list already expresses (`1_AGW.md` chapter 9). +- **No reading of Solana writable flags.** A pinned account passed read-only fails on Solana, not here. +- **No understanding of native calls.** The native rulebook compares words at positions; it does not know what a function does. A pinned argument is locked; an unpinned one is the agent's to choose. So allow-listing a token approval without pinning its spender hands the agent that approval — the native form of the no-deny-list rule. The SDK refuses to emit an unpinned approval (`1_AGW.md` chapter 10); the contract will not. +## 1.7 Which rulebook — how the kind is fixed, and locked three ways +- **The chain travels inside URP's initialisation data, and the kind is derived from it.** The engine passes each policy an opaque blob at grant; URP's blob is a chain identifier followed by the configuration body. URP hashes the chain, compares it to this chain's own identifier — computed from the chain id, never configured — and derives the kind exactly as the wallet did, from the same bytes. An empty chain produces a named error; a blob in any other shape reverts rather than mis-decoding. +- **For a universal permission URP derives one more thing: the destination family.** It reads the chain's namespace — the first seven bytes, `eip155:` or `solana:` — and chooses the EVM or the Solana configuration body and rulebook accordingly. Any other namespace is refused at grant with a named error, so a permission for a chain URP has no rulebook for can never be granted and then fail every request. The kind still comes from the full chain hash; the family is a second, narrower classification inside the universal kind, and URP never asks it of a native chain. The wallet does not derive the family at all: both universal families look identical to it — one action, the gateway's send. +- **URP writes a mode record beside the configuration** — initialised, which kind, and for a universal permission which destination family — and consults that record on every validation. It does not infer the kind from the data's shape, and it does not trust the request. Universal is the record's zero value, so an *empty* record cannot be told from a universal one by its kind field alone; the initialised flag is what is authoritative, and the mode field is meaningless without it. EVM is likewise the family's zero value, so a universal record whose family was never written is an EVM one — which is what every such record is. +- **A permission initialised as one kind can never be re-initialised as the other, or as itself.** The re-initialisation refusal reads the mode record and, beneath it, the universal configuration — so a universal configuration written before its mode record existed is still recognised, and is still protected. URP is upgradeable behind a proxy and its storage is append-only: the universal configuration, the credit-back set, the mode record, the native configuration and the Solana configuration each hold their own slot, and a later implementation may add state only after them. +- **The wallet and URP cannot disagree about the kind, because neither one authors it.** Both derive it from the same chain string in the same blob, with the same rule. The wallet reads that one field — and only that field, only after it has proven the policy is URP's — to choose which shape rules to apply; it still never inspects the terms, which remain URP's sole business. There is therefore no second author for the two to disagree with, and the grant event now reports a derived fact rather than a claim. +- **Three further layers remain, as defence in depth.** Gate 3 requires a universal request to target the gateway. Gate N3 refuses a native request that does. Native initialisation refuses a gateway target outright. Between them there is no shape in which a gateway call reaches a native record, and none in which a native call reaches a universal one. +- **And for a universal permission the chain is checked against the money** — identically for both families, which is what makes a Solana permission over an EVM chain's asset impossible to grant. At initialisation URP asks the asset which chain it came from — the same view the gateway reads on every outbound to decide where to route — and refuses the grant if it disagrees with the declared chain, or if the asset cannot answer. Because every request then pins that same asset, one check at grant makes the declared chain true for the permission's whole life, with no external call at validation time. +- **The mode is readable.** A getter returns the mode record — kind, family and chain — and never reverts; it is the documented first call for anything that does not already know a permission's kind. The universal EVM, universal Solana and native getters each revert, with the actual kind or family named, when asked about a record of another shape — a wrong-kind read is a caller bug — and each returns an all-zero record for an empty slot, which is a state, not an error. +## Diagram — the full agentic flow, Push Chain to an EVM chain, every gate +```mermaid +flowchart TB + subgraph OFF["Off-chain"] + AG["Agent builds the request\ +and calls the agent door itself"] + end + subgraph PUSH["Push Chain — one transaction"] + DOOR["Wallet: agent door\ +caller must be the permission's agent"] + ENG["Permission engine: look up the permission,\ +run its policies"] + subgraph GAUNTLET["URP — the gauntlet (any failure: revert, nothing spent)"] + G1["1 configured?"] --> G2["2 NOT EXPIRED"] --> G3["3 gateway only"] + G3 --> G4["4 send function only"] --> G5["5 the one token"] --> G6["6 per-action cap"] + G6 --> G7["7 lifetime cap"] --> G8["8 gas-value cap"] --> G9["9 gas-swap field non-zero"] + G9 --> G10["10 refunds come home"] --> G11["11 recipient EMPTY"] --> G12["12 instruction list only"] + G12 --> G13["13 at most ten entries"] + G13 --> G14["14 no loopbacks —\ +not the wallet, not URP, not the gateway,\ +not the destination account · BEFORE the allow-list"] + G14 --> G15["15 the allow-list + beneficiary:\ +target + function every entry,\ +beneficiary = destination account"] + G15 --> G16["16 per-entry value cap"] + end + SIGN["Session validator LAST:\ +the sender is the permission's agent"] + SPEND["URP records the spend\ +(before the bridge)"] + GW["Gateway: pulls the token,\ +emits the cross-chain message"] + end + subgraph FARC["Destination chain"] + DA["Destination account\ +runs each instruction as the user"] + PR["Allowed protocol\ +(the only reachable far-chain code)"] + end + EXE["Push Chain's executor module"] + + AG --> DOOR --> ENG --> G1 + G16 --> SIGN --> SPEND --> GW --> DA --> PR + DA -. "far-side failure: funds return" .-> EXE + EXE -. "credit the spend back\ +(module-only · once per tx id · never below zero)\ +DESIGNED — NOT YET FUNCTIONAL" .-> SPEND +``` +## Diagram — the native flow, every gate +```mermaid +flowchart TB + subgraph OFF["Off-chain"] + AG["Agent builds the request — one flat call —\ +and calls the agent door itself"] + end + subgraph PUSH["Push Chain — one transaction, start to finish"] + DOOR["Wallet: agent door\ +caller must be the permission's agent"] + ENG["Permission engine: identify the action by\ +(contract, function) — an ungranted pair dies here"] + subgraph NGATES["URP — the native gates (any failure: revert, nothing spent)"] + N1["N1 configured?"] --> N2["N2 NOT EXPIRED"] --> N3["N3 never the gateway"] + N3 --> N4["N4 the named contract\ +(record's own copy)"] --> N5["N5 the named function\ +value-only = EMPTY call data"] + N5 --> N6["N6 value caps\ +per call · lifetime"] + N6 --> N7["N7 every argument pin:\ +in bounds · exact 32-byte word"] + N7 --> N8["N8 metered amount:\ +in bounds · per call · lifetime"] + N8 --> N9["N9 call limit\ +(every call counts)"] + end + SIGN["Session validator LAST:\ +the sender is the permission's agent"] + METER["URP writes value · amount · calls\ +(all three, after every gate)"] + GUARD["Wallet refuses the wallet or the engine\ +as target, whatever the verdict"] + NP["The named Push contract\ +called by the WALLET, as itself"] + RES["Position · shares · claim →\ +credited to the wallet. Done."] + end + + AG --> DOOR --> ENG --> N1 + N9 --> SIGN --> METER --> GUARD --> NP --> RES +``` +## Diagram — the Solana flow, every gate +```mermaid +flowchart TB + subgraph OFF["Off-chain"] + AG["Agent builds the request — one Solana instruction —\ +and calls the agent door itself"] + end + subgraph PUSH["Push Chain — one transaction"] + DOOR["Wallet: agent door\ +caller must be the permission's agent"] + ENG["Permission engine: look up the permission,\ +run its policies"] + subgraph SGATES["URP — the Solana gauntlet (any failure: revert, nothing spent)"] + S1["S1–S10 = gates 1–10\ +configured · NOT EXPIRED · gateway · send ·\ +token · caps · gas · refunds home"] --> S6b["S6b amount fits 64 bits"] + S6b --> S11["S11 recipient = a 32-byte program"] --> S12["S12 one instruction,\ +parsed exactly"] + S12 --> S13["S13 execute only · bounded"] --> S14["S14 recipient = target program"] + S14 --> S15["S15 never a forbidden program —\ +system, token, stake, loader, lookup table,\ +gateway program, destination account · BEFORE the allow-list"] + S15 --> S16["S16 the allow-list:\ +(program, tag) exact match · account count"] + S16 --> S17["S17 account pins + data pins\ +(source · destination · authority ·\ +fee · slippage · price floor)"] + S17 --> S18["S18 value-holding accounts\ +only where pinned"] + end + SIGN["Session validator LAST:\ +the sender is the permission's agent"] + SPEND["URP records the spend"] + GW["Gateway: pulls the token,\ +emits the cross-chain message"] + end + subgraph SOL["Solana"] + DA["Destination account\ +(gateway PDA of the wallet) receives the funds"] + PR["The one allow-listed program,\ +called with the destination account signing"] + end + EXE["Push Chain's executor module"] + + AG --> DOOR --> ENG --> S1 + S18 --> SIGN --> SPEND --> GW --> DA --> PR + DA -. "far-side failure: funds return" .-> EXE + EXE -. "credit the spend back\ +DESIGNED — NOT YET FUNCTIONAL" .-> SPEND +``` +## Diagram — when things fail +```mermaid +flowchart TB + REQ["Agent request submitted"] + V{"Validation on Push Chain\ +(the agent check, gates 1–16, S1–S18 or N1–N9,\ +expiry, the session validator)"} + REV["Whole transaction reverts.\ +Nothing bridged, nothing spent,\ +counters unwound.\ +The agent paid gas — nothing else happened."] + OK["Dispatched through the gateway.\ +Spend recorded. Token bridged."] + NOK["Native: the Push contract was called.\ +Value · amount · calls recorded.\ +Complete — nothing in flight, nothing to credit."] + F{"Far-chain execution"} + DONE["Instructions ran as the user's account.\ +Proceeds sit in the user's destination account\ +(on Solana, its pinned token accounts)."] + FAIL["Far side failed.\ +Funds return via Push infrastructure."] + CREDIT["Executor module reports the failure to URP →\ +spent counter credited back.\ +DESIGNED — NOT YET FUNCTIONAL.\ +Until it lands: counter stays inflated;\ +remedy is revoke + regrant.\ +Gas is never credited — it was consumed."] + + REQ --> V + V -- "any gate fails" --> REV + V -- "all pass · native" --> NOK + V -- "all pass · universal" --> OK --> F + F -- "succeeds" --> DONE + F -- "fails" --> FAIL --> CREDIT +``` diff --git a/plan/agw/research/deployment-review-2026-10-06/source/docs/5_SDK_Owner_Integration.md b/plan/agw/research/deployment-review-2026-10-06/source/docs/5_SDK_Owner_Integration.md new file mode 100644 index 00000000..264778d6 --- /dev/null +++ b/plan/agw/research/deployment-review-2026-10-06/source/docs/5_SDK_Owner_Integration.md @@ -0,0 +1,488 @@ +# AGW for the SDK — owner side + +What the SDK needs to create agentic wallets, grant and revoke rules, act as the owner, and read state, against the +**v4 deployment on Donut**. Owner side only: the agent side (`executeAsAgent`, building outbound requests) is out of +scope here. + +Everything below is taken from the deployed contracts (commit `e8db748`). ABIs: use the verified contracts on +[donut.push.network](https://donut.push.network), or the build artifacts in this repo (`out/.sol/.json`). + +--- + +## 1. The contracts the SDK talks to + +| Contract | Address (Donut, chain id `42101`) | What the SDK does with it | +|---|---|---| +| **AGWFactory** (proxy) | `0xaF88D0FD947afAe7bBb8F34e8417DCfc165e1aaF` | Predict, deploy and look up wallets | +| **AGW** (one per user) | address from `predictWallet` | Grant / revoke rules, owner actions, reads | +| **URP** (proxy) | `0x603E7f0aF6e1aAFf46DDfb28b1e99364f8BC59af` | Named inside every rule; read rule terms and spend | +| **SmartSession** (engine) | `0x165A5E6782f39D30B38c7D97e1303e4CB2aD102a` | Read only: list a wallet's rules | +| **AgentValidator** | `0x068EE2388475A98EE1f5a434C58bFF3444fffFe6` | Named inside every rule; never called | +| UniversalGatewayPC (Push core) | `0x00000000000000000000000000000000000000C1` | Named as the target of every cross-chain rule | +| UniversalCore (Push core) | `0x00000000000000000000000000000000000000C0` | Look up a chain's gas token (`gasTokenPRC20ByChainNamespace`) | + +`AGW.SESSION_ENGINE()`, `AGW.RULES_POLICY()`, `AGW.SESSION_VALIDATOR()` and `AGW.UNIVERSAL_GATEWAY_PC()` return the +engine, URP, validator and gateway a wallet expects. Prefer reading them from the wallet over hard-coding. + +## 2. Five terms + +- **Owner**: the Push address that owns a wallet (an EOA, or the UEA of an external key). Fixed at deploy. +- **Wallet (AGW)**: a small contract account. It holds the funds the agent may use; its balance is the hard ceiling. +- **Rule**: what one agent may do from one wallet. Granted by the owner, stored in the engine and URP, immutable once + granted. Identified by a `rulesId` (`bytes32`). +- **Agent**: the Push address a rule names (an EOA, or the UEA of an external key). Never the owner. +- **Checkpoint**: a counter on the wallet that moves on every owner-side action (owner calls, grants, revokes), never + on agent actions. Evaluators compare it before and after a job. + +--- + +## 3. Wallets: predict, fund, deploy + +### Predict + +```solidity +function walletCount(address owner) external view returns (uint256); // also the next index +function predictWallet(address owner, uint256 index) external view returns (address wallet, bool deployed); +``` + +The address depends only on `(owner, index)` and never changes, so it can be shown and **funded before deployment** +(PC and PRC20s sent to it are there when it deploys). The next wallet is `predictWallet(owner, walletCount(owner))`. +`index` may be at most `walletCount(owner)`: predicting further ahead reverts `IndexOutOfRange(index, next)`. + +### Deploy + +```solidity +function deployWallet(string calldata label) external returns (address wallet); // caller = owner +function deployWalletWithSig(OwnerIntent calldata intent, bytes calldata sig, string calldata label) + external returns (address wallet); // relayed, see §7 +``` + +- `deployWallet` makes **the caller** the owner; there is no owner parameter. +- `label` is emitted in `WalletDeployed`, **not stored** on-chain. Read it from events. +- Deploys revert while the factory is paused (`EnforcedPause`). + +### Look up + +```solidity +function isWallet(address account) external view returns (bool); +function ownerOf(address wallet) external view returns (address); // address(0) if not a factory wallet +function indexOf(address wallet) external view returns (uint256); // reverts NotAWallet for a non-wallet +``` + +To list an owner's wallets: indices `0 .. walletCount(owner)-1` through `predictWallet`, or the `WalletDeployed` +events filtered by `owner`. + +--- + +## 4. Granting a rule + +```solidity +function grantRules(Session calldata session) external returns (bytes32 rulesId); // owner, or the wallet itself +``` + +One call grants one rule. A rule is a **`Session`** (the engine's struct) whose one policy is URP, carrying the terms +in an **envelope**. + +### 4.1 The Session, field by field + +```solidity +struct Session { + address sessionValidator; // AgentValidator 0x068E…FfFe6 (must equal wallet.SESSION_VALIDATOR()) + bytes sessionValidatorInitData; // abi.encode(address agent), agent != address(0) + bytes32 salt; // anything; the wallet overwrites it with its grant nonce + PolicyData[] userOpPolicies; // MUST be empty + ERC7739Data erc7739Policies; // MUST be empty: { allowedERC7739Content: [], erc1271Policies: [] } + ActionData[] actions; // see below + bool permitERC4337Paymaster; // MUST be false +} +struct PolicyData { address policy; bytes initData; } +struct ActionData { bytes4 actionTargetSelector; address actionTarget; PolicyData[] actionPolicies; } +struct ERC7739Data { ERC7739Context[] allowedERC7739Content; PolicyData[] erc1271Policies; } +struct ERC7739Context { bytes32 appDomainSeparator; string[] contentNames; } +``` + +Every action has **exactly one** policy: `{ policy: URP, initData: }`. Anything else reverts +`MalformedSessionShape`. + +Actions by rule kind: + +| Kind | `actions` | +|---|---| +| **Cross-chain** (EVM or Solana destination) | Exactly 1 action: `actionTarget = UniversalGatewayPC`, `actionTargetSelector = 0x77b86bec` (the gateway's `sendUniversalTxOutbound`) | +| **Native** (Push-side calls) | 1 to 8 actions, one per `(target, selector)` the agent may call; no duplicates; every action's envelope names the same chain | + +The **kind is never declared**: it is derived from the envelope's chain string. This chain (`"eip155:42101"`) means +native; any other `eip155:` or `solana:` chain means cross-chain. + +### 4.2 The envelope (`initData` of the URP policy) + +```solidity +initData = abi.encode(uint16 version, string chainNamespace, bytes body) +``` + +- `version` = **1** (`ENVELOPE_VERSION`). Anything else is refused (`UnsupportedEnvelopeVersion`). +- `chainNamespace`: CAIP-2 string, byte-exact. Destination chain for cross-chain rules (e.g. `"eip155:11155111"`, + `"solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1"`); `"eip155:42101"` for native rules on Donut. + (`URP.pushChainHash()` returns `keccak256("eip155:42101")` if you want to confirm.) +- `body`: `abi.encode(UniversalTerms)`, `abi.encode(SvmTerms)` or `abi.encode(NativeTerms)`, by kind. + +### 4.3 Cross-chain rule, EVM destination: `UniversalTerms` + +```solidity +struct UniversalTerms { + uint48 validUntil; // unix seconds, in the future; "never" = type(uint48).max + address expectedCEA; // the wallet's account on the destination chain + AssetCap[] assets; // 1..8 tokens the agent may move + uint256 maxGasPerCall; // PC (wei) the wallet may spend per outbound (protocol fee + gas) + AllowedCall[] allowedCalls; // 1..32 destination-chain calls the agent may make +} +struct AssetCap { + address token; // PRC20 ON PUSH (e.g. USDC.eth), never the destination chain's address + uint256 maxPerCall; // per request; 0 = this token can never move + uint256 maxTotal; // lifetime amount sent out; type(uint256).max = unlimited; 0 = nothing +} +struct AllowedCall { + address target; // destination-chain contract + bytes4 selector; // destination-chain function + uint16 beneficiaryOffset; // byte offset of the beneficiary argument: 4 + 32 * argIndex + bool hasBeneficiary; // if true, that argument must equal expectedCEA + uint256 maxValue; // native value per call, in DESTINATION-chain units; 0 = non-payable +} +``` + +ABI tuple: `(uint48,address,(address,uint256,uint256)[],uint256,(address,bytes4,uint16,bool,uint256)[])` + +Rules the contracts enforce at grant (each with a named error, §10): + +- **At least one token, at most 8, no duplicates.** A rule with no token is refused (`AssetListOutOfRange(0)`): the + gateway picks the destination chain from the request's token, so a rule without a token has no chain. +- **Every token's chain must equal the rule's chain**: URP calls `token.SOURCE_CHAIN_NAMESPACE()` and compares + (`ChainMismatch`, `InvalidAsset`). It checks the chain, **not which token**, so picking the right PRC20 is the SDK's job. +- `expectedCEA` non-zero; `allowedCalls` 1..32; `validUntil` non-zero and in the future. + +What the SDK has to resolve: + +- **Token → PRC20**: users give the destination chain's token (e.g. `MOVEABLE.TOKEN.ETHEREUM_SEPOLIA.USDC`); convert + with `PushChain.utils.tokens.getPRC20Address(...)` and confirm `SOURCE_CHAIN_NAMESPACE()` equals the rule's chain. +- **A rule that moves no tokens**: the contracts refuse an empty list, so the SDK adds the destination chain's gas + token with both limits at 0: `UniversalCore.gasTokenPRC20ByChainNamespace(chain)` (Sepolia: pETH + `0x2971824Db68229D087931155C2b8bB820B275809`). Add it only when the user lists no token, or it would duplicate. +- **"No total limit"**: encode `maxTotal = type(uint256).max`. Do not encode 0; 0 means nothing may move. +- **`expectedCEA`**: the wallet's CEA on the destination chain, from that chain's CEA factory: + `getCEAForPushAccount(walletAddress) returns (address cea, bool isDeployed)`. +- **`beneficiaryOffset`**: from the function ABI, `4 + 32 * argIndex` (e.g. Aave `supply(address,uint256,address,uint16)`, + `onBehalfOf` is argument 2, offset 68). + +One rule may list several tokens and several protocols. Limits are **per token**; there is no combined limit across +tokens, and every listed token may be used with every allowed call. Different scopes need separate rules. + +### 4.4 Cross-chain rule, Solana destination: `SvmTerms` + +```solidity +struct SvmTerms { + uint48 validUntil; + bytes32 expectedCEA; // PDA(["push_identity", wallet], gatewayProgram) + bytes32 gatewayProgram; // the Push gateway program on that cluster (from the chain registry) + AssetCap[] assets; // 1..8, same as §4.3; request amounts must fit u64 + uint256 maxGasPerCall; + bytes32[] ceaAccounts; // the CEA's value-holding accounts, max 16, MUST include expectedCEA + AllowedProgram[] programs; // 1..32 allowed (program, instruction) pairs + SvmAccountPin[] pins; // max 16 account pins + SvmDataPin[] dataPins; // max 8 instruction-data pins +} +struct AllowedProgram { bytes32 program; bytes8 discriminator; uint8 discriminatorLen; bool dataless; uint8 maxAccounts; } +struct SvmAccountPin { uint8 ruleIndex; uint8 accountIndex; bytes32 expected; } +struct SvmDataPin { uint8 ruleIndex; bool fromEnd; uint16 offset; uint16 offsetB; uint8 len; + uint8 mode /* 0 EQ, 1 GTE_LE, 2 LTE_LE, 3 RATIO_GTE_LE */; bytes32 expected; uint64 num; uint64 den; } +``` + +What the SDK must get right (all checked at grant, named errors): + +- `ceaAccounts`: the CEA plus **the CEA's token account for every listed token** and any swap-output accounts. URP + cannot derive Solana token accounts, so it cannot check this; an unlisted account is unprotected. +- **One rule per (program, instruction).** Each position takes one pinned key, so if a swap rule pins its input to the + USDC account, USDT cannot be that instruction's input. Plan Solana rules so different tokens use different instructions. +- Every program rule needs at least one account pin; `discriminatorLen` is 1..8, or 0 exactly when `dataless`. +- System, SPL Token, Token-2022, Stake, the upgradeable loader, the lookup-table program, the gateway program and the + CEA itself can never be allowed programs. + +Field-level detail: `docs/2_UniversalRulesPolicy.md` §1.2c. + +### 4.5 Native rule (Push-side calls): `NativeTerms`, one per action + +```solidity +struct NativeTerms { + uint48 validUntil; + address target; // MUST equal this action's actionTarget + bytes4 selector; // MUST equal this action's actionTargetSelector; 0xFFFFFFFF = plain PC transfer + uint256 maxValuePerCall; // PC (wei) per call + uint256 maxValueTotal; // lifetime PC; type(uint256).max = unlimited + AmountRule amount; // optional metering of one uint256 argument + uint32 maxCalls; // 0 = unlimited + ArgPin[] pins; // 0..8 arguments that must equal a fixed word +} +struct AmountRule { bool enabled; uint16 offset; uint256 maxPerCall; uint256 maxTotal; } +struct ArgPin { uint16 offset; bytes32 expected; } // offset counts from byte 0, selector included: 4 = first argument +``` + +ABI tuple: `(uint48,address,bytes4,uint256,uint256,(bool,uint16,uint256,uint256),uint32,(uint16,bytes32)[])` + +- `target`/`selector` must match the action they sit in. The contracts do not cross-check at grant, and a mismatch + makes the rule unusable. +- Targets that can never be granted: the gateway (use a cross-chain rule), the wallet, the factory, the engine, URP, + the validator, `address(0)`, `address(1)`. +- A plain PC transfer (`0xFFFFFFFF`) carries no pins and no amount rule. + +### 4.6 The `rulesId` + +`grantRules` returns it, and `RulesGranted(rulesId, …)` carries it. It is also predictable before sending: + +``` +rulesId = keccak256(abi.encode(address sessionValidator, bytes sessionValidatorInitData, bytes32(grantNonce))) + // grantNonce = wallet.grantNonce() at the moment of the grant; it advances by 1 on every grant +``` + +Equivalently, call `SmartSession.getPermissionId(session)` with `salt = bytes32(grantNonce)`. Ids never repeat, even +for byte-identical rules granted twice. + +### 4.7 Encoding a cross-chain rule (viem) + +```ts +import { encodeAbiParameters, parseAbiParameters, parseEther, maxUint256, zeroHash } from 'viem'; + +const terms = encodeAbiParameters( + parseAbiParameters('(uint48,address,(address,uint256,uint256)[],uint256,(address,bytes4,uint16,bool,uint256)[])'), + [[validUntil, expectedCEA, + [[USDC_ETH, 100_000000n, 1000_000000n], [USDT_ETH, 50_000000n, maxUint256]], + parseEther('1'), + [[aavePool, '0x617ba037', 68, true, 0n], [usdcSepolia, '0x095ea7b3', 0, false, 0n]]]], +); +const initData = encodeAbiParameters(parseAbiParameters('uint16, string, bytes'), [1, 'eip155:11155111', terms]); + +const session = { + sessionValidator: wallet.SESSION_VALIDATOR, // 0x068E…FfFe6 + sessionValidatorInitData: encodeAbiParameters([{ type: 'address' }], [agent]), + salt: zeroHash, + userOpPolicies: [], + erc7739Policies: { allowedERC7739Content: [], erc1271Policies: [] }, + actions: [{ + actionTargetSelector: '0x77b86bec', // gateway sendUniversalTxOutbound + actionTarget: '0x00000000000000000000000000000000000000C1', // UniversalGatewayPC + actionPolicies: [{ policy: URP, initData }], + }], + permitERC4337Paymaster: false, +}; +// wallet.grantRules(session), from the owner +``` + +--- + +## 5. Revoking and replacing rules + +```solidity +function revokeRules(bytes32 rulesId) external; // owner, or the wallet itself; UnknownPermission if not live +function revokeAllRules() external; // owner, or the wallet itself +``` + +Revocation is immediate on Push and cannot be blocked. An outbound already sent across the bridge still completes. + +**Rules are immutable.** To "update" one, the owner sends **one batch through the owner door** (§6): + +1. `URP.assertSpent(configId, wallet, expectedSpent)` — reverts if the agent spent since the SDK read the counters; +2. `wallet.revokeRules(oldRulesId)`; +3. `wallet.grantRules(newSession)`. + +If step 1 reverts, nothing changes. Counters start at zero on the new rule. `assertSpent` forms: + +```solidity +// cross-chain (EVM or Solana): one expected value per listed token, IN THE ORDER THE RULE LISTED THEM +function assertSpent(ConfigId id, address account, uint256[] calldata expectedSpent) external view; +// native: per action +function assertSpent(ConfigId id, address account, uint256 expectedValueSpent, uint256 expectedAmountSpent, uint32 expectedCalls) + external view; +``` + +--- + +## 6. The owner door: `execute` + +```solidity +function execute(bytes32 mode, bytes calldata executionCalldata) external payable; // owner only +``` + +The owner acts as the wallet with **no rule checked**: withdraw, approve, call anything, or call the wallet's own +`grantRules` / `revokeRules` in a batch. + +| | `mode` | `executionCalldata` | +|---|---|---| +| Single call | `0x0000…00` (32 zero bytes) | `abi.encodePacked(address target, uint256 value, bytes callData)` | +| Batch | `0x01` followed by 31 zero bytes | `abi.encode(Execution[])`, `Execution = (address target, uint256 value, bytes callData)` | + +Other modes (delegatecall, try) revert `UnsupportedExecutionMode`. Every call in an owner action records one +checkpoint. Withdraw PC: single call to the destination address with `value = amount, callData = 0x`. Withdraw a +token: single call to the token with `transfer(to, amount)`. + +--- + +## 7. Relayed owner actions: `OwnerIntent` + +For owners who sign but do not send (a Push EOA without gas, or a relayer-driven flow). The owner signs one EIP-712 +`OwnerIntent`; the named `executor` submits it. + +```solidity +struct OwnerIntent { + address owner; // the wallet owner + address wallet; // the wallet (its predicted address if not deployed yet) + address executor; // the ONLY address allowed to submit this intent + uint96 index; // deploy: must equal factory.walletCount(owner) + bytes32 sessionHash; // grant: keccak256(abi.encode(session)) of the session AS SUBMITTED; 0 = no grant + bytes32 mode; // execute: the mode word + bytes32 execCalldataHash; // execute: keccak256(executionCalldata); 0 = no execute + uint192 nonceKey; // execute: lane key; the top bit (1 << 191) MUST be set + uint64 nonceSeq; // execute: must equal wallet.getNonce(nonceKey) + uint64 grantNonce; // grant: must equal wallet.grantNonce() + uint48 deadline; // unix seconds; every door rejects after it + uint256 signerChainId; // the chain id the owner's wallet signs under (their home chain) +} +``` + +EIP-712 type string (fields in this order): + +``` +OwnerIntent(address owner,address wallet,address executor,uint96 index,bytes32 sessionHash,bytes32 mode,bytes32 execCalldataHash,uint192 nonceKey,uint64 nonceSeq,uint64 grantNonce,uint48 deadline,uint256 signerChainId) +``` + +Domain: `name "AGWFactory"`, `version "1"`, `chainId = signerChainId`, `verifyingContract = factory proxy` +(`0xaF88…1aaF`, also for wallet doors), `salt = bytes32(uint256(42101))`. Check the local derivation against +`factory.domainSeparator(signerChainId)` (or `wallet.domainSeparator(...)`, identical) before prompting. + +| Door | Contract | Fields it checks | +|---|---|---| +| `deployWalletWithSig(intent, sig, label)` | factory | `owner`, `index`, `wallet` (= predicted), `executor`, `deadline` | +| `grantRulesWithSig(session, intent, sig)` | wallet | `wallet`, `owner`, `executor`, `deadline`, `sessionHash`, `grantNonce` | +| `executeWithSig(mode, executionCalldata, intent, sig)` | wallet | `wallet`, `owner`, `executor`, `deadline`, `mode`, `execCalldataHash`, `nonceKey`, `nonceSeq` | + +- **One signature can cover all three doors**: each door checks only its own fields, and each is single-use (deploy: + the index advances; grant: the grant nonce advances; execute: the lane sequence advances). +- **Several rules in one signature**: put a batch of the wallet's own `grantRules` calls in `executeWithSig` + (`grantRulesWithSig` grants exactly one). +- `executeWithSig` is **not payable**; value comes from the wallet's balance. +- Signature check: an owner with no code is verified by ECDSA; a contract owner by its UEA method + (`verifyUniversalPayloadSignature`), then ERC-1271. A **Solana-key owner's UEA must already exist on Push** before + its first signed intent. +- If the owner calls `deployWalletWithSig` directly, no signature is needed. + +--- + +## 8. "Create a wallet with rules" in practice + +| Owner | How | +|---|---| +| **UEA** (external key) | One UEA multicall, one signature: `factory.deployWallet(label)` then `predictedWallet.grantRules(session)` per rule. | +| **Push EOA**, sends its own txs | Two transactions: `factory.deployWallet(label)`, then `wallet.execute(batch of wallet.grantRules(...))`. | +| **Push EOA via a relayer** | One signature: an `OwnerIntent` with the deploy fields plus an execute batch of self-grants. The relayer sends `deployWalletWithSig`, then `executeWithSig`. | + +Fund the wallet with PC (for the agent's per-call fees) and the tokens the rules allow, at its address, before or after +deployment. + +--- + +## 9. Reading state + +| To get | Call | +|---|---| +| A wallet's live rules | `SmartSession.getPermissionIDs(wallet)` → `bytes32[]` | +| Is a rule live | `SmartSession.isPermissionEnabled(rulesId, wallet)` | +| The rule's agent | `wallet.agentOf(rulesId)` (zero if revoked or unknown) | +| Kind, VM family, chain | `URP.getMode(configId, wallet)` → `{initialized, mode (0 cross-chain, 1 native), vm (0 EVM, 1 Solana), chainHash}` | +| Cross-chain EVM terms + spend | `URP.getConfig(configId, wallet)` → `{initialized, validUntil, expectedCEA, maxGasPerCall, assets[], allowedCalls[]}`, each asset `{token, maxPerCall, maxTotal, spent}` | +| Solana terms + spend | `URP.getSvmConfig(configId, wallet)` (same `assets[]` with `spent`) | +| Native terms + spend | `URP.getNativeConfig(configId, wallet)` → `{…, valueSpent, amountSpent, callsUsed, …}` | +| Checkpoints | `wallet.checkpointCount()`, `wallet.lastCheckpointBlock()`, `Checkpointed` events | +| Owner / factory | `wallet.owner()`, `wallet.factory()` | +| Next grant nonce | `wallet.grantNonce()` | +| Owner lane position | `wallet.getNonce(nonceKey)` | + +**`configId`** (the key URP reads take), per action: + +``` +actionId = keccak256(abi.encodePacked(address target, bytes4 selector)) +actionPolicyId = keccak256(abi.encodePacked(bytes32 rulesId, actionId)) +configId = keccak256(abi.encodePacked(address wallet, actionPolicyId)) +``` + +- Cross-chain rule: one action, `target = UniversalGatewayPC`, `selector = 0x77b86bec`, so the `configId` follows from + `rulesId` alone. +- Native rule: one `configId` per action; use each action's `(target, selector)` from the session the SDK built (or + decode the grant transaction's input). +- `getConfig` reverts `WrongModeForCall` / `WrongVmForCall` if called on the wrong kind; call `getMode` first when + unsure. An empty slot returns a zeroed struct. +- `spent` counts what was **sent out**. Money coming back to the wallet does not lower it. + +The contracts do not enforce one rule per agent per chain. A wallet can hold several rules for the same agent and +chain, so a lookup by `(agent, chain)` can return more than one. + +--- + +## 10. Events + +| Contract | Event | Notes | +|---|---|---| +| Factory | `WalletDeployed(address indexed owner, uint256 indexed index, address indexed wallet, string label)` | The only place `label` lives | +| Wallet | `AccountInitialized(address indexed owner, address indexed engine)` | Emitted once at deploy | +| Wallet | `RulesGranted(bytes32 indexed rulesId, uint8 mode, bytes32 indexed chainHash, string chainNamespace)` | `mode`: 0 cross-chain, 1 native | +| Wallet | `RulesRevoked(bytes32 indexed rulesId)` | Once per revoked id | +| Wallet | `OwnerExecuted(bytes32 indexed mode, bytes32 executionCalldataHash)` | `execute` | +| Wallet | `OwnerExecutedWithSig(bytes32 indexed mode, bytes32 executionCalldataHash, uint192 nonceKey, uint64 nonceSeq)` | `executeWithSig` | +| Wallet | `Checkpointed(uint64 indexed seq, uint8 kind, bytes32 ref, uint64 blockNumber)` | `kind`: 0 owner action (`ref` = `keccak256(abi.encode(target, value, callData))`), 1 rules granted, 2 rules revoked (`ref` = `rulesId`) | +| Wallet | `RulesActionAuthorized(bytes32 indexed rulesId, address indexed agent, bytes32 callsHash)` | An agent action passed (agent side) | +| URP | `OutboundMetered(bytes32 indexed id, address indexed multiplexer, address indexed account, address token, uint256 amount)` | A cross-chain spend was counted | +| URP | `NativeCallMetered(bytes32 indexed id, address indexed multiplexer, address indexed account, uint256 value, uint256 amount)` | A native call was counted | + +--- + +## 11. Errors the owner side can hit + +All are custom errors with arguments; decode with the contract ABIs. URP errors raised during a grant reach the caller +in full (they come through the wallet). + +| When | Errors | +|---|---| +| **Deploy** | `IndexMismatch(expected, provided)`, `IntentWalletMismatch`, `ExecutorMismatch`, `SignatureExpired`, `InvalidOwnerSignature`, `EnforcedPause` | +| **Grant: session shape** (wallet) | `MalformedSessionShape`, `TooManyActions(n)`, `DuplicateAction(target, selector)`, `ForbiddenActionTarget(target)`, `ForbiddenActionSelector(selector)`, `RulesTypeMismatch(mode, actionIndex, target)`, `EmptyChain`, `InconsistentChain(actionIndex)`, `CallerIsNotOwner` | +| **Grant: envelope** (URP) | `UnsupportedEnvelopeVersion(firstWord)`, `EmptyChain`, `UnsupportedNamespace(chainHash)` (chain is neither `eip155:` nor `solana:`; declared in `PushChainLib`) | +| **Grant: cross-chain terms** (URP) | `AssetListOutOfRange(length)`, `DuplicateAsset(token)`, `InvalidAsset(token)`, `ChainMismatch(declared, assetChain)`, `InvalidConfigField`, `AllowListOutOfRange(length)`, `InvalidExpiry(validUntil)` | +| **Grant: Solana terms** (URP) | `InvalidSvmConfigField`, `ProgramListOutOfRange`, `TooManySvmPins`, `TooManySvmDataPins`, `TooManyCeaAccounts`, `DiscriminatorLenOutOfRange`, `AmbiguousRule`, `ForbiddenProgramInAllowList`, `SvmPinRuleOutOfRange`, `SvmPinIndexOutOfRange`, `SvmMaxAccountsOutOfRange`, `DuplicateSvmPin`, `InvalidCeaAccount`, `CeaAccountsMissExpectedCEA`, `SvmDataPinInvalid`, `RuleWithoutPin` | +| **Grant: native terms** (URP) | `NativeTargetZero`, `NativeTargetIsGateway`, `TooManyPins`, `ValueOnlyWithPins`, `ValueOnlyWithAmountRule`, `InvalidExpiry` | +| **Revoke** | `UnknownPermission(rulesId)`, `CallerIsNotOwner` | +| **Update batch** | `AssetSpentMismatch(token, expected, actual)`, `SpentLengthMismatch(expected, actual)`, `SpentMismatch(expected, actual)` (native), `NotInitialized`, `WrongModeForCall` | +| **Owner door / signed doors** | `CallerIsNotOwner`, `UnsupportedExecutionMode`, `MalformedBatchCalldata`, `OwnerSigExpired`, `IntentWalletMismatch`, `ExecutorMismatch`, `InvalidOwnerSignature`, `IntentSessionMismatch`, `IntentGrantNonceMismatch`, `IntentExecMismatch`, `OwnerLaneRequired`, `InvalidNonce` | +| **Reads** | `WrongModeForCall(actual)`, `WrongVmForCall(actual)`, `NotAWallet(account)`, `IndexOutOfRange(index, next)` | + +A call made inside an owner action that reverts bubbles its own revert data up unchanged. + +--- + +## 12. Limits + +| Limit | Value | +|---|---| +| Tokens per cross-chain rule | 1 to 8 | +| Allowed calls per EVM rule | 1 to 32 | +| Actions per native rule | 1 to 8 | +| Argument pins per native action | 0 to 8 | +| Solana: programs / account pins / data pins / value-holding accounts | 1–32 / ≤16 / ≤8 / ≤16 | +| `validUntil` | non-zero, in the future; `type(uint48).max` = never | +| Unlimited total | `type(uint256).max` (0 means nothing) | +| Envelope version | 1 | + +## 13. Checklist before sending a grant + +- [ ] `sessionValidator` is the wallet's `SESSION_VALIDATOR()`; `sessionValidatorInitData = abi.encode(agent)`; agent ≠ owner. +- [ ] Every action has exactly one policy, URP, with a version-1 envelope. +- [ ] Cross-chain: one action, gateway + `0x77b86bec`; 1–8 PRC20 tokens, each on the rule's chain; a gas-token entry + at 0/0 if the user listed none; `maxTotal` is `type(uint256).max` when the user set no total. +- [ ] `expectedCEA` is the wallet's CEA on that chain; beneficiary offsets are `4 + 32 * argIndex`. +- [ ] Native: each `NativeTerms.target/selector` equals its action's. +- [ ] Solana: `ceaAccounts` includes the CEA and the CEA's account for every listed token. +- [ ] Record the `rulesId` from the receipt (or predict it from `grantNonce`) and keep the token order for `assertSpent`. diff --git a/plan/agw/research/deployment-review-2026-10-06/source/docs/addresses/donut.md b/plan/agw/research/deployment-review-2026-10-06/source/docs/addresses/donut.md new file mode 100644 index 00000000..b153465a --- /dev/null +++ b/plan/agw/research/deployment-review-2026-10-06/source/docs/addresses/donut.md @@ -0,0 +1,83 @@ +# Push Agentic Wallet — deployed addresses (Donut) + +**Generation `v4` (multi-asset rules, versioned envelope, agent sender door, checkpoints)** · Chain ID `42101` · +explorer [donut.push.network](https://donut.push.network) · deployed in blocks `23923806`–`23923810` · +commit `e8db748` (branch `deploy-agw` = `pushAgenticWallet_v3`) · `forge 1.5.1-stable` + +## The two addresses you need + +| | Address | +| ------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------- | +| **Factory**: deploy and look up wallets | [`0xaF88D0FD947afAe7bBb8F34e8417DCfc165e1aaF`](https://donut.push.network/address/0xaF88D0FD947afAe7bBb8F34e8417DCfc165e1aaF) | +| **URP**: name this as every rule's action policy | [`0x603E7f0aF6e1aAFf46DDfb28b1e99364f8BC59af`](https://donut.push.network/address/0x603E7f0aF6e1aAFf46DDfb28b1e99364f8BC59af) | + +Both are **proxies**. Point integrations at these, never at an implementation. + +## Everything + +| Contract | Address | Size (B) | Verified | +| -------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | -------: | :------: | +| `factoryProxy` (ERC-1967, UUPS) | [`0xaF88D0FD947afAe7bBb8F34e8417DCfc165e1aaF`](https://donut.push.network/address/0xaF88D0FD947afAe7bBb8F34e8417DCfc165e1aaF) | 141 | ✅ | +| `factoryLogic` (`AGWFactory`) | [`0xe138Dc6EfC10233BE1e6c8aF1Caf8cABe599cfC2`](https://donut.push.network/address/0xe138Dc6EfC10233BE1e6c8aF1Caf8cABe599cfC2) | 9,992 | ✅ | +| `walletImplementation` (`AGW`) | [`0x96D69ec7e6cDdaD414e656B5c9DCA24587DF713c`](https://donut.push.network/address/0x96D69ec7e6cDdaD414e656B5c9DCA24587DF713c) | 16,564 | ✅ | +| `urp` (Transparent proxy) | [`0x603E7f0aF6e1aAFf46DDfb28b1e99364f8BC59af`](https://donut.push.network/address/0x603E7f0aF6e1aAFf46DDfb28b1e99364f8BC59af) | 830 | ✅ | +| `urpImplementation` (`UniversalRulesPolicy` 3.1.0) | [`0xA2391eee4C9EA1B32AEB3A460B77296EA709F02F`](https://donut.push.network/address/0xA2391eee4C9EA1B32AEB3A460B77296EA709F02F) | 24,326 | ✅ | +| `urpProxyAdmin` (`ProxyAdmin`) | [`0x0b7a31ec85117892aEA90AA5cB6514e2F97c2295`](https://donut.push.network/address/0x0b7a31ec85117892aEA90AA5cB6514e2F97c2295) | 926 | ✅ | +| `sessionValidator` (`AgentValidator`) | [`0x068EE2388475A98EE1f5a434C58bFF3444fffFe6`](https://donut.push.network/address/0x068EE2388475A98EE1f5a434C58bFF3444fffFe6) | 806 | ✅ | +| `sessionEngine` (`SmartSession`, fork `7dc20e4`) | [`0x165A5E6782f39D30B38c7D97e1303e4CB2aD102a`](https://donut.push.network/address/0x165A5E6782f39D30B38c7D97e1303e4CB2aD102a) | 22,581 | ✅ | + +**All eight verified** on Blockscout. Keep `urpProxyAdmin`: without it URP can never be upgraded. + +### Push core contracts this deployment points at (not deployed by this repo) + +| | Address | +| --------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | +| `UniversalGatewayPC` | `0x00000000000000000000000000000000000000C1` (implementation `0x1e41…a659`, 8-field outbound request, selector `0x77b86bec`) | +| `UniversalCore` | `0x00000000000000000000000000000000000000C0` | +| `UEAFactory` | `0x00000000000000000000000000000000000000eA` | +| `UNIVERSAL_EXECUTOR_MODULE` | `0x14191Ea54B4c176fCf86f51b0FAc7CB1E71Df7d7` (the address core's UniversalCore and PRC20s use; an account with no code) | + +## How to grant a rule (what changed from v3.2) + +| | v3.2 | v4 | +| --------------------------- | --------------------------------------------------------- | ----------------------------------------------------------------------------------------- | +| Policy `initData` | `abi.encode(string chainNamespace, bytes body)` | **`abi.encode(uint16 version, string chainNamespace, bytes body)`**, `version = 1` | +| Tokens per cross-chain rule | exactly 1 (`asset`, `maxAmountPerCall`, `maxAmountTotal`) | **1 to 8** (`assets: AssetCap[]`), each with its own limits and spend counter | +| PC fee limit | `maxPCPerCall` | **`maxGasPerCall`** (same meaning: PC per outbound for protocol fee + gas) | +| Agent door | session signature through a validator | **`executeAsAgent(rulesId, mode, executionCalldata)`**, callable only by the rule's agent | +| Owner-side changes | not recorded | **checkpoint counter** (`checkpointCount()`, `Checkpointed` event) | + +Cross-chain body (EVM destination): + +```solidity +struct AssetCap { address token; uint256 maxPerCall; uint256 maxTotal; } // token = PRC20 on Push +struct UniversalTerms { + uint48 validUntil; address expectedCEA; AssetCap[] assets; uint256 maxGasPerCall; AllowedCall[] allowedCalls; +} +// ABI tuple: (uint48,address,(address,uint256,uint256)[],uint256,(address,bytes4,uint16,bool,uint256)[]) +``` + +``` +cast call 0x603E7f0aF6e1aAFf46DDfb28b1e99364f8BC59af 'pushChainHash()(bytes32)' --rpc-url +# -> 0x3d6bc1f1d3fb03065860265a8e93840b586e57075d956cd41b4319d040be87f9 == keccak256("eip155:42101") +``` + +Full design notes: `docs/1_AGW.md`, `docs/2_UniversalRulesPolicy.md`, `docs/multi-asset-review.md`. + +## Admin + +| Authority | Holder | How to change it | +| ----------------------------------------------- | --------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | +| Factory `DEFAULT_ADMIN_ROLE` (factory upgrades) | deployer EOA `0xa89523351BE1e2De64937AA9AF61Ae06eAd199C7` | `beginDefaultAdminTransfer(new)`, then the new admin calls `acceptDefaultAdminTransfer()` after the **48-hour** delay | +| URP `ProxyAdmin` owner (URP upgrades) | deployer EOA `0xa89523351BE1e2De64937AA9AF61Ae06eAd199C7` | `transferOwnership(new)` on `0x0b7a…2295`, immediate | +| Factory `PAUSER_ROLE` / `OPERATOR_ROLE` | **nobody yet** | the default admin must `grantRole` before the factory can be paused or unpaused | + +These are different powers, and for production they belong in different multisigs: the factory admin can strand +counterfactually funded addresses; the URP ProxyAdmin owner can rewrite every gate in the security boundary. + + +## Previous generation (retired) + +`v3.2` (factory `0x2578041963f692f8b51A137A1c7ddc0c84a8226A`, URP `0xeAd99E254ACD64219d057400cdC2A2390bC74372`) stays on +chain but is no longer current. Its wallets and rules do not carry over; owners withdraw through the owner door. Its +record is in `deployments/address-book-v3/`. diff --git a/plan/agw/research/deployment-review-2026-10-06/source/foundry.toml b/plan/agw/research/deployment-review-2026-10-06/source/foundry.toml new file mode 100644 index 00000000..0b4bdf74 --- /dev/null +++ b/plan/agw/research/deployment-review-2026-10-06/source/foundry.toml @@ -0,0 +1,88 @@ +[profile.default] +src = "src" +out = "out" +libs = ["lib"] +ffi = true +ast = true +build_info = true +extra_output = ["storageLayout"] + +solc = "0.8.26" +optimizer = true +# 833 matches the setting smartsessions is built and audited at upstream. At a +# higher setting SmartSession compiles to ~28.7 KB — over the EIP-170 limit and +# undeployable. Bytecode equivalence with the audited artifact is worth more than +# our gas profile. Do not raise this without re-checking `forge build --sizes`. +optimizer_runs = 833 +auto_detect_solc = false +# cancun is REQUIRED: URP's _slice helper uses MCOPY. Lowering this breaks the +# build at deploy time rather than at compile time. +evm_version = "cancun" +via_ir = true + +# Coverage scope: src/ excluding interfaces and libraries of pure types. +no_match_coverage = "(src/interfaces/|test/|script/|lib/)" + +# `out/` is READ-ONLY and is required, not a convenience: the statelessness invariant +# (validator PRD §4, factory PRD T-01(a)) is asserted against the build artifact's +# storageLayout, because Solidity offers no runtime way to prove "declares no storage" — +# a vm.load slot read is equally satisfied by a contract that declares variables and never +# writes them, i.e. a test that cannot fail. +fs_permissions = [ + { access = "read-write", path = "deployments/" }, + { access = "read", path = "out/" }, + # The Demo Ledger (demo/state/ledger.json). The demo scripts are separate processes with no + # shared memory, so the ledger is the only way state survives from one act to the next — it is + # what makes a failed step recoverable rather than fatal. + { access = "read-write", path = "demo/state/" }, + # READ-ONLY: the core repo's own build artifacts, which the UniversalMarketplace E2E deploys with + # vm.deployCode so it runs exactly the bytecode that ships (test_E2E_13 pins it). + { access = "read", path = "lib/push-chain-core-contracts/out/" }, + # READ-ONLY: core's sources, so test_E2E_13 can prove each artifact was built from the source on disk. + { access = "read", path = "lib/push-chain-core-contracts/src/" }, +] + +# ─── The core contracts the UniversalMarketplace E2E deploys (test/integration/24_marketplaceE2E.t.sol) ─── +# +# E2E must run the bytecode that SHIPS: core compiles shanghai / 99 999 runs against OZ 5.3, this repo +# cancun / 833 against OZ 5.7. So this repo does NOT recompile core: the E2E deploys the core repo's own +# build artifacts with vm.deployCode("lib/push-chain-core-contracts/out/…json"). Build core first. +# +# Why not compilation_restrictions + context remappings (the first design): forge's source graph ignores +# context remappings when it assembles a restricted compilation unit, so core's OZ imports resolved to +# this repo's OZ 5.7 and pulled Bytes.sol (MCOPY) into the shanghai job — solc 7755. Measured on 1.5.1. +# +# Only core INTERFACES are compiled here (via the push-core/ remapping), and those carry no settings +# that matter. +# +# TEMPORARY, while lib/push-chain-core-contracts is a symlink to the sibling checkout (the core changes are +# not committed yet, so there is no commit to pin a submodule to). Remove once it is a real submodule. +allow_paths = ["../push-chain-core-contracts"] + +# The demo's own tests (StakeDummy, and the AgentSigning equivalence proof). A SEPARATE PROFILE, +# not a change to the default `test` path: the v3 suite is the contracts' specification and must +# stay exactly what `forge test` runs. Demo tests are run with `FOUNDRY_PROFILE=demo forge test`, +# which the justfile wraps. Everything else is inherited from [profile.default]. +[profile.demo] +test = "demo/test" + +[fmt] +line_length = 120 +tab_width = 4 +bracket_spacing = true + +[fuzz] +runs = 1024 +max_test_rejects = 65536 +seed = '0x1' + +[invariant] +runs = 256 +depth = 64 +fail_on_revert = false + +[profile.ci.fuzz] +runs = 4096 + +[rpc_endpoints] +push_donut = "${PUSH_DONUT_RPC_URL}" diff --git a/plan/agw/research/deployment-review-2026-10-06/source/src/AGW.sol b/plan/agw/research/deployment-review-2026-10-06/source/src/AGW.sol new file mode 100644 index 00000000..e0f635a5 --- /dev/null +++ b/plan/agw/research/deployment-review-2026-10-06/source/src/AGW.sol @@ -0,0 +1,1176 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import { Clones } from "@openzeppelin/contracts/proxy/Clones.sol"; +import { ReentrancyGuardTransient } from "@openzeppelin/contracts/utils/ReentrancyGuardTransient.sol"; +import { IERC165 } from "forge-std/interfaces/IERC165.sol"; + +import { ISmartSession } from "smartsessions/ISmartSession.sol"; +import { Session, ActionData, PermissionId, ValidationData, SmartSessionMode } from "smartsessions/DataTypes.sol"; +import { PackedUserOperation } from "account-abstraction/interfaces/PackedUserOperation.sol"; +import { IModule as IERC7579Module } from "erc7579/interfaces/IERC7579Module.sol"; + +import { IAgentValidator } from "./interfaces/IAgentValidator.sol"; +import { IAGW } from "./interfaces/IAGW.sol"; +import { ISmartSessionConfigReader } from "./interfaces/ISmartSessionConfigReader.sol"; +import { AGWErrors } from "./libraries/Errors.sol"; +import { AgentConfigLib } from "./libraries/AgentConfigLib.sol"; +import { PushChainLib } from "./libraries/PushChainLib.sol"; +import { OwnerAuthLib } from "./libraries/OwnerAuthLib.sol"; +import { + OwnerIntent, + OWNER_LANE_FLAG, + SEND_OUTBOUND_SELECTOR, + RulesType, + CheckpointKind, + ENGINE_FALLBACK_TARGET, + ENGINE_FALLBACK_SELECTOR, + ENGINE_FALLBACK_SELECTOR_SMARTSESSION +} from "./libraries/Types.sol"; +import { + ModeCode, + CallType, + ExecType, + ModeLib, + CALLTYPE_SINGLE, + CALLTYPE_BATCH, + EXECTYPE_DEFAULT +} from "./libraries/ModeLib.sol"; +import { ExecutionLib, Execution } from "./libraries/ExecutionLib.sol"; + +/** + * @title AGW — Agentic Wallet + * @notice The user's per-purpose agent wallet on Push Chain. It holds the budgeted funds and is + * `msg.sender` at the gateway, which is what binds it to its destination-chain account. + * + * @dev - Push Chain has no ERC-4337 EntryPoint, so this wallet builds the operation and enforces + * the engine's verdict itself in `executeAsAgent`. + * - An ERC-7579 modular account restricted to validator modules; executor, fallback and + * hook modules are refused. A hook would run on the owner path and could block it. + * - `execute` is the owner door: no policy is ever consulted on it. + * - `executeAsAgent` is the agent door: callable only by the rules set's agent — a Push + * address (an EOA, or the UEA of an external key) — and every call is checked by the + * rules set's policy. + * - Deliberately near-stateless. A request exists only for the transaction that carries it. + */ +contract AGW is IAGW, ReentrancyGuardTransient { + using ModeLib for ModeCode; + + /// @dev ERC-7579 account id, in vendor.account.semver form. + string internal constant ACCOUNT_ID = "push.agw.1.0.0"; + + /// @dev The only ERC-7579 module type this account supports. + uint256 internal constant MODULE_TYPE_VALIDATOR = 1; + + /// @dev Gas stipend for a module's uninstall callback. + uint256 internal constant UNINSTALL_CALLBACK_GAS_STIPEND = 100_000; + + /// @dev Gas cap on the pre-uninstall state probe of the session engine. + uint256 internal constant ENGINE_STATE_PROBE_GAS = 30_000; + + /** + * @dev Maximum actions in one NATIVE rules set. `UNIVERSAL` is always exactly one. + * + * A SANITY BOUND, NOT A GAS BOUND — measured, a maximal 8x8 grant sits far inside the + * budget. It caps the O(n^2) duplicate scan below, the per-rules-set audit and UI surface a + * human has to reason about, and `revokeRules`'s engine-side cleanup cost. + * + * Lives HERE, not in `Types.sol`, because it is a wallet policy number that URP never + * reads — unlike the engine mirrors, which are shared. Do not confuse it with URP's + * `MAX_ACTIONS_PER_REQUEST` (10): that bounds multicall ENTRIES inside one universal + * payload, two layers down. Different layers, different numbers, never conflated. + */ + uint256 internal constant MAX_NATIVE_ACTIONS = 8; + + // The four wiring addresses, read through their UPPER_CASE() auto-getters. Resolved from the + // implementation's runtime bytecode, so every clone reads them correctly through delegatecall. + + /// @notice The permission engine this wallet installs as its default validator. + address public immutable SESSION_ENGINE; + + /// @notice The canonical action policy (URP) every rules set on this wallet must name. + address public immutable RULES_POLICY; + + /// @notice The canonical session validator every rules set on this wallet must name — the sender + /// validator that confirms the caller is the rules set's agent. + address public immutable SESSION_VALIDATOR; + + /// @notice The Push-side outbound gateway, the only target a universal agent action may reach. + address public immutable UNIVERSAL_GATEWAY_PC; + + /// @dev One-shot latch for initializeAccount. + bool private _initialized; + + /// @dev Monotonic salt source for permission ids; never reused. + uint64 private _grantNonce; + + /// @dev Owner-side checkpoints so far; also the `seq` of the latest `Checkpointed`. Packed in slot 0. + uint64 private _checkpointCount; + + /// @dev `block.number` of the latest checkpoint; zero before the first. Packed in slot 0. + uint64 private _lastCheckpointBlock; + + /// @dev The account's entire module registry. + mapping(address => bool) private _installedValidators; + + /// @dev Owner replay lanes for `executeWithSig`: lane key => next expected sequence number. + mapping(uint192 => uint64) private _nonces; + + /** + * @notice Sets the wallet's permanent wiring and locks the implementation itself. + * + * @dev - Reverts with `InvalidModuleAddress` if any of the four addresses is zero. + * - Sets the initialised latch, so the implementation can never be initialised or + * driven directly; only clones of it can. + * + * @param sessionEngine_ Permission engine installed as the default validator. + * @param rulesPolicy_ Canonical action policy every rules set must name. + * @param sessionValidator_ Canonical session validator every rules set must name. + * @param universalGatewayPC_ Push-side outbound gateway. + */ + constructor(address sessionEngine_, address rulesPolicy_, address sessionValidator_, address universalGatewayPC_) { + if ( + sessionEngine_ == address(0) || rulesPolicy_ == address(0) || sessionValidator_ == address(0) + || universalGatewayPC_ == address(0) + ) { + revert AGWErrors.InvalidModuleAddress(); + } + SESSION_ENGINE = sessionEngine_; + RULES_POLICY = rulesPolicy_; + SESSION_VALIDATOR = sessionValidator_; + UNIVERSAL_GATEWAY_PC = universalGatewayPC_; + + _initialized = true; + } + + /// @dev Reverts unless the caller is the clone's immutable-args owner. + modifier onlyOwner() { + if (msg.sender != _owner()) revert AGWErrors.CallerIsNotOwner(); + _; + } + + /** + * @dev Reverts unless the caller is the owner or the wallet itself. Applied to the three + * lifecycle functions only. + * + * - A batch entry targeting the wallet arrives with `msg.sender == address(this)`, so + * without this the owner's own one-signature change batch reverts against itself. + * - Widening to self is safe because self is reachable only through the owner door. From + * the agent door it is refused FOUR ways, in the order they fire: + * (a) at grant time, by `_requireGrantableTarget` — the wallet is never a grantable + * native action target; + * (b) at dispatch time, by the guard in `_gateAndDispatch` — which holds even for a + * session the owner enabled on the engine directly through the owner door, + * bypassing `grantRules` entirely; + * (c) by the engine's `NoPoliciesSet`, because (a) guarantees the wallet is never a + * configured action — true regardless of how many actions a rules set holds; + * (d) by the engine's `InvalidSelfCall`, for the `execute` selector specifically. + * (a) and (b) are never-delete tests. + * - Not applied to installModule or uninstallModule; nothing needs them batched. + */ + modifier onlyOwnerOrSelf() { + if (msg.sender != _owner() && msg.sender != address(this)) revert AGWErrors.CallerIsNotOwner(); + _; + } + + /** + * @dev Reads the owner out of the clone's immutable args. + * + * - Clone args are 40 bytes: owner at 0-19, factory at 20-39. + * - Read from bytecode on every call and never cached; a storage mirror of an immutable is + * drift surface. + * - Meaningful only on a clone. `Clones.fetchCloneArgs` is undefined on a non-clone, and on + * the implementation it returns a slice of that contract's own runtime bytecode. + * - No guard is added for the implementation case: every door on the implementation is + * already inert for an independent reason. + * + * @return The clone's owner. + */ + function _owner() internal view returns (address) { + return address(bytes20(Clones.fetchCloneArgs(address(this)))); + } + + /** + * @dev Reads the deploying factory out of the clone's immutable args. + * @return The factory recorded at clone creation. + */ + function _factory() internal view returns (address) { + bytes memory args = Clones.fetchCloneArgs(address(this)); + return address(bytes20(_slice20(args, 20))); + } + + /** + * @dev Reads 20 bytes at `start` out of a memory blob, without assuming a length. The + * short-blob branch is unreachable from the single call site and is expected to show as + * uncovered. + * + * @param data Blob to read from. + * @param start Byte offset to read at. + * @return out The 20 bytes at `start`, or zero if the blob is too short. + */ + function _slice20(bytes memory data, uint256 start) private pure returns (bytes20 out) { + if (data.length < start + 20) return bytes20(0); + assembly { + out := mload(add(add(data, 0x20), start)) + } + } + + /** + * @notice Factory-only, callable exactly once. Installs the session engine as the account's + * sole validator. + * + * @dev - Reverts with `CallerIsNotFactory` unless the caller is the clone's recorded factory. + * - Reverts with `AlreadyInitialized` if the latch is already set. + * - Sets the latch, marks the engine installed, then calls `onInstall("")` with full gas + * and bubbles any revert, so the factory's deploy transaction unwinds atomically. + * - Emits `ModuleInstalled`, then `AccountInitialized`. + * - Session data is never passed here; grants travel only through `grantRules`. + */ + function initializeAccount() external { + if (msg.sender != _factory()) revert AGWErrors.CallerIsNotFactory(); + if (_initialized) revert AGWErrors.AlreadyInitialized(); + + _initialized = true; + _installedValidators[SESSION_ENGINE] = true; + + IERC7579Module(SESSION_ENGINE).onInstall(""); + + emit ModuleInstalled(MODULE_TYPE_VALIDATOR, SESSION_ENGINE); + emit AccountInitialized(_owner(), SESSION_ENGINE); + } + + /** + * @notice The owner door. Executes a single call or a batch on the owner's behalf; no policy is + * ever consulted. + * + * @dev - Reverts unless the caller is the owner; reentrancy-guarded. + * - Reverts on any execution type other than default, and on any call type other than + * single or batch. + * - Reads no module, policy or engine state — only the immutable-args owner, its calldata, + * and the wallet's own checkpoint slot — so the door still works with the engine + * uninstalled, with a hostile validator installed, or in ghost-rules state. + * - Records one checkpoint per call, before the call (`_checkpointOwnerCall`). The write + * cannot revert. + * - The signature is frozen at `execute(bytes32,bytes)`: the session engine branches on + * this exact selector, and any other shape routes validation down a path where the + * action policy sees a hardcoded zero value instead of the real one. + * - Batch is required product surface: the permission-change flow is one owner signature + * batching a spend assertion, a revoke and a grant. + * - Dispatches through `_execute` and emits `OwnerExecuted`. + * - There is no separate withdraw function; withdrawal, revocation escort and incident + * response all run through this door. + * + * @param mode ERC-7579 mode word; call type and execution type are decoded from it. + * @param executionCalldata Encoded execution, single or batch according to `mode`. + */ + function execute(bytes32 mode, bytes calldata executionCalldata) external payable onlyOwner nonReentrant { + ModeCode m = ModeCode.wrap(mode); + (CallType callType, ExecType execType,,) = m.decode(); + + if (execType != EXECTYPE_DEFAULT) revert AGWErrors.UnsupportedExecutionMode(); + if (callType == CALLTYPE_SINGLE) { + (address target, uint256 value, bytes calldata callData) = ExecutionLib.decodeSingle(executionCalldata); + _checkpointOwnerCall(target, value, callData); + _execute(target, value, callData); + } else if (callType == CALLTYPE_BATCH) { + Execution[] calldata execs = ExecutionLib.decodeBatch(executionCalldata); + uint256 len = execs.length; + for (uint256 i; i < len;) { + _checkpointOwnerCall(execs[i].target, execs[i].value, execs[i].callData); + _execute(execs[i].target, execs[i].value, execs[i].callData); + unchecked { + ++i; + } + } + } else { + revert AGWErrors.UnsupportedExecutionMode(); + } + + emit OwnerExecuted(mode, keccak256(executionCalldata)); + } + + /** + * @dev Plain call, bubbling the callee's revert data verbatim. Shared by both doors so the agent + * path executes the exact validated bytes. + * + * @param target Address to call. + * @param value Native PC to send with the call. + * @param callData Calldata to pass, forwarded unchanged. + */ + function _execute(address target, uint256 value, bytes calldata callData) internal { + (bool ok, bytes memory ret) = target.call{ value: value }(callData); + if (!ok) { + assembly { + revert(add(ret, 0x20), mload(ret)) + } + } + } + + /** + * @dev Records one owner-side change: advances the counter, stamps the block, emits `Checkpointed`. + * + * - CANNOT REVERT except by running out of gas: an unchecked increment of a uint64 that cannot + * realistically reach 2^64, one write to the wallet's own slot 0, one event. No external call. + * That is what lets it sit on the owner doors and on the revocation path. + * - NEVER called from `_execute` or anywhere the agent door reaches. A checkpoint means "the + * owner side touched this wallet"; an agent that could tick it could always fake owner + * interference. + * + * @param kind What changed. + * @param ref Per-kind reference (see `IAGW.Checkpointed`). + */ + function _checkpoint(CheckpointKind kind, bytes32 ref) private { + uint64 seq; + unchecked { + seq = _checkpointCount + 1; + } + // forge-lint: disable-next-line(unsafe-typecast) + uint64 blockNumber = uint64(block.number); // a block number does not exceed 2^64 in practice + _checkpointCount = seq; + _lastCheckpointBlock = blockNumber; + emit Checkpointed(seq, kind, ref, blockNumber); + } + + /** + * @dev The owner-door tick for one call, taken BEFORE the call runs, so a consumer snapshotting the + * counter during that call already sees it, and any later call in the same batch moves it again. + * + * @param target The call's target. + * @param value The call's native value. + * @param callData The call's calldata. + */ + function _checkpointOwnerCall(address target, uint256 value, bytes calldata callData) private { + _checkpoint(CheckpointKind.OWNER_ACTION, keccak256(abi.encode(target, value, callData))); + } + + /** + * @notice The owner door, authorised by a signed OwnerIntent instead of `msg.sender`. Relayable. + * + * @dev - A THIRD door, separate from `execute`. `execute` reads no module, policy or engine + * state — only the immutable-args owner, its calldata and its own checkpoint slot — and + * remains the unblockable fallback. This door reads storage (the nonce lane) and may + * therefore fail where `execute` cannot. + * - The mode switch below is DUPLICATED from `execute`, not shared with it, so that no + * refactor can ever add a check to `execute`. + * - Checks, in order: deadline · `intent.wallet == this` · owner · presenter is + * `intent.executor` · owner lane · `mode` and a non-zero `execCalldataHash` match · + * nonce (consumed before the signature check; any revert unwinds it) · the owner's + * signature under the FACTORY's domain. + * - Single or batch, default exec type. No dispatch guard: this is owner authority, so a + * batch may call the wallet's own lifecycle functions through `onlyOwnerOrSelf`. + * - Records one checkpoint per call, before the call, exactly as `execute` does. + * - Emits `OwnerExecutedWithSig`. + * + * @param mode ERC-7579 mode word; must equal `intent.mode`. + * @param executionCalldata Encoded execution; its hash must equal `intent.execCalldataHash`. + * @param intent The owner's intent; the grant fields are ignored here. + * @param sig The owner's signature over `intent`. + */ + function executeWithSig( + bytes32 mode, + bytes calldata executionCalldata, + OwnerIntent calldata intent, + bytes calldata sig + ) external nonReentrant { + address owner_ = _requireIntentPresenter(intent); + + uint192 nonceKey = intent.nonceKey; + if (nonceKey & OWNER_LANE_FLAG == 0) revert AGWErrors.OwnerLaneRequired(nonceKey); + + bytes32 calldataHash = keccak256(executionCalldata); + if (intent.execCalldataHash == bytes32(0) || intent.execCalldataHash != calldataHash || intent.mode != mode) { + revert AGWErrors.IntentExecMismatch(calldataHash); + } + + uint64 expected = _nonces[nonceKey]; + if (intent.nonceSeq != expected) revert AGWErrors.InvalidNonce(nonceKey, expected, intent.nonceSeq); + _nonces[nonceKey] = expected + 1; + + _requireOwnerSig(owner_, intent, sig); + + (CallType callType, ExecType execType,,) = ModeCode.wrap(mode).decode(); + if (execType != EXECTYPE_DEFAULT) revert AGWErrors.UnsupportedExecutionMode(); + if (callType == CALLTYPE_SINGLE) { + (address target, uint256 value, bytes calldata callData) = ExecutionLib.decodeSingle(executionCalldata); + _checkpointOwnerCall(target, value, callData); + _execute(target, value, callData); + } else if (callType == CALLTYPE_BATCH) { + Execution[] calldata execs = ExecutionLib.decodeBatch(executionCalldata); + uint256 len = execs.length; + for (uint256 i; i < len;) { + _checkpointOwnerCall(execs[i].target, execs[i].value, execs[i].callData); + _execute(execs[i].target, execs[i].value, execs[i].callData); + unchecked { + ++i; + } + } + } else { + revert AGWErrors.UnsupportedExecutionMode(); + } + + emit OwnerExecutedWithSig(mode, calldataHash, nonceKey, intent.nonceSeq); + } + + /** + * @dev The checks every intent door shares, in order: deadline, wallet, owner, presenter. + * Returns the owner so the caller does not re-read the immutable args. + */ + function _requireIntentPresenter(OwnerIntent calldata intent) internal view returns (address owner_) { + if (block.timestamp > intent.deadline) revert AGWErrors.OwnerSigExpired(intent.deadline); + if (intent.wallet != address(this)) { + revert AGWErrors.IntentWalletMismatch(address(this), intent.wallet); + } + owner_ = _owner(); + if (intent.owner != owner_) revert AGWErrors.CallerIsNotOwner(); + if (intent.executor == address(0) || msg.sender != intent.executor) { + revert AGWErrors.ExecutorMismatch(intent.executor, msg.sender); + } + } + + /// @dev The owner's signature over `intent`, under the factory's domain. Last check before effects. + function _requireOwnerSig(address owner_, OwnerIntent calldata intent, bytes calldata sig) internal view { + if (!OwnerAuthLib.isOwnerSig(owner_, OwnerAuthLib.intentDigest(_factory(), intent), sig)) { + revert AGWErrors.InvalidOwnerSignature(); + } + } + + /** + * @notice Grants one rules set to an agent. One of exactly two lifecycle operations. + * + * @dev - Reverts unless the caller is the owner or the wallet itself. + * - Rejects any session that is not the one shape this wallet permits, all with + * `MalformedSessionShape`: any user-op policy present, any ERC-7739 content or policy, + * the ERC-4337 paymaster permit set, an action count other than one, an action whose + * target is not the gateway or whose selector is not the outbound send, an action + * policy set that is not exactly the canonical policy, or a session validator that is + * not the canonical one. + * - Rejects an agent config the session validator does not accept — anything but + * `abi.encode(address agent)` with a non-zero agent. The canonical validator's check + * never reverts; the call is still wrapped in a bare catch rather than a typed one, so a + * future validator's revert or compiler panic is absorbed as a refusal. Wrapping is + * correct here only because the external call already exists; the action policy's own + * decode is deliberately not wrapped, since there it would introduce one. + * - Refusing the paymaster permit keeps dead surface dead: setting it would write a live + * permit row into engine storage, and that row decides whether a non-empty + * `paymasterAndData` is rejected outright or instead requires a user-op policy to run, + * which this shape forbids. + * - Overwrites the caller's salt with the wallet's monotonic grant counter, so identical + * terms granted twice yield distinct permission ids and a replaced id never recurs. + * That is what makes a request built for a revoked rules set die on regrant. + * - Enables the session on the engine and emits `RulesGranted`. + * - Records a checkpoint (`RULES_GRANTED`). + * - Validates the session's shape only. The caps, allow-list and expiry inside the policy + * config are the policy's own concern; do not extend this into term validation. + * - Carries no reentrancy guard: the guard would trip on the owner's own change batch, + * and the engine's enable path never calls back into the account. + * + * - TAKES NO MANDATE TYPE. The kind of a rules set is DERIVED, not declared: each action's + * URP policy envelope is `abi.encode(uint16 version, string chain, bytes body)`, and the chain decides + * the rulebook — this chain means a Push-side call (NATIVE), any other means a call + * through the gateway (UNIVERSAL). The owner states a chain once, where they were + * already stating the terms; nobody states a mode anywhere. Every action must name the + * same chain, which is what makes a mixed rules set unrepresentable rather than merely + * forbidden. + * - The envelope is NOT REWRITTEN. The wallet reads one field and passes the caller's + * bytes to the engine untouched, so what URP validates is exactly what the owner + * reviewed. + * + * @param session The session to enable. Its `salt` field is ignored and overwritten. + * @return rulesId The engine's id for the newly enabled rules set. + * + * `rulesId` is the engine's `permissionId`. + */ + function grantRules(Session calldata session) external onlyOwnerOrSelf returns (bytes32 rulesId) { + return _grantRules(session); + } + + /** + * @notice `grantRules`, authorised by the owner's signed OwnerIntent instead of `msg.sender`. + * + * @dev - Checks, in order: deadline · `intent.wallet == this` · `intent.owner` is this wallet's + * owner · presenter is `intent.executor` (non-zero) · `sessionHash` is non-zero and is the + * hash of `session` · `grantNonce` is the current `_grantNonce` · the owner's signature under + * the FACTORY's domain. Then the entire `grantRules` body, unchanged. + * - `_grantNonce` advances on every grant, so an intent grants at most once and dies on any + * other grant. No new storage. + * - `sessionHash` covers the session AS SUPPLIED, salt included; the salt is then overwritten + * with the grant nonce exactly as on the owner path. + * - Unreachable from the agent door: the wallet is never a grantable action target, and the + * dispatch guard refuses `address(this)` whatever the selector. + * - No reentrancy guard, for the same reason `grantRules` has none. + * + * @param session The session to enable. + * @param intent The owner's intent; the exec fields are ignored here. + * @param sig The owner's signature over `intent`. + * @return rulesId The engine's id for the newly enabled rules set. + * + * `rulesId` is the engine's `permissionId`. + */ + function grantRulesWithSig(Session calldata session, OwnerIntent calldata intent, bytes calldata sig) + external + returns (bytes32 rulesId) + { + address owner_ = _requireIntentPresenter(intent); + + bytes32 sessionHash = keccak256(abi.encode(session)); + if (intent.sessionHash == bytes32(0) || intent.sessionHash != sessionHash) { + revert AGWErrors.IntentSessionMismatch(sessionHash); + } + if (intent.grantNonce != _grantNonce) { + revert AGWErrors.IntentGrantNonceMismatch(_grantNonce, intent.grantNonce); + } + _requireOwnerSig(owner_, intent, sig); + + return _grantRules(session); + } + + /** + * @dev The entire body `grantRules` always had, moved here unchanged so both entry points run the + * same checks in the same order with the same errors. See `grantRules` for the rules. + */ + function _grantRules(Session calldata session) internal returns (bytes32 rulesId) { + // ─── rules COMMON to both types, first ─── + + if (session.userOpPolicies.length != 0) revert AGWErrors.MalformedSessionShape(); + + if ( + session.erc7739Policies.allowedERC7739Content.length != 0 + || session.erc7739Policies.erc1271Policies.length != 0 + ) revert AGWErrors.MalformedSessionShape(); + + if (session.permitERC4337Paymaster) revert AGWErrors.MalformedSessionShape(); + + uint256 n = session.actions.length; + + // BEFORE THE DECODE, AND FOR BOTH MODES. The mode is derived from action 0's envelope, so + // action 0 must exist before anything can be derived: with no actions there is no envelope, + // no chain, and therefore no mode to report. A universal session with zero actions + // consequently reports `TooManyActions(0)`, not `MalformedSessionShape`. + if (n == 0) revert AGWErrors.TooManyActions(0); + + // THE POLICY-SHAPE CHECK RUNS BEFORE THE DECODE, ALWAYS. Decoding first would read an + // arbitrary policy's `initData` as though it were URP's. This ordering is load-bearing. + _requirePolicyShape(session.actions[0]); + (string memory chain, bytes32 chainHash) = _chainNamespaceOf(session.actions[0]); + + // ─── THE ENTIRE MODE DECISION. Nobody declared it. ─── + RulesType mode = PushChainLib.deriveMode(chainHash); + + // THE INVARIANT, STATED ONCE: a wrong POLICY is always `MalformedSessionShape`; a target + // wrong FOR THE DERIVED TYPE is always `RulesTypeMismatch`. Between the two branches + // there is no shape in which a gateway call reaches a native config, and none in which a + // native call reaches a universal one — which, with URP's N3 and gate 3 at runtime, is the + // whole consistency argument. One chain per rules set makes mixed rules sets unrepresentable. + + if (mode == RulesType.UNIVERSAL) { + // `n != 1` BEFORE the target check, as before. A malformed chain string on a + // multi-action session therefore reports `MalformedSessionShape`, not a type mismatch. + if (n != 1) revert AGWErrors.MalformedSessionShape(); + + ActionData calldata a = session.actions[0]; + if (a.actionTarget != UNIVERSAL_GATEWAY_PC || a.actionTargetSelector != SEND_OUTBOUND_SELECTOR) { + revert AGWErrors.RulesTypeMismatch(mode, 0, a.actionTarget); + } + } else { + if (n > MAX_NATIVE_ACTIONS) revert AGWErrors.TooManyActions(n); + + // Hoisted: `_factory()` does an extcodecopy of the clone's own bytecode on every call. + address factoryAddr = _factory(); + + for (uint256 i; i < n;) { + ActionData calldata a = session.actions[i]; + + _requireGrantableTarget(a.actionTarget, factoryAddr, i); + _requireGrantableSelector(a.actionTargetSelector); + + // Action 0's shape and chain were read above; re-reading would waste ~900 gas. + // EVERY action must name the same chain — that is what makes "one rules set, one + // mode" true by construction rather than by a rule. + if (i != 0) { + _requirePolicyShape(a); + (, bytes32 h) = _chainNamespaceOf(a); + if (h != chainHash) revert AGWErrors.InconsistentChain(i); + } + + // O(n^2) by design: 28 comparisons at the n=8 ceiling, which beats a mapping and its + // clear-down. Two identical (target, selector) pairs would hash to one actionId. + for (uint256 j; j < i;) { + if ( + session.actions[j].actionTarget == a.actionTarget + && session.actions[j].actionTargetSelector == a.actionTargetSelector + ) { + revert AGWErrors.DuplicateAction(a.actionTarget, a.actionTargetSelector); + } + unchecked { + ++j; + } + } + + unchecked { + ++i; + } + } + } + + if (address(session.sessionValidator) != SESSION_VALIDATOR) { + revert AGWErrors.MalformedSessionShape(); + } + + try IAgentValidator(SESSION_VALIDATOR).validateConfig(session.sessionValidatorInitData) returns (bool ok) { + if (!ok) revert AGWErrors.MalformedSessionShape(); + } catch { + revert AGWErrors.MalformedSessionShape(); + } + + Session memory sessionMem = session; + sessionMem.salt = bytes32(uint256(_grantNonce)); + // Checked on purpose: a wrapping counter would mean silent salt reuse. + _grantNonce++; + + Session[] memory sessions = new Session[](1); + sessions[0] = sessionMem; + PermissionId[] memory ids = ISmartSession(SESSION_ENGINE).enableSessions(sessions); + + rulesId = PermissionId.unwrap(ids[0]); + _checkpoint(CheckpointKind.RULES_GRANTED, rulesId); + emit RulesGranted(rulesId, mode, chainHash, chain); + } + + /** + * @dev The policy-shape rule, hoisted so it can run before each envelope decode. + * + * A SHAPE rule, so it raises `MalformedSessionShape` like every other shape rule. It is + * also the precondition for `_chainNamespaceOf`: without it, the decode below would be reading an + * arbitrary policy's `initData` as though URP had authored it. + * + * @param a The action whose policy slot is vetted. + */ + function _requirePolicyShape(ActionData calldata a) internal view { + if (a.actionPolicies.length != 1 || a.actionPolicies[0].policy != RULES_POLICY) { + revert AGWErrors.MalformedSessionShape(); + } + } + + /** + * @dev Reads ONE field of the policy envelope — the bounded exception to "the skeleton, not the + * organs". + * + * WHAT THIS IS NOT: it is not term validation. The wallet does not check caps, expiry, + * allow-list contents or anything else inside the body, and must never start. It reads the + * label on the jar: the one field that decides WHICH RULEBOOK the action belongs to, which + * is the wallet's own business because the wallet's target rules depend on it. URP + * re-derives the same value from the same bytes and remains the sole judge of the terms. + * + * CALLER MUST HAVE RUN `_requirePolicyShape` FIRST. + * + * Same decoder as URP's, deliberately (`abi.decode(initData, (uint16, string, bytes))`): + * two different readers of one security-relevant field is the drift this design exists to + * prevent. A malformed envelope reverts here, unnamed, and fails closed. The version is + * URP's to judge: it refuses anything but `ENVELOPE_VERSION` at init, inside this grant. + * + * @param a The action to read. + * @return chain The declared CAIP-2 string, e.g. `"eip155:11155111"`. + * @return chainHash Its keccak256, the value everything downstream compares. + */ + function _chainNamespaceOf(ActionData calldata a) internal pure returns (string memory chain, bytes32 chainHash) { + (, chain,) = abi.decode(a.actionPolicies[0].initData, (uint16, string, bytes)); + if (bytes(chain).length == 0) revert AGWErrors.EmptyChain(); + chainHash = keccak256(bytes(chain)); + } + + /** + * @dev Every grant-time target rule for a NATIVE action, in one place. + * + * TWO RULES, TWO ERRORS, AND THE DISTINCTION IS THE POINT: + * + * - **The gateway → `RulesTypeMismatch`.** The session is well-formed; the CHAIN the + * envelope declares is this chain, and a gateway call is not a Push-side call. A gateway + * target is perfectly grantable — under a foreign chain, as `UNIVERSAL`. Carries the + * action index, because with up to eight actions "something was wrong" is not a usable + * diagnostic. This is one half of the consistency lock; URP's N3 is the runtime mirror. + * - **The other seven → `ForbiddenActionTarget`.** Never grantable, under any type. + * + * Of those seven the severe pair is the wallet and the engine: from the agent door, + * `_execute(wallet, 0, grantRules(...))` would arrive with `msg.sender == address(this)`, + * pass `onlyOwnerOrSelf`, and the agent would have granted itself a rules set of its own + * design. `revokeAllRules` is the mirror. + * + * LAYER CREDIT, so nobody deletes the wrong one as redundant: the engine independently + * refuses `address(0)` and ITSELF at enable time (`ConfigLib.sol:139-143`), but it does NOT + * refuse `address(1)` there — only at check time. **This is the only grant-time layer for + * the fallback flag.** + * + * The action-policy check is deliberately NOT here. That is a SHAPE rule — it raises + * `MalformedSessionShape`, and the UNIVERSAL branch and the common rules raise the same + * error for the same class of defect. It belongs with them, not inside a target helper. + * + * @param t Action target to vet. + * @param factoryAddr The clone's factory, hoisted by the caller so the loop reads it once. + * `_factory()` does an extcodecopy of the clone's own bytecode; the other + * six comparands are immutables and are free to read here. + * @param index Index of this action, reported by `RulesTypeMismatch`. + */ + function _requireGrantableTarget(address t, address factoryAddr, uint256 index) internal view { + if (t == UNIVERSAL_GATEWAY_PC) { + revert AGWErrors.RulesTypeMismatch(RulesType.NATIVE, index, t); + } + if ( + t == address(0) || t == ENGINE_FALLBACK_TARGET || t == address(this) || t == SESSION_ENGINE + || t == RULES_POLICY || t == SESSION_VALIDATOR || t == factoryAddr + ) { + revert AGWErrors.ForbiddenActionTarget(t); + } + } + + /** + * @dev The grant-time forbidden-selector list for NATIVE actions. + * + * Refuses the engine's two fallback selectors by name. `0xFFFFFFFF` (value-only) is + * PERMITTED and is deliberately not on this list. + * + * @param s Action selector to vet. + */ + function _requireGrantableSelector(bytes4 s) internal pure { + if (s == ENGINE_FALLBACK_SELECTOR || s == ENGINE_FALLBACK_SELECTOR_SMARTSESSION) { + revert AGWErrors.ForbiddenActionSelector(s); + } + } + + /** + * @notice Revoke one rules set. The other lifecycle operation, and the emergency lever. + * + * @dev - Reverts unless the caller is the owner or the wallet itself. + * - Reverts with `UnknownPermission` if the id is not enabled, because the upstream + * removal silently no-ops on a ghost id and an operator must never read "revoked" + * while the rules set lives. + * - Removes the session and emits `RulesRevoked`. Revocation is immediate: removal clears + * the agent, so any request under the id fails `CallerIsNotAgent`. + * - Deliberately carries no reentrancy guard and no health probe: nothing that can fail + * belongs on the stop path, since blockable removal is the one regression this + * function can develop. It records a checkpoint (`RULES_REVOKED`) per removed id; that + * write cannot revert. + * + * @param rulesId The rules set to revoke. + * + * `rulesId` is the engine's `permissionId`. + */ + function revokeRules(bytes32 rulesId) external onlyOwnerOrSelf { + if (!ISmartSession(SESSION_ENGINE).isPermissionEnabled(PermissionId.wrap(rulesId), address(this))) { + revert AGWErrors.UnknownPermission(rulesId); + } + + ISmartSession(SESSION_ENGINE).removeSession(PermissionId.wrap(rulesId)); + + _checkpoint(CheckpointKind.RULES_REVOKED, rulesId); + emit RulesRevoked(rulesId); + } + + /** + * @notice Revokes every rules set on this wallet in one call. The incident-response lever. + * + * @dev - Reverts unless the caller is the owner or the wallet itself. + * - Snapshots the permission ids, removes each by id, and emits `RulesRevoked` per id. + * Removal is by id, so engine-side array shifting cannot disturb the snapshot. + * - Deliberately carries no reentrancy guard and no health probe, for the same reason as + * `revokeRules`. It records a checkpoint (`RULES_REVOKED`) per removed id; that write + * cannot revert. + * - Gas grows with permission count; wallets hold few permissions by design. + */ + function revokeAllRules() external onlyOwnerOrSelf { + PermissionId[] memory ids = ISmartSession(SESSION_ENGINE).getPermissionIDs(address(this)); + + uint256 len = ids.length; + for (uint256 i; i < len;) { + ISmartSession(SESSION_ENGINE).removeSession(ids[i]); + _checkpoint(CheckpointKind.RULES_REVOKED, PermissionId.unwrap(ids[i])); + emit RulesRevoked(PermissionId.unwrap(ids[i])); + unchecked { + ++i; + } + } + } + + /** + * @notice The agent door. Callable only by the rules set's agent; every call is checked by the + * rules set's policy before it runs. + * + * @dev This chain has no EntryPoint, so this function does the EntryPoint's work, in order: + * 1. reject if the session engine is no longer installed + * 2. reject unless `msg.sender` is the agent `rulesId` names on this wallet + * 3. build the operation, validate it through the engine, and enforce the verdict + * 4. reject any mode other than single and default, and the two forbidden targets + * 5. dispatch the exact validated bytes + * 6. emit `RulesActionAuthorized` + * + * - The agent is a Push address. An external key (EVM, Solana, anything) acts through its + * UEA, which verifies that key before calling here; this wallet verifies no signature. + * - Replay protection is the sender's own transaction nonce (an EOA's nonce, or the UEA + * payload's nonce). Expiry is the rules set's own (policy gate 2 / N2 / S2); an EOA + * transaction carries no per-request expiry, a UEA payload carries its `deadline`. + * - A request against a revoked rules set fails at step 2: removal clears the agent. + * - Not payable, but a validated request does move PC out of the wallet's own balance, + * bounded by the policy's per-call ceiling. + * - Any revert unwinds the whole transaction, including the policy's counters; dispatch + * is never wrapped in try/catch. + * - Mode is single-only here: batching lives inside the multicall payload, bounded by the + * policy. + * + * @param rulesId The rules set this call acts under. `rulesId` is the engine's + * `permissionId`. + * @param mode ERC-7579 mode word; must decode to single and default. + * @param executionCalldata Encoded single execution, dispatched byte-for-byte once validated. + */ + function executeAsAgent(bytes32 rulesId, bytes32 mode, bytes calldata executionCalldata) external nonReentrant { + if (!_installedValidators[SESSION_ENGINE]) { + revert AGWErrors.ValidatorNotInstalled(SESSION_ENGINE); + } + + if (msg.sender != _agentOf(rulesId)) revert AGWErrors.CallerIsNotAgent(rulesId, msg.sender); + + bytes32 callsHash = keccak256(executionCalldata); + + _validate(rulesId, mode, executionCalldata, callsHash); + + _gateAndDispatch(mode, executionCalldata); + + emit RulesActionAuthorized(rulesId, msg.sender, callsHash); + } + + /** + * @dev Gates the mode to single and default, then dispatches the validated execution unchanged. + * + * - The agent path never batches at the ERC-7579 layer; batching lives inside the multicall + * payload instead, bounded by the policy. + * - Split out for stack depth only. Inlined, this does not compile with the optimizer off, + * which is the configuration `forge coverage` uses. + * + * @param mode ERC-7579 mode word. + * @param executionCalldata Encoded single execution to dispatch. + */ + function _gateAndDispatch(bytes32 mode, bytes calldata executionCalldata) internal { + (CallType callType, ExecType execType,,) = ModeCode.wrap(mode).decode(); + if (callType != CALLTYPE_SINGLE || execType != EXECTYPE_DEFAULT) { + revert AGWErrors.UnsupportedExecutionMode(); + } + (address target, uint256 value, bytes calldata callData) = ExecutionLib.decodeSingle(executionCalldata); + + // ⚠️ THE DISPATCH GUARD — never-delete, and it belongs HERE, after validation. + // + // Two comparisons, no storage, no module or policy state. It holds regardless of how the + // session was enabled — including a session the owner enabled on the engine DIRECTLY + // through the owner door, bypassing `grantRules` and its forbidden-target list entirely. + // That path exists today and is legitimate; this is what stops it reaching the wallet's own + // lifecycle functions from the agent side. + // + // DO NOT MOVE IT BEFORE `_validate`. Placed earlier it would pre-empt the engine's own + // refusals and change which error surfaces, and the engine-target case only ever reaches + // this point through the fallback sentinel, which validation has to run to resolve. + if (target == address(this) || target == SESSION_ENGINE) { + revert AGWErrors.ForbiddenDispatchTarget(target); + } + + _execute(target, value, callData); + } + + /** + * @dev Builds the operation, validates it through the engine, and enforces the verdict. + * + * - Builds a `PackedUserOperation` for its ABI shape only, since there is no EntryPoint. The + * engine requires `sender` to equal `msg.sender` (the wallet); that is what makes the + * signature field below unforgeable. + * - The callData selector must be `execute(bytes32,bytes)`, because that is the only engine + * branch that decodes the mode and forwards the real decoded value to the action policy. + * Every other selector reaches the policy with the account as target and a hardcoded zero + * value, which would make the policy's value gate compare against nothing. + * - The signature field is `USE ‖ rulesId ‖ msg.sender`, written here and nowhere else. The + * session validator accepts it only when those 20 bytes are the rules set's agent. + * - `callsHash` is passed as the operation hash. Nothing verifies a signature over it; it is + * what the engine forwards to the validator, which ignores it. + * - Gas fields are zero and `paymasterAndData` must stay empty, or the engine's paymaster + * permit check reverts. The nonce field is zero: replay protection is the sender's own. + * - Enforces the returned authorizer and time window itself — the EntryPoint's job, and what + * makes the policy's expiry gate real rather than decorative. + * - The engine runs the action policy before it consults the session validator, so policies + * still see calldata the engine has not yet authenticated; the wallet's own agent check + * has already run by then. + * - Performs exactly one external call, to the engine. Split out for stack depth. + * + * @param rulesId The rules set, written into the signature field. + * @param mode ERC-7579 mode word, re-encoded into the operation's calldata. + * @param executionCalldata Execution calldata, re-encoded into the operation's calldata. + * @param callsHash `keccak256(executionCalldata)`, passed as the operation hash. + */ + function _validate(bytes32 rulesId, bytes32 mode, bytes calldata executionCalldata, bytes32 callsHash) internal { + PackedUserOperation memory op; + op.sender = address(this); + op.nonce = 0; + op.initCode = ""; + op.callData = abi.encodeWithSelector(this.execute.selector, mode, executionCalldata); + op.accountGasLimits = bytes32(0); + op.preVerificationGas = 0; + op.gasFees = bytes32(0); + op.paymasterAndData = ""; + op.signature = abi.encodePacked(SmartSessionMode.USE, rulesId, msg.sender); + + uint256 vd = ValidationData.unwrap(ISmartSession(SESSION_ENGINE).validateUserOp(op, callsHash)); + + address authorizer = address(uint160(vd)); + uint48 validUntil = uint48(vd >> 160); // 0 = unbounded + uint48 validAfter = uint48(vd >> 208); + + if (authorizer != address(0)) revert AGWErrors.ValidationFailed(authorizer); + if (block.timestamp < validAfter) revert AGWErrors.OutsideTimeWindow(validAfter, validUntil); + if (validUntil != 0 && block.timestamp > validUntil) { + revert AGWErrors.OutsideTimeWindow(validAfter, validUntil); + } + } + + /** + * @dev The agent `rulesId` names on this wallet, or `address(0)` if it names none. + * Zero when the id is unknown or revoked (removal clears the config), when its session + * validator is not the canonical one, or when its config is malformed. One external view + * call to the engine; decodes through the same library the validator enforces with. + * @param rulesId The rules set to look up. + * @return The agent's Push address, or zero. + */ + function _agentOf(bytes32 rulesId) internal view returns (address) { + (address sessionValidator_, bytes memory config) = ISmartSessionConfigReader(SESSION_ENGINE) + .getSessionValidatorAndConfig(address(this), PermissionId.wrap(rulesId)); + if (sessionValidator_ != SESSION_VALIDATOR) return address(0); + return AgentConfigLib.decode(config); + } + + /** + * @notice Installs a validator module. + * + * @dev - Reverts unless the caller is the owner; reentrancy-guarded. + * - Rejects any module type but validator, the zero address, an address with no code, + * and a module that is already installed. + * - Marks the module installed, calls `onInstall` with full gas and bubbles any revert, + * then emits `ModuleInstalled`. + * - Exists as the recovery lever: a corrected validator can be installed on an existing + * wallet without moving addresses or funds. + * + * @param moduleTypeId ERC-7579 module type; only the validator type is accepted. + * @param module Module to install. + * @param initData Opaque data forwarded to the module's `onInstall`. + */ + function installModule(uint256 moduleTypeId, address module, bytes calldata initData) + external + onlyOwner + nonReentrant + { + if (moduleTypeId != MODULE_TYPE_VALIDATOR) { + revert AGWErrors.UnsupportedModuleType(moduleTypeId); + } + if (module == address(0) || module.code.length == 0) revert AGWErrors.InvalidModuleAddress(); + if (_installedValidators[module]) revert AGWErrors.ModuleAlreadyInstalled(module); + + _installedValidators[module] = true; + + IERC7579Module(module).onInstall(initData); + + emit ModuleInstalled(moduleTypeId, module); + } + + /** + * @notice Uninstalls a validator module. Removal always proceeds. + * + * @dev - Reverts unless the caller is the owner; reentrancy-guarded. + * - Rejects any module type but validator, and a module that is not installed. + * - If and only if the module is the session engine, probes its initialised state under + * a gas cap and refuses removal while it still holds permissions. Uninstalling the + * engine with live permissions would run its cleanup loop out of gas and leave rows it + * then refuses to reinstall over, so the guard forces a `revokeAllRules` first. + * - Unmarks the module before calling back, so a module can never block its own removal. + * - Calls `onUninstall` under a stipend inside try/catch, emitting + * `UninstallCallbackFailed` if it reverts or exhausts the stipend, then emits + * `ModuleUninstalled`. + * - The probe is scoped to the engine alone, so a hostile third-party validator can + * never block its own removal. + * - A probe that reverts or runs out of gas proceeds with removal: the guard exists to + * prevent an ordering mistake, not to make a broken engine permanent. + * + * @param moduleTypeId ERC-7579 module type; only the validator type is accepted. + * @param module Module to uninstall. + * @param deInitData Opaque data forwarded to the module's `onUninstall`. + */ + function uninstallModule(uint256 moduleTypeId, address module, bytes calldata deInitData) + external + onlyOwner + nonReentrant + { + if (moduleTypeId != MODULE_TYPE_VALIDATOR) { + revert AGWErrors.UnsupportedModuleType(moduleTypeId); + } + if (!_installedValidators[module]) revert AGWErrors.ValidatorNotInstalled(module); + + if (module == SESSION_ENGINE) { + (bool ok, bytes memory ret) = module.staticcall{ gas: ENGINE_STATE_PROBE_GAS }( + abi.encodeCall(ISmartSession.isInitialized, (address(this))) + ); + if (ok && ret.length >= 32 && abi.decode(ret, (bool))) { + revert AGWErrors.EngineStillHoldsPermissions(); + } + } + + _installedValidators[module] = false; + + try IERC7579Module(module).onUninstall{ gas: UNINSTALL_CALLBACK_GAS_STIPEND }(deInitData) { } + catch { + emit UninstallCallbackFailed(module); + } + + emit ModuleUninstalled(moduleTypeId, module); + } + + /** + * @notice Whether `module` is installed under `moduleTypeId`. + * @param moduleTypeId ERC-7579 module type to query. + * @param module Module to query. + * @return True only for an installed validator. + */ + function isModuleInstalled(uint256 moduleTypeId, address module, bytes calldata) external view returns (bool) { + return moduleTypeId == MODULE_TYPE_VALIDATOR && _installedValidators[module]; + } + + /** + * @notice Whether this account supports an ERC-7579 module type. + * @param moduleTypeId Module type to query. + * @return True only for the validator type. + */ + function supportsModule(uint256 moduleTypeId) external pure returns (bool) { + return moduleTypeId == MODULE_TYPE_VALIDATOR; + } + + /** + * @notice Whether this account supports an ERC-7579 execution mode. + * @dev Answers for the account as a whole; the agent door additionally restricts itself to + * single calls. + * @param mode ERC-7579 mode word to query. + * @return True for default execution in single or batch call type. + */ + function supportsExecutionMode(bytes32 mode) external pure returns (bool) { + (CallType callType, ExecType execType,,) = ModeCode.wrap(mode).decode(); + if (execType != EXECTYPE_DEFAULT) return false; + return callType == CALLTYPE_SINGLE || callType == CALLTYPE_BATCH; + } + + /// @notice The wallet's owner, read from the clone's immutable args. + function owner() external view returns (address) { + return _owner(); + } + + /// @notice The factory that deployed this wallet. + function factory() external view returns (address) { + return _factory(); + } + + /** + * @notice Next expected sequence number in an owner lane (`OWNER_LANE_FLAG` set), consumed by + * `executeWithSig`. The agent door uses no nonce lanes. + * @param nonceKey Replay lane to query. + * @return The sequence number the next intent in that lane must carry. + */ + function getNonce(uint192 nonceKey) external view returns (uint64) { + return _nonces[nonceKey]; + } + + /// @notice The salt the next grant will use. + function grantNonce() external view returns (uint64) { + return _grantNonce; + } + + /** + * @notice The agent a rules set names on this wallet, or zero if it names none. + * @dev Zero for an unknown or revoked id, for a session the owner enabled on the engine + * directly with a non-canonical session validator, and for a malformed config. Such a + * rules set cannot be used through `executeAsAgent`. + * @param rulesId The rules set to look up. `rulesId` is the engine's `permissionId`. + * @return The agent's Push address, or zero. + */ + function agentOf(bytes32 rulesId) external view returns (address) { + return _agentOf(rulesId); + } + + /** + * @notice Owner-side checkpoints so far. Compare against a snapshot to learn whether the owner side + * touched this wallet since: any owner-door call, grant or revoke moves it; agent actions + * never do. + * @return The number of checkpoints recorded. + */ + function checkpointCount() external view returns (uint64) { + return _checkpointCount; + } + + /** + * @notice `block.number` of the latest checkpoint, or zero if none. A convenience only: consumers + * must compare COUNTS, because several checkpoints can share a block with their snapshot. + * @return The block number of the latest checkpoint. + */ + function lastCheckpointBlock() external view returns (uint64) { + return _lastCheckpointBlock; + } + + /// @notice The OwnerIntent domain separator this wallet verifies against, for a signer on + /// `signerChainId`. Identical to the factory's: the factory is the verifying contract. + function domainSeparator(uint256 signerChainId) external view returns (bytes32) { + return OwnerAuthLib.domainSeparator(_factory(), signerChainId); + } + + /// @notice The ERC-7579 account id, in vendor.account.semver form. + function accountId() external pure returns (string memory) { + return ACCOUNT_ID; + } + + /// @dev Accepts PC with no logic; the wallet pays outbound gas swaps from its own balance and + /// refunds land here. + receive() external payable { } + + /// @notice Accepts ERC-721 transfers, so destination-side refunds and NFTs can land. + function onERC721Received(address, address, uint256, bytes calldata) external pure returns (bytes4) { + return this.onERC721Received.selector; + } + + /// @notice Accepts ERC-1155 transfers, so destination-side refunds and NFTs can land. + function onERC1155Received(address, address, uint256, uint256, bytes calldata) external pure returns (bytes4) { + return this.onERC1155Received.selector; + } + + /// @notice Accepts batched ERC-1155 transfers, so destination-side refunds and NFTs can land. + function onERC1155BatchReceived(address, address, uint256[] calldata, uint256[] calldata, bytes calldata) + external + pure + returns (bytes4) + { + return this.onERC1155BatchReceived.selector; + } + + /** + * @notice ERC-165 support check. + * + * @dev - Reports ERC-165 and the two token-receiver interfaces only. + * - Deliberately does not report `IERC7579Account`: this account implements that + * interface partially, so advertising it would mislead the tooling that probes for it. + * Tooling detects the account through `accountId`, `supportsModule` and + * `supportsExecutionMode` instead. + * + * @param interfaceId Interface id to query. + * @return True for the three supported interfaces. + */ + function supportsInterface(bytes4 interfaceId) external pure returns (bool) { + return interfaceId == type(IERC165).interfaceId // 0x01ffc9a7 + || interfaceId == 0x150b7a02 // IERC721Receiver + || interfaceId == 0x4e2312e0; // IERC1155Receiver + } + + /** + * @notice Always invalid: the wallet never signs as an ERC-1271 party. + * @dev A constant return, with no logic and no future hook. This is also what makes the + * engine's enable-mode grant path dead on these wallets. + * @return The ERC-1271 failure magic value. + */ + function isValidSignature(bytes32, bytes calldata) external pure returns (bytes4) { + return 0xffffffff; + } +} diff --git a/plan/agw/research/deployment-review-2026-10-06/source/src/AGWFactory.sol b/plan/agw/research/deployment-review-2026-10-06/source/src/AGWFactory.sol new file mode 100644 index 00000000..704f1068 --- /dev/null +++ b/plan/agw/research/deployment-review-2026-10-06/source/src/AGWFactory.sol @@ -0,0 +1,355 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import { AGWFactoryErrors } from "./libraries/Errors.sol"; + +import { Clones } from "@openzeppelin/contracts/proxy/Clones.sol"; + +import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import { + AccessControlDefaultAdminRulesUpgradeable +} from "@openzeppelin/contracts-upgradeable/access/extensions/AccessControlDefaultAdminRulesUpgradeable.sol"; +import { PausableUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol"; +import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +import { IAGWFactory } from "./interfaces/IAGWFactory.sol"; +import { IAGWInit } from "./interfaces/IAGWInit.sol"; +import { OwnerIntent } from "./libraries/Types.sol"; +import { OwnerAuthLib } from "./libraries/OwnerAuthLib.sol"; + +/** + * @title AGWFactory + * @notice Deploys `AGW` clones at addresses computable before deployment, and is the + * root of trust for wallet identity. + * + * @dev - Wallet addresses are deterministic and predictable before deployment, so counterfactual + * funding is a supported flow. + * - This registry is the only proof of a wallet's provenance: anyone can deploy a contract + * with a lying `owner()` view. The audit chain is destination account, wallet, this + * registry, owner. + * - The owner is the caller, or the signer of an `OwnerIntent` naming this owner, index and + * wallet, presented by the intent's `executor`. Deploying a wallet owned by someone else + * without that owner's signature is impossible. + * - Holds no funds, never touches a wallet after deployment, and has no setter for the + * wallet implementation. + * - Deployed behind an ERC-1967 UUPS proxy; the proxy address is the permanent, + * user-facing factory address and never changes across logic upgrades. + */ +contract AGWFactory is + Initializable, + AccessControlDefaultAdminRulesUpgradeable, + PausableUpgradeable, + UUPSUpgradeable, + IAGWFactory +{ + /// @dev Holder may pause wallet deployment. + bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); + + /// @dev Holder may unpause wallet deployment. + bytes32 public constant OPERATOR_ROLE = keccak256("OPERATOR_ROLE"); + + /** + * @dev Delay on the two-step admin transfer. + * + * - The admin's one real power is authorising a UUPS upgrade of this logic, which is the + * single action that can permanently strand counterfactually funded addresses. + * - The extension makes `grantRole` and `renounceRole` on the admin role revert, forcing + * the scheduled flow. + */ + uint48 internal constant DEFAULT_ADMIN_DELAY = 2 days; + + /// @dev All bases use ERC-7201 namespaced storage, so these three variables occupy slots 0, 1 + /// and 2. Order is frozen, and a layout test asserts it from `forge inspect` output. + + /// @dev owner => wallets deployed for them, doubling as the next index so a count and an index + /// can never drift apart. `uint96` matches `WalletRecord.index`, so no narrowing cast + /// exists anywhere in this contract. + mapping(address => uint96) internal _walletCount; + + /// @dev wallet => its record; a zero owner means not deployed by this factory. This is the + /// entire registry: existence, owner and index from one packed slot per wallet. + mapping(address => IAGWFactory.WalletRecord) internal _records; + + /** + * @notice The canonical AGW logic contract all clones delegate to. + * + * @dev - Written once, in `initialize`. There is no setter: a function able to rewrite this + * would silently move every predicted address and strand counterfactually funded + * wallets, with no migration path to recover them. + * - Declared last and appended to only. Every future variable goes after it, and nothing + * is inserted or reordered before it, or address derivation breaks with no remedy. + * - `internal`, exposed only through `walletImplementation()`, so no second + * auto-generated getter with a different selector exists. + */ + address internal _walletImplementation; + + // No storage gap: this is a leaf UUPS implementation, so a future version simply appends after + // _walletImplementation. + + /// @dev Locks the logic contract so it can never be initialised directly. + constructor() { + _disableInitializers(); + } + + /** + * @notice Configures the proxy. Callable once, at deployment. + * + * @dev - Reverts with `ZeroAddress` if either address is zero. + * - Sets the admin with the two-day transfer delay, initialises pausable, and records + * the wallet implementation. + * - Makes no external calls and deploys nothing. Pauser and operator membership are + * granted afterwards by the admin through the standard `grantRole`. + * + * @param admin Receives the default admin role. + * @param walletImplementation_ Logic contract every wallet clone will delegate to. + */ + function initialize(address admin, address walletImplementation_) external initializer { + if (admin == address(0) || walletImplementation_ == address(0)) revert AGWFactoryErrors.ZeroAddress(); + + __AccessControlDefaultAdminRules_init(DEFAULT_ADMIN_DELAY, admin); + __Pausable_init(); + // UUPSUpgradeable in OZ 5.7.0 has no initializer; calling one does not compile. + + _walletImplementation = walletImplementation_; + } + + /** + * @notice Deploys the caller's next agent wallet and initialises it. + * + * @dev - Reverts while paused, and with `ImplementationNotSet` if the wallet implementation + * is unset. The latter is reachable only on a proxy deployed without its atomic init + * call; without it, `Clones` would deploy a permanently uninitialisable clone. + * - Advances the caller's wallet count and writes the registry record before the single + * external call, which is what makes a reentrant deploy unable to reuse an index. + * There is deliberately no reentrancy guard; the effect ordering is the protection. + * - Salt is the owner and the factory-assigned sequential index only. Nothing + * rules-related enters the derivation. + * - The owner appears twice, in the salt and in the immutable args, on purpose; + * removing either changes every future address. + * - Calls `initializeAccount` on the new clone. Any revert bubbles and the whole + * deployment unwinds, so an uninitialised wallet can never exist on-chain. + * - Emits `WalletDeployed`. + * + * @param label Free-form label, emitted in the event and never stored. + * @return wallet Address of the newly deployed wallet. + */ + function deployWallet(string calldata label) external whenNotPaused returns (address wallet) { + address implementation = _walletImplementation; + if (implementation == address(0)) revert AGWFactoryErrors.ImplementationNotSet(); + + address owner = msg.sender; + wallet = _deploy(implementation, owner, _walletCount[owner], label); + } + + /** + * @notice Deploys wallet `intent.index` for `intent.owner`, on the owner's signature. + * + * @dev - The index is EXPLICIT and must equal the owner's current count, and `intent.wallet` must + * be the address this call deploys. So a signed intent is idempotent and unmovable: a + * replay fails on the index, and nobody can advance an owner's count without the owner's + * signature. + * - `msg.sender == intent.owner` needs no signature (the caller is the owner, exactly as in + * the single-argument form). Any other caller must be `intent.executor` (non-zero) and + * must carry the owner's signature, before the deadline. + * - Grant and exec fields of the intent are ignored here; the wallet checks those. + * - Every check runs before `_deploy`, which advances the count before its one external + * call — the same effect ordering the single-argument form relies on. + * + * @param intent The owner's intent. Only `owner`, `wallet`, `executor`, `index`, `deadline` and + * `signerChainId` are read here. + * @param sig The owner's signature over `intent`; ignored when the caller is the owner. + * @param label Free-form label, emitted and never stored. Not signed. + * @return wallet The deployed wallet. + */ + function deployWalletWithSig(OwnerIntent calldata intent, bytes calldata sig, string calldata label) + external + whenNotPaused + returns (address wallet) + { + address implementation = _walletImplementation; + if (implementation == address(0)) revert AGWFactoryErrors.ImplementationNotSet(); + + address owner = intent.owner; + if (owner == address(0)) revert AGWFactoryErrors.ZeroAddress(); + + uint96 index = intent.index; + uint96 next = _walletCount[owner]; + if (index != next) revert AGWFactoryErrors.IndexMismatch(next, index); + + address predicted = _predict(implementation, owner, index); + if (intent.wallet != predicted) revert AGWFactoryErrors.IntentWalletMismatch(predicted, intent.wallet); + + if (msg.sender != owner) { + if (intent.executor == address(0) || msg.sender != intent.executor) { + revert AGWFactoryErrors.ExecutorMismatch(intent.executor, msg.sender); + } + if (block.timestamp > intent.deadline) revert AGWFactoryErrors.SignatureExpired(intent.deadline); + if (!OwnerAuthLib.isOwnerSig(owner, OwnerAuthLib.intentDigest(address(this), intent), sig)) { + revert AGWFactoryErrors.InvalidOwnerSignature(); + } + } + + wallet = _deploy(implementation, owner, index, label); + } + + /// @inheritdoc IAGWFactory + function domainSeparator(uint256 signerChainId) external view returns (bytes32) { + return OwnerAuthLib.domainSeparator(address(this), signerChainId); + } + + /** + * @dev The deployment tail shared by `deployWallet` and `deployWalletWithSig`. BYTE-FOR-BYTE the logic the + * single-argument form always had: count advance → salt → args → clone → record → + * initializeAccount → event. Every caller has run all of its checks before calling this. + * + * - The count advances and the record is written before the single external call, which is + * what makes a reentrant deploy unable to reuse an index. + * - Salt and args are frozen forever: counterfactual funding relies on them. + */ + function _deploy(address implementation, address owner, uint96 index, string calldata label) + internal + returns (address wallet) + { + _walletCount[owner] = index + 1; + + bytes32 salt = keccak256(abi.encode(owner, index)); + // 40 bytes: owner at 0-19, factory at 20-39. Frozen forever. + bytes memory args = abi.encodePacked(owner, address(this)); + + wallet = Clones.cloneDeterministicWithImmutableArgs(implementation, args, salt); + + _records[wallet] = WalletRecord({ owner: owner, index: index }); + + IAGWInit(wallet).initializeAccount(); + + emit WalletDeployed(owner, index, wallet, label); + } + + /** + * @dev The address derivation, shared by `predictWallet` and `deployWalletWithSig`. + * Mirrors `_deploy`'s salt and args exactly; any divergence is a critical bug. + */ + function _predict(address implementation, address owner, uint96 index) internal view returns (address) { + bytes32 salt = keccak256(abi.encode(owner, index)); + bytes memory args = abi.encodePacked(owner, address(this)); + return Clones.predictDeterministicAddressWithImmutableArgs(implementation, args, salt, address(this)); + } + + /** + * @notice The address wallet `index` of `owner` has, or will have. + * + * @dev - Reverts with `ImplementationNotSet` if the implementation is unset, and with + * `IndexOutOfRange` if `index` is beyond the next deployable one. Funding an address + * further out than that would put money in a permanent hole. + * - Mirrors `deployWallet`'s salt and args derivation exactly. Any divergence between + * the two is a critical bug, because counterfactual funding relies on this answer. + * - `deployed` is derived from the sequential index rather than `extcodesize`, which + * would misreport during construction and cost more. + * + * @param owner Wallet owner to predict for. + * @param index Wallet index under that owner. + * @return wallet The deterministic address for that owner and index. + * @return deployed True if that wallet already exists. + */ + function predictWallet(address owner, uint256 index) external view returns (address wallet, bool deployed) { + address implementation = _walletImplementation; + if (implementation == address(0)) revert AGWFactoryErrors.ImplementationNotSet(); + + uint256 next = _walletCount[owner]; + if (index > next) revert AGWFactoryErrors.IndexOutOfRange(index, next); + + wallet = _predict(implementation, owner, uint96(index)); + deployed = index < next; + } + + /** + * @notice How many wallets `owner` has; also the index the next deploy will use. + * @dev Full enumeration is this call plus `predictWallet(owner, 0..count-1)`, which is why no + * per-owner wallet array is stored: it cannot be lost or desynced. + * @param owner Owner to count wallets for. + * @return The number of wallets deployed for that owner. + */ + function walletCount(address owner) external view returns (uint256) { + return _walletCount[owner]; + } + + /** + * @notice The owner of `wallet`, or address(0) if this factory did not deploy it. + * @param wallet Wallet to look up. + * @return The recorded owner, or the zero address. + */ + function ownerOf(address wallet) external view returns (address) { + return _records[wallet].owner; + } + + /** + * @notice True only for wallets this factory deployed. + * @param account Address to test. + * @return Whether this factory deployed it. + */ + function isWallet(address account) external view returns (bool) { + return _records[account].owner != address(0); + } + + /** + * @notice The wallet's index under its owner. + * @dev Reverts with `NotAWallet` rather than returning zero, because zero is a valid index. + * @param wallet Wallet to look up. + * @return Its index under its owner. + */ + function indexOf(address wallet) external view returns (uint256) { + WalletRecord memory record = _records[wallet]; + if (record.owner == address(0)) revert AGWFactoryErrors.NotAWallet(wallet); + return record.index; + } + + /** + * @notice The canonical wallet logic contract. + * @dev The only getter for it; the variable is `internal` precisely so no second, + * auto-generated getter exists. Exposed so the SDK can verify its local derivation + * mirror before showing a user an address to fund. + * @return The wallet implementation every clone delegates to. + */ + function walletImplementation() external view returns (address) { + return _walletImplementation; + } + + /** + * @notice Pauses wallet deployment. + * @dev - Gates `deployWallet` only. Views are never gated, and deployed wallets are + * unaffected, since the factory has no reach into them. + * - While paused, a user who funded a predicted address cannot deploy it. Availability + * only; funds are never lost. + */ + function pause() external onlyRole(PAUSER_ROLE) { + _pause(); + } + + /** + * @notice Resumes wallet deployment. + * @dev The role split is deliberate: pause is a cheap panic button, unpause a considered + * operational act. A pauser cannot unpause, and an operator cannot pause. + */ + function unpause() external onlyRole(OPERATOR_ROLE) { + _unpause(); + } + + /** + * @dev Authorises a UUPS upgrade of this logic contract. + * + * - Restricted to the default admin role; reverts with `ZeroAddress` on a zero + * implementation. + * - Every future logic upgrade must leave the salt formula, the immutable-args encoding, + * the value of `_walletImplementation` and the storage layout unchanged. Upgrades exist + * for logic bugs only; the address derivation is frozen forever. + * - New variables are appended after `_walletImplementation`; base contracts are never + * added, removed or reordered, and nothing may come to share that slot. + * - Not `view` although solc suggests it: the base declares `_authorizeUpgrade` non-view, + * and an override cannot add mutability restrictions the base does not have. + * + * @param newImplementation The logic contract being upgraded to. + */ + function _authorizeUpgrade(address newImplementation) internal override onlyRole(DEFAULT_ADMIN_ROLE) { + if (newImplementation == address(0)) revert AGWFactoryErrors.ZeroAddress(); + } +} diff --git a/plan/agw/research/deployment-review-2026-10-06/source/src/interfaces/IAGW.sol b/plan/agw/research/deployment-review-2026-10-06/source/src/interfaces/IAGW.sol new file mode 100644 index 00000000..24155866 --- /dev/null +++ b/plan/agw/research/deployment-review-2026-10-06/source/src/interfaces/IAGW.sol @@ -0,0 +1,199 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import { Session } from "smartsessions/DataTypes.sol"; + +import { OwnerIntent, RulesType, CheckpointKind } from "../libraries/Types.sol"; + +/** + * @title IAGW — the Agentic Wallet's external surface. + * @notice The wallet's complete external surface. `AGW is IAGW`, so the compiler rejects any function + * declared here that the contract does not implement with the identical signature — this file + * cannot drift from the contract. Errors live in `AGWErrors` (`libraries/Errors.sol`); types in + * `libraries/Types.sol`. + * + * @dev `rulesId` is the engine's `permissionId`: `rulesId == permissionId` for every rules set this + * wallet grants. SmartSession's own vocabulary (`Session`, `PermissionId`) is kept at the engine + * boundary. + * + * @dev The events are a CONSUMED WIRE FORMAT. Changing a name, a parameter type, or which parameters + * are indexed changes the topic hash and silently breaks every deployed indexer and monitoring + * rule reading the old one. Add events freely; alter an existing one only as a deliberate, + * announced break. + */ +interface IAGW { + // ═══════════════════════════════ AGW_1: EVENTS ═══════════════════════════════ + + /// @notice The one-shot factory initialisation completed; the wallet is live. + event AccountInitialized(address indexed owner, address indexed engine); + + /// @notice The owner executed directly, with no policy consulted. + /// @dev The calldata is hashed rather than logged: an owner batch can be large, and the + /// hash is what an observer needs to tie the event to the transaction it came from. + event OwnerExecuted(bytes32 indexed mode, bytes32 executionCalldataHash); + + /// @notice The owner executed through `executeWithSig`, authorised by a signed OwnerIntent. + /// @dev A separate event from `OwnerExecuted` so an indexer can tell a relayed owner action + /// from one the owner submitted directly. The lane position ties it to the intent. + event OwnerExecutedWithSig(bytes32 indexed mode, bytes32 executionCalldataHash, uint192 nonceKey, uint64 nonceSeq); + + /// @notice A validator module was installed. + event ModuleInstalled(uint256 moduleTypeId, address module); + + /// @notice A validator module was uninstalled. + event ModuleUninstalled(uint256 moduleTypeId, address module); + + /// @notice A module's uninstall callback reverted or exhausted its gas stipend. + /// @dev THE MODULE WAS STILL REMOVED. This is the audit trail for a module that tried to + /// resist its own removal, not a failure of the uninstall. + event UninstallCallbackFailed(address module); + + /// @notice A rules set was granted. + /// @dev `mode` and `chainHash` are DERIVED from the policy envelope's chain namespace, not + /// declared by anyone — nobody in this system states a rules set's kind. The hash is + /// INDEXED so an indexer can filter rules by chain without decoding; the string is carried + /// as data because the wallet already holds it in memory after the action-0 decode + /// (~200 gas) and it makes every explorer record human-readable. + event RulesGranted(bytes32 indexed rulesId, RulesType mode, bytes32 indexed chainHash, string chainNamespace); + + /// @notice A rules set was revoked. + event RulesRevoked(bytes32 indexed rulesId); + + /// @notice An agent request passed validation and was dispatched. + /// @dev Rules-level attribution on the Push side, without touching the gateway's own frozen + /// event. `agent` is the sender (always equal to the rules set's agent). `callsHash` is + /// `keccak256(executionCalldata)` — what ties this record to the exact call executed. + /// A deliberate wire-format break from the earlier `(rulesId, nonceKey, nonceSeq, opHash)` + /// shape; it ships with the new deployment. + event RulesActionAuthorized(bytes32 indexed rulesId, address indexed agent, bytes32 callsHash); + + /// @notice The owner side of this wallet changed. The wallet's checkpoint counter is now `seq`. + /// @dev Emitted once per owner-door call (before the call runs), once per grant and once per + /// revoked id. Never emitted by the agent door. On-chain consumers compare + /// `checkpointCount()` against a snapshot; `kind` and `ref` are for indexers — `ref` is + /// `keccak256(abi.encode(target, value, callData))` for `OWNER_ACTION` and the `rulesId` + /// for `RULES_GRANTED` / `RULES_REVOKED`. + event Checkpointed(uint64 indexed seq, CheckpointKind kind, bytes32 ref, uint64 blockNumber); + + // ═══════════════════════════════ AGW_2: OWNER DOOR ═══════════════════════════════ + + /// @notice The owner door: executes a single call or a batch on the owner's behalf. No policy is + /// ever consulted. Owner only. + function execute(bytes32 mode, bytes calldata executionCalldata) external payable; + + /// @notice The owner door, authorised by a signed OwnerIntent instead of `msg.sender`. Relayable by + /// `intent.executor` only. + function executeWithSig( + bytes32 mode, + bytes calldata executionCalldata, + OwnerIntent calldata intent, + bytes calldata sig + ) external; + + // ═══════════════════════════════ AGW_3: AGENT DOOR ═══════════════════════════════ + + /// @notice The agent door. Callable only by the agent `rulesId` names — a Push address (an EOA, or + /// the UEA of an external key); every call is checked by the rules set's policy. + function executeAsAgent(bytes32 rulesId, bytes32 mode, bytes calldata executionCalldata) external; + + /// @notice The agent a rules set names on this wallet, or zero if it names none (unknown or + /// revoked id, non-canonical session validator, malformed config). + function agentOf(bytes32 rulesId) external view returns (address); + + // ═══════════════════════════════ AGW_4: RULES LIFECYCLE ═══════════════════════════════ + + /// @notice Grants one rules set to an agent. Owner or the wallet itself. + /// @return rulesId The engine's `permissionId` for the new rules set. + function grantRules(Session calldata session) external returns (bytes32 rulesId); + + /// @notice `grantRules`, authorised by the owner's signed OwnerIntent. + /// @return rulesId The engine's `permissionId` for the new rules set. + function grantRulesWithSig(Session calldata session, OwnerIntent calldata intent, bytes calldata sig) + external + returns (bytes32 rulesId); + + /// @notice Revokes one rules set. Owner or the wallet itself. + function revokeRules(bytes32 rulesId) external; + + /// @notice Revokes every rules set on this wallet. Owner or the wallet itself. + function revokeAllRules() external; + + /// @notice Factory-only, once: installs the session engine as the account's sole validator. + function initializeAccount() external; + + /// @notice Installs a validator module. Owner only. + function installModule(uint256 moduleTypeId, address module, bytes calldata initData) external; + + /// @notice Uninstalls a validator module. Owner only; removal always proceeds. + function uninstallModule(uint256 moduleTypeId, address module, bytes calldata deInitData) external; + + // ═══════════════════════════════ AGW_5: VIEWS ═══════════════════════════════ + + /// @notice Whether `module` is installed under `moduleTypeId`. + function isModuleInstalled(uint256 moduleTypeId, address module, bytes calldata) external view returns (bool); + + /// @notice Whether this account supports an ERC-7579 module type. True only for validators. + function supportsModule(uint256 moduleTypeId) external pure returns (bool); + + /// @notice Whether this account supports an ERC-7579 execution mode. + function supportsExecutionMode(bytes32 mode) external pure returns (bool); + + /// @notice The wallet's owner, read from the clone's immutable args. + function owner() external view returns (address); + + /// @notice The factory that deployed this wallet. + function factory() external view returns (address); + + /// @notice Next expected sequence number in an owner lane (`OWNER_LANE_FLAG` set), consumed by + /// `executeWithSig`. + function getNonce(uint192 nonceKey) external view returns (uint64); + + /// @notice The salt the next grant will use. + function grantNonce() external view returns (uint64); + + /// @notice Owner-side checkpoints so far. Any owner-door call, grant or revoke moves it; agent + /// actions never do. + function checkpointCount() external view returns (uint64); + + /// @notice `block.number` of the latest checkpoint, or zero if none. Consumers compare counts, not + /// blocks: several checkpoints can share a block. + function lastCheckpointBlock() external view returns (uint64); + + /// @notice The OwnerIntent EIP-712 domain separator for a signer on `signerChainId`. Identical to + /// the factory's: the factory is the verifying contract. + function domainSeparator(uint256 signerChainId) external view returns (bytes32); + + /// @notice The ERC-7579 account id, in vendor.account.semver form. + function accountId() external pure returns (string memory); + + /// @notice The permission engine this wallet installs as its default validator. + function SESSION_ENGINE() external view returns (address); + + /// @notice The canonical action policy (URP) every rules set on this wallet must name. + function RULES_POLICY() external view returns (address); + + /// @notice The canonical session validator every rules set on this wallet must name — the sender + /// validator that confirms the caller is the rules set's agent. + function SESSION_VALIDATOR() external view returns (address); + + /// @notice The Push-side gateway this wallet's agents send through. + function UNIVERSAL_GATEWAY_PC() external view returns (address); + + /// @notice ERC-165 support check: ERC-165 and the two token-receiver interfaces only. + function supportsInterface(bytes4 interfaceId) external pure returns (bool); + + /// @notice Always the ERC-1271 failure value: the wallet never signs as an ERC-1271 party. + function isValidSignature(bytes32, bytes calldata) external pure returns (bytes4); + + /// @notice Accepts ERC-721 transfers. + function onERC721Received(address, address, uint256, bytes calldata) external pure returns (bytes4); + + /// @notice Accepts ERC-1155 transfers. + function onERC1155Received(address, address, uint256, uint256, bytes calldata) external pure returns (bytes4); + + /// @notice Accepts batched ERC-1155 transfers. + function onERC1155BatchReceived(address, address, uint256[] calldata, uint256[] calldata, bytes calldata) + external + pure + returns (bytes4); +} diff --git a/plan/agw/research/deployment-review-2026-10-06/source/src/interfaces/IUniversalRulesPolicy.sol b/plan/agw/research/deployment-review-2026-10-06/source/src/interfaces/IUniversalRulesPolicy.sol new file mode 100644 index 00000000..abde64fd --- /dev/null +++ b/plan/agw/research/deployment-review-2026-10-06/source/src/interfaces/IUniversalRulesPolicy.sol @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import { IActionPolicy } from "smartsessions/interfaces/IPolicy.sol"; +import { ConfigId } from "smartsessions/DataTypes.sol"; + +import { RulesType, VmFamily, Config, ModeSlot, NativeConfig, SvmConfig } from "../libraries/Types.sol"; + +/** + * @title IUniversalRulesPolicy (IURP) + * @notice The engine-facing functions (`initializeWithMultiplexer`, `checkAction`) and + * `supportsInterface` are INHERITED from upstream `IActionPolicy`, never repeated here. + * Duplicating a signature across a trust boundary is the drift this project removes. + * + * @dev INHERITANCE SHAPE, verified by compiled probe. `IActionPolicy is IPolicy is IERC165`, + * so IERC165 already arrives transitively and listing it again as + * `is IActionPolicy, IERC165` fails with `Error (5005): Linearization of inheritance + * graph impossible` — C3 linearization requires the most-derived base first. Single + * inheritance is both correct and sufficient; do not "complete" it by adding IERC165. + * + * @dev Errors live in `UniversalRulesPolicyErrors` (`libraries/Errors.sol`); the policy's types live + * in `libraries/Types.sol`. + * + * @dev Revert data truncates to 32 bytes through the engine (`PolicyLib.sol:139-152`, + * `_maxCopy: 32`, surfacing as `PolicyCheckReverted(bytes32)`). The 4-byte selector + * survives; multi-argument custom errors do not round-trip to the caller. Errors below + * still carry their arguments because URP is also called directly (owner path, + * executor module) where they do survive. + */ +interface IUniversalRulesPolicy is IActionPolicy { + // ═══════════════════════════════ URP_1: EVENTS ═══════════════════════════════ + + /// @dev `mode`, `vm` and `chainHash` are all DERIVED from the envelope's chain string, not + /// declared. For a universal config `chainHash` has additionally been verified against EVERY + /// listed asset's own `SOURCE_CHAIN_NAMESPACE()`. `vm` was added with the SVM rulebook (1.1.0). + event RulesConfigured( + ConfigId indexed id, + address indexed multiplexer, + address indexed account, + RulesType mode, + VmFamily vm, + bytes32 chainHash + ); + /// @dev Emitted on every successful native check. Mirrors the effects: `value` and `amount` may + /// both be zero, and the event still fires, because `callsUsed` still moved. + event NativeCallMetered( + ConfigId indexed id, address indexed multiplexer, address indexed account, uint256 value, uint256 amount + ); + /// @dev `token` is the PRC20 whose counter moved — one rules set meters each listed asset separately. + event OutboundMetered( + ConfigId indexed id, address indexed multiplexer, address indexed account, address token, uint256 amount + ); + event RevertCredited( + bytes32 indexed outboundTxId, ConfigId indexed id, address indexed account, address token, uint256 amountApplied + ); + + // ═══════════════════════════════ URP_2: POLICY ═══════════════════════════════ + + /// @notice Exact-equality assertion on every per-asset spend counter — the change-flow race guard. + /// @dev `expectedSpent[i]` is the expected `spent` of `assets[i]`, in the order the rules set + /// listed them; the array must have exactly one entry per asset. Keyed on the SESSION_ENGINE + /// immutable; there is no multiplexer argument to get wrong. + function assertSpent(ConfigId id, address account, uint256[] calldata expectedSpent) external view; + + /// @notice Credit a confirmed far-side failure back to one asset's spend counter. + /// @dev Executor-module-only, once per outboundTxId, saturating. `token` names the counter and + /// must be a listed asset. Ships inert — Push core's calling side is not yet landed. + function creditRevert(ConfigId id, address account, bytes32 outboundTxId, address token, uint256 amount) external; + + /// @notice The native change-flow race guard: exact equality on all three counters. + /// @dev Reverts `WrongModeForCall(UNIVERSAL)` on a universal config and `NotInitialized` on a + /// ghost, for the same reason the universal overload does — this exists to catch stale + /// belief, so it must not have a silent-pass mode. + function assertSpent( + ConfigId id, + address account, + uint256 expectedValueSpent, + uint256 expectedAmountSpent, + uint32 expectedCalls + ) external view; + + // ═══════════════════════════════ URP_3: VIEWS ═══════════════════════════════ + + /// @notice The universal config. Reverts `WrongModeForCall(NATIVE)` on a native slot; returns a + /// zeroed struct on an EMPTY slot, exactly as it always has. + function getConfig(ConfigId id, address account) external view returns (Config memory); + + /// @notice The native config. Reverts `WrongModeForCall(UNIVERSAL)` on a universal slot; returns + /// a zeroed struct on an empty slot. + function getNativeConfig(ConfigId id, address account) external view returns (NativeConfig memory); + + /// @notice The SVM config. Reverts `WrongModeForCall(NATIVE)` on a native slot and + /// `WrongVmForCall(EVM)` on an EVM universal slot; returns a zeroed struct on an empty + /// slot, the same convention as the other two getters. + function getSvmConfig(ConfigId id, address account) external view returns (SvmConfig memory); + + /// @notice The mode record. NEVER REVERTS — the documented first call for any integrator that + /// does not already know a rules set's mode. An empty slot returns + /// `(initialized: false, mode: UNIVERSAL, vm: EVM, chainHash: 0)`, where the mode and vm + /// values are meaningless. An initialised entry always carries its chain. + function getMode(ConfigId id, address account) external view returns (ModeSlot memory); + + /// @notice The hash this URP derives NATIVE from: `keccak256("eip155:" ‖ decimal(block.chainid))`. + /// @dev Exposed so the deploy script asserts what URP will ACTUALLY derive rather than + /// recomputing the formula and agreeing with itself, and so an SDK can confirm the exact + /// native chain string it should emit. Computed, never stored. + function pushChainHash() external view returns (bytes32); + + /// @notice Whether a Push-core outbound id has already been credited back. + function isCredited(bytes32 outboundTxId) external view returns (bool); +} diff --git a/plan/agw/research/deployment-review-2026-10-06/source/src/libraries/AgentConfigLib.sol b/plan/agw/research/deployment-review-2026-10-06/source/src/libraries/AgentConfigLib.sol new file mode 100644 index 00000000..85461cb2 --- /dev/null +++ b/plan/agw/research/deployment-review-2026-10-06/source/src/libraries/AgentConfigLib.sol @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +/** + * @title AgentConfigLib + * @notice The one decoder of a rules set's agent config — `sessionValidatorInitData` — shared by the + * session validator, which enforces it, and the wallet, which reads it for the agent door's + * pre-check and the `agentOf` view. One decoder, so the two can never disagree. + * + * @dev THE FORMAT, FROZEN: `abi.encode(address agent)` — exactly 32 bytes, the upper 12 bytes zero, + * the address non-zero. The agent is a Push address: an EOA, or the UEA of an external key. + * The config is an input to every permission id (`IdLib`), so changing this format changes + * every id; it may never change. + * + * Never reverts. A config that is not exactly that shape decodes to `address(0)`, which no + * caller can ever be, so every consumer fails closed on it. + */ +library AgentConfigLib { + /// @dev Byte length of a well-formed config: one ABI word. + uint256 internal constant CONFIG_LENGTH = 32; + + /** + * @notice The agent named by `config`, or `address(0)` if `config` is malformed. + * @param config The rules set's `sessionValidatorInitData`. + * @return agent The agent's Push address; zero when the config is not exactly one ABI word + * holding a non-zero address with clean upper bytes. + */ + function decode(bytes memory config) internal pure returns (address agent) { + if (config.length != CONFIG_LENGTH) return address(0); + uint256 word; + assembly ("memory-safe") { + word := mload(add(config, 0x20)) + } + if (word >> 160 != 0) return address(0); + // forge-lint: disable-next-line(unsafe-typecast) + agent = address(uint160(word)); // the upper 96 bits were just checked zero, nothing truncates + } +} diff --git a/plan/agw/research/deployment-review-2026-10-06/source/src/libraries/Errors.sol b/plan/agw/research/deployment-review-2026-10-06/source/src/libraries/Errors.sol new file mode 100644 index 00000000..edb98108 --- /dev/null +++ b/plan/agw/research/deployment-review-2026-10-06/source/src/libraries/Errors.sol @@ -0,0 +1,402 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import { ConfigId } from "smartsessions/DataTypes.sol"; + +import { RulesType, VmFamily } from "./Types.sol"; + +/** + * @title Errors — every custom error in the AGW system, one library per contract. + * @notice `AGWErrors` (the wallet), `AGWFactoryErrors`, `UniversalRulesPolicyErrors` (URP) and + * `AgentValidatorErrors`. Moving an error into a library does not change its selector: a + * selector is `bytes4(keccak256(name ‖ argument types))`, independent of where the error + * is declared. + */ + +/// @title AGWErrors +/// @notice Custom errors of the AGW (wallet). +/// @dev Errors used by ExecutionLib live here too, so the libraries do not need an error home +/// of their own. +/// @dev THE ERRORS BELOW ARE NEVER TRUNCATED. They revert directly from the wallet, not through +/// the engine's 32-byte `PolicyCheckReverted` wrapper, so every argument survives intact. +/// URP's diagnostic-first argument ordering (which exists only because of that truncation) +/// deliberately does NOT apply here — do not reorder these for consistency with it. +library AGWErrors { + // ───────────────────── access control ───────────────────── + + error CallerIsNotOwner(); + error CallerIsNotFactory(); + + // ─────────────────── initialisation ─────────────────── + + error AlreadyInitialized(); + /// @dev Zero address, or a codeless target on install. Also raised by the wallet's constructor + /// when any of the four wiring addresses is zero. + error InvalidModuleAddress(); + + // ──────────────────── module manager ──────────────────── + + error ModuleAlreadyInstalled(address module); + error UnsupportedModuleType(uint256 moduleTypeId); + error ValidatorNotInstalled(address validator); + /// @dev The engine-scoped uninstall guard: uninstalling the permission engine while it still + /// holds live permissions would strand rows it then refuses to reinstall over. Revoke + /// everything first. + error EngineStillHoldsPermissions(); + + // ──────────────────── execution modes ──────────────────── + + /// @dev ONE error for every rejected mode — delegatecall, static, try-exec, and, on the agent + /// door specifically, batch. + error UnsupportedExecutionMode(); + + // ──────────────────── the agent door ──────────────────── + + /// @dev `executeAsAgent`: the caller is not the agent named by `rulesId` on this wallet — + /// including when the id is unknown, revoked, or names a session validator other than the + /// canonical one (all of which have no agent). Carries both values: this error is raised by + /// the wallet directly and is never truncated. + error CallerIsNotAgent(bytes32 rulesId, address caller); + /// @dev `executeWithSig`: the intent's sequence number is not the owner lane's next one. + error InvalidNonce(uint192 nonceKey, uint64 expected, uint64 provided); + error ValidationFailed(address authorizer); + error OutsideTimeWindow(uint48 validAfter, uint48 validUntil); + + // ──────────────────── rules set lifecycle ──────────────────── + + error UnknownPermission(bytes32 rulesId); + /// @dev Raised by grantRules's canonical-shape check — the granted session deviates from the + /// shape this system accepts for the DERIVED `RulesType`. Stays for the rules COMMON to + /// both types: user-op policies, ERC-7739, the paymaster permit, the session validator, and + /// the action-policy count. A target that is wrong FOR THE DERIVED TYPE is + /// `RulesTypeMismatch` instead — that distinction is the invariant, stated once. + error MalformedSessionShape(); + + // ──────────────────── native rules set shape (grantRules) ──────────────────── + + /// @dev Action count outside 1..MAX_NATIVE_ACTIONS. Zero is refused too: a rules set that + /// authorises nothing is a misconfiguration, not a valid ascetic grant. + /// + /// ZERO IS NOW CHECKED FOR BOTH MODES, BEFORE THE MODE IS KNOWN. The mode is derived from + /// action 0's envelope, so action 0 must exist before anything can be derived — with no + /// actions there is no envelope, no chain, and therefore no mode. A universal session with + /// zero actions consequently reports `TooManyActions(0)` rather than + /// `MalformedSessionShape`. + error TooManyActions(uint256 count); + + /// @dev The same (target, selector) pair twice in one rules set. Both would hash to one actionId, + /// so the second config would overwrite the first — or be refused — depending on engine + /// internals. Refused here instead, where the error can name the pair. + error DuplicateAction(address target, bytes4 selector); + + /// @dev A NATIVE action naming a target no rules set may ever reach: the zero address, the + /// engine's fallback flag, the wallet itself, the engine, URP, the validator, or the + /// factory. Self and engine are the severe ones — both would let an agent reach the + /// wallet's own lifecycle functions through `onlyOwnerOrSelf`. + error ForbiddenActionTarget(address target); + + /// @dev A NATIVE action naming one of the engine's fallback selectors. `0xFFFFFFFF` + /// (value-only) is permitted and is not one of these. + error ForbiddenActionSelector(bytes4 selector); + + /// @dev The type DERIVED from the envelope's chain does not match the action set: a gateway + /// target under the Push chain, or a non-gateway target under a foreign chain. Carries the + /// offending action's index and target, which is why it is distinct from + /// `MalformedSessionShape` — with up to eight actions, "something was wrong" is not a + /// usable diagnostic. + /// + /// IF YOU MEANT A NATIVE MANDATE AND SEE `UNIVERSAL` HERE, THE CHAIN STRING IS NOT + /// BYTE-EXACT `eip155:` OF THIS CHAIN. `"EIP155:42101"`, `"eip155:042101"` and a + /// leading space all hash to not-Push and therefore derive UNIVERSAL. That is deliberate: + /// the hash comparison is the whole rule, and a string parser would be a second rulebook + /// and a heuristic. The SDK prechecks this so a user sees the real cause. + /// + /// ORDER NOTE: under UNIVERSAL the `n != 1` shape rule runs BEFORE the target check, so a + /// malformed chain string on a multi-action session reports `MalformedSessionShape`. + error RulesTypeMismatch(RulesType derived, uint256 actionIndex, address target); + + /// @dev `grantRules`: action 0's policy envelope declares an empty chain string. The wallet + /// performs no other validation of it — a malformed non-empty string derives UNIVERSAL and + /// is then refused against the targets, or against the asset by URP at init. + error EmptyChain(); + + /// @dev `grantRules`: action `actionIndex` declares a different chain than action 0. A rules set + /// is one thing, on one chain, in one mode — which is what makes mixed rules sets impossible + /// by construction rather than by a rule. + error InconsistentChain(uint256 actionIndex); + + // ──────────────────── the agent door, dispatch ──────────────────── + + /// @dev The validated execution's target is the wallet itself or the engine. Fires in + /// `_gateAndDispatch`, AFTER validation — it is the last layer, and it holds even for a + /// session the owner enabled directly on the engine through the owner door, bypassing + /// `grantRules` entirely. Do not move this check before `_validate`. + error ForbiddenDispatchTarget(address target); + + // ─────────────────── the owner-intent doors ─────────────────── + // + // One shape per name, shared with AGWFactory and UniversalMarketplace, so a test encodes one + // selector whichever contract reverts first. + + /// @dev `intent.deadline` has passed. + error OwnerSigExpired(uint48 deadline); + /// @dev The signature is not the owner's over the intent. + error InvalidOwnerSignature(); + /// @dev `intent.wallet` is not this wallet. + error IntentWalletMismatch(address expected, address provided); + /// @dev Presented by someone other than `intent.executor`, or `intent.executor` is zero. + error ExecutorMismatch(address expected, address actual); + /// @dev `intent.sessionHash` is zero or is not the hash of the session being granted. + error IntentSessionMismatch(bytes32 actual); + /// @dev `intent.grantNonce` is not the wallet's current grant nonce. + error IntentGrantNonceMismatch(uint64 expected, uint64 provided); + /// @dev `intent.execCalldataHash` is zero or does not match, or `intent.mode` does not match. + error IntentExecMismatch(bytes32 actualCalldataHash); + /// @dev `executeWithSig` on a nonce key without `OWNER_LANE_FLAG`. + error OwnerLaneRequired(uint192 nonceKey); + + // ──────────────────── used by ExecutionLib ──────────────────── + + /// @dev ExecutionLib.decodeBatch — the only error any library in src/ actually references. + error MalformedBatchCalldata(); +} + +/// @title AGWFactoryErrors +/// @notice Custom errors of `AGWFactory`. +library AGWFactoryErrors { + /// @dev initialize: admin or implementation is zero. + error ZeroAddress(); + /// @dev deploy/predict called on an uninitialised factory. + error ImplementationNotSet(); + /// @dev indexOf on an address this factory did not deploy. + error NotAWallet(address account); + /// @dev predictWallet beyond the next deployable index. + error IndexOutOfRange(uint256 index, uint256 next); + /// @dev deployWalletWithSig: `intent.index` is not the owner's next index. + error IndexMismatch(uint96 expected, uint96 provided); + /// @dev deployWalletWithSig: `intent.wallet` is not the address this call would deploy. + error IntentWalletMismatch(address expected, address provided); + /// @dev deployWalletWithSig: signature path presented by someone other than `intent.executor`, + /// or `intent.executor` is zero. + error ExecutorMismatch(address expected, address actual); + /// @dev deployWalletWithSig: signature path after `intent.deadline`. + error SignatureExpired(uint48 deadline); + /// @dev deployWalletWithSig: the signature is not the owner's over the intent. + error InvalidOwnerSignature(); +} + +/// @title UniversalRulesPolicyErrors +/// @notice Custom errors of the Universal Rules Policy (URP). +/// @dev Revert data truncates to 32 bytes through the engine (`PolicyLib.sol:139-152`, +/// `_maxCopy: 32`, surfacing as `PolicyCheckReverted(bytes32)`). The 4-byte selector +/// survives; multi-argument custom errors do not round-trip to the caller. Errors below +/// still carry their arguments because URP is also called directly (owner path, executor +/// module, init) where they do survive. +library UniversalRulesPolicyErrors { + error ZeroAddress(); + error NotInitialized(ConfigId id, address account); + error AlreadyInitialized(ConfigId id); + /// @dev init: zero, or not in the future. + error InvalidExpiry(uint48 validUntil); + /// @dev init: zero expectedCEA. + error InvalidConfigField(); + /// @dev init, universal (EVM and SVM): the asset list is empty or longer than MAX_ASSETS. Empty is + /// refused because the token is what pins the destination chain: the gateway routes by it. + error AssetListOutOfRange(uint256 length); + /// @dev init, universal: the same token listed twice — the second entry's caps would be dead. + error DuplicateAsset(address token); + /// @dev init: 0 or > MAX_ALLOWED_CALLS. + error AllowListOutOfRange(uint256 length); + error RulesExpired(uint48 validUntil); + error InvalidTarget(address target); + /// @dev Gate 4a. Distinct from InvalidSelector: there is no selector to report, and a zero + /// sentinel would be indistinguishable from a genuine all-zero-selector payload. + error CalldataTooShort(uint256 length); + error InvalidSelector(bytes4 selector); + /// @dev Gate 4c — body below MIN_OUTBOUND_BODY_LEN. + error MalformedOutboundRequest(uint256 length); + /// @dev Gate 5: the request's token is not in the rules set's asset list. Checked on EVERY request, + /// zero amount included — the token decides the destination chain, so an unlisted token is a + /// chain the owner never approved. + error AssetNotAllowed(address token); + error AmountExceedsCap(uint256 amount, uint256 cap); + error TotalSpendCapExceeded(uint256 wouldBeTotal, uint256 cap); + error PCValueExceedsCap(uint256 value, uint256 cap); + error UncappedGasSwapRejected(); + error InvalidRevertRecipient(address expected, address actual); + error RecipientMustBeEmpty(); + error PayloadNotMulticall(); + error BatchSizeOutOfRange(uint256 count); + error ForbiddenInnerTarget(address target); + error CallNotAllowed(address target, bytes4 selector); + error BeneficiaryMismatch(address expected, address actual); + error InnerValueExceedsAllowance(uint256 index, uint256 value, uint256 maxValue); + error MalformedInnerCalldata(); + error SpentMismatch(uint256 expected, uint256 actual); + /// @dev Universal `assertSpent`: one token's counter differs from what the caller composed against. + error AssetSpentMismatch(address token, uint256 expected, uint256 actual); + /// @dev Universal `assertSpent`: the expected array does not have one entry per listed asset. + error SpentLengthMismatch(uint256 expected, uint256 actual); + error CallerIsNotUEModule(address caller); + error AlreadyCredited(bytes32 outboundTxId); + + // ───────────────────────── native mode errors ───────────────────────── + // + // DIAGNOSTIC VALUE FIRST. The engine truncates policy revert data to 32 bytes + // (`PolicyLib.sol:145`), so a caller sees the 4-byte selector plus only the first 28 bytes of + // the FIRST argument. Putting an index or a length first would surface 28 zero bytes and tell + // nobody anything; putting the offending value first surfaces the thing you debug with. + // This ordering applies to URP errors only — wallet errors are never truncated. + + // init + // + // NOT TRUNCATED. The 28-byte rule above applies to `checkAction`, which the engine wraps in + // `PolicyCheckReverted`. `initializeWithMultiplexer` is a plain high-level call from + // `ConfigLib.sol:98-101` inside `enableSessions`, so init reverts BUBBLE WITH FULL DATA. Tests + // assert these with a plain `vm.expectRevert(abi.encodeWithSelector(...))` carrying every + // argument — never `expectUrpGate`. + + /// @dev init: the envelope's `chain` string is empty. The only validation URP performs on the + /// string itself; a malformed non-empty string derives UNIVERSAL and is caught by the + /// asset check instead. + error EmptyChain(); + /// @dev init: the envelope's first word is not `ENVELOPE_VERSION`. Read before anything else is + /// decoded, so most malformed or pre-version blobs land here, named: a two-field + /// `(string, bytes)` envelope starts with its string offset and reports version 64. + error UnsupportedEnvelopeVersion(uint256 version); + + /// @dev init, universal: the asset reports a different source chain than the envelope declares. + /// `declared` first because it is the value the owner can act on. + error ChainMismatch(bytes32 declared, bytes32 assetChain); + + /// @dev init, universal: the asset has no code, is an EOA, or REVERTED when asked for + /// `SOURCE_CHAIN_NAMESPACE()`. + /// + /// AN ASSET THAT *ANSWERS* WITH A NON-STRING, OR WITH NOTHING, REVERTS UNNAMED INSTEAD — + /// the returndata fails ABI decoding in URP's own frame, which `catch` does not see. The + /// no-code and EOA cases are named only because an explicit `code.length` guard runs first; + /// since solc 0.8.10 the compiler omits the `extcodesize` check when return data is + /// expected, so `try/catch` alone would let both through as unnamed reverts. Measured. + error InvalidAsset(address asset); + /// @dev init: native config with a zero target. + error NativeTargetZero(); + /// @dev init AND gate N3. A native config may never name the gateway, and a native config may + /// never be reached by a gateway-targeted request. The mirror of universal gate 3. + error NativeTargetIsGateway(address target); + /// @dev init: a value-only config (`selector == 0xFFFFFFFF`) carrying pins. Refused rather than + /// left to fail closed at N7: such a config can NEVER authorise anything, so it is a + /// misconfiguration the owner believes they granted, not a valid ascetic config. + error ValueOnlyWithPins(); + /// @dev init: a value-only config carrying an amount rule. Same reasoning. + error ValueOnlyWithAmountRule(); + /// @dev init: pins.length > MAX_PINS. + error TooManyPins(uint256 count); + + // check + error TargetMismatch(address actual, address expected); + error SelectorMismatch(bytes4 actual, bytes4 expected); + /// @dev N5: a value-only action carrying 1..3 bytes of calldata. The engine buckets those under + /// `VALUE_SELECTOR` too; URP is where "value-only means empty calldata" becomes true. + error ValueOnlyCalldataNotEmpty(uint256 length); + error ValueExceedsCap(uint256 value, uint256 cap); + error TotalValueExceeded(uint256 newSpent, uint256 cap); + error CalldataTooShortForPin(uint256 actualLength, uint256 index, uint256 needed); + error ArgPinMismatch(bytes32 actual, uint256 index, bytes32 expected); + error CalldataTooShortForAmount(uint256 actualLength, uint256 needed); + error NativeAmountExceedsCap(uint256 amount, uint256 cap); + error TotalNativeAmountExceeded(uint256 newSpent, uint256 cap); + error CallLimitReached(uint32 callsUsed, uint32 maxCalls); + + // views / assertions + /// @dev A getter or assertion was called against the wrong rulebook — `getConfig` on a native + /// slot, or the five-argument `assertSpent` on a universal one. Carries the mode the config + /// ACTUALLY is. An EMPTY slot is not this error: it returns a zeroed struct exactly as + /// before, because an empty slot is a state while a wrong-mode read is a caller bug. + error WrongModeForCall(RulesType actual); + /// @dev A getter or assertion was called against the wrong VM family — `getConfig` on an SVM + /// slot, `getSvmConfig` on an EVM one. Carries the family the config ACTUALLY is. + error WrongVmForCall(VmFamily actual); + + // ───────────────────────── svm mode errors ───────────────────────── + + // init + /// @dev init: zero expectedCEA or gatewayProgram. + error InvalidSvmConfigField(); + /// @dev init: 0 or > MAX_ALLOWED_PROGRAMS. + error ProgramListOutOfRange(uint256 length); + error TooManySvmPins(uint256 count); + error TooManySvmDataPins(uint256 count); + error TooManyCeaAccounts(uint256 count); + /// @dev init: `discriminatorLen` is 0 without `dataless`, non-zero with it, or above 8. + error DiscriminatorLenOutOfRange(uint256 rule, uint8 len); + /// @dev init: two rules on one program that a single request could both match. First-match + /// must be EXACT, or the stricter rule is dead and its pins never run. + error AmbiguousRule(uint256 i, uint256 j); + /// @dev init: a program the rulebook forbids as a target can never be allow-listed either. + error ForbiddenProgramInAllowList(uint256 rule, bytes32 program); + error SvmPinRuleOutOfRange(uint256 pin, uint8 rule); + /// @dev init: account index at or beyond MAX_SVM_ACCOUNTS, or beyond the rule's `maxAccounts`. + error SvmPinIndexOutOfRange(uint256 pin, uint8 accountIndex); + /// @dev init: a rule's fixed account count exceeds the S13 bound, so no request could meet it. + error SvmMaxAccountsOutOfRange(uint256 rule, uint8 maxAccounts); + /// @dev init: two account pins name the same (rule, index). + error DuplicateSvmPin(uint256 first, uint256 second); + /// @dev init: a `ceaAccounts` entry is zero, repeated, or equal to an allow-listed program. + error InvalidCeaAccount(uint256 index); + /// @dev init: `ceaAccounts` does not contain `expectedCEA`, which would switch S18 off for the + /// one account that always holds value. + error CeaAccountsMissExpectedCEA(); + /// @dev init: a data pin with an impossible shape, or a vacuous / impossible comparison value + /// (a ceiling or floor outside the field's range, a zero ratio term, an EQ value with bytes + /// past `len`). See `SvmDataPin` and `URP._dataPinValueValid`. + error SvmDataPinInvalid(uint256 pin); + /// @dev init: every rule must own at least one account pin. HYGIENE, not a guarantee: one + /// authority pin always passes. Which positions must be pinned is the compiler's job. + error RuleWithoutPin(uint256 rule); + + // check + /// @dev S6b. Solana amounts are u64; the node would truncate. Defence in depth. + error AmountExceedsU64(uint256 amount); + /// @dev S11. The recipient must be a 32-byte, non-zero pubkey — the target program. + error RecipientNotPubkey(uint256 length); + /// @dev S12. Execute-only: an empty payload is a funds-only withdraw, never admitted (parity + /// with EVM gate 12). + error SvmPayloadEmpty(); + /// @dev S12. 1 = short header, 2 = short account list, 3 = short ix_data, 4 = trailing bytes. + /// The grammar is the node's `decodePayload`, byte for byte. + error MalformedSvmPayload(uint8 code); + /// @dev S13. Only instruction_id 2 (execute) is admitted. + error SvmInstructionNotExecute(uint8 instructionId); + error SvmAccountsOutOfRange(uint256 count); + error SvmIxDataTooLong(uint256 length); + /// @dev S14. The node signs the payload's target but finalises with the recipient; they must + /// agree or the TSS check fails on Solana at the owner's expense. + error RecipientTargetMismatch(bytes32 recipient, bytes32 target); + /// @dev S15. System, SPL Token, Token-2022, Stake, BPF Loader Upgradeable, Address Lookup Table, + /// the gateway program and the CEA itself. + error ForbiddenTargetProgram(bytes32 program); + /// @dev S16. No rule matches (program, discriminator). Carries the first 8 bytes of ix_data. + error ProgramNotAllowed(bytes32 program, bytes8 discriminator); + /// @dev S16. The rule fixes the account count and the request's differs. + error SvmAccountCountMismatch(uint256 count, uint8 expected); + /// @dev S17. A pinned index does not exist in the request. + error SvmAccountCountBelowPin(uint256 pin, uint256 count, uint8 needed); + error SvmAccountPinMismatch(uint256 pin, uint8 accountIndex, bytes32 expected, bytes32 actual); + /// @dev S17. ix_data is too short for the pin's field. + error SvmDataTooShortForPin(uint256 pin, uint256 ixLen); + error SvmDataPinMismatch(uint256 pin, bytes32 expected, bytes32 actual); + error SvmDataFloorNotMet(uint256 pin, uint256 actual, uint256 floor); + error SvmDataCeilingExceeded(uint256 pin, uint256 actual, uint256 ceiling); + error SvmDataRatioNotMet(uint256 pin, uint256 a, uint256 b, uint64 num, uint64 den); + /// @dev S18. A CEA-controlled account appears at a position the matched rule does not pin to it. + error CeaAccountAtUnpinnedIndex(uint256 accountIndex, bytes32 account); +} + +/// @title AgentValidatorErrors +/// @notice Custom errors of the session validator. +library AgentValidatorErrors { + /// @dev The stored config is not exactly `abi.encode(address agent)` with a non-zero agent. + /// Unreachable through the wallet's grant path, which runs `validateConfig` first; reachable + /// only for a session the owner enabled on the engine directly. + error MalformedConfig(); +} diff --git a/plan/agw/research/deployment-review-2026-10-06/source/src/libraries/Types.sol b/plan/agw/research/deployment-review-2026-10-06/source/src/libraries/Types.sol new file mode 100644 index 00000000..efef214a --- /dev/null +++ b/plan/agw/research/deployment-review-2026-10-06/source/src/libraries/Types.sol @@ -0,0 +1,544 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +/** + * @notice Mirror of push-chain-gateway .../libraries/TypesUGPC.sol + * @dev MUST match field-for-field and in order. Verified against + * contracts/evm-gateway/src/libraries/TypesUGPC.sol. + */ +struct UniversalOutboundTxRequest { + bytes recipient; // raw destination address on source chain (bytes for SVM compat) + address token; // PRC20 token address on Push Chain + uint256 amount; // amount to withdraw (burn on Push, unlock at origin) + uint256 gasLimit; // gas limit for fee quote; 0 = per-chain default + uint256 gasPrice; // gas price override; 0 = per-chain default + uint256 maxPCForGas; // max native PC for gas swap; 0 = no cap + bytes payload; // ABI-encoded calldata to execute on origin chain + address revertRecipient; // address to receive funds in case of revert +} + +/** + * @notice Mirror of push-chain-core .../libraries/Types.sol + * @dev Batch call entry for multicall execution. + */ +struct Multicall { + address to; + uint256 value; + bytes data; +} + +/// @dev bytes4(keccak256("UEA_MULTICALL")) — magic prefix for multicall payloads. +bytes4 constant MULTICALL_SELECTOR = bytes4(keccak256("UEA_MULTICALL")); + +/** + * @dev The two kinds of rules set. Declared by the owner at grant, asserted by the wallet, stored by + * URP as the config's mode. + * + * DECLARED ONCE, HERE, AND IMPORTED BY BOTH THE WALLET AND `IUniversalRulesPolicy`. Two enums with identical + * values that must always agree is the duplication this file exists to prevent — see the note + * on `SEND_OUTBOUND_SELECTOR` below. The wallet asserts the declared type against the action + * set at grant; URP stores it and branches on it at validation. They must be the same type. + * + * `UNIVERSAL` is the zero value, so an uninitialised slot reads as `UNIVERSAL`. That is why + * URP's `ModeSlot` carries an explicit `initialized` flag and never infers emptiness from the + * mode alone. + */ +enum RulesType { + UNIVERSAL, + NATIVE +} + +/** + * @dev Which destination VM a UNIVERSAL rules set targets. Derived by URP from the envelope's chain + * namespace prefix (`eip155:` / `solana:`) at config init; the wallet never reads it, because + * its grant rules are identical for every non-Push chain. + * + * `EVM` MUST STAY THE ZERO VALUE. URP's `ModeSlot` entries written before this enum existed + * read 0 in the byte that now holds it, and every one of them is an EVM rules set. + */ +enum VmFamily { + EVM, + SVM +} + +/** + * @dev Mirrors of engine constants that are not importable — `IdLib.VALUE_SELECTOR` is `internal` + * to a library, and the fallback flags are file-level constants in the vendored fork. + * + * MIRRORED, NOT GUESSED: each is pinned by a constant-mirror test against the upstream value, + * exactly as `MULTICALL_SELECTOR` is. If the fork moves, the test fails rather than the wallet + * silently permitting an action it means to forbid. + */ + +/// @dev `IdLib.VALUE_SELECTOR` — the action selector the engine assigns when calldata is under four +/// bytes. A native action carrying this selector is a value-only transfer with EMPTY calldata; +/// a no-argument function like `unstake()` still carries its own four bytes and is a normal +/// selector action. +bytes4 constant VALUE_SELECTOR = 0xFFFFFFFF; + +/// @dev `DataTypes.FALLBACK_TARGET_FLAG`. Refused by name at grant time: the engine does NOT reject +/// it at enable time (only at check time, `PolicyLib.sol:200`), so the wallet is the only +/// grant-time layer for this value. +address constant ENGINE_FALLBACK_TARGET = address(1); + +/// @dev `DataTypes.FALLBACK_TARGET_SELECTOR_FLAG` — the wildcard action's selector. +bytes4 constant ENGINE_FALLBACK_SELECTOR = 0x00000001; + +/// @dev `DataTypes.FALLBACK_TARGET_SELECTOR_FLAG_PERMITTED_TO_CALL_SMARTSESSION` — the sentinel that +/// routes a request to the engine itself. An agent reaching this could configure sessions. +bytes4 constant ENGINE_FALLBACK_SELECTOR_SMARTSESSION = 0x00000002; + +/** + * @dev The gateway's outbound entry point — the ONE selector an agent rules set may ever name. + * + * DECLARED HERE, BESIDE THE STRUCT IT TAKES, AND NOWHERE ELSE. The wallet's grant-shape check + * and the policy's request-decode gate must agree on this value exactly: the wallet refuses to + * grant a rules set naming any other selector, and the policy refuses to validate a request + * carrying any other selector. Two independently hand-typed copies of the same signature + * string is the kind of duplication that stays correct only until one of them is edited, and + * the failure would be silent in the safe direction for one contract and open in the other. + * + * The signature string spells out `UniversalOutboundTxRequest` field-for-field because that is + * how Solidity encodes a struct parameter into a selector. It is therefore load-bearing on the + * mirror above: reorder or retype a field there without editing this string and the selector + * silently stops matching the deployed gateway. + */ +bytes4 constant SEND_OUTBOUND_SELECTOR = + bytes4(keccak256("sendUniversalTxOutbound((bytes,address,uint256,uint256,uint256,uint256,bytes,address))")); + +/** + * @dev The owner's signed authorisation for up to three actions: deploy, grant, execute. + * + * SIGNED ONCE under the FACTORY's EIP-712 domain and verified by the factory and by every wallet + * it deploys. Each door checks only its own fields and advances its own nonce, so one signature + * serves each door exactly once. + * + * - Presentable ONLY by `executor`: every door, on its signature path, requires + * `intent.executor != address(0) && msg.sender == intent.executor`. Without that, anyone who saw + * the intent in calldata could drive the doors out of order and burn the owner's signature. + * - A zero `sessionHash` / `execCalldataHash` means "not authorised for that action". + * - EVERY FIELD IS IN THE TYPEHASH, IN DECLARATION ORDER. A field outside the typed data would + * guarantee the SDK and the contract disagree about what was signed. + * + * DECLARED HERE, beside the other values the factory and the wallet must agree on exactly. + */ +struct OwnerIntent { + address owner; // the wallet owner (UEA or EOA) + address wallet; // the wallet this intent is for — the predicted address if not yet deployed + address executor; // the ONLY msg.sender allowed to present this intent to a door + uint96 index; // wallet index under owner; deployWallet requires index == walletCount(owner) + bytes32 sessionHash; // keccak256(abi.encode(Session)) for grantRulesWithSig; 0 = no grant + bytes32 mode; // ERC-7579 mode word for executeWithSig + bytes32 execCalldataHash; // keccak256(executionCalldata) for executeWithSig; 0 = no exec + uint192 nonceKey; // owner lane for executeWithSig; must have OWNER_LANE_FLAG set + uint64 nonceSeq; // expected _nonces[nonceKey] at execution + uint64 grantNonce; // expected _grantNonce at grant + uint48 deadline; // unix seconds; all three doors reject after this + uint256 signerChainId; // EIP-712 domain.chainId the signer's wallet accepts — the owner's HOME chain +} + +/// @dev The struct string must list every OwnerIntent field, in declaration order, with its exact type. +bytes32 constant OWNER_INTENT_TYPEHASH = keccak256( + "OwnerIntent(address owner,address wallet,address executor,uint96 index,bytes32 sessionHash," + "bytes32 mode,bytes32 execCalldataHash,uint192 nonceKey,uint64 nonceSeq,uint64 grantNonce," + "uint48 deadline,uint256 signerChainId)" +); + +/** + * @dev The intent's EIP-712 domain. Five fields: + * - `chainId` is the SIGNER's home chain (`intent.signerChainId`), not Push: MetaMask refuses to + * sign typed data whose `domain.chainId` differs from the active chain. + * - `salt` is `bytes32(block.chainid)` — the Push chain id — which is what isolates one Push chain + * from another. + * - `verifyingContract` is the FACTORY PROXY for both the factory and every wallet; the wallet + * reads it from its immutable args. The `wallet` field stops cross-wallet replay. + */ +bytes32 constant OWNER_INTENT_DOMAIN_TYPEHASH = + keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract,bytes32 salt)"); +bytes32 constant OWNER_INTENT_DOMAIN_NAME_HASH = keccak256("AGWFactory"); +bytes32 constant OWNER_INTENT_DOMAIN_VERSION_HASH = keccak256("1"); + +/** + * @dev Top bit of a uint192 nonce key. `executeWithSig` requires it SET: only owner lanes are ever + * consumed, and keys with it CLEAR are never touched. The agent door uses no nonce lanes at all — + * its replay protection is the sender's own transaction nonce. + */ +uint192 constant OWNER_LANE_FLAG = uint192(1) << 191; + +/** + * @dev The kinds of owner-side change the wallet records as a checkpoint (`IAGW.Checkpointed`). + * + * ORDINALS ARE A FROZEN WIRE FORMAT: indexers and evaluators read them. Append only — never + * reorder, never remove. A future kind (e.g. a binder) is appended as the next ordinal. + */ +enum CheckpointKind { + OWNER_ACTION, + RULES_GRANTED, + RULES_REVOKED +} + +// ─────────────────────── policy types (moved from IURP) ─────────────────────── + +/** + * @dev Maximum pinned arguments per native action. Bounds the N7 loop. + * + * FILE-LEVEL, NOT INSIDE THE INTERFACE — Solidity forbids variables in interfaces (solc 8274), + * and unlike `MAX_ACTIONS_PER_REQUEST` / `MAX_ALLOWED_CALLS` (which are `internal` to URP + * because they bound loops nobody off-chain constructs) this one bounds an array THE SDK + * BUILDS, so an encoder has to be able to see it. Parallel to `MULTICALL_SELECTOR` in + * `Types.sol`. + */ +uint256 constant MAX_PINS = 8; + +/** + * @dev Maximum tokens one UNIVERSAL rules set may list (EVM and SVM alike). Bounds the init duplicate + * check and the gate-5 scan. + * + * FILE-LEVEL FOR THE SAME REASON AS `MAX_PINS`: it bounds an array THE SDK BUILDS. + */ +uint256 constant MAX_ASSETS = 8; + +/** + * @dev The rules-envelope version URP accepts. Every action policy's `initData` is + * `abi.encode(uint16 version, string chainNamespace, bytes body)`, the same shape in every mode. + * URP reads the version from the FIRST WORD before decoding anything else and refuses any other + * value, so a body layout can change later under a new version without being misread. + * FILE-LEVEL so the SDK, which writes the envelope, can read it. + */ +uint16 constant ENVELOPE_VERSION = 1; + +/** + * @notice WIRE TYPE — one token a UNIVERSAL rules set may move, with its own caps. + * @param token The PRC20 ON PUSH (e.g. USDC.eth), never the destination chain's address: the + * gateway request carries the PRC20 and routes by it. Its `SOURCE_CHAIN_NAMESPACE()` + * must equal the rules set's chain, checked at init for every entry. + * @param maxPerCall Per-request ceiling, PRC20 base units. ZERO IS LEGAL and means "this token may + * route a request but never moves": the move-nothing rules set is one entry with a + * zero `maxPerCall`, never an empty list (an empty list would pin no chain). + * @param maxTotal Lifetime ceiling on the amount SENT OUT in this token. `type(uint256).max` = + * unlimited, with no special branch; zero means nothing may move. + */ +struct AssetCap { + address token; + uint256 maxPerCall; + uint256 maxTotal; +} + +/** + * @notice STORAGE TYPE — an `AssetCap` plus the counter URP owns. Never a wire type: a caller-set + * counter would be a granted head start on the cap. + * @param spent Lifetime amount sent out in this token, recorded before dispatch. Money coming back + * to the wallet never lowers it (URP cannot see inflows, and could not tell an agent's + * return from the owner's top-up); only `creditRevert` does. + */ +struct AssetCapState { + address token; + uint256 maxPerCall; + uint256 maxTotal; + uint256 spent; +} + +/// @param target far-chain contract +/// @param selector far-chain function +/// @param beneficiaryOffset byte offset of the beneficiary word in the inner calldata +/// @param hasBeneficiary false for calls with no beneficiary argument +/// @param maxValue per-entry native ceiling, DESTINATION-chain units (0 = non-payable) +struct AllowedCall { + address target; + bytes4 selector; + uint16 beneficiaryOffset; + bool hasBeneficiary; + uint256 maxValue; +} + +/** + * @notice WIRE TYPE — what a UNIVERSAL envelope's body encodes. Not a storage type. + * + * @dev ABSENT BY DESIGN, and each absence is the point: `initialized` (URP sets it), `spent` + * (URP owns it), and the chain (the envelope carries it, exactly once). The SDK used to + * type all three and URP overwrote them — a field whose only legal value is a + * placeholder is a field the caller fills in believing it matters. + * + * Mapped field-by-field onto the storage `Config` by `_store`. The storage struct's + * layout never moves; this one is free to change with the wire format. + */ +struct UniversalTerms { + uint48 validUntil; + address expectedCEA; + AssetCap[] assets; + uint256 maxGasPerCall; + AllowedCall[] allowedCalls; +} + +/// @param initialized set once, at initialisation; re-initialisation is refused +/// @param validUntil non-zero always (enforced at init); "never" = type(uint48).max, explicit +/// @param expectedCEA the wallet's destination account, committed at grant. The rules set's +/// chain is not stored here: it lives on `getMode(id, account).chainHash` +/// @param maxGasPerCall Push-native per-call ceiling on `msg.value`, in PC wei. It pays the protocol +/// fee AND the gas swap, despite the name (renamed from `maxPCPerCall` to +/// match the SDK) +/// @param assets 1..MAX_ASSETS permitted PRC20s, each with its own caps and its own `spent` +struct Config { + bool initialized; + uint48 validUntil; + address expectedCEA; + uint256 maxGasPerCall; + AssetCapState[] assets; + AllowedCall[] allowedCalls; +} + +// ───────────────────────── native mode structs ───────────────────────── + +/** + * @dev Per-config mode record. THE MODE DISCRIMINATOR, and the reason it is a struct rather than + * a bare enum: `RulesType.UNIVERSAL` is the zero value, so an empty storage slot reads as + * `UNIVERSAL` and could not be told apart from a real universal rules set. `initialized` is + * authoritative; `mode` is MEANINGLESS when it is false. + * @param initialized true once any rulebook has been written for this config + * @param mode which rulebook; only meaningful when `initialized` + * @param vm which destination VM a UNIVERSAL config targets; meaningless for NATIVE + */ +struct ModeSlot { + bool initialized; + RulesType mode; + /// @dev ADDED for the SVM rulebook, PLACED HERE ON PURPOSE. Declared between `mode` and + /// `chainHash` it packs into slot 0 at byte 2 — a byte no earlier implementation ever + /// wrote, so every existing entry reads 0 = `EVM`, which is what every existing entry + /// is. No existing member moves: `chainHash` stays at slot 1. Appending it after + /// `chainHash` would be equally safe and cost one more slot per grant; the layout test + /// pins label, slot, offset and type of all four members either way. + VmFamily vm; + /// @dev keccak256(bytes(chain)) as declared in the policy envelope. THE single chain record + /// for BOTH modes — universal stores the destination chain, native stores this chain's + /// own hash. Written at init, never zero on an initialised entry. + bytes32 chainHash; +} + +/** + * @dev One pinned argument of a native call. + * @param offset ABSOLUTE byte offset from byte 0 of the calldata, SELECTOR INCLUDED — so 4 is + * the first argument word, 36 the second, and so on. + * @param expected The full 32-byte word that must appear there. An address argument is + * left-padded by the ABI, so a non-zero high half is a MISMATCH, deliberately: + * full-word equality also proves the padding is clean, which masking would + * silently accept. + */ +struct ArgPin { + uint16 offset; + bytes32 expected; +} + +/** + * @dev Optional metering of a `uint256` argument read out of native calldata. + * @param enabled Whether to meter at all. A BOOL rather than "offset 0 means off", because + * offset 0 is a legal position — it just points inside the selector. + * @param offset Absolute byte offset of the amount word, selector included. + * @param maxPerCall Per-call ceiling. Zero is legal (a call that must carry amount zero). + * @param maxTotal Lifetime ceiling; `type(uint256).max` = unlimited, with no special branch. + */ +struct AmountRule { + bool enabled; + uint16 offset; + uint256 maxPerCall; + uint256 maxTotal; +} + +/** + * @dev The native rulebook for ONE (target, selector) action. One of these per action, so a + * rules set with eight actions holds eight of them under eight distinct config ids. + * + * @param initialized set once; re-initialisation is refused, as in universal mode + * @param validUntil non-zero and future (enforced at init); "never" = type(uint48).max + * @param target defensive copy of the action target, asserted at N4 + * @param selector defensive copy, asserted at N5. `0xFFFFFFFF` = value-only, which means + * EMPTY calldata — a no-argument function still carries four bytes + * @param maxValuePerCall Push-native per-call ceiling + * @param maxValueTotal Push-native lifetime ceiling; type(uint256).max = unlimited + * @param valueSpent lifetime native value metered, written effects-last + * @param amount optional calldata-amount metering + * @param amountSpent lifetime metered amount, written effects-last + * @param maxCalls 0 = unlimited; otherwise the lifetime call ceiling + * @param callsUsed calls consumed. ALWAYS increments on a successful check, including a + * zero-value zero-amount call — a call is a use, and the alternative + * makes `maxCalls` bypassable + * @param pins 0..MAX_PINS pinned argument words + */ +struct NativeConfig { + bool initialized; + uint48 validUntil; + address target; + bytes4 selector; + uint256 maxValuePerCall; + uint256 maxValueTotal; + uint256 valueSpent; + AmountRule amount; + uint256 amountSpent; + uint32 maxCalls; + uint32 callsUsed; + ArgPin[] pins; +} + +/** + * @notice WIRE TYPE — what a NATIVE envelope's body encodes. Not a storage type. + * + * @dev ABSENT BY DESIGN: `initialized`, `valueSpent`, `amountSpent` and `callsUsed` are all + * URP's own counters, zeroed at init. The SDK had to type four zeroes it did not own. + * + * SPLIT EVEN THOUGH ONLY THE UNIVERSAL SIDE FORCES IT. The SDK builds both; one struct + * with dead input fields sitting beside one without is precisely the inconsistency that + * let a since-removed chain field acquire four different conventions in one repository. + */ +struct NativeTerms { + uint48 validUntil; + address target; + bytes4 selector; + uint256 maxValuePerCall; + uint256 maxValueTotal; + AmountRule amount; + uint32 maxCalls; + ArgPin[] pins; +} + +// ───────────────────────── svm mode structs ───────────────────────── +// +// The third rulebook: a UNIVERSAL rules set whose destination is a `solana:*` chain. On Solana an +// outbound is ONE cross-program invocation — a target program, an ordered account list, and an +// instruction byte string — signed by the wallet's CEA (a PDA), not an EVM multicall. Every +// EVM-shaped gate (multicall walk, `address` target, `bytes4` selector, beneficiary word, per-entry +// value) is replaced by the shapes below. See `URP._checkSvm` for the gate list. + +/** + * @dev One allow-listed (program, instruction) pair. + * @param program Target program id, 32 bytes. + * @param discriminator Left-aligned instruction tag; only the first `discriminatorLen` bytes + * are compared. 8 for Anchor (`sha256("global:")[..8]`), 1 for + * SPL-style instruction indexes. + * @param discriminatorLen 1..8, or 0 iff `dataless`. + * @param dataless The instruction carries NO data. The only way to get a length-0 tag, + * and it forces `ix_data` to be EMPTY at check time — so a rule can never + * match an instruction its pins were not written for. + * @param maxAccounts 0 = unbounded; otherwise the request's account count must EQUAL it. + * Set to the IDL count for fixed-layout instructions so nothing can be + * appended behind the pinned positions. + */ +struct AllowedProgram { + bytes32 program; + bytes8 discriminator; + uint8 discriminatorLen; + bool dataless; + uint8 maxAccounts; +} + +/** + * @dev `accounts[accountIndex]` of a request matching rule `ruleIndex` must equal `expected`. + * The SVM counterpart of the EVM beneficiary pin: programs read accounts by POSITION, so a + * value-carrying position is pinned to an owner-committed key (the CEA, or one of its ATAs). + */ +struct SvmAccountPin { + uint8 ruleIndex; + uint8 accountIndex; + bytes32 expected; +} + +/// @dev How an `SvmDataPin` compares. Integers are LITTLE-ENDIAN (Borsh), `len` bytes wide. +enum SvmDataPinMode { + EQ, + GTE_LE, + LTE_LE, + RATIO_GTE_LE +} + +/** + * @dev A constraint on the `ix_data` of a request matching rule `ruleIndex`. + * - EQ `ix_data[off : off+len] == expected[0 : len]`, `len` 1..32, raw bytes, + * LEFT-ALIGNED: bytes of `expected` past `len` must be zero. + * - GTE_LE `uintLE(ix_data[off : off+len]) >= uint256(expected)`, `len` 1..8, + * RIGHT-ALIGNED integer: `expected` must fit in `len` bytes. + * - LTE_LE `uintLE(ix_data[off : off+len]) <= uint256(expected)`, same encoding. + * - RATIO_GTE_LE `uintLE(A) * den >= uintLE(B) * num`, A at `offset`, B at `offsetB`, both + * `len` bytes and both addressed with the same `fromEnd`; `expected` unused; + * `num` and `den` both non-zero. + * This is the min-out floor RELATIVE to the input amount — a static floor on + * the output alone is bypassed by an input equal to the whole balance. + * - fromEnd `offset` counts back from the END of `ix_data` to the field's START. + * Borsh serialises vectors before scalars, so trailing scalar arguments have + * stable from-end offsets and unstable from-start ones. Requires + * `offset >= len`. + */ +struct SvmDataPin { + uint8 ruleIndex; + bool fromEnd; + uint16 offset; + uint16 offsetB; + uint8 len; + SvmDataPinMode mode; + bytes32 expected; + uint64 num; + uint64 den; +} + +/** + * @notice WIRE TYPE — what a `solana:*` UNIVERSAL envelope's body encodes. Not a storage type. + * + * @dev ABSENT BY DESIGN, as in `UniversalTerms`: `initialized` and `spent` are URP's. + * + * @param validUntil non-zero, in the future (enforced at init); "never" = type(uint48).max + * @param expectedCEA the wallet's CEA on the destination: `PDA(["push_identity", wallet], + * gatewayProgram)`. Owner-committed — Solidity cannot derive a PDA. + * @param gatewayProgram the Push gateway program on the declared cluster. Owner-committed; the + * SDK sources it from the chain registry. Forbidden as a target: that + * route only returns the permitted asset to the owner's wallet, at the + * owner's rate-limit and gas cost. + * @param assets 1..MAX_ASSETS permitted PRC20s with their caps, exactly as `UniversalTerms`; + * amounts are PRC20 base units (lamports / SPL base units), and a request's + * amount must also fit Solana's u64 (S6b) + * @param maxGasPerCall Push-native per-call ceiling (protocol fee + gas swap budget), PC wei + * @param ceaAccounts every CEA-controlled account that HOLDS VALUE: the CEA, its ATA for EACH + * listed asset, its ATAs for allowed outputs. At most MAX_CEA_ACCOUNTS (16, + * the CEA included: room for all 8 assets plus 7 outputs). Each may appear in + * a request ONLY at a position the matched rule pins to it; a listed account + * no rule pins can never be passed at all. Unlisted accounts are not + * protected — the list is the owner's statement of what is worth taking. + * URP CANNOT CHECK that each listed asset's ATA is here (it cannot derive a + * Solana token account, and does not know a PRC20's mint): listing them is + * the SDK's job. Must contain `expectedCEA`; no zero, duplicate, or program + * entries. + * @param programs the allow-list; first match wins, made exact by the init ambiguity rule. + * ONE RULE PER (program, instruction), so ONE PINNED KEY PER POSITION: if a + * swap rule pins its input to the USDC account, USDT can never be that + * instruction's input. Using several listed tokens through one instruction + * means leaving the input unpinned and those token accounts unlisted, so + * only the output and price pins protect them. Multi-asset on Solana is + * strongest when different tokens are used by different instructions. + * @param pins account pins, each naming its rule + * @param dataPins `ix_data` pins, each naming its rule + */ +struct SvmTerms { + uint48 validUntil; + bytes32 expectedCEA; + bytes32 gatewayProgram; + AssetCap[] assets; + uint256 maxGasPerCall; + bytes32[] ceaAccounts; + AllowedProgram[] programs; + SvmAccountPin[] pins; + SvmDataPin[] dataPins; +} + +/** + * @dev The SVM rulebook — STORAGE type, lives inside `_svm`. + * @param initialized set once; re-initialisation is refused + * @param assets per-token caps and per-token `spent`, exactly as `Config.assets` + */ +struct SvmConfig { + bool initialized; + uint48 validUntil; + bytes32 expectedCEA; + bytes32 gatewayProgram; + uint256 maxGasPerCall; + AssetCapState[] assets; + bytes32[] ceaAccounts; + AllowedProgram[] programs; + SvmAccountPin[] pins; + SvmDataPin[] dataPins; +} diff --git a/plan/agw/research/deployment-review-2026-10-06/source/src/policies/UniversalRulesPolicy.sol b/plan/agw/research/deployment-review-2026-10-06/source/src/policies/UniversalRulesPolicy.sol new file mode 100644 index 00000000..17799758 --- /dev/null +++ b/plan/agw/research/deployment-review-2026-10-06/source/src/policies/UniversalRulesPolicy.sol @@ -0,0 +1,1881 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import { UniversalRulesPolicyErrors } from "../libraries/Errors.sol"; + +import { VALIDATION_SUCCESS } from "erc7579/interfaces/IERC7579Module.sol"; +import { ConfigId } from "smartsessions/DataTypes.sol"; +import { IActionPolicy, IPolicy } from "smartsessions/interfaces/IPolicy.sol"; +import { IERC165 } from "forge-std/interfaces/IERC165.sol"; +import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; + +import { IUniversalRulesPolicy } from "../interfaces/IUniversalRulesPolicy.sol"; +import { IPRC20Source } from "../interfaces/IPRC20Source.sol"; +import { PushChainLib } from "../libraries/PushChainLib.sol"; +import { + AllowedCall, + AllowedProgram, + ArgPin, + AssetCap, + AssetCapState, + Config, + MAX_ASSETS, + ENVELOPE_VERSION, + MAX_PINS, + ModeSlot, + Multicall, + MULTICALL_SELECTOR, + NativeConfig, + NativeTerms, + RulesType, + SEND_OUTBOUND_SELECTOR as GATEWAY_SEND_OUTBOUND_SELECTOR, + SvmAccountPin, + SvmConfig, + SvmDataPin, + SvmDataPinMode, + SvmTerms, + UniversalOutboundTxRequest, + UniversalTerms, + VALUE_SELECTOR, + VmFamily +} from "../libraries/Types.sol"; + +// Cluster-independent Solana program ids, never targets. Decoded from their base58 ids by tooling and +// pinned by `test_svm_forbiddenProgramConstantsMatchBase58` — do not hand-edit a hex word. FILE-LEVEL, +// not inside the contract, so that test can import them without inheriting all of URP: a harness that +// did so grew past the 24,576-byte limit and failed `make sizes`. Inlined either way; no runtime cost. +/// @dev `11111111111111111111111111111111` — a system transfer with the CEA as funder drains it. +bytes32 constant SYSTEM_PROGRAM = bytes32(0); +/// @dev `TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA` — transfer/approve/close with CEA authority. +bytes32 constant SPL_TOKEN_PROGRAM = 0x06ddf6e1d765a193d9cbe146ceeb79ac1cb485ed5f5b37913a8cf5857eff00a9; +/// @dev `TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb` — the same surface on Token-2022. +bytes32 constant TOKEN_2022_PROGRAM = 0x06ddf6e1ee758fde18425dbce46ccddab61afc4d83b90d27febdf928d8a18bfc; +/// @dev `Stake11111111111111111111111111111111111111` — withdraw with the CEA as authority. +bytes32 constant STAKE_PROGRAM = 0x06a1d8179137542a983437bdfe2a7ab2557f535c8a78722b68a49dc000000000; +/// @dev `BPFLoaderUpgradeab1e11111111111111111111111` — never a CEA action; refused outright. +bytes32 constant BPF_LOADER_UPGRADEABLE = 0x02a8f6914e88a1b0e210153ef763ae2b00c2b93d16c124d2c0537a1004800000; +/// @dev `AddressLookupTab1e1111111111111111111111111` — rent drain with the CEA as payer. +bytes32 constant ADDRESS_LOOKUP_TABLE = 0x0277a6af97339b7ac88d1892c90446f50002309266f62e53c118244982000000; + +/** + * @title UniversalRulesPolicy (URP) + * @notice The security boundary of the whole system: the only contract that ever inspects what an + * agent really does on the far chain. Everything else routes, stores, or signs. + * + * @dev - The engine identifies actions by hashing the Push-side target and selector, and every + * agent action is the same Push-side call, so to the engine a trade, a deposit and a theft + * are identical. What the user actually authorised lives two decode levels down, inside + * the payload. This policy opens it. + * - It is the fail-closed anchor: the engine requires at least one action policy per action + * (`PolicyLib.check`), so removing this one does not weaken a rules set, it kills every + * request under it. + * - No owner, no setters, no pause. Its three trust anchors are written once, at + * initialisation, and there is no function that can change them afterwards. + * - It never makes an external call, and writes only after every gate has passed. + * + * UPGRADEABLE, BEHIND A TRANSPARENT PROXY, AND THAT IS A DELIBERATE TRADE. This contract + * used to hold its trust anchors in immutables and describe itself as needing no trust at + * all. Immutables live in the implementation's bytecode, which a `delegatecall` never + * executes the constructor of, so upgradeability and immutables are mutually exclusive — + * they had to become storage. The consequence is worth stating plainly rather than + * discovering later: **URP's guarantees now hold subject to the proxy admin not being + * malicious.** An admin able to install new logic can rewrite every gate in this file. + * + * What that means in practice, and what it does NOT mean: + * - No function here can move `SESSION_ENGINE`, the gateway or the executor module. The + * only route to changing them is a full implementation swap by the admin. + * - The admin cannot reach `_configs` or `_credited` directly; it can only replace the code + * that reads them. Existing rules sets keep their caps until an upgrade says otherwise. + * - Storage layout is therefore load-bearing FOREVER. See the layout note on `__gap`. + * + * THE IMPLEMENTATION MUST NEVER BE INITIALISED DIRECTLY. Its constructor disables the + * initialiser for exactly that reason; an initialised implementation is a contract with a + * live config that the proxy does not know about. + */ +contract UniversalRulesPolicy is IUniversalRulesPolicy, Initializable { + /// @dev Maximum inner calls in one request. Bounds the gate-13 loop. + uint256 internal constant MAX_ACTIONS_PER_REQUEST = 10; + + /// @dev Maximum allow-list entries per config. Bounds the allow-list scan. + uint256 internal constant MAX_ALLOWED_CALLS = 32; + + /// @notice The gateway selector every agent action must carry. + /// @dev Part of this contract's ABI, so it stays a public constant. The value comes from the + /// shared gateway constant, so this policy and the wallet's grant-shape check cannot + /// disagree. + bytes4 public constant SEND_OUTBOUND_SELECTOR = GATEWAY_SEND_OUTBOUND_SELECTOR; + + /// @dev Smallest valid ABI encoding of a UniversalOutboundTxRequest argument list: + /// 32 (outer offset) + 256 (eight head words) + 32 + 32 (length words for the two empty + /// bytes fields). Do not hand-maintain: a test pins this against abi.encode of an empty + /// request, so a new struct field fails the build rather than loosening gate 4c. + uint256 internal constant MIN_OUTBOUND_BODY_LEN = 352; + + // ───────────────────────────── svm rulebook bounds ───────────────────────────── + + /// @dev Maximum allow-list entries per SVM config. Mirrors MAX_ALLOWED_CALLS. + uint256 internal constant MAX_ALLOWED_PROGRAMS = 32; + /// @dev Maximum account pins per SVM config. Bounds the S17 and S18 loops. + uint256 internal constant MAX_SVM_PINS = 16; + /// @dev Maximum ix_data pins per SVM config. + uint256 internal constant MAX_SVM_DATA_PINS = 8; + /// @dev Maximum CEA-controlled accounts an owner may list. Bounds the S18 loop. 16 = the CEA, one + /// token account per listed asset (MAX_ASSETS = 8) and up to 7 swap-output accounts. S18 gas + /// grows with the number actually listed, never with this bound. + uint256 internal constant MAX_CEA_ACCOUNTS = 16; + /// @dev Loop bound on a request's account list. Solana's transaction size limit bites first. + uint256 internal constant MAX_SVM_ACCOUNTS = 64; + /// @dev Loop bound on a request's instruction data. + uint256 internal constant MAX_SVM_IX_DATA = 1024; + + // The SVM payload grammar — the node's `decodePayload`, byte for byte: + // [u32 BE count][count × (pubkey32 ‖ is_writable u8)][u32 BE len][ix_data][u8 id][target32] + uint256 internal constant SVM_HEADER_LEN = 4; + uint256 internal constant SVM_ACCOUNT_LEN = 33; + uint256 internal constant SVM_LEN_FIELD = 4; + uint256 internal constant SVM_TRAILER_LEN = 33; + uint8 internal constant SVM_INSTRUCTION_EXECUTE = 2; + + // ───────────────────────────────── storage ───────────────────────────────── + // + // THE LAYOUT BELOW IS FROZEN. Behind a proxy, storage belongs to the proxy and outlives every + // implementation, so a new version may only APPEND — never reorder, never remove, never change + // a type. Doing so does not fail the build: it silently reinterprets live rules sets, which is + // the worst failure mode this system has. + // + // slot 0 UNIVERSAL_GATEWAY_PC + // slot 1 UNIVERSAL_EXECUTOR_MODULE + // slot 2 SESSION_ENGINE + // slot 3 _configs + // slot 4 _credited + // slot 5 _mode APPENDED 2026-09-09 (native mode) + // slot 6 _native APPENDED 2026-09-09 (native mode) + // slot 7 _svm APPENDED 2026-09-30 (svm rulebook) + // slots 8..49 __gap (uint256[42]) + // + // THE 2026-09-09 APPEND, AND WHY IT IS SAFE. `_mode` and `_native` were added AFTER `_credited` + // and `__gap` was shrunk 45 -> 43 in the same commit, so slots 0-4 are byte-identical to the + // deployed layout and `__gap` still ends at slot 49. Nothing that holds data moved. The + // alternative that was rejected — renaming `_configs` to `_universal` and inserting `_native` + // beside it — would have shifted `_credited` and silently reinterpreted the live idempotency + // set. Measured with `forge inspect` before the change, not assumed. + // + // `Initializable` adds nothing here: OZ 5.x keeps its initialisation flags in an ERC-7201 + // namespaced slot, not slot 0. A test pins this exact layout against solc's own output. + + /// @notice The one Push-side target any agent action may reach. + /// @dev Written once by `initialize`. No setter exists, here or anywhere. + address public UNIVERSAL_GATEWAY_PC; + + /// @notice The sole caller permitted to credit a failed outbound. + /// @dev Address unconfirmed against a live deployment; confirm before mainnet. It is an + /// initialiser argument, so nothing about building or testing depends on the real one. + address public UNIVERSAL_EXECUTOR_MODULE; + + /// @notice The multiplexer this contract trusts on every non-engine-driven path. + /// @dev Never accepted as a call argument: a wrong value would silently address an empty + /// slice. It is set once at initialisation and read from storage thereafter. + address public SESSION_ENGINE; + + /// @dev configId => multiplexer (the engine) => account (the wallet) => config. + /// @dev The configId already binds the account and the permission, so the middle level isolates + /// callers, not permissions. + /// @dev On the two engine-driven entry points the multiplexer is msg.sender; every other + /// function keys on SESSION_ENGINE. + mapping(ConfigId => mapping(address => mapping(address => Config))) internal _configs; + + /// @dev outbound tx id => credited already; idempotency for the refund path. + mapping(bytes32 => bool) internal _credited; + + /// @dev configId => multiplexer => account => which rulebook this config uses. + /// @dev THE MODE DISCRIMINATOR. Stored rather than derived from `_native[...].initialized`, + /// because a one-bit derived mode cannot grow: URP is upgradeable behind a proxy, and the + /// register's extensibility item points at MORE MODES. `ModeSlot.initialized` is + /// authoritative for emptiness; `mode` is meaningless when it is false. + mapping(ConfigId => mapping(address => mapping(address => ModeSlot))) internal _mode; + + /// @dev configId => multiplexer => account => the native rulebook. + /// @dev One entry per ACTION, not per rules set: a native rules set with eight actions writes eight + /// of these under eight distinct config ids. + mapping(ConfigId => mapping(address => mapping(address => NativeConfig))) internal _native; + + /// @dev configId => multiplexer => account => the SVM rulebook. + /// @dev APPENDED 2026-09-30 after `_native`; `__gap` shrunk 43 -> 42 in the same commit so it + /// still ends at slot 49. Slots 0-6 are byte-identical to the deployed layout. `ModeSlot` + /// gained a packed byte in the same change (see `ModeSlot.vm`); no member of any live + /// struct moved. Measured with the layout tests, not assumed. + mapping(ConfigId => mapping(address => mapping(address => SvmConfig))) internal _svm; + + /** + * @dev Reserved so a later version can add state without shifting anything above. + * + * Adding a variable means DECREMENTING this by exactly the number of slots consumed, in + * the same commit. A mapping or dynamic array costs one slot; a struct costs its packed + * size. `Config` itself lives inside a mapping, so APPENDING a field to that struct is + * safe and costs nothing here — reordering or removing one is not. + * + * Was `uint256[45]` before the 2026-09-09 native-mode append; `_mode` and `_native` took + * two slots, so it became 43. `_svm` took one more on 2026-09-30, so it is 42. `__gap` + * still ends at slot 49. + */ + uint256[42] private __gap; + + /** + * @notice Locks the implementation so it can never be initialised in its own context. + * + * @dev An implementation left initialisable is a live contract holding a config the proxy + * has no knowledge of. This is the standard guard and it is not optional. + */ + constructor() { + _disableInitializers(); + } + + /** + * @notice Pins the three addresses this policy trusts for its whole lifetime. + * + * @dev Runs once, in the PROXY's context, immediately after deployment. Reverts with + * `ZeroAddress` if any argument is zero, and with `InvalidInitialization` on any + * second call. + * + * Deploy and initialise atomically — pass this call as the TransparentUpgradeableProxy + * constructor's `_data`. A proxy deployed uninitialised is front-runnable: whoever + * calls `initialize` first chooses the engine this policy trusts. + * + * @param universalGatewayPC The one Push-side target agent actions may reach. + * @param universalExecutorModule The only caller permitted to credit a failed outbound. + * @param sessionEngine The multiplexer trusted on non-engine-driven paths. + */ + function initialize(address universalGatewayPC, address universalExecutorModule, address sessionEngine) + external + initializer + { + if (universalGatewayPC == address(0)) revert UniversalRulesPolicyErrors.ZeroAddress(); + if (universalExecutorModule == address(0)) revert UniversalRulesPolicyErrors.ZeroAddress(); + if (sessionEngine == address(0)) revert UniversalRulesPolicyErrors.ZeroAddress(); + + UNIVERSAL_GATEWAY_PC = universalGatewayPC; + UNIVERSAL_EXECUTOR_MODULE = universalExecutorModule; + SESSION_ENGINE = sessionEngine; + } + + /** + * @dev The mode of a config, from its `ModeSlot`, which every init writes. Read by every + * mode-sensitive entry point that is not `checkAction`. + * + * @return initialized true once any rulebook has been written for this config + * @return mode the rulebook; meaningless when `initialized` is false + */ + function _modeOf(ConfigId id, address mux, address account) + internal + view + returns (bool initialized, RulesType mode) + { + ModeSlot storage slot = _mode[id][mux][account]; + return (slot.initialized, slot.mode); + } + + /// @dev The family of a UNIVERSAL config. Meaningless for NATIVE and for empty slots; callers check + /// the mode first. + function _vmOf(ConfigId id, address mux, address account) internal view returns (VmFamily) { + return _mode[id][mux][account].vm; + } + + /** + * @notice Writes one permission's configuration. Reached inside `enableSessions` during the + * wallet's `grantRules`, where `msg.sender` becomes the multiplexer key. + * + * @dev - Refuses re-initialisation, a deliberate deviation from the upstream policy + * interface, which says a repeat call must overwrite. Do not restore overwrite + * semantics for interface fidelity. + * - This cannot break a legitimate regrant: the wallet supplies a fresh salt on every + * grant, so a regranted rules set has a new permission id and therefore an untouched + * config slot. The refusal only ever fires on a path this system does not use. + * - Rejects an allow-list that is empty or longer than the cap, an expiry that is zero + * or already past, a zero expected destination account, and an asset list that is + * empty, longer than MAX_ASSETS, repeats a token, or names a token whose source chain + * is not the declared chain. An owner consent term has no meaningful silence, so + * "never expires" is written as the maximum value. + * - Deliberately does not validate cap values (zero and max are both legal, a zero + * per-call cap being a valid move-nothing entry), `beneficiaryOffset`, or + * allow-list contents. A wrong offset fails closed at validation time; it cannot widen + * a rules set, only break it. Offsets must be generated from each protocol's ABI by + * tooling rather than hand-typed, and each newly supported protocol must ship a test + * rejecting a wrong beneficiary and an oversized amount. + * - Anyone may call this with themselves as the multiplexer; that writes into their own + * keyed slice and the engine never reads it. + * - Writes the config, sets the initialised flag, and emits `RulesConfigured` and + * `PolicySet`. + * + * - THE ENVELOPE. `initData` is `abi.encode(uint16 version, string chain, bytes body)` — + * IDENTICAL IN SHAPE FOR EVERY MODE, which is what lets the chain be read before the + * mode is known. Nobody declares the mode: URP derives it from the chain with + * `PushChainLib.deriveMode`, and the wallet derived the same value from the same bytes + * at grant. There is no mode byte and therefore no `InvalidPolicyMode`. + * - THE VERSION is read from the first word BEFORE anything else is decoded, and anything + * but `ENVELOPE_VERSION` is refused `UnsupportedEnvelopeVersion`. So a body layout can + * change later under a new version, and almost every malformed or pre-version blob is + * refused NAMED: a two-field `(string, bytes)` envelope reports version 64 (its string + * offset), a bare struct 32, a zeroed blob 0. Blobs shorter than one word, and a + * version-1 envelope whose body is the wrong `Terms` type, revert unnamed. Nothing + * mis-decodes into a live config — measured, one test per shape. + * - Re-initialisation is refused ACROSS MODES, and the guard runs BEFORE the decode, so + * a malformed blob aimed at a live config still gets a named `AlreadyInitialized`. + * + * @param account The wallet this config belongs to. + * @param configId Engine-derived id binding the account and the permission. + * @param initData `abi.encode(uint16 version, string chain, bytes body)`, body being + * `abi.encode(UniversalTerms)`, `abi.encode(SvmTerms)` or `abi.encode(NativeTerms)` + * according to the DERIVED mode and family. + */ + function initializeWithMultiplexer(address account, ConfigId configId, bytes calldata initData) external { + ModeSlot storage slot = _mode[configId][msg.sender][account]; + + // Re-initialisation would let the owner door reset a spend counter or flip a mode. + if (slot.initialized) revert UniversalRulesPolicyErrors.AlreadyInitialized(configId); + + // THE VERSION, from the first word, before anything else is decoded. + uint256 envelopeVersion = uint256(bytes32(initData[0:32])); + if (envelopeVersion != ENVELOPE_VERSION) { + revert UniversalRulesPolicyErrors.UnsupportedEnvelopeVersion(envelopeVersion); + } + + // THE ENVELOPE, decoded exactly as the wallet decoded it at grant — same expression, same + // bytes. That identity is the whole consistency argument: there is no second author of the + // discriminator, so there is nothing for the two contracts to disagree about. + (, string memory chainNamespace, bytes memory body) = abi.decode(initData, (uint16, string, bytes)); + if (bytes(chainNamespace).length == 0) revert UniversalRulesPolicyErrors.EmptyChain(); + + bytes32 chainHash = keccak256(bytes(chainNamespace)); + RulesType mode = PushChainLib.deriveMode(chainHash); + + // THE FAMILY, derived only for UNIVERSAL. A native string is `eip155:` too and would classify + // EVM, but NATIVE has no family and must not carry a meaningless one. `deriveVm` refuses any + // namespace without a rulebook, so a `cosmos:` grant fails here, named, instead of producing + // a rules set that passes init and rejects every request. + VmFamily vm = VmFamily.EVM; + if (mode == RulesType.UNIVERSAL) { + vm = PushChainLib.deriveVm(chainNamespace); + if (vm == VmFamily.EVM) { + _initUniversal(_configs[configId][msg.sender][account], body, chainHash); + } else { + _initSvm(_svm[configId][msg.sender][account], body, chainHash); + } + } else { + _initNative(_native[configId][msg.sender][account], body); + } + + slot.initialized = true; + slot.mode = mode; + slot.vm = vm; + slot.chainHash = chainHash; + + emit RulesConfigured(configId, msg.sender, account, mode, vm, chainHash); + emit PolicySet(configId, msg.sender, account); + } + + /// @inheritdoc IUniversalRulesPolicy + function pushChainHash() external view returns (bytes32) { + return PushChainLib.selfChainHash(); + } + + /** + * @dev The universal init guards — unchanged from the single-mode contract, only relocated. + * @param cfg Storage slot to write. + * @param body `abi.encode(Config)`. + */ + function _initUniversal(Config storage cfg, bytes memory body, bytes32 chainHash) internal { + UniversalTerms memory incoming = abi.decode(body, (UniversalTerms)); + + uint256 listLength = incoming.allowedCalls.length; + if (listLength == 0 || listLength > MAX_ALLOWED_CALLS) { + revert UniversalRulesPolicyErrors.AllowListOutOfRange(listLength); + } + + if (incoming.validUntil == 0 || incoming.validUntil <= block.timestamp) { + revert UniversalRulesPolicyErrors.InvalidExpiry(incoming.validUntil); + } + if (incoming.expectedCEA == address(0)) revert UniversalRulesPolicyErrors.InvalidConfigField(); + + // ─── THE TEETH ─── + // + // After every decode and guard, before every write. Effects last, as everywhere else here. + // + // WHY THIS MAKES THE DECLARED CHAIN TRUE AT RUNTIME. `SOURCE_CHAIN_NAMESPACE()` is the exact + // view the gateway reads on every outbound, through `UniversalCore.getOutboundTxGasAndFees`, + // to decide where to route. Gate 5 pins `req.token` to a LISTED asset on every request, zero + // amount included. So asserting it here, for EVERY listed asset, binds the owner's declared + // chain to the chain the gateway will actually use — with no runtime change and no external + // call in `checkAction`. It is also why the list may never be empty: an empty list would pin + // no token, and the agent would choose the chain. + // + // WHY AN EXTERNAL CALL IS SAFE HERE AND NOWHERE ELSE: this runs at INIT, inside the owner's + // own grant transaction, never in `checkAction` and never on a removal path. A failure + // blocks a grant; it can never block a revocation or an execution. The `try/catch` is + // permitted because the external call ALREADY EXISTS — do not extend that reasoning to + // `checkAction`'s decode, which has no external call to hide behind. + // + // A `view` call compiles to STATICCALL, so the callee cannot write state: reentrancy from a + // hostile asset is structurally impossible, not merely unreachable. + // + // ⚠️ THE `code.length` GUARD IS NOT REDUNDANT WITH THE `catch`. MEASURED: + // callee reverts -> catch fires -> named InvalidAsset + // no code at the address, or EOA -> catch does NOT -> UNNAMED, empty revert + // answers with a non-string -> catch does NOT -> UNNAMED, empty revert + // Since solc 0.8.10 the compiler omits the extcodesize check when return data is + // expected; the call to a codeless address then SUCCEEDS with empty returndata and the + // failure happens when THIS frame tries to ABI-decode it — outside the try/catch. Without + // this line a typo'd asset address, the likeliest real mistake, reverts unnamed. + _requireAssets(incoming.assets, chainHash); + + _store(cfg, incoming); + cfg.initialized = true; + } + + /** + * @dev The asset-list guards, shared by both universal families: 1..MAX_ASSETS entries, no token + * twice, and THE TEETH for every entry. A zero token fails the teeth as `InvalidAsset(0)`. + * O(n^2) duplicate check at n <= 8. + */ + function _requireAssets(AssetCap[] memory assets, bytes32 chainHash) internal view { + uint256 n = assets.length; + if (n == 0 || n > MAX_ASSETS) revert UniversalRulesPolicyErrors.AssetListOutOfRange(n); + for (uint256 i; i < n;) { + address token = assets[i].token; + for (uint256 j; j < i;) { + if (assets[j].token == token) revert UniversalRulesPolicyErrors.DuplicateAsset(token); + unchecked { + ++j; + } + } + _requireAssetOnChain(token, chainHash); + unchecked { + ++i; + } + } + } + + /** + * @dev THE TEETH, shared by both universal families. Reverts `InvalidAsset` for a codeless + * address, a reverting callee or a non-string answer, and `ChainMismatch` when the asset's + * own `SOURCE_CHAIN_NAMESPACE()` hash differs from the declared chain. See the long note + * in `_initUniversal` for why this external call is safe at init and nowhere else. + */ + function _requireAssetOnChain(address asset, bytes32 chainHash) internal view { + if (asset.code.length == 0) revert UniversalRulesPolicyErrors.InvalidAsset(asset); + + try IPRC20Source(asset).SOURCE_CHAIN_NAMESPACE() returns (string memory ns) { + bytes32 assetChain = keccak256(bytes(ns)); + if (assetChain != chainHash) revert UniversalRulesPolicyErrors.ChainMismatch(chainHash, assetChain); + } catch { + revert UniversalRulesPolicyErrors.InvalidAsset(asset); + } + } + + /** + * @dev The native init guards. + * + * - Refuses a zero target, and the GATEWAY as a target: the mirror of gate 3, and half of + * the consistency lock. A native config can never be written against the gateway. + * - Refuses a value-only config carrying pins or an amount rule. That combination can never + * authorise anything — every request under it would die at N7/N8 — so it is a + * misconfiguration the owner believes they granted, not a valid ascetic config. Same + * reasoning as the empty-allow-list refusal in universal mode. + * - Deliberately does NOT validate cap values (zero and max are both legal), pin offsets or + * `amount.offset` — they cannot be checked against calldata that does not exist yet, and a + * wrong offset fails closed at N7/N8 rather than widening anything. Nor the selector + * against the engine's fallback flags: the wallet refuses those at grant, and a + * stranger-slice config the engine never reads is harmless. + * + * - MAKES NO EXTERNAL CALL. A native rules set has no asset, so there is nothing to verify the + * chain against — and nothing to verify: the chain IS this chain, which is what made the + * mode NATIVE in the first place. The universal branch's teeth have no native counterpart + * and must not acquire one. + * + * @param cfg Storage slot to write. + * @param body `abi.encode(NativeTerms)`. + */ + function _initNative(NativeConfig storage cfg, bytes memory body) internal { + NativeTerms memory incoming = abi.decode(body, (NativeTerms)); + + if (incoming.validUntil == 0 || incoming.validUntil <= block.timestamp) { + revert UniversalRulesPolicyErrors.InvalidExpiry(incoming.validUntil); + } + if (incoming.target == address(0)) revert UniversalRulesPolicyErrors.NativeTargetZero(); + if (incoming.target == UNIVERSAL_GATEWAY_PC) { + revert UniversalRulesPolicyErrors.NativeTargetIsGateway(incoming.target); + } + if (incoming.pins.length > MAX_PINS) revert UniversalRulesPolicyErrors.TooManyPins(incoming.pins.length); + + if (incoming.selector == VALUE_SELECTOR) { + if (incoming.pins.length != 0) revert UniversalRulesPolicyErrors.ValueOnlyWithPins(); + if (incoming.amount.enabled) revert UniversalRulesPolicyErrors.ValueOnlyWithAmountRule(); + } + + _storeNative(cfg, incoming); + cfg.initialized = true; + } + + /** + * @dev The SVM init guards — the `solana:*` counterpart of `_initUniversal`. + * - Shape bounds first, then expiry and the three identity fields, then the allow-list + * rules, then the pins, then the teeth. Same discipline as the universal branch: every + * decode and guard before any write. + * - The teeth are IDENTICAL to the universal branch and for the same reason: each listed + * asset's `SOURCE_CHAIN_NAMESPACE()` is what the gateway routes on, so binding the declared + * chain to every one of them here is what makes a `solana:` grant with an EVM asset impossible. + * @param cfg Storage slot to write. + * @param body `abi.encode(SvmTerms)`. + * @param chainHash keccak256 of the declared chain string, verified against every listed asset. + */ + function _initSvm(SvmConfig storage cfg, bytes memory body, bytes32 chainHash) internal { + SvmTerms memory incoming = abi.decode(body, (SvmTerms)); + + uint256 ruleCount = incoming.programs.length; + if (ruleCount == 0 || ruleCount > MAX_ALLOWED_PROGRAMS) { + revert UniversalRulesPolicyErrors.ProgramListOutOfRange(ruleCount); + } + if (incoming.pins.length > MAX_SVM_PINS) { + revert UniversalRulesPolicyErrors.TooManySvmPins(incoming.pins.length); + } + if (incoming.dataPins.length > MAX_SVM_DATA_PINS) { + revert UniversalRulesPolicyErrors.TooManySvmDataPins(incoming.dataPins.length); + } + if (incoming.ceaAccounts.length > MAX_CEA_ACCOUNTS) { + revert UniversalRulesPolicyErrors.TooManyCeaAccounts(incoming.ceaAccounts.length); + } + + if (incoming.validUntil == 0 || incoming.validUntil <= block.timestamp) { + revert UniversalRulesPolicyErrors.InvalidExpiry(incoming.validUntil); + } + if (incoming.expectedCEA == bytes32(0) || incoming.gatewayProgram == bytes32(0)) { + revert UniversalRulesPolicyErrors.InvalidSvmConfigField(); + } + + _checkSvmRules(incoming); + _checkSvmPinShapes(incoming); + _checkCeaAccountList(incoming); + + _requireAssets(incoming.assets, chainHash); + + _storeSvm(cfg, incoming); + cfg.initialized = true; + } + + /** + * @dev Allow-list rule guards: tag shape, forbidden programs, and pairwise exactness. + * - A rule is `dataless` XOR has a 1..8-byte tag. + * - A fixed account count, if set, is within the S13 bound. + * - A program the check path forbids as a target is refused here too; S15 is then defence + * in depth against state this guard makes unreachable. + * - Two rules on one program must not both match one request, or first-match makes the + * later rule dead and its pins never run. O(n^2) at n <= 32. + */ + function _checkSvmRules(SvmTerms memory t) internal pure { + uint256 n = t.programs.length; + for (uint256 i; i < n;) { + AllowedProgram memory r = t.programs[i]; + bool badLen = r.dataless ? r.discriminatorLen != 0 : (r.discriminatorLen == 0 || r.discriminatorLen > 8); + if (badLen) revert UniversalRulesPolicyErrors.DiscriminatorLenOutOfRange(i, r.discriminatorLen); + // A fixed count above the S13 loop bound can never be met: every request would fail + // S13 or S16. Refused here so the owner never grants a rule that is dead on arrival. + if (r.maxAccounts > MAX_SVM_ACCOUNTS) { + revert UniversalRulesPolicyErrors.SvmMaxAccountsOutOfRange(i, r.maxAccounts); + } + if (_isForbiddenProgram(r.program, t.gatewayProgram, t.expectedCEA)) { + revert UniversalRulesPolicyErrors.ForbiddenProgramInAllowList(i, r.program); + } + for (uint256 j; j < i;) { + if (_rulesCollide(t.programs[j], r)) revert UniversalRulesPolicyErrors.AmbiguousRule(j, i); + unchecked { + ++j; + } + } + unchecked { + ++i; + } + } + } + + /// @dev Two rules collide when a single request could match both: same program and either both + /// dataless, or neither dataless with one tag a prefix of the other. A dataless rule and a + /// tagged rule never collide — one needs empty ix_data, the other needs at least the tag. + function _rulesCollide(AllowedProgram memory a, AllowedProgram memory b) internal pure returns (bool) { + if (a.program != b.program) return false; + if (a.dataless || b.dataless) return a.dataless && b.dataless; + uint256 shorter = a.discriminatorLen < b.discriminatorLen ? a.discriminatorLen : b.discriminatorLen; + bytes8 mask = _prefixMask8(shorter); + return (a.discriminator & mask) == (b.discriminator & mask); + } + + /** + * @dev Pin shape guards, both kinds. + * - Account pins: rule in range; index below the loop bound and, when the rule fixes its + * account count, below that too. Every rule must own at least one — HYGIENE: an + * authority-only pin always passes, and which positions must be pinned is the compiler's + * responsibility, not this contract's. + * One pin per (rule, index). + * - Data pins: rule in range and not dataless; `len` 1..32 for EQ, 1..8 otherwise; from-end + * offsets must reach at least `len` back; every offset stays inside the ix_data bound; + * the comparison value must be one the field can actually be compared against + * (`_dataPinValueValid`). + */ + function _checkSvmPinShapes(SvmTerms memory t) internal pure { + uint256 ruleCount = t.programs.length; + bool[] memory covered = new bool[](ruleCount); // rule i has at least one account pin + + uint256 n = t.pins.length; + for (uint256 i; i < n;) { + SvmAccountPin memory pin = t.pins[i]; + if (pin.ruleIndex >= ruleCount) revert UniversalRulesPolicyErrors.SvmPinRuleOutOfRange(i, pin.ruleIndex); + uint8 cap = t.programs[pin.ruleIndex].maxAccounts; + if (pin.accountIndex >= MAX_SVM_ACCOUNTS || (cap != 0 && pin.accountIndex >= cap)) { + revert UniversalRulesPolicyErrors.SvmPinIndexOutOfRange(i, pin.accountIndex); + } + // One position, one pin. Two pins on a (rule, index) are either redundant or + // contradictory, and a contradictory pair makes the rule unsatisfiable. O(n^2), n <= 16. + for (uint256 j; j < i;) { + if (t.pins[j].ruleIndex == pin.ruleIndex && t.pins[j].accountIndex == pin.accountIndex) { + revert UniversalRulesPolicyErrors.DuplicateSvmPin(j, i); + } + unchecked { + ++j; + } + } + covered[pin.ruleIndex] = true; + unchecked { + ++i; + } + } + for (uint256 r; r < ruleCount;) { + if (!covered[r]) revert UniversalRulesPolicyErrors.RuleWithoutPin(r); + unchecked { + ++r; + } + } + + n = t.dataPins.length; + for (uint256 i; i < n;) { + SvmDataPin memory dp = t.dataPins[i]; + if (dp.ruleIndex >= ruleCount || t.programs[dp.ruleIndex].dataless) { + revert UniversalRulesPolicyErrors.SvmDataPinInvalid(i); + } + uint256 maxLen = dp.mode == SvmDataPinMode.EQ ? 32 : 8; + if (dp.len == 0 || dp.len > maxLen) revert UniversalRulesPolicyErrors.SvmDataPinInvalid(i); + if (!_offsetValid(dp.fromEnd, dp.offset, dp.len)) revert UniversalRulesPolicyErrors.SvmDataPinInvalid(i); + if (!_dataPinValueValid(dp)) revert UniversalRulesPolicyErrors.SvmDataPinInvalid(i); + unchecked { + ++i; + } + } + } + + /// @dev A from-start field must end inside the bound; a from-end field must start at least `len` + /// back and no further back than the bound. + function _offsetValid(bool fromEnd, uint16 offset, uint8 len) internal pure returns (bool) { + if (fromEnd) return uint256(offset) >= len && uint256(offset) <= MAX_SVM_IX_DATA; + return uint256(offset) + len <= MAX_SVM_IX_DATA; + } + + /** + * @dev Refuses a data pin whose comparison is vacuous or impossible, and the encoding mistake that + * would make it so. The two value encodings differ by mode — EQ compares LEFT-ALIGNED raw + * bytes, the integer modes compare a RIGHT-ALIGNED integer — and each mis-encoding of one + * as the other is caught here, at grant, instead of producing a pin that silently never + * fails (a ceiling above the field's range) or never passes. + * - EQ: every byte of `expected` past `len` must be zero (a right-aligned integer would + * leave its value there). + * - GTE / LTE: `expected` must fit in `len` bytes, i.e. `< 2^(8·len)`. + * - RATIO: `num` and `den` non-zero (`num == 0` makes `a·den >= 0` always true), and the + * second field's offset valid. + */ + function _dataPinValueValid(SvmDataPin memory dp) internal pure returns (bool) { + if (dp.mode == SvmDataPinMode.EQ) return dp.expected & ~_prefixMask32(dp.len) == bytes32(0); + if (dp.mode == SvmDataPinMode.RATIO_GTE_LE) { + return dp.num != 0 && dp.den != 0 && _offsetValid(dp.fromEnd, dp.offsetB, dp.len); + } + return uint256(dp.expected) >> (8 * uint256(dp.len)) == 0; + } + + /** + * @dev The CEA-controlled account list that S18 enforces. + * - Must contain `expectedCEA`. The CEA always holds value (it is the signer, and pSOL lands + * on it), so an empty or CEA-less list would silently switch the aliasing defence off. + * - No zero entry: `bytes32(0)` is the System program's id, present in most account lists, + * and would make every request fail. + * - No entry equal to an allow-listed program: Anchor passes the program's own account in + * many instructions, and listing it would make every such request fail. + * - No duplicates. + * All four fail closed at check time anyway; refusing them here means an owner never grants + * a rules set that can never be used. + */ + function _checkCeaAccountList(SvmTerms memory t) internal pure { + uint256 n = t.ceaAccounts.length; + bool hasCea; + for (uint256 i; i < n;) { + bytes32 key = t.ceaAccounts[i]; + if (key == bytes32(0)) revert UniversalRulesPolicyErrors.InvalidCeaAccount(i); + if (key == t.expectedCEA) hasCea = true; + for (uint256 j; j < i;) { + if (t.ceaAccounts[j] == key) revert UniversalRulesPolicyErrors.InvalidCeaAccount(i); + unchecked { + ++j; + } + } + uint256 rules = t.programs.length; + for (uint256 r; r < rules;) { + if (t.programs[r].program == key) revert UniversalRulesPolicyErrors.InvalidCeaAccount(i); + unchecked { + ++r; + } + } + unchecked { + ++i; + } + } + if (!hasCea) revert UniversalRulesPolicyErrors.CeaAccountsMissExpectedCEA(); + } + + /// @dev The programs an SVM rules set may never target, directly. Inner CPIs are the allow-listed + /// program's own business — this set guards the top level only. + function _isForbiddenProgram(bytes32 program, bytes32 gatewayProgram, bytes32 cea) internal pure returns (bool) { + return program == SYSTEM_PROGRAM || program == SPL_TOKEN_PROGRAM || program == TOKEN_2022_PROGRAM + || program == STAKE_PROGRAM || program == BPF_LOADER_UPGRADEABLE || program == ADDRESS_LOOKUP_TABLE + || program == gatewayProgram || program == cea; + } + + /** + * @notice Runs every gate a cross-chain agent request must pass. Order is fixed; any failure + * reverts with nothing written. + * + * @dev - Not `view`: gate 7 accumulates spend, and the engine invokes this with a real call + * so the write persists. + * - Runs before the session signature is verified, on unauthenticated calldata from an + * arbitrary caller. It is safe because it makes no external call, applies all effects + * last, and reverts on every failure. Do not introduce an external call here. + * - Replayed signatures cannot burn budget through this door; they die at the wallet's + * nonce gate first. + * + * The gates, in order: + * 1. the config is initialised + * 2. the rules set has not expired + * 3. the target is the gateway + * 4. calldata is at least four bytes; the selector is the outbound send; the body is at + * least the minimum encoded length + * 5. the token is one of the listed assets — on EVERY request, zero amount included, + * because the token is what the gateway routes by + * 6. the amount is within THAT asset's per-call cap + * 7. THAT asset's running total is within its lifetime cap + * 8. the Push-native value is within the per-call ceiling (`maxGasPerCall`) + * 9. the request does not ask for an uncapped gas swap + * 10. the revert recipient is the wallet + * 11. the recipient field is empty + * 12. the payload is a multicall + * 13. the inner call count is between one and the maximum + * 14. no inner call targets the wallet, this policy, the gateway or the destination + * account + * 15. each inner target and selector is allow-listed, and where the rule declares a + * beneficiary it matches the expected destination account + * 16. each inner value is within its rule's allowance + * + * - A zero amount passes gate 6 and writes nothing: zero-amount is the redeployment + * path, acting on capital already at the destination. There is no zero-amount gate and + * one must not be added. + * - `abi.decode` ignores trailing bytes, so gate 4c is a length floor and not a + * canonical-encoding check. There is no exploit: the whole execution calldata is bound + * into the wallet's operation hash, and the signature is verified last. + * - A body of correct length carrying malformed internal offsets reverts with a compiler + * panic rather than a named error. It cannot be given a named error without wrapping + * the decode in an external call, which this function must not have. + * - Spend accumulation is optimistic but atomic: it is written during validation and + * survives only because validation and dispatch share one transaction. Splitting them + * breaks the accounting silently. + * - Gate 14 runs before gate 15 on purpose, so a forbidden destination beats the + * allow-list: an owner who allow-listed their own destination account still cannot + * hand the agent direct control of it. + * + * @param id Config id identifying the rules set. + * @param account The wallet. The engine passes its own caller through as this parameter, so it + * is never the engine itself. + * @param target Push-side call target; must be the gateway. + * @param value Push-native value attached to the call. + * @param data The gateway calldata, opened and walked by the gates above. + * @return The engine's success sentinel. + */ + function checkAction(ConfigId id, address account, address target, uint256 value, bytes calldata data) + external + returns (uint256) + { + // MODE ROUTING. An EMPTY slot falls through to the universal path, whose gate 1 reverts + // `NotInitialized` — fail-closed either way. The `initialized &&` conjunction is what makes + // that safe: `RulesType.UNIVERSAL` is the zero value, so testing `mode` alone could not + // tell an empty slot from a real universal one. + ModeSlot storage slot = _mode[id][msg.sender][account]; + if (slot.initialized) { + if (slot.mode == RulesType.NATIVE) return _checkNative(id, account, target, value, data); + // The family byte was never written by earlier implementations, so it reads 0 = EVM on + // every pre-existing universal slot — those keep routing exactly where they always did. + if (slot.vm == VmFamily.SVM) return _checkSvm(id, account, target, value, data); + } + return _checkUniversal(id, account, target, value, data); + } + + /** + * @dev The universal gauntlet — gates 1 to 16, unchanged from the single-mode contract. Only the + * function name and visibility changed; the body is byte-for-byte what `checkAction` was. + * + * @param id Config id identifying the rules set. + * @param account The wallet. + * @param target Push-side call target; must be the gateway. + * @param value Push-native value attached to the call. + * @param data The gateway calldata. + * @return The engine's success sentinel. + */ + function _checkUniversal(ConfigId id, address account, address target, uint256 value, bytes calldata data) + internal + returns (uint256) + { + Config storage cfg = _configs[id][msg.sender][account]; + + if (!cfg.initialized) revert UniversalRulesPolicyErrors.NotInitialized(id, account); + + if (block.timestamp > cfg.validUntil) revert UniversalRulesPolicyErrors.RulesExpired(cfg.validUntil); + + if (target != UNIVERSAL_GATEWAY_PC) revert UniversalRulesPolicyErrors.InvalidTarget(target); + + if (data.length < 4) revert UniversalRulesPolicyErrors.CalldataTooShort(data.length); + + if (bytes4(data[0:4]) != SEND_OUTBOUND_SELECTOR) { + revert UniversalRulesPolicyErrors.InvalidSelector(bytes4(data[0:4])); + } + + if (data.length < 4 + MIN_OUTBOUND_BODY_LEN) { + revert UniversalRulesPolicyErrors.MalformedOutboundRequest(data.length); + } + UniversalOutboundTxRequest memory req = abi.decode(data[4:], (UniversalOutboundTxRequest)); + + AssetCapState storage cap = _assetFor(cfg.assets, req.token); + + if (req.amount > cap.maxPerCall) { + revert UniversalRulesPolicyErrors.AmountExceedsCap(req.amount, cap.maxPerCall); + } + + uint256 newSpent = cap.spent + req.amount; + if (newSpent > cap.maxTotal) revert UniversalRulesPolicyErrors.TotalSpendCapExceeded(newSpent, cap.maxTotal); + + if (value > cfg.maxGasPerCall) revert UniversalRulesPolicyErrors.PCValueExceedsCap(value, cfg.maxGasPerCall); + + if (req.maxPCForGas == 0) revert UniversalRulesPolicyErrors.UncappedGasSwapRejected(); + + if (req.revertRecipient != account) { + revert UniversalRulesPolicyErrors.InvalidRevertRecipient(account, req.revertRecipient); + } + + if (req.recipient.length != 0) revert UniversalRulesPolicyErrors.RecipientMustBeEmpty(); + + _checkInnerCalls(cfg, account, req.payload); + + if (req.amount > 0) { + cap.spent = newSpent; + emit OutboundMetered(id, msg.sender, account, req.token, req.amount); + } + + return VALIDATION_SUCCESS; + } + + /** + * @dev The native gauntlet — gates N1 to N9, then effects. The same discipline as the universal + * path and for the same reason: this runs BEFORE the session signature is verified, on + * unauthenticated calldata from an arbitrary caller. + * + * - NO EXTERNAL CALLS. Pins and the metered amount are read by slicing `data` directly, + * never through `_slice` into memory and never through a helper that calls out. + * - ALL EFFECTS LAST. `newValueSpent` and `newAmountSpent` are computed at N6/N8 and + * assigned only after N9 passes, exactly as `_checkUniversal` handles `newSpent`. A + * request that fails at N7 leaves every counter untouched. + * - BOUNDS ARITHMETIC IS DONE IN `uint256`. `pin.offset` is `uint16`, so + * `uint256(offset) + 32` cannot wrap — but written as `uint16` arithmetic it would, and + * the check would pass on a crafted offset. Do not "simplify" the cast away. + * - `callsUsed` ALWAYS increments on success, including on a zero-value zero-amount call. + * A call is a use; mirroring universal's zero-amount rule (which writes nothing) would + * make `maxCalls` bypassable by zero-value calls, i.e. advisory. This is the one + * deliberate divergence between the two rulebooks. + * - Value-only configs carry no pins and no amount rule — init refuses that combination — + * so with `data.length == 0` the N7 loop does not execute and N8 is skipped. + * + * @param id Config id identifying the rules set. + * @param account The wallet. + * @param target Push-side call target; must be the configured native target. + * @param value Push-native value attached to the call. + * @param data The native calldata, read but never decoded as a structure. + * @return The engine's success sentinel. + */ + function _checkNative(ConfigId id, address account, address target, uint256 value, bytes calldata data) + internal + returns (uint256) + { + NativeConfig storage cfg = _native[id][msg.sender][account]; + + // N1 + if (!cfg.initialized) revert UniversalRulesPolicyErrors.NotInitialized(id, account); + + // N2 + if (block.timestamp > cfg.validUntil) revert UniversalRulesPolicyErrors.RulesExpired(cfg.validUntil); + + // N3 — the consistency lock, mirror of universal gate 3. Init refuses a gateway target, so + // this can only fire on state the wallet's grant check makes unreachable. It is defence in + // depth against a mis-wired grant, not dead code. + if (target == UNIVERSAL_GATEWAY_PC) revert UniversalRulesPolicyErrors.NativeTargetIsGateway(target); + + // N4 + if (target != cfg.target) revert UniversalRulesPolicyErrors.TargetMismatch(target, cfg.target); + + // N5 — under four bytes is the engine's value-only selector; four or more is a real one. + bytes4 sel = data.length < 4 ? VALUE_SELECTOR : bytes4(data[0:4]); + if (sel != cfg.selector) revert UniversalRulesPolicyErrors.SelectorMismatch(sel, cfg.selector); + // Value-only means EMPTY calldata (register N-46). The engine buckets 1..3 bytes under the + // same actionId, so URP is the layer that makes the documented meaning true. + if (sel == VALUE_SELECTOR && data.length != 0) { + revert UniversalRulesPolicyErrors.ValueOnlyCalldataNotEmpty(data.length); + } + + // N6 + if (value > cfg.maxValuePerCall) revert UniversalRulesPolicyErrors.ValueExceedsCap(value, cfg.maxValuePerCall); + uint256 newValueSpent = cfg.valueSpent + value; + if (newValueSpent > cfg.maxValueTotal) { + revert UniversalRulesPolicyErrors.TotalValueExceeded(newValueSpent, cfg.maxValueTotal); + } + + // N7 + uint256 pinCount = cfg.pins.length; + for (uint256 i; i < pinCount;) { + ArgPin storage pin = cfg.pins[i]; + uint256 needed = uint256(pin.offset) + 32; + if (data.length < needed) revert UniversalRulesPolicyErrors.CalldataTooShortForPin(data.length, i, needed); + + bytes32 actual = bytes32(data[pin.offset:needed]); + if (actual != pin.expected) revert UniversalRulesPolicyErrors.ArgPinMismatch(actual, i, pin.expected); + + unchecked { + ++i; + } + } + + // N8 + uint256 amt; + uint256 newAmountSpent = cfg.amountSpent; + if (cfg.amount.enabled) { + uint256 neededAmt = uint256(cfg.amount.offset) + 32; + if (data.length < neededAmt) { + revert UniversalRulesPolicyErrors.CalldataTooShortForAmount(data.length, neededAmt); + } + + amt = uint256(bytes32(data[cfg.amount.offset:neededAmt])); + if (amt > cfg.amount.maxPerCall) { + revert UniversalRulesPolicyErrors.NativeAmountExceedsCap(amt, cfg.amount.maxPerCall); + } + + newAmountSpent = cfg.amountSpent + amt; + if (newAmountSpent > cfg.amount.maxTotal) { + revert UniversalRulesPolicyErrors.TotalNativeAmountExceeded(newAmountSpent, cfg.amount.maxTotal); + } + } + + // N9 + if (cfg.maxCalls != 0 && cfg.callsUsed >= cfg.maxCalls) { + revert UniversalRulesPolicyErrors.CallLimitReached(cfg.callsUsed, cfg.maxCalls); + } + + // Effects, last. + cfg.valueSpent = newValueSpent; + cfg.amountSpent = newAmountSpent; + unchecked { + // Bounded by N9 when maxCalls != 0; when it is 0 the counter is informational and a + // uint32 overflow is unreachable at any realistic call volume. + cfg.callsUsed = cfg.callsUsed + 1; + } + emit NativeCallMetered(id, msg.sender, account, value, amt); + + return VALIDATION_SUCCESS; + } + + /** + * @dev Implements gates 12 to 16 of `checkAction`'s list. + * + * - Split out for stack depth only. It makes no external call and writes no storage, so the + * caller's effects-last property holds. + * - Gate 12 is not merely a format check: the destination account dispatches on the payload + * prefix, and only the multicall branch has entries that gates 13 to 16 can walk. Its + * other branches re-target the account itself or call an arbitrary target with the raw + * payload, bypassing the allow-list, the beneficiary pin and the per-entry value cap. + * Do not weaken this gate, or the agent picks its own branch. + * - A payload that is exactly the multicall selector, or the selector followed by malformed + * bytes, reverts inside the ABI decoder rather than with a named error. No minimum-length + * pre-check is added: unlike gate 4c, this decode sits behind eleven gates on an already + * constrained request, so a second hand-derived constant would be more surface than the + * named error is worth. It fails closed either way. + * + * @param cfg Config to validate against. + * @param account The wallet, used as the forbidden self-target and the refund destination. + * @param payload The multicall payload carried by the outbound request. + */ + function _checkInnerCalls(Config storage cfg, address account, bytes memory payload) internal view { + if (payload.length < 4 || bytes4(_slice(payload, 0, 4)) != MULTICALL_SELECTOR) { + revert UniversalRulesPolicyErrors.PayloadNotMulticall(); + } + + Multicall[] memory calls = abi.decode(_slice(payload, 4, payload.length - 4), (Multicall[])); + + uint256 count = calls.length; + if (count == 0 || count > MAX_ACTIONS_PER_REQUEST) { + revert UniversalRulesPolicyErrors.BatchSizeOutOfRange(count); + } + + address expectedCEA = cfg.expectedCEA; + + for (uint256 i; i < count;) { + Multicall memory entry = calls[i]; + + if ( + entry.to == account || entry.to == address(this) || entry.to == UNIVERSAL_GATEWAY_PC + || entry.to == expectedCEA + ) { + revert UniversalRulesPolicyErrors.ForbiddenInnerTarget(entry.to); + } + if (entry.data.length < 4) revert UniversalRulesPolicyErrors.MalformedInnerCalldata(); + + AllowedCall memory rule = _requireAllowed(cfg, entry.to, bytes4(_slice(entry.data, 0, 4))); + if (rule.hasBeneficiary) { + address beneficiary = _extractBeneficiary(entry.data, rule.beneficiaryOffset); + if (beneficiary != expectedCEA) { + revert UniversalRulesPolicyErrors.BeneficiaryMismatch(expectedCEA, beneficiary); + } + } + + // Destination-chain native units, never the Push-side value: two assets on two chains. + if (entry.value > rule.maxValue) { + revert UniversalRulesPolicyErrors.InnerValueExceedsAllowance(i, entry.value, rule.maxValue); + } + + unchecked { + ++i; + } + } + } + + /** + * @dev The SVM gauntlet — S1 to S18, then effects. Same discipline as the other two: it runs + * BEFORE the session signature is verified, on unauthenticated calldata from an arbitrary + * caller, so it makes no external call, applies all effects last, and reverts on every + * failure. + * + * S1-S10 are the universal gates 1-10 restated against `SvmConfig` — they are chain- + * independent. S6b is Solana's u64 amount. S11 onwards replace gates 11-16: + * + * S11 the recipient is a 32-byte, non-zero pubkey (the target program) + * S12 the payload is non-empty and parses as the node's execute grammar, exactly + * S13 instruction_id is 2 (execute); account count and ix_data length are within bounds + * S14 the payload's target program equals the recipient + * S15 the target is not a forbidden program + * S16 a rule matches (program, tag) — first match — and its account count, if fixed, holds + * S17 every account pin and every data pin of that rule holds + * S18 every CEA-controlled account in the list sits only where that rule pins it + * + * - A zero amount passes S6/S7 and writes nothing: on SVM that is a payload-only call + * acting on capital already at the destination, the analogue of the EVM redeploy path. + * - The forbidden-program check runs before the allow-list, as gate 14 runs before 15. + */ + function _checkSvm(ConfigId id, address account, address target, uint256 value, bytes calldata data) + internal + returns (uint256) + { + SvmConfig storage cfg = _svm[id][msg.sender][account]; + + if (!cfg.initialized) revert UniversalRulesPolicyErrors.NotInitialized(id, account); + + if (block.timestamp > cfg.validUntil) revert UniversalRulesPolicyErrors.RulesExpired(cfg.validUntil); + + if (target != UNIVERSAL_GATEWAY_PC) revert UniversalRulesPolicyErrors.InvalidTarget(target); + + if (data.length < 4) revert UniversalRulesPolicyErrors.CalldataTooShort(data.length); + + if (bytes4(data[0:4]) != SEND_OUTBOUND_SELECTOR) { + revert UniversalRulesPolicyErrors.InvalidSelector(bytes4(data[0:4])); + } + + if (data.length < 4 + MIN_OUTBOUND_BODY_LEN) { + revert UniversalRulesPolicyErrors.MalformedOutboundRequest(data.length); + } + UniversalOutboundTxRequest memory req = abi.decode(data[4:], (UniversalOutboundTxRequest)); + + AssetCapState storage cap = _assetFor(cfg.assets, req.token); + + if (req.amount > cap.maxPerCall) { + revert UniversalRulesPolicyErrors.AmountExceedsCap(req.amount, cap.maxPerCall); + } + + if (req.amount > type(uint64).max) revert UniversalRulesPolicyErrors.AmountExceedsU64(req.amount); + + uint256 newSpent = cap.spent + req.amount; + if (newSpent > cap.maxTotal) revert UniversalRulesPolicyErrors.TotalSpendCapExceeded(newSpent, cap.maxTotal); + + if (value > cfg.maxGasPerCall) revert UniversalRulesPolicyErrors.PCValueExceedsCap(value, cfg.maxGasPerCall); + + if (req.maxPCForGas == 0) revert UniversalRulesPolicyErrors.UncappedGasSwapRejected(); + + if (req.revertRecipient != account) { + revert UniversalRulesPolicyErrors.InvalidRevertRecipient(account, req.revertRecipient); + } + + // S11 — a zero pubkey is reported with the length it has (32): the shape is right, the value + // is not, and both are "not a pubkey". + if (req.recipient.length != 32) revert UniversalRulesPolicyErrors.RecipientNotPubkey(req.recipient.length); + bytes32 recipient = _loadWord(req.recipient, 0); + if (recipient == bytes32(0)) revert UniversalRulesPolicyErrors.RecipientNotPubkey(32); + + _checkSvmPayload(cfg, recipient, req.payload); + + if (req.amount > 0) { + cap.spent = newSpent; + emit OutboundMetered(id, msg.sender, account, req.token, req.amount); + } + + return VALIDATION_SUCCESS; + } + + /// @dev The parsed shape of an execute payload. Memory only; never stored. + struct SvmPayloadView { + uint256 count; + uint256 ixOff; + uint256 ixLen; + bytes32 target; + } + + /** + * @dev S12 to S18. Split out for stack depth; makes no external call, writes no storage. + * @param cfg Config to validate against. + * @param recipient The request's recipient, already proven to be a non-zero pubkey. + * @param payload The execute payload carried by the outbound request. + */ + function _checkSvmPayload(SvmConfig storage cfg, bytes32 recipient, bytes memory payload) internal view { + SvmPayloadView memory v = _parseSvmPayload(payload); + + if (v.target != recipient) revert UniversalRulesPolicyErrors.RecipientTargetMismatch(recipient, v.target); + + if (_isForbiddenProgram(v.target, cfg.gatewayProgram, cfg.expectedCEA)) { + revert UniversalRulesPolicyErrors.ForbiddenTargetProgram(v.target); + } + + uint256 rule = _matchSvmRule(cfg, payload, v); + + _checkSvmAccountPins(cfg, payload, v, rule); + _checkSvmDataPins(cfg, payload, v, rule); + _checkCeaAccounts(cfg, payload, v, rule); + } + + /** + * @dev S12/S13 — the node's `decodePayload` grammar, byte for byte, including "consumed exactly": + * `[u32 BE count][count × (pubkey32 ‖ writable u8)][u32 BE len][ix_data][u8 id][target32]`. + * Every length is checked before the read it guards. `is_writable` bytes are read past, + * never judged — a wrong flag fails on Solana, not here. + */ + function _parseSvmPayload(bytes memory p) internal pure returns (SvmPayloadView memory v) { + if (p.length == 0) revert UniversalRulesPolicyErrors.SvmPayloadEmpty(); + if (p.length < SVM_HEADER_LEN + SVM_LEN_FIELD + SVM_TRAILER_LEN) { + revert UniversalRulesPolicyErrors.MalformedSvmPayload(1); + } + + v.count = _u32be(p, 0); + if (v.count > MAX_SVM_ACCOUNTS) revert UniversalRulesPolicyErrors.SvmAccountsOutOfRange(v.count); + + uint256 lenOff = SVM_HEADER_LEN + v.count * SVM_ACCOUNT_LEN; + if (p.length < lenOff + SVM_LEN_FIELD) revert UniversalRulesPolicyErrors.MalformedSvmPayload(2); + + v.ixLen = _u32be(p, lenOff); + if (v.ixLen > MAX_SVM_IX_DATA) revert UniversalRulesPolicyErrors.SvmIxDataTooLong(v.ixLen); + v.ixOff = lenOff + SVM_LEN_FIELD; + + uint256 expected = v.ixOff + v.ixLen + SVM_TRAILER_LEN; + if (p.length < expected) revert UniversalRulesPolicyErrors.MalformedSvmPayload(3); + if (p.length > expected) revert UniversalRulesPolicyErrors.MalformedSvmPayload(4); + + uint8 id = uint8(p[v.ixOff + v.ixLen]); + if (id != SVM_INSTRUCTION_EXECUTE) revert UniversalRulesPolicyErrors.SvmInstructionNotExecute(id); + + v.target = _loadWord(p, v.ixOff + v.ixLen + 1); + } + + /** + * @dev S16 — first rule whose program equals the target and whose tag matches: a dataless rule + * matches only empty ix_data; a tagged rule needs at least `discriminatorLen` bytes and a + * prefix-equal tag. Init guarantees at most one rule can match, so first-match is exact. + * Then the rule's fixed account count, if any. + */ + function _matchSvmRule(SvmConfig storage cfg, bytes memory p, SvmPayloadView memory v) + internal + view + returns (uint256) + { + uint256 n = cfg.programs.length; + for (uint256 i; i < n;) { + AllowedProgram storage r = cfg.programs[i]; + if (r.program == v.target && _tagMatches(r, p, v)) { + uint8 cap = r.maxAccounts; + if (cap != 0 && v.count != cap) { + revert UniversalRulesPolicyErrors.SvmAccountCountMismatch(v.count, cap); + } + return i; + } + unchecked { + ++i; + } + } + uint256 shown = v.ixLen < 8 ? v.ixLen : 8; + revert UniversalRulesPolicyErrors.ProgramNotAllowed( + v.target, bytes8(_loadWord(p, v.ixOff)) & _prefixMask8(shown) + ); + } + + function _tagMatches(AllowedProgram storage r, bytes memory p, SvmPayloadView memory v) + internal + view + returns (bool) + { + if (r.dataless) return v.ixLen == 0; + uint8 len = r.discriminatorLen; + if (v.ixLen < len) return false; + bytes8 mask = _prefixMask8(len); + return (bytes8(_loadWord(p, v.ixOff)) & mask) == (r.discriminator & mask); + } + + /// @dev S17, account half: every pin of the matched rule names an index that exists and holds + /// the expected key. + function _checkSvmAccountPins(SvmConfig storage cfg, bytes memory p, SvmPayloadView memory v, uint256 rule) + internal + view + { + uint256 n = cfg.pins.length; + for (uint256 i; i < n;) { + SvmAccountPin storage pin = cfg.pins[i]; + if (pin.ruleIndex == rule) { + if (v.count <= pin.accountIndex) { + revert UniversalRulesPolicyErrors.SvmAccountCountBelowPin(i, v.count, pin.accountIndex); + } + bytes32 actual = _svmAccount(p, pin.accountIndex); + if (actual != pin.expected) { + revert UniversalRulesPolicyErrors.SvmAccountPinMismatch(i, pin.accountIndex, pin.expected, actual); + } + } + unchecked { + ++i; + } + } + } + + /// @dev S17, data half. Offsets resolve from the start or the end of ix_data; init proved the + /// from-end shape reaches at least `len` back, so only the length floor is checked here. + /// Integer reads are little-endian, `len` bytes; the ratio is computed in uint256 and cannot + /// overflow (both operands are at most 64 bits wide). + function _checkSvmDataPins(SvmConfig storage cfg, bytes memory p, SvmPayloadView memory v, uint256 rule) + internal + view + { + uint256 n = cfg.dataPins.length; + for (uint256 i; i < n;) { + SvmDataPin storage dp = cfg.dataPins[i]; + if (dp.ruleIndex == rule) _checkOneDataPin(dp, p, v, i); + unchecked { + ++i; + } + } + } + + function _checkOneDataPin(SvmDataPin storage dp, bytes memory p, SvmPayloadView memory v, uint256 i) internal view { + uint256 off = _resolveOffset(dp.fromEnd, dp.offset, dp.len, v.ixLen, i); + uint256 at = v.ixOff + off; + SvmDataPinMode mode = dp.mode; + + if (mode == SvmDataPinMode.EQ) { + bytes32 mask = _prefixMask32(dp.len); + bytes32 actual = _loadWord(p, at) & mask; + bytes32 want = dp.expected & mask; + if (actual != want) revert UniversalRulesPolicyErrors.SvmDataPinMismatch(i, want, actual); + return; + } + + uint256 a = _uintLE(p, at, dp.len); + if (mode == SvmDataPinMode.GTE_LE) { + if (a < uint256(dp.expected)) { + revert UniversalRulesPolicyErrors.SvmDataFloorNotMet(i, a, uint256(dp.expected)); + } + } else if (mode == SvmDataPinMode.LTE_LE) { + if (a > uint256(dp.expected)) { + revert UniversalRulesPolicyErrors.SvmDataCeilingExceeded(i, a, uint256(dp.expected)); + } + } else { + uint256 offB = _resolveOffset(dp.fromEnd, dp.offsetB, dp.len, v.ixLen, i); + uint256 b = _uintLE(p, v.ixOff + offB, dp.len); + if (a * dp.den < b * dp.num) revert UniversalRulesPolicyErrors.SvmDataRatioNotMet(i, a, b, dp.num, dp.den); + } + } + + /// @dev The field's start relative to ix_data, or `SvmDataTooShortForPin` if ix_data cannot hold it. + function _resolveOffset(bool fromEnd, uint16 offset, uint8 len, uint256 ixLen, uint256 pin) + internal + pure + returns (uint256) + { + if (fromEnd) { + if (ixLen < offset) revert UniversalRulesPolicyErrors.SvmDataTooShortForPin(pin, ixLen); + return ixLen - offset; + } + if (ixLen < uint256(offset) + len) revert UniversalRulesPolicyErrors.SvmDataTooShortForPin(pin, ixLen); + return offset; + } + + /** + * @dev S18 — a CEA-controlled account may appear only where the matched rule pins it. Any other + * occurrence hands a program, running with the CEA's signature, an account it was not + * granted. Accounts absent from `ceaAccounts` are not judged: the list is the owner's + * statement of what holds value. O(count × |ceaAccounts| × |pins|), all bounded. + */ + function _checkCeaAccounts(SvmConfig storage cfg, bytes memory p, SvmPayloadView memory v, uint256 rule) + internal + view + { + // Never empty: init requires `expectedCEA` in the list (`_checkCeaAccountList`). + uint256 listed = cfg.ceaAccounts.length; + for (uint256 i; i < v.count;) { + bytes32 key = _svmAccount(p, i); + for (uint256 c; c < listed;) { + if (cfg.ceaAccounts[c] == key && !_pinnedAt(cfg, rule, i)) { + revert UniversalRulesPolicyErrors.CeaAccountAtUnpinnedIndex(i, key); + } + unchecked { + ++c; + } + } + unchecked { + ++i; + } + } + } + + /// @dev Whether the matched rule pins `index` at all. S17 has already proved that every pinned + /// position holds its expected key, so "pinned" and "pinned to this key" are the same fact + /// here and the key is not re-compared. + function _pinnedAt(SvmConfig storage cfg, uint256 rule, uint256 index) internal view returns (bool) { + uint256 n = cfg.pins.length; + for (uint256 i; i < n;) { + SvmAccountPin storage pin = cfg.pins[i]; + if (pin.ruleIndex == rule && pin.accountIndex == index) return true; + unchecked { + ++i; + } + } + return false; + } + + // ───────────────────────── svm byte helpers (pure, memory only) ───────────────────────── + + /// @dev The pubkey of account `i` in a parsed payload. Callers bound `i` by the parsed count. + function _svmAccount(bytes memory p, uint256 i) internal pure returns (bytes32) { + return _loadWord(p, SVM_HEADER_LEN + i * SVM_ACCOUNT_LEN); + } + + /// @dev Loads 32 bytes at `off`. Every caller has already proved the bytes it USES are inside + /// `b`; bytes past the end are masked away by the caller, never compared. + function _loadWord(bytes memory b, uint256 off) internal pure returns (bytes32 w) { + // solhint-disable-next-line no-inline-assembly + assembly ("memory-safe") { + w := mload(add(add(b, 0x20), off)) + } + } + + function _u32be(bytes memory b, uint256 off) internal pure returns (uint256) { + return uint256(uint32(bytes4(_loadWord(b, off)))); + } + + /// @dev Little-endian unsigned integer of `len` bytes (1..8) starting at `off`. + function _uintLE(bytes memory b, uint256 off, uint256 len) internal pure returns (uint256 v) { + bytes32 w = _loadWord(b, off); + for (uint256 i; i < len;) { + v |= uint256(uint8(w[i])) << (8 * i); + unchecked { + ++i; + } + } + } + + /// @dev Keeps the top `len` bytes of a bytes8. `len` 8 keeps all (a shift by >= 64 is zero). + function _prefixMask8(uint256 len) internal pure returns (bytes8) { + return bytes8(~(type(uint64).max >> (8 * len))); + } + + /// @dev Keeps the top `len` bytes of a bytes32. `len` 32 keeps all. + function _prefixMask32(uint256 len) internal pure returns (bytes32) { + return bytes32(~(type(uint256).max >> (8 * len))); + } + + /** + * @notice Exact-equality assertion on every per-asset spend counter; the change-flow race guard. + * + * @dev - Intended as the first entry of the owner's atomic change batch: assert, revoke, + * grant. A mismatch reverts the whole change. + * - Reverts if the config is not initialised. Reading zero from a ghost config is + * indistinguishable from reading zero from a real unused rules set, and this function + * exists to catch stale belief, so it must not have a silent-pass mode. + * - One expected value per listed asset, in list order; a different count reverts + * `SpentLengthMismatch` rather than checking a prefix. + * - Exact equality in both directions, so a credit landing between read and submit also + * forces recomposition. + * - Callable by anyone; it is a pure read. + * + * @param id Config id identifying the rules set. + * @param account The wallet the rules set belongs to. + * @param expectedSpent The per-asset spend totals the caller composed its change against. + */ + function assertSpent(ConfigId id, address account, uint256[] calldata expectedSpent) external view { + (bool init, RulesType mode) = _modeOf(id, SESSION_ENGINE, account); + if (init && mode == RulesType.NATIVE) revert UniversalRulesPolicyErrors.WrongModeForCall(RulesType.NATIVE); + + AssetCapState[] storage assets = _universalAssets(id, account); + + uint256 n = assets.length; + if (expectedSpent.length != n) revert UniversalRulesPolicyErrors.SpentLengthMismatch(n, expectedSpent.length); + for (uint256 i; i < n;) { + AssetCapState storage a = assets[i]; + if (a.spent != expectedSpent[i]) { + revert UniversalRulesPolicyErrors.AssetSpentMismatch(a.token, expectedSpent[i], a.spent); + } + unchecked { + ++i; + } + } + } + + /** + * @notice The native change-flow race guard: exact equality on all three counters. + * + * @dev - The native counterpart of the universal `assertSpent`, and the same intent: the + * first entry of the owner's atomic change batch — assert, revoke, grant. + * - Reverts `WrongModeForCall(UNIVERSAL)` on a universal config and `NotInitialized` on + * a ghost. It must not have a silent-pass mode: reading zero from a ghost config is + * indistinguishable from reading zero from a real unused rules set, and this function + * exists to catch stale belief. + * - Exact equality on every counter, in both directions. + * - Callable by anyone; it is a pure read. + * + * @param id Config id identifying the rules set. + * @param account The wallet the rules set belongs to. + * @param expectedValueSpent Native value total the caller composed against. + * @param expectedAmountSpent Metered calldata-amount total the caller composed against. + * @param expectedCalls Call count the caller composed against. + */ + function assertSpent( + ConfigId id, + address account, + uint256 expectedValueSpent, + uint256 expectedAmountSpent, + uint32 expectedCalls + ) external view { + (bool init, RulesType mode) = _modeOf(id, SESSION_ENGINE, account); + + if (!init) revert UniversalRulesPolicyErrors.NotInitialized(id, account); + if (mode != RulesType.NATIVE) revert UniversalRulesPolicyErrors.WrongModeForCall(RulesType.UNIVERSAL); + + NativeConfig storage cfg = _native[id][SESSION_ENGINE][account]; + + if (cfg.valueSpent != expectedValueSpent) { + revert UniversalRulesPolicyErrors.SpentMismatch(expectedValueSpent, cfg.valueSpent); + } + if (cfg.amountSpent != expectedAmountSpent) { + revert UniversalRulesPolicyErrors.SpentMismatch(expectedAmountSpent, cfg.amountSpent); + } + if (cfg.callsUsed != expectedCalls) { + revert UniversalRulesPolicyErrors.SpentMismatch(expectedCalls, cfg.callsUsed); + } + } + + /** + * @notice Credits a confirmed far-side failure back to one asset's spend counter. + * + * @dev - Callable only by the executor module; nobody else can fabricate a failure. + * - A ghost config reverts `NotInitialized` and an unlisted token `AssetNotAllowed`; the + * revert rolls the idempotency flag back, so a misrouted credit stays retryable. Both are + * resolved BEFORE the flag is checked, so an already-credited id sent with an unlisted + * token reports the token, the actionable mistake. + * - Reverts if the id was already credited. + * - Subtracts saturating, since the amount is trusted from Push core and cannot be + * verified here. Idempotency and saturation bound a wrong value, PER ASSET: a credit + * can never lower another token's counter. + * - `token` is trusted from the caller as much as `amount` is: URP never learns the + * outbound id at check time, so it cannot map an id to the token it metered. + * - Emits the amount actually applied, not the amount claimed, so monitoring can detect + * divergence between the two. + * - Not yet functional: the executor module does not yet call this on outbound failure, + * so until that lands a failed far leg leaves `spent` inflated and the remedy is + * revoke-and-regrant. + * - There is no gas counter and this path must never introduce one, because gas consumed + * on a failed outbound was genuinely consumed. + * + * @param id Config id identifying the rules set. + * @param account The wallet the rules set belongs to. + * @param outboundTxId Push-core transaction id, the idempotency key. + * @param token The listed asset whose counter is credited. + * @param amount Amount claimed as failed, credited saturating. + */ + function creditRevert(ConfigId id, address account, bytes32 outboundTxId, address token, uint256 amount) external { + if (msg.sender != UNIVERSAL_EXECUTOR_MODULE) revert UniversalRulesPolicyErrors.CallerIsNotUEModule(msg.sender); + + AssetCapState storage cap = _assetFor(_universalAssets(id, account), token); + + if (_credited[outboundTxId]) revert UniversalRulesPolicyErrors.AlreadyCredited(outboundTxId); + _credited[outboundTxId] = true; + + uint256 applied = cap.spent > amount ? amount : cap.spent; + cap.spent -= applied; + + emit RevertCredited(outboundTxId, id, account, token, applied); + } + + /** + * @dev The engine-keyed asset list of a UNIVERSAL config, either family. Reverts `NotInitialized` + * on an empty EVM slot; an SVM family byte is only ever written together with an initialised + * `SvmConfig`, so that branch needs no check. Shared by `assertSpent` and `creditRevert`. + */ + function _universalAssets(ConfigId id, address account) internal view returns (AssetCapState[] storage) { + if (_vmOf(id, SESSION_ENGINE, account) == VmFamily.SVM) return _svm[id][SESSION_ENGINE][account].assets; + + Config storage cfg = _configs[id][SESSION_ENGINE][account]; + if (!cfg.initialized) revert UniversalRulesPolicyErrors.NotInitialized(id, account); + return cfg.assets; + } + + /** + * @dev Gate 5: the entry for `token` in a listed-asset array, or `AssetNotAllowed`. A linear scan + * at n <= MAX_ASSETS, so up to eight cold reads on a miss. Makes no external call. + */ + function _assetFor(AssetCapState[] storage assets, address token) internal view returns (AssetCapState storage) { + uint256 n = assets.length; + for (uint256 i; i < n;) { + AssetCapState storage a = assets[i]; + if (a.token == token) return a; + unchecked { + ++i; + } + } + revert UniversalRulesPolicyErrors.AssetNotAllowed(token); + } + + /** + * @notice The full universal config including the allow-list, keyed on the session engine. + * + * @dev Reverts `WrongModeForCall(NATIVE)` on a native slot. An EMPTY slot returns the zeroed + * struct exactly as it always has — an empty slot is a STATE, a wrong-mode read is a + * CALLER BUG, and only the second is worth a revert. `getMode` is the documented first + * call for anything that does not already know a rules set's mode. + * + * @param id Config id identifying the rules set. + * @param account The wallet the rules set belongs to. + * @return The stored config. + */ + function getConfig(ConfigId id, address account) external view returns (Config memory) { + (bool init, RulesType mode) = _modeOf(id, SESSION_ENGINE, account); + if (init && mode == RulesType.NATIVE) revert UniversalRulesPolicyErrors.WrongModeForCall(RulesType.NATIVE); + if (init && _vmOf(id, SESSION_ENGINE, account) == VmFamily.SVM) { + revert UniversalRulesPolicyErrors.WrongVmForCall(VmFamily.SVM); + } + + return _configs[id][SESSION_ENGINE][account]; + } + + /** + * @notice The full SVM config including its rules and pins, keyed on the session engine. + * @dev Reverts `WrongModeForCall(NATIVE)` on a native slot and `WrongVmForCall(EVM)` on an EVM + * universal slot; an empty slot returns the zeroed struct. See `getConfig`. + * @param id Config id identifying the rules set. + * @param account The wallet the rules set belongs to. + * @return The stored SVM config. + */ + function getSvmConfig(ConfigId id, address account) external view returns (SvmConfig memory) { + (bool init, RulesType mode) = _modeOf(id, SESSION_ENGINE, account); + if (init && mode == RulesType.NATIVE) revert UniversalRulesPolicyErrors.WrongModeForCall(RulesType.NATIVE); + if (init && _vmOf(id, SESSION_ENGINE, account) == VmFamily.EVM) { + revert UniversalRulesPolicyErrors.WrongVmForCall(VmFamily.EVM); + } + + return _svm[id][SESSION_ENGINE][account]; + } + + /** + * @notice The full native config including its pins, keyed on the session engine. + * @dev Reverts `WrongModeForCall(UNIVERSAL)` on a universal slot; an empty slot returns the + * zeroed struct. See `getConfig`. + * @param id Config id identifying the rules set. + * @param account The wallet the rules set belongs to. + * @return The stored native config. + */ + function getNativeConfig(ConfigId id, address account) external view returns (NativeConfig memory) { + (bool init, RulesType mode) = _modeOf(id, SESSION_ENGINE, account); + if (init && mode == RulesType.UNIVERSAL) { + revert UniversalRulesPolicyErrors.WrongModeForCall(RulesType.UNIVERSAL); + } + + return _native[id][SESSION_ENGINE][account]; + } + + /** + * @notice Which rulebook a config uses, and which chain it was granted for. NEVER REVERTS. + * @dev The documented first call for any integrator that does not already know a rules set's + * mode. An empty slot returns `(initialized: false, mode: UNIVERSAL, chainHash: 0)` — and + * the mode value is MEANINGLESS when `initialized` is false, because `UNIVERSAL` is the + * enum's zero value. Read `initialized` first, always. + * + * `chainHash` is the rules set's chain, recorded at init (and, for a universal rules set, + * verified against every listed asset). It is THE chain record; there is no other. + * @param id Config id identifying the rules set. + * @param account The wallet the rules set belongs to. + * @return The stored mode record. + */ + function getMode(ConfigId id, address account) external view returns (ModeSlot memory) { + return _mode[id][SESSION_ENGINE][account]; + } + + /** + * @notice Exposes the idempotency set for monitoring. + * @param outboundTxId Push-core transaction id to query. + * @return Whether that id has already been credited. + */ + function isCredited(bytes32 outboundTxId) external view returns (bool) { + return _credited[outboundTxId]; + } + + /** + * @notice The implementation's version, readable THROUGH the proxy. + * + * @dev The proxy has no version of its own — it delegates, so this answers with whichever + * implementation is currently installed. That makes it the cheapest possible check that + * an upgrade actually took effect: read it before, upgrade, read it again. + * + * A `constant` in bytecode, deliberately not storage: it must change with the CODE, and + * a storage value could drift from the logic it claims to describe. + * + * BUMP THIS IN THE SAME COMMIT AS ANY LOGIC CHANGE. + */ + function version() external pure returns (string memory) { + return "3.1.0"; + } + + /** + * @notice ERC-165 support check. + * @param iid Interface id to query. + * @return True for the action-policy, policy and ERC-165 interfaces. + */ + function supportsInterface(bytes4 iid) external pure returns (bool) { + return + iid == type(IActionPolicy).interfaceId || iid == type(IPolicy).interfaceId + || iid == type(IERC165).interfaceId; + } + + /** + * @dev Reads the 32-byte word at `offset` and returns its low 20 bytes. Bounds-checked because + * reading past the end of a short blob would return adjacent memory, which could be + * manipulated to pass the beneficiary check. + * + * @param data Inner call calldata to read from. + * @param offset Byte offset of the beneficiary word, taken from config and never the request. + * @return The address encoded at that offset. + */ + function _extractBeneficiary(bytes memory data, uint16 offset) internal pure returns (address) { + if (uint256(offset) + 32 > data.length) revert UniversalRulesPolicyErrors.MalformedInnerCalldata(); + bytes32 word; + assembly { + word := mload(add(add(data, 0x20), offset)) + } + return address(uint160(uint256(word))); + } + + /** + * @dev The target and selector pair must appear in the allow-list. + * @param cfg Config whose allow-list is scanned. + * @param to Inner call target. + * @param selector Inner call selector. + * @return The matching rule; reverts with `CallNotAllowed` if there is none. + */ + function _requireAllowed(Config storage cfg, address to, bytes4 selector) + internal + view + returns (AllowedCall memory) + { + uint256 len = cfg.allowedCalls.length; + for (uint256 i; i < len;) { + AllowedCall storage rule = cfg.allowedCalls[i]; + if (rule.target == to && rule.selector == selector) { + return + AllowedCall(rule.target, rule.selector, rule.beneficiaryOffset, rule.hasBeneficiary, rule.maxValue); + } + unchecked { + ++i; + } + } + revert UniversalRulesPolicyErrors.CallNotAllowed(to, selector); + } + + /** + * @dev Memory slice helper. The bounds branch is unreachable from the three call sites, which + * are all length-guarded by gates 12 and 14, and is expected to show as uncovered. It stays + * because this is a `pure` helper whose safety must not depend on every future caller. + * + * @param data Blob to slice. + * @param start Byte offset to start at. + * @param len Number of bytes to copy. + * @return out The requested slice. + */ + function _slice(bytes memory data, uint256 start, uint256 len) internal pure returns (bytes memory out) { + if (start + len > data.length) revert UniversalRulesPolicyErrors.MalformedInnerCalldata(); + out = new bytes(len); + // MCOPY requires evm_version = "cancun"; lowering the EVM target breaks this silently at + // deploy time rather than loudly at compile time. + assembly ("memory-safe") { + mcopy(add(out, 0x20), add(add(data, 0x20), start), len) + } + } + + /** + * @dev Copies decoded WIRE terms into the STORAGE config. The two are deliberately different + * types: the wire shape is free to change, the storage layout is frozen forever + * (see the layout note on `__gap`). + * + * - Forces every asset's `spent` to zero. It is not a wire field at all — URP owns it. + * - Stores no chain: the chain of every rules set lives on `ModeSlot.chainHash`, where it has + * been verified against every listed asset. + * - Clears and repopulates the allow-list. + * - Does not set `initialized`; the caller does, immediately after this returns. + * + * @param cfg Storage slot to write into. + * @param incoming Decoded wire terms to copy from. + */ + function _store(Config storage cfg, UniversalTerms memory incoming) internal { + cfg.validUntil = incoming.validUntil; + cfg.expectedCEA = incoming.expectedCEA; + cfg.maxGasPerCall = incoming.maxGasPerCall; + delete cfg.assets; + _storeAssets(cfg.assets, incoming.assets); + + // Re-initialisation is refused, so in production this array is always empty here. The + // delete is kept for the stranger-slice path and for tests. + delete cfg.allowedCalls; + uint256 len = incoming.allowedCalls.length; + for (uint256 i; i < len;) { + cfg.allowedCalls.push(incoming.allowedCalls[i]); + unchecked { + ++i; + } + } + } + + /// @dev Wire asset caps into storage, element by element, every `spent` forced to zero. Shared by + /// both universal families. The caller deletes `dst` first, as for every other array. + function _storeAssets(AssetCapState[] storage dst, AssetCap[] memory src) internal { + uint256 len = src.length; + for (uint256 i; i < len;) { + dst.push( + AssetCapState({ + token: src[i].token, maxPerCall: src[i].maxPerCall, maxTotal: src[i].maxTotal, spent: 0 + }) + ); + unchecked { + ++i; + } + } + } + + /** + * @dev Copies a decoded native config into storage. The native counterpart of `_store`. + * + * - Forces `valueSpent`, `amountSpent` and `callsUsed` to zero, ignoring anything the + * caller supplied. A caller-set counter would be a granted head start on every cap. + * - `amount` is a value struct with no dynamic members, so it assigns wholesale. + * - `pins` must be copied ELEMENT BY ELEMENT: Solidity cannot assign a memory dynamic array + * into a storage struct field. Same shape as `allowedCalls` above, same reason. + * - Does not set `initialized`; the caller does, immediately after this returns. + * + * @param cfg Storage slot to write into. + * @param incoming Decoded native wire terms to copy from. + */ + function _storeNative(NativeConfig storage cfg, NativeTerms memory incoming) internal { + cfg.validUntil = incoming.validUntil; + cfg.target = incoming.target; + cfg.selector = incoming.selector; + cfg.maxValuePerCall = incoming.maxValuePerCall; + cfg.maxValueTotal = incoming.maxValueTotal; + cfg.valueSpent = 0; + cfg.amount = incoming.amount; + cfg.amountSpent = 0; + cfg.maxCalls = incoming.maxCalls; + cfg.callsUsed = 0; + + // Re-initialisation is refused, so in production this array is always empty here. The + // delete is kept for the stranger-slice path and for tests. + delete cfg.pins; + uint256 len = incoming.pins.length; + for (uint256 i; i < len;) { + cfg.pins.push(incoming.pins[i]); + unchecked { + ++i; + } + } + } + + /** + * @dev Copies decoded SVM wire terms into storage. The SVM counterpart of `_store`. + * - Forces every asset's `spent` to zero; URP owns it. + * - Every dynamic member is copied ELEMENT BY ELEMENT, same shape and same reason as + * `allowedCalls` and `pins`. + * - Does not set `initialized`; the caller does, immediately after this returns. + */ + function _storeSvm(SvmConfig storage cfg, SvmTerms memory incoming) internal { + cfg.validUntil = incoming.validUntil; + cfg.expectedCEA = incoming.expectedCEA; + cfg.gatewayProgram = incoming.gatewayProgram; + cfg.maxGasPerCall = incoming.maxGasPerCall; + delete cfg.assets; + _storeAssets(cfg.assets, incoming.assets); + + delete cfg.ceaAccounts; + uint256 len = incoming.ceaAccounts.length; + for (uint256 i; i < len;) { + cfg.ceaAccounts.push(incoming.ceaAccounts[i]); + unchecked { + ++i; + } + } + + delete cfg.programs; + len = incoming.programs.length; + for (uint256 i; i < len;) { + cfg.programs.push(incoming.programs[i]); + unchecked { + ++i; + } + } + + delete cfg.pins; + len = incoming.pins.length; + for (uint256 i; i < len;) { + cfg.pins.push(incoming.pins[i]); + unchecked { + ++i; + } + } + + delete cfg.dataPins; + len = incoming.dataPins.length; + for (uint256 i; i < len;) { + cfg.dataPins.push(incoming.dataPins[i]); + unchecked { + ++i; + } + } + } +} diff --git a/plan/agw/research/deployment-review-2026-10-06/source/src/validators/AgentValidator.sol b/plan/agw/research/deployment-review-2026-10-06/source/src/validators/AgentValidator.sol new file mode 100644 index 00000000..053a79af --- /dev/null +++ b/plan/agw/research/deployment-review-2026-10-06/source/src/validators/AgentValidator.sol @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import { AgentValidatorErrors } from "../libraries/Errors.sol"; + +import { ISessionValidator } from "smartsessions/interfaces/ISessionValidator.sol"; +import { IAgentValidator } from "../interfaces/IAgentValidator.sol"; +import { AgentConfigLib } from "../libraries/AgentConfigLib.sol"; + +/** + * @title AgentValidator + * @notice A stateless ISessionValidator (ERC-7579 module type 7) that authorises a rules set's agent by + * WHO SENT THE TRANSACTION, not by a signature. The rules set's config is the agent's Push + * address — an EOA, or the UEA of an external key — and the "signature" the engine hands this + * contract is the 20-byte sender the wallet wrote into it. + * + * @dev WHY THIS IS SOUND. The engine calls this only from `validateUserOp`, which reverts unless + * `userOp.sender == msg.sender == account` — so only the wallet can obtain a verdict for its + * own account. The wallet's agent door builds the operation itself and always writes + * `USE ‖ rulesId ‖ msg.sender` into the signature field; no caller-supplied bytes reach it. + * The wallet also refuses a non-agent sender BEFORE the engine runs (`CallerIsNotAgent`); this + * contract is the second, independent layer, and the one the engine requires. + * + * WHY IT STILL EXISTS. SmartSession always ends policy enforcement by calling the permission's + * session validator and reverts `SignerNotFound` without one, and a validator never sees the + * transaction sender. Removing this contract would mean forking the engine. + * + * External-key verification (secp256k1, Ed25519) is NOT done here. It happens inside the + * agent's UEA before the UEA ever calls the wallet. + * + * Holds no storage and calls nothing, so one deployment serves every account. + */ +contract AgentValidator is ISessionValidator, IAgentValidator { + /// @dev ERC-7579 stateless-validator module type. + uint256 internal constant MODULE_TYPE_STATELESS_VALIDATOR = 7; + + /** + * @notice Whether `sig` is the configured agent. + * + * @dev - Reverts `MalformedConfig` if `data` is not a well-formed agent config. Unreachable + * through the wallet's grant path, which runs `validateConfig` first; reachable only for + * a session the owner enabled on the engine directly. + * - Returns false unless `sig` is exactly 20 bytes. + * - Returns whether those 20 bytes equal the configured agent. + * - `hash` is ignored: there is no signature to check it against. + * + * @param sig The 20-byte sender written by the wallet. + * @param data The rules set's config, `abi.encode(address agent)`. + * @return validSig True iff the sender is the agent. + */ + function validateSignatureWithData(bytes32, bytes calldata sig, bytes calldata data) + external + pure + override + returns (bool validSig) + { + address agent = AgentConfigLib.decode(data); + if (agent == address(0)) revert AgentValidatorErrors.MalformedConfig(); + if (sig.length != 20) return false; + // forge-lint: disable-next-line(unsafe-typecast) + return address(bytes20(sig)) == agent; // `sig` is exactly 20 bytes, checked above + } + + /** + * @notice Grant-time config check, used by the wallet's grant path and by tooling. + * + * @dev Two-valued and never reverts: true iff `data` is exactly one ABI word holding a non-zero + * address with clean upper bytes. True means `validateSignatureWithData` will not revert on + * this config; false means it reverts `MalformedConfig`. + * + * @param data Candidate `sessionValidatorInitData`. + * @return True iff `data` is a well-formed agent config. + */ + function validateConfig(bytes calldata data) external pure returns (bool) { + return AgentConfigLib.decode(data) != address(0); + } + + // --- IERC7579Module --- + + /// @dev No-op: the validator holds no per-account state. + function onInstall(bytes calldata) external pure { } + + /// @dev No-op: the validator holds no per-account state. + function onUninstall(bytes calldata) external pure { } + + /** + * @notice Whether this module implements an ERC-7579 module type. + * @param moduleTypeId Module type to query. + * @return True only for the stateless-validator type. + */ + function isModuleType(uint256 moduleTypeId) external pure returns (bool) { + return moduleTypeId == MODULE_TYPE_STATELESS_VALIDATOR; + } + + /** + * @notice Whether this module is initialised for an account. + * @dev Always true: the validator is stateless, so there is nothing to initialise. + * @return Always true. + */ + function isInitialized(address) external pure returns (bool) { + return true; + } +} diff --git a/plan/agw/research/deployment-review-2026-10-06/source/test/unit/28_multiAsset.t.sol b/plan/agw/research/deployment-review-2026-10-06/source/test/unit/28_multiAsset.t.sol new file mode 100644 index 00000000..0dcef8e3 --- /dev/null +++ b/plan/agw/research/deployment-review-2026-10-06/source/test/unit/28_multiAsset.t.sol @@ -0,0 +1,590 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import { UniversalRulesPolicyErrors } from "../../src/libraries/Errors.sol"; + +import { BaseTest } from "../Base.t.sol"; +import { AGW } from "../../src/AGW.sol"; +import { IUniversalRulesPolicy } from "../../src/interfaces/IUniversalRulesPolicy.sol"; +import { AllowedCall, AssetCapState, Config, MAX_ASSETS, Multicall, OwnerIntent } from "../../src/libraries/Types.sol"; +import { ModeLib, ModeCode } from "../../src/libraries/ModeLib.sol"; +import { ExecutionLib } from "../../src/libraries/ExecutionLib.sol"; +import { ConfigId, Session } from "smartsessions/DataTypes.sol"; +import { ISmartSession } from "smartsessions/ISmartSession.sol"; +import { MockPRC20 } from "../mocks/MockUniversalGateway.sol"; +import { MockPRC20Source } from "../mocks/MockPRC20Source.sol"; + +/** + * @title MultiAssetTest — one UNIVERSAL rules set, several tokens (the multi-asset branch) + * @notice A rules set lists 1..MAX_ASSETS PRC20s, each with its own per-call cap, lifetime cap and + * spend counter. These tests pin the three properties the change must not lose: + * - THE CHAIN STAYS PINNED. The gateway routes by `req.token`, so every listed token is + * chain-checked at grant and every request's token must be listed — zero amount included. + * An empty list is refused for the same reason. + * - TOKENS ARE ISOLATED. One token's spend, cap, credit or exhaustion never touches another's. + * - "TOTAL" IS GROSS. A lifetime cap counts what was sent out; money coming back to the wallet + * never restores room (only `creditRevert` lowers a counter). + */ +contract MultiAssetTest is BaseTest { + bytes4 internal constant SWAP_SELECTOR = bytes4(keccak256("swap(uint256,address)")); + uint16 internal constant BENEFICIARY_OFFSET = 36; + ConfigId internal constant CID = ConfigId.wrap(bytes32(uint256(0xA55E7))); + uint48 internal constant VALID_UNTIL = 2_000_000_000; + + string internal constant CHAIN_ARBITRUM_SEPOLIA = "eip155:421614"; + + address internal account; + address internal cea; + address internal protocol; + + /// @dev Two Sepolia PRC20s (the defaults of `MockPRC20`) and one PRC20 of ANOTHER chain. + address internal usdc; + address internal usdt; + address internal arbUsdc; + + function setUp() public override { + super.setUp(); + account = makeAddr("agentWallet"); + cea = makeAddr("destinationAccount"); + protocol = makeAddr("farChainProtocol"); + usdc = address(new MockPRC20()); + usdt = address(new MockPRC20()); + arbUsdc = address(new MockPRC20Source(CHAIN_ARBITRUM_SEPOLIA)); + vm.warp(1_000_000_000); + } + + // ───────────────────────────── builders ───────────────────────────── + + function _rules() internal view returns (AllowedCall[] memory r) { + r = new AllowedCall[](1); + r[0] = AllowedCall({ + target: protocol, + selector: SWAP_SELECTOR, + beneficiaryOffset: BENEFICIARY_OFFSET, + hasBeneficiary: true, + maxValue: 0 + }); + } + + /// @dev The confirmed example: "on Ethereum, move 1000 USDC and 500 USDT". USDC 100/1000, USDT 50/500. + function _two() internal view returns (AssetCapState[] memory a) { + a = new AssetCapState[](2); + a[0] = AssetCapState({ token: usdc, maxPerCall: 100e6, maxTotal: 1000e6, spent: 0 }); + a[1] = AssetCapState({ token: usdt, maxPerCall: 50e6, maxTotal: 500e6, spent: 0 }); + } + + function _config(AssetCapState[] memory assets) internal view returns (Config memory) { + return Config({ + initialized: false, + validUntil: VALID_UNTIL, + expectedCEA: cea, + maxGasPerCall: 5 ether, + assets: assets, + allowedCalls: _rules() + }); + } + + function _init(AssetCapState[] memory assets) internal { + _initAt(CID, assets); + } + + function _initAt(ConfigId id, AssetCapState[] memory assets) internal { + vm.prank(address(engine)); + urp.initializeWithMultiplexer(account, id, universalInitData(_config(assets))); + } + + function _initReverts(bytes memory err, AssetCapState[] memory assets) internal { + vm.prank(address(engine)); + vm.expectRevert(err); + urp.initializeWithMultiplexer(account, CID, universalInitData(_config(assets))); + } + + function _calls() internal view returns (Multicall[] memory c) { + c = new Multicall[](1); + c[0] = Multicall({ to: protocol, value: 0, data: abi.encodeWithSelector(SWAP_SELECTOR, uint256(1), cea) }); + } + + function _req(address token, uint256 amount) internal view returns (bytes memory) { + return outboundRequest(token, amount, 1 ether, account, _calls()); + } + + function _check(address token, uint256 amount) internal { + vm.prank(address(engine)); + urp.checkAction(CID, account, GATEWAY, 0, _req(token, amount)); + } + + function _checkReverts(bytes memory err, address token, uint256 amount) internal { + vm.prank(address(engine)); + vm.expectRevert(err); + urp.checkAction(CID, account, GATEWAY, 0, _req(token, amount)); + } + + function _spent(uint256 i) internal view returns (uint256) { + return urp.getConfig(CID, account).assets[i].spent; + } + + function _spentPair(uint256 a, uint256 b) internal pure returns (uint256[] memory s) { + s = new uint256[](2); + s[0] = a; + s[1] = b; + } + + /// @dev `n` distinct Sepolia PRC20s, each 1/1 capped. + function _many(uint256 n) internal returns (AssetCapState[] memory a) { + a = new AssetCapState[](n); + for (uint256 i; i < n; ++i) { + a[i] = AssetCapState({ token: address(new MockPRC20()), maxPerCall: 1, maxTotal: 1, spent: 0 }); + } + } + + // ═══════════════════════════════ grant time ═══════════════════════════════ + + function test_MA01_twoAssetsStoredInOrderWithZeroSpent() public { + _init(_two()); + Config memory got = urp.getConfig(CID, account); + assertEq(got.assets.length, 2, "two entries"); + assertEq(got.assets[0].token, usdc, "order kept: USDC first"); + assertEq(got.assets[0].maxPerCall, 100e6, "USDC per-call"); + assertEq(got.assets[0].maxTotal, 1000e6, "USDC total"); + assertEq(got.assets[1].token, usdt, "USDT second"); + assertEq(got.assets[1].maxPerCall, 50e6, "USDT per-call"); + assertEq(got.assets[1].maxTotal, 500e6, "USDT total"); + assertEq(got.assets[0].spent + got.assets[1].spent, 0, "every counter starts at zero"); + assertEq(got.maxGasPerCall, 5 ether, "maxGasPerCall stored"); + } + + /** + * ⚠️ NEVER-DELETE. The token is what the gateway routes by, so a rules set with no token pins no + * chain. §4c's "empty = call contracts, move nothing" is refused; move-nothing is one entry with + * a zero `maxPerCall` (MA11). + */ + function test_MA02_emptyAssetListRefused() public { + _initReverts( + abi.encodeWithSelector(UniversalRulesPolicyErrors.AssetListOutOfRange.selector, uint256(0)), + new AssetCapState[](0) + ); + } + + function test_MA03_listBoundIsMaxAssets() public { + assertEq(MAX_ASSETS, 8, "the bound the SDK encodes against"); + _init(_many(MAX_ASSETS)); + assertEq(urp.getConfig(CID, account).assets.length, MAX_ASSETS, "eight accepted"); + + AssetCapState[] memory nine = _many(MAX_ASSETS + 1); + vm.prank(address(engine)); + vm.expectRevert(abi.encodeWithSelector(UniversalRulesPolicyErrors.AssetListOutOfRange.selector, MAX_ASSETS + 1)); + urp.initializeWithMultiplexer(account, ConfigId.wrap(bytes32(uint256(2))), universalInitData(_config(nine))); + } + + /// The duplicate is NOT adjacent: the check compares every pair, not neighbours. + function test_MA04_duplicateTokenRefused() public { + AssetCapState[] memory a = new AssetCapState[](3); + a[0] = AssetCapState({ token: usdc, maxPerCall: 1, maxTotal: 1, spent: 0 }); + a[1] = AssetCapState({ token: usdt, maxPerCall: 1, maxTotal: 1, spent: 0 }); + a[2] = AssetCapState({ token: usdc, maxPerCall: 9, maxTotal: 9, spent: 0 }); + _initReverts(abi.encodeWithSelector(UniversalRulesPolicyErrors.DuplicateAsset.selector, usdc), a); + } + + /** + * ⚠️ NEVER-DELETE. Every listed token is chain-checked, not just the first: a Sepolia rules set + * whose SECOND token is an Arbitrum PRC20 would let the agent route to Arbitrum by naming it. + */ + function test_MA05_everyTokenIsChainChecked() public { + AssetCapState[] memory a = _two(); + a[1].token = arbUsdc; + _initReverts( + abi.encodeWithSelector( + UniversalRulesPolicyErrors.ChainMismatch.selector, + keccak256(bytes(CHAIN_SEPOLIA)), + keccak256(bytes(CHAIN_ARBITRUM_SEPOLIA)) + ), + a + ); + } + + function test_MA06_codelessOrZeroTokenRefusedAtAnyPosition() public { + address codeless = makeAddr("typoedToken"); + AssetCapState[] memory a = _two(); + a[1].token = codeless; + _initReverts(abi.encodeWithSelector(UniversalRulesPolicyErrors.InvalidAsset.selector, codeless), a); + + a = _two(); + a[1].token = address(0); + _initReverts(abi.encodeWithSelector(UniversalRulesPolicyErrors.InvalidAsset.selector, address(0)), a); + } + + // ═══════════════════════════════ check time ═══════════════════════════════ + + /** + * ⚠️ NEVER-DELETE. THE CHAIN-ESCAPE GUARD. A zero-amount request moves nothing, but its token + * still decides the destination chain. If gate 5 ran only for "the token being moved" (§4c's + * wording), an agent could send the rules set's calls to Arbitrum by naming an Arbitrum token + * with amount 0. + */ + function test_MA07_unlistedTokenRefusedEvenAtZeroAmount() public { + _init(_two()); + _checkReverts(abi.encodeWithSelector(UniversalRulesPolicyErrors.AssetNotAllowed.selector, arbUsdc), arbUsdc, 0); + + // An unlisted token of the RIGHT chain is refused too: the list is the owner's statement. + address otherSepolia = address(new MockPRC20()); + _checkReverts( + abi.encodeWithSelector(UniversalRulesPolicyErrors.AssetNotAllowed.selector, otherSepolia), otherSepolia, 0 + ); + + // A listed token at amount 0 passes and writes nothing. + vm.recordLogs(); + _check(usdt, 0); + assertEq(vm.getRecordedLogs().length, 0, "no OutboundMetered for a zero-amount request"); + assertEq(_spent(1), 0, "nothing metered"); + } + + function test_MA08_eachTokenIsMeteredOnItsOwnCounter() public { + _init(_two()); + + vm.expectEmit(true, true, true, true, address(urp)); + emit IUniversalRulesPolicy.OutboundMetered(CID, address(engine), account, usdc, 60e6); + _check(usdc, 60e6); + + vm.expectEmit(true, true, true, true, address(urp)); + emit IUniversalRulesPolicy.OutboundMetered(CID, address(engine), account, usdt, 30e6); + _check(usdt, 30e6); + + _check(usdc, 40e6); + + assertEq(_spent(0), 100e6, "USDC counter: 60 + 40"); + assertEq(_spent(1), 30e6, "USDT counter: 30, untouched by USDC"); + } + + function test_MA09_perCallCapIsTheMatchedTokens() public { + _init(_two()); + // 51 is within USDC's per-call cap (100) and above USDT's (50). + _check(usdc, 51e6); + _checkReverts( + abi.encodeWithSelector(UniversalRulesPolicyErrors.AmountExceedsCap.selector, uint256(51e6), uint256(50e6)), + usdt, + 51e6 + ); + } + + function test_MA10_exhaustingOneTokenLeavesTheOthersUsable() public { + _init(_two()); + for (uint256 i; i < 10; ++i) { + _check(usdc, 100e6); + } + _checkReverts( + abi.encodeWithSelector( + UniversalRulesPolicyErrors.TotalSpendCapExceeded.selector, uint256(1000e6 + 1), uint256(1000e6) + ), + usdc, + 1 + ); + _check(usdt, 50e6); + assertEq(_spent(1), 50e6, "USDT still spends after USDC is exhausted"); + } + + /// Move-nothing: the token pins the chain, the zero per-call cap forbids moving it. + function test_MA11_zeroPerCallTokenRoutesButNeverMoves() public { + AssetCapState[] memory a = new AssetCapState[](1); + a[0] = AssetCapState({ token: usdc, maxPerCall: 0, maxTotal: 0, spent: 0 }); + _init(a); + + _check(usdc, 0); + _checkReverts( + abi.encodeWithSelector(UniversalRulesPolicyErrors.AmountExceedsCap.selector, uint256(1), uint256(0)), + usdc, + 1 + ); + } + + /// Unlimited is `type(uint256).max`, with no special branch; a zero total means NOTHING moves. + function test_MA12_unlimitedIsMaxUintAndZeroTotalMovesNothing() public { + AssetCapState[] memory a = new AssetCapState[](2); + a[0] = AssetCapState({ token: usdc, maxPerCall: type(uint256).max, maxTotal: type(uint256).max, spent: 0 }); + a[1] = AssetCapState({ token: usdt, maxPerCall: 100e6, maxTotal: 0, spent: 0 }); + _init(a); + + _check(usdc, 1e30); + assertEq(_spent(0), 1e30, "unlimited really is unlimited"); + + _checkReverts( + abi.encodeWithSelector(UniversalRulesPolicyErrors.TotalSpendCapExceeded.selector, uint256(1), uint256(0)), + usdt, + 1 + ); + } + + /** + * The bridge-back edge case raised in review: limit 1000, agent sends 600, 300 comes back to the wallet. The agent has + * 400 left, not 700. URP never sees inflows; it could not tell an agent's return from the + * owner's top-up, and counting inflows would let any deposit raise the agent's limit. + */ + function test_MA13_moneyComingBackDoesNotRestoreRoom() public { + AssetCapState[] memory a = new AssetCapState[](1); + a[0] = AssetCapState({ token: usdc, maxPerCall: 1000e6, maxTotal: 1000e6, spent: 0 }); + _init(a); + + _check(usdc, 600e6); + MockPRC20(usdc).mint(account, 300e6); // the 300 coming back, landing on the wallet + assertEq(_spent(0), 600e6, "an inflow changes nothing"); + + _checkReverts( + abi.encodeWithSelector( + UniversalRulesPolicyErrors.TotalSpendCapExceeded.selector, uint256(1001e6), uint256(1000e6) + ), + usdc, + 401e6 + ); + _check(usdc, 400e6); + } + + // ═══════════════════════════ assertSpent / creditRevert ═══════════════════════════ + + function test_MA14_assertSpentIsExactPerAsset() public { + _init(_two()); + _check(usdc, 70e6); + _check(usdt, 20e6); + + urp.assertSpent(CID, account, _spentPair(70e6, 20e6)); + + vm.expectRevert( + abi.encodeWithSelector( + UniversalRulesPolicyErrors.AssetSpentMismatch.selector, usdt, uint256(21e6), uint256(20e6) + ) + ); + urp.assertSpent(CID, account, _spentPair(70e6, 21e6)); + + // A prefix is not accepted: one entry per listed asset, exactly. + vm.expectRevert( + abi.encodeWithSelector(UniversalRulesPolicyErrors.SpentLengthMismatch.selector, uint256(2), uint256(1)) + ); + urp.assertSpent(CID, account, oneSpent(70e6)); + + uint256[] memory three = new uint256[](3); + vm.expectRevert( + abi.encodeWithSelector(UniversalRulesPolicyErrors.SpentLengthMismatch.selector, uint256(2), uint256(3)) + ); + urp.assertSpent(CID, account, three); + } + + function test_MA15_creditRevertTouchesOnlyItsToken() public { + _init(_two()); + _check(usdc, 100e6); + _check(usdt, 50e6); + + bytes32 txId = keccak256("failed-USDT-outbound"); + + // An unlisted token is refused; the revert leaves the id uncredited, so the credit stays retryable. + vm.prank(EXECUTOR_MODULE); + vm.expectRevert(abi.encodeWithSelector(UniversalRulesPolicyErrors.AssetNotAllowed.selector, arbUsdc)); + urp.creditRevert(CID, account, txId, arbUsdc, 20e6); + assertFalse(urp.isCredited(txId), "a misrouted credit does not burn the id"); + + vm.expectEmit(true, true, true, true, address(urp)); + emit IUniversalRulesPolicy.RevertCredited(txId, CID, account, usdt, 20e6); + vm.prank(EXECUTOR_MODULE); + urp.creditRevert(CID, account, txId, usdt, 20e6); + + assertEq(_spent(1), 30e6, "USDT credited"); + assertEq(_spent(0), 100e6, "USDC untouched"); + + // Precedence: the token is resolved before the idempotency check, so an already-credited id + // sent with an unlisted token reports the token, not `AlreadyCredited`. + vm.prank(EXECUTOR_MODULE); + vm.expectRevert(abi.encodeWithSelector(UniversalRulesPolicyErrors.AssetNotAllowed.selector, arbUsdc)); + urp.creditRevert(CID, account, txId, arbUsdc, 1); + } + + /// Per-token isolation under arbitrary amounts: spending one token never moves another's counter. + function testFuzz_MA16_perTokenIsolation(uint256 a, uint256 b) public { + a = bound(a, 0, 100e6); + b = bound(b, 0, 50e6); + _init(_two()); + + _check(usdc, a); + assertEq(_spent(1), 0, "USDT untouched by a USDC spend"); + _check(usdt, b); + assertEq(_spent(0), a, "USDC untouched by a USDT spend"); + assertEq(_spent(1), b, "USDT exact"); + } + + // ═══════════════════════════ through the wallet ═══════════════════════════ + + /// The point of the change: ONE rulesId moves two tokens, through the real engine path. + function test_MA17_oneRulesIdMovesTwoTokensThroughTheWallet() public { + (address agent,) = ecdsaKey("multiAssetAgent"); + address owner = makeAddr("multiAssetOwner"); + AGW wallet = newWallet(owner); + cea = makeAddr("walletCea"); + + Config memory cfg = _config(_two()); + vm.prank(owner); + bytes32 rulesId = wallet.grantRules(canonicalSession(agentConfig(agent), universalInitData(cfg))); + + etchCallRecorder(GATEWAY); + bytes32 mode = ModeCode.unwrap(ModeLib.encodeSimpleSingle()); + vm.prank(agent); + wallet.executeAsAgent(rulesId, mode, _walletEcd(wallet, usdc, 80e6)); + vm.prank(agent); + wallet.executeAsAgent(rulesId, mode, _walletEcd(wallet, usdt, 40e6)); + + ConfigId cid = _walletConfigId(wallet, rulesId); + Config memory got = urp.getConfig(cid, address(wallet)); + assertEq(got.assets[0].spent, 80e6, "USDC metered under the one rulesId"); + assertEq(got.assets[1].spent, 40e6, "USDT metered under the same rulesId"); + + // An unlisted token through the wallet dies at gate 5, named through the engine. + expectUrpGate(abi.encodeWithSelector(UniversalRulesPolicyErrors.AssetNotAllowed.selector, arbUsdc)); + vm.prank(agent); + wallet.executeAsAgent(rulesId, mode, _walletEcd(wallet, arbUsdc, 0)); + } + + function _walletEcd(AGW wallet, address token, uint256 amount) internal view returns (bytes memory) { + return ExecutionLib.encodeSingle(GATEWAY, 0, outboundRequest(token, amount, 1 ether, address(wallet), _calls())); + } + + function _walletConfigId(AGW wallet, bytes32 rulesId) internal view returns (ConfigId) { + bytes32 actionId = keccak256(abi.encodePacked(GATEWAY, SEND_OUTBOUND_SELECTOR)); + bytes32 actionPolicyId = keccak256(abi.encodePacked(rulesId, actionId)); + return ConfigId.wrap(keccak256(abi.encodePacked(address(wallet), actionPolicyId))); + } + + // ═══════════════════ C1: every rule lists at least one token ═══════════════════ + + /** + * ⚠️ NEVER-DELETE. C1: A CROSS-CHAIN RULE MUST LIST AT LEAST ONE TOKEN. + * + * The gateway picks the destination chain from the request's token alone; the request has no + * chain field. A rule with no token therefore pins no chain, and an agent could run its calls on + * any chain by naming that chain's token at amount 0. URP refuses the empty list at grant + * (`AssetListOutOfRange(0)`); this pins that EVERY grant path reaches that refusal: + * 1. `grantRules`; + * 2. `grantRulesWithSig`, a relayer presenting the owner's signed intent; + * 3. the owner door enabling the session on the engine directly, bypassing `grantRules`. + * The revert unwinds everything: the grant nonce and the checkpoint counter do not move. + */ + function test_MA19_ruleWithNoTokenRefusedOnEveryGrantPath() public { + (address owner, uint256 ownerPk) = ecdsaKey("noTokenOwner"); + address relayer = makeAddr("noTokenRelayer"); + AGW wallet = newWallet(owner); + Session memory s = + canonicalSession(agentConfig(makeAddr("noTokenAgent")), universalInitData(_config(new AssetCapState[](0)))); + bytes memory refused = + abi.encodeWithSelector(UniversalRulesPolicyErrors.AssetListOutOfRange.selector, uint256(0)); + uint64 grantNonceBefore = wallet.grantNonce(); + uint64 checkpointsBefore = wallet.checkpointCount(); + + // 1. grantRules + vm.prank(owner); + vm.expectRevert(refused); + wallet.grantRules(s); + + // 2. grantRulesWithSig + OwnerIntent memory intent = blankIntent(owner, address(wallet), relayer); + intent.sessionHash = keccak256(abi.encode(s)); + intent.grantNonce = wallet.grantNonce(); + bytes memory sig = signIntent(ownerPk, intent); + vm.prank(relayer); + vm.expectRevert(refused); + wallet.grantRulesWithSig(s, intent, sig); + + // 3. the owner door, straight to the engine + Session[] memory sessions = new Session[](1); + sessions[0] = s; + bytes memory direct = + ExecutionLib.encodeSingle(address(engine), 0, abi.encodeCall(ISmartSession.enableSessions, (sessions))); + vm.prank(owner); + vm.expectRevert(refused); + wallet.execute(ModeCode.unwrap(ModeLib.encodeSimpleSingle()), direct); + + assertEq(wallet.grantNonce(), grantNonceBefore, "no grant nonce consumed"); + assertEq(wallet.checkpointCount(), checkpointsBefore, "no checkpoint recorded"); + } + + /** + * The SDK's "no tokens" rule, end to end. A user who wants a rule that moves nothing gets one + * token, the destination chain's gas token, with `maxPerCall = 0` and `maxTotal = 0`. The token + * pins the chain; the zero limits mean the agent can make payload-only calls and never move it. + * Through the real wallet and engine: amount 0 passes, amount 1 is refused, and another chain's + * token is refused even at amount 0. + */ + function test_MA20_noMovementRuleIsOneZeroLimitToken() public { + (address agent,) = ecdsaKey("noMovementAgent"); + address owner = makeAddr("noMovementOwner"); + AGW wallet = newWallet(owner); + address gasToken = address(new MockPRC20()); // stands in for the chain's gas token PRC20 + + AssetCapState[] memory pin = new AssetCapState[](1); + pin[0] = AssetCapState({ token: gasToken, maxPerCall: 0, maxTotal: 0, spent: 0 }); + vm.prank(owner); + bytes32 rulesId = wallet.grantRules(canonicalSession(agentConfig(agent), universalInitData(_config(pin)))); + + etchCallRecorder(GATEWAY); + bytes32 mode = ModeCode.unwrap(ModeLib.encodeSimpleSingle()); + + vm.prank(agent); + wallet.executeAsAgent(rulesId, mode, _walletEcd(wallet, gasToken, 0)); + assertEq(urp.getConfig(_walletConfigId(wallet, rulesId), address(wallet)).assets[0].spent, 0, "nothing moved"); + + expectUrpGate( + abi.encodeWithSelector(UniversalRulesPolicyErrors.AmountExceedsCap.selector, uint256(1), uint256(0)) + ); + vm.prank(agent); + wallet.executeAsAgent(rulesId, mode, _walletEcd(wallet, gasToken, 1)); + + expectUrpGate(abi.encodeWithSelector(UniversalRulesPolicyErrors.AssetNotAllowed.selector, arbUsdc)); + vm.prank(agent); + wallet.executeAsAgent(rulesId, mode, _walletEcd(wallet, arbUsdc, 0)); + } + + // ═══════════════════════════════ gas ═══════════════════════════════ + + /// @dev Marginal gate-5 cost of one more listed token ahead of the matched one, budget = measured + /// +10%. Two budgets, because the mode decides warmth: in a plain run the whole test is one + /// transaction, so the slots init just wrote are WARM (measured 402); under `--isolate` / + /// `--gas-report` every call is its own transaction and the entry's `token` slot is a COLD + /// read, as on a real agent call (measured 2,402). Worst case, eight listed tokens and the + /// last one matched: about 16.8k gas over a first-entry match. + uint256 internal constant GATE5_SCAN_GAS_PER_ENTRY_BUDGET = 443; + uint256 internal constant GATE5_SCAN_GAS_PER_ENTRY_BUDGET_ISOLATED = 2_643; + + /** + * The scan is linear: a token at index 7 costs seven extra cold reads over one at index 0. + * Measured on two FRESH configs, each with eight tokens, after a warm-up check on a third, so + * both measured checks start equally cold and differ only in where the match sits. Amount 0, so + * neither check writes. + */ + function test_gas_MA18_gate5ScanCostPerListedToken() public { + AssetCapState[] memory a = _many(MAX_ASSETS); + ConfigId warm = ConfigId.wrap(bytes32(uint256(0xF0))); + ConfigId first = ConfigId.wrap(bytes32(uint256(0xF1))); + ConfigId last = ConfigId.wrap(bytes32(uint256(0xF8))); + _initAt(warm, a); + _initAt(first, a); + _initAt(last, a); + + // Pay the costs both measured checks share — the proxy and implementation accounts, the + // gateway slot — once, on a third config, so they land on neither measurement. + vm.prank(address(engine)); + urp.checkAction(warm, account, GATEWAY, 0, _req(a[0].token, 0)); + + bytes memory hitFirst = _req(a[0].token, 0); + bytes memory hitLast = _req(a[MAX_ASSETS - 1].token, 0); + + vm.prank(address(engine)); + uint256 g0 = gasleft(); + urp.checkAction(first, account, GATEWAY, 0, hitFirst); + g0 -= gasleft(); + + vm.prank(address(engine)); + uint256 g7 = gasleft(); + urp.checkAction(last, account, GATEWAY, 0, hitLast); + g7 -= gasleft(); + + uint256 perEntry = (g7 - g0) / (MAX_ASSETS - 1); + emit log_named_uint("gate-5 scan gas per listed token ahead of the match", perEntry); + emit log_named_uint("checkAction gas, match at index 0 of 8", g0); + emit log_named_uint("checkAction gas, match at index 7 of 8", g7); + uint256 budget = isolatedCalls() ? GATE5_SCAN_GAS_PER_ENTRY_BUDGET_ISOLATED : GATE5_SCAN_GAS_PER_ENTRY_BUDGET; + assertLe(perEntry, budget, "gate-5 scan per entry"); + } +} diff --git a/plan/agw/research/deployment-review-2026-10-06/supplemental-reads.json b/plan/agw/research/deployment-review-2026-10-06/supplemental-reads.json new file mode 100644 index 00000000..f5b33f7c --- /dev/null +++ b/plan/agw/research/deployment-review-2026-10-06/supplemental-reads.json @@ -0,0 +1,25 @@ +{ + "rpc": "https://evm.donut.rpc.push.org/", + "block": 23931055, + "checked_at": "2026-10-05T18:42:12.699217+00:00", + "reads": [ + { + "address": "0x00000000000000000000000000000000000000C0", + "signature": "gasTokenPRC20ByChainNamespace(string)(address)", + "args": [ + "eip155:11155111" + ], + "exit_code": 0, + "output": "0x2971824Db68229D087931155C2b8bB820B275809", + "error": "" + }, + { + "address": "0x603E7f0aF6e1aAFf46DDfb28b1e99364f8BC59af", + "signature": "SESSION_ENGINE()(address)", + "args": [], + "exit_code": 0, + "output": "0x165A5E6782f39D30B38c7D97e1303e4CB2aD102a", + "error": "" + } + ] +} diff --git a/plan/agw/research/deployment-review-2026-10-06/verify-wire.cjs b/plan/agw/research/deployment-review-2026-10-06/verify-wire.cjs new file mode 100644 index 00000000..0ecde19e --- /dev/null +++ b/plan/agw/research/deployment-review-2026-10-06/verify-wire.cjs @@ -0,0 +1,52 @@ +// Read-only ABI/envelope compatibility checks; no signer or transaction submission. +const fs = require('node:fs'); +const path = require('node:path'); +const assert = require('node:assert/strict'); +const v = require('viem'); +const root = __dirname; +const policy = JSON.parse(fs.readFileSync(path.join(root, 'abis/policy.json'), 'utf8')); +const oldPolicy = JSON.parse(fs.readFileSync(path.join(root, '../validation-e704d5b/abi/UniversalRulesPolicy.json'), 'utf8')); +const probe = JSON.parse(fs.readFileSync(path.join(root, 'donut-probe.json'), 'utf8')); +const results = []; + +async function main() { + const header = v.parseAbiParameters('uint16,string,bytes'); + const oldEnvelope = v.encodeAbiParameters(v.parseAbiParameters('string,bytes'), ['eip155:42101', '0x']); + assert.equal(BigInt(oldEnvelope.slice(0, 66)), 64n); + const newEnvelope = v.encodeAbiParameters(header, [1, 'eip155:42101', '0x']); + assert.deepEqual(v.decodeAbiParameters(header, newEnvelope), [1, 'eip155:42101', '0x']); + results.push({check: 'Old SDK envelope starts with 64; v4 requires version 1. Native grants also need migration.', pass: true}); + + const terms = v.parseAbiParameters('(uint48,address,(address,uint256,uint256)[],uint256,(address,bytes4,uint16,bool,uint256)[])'); + const value = [2000000000, probe.code.walletImplementation.address, + [[probe.code.policy.address, 5n, v.maxUint256], [probe.code.factory.address, 0n, 0n]], + 1n, [[probe.code.walletImplementation.address, '0x12345678', 68, true, 0n]]]; + const encoded = v.encodeAbiParameters(terms, [value]); + assert.deepEqual(v.decodeAbiParameters(terms, encoded)[0], value); + results.push({check: 'Owner-guide UniversalTerms tuple round-trips two ordered caps; maxUint256 and zero remain distinct.', pass: true, + note: 'Synthetic codec values only; the addresses used as dummy tokens/CEA/target are not a valid grant or chain-valid token fixture.'}); + + const snapshot = v.createPublicClient({transport: v.http(probe.rpc)}); + const data = v.encodeFunctionData({abi: policy, functionName: 'getConfig', args: [v.zeroHash, probe.code.walletImplementation.address]}); + const raw = await snapshot.call({to: probe.code.policy.address, data, blockNumber: BigInt(probe.block)}); + const cfg = v.decodeFunctionResult({abi: policy, functionName: 'getConfig', data: raw.data}); + assert.equal(cfg.initialized, false); + assert.deepEqual(cfg.assets, []); + let oldDecoderRejected = false; + try { v.decodeFunctionResult({abi: oldPolicy, functionName: 'getConfig', data: raw.data}); } + catch { oldDecoderRejected = true; } + assert.equal(oldDecoderRejected, true); + results.push({check: 'Verified v4 ABI decodes a live empty getConfig; e704d5b ABI rejects the same result.', pass: true, + block: probe.block, returndata: raw.data}); + + const assertion = v.encodeFunctionData({abi: policy, functionName: 'assertSpent', args: [v.zeroHash, probe.code.walletImplementation.address, []]}); + const decoded = v.decodeFunctionData({abi: policy, data: assertion}); + assert.equal(decoded.functionName, 'assertSpent'); + assert.deepEqual(decoded.args[2], []); + results.push({check: 'New array-form assertSpent encodes/decodes using explorer-verified ABI.', pass: true, selector: assertion.slice(0, 10)}); + + fs.writeFileSync(path.join(root, 'wire-checks.json'), JSON.stringify({run_at: new Date().toISOString(), checks: results, + limits: 'Envelope/ABI compatibility and synthetic wire round-trip only. No rule grant, spend-race execution, SDK full-suite rerun or live funded E2E.'}, null, 2) + '\n'); + console.log(JSON.stringify(results.map(({returndata, ...x}) => x), null, 2)); +} +main().catch(e => { console.error(e.message); process.exitCode = 1; }); diff --git a/plan/agw/research/deployment-review-2026-10-06/wire-checks.json b/plan/agw/research/deployment-review-2026-10-06/wire-checks.json new file mode 100644 index 00000000..19ad1267 --- /dev/null +++ b/plan/agw/research/deployment-review-2026-10-06/wire-checks.json @@ -0,0 +1,26 @@ +{ + "run_at": "2026-10-05T18:36:03.715Z", + "checks": [ + { + "check": "Old SDK envelope starts with 64; v4 requires version 1. Native grants also need migration.", + "pass": true + }, + { + "check": "Owner-guide UniversalTerms tuple round-trips two ordered caps; maxUint256 and zero remain distinct.", + "pass": true, + "note": "Synthetic codec values only; the addresses used as dummy tokens/CEA/target are not a valid grant or chain-valid token fixture." + }, + { + "check": "Verified v4 ABI decodes a live empty getConfig; e704d5b ABI rejects the same result.", + "pass": true, + "block": 23931055, + "returndata": "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + }, + { + "check": "New array-form assertSpent encodes/decodes using explorer-verified ABI.", + "pass": true, + "selector": "0x997b1856" + } + ], + "limits": "Envelope/ABI compatibility and synthetic wire round-trip only. No rule grant, spend-race execution, SDK full-suite rerun or live funded E2E." +} diff --git a/plan/agw/research/live-acceptance-2026-10-06/README.md b/plan/agw/research/live-acceptance-2026-10-06/README.md new file mode 100644 index 00000000..70696912 --- /dev/null +++ b/plan/agw/research/live-acceptance-2026-10-06/README.md @@ -0,0 +1,76 @@ +# Donut live acceptance — October 6, 2026 + +Branch `feat/agw-sdk-v4`; runtime commits `a66ff7d` and `b68bab7`, acceptance-test commit `ab42b84`; deployed source `e8db74815cfbbf5389593805e464fe8d85f7f735`. This report supersedes the earlier restricted-environment and unrun-live status. Test funding and broadcasts were authorized by Shoaib. No contract was deployed and no team message was sent. + +## Validation + +| Check | Result | +| --- | --- | +| Full, unfiltered core unit suite | 1,947 passed, 0 failed; 12 existing skips; 113 passed suites, 1 skipped | +| SDK against actual v4 contracts on Anvil | 53 passed in 7 suites, including all 7 SVM integration cases | +| Focused gas/agent-send regressions | 36 passed | +| Typechecks | lib, spec, local harness and portable AGW E2E config pass | +| Build | Nx core:build passes | +| Changed AGW, VM client and acceptance-file lint | 0 errors; existing warnings retained | +| Existing full-core lint | 7 pre-existing errors in unchanged files | +| Explorer ABI comparison | All 5 ABI entry sets match the isolated source build | +| Public SDK Donut derive | Pass; read-only result recorded in the prior v4 report directory | +| Opt-in scenario selection | AGW remains 25 scenarios; default all remains 76 | + +The 53 Anvil cases include actual factory/wallet/engine/validator/URP contracts, with gateway/core/token/executor fixtures. SVM uses encoded Solana terms/payloads inside that local EVM harness; this does not establish live Solana CPI or settlement. The separate 10 Foundry checks are not counted as 10 more SDK integration cases. + +## Funded checks completed + +All 25 registered AGW scenarios have passing live coverage across sequential selected runs. [Per-scenario results and log links](scenario-results.json). These include: + +- Bare wallet creation and information reads. +- Creation with a native rule. +- Native agent transfer, owner transfer, over-cap rejection and stranger initialization rejection. +- Public two-asset grant/read/atomic update, including its five checkpoint ticks. +- Call-only outbound, with confirmed Sepolia delivery through the wallet's CEA. +- Positive-amount outbound: wallet token debit, bounded allowance reduction, confirmed Sepolia receipt, CEA balance increase and replay identity all pass. +- Destination revert: the Push leg succeeds and the receipt classifies the external outcome as failed. + +This was not one complete group invocation: each registered title has a passing selected-run result, with fresh bounded fixtures. Logs include failed initial attempts as well as passing retries; a selected skip is not a pass. [Public wallet/transaction evidence](live-evidence.json) records events produced by successful cases. Individual cases without an evidence event remain verifiable in the saved Jest logs. + +The completed coverage also includes native EIP-7702 batching and rollback, native rule add/update/checkpoint/revoke-all, explicit allowance set/remove, response hooks/replay, revoked and expired rule rejection, existing EVM-origin UEA identity, fresh EVM UEA first-use fee handling and Solana-origin UEA identity on a Push destination. Public Solana destinations remain capability-gated. + +The initial lifecycle run asserted a removed diagnostic kind field from the test helper. On-chain spend/call counters matched. The obsolete field assertion was removed; the entire four-case lifecycle suite then passed. The independent counter, replacement/reset and checkpoint assertions were preserved. + +The fresh EVM first-use test now uses the configured public RPC fallback and waits for the origin funding receipt before spending. [Read-only origin budget preflight](origin-preflight.json) preceded the bounded 0.003 ETH transfer; the existing Solana-origin case uses the configured devnet key. Origin keys were not printed or committed. + +## Issues found and fixed + +1. Donut rejects eth_getLogs ranges larger than 1,000 blocks. Snapshot paging now requests contiguous windows of at most 1,000 blocks. The regression verifies boundary coverage; bare wallet info now passes live. +2. A native gas PRC20 can return a static zero address from SOURCE_TOKEN_ADDRESS(), while ERC20-backed PRC20s return a dynamic string. Native mapping now verifies the registered gas PRC20 before accepting the static-zero result; other malformed metadata fails. The public two-asset grant/read/update now passes live. +3. Viem simulation revert bytes can be in cause.raw. Error extraction preserves them; all seven formerly blocked SVM Anvil cases now pass with named errors. +4. The Sepolia acceptance reader was using viem's default paid dRPC endpoint. It now uses the SDK's configured public RPC fallback. This is test-only transport configuration. +5. The initial positive-amount AGW → gateway → token transaction reverted with its exact RPC gas estimate. At the preceding block, replay fails at 483,168 gas and succeeds at 500,000 and larger limits. Direct gateway and token replays succeed. [Receipt and replay evidence](positive-revert-probe.json) isolates insufficient nested-call gas headroom. Estimated VM-client contract gas now receives 20% headroom, rounded up, consistent with the existing EIP-7702 path. Explicit gas limits and the 21,000-gas code-free EOA path are unchanged. This Push execution limit is separate from destination gas and the URP PC budget. The regression checks the observed estimate, explicit-gas preservation and EOA/delegated-account behavior. The passing Push receipt additionally records the exact pETH transfer from wallet to C1 and its C1-to-zero burn. [Push receipt/events and gas](positive-push-events.json). + +## Funding and evidence boundaries + +The loader uses packages/core/.env. Key values stay in memory and are redacted from copied artifacts; no key was printed or committed. [Read-only preflight](preflight.json) verifies chain 42101, deployment wiring, balances and bounded reserves before funding. Outbound setup uses a fresh wallet, 21 PC (20 PC ceiling plus 1), 0.000003 pETH and a bounded 0.000002 pETH gateway allowance. Each fresh Push agent receives 0.5 PC. Funding is separate from creation/rule grants. + +Unspent funds can remain in fresh master-owned test wallets; no shared wallet was revoked or drained. Destination success checks use a fresh wallet CEA and independently verify its balance increase. A read-only check of the confirmed Sepolia receipt additionally verifies the `UniversalTxExecuted` emitter equals that CEA, originCaller equals the AGW, and target/data equal the intended counter/increment. [Attribution evidence](positive-destination-execution.json). The same assertion is now in the live test without submitting a duplicate funded transaction for that extra receipt check. creditRevert remains an executor dependency. A real far-side failure must not be treated as restoring the policy spend. + +[Sanitized logs](logs/) preserve commands' output and initial failures; trailing whitespace/extra EOF blank lines were normalized for Git. No full security audit or complete release acceptance is claimed. Product H3/H4.5/H6, ref/label scope and public SVM mapping are separate remaining decisions. + +## Reproduction + +From the SDK root, using the existing local test environment: + +```sh +AGW_LOCAL_DIR="${TMPDIR:-/tmp}/push-agw-local-v4" node node_modules/jest/bin/jest.js --config packages/core/jest.agw-local.config.ts --runInBand +node node_modules/jest/bin/jest.js --config packages/core/jest.config.ts --runInBand +node node_modules/typescript/bin/tsc --project packages/core/tsconfig.lib.json --noEmit +node node_modules/typescript/bin/tsc --project packages/core/tsconfig.spec.json --noEmit +node node_modules/typescript/bin/tsc --project packages/core/tsconfig.agw-local.json --noEmit +node node_modules/typescript/bin/tsc --project plan/agw/research/v4-implementation-2026-10-06/tsconfig.agw-e2e.json --noEmit +NX_DAEMON=false node node_modules/nx/bin/nx.js run core:build --skip-nx-cache +``` + +The opt-in live command submits transactions and spends testnet funds. Use the same verified manifest and bounded fixtures, run sequentially, and choose scenarios deliberately: + +```sh +AGW_E2E=1 AGW_E2E_AGENT_PC=0.5 node node_modules/jest/bin/jest.js --config packages/core/jest.e2e.config.ts --runInBand --forceExit --runTestsByPath packages/core/__e2e__/agw/universal-evm.spec.ts +``` diff --git a/plan/agw/research/live-acceptance-2026-10-06/live-evidence.json b/plan/agw/research/live-acceptance-2026-10-06/live-evidence.json new file mode 100644 index 00000000..9399561b --- /dev/null +++ b/plan/agw/research/live-acceptance-2026-10-06/live-evidence.json @@ -0,0 +1,145 @@ +[ + { + "name": "create-with-rule", + "at": "2026-10-05T21:06:35.105Z", + "network": "TESTNET_DONUT", + "sourceCommit": "e8db74815cfbbf5389593805e464fe8d85f7f735", + "wallet": "0x428325Ce3966A4B32D8B1d929AB0Df0723042Da4", + "rulesIds": [ + "0x6f7881f8a6e019f0a91d639dfd26170eebf12884348ed8f7f0490ed0f85e1ddf" + ], + "tx": "0xac162329f85fac96ca3fadd453aa151a92f224033f88fa49a4a33062dbd81fc0", + "atomic": true + }, + { + "name": "native-agent-send", + "at": "2026-10-05T21:07:11.307Z", + "network": "TESTNET_DONUT", + "sourceCommit": "e8db74815cfbbf5389593805e464fe8d85f7f735", + "wallet": "0xc8982105786701598aE2A4E6685304074e7e99f0", + "rulesId": "0xfe24f47d822c340f0ccfac6c3fb70ea6337c52f27dad2cf5949fdf14cb07a6ae", + "tx": "0x18a59103e292e5b4a70e6ea1bdb14dbccf7e04e0562f6a2cefbfc219cde2bf43", + "block": "23934793" + }, + { + "name": "create-bare", + "at": "2026-10-05T21:10:27.937Z", + "network": "TESTNET_DONUT", + "sourceCommit": "e8db74815cfbbf5389593805e464fe8d85f7f735", + "wallet": "0x91B812Fa58775a6C287658d2A51Ff899aDF3308E", + "index": 3, + "tx": "0xa9e5f13e0d4629e0be1746d0c8fe0646a9c65c4bd42256d2bb8eae7e09dd8865", + "block": "23934869" + }, + { + "name": "v4-two-token-replacement", + "at": "2026-10-05T21:16:54.137Z", + "network": "TESTNET_DONUT", + "sourceCommit": "e8db74815cfbbf5389593805e464fe8d85f7f735", + "wallet": "0xcd9FB65aeDB3b200163D3209520926181a2C0611", + "oldId": "0xef98211b8734b57da5fba9ad7b32e3b5e7e6c3779e4ad86c22e2882b21810f77", + "newId": "0xeef1b885580ab2ae5ea2a1e112e72f4df94d7e2173406c400f697b4b68da4341", + "txHash": "0x31e2c657ba10d4da07c7453c8a41810af9d7e9152d9e48b5155d623a29e09f5a" + }, + { + "name": "v4-call-only", + "at": "2026-10-05T21:21:18.546Z", + "network": "TESTNET_DONUT", + "sourceCommit": "e8db74815cfbbf5389593805e464fe8d85f7f735", + "wallet": "0x4780C8fd6643387BB1af016CB750fe0b8F17ed5e", + "pushTx": "0x7fb0792747909149da3c8975aaba43a80224a20544c41ac88c04a3cf899c9926", + "externalTx": "0xadb89cd9cfb70fd33b9eaa2e05b109b0a9a26d3fb9221e8dc28cd8cf8d4f27fe" + }, + { + "name": "universal-outbound", + "at": "2026-10-05T21:51:27.498Z", + "network": "TESTNET_DONUT", + "sourceCommit": "e8db74815cfbbf5389593805e464fe8d85f7f735", + "wallet": "0x1C015E6B101ad2965D9912437c2499262Ef8F502", + "cea": "0x485E0aF54D8944ebDF9a3eC9641D8aB838b7C590", + "rulesId": "0xa7b3993ea6ec9794d0d46574def4379a96340773e242fbc6082c2c5c690902a4", + "pushTx": "0x3236bbc8f2029f53a2aa09d0c0d3cd291568bbaccf4de70061ecd085d4adcb3e", + "externalTx": "0x1dac9f08f651c30e0c2de11c42c8df8bbcbd12484575b536e4d42f40819989ea", + "amount": "1000000000000" + }, + { + "name": "universal-destination-revert", + "at": "2026-10-05T21:53:12.285Z", + "network": "TESTNET_DONUT", + "sourceCommit": "e8db74815cfbbf5389593805e464fe8d85f7f735", + "wallet": "0x1C015E6B101ad2965D9912437c2499262Ef8F502", + "pushTx": "0xe64f8e09992b059feaaf77a00182f2337105479af028212876b5031f2363f71e", + "externalStatus": "failed" + }, + { + "name": "native-agent-batch", + "at": "2026-10-05T21:56:41.474Z", + "network": "TESTNET_DONUT", + "sourceCommit": "e8db74815cfbbf5389593805e464fe8d85f7f735", + "wallet": "0x93e17E662a68fAD566A9BF85B864e44e13e17c4F", + "rulesId": "0x1bbae44588285709fd2b6a7819e9c7b2cfecfb9d1d434bca710d5693e2a46804", + "tx": "0x33aa4cceb64dc6652324aaab72917212a27cab191d353cd311ec81b7fa648679" + }, + { + "name": "native-agent-batch-rollback", + "at": "2026-10-05T21:57:09.796Z", + "network": "TESTNET_DONUT", + "sourceCommit": "e8db74815cfbbf5389593805e464fe8d85f7f735", + "wallet": "0xBab9effbE66F51aF9Ca592472C80536EE87B0C0b", + "rulesId": "0x1bbae44588285709fd2b6a7819e9c7b2cfecfb9d1d434bca710d5693e2a46804" + }, + { + "name": "replay-identity", + "at": "2026-10-05T21:58:18.163Z", + "network": "TESTNET_DONUT", + "sourceCommit": "e8db74815cfbbf5389593805e464fe8d85f7f735", + "wallet": "0x4114E1aE8e076818336da09e3B3A3a7a11258766", + "tx": "0xbf615e5c7dda51d0b448a792bfcd446de8ca49b1939d453cd4a92044db1bf236" + }, + { + "name": "allowance-set-remove", + "at": "2026-10-05T21:59:07.661Z", + "network": "TESTNET_DONUT", + "sourceCommit": "e8db74815cfbbf5389593805e464fe8d85f7f735", + "wallet": "0x4A75e0060de0287987FFF9b33985119e448Ab0cE", + "token": "0x2971824Db68229D087931155C2b8bB820B275809", + "setTx": "0x8e0cfab44132e406fa3af77434f324def1bcb4ed7386dddff5d6b6c6854da3dd" + }, + { + "name": "rules-update", + "at": "2026-10-05T22:00:56.863Z", + "network": "TESTNET_DONUT", + "sourceCommit": "e8db74815cfbbf5389593805e464fe8d85f7f735", + "wallet": "0x5657d413eC5f1d4Fa9Fc6a91210b29a5C399046F", + "original": "0x76aeb12a16f8dd99ce775fffc6642f28c8f99668cf509cee99ea1335c6d2f8d9", + "replacement": "0xd687e19b9ab378328b341320981ca4259682220ea589dee5a13b22ad46bc859a", + "tx": "0x21b1f56f999773e29c516c1944976ee923f972857211db1e8c005cb441e7526b", + "checkpointDelta": 5 + }, + { + "name": "external-evm-agent", + "at": "2026-10-05T22:02:03.221Z", + "network": "TESTNET_DONUT", + "sourceCommit": "e8db74815cfbbf5389593805e464fe8d85f7f735", + "wallet": "0x24CB91b9284097E591F36476bBc2d165AAc51873", + "uea": "0x5C70C864Cf1aDfB04A0e107fFA248ba3600EAb8D", + "tx": "0xc3f7bd68a84b7042189cd5540917f5dfd8e9b991f0548511e80801df845b8ba7" + }, + { + "name": "first-use-uea", + "at": "2026-10-05T22:03:29.060Z", + "network": "TESTNET_DONUT", + "sourceCommit": "e8db74815cfbbf5389593805e464fe8d85f7f735", + "wallet": "0xa416185c2e1790A4f23da0Bb16FfEA95aca95EA1", + "uea": "0x0302B6d6dadDb35F3b5618b39E01C7bB874FC156" + }, + { + "name": "solana-origin-agent", + "at": "2026-10-05T22:04:00.125Z", + "network": "TESTNET_DONUT", + "sourceCommit": "e8db74815cfbbf5389593805e464fe8d85f7f735", + "wallet": "0xE66E9C651548f2f94d16F4daC9C872c5dEF4361a", + "uea": "0xad977a75D8BEd06579D6498b7e2e3885f9D31F15", + "tx": "0xf010a8c0690cd1b4696a8d5b186663bc1ffd7def8acee86016c5d552f96b03a0" + } +] diff --git a/plan/agw/research/live-acceptance-2026-10-06/logs/agw-final-build.log b/plan/agw/research/live-acceptance-2026-10-06/logs/agw-final-build.log new file mode 100644 index 00000000..bf76aced --- /dev/null +++ b/plan/agw/research/live-acceptance-2026-10-06/logs/agw-final-build.log @@ -0,0 +1,11 @@ + +> nx run core:build + +Compiling TypeScript files for project "core"... +Done compiling TypeScript files for project "core". +(node:98450) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. +(Use `node --trace-warnings ...` to show where the warning was created) + + + + NX Successfully ran target build for project core diff --git a/plan/agw/research/live-acceptance-2026-10-06/logs/agw-final-e2e-tsc.log b/plan/agw/research/live-acceptance-2026-10-06/logs/agw-final-e2e-tsc.log new file mode 100644 index 00000000..e69de29b diff --git a/plan/agw/research/live-acceptance-2026-10-06/logs/agw-final-lib-tsc.log b/plan/agw/research/live-acceptance-2026-10-06/logs/agw-final-lib-tsc.log new file mode 100644 index 00000000..e69de29b diff --git a/plan/agw/research/live-acceptance-2026-10-06/logs/agw-final-lint.log b/plan/agw/research/live-acceptance-2026-10-06/logs/agw-final-lint.log new file mode 100644 index 00000000..f12c71c9 --- /dev/null +++ b/plan/agw/research/live-acceptance-2026-10-06/logs/agw-final-lint.log @@ -0,0 +1,91 @@ + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__agw-local__/agw-local-advanced.spec.ts + 73:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 85:17 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 295:22 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 311:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 337:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 426:13 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__agw-local__/agw-local-batch.spec.ts + 44:16 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 90:37 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 91:46 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 98:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 106:16 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__agw-local__/agw-local-races.spec.ts + 54:20 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 99:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 117:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 145:20 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__agw-local__/agw-local.spec.ts + 47:17 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 48:17 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__agw-local__/harness.ts + 210:16 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 229:16 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 238:17 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 373:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__agw-local__/svm-internals.spec.ts + 86:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 119:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 189:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__agw-local__/v4-multiasset.spec.ts + 12:10 warning 'createWallet' is defined but never used @typescript-eslint/no-unused-vars + 78:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 92:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 176:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 188:16 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 325:16 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 335:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 353:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__agw-local__/vectors.spec.ts + 56:7 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 57:7 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 98:7 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 207:25 warning '_a' is assigned a value but never used @typescript-eslint/no-unused-vars + 208:25 warning '_b' is assigned a value but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/agw/identity-gas.spec.ts + 62:123 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/agw/universal-evm.spec.ts + 27:10 warning 'v4' is defined but never used @typescript-eslint/no-unused-vars + 41:17 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/agw/v4-multiasset.spec.ts + 17:17 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/codec.spec.ts + 373:21 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/management.spec.ts + 12:10 warning 'AgenticCapability' is defined but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts + 2:17 warning 'PUSH_NETWORK' is defined but never used @typescript-eslint/no-unused-vars + 41:21 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/reads-context.spec.ts + 374:5 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/response-surface.spec.ts + 4:3 warning 'getAddress' is defined but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts + 457:21 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/reads/rules.ts + 3:3 warning 'isAddress' is defined but never used @typescript-eslint/no-unused-vars + 11:3 warning 'CAPABILITY_DEPENDENCY' is defined but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/wallet.ts + 92:33 warning '_opts' is defined but never used @typescript-eslint/no-unused-vars + +✖ 51 problems (0 errors, 51 warnings) diff --git a/plan/agw/research/live-acceptance-2026-10-06/logs/agw-final-live-lint.log b/plan/agw/research/live-acceptance-2026-10-06/logs/agw-final-live-lint.log new file mode 100644 index 00000000..5800fb9e --- /dev/null +++ b/plan/agw/research/live-acceptance-2026-10-06/logs/agw-final-live-lint.log @@ -0,0 +1,9 @@ + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/agw/identity-gas.spec.ts + 112:16 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/agw/universal-evm.spec.ts + 29:10 warning 'v4' is defined but never used @typescript-eslint/no-unused-vars + 43:17 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +✖ 3 problems (0 errors, 3 warnings) diff --git a/plan/agw/research/live-acceptance-2026-10-06/logs/agw-final-local-tsc.log b/plan/agw/research/live-acceptance-2026-10-06/logs/agw-final-local-tsc.log new file mode 100644 index 00000000..e69de29b diff --git a/plan/agw/research/live-acceptance-2026-10-06/logs/agw-final-selection-agw.log b/plan/agw/research/live-acceptance-2026-10-06/logs/agw-final-selection-agw.log new file mode 100644 index 00000000..16369abf --- /dev/null +++ b/plan/agw/research/live-acceptance-2026-10-06/logs/agw-final-selection-agw.log @@ -0,0 +1,28 @@ +✓ agw-create-bare 1 test +✓ agw-create-rules 1 test +✓ agw-funding-pc 1 test +✓ agw-funding-allowance 1 test +✓ agw-native-batch 1 test +✓ agw-native-batch-rollback 1 test +✓ agw-native-agent 1 test +✓ agw-native-owner 1 test +✓ agw-native-over-cap 1 test +✓ agw-native-stranger 1 test +✓ agw-native-revoked 1 test +✓ agw-native-expired 1 test +✓ agw-lifecycle-add 1 test +✓ agw-lifecycle-update 1 test +✓ agw-lifecycle-checkpoints 1 test +✓ agw-lifecycle-revoke-all 1 test +✓ agw-universal-outbound 1 test +✓ agw-v4-multi-asset 1 test +✓ agw-v4-call-only 1 test +✓ agw-universal-dest-revert 1 test +✓ agw-identity-evm 1 test +✓ agw-identity-first-use 1 test +✓ agw-identity-solana 1 test +✓ agw-responses-hooks 1 test +✓ agw-responses-replay 1 test + +25 scenarios, 9 spec files, 25 distinct tests. +Manifest is consistent with the specs. diff --git a/plan/agw/research/live-acceptance-2026-10-06/logs/agw-final-selection-all.log b/plan/agw/research/live-acceptance-2026-10-06/logs/agw-final-selection-all.log new file mode 100644 index 00000000..dfa5f250 --- /dev/null +++ b/plan/agw/research/live-acceptance-2026-10-06/logs/agw-final-selection-all.log @@ -0,0 +1,79 @@ +✓ smoke-uea-derive-evm 1 test +✓ smoke-read-track-lookup 1 test +✓ smoke-cea-derive-evm 1 test +✓ smoke-roundtrip-evm 1 test +✓ smoke-roundtrip-svm 1 test +✓ smoke-cea-pda-svm 1 test +✓ smoke-gasfee-reads 2 tests +✓ smoke-gas-sizer 2 tests +✓ smoke-pc20-registry 2 tests +✓ smoke-pc20-resolve 1 test +✓ evm-r1-transfer 1 test +✓ evm-r1-funds-usdt 1 test +✓ evm-r1-funds-native 1 test +✓ evm-r1-value-funds-data 1 test +✓ evm-r1-bridge-multicall 1 test +✓ evm-r1-fresh-value-native 1 test +✓ evm-r2-funds-erc20 1 test +✓ evm-r2-payload 1 test +✓ evm-r2-multicall 1 test +✓ evm-r2-funds-payload 1 test +✓ evm-r2-native-funds 1 test +✓ evm-r2-native-funds-payload 1 test +✓ evm-r3-funds-erc20 1 test +✓ evm-r3-payload 1 test +✓ evm-r3-multicall 1 test +✓ evm-r3-funds-payload 1 test +✓ evm-r3-native-funds 1 test +✓ evm-r3-eoa-native-funds 1 test +✓ svm-r1-transfer 1 test +✓ svm-r1-funds-sol-self 1 test +✓ svm-r1-value-self 1 test +✓ svm-r1-data-contract 1 test +✓ svm-r1-fresh-key-repro 1 test +✓ svm-r2-funds-sol 1 test +✓ svm-r2-funds-spl 1 test +✓ svm-r2-payload-cpi 1 test +✓ svm-r2-sol-cpi 1 test +✓ svm-r3-drain-sol 1 test +✓ svm-r3-drain-spl 1 test +✓ pc20-export-deployed-wrapper 1 test +✓ pc20-export-predicts-wrapper 1 test +✓ pc20-inbound-burn-unlock 1 test +✓ pc20-r3-cea-burn 1 test +✓ pc20-svm-r1-direct-burn 1 test +✓ pc20-svm-r3-cea-ata-burn 1 test +✓ push-send-transaction 1 test +✓ push-value-own-uea 1 test +✓ push-multicall-no-funds 1 test +✓ push-track-r1-sepolia-parity 1 test +✓ push-track-r3-funds-roundtrip 1 test +✓ push-track-source-leg-hashes 2 tests +✓ xc-multi-child-r3 1 test +✓ xc-fresh-wallet-r3 1 test +✓ xc-peth-bridge-back 1 test +✓ xc-cascade-6hop 1 test +✓ read-evm-balance-eoa 1 test +✓ read-canonical-registry 1 test +✓ read-evm-balance-uea 1 test +✓ read-evm-contract-call 1 test +✓ read-evm-callback-reverts 1 test +✓ read-expiry 1 test +✓ read-svm-lamports 1 test +✓ read-web2-json 1 test +✓ read-docs-example 1 test +✓ read-docs-evm-balance 1 test +✓ read-docs-batch 1 test +✓ read-docs-resume 2 tests +✓ read-app-batch-eoa 1 test +✓ read-app-batch-uea 1 test +✓ read-app-batch-recovery 1 test +✓ read-api-token 1 test +✓ read-api-mixed-outcomes 1 test +✓ read-svm-token-auto 1 test +✓ read-svm-idl 1 test +✓ read-evm-any-mutability 1 test +✓ read-svm-raw 1 test + +76 scenarios, 40 spec files, 81 distinct tests. +Manifest is consistent with the specs. diff --git a/plan/agw/research/live-acceptance-2026-10-06/logs/agw-final-spec-tsc.log b/plan/agw/research/live-acceptance-2026-10-06/logs/agw-final-spec-tsc.log new file mode 100644 index 00000000..e69de29b diff --git a/plan/agw/research/live-acceptance-2026-10-06/logs/agw-final-unit.log b/plan/agw/research/live-acceptance-2026-10-06/logs/agw-final-unit.log new file mode 100644 index 00000000..e82c719e --- /dev/null +++ b/plan/agw/research/live-acceptance-2026-10-06/logs/agw-final-unit.log @@ -0,0 +1,166 @@ +PASS core packages/core/src/lib/agentic/__tests__/send.spec.ts +PASS core packages/core/src/lib/universal/account/account.spec.ts + ● Console + + console.warn + [PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead. + + 207 | ): Promise { + 208 | if (!_convertOriginToExecutorWarned) { + > 209 | console.warn( + | ^ + 210 | '[PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead.' + 211 | ); + 212 | _convertOriginToExecutorWarned = true; + + at Object.convertOriginToExecutor (src/lib/universal/account/account.ts:209:13) + at Object. (src/lib/universal/account/account.spec.ts:80:52) + + console.warn + [PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead. + + 425 | ): Promise { + 426 | if (!options?._internal && !_convertExecutorToOriginWarned) { + > 427 | console.warn( + | ^ + 428 | '[PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead.' + 429 | ); + 430 | _convertExecutorToOriginWarned = true; + + at convertExecutorToOrigin (src/lib/universal/account/account.ts:427:13) + at Object. (src/lib/universal/account/account.spec.ts:106:38) + +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/export.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/block-results-client.spec.ts +PASS core packages/core/src/lib/push-client/push-client.archive-fallback.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-tx-retry.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-confirmation-gate.spec.ts +PASS core packages/core/src/lib/universal/signer/signer.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/track-transaction-guard.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/payload-builders.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm-rent-pc20.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-timeout-clamp.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-gas.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/multichain-hooks.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/response-invariant.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-request-recipient.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/resolve.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/build-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r2-outbound-revert-flow.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-evm-r3-native-eoa.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/inbound-tracker-derivation.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-native-multicall.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/registry.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-tracker.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/chain-namespace.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-classification.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/management.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gateway-uea-account.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/source-hash-resolution.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r3-spec-strings.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/spec-builder.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-detector.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/rescue-svm-confirmation.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-emission.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-executor.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-usd-sizer.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/response-surface.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-composition.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/public-surface.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/scenarios.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-error-classification.spec.ts +PASS core packages/core/src/lib/utils.spec.ts + ● Console + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:973:17) + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:977:17) + + console.log + 1.23 + + at Object. (src/lib/utils.spec.ts:982:17) + +PASS core packages/core/src/lib/vm-client/evm-client.dynamic-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/funds-only-burn-guard.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-svm-r3.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/inbound-payload.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/read-tx-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/terminal-suppression.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-multichain.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/response-builder-push-revert.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/context-helpers-tracker.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/signing-payload.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r2-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-calculator.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/web2-compat.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/svm-rent.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/gate.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/account-status.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/resolver.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-event-hook-bridge.spec.ts +PASS core packages/core/src/lib/push-client/push-client.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r1-spec-strings.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/cascade.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/send-transaction-progress-hook.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-builder-progress-hook.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/execute-standard-required-funds.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-svm-rent.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-evm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/revalidate-read.spec.ts +PASS core packages/core/src/lib/constants/__tests__/token-constants.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm-log-index.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/svm-account.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/codec.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-svm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/result-decoder.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/address-codec.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-params.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/ucallback-codec.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/reads-context.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/child-inbounds.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/__tests__/signing.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/abi-selectors.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/auto-detect.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/normalize.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.chain-symbol.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/ix-encoder.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-web2.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg-svm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-events.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/validate.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-types.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/registry.spec.ts +PASS core packages/core/src/lib/constants/__tests__/svm-gateway-idl.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/error-decoder.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/max-pc-for-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/normalize-address.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/tracking.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/classify.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-execute-order.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/budget.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/errors.spec.ts +PASS core packages/core/src/lib/formatters.spec.ts + +Test Suites: 1 skipped, 113 passed, 113 of 114 total +Tests: 12 skipped, 1947 passed, 1959 total +Snapshots: 0 total +Time: 35.789 s, estimated 42 s +Ran all test suites. diff --git a/plan/agw/research/live-acceptance-2026-10-06/logs/agw-gas-local.log b/plan/agw/research/live-acceptance-2026-10-06/logs/agw-gas-local.log new file mode 100644 index 00000000..0c45b0e1 --- /dev/null +++ b/plan/agw/research/live-acceptance-2026-10-06/logs/agw-gas-local.log @@ -0,0 +1,16 @@ +PASS core-agw-local packages/core/__agw-local__/svm-internals.spec.ts (15.775 s) +PASS core-agw-local packages/core/__agw-local__/v4-multiasset.spec.ts +PASS core-agw-local packages/core/__agw-local__/agw-local-advanced.spec.ts +PASS core-agw-local packages/core/__agw-local__/agw-local.spec.ts +PASS core-agw-local packages/core/__agw-local__/agw-local-races.spec.ts +PASS core-agw-local packages/core/__agw-local__/agw-local-batch.spec.ts +PASS core-agw-local packages/core/__agw-local__/vectors.spec.ts + +Test Suites: 7 passed, 7 total +Tests: 53 passed, 53 total +Snapshots: 0 total +Time: 28.564 s +Ran all test suites. +Jest did not exit one second after the test run has completed. + +'This usually means that there are asynchronous operations that weren't stopped in your tests. Consider running Jest with `--detectOpenHandles` to troubleshoot this issue. diff --git a/plan/agw/research/live-acceptance-2026-10-06/logs/agw-gas-unit.log b/plan/agw/research/live-acceptance-2026-10-06/logs/agw-gas-unit.log new file mode 100644 index 00000000..73b0b3eb --- /dev/null +++ b/plan/agw/research/live-acceptance-2026-10-06/logs/agw-gas-unit.log @@ -0,0 +1,8 @@ +PASS core packages/core/src/lib/agentic/__tests__/send.spec.ts (5.439 s) +PASS core packages/core/src/lib/vm-client/evm-client.dynamic-gas.spec.ts + +Test Suites: 2 passed, 2 total +Tests: 36 passed, 36 total +Snapshots: 0 total +Time: 5.713 s +Ran all test suites within paths "packages/core/src/lib/vm-client/evm-client.dynamic-gas.spec.ts", "packages/core/src/lib/vm-client/evm-client.spec.ts", "packages/core/src/lib/agentic/__tests__/send.spec.ts". diff --git a/plan/agw/research/live-acceptance-2026-10-06/logs/agw-live-callonly.log b/plan/agw/research/live-acceptance-2026-10-06/logs/agw-live-callonly.log new file mode 100644 index 00000000..83649c1a --- /dev/null +++ b/plan/agw/research/live-acceptance-2026-10-06/logs/agw-live-callonly.log @@ -0,0 +1,26 @@ + console.log + [ExternalTxVerifier] Verifying EVM tx on eip155:11155111: 0xadb89cd9cfb70fd33b9eaa2e05b109b0a9a26d3fb9221e8dc28cd8cf8d4f27fe + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [ExternalTxVerifier] EVM tx 0xadb89cd9cfb70fd33b9eaa2e05b109b0a9a26d3fb9221e8dc28cd8cf8d4f27fe on eip155:11155111: status=0x1 + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [ExternalTxVerifier] EVM tx CONFIRMED SUCCESS on eip155:11155111 + + at console.log (__e2e__/shared/logger.ts:42:5) + +PASS core-e2e packages/core/__e2e__/agw/v4-multiasset.spec.ts (102.469 s) + agw v4 multi-asset + ✓ 2. empty user assets routes a call-only outbound with zero token spend (89508 ms) + ○ skipped 1. public create reads and replaces an ordered two-token rule + +Test Suites: 1 passed, 1 total +Tests: 1 skipped, 1 passed, 2 total +Snapshots: 0 total +Time: 102.497 s +Ran all test suites within paths "packages/core/__e2e__/agw/v4-multiasset.spec.ts". +Force exiting Jest: Have you considered using `--detectOpenHandles` to detect async operations that kept running after all tests finished? diff --git a/plan/agw/research/live-acceptance-2026-10-06/logs/agw-live-final-cases.log b/plan/agw/research/live-acceptance-2026-10-06/logs/agw-live-final-cases.log new file mode 100644 index 00000000..8ed7e563 --- /dev/null +++ b/plan/agw/research/live-acceptance-2026-10-06/logs/agw-live-final-cases.log @@ -0,0 +1,182 @@ +PASS core-e2e packages/core/__e2e__/agw/lifecycle.spec.ts (93.065 s) +PASS core-e2e packages/core/__e2e__/agw/identity-gas.spec.ts (159.091 s) + ● Console + + console.log + [4.80s] AGENTIC-TX-107: Rule Resolved + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [4.81s] SEND-TX-101: Origin Chain Detected + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [4.82s] SEND-TX-102-01: Estimating Gas + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [5.17s] SEND-TX-103-01: Resolving Universal Execution Account + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [5.49s] SEND-TX-103-02: Universal Execution Account Resolved + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [5.49s] SEND-TX-103-03-04: Prepaid Deposit Estimated + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [7.80s] SEND-TX-104-01: Awaiting Transaction + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [9.70s] SEND-TX-105-01: Gas Funding In Progress + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [26.48s] SEND-TX-105-02: Gas Funding Confirmed + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [26.48s] SEND-TX-107: Broadcasting to Push Chain + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [39.43s] SEND-TX-199-01: Push Chain Tx Success + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [39.43s] AGENTIC-TX-199-01: Agentic Operation Done + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [41.82s] AGENTIC-TX-107: Rule Resolved + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [1.38s] AGENTIC-TX-107: Rule Resolved + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [41.82s] SEND-TX-101: Origin Chain Detected + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [1.38s] SEND-TX-101: Origin Chain Detected + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [41.82s] SEND-TX-102-01: Estimating Gas + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [1.38s] SEND-TX-102-01: Estimating Gas + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [42.15s] SEND-TX-103-01: Resolving Universal Execution Account + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [1.70s] SEND-TX-103-01: Resolving Universal Execution Account + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [42.80s] SEND-TX-103-02: Universal Execution Account Resolved + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [2.35s] SEND-TX-103-02: Universal Execution Account Resolved + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [42.80s] SEND-TX-103-03-04: Prepaid Deposit Estimated + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [2.35s] SEND-TX-103-03-04: Prepaid Deposit Estimated + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [43.43s] SEND-TX-104-02: Awaiting Signature + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [2.99s] SEND-TX-104-02: Awaiting Signature + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [43.43s] SEND-TX-104-03: Verification Success + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [2.99s] SEND-TX-104-03: Verification Success + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [43.43s] SEND-TX-107: Broadcasting to Push Chain + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [2.99s] SEND-TX-107: Broadcasting to Push Chain + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [51.01s] SEND-TX-199-01: Push Chain Tx Success + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [10.57s] SEND-TX-199-01: Push Chain Tx Success + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [51.01s] AGENTIC-TX-199-01: Agentic Operation Done + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [10.57s] AGENTIC-TX-199-01: Agentic Operation Done + + at console.log (__e2e__/shared/logger.ts:42:5) + +PASS core-e2e packages/core/__e2e__/agw/native-exec.spec.ts (113.845 s) + +Test Suites: 3 passed, 3 total +Tests: 4 skipped, 9 passed, 13 total +Snapshots: 0 total +Time: 366.042 s +Ran all test suites within paths "packages/core/__e2e__/agw/lifecycle.spec.ts", "packages/core/__e2e__/agw/native-exec.spec.ts", "packages/core/__e2e__/agw/identity-gas.spec.ts". +Force exiting Jest: Have you considered using `--detectOpenHandles` to detect async operations that kept running after all tests finished? diff --git a/plan/agw/research/live-acceptance-2026-10-06/logs/agw-live-management.log b/plan/agw/research/live-acceptance-2026-10-06/logs/agw-live-management.log new file mode 100644 index 00000000..ff988910 --- /dev/null +++ b/plan/agw/research/live-acceptance-2026-10-06/logs/agw-live-management.log @@ -0,0 +1,75 @@ +PASS core-e2e packages/core/__e2e__/agw/create.spec.ts (28.902 s) +FAIL core-e2e packages/core/__e2e__/agw/v4-multiasset.spec.ts (12.983 s) + ● agw v4 multi-asset › 1. public create reads and replaces an ordered two-token rule + + AgenticError: SOURCE_TOKEN_ADDRESS read on 0x2971824Db68229D087931155C2b8bB820B275809 failed at block 23934879 + + 43 | ): Promise { + 44 | try { + > 45 | return (await this.reader.readContract({ + | ^ + 46 | address, + 47 | abi, + 48 | functionName, + + at Snapshot.read (src/lib/agentic/reads/snapshot.ts:45:13) + at async prepareWalletRules (src/lib/agentic/management/prepare.ts:102:24) + at async createWallet (src/lib/agentic/management/create.ts:81:20) + at async Object. (__e2e__/agw/v4-multiasset.spec.ts:45:21) + + Cause: + ContractFunctionExecutionError: Position `32` is out of bounds (`0 < position < 32`). + + Contract Call: + address: 0x2971824Db68229D087931155C2b8bB820B275809 + function: SOURCE_TOKEN_ADDRESS() + + Docs: https://viem.sh/docs/contract/readContract + Version: viem@2.27.2 + + 35 | return new Snapshot(reader, block, failCode); + 36 | } + > 37 | + | ^ + 38 | async read( + 39 | address: Address, + 40 | abi: readonly unknown[], + + at getContractError (../../node_modules/viem/utils/errors/getContractError.ts:78:10) + at readContract (../../node_modules/viem/actions/public/readContract.ts:136:27) + at async Snapshot.read (src/lib/agentic/reads/snapshot.ts:37:15) + at async prepareWalletRules (src/lib/agentic/management/prepare.ts:102:24) + at async createWallet (src/lib/agentic/management/create.ts:81:20) + at async Object. (__e2e__/agw/v4-multiasset.spec.ts:45:21) + + Cause: + PositionOutOfBoundsError: Position `32` is out of bounds (`0 < position < 32`). + + Version: viem@2.27.2 + + 35 | return new Snapshot(reader, block, failCode); + 36 | } + > 37 | + | ^ + 38 | async read( + 39 | address: Address, + 40 | abi: readonly unknown[], + + at Object.assertPosition (../../node_modules/viem/utils/cursor.ts:79:13) + at Object.setPosition (../../node_modules/viem/utils/cursor.ts:210:10) + at decodeString (../../node_modules/viem/utils/abi/decodeAbiParameters.ts:357:12) + at decodeParameter (../../node_modules/viem/utils/abi/decodeAbiParameters.ts:113:39) + at decodeAbiParameters (../../node_modules/viem/utils/abi/decodeAbiParameters.ts:75:31) + at decodeFunctionResult (../../node_modules/viem/utils/abi/decodeFunctionResult.ts:161:37) + at readContract (../../node_modules/viem/actions/public/readContract.ts:129:32) + at async Snapshot.read (src/lib/agentic/reads/snapshot.ts:37:15) + at async prepareWalletRules (src/lib/agentic/management/prepare.ts:102:24) + at async createWallet (src/lib/agentic/management/create.ts:81:20) + at async Object. (__e2e__/agw/v4-multiasset.spec.ts:45:21) + +Test Suites: 1 failed, 1 passed, 2 total +Tests: 1 failed, 2 skipped, 1 passed, 4 total +Snapshots: 0 total +Time: 41.91 s +Ran all test suites within paths "packages/core/__e2e__/agw/create.spec.ts", "packages/core/__e2e__/agw/v4-multiasset.spec.ts". +Force exiting Jest: Have you considered using `--detectOpenHandles` to detect async operations that kept running after all tests finished? diff --git a/plan/agw/research/live-acceptance-2026-10-06/logs/agw-live-multiasset.log b/plan/agw/research/live-acceptance-2026-10-06/logs/agw-live-multiasset.log new file mode 100644 index 00000000..32c66cd5 --- /dev/null +++ b/plan/agw/research/live-acceptance-2026-10-06/logs/agw-live-multiasset.log @@ -0,0 +1,11 @@ +PASS core-e2e packages/core/__e2e__/agw/v4-multiasset.spec.ts (47.483 s) + agw v4 multi-asset + ✓ 1. public create reads and replaces an ordered two-token rule (31012 ms) + ○ skipped 2. empty user assets routes a call-only outbound with zero token spend + +Test Suites: 1 passed, 1 total +Tests: 1 skipped, 1 passed, 2 total +Snapshots: 0 total +Time: 47.514 s +Ran all test suites within paths "packages/core/__e2e__/agw/v4-multiasset.spec.ts". +Force exiting Jest: Have you considered using `--detectOpenHandles` to detect async operations that kept running after all tests finished? diff --git a/plan/agw/research/live-acceptance-2026-10-06/logs/agw-live-native-remaining.log b/plan/agw/research/live-acceptance-2026-10-06/logs/agw-live-native-remaining.log new file mode 100644 index 00000000..0dca300e --- /dev/null +++ b/plan/agw/research/live-acceptance-2026-10-06/logs/agw-live-native-remaining.log @@ -0,0 +1,34 @@ +FAIL core-e2e packages/core/__e2e__/agw/lifecycle.spec.ts (69.275 s) + ● agw lifecycle › 2. rules.update: old ID disabled, new ID usable with reset counters, five checkpoint ticks + + expect(received).toMatchObject(expected) + + - Expected - 1 + + Received + 0 + + Object { + "callsUsed": 1, + - "kind": "native", + "valueSpent": 10n, + } + + 73 | original + 74 | ); + > 75 | expect(spentBefore).toMatchObject({ + | ^ + 76 | kind: 'native', + 77 | valueSpent: BigInt(10), + 78 | callsUsed: 1, + + at Object. (__e2e__/agw/lifecycle.spec.ts:75:25) + +PASS core-e2e packages/core/__e2e__/agw/native-batch.spec.ts (85.028 s) +PASS core-e2e packages/core/__e2e__/agw/responses-hooks.spec.ts (68.355 s) +PASS core-e2e packages/core/__e2e__/agw/funding-allowance.spec.ts (49.494 s) + +Test Suites: 1 failed, 3 passed, 4 total +Tests: 1 failed, 9 passed, 10 total +Snapshots: 0 total +Time: 272.19 s +Ran all test suites within paths "packages/core/__e2e__/agw/native-batch.spec.ts", "packages/core/__e2e__/agw/lifecycle.spec.ts", "packages/core/__e2e__/agw/funding-allowance.spec.ts", "packages/core/__e2e__/agw/responses-hooks.spec.ts". +Force exiting Jest: Have you considered using `--detectOpenHandles` to detect async operations that kept running after all tests finished? diff --git a/plan/agw/research/live-acceptance-2026-10-06/logs/agw-live-native-smoke.log b/plan/agw/research/live-acceptance-2026-10-06/logs/agw-live-native-smoke.log new file mode 100644 index 00000000..a2e2dabf --- /dev/null +++ b/plan/agw/research/live-acceptance-2026-10-06/logs/agw-live-native-smoke.log @@ -0,0 +1,65 @@ +FAIL core-e2e packages/core/__e2e__/agw/create.spec.ts (39.418 s) + ● agw create › 1. bare wallet: factory records the owner and index, no rules, no implicit funding + + AgenticError: log scan for WalletDeployed failed for blocks 23923806-23934775 + + 82 | out.push(...(await reader.getLogs({ ...args, fromBlock: start, toBlock: end }))); + 83 | } catch (cause) { + > 84 | throw new AgenticError( + | ^ + 85 | AGENTIC_ERROR_CODE.RULE_READ_FAILED, + 86 | `log scan for ${args.event.name} failed for blocks ${start}-${end}`, + 87 | { cause } + + at scanLogs (src/lib/agentic/reads/snapshot.ts:84:13) + at async labelsFor (src/lib/agentic/reads/wallets.ts:78:16) + at async walletInfo (src/lib/agentic/reads/wallets.ts:183:18) + at async Object. (__e2e__/agw/create.spec.ts:49:18) + + Cause: + InvalidInputRpcError: Missing or invalid parameters. + Double check you have provided the correct parameters. + + URL: https://evm.donut.rpc.push.org/ + Request body: {"method":"eth_getLogs","params":[{"address":"0xaF88D0FD947afAe7bBb8F34e8417DCfc165e1aaF","topics":["0xc8b37f011e9b6e64684cc9a96d216bbbc580aa1834cdbb981be54e529671b04c",null,null,"0x00000000000000000000000017d7f35da183685229694efd82b5701fd8b240d2"],"fromBlock":"0x16d0c5e","toBlock":"0x16d3737"}]} + + Details: maximum [from, to] blocks distance: 1000 + Version: viem@2.27.2 + + at delay.count.count (../../node_modules/viem/utils/buildRequest.ts:173:25) + at async attemptRetry (../../node_modules/viem/utils/promise/withRetry.ts:44:22) + + Cause: + InvalidInputRpcError: Missing or invalid parameters. + Double check you have provided the correct parameters. + + URL: https://evm.donut.rpc.push.org/ + Request body: {"method":"eth_getLogs","params":[{"address":"0xaF88D0FD947afAe7bBb8F34e8417DCfc165e1aaF","topics":["0xc8b37f011e9b6e64684cc9a96d216bbbc580aa1834cdbb981be54e529671b04c",null,null,"0x00000000000000000000000017d7f35da183685229694efd82b5701fd8b240d2"],"fromBlock":"0x16d0c5e","toBlock":"0x16d3737"}]} + + Details: maximum [from, to] blocks distance: 1000 + Version: viem@2.27.2 + + at delay.count.count (../../node_modules/viem/utils/buildRequest.ts:173:25) + at async attemptRetry (../../node_modules/viem/utils/promise/withRetry.ts:44:22) + + Cause: + RpcRequestError: RPC Request failed. + + URL: https://evm.donut.rpc.push.org/ + Request body: {"method":"eth_getLogs","params":[{"address":"0xaF88D0FD947afAe7bBb8F34e8417DCfc165e1aaF","topics":["0xc8b37f011e9b6e64684cc9a96d216bbbc580aa1834cdbb981be54e529671b04c",null,null,"0x00000000000000000000000017d7f35da183685229694efd82b5701fd8b240d2"],"fromBlock":"0x16d0c5e","toBlock":"0x16d3737"}]} + + Details: maximum [from, to] blocks distance: 1000 + Version: viem@2.27.2 + + at request (../../node_modules/viem/clients/transports/http.ts:154:19) + at async delay.count.count (../../node_modules/viem/utils/buildRequest.ts:150:22) + at async attemptRetry (../../node_modules/viem/utils/promise/withRetry.ts:44:22) + +PASS core-e2e packages/core/__e2e__/agw/native-exec.spec.ts (54.496 s) + +Test Suites: 1 failed, 1 passed, 2 total +Tests: 1 failed, 2 skipped, 5 passed, 8 total +Snapshots: 0 total +Time: 93.95 s +Ran all test suites within paths "packages/core/__e2e__/agw/create.spec.ts", "packages/core/__e2e__/agw/native-exec.spec.ts". +Force exiting Jest: Have you considered using `--detectOpenHandles` to detect async operations that kept running after all tests finished? diff --git a/plan/agw/research/live-acceptance-2026-10-06/logs/agw-live-positive-buffered.log b/plan/agw/research/live-acceptance-2026-10-06/logs/agw-live-positive-buffered.log new file mode 100644 index 00000000..f3fb460a --- /dev/null +++ b/plan/agw/research/live-acceptance-2026-10-06/logs/agw-live-positive-buffered.log @@ -0,0 +1,26 @@ + console.log + [ExternalTxVerifier] Verifying EVM tx on eip155:11155111: 0x1dac9f08f651c30e0c2de11c42c8df8bbcbd12484575b536e4d42f40819989ea + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [ExternalTxVerifier] EVM tx 0x1dac9f08f651c30e0c2de11c42c8df8bbcbd12484575b536e4d42f40819989ea on eip155:11155111: status=0x1 + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [ExternalTxVerifier] EVM tx CONFIRMED SUCCESS on eip155:11155111 + + at console.log (__e2e__/shared/logger.ts:42:5) + +PASS core-e2e packages/core/__e2e__/agw/universal-evm.spec.ts (340.877 s) + agw universal evm + ✓ 1. positive-amount outbound: allowance pull/burn, the wallet CEA executes on Sepolia, receipts and replay identity (182705 ms) + ✓ 2. destination revert is classified on the receipt; the Push leg succeeded (104785 ms) + +Test Suites: 1 passed, 1 total +Tests: 2 passed, 2 total +Snapshots: 0 total +Time: 340.897 s +Ran all test suites within paths "packages/core/__e2e__/agw/universal-evm.spec.ts". +Force exiting Jest: Have you considered using `--detectOpenHandles` to detect async operations that kept running after all tests finished? diff --git a/plan/agw/research/live-acceptance-2026-10-06/logs/agw-live-positive.log b/plan/agw/research/live-acceptance-2026-10-06/logs/agw-live-positive.log new file mode 100644 index 00000000..8b1b596f --- /dev/null +++ b/plan/agw/research/live-acceptance-2026-10-06/logs/agw-live-positive.log @@ -0,0 +1,45 @@ +FAIL core-e2e packages/core/__e2e__/agw/universal-evm.spec.ts (59.44 s) + agw universal evm + ✕ 1. positive-amount outbound: allowance pull/burn, the wallet CEA executes on Sepolia, receipts and replay identity (9436 ms) + ○ skipped 2. destination revert is classified on the receipt; the Push leg succeeded + + ● agw universal evm › 1. positive-amount outbound: allowance pull/burn, the wallet CEA executes on Sepolia, receipts and replay identity + + AgenticRevertError: sendPushTx — Push Chain transaction 0x33b8ed9690023e9c8450ce2219f197e98da0412a49a267672ef7ddbe3fe48c27 reverted + + 135 | if (decoded || err instanceof PushChainExecutionError) { + 136 | const e = err as { message?: string; gatewayTxHash?: string; decodedError?: DecodedErrorPayload }; + > 137 | return new AgenticRevertError(e?.message ?? decoded?.name ?? 'AGW revert', { + | ^ + 138 | decodedError: decoded ?? e?.decodedError, + 139 | gatewayTxHash: e?.gatewayTxHash, + 140 | agenticCode: decoded?.name, + + at wrapSendError (src/lib/agentic/management/common.ts:137:12) + at agenticSend (src/lib/agentic/execution/send.ts:359:34) + at async Object. (__e2e__/agw/universal-evm.spec.ts:137:16) + + Cause: + PushChainExecutionError: sendPushTx — Push Chain transaction 0x33b8ed9690023e9c8450ce2219f197e98da0412a49a267672ef7ddbe3fe48c27 reverted + + 76 | receiptWaited = true; + 77 | if (receipt.status === 'reverted') { + > 78 | throw new PushChainExecutionError( + | ^ + 79 | `${label} — Push Chain transaction ${txHash} reverted` + 80 | ); + 81 | } + + at getIndexedPushTransaction (src/lib/orchestrator/internals/push-chain-tx.ts:78:17) + at async sendPushTx (src/lib/orchestrator/internals/push-chain-tx.ts:316:22) + at async executeStandardPayload (src/lib/orchestrator/internals/execute-standard.ts:173:12) + at async Orchestrator.executeWithPolicy (src/lib/orchestrator/orchestrator.ts:471:11) + at async agenticSend (src/lib/agentic/execution/send.ts:349:9) + at async Object. (__e2e__/agw/universal-evm.spec.ts:137:16) + +Test Suites: 1 failed, 1 total +Tests: 1 failed, 1 skipped, 2 total +Snapshots: 0 total +Time: 59.469 s +Ran all test suites within paths "packages/core/__e2e__/agw/universal-evm.spec.ts". +Force exiting Jest: Have you considered using `--detectOpenHandles` to detect async operations that kept running after all tests finished? diff --git a/plan/agw/research/live-acceptance-2026-10-06/logs/agw-permissions-unit-final.log b/plan/agw/research/live-acceptance-2026-10-06/logs/agw-permissions-unit-final.log new file mode 100644 index 00000000..3df9a6b8 --- /dev/null +++ b/plan/agw/research/live-acceptance-2026-10-06/logs/agw-permissions-unit-final.log @@ -0,0 +1,166 @@ +PASS core packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts +PASS core packages/core/src/lib/universal/account/account.spec.ts + ● Console + + console.warn + [PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead. + + 207 | ): Promise { + 208 | if (!_convertOriginToExecutorWarned) { + > 209 | console.warn( + | ^ + 210 | '[PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead.' + 211 | ); + 212 | _convertOriginToExecutorWarned = true; + + at Object.convertOriginToExecutor (src/lib/universal/account/account.ts:209:13) + at Object. (src/lib/universal/account/account.spec.ts:80:52) + + console.warn + [PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead. + + 425 | ): Promise { + 426 | if (!options?._internal && !_convertExecutorToOriginWarned) { + > 427 | console.warn( + | ^ + 428 | '[PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead.' + 429 | ); + 430 | _convertExecutorToOriginWarned = true; + + at convertExecutorToOrigin (src/lib/universal/account/account.ts:427:13) + at Object. (src/lib/universal/account/account.spec.ts:106:38) + +PASS core packages/core/src/lib/read-state/__tests__/block-results-client.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-tx-retry.spec.ts +PASS core packages/core/src/lib/push-client/push-client.archive-fallback.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-confirmation-gate.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/send.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/management.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-timeout-clamp.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/inbound-tracker-derivation.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r2-outbound-revert-flow.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/source-hash-resolution.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-executor.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-multichain.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/multichain-hooks.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/reads-context.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/response-surface.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/rescue-svm-confirmation.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-emission.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-usd-sizer.spec.ts +PASS core packages/core/src/lib/universal/signer/signer.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/response-invariant.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-native-multicall.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/build-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm-rent-pc20.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/execute-standard-required-funds.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r1-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-composition.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-error-classification.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-tracker.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/chain-namespace.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r2-spec-strings.spec.ts +PASS core packages/core/src/lib/utils.spec.ts + ● Console + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:973:17) + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:977:17) + + console.log + 1.23 + + at Object. (src/lib/utils.spec.ts:982:17) + +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/send-transaction-progress-hook.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-builder-progress-hook.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/svm-rent.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gateway-uea-account.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/signing-payload.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/scenarios.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-params.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/web2-compat.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/resolve.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/context-helpers-tracker.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-event-hook-bridge.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/read-tx-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/payload-builders.spec.ts +PASS core packages/core/src/lib/push-client/push-client.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-detector.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-calculator.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-request-recipient.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-svm-rent.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/cascade.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-svm-r3.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/gate.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/account-status.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/resolver.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/registry.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/response-builder-push-revert.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/export.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/track-transaction-guard.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/funds-only-burn-guard.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r3-spec-strings.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/public-surface.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-evm-r3-native-eoa.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/inbound-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/terminal-suppression.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/ucallback-codec.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/svm-account.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/address-codec.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/codec.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-evm.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/spec-builder.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/result-decoder.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/revalidate-read.spec.ts +PASS core packages/core/src/lib/constants/__tests__/token-constants.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-svm.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm-log-index.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/__tests__/signing.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.chain-symbol.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/normalize.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/abi-selectors.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/child-inbounds.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/auto-detect.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/validate.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg-svm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-events.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-web2.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/ix-encoder.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.dynamic-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/registry.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-types.spec.ts +PASS core packages/core/src/lib/constants/__tests__/svm-gateway-idl.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/error-decoder.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/budget.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/tracking.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/classify.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/normalize-address.spec.ts +PASS core packages/core/src/lib/formatters.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-execute-order.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/max-pc-for-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/errors.spec.ts + +Test Suites: 1 skipped, 113 passed, 113 of 114 total +Tests: 12 skipped, 1945 passed, 1957 total +Snapshots: 0 total +Time: 50.322 s +Ran all test suites. diff --git a/plan/agw/research/live-acceptance-2026-10-06/origin-preflight.json b/plan/agw/research/live-acceptance-2026-10-06/origin-preflight.json new file mode 100644 index 00000000..cc8ed342 --- /dev/null +++ b/plan/agw/research/live-acceptance-2026-10-06/origin-preflight.json @@ -0,0 +1,9 @@ +{ + "checkedAt": "2026-10-05T21:57:16.868Z", + "sepoliaMasterBalanceETH": "3.840195032605851535", + "sepoliaFirstUseReserveETH": "0.004", + "sufficientForFirstUse": true, + "solanaMasterBalanceLamports": 615330949, + "solanaSlot": 507874335, + "transactionsSubmitted": false +} diff --git a/plan/agw/research/live-acceptance-2026-10-06/outbound-preflight.json b/plan/agw/research/live-acceptance-2026-10-06/outbound-preflight.json new file mode 100644 index 00000000..6f34ad08 --- /dev/null +++ b/plan/agw/research/live-acceptance-2026-10-06/outbound-preflight.json @@ -0,0 +1,7 @@ +{ + "ownerPC": "970102.514236583381997743", + "ownerPETH": "434.311538549551169292", + "positiveOutboundReservePC": "25", + "positiveOutboundTokenAmount": "0.000003", + "sufficient": true +} diff --git a/plan/agw/research/live-acceptance-2026-10-06/positive-destination-execution.json b/plan/agw/research/live-acceptance-2026-10-06/positive-destination-execution.json new file mode 100644 index 00000000..fb32db79 --- /dev/null +++ b/plan/agw/research/live-acceptance-2026-10-06/positive-destination-execution.json @@ -0,0 +1,20 @@ +{ + "chainId": 11155111, + "transactionHash": "0x1dac9f08f651c30e0c2de11c42c8df8bbcbd12484575b536e4d42f40819989ea", + "block": "11851537", + "status": "success", + "attributionAssertionsPass": true, + "executionEvents": [ + { + "emitter": "0x485e0af54d8944ebdf9a3ec9641d8ab838b7c590", + "eventName": "UniversalTxExecuted", + "args": { + "subTxId": "0x2e0cddd56aa8ceb6dcf89342a187207be138efc13d255ae296b00ff8747261de", + "universalTxId": "0x468b004e8920b299f06158f6fba82be8e8ac327abd107854ec7c8bee175ddc16", + "originCaller": "0x1C015E6B101ad2965D9912437c2499262Ef8F502", + "target": "0xF1552eD5ac48C273570500bD10b10C00E1C418bB", + "data": "0xd09de08a" + } + } + ] +} diff --git a/plan/agw/research/live-acceptance-2026-10-06/positive-push-events.json b/plan/agw/research/live-acceptance-2026-10-06/positive-push-events.json new file mode 100644 index 00000000..0b65fa63 --- /dev/null +++ b/plan/agw/research/live-acceptance-2026-10-06/positive-push-events.json @@ -0,0 +1,50 @@ +{ + "chainId": 42101, + "transactionHash": "0x3236bbc8f2029f53a2aa09d0c0d3cd291568bbaccf4de70061ecd085d4adcb3e", + "block": "23935801", + "status": "success", + "gasLimit": "584699", + "gasUsed": "398931", + "transfers": [ + { + "token": "0x2971824db68229d087931155c2b8bb820b275809", + "args": { + "from": "0x1C015E6B101ad2965D9912437c2499262Ef8F502", + "to": "0x00000000000000000000000000000000000000C1", + "value": "1000000000000" + } + }, + { + "token": "0x2971824db68229d087931155c2b8bb820b275809", + "args": { + "from": "0x00000000000000000000000000000000000000C1", + "to": "0x0000000000000000000000000000000000000000", + "value": "1000000000000" + } + }, + { + "token": "0x2971824db68229d087931155c2b8bb820b275809", + "args": { + "from": "0x012d5C099f8AE00009f40824317a18c3A342f622", + "to": "0x00000000000000000000000000000000000000C0", + "value": "622648148500000" + } + }, + { + "token": "0xe17dd2e0509f99e9ee9469cf6634048ec5a3ade9", + "args": { + "from": "0x00000000000000000000000000000000000000C0", + "to": "0x012d5C099f8AE00009f40824317a18c3A342f622", + "value": "1050217272734187113" + } + }, + { + "token": "0x2971824db68229d087931155c2b8bb820b275809", + "args": { + "from": "0x00000000000000000000000000000000000000C0", + "to": "0x0000000000000000000000000000000000000000", + "value": "622648148500000" + } + } + ] +} diff --git a/plan/agw/research/live-acceptance-2026-10-06/positive-revert-probe.json b/plan/agw/research/live-acceptance-2026-10-06/positive-revert-probe.json new file mode 100644 index 00000000..6a6768af --- /dev/null +++ b/plan/agw/research/live-acceptance-2026-10-06/positive-revert-probe.json @@ -0,0 +1,132 @@ +{ + "receipt": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "blockHash": "0xea6d93a1d7f273f80f82b53cc2d74bb29cde9113e158c000536ac6d2866d5ee6", + "blockNumber": "0x16d39a1", + "contractAddress": null, + "cumulativeGasUsed": "0x71d28", + "effectiveGasPrice": "0x430e2340", + "from": "0x582b101ad4db4890f38486047ab5dd3e65b1eb24", + "gasUsed": "0x71d28", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "status": "0x0", + "to": "0x2c7659030ea646b46d9f7e15c6dca7e64aceef56", + "transactionHash": "0x33b8ed9690023e9c8450ce2219f197e98da0412a49a267672ef7ddbe3fe48c27", + "transactionIndex": "0x0", + "type": "0x2" + } + }, + "transaction": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "blockHash": "0xea6d93a1d7f273f80f82b53cc2d74bb29cde9113e158c000536ac6d2866d5ee6", + "blockNumber": "0x16d39a1", + "from": "0x582b101ad4db4890f38486047ab5dd3e65b1eb24", + "gas": "0x75f60", + "gasPrice": "0x430e2340", + "maxFeePerGas": "0x4ef9e540", + "maxPriorityFeePerGas": "0x7735940", + "hash": "0x33b8ed9690023e9c8450ce2219f197e98da0412a49a267672ef7ddbe3fe48c27", + "input": "0xc0ca77910c69104ab07365f615452dc733dbdf400ffdf6f90129f72d0b7a52e537d8f0c30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002b800000000000000000000000000000000000000c1000000000000000000000000000000000000000000000000e6b73cb59223280077b86bec000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001000000000000000000000000002971824db68229d087931155c2b8bb820b275809000000000000000000000000000000000000000000000000000000e8d4a51000000000000000000000000000000000000000000000000000000000000007a1200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e6b73cb59223280000000000000000000000000000000000000000000000000000000000000001200000000000000000000000002c7659030ea646b46d9f7e15c6dca7e64aceef56000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001042cc2842d000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000f1552ed5ac48c273570500bd10b10c00e1c418bb000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000004d09de08a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "nonce": "0x0", + "to": "0x2c7659030ea646b46d9f7e15c6dca7e64aceef56", + "transactionIndex": "0x0", + "value": "0x0", + "type": "0x2", + "accessList": [], + "chainId": "0xa475", + "v": "0x0", + "r": "0x237124e9d372930758f5b44d5897a505efc655a4b45f6c63fe4d10bdf4d6626f", + "s": "0x9170ee2602fe6c90815f31e8b2068717dd410c0169d921c6f7e9fc57625f2a8", + "yParity": "0x0" + } + }, + "trace": { + "jsonrpc": "2.0", + "id": 1, + "error": { + "code": -32601, + "message": "the method debug_traceTransaction does not exist/is not available" + } + }, + "replays": [ + { + "block": "0x16d39a0", + "response": { + "jsonrpc": "2.0", + "id": 1, + "error": { + "code": -32000, + "message": "execution reverted" + } + } + }, + { + "block": "0x16d39a1", + "response": { + "jsonrpc": "2.0", + "id": 1, + "error": { + "code": -32000, + "message": "execution reverted" + } + } + } + ], + "isolation": { + "block": "23935392", + "wallet": "0x2c7659030ea646b46d9f7e15c6dca7e64aceef56", + "amount": "1000000000000", + "gateway": "0x00000000000000000000000000000000000000C1", + "token": "0x2971824Db68229D087931155C2b8bB820B275809", + "probes": [ + { + "name": "wallet-high-gas", + "status": "success" + }, + { + "name": "gateway-direct", + "status": "success" + }, + { + "name": "token-pull", + "status": "success", + "data": "0x0000000000000000000000000000000000000000000000000000000000000001" + } + ] + }, + "gas_ladder": [ + { + "gas": 483168, + "success": false, + "error": { + "code": -32000, + "message": "execution reverted" + } + }, + { + "gas": 500000, + "success": true, + "error": null + }, + { + "gas": 600000, + "success": true, + "error": null + }, + { + "gas": 800000, + "success": true, + "error": null + }, + { + "gas": 1000000, + "success": true, + "error": null + } + ] +} diff --git a/plan/agw/research/live-acceptance-2026-10-06/preflight.json b/plan/agw/research/live-acceptance-2026-10-06/preflight.json new file mode 100644 index 00000000..4df7fa72 --- /dev/null +++ b/plan/agw/research/live-acceptance-2026-10-06/preflight.json @@ -0,0 +1,15 @@ +{ + "checkedAt": "2026-10-05T21:04:12.624Z", + "chainId": 42101, + "block": "23934720", + "wiringVerified": true, + "ownerBalancePC": "970126.529158449381997743", + "nativeSmokeBudgetPC": "6", + "sufficientForNativeSmoke": true, + "keysPresent": { + "push": true, + "evm": true, + "solana": true + }, + "transactionsSubmitted": false +} diff --git a/plan/agw/research/live-acceptance-2026-10-06/preflight.ts b/plan/agw/research/live-acceptance-2026-10-06/preflight.ts new file mode 100644 index 00000000..2dc09ea5 --- /dev/null +++ b/plan/agw/research/live-acceptance-2026-10-06/preflight.ts @@ -0,0 +1,30 @@ +/** Read-only. Key material stays in memory; never printed, copied or logged. */ +import { readFileSync, writeFileSync } from 'node:fs'; +import { join, resolve } from 'node:path'; +import dotenv from 'dotenv'; +import { createPublicClient, http, formatEther, parseEther } from 'viem'; +import { privateKeyToAccount } from 'viem/accounts'; +import { getPushViemChain } from '../../../../packages/core/src/lib/constants/chain'; +import { CHAIN } from '../../../../packages/core/src/lib/constants/enums'; +import { loadAgwManifest, verifyAgwManifest } from '../../../../packages/core/__e2e__/agw/_manifest'; + +async function main() { + const env = dotenv.parse(readFileSync(resolve(__dirname, '../../../../packages/core/.env'))); + const raw = env.PUSH_PRIVATE_KEY; + if (!raw || !/^0x[0-9a-fA-F]{64}$/.test(raw)) throw new Error('Configured PUSH_PRIVATE_KEY is missing or invalid'); + let account; + try { account = privateKeyToAccount(raw as `0x${string}`); } + catch { throw new Error('Configured PUSH_PRIVATE_KEY cannot be used'); } + const chain = getPushViemChain(CHAIN.PUSH_TESTNET_DONUT)!; + const client = createPublicClient({ chain, transport: http('https://evm.donut.rpc.push.org/') }); + if (await client.getChainId() !== 42101) throw new Error('Unexpected chain; no funding permitted'); + await verifyAgwManifest(client, loadAgwManifest()); + const [balance, block] = await Promise.all([client.getBalance({ address: account.address }), client.getBlockNumber()]); + const result = { checkedAt: new Date().toISOString(), chainId: 42101, block: block.toString(), wiringVerified: true, + ownerBalancePC: formatEther(balance), nativeSmokeBudgetPC: '6', sufficientForNativeSmoke: balance >= parseEther('6'), + keysPresent: { push: true, evm: !!env.EVM_PRIVATE_KEY, solana: !!env.SOLANA_PRIVATE_KEY }, transactionsSubmitted: false }; + writeFileSync(join(__dirname, 'preflight.json'), JSON.stringify(result, null, 2) + '\n'); + process.stdout.write(JSON.stringify(result, null, 2) + '\n'); + if (!result.sufficientForNativeSmoke) throw new Error('Owner balance is below the native smoke reserve; no funding performed'); +} +main().catch(() => { process.stderr.write('Read-only preflight did not complete; no funding was performed.\n'); process.exitCode = 1; }); diff --git a/plan/agw/research/live-acceptance-2026-10-06/scenario-results.json b/plan/agw/research/live-acceptance-2026-10-06/scenario-results.json new file mode 100644 index 00000000..7eb87d4e --- /dev/null +++ b/plan/agw/research/live-acceptance-2026-10-06/scenario-results.json @@ -0,0 +1,183 @@ +{ + "chainId": 42101, + "sourceCommit": "e8db74815cfbbf5389593805e464fe8d85f7f735", + "scenariosPassed": 25, + "method": "Distinct registered scenarios passed across sequential selected runs; not a claim of one complete group invocation. Initial failures were corrected and retested; selection skips are not passes.", + "results": [ + { + "id": "agw-create-bare", + "status": "passed", + "evidenceLogs": [ + "logs/agw-live-management.log" + ] + }, + { + "id": "agw-create-rules", + "status": "passed", + "evidenceLogs": [ + "logs/agw-live-native-smoke.log" + ] + }, + { + "id": "agw-funding-pc", + "status": "passed", + "evidenceLogs": [ + "logs/agw-live-native-remaining.log" + ] + }, + { + "id": "agw-funding-allowance", + "status": "passed", + "evidenceLogs": [ + "logs/agw-live-native-remaining.log" + ] + }, + { + "id": "agw-native-batch", + "status": "passed", + "evidenceLogs": [ + "logs/agw-live-native-remaining.log" + ] + }, + { + "id": "agw-native-batch-rollback", + "status": "passed", + "evidenceLogs": [ + "logs/agw-live-native-remaining.log" + ] + }, + { + "id": "agw-native-agent", + "status": "passed", + "evidenceLogs": [ + "logs/agw-live-native-smoke.log" + ] + }, + { + "id": "agw-native-owner", + "status": "passed", + "evidenceLogs": [ + "logs/agw-live-native-smoke.log" + ] + }, + { + "id": "agw-native-over-cap", + "status": "passed", + "evidenceLogs": [ + "logs/agw-live-native-smoke.log" + ] + }, + { + "id": "agw-native-stranger", + "status": "passed", + "evidenceLogs": [ + "logs/agw-live-native-smoke.log" + ] + }, + { + "id": "agw-native-revoked", + "status": "passed", + "evidenceLogs": [ + "logs/agw-live-final-cases.log" + ] + }, + { + "id": "agw-native-expired", + "status": "passed", + "evidenceLogs": [ + "logs/agw-live-final-cases.log" + ] + }, + { + "id": "agw-lifecycle-add", + "status": "passed", + "evidenceLogs": [ + "logs/agw-live-final-cases.log" + ] + }, + { + "id": "agw-lifecycle-update", + "status": "passed", + "evidenceLogs": [ + "logs/agw-live-final-cases.log" + ] + }, + { + "id": "agw-lifecycle-checkpoints", + "status": "passed", + "evidenceLogs": [ + "logs/agw-live-final-cases.log" + ] + }, + { + "id": "agw-lifecycle-revoke-all", + "status": "passed", + "evidenceLogs": [ + "logs/agw-live-final-cases.log" + ] + }, + { + "id": "agw-universal-outbound", + "status": "passed", + "evidenceLogs": [ + "logs/agw-live-positive-buffered.log" + ] + }, + { + "id": "agw-v4-multi-asset", + "status": "passed", + "evidenceLogs": [ + "logs/agw-live-multiasset.log" + ] + }, + { + "id": "agw-v4-call-only", + "status": "passed", + "evidenceLogs": [ + "logs/agw-live-callonly.log" + ] + }, + { + "id": "agw-universal-dest-revert", + "status": "passed", + "evidenceLogs": [ + "logs/agw-live-positive-buffered.log" + ] + }, + { + "id": "agw-identity-evm", + "status": "passed", + "evidenceLogs": [ + "logs/agw-live-final-cases.log" + ] + }, + { + "id": "agw-identity-first-use", + "status": "passed", + "evidenceLogs": [ + "logs/agw-live-final-cases.log" + ] + }, + { + "id": "agw-identity-solana", + "status": "passed", + "evidenceLogs": [ + "logs/agw-live-final-cases.log" + ] + }, + { + "id": "agw-responses-hooks", + "status": "passed", + "evidenceLogs": [ + "logs/agw-live-native-remaining.log" + ] + }, + { + "id": "agw-responses-replay", + "status": "passed", + "evidenceLogs": [ + "logs/agw-live-native-remaining.log" + ] + } + ] +} diff --git a/plan/agw/research/notion-comments-2026-10-05.md b/plan/agw/research/notion-comments-2026-10-05.md new file mode 100644 index 00000000..1563bfc3 --- /dev/null +++ b/plan/agw/research/notion-comments-2026-10-05.md @@ -0,0 +1,63 @@ +# Live Notion comment review — October 5, 2026 + +Checked through Shoaib’s connected Chrome browser on October 5, 2026, starting around 08:03 UTC (13:33 IST); a local clock check during the review recorded 08:09:35 UTC. This is a focused comment review, not a new twelve-page Markdown export or contract/deployment refresh. Native Notion exports exclude discussions. Saved canonical snapshots and the full-export manifest remain unchanged. + +## Pages checked + +| Page | Method and observation | +| --- | --- | +| [5. SDK: AGW](https://app.notion.com/p/pushprotocol/5-SDK-AGW-3e9188aea7f481cf8e8de324956549b9) | Opened **All discussions**, including threads displaying Reopen (resolved). One thread was marked New/Today. Read the attached create example, validation paragraph and rule type block. | +| [1. AGW Contract Changes](https://app.notion.com/p/pushprotocol/1-AGW-Contract-Changes-nomenclature-standard-change-set-3e9188aea7f4813aa31fc95ceb4e684d) | Opened All discussions. Visible comments dated September 29 and October 1; no newer substantive reply was visible. | +| [AGW overview](https://app.notion.com/p/pushprotocol/AGW-UniversalMarketplace-8183-UniversalEvaluator-3e9188aea7f481c8b38ccba332b0afa2) | Page displayed Edited Oct 1 and Add comment; no page-body discussion was visible. No claim about hidden/resolved overview discussions. | + +The other nine registered pages were not checked in this pass. Relative comment ages below are UI observations, not independently verified creation timestamps. No comments were posted, resolved or edited. + +## SDK comments and their meaning + +### C1 — Multiple rules per chain (new) + +**Author:** Harsh Rajat. **UI:** Today, New, initially 9m and later 13m/14m. + +**Exact comment:** “multiple rules per chain is also acepted @Shoaib Mohammed” + +**Context:** [create example block](https://app.notion.com/p/pushprotocol/5-SDK-AGW-3e9188aea7f481cf8e8de324956549b9#f9712c13f75c4398aef2dbf7628450b2). The example still contains `// one entry per chain per agent`, and its parameter notes still say `one per chain per agent`. The [validation paragraph](https://app.notion.com/p/pushprotocol/5-SDK-AGW-3e9188aea7f481cf8e8de324956549b9#af9c3fac35d94f2585cb27310271c1d8) still rejects two rules sharing agent and chain. + +**Confirmed:** multiple rules on a chain are accepted product direction. **Unresolved:** whether this includes multiple rules for the *same agent*, and how an agent send chooses a rulesId when several candidates exist. Different agents sharing one chain were already allowed. The attached wording makes relaxing same-agent uniqueness plausible, but the comment alone does not specify selection behavior. + +**SDK impact:** [codec/rules.ts](../../../packages/core/src/lib/agentic/codec/rules.ts) rejects duplicate agent/chain pairs in create/add/update, while [reads/rules.ts](../../../packages/core/src/lib/agentic/reads/rules.ts) rejects more than one matching enabled rule at send time. Existing tests assert that behavior. These are provisional pending [H6](../questions-harsh.md#h6), not settled product invariants. Do not remove the guard and silently pick the first grant or try several transactions. + +### C2 — Tokens independent from the rule (needs interpretation) + +**Author:** Harsh Rajat. **UI:** Last Saturday, 1d. Both comments are attached to the validation paragraph linked above. + +**Exact comments:** “iterative SDK only, step”; “we usually want the tokens to be independent and not attached to this”. + +**Unresolved:** “this” and the intended token model are not defined. It may concern token resolution/validation, the attachment of assets to a rule, or staged SDK delivery. The current UniversalRule still contains assets[]. Treat this as a clarification within H3/Z1.1, not authorization to remove asset policy enforcement or invent a new schema. + +### C3 — Earlier resolved universal-limit discussion + +The thread displays **Original content deleted** and **Reopen**. Harsh’s visible messages, October 1–2, discuss whether constraints belong per allowed call, defining token/native treatment, removing redundant maxPCPerCall and keeping maxGasPerCall/AllowedAmount. No visible Zaryab answer accompanies them. + +These provide background for the existing multi-asset/gas-cap proposal. Their deleted source context and abbreviated wording do not settle the current native omission/default table or the precise final universal ABI. Keep H3 and Z1 open. + +### C4 — Update counters + +An October 1 comment tagging Zaryab is attached to `rules.update resets spend counters because it is revoke plus grant`. No substantive reply was visible. It does not change the implemented atomic replacement or remove internal stale-spend assertions. + +## Contract-page comments + +All visible comments were from Harsh: + +- October 1: “Need explaination here @Zaryab Afser”, with Original content deleted. +- October 1 and September 29: tag-only comments with deleted original content. +- October 1 (edited): the existing page-level request to review editable owner-only setLabel, its LabelSet event, cosmetic/non-checkpoint status, D3 and the D4 rename boundary. + +No new contract artifact, limit/default decision, deployment confirmation or raw-offset answer was provided by these visible threads. Deleted original context cannot be reconstructed from this UI. + +## Actions from this review + +- Added H6 for same-agent multiplicity and send selection; tracked as G26. +- Added the token-independence clarification to H3 and referenced it in Z1.1. +- Updated the source index, gap register, external dependencies and implementation-plan warning. +- H3 defaults and H4.5 raw offsets remain unresolved. The live rule type block still declares optional maxValueTotal and arg-based pins/amount. +- No production SDK code, contract source, snapshot body, deployment registry or team message was changed. diff --git a/plan/agw/research/svm-internals-2026-10-06/README.md b/plan/agw/research/svm-internals-2026-10-06/README.md new file mode 100644 index 00000000..6e49f6bf --- /dev/null +++ b/plan/agw/research/svm-internals-2026-10-06/README.md @@ -0,0 +1,57 @@ +# SVM internals — October 6, 2026 + +> Superseded validation status: [live acceptance report](../live-acceptance-2026-10-06/README.md). Full permissions are restored: public Donut derive, all 53 Anvil cases, unfiltered units, Nx build and four typechecks pass. Bounded testnet funding/broadcasts have started. Earlier restrictions and unrun-live statements below describe the original execution only. + +Branch feat/agw-sdk-v4; uncommitted/not pushed. This completes the independent SVM foundation against deployed source e8db748. It does not enable a guessed public SVM Rule API or claim live Solana execution. + +## Implemented + +- [SVM terms codec](../../../../packages/core/src/lib/agentic/codec/svm-terms.ts): exact version-4 body tuple, ordered AssetCaps, program/discriminator rules, account/data pins, shape/bounds, ambiguous prefixes, forbidden programs, raw EQ alignment, little-endian integer widths and ratio constraints. +- [Value-account derivation](../../../../packages/core/src/lib/agentic/codec/svm-accounts.ts): CEA PDA uses the wallet's 20 bytes plus the selected registry gateway; legacy SPL/Token-2022 ATAs; input/output mint coverage, deduplication and the 16-account bound. The resolved-asset context contributes an ATA for every listed SPL mint; native SOL is protected by the CEA itself. Gateway is caller-resolved, not a hard-coded devnet program. +- [Payload checks](../../../../packages/core/src/lib/agentic/execution/svm-payload.ts): reuses the existing node encoder and parses BE counts/lengths, exact consumption, execute ID, recipient/program identity, account positions, protected-account aliasing and all four data-pin modes. Writable bytes are preserved diagnostically; URP deliberately does not enforce them. +- [Internal outbound action](../../../../packages/core/src/lib/agentic/execution/svm-outbound.ts): program recipient, wallet refund, per-token current spend/caps, u64 request amounts and quoted PC budget. Takes a resolved config snapshot; on-chain URP remains final authority. +- SvmConfigRead is available internally. Public exports, Rule union and UNIVERSAL_SVM_RULES capability remain unchanged/gated while the public mapping is unsettled. + +## Validation and limitations + +| Check | Result | +| --- | --- | +| AGW unit suites | 178 passed; includes 23 SVM cases | +| New SDK-generated bytes against actual AGW/engine/URP in Foundry | 10 passed, 0 failed | +| Unfiltered full core Jest run | 1,938 passed; 4 unchanged network-dependent account tests failed; 12 skipped | +| Explicit offline run excluding those four titles | 1,938 passed, 0 failed; 16 skipped (12 existing + 4 explicit network exclusions) | +| lib/spec/local-harness typechecks | Pass | +| Direct TypeScript emit/build | Pass | +| Changed-file lint | 0 errors, 4 existing-style non-null assertion warnings in tests | +| Nx build | Blocked: plugin worker cannot start in this sandbox; direct tsc build passes | +| Anvil SVM SDK end-to-end suite | Authored/typechecked, but 7 cases cannot run: localhost RPC startup is blocked | +| Donut RPC | DNS resolution unavailable in the restricted session | +| Funded/live E2E | Not run; no private key was loaded or displayed, no funding or broadcast | + +The previous v4 migration's 46 Anvil passes remain historical evidence from the earlier environment. They are not counted again as new SVM execution here. + +[Contract runner](run-forge.sh) uses Foundry's in-process EVM, no RPC/ffi. [SDK-generated fixtures](sdk-vectors.json) feed [SdkSvmWire.t.sol](SdkSvmWire.t.sol), which uses the actual pinned BaseTest deployment of factory/wallet/engine/validator/URP. The asset supplies only its namespace; the gateway is a recording observer. The ten checks prove encoded terms/pins/assets, successful metering, account substitution, CEA aliasing, relative price floor, recipient mismatch, trailing bytes, non-execute ID, u64 overflow and dataless constraints. Reverts use named errors with full arguments where SmartSession's truncation includes them. + +The fixture Solana keys are deterministic owner commitments, not a live cluster/PDA claim. PDA/ATA derivation is tested separately. No Solana CPI, real token burn, TSS, production gateway/executor or destination settlement is simulated. [Logs](logs/). + +The four full-suite failures are in unchanged universal/account/account.spec.ts: two direct origin computations and Solana/Ethereum origin lookups that call Donut. They were not weakened or edited. The offline run uses an explicit negative test-name filter, and the original failure log is retained. + +## Keys, funding and next steps + +Shoaib explicitly authorized using the E2E .env keys to fund tests. The existing loader points at packages/core/.env; that file exists, while packages/core/__e2e__/.env does not. Values were neither read for printing nor copied into artifacts. Loading keys is deferred until RPC connectivity succeeds; the blocked public eth_chainId probe needs no secrets. + +When the environment permits network access, first run the existing read-only deployment/balance preflight, honor the selected scenarios' needs and per-run limits (agent PC default 0.5; outbound PC limit default 20), then run the authorized funded acceptance. Do not blindly execute/fund the entire suite. This authorization persists; no repeat permission question is needed for the agreed test purpose within those existing limits. + +Remaining code/API work: agree the public SVM input/read model, connect registry/mint resolution and IDL/account mapping to these internals, integrate public dispatch/tracking, and exercise live UEA/TSS/Solana delivery. H3/H4.5/H6 and absent ref/label scope remain separate. The source-only fixture request is substantially answered by this work; a representative live cluster case is still useful. + +## Reproduce locally + +```sh +bash plan/agw/research/svm-internals-2026-10-06/run-forge.sh +node node_modules/jest/bin/jest.js --config packages/core/jest.config.ts --runInBand --testPathPattern=agentic +node node_modules/typescript/bin/tsc --project packages/core/tsconfig.lib.json --noEmit +node node_modules/typescript/bin/tsc --project packages/core/tsconfig.spec.json --noEmit +node node_modules/typescript/bin/tsc --project packages/core/tsconfig.agw-local.json --noEmit +``` + +run-forge.sh requires the isolated e8db748 build prepared by scripts/agw-local/prepare.sh (or AGW_LOCAL_DIR). It only copies review fixtures and adds read access for them in that temporary build; the contract checkout is not edited. The Anvil integration suite is packages/core/__agw-local__/svm-internals.spec.ts and must be rerun when localhost access is available. diff --git a/plan/agw/research/svm-internals-2026-10-06/SdkSvmWire.t.sol b/plan/agw/research/svm-internals-2026-10-06/SdkSvmWire.t.sol new file mode 100644 index 00000000..dbb01c6a --- /dev/null +++ b/plan/agw/research/svm-internals-2026-10-06/SdkSvmWire.t.sol @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import { BaseTest } from "../test/Base.t.sol"; +import { AGW } from "../src/AGW.sol"; +import { UniversalRulesPolicyErrors } from "../src/libraries/Errors.sol"; +import { ConfigId, Session } from "smartsessions/DataTypes.sol"; +import { SvmConfig, UniversalOutboundTxRequest } from "../src/libraries/Types.sol"; +import { IUniversalGatewayPC } from "../src/interfaces/IUniversalGatewayPC.sol"; + +contract SdkSvmAsset { + function SOURCE_CHAIN_NAMESPACE() external pure returns (string memory) { return "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1"; } +} +contract SdkSvmGatewayObserver { + uint256 public calls; + function sendUniversalTxOutbound(UniversalOutboundTxRequest calldata) external payable { calls++; } +} +/** Review-only. SDK emits bytes; actual AGW/engine/URP decide acceptance. No RPC/server/ffi. */ +contract SdkSvmWireTest is BaseTest { + string private vectors; + AGW private wallet; + bytes32 private rid; + ConfigId private cid; + bytes32 private constant PROGRAM = 0x3333333333333333333333333333333333333333333333333333333333333333; + address private constant ASSET = address(0x7070); + function setUp() public override { + super.setUp(); + vectors = vm.readFile("sdk-harness/sdk-vectors.json"); + vm.etch(ASSET, address(new SdkSvmAsset()).code); + vm.etch(GATEWAY, address(new SdkSvmGatewayObserver()).code); + wallet = newWallet(OWNER); + _grant(".initData"); + vm.deal(address(wallet), 1 ether); + } + function _grant(string memory key) private { + Session memory s = canonicalSession(abi.encode(AGENT), vm.parseJsonBytes(vectors, key)); + vm.prank(OWNER); rid = wallet.grantRules(s); + bytes32 actionId = keccak256(abi.encodePacked(GATEWAY, SEND_OUTBOUND_SELECTOR)); + cid = ConfigId.wrap(keccak256(abi.encodePacked(address(wallet), keccak256(abi.encodePacked(rid, actionId))))); + } + function _data(string memory key, bytes32 recipient, uint256 amount) private view returns (bytes memory) { + UniversalOutboundTxRequest memory r = UniversalOutboundTxRequest({ recipient: abi.encodePacked(recipient), token: ASSET, amount: amount, gasLimit: 200_000, gasPrice: 0, maxPCForGas: 1e15, payload: vm.parseJsonBytes(vectors, key), revertRecipient: address(wallet) }); + return abi.encodeCall(IUniversalGatewayPC.sendUniversalTxOutbound, (r)); + } + function _run(string memory key, bytes32 recipient, uint256 amount) private { + bytes memory data = abi.encodePacked(GATEWAY, uint256(1.1e15), _data(key, recipient, amount)); + vm.prank(AGENT); wallet.executeAsAgent(rid, bytes32(0), data); + } + function test_SdkSvm_EncodedTermsMatchStoredPinsAndAssets() public view { + SvmConfig memory c = urp.getSvmConfig(cid, address(wallet)); + assertTrue(c.initialized); assertEq(c.assets.length, 1); assertEq(c.assets[0].token, ASSET); + assertEq(c.ceaAccounts.length, 2); assertEq(c.pins.length, 2); assertEq(c.dataPins.length, 1); + assertEq(c.dataPins[0].num, 9); assertEq(c.dataPins[0].den, 10); + } + function test_SdkSvm_ValidPayloadPassesAndMeters() public { + _run(".valid", PROGRAM, 5); + assertEq(urp.getSvmConfig(cid, address(wallet)).assets[0].spent, 5); + assertEq(SdkSvmGatewayObserver(GATEWAY).calls(), 1); + } + function test_SdkSvm_AccountSubstitutionFails() public { + expectUrpGate(UniversalRulesPolicyErrors.SvmAccountPinMismatch.selector); _run(".badPin", PROGRAM, 5); + } + function test_SdkSvm_ProtectedAccountAliasFails() public { + expectUrpGate(UniversalRulesPolicyErrors.CeaAccountAtUnpinnedIndex.selector); _run(".alias", PROGRAM, 5); + } + function test_SdkSvm_RatioFloorFailsWithoutSpend() public { + expectUrpGate(UniversalRulesPolicyErrors.SvmDataRatioNotMet.selector); _run(".badRatio", PROGRAM, 5); + assertEq(urp.getSvmConfig(cid, address(wallet)).assets[0].spent, 0); + } + function test_SdkSvm_RecipientMismatchFails() public { + expectUrpGate(UniversalRulesPolicyErrors.RecipientTargetMismatch.selector); _run(".valid", bytes32(uint256(7)), 5); + } + function test_SdkSvm_TrailingPayloadFails() public { + expectUrpGate(UniversalRulesPolicyErrors.MalformedSvmPayload.selector); _run(".trailing", PROGRAM, 5); + } + function test_SdkSvm_NonExecuteFails() public { + expectUrpGate(UniversalRulesPolicyErrors.SvmInstructionNotExecute.selector); _run(".wrongId", PROGRAM, 5); + } + function test_SdkSvm_U64OverflowFails() public { + expectUrpGate(abi.encodeWithSelector(UniversalRulesPolicyErrors.AmountExceedsU64.selector, uint256(type(uint64).max) + 1)); _run(".valid", PROGRAM, uint256(type(uint64).max) + 1); + } + function test_SdkSvm_DatalessOnlyEmptyData() public { + _grant(".datalessInitData"); _run(".datalessPayload", PROGRAM, 0); + expectUrpGate(abi.encodeWithSelector(UniversalRulesPolicyErrors.ProgramNotAllowed.selector, PROGRAM, bytes8(0x0100000000000000))); _run(".valid", PROGRAM, 0); + } +} diff --git a/plan/agw/research/svm-internals-2026-10-06/generate-vectors.ts b/plan/agw/research/svm-internals-2026-10-06/generate-vectors.ts new file mode 100644 index 00000000..ce60384b --- /dev/null +++ b/plan/agw/research/svm-internals-2026-10-06/generate-vectors.ts @@ -0,0 +1,29 @@ +/** Public fixture values only. No network, key loading, signing or broadcasting. */ +import { writeFileSync } from 'node:fs'; +import { join } from 'node:path'; +import type { Hex } from 'viem'; +import { encodeSvmTerms, type SvmTermsWire } from '../../../../packages/core/src/lib/agentic/codec/svm-terms'; +import { encodeEnvelope } from '../../../../packages/core/src/lib/agentic/codec/session'; +import { encodeAgwSvmPayload } from '../../../../packages/core/src/lib/agentic/execution/svm-payload'; +const key = (b: string) => `0x${b.repeat(32)}` as Hex; +const cea = key('11'), ata = key('44'), program = key('33'); +const terms: SvmTermsWire = { + validUntil: 2_000_000_000, expectedCEA: cea, gatewayProgram: key('22'), + assets: [{ token: '0x0000000000000000000000000000000000007070', maxPerCall: BigInt(2) ** BigInt(256) - BigInt(1), maxTotal: BigInt(2) ** BigInt(256) - BigInt(1) }], maxGasPerCall: BigInt(10) ** BigInt(16), + ceaAccounts: [cea, ata], programs: [{ program, discriminator: '0x0100000000000000', discriminatorLen: 1, dataless: false, maxAccounts: 0 }], + pins: [{ ruleIndex: 0, accountIndex: 0, expected: cea }, { ruleIndex: 0, accountIndex: 1, expected: ata }], + dataPins: [{ ruleIndex: 0, fromEnd: true, offset: 4, offsetB: 2, len: 2, mode: 3, expected: key('00'), num: BigInt(9), den: BigInt(10) }], +}; +const accounts = [{ pubkey: cea, isWritable: true }, { pubkey: ata, isWritable: true }]; +const payload = (a: typeof accounts, out = 90) => encodeAgwSvmPayload(program, a, new Uint8Array([1, out, 0, 100, 0])); +const valid = payload(accounts), wrongId = Buffer.from(valid.slice(2), 'hex'); wrongId[wrongId.length - 33] = 1; +const dataless = { ...terms, programs: [{ ...terms.programs[0], discriminatorLen: 0, dataless: true }], dataPins: [] }; +writeFileSync(join(__dirname, 'sdk-vectors.json'), JSON.stringify({ + source: 'e8db74815cfbbf5389593805e464fe8d85f7f735', + note: 'Deterministic owner-committed Solana keys; no live PDA/cluster or transport claim.', + initData: encodeEnvelope('solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1', encodeSvmTerms(terms, 0)), + datalessInitData: encodeEnvelope('solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1', encodeSvmTerms(dataless, 0)), + valid, badRatio: payload(accounts, 89), badPin: payload([{ ...accounts[0], pubkey: key('77') }, accounts[1]]), + alias: payload([...accounts, accounts[0]]), trailing: `${valid}00`, wrongId: `0x${wrongId.toString('hex')}`, + datalessPayload: encodeAgwSvmPayload(program, accounts, new Uint8Array()), +}, null, 2) + '\n'); diff --git a/plan/agw/research/svm-internals-2026-10-06/logs/agentic-unit.log b/plan/agw/research/svm-internals-2026-10-06/logs/agentic-unit.log new file mode 100644 index 00000000..17f70357 --- /dev/null +++ b/plan/agw/research/svm-internals-2026-10-06/logs/agentic-unit.log @@ -0,0 +1,15 @@ +PASS core packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/management.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/response-surface.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/send.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/codec.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/reads-context.spec.ts + +Test Suites: 9 passed, 9 total +Tests: 178 passed, 178 total +Snapshots: 0 total +Time: 3.414 s, estimated 4 s +Ran all test suites matching /agentic/i. diff --git a/plan/agw/research/svm-internals-2026-10-06/logs/anvil-blocked.log b/plan/agw/research/svm-internals-2026-10-06/logs/anvil-blocked.log new file mode 100644 index 00000000..23f0f3a7 --- /dev/null +++ b/plan/agw/research/svm-internals-2026-10-06/logs/anvil-blocked.log @@ -0,0 +1,134 @@ +FAIL core-agw-local packages/core/__agw-local__/svm-internals.spec.ts (25.615 s) + internal SVM codec/payloads against actual v4 contracts + ✕ grants SDK-encoded SVM terms and preserves every field/account (2 ms) + ✕ the internal composed call passes actual S1–S18 and meters its token + ✕ account substitution and CEA aliasing are rejected by URP + ✕ relative price floor and recipient/program identity are enforced on-chain + ✕ trailing bytes, non-execute IDs and u64 overflow are rejected + ✕ dataless rules accept only empty instruction data (1 ms) + ✕ fixed account counts reject appended accounts and failed calls do not change spend + + ● internal SVM codec/payloads against actual v4 contracts › grants SDK-encoded SVM terms and preserves every field/account + + anvil did not start at http://127.0.0.1:18552 + + 149 | } + 150 | if (Date.now() - start > timeoutMs) + > 151 | throw new Error(`anvil did not start at ${url}`); + | ^ + 152 | await new Promise((r) => setTimeout(r, 200)); + 153 | } + 154 | } + + at waitForRpc (__agw-local__/harness.ts:151:13) + at async deployHarness (__agw-local__/harness.ts:185:3) + at async startHarness (__agw-local__/harness.ts:173:12) + at async Object. (__agw-local__/svm-internals.spec.ts:31:9) + + ● internal SVM codec/payloads against actual v4 contracts › the internal composed call passes actual S1–S18 and meters its token + + anvil did not start at http://127.0.0.1:18552 + + 149 | } + 150 | if (Date.now() - start > timeoutMs) + > 151 | throw new Error(`anvil did not start at ${url}`); + | ^ + 152 | await new Promise((r) => setTimeout(r, 200)); + 153 | } + 154 | } + + at waitForRpc (__agw-local__/harness.ts:151:13) + at async deployHarness (__agw-local__/harness.ts:185:3) + at async startHarness (__agw-local__/harness.ts:173:12) + at async Object. (__agw-local__/svm-internals.spec.ts:31:9) + + ● internal SVM codec/payloads against actual v4 contracts › account substitution and CEA aliasing are rejected by URP + + anvil did not start at http://127.0.0.1:18552 + + 149 | } + 150 | if (Date.now() - start > timeoutMs) + > 151 | throw new Error(`anvil did not start at ${url}`); + | ^ + 152 | await new Promise((r) => setTimeout(r, 200)); + 153 | } + 154 | } + + at waitForRpc (__agw-local__/harness.ts:151:13) + at async deployHarness (__agw-local__/harness.ts:185:3) + at async startHarness (__agw-local__/harness.ts:173:12) + at async Object. (__agw-local__/svm-internals.spec.ts:31:9) + + ● internal SVM codec/payloads against actual v4 contracts › relative price floor and recipient/program identity are enforced on-chain + + anvil did not start at http://127.0.0.1:18552 + + 149 | } + 150 | if (Date.now() - start > timeoutMs) + > 151 | throw new Error(`anvil did not start at ${url}`); + | ^ + 152 | await new Promise((r) => setTimeout(r, 200)); + 153 | } + 154 | } + + at waitForRpc (__agw-local__/harness.ts:151:13) + at async deployHarness (__agw-local__/harness.ts:185:3) + at async startHarness (__agw-local__/harness.ts:173:12) + at async Object. (__agw-local__/svm-internals.spec.ts:31:9) + + ● internal SVM codec/payloads against actual v4 contracts › trailing bytes, non-execute IDs and u64 overflow are rejected + + anvil did not start at http://127.0.0.1:18552 + + 149 | } + 150 | if (Date.now() - start > timeoutMs) + > 151 | throw new Error(`anvil did not start at ${url}`); + | ^ + 152 | await new Promise((r) => setTimeout(r, 200)); + 153 | } + 154 | } + + at waitForRpc (__agw-local__/harness.ts:151:13) + at async deployHarness (__agw-local__/harness.ts:185:3) + at async startHarness (__agw-local__/harness.ts:173:12) + at async Object. (__agw-local__/svm-internals.spec.ts:31:9) + + ● internal SVM codec/payloads against actual v4 contracts › dataless rules accept only empty instruction data + + anvil did not start at http://127.0.0.1:18552 + + 149 | } + 150 | if (Date.now() - start > timeoutMs) + > 151 | throw new Error(`anvil did not start at ${url}`); + | ^ + 152 | await new Promise((r) => setTimeout(r, 200)); + 153 | } + 154 | } + + at waitForRpc (__agw-local__/harness.ts:151:13) + at async deployHarness (__agw-local__/harness.ts:185:3) + at async startHarness (__agw-local__/harness.ts:173:12) + at async Object. (__agw-local__/svm-internals.spec.ts:31:9) + + ● internal SVM codec/payloads against actual v4 contracts › fixed account counts reject appended accounts and failed calls do not change spend + + anvil did not start at http://127.0.0.1:18552 + + 149 | } + 150 | if (Date.now() - start > timeoutMs) + > 151 | throw new Error(`anvil did not start at ${url}`); + | ^ + 152 | await new Promise((r) => setTimeout(r, 200)); + 153 | } + 154 | } + + at waitForRpc (__agw-local__/harness.ts:151:13) + at async deployHarness (__agw-local__/harness.ts:185:3) + at async startHarness (__agw-local__/harness.ts:173:12) + at async Object. (__agw-local__/svm-internals.spec.ts:31:9) + +Test Suites: 1 failed, 1 total +Tests: 7 failed, 7 total +Snapshots: 0 total +Time: 25.652 s +Ran all test suites within paths "packages/core/__agw-local__/svm-internals.spec.ts". diff --git a/plan/agw/research/svm-internals-2026-10-06/logs/forge-contracts.log b/plan/agw/research/svm-internals-2026-10-06/logs/forge-contracts.log new file mode 100644 index 00000000..f5a0ce91 --- /dev/null +++ b/plan/agw/research/svm-internals-2026-10-06/logs/forge-contracts.log @@ -0,0 +1,48 @@ +Compiling 1 files with Solc 0.8.26 +Solc 0.8.26 finished in 12.54s +Compiler run successful with warnings: +Warning (5667): Unused function parameter. Remove or comment out the variable name to silence this warning. + --> lib/smartsessions/contracts/lib/ConfigLib.sol:77:9: + | +77 | bool useRegistry + | ^^^^^^^^^^^^^^^^ + +Warning (5667): Unused function parameter. Remove or comment out the variable name to silence this warning. + --> lib/smartsessions/contracts/lib/ConfigLib.sol:123:9: + | +123 | bool useRegistry + | ^^^^^^^^^^^^^^^^ + +Warning (5667): Unused function parameter. Remove or comment out the variable name to silence this warning. + --> lib/smartsessions/contracts/lib/ConfigLib.sol:203:9: + | +203 | bool useRegistry + | ^^^^^^^^^^^^^^^^ + +Warning (5667): Unused function parameter. Remove or comment out the variable name to silence this warning. + --> lib/smartsessions/contracts/core/SmartSessionBase.sol:270:9: + | +270 | bool useRegistry + | ^^^^^^^^^^^^^^^^ + +Warning (2018): Function state mutability can be restricted to view + --> src/AGWFactory.sol:352:5: + | +352 | function _authorizeUpgrade(address newImplementation) internal override onlyRole(DEFAULT_ADMIN_ROLE) { + | ^ (Relevant source part starts here and spans across multiple lines). + + +Ran 10 tests for sdk-harness/SdkSvmWire.t.sol:SdkSvmWireTest +[PASS] test_SdkSvm_AccountSubstitutionFails() (gas: 622358) +[PASS] test_SdkSvm_DatalessOnlyEmptyData() (gas: 1573814) +[PASS] test_SdkSvm_EncodedTermsMatchStoredPinsAndAssets() (gas: 83952) +[PASS] test_SdkSvm_NonExecuteFails() (gas: 603571) +[PASS] test_SdkSvm_ProtectedAccountAliasFails() (gas: 647688) +[PASS] test_SdkSvm_RatioFloorFailsWithoutSpend() (gas: 716489) +[PASS] test_SdkSvm_RecipientMismatchFails() (gas: 603986) +[PASS] test_SdkSvm_TrailingPayloadFails() (gas: 603572) +[PASS] test_SdkSvm_U64OverflowFails() (gas: 595604) +[PASS] test_SdkSvm_ValidPayloadPassesAndMeters() (gas: 736266) +Suite result: ok. 10 passed; 0 failed; 0 skipped; finished in 10.64ms (10.46ms CPU time) + +Ran 1 test suite in 17.80ms (10.64ms CPU time): 10 tests passed, 0 failed, 0 skipped (10 total tests) diff --git a/plan/agw/research/svm-internals-2026-10-06/logs/full-unit-network-blocked.log b/plan/agw/research/svm-internals-2026-10-06/logs/full-unit-network-blocked.log new file mode 100644 index 00000000..59d1ed0f --- /dev/null +++ b/plan/agw/research/svm-internals-2026-10-06/logs/full-unit-network-blocked.log @@ -0,0 +1,600 @@ +FAIL core packages/core/src/lib/universal/account/account.spec.ts (63.147 s) + ● Console + + console.warn + [PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead. + + 425 | ): Promise { + 426 | if (!options?._internal && !_convertExecutorToOriginWarned) { + > 427 | console.warn( + | ^ + 428 | '[PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead.' + 429 | ); + 430 | _convertExecutorToOriginWarned = true; + + at convertExecutorToOrigin (src/lib/universal/account/account.ts:427:13) + at Object. (src/lib/universal/account/account.spec.ts:106:38) + + console.warn + [PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead. + + 207 | ): Promise { + 208 | if (!_convertOriginToExecutorWarned) { + > 209 | console.warn( + | ^ + 210 | '[PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead.' + 211 | ); + 212 | _convertOriginToExecutorWarned = true; + + at convertOriginToExecutor (src/lib/universal/account/account.ts:209:13) + at Object. (src/lib/universal/account/account.spec.ts:158:51) + + ● Universal Account Utilities › convertOriginToExecutor() - Not Mocked › should return same address and pushChainClient.universal.account + + thrown: "Exceeded timeout of 30000 ms for a test. + Add a timeout value to this test to increase the timeout, if this is a long-running test. See https://jestjs.io/docs/api#testname-fn-timeout." + + 64 | // Network-dependent tests - run via integration config + 65 | describe('convertOriginToExecutor() - Not Mocked', () => { + > 66 | it('should return same address and pushChainClient.universal.account', async () => { + | ^ + 67 | const account = privateKeyToAccount(generatePrivateKey()); + 68 | const walletClient = createWalletClient({ + 69 | account: account, + + at src/lib/universal/account/account.spec.ts:66:5 + at src/lib/universal/account/account.spec.ts:65:3 + at Object. (src/lib/universal/account/account.spec.ts:17:1) + + ● Universal Account Utilities › convertExecutorToOrigin() › Solana: should return valid origin data for a UEA address + + ContractFunctionExecutionError: HTTP request failed. + + URL: https://evm.donut.rpc.push.org/ + Request body: {"method":"eth_call","params":[{"data":"0xd0f4b097000000000000000000000000bcfad05e5f19ae46feaab2f72ad9977bc239b395","to":"0x00000000000000000000000000000000000000eA"},"latest"]} + + Raw Call Arguments: + to: 0x00000000000000000000000000000000000000eA + data: 0xd0f4b097000000000000000000000000bcfad05e5f19ae46feaab2f72ad9977bc239b395 + + Contract Call: + address: 0x00000000000000000000000000000000000000eA + function: getOriginForUEA(address addr) + args: (0xbCfaD05E5f19Ae46feAab2F72Ad9977BC239b395) + + Docs: https://viem.sh/docs/contract/readContract + Details: fetch failed + Version: viem@2.27.2 + + 486 | }); + 487 | + > 488 | const originResult = (await client.readContract({ + | ^ + 489 | address: FACTORY_ADDRESS, + 490 | abi: FACTORY_V1, + 491 | functionName: 'getOriginForUEA', + + at getContractError (../../node_modules/viem/utils/errors/getContractError.ts:78:10) + at readContract (../../node_modules/viem/actions/public/readContract.ts:136:27) + at async convertExecutorToOrigin (src/lib/universal/account/account.ts:488:25) + at async Object. (src/lib/universal/account/account.spec.ts:106:9) + + Cause: + CallExecutionError: HTTP request failed. + + URL: https://evm.donut.rpc.push.org/ + Request body: {"method":"eth_call","params":[{"data":"0xd0f4b097000000000000000000000000bcfad05e5f19ae46feaab2f72ad9977bc239b395","to":"0x00000000000000000000000000000000000000eA"},"latest"]} + + Raw Call Arguments: + to: 0x00000000000000000000000000000000000000eA + data: 0xd0f4b097000000000000000000000000bcfad05e5f19ae46feaab2f72ad9977bc239b395 + + Details: fetch failed + Version: viem@2.27.2 + + 486 | }); + 487 | + > 488 | const originResult = (await client.readContract({ + | ^ + 489 | address: FACTORY_ADDRESS, + 490 | abi: FACTORY_V1, + 491 | functionName: 'getOriginForUEA', + + at getCallError (../../node_modules/viem/utils/errors/getCallError.ts:42:10) + at call (../../node_modules/viem/actions/public/call.ts:282:23) + at async readContract (../../node_modules/viem/actions/public/readContract.ts:120:22) + at async convertExecutorToOrigin (src/lib/universal/account/account.ts:488:25) + at async Object. (src/lib/universal/account/account.spec.ts:106:9) + + Cause: + HttpRequestError: HTTP request failed. + + URL: https://evm.donut.rpc.push.org/ + Request body: {"method":"eth_call","params":[{"data":"0xd0f4b097000000000000000000000000bcfad05e5f19ae46feaab2f72ad9977bc239b395","to":"0x00000000000000000000000000000000000000eA"},"latest"]} + + Details: fetch failed + Version: viem@2.27.2 + + at Object.request (../../node_modules/viem/utils/rpc/http.ts:161:15) + at async fn (../../node_modules/viem/clients/transports/http.ts:145:19) + at async request (../../node_modules/viem/clients/transports/http.ts:150:39) + at async delay.count.count (../../node_modules/viem/utils/buildRequest.ts:150:22) + at async attemptRetry (../../node_modules/viem/utils/promise/withRetry.ts:44:22) + + Cause: + TypeError: fetch failed + + at async response.errorInstance.request_js_1.TimeoutError.body.body (../../node_modules/viem/utils/rpc/http.ts:120:30) + at ../../async /Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/utils/promise/withTimeout.ts:36:17 + + Cause: + getaddrinfo ENOTFOUND evm.donut.rpc.push.org + + + + ● Universal Account Utilities › convertExecutorToOrigin() › Ethereum: should return valid origin data for a UEA address + + ContractFunctionExecutionError: HTTP request failed. + + URL: https://evm.donut.rpc.push.org/ + Request body: {"method":"eth_call","params":[{"data":"0xd0f4b0970000000000000000000000007aee1699fee2c906251863d24d35b3debe0932ec","to":"0x00000000000000000000000000000000000000eA"},"latest"]} + + Raw Call Arguments: + to: 0x00000000000000000000000000000000000000eA + data: 0xd0f4b0970000000000000000000000007aee1699fee2c906251863d24d35b3debe0932ec + + Contract Call: + address: 0x00000000000000000000000000000000000000eA + function: getOriginForUEA(address addr) + args: (0x7AEE1699FeE2C906251863D24D35B3dEbe0932EC) + + Docs: https://viem.sh/docs/contract/readContract + Details: fetch failed + Version: viem@2.27.2 + + 486 | }); + 487 | + > 488 | const originResult = (await client.readContract({ + | ^ + 489 | address: FACTORY_ADDRESS, + 490 | abi: FACTORY_V1, + 491 | functionName: 'getOriginForUEA', + + at getContractError (../../node_modules/viem/utils/errors/getContractError.ts:78:10) + at readContract (../../node_modules/viem/actions/public/readContract.ts:136:27) + at async convertExecutorToOrigin (src/lib/universal/account/account.ts:488:25) + at async Object. (src/lib/universal/account/account.spec.ts:130:9) + + Cause: + CallExecutionError: HTTP request failed. + + URL: https://evm.donut.rpc.push.org/ + Request body: {"method":"eth_call","params":[{"data":"0xd0f4b0970000000000000000000000007aee1699fee2c906251863d24d35b3debe0932ec","to":"0x00000000000000000000000000000000000000eA"},"latest"]} + + Raw Call Arguments: + to: 0x00000000000000000000000000000000000000eA + data: 0xd0f4b0970000000000000000000000007aee1699fee2c906251863d24d35b3debe0932ec + + Details: fetch failed + Version: viem@2.27.2 + + 486 | }); + 487 | + > 488 | const originResult = (await client.readContract({ + | ^ + 489 | address: FACTORY_ADDRESS, + 490 | abi: FACTORY_V1, + 491 | functionName: 'getOriginForUEA', + + at getCallError (../../node_modules/viem/utils/errors/getCallError.ts:42:10) + at call (../../node_modules/viem/actions/public/call.ts:282:23) + at async readContract (../../node_modules/viem/actions/public/readContract.ts:120:22) + at async convertExecutorToOrigin (src/lib/universal/account/account.ts:488:25) + at async Object. (src/lib/universal/account/account.spec.ts:130:9) + + Cause: + HttpRequestError: HTTP request failed. + + URL: https://evm.donut.rpc.push.org/ + Request body: {"method":"eth_call","params":[{"data":"0xd0f4b0970000000000000000000000007aee1699fee2c906251863d24d35b3debe0932ec","to":"0x00000000000000000000000000000000000000eA"},"latest"]} + + Details: fetch failed + Version: viem@2.27.2 + + at Object.request (../../node_modules/viem/utils/rpc/http.ts:161:15) + at async fn (../../node_modules/viem/clients/transports/http.ts:145:19) + at async request (../../node_modules/viem/clients/transports/http.ts:150:39) + at async delay.count.count (../../node_modules/viem/utils/buildRequest.ts:150:22) + at async attemptRetry (../../node_modules/viem/utils/promise/withRetry.ts:44:22) + + Cause: + TypeError: fetch failed + + at async response.errorInstance.request_js_1.TimeoutError.body.body (../../node_modules/viem/utils/rpc/http.ts:120:30) + at ../../async /Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/utils/promise/withTimeout.ts:36:17 + + Cause: + getaddrinfo ENOTFOUND evm.donut.rpc.push.org + + + + ● Universal Account Utilities › convertOriginToExecutor() - Direct Tests › should compute and cache address for EVM chain + + thrown: "Exceeded timeout of 30000 ms for a test. + Add a timeout value to this test to increase the timeout, if this is a long-running test. See https://jestjs.io/docs/api#testname-fn-timeout." + + 191 | + 192 | // Network-dependent test - run via integration config + > 193 | it('should compute and cache address for EVM chain', async () => { + | ^ + 194 | const evmAccount = { + 195 | chain: CHAIN.ETHEREUM_SEPOLIA, + 196 | address: EVM_ADDRESS, + + at src/lib/universal/account/account.spec.ts:193:5 + at src/lib/universal/account/account.spec.ts:151:3 + at Object. (src/lib/universal/account/account.spec.ts:17:1) + +PASS core packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-error-classification.spec.ts + +ReferenceError: You are trying to `import` a file after the Jest environment has been torn down. From src/lib/universal/account/account.spec.ts. + + 69 | bytecodeHash: initCodeHash, + 70 | }); + > 71 | } + | ^ + 72 | + 73 | // ============================================================================ + 74 | // On-chain UEA Computation + + at ../../node_modules/viem/actions/public/call.ts:268:57 + at async call (../../node_modules/viem/actions/public/call.ts:268:57) + at async readContract (../../node_modules/viem/actions/public/readContract.ts:120:22) + at async computeUEA (src/lib/orchestrator/internals/uea-manager.ts:71:29) + at async Object. (src/lib/universal/account/account.spec.ts:79:24) +PASS core packages/core/src/lib/orchestrator/__tests__/send-transaction-progress-hook.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/block-results-client.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/response-invariant.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r2-outbound-revert-flow.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/inbound-tracker-derivation.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-tx-retry.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-timeout-clamp.spec.ts +PASS core packages/core/src/lib/push-client/push-client.archive-fallback.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-confirmation-gate.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/response-surface.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/funds-only-burn-guard.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-composition.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r1-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-emission.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/read-tx-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-event-hook-bridge.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-calculator.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/resolve.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-svm-r3.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/multichain-hooks.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-executor.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r3-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/signing-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/account-status.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-tracker.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/execute-standard-required-funds.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-evm.spec.ts +PASS core packages/core/src/lib/universal/signer/signer.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/gate.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-gas.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-multichain.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gateway-uea-account.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm-rent-pc20.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/resolver.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/send.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/inbound-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/source-hash-resolution.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/chain-namespace.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-evm-r3-native-eoa.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/rescue-svm-confirmation.spec.ts +PASS core packages/core/src/lib/utils.spec.ts + ● Console + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:973:17) + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:977:17) + + console.log + 1.23 + + at Object. (src/lib/utils.spec.ts:982:17) + +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-native-multicall.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-builder-progress-hook.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-svm-rent.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-request-recipient.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/context-helpers-tracker.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/management.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/payload-builders.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/scenarios.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/public-surface.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/export.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r2-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/svm-rent.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/track-transaction-guard.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/registry.spec.ts +PASS core packages/core/src/lib/push-client/push-client.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/response-builder-push-revert.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-detector.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/build-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/__tests__/signing.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/terminal-suppression.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/cascade.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-usd-sizer.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-params.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-svm.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/spec-builder.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-events.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm-log-index.spec.ts +PASS core packages/core/src/lib/constants/__tests__/token-constants.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/web2-compat.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/revalidate-read.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/normalize.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/result-decoder.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/ucallback-codec.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/abi-selectors.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/svm-account.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/child-inbounds.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/codec.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/auto-detect.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/reads-context.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-web2.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/validate.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg-svm.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/address-codec.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.chain-symbol.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/budget.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/registry.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.dynamic-gas.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-types.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/classify.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/errors.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/max-pc-for-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/normalize-address.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/ix-encoder.spec.ts +PASS core packages/core/src/lib/constants/__tests__/svm-gateway-idl.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/tracking.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/error-decoder.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-execute-order.spec.ts +PASS core packages/core/src/lib/formatters.spec.ts + +Summary of all failing tests +FAIL src/lib/universal/account/account.spec.ts (63.147 s) + ● Universal Account Utilities › convertOriginToExecutor() - Not Mocked › should return same address and pushChainClient.universal.account + + thrown: "Exceeded timeout of 30000 ms for a test. + Add a timeout value to this test to increase the timeout, if this is a long-running test. See https://jestjs.io/docs/api#testname-fn-timeout." + + 64 | // Network-dependent tests - run via integration config + 65 | describe('convertOriginToExecutor() - Not Mocked', () => { + > 66 | it('should return same address and pushChainClient.universal.account', async () => { + | ^ + 67 | const account = privateKeyToAccount(generatePrivateKey()); + 68 | const walletClient = createWalletClient({ + 69 | account: account, + + at src/lib/universal/account/account.spec.ts:66:5 + at src/lib/universal/account/account.spec.ts:65:3 + at Object. (src/lib/universal/account/account.spec.ts:17:1) + + ● Universal Account Utilities › convertExecutorToOrigin() › Solana: should return valid origin data for a UEA address + + ContractFunctionExecutionError: HTTP request failed. + + URL: https://evm.donut.rpc.push.org/ + Request body: {"method":"eth_call","params":[{"data":"0xd0f4b097000000000000000000000000bcfad05e5f19ae46feaab2f72ad9977bc239b395","to":"0x00000000000000000000000000000000000000eA"},"latest"]} + + Raw Call Arguments: + to: 0x00000000000000000000000000000000000000eA + data: 0xd0f4b097000000000000000000000000bcfad05e5f19ae46feaab2f72ad9977bc239b395 + + Contract Call: + address: 0x00000000000000000000000000000000000000eA + function: getOriginForUEA(address addr) + args: (0xbCfaD05E5f19Ae46feAab2F72Ad9977BC239b395) + + Docs: https://viem.sh/docs/contract/readContract + Details: fetch failed + Version: viem@2.27.2 + + 486 | }); + 487 | + > 488 | const originResult = (await client.readContract({ + | ^ + 489 | address: FACTORY_ADDRESS, + 490 | abi: FACTORY_V1, + 491 | functionName: 'getOriginForUEA', + + at getContractError (../../node_modules/viem/utils/errors/getContractError.ts:78:10) + at readContract (../../node_modules/viem/actions/public/readContract.ts:136:27) + at async convertExecutorToOrigin (src/lib/universal/account/account.ts:488:25) + at async Object. (src/lib/universal/account/account.spec.ts:106:9) + + Cause: + CallExecutionError: HTTP request failed. + + URL: https://evm.donut.rpc.push.org/ + Request body: {"method":"eth_call","params":[{"data":"0xd0f4b097000000000000000000000000bcfad05e5f19ae46feaab2f72ad9977bc239b395","to":"0x00000000000000000000000000000000000000eA"},"latest"]} + + Raw Call Arguments: + to: 0x00000000000000000000000000000000000000eA + data: 0xd0f4b097000000000000000000000000bcfad05e5f19ae46feaab2f72ad9977bc239b395 + + Details: fetch failed + Version: viem@2.27.2 + + 486 | }); + 487 | + > 488 | const originResult = (await client.readContract({ + | ^ + 489 | address: FACTORY_ADDRESS, + 490 | abi: FACTORY_V1, + 491 | functionName: 'getOriginForUEA', + + at getCallError (../../node_modules/viem/utils/errors/getCallError.ts:42:10) + at call (../../node_modules/viem/actions/public/call.ts:282:23) + at async readContract (../../node_modules/viem/actions/public/readContract.ts:120:22) + at async convertExecutorToOrigin (src/lib/universal/account/account.ts:488:25) + at async Object. (src/lib/universal/account/account.spec.ts:106:9) + + Cause: + HttpRequestError: HTTP request failed. + + URL: https://evm.donut.rpc.push.org/ + Request body: {"method":"eth_call","params":[{"data":"0xd0f4b097000000000000000000000000bcfad05e5f19ae46feaab2f72ad9977bc239b395","to":"0x00000000000000000000000000000000000000eA"},"latest"]} + + Details: fetch failed + Version: viem@2.27.2 + + at Object.request (../../node_modules/viem/utils/rpc/http.ts:161:15) + at async fn (../../node_modules/viem/clients/transports/http.ts:145:19) + at async request (../../node_modules/viem/clients/transports/http.ts:150:39) + at async delay.count.count (../../node_modules/viem/utils/buildRequest.ts:150:22) + at async attemptRetry (../../node_modules/viem/utils/promise/withRetry.ts:44:22) + + Cause: + TypeError: fetch failed + + at async response.errorInstance.request_js_1.TimeoutError.body.body (../../node_modules/viem/utils/rpc/http.ts:120:30) + at ../../async /Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/utils/promise/withTimeout.ts:36:17 + + Cause: + getaddrinfo ENOTFOUND evm.donut.rpc.push.org + + + + ● Universal Account Utilities › convertExecutorToOrigin() › Ethereum: should return valid origin data for a UEA address + + ContractFunctionExecutionError: HTTP request failed. + + URL: https://evm.donut.rpc.push.org/ + Request body: {"method":"eth_call","params":[{"data":"0xd0f4b0970000000000000000000000007aee1699fee2c906251863d24d35b3debe0932ec","to":"0x00000000000000000000000000000000000000eA"},"latest"]} + + Raw Call Arguments: + to: 0x00000000000000000000000000000000000000eA + data: 0xd0f4b0970000000000000000000000007aee1699fee2c906251863d24d35b3debe0932ec + + Contract Call: + address: 0x00000000000000000000000000000000000000eA + function: getOriginForUEA(address addr) + args: (0x7AEE1699FeE2C906251863D24D35B3dEbe0932EC) + + Docs: https://viem.sh/docs/contract/readContract + Details: fetch failed + Version: viem@2.27.2 + + 486 | }); + 487 | + > 488 | const originResult = (await client.readContract({ + | ^ + 489 | address: FACTORY_ADDRESS, + 490 | abi: FACTORY_V1, + 491 | functionName: 'getOriginForUEA', + + at getContractError (../../node_modules/viem/utils/errors/getContractError.ts:78:10) + at readContract (../../node_modules/viem/actions/public/readContract.ts:136:27) + at async convertExecutorToOrigin (src/lib/universal/account/account.ts:488:25) + at async Object. (src/lib/universal/account/account.spec.ts:130:9) + + Cause: + CallExecutionError: HTTP request failed. + + URL: https://evm.donut.rpc.push.org/ + Request body: {"method":"eth_call","params":[{"data":"0xd0f4b0970000000000000000000000007aee1699fee2c906251863d24d35b3debe0932ec","to":"0x00000000000000000000000000000000000000eA"},"latest"]} + + Raw Call Arguments: + to: 0x00000000000000000000000000000000000000eA + data: 0xd0f4b0970000000000000000000000007aee1699fee2c906251863d24d35b3debe0932ec + + Details: fetch failed + Version: viem@2.27.2 + + 486 | }); + 487 | + > 488 | const originResult = (await client.readContract({ + | ^ + 489 | address: FACTORY_ADDRESS, + 490 | abi: FACTORY_V1, + 491 | functionName: 'getOriginForUEA', + + at getCallError (../../node_modules/viem/utils/errors/getCallError.ts:42:10) + at call (../../node_modules/viem/actions/public/call.ts:282:23) + at async readContract (../../node_modules/viem/actions/public/readContract.ts:120:22) + at async convertExecutorToOrigin (src/lib/universal/account/account.ts:488:25) + at async Object. (src/lib/universal/account/account.spec.ts:130:9) + + Cause: + HttpRequestError: HTTP request failed. + + URL: https://evm.donut.rpc.push.org/ + Request body: {"method":"eth_call","params":[{"data":"0xd0f4b0970000000000000000000000007aee1699fee2c906251863d24d35b3debe0932ec","to":"0x00000000000000000000000000000000000000eA"},"latest"]} + + Details: fetch failed + Version: viem@2.27.2 + + at Object.request (../../node_modules/viem/utils/rpc/http.ts:161:15) + at async fn (../../node_modules/viem/clients/transports/http.ts:145:19) + at async request (../../node_modules/viem/clients/transports/http.ts:150:39) + at async delay.count.count (../../node_modules/viem/utils/buildRequest.ts:150:22) + at async attemptRetry (../../node_modules/viem/utils/promise/withRetry.ts:44:22) + + Cause: + TypeError: fetch failed + + at async response.errorInstance.request_js_1.TimeoutError.body.body (../../node_modules/viem/utils/rpc/http.ts:120:30) + at ../../async /Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/utils/promise/withTimeout.ts:36:17 + + Cause: + getaddrinfo ENOTFOUND evm.donut.rpc.push.org + + + + ● Universal Account Utilities › convertOriginToExecutor() - Direct Tests › should compute and cache address for EVM chain + + thrown: "Exceeded timeout of 30000 ms for a test. + Add a timeout value to this test to increase the timeout, if this is a long-running test. See https://jestjs.io/docs/api#testname-fn-timeout." + + 191 | + 192 | // Network-dependent test - run via integration config + > 193 | it('should compute and cache address for EVM chain', async () => { + | ^ + 194 | const evmAccount = { + 195 | chain: CHAIN.ETHEREUM_SEPOLIA, + 196 | address: EVM_ADDRESS, + + at src/lib/universal/account/account.spec.ts:193:5 + at src/lib/universal/account/account.spec.ts:151:3 + at Object. (src/lib/universal/account/account.spec.ts:17:1) + + +Test Suites: 1 failed, 1 skipped, 112 passed, 113 of 114 total +Tests: 4 failed, 12 skipped, 1938 passed, 1954 total +Snapshots: 0 total +Time: 92.153 s +Ran all test suites. +Jest did not exit one second after the test run has completed. + +'This usually means that there are asynchronous operations that weren't stopped in your tests. Consider running Jest with `--detectOpenHandles` to troubleshoot this issue. diff --git a/plan/agw/research/svm-internals-2026-10-06/logs/lib-typecheck.log b/plan/agw/research/svm-internals-2026-10-06/logs/lib-typecheck.log new file mode 100644 index 00000000..e69de29b diff --git a/plan/agw/research/svm-internals-2026-10-06/logs/lint.log b/plan/agw/research/svm-internals-2026-10-06/logs/lint.log new file mode 100644 index 00000000..01926690 --- /dev/null +++ b/plan/agw/research/svm-internals-2026-10-06/logs/lint.log @@ -0,0 +1,10 @@ + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__agw-local__/svm-internals.spec.ts + 86:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 119:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 189:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts + 457:21 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +✖ 4 problems (0 errors, 4 warnings) diff --git a/plan/agw/research/svm-internals-2026-10-06/logs/local-typecheck.log b/plan/agw/research/svm-internals-2026-10-06/logs/local-typecheck.log new file mode 100644 index 00000000..e69de29b diff --git a/plan/agw/research/svm-internals-2026-10-06/logs/nx-build-blocked.log b/plan/agw/research/svm-internals-2026-10-06/logs/nx-build-blocked.log new file mode 100644 index 00000000..e2cae97e --- /dev/null +++ b/plan/agw/research/svm-internals-2026-10-06/logs/nx-build-blocked.log @@ -0,0 +1,2 @@ + + NX Failed to start plugin worker. diff --git a/plan/agw/research/svm-internals-2026-10-06/logs/offline-unit.log b/plan/agw/research/svm-internals-2026-10-06/logs/offline-unit.log new file mode 100644 index 00000000..5c4c8c3f --- /dev/null +++ b/plan/agw/research/svm-internals-2026-10-06/logs/offline-unit.log @@ -0,0 +1,155 @@ +PASS core packages/core/src/lib/universal/account/account.spec.ts + ● Console + + console.warn + [PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead. + + 207 | ): Promise { + 208 | if (!_convertOriginToExecutorWarned) { + > 209 | console.warn( + | ^ + 210 | '[PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead.' + 211 | ); + 212 | _convertOriginToExecutorWarned = true; + + at convertOriginToExecutor (src/lib/universal/account/account.ts:209:13) + at Object. (src/lib/universal/account/account.spec.ts:158:51) + +PASS core packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/block-results-client.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-tx-retry.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-confirmation-gate.spec.ts +PASS core packages/core/src/lib/push-client/push-client.archive-fallback.spec.ts +PASS core packages/core/src/lib/utils.spec.ts + ● Console + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:973:17) + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:977:17) + + console.log + 1.23 + + at Object. (src/lib/utils.spec.ts:982:17) + +PASS core packages/core/src/lib/read-state/__tests__/read-executor.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-timeout-clamp.spec.ts +PASS core packages/core/src/lib/universal/signer/signer.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-evm-r3-native-eoa.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/signing-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r2-outbound-revert-flow.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-composition.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/payload-builders.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/registry.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-multichain.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/rescue-svm-confirmation.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-builder-progress-hook.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/send-transaction-progress-hook.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/inbound-tracker-derivation.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/context-helpers-tracker.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gateway-uea-account.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/gate.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-svm-r3.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-svm-rent.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-request-recipient.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/inbound-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-detector.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/web2-compat.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-native-multicall.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/account-status.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/revalidate-read.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/source-hash-resolution.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-tracker.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-calculator.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r1-spec-strings.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-params.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/response-surface.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.dynamic-gas.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/send.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/resolve.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/management.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/execute-standard-required-funds.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/response-invariant.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/chain-namespace.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/build-payload.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/terminal-suppression.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/scenarios.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r2-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/resolver.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r3-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/svm-rent.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/response-builder-push-revert.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/export.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/read-tx-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-event-hook-bridge.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/track-transaction-guard.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/cascade.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/funds-only-burn-guard.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-usd-sizer.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/public-surface.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-emission.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg.spec.ts +PASS core packages/core/src/lib/push-client/push-client.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm-rent-pc20.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/multichain-hooks.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/__tests__/signing.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/svm-account.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/spec-builder.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/reads-context.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-evm.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm-log-index.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-svm.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/result-decoder.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts +PASS core packages/core/src/lib/constants/__tests__/token-constants.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/address-codec.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/normalize.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/abi-selectors.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.chain-symbol.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/child-inbounds.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/auto-detect.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/codec.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/ucallback-codec.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg-svm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/validate.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-events.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-web2.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/registry.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/ix-encoder.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-types.spec.ts +PASS core packages/core/src/lib/constants/__tests__/svm-gateway-idl.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/error-decoder.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/max-pc-for-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/normalize-address.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-execute-order.spec.ts +PASS core packages/core/src/lib/formatters.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/errors.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/tracking.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/classify.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/budget.spec.ts + +Test Suites: 1 skipped, 113 passed, 113 of 114 total +Tests: 16 skipped, 1938 passed, 1954 total +Snapshots: 0 total +Time: 22.857 s, estimated 88 s +Ran all test suites with tests matching "^(?!.*(?:convertOriginToExecutor\(\) - Not Mocked|Solana: should return valid origin data for a UEA address|Ethereum: should return valid origin data for a UEA address|should compute and cache address for EVM chain)).*$". +Jest did not exit one second after the test run has completed. + +'This usually means that there are asynchronous operations that weren't stopped in your tests. Consider running Jest with `--detectOpenHandles` to troubleshoot this issue. diff --git a/plan/agw/research/svm-internals-2026-10-06/logs/spec-typecheck.log b/plan/agw/research/svm-internals-2026-10-06/logs/spec-typecheck.log new file mode 100644 index 00000000..e69de29b diff --git a/plan/agw/research/svm-internals-2026-10-06/logs/svm-unit.log b/plan/agw/research/svm-internals-2026-10-06/logs/svm-unit.log new file mode 100644 index 00000000..c32cabac --- /dev/null +++ b/plan/agw/research/svm-internals-2026-10-06/logs/svm-unit.log @@ -0,0 +1,33 @@ +PASS core packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts + v4 internal SVM wire codec + ✓ round-trips ordered per-token caps and all four data-pin modes (3 ms) + ✓ rejects expired before encoding (4 ms) + ✓ rejects zero CEA before encoding + ✓ rejects empty assets before encoding (1 ms) + ✓ rejects duplicate tokens before encoding + ✓ rejects system program before encoding (1 ms) + ✓ rejects ambiguous prefixes before encoding + ✓ rejects missing pin before encoding + ✓ rejects duplicate pin before encoding + ✓ rejects CEA absent before encoding + ✓ rejects fixed count outside bound before encoding + ✓ refuses misleading integer/raw alignment and zero ratio denominators (1 ms) + wallet-scoped SVM value accounts + ✓ derives the exact PDA from wallet20 and the selected gateway (3 ms) + ✓ includes input/output ATAs, deduplicates, and separates Token-2022 accounts (3 ms) + S12–S18 payload checks + ✓ matches the existing node encoder and parses every byte including writable flags (1 ms) + ✓ rejects trailing data with the corresponding contract error (1 ms) + ✓ rejects truncated with the corresponding contract error + ✓ rejects oversized count with the corresponding contract error + ✓ pins prevent key substitution and protected-account aliasing (1 ms) + ✓ enforces little-endian floors/ceilings, from-end offsets, ratios and exact byte pins (1 ms) + internal SVM outbound action + ✓ uses the program recipient, wallet refund and quoted PC while preserving the exact payload (2 ms) + ✓ rejects caps, zero gas and unknown assets before signing (2 ms) + +Test Suites: 1 passed, 1 total +Tests: 22 passed, 22 total +Snapshots: 0 total +Time: 3.546 s, estimated 6 s +Ran all test suites within paths "packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts". diff --git a/plan/agw/research/svm-internals-2026-10-06/logs/tsc-build.log b/plan/agw/research/svm-internals-2026-10-06/logs/tsc-build.log new file mode 100644 index 00000000..e69de29b diff --git a/plan/agw/research/svm-internals-2026-10-06/network-status.json b/plan/agw/research/svm-internals-2026-10-06/network-status.json new file mode 100644 index 00000000..e2d3ade4 --- /dev/null +++ b/plan/agw/research/svm-internals-2026-10-06/network-status.json @@ -0,0 +1,13 @@ +{ + "checked_at": "2026-10-05T20:56:15.612784+00:00", + "rpc": "https://evm.donut.rpc.push.org/", + "read_only_method": "eth_chainId", + "status": "blocked", + "reason": "DNS resolution failed in restricted-network sandbox", + "env_file_present": "packages/core/.env", + "private_keys_loaded": false, + "funding_authorized": true, + "funding_submitted": false, + "anvil_status": "localhost RPC unavailable", + "alternative_contract_checks": "10 passing in-process Foundry checks" +} diff --git a/plan/agw/research/svm-internals-2026-10-06/run-forge.sh b/plan/agw/research/svm-internals-2026-10-06/run-forge.sh new file mode 100644 index 00000000..5f279bbe --- /dev/null +++ b/plan/agw/research/svm-internals-2026-10-06/run-forge.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +# Offline in-process EVM checks. No network, private keys, signing or broadcast. +set -euo pipefail +HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +SDK_ROOT="$(cd "$HERE/../../../.." && pwd)" +SDK_SVM_BUILD_DIR="${AGW_LOCAL_DIR:-${TMPDIR:-/tmp}/push-agw-local-v4}" +test "$(cat "$SDK_SVM_BUILD_DIR/.agw-pin")" = "e8db74815cfbbf5389593805e464fe8d85f7f735" +cd "$SDK_ROOT" +TS_NODE_PROJECT=packages/core/tsconfig.lib.json node -r ts-node/register/transpile-only "$HERE/generate-vectors.ts" +cp "$HERE/SdkSvmWire.t.sol" "$SDK_SVM_BUILD_DIR/sdk-harness/SdkSvmWire.t.sol" +cp "$HERE/sdk-vectors.json" "$SDK_SVM_BUILD_DIR/sdk-harness/sdk-vectors.json" +python3 - "$SDK_SVM_BUILD_DIR/foundry.toml" <<'PY' +from pathlib import Path +import sys +p = Path(sys.argv[1]); text = p.read_text() +entry = '{ access = "read", path = "sdk-harness/" }' +if entry not in text: + p.write_text(text.replace('fs_permissions = [', 'fs_permissions = [\n ' + entry + ',')) +PY +FOUNDRY_TEST=sdk-harness forge test --root "$SDK_SVM_BUILD_DIR" --offline --match-contract SdkSvmWireTest -vv diff --git a/plan/agw/research/svm-internals-2026-10-06/sdk-vectors.json b/plan/agw/research/svm-internals-2026-10-06/sdk-vectors.json new file mode 100644 index 00000000..626eb649 --- /dev/null +++ b/plan/agw/research/svm-internals-2026-10-06/sdk-vectors.json @@ -0,0 +1,13 @@ +{ + "source": "e8db74815cfbbf5389593805e464fe8d85f7f735", + "note": "Deterministic owner-committed Solana keys; no live PDA/cluster or transport claim.", + "initData": "0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000027736f6c616e613a457457545241425a61597136694d6665594b6f7552753136365655327871613100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000077359400111111111111111111111111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222222222222222222220000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000002386f26fc1000000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000007070ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000002111111111111111111111111111111111111111111111111111111111111111144444444444444444444444444444444444444444444444444444444444444440000000000000000000000000000000000000000000000000000000000000001333333333333333333333333333333333333333333333333333333333333333301000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014444444444444444444444444444444444444444444444444444444444444444000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a", + "datalessInitData": "0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000027736f6c616e613a457457545241425a61597136694d6665594b6f755275313636565532787161310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000077359400111111111111111111111111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222222222222222222220000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000002386f26fc1000000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000007070ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000000000021111111111111111111111111111111111111111111111111111111111111111444444444444444444444444444444444444444444444444444444444444444400000000000000000000000000000000000000000000000000000000000000013333333333333333333333333333333333333333333333333333333333333333010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000144444444444444444444444444444444444444444444444444444444444444440000000000000000000000000000000000000000000000000000000000000000", + "valid": "0x0000000211111111111111111111111111111111111111111111111111111111111111110144444444444444444444444444444444444444444444444444444444444444440100000005015a006400023333333333333333333333333333333333333333333333333333333333333333", + "badRatio": "0x00000002111111111111111111111111111111111111111111111111111111111111111101444444444444444444444444444444444444444444444444444444444444444401000000050159006400023333333333333333333333333333333333333333333333333333333333333333", + "badPin": "0x0000000277777777777777777777777777777777777777777777777777777777777777770144444444444444444444444444444444444444444444444444444444444444440100000005015a006400023333333333333333333333333333333333333333333333333333333333333333", + "alias": "0x0000000311111111111111111111111111111111111111111111111111111111111111110144444444444444444444444444444444444444444444444444444444444444440111111111111111111111111111111111111111111111111111111111111111110100000005015a006400023333333333333333333333333333333333333333333333333333333333333333", + "trailing": "0x0000000211111111111111111111111111111111111111111111111111111111111111110144444444444444444444444444444444444444444444444444444444444444440100000005015a00640002333333333333333333333333333333333333333333333333333333333333333300", + "wrongId": "0x0000000211111111111111111111111111111111111111111111111111111111111111110144444444444444444444444444444444444444444444444444444444444444440100000005015a006400013333333333333333333333333333333333333333333333333333333333333333", + "datalessPayload": "0x0000000211111111111111111111111111111111111111111111111111111111111111110144444444444444444444444444444444444444444444444444444444444444440100000000023333333333333333333333333333333333333333333333333333333333333333" +} diff --git a/plan/agw/research/v4-implementation-2026-10-06/README.md b/plan/agw/research/v4-implementation-2026-10-06/README.md new file mode 100644 index 00000000..d2eaed90 --- /dev/null +++ b/plan/agw/research/v4-implementation-2026-10-06/README.md @@ -0,0 +1,63 @@ +# V4 SDK migration — October 6, 2026 + +> Superseded validation status: [live acceptance report](../live-acceptance-2026-10-06/README.md). Full permissions are restored: public Donut derive, all 53 Anvil cases, unfiltered units, Nx build and four typechecks pass. Bounded testnet funding/broadcasts have started. Earlier restrictions and unrun-live statements below describe the original execution only. + +Branch: `feat/agw-sdk-v4`, based on `b1597b9`. Working changes are uncommitted and not pushed. The pending October 5 comment review and October 6 deployment review were preserved. This implements native and EVM v4 integration; it is not a claim of completed SVM support or funded live acceptance. + +## Implemented + +- **V4 only:** removed the e704d5b adapter, ABI modules, single-asset historical codec and old contract vector file from runtime/test code. Replaced them with e8db748/v4 artifacts and regenerated contract-produced vectors. Earlier review documents remain historical evidence, not runtime dependencies. +- **Donut configuration:** checked factory, URP, implementation, engine/validator and start block are in the registry; CONSTANTS.AGENTIC is populated. Unsupported networks still fail before signing. Custom registrations/manifests must match the v4 source pin. +- **Envelopes:** version 1 for native/EVM; other versions and old two-field data are rejected. Actual v4 contracts reject the old envelope in the new local suite. +- **EVM multi-asset grants:** resolve wallet CEA and ordered token caps, check PRC20 source chain and token identity, reject duplicate resolved assets and preserve token units. Omitted total is maxUint256; explicit zero stays zero. Empty user lists become a single destination gas-token cap at 0/0. +- **Reads and pure helpers:** decode v4 Config/asset arrays, reconstruct origin token addresses and exact beneficiary offsets, retain enabled-only reads without public spent. Native gas PRC20s can report an empty source address; only the on-chain gas-token identity maps that to the native marker. Pure decodeRules resolves known static-registry tokens; unknown mappings fail with a hint to use asynchronous rules.get. Shared PRC20 mapping was extracted without changing its existing behavior. +- **Replacement:** snapshot every old token in stored order and encode assertSpent(expectedSpent[]) before revoke/grant in one owner batch. Native replacement also asserts every action if the old rule has several. Existing race/partial-create/allowance/identity fixes are retained. +- **Execution:** choose the request token from the selected rule's assets, use maxGasPerCall, and consume separately established owner allowance. Updated policy ABI/events/errors and response/replay imports; each outbound still moves one request token. +- **Multiplicity:** management permits multiple same-agent/same-chain grants. An ambiguous send returns AMBIGUOUS_RULE with candidate IDs; no arbitrary first match, automatic permission deletion or speculative selection API. +- **Acceptance preparation:** live EVM setup now grants via public SDK methods. Added opt-in two-token create/read/replacement and call-only outbound scenarios. Built-in Donut manifest supplies defaults; read-only code/wiring/version checks still precede funding. SVM todos only describe the remaining public mapping/cluster acceptance, not absent wire types. + +## Validation + +| Check | Result | +| --- | --- | +| Full core unit suite | 1,919 passed, 0 failed; 12 skipped; 112 suites passed, 1 skipped | +| Actual v4 contracts through SDK on Anvil | 46 passed, 0 failed; 6 suites | +| Explorer ABIs vs isolated e8db748 build | All 5 sets match exactly, including constructors/errors/events/parameter names/internalTypes; ABI array order ignored | +| Typechecks | lib, spec, local harness and AGW E2E files pass | +| SDK build | core:build passes | +| Lint | Same 7 pre-existing errors in unchanged read-example/PC20 files; no new errors | +| Opt-in AGW E2E selection | 25 scenarios, 9 files, 25 distinct tests; consistent | +| Default all E2E selection | Unchanged: 76 scenarios, 40 files, 81 distinct tests | +| Public SDK Donut read-only derive | Unconfirmed in this session: the corrected script could not read a block from the RPC under the current restricted network environment | + +[ABI build comparison](abi-build-comparison.json). Command outputs are under [logs/](logs/). Local tests use actual AGW/factory/engine/validator/URP and real type-4 transactions, with token/core/gateway/executor and destination lookup fixtures. They do not prove Cosmos/TSS, production executor, UEA or destination execution. The local Jest run prints an open-handle warning but exits; Anvil children are stopped. No full contract-security suite/audit is claimed. + +The ten new actual-contract cases cover ordered two-asset grant/read; wrong chain; same-chain wrong token identity; independent counters; hard zero and maxUint256; call-only routing; atomic replacement/five checkpoints; second-token intervening spend rollback; permitted duplicate grants/ambiguous sends; and old-envelope rejection. Reverts are checked by their named errors. + +The original read-only invocation mistakenly imported PUSH_NETWORK from the package root; that enum is accessed through PushChain.CONSTANTS. The corrected saved script reaches its RPC read but cannot complete here. This is separate from the successful earlier block-23931055 deployment probe and is not reported as public-SDK live success. + +## Still pending + +- Harsh H3: exact native omission defaults/public maxValueTotal and token-independence wording. Native defaults remain provisional and unchanged; delivered universal total semantics are implemented. +- Harsh H4.5: public raw-offset authoring versus separate decoded wire records. Native pins/amount and EVM beneficiary offsets are lossless raw data; the latter now has beneficiaryOffset. The SDK never invents ABI argument indexes. +- Harsh H6: send selection when multiple rules match, including native arrays and overlapping permissions. Source/management capacity is implemented; selection remains explicit ambiguity. +- Ref and editable-label v1 scope: absent from deployed contracts; capability gates remain. +- SVM: contract types are delivered, but public SDK mapping/composition/account coverage and cluster acceptance remain gated. Solana-origin agents through UEA are separate from Solana destinations. +- Authorized funded Donut E2Es: none were run. creditRevert still depends on executor integration. Release validation must prove real pull/burn, node/TSS handling, recipient/executor correlation and destination tracking. + +## Reproduction + +From the SDK root: + +```sh +node packages/core/scripts/agw-local/gen-abi.mjs +OUT="${TMPDIR:-/tmp}/push-agw-local-v4" packages/core/scripts/agw-local/prepare.sh +AGW_LOCAL_DIR="${TMPDIR:-/tmp}/push-agw-local-v4" node node_modules/jest/bin/jest.js --config packages/core/jest.agw-local.config.ts --runInBand +node node_modules/jest/bin/jest.js --config packages/core/jest.config.ts --runInBand +node node_modules/typescript/bin/tsc --project packages/core/tsconfig.lib.json --noEmit +node node_modules/typescript/bin/tsc --project packages/core/tsconfig.spec.json --noEmit +node node_modules/typescript/bin/tsc --project packages/core/tsconfig.agw-local.json --noEmit +NX_DAEMON=false node node_modules/nx/bin/nx.js run core:build --skip-nx-cache +``` + +The AGW E2E typecheck uses [tsconfig.agw-e2e.json](tsconfig.agw-e2e.json), extending the core config with AGW E2E includes, Jest/Node types and the existing @e2e/shared alias; no specs are executed. From packages/core, run e2e:verify with --group agw or --group all to check selection without broadcasting. [donut-readonly.ts](donut-readonly.ts) uses a public read-only account and only calls initialize/derive; it contains no transaction submission. diff --git a/plan/agw/research/v4-implementation-2026-10-06/abi-build-comparison.json b/plan/agw/research/v4-implementation-2026-10-06/abi-build-comparison.json new file mode 100644 index 00000000..de4f7e36 --- /dev/null +++ b/plan/agw/research/v4-implementation-2026-10-06/abi-build-comparison.json @@ -0,0 +1,36 @@ +{ + "source": "e8db74815cfbbf5389593805e464fe8d85f7f735", + "comparison": "All ABI entries including constructors/errors/events/inputs/outputs/internalTypes; top-level ABI array ordering ignored.", + "contracts": [ + { + "contract": "wallet", + "explorer_entries": 76, + "built_entries": 76, + "canonical_entry_sets_match": true + }, + { + "contract": "factory", + "explorer_entries": 78, + "built_entries": 78, + "canonical_entry_sets_match": true + }, + { + "contract": "policy", + "explorer_entries": 118, + "built_entries": 118, + "canonical_entry_sets_match": true + }, + { + "contract": "validator", + "explorer_entries": 9, + "built_entries": 9, + "canonical_entry_sets_match": true + }, + { + "contract": "engine", + "explorer_entries": 78, + "built_entries": 78, + "canonical_entry_sets_match": true + } + ] +} diff --git a/plan/agw/research/v4-implementation-2026-10-06/donut-readonly.ts b/plan/agw/research/v4-implementation-2026-10-06/donut-readonly.ts new file mode 100644 index 00000000..d5acec19 --- /dev/null +++ b/plan/agw/research/v4-implementation-2026-10-06/donut-readonly.ts @@ -0,0 +1,23 @@ +/** Read-only public SDK check. No signer key, create(), funding or grant calls. */ +import { PushChain } from '../../../../packages/core/src'; +import { writeFileSync } from 'node:fs'; +import { join } from 'node:path'; + +async function main() { + const { CHAIN, PUSH_NETWORK } = PushChain.CONSTANTS; + const client = await PushChain.initialize({ + address: '0xa89523351BE1e2De64937AA9AF61Ae06eAd199C7', + chain: CHAIN.PUSH_TESTNET_DONUT, + }, { + network: PUSH_NETWORK.TESTNET_DONUT, + rpcUrls: { [CHAIN.PUSH_TESTNET_DONUT]: ['https://evm.donut.rpc.push.org/'] }, + }); + const result = { + checkedAt: new Date().toISOString(), mode: 'read-only', + factory: PushChain.CONSTANTS.AGENTIC[PUSH_NETWORK.TESTNET_DONUT]!.FACTORY, + derived: await client.agentic.derive(), + }; + writeFileSync(join(__dirname, 'donut-sdk-readonly.json'), JSON.stringify(result, null, 2) + '\n'); + process.stdout.write(JSON.stringify(result, null, 2) + '\n'); +} +main().catch(error => { process.stderr.write(error.message + '\n'); process.exitCode = 1; }); diff --git a/plan/agw/research/v4-implementation-2026-10-06/donut-sdk-readonly.json b/plan/agw/research/v4-implementation-2026-10-06/donut-sdk-readonly.json new file mode 100644 index 00000000..2753bd61 --- /dev/null +++ b/plan/agw/research/v4-implementation-2026-10-06/donut-sdk-readonly.json @@ -0,0 +1,10 @@ +{ + "checkedAt": "2026-10-05T20:59:38.387Z", + "mode": "read-only", + "factory": "0xaF88D0FD947afAe7bBb8F34e8417DCfc165e1aaF", + "derived": { + "address": "0x6842327d839C4f429c20c0103Dd6E366f3A5758f", + "index": 0, + "deployed": false + } +} diff --git a/plan/agw/research/v4-implementation-2026-10-06/logs/agw-e2e-typecheck.log b/plan/agw/research/v4-implementation-2026-10-06/logs/agw-e2e-typecheck.log new file mode 100644 index 00000000..e69de29b diff --git a/plan/agw/research/v4-implementation-2026-10-06/logs/build.log b/plan/agw/research/v4-implementation-2026-10-06/logs/build.log new file mode 100644 index 00000000..9af49eec --- /dev/null +++ b/plan/agw/research/v4-implementation-2026-10-06/logs/build.log @@ -0,0 +1,11 @@ + +> nx run core:build + +Compiling TypeScript files for project "core"... +Done compiling TypeScript files for project "core". +(node:24227) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. +(Use `node --trace-warnings ...` to show where the warning was created) + + + + NX Successfully ran target build for project core diff --git a/plan/agw/research/v4-implementation-2026-10-06/logs/donut-readonly-attempt.log b/plan/agw/research/v4-implementation-2026-10-06/logs/donut-readonly-attempt.log new file mode 100644 index 00000000..5dc5cb61 --- /dev/null +++ b/plan/agw/research/v4-implementation-2026-10-06/logs/donut-readonly-attempt.log @@ -0,0 +1 @@ +could not read the current Push block number diff --git a/plan/agw/research/v4-implementation-2026-10-06/logs/e2e-agw-selection.log b/plan/agw/research/v4-implementation-2026-10-06/logs/e2e-agw-selection.log new file mode 100644 index 00000000..16369abf --- /dev/null +++ b/plan/agw/research/v4-implementation-2026-10-06/logs/e2e-agw-selection.log @@ -0,0 +1,28 @@ +✓ agw-create-bare 1 test +✓ agw-create-rules 1 test +✓ agw-funding-pc 1 test +✓ agw-funding-allowance 1 test +✓ agw-native-batch 1 test +✓ agw-native-batch-rollback 1 test +✓ agw-native-agent 1 test +✓ agw-native-owner 1 test +✓ agw-native-over-cap 1 test +✓ agw-native-stranger 1 test +✓ agw-native-revoked 1 test +✓ agw-native-expired 1 test +✓ agw-lifecycle-add 1 test +✓ agw-lifecycle-update 1 test +✓ agw-lifecycle-checkpoints 1 test +✓ agw-lifecycle-revoke-all 1 test +✓ agw-universal-outbound 1 test +✓ agw-v4-multi-asset 1 test +✓ agw-v4-call-only 1 test +✓ agw-universal-dest-revert 1 test +✓ agw-identity-evm 1 test +✓ agw-identity-first-use 1 test +✓ agw-identity-solana 1 test +✓ agw-responses-hooks 1 test +✓ agw-responses-replay 1 test + +25 scenarios, 9 spec files, 25 distinct tests. +Manifest is consistent with the specs. diff --git a/plan/agw/research/v4-implementation-2026-10-06/logs/e2e-default-selection.log b/plan/agw/research/v4-implementation-2026-10-06/logs/e2e-default-selection.log new file mode 100644 index 00000000..dfa5f250 --- /dev/null +++ b/plan/agw/research/v4-implementation-2026-10-06/logs/e2e-default-selection.log @@ -0,0 +1,79 @@ +✓ smoke-uea-derive-evm 1 test +✓ smoke-read-track-lookup 1 test +✓ smoke-cea-derive-evm 1 test +✓ smoke-roundtrip-evm 1 test +✓ smoke-roundtrip-svm 1 test +✓ smoke-cea-pda-svm 1 test +✓ smoke-gasfee-reads 2 tests +✓ smoke-gas-sizer 2 tests +✓ smoke-pc20-registry 2 tests +✓ smoke-pc20-resolve 1 test +✓ evm-r1-transfer 1 test +✓ evm-r1-funds-usdt 1 test +✓ evm-r1-funds-native 1 test +✓ evm-r1-value-funds-data 1 test +✓ evm-r1-bridge-multicall 1 test +✓ evm-r1-fresh-value-native 1 test +✓ evm-r2-funds-erc20 1 test +✓ evm-r2-payload 1 test +✓ evm-r2-multicall 1 test +✓ evm-r2-funds-payload 1 test +✓ evm-r2-native-funds 1 test +✓ evm-r2-native-funds-payload 1 test +✓ evm-r3-funds-erc20 1 test +✓ evm-r3-payload 1 test +✓ evm-r3-multicall 1 test +✓ evm-r3-funds-payload 1 test +✓ evm-r3-native-funds 1 test +✓ evm-r3-eoa-native-funds 1 test +✓ svm-r1-transfer 1 test +✓ svm-r1-funds-sol-self 1 test +✓ svm-r1-value-self 1 test +✓ svm-r1-data-contract 1 test +✓ svm-r1-fresh-key-repro 1 test +✓ svm-r2-funds-sol 1 test +✓ svm-r2-funds-spl 1 test +✓ svm-r2-payload-cpi 1 test +✓ svm-r2-sol-cpi 1 test +✓ svm-r3-drain-sol 1 test +✓ svm-r3-drain-spl 1 test +✓ pc20-export-deployed-wrapper 1 test +✓ pc20-export-predicts-wrapper 1 test +✓ pc20-inbound-burn-unlock 1 test +✓ pc20-r3-cea-burn 1 test +✓ pc20-svm-r1-direct-burn 1 test +✓ pc20-svm-r3-cea-ata-burn 1 test +✓ push-send-transaction 1 test +✓ push-value-own-uea 1 test +✓ push-multicall-no-funds 1 test +✓ push-track-r1-sepolia-parity 1 test +✓ push-track-r3-funds-roundtrip 1 test +✓ push-track-source-leg-hashes 2 tests +✓ xc-multi-child-r3 1 test +✓ xc-fresh-wallet-r3 1 test +✓ xc-peth-bridge-back 1 test +✓ xc-cascade-6hop 1 test +✓ read-evm-balance-eoa 1 test +✓ read-canonical-registry 1 test +✓ read-evm-balance-uea 1 test +✓ read-evm-contract-call 1 test +✓ read-evm-callback-reverts 1 test +✓ read-expiry 1 test +✓ read-svm-lamports 1 test +✓ read-web2-json 1 test +✓ read-docs-example 1 test +✓ read-docs-evm-balance 1 test +✓ read-docs-batch 1 test +✓ read-docs-resume 2 tests +✓ read-app-batch-eoa 1 test +✓ read-app-batch-uea 1 test +✓ read-app-batch-recovery 1 test +✓ read-api-token 1 test +✓ read-api-mixed-outcomes 1 test +✓ read-svm-token-auto 1 test +✓ read-svm-idl 1 test +✓ read-evm-any-mutability 1 test +✓ read-svm-raw 1 test + +76 scenarios, 40 spec files, 81 distinct tests. +Manifest is consistent with the specs. diff --git a/plan/agw/research/v4-implementation-2026-10-06/logs/forge-build.log b/plan/agw/research/v4-implementation-2026-10-06/logs/forge-build.log new file mode 100644 index 00000000..626bb23a --- /dev/null +++ b/plan/agw/research/v4-implementation-2026-10-06/logs/forge-build.log @@ -0,0 +1 @@ +/var/folders/4_/d47r2_4s1wb3x2dvmt2ghp800000gp/T//push-agw-local-v4 diff --git a/plan/agw/research/v4-implementation-2026-10-06/logs/lib-typecheck.log b/plan/agw/research/v4-implementation-2026-10-06/logs/lib-typecheck.log new file mode 100644 index 00000000..e69de29b diff --git a/plan/agw/research/v4-implementation-2026-10-06/logs/lint.log b/plan/agw/research/v4-implementation-2026-10-06/logs/lint.log new file mode 100644 index 00000000..74c49a10 --- /dev/null +++ b/plan/agw/research/v4-implementation-2026-10-06/logs/lint.log @@ -0,0 +1,1194 @@ + +> nx run core:lint + +> eslint . + + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__agw-local__/agw-local-advanced.spec.ts + 73:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 85:17 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 295:22 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 311:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 337:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 426:13 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__agw-local__/agw-local-batch.spec.ts + 44:16 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 90:37 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 91:46 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 98:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 106:16 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__agw-local__/agw-local-races.spec.ts + 54:20 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 99:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 117:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 145:20 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__agw-local__/agw-local.spec.ts + 47:17 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 48:17 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__agw-local__/harness.ts + 210:16 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 229:16 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 238:17 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 373:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__agw-local__/v4-multiasset.spec.ts + 12:10 warning 'createWallet' is defined but never used @typescript-eslint/no-unused-vars + 78:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 92:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 176:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 188:16 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 325:16 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 335:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 353:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__agw-local__/vectors.spec.ts + 56:7 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 57:7 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 98:7 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 207:25 warning '_a' is assigned a value but never used @typescript-eslint/no-unused-vars + 208:25 warning '_b' is assigned a value but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/agw/identity-gas.spec.ts + 62:123 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/agw/universal-evm.spec.ts + 25:10 warning 'v4' is defined but never used @typescript-eslint/no-unused-vars + 39:17 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/agw/v4-multiasset.spec.ts + 17:17 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/cross-chain/cascade-amm.spec.ts + 1715:41 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 1897:41 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 2003:41 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 2096:41 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 2167:41 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 2256:41 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/cross-chain/cea-to-push-erc20.spec.ts + 92:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 95:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 102:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/cross-chain/forced-sizer.spec.ts + 36:17 warning 'PUSH_NETWORK' is defined but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/cross-chain/fresh-wallet.spec.ts + 92:16 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/cross-chain/multi-child-r3-sepolia.spec.ts + 83:7 warning 'VALUE_RECEIVER' is assigned a value but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/cross-chain/peth-bridge.spec.ts + 114:77 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 132:76 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 149:42 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 165:35 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 174:50 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 218:21 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 241:31 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 261:21 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 271:28 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 295:27 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/cross-chain/uoa-multi-hop.spec.ts + 43:7 warning 'SOL_COUNTER_PDA' is assigned a value but never used @typescript-eslint/no-unused-vars + 44:7 warning 'SOL_TARGET' is assigned a value but never used @typescript-eslint/no-unused-vars + 45:7 warning 'SOL_ZERO_ADDRESS' is assigned a value but never used @typescript-eslint/no-unused-vars + 51:7 warning 'bscPublicClient' is assigned a value but never used @typescript-eslint/no-unused-vars + 52:7 warning 'pushPublicClient' is assigned a value but never used @typescript-eslint/no-unused-vars + 68:27 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/docs-examples/07-transaction-scenarios/route1.spec.ts + 357:7 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 357:7 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 360:46 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 364:16 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 389:20 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/docs-examples/07-transaction-scenarios/route2.spec.ts + 297:30 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 386:7 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 389:46 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 412:60 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/docs-examples/07-transaction-scenarios/route3.spec.ts + 375:7 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 375:7 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 378:46 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 384:16 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 404:20 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/docs-examples/08-multichain-transactions/multichain-transactions.spec.ts + 218:30 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 232:25 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 398:25 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 455:25 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 523:30 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 536:25 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/docs-examples/13-read-state/fixtures/universal_read_batch.js + 4:1 error Projects should use relative imports to import from other files within the same project. Use "./path/to/file" instead of import from "@pushchain/core" @nx/enforce-module-boundaries + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/docs-examples/13-read-state/fixtures/universal_read_evm_balance.js + 4:1 error Projects should use relative imports to import from other files within the same project. Use "./path/to/file" instead of import from "@pushchain/core" @nx/enforce-module-boundaries + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/docs-examples/13-read-state/fixtures/universal_read_resume.js + 4:1 error Projects should use relative imports to import from other files within the same project. Use "./path/to/file" instead of import from "@pushchain/core" @nx/enforce-module-boundaries + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/docs-examples/13-read-state/playgrounds.spec.ts + 20:63 error Unexpected empty async function @typescript-eslint/no-empty-function + 69:43 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 74:16 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 102:23 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 104:30 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 115:19 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 116:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-as(node:31858) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. +(Use `node --trace-warnings ...` to show where the warning was created) +sertion + 132:23 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 146:19 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 149:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 174:43 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 180:36 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 184:27 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 184:69 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/docs-examples/13-read-state/read-state.spec.ts + 56:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 56:32 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/docs-examples/_helpers/docs-fund.ts + 95:12 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/evm/inbound/rescue-funds.spec.ts + 165:20 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 227:15 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/evm/outbound/cea-to-smart-contracts.spec.ts + 48:3 warning 'UGPC_PRECOMPILE' is defined but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/evm/outbound/cea-to-uea.spec.ts + 1411:15 warning 'tx' is assigned a value but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/evm/outbound/uea-to-cea.spec.ts + 2277:41 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 2330:43 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/evm/pc20/pc20-inbound.spec.ts + 15:10 warning 'PUSH_NETWORK' is defined but never used @typescript-eslint/no-unused-vars + 21:3 warning 'waitToleratingFeeCreditBug' is defined but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/evm/pc20/pc20-roundtrip.spec.ts + 17:3 warning 'waitToleratingFeeCreditBug' is defined but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/push/account-conversion/eth.spec.ts + 176:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 177:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 181:55 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 181:80 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 192:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 193:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 244:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 245:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 246:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 250:50 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 250:75 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 277:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 278:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 314:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 315:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 320:108 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 350:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 351:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 352:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 355:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 356:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 378:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 379:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 380:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 408:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 409:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 410:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 411:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 415:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 416:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 417:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 420:50 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 420:76 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 420:97 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 442:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 443:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 470:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 471:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 474:73 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 474:99 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/push/account-conversion/solana.spec.ts + 78:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 79:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 81:58 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 81:83 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 92:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 93:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 121:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 122:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 136:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 137:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 138:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 139:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 140:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 160:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 161:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 162:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 183:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 184:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/push/fee-lock-cap-raise.spec.ts + 60:19 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 170:38 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/push/native.spec.ts + 389:7 warning 'mainPushClient' is assigned a value but never used @typescript-eslint/no-unused-vars + 428:16 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 517:16 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/push/pool-depth-diagnostic.spec.ts + 27:24 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/push/progress-hooks.spec.ts + 383:19 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 594:25 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/push/utilities.spec.ts + 128:79 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/read/_shared.ts + 54:70 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/read/evm/any-mutability.spec.ts + 34:48 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/read/evm/api-coverage.spec.ts + 18:48 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 30:48 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 53:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 53:31 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/read/evm/app-batch.spec.ts + 38:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 38:29 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 46:48 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 67:67 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 71:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 71:32 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 76:48 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 81:107 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/read/evm/balance-eoa.spec.ts + 23:57 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 59:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 59:32 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/read/evm/balance-uea.spec.ts + 25:116 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 52:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 52:32 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/read/evm/callback-reverts.spec.ts + 22:48 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 36:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 36:32 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/read/evm/contract-call.spec.ts + 28:48 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/read/evm/registry.spec.ts + 14:57 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 40:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 40:36 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/read/lifecycle/expiry.spec.ts + 25:57 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/read/lifecycle/track-lookup.spec.ts + 21:48 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/read/svm/account-idl.spec.ts + 20:53 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 25:59 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 27:48 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 45:48 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 62:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 62:31 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 63:102 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 70:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 70:52 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 79:44 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/read/svm/lamports.spec.ts + 19:53 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 22:48 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/read/svm/raw-account.spec.ts + 13:48 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/read/tools/live-read-uea.ts + 57:15 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 57:63 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 57:101 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 103:18 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 106:46 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 107:143 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/read/web2/json.spec.ts + 15:48 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/scripts/e2e-7702-multicall.ts + 93:44 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 132:28 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/shared/evm-client.ts + 14:24 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/shared/svm-client.ts + 10:24 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/svm/inbound/uea-to-push.spec.ts + 16:10 warning 'MOVEABLE_TOKENS' is defined but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/svm/outbound/cea-to-eoa.spec.ts + 15:61 warning 'encodeFunctionData' is defined but never used @typescript-eslint/no-unused-vars + 24:3 warning 'COUNTER_ADDRESS_PAYABLE' is defined but never used @typescript-eslint/no-unused-vars + 25:3 warning 'COUNTER_ABI_PAYABLE' is defined but never used @typescript-eslint/no-unused-vars + 27:10 warning 'COUNTER_ABI' is defined but never used @typescript-eslint/no-unused-vars + 37:7 warning 'pushPublicClient' is assigned a value but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/svm/outbound/cea-to-uea.spec.ts + 39:3 warning 'buildReceiveSolAccounts' is defined but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/svm/outbound/eoa-to-cea.spec.ts + 23:3 warning 'SOL_ZERO_ADDRESS' is defined but never used @typescript-eslint/no-unused-vars + 25:3 warning 'COUNTER_PDA' is defined but never used @typescript-eslint/no-unused-vars + 28:3 warning 'buildReceiveSolAccounts' is defined but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/svm/outbound/eoa-to-smart-contracts.spec.ts + 86:19 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/svm/outbound/uea-to-cea.spec.ts + 43:3 warning 'buildReceiveSolAccounts' is defined but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/scripts/poll-outbound.ts + 24:3 warning 'UniversalTxStatus' is defined but never used @typescript-eslint/no-unused-vars + 25:3 warning 'OutboundStatus' is defined but never used @typescript-eslint/no-unused-vars + 236:19 warning 'intervalMs' is assigned a value but never used @typescript-eslint/no-unused-vars + 236:31 warning 'timeoutMs' is assigned a value but never used @typescript-eslint/no-unused-vars + 260:30 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 292:29 warning 'childUtxIds' is assigned a value but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/scripts/probe-multihop-track.ts + 36:40 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 40:12 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 41:12 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 42:12 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 55:37 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/scripts/test-uea-migration.ts + 80:122 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 165:20 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 166:20 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 168:27 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 169:23 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 191:17 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/codec.spec.ts + 373:21 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/management.spec.ts + 12:10 warning 'AgenticCapability' is defined but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts + 2:17 warning 'PUSH_NETWORK' is defined but never used @typescript-eslint/no-unused-vars + 41:21 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/reads-context.spec.ts + 329:5 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/response-surface.spec.ts + 4:3 warning 'getAddress' is defined but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/reads/rules.ts + 11:3 warning 'CAPABILITY_DEPENDENCY' is defined but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/wallet.ts + 92:33 warning '_opts' is defined but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/cache/cache.ts + 4:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 38:21 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 56:27 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/constants/__tests__/svm-gateway-idl.spec.ts + 13:22 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/internal/buffer.ts + 4:18 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/internal/global-buffer-polyfill.ts + 3:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/account-status.spec.ts + 274:15 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 286:15 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/cascade-composition.spec.ts + 363:13 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 431:13 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 447:13 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 480:13 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 552:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 618:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 686:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 758:13 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 774:13 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 811:13 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 887:13 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/context-helpers-tracker.spec.ts + 36:47 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 39:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 167:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/gas-usd-sizer.spec.ts + 26:25 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 32:7 warning 'PC_USD_1E8' is assigned a value but never used @typescript-eslint/no-unused-vars + 35:44 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 41:57 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 65:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 71:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 215:59 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 231:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 243:31 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 252:65 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 281:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 297:31 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/gateway-uea-account.spec.ts + 9:10 warning 'CHAIN_INFO' is defined but never used @typescript-eslint/no-unused-vars + 14:3 warning 'AccountStatus' is defined but never used @typescript-eslint/no-unused-vars + 62:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 68:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 86:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 223:12 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 231:12 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 243:12 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 251:12 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 264:12 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 441:11 warning 'first' is assigned a value but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/payload-builders.spec.ts + 11:44 warning 'MULTICALL_SELECTOR' is defined but never used @typescript-eslint/no-unused-vars + 152:24 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 152:24 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 175:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 176:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 325:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 326:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 365:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 373:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 374:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 516:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 517:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 575:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 576:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 577:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 578:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 599:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 600:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 620:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/preflight.spec.ts + 54:35 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 72:35 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 73:35 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 93:35 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 94:35 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 97:35 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 156:35 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 158:35 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 179:35 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 199:35 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 200:35 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 297:33 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 394:13 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 394:33 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 423:35 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 424:35 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 440:35 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 456:35 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/push-chain-tx-retry.spec.ts + 12:31 warning 'VM' is defined but never used @typescript-eslint/no-unused-vars + 49:85 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 102:72 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 239:64 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 261:72 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/rescue-svm-confirmation.spec.ts + 13:10 warning 'bytesToHex' is defined but never used @typescript-eslint/no-unused-vars + 13:22 warning 'hexToBytes' is defined but never used @typescript-eslint/no-unused-vars + 15:10 warning 'VM' is defined but never used @typescript-eslint/no-unused-vars + 29:33 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 30:26 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 34:43 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 39:32 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 43:7 warning 'mockEvmConfirmations' is assigned a value but never used @typescript-eslint/no-unused-vars + 44:7 warning 'mockSvmConfirmations' is assigned a value but never used @typescript-eslint/no-unused-vars + 148:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 154:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 155:37 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 167:36 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 188:49 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 194:48 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 203:55 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 209:47 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 218:81 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 227:56 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 231:51 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 255:54 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 263:61 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 347:30 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 349:30 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 351:30 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 356:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 357:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 367:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 368:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 375:52 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 435:25 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 566:43 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 612:41 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 702:25 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 705:12 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 706:39 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 751:13 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 751:61 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 765:23 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 794:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 816:25 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 819:12 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 820:39 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 835:25 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 838:12 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 839:39 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 852:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/response-builder-push-revert.spec.ts + 64:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 66:70 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/send-transaction-progress-hook.spec.ts + 79:20 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 199:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/signing-payload.spec.ts + 19:3 warning 'encodeAbiParameters' is defined but never used @typescript-eslint/no-unused-vars + 20:3 warning 'encodePacked' is defined but never used @typescript-eslint/no-unused-vars + 25:31 warning 'VM' is defined but never used @typescript-eslint/no-unused-vars + 144:46 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 148:46 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 157:46 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 161:49 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 232:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 239:51 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 248:48 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 252:54 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 261:78 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 265:83 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 606:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 619:58 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 651:48 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 659:54 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 666:59 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 677:51 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 690:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 711:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 740:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 750:51 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 767:68 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 772:82 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 922:37 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 932:37 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 941:37 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 950:37 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/source-hash-resolution.spec.ts + 24:8 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 34:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 58:70 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 74:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 91:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/terminal-suppression.spec.ts + 26:23 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 27:28 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 28:24 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/track-transaction-guard.spec.ts + 21:27 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 23:21 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 30:40 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 38:69 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 44:64 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/tx-transformer-gas.spec.ts + 10:15 warning 'UniversalTxReceipt' is defined but never used @typescript-eslint/no-unused-vars + 22:32 warning 'PayableToken' is defined but never used @typescript-eslint/no-unused-vars + 22:46 warning 'MoveableToken' is defined but never used @typescript-eslint/no-unused-vars + 28:52 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 44:60 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 65:47 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 110:64 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 115:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 121:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 122:37 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 144:63 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 165:63 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 174:63 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 183:63 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 193:63 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 202:63 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 215:63 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 224:63 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 505:14 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 529:14 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 614:12 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 663:12 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 693:12 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 709:12 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 839:58 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 850:27 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 850:27 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 866:27 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 866:27 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 880:27 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 880:27 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 955:87 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 994:27 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 994:27 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 1015:27 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 1015:27 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 1028:27 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 1028:27 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/tx-transformer-multichain.spec.ts + 10:10 warning 'encodeAbiParameters' is defined but never used @typescript-eslint/no-unused-vars + 15:10 warning 'UEA_MULTICALL_SELECTOR' is defined but never used @typescript-eslint/no-unused-vars + 15:34 warning 'ZERO_ADDRESS' is defined but never used @typescript-eslint/no-unused-vars + 107:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 108:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 128:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 149:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 168:13 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 241:15 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 279:15 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/account-manager.ts + 113:46 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 205:23 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/cascade.ts + 18:22 warning 'UNIVERSAL_GATEWAY_ADDRESSES' is defined but never used @typescript-eslint/no-unused-vars + 123:23 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 136:11 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 180:3 warning 'callbacks' is defined but never used @typescript-eslint/no-unused-vars + 613:27 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 636:15 warning 'gatewayProgramHex' is assigned a value but never used @typescript-eslint/no-unused-vars + 668:11 warning 'amount' is assigned a value but never used @typescript-eslint/no-unused-vars + 741:13 warning 'tokenAddress' is assigned a value but never used @typescript-eslint/no-unused-vars + 746:9 warning 'amount' is assigned a value but never used @typescript-eslint/no-unused-vars + 747:9 warning 'nativeValue' is assigned a value but never used @typescript-eslint/no-unused-vars + 802:11 warning 'chain' is assigned a value but never used @typescript-eslint/no-unused-vars + 1711:29 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 2678:45 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/confirmation.ts + 134:38 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 135:21 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/context.ts + 135:12 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/execute-funds-only.ts + 18:10 warning 'EvmClient' is defined but never used @typescript-eslint/no-unused-vars + 82:8 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 92:5 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 95:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 96:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 123:21 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 123:21 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 124:20 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 124:20 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 137:20 warning 'universalPayload' is assigned a value but never used @typescript-eslint/no-unused-vars + 262:55 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 262:78 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 262:78 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 270:7 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 270:7 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 271:75 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 272:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 272:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 297:77 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 297:77 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 326:69 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 326:69 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 365:11 warning 'nonce' is assigned a value but never used @typescript-eslint/no-unused-vars + 370:7 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 370:7 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 390:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 390:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 391:34 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 391:34 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 419:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 419:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 436:34 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 436:34 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 465:82 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 465:82 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 487:69 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 487:69 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/execute-funds-payload.ts + 77:8 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 88:5 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 91:21 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 105:45 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 210:18 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 236:24 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 237:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 239:69 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 242:23 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 255:13 warning 'tokenAddr' is assigned a value but never used @typescript-eslint/no-unused-vars + 255:25 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 261:13 warning 'payloadBytes' is assigned a value but never used @typescript-eslint/no-unused-vars + 277:62 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 319:77 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 372:69 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/gas-calculator.ts + 596:18 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/helpers.ts + 16:10 warning 'EvmClient' is defined but never used @typescript-eslint/no-unused-vars + 152:53 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 152:59 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 220:12 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/outbound-sync.ts + 131:40 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 132:9 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/payload-builder.ts + 75:43 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/pc20/__tests__/inbound-payload.spec.ts + 107:19 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 107:19 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 116:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 116:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 117:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm.spec.ts + 286:28 error Require statement not part of import statement @typescript-eslint/no-var-requires + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/pc20/tracking.ts + 128:40 error Require statement not part of import statement @typescript-eslint/no-var-requires + 131:28 error Require statement not part of import statement @typescript-eslint/no-var-requires + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/push-chain-tx.ts + 84:19 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 227:25 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 264:28 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 408:19 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 467:20 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 468:20 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 470:27 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 471:23 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 531:20 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 532:20 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 534:27 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 535:23 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 583:39 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/response-builder.ts + 30:10 warning 'PushChain' is defined but never used @typescript-eslint/no-unused-vars + 64:43 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 65:44 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 65:60 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 66:44 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 66:59 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 180:13 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 185:29 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 191:55 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 195:41 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 222:12 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 248:25 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/route-handlers.ts + 1154:21 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 2094:5 warning 'ueaBalance' is assigned a value but never used @typescript-eslint/no-unused-vars + 2404:3 warning 'ctx' is defined but never used @typescript-eslint/no-unused-vars + 2405:3 warning 'params' is defined but never used @typescript-eslint/no-unused-vars + 2406:3 warning 'executeFn' is defined but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/signing.ts + 427:32 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/svm-bridge.ts + 41:77 warning 'req' is assigned a value but never used @typescript-eslint/no-unused-vars + 212:34 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 212:34 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/svm-helpers.ts + 107:37 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 107:53 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 115:21 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 188:11 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/tx-transformer.ts + 97:7 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/orchestrator.spec.ts + 87:50 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 134:50 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 162:28 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 182:28 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/orchestrator.ts + 3:31 warning 'VM' is defined but never used @typescript-eslint/no-unused-vars + 37:76 warning '_transformToUniversalTxResponse' is defined but never used @typescript-eslint/no-unused-vars + 76:41 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 92:48 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 103:50 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 104:74 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 105:77 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/orchestrator.types.ts + 387:15 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 566:9 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/payload-builders.ts + 7:44 warning 'MULTICALL_SELECTOR' is defined but never used @typescript-eslint/no-unused-vars + 14:3 warning 'ChainTarget' is defined but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/route-detector.ts + 17:3 warning 'TransactionRouteType' is defined but never used @typescript-eslint/no-unused-vars + 378:25 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 378:25 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/svm-idl/resolve.spec.ts + 51:55 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 72:55 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 90:55 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/svm-idl/resolve.ts + 10:6 warning 'AccountItem' is defined but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/push-chain/push-chain.explorer.spec.ts + 192:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 199:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/push-chain/push-chain.reinitialize.spec.ts + 198:29 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 199:39 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/push-chain/push-chain.signing.spec.ts + 21:7 warning 'pushChainSVM' is assigned a value but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/push-chain/push-chain.spec.ts + 12:3 warning 'isAddress' is defined but never used @typescript-eslint/no-unused-vars + 13:3 warning 'verifyMessage' is defined but never used @typescript-eslint/no-unused-vars + 452:9 warning 'pushPublicClient' is assigned a value but never used @typescript-eslint/no-unused-vars + 1199:9 warning 'beforeCounterPCBalance' is assigned a value but never used @typescript-eslint/no-unused-vars + 1222:9 warning 'afterCounterPCBalance' is assigned a value but never used @typescript-eslint/no-unused-vars + 1317:9 warning 'balanceBeforePC_UEA' is assigned a value but never used @typescript-eslint/no-unused-vars + 1353:9 warning 'balanceAfterPC_UEA' is assigned a value but never used @typescript-eslint/no-unused-vars + 1434:9 warning 'balanceBeforePC_UEA' is assigned a value but never used @typescript-eslint/no-unused-vars + 1470:9 warning 'balanceAfterPC_UEA' is assigned a value but never used @typescript-eslint/no-unused-vars + 1682:9 warning 'balanceBeforePC_COUNTER' is assigned a value but never used @typescript-eslint/no-unused-vars + 1685:9 warning 'balanceBeforePC_UEA' is assigned a value but never used @typescript-eslint/no-unused-vars + 1717:9 warning 'balanceAfterPC_COUNTER' is assigned a value but never used @typescript-eslint/no-unused-vars + 1720:9 warning 'balanceAfterPC_UEA' is assigned a value but never used @typescript-eslint/no-unused-vars + 1879:35 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 1894:35 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 1910:35 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 1940:9 warning 'pushClientEVM' is assigned a value but never used @typescript-eslint/no-unused-vars + 2145:9 warning 'pcBeforeRecipient' is assigned a value but never used @typescript-eslint/no-unused-vars + 2170:9 warning 'pcAfterRecipient' is assigned a value but never used @typescript-eslint/no-unused-vars + 2487:41 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 2504:41 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 2523:41 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 2533:41 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 2556:41 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 2571:41 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 2592:41 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 2602:41 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 2612:41 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 2649:41 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 3328:18 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 3330:14 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 3537:15 warning 'recipient' is assigned a value but never used @typescript-eslint/no-unused-vars + 3832:13 warning 'WETH9' is assigned a value but never used @typescript-eslint/no-unused-vars + 3863:13 warning 'WETH9' is assigned a value but never used @typescript-eslint/no-unused-vars + 3865:13 warning 'USDC' is assigned a value but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/push-chain/push-chain.ts + 33:3 warning 'UniversalTxResponse' is defined but never used @typescript-eslint/no-unused-vars + 244:31 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/push-client/push-client.archive-fallback.spec.ts + 30:3 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 127:37 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 133:37 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 148:37 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 155:37 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 162:40 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/push-client/push-client.ts + 359:42 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/read-state/__integration__/read-state.integration.spec.ts + 45:38 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 45:38 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 45:77 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 45:77 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 45:117 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 48:68 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 225:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 225:29 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/read-state/__tests__/read-events.spec.ts + 95:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 95:24 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/read-state/__tests__/read-tracker.spec.ts + 26:3 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 104:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 104:29 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 274:5 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 282:5 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 385:20 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/read-state/__tests__/read-types.spec.ts + 30:9 warning 'removed' is assigned a value but never used @typescript-eslint/no-unused-vars + 48:8 warning '_typed' is defined but never used @typescript-eslint/no-unused-vars + 61:9 warning 'missingEntrypoint' is assigned a value but never used @typescript-eslint/no-unused-vars + 63:9 warning 'registryAbi' is assigned a value but never used @typescript-eslint/no-unused-vars + 65:9 warning 'legacy' is assigned a value but never used @typescript-eslint/no-unused-vars + 86:8 warning '_loose' is defined but never used @typescript-eslint/no-unused-vars + 135:6 warning 'ExportChecks' is defined but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/read-state/__tests__/registry.spec.ts + 91:94 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 97:46 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/read-state/__tests__/revalidate-read.spec.ts + 55:62 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/read-state/__tests__/svm-account.spec.ts + 101:25 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 101:25 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 102:23 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 102:23 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 103:27 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 103:27 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 104:25 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 104:25 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/read-state/__tests__/ucallback-codec.spec.ts + 35:15 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 51:23 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 84:17 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 87:23 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 88:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 91:23 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 116:22 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/read-state/read-params.ts + 254:15 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 295:46 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/universal-tx-detector/__tests__/cascade.spec.ts + 319:20 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 322:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 325:22 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 325:22 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 357:22 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/universal-tx-detector/__tests__/detector-svm-log-index.spec.ts + 90:7 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/universal-tx-detector/__tests__/detector.live.spec.ts + 180:25 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 317:29 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 317:29 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 324:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 326:9 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 328:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 329:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 333:27 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 357:33 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 357:33 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/universal-tx-detector/__tests__/normalize.spec.ts + 154:49 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 248:9 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 254:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/universal-tx-detector/cascade.ts + 16:51 warning 'PublicClient' is defined but never used @typescript-eslint/no-unused-vars + 23:3 warning 'deriveChildUniversalTxId' is defined but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/universal-tx-detector/detector-svm.ts + 242:30 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 243:9 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/universal-tx-detector/detector.ts + 88:30 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 89:9 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/universal-tx-detector/svm-events.ts + 30:11 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/universal/account/account.spec.ts + 12:3 warning 'resolveControllerAccount' is defined but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/universal/signer/signer.spec.ts + 38:18 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 68:23 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 82:38 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 136:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 200:49 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 334:7 warning 'domain' is defined but never used @typescript-eslint/no-unused-vars + 335:7 warning 'types' is defined but never used @typescript-eslint/no-unused-vars + 336:7 warning 'primaryType' is defined but never used @typescript-eslint/no-unused-vars + 337:7 warning 'message' is defined but never used @typescript-eslint/no-unused-vars + 339:15 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 340:14 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 342:16 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/universal/signer/signer.ts + 47:16 warning 'type' is assigned a value but never used @typescript-eslint/no-unused-vars + 49:5 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 54:58 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 73:11 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 102:11 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 213:29 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 228:36 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 229:36 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 230:36 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 265:47 warning 'primaryType' is defined but never used @typescript-eslint/no-unused-vars + 268:46 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 422:31 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 516:44 warning 'primaryType' is defined but never used @typescript-eslint/no-unused-vars + 519:44 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 552:44 warning 'primaryType' is defined but never used @typescript-eslint/no-unused-vars + 555:44 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 569:23 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 570:23 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/universal/universal.types.ts + 22:14 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 23:13 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 24:12 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 25:18 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 26:14 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 30:14 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 31:14 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 32:20 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 34:29 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 35:34 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 35:50 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 36:14 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 42:33 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 43:27 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 47:34 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 47:50 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 48:14 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 54:25 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 54:41 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 57:33 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 58:27 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 60:14 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 130:29 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 167:29 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/utils.spec.ts + 172:72 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 419:29 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 425:24 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 436:30 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 487:28 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 571:16 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 648:62 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 652:63 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 657:57 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 663:57 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 669:57 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 878:71 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 882:71 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 893:66 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 898:68 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 904:57 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 910:62 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 1215:54 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 1219:55 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 1223:60 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 1227:53 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 1233:62 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 1239:62 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 1245:67 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 1251:60 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 1554:65 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 1563:35 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/utils.ts + 24:43 warning 'getAddress' is defined but never used @typescript-eslint/no-unused-vars + 292:13 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 295:14 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 326:40 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/vm-client/evm-client.chain-symbol.spec.ts + 64:23 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/vm-client/svm-client.ts + 92:34 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 152:51 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 184:41 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 215:45 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 216:35 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 286:63 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 287:47 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/vm-client/vm-client.types.ts + 29:14 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + 40:10 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any + +✖ 861 problems (7 errors, 854 warnings) + 3 errors and 0 warnings potentially fixable with the `--fix` option. + +Warning: command "eslint ." exited with non-zero status code + + + NX Running target lint for project core failed + +Failed tasks: + +- core:lint + +Hint: run the command with --verbose for more details. diff --git a/plan/agw/research/v4-implementation-2026-10-06/logs/local-contracts.log b/plan/agw/research/v4-implementation-2026-10-06/logs/local-contracts.log new file mode 100644 index 00000000..b134ebd9 --- /dev/null +++ b/plan/agw/research/v4-implementation-2026-10-06/logs/local-contracts.log @@ -0,0 +1,15 @@ +PASS core-agw-local packages/core/__agw-local__/agw-local-advanced.spec.ts (11.607 s) +PASS core-agw-local packages/core/__agw-local__/v4-multiasset.spec.ts (6.052 s) +PASS core-agw-local packages/core/__agw-local__/agw-local.spec.ts (5.515 s) +PASS core-agw-local packages/core/__agw-local__/agw-local-races.spec.ts (5.095 s) +PASS core-agw-local packages/core/__agw-local__/agw-local-batch.spec.ts +PASS core-agw-local packages/core/__agw-local__/vectors.spec.ts + +Test Suites: 6 passed, 6 total +Tests: 46 passed, 46 total +Snapshots: 0 total +Time: 31.661 s, estimated 49 s +Ran all test suites. +Jest did not exit one second after the test run has completed. + +'This usually means that there are asynchronous operations that weren't stopped in your tests. Consider running Jest with `--detectOpenHandles` to troubleshoot this issue. diff --git a/plan/agw/research/v4-implementation-2026-10-06/logs/local-typecheck.log b/plan/agw/research/v4-implementation-2026-10-06/logs/local-typecheck.log new file mode 100644 index 00000000..e69de29b diff --git a/plan/agw/research/v4-implementation-2026-10-06/logs/spec-typecheck.log b/plan/agw/research/v4-implementation-2026-10-06/logs/spec-typecheck.log new file mode 100644 index 00000000..e69de29b diff --git a/plan/agw/research/v4-implementation-2026-10-06/logs/unit-full.log b/plan/agw/research/v4-implementation-2026-10-06/logs/unit-full.log new file mode 100644 index 00000000..6d6f9180 --- /dev/null +++ b/plan/agw/research/v4-implementation-2026-10-06/logs/unit-full.log @@ -0,0 +1,165 @@ +PASS core packages/core/src/lib/agentic/__tests__/management.spec.ts +PASS core packages/core/src/lib/universal/account/account.spec.ts + ● Console + + console.warn + [PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead. + + 207 | ): Promise { + 208 | if (!_convertOriginToExecutorWarned) { + > 209 | console.warn( + | ^ + 210 | '[PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead.' + 211 | ); + 212 | _convertOriginToExecutorWarned = true; + + at Object.convertOriginToExecutor (src/lib/universal/account/account.ts:209:13) + at Object. (src/lib/universal/account/account.spec.ts:80:52) + + console.warn + [PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead. + + 425 | ): Promise { + 426 | if (!options?._internal && !_convertExecutorToOriginWarned) { + > 427 | console.warn( + | ^ + 428 | '[PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead.' + 429 | ); + 430 | _convertExecutorToOriginWarned = true; + + at convertExecutorToOrigin (src/lib/universal/account/account.ts:427:13) + at Object. (src/lib/universal/account/account.spec.ts:106:38) + +PASS core packages/core/src/lib/read-state/__tests__/block-results-client.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-tx-retry.spec.ts +PASS core packages/core/src/lib/utils.spec.ts + ● Console + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:973:17) + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:977:17) + + console.log + 1.23 + + at Object. (src/lib/utils.spec.ts:982:17) + +PASS core packages/core/src/lib/push-client/push-client.archive-fallback.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-confirmation-gate.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-composition.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/signing-payload.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/send.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r2-outbound-revert-flow.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-timeout-clamp.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/inbound-tracker-derivation.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/send-transaction-progress-hook.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-tracker.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/response-surface.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/scenarios.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/build-payload.spec.ts +PASS core packages/core/src/lib/universal/signer/signer.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/execute-standard-required-funds.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-gas.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/registry.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-evm-r3-native-eoa.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/address-codec.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/svm-rent.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-calculator.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/gate.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-builder-progress-hook.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/source-hash-resolution.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/multichain-hooks.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-executor.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-detector.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gateway-uea-account.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/cascade.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/terminal-suppression.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r2-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/rescue-svm-confirmation.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/payload-builders.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/public-surface.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/web2-compat.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-svm-rent.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/context-helpers-tracker.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/reads-context.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/export.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.chain-symbol.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/spec-builder.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-native-multicall.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-multichain.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/resolve.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/chain-namespace.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/response-invariant.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-error-classification.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r3-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/resolver.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/child-inbounds.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/inbound-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-error-classification.spec.ts +PASS core packages/core/src/lib/push-client/push-client.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/svm-account.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-usd-sizer.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/account-status.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/auto-detect.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/read-tx-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/response-builder-push-revert.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-types.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-event-hook-bridge.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-svm-r3.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-emission.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r1-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm-rent-pc20.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/funds-only-burn-guard.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/track-transaction-guard.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-evm.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/normalize.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm-log-index.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/result-decoder.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-request-recipient.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/abi-selectors.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/revalidate-read.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg-svm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-events.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-svm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-params.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-web2.spec.ts +PASS core packages/core/src/lib/constants/__tests__/token-constants.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/validate.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/__tests__/signing.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.dynamic-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/errors.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/classify.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/budget.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/codec.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/ucallback-codec.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/registry.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/ix-encoder.spec.ts +PASS core packages/core/src/lib/constants/__tests__/svm-gateway-idl.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/normalize-address.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/tracking.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/error-decoder.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/max-pc-for-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-execute-order.spec.ts +PASS core packages/core/src/lib/formatters.spec.ts + +Test Suites: 1 skipped, 112 passed, 112 of 113 total +Tests: 12 skipped, 1919 passed, 1931 total +Snapshots: 0 total +Time: 73.069 s +Ran all test suites. diff --git a/plan/agw/research/v4-implementation-2026-10-06/tsconfig.agw-e2e.json b/plan/agw/research/v4-implementation-2026-10-06/tsconfig.agw-e2e.json new file mode 100644 index 00000000..89f04f3f --- /dev/null +++ b/plan/agw/research/v4-implementation-2026-10-06/tsconfig.agw-e2e.json @@ -0,0 +1,23 @@ +{ + "extends": "../../../../packages/core/tsconfig.json", + "compilerOptions": { + "module": "commonjs", + "types": [ + "jest", + "node" + ], + "baseUrl": "../../../..", + "paths": { + "@e2e/shared/*": [ + "packages/core/__e2e__/shared/*" + ] + }, + "typeRoots": [ + "../../../../node_modules/@types" + ] + }, + "include": [ + "../../../../packages/core/__e2e__/agw/**/*.ts" + ], + "references": [] +} diff --git a/plan/agw/sdk-design-review.md b/plan/agw/sdk-design-review.md index 9c4efb46..3069964e 100644 --- a/plan/agw/sdk-design-review.md +++ b/plan/agw/sdk-design-review.md @@ -1,5 +1,9 @@ # AGW SDK design review +> Current implementation: [v4-only native/EVM migration and validation](research/v4-implementation-2026-10-06/README.md) supersede earlier missing-adapter/empty-registry statements below. Legacy runtime/test artifacts are removed. SVM mapping, H3/H4.5/H6, ref/label scope and funded acceptance remain. + +> October 6: [v4 wire definitions and deployment are delivered](research/deployment-review-2026-10-06/README.md). Artifact/deployment absence below describes the earlier baseline. Migrate the adapter/envelope/universal reads/outbound before registry enablement; same-agent multiplicity is supported, send selection is H6, and grant ref/setLabel remain absent. Earlier one-rule uniqueness recommendations are provisional/stale. + > October 4 update: [Harsh’s replies](product-decisions-2026-10-04.md) supersede earlier provisional approval/default/helper/history/compiler recommendations below. Use [remaining dependencies](external-blockers.md) for current blockers. The clear scope changes and sender-preserving native batching are now implemented; H3 defaults remain unchanged pending clarification. See [alignment evidence](research/product-alignment-2026-10-04/README.md). The proposed design adds AGW management and execution to `@pushchain/core` through the API in [page 5](notion/5-sdk-agw.md). It keeps the existing signer and transaction machinery, while introducing a separate wallet execution context. The public API is the agreed target; this review proposes internal boundaries and identifies the evidence needed to implement them correctly. From 7356346dad53cf8031a0e06732050576a1d05d77 Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Tue, 6 Oct 2026 08:58:41 +0530 Subject: [PATCH 21/68] test(agw): cover delayed indexing and add checked integration guide --- packages/core/.eslintrc.json | 1 + packages/core/AGW.md | 270 ++++++++++++++++++ packages/core/README.md | 2 + .../core/__agw-local__/delayed-index.spec.ts | 257 +++++++++++++++++ packages/core/package.json | 2 + packages/core/scripts/check-agw-docs.js | 50 ++++ plan/agw/README.md | 5 +- plan/agw/current-baseline.md | 2 +- plan/agw/external-blockers.md | 8 +- plan/agw/gaps.md | 8 +- plan/agw/implementation-plan.md | 2 +- plan/agw/implementation-review-handoff.md | 2 + plan/agw/implementation-status.md | 10 +- plan/agw/questions-harsh.md | 2 +- .../README.md | 53 ++++ .../logs/agw-consumer-docs.log | 1 + .../logs/agw-delayed-index.log | 17 ++ .../logs/agw-independent-build.log | 11 + .../logs/agw-independent-lint.log | 10 + .../logs/agw-independent-local-tsc.log | 0 .../logs/agw-independent-local.log | 17 ++ .../package-inspection.json | 14 + plan/agw/sdk-design-review.md | 6 +- 23 files changed, 731 insertions(+), 19 deletions(-) create mode 100644 packages/core/AGW.md create mode 100644 packages/core/__agw-local__/delayed-index.spec.ts create mode 100644 packages/core/scripts/check-agw-docs.js create mode 100644 plan/agw/research/sdk-independent-followup-2026-10-06/README.md create mode 100644 plan/agw/research/sdk-independent-followup-2026-10-06/logs/agw-consumer-docs.log create mode 100644 plan/agw/research/sdk-independent-followup-2026-10-06/logs/agw-delayed-index.log create mode 100644 plan/agw/research/sdk-independent-followup-2026-10-06/logs/agw-independent-build.log create mode 100644 plan/agw/research/sdk-independent-followup-2026-10-06/logs/agw-independent-lint.log create mode 100644 plan/agw/research/sdk-independent-followup-2026-10-06/logs/agw-independent-local-tsc.log create mode 100644 plan/agw/research/sdk-independent-followup-2026-10-06/logs/agw-independent-local.log create mode 100644 plan/agw/research/sdk-independent-followup-2026-10-06/package-inspection.json diff --git a/packages/core/.eslintrc.json b/packages/core/.eslintrc.json index 4096b286..2d6444ec 100644 --- a/packages/core/.eslintrc.json +++ b/packages/core/.eslintrc.json @@ -23,6 +23,7 @@ { "ignoredFiles": [ "{projectRoot}/eslint.config.{js,cjs,mjs}", + "{projectRoot}/scripts/check-agw-docs.js", "{projectRoot}/**/*.spec.ts" ], "ignoredDependencies": [ diff --git a/packages/core/AGW.md b/packages/core/AGW.md new file mode 100644 index 00000000..494ce68e --- /dev/null +++ b/packages/core/AGW.md @@ -0,0 +1,270 @@ +# Agentic wallets on Push Chain + +This guide describes AGW v4 in this SDK branch. Donut is the configured deployment. Native Push and EVM destination rules are supported; public Solana destination rules are not enabled yet. Solana-origin signers can already act through their Push UEA. + +An AGW holds assets. Its owner grants or revokes rules and can execute unrestricted owner calls. An agent executes through its own Push identity, and each agent call must pass the granted policy. A Push-native key's identity is its EOA; an external key's identity is its Push UEA for that origin chain. + +```mermaid +flowchart LR + Owner[Owner EOA or UEA] -->|create, grant, update, revoke| Wallet[AGW] + Owner -->|owner execution| Wallet + Agent[Agent EOA or UEA] -->|agent execution| Wallet + Wallet -->|agent calls checked| Policy[Engine and rules policy] + Policy --> Native[Push target] + Policy --> Gateway[Gateway and destination account] +``` + +## Connect a Push-native signer + +Pass a key from your application's key management. The functions below do not load `.env` files or run automatically. They use `viem` and the SDK's public exports. From the SDK checkout, check all TypeScript blocks together with `node packages/core/scripts/check-agw-docs.js` (or `yarn docs:check:agw` from packages/core). + +```ts +import { + PushChain, + AgenticError, + type NativeRule, + type UniversalRule, +} from '@pushchain/core'; +import { + createWalletClient, + http, + parseEther, + encodeFunctionData, + erc20Abi, + type Address, + type Hex, +} from 'viem'; +import { privateKeyToAccount } from 'viem/accounts'; + +type WalletTransaction = Awaited>; + +const NETWORK = PushChain.CONSTANTS.PUSH_NETWORK.TESTNET_DONUT; +const PUSH = PushChain.CONSTANTS.CHAIN.PUSH_TESTNET_DONUT; +const SEPOLIA = PushChain.CONSTANTS.CHAIN.ETHEREUM_SEPOLIA; +const ETH = PushChain.CONSTANTS.MOVEABLE.TOKEN.ETHEREUM_SEPOLIA.ETH; + +async function connectPush(key: Hex, wallet?: Address): Promise { + const walletClient = createWalletClient({ + account: privateKeyToAccount(key), + transport: http('https://evm.donut.rpc.push.org/'), + }); + const signer = await PushChain.utils.signer.toUniversalFromKeypair( + walletClient, + { chain: PUSH, library: PushChain.CONSTANTS.LIBRARY.ETHEREUM_VIEM }, + ); + return PushChain.initialize(signer, { + network: NETWORK, + ...(wallet ? { agenticWallet: wallet } : {}), + }); +} +``` + +`connectPush(ownerKey)` creates an ordinary owner client for management and funding. `connectPush(key, wallet)` sends from that AGW. The SDK determines the owner or agent door from the connected signer; the caller does not select a door. + +## Create a wallet and grant a native rule + +This example permits ten value transfers to one recipient before expiry, with explicit per-call and total limits. Explicit limits avoid relying on native omission defaults that are still being finalized. + +```ts +async function createNativeWallet( + owner: PushChain, + agent: Address, + recipient: Address, +) { + const rule: NativeRule = { + agent, + target: recipient, + selector: 'value-only', + validUntil: Math.floor(Date.now() / 1000) + 3600, + maxValuePerCall: parseEther('0.001'), + maxValueTotal: parseEther('0.01'), + maxCalls: 10, + }; + const prediction = await owner.agentic.derive(); + const created = await owner.agentic.create('native-transfers', { + rules: [rule], + }); + return { prediction, created, rule }; +} +``` + +Create confirms deployment/grant receipts and returns `wallet`, `index`, `rulesIds` and transaction metadata. It does not fund the wallet or agent. A concurrent owner creation can invalidate a predicted index; the index-bound deployment refuses that race instead of granting on another wallet. + +## Fund separately, then send as the agent + +The wallet pays the transfer value. The agent pays Push transaction gas from its own EOA/UEA. Cross-chain sends also need PC in the wallet for the outbound budget. These are separate balances. + +```ts +async function fundAndSendNative( + owner: PushChain, + wallet: Address, + agentKey: Hex, + recipient: Address, +) { + await (await owner.universal.sendTransaction({ + to: wallet, + value: parseEther('0.02'), + })).wait(); + // Fund the agent's Push identity separately if it needs transaction gas. + const agent = await connectPush(agentKey, wallet); + const response = await agent.universal.sendTransaction({ + to: recipient, + value: parseEther('0.001'), + }); + return response.wait(); +} +``` + +For an external signer, grant to its derived Push UEA rather than its origin-chain address. Use `PushChain.utils.account.deriveExecutorAccount` with the signer’s actual origin chain. First-use external UEA gas handling uses that origin; changing the origin chain changes the UEA identity. + +Native agent arrays use an atomic UEA/EIP-7702 transport that preserves the agent sender. Each action is checked individually. An unavailable atomic transport fails explicitly; the SDK does not submit the agent batch sequentially. + +## Read, replace and revoke rules + +A management handle is `owner.agentic.wallet(wallet)`. It reads and writes rules but does not switch the owner's transaction execution identity to the wallet. + +```ts +async function inspectWallet(owner: PushChain, wallet: Address) { + const handle = owner.agentic.wallet(wallet); + const [info, ownerRecord, rules] = await Promise.all([ + handle.info(), handle.owner(), handle.rules.list(), + ]); + return { info, owner: ownerRecord.owner, rules: rules.rules }; +} + +async function replaceNativeRule( + owner: PushChain, + wallet: Address, + rulesId: Hex, + replacement: NativeRule, +) { + return owner.agentic.wallet(wallet).rules.update({ + rules: [{ rulesId, rule: replacement }], + }); +} + +async function revokeRule(owner: PushChain, wallet: Address, rulesId: Hex) { + return (await owner.agentic.wallet(wallet).rules.revoke([rulesId])).wait(); +} +``` + +Replacement asserts the old spend, revokes and grants in one owner transaction. Intervening agent spending makes the whole replacement revert. The new rule gets a new ID and fresh counters. A single replacement records five checkpoints. Failed transactions unwind their checkpoints; agent calls do not tick the owner checkpoint count. + +`rules.list()` returns enabled rules, including enabled rules whose expiry has passed. Expiry is enforced on execution. Revoked-history reconstruction is outside v1. Rule IDs are wallet-scoped; do not treat an ID alone as a globally unique permission. + +## Grant an EVM destination rule + +The destination token identifies an asset on that destination chain. The SDK resolves the mapped PRC20 held by the AGW. Limits use the token's smallest units; `maxGasPerCall` uses PC wei. A rule may list several assets, but each outbound request moves one listed token. + +The example below bridges at most 0.000001 ETH per call and permits a counter's `increment()` call. The explicit zero-value call leaves the bridged ETH in the wallet's CEA. Use a target that actually implements that selector. + +```ts +async function createSepoliaWallet( + owner: PushChain, + agent: Address, + counter: Address, +) { + const rule: UniversalRule = { + agent, + chainNamespace: SEPOLIA, + assets: [{ + token: ETH, + maxPerCall: BigInt(10) ** BigInt(12), + maxTotal: BigInt(10) ** BigInt(13), + }], + maxGasPerCall: parseEther('20'), + validUntil: Math.floor(Date.now() / 1000) + 3600, + allowedCalls: [{ target: counter, selector: 'increment()', maxValue: BigInt(0) }], + }; + return owner.agentic.create('sepolia-counter', { rules: [rule] }); +} +``` + +An omitted universal asset total uses uint256 maximum; explicit zero forbids movement. `assets: []` is a call-only rule, represented internally by a zero-cap destination gas token. The SDK derives `expectedCEA` from the wallet, not the agent. + +## Fund the PRC20 and set a bounded allowance + +The gateway pulls the selected PRC20 from the AGW. Set the allowance through the owner door as a separate, explicit action. Neither owner nor agent outbound sends change allowances automatically. + +```ts +async function prepareSepoliaWallet( + owner: PushChain, + ownerKey: Hex, + wallet: Address, + amount: bigint, +) { + const prc20 = PushChain.utils.tokens.getPRC20Address(ETH, { network: NETWORK }); + // The ordinary owner account must already hold the mapped PRC20. + await (await owner.universal.sendTransaction({ + to: wallet, value: parseEther('21'), + })).wait(); + await (await owner.universal.sendTransaction({ + to: prc20.address, + data: encodeFunctionData({ + abi: erc20Abi, functionName: 'transfer', args: [wallet, amount], + }), + })).wait(); + const ownerDoor = await connectPush(ownerKey, wallet); + const gateway = '0x00000000000000000000000000000000000000C1' as Address; + await (await ownerDoor.universal.sendTransaction({ + to: prc20.address, + data: encodeFunctionData({ + abi: erc20Abi, functionName: 'approve', args: [gateway, amount], + }), + })).wait(); +} + +async function sendToSepolia(agent: PushChain, counter: Address, amount: bigint) { + return agent.universal.sendTransaction({ + to: { address: counter, chain: SEPOLIA }, + data: [{ to: counter, value: BigInt(0), data: '0xd09de08a' }], + funds: { amount, token: ETH }, + }); +} +``` + +The 20/21-PC values are example budgets, not fee estimates. Fees and gas are quoted for the current request. Approval safety is the application's responsibility; the SDK validates structure and contract limits rather than deciding whether a grant is appropriate. + +## Wait, replay and recover + +`from` is the AGW and `origin` is the signer. For EVM outbounds, `to/data/value` describe the first destination call; `agentic.destinationCalls` preserves all destination calls. `agentic.rawTo/rawData` retain the wrapped Push call. + +```ts +async function waitForDelivery(response: WalletTransaction) { + const receipt = await response.wait({ outboundTimeoutMs: 600_000 }); + return { + pushSucceeded: receipt.status === 1, + destinationStatus: receipt.externalStatus, + externalTxHash: receipt.externalTxHash, + }; +} + +async function replay(owner: PushChain, hash: string) { + const response = await owner.universal.trackTransaction(hash); + return response.wait({ outboundTimeoutMs: 600_000 }); +} + +function recoveryDetails(error: unknown) { + if (!(error instanceof AgenticError)) throw error; + return { code: error.code, hint: error.hint, details: error.details }; +} +``` + +A successful Push receipt does not mean destination success. Check `externalStatus`. A timeout can mean the relay is still processing; track the same hash rather than assuming the transaction failed. Reverted Push roots do not start destination polling. Wrapped outbounds are recognized from their calldata even if the indexer initially reports only the Push leg. + +| Result | Application action | +| --- | --- | +| `INDEX_RACE` | This create committed nothing; derive/retry the next slot. | +| `CREATE_PARTIAL` | Inspect `details.walletDeployed`, `grantedRulesIds`, `confirmedHashes` and `pendingHash`. Reconcile unknown/pending outcomes. If deployed, finish missing grants with `rules.add`; do not create a replacement wallet blindly. | +| `NO_RULES_FOR_CHAIN` | Grant a suitable enabled rule before the agent sends. | +| `AMBIGUOUS_RULE` | Inspect candidate IDs in `details.rulesIds`. The SDK does not pick or revoke a rule arbitrarily; the public selection API is still being agreed. | +| `GATEWAY_ALLOWANCE_INSUFFICIENT` | The owner must explicitly establish a sufficient allowance. | +| `CAPABILITY_UNAVAILABLE` / `GENERATION_UNSUPPORTED` | Inspect the capability/deployment details; no compatible operation was submitted. | + +Ordinary returned funds do not lower policy spend. `creditRevert` still needs platform executor support. Revoking rules stops agent authorization but does not remove ERC20 allowances; the owner manages those separately. + +## Current API boundaries + +Grant `ref` and editable `setLabel` are unavailable on this deployed generation. Public Solana destination mapping/dispatch remains gated. Revoked history, public spend records, public generation context and `compileCard` are outside standalone v1. Native omission defaults, raw-offset authoring and multiple-rule send selection remain open; the examples use explicit native limits and one matching rule. + +Use `PushChain.CONSTANTS.READ.CHAIN.WEB2` for Web2 reads. Its value is `web2`; the old literal `web2:https` is still accepted and normalizes to the same wire identity. Literal comparisons against the older spelling need updating. Web2 is a read source, not a transaction destination. diff --git a/packages/core/README.md b/packages/core/README.md index e19eeebe..d5f44027 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -8,6 +8,8 @@ Push Chain is a true universal L1 that is 100% EVM compatible. It allows develop ## Documentation +For AGW v4 in this branch, see the [agentic wallet integration guide](AGW.md) for creation, rules, funding, execution and recovery. + For full documentation, API references, and guides, visit: 👉 [Push Chain Developer Docs](https://push.org/docs) diff --git a/packages/core/__agw-local__/delayed-index.spec.ts b/packages/core/__agw-local__/delayed-index.spec.ts new file mode 100644 index 00000000..ea7c2a28 --- /dev/null +++ b/packages/core/__agw-local__/delayed-index.spec.ts @@ -0,0 +1,257 @@ +/** Real v4 execution/receipts; only origin mapping and Cosmos indexing are fixtures. */ +import { getAddress, parseAbi, type Address, type Hex } from 'viem'; +import { CHAIN, type PushChain } from '../src'; +import * as account from '../src/lib/universal/account/account'; +import type { AgenticRuntime } from '../src/lib/agentic/runtime'; +import type { OrchestratorContext } from '../src/lib/orchestrator/internals/context'; +import { detectRouteFromUniversalTxData } from '../src/lib/orchestrator/internals/tx-transformer'; +import { UniversalTxStatus } from '../src/lib/generated/uexecutor/v1/types'; +import { + OutboundStatus, + UniversalTxV2Codec, + OutboundTxV2Codec, +} from '../src/lib/generated/uexecutor/v2/types'; +import type { ProgressEvent } from '../src/lib/progress-hook/progress-hook.types'; +import { startHarness, type Harness } from './harness'; + +const DEST = getAddress('0x0000000000000000000000000000000000001234'); +const CEA = getAddress('0x000000000000000000000000000000000000cea1'); +const EXTERNAL_HASH = `0x${'ef'.repeat(32)}` as Hex; +const CORE = parseAbi([ + 'function setGasToken(string,address)', + 'function getOutboundTxGasAndFees(address,uint256) view returns (address,uint256,uint256,uint256,string,uint256)', +]); +const runtime = (c: PushChain) => + (c as unknown as { agenticRuntime: AgenticRuntime }).agenticRuntime; +const context = (c: PushChain) => + (c as unknown as { orchestrator: { ctx: OrchestratorContext } }).orchestrator + .ctx; + +describe('AGW replay with delayed Cosmos indexing', () => { + let h: Harness, token: Address; + beforeAll(async () => { + h = await startHarness(18553); + token = await h.deploy(0, 'HarnessPRC20', 'HarnessFixtures.sol', [ + CHAIN.ETHEREUM_SEPOLIA, + 18, + ]); + await h.write(0, h.addresses.universalCore, CORE, 'setGasToken', [ + CHAIN.ETHEREUM_SEPOLIA, + token, + ]); + }); + afterEach(() => jest.restoreAllMocks()); + afterAll(async () => h?.stop()); + + function configure(c: PushChain) { + runtime(c).resolvePrc20 = () => token; + runtime(c).resolveCEA = async () => ({ cea: CEA, isDeployed: false }); + runtime(c).quoteOutbound = async (asset, limit) => { + const [, nativeValueForGas, protocolFee, , , gasLimitUsed] = + await h.publicClient.readContract({ + address: h.addresses.universalCore, + abi: CORE, + functionName: 'getOutboundTxGasAndFees', + args: [asset, limit], + }); + return { nativeValueForGas, protocolFee, gasLimitUsed }; + }; + } + + it.each([ + ['owner', 'success'], + ['agent', 'success'], + ['owner', 'failed'], + ['agent', 'failed'], + ['owner', 'timeout'], + ['agent', 'timeout'], + ] as const)( + '%s door: real Push receipt then delayed external %s', + async (door, outcome) => { + // No UEA factory is present locally. Preserve real EVM RPC and contract + // verification, while isolating the unrelated UEA origin lookup. + jest + .spyOn(account, 'convertExecutorToOrigin') + .mockResolvedValue({ account: null, exists: false }); + const owner = await h.client(0); + configure(owner); + const created = await owner.agentic.create('delayed-index', { + rules: [ + { + agent: h.wallets[1].account!.address, + chainNamespace: CHAIN.ETHEREUM_SEPOLIA, + assets: [], + maxGasPerCall: BigInt(10) ** BigInt(16), + validUntil: Math.floor(Date.now() / 1000) + 3600, + allowedCalls: [{ target: DEST, selector: 'increment()' }], + }, + ], + }); + const wallet = created.wallet; + await h.publicClient.waitForTransactionReceipt({ + hash: await h.wallets[4].sendTransaction({ + to: wallet, + value: BigInt(10) ** BigInt(18), + account: h.wallets[4].account!, + chain: h.wallets[4].chain, + }), + }); + const sender = await h.client(door === 'owner' ? 0 : 1, { + agenticWallet: wallet, + }); + configure(sender); + const sent = await sender.universal.sendTransaction({ + to: { address: DEST, chain: CHAIN.ETHEREUM_SEPOLIA }, + data: [{ to: DEST, value: BigInt(0), data: '0xd09de08a' }], + }); + const root = await h.publicClient.waitForTransactionReceipt({ + hash: sent.hash as Hex, + }); + expect(root.status).toBe('success'); + expect(getAddress(root.from)).toBe( + h.wallets[door === 'owner' ? 0 : 1].account!.address + ); + + const init: ProgressEvent[] = [], + perCall: ProgressEvent[] = []; + const tracker = await h.client(0, { + progressHook: (e) => init.push(e as ProgressEvent), + }); + const ctx = context(tracker); + const partial = UniversalTxV2Codec.fromPartial({ + id: 'delayed-record', + universalStatus: UniversalTxStatus.PC_EXECUTED_SUCCESS, + pcTx: [ + { + txHash: sent.hash, + status: 'SUCCESS', + sender: wallet, + gasUsed: 0, + blockHeight: Number(root.blockNumber), + errorMsg: '', + }, + ], + }); + expect(detectRouteFromUniversalTxData(partial)).toBe('UOA_TO_PUSH'); + let waiting = false, + polls = 0; + const lookup = jest + .spyOn(ctx.pushClient, 'getUniversalTxByIdV2') + .mockImplementation(async () => { + if (!waiting) return { universalTx: partial }; + polls++; + // Missing record, then root-only record, then the destination observation. + if (polls === 1) return { universalTx: undefined }; + if (polls === 2 || outcome === 'timeout') + return { universalTx: partial }; + return { + universalTx: UniversalTxV2Codec.fromPartial({ + ...partial, + universalStatus: UniversalTxStatus.OUTBOUND_PENDING, + outboundTx: [ + OutboundTxV2Codec.fromPartial({ + destinationChain: CHAIN.ETHEREUM_SEPOLIA, + sender: wallet, + recipient: CEA, + amount: '0', + prc20AssetAddr: token, + externalAssetAddr: token, + outboundStatus: + outcome === 'success' + ? OutboundStatus.OBSERVED + : OutboundStatus.REVERTED, + observedTx: { + txHash: EXTERNAL_HASH, + success: outcome === 'success', + errorMsg: + outcome === 'failed' ? 'fixture destination revert' : '', + blockHeight: 1, + gasFeeUsed: '', + pc20WrapperAddress: '', + }, + }), + ], + }), + }; + }); + const cosmos = jest + .spyOn(ctx.pushClient, 'getCosmosTx') + .mockResolvedValue({ + events: [], + height: Number(root.blockNumber), + txIndex: 0, + code: 0, + transactionHash: sent.hash, + msgResponses: [], + gasWanted: BigInt(0), + gasUsed: BigInt(0), + }); + const signerNonces = await Promise.all( + h.wallets + .slice(0, 2) + .map((signer) => + h.publicClient.getTransactionCount({ + address: signer.account!.address, + blockTag: 'pending', + }) + ) + ); + const replay = await tracker.universal.trackTransaction(sent.hash, { + progressHook: (e) => perCall.push(e), + }); + expect(lookup).toHaveBeenCalledTimes(1); + expect(polls).toBe(0); + expect(replay).toMatchObject({ + from: wallet, + origin: sent.origin, + to: DEST, + data: '0xd09de08a', + route: 'UOA_TO_CEA', + chain: CHAIN.ETHEREUM_SEPOLIA, + }); + expect(replay.agentic).toMatchObject({ wallet, door }); + waiting = true; + const receipt = await replay.wait({ + outboundInitialWaitMs: 0, + outboundPollingIntervalMs: 1, + outboundTimeoutMs: outcome === 'timeout' ? 100 : 1000, + }); + expect(receipt).toMatchObject({ + status: 1, + from: wallet, + externalStatus: outcome, + }); + expect(cosmos).toHaveBeenCalledTimes(1); + expect(polls).toBeGreaterThanOrEqual(outcome === 'timeout' ? 1 : 3); + if (outcome !== 'timeout') + expect(receipt.externalTxHash).toBe(EXTERNAL_HASH); + else expect(receipt.externalTxHash).toBeUndefined(); + const terminal = + outcome === 'success' + ? 'SEND-TX-299-01' + : outcome === 'failed' + ? 'SEND-TX-299-02' + : 'SEND-TX-299-03'; + for (const events of [init, perCall]) { + expect(events.filter((event) => event.id === terminal)).toHaveLength(1); + } + expect(perCall.map((e) => e.id)).toEqual(init.map((e) => e.id)); + // wait reuses the mined root; it does not sign or send a replacement. + expect( + await Promise.all( + h.wallets + .slice(0, 2) + .map((signer) => + h.publicClient.getTransactionCount({ + address: signer.account!.address, + blockTag: 'pending', + }) + ) + ) + ).toEqual(signerNonces); + expect( + (await h.publicClient.getTransaction({ hash: sent.hash as Hex })).input + ).toBe(sent.agentic!.rawData); + } + ); +}); diff --git a/packages/core/package.json b/packages/core/package.json index 45bf8bc3..4a861f01 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -51,6 +51,7 @@ }, "scripts": { "build:proto": "scripts/protoc-generate.sh", + "docs:check:agw": "node scripts/check-agw-docs.js", "e2e:list": "ts-node --transpile-only __e2e__/ci/run.ts --list", "e2e:verify": "ts-node --transpile-only __e2e__/ci/run.ts --verify", "e2e:preflight": "ts-node --transpile-only __e2e__/ci/preflight.ts", @@ -67,6 +68,7 @@ "src/**/*.d.ts", "src/**/*.json", "README.md", + "AGW.md", "CHANGELOG.md" ], "devDependencies": { diff --git a/packages/core/scripts/check-agw-docs.js b/packages/core/scripts/check-agw-docs.js new file mode 100644 index 00000000..ec10c4b1 --- /dev/null +++ b/packages/core/scripts/check-agw-docs.js @@ -0,0 +1,50 @@ +/** Typecheck public AGW guide blocks; never evaluate examples or load keys. */ +const fs = require('node:fs'); +const path = require('node:path'); +const ts = require('typescript'); + +const root = path.resolve(__dirname, '../../..'); +const guide = path.join(root, 'packages/core/AGW.md'); +const blocks = [ + ...fs.readFileSync(guide, 'utf8').matchAll(/```ts\n([\s\S]*?)```/g), +].map((m) => m[1]); +if (!blocks.length) throw new Error('No AGW TypeScript examples found'); +const cache = path.join(root, 'node_modules/.cache'); +fs.mkdirSync(cache, { recursive: true }); +const dir = fs.mkdtempSync(path.join(cache, 'agw-docs-')); +try { + const source = path.join(dir, 'examples.ts'); + fs.writeFileSync(source, blocks.join('\n\n')); + const configPath = path.join(root, 'packages/core/tsconfig.lib.json'); + const config = ts.readConfigFile(configPath, ts.sys.readFile); + if (config.error) + throw new Error( + ts.flattenDiagnosticMessageText(config.error.messageText, '\n') + ); + const parsed = ts.parseJsonConfigFileContent( + config.config, + ts.sys, + path.dirname(configPath) + ); + const program = ts.createProgram([source], { + ...parsed.options, + noEmit: true, + }); + const diagnostics = [...parsed.errors, ...ts.getPreEmitDiagnostics(program)]; + if (diagnostics.length) { + process.stderr.write( + ts.formatDiagnostics(diagnostics, { + getCanonicalFileName: (file) => file, + getCurrentDirectory: () => root, + getNewLine: () => '\n', + }) + ); + process.exitCode = 1; + } else { + process.stdout.write( + `AGW guide: ${blocks.length} TypeScript blocks typechecked against public exports; no examples executed.\n` + ); + } +} finally { + fs.rmSync(dir, { recursive: true, force: true }); +} diff --git a/plan/agw/README.md b/plan/agw/README.md index 414e0c33..6d9d24ae 100644 --- a/plan/agw/README.md +++ b/plan/agw/README.md @@ -2,16 +2,19 @@ This package contains the SDK implementation plan, source snapshots, open decisions and validation evidence. Current work is on feat/agw-sdk-v4. Runtime commits are a66ff7d (v4/SVM foundations) and b68bab7 (gas headroom); current validation is linked below. Native/EVM support now uses the checked Donut v4 deployment; old runtime adapters/ABIs/fixtures were removed. All 25 registered AGW scenarios have passing bounded live coverage, including native/UEA identities and Sepolia outbound success/failure. -Latest: [live acceptance and fixes](research/live-acceptance-2026-10-06/README.md), following the [v4 migration](research/v4-implementation-2026-10-06/README.md). The unrestricted full core unit run passes 1,947 tests; the actual-contract harness passes 53. Build and four typechecks pass. Native defaults/raw-offset API/multi-rule selection decisions, absent ref/labels, public SVM integration and release scope remain explicit. +Latest: [live acceptance and fixes](research/live-acceptance-2026-10-06/README.md), following the [v4 migration](research/v4-implementation-2026-10-06/README.md). The unrestricted full core unit run passes 1,947 tests; the actual-contract harness passes 59. Build and four typechecks pass. Native defaults/raw-offset API/multi-rule selection decisions, absent ref/labels, public SVM integration and release scope remain explicit. The public target remains [Notion page 5](notion/5-sdk-agw.md), qualified by [Harsh's replies](product-decisions-2026-10-04.md) and [live comments](research/notion-comments-2026-10-05.md). The [v4 deployment/owner-guide review](research/deployment-review-2026-10-06/README.md) records the supplied deployed wire definitions. Historical adapter-absence statements in that review describe the pre-migration inspection, not current implementation. Latest SVM work: [internal codec/account/payload foundation](research/svm-internals-2026-10-06/README.md) now passes 23 unit and 10 in-process actual-contract checks. Public mapping/dispatch remains gated. Network permissions are restored. All seven SVM Anvil tests now pass and the unfiltered core unit suite passes, including the four previously network-blocked titles. Public Solana execution remains untested. +Latest SDK-owned work: [delayed-index contract acceptance and checked consumer guide](research/sdk-independent-followup-2026-10-06/README.md). No public API decision was changed by this follow-up. + ## Start here | Document | Purpose | | --- | --- | +| [Consumer AGW guide](../../packages/core/AGW.md) | Public SDK examples for creation, funding, rules, execution and recovery | | [Current baseline](current-baseline.md) | Source revisions, capabilities and remaining differences | | [SDK design review](sdk-design-review.md) | Proposed internal architecture and execution flows | | [Gap register](gaps.md) | Current G01–G26 findings and closure criteria | diff --git a/plan/agw/current-baseline.md b/plan/agw/current-baseline.md index 2b6166e2..ff75862c 100644 --- a/plan/agw/current-baseline.md +++ b/plan/agw/current-baseline.md @@ -61,7 +61,7 @@ The ABI comparison found matching factory/wallet/engine function/event/error sig Four checks passed: version-1 envelope round-trip/old first-word incompatibility; synthetic ordered two-asset tuple round-trip; live v4 getConfig decode with old-ABI rejection; array assertion encoding. [Results and limits](research/deployment-review-2026-10-06/wire-checks.json). This is not a rule-grant, stale-spend transaction or funded E2E proof. -The unrestricted run passes 1,947 unit and 53 actual-contract tests. All five explorer ABI sets match the isolated build. Donut is registered and all 25 registered native/EVM/identity cases have passing coverage. [Current acceptance evidence](research/live-acceptance-2026-10-06/README.md). +The unrestricted run passes 1,947 unit and 59 actual-contract tests. All five explorer ABI sets match the isolated build. Donut is registered and all 25 registered native/EVM/identity cases have passing coverage. [Current acceptance evidence](research/live-acceptance-2026-10-06/README.md). ## Remaining decisions and acceptance diff --git a/plan/agw/external-blockers.md b/plan/agw/external-blockers.md index 481eafd0..ce37bb55 100644 --- a/plan/agw/external-blockers.md +++ b/plan/agw/external-blockers.md @@ -36,10 +36,14 @@ All 25 registered AGW live scenarios have passing bounded selected-run coverage, ## Freshness -AGW deployment source e8db748; documentation head deploy-agw@10a24f1, with identical src. Explorer-verified ABIs and a pinned RPC probe are saved in the [review bundle](research/deployment-review-2026-10-06/README.md). No local runtime rebuild or full suite was run in this pass. Core/gateway source pins were not refreshed. +AGW deployment source e8db748; documentation head deploy-agw@10a24f1, with identical src. Explorer-verified ABIs and a pinned RPC probe are saved in the [review bundle](research/deployment-review-2026-10-06/README.md). The native/EVM migration was rebuilt and validated: 1,947 unit tests, 25 distinct registered live scenarios and the expanded actual-contract suite pass. See the current validation report. Core/gateway source pins were not refreshed. Notion's last full export remains October 3, with focused October 4 body and October 5 comment checks. The GitHub guide is a separate deployed-wire source, not a silent replacement for the target public SDK API. ## SVM foundation and current execution environment -[SVM internals](research/svm-internals-2026-10-06/README.md) are implemented and tested offline; public mapping/dispatch remains pending. Shoaib authorized .env-backed funding for tests. The current sandbox blocks Donut DNS and Anvil's localhost RPC, so keys are not loaded and no funds are sent. Networking availability is an execution blocker, not a missing product answer. +[SVM internals](research/svm-internals-2026-10-06/README.md) are implemented and tested, including all seven Anvil cases. Full permissions and RPC access are restored. Authorized bounded Donut tests have completed; networking and test funding are no longer blockers. Public SVM destination mapping/dispatch and live Solana acceptance remain separate work. + +## SDK-owned follow-up completed + +The [independent SDK follow-up](research/sdk-independent-followup-2026-10-06/README.md) closes deliberate delayed-index replay/wait coverage using real local transactions/receipts and controlled indexer responses. The consumer AGW guide and public-export example checker are supplied. Neither change chooses unresolved defaults, raw-offset authoring or a multiple-rule selection API. diff --git a/plan/agw/gaps.md b/plan/agw/gaps.md index 516e8fbe..e0047614 100644 --- a/plan/agw/gaps.md +++ b/plan/agw/gaps.md @@ -2,7 +2,7 @@ Updated October 6, 2026 after the [v4 deployment/owner-guide review](research/deployment-review-2026-10-06/README.md), [Harsh’s replies](product-decisions-2026-10-04.md), v4 implementation on feat/agw-sdk-v4, and [live Notion comments](research/notion-comments-2026-10-05.md). This register distinguishes unresolved dependencies, implemented SDK work, deferred scope and historical corrections. G01–G26 are tracking IDs, not a count of open defects. -Evidence: [current baseline](current-baseline.md), [implementation status](implementation-status.md), [product alignment validation](research/product-alignment-2026-10-04/README.md). The unrestricted v4 SDK run passes 1,947 unit tests and 53 local-contract tests. Bounded live tests cover native management/execution, two-token replacement and call-only Sepolia delivery; remaining acceptance is tracked below. +Evidence: [current baseline](current-baseline.md), [implementation status](implementation-status.md), [product alignment validation](research/product-alignment-2026-10-04/README.md). The unrestricted v4 SDK run passes 1,947 unit tests and 59 local-contract tests. All 25 registered live scenarios have passing coverage. The independent SDK follow-up adds delayed-index actual-contract checks and consumer documentation; public SVM destinations remain gated. Current contract baseline: reported deployed source `e8db748`, documentation head `deploy-agw@10a24f1` (src unchanged between them). Donut v4 addresses/code/wiring and URP 3.1.0 were checked at block 23931055; verified ABIs were saved. The SDK now uses v4 only, registers Donut and has a ported actual-contract harness. [Implementation evidence](research/v4-implementation-2026-10-06/README.md). Core marketplace cb69e0b and gateway bcbf7df remain prior source pins; they were not freshly fetched. Notion bodies were not refreshed in this pass. @@ -40,7 +40,7 @@ P0 blocks agreed authorization/accounting or safe final integration. P1 affects | G13 | P1 | SDK implemented locally; spec wording stale | Core supports native 7702 batching with a sequential fallback. Creation uses actual capability, index-bound deployment and receipt/recovery metadata. | Correct the stale factory-batch requirement in source docs when maintained; Native creation and UEA identity acceptance pass on the verified deployment. | | G14 | P1 | V4 native/EVM update implemented locally | Ordered all-token assertions precede revoke/grant; actual second-token spend races roll back the entire update and checkpoints. Native per-action guards retained. | Native/EVM updates pass live. Public SVM wrapper remains. | | G15 | P2 | SDK implemented locally | create deploys/grants only; funding is separate. No required new createWallet factory method. Index binding prevents grants on a raced wallet; partial recovery preserves operation receipts and unknown state. | Final-generation events/native batching and UEA identities are verified; do not restore removed funding inputs. | -| G16 | P1 | Implemented; migration documentation pending | READ.CHAIN.WEB2 is web2. Legacy web2:https input is normalized to unchanged wire identity. Deprecated aliases now use the new public value. | Document the observable alias/literal-comparison migration and run relevant read acceptance before release. | +| G16 | P1 | Implemented; migration documentation supplied | READ.CHAIN.WEB2 is web2. Legacy web2:https input is normalized to unchanged wire identity. Deprecated aliases now use the new public value. | The consumer guide documents the alias/literal migration; Web2 normalization/read-source tests pass. | | G17 | P1 | SDK decision implemented locally | Read-only write guards and explicit agenticWallet selection on reinitialize are implemented. Signer/network/wallet changes rebuild role/capability context. | Preserve compatibility coverage and verify with the release deployment. | | G18 | P1 | SDK behavior implemented locally; selection under review | Initialization uses enabled-rule identity; sends perform uncached lookup without expiry filtering. Missing/ambiguous candidates fail before signing. Public list is enabled-only; unknown/revoked get returns RULE_NOT_FOUND. The October 5 multiple-rules comment may change selection/cardinality assumptions. | Resolve G26 before treating uniqueness/ambiguous-candidate behavior as final. Verify final-generation and live permission-change cases; public history is deferred. | | G19 | P0/P1 | Universal defaults implemented; H3 native choices open | Universal omission uses maxUint256 and explicit zero is hard zero; empty input gets a gas-token 0/0 route. Native defaults remain provisional. | Clarify H3 native/public fields and token wording; retain UI-owned approval policy. | @@ -54,7 +54,7 @@ P0 blocks agreed authorization/accounting or safe final integration. P1 affects ## Validation and release boundaries -The [current acceptance evidence](research/live-acceptance-2026-10-06/README.md) records 1,947 passing unit tests, 53 actual-contract tests, build/four typechecks and seven existing lint errors. All 25 opt-in AGW scenarios have passing bounded selected-run coverage; default all remains 76. Native/UEA/7702, lifecycle, allowance, responses and Sepolia success/failure pass. The initial positive-amount Push transaction exposed insufficient gas headroom. A tested 20% headroom fix passes the bounded retry, including token debit, allowance reduction, destination receipt/CEA balance and replay checks. Destination-revert classification also passes. +The [current acceptance evidence](research/live-acceptance-2026-10-06/README.md) records 1,947 passing unit tests, 59 actual-contract tests, build/four typechecks and seven existing lint errors. All 25 opt-in AGW scenarios have passing bounded selected-run coverage; default all remains 76. Native/UEA/7702, lifecycle, allowance, responses and Sepolia success/failure pass. The initial positive-amount Push transaction exposed insufficient gas headroom. A tested 20% headroom fix passes the bounded retry, including token debit, allowance reduction, destination receipt/CEA balance and replay checks. Destination-revert classification also passes. Local batch proof uses actual AGW/factory/engine/policy and real Anvil EIP-7702 transactions, with a small fixture executor. UEA shaping/replay is unit-tested and reuses the existing transport; all registered native/EVM/UEA acceptance scenarios now pass. Public Solana destination coverage remains outstanding. @@ -69,4 +69,4 @@ Local batch proof uses actual AGW/factory/engine/policy and real Anvil EIP-7702 - H6 remains a send-selection choice. Same-agent capacity is supplied; uniqueness validation is provisional/stale. Token-independence wording is a product follow-up, not permission to remove policy checks. - Harsh’s replies have been received. The linked question documents now contain remaining follow-ups; no outbound team messages were sent by this agent. -The October 5 historical table is superseded for new integrations by the October 6 v4 completion notice and address book. Contract delivery/code/wiring checks are recorded in the review; Native/EVM migration is complete locally; authorized funded acceptance remains separate. +The October 5 historical table is superseded for new integrations by the October 6 v4 completion notice and address book. Contract delivery/code/wiring checks are recorded in the review; Native/EVM migration and registered funded acceptance pass. Delayed-index local acceptance and consumer documentation are complete; public SVM destination integration remains. diff --git a/plan/agw/implementation-plan.md b/plan/agw/implementation-plan.md index 505f4c87..67915d52 100644 --- a/plan/agw/implementation-plan.md +++ b/plan/agw/implementation-plan.md @@ -1,6 +1,6 @@ # Complete AGW SDK implementation plan -Updated October 6, 2026. The v4-only native/EVM implementation uses deployed source e8db748 and the Donut manifest. Old runtime/test adapters and single-asset codecs are removed. The unfiltered unit suite passes 1,947 tests; all 53 actual-contract Anvil cases pass; build and four typechecks pass. All 25 registered AGW live scenarios pass across selected runs; remaining work is public SVM integration and release scope decisions. [Current acceptance and remaining coverage](research/live-acceptance-2026-10-06/README.md). +Updated October 6, 2026. The v4-only native/EVM implementation uses deployed source e8db748 and the Donut manifest. Old runtime/test adapters and single-asset codecs are removed. The unfiltered unit suite passes 1,947 tests; all 59 actual-contract Anvil cases pass; build and four typechecks pass. All 25 registered AGW live scenarios pass across selected runs; remaining work is public SVM integration and release scope decisions. [Current acceptance and remaining coverage](research/live-acceptance-2026-10-06/README.md). SVM internal terms/accounts/payload/builder are implemented and validated. Public SVM mapping/dispatch remains gated. Remaining decisions are H3 native defaults, H4.5 raw-offset public shape, H6 send selection and ref/label v1 scope. Earlier plan recommendations below are qualified by those accepted decisions and the current implementation status. diff --git a/plan/agw/implementation-review-handoff.md b/plan/agw/implementation-review-handoff.md index 2896a63a..3322cb92 100644 --- a/plan/agw/implementation-review-handoff.md +++ b/plan/agw/implementation-review-handoff.md @@ -1,5 +1,7 @@ # AGW SDK implementation — review handoff +> Latest SDK-owned follow-up: [six delayed-index contract cases, checked consumer examples and package documentation](research/sdk-independent-followup-2026-10-06/README.md). All 59 local actual-contract cases pass; the prior 25 live scenarios remain passing evidence. Public SDK APIs and pending decisions are unchanged by this follow-up. + > Latest acceptance: [October 6 funded tests and fixes](research/live-acceptance-2026-10-06/README.md). Network restrictions are resolved; all 53 Anvil cases and the unfiltered unit suite pass. All 25 registered AGW scenarios have passing selected-run coverage; public SVM destination integration and scope decisions remain. Changes are on feat/agw-sdk-v4. Everything below the current banners describes historical implementation/review evidence. > Current implementation: [v4-only native/EVM migration and validation](research/v4-implementation-2026-10-06/README.md) supersede earlier missing-adapter/empty-registry statements below. Legacy runtime/test artifacts are removed. SVM mapping, H3/H4.5/H6, ref/label scope and funded acceptance remain. diff --git a/plan/agw/implementation-status.md b/plan/agw/implementation-status.md index 2428dd8e..d3dc73c6 100644 --- a/plan/agw/implementation-status.md +++ b/plan/agw/implementation-status.md @@ -1,6 +1,6 @@ # AGW SDK implementation status -> Latest: [funded acceptance and fixes](research/live-acceptance-2026-10-06/README.md). Full permissions are restored: 1,947 unfiltered unit tests, all 53 Anvil cases, build and four typechecks pass. All 25 registered AGW scenarios pass across selected live runs, including UEA identities, native 7702 batches, lifecycle and Sepolia success/failure. Public SVM destinations remain gated. +> Latest: [funded acceptance and fixes](research/live-acceptance-2026-10-06/README.md). Full permissions are restored: 1,947 unfiltered unit tests, all 59 Anvil cases, build and four typechecks pass. All 25 registered AGW scenarios pass across selected live runs, including UEA identities, native 7702 batches, lifecycle and Sepolia success/failure. Public SVM destinations remain gated. Updated October 6, 2026. Branch feat/agw-sdk-v4; runtime commits a66ff7d and b68bab7. The native/EVM migration uses deployed source e8db748. Runtime/test e704d5b adapters, ABIs and fixtures were removed at Shoaib's request; historical review documents are evidence only. [Full handoff, commands and validation](research/v4-implementation-2026-10-06/README.md). @@ -9,7 +9,7 @@ Updated October 6, 2026. Branch feat/agw-sdk-v4; runtime commits a66ff7d and b68 | Level | Current evidence | | --- | --- | | Unit | 1,947 passed, 0 failed; 12 skipped; 113 suites passed, 1 skipped | -| Local actual contracts | 53 passed, 0 failed; 7 suites against e8db748 on Anvil | +| Local actual contracts | 59 passed, 0 failed; 8 suites against e8db748 on Anvil | | ABI reproduction | All 5 explorer ABI entry sets match the isolated build, ignoring array order | | Build/typechecks | Build and lib/spec/local/AGW-E2E typechecks pass | | Lint | 7 pre-existing errors in unchanged files; no new errors | @@ -34,11 +34,11 @@ Local gateway/core/token/executor and CEA lookup are fixtures. Actual AGW/factor | 10 | Native agent sends | Sender-preserving atomic batches retained | H6 selection for multiple matching rules | | 11 | EVM outbound | V4 asset membership, maxGasPerCall, wallet CEA/refunds, signer gas and responses | Release review; Sepolia success/failure and UEA cases verified | | 12 | SVM destinations | Source wire types delivered; SDK capability remains gated | Internal codec/accounts/payload/builder delivered; public mapping/dispatch and cluster acceptance | -| 13 | Responses/progress/errors | V4 ABIs and prior canonical replay/wait fixes retained | Deliberate delayed-indexing acceptance remains unit-tested; funded destination and replay proof pass | +| 13 | Responses/progress/errors | V4 ABIs and prior canonical replay/wait fixes retained | Delayed-index replay/polling tested with real contracts/receipts; no remaining SDK-owned response gap | | 14 | E2E | 25 opt-in scenarios registered; public universal setup and new two-token/call-only cases | Completed native/EVM live coverage; public SVM acceptance after integration | -| 15 | Web2 | Prior implementation retained and included in full unit run | Release documentation/acceptance | +| 15 | Web2 | Prior implementation retained and included in full unit run | Consumer migration notes supplied; existing Web2 unit acceptance passes | | 16 | compileCard | Outside standalone AGW; absent public export | Future marketplace scope | -| 17 | Documentation/release | Current status/gaps/handoff updated | Product scope decisions and funded acceptance | +| 17 | Documentation/release | Current status/gaps/handoff updated | Product scope decisions and public SVM integration/release review | ## Open product/contract choices diff --git a/plan/agw/questions-harsh.md b/plan/agw/questions-harsh.md index ddb2f526..3e504294 100644 --- a/plan/agw/questions-harsh.md +++ b/plan/agw/questions-harsh.md @@ -54,4 +54,4 @@ Lifecycle validation is already aligned with multiple rules. The SDK reports AMB ## Supporting context -Native array implementation is now an SDK validation task: use sender-preserving outer UEA/7702 batching of single executeAsAgent calls, and handle unsupported atomic transports explicitly. Universal/SVM wire definitions and the deployment are supplied; Native/EVM adapter/codec work is implemented and locally validated; SVM mapping and funded acceptance remain. [Zaryab's draft](questions-zaryab.md) now asks only about missing metadata scope and representative SVM integration fixtures. compileCard and revoked history remain outside standalone AGW v1. +Native array implementation is now validated locally and on Donut: use sender-preserving outer UEA/7702 batching of single executeAsAgent calls, and handle unsupported atomic transports explicitly. Universal/SVM wire definitions and the deployment are supplied; Native/EVM adapter/codec work and all 25 registered live scenarios pass; public SVM destination mapping and acceptance remain. [Zaryab's draft](questions-zaryab.md) now asks only about missing metadata scope and representative SVM integration fixtures. compileCard and revoked history remain outside standalone AGW v1. diff --git a/plan/agw/research/sdk-independent-followup-2026-10-06/README.md b/plan/agw/research/sdk-independent-followup-2026-10-06/README.md new file mode 100644 index 00000000..ccde172f --- /dev/null +++ b/plan/agw/research/sdk-independent-followup-2026-10-06/README.md @@ -0,0 +1,53 @@ +# SDK-owned follow-up — October 6, 2026 + +This follow-up completes work that does not require new product or contract decisions. It changes tests, developer documentation and package metadata, not public SDK method signatures, exported types or transaction behavior. + +## Completed + +1. **Delayed-index replay/wait acceptance.** Six cases run real AGW/factory/engine/validator/URP transactions and obtain actual Anvil EVM receipts. Public `trackTransaction` first sees a root-only universal record that core identifies as Push-only. The AGW adapter restores the outbound route from verified wallet calldata. Public `wait()` then runs the actual indexer poller across missing/root-only records into destination success, destination failure or timeout, on both owner and agent doors. Wallet/signer identity stays correct, terminal hooks fire once to each callback, both actors' pending nonces stay unchanged, and Cosmos sub-ID extraction is cached. This closes the prior mock-poller-only coverage limit. +2. **Consumer guide with checked examples.** [packages/core/AGW.md](../../../../packages/core/AGW.md) covers owner/agent identity, native rules, independent funding, lifecycle, EVM token caps, explicit bounded gateway allowance, receipts/replay/partial-create recovery and current scope. Seven TypeScript blocks are checked together against public exports without evaluation. The examples use explicit native limits and one matching rule. They do not choose H3/H4.5/H6 behavior. Existing transaction return types are inferred; no new root type export was added for the documentation. +3. **Documentation packaging and status cleanup.** The guide is linked from the package README and included in the npm files list. `docs:check:agw` invokes its checker from the SDK checkout. The checker uses the root workspace's TypeScript compiler as developer tooling; only this unshipped script is excluded from Nx's runtime-dependency check, keeping compiler dependencies out of the published SDK. Stale network-blocked, unfinished-native-batch and unrun-funded statements were removed from active blocker/question/design documents. Web2 alias/literal migration notes are supplied. + +## Validation + +| Check | Result | +| --- | --- | +| Full actual-contract local suite | 59 passed in 8 suites (previous 53 plus 6 delayed-index cases) | +| Focused suite after strengthening the no-resubmission nonce check | 6 passed | +| Guide examples | 7 TypeScript blocks typecheck using public exports; not executed | +| Local harness typecheck | Pass | +| Changed-file lint | 0 errors; 6 conventional non-null assertion warnings in tests | +| Core build | Pass | +| npm dry-run | [Guide included in proposed package contents](package-inspection.json); no publication | +| Prior production unit evidence | 1,947 passed, 12 existing skips; production source unchanged by this follow-up | +| Prior live acceptance | All 25 registered AGW scenarios have passing coverage; no new live scenario/funding is needed for this follow-up | + +Logs are in [logs/](logs/). Log trailing whitespace and EOF blank lines are normalized. The six new cases control origin lookup and indexer responses; gateway/core/token/destination lookup remain local fixtures. The destination hashes/outcomes are fixture observations, not live TSS or destination receipts. Existing [live acceptance](../live-acceptance-2026-10-06/README.md) remains the production gateway/UEA/Sepolia evidence. No `.env` keys were loaded, no funded transactions were submitted and no contract checkout was changed by this follow-up. + +## API impact + +**This follow-up:** no public SDK API or default/authorization behavior changes. The package gains a guide and a developer command; tests gain deterministic delayed-index coverage. + +**Earlier AGW work:** the target agentic namespace and agenticWallet initialization remain; v4 enables the specified EVM assets[] model and native arrays. AGW responses add wallet/signature-origin metadata. Raw native offsets and EVM beneficiaryOffset remain the previously introduced public type extensions awaiting H4.5. Multiple matches return AMBIGUOUS_RULE; no caller selection parameter was added. Web2 public constants use web2 while the old web2:https literal remains accepted. Spend/history/generation helpers and compileCard follow Harsh's accepted removals/deferrals. These are not new decisions in this follow-up. + +## Remaining work + +- H3 native defaults/public maxValueTotal and token wording. +- H4.5 public raw-offset authoring/read shape. +- H6 selecting among multiple matching rules, including arrays. +- Ref/editable-label v1 delivery or deferral. +- Public Solana destination mapping, registry/IDL integration, dispatch/tracking and live acceptance. +- Platform executor support for creditRevert; refunds currently do not restore policy spend. + +None of these choices is silently settled by the new guide or tests. Standalone history/compiler scope stays deferred. + +## Reproduce + +```sh +node packages/core/scripts/check-agw-docs.js +AGW_LOCAL_DIR="${TMPDIR:-/tmp}/push-agw-local-v4" node node_modules/jest/bin/jest.js --config packages/core/jest.agw-local.config.ts --runInBand +node node_modules/typescript/bin/tsc --project packages/core/tsconfig.agw-local.json --noEmit +NX_DAEMON=false node node_modules/nx/bin/nx.js run core:build --skip-nx-cache +``` + +The package inspection uses npm pack --dry-run --json --ignore-scripts from dist/packages/core after the build. It is a local content inspection, not an npm publish. diff --git a/plan/agw/research/sdk-independent-followup-2026-10-06/logs/agw-consumer-docs.log b/plan/agw/research/sdk-independent-followup-2026-10-06/logs/agw-consumer-docs.log new file mode 100644 index 00000000..5996134d --- /dev/null +++ b/plan/agw/research/sdk-independent-followup-2026-10-06/logs/agw-consumer-docs.log @@ -0,0 +1 @@ +AGW guide: 7 TypeScript blocks typechecked against public exports; no examples executed. diff --git a/plan/agw/research/sdk-independent-followup-2026-10-06/logs/agw-delayed-index.log b/plan/agw/research/sdk-independent-followup-2026-10-06/logs/agw-delayed-index.log new file mode 100644 index 00000000..faeca34b --- /dev/null +++ b/plan/agw/research/sdk-independent-followup-2026-10-06/logs/agw-delayed-index.log @@ -0,0 +1,17 @@ +PASS core-agw-local packages/core/__agw-local__/delayed-index.spec.ts + AGW replay with delayed Cosmos indexing + ✓ owner door: real Push receipt then delayed external success (48 ms) + ✓ agent door: real Push receipt then delayed external success (43 ms) + ✓ owner door: real Push receipt then delayed external failed (36 ms) + ✓ agent door: real Push receipt then delayed external failed (38 ms) + ✓ owner door: real Push receipt then delayed external timeout (130 ms) + ✓ agent door: real Push receipt then delayed external timeout (137 ms) + +Test Suites: 1 passed, 1 total +Tests: 6 passed, 6 total +Snapshots: 0 total +Time: 3.644 s +Ran all test suites within paths "packages/core/__agw-local__/delayed-index.spec.ts". +Jest did not exit one second after the test run has completed. + +'This usually means that there are asynchronous operations that weren't stopped in your tests. Consider running Jest with `--detectOpenHandles` to troubleshoot this issue. diff --git a/plan/agw/research/sdk-independent-followup-2026-10-06/logs/agw-independent-build.log b/plan/agw/research/sdk-independent-followup-2026-10-06/logs/agw-independent-build.log new file mode 100644 index 00000000..15743dd0 --- /dev/null +++ b/plan/agw/research/sdk-independent-followup-2026-10-06/logs/agw-independent-build.log @@ -0,0 +1,11 @@ + +> nx run core:build + +Compiling TypeScript files for project "core"... +Done compiling TypeScript files for project "core". +(node:29017) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. +(Use `node --trace-warnings ...` to show where the warning was created) + + + + NX Successfully ran target build for project core diff --git a/plan/agw/research/sdk-independent-followup-2026-10-06/logs/agw-independent-lint.log b/plan/agw/research/sdk-independent-followup-2026-10-06/logs/agw-independent-lint.log new file mode 100644 index 00000000..ad88f953 --- /dev/null +++ b/plan/agw/research/sdk-independent-followup-2026-10-06/logs/agw-independent-lint.log @@ -0,0 +1,10 @@ + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__agw-local__/delayed-index.spec.ts + 81:20 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 95:20 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 112:9 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 194:24 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 246:26 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 254:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +✖ 6 problems (0 errors, 6 warnings) diff --git a/plan/agw/research/sdk-independent-followup-2026-10-06/logs/agw-independent-local-tsc.log b/plan/agw/research/sdk-independent-followup-2026-10-06/logs/agw-independent-local-tsc.log new file mode 100644 index 00000000..e69de29b diff --git a/plan/agw/research/sdk-independent-followup-2026-10-06/logs/agw-independent-local.log b/plan/agw/research/sdk-independent-followup-2026-10-06/logs/agw-independent-local.log new file mode 100644 index 00000000..3c8f8b91 --- /dev/null +++ b/plan/agw/research/sdk-independent-followup-2026-10-06/logs/agw-independent-local.log @@ -0,0 +1,17 @@ +PASS core-agw-local packages/core/__agw-local__/svm-internals.spec.ts (5.324 s) +PASS core-agw-local packages/core/__agw-local__/v4-multiasset.spec.ts +PASS core-agw-local packages/core/__agw-local__/delayed-index.spec.ts +PASS core-agw-local packages/core/__agw-local__/agw-local-advanced.spec.ts +PASS core-agw-local packages/core/__agw-local__/agw-local.spec.ts +PASS core-agw-local packages/core/__agw-local__/agw-local-races.spec.ts +PASS core-agw-local packages/core/__agw-local__/agw-local-batch.spec.ts +PASS core-agw-local packages/core/__agw-local__/vectors.spec.ts + +Test Suites: 8 passed, 8 total +Tests: 59 passed, 59 total +Snapshots: 0 total +Time: 19.139 s, estimated 33 s +Ran all test suites. +Jest did not exit one second after the test run has completed. + +'This usually means that there are asynchronous operations that weren't stopped in your tests. Consider running Jest with `--detectOpenHandles` to troubleshoot this issue. diff --git a/plan/agw/research/sdk-independent-followup-2026-10-06/package-inspection.json b/plan/agw/research/sdk-independent-followup-2026-10-06/package-inspection.json new file mode 100644 index 00000000..972eb9ca --- /dev/null +++ b/plan/agw/research/sdk-independent-followup-2026-10-06/package-inspection.json @@ -0,0 +1,14 @@ +{ + "name": "@pushchain/core", + "version": "6.0.26", + "entryCount": 390, + "guideIncluded": true, + "guide": { + "path": "AGW.md", + "size": 12631, + "mode": 420 + }, + "dryRun": true, + "ignoreScripts": true, + "published": false +} diff --git a/plan/agw/sdk-design-review.md b/plan/agw/sdk-design-review.md index 3069964e..3b417a54 100644 --- a/plan/agw/sdk-design-review.md +++ b/plan/agw/sdk-design-review.md @@ -1,14 +1,12 @@ # AGW SDK design review -> Current implementation: [v4-only native/EVM migration and validation](research/v4-implementation-2026-10-06/README.md) supersede earlier missing-adapter/empty-registry statements below. Legacy runtime/test artifacts are removed. SVM mapping, H3/H4.5/H6, ref/label scope and funded acceptance remain. - -> October 6: [v4 wire definitions and deployment are delivered](research/deployment-review-2026-10-06/README.md). Artifact/deployment absence below describes the earlier baseline. Migrate the adapter/envelope/universal reads/outbound before registry enablement; same-agent multiplicity is supported, send selection is H6, and grant ref/setLabel remain absent. Earlier one-rule uniqueness recommendations are provisional/stale. +Current implementation: v4-only native/EVM support is implemented and all 25 registered live scenarios have passing coverage. Old runtime/test adapters are removed. [Latest independent SDK follow-up](research/sdk-independent-followup-2026-10-06/README.md) adds actual-contract delayed-index replay/wait tests and the consumer guide. Remaining decisions are H3/H4.5/H6, ref/label scope and public SVM destination integration. Older architecture recommendations below are historical where they conflict with these accepted changes. > October 4 update: [Harsh’s replies](product-decisions-2026-10-04.md) supersede earlier provisional approval/default/helper/history/compiler recommendations below. Use [remaining dependencies](external-blockers.md) for current blockers. The clear scope changes and sender-preserving native batching are now implemented; H3 defaults remain unchanged pending clarification. See [alignment evidence](research/product-alignment-2026-10-04/README.md). The proposed design adds AGW management and execution to `@pushchain/core` through the API in [page 5](notion/5-sdk-agw.md). It keeps the existing signer and transaction machinery, while introducing a separate wallet execution context. The public API is the agreed target; this review proposes internal boundaries and identifies the evidence needed to implement them correctly. -Review status: proposed architecture, pending [gap resolutions](gaps.md) and matching multi-asset artifacts/deployment. This document does not claim that the new contract methods are deployed. +Review status: the native/EVM architecture is implemented against checked deployed v4 contracts. [Current gaps](gaps.md) identify remaining scope/API decisions and public SVM work. The detailed proposals below retain their original review context. ## Core design From 4d2c4d2891b6f068ad8605feb1fda29fce47a1c3 Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Tue, 6 Oct 2026 10:05:16 +0530 Subject: [PATCH 22/68] feat(agw): complete internal SVM backend and unfunded verification --- .github/workflows/agw-sdk-validation.yml | 45 + .gitignore | 2 + packages/core/.eslintrc.json | 2 + packages/core/__agw-local__/harness.ts | 43 +- packages/core/__agw-local__/setup.ts | 18 + .../core/__agw-local__/svm-backend.spec.ts | 389 +++++ packages/core/jest.agw-local.config.ts | 1 + packages/core/package.json | 3 + .../agw-local/contracts/HarnessFixtures.sol | 7 + packages/core/scripts/agw-verify.js | 74 + packages/core/scripts/check-agw-api.js | 185 +++ packages/core/scripts/check-agw-package.js | 74 + .../lib/agentic/__tests__/svm-backend.spec.ts | 323 ++++ .../lib/agentic/execution/svm-instruction.ts | 59 + .../src/lib/agentic/execution/svm-send.ts | 177 +++ .../src/lib/agentic/management/svm-context.ts | 136 ++ .../lib/agentic/management/svm-metadata.ts | 75 + .../core/src/lib/agentic/management/svm.ts | 254 +++ packages/core/src/lib/agentic/reads/svm.ts | 98 ++ .../outbound-svm-confirmation.spec.ts | 127 ++ .../orchestrator/internals/outbound-sync.ts | 69 +- .../src/lib/orchestrator/svm-idl/resolve.ts | 16 +- plan/agw/README.md | 4 +- plan/agw/current-baseline.md | 2 +- plan/agw/external-blockers.md | 2 + plan/agw/gaps.md | 6 +- plan/agw/implementation-plan.md | 2 +- plan/agw/implementation-review-handoff.md | 2 + plan/agw/implementation-status.md | 12 +- .../README.md | 56 + .../api-comparison.json | 1360 +++++++++++++++++ .../logs/build.log | 13 + .../logs/changed-lint.log | 75 + .../logs/docs.log | 1 + .../logs/focused-svm-unit.log | 8 + .../logs/full-unit.log | 168 ++ .../logs/local-contracts.log | 15 + .../logs/package.log | 1 + .../logs/prepare-contracts.log | 1 + .../logs/public-api.log | 1 + .../logs/types-agw-local.log | 0 .../logs/types-lib.log | 0 .../logs/types-spec.log | 0 .../logs/units.log | 23 + .../logs/verification.log | 11 + 45 files changed, 3906 insertions(+), 34 deletions(-) create mode 100644 .github/workflows/agw-sdk-validation.yml create mode 100644 packages/core/__agw-local__/setup.ts create mode 100644 packages/core/__agw-local__/svm-backend.spec.ts create mode 100644 packages/core/scripts/agw-verify.js create mode 100644 packages/core/scripts/check-agw-api.js create mode 100644 packages/core/scripts/check-agw-package.js create mode 100644 packages/core/src/lib/agentic/__tests__/svm-backend.spec.ts create mode 100644 packages/core/src/lib/agentic/execution/svm-instruction.ts create mode 100644 packages/core/src/lib/agentic/execution/svm-send.ts create mode 100644 packages/core/src/lib/agentic/management/svm-context.ts create mode 100644 packages/core/src/lib/agentic/management/svm-metadata.ts create mode 100644 packages/core/src/lib/agentic/management/svm.ts create mode 100644 packages/core/src/lib/agentic/reads/svm.ts create mode 100644 packages/core/src/lib/orchestrator/__tests__/outbound-svm-confirmation.spec.ts create mode 100644 plan/agw/research/sdk-independent-completion-2026-10-06/README.md create mode 100644 plan/agw/research/sdk-independent-completion-2026-10-06/api-comparison.json create mode 100644 plan/agw/research/sdk-independent-completion-2026-10-06/logs/build.log create mode 100644 plan/agw/research/sdk-independent-completion-2026-10-06/logs/changed-lint.log create mode 100644 plan/agw/research/sdk-independent-completion-2026-10-06/logs/docs.log create mode 100644 plan/agw/research/sdk-independent-completion-2026-10-06/logs/focused-svm-unit.log create mode 100644 plan/agw/research/sdk-independent-completion-2026-10-06/logs/full-unit.log create mode 100644 plan/agw/research/sdk-independent-completion-2026-10-06/logs/local-contracts.log create mode 100644 plan/agw/research/sdk-independent-completion-2026-10-06/logs/package.log create mode 100644 plan/agw/research/sdk-independent-completion-2026-10-06/logs/prepare-contracts.log create mode 100644 plan/agw/research/sdk-independent-completion-2026-10-06/logs/public-api.log create mode 100644 plan/agw/research/sdk-independent-completion-2026-10-06/logs/types-agw-local.log create mode 100644 plan/agw/research/sdk-independent-completion-2026-10-06/logs/types-lib.log create mode 100644 plan/agw/research/sdk-independent-completion-2026-10-06/logs/types-spec.log create mode 100644 plan/agw/research/sdk-independent-completion-2026-10-06/logs/units.log create mode 100644 plan/agw/research/sdk-independent-completion-2026-10-06/logs/verification.log diff --git a/.github/workflows/agw-sdk-validation.yml b/.github/workflows/agw-sdk-validation.yml new file mode 100644 index 00000000..f9a8850b --- /dev/null +++ b/.github/workflows/agw-sdk-validation.yml @@ -0,0 +1,45 @@ +name: AGW SDK validation (unfunded) +on: + pull_request: + paths: ['packages/core/**', 'tsconfig.base.json', 'yarn.lock', '.github/workflows/agw-sdk-validation.yml'] + workflow_dispatch: +permissions: + contents: read +concurrency: + group: agw-validation-${{ github.ref }} + cancel-in-progress: true +jobs: + validate: + runs-on: ubuntu-latest + timeout-minutes: 30 + env: + NX_DAEMON: 'false' + AGW_REPO: ${{ github.workspace }}/.ci-contracts + AGW_LOCAL_DIR: ${{ runner.temp }}/agw-v4-build + steps: + - uses: actions/checkout@v5 + with: + persist-credentials: false + - uses: actions/checkout@v5 + with: + repository: pushchain/push-agentic-wallets + ref: e8db74815cfbbf5389593805e464fe8d85f7f735 + path: .ci-contracts + persist-credentials: false + - uses: actions/setup-node@v6 + with: + node-version: '24.18.0' + package-manager-cache: false + - uses: foundry-rs/foundry-toolchain@v1 + with: + version: v1.5.1 + - run: corepack enable + - run: yarn install --immutable + - name: Unit, contracts, types, docs and package checks + run: node packages/core/scripts/agw-verify.js + - uses: actions/upload-artifact@v4 + if: always() + with: + name: agw-unfunded-validation + path: .agw-validation/ + if-no-files-found: ignore diff --git a/.gitignore b/.gitignore index 20499081..c3a31375 100644 --- a/.gitignore +++ b/.gitignore @@ -59,3 +59,5 @@ e2e-logs/ /packages/core/outbound-test-logs /packages/core/__e2e__/graphify-out /graphify-out +.agw-validation/ +.ci-contracts/ diff --git a/packages/core/.eslintrc.json b/packages/core/.eslintrc.json index 2d6444ec..cc65fded 100644 --- a/packages/core/.eslintrc.json +++ b/packages/core/.eslintrc.json @@ -24,6 +24,8 @@ "ignoredFiles": [ "{projectRoot}/eslint.config.{js,cjs,mjs}", "{projectRoot}/scripts/check-agw-docs.js", + "{projectRoot}/scripts/check-agw-package.js", + "{projectRoot}/scripts/check-agw-api.js", "{projectRoot}/**/*.spec.ts" ], "ignoredDependencies": [ diff --git a/packages/core/__agw-local__/harness.ts b/packages/core/__agw-local__/harness.ts index 93c898ff..a34e199f 100644 --- a/packages/core/__agw-local__/harness.ts +++ b/packages/core/__agw-local__/harness.ts @@ -172,11 +172,34 @@ export async function startHarness(port = 18545): Promise { try { return await deployHarness(dir, rpcUrl, anvil); } catch (err) { - anvil.kill('SIGTERM'); + await stopAnvil(anvil); throw err; } } +/** Wait for the child to release its port; never leave cleanup to Jest exit. */ +async function stopAnvil(child: ChildProcess): Promise { + if (child.exitCode !== null || child.signalCode !== null) return; + await new Promise((resolve, reject) => { + const killTimer = setTimeout(() => child.kill('SIGKILL'), 2000); + const deadline = setTimeout(() => { + cleanup(); + reject(new Error('Anvil did not exit after SIGTERM/SIGKILL')); + }, 5000); + const cleanup = () => { + clearTimeout(killTimer); + clearTimeout(deadline); + child.off('exit', exited); + }; + const exited = () => { + cleanup(); + resolve(); + }; + child.once('exit', exited); + child.kill('SIGTERM'); + }); +} + async function deployHarness( dir: string, rpcUrl: string, @@ -195,6 +218,7 @@ async function deployHarness( transport: http(rpcUrl), }) ); + const clients = new Set(); const deploy = async ( walletIndex: number, @@ -354,8 +378,8 @@ async function deployHarness( const client = async ( walletIndex: number, opts: { agenticWallet?: Address; progressHook?: (e: unknown) => void } = {} - ) => - PushChain.initialize(await signerFor(walletIndex), { + ) => { + const c = await PushChain.initialize(await signerFor(walletIndex), { network: PUSH_NETWORK.LOCALNET, rpcUrls: { [CHAIN.PUSH_LOCALNET]: [rpcUrl] }, ...(opts.agenticWallet ? { agenticWallet: opts.agenticWallet } : {}), @@ -363,12 +387,15 @@ async function deployHarness( ? { progressHook: opts.progressHook as never } : {}), }); + clients.add(c); + return c; + }; const readOnlyClient = async ( walletIndex: number, opts: { agenticWallet?: Address } = {} - ) => - PushChain.initialize( + ) => { + const c = await PushChain.initialize( { address: wallets[walletIndex].account!.address, chain: CHAIN.PUSH_LOCALNET, @@ -379,6 +406,9 @@ async function deployHarness( ...(opts.agenticWallet ? { agenticWallet: opts.agenticWallet } : {}), } ); + clients.add(c); + return c; + }; return { rpcUrl, @@ -402,8 +432,9 @@ async function deployHarness( readOnlyClient, dir, stop: async () => { + await Promise.allSettled([...clients].map((c) => c.accountStatusReady)); resetAgenticGenerations(); - anvil.kill('SIGTERM'); + await stopAnvil(anvil); }, }; } diff --git a/packages/core/__agw-local__/setup.ts b/packages/core/__agw-local__/setup.ts new file mode 100644 index 00000000..c35a8fc5 --- /dev/null +++ b/packages/core/__agw-local__/setup.ts @@ -0,0 +1,18 @@ +/** Actual RPC/actions with a local poll interval, not mocked transactions. */ +jest.mock('viem', () => { + const actual = jest.requireActual('viem'); + return { + ...actual, + // viem 2.27 poll() leaves an already-scheduled wait alive after unwatch. + // Its production 4s default needlessly delays local Jest shutdown. Keep + // real receipt/replacement logic, and configure short local polling. + createPublicClient: (options: { + pollingInterval?: number; + [key: string]: unknown; + }) => + actual.createPublicClient({ + ...options, + pollingInterval: options?.pollingInterval ?? 25, + }), + }; +}); diff --git a/packages/core/__agw-local__/svm-backend.spec.ts b/packages/core/__agw-local__/svm-backend.spec.ts new file mode 100644 index 00000000..a965d909 --- /dev/null +++ b/packages/core/__agw-local__/svm-backend.spec.ts @@ -0,0 +1,389 @@ +/** Internal SVM lifecycle/execution on actual v4 contracts; no Solana/TSS simulation. */ +import { PublicKey } from '@solana/web3.js'; +import { encodeFunctionData, parseAbi, type Address, type Hex } from 'viem'; +import { CHAIN, type PushChain } from '../src'; +import type { AgenticRuntime } from '../src/lib/agentic/runtime'; +import { Snapshot } from '../src/lib/agentic/reads/snapshot'; +import { readSvmRule } from '../src/lib/agentic/reads/svm'; +import { + grantSvmWire, + prepareSvmReplacement, + replaceSvmWire, + type SvmWireGrant, +} from '../src/lib/agentic/management/svm'; +import { + resolveSvmContext, + type SvmMetadataProvider, +} from '../src/lib/agentic/management/svm-context'; +import { + prepareSvmAgentExecution, + sendSvmAgentWire, +} from '../src/lib/agentic/execution/svm-send'; +import { + registerIdl, + clearRegistry, +} from '../src/lib/orchestrator/svm-idl/registry'; +import { v4 } from '../src/lib/agentic/contracts/v4'; +import { wrapSendError } from '../src/lib/agentic/management/common'; +import { startHarness, type Harness } from './harness'; + +const key = (b: string) => `0x${b.repeat(32)}` as Hex; +const GATEWAY = key('22'), + PROGRAM = key('33'), + MINT = key('44'), + MINT2 = key('55'); +const SPL = 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', + TOKEN2022 = 'TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb'; +const TOKEN = parseAbi([ + 'function mint(address,uint256)', + 'function approve(address,uint256) returns (bool)', + 'function setSourceTokenAddress(string)', + 'function setSourceChainNamespace(string)', +]); +const CORE = parseAbi([ + 'function setGasToken(string,address)', + 'function getOutboundTxGasAndFees(address,uint256) view returns (address,uint256,uint256,uint256,string,uint256)', +]); +const rt = (c: PushChain) => + (c as unknown as { agenticRuntime: AgenticRuntime }).agenticRuntime; +const metadata: SvmMetadataProvider = { + gateway: async (chain) => ({ chainNamespace: chain, program: GATEWAY }), + mint: async (_chain, address) => ({ + mint: address, + tokenProgram: address === MINT2 ? TOKEN2022 : SPL, + }), +}; + +describe('internal prepared SVM backend on v4', () => { + let h: Harness, owner: PushChain, tokens: Address[]; + beforeAll(async () => { + h = await startHarness(18554); + owner = await h.client(0); + tokens = []; + for (const source of ['', MINT, MINT2]) { + const token = await h.deploy(0, 'HarnessPRC20', 'HarnessFixtures.sol', [ + CHAIN.SOLANA_DEVNET, + 9, + ]); + await h.write(0, token, TOKEN, 'setSourceTokenAddress', [source]); + tokens.push(token); + } + await h.write(0, h.addresses.universalCore, CORE, 'setGasToken', [ + CHAIN.SOLANA_DEVNET, + tokens[0], + ]); + }); + afterEach(() => { + jest.restoreAllMocks(); + clearRegistry(); + }); + afterAll(async () => h?.stop()); + const cfg = async (wallet: Address, id: Hex) => + readSvmRule( + await Snapshot.at(rt(owner).reader), + h.generation, + wallet, + id, + rt(owner).pushChainNamespace + ); + function configure(runtime: AgenticRuntime) { + runtime.quoteOutbound = async (token, limit) => { + const [, nativeValueForGas, protocolFee, , , gasLimitUsed] = + await h.publicClient.readContract({ + address: h.addresses.universalCore, + abi: CORE, + functionName: 'getOutboundTxGasAndFees', + args: [token, limit], + }); + return { nativeValueForGas, protocolFee, gasLimitUsed }; + }; + } + async function setup() { + const { wallet } = await owner.agentic.create('svm-backend', { rules: [] }); + const caps = tokens.map((token) => ({ + token, + maxPerCall: BigInt(5), + maxTotal: BigInt(10), + })); + const resolved = await resolveSvmContext( + await Snapshot.at(rt(owner).reader), + wallet, + CHAIN.SOLANA_DEVNET, + caps, + metadata + ); + const terms = { + ...resolved, + validUntil: Math.floor(Date.now() / 1000) + 3600, + maxGasPerCall: BigInt(10) ** BigInt(16), + programs: [ + { + program: PROGRAM, + discriminator: '0x0102030405060708' as Hex, + discriminatorLen: 8, + dataless: false, + maxAccounts: 3, + }, + ], + pins: resolved.ceaAccounts.map((expected, accountIndex) => ({ + ruleIndex: 0, + accountIndex, + expected, + })), + dataPins: [], + }; + const input: SvmWireGrant = { + agent: h.wallets[1].account!.address, + chainNamespace: CHAIN.SOLANA_DEVNET, + terms, + }; + const grant = await grantSvmWire(rt(owner), h.generation, wallet, input); + registerIdl({ + address: new PublicKey(Buffer.from(PROGRAM.slice(2), 'hex')).toBase58(), + metadata: { name: 'fixture', version: '1', spec: '0.1.0' }, + instructions: [ + { + name: 'go', + discriminator: [1, 2, 3, 4, 5, 6, 7, 8], + accounts: [ + { name: 'cea_authority', writable: true }, + ...resolved.ceaAccounts.slice(1).map((k, i) => ({ + name: `ata${i}`, + writable: true, + address: new PublicKey(Buffer.from(k.slice(2), 'hex')).toBase58(), + })), + ], + args: [], + }, + ], + }); + await h.publicClient.waitForTransactionReceipt({ + hash: await h.wallets[4].sendTransaction({ + to: wallet, + value: BigInt(10) ** BigInt(18), + account: h.wallets[4].account!, + chain: h.wallets[4].chain, + }), + }); + for (const token of tokens) { + await h.write(0, token, TOKEN, 'mint', [wallet, BigInt(100)]); + await h.write(0, wallet, v4.abis.wallet, 'execute', [ + key('00'), + v4.packSingle({ + target: token, + value: BigInt(0), + data: encodeFunctionData({ + abi: TOKEN, + functionName: 'approve', + args: [h.addresses.gateway, BigInt(100)], + }), + }), + ]); + } + const agent = await h.client(1); + configure(rt(agent)); + const request = (token = tokens[2], amount = BigInt(5)) => ({ + wallet, + rulesId: grant.rulesId, + token, + amount, + gasLimit: BigInt(200_000), + program: PROGRAM, + instructionData: new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]), + }); + return { wallet, id: grant.rulesId, input, agent, request }; + } + it('reads all source assets/counters/pins losslessly while public SVM remains gated', async () => { + const s = await setup(), + stored = await cfg(s.wallet, s.id); + expect(stored.config.assets.map((a) => a.token)).toEqual(tokens); + expect(stored.config.assets.map((a) => a.spent)).toEqual([ + BigInt(0), + BigInt(0), + BigInt(0), + ]); + expect(stored.config.pins).toEqual(s.input.terms.pins); + expect(stored.chainNamespace).toBe(CHAIN.SOLANA_DEVNET); + await expect( + owner.agentic.wallet(s.wallet).rules.get(s.id) + ).rejects.toMatchObject({ code: 'CAPABILITY_UNAVAILABLE' }); + }); + it('runs context, IDL, quote, allowance, wrapping and real token pull/burn as the agent', async () => { + const s = await setup(); + const sent = await sendSvmAgentWire( + rt(s.agent), + h.generation, + s.request(), + metadata + ); + expect((await sent.tx.wait()).status).toBe(1); + const root = await h.publicClient.getTransactionReceipt({ + hash: sent.tx.hash as Hex, + }); + expect(root.from).toBe(h.wallets[1].account!.address.toLowerCase()); + expect( + (await cfg(s.wallet, s.id)).config.assets.map((a) => a.spent) + ).toEqual([BigInt(0), BigInt(0), BigInt(5)]); + }); + it('refuses the wrong signer before execute', async () => { + const s = await setup(), + execute = jest.spyOn(rt(owner), 'execute'); + await expect( + prepareSvmAgentExecution(rt(owner), h.generation, s.request(), metadata) + ).rejects.toMatchObject({ code: 'NOT_OWNER_OR_AGENT' }); + expect(execute).not.toHaveBeenCalled(); + }); + it('requires separate allowance and never writes an approval on the agent path', async () => { + const s = await setup(); + await h.write(0, s.wallet, v4.abis.wallet, 'execute', [ + key('00'), + v4.packSingle({ + target: tokens[2], + value: BigInt(0), + data: encodeFunctionData({ + abi: TOKEN, + functionName: 'approve', + args: [h.addresses.gateway, BigInt(0)], + }), + }), + ]); + const execute = jest.spyOn(rt(s.agent), 'execute'); + await expect( + sendSvmAgentWire(rt(s.agent), h.generation, s.request(), metadata) + ).rejects.toMatchObject({ code: 'GATEWAY_ALLOWANCE_INSUFFICIENT' }); + expect(execute).not.toHaveBeenCalled(); + }); + it('atomically replaces and resets every asset, recording five checkpoints', async () => { + const s = await setup(); + await ( + await sendSvmAgentWire(rt(s.agent), h.generation, s.request(), metadata) + ).tx.wait(); + const before = await h.publicClient.readContract({ + address: s.wallet, + abi: v4.abis.wallet, + functionName: 'checkpointCount', + }); + const next = await replaceSvmWire( + rt(owner), + h.generation, + s.wallet, + s.id, + s.input + ); + expect( + (await cfg(s.wallet, next.rulesId)).config.assets.map((a) => a.spent) + ).toEqual([BigInt(0), BigInt(0), BigInt(0)]); + await expect(cfg(s.wallet, s.id)).rejects.toMatchObject({ + code: 'RULE_NOT_FOUND', + }); + expect( + await h.publicClient.readContract({ + address: s.wallet, + abi: v4.abis.wallet, + functionName: 'checkpointCount', + }) + ).toBe(before + BigInt(5)); + }); + it('a second-asset spend after snapshot rolls back revoke/grant/checkpoints', async () => { + const s = await setup(), + prepared = await prepareSvmReplacement( + rt(owner), + h.generation, + s.wallet, + s.id, + s.input + ); + await ( + await sendSvmAgentWire( + rt(s.agent), + h.generation, + s.request(tokens[1]), + metadata + ) + ).tx.wait(); + const before = await h.publicClient.readContract({ + address: s.wallet, + abi: v4.abis.wallet, + functionName: 'checkpointCount', + }); + const error = await rt(owner) + .execute({ to: s.wallet, value: BigInt(0), data: prepared.data }) + .catch(wrapSendError); + expect(error).toMatchObject({ + decodedError: { name: 'AssetSpentMismatch' }, + }); + expect((await cfg(s.wallet, s.id)).config.assets[1].spent).toBe(BigInt(5)); + expect( + await h.publicClient.readContract({ + address: s.wallet, + abi: v4.abis.wallet, + functionName: 'checkpointCount', + }) + ).toBe(before); + }); + it('grant initialization failure after revoke rolls back the old rule', async () => { + const s = await setup(); + const alternate = await h.deploy(0, 'HarnessPRC20', 'HarnessFixtures.sol', [ + CHAIN.SOLANA_DEVNET, + 9, + ]); + const input = { + ...s.input, + terms: { + ...s.input.terms, + assets: [ + { token: alternate, maxPerCall: BigInt(5), maxTotal: BigInt(10) }, + ], + }, + }; + const prepared = await prepareSvmReplacement( + rt(owner), + h.generation, + s.wallet, + s.id, + input + ); + await h.write(0, alternate, TOKEN, 'setSourceChainNamespace', [ + CHAIN.ETHEREUM_SEPOLIA, + ]); + const error = await rt(owner) + .execute({ to: s.wallet, value: BigInt(0), data: prepared.data }) + .catch(wrapSendError); + expect(error).toMatchObject({ decodedError: { name: 'ChainMismatch' } }); + expect((await cfg(s.wallet, s.id)).config.assets).toHaveLength(3); + }); + it('generic owner revocation disables a SVM rule without public decoding', async () => { + const s = await setup(); + await (await owner.agentic.wallet(s.wallet).rules.revoke([s.id])).wait(); + await expect(cfg(s.wallet, s.id)).rejects.toMatchObject({ + code: 'RULE_NOT_FOUND', + }); + }); + it('returns the receipt ID when another owner grant advances the nonce during replacement', async () => { + const s = await setup(), + execute = rt(owner).execute; + let intercepted = false; + rt(owner).execute = async (params, opts) => { + if (!intercepted) { + intercepted = true; + await grantSvmWire(rt(owner), h.generation, s.wallet, s.input); + } + return execute(params, opts); + }; + try { + const next = await replaceSvmWire( + rt(owner), + h.generation, + s.wallet, + s.id, + s.input + ); + expect((await cfg(s.wallet, next.rulesId)).config.assets).toHaveLength(3); + await expect(cfg(s.wallet, s.id)).rejects.toMatchObject({ + code: 'RULE_NOT_FOUND', + }); + } finally { + rt(owner).execute = execute; + } + }); +}); diff --git a/packages/core/jest.agw-local.config.ts b/packages/core/jest.agw-local.config.ts index fb2a6321..8d332245 100644 --- a/packages/core/jest.agw-local.config.ts +++ b/packages/core/jest.agw-local.config.ts @@ -10,6 +10,7 @@ export default { displayName: 'core-agw-local', preset: '../../jest.preset.js', testEnvironment: 'node', + setupFilesAfterEnv: ['/__agw-local__/setup.ts'], transform: { '^.+\\.[tj]s$': [ 'ts-jest', diff --git a/packages/core/package.json b/packages/core/package.json index 4a861f01..a1920f4b 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -52,6 +52,9 @@ "scripts": { "build:proto": "scripts/protoc-generate.sh", "docs:check:agw": "node scripts/check-agw-docs.js", + "agw:verify": "node scripts/agw-verify.js", + "agw:check:package": "node scripts/check-agw-package.js", + "agw:check:api": "node scripts/check-agw-api.js", "e2e:list": "ts-node --transpile-only __e2e__/ci/run.ts --list", "e2e:verify": "ts-node --transpile-only __e2e__/ci/run.ts --verify", "e2e:preflight": "ts-node --transpile-only __e2e__/ci/preflight.ts", diff --git a/packages/core/scripts/agw-local/contracts/HarnessFixtures.sol b/packages/core/scripts/agw-local/contracts/HarnessFixtures.sol index e349cb18..9f509350 100644 --- a/packages/core/scripts/agw-local/contracts/HarnessFixtures.sol +++ b/packages/core/scripts/agw-local/contracts/HarnessFixtures.sol @@ -10,7 +10,14 @@ pragma solidity 0.8.26; /// SOURCE_CHAIN_NAMESPACE view URP interrogates at universal grant. contract HarnessPRC20 { string public SOURCE_CHAIN_NAMESPACE; + string private _sourceOverride; + bool private _hasSourceOverride; + function setSourceChainNamespace(string calldata chain) external { SOURCE_CHAIN_NAMESPACE = chain; } + function setSourceTokenAddress(string calldata source) external { + _sourceOverride = source; _hasSourceOverride = true; + } function SOURCE_TOKEN_ADDRESS() external view returns (string memory) { + if (_hasSourceOverride) return _sourceOverride; bytes memory chars = "0123456789abcdef"; bytes memory out = new bytes(42); out[0] = "0"; out[1] = "x"; uint160 v = uint160(address(this)); diff --git a/packages/core/scripts/agw-verify.js b/packages/core/scripts/agw-verify.js new file mode 100644 index 00000000..ada651e2 --- /dev/null +++ b/packages/core/scripts/agw-verify.js @@ -0,0 +1,74 @@ +/** One unfunded verification entry point. No .env loading, live E2E or publishing. */ +const { spawnSync } = require('node:child_process'); +const fs = require('node:fs'); +const path = require('node:path'); +const root = path.resolve(__dirname, '../../..'); +const dir = path.join(root, '.agw-validation'); +fs.mkdirSync(dir, { recursive: true }); +function run(name, file, args, options = {}) { + process.stdout.write(`AGW validation: ${name}\n`); + const result = spawnSync(file, args, { + cwd: root, + encoding: 'utf8', + maxBuffer: 20 * 1024 * 1024, + ...options, + }); + const out = String(result.stdout || '') + String(result.stderr || ''); + fs.writeFileSync(path.join(dir, `${name}.log`), out); + if (result.error || result.status !== 0) { + throw new Error( + `AGW validation failed: ${name}; see .agw-validation/${name}.log` + ); + } + return out; +} +const node = process.execPath; +run('units', node, [ + 'node_modules/jest/bin/jest.js', + '--config', + 'packages/core/jest.config.ts', + '--runInBand', + '--testPathPattern=agentic|outbound-(confirmation-gate|svm-confirmation)|svm-idl', +]); +for (const kind of ['lib', 'spec', 'agw-local']) + run(`types-${kind}`, node, [ + 'node_modules/typescript/bin/tsc', + '-p', + `packages/core/tsconfig.${kind}.json`, + '--noEmit', + ]); +run('docs', node, ['packages/core/scripts/check-agw-docs.js']); +const env = { + ...process.env, + OUT: process.env.AGW_LOCAL_DIR || path.join(dir, 'contracts'), +}; +run( + 'prepare-contracts', + 'bash', + ['packages/core/scripts/agw-local/prepare.sh'], + { env } +); +run( + 'local-contracts', + node, + [ + 'node_modules/jest/bin/jest.js', + '--config', + 'packages/core/jest.agw-local.config.ts', + '--runInBand', + ], + { env: { ...env, AGW_LOCAL_DIR: env.OUT } } +); +run( + 'build', + node, + ['node_modules/nx/bin/nx.js', 'run', 'core:build', '--skip-nx-cache'], + { env: { ...process.env, NX_DAEMON: 'false' } } +); +run('package', node, ['packages/core/scripts/check-agw-package.js']); +run('public-api', node, [ + 'packages/core/scripts/check-agw-api.js', + '--output', + path.join(dir, 'api-comparison.json'), +]); +process.stdout.write('AGW unfunded validation completed.\n'); diff --git a/packages/core/scripts/check-agw-api.js b/packages/core/scripts/check-agw-api.js new file mode 100644 index 00000000..7ff4ca8f --- /dev/null +++ b/packages/core/scripts/check-agw-api.js @@ -0,0 +1,185 @@ +/** Public export/type comparison. Report changes; do not approve pending API choices. */ +const fs = require('node:fs'); +const path = require('node:path'); +const { execFileSync } = require('node:child_process'); +const ts = require('typescript'); +const assert = require('node:assert/strict'); +const root = path.resolve(__dirname, '../../..'); +const baseline = 'b1597b91a25dbf7f691f589b4e1e154add604315'; +const config = ts.readConfigFile( + path.join(root, 'packages/core/tsconfig.lib.json'), + ts.sys.readFile +); +const options = ts.parseJsonConfigFileContent( + config.config, + ts.sys, + path.join(root, 'packages/core') +).options; +const selected = [ + 'AgenticNamespace', + 'AgenticWallet', + 'AgenticError', + 'AgenticRevertError', + 'AGENTIC_ERROR_CODE', + 'NativeRule', + 'ArgPin', + 'AmountLimit', + 'AssetCap', + 'AllowedCall', + 'UniversalRule', + 'RulesRecord', + 'CreateOptions', + 'CreateResult', + 'AgenticTxMetadata', +]; +function snapshot(entry) { + const program = ts.createProgram([entry], { ...options, noEmit: true }); + const diagnostics = ts.getPreEmitDiagnostics(program); + if (diagnostics.length) + throw new Error( + ts.formatDiagnostics(diagnostics, { + getCanonicalFileName: (f) => f, + getCurrentDirectory: () => root, + getNewLine: () => '\n', + }) + ); + const checker = program.getTypeChecker(), + file = program.getSourceFile(entry); + const exports = checker.getExportsOfModule(checker.getSymbolAtLocation(file)); + const normal = (s) => + s.replace( + /import\("([^"]+)"\)/g, + (_, p) => + `import("${ + p.includes('/src/') ? 'sdk/src/' + p.split('/src/').pop() : p + }")` + ); + const text = (t, node) => + normal(checker.typeToString(t, node, ts.TypeFormatFlags.NoTruncation)); + function properties(t) { + return Object.fromEntries( + checker + .getPropertiesOfType(t) + .filter((p) => { + const d = p.valueDeclaration || p.declarations?.[0]; + return ( + !d || + !( + ts.getCombinedModifierFlags(d) & + (ts.ModifierFlags.Private | ts.ModifierFlags.Protected) + ) + ); + }) + .map((p) => [ + p.name, + { + optional: Boolean(p.flags & ts.SymbolFlags.Optional), + type: text(checker.getTypeOfSymbolAtLocation(p, file), file), + }, + ]) + .sort(([a], [b]) => a.localeCompare(b)) + ); + } + const result = { exports: exports.map((s) => s.name).sort(), agw: {} }; + for (const name of selected) { + let s = exports.find((s) => s.name === name); + if (!s) continue; + if (s.flags & ts.SymbolFlags.Alias) s = checker.getAliasedSymbol(s); + const t = + s.flags & + (ts.SymbolFlags.Interface | + ts.SymbolFlags.TypeAlias | + ts.SymbolFlags.Class) + ? checker.getDeclaredTypeOfSymbol(s) + : checker.getTypeOfSymbolAtLocation(s, file); + result.agw[name] = { type: text(t, file), members: properties(t) }; + } + let push = exports.find((s) => s.name === 'PushChain'); + if (push.flags & ts.SymbolFlags.Alias) push = checker.getAliasedSymbol(push); + const staticType = checker.getTypeOfSymbolAtLocation(push, file); + const init = staticType.getProperty('initialize'); + result.initialize = text(checker.getTypeOfSymbolAtLocation(init, file), file); + const constants = staticType.getProperty('CONSTANTS'); + const cType = checker.getTypeOfSymbolAtLocation(constants, file), + agw = cType.getProperty('AGENTIC'); + const aType = checker.getTypeOfSymbolAtLocation(agw, file); + const donut = aType.getProperty('TESTNET_DONUT'); + result.agwConstants = properties( + checker.getNonNullableType(checker.getTypeOfSymbolAtLocation(donut, file)) + ); + return result; +} +const current = snapshot(path.join(root, 'packages/core/src/index.ts')); +const built = snapshot(path.join(root, 'dist/packages/core/src/index.d.ts')); +assert.deepEqual( + built, + current, + 'compiled public API differs from source public API' +); +try { + execFileSync('git', ['cat-file', '-e', `${baseline}^{commit}`], { + cwd: root, + stdio: 'ignore', + }); +} catch { + execFileSync( + 'git', + [ + 'fetch', + '--depth=1', + 'https://github.com/pushchain/push-chain-sdk.git', + baseline, + ], + { cwd: root, stdio: 'ignore' } + ); +} +const temp = fs.mkdtempSync(path.join(root, 'node_modules/.cache/agw-api-')); +try { + const archive = execFileSync( + 'git', + ['archive', baseline, 'packages/core/src'], + { cwd: root, maxBuffer: 30 * 1024 * 1024 } + ); + execFileSync('tar', ['-x', '-C', temp], { input: archive }); + const old = snapshot(path.join(temp, 'packages/core/src/index.ts')); + const changes = []; + for (const name of selected) + if (JSON.stringify(old.agw[name]) !== JSON.stringify(current.agw[name])) + changes.push(name); + const report = { + baseline, + head: execFileSync('git', ['rev-parse', 'HEAD'], { + cwd: root, + encoding: 'utf8', + }).trim(), + compiledMatchesSource: true, + initializeSignatureChanged: old.initialize !== current.initialize, + addedExports: current.exports.filter((s) => !old.exports.includes(s)), + removedExports: old.exports.filter((s) => !current.exports.includes(s)), + changedAgwTypes: changes, + agwConstantsChanged: + JSON.stringify(old.agwConstants) !== JSON.stringify(current.agwConstants), + before: old, + after: current, + scope: + 'Root exports, AGW types, initialize and agentic constants. Behavioral/default/deployment changes need the written session review.', + }; + const at = process.argv.indexOf('--output'); + if (at >= 0) + fs.writeFileSync( + path.resolve(process.argv[at + 1]), + JSON.stringify(report, null, 2) + '\n' + ); + process.stdout.write( + JSON.stringify({ + compiledMatchesSource: true, + addedExports: report.addedExports, + removedExports: report.removedExports, + changedAgwTypes: changes, + initializeSignatureChanged: report.initializeSignatureChanged, + agwConstantsChanged: report.agwConstantsChanged, + }) + '\n' + ); +} finally { + fs.rmSync(temp, { recursive: true, force: true }); +} diff --git a/packages/core/scripts/check-agw-package.js b/packages/core/scripts/check-agw-package.js new file mode 100644 index 00000000..83cc7805 --- /dev/null +++ b/packages/core/scripts/check-agw-package.js @@ -0,0 +1,74 @@ +/** Consume built JS/declarations, not tsconfig's source alias. No wallet operations. */ +const fs = require('node:fs'); +const path = require('node:path'); +const { pathToFileURL } = require('node:url'); +const { execFileSync } = require('node:child_process'); +const assert = require('node:assert/strict'); +const ts = require('typescript'); +const root = path.resolve(__dirname, '../../..'); +const built = path.join(root, 'dist/packages/core'); +async function main() { + const entry = path.join(built, 'src/index.js'); + const cjs = require(entry), + esm = await import(pathToFileURL(entry).href); + assert.equal(typeof cjs.PushChain.initialize, 'function'); + assert.equal(esm.PushChain, cjs.PushChain); + assert.equal( + cjs.PushChain.CONSTANTS.AGENTIC.TESTNET_DONUT.ENVELOPE_VERSION, + 1 + ); + assert.equal(typeof cjs.AgenticError, 'function'); + const [pack] = JSON.parse( + execFileSync('npm', ['pack', '--dry-run', '--json', '--ignore-scripts'], { + cwd: built, + encoding: 'utf8', + }) + ); + assert(pack.files.some((f) => f.path === 'AGW.md')); + assert(!pack.files.some((f) => /(^|\/)\.env($|\.)/.test(f.path))); + const guide = fs.readFileSync(path.join(built, 'AGW.md'), 'utf8'); + const source = [...guide.matchAll(/```ts\n([\s\S]*?)```/g)] + .map((m) => m[1]) + .join('\n\n'); + const tmp = fs.mkdtempSync( + path.join(root, 'node_modules/.cache/agw-consumer-') + ); + try { + const file = path.join(tmp, 'consumer.ts'); + fs.writeFileSync(file, source); + const config = ts.readConfigFile( + path.join(root, 'packages/core/tsconfig.lib.json'), + ts.sys.readFile + ); + const parsed = ts.parseJsonConfigFileContent( + config.config, + ts.sys, + path.join(root, 'packages/core') + ); + const options = { + ...parsed.options, + noEmit: true, + paths: { '@pushchain/core': [path.join(built, 'src/index.d.ts')] }, + }; + const diagnostics = ts.getPreEmitDiagnostics( + ts.createProgram([file], options) + ); + if (diagnostics.length) + throw new Error( + ts.formatDiagnostics(diagnostics, { + getCanonicalFileName: (f) => f, + getCurrentDirectory: () => root, + getNewLine: () => '\n', + }) + ); + } finally { + fs.rmSync(tmp, { recursive: true, force: true }); + } + process.stdout.write( + 'AGW package: CJS/ESM imports, compiled declaration examples and npm contents pass. No examples executed/published.\n' + ); +} +main().catch((error) => { + process.stderr.write(`${error.message}\n`); + process.exitCode = 1; +}); diff --git a/packages/core/src/lib/agentic/__tests__/svm-backend.spec.ts b/packages/core/src/lib/agentic/__tests__/svm-backend.spec.ts new file mode 100644 index 00000000..28e76662 --- /dev/null +++ b/packages/core/src/lib/agentic/__tests__/svm-backend.spec.ts @@ -0,0 +1,323 @@ +import { PublicKey } from '@solana/web3.js'; +import { bytesToHex, type Hex } from 'viem'; +import { CHAIN } from '../../constants/enums'; +import { createSvmMetadataProvider } from '../management/svm-metadata'; +import { resolveSvmContext } from '../management/svm-context'; +import { Snapshot } from '../reads/snapshot'; +import { + registerIdl, + clearRegistry, +} from '../../orchestrator/svm-idl/registry'; +import { prepareAgwSvmInstruction } from '../execution/svm-instruction'; +import { + deriveAgwSvmValueAccounts, + deriveAgwSvmAta, +} from '../codec/svm-accounts'; +import { ADDR, FakeChain } from './fake-chain'; +import type { SvmTermsWire } from '../codec/svm-terms'; +const key = (b: string) => `0x${b.repeat(32)}` as Hex; +const SPL = 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'; +const TOKEN2022 = 'TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb'; +const MINT = new PublicKey(Buffer.from(key('44').slice(2), 'hex')); +const PROGRAM = key('33'), + GATEWAY = key('22'); +const genesis = CHAIN.SOLANA_DEVNET.slice(7) + 'abcdefghijk'; +function rpc(owner = SPL, length = 82) { + const data = Buffer.alloc(length); + data[45] = 1; + if (length >= 166) data[165] = 1; + return { + getGenesisHash: jest.fn().mockResolvedValue(genesis), + getAccountInfo: jest.fn().mockResolvedValue({ + owner: new PublicKey(owner), + executable: false, + data, + lamports: 1, + rentEpoch: 0, + }), + }; +} +afterEach(clearRegistry); +describe('SVM metadata and resolved instruction backend', () => { + it.each(['dataless', 'non-anchor', 'wrong-account'])( + 'validates explicit wire accounts for %s instructions', + (kind) => { + const derived = deriveAgwSvmValueAccounts(ADDR.owner, GATEWAY, []); + const dataless = kind === 'dataless'; + const terms: SvmTermsWire = { + ...derived, + validUntil: 9999999999, + assets: [ + { token: ADDR.target, maxPerCall: BigInt(1), maxTotal: BigInt(2) }, + ], + maxGasPerCall: BigInt(10), + programs: [ + { + program: PROGRAM, + discriminator: '0x0100000000000000', + discriminatorLen: dataless ? 0 : 1, + dataless, + maxAccounts: 1, + }, + ], + pins: [ + { ruleIndex: 0, accountIndex: 0, expected: derived.expectedCEA }, + ], + dataPins: [], + }; + const build = () => + prepareAgwSvmInstruction( + { + wallet: ADDR.owner, + chain: CHAIN.SOLANA_DEVNET, + program: PROGRAM, + instructionData: dataless ? new Uint8Array() : new Uint8Array([1]), + accounts: [ + { + pubkey: + kind === 'wrong-account' ? key('66') : derived.expectedCEA, + isWritable: true, + }, + ], + }, + terms + ); + if (kind === 'wrong-account') + expect(build).toThrow('SvmAccountPinMismatch'); + else expect(build().recipient).toBe(PROGRAM); + } + ); + it.each([false, true])( + 'resolves output mint Token-2022 ownership, rejecting a wrong supplied program: %s', + async (wrong) => { + const fake = new FakeChain(); + fake.readContract = async ({ functionName }) => + functionName === 'gasTokenPRC20ByChainNamespace' + ? ADDR.other + : functionName === 'SOURCE_CHAIN_NAMESPACE' + ? CHAIN.SOLANA_DEVNET + : ''; + const mint = key('55'); + const metadata = { + gateway: async () => ({ + chainNamespace: CHAIN.SOLANA_DEVNET, + program: GATEWAY, + }), + mint: async () => ({ mint, tokenProgram: TOKEN2022 }), + }; + const promise = resolveSvmContext( + new Snapshot(fake, BigInt(1)), + ADDR.owner, + CHAIN.SOLANA_DEVNET, + [{ token: ADDR.other, maxPerCall: BigInt(1), maxTotal: BigInt(2) }], + metadata, + [{ mint, ...(wrong ? { tokenProgram: SPL } : {}) }] + ); + if (wrong) + await expect(promise).rejects.toThrow( + 'output mint/token-program mismatch' + ); + else { + const ctx = await promise; + expect(ctx.ceaAccounts).toEqual([ + ctx.expectedCEA, + deriveAgwSvmAta(ctx.expectedCEA, { mint, tokenProgram: TOKEN2022 }), + ]); + } + } + ); + it.each([ + [SPL, 82], + [TOKEN2022, 82], + [TOKEN2022, 166], + ])('reads initialized mint owner %s length %s', async (owner, length) => { + const r = rpc(owner, length); + const provider = createSvmMetadataProvider( + { + [CHAIN.SOLANA_DEVNET]: { + gatewayProgram: GATEWAY, + rpcUrls: ['http://fixture'], + }, + }, + () => r + ); + expect( + await provider.mint(CHAIN.SOLANA_DEVNET, bytesToHex(MINT.toBytes())) + ).toEqual({ mint: MINT.toBase58(), tokenProgram: owner }); + expect(await provider.gateway(CHAIN.SOLANA_DEVNET)).toEqual({ + chainNamespace: CHAIN.SOLANA_DEVNET, + program: GATEWAY, + }); + }); + it('rejects wrong cluster RPCs and falls back to the configured correct cluster', async () => { + const wrong = rpc(), + correct = rpc(); + wrong.getGenesisHash.mockResolvedValue('wrong-genesis'); + const provider = createSvmMetadataProvider( + { + [CHAIN.SOLANA_DEVNET]: { + gatewayProgram: GATEWAY, + rpcUrls: ['wrong', 'right'], + }, + }, + (url) => (url === 'wrong' ? wrong : correct) + ); + await provider.mint(CHAIN.SOLANA_DEVNET, bytesToHex(MINT.toBytes())); + expect(wrong.getAccountInfo).not.toHaveBeenCalled(); + expect(correct.getAccountInfo).toHaveBeenCalledTimes(1); + }); + it.each([ + 'missing', + 'executable', + 'token-account', + 'uninitialized', + 'wrong-owner', + ])('rejects %s as a mint', async (kind) => { + const r = rpc(), + info = await r.getAccountInfo(); + if (kind === 'missing') r.getAccountInfo.mockResolvedValue(null); + else { + if (kind === 'executable') info.executable = true; + if (kind === 'token-account') info.data = Buffer.alloc(165); + if (kind === 'uninitialized') info.data[45] = 0; + if (kind === 'wrong-owner') info.owner = PublicKey.default; + r.getAccountInfo.mockResolvedValue(info); + } + const p = createSvmMetadataProvider( + { + [CHAIN.SOLANA_DEVNET]: { + gatewayProgram: GATEWAY, + rpcUrls: ['fixture'], + }, + }, + () => r + ); + await expect( + p.mint(CHAIN.SOLANA_DEVNET, bytesToHex(MINT.toBytes())) + ).rejects.toMatchObject({ code: 'INVALID_RULE' }); + }); + it('requires a configured gateway/RPC, rather than choosing a devnet default', async () => { + await expect( + createSvmMetadataProvider({}).gateway(CHAIN.SOLANA_DEVNET) + ).rejects.toMatchObject({ code: 'INVALID_RULE' }); + }); + it('pins all PRC20 reads and rejects a source-chain mismatch', async () => { + const fake = new FakeChain(); + fake.readContract = jest.fn(async ({ functionName }) => + functionName === 'gasTokenPRC20ByChainNamespace' + ? ADDR.other + : CHAIN.ETHEREUM_SEPOLIA + ); + const snap = new Snapshot(fake, BigInt(123)); + const metadata = { + gateway: async () => ({ + chainNamespace: CHAIN.SOLANA_DEVNET, + program: GATEWAY, + }), + mint: jest.fn(), + }; + await expect( + resolveSvmContext( + snap, + ADDR.owner, + CHAIN.SOLANA_DEVNET, + [{ token: ADDR.target, maxPerCall: BigInt(1), maxTotal: BigInt(2) }], + metadata + ) + ).rejects.toMatchObject({ code: 'ASSET_CHAIN_MISMATCH' }); + expect( + (fake.readContract as jest.Mock).mock.calls.every( + ([arg]) => arg.blockNumber === BigInt(123) + ) + ).toBe(true); + }); + it('rejects registry and mint substitution', async () => { + const fake = new FakeChain(); + fake.readContract = async ({ functionName }) => + functionName === 'gasTokenPRC20ByChainNamespace' + ? ADDR.other + : functionName === 'SOURCE_CHAIN_NAMESPACE' + ? CHAIN.SOLANA_DEVNET + : MINT.toBase58(); + const snap = new Snapshot(fake, BigInt(1)), + caps = [ + { token: ADDR.target, maxPerCall: BigInt(1), maxTotal: BigInt(2) }, + ]; + await expect( + resolveSvmContext(snap, ADDR.owner, CHAIN.SOLANA_DEVNET, caps, { + gateway: async () => ({ + chainNamespace: CHAIN.SOLANA_TESTNET, + program: GATEWAY, + }), + mint: jest.fn(), + }) + ).rejects.toThrow('cluster mismatch'); + await expect( + resolveSvmContext(snap, ADDR.owner, CHAIN.SOLANA_DEVNET, caps, { + gateway: async () => ({ + chainNamespace: CHAIN.SOLANA_DEVNET, + program: GATEWAY, + }), + mint: async () => ({ mint: key('55'), tokenProgram: SPL }), + }) + ).rejects.toThrow('different mint'); + }); + it('derives the wallet authority for IDL accounts, not the signer/default gateway authority', () => { + const derived = deriveAgwSvmValueAccounts(ADDR.owner, GATEWAY, []); + const program = new PublicKey( + Buffer.from(PROGRAM.slice(2), 'hex') + ).toBase58(); + registerIdl({ + address: program, + metadata: { name: 'fixture', version: '1', spec: '0.1.0' }, + instructions: [ + { + name: 'go', + discriminator: [1, 2, 3, 4, 5, 6, 7, 8], + accounts: [{ name: 'cea_authority', writable: true }], + args: [], + }, + ], + }); + const t: SvmTermsWire = { + ...derived, + validUntil: 9999999999, + assets: [ + { token: ADDR.target, maxPerCall: BigInt(1), maxTotal: BigInt(2) }, + ], + maxGasPerCall: BigInt(10), + programs: [ + { + program: PROGRAM, + discriminator: '0x0102030405060708', + discriminatorLen: 8, + dataless: false, + maxAccounts: 1, + }, + ], + pins: [{ ruleIndex: 0, accountIndex: 0, expected: derived.expectedCEA }], + dataPins: [], + }; + const out = prepareAgwSvmInstruction( + { + wallet: ADDR.owner, + chain: CHAIN.SOLANA_DEVNET, + program, + instructionData: new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]), + }, + t + ); + expect(out.accounts[0].pubkey).toBe(derived.expectedCEA); + expect(() => + prepareAgwSvmInstruction( + { + wallet: ADDR.owner, + chain: CHAIN.SOLANA_DEVNET, + program, + instructionData: new Uint8Array([9, 2, 3, 4, 5, 6, 7, 8]), + }, + t + ) + ).toThrow(/discriminator/); + }); +}); diff --git a/packages/core/src/lib/agentic/execution/svm-instruction.ts b/packages/core/src/lib/agentic/execution/svm-instruction.ts new file mode 100644 index 00000000..26a57a54 --- /dev/null +++ b/packages/core/src/lib/agentic/execution/svm-instruction.ts @@ -0,0 +1,59 @@ +import type { CHAIN } from '../../constants/enums'; +import { resolveSvmCallForCea } from '../../orchestrator/svm-idl/resolve'; +import type { SvmTermsWire } from '../codec/svm-terms'; +import { svmKey } from '../codec/svm-accounts'; +import { + encodeAgwSvmPayload, + validateAgwSvmPayload, + type SvmPayloadAccount, +} from './svm-payload'; +import type { Address } from 'viem'; + +/** Existing IDL encoding, with the wallet's authority and strict policy checks. */ +export function prepareAgwSvmInstruction( + input: { + wallet: Address; + chain: CHAIN; + program: string; + instructionData: Uint8Array; + accounts?: readonly SvmPayloadAccount[]; + }, + terms: SvmTermsWire +) { + const program = svmKey(input.program); + if (input.accounts) { + const payload = encodeAgwSvmPayload( + program, + input.accounts, + input.instructionData + ); + validateAgwSvmPayload(terms, program, payload); + return { + recipient: program, + payload, + accounts: [...input.accounts], + instructionData: input.instructionData, + }; + } + const resolved = resolveSvmCallForCea( + { + programAddress: program, + data: input.instructionData, + senderUea: input.wallet, + targetChain: input.chain, + }, + terms.expectedCEA + ); + const payload = encodeAgwSvmPayload( + resolved.targetProgram, + resolved.accounts, + resolved.ixData + ); + validateAgwSvmPayload(terms, program, payload); + return { + recipient: program, + payload, + accounts: resolved.accounts, + instructionData: resolved.ixData, + }; +} diff --git a/packages/core/src/lib/agentic/execution/svm-send.ts b/packages/core/src/lib/agentic/execution/svm-send.ts new file mode 100644 index 00000000..aa9cb162 --- /dev/null +++ b/packages/core/src/lib/agentic/execution/svm-send.ts @@ -0,0 +1,177 @@ +/** Prepared-wire agent execution. Public SVM entry points remain disabled. */ +import { getAddress, erc20Abi, type Address, type Hex } from 'viem'; +import { CHAIN } from '../../constants/enums'; +import type { AgenticGeneration } from '../deployments'; +import type { AgenticRuntime } from '../runtime'; +import { assertCanSign, wrapSendError } from '../management/common'; +import { Snapshot } from '../reads/snapshot'; +import { readSvmRule } from '../reads/svm'; +import { + resolveSvmContext, + type SvmMetadataProvider, +} from '../management/svm-context'; +import { composeAgwSvmAction } from './svm-outbound'; +import { prepareAgwSvmInstruction } from './svm-instruction'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; +import { verifySvmWallet } from '../management/svm'; +import type { SvmPayloadAccount } from './svm-payload'; + +export interface PreparedSvmRequest { + wallet: Address; + rulesId: Hex; + token: Address; + amount: bigint; + gasLimit: bigint; + program: string; + instructionData: Uint8Array; + /** Already-resolved wire accounts for non-Anchor/dataless programs. */ + accounts?: readonly SvmPayloadAccount[]; +} + +export async function prepareSvmAgentExecution( + runtime: AgenticRuntime, + gen: AgenticGeneration, + input: PreparedSvmRequest, + metadata: SvmMetadataProvider +) { + assertCanSign(runtime, 'internal SVM send'); + await verifySvmWallet(runtime, gen, input.wallet); + const snap = await Snapshot.at(runtime.reader); + const stored = await readSvmRule( + snap, + gen, + input.wallet, + input.rulesId, + runtime.pushChainNamespace + ); + if (getAddress(stored.agent) !== getAddress(runtime.signerPushAccount())) + throw new AgenticError( + AGENTIC_ERROR_CODE.NOT_OWNER_OR_AGENT, + 'signer is not this SVM rule agent' + ); + const chain = stored.chainNamespace as CHAIN; + const resolved = await resolveSvmContext( + snap, + input.wallet, + stored.chainNamespace, + stored.config.assets, + metadata + ); + if ( + resolved.expectedCEA.toLowerCase() !== + stored.config.expectedCEA.toLowerCase() || + resolved.gatewayProgram.toLowerCase() !== + stored.config.gatewayProgram.toLowerCase() || + resolved.ceaAccounts.some( + (a) => + !stored.config.ceaAccounts.some( + (b) => a.toLowerCase() === b.toLowerCase() + ) + ) + ) + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'stored SVM context does not cover the wallet and every asset' + ); + const instruction = prepareAgwSvmInstruction( + { + wallet: input.wallet, + chain, + program: input.program, + instructionData: input.instructionData, + accounts: input.accounts, + }, + stored.config + ); + const quote = await runtime.quoteOutbound( + getAddress(input.token), + input.gasLimit, + chain + ); + const call = composeAgwSvmAction( + { + ...input, + gateway: gen.addresses.gateway, + recipient: instruction.recipient, + payload: instruction.payload, + gasLimit: quote.gasLimitUsed, + protocolFee: quote.protocolFee, + maxPCForGas: quote.nativeValueForGas, + }, + stored.config, + runtime.nowSeconds() + ); + const walletPc = await runtime.reader.getBalance({ + address: input.wallet, + blockNumber: snap.blockNumber, + }); + if (walletPc < call.value) + throw new AgenticError( + AGENTIC_ERROR_CODE.WALLET_BALANCE_INSUFFICIENT, + 'wallet PC is below the SVM outbound quote' + ); + if (input.amount > BigInt(0)) { + const balance = await snap.read( + input.token, + erc20Abi, + 'balanceOf', + [input.wallet] + ); + if (balance < input.amount) + throw new AgenticError( + AGENTIC_ERROR_CODE.WALLET_BALANCE_INSUFFICIENT, + 'wallet token balance is below the SVM amount' + ); + const allowance = await snap.read( + input.token, + erc20Abi, + 'allowance', + [input.wallet, gen.addresses.gateway] + ); + if (allowance < input.amount) + throw new AgenticError( + AGENTIC_ERROR_CODE.GATEWAY_ALLOWANCE_INSUFFICIENT, + 'owner must establish the SVM gateway allowance separately' + ); + } + const signerPc = await runtime.signerBalance(); + const gasReserve = (await runtime.getGasPrice()) * BigInt(10_000_000); + if ((await runtime.signerAccountDeployed()) && signerPc < gasReserve) + throw new AgenticError( + AGENTIC_ERROR_CODE.AGENT_GAS_INSUFFICIENT, + 'deployed SVM agent identity has no Push gas balance' + ); + return { + stored, + call, + instruction, + quote, + data: gen.contracts.encodeExecuteAsAgent(input.rulesId, call), + }; +} + +export async function sendSvmAgentWire( + runtime: AgenticRuntime, + gen: AgenticGeneration, + input: PreparedSvmRequest, + metadata: SvmMetadataProvider +) { + const prepared = await prepareSvmAgentExecution( + runtime, + gen, + input, + metadata + ); + try { + const tx = await runtime.execute({ + to: input.wallet, + value: BigInt(0), + data: prepared.data, + }); + // Return the ordinary signer response and explicit wire context internally. + // Public display/Rule mapping is deliberately not invented here. + return { tx, context: prepared.stored, instruction: prepared.instruction }; + } catch (error) { + throw wrapSendError(error); + } +} diff --git a/packages/core/src/lib/agentic/management/svm-context.ts b/packages/core/src/lib/agentic/management/svm-context.ts new file mode 100644 index 00000000..72f7ed80 --- /dev/null +++ b/packages/core/src/lib/agentic/management/svm-context.ts @@ -0,0 +1,136 @@ +/** Internal resolved context; no public Rule schema or cluster assumptions. */ +import { + getAddress, + parseAbi, + zeroAddress, + type Address, + type Hex, +} from 'viem'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; +import { PRC20_SOURCE_ABI, readGasPrc20 } from '../contracts/prc20-metadata'; +import { + svmKey, + resolveAgwSvmRuleContext, + type SvmTokenAccountInput, + type ResolvedSvmAsset, +} from '../codec/svm-accounts'; +import type { AssetCapWire } from '../codec/universal-terms'; +import type { Snapshot } from '../reads/snapshot'; + +export interface SvmMetadataProvider { + /** Must identify the requested full CAIP-2 cluster; no global gateway default. */ + gateway( + chainNamespace: `solana:${string}` + ): Promise<{ chainNamespace: string; program: string }>; + /** RPC-backed mint owner (legacy SPL or Token-2022), not an assumed default. */ + mint( + chainNamespace: `solana:${string}`, + address: Hex + ): Promise<{ mint: string; tokenProgram: string }>; +} + +const NATIVE_SOURCE = parseAbi([ + 'function SOURCE_TOKEN_ADDRESS() view returns (address)', +]); +const ZERO_KEY = `0x${'00'.repeat(32)}` as Hex; + +export async function resolveSvmAssets( + snap: Snapshot, + chain: `solana:${string}`, + caps: readonly AssetCapWire[], + metadata: SvmMetadataProvider +): Promise { + const gas = await readGasPrc20(snap, chain); + const out: ResolvedSvmAsset[] = []; + for (const cap of caps) { + const token = getAddress(cap.token); + const namespace = await snap.read( + token, + PRC20_SOURCE_ABI, + 'SOURCE_CHAIN_NAMESPACE' + ); + if (namespace !== chain) + throw new AgenticError( + AGENTIC_ERROR_CODE.ASSET_CHAIN_MISMATCH, + `PRC20 ${token} belongs to ${namespace}, not ${chain}` + ); + let source: string; + try { + source = await snap.read( + token, + PRC20_SOURCE_ABI, + 'SOURCE_TOKEN_ADDRESS' + ); + } catch (cause) { + if (token !== gas) throw cause; + const native = await snap.read
( + token, + NATIVE_SOURCE, + 'SOURCE_TOKEN_ADDRESS' + ); + if (getAddress(native) !== zeroAddress) throw cause; + source = ''; + } + const native = + source === '' || + source.toLowerCase() === zeroAddress || + source.toLowerCase() === ZERO_KEY; + if (native) { + if (token !== gas) + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'native marker is not the registered gas PRC20' + ); + out.push({ kind: 'native', cap: { ...cap, token } }); + } else { + const key = svmKey(source); + const mint = await metadata.mint(chain, key); + if (svmKey(mint.mint) !== key) + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'mint resolver returned a different mint' + ); + out.push({ kind: 'spl', cap: { ...cap, token }, ...mint }); + } + } + return out; +} + +export async function resolveSvmContext( + snap: Snapshot, + wallet: Address, + chain: `solana:${string}`, + caps: readonly AssetCapWire[], + metadata: SvmMetadataProvider, + outputs: readonly SvmTokenAccountInput[] = [] +) { + const gateway = await metadata.gateway(chain); + if (gateway.chainNamespace !== chain) + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'gateway registry cluster mismatch' + ); + const assets = await resolveSvmAssets(snap, chain, caps, metadata); + const resolvedOutputs = []; + for (const output of outputs) { + const key = svmKey(output.mint); + const resolved = await metadata.mint(chain, key); + if ( + svmKey(resolved.mint) !== key || + (output.tokenProgram && + svmKey(output.tokenProgram) !== svmKey(resolved.tokenProgram)) + ) + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'output mint/token-program mismatch' + ); + resolvedOutputs.push(resolved); + } + // Derivation validates token programs and covers every mint/output. + return resolveAgwSvmRuleContext( + wallet, + gateway.program, + assets, + resolvedOutputs + ); +} diff --git a/packages/core/src/lib/agentic/management/svm-metadata.ts b/packages/core/src/lib/agentic/management/svm-metadata.ts new file mode 100644 index 00000000..82aa0bef --- /dev/null +++ b/packages/core/src/lib/agentic/management/svm-metadata.ts @@ -0,0 +1,75 @@ +import { Connection, PublicKey } from '@solana/web3.js'; +import { svmKey } from '../codec/svm-accounts'; +import { svmInvalid } from '../codec/svm-terms'; +import type { SvmMetadataProvider } from './svm-context'; +import { AgenticError, AGENTIC_ERROR_CODE } from '../errors'; + +export interface SvmClusterConfig { + gatewayProgram: string; + rpcUrls: readonly string[]; +} +type MintRpc = Pick; +const SPL = 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'; +const TOKEN_2022 = 'TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb'; + +/** Explicit cluster configuration; HTTP reads only, no signing/subscriptions. */ +export function createSvmMetadataProvider( + clusters: Readonly>>, + connect: (url: string) => MintRpc = (url) => new Connection(url, 'confirmed') +): SvmMetadataProvider { + function config(chain: `solana:${string}`) { + const c = clusters[chain]; + if (!c || !c.rpcUrls.length) + throw svmInvalid(`no SVM registry/RPC configuration for ${chain}`); + svmKey(c.gatewayProgram); + return c; + } + async function read( + chain: `solana:${string}`, + fn: (rpc: MintRpc) => Promise + ): Promise { + const c = config(chain); + let last: unknown; + for (const url of c.rpcUrls) { + try { + const rpc = connect(url); + // CAIP-2 Solana references are the first 32 characters of genesisHash. + if (`solana:${(await rpc.getGenesisHash()).slice(0, 32)}` !== chain) + throw svmInvalid('SVM RPC genesis/cluster mismatch'); + return await fn(rpc); + } catch (error) { + last = error; + } + } + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + `SVM metadata lookup failed for ${chain}`, + { cause: last } + ); + } + return { + gateway: async (chain) => + read(chain, async () => ({ + chainNamespace: chain, + program: config(chain).gatewayProgram, + })), + mint: async (chain, address) => + read(chain, async (rpc) => { + const mint = new PublicKey( + Buffer.from(svmKey(address).slice(2), 'hex') + ); + const info = await rpc.getAccountInfo(mint, 'confirmed'); + if (!info || info.executable) + throw svmInvalid('mint account missing or executable'); + const owner = info.owner.toBase58(), + data = info.data; + const legacy = owner === SPL && data.length === 82; + const extended = + owner === TOKEN_2022 && + (data.length === 82 || (data.length >= 166 && data[165] === 1)); + if ((!legacy && !extended) || data[45] !== 1) + throw svmInvalid('account is not an initialized supported SPL mint'); + return { mint: mint.toBase58(), tokenProgram: owner }; + }), + }; +} diff --git a/packages/core/src/lib/agentic/management/svm.ts b/packages/core/src/lib/agentic/management/svm.ts new file mode 100644 index 00000000..680bd620 --- /dev/null +++ b/packages/core/src/lib/agentic/management/svm.ts @@ -0,0 +1,254 @@ +/** Internal explicit-wire operations. Not exported by the SDK entry point. */ +import { getAddress, type Address, type Hex } from 'viem'; +import type { AgenticRuntime } from '../runtime'; +import { + resolveWalletGeneration, + verifyPolicyVersion, + type AgenticGeneration, +} from '../deployments'; +import { Snapshot } from '../reads/snapshot'; +import { readSvmRule } from '../reads/svm'; +import { + assertCanSign, + assertOwner, + confirmedLogs, + wrapSendError, +} from './common'; +import { encodeSvmTerms, type SvmTermsWire } from '../codec/svm-terms'; +import { buildSession, encodeEnvelope } from '../codec/session'; +import { rulesId as predictRulesId } from '../codec/ids'; +import { SEND_OUTBOUND_SELECTOR } from '../contracts/v4'; +import { deriveAgwSvmCea } from '../codec/svm-accounts'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; +import { PRC20_SOURCE_ABI } from '../contracts/prc20-metadata'; + +async function verifyAssets(snap: Snapshot, input: SvmWireGrant) { + if (!/^solana:[1-9A-HJ-NP-Za-km-z]{32}$/.test(input.chainNamespace)) + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'SVM chain must be a full Solana CAIP-2 namespace' + ); + for (const cap of input.terms.assets) { + if ( + (await snap.read( + cap.token, + PRC20_SOURCE_ABI, + 'SOURCE_CHAIN_NAMESPACE' + )) !== input.chainNamespace + ) + throw new AgenticError( + AGENTIC_ERROR_CODE.ASSET_CHAIN_MISMATCH, + 'SVM asset source-chain mismatch' + ); + } +} + +export interface SvmWireGrant { + agent: Address; + chainNamespace: `solana:${string}`; + terms: SvmTermsWire; +} + +export async function verifySvmWallet( + runtime: AgenticRuntime, + gen: AgenticGeneration, + wallet: Address +) { + const actual = await resolveWalletGeneration( + runtime.reader, + runtime.network, + wallet + ); + if (actual.addresses.factory !== gen.addresses.factory) + throw new AgenticError( + AGENTIC_ERROR_CODE.GENERATION_UNSUPPORTED, + 'SVM wallet generation mismatch' + ); + await verifyPolicyVersion(runtime.reader, gen); +} + +function session( + gen: AgenticGeneration, + wallet: Address, + owner: Address, + input: SvmWireGrant, + now: number +) { + const agent = getAddress(input.agent); + if (agent === owner) + throw new AgenticError( + AGENTIC_ERROR_CODE.AGENT_IS_OWNER, + 'agent must differ from owner' + ); + const cea = deriveAgwSvmCea(wallet, input.terms.gatewayProgram).address; + if (cea.toLowerCase() !== input.terms.expectedCEA.toLowerCase()) + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'SVM expectedCEA does not belong to this wallet/gateway' + ); + return buildSession({ + validator: gen.addresses.sessionValidator, + rulesPolicy: gen.addresses.rulesPolicy, + agent, + actions: [ + { + target: gen.addresses.gateway, + selector: SEND_OUTBOUND_SELECTOR, + initData: encodeEnvelope( + input.chainNamespace, + encodeSvmTerms(input.terms, now) + ), + }, + ], + }); +} + +export async function grantSvmWire( + runtime: AgenticRuntime, + gen: AgenticGeneration, + wallet: Address, + input: SvmWireGrant +) { + assertCanSign(runtime, 'internal SVM grant'); + await verifySvmWallet(runtime, gen, wallet); + const snap = await Snapshot.at(runtime.reader); + const owner = await assertOwner(runtime, gen, wallet, snap); + await verifyAssets(snap, input); + const s = session(gen, wallet, owner, input, runtime.nowSeconds()); + const nonce = await snap.read( + wallet, + gen.contracts.abis.wallet, + 'grantNonce' + ); + const expected = predictRulesId({ + validator: gen.addresses.sessionValidator, + agent: getAddress(input.agent), + grantNonce: nonce, + }); + let tx; + try { + tx = await runtime.execute({ + to: wallet, + value: BigInt(0), + data: gen.contracts.encodeGrantRules(s), + }); + } catch (error) { + throw wrapSendError(error); + } + const { logs } = await confirmedLogs(runtime, tx); + const granted = gen.contracts.parseRulesGranted(logs, wallet); + if ( + granted.length !== 1 || + granted[0].mode !== 0 || + granted[0].chainNamespace !== input.chainNamespace + ) + throw new AgenticError( + AGENTIC_ERROR_CODE.RECEIPT_MISMATCH, + 'SVM grant receipt did not match this operation', + { details: { txHash: tx.hash, expected } } + ); + // Another owner grant can advance grantNonce between read and inclusion. + // The sole matching event from this receipt is the authoritative ID. + return { rulesId: granted[0].rulesId, tx }; +} + +/** Snapshot -> all-asset assertion -> revoke -> grant. No sequential fallback. */ +export async function prepareSvmReplacement( + runtime: AgenticRuntime, + gen: AgenticGeneration, + wallet: Address, + oldId: Hex, + input: SvmWireGrant +) { + assertCanSign(runtime, 'internal SVM replacement'); + await verifySvmWallet(runtime, gen, wallet); + const snap = await Snapshot.at(runtime.reader); + const owner = await assertOwner(runtime, gen, wallet, snap); + await verifyAssets(snap, input); + const old = await readSvmRule( + snap, + gen, + wallet, + oldId, + runtime.pushChainNamespace + ); + const s = session(gen, wallet, owner, input, runtime.nowSeconds()); + const nonce = await snap.read( + wallet, + gen.contracts.abis.wallet, + 'grantNonce' + ); + const rulesId = predictRulesId({ + validator: gen.addresses.sessionValidator, + agent: getAddress(input.agent), + grantNonce: nonce, + }); + const calls = [ + { + target: gen.addresses.rulesPolicy, + value: BigInt(0), + data: gen.contracts.encodeAssertSpentUniversal( + old.configId, + wallet, + old.config.assets.map((a) => a.spent) + ), + }, + { + target: wallet, + value: BigInt(0), + data: gen.contracts.encodeRevokeRules(oldId), + }, + { + target: wallet, + value: BigInt(0), + data: gen.contracts.encodeGrantRules(s), + }, + ]; + return { + rulesId, + oldId, + snapshotBlock: snap.blockNumber, + data: gen.contracts.encodeExecute(calls), + }; +} + +export async function replaceSvmWire( + runtime: AgenticRuntime, + gen: AgenticGeneration, + wallet: Address, + oldId: Hex, + input: SvmWireGrant +) { + const prepared = await prepareSvmReplacement( + runtime, + gen, + wallet, + oldId, + input + ); + let tx; + try { + tx = await runtime.execute({ + to: wallet, + value: BigInt(0), + data: prepared.data, + }); + } catch (error) { + throw wrapSendError(error); + } + const { logs } = await confirmedLogs(runtime, tx); + const grants = gen.contracts.parseRulesGranted(logs, wallet); + const revokes = gen.contracts.parseRulesRevoked(logs, wallet); + if ( + grants.length !== 1 || + grants[0].mode !== 0 || + grants[0].chainNamespace !== input.chainNamespace || + !revokes.some((r) => r.rulesId.toLowerCase() === oldId.toLowerCase()) + ) + throw new AgenticError( + AGENTIC_ERROR_CODE.RECEIPT_MISMATCH, + 'SVM replacement receipt mismatch', + { details: { txHash: tx.hash } } + ); + return { rulesId: grants[0].rulesId, replaced: oldId, tx }; +} diff --git a/packages/core/src/lib/agentic/reads/svm.ts b/packages/core/src/lib/agentic/reads/svm.ts new file mode 100644 index 00000000..99b8649b --- /dev/null +++ b/packages/core/src/lib/agentic/reads/svm.ts @@ -0,0 +1,98 @@ +/** Internal lossless SVM state. Public Rule mapping stays capability-gated. */ +import type { Address, Hex } from 'viem'; +import type { AgenticGeneration } from '../deployments'; +import type { SvmConfigRead } from '../contracts/v4'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; +import { actionId, configId } from '../codec/ids'; +import { SEND_OUTBOUND_SELECTOR } from '../contracts/v4'; +import { validateSvmTerms } from '../codec/svm-terms'; +import { chainFromHash, readActiveRules, type ActiveRule } from './rules'; +import type { Snapshot } from './snapshot'; + +export interface SvmRuleSnapshot { + wallet: Address; + rulesId: Hex; + agent: Address; + chainNamespace: `solana:${string}`; + configId: Hex; + config: SvmConfigRead; + blockNumber: bigint; +} + +export async function readSvmRule( + snap: Snapshot, + gen: AgenticGeneration, + wallet: Address, + rulesId: Hex, + pushChainNamespace: string +): Promise { + const active = (await readActiveRules(snap, gen, wallet)).find( + (r) => r.rulesId.toLowerCase() === rulesId.toLowerCase() + ); + if (!active) + throw new AgenticError( + AGENTIC_ERROR_CODE.RULE_NOT_FOUND, + `no enabled SVM rule ${rulesId} on ${wallet}` + ); + return readSvmConfig(snap, gen, wallet, active, pushChainNamespace); +} + +export async function readSvmConfig( + snap: Snapshot, + gen: AgenticGeneration, + wallet: Address, + active: ActiveRule, + pushChainNamespace: string +): Promise { + const chain = chainFromHash(active.chainHash, pushChainNamespace); + const expectedAction = actionId( + gen.addresses.gateway, + SEND_OUTBOUND_SELECTOR + ); + if ( + active.mode !== 0 || + active.vm !== 1 || + !chain?.startsWith('solana:') || + active.actionIds.length !== 1 || + active.actionIds[0].toLowerCase() !== expectedAction.toLowerCase() + ) + throw new AgenticError( + AGENTIC_ERROR_CODE.INCONSISTENT_READ, + 'rule is not a single gateway SVM action' + ); + const id = configId(wallet, active.rulesId, active.actionIds[0]); + const cfg = await snap.read( + gen.addresses.rulesPolicy, + gen.contracts.abis.policy, + 'getSvmConfig', + [id, wallet] + ); + try { + if (!cfg.initialized) throw new Error('uninitialized SVM config'); + // Stored expired rules remain readable. Grant-time validation still checks expiry. + validateSvmTerms(cfg, -1); + for (const cap of cfg.assets) { + if ( + typeof cap.spent !== 'bigint' || + cap.spent < BigInt(0) || + cap.spent > cap.maxTotal + ) + throw new Error('invalid stored asset counter'); + } + } catch (cause) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INCONSISTENT_READ, + 'malformed stored SVM config', + { cause } + ); + } + return { + wallet, + rulesId: active.rulesId, + agent: active.agent, + chainNamespace: chain as `solana:${string}`, + configId: id, + config: cfg, + blockNumber: snap.blockNumber, + }; +} diff --git a/packages/core/src/lib/orchestrator/__tests__/outbound-svm-confirmation.spec.ts b/packages/core/src/lib/orchestrator/__tests__/outbound-svm-confirmation.spec.ts new file mode 100644 index 00000000..11f50cc0 --- /dev/null +++ b/packages/core/src/lib/orchestrator/__tests__/outbound-svm-confirmation.spec.ts @@ -0,0 +1,127 @@ +import { Connection } from '@solana/web3.js'; +import bs58 from 'bs58'; +import { CHAIN } from '../../constants/enums'; +import { + waitForOutboundTx, + OutboundFailedError, + OutboundTimeoutError, +} from '../internals/outbound-sync'; +import { OutboundStatus } from '../../generated/uexecutor/v2/types'; +import type { OrchestratorContext } from '../internals/context'; +jest.mock('@solana/web3.js', () => ({ + ...jest.requireActual('@solana/web3.js'), + Connection: jest.fn(), +})); +const bytes = Buffer.alloc(64, 12), + signature = bs58.encode(bytes), + hex = '0x' + bytes.toString('hex'); +const statuses = jest.fn(), + genesis = jest.fn(); +beforeEach(() => { + statuses.mockReset(); + genesis + .mockReset() + .mockResolvedValue(CHAIN.SOLANA_DEVNET.slice(7) + 'abcdefghijk'); + (Connection as unknown as jest.Mock).mockImplementation(() => ({ + getGenesisHash: genesis, + getSignatureStatuses: statuses, + })); +}); +function context(hash: string): OrchestratorContext { + return { + printTraces: false, + pushNetwork: 'TESTNET_DONUT', + rpcUrls: { [CHAIN.SOLANA_DEVNET]: ['http://fixture'] }, + pushClient: { + getCosmosTx: jest.fn().mockResolvedValue({ events: [] }), + getUniversalTxByIdV2: jest + .fn() + .mockResolvedValue({ + universalTx: { + universalStatus: 6, + pcTx: [], + outboundTx: [ + { + destinationChain: CHAIN.SOLANA_DEVNET, + outboundStatus: OutboundStatus.PENDING, + recipient: 'fixture', + amount: '0', + externalAssetAddr: '', + observedTx: { txHash: hash }, + }, + ], + }, + }), + }, + } as unknown as OrchestratorContext; +} +const opts = { initialWaitMs: 0, pollingIntervalMs: 1, timeout: 100 }; +it.each([signature, hex])( + 'confirms pending Cosmos signature %s through Solana RPC', + async (hash) => { + statuses.mockResolvedValue({ + value: [{ confirmationStatus: 'confirmed', err: null }], + }); + const out = await waitForOutboundTx(context(hash), '0xpush', opts); + expect(out.externalTxHash).toBe(hash); + expect(statuses).toHaveBeenCalledWith([signature], { + searchTransactionHistory: true, + }); + } +); +it('waits through processed status before finalization', async () => { + statuses + .mockResolvedValueOnce({ + value: [{ confirmationStatus: 'processed', err: null }], + }) + .mockResolvedValue({ + value: [{ confirmationStatus: 'finalized', err: null }], + }); + await waitForOutboundTx(context(signature), '0xpush', opts); + expect(statuses).toHaveBeenCalledTimes(2); +}); +it('reports a confirmed signature error as failure, preserving the hash', async () => { + statuses.mockResolvedValue({ + value: [ + { + confirmationStatus: 'confirmed', + err: { InstructionError: [0, 'Custom'] }, + }, + ], + }); + await expect( + waitForOutboundTx(context(hex), '0xpush', opts) + ).rejects.toMatchObject({ code: 'OUTBOUND_FAILED', externalTxHash: hex }); +}); +it.each([ + 'wrong-cluster', + 'missing', + 'processed-error', + 'rpc-error', + 'malformed-hash', +])('keeps %s pending until timeout', async (kind) => { + statuses.mockResolvedValue({ value: [null] }); + if (kind === 'wrong-cluster') genesis.mockResolvedValue('wrong'); + if (kind === 'processed-error') + statuses.mockResolvedValue({ + value: [{ confirmationStatus: 'processed', err: { failure: true } }], + }); + if (kind === 'rpc-error') + statuses.mockRejectedValue(new Error('RPC unavailable')); + const hash = kind === 'malformed-hash' ? '0x1234' : signature; + await expect( + waitForOutboundTx(context(hash), '0xpush', { ...opts, timeout: 20 }) + ).rejects.toBeInstanceOf(OutboundTimeoutError); + if (kind === 'wrong-cluster' || kind === 'malformed-hash') + expect(statuses).not.toHaveBeenCalled(); +}); +it('keeps an authoritative Cosmos revert ahead of the RPC tiebreaker', async () => { + const ctx = context(signature); + (ctx.pushClient.getUniversalTxByIdV2 as jest.Mock).mockResolvedValue({ + universalTx: { universalStatus: 8, pcTx: [], outboundTx: [] }, + }); + await expect(waitForOutboundTx(ctx, '0xpush', opts)).rejects.toBeInstanceOf( + OutboundFailedError + ); + expect(statuses).not.toHaveBeenCalled(); +}); diff --git a/packages/core/src/lib/orchestrator/internals/outbound-sync.ts b/packages/core/src/lib/orchestrator/internals/outbound-sync.ts index 56089d9b..f9cb9831 100644 --- a/packages/core/src/lib/orchestrator/internals/outbound-sync.ts +++ b/packages/core/src/lib/orchestrator/internals/outbound-sync.ts @@ -7,6 +7,8 @@ import { resolvePC20WrapperForReceipt } from './pc20/tracking'; import { createPublicClient, fallback, http } from 'viem'; +import { Connection } from '@solana/web3.js'; +import bs58 from 'bs58'; import { CHAIN_INFO, VM_NAMESPACE } from '../../constants/chain'; import { CHAIN, VM } from '../../constants/enums'; import { UniversalTxStatus } from '../../generated/uexecutor/v1/types'; @@ -113,15 +115,15 @@ export class OutboundFailedError extends Error { * (preserves the silent-success bug fix); if no receipt yet or RPC failure, * we keep polling. * - * EVM-only — SVM tiebreaker would need a separate signature lookup path. + * EVM receipts and confirmed/finalized Solana signatures are supported. */ -async function verifyExternalEvmReceipt( +async function verifyExternalReceipt( ctx: OrchestratorContext, destinationChain: CHAIN, externalTxHash: string ): Promise<'success' | 'reverted' | 'pending' | 'unsupported'> { const chainInfo = CHAIN_INFO[destinationChain]; - if (!chainInfo || chainInfo.vm !== VM.EVM) { + if (!chainInfo || (chainInfo.vm !== VM.EVM && chainInfo.vm !== VM.SVM)) { return 'unsupported'; } // Guard against unit-test contexts that don't pass a real rpcUrls map — @@ -133,6 +135,52 @@ async function verifyExternalEvmReceipt( : chainInfo.defaultRPC; if (!rpcUrls?.length) return 'unsupported'; + if (chainInfo.vm === VM.SVM) { + let signature: string; + try { + const bytes = externalTxHash.startsWith('0x') + ? /^0x[0-9a-fA-F]{128}$/.test(externalTxHash) + ? Buffer.from(externalTxHash.slice(2), 'hex') + : new Uint8Array() + : bs58.decode(externalTxHash); + if (bytes.length !== 64) return 'pending'; + signature = bs58.encode(bytes); + } catch { + return 'pending'; + } + for (const url of rpcUrls) { + try { + const connection = new Connection(url, 'confirmed'); + if ( + `solana:${(await connection.getGenesisHash()).slice(0, 32)}` !== + destinationChain + ) + continue; + const result = await connection.getSignatureStatuses([signature], { + searchTransactionHistory: true, + }); + const status = result.value[0]; + // A processed vote can still disappear. Never report success/failure + // before the signature is confirmed or finalized on the right cluster. + if ( + !status || + (status.confirmationStatus !== 'confirmed' && + status.confirmationStatus !== 'finalized') + ) + return 'pending'; + return status.err ? 'reverted' : 'success'; + } catch (error) { + printLog( + ctx, + `[verifyExternalReceipt] SVM RPC unavailable: ${ + error instanceof Error ? error.name : 'unknown' + }` + ); + } + } + return 'pending'; + } + try { const client = createPublicClient({ transport: fallback(rpcUrls.map((url) => http(url))), @@ -153,7 +201,7 @@ async function verifyExternalEvmReceipt( } printLog( ctx, - `[verifyExternalEvmReceipt] RPC error for ${destinationChain} tx ${externalTxHash}: ${msg}` + `[verifyExternalReceipt] RPC error for ${destinationChain} tx ${externalTxHash}: ${msg}` ); return 'pending'; } @@ -397,7 +445,7 @@ export async function waitForOutboundTx( ob.outboundStatus === OutboundStatus.OBSERVED; if (!isCosmosObserved) { // Tiebreaker: ask the destination-chain RPC directly. - const verdict = await verifyExternalEvmReceipt( + const verdict = await verifyExternalReceipt( ctx, chain, ob.observedTx.txHash @@ -468,11 +516,10 @@ export async function waitForOutboundTx( // created, and a repeat export deploys no wrapper so nothing is // ever observed to backfill it. Resolve from UniversalCore instead, // keyed by the Push-native source token. - const pc20Wrapper = await resolvePC20WrapperForReceipt( - ctx, - ob, - { network: ctx.pushNetwork, rpcUrls: ctx.rpcUrls } - ); + const pc20Wrapper = await resolvePC20WrapperForReceipt(ctx, ob, { + network: ctx.pushNetwork, + rpcUrls: ctx.rpcUrls, + }); const details: OutboundTxDetails = { externalTxHash: ob.observedTx.txHash, destinationChain: chain, @@ -738,7 +785,7 @@ export async function waitForAllOutboundTxsV2( const isCosmosObserved = ob.outboundStatus === OutboundStatus.OBSERVED; if (!isCosmosObserved) { - const verdict = await verifyExternalEvmReceipt( + const verdict = await verifyExternalReceipt( ctx, chain, externalTxHash diff --git a/packages/core/src/lib/orchestrator/svm-idl/resolve.ts b/packages/core/src/lib/orchestrator/svm-idl/resolve.ts index 444b7760..dbcc2792 100644 --- a/packages/core/src/lib/orchestrator/svm-idl/resolve.ts +++ b/packages/core/src/lib/orchestrator/svm-idl/resolve.ts @@ -43,6 +43,16 @@ const CEA_AUTHORITY_NAMES = new Set([ ]); export function resolveSvmCall(input: ResolveInput): ResolvedSvmCall { + return resolveCall(input); +} + +/** Internal AGW seam: use its registry-derived authority, not the signer's CEA. */ +export function resolveSvmCallForCea(input: ResolveInput, ceaAuthority: `0x${string}`): ResolvedSvmCall { + if (!/^0x[0-9a-fA-F]{64}$/.test(ceaAuthority)) throw new Error('SVM CEA authority must be 32 bytes'); + return resolveCall(input, ceaAuthority); +} + +function resolveCall(input: ResolveInput, authority?: `0x${string}`): ResolvedSvmCall { const idl = getIdl(input.programAddress); if (!idl) { throw new Error( @@ -74,11 +84,7 @@ export function resolveSvmCall(input: ResolveInput): ResolvedSvmCall { const programPk = new PublicKey( Buffer.from(input.programAddress.slice(2), 'hex') ); - const { address: ceaPdaHex } = deriveSvmCeaPda( - input.senderUea, - input.targetChain, - true - ); + const ceaPdaHex = authority ?? deriveSvmCeaPda(input.senderUea, input.targetChain, true).address; const accounts: SvmGatewayAccountMeta[] = []; for (const item of ix.accounts) { diff --git a/plan/agw/README.md b/plan/agw/README.md index 6d9d24ae..e90148dc 100644 --- a/plan/agw/README.md +++ b/plan/agw/README.md @@ -2,7 +2,7 @@ This package contains the SDK implementation plan, source snapshots, open decisions and validation evidence. Current work is on feat/agw-sdk-v4. Runtime commits are a66ff7d (v4/SVM foundations) and b68bab7 (gas headroom); current validation is linked below. Native/EVM support now uses the checked Donut v4 deployment; old runtime adapters/ABIs/fixtures were removed. All 25 registered AGW scenarios have passing bounded live coverage, including native/UEA identities and Sepolia outbound success/failure. -Latest: [live acceptance and fixes](research/live-acceptance-2026-10-06/README.md), following the [v4 migration](research/v4-implementation-2026-10-06/README.md). The unrestricted full core unit run passes 1,947 tests; the actual-contract harness passes 59. Build and four typechecks pass. Native defaults/raw-offset API/multi-rule selection decisions, absent ref/labels, public SVM integration and release scope remain explicit. +Latest: [live acceptance and fixes](research/live-acceptance-2026-10-06/README.md), following the [v4 migration](research/v4-implementation-2026-10-06/README.md). The unrestricted full core unit run passes 1,975 tests; the actual-contract harness passes 68. Build and four typechecks pass. Native defaults/raw-offset API/multi-rule selection decisions, absent ref/labels, public SVM integration and release scope remain explicit. The public target remains [Notion page 5](notion/5-sdk-agw.md), qualified by [Harsh's replies](product-decisions-2026-10-04.md) and [live comments](research/notion-comments-2026-10-05.md). The [v4 deployment/owner-guide review](research/deployment-review-2026-10-06/README.md) records the supplied deployed wire definitions. Historical adapter-absence statements in that review describe the pre-migration inspection, not current implementation. @@ -10,6 +10,8 @@ Latest SVM work: [internal codec/account/payload foundation](research/svm-intern Latest SDK-owned work: [delayed-index contract acceptance and checked consumer guide](research/sdk-independent-followup-2026-10-06/README.md). No public API decision was changed by this follow-up. +Latest: [all nine SDK-owned items completed](research/sdk-independent-completion-2026-10-06/README.md). Internal SVM integration, Solana confirmation, CI and package/API checks are complete; public SVM remains gated. + ## Start here | Document | Purpose | diff --git a/plan/agw/current-baseline.md b/plan/agw/current-baseline.md index ff75862c..131c11fa 100644 --- a/plan/agw/current-baseline.md +++ b/plan/agw/current-baseline.md @@ -61,7 +61,7 @@ The ABI comparison found matching factory/wallet/engine function/event/error sig Four checks passed: version-1 envelope round-trip/old first-word incompatibility; synthetic ordered two-asset tuple round-trip; live v4 getConfig decode with old-ABI rejection; array assertion encoding. [Results and limits](research/deployment-review-2026-10-06/wire-checks.json). This is not a rule-grant, stale-spend transaction or funded E2E proof. -The unrestricted run passes 1,947 unit and 59 actual-contract tests. All five explorer ABI sets match the isolated build. Donut is registered and all 25 registered native/EVM/identity cases have passing coverage. [Current acceptance evidence](research/live-acceptance-2026-10-06/README.md). +The unrestricted run passes 1,975 unit and 68 actual-contract tests. All five explorer ABI sets match the isolated build. Donut is registered and all 25 registered native/EVM/identity cases have passing coverage. [Current acceptance evidence](research/live-acceptance-2026-10-06/README.md). ## Remaining decisions and acceptance diff --git a/plan/agw/external-blockers.md b/plan/agw/external-blockers.md index ce37bb55..45c224a0 100644 --- a/plan/agw/external-blockers.md +++ b/plan/agw/external-blockers.md @@ -47,3 +47,5 @@ Notion's last full export remains October 3, with focused October 4 body and Oct ## SDK-owned follow-up completed The [independent SDK follow-up](research/sdk-independent-followup-2026-10-06/README.md) closes deliberate delayed-index replay/wait coverage using real local transactions/receipts and controlled indexer responses. The consumer AGW guide and public-export example checker are supplied. Neither change chooses unresolved defaults, raw-offset authoring or a multiple-rule selection API. + +The [nine-item completion report](research/sdk-independent-completion-2026-10-06/README.md) records the finished internal SVM integration and automated checks. These are no longer missing SDK backend components; public adapters/capability enablement and live destination acceptance remain after the external decisions. diff --git a/plan/agw/gaps.md b/plan/agw/gaps.md index e0047614..00d6f2fd 100644 --- a/plan/agw/gaps.md +++ b/plan/agw/gaps.md @@ -2,7 +2,7 @@ Updated October 6, 2026 after the [v4 deployment/owner-guide review](research/deployment-review-2026-10-06/README.md), [Harsh’s replies](product-decisions-2026-10-04.md), v4 implementation on feat/agw-sdk-v4, and [live Notion comments](research/notion-comments-2026-10-05.md). This register distinguishes unresolved dependencies, implemented SDK work, deferred scope and historical corrections. G01–G26 are tracking IDs, not a count of open defects. -Evidence: [current baseline](current-baseline.md), [implementation status](implementation-status.md), [product alignment validation](research/product-alignment-2026-10-04/README.md). The unrestricted v4 SDK run passes 1,947 unit tests and 59 local-contract tests. All 25 registered live scenarios have passing coverage. The independent SDK follow-up adds delayed-index actual-contract checks and consumer documentation; public SVM destinations remain gated. +Evidence: [current baseline](current-baseline.md), [implementation status](implementation-status.md), [product alignment validation](research/product-alignment-2026-10-04/README.md). The unrestricted v4 SDK run passes 1,975 unit tests and 68 local-contract tests. All 25 registered live scenarios have passing coverage. The independent SDK follow-up adds delayed-index actual-contract checks and consumer documentation; public SVM destinations remain gated. Current contract baseline: reported deployed source `e8db748`, documentation head `deploy-agw@10a24f1` (src unchanged between them). Donut v4 addresses/code/wiring and URP 3.1.0 were checked at block 23931055; verified ABIs were saved. The SDK now uses v4 only, registers Donut and has a ported actual-contract harness. [Implementation evidence](research/v4-implementation-2026-10-06/README.md). Core marketplace cb69e0b and gateway bcbf7df remain prior source pins; they were not freshly fetched. Notion bodies were not refreshed in this pass. @@ -46,7 +46,7 @@ P0 blocks agreed authorization/accounting or safe final integration. P1 affects | G19 | P0/P1 | Universal defaults implemented; H3 native choices open | Universal omission uses maxUint256 and explicit zero is hard zero; empty input gets a gas-token 0/0 route. Native defaults remain provisional. | Clarify H3 native/public fields and token wording; retain UI-owned approval policy. | | G20 | P1 | V4 composer/response and live EVM acceptance pass | Uses selected listed token, maxGasPerCall, wallet CEA/refund context, separate allowance and signer gas. Local requests pass actual URP with fixture gateway. | Production token debit, node/TSS delivery, CEA execution attribution/balance, replay identity and destination-revert classification pass. Public SVM integration remains tracked under G22. | | G21 | P1 | Product direction resolved; batching implemented locally | NativeRule remains one action. Arrays use a sender-preserving UEA/7702 outer batch of single executeAsAgent calls, each checked by policy. Native sequential fallback is prohibited. Local real-type-4 tests prove sender identity, cumulative counters and mined rollback. | Release-deployment UEA identities and native 7702 batch/rollback cases pass. The local executor is a fixture; arbitrary forwarding helpers are not a substitute for the agent account. | -| G22 | P1 | SVM internals implemented; public integration pending | Wire codec, wallet/ATA coverage, payload pins and internal outbound builder pass 23 unit cases, 10 actual-contract Foundry checks and 7 Anvil SDK cases. | Agree public mapping, connect registry/IDL inputs and dispatch/tracking; run live Solana acceptance after public integration. | +| G22 | P1 | SVM backend completed; public integration pending | Internal read/context/mint/IDL/lifecycle/execution pipeline is complete. New unit and actual-contract backend tests pass; shared Solana confirmation supports indexer lag. Public capability remains gated. | Agree public authoring/read/display mapping, connect public adapters to the completed backend, enable capability and run live Solana acceptance with confirmed cluster inputs. | | G23 | P0 | V4 EVM integration verified locally and live | Multi-asset codecs/reads/outbound, envelope 1, source chain/token identity, hard-zero semantics and empty-input routing are implemented. Old adapter/ABIs/fixtures removed. | Registered EVM acceptance passes. Public SVM SDK mapping/composition remains. | | G24 | P1 | Internal per-token update verified locally and live | Reads/stores every expected counter in asset order; array assertion catches intervening second-token spend. Public spent stays absent. | Live two-asset replacement passes; public SVM integration remains. | | G25 | P1 | Public raw-offset decision open | Exact native pin/amount offsets and EVM beneficiaryOffset are returned/accepted losslessly; no invented argument indexes. This extends the target input shape. | H4.5: public raw authoring versus separate decoded wire records. | @@ -54,7 +54,7 @@ P0 blocks agreed authorization/accounting or safe final integration. P1 affects ## Validation and release boundaries -The [current acceptance evidence](research/live-acceptance-2026-10-06/README.md) records 1,947 passing unit tests, 59 actual-contract tests, build/four typechecks and seven existing lint errors. All 25 opt-in AGW scenarios have passing bounded selected-run coverage; default all remains 76. Native/UEA/7702, lifecycle, allowance, responses and Sepolia success/failure pass. The initial positive-amount Push transaction exposed insufficient gas headroom. A tested 20% headroom fix passes the bounded retry, including token debit, allowance reduction, destination receipt/CEA balance and replay checks. Destination-revert classification also passes. +The [current acceptance evidence](research/live-acceptance-2026-10-06/README.md) records 1,975 passing unit tests, 68 actual-contract tests, build/four typechecks and seven existing lint errors. All 25 opt-in AGW scenarios have passing bounded selected-run coverage; default all remains 76. Native/UEA/7702, lifecycle, allowance, responses and Sepolia success/failure pass. The initial positive-amount Push transaction exposed insufficient gas headroom. A tested 20% headroom fix passes the bounded retry, including token debit, allowance reduction, destination receipt/CEA balance and replay checks. Destination-revert classification also passes. Local batch proof uses actual AGW/factory/engine/policy and real Anvil EIP-7702 transactions, with a small fixture executor. UEA shaping/replay is unit-tested and reuses the existing transport; all registered native/EVM/UEA acceptance scenarios now pass. Public Solana destination coverage remains outstanding. diff --git a/plan/agw/implementation-plan.md b/plan/agw/implementation-plan.md index 67915d52..eb265eab 100644 --- a/plan/agw/implementation-plan.md +++ b/plan/agw/implementation-plan.md @@ -1,6 +1,6 @@ # Complete AGW SDK implementation plan -Updated October 6, 2026. The v4-only native/EVM implementation uses deployed source e8db748 and the Donut manifest. Old runtime/test adapters and single-asset codecs are removed. The unfiltered unit suite passes 1,947 tests; all 59 actual-contract Anvil cases pass; build and four typechecks pass. All 25 registered AGW live scenarios pass across selected runs; remaining work is public SVM integration and release scope decisions. [Current acceptance and remaining coverage](research/live-acceptance-2026-10-06/README.md). +Updated October 6, 2026. The v4-only native/EVM implementation uses deployed source e8db748 and the Donut manifest. Old runtime/test adapters and single-asset codecs are removed. The unfiltered unit suite passes 1,975 tests; all 68 actual-contract Anvil cases pass; build and four typechecks pass. All 25 registered AGW live scenarios pass across selected runs; remaining work is public SVM integration and release scope decisions. [Current acceptance and remaining coverage](research/live-acceptance-2026-10-06/README.md). SVM internal terms/accounts/payload/builder are implemented and validated. Public SVM mapping/dispatch remains gated. Remaining decisions are H3 native defaults, H4.5 raw-offset public shape, H6 send selection and ref/label v1 scope. Earlier plan recommendations below are qualified by those accepted decisions and the current implementation status. diff --git a/plan/agw/implementation-review-handoff.md b/plan/agw/implementation-review-handoff.md index 3322cb92..b385678c 100644 --- a/plan/agw/implementation-review-handoff.md +++ b/plan/agw/implementation-review-handoff.md @@ -1,5 +1,7 @@ # AGW SDK implementation — review handoff +> Latest: [nine SDK-owned tasks completed](research/sdk-independent-completion-2026-10-06/README.md), including internal SVM integration and shared confirmation. 1,975 units and 68 actual-contract tests pass. Public SVM and pending product choices remain gated; automated API comparison is saved. + > Latest SDK-owned follow-up: [six delayed-index contract cases, checked consumer examples and package documentation](research/sdk-independent-followup-2026-10-06/README.md). All 59 local actual-contract cases pass; the prior 25 live scenarios remain passing evidence. Public SDK APIs and pending decisions are unchanged by this follow-up. > Latest acceptance: [October 6 funded tests and fixes](research/live-acceptance-2026-10-06/README.md). Network restrictions are resolved; all 53 Anvil cases and the unfiltered unit suite pass. All 25 registered AGW scenarios have passing selected-run coverage; public SVM destination integration and scope decisions remain. Changes are on feat/agw-sdk-v4. Everything below the current banners describes historical implementation/review evidence. diff --git a/plan/agw/implementation-status.md b/plan/agw/implementation-status.md index d3dc73c6..1aa2bbb9 100644 --- a/plan/agw/implementation-status.md +++ b/plan/agw/implementation-status.md @@ -1,6 +1,6 @@ # AGW SDK implementation status -> Latest: [funded acceptance and fixes](research/live-acceptance-2026-10-06/README.md). Full permissions are restored: 1,947 unfiltered unit tests, all 59 Anvil cases, build and four typechecks pass. All 25 registered AGW scenarios pass across selected live runs, including UEA identities, native 7702 batches, lifecycle and Sepolia success/failure. Public SVM destinations remain gated. +> Latest: [funded acceptance and fixes](research/live-acceptance-2026-10-06/README.md). Full permissions are restored: 1,975 unfiltered unit tests, all 68 Anvil cases, build and four typechecks pass. All 25 registered AGW scenarios pass across selected live runs, including UEA identities, native 7702 batches, lifecycle and Sepolia success/failure. Public SVM destinations remain gated. Updated October 6, 2026. Branch feat/agw-sdk-v4; runtime commits a66ff7d and b68bab7. The native/EVM migration uses deployed source e8db748. Runtime/test e704d5b adapters, ABIs and fixtures were removed at Shoaib's request; historical review documents are evidence only. [Full handoff, commands and validation](research/v4-implementation-2026-10-06/README.md). @@ -8,8 +8,8 @@ Updated October 6, 2026. Branch feat/agw-sdk-v4; runtime commits a66ff7d and b68 | Level | Current evidence | | --- | --- | -| Unit | 1,947 passed, 0 failed; 12 skipped; 113 suites passed, 1 skipped | -| Local actual contracts | 59 passed, 0 failed; 8 suites against e8db748 on Anvil | +| Unit | 1,975 passed, 0 failed; 12 skipped; 115 suites passed, 1 skipped | +| Local actual contracts | 68 passed, 0 failed; 9 suites against e8db748 on Anvil | | ABI reproduction | All 5 explorer ABI entry sets match the isolated build, ignoring array order | | Build/typechecks | Build and lib/spec/local/AGW-E2E typechecks pass | | Lint | 7 pre-existing errors in unchanged files; no new errors | @@ -26,14 +26,14 @@ Local gateway/core/token/executor and CEA lookup are fixtures. Actual AGW/factor | 2 | Namespace/types/errors | Implemented; AMBIGUOUS_RULE replaces duplicate-authoring rejection | H4.5 public raw-offset boundary | | 3 | Signer/wallet context | Owner/agent/read-only/identity guards retained | Release review; UEA identity cases pass | | 4 | Registry/adapter | Donut v4 registered; unsupported networks fail | Release review; no legacy fallback | -| 5 | Wallet/checkpoint/rule reads | Native and EVM reads implemented; source tokens/beneficiary offsets reconstructed | Metadata scope; SVM reads/public mapping | +| 5 | Wallet/checkpoint/rule reads | Native and EVM reads implemented; source tokens/beneficiary offsets reconstructed | Metadata scope; public SVM mapping (internal reads complete) | | 6 | Normalization/codecs | Native/EVM envelope 1, ordered caps, hard-zero/max total, empty-list routing | Native H3 defaults; SVM public mapping | | 7 | Create/add/revoke | Index-bound create, partial recovery, atomic writes; same-agent multiples allowed | Release review; deployed create/identity/batching paths verified | -| 8 | Atomic update | Native per-action and universal all-token assertions before revoke/grant | Public SVM wrapper | +| 8 | Atomic update | Native per-action and universal all-token assertions before revoke/grant | Public SVM authoring wrapper (internal lifecycle complete) | | 9 | Owner/allowance | Owner path unrestricted; explicit separate allowance retained | Release review; production allowance/token debit and delivery verified | | 10 | Native agent sends | Sender-preserving atomic batches retained | H6 selection for multiple matching rules | | 11 | EVM outbound | V4 asset membership, maxGasPerCall, wallet CEA/refunds, signer gas and responses | Release review; Sepolia success/failure and UEA cases verified | -| 12 | SVM destinations | Source wire types delivered; SDK capability remains gated | Internal codec/accounts/payload/builder delivered; public mapping/dispatch and cluster acceptance | +| 12 | SVM destinations | Source wire types delivered; SDK capability remains gated | Internal reads/context/IDL/wire lifecycle/execution complete; public mapping/display/dispatch enablement and live cluster acceptance | | 13 | Responses/progress/errors | V4 ABIs and prior canonical replay/wait fixes retained | Delayed-index replay/polling tested with real contracts/receipts; no remaining SDK-owned response gap | | 14 | E2E | 25 opt-in scenarios registered; public universal setup and new two-token/call-only cases | Completed native/EVM live coverage; public SVM acceptance after integration | | 15 | Web2 | Prior implementation retained and included in full unit run | Consumer migration notes supplied; existing Web2 unit acceptance passes | diff --git a/plan/agw/research/sdk-independent-completion-2026-10-06/README.md b/plan/agw/research/sdk-independent-completion-2026-10-06/README.md new file mode 100644 index 00000000..059c29d2 --- /dev/null +++ b/plan/agw/research/sdk-independent-completion-2026-10-06/README.md @@ -0,0 +1,56 @@ +# Nine SDK-owned items — completion report + +October 6, 2026. Branch feat/agw-sdk-v4. This completes the nine approved SDK-owned tasks without selecting H3/H4.5/H6 behavior or enabling public Solana destinations. Contract source remains e8db748; no contract checkout was edited. + +| Item | Completion and files | +| --- | --- | +| 1 Internal SVM reads | reads/svm.ts decodes the verified getter, verifies mode/action/config shape, retains expired enabled rules and returns ordered counters and the pinned block. Actual-contract round-trip/read/revoke coverage passes. | +| 2 Context/asset resolution | management/svm-context.ts and svm-metadata.ts validate PRC20 source chains, native gas-token identity, mint ownership/initialization, configured cluster genesis, and registry/mint substitutions. Every listed/output mint contributes its correctly resolved SPL/Token-2022 ATA. Missing cluster/gateway configuration fails explicitly. | +| 3 Instruction integration | execution/svm-instruction.ts connects the existing IDL resolver with the wallet's configured CEA authority. Explicit wire-account input supports non-Anchor/dataless instructions. The existing payload/pin/alias validator is applied to both. No guessed public authoring form. | +| 4 Internal lifecycle | management/svm.ts verifies wallet generation/version and owner, prepares explicit-wire grants, and performs all-asset assert/revoke/grant in one owner execution. Revoke uses the existing owner path. Receipt events provide actual IDs if another owner grant advances the nonce. Atomic update, five checkpoints, second-asset race rollback and initialization failure rollback pass against real contracts. | +| 5 Prepared execution | execution/svm-send.ts connects verified wallet/rule/signer identity, resolved context, payload, current quote, PC/token/allowance/gas checks and executeAsAgent wrapping. It returns raw signer response plus internal wire context; public SVM display/types are not invented. No automatic approval. | +| 6 Confirmation/tracking | Shared outbound-sync now verifies pending Solana observations through the selected cluster's RPC, supporting base58 and raw 64-byte hex signatures. Only confirmed/finalized outcomes settle; processed/missing/wrong-cluster/RPC-error cases keep polling. Confirmed errors preserve failure/hash. Authoritative Cosmos failure still wins. | +| 7 Automated regression | agw-sdk-validation.yml adds an unfunded PR/manual job with a pinned public contract checkout and Foundry version. agw-verify.js runs focused units, types, guide, prepared contracts, actual local tests, build and package/API checks. Logs capture stdout/stderr. Existing funded workflow stays manual. | +| 8 Harness cleanup | Waits for SDK account-status reads and Anvil exit, with bounded SIGKILL fallback. The warning was traced to viem's scheduled 4-second poll sleeps surviving unwatch, not unclosed contract transactions. Local clients use 25ms polling through real RPC/actions; production defaults stay unchanged. All nine suites exit without warning or forceExit. | +| 9 Package/API checks | check-agw-package.js validates CJS/ESM imports, guide examples against built declarations and npm dry-run contents. check-agw-api.js compares source/declarations and reports session-baseline root exports, AGW types, initialize and constants. These tools report changes rather than approving pending API decisions. | + +All listed code paths are internal except the shared Solana confirmation improvement and developer tooling. Internal files are not exported from the package root; UNIVERSAL_SVM_RULES is still absent from advertised capabilities. + +## Validation + +| Check | Final result | +| --- | --- | +| Full unfiltered unit suite | 1,975 passed, 0 failed; 12 existing skips; 115 suites passed, 1 skipped | +| New focused SVM/confirmation unit cases | 28 passed | +| Actual local contracts | 68 passed, 0 failed; 9 suites; no open-handle warning/forceExit | +| New backend actual-contract cases | 9 passed | +| Library/spec/local typechecks | Pass via unfunded command | +| Guide | 7 blocks typecheck without execution | +| Build, package imports/declarations/contents | Pass | +| Changed-file lint | 0 errors; 49 existing-style non-null/unused warnings across inspected tests/shared files | +| Workflow definition | YAML parses; read-only permissions; no wallet-key secrets; pinned contract source/Foundry | +| Local CI-equivalent command | Completes successfully; GitHub-hosted job has not been run yet | +| Prior live acceptance | 25 distinct registered native/EVM/UEA scenarios passed previously; not repeated or counted as new SVM settlement | + +[Logs](logs/). Local tests use actual factory/wallet/engine/validator/URP; token/core/gateway and metadata/indexer/destination observations are fixtures. They prove SDK preflight, wrapping and contract enforcement, not Solana CPI/TSS settlement. This work did not load .env keys, broadcast funded transactions, deploy live contracts or publish npm. + +The cluster check follows [Solana CAIP-2 genesis-prefix resolution](https://namespaces.chainagnostic.org/solana/caip2). CI uses the official [Foundry toolchain action](https://github.com/foundry-rs/foundry-toolchain) and the pinned [public contract source](https://github.com/pushchain/push-agentic-wallets/tree/e8db74815cfbbf5389593805e464fe8d85f7f735). + +## API impact + +[Automated comparison](api-comparison.json) against b1597b9: no added/removed root exports and no changed initialize signature. The changed root-visible AGW types are AGENTIC_ERROR_CODE (DUPLICATE_RULE → AMBIGUOUS_RULE) and AllowedCall (beneficiaryOffset). Donut agentic constants also changed. Those differences were introduced in the earlier v4 migration, not this backend batch. Native defaults/public raw authoring/multiple-rule selection remain unresolved. + +Behavioral changes in this batch: Solana observations can settle from a confirmed/finalized destination RPC while Cosmos lags; wrong-cluster or processed observations cannot settle. The existing public method/receipt shapes remain. Internal wire requests can be executed by the backend tests, but public AGW Solana sends remain capability-gated. Existing public IDL resolution retains its default authority; only the internal AGW seam supplies the wallet's authority. + +## What still needs external input or later integration + +H3 native defaults/token wording, H4.5 public raw-offset shape, H6 multi-rule selection, ref/label v1 delivery/deferral and live SVM cluster fixtures remain. Once the SVM authoring/read model is agreed, connect it to the completed backend, agree public response presentation, enable the capability and run live Solana destination acceptance. creditRevert still needs the platform executor; nothing here restores spend automatically. + +## Reproduction + +```sh +AGW_LOCAL_DIR="${TMPDIR:-/tmp}/push-agw-local-v4" node packages/core/scripts/agw-verify.js +node node_modules/jest/bin/jest.js --config packages/core/jest.config.ts --runInBand +``` + +The verification command never invokes funded E2Es or publication. AGW_REPO can point at the read-only pinned contract checkout; an absent local build is prepared in an isolated output directory. diff --git a/plan/agw/research/sdk-independent-completion-2026-10-06/api-comparison.json b/plan/agw/research/sdk-independent-completion-2026-10-06/api-comparison.json new file mode 100644 index 00000000..28ed42bd --- /dev/null +++ b/plan/agw/research/sdk-independent-completion-2026-10-06/api-comparison.json @@ -0,0 +1,1360 @@ +{ + "baseline": "b1597b91a25dbf7f691f589b4e1e154add604315", + "head": "7356346dad53cf8031a0e06732050576a1d05d77", + "compiledMatchesSource": true, + "initializeSignatureChanged": false, + "addedExports": [], + "removedExports": [], + "changedAgwTypes": [ + "AGENTIC_ERROR_CODE", + "AllowedCall" + ], + "agwConstantsChanged": true, + "before": { + "exports": [ + "AGENTIC_ERROR_CODE", + "AccountRole", + "AccountStatus", + "AccountType", + "AgenticAddress", + "AgenticDoor", + "AgenticError", + "AgenticErrorCode", + "AgenticHex", + "AgenticNamespace", + "AgenticNetworkConstants", + "AgenticProgressHook", + "AgenticRevertError", + "AgenticTxMetadata", + "AgenticWallet", + "AllowedCall", + "AssetCap", + "BatchReadResponse", + "BuildReadSpecParams", + "CHAIN", + "CONTRACT_REQUEST_STATUS", + "CascadeCompletionResult", + "CascadeHopInfo", + "CascadeProgressEvent", + "CascadeTrackOptions", + "CascadedTxResponse", + "ChainSource", + "ChainTarget", + "Checkpoint", + "CheckpointKind", + "ConversionQuote", + "CreateOptions", + "CreateResult", + "DEFAULT_MAX_PC_FOR_GAS_BUFFER_BPS", + "DecodedErrorPayload", + "DecodedReadResult", + "DerivedExecutorAccount", + "EncodedReadQuery", + "EvmReadQuery", + "ForeignChainNamespace", + "FulfilOutcome", + "FundsToken", + "InsufficientPC20BalanceError", + "InvalidPC20AddressError", + "InvalidPC20MetadataError", + "InvalidReadQueryError", + "InvalidReadSpecError", + "MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT", + "MaxPCForGasCapFromNativeValueInput", + "MaxPCForGasCapInput", + "MaxPCForGasCapQuote", + "MultiChainTxResponse", + "NativeRule", + "OutboundTxDetails", + "PC20AddressResult", + "PC20AmbiguousAddressError", + "PC20Error", + "PC20ExpectedButPRC20Error", + "PC20ExportRevertedError", + "PC20FactoryMismatchError", + "PC20RegistryEntry", + "PC20RegistryMismatchError", + "PC20TokenChainMismatchError", + "PC20TokenReference", + "PC20UnknownChainNamespaceError", + "PC20UnsafeEmptyPayloadError", + "PC20WrapperNotRegisteredError", + "PC20WrapperPredictionUnavailableError", + "ParsedReadRequest", + "PreparedRead", + "PreparedUniversalTx", + "PushChain", + "PushChainBatchExecutionError", + "PushChainExecutionError", + "PushChainInitializeOptions", + "READ_ERROR_CODE", + "READ_OUTCOME", + "READ_STATUS", + "ReadCallback", + "ReadCallbackOptions", + "ReadChain", + "ReadDecodeError", + "ReadDestination", + "ReadExecuteOptions", + "ReadFees", + "ReadHeightUnavailableError", + "ReadLifecycleOptions", + "ReadNotFoundError", + "ReadOptions", + "ReadPreflight", + "ReadPrepareOptions", + "ReadQuery", + "ReadQueryOptions", + "ReadRef", + "ReadRegistryUnavailableError", + "ReadResponseTuple", + "ReadResultShape", + "ReadSpec", + "ReadSpecTuple", + "ReadSpecViolation", + "ReadStateError", + "ReadTimeoutError", + "ReadTrackOptions", + "ReadValue", + "ReadWeb2Options", + "ReceiptLike", + "RescueFundsParams", + "ResolvedAccount", + "ResolvedControllerAccounts", + "ResolvedDestination", + "Rule", + "RulesRecord", + "Selector", + "SignAuthorizationParams", + "SignedAuthorization", + "SimulateReadResult", + "SvmExecutePayloadFields", + "SvmGatewayAccountMeta", + "SvmReadQuery", + "TERMINAL_READ_STATUSES", + "TransactionRoute", + "TransactionRouteType", + "UEAStatus", + "UNIVERSAL_CALLBACK_EVM", + "UNIVERSAL_READ_REGISTRY_EVM", + "UNIVERSAL_READ_STATUS", + "UniversalAccount", + "UniversalExecuteParams", + "UniversalOutboundTxRequest", + "UniversalReadResponse", + "UniversalRule", + "UniversalSigner", + "UniversalSignerSkeleton", + "UniversalTo", + "UnsupportedPC20DestinationError", + "UnsupportedReadDestinationError", + "ValidateReadCall", + "WaitForOutboundOptions", + "WalletInfo", + "WalletSummary", + "Web2Extract", + "Web2ReadQuery", + "Web2ValueType", + "buildErc20WithdrawalMulticall", + "buildMigrationPayload", + "buildReadSpecFromPreflight", + "chainSupportsCEA", + "chainSupportsOutbound", + "decodeReadResult", + "detectRoute", + "encodeReadQuery", + "encodeSvmExecutePayload", + "getAllCEAAddresses", + "getCEAAddress", + "getCEAFactoryAddress", + "getPushAccountForCEA", + "inferResultShape", + "isCEA", + "isChainTarget", + "isPC20Reference", + "isSvmChain", + "isValidSolanaHexAddress", + "parseFulfilOutcome", + "parseReadRequestsFromReceipt", + "parseUEAVersion", + "quoteMaxPCForGasCap", + "quoteMaxPCForGasCapFromNativeValue", + "resolveDestination", + "sizeCallbackBudget", + "toCallData", + "toReadQuery", + "toRequestIdHex", + "validateReadSpec" + ], + "agw": { + "AgenticNamespace": { + "type": "import(\"sdk/src/lib/index\").AgenticNamespace", + "members": { + "create": { + "optional": false, + "type": "(label: string, options: import(\"sdk/src/lib/index\").CreateOptions) => Promise" + }, + "derive": { + "optional": false, + "type": "(opts?: { index?: number; }) => Promise<{ address: import(\"sdk/src/lib/index\").AgenticAddress; index: number; deployed: boolean; }>" + }, + "list": { + "optional": false, + "type": "() => Promise<{ wallets: import(\"sdk/src/lib/index\").WalletSummary[]; }>" + }, + "wallet": { + "optional": false, + "type": "(address: import(\"sdk/src/lib/index\").AgenticAddress) => import(\"sdk/src/lib/index\").AgenticWallet" + } + } + }, + "AgenticWallet": { + "type": "import(\"sdk/src/lib/index\").AgenticWallet", + "members": { + "address": { + "optional": false, + "type": "`0x${string}`" + }, + "checkpoints": { + "optional": false, + "type": "(opts?: { sinceBlock?: bigint; }) => Promise<{ checkpoints: import(\"sdk/src/lib/index\").Checkpoint[]; }>" + }, + "info": { + "optional": false, + "type": "() => Promise" + }, + "owner": { + "optional": false, + "type": "() => Promise<{ owner: import(\"sdk/src/lib/index\").AgenticAddress; }>" + }, + "rules": { + "optional": false, + "type": "{ list(): Promise<{ rules: import(\"sdk/src/lib/index\").RulesRecord[]; }>; get(rulesId: import(\"sdk/src/lib/index\").AgenticHex): Promise; add(rules: import(\"sdk/src/lib/index\").Rule[], opts?: { progressHook?: import(\"sdk/src/lib/index\").AgenticProgressHook; }): Promise<{ rulesIds: import(\"sdk/src/lib/index\").AgenticHex[]; tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse; }>; update(params: { rules: { rulesId: import(\"sdk/src/lib/index\").AgenticHex; rule: import(\"sdk/src/lib/index\").Rule; }[]; progressHook?: import(\"sdk/src/lib/index\").AgenticProgressHook; }): Promise<{ rules: { rulesId: import(\"sdk/src/lib/index\").AgenticHex; replaced: import(\"sdk/src/lib/index\").AgenticHex; }[]; tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse; }>; revoke(rulesIds: import(\"sdk/src/lib/index\").AgenticHex[], opts?: { progressHook?: import(\"sdk/src/lib/index\").AgenticProgressHook; }): Promise; revoke(params: { all: true; progressHook?: import(\"sdk/src/lib/index\").AgenticProgressHook; }): Promise; }" + }, + "setLabel": { + "optional": false, + "type": "(label: string, opts?: { progressHook?: import(\"sdk/src/lib/index\").AgenticProgressHook; }) => Promise" + } + } + }, + "AgenticError": { + "type": "import(\"sdk/src/lib/index\").AgenticError", + "members": { + "cause": { + "optional": true, + "type": "unknown" + }, + "code": { + "optional": false, + "type": "import(\"sdk/src/lib/index\").AgenticErrorCode" + }, + "details": { + "optional": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "type": "string | undefined" + }, + "message": { + "optional": false, + "type": "string" + }, + "name": { + "optional": false, + "type": "string" + }, + "stack": { + "optional": true, + "type": "string | undefined" + } + } + }, + "AgenticRevertError": { + "type": "import(\"sdk/src/lib/index\").AgenticRevertError", + "members": { + "agenticCode": { + "optional": true, + "type": "string | undefined" + }, + "cause": { + "optional": true, + "type": "unknown" + }, + "code": { + "optional": false, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "type": "import(\"sdk/src/lib/index\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "type": "string | undefined" + }, + "message": { + "optional": false, + "type": "string" + }, + "name": { + "optional": false, + "type": "string" + }, + "pendingTransactionHash": { + "optional": true, + "type": "`0x${string}` | undefined" + }, + "stack": { + "optional": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "type": "`0x${string}`[] | undefined" + } + } + }, + "AGENTIC_ERROR_CODE": { + "type": "{ readonly AGENT_IS_OWNER: \"AGENT_IS_OWNER\"; readonly DUPLICATE_RULE: \"DUPLICATE_RULE\"; readonly TARGET_NOT_ON_RULE_CHAIN: \"TARGET_NOT_ON_RULE_CHAIN\"; readonly ASSET_CHAIN_MISMATCH: \"ASSET_CHAIN_MISMATCH\"; readonly NOT_OWNER_OR_AGENT: \"NOT_OWNER_OR_AGENT\"; readonly WALLET_NOT_DEPLOYED: \"WALLET_NOT_DEPLOYED\"; readonly NOT_AGENTIC_WALLET: \"NOT_AGENTIC_WALLET\"; readonly REVOKE_NEEDS_TARGET: \"REVOKE_NEEDS_TARGET\"; readonly NO_RULES_FOR_CHAIN: \"NO_RULES_FOR_CHAIN\"; readonly FROM_NOT_ALLOWED: \"FROM_NOT_ALLOWED\"; readonly NOT_ALLOWED_IN_AGENTIC_MODE: \"NOT_ALLOWED_IN_AGENTIC_MODE\"; readonly INVALID_RULE: \"INVALID_RULE\"; readonly CAPABILITY_UNAVAILABLE: \"CAPABILITY_UNAVAILABLE\"; readonly GENERATION_UNSUPPORTED: \"GENERATION_UNSUPPORTED\"; readonly READ_ONLY: \"READ_ONLY\"; readonly NOT_WALLET_OWNER: \"NOT_WALLET_OWNER\"; readonly RULE_NOT_FOUND: \"RULE_NOT_FOUND\"; readonly RULE_READ_FAILED: \"RULE_READ_FAILED\"; readonly INCONSISTENT_READ: \"INCONSISTENT_READ\"; readonly INDEX_RACE: \"INDEX_RACE\"; readonly CREATE_PARTIAL: \"CREATE_PARTIAL\"; readonly RECEIPT_MISMATCH: \"RECEIPT_MISMATCH\"; readonly RECEIPT_UNAVAILABLE: \"RECEIPT_UNAVAILABLE\"; readonly AGENT_GAS_INSUFFICIENT: \"AGENT_GAS_INSUFFICIENT\"; readonly WALLET_BALANCE_INSUFFICIENT: \"WALLET_BALANCE_INSUFFICIENT\"; readonly GATEWAY_ALLOWANCE_INSUFFICIENT: \"GATEWAY_ALLOWANCE_INSUFFICIENT\"; readonly RULE_LIMIT_EXCEEDED: \"RULE_LIMIT_EXCEEDED\"; }", + "members": { + "AGENT_GAS_INSUFFICIENT": { + "optional": false, + "type": "\"AGENT_GAS_INSUFFICIENT\"" + }, + "AGENT_IS_OWNER": { + "optional": false, + "type": "\"AGENT_IS_OWNER\"" + }, + "ASSET_CHAIN_MISMATCH": { + "optional": false, + "type": "\"ASSET_CHAIN_MISMATCH\"" + }, + "CAPABILITY_UNAVAILABLE": { + "optional": false, + "type": "\"CAPABILITY_UNAVAILABLE\"" + }, + "CREATE_PARTIAL": { + "optional": false, + "type": "\"CREATE_PARTIAL\"" + }, + "DUPLICATE_RULE": { + "optional": false, + "type": "\"DUPLICATE_RULE\"" + }, + "FROM_NOT_ALLOWED": { + "optional": false, + "type": "\"FROM_NOT_ALLOWED\"" + }, + "GATEWAY_ALLOWANCE_INSUFFICIENT": { + "optional": false, + "type": "\"GATEWAY_ALLOWANCE_INSUFFICIENT\"" + }, + "GENERATION_UNSUPPORTED": { + "optional": false, + "type": "\"GENERATION_UNSUPPORTED\"" + }, + "INCONSISTENT_READ": { + "optional": false, + "type": "\"INCONSISTENT_READ\"" + }, + "INDEX_RACE": { + "optional": false, + "type": "\"INDEX_RACE\"" + }, + "INVALID_RULE": { + "optional": false, + "type": "\"INVALID_RULE\"" + }, + "NO_RULES_FOR_CHAIN": { + "optional": false, + "type": "\"NO_RULES_FOR_CHAIN\"" + }, + "NOT_AGENTIC_WALLET": { + "optional": false, + "type": "\"NOT_AGENTIC_WALLET\"" + }, + "NOT_ALLOWED_IN_AGENTIC_MODE": { + "optional": false, + "type": "\"NOT_ALLOWED_IN_AGENTIC_MODE\"" + }, + "NOT_OWNER_OR_AGENT": { + "optional": false, + "type": "\"NOT_OWNER_OR_AGENT\"" + }, + "NOT_WALLET_OWNER": { + "optional": false, + "type": "\"NOT_WALLET_OWNER\"" + }, + "READ_ONLY": { + "optional": false, + "type": "\"READ_ONLY\"" + }, + "RECEIPT_MISMATCH": { + "optional": false, + "type": "\"RECEIPT_MISMATCH\"" + }, + "RECEIPT_UNAVAILABLE": { + "optional": false, + "type": "\"RECEIPT_UNAVAILABLE\"" + }, + "REVOKE_NEEDS_TARGET": { + "optional": false, + "type": "\"REVOKE_NEEDS_TARGET\"" + }, + "RULE_LIMIT_EXCEEDED": { + "optional": false, + "type": "\"RULE_LIMIT_EXCEEDED\"" + }, + "RULE_NOT_FOUND": { + "optional": false, + "type": "\"RULE_NOT_FOUND\"" + }, + "RULE_READ_FAILED": { + "optional": false, + "type": "\"RULE_READ_FAILED\"" + }, + "TARGET_NOT_ON_RULE_CHAIN": { + "optional": false, + "type": "\"TARGET_NOT_ON_RULE_CHAIN\"" + }, + "WALLET_BALANCE_INSUFFICIENT": { + "optional": false, + "type": "\"WALLET_BALANCE_INSUFFICIENT\"" + }, + "WALLET_NOT_DEPLOYED": { + "optional": false, + "type": "\"WALLET_NOT_DEPLOYED\"" + } + } + }, + "NativeRule": { + "type": "import(\"sdk/src/lib/index\").NativeRule", + "members": { + "agent": { + "optional": false, + "type": "`0x${string}`" + }, + "amount": { + "optional": true, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AmountLimit | undefined" + }, + "chainNamespace": { + "optional": true, + "type": "undefined" + }, + "maxCalls": { + "optional": true, + "type": "number | undefined" + }, + "maxValuePerCall": { + "optional": true, + "type": "bigint | undefined" + }, + "maxValueTotal": { + "optional": true, + "type": "bigint | undefined" + }, + "pins": { + "optional": true, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ArgPin[] | undefined" + }, + "ref": { + "optional": true, + "type": "`0x${string}` | undefined" + }, + "selector": { + "optional": false, + "type": "import(\"sdk/src/lib/index\").Selector | \"value-only\"" + }, + "target": { + "optional": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "type": "number" + } + } + }, + "AssetCap": { + "type": "import(\"sdk/src/lib/index\").AssetCap", + "members": { + "maxPerCall": { + "optional": false, + "type": "bigint" + }, + "maxTotal": { + "optional": true, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "type": "`0x${string}` | import(\"sdk/src/lib/constants/tokens\").MoveableToken" + } + } + }, + "AllowedCall": { + "type": "import(\"sdk/src/lib/index\").AllowedCall", + "members": { + "beneficiary": { + "optional": true, + "type": "number | undefined" + }, + "maxValue": { + "optional": true, + "type": "bigint | undefined" + }, + "selector": { + "optional": false, + "type": "import(\"sdk/src/lib/index\").Selector" + }, + "target": { + "optional": false, + "type": "`0x${string}`" + } + } + }, + "UniversalRule": { + "type": "import(\"sdk/src/lib/index\").UniversalRule", + "members": { + "agent": { + "optional": false, + "type": "`0x${string}`" + }, + "allowedCalls": { + "optional": false, + "type": "import(\"sdk/src/lib/index\").AllowedCall[]" + }, + "assets": { + "optional": false, + "type": "import(\"sdk/src/lib/index\").AssetCap[]" + }, + "chainNamespace": { + "optional": false, + "type": "import(\"sdk/src/lib/index\").ForeignChainNamespace" + }, + "maxGasPerCall": { + "optional": false, + "type": "bigint" + }, + "ref": { + "optional": true, + "type": "`0x${string}` | undefined" + }, + "validUntil": { + "optional": false, + "type": "number" + } + } + }, + "RulesRecord": { + "type": "import(\"sdk/src/lib/index\").RulesRecord", + "members": { + "agent": { + "optional": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": false, + "type": "string" + }, + "enabled": { + "optional": false, + "type": "boolean" + }, + "ref": { + "optional": false, + "type": "`0x${string}`" + }, + "rule": { + "optional": false, + "type": "import(\"sdk/src/lib/index\").Rule" + }, + "rulesId": { + "optional": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "type": "number" + } + } + }, + "CreateOptions": { + "type": "import(\"sdk/src/lib/index\").CreateOptions", + "members": { + "progressHook": { + "optional": true, + "type": "import(\"sdk/src/lib/index\").AgenticProgressHook | undefined" + }, + "rules": { + "optional": false, + "type": "import(\"sdk/src/lib/index\").Rule[]" + } + } + }, + "CreateResult": { + "type": "import(\"sdk/src/lib/index\").CreateResult", + "members": { + "index": { + "optional": false, + "type": "number" + }, + "rulesIds": { + "optional": false, + "type": "`0x${string}`[]" + }, + "tx": { + "optional": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wallet": { + "optional": false, + "type": "`0x${string}`" + } + } + }, + "AgenticTxMetadata": { + "type": "import(\"sdk/src/lib/index\").AgenticTxMetadata", + "members": { + "chainNamespace": { + "optional": true, + "type": "string | undefined" + }, + "destinationAccount": { + "optional": true, + "type": "`0x${string}` | undefined" + }, + "destinationCalls": { + "optional": true, + "type": "readonly { to: import(\"sdk/src/lib/index\").AgenticAddress; data: import(\"sdk/src/lib/index\").AgenticHex; value: bigint; }[] | undefined" + }, + "door": { + "optional": false, + "type": "import(\"sdk/src/lib/index\").AgenticDoor" + }, + "nativeCalls": { + "optional": true, + "type": "readonly { to: import(\"sdk/src/lib/index\").AgenticAddress; data: import(\"sdk/src/lib/index\").AgenticHex; value: bigint; }[] | undefined" + }, + "rawData": { + "optional": false, + "type": "string" + }, + "rawTo": { + "optional": false, + "type": "string" + }, + "rulesId": { + "optional": true, + "type": "`0x${string}` | undefined" + }, + "wallet": { + "optional": false, + "type": "`0x${string}`" + } + } + } + }, + "initialize": "(universalSigner: import(\"sdk/src/lib/index\").UniversalSigner | import(\"sdk/src/lib/index\").UniversalAccount, options?: import(\"sdk/src/lib/index\").PushChainInitializeOptions) => Promise", + "agwConstants": { + "ENVELOPE_VERSION": { + "optional": true, + "type": "number | undefined" + }, + "FACTORY": { + "optional": false, + "type": "`0x${string}`" + }, + "MAX_ALLOWED_CALLS": { + "optional": false, + "type": "number" + }, + "MAX_PINS": { + "optional": false, + "type": "number" + }, + "RULES_POLICY": { + "optional": false, + "type": "`0x${string}`" + } + } + }, + "after": { + "exports": [ + "AGENTIC_ERROR_CODE", + "AccountRole", + "AccountStatus", + "AccountType", + "AgenticAddress", + "AgenticDoor", + "AgenticError", + "AgenticErrorCode", + "AgenticHex", + "AgenticNamespace", + "AgenticNetworkConstants", + "AgenticProgressHook", + "AgenticRevertError", + "AgenticTxMetadata", + "AgenticWallet", + "AllowedCall", + "AssetCap", + "BatchReadResponse", + "BuildReadSpecParams", + "CHAIN", + "CONTRACT_REQUEST_STATUS", + "CascadeCompletionResult", + "CascadeHopInfo", + "CascadeProgressEvent", + "CascadeTrackOptions", + "CascadedTxResponse", + "ChainSource", + "ChainTarget", + "Checkpoint", + "CheckpointKind", + "ConversionQuote", + "CreateOptions", + "CreateResult", + "DEFAULT_MAX_PC_FOR_GAS_BUFFER_BPS", + "DecodedErrorPayload", + "DecodedReadResult", + "DerivedExecutorAccount", + "EncodedReadQuery", + "EvmReadQuery", + "ForeignChainNamespace", + "FulfilOutcome", + "FundsToken", + "InsufficientPC20BalanceError", + "InvalidPC20AddressError", + "InvalidPC20MetadataError", + "InvalidReadQueryError", + "InvalidReadSpecError", + "MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT", + "MaxPCForGasCapFromNativeValueInput", + "MaxPCForGasCapInput", + "MaxPCForGasCapQuote", + "MultiChainTxResponse", + "NativeRule", + "OutboundTxDetails", + "PC20AddressResult", + "PC20AmbiguousAddressError", + "PC20Error", + "PC20ExpectedButPRC20Error", + "PC20ExportRevertedError", + "PC20FactoryMismatchError", + "PC20RegistryEntry", + "PC20RegistryMismatchError", + "PC20TokenChainMismatchError", + "PC20TokenReference", + "PC20UnknownChainNamespaceError", + "PC20UnsafeEmptyPayloadError", + "PC20WrapperNotRegisteredError", + "PC20WrapperPredictionUnavailableError", + "ParsedReadRequest", + "PreparedRead", + "PreparedUniversalTx", + "PushChain", + "PushChainBatchExecutionError", + "PushChainExecutionError", + "PushChainInitializeOptions", + "READ_ERROR_CODE", + "READ_OUTCOME", + "READ_STATUS", + "ReadCallback", + "ReadCallbackOptions", + "ReadChain", + "ReadDecodeError", + "ReadDestination", + "ReadExecuteOptions", + "ReadFees", + "ReadHeightUnavailableError", + "ReadLifecycleOptions", + "ReadNotFoundError", + "ReadOptions", + "ReadPreflight", + "ReadPrepareOptions", + "ReadQuery", + "ReadQueryOptions", + "ReadRef", + "ReadRegistryUnavailableError", + "ReadResponseTuple", + "ReadResultShape", + "ReadSpec", + "ReadSpecTuple", + "ReadSpecViolation", + "ReadStateError", + "ReadTimeoutError", + "ReadTrackOptions", + "ReadValue", + "ReadWeb2Options", + "ReceiptLike", + "RescueFundsParams", + "ResolvedAccount", + "ResolvedControllerAccounts", + "ResolvedDestination", + "Rule", + "RulesRecord", + "Selector", + "SignAuthorizationParams", + "SignedAuthorization", + "SimulateReadResult", + "SvmExecutePayloadFields", + "SvmGatewayAccountMeta", + "SvmReadQuery", + "TERMINAL_READ_STATUSES", + "TransactionRoute", + "TransactionRouteType", + "UEAStatus", + "UNIVERSAL_CALLBACK_EVM", + "UNIVERSAL_READ_REGISTRY_EVM", + "UNIVERSAL_READ_STATUS", + "UniversalAccount", + "UniversalExecuteParams", + "UniversalOutboundTxRequest", + "UniversalReadResponse", + "UniversalRule", + "UniversalSigner", + "UniversalSignerSkeleton", + "UniversalTo", + "UnsupportedPC20DestinationError", + "UnsupportedReadDestinationError", + "ValidateReadCall", + "WaitForOutboundOptions", + "WalletInfo", + "WalletSummary", + "Web2Extract", + "Web2ReadQuery", + "Web2ValueType", + "buildErc20WithdrawalMulticall", + "buildMigrationPayload", + "buildReadSpecFromPreflight", + "chainSupportsCEA", + "chainSupportsOutbound", + "decodeReadResult", + "detectRoute", + "encodeReadQuery", + "encodeSvmExecutePayload", + "getAllCEAAddresses", + "getCEAAddress", + "getCEAFactoryAddress", + "getPushAccountForCEA", + "inferResultShape", + "isCEA", + "isChainTarget", + "isPC20Reference", + "isSvmChain", + "isValidSolanaHexAddress", + "parseFulfilOutcome", + "parseReadRequestsFromReceipt", + "parseUEAVersion", + "quoteMaxPCForGasCap", + "quoteMaxPCForGasCapFromNativeValue", + "resolveDestination", + "sizeCallbackBudget", + "toCallData", + "toReadQuery", + "toRequestIdHex", + "validateReadSpec" + ], + "agw": { + "AgenticNamespace": { + "type": "import(\"sdk/src/lib/index\").AgenticNamespace", + "members": { + "create": { + "optional": false, + "type": "(label: string, options: import(\"sdk/src/lib/index\").CreateOptions) => Promise" + }, + "derive": { + "optional": false, + "type": "(opts?: { index?: number; }) => Promise<{ address: import(\"sdk/src/lib/index\").AgenticAddress; index: number; deployed: boolean; }>" + }, + "list": { + "optional": false, + "type": "() => Promise<{ wallets: import(\"sdk/src/lib/index\").WalletSummary[]; }>" + }, + "wallet": { + "optional": false, + "type": "(address: import(\"sdk/src/lib/index\").AgenticAddress) => import(\"sdk/src/lib/index\").AgenticWallet" + } + } + }, + "AgenticWallet": { + "type": "import(\"sdk/src/lib/index\").AgenticWallet", + "members": { + "address": { + "optional": false, + "type": "`0x${string}`" + }, + "checkpoints": { + "optional": false, + "type": "(opts?: { sinceBlock?: bigint; }) => Promise<{ checkpoints: import(\"sdk/src/lib/index\").Checkpoint[]; }>" + }, + "info": { + "optional": false, + "type": "() => Promise" + }, + "owner": { + "optional": false, + "type": "() => Promise<{ owner: import(\"sdk/src/lib/index\").AgenticAddress; }>" + }, + "rules": { + "optional": false, + "type": "{ list(): Promise<{ rules: import(\"sdk/src/lib/index\").RulesRecord[]; }>; get(rulesId: import(\"sdk/src/lib/index\").AgenticHex): Promise; add(rules: import(\"sdk/src/lib/index\").Rule[], opts?: { progressHook?: import(\"sdk/src/lib/index\").AgenticProgressHook; }): Promise<{ rulesIds: import(\"sdk/src/lib/index\").AgenticHex[]; tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse; }>; update(params: { rules: { rulesId: import(\"sdk/src/lib/index\").AgenticHex; rule: import(\"sdk/src/lib/index\").Rule; }[]; progressHook?: import(\"sdk/src/lib/index\").AgenticProgressHook; }): Promise<{ rules: { rulesId: import(\"sdk/src/lib/index\").AgenticHex; replaced: import(\"sdk/src/lib/index\").AgenticHex; }[]; tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse; }>; revoke(rulesIds: import(\"sdk/src/lib/index\").AgenticHex[], opts?: { progressHook?: import(\"sdk/src/lib/index\").AgenticProgressHook; }): Promise; revoke(params: { all: true; progressHook?: import(\"sdk/src/lib/index\").AgenticProgressHook; }): Promise; }" + }, + "setLabel": { + "optional": false, + "type": "(label: string, opts?: { progressHook?: import(\"sdk/src/lib/index\").AgenticProgressHook; }) => Promise" + } + } + }, + "AgenticError": { + "type": "import(\"sdk/src/lib/index\").AgenticError", + "members": { + "cause": { + "optional": true, + "type": "unknown" + }, + "code": { + "optional": false, + "type": "import(\"sdk/src/lib/index\").AgenticErrorCode" + }, + "details": { + "optional": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "type": "string | undefined" + }, + "message": { + "optional": false, + "type": "string" + }, + "name": { + "optional": false, + "type": "string" + }, + "stack": { + "optional": true, + "type": "string | undefined" + } + } + }, + "AgenticRevertError": { + "type": "import(\"sdk/src/lib/index\").AgenticRevertError", + "members": { + "agenticCode": { + "optional": true, + "type": "string | undefined" + }, + "cause": { + "optional": true, + "type": "unknown" + }, + "code": { + "optional": false, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "type": "import(\"sdk/src/lib/index\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "type": "string | undefined" + }, + "message": { + "optional": false, + "type": "string" + }, + "name": { + "optional": false, + "type": "string" + }, + "pendingTransactionHash": { + "optional": true, + "type": "`0x${string}` | undefined" + }, + "stack": { + "optional": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "type": "`0x${string}`[] | undefined" + } + } + }, + "AGENTIC_ERROR_CODE": { + "type": "{ readonly AGENT_IS_OWNER: \"AGENT_IS_OWNER\"; readonly AMBIGUOUS_RULE: \"AMBIGUOUS_RULE\"; readonly TARGET_NOT_ON_RULE_CHAIN: \"TARGET_NOT_ON_RULE_CHAIN\"; readonly ASSET_CHAIN_MISMATCH: \"ASSET_CHAIN_MISMATCH\"; readonly NOT_OWNER_OR_AGENT: \"NOT_OWNER_OR_AGENT\"; readonly WALLET_NOT_DEPLOYED: \"WALLET_NOT_DEPLOYED\"; readonly NOT_AGENTIC_WALLET: \"NOT_AGENTIC_WALLET\"; readonly REVOKE_NEEDS_TARGET: \"REVOKE_NEEDS_TARGET\"; readonly NO_RULES_FOR_CHAIN: \"NO_RULES_FOR_CHAIN\"; readonly FROM_NOT_ALLOWED: \"FROM_NOT_ALLOWED\"; readonly NOT_ALLOWED_IN_AGENTIC_MODE: \"NOT_ALLOWED_IN_AGENTIC_MODE\"; readonly INVALID_RULE: \"INVALID_RULE\"; readonly CAPABILITY_UNAVAILABLE: \"CAPABILITY_UNAVAILABLE\"; readonly GENERATION_UNSUPPORTED: \"GENERATION_UNSUPPORTED\"; readonly READ_ONLY: \"READ_ONLY\"; readonly NOT_WALLET_OWNER: \"NOT_WALLET_OWNER\"; readonly RULE_NOT_FOUND: \"RULE_NOT_FOUND\"; readonly RULE_READ_FAILED: \"RULE_READ_FAILED\"; readonly INCONSISTENT_READ: \"INCONSISTENT_READ\"; readonly INDEX_RACE: \"INDEX_RACE\"; readonly CREATE_PARTIAL: \"CREATE_PARTIAL\"; readonly RECEIPT_MISMATCH: \"RECEIPT_MISMATCH\"; readonly RECEIPT_UNAVAILABLE: \"RECEIPT_UNAVAILABLE\"; readonly AGENT_GAS_INSUFFICIENT: \"AGENT_GAS_INSUFFICIENT\"; readonly WALLET_BALANCE_INSUFFICIENT: \"WALLET_BALANCE_INSUFFICIENT\"; readonly GATEWAY_ALLOWANCE_INSUFFICIENT: \"GATEWAY_ALLOWANCE_INSUFFICIENT\"; readonly RULE_LIMIT_EXCEEDED: \"RULE_LIMIT_EXCEEDED\"; }", + "members": { + "AGENT_GAS_INSUFFICIENT": { + "optional": false, + "type": "\"AGENT_GAS_INSUFFICIENT\"" + }, + "AGENT_IS_OWNER": { + "optional": false, + "type": "\"AGENT_IS_OWNER\"" + }, + "AMBIGUOUS_RULE": { + "optional": false, + "type": "\"AMBIGUOUS_RULE\"" + }, + "ASSET_CHAIN_MISMATCH": { + "optional": false, + "type": "\"ASSET_CHAIN_MISMATCH\"" + }, + "CAPABILITY_UNAVAILABLE": { + "optional": false, + "type": "\"CAPABILITY_UNAVAILABLE\"" + }, + "CREATE_PARTIAL": { + "optional": false, + "type": "\"CREATE_PARTIAL\"" + }, + "FROM_NOT_ALLOWED": { + "optional": false, + "type": "\"FROM_NOT_ALLOWED\"" + }, + "GATEWAY_ALLOWANCE_INSUFFICIENT": { + "optional": false, + "type": "\"GATEWAY_ALLOWANCE_INSUFFICIENT\"" + }, + "GENERATION_UNSUPPORTED": { + "optional": false, + "type": "\"GENERATION_UNSUPPORTED\"" + }, + "INCONSISTENT_READ": { + "optional": false, + "type": "\"INCONSISTENT_READ\"" + }, + "INDEX_RACE": { + "optional": false, + "type": "\"INDEX_RACE\"" + }, + "INVALID_RULE": { + "optional": false, + "type": "\"INVALID_RULE\"" + }, + "NO_RULES_FOR_CHAIN": { + "optional": false, + "type": "\"NO_RULES_FOR_CHAIN\"" + }, + "NOT_AGENTIC_WALLET": { + "optional": false, + "type": "\"NOT_AGENTIC_WALLET\"" + }, + "NOT_ALLOWED_IN_AGENTIC_MODE": { + "optional": false, + "type": "\"NOT_ALLOWED_IN_AGENTIC_MODE\"" + }, + "NOT_OWNER_OR_AGENT": { + "optional": false, + "type": "\"NOT_OWNER_OR_AGENT\"" + }, + "NOT_WALLET_OWNER": { + "optional": false, + "type": "\"NOT_WALLET_OWNER\"" + }, + "READ_ONLY": { + "optional": false, + "type": "\"READ_ONLY\"" + }, + "RECEIPT_MISMATCH": { + "optional": false, + "type": "\"RECEIPT_MISMATCH\"" + }, + "RECEIPT_UNAVAILABLE": { + "optional": false, + "type": "\"RECEIPT_UNAVAILABLE\"" + }, + "REVOKE_NEEDS_TARGET": { + "optional": false, + "type": "\"REVOKE_NEEDS_TARGET\"" + }, + "RULE_LIMIT_EXCEEDED": { + "optional": false, + "type": "\"RULE_LIMIT_EXCEEDED\"" + }, + "RULE_NOT_FOUND": { + "optional": false, + "type": "\"RULE_NOT_FOUND\"" + }, + "RULE_READ_FAILED": { + "optional": false, + "type": "\"RULE_READ_FAILED\"" + }, + "TARGET_NOT_ON_RULE_CHAIN": { + "optional": false, + "type": "\"TARGET_NOT_ON_RULE_CHAIN\"" + }, + "WALLET_BALANCE_INSUFFICIENT": { + "optional": false, + "type": "\"WALLET_BALANCE_INSUFFICIENT\"" + }, + "WALLET_NOT_DEPLOYED": { + "optional": false, + "type": "\"WALLET_NOT_DEPLOYED\"" + } + } + }, + "NativeRule": { + "type": "import(\"sdk/src/lib/index\").NativeRule", + "members": { + "agent": { + "optional": false, + "type": "`0x${string}`" + }, + "amount": { + "optional": true, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AmountLimit | undefined" + }, + "chainNamespace": { + "optional": true, + "type": "undefined" + }, + "maxCalls": { + "optional": true, + "type": "number | undefined" + }, + "maxValuePerCall": { + "optional": true, + "type": "bigint | undefined" + }, + "maxValueTotal": { + "optional": true, + "type": "bigint | undefined" + }, + "pins": { + "optional": true, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ArgPin[] | undefined" + }, + "ref": { + "optional": true, + "type": "`0x${string}` | undefined" + }, + "selector": { + "optional": false, + "type": "import(\"sdk/src/lib/index\").Selector | \"value-only\"" + }, + "target": { + "optional": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "type": "number" + } + } + }, + "AssetCap": { + "type": "import(\"sdk/src/lib/index\").AssetCap", + "members": { + "maxPerCall": { + "optional": false, + "type": "bigint" + }, + "maxTotal": { + "optional": true, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "type": "`0x${string}` | import(\"sdk/src/lib/constants/tokens\").MoveableToken" + } + } + }, + "AllowedCall": { + "type": "import(\"sdk/src/lib/index\").AllowedCall", + "members": { + "beneficiary": { + "optional": true, + "type": "number | undefined" + }, + "beneficiaryOffset": { + "optional": true, + "type": "number | undefined" + }, + "maxValue": { + "optional": true, + "type": "bigint | undefined" + }, + "selector": { + "optional": false, + "type": "import(\"sdk/src/lib/index\").Selector" + }, + "target": { + "optional": false, + "type": "`0x${string}`" + } + } + }, + "UniversalRule": { + "type": "import(\"sdk/src/lib/index\").UniversalRule", + "members": { + "agent": { + "optional": false, + "type": "`0x${string}`" + }, + "allowedCalls": { + "optional": false, + "type": "import(\"sdk/src/lib/index\").AllowedCall[]" + }, + "assets": { + "optional": false, + "type": "import(\"sdk/src/lib/index\").AssetCap[]" + }, + "chainNamespace": { + "optional": false, + "type": "import(\"sdk/src/lib/index\").ForeignChainNamespace" + }, + "maxGasPerCall": { + "optional": false, + "type": "bigint" + }, + "ref": { + "optional": true, + "type": "`0x${string}` | undefined" + }, + "validUntil": { + "optional": false, + "type": "number" + } + } + }, + "RulesRecord": { + "type": "import(\"sdk/src/lib/index\").RulesRecord", + "members": { + "agent": { + "optional": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": false, + "type": "string" + }, + "enabled": { + "optional": false, + "type": "boolean" + }, + "ref": { + "optional": false, + "type": "`0x${string}`" + }, + "rule": { + "optional": false, + "type": "import(\"sdk/src/lib/index\").Rule" + }, + "rulesId": { + "optional": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "type": "number" + } + } + }, + "CreateOptions": { + "type": "import(\"sdk/src/lib/index\").CreateOptions", + "members": { + "progressHook": { + "optional": true, + "type": "import(\"sdk/src/lib/index\").AgenticProgressHook | undefined" + }, + "rules": { + "optional": false, + "type": "import(\"sdk/src/lib/index\").Rule[]" + } + } + }, + "CreateResult": { + "type": "import(\"sdk/src/lib/index\").CreateResult", + "members": { + "index": { + "optional": false, + "type": "number" + }, + "rulesIds": { + "optional": false, + "type": "`0x${string}`[]" + }, + "tx": { + "optional": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wallet": { + "optional": false, + "type": "`0x${string}`" + } + } + }, + "AgenticTxMetadata": { + "type": "import(\"sdk/src/lib/index\").AgenticTxMetadata", + "members": { + "chainNamespace": { + "optional": true, + "type": "string | undefined" + }, + "destinationAccount": { + "optional": true, + "type": "`0x${string}` | undefined" + }, + "destinationCalls": { + "optional": true, + "type": "readonly { to: import(\"sdk/src/lib/index\").AgenticAddress; data: import(\"sdk/src/lib/index\").AgenticHex; value: bigint; }[] | undefined" + }, + "door": { + "optional": false, + "type": "import(\"sdk/src/lib/index\").AgenticDoor" + }, + "nativeCalls": { + "optional": true, + "type": "readonly { to: import(\"sdk/src/lib/index\").AgenticAddress; data: import(\"sdk/src/lib/index\").AgenticHex; value: bigint; }[] | undefined" + }, + "rawData": { + "optional": false, + "type": "string" + }, + "rawTo": { + "optional": false, + "type": "string" + }, + "rulesId": { + "optional": true, + "type": "`0x${string}` | undefined" + }, + "wallet": { + "optional": false, + "type": "`0x${string}`" + } + } + } + }, + "initialize": "(universalSigner: import(\"sdk/src/lib/index\").UniversalSigner | import(\"sdk/src/lib/index\").UniversalAccount, options?: import(\"sdk/src/lib/index\").PushChainInitializeOptions) => Promise", + "agwConstants": { + "ENVELOPE_VERSION": { + "optional": false, + "type": "number" + }, + "FACTORY": { + "optional": false, + "type": "`0x${string}`" + }, + "MAX_ALLOWED_CALLS": { + "optional": false, + "type": "number" + }, + "MAX_PINS": { + "optional": false, + "type": "number" + }, + "RULES_POLICY": { + "optional": false, + "type": "`0x${string}`" + } + } + }, + "scope": "Root exports, AGW types, initialize and agentic constants. Behavioral/default/deployment changes need the written session review." +} diff --git a/plan/agw/research/sdk-independent-completion-2026-10-06/logs/build.log b/plan/agw/research/sdk-independent-completion-2026-10-06/logs/build.log new file mode 100644 index 00000000..96b66883 --- /dev/null +++ b/plan/agw/research/sdk-independent-completion-2026-10-06/logs/build.log @@ -0,0 +1,13 @@ + +> nx run core:build + +Compiling TypeScript files for project "core"... +Done compiling TypeScript files for project "core". + + + + NX Successfully ran target build for project core + + +(node:68414) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. +(Use `node --trace-warnings ...` to show where the warning was created) diff --git a/plan/agw/research/sdk-independent-completion-2026-10-06/logs/changed-lint.log b/plan/agw/research/sdk-independent-completion-2026-10-06/logs/changed-lint.log new file mode 100644 index 00000000..75806793 --- /dev/null +++ b/plan/agw/research/sdk-independent-completion-2026-10-06/logs/changed-lint.log @@ -0,0 +1,75 @@ + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__agw-local__/agw-local-advanced.spec.ts + 73:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 85:17 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 295:22 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 311:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 337:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 426:13 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__agw-local__/agw-local-batch.spec.ts + 44:16 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 90:37 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 91:46 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 98:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 106:16 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__agw-local__/agw-local-races.spec.ts + 54:20 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 99:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 117:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 145:20 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__agw-local__/agw-local.spec.ts + 47:17 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 48:17 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__agw-local__/delayed-index.spec.ts + 81:20 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 95:20 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 112:9 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 194:24 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 246:26 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 254:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__agw-local__/harness.ts + 234:16 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 253:16 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 262:17 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 400:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__agw-local__/svm-backend.spec.ts + 136:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 164:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 223:28 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__agw-local__/svm-internals.spec.ts + 86:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 119:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 189:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__agw-local__/v4-multiasset.spec.ts + 12:10 warning 'createWallet' is defined but never used @typescript-eslint/no-unused-vars + 78:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 92:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 176:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 188:16 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 325:16 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 335:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 353:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__agw-local__/vectors.spec.ts + 56:7 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 57:7 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 98:7 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 207:25 warning '_a' is assigned a value but never used @typescript-eslint/no-unused-vars + 208:25 warning '_b' is assigned a value but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/outbound-sync.ts + 133:40 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 134:9 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/svm-idl/resolve.ts + 10:6 warning 'AccountItem' is defined but never used @typescript-eslint/no-unused-vars + +✖ 49 problems (0 errors, 49 warnings) diff --git a/plan/agw/research/sdk-independent-completion-2026-10-06/logs/docs.log b/plan/agw/research/sdk-independent-completion-2026-10-06/logs/docs.log new file mode 100644 index 00000000..5996134d --- /dev/null +++ b/plan/agw/research/sdk-independent-completion-2026-10-06/logs/docs.log @@ -0,0 +1 @@ +AGW guide: 7 TypeScript blocks typechecked against public exports; no examples executed. diff --git a/plan/agw/research/sdk-independent-completion-2026-10-06/logs/focused-svm-unit.log b/plan/agw/research/sdk-independent-completion-2026-10-06/logs/focused-svm-unit.log new file mode 100644 index 00000000..dbc07dd3 --- /dev/null +++ b/plan/agw/research/sdk-independent-completion-2026-10-06/logs/focused-svm-unit.log @@ -0,0 +1,8 @@ +PASS core packages/core/src/lib/agentic/__tests__/svm-backend.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-svm-confirmation.spec.ts + +Test Suites: 2 passed, 2 total +Tests: 28 passed, 28 total +Snapshots: 0 total +Time: 3.034 s +Ran all test suites within paths "packages/core/src/lib/agentic/__tests__/svm-backend.spec.ts", "packages/core/src/lib/orchestrator/__tests__/outbound-svm-confirmation.spec.ts". diff --git a/plan/agw/research/sdk-independent-completion-2026-10-06/logs/full-unit.log b/plan/agw/research/sdk-independent-completion-2026-10-06/logs/full-unit.log new file mode 100644 index 00000000..49747bae --- /dev/null +++ b/plan/agw/research/sdk-independent-completion-2026-10-06/logs/full-unit.log @@ -0,0 +1,168 @@ +PASS core packages/core/src/lib/universal/account/account.spec.ts + ● Console + + console.warn + [PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead. + + 207 | ): Promise { + 208 | if (!_convertOriginToExecutorWarned) { + > 209 | console.warn( + | ^ + 210 | '[PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead.' + 211 | ); + 212 | _convertOriginToExecutorWarned = true; + + at Object.convertOriginToExecutor (src/lib/universal/account/account.ts:209:13) + at Object. (src/lib/universal/account/account.spec.ts:80:52) + + console.warn + [PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead. + + 425 | ): Promise { + 426 | if (!options?._internal && !_convertExecutorToOriginWarned) { + > 427 | console.warn( + | ^ + 428 | '[PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead.' + 429 | ); + 430 | _convertExecutorToOriginWarned = true; + + at convertExecutorToOrigin (src/lib/universal/account/account.ts:427:13) + at Object. (src/lib/universal/account/account.spec.ts:106:38) + +PASS core packages/core/src/lib/agentic/__tests__/svm-backend.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-detector.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/block-results-client.spec.ts +PASS core packages/core/src/lib/push-client/push-client.archive-fallback.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-confirmation-gate.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r2-outbound-revert-flow.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-timeout-clamp.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/source-hash-resolution.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-tx-retry.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/resolver.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/response-surface.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/track-transaction-guard.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-evm-r3-native-eoa.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r1-spec-strings.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/build-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/payload-builders.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/response-builder-push-revert.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-multichain.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-request-recipient.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-gas.spec.ts +PASS core packages/core/src/lib/utils.spec.ts + ● Console + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:973:17) + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:977:17) + + console.log + 1.23 + + at Object. (src/lib/utils.spec.ts:982:17) + +PASS core packages/core/src/lib/progress-hook/__tests__/r2-spec-strings.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/registry.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-emission.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/terminal-suppression.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/inbound-tracker-derivation.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/inbound-payload.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/send.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-tracker.spec.ts +PASS core packages/core/src/lib/universal/signer/signer.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-calculator.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/chain-namespace.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/account-status.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gateway-uea-account.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/signing-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-event-hook-bridge.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/multichain-hooks.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/public-surface.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-svm-rent.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/funds-only-burn-guard.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/management.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-evm.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-usd-sizer.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/gate.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/export.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/web2-compat.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/send-transaction-progress-hook.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/rescue-svm-confirmation.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/svm-rent.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/cascade.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/read-tx-spec-strings.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/scenarios.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/context-helpers-tracker.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-error-classification.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-params.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/response-invariant.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-svm-r3.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-builder-progress-hook.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r3-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-composition.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-native-multicall.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm-rent-pc20.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/resolve.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/svm-account.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-svm-confirmation.spec.ts +PASS core packages/core/src/lib/push-client/push-client.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-executor.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/execute-standard-required-funds.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm-log-index.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/spec-builder.spec.ts +PASS core packages/core/src/lib/constants/__tests__/token-constants.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/normalize.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/address-codec.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-svm.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/__tests__/signing.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/child-inbounds.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/result-decoder.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/reads-context.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.chain-symbol.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/revalidate-read.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/auto-detect.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/ucallback-codec.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.dynamic-gas.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/abi-selectors.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-events.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/codec.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/registry.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-types.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg-svm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-web2.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/normalize-address.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/validate.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/ix-encoder.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/errors.spec.ts +PASS core packages/core/src/lib/constants/__tests__/svm-gateway-idl.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/max-pc-for-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/tracking.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/classify.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/error-decoder.spec.ts +PASS core packages/core/src/lib/formatters.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/budget.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-execute-order.spec.ts + +Test Suites: 1 skipped, 115 passed, 115 of 116 total +Tests: 12 skipped, 1975 passed, 1987 total +Snapshots: 0 total +Time: 37.497 s, estimated 58 s +Ran all test suites. diff --git a/plan/agw/research/sdk-independent-completion-2026-10-06/logs/local-contracts.log b/plan/agw/research/sdk-independent-completion-2026-10-06/logs/local-contracts.log new file mode 100644 index 00000000..583271c0 --- /dev/null +++ b/plan/agw/research/sdk-independent-completion-2026-10-06/logs/local-contracts.log @@ -0,0 +1,15 @@ +PASS core-agw-local packages/core/__agw-local__/svm-backend.spec.ts (9.995 s) +PASS core-agw-local packages/core/__agw-local__/v4-multiasset.spec.ts +PASS core-agw-local packages/core/__agw-local__/agw-local-advanced.spec.ts +PASS core-agw-local packages/core/__agw-local__/delayed-index.spec.ts +PASS core-agw-local packages/core/__agw-local__/agw-local.spec.ts +PASS core-agw-local packages/core/__agw-local__/agw-local-races.spec.ts +PASS core-agw-local packages/core/__agw-local__/svm-internals.spec.ts +PASS core-agw-local packages/core/__agw-local__/agw-local-batch.spec.ts +PASS core-agw-local packages/core/__agw-local__/vectors.spec.ts + +Test Suites: 9 passed, 9 total +Tests: 68 passed, 68 total +Snapshots: 0 total +Time: 25.23 s, estimated 28 s +Ran all test suites. diff --git a/plan/agw/research/sdk-independent-completion-2026-10-06/logs/package.log b/plan/agw/research/sdk-independent-completion-2026-10-06/logs/package.log new file mode 100644 index 00000000..8e1b97e4 --- /dev/null +++ b/plan/agw/research/sdk-independent-completion-2026-10-06/logs/package.log @@ -0,0 +1 @@ +AGW package: CJS/ESM imports, compiled declaration examples and npm contents pass. No examples executed/published. diff --git a/plan/agw/research/sdk-independent-completion-2026-10-06/logs/prepare-contracts.log b/plan/agw/research/sdk-independent-completion-2026-10-06/logs/prepare-contracts.log new file mode 100644 index 00000000..626bb23a --- /dev/null +++ b/plan/agw/research/sdk-independent-completion-2026-10-06/logs/prepare-contracts.log @@ -0,0 +1 @@ +/var/folders/4_/d47r2_4s1wb3x2dvmt2ghp800000gp/T//push-agw-local-v4 diff --git a/plan/agw/research/sdk-independent-completion-2026-10-06/logs/public-api.log b/plan/agw/research/sdk-independent-completion-2026-10-06/logs/public-api.log new file mode 100644 index 00000000..51254108 --- /dev/null +++ b/plan/agw/research/sdk-independent-completion-2026-10-06/logs/public-api.log @@ -0,0 +1 @@ +{"compiledMatchesSource":true,"addedExports":[],"removedExports":[],"changedAgwTypes":["AGENTIC_ERROR_CODE","AllowedCall"],"initializeSignatureChanged":false,"agwConstantsChanged":true} diff --git a/plan/agw/research/sdk-independent-completion-2026-10-06/logs/types-agw-local.log b/plan/agw/research/sdk-independent-completion-2026-10-06/logs/types-agw-local.log new file mode 100644 index 00000000..e69de29b diff --git a/plan/agw/research/sdk-independent-completion-2026-10-06/logs/types-lib.log b/plan/agw/research/sdk-independent-completion-2026-10-06/logs/types-lib.log new file mode 100644 index 00000000..e69de29b diff --git a/plan/agw/research/sdk-independent-completion-2026-10-06/logs/types-spec.log b/plan/agw/research/sdk-independent-completion-2026-10-06/logs/types-spec.log new file mode 100644 index 00000000..e69de29b diff --git a/plan/agw/research/sdk-independent-completion-2026-10-06/logs/units.log b/plan/agw/research/sdk-independent-completion-2026-10-06/logs/units.log new file mode 100644 index 00000000..b6d5cf43 --- /dev/null +++ b/plan/agw/research/sdk-independent-completion-2026-10-06/logs/units.log @@ -0,0 +1,23 @@ +PASS core packages/core/src/lib/agentic/__tests__/svm-backend.spec.ts (5.151 s) +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-confirmation-gate.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/response-surface.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/build-payload.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/send.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/management.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/resolve.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-svm-confirmation.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/reads-context.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/codec.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/registry.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/normalize-address.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/ix-encoder.spec.ts + +Test Suites: 17 passed, 17 total +Tests: 254 passed, 254 total +Snapshots: 0 total +Time: 8.468 s, estimated 10 s +Ran all test suites matching /agentic|outbound-(confirmation-gate|svm-confirmation)|svm-idl/i. diff --git a/plan/agw/research/sdk-independent-completion-2026-10-06/logs/verification.log b/plan/agw/research/sdk-independent-completion-2026-10-06/logs/verification.log new file mode 100644 index 00000000..baec7036 --- /dev/null +++ b/plan/agw/research/sdk-independent-completion-2026-10-06/logs/verification.log @@ -0,0 +1,11 @@ +AGW validation: units +AGW validation: types-lib +AGW validation: types-spec +AGW validation: types-agw-local +AGW validation: docs +AGW validation: prepare-contracts +AGW validation: local-contracts +AGW validation: build +AGW validation: package +AGW validation: public-api +AGW unfunded validation completed. From 9e9d842415c87f088df15b13782027ffbfc1e085 Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Tue, 6 Oct 2026 11:15:07 +0530 Subject: [PATCH 23/68] test(agw): add differential races and Node runtime compatibility checks --- .gitignore | 1 + .../core/__agw-local__/svm-backend.spec.ts | 162 +- .../__agw-local__/svm-differential.spec.ts | 418 + packages/core/package.json | 1 + packages/core/scripts/check-agw-api.js | 247 +- packages/core/scripts/check-agw-runtimes.js | 93 + plan/agw/README.md | 4 +- plan/agw/current-baseline.md | 2 +- plan/agw/gaps.md | 4 +- plan/agw/implementation-plan.md | 2 +- plan/agw/implementation-review-handoff.md | 2 + plan/agw/implementation-status.md | 5 +- .../sdk-hardening-2026-10-06/README.md | 38 + .../api-comparison.json | 11306 ++++++++++++++++ .../sdk-hardening-2026-10-06/changed-lint.log | 17 + .../live-receipt-recheck.json | 31 + .../sdk-hardening-2026-10-06/node20/build.log | 13 + .../sdk-hardening-2026-10-06/node20/docs.log | 1 + .../node20/full-unit.log | 168 + .../node20/local-contracts.log | 28 + .../node20/package.log | 1 + .../node20/prepare-contracts.log | 1 + .../node20/public-api.log | 1 + .../node20/types-agw-local.log | 0 .../node20/types-lib.log | 0 .../node20/types-spec.log | 0 .../sdk-hardening-2026-10-06/node20/units.log | 23 + .../node20/verification.log | 11 + .../node20/version.log | 1 + .../sdk-hardening-2026-10-06/node24/build.log | 13 + .../sdk-hardening-2026-10-06/node24/docs.log | 1 + .../node24/full-unit.log | 168 + .../node24/local-contracts.log | 28 + .../node24/package.log | 1 + .../node24/prepare-contracts.log | 1 + .../node24/public-api.log | 1 + .../node24/types-agw-local.log | 0 .../node24/types-lib.log | 0 .../node24/types-spec.log | 0 .../sdk-hardening-2026-10-06/node24/units.log | 23 + .../node24/verification.log | 11 + .../node24/version.log | 1 + .../runtime-results.json | 21 + 43 files changed, 12838 insertions(+), 12 deletions(-) create mode 100644 packages/core/__agw-local__/svm-differential.spec.ts create mode 100644 packages/core/scripts/check-agw-runtimes.js create mode 100644 plan/agw/research/sdk-hardening-2026-10-06/README.md create mode 100644 plan/agw/research/sdk-hardening-2026-10-06/api-comparison.json create mode 100644 plan/agw/research/sdk-hardening-2026-10-06/changed-lint.log create mode 100644 plan/agw/research/sdk-hardening-2026-10-06/live-receipt-recheck.json create mode 100644 plan/agw/research/sdk-hardening-2026-10-06/node20/build.log create mode 100644 plan/agw/research/sdk-hardening-2026-10-06/node20/docs.log create mode 100644 plan/agw/research/sdk-hardening-2026-10-06/node20/full-unit.log create mode 100644 plan/agw/research/sdk-hardening-2026-10-06/node20/local-contracts.log create mode 100644 plan/agw/research/sdk-hardening-2026-10-06/node20/package.log create mode 100644 plan/agw/research/sdk-hardening-2026-10-06/node20/prepare-contracts.log create mode 100644 plan/agw/research/sdk-hardening-2026-10-06/node20/public-api.log create mode 100644 plan/agw/research/sdk-hardening-2026-10-06/node20/types-agw-local.log create mode 100644 plan/agw/research/sdk-hardening-2026-10-06/node20/types-lib.log create mode 100644 plan/agw/research/sdk-hardening-2026-10-06/node20/types-spec.log create mode 100644 plan/agw/research/sdk-hardening-2026-10-06/node20/units.log create mode 100644 plan/agw/research/sdk-hardening-2026-10-06/node20/verification.log create mode 100644 plan/agw/research/sdk-hardening-2026-10-06/node20/version.log create mode 100644 plan/agw/research/sdk-hardening-2026-10-06/node24/build.log create mode 100644 plan/agw/research/sdk-hardening-2026-10-06/node24/docs.log create mode 100644 plan/agw/research/sdk-hardening-2026-10-06/node24/full-unit.log create mode 100644 plan/agw/research/sdk-hardening-2026-10-06/node24/local-contracts.log create mode 100644 plan/agw/research/sdk-hardening-2026-10-06/node24/package.log create mode 100644 plan/agw/research/sdk-hardening-2026-10-06/node24/prepare-contracts.log create mode 100644 plan/agw/research/sdk-hardening-2026-10-06/node24/public-api.log create mode 100644 plan/agw/research/sdk-hardening-2026-10-06/node24/types-agw-local.log create mode 100644 plan/agw/research/sdk-hardening-2026-10-06/node24/types-lib.log create mode 100644 plan/agw/research/sdk-hardening-2026-10-06/node24/types-spec.log create mode 100644 plan/agw/research/sdk-hardening-2026-10-06/node24/units.log create mode 100644 plan/agw/research/sdk-hardening-2026-10-06/node24/verification.log create mode 100644 plan/agw/research/sdk-hardening-2026-10-06/node24/version.log create mode 100644 plan/agw/research/sdk-hardening-2026-10-06/runtime-results.json diff --git a/.gitignore b/.gitignore index c3a31375..a3622c68 100644 --- a/.gitignore +++ b/.gitignore @@ -61,3 +61,4 @@ e2e-logs/ /graphify-out .agw-validation/ .ci-contracts/ +.agw-runtime-validation/ diff --git a/packages/core/__agw-local__/svm-backend.spec.ts b/packages/core/__agw-local__/svm-backend.spec.ts index a965d909..f6fc5ef4 100644 --- a/packages/core/__agw-local__/svm-backend.spec.ts +++ b/packages/core/__agw-local__/svm-backend.spec.ts @@ -1,6 +1,12 @@ /** Internal SVM lifecycle/execution on actual v4 contracts; no Solana/TSS simulation. */ import { PublicKey } from '@solana/web3.js'; -import { encodeFunctionData, parseAbi, type Address, type Hex } from 'viem'; +import { + encodeFunctionData, + encodeErrorResult, + parseAbi, + type Address, + type Hex, +} from 'viem'; import { CHAIN, type PushChain } from '../src'; import type { AgenticRuntime } from '../src/lib/agentic/runtime'; import { Snapshot } from '../src/lib/agentic/reads/snapshot'; @@ -386,4 +392,158 @@ describe('internal prepared SVM backend on v4', () => { rt(owner).execute = execute; } }); + it.each(['allowance', 'balance', 'revocation'])( + 'on-chain %s change after preflight refuses submission without metering', + async (kind) => { + const s = await setup(), + runtime = rt(s.agent), + original = runtime.execute; + const before = await cfg(s.wallet, s.id); + const nonce = await h.publicClient.getTransactionCount({ + address: h.wallets[1].account!.address, + blockTag: 'pending', + }); + let ticks: bigint | undefined; + runtime.execute = async (params, options) => { + if (kind === 'revocation') + await ( + await owner.agentic.wallet(s.wallet).rules.revoke([s.id]) + ).wait(); + else + await h.write(0, s.wallet, v4.abis.wallet, 'execute', [ + key('00'), + v4.packSingle({ + target: tokens[2], + value: BigInt(0), + data: encodeFunctionData({ + abi: parseAbi([ + 'function approve(address,uint256) returns(bool)', + 'function transfer(address,uint256) returns(bool)', + ]), + functionName: kind === 'allowance' ? 'approve' : 'transfer', + args: [ + kind === 'allowance' + ? h.addresses.gateway + : h.wallets[0].account!.address, + kind === 'allowance' ? BigInt(0) : BigInt(100), + ], + }), + }), + ]); + ticks = await h.publicClient.readContract({ + address: s.wallet, + abi: v4.abis.wallet, + functionName: 'checkpointCount', + }); + return original(params, options); + }; + try { + const error = await sendSvmAgentWire( + runtime, + h.generation, + s.request(), + metadata + ).catch((e) => e); + expect(error.name).toBe('AgenticRevertError'); + if (kind === 'revocation') + expect(error.decodedError?.name).toBe('CallerIsNotAgent'); + else { + const name = kind === 'allowance' ? 'LowAllowance' : 'LowBalance'; + const data = encodeErrorResult({ + abi: parseAbi([`error ${name}()`]), + errorName: name, + }); + expect(error.message).toContain(data); + } + const stored = await h.publicClient.readContract({ + address: h.addresses.rulesPolicy, + abi: v4.abis.policy, + functionName: 'getSvmConfig', + args: [before.configId, s.wallet], + }); + expect(stored.assets.map((a) => a.spent)).toEqual([ + BigInt(0), + BigInt(0), + BigInt(0), + ]); + expect( + await h.publicClient.getTransactionCount({ + address: h.wallets[1].account!.address, + blockTag: 'pending', + }) + ).toBe(nonce); + expect( + await h.publicClient.readContract({ + address: s.wallet, + abi: v4.abis.wallet, + functionName: 'checkpointCount', + }) + ).toBe(ticks); + } finally { + runtime.execute = original; + } + } + ); + it('an RPC outage during rule reads fails before execute or signing', async () => { + const s = await setup(), + runtime = rt(s.agent), + reader = runtime.reader, + read = reader.readContract.bind(reader); + const execute = jest.spyOn(runtime, 'execute'); + const failedReader = { + ...reader, + readContract: async (args: Parameters[0]) => { + if (args.functionName === 'getSvmConfig') + throw new Error('fixture RPC outage'); + return read(args); + }, + }; + const failed = { ...runtime, reader: failedReader }; + await expect( + sendSvmAgentWire(failed, h.generation, s.request(), metadata) + ).rejects.toMatchObject({ code: 'RULE_READ_FAILED' }); + expect(execute).not.toHaveBeenCalled(); + expect( + (await cfg(s.wallet, s.id)).config.assets.map((a) => a.spent) + ).toEqual([BigInt(0), BigInt(0), BigInt(0)]); + }); + it('receipt failure after a mined grant retains the hash and does not retry', async () => { + const s = await setup(), + runtime = rt(owner), + original = runtime.execute; + let hash: Hex | undefined, + submissions = 0; + runtime.execute = async (params, options) => { + submissions++; + const tx = await original(params, options); + hash = tx.hash as Hex; + await h.publicClient.waitForTransactionReceipt({ hash }); + tx.wait = async () => { + throw new Error('fixture receipt outage'); + }; + return tx; + }; + try { + await expect( + grantSvmWire(runtime, h.generation, s.wallet, s.input) + ).rejects.toMatchObject({ + code: 'RECEIPT_UNAVAILABLE', + details: { txHash: expect.any(String) }, + }); + expect(submissions).toBe(1); + expect(hash).toBeDefined(); + expect( + await h.publicClient.readContract({ + address: s.wallet, + abi: v4.abis.wallet, + functionName: 'grantNonce', + }) + ).toBe(BigInt(2)); + expect( + (await h.publicClient.getTransactionReceipt({ hash: hash! })).status + ).toBe('success'); + } finally { + runtime.execute = original; + } + }); }); diff --git a/packages/core/__agw-local__/svm-differential.spec.ts b/packages/core/__agw-local__/svm-differential.spec.ts new file mode 100644 index 00000000..5dc93cfd --- /dev/null +++ b/packages/core/__agw-local__/svm-differential.spec.ts @@ -0,0 +1,418 @@ +/** Seeded, independent SDK-vs-contract comparisons. No live transport/funding. */ +import { + encodeAbiParameters, + encodeFunctionData, + parseAbi, + type Hex, +} from 'viem'; +import { CHAIN } from '../src/lib/constants/enums'; +import { buildSession, encodeEnvelope } from '../src/lib/agentic/codec/session'; +import { + SVM_TERMS_PARAM, + validateSvmTerms, + type SvmTermsWire, +} from '../src/lib/agentic/codec/svm-terms'; +import { + encodeAgwSvmPayload, + validateAgwSvmPayload, +} from '../src/lib/agentic/execution/svm-payload'; +import { v4 } from '../src/lib/agentic/contracts/v4'; +import { deriveAgwSvmValueAccounts } from '../src/lib/agentic/codec/svm-accounts'; +import { decodeAgenticRevert } from '../src/lib/agentic/revert'; +import { startHarness, type Harness } from './harness'; +const key = (b: string) => `0x${b.repeat(32)}` as Hex; +const GATEWAY = key('22'), + PROGRAM = key('33'); +const TOKEN = parseAbi([ + 'function mint(address,uint256)', + 'function approve(address,uint256) returns(bool)', +]); +const seed = 0x5a17; +let rng = seed; +function random(n: number) { + rng = (Math.imul(rng, 1664525) + 1013904223) >>> 0; + return rng % n; +} +const clone = (t: T): T => structuredClone(t); + +describe('seeded SVM differential validation', () => { + let h: Harness, wallet: `0x${string}`, token: `0x${string}`; + let terms: SvmTermsWire; + beforeAll(async () => { + h = await startHarness(18555); + token = await h.deploy(0, 'HarnessPRC20', 'HarnessFixtures.sol', [ + CHAIN.SOLANA_DEVNET, + 9, + ]); + wallet = ( + await (await h.client(0)).agentic.create('differential', { rules: [] }) + ).wallet; + const derived = deriveAgwSvmValueAccounts(wallet, GATEWAY, []); + terms = { + ...derived, + validUntil: Math.floor(Date.now() / 1000) + 3600, + assets: [{ token, maxPerCall: BigInt(10), maxTotal: BigInt(100) }], + maxGasPerCall: BigInt(10) ** BigInt(16), + programs: [ + { + program: PROGRAM, + discriminator: '0x0100000000000000', + discriminatorLen: 1, + dataless: false, + maxAccounts: 1, + }, + ], + pins: [{ ruleIndex: 0, accountIndex: 0, expected: derived.expectedCEA }], + dataPins: [], + }; + }); + afterAll(async () => h?.stop()); + const session = (t: SvmTermsWire) => + buildSession({ + validator: h.addresses.validator, + rulesPolicy: h.addresses.rulesPolicy, + agent: h.wallets[1].account!.address, + actions: [ + { + target: h.addresses.gateway, + selector: '0x77b86bec', + initData: encodeEnvelope( + CHAIN.SOLANA_DEVNET, + encodeAbiParameters([SVM_TERMS_PARAM], [t]) + ), + }, + ], + }); + + it('grant-shape corpus agrees with the actual URP initializer', async () => { + const cases: { name: string; terms: SvmTermsWire }[] = []; + const add = (name: string, mutate: (t: SvmTermsWire) => void) => { + const t = clone(terms); + mutate(t); + cases.push({ name, terms: t }); + }; + add('base', () => { + /* Keep the baseline unchanged for the first comparison. */ + }); + for (const per of [ + BigInt(0), + BigInt(1), + (BigInt(1) << BigInt(64)) - BigInt(1), + (BigInt(1) << BigInt(256)) - BigInt(1), + ]) + for (const total of [ + BigInt(0), + BigInt(1), + (BigInt(1) << BigInt(64)) - BigInt(1), + (BigInt(1) << BigInt(256)) - BigInt(1), + ]) + add(`caps-${per}-${total}`, (t) => { + t.assets = [{ token, maxPerCall: per, maxTotal: total }]; + }); + add('zero-pc-hard-cap', (t) => { + t.maxGasPerCall = BigInt(0); + }); + add('zero-assets', (t) => { + t.assets = []; + }); + add('duplicate-asset', (t) => { + t.assets = [...t.assets, t.assets[0]]; + }); + add('zero-token', (t) => { + t.assets = [ + { ...t.assets[0], token: '0x0000000000000000000000000000000000000000' }, + ]; + }); + add('empty-programs', (t) => { + t.programs = []; + }); + add('zero-cea', (t) => { + t.expectedCEA = key('00'); + }); + add('zero-gateway', (t) => { + t.gatewayProgram = key('00'); + }); + add('zero-expiry', (t) => { + t.validUntil = 0; + }); + add('no-pins', (t) => { + t.pins = []; + }); + add('duplicate-pin', (t) => { + t.pins = [...t.pins, t.pins[0]]; + }); + add('pin-rule-outside', (t) => { + t.pins[0].ruleIndex = 1; + }); + add('pin-index-outside', (t) => { + t.pins[0].accountIndex = 64; + }); + add('no-cea-coverage', (t) => { + t.ceaAccounts = []; + }); + add('duplicate-cea', (t) => { + t.ceaAccounts = [t.expectedCEA, t.expectedCEA]; + }); + add('forbidden-program', (t) => { + t.programs[0].program = t.gatewayProgram; + }); + add('overlapping-program-rules', (t) => { + t.programs = [...t.programs, { ...t.programs[0] }]; + t.pins = [...t.pins, { ...t.pins[0], ruleIndex: 1 }]; + }); + for (const count of [0, 1, 63, 64, 65]) + add(`account-count-${count}`, (t) => { + t.programs[0].maxAccounts = count; + }); + for (const len of [0, 1, 8, 9]) + add(`tag-len-${len}`, (t) => { + t.programs[0].discriminatorLen = len; + }); + add('dataless', (t) => { + t.programs[0].dataless = true; + t.programs[0].discriminatorLen = 0; + }); + for (let i = 0; i < 64; i++) { + const mode = random(4), + width = [0, 1, 2, 8, 9, 32, 33][random(7)], + fromEnd = Boolean(random(2)); + const offset = [0, 1, width, 1024 - width, 1024, 1025][random(6)]; + add(`pin-seed-${i}`, (t) => { + t.dataPins = [ + { + ruleIndex: 0, + fromEnd, + offset, + offsetB: width, + len: width, + mode, + expected: key('00'), + num: BigInt(mode === 3 ? random(2) : 0), + den: BigInt(mode === 3 ? random(2) : 0), + }, + ]; + }); + } + const mismatches: string[] = []; + let accepted = 0, + rejected = 0; + const now = Number((await h.publicClient.getBlock()).timestamp); + for (const c of cases) { + let sdk = true, + contract = true; + try { + validateSvmTerms(c.terms, now); + } catch { + sdk = false; + } + try { + await h.publicClient.call({ + to: wallet, + data: v4.encodeGrantRules(session(c.terms)), + account: h.wallets[0].account!.address, + }); + } catch (e) { + contract = false; + expect(decodeAgenticRevert(e)).toBeDefined(); + } + if (contract) accepted++; + else rejected++; + if (sdk !== contract) + mismatches.push(c.name + `: sdk=${sdk},contract=${contract}`); + } + expect(accepted).toBeGreaterThan(0); + expect(rejected).toBeGreaterThan(0); + expect(mismatches).toEqual([]); + console.log( + JSON.stringify({ + corpus: 'svm-grant', + seed, + cases: cases.length, + accepted, + rejected, + mismatches, + }) + ); + }); + + it('payload mutation corpus agrees with actual URP authorization and rejects without metering', async () => { + const t = clone(terms); + t.programs[0].maxAccounts = 0; + t.dataPins = [ + { + ruleIndex: 0, + fromEnd: false, + offset: 1, + offsetB: 0, + len: 1, + mode: 1, + expected: `0x${'00'.repeat(31)}05`, + num: BigInt(0), + den: BigInt(0), + }, + ]; + await h.write(0, wallet, v4.abis.wallet, 'grantRules', [session(t)]); + const [id] = await h.publicClient.readContract({ + address: h.addresses.engine, + abi: v4.abis.engine, + functionName: 'getPermissionIDs', + args: [wallet], + }); + await h.publicClient.waitForTransactionReceipt({ + hash: await h.wallets[4].sendTransaction({ + to: wallet, + value: BigInt(10) ** BigInt(18), + account: h.wallets[4].account!, + chain: h.wallets[4].chain, + }), + }); + await h.write(0, token, TOKEN, 'mint', [wallet, BigInt(100)]); + await h.write(0, wallet, v4.abis.wallet, 'execute', [ + key('00'), + v4.packSingle({ + target: token, + value: BigInt(0), + data: encodeFunctionData({ + abi: TOKEN, + functionName: 'approve', + args: [h.addresses.gateway, BigInt(100)], + }), + }), + ]); + const base = encodeAgwSvmPayload( + PROGRAM, + [{ pubkey: t.expectedCEA, isWritable: true }], + new Uint8Array([1, 5]) + ); + const cases: { name: string; payload: Hex }[] = [ + { name: 'base', payload: base }, + ]; + for (const amount of [0, 4, 5, 6, 255]) + cases.push({ + name: `floor-${amount}`, + payload: encodeAgwSvmPayload( + PROGRAM, + [{ pubkey: t.expectedCEA, isWritable: true }], + new Uint8Array([1, amount]) + ), + }); + cases.push({ + name: 'uncovered-cea-alias', + payload: encodeAgwSvmPayload( + PROGRAM, + [ + { pubkey: t.expectedCEA, isWritable: true }, + { pubkey: t.expectedCEA, isWritable: false }, + ], + new Uint8Array([1, 5]) + ), + }); + cases.push({ + name: 'pin-substitution', + payload: encodeAgwSvmPayload( + PROGRAM, + [{ pubkey: key('66'), isWritable: true }], + new Uint8Array([1, 5]) + ), + }); + for (let i = 0; i < 80; i++) { + const bytes = Buffer.from(base.slice(2), 'hex'); + if (i % 4 === 0) + cases.push({ + name: `truncate-${i}`, + payload: `0x${bytes + .subarray(0, random(bytes.length)) + .toString('hex')}`, + }); + else if (i % 4 === 1) + cases.push({ + name: `trailing-${i}`, + payload: `${base}${random(256).toString(16).padStart(2, '0')}` as Hex, + }); + else { + const at = random(bytes.length); + bytes[at] ^= 1 << random(8); + cases.push({ + name: `flip-${i}-${at}`, + payload: `0x${bytes.toString('hex')}`, + }); + } + } + const mismatches: string[] = []; + let accepted = 0, + rejected = 0; + for (const c of cases) { + let sdk = true, + contract = true; + try { + validateAgwSvmPayload(t, PROGRAM, c.payload); + } catch { + sdk = false; + } + const data = encodeFunctionData({ + abi: parseAbi([ + 'function sendUniversalTxOutbound((bytes recipient,address token,uint256 amount,uint256 gasLimit,uint256 gasPrice,uint256 maxPCForGas,bytes payload,address revertRecipient) req) payable', + ]), + functionName: 'sendUniversalTxOutbound', + args: [ + { + recipient: PROGRAM, + token, + amount: BigInt(1), + gasLimit: BigInt(200_000), + gasPrice: BigInt(0), + maxPCForGas: BigInt(10) ** BigInt(15), + payload: c.payload, + revertRecipient: wallet, + }, + ], + }); + try { + await h.publicClient.simulateContract({ + address: wallet, + abi: v4.abis.wallet, + functionName: 'executeAsAgent', + args: [ + id, + key('00'), + v4.packSingle({ + target: h.addresses.gateway, + value: BigInt(11) * BigInt(10) ** BigInt(14), + data, + }), + ], + account: h.wallets[1].account!.address, + }); + } catch (e) { + contract = false; + expect(decodeAgenticRevert(e)).toBeDefined(); + } + if (contract) accepted++; + else rejected++; + if (sdk !== contract) + mismatches.push(c.name + `: sdk=${sdk},contract=${contract}`); + } + expect(accepted).toBeGreaterThan(0); + expect(rejected).toBeGreaterThan(0); + expect(mismatches).toEqual([]); + // Every case used eth_call; even successful probes cannot spend an asset. + expect( + await h.publicClient.readContract({ + address: token, + abi: parseAbi(['function balanceOf(address) view returns(uint256)']), + functionName: 'balanceOf', + args: [wallet], + }) + ).toBe(BigInt(100)); + console.log( + JSON.stringify({ + corpus: 'svm-payload', + seed, + cases: cases.length, + accepted, + rejected, + mismatches, + }) + ); + }); +}); diff --git a/packages/core/package.json b/packages/core/package.json index a1920f4b..7572d206 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -55,6 +55,7 @@ "agw:verify": "node scripts/agw-verify.js", "agw:check:package": "node scripts/check-agw-package.js", "agw:check:api": "node scripts/check-agw-api.js", + "agw:check:runtimes": "node scripts/check-agw-runtimes.js", "e2e:list": "ts-node --transpile-only __e2e__/ci/run.ts --list", "e2e:verify": "ts-node --transpile-only __e2e__/ci/run.ts --verify", "e2e:preflight": "ts-node --transpile-only __e2e__/ci/preflight.ts", diff --git a/packages/core/scripts/check-agw-api.js b/packages/core/scripts/check-agw-api.js index 7ff4ca8f..41cde023 100644 --- a/packages/core/scripts/check-agw-api.js +++ b/packages/core/scripts/check-agw-api.js @@ -46,6 +46,168 @@ function snapshot(entry) { const checker = program.getTypeChecker(), file = program.getSourceFile(entry); const exports = checker.getExportsOfModule(checker.getSymbolAtLocation(file)); + const literals = new Map(), + ambiguous = new Set(); + for (const source of program + .getSourceFiles() + .filter((f) => f.fileName.includes('/packages/core/src/'))) { + for (let symbol of checker.getSymbolsInScope( + source, + ts.SymbolFlags.Value + )) { + const name = symbol.name; + if (symbol.flags & ts.SymbolFlags.Alias) + symbol = checker.getAliasedSymbol(symbol); + const type = checker.getTypeOfSymbolAtLocation(symbol, source); + if (type.flags & ts.TypeFlags.EnumLiteral) continue; + const literal = type.isStringLiteral() + ? JSON.stringify(type.value) + : type.isNumberLiteral() + ? String(type.value) + : undefined; + if (literal === undefined) continue; + if (literals.has(name) && literals.get(name) !== literal) + ambiguous.add(name); + else literals.set(name, literal); + } + } + const printer = ts.createPrinter({ removeComments: true }); + const modules = new Map( + program + .getSourceFiles() + .filter((f) => f.fileName.includes('/packages/core/src/')) + .map((f) => [ + 'sdk/src/' + + f.fileName + .split('/src/') + .pop() + .replace(/\.d\.ts$|\.tsx?$/, ''), + f, + ]) + ); + function reference(match, kind, module, name) { + const source = + modules.get(module) || + program.getSourceFile(module + '.d.ts') || + program.getSourceFile(module + '.ts'); + if (!source) return match; + const moduleSymbol = checker.getSymbolAtLocation(source); + let symbol = [ + ...(moduleSymbol ? checker.getExportsOfModule(moduleSymbol) : []), + ...checker.getSymbolsInScope( + source, + ts.SymbolFlags.Type | ts.SymbolFlags.Value | ts.SymbolFlags.Namespace + ), + ].find((s) => s.name === name); + if (!symbol) return match; + if (symbol.flags & ts.SymbolFlags.Alias) + symbol = checker.getAliasedSymbol(symbol); + const decl = symbol.declarations?.[0]; + if (!decl) return match; + if (!kind && symbol.flags & ts.SymbolFlags.TypeAlias) { + const type = checker.getDeclaredTypeOfSymbol(symbol); + if ( + type.flags & + (ts.TypeFlags.StringLike | + ts.TypeFlags.NumberLike | + ts.TypeFlags.BooleanLike | + ts.TypeFlags.BigIntLike | + ts.TypeFlags.TemplateLiteral | + ts.TypeFlags.Null | + ts.TypeFlags.Undefined) + ) + return normal( + checker.typeToString( + type, + file, + ts.TypeFormatFlags.NoTruncation | ts.TypeFormatFlags.InTypeAlias + ) + ); + } + if (kind === 'typeof ') { + const type = checker.getTypeOfSymbolAtLocation(symbol, decl); + const calls = type.getCallSignatures(); + if (calls.length === 1) + return normal( + checker.signatureToString( + calls[0], + file, + ts.TypeFormatFlags.NoTruncation | + ts.TypeFormatFlags.WriteArrowStyleSignature + ) + ); + } + const location = decl.getSourceFile().fileName; + if (!location.includes('/packages/core/src/')) return match; + return `${kind || ''}import("sdk/src/${location + .split('/src/') + .pop() + .replace(/\.d\.ts$|\.tsx?$/, '')}").${symbol.name}`; + } + function canonicalType(text) { + for (let pass = 0; pass < 4; pass++) + text = text.replace( + /(typeof )?import\("([^"]+)"\)\.([A-Za-z_][\w]*)/g, + reference + ); + text = text.replace( + /typeof import\("[^"]+"\)\.([A-Za-z_][\w]*)/g, + (match, name) => + ambiguous.has(name) ? match : literals.get(name) || match + ); + const parsed = ts.createSourceFile( + 'surface.ts', + `type Surface = ${text};`, + ts.ScriptTarget.Latest, + true + ); + const result = ts.transform(parsed, [ + (context) => { + const visit = (node) => { + node = ts.visitEachChild(node, visit, context); + if (ts.isUnionTypeNode(node) || ts.isIntersectionTypeNode(node)) { + const types = [...node.types].sort((a, b) => + printer + .printNode(ts.EmitHint.Unspecified, a, parsed) + .localeCompare( + printer.printNode(ts.EmitHint.Unspecified, b, parsed) + ) + ); + return ts.isUnionTypeNode(node) + ? ts.factory.createUnionTypeNode(types) + : ts.factory.createIntersectionTypeNode(types); + } + if ( + ts.isTypeLiteralNode(node) && + node.members.every( + (m) => ts.isPropertySignature(m) || ts.isMethodSignature(m) + ) + ) { + return ts.factory.createTypeLiteralNode( + [...node.members].sort((a, b) => + printer + .printNode(ts.EmitHint.Unspecified, a.name, parsed) + .localeCompare( + printer.printNode(ts.EmitHint.Unspecified, b.name, parsed) + ) + ) + ); + } + return node; + }; + return (source) => ts.visitNode(source, visit); + }, + ]); + try { + return printer.printNode( + ts.EmitHint.Unspecified, + result.transformed[0].statements[0].type, + parsed + ); + } finally { + result.dispose(); + } + } const normal = (s) => s.replace( /import\("([^"]+)"\)/g, @@ -55,13 +217,28 @@ function snapshot(entry) { }")` ); const text = (t, node) => - normal(checker.typeToString(t, node, ts.TypeFormatFlags.NoTruncation)); + canonicalType( + normal( + checker.typeToString( + t, + node, + ts.TypeFormatFlags.NoTruncation | ts.TypeFormatFlags.InTypeAlias + ) + ) + ); function properties(t) { return Object.fromEntries( checker .getPropertiesOfType(t) .filter((p) => { const d = p.valueDeclaration || p.declarations?.[0]; + if ( + d && + /\/typescript\/lib\/lib\.[^/]+\.d\.ts$/.test( + d.getSourceFile().fileName + ) + ) + return false; return ( !d || !( @@ -71,16 +248,42 @@ function snapshot(entry) { ); }) .map((p) => [ - p.name, + p.name.replace(/(__@[^@]+)@\d+$/, '$1'), { optional: Boolean(p.flags & ts.SymbolFlags.Optional), + readonly: Boolean( + ts.getCheckFlags(p) & ts.CheckFlags.Readonly || + p.declarations?.some( + (d) => + ts.getCombinedModifierFlags(d) & ts.ModifierFlags.Readonly + ) + ), type: text(checker.getTypeOfSymbolAtLocation(p, file), file), }, ]) .sort(([a], [b]) => a.localeCompare(b)) ); } - const result = { exports: exports.map((s) => s.name).sort(), agw: {} }; + const result = { + exports: exports.map((s) => s.name).sort(), + agw: {}, + publicSurface: {}, + }; + for (let s of exports) { + const name = s.name; + if (s.flags & ts.SymbolFlags.Alias) s = checker.getAliasedSymbol(s); + const t = + s.flags & + (ts.SymbolFlags.Interface | + ts.SymbolFlags.TypeAlias | + ts.SymbolFlags.Class) + ? checker.getDeclaredTypeOfSymbol(s) + : checker.getTypeOfSymbolAtLocation(s, file); + result.publicSurface[name] = { + type: text(t, file), + members: properties(t), + }; + } for (const name of selected) { let s = exports.find((s) => s.name === name); if (!s) continue; @@ -97,6 +300,18 @@ function snapshot(entry) { let push = exports.find((s) => s.name === 'PushChain'); if (push.flags & ts.SymbolFlags.Alias) push = checker.getAliasedSymbol(push); const staticType = checker.getTypeOfSymbolAtLocation(push, file); + const instanceType = checker.getDeclaredTypeOfSymbol(push); + result.pushChainStatic = properties(staticType); + delete result.pushChainStatic.prototype; + result.pushChainInstance = properties(instanceType); + const universal = instanceType.getProperty('universal'); + result.transactionMethods = properties( + checker.getTypeOfSymbolAtLocation(universal, file) + ); + const utils = staticType.getProperty('utils'); + const utilsType = checker.getTypeOfSymbolAtLocation(utils, file); + result.utilityMethods = properties(utilsType); + delete result.utilityMethods.prototype; const init = staticType.getProperty('initialize'); result.initialize = text(checker.getTypeOfSymbolAtLocation(init, file), file); const constants = staticType.getProperty('CONSTANTS'); @@ -107,6 +322,7 @@ function snapshot(entry) { result.agwConstants = properties( checker.getNonNullableType(checker.getTypeOfSymbolAtLocation(donut, file)) ); + result.constants = properties(cType); return result; } const current = snapshot(path.join(root, 'packages/core/src/index.ts')); @@ -146,6 +362,23 @@ try { for (const name of selected) if (JSON.stringify(old.agw[name]) !== JSON.stringify(current.agw[name])) changes.push(name); + const publicTypeChanges = Object.keys(current.publicSurface).filter( + (name) => + JSON.stringify(old.publicSurface[name]) !== + JSON.stringify(current.publicSurface[name]) + ); + const transactionMethodChanges = Object.keys( + current.transactionMethods + ).filter( + (name) => + JSON.stringify(old.transactionMethods[name]) !== + JSON.stringify(current.transactionMethods[name]) + ); + const instanceMethodChanges = Object.keys(current.pushChainInstance).filter( + (name) => + JSON.stringify(old.pushChainInstance[name]) !== + JSON.stringify(current.pushChainInstance[name]) + ); const report = { baseline, head: execFileSync('git', ['rev-parse', 'HEAD'], { @@ -157,12 +390,15 @@ try { addedExports: current.exports.filter((s) => !old.exports.includes(s)), removedExports: old.exports.filter((s) => !current.exports.includes(s)), changedAgwTypes: changes, + publicTypeChanges, + transactionMethodChanges, + instanceMethodChanges, agwConstantsChanged: JSON.stringify(old.agwConstants) !== JSON.stringify(current.agwConstants), before: old, after: current, scope: - 'Root exports, AGW types, initialize and agentic constants. Behavioral/default/deployment changes need the written session review.', + 'All root exports and declared public members, PushChain static/instance members, universal transaction methods, utility groups, readonly/optional markers and constants. Behavior/default/deployment changes need the written session review.', }; const at = process.argv.indexOf('--output'); if (at >= 0) @@ -176,6 +412,9 @@ try { addedExports: report.addedExports, removedExports: report.removedExports, changedAgwTypes: changes, + publicTypeChanges, + transactionMethodChanges, + instanceMethodChanges, initializeSignatureChanged: report.initializeSignatureChanged, agwConstantsChanged: report.agwConstantsChanged, }) + '\n' diff --git a/packages/core/scripts/check-agw-runtimes.js b/packages/core/scripts/check-agw-runtimes.js new file mode 100644 index 00000000..6161bc73 --- /dev/null +++ b/packages/core/scripts/check-agw-runtimes.js @@ -0,0 +1,93 @@ +/** Local runtime matrix only. Never dispatch GitHub CI, fund E2Es or publish. */ +const fs = require('node:fs'), + path = require('node:path'); +const { spawnSync } = require('node:child_process'); +const root = path.resolve(__dirname, '../../..'); +const argument = (name) => { + const at = process.argv.indexOf(name); + return at < 0 ? undefined : process.argv[at + 1]; +}; +const binaries = [ + { major: 20, node: argument('--node20') || process.execPath }, + { major: 24, node: argument('--node24') }, +]; +if (!binaries[1].node) + throw new Error( + 'Provide --node24 ; --node20 defaults to the current executable.' + ); +const output = path.resolve( + argument('--output') || path.join(root, '.agw-runtime-validation') +); +fs.mkdirSync(output, { recursive: true }); +const results = []; +function command(dir, node, args, env, name) { + const result = spawnSync(node, args, { + cwd: root, + env, + encoding: 'utf8', + maxBuffer: 30 * 1024 * 1024, + }); + fs.writeFileSync( + path.join(dir, name + '.log'), + String(result.stdout || '') + String(result.stderr || '') + ); + if (result.error || result.status !== 0) + throw new Error(`Node ${node} failed ${name}; see ${dir}/${name}.log`); + return result.stdout; +} +for (const runtime of binaries) { + const dir = path.join(output, 'node' + runtime.major); + fs.mkdirSync(dir, { recursive: true }); + const env = { + ...process.env, + PATH: path.dirname(runtime.node) + path.delimiter + process.env.PATH, + }; + const version = command( + dir, + runtime.node, + [ + '-p', + 'JSON.stringify({version:process.version,major:Number(process.versions.node.split(".")[0]),platform:process.platform,arch:process.arch})', + ], + env, + 'version' + ); + const actual = JSON.parse(version); + if (actual.major !== runtime.major) + throw new Error(`Expected Node ${runtime.major}, got ${actual.version}`); + process.stdout.write(`AGW runtime matrix: ${actual.version}\n`); + command( + dir, + runtime.node, + [ + 'node_modules/jest/bin/jest.js', + '--config', + 'packages/core/jest.config.ts', + '--runInBand', + ], + env, + 'full-unit' + ); + command( + dir, + runtime.node, + ['packages/core/scripts/agw-verify.js'], + env, + 'verification' + ); + for (const file of fs.readdirSync(path.join(root, '.agw-validation'))) { + const source = path.join(root, '.agw-validation', file); + if (fs.statSync(source).isFile()) + fs.copyFileSync(source, path.join(dir, file)); + } + results.push({ ...actual, passed: true }); +} +fs.writeFileSync( + path.join(output, 'results.json'), + JSON.stringify( + { results, hostedCi: false, published: false, fundedE2Es: false }, + null, + 2 + ) + '\n' +); +process.stdout.write('Both runtime matrix entries passed.\n'); diff --git a/plan/agw/README.md b/plan/agw/README.md index e90148dc..5a291d1f 100644 --- a/plan/agw/README.md +++ b/plan/agw/README.md @@ -2,7 +2,7 @@ This package contains the SDK implementation plan, source snapshots, open decisions and validation evidence. Current work is on feat/agw-sdk-v4. Runtime commits are a66ff7d (v4/SVM foundations) and b68bab7 (gas headroom); current validation is linked below. Native/EVM support now uses the checked Donut v4 deployment; old runtime adapters/ABIs/fixtures were removed. All 25 registered AGW scenarios have passing bounded live coverage, including native/UEA identities and Sepolia outbound success/failure. -Latest: [live acceptance and fixes](research/live-acceptance-2026-10-06/README.md), following the [v4 migration](research/v4-implementation-2026-10-06/README.md). The unrestricted full core unit run passes 1,975 tests; the actual-contract harness passes 68. Build and four typechecks pass. Native defaults/raw-offset API/multi-rule selection decisions, absent ref/labels, public SVM integration and release scope remain explicit. +Latest: [live acceptance and fixes](research/live-acceptance-2026-10-06/README.md), following the [v4 migration](research/v4-implementation-2026-10-06/README.md). The unrestricted full core unit run passes 1,975 tests; the actual-contract harness passes 75. Build and four typechecks pass. Native defaults/raw-offset API/multi-rule selection decisions, absent ref/labels, public SVM integration and release scope remain explicit. The public target remains [Notion page 5](notion/5-sdk-agw.md), qualified by [Harsh's replies](product-decisions-2026-10-04.md) and [live comments](research/notion-comments-2026-10-05.md). The [v4 deployment/owner-guide review](research/deployment-review-2026-10-06/README.md) records the supplied deployed wire definitions. Historical adapter-absence statements in that review describe the pre-migration inspection, not current implementation. @@ -12,6 +12,8 @@ Latest SDK-owned work: [delayed-index contract acceptance and checked consumer g Latest: [all nine SDK-owned items completed](research/sdk-independent-completion-2026-10-06/README.md). Internal SVM integration, Solana confirmation, CI and package/API checks are complete; public SVM remains gated. +Latest validation: [selected differential/race/API/runtime hardening](research/sdk-hardening-2026-10-06/README.md). Both Node 20/24 pass; existing live E2E receipts are independently rechecked. + ## Start here | Document | Purpose | diff --git a/plan/agw/current-baseline.md b/plan/agw/current-baseline.md index 131c11fa..8b538a1f 100644 --- a/plan/agw/current-baseline.md +++ b/plan/agw/current-baseline.md @@ -61,7 +61,7 @@ The ABI comparison found matching factory/wallet/engine function/event/error sig Four checks passed: version-1 envelope round-trip/old first-word incompatibility; synthetic ordered two-asset tuple round-trip; live v4 getConfig decode with old-ABI rejection; array assertion encoding. [Results and limits](research/deployment-review-2026-10-06/wire-checks.json). This is not a rule-grant, stale-spend transaction or funded E2E proof. -The unrestricted run passes 1,975 unit and 68 actual-contract tests. All five explorer ABI sets match the isolated build. Donut is registered and all 25 registered native/EVM/identity cases have passing coverage. [Current acceptance evidence](research/live-acceptance-2026-10-06/README.md). +The unrestricted run passes 1,975 unit and 75 actual-contract tests. All five explorer ABI sets match the isolated build. Donut is registered and all 25 registered native/EVM/identity cases have passing coverage. [Current acceptance evidence](research/live-acceptance-2026-10-06/README.md). ## Remaining decisions and acceptance diff --git a/plan/agw/gaps.md b/plan/agw/gaps.md index 00d6f2fd..5de643d5 100644 --- a/plan/agw/gaps.md +++ b/plan/agw/gaps.md @@ -2,7 +2,7 @@ Updated October 6, 2026 after the [v4 deployment/owner-guide review](research/deployment-review-2026-10-06/README.md), [Harsh’s replies](product-decisions-2026-10-04.md), v4 implementation on feat/agw-sdk-v4, and [live Notion comments](research/notion-comments-2026-10-05.md). This register distinguishes unresolved dependencies, implemented SDK work, deferred scope and historical corrections. G01–G26 are tracking IDs, not a count of open defects. -Evidence: [current baseline](current-baseline.md), [implementation status](implementation-status.md), [product alignment validation](research/product-alignment-2026-10-04/README.md). The unrestricted v4 SDK run passes 1,975 unit tests and 68 local-contract tests. All 25 registered live scenarios have passing coverage. The independent SDK follow-up adds delayed-index actual-contract checks and consumer documentation; public SVM destinations remain gated. +Evidence: [current baseline](current-baseline.md), [implementation status](implementation-status.md), [product alignment validation](research/product-alignment-2026-10-04/README.md). The unrestricted v4 SDK run passes 1,975 unit tests and 75 local-contract tests. All 25 registered live scenarios have passing coverage. The independent SDK follow-up adds delayed-index actual-contract checks and consumer documentation; public SVM destinations remain gated. Current contract baseline: reported deployed source `e8db748`, documentation head `deploy-agw@10a24f1` (src unchanged between them). Donut v4 addresses/code/wiring and URP 3.1.0 were checked at block 23931055; verified ABIs were saved. The SDK now uses v4 only, registers Donut and has a ported actual-contract harness. [Implementation evidence](research/v4-implementation-2026-10-06/README.md). Core marketplace cb69e0b and gateway bcbf7df remain prior source pins; they were not freshly fetched. Notion bodies were not refreshed in this pass. @@ -54,7 +54,7 @@ P0 blocks agreed authorization/accounting or safe final integration. P1 affects ## Validation and release boundaries -The [current acceptance evidence](research/live-acceptance-2026-10-06/README.md) records 1,975 passing unit tests, 68 actual-contract tests, build/four typechecks and seven existing lint errors. All 25 opt-in AGW scenarios have passing bounded selected-run coverage; default all remains 76. Native/UEA/7702, lifecycle, allowance, responses and Sepolia success/failure pass. The initial positive-amount Push transaction exposed insufficient gas headroom. A tested 20% headroom fix passes the bounded retry, including token debit, allowance reduction, destination receipt/CEA balance and replay checks. Destination-revert classification also passes. +The [current acceptance evidence](research/live-acceptance-2026-10-06/README.md) records 1,975 passing unit tests, 75 actual-contract tests, build/four typechecks and seven existing lint errors. All 25 opt-in AGW scenarios have passing bounded selected-run coverage; default all remains 76. Native/UEA/7702, lifecycle, allowance, responses and Sepolia success/failure pass. The initial positive-amount Push transaction exposed insufficient gas headroom. A tested 20% headroom fix passes the bounded retry, including token debit, allowance reduction, destination receipt/CEA balance and replay checks. Destination-revert classification also passes. Local batch proof uses actual AGW/factory/engine/policy and real Anvil EIP-7702 transactions, with a small fixture executor. UEA shaping/replay is unit-tested and reuses the existing transport; all registered native/EVM/UEA acceptance scenarios now pass. Public Solana destination coverage remains outstanding. diff --git a/plan/agw/implementation-plan.md b/plan/agw/implementation-plan.md index eb265eab..5de1a5f1 100644 --- a/plan/agw/implementation-plan.md +++ b/plan/agw/implementation-plan.md @@ -1,6 +1,6 @@ # Complete AGW SDK implementation plan -Updated October 6, 2026. The v4-only native/EVM implementation uses deployed source e8db748 and the Donut manifest. Old runtime/test adapters and single-asset codecs are removed. The unfiltered unit suite passes 1,975 tests; all 68 actual-contract Anvil cases pass; build and four typechecks pass. All 25 registered AGW live scenarios pass across selected runs; remaining work is public SVM integration and release scope decisions. [Current acceptance and remaining coverage](research/live-acceptance-2026-10-06/README.md). +Updated October 6, 2026. The v4-only native/EVM implementation uses deployed source e8db748 and the Donut manifest. Old runtime/test adapters and single-asset codecs are removed. The unfiltered unit suite passes 1,975 tests; all 75 actual-contract Anvil cases pass; build and four typechecks pass. All 25 registered AGW live scenarios pass across selected runs; remaining work is public SVM integration and release scope decisions. [Current acceptance and remaining coverage](research/live-acceptance-2026-10-06/README.md). SVM internal terms/accounts/payload/builder are implemented and validated. Public SVM mapping/dispatch remains gated. Remaining decisions are H3 native defaults, H4.5 raw-offset public shape, H6 send selection and ref/label v1 scope. Earlier plan recommendations below are qualified by those accepted decisions and the current implementation status. diff --git a/plan/agw/implementation-review-handoff.md b/plan/agw/implementation-review-handoff.md index b385678c..328991f6 100644 --- a/plan/agw/implementation-review-handoff.md +++ b/plan/agw/implementation-review-handoff.md @@ -1,5 +1,7 @@ # AGW SDK implementation — review handoff +> Latest: [selected hardening and exact live-E2E status](research/sdk-hardening-2026-10-06/README.md). Node 20/24 pass 1,975 units and 75 local cases; the seeded differential corpus has zero mismatches. No new SDK API, hosted CI, release or funded-run change in this batch. + > Latest: [nine SDK-owned tasks completed](research/sdk-independent-completion-2026-10-06/README.md), including internal SVM integration and shared confirmation. 1,975 units and 68 actual-contract tests pass. Public SVM and pending product choices remain gated; automated API comparison is saved. > Latest SDK-owned follow-up: [six delayed-index contract cases, checked consumer examples and package documentation](research/sdk-independent-followup-2026-10-06/README.md). All 59 local actual-contract cases pass; the prior 25 live scenarios remain passing evidence. Public SDK APIs and pending decisions are unchanged by this follow-up. diff --git a/plan/agw/implementation-status.md b/plan/agw/implementation-status.md index 1aa2bbb9..3d16fed0 100644 --- a/plan/agw/implementation-status.md +++ b/plan/agw/implementation-status.md @@ -1,6 +1,6 @@ # AGW SDK implementation status -> Latest: [funded acceptance and fixes](research/live-acceptance-2026-10-06/README.md). Full permissions are restored: 1,975 unfiltered unit tests, all 68 Anvil cases, build and four typechecks pass. All 25 registered AGW scenarios pass across selected live runs, including UEA identities, native 7702 batches, lifecycle and Sepolia success/failure. Public SVM destinations remain gated. +> Latest: [funded acceptance and fixes](research/live-acceptance-2026-10-06/README.md). Full permissions are restored: 1,975 unfiltered unit tests, all 75 Anvil cases, build and four typechecks pass. All 25 registered AGW scenarios pass across selected live runs, including UEA identities, native 7702 batches, lifecycle and Sepolia success/failure. Public SVM destinations remain gated. Updated October 6, 2026. Branch feat/agw-sdk-v4; runtime commits a66ff7d and b68bab7. The native/EVM migration uses deployed source e8db748. Runtime/test e704d5b adapters, ABIs and fixtures were removed at Shoaib's request; historical review documents are evidence only. [Full handoff, commands and validation](research/v4-implementation-2026-10-06/README.md). @@ -9,8 +9,9 @@ Updated October 6, 2026. Branch feat/agw-sdk-v4; runtime commits a66ff7d and b68 | Level | Current evidence | | --- | --- | | Unit | 1,975 passed, 0 failed; 12 skipped; 115 suites passed, 1 skipped | -| Local actual contracts | 68 passed, 0 failed; 9 suites against e8db748 on Anvil | +| Local actual contracts | 75 passed, 0 failed; 10 suites against e8db748 on Anvil | | ABI reproduction | All 5 explorer ABI entry sets match the isolated build, ignoring array order | +| Runtime matrix | Node 20.19.2 and 24.14.0 pass full units, local contracts and package/API checks | | Build/typechecks | Build and lib/spec/local/AGW-E2E typechecks pass | | Lint | 7 pre-existing errors in unchanged files; no new errors | | E2E selection | AGW: 25 scenarios/9 files/25 tests; default all unchanged at 76/40/81 | diff --git a/plan/agw/research/sdk-hardening-2026-10-06/README.md b/plan/agw/research/sdk-hardening-2026-10-06/README.md new file mode 100644 index 00000000..af717f89 --- /dev/null +++ b/plan/agw/research/sdk-hardening-2026-10-06/README.md @@ -0,0 +1,38 @@ +# Selected SDK hardening — October 6, 2026 + +Shoaib approved items 2, 3, 4 and 5 only. Hosted CI execution and release preparation were excluded and were not performed. This batch changes tests and developer verification scripts, not production SDK API/transaction behavior. + +## Completed items + +| Item | Evidence | +| --- | --- | +| 2 Differential SVM validation | A reproducible seeded corpus (seed 23063) compares SDK validation directly with actual v4 URP initialization and authorization. 107 grant-shape cases (38 accepted/69 rejected), including uint64/uint256 cap boundaries, and 88 payload cases (6 accepted/82 rejected), including truncation/trailing bytes, pin substitution, aliasing, account counts and data floors. Zero accept/reject mismatches. Successful eth_call probes leave token balances unchanged. | +| 3 Races/faults | Five new actual-contract cases cover allowance revocation, token balance withdrawal and rule revocation after preflight, plus RPC failure during reads and receipt loss after a mined grant. Failures are checked by expected code/revert selector, agent nonce, spend counters and checkpoints. Receipt loss preserves the submitted hash and does not retry. Existing replacement/spend/initialization/nonce races remain. | +| 4 Broader API audit | Comparison now covers all root exports and their public declared members, static/instance PushChain members, universal transaction/tracking methods, utility groups, constants and optional/readonly markers. Transparent aliases, barrel forwarding, const-assertion readonly state, property/union ordering and compiler-generated symbol IDs are canonicalized. Source public declarations match built declarations. | +| 5 Runtime matrix | Node 20.19.2 and 24.14.0 pass the full unit run and the unfunded verification command: targeted units, lib/spec/local types, guide, local contracts, build, CJS/ESM consumer imports, built declaration examples, npm dry-run and API comparison. These are local macOS arm64 results, not a hosted Linux CI result. | + +## Results + +Both runtime entries: 1,975 unit passes (12 existing skips, 115 passed suites/1 skipped), 75 actual-contract passes in 10 suites, no open-handle warning or forceExit. Differential cases are probes inside two Jest tests; they are not reported as 195 additional Jest passes. Changed-file lint: 0 errors, 11 conventional non-null assertion warnings in tests. + +[Runtime versions/results](runtime-results.json). Logs are in [node20/](node20/) and [node24/](node24/). The runtime runner takes explicit binary paths and copies per-runtime results before the next run; it dispatches no GitHub jobs, loads no .env keys, funds no live E2Es and publishes nothing. + +## API findings + +[Full comparison](api-comparison.json) against session baseline b1597b9: no added/removed root exports, no initialize signature change, no universal transaction/tracking method changes and no instance-member changes. Root-visible type differences are AGENTIC_ERROR_CODE, its dependent AgenticErrorCode/AgenticError code types, AllowedCall.beneficiaryOffset and AgenticNetworkConstants.ENVELOPE_VERSION. These arose in the earlier v4 migration. Native defaults, raw-offset authoring and rule selection remain externally unresolved. This batch adds no public SDK field/method. + +## Actual live E2E status + +**Actual funded runs have happened.** [The registered scenario matrix](../live-acceptance-2026-10-06/scenario-results.json) records 25 distinct passing AGW scenarios across selected sequential Donut runs, including native/UEA identities, grants/update/revoke/checkpoints, native batching/rollback, allowance, progress/replay and Sepolia call-only/positive-amount success and destination failure. It is not a claim that one complete group invocation passed without any initial failures. + +The positive outbound independently checked wallet PRC20 debit, gateway allowance reduction and burn events, successful Sepolia receipt, CEA balance increase and the CEA-emitted execution event with AGW originCaller and intended target/data. [Previous live evidence](../live-acceptance-2026-10-06/README.md). + +This batch performs a **read-only recheck**, not a new funded run: the Push and Sepolia receipts for both positive-amount and call-only sends remain successful. [Hashes, blocks and results](live-receipt-recheck.json). No new live transaction was submitted. The 75 local cases use actual contracts on Anvil with transport/metadata/destination fixtures; they are separate from live bridge/settlement evidence. No live AGW Solana-destination E2E has run because public mapping/cluster input and enablement are pending. + +## Reproduce + +```sh +AGW_LOCAL_DIR="${TMPDIR:-/tmp}/push-agw-local-v4" node packages/core/scripts/check-agw-runtimes.js --node20 /path/to/node20 --node24 /path/to/node24 +``` + +Outputs default to .agw-runtime-validation/, ignored by Git. No runtime is installed automatically. Hosted CI and release/changelog/PR preparation remain outside this approved batch. diff --git a/plan/agw/research/sdk-hardening-2026-10-06/api-comparison.json b/plan/agw/research/sdk-hardening-2026-10-06/api-comparison.json new file mode 100644 index 00000000..7101c160 --- /dev/null +++ b/plan/agw/research/sdk-hardening-2026-10-06/api-comparison.json @@ -0,0 +1,11306 @@ +{ + "baseline": "b1597b91a25dbf7f691f589b4e1e154add604315", + "head": "4d2c4d2891b6f068ad8605feb1fda29fce47a1c3", + "compiledMatchesSource": true, + "initializeSignatureChanged": false, + "addedExports": [], + "removedExports": [], + "changedAgwTypes": [ + "AgenticError", + "AGENTIC_ERROR_CODE", + "AllowedCall" + ], + "publicTypeChanges": [ + "AGENTIC_ERROR_CODE", + "AgenticError", + "AgenticErrorCode", + "AgenticNetworkConstants", + "AllowedCall" + ], + "transactionMethodChanges": [], + "instanceMethodChanges": [], + "agwConstantsChanged": true, + "before": { + "exports": [ + "AGENTIC_ERROR_CODE", + "AccountRole", + "AccountStatus", + "AccountType", + "AgenticAddress", + "AgenticDoor", + "AgenticError", + "AgenticErrorCode", + "AgenticHex", + "AgenticNamespace", + "AgenticNetworkConstants", + "AgenticProgressHook", + "AgenticRevertError", + "AgenticTxMetadata", + "AgenticWallet", + "AllowedCall", + "AssetCap", + "BatchReadResponse", + "BuildReadSpecParams", + "CHAIN", + "CONTRACT_REQUEST_STATUS", + "CascadeCompletionResult", + "CascadeHopInfo", + "CascadeProgressEvent", + "CascadeTrackOptions", + "CascadedTxResponse", + "ChainSource", + "ChainTarget", + "Checkpoint", + "CheckpointKind", + "ConversionQuote", + "CreateOptions", + "CreateResult", + "DEFAULT_MAX_PC_FOR_GAS_BUFFER_BPS", + "DecodedErrorPayload", + "DecodedReadResult", + "DerivedExecutorAccount", + "EncodedReadQuery", + "EvmReadQuery", + "ForeignChainNamespace", + "FulfilOutcome", + "FundsToken", + "InsufficientPC20BalanceError", + "InvalidPC20AddressError", + "InvalidPC20MetadataError", + "InvalidReadQueryError", + "InvalidReadSpecError", + "MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT", + "MaxPCForGasCapFromNativeValueInput", + "MaxPCForGasCapInput", + "MaxPCForGasCapQuote", + "MultiChainTxResponse", + "NativeRule", + "OutboundTxDetails", + "PC20AddressResult", + "PC20AmbiguousAddressError", + "PC20Error", + "PC20ExpectedButPRC20Error", + "PC20ExportRevertedError", + "PC20FactoryMismatchError", + "PC20RegistryEntry", + "PC20RegistryMismatchError", + "PC20TokenChainMismatchError", + "PC20TokenReference", + "PC20UnknownChainNamespaceError", + "PC20UnsafeEmptyPayloadError", + "PC20WrapperNotRegisteredError", + "PC20WrapperPredictionUnavailableError", + "ParsedReadRequest", + "PreparedRead", + "PreparedUniversalTx", + "PushChain", + "PushChainBatchExecutionError", + "PushChainExecutionError", + "PushChainInitializeOptions", + "READ_ERROR_CODE", + "READ_OUTCOME", + "READ_STATUS", + "ReadCallback", + "ReadCallbackOptions", + "ReadChain", + "ReadDecodeError", + "ReadDestination", + "ReadExecuteOptions", + "ReadFees", + "ReadHeightUnavailableError", + "ReadLifecycleOptions", + "ReadNotFoundError", + "ReadOptions", + "ReadPreflight", + "ReadPrepareOptions", + "ReadQuery", + "ReadQueryOptions", + "ReadRef", + "ReadRegistryUnavailableError", + "ReadResponseTuple", + "ReadResultShape", + "ReadSpec", + "ReadSpecTuple", + "ReadSpecViolation", + "ReadStateError", + "ReadTimeoutError", + "ReadTrackOptions", + "ReadValue", + "ReadWeb2Options", + "ReceiptLike", + "RescueFundsParams", + "ResolvedAccount", + "ResolvedControllerAccounts", + "ResolvedDestination", + "Rule", + "RulesRecord", + "Selector", + "SignAuthorizationParams", + "SignedAuthorization", + "SimulateReadResult", + "SvmExecutePayloadFields", + "SvmGatewayAccountMeta", + "SvmReadQuery", + "TERMINAL_READ_STATUSES", + "TransactionRoute", + "TransactionRouteType", + "UEAStatus", + "UNIVERSAL_CALLBACK_EVM", + "UNIVERSAL_READ_REGISTRY_EVM", + "UNIVERSAL_READ_STATUS", + "UniversalAccount", + "UniversalExecuteParams", + "UniversalOutboundTxRequest", + "UniversalReadResponse", + "UniversalRule", + "UniversalSigner", + "UniversalSignerSkeleton", + "UniversalTo", + "UnsupportedPC20DestinationError", + "UnsupportedReadDestinationError", + "ValidateReadCall", + "WaitForOutboundOptions", + "WalletInfo", + "WalletSummary", + "Web2Extract", + "Web2ReadQuery", + "Web2ValueType", + "buildErc20WithdrawalMulticall", + "buildMigrationPayload", + "buildReadSpecFromPreflight", + "chainSupportsCEA", + "chainSupportsOutbound", + "decodeReadResult", + "detectRoute", + "encodeReadQuery", + "encodeSvmExecutePayload", + "getAllCEAAddresses", + "getCEAAddress", + "getCEAFactoryAddress", + "getPushAccountForCEA", + "inferResultShape", + "isCEA", + "isChainTarget", + "isPC20Reference", + "isSvmChain", + "isValidSolanaHexAddress", + "parseFulfilOutcome", + "parseReadRequestsFromReceipt", + "parseUEAVersion", + "quoteMaxPCForGasCap", + "quoteMaxPCForGasCapFromNativeValue", + "resolveDestination", + "sizeCallbackBudget", + "toCallData", + "toReadQuery", + "toRequestIdHex", + "validateReadSpec" + ], + "agw": { + "AgenticNamespace": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace", + "members": { + "create": { + "optional": false, + "readonly": false, + "type": "(label: string, options: import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions) => Promise" + }, + "derive": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n index?: number;\n}) => Promise<{\n address: `0x${string}`;\n deployed: boolean;\n index: number;\n}>" + }, + "list": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n wallets: import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary[];\n}>" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "(address: `0x${string}`) => import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet" + } + } + }, + "AgenticWallet": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "checkpoints": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n sinceBlock?: bigint;\n}) => Promise<{\n checkpoints: import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint[];\n}>" + }, + "info": { + "optional": false, + "readonly": false, + "type": "() => Promise" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n owner: `0x${string}`;\n}>" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "{\n add(rules: import(\"sdk/src/lib/agentic/agentic.types\").Rule[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise<{\n rulesIds: `0x${string}`[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n get(rulesId: `0x${string}`): Promise;\n list(): Promise<{\n rules: import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord[];\n }>;\n revoke(rulesIds: `0x${string}`[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n revoke(params: {\n all: true;\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n update(params: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n rules: {\n rule: import(\"sdk/src/lib/agentic/agentic.types\").Rule;\n rulesId: `0x${string}`;\n }[];\n }): Promise<{\n rules: {\n replaced: `0x${string}`;\n rulesId: `0x${string}`;\n }[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n}" + }, + "setLabel": { + "optional": false, + "readonly": false, + "type": "(label: string, opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n}) => Promise" + } + } + }, + "AgenticError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"CREATE_PARTIAL\" | \"DUPLICATE_RULE\" | \"FROM_NOT_ALLOWED\" | \"GATEWAY_ALLOWANCE_INSUFFICIENT\" | \"GENERATION_UNSUPPORTED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"REVOKE_NEEDS_TARGET\" | \"RULE_LIMIT_EXCEEDED\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"" + }, + "details": { + "optional": true, + "readonly": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "AgenticRevertError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticRevertError", + "members": { + "agenticCode": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + } + } + }, + "AGENTIC_ERROR_CODE": { + "type": "{\n readonly AGENT_GAS_INSUFFICIENT: \"AGENT_GAS_INSUFFICIENT\";\n readonly AGENT_IS_OWNER: \"AGENT_IS_OWNER\";\n readonly ASSET_CHAIN_MISMATCH: \"ASSET_CHAIN_MISMATCH\";\n readonly CAPABILITY_UNAVAILABLE: \"CAPABILITY_UNAVAILABLE\";\n readonly CREATE_PARTIAL: \"CREATE_PARTIAL\";\n readonly DUPLICATE_RULE: \"DUPLICATE_RULE\";\n readonly FROM_NOT_ALLOWED: \"FROM_NOT_ALLOWED\";\n readonly GATEWAY_ALLOWANCE_INSUFFICIENT: \"GATEWAY_ALLOWANCE_INSUFFICIENT\";\n readonly GENERATION_UNSUPPORTED: \"GENERATION_UNSUPPORTED\";\n readonly INCONSISTENT_READ: \"INCONSISTENT_READ\";\n readonly INDEX_RACE: \"INDEX_RACE\";\n readonly INVALID_RULE: \"INVALID_RULE\";\n readonly NO_RULES_FOR_CHAIN: \"NO_RULES_FOR_CHAIN\";\n readonly NOT_AGENTIC_WALLET: \"NOT_AGENTIC_WALLET\";\n readonly NOT_ALLOWED_IN_AGENTIC_MODE: \"NOT_ALLOWED_IN_AGENTIC_MODE\";\n readonly NOT_OWNER_OR_AGENT: \"NOT_OWNER_OR_AGENT\";\n readonly NOT_WALLET_OWNER: \"NOT_WALLET_OWNER\";\n readonly READ_ONLY: \"READ_ONLY\";\n readonly RECEIPT_MISMATCH: \"RECEIPT_MISMATCH\";\n readonly RECEIPT_UNAVAILABLE: \"RECEIPT_UNAVAILABLE\";\n readonly REVOKE_NEEDS_TARGET: \"REVOKE_NEEDS_TARGET\";\n readonly RULE_LIMIT_EXCEEDED: \"RULE_LIMIT_EXCEEDED\";\n readonly RULE_NOT_FOUND: \"RULE_NOT_FOUND\";\n readonly RULE_READ_FAILED: \"RULE_READ_FAILED\";\n readonly TARGET_NOT_ON_RULE_CHAIN: \"TARGET_NOT_ON_RULE_CHAIN\";\n readonly WALLET_BALANCE_INSUFFICIENT: \"WALLET_BALANCE_INSUFFICIENT\";\n readonly WALLET_NOT_DEPLOYED: \"WALLET_NOT_DEPLOYED\";\n}", + "members": { + "AGENT_GAS_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\"" + }, + "AGENT_IS_OWNER": { + "optional": false, + "readonly": true, + "type": "\"AGENT_IS_OWNER\"" + }, + "ASSET_CHAIN_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"ASSET_CHAIN_MISMATCH\"" + }, + "CAPABILITY_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"CAPABILITY_UNAVAILABLE\"" + }, + "CREATE_PARTIAL": { + "optional": false, + "readonly": true, + "type": "\"CREATE_PARTIAL\"" + }, + "DUPLICATE_RULE": { + "optional": false, + "readonly": true, + "type": "\"DUPLICATE_RULE\"" + }, + "FROM_NOT_ALLOWED": { + "optional": false, + "readonly": true, + "type": "\"FROM_NOT_ALLOWED\"" + }, + "GATEWAY_ALLOWANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"GATEWAY_ALLOWANCE_INSUFFICIENT\"" + }, + "GENERATION_UNSUPPORTED": { + "optional": false, + "readonly": true, + "type": "\"GENERATION_UNSUPPORTED\"" + }, + "INCONSISTENT_READ": { + "optional": false, + "readonly": true, + "type": "\"INCONSISTENT_READ\"" + }, + "INDEX_RACE": { + "optional": false, + "readonly": true, + "type": "\"INDEX_RACE\"" + }, + "INVALID_RULE": { + "optional": false, + "readonly": true, + "type": "\"INVALID_RULE\"" + }, + "NO_RULES_FOR_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"NO_RULES_FOR_CHAIN\"" + }, + "NOT_AGENTIC_WALLET": { + "optional": false, + "readonly": true, + "type": "\"NOT_AGENTIC_WALLET\"" + }, + "NOT_ALLOWED_IN_AGENTIC_MODE": { + "optional": false, + "readonly": true, + "type": "\"NOT_ALLOWED_IN_AGENTIC_MODE\"" + }, + "NOT_OWNER_OR_AGENT": { + "optional": false, + "readonly": true, + "type": "\"NOT_OWNER_OR_AGENT\"" + }, + "NOT_WALLET_OWNER": { + "optional": false, + "readonly": true, + "type": "\"NOT_WALLET_OWNER\"" + }, + "READ_ONLY": { + "optional": false, + "readonly": true, + "type": "\"READ_ONLY\"" + }, + "RECEIPT_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_MISMATCH\"" + }, + "RECEIPT_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_UNAVAILABLE\"" + }, + "REVOKE_NEEDS_TARGET": { + "optional": false, + "readonly": true, + "type": "\"REVOKE_NEEDS_TARGET\"" + }, + "RULE_LIMIT_EXCEEDED": { + "optional": false, + "readonly": true, + "type": "\"RULE_LIMIT_EXCEEDED\"" + }, + "RULE_NOT_FOUND": { + "optional": false, + "readonly": true, + "type": "\"RULE_NOT_FOUND\"" + }, + "RULE_READ_FAILED": { + "optional": false, + "readonly": true, + "type": "\"RULE_READ_FAILED\"" + }, + "TARGET_NOT_ON_RULE_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"TARGET_NOT_ON_RULE_CHAIN\"" + }, + "WALLET_BALANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"WALLET_BALANCE_INSUFFICIENT\"" + }, + "WALLET_NOT_DEPLOYED": { + "optional": false, + "readonly": true, + "type": "\"WALLET_NOT_DEPLOYED\"" + } + } + }, + "NativeRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "amount": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AmountLimit | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "maxCalls": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValuePerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxValueTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "pins": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ArgPin[] | undefined" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "AssetCap": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap", + "members": { + "maxPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/constants/tokens\").MoveableToken" + } + } + }, + "AllowedCall": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall", + "members": { + "beneficiary": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValue": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "`${string}(${string})` | `0x${string}`" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "UniversalRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall[]" + }, + "assets": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap[]" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "`eip155:${string}` | `solana:${string}`" + }, + "maxGasPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "RulesRecord": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "enabled": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "ref": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "rule": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule | import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule" + }, + "rulesId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "CreateOptions": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions", + "members": { + "progressHook": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook | undefined" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Rule[]" + } + } + }, + "CreateResult": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateResult", + "members": { + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "rulesIds": { + "optional": false, + "readonly": false, + "type": "`0x${string}`[]" + }, + "tx": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticTxMetadata": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticTxMetadata", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destinationAccount": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "destinationCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "door": { + "optional": false, + "readonly": false, + "type": "\"agent\" | \"owner\"" + }, + "nativeCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "rawData": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rawTo": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesId": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + } + }, + "publicSurface": { + "CHAIN": { + "type": "typeof import(\"sdk/src/lib/constants/enums\").CHAIN", + "members": { + "ARBITRUM_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA" + }, + "BASE_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA" + }, + "BNB_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET" + }, + "ETHEREUM_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET" + }, + "ETHEREUM_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA" + }, + "PUSH_LOCALNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET" + }, + "PUSH_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET" + }, + "PUSH_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET" + }, + "PUSH_TESTNET_DONUT": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET" + }, + "SOLANA_DEVNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET" + }, + "SOLANA_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET" + }, + "SOLANA_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET" + }, + "WEB2": { + "optional": false, + "readonly": false, + "type": "\"web2\"" + } + } + }, + "ConversionQuote": { + "type": "import(\"sdk/src/lib/constants/tokens\").ConversionQuote", + "members": { + "amountIn": { + "optional": false, + "readonly": false, + "type": "string" + }, + "amountOut": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rate": { + "optional": false, + "readonly": false, + "type": "number" + }, + "route": { + "optional": true, + "readonly": false, + "type": "string[] | undefined" + }, + "timestamp": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "UniversalSigner": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalSigner", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "signAndSendTransaction": { + "optional": false, + "readonly": false, + "type": "(unsignedTx: Uint8Array) => Promise" + }, + "signAuthorization": { + "optional": true, + "readonly": false, + "type": "((params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise) | undefined" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": true, + "readonly": false, + "type": "(({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise) | undefined" + } + } + }, + "UniversalAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "UniversalSignerSkeleton": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "signAndSendTransaction": { + "optional": false, + "readonly": false, + "type": "(unsignedTx: Uint8Array) => Promise" + }, + "signAuthorization": { + "optional": true, + "readonly": false, + "type": "((params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise) | undefined" + }, + "signerId": { + "optional": false, + "readonly": false, + "type": "string" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": true, + "readonly": false, + "type": "(({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise) | undefined" + } + } + }, + "SignAuthorizationParams": { + "type": "{\n chainId?: number;\n contractAddress: `0x${string}`;\n executor?: \"self\";\n nonce?: number;\n}", + "members": { + "chainId": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "contractAddress": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "executor": { + "optional": true, + "readonly": false, + "type": "\"self\" | undefined" + }, + "nonce": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "SignedAuthorization": { + "type": "{\n address: `0x${string}`;\n chainId: number;\n nonce: number;\n r: `0x${string}`;\n s: `0x${string}`;\n v?: bigint;\n yParity: number;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainId": { + "optional": false, + "readonly": false, + "type": "number" + }, + "nonce": { + "optional": false, + "readonly": false, + "type": "number" + }, + "r": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "s": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "v": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "yParity": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "DerivedExecutorAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").DerivedExecutorAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean | null" + } + } + }, + "ResolvedAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainName": { + "optional": false, + "readonly": false, + "type": "string" + }, + "exists": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "role": { + "optional": true, + "readonly": false, + "type": "\"controller\" | undefined" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"cea\" | \"uea\" | \"uoa\"" + } + } + }, + "ResolvedControllerAccounts": { + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedControllerAccounts", + "members": { + "accounts": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedAccount[]" + } + } + }, + "AccountType": { + "type": "\"cea\" | \"uea\" | \"uoa\"", + "members": {} + }, + "AccountRole": { + "type": "\"controller\"", + "members": {} + }, + "PC20TokenReference": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "FundsToken": { + "type": "import(\"sdk/src/lib/constants/tokens\").MoveableToken | import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20TokenReference", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "PC20RegistryEntry": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "chainName": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "PC20AddressResult": { + "type": "{\n address: `0x${string}`;\n decimals: number;\n name: string;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n registry: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20RegistryEntry[];\n symbol: string;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "decimals": { + "optional": false, + "readonly": false, + "type": "number" + }, + "name": { + "optional": false, + "readonly": false, + "type": "string" + }, + "network": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "registry": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20RegistryEntry[]" + }, + "symbol": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "isPC20Reference": { + "type": "(token: import(\"sdk/src/lib/orchestrator/orchestrator.types\").FundsToken | undefined) => token is import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20TokenReference", + "members": {} + }, + "PC20Error": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20Error", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidPC20AddressError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InvalidPC20AddressError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20TokenChainMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20TokenChainMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20WrapperNotRegisteredError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20WrapperNotRegisteredError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20RegistryMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20RegistryMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20FactoryMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20FactoryMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidPC20MetadataError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InvalidPC20MetadataError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20ExpectedButPRC20Error": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20ExpectedButPRC20Error", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20AmbiguousAddressError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20AmbiguousAddressError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "candidates": { + "optional": false, + "readonly": true, + "type": "{\n chain: string;\n pushAddress: string;\n}[]" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "UnsupportedPC20DestinationError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").UnsupportedPC20DestinationError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InsufficientPC20BalanceError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InsufficientPC20BalanceError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20UnknownChainNamespaceError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20UnknownChainNamespaceError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20WrapperPredictionUnavailableError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20WrapperPredictionUnavailableError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20ExportRevertedError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20ExportRevertedError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "lockedAmount": { + "optional": true, + "readonly": true, + "type": "bigint | undefined" + }, + "outboundTxId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "revertRecipient": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20UnsafeEmptyPayloadError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20UnsafeEmptyPayloadError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ChainTarget": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "ChainSource": { + "type": "{\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "UniversalTo": { + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget", + "members": {} + }, + "TransactionRouteType": { + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"", + "members": {} + }, + "UniversalExecuteParams": { + "type": "{\n from?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainSource;\n migration?: boolean;\n to: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTo;\n} & Omit", + "members": { + "_minimumDepositUsd": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "_requiredFundsOverride": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "_skipFeeLocking": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "_ueaStatus": { + "optional": true, + "readonly": false, + "type": "{\n balance: bigint;\n isDeployed: boolean;\n nonce: bigint;\n} | undefined" + }, + "data": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiCall[] | undefined" + }, + "deadline": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "feeLockTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "from": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainSource | undefined" + }, + "funds": { + "optional": true, + "readonly": false, + "type": "{\n amount: bigint;\n token?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").FundsToken;\n} | undefined" + }, + "gasLimit": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFeePerGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxPCForGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxPriorityFeePerGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "migration": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "nonce": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "options": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions | undefined" + }, + "payGasWith": { + "optional": true, + "readonly": false, + "type": "{\n minAmountOut?: bigint | string;\n slippageBps?: number;\n token?: import(\"sdk/src/lib/constants/tokens\").PayableToken;\n} | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "to": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget" + }, + "value": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "UniversalOutboundTxRequest": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalOutboundTxRequest", + "members": { + "amount": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gasPrice": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxPCForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "payload": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "recipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "revertRecipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "PreparedUniversalTx": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx", + "members": { + "_hop": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").HopDescriptor" + }, + "deadline": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "estimatedGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gatewayRequest": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalOutboundTxRequest | import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxRequest" + }, + "nonce": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "payload": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + } + } + }, + "CascadedTxResponse": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadedTxResponse", + "members": { + "finalTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hopCount": { + "optional": false, + "readonly": false, + "type": "number" + }, + "hops": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo[]" + }, + "initialTxHash": { + "optional": false, + "readonly": false, + "type": "string" + }, + "initialTxResponse": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions) => Promise" + }, + "waitForAll": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions) => Promise" + } + } + }, + "CascadeHopInfo": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo", + "members": { + "executionChain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "expectedSubTxId": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hopIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "outboundDetails": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").OutboundTxDetails | undefined" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + }, + "status": { + "optional": false, + "readonly": false, + "type": "\"confirmed\" | \"failed\" | \"pending\" | \"submitted\"" + }, + "txHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "CascadeTrackOptions": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions", + "members": { + "eventHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeProgressEvent) => void) | undefined" + }, + "timeout": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "CascadeProgressEvent": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeProgressEvent", + "members": { + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "elapsed": { + "optional": false, + "readonly": false, + "type": "number" + }, + "hopIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + }, + "status": { + "optional": false, + "readonly": false, + "type": "\"confirmed\" | \"failed\" | \"found\" | \"polling\" | \"timeout\" | \"waiting\"" + }, + "txHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "CascadeCompletionResult": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeCompletionResult", + "members": { + "failedAt": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "finalTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "finalTxResponse": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadedTxResponse | undefined" + }, + "hops": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo[]" + }, + "success": { + "optional": false, + "readonly": false, + "type": "boolean" + } + } + }, + "MultiChainTxResponse": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiChainTxResponse", + "members": { + "chains": { + "optional": false, + "readonly": false, + "type": "{\n blockNumber: bigint;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n hash: string;\n status: \"confirmed\" | \"failed\" | \"pending\";\n}[]" + }, + "transactions": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse[]" + } + } + }, + "OutboundTxDetails": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").OutboundTxDetails", + "members": { + "amount": { + "optional": false, + "readonly": false, + "type": "string" + }, + "assetAddr": { + "optional": false, + "readonly": false, + "type": "string" + }, + "destinationChain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "explorerUrl": { + "optional": false, + "readonly": false, + "type": "string" + }, + "externalTxHash": { + "optional": false, + "readonly": false, + "type": "string" + }, + "recipient": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "WaitForOutboundOptions": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").WaitForOutboundOptions", + "members": { + "_expectedDestinationChain": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "_outboundIndex": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "_resolvedSubTxId": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "initialWaitMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: {\n elapsed: number;\n status: \"failed\" | \"found\" | \"polling\" | \"timeout\" | \"waiting\";\n}) => void) | undefined" + }, + "timeout": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "SvmGatewayAccountMeta": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmGatewayAccountMeta", + "members": { + "isWritable": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "pubkey": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "SvmExecutePayloadFields": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmExecutePayloadFields", + "members": { + "accounts": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmGatewayAccountMeta[]" + }, + "instructionId": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "ixData": { + "optional": false, + "readonly": false, + "type": "Uint8Array" + }, + "targetProgram": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AccountStatus": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus", + "members": { + "mode": { + "optional": false, + "readonly": false, + "type": "\"read-only\" | \"signer\"" + }, + "uea": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UEAStatus" + } + } + }, + "UEAStatus": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UEAStatus", + "members": { + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "loaded": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "minRequiredVersion": { + "optional": false, + "readonly": false, + "type": "string" + }, + "requiresUpgrade": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "version": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "RescueFundsParams": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").RescueFundsParams", + "members": { + "prc20": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "universalTxId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "parseUEAVersion": { + "type": "(version: string) => number", + "members": {} + }, + "TransactionRoute": { + "type": "typeof import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute", + "members": { + "CEA_TO_CEA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.CEA_TO_CEA" + }, + "CEA_TO_PUSH": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.CEA_TO_PUSH" + }, + "UOA_TO_CEA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.UOA_TO_CEA" + }, + "UOA_TO_PUSH": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.UOA_TO_PUSH" + } + } + }, + "detectRoute": { + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams) => import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute", + "members": {} + }, + "isChainTarget": { + "type": "(to: unknown) => to is import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget", + "members": {} + }, + "DEFAULT_MAX_PC_FOR_GAS_BUFFER_BPS": { + "type": "1000", + "members": {} + }, + "MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT": { + "type": "10000", + "members": {} + }, + "quoteMaxPCForGasCap": { + "type": "(input: import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapInput) => import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": {} + }, + "quoteMaxPCForGasCapFromNativeValue": { + "type": "(input: import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapFromNativeValueInput) => import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": {} + }, + "MaxPCForGasCapInput": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapInput", + "members": { + "bufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "gasLegNativePc": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "MaxPCForGasCapFromNativeValueInput": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapFromNativeValueInput", + "members": { + "bufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "nativeValueForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "MaxPCForGasCapQuote": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": { + "bufferBps": { + "optional": false, + "readonly": false, + "type": "number" + }, + "gasLegNativePc": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxPCForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "nativeValueForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "getCEAAddress": { + "type": "(ueaAddress: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise", + "members": {} + }, + "getPushAccountForCEA": { + "type": "(ceaAddress: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise<`0x${string}`>", + "members": {} + }, + "isCEA": { + "type": "(address: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise", + "members": {} + }, + "chainSupportsCEA": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "chainSupportsOutbound": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "getCEAFactoryAddress": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => `0x${string}` | undefined", + "members": {} + }, + "getAllCEAAddresses": { + "type": "(ueaAddress: `0x${string}`, rpcUrls?: Partial>) => Promise", + "members": {} + }, + "encodeSvmExecutePayload": { + "type": "(fields: import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmExecutePayloadFields) => `0x${string}`", + "members": {} + }, + "isSvmChain": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "isValidSolanaHexAddress": { + "type": "(address: string) => boolean", + "members": {} + }, + "buildMigrationPayload": { + "type": "() => `0x${string}`", + "members": {} + }, + "buildErc20WithdrawalMulticall": { + "type": "(tokenAddress: `0x${string}`, recipientAddress: `0x${string}`, amount: bigint) => import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiCall[]", + "members": {} + }, + "ReadChain": { + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain", + "members": {} + }, + "ReadDestination": { + "type": "{\n chain: import(\"sdk/src/lib/read-state/read-state.types\").ReadChain;\n} | {\n chainId: string;\n chainNamespace: string;\n}", + "members": {} + }, + "ResolvedDestination": { + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}", + "members": { + "caip2": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainId": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "namespace": { + "optional": false, + "readonly": false, + "type": "\"eip155\" | \"solana\" | \"web2\"" + } + } + }, + "ReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").SvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery", + "members": { + "type": { + "optional": false, + "readonly": false, + "type": "\"accountBalance\" | \"contractCall\" | \"http\" | \"lamportBalance\" | \"rawAccountData\" | \"splTokenAccount\" | \"storageSlot\"" + } + } + }, + "EvmReadQuery": { + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n target: `0x${string}`;\n type: \"contractCall\";\n} | {\n callData: `0x${string}`;\n target: `0x${string}`;\n type: \"contractCall\";\n} | {\n slot: `0x${string}` | bigint;\n target: `0x${string}`;\n type: \"storageSlot\";\n} | {\n target: `0x${string}`;\n type: \"accountBalance\";\n}", + "members": { + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"accountBalance\" | \"contractCall\" | \"storageSlot\"" + } + } + }, + "SvmReadQuery": { + "type": "{\n account: string | Uint8Array;\n accountName?: string;\n idl?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n type: \"rawAccountData\";\n} | {\n account: string | Uint8Array;\n type: \"lamportBalance\";\n} | {\n account: string | Uint8Array;\n type: \"splTokenAccount\";\n}", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "string | Uint8Array" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"lamportBalance\" | \"rawAccountData\" | \"splTokenAccount\"" + } + } + }, + "Web2ReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery", + "members": { + "body": { + "optional": true, + "readonly": false, + "type": "string | Uint8Array | undefined" + }, + "extract": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[]" + }, + "headers": { + "optional": true, + "readonly": false, + "type": "Record | undefined" + }, + "method": { + "optional": true, + "readonly": false, + "type": "\"GET\" | \"POST\" | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"http\"" + }, + "url": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "Web2Extract": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract", + "members": { + "decimals": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "path": { + "optional": false, + "readonly": false, + "type": "string" + }, + "valueType": { + "optional": false, + "readonly": false, + "type": "\"bool\" | \"bytes\" | \"int256\" | \"string\" | \"uint256\"" + } + } + }, + "Web2ValueType": { + "type": "\"bool\" | \"bytes\" | \"int256\" | \"string\" | \"uint256\"", + "members": {} + }, + "EncodedReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery", + "members": { + "blockRef": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "encoded": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "namespace": { + "optional": false, + "readonly": false, + "type": "\"eip155\" | \"solana\" | \"web2\"" + }, + "ownerBytes": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "queryType": { + "optional": false, + "readonly": false, + "type": "number" + }, + "resultShape": { + "optional": false, + "readonly": false, + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}" + }, + "warnings": { + "optional": false, + "readonly": false, + "type": "string[]" + } + } + }, + "ReadResultShape": { + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"bytes32\" | \"evmCall\" | \"raw\" | \"svmAccount\" | \"uint256\" | \"web2\"" + } + } + }, + "DecodedReadResult": { + "type": "{\n accountName: string;\n kind: \"svmAccount\";\n value: unknown;\n} | {\n kind: \"bytes32\";\n value: `0x${string}`;\n} | {\n kind: \"evmCall\";\n value: unknown;\n} | {\n kind: \"raw\";\n value: `0x${string}`;\n} | {\n kind: \"uint256\";\n value: bigint;\n} | {\n kind: \"web2\";\n values: readonly unknown[];\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"bytes32\" | \"evmCall\" | \"raw\" | \"svmAccount\" | \"uint256\" | \"web2\"" + } + } + }, + "ReadPreflight": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight", + "members": { + "destination": { + "optional": false, + "readonly": false, + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}" + }, + "fetchedAt": { + "optional": false, + "readonly": false, + "type": "number" + }, + "observedChainHeight": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pushBlockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pushGasPrice": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "universalCallback": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "universalCore": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ReadSpec": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "{\n chainId: string;\n chainNamespace: string;\n owner: `0x${string}`;\n}" + }, + "blockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "expiryPushChainHeight": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "minConfirmations": { + "optional": false, + "readonly": false, + "type": "number" + }, + "query": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "revertRecipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ReadSpecTuple": { + "type": "readonly [\n readonly [\n string,\n string,\n `0x${string}`\n ],\n `0x${string}`,\n number,\n bigint,\n bigint,\n bigint,\n `0x${string}`\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "readonly [\n string,\n string,\n `0x${string}`\n]" + }, + "1": { + "optional": false, + "readonly": true, + "type": "`0x${string}`" + }, + "2": { + "optional": false, + "readonly": true, + "type": "number" + }, + "3": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "4": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "5": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "6": { + "optional": false, + "readonly": true, + "type": "`0x${string}`" + }, + "length": { + "optional": false, + "readonly": true, + "type": "7" + } + } + }, + "BuildReadSpecParams": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").BuildReadSpecParams", + "members": { + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "budgetBuffer": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback | undefined" + }, + "callbackBudget": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "destination": { + "optional": false, + "readonly": false, + "type": "{\n chain: import(\"sdk/src/lib/read-state/read-state.types\").ReadChain;\n} | {\n chainId: string;\n chainNamespace: string;\n}" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "expiryPushChainHeight": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFeeBufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "owner": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "query": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").SvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "PreparedRead": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead", + "members": { + "__@preparedReadValue": { + "optional": true, + "readonly": true, + "type": "T | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback | undefined" + }, + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "encodedQuery": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery" + }, + "encodedSpec": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "fees": { + "optional": false, + "readonly": false, + "type": "{\n callbackBudget: bigint;\n protocolFee: bigint;\n total: bigint;\n}" + }, + "preflight": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "queryKey": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "resultShape": { + "optional": false, + "readonly": false, + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}" + }, + "spec": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec" + }, + "specTuple": { + "optional": false, + "readonly": false, + "type": "readonly [\n readonly [\n string,\n string,\n `0x${string}`\n ],\n `0x${string}`,\n number,\n bigint,\n bigint,\n bigint,\n `0x${string}`\n]" + }, + "value": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "warnings": { + "optional": false, + "readonly": false, + "type": "string[]" + } + } + }, + "ReadCallback": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "((spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpecTuple, callbackGasLimit: bigint) => readonly unknown[]) | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "gasLimit": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "target": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "SimulateReadResult": { + "type": "{\n args?: readonly unknown[];\n error: string;\n errorName?: string;\n ok: false;\n} | {\n ok: true;\n}", + "members": { + "ok": { + "optional": false, + "readonly": false, + "type": "boolean" + } + } + }, + "ParsedReadRequest": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ParsedReadRequest", + "members": { + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackTarget": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "logIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "originalFunder": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "requestId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "requestIdUint": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "spec": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec" + }, + "totalPaid": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "FulfilOutcome": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").FulfilOutcome", + "members": { + "burned": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "delivered": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "expired": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "failReason": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "gasReported": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refunded": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refundFailed": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "ReceiptLike": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike", + "members": { + "logs": { + "optional": false, + "readonly": false, + "type": "readonly {\n address: string;\n data: string;\n logIndex?: number | string;\n topics: readonly string[];\n}[]" + } + } + }, + "ReadRef": { + "type": "{\n requestId: `0x${string}` | bigint;\n} | {\n txHash: `0x${string}`;\n}", + "members": {} + }, + "ReadLifecycleOptions": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadLifecycleOptions", + "members": { + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "resultShape": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadFees": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadFees", + "members": { + "burned": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "paid": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "refunded": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refundFailed": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + } + } + }, + "UniversalReadResponse": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse", + "members": { + "callbackDelivered": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "callbackFailReason": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "decoded": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").DecodedReadResult | undefined" + }, + "decodeError": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destination": { + "optional": false, + "readonly": false, + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}" + }, + "errorMsg": { + "optional": false, + "readonly": false, + "type": "string" + }, + "explorerUrl": { + "optional": false, + "readonly": false, + "type": "string" + }, + "fees": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadFees" + }, + "isTerminal": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "outcome": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME" + }, + "pcTx": { + "optional": false, + "readonly": false, + "type": "readonly {\n blockHeight: number;\n errorMsg: string;\n status: string;\n txHash: `0x${string}`;\n}[]" + }, + "raw": { + "optional": false, + "readonly": false, + "type": "{\n errorCode: import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n resultData: `0x${string}`;\n status: import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n} | null" + }, + "refresh": { + "optional": false, + "readonly": false, + "type": "() => Promise>" + }, + "request": { + "optional": false, + "readonly": false, + "type": "{\n callbackGasLimit: bigint;\n callbackTarget: `0x${string}`;\n createdAtHeight: bigint;\n logIndex: number;\n originalFunder: `0x${string}`;\n refundTo: `0x${string}`;\n spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec;\n}" + }, + "requestId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "requestIdUint": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "status": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "value": { + "optional": true, + "readonly": false, + "type": "T | undefined" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/read-state/read-state.types\").ReadLifecycleOptions) => Promise>" + } + } + }, + "ReadResponseTuple": { + "type": "{\n -readonly [K in keyof R]: import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse ? T : unknown>;\n}", + "members": {} + }, + "BatchReadResponse": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").BatchReadResponse", + "members": { + "atomic": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "count": { + "optional": false, + "readonly": false, + "type": "number" + }, + "reads": { + "optional": false, + "readonly": false, + "type": "{\n -readonly [K in keyof R]: import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse ? T : unknown>;\n}" + }, + "transactionHashes": { + "optional": true, + "readonly": false, + "type": "readonly `0x${string}`[] | undefined" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: Omit) => Promise>" + } + } + }, + "ReadOptions": { + "type": "((import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">)) & {\n callback?: (Pick & Required>) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n };\n}", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "advanced": { + "optional": true, + "readonly": false, + "type": "{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n} | undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "({\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} & {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n}) | ({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick & Pick & Required>) | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadPrepareOptions": { + "type": "((((({\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\">) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n}) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">)) & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n}) | ((({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n}) | ({\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\">)) & {\n blockNumber?: never;\n minConfirmations?: never;\n})) & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n}) & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "advanced": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadQueryOptions": { + "type": "({\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\">) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n}) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n}) | ({\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\">)", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadCallbackOptions": { + "type": "{\n callback?: ({\n gasLimit?: bigint;\n target: `0x${string}`;\n } & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n };\n}", + "members": { + "callback": { + "optional": true, + "readonly": false, + "type": "({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} | undefined" + } + } + }, + "ReadValue": { + "type": "O extends {\n abi: infer A extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: infer F extends string;\n} ? number extends A[\"length\"] ? unknown : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, O extends {\n args: infer Args extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n} ? Args : readonly [\n] extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> ? import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> & readonly [\n] : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>> extends infer Selected ? Selected extends {\n outputs: readonly unknown[];\n type: \"function\";\n} & import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiFunction ? {\n [key in keyof {\n [key in keyof import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"]]: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterToPrimitiveType, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"][key], import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterKind>;\n }]: {\n [key in keyof import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"]]: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterToPrimitiveType, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"][key], import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterKind>;\n }[key];\n} extends infer types ? types extends readonly [\n] ? void : types extends readonly [\n infer type\n] ? type : types : never : never : never : O extends {\n web2: {\n extract: infer E extends readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n };\n} ? {\n readonly [K in keyof E]: {\n bool: boolean;\n bytes: `0x${string}`;\n int256: bigint;\n string: string;\n uint256: bigint;\n }[E[K][\"valueType\"]];\n} : O extends {\n storageSlot: unknown;\n} ? `0x${string}` : O extends {\n idl: infer I extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} ? string extends Extract, string> ? unknown : (O extends {\n functionName: infer N extends string;\n} ? N : undefined) extends string ? import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/index\").IdlAccounts[{\n [K in Extract, string>]: Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : K> extends Lowercase<(O extends {\n functionName: infer N extends string;\n } ? N : undefined) & string extends `${infer H}_${infer T}` ? `${H}${Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : (O extends {\n functionName: infer N extends string;\n } ? N : undefined) & string> ? K : never;\n}[Extract, string>]] : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/index\").IdlAccounts[Extract, string>] : bigint", + "members": {} + }, + "ValidateReadCall": { + "type": "O extends {\n abi: infer A extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: infer F extends string;\n} ? (readonly [\n] extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> ? {\n args?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n} : {\n args: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n}) & {\n functionName: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionName;\n} : O extends {\n functionName: infer N extends string;\n idl: infer I extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} ? string extends Extract, string> ? unknown : [\n {\n [K in Extract, string>]: Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : K> extends Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : N> ? K : never;\n }[Extract, string>]\n] extends [\n never\n] ? {\n functionName: Extract, string>;\n} : unknown : unknown", + "members": {} + }, + "ReadWeb2Options": { + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options", + "members": { + "body": { + "optional": true, + "readonly": false, + "type": "string | Uint8Array | undefined" + }, + "extract": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[]" + }, + "headers": { + "optional": true, + "readonly": false, + "type": "Record | undefined" + }, + "method": { + "optional": true, + "readonly": false, + "type": "\"GET\" | \"POST\" | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadTrackOptions": { + "type": "{\n advanced?: Omit, \"enforceGasCheck\">;\n resultShape?: import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape;\n}", + "members": { + "advanced": { + "optional": true, + "readonly": false, + "type": "Omit<{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n}, \"enforceGasCheck\"> | undefined" + }, + "resultShape": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape | undefined" + } + } + }, + "ReadExecuteOptions": { + "type": "{\n advanced?: {\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n } | undefined;\n progressHook?: ((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined;\n waitForCompletion?: boolean | undefined;\n}", + "members": { + "advanced": { + "optional": true, + "readonly": false, + "type": "{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n} | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + } + } + }, + "UNIVERSAL_READ_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS", + "members": { + "ABORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.ABORTED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.EXPIRED" + }, + "FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.FAILED" + }, + "FULFILLED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.FULFILLED" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.PENDING" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.UNSPECIFIED" + }, + "VOTING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.VOTING" + } + } + }, + "READ_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS", + "members": { + "ERROR": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.ERROR" + }, + "SUCCESS": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.SUCCESS" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.UNSPECIFIED" + } + } + }, + "READ_ERROR_CODE": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE", + "members": { + "INVALID_QUERY": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.INVALID_QUERY" + }, + "INVALID_RESULT": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.INVALID_RESULT" + }, + "NOT_FOUND": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.NOT_FOUND" + }, + "REJECTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.REJECTED" + }, + "REVERTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.REVERTED" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.UNSPECIFIED" + }, + "UNSUPPORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.UNSUPPORTED" + } + } + }, + "READ_OUTCOME": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME", + "members": { + "ABORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.ABORTED" + }, + "CALLBACK_FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.CALLBACK_FAILED" + }, + "DECODE_FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.DECODE_FAILED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.EXPIRED" + }, + "FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.FAILED" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.PENDING" + }, + "SOURCE_ERROR": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.SOURCE_ERROR" + }, + "SUCCESS": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.SUCCESS" + }, + "UNKNOWN": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.UNKNOWN" + } + } + }, + "CONTRACT_REQUEST_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS", + "members": { + "EXECUTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.EXECUTED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.EXPIRED" + }, + "NONE": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.NONE" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.PENDING" + }, + "SETTLED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.SETTLED" + } + } + }, + "TERMINAL_READ_STATUSES": { + "type": "ReadonlySet", + "members": {} + }, + "ReadStateError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadStateError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidReadQueryError": { + "type": "import(\"sdk/src/lib/read-state/errors\").InvalidReadQueryError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidReadSpecError": { + "type": "import(\"sdk/src/lib/read-state/errors\").InvalidReadSpecError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "violations": { + "optional": false, + "readonly": true, + "type": "readonly import(\"sdk/src/lib/read-state/errors\").ReadSpecViolation[]" + } + } + }, + "ReadHeightUnavailableError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadHeightUnavailableError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "UnsupportedReadDestinationError": { + "type": "import(\"sdk/src/lib/read-state/errors\").UnsupportedReadDestinationError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadDecodeError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadDecodeError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadTimeoutError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadTimeoutError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "lastStatus": { + "optional": false, + "readonly": true, + "type": "number" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadNotFoundError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadNotFoundError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadRegistryUnavailableError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadRegistryUnavailableError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadSpecViolation": { + "type": "\"CALLBACK_GAS_LIMIT_EXCEEDED\" | \"DOMAIN_BLOCKED\" | \"EMPTY_QUERY\" | \"EXCESSIVE_FEE\" | \"INSUFFICIENT_CALLBACK_BUDGET\" | \"INSUFFICIENT_FEE\" | \"INVALID_ACCOUNT_ID\" | \"INVALID_BLOCK_NUMBER\" | \"INVALID_EXPIRY_HEIGHT\" | \"INVALID_MIN_CONFIRMATIONS\" | \"SVM_OWNER_NOT_32_BYTES\" | \"ZERO_CALLBACK_BUDGET\" | \"ZERO_CALLBACK_GAS_LIMIT\" | \"ZERO_REVERT_RECIPIENT\"", + "members": {} + }, + "resolveDestination": { + "type": "(dest: import(\"sdk/src/lib/read-state/read-state.types\").ReadDestination) => import(\"sdk/src/lib/read-state/read-state.types\").ResolvedDestination", + "members": {} + }, + "encodeReadQuery": { + "type": "(destination: import(\"sdk/src/lib/read-state/read-state.types\").ReadDestination, query: import(\"sdk/src/lib/read-state/read-state.types\").ReadQuery, options?: {\n blockNumber?: bigint;\n minSlot?: bigint;\n}) => import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery", + "members": {} + }, + "decodeReadResult": { + "type": "(resultData: `0x${string}`, shape: import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape) => import(\"sdk/src/lib/read-state/read-state.types\").DecodedReadResult", + "members": {} + }, + "parseReadRequestsFromReceipt": { + "type": "(receipt: import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike, universalCallback: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").ParsedReadRequest[]", + "members": {} + }, + "parseFulfilOutcome": { + "type": "(receipt: import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike, universalCallback: `0x${string}`, requestId: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").FulfilOutcome", + "members": {} + }, + "buildReadSpecFromPreflight": { + "type": "(preflight: import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight, params: import(\"sdk/src/lib/read-state/read-state.types\").BuildReadSpecParams, defaults?: {\n refundTo?: `0x${string}`;\n}) => import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead", + "members": {} + }, + "validateReadSpec": { + "type": "(input: import(\"sdk/src/lib/read-state/validate\").ValidateReadSpecInput) => {\n ok: false;\n violations: import(\"sdk/src/lib/read-state/errors\").ReadSpecViolation[];\n} | {\n ok: true;\n}", + "members": {} + }, + "toCallData": { + "type": "(prepared: import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead, target: {\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: (spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpecTuple, callbackGasLimit: bigint) => readonly unknown[];\n functionName: string;\n}) => {\n data: `0x${string}`;\n value: bigint;\n}", + "members": {} + }, + "sizeCallbackBudget": { + "type": "(callbackGasLimit: bigint, pushGasPrice: bigint, buffer?: number) => bigint", + "members": {} + }, + "inferResultShape": { + "type": "(namespace: string, query: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape", + "members": {} + }, + "toRequestIdHex": { + "type": "(id: `0x${string}` | bigint) => `0x${string}`", + "members": {} + }, + "toReadQuery": { + "type": "(subject: string, o: ReadOptionsInput, resolvedTokenProgram?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@solana/web3.js/lib/index\").PublicKey) => import(\"sdk/src/lib/read-state/read-state.types\").ReadQuery", + "members": {} + }, + "UNIVERSAL_CALLBACK_EVM": { + "type": "readonly [\n {\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"requestExternalReadSelf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"estimateFee\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"statusOf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"enum RequestStatus\";\n readonly name: \"\";\n readonly type: \"uint8\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"isFulfilled\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getPendingRead\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly internalType: \"struct PendingRead\";\n readonly name: \"\";\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"totalEscrowed\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"blockedDomains\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly indexed: false;\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"readSpec\";\n readonly type: \"tuple\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"totalPaid\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"protocolFee\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ReadRequested\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"ReadFulfilled\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"reason\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"CallbackFailed\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"gasReported\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"burned\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"CallbackGasReported\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundSent\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundFailed\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RequestExpired\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"vaultPC\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ProtocolFeeDistributed\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidAccountId\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"EmptyQuery\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidMinConfirmations\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"DomainBlocked\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidBlockNumber\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidExpiryHeight\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroRevertRecipient\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroCallbackGasLimit\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint64\";\n readonly name: \"provided\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"max\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"CallbackGasLimitExceeded\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"required\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"InsufficientFee\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ExcessiveFee\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"actual\";\n readonly type: \"uint8\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"expected\";\n readonly type: \"uint8\";\n }\n ];\n readonly name: \"InvalidRequestStatus\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ContractIsPaused\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"CallerIsNotUCallbackModule\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n }\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"requestExternalReadSelf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n}" + }, + "1": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"estimateFee\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "2": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"statusOf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"enum RequestStatus\";\n readonly name: \"\";\n readonly type: \"uint8\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "3": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"isFulfilled\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "4": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getPendingRead\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly internalType: \"struct PendingRead\";\n readonly name: \"\";\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "5": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"totalEscrowed\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "6": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"blockedDomains\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "7": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly indexed: false;\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"readSpec\";\n readonly type: \"tuple\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"totalPaid\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"protocolFee\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ReadRequested\";\n readonly type: \"event\";\n}" + }, + "8": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"ReadFulfilled\";\n readonly type: \"event\";\n}" + }, + "9": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"reason\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"CallbackFailed\";\n readonly type: \"event\";\n}" + }, + "10": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"gasReported\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"burned\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"CallbackGasReported\";\n readonly type: \"event\";\n}" + }, + "11": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundSent\";\n readonly type: \"event\";\n}" + }, + "12": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundFailed\";\n readonly type: \"event\";\n}" + }, + "13": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RequestExpired\";\n readonly type: \"event\";\n}" + }, + "14": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"vaultPC\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ProtocolFeeDistributed\";\n readonly type: \"event\";\n}" + }, + "15": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidAccountId\";\n readonly type: \"error\";\n}" + }, + "16": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"EmptyQuery\";\n readonly type: \"error\";\n}" + }, + "17": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidMinConfirmations\";\n readonly type: \"error\";\n}" + }, + "18": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"DomainBlocked\";\n readonly type: \"error\";\n}" + }, + "19": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidBlockNumber\";\n readonly type: \"error\";\n}" + }, + "20": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidExpiryHeight\";\n readonly type: \"error\";\n}" + }, + "21": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroRevertRecipient\";\n readonly type: \"error\";\n}" + }, + "22": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroCallbackGasLimit\";\n readonly type: \"error\";\n}" + }, + "23": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint64\";\n readonly name: \"provided\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"max\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"CallbackGasLimitExceeded\";\n readonly type: \"error\";\n}" + }, + "24": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"required\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"InsufficientFee\";\n readonly type: \"error\";\n}" + }, + "25": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ExcessiveFee\";\n readonly type: \"error\";\n}" + }, + "26": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"actual\";\n readonly type: \"uint8\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"expected\";\n readonly type: \"uint8\";\n }\n ];\n readonly name: \"InvalidRequestStatus\";\n readonly type: \"error\";\n}" + }, + "27": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ContractIsPaused\";\n readonly type: \"error\";\n}" + }, + "28": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"CallerIsNotUCallbackModule\";\n readonly type: \"error\";\n}" + }, + "29": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n}" + }, + "length": { + "optional": false, + "readonly": true, + "type": "30" + } + } + }, + "UNIVERSAL_READ_REGISTRY_EVM": { + "type": "readonly [\n {\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n },\n {\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"read\";\n readonly outputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"universalCallback_\";\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"constructor\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"initialize\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getLocalContext\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"hasResult\";\n readonly outputs: readonly [\n {\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"onUniversalData\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"queryKeyOf\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes32\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"readerOf\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"requestOrderOf\";\n readonly outputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"universalCallback\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"resultByRequestId\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"latestResult\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"version\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"Initialized\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadRequested\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadStored\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidInitialization\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"NotInitializing\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroAddressInit\";\n readonly type: \"error\";\n }\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n },\n {\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"read\";\n readonly outputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n}" + }, + "1": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"universalCallback_\";\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"constructor\";\n}" + }, + "2": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"initialize\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n}" + }, + "3": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getLocalContext\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "4": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"hasResult\";\n readonly outputs: readonly [\n {\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "5": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"onUniversalData\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n}" + }, + "6": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"queryKeyOf\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes32\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "7": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"readerOf\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "8": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"requestOrderOf\";\n readonly outputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "9": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"universalCallback\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "10": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"resultByRequestId\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "11": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"latestResult\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "12": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"version\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"Initialized\";\n readonly type: \"event\";\n}" + }, + "13": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadRequested\";\n readonly type: \"event\";\n}" + }, + "14": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadStored\";\n readonly type: \"event\";\n}" + }, + "15": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidInitialization\";\n readonly type: \"error\";\n}" + }, + "16": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"NotInitializing\";\n readonly type: \"error\";\n}" + }, + "17": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n}" + }, + "18": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroAddressInit\";\n readonly type: \"error\";\n}" + }, + "length": { + "optional": false, + "readonly": true, + "type": "19" + } + } + }, + "PushChainExecutionError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").PushChainExecutionError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PushChainBatchExecutionError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").PushChainBatchExecutionError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": false, + "readonly": true, + "type": "`0x${string}`[]" + } + } + }, + "DecodedErrorPayload": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload", + "members": { + "decoded": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "name": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "selector": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "PushChainInitializeOptions": { + "type": "import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions", + "members": { + "agenticWallet": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "blockExplorers": { + "optional": true, + "readonly": false, + "type": "Partial> | undefined" + }, + "network": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "printTraces": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "rpcUrls": { + "optional": true, + "readonly": false, + "type": "Partial> | undefined" + } + } + }, + "AGENTIC_ERROR_CODE": { + "type": "{\n readonly AGENT_GAS_INSUFFICIENT: \"AGENT_GAS_INSUFFICIENT\";\n readonly AGENT_IS_OWNER: \"AGENT_IS_OWNER\";\n readonly ASSET_CHAIN_MISMATCH: \"ASSET_CHAIN_MISMATCH\";\n readonly CAPABILITY_UNAVAILABLE: \"CAPABILITY_UNAVAILABLE\";\n readonly CREATE_PARTIAL: \"CREATE_PARTIAL\";\n readonly DUPLICATE_RULE: \"DUPLICATE_RULE\";\n readonly FROM_NOT_ALLOWED: \"FROM_NOT_ALLOWED\";\n readonly GATEWAY_ALLOWANCE_INSUFFICIENT: \"GATEWAY_ALLOWANCE_INSUFFICIENT\";\n readonly GENERATION_UNSUPPORTED: \"GENERATION_UNSUPPORTED\";\n readonly INCONSISTENT_READ: \"INCONSISTENT_READ\";\n readonly INDEX_RACE: \"INDEX_RACE\";\n readonly INVALID_RULE: \"INVALID_RULE\";\n readonly NO_RULES_FOR_CHAIN: \"NO_RULES_FOR_CHAIN\";\n readonly NOT_AGENTIC_WALLET: \"NOT_AGENTIC_WALLET\";\n readonly NOT_ALLOWED_IN_AGENTIC_MODE: \"NOT_ALLOWED_IN_AGENTIC_MODE\";\n readonly NOT_OWNER_OR_AGENT: \"NOT_OWNER_OR_AGENT\";\n readonly NOT_WALLET_OWNER: \"NOT_WALLET_OWNER\";\n readonly READ_ONLY: \"READ_ONLY\";\n readonly RECEIPT_MISMATCH: \"RECEIPT_MISMATCH\";\n readonly RECEIPT_UNAVAILABLE: \"RECEIPT_UNAVAILABLE\";\n readonly REVOKE_NEEDS_TARGET: \"REVOKE_NEEDS_TARGET\";\n readonly RULE_LIMIT_EXCEEDED: \"RULE_LIMIT_EXCEEDED\";\n readonly RULE_NOT_FOUND: \"RULE_NOT_FOUND\";\n readonly RULE_READ_FAILED: \"RULE_READ_FAILED\";\n readonly TARGET_NOT_ON_RULE_CHAIN: \"TARGET_NOT_ON_RULE_CHAIN\";\n readonly WALLET_BALANCE_INSUFFICIENT: \"WALLET_BALANCE_INSUFFICIENT\";\n readonly WALLET_NOT_DEPLOYED: \"WALLET_NOT_DEPLOYED\";\n}", + "members": { + "AGENT_GAS_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\"" + }, + "AGENT_IS_OWNER": { + "optional": false, + "readonly": true, + "type": "\"AGENT_IS_OWNER\"" + }, + "ASSET_CHAIN_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"ASSET_CHAIN_MISMATCH\"" + }, + "CAPABILITY_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"CAPABILITY_UNAVAILABLE\"" + }, + "CREATE_PARTIAL": { + "optional": false, + "readonly": true, + "type": "\"CREATE_PARTIAL\"" + }, + "DUPLICATE_RULE": { + "optional": false, + "readonly": true, + "type": "\"DUPLICATE_RULE\"" + }, + "FROM_NOT_ALLOWED": { + "optional": false, + "readonly": true, + "type": "\"FROM_NOT_ALLOWED\"" + }, + "GATEWAY_ALLOWANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"GATEWAY_ALLOWANCE_INSUFFICIENT\"" + }, + "GENERATION_UNSUPPORTED": { + "optional": false, + "readonly": true, + "type": "\"GENERATION_UNSUPPORTED\"" + }, + "INCONSISTENT_READ": { + "optional": false, + "readonly": true, + "type": "\"INCONSISTENT_READ\"" + }, + "INDEX_RACE": { + "optional": false, + "readonly": true, + "type": "\"INDEX_RACE\"" + }, + "INVALID_RULE": { + "optional": false, + "readonly": true, + "type": "\"INVALID_RULE\"" + }, + "NO_RULES_FOR_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"NO_RULES_FOR_CHAIN\"" + }, + "NOT_AGENTIC_WALLET": { + "optional": false, + "readonly": true, + "type": "\"NOT_AGENTIC_WALLET\"" + }, + "NOT_ALLOWED_IN_AGENTIC_MODE": { + "optional": false, + "readonly": true, + "type": "\"NOT_ALLOWED_IN_AGENTIC_MODE\"" + }, + "NOT_OWNER_OR_AGENT": { + "optional": false, + "readonly": true, + "type": "\"NOT_OWNER_OR_AGENT\"" + }, + "NOT_WALLET_OWNER": { + "optional": false, + "readonly": true, + "type": "\"NOT_WALLET_OWNER\"" + }, + "READ_ONLY": { + "optional": false, + "readonly": true, + "type": "\"READ_ONLY\"" + }, + "RECEIPT_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_MISMATCH\"" + }, + "RECEIPT_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_UNAVAILABLE\"" + }, + "REVOKE_NEEDS_TARGET": { + "optional": false, + "readonly": true, + "type": "\"REVOKE_NEEDS_TARGET\"" + }, + "RULE_LIMIT_EXCEEDED": { + "optional": false, + "readonly": true, + "type": "\"RULE_LIMIT_EXCEEDED\"" + }, + "RULE_NOT_FOUND": { + "optional": false, + "readonly": true, + "type": "\"RULE_NOT_FOUND\"" + }, + "RULE_READ_FAILED": { + "optional": false, + "readonly": true, + "type": "\"RULE_READ_FAILED\"" + }, + "TARGET_NOT_ON_RULE_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"TARGET_NOT_ON_RULE_CHAIN\"" + }, + "WALLET_BALANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"WALLET_BALANCE_INSUFFICIENT\"" + }, + "WALLET_NOT_DEPLOYED": { + "optional": false, + "readonly": true, + "type": "\"WALLET_NOT_DEPLOYED\"" + } + } + }, + "AgenticError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"CREATE_PARTIAL\" | \"DUPLICATE_RULE\" | \"FROM_NOT_ALLOWED\" | \"GATEWAY_ALLOWANCE_INSUFFICIENT\" | \"GENERATION_UNSUPPORTED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"REVOKE_NEEDS_TARGET\" | \"RULE_LIMIT_EXCEEDED\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"" + }, + "details": { + "optional": true, + "readonly": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "AgenticRevertError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticRevertError", + "members": { + "agenticCode": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + } + } + }, + "AgenticAddress": { + "type": "`0x${string}`", + "members": {} + }, + "AgenticDoor": { + "type": "\"agent\" | \"owner\"", + "members": {} + }, + "AgenticErrorCode": { + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"CREATE_PARTIAL\" | \"DUPLICATE_RULE\" | \"FROM_NOT_ALLOWED\" | \"GATEWAY_ALLOWANCE_INSUFFICIENT\" | \"GENERATION_UNSUPPORTED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"REVOKE_NEEDS_TARGET\" | \"RULE_LIMIT_EXCEEDED\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"", + "members": {} + }, + "AgenticHex": { + "type": "`0x${string}`", + "members": {} + }, + "AgenticNamespace": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace", + "members": { + "create": { + "optional": false, + "readonly": false, + "type": "(label: string, options: import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions) => Promise" + }, + "derive": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n index?: number;\n}) => Promise<{\n address: `0x${string}`;\n deployed: boolean;\n index: number;\n}>" + }, + "list": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n wallets: import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary[];\n}>" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "(address: `0x${string}`) => import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet" + } + } + }, + "AgenticNetworkConstants": { + "type": "import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants", + "members": { + "ENVELOPE_VERSION": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "FACTORY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "MAX_ALLOWED_CALLS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "MAX_PINS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "RULES_POLICY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticProgressHook": { + "type": "(event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void", + "members": {} + }, + "AgenticTxMetadata": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticTxMetadata", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destinationAccount": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "destinationCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "door": { + "optional": false, + "readonly": false, + "type": "\"agent\" | \"owner\"" + }, + "nativeCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "rawData": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rawTo": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesId": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticWallet": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "checkpoints": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n sinceBlock?: bigint;\n}) => Promise<{\n checkpoints: import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint[];\n}>" + }, + "info": { + "optional": false, + "readonly": false, + "type": "() => Promise" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n owner: `0x${string}`;\n}>" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "{\n add(rules: import(\"sdk/src/lib/agentic/agentic.types\").Rule[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise<{\n rulesIds: `0x${string}`[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n get(rulesId: `0x${string}`): Promise;\n list(): Promise<{\n rules: import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord[];\n }>;\n revoke(rulesIds: `0x${string}`[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n revoke(params: {\n all: true;\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n update(params: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n rules: {\n rule: import(\"sdk/src/lib/agentic/agentic.types\").Rule;\n rulesId: `0x${string}`;\n }[];\n }): Promise<{\n rules: {\n replaced: `0x${string}`;\n rulesId: `0x${string}`;\n }[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n}" + }, + "setLabel": { + "optional": false, + "readonly": false, + "type": "(label: string, opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n}) => Promise" + } + } + }, + "AllowedCall": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall", + "members": { + "beneficiary": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValue": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "`${string}(${string})` | `0x${string}`" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AssetCap": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap", + "members": { + "maxPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/constants/tokens\").MoveableToken" + } + } + }, + "Checkpoint": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint", + "members": { + "blockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "kind": { + "optional": false, + "readonly": false, + "type": "\"OWNER_ACTION\" | \"RULES_GRANTED\" | \"RULES_REVOKED\"" + }, + "ref": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "seq": { + "optional": false, + "readonly": false, + "type": "number" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "CheckpointKind": { + "type": "\"OWNER_ACTION\" | \"RULES_GRANTED\" | \"RULES_REVOKED\"", + "members": {} + }, + "CreateOptions": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions", + "members": { + "progressHook": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook | undefined" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Rule[]" + } + } + }, + "CreateResult": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateResult", + "members": { + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "rulesIds": { + "optional": false, + "readonly": false, + "type": "`0x${string}`[]" + }, + "tx": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ForeignChainNamespace": { + "type": "`eip155:${string}` | `solana:${string}`", + "members": {} + }, + "NativeRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "amount": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AmountLimit | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "maxCalls": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValuePerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxValueTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "pins": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ArgPin[] | undefined" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Rule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule | import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "RulesRecord": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "enabled": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "ref": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "rule": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule | import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule" + }, + "rulesId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Selector": { + "type": "`${string}(${string})` | `0x${string}`", + "members": {} + }, + "UniversalRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall[]" + }, + "assets": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap[]" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "`eip155:${string}` | `solana:${string}`" + }, + "maxGasPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "WalletInfo": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").WalletInfo", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "label": { + "optional": false, + "readonly": false, + "type": "string" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "rulesCount": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "WalletSummary": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "label": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesCount": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "PushChain": { + "type": "import(\"sdk/src/lib/push-chain/push-chain\").PushChain", + "members": { + "accountStatus": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus" + }, + "accountStatusReady": { + "optional": false, + "readonly": false, + "type": "Promise" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace" + }, + "explorer": { + "optional": false, + "readonly": false, + "type": "{\n getTransactionUrl: (txHash: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n listAllUrls: () => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n listUrls: (options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n}" + }, + "funds": { + "optional": false, + "readonly": false, + "type": "{\n getConversionQuote: (amountIn: bigint, options: {\n from: import(\"sdk/src/lib/constants/tokens\").PayableToken | undefined;\n to: import(\"sdk/src/lib/constants/tokens\").MoveableToken | undefined;\n }) => Promise;\n}" + }, + "getAccountStatus": { + "optional": false, + "readonly": false, + "type": "(options?: {\n forceRefresh?: boolean;\n}) => Promise" + }, + "isReadMode": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "moveable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").MoveableTokenAccessor;\n}" + }, + "payable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").PayableTokenAccessor;\n}" + }, + "reinitialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "universal": { + "optional": false, + "readonly": false, + "type": "{\n readonly account: `0x${string}`;\n executeReads: (reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>;\n executeTransactions: (txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise;\n migrateCEA: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"migrateCEA\"];\n readonly origin: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n prepareRead: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n prepareTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"prepareTransaction\"];\n read: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n rescueFunds: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"rescueFunds\"];\n sendTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"execute\"];\n signMessage: (data: Uint8Array) => Promise;\n signTypedData: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n trackRead: {\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n };\n trackTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"trackTransaction\"];\n}" + }, + "upgradeAccount": { + "optional": false, + "readonly": false, + "type": "(options?: {\n progressHook?: (progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n}) => Promise" + } + } + } + }, + "pushChainStatic": { + "CONSTANTS": { + "optional": false, + "readonly": false, + "type": "{\n AGENTIC: Readonly>>;\n CHAIN: typeof import(\"sdk/src/lib/constants/enums\").CHAIN;\n LIBRARY: typeof import(\"sdk/src/lib/constants/enums\").LIBRARY;\n MOVEABLE: {\n TOKEN: import(\"sdk/src/lib/constants/tokens\").MoveableTokenConstantsMap;\n };\n PAYABLE: {\n TOKEN: import(\"sdk/src/lib/constants/tokens\").PayableTokenConstantsMap;\n };\n PUSH_NETWORK: typeof import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n READ: {\n readonly CALLBACK_BUDGET_BUFFER: 3;\n readonly CHAIN: {\n readonly WEB2: \"web2\";\n } & Readonly<{\n readonly ARBITRUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA;\n readonly BASE_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA;\n readonly BNB_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET;\n readonly ETHEREUM_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET;\n readonly ETHEREUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA;\n readonly PUSH_LOCALNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET;\n readonly PUSH_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET;\n readonly PUSH_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly PUSH_TESTNET_DONUT: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly SOLANA_DEVNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET;\n readonly SOLANA_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET;\n readonly SOLANA_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n readonly WEB2: \"web2\";\n }>;\n readonly DEFAULT_EXPIRY_BLOCKS: 300n;\n readonly ERROR_CODE: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n readonly MAX_CALLBACK_GAS_LIMIT: 1000000n;\n readonly MIN_CONFIRMATIONS_FLOOR: 1;\n readonly NAMESPACE: {\n readonly EVM: \"eip155\";\n readonly SVM: \"solana\";\n readonly WEB2: \"web2\";\n };\n readonly OUTCOME: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME;\n readonly REGISTRY_CALLBACK_GAS: 500000n;\n readonly RESULT_STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n readonly STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS;\n readonly UNIVERSAL_CALLBACK_ADDRESSES: Record;\n readonly UNIVERSAL_CORE_ADDRESSES: Record;\n readonly UNIVERSAL_READ_REGISTRY_ADDRESS: {\n readonly TESTNET_DONUT: \"0x00000000000000000000000000000000000000b2\";\n };\n readonly WEB2: \"web2\";\n readonly WEB2_DEFAULT_TIMEOUT_MS: 5000;\n readonly WEB2_MAX_EXTRACT_ENTRIES: 16;\n };\n}" + }, + "initialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "utils": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/utils\").Utils" + } + }, + "pushChainInstance": { + "accountStatus": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus" + }, + "accountStatusReady": { + "optional": false, + "readonly": false, + "type": "Promise" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace" + }, + "explorer": { + "optional": false, + "readonly": false, + "type": "{\n getTransactionUrl: (txHash: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n listAllUrls: () => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n listUrls: (options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n}" + }, + "funds": { + "optional": false, + "readonly": false, + "type": "{\n getConversionQuote: (amountIn: bigint, options: {\n from: import(\"sdk/src/lib/constants/tokens\").PayableToken | undefined;\n to: import(\"sdk/src/lib/constants/tokens\").MoveableToken | undefined;\n }) => Promise;\n}" + }, + "getAccountStatus": { + "optional": false, + "readonly": false, + "type": "(options?: {\n forceRefresh?: boolean;\n}) => Promise" + }, + "isReadMode": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "moveable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").MoveableTokenAccessor;\n}" + }, + "payable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").PayableTokenAccessor;\n}" + }, + "reinitialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "universal": { + "optional": false, + "readonly": false, + "type": "{\n readonly account: `0x${string}`;\n executeReads: (reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>;\n executeTransactions: (txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise;\n migrateCEA: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"migrateCEA\"];\n readonly origin: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n prepareRead: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n prepareTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"prepareTransaction\"];\n read: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n rescueFunds: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"rescueFunds\"];\n sendTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"execute\"];\n signMessage: (data: Uint8Array) => Promise;\n signTypedData: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n trackRead: {\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n };\n trackTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"trackTransaction\"];\n}" + }, + "upgradeAccount": { + "optional": false, + "readonly": false, + "type": "(options?: {\n progressHook?: (progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n}) => Promise" + } + }, + "transactionMethods": { + "account": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "executeReads": { + "optional": false, + "readonly": false, + "type": "(reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>" + }, + "executeTransactions": { + "optional": false, + "readonly": false, + "type": "(txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise" + }, + "migrateCEA": { + "optional": false, + "readonly": false, + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => Promise" + }, + "origin": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "prepareRead": { + "optional": false, + "readonly": false, + "type": "(subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>" + }, + "prepareTransaction": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions) => Promise" + }, + "read": { + "optional": false, + "readonly": false, + "type": "(subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>" + }, + "rescueFunds": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").RescueFundsParams) => Promise" + }, + "sendTransaction": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").ExecuteParams | import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions) => Promise" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": false, + "readonly": false, + "type": "({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise" + }, + "trackRead": { + "optional": false, + "readonly": false, + "type": "{\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n}" + }, + "trackTransaction": { + "optional": false, + "readonly": false, + "type": "(txHash: string, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TrackTransactionOptions) => Promise" + } + }, + "utilityMethods": { + "account": { + "optional": false, + "readonly": false, + "type": "{\n convertExecutorToOriginAccount: (ueaAddress: `0x${string}`, options?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n }) => Promise;\n convertOriginToExecutor: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n onlyCompute?: boolean;\n }) => Promise;\n deriveExecutorAccount: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n skipNetworkCheck?: boolean;\n }) => Promise;\n fromChainAgnostic: (caip: string) => import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n resolveControllerAccount: (address: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n skipNetworkCheck?: boolean;\n }) => Promise;\n toChainAgnostic: (address: string, options: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n toUniversal: (address: string, options: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n}" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "{\n actionId: (target: `0x${string}`, selector: \"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector) => `0x${string}`;\n configId: (wallet: `0x${string}`, rulesId: `0x${string}`, actionId: `0x${string}`) => `0x${string}`;\n decodeRules: (bytes: `0x${string}`, ctx?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n pushChainNamespace?: string;\n }) => import(\"sdk/src/lib/agentic/agentic.types\").Rule;\n}" + }, + "chains": { + "optional": false, + "readonly": false, + "type": "{\n getChainName: (chainNamespace: string) => string | undefined;\n getChainNamespace: (chainName: string) => string | undefined;\n getSupportedChains: (network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK) => {\n chains: import(\"sdk/src/lib/constants/enums\").CHAIN[];\n };\n getSupportedChainsByName: (network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK) => {\n chains: string[];\n };\n}" + }, + "conversion": { + "optional": false, + "readonly": false, + "type": "{\n slippageToMinAmount(amount: string, options: {\n slippageBps: number;\n }): string;\n}" + }, + "helpers": { + "optional": false, + "readonly": false, + "type": "{\n encodeTxData({ abi, idl, functionName, args, }: {\n abi?: any;\n args?: any[];\n functionName: string;\n idl?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n }): `0x${string}`;\n formatUnits(value: bigint | string, decimalsOrOptions: {\n decimals: number;\n precision?: number;\n } | number): string;\n getChainName: (chainName: string) => string | undefined;\n parseUnits(value: string, exponent: {\n decimals: number;\n } | number): bigint;\n}" + }, + "signer": { + "optional": false, + "readonly": false, + "type": "{\n construct: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options: {\n signAndSendTransaction: (unsignedTx: Uint8Array) => Promise;\n signAuthorization?: (params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise;\n signMessage: (data: Uint8Array) => Promise;\n signTypedData?: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n }) => import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton;\n toUniversal: (signer: import(\"sdk/src/lib/universal/universal.types\").EthersV5SignerType | import(\"sdk/src/lib/universal/universal.types\").EthersV6SignerType | import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton | import(\"sdk/src/lib/universal/universal.types\").ViemSignerType) => Promise;\n toUniversalFromKeypair: (clientOrAccount: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@solana/web3.js/lib/index\").Keypair | import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").WalletClient | import(\"sdk/src/lib/universal/universal.types\").EthersV6SignerType, { chain, library }: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n library: import(\"sdk/src/lib/constants/enums\").LIBRARY;\n }) => Promise;\n}" + }, + "svm": { + "optional": false, + "readonly": false, + "type": "{\n getRegisteredIdls: () => Array<{\n address: `0x${string}`;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n }>;\n registerIdl: (idl: unknown) => void;\n}" + }, + "tokens": { + "optional": false, + "readonly": false, + "type": "{\n getMoveableTokens(chainOrClient?: import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/push-chain/push-chain\").PushChain): {\n tokens: Array<{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n decimals: number;\n mechanism: \"approve\" | \"native\" | \"permit2\";\n prc20Address?: `0x${string}`;\n sourceChain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n symbol: string;\n }>;\n };\n getPayableTokens(chainOrClient?: import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/push-chain/push-chain\").PushChain): {\n tokens: Array<{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n decimals: number;\n mechanism: \"approve\" | \"native\" | \"permit2\";\n symbol: string;\n }>;\n };\n getPC20Address(address: string, options: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n rpcUrls?: Partial>;\n strict?: boolean;\n }): Promise;\n getPRC20Address(token: {\n address: string;\n chain: string;\n } | import(\"sdk/src/lib/constants/tokens\").MoveableToken, options?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n }): {\n address: `0x${string}`;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n decimals: number;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n symbol: string;\n };\n}" + } + }, + "initialize": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise", + "agwConstants": { + "ENVELOPE_VERSION": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "FACTORY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "MAX_ALLOWED_CALLS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "MAX_PINS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "RULES_POLICY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + }, + "constants": { + "AGENTIC": { + "optional": false, + "readonly": false, + "type": "{\n readonly LOCALNET?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n readonly MAINNET?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n readonly TESTNET?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n readonly TESTNET_DONUT?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n}" + }, + "CHAIN": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "LIBRARY": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").LIBRARY" + }, + "MOVEABLE": { + "optional": false, + "readonly": false, + "type": "{\n TOKEN: import(\"sdk/src/lib/constants/tokens\").MoveableTokenConstantsMap;\n}" + }, + "PAYABLE": { + "optional": false, + "readonly": false, + "type": "{\n TOKEN: import(\"sdk/src/lib/constants/tokens\").PayableTokenConstantsMap;\n}" + }, + "PUSH_NETWORK": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "READ": { + "optional": false, + "readonly": false, + "type": "{\n readonly CALLBACK_BUDGET_BUFFER: 3;\n readonly CHAIN: {\n readonly WEB2: \"web2\";\n } & Readonly<{\n readonly ARBITRUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA;\n readonly BASE_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA;\n readonly BNB_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET;\n readonly ETHEREUM_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET;\n readonly ETHEREUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA;\n readonly PUSH_LOCALNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET;\n readonly PUSH_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET;\n readonly PUSH_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly PUSH_TESTNET_DONUT: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly SOLANA_DEVNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET;\n readonly SOLANA_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET;\n readonly SOLANA_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n readonly WEB2: \"web2\";\n }>;\n readonly DEFAULT_EXPIRY_BLOCKS: 300n;\n readonly ERROR_CODE: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n readonly MAX_CALLBACK_GAS_LIMIT: 1000000n;\n readonly MIN_CONFIRMATIONS_FLOOR: 1;\n readonly NAMESPACE: {\n readonly EVM: \"eip155\";\n readonly SVM: \"solana\";\n readonly WEB2: \"web2\";\n };\n readonly OUTCOME: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME;\n readonly REGISTRY_CALLBACK_GAS: 500000n;\n readonly RESULT_STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n readonly STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS;\n readonly UNIVERSAL_CALLBACK_ADDRESSES: Record;\n readonly UNIVERSAL_CORE_ADDRESSES: Record;\n readonly UNIVERSAL_READ_REGISTRY_ADDRESS: {\n readonly TESTNET_DONUT: \"0x00000000000000000000000000000000000000b2\";\n };\n readonly WEB2: \"web2\";\n readonly WEB2_DEFAULT_TIMEOUT_MS: 5000;\n readonly WEB2_MAX_EXTRACT_ENTRIES: 16;\n}" + } + } + }, + "after": { + "exports": [ + "AGENTIC_ERROR_CODE", + "AccountRole", + "AccountStatus", + "AccountType", + "AgenticAddress", + "AgenticDoor", + "AgenticError", + "AgenticErrorCode", + "AgenticHex", + "AgenticNamespace", + "AgenticNetworkConstants", + "AgenticProgressHook", + "AgenticRevertError", + "AgenticTxMetadata", + "AgenticWallet", + "AllowedCall", + "AssetCap", + "BatchReadResponse", + "BuildReadSpecParams", + "CHAIN", + "CONTRACT_REQUEST_STATUS", + "CascadeCompletionResult", + "CascadeHopInfo", + "CascadeProgressEvent", + "CascadeTrackOptions", + "CascadedTxResponse", + "ChainSource", + "ChainTarget", + "Checkpoint", + "CheckpointKind", + "ConversionQuote", + "CreateOptions", + "CreateResult", + "DEFAULT_MAX_PC_FOR_GAS_BUFFER_BPS", + "DecodedErrorPayload", + "DecodedReadResult", + "DerivedExecutorAccount", + "EncodedReadQuery", + "EvmReadQuery", + "ForeignChainNamespace", + "FulfilOutcome", + "FundsToken", + "InsufficientPC20BalanceError", + "InvalidPC20AddressError", + "InvalidPC20MetadataError", + "InvalidReadQueryError", + "InvalidReadSpecError", + "MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT", + "MaxPCForGasCapFromNativeValueInput", + "MaxPCForGasCapInput", + "MaxPCForGasCapQuote", + "MultiChainTxResponse", + "NativeRule", + "OutboundTxDetails", + "PC20AddressResult", + "PC20AmbiguousAddressError", + "PC20Error", + "PC20ExpectedButPRC20Error", + "PC20ExportRevertedError", + "PC20FactoryMismatchError", + "PC20RegistryEntry", + "PC20RegistryMismatchError", + "PC20TokenChainMismatchError", + "PC20TokenReference", + "PC20UnknownChainNamespaceError", + "PC20UnsafeEmptyPayloadError", + "PC20WrapperNotRegisteredError", + "PC20WrapperPredictionUnavailableError", + "ParsedReadRequest", + "PreparedRead", + "PreparedUniversalTx", + "PushChain", + "PushChainBatchExecutionError", + "PushChainExecutionError", + "PushChainInitializeOptions", + "READ_ERROR_CODE", + "READ_OUTCOME", + "READ_STATUS", + "ReadCallback", + "ReadCallbackOptions", + "ReadChain", + "ReadDecodeError", + "ReadDestination", + "ReadExecuteOptions", + "ReadFees", + "ReadHeightUnavailableError", + "ReadLifecycleOptions", + "ReadNotFoundError", + "ReadOptions", + "ReadPreflight", + "ReadPrepareOptions", + "ReadQuery", + "ReadQueryOptions", + "ReadRef", + "ReadRegistryUnavailableError", + "ReadResponseTuple", + "ReadResultShape", + "ReadSpec", + "ReadSpecTuple", + "ReadSpecViolation", + "ReadStateError", + "ReadTimeoutError", + "ReadTrackOptions", + "ReadValue", + "ReadWeb2Options", + "ReceiptLike", + "RescueFundsParams", + "ResolvedAccount", + "ResolvedControllerAccounts", + "ResolvedDestination", + "Rule", + "RulesRecord", + "Selector", + "SignAuthorizationParams", + "SignedAuthorization", + "SimulateReadResult", + "SvmExecutePayloadFields", + "SvmGatewayAccountMeta", + "SvmReadQuery", + "TERMINAL_READ_STATUSES", + "TransactionRoute", + "TransactionRouteType", + "UEAStatus", + "UNIVERSAL_CALLBACK_EVM", + "UNIVERSAL_READ_REGISTRY_EVM", + "UNIVERSAL_READ_STATUS", + "UniversalAccount", + "UniversalExecuteParams", + "UniversalOutboundTxRequest", + "UniversalReadResponse", + "UniversalRule", + "UniversalSigner", + "UniversalSignerSkeleton", + "UniversalTo", + "UnsupportedPC20DestinationError", + "UnsupportedReadDestinationError", + "ValidateReadCall", + "WaitForOutboundOptions", + "WalletInfo", + "WalletSummary", + "Web2Extract", + "Web2ReadQuery", + "Web2ValueType", + "buildErc20WithdrawalMulticall", + "buildMigrationPayload", + "buildReadSpecFromPreflight", + "chainSupportsCEA", + "chainSupportsOutbound", + "decodeReadResult", + "detectRoute", + "encodeReadQuery", + "encodeSvmExecutePayload", + "getAllCEAAddresses", + "getCEAAddress", + "getCEAFactoryAddress", + "getPushAccountForCEA", + "inferResultShape", + "isCEA", + "isChainTarget", + "isPC20Reference", + "isSvmChain", + "isValidSolanaHexAddress", + "parseFulfilOutcome", + "parseReadRequestsFromReceipt", + "parseUEAVersion", + "quoteMaxPCForGasCap", + "quoteMaxPCForGasCapFromNativeValue", + "resolveDestination", + "sizeCallbackBudget", + "toCallData", + "toReadQuery", + "toRequestIdHex", + "validateReadSpec" + ], + "agw": { + "AgenticNamespace": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace", + "members": { + "create": { + "optional": false, + "readonly": false, + "type": "(label: string, options: import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions) => Promise" + }, + "derive": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n index?: number;\n}) => Promise<{\n address: `0x${string}`;\n deployed: boolean;\n index: number;\n}>" + }, + "list": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n wallets: import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary[];\n}>" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "(address: `0x${string}`) => import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet" + } + } + }, + "AgenticWallet": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "checkpoints": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n sinceBlock?: bigint;\n}) => Promise<{\n checkpoints: import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint[];\n}>" + }, + "info": { + "optional": false, + "readonly": false, + "type": "() => Promise" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n owner: `0x${string}`;\n}>" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "{\n add(rules: import(\"sdk/src/lib/agentic/agentic.types\").Rule[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise<{\n rulesIds: `0x${string}`[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n get(rulesId: `0x${string}`): Promise;\n list(): Promise<{\n rules: import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord[];\n }>;\n revoke(rulesIds: `0x${string}`[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n revoke(params: {\n all: true;\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n update(params: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n rules: {\n rule: import(\"sdk/src/lib/agentic/agentic.types\").Rule;\n rulesId: `0x${string}`;\n }[];\n }): Promise<{\n rules: {\n replaced: `0x${string}`;\n rulesId: `0x${string}`;\n }[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n}" + }, + "setLabel": { + "optional": false, + "readonly": false, + "type": "(label: string, opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n}) => Promise" + } + } + }, + "AgenticError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"AMBIGUOUS_RULE\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"CREATE_PARTIAL\" | \"FROM_NOT_ALLOWED\" | \"GATEWAY_ALLOWANCE_INSUFFICIENT\" | \"GENERATION_UNSUPPORTED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"REVOKE_NEEDS_TARGET\" | \"RULE_LIMIT_EXCEEDED\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"" + }, + "details": { + "optional": true, + "readonly": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "AgenticRevertError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticRevertError", + "members": { + "agenticCode": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + } + } + }, + "AGENTIC_ERROR_CODE": { + "type": "{\n readonly AGENT_GAS_INSUFFICIENT: \"AGENT_GAS_INSUFFICIENT\";\n readonly AGENT_IS_OWNER: \"AGENT_IS_OWNER\";\n readonly AMBIGUOUS_RULE: \"AMBIGUOUS_RULE\";\n readonly ASSET_CHAIN_MISMATCH: \"ASSET_CHAIN_MISMATCH\";\n readonly CAPABILITY_UNAVAILABLE: \"CAPABILITY_UNAVAILABLE\";\n readonly CREATE_PARTIAL: \"CREATE_PARTIAL\";\n readonly FROM_NOT_ALLOWED: \"FROM_NOT_ALLOWED\";\n readonly GATEWAY_ALLOWANCE_INSUFFICIENT: \"GATEWAY_ALLOWANCE_INSUFFICIENT\";\n readonly GENERATION_UNSUPPORTED: \"GENERATION_UNSUPPORTED\";\n readonly INCONSISTENT_READ: \"INCONSISTENT_READ\";\n readonly INDEX_RACE: \"INDEX_RACE\";\n readonly INVALID_RULE: \"INVALID_RULE\";\n readonly NO_RULES_FOR_CHAIN: \"NO_RULES_FOR_CHAIN\";\n readonly NOT_AGENTIC_WALLET: \"NOT_AGENTIC_WALLET\";\n readonly NOT_ALLOWED_IN_AGENTIC_MODE: \"NOT_ALLOWED_IN_AGENTIC_MODE\";\n readonly NOT_OWNER_OR_AGENT: \"NOT_OWNER_OR_AGENT\";\n readonly NOT_WALLET_OWNER: \"NOT_WALLET_OWNER\";\n readonly READ_ONLY: \"READ_ONLY\";\n readonly RECEIPT_MISMATCH: \"RECEIPT_MISMATCH\";\n readonly RECEIPT_UNAVAILABLE: \"RECEIPT_UNAVAILABLE\";\n readonly REVOKE_NEEDS_TARGET: \"REVOKE_NEEDS_TARGET\";\n readonly RULE_LIMIT_EXCEEDED: \"RULE_LIMIT_EXCEEDED\";\n readonly RULE_NOT_FOUND: \"RULE_NOT_FOUND\";\n readonly RULE_READ_FAILED: \"RULE_READ_FAILED\";\n readonly TARGET_NOT_ON_RULE_CHAIN: \"TARGET_NOT_ON_RULE_CHAIN\";\n readonly WALLET_BALANCE_INSUFFICIENT: \"WALLET_BALANCE_INSUFFICIENT\";\n readonly WALLET_NOT_DEPLOYED: \"WALLET_NOT_DEPLOYED\";\n}", + "members": { + "AGENT_GAS_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\"" + }, + "AGENT_IS_OWNER": { + "optional": false, + "readonly": true, + "type": "\"AGENT_IS_OWNER\"" + }, + "AMBIGUOUS_RULE": { + "optional": false, + "readonly": true, + "type": "\"AMBIGUOUS_RULE\"" + }, + "ASSET_CHAIN_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"ASSET_CHAIN_MISMATCH\"" + }, + "CAPABILITY_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"CAPABILITY_UNAVAILABLE\"" + }, + "CREATE_PARTIAL": { + "optional": false, + "readonly": true, + "type": "\"CREATE_PARTIAL\"" + }, + "FROM_NOT_ALLOWED": { + "optional": false, + "readonly": true, + "type": "\"FROM_NOT_ALLOWED\"" + }, + "GATEWAY_ALLOWANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"GATEWAY_ALLOWANCE_INSUFFICIENT\"" + }, + "GENERATION_UNSUPPORTED": { + "optional": false, + "readonly": true, + "type": "\"GENERATION_UNSUPPORTED\"" + }, + "INCONSISTENT_READ": { + "optional": false, + "readonly": true, + "type": "\"INCONSISTENT_READ\"" + }, + "INDEX_RACE": { + "optional": false, + "readonly": true, + "type": "\"INDEX_RACE\"" + }, + "INVALID_RULE": { + "optional": false, + "readonly": true, + "type": "\"INVALID_RULE\"" + }, + "NO_RULES_FOR_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"NO_RULES_FOR_CHAIN\"" + }, + "NOT_AGENTIC_WALLET": { + "optional": false, + "readonly": true, + "type": "\"NOT_AGENTIC_WALLET\"" + }, + "NOT_ALLOWED_IN_AGENTIC_MODE": { + "optional": false, + "readonly": true, + "type": "\"NOT_ALLOWED_IN_AGENTIC_MODE\"" + }, + "NOT_OWNER_OR_AGENT": { + "optional": false, + "readonly": true, + "type": "\"NOT_OWNER_OR_AGENT\"" + }, + "NOT_WALLET_OWNER": { + "optional": false, + "readonly": true, + "type": "\"NOT_WALLET_OWNER\"" + }, + "READ_ONLY": { + "optional": false, + "readonly": true, + "type": "\"READ_ONLY\"" + }, + "RECEIPT_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_MISMATCH\"" + }, + "RECEIPT_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_UNAVAILABLE\"" + }, + "REVOKE_NEEDS_TARGET": { + "optional": false, + "readonly": true, + "type": "\"REVOKE_NEEDS_TARGET\"" + }, + "RULE_LIMIT_EXCEEDED": { + "optional": false, + "readonly": true, + "type": "\"RULE_LIMIT_EXCEEDED\"" + }, + "RULE_NOT_FOUND": { + "optional": false, + "readonly": true, + "type": "\"RULE_NOT_FOUND\"" + }, + "RULE_READ_FAILED": { + "optional": false, + "readonly": true, + "type": "\"RULE_READ_FAILED\"" + }, + "TARGET_NOT_ON_RULE_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"TARGET_NOT_ON_RULE_CHAIN\"" + }, + "WALLET_BALANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"WALLET_BALANCE_INSUFFICIENT\"" + }, + "WALLET_NOT_DEPLOYED": { + "optional": false, + "readonly": true, + "type": "\"WALLET_NOT_DEPLOYED\"" + } + } + }, + "NativeRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "amount": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AmountLimit | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "maxCalls": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValuePerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxValueTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "pins": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ArgPin[] | undefined" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "AssetCap": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap", + "members": { + "maxPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/constants/tokens\").MoveableToken" + } + } + }, + "AllowedCall": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall", + "members": { + "beneficiary": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "beneficiaryOffset": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValue": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "`${string}(${string})` | `0x${string}`" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "UniversalRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall[]" + }, + "assets": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap[]" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "`eip155:${string}` | `solana:${string}`" + }, + "maxGasPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "RulesRecord": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "enabled": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "ref": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "rule": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule | import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule" + }, + "rulesId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "CreateOptions": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions", + "members": { + "progressHook": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook | undefined" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Rule[]" + } + } + }, + "CreateResult": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateResult", + "members": { + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "rulesIds": { + "optional": false, + "readonly": false, + "type": "`0x${string}`[]" + }, + "tx": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticTxMetadata": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticTxMetadata", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destinationAccount": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "destinationCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "door": { + "optional": false, + "readonly": false, + "type": "\"agent\" | \"owner\"" + }, + "nativeCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "rawData": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rawTo": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesId": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + } + }, + "publicSurface": { + "CHAIN": { + "type": "typeof import(\"sdk/src/lib/constants/enums\").CHAIN", + "members": { + "ARBITRUM_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA" + }, + "BASE_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA" + }, + "BNB_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET" + }, + "ETHEREUM_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET" + }, + "ETHEREUM_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA" + }, + "PUSH_LOCALNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET" + }, + "PUSH_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET" + }, + "PUSH_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET" + }, + "PUSH_TESTNET_DONUT": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET" + }, + "SOLANA_DEVNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET" + }, + "SOLANA_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET" + }, + "SOLANA_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET" + }, + "WEB2": { + "optional": false, + "readonly": false, + "type": "\"web2\"" + } + } + }, + "ConversionQuote": { + "type": "import(\"sdk/src/lib/constants/tokens\").ConversionQuote", + "members": { + "amountIn": { + "optional": false, + "readonly": false, + "type": "string" + }, + "amountOut": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rate": { + "optional": false, + "readonly": false, + "type": "number" + }, + "route": { + "optional": true, + "readonly": false, + "type": "string[] | undefined" + }, + "timestamp": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "UniversalSigner": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalSigner", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "signAndSendTransaction": { + "optional": false, + "readonly": false, + "type": "(unsignedTx: Uint8Array) => Promise" + }, + "signAuthorization": { + "optional": true, + "readonly": false, + "type": "((params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise) | undefined" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": true, + "readonly": false, + "type": "(({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise) | undefined" + } + } + }, + "UniversalAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "UniversalSignerSkeleton": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "signAndSendTransaction": { + "optional": false, + "readonly": false, + "type": "(unsignedTx: Uint8Array) => Promise" + }, + "signAuthorization": { + "optional": true, + "readonly": false, + "type": "((params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise) | undefined" + }, + "signerId": { + "optional": false, + "readonly": false, + "type": "string" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": true, + "readonly": false, + "type": "(({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise) | undefined" + } + } + }, + "SignAuthorizationParams": { + "type": "{\n chainId?: number;\n contractAddress: `0x${string}`;\n executor?: \"self\";\n nonce?: number;\n}", + "members": { + "chainId": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "contractAddress": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "executor": { + "optional": true, + "readonly": false, + "type": "\"self\" | undefined" + }, + "nonce": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "SignedAuthorization": { + "type": "{\n address: `0x${string}`;\n chainId: number;\n nonce: number;\n r: `0x${string}`;\n s: `0x${string}`;\n v?: bigint;\n yParity: number;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainId": { + "optional": false, + "readonly": false, + "type": "number" + }, + "nonce": { + "optional": false, + "readonly": false, + "type": "number" + }, + "r": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "s": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "v": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "yParity": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "DerivedExecutorAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").DerivedExecutorAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean | null" + } + } + }, + "ResolvedAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainName": { + "optional": false, + "readonly": false, + "type": "string" + }, + "exists": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "role": { + "optional": true, + "readonly": false, + "type": "\"controller\" | undefined" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"cea\" | \"uea\" | \"uoa\"" + } + } + }, + "ResolvedControllerAccounts": { + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedControllerAccounts", + "members": { + "accounts": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedAccount[]" + } + } + }, + "AccountType": { + "type": "\"cea\" | \"uea\" | \"uoa\"", + "members": {} + }, + "AccountRole": { + "type": "\"controller\"", + "members": {} + }, + "PC20TokenReference": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "FundsToken": { + "type": "import(\"sdk/src/lib/constants/tokens\").MoveableToken | import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20TokenReference", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "PC20RegistryEntry": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "chainName": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "PC20AddressResult": { + "type": "{\n address: `0x${string}`;\n decimals: number;\n name: string;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n registry: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20RegistryEntry[];\n symbol: string;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "decimals": { + "optional": false, + "readonly": false, + "type": "number" + }, + "name": { + "optional": false, + "readonly": false, + "type": "string" + }, + "network": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "registry": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20RegistryEntry[]" + }, + "symbol": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "isPC20Reference": { + "type": "(token: import(\"sdk/src/lib/orchestrator/orchestrator.types\").FundsToken | undefined) => token is import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20TokenReference", + "members": {} + }, + "PC20Error": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20Error", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidPC20AddressError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InvalidPC20AddressError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20TokenChainMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20TokenChainMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20WrapperNotRegisteredError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20WrapperNotRegisteredError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20RegistryMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20RegistryMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20FactoryMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20FactoryMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidPC20MetadataError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InvalidPC20MetadataError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20ExpectedButPRC20Error": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20ExpectedButPRC20Error", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20AmbiguousAddressError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20AmbiguousAddressError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "candidates": { + "optional": false, + "readonly": true, + "type": "{\n chain: string;\n pushAddress: string;\n}[]" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "UnsupportedPC20DestinationError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").UnsupportedPC20DestinationError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InsufficientPC20BalanceError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InsufficientPC20BalanceError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20UnknownChainNamespaceError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20UnknownChainNamespaceError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20WrapperPredictionUnavailableError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20WrapperPredictionUnavailableError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20ExportRevertedError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20ExportRevertedError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "lockedAmount": { + "optional": true, + "readonly": true, + "type": "bigint | undefined" + }, + "outboundTxId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "revertRecipient": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20UnsafeEmptyPayloadError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20UnsafeEmptyPayloadError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ChainTarget": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "ChainSource": { + "type": "{\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "UniversalTo": { + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget", + "members": {} + }, + "TransactionRouteType": { + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"", + "members": {} + }, + "UniversalExecuteParams": { + "type": "{\n from?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainSource;\n migration?: boolean;\n to: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTo;\n} & Omit", + "members": { + "_minimumDepositUsd": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "_requiredFundsOverride": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "_skipFeeLocking": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "_ueaStatus": { + "optional": true, + "readonly": false, + "type": "{\n balance: bigint;\n isDeployed: boolean;\n nonce: bigint;\n} | undefined" + }, + "data": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiCall[] | undefined" + }, + "deadline": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "feeLockTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "from": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainSource | undefined" + }, + "funds": { + "optional": true, + "readonly": false, + "type": "{\n amount: bigint;\n token?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").FundsToken;\n} | undefined" + }, + "gasLimit": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFeePerGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxPCForGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxPriorityFeePerGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "migration": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "nonce": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "options": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions | undefined" + }, + "payGasWith": { + "optional": true, + "readonly": false, + "type": "{\n minAmountOut?: bigint | string;\n slippageBps?: number;\n token?: import(\"sdk/src/lib/constants/tokens\").PayableToken;\n} | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "to": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget" + }, + "value": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "UniversalOutboundTxRequest": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalOutboundTxRequest", + "members": { + "amount": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gasPrice": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxPCForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "payload": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "recipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "revertRecipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "PreparedUniversalTx": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx", + "members": { + "_hop": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").HopDescriptor" + }, + "deadline": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "estimatedGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gatewayRequest": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalOutboundTxRequest | import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxRequest" + }, + "nonce": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "payload": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + } + } + }, + "CascadedTxResponse": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadedTxResponse", + "members": { + "finalTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hopCount": { + "optional": false, + "readonly": false, + "type": "number" + }, + "hops": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo[]" + }, + "initialTxHash": { + "optional": false, + "readonly": false, + "type": "string" + }, + "initialTxResponse": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions) => Promise" + }, + "waitForAll": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions) => Promise" + } + } + }, + "CascadeHopInfo": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo", + "members": { + "executionChain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "expectedSubTxId": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hopIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "outboundDetails": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").OutboundTxDetails | undefined" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + }, + "status": { + "optional": false, + "readonly": false, + "type": "\"confirmed\" | \"failed\" | \"pending\" | \"submitted\"" + }, + "txHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "CascadeTrackOptions": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions", + "members": { + "eventHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeProgressEvent) => void) | undefined" + }, + "timeout": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "CascadeProgressEvent": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeProgressEvent", + "members": { + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "elapsed": { + "optional": false, + "readonly": false, + "type": "number" + }, + "hopIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + }, + "status": { + "optional": false, + "readonly": false, + "type": "\"confirmed\" | \"failed\" | \"found\" | \"polling\" | \"timeout\" | \"waiting\"" + }, + "txHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "CascadeCompletionResult": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeCompletionResult", + "members": { + "failedAt": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "finalTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "finalTxResponse": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadedTxResponse | undefined" + }, + "hops": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo[]" + }, + "success": { + "optional": false, + "readonly": false, + "type": "boolean" + } + } + }, + "MultiChainTxResponse": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiChainTxResponse", + "members": { + "chains": { + "optional": false, + "readonly": false, + "type": "{\n blockNumber: bigint;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n hash: string;\n status: \"confirmed\" | \"failed\" | \"pending\";\n}[]" + }, + "transactions": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse[]" + } + } + }, + "OutboundTxDetails": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").OutboundTxDetails", + "members": { + "amount": { + "optional": false, + "readonly": false, + "type": "string" + }, + "assetAddr": { + "optional": false, + "readonly": false, + "type": "string" + }, + "destinationChain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "explorerUrl": { + "optional": false, + "readonly": false, + "type": "string" + }, + "externalTxHash": { + "optional": false, + "readonly": false, + "type": "string" + }, + "recipient": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "WaitForOutboundOptions": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").WaitForOutboundOptions", + "members": { + "_expectedDestinationChain": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "_outboundIndex": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "_resolvedSubTxId": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "initialWaitMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: {\n elapsed: number;\n status: \"failed\" | \"found\" | \"polling\" | \"timeout\" | \"waiting\";\n}) => void) | undefined" + }, + "timeout": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "SvmGatewayAccountMeta": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmGatewayAccountMeta", + "members": { + "isWritable": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "pubkey": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "SvmExecutePayloadFields": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmExecutePayloadFields", + "members": { + "accounts": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmGatewayAccountMeta[]" + }, + "instructionId": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "ixData": { + "optional": false, + "readonly": false, + "type": "Uint8Array" + }, + "targetProgram": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AccountStatus": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus", + "members": { + "mode": { + "optional": false, + "readonly": false, + "type": "\"read-only\" | \"signer\"" + }, + "uea": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UEAStatus" + } + } + }, + "UEAStatus": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UEAStatus", + "members": { + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "loaded": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "minRequiredVersion": { + "optional": false, + "readonly": false, + "type": "string" + }, + "requiresUpgrade": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "version": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "RescueFundsParams": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").RescueFundsParams", + "members": { + "prc20": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "universalTxId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "parseUEAVersion": { + "type": "(version: string) => number", + "members": {} + }, + "TransactionRoute": { + "type": "typeof import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute", + "members": { + "CEA_TO_CEA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.CEA_TO_CEA" + }, + "CEA_TO_PUSH": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.CEA_TO_PUSH" + }, + "UOA_TO_CEA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.UOA_TO_CEA" + }, + "UOA_TO_PUSH": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.UOA_TO_PUSH" + } + } + }, + "detectRoute": { + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams) => import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute", + "members": {} + }, + "isChainTarget": { + "type": "(to: unknown) => to is import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget", + "members": {} + }, + "DEFAULT_MAX_PC_FOR_GAS_BUFFER_BPS": { + "type": "1000", + "members": {} + }, + "MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT": { + "type": "10000", + "members": {} + }, + "quoteMaxPCForGasCap": { + "type": "(input: import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapInput) => import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": {} + }, + "quoteMaxPCForGasCapFromNativeValue": { + "type": "(input: import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapFromNativeValueInput) => import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": {} + }, + "MaxPCForGasCapInput": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapInput", + "members": { + "bufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "gasLegNativePc": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "MaxPCForGasCapFromNativeValueInput": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapFromNativeValueInput", + "members": { + "bufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "nativeValueForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "MaxPCForGasCapQuote": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": { + "bufferBps": { + "optional": false, + "readonly": false, + "type": "number" + }, + "gasLegNativePc": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxPCForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "nativeValueForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "getCEAAddress": { + "type": "(ueaAddress: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise", + "members": {} + }, + "getPushAccountForCEA": { + "type": "(ceaAddress: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise<`0x${string}`>", + "members": {} + }, + "isCEA": { + "type": "(address: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise", + "members": {} + }, + "chainSupportsCEA": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "chainSupportsOutbound": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "getCEAFactoryAddress": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => `0x${string}` | undefined", + "members": {} + }, + "getAllCEAAddresses": { + "type": "(ueaAddress: `0x${string}`, rpcUrls?: Partial>) => Promise", + "members": {} + }, + "encodeSvmExecutePayload": { + "type": "(fields: import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmExecutePayloadFields) => `0x${string}`", + "members": {} + }, + "isSvmChain": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "isValidSolanaHexAddress": { + "type": "(address: string) => boolean", + "members": {} + }, + "buildMigrationPayload": { + "type": "() => `0x${string}`", + "members": {} + }, + "buildErc20WithdrawalMulticall": { + "type": "(tokenAddress: `0x${string}`, recipientAddress: `0x${string}`, amount: bigint) => import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiCall[]", + "members": {} + }, + "ReadChain": { + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain", + "members": {} + }, + "ReadDestination": { + "type": "{\n chain: import(\"sdk/src/lib/read-state/read-state.types\").ReadChain;\n} | {\n chainId: string;\n chainNamespace: string;\n}", + "members": {} + }, + "ResolvedDestination": { + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}", + "members": { + "caip2": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainId": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "namespace": { + "optional": false, + "readonly": false, + "type": "\"eip155\" | \"solana\" | \"web2\"" + } + } + }, + "ReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").SvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery", + "members": { + "type": { + "optional": false, + "readonly": false, + "type": "\"accountBalance\" | \"contractCall\" | \"http\" | \"lamportBalance\" | \"rawAccountData\" | \"splTokenAccount\" | \"storageSlot\"" + } + } + }, + "EvmReadQuery": { + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n target: `0x${string}`;\n type: \"contractCall\";\n} | {\n callData: `0x${string}`;\n target: `0x${string}`;\n type: \"contractCall\";\n} | {\n slot: `0x${string}` | bigint;\n target: `0x${string}`;\n type: \"storageSlot\";\n} | {\n target: `0x${string}`;\n type: \"accountBalance\";\n}", + "members": { + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"accountBalance\" | \"contractCall\" | \"storageSlot\"" + } + } + }, + "SvmReadQuery": { + "type": "{\n account: string | Uint8Array;\n accountName?: string;\n idl?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n type: \"rawAccountData\";\n} | {\n account: string | Uint8Array;\n type: \"lamportBalance\";\n} | {\n account: string | Uint8Array;\n type: \"splTokenAccount\";\n}", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "string | Uint8Array" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"lamportBalance\" | \"rawAccountData\" | \"splTokenAccount\"" + } + } + }, + "Web2ReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery", + "members": { + "body": { + "optional": true, + "readonly": false, + "type": "string | Uint8Array | undefined" + }, + "extract": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[]" + }, + "headers": { + "optional": true, + "readonly": false, + "type": "Record | undefined" + }, + "method": { + "optional": true, + "readonly": false, + "type": "\"GET\" | \"POST\" | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"http\"" + }, + "url": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "Web2Extract": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract", + "members": { + "decimals": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "path": { + "optional": false, + "readonly": false, + "type": "string" + }, + "valueType": { + "optional": false, + "readonly": false, + "type": "\"bool\" | \"bytes\" | \"int256\" | \"string\" | \"uint256\"" + } + } + }, + "Web2ValueType": { + "type": "\"bool\" | \"bytes\" | \"int256\" | \"string\" | \"uint256\"", + "members": {} + }, + "EncodedReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery", + "members": { + "blockRef": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "encoded": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "namespace": { + "optional": false, + "readonly": false, + "type": "\"eip155\" | \"solana\" | \"web2\"" + }, + "ownerBytes": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "queryType": { + "optional": false, + "readonly": false, + "type": "number" + }, + "resultShape": { + "optional": false, + "readonly": false, + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}" + }, + "warnings": { + "optional": false, + "readonly": false, + "type": "string[]" + } + } + }, + "ReadResultShape": { + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"bytes32\" | \"evmCall\" | \"raw\" | \"svmAccount\" | \"uint256\" | \"web2\"" + } + } + }, + "DecodedReadResult": { + "type": "{\n accountName: string;\n kind: \"svmAccount\";\n value: unknown;\n} | {\n kind: \"bytes32\";\n value: `0x${string}`;\n} | {\n kind: \"evmCall\";\n value: unknown;\n} | {\n kind: \"raw\";\n value: `0x${string}`;\n} | {\n kind: \"uint256\";\n value: bigint;\n} | {\n kind: \"web2\";\n values: readonly unknown[];\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"bytes32\" | \"evmCall\" | \"raw\" | \"svmAccount\" | \"uint256\" | \"web2\"" + } + } + }, + "ReadPreflight": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight", + "members": { + "destination": { + "optional": false, + "readonly": false, + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}" + }, + "fetchedAt": { + "optional": false, + "readonly": false, + "type": "number" + }, + "observedChainHeight": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pushBlockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pushGasPrice": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "universalCallback": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "universalCore": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ReadSpec": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "{\n chainId: string;\n chainNamespace: string;\n owner: `0x${string}`;\n}" + }, + "blockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "expiryPushChainHeight": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "minConfirmations": { + "optional": false, + "readonly": false, + "type": "number" + }, + "query": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "revertRecipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ReadSpecTuple": { + "type": "readonly [\n readonly [\n string,\n string,\n `0x${string}`\n ],\n `0x${string}`,\n number,\n bigint,\n bigint,\n bigint,\n `0x${string}`\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "readonly [\n string,\n string,\n `0x${string}`\n]" + }, + "1": { + "optional": false, + "readonly": true, + "type": "`0x${string}`" + }, + "2": { + "optional": false, + "readonly": true, + "type": "number" + }, + "3": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "4": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "5": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "6": { + "optional": false, + "readonly": true, + "type": "`0x${string}`" + }, + "length": { + "optional": false, + "readonly": true, + "type": "7" + } + } + }, + "BuildReadSpecParams": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").BuildReadSpecParams", + "members": { + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "budgetBuffer": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback | undefined" + }, + "callbackBudget": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "destination": { + "optional": false, + "readonly": false, + "type": "{\n chain: import(\"sdk/src/lib/read-state/read-state.types\").ReadChain;\n} | {\n chainId: string;\n chainNamespace: string;\n}" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "expiryPushChainHeight": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFeeBufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "owner": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "query": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").SvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "PreparedRead": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead", + "members": { + "__@preparedReadValue": { + "optional": true, + "readonly": true, + "type": "T | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback | undefined" + }, + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "encodedQuery": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery" + }, + "encodedSpec": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "fees": { + "optional": false, + "readonly": false, + "type": "{\n callbackBudget: bigint;\n protocolFee: bigint;\n total: bigint;\n}" + }, + "preflight": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "queryKey": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "resultShape": { + "optional": false, + "readonly": false, + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}" + }, + "spec": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec" + }, + "specTuple": { + "optional": false, + "readonly": false, + "type": "readonly [\n readonly [\n string,\n string,\n `0x${string}`\n ],\n `0x${string}`,\n number,\n bigint,\n bigint,\n bigint,\n `0x${string}`\n]" + }, + "value": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "warnings": { + "optional": false, + "readonly": false, + "type": "string[]" + } + } + }, + "ReadCallback": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "((spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpecTuple, callbackGasLimit: bigint) => readonly unknown[]) | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "gasLimit": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "target": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "SimulateReadResult": { + "type": "{\n args?: readonly unknown[];\n error: string;\n errorName?: string;\n ok: false;\n} | {\n ok: true;\n}", + "members": { + "ok": { + "optional": false, + "readonly": false, + "type": "boolean" + } + } + }, + "ParsedReadRequest": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ParsedReadRequest", + "members": { + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackTarget": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "logIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "originalFunder": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "requestId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "requestIdUint": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "spec": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec" + }, + "totalPaid": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "FulfilOutcome": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").FulfilOutcome", + "members": { + "burned": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "delivered": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "expired": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "failReason": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "gasReported": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refunded": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refundFailed": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "ReceiptLike": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike", + "members": { + "logs": { + "optional": false, + "readonly": false, + "type": "readonly {\n address: string;\n data: string;\n logIndex?: number | string;\n topics: readonly string[];\n}[]" + } + } + }, + "ReadRef": { + "type": "{\n requestId: `0x${string}` | bigint;\n} | {\n txHash: `0x${string}`;\n}", + "members": {} + }, + "ReadLifecycleOptions": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadLifecycleOptions", + "members": { + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "resultShape": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadFees": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadFees", + "members": { + "burned": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "paid": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "refunded": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refundFailed": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + } + } + }, + "UniversalReadResponse": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse", + "members": { + "callbackDelivered": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "callbackFailReason": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "decoded": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").DecodedReadResult | undefined" + }, + "decodeError": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destination": { + "optional": false, + "readonly": false, + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}" + }, + "errorMsg": { + "optional": false, + "readonly": false, + "type": "string" + }, + "explorerUrl": { + "optional": false, + "readonly": false, + "type": "string" + }, + "fees": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadFees" + }, + "isTerminal": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "outcome": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME" + }, + "pcTx": { + "optional": false, + "readonly": false, + "type": "readonly {\n blockHeight: number;\n errorMsg: string;\n status: string;\n txHash: `0x${string}`;\n}[]" + }, + "raw": { + "optional": false, + "readonly": false, + "type": "{\n errorCode: import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n resultData: `0x${string}`;\n status: import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n} | null" + }, + "refresh": { + "optional": false, + "readonly": false, + "type": "() => Promise>" + }, + "request": { + "optional": false, + "readonly": false, + "type": "{\n callbackGasLimit: bigint;\n callbackTarget: `0x${string}`;\n createdAtHeight: bigint;\n logIndex: number;\n originalFunder: `0x${string}`;\n refundTo: `0x${string}`;\n spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec;\n}" + }, + "requestId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "requestIdUint": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "status": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "value": { + "optional": true, + "readonly": false, + "type": "T | undefined" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/read-state/read-state.types\").ReadLifecycleOptions) => Promise>" + } + } + }, + "ReadResponseTuple": { + "type": "{\n -readonly [K in keyof R]: import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse ? T : unknown>;\n}", + "members": {} + }, + "BatchReadResponse": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").BatchReadResponse", + "members": { + "atomic": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "count": { + "optional": false, + "readonly": false, + "type": "number" + }, + "reads": { + "optional": false, + "readonly": false, + "type": "{\n -readonly [K in keyof R]: import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse ? T : unknown>;\n}" + }, + "transactionHashes": { + "optional": true, + "readonly": false, + "type": "readonly `0x${string}`[] | undefined" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: Omit) => Promise>" + } + } + }, + "ReadOptions": { + "type": "((import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">)) & {\n callback?: (Pick & Required>) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n };\n}", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "advanced": { + "optional": true, + "readonly": false, + "type": "{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n} | undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "({\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} & {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n}) | ({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick & Pick & Required>) | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadPrepareOptions": { + "type": "((((({\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\">) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n}) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">)) & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n}) | ((({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n}) | ({\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\">)) & {\n blockNumber?: never;\n minConfirmations?: never;\n})) & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n}) & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "advanced": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadQueryOptions": { + "type": "({\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\">) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n}) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n}) | ({\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\">)", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadCallbackOptions": { + "type": "{\n callback?: ({\n gasLimit?: bigint;\n target: `0x${string}`;\n } & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n };\n}", + "members": { + "callback": { + "optional": true, + "readonly": false, + "type": "({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} | undefined" + } + } + }, + "ReadValue": { + "type": "O extends {\n abi: infer A extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: infer F extends string;\n} ? number extends A[\"length\"] ? unknown : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, O extends {\n args: infer Args extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n} ? Args : readonly [\n] extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> ? import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> & readonly [\n] : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>> extends infer Selected ? Selected extends {\n outputs: readonly unknown[];\n type: \"function\";\n} & import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiFunction ? {\n [key in keyof {\n [key in keyof import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"]]: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterToPrimitiveType, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"][key], import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterKind>;\n }]: {\n [key in keyof import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"]]: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterToPrimitiveType, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"][key], import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterKind>;\n }[key];\n} extends infer types ? types extends readonly [\n] ? void : types extends readonly [\n infer type\n] ? type : types : never : never : never : O extends {\n web2: {\n extract: infer E extends readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n };\n} ? {\n readonly [K in keyof E]: {\n bool: boolean;\n bytes: `0x${string}`;\n int256: bigint;\n string: string;\n uint256: bigint;\n }[E[K][\"valueType\"]];\n} : O extends {\n storageSlot: unknown;\n} ? `0x${string}` : O extends {\n idl: infer I extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} ? string extends Extract, string> ? unknown : (O extends {\n functionName: infer N extends string;\n} ? N : undefined) extends string ? import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/index\").IdlAccounts[{\n [K in Extract, string>]: Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : K> extends Lowercase<(O extends {\n functionName: infer N extends string;\n } ? N : undefined) & string extends `${infer H}_${infer T}` ? `${H}${Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : (O extends {\n functionName: infer N extends string;\n } ? N : undefined) & string> ? K : never;\n}[Extract, string>]] : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/index\").IdlAccounts[Extract, string>] : bigint", + "members": {} + }, + "ValidateReadCall": { + "type": "O extends {\n abi: infer A extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: infer F extends string;\n} ? (readonly [\n] extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> ? {\n args?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n} : {\n args: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n}) & {\n functionName: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionName;\n} : O extends {\n functionName: infer N extends string;\n idl: infer I extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} ? string extends Extract, string> ? unknown : [\n {\n [K in Extract, string>]: Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : K> extends Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : N> ? K : never;\n }[Extract, string>]\n] extends [\n never\n] ? {\n functionName: Extract, string>;\n} : unknown : unknown", + "members": {} + }, + "ReadWeb2Options": { + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options", + "members": { + "body": { + "optional": true, + "readonly": false, + "type": "string | Uint8Array | undefined" + }, + "extract": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[]" + }, + "headers": { + "optional": true, + "readonly": false, + "type": "Record | undefined" + }, + "method": { + "optional": true, + "readonly": false, + "type": "\"GET\" | \"POST\" | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadTrackOptions": { + "type": "{\n advanced?: Omit, \"enforceGasCheck\">;\n resultShape?: import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape;\n}", + "members": { + "advanced": { + "optional": true, + "readonly": false, + "type": "Omit<{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n}, \"enforceGasCheck\"> | undefined" + }, + "resultShape": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape | undefined" + } + } + }, + "ReadExecuteOptions": { + "type": "{\n advanced?: {\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n } | undefined;\n progressHook?: ((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined;\n waitForCompletion?: boolean | undefined;\n}", + "members": { + "advanced": { + "optional": true, + "readonly": false, + "type": "{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n} | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + } + } + }, + "UNIVERSAL_READ_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS", + "members": { + "ABORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.ABORTED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.EXPIRED" + }, + "FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.FAILED" + }, + "FULFILLED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.FULFILLED" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.PENDING" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.UNSPECIFIED" + }, + "VOTING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.VOTING" + } + } + }, + "READ_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS", + "members": { + "ERROR": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.ERROR" + }, + "SUCCESS": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.SUCCESS" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.UNSPECIFIED" + } + } + }, + "READ_ERROR_CODE": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE", + "members": { + "INVALID_QUERY": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.INVALID_QUERY" + }, + "INVALID_RESULT": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.INVALID_RESULT" + }, + "NOT_FOUND": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.NOT_FOUND" + }, + "REJECTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.REJECTED" + }, + "REVERTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.REVERTED" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.UNSPECIFIED" + }, + "UNSUPPORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.UNSUPPORTED" + } + } + }, + "READ_OUTCOME": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME", + "members": { + "ABORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.ABORTED" + }, + "CALLBACK_FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.CALLBACK_FAILED" + }, + "DECODE_FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.DECODE_FAILED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.EXPIRED" + }, + "FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.FAILED" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.PENDING" + }, + "SOURCE_ERROR": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.SOURCE_ERROR" + }, + "SUCCESS": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.SUCCESS" + }, + "UNKNOWN": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.UNKNOWN" + } + } + }, + "CONTRACT_REQUEST_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS", + "members": { + "EXECUTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.EXECUTED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.EXPIRED" + }, + "NONE": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.NONE" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.PENDING" + }, + "SETTLED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.SETTLED" + } + } + }, + "TERMINAL_READ_STATUSES": { + "type": "ReadonlySet", + "members": {} + }, + "ReadStateError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadStateError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidReadQueryError": { + "type": "import(\"sdk/src/lib/read-state/errors\").InvalidReadQueryError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidReadSpecError": { + "type": "import(\"sdk/src/lib/read-state/errors\").InvalidReadSpecError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "violations": { + "optional": false, + "readonly": true, + "type": "readonly import(\"sdk/src/lib/read-state/errors\").ReadSpecViolation[]" + } + } + }, + "ReadHeightUnavailableError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadHeightUnavailableError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "UnsupportedReadDestinationError": { + "type": "import(\"sdk/src/lib/read-state/errors\").UnsupportedReadDestinationError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadDecodeError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadDecodeError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadTimeoutError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadTimeoutError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "lastStatus": { + "optional": false, + "readonly": true, + "type": "number" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadNotFoundError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadNotFoundError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadRegistryUnavailableError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadRegistryUnavailableError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadSpecViolation": { + "type": "\"CALLBACK_GAS_LIMIT_EXCEEDED\" | \"DOMAIN_BLOCKED\" | \"EMPTY_QUERY\" | \"EXCESSIVE_FEE\" | \"INSUFFICIENT_CALLBACK_BUDGET\" | \"INSUFFICIENT_FEE\" | \"INVALID_ACCOUNT_ID\" | \"INVALID_BLOCK_NUMBER\" | \"INVALID_EXPIRY_HEIGHT\" | \"INVALID_MIN_CONFIRMATIONS\" | \"SVM_OWNER_NOT_32_BYTES\" | \"ZERO_CALLBACK_BUDGET\" | \"ZERO_CALLBACK_GAS_LIMIT\" | \"ZERO_REVERT_RECIPIENT\"", + "members": {} + }, + "resolveDestination": { + "type": "(dest: import(\"sdk/src/lib/read-state/read-state.types\").ReadDestination) => import(\"sdk/src/lib/read-state/read-state.types\").ResolvedDestination", + "members": {} + }, + "encodeReadQuery": { + "type": "(destination: import(\"sdk/src/lib/read-state/read-state.types\").ReadDestination, query: import(\"sdk/src/lib/read-state/read-state.types\").ReadQuery, options?: {\n blockNumber?: bigint;\n minSlot?: bigint;\n}) => import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery", + "members": {} + }, + "decodeReadResult": { + "type": "(resultData: `0x${string}`, shape: import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape) => import(\"sdk/src/lib/read-state/read-state.types\").DecodedReadResult", + "members": {} + }, + "parseReadRequestsFromReceipt": { + "type": "(receipt: import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike, universalCallback: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").ParsedReadRequest[]", + "members": {} + }, + "parseFulfilOutcome": { + "type": "(receipt: import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike, universalCallback: `0x${string}`, requestId: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").FulfilOutcome", + "members": {} + }, + "buildReadSpecFromPreflight": { + "type": "(preflight: import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight, params: import(\"sdk/src/lib/read-state/read-state.types\").BuildReadSpecParams, defaults?: {\n refundTo?: `0x${string}`;\n}) => import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead", + "members": {} + }, + "validateReadSpec": { + "type": "(input: import(\"sdk/src/lib/read-state/validate\").ValidateReadSpecInput) => {\n ok: false;\n violations: import(\"sdk/src/lib/read-state/errors\").ReadSpecViolation[];\n} | {\n ok: true;\n}", + "members": {} + }, + "toCallData": { + "type": "(prepared: import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead, target: {\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: (spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpecTuple, callbackGasLimit: bigint) => readonly unknown[];\n functionName: string;\n}) => {\n data: `0x${string}`;\n value: bigint;\n}", + "members": {} + }, + "sizeCallbackBudget": { + "type": "(callbackGasLimit: bigint, pushGasPrice: bigint, buffer?: number) => bigint", + "members": {} + }, + "inferResultShape": { + "type": "(namespace: string, query: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape", + "members": {} + }, + "toRequestIdHex": { + "type": "(id: `0x${string}` | bigint) => `0x${string}`", + "members": {} + }, + "toReadQuery": { + "type": "(subject: string, o: ReadOptionsInput, resolvedTokenProgram?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@solana/web3.js/lib/index\").PublicKey) => import(\"sdk/src/lib/read-state/read-state.types\").ReadQuery", + "members": {} + }, + "UNIVERSAL_CALLBACK_EVM": { + "type": "readonly [\n {\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"requestExternalReadSelf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"estimateFee\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"statusOf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"enum RequestStatus\";\n readonly name: \"\";\n readonly type: \"uint8\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"isFulfilled\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getPendingRead\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly internalType: \"struct PendingRead\";\n readonly name: \"\";\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"totalEscrowed\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"blockedDomains\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly indexed: false;\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"readSpec\";\n readonly type: \"tuple\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"totalPaid\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"protocolFee\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ReadRequested\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"ReadFulfilled\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"reason\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"CallbackFailed\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"gasReported\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"burned\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"CallbackGasReported\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundSent\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundFailed\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RequestExpired\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"vaultPC\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ProtocolFeeDistributed\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidAccountId\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"EmptyQuery\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidMinConfirmations\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"DomainBlocked\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidBlockNumber\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidExpiryHeight\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroRevertRecipient\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroCallbackGasLimit\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint64\";\n readonly name: \"provided\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"max\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"CallbackGasLimitExceeded\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"required\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"InsufficientFee\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ExcessiveFee\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"actual\";\n readonly type: \"uint8\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"expected\";\n readonly type: \"uint8\";\n }\n ];\n readonly name: \"InvalidRequestStatus\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ContractIsPaused\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"CallerIsNotUCallbackModule\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n }\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"requestExternalReadSelf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n}" + }, + "1": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"estimateFee\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "2": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"statusOf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"enum RequestStatus\";\n readonly name: \"\";\n readonly type: \"uint8\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "3": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"isFulfilled\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "4": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getPendingRead\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly internalType: \"struct PendingRead\";\n readonly name: \"\";\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "5": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"totalEscrowed\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "6": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"blockedDomains\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "7": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly indexed: false;\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"readSpec\";\n readonly type: \"tuple\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"totalPaid\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"protocolFee\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ReadRequested\";\n readonly type: \"event\";\n}" + }, + "8": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"ReadFulfilled\";\n readonly type: \"event\";\n}" + }, + "9": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"reason\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"CallbackFailed\";\n readonly type: \"event\";\n}" + }, + "10": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"gasReported\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"burned\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"CallbackGasReported\";\n readonly type: \"event\";\n}" + }, + "11": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundSent\";\n readonly type: \"event\";\n}" + }, + "12": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundFailed\";\n readonly type: \"event\";\n}" + }, + "13": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RequestExpired\";\n readonly type: \"event\";\n}" + }, + "14": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"vaultPC\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ProtocolFeeDistributed\";\n readonly type: \"event\";\n}" + }, + "15": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidAccountId\";\n readonly type: \"error\";\n}" + }, + "16": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"EmptyQuery\";\n readonly type: \"error\";\n}" + }, + "17": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidMinConfirmations\";\n readonly type: \"error\";\n}" + }, + "18": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"DomainBlocked\";\n readonly type: \"error\";\n}" + }, + "19": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidBlockNumber\";\n readonly type: \"error\";\n}" + }, + "20": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidExpiryHeight\";\n readonly type: \"error\";\n}" + }, + "21": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroRevertRecipient\";\n readonly type: \"error\";\n}" + }, + "22": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroCallbackGasLimit\";\n readonly type: \"error\";\n}" + }, + "23": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint64\";\n readonly name: \"provided\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"max\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"CallbackGasLimitExceeded\";\n readonly type: \"error\";\n}" + }, + "24": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"required\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"InsufficientFee\";\n readonly type: \"error\";\n}" + }, + "25": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ExcessiveFee\";\n readonly type: \"error\";\n}" + }, + "26": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"actual\";\n readonly type: \"uint8\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"expected\";\n readonly type: \"uint8\";\n }\n ];\n readonly name: \"InvalidRequestStatus\";\n readonly type: \"error\";\n}" + }, + "27": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ContractIsPaused\";\n readonly type: \"error\";\n}" + }, + "28": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"CallerIsNotUCallbackModule\";\n readonly type: \"error\";\n}" + }, + "29": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n}" + }, + "length": { + "optional": false, + "readonly": true, + "type": "30" + } + } + }, + "UNIVERSAL_READ_REGISTRY_EVM": { + "type": "readonly [\n {\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n },\n {\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"read\";\n readonly outputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"universalCallback_\";\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"constructor\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"initialize\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getLocalContext\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"hasResult\";\n readonly outputs: readonly [\n {\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"onUniversalData\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"queryKeyOf\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes32\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"readerOf\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"requestOrderOf\";\n readonly outputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"universalCallback\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"resultByRequestId\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"latestResult\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"version\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"Initialized\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadRequested\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadStored\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidInitialization\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"NotInitializing\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroAddressInit\";\n readonly type: \"error\";\n }\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n },\n {\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"read\";\n readonly outputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n}" + }, + "1": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"universalCallback_\";\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"constructor\";\n}" + }, + "2": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"initialize\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n}" + }, + "3": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getLocalContext\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "4": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"hasResult\";\n readonly outputs: readonly [\n {\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "5": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"onUniversalData\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n}" + }, + "6": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"queryKeyOf\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes32\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "7": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"readerOf\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "8": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"requestOrderOf\";\n readonly outputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "9": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"universalCallback\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "10": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"resultByRequestId\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "11": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"latestResult\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "12": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"version\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"Initialized\";\n readonly type: \"event\";\n}" + }, + "13": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadRequested\";\n readonly type: \"event\";\n}" + }, + "14": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadStored\";\n readonly type: \"event\";\n}" + }, + "15": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidInitialization\";\n readonly type: \"error\";\n}" + }, + "16": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"NotInitializing\";\n readonly type: \"error\";\n}" + }, + "17": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n}" + }, + "18": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroAddressInit\";\n readonly type: \"error\";\n}" + }, + "length": { + "optional": false, + "readonly": true, + "type": "19" + } + } + }, + "PushChainExecutionError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").PushChainExecutionError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PushChainBatchExecutionError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").PushChainBatchExecutionError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": false, + "readonly": true, + "type": "`0x${string}`[]" + } + } + }, + "DecodedErrorPayload": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload", + "members": { + "decoded": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "name": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "selector": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "PushChainInitializeOptions": { + "type": "import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions", + "members": { + "agenticWallet": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "blockExplorers": { + "optional": true, + "readonly": false, + "type": "Partial> | undefined" + }, + "network": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "printTraces": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "rpcUrls": { + "optional": true, + "readonly": false, + "type": "Partial> | undefined" + } + } + }, + "AGENTIC_ERROR_CODE": { + "type": "{\n readonly AGENT_GAS_INSUFFICIENT: \"AGENT_GAS_INSUFFICIENT\";\n readonly AGENT_IS_OWNER: \"AGENT_IS_OWNER\";\n readonly AMBIGUOUS_RULE: \"AMBIGUOUS_RULE\";\n readonly ASSET_CHAIN_MISMATCH: \"ASSET_CHAIN_MISMATCH\";\n readonly CAPABILITY_UNAVAILABLE: \"CAPABILITY_UNAVAILABLE\";\n readonly CREATE_PARTIAL: \"CREATE_PARTIAL\";\n readonly FROM_NOT_ALLOWED: \"FROM_NOT_ALLOWED\";\n readonly GATEWAY_ALLOWANCE_INSUFFICIENT: \"GATEWAY_ALLOWANCE_INSUFFICIENT\";\n readonly GENERATION_UNSUPPORTED: \"GENERATION_UNSUPPORTED\";\n readonly INCONSISTENT_READ: \"INCONSISTENT_READ\";\n readonly INDEX_RACE: \"INDEX_RACE\";\n readonly INVALID_RULE: \"INVALID_RULE\";\n readonly NO_RULES_FOR_CHAIN: \"NO_RULES_FOR_CHAIN\";\n readonly NOT_AGENTIC_WALLET: \"NOT_AGENTIC_WALLET\";\n readonly NOT_ALLOWED_IN_AGENTIC_MODE: \"NOT_ALLOWED_IN_AGENTIC_MODE\";\n readonly NOT_OWNER_OR_AGENT: \"NOT_OWNER_OR_AGENT\";\n readonly NOT_WALLET_OWNER: \"NOT_WALLET_OWNER\";\n readonly READ_ONLY: \"READ_ONLY\";\n readonly RECEIPT_MISMATCH: \"RECEIPT_MISMATCH\";\n readonly RECEIPT_UNAVAILABLE: \"RECEIPT_UNAVAILABLE\";\n readonly REVOKE_NEEDS_TARGET: \"REVOKE_NEEDS_TARGET\";\n readonly RULE_LIMIT_EXCEEDED: \"RULE_LIMIT_EXCEEDED\";\n readonly RULE_NOT_FOUND: \"RULE_NOT_FOUND\";\n readonly RULE_READ_FAILED: \"RULE_READ_FAILED\";\n readonly TARGET_NOT_ON_RULE_CHAIN: \"TARGET_NOT_ON_RULE_CHAIN\";\n readonly WALLET_BALANCE_INSUFFICIENT: \"WALLET_BALANCE_INSUFFICIENT\";\n readonly WALLET_NOT_DEPLOYED: \"WALLET_NOT_DEPLOYED\";\n}", + "members": { + "AGENT_GAS_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\"" + }, + "AGENT_IS_OWNER": { + "optional": false, + "readonly": true, + "type": "\"AGENT_IS_OWNER\"" + }, + "AMBIGUOUS_RULE": { + "optional": false, + "readonly": true, + "type": "\"AMBIGUOUS_RULE\"" + }, + "ASSET_CHAIN_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"ASSET_CHAIN_MISMATCH\"" + }, + "CAPABILITY_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"CAPABILITY_UNAVAILABLE\"" + }, + "CREATE_PARTIAL": { + "optional": false, + "readonly": true, + "type": "\"CREATE_PARTIAL\"" + }, + "FROM_NOT_ALLOWED": { + "optional": false, + "readonly": true, + "type": "\"FROM_NOT_ALLOWED\"" + }, + "GATEWAY_ALLOWANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"GATEWAY_ALLOWANCE_INSUFFICIENT\"" + }, + "GENERATION_UNSUPPORTED": { + "optional": false, + "readonly": true, + "type": "\"GENERATION_UNSUPPORTED\"" + }, + "INCONSISTENT_READ": { + "optional": false, + "readonly": true, + "type": "\"INCONSISTENT_READ\"" + }, + "INDEX_RACE": { + "optional": false, + "readonly": true, + "type": "\"INDEX_RACE\"" + }, + "INVALID_RULE": { + "optional": false, + "readonly": true, + "type": "\"INVALID_RULE\"" + }, + "NO_RULES_FOR_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"NO_RULES_FOR_CHAIN\"" + }, + "NOT_AGENTIC_WALLET": { + "optional": false, + "readonly": true, + "type": "\"NOT_AGENTIC_WALLET\"" + }, + "NOT_ALLOWED_IN_AGENTIC_MODE": { + "optional": false, + "readonly": true, + "type": "\"NOT_ALLOWED_IN_AGENTIC_MODE\"" + }, + "NOT_OWNER_OR_AGENT": { + "optional": false, + "readonly": true, + "type": "\"NOT_OWNER_OR_AGENT\"" + }, + "NOT_WALLET_OWNER": { + "optional": false, + "readonly": true, + "type": "\"NOT_WALLET_OWNER\"" + }, + "READ_ONLY": { + "optional": false, + "readonly": true, + "type": "\"READ_ONLY\"" + }, + "RECEIPT_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_MISMATCH\"" + }, + "RECEIPT_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_UNAVAILABLE\"" + }, + "REVOKE_NEEDS_TARGET": { + "optional": false, + "readonly": true, + "type": "\"REVOKE_NEEDS_TARGET\"" + }, + "RULE_LIMIT_EXCEEDED": { + "optional": false, + "readonly": true, + "type": "\"RULE_LIMIT_EXCEEDED\"" + }, + "RULE_NOT_FOUND": { + "optional": false, + "readonly": true, + "type": "\"RULE_NOT_FOUND\"" + }, + "RULE_READ_FAILED": { + "optional": false, + "readonly": true, + "type": "\"RULE_READ_FAILED\"" + }, + "TARGET_NOT_ON_RULE_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"TARGET_NOT_ON_RULE_CHAIN\"" + }, + "WALLET_BALANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"WALLET_BALANCE_INSUFFICIENT\"" + }, + "WALLET_NOT_DEPLOYED": { + "optional": false, + "readonly": true, + "type": "\"WALLET_NOT_DEPLOYED\"" + } + } + }, + "AgenticError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"AMBIGUOUS_RULE\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"CREATE_PARTIAL\" | \"FROM_NOT_ALLOWED\" | \"GATEWAY_ALLOWANCE_INSUFFICIENT\" | \"GENERATION_UNSUPPORTED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"REVOKE_NEEDS_TARGET\" | \"RULE_LIMIT_EXCEEDED\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"" + }, + "details": { + "optional": true, + "readonly": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "AgenticRevertError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticRevertError", + "members": { + "agenticCode": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + } + } + }, + "AgenticAddress": { + "type": "`0x${string}`", + "members": {} + }, + "AgenticDoor": { + "type": "\"agent\" | \"owner\"", + "members": {} + }, + "AgenticErrorCode": { + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"AMBIGUOUS_RULE\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"CREATE_PARTIAL\" | \"FROM_NOT_ALLOWED\" | \"GATEWAY_ALLOWANCE_INSUFFICIENT\" | \"GENERATION_UNSUPPORTED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"REVOKE_NEEDS_TARGET\" | \"RULE_LIMIT_EXCEEDED\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"", + "members": {} + }, + "AgenticHex": { + "type": "`0x${string}`", + "members": {} + }, + "AgenticNamespace": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace", + "members": { + "create": { + "optional": false, + "readonly": false, + "type": "(label: string, options: import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions) => Promise" + }, + "derive": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n index?: number;\n}) => Promise<{\n address: `0x${string}`;\n deployed: boolean;\n index: number;\n}>" + }, + "list": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n wallets: import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary[];\n}>" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "(address: `0x${string}`) => import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet" + } + } + }, + "AgenticNetworkConstants": { + "type": "import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants", + "members": { + "ENVELOPE_VERSION": { + "optional": false, + "readonly": false, + "type": "number" + }, + "FACTORY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "MAX_ALLOWED_CALLS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "MAX_PINS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "RULES_POLICY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticProgressHook": { + "type": "(event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void", + "members": {} + }, + "AgenticTxMetadata": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticTxMetadata", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destinationAccount": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "destinationCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "door": { + "optional": false, + "readonly": false, + "type": "\"agent\" | \"owner\"" + }, + "nativeCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "rawData": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rawTo": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesId": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticWallet": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "checkpoints": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n sinceBlock?: bigint;\n}) => Promise<{\n checkpoints: import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint[];\n}>" + }, + "info": { + "optional": false, + "readonly": false, + "type": "() => Promise" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n owner: `0x${string}`;\n}>" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "{\n add(rules: import(\"sdk/src/lib/agentic/agentic.types\").Rule[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise<{\n rulesIds: `0x${string}`[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n get(rulesId: `0x${string}`): Promise;\n list(): Promise<{\n rules: import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord[];\n }>;\n revoke(rulesIds: `0x${string}`[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n revoke(params: {\n all: true;\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n update(params: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n rules: {\n rule: import(\"sdk/src/lib/agentic/agentic.types\").Rule;\n rulesId: `0x${string}`;\n }[];\n }): Promise<{\n rules: {\n replaced: `0x${string}`;\n rulesId: `0x${string}`;\n }[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n}" + }, + "setLabel": { + "optional": false, + "readonly": false, + "type": "(label: string, opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n}) => Promise" + } + } + }, + "AllowedCall": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall", + "members": { + "beneficiary": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "beneficiaryOffset": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValue": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "`${string}(${string})` | `0x${string}`" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AssetCap": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap", + "members": { + "maxPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/constants/tokens\").MoveableToken" + } + } + }, + "Checkpoint": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint", + "members": { + "blockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "kind": { + "optional": false, + "readonly": false, + "type": "\"OWNER_ACTION\" | \"RULES_GRANTED\" | \"RULES_REVOKED\"" + }, + "ref": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "seq": { + "optional": false, + "readonly": false, + "type": "number" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "CheckpointKind": { + "type": "\"OWNER_ACTION\" | \"RULES_GRANTED\" | \"RULES_REVOKED\"", + "members": {} + }, + "CreateOptions": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions", + "members": { + "progressHook": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook | undefined" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Rule[]" + } + } + }, + "CreateResult": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateResult", + "members": { + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "rulesIds": { + "optional": false, + "readonly": false, + "type": "`0x${string}`[]" + }, + "tx": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ForeignChainNamespace": { + "type": "`eip155:${string}` | `solana:${string}`", + "members": {} + }, + "NativeRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "amount": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AmountLimit | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "maxCalls": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValuePerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxValueTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "pins": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ArgPin[] | undefined" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Rule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule | import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "RulesRecord": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "enabled": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "ref": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "rule": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule | import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule" + }, + "rulesId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Selector": { + "type": "`${string}(${string})` | `0x${string}`", + "members": {} + }, + "UniversalRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall[]" + }, + "assets": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap[]" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "`eip155:${string}` | `solana:${string}`" + }, + "maxGasPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "WalletInfo": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").WalletInfo", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "label": { + "optional": false, + "readonly": false, + "type": "string" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "rulesCount": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "WalletSummary": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "label": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesCount": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "PushChain": { + "type": "import(\"sdk/src/lib/push-chain/push-chain\").PushChain", + "members": { + "accountStatus": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus" + }, + "accountStatusReady": { + "optional": false, + "readonly": false, + "type": "Promise" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace" + }, + "explorer": { + "optional": false, + "readonly": false, + "type": "{\n getTransactionUrl: (txHash: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n listAllUrls: () => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n listUrls: (options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n}" + }, + "funds": { + "optional": false, + "readonly": false, + "type": "{\n getConversionQuote: (amountIn: bigint, options: {\n from: import(\"sdk/src/lib/constants/tokens\").PayableToken | undefined;\n to: import(\"sdk/src/lib/constants/tokens\").MoveableToken | undefined;\n }) => Promise;\n}" + }, + "getAccountStatus": { + "optional": false, + "readonly": false, + "type": "(options?: {\n forceRefresh?: boolean;\n}) => Promise" + }, + "isReadMode": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "moveable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").MoveableTokenAccessor;\n}" + }, + "payable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").PayableTokenAccessor;\n}" + }, + "reinitialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "universal": { + "optional": false, + "readonly": false, + "type": "{\n readonly account: `0x${string}`;\n executeReads: (reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>;\n executeTransactions: (txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise;\n migrateCEA: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"migrateCEA\"];\n readonly origin: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n prepareRead: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n prepareTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"prepareTransaction\"];\n read: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n rescueFunds: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"rescueFunds\"];\n sendTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"execute\"];\n signMessage: (data: Uint8Array) => Promise;\n signTypedData: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n trackRead: {\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n };\n trackTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"trackTransaction\"];\n}" + }, + "upgradeAccount": { + "optional": false, + "readonly": false, + "type": "(options?: {\n progressHook?: (progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n}) => Promise" + } + } + } + }, + "pushChainStatic": { + "CONSTANTS": { + "optional": false, + "readonly": false, + "type": "{\n AGENTIC: Readonly>>;\n CHAIN: typeof import(\"sdk/src/lib/constants/enums\").CHAIN;\n LIBRARY: typeof import(\"sdk/src/lib/constants/enums\").LIBRARY;\n MOVEABLE: {\n TOKEN: import(\"sdk/src/lib/constants/tokens\").MoveableTokenConstantsMap;\n };\n PAYABLE: {\n TOKEN: import(\"sdk/src/lib/constants/tokens\").PayableTokenConstantsMap;\n };\n PUSH_NETWORK: typeof import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n READ: {\n readonly CALLBACK_BUDGET_BUFFER: 3;\n readonly CHAIN: {\n readonly WEB2: \"web2\";\n } & Readonly<{\n readonly ARBITRUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA;\n readonly BASE_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA;\n readonly BNB_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET;\n readonly ETHEREUM_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET;\n readonly ETHEREUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA;\n readonly PUSH_LOCALNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET;\n readonly PUSH_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET;\n readonly PUSH_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly PUSH_TESTNET_DONUT: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly SOLANA_DEVNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET;\n readonly SOLANA_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET;\n readonly SOLANA_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n readonly WEB2: \"web2\";\n }>;\n readonly DEFAULT_EXPIRY_BLOCKS: 300n;\n readonly ERROR_CODE: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n readonly MAX_CALLBACK_GAS_LIMIT: 1000000n;\n readonly MIN_CONFIRMATIONS_FLOOR: 1;\n readonly NAMESPACE: {\n readonly EVM: \"eip155\";\n readonly SVM: \"solana\";\n readonly WEB2: \"web2\";\n };\n readonly OUTCOME: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME;\n readonly REGISTRY_CALLBACK_GAS: 500000n;\n readonly RESULT_STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n readonly STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS;\n readonly UNIVERSAL_CALLBACK_ADDRESSES: Record;\n readonly UNIVERSAL_CORE_ADDRESSES: Record;\n readonly UNIVERSAL_READ_REGISTRY_ADDRESS: {\n readonly TESTNET_DONUT: \"0x00000000000000000000000000000000000000b2\";\n };\n readonly WEB2: \"web2\";\n readonly WEB2_DEFAULT_TIMEOUT_MS: 5000;\n readonly WEB2_MAX_EXTRACT_ENTRIES: 16;\n };\n}" + }, + "initialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "utils": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/utils\").Utils" + } + }, + "pushChainInstance": { + "accountStatus": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus" + }, + "accountStatusReady": { + "optional": false, + "readonly": false, + "type": "Promise" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace" + }, + "explorer": { + "optional": false, + "readonly": false, + "type": "{\n getTransactionUrl: (txHash: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n listAllUrls: () => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n listUrls: (options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n}" + }, + "funds": { + "optional": false, + "readonly": false, + "type": "{\n getConversionQuote: (amountIn: bigint, options: {\n from: import(\"sdk/src/lib/constants/tokens\").PayableToken | undefined;\n to: import(\"sdk/src/lib/constants/tokens\").MoveableToken | undefined;\n }) => Promise;\n}" + }, + "getAccountStatus": { + "optional": false, + "readonly": false, + "type": "(options?: {\n forceRefresh?: boolean;\n}) => Promise" + }, + "isReadMode": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "moveable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").MoveableTokenAccessor;\n}" + }, + "payable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").PayableTokenAccessor;\n}" + }, + "reinitialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "universal": { + "optional": false, + "readonly": false, + "type": "{\n readonly account: `0x${string}`;\n executeReads: (reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>;\n executeTransactions: (txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise;\n migrateCEA: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"migrateCEA\"];\n readonly origin: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n prepareRead: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n prepareTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"prepareTransaction\"];\n read: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n rescueFunds: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"rescueFunds\"];\n sendTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"execute\"];\n signMessage: (data: Uint8Array) => Promise;\n signTypedData: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n trackRead: {\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n };\n trackTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"trackTransaction\"];\n}" + }, + "upgradeAccount": { + "optional": false, + "readonly": false, + "type": "(options?: {\n progressHook?: (progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n}) => Promise" + } + }, + "transactionMethods": { + "account": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "executeReads": { + "optional": false, + "readonly": false, + "type": "(reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>" + }, + "executeTransactions": { + "optional": false, + "readonly": false, + "type": "(txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise" + }, + "migrateCEA": { + "optional": false, + "readonly": false, + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => Promise" + }, + "origin": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "prepareRead": { + "optional": false, + "readonly": false, + "type": "(subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>" + }, + "prepareTransaction": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions) => Promise" + }, + "read": { + "optional": false, + "readonly": false, + "type": "(subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>" + }, + "rescueFunds": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").RescueFundsParams) => Promise" + }, + "sendTransaction": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").ExecuteParams | import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions) => Promise" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": false, + "readonly": false, + "type": "({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise" + }, + "trackRead": { + "optional": false, + "readonly": false, + "type": "{\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n}" + }, + "trackTransaction": { + "optional": false, + "readonly": false, + "type": "(txHash: string, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TrackTransactionOptions) => Promise" + } + }, + "utilityMethods": { + "account": { + "optional": false, + "readonly": false, + "type": "{\n convertExecutorToOriginAccount: (ueaAddress: `0x${string}`, options?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n }) => Promise;\n convertOriginToExecutor: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n onlyCompute?: boolean;\n }) => Promise;\n deriveExecutorAccount: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n skipNetworkCheck?: boolean;\n }) => Promise;\n fromChainAgnostic: (caip: string) => import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n resolveControllerAccount: (address: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n skipNetworkCheck?: boolean;\n }) => Promise;\n toChainAgnostic: (address: string, options: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n toUniversal: (address: string, options: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n}" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "{\n actionId: (target: `0x${string}`, selector: \"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector) => `0x${string}`;\n configId: (wallet: `0x${string}`, rulesId: `0x${string}`, actionId: `0x${string}`) => `0x${string}`;\n decodeRules: (bytes: `0x${string}`, ctx?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n pushChainNamespace?: string;\n }) => import(\"sdk/src/lib/agentic/agentic.types\").Rule;\n}" + }, + "chains": { + "optional": false, + "readonly": false, + "type": "{\n getChainName: (chainNamespace: string) => string | undefined;\n getChainNamespace: (chainName: string) => string | undefined;\n getSupportedChains: (network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK) => {\n chains: import(\"sdk/src/lib/constants/enums\").CHAIN[];\n };\n getSupportedChainsByName: (network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK) => {\n chains: string[];\n };\n}" + }, + "conversion": { + "optional": false, + "readonly": false, + "type": "{\n slippageToMinAmount(amount: string, options: {\n slippageBps: number;\n }): string;\n}" + }, + "helpers": { + "optional": false, + "readonly": false, + "type": "{\n encodeTxData({ abi, idl, functionName, args, }: {\n abi?: any;\n args?: any[];\n functionName: string;\n idl?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n }): `0x${string}`;\n formatUnits(value: bigint | string, decimalsOrOptions: {\n decimals: number;\n precision?: number;\n } | number): string;\n getChainName: (chainName: string) => string | undefined;\n parseUnits(value: string, exponent: {\n decimals: number;\n } | number): bigint;\n}" + }, + "signer": { + "optional": false, + "readonly": false, + "type": "{\n construct: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options: {\n signAndSendTransaction: (unsignedTx: Uint8Array) => Promise;\n signAuthorization?: (params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise;\n signMessage: (data: Uint8Array) => Promise;\n signTypedData?: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n }) => import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton;\n toUniversal: (signer: import(\"sdk/src/lib/universal/universal.types\").EthersV5SignerType | import(\"sdk/src/lib/universal/universal.types\").EthersV6SignerType | import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton | import(\"sdk/src/lib/universal/universal.types\").ViemSignerType) => Promise;\n toUniversalFromKeypair: (clientOrAccount: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@solana/web3.js/lib/index\").Keypair | import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").WalletClient | import(\"sdk/src/lib/universal/universal.types\").EthersV6SignerType, { chain, library }: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n library: import(\"sdk/src/lib/constants/enums\").LIBRARY;\n }) => Promise;\n}" + }, + "svm": { + "optional": false, + "readonly": false, + "type": "{\n getRegisteredIdls: () => Array<{\n address: `0x${string}`;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n }>;\n registerIdl: (idl: unknown) => void;\n}" + }, + "tokens": { + "optional": false, + "readonly": false, + "type": "{\n getMoveableTokens(chainOrClient?: import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/push-chain/push-chain\").PushChain): {\n tokens: Array<{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n decimals: number;\n mechanism: \"approve\" | \"native\" | \"permit2\";\n prc20Address?: `0x${string}`;\n sourceChain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n symbol: string;\n }>;\n };\n getPayableTokens(chainOrClient?: import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/push-chain/push-chain\").PushChain): {\n tokens: Array<{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n decimals: number;\n mechanism: \"approve\" | \"native\" | \"permit2\";\n symbol: string;\n }>;\n };\n getPC20Address(address: string, options: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n rpcUrls?: Partial>;\n strict?: boolean;\n }): Promise;\n getPRC20Address: (token: {\n address: string;\n chain: string;\n } | import(\"sdk/src/lib/constants/tokens\").MoveableToken, options?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n }) => {\n address: `0x${string}`;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n decimals: number;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n symbol: string;\n };\n}" + } + }, + "initialize": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise", + "agwConstants": { + "ENVELOPE_VERSION": { + "optional": false, + "readonly": false, + "type": "number" + }, + "FACTORY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "MAX_ALLOWED_CALLS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "MAX_PINS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "RULES_POLICY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + }, + "constants": { + "AGENTIC": { + "optional": false, + "readonly": false, + "type": "{\n readonly LOCALNET?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n readonly MAINNET?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n readonly TESTNET?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n readonly TESTNET_DONUT?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n}" + }, + "CHAIN": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "LIBRARY": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").LIBRARY" + }, + "MOVEABLE": { + "optional": false, + "readonly": false, + "type": "{\n TOKEN: import(\"sdk/src/lib/constants/tokens\").MoveableTokenConstantsMap;\n}" + }, + "PAYABLE": { + "optional": false, + "readonly": false, + "type": "{\n TOKEN: import(\"sdk/src/lib/constants/tokens\").PayableTokenConstantsMap;\n}" + }, + "PUSH_NETWORK": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "READ": { + "optional": false, + "readonly": false, + "type": "{\n readonly CALLBACK_BUDGET_BUFFER: 3;\n readonly CHAIN: {\n readonly WEB2: \"web2\";\n } & Readonly<{\n readonly ARBITRUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA;\n readonly BASE_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA;\n readonly BNB_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET;\n readonly ETHEREUM_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET;\n readonly ETHEREUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA;\n readonly PUSH_LOCALNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET;\n readonly PUSH_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET;\n readonly PUSH_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly PUSH_TESTNET_DONUT: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly SOLANA_DEVNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET;\n readonly SOLANA_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET;\n readonly SOLANA_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n readonly WEB2: \"web2\";\n }>;\n readonly DEFAULT_EXPIRY_BLOCKS: 300n;\n readonly ERROR_CODE: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n readonly MAX_CALLBACK_GAS_LIMIT: 1000000n;\n readonly MIN_CONFIRMATIONS_FLOOR: 1;\n readonly NAMESPACE: {\n readonly EVM: \"eip155\";\n readonly SVM: \"solana\";\n readonly WEB2: \"web2\";\n };\n readonly OUTCOME: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME;\n readonly REGISTRY_CALLBACK_GAS: 500000n;\n readonly RESULT_STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n readonly STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS;\n readonly UNIVERSAL_CALLBACK_ADDRESSES: Record;\n readonly UNIVERSAL_CORE_ADDRESSES: Record;\n readonly UNIVERSAL_READ_REGISTRY_ADDRESS: {\n readonly TESTNET_DONUT: \"0x00000000000000000000000000000000000000b2\";\n };\n readonly WEB2: \"web2\";\n readonly WEB2_DEFAULT_TIMEOUT_MS: 5000;\n readonly WEB2_MAX_EXTRACT_ENTRIES: 16;\n}" + } + } + }, + "scope": "All root exports and declared public members, PushChain static/instance members, universal transaction methods, utility groups, readonly/optional markers and constants. Behavior/default/deployment changes need the written session review." +} diff --git a/plan/agw/research/sdk-hardening-2026-10-06/changed-lint.log b/plan/agw/research/sdk-hardening-2026-10-06/changed-lint.log new file mode 100644 index 00000000..842c60cd --- /dev/null +++ b/plan/agw/research/sdk-hardening-2026-10-06/changed-lint.log @@ -0,0 +1,17 @@ + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__agw-local__/svm-backend.spec.ts + 142:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 170:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 229:28 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 403:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 427:23 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 471:22 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 543:61 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__agw-local__/svm-differential.spec.ts + 74:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 212:20 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 265:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 384:20 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +✖ 11 problems (0 errors, 11 warnings) diff --git a/plan/agw/research/sdk-hardening-2026-10-06/live-receipt-recheck.json b/plan/agw/research/sdk-hardening-2026-10-06/live-receipt-recheck.json new file mode 100644 index 00000000..e0fdca95 --- /dev/null +++ b/plan/agw/research/sdk-hardening-2026-10-06/live-receipt-recheck.json @@ -0,0 +1,31 @@ +{ + "checkedAt": "2026-10-06T05:36:02.227Z", + "readOnly": true, + "transactionsSubmitted": false, + "receipts": [ + { + "name": "positive-push", + "hash": "0x3236bbc8f2029f53a2aa09d0c0d3cd291568bbaccf4de70061ecd085d4adcb3e", + "status": "success", + "block": "23935801" + }, + { + "name": "positive-sepolia", + "hash": "0x1dac9f08f651c30e0c2de11c42c8df8bbcbd12484575b536e4d42f40819989ea", + "status": "success", + "block": "11851537" + }, + { + "name": "call-only-push", + "hash": "0x7fb0792747909149da3c8975aaba43a80224a20544c41ac88c04a3cf899c9926", + "status": "success", + "block": "23935113" + }, + { + "name": "call-only-sepolia", + "hash": "0xadb89cd9cfb70fd33b9eaa2e05b109b0a9a26d3fb9221e8dc28cd8cf8d4f27fe", + "status": "success", + "block": "11851391" + } + ] +} diff --git a/plan/agw/research/sdk-hardening-2026-10-06/node20/build.log b/plan/agw/research/sdk-hardening-2026-10-06/node20/build.log new file mode 100644 index 00000000..b75e1983 --- /dev/null +++ b/plan/agw/research/sdk-hardening-2026-10-06/node20/build.log @@ -0,0 +1,13 @@ + +> nx run core:build + +Compiling TypeScript files for project "core"... +Done compiling TypeScript files for project "core". + + + + NX Successfully ran target build for project core + + +(node:39395) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. +(Use `node --trace-warnings ...` to show where the warning was created) diff --git a/plan/agw/research/sdk-hardening-2026-10-06/node20/docs.log b/plan/agw/research/sdk-hardening-2026-10-06/node20/docs.log new file mode 100644 index 00000000..5996134d --- /dev/null +++ b/plan/agw/research/sdk-hardening-2026-10-06/node20/docs.log @@ -0,0 +1 @@ +AGW guide: 7 TypeScript blocks typechecked against public exports; no examples executed. diff --git a/plan/agw/research/sdk-hardening-2026-10-06/node20/full-unit.log b/plan/agw/research/sdk-hardening-2026-10-06/node20/full-unit.log new file mode 100644 index 00000000..da3d0edb --- /dev/null +++ b/plan/agw/research/sdk-hardening-2026-10-06/node20/full-unit.log @@ -0,0 +1,168 @@ +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-confirmation-gate.spec.ts +PASS core packages/core/src/lib/universal/account/account.spec.ts + ● Console + + console.warn + [PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead. + + 207 | ): Promise { + 208 | if (!_convertOriginToExecutorWarned) { + > 209 | console.warn( + | ^ + 210 | '[PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead.' + 211 | ); + 212 | _convertOriginToExecutorWarned = true; + + at Object.convertOriginToExecutor (src/lib/universal/account/account.ts:209:13) + at Object. (src/lib/universal/account/account.spec.ts:80:52) + + console.warn + [PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead. + + 425 | ): Promise { + 426 | if (!options?._internal && !_convertExecutorToOriginWarned) { + > 427 | console.warn( + | ^ + 428 | '[PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead.' + 429 | ); + 430 | _convertExecutorToOriginWarned = true; + + at convertExecutorToOrigin (src/lib/universal/account/account.ts:427:13) + at Object. (src/lib/universal/account/account.spec.ts:106:38) + +PASS core packages/core/src/lib/read-state/__tests__/block-results-client.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/send.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-tx-retry.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-svm-confirmation.spec.ts +PASS core packages/core/src/lib/push-client/push-client.archive-fallback.spec.ts +PASS core packages/core/src/lib/utils.spec.ts + ● Console + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:973:17) + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:977:17) + + console.log + 1.23 + + at Object. (src/lib/utils.spec.ts:982:17) + +PASS core packages/core/src/lib/orchestrator/svm-idl/resolve.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-backend.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-multichain.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/source-hash-resolution.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r2-outbound-revert-flow.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/cascade.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-timeout-clamp.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/payload-builders.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-error-classification.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/management.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/web2-compat.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r3-spec-strings.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/response-surface.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-classification.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/svm-account.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/inbound-tracker-derivation.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm-rent-pc20.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm-log-index.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/account-status.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/signing-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-emission.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-executor.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-calculator.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/track-transaction-guard.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r1-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/resolver.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gateway-uea-account.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r2-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/context-helpers-tracker.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-request-recipient.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-tracker.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/export.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/chain-namespace.spec.ts +PASS core packages/core/src/lib/universal/signer/signer.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/response-builder-push-revert.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/build-payload.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/read-tx-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/send-transaction-progress-hook.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-evm-r3-native-eoa.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/rescue-svm-confirmation.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/execute-standard-required-funds.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-event-hook-bridge.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/gate.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/multichain-hooks.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-composition.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-detector.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-builder-progress-hook.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-native-multicall.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/response-invariant.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-svm-r3.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/registry.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/terminal-suppression.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/scenarios.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts +PASS core packages/core/src/lib/push-client/push-client.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-usd-sizer.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/inbound-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/svm-rent.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/funds-only-burn-guard.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-svm-rent.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/public-surface.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/revalidate-read.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/codec.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/reads-context.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/validate.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/abi-selectors.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/auto-detect.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/ucallback-codec.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-svm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-params.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/spec-builder.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/result-decoder.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/address-codec.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-evm.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg-svm.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.chain-symbol.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/child-inbounds.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.dynamic-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/__tests__/signing.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/errors.spec.ts +PASS core packages/core/src/lib/constants/__tests__/token-constants.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-types.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-web2.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/normalize.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-events.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/max-pc-for-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/ix-encoder.spec.ts +PASS core packages/core/src/lib/constants/__tests__/svm-gateway-idl.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/registry.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/error-decoder.spec.ts +PASS core packages/core/src/lib/formatters.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/tracking.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-execute-order.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/classify.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/normalize-address.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/budget.spec.ts + +Test Suites: 1 skipped, 115 passed, 115 of 116 total +Tests: 12 skipped, 1975 passed, 1987 total +Snapshots: 0 total +Time: 26.399 s, estimated 38 s +Ran all test suites. diff --git a/plan/agw/research/sdk-hardening-2026-10-06/node20/local-contracts.log b/plan/agw/research/sdk-hardening-2026-10-06/node20/local-contracts.log new file mode 100644 index 00000000..c66392fd --- /dev/null +++ b/plan/agw/research/sdk-hardening-2026-10-06/node20/local-contracts.log @@ -0,0 +1,28 @@ +PASS core-agw-local packages/core/__agw-local__/svm-backend.spec.ts (10.541 s) +PASS core-agw-local packages/core/__agw-local__/v4-multiasset.spec.ts +PASS core-agw-local packages/core/__agw-local__/agw-local-advanced.spec.ts +PASS core-agw-local packages/core/__agw-local__/svm-differential.spec.ts + ● Console + + console.log + {"corpus":"svm-grant","seed":23063,"cases":107,"accepted":38,"rejected":69,"mismatches":[]} + + at Object. (__agw-local__/svm-differential.spec.ts:224:13) + + console.log + {"corpus":"svm-payload","seed":23063,"cases":88,"accepted":6,"rejected":82,"mismatches":[]} + + at Object. (__agw-local__/svm-differential.spec.ts:405:13) + +PASS core-agw-local packages/core/__agw-local__/delayed-index.spec.ts +PASS core-agw-local packages/core/__agw-local__/agw-local.spec.ts +PASS core-agw-local packages/core/__agw-local__/agw-local-batch.spec.ts +PASS core-agw-local packages/core/__agw-local__/vectors.spec.ts +PASS core-agw-local packages/core/__agw-local__/svm-internals.spec.ts +PASS core-agw-local packages/core/__agw-local__/agw-local-races.spec.ts + +Test Suites: 10 passed, 10 total +Tests: 75 passed, 75 total +Snapshots: 0 total +Time: 29.867 s, estimated 35 s +Ran all test suites. diff --git a/plan/agw/research/sdk-hardening-2026-10-06/node20/package.log b/plan/agw/research/sdk-hardening-2026-10-06/node20/package.log new file mode 100644 index 00000000..8e1b97e4 --- /dev/null +++ b/plan/agw/research/sdk-hardening-2026-10-06/node20/package.log @@ -0,0 +1 @@ +AGW package: CJS/ESM imports, compiled declaration examples and npm contents pass. No examples executed/published. diff --git a/plan/agw/research/sdk-hardening-2026-10-06/node20/prepare-contracts.log b/plan/agw/research/sdk-hardening-2026-10-06/node20/prepare-contracts.log new file mode 100644 index 00000000..626bb23a --- /dev/null +++ b/plan/agw/research/sdk-hardening-2026-10-06/node20/prepare-contracts.log @@ -0,0 +1 @@ +/var/folders/4_/d47r2_4s1wb3x2dvmt2ghp800000gp/T//push-agw-local-v4 diff --git a/plan/agw/research/sdk-hardening-2026-10-06/node20/public-api.log b/plan/agw/research/sdk-hardening-2026-10-06/node20/public-api.log new file mode 100644 index 00000000..ec908eca --- /dev/null +++ b/plan/agw/research/sdk-hardening-2026-10-06/node20/public-api.log @@ -0,0 +1 @@ +{"compiledMatchesSource":true,"addedExports":[],"removedExports":[],"changedAgwTypes":["AgenticError","AGENTIC_ERROR_CODE","AllowedCall"],"publicTypeChanges":["AGENTIC_ERROR_CODE","AgenticError","AgenticErrorCode","AgenticNetworkConstants","AllowedCall"],"transactionMethodChanges":[],"instanceMethodChanges":[],"initializeSignatureChanged":false,"agwConstantsChanged":true} diff --git a/plan/agw/research/sdk-hardening-2026-10-06/node20/types-agw-local.log b/plan/agw/research/sdk-hardening-2026-10-06/node20/types-agw-local.log new file mode 100644 index 00000000..e69de29b diff --git a/plan/agw/research/sdk-hardening-2026-10-06/node20/types-lib.log b/plan/agw/research/sdk-hardening-2026-10-06/node20/types-lib.log new file mode 100644 index 00000000..e69de29b diff --git a/plan/agw/research/sdk-hardening-2026-10-06/node20/types-spec.log b/plan/agw/research/sdk-hardening-2026-10-06/node20/types-spec.log new file mode 100644 index 00000000..e69de29b diff --git a/plan/agw/research/sdk-hardening-2026-10-06/node20/units.log b/plan/agw/research/sdk-hardening-2026-10-06/node20/units.log new file mode 100644 index 00000000..375cc743 --- /dev/null +++ b/plan/agw/research/sdk-hardening-2026-10-06/node20/units.log @@ -0,0 +1,23 @@ +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-confirmation-gate.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/send.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-svm-confirmation.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/resolve.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/management.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-backend.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/response-surface.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/build-payload.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/reads-context.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/codec.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/registry.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/ix-encoder.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/normalize-address.spec.ts + +Test Suites: 17 passed, 17 total +Tests: 254 passed, 254 total +Snapshots: 0 total +Time: 4.769 s +Ran all test suites matching /agentic|outbound-(confirmation-gate|svm-confirmation)|svm-idl/i. diff --git a/plan/agw/research/sdk-hardening-2026-10-06/node20/verification.log b/plan/agw/research/sdk-hardening-2026-10-06/node20/verification.log new file mode 100644 index 00000000..baec7036 --- /dev/null +++ b/plan/agw/research/sdk-hardening-2026-10-06/node20/verification.log @@ -0,0 +1,11 @@ +AGW validation: units +AGW validation: types-lib +AGW validation: types-spec +AGW validation: types-agw-local +AGW validation: docs +AGW validation: prepare-contracts +AGW validation: local-contracts +AGW validation: build +AGW validation: package +AGW validation: public-api +AGW unfunded validation completed. diff --git a/plan/agw/research/sdk-hardening-2026-10-06/node20/version.log b/plan/agw/research/sdk-hardening-2026-10-06/node20/version.log new file mode 100644 index 00000000..8407009b --- /dev/null +++ b/plan/agw/research/sdk-hardening-2026-10-06/node20/version.log @@ -0,0 +1 @@ +{"version":"v20.19.2","major":20,"platform":"darwin","arch":"arm64"} diff --git a/plan/agw/research/sdk-hardening-2026-10-06/node24/build.log b/plan/agw/research/sdk-hardening-2026-10-06/node24/build.log new file mode 100644 index 00000000..a7ae5c2f --- /dev/null +++ b/plan/agw/research/sdk-hardening-2026-10-06/node24/build.log @@ -0,0 +1,13 @@ + +> nx run core:build + +Compiling TypeScript files for project "core"... +Done compiling TypeScript files for project "core". + + + + NX Successfully ran target build for project core + + +(node:44042) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. +(Use `node --trace-warnings ...` to show where the warning was created) diff --git a/plan/agw/research/sdk-hardening-2026-10-06/node24/docs.log b/plan/agw/research/sdk-hardening-2026-10-06/node24/docs.log new file mode 100644 index 00000000..5996134d --- /dev/null +++ b/plan/agw/research/sdk-hardening-2026-10-06/node24/docs.log @@ -0,0 +1 @@ +AGW guide: 7 TypeScript blocks typechecked against public exports; no examples executed. diff --git a/plan/agw/research/sdk-hardening-2026-10-06/node24/full-unit.log b/plan/agw/research/sdk-hardening-2026-10-06/node24/full-unit.log new file mode 100644 index 00000000..951289e2 --- /dev/null +++ b/plan/agw/research/sdk-hardening-2026-10-06/node24/full-unit.log @@ -0,0 +1,168 @@ +PASS core packages/core/src/lib/universal/account/account.spec.ts + ● Console + + console.warn + [PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead. + + 207 | ): Promise { + 208 | if (!_convertOriginToExecutorWarned) { + > 209 | console.warn( + | ^ + 210 | '[PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead.' + 211 | ); + 212 | _convertOriginToExecutorWarned = true; + + at Object.convertOriginToExecutor (src/lib/universal/account/account.ts:209:13) + at Object. (src/lib/universal/account/account.spec.ts:80:52) + + console.warn + [PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead. + + 425 | ): Promise { + 426 | if (!options?._internal && !_convertExecutorToOriginWarned) { + > 427 | console.warn( + | ^ + 428 | '[PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead.' + 429 | ); + 430 | _convertExecutorToOriginWarned = true; + + at convertExecutorToOrigin (src/lib/universal/account/account.ts:427:13) + at Object. (src/lib/universal/account/account.spec.ts:106:38) + +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-confirmation-gate.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/block-results-client.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-tx-retry.spec.ts +PASS core packages/core/src/lib/push-client/push-client.archive-fallback.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r2-outbound-revert-flow.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-timeout-clamp.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/read-tx-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/inbound-tracker-derivation.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/signing-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/payload-builders.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-detector.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/export.spec.ts +PASS core packages/core/src/lib/utils.spec.ts + ● Console + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:973:17) + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:977:17) + + console.log + 1.23 + + at Object. (src/lib/utils.spec.ts:982:17) + +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/source-hash-resolution.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-svm-confirmation.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-svm-r3.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-classification.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r2-spec-strings.spec.ts +PASS core packages/core/src/lib/universal/signer/signer.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-usd-sizer.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/response-surface.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r1-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-event-hook-bridge.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-svm-rent.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/registry.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-composition.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm-rent-pc20.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/web2-compat.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-tracker.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/response-invariant.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/send.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/multichain-hooks.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/management.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/scenarios.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/context-helpers-tracker.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/build-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/gate.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-executor.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/send-transaction-progress-hook.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/rescue-svm-confirmation.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gateway-uea-account.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/execute-standard-required-funds.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-backend.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/resolver.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/chain-namespace.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/cascade.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-builder-progress-hook.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/terminal-suppression.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/resolve.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/track-transaction-guard.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-emission.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r3-spec-strings.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/funds-only-burn-guard.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-multichain.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/svm-rent.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/inbound-payload.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-evm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/public-surface.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-native-multicall.spec.ts +PASS core packages/core/src/lib/push-client/push-client.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/account-status.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-evm-r3-native-eoa.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/response-builder-push-revert.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-request-recipient.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-calculator.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/svm-account.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/spec-builder.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/address-codec.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-params.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/revalidate-read.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/result-decoder.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm-log-index.spec.ts +PASS core packages/core/src/lib/constants/__tests__/token-constants.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-svm.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/codec.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/child-inbounds.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/reads-context.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/normalize.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.chain-symbol.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/abi-selectors.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/__tests__/signing.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/auto-detect.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg-svm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/ucallback-codec.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/validate.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-events.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-web2.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/ix-encoder.spec.ts +PASS core packages/core/src/lib/constants/__tests__/svm-gateway-idl.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.dynamic-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/registry.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-types.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/error-decoder.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/normalize-address.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/classify.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-execute-order.spec.ts +PASS core packages/core/src/lib/formatters.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/tracking.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/budget.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/max-pc-for-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/errors.spec.ts + +Test Suites: 1 skipped, 115 passed, 115 of 116 total +Tests: 12 skipped, 1975 passed, 1987 total +Snapshots: 0 total +Time: 22.365 s, estimated 25 s +Ran all test suites. diff --git a/plan/agw/research/sdk-hardening-2026-10-06/node24/local-contracts.log b/plan/agw/research/sdk-hardening-2026-10-06/node24/local-contracts.log new file mode 100644 index 00000000..94d08296 --- /dev/null +++ b/plan/agw/research/sdk-hardening-2026-10-06/node24/local-contracts.log @@ -0,0 +1,28 @@ +PASS core-agw-local packages/core/__agw-local__/svm-backend.spec.ts (9.619 s) +PASS core-agw-local packages/core/__agw-local__/v4-multiasset.spec.ts +PASS core-agw-local packages/core/__agw-local__/agw-local-advanced.spec.ts +PASS core-agw-local packages/core/__agw-local__/svm-differential.spec.ts + ● Console + + console.log + {"corpus":"svm-grant","seed":23063,"cases":107,"accepted":38,"rejected":69,"mismatches":[]} + + at Object. (__agw-local__/svm-differential.spec.ts:224:13) + + console.log + {"corpus":"svm-payload","seed":23063,"cases":88,"accepted":6,"rejected":82,"mismatches":[]} + + at Object. (__agw-local__/svm-differential.spec.ts:405:13) + +PASS core-agw-local packages/core/__agw-local__/agw-local-batch.spec.ts +PASS core-agw-local packages/core/__agw-local__/agw-local-races.spec.ts +PASS core-agw-local packages/core/__agw-local__/agw-local.spec.ts +PASS core-agw-local packages/core/__agw-local__/svm-internals.spec.ts +PASS core-agw-local packages/core/__agw-local__/vectors.spec.ts +PASS core-agw-local packages/core/__agw-local__/delayed-index.spec.ts + +Test Suites: 10 passed, 10 total +Tests: 75 passed, 75 total +Snapshots: 0 total +Time: 24.855 s, estimated 30 s +Ran all test suites. diff --git a/plan/agw/research/sdk-hardening-2026-10-06/node24/package.log b/plan/agw/research/sdk-hardening-2026-10-06/node24/package.log new file mode 100644 index 00000000..8e1b97e4 --- /dev/null +++ b/plan/agw/research/sdk-hardening-2026-10-06/node24/package.log @@ -0,0 +1 @@ +AGW package: CJS/ESM imports, compiled declaration examples and npm contents pass. No examples executed/published. diff --git a/plan/agw/research/sdk-hardening-2026-10-06/node24/prepare-contracts.log b/plan/agw/research/sdk-hardening-2026-10-06/node24/prepare-contracts.log new file mode 100644 index 00000000..626bb23a --- /dev/null +++ b/plan/agw/research/sdk-hardening-2026-10-06/node24/prepare-contracts.log @@ -0,0 +1 @@ +/var/folders/4_/d47r2_4s1wb3x2dvmt2ghp800000gp/T//push-agw-local-v4 diff --git a/plan/agw/research/sdk-hardening-2026-10-06/node24/public-api.log b/plan/agw/research/sdk-hardening-2026-10-06/node24/public-api.log new file mode 100644 index 00000000..ec908eca --- /dev/null +++ b/plan/agw/research/sdk-hardening-2026-10-06/node24/public-api.log @@ -0,0 +1 @@ +{"compiledMatchesSource":true,"addedExports":[],"removedExports":[],"changedAgwTypes":["AgenticError","AGENTIC_ERROR_CODE","AllowedCall"],"publicTypeChanges":["AGENTIC_ERROR_CODE","AgenticError","AgenticErrorCode","AgenticNetworkConstants","AllowedCall"],"transactionMethodChanges":[],"instanceMethodChanges":[],"initializeSignatureChanged":false,"agwConstantsChanged":true} diff --git a/plan/agw/research/sdk-hardening-2026-10-06/node24/types-agw-local.log b/plan/agw/research/sdk-hardening-2026-10-06/node24/types-agw-local.log new file mode 100644 index 00000000..e69de29b diff --git a/plan/agw/research/sdk-hardening-2026-10-06/node24/types-lib.log b/plan/agw/research/sdk-hardening-2026-10-06/node24/types-lib.log new file mode 100644 index 00000000..e69de29b diff --git a/plan/agw/research/sdk-hardening-2026-10-06/node24/types-spec.log b/plan/agw/research/sdk-hardening-2026-10-06/node24/types-spec.log new file mode 100644 index 00000000..e69de29b diff --git a/plan/agw/research/sdk-hardening-2026-10-06/node24/units.log b/plan/agw/research/sdk-hardening-2026-10-06/node24/units.log new file mode 100644 index 00000000..62fbe838 --- /dev/null +++ b/plan/agw/research/sdk-hardening-2026-10-06/node24/units.log @@ -0,0 +1,23 @@ +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-confirmation-gate.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-svm-confirmation.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/resolve.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/management.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/send.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-backend.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/response-surface.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/build-payload.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/codec.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/registry.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/reads-context.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/ix-encoder.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/normalize-address.spec.ts + +Test Suites: 17 passed, 17 total +Tests: 254 passed, 254 total +Snapshots: 0 total +Time: 4.22 s +Ran all test suites matching /agentic|outbound-(confirmation-gate|svm-confirmation)|svm-idl/i. diff --git a/plan/agw/research/sdk-hardening-2026-10-06/node24/verification.log b/plan/agw/research/sdk-hardening-2026-10-06/node24/verification.log new file mode 100644 index 00000000..baec7036 --- /dev/null +++ b/plan/agw/research/sdk-hardening-2026-10-06/node24/verification.log @@ -0,0 +1,11 @@ +AGW validation: units +AGW validation: types-lib +AGW validation: types-spec +AGW validation: types-agw-local +AGW validation: docs +AGW validation: prepare-contracts +AGW validation: local-contracts +AGW validation: build +AGW validation: package +AGW validation: public-api +AGW unfunded validation completed. diff --git a/plan/agw/research/sdk-hardening-2026-10-06/node24/version.log b/plan/agw/research/sdk-hardening-2026-10-06/node24/version.log new file mode 100644 index 00000000..8b26aafb --- /dev/null +++ b/plan/agw/research/sdk-hardening-2026-10-06/node24/version.log @@ -0,0 +1 @@ +{"version":"v24.14.0","major":24,"platform":"darwin","arch":"arm64"} diff --git a/plan/agw/research/sdk-hardening-2026-10-06/runtime-results.json b/plan/agw/research/sdk-hardening-2026-10-06/runtime-results.json new file mode 100644 index 00000000..60c94d59 --- /dev/null +++ b/plan/agw/research/sdk-hardening-2026-10-06/runtime-results.json @@ -0,0 +1,21 @@ +{ + "results": [ + { + "version": "v20.19.2", + "major": 20, + "platform": "darwin", + "arch": "arm64", + "passed": true + }, + { + "version": "v24.14.0", + "major": 24, + "platform": "darwin", + "arch": "arm64", + "passed": true + } + ], + "hostedCi": false, + "published": false, + "fundedE2Es": false +} From fc5ab8effd7c8eb022b472751c468040ec293c62 Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Tue, 6 Oct 2026 12:31:15 +0530 Subject: [PATCH 24/68] docs(agw): recheck sources and narrow remaining team questions --- plan/agw/README.md | 4 +- plan/agw/SOURCES.md | 2 + plan/agw/current-baseline.md | 12 +- plan/agw/external-blockers.md | 16 ++- plan/agw/gaps.md | 11 +- plan/agw/questions-harsh.md | 42 ++++-- plan/agw/questions-zaryab.md | 21 +-- .../README.md | 59 +++++++++ .../evidence.json | 125 ++++++++++++++++++ 9 files changed, 251 insertions(+), 41 deletions(-) create mode 100644 plan/agw/research/question-source-recheck-2026-10-06/README.md create mode 100644 plan/agw/research/question-source-recheck-2026-10-06/evidence.json diff --git a/plan/agw/README.md b/plan/agw/README.md index 5a291d1f..a3b438bc 100644 --- a/plan/agw/README.md +++ b/plan/agw/README.md @@ -14,6 +14,8 @@ Latest: [all nine SDK-owned items completed](research/sdk-independent-completion Latest validation: [selected differential/race/API/runtime hardening](research/sdk-hardening-2026-10-06/README.md). Both Node 20/24 pass; existing live E2E receipts are independently rechecked. +Before sharing: [October 6 question source recheck](research/question-source-recheck-2026-10-06/README.md) confirms unchanged contract heads and re-inspects live pages 1/5 and All discussions. Drafts now ask only remaining public/release decisions; the Solana fixture is explicitly optional, and internal wire-level validation can proceed independently. + ## Start here | Document | Purpose | @@ -31,7 +33,7 @@ Latest validation: [selected differential/race/API/runtime hardening](research/s | [Integrator obligations](contract-integrator-obligations.md) | Contract-delegated SDK/product requirements | | [External blockers](external-blockers.md) | Remaining defaults/type clarification and contract/deployment dependencies | | [Questions for Harsh](questions-harsh.md) | Product decisions and recommendations | -| [Questions for Zaryab](questions-zaryab.md) | Ref/label v1 scope and representative SVM integration fixtures | +| [Questions for Zaryab](questions-zaryab.md) | Ref/label v1 scope, joint Solana review and optional integration fixture | | [Review summary](review-summary.md) | Consequential independent-review corrections | ## Sources and evidence diff --git a/plan/agw/SOURCES.md b/plan/agw/SOURCES.md index bbe04118..e112cdf8 100644 --- a/plan/agw/SOURCES.md +++ b/plan/agw/SOURCES.md @@ -8,6 +8,8 @@ Focused October 4 recheck: page 5 was downloaded again; its body matches the sav Focused October 5 comment review: live All discussions on pages 5 and 1, plus the overview’s visible page state, were inspected through Chrome. [Comment evidence and SDK impact](research/notion-comments-2026-10-05.md). Harsh’s new multiple-rules direction needs same-agent scope/send-selection clarification; token-independence wording needs a final definition. This was not a body export or contract refresh. Comments are recorded separately; snapshot hashes/pull timestamps remain unchanged. +October 6 pre-sharing source recheck: all twelve saved Notion sources and relevant contract/SDK/sibling documents were searched; live pages 1/5 and All discussions were inspected again. All eight AGW remote branch heads were fetched; deploy-agw remains 10a24f1 and pushAgenticWallet_v3 remains e8db748. [Evidence and narrowed questions](research/question-source-recheck-2026-10-06/README.md). Same-agent capacity is now supplied; send selection remains open. Public Solana representation needs joint review, while a representative fixture is optional. No full Notion export, sibling fetch, new live deployment probe or snapshot hash change is claimed by this pass. + ## Notion inventory | Document | Source | Local snapshot | Authority | diff --git a/plan/agw/current-baseline.md b/plan/agw/current-baseline.md index 8b538a1f..df8a2691 100644 --- a/plan/agw/current-baseline.md +++ b/plan/agw/current-baseline.md @@ -13,7 +13,7 @@ The public SDK target remains Notion page 5, qualified by Harsh's later replies/ | SDK contract adapter | V4 only (e8db748); Donut registry populated; old runtime/test generation removed | | Core marketplace | Prior pin cb69e0ba101bef1bb4440e54b2c45396be3e92ce; not freshly fetched | | Gateway source | Prior eight-field pin bcbf7df42e8e6dd11088a43bcc0b056a54ea0a18; live implementation slot checked | -| Notion | Last full export October 3 at 13:23 IST; focused October 4 body comparison and October 5 comment review; no new export here | +| Notion | Last full export October 3 at 13:23 IST; October 4 body comparison, October 5 comments, October 6 live pages 1/5 and All discussions inspection; no new export | [Saved GitHub sources and hashes](research/deployment-review-2026-10-06/source-manifest.json) are separate from the Notion manifest. [Verified ABIs](research/deployment-review-2026-10-06/abis/) came from the explorer. This review did not locally rebuild runtime bytecode or rerun the full contract/SDK suites. @@ -47,9 +47,9 @@ The earlier supplied historical addresses are superseded for new v4 integrations | Internal replacement guard | assertSpent(configId,wallet,uint256[]) compares all totals in asset order | SDK implemented; second-token intervening spend rolls back replacement | | Native terms | Same body layout, one config per action; envelope changed | V4 native tests pass; ABI offset validation retained | | Multiple rules | Several same-agent/same-chain grants supported | Management permits multiplicity; ambiguous sends fail; H6 selection remains | -| Checkpoints | Stored count/last block, three event kinds, per-owner-call/lifecycle ticks | Earlier read/update design retained; v4 acceptance pending | +| Checkpoints | Stored count/last block, three event kinds, per-owner-call/lifecycle ticks | Local and registered live native/EVM lifecycle acceptance pass | | Grant ref / label | Grant has no ref; label is deployment event only; no setLabel | Explicit capability gates; Z1.3 asks v1 scope/delivery | -| SVM | Full multi-asset terms/program/account/data pins supplied | Public mapping, PDA/ATA/registry resolution, payload and acceptance remain | +| SVM | Full multi-asset terms/program/account/data pins supplied | Internal reads, PDA/ATA/metadata/IDL resolution, lifecycle and outbound backend complete; public mapping/dispatch and live destination acceptance remain | | Gateway request | Eight-field live implementation, selector 0x77b86bec | Dedicated context, listed-token choice and maxGasPerCall implemented | | Allowance | Consume separate owner-established allowance | Keep existing race-safe behavior; Live allowance/token debit passes; remaining identity coverage explicit | | Refund spend credit | creditRevert gains token; executor still does not call it | Known Push-core dependency; ordinary returns do not lower spent | @@ -65,9 +65,11 @@ The unrestricted run passes 1,975 unit and 75 actual-contract tests. All five ex ## Remaining decisions and acceptance -- Harsh: native omission defaults/public maxValueTotal, raw-offset authoring/read model, multi-rule send selection. [Open draft](questions-harsh.md). -- Zaryab: ref/label v1 scope and representative SVM integration fixtures. Wire/accounting/deployment delivery requests are removed. [Open draft](questions-zaryab.md). +- Harsh: native PC omission defaults/token intent, raw-offset authoring/read model, multi-rule send selection and joint public Solana representation. Current target retains maxValueTotal. [Open draft](questions-harsh.md). +- Zaryab: ref/label v1 scope, joint Solana SDK review and optional representative SVM fixture. Wire/accounting/deployment delivery requests are removed. [Open draft](questions-zaryab.md). - SDK: native/EVM migration is implemented and locally validated. Public SVM mapping/composition and release scope decisions remain. No legacy runtime adapter is retained. - Live: registered native/EVM/UEA/7702 and Sepolia success/failure scenarios pass, including independent CEA execution attribution. Public SVM destination acceptance remains after integration. Authorized testnet transactions are recorded in the live report. Checkpoint count semantics remain per action, not per transaction: assert/revoke/grant adds five ticks; failed transactions unwind ticks; agent calls do not tick. Pre-existing allowances may change balances without checkpoints. Preserve internal spend assertions even though public spent records are removed. + +The [question source recheck](research/question-source-recheck-2026-10-06/README.md) freshly confirms unchanged deploy-agw/pushAgenticWallet_v3 heads. It records answered definitions separately from remaining public decisions and SDK-owned fixture validation; it does not claim a fresh live bytecode probe. diff --git a/plan/agw/external-blockers.md b/plan/agw/external-blockers.md index 45c224a0..3680d360 100644 --- a/plan/agw/external-blockers.md +++ b/plan/agw/external-blockers.md @@ -1,16 +1,18 @@ # Remaining external dependencies for AGW -Updated October 6, 2026 after the [v4 deployment and owner-guide review](research/deployment-review-2026-10-06/README.md). Contract wire/accounting definitions and deployment addresses are supplied; distinguish remaining decisions from SDK implementation and live acceptance. +Rechecked October 6, 2026 against live Notion pages 1/5 and All discussions, all saved sources, freshly fetched contract refs and SDK code. [Question dispositions and evidence](research/question-source-recheck-2026-10-06/README.md). Contract wire/accounting definitions and deployment addresses are supplied; distinguish remaining decisions from SDK implementation and live acceptance. ## Remaining team input | Area | Owner | Remaining answer | | --- | --- | --- | -| Native optional-input defaults/public fields | Harsh H3 | Native value omission defaults, referenced public maxValueTotal change, confirmation of remaining omission rows and token-independence wording | -| Native decoded-rule representation | Harsh H4.5 | Public raw-offset read/write authoring versus separate decoded/internal form | +| Native PC optional-input defaults/token intent | Harsh H3 | Exact omitted maxValuePerCall/maxValueTotal behavior and whether token-independence requests a public-model change; current target retains maxValueTotal | +| Public Solana representation | Harsh H4.4 with Zaryab | Solana-specific authoring/read shape, explicit program/account/data constraints versus higher-level IDL inputs; wire structs are supplied | +| Decoded-rule representation | Harsh H4.5 | Public native/EVM raw-offset authoring versus separate decoded records | | Multiple-rule execution | Harsh H6 | Explicit caller rule selection versus a defined automatic strategy, including arrays/overlapping rules; same-agent capacity is supplied | | Metadata scope | Zaryab Z1.3 with Harsh | Whether absent grant ref/editable label will be delivered or explicitly deferred from v1 | -| Representative SVM integration fixture | Zaryab Z1.4, where available | Cluster gateway/registry and protected-account derivation inputs, valid envelope/outbound example and expected failure cases | + +Zaryab Z1.4 is an **optional fixture request**, not a hard dependency. The SDK already has a candidate devnet gateway and counter-program IDL. We can verify their current deployment/compatibility read-only and prepare a bounded wire-level test ourselves. A known-good team fixture would improve independent comparison; this review does not claim those candidate inputs have passed live AGW delivery. The owner guide retains assets[] on the rule, with each listed token usable by every allowed call. Harsh's token-independence comment is not treated as permission to remove token limits. SVM wire types are supplied; the remaining fixture request does not reopen struct delivery. @@ -22,7 +24,7 @@ The owner guide retains assets[] on the rule, with each listed token usable by e - Multiple same-agent/same-chain rules: contract guide explicitly permits them; product accepts multiplicity. Choosing the rule for a send remains H6. - Separate owner allowance, immutable-wallet generations, internal accounting and sender-preserving native batching: preserve the existing design while migrating to v4. -Native/EVM v4 migration is now implemented: adapter/registry, envelopes, multi-asset reads/codecs, ordered assertions, outbound token choice and ABI integration. The actual-contract harness is ported; runtime/test legacy artifacts were removed. [Current evidence](research/v4-implementation-2026-10-06/README.md). SVM SDK mapping/composition and live acceptance remain. +Native/EVM v4 migration and the internal SVM read/context/instruction/lifecycle/execution backend are implemented. The actual-contract harness is ported; runtime/test legacy artifacts were removed. [Backend evidence](research/sdk-independent-completion-2026-10-06/README.md). Public SVM adapters/presentation and live destination acceptance remain SDK work after agreeing the public model; internal wire-level validation can proceed independently. ## Previously settled scope @@ -36,9 +38,9 @@ All 25 registered AGW live scenarios have passing bounded selected-run coverage, ## Freshness -AGW deployment source e8db748; documentation head deploy-agw@10a24f1, with identical src. Explorer-verified ABIs and a pinned RPC probe are saved in the [review bundle](research/deployment-review-2026-10-06/README.md). The native/EVM migration was rebuilt and validated: 1,947 unit tests, 25 distinct registered live scenarios and the expanded actual-contract suite pass. See the current validation report. Core/gateway source pins were not refreshed. +Fresh fetch confirms AGW source e8db748 and documentation head deploy-agw@10a24f1, with identical src. Explorer-verified ABIs and the earlier pinned RPC probe are saved in the [review bundle](research/deployment-review-2026-10-06/README.md); no new deployment probe in this question pass. Current evidence is 1,975 unit tests, 75 actual-contract tests and 25 registered live scenarios with passing selected-run coverage. [Validation](research/sdk-hardening-2026-10-06/README.md). Core/gateway source pins were not refreshed. -Notion's last full export remains October 3, with focused October 4 body and October 5 comment checks. The GitHub guide is a separate deployed-wire source, not a silent replacement for the target public SDK API. +Notion's last full export remains October 3, with October 4 body comparison, October 5 comments and a fresh October 6 live inspection of pages 1/5 and All discussions. The GitHub guide supplies deployed wire behavior; the target public API remains qualified by Harsh's replies. ## SVM foundation and current execution environment diff --git a/plan/agw/gaps.md b/plan/agw/gaps.md index 5de643d5..0109c97d 100644 --- a/plan/agw/gaps.md +++ b/plan/agw/gaps.md @@ -10,10 +10,13 @@ Current contract baseline: reported deployed source `e8db748`, documentation hea | Dependency | Owner | Related IDs | | --- | --- | --- | -| Remaining native omission defaults/public maxValueTotal and token wording | [Harsh H3](questions-harsh.md#h3) | G19 | +| Native PC omission defaults and token wording; current target retains maxValueTotal | [Harsh H3](questions-harsh.md#h3) | G19 | +| Public Solana authoring/read model; wire/backend supplied | [Harsh H4.4 with Zaryab](questions-harsh.md#h4-4) | G22 | | Public raw-offset read/write representation | [Harsh H4.5](questions-harsh.md#h4-5) | G25 | | Multiple-rule send selection (same-agent capacity is supplied) | [Harsh H6](questions-harsh.md#h6) | G26 | -| V1 ref/label scope and representative SVM integration fixtures | [Zaryab Z1](questions-zaryab.md#z1) | G08, G22 | +| V1 ref/label scope | [Zaryab Z1.3 with Harsh](questions-zaryab.md#z1-3) | G08 | + +The [October 6 source recheck](research/question-source-recheck-2026-10-06/README.md) narrows the questions above. Z1.4's Solana fixture is optional supporting evidence; checking existing SDK gateway/IDL candidates and running an internal wire-level test are SDK-owned work, not blocked on receiving that fixture. Multi-asset wire/read/assertion ABI, EVM CEA width, envelope version and SVM wire layouts are now supplied. G23/G24 and the native/EVM adapter/registry migration are implemented locally; SVM mapping/live acceptance remain SDK work; do not keep asking for those delivered definitions. @@ -43,10 +46,10 @@ P0 blocks agreed authorization/accounting or safe final integration. P1 affects | G16 | P1 | Implemented; migration documentation supplied | READ.CHAIN.WEB2 is web2. Legacy web2:https input is normalized to unchanged wire identity. Deprecated aliases now use the new public value. | The consumer guide documents the alias/literal migration; Web2 normalization/read-source tests pass. | | G17 | P1 | SDK decision implemented locally | Read-only write guards and explicit agenticWallet selection on reinitialize are implemented. Signer/network/wallet changes rebuild role/capability context. | Preserve compatibility coverage and verify with the release deployment. | | G18 | P1 | SDK behavior implemented locally; selection under review | Initialization uses enabled-rule identity; sends perform uncached lookup without expiry filtering. Missing/ambiguous candidates fail before signing. Public list is enabled-only; unknown/revoked get returns RULE_NOT_FOUND. The October 5 multiple-rules comment may change selection/cardinality assumptions. | Resolve G26 before treating uniqueness/ambiguous-candidate behavior as final. Verify final-generation and live permission-change cases; public history is deferred. | -| G19 | P0/P1 | Universal defaults implemented; H3 native choices open | Universal omission uses maxUint256 and explicit zero is hard zero; empty input gets a gas-token 0/0 route. Native defaults remain provisional. | Clarify H3 native/public fields and token wording; retain UI-owned approval policy. | +| G19 | P0/P1 | Universal defaults implemented; H3 native PC choices open | Universal omission uses maxUint256 and explicit zero is hard zero; empty input gets a gas-token 0/0 route. Native PC omission remains provisional at 0. Current live NativeRule retains maxValueTotal; wire sentinel meanings are supplied. | Confirm omitted native PC limits and intended token model; preserve the current field unless an explicit revision is supplied. | | G20 | P1 | V4 composer/response and live EVM acceptance pass | Uses selected listed token, maxGasPerCall, wallet CEA/refund context, separate allowance and signer gas. Local requests pass actual URP with fixture gateway. | Production token debit, node/TSS delivery, CEA execution attribution/balance, replay identity and destination-revert classification pass. Public SVM integration remains tracked under G22. | | G21 | P1 | Product direction resolved; batching implemented locally | NativeRule remains one action. Arrays use a sender-preserving UEA/7702 outer batch of single executeAsAgent calls, each checked by policy. Native sequential fallback is prohibited. Local real-type-4 tests prove sender identity, cumulative counters and mined rollback. | Release-deployment UEA identities and native 7702 batch/rollback cases pass. The local executor is a fixture; arbitrary forwarding helpers are not a substitute for the agent account. | -| G22 | P1 | SVM backend completed; public integration pending | Internal read/context/mint/IDL/lifecycle/execution pipeline is complete. New unit and actual-contract backend tests pass; shared Solana confirmation supports indexer lag. Public capability remains gated. | Agree public authoring/read/display mapping, connect public adapters to the completed backend, enable capability and run live Solana acceptance with confirmed cluster inputs. | +| G22 | P1 | SVM backend completed; public integration pending | Internal read/context/mint/IDL/lifecycle/execution pipeline is complete. New unit and actual-contract backend tests pass; shared Solana confirmation supports indexer lag. Public capability remains gated. SDK gateway/IDL candidates exist; an external fixture is optional. | H4.4: agree public authoring/read mapping and connect adapters. Independently verify cluster/program inputs and run a wire-level test; then enable the agreed public surface and run public Solana acceptance. | | G23 | P0 | V4 EVM integration verified locally and live | Multi-asset codecs/reads/outbound, envelope 1, source chain/token identity, hard-zero semantics and empty-input routing are implemented. Old adapter/ABIs/fixtures removed. | Registered EVM acceptance passes. Public SVM SDK mapping/composition remains. | | G24 | P1 | Internal per-token update verified locally and live | Reads/stores every expected counter in asset order; array assertion catches intervening second-token spend. Public spent stays absent. | Live two-asset replacement passes; public SVM integration remains. | | G25 | P1 | Public raw-offset decision open | Exact native pin/amount offsets and EVM beneficiaryOffset are returned/accepted losslessly; no invented argument indexes. This extends the target input shape. | H4.5: public raw authoring versus separate decoded wire records. | diff --git a/plan/agw/questions-harsh.md b/plan/agw/questions-harsh.md index 3e504294..e5660531 100644 --- a/plan/agw/questions-harsh.md +++ b/plan/agw/questions-harsh.md @@ -1,40 +1,54 @@ # Remaining AGW product follow-ups for Harsh -Updated October 6, 2026 after your replies, [live Notion comment review](research/notion-comments-2026-10-05.md) and the [v4 owner guide/deployment review](research/deployment-review-2026-10-06/README.md). Accepted decisions and implementation impact are recorded in [product decisions](product-decisions-2026-10-04.md); this document contains only remaining questions. +Rechecked October 6, 2026 against all twelve saved Notion pages, your replies, live pages 1/5 and their All discussions, freshly fetched contract branches, the owner guide and SDK code. [Evidence and dispositions](research/question-source-recheck-2026-10-06/README.md). Accepted decisions remain in [product decisions](product-decisions-2026-10-04.md). No questions have been sent. | Item | Answer needed | | --- | --- | -| [H3](#h3) | Remaining native omission defaults/public maxValueTotal and token wording | -| [H4.5](#h4-5) | Raw-offset representation introduced by the SDK review fix | +| [H3](#h3) | Native PC omission defaults and the intended token model | +| [H4.4](#h4-4) | Public Solana rule representation, jointly with Zaryab | +| [H4.5](#h4-5) | Public raw-offset authoring versus separate decoded records | | [H6](#h6) | Choosing a rule for a send when several match | ## Source check -We downloaded [page 5](https://app.notion.com/p/pushprotocol/5-SDK-AGW-3e9188aea7f481cf8e8de324956549b9) again on October 4. Its exported body still matches our October 3 snapshot after link normalization, including maxValueTotal and the old public helper/Spent/compileCard entries. [Comparison evidence](research/notion-check-2026-10-04/comparison.json). We will apply your newer scope directions rather than repeat those answered questions. +The live [SDK page](https://app.notion.com/p/pushprotocol/5-SDK-AGW-3e9188aea7f481cf8e8de324956549b9) still has optional native maxValueTotal, argument-index inputs and the older unique-rule lookup wording. Its visible active/resolved discussions supply no further answer to the questions below. This was a live inspection, not a new Markdown export; the last full export remains October 3. -On October 5 we read live discussions, including resolved threads. Your new multiple-rules comment is captured under H6. The token-independence comment is included in H3 below. Neither comment provides the missing default table or answers H4.5. - -The October 6 owner guide now settles universal total encoding: omitted/no-limit maxTotal uses uint256 maximum, explicit zero forbids movement. It supplies the versioned multi-asset wire layout and confirms same-agent multiplicity. These are no longer questions below. It does not determine every public SDK omission default or the rule-selection API. +The freshly fetched [owner guide](https://github.com/pushchain/push-agentic-wallets/blob/10a24f101e2e6e0a9b76517b29f5cdb1aa967796/docs/5_SDK_Owner_Integration.md) is unchanged. It supplies universal total encoding, same-agent multiplicity and SVM wire definitions. Those delivery questions are closed. Your later scope replies continue to take precedence over older page-body helper/spend/compiler entries. -## H3 Remaining native defaults and public fields +## H3 Native PC defaults and token model The delivered contracts distinguish hard zero from uint256 maximum, keep maxValueTotal, use maxCalls=0 for unlimited calls and destination maxValue=0 for non-payable calls. We will apply the guide's universal no-total-limit encoding and preserve explicit zeros. -Please confirm the remaining public SDK choices: +**Decision needed:** should omitted native maxValuePerCall and maxValueTotal both encode uint256 maximum? Your earlier reply was tentative for the former and referred to a change to the latter. The current live NativeRule still includes maxValueTotal, so we retain that field unless you specify a replacement. + +| Optional input | Proposed omission behavior | Current SDK | +| --- | --- | --- | +| Native maxValuePerCall | uint256 maximum | 0, provisional | +| Native maxValueTotal | uint256 maximum | 0, provisional | -- Should omitted native maxValuePerCall and maxValueTotal both mean uint256 maximum? Your earlier reply was tentative for the former and said the latter had changed. -- Is maxValueTotal retained in the public NativeRule, or replaced/removed? The new owner guide still includes it on the wire. -- May we use native amount.maxTotal=uint256 maximum, maxCalls=0 and destination allowedCalls[].maxValue=0 as the omission defaults? The wire meanings are clear; this confirms the public optional-input behavior. +Explicit zero stays zero. We are not asking again what the on-chain sentinels mean. The other implemented conventions are native amount.maxTotal=uint256 maximum, maxCalls=0 and destination allowedCalls[].maxValue=0; these are context, not additional wire-format questions. Your [token-independence comment](https://app.notion.com/p/pushprotocol/5-SDK-AGW-3e9188aea7f481cf8e8de324956549b9#af9c3fac35d94f2585cb27310271c1d8) needs one scope clarification: the delivered guide keeps assets[] on the rule and allows each listed token with every allowed call. Is that the intended SDK model, or does your comment request a different public model? + + +## H4.4 Public Solana rules — jointly with Zaryab + +Your earlier reply assigned SVM work to Zaryab. The SVM contract rulebook and its wire types are now delivered; our internal reads, metadata/IDL resolution, lifecycle and outbound backend are implemented. We are not asking for contract structs again. + +**Decision needed:** agree how those constraints appear in public Rule inputs and rules.get/list results. The current live AllowedCall is EVM-shaped: address target, function selector and beneficiary argument index. It does not represent Solana programs, instruction discriminators, account pins or instruction-data pins. + +**SDK proposal for review:** add a Solana-specific Rule variant selected by its solana: chainNamespace, keep asset caps/expiry/gas fields, and expose program/instruction constraints with account/data pins. Gateway, wallet CEA and protected token-account derivation stay internal. Confirm whether callers may provide explicit constraints in this variant, or whether public authoring must use higher-level IDL/account/field inputs that the SDK compiles. The decoded result must preserve the stored constraints without inventing an IDL. + +This is a public SDK design agreement, not missing contract support. We can validate internal wire-level delivery independently. A representative fixture is optional supporting input in [Z1.4](questions-zaryab.md#z1-4). + ## H4.5 Decoded rules and raw offsets -This was added during implementation review and was not part of the earlier question set. Stored native rules contain calldata byte offsets, but do not contain the ABI needed to recover argument indexes. Returning a guessed arg index was incorrect for arrays/tuples. +This question was added during implementation review and was not covered by your earlier replies. The historical SDK document already used raw offsets; current page 5 instead uses argument indexes. Stored native rules contain byte offsets without the ABI needed to recover indexes. Returning a guessed arg index was incorrect for arrays/tuples. The current fix returns native pins as `{ offset, expected }` and amount limits with `{ offset, maxPerCall, maxTotal }`. V4 EVM allowed-call reads also return exact beneficiaryOffset because stored selectors do not include the ABI needed to recover beneficiary argument indexes. It also accepts these raw forms when granting/updating so decoded rules can round-trip without loss. @@ -54,4 +68,4 @@ Lifecycle validation is already aligned with multiple rules. The SDK reports AMB ## Supporting context -Native array implementation is now validated locally and on Donut: use sender-preserving outer UEA/7702 batching of single executeAsAgent calls, and handle unsupported atomic transports explicitly. Universal/SVM wire definitions and the deployment are supplied; Native/EVM adapter/codec work and all 25 registered live scenarios pass; public SVM destination mapping and acceptance remain. [Zaryab's draft](questions-zaryab.md) now asks only about missing metadata scope and representative SVM integration fixtures. compileCard and revoked history remain outside standalone AGW v1. +Native array implementation is validated locally and on Donut through sender-preserving UEA/7702 batching. Universal/SVM wire definitions and deployment are supplied; all 25 registered native/EVM live scenarios have passing coverage. Public SVM mapping and live destination acceptance remain. [Zaryab's draft](questions-zaryab.md) asks about metadata release scope and labels its SVM fixture request optional. compileCard and revoked history remain outside standalone AGW v1. diff --git a/plan/agw/questions-zaryab.md b/plan/agw/questions-zaryab.md index 913ed379..bba4c9a5 100644 --- a/plan/agw/questions-zaryab.md +++ b/plan/agw/questions-zaryab.md @@ -1,20 +1,21 @@ # AGW SDK remaining contract follow-ups for Zaryab -Updated October 6, 2026 after the new Donut deployment and owner integration guide. Thank you: the multi-asset terms, versioned envelope, EVM CEA width, internal per-token reads/assertion ABI and SVM wire definitions are supplied. We have checked code/wiring read-only and saved the verified ABIs. Those delivery questions have been removed. +Rechecked October 6, 2026 against all saved Notion sources, live pages 1/5 and their All discussions, freshly fetched contract branches, the owner guide and SDK code. [Evidence and dispositions](research/question-source-recheck-2026-10-06/README.md). Multi-asset terms, envelope, EVM CEA width, accounting ABI, SVM wire definitions and deployment are supplied; those questions are closed. No questions have been sent. -Only the following items remain in Z1. Please reply by sub-item with the agreed scope or fixture link. Deployment/address coordination is complete; adapter integration and funded acceptance are SDK work. +Only Z1.3 needs a contract release-scope answer. Z1.4 is optional supporting evidence, not a requirement to start our wire-level testing. The public Solana SDK representation needs joint review under [Harsh H4.4](questions-harsh.md#h4-4). Deployment/address coordination is complete; adapter integration and funded acceptance are SDK work. | Item | Remaining answer | | --- | --- | | [Z1.3](#z1-3) | Ref/label scope for this release | -| [Z1.4](#z1-4) | Representative SVM integration fixtures/registry inputs where available | +| [Z1.4](#z1-4) | Optional representative SVM integration fixture | ## Source baseline - [Owner integration guide](https://github.com/pushchain/push-agentic-wallets/blob/10a24f101e2e6e0a9b76517b29f5cdb1aa967796/docs/5_SDK_Owner_Integration.md). - [V4 address book](https://github.com/pushchain/push-agentic-wallets/blob/10a24f101e2e6e0a9b76517b29f5cdb1aa967796/docs/addresses/donut.md). - Reported deployed source e8db748; documentation head deploy-agw@10a24f1 has identical src. Donut probe block 23931055: factory/wallet/policy wiring matches, URP 3.1.0. [Evidence and remaining SDK work](research/deployment-review-2026-10-06/README.md). -- Target public API remains [page 5](notion/5-sdk-agw.md), qualified by Harsh's later replies/comments. New owner guide describes deployed wire behavior; it does not settle every public API/scope question. Notion was not re-exported in this pass. +- Fresh fetch confirms deploy-agw remains 10a24f1 and pushAgenticWallet_v3 remains e8db748; no src difference. No later branch supplies ref/setLabel. +- Target public API remains [page 5](notion/5-sdk-agw.md), qualified by Harsh's later replies/comments. Live pages 1/5 and All discussions were inspected again; no release-scope answer was visible. Notion was not re-exported in this pass. @@ -24,24 +25,24 @@ Only the following items remain in Z1. Please reply by sub-item with the agreed ### Z1.3 Ref and editable labels: delivery or v1 scope change? -The new generation still exposes grantRules(Session) without ref, and RulesGranted carries no job reference. Label is emitted by WalletDeployed only; setLabel and label storage are absent. The target SDK still promises rule ref and w.setLabel. +The generation still exposes grantRules(Session) without ref, and RulesGranted carries no job reference. Label is emitted by WalletDeployed only; setLabel is absent. Page 1 already proposes grantRules(Session, ref) and owner-only setLabel with LabelSet, without a checkpoint. We are not asking you to design that surface again. -Please confirm whether those are follow-up contract changes for this release or should be explicitly deferred from v1 with Harsh. If they are coming, provide the selected parameter/event shape when ready, including signature binding for ref on signed grants. We will keep unsupported capabilities explicit until the public scope and delivered ABI agree. +**Decision needed:** are rule ref and editable labels included in this release, or explicitly deferred from v1 with Harsh? If included, confirm that the existing page-1 proposal is still the target and announce the compatible source/ABI when ready. Signed grants must bind the ref as part of their authorized contents. We will keep absent capabilities explicit until the agreed scope and delivered ABI match. Checkpoint event ref is a rulesId/action hash; it is not the missing job ref. -### Z1.4 SVM example to validate the SDK mapping +### Z1.4 Optional SVM example to validate the SDK mapping -SvmTerms/program/account/data-pin definitions are supplied; we are not asking for those structs again. If available, please share one representative Donut-to-Solana fixture covering: +SvmTerms/program/account/data-pin definitions and PDA/ATA responsibilities are supplied. Our internal SDK backend is implemented and actual-contract tests pass. We are not asking for those definitions again. If available, please share a known-good Donut-to-Solana fixture covering: - Cluster CAIP-2 value and gateway program/registry source. - Destination CEA and protected token/output accounts, with their derivation inputs. - A valid encoded envelope and outbound payload for one allowed instruction; expected account/data-pin matches and corresponding failure cases. -We will implement SDK resolution/composition. This fixture helps verify that our PDA/ATA coverage and payload encoding match the contract/parser and actual cluster configuration. The owner guide explicitly excludes agent outbound composition; source-level SVM support alone does not prove a live destination route. +The SDK already contains a Solana-devnet gateway setting and a counter-program IDL, so we can perform read-only preflight and build a bounded wire-level test ourselves. Their current deployment/compatibility still needs verification. Your fixture would provide a useful independent comparison, not unblock missing backend work. Contract SVM tests use synthetic keys and do not prove live destination settlement. ## Product choices kept separate -[Harsh's draft](questions-harsh.md) retains native omission defaults/public fields, raw-offset authoring and multi-rule send selection. The new guide confirms that multiple rules may exist for the same agent and chain; it does not choose a sendTransaction selection API. No public multi-asset spend, revoked-history or compileCard request is reopened. +[Harsh's draft](questions-harsh.md) retains native PC defaults/token wording, raw-offset authoring, multi-rule send selection and the joint public-Solana representation decision. The new guide confirms same-agent/same-chain multiplicity; it does not choose a send selection API. No public spend, revoked-history or compileCard request is reopened. [Implementation plan](implementation-plan.md) · [External dependencies](external-blockers.md) · [Current baseline](current-baseline.md) diff --git a/plan/agw/research/question-source-recheck-2026-10-06/README.md b/plan/agw/research/question-source-recheck-2026-10-06/README.md new file mode 100644 index 00000000..4e5908a6 --- /dev/null +++ b/plan/agw/research/question-source-recheck-2026-10-06/README.md @@ -0,0 +1,59 @@ +# Remaining-question source recheck + +October 6, 2026; the evidence capture timestamp is recorded in [evidence.json](evidence.json). SDK baseline feat/agw-sdk-v4@9e9d8424. This review verifies whether our team-question drafts ask for information already supplied. It changes planning documents only; no production code, contract checkout, remote document or team message is changed. + +## Result + +The technical definitions are supplied. Four existing decision areas remain: native PC defaults/token intent, raw-offset public representation, multiple-rule send selection and ref/label release scope. The public Solana representation also needs joint SDK/product/contract review and is now explicit as H4.4. The representative SVM fixture request is optional supporting evidence, not a hard external blocker. + +The defaults and decoded-rule implementation remain provisional; this review does not approve them or silently change runtime behavior. The SDK team can prepare a concrete public Solana proposal and perform wire-level live validation while these decisions are pending. + +## Sources checked and freshness + +| Source | Inspection | +| --- | --- | +| All 12 registered Notion snapshots | Searched relevant defaults, rule selection, metadata, offsets and SVM sections. Stable inventory/hashes remain in [source-manifest](../../source-manifest.json). Marketplace/job/evaluator designs do not select standalone send rules or supply the missing public SVM input. | +| Live Notion page 5 | Opened through connected Chrome; reviewed current rules/types, agent selection, label scope and All discussions, including resolved/deleted-context threads. Native maxValueTotal remains optional; inputs remain arg-based and AllowedCall EVM-shaped. No new substantive answer beyond the recorded October 5 comments was visible. Header displayed Edited 23h ago; this is a UI observation, not a body-diff result. | +| Live Notion page 1 | Reviewed current metadata/SVM proposals and All discussions. Header displayed Edited Oct 2. Editable labels remain proposed; no release inclusion/deferral answer was visible. | +| Harsh's supplied replies | Re-read the [recorded product decisions](../../product-decisions-2026-10-04.md), preserving clear scope decisions and the tentative/default-revision wording. No Slack search or new Slack messages were accessed. | +| AGW public remote | Fetched all eight current branch heads from the explicit public repository into isolated local refs; [fetch evidence](evidence.json). deploy-agw=10a24f1 and pushAgenticWallet_v3=e8db748 are unchanged. Other heads are historical and do not supersede the delivered generation. No refs in the contract checkout were changed. | +| Current AGW docs/source/ABI | Re-read owner guide §§3–4, 9–10; design/policy docs; wallet interface/implementation; SVM tests; saved verified ABIs. deploy-agw src is identical to the reported deployment source. This pass did not re-probe live wiring or assert bytecode freshness. | +| SDK implementation/evidence | Public types, defaults, native encoder/decoder, rule selector, SVM capability gate, internal backend and actual-contract evidence. Existing local tests prove contract enforcement with a fixture gateway, not live Solana settlement. | +| Sibling core/gateway documents | Searched 11 core and 24 gateway docs in the existing checkouts for direct NativeRule/default/metadata/SVM public-schema/selection definitions. No direct answer to these product questions. These repositories were not freshly fetched; prior baseline pins remain authoritative only for earlier inspections. | + +This was not a full Notion export or a fresh inspection of every live Notion page. The last full export remains October 3; only pages 1 and 5 and their discussions were freshly inspected. No claim that all twelve live bodies are unchanged. + +## Question-by-question disposition + +| Item | What the sources already answer | What still needs agreement | Draft change | +| --- | --- | --- | --- | +| H3 limits | Owner guide §§4.3/4.5 defines uint256 maximum/zero, retains NativeTerms.maxValueTotal, maxCalls=0 unlimited, and destination maxValue=0 non-payable. Live NativeRule still retains maxValueTotal. Universal omitted total is supplied. | Exact omitted native PC limits; Harsh's reference to a changed field/default has no matching revised specification. | Removed the separate retained-field and wire-sentinel questions; asks about the two PC omission rows, preserving maxValueTotal unless an explicit revision is supplied. Other defaults are shown as SDK conventions, not newly confirmed product decisions. | +| H3 token intent | Owner guide §4.3: caps per token, each listed asset usable with every allowed call. Target page still contains assets[]. | Whether the token-independence comment requests a public-model change. | Keep one clarification; do not infer permission to remove token enforcement. | +| H4.5 offsets | Wire structs store offsets without ABI signatures. Historical SDK already used raw offsets; current public target uses arg indexes. Raw decoded values are necessary for lossless representation. | Whether raw-offset authoring is public, or decoded records are distinct from ABI-based authoring inputs. | Correct the implication that raw offsets are an invented contract feature; retain the current public API choice. | +| H6 multiplicity | Owner guide §9 explicitly allows several same-agent/same-chain rules; Harsh's comment accepts multiplicity. | Selection under overlapping rules/arrays. Current target lookup assumes uniqueness; no source defines a replacement algorithm. | Keep selection only; do not re-ask capacity or silently pick the first match. | +| Z1.3 metadata | Page 1 already proposes grant ref and setLabel/LabelSet, with labels excluded from checkpoints. Delivered IAGW has grantRules(Session) and a four-field RulesGranted event, without job ref or setLabel. | Include these in this release or defer with product. | Ask release scope and confirm the existing proposal if included; remove the broad request to redesign parameter/event shapes. | +| H4.4 public SVM | Owner guide §4.4 and Types.sol supply SvmTerms, programs, account/data pins, CEA/ATA derivation obligations. Internal SDK backend is complete. | Public authoring and decoded-record representation: current AllowedCall cannot express those constraints. | Add an explicit joint review item; this is SDK design agreement, not missing contract structs. | +| Z1.4 fixture | SDK chain constants contain a devnet gateway; a counter IDL exists. Contract SVM tests deliberately use synthetic keys. | Live program/IDL/configuration compatibility must be checked. | Mark fixture optional. Read-only preflight and a bounded internal wire test are SDK-owned work; a fixture is useful independent evidence. | + +## Exact evidence pointers + +Paths below are relative to the SDK repository; contract line numbers refer to the saved deploy-agw source whose relevant files match the freshly fetched head. + +- Public target: plan/agw/notion/5-sdk-agw.md:484 (unique lookup), :582 (NativeRule), :610 (EVM AllowedCall), :633 (setLabel proposal). The live page still shows those relevant declarations. +- Historical raw inputs: plan/agw/notion/legacy-agw-sdk-v1.md:205 and :206. They describe an older, different public API; they do not authorize the current extension by themselves. +- Owner guide: plan/agw/research/deployment-review-2026-10-06/source/docs/5_SDK_Owner_Integration.md:142, :167, :176, :179, :212, :422, :433. +- Delivered metadata: same bundle src/interfaces/IAGW.sol:57 and :107; src/AGW.sol:483 and :636. Grant checkpoint ref names the rulesId, not an application job reference. +- SVM wire responsibilities: same bundle src/libraries/Types.sol:486–525. Remote test/unit/9_svmRulebook.t.sol at 10a24f1:72 explicitly describes synthetic Solana keys; the fixture has hash-generated CEA/ATA/program values. +- Runtime defaults: packages/core/src/lib/agentic/codec/defaults.ts:21–56; native PC omission is still 0, with provisional markers. +- Raw inputs/outputs: packages/core/src/lib/agentic/agentic.types.ts:43–71; codec/native.ts:147 and :255. Arbitrary raw authoring and ABI-generated pins have different validation boundaries; H1's UI approval direction does not answer this API question. +- Rule selection: packages/core/src/lib/agentic/reads/rules.ts:131–169; public SVM read gate :179–183. +- Existing SVM candidate config: packages/core/src/lib/constants/chain.ts:399 (devnet gateway CFVSincHYbETh2k7w6u1ENEkjbSLtveRCEBupKidw2VS); orchestrator/svm-idl/__fixtures__/test_counter.idl.json:2 (program 8yNqjrMnFiFbVTVQcKij8tNWWTMdFkrDf9abCGgc2sgx). These are candidate fixture inputs, not new live acceptance proof. +- Completed backend and limits: [nine-item completion report](../sdk-independent-completion-2026-10-06/README.md), qualified by the newer [hardening report](../sdk-hardening-2026-10-06/README.md). + +Primary remote links: [owner guide](https://github.com/pushchain/push-agentic-wallets/blob/10a24f101e2e6e0a9b76517b29f5cdb1aa967796/docs/5_SDK_Owner_Integration.md), [wallet interface](https://github.com/pushchain/push-agentic-wallets/blob/10a24f101e2e6e0a9b76517b29f5cdb1aa967796/src/interfaces/IAGW.sol), [SVM contract test](https://github.com/pushchain/push-agentic-wallets/blob/10a24f101e2e6e0a9b76517b29f5cdb1aa967796/test/unit/9_svmRulebook.t.sol), [live SDK spec](https://app.notion.com/p/pushprotocol/5-SDK-AGW-3e9188aea7f481cf8e8de324956549b9), [live contract target](https://app.notion.com/p/pushprotocol/1-AGW-Contract-Changes-nomenclature-standard-change-set-3e9188aea7f4813aa31fc95ceb4e684d). + +## What not to send as questions + +Do not re-open deployment/address delivery, the validator/engine design, checkpoint storage, the universal envelope or multi-asset layouts, EVM CEA width, internal spend accounting, same-agent capacity, revoked history, approval-screening ownership or compileCard. Those are supplied, accepted, implemented or explicitly out of standalone scope. + +creditRevert remains a documented Push-core executor dependency. It is a tracked platform limitation, not another unanswered AGW design question. No live Solana test or refund-credit integration is claimed by this source review. diff --git a/plan/agw/research/question-source-recheck-2026-10-06/evidence.json b/plan/agw/research/question-source-recheck-2026-10-06/evidence.json new file mode 100644 index 00000000..d353a87e --- /dev/null +++ b/plan/agw/research/question-source-recheck-2026-10-06/evidence.json @@ -0,0 +1,125 @@ +{ + "checked_at_utc": "2026-10-06T06:59:51.261182+00:00", + "sdk_baseline": "9e9d842415c87f088df15b13782027ffbfc1e085", + "contract_repository": "https://github.com/pushchain/push-agentic-wallets", + "branch_heads": [ + { + "branch": "demo-v1", + "sha": "94e0ad21f5dcf353bc792b3fbf5ae31f63949483", + "committed_at": "2026-09-18T06:35:12+05:30", + "subject": "deployed contracts" + }, + { + "branch": "demo-v1-backup", + "sha": "b3f53297bb38176b72611e0b58487f20a68f6912", + "committed_at": "2026-09-08T08:42:10+05:30", + "subject": "demo-cross-chain-workflow" + }, + { + "branch": "deploy-agw", + "sha": "10a24f101e2e6e0a9b76517b29f5cdb1aa967796", + "committed_at": "2026-10-05T19:29:43+05:30", + "subject": "sdk-doc" + }, + { + "branch": "main", + "sha": "9ddd95402b9a2dbf494f6ebfdb477e9a0fb1408a", + "committed_at": "2026-09-04T10:23:32+05:30", + "subject": "Merge pull request #3 from pushchain/pushAgenticWallet_v3" + }, + { + "branch": "pushAgenticWallet_v1", + "sha": "7dc20e4f3087810be107294350c97e723cb64e8d", + "committed_at": "2026-08-07T12:59:33+05:30", + "subject": "Merge pull request #1 from pushchain/v0-review-fixes" + }, + { + "branch": "pushAgenticWallet_v2", + "sha": "83d568cc484b28f86113a5dd954d06a7ac540232", + "committed_at": "2026-08-07T18:54:06+05:30", + "subject": "docs and claude.md" + }, + { + "branch": "pushAgenticWallet_v3", + "sha": "e8db74815cfbbf5389593805e464fe8d85f7f735", + "committed_at": "2026-10-05T18:38:15+05:30", + "subject": "Merge pull request #16 from pushchain/multi-asset-grantRule" + }, + { + "branch": "urp-fixes", + "sha": "eb5961721017475042d5199687cb46f4733fe3a8", + "committed_at": "2026-09-14T11:34:20+05:30", + "subject": "added docs" + } + ], + "deployed_source": "e8db74815cfbbf5389593805e464fe8d85f7f735", + "documentation_source": "10a24f101e2e6e0a9b76517b29f5cdb1aa967796", + "src_identical": true, + "verified_files": [ + { + "path": "docs/5_SDK_Owner_Integration.md", + "sha256": "a77c3cdc4dbbb791ed1c9df6bdaa9e01b85f221fb7173bfa7e73f89f9eeb4175", + "matches_saved_snapshot": true + }, + { + "path": "docs/addresses/donut.md", + "sha256": "aaab188fbc2bf52afc4aaf2f99ec02c99a34dd5ba006e1f55f7c922f85c6ad3c", + "matches_saved_snapshot": true + }, + { + "path": "docs/1_AGW.md", + "sha256": "6b111652c2ce78b3e227b0838fc3ed2f32b6f0f7eb10146f2352730e327abe45", + "matches_saved_snapshot": true + }, + { + "path": "docs/2_UniversalRulesPolicy.md", + "sha256": "3a5d943dda72396b46d38ef72ea6b7c456368bfd8fee11334675457d4dc42b1b", + "matches_saved_snapshot": true + }, + { + "path": "src/interfaces/IAGW.sol", + "sha256": "72ba3f081c5ad454fdee29aa313216f47d3a1759afccde0ad2360e3af03cf1bb", + "matches_saved_snapshot": true + }, + { + "path": "src/AGW.sol", + "sha256": "9d3fa4c96e7ed0fa74e155aa11c96ffaa0d80fe9a45683ba433a8ba49d30e821", + "matches_saved_snapshot": true + }, + { + "path": "src/libraries/Types.sol", + "sha256": "37ff942bd22e03e3868282381a030423773f16988f4463433e8068cf04ccb552", + "matches_saved_snapshot": true + } + ], + "notion": { + "full_export_refreshed": false, + "last_full_export": "2026-10-03T07:53:10.278902+00:00", + "saved_pages_reviewed": [ + "notion/overview.md", + "notion/1-agw-contract-changes.md", + "notion/2-universal-marketplace.md", + "notion/3-8183-job-kernel-and-hook.md", + "notion/4-universal-evaluation.md", + "notion/5-sdk-agw.md", + "notion/6-sdk-universal-marketplace.md", + "notion/7-sdk-8183-job.md", + "notion/8-sdk-universal-evaluation.md", + "notion/legacy-agw-sdk-v1.md", + "notion/agw-address-book-donut-2026-09-04.md", + "notion/agentic-wallet-flow-2026-09-07.md" + ], + "live_pages_inspected": [ + "3e9188aea7f481cf8e8de324956549b9", + "3e9188aea7f4813aa31fc95ceb4e684d" + ], + "discussion_scope": "All discussions including resolved threads; no new substantive replies visible" + }, + "limits": { + "new_live_probe": false, + "funded_transactions": false, + "tests_rerun": false, + "sibling_repositories_fetched": false, + "production_code_changed": false + } +} From 8e54b5b653ea995c179c2f55eff08bc9ed7dd75b Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Tue, 6 Oct 2026 13:38:00 +0530 Subject: [PATCH 25/68] test(agw): validate live Solana wire delivery and rejection replay --- .../__e2e__/agw-svm-wire/outbound.spec.ts | 174 +++ .../core/__e2e__/agw-svm-wire/replay.spec.ts | 59 + packages/core/__e2e__/ci/agw-svm-preflight.ts | 30 + packages/core/__e2e__/ci/preflight.ts | 13 +- packages/core/__e2e__/ci/run.ts | 4 +- packages/core/__e2e__/ci/suite.ts | 41 +- .../__e2e__/shared/agw-svm-policy-probe.ts | 34 + .../core/__e2e__/shared/agw-svm-preflight.ts | 73 + .../__tests__/svm-wire-fixture.spec.ts | 59 + plan/agw/README.md | 7 +- plan/agw/SOURCES.md | 2 + plan/agw/current-baseline.md | 8 +- plan/agw/external-blockers.md | 6 +- plan/agw/gaps.md | 8 +- plan/agw/implementation-plan.md | 2 +- plan/agw/implementation-status.md | 8 +- plan/agw/public-api-proposals.md | 110 ++ plan/agw/questions-harsh.md | 8 +- plan/agw/questions-zaryab.md | 17 +- .../live-svm-wire-2026-10-06/README.md | 80 + .../destination-rejection-simulation.json | 58 + .../failure-observation-final.json | 74 + .../failure-observation.json | 103 ++ .../live-evidence.json | 1296 +++++++++++++++++ .../live-policy-probes.json | 29 + .../live-svm-wire-2026-10-06/logs/build.log | 11 + .../live-svm-wire-2026-10-06/logs/lint.log | 31 + .../logs/live-bootstrap-fixed.log | 31 + .../logs/live-initial.log | 62 + .../live-svm-wire-2026-10-06/logs/replay.log | 14 + .../live-svm-wire-2026-10-06/logs/unit.log | 169 +++ .../platform-followup.md | 35 + .../policy-spend-after-timeout.json | 14 + .../live-svm-wire-2026-10-06/preflight.json | 53 + .../readonly-replay.json | 574 ++++++++ .../live-svm-wire-2026-10-06/run-redacted.cjs | 31 + .../terminal-accounting.json | 10 + .../live-svm-wire-2026-10-06/validation.json | 47 + 38 files changed, 3345 insertions(+), 40 deletions(-) create mode 100644 packages/core/__e2e__/agw-svm-wire/outbound.spec.ts create mode 100644 packages/core/__e2e__/agw-svm-wire/replay.spec.ts create mode 100644 packages/core/__e2e__/ci/agw-svm-preflight.ts create mode 100644 packages/core/__e2e__/shared/agw-svm-policy-probe.ts create mode 100644 packages/core/__e2e__/shared/agw-svm-preflight.ts create mode 100644 packages/core/src/lib/agentic/__tests__/svm-wire-fixture.spec.ts create mode 100644 plan/agw/public-api-proposals.md create mode 100644 plan/agw/research/live-svm-wire-2026-10-06/README.md create mode 100644 plan/agw/research/live-svm-wire-2026-10-06/destination-rejection-simulation.json create mode 100644 plan/agw/research/live-svm-wire-2026-10-06/failure-observation-final.json create mode 100644 plan/agw/research/live-svm-wire-2026-10-06/failure-observation.json create mode 100644 plan/agw/research/live-svm-wire-2026-10-06/live-evidence.json create mode 100644 plan/agw/research/live-svm-wire-2026-10-06/live-policy-probes.json create mode 100644 plan/agw/research/live-svm-wire-2026-10-06/logs/build.log create mode 100644 plan/agw/research/live-svm-wire-2026-10-06/logs/lint.log create mode 100644 plan/agw/research/live-svm-wire-2026-10-06/logs/live-bootstrap-fixed.log create mode 100644 plan/agw/research/live-svm-wire-2026-10-06/logs/live-initial.log create mode 100644 plan/agw/research/live-svm-wire-2026-10-06/logs/replay.log create mode 100644 plan/agw/research/live-svm-wire-2026-10-06/logs/unit.log create mode 100644 plan/agw/research/live-svm-wire-2026-10-06/platform-followup.md create mode 100644 plan/agw/research/live-svm-wire-2026-10-06/policy-spend-after-timeout.json create mode 100644 plan/agw/research/live-svm-wire-2026-10-06/preflight.json create mode 100644 plan/agw/research/live-svm-wire-2026-10-06/readonly-replay.json create mode 100644 plan/agw/research/live-svm-wire-2026-10-06/run-redacted.cjs create mode 100644 plan/agw/research/live-svm-wire-2026-10-06/terminal-accounting.json create mode 100644 plan/agw/research/live-svm-wire-2026-10-06/validation.json diff --git a/packages/core/__e2e__/agw-svm-wire/outbound.spec.ts b/packages/core/__e2e__/agw-svm-wire/outbound.spec.ts new file mode 100644 index 00000000..c4dd168d --- /dev/null +++ b/packages/core/__e2e__/agw-svm-wire/outbound.spec.ts @@ -0,0 +1,174 @@ +/** Internal wire acceptance only. Public Solana Rule/send capability stays disabled. */ +import '@e2e/shared/setup'; +import { PushChain } from '../../src'; +import { Keypair, PublicKey, type ParsedTransactionWithMeta } from '@solana/web3.js'; +import bs58 from 'bs58'; +import { bytesToHex, createPublicClient, http, encodeFunctionData, erc20Abi, parseAbi, parseEther, type Address, type Hex } from 'viem'; +import { privateKeyToAccount } from 'viem/accounts'; +import { CHAIN, PUSH_NETWORK } from '../../src/lib/constants/enums'; +import { CHAIN_INFO, getPushViemChain } from '../../src/lib/constants/chain'; +import type { AgenticRuntime } from '../../src/lib/agentic/runtime'; +import { resolveWalletGeneration } from '../../src/lib/agentic/deployments'; +import { Snapshot } from '../../src/lib/agentic/reads/snapshot'; +import { readSvmRule } from '../../src/lib/agentic/reads/svm'; +import { grantSvmWire } from '../../src/lib/agentic/management/svm'; +import { createSvmMetadataProvider } from '../../src/lib/agentic/management/svm-metadata'; +import { resolveSvmContext } from '../../src/lib/agentic/management/svm-context'; +import { sendSvmAgentWire, prepareSvmAgentExecution, type PreparedSvmRequest } from '../../src/lib/agentic/execution/svm-send'; +import { SvmDataPinMode, type SvmTermsWire } from '../../src/lib/agentic/codec/svm-terms'; +import { svmKey } from '../../src/lib/agentic/codec/svm-accounts'; +import { adaptTrackedResponse } from '../../src/lib/agentic/response'; +import { v4 } from '../../src/lib/agentic/contracts/v4'; +import { setupAgw, evmClient, inSeconds, type AgwFixture } from '../agw/_fixture'; +import { loadAgwManifest, verifyAgwManifest } from '../agw/_manifest'; +import { inspectSvmWirePrograms, svmWireConnection, SVM_WIRE_CHAIN, SVM_WIRE_GATEWAY, SVM_WIRE_PROGRAM, SVM_WIRE_COUNTER, decodeWireCounter } from '../shared/agw-svm-preflight'; +import { probeSvmWirePolicies } from '../shared/agw-svm-policy-probe'; + +const d = process.env['AGW_SVM_WIRE_E2E'] === '1' ? describe : describe.skip; +// Load the public entry point before internal modules (the existing harness +// does the same); keeping this runtime use prevents TypeScript erasing it. +if (PushChain.CONSTANTS.CHAIN.SOLANA_DEVNET !== SVM_WIRE_CHAIN) throw new Error('Solana fixture chain mismatch'); +const AMOUNT = BigInt(10_000); // 0.00001 SOL, twice at most per run. +const MAX_PC = parseEther('20'); +const RECEIVE = '0x79f4fa0308e5e101' as Hex; +const DECREMENT = '0x6ae3a83bf81b9665' as Hex; +const ZERO = `0x${'00'.repeat(32)}` as Hex; +const rt = (c: PushChain) => (c as unknown as { agenticRuntime: AgenticRuntime }).agenticRuntime; +const ixData = (disc: Hex, amount: bigint) => { + const b = Buffer.alloc(16); Buffer.from(disc.slice(2), 'hex').copy(b); b.writeBigUInt64LE(amount, 8); return b; +}; + +function transferFromCea(tx: ParsedTransactionWithMeta, cea: string, recipient: string, amount: bigint) { + return tx.meta?.innerInstructions?.some((group) => group.instructions.some((ix) => + 'parsed' in ix && ix.program === 'system' && ix.parsed.type === 'transfer' && + ix.parsed.info.source === cea && ix.parsed.info.destination === recipient && + BigInt(ix.parsed.info.lamports) === amount + )); +} + +d('agw svm wire', () => { + let f: AgwFixture, wallet: Address, token: Address, rulesId: Hex, agent: PushChain; + let gen: Awaited>; + let recipient: PublicKey, cea: PublicKey; + const sol = svmWireConnection(); + const metadata = createSvmMetadataProvider({ [SVM_WIRE_CHAIN]: { + gatewayProgram: SVM_WIRE_GATEWAY, rpcUrls: CHAIN_INFO[SVM_WIRE_CHAIN].defaultRPC, + } }, (url) => svmWireConnection(url)); + const accounts = (failure = false) => failure + ? [{ pubkey: svmKey(SVM_WIRE_COUNTER.toBase58()), isWritable: true }, { pubkey: svmKey(cea.toBase58()), isWritable: false }] + : [{ pubkey: svmKey(SVM_WIRE_COUNTER.toBase58()), isWritable: true }, { pubkey: svmKey(recipient.toBase58()), isWritable: true }, { pubkey: svmKey(cea.toBase58()), isWritable: true }, { pubkey: ZERO, isWritable: false }]; + const request = (failure = false): PreparedSvmRequest => ({ wallet, rulesId, token, amount: AMOUNT, gasLimit: BigInt(0), + program: SVM_WIRE_PROGRAM, instructionData: ixData(failure ? DECREMENT : RECEIVE, failure ? BigInt(1) : AMOUNT), accounts: accounts(failure) }); + const stored = () => Snapshot.at(rt(f.owner).reader).then((snap) => readSvmRule(snap, gen, wallet, rulesId, rt(f.owner).pushChainNamespace)); + + beforeAll(async () => { + // Every cluster/program check runs before setupAgw can fund anything. + const preflight = await inspectSvmWirePrograms(sol); + const key = process.env['SOLANA_PRIVATE_KEY']; + if (!key) throw new Error('SOLANA_PRIVATE_KEY is needed only to identify the owned recipient'); + try { recipient = Keypair.fromSecretKey(bs58.decode(key)).publicKey; } + catch { recipient = Keypair.fromSecretKey(Uint8Array.from(JSON.parse(key))).publicKey; } + const destination = await sol.getAccountInfo(recipient); + if (!destination || destination.executable || !destination.owner.equals(PublicKey.default)) throw new Error('Owned recipient must be an existing System account'); + if (parseEther(process.env['AGW_E2E_AGENT_PC'] ?? '0.5') > parseEther('0.5')) throw new Error('Wire suite agent funding is bounded to 0.5 PC'); + const manifest = loadAgwManifest(); + if (manifest.network !== PUSH_NETWORK.TESTNET_DONUT) throw new Error('Wire suite is restricted to Donut'); + const push = createPublicClient({ chain: getPushViemChain(CHAIN.PUSH_TESTNET_DONUT), transport: http(CHAIN_INFO[CHAIN.PUSH_TESTNET_DONUT].defaultRPC[0]) }); + await verifyAgwManifest(push, manifest); + const ownerKey = process.env['PUSH_PRIVATE_KEY'] as Hex | undefined; + if (!ownerKey) throw new Error('PUSH_PRIVATE_KEY is required'); + const ownerAddress = privateKeyToAccount(ownerKey).address; + token = await push.readContract({ address: '0x00000000000000000000000000000000000000C0', + abi: parseAbi(['function gasTokenPRC20ByChainNamespace(string) view returns (address)']), + functionName: 'gasTokenPRC20ByChainNamespace', args: [SVM_WIRE_CHAIN] }); + const ownerTokens = await push.readContract({ address: token, abi: erc20Abi, functionName: 'balanceOf', args: [ownerAddress] }); + if (ownerTokens < AMOUNT * BigInt(2)) throw new Error('Push owner needs 0.00002 pSOL for this bounded suite'); + if (await push.getBalance({ address: ownerAddress }) < parseEther('45')) throw new Error('Push owner needs 45 PC to cover bounded setup and outbound budgets'); + f = await setupAgw(); + f.evidence('svm-wire-program-preflight', preflight); + wallet = (await f.owner.agentic.create('e2e-internal-svm-wire', { rules: [] })).wallet; + gen = await resolveWalletGeneration(rt(f.owner).reader, f.manifest.network, wallet); + const resolved = await resolveSvmContext(await Snapshot.at(rt(f.owner).reader), wallet, SVM_WIRE_CHAIN, + [{ token, maxPerCall: AMOUNT, maxTotal: AMOUNT * BigInt(2) }], metadata); + cea = new PublicKey(Buffer.from(resolved.expectedCEA.slice(2), 'hex')); + if (cea.toBase58() === preflight.counter.authority) throw new Error('Failure fixture requires a counter authority different from the fresh AGW CEA'); + const terms: SvmTermsWire = { ...resolved, validUntil: inSeconds(7200), maxGasPerCall: MAX_PC, + programs: [RECEIVE, DECREMENT].map((discriminator, i) => ({ program: svmKey(SVM_WIRE_PROGRAM), discriminator, + discriminatorLen: 8, dataless: false, maxAccounts: i === 0 ? 4 : 2 })), + pins: [false, true].flatMap((failure, ruleIndex) => accounts(failure).map((a, accountIndex) => ({ ruleIndex, accountIndex, expected: a.pubkey }))), + dataPins: [AMOUNT, BigInt(1)].map((limit, ruleIndex) => ({ ruleIndex, fromEnd: false, offset: 8, offsetB: 0, len: 8, + mode: SvmDataPinMode.LTE_LE, expected: `0x${limit.toString(16).padStart(64, '0')}`, num: BigInt(0), den: BigInt(0) })), + }; + const grant = await grantSvmWire(rt(f.owner), gen, wallet, { agent: f.agentAddress, chainNamespace: SVM_WIRE_CHAIN, terms }); + rulesId = grant.rulesId; + await f.fundPC(wallet, MAX_PC * BigInt(2) + parseEther('1')); + await (await f.owner.universal.sendTransaction({ to: token, data: encodeFunctionData({ abi: erc20Abi, functionName: 'transfer', args: [wallet, AMOUNT * BigInt(2)] }) })).wait(); + const ownerWallet = await evmClient(process.env['PUSH_PRIVATE_KEY'] as Hex, CHAIN.PUSH_TESTNET_DONUT, f.manifest.network, wallet); + await (await ownerWallet.universal.sendTransaction({ to: token, data: encodeFunctionData({ abi: erc20Abi, functionName: 'approve', args: [f.manifest.addresses.gateway, AMOUNT * BigInt(2)] }) })).wait(); + agent = await f.agent(wallet); + f.evidence('svm-wire-setup', { wallet, rulesId, grantHash: grant.tx.hash, agent: f.agentAddress, recipient: recipient.toBase58(), cea: cea.toBase58(), token, terms, walletPCFunded: MAX_PC * BigInt(2) + parseEther('1'), tokenFunded: AMOUNT * BigInt(2) }); + }, 900_000); + afterAll(() => f?.teardown()); + + it('1. positive outbound: actual CEA transfer and counter execution, receipt and replay', async () => { + const before = decodeWireCounter((await sol.getAccountInfo(SVM_WIRE_COUNTER))!.data).value; + const count = await f.push.readContract({ address: wallet, abi: v4.abis.wallet, functionName: 'checkpointCount' }); + const { tx } = await sendSvmAgentWire(rt(agent), gen, request(), metadata); + f.evidence('svm-wire-positive-submitted', { wallet, rulesId, hash: tx.hash }); + // Existing verified-wallet replay adaptation enables normal outbound wait; + // it uses the gateway wire call as the logical summary, not a new SVM API. + await adaptTrackedResponse(rt(agent), tx); + expect(tx.from).toBe(wallet); expect(tx.route).toBe('UOA_TO_CEA'); + const receipt = await tx.wait({ outboundTimeoutMs: 600_000 }); + f.evidence('svm-wire-positive-receipt', { hash: tx.hash, receipt }); + expect(receipt.status).toBe(1); expect(receipt.externalStatus).toBe('success'); + expect(receipt.from).toBe(wallet); expect(receipt.externalChain).toBe(SVM_WIRE_CHAIN); + const destination = await sol.getParsedTransaction(receipt.externalTxHash!, { commitment: 'confirmed', maxSupportedTransactionVersion: 0 }); + expect(destination).not.toBeNull(); expect(destination!.meta!.err).toBeNull(); + expect(transferFromCea(destination!, cea.toBase58(), recipient.toBase58(), AMOUNT)).toBe(true); + expect(destination!.meta!.innerInstructions?.some((g) => g.instructions.some((ix) => + 'data' in ix && ix.programId.toBase58() === SVM_WIRE_PROGRAM && bytesToHex(bs58.decode(ix.data)) === bytesToHex(ixData(RECEIVE, AMOUNT)) && + ix.accounts.some((a) => a.equals(cea)) + ))).toBe(true); + expect(decodeWireCounter((await sol.getAccountInfo(SVM_WIRE_COUNTER))!.data).value).toBeGreaterThanOrEqual(before + AMOUNT); + expect((await stored()).config.assets[0].spent).toBe(AMOUNT); + expect(await f.push.readContract({ address: wallet, abi: v4.abis.wallet, functionName: 'checkpointCount' })).toBe(count); + const replay = await f.owner.universal.trackTransaction(tx.hash); + expect(replay.from).toBe(wallet); expect(replay.route).toBe('UOA_TO_CEA'); + expect(replay.agentic).toMatchObject({ door: 'agent', rulesId }); + const replayReceipt = await replay.wait({ outboundTimeoutMs: 600_000 }); + expect(replayReceipt.externalTxHash).toBe(receipt.externalTxHash); + f.evidence('svm-wire-positive-destination', { hash: tx.hash, externalTxHash: receipt.externalTxHash, destination, replayReceipt }); + }, 900_000); + + it('2. substituted account and oversized instruction amount fail before submission', async () => { + const base = request(); + const wrong = [...base.accounts!]; wrong[2] = { ...wrong[2], pubkey: svmKey(recipient.toBase58()) }; + const nonce = await f.push.getTransactionCount({ address: f.agentAddress }); + await expect(prepareSvmAgentExecution(rt(agent), gen, { ...base, accounts: wrong }, metadata)).rejects.toThrow(); + await expect(prepareSvmAgentExecution(rt(agent), gen, { ...base, instructionData: ixData(RECEIVE, AMOUNT + BigInt(1)) }, metadata)).rejects.toThrow(); + const prepared = await prepareSvmAgentExecution(rt(agent), gen, base, metadata); + const policy = await probeSvmWirePolicies(f.push, { from: f.agentAddress, wallet, rulesId, call: prepared.call, blockNumber: await f.push.getBlockNumber() }); + expect(await f.push.getTransactionCount({ address: f.agentAddress })).toBe(nonce); + f.evidence('svm-wire-preflight-refusals', { wallet, rulesId, nonce, policy, transactionsSent: 0 }); + }); + + it('3. destination program failure is classified and does not restore policy spend', async () => { + const prior = (await stored()).config.assets[0].spent; + const { tx } = await sendSvmAgentWire(rt(agent), gen, request(true), metadata); + f.evidence('svm-wire-failure-submitted', { wallet, rulesId, hash: tx.hash }); + await adaptTrackedResponse(rt(agent), tx); + // The observed node rejection lifecycle exceeded ten minutes. Keep the + // failed assertion strict while allowing the bounded terminalization window. + const receipt = await tx.wait({ outboundTimeoutMs: 1_200_000 }); + f.evidence('svm-wire-failure-receipt', { hash: tx.hash, receipt }); + const pushReceipt = await f.push.getTransactionReceipt({ hash: tx.hash as Hex }); + expect(pushReceipt.status).toBe('success'); expect(receipt.externalStatus).toBe('failed'); + expect((await stored()).config.assets[0].spent).toBe(prior + AMOUNT); + if (receipt.externalTxHash) { + const destination = await sol.getParsedTransaction(receipt.externalTxHash, { commitment: 'confirmed', maxSupportedTransactionVersion: 0 }); + expect(destination).not.toBeNull(); expect(destination!.meta!.err).not.toBeNull(); + f.evidence('svm-wire-failure-destination', { hash: tx.hash, externalTxHash: receipt.externalTxHash, destination }); + } + }, 1_500_000); +}); diff --git a/packages/core/__e2e__/agw-svm-wire/replay.spec.ts b/packages/core/__e2e__/agw-svm-wire/replay.spec.ts new file mode 100644 index 00000000..d0009036 --- /dev/null +++ b/packages/core/__e2e__/agw-svm-wire/replay.spec.ts @@ -0,0 +1,59 @@ +/** Read-only acceptance of recorded wire transactions; no signer or funding required. */ +import { PushChain } from '../../src'; +import { createPublicClient, http, type Hex } from 'viem'; +import { CHAIN_INFO, getPushViemChain } from '../../src/lib/constants/chain'; +import { CHAIN, PUSH_NETWORK } from '../../src/lib/constants/enums'; +import { v4 } from '../../src/lib/agentic/contracts/v4'; +import { chainReaderFromPublicClient } from '../../src/lib/agentic/contracts/reader'; +import { resolveWalletGeneration } from '../../src/lib/agentic/deployments'; +import { Snapshot } from '../../src/lib/agentic/reads/snapshot'; +import { readSvmRule } from '../../src/lib/agentic/reads/svm'; +import { probeSvmWirePolicies } from '../shared/agw-svm-policy-probe'; + +const d = process.env['AGW_SVM_WIRE_REPLAY_E2E'] === '1' ? describe : describe.skip; +const POSITIVE = '0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8' as Hex; +const REJECTED = '0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc' as Hex; +const EXTERNAL = 'kGUaPUfASg9Poo93aMsztHJjUk27MKuRJBfDZK1WP3FFSaXSYcoPcxjUMFyDxaK6aU6mQkZeowSu3MtvK5PXKgK'; + +d('agw svm recorded replay', () => { + const push = createPublicClient({ chain: getPushViemChain(CHAIN.PUSH_TESTNET_DONUT), transport: http(CHAIN_INFO[CHAIN.PUSH_TESTNET_DONUT].defaultRPC[0]) }); + let source: Awaited>; + let decoded: Extract>, { kind: 'executeAsAgent' }>; + let client: PushChain; + beforeAll(async () => { + source = await push.getTransaction({ hash: POSITIVE }); + const call = v4.decodeWalletCall(source.input); + if (!source.to || call?.kind !== 'executeAsAgent') throw new Error('Recorded fixture is not an AGW agent call'); + decoded = call; + client = await PushChain.initialize({ chain: PushChain.CONSTANTS.CHAIN.PUSH_TESTNET_DONUT, address: source.from }, { network: PUSH_NETWORK.TESTNET_DONUT }); + expect(client.isReadMode).toBe(true); + }); + it('1. positive replay retains wallet, signer origin and actual Solana signature', async () => { + const tx = await client.universal.trackTransaction(POSITIVE); + expect(tx.from.toLowerCase()).toBe(source.to!.toLowerCase()); + expect(tx.origin.toLowerCase()).toBe(`eip155:42101:${source.from}`.toLowerCase()); + expect(tx.agentic?.rulesId).toBe(decoded.rulesId); expect(tx.route).toBe('UOA_TO_CEA'); + const receipt = await tx.wait({ outboundTimeoutMs: 30_000 }); + expect(receipt.status).toBe(1); expect(receipt.externalStatus).toBe('success'); expect(receipt.externalTxHash).toBe(EXTERNAL); + }, 120_000); + it('2. later terminal rejection is failed, while the source succeeded and spend remains charged', async () => { + const tx = await client.universal.trackTransaction(REJECTED); + const receipt = await tx.wait({ outboundTimeoutMs: 30_000 }); + expect(receipt.status).toBe(1); expect(receipt.externalStatus).toBe('failed'); + expect(receipt.externalError).toContain('tx not executed on destination chain'); + expect(tx.from.toLowerCase()).toBe(source.to!.toLowerCase()); + // Historical snapshot after the actual refund block, immune to later owner changes. + const reader = chainReaderFromPublicClient(push); + const gen = await resolveWalletGeneration(reader, PUSH_NETWORK.TESTNET_DONUT, source.to!); + const snapshot = new Snapshot(reader, BigInt(23950160)); + const rule = await readSvmRule(snapshot, gen, source.to!, decoded.rulesId, 'eip155:42101'); + expect(rule.config.assets[0].spent).toBe(BigInt(20_000)); + }, 120_000); + it('3. pinned live policy calls refuse account and data mutations without submitting', async () => { + const receipt = await push.getTransactionReceipt({ hash: POSITIVE }); + const result = await probeSvmWirePolicies(push, { from: source.from, wallet: source.to!, rulesId: decoded.rulesId, call: decoded.calls[0], blockNumber: receipt.blockNumber }); + expect(result.transactionsSent).toBe(0); expect(result.observations.map((r) => r.decoded.name)).toEqual([ + 'PolicyCheckReverted(SvmAccountPinMismatch)', 'PolicyCheckReverted(SvmDataCeilingExceeded)', + ]); + }); +}); diff --git a/packages/core/__e2e__/ci/agw-svm-preflight.ts b/packages/core/__e2e__/ci/agw-svm-preflight.ts new file mode 100644 index 00000000..588ef2c5 --- /dev/null +++ b/packages/core/__e2e__/ci/agw-svm-preflight.ts @@ -0,0 +1,30 @@ +/** No dotenv, signers or transactions: inspect both networks before funding a wire test. */ +import { mkdirSync, writeFileSync } from 'node:fs'; +import { dirname } from 'node:path'; +import { createPublicClient, fallback, http, parseAbi, type Address } from 'viem'; +import { CHAIN_INFO, getPushViemChain } from '../../src/lib/constants/chain'; +import { CHAIN } from '../../src/lib/constants/enums'; +import { loadAgwManifest, verifyAgwManifest } from '../agw/_manifest'; +import { inspectSvmWirePrograms, svmWireConnection, SVM_WIRE_CHAIN } from '../shared/agw-svm-preflight'; + +async function main() { + const manifest = loadAgwManifest(); + const push = createPublicClient({ chain: getPushViemChain(CHAIN.PUSH_TESTNET_DONUT), transport: fallback(CHAIN_INFO[CHAIN.PUSH_TESTNET_DONUT].defaultRPC.map((u) => http(u))) }); + await verifyAgwManifest(push, manifest); + const block = await push.getBlockNumber(); + const token = await push.readContract({ address: '0x00000000000000000000000000000000000000C0', + abi: parseAbi(['function gasTokenPRC20ByChainNamespace(string) view returns (address)']), + functionName: 'gasTokenPRC20ByChainNamespace', args: [SVM_WIRE_CHAIN], blockNumber: block }) as Address; + const source = await push.readContract({ address: token, abi: parseAbi(['function SOURCE_CHAIN_NAMESPACE() view returns (string)']), functionName: 'SOURCE_CHAIN_NAMESPACE', blockNumber: block }); + if (source !== SVM_WIRE_CHAIN) throw new Error('Gas PRC20 does not match Solana devnet'); + const quote = await push.readContract({ address: '0x00000000000000000000000000000000000000C0', + abi: parseAbi(['function getOutboundTxGasAndFees(address,uint256) view returns (address,uint256,uint256,uint256,string,uint256)']), + functionName: 'getOutboundTxGasAndFees', args: [token, BigInt(0)], blockNumber: block }); + const solana = await inspectSvmWirePrograms(svmWireConnection()); + const result = { push: { chainId: await push.getChainId(), block, sourceCommit: manifest.sourceCommit, token, quote }, solana, transactionsSent: 0 }; + const json = JSON.stringify(result, (_k, v) => typeof v === 'bigint' ? v.toString() : v, 2) + '\n'; + const output = process.argv[2]; + if (output) { mkdirSync(dirname(output), { recursive: true }); writeFileSync(output, json); } + process.stdout.write(json); +} +main().catch((error) => { console.error((error as Error).message); process.exitCode = 1; }); diff --git a/packages/core/__e2e__/ci/preflight.ts b/packages/core/__e2e__/ci/preflight.ts index 757fd8a2..b3a46c64 100644 --- a/packages/core/__e2e__/ci/preflight.ts +++ b/packages/core/__e2e__/ci/preflight.ts @@ -286,6 +286,10 @@ function renderTable(rows: Row[]): void { (async () => { const scenarios = scenariosFor(group); const raw = aggregateNeeds(scenarios); + if (group === 'agw-svm-replay') { + console.log('Recorded SVM replay is read-only: no keys, signing or funding needed.'); + return; + } /** Summed need for an asset, with headroom and reserve, as a decimal string. */ const target = (a: Asset): number => { @@ -332,7 +336,7 @@ function renderTable(rows: Row[]): void { // The agw group needs a verified compatible AGW deployment (plan/agw A07). // Check it read-only BEFORE any balance work so nothing is ever funded for // a run that cannot exercise a real deployment. - if (scenarios.some((s) => s.group === 'agw')) { + if (scenarios.some((s) => s.group === 'agw' || s.group === 'agw-svm-wire')) { try { await verifyAgwManifest(push, loadAgwManifest()); console.log('AGW deployment manifest verified on-chain.'); @@ -342,6 +346,11 @@ function renderTable(rows: Row[]): void { process.exit(1); } } + if (scenarios.some((s) => s.group === 'agw-svm-wire')) { + const { inspectSvmWirePrograms, svmWireConnection } = await import('../shared/agw-svm-preflight'); + await inspectSvmWirePrograms(svmWireConnection(solRpc)); + console.log('Solana wire fixture verified read-only before funding.'); + } const pushWallet = createWalletClient({ account: pushAcc, chain: pushChainDef, @@ -474,7 +483,7 @@ function renderTable(rows: Row[]): void { { scope: 'Push master (Donut)', asset: 'PC', need: units(target('masterPC'), 18) + deficit('ueaPC'), have: mPC, decimals: 18, tier: 'master' }, { scope: 'Push master (Donut)', asset: 'pETH', need: units(target('masterPETH'), dPeth) + deficit('ueaPETH'), have: mPeth, decimals: dPeth, tier: 'master' }, { scope: 'Push master (Donut)', asset: 'pUSDT.eth', need: deficit('ueaUsdtEth'), have: mUsdtEth, decimals: dUsdtEth, tier: 'master' }, - { scope: 'Push master (Donut)', asset: 'pSOL', need: deficit('ueaPSOL'), have: mPsol, decimals: dPsol, tier: 'master' }, + { scope: 'Push master (Donut)', asset: 'pSOL', need: units(target('masterPSOL'), dPsol) + deficit('ueaPSOL'), have: mPsol, decimals: dPsol, tier: 'master' }, { scope: 'Push master (Donut)', asset: 'pUSDT.sol', need: deficit('ueaUsdtSol'), have: mUsdtSol, decimals: dUsdtSol, tier: 'master' }, { scope: 'Push master (Donut)', asset: 'PC20', need: deficit('ueaPC20'), have: mPc20, decimals: dPc20, tier: 'master' }, { scope: 'Solana master (Devnet)', asset: 'SOL', need: units(target('solanaSOL'), 9) + deficit('ceaSvmSOL'), have: solBal, decimals: 9, tier: 'master' }, diff --git a/packages/core/__e2e__/ci/run.ts b/packages/core/__e2e__/ci/run.ts index 9dcd111c..06b48485 100644 --- a/packages/core/__e2e__/ci/run.ts +++ b/packages/core/__e2e__/ci/run.ts @@ -7,8 +7,8 @@ * * --group One of: all (default), smoke, evm-r1, evm-r2, evm-r3, * svm-r1, svm-r2r3, pc20, push, cross-chain, read, - * known-fail, agw - * (`all` excludes known-fail and agw — ask for them by name; + * known-fail, agw, agw-svm-wire, agw-svm-replay + * (`all` excludes known-fail and AGW groups — ask by name; * agw uses the checked Donut v4 manifest by default, see __e2e__/agw/_manifest.ts) * --list Print the selection and the jest argv, run nothing * --verify Check every `grep` against the real spec titles and exit diff --git a/packages/core/__e2e__/ci/suite.ts b/packages/core/__e2e__/ci/suite.ts index cafc9ff5..9f39c796 100644 --- a/packages/core/__e2e__/ci/suite.ts +++ b/packages/core/__e2e__/ci/suite.ts @@ -35,6 +35,8 @@ export const GROUPS = [ 'read', 'known-fail', 'agw', + 'agw-svm-wire', + 'agw-svm-replay', ] as const; export type Group = (typeof GROUPS)[number]; @@ -70,6 +72,7 @@ export type Asset = // Push master (PUSH_PRIVATE_KEY) on Push Donut — Push-native origin specs | 'masterPC' | 'masterPETH' + | 'masterPSOL' // The EVM master's UEA on Push Donut — Routes 2/3 on both VMs, and PC20 | 'ueaPC' | 'ueaPETH' @@ -160,6 +163,40 @@ const F = { } as const; export const SCENARIOS: Scenario[] = [ + { + id: 'agw-svm-replay-positive', group: 'agw-svm-replay', file: '__e2e__/agw-svm-wire/replay.spec.ts', + grep: 'agw svm recorded replay 1\\. positive replay', needs: {}, env: { AGW_SVM_WIRE_REPLAY_E2E: '1' }, + }, + { + id: 'agw-svm-replay-rejected', group: 'agw-svm-replay', file: '__e2e__/agw-svm-wire/replay.spec.ts', + grep: 'agw svm recorded replay 2\\. later terminal rejection', needs: {}, env: { AGW_SVM_WIRE_REPLAY_E2E: '1' }, + }, + { + id: 'agw-svm-replay-policy', group: 'agw-svm-replay', file: '__e2e__/agw-svm-wire/replay.spec.ts', + grep: 'agw svm recorded replay 3\\. pinned live policy', needs: {}, env: { AGW_SVM_WIRE_REPLAY_E2E: '1' }, + }, + { + id: 'agw-svm-wire-positive', group: 'agw-svm-wire', + file: '__e2e__/agw-svm-wire/outbound.spec.ts', + grep: 'agw svm wire 1\\. positive outbound', + needs: { masterPC: '45', masterPSOL: '0.00002' }, + env: { AGW_SVM_WIRE_E2E: '1' }, + note: 'Internal prepared-wire backend; public SVM capability remains gated.', + }, + { + id: 'agw-svm-wire-refusals', group: 'agw-svm-wire', + file: '__e2e__/agw-svm-wire/outbound.spec.ts', + grep: 'agw svm wire 2\\. substituted account', + needs: { masterPC: '45', masterPSOL: '0.00002' }, + env: { AGW_SVM_WIRE_E2E: '1' }, + }, + { + id: 'agw-svm-wire-failure', group: 'agw-svm-wire', + file: '__e2e__/agw-svm-wire/outbound.spec.ts', + grep: 'agw svm wire 3\\. destination program failure', + needs: { masterPC: '45', masterPSOL: '0.00002' }, + env: { AGW_SVM_WIRE_E2E: '1' }, + }, // --------------------------------------------------------------------------- // smoke — read-only. No transactions, no funds. Runs first so a broken build or // a dead RPC fails in ~3 min instead of 90. @@ -1004,13 +1041,13 @@ export const SCENARIOS: Scenario[] = [ /** * Scenarios for a group. `all` means "everything that should pass" — it deliberately - * excludes `known-fail` and `agw`, which have to be asked for by name. + * excludes `known-fail`, `agw` and `agw-svm-wire`, which must be requested by name. */ export function scenariosFor(group: string | undefined): Scenario[] { if (!group || group === 'all') { // AGW stays opt-in: scenarios create/fund fresh wallets and consume testnet funds. return SCENARIOS.filter( - (s) => s.group !== 'known-fail' && s.group !== 'agw' + (s) => s.group !== 'known-fail' && !s.group.startsWith('agw') ); } if (!(GROUPS as readonly string[]).includes(group)) { diff --git a/packages/core/__e2e__/shared/agw-svm-policy-probe.ts b/packages/core/__e2e__/shared/agw-svm-policy-probe.ts new file mode 100644 index 00000000..0a8044aa --- /dev/null +++ b/packages/core/__e2e__/shared/agw-svm-policy-probe.ts @@ -0,0 +1,34 @@ +/** Bypass SDK validation to verify the deployed URP refuses the same mutations. eth_call only. */ +import { decodeFunctionData, encodeFunctionData, type Address, type Hex, type PublicClient } from 'viem'; +import { UNIVERSAL_GATEWAY_PC } from '../../src/lib/constants/abi'; +import { v4, type Call } from '../../src/lib/agentic/contracts/v4'; +import { parseAgwSvmPayload, encodeAgwSvmPayload } from '../../src/lib/agentic/execution/svm-payload'; +import { decodeAgenticRevert } from '../../src/lib/agentic/revert'; + +export async function probeSvmWirePolicies(push: PublicClient, input: { + from: Address; wallet: Address; rulesId: Hex; call: Call; blockNumber: bigint; +}) { + const decodedCall = decodeFunctionData({ abi: UNIVERSAL_GATEWAY_PC, data: input.call.data }); + if (decodedCall.functionName !== 'sendUniversalTxOutbound') throw new Error('Expected a gateway outbound request'); + const request = decodedCall.args[0]; + const parsed = parseAgwSvmPayload(request.payload); + const observations = []; + for (const kind of ['account-pin', 'instruction-data-pin'] as const) { + const accounts = parsed.accounts.map((account) => ({ ...account })); + const data = new Uint8Array(parsed.instructionData); + if (kind === 'account-pin') accounts[2].pubkey = accounts[1].pubkey; + else { + const view = new DataView(data.buffer, data.byteOffset, data.byteLength); + view.setBigUint64(8, view.getBigUint64(8, true) + BigInt(1), true); + } + const altered = { ...request, payload: encodeAgwSvmPayload(parsed.program, accounts, data) }; + const packet = v4.encodeExecuteAsAgent(input.rulesId, { ...input.call, + data: encodeFunctionData({ abi: UNIVERSAL_GATEWAY_PC, functionName: 'sendUniversalTxOutbound', args: [altered] }) }); + let decoded; + try { await push.call({ account: input.from, to: input.wallet, data: packet, blockNumber: input.blockNumber }); } + catch (error) { decoded = decodeAgenticRevert(error); } + if (!decoded?.name?.includes('Svm')) throw new Error(`Expected a decoded SVM policy refusal for ${kind}, got ${decoded?.name ?? 'no decoded refusal'}`); + observations.push({ kind, reverted: true, decoded }); + } + return { chainId: 42101, block: input.blockNumber.toString(), observations, transactionsSent: 0 }; +} diff --git a/packages/core/__e2e__/shared/agw-svm-preflight.ts b/packages/core/__e2e__/shared/agw-svm-preflight.ts new file mode 100644 index 00000000..1272c52b --- /dev/null +++ b/packages/core/__e2e__/shared/agw-svm-preflight.ts @@ -0,0 +1,73 @@ +/** Read-only checks for the internal AGW Solana wire acceptance suite. */ +import { createHash } from 'node:crypto'; +import { BorshAccountsCoder, type Idl } from '@coral-xyz/anchor'; +import { Connection, PublicKey } from '@solana/web3.js'; +import { CHAIN_INFO } from '../../src/lib/constants/chain'; +import { CHAIN } from '../../src/lib/constants/enums'; +import gatewayIdl from '../../src/lib/constants/abi/universalGatewayV0.json'; +import counterIdl from '../../src/lib/orchestrator/svm-idl/__fixtures__/test_counter.idl.json'; + +export const SVM_WIRE_CHAIN = CHAIN.SOLANA_DEVNET; +export const SVM_WIRE_PROGRAM = counterIdl.address; +export const SVM_WIRE_GATEWAY = CHAIN_INFO[SVM_WIRE_CHAIN].lockerContract!; +export const SVM_WIRE_COUNTER = PublicKey.findProgramAddressSync( + [Buffer.from('counter')], new PublicKey(SVM_WIRE_PROGRAM) +)[0]; +const LOADER = 'BPFLoaderUpgradeab1e11111111111111111111111'; +const COUNTER_DISC = Buffer.from(counterIdl.accounts.find((a) => a.name === 'Counter')!.discriminator); + +export function decodeWireCounter(data: Buffer) { + if (data.length < 48 || !data.subarray(0, 8).equals(COUNTER_DISC)) + throw new Error('Counter data does not match the selected IDL'); + return { value: data.readBigUInt64LE(8), authority: new PublicKey(data.subarray(16, 48)).toBase58() }; +} + +export function svmWireConnection(url = CHAIN_INFO[SVM_WIRE_CHAIN].defaultRPC[0]) { + return new Connection(url, { + commitment: 'confirmed', + disableRetryOnRateLimit: true, + fetch: (input, init) => fetch(input, { ...init, signal: AbortSignal.timeout(20_000) }), + }); +} + +export async function inspectSvmWirePrograms(connection: Connection) { + const genesis = await connection.getGenesisHash(); + if (`solana:${genesis.slice(0, 32)}` !== SVM_WIRE_CHAIN) + throw new Error('Solana RPC is not the selected devnet cluster'); + const gateway = new PublicKey(SVM_WIRE_GATEWAY), program = new PublicKey(SVM_WIRE_PROGRAM); + if (gatewayIdl.address !== gateway.toBase58()) throw new Error('Gateway registry and IDL disagree'); + const config = PublicKey.findProgramAddressSync([Buffer.from('config')], gateway)[0]; + const keys = [gateway, program, SVM_WIRE_COUNTER, config]; + const info = await connection.getMultipleAccountsInfoAndContext(keys); + const fingerprint = (data: Buffer) => createHash('sha256').update(data).digest('hex'); + const programDataKeys = info.value.slice(0, 2).map((account, i) => { + if (!account?.executable || account.owner.toBase58() !== LOADER || + account.data.length !== 36 || account.data.readUInt32LE(0) !== 2) + throw new Error(`Program ${keys[i].toBase58()} is not an executable upgradeable program`); + return new PublicKey(account.data.subarray(4, 36)); + }); + const counter = info.value[2], configuration = info.value[3]; + if (!counter || counter.executable || !counter.owner.equals(program)) throw new Error('Counter account is missing or has the wrong owner'); + const counterState = decodeWireCounter(counter.data); + if (!configuration || configuration.executable || !configuration.owner.equals(gateway)) throw new Error('Gateway configuration is missing or has the wrong owner'); + const decoded = new BorshAccountsCoder(gatewayIdl as unknown as Idl).decode('Config', configuration.data); + if (decoded.paused !== false) throw new Error('Gateway is paused'); + const implementations = await connection.getMultipleAccountsInfoAndContext(programDataKeys); + const programs = implementations.value.map((account, i) => { + if (!account || account.owner.toBase58() !== LOADER || account.data.readUInt32LE(0) !== 3 || account.data.length <= 45) + throw new Error('ProgramData account is missing or invalid'); + return { + address: keys[i].toBase58(), programData: programDataKeys[i].toBase58(), + lastUpgradeSlot: account.data.readBigUInt64LE(4).toString(), + dataLength: account.data.length, dataSha256: fingerprint(account.data), + }; + }); + return { + checkedAt: new Date().toISOString(), chain: SVM_WIRE_CHAIN, genesis, + slot: info.context.slot, programDataSlot: implementations.context.slot, programs, + gatewayConfig: { address: config.toBase58(), paused: decoded.paused, dataSha256: fingerprint(configuration.data) }, + counter: { address: SVM_WIRE_COUNTER.toBase58(), value: counterState.value.toString(), authority: counterState.authority, dataSha256: fingerprint(counter.data) }, + counterIdlSha256: fingerprint(Buffer.from(JSON.stringify(counterIdl))), + gatewayIdlSha256: fingerprint(Buffer.from(JSON.stringify(gatewayIdl))), + }; +} diff --git a/packages/core/src/lib/agentic/__tests__/svm-wire-fixture.spec.ts b/packages/core/src/lib/agentic/__tests__/svm-wire-fixture.spec.ts new file mode 100644 index 00000000..cb2a2d6b --- /dev/null +++ b/packages/core/src/lib/agentic/__tests__/svm-wire-fixture.spec.ts @@ -0,0 +1,59 @@ +import { Connection, PublicKey, type AccountInfo } from '@solana/web3.js'; +import { decodeWireCounter, inspectSvmWirePrograms, SVM_WIRE_COUNTER, SVM_WIRE_GATEWAY, SVM_WIRE_PROGRAM } from '../../../../__e2e__/shared/agw-svm-preflight'; + +const gateway = new PublicKey(SVM_WIRE_GATEWAY), program = new PublicKey(SVM_WIRE_PROGRAM); +const loader = new PublicKey('BPFLoaderUpgradeab1e11111111111111111111111'); +const config = PublicKey.findProgramAddressSync([Buffer.from('config')], gateway)[0]; +function fixture() { + const rows = new Map>(); + [gateway, program].forEach((key, i) => { + const programData = new PublicKey(Buffer.alloc(32, i + 1)); + const data = Buffer.alloc(36); data.writeUInt32LE(2); programData.toBuffer().copy(data, 4); + rows.set(key.toBase58(), { data, owner: loader, executable: true, lamports: 1, rentEpoch: 0 }); + const implementation = Buffer.alloc(49); implementation.writeUInt32LE(3); implementation.writeBigUInt64LE(BigInt(42), 4); + rows.set(programData.toBase58(), { data: implementation, owner: loader, executable: false, lamports: 1, rentEpoch: 0 }); + }); + const counter = Buffer.alloc(48); Buffer.from([255, 176, 4, 245, 188, 253, 124, 25]).copy(counter); counter.writeBigUInt64LE(BigInt(7), 8); + rows.set(SVM_WIRE_COUNTER.toBase58(), { data: counter, owner: program, executable: false, lamports: 1, rentEpoch: 0 }); + const data = Buffer.alloc(279); Buffer.from([155, 12, 170, 224, 30, 250, 204, 130]).copy(data); + rows.set(config.toBase58(), { data, owner: gateway, executable: false, lamports: 1, rentEpoch: 0 }); + const rpc = { + getGenesisHash: jest.fn().mockResolvedValue('EtWTRABZaYq6iMfeYKouRu166VU2xqa1wcaWoxPkrZBG'), + getMultipleAccountsInfoAndContext: jest.fn(async (keys: PublicKey[]) => ({ context: { slot: 99 }, value: keys.map((k) => rows.get(k.toBase58()) ?? null) })), + }; + return { rows, rpc, connection: rpc as unknown as Connection }; +} + +describe('unfunded AGW SVM wire fixture gate', () => { + it('records program fingerprints, slot and the actual IDL-decoded counter/config', async () => { + const { connection } = fixture(); + const result = await inspectSvmWirePrograms(connection); + expect(result.counter.value).toBe('7'); expect(result.gatewayConfig.paused).toBe(false); + expect(result.programs).toHaveLength(2); expect(result.programs[0].lastUpgradeSlot).toBe('42'); + expect(result.programs[0].dataSha256).toMatch(/^[0-9a-f]{64}$/); expect(result.slot).toBe(99); + }); + it('rejects an RPC for another cluster before reading account state', async () => { + const { rpc, connection } = fixture(); rpc.getGenesisHash.mockResolvedValue('other-cluster'); + await expect(inspectSvmWirePrograms(connection)).rejects.toThrow('selected devnet'); + expect(rpc.getMultipleAccountsInfoAndContext).not.toHaveBeenCalled(); + }); + it('rejects a non-executable program before reading ProgramData', async () => { + const { rows, rpc, connection } = fixture(); rows.get(gateway.toBase58())!.executable = false; + await expect(inspectSvmWirePrograms(connection)).rejects.toThrow('executable upgradeable'); + expect(rpc.getMultipleAccountsInfoAndContext).toHaveBeenCalledTimes(1); + }); + it('rejects a paused gateway using the actual Config decoder', async () => { + const { rows, connection } = fixture(); rows.get(config.toBase58())!.data[136] = 1; + await expect(inspectSvmWirePrograms(connection)).rejects.toThrow('paused'); + }); + it('rejects a substituted counter owner and an incompatible discriminator', async () => { + const { rows, connection } = fixture(); rows.get(SVM_WIRE_COUNTER.toBase58())!.owner = gateway; + await expect(inspectSvmWirePrograms(connection)).rejects.toThrow('wrong owner'); + expect(() => decodeWireCounter(Buffer.alloc(48))).toThrow('selected IDL'); + expect(() => decodeWireCounter(Buffer.alloc(8))).toThrow('selected IDL'); + }); + it('rejects missing ProgramData rather than treating program metadata as delivery proof', async () => { + const { rows, connection } = fixture(); rows.delete(new PublicKey(Buffer.alloc(32, 1)).toBase58()); + await expect(inspectSvmWirePrograms(connection)).rejects.toThrow('ProgramData'); + }); +}); diff --git a/plan/agw/README.md b/plan/agw/README.md index a3b438bc..fb847bdc 100644 --- a/plan/agw/README.md +++ b/plan/agw/README.md @@ -2,7 +2,7 @@ This package contains the SDK implementation plan, source snapshots, open decisions and validation evidence. Current work is on feat/agw-sdk-v4. Runtime commits are a66ff7d (v4/SVM foundations) and b68bab7 (gas headroom); current validation is linked below. Native/EVM support now uses the checked Donut v4 deployment; old runtime adapters/ABIs/fixtures were removed. All 25 registered AGW scenarios have passing bounded live coverage, including native/UEA identities and Sepolia outbound success/failure. -Latest: [live acceptance and fixes](research/live-acceptance-2026-10-06/README.md), following the [v4 migration](research/v4-implementation-2026-10-06/README.md). The unrestricted full core unit run passes 1,975 tests; the actual-contract harness passes 75. Build and four typechecks pass. Native defaults/raw-offset API/multi-rule selection decisions, absent ref/labels, public SVM integration and release scope remain explicit. +Latest: [live acceptance and fixes](research/live-acceptance-2026-10-06/README.md), following the [v4 migration](research/v4-implementation-2026-10-06/README.md). The unrestricted full core unit run passes 1,981 tests; the actual-contract harness passes 75. Build and four typechecks pass. Native defaults/raw-offset API/multi-rule selection decisions, absent ref/labels, public SVM integration and release scope remain explicit. The public target remains [Notion page 5](notion/5-sdk-agw.md), qualified by [Harsh's replies](product-decisions-2026-10-04.md) and [live comments](research/notion-comments-2026-10-05.md). The [v4 deployment/owner-guide review](research/deployment-review-2026-10-06/README.md) records the supplied deployed wire definitions. Historical adapter-absence statements in that review describe the pre-migration inspection, not current implementation. @@ -16,6 +16,8 @@ Latest validation: [selected differential/race/API/runtime hardening](research/s Before sharing: [October 6 question source recheck](research/question-source-recheck-2026-10-06/README.md) confirms unchanged contract heads and re-inspects live pages 1/5 and All discussions. Drafts now ask only remaining public/release decisions; the Solana fixture is explicitly optional, and internal wire-level validation can proceed independently. +Latest independent work: [live internal Solana wire validation](research/live-svm-wire-2026-10-06/README.md) verifies actual CEA transfer/CPI, receipts/replay and policy refusals. The initial funded run is 2 passed / 1 ten-minute timeout; that request later reached REVERTED and read-only replay verified failed. Public SVM stays gated. [Concrete API proposals](public-api-proposals.md) are ready; Zaryab's fixture request is closed. + ## Start here | Document | Purpose | @@ -33,7 +35,8 @@ Before sharing: [October 6 question source recheck](research/question-source-rec | [Integrator obligations](contract-integrator-obligations.md) | Contract-delegated SDK/product requirements | | [External blockers](external-blockers.md) | Remaining defaults/type clarification and contract/deployment dependencies | | [Questions for Harsh](questions-harsh.md) | Product decisions and recommendations | -| [Questions for Zaryab](questions-zaryab.md) | Ref/label v1 scope, joint Solana review and optional integration fixture | +| [Questions for Zaryab](questions-zaryab.md) | Ref/label v1 scope and joint Solana review; fixture request closed | +| [Public API proposals](public-api-proposals.md) | Concrete Solana input/read and raw-offset/selection choices for review | | [Review summary](review-summary.md) | Consequential independent-review corrections | ## Sources and evidence diff --git a/plan/agw/SOURCES.md b/plan/agw/SOURCES.md index e112cdf8..f9f7a793 100644 --- a/plan/agw/SOURCES.md +++ b/plan/agw/SOURCES.md @@ -10,6 +10,8 @@ Focused October 5 comment review: live All discussions on pages 5 and 1, plus th October 6 pre-sharing source recheck: all twelve saved Notion sources and relevant contract/SDK/sibling documents were searched; live pages 1/5 and All discussions were inspected again. All eight AGW remote branch heads were fetched; deploy-agw remains 10a24f1 and pushAgenticWallet_v3 remains e8db748. [Evidence and narrowed questions](research/question-source-recheck-2026-10-06/README.md). Same-agent capacity is now supplied; send selection remains open. Public Solana representation needs joint review, while a representative fixture is optional. No full Notion export, sibling fetch, new live deployment probe or snapshot hash change is claimed by this pass. +Subsequent October 6 [live SVM wire validation](research/live-svm-wire-2026-10-06/README.md) re-verifies Donut wiring and devnet programs/configuration, records ProgramData fingerprints and proves actual wallet CEA delivery/replay. It closes the external fixture request. The rejected request first returned SDK timeout, later became REVERTED, and read-only replay confirmed failed with returned assets but unchanged policy spend. Public API agreement remains separate. No additional Notion export or contract-source change occurred. + ## Notion inventory | Document | Source | Local snapshot | Authority | diff --git a/plan/agw/current-baseline.md b/plan/agw/current-baseline.md index df8a2691..694f346e 100644 --- a/plan/agw/current-baseline.md +++ b/plan/agw/current-baseline.md @@ -49,7 +49,7 @@ The earlier supplied historical addresses are superseded for new v4 integrations | Multiple rules | Several same-agent/same-chain grants supported | Management permits multiplicity; ambiguous sends fail; H6 selection remains | | Checkpoints | Stored count/last block, three event kinds, per-owner-call/lifecycle ticks | Local and registered live native/EVM lifecycle acceptance pass | | Grant ref / label | Grant has no ref; label is deployment event only; no setLabel | Explicit capability gates; Z1.3 asks v1 scope/delivery | -| SVM | Full multi-asset terms/program/account/data pins supplied | Internal reads, PDA/ATA/metadata/IDL resolution, lifecycle and outbound backend complete; public mapping/dispatch and live destination acceptance remain | +| SVM | Full multi-asset terms/program/account/data pins supplied | Internal live CEA transfer/CPI, replay and policy refusals pass. Initial rejection timed out, then REVERTED/failed replay was verified. Public mapping/dispatch remains gated. | | Gateway request | Eight-field live implementation, selector 0x77b86bec | Dedicated context, listed-token choice and maxGasPerCall implemented | | Allowance | Consume separate owner-established allowance | Keep existing race-safe behavior; Live allowance/token debit passes; remaining identity coverage explicit | | Refund spend credit | creditRevert gains token; executor still does not call it | Known Push-core dependency; ordinary returns do not lower spent | @@ -61,14 +61,14 @@ The ABI comparison found matching factory/wallet/engine function/event/error sig Four checks passed: version-1 envelope round-trip/old first-word incompatibility; synthetic ordered two-asset tuple round-trip; live v4 getConfig decode with old-ABI rejection; array assertion encoding. [Results and limits](research/deployment-review-2026-10-06/wire-checks.json). This is not a rule-grant, stale-spend transaction or funded E2E proof. -The unrestricted run passes 1,975 unit and 75 actual-contract tests. All five explorer ABI sets match the isolated build. Donut is registered and all 25 registered native/EVM/identity cases have passing coverage. [Current acceptance evidence](research/live-acceptance-2026-10-06/README.md). +The unrestricted run passes 1,981 unit and 75 actual-contract tests. All five explorer ABI sets match the isolated build. Donut is registered and all 25 registered native/EVM/identity cases have passing coverage. [Current acceptance evidence](research/live-acceptance-2026-10-06/README.md). ## Remaining decisions and acceptance - Harsh: native PC omission defaults/token intent, raw-offset authoring/read model, multi-rule send selection and joint public Solana representation. Current target retains maxValueTotal. [Open draft](questions-harsh.md). -- Zaryab: ref/label v1 scope, joint Solana SDK review and optional representative SVM fixture. Wire/accounting/deployment delivery requests are removed. [Open draft](questions-zaryab.md). +- Zaryab: ref/label v1 scope and joint Solana SDK review. Z1.4 fixture is closed with our own verified live example. [Open draft](questions-zaryab.md). - SDK: native/EVM migration is implemented and locally validated. Public SVM mapping/composition and release scope decisions remain. No legacy runtime adapter is retained. -- Live: registered native/EVM/UEA/7702 and Sepolia success/failure scenarios pass, including independent CEA execution attribution. Public SVM destination acceptance remains after integration. Authorized testnet transactions are recorded in the live report. +- Live: registered native/EVM/UEA/7702 and Sepolia success/failure scenarios pass. Internal Solana delivery, policy refusals and replay pass; later terminal rejection is verified through read-only replay after the initial ten-minute timeout. Public SVM destination acceptance remains after integration. [Wire evidence and limits](research/live-svm-wire-2026-10-06/README.md). Checkpoint count semantics remain per action, not per transaction: assert/revoke/grant adds five ticks; failed transactions unwind ticks; agent calls do not tick. Pre-existing allowances may change balances without checkpoints. Preserve internal spend assertions even though public spent records are removed. diff --git a/plan/agw/external-blockers.md b/plan/agw/external-blockers.md index 3680d360..37dfc196 100644 --- a/plan/agw/external-blockers.md +++ b/plan/agw/external-blockers.md @@ -12,7 +12,7 @@ Rechecked October 6, 2026 against live Notion pages 1/5 and All discussions, all | Multiple-rule execution | Harsh H6 | Explicit caller rule selection versus a defined automatic strategy, including arrays/overlapping rules; same-agent capacity is supplied | | Metadata scope | Zaryab Z1.3 with Harsh | Whether absent grant ref/editable label will be delivered or explicitly deferred from v1 | -Zaryab Z1.4 is an **optional fixture request**, not a hard dependency. The SDK already has a candidate devnet gateway and counter-program IDL. We can verify their current deployment/compatibility read-only and prepare a bounded wire-level test ourselves. A known-good team fixture would improve independent comparison; this review does not claim those candidate inputs have passed live AGW delivery. +Zaryab Z1.4 is now **closed with SDK-owned evidence**: the configured devnet gateway and counter IDL were checked against actual deployed accounts, and internal AGW delivery/receipt/replay passed. [Live Solana wire report](research/live-svm-wire-2026-10-06/README.md). No external fixture is needed for that baseline. [Concrete public API proposals](public-api-proposals.md) are ready for H4.4/H4.5/H6 review. The owner guide retains assets[] on the rule, with each listed token usable by every allowed call. Harsh's token-independence comment is not treated as permission to remove token limits. SVM wire types are supplied; the remaining fixture request does not reopen struct delivery. @@ -36,9 +36,11 @@ creditRevert still depends on Push-core executor integration; the source explici All 25 registered AGW live scenarios have passing bounded selected-run coverage, including UEA/7702 identities/batching, lifecycle, allowance, response hooks/replay and Sepolia outbound success/failure. This resolves the outstanding native/EVM acceptance tasks; public Solana destinations still need integration and live coverage. External product/scope decisions above remain separate. [Current evidence](research/live-acceptance-2026-10-06/README.md). +**SVM negative acceptance:** the initial ten-minute wait returned timeout while the outbound was pending. The same request subsequently became REVERTED, and read-only SDK replay returned failed with Push status 1. Terminal classification is now supplied/verified; no new hard delivery blocker is inferred. Retry/terminalization timing and richer program-error reporting are optional [operational follow-ups](research/live-svm-wire-2026-10-06/platform-followup.md). Returned funds still do not lower the rule's spend, consistent with the separate creditRevert dependency. + ## Freshness -Fresh fetch confirms AGW source e8db748 and documentation head deploy-agw@10a24f1, with identical src. Explorer-verified ABIs and the earlier pinned RPC probe are saved in the [review bundle](research/deployment-review-2026-10-06/README.md); no new deployment probe in this question pass. Current evidence is 1,975 unit tests, 75 actual-contract tests and 25 registered live scenarios with passing selected-run coverage. [Validation](research/sdk-hardening-2026-10-06/README.md). Core/gateway source pins were not refreshed. +Fresh fetch confirms AGW source e8db748 and documentation head deploy-agw@10a24f1, with identical src. The earlier verified ABIs/probe remain in the [review bundle](research/deployment-review-2026-10-06/README.md); subsequent [wire preflight and acceptance](research/live-svm-wire-2026-10-06/README.md) recheck live wiring and both networks. Full units now pass 1,981; prior unchanged local-contract evidence is 75 passes, and native/EVM live coverage is 25 scenarios. New Solana wire/replay outcomes are recorded separately, including the initial timeout and later terminal failure. Core/gateway source pins were not refreshed. Notion's last full export remains October 3, with October 4 body comparison, October 5 comments and a fresh October 6 live inspection of pages 1/5 and All discussions. The GitHub guide supplies deployed wire behavior; the target public API remains qualified by Harsh's replies. diff --git a/plan/agw/gaps.md b/plan/agw/gaps.md index 0109c97d..3efe33b3 100644 --- a/plan/agw/gaps.md +++ b/plan/agw/gaps.md @@ -2,7 +2,7 @@ Updated October 6, 2026 after the [v4 deployment/owner-guide review](research/deployment-review-2026-10-06/README.md), [Harsh’s replies](product-decisions-2026-10-04.md), v4 implementation on feat/agw-sdk-v4, and [live Notion comments](research/notion-comments-2026-10-05.md). This register distinguishes unresolved dependencies, implemented SDK work, deferred scope and historical corrections. G01–G26 are tracking IDs, not a count of open defects. -Evidence: [current baseline](current-baseline.md), [implementation status](implementation-status.md), [product alignment validation](research/product-alignment-2026-10-04/README.md). The unrestricted v4 SDK run passes 1,975 unit tests and 75 local-contract tests. All 25 registered live scenarios have passing coverage. The independent SDK follow-up adds delayed-index actual-contract checks and consumer documentation; public SVM destinations remain gated. +Evidence: [current baseline](current-baseline.md), [implementation status](implementation-status.md), [product alignment validation](research/product-alignment-2026-10-04/README.md). The unrestricted v4 SDK run passes 1,981 unit tests and 75 local-contract tests. All 25 registered live scenarios have passing coverage. The independent SDK follow-up adds delayed-index actual-contract checks and consumer documentation; public SVM destinations remain gated. Current contract baseline: reported deployed source `e8db748`, documentation head `deploy-agw@10a24f1` (src unchanged between them). Donut v4 addresses/code/wiring and URP 3.1.0 were checked at block 23931055; verified ABIs were saved. The SDK now uses v4 only, registers Donut and has a ported actual-contract harness. [Implementation evidence](research/v4-implementation-2026-10-06/README.md). Core marketplace cb69e0b and gateway bcbf7df remain prior source pins; they were not freshly fetched. Notion bodies were not refreshed in this pass. @@ -16,7 +16,7 @@ Current contract baseline: reported deployed source `e8db748`, documentation hea | Multiple-rule send selection (same-agent capacity is supplied) | [Harsh H6](questions-harsh.md#h6) | G26 | | V1 ref/label scope | [Zaryab Z1.3 with Harsh](questions-zaryab.md#z1-3) | G08 | -The [October 6 source recheck](research/question-source-recheck-2026-10-06/README.md) narrows the questions above. Z1.4's Solana fixture is optional supporting evidence; checking existing SDK gateway/IDL candidates and running an internal wire-level test are SDK-owned work, not blocked on receiving that fixture. +The [October 6 source recheck](research/question-source-recheck-2026-10-06/README.md) narrowed the questions. Subsequent [live wire validation](research/live-svm-wire-2026-10-06/README.md) supplies our own Solana fixture and successful delivery/replay, closing Z1.4. The rejected outbound initially timed out, then reached REVERTED and read-only replay classified it failed. [Concrete API proposals](public-api-proposals.md) are ready; retry/terminalization timing is an operational follow-up. Multi-asset wire/read/assertion ABI, EVM CEA width, envelope version and SVM wire layouts are now supplied. G23/G24 and the native/EVM adapter/registry migration are implemented locally; SVM mapping/live acceptance remain SDK work; do not keep asking for those delivered definitions. @@ -49,7 +49,7 @@ P0 blocks agreed authorization/accounting or safe final integration. P1 affects | G19 | P0/P1 | Universal defaults implemented; H3 native PC choices open | Universal omission uses maxUint256 and explicit zero is hard zero; empty input gets a gas-token 0/0 route. Native PC omission remains provisional at 0. Current live NativeRule retains maxValueTotal; wire sentinel meanings are supplied. | Confirm omitted native PC limits and intended token model; preserve the current field unless an explicit revision is supplied. | | G20 | P1 | V4 composer/response and live EVM acceptance pass | Uses selected listed token, maxGasPerCall, wallet CEA/refund context, separate allowance and signer gas. Local requests pass actual URP with fixture gateway. | Production token debit, node/TSS delivery, CEA execution attribution/balance, replay identity and destination-revert classification pass. Public SVM integration remains tracked under G22. | | G21 | P1 | Product direction resolved; batching implemented locally | NativeRule remains one action. Arrays use a sender-preserving UEA/7702 outer batch of single executeAsAgent calls, each checked by policy. Native sequential fallback is prohibited. Local real-type-4 tests prove sender identity, cumulative counters and mined rollback. | Release-deployment UEA identities and native 7702 batch/rollback cases pass. The local executor is a fixture; arbitrary forwarding helpers are not a substitute for the agent account. | -| G22 | P1 | SVM backend completed; public integration pending | Internal read/context/mint/IDL/lifecycle/execution pipeline is complete. New unit and actual-contract backend tests pass; shared Solana confirmation supports indexer lag. Public capability remains gated. SDK gateway/IDL candidates exist; an external fixture is optional. | H4.4: agree public authoring/read mapping and connect adapters. Independently verify cluster/program inputs and run a wire-level test; then enable the agreed public surface and run public Solana acceptance. | +| G22 | P1 | Internal SVM delivery and terminal replay verified; public integration pending | Actual CEA transfer/CPI, replay and deployed policy refusals pass. Initial rejection wait timed out; the same outbound later became REVERTED and replay returned failed. Public capability stays gated. | H4.4: agree public authoring/read mapping, connect adapters and complete public acceptance. Z1.4 fixture delivery is closed; terminalization timing is an operational follow-up, not a newly inferred delivery blocker. | | G23 | P0 | V4 EVM integration verified locally and live | Multi-asset codecs/reads/outbound, envelope 1, source chain/token identity, hard-zero semantics and empty-input routing are implemented. Old adapter/ABIs/fixtures removed. | Registered EVM acceptance passes. Public SVM SDK mapping/composition remains. | | G24 | P1 | Internal per-token update verified locally and live | Reads/stores every expected counter in asset order; array assertion catches intervening second-token spend. Public spent stays absent. | Live two-asset replacement passes; public SVM integration remains. | | G25 | P1 | Public raw-offset decision open | Exact native pin/amount offsets and EVM beneficiaryOffset are returned/accepted losslessly; no invented argument indexes. This extends the target input shape. | H4.5: public raw authoring versus separate decoded wire records. | @@ -57,7 +57,7 @@ P0 blocks agreed authorization/accounting or safe final integration. P1 affects ## Validation and release boundaries -The [current acceptance evidence](research/live-acceptance-2026-10-06/README.md) records 1,975 passing unit tests, 75 actual-contract tests, build/four typechecks and seven existing lint errors. All 25 opt-in AGW scenarios have passing bounded selected-run coverage; default all remains 76. Native/UEA/7702, lifecycle, allowance, responses and Sepolia success/failure pass. The initial positive-amount Push transaction exposed insufficient gas headroom. A tested 20% headroom fix passes the bounded retry, including token debit, allowance reduction, destination receipt/CEA balance and replay checks. Destination-revert classification also passes. +The [current acceptance evidence](research/live-acceptance-2026-10-06/README.md) records 1,981 passing unit tests, 75 actual-contract tests, build/four typechecks and seven existing lint errors. All 25 opt-in AGW scenarios have passing bounded selected-run coverage; default all remains 76. Native/UEA/7702, lifecycle, allowance, responses and Sepolia success/failure pass. The initial positive-amount Push transaction exposed insufficient gas headroom. A tested 20% headroom fix passes the bounded retry, including token debit, allowance reduction, destination receipt/CEA balance and replay checks. Destination-revert classification also passes. Local batch proof uses actual AGW/factory/engine/policy and real Anvil EIP-7702 transactions, with a small fixture executor. UEA shaping/replay is unit-tested and reuses the existing transport; all registered native/EVM/UEA acceptance scenarios now pass. Public Solana destination coverage remains outstanding. diff --git a/plan/agw/implementation-plan.md b/plan/agw/implementation-plan.md index 5de1a5f1..5e90616b 100644 --- a/plan/agw/implementation-plan.md +++ b/plan/agw/implementation-plan.md @@ -1,6 +1,6 @@ # Complete AGW SDK implementation plan -Updated October 6, 2026. The v4-only native/EVM implementation uses deployed source e8db748 and the Donut manifest. Old runtime/test adapters and single-asset codecs are removed. The unfiltered unit suite passes 1,975 tests; all 75 actual-contract Anvil cases pass; build and four typechecks pass. All 25 registered AGW live scenarios pass across selected runs; remaining work is public SVM integration and release scope decisions. [Current acceptance and remaining coverage](research/live-acceptance-2026-10-06/README.md). +Updated October 6, 2026. The v4-only native/EVM implementation uses deployed source e8db748 and the Donut manifest. Old runtime/test adapters and single-asset codecs are removed. The unfiltered unit suite passes 1,981 tests; all 75 actual-contract Anvil cases pass; build and four typechecks pass. All 25 registered AGW live scenarios pass across selected runs; remaining work is public SVM integration and release scope decisions. [Current acceptance and remaining coverage](research/live-acceptance-2026-10-06/README.md). SVM internal terms/accounts/payload/builder are implemented and validated. Public SVM mapping/dispatch remains gated. Remaining decisions are H3 native defaults, H4.5 raw-offset public shape, H6 send selection and ref/label v1 scope. Earlier plan recommendations below are qualified by those accepted decisions and the current implementation status. diff --git a/plan/agw/implementation-status.md b/plan/agw/implementation-status.md index 3d16fed0..798f0e03 100644 --- a/plan/agw/implementation-status.md +++ b/plan/agw/implementation-status.md @@ -1,6 +1,6 @@ # AGW SDK implementation status -> Latest: [funded acceptance and fixes](research/live-acceptance-2026-10-06/README.md). Full permissions are restored: 1,975 unfiltered unit tests, all 75 Anvil cases, build and four typechecks pass. All 25 registered AGW scenarios pass across selected live runs, including UEA identities, native 7702 batches, lifecycle and Sepolia success/failure. Public SVM destinations remain gated. +> Latest: [funded acceptance and fixes](research/live-acceptance-2026-10-06/README.md). Full permissions are restored: 1,981 unfiltered unit tests, all 75 Anvil cases, build and four typechecks pass. All 25 registered AGW scenarios pass across selected live runs, including UEA identities, native 7702 batches, lifecycle and Sepolia success/failure. Public SVM destinations remain gated. Updated October 6, 2026. Branch feat/agw-sdk-v4; runtime commits a66ff7d and b68bab7. The native/EVM migration uses deployed source e8db748. Runtime/test e704d5b adapters, ABIs and fixtures were removed at Shoaib's request; historical review documents are evidence only. [Full handoff, commands and validation](research/v4-implementation-2026-10-06/README.md). @@ -8,7 +8,7 @@ Updated October 6, 2026. Branch feat/agw-sdk-v4; runtime commits a66ff7d and b68 | Level | Current evidence | | --- | --- | -| Unit | 1,975 passed, 0 failed; 12 skipped; 115 suites passed, 1 skipped | +| Unit | 1,981 passed, 0 failed; 12 skipped; 115 suites passed, 1 skipped | | Local actual contracts | 75 passed, 0 failed; 10 suites against e8db748 on Anvil | | ABI reproduction | All 5 explorer ABI entry sets match the isolated build, ignoring array order | | Runtime matrix | Node 20.19.2 and 24.14.0 pass full units, local contracts and package/API checks | @@ -34,7 +34,7 @@ Local gateway/core/token/executor and CEA lookup are fixtures. Actual AGW/factor | 9 | Owner/allowance | Owner path unrestricted; explicit separate allowance retained | Release review; production allowance/token debit and delivery verified | | 10 | Native agent sends | Sender-preserving atomic batches retained | H6 selection for multiple matching rules | | 11 | EVM outbound | V4 asset membership, maxGasPerCall, wallet CEA/refunds, signer gas and responses | Release review; Sepolia success/failure and UEA cases verified | -| 12 | SVM destinations | Source wire types delivered; SDK capability remains gated | Internal reads/context/IDL/wire lifecycle/execution complete; public mapping/display/dispatch enablement and live cluster acceptance | +| 12 | SVM destinations | Internal live positive delivery and later terminal-rejection replay verified; public capability gated | Public mapping/display/dispatch agreement, adapters and public acceptance; rejection retry timing is documented separately | | 13 | Responses/progress/errors | V4 ABIs and prior canonical replay/wait fixes retained | Delayed-index replay/polling tested with real contracts/receipts; no remaining SDK-owned response gap | | 14 | E2E | 25 opt-in scenarios registered; public universal setup and new two-token/call-only cases | Completed native/EVM live coverage; public SVM acceptance after integration | | 15 | Web2 | Prior implementation retained and included in full unit run | Consumer migration notes supplied; existing Web2 unit acceptance passes | @@ -45,6 +45,6 @@ Local gateway/core/token/executor and CEA lookup are fixtures. Actual AGW/factor A01 approval policy, A04 internal generation details, A06 history deferral and A08 compiler scope remain settled. A02 native batching is implemented locally. A05 wire/accounting is delivered and implemented for EVM. A07 deployment/registry is supplied; grant ref and editable label remain absent and capability-gated. -H3 is narrowed to native omission defaults/public maxValueTotal and token wording; universal total semantics are implemented. H4.5 covers native pins/amount and the exact EVM beneficiaryOffset read/write form. H6 remains send selection, not management capacity. [Harsh draft](questions-harsh.md); [Zaryab metadata/SVM fixture draft](questions-zaryab.md). +H3 is narrowed to native PC omission defaults/token wording; current target retains maxValueTotal. H4.4 is joint public SVM representation, with [concrete proposals](public-api-proposals.md) ready. H4.5 covers raw-offset representation, and H6 send selection. [Harsh draft](questions-harsh.md); [Zaryab metadata draft](questions-zaryab.md). The fixture request is closed with [our live wire evidence](research/live-svm-wire-2026-10-06/README.md), including later terminal rejection after the initial timeout. No public spent/history/compiler feature is reopened. Rule updates reset counters as agreed. Ordinary inflows do not restore spent; creditRevert remains a platform dependency. diff --git a/plan/agw/public-api-proposals.md b/plan/agw/public-api-proposals.md new file mode 100644 index 00000000..eaeabad5 --- /dev/null +++ b/plan/agw/public-api-proposals.md @@ -0,0 +1,110 @@ +# AGW public API proposals for team review + +October 6, 2026. These are proposals for H4.4/H4.5/H6, not implemented public contracts. Native/EVM methods remain as implemented; public Solana capability stays gated. The [source recheck](research/question-source-recheck-2026-10-06/README.md) separates supplied wire definitions from these remaining SDK choices. + +## H4.4 Solana rule inputs and decoded records + +Recommend a Solana-specific member of Rule, selected by `chainNamespace: solana:*`. Keep the existing lifecycle methods and shared agent/expiry/asset/gas fields. Do not make callers supply the gateway or wallet CEA: resolve the configured cluster, derive the CEA and every protected input/output ATA internally. + +For public authoring, recommend IDL instruction/account/field inputs. The SDK compiles them into the supplied program/account/data constraints. Explicit raw wire authoring is an alternative requiring agreement; it is already available internally for acceptance tests, not a root export. + +The following is a proposed input sketch, not a current SDK example: + +```ts +type SvmAddress = string; // validated base58, or explicitly supported 32-byte hex +type SvmAccountRef = + | { kind: 'walletCEA' } + | { kind: 'walletATA'; token: SvmAddress } + | { kind: 'address'; address: SvmAddress }; + +interface SvmInstructionRule { + program: SvmAddress; + instruction: { idl: SvmIdl; name: string }; + accounts: { name: string; expected: SvmAccountRef }[]; + fields?: ( + | { name: string; equals: Hex | bigint } + | { name: string; min: bigint } + | { name: string; max: bigint } + | { numerator: string; denominator: string; minRatio: { num: bigint; den: bigint } } + )[]; +} + +interface SolanaRuleInput { + agent: Address; + chainNamespace: `solana:${string}`; + validUntil: number; + assets: { token: MoveableToken | SvmAddress; maxPerCall: bigint; maxTotal?: bigint }[]; + maxGasPerCall: bigint; + outputTokens?: SvmAddress[]; + allowedInstructions: SvmInstructionRule[]; +} +``` + +Output tokens are separate derivation inputs: they must contribute protected ATAs even if the rule only spends its input tokens. An output declaration is not a guarantee that the instruction pays it; the instruction's actual value-carrying accounts and relevant data fields still need pins. + +Compilation requirements: + +- Resolve instruction discriminators and exact account ordering from the selected IDL; pin the CEA and every value-carrying account. Refuse layouts that cannot be identified reliably. +- Record the source IDL hash in SDK evidence. There is no delivered grant ref/hash field to claim this is stored on-chain; durable metadata is a separate decision. +- Apply the delivered aggregate caps: 8 assets, 32 program entries, 16 account pins, 8 data pins and 16 protected CEA accounts. Each program entry needs a pin, so the aggregate pin cap can limit the practical instruction count below 32. +- Map fixed unsigned fields of at most eight bytes to GTE_LE/LTE_LE, exact byte values to EQ, and supported paired fields to RATIO_GTE_LE. Verify offsets from the actual layout; two variable-length regions are not guessed through. +- Preserve account/data constraints on reads. An on-chain discriminator/offset does not reconstruct an IDL or named field; a decoded record must use exact keys, indexes and offsets unless a separately verified IDL is supplied. +- Keep instruction execution on the normal sendTransaction surface after agreement. One SVM outbound contains one instruction; do not promise a destination instruction array the delivered wire format cannot represent. + +Recommend `RulesRecord.rule` become a discriminated decoded union, including the stored SVM programs, account/data pins and protected accounts. Authoring and decoding should have distinct names; decoded records are not silently passed through the IDL authoring compiler. A conversion helper would need verified IDL/context. Public spend, revoked history and marketplace compilation remain excluded. + +**Decision for Harsh/Zaryab:** adopt the IDL-authoring/explicit-decoded model above, or approve explicit raw constraints as a public authoring alternative. Base58/hex acceptance and non-Anchor instructions must be stated with the selected model. The SDK team will implement and test the selected representation; the delivered wire types do not need redesign. + +## H4.5 Native/EVM raw authoring and decoding + +The current implementation accepts both argument-index and raw-offset authoring, and always reads exact offsets. That is lossless and tested, but extends the latest page-5 shape. The historical SDK used offsets; it does not by itself approve the current public API. + +Two concrete choices: + +| Choice | Inputs | Decoded rules | Compatibility/work | +| --- | --- | --- | --- | +| Keep current dual form | `pins: {arg, expected}` or `{offset, expectedWord}`; amount uses arg or offset; EVM beneficiary uses argument index or beneficiaryOffset | Exact raw offsets/words | Smallest implementation delta; reads can round-trip into add/update. Caller-authored offsets lack ABI semantic validation. | +| Separate input/decoded forms | Public new authoring uses ABI argument indexes; raw wire values remain a decoded type | `DecodedNativeRule` / `DecodedEvmRule` retain exact offsets | More explicit validation boundary; changes RulesRecord.rule type and requires an explicit conversion/reuse story. | + +If the current dual form is chosen, keep exact word validation and integer bounds, reject conflicting index/offset fields, and prefer ABI generation in examples. The SDK must not claim that an arbitrary raw offset pins a particular named argument. + +If separate forms are chosen, do not reconstruct `arg = (offset - 4) / 32`: that assumes a layout that storage does not prove. Keep decoded values exact and specify how an owner reuses an existing rule with a verified ABI. + +**Recommendation:** retain the tested dual form for this SDK revision if product accepts explicit low-level authoring. If public authoring must be ABI-only, use separate decoded records across native/EVM/SVM rather than losing wire information. This choice does not re-open H1's UI/marketplace-owned approval-screening policy. + +## H6 Rule selection for sends + +Recommend an explicit optional selector in per-send options. A single candidate still works without it; multiple candidates require an explicit ID. Selection is never cached at initialize and never based on remaining budget, expiry, grant order or trying several paid transactions. + +Proposed examples, not current supported options: + +```ts +await agent.universal.sendTransaction( + { to: target, data }, + { agentic: { rulesId } }, +); + +await agent.universal.sendTransaction( + { to: wallet, data: [nativeCallA, nativeCallB] }, + { agentic: { rulesIds: [idA, idB] } }, +); +``` + +The exact containing options type is an implementation detail to align with core. The important public contract is one ID for a single action/outbound and an ordered ID list only for an outer native batch. + +| Request | Selection | +| --- | --- | +| Single Push-native action | One optional rulesId | +| Native array | Ordered rulesIds, one per item; alternatively one rulesId reused for every item | +| EVM destination call array | One rulesId for the entire gateway outbound; no merging of permissions from different rules | +| SVM destination | One rulesId for the single instruction/outbound | + +Validation before signing: the selected ID is currently enabled on the selected wallet, names the signer's Push identity and matches the destination chain. Refuse mixed selector forms, count mismatches and selector use outside the agent door. The on-chain policy remains the action/budget/expiry authority. A rule revoked after lookup still fails on-chain; a selector does not lock contract state. + +Native batches retain sender-preserving UEA/7702 execution and atomic rollback. If several IDs are allowed in one batch, internal replay currently assumes one common ID and must be extended deliberately. Proposal: keep existing metadata.rulesId for a single/common ID and add ordered metadata.rulesIds only for a heterogeneous native batch. Preserve origin and raw transport fields. + +**Decision for Harsh:** approve explicit per-send selection, including the native-array and metadata semantics above, or specify a deterministic automatic strategy. Current management permits multiplicity; current ambiguous sends fail before signing with candidate IDs. + +## Boundaries + +These proposals introduce public types/options and need agreement before being advertised. Internal wire-level tests can continue independently. H3's native PC omission defaults and token-model wording, plus Z1.3's ref/label release scope, remain separate. Nothing here adds compileCard, public accounting, historical reconstruction or a legacy adapter. diff --git a/plan/agw/questions-harsh.md b/plan/agw/questions-harsh.md index e5660531..4419e1b7 100644 --- a/plan/agw/questions-harsh.md +++ b/plan/agw/questions-harsh.md @@ -9,6 +9,8 @@ Rechecked October 6, 2026 against all twelve saved Notion pages, your replies, l | [H4.5](#h4-5) | Public raw-offset authoring versus separate decoded records | | [H6](#h6) | Choosing a rule for a send when several match | +[Concrete API proposals](public-api-proposals.md) provide input/decoded-type and rule-selection examples for review. The internal [live Solana wire validation](research/live-svm-wire-2026-10-06/README.md) now proves positive delivery and replay; public SVM remains gated. + ## Source check The live [SDK page](https://app.notion.com/p/pushprotocol/5-SDK-AGW-3e9188aea7f481cf8e8de324956549b9) still has optional native maxValueTotal, argument-index inputs and the older unique-rule lookup wording. Its visible active/resolved discussions supply no further answer to the questions below. This was a live inspection, not a new Markdown export; the last full export remains October 3. @@ -40,9 +42,9 @@ Your earlier reply assigned SVM work to Zaryab. The SVM contract rulebook and it **Decision needed:** agree how those constraints appear in public Rule inputs and rules.get/list results. The current live AllowedCall is EVM-shaped: address target, function selector and beneficiary argument index. It does not represent Solana programs, instruction discriminators, account pins or instruction-data pins. -**SDK proposal for review:** add a Solana-specific Rule variant selected by its solana: chainNamespace, keep asset caps/expiry/gas fields, and expose program/instruction constraints with account/data pins. Gateway, wallet CEA and protected token-account derivation stay internal. Confirm whether callers may provide explicit constraints in this variant, or whether public authoring must use higher-level IDL/account/field inputs that the SDK compiles. The decoded result must preserve the stored constraints without inventing an IDL. +**SDK proposal for review:** add a Solana-specific Rule variant selected by its solana: chainNamespace, keep asset caps/expiry/gas fields, and compile IDL instruction/account/field inputs into program/account/data constraints. Gateway, wallet CEA and protected token-account derivation stay internal. Confirm that model, or approve explicit constraints as a public authoring alternative. The decoded result must preserve stored constraints without inventing an IDL. [Types and examples](public-api-proposals.md#h44-solana-rule-inputs-and-decoded-records). -This is a public SDK design agreement, not missing contract support. We can validate internal wire-level delivery independently. A representative fixture is optional supporting input in [Z1.4](questions-zaryab.md#z1-4). +This is a public SDK design agreement, not missing contract support. We have supplied our own verified gateway/program/account/payload fixture, successful live wire execution and later terminal-rejection replay, so no external fixture is needed to unblock this design review. Retry timing has an optional [operational follow-up](research/live-svm-wire-2026-10-06/platform-followup.md). @@ -68,4 +70,4 @@ Lifecycle validation is already aligned with multiple rules. The SDK reports AMB ## Supporting context -Native array implementation is validated locally and on Donut through sender-preserving UEA/7702 batching. Universal/SVM wire definitions and deployment are supplied; all 25 registered native/EVM live scenarios have passing coverage. Public SVM mapping and live destination acceptance remain. [Zaryab's draft](questions-zaryab.md) asks about metadata release scope and labels its SVM fixture request optional. compileCard and revoked history remain outside standalone AGW v1. +Native array implementation is validated locally and on Donut through sender-preserving UEA/7702 batching. Universal/SVM wire definitions and deployment are supplied; all 25 registered native/EVM live scenarios have passing coverage. Internal Solana delivery/replay and later terminal-rejection classification are verified; its initial ten-minute timeout is retained as evidence. Public SVM mapping/acceptance remains. [Zaryab's draft](questions-zaryab.md) asks only about metadata release scope and links this joint API review. compileCard and revoked history remain outside standalone AGW v1. diff --git a/plan/agw/questions-zaryab.md b/plan/agw/questions-zaryab.md index bba4c9a5..9a9ab7fb 100644 --- a/plan/agw/questions-zaryab.md +++ b/plan/agw/questions-zaryab.md @@ -2,12 +2,11 @@ Rechecked October 6, 2026 against all saved Notion sources, live pages 1/5 and their All discussions, freshly fetched contract branches, the owner guide and SDK code. [Evidence and dispositions](research/question-source-recheck-2026-10-06/README.md). Multi-asset terms, envelope, EVM CEA width, accounting ABI, SVM wire definitions and deployment are supplied; those questions are closed. No questions have been sent. -Only Z1.3 needs a contract release-scope answer. Z1.4 is optional supporting evidence, not a requirement to start our wire-level testing. The public Solana SDK representation needs joint review under [Harsh H4.4](questions-harsh.md#h4-4). Deployment/address coordination is complete; adapter integration and funded acceptance are SDK work. +Only Z1.3 needs a contract release-scope answer. We supplied and live-validated our own SVM fixture, so Z1.4 is removed. The public Solana SDK representation needs joint review under [Harsh H4.4](questions-harsh.md#h4-4); [concrete proposals](public-api-proposals.md) are ready. Deployment/address coordination is complete. | Item | Remaining answer | | --- | --- | | [Z1.3](#z1-3) | Ref/label scope for this release | -| [Z1.4](#z1-4) | Optional representative SVM integration fixture | ## Source baseline @@ -29,20 +28,10 @@ The generation still exposes grantRules(Session) without ref, and RulesGranted c **Decision needed:** are rule ref and editable labels included in this release, or explicitly deferred from v1 with Harsh? If included, confirm that the existing page-1 proposal is still the target and announce the compatible source/ABI when ready. Signed grants must bind the ref as part of their authorized contents. We will keep absent capabilities explicit until the agreed scope and delivered ABI match. Checkpoint event ref is a rulesId/action hash; it is not the missing job ref. - - -### Z1.4 Optional SVM example to validate the SDK mapping - -SvmTerms/program/account/data-pin definitions and PDA/ATA responsibilities are supplied. Our internal SDK backend is implemented and actual-contract tests pass. We are not asking for those definitions again. If available, please share a known-good Donut-to-Solana fixture covering: - -- Cluster CAIP-2 value and gateway program/registry source. -- Destination CEA and protected token/output accounts, with their derivation inputs. -- A valid encoded envelope and outbound payload for one allowed instruction; expected account/data-pin matches and corresponding failure cases. - -The SDK already contains a Solana-devnet gateway setting and a counter-program IDL, so we can perform read-only preflight and build a bounded wire-level test ourselves. Their current deployment/compatibility still needs verification. Your fixture would provide a useful independent comparison, not unblock missing backend work. Contract SVM tests use synthetic keys and do not prove live destination settlement. - ## Product choices kept separate [Harsh's draft](questions-harsh.md) retains native PC defaults/token wording, raw-offset authoring, multi-rule send selection and the joint public-Solana representation decision. The new guide confirms same-agent/same-chain multiplicity; it does not choose a send selection API. No public spend, revoked-history or compileCard request is reopened. +The [Solana wire evidence](research/live-svm-wire-2026-10-06/README.md) proves positive delivery/replay and later terminal-rejection classification. Its initial ten-minute timeout is retained; retry timing is an optional [operational follow-up](research/live-svm-wire-2026-10-06/platform-followup.md), separate from the contract scope question above. + [Implementation plan](implementation-plan.md) · [External dependencies](external-blockers.md) · [Current baseline](current-baseline.md) diff --git a/plan/agw/research/live-svm-wire-2026-10-06/README.md b/plan/agw/research/live-svm-wire-2026-10-06/README.md new file mode 100644 index 00000000..5654ab32 --- /dev/null +++ b/plan/agw/research/live-svm-wire-2026-10-06/README.md @@ -0,0 +1,80 @@ +# Live AGW Solana wire acceptance + +October 6, 2026. Internal SVM backend against verified Donut v4 contracts and Solana devnet. Public Solana Rule inputs/capability are still gated; no native/EVM behavior, public method, default, selector option or export changed. + +## Outcome + +| Work | Result | +| --- | --- | +| Read-only network/program preflight | Pass: Donut wiring/URP 3.1.0, devnet genesis, executable gateway/counter programs, ProgramData fingerprints, unpaused gateway Config and decoded counter | +| Positive internal outbound | Pass: actual Solana counter CPI plus System transfer from the AGW-derived CEA to the pinned owned recipient | +| SDK preflight refusals | Pass: substituted account / excessive instruction amount fail without advancing the agent nonce | +| Deployed policy refusals | Pass: read-only eth_call bypasses SDK validation and obtains SvmAccountPinMismatch and SvmDataCeilingExceeded, wrapped/truncated by SmartSession | +| Receipt/replay | Pass: wallet from, agent origin, SVM route, same external signature on replay and wait | +| Destination-error acceptance | Initial 600-second wait timed out; the same outbound later became REVERTED and read-only SDK replay returned failed, preserving Push status 1 | +| Concrete public API proposals | [Prepared for H4.4/H4.5/H6](../../public-api-proposals.md); no proposed public type/option enabled | + +The initial funded suite result is **2 passed, 1 failed**: its strict terminal-failure assertion received timeout at ten minutes. The platform subsequently published REVERTED for that exact outbound, and read-only replay confirmed failed without another funded submission. The failed assertion remains strict; its future bounded terminalization window is extended to twenty minutes. A full second funded run is not claimed. [Operational timing follow-up](platform-followup.md). Public SVM E2E coverage still requires the agreed public adapters. + +The follow-up **read-only E2E group passes 3/3** against these recorded transactions: success/identity/signature, terminal rejection/charged spend and deployed policy refusals. It performs no signing or funding. [Jest result](logs/replay.log). + +## Actual delivery + +- Push transaction: [0x50a96ff8…ee73b8](https://donut.push.network/tx/0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8), block 23949837. +- Solana transaction: [kGUaPUfA…PXKgK](https://explorer.solana.com/tx/kGUaPUfASg9Poo93aMsztHJjUk27MKuRJBfDZK1WP3FFSaXSYcoPcxjUMFyDxaK6aU6mQkZeowSu3MtvK5PXKgK?cluster=devnet). +- Wallet: 0x4612ad240cd66A77b921693BbbB356d1B8219b2c. +- CEA: Fuas2d6gmyPEpKgvBEHGhNgu99Nx8xVWmmf6cVFp4feY, derived from this wallet's 20 bytes under the configured gateway. +- Rules ID: 0x0ed59a0b2764cf395b53a7a7d1b58e2ae3fb99b818be5392f3fdbc7eb4f645d0. +- Destination program: 8yNqjrMnFiFbVTVQcKij8tNWWTMdFkrDf9abCGgc2sgx; counter PDA 6Kg1NF5RRytjGwR6USttBLEYJrqwm65xtJzdPbbFwJKg. +- Actual instruction: receive_sol(10000), with counter, pinned owned recipient, wallet CEA and System program accounts. + +The parsed transaction independently shows the counter program's inner instruction with the exact discriminator/amount and the wallet CEA account, and a System transfer of **10,000 lamports** from that CEA to the pinned recipient. The shared counter increased by at least this amount. Attribution relies on this transaction's CPI/transfer, not only a global counter change. Push-side policy spent increased; the agent call did not tick checkpoints. Replay resolved the same Solana signature. + +[Public live evidence](live-evidence.json) includes setup, receipt, parsed destination transaction, replay and initial timeout records. [Read-only replay](readonly-replay.json) separately verifies the wallet from, actual agent CAIP-10 origin, successful signature and later terminal failure. These contain public addresses/signatures and wire terms only; signer keys are not recorded. + +## Fixture and funding boundaries + +Preflight recorded Donut block 23949601 and Solana slot 508014048. The gateway is CFVSincHYbETh2k7w6u1ENEkjbSLtveRCEBupKidw2VS. The local sibling counter source declares a different program ID, so it was not used as proof of deployed binary equivalence. We fingerprinted live ProgramData and verified actual instruction behavior against the selected SDK IDL. + +Setup creates a fresh owner-controlled AGW and a fresh native agent. It checks cluster/program/configuration and funding prerequisites before setup funding. Agent funding is at most 0.5 PC; wallet receives 41 PC for two outbounds capped at 20 PC each plus reserve; exactly 20,000 pSOL base units are funded/approved. No origin-chain deposit or Solana signing is needed; the existing Solana key is used internally only to identify the owned recipient. Each source send uses the separate owner-established allowance. No agent approval is inserted. + +Two source outbounds were submitted: positive and intentional destination rejection. The first live attempt failed in the new test's module bootstrap before any funding; its log is retained. The corrected attempt funded one fixture and submitted those two outbounds. Subsequent policy probes, rejection simulation, spend checks and replay were read-only; the rejected transaction was not rebroadcast. Unused PC remains in the owner-controlled wallet. The fresh agent key is not retained in the committed evidence. + +## Negative evidence and limitation + +The intended failure calls decrement(1) using the wallet CEA against a counter owned by a different authority. Solana read-only simulation independently returns custom error 6002/Unauthorized, with the actual counter authority and wallet CEA in its logs. It does not send a transaction or charge the simulated fee. [Simulation](destination-rejection-simulation.json). + +The actual Push outbound [0x51e2227e…410fc](https://donut.push.network/tx/0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc), block 23949885, succeeded. The first captured node state was PENDING without a hash/error, and the SDK's ten-minute wait accurately returned timeout. The [later record](failure-observation-final.json) is REVERTED (3), observed success=false and error "tx not executed on destination chain", with no Solana hash. Read-only SDK replay accurately returns failed; a missing destination hash is legitimate for a pre-broadcast rejection. + +The later record reports successful asset/gas refund executions at block 23950149. At block 23950160 the rule's pSOL spent is still 20,000. [Final accounting](terminal-accounting.json), block 23950641, independently checks returned wallet balance=10,000, allowance=0 and spent=20,000. Returning funds does not restore the rule budget: the separately documented creditRevert platform dependency remains. + +Direct deployed-URP probes at block 23949837 independently refuse account and instruction-data mutations. [Results](live-policy-probes.json). These were added to the final reusable E2E source after the funded run and exercised separately against its pinned historical state; no second funded run is claimed. + +## Code and validation + +- New opt-in agw-svm-wire group: 3 funded scenarios in one spec; agw-svm-replay: 3 read-only recorded-transaction scenarios in another spec. Default all remains 76 scenarios/81 tests; public AGW group remains 25 scenarios. +- Fixture preflight records account owners, discriminators, ProgramData hashes/upgrade slots, cluster genesis and Config paused state. Six unit cases cover substituted/missing/paused/wrong-cluster prerequisites. +- A shared eth_call probe verifies actual policy refusals independently of the SDK validator. +- Full units: **1,981 passed**, 12 existing skips; library/spec typechecks and core build pass. Changed-file lint has 0 errors and 21 non-null assertion warnings. No production library code changed; the earlier 75 local-contract cases were not rerun for this fixture-only change. +- Existing public replay adaptation is applied to the internal raw signer response, using the gateway wire call as the logical summary. That enables normal outbound wait without inventing public Solana instruction-display fields. + +[Logs](logs/): live-initial.log (unfunded bootstrap error), live-bootstrap-fixed.log (initial 2/1 funded result), replay.log (read-only acceptance), unit.log, lint.log. The funded runner redacts credential environment values before saving/printing logs. Its ten-minute timeout is retained as evidence; no timeout was relabeled failed or counted as a passing funded run. + +## Reproduction + +Read-only, no keys loaded: + +```sh +cd packages/core +node ../../node_modules/ts-node/dist/bin.js --transpile-only __e2e__/ci/agw-svm-preflight.ts ../../plan/agw/research/live-svm-wire-2026-10-06/preflight.json +node ../../node_modules/ts-node/dist/bin.js --transpile-only __e2e__/ci/run.ts --verify --group agw-svm-wire +node ../../node_modules/ts-node/dist/bin.js --transpile-only __e2e__/ci/run.ts --group agw-svm-replay +``` + +Funded opt-in run from the repository root, using the existing authorized testnet environment internally: + +```sh +node plan/agw/research/live-svm-wire-2026-10-06/run-redacted.cjs live.log +``` + +The replay group never signs or funds and can check these recorded hashes independently. Repeating the funded suite creates/funds a fresh fixture. Public Solana authoring/dispatch acceptance remains a later task after H4.4; this wire suite is an independent contract/node/destination proof. diff --git a/plan/agw/research/live-svm-wire-2026-10-06/destination-rejection-simulation.json b/plan/agw/research/live-svm-wire-2026-10-06/destination-rejection-simulation.json new file mode 100644 index 00000000..ce849df0 --- /dev/null +++ b/plan/agw/research/live-svm-wire-2026-10-06/destination-rejection-simulation.json @@ -0,0 +1,58 @@ +{ + "at": "2026-10-06T07:32:23.955Z", + "wallet": "0x4612ad240cd66A77b921693BbbB356d1B8219b2c", + "cea": "Fuas2d6gmyPEpKgvBEHGhNgu99Nx8xVWmmf6cVFp4feY", + "program": "8yNqjrMnFiFbVTVQcKij8tNWWTMdFkrDf9abCGgc2sgx", + "readOnlySimulation": true, + "transactionsSent": 0, + "slot": 508018651, + "result": { + "accounts": null, + "err": { + "InstructionError": [ + 0, + { + "Custom": 6002 + } + ] + }, + "fee": 5000, + "innerInstructions": null, + "loadedAccountsDataSize": 280057, + "loadedAddresses": { + "readonly": [], + "writable": [] + }, + "logs": [ + "Program 8yNqjrMnFiFbVTVQcKij8tNWWTMdFkrDf9abCGgc2sgx invoke [1]", + "Program log: Instruction: Decrement", + "Program log: AnchorError caused by account: counter. Error Code: Unauthorized. Error Number: 6002. Error Message: Unauthorized.", + "Program log: Left:", + "Program log: BesWssuCiGE3EqeGRFamuouvAxJDUCdWH6NPHpAFPMBa", + "Program log: Right:", + "Program log: Fuas2d6gmyPEpKgvBEHGhNgu99Nx8xVWmmf6cVFp4feY", + "Program 8yNqjrMnFiFbVTVQcKij8tNWWTMdFkrDf9abCGgc2sgx consumed 5387 of 200000 compute units", + "Program 8yNqjrMnFiFbVTVQcKij8tNWWTMdFkrDf9abCGgc2sgx failed: custom program error: 0x1772" + ], + "postBalances": [ + 615335949, + 4280640, + 1141440, + 0 + ], + "postTokenBalances": [], + "preBalances": [ + 615340949, + 4280640, + 1141440, + 0 + ], + "preTokenBalances": [], + "replacementBlockhash": { + "blockhash": "EyLpG12Ns8fdRbN6CzowR5CYRU6TPErXvwHRNf4ojYYQ", + "lastValidBlockHeight": 495260925 + }, + "returnData": null, + "unitsConsumed": 5387 + } +} \ No newline at end of file diff --git a/plan/agw/research/live-svm-wire-2026-10-06/failure-observation-final.json b/plan/agw/research/live-svm-wire-2026-10-06/failure-observation-final.json new file mode 100644 index 00000000..295c3a22 --- /dev/null +++ b/plan/agw/research/live-svm-wire-2026-10-06/failure-observation-final.json @@ -0,0 +1,74 @@ +{ + "at": "2026-10-06T07:49:02.484Z", + "id": "f328cfa0af8a4e50afc3648205161759c02f1d0ddd27c40ba25f15990d084f36", + "record": { + "universalTx": { + "id": "f328cfa0af8a4e50afc3648205161759c02f1d0ddd27c40ba25f15990d084f36", + "pcTx": [ + { + "txHash": "0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc", + "sender": "0xDfFb9e4cc2b869cF35ab811675333f40cD04dF76", + "gasUsed": 417241, + "blockHeight": 23949885, + "status": "SUCCESS", + "errorMsg": "" + } + ], + "outboundTx": [ + { + "destinationChain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "recipient": "0x7673075a980bfd5d6b1dffe99c31f63e8938519cc1c2af009dda5e568a94460d", + "amount": "10000", + "externalAssetAddr": "0x0000000000000000000000000000000000000000", + "prc20AssetAddr": "0x5D525Df2bD99a6e7ec58b76aF2fd95F39874EBed", + "sender": "0x4612ad240cd66A77b921693BbbB356d1B8219b2c", + "payload": "0x000000024f12fe6816ae7e33ebf7db0b154ec3b09e3bf1a7690481e8e9477d5a278ad3af01dd7c1b885eb85dbac2db2a4ce5887489200c20d2549a6ed12d202cd12a7dfe8100000000106ae3a83bf81b96650100000000000000027673075a980bfd5d6b1dffe99c31f63e8938519cc1c2af009dda5e568a94460d", + "gasLimit": "960", + "txType": 4, + "pcTx": { + "txHash": "0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc", + "logIndex": "13" + }, + "observedTx": { + "success": false, + "blockHeight": 0, + "txHash": "", + "errorMsg": "tx not executed on destination chain", + "gasFeeUsed": "0", + "pc20WrapperAddress": "" + }, + "id": "d7e4da935abc97cbb68c0869dafa1e28038b89848c53650364250f60cd11e1ef", + "outboundStatus": 3, + "revertInstructions": { + "fundRecipient": "0x4612ad240cd66A77b921693BbbB356d1B8219b2c" + }, + "pcRevertExecution": { + "txHash": "0xcae270b1615ef4912ec9adbf8aa6afed9455107ee24e211af537f99ea9765ecb", + "sender": "0x4612ad240cd66A77b921693BbbB356d1B8219b2c", + "gasUsed": 74893, + "blockHeight": 23950149, + "status": "SUCCESS", + "errorMsg": "" + }, + "gasPrice": "1000", + "gasFee": "960000", + "pcRefundExecution": { + "txHash": "0x8f77c3e8504b1b493cf40f4b677b17dc81aa46e034aa3edc13711aa79dee0934", + "sender": "0x4612ad240cd66A77b921693BbbB356d1B8219b2c", + "gasUsed": 178441, + "blockHeight": 23950149, + "status": "SUCCESS", + "errorMsg": "" + }, + "refundSwapError": "", + "gasToken": "0x5D525Df2bD99a6e7ec58b76aF2fd95F39874EBed", + "abortReason": "", + "isPc20": false, + "pc20ContractAddress": "" + } + ], + "universalStatus": 0 + } + }, + "transactionsSent": 0 +} \ No newline at end of file diff --git a/plan/agw/research/live-svm-wire-2026-10-06/failure-observation.json b/plan/agw/research/live-svm-wire-2026-10-06/failure-observation.json new file mode 100644 index 00000000..dda32f29 --- /dev/null +++ b/plan/agw/research/live-svm-wire-2026-10-06/failure-observation.json @@ -0,0 +1,103 @@ +{ + "at": "2026-10-06T07:29:28.593Z", + "hash": "0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc", + "block": 23949885, + "observations": [ + { + "id": "0xf328cfa0af8a4e50afc3648205161759c02f1d0ddd27c40ba25f15990d084f36", + "record": { + "universalTx": { + "id": "f328cfa0af8a4e50afc3648205161759c02f1d0ddd27c40ba25f15990d084f36", + "pcTx": [ + { + "txHash": "0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc", + "sender": "0xDfFb9e4cc2b869cF35ab811675333f40cD04dF76", + "gasUsed": 417241, + "blockHeight": 23949885, + "status": "SUCCESS", + "errorMsg": "" + } + ], + "outboundTx": [ + { + "destinationChain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "recipient": "0x7673075a980bfd5d6b1dffe99c31f63e8938519cc1c2af009dda5e568a94460d", + "amount": "10000", + "externalAssetAddr": "0x0000000000000000000000000000000000000000", + "prc20AssetAddr": "0x5D525Df2bD99a6e7ec58b76aF2fd95F39874EBed", + "sender": "0x4612ad240cd66A77b921693BbbB356d1B8219b2c", + "payload": "0x000000024f12fe6816ae7e33ebf7db0b154ec3b09e3bf1a7690481e8e9477d5a278ad3af01dd7c1b885eb85dbac2db2a4ce5887489200c20d2549a6ed12d202cd12a7dfe8100000000106ae3a83bf81b96650100000000000000027673075a980bfd5d6b1dffe99c31f63e8938519cc1c2af009dda5e568a94460d", + "gasLimit": "960", + "txType": 4, + "pcTx": { + "txHash": "0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc", + "logIndex": "13" + }, + "id": "d7e4da935abc97cbb68c0869dafa1e28038b89848c53650364250f60cd11e1ef", + "outboundStatus": 1, + "revertInstructions": { + "fundRecipient": "0x4612ad240cd66A77b921693BbbB356d1B8219b2c" + }, + "gasPrice": "1000", + "gasFee": "960000", + "refundSwapError": "", + "gasToken": "0x5D525Df2bD99a6e7ec58b76aF2fd95F39874EBed", + "abortReason": "", + "isPc20": false, + "pc20ContractAddress": "" + } + ], + "universalStatus": 0 + } + } + }, + { + "id": "0xf328cfa0af8a4e50afc3648205161759c02f1d0ddd27c40ba25f15990d084f36", + "record": { + "universalTx": { + "id": "f328cfa0af8a4e50afc3648205161759c02f1d0ddd27c40ba25f15990d084f36", + "pcTx": [ + { + "txHash": "0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc", + "sender": "0xDfFb9e4cc2b869cF35ab811675333f40cD04dF76", + "gasUsed": 417241, + "blockHeight": 23949885, + "status": "SUCCESS", + "errorMsg": "" + } + ], + "outboundTx": [ + { + "destinationChain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "recipient": "0x7673075a980bfd5d6b1dffe99c31f63e8938519cc1c2af009dda5e568a94460d", + "amount": "10000", + "externalAssetAddr": "0x0000000000000000000000000000000000000000", + "prc20AssetAddr": "0x5D525Df2bD99a6e7ec58b76aF2fd95F39874EBed", + "sender": "0x4612ad240cd66A77b921693BbbB356d1B8219b2c", + "payload": "0x000000024f12fe6816ae7e33ebf7db0b154ec3b09e3bf1a7690481e8e9477d5a278ad3af01dd7c1b885eb85dbac2db2a4ce5887489200c20d2549a6ed12d202cd12a7dfe8100000000106ae3a83bf81b96650100000000000000027673075a980bfd5d6b1dffe99c31f63e8938519cc1c2af009dda5e568a94460d", + "gasLimit": "960", + "txType": 4, + "pcTx": { + "txHash": "0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc", + "logIndex": "13" + }, + "id": "d7e4da935abc97cbb68c0869dafa1e28038b89848c53650364250f60cd11e1ef", + "outboundStatus": 1, + "revertInstructions": { + "fundRecipient": "0x4612ad240cd66A77b921693BbbB356d1B8219b2c" + }, + "gasPrice": "1000", + "gasFee": "960000", + "refundSwapError": "", + "gasToken": "0x5D525Df2bD99a6e7ec58b76aF2fd95F39874EBed", + "abortReason": "", + "isPc20": false, + "pc20ContractAddress": "" + } + ], + "universalStatus": 0 + } + } + } + ] +} \ No newline at end of file diff --git a/plan/agw/research/live-svm-wire-2026-10-06/live-evidence.json b/plan/agw/research/live-svm-wire-2026-10-06/live-evidence.json new file mode 100644 index 00000000..efdc5bac --- /dev/null +++ b/plan/agw/research/live-svm-wire-2026-10-06/live-evidence.json @@ -0,0 +1,1296 @@ +[ + { + "name": "svm-wire-program-preflight", + "at": "2026-10-06T07:22:43.969Z", + "network": "TESTNET_DONUT", + "sourceCommit": "e8db74815cfbbf5389593805e464fe8d85f7f735", + "checkedAt": "2026-10-06T07:22:25.858Z", + "chain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "genesis": "EtWTRABZaYq6iMfeYKouRu166VU2xqa1wcaWoxPkrZBG", + "slot": 508016133, + "programDataSlot": 508016133, + "programs": [ + { + "address": "CFVSincHYbETh2k7w6u1ENEkjbSLtveRCEBupKidw2VS", + "programData": "DqeV1giGX9UPbTCsUaqau4ZaTqmjxKeRa4TQdbLiUCYC", + "lastUpgradeSlot": "496655369", + "dataLength": 724997, + "dataSha256": "2633943f479debc6bf0cba19861f90dfd01a09ecba206b2ce941c97281b8a95d" + }, + { + "address": "8yNqjrMnFiFbVTVQcKij8tNWWTMdFkrDf9abCGgc2sgx", + "programData": "GQmC7eueNLqazwr7U9fR3s4VwbXUtNf1HL6UCXuSWvaN", + "lastUpgradeSlot": "447956626", + "dataLength": 279709, + "dataSha256": "6887b9299b53bcaede79facbe9d9a53c9a0ba78e2c109322caef070b57637f95" + } + ], + "gatewayConfig": { + "address": "2urirovTZSgpEAEFyf2dMWjMTqfkgg1J3piTBeSEwV5P", + "paused": false, + "dataSha256": "1f7595b955ae35e2ea577db04d3e73f30d7284d9536910065e0fc7b078b6ae33" + }, + "counter": { + "address": "6Kg1NF5RRytjGwR6USttBLEYJrqwm65xtJzdPbbFwJKg", + "value": "201889018", + "authority": "BesWssuCiGE3EqeGRFamuouvAxJDUCdWH6NPHpAFPMBa", + "dataSha256": "4b1725035d45f06567ffe10489d847db80caeb03a2fa853a018cac309879e224" + }, + "counterIdlSha256": "493678d103afab762cc1668d02c641226125166ba8b4d7df46b67fec52b3a9ca", + "gatewayIdlSha256": "62d7792d04c657e1224f7c64d13b68e2f49dd39fdd6da0088deca0c32a5fb042" + }, + { + "name": "svm-wire-setup", + "at": "2026-10-06T07:23:28.532Z", + "network": "TESTNET_DONUT", + "sourceCommit": "e8db74815cfbbf5389593805e464fe8d85f7f735", + "wallet": "0x4612ad240cd66A77b921693BbbB356d1B8219b2c", + "rulesId": "0x0ed59a0b2764cf395b53a7a7d1b58e2ae3fb99b818be5392f3fdbc7eb4f645d0", + "grantHash": "0x5a1f05556a1abac0f05773b666f554977fecb54294d9a5119844da41632dc638", + "agent": "0xDfFb9e4cc2b869cF35ab811675333f40cD04dF76", + "recipient": "3nK8X1re4zLNrgz9Y3xKS4g2fKPJ6M3N9BhNuFfkjwAb", + "cea": "Fuas2d6gmyPEpKgvBEHGhNgu99Nx8xVWmmf6cVFp4feY", + "token": "0x5D525Df2bD99a6e7ec58b76aF2fd95F39874EBed", + "terms": { + "expectedCEA": "0xdd7c1b885eb85dbac2db2a4ce5887489200c20d2549a6ed12d202cd12a7dfe81", + "gatewayProgram": "0xa726d940296890606ae77be948a7726799b7e19076ced8c14c6ed43e98b7a6e5", + "ceaAccounts": [ + "0xdd7c1b885eb85dbac2db2a4ce5887489200c20d2549a6ed12d202cd12a7dfe81" + ], + "assets": [ + { + "token": "0x5D525Df2bD99a6e7ec58b76aF2fd95F39874EBed", + "maxPerCall": "10000", + "maxTotal": "20000" + } + ], + "validUntil": 1791278580, + "maxGasPerCall": "20000000000000000000", + "programs": [ + { + "program": "0x7673075a980bfd5d6b1dffe99c31f63e8938519cc1c2af009dda5e568a94460d", + "discriminator": "0x79f4fa0308e5e101", + "discriminatorLen": 8, + "dataless": false, + "maxAccounts": 4 + }, + { + "program": "0x7673075a980bfd5d6b1dffe99c31f63e8938519cc1c2af009dda5e568a94460d", + "discriminator": "0x6ae3a83bf81b9665", + "discriminatorLen": 8, + "dataless": false, + "maxAccounts": 2 + } + ], + "pins": [ + { + "ruleIndex": 0, + "accountIndex": 0, + "expected": "0x4f12fe6816ae7e33ebf7db0b154ec3b09e3bf1a7690481e8e9477d5a278ad3af" + }, + { + "ruleIndex": 0, + "accountIndex": 1, + "expected": "0x2953026d328218b107268efe60f7d98635af1ff535a91731f75ca7cf8a859044" + }, + { + "ruleIndex": 0, + "accountIndex": 2, + "expected": "0xdd7c1b885eb85dbac2db2a4ce5887489200c20d2549a6ed12d202cd12a7dfe81" + }, + { + "ruleIndex": 0, + "accountIndex": 3, + "expected": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "ruleIndex": 1, + "accountIndex": 0, + "expected": "0x4f12fe6816ae7e33ebf7db0b154ec3b09e3bf1a7690481e8e9477d5a278ad3af" + }, + { + "ruleIndex": 1, + "accountIndex": 1, + "expected": "0xdd7c1b885eb85dbac2db2a4ce5887489200c20d2549a6ed12d202cd12a7dfe81" + } + ], + "dataPins": [ + { + "ruleIndex": 0, + "fromEnd": false, + "offset": 8, + "offsetB": 0, + "len": 8, + "mode": 2, + "expected": "0x0000000000000000000000000000000000000000000000000000000000002710", + "num": "0", + "den": "0" + }, + { + "ruleIndex": 1, + "fromEnd": false, + "offset": 8, + "offsetB": 0, + "len": 8, + "mode": 2, + "expected": "0x0000000000000000000000000000000000000000000000000000000000000001", + "num": "0", + "den": "0" + } + ] + }, + "walletPCFunded": "41000000000000000000", + "tokenFunded": "20000" + }, + { + "name": "svm-wire-positive-submitted", + "at": "2026-10-06T07:23:41.870Z", + "network": "TESTNET_DONUT", + "sourceCommit": "e8db74815cfbbf5389593805e464fe8d85f7f735", + "wallet": "0x4612ad240cd66A77b921693BbbB356d1B8219b2c", + "rulesId": "0x0ed59a0b2764cf395b53a7a7d1b58e2ae3fb99b818be5392f3fdbc7eb4f645d0", + "hash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8" + }, + { + "name": "svm-wire-positive-receipt", + "at": "2026-10-06T07:24:40.063Z", + "network": "TESTNET_DONUT", + "sourceCommit": "e8db74815cfbbf5389593805e464fe8d85f7f735", + "hash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "receipt": { + "hash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "blockNumber": "23949837", + "blockHash": "0xf5a2ba7e2704285075f3df2c63321ea337f6e0e55fc042abe4441afc260c594b", + "transactionIndex": 1, + "from": "0x4612ad240cd66A77b921693BbbB356d1B8219b2c", + "to": "0x00000000000000000000000000000000000000C1", + "contractAddress": null, + "gasPrice": "1125000000", + "gasUsed": "445073", + "cumulativeGasUsed": "445073", + "logs": [ + { + "address": "0x603e7f0af6e1aaff46ddfb28b1e99364f8bc59af", + "topics": [ + "0x3ac286ad36e454b1ae54d96d9de29fdde1f3984110b62d27d0c7bbc70ccfbf93", + "0xc83601cd9bbdf58b8e3e8ca5eda8bf224739c5f34b1b91e2c4c5d7a93cdb4fd5", + "0x000000000000000000000000165a5e6782f39d30b38c7d97e1303e4cb2ad102a", + "0x0000000000000000000000004612ad240cd66a77b921693bbbb356d1b8219b2c" + ], + "data": "0x0000000000000000000000005d525df2bd99a6e7ec58b76af2fd95f39874ebed0000000000000000000000000000000000000000000000000000000000002710", + "blockNumber": "23949837", + "transactionHash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "transactionIndex": 1, + "blockHash": "0xf5a2ba7e2704285075f3df2c63321ea337f6e0e55fc042abe4441afc260c594b", + "blockTimestamp": "0x6ac4a1f7", + "logIndex": 1, + "removed": false + }, + { + "address": "0x5d525df2bd99a6e7ec58b76af2fd95f39874ebed", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000004612ad240cd66a77b921693bbbb356d1b8219b2c", + "0x00000000000000000000000000000000000000000000000000000000000000c1" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000002710", + "blockNumber": "23949837", + "transactionHash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "transactionIndex": 1, + "blockHash": "0xf5a2ba7e2704285075f3df2c63321ea337f6e0e55fc042abe4441afc260c594b", + "blockTimestamp": "0x6ac4a1f7", + "logIndex": 2, + "removed": false + }, + { + "address": "0x5d525df2bd99a6e7ec58b76af2fd95f39874ebed", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x0000000000000000000000004612ad240cd66a77b921693bbbb356d1b8219b2c", + "0x00000000000000000000000000000000000000000000000000000000000000c1" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000002710", + "blockNumber": "23949837", + "transactionHash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "transactionIndex": 1, + "blockHash": "0xf5a2ba7e2704285075f3df2c63321ea337f6e0e55fc042abe4441afc260c594b", + "blockTimestamp": "0x6ac4a1f7", + "logIndex": 3, + "removed": false + }, + { + "address": "0x5d525df2bd99a6e7ec58b76af2fd95f39874ebed", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x00000000000000000000000000000000000000000000000000000000000000c1", + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000002710", + "blockNumber": "23949837", + "transactionHash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "transactionIndex": 1, + "blockHash": "0xf5a2ba7e2704285075f3df2c63321ea337f6e0e55fc042abe4441afc260c594b", + "blockTimestamp": "0x6ac4a1f7", + "logIndex": 4, + "removed": false + }, + { + "address": "0xe17dd2e0509f99e9ee9469cf6634048ec5a3ade9", + "topics": [ + "0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c", + "0x00000000000000000000000000000000000000000000000000000000000000c0" + ], + "data": "0x0000000000000000000000000000000000000000000000008ac7230489e80000", + "blockNumber": "23949837", + "transactionHash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "transactionIndex": 1, + "blockHash": "0xf5a2ba7e2704285075f3df2c63321ea337f6e0e55fc042abe4441afc260c594b", + "blockTimestamp": "0x6ac4a1f7", + "logIndex": 5, + "removed": false + }, + { + "address": "0xe17dd2e0509f99e9ee9469cf6634048ec5a3ade9", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x00000000000000000000000000000000000000000000000000000000000000c0", + "0x0000000000000000000000005d548bb9e305aae0d6dc6e6fdc3ab419f6ac0037" + ], + "data": "0x0000000000000000000000000000000000000000000000008ac7230489e80000", + "blockNumber": "23949837", + "transactionHash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "transactionIndex": 1, + "blockHash": "0xf5a2ba7e2704285075f3df2c63321ea337f6e0e55fc042abe4441afc260c594b", + "blockTimestamp": "0x6ac4a1f7", + "logIndex": 6, + "removed": false + }, + { + "address": "0x5d525df2bd99a6e7ec58b76af2fd95f39874ebed", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000000e5914e3a7e2e6d18330dd33fa387ce33da48b54", + "0x00000000000000000000000000000000000000000000000000000000000000c0" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000ea600", + "blockNumber": "23949837", + "transactionHash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "transactionIndex": 1, + "blockHash": "0xf5a2ba7e2704285075f3df2c63321ea337f6e0e55fc042abe4441afc260c594b", + "blockTimestamp": "0x6ac4a1f7", + "logIndex": 7, + "removed": false + }, + { + "address": "0xe17dd2e0509f99e9ee9469cf6634048ec5a3ade9", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x00000000000000000000000000000000000000000000000000000000000000c0", + "0x0000000000000000000000000e5914e3a7e2e6d18330dd33fa387ce33da48b54" + ], + "data": "0x0000000000000000000000000000000000000000000000000c112c5348fdcf04", + "blockNumber": "23949837", + "transactionHash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "transactionIndex": 1, + "blockHash": "0xf5a2ba7e2704285075f3df2c63321ea337f6e0e55fc042abe4441afc260c594b", + "blockTimestamp": "0x6ac4a1f7", + "logIndex": 8, + "removed": false + }, + { + "address": "0x0e5914e3a7e2e6d18330dd33fa387ce33da48b54", + "topics": [ + "0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67", + "0x0000000000000000000000005d548bb9e305aae0d6dc6e6fdc3ab419f6ac0037", + "0x00000000000000000000000000000000000000000000000000000000000000c0" + ], + "data": "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffff15a000000000000000000000000000000000000000000000000000c112c5348fdcf0400000000000000000000000000000000000e84b1be17079db39e9ef80a30b925000000000000000000000000000000000000000000000002f15ecbc2e691bc650000000000000000000000000000000000000000000000000000000000043381", + "blockNumber": "23949837", + "transactionHash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "transactionIndex": 1, + "blockHash": "0xf5a2ba7e2704285075f3df2c63321ea337f6e0e55fc042abe4441afc260c594b", + "blockTimestamp": "0x6ac4a1f7", + "logIndex": 9, + "removed": false + }, + { + "address": "0xe17dd2e0509f99e9ee9469cf6634048ec5a3ade9", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x00000000000000000000000000000000000000000000000000000000000000c0", + "0x0000000000000000000000005d548bb9e305aae0d6dc6e6fdc3ab419f6ac0037" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000000", + "blockNumber": "23949837", + "transactionHash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "transactionIndex": 1, + "blockHash": "0xf5a2ba7e2704285075f3df2c63321ea337f6e0e55fc042abe4441afc260c594b", + "blockTimestamp": "0x6ac4a1f7", + "logIndex": 10, + "removed": false + }, + { + "address": "0x5d525df2bd99a6e7ec58b76af2fd95f39874ebed", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x00000000000000000000000000000000000000000000000000000000000000c0", + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000ea600", + "blockNumber": "23949837", + "transactionHash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "transactionIndex": 1, + "blockHash": "0xf5a2ba7e2704285075f3df2c63321ea337f6e0e55fc042abe4441afc260c594b", + "blockTimestamp": "0x6ac4a1f7", + "logIndex": 11, + "removed": false + }, + { + "address": "0xe17dd2e0509f99e9ee9469cf6634048ec5a3ade9", + "topics": [ + "0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65", + "0x00000000000000000000000000000000000000000000000000000000000000c0" + ], + "data": "0x0000000000000000000000000000000000000000000000007eb5f6b140ea30fc", + "blockNumber": "23949837", + "transactionHash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "transactionIndex": 1, + "blockHash": "0xf5a2ba7e2704285075f3df2c63321ea337f6e0e55fc042abe4441afc260c594b", + "blockTimestamp": "0x6ac4a1f7", + "logIndex": 12, + "removed": false + }, + { + "address": "0x00000000000000000000000000000000000000c0", + "topics": [ + "0x01fd625a5ce1109c10761818e2ef64ea92cd4966d78086d37e5a4b50e3226878", + "0x0000000000000000000000005d525df2bd99a6e7ec58b76af2fd95f39874ebed", + "0x0000000000000000000000004612ad240cd66a77b921693bbbb356d1b8219b2c" + ], + "data": "0x0000000000000000000000000000000000000000000000000c112c5348fdcf0400000000000000000000000000000000000000000000000000000000000ea60000000000000000000000000000000000000000000000000000000000000001f4", + "blockNumber": "23949837", + "transactionHash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "transactionIndex": 1, + "blockHash": "0xf5a2ba7e2704285075f3df2c63321ea337f6e0e55fc042abe4441afc260c594b", + "blockTimestamp": "0x6ac4a1f7", + "logIndex": 13, + "removed": false + }, + { + "address": "0x00000000000000000000000000000000000000c1", + "topics": [ + "0x8882d1d8f7b1750e49d021ea8d62e07c2d163645b8fa31c035905d6572ffc637", + "0xdcce211428bdd1e5bb6cd8c346fd68e2e919245bd28bca9692ec281d7a69fbcc", + "0x0000000000000000000000004612ad240cd66a77b921693bbbb356d1b8219b2c", + "0x0000000000000000000000005d525df2bd99a6e7ec58b76af2fd95f39874ebed" + ], + "data": "0x000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000027100000000000000000000000005d525df2bd99a6e7ec58b76af2fd95f39874ebed00000000000000000000000000000000000000000000000000000000000ea60000000000000000000000000000000000000000000000000000000000000003c0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004612ad240cd66a77b921693bbbb356d1b8219b2c000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000003e80000000000000000000000000000000000000000000000000000000000000027736f6c616e613a457457545241425a61597136694d6665594b6f755275313636565532787161310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000207673075a980bfd5d6b1dffe99c31f63e8938519cc1c2af009dda5e568a94460d00000000000000000000000000000000000000000000000000000000000000bd000000044f12fe6816ae7e33ebf7db0b154ec3b09e3bf1a7690481e8e9477d5a278ad3af012953026d328218b107268efe60f7d98635af1ff535a91731f75ca7cf8a85904401dd7c1b885eb85dbac2db2a4ce5887489200c20d2549a6ed12d202cd12a7dfe81010000000000000000000000000000000000000000000000000000000000000000000000001079f4fa0308e5e1011027000000000000027673075a980bfd5d6b1dffe99c31f63e8938519cc1c2af009dda5e568a94460d000000", + "blockNumber": "23949837", + "transactionHash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "transactionIndex": 1, + "blockHash": "0xf5a2ba7e2704285075f3df2c63321ea337f6e0e55fc042abe4441afc260c594b", + "blockTimestamp": "0x6ac4a1f7", + "logIndex": 14, + "removed": false + }, + { + "address": "0x4612ad240cd66a77b921693bbbb356d1b8219b2c", + "topics": [ + "0x3dbef004c3d4318a109f103c40928ef6cb77519329e4d7f473364dd15bf6b3fd", + "0x0ed59a0b2764cf395b53a7a7d1b58e2ae3fb99b818be5392f3fdbc7eb4f645d0", + "0x000000000000000000000000dffb9e4cc2b869cf35ab811675333f40cd04df76" + ], + "data": "0xc2c1ff13c20fb17960a533cdbe11f2e82e5f4020bef7ff8e0c3749d5f2edd18b", + "blockNumber": "23949837", + "transactionHash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "transactionIndex": 1, + "blockHash": "0xf5a2ba7e2704285075f3df2c63321ea337f6e0e55fc042abe4441afc260c594b", + "blockTimestamp": "0x6ac4a1f7", + "logIndex": 15, + "removed": false + } + ], + "logsBloom": "0x0020000110100000000000010000030100000000000000000000000000000000000000000000000000001e000000000000000000000022000400020040200008000000000200004808000008000000080000020004400004000800008020200000000000020002001000000004000803200000000000040200000090404c00000000000000000004000000000000000000010001000000002000020000001000020010000000000200000080000000000000000000000040010000100000000004000002200020000000000000000090800000100000000000000002000020004010020012004000000000000000000000000000000001400000000040000000", + "status": 1, + "raw": { + "from": "0xDfFb9e4cc2b869cF35ab811675333f40cD04dF76", + "to": "0x4612ad240cd66A77b921693BbbB356d1B8219b2c", + "nonce": 0, + "data": "0xc0ca77910ed59a0b2764cf395b53a7a7d1b58e2ae3fb99b818be5392f3fdbc7eb4f645d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000027800000000000000000000000000000000000000c10000000000000000000000000000000000000000000000008ac7230489e8000077b86bec000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001000000000000000000000000005d525df2bd99a6e7ec58b76af2fd95f39874ebed000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008ac7230489e8000000000000000000000000000000000000000000000000000000000000000001400000000000000000000000004612ad240cd66a77b921693bbbb356d1b8219b2c00000000000000000000000000000000000000000000000000000000000000207673075a980bfd5d6b1dffe99c31f63e8938519cc1c2af009dda5e568a94460d00000000000000000000000000000000000000000000000000000000000000bd000000044f12fe6816ae7e33ebf7db0b154ec3b09e3bf1a7690481e8e9477d5a278ad3af012953026d328218b107268efe60f7d98635af1ff535a91731f75ca7cf8a85904401dd7c1b885eb85dbac2db2a4ce5887489200c20d2549a6ed12d202cd12a7dfe81010000000000000000000000000000000000000000000000000000000000000000000000001079f4fa0308e5e1011027000000000000027673075a980bfd5d6b1dffe99c31f63e8938519cc1c2af009dda5e568a94460d0000000000000000000000", + "value": "0" + }, + "finalTxHash": "kGUaPUfASg9Poo93aMsztHJjUk27MKuRJBfDZK1WP3FFSaXSYcoPcxjUMFyDxaK6aU6mQkZeowSu3MtvK5PXKgK", + "externalTxHash": "kGUaPUfASg9Poo93aMsztHJjUk27MKuRJBfDZK1WP3FFSaXSYcoPcxjUMFyDxaK6aU6mQkZeowSu3MtvK5PXKgK", + "externalChain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "externalExplorerUrl": "https://explorer.solana.com/tx/kGUaPUfASg9Poo93aMsztHJjUk27MKuRJBfDZK1WP3FFSaXSYcoPcxjUMFyDxaK6aU6mQkZeowSu3MtvK5PXKgK?cluster=devnet", + "externalRecipient": "0x7673075a980bfd5d6b1dffe99c31f63e8938519cc1c2af009dda5e568a94460d", + "externalAmount": "10000", + "externalAssetAddr": "0x0000000000000000000000000000000000000000", + "externalStatus": "success" + } + }, + { + "name": "svm-wire-positive-destination", + "at": "2026-10-06T07:25:10.654Z", + "network": "TESTNET_DONUT", + "sourceCommit": "e8db74815cfbbf5389593805e464fe8d85f7f735", + "hash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "externalTxHash": "kGUaPUfASg9Poo93aMsztHJjUk27MKuRJBfDZK1WP3FFSaXSYcoPcxjUMFyDxaK6aU6mQkZeowSu3MtvK5PXKgK", + "destination": { + "blockTime": 1791271462, + "meta": { + "computeUnitsConsumed": 90001, + "costUnits": 93130, + "err": null, + "fee": 5000, + "innerInstructions": [ + { + "index": 1, + "instructions": [ + { + "parsed": { + "info": { + "lamports": 690880, + "newAccount": "DBX5UrNvpkfd351q6xQ7B71QxsmW7on8HwSmbtHJigCD", + "owner": "CFVSincHYbETh2k7w6u1ENEkjbSLtveRCEBupKidw2VS", + "source": "FkXGfYVbXT5euXjYabvZn4e6Ygc8aCYpFv9j1hKstw2H", + "space": 8 + }, + "type": "createAccount" + }, + "program": "system", + "programId": "11111111111111111111111111111111", + "stackHeight": 2 + }, + { + "parsed": { + "info": { + "destination": "Fuas2d6gmyPEpKgvBEHGhNgu99Nx8xVWmmf6cVFp4feY", + "lamports": 10000, + "source": "89q1AUFb7YREHtjc1aYaPywovPq6tb3GYNPyDUJ3rshi" + }, + "type": "transfer" + }, + "program": "system", + "programId": "11111111111111111111111111111111", + "stackHeight": 2 + }, + { + "accounts": [ + "6Kg1NF5RRytjGwR6USttBLEYJrqwm65xtJzdPbbFwJKg", + "3nK8X1re4zLNrgz9Y3xKS4g2fKPJ6M3N9BhNuFfkjwAb", + "Fuas2d6gmyPEpKgvBEHGhNgu99Nx8xVWmmf6cVFp4feY", + "11111111111111111111111111111111" + ], + "data": "G4U3TEuFnivMddm3E6dMCb", + "programId": "8yNqjrMnFiFbVTVQcKij8tNWWTMdFkrDf9abCGgc2sgx", + "stackHeight": 2 + }, + { + "parsed": { + "info": { + "destination": "3nK8X1re4zLNrgz9Y3xKS4g2fKPJ6M3N9BhNuFfkjwAb", + "lamports": 10000, + "source": "Fuas2d6gmyPEpKgvBEHGhNgu99Nx8xVWmmf6cVFp4feY" + }, + "type": "transfer" + }, + "program": "system", + "programId": "11111111111111111111111111111111", + "stackHeight": 3 + }, + { + "parsed": { + "info": { + "destination": "FkXGfYVbXT5euXjYabvZn4e6Ygc8aCYpFv9j1hKstw2H", + "lamports": 695880, + "source": "89q1AUFb7YREHtjc1aYaPywovPq6tb3GYNPyDUJ3rshi" + }, + "type": "transfer" + }, + "program": "system", + "programId": "11111111111111111111111111111111", + "stackHeight": 2 + }, + { + "accounts": [ + "Hd8hF5GsJ3a54yxA1HNNNUvB55QCXsXA5mgyL167rJk5" + ], + "data": "5oQqPwQ2EA5YePTzsKVUGyA2fXjYdrQAiALVKG7Lp1PFqU6wHrUnK2Qd1pMGPvwceSRafE2bm4JZVdTViCcxivaGefCJmj6xpa4buvSwUmdksfosJdpvS5mnJ79jkZL1iH5zd8yJ2Qt5MahkAnVcrVkFF7Tw3xczwJteMiBgfsGMbYVZyXewCnRx1iottBERuZ7zuWFikUW7FQzrHposgLTux1qBL1aLQReFwReUhvvVWTBLMELN46geeRrn3qq1N7p2GuNoeJ5ezhM8ii9bUooWsdnfdy7GkVdhQywX2LFL1QjQQW2QjA7sbrankwc9hYfURXCwpM1gFSJiKGDeEB", + "programId": "CFVSincHYbETh2k7w6u1ENEkjbSLtveRCEBupKidw2VS", + "stackHeight": 2 + } + ] + } + ], + "logMessages": [ + "Program ComputeBudget111111111111111111111111111111 invoke [1]", + "Program ComputeBudget111111111111111111111111111111 success", + "Program CFVSincHYbETh2k7w6u1ENEkjbSLtveRCEBupKidw2VS invoke [1]", + "Program log: Instruction: FinalizeUniversalTx", + "Program 11111111111111111111111111111111 invoke [2]", + "Program 11111111111111111111111111111111 success", + "Program 11111111111111111111111111111111 invoke [2]", + "Program 11111111111111111111111111111111 success", + "Program 8yNqjrMnFiFbVTVQcKij8tNWWTMdFkrDf9abCGgc2sgx invoke [2]", + "Program log: Instruction: ReceiveSol", + "Program 11111111111111111111111111111111 invoke [3]", + "Program 11111111111111111111111111111111 success", + "Program log: Received 10000 lamports, counter incremented to: 201899018", + "Program 8yNqjrMnFiFbVTVQcKij8tNWWTMdFkrDf9abCGgc2sgx consumed 7499 of 331858 compute units", + "Program 8yNqjrMnFiFbVTVQcKij8tNWWTMdFkrDf9abCGgc2sgx success", + "Program 11111111111111111111111111111111 invoke [2]", + "Program 11111111111111111111111111111111 success", + "Program CFVSincHYbETh2k7w6u1ENEkjbSLtveRCEBupKidw2VS invoke [2]", + "Program CFVSincHYbETh2k7w6u1ENEkjbSLtveRCEBupKidw2VS consumed 4017 of 315404 compute units", + "Program CFVSincHYbETh2k7w6u1ENEkjbSLtveRCEBupKidw2VS success", + "Program CFVSincHYbETh2k7w6u1ENEkjbSLtveRCEBupKidw2VS consumed 89851 of 399850 compute units", + "Program CFVSincHYbETh2k7w6u1ENEkjbSLtveRCEBupKidw2VS success" + ], + "postBalances": [ + 41078347081, + 0, + 1566000, + 690880, + 4280640, + 615340949, + 1141440, + 41141440, + 0, + 1, + 1501617194629, + 2832720, + 1 + ], + "postTokenBalances": [], + "preBalances": [ + 41078347081, + 0, + 1566000, + 0, + 4280640, + 615330949, + 1141440, + 41141440, + 0, + 1, + 1501617900509, + 2832720, + 1 + ], + "preTokenBalances": [], + "rewards": [], + "status": { + "Ok": null + } + }, + "slot": 508016629, + "transaction": { + "message": { + "accountKeys": [ + { + "pubkey": "FkXGfYVbXT5euXjYabvZn4e6Ygc8aCYpFv9j1hKstw2H", + "signer": true, + "source": "transaction", + "writable": true + }, + { + "pubkey": "Fuas2d6gmyPEpKgvBEHGhNgu99Nx8xVWmmf6cVFp4feY", + "signer": false, + "source": "transaction", + "writable": true + }, + { + "pubkey": "79jbZqURnjNAeEL9C8jzQfoMCV8Excux3qArET3oWBBY", + "signer": false, + "source": "transaction", + "writable": true + }, + { + "pubkey": "DBX5UrNvpkfd351q6xQ7B71QxsmW7on8HwSmbtHJigCD", + "signer": false, + "source": "transaction", + "writable": true + }, + { + "pubkey": "6Kg1NF5RRytjGwR6USttBLEYJrqwm65xtJzdPbbFwJKg", + "signer": false, + "source": "transaction", + "writable": true + }, + { + "pubkey": "3nK8X1re4zLNrgz9Y3xKS4g2fKPJ6M3N9BhNuFfkjwAb", + "signer": false, + "source": "transaction", + "writable": true + }, + { + "pubkey": "8yNqjrMnFiFbVTVQcKij8tNWWTMdFkrDf9abCGgc2sgx", + "signer": false, + "source": "transaction", + "writable": false + }, + { + "pubkey": "CFVSincHYbETh2k7w6u1ENEkjbSLtveRCEBupKidw2VS", + "signer": false, + "source": "transaction", + "writable": false + }, + { + "pubkey": "Hd8hF5GsJ3a54yxA1HNNNUvB55QCXsXA5mgyL167rJk5", + "signer": false, + "source": "transaction", + "writable": false + }, + { + "pubkey": "ComputeBudget111111111111111111111111111111", + "signer": false, + "source": "transaction", + "writable": false + }, + { + "pubkey": "89q1AUFb7YREHtjc1aYaPywovPq6tb3GYNPyDUJ3rshi", + "signer": false, + "source": "lookupTable", + "writable": true + }, + { + "pubkey": "2urirovTZSgpEAEFyf2dMWjMTqfkgg1J3piTBeSEwV5P", + "signer": false, + "source": "lookupTable", + "writable": false + }, + { + "pubkey": "11111111111111111111111111111111", + "signer": false, + "source": "lookupTable", + "writable": false + } + ], + "addressTableLookups": [ + { + "accountKey": "6AdUqeKQMapkoMXP3wJ7FrjYfVreqaD7bq3HZyZEn8kN", + "readonlyIndexes": [ + 0, + 3 + ], + "writableIndexes": [ + 2 + ] + } + ], + "instructions": [ + { + "accounts": [], + "data": "HMypLP", + "programId": "ComputeBudget111111111111111111111111111111", + "stackHeight": 1 + }, + { + "accounts": [ + "FkXGfYVbXT5euXjYabvZn4e6Ygc8aCYpFv9j1hKstw2H", + "2urirovTZSgpEAEFyf2dMWjMTqfkgg1J3piTBeSEwV5P", + "89q1AUFb7YREHtjc1aYaPywovPq6tb3GYNPyDUJ3rshi", + "Fuas2d6gmyPEpKgvBEHGhNgu99Nx8xVWmmf6cVFp4feY", + "79jbZqURnjNAeEL9C8jzQfoMCV8Excux3qArET3oWBBY", + "DBX5UrNvpkfd351q6xQ7B71QxsmW7on8HwSmbtHJigCD", + "11111111111111111111111111111111", + "8yNqjrMnFiFbVTVQcKij8tNWWTMdFkrDf9abCGgc2sgx", + "CFVSincHYbETh2k7w6u1ENEkjbSLtveRCEBupKidw2VS", + "CFVSincHYbETh2k7w6u1ENEkjbSLtveRCEBupKidw2VS", + "CFVSincHYbETh2k7w6u1ENEkjbSLtveRCEBupKidw2VS", + "CFVSincHYbETh2k7w6u1ENEkjbSLtveRCEBupKidw2VS", + "CFVSincHYbETh2k7w6u1ENEkjbSLtveRCEBupKidw2VS", + "CFVSincHYbETh2k7w6u1ENEkjbSLtveRCEBupKidw2VS", + "CFVSincHYbETh2k7w6u1ENEkjbSLtveRCEBupKidw2VS", + "CFVSincHYbETh2k7w6u1ENEkjbSLtveRCEBupKidw2VS", + "CFVSincHYbETh2k7w6u1ENEkjbSLtveRCEBupKidw2VS", + "CFVSincHYbETh2k7w6u1ENEkjbSLtveRCEBupKidw2VS", + "CFVSincHYbETh2k7w6u1ENEkjbSLtveRCEBupKidw2VS", + "CFVSincHYbETh2k7w6u1ENEkjbSLtveRCEBupKidw2VS", + "Hd8hF5GsJ3a54yxA1HNNNUvB55QCXsXA5mgyL167rJk5", + "CFVSincHYbETh2k7w6u1ENEkjbSLtveRCEBupKidw2VS", + "6Kg1NF5RRytjGwR6USttBLEYJrqwm65xtJzdPbbFwJKg", + "3nK8X1re4zLNrgz9Y3xKS4g2fKPJ6M3N9BhNuFfkjwAb", + "Fuas2d6gmyPEpKgvBEHGhNgu99Nx8xVWmmf6cVFp4feY", + "11111111111111111111111111111111" + ], + "data": "5GnKk9T5dWyimwxJHxPqPwrXGUzE211fQE38qmM75Uas2qDURUoijyfXKBa2yNTikSYRZQ2WoQCjxBUkKsX9VP5kaW78ft3Mu21PjiPmAu7PEUkuEHgX1A4gx2JSYARQCdaZqEyFJg9ZZAghEBWcbQjyhAL6zFypw2HYWVnBKwdxC72v5kbSb4Fs3jR4wTgWmtjvvgVmMcjPzARJPJ3oYwftpzwBJYWzYeX4CRKMv162qbRZQ7jfFbqW3nNZuvZnaK746PKEgexCgRKxkWL4AC3fAK9PDbZUZRUX6w1Ay1yZKX1bA6SJX8v8PrUwCEKQkBeqzfc", + "programId": "CFVSincHYbETh2k7w6u1ENEkjbSLtveRCEBupKidw2VS", + "stackHeight": 1 + } + ], + "recentBlockhash": "HUtUv2neQFdpXVtyJj8Bq4ju3cSwn4mjp6AcTHjGEXX1" + }, + "signatures": [ + "kGUaPUfASg9Poo93aMsztHJjUk27MKuRJBfDZK1WP3FFSaXSYcoPcxjUMFyDxaK6aU6mQkZeowSu3MtvK5PXKgK" + ] + }, + "transactionIndex": 5, + "version": 0 + }, + "replayReceipt": { + "hash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "blockNumber": "23949837", + "blockHash": "0xf5a2ba7e2704285075f3df2c63321ea337f6e0e55fc042abe4441afc260c594b", + "transactionIndex": 1, + "from": "0x4612ad240cd66A77b921693BbbB356d1B8219b2c", + "to": "0x00000000000000000000000000000000000000C1", + "contractAddress": null, + "gasPrice": "1125000000", + "gasUsed": "445073", + "cumulativeGasUsed": "445073", + "logs": [ + { + "address": "0x603e7f0af6e1aaff46ddfb28b1e99364f8bc59af", + "topics": [ + "0x3ac286ad36e454b1ae54d96d9de29fdde1f3984110b62d27d0c7bbc70ccfbf93", + "0xc83601cd9bbdf58b8e3e8ca5eda8bf224739c5f34b1b91e2c4c5d7a93cdb4fd5", + "0x000000000000000000000000165a5e6782f39d30b38c7d97e1303e4cb2ad102a", + "0x0000000000000000000000004612ad240cd66a77b921693bbbb356d1b8219b2c" + ], + "data": "0x0000000000000000000000005d525df2bd99a6e7ec58b76af2fd95f39874ebed0000000000000000000000000000000000000000000000000000000000002710", + "blockNumber": "23949837", + "transactionHash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "transactionIndex": 1, + "blockHash": "0xf5a2ba7e2704285075f3df2c63321ea337f6e0e55fc042abe4441afc260c594b", + "blockTimestamp": "0x6ac4a1f7", + "logIndex": 1, + "removed": false + }, + { + "address": "0x5d525df2bd99a6e7ec58b76af2fd95f39874ebed", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000004612ad240cd66a77b921693bbbb356d1b8219b2c", + "0x00000000000000000000000000000000000000000000000000000000000000c1" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000002710", + "blockNumber": "23949837", + "transactionHash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "transactionIndex": 1, + "blockHash": "0xf5a2ba7e2704285075f3df2c63321ea337f6e0e55fc042abe4441afc260c594b", + "blockTimestamp": "0x6ac4a1f7", + "logIndex": 2, + "removed": false + }, + { + "address": "0x5d525df2bd99a6e7ec58b76af2fd95f39874ebed", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x0000000000000000000000004612ad240cd66a77b921693bbbb356d1b8219b2c", + "0x00000000000000000000000000000000000000000000000000000000000000c1" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000002710", + "blockNumber": "23949837", + "transactionHash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "transactionIndex": 1, + "blockHash": "0xf5a2ba7e2704285075f3df2c63321ea337f6e0e55fc042abe4441afc260c594b", + "blockTimestamp": "0x6ac4a1f7", + "logIndex": 3, + "removed": false + }, + { + "address": "0x5d525df2bd99a6e7ec58b76af2fd95f39874ebed", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x00000000000000000000000000000000000000000000000000000000000000c1", + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000002710", + "blockNumber": "23949837", + "transactionHash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "transactionIndex": 1, + "blockHash": "0xf5a2ba7e2704285075f3df2c63321ea337f6e0e55fc042abe4441afc260c594b", + "blockTimestamp": "0x6ac4a1f7", + "logIndex": 4, + "removed": false + }, + { + "address": "0xe17dd2e0509f99e9ee9469cf6634048ec5a3ade9", + "topics": [ + "0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c", + "0x00000000000000000000000000000000000000000000000000000000000000c0" + ], + "data": "0x0000000000000000000000000000000000000000000000008ac7230489e80000", + "blockNumber": "23949837", + "transactionHash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "transactionIndex": 1, + "blockHash": "0xf5a2ba7e2704285075f3df2c63321ea337f6e0e55fc042abe4441afc260c594b", + "blockTimestamp": "0x6ac4a1f7", + "logIndex": 5, + "removed": false + }, + { + "address": "0xe17dd2e0509f99e9ee9469cf6634048ec5a3ade9", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x00000000000000000000000000000000000000000000000000000000000000c0", + "0x0000000000000000000000005d548bb9e305aae0d6dc6e6fdc3ab419f6ac0037" + ], + "data": "0x0000000000000000000000000000000000000000000000008ac7230489e80000", + "blockNumber": "23949837", + "transactionHash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "transactionIndex": 1, + "blockHash": "0xf5a2ba7e2704285075f3df2c63321ea337f6e0e55fc042abe4441afc260c594b", + "blockTimestamp": "0x6ac4a1f7", + "logIndex": 6, + "removed": false + }, + { + "address": "0x5d525df2bd99a6e7ec58b76af2fd95f39874ebed", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000000e5914e3a7e2e6d18330dd33fa387ce33da48b54", + "0x00000000000000000000000000000000000000000000000000000000000000c0" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000ea600", + "blockNumber": "23949837", + "transactionHash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "transactionIndex": 1, + "blockHash": "0xf5a2ba7e2704285075f3df2c63321ea337f6e0e55fc042abe4441afc260c594b", + "blockTimestamp": "0x6ac4a1f7", + "logIndex": 7, + "removed": false + }, + { + "address": "0xe17dd2e0509f99e9ee9469cf6634048ec5a3ade9", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x00000000000000000000000000000000000000000000000000000000000000c0", + "0x0000000000000000000000000e5914e3a7e2e6d18330dd33fa387ce33da48b54" + ], + "data": "0x0000000000000000000000000000000000000000000000000c112c5348fdcf04", + "blockNumber": "23949837", + "transactionHash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "transactionIndex": 1, + "blockHash": "0xf5a2ba7e2704285075f3df2c63321ea337f6e0e55fc042abe4441afc260c594b", + "blockTimestamp": "0x6ac4a1f7", + "logIndex": 8, + "removed": false + }, + { + "address": "0x0e5914e3a7e2e6d18330dd33fa387ce33da48b54", + "topics": [ + "0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67", + "0x0000000000000000000000005d548bb9e305aae0d6dc6e6fdc3ab419f6ac0037", + "0x00000000000000000000000000000000000000000000000000000000000000c0" + ], + "data": "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffff15a000000000000000000000000000000000000000000000000000c112c5348fdcf0400000000000000000000000000000000000e84b1be17079db39e9ef80a30b925000000000000000000000000000000000000000000000002f15ecbc2e691bc650000000000000000000000000000000000000000000000000000000000043381", + "blockNumber": "23949837", + "transactionHash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "transactionIndex": 1, + "blockHash": "0xf5a2ba7e2704285075f3df2c63321ea337f6e0e55fc042abe4441afc260c594b", + "blockTimestamp": "0x6ac4a1f7", + "logIndex": 9, + "removed": false + }, + { + "address": "0xe17dd2e0509f99e9ee9469cf6634048ec5a3ade9", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x00000000000000000000000000000000000000000000000000000000000000c0", + "0x0000000000000000000000005d548bb9e305aae0d6dc6e6fdc3ab419f6ac0037" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000000", + "blockNumber": "23949837", + "transactionHash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "transactionIndex": 1, + "blockHash": "0xf5a2ba7e2704285075f3df2c63321ea337f6e0e55fc042abe4441afc260c594b", + "blockTimestamp": "0x6ac4a1f7", + "logIndex": 10, + "removed": false + }, + { + "address": "0x5d525df2bd99a6e7ec58b76af2fd95f39874ebed", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x00000000000000000000000000000000000000000000000000000000000000c0", + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000ea600", + "blockNumber": "23949837", + "transactionHash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "transactionIndex": 1, + "blockHash": "0xf5a2ba7e2704285075f3df2c63321ea337f6e0e55fc042abe4441afc260c594b", + "blockTimestamp": "0x6ac4a1f7", + "logIndex": 11, + "removed": false + }, + { + "address": "0xe17dd2e0509f99e9ee9469cf6634048ec5a3ade9", + "topics": [ + "0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65", + "0x00000000000000000000000000000000000000000000000000000000000000c0" + ], + "data": "0x0000000000000000000000000000000000000000000000007eb5f6b140ea30fc", + "blockNumber": "23949837", + "transactionHash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "transactionIndex": 1, + "blockHash": "0xf5a2ba7e2704285075f3df2c63321ea337f6e0e55fc042abe4441afc260c594b", + "blockTimestamp": "0x6ac4a1f7", + "logIndex": 12, + "removed": false + }, + { + "address": "0x00000000000000000000000000000000000000c0", + "topics": [ + "0x01fd625a5ce1109c10761818e2ef64ea92cd4966d78086d37e5a4b50e3226878", + "0x0000000000000000000000005d525df2bd99a6e7ec58b76af2fd95f39874ebed", + "0x0000000000000000000000004612ad240cd66a77b921693bbbb356d1b8219b2c" + ], + "data": "0x0000000000000000000000000000000000000000000000000c112c5348fdcf0400000000000000000000000000000000000000000000000000000000000ea60000000000000000000000000000000000000000000000000000000000000001f4", + "blockNumber": "23949837", + "transactionHash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "transactionIndex": 1, + "blockHash": "0xf5a2ba7e2704285075f3df2c63321ea337f6e0e55fc042abe4441afc260c594b", + "blockTimestamp": "0x6ac4a1f7", + "logIndex": 13, + "removed": false + }, + { + "address": "0x00000000000000000000000000000000000000c1", + "topics": [ + "0x8882d1d8f7b1750e49d021ea8d62e07c2d163645b8fa31c035905d6572ffc637", + "0xdcce211428bdd1e5bb6cd8c346fd68e2e919245bd28bca9692ec281d7a69fbcc", + "0x0000000000000000000000004612ad240cd66a77b921693bbbb356d1b8219b2c", + "0x0000000000000000000000005d525df2bd99a6e7ec58b76af2fd95f39874ebed" + ], + "data": "0x000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000027100000000000000000000000005d525df2bd99a6e7ec58b76af2fd95f39874ebed00000000000000000000000000000000000000000000000000000000000ea60000000000000000000000000000000000000000000000000000000000000003c0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004612ad240cd66a77b921693bbbb356d1b8219b2c000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000003e80000000000000000000000000000000000000000000000000000000000000027736f6c616e613a457457545241425a61597136694d6665594b6f755275313636565532787161310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000207673075a980bfd5d6b1dffe99c31f63e8938519cc1c2af009dda5e568a94460d00000000000000000000000000000000000000000000000000000000000000bd000000044f12fe6816ae7e33ebf7db0b154ec3b09e3bf1a7690481e8e9477d5a278ad3af012953026d328218b107268efe60f7d98635af1ff535a91731f75ca7cf8a85904401dd7c1b885eb85dbac2db2a4ce5887489200c20d2549a6ed12d202cd12a7dfe81010000000000000000000000000000000000000000000000000000000000000000000000001079f4fa0308e5e1011027000000000000027673075a980bfd5d6b1dffe99c31f63e8938519cc1c2af009dda5e568a94460d000000", + "blockNumber": "23949837", + "transactionHash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "transactionIndex": 1, + "blockHash": "0xf5a2ba7e2704285075f3df2c63321ea337f6e0e55fc042abe4441afc260c594b", + "blockTimestamp": "0x6ac4a1f7", + "logIndex": 14, + "removed": false + }, + { + "address": "0x4612ad240cd66a77b921693bbbb356d1b8219b2c", + "topics": [ + "0x3dbef004c3d4318a109f103c40928ef6cb77519329e4d7f473364dd15bf6b3fd", + "0x0ed59a0b2764cf395b53a7a7d1b58e2ae3fb99b818be5392f3fdbc7eb4f645d0", + "0x000000000000000000000000dffb9e4cc2b869cf35ab811675333f40cd04df76" + ], + "data": "0xc2c1ff13c20fb17960a533cdbe11f2e82e5f4020bef7ff8e0c3749d5f2edd18b", + "blockNumber": "23949837", + "transactionHash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "transactionIndex": 1, + "blockHash": "0xf5a2ba7e2704285075f3df2c63321ea337f6e0e55fc042abe4441afc260c594b", + "blockTimestamp": "0x6ac4a1f7", + "logIndex": 15, + "removed": false + } + ], + "logsBloom": "0x0020000110100000000000010000030100000000000000000000000000000000000000000000000000001e000000000000000000000022000400020040200008000000000200004808000008000000080000020004400004000800008020200000000000020002001000000004000803200000000000040200000090404c00000000000000000004000000000000000000010001000000002000020000001000020010000000000200000080000000000000000000000040010000100000000004000002200020000000000000000090800000100000000000000002000020004010020012004000000000000000000000000000000001400000000040000000", + "status": 1, + "raw": { + "from": "0xDfFb9e4cc2b869cF35ab811675333f40cD04dF76", + "to": "0x4612ad240cd66A77b921693BbbB356d1B8219b2c", + "nonce": 0, + "data": "0xc0ca77910ed59a0b2764cf395b53a7a7d1b58e2ae3fb99b818be5392f3fdbc7eb4f645d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000027800000000000000000000000000000000000000c10000000000000000000000000000000000000000000000008ac7230489e8000077b86bec000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001000000000000000000000000005d525df2bd99a6e7ec58b76af2fd95f39874ebed000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008ac7230489e8000000000000000000000000000000000000000000000000000000000000000001400000000000000000000000004612ad240cd66a77b921693bbbb356d1b8219b2c00000000000000000000000000000000000000000000000000000000000000207673075a980bfd5d6b1dffe99c31f63e8938519cc1c2af009dda5e568a94460d00000000000000000000000000000000000000000000000000000000000000bd000000044f12fe6816ae7e33ebf7db0b154ec3b09e3bf1a7690481e8e9477d5a278ad3af012953026d328218b107268efe60f7d98635af1ff535a91731f75ca7cf8a85904401dd7c1b885eb85dbac2db2a4ce5887489200c20d2549a6ed12d202cd12a7dfe81010000000000000000000000000000000000000000000000000000000000000000000000001079f4fa0308e5e1011027000000000000027673075a980bfd5d6b1dffe99c31f63e8938519cc1c2af009dda5e568a94460d0000000000000000000000", + "value": "0" + }, + "finalTxHash": "kGUaPUfASg9Poo93aMsztHJjUk27MKuRJBfDZK1WP3FFSaXSYcoPcxjUMFyDxaK6aU6mQkZeowSu3MtvK5PXKgK", + "externalTxHash": "kGUaPUfASg9Poo93aMsztHJjUk27MKuRJBfDZK1WP3FFSaXSYcoPcxjUMFyDxaK6aU6mQkZeowSu3MtvK5PXKgK", + "externalChain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "externalExplorerUrl": "https://explorer.solana.com/tx/kGUaPUfASg9Poo93aMsztHJjUk27MKuRJBfDZK1WP3FFSaXSYcoPcxjUMFyDxaK6aU6mQkZeowSu3MtvK5PXKgK?cluster=devnet", + "externalRecipient": "0x7673075a980bfd5d6b1dffe99c31f63e8938519cc1c2af009dda5e568a94460d", + "externalAmount": "10000", + "externalAssetAddr": "0x0000000000000000000000000000000000000000", + "externalStatus": "success" + } + }, + { + "name": "svm-wire-preflight-refusals", + "at": "2026-10-06T07:25:22.319Z", + "network": "TESTNET_DONUT", + "sourceCommit": "e8db74815cfbbf5389593805e464fe8d85f7f735", + "wallet": "0x4612ad240cd66A77b921693BbbB356d1B8219b2c", + "rulesId": "0x0ed59a0b2764cf395b53a7a7d1b58e2ae3fb99b818be5392f3fdbc7eb4f645d0", + "nonce": 1, + "transactionsSent": 0 + }, + { + "name": "svm-wire-failure-submitted", + "at": "2026-10-06T07:25:42.438Z", + "network": "TESTNET_DONUT", + "sourceCommit": "e8db74815cfbbf5389593805e464fe8d85f7f735", + "wallet": "0x4612ad240cd66A77b921693BbbB356d1B8219b2c", + "rulesId": "0x0ed59a0b2764cf395b53a7a7d1b58e2ae3fb99b818be5392f3fdbc7eb4f645d0", + "hash": "0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc" + }, + { + "name": "svm-wire-failure-receipt", + "at": "2026-10-06T07:35:47.327Z", + "network": "TESTNET_DONUT", + "sourceCommit": "e8db74815cfbbf5389593805e464fe8d85f7f735", + "hash": "0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc", + "receipt": { + "hash": "0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc", + "blockNumber": "23949885", + "blockHash": "0xc465553f489498b344dd61a15da3ac67a7b98a294c72787ba4ab399e8adbfb4e", + "transactionIndex": 0, + "from": "0x4612ad240cd66A77b921693BbbB356d1B8219b2c", + "to": "0x00000000000000000000000000000000000000C1", + "contractAddress": null, + "gasPrice": "1125000000", + "gasUsed": "417241", + "cumulativeGasUsed": "417241", + "logs": [ + { + "address": "0x603e7f0af6e1aaff46ddfb28b1e99364f8bc59af", + "topics": [ + "0x3ac286ad36e454b1ae54d96d9de29fdde1f3984110b62d27d0c7bbc70ccfbf93", + "0xc83601cd9bbdf58b8e3e8ca5eda8bf224739c5f34b1b91e2c4c5d7a93cdb4fd5", + "0x000000000000000000000000165a5e6782f39d30b38c7d97e1303e4cb2ad102a", + "0x0000000000000000000000004612ad240cd66a77b921693bbbb356d1b8219b2c" + ], + "data": "0x0000000000000000000000005d525df2bd99a6e7ec58b76af2fd95f39874ebed0000000000000000000000000000000000000000000000000000000000002710", + "blockNumber": "23949885", + "transactionHash": "0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc", + "transactionIndex": 0, + "blockHash": "0xc465553f489498b344dd61a15da3ac67a7b98a294c72787ba4ab399e8adbfb4e", + "blockTimestamp": "0x6ac4a26c", + "logIndex": 0, + "removed": false + }, + { + "address": "0x5d525df2bd99a6e7ec58b76af2fd95f39874ebed", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000004612ad240cd66a77b921693bbbb356d1b8219b2c", + "0x00000000000000000000000000000000000000000000000000000000000000c1" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000002710", + "blockNumber": "23949885", + "transactionHash": "0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc", + "transactionIndex": 0, + "blockHash": "0xc465553f489498b344dd61a15da3ac67a7b98a294c72787ba4ab399e8adbfb4e", + "blockTimestamp": "0x6ac4a26c", + "logIndex": 1, + "removed": false + }, + { + "address": "0x5d525df2bd99a6e7ec58b76af2fd95f39874ebed", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x0000000000000000000000004612ad240cd66a77b921693bbbb356d1b8219b2c", + "0x00000000000000000000000000000000000000000000000000000000000000c1" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000000", + "blockNumber": "23949885", + "transactionHash": "0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc", + "transactionIndex": 0, + "blockHash": "0xc465553f489498b344dd61a15da3ac67a7b98a294c72787ba4ab399e8adbfb4e", + "blockTimestamp": "0x6ac4a26c", + "logIndex": 2, + "removed": false + }, + { + "address": "0x5d525df2bd99a6e7ec58b76af2fd95f39874ebed", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x00000000000000000000000000000000000000000000000000000000000000c1", + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000002710", + "blockNumber": "23949885", + "transactionHash": "0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc", + "transactionIndex": 0, + "blockHash": "0xc465553f489498b344dd61a15da3ac67a7b98a294c72787ba4ab399e8adbfb4e", + "blockTimestamp": "0x6ac4a26c", + "logIndex": 3, + "removed": false + }, + { + "address": "0xe17dd2e0509f99e9ee9469cf6634048ec5a3ade9", + "topics": [ + "0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c", + "0x00000000000000000000000000000000000000000000000000000000000000c0" + ], + "data": "0x0000000000000000000000000000000000000000000000008ac7230489e80000", + "blockNumber": "23949885", + "transactionHash": "0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc", + "transactionIndex": 0, + "blockHash": "0xc465553f489498b344dd61a15da3ac67a7b98a294c72787ba4ab399e8adbfb4e", + "blockTimestamp": "0x6ac4a26c", + "logIndex": 4, + "removed": false + }, + { + "address": "0xe17dd2e0509f99e9ee9469cf6634048ec5a3ade9", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x00000000000000000000000000000000000000000000000000000000000000c0", + "0x0000000000000000000000005d548bb9e305aae0d6dc6e6fdc3ab419f6ac0037" + ], + "data": "0x0000000000000000000000000000000000000000000000008ac7230489e80000", + "blockNumber": "23949885", + "transactionHash": "0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc", + "transactionIndex": 0, + "blockHash": "0xc465553f489498b344dd61a15da3ac67a7b98a294c72787ba4ab399e8adbfb4e", + "blockTimestamp": "0x6ac4a26c", + "logIndex": 5, + "removed": false + }, + { + "address": "0x5d525df2bd99a6e7ec58b76af2fd95f39874ebed", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000000e5914e3a7e2e6d18330dd33fa387ce33da48b54", + "0x00000000000000000000000000000000000000000000000000000000000000c0" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000ea600", + "blockNumber": "23949885", + "transactionHash": "0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc", + "transactionIndex": 0, + "blockHash": "0xc465553f489498b344dd61a15da3ac67a7b98a294c72787ba4ab399e8adbfb4e", + "blockTimestamp": "0x6ac4a26c", + "logIndex": 6, + "removed": false + }, + { + "address": "0xe17dd2e0509f99e9ee9469cf6634048ec5a3ade9", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x00000000000000000000000000000000000000000000000000000000000000c0", + "0x0000000000000000000000000e5914e3a7e2e6d18330dd33fa387ce33da48b54" + ], + "data": "0x0000000000000000000000000000000000000000000000000c112c58397d3a87", + "blockNumber": "23949885", + "transactionHash": "0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc", + "transactionIndex": 0, + "blockHash": "0xc465553f489498b344dd61a15da3ac67a7b98a294c72787ba4ab399e8adbfb4e", + "blockTimestamp": "0x6ac4a26c", + "logIndex": 7, + "removed": false + }, + { + "address": "0x0e5914e3a7e2e6d18330dd33fa387ce33da48b54", + "topics": [ + "0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67", + "0x0000000000000000000000005d548bb9e305aae0d6dc6e6fdc3ab419f6ac0037", + "0x00000000000000000000000000000000000000000000000000000000000000c0" + ], + "data": "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffff15a000000000000000000000000000000000000000000000000000c112c58397d3a8700000000000000000000000000000000000e84b1c10fb5fd51e951bcc48cb09f000000000000000000000000000000000000000000000002f15ecbc2e691bc650000000000000000000000000000000000000000000000000000000000043381", + "blockNumber": "23949885", + "transactionHash": "0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc", + "transactionIndex": 0, + "blockHash": "0xc465553f489498b344dd61a15da3ac67a7b98a294c72787ba4ab399e8adbfb4e", + "blockTimestamp": "0x6ac4a26c", + "logIndex": 8, + "removed": false + }, + { + "address": "0xe17dd2e0509f99e9ee9469cf6634048ec5a3ade9", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x00000000000000000000000000000000000000000000000000000000000000c0", + "0x0000000000000000000000005d548bb9e305aae0d6dc6e6fdc3ab419f6ac0037" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000000", + "blockNumber": "23949885", + "transactionHash": "0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc", + "transactionIndex": 0, + "blockHash": "0xc465553f489498b344dd61a15da3ac67a7b98a294c72787ba4ab399e8adbfb4e", + "blockTimestamp": "0x6ac4a26c", + "logIndex": 9, + "removed": false + }, + { + "address": "0x5d525df2bd99a6e7ec58b76af2fd95f39874ebed", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x00000000000000000000000000000000000000000000000000000000000000c0", + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000ea600", + "blockNumber": "23949885", + "transactionHash": "0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc", + "transactionIndex": 0, + "blockHash": "0xc465553f489498b344dd61a15da3ac67a7b98a294c72787ba4ab399e8adbfb4e", + "blockTimestamp": "0x6ac4a26c", + "logIndex": 10, + "removed": false + }, + { + "address": "0xe17dd2e0509f99e9ee9469cf6634048ec5a3ade9", + "topics": [ + "0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65", + "0x00000000000000000000000000000000000000000000000000000000000000c0" + ], + "data": "0x0000000000000000000000000000000000000000000000007eb5f6ac506ac579", + "blockNumber": "23949885", + "transactionHash": "0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc", + "transactionIndex": 0, + "blockHash": "0xc465553f489498b344dd61a15da3ac67a7b98a294c72787ba4ab399e8adbfb4e", + "blockTimestamp": "0x6ac4a26c", + "logIndex": 11, + "removed": false + }, + { + "address": "0x00000000000000000000000000000000000000c0", + "topics": [ + "0x01fd625a5ce1109c10761818e2ef64ea92cd4966d78086d37e5a4b50e3226878", + "0x0000000000000000000000005d525df2bd99a6e7ec58b76af2fd95f39874ebed", + "0x0000000000000000000000004612ad240cd66a77b921693bbbb356d1b8219b2c" + ], + "data": "0x0000000000000000000000000000000000000000000000000c112c58397d3a8700000000000000000000000000000000000000000000000000000000000ea60000000000000000000000000000000000000000000000000000000000000001f4", + "blockNumber": "23949885", + "transactionHash": "0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc", + "transactionIndex": 0, + "blockHash": "0xc465553f489498b344dd61a15da3ac67a7b98a294c72787ba4ab399e8adbfb4e", + "blockTimestamp": "0x6ac4a26c", + "logIndex": 12, + "removed": false + }, + { + "address": "0x00000000000000000000000000000000000000c1", + "topics": [ + "0x8882d1d8f7b1750e49d021ea8d62e07c2d163645b8fa31c035905d6572ffc637", + "0xd7e4da935abc97cbb68c0869dafa1e28038b89848c53650364250f60cd11e1ef", + "0x0000000000000000000000004612ad240cd66a77b921693bbbb356d1b8219b2c", + "0x0000000000000000000000005d525df2bd99a6e7ec58b76af2fd95f39874ebed" + ], + "data": "0x000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000027100000000000000000000000005d525df2bd99a6e7ec58b76af2fd95f39874ebed00000000000000000000000000000000000000000000000000000000000ea60000000000000000000000000000000000000000000000000000000000000003c0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004612ad240cd66a77b921693bbbb356d1b8219b2c000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000003e80000000000000000000000000000000000000000000000000000000000000027736f6c616e613a457457545241425a61597136694d6665594b6f755275313636565532787161310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000207673075a980bfd5d6b1dffe99c31f63e8938519cc1c2af009dda5e568a94460d000000000000000000000000000000000000000000000000000000000000007b000000024f12fe6816ae7e33ebf7db0b154ec3b09e3bf1a7690481e8e9477d5a278ad3af01dd7c1b885eb85dbac2db2a4ce5887489200c20d2549a6ed12d202cd12a7dfe8100000000106ae3a83bf81b96650100000000000000027673075a980bfd5d6b1dffe99c31f63e8938519cc1c2af009dda5e568a94460d0000000000", + "blockNumber": "23949885", + "transactionHash": "0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc", + "transactionIndex": 0, + "blockHash": "0xc465553f489498b344dd61a15da3ac67a7b98a294c72787ba4ab399e8adbfb4e", + "blockTimestamp": "0x6ac4a26c", + "logIndex": 13, + "removed": false + }, + { + "address": "0x4612ad240cd66a77b921693bbbb356d1b8219b2c", + "topics": [ + "0x3dbef004c3d4318a109f103c40928ef6cb77519329e4d7f473364dd15bf6b3fd", + "0x0ed59a0b2764cf395b53a7a7d1b58e2ae3fb99b818be5392f3fdbc7eb4f645d0", + "0x000000000000000000000000dffb9e4cc2b869cf35ab811675333f40cd04df76" + ], + "data": "0x356b0bac276dd8ee6f6f4f4e0ecbcc5ca8f3667706ef81daaa6b1d70a52701d3", + "blockNumber": "23949885", + "transactionHash": "0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc", + "transactionIndex": 0, + "blockHash": "0xc465553f489498b344dd61a15da3ac67a7b98a294c72787ba4ab399e8adbfb4e", + "blockTimestamp": "0x6ac4a26c", + "logIndex": 14, + "removed": false + } + ], + "logsBloom": "0x0020000110100000000000010000030100000000000000000000000000000000000000000000000000001e000000000000000000000022000400020040200008000000000200004808000008000000080000022004400004000800008020200400000000020002001000000004000802200000000000040200000090404800000000000000000004000000000000000000010001000000002000020000001000020010000000000200000080000000000000000000000040010000100000000004000002200020000000000000000090800000120000000000000002000020004010000012004000000000000000000000000000000001400000000040000000", + "status": 1, + "raw": { + "from": "0xDfFb9e4cc2b869cF35ab811675333f40cD04dF76", + "to": "0x4612ad240cd66A77b921693BbbB356d1B8219b2c", + "nonce": 1, + "data": "0xc0ca77910ed59a0b2764cf395b53a7a7d1b58e2ae3fb99b818be5392f3fdbc7eb4f645d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000023800000000000000000000000000000000000000c10000000000000000000000000000000000000000000000008ac7230489e8000077b86bec000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001000000000000000000000000005d525df2bd99a6e7ec58b76af2fd95f39874ebed000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008ac7230489e8000000000000000000000000000000000000000000000000000000000000000001400000000000000000000000004612ad240cd66a77b921693bbbb356d1b8219b2c00000000000000000000000000000000000000000000000000000000000000207673075a980bfd5d6b1dffe99c31f63e8938519cc1c2af009dda5e568a94460d000000000000000000000000000000000000000000000000000000000000007b000000024f12fe6816ae7e33ebf7db0b154ec3b09e3bf1a7690481e8e9477d5a278ad3af01dd7c1b885eb85dbac2db2a4ce5887489200c20d2549a6ed12d202cd12a7dfe8100000000106ae3a83bf81b96650100000000000000027673075a980bfd5d6b1dffe99c31f63e8938519cc1c2af009dda5e568a94460d00000000000000000000000000", + "value": "0" + }, + "finalTxHash": "0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc", + "externalStatus": "timeout", + "externalError": "Timeout waiting for outbound transaction. Push Chain TX: 0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc. Timeout: 600000ms. The relay may still be processing." + } + } +] diff --git a/plan/agw/research/live-svm-wire-2026-10-06/live-policy-probes.json b/plan/agw/research/live-svm-wire-2026-10-06/live-policy-probes.json new file mode 100644 index 00000000..875f77f4 --- /dev/null +++ b/plan/agw/research/live-svm-wire-2026-10-06/live-policy-probes.json @@ -0,0 +1,29 @@ +{ + "at": "2026-10-06T07:36:52.702Z", + "sourceHash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "chainId": 42101, + "block": "23949837", + "observations": [ + { + "kind": "account-pin", + "reverted": true, + "decoded": { + "name": "PolicyCheckReverted(SvmAccountPinMismatch)", + "selector": "0xf4270752", + "decoded": "0xff3dafe500000000000000000000000000000000000000000000000000000000", + "hint": "URP rejected the action (truncated through the session engine). The inner selector names the gate; arguments are truncated to 28 bytes." + } + }, + { + "kind": "instruction-data-pin", + "reverted": true, + "decoded": { + "name": "PolicyCheckReverted(SvmDataCeilingExceeded)", + "selector": "0xf4270752", + "decoded": "0x94de1ef800000000000000000000000000000000000000000000000000000000", + "hint": "URP rejected the action (truncated through the session engine). The inner selector names the gate; arguments are truncated to 28 bytes." + } + } + ], + "transactionsSent": 0 +} \ No newline at end of file diff --git a/plan/agw/research/live-svm-wire-2026-10-06/logs/build.log b/plan/agw/research/live-svm-wire-2026-10-06/logs/build.log new file mode 100644 index 00000000..e255f704 --- /dev/null +++ b/plan/agw/research/live-svm-wire-2026-10-06/logs/build.log @@ -0,0 +1,11 @@ + +> nx run core:build + +Compiling TypeScript files for project "core"... +Done compiling TypeScript files for project "core". +(node:77080) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. +(Use `node --trace-warnings ...` to show where the warning was created) + + + + NX Successfully ran target build for project core diff --git a/plan/agw/research/live-svm-wire-2026-10-06/logs/lint.log b/plan/agw/research/live-svm-wire-2026-10-06/logs/lint.log new file mode 100644 index 00000000..5c65d631 --- /dev/null +++ b/plan/agw/research/live-svm-wire-2026-10-06/logs/lint.log @@ -0,0 +1,31 @@ + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/agw-svm-wire/outbound.spec.ts + 114:38 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 126:56 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 127:48 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 127:48 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 128:28 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 129:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 129:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 133:30 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 146:23 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 170:50 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 170:50 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/agw-svm-wire/replay.spec.ts + 33:40 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 44:40 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 47:83 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 49:51 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 54:82 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/shared/agw-svm-preflight.ts + 12:33 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 17:34 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/svm-wire-fixture.spec.ts + 41:50 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 46:45 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 50:45 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +✖ 21 problems (0 errors, 21 warnings) diff --git a/plan/agw/research/live-svm-wire-2026-10-06/logs/live-bootstrap-fixed.log b/plan/agw/research/live-svm-wire-2026-10-06/logs/live-bootstrap-fixed.log new file mode 100644 index 00000000..49b667c1 --- /dev/null +++ b/plan/agw/research/live-svm-wire-2026-10-06/logs/live-bootstrap-fixed.log @@ -0,0 +1,31 @@ +Running 3 scenarios (group: agw-svm-wire) across 1 spec files. + +FAIL core-e2e __e2e__/agw-svm-wire/outbound.spec.ts (805.011 s) + agw svm wire + ✓ 1. positive outbound: actual CEA transfer and counter execution, receipt and replay (102123 ms) + ✓ 2. substituted account and oversized instruction amount fail before submission (11664 ms) + ✕ 3. destination program failure is classified and does not restore policy spend (625608 ms) + + ● agw svm wire › 3. destination program failure is classified and does not restore policy spend + + expect(received).toBe(expected) // Object.is equality + + Expected: "failed" + Received: "timeout" + + 159 | f.evidence('svm-wire-failure-submitted', { wallet, rulesId, hash: tx.hash }); + 160 | await adaptTrackedResponse(rt(agent), tx); + > 161 | const receipt = await tx.wait({ outboundTimeoutMs: 600_000 }); + | ^ + 162 | f.evidence('svm-wire-failure-receipt', { hash: tx.hash, receipt }); + 163 | const pushReceipt = await f.push.getTransactionReceipt({ hash: tx.hash as Hex }); + 164 | expect(pushReceipt.status).toBe('success'); expect(receipt.externalStatus).toBe('failed'); + + at Object. (__e2e__/agw-svm-wire/outbound.spec.ts:161:80) + +Test Suites: 1 failed, 1 total +Tests: 1 failed, 2 passed, 3 total +Snapshots: 0 total +Time: 805.092 s +Ran all test suites within paths "__e2e__/agw-svm-wire/outbound.spec.ts". +Force exiting Jest: Have you considered using `--detectOpenHandles` to detect async operations that kept running after all tests finished? diff --git a/plan/agw/research/live-svm-wire-2026-10-06/logs/live-initial.log b/plan/agw/research/live-svm-wire-2026-10-06/logs/live-initial.log new file mode 100644 index 00000000..a6d7d817 --- /dev/null +++ b/plan/agw/research/live-svm-wire-2026-10-06/logs/live-initial.log @@ -0,0 +1,62 @@ +Running 3 scenarios (group: agw-svm-wire) across 1 spec files. + +FAIL core-e2e __e2e__/agw-svm-wire/outbound.spec.ts (20.197 s) + agw svm wire + ✕ 1. positive outbound: actual CEA transfer and counter execution, receipt and replay (1 ms) + ✕ 2. substituted account and oversized instruction amount fail before submission + ✕ 3. destination program failure is classified and does not restore policy spend + + ● agw svm wire › 1. positive outbound: actual CEA transfer and counter execution, receipt and replay + + TypeError: Cannot read properties of undefined (reading 'signer') + + 37 | + 38 | const universalSigner = + > 39 | await PushChain.utils.signer.toUniversalFromKeypair(walletClient, { + | ^ + 40 | chain: opts.chain, + 41 | library: PushChain.CONSTANTS.LIBRARY.ETHEREUM_VIEM, + 42 | }); + + at createEvmPushClient (__e2e__/shared/evm-client.ts:39:27) + at setupAgw (__e2e__/agw/_fixture.ts:77:67) + at async Object. (__e2e__/agw-svm-wire/outbound.spec.ts:83:9) + + ● agw svm wire › 2. substituted account and oversized instruction amount fail before submission + + TypeError: Cannot read properties of undefined (reading 'signer') + + 37 | + 38 | const universalSigner = + > 39 | await PushChain.utils.signer.toUniversalFromKeypair(walletClient, { + | ^ + 40 | chain: opts.chain, + 41 | library: PushChain.CONSTANTS.LIBRARY.ETHEREUM_VIEM, + 42 | }); + + at createEvmPushClient (__e2e__/shared/evm-client.ts:39:27) + at setupAgw (__e2e__/agw/_fixture.ts:77:67) + at async Object. (__e2e__/agw-svm-wire/outbound.spec.ts:83:9) + + ● agw svm wire › 3. destination program failure is classified and does not restore policy spend + + TypeError: Cannot read properties of undefined (reading 'signer') + + 37 | + 38 | const universalSigner = + > 39 | await PushChain.utils.signer.toUniversalFromKeypair(walletClient, { + | ^ + 40 | chain: opts.chain, + 41 | library: PushChain.CONSTANTS.LIBRARY.ETHEREUM_VIEM, + 42 | }); + + at createEvmPushClient (__e2e__/shared/evm-client.ts:39:27) + at setupAgw (__e2e__/agw/_fixture.ts:77:67) + at async Object. (__e2e__/agw-svm-wire/outbound.spec.ts:83:9) + +Test Suites: 1 failed, 1 total +Tests: 3 failed, 3 total +Snapshots: 0 total +Time: 20.219 s +Ran all test suites within paths "__e2e__/agw-svm-wire/outbound.spec.ts". +Force exiting Jest: Have you considered using `--detectOpenHandles` to detect async operations that kept running after all tests finished? diff --git a/plan/agw/research/live-svm-wire-2026-10-06/logs/replay.log b/plan/agw/research/live-svm-wire-2026-10-06/logs/replay.log new file mode 100644 index 00000000..63bf6a05 --- /dev/null +++ b/plan/agw/research/live-svm-wire-2026-10-06/logs/replay.log @@ -0,0 +1,14 @@ +Running 3 scenarios (group: agw-svm-replay) across 1 spec files. + +PASS core-e2e __e2e__/agw-svm-wire/replay.spec.ts (58.193 s) + agw svm recorded replay + ✓ 1. positive replay retains wallet, signer origin and actual Solana signature (26146 ms) + ✓ 2. later terminal rejection is failed, while the source succeeded and spend remains charged (28339 ms) + ✓ 3. pinned live policy calls refuse account and data mutations without submitting (1057 ms) + +Test Suites: 1 passed, 1 total +Tests: 3 passed, 3 total +Snapshots: 0 total +Time: 58.215 s +Ran all test suites within paths "__e2e__/agw-svm-wire/replay.spec.ts". +Force exiting Jest: Have you considered using `--detectOpenHandles` to detect async operations that kept running after all tests finished? diff --git a/plan/agw/research/live-svm-wire-2026-10-06/logs/unit.log b/plan/agw/research/live-svm-wire-2026-10-06/logs/unit.log new file mode 100644 index 00000000..181c7190 --- /dev/null +++ b/plan/agw/research/live-svm-wire-2026-10-06/logs/unit.log @@ -0,0 +1,169 @@ +PASS core packages/core/src/lib/universal/account/account.spec.ts + ● Console + + console.warn + [PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead. + + 207 | ): Promise { + 208 | if (!_convertOriginToExecutorWarned) { + > 209 | console.warn( + | ^ + 210 | '[PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead.' + 211 | ); + 212 | _convertOriginToExecutorWarned = true; + + at Object.convertOriginToExecutor (src/lib/universal/account/account.ts:209:13) + at Object. (src/lib/universal/account/account.spec.ts:80:52) + + console.warn + [PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead. + + 425 | ): Promise { + 426 | if (!options?._internal && !_convertExecutorToOriginWarned) { + > 427 | console.warn( + | ^ + 428 | '[PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead.' + 429 | ); + 430 | _convertExecutorToOriginWarned = true; + + at convertExecutorToOrigin (src/lib/universal/account/account.ts:427:13) + at Object. (src/lib/universal/account/account.spec.ts:106:38) + +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-confirmation-gate.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-wire-fixture.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/block-results-client.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-tx-retry.spec.ts +PASS core packages/core/src/lib/push-client/push-client.archive-fallback.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-timeout-clamp.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r2-outbound-revert-flow.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-svm-confirmation.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gateway-uea-account.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/inbound-tracker-derivation.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/source-hash-resolution.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/cascade.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-executor.spec.ts +PASS core packages/core/src/lib/universal/signer/signer.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/chain-namespace.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/signing-payload.spec.ts +PASS core packages/core/src/lib/utils.spec.ts + ● Console + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:973:17) + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:977:17) + + console.log + 1.23 + + at Object. (src/lib/utils.spec.ts:982:17) + +PASS core packages/core/src/lib/read-state/__tests__/read-tracker.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/rescue-svm-confirmation.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/execute-standard-required-funds.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/send-transaction-progress-hook.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/context-helpers-tracker.spec.ts +PASS core packages/core/src/lib/push-client/push-client.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/scenarios.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/management.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/response-invariant.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/track-transaction-guard.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/inbound-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/gate.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-svm-r3.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/build-payload.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/read-tx-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/response-surface.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/public-surface.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-emission.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/account-status.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/send.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-evm-r3-native-eoa.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/resolver.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/resolve.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/payload-builders.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-builder-progress-hook.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-composition.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r3-spec-strings.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/multichain-hooks.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-detector.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/registry.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/export.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-native-multicall.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r1-spec-strings.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-backend.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r2-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-svm-rent.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-usd-sizer.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/web2-compat.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/svm-rent.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-multichain.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm-rent-pc20.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/funds-only-burn-guard.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/terminal-suppression.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/response-builder-push-revert.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-calculator.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-event-hook-bridge.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-request-recipient.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/svm-account.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-svm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-evm.spec.ts +PASS core packages/core/src/lib/constants/__tests__/token-constants.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-events.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/spec-builder.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.chain-symbol.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/revalidate-read.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/result-decoder.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm-log-index.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-params.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/budget.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/address-codec.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/abi-selectors.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/__tests__/signing.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-types.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/normalize.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/validate.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/child-inbounds.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/reads-context.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/auto-detect.spec.ts +PASS core packages/core/src/lib/formatters.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/codec.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg-svm.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.dynamic-gas.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/ucallback-codec.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/tracking.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-web2.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/classify.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/ix-encoder.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-execute-order.spec.ts +PASS core packages/core/src/lib/constants/__tests__/svm-gateway-idl.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/registry.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/max-pc-for-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/error-decoder.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/normalize-address.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/errors.spec.ts + +Test Suites: 1 skipped, 116 passed, 116 of 117 total +Tests: 12 skipped, 1981 passed, 1993 total +Snapshots: 0 total +Time: 31.077 s +Ran all test suites. diff --git a/plan/agw/research/live-svm-wire-2026-10-06/platform-followup.md b/plan/agw/research/live-svm-wire-2026-10-06/platform-followup.md new file mode 100644 index 00000000..461fb86f --- /dev/null +++ b/plan/agw/research/live-svm-wire-2026-10-06/platform-followup.md @@ -0,0 +1,35 @@ +# Solana rejection terminalizes after the SDK timeout — operational follow-up + +For the Push outbound executor/relay team; Harsh/Zaryab can help route this if timing clarification is useful. This is a read-only evidence note, not a message that has been sent. Terminal failure is now observed, so this is not an unresolved delivery blocker or an established relay defect. + +## Observed behavior + +On October 6, 2026 we sent two internal AGW SVM outbounds through the same verified Donut v4 generation and devnet gateway. The positive receive_sol call completed and its wallet CEA transfer/CPI were verified. The second intentionally calls decrement with a CEA that is not the counter's authority. + +| Evidence | Value | +| --- | --- | +| Push hash | 0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc | +| Push block/status | 23949885 / SUCCESS | +| Universal/subtransaction ID | f328cfa0af8a4e50afc3648205161759c02f1d0ddd27c40ba25f15990d084f36 | +| Outbound ID | d7e4da935abc97cbb68c0869dafa1e28038b89848c53650364250f60cd11e1ef | +| Destination | Solana devnet; gateway CFVSincHYbETh2k7w6u1ENEkjbSLtveRCEBupKidw2VS | +| Program/instruction | 8yNqjrMnFiFbVTVQcKij8tNWWTMdFkrDf9abCGgc2sgx / decrement(1) | +| Expected destination error | Actual read-only simulation returns Unauthorized, custom error 6002 | +| Node observation | PENDING (1), universal status UNSPECIFIED (0), no observedTx hash, no abortReason | +| SDK wait | Push status 1, externalStatus timeout after 600 seconds; source hash retained | +| Later node observation | REVERTED (3), observed success=false, error "tx not executed on destination chain", no Solana hash | +| Later read-only replay | Push status 1, externalStatus failed, same source identity/hash | +| Refund executions | Asset and gas refunds report SUCCESS at block 23950149; policy spent remains 20,000 | + +[Initial node state](failure-observation.json), [terminal record](failure-observation-final.json), [simulation and error logs](destination-rejection-simulation.json), [source/SDK receipt evidence](live-evidence.json), [read-only replay](readonly-replay.json), [initial strict test output](logs/live-bootstrap-fixed.log). + +The positive sibling source hash is 0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8. It proves this wallet/gateway/program route delivers a permitted instruction; the negative route is not evidence of missing deployed SVM support. + +## Optional operational clarification + +1. What retry/expiry and terminalization window should the SDK documentation and negative live tests expect for a Solana program/preflight rejection? This case exceeded the initial ten-minute wait, then became terminal without another source submission. +2. Can the observed record preserve the actual program/preflight reason (Unauthorized/6002 here), instead of only "tx not executed on destination chain"? A destination hash may legitimately be absent. + +The SDK follows the published state correctly: timeout while pending, failed after REVERTED. The test keeps that distinction and allows a bounded twenty-minute failure window for future funded runs. The successful read-only recovery does not erase the initial timeout result or establish a guaranteed terminalization SLA. + +This is separate from creditRevert integration. Returning assets/gas does not lower policy spend; final accounting remains charged. No failed Solana transaction signature is claimed because the record says execution did not occur on the destination. diff --git a/plan/agw/research/live-svm-wire-2026-10-06/policy-spend-after-timeout.json b/plan/agw/research/live-svm-wire-2026-10-06/policy-spend-after-timeout.json new file mode 100644 index 00000000..afe16d0b --- /dev/null +++ b/plan/agw/research/live-svm-wire-2026-10-06/policy-spend-after-timeout.json @@ -0,0 +1,14 @@ +{ + "at": "2026-10-06T07:36:57.491Z", + "block": "23950160", + "wallet": "0x4612ad240cd66a77b921693bbbb356d1b8219b2c", + "rulesId": "0x0ed59a0b2764cf395b53a7a7d1b58e2ae3fb99b818be5392f3fdbc7eb4f645d0", + "assets": [ + { + "token": "0x5D525Df2bD99a6e7ec58b76aF2fd95F39874EBed", + "maxPerCall": "10000", + "maxTotal": "20000", + "spent": "20000" + } + ] +} \ No newline at end of file diff --git a/plan/agw/research/live-svm-wire-2026-10-06/preflight.json b/plan/agw/research/live-svm-wire-2026-10-06/preflight.json new file mode 100644 index 00000000..a4933c48 --- /dev/null +++ b/plan/agw/research/live-svm-wire-2026-10-06/preflight.json @@ -0,0 +1,53 @@ +{ + "push": { + "chainId": 42101, + "block": "23949601", + "sourceCommit": "e8db74815cfbbf5389593805e464fe8d85f7f735", + "token": "0x5D525Df2bD99a6e7ec58b76aF2fd95F39874EBed", + "quote": [ + "0x5D525Df2bD99a6e7ec58b76aF2fd95F39874EBed", + "960000", + "0", + "1000", + "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "960" + ] + }, + "solana": { + "checkedAt": "2026-10-06T07:14:03.580Z", + "chain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "genesis": "EtWTRABZaYq6iMfeYKouRu166VU2xqa1wcaWoxPkrZBG", + "slot": 508014048, + "programDataSlot": 508014048, + "programs": [ + { + "address": "CFVSincHYbETh2k7w6u1ENEkjbSLtveRCEBupKidw2VS", + "programData": "DqeV1giGX9UPbTCsUaqau4ZaTqmjxKeRa4TQdbLiUCYC", + "lastUpgradeSlot": "496655369", + "dataLength": 724997, + "dataSha256": "2633943f479debc6bf0cba19861f90dfd01a09ecba206b2ce941c97281b8a95d" + }, + { + "address": "8yNqjrMnFiFbVTVQcKij8tNWWTMdFkrDf9abCGgc2sgx", + "programData": "GQmC7eueNLqazwr7U9fR3s4VwbXUtNf1HL6UCXuSWvaN", + "lastUpgradeSlot": "447956626", + "dataLength": 279709, + "dataSha256": "6887b9299b53bcaede79facbe9d9a53c9a0ba78e2c109322caef070b57637f95" + } + ], + "gatewayConfig": { + "address": "2urirovTZSgpEAEFyf2dMWjMTqfkgg1J3piTBeSEwV5P", + "paused": false, + "dataSha256": "1f7595b955ae35e2ea577db04d3e73f30d7284d9536910065e0fc7b078b6ae33" + }, + "counter": { + "address": "6Kg1NF5RRytjGwR6USttBLEYJrqwm65xtJzdPbbFwJKg", + "value": "201889018", + "authority": "BesWssuCiGE3EqeGRFamuouvAxJDUCdWH6NPHpAFPMBa", + "dataSha256": "4b1725035d45f06567ffe10489d847db80caeb03a2fa853a018cac309879e224" + }, + "counterIdlSha256": "493678d103afab762cc1668d02c641226125166ba8b4d7df46b67fec52b3a9ca", + "gatewayIdlSha256": "62d7792d04c657e1224f7c64d13b68e2f49dd39fdd6da0088deca0c32a5fb042" + }, + "transactionsSent": 0 +} diff --git a/plan/agw/research/live-svm-wire-2026-10-06/readonly-replay.json b/plan/agw/research/live-svm-wire-2026-10-06/readonly-replay.json new file mode 100644 index 00000000..1e6ec02e --- /dev/null +++ b/plan/agw/research/live-svm-wire-2026-10-06/readonly-replay.json @@ -0,0 +1,574 @@ +{ + "at": "2026-10-06T07:46:11.434Z", + "readOnlyClient": true, + "transactionsSent": 0, + "observations": [ + { + "kind": "positive", + "hash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "from": "0x4612ad240cd66A77b921693BbbB356d1B8219b2c", + "origin": "eip155:42101:0xDfFb9e4cc2b869cF35ab811675333f40cD04dF76", + "route": "UOA_TO_CEA", + "agentic": { + "wallet": "0x4612ad240cd66A77b921693BbbB356d1B8219b2c", + "door": "agent", + "rulesId": "0x0ed59a0b2764cf395b53a7a7d1b58e2ae3fb99b818be5392f3fdbc7eb4f645d0", + "chainNamespace": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "rawTo": "0x4612ad240cd66A77b921693BbbB356d1B8219b2c", + "rawData": "0xc0ca77910ed59a0b2764cf395b53a7a7d1b58e2ae3fb99b818be5392f3fdbc7eb4f645d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000027800000000000000000000000000000000000000c10000000000000000000000000000000000000000000000008ac7230489e8000077b86bec000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001000000000000000000000000005d525df2bd99a6e7ec58b76af2fd95f39874ebed000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008ac7230489e8000000000000000000000000000000000000000000000000000000000000000001400000000000000000000000004612ad240cd66a77b921693bbbb356d1b8219b2c00000000000000000000000000000000000000000000000000000000000000207673075a980bfd5d6b1dffe99c31f63e8938519cc1c2af009dda5e568a94460d00000000000000000000000000000000000000000000000000000000000000bd000000044f12fe6816ae7e33ebf7db0b154ec3b09e3bf1a7690481e8e9477d5a278ad3af012953026d328218b107268efe60f7d98635af1ff535a91731f75ca7cf8a85904401dd7c1b885eb85dbac2db2a4ce5887489200c20d2549a6ed12d202cd12a7dfe81010000000000000000000000000000000000000000000000000000000000000000000000001079f4fa0308e5e1011027000000000000027673075a980bfd5d6b1dffe99c31f63e8938519cc1c2af009dda5e568a94460d0000000000000000000000" + }, + "receipt": { + "hash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "blockNumber": "23949837", + "blockHash": "0xf5a2ba7e2704285075f3df2c63321ea337f6e0e55fc042abe4441afc260c594b", + "transactionIndex": 1, + "from": "0x4612ad240cd66A77b921693BbbB356d1B8219b2c", + "to": "0x00000000000000000000000000000000000000C1", + "contractAddress": null, + "gasPrice": "1125000000", + "gasUsed": "445073", + "cumulativeGasUsed": "445073", + "logs": [ + { + "address": "0x603e7f0af6e1aaff46ddfb28b1e99364f8bc59af", + "topics": [ + "0x3ac286ad36e454b1ae54d96d9de29fdde1f3984110b62d27d0c7bbc70ccfbf93", + "0xc83601cd9bbdf58b8e3e8ca5eda8bf224739c5f34b1b91e2c4c5d7a93cdb4fd5", + "0x000000000000000000000000165a5e6782f39d30b38c7d97e1303e4cb2ad102a", + "0x0000000000000000000000004612ad240cd66a77b921693bbbb356d1b8219b2c" + ], + "data": "0x0000000000000000000000005d525df2bd99a6e7ec58b76af2fd95f39874ebed0000000000000000000000000000000000000000000000000000000000002710", + "blockNumber": "23949837", + "transactionHash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "transactionIndex": 1, + "blockHash": "0xf5a2ba7e2704285075f3df2c63321ea337f6e0e55fc042abe4441afc260c594b", + "blockTimestamp": "0x6ac4a1f7", + "logIndex": 1, + "removed": false + }, + { + "address": "0x5d525df2bd99a6e7ec58b76af2fd95f39874ebed", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000004612ad240cd66a77b921693bbbb356d1b8219b2c", + "0x00000000000000000000000000000000000000000000000000000000000000c1" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000002710", + "blockNumber": "23949837", + "transactionHash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "transactionIndex": 1, + "blockHash": "0xf5a2ba7e2704285075f3df2c63321ea337f6e0e55fc042abe4441afc260c594b", + "blockTimestamp": "0x6ac4a1f7", + "logIndex": 2, + "removed": false + }, + { + "address": "0x5d525df2bd99a6e7ec58b76af2fd95f39874ebed", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x0000000000000000000000004612ad240cd66a77b921693bbbb356d1b8219b2c", + "0x00000000000000000000000000000000000000000000000000000000000000c1" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000002710", + "blockNumber": "23949837", + "transactionHash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "transactionIndex": 1, + "blockHash": "0xf5a2ba7e2704285075f3df2c63321ea337f6e0e55fc042abe4441afc260c594b", + "blockTimestamp": "0x6ac4a1f7", + "logIndex": 3, + "removed": false + }, + { + "address": "0x5d525df2bd99a6e7ec58b76af2fd95f39874ebed", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x00000000000000000000000000000000000000000000000000000000000000c1", + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000002710", + "blockNumber": "23949837", + "transactionHash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "transactionIndex": 1, + "blockHash": "0xf5a2ba7e2704285075f3df2c63321ea337f6e0e55fc042abe4441afc260c594b", + "blockTimestamp": "0x6ac4a1f7", + "logIndex": 4, + "removed": false + }, + { + "address": "0xe17dd2e0509f99e9ee9469cf6634048ec5a3ade9", + "topics": [ + "0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c", + "0x00000000000000000000000000000000000000000000000000000000000000c0" + ], + "data": "0x0000000000000000000000000000000000000000000000008ac7230489e80000", + "blockNumber": "23949837", + "transactionHash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "transactionIndex": 1, + "blockHash": "0xf5a2ba7e2704285075f3df2c63321ea337f6e0e55fc042abe4441afc260c594b", + "blockTimestamp": "0x6ac4a1f7", + "logIndex": 5, + "removed": false + }, + { + "address": "0xe17dd2e0509f99e9ee9469cf6634048ec5a3ade9", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x00000000000000000000000000000000000000000000000000000000000000c0", + "0x0000000000000000000000005d548bb9e305aae0d6dc6e6fdc3ab419f6ac0037" + ], + "data": "0x0000000000000000000000000000000000000000000000008ac7230489e80000", + "blockNumber": "23949837", + "transactionHash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "transactionIndex": 1, + "blockHash": "0xf5a2ba7e2704285075f3df2c63321ea337f6e0e55fc042abe4441afc260c594b", + "blockTimestamp": "0x6ac4a1f7", + "logIndex": 6, + "removed": false + }, + { + "address": "0x5d525df2bd99a6e7ec58b76af2fd95f39874ebed", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000000e5914e3a7e2e6d18330dd33fa387ce33da48b54", + "0x00000000000000000000000000000000000000000000000000000000000000c0" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000ea600", + "blockNumber": "23949837", + "transactionHash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "transactionIndex": 1, + "blockHash": "0xf5a2ba7e2704285075f3df2c63321ea337f6e0e55fc042abe4441afc260c594b", + "blockTimestamp": "0x6ac4a1f7", + "logIndex": 7, + "removed": false + }, + { + "address": "0xe17dd2e0509f99e9ee9469cf6634048ec5a3ade9", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x00000000000000000000000000000000000000000000000000000000000000c0", + "0x0000000000000000000000000e5914e3a7e2e6d18330dd33fa387ce33da48b54" + ], + "data": "0x0000000000000000000000000000000000000000000000000c112c5348fdcf04", + "blockNumber": "23949837", + "transactionHash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "transactionIndex": 1, + "blockHash": "0xf5a2ba7e2704285075f3df2c63321ea337f6e0e55fc042abe4441afc260c594b", + "blockTimestamp": "0x6ac4a1f7", + "logIndex": 8, + "removed": false + }, + { + "address": "0x0e5914e3a7e2e6d18330dd33fa387ce33da48b54", + "topics": [ + "0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67", + "0x0000000000000000000000005d548bb9e305aae0d6dc6e6fdc3ab419f6ac0037", + "0x00000000000000000000000000000000000000000000000000000000000000c0" + ], + "data": "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffff15a000000000000000000000000000000000000000000000000000c112c5348fdcf0400000000000000000000000000000000000e84b1be17079db39e9ef80a30b925000000000000000000000000000000000000000000000002f15ecbc2e691bc650000000000000000000000000000000000000000000000000000000000043381", + "blockNumber": "23949837", + "transactionHash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "transactionIndex": 1, + "blockHash": "0xf5a2ba7e2704285075f3df2c63321ea337f6e0e55fc042abe4441afc260c594b", + "blockTimestamp": "0x6ac4a1f7", + "logIndex": 9, + "removed": false + }, + { + "address": "0xe17dd2e0509f99e9ee9469cf6634048ec5a3ade9", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x00000000000000000000000000000000000000000000000000000000000000c0", + "0x0000000000000000000000005d548bb9e305aae0d6dc6e6fdc3ab419f6ac0037" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000000", + "blockNumber": "23949837", + "transactionHash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "transactionIndex": 1, + "blockHash": "0xf5a2ba7e2704285075f3df2c63321ea337f6e0e55fc042abe4441afc260c594b", + "blockTimestamp": "0x6ac4a1f7", + "logIndex": 10, + "removed": false + }, + { + "address": "0x5d525df2bd99a6e7ec58b76af2fd95f39874ebed", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x00000000000000000000000000000000000000000000000000000000000000c0", + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000ea600", + "blockNumber": "23949837", + "transactionHash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "transactionIndex": 1, + "blockHash": "0xf5a2ba7e2704285075f3df2c63321ea337f6e0e55fc042abe4441afc260c594b", + "blockTimestamp": "0x6ac4a1f7", + "logIndex": 11, + "removed": false + }, + { + "address": "0xe17dd2e0509f99e9ee9469cf6634048ec5a3ade9", + "topics": [ + "0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65", + "0x00000000000000000000000000000000000000000000000000000000000000c0" + ], + "data": "0x0000000000000000000000000000000000000000000000007eb5f6b140ea30fc", + "blockNumber": "23949837", + "transactionHash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "transactionIndex": 1, + "blockHash": "0xf5a2ba7e2704285075f3df2c63321ea337f6e0e55fc042abe4441afc260c594b", + "blockTimestamp": "0x6ac4a1f7", + "logIndex": 12, + "removed": false + }, + { + "address": "0x00000000000000000000000000000000000000c0", + "topics": [ + "0x01fd625a5ce1109c10761818e2ef64ea92cd4966d78086d37e5a4b50e3226878", + "0x0000000000000000000000005d525df2bd99a6e7ec58b76af2fd95f39874ebed", + "0x0000000000000000000000004612ad240cd66a77b921693bbbb356d1b8219b2c" + ], + "data": "0x0000000000000000000000000000000000000000000000000c112c5348fdcf0400000000000000000000000000000000000000000000000000000000000ea60000000000000000000000000000000000000000000000000000000000000001f4", + "blockNumber": "23949837", + "transactionHash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "transactionIndex": 1, + "blockHash": "0xf5a2ba7e2704285075f3df2c63321ea337f6e0e55fc042abe4441afc260c594b", + "blockTimestamp": "0x6ac4a1f7", + "logIndex": 13, + "removed": false + }, + { + "address": "0x00000000000000000000000000000000000000c1", + "topics": [ + "0x8882d1d8f7b1750e49d021ea8d62e07c2d163645b8fa31c035905d6572ffc637", + "0xdcce211428bdd1e5bb6cd8c346fd68e2e919245bd28bca9692ec281d7a69fbcc", + "0x0000000000000000000000004612ad240cd66a77b921693bbbb356d1b8219b2c", + "0x0000000000000000000000005d525df2bd99a6e7ec58b76af2fd95f39874ebed" + ], + "data": "0x000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000027100000000000000000000000005d525df2bd99a6e7ec58b76af2fd95f39874ebed00000000000000000000000000000000000000000000000000000000000ea60000000000000000000000000000000000000000000000000000000000000003c0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004612ad240cd66a77b921693bbbb356d1b8219b2c000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000003e80000000000000000000000000000000000000000000000000000000000000027736f6c616e613a457457545241425a61597136694d6665594b6f755275313636565532787161310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000207673075a980bfd5d6b1dffe99c31f63e8938519cc1c2af009dda5e568a94460d00000000000000000000000000000000000000000000000000000000000000bd000000044f12fe6816ae7e33ebf7db0b154ec3b09e3bf1a7690481e8e9477d5a278ad3af012953026d328218b107268efe60f7d98635af1ff535a91731f75ca7cf8a85904401dd7c1b885eb85dbac2db2a4ce5887489200c20d2549a6ed12d202cd12a7dfe81010000000000000000000000000000000000000000000000000000000000000000000000001079f4fa0308e5e1011027000000000000027673075a980bfd5d6b1dffe99c31f63e8938519cc1c2af009dda5e568a94460d000000", + "blockNumber": "23949837", + "transactionHash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "transactionIndex": 1, + "blockHash": "0xf5a2ba7e2704285075f3df2c63321ea337f6e0e55fc042abe4441afc260c594b", + "blockTimestamp": "0x6ac4a1f7", + "logIndex": 14, + "removed": false + }, + { + "address": "0x4612ad240cd66a77b921693bbbb356d1b8219b2c", + "topics": [ + "0x3dbef004c3d4318a109f103c40928ef6cb77519329e4d7f473364dd15bf6b3fd", + "0x0ed59a0b2764cf395b53a7a7d1b58e2ae3fb99b818be5392f3fdbc7eb4f645d0", + "0x000000000000000000000000dffb9e4cc2b869cf35ab811675333f40cd04df76" + ], + "data": "0xc2c1ff13c20fb17960a533cdbe11f2e82e5f4020bef7ff8e0c3749d5f2edd18b", + "blockNumber": "23949837", + "transactionHash": "0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8", + "transactionIndex": 1, + "blockHash": "0xf5a2ba7e2704285075f3df2c63321ea337f6e0e55fc042abe4441afc260c594b", + "blockTimestamp": "0x6ac4a1f7", + "logIndex": 15, + "removed": false + } + ], + "logsBloom": "0x0020000110100000000000010000030100000000000000000000000000000000000000000000000000001e000000000000000000000022000400020040200008000000000200004808000008000000080000020004400004000800008020200000000000020002001000000004000803200000000000040200000090404c00000000000000000004000000000000000000010001000000002000020000001000020010000000000200000080000000000000000000000040010000100000000004000002200020000000000000000090800000100000000000000002000020004010020012004000000000000000000000000000000001400000000040000000", + "status": 1, + "raw": { + "from": "0xDfFb9e4cc2b869cF35ab811675333f40cD04dF76", + "to": "0x4612ad240cd66A77b921693BbbB356d1B8219b2c", + "nonce": 0, + "data": "0xc0ca77910ed59a0b2764cf395b53a7a7d1b58e2ae3fb99b818be5392f3fdbc7eb4f645d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000027800000000000000000000000000000000000000c10000000000000000000000000000000000000000000000008ac7230489e8000077b86bec000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001000000000000000000000000005d525df2bd99a6e7ec58b76af2fd95f39874ebed000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008ac7230489e8000000000000000000000000000000000000000000000000000000000000000001400000000000000000000000004612ad240cd66a77b921693bbbb356d1b8219b2c00000000000000000000000000000000000000000000000000000000000000207673075a980bfd5d6b1dffe99c31f63e8938519cc1c2af009dda5e568a94460d00000000000000000000000000000000000000000000000000000000000000bd000000044f12fe6816ae7e33ebf7db0b154ec3b09e3bf1a7690481e8e9477d5a278ad3af012953026d328218b107268efe60f7d98635af1ff535a91731f75ca7cf8a85904401dd7c1b885eb85dbac2db2a4ce5887489200c20d2549a6ed12d202cd12a7dfe81010000000000000000000000000000000000000000000000000000000000000000000000001079f4fa0308e5e1011027000000000000027673075a980bfd5d6b1dffe99c31f63e8938519cc1c2af009dda5e568a94460d0000000000000000000000", + "value": "0" + }, + "finalTxHash": "kGUaPUfASg9Poo93aMsztHJjUk27MKuRJBfDZK1WP3FFSaXSYcoPcxjUMFyDxaK6aU6mQkZeowSu3MtvK5PXKgK", + "externalTxHash": "kGUaPUfASg9Poo93aMsztHJjUk27MKuRJBfDZK1WP3FFSaXSYcoPcxjUMFyDxaK6aU6mQkZeowSu3MtvK5PXKgK", + "externalChain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "externalExplorerUrl": "https://explorer.solana.com/tx/kGUaPUfASg9Poo93aMsztHJjUk27MKuRJBfDZK1WP3FFSaXSYcoPcxjUMFyDxaK6aU6mQkZeowSu3MtvK5PXKgK?cluster=devnet", + "externalRecipient": "0x7673075a980bfd5d6b1dffe99c31f63e8938519cc1c2af009dda5e568a94460d", + "externalAmount": "10000", + "externalAssetAddr": "0x0000000000000000000000000000000000000000", + "externalStatus": "success" + } + }, + { + "kind": "pending-rejection", + "hash": "0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc", + "from": "0x4612ad240cd66A77b921693BbbB356d1B8219b2c", + "origin": "eip155:42101:0xDfFb9e4cc2b869cF35ab811675333f40cD04dF76", + "route": "UOA_TO_CEA", + "agentic": { + "wallet": "0x4612ad240cd66A77b921693BbbB356d1B8219b2c", + "door": "agent", + "rulesId": "0x0ed59a0b2764cf395b53a7a7d1b58e2ae3fb99b818be5392f3fdbc7eb4f645d0", + "chainNamespace": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "rawTo": "0x4612ad240cd66A77b921693BbbB356d1B8219b2c", + "rawData": "0xc0ca77910ed59a0b2764cf395b53a7a7d1b58e2ae3fb99b818be5392f3fdbc7eb4f645d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000023800000000000000000000000000000000000000c10000000000000000000000000000000000000000000000008ac7230489e8000077b86bec000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001000000000000000000000000005d525df2bd99a6e7ec58b76af2fd95f39874ebed000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008ac7230489e8000000000000000000000000000000000000000000000000000000000000000001400000000000000000000000004612ad240cd66a77b921693bbbb356d1b8219b2c00000000000000000000000000000000000000000000000000000000000000207673075a980bfd5d6b1dffe99c31f63e8938519cc1c2af009dda5e568a94460d000000000000000000000000000000000000000000000000000000000000007b000000024f12fe6816ae7e33ebf7db0b154ec3b09e3bf1a7690481e8e9477d5a278ad3af01dd7c1b885eb85dbac2db2a4ce5887489200c20d2549a6ed12d202cd12a7dfe8100000000106ae3a83bf81b96650100000000000000027673075a980bfd5d6b1dffe99c31f63e8938519cc1c2af009dda5e568a94460d00000000000000000000000000" + }, + "receipt": { + "hash": "0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc", + "blockNumber": "23949885", + "blockHash": "0xc465553f489498b344dd61a15da3ac67a7b98a294c72787ba4ab399e8adbfb4e", + "transactionIndex": 0, + "from": "0x4612ad240cd66A77b921693BbbB356d1B8219b2c", + "to": "0x00000000000000000000000000000000000000C1", + "contractAddress": null, + "gasPrice": "1125000000", + "gasUsed": "417241", + "cumulativeGasUsed": "417241", + "logs": [ + { + "address": "0x603e7f0af6e1aaff46ddfb28b1e99364f8bc59af", + "topics": [ + "0x3ac286ad36e454b1ae54d96d9de29fdde1f3984110b62d27d0c7bbc70ccfbf93", + "0xc83601cd9bbdf58b8e3e8ca5eda8bf224739c5f34b1b91e2c4c5d7a93cdb4fd5", + "0x000000000000000000000000165a5e6782f39d30b38c7d97e1303e4cb2ad102a", + "0x0000000000000000000000004612ad240cd66a77b921693bbbb356d1b8219b2c" + ], + "data": "0x0000000000000000000000005d525df2bd99a6e7ec58b76af2fd95f39874ebed0000000000000000000000000000000000000000000000000000000000002710", + "blockNumber": "23949885", + "transactionHash": "0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc", + "transactionIndex": 0, + "blockHash": "0xc465553f489498b344dd61a15da3ac67a7b98a294c72787ba4ab399e8adbfb4e", + "blockTimestamp": "0x6ac4a26c", + "logIndex": 0, + "removed": false + }, + { + "address": "0x5d525df2bd99a6e7ec58b76af2fd95f39874ebed", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000004612ad240cd66a77b921693bbbb356d1b8219b2c", + "0x00000000000000000000000000000000000000000000000000000000000000c1" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000002710", + "blockNumber": "23949885", + "transactionHash": "0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc", + "transactionIndex": 0, + "blockHash": "0xc465553f489498b344dd61a15da3ac67a7b98a294c72787ba4ab399e8adbfb4e", + "blockTimestamp": "0x6ac4a26c", + "logIndex": 1, + "removed": false + }, + { + "address": "0x5d525df2bd99a6e7ec58b76af2fd95f39874ebed", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x0000000000000000000000004612ad240cd66a77b921693bbbb356d1b8219b2c", + "0x00000000000000000000000000000000000000000000000000000000000000c1" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000000", + "blockNumber": "23949885", + "transactionHash": "0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc", + "transactionIndex": 0, + "blockHash": "0xc465553f489498b344dd61a15da3ac67a7b98a294c72787ba4ab399e8adbfb4e", + "blockTimestamp": "0x6ac4a26c", + "logIndex": 2, + "removed": false + }, + { + "address": "0x5d525df2bd99a6e7ec58b76af2fd95f39874ebed", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x00000000000000000000000000000000000000000000000000000000000000c1", + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000002710", + "blockNumber": "23949885", + "transactionHash": "0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc", + "transactionIndex": 0, + "blockHash": "0xc465553f489498b344dd61a15da3ac67a7b98a294c72787ba4ab399e8adbfb4e", + "blockTimestamp": "0x6ac4a26c", + "logIndex": 3, + "removed": false + }, + { + "address": "0xe17dd2e0509f99e9ee9469cf6634048ec5a3ade9", + "topics": [ + "0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c", + "0x00000000000000000000000000000000000000000000000000000000000000c0" + ], + "data": "0x0000000000000000000000000000000000000000000000008ac7230489e80000", + "blockNumber": "23949885", + "transactionHash": "0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc", + "transactionIndex": 0, + "blockHash": "0xc465553f489498b344dd61a15da3ac67a7b98a294c72787ba4ab399e8adbfb4e", + "blockTimestamp": "0x6ac4a26c", + "logIndex": 4, + "removed": false + }, + { + "address": "0xe17dd2e0509f99e9ee9469cf6634048ec5a3ade9", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x00000000000000000000000000000000000000000000000000000000000000c0", + "0x0000000000000000000000005d548bb9e305aae0d6dc6e6fdc3ab419f6ac0037" + ], + "data": "0x0000000000000000000000000000000000000000000000008ac7230489e80000", + "blockNumber": "23949885", + "transactionHash": "0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc", + "transactionIndex": 0, + "blockHash": "0xc465553f489498b344dd61a15da3ac67a7b98a294c72787ba4ab399e8adbfb4e", + "blockTimestamp": "0x6ac4a26c", + "logIndex": 5, + "removed": false + }, + { + "address": "0x5d525df2bd99a6e7ec58b76af2fd95f39874ebed", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000000e5914e3a7e2e6d18330dd33fa387ce33da48b54", + "0x00000000000000000000000000000000000000000000000000000000000000c0" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000ea600", + "blockNumber": "23949885", + "transactionHash": "0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc", + "transactionIndex": 0, + "blockHash": "0xc465553f489498b344dd61a15da3ac67a7b98a294c72787ba4ab399e8adbfb4e", + "blockTimestamp": "0x6ac4a26c", + "logIndex": 6, + "removed": false + }, + { + "address": "0xe17dd2e0509f99e9ee9469cf6634048ec5a3ade9", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x00000000000000000000000000000000000000000000000000000000000000c0", + "0x0000000000000000000000000e5914e3a7e2e6d18330dd33fa387ce33da48b54" + ], + "data": "0x0000000000000000000000000000000000000000000000000c112c58397d3a87", + "blockNumber": "23949885", + "transactionHash": "0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc", + "transactionIndex": 0, + "blockHash": "0xc465553f489498b344dd61a15da3ac67a7b98a294c72787ba4ab399e8adbfb4e", + "blockTimestamp": "0x6ac4a26c", + "logIndex": 7, + "removed": false + }, + { + "address": "0x0e5914e3a7e2e6d18330dd33fa387ce33da48b54", + "topics": [ + "0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67", + "0x0000000000000000000000005d548bb9e305aae0d6dc6e6fdc3ab419f6ac0037", + "0x00000000000000000000000000000000000000000000000000000000000000c0" + ], + "data": "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffff15a000000000000000000000000000000000000000000000000000c112c58397d3a8700000000000000000000000000000000000e84b1c10fb5fd51e951bcc48cb09f000000000000000000000000000000000000000000000002f15ecbc2e691bc650000000000000000000000000000000000000000000000000000000000043381", + "blockNumber": "23949885", + "transactionHash": "0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc", + "transactionIndex": 0, + "blockHash": "0xc465553f489498b344dd61a15da3ac67a7b98a294c72787ba4ab399e8adbfb4e", + "blockTimestamp": "0x6ac4a26c", + "logIndex": 8, + "removed": false + }, + { + "address": "0xe17dd2e0509f99e9ee9469cf6634048ec5a3ade9", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x00000000000000000000000000000000000000000000000000000000000000c0", + "0x0000000000000000000000005d548bb9e305aae0d6dc6e6fdc3ab419f6ac0037" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000000", + "blockNumber": "23949885", + "transactionHash": "0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc", + "transactionIndex": 0, + "blockHash": "0xc465553f489498b344dd61a15da3ac67a7b98a294c72787ba4ab399e8adbfb4e", + "blockTimestamp": "0x6ac4a26c", + "logIndex": 9, + "removed": false + }, + { + "address": "0x5d525df2bd99a6e7ec58b76af2fd95f39874ebed", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x00000000000000000000000000000000000000000000000000000000000000c0", + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000ea600", + "blockNumber": "23949885", + "transactionHash": "0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc", + "transactionIndex": 0, + "blockHash": "0xc465553f489498b344dd61a15da3ac67a7b98a294c72787ba4ab399e8adbfb4e", + "blockTimestamp": "0x6ac4a26c", + "logIndex": 10, + "removed": false + }, + { + "address": "0xe17dd2e0509f99e9ee9469cf6634048ec5a3ade9", + "topics": [ + "0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65", + "0x00000000000000000000000000000000000000000000000000000000000000c0" + ], + "data": "0x0000000000000000000000000000000000000000000000007eb5f6ac506ac579", + "blockNumber": "23949885", + "transactionHash": "0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc", + "transactionIndex": 0, + "blockHash": "0xc465553f489498b344dd61a15da3ac67a7b98a294c72787ba4ab399e8adbfb4e", + "blockTimestamp": "0x6ac4a26c", + "logIndex": 11, + "removed": false + }, + { + "address": "0x00000000000000000000000000000000000000c0", + "topics": [ + "0x01fd625a5ce1109c10761818e2ef64ea92cd4966d78086d37e5a4b50e3226878", + "0x0000000000000000000000005d525df2bd99a6e7ec58b76af2fd95f39874ebed", + "0x0000000000000000000000004612ad240cd66a77b921693bbbb356d1b8219b2c" + ], + "data": "0x0000000000000000000000000000000000000000000000000c112c58397d3a8700000000000000000000000000000000000000000000000000000000000ea60000000000000000000000000000000000000000000000000000000000000001f4", + "blockNumber": "23949885", + "transactionHash": "0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc", + "transactionIndex": 0, + "blockHash": "0xc465553f489498b344dd61a15da3ac67a7b98a294c72787ba4ab399e8adbfb4e", + "blockTimestamp": "0x6ac4a26c", + "logIndex": 12, + "removed": false + }, + { + "address": "0x00000000000000000000000000000000000000c1", + "topics": [ + "0x8882d1d8f7b1750e49d021ea8d62e07c2d163645b8fa31c035905d6572ffc637", + "0xd7e4da935abc97cbb68c0869dafa1e28038b89848c53650364250f60cd11e1ef", + "0x0000000000000000000000004612ad240cd66a77b921693bbbb356d1b8219b2c", + "0x0000000000000000000000005d525df2bd99a6e7ec58b76af2fd95f39874ebed" + ], + "data": "0x000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000027100000000000000000000000005d525df2bd99a6e7ec58b76af2fd95f39874ebed00000000000000000000000000000000000000000000000000000000000ea60000000000000000000000000000000000000000000000000000000000000003c0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004612ad240cd66a77b921693bbbb356d1b8219b2c000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000003e80000000000000000000000000000000000000000000000000000000000000027736f6c616e613a457457545241425a61597136694d6665594b6f755275313636565532787161310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000207673075a980bfd5d6b1dffe99c31f63e8938519cc1c2af009dda5e568a94460d000000000000000000000000000000000000000000000000000000000000007b000000024f12fe6816ae7e33ebf7db0b154ec3b09e3bf1a7690481e8e9477d5a278ad3af01dd7c1b885eb85dbac2db2a4ce5887489200c20d2549a6ed12d202cd12a7dfe8100000000106ae3a83bf81b96650100000000000000027673075a980bfd5d6b1dffe99c31f63e8938519cc1c2af009dda5e568a94460d0000000000", + "blockNumber": "23949885", + "transactionHash": "0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc", + "transactionIndex": 0, + "blockHash": "0xc465553f489498b344dd61a15da3ac67a7b98a294c72787ba4ab399e8adbfb4e", + "blockTimestamp": "0x6ac4a26c", + "logIndex": 13, + "removed": false + }, + { + "address": "0x4612ad240cd66a77b921693bbbb356d1b8219b2c", + "topics": [ + "0x3dbef004c3d4318a109f103c40928ef6cb77519329e4d7f473364dd15bf6b3fd", + "0x0ed59a0b2764cf395b53a7a7d1b58e2ae3fb99b818be5392f3fdbc7eb4f645d0", + "0x000000000000000000000000dffb9e4cc2b869cf35ab811675333f40cd04df76" + ], + "data": "0x356b0bac276dd8ee6f6f4f4e0ecbcc5ca8f3667706ef81daaa6b1d70a52701d3", + "blockNumber": "23949885", + "transactionHash": "0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc", + "transactionIndex": 0, + "blockHash": "0xc465553f489498b344dd61a15da3ac67a7b98a294c72787ba4ab399e8adbfb4e", + "blockTimestamp": "0x6ac4a26c", + "logIndex": 14, + "removed": false + } + ], + "logsBloom": "0x0020000110100000000000010000030100000000000000000000000000000000000000000000000000001e000000000000000000000022000400020040200008000000000200004808000008000000080000022004400004000800008020200400000000020002001000000004000802200000000000040200000090404800000000000000000004000000000000000000010001000000002000020000001000020010000000000200000080000000000000000000000040010000100000000004000002200020000000000000000090800000120000000000000002000020004010000012004000000000000000000000000000000001400000000040000000", + "status": 1, + "raw": { + "from": "0xDfFb9e4cc2b869cF35ab811675333f40cD04dF76", + "to": "0x4612ad240cd66A77b921693BbbB356d1B8219b2c", + "nonce": 1, + "data": "0xc0ca77910ed59a0b2764cf395b53a7a7d1b58e2ae3fb99b818be5392f3fdbc7eb4f645d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000023800000000000000000000000000000000000000c10000000000000000000000000000000000000000000000008ac7230489e8000077b86bec000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001000000000000000000000000005d525df2bd99a6e7ec58b76af2fd95f39874ebed000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008ac7230489e8000000000000000000000000000000000000000000000000000000000000000001400000000000000000000000004612ad240cd66a77b921693bbbb356d1b8219b2c00000000000000000000000000000000000000000000000000000000000000207673075a980bfd5d6b1dffe99c31f63e8938519cc1c2af009dda5e568a94460d000000000000000000000000000000000000000000000000000000000000007b000000024f12fe6816ae7e33ebf7db0b154ec3b09e3bf1a7690481e8e9477d5a278ad3af01dd7c1b885eb85dbac2db2a4ce5887489200c20d2549a6ed12d202cd12a7dfe8100000000106ae3a83bf81b96650100000000000000027673075a980bfd5d6b1dffe99c31f63e8938519cc1c2af009dda5e568a94460d00000000000000000000000000", + "value": "0" + }, + "finalTxHash": "0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc", + "externalStatus": "failed", + "externalError": "Outbound to solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1 reverted: tx not executed on destination chain. Push Chain TX: 0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc." + } + } + ] +} \ No newline at end of file diff --git a/plan/agw/research/live-svm-wire-2026-10-06/run-redacted.cjs b/plan/agw/research/live-svm-wire-2026-10-06/run-redacted.cjs new file mode 100644 index 00000000..0d51e039 --- /dev/null +++ b/plan/agw/research/live-svm-wire-2026-10-06/run-redacted.cjs @@ -0,0 +1,31 @@ +/** Bounded, opt-in test runner. Never prints/copies environment credentials. */ +const fs = require('node:fs'); +const path = require('node:path'); +const { spawn } = require('node:child_process'); +const dotenv = require('dotenv'); +const root = path.resolve(__dirname, '../../../..'); +const env = { ...process.env, ...dotenv.parse(fs.readFileSync(path.join(root, 'packages/core/.env'))) }; +const secrets = [...new Set(Object.entries(env) + .filter(([name, value]) => /KEY|SECRET|TOKEN|PASSWORD/.test(name) && value && value.length >= 6) + .flatMap(([, value]) => [value, ...(value.startsWith('0x') ? [value.slice(2)] : [])]))] + .sort((a, b) => b.length - a.length); +const redact = (text) => secrets.reduce((result, secret) => result.split(secret).join('[REDACTED]'), text); +const name = process.argv[2] ?? 'live.log'; +if (!/^[a-z0-9-]+\.log$/.test(name)) throw new Error('Use a simple log filename'); +const child = spawn(process.execPath, ['../../node_modules/ts-node/dist/bin.js', '--transpile-only', + '__e2e__/ci/run.ts', '--group', 'agw-svm-wire'], { + cwd: path.join(root, 'packages/core'), env, stdio: ['ignore', 'pipe', 'pipe'], +}); +let log = ''; +child.stdout.on('data', (data) => { log += data.toString(); }); +child.stderr.on('data', (data) => { log += data.toString(); }); +child.on('error', (error) => console.error(redact(error.message))); +child.on('exit', (code) => { + const clean = redact(log); + fs.mkdirSync(path.join(__dirname, 'logs'), { recursive: true }); + fs.writeFileSync(path.join(__dirname, 'logs', name), clean); + console.log(clean.slice(-12000)); + console.log(`Sanitized wire test log saved; exit=${code}`); + process.exitCode = code || 0; +}); +console.log('Starting bounded live wire suite; output is buffered and redacted.'); diff --git a/plan/agw/research/live-svm-wire-2026-10-06/terminal-accounting.json b/plan/agw/research/live-svm-wire-2026-10-06/terminal-accounting.json new file mode 100644 index 00000000..d5ca6b81 --- /dev/null +++ b/plan/agw/research/live-svm-wire-2026-10-06/terminal-accounting.json @@ -0,0 +1,10 @@ +{ + "at": "2026-10-06T07:56:43.396Z", + "block": "23950641", + "wallet": "0x4612ad240cd66A77b921693BbbB356d1B8219b2c", + "token": "0x5D525Df2bD99a6e7ec58b76aF2fd95F39874EBed", + "balance": "10000", + "allowance": "0", + "spent": "20000", + "transactionsSent": 0 +} \ No newline at end of file diff --git a/plan/agw/research/live-svm-wire-2026-10-06/validation.json b/plan/agw/research/live-svm-wire-2026-10-06/validation.json new file mode 100644 index 00000000..3e2f2a21 --- /dev/null +++ b/plan/agw/research/live-svm-wire-2026-10-06/validation.json @@ -0,0 +1,47 @@ +{ + "at": "2026-10-06T08:06:26.092329+00:00", + "unit": { + "passed": 1981, + "failed": 0, + "skipped": 12 + }, + "recorded_live_e2e": { + "passed": 3, + "failed": 0, + "transactions_sent": 0 + }, + "initial_funded_e2e": { + "passed": 2, + "failed": 1, + "failure": "externalStatus timeout at 600 seconds; same source outbound later became REVERTED and read-only replay classified failed" + }, + "funded_source_outbounds": 2, + "core_build": "pass", + "types": { + "library": "pass", + "spec": "pass" + }, + "lint": { + "errors": 0, + "warnings": 21 + }, + "groups": { + "all": { + "scenarios": 76, + "tests": 81 + }, + "agw": { + "scenarios": 25 + }, + "agw-svm-wire": { + "scenarios": 3 + }, + "agw-svm-replay": { + "scenarios": 3 + } + }, + "public_svm_enabled": false, + "production_library_files_changed": false, + "prior_local_contract_passes": 75, + "local_contract_suite_rerun": false +} From 12a067090dcbb8434ea65663a2aa27269f1220ff Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Tue, 6 Oct 2026 14:09:59 +0530 Subject: [PATCH 26/68] docs(agw): simplify team questions and proposed choices --- plan/agw/questions-harsh.md | 69 +++++++++++++----------------------- plan/agw/questions-zaryab.md | 42 ++++++++++------------ 2 files changed, 42 insertions(+), 69 deletions(-) diff --git a/plan/agw/questions-harsh.md b/plan/agw/questions-harsh.md index 4419e1b7..81dcf4b1 100644 --- a/plan/agw/questions-harsh.md +++ b/plan/agw/questions-harsh.md @@ -1,73 +1,52 @@ -# Remaining AGW product follow-ups for Harsh +# AGW SDK — questions for Harsh -Rechecked October 6, 2026 against all twelve saved Notion pages, your replies, live pages 1/5 and their All discussions, freshly fetched contract branches, the owner guide and SDK code. [Evidence and dispositions](research/question-source-recheck-2026-10-06/README.md). Accepted decisions remain in [product decisions](product-decisions-2026-10-04.md). No questions have been sent. - -| Item | Answer needed | -| --- | --- | -| [H3](#h3) | Native PC omission defaults and the intended token model | -| [H4.4](#h4-4) | Public Solana rule representation, jointly with Zaryab | -| [H4.5](#h4-5) | Public raw-offset authoring versus separate decoded records | -| [H6](#h6) | Choosing a rule for a send when several match | - -[Concrete API proposals](public-api-proposals.md) provide input/decoded-type and rule-selection examples for review. The internal [live Solana wire validation](research/live-svm-wire-2026-10-06/README.md) now proves positive delivery and replay; public SVM remains gated. - -## Source check - -The live [SDK page](https://app.notion.com/p/pushprotocol/5-SDK-AGW-3e9188aea7f481cf8e8de324956549b9) still has optional native maxValueTotal, argument-index inputs and the older unique-rule lookup wording. Its visible active/resolved discussions supply no further answer to the questions below. This was a live inspection, not a new Markdown export; the last full export remains October 3. - -The freshly fetched [owner guide](https://github.com/pushchain/push-agentic-wallets/blob/10a24f101e2e6e0a9b76517b29f5cdb1aa967796/docs/5_SDK_Owner_Integration.md) is unchanged. It supplies universal total encoding, same-agent multiplicity and SVM wire definitions. Those delivery questions are closed. Your later scope replies continue to take precedence over older page-body helper/spend/compiler entries. +Updated October 6, 2026. Please reply by question ID. These are the remaining product/API decisions. -## H3 Native PC defaults and token model +## H3. Native defaults and token model -The delivered contracts distinguish hard zero from uint256 maximum, keep maxValueTotal, use maxCalls=0 for unlimited calls and destination maxValue=0 for non-payable calls. We will apply the guide's universal no-total-limit encoding and preserve explicit zeros. +**1. Should omitted native PC limits mean unlimited?** -**Decision needed:** should omitted native maxValuePerCall and maxValueTotal both encode uint256 maximum? Your earlier reply was tentative for the former and referred to a change to the latter. The current live NativeRule still includes maxValueTotal, so we retain that field unless you specify a replacement. - -| Optional input | Proposed omission behavior | Current SDK | +| Field | Proposed default | Current SDK | | --- | --- | --- | -| Native maxValuePerCall | uint256 maximum | 0, provisional | -| Native maxValueTotal | uint256 maximum | 0, provisional | +| `maxValuePerCall` | `maxUint256` (unlimited) | `0`, provisional | +| `maxValueTotal` | `maxUint256` (unlimited) | `0`, provisional | -Explicit zero stays zero. We are not asking again what the on-chain sentinels mean. The other implemented conventions are native amount.maxTotal=uint256 maximum, maxCalls=0 and destination allowedCalls[].maxValue=0; these are context, not additional wire-format questions. +Explicit `0` would still forbid value movement. We retain `maxValueTotal`, which is still in the SDK spec. -Your [token-independence comment](https://app.notion.com/p/pushprotocol/5-SDK-AGW-3e9188aea7f481cf8e8de324956549b9#af9c3fac35d94f2585cb27310271c1d8) needs one scope clarification: the delivered guide keeps assets[] on the rule and allows each listed token with every allowed call. Is that the intended SDK model, or does your comment request a different public model? +**2. Does your “tokens independent” comment mean the current `assets[]` model should stay?** - +The delivered model has independent limits per token; each listed token can be used with every allowed call. If you intended a different SDK input model, please provide one example. -## H4.4 Public Solana rules — jointly with Zaryab + -Your earlier reply assigned SVM work to Zaryab. The SVM contract rulebook and its wire types are now delivered; our internal reads, metadata/IDL resolution, lifecycle and outbound backend are implemented. We are not asking for contract structs again. +## H4.4. Public Solana rules — with Zaryab -**Decision needed:** agree how those constraints appear in public Rule inputs and rules.get/list results. The current live AllowedCall is EVM-shaped: address target, function selector and beneficiary argument index. It does not represent Solana programs, instruction discriminators, account pins or instruction-data pins. +**Should public Solana rules use IDL-based authoring, or explicit raw constraints?** -**SDK proposal for review:** add a Solana-specific Rule variant selected by its solana: chainNamespace, keep asset caps/expiry/gas fields, and compile IDL instruction/account/field inputs into program/account/data constraints. Gateway, wallet CEA and protected token-account derivation stay internal. Confirm that model, or approve explicit constraints as a public authoring alternative. The decoded result must preserve stored constraints without inventing an IDL. [Types and examples](public-api-proposals.md#h44-solana-rule-inputs-and-decoded-records). +Our proposal is a Solana-specific `Rule` with instruction/account/field inputs compiled from an IDL. The SDK derives the gateway, wallet CEA and protected token accounts internally. Decoded records preserve the exact stored constraints. -This is a public SDK design agreement, not missing contract support. We have supplied our own verified gateway/program/account/payload fixture, successful live wire execution and later terminal-rejection replay, so no external fixture is needed to unblock this design review. Retry timing has an optional [operational follow-up](research/live-svm-wire-2026-10-06/platform-followup.md). +The alternative is to let callers author explicit program, account-pin and data-pin constraints. Please agree on the input/read model together. [Proposed types and examples](public-api-proposals.md#h44-solana-rule-inputs-and-decoded-records). -## H4.5 Decoded rules and raw offsets +## H4.5. Argument indexes versus raw offsets -This question was added during implementation review and was not covered by your earlier replies. The historical SDK document already used raw offsets; current page 5 instead uses argument indexes. Stored native rules contain byte offsets without the ABI needed to recover indexes. Returning a guessed arg index was incorrect for arrays/tuples. +**May callers use both ABI argument indexes and raw byte offsets, or should authoring and decoded records have separate types?** -The current fix returns native pins as `{ offset, expected }` and amount limits with `{ offset, maxPerCall, maxTotal }`. V4 EVM allowed-call reads also return exact beneficiaryOffset because stored selectors do not include the ABI needed to recover beneficiary argument indexes. It also accepts these raw forms when granting/updating so decoded rules can round-trip without loss. +This covers native pins/amount limits and EVM `beneficiaryOffset`. Contracts store offsets without an ABI, so reads cannot reliably recover argument indexes. -Please confirm whether this raw form should be public and accepted for new authoring, or whether decoded wire records should be separate from the ABI-based `{ arg, ... }` input. Accepting arbitrary raw offsets is a different public validation boundary from generating them from ABI information. We will keep internal accounting/codec needs separate from the reduced public spend/helper surface. - -**References:** [follow-up review](implementation-review/followup-9e16b23/review.md), [current public types](../../packages/core/src/lib/agentic/agentic.types.ts), [integrator obligations](contract-integrator-obligations.md). +**Recommendation:** keep the tested dual input form and exact raw-offset reads. If public authoring must be ABI-only, we will separate decoded records. [Options and examples](public-api-proposals.md#h45-nativeevm-raw-authoring-and-decoding). -## H6 Multiple rules and choosing a rule for a send - -Your new [create-example comment](https://app.notion.com/p/pushprotocol/5-SDK-AGW-3e9188aea7f481cf8e8de324956549b9#f9712c13f75c4398aef2dbf7628450b2) says multiple rules per chain are accepted. We already support different agents sharing a chain. The page body still says one per agent and chain; the v4 SDK now permits multiple during create/add/update. +## H6. Selecting among multiple rules -The new owner guide explicitly permits multiple rules for the **same agent and chain**, so the capacity question is answered. How should sendTransaction select rulesId: an explicit caller choice, or a defined automatic selection rule? Please include native arrays whose calls need different rules and cross-chain calls with overlapping permissions. +**Can we add explicit per-send rule selection, or do you want an automatic strategy?** -Lifecycle validation is already aligned with multiple rules. The SDK reports AMBIGUOUS_RULE with candidate IDs before signing; choosing the first rule would make grants, budgets and expiry determine execution accidentally. An explicit selector would add to the public API, so we will not introduce it without agreement. +**Proposal:** optional `rulesId` for one action/outbound; ordered `rulesIds` for a native batch using different rules. An EVM destination call array uses one rule for the entire outbound. -## Supporting context +Today, multiple matching rules produce `AMBIGUOUS_RULE` before signing. If you prefer automatic selection, please define how overlapping rules are chosen. [Proposed options and examples](public-api-proposals.md#h6-rule-selection-for-sends). -Native array implementation is validated locally and on Donut through sender-preserving UEA/7702 batching. Universal/SVM wire definitions and deployment are supplied; all 25 registered native/EVM live scenarios have passing coverage. Internal Solana delivery/replay and later terminal-rejection classification are verified; its initial ten-minute timeout is retained as evidence. Public SVM mapping/acceptance remains. [Zaryab's draft](questions-zaryab.md) asks only about metadata release scope and links this joint API review. compileCard and revoked history remain outside standalone AGW v1. +[SDK spec](https://app.notion.com/p/pushprotocol/5-SDK-AGW-3e9188aea7f481cf8e8de324956549b9) · [Questions for Zaryab](questions-zaryab.md) diff --git a/plan/agw/questions-zaryab.md b/plan/agw/questions-zaryab.md index 9a9ab7fb..c8679af5 100644 --- a/plan/agw/questions-zaryab.md +++ b/plan/agw/questions-zaryab.md @@ -1,37 +1,31 @@ -# AGW SDK remaining contract follow-ups for Zaryab +# AGW SDK — questions for Zaryab -Rechecked October 6, 2026 against all saved Notion sources, live pages 1/5 and their All discussions, freshly fetched contract branches, the owner guide and SDK code. [Evidence and dispositions](research/question-source-recheck-2026-10-06/README.md). Multi-asset terms, envelope, EVM CEA width, accounting ABI, SVM wire definitions and deployment are supplied; those questions are closed. No questions have been sent. +Updated October 6, 2026. Please confirm the release scope below and review the shared Solana API choice with Harsh. -Only Z1.3 needs a contract release-scope answer. We supplied and live-validated our own SVM fixture, so Z1.4 is removed. The public Solana SDK representation needs joint review under [Harsh H4.4](questions-harsh.md#h4-4); [concrete proposals](public-api-proposals.md) are ready. Deployment/address coordination is complete. - -| Item | Remaining answer | -| --- | --- | -| [Z1.3](#z1-3) | Ref/label scope for this release | - -## Source baseline + + -- [Owner integration guide](https://github.com/pushchain/push-agentic-wallets/blob/10a24f101e2e6e0a9b76517b29f5cdb1aa967796/docs/5_SDK_Owner_Integration.md). -- [V4 address book](https://github.com/pushchain/push-agentic-wallets/blob/10a24f101e2e6e0a9b76517b29f5cdb1aa967796/docs/addresses/donut.md). -- Reported deployed source e8db748; documentation head deploy-agw@10a24f1 has identical src. Donut probe block 23931055: factory/wallet/policy wiring matches, URP 3.1.0. [Evidence and remaining SDK work](research/deployment-review-2026-10-06/README.md). -- Fresh fetch confirms deploy-agw remains 10a24f1 and pushAgenticWallet_v3 remains e8db748; no src difference. No later branch supplies ref/setLabel. -- Target public API remains [page 5](notion/5-sdk-agw.md), qualified by Harsh's later replies/comments. Live pages 1/5 and All discussions were inspected again; no release-scope answer was visible. Notion was not re-exported in this pass. +## Z1.3. Rule references and editable labels - +**For each item, is it included in v1 or deferred?** -## Z1 Remaining surface and integration details +| Item | SDK target | Current contracts | +| --- | --- | --- | +| Rule `ref` | Optional job/card reference on a grant | `grantRules(Session)` and `RulesGranted` have no job reference | +| Editable label | Owner calls `w.setLabel(label)` | Label is emitted at deployment; `setLabel` is absent | - +If included, please confirm the existing [page-1 proposal](https://app.notion.com/p/pushprotocol/1-AGW-Contract-Changes-nomenclature-standard-change-set-3e9188aea7f4813aa31fc95ceb4e684d) remains the target and share the updated ABI when ready. Signed grants must bind the rule `ref`. -### Z1.3 Ref and editable labels: delivery or v1 scope change? +If deferred, please agree the v1 scope with Harsh so we can align the public SDK. -The generation still exposes grantRules(Session) without ref, and RulesGranted carries no job reference. Label is emitted by WalletDeployed only; setLabel is absent. Page 1 already proposes grantRules(Session, ref) and owner-only setLabel with LabelSet, without a checkpoint. We are not asking you to design that surface again. + -**Decision needed:** are rule ref and editable labels included in this release, or explicitly deferred from v1 with Harsh? If included, confirm that the existing page-1 proposal is still the target and announce the compatible source/ABI when ready. Signed grants must bind the ref as part of their authorized contents. We will keep absent capabilities explicit until the agreed scope and delivered ABI match. Checkpoint event ref is a rulesId/action hash; it is not the missing job ref. +## H4.4. Public Solana rules — with Harsh -## Product choices kept separate +**Should public Solana rules use IDL-based authoring, or explicit raw constraints?** -[Harsh's draft](questions-harsh.md) retains native PC defaults/token wording, raw-offset authoring, multi-rule send selection and the joint public-Solana representation decision. The new guide confirms same-agent/same-chain multiplicity; it does not choose a send selection API. No public spend, revoked-history or compileCard request is reopened. +Our proposal compiles instruction/account/field inputs from an IDL and keeps gateway/CEA/token-account derivation internal. Decoded records preserve exact stored constraints. -The [Solana wire evidence](research/live-svm-wire-2026-10-06/README.md) proves positive delivery/replay and later terminal-rejection classification. Its initial ten-minute timeout is retained; retry timing is an optional [operational follow-up](research/live-svm-wire-2026-10-06/platform-followup.md), separate from the contract scope question above. +Please review the [proposed types and examples](public-api-proposals.md#h44-solana-rule-inputs-and-decoded-records) with Harsh. This is the same [H4.4 question](questions-harsh.md#h4-4) in his document. -[Implementation plan](implementation-plan.md) · [External dependencies](external-blockers.md) · [Current baseline](current-baseline.md) +[Current contract guide](https://github.com/pushchain/push-agentic-wallets/blob/10a24f101e2e6e0a9b76517b29f5cdb1aa967796/docs/5_SDK_Owner_Integration.md) · [SDK spec](https://app.notion.com/p/pushprotocol/5-SDK-AGW-3e9188aea7f481cf8e8de324956549b9) From 1e570b6def3aadc9fc0067f4bf1fb0373d41abdd Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Tue, 6 Oct 2026 16:32:19 +0530 Subject: [PATCH 27/68] test(agw): expand funded management and policy coverage --- .../__e2e__/agw-extended/management.spec.ts | 283 ++++++++++++++++++ .../agw-extended/native-policy.spec.ts | 210 +++++++++++++ packages/core/__e2e__/ci/preflight.ts | 2 +- packages/core/__e2e__/ci/run.ts | 2 +- packages/core/__e2e__/ci/suite.ts | 28 ++ .../lib/agentic/__tests__/management.spec.ts | 24 +- .../core/src/lib/agentic/management/create.ts | 51 +++- plan/agw/README.md | 4 +- plan/agw/current-baseline.md | 4 +- plan/agw/gaps.md | 8 +- plan/agw/implementation-status.md | 10 +- .../extended-e2e-2026-10-06/README.md | 56 ++++ .../logs/build-final.log | 11 + .../logs/live-agw-extended-final.log | 11 + .../logs/live-agw-extended-index-race.log | 225 ++++++++++++++ .../logs/live-agw-extended.log | 37 +++ .../logs/management-unit.log | 29 ++ .../logs/unit-final.log | 169 +++++++++++ .../live-svm-wire-2026-10-06/run-redacted.cjs | 6 +- 19 files changed, 1152 insertions(+), 18 deletions(-) create mode 100644 packages/core/__e2e__/agw-extended/management.spec.ts create mode 100644 packages/core/__e2e__/agw-extended/native-policy.spec.ts create mode 100644 plan/agw/research/extended-e2e-2026-10-06/README.md create mode 100644 plan/agw/research/live-svm-wire-2026-10-06/logs/build-final.log create mode 100644 plan/agw/research/live-svm-wire-2026-10-06/logs/live-agw-extended-final.log create mode 100644 plan/agw/research/live-svm-wire-2026-10-06/logs/live-agw-extended-index-race.log create mode 100644 plan/agw/research/live-svm-wire-2026-10-06/logs/live-agw-extended.log create mode 100644 plan/agw/research/live-svm-wire-2026-10-06/logs/management-unit.log create mode 100644 plan/agw/research/live-svm-wire-2026-10-06/logs/unit-final.log diff --git a/packages/core/__e2e__/agw-extended/management.spec.ts b/packages/core/__e2e__/agw-extended/management.spec.ts new file mode 100644 index 00000000..70778529 --- /dev/null +++ b/packages/core/__e2e__/agw-extended/management.spec.ts @@ -0,0 +1,283 @@ +import { PushChain } from '../../src'; +import { getAddress, type Address } from 'viem'; +import type { AgenticRuntime } from '../../src/lib/agentic/runtime'; +import { v4 } from '../../src/lib/agentic/contracts/v4'; +import { setupAgw, inSeconds, type AgwFixture } from '../agw/_fixture'; +import { readNativeCounters } from '../shared/agw-state'; + +const d = process.env['AGW_EXTENDED_E2E'] === '1' ? describe : describe.skip; +const runtime = (client: PushChain) => + (client as unknown as { agenticRuntime: AgenticRuntime }).agenticRuntime; + +d('agw extended management', () => { + let f: AgwFixture; + beforeAll(async () => { + f = await setupAgw(); + }, 300_000); + afterAll(() => f?.teardown()); + const rule = (agent = f.agentAddress) => ({ + agent, + target: f.ownerAddress, + selector: 'value-only' as const, + validUntil: inSeconds(3600), + maxValuePerCall: BigInt(10), + maxValueTotal: BigInt(100), + maxCalls: 10, + }); + const count = (wallet: Address) => + f.push.readContract({ + address: wallet, + abi: v4.abis.wallet, + functionName: 'checkpointCount', + }); + it('1. prefunding a derived address survives deployment and info/list keep owner index and label', async () => { + const predicted = await f.owner.agentic.derive(); + expect(predicted.deployed).toBe(false); + await f.fundPC(predicted.address, BigInt(10)); + const made = await f.owner.agentic.create('e2e-prefunded-identity', { + rules: [], + }); + expect(made.wallet).toBe(predicted.address); + expect(made.index).toBe(predicted.index); + expect(await f.push.getBalance({ address: made.wallet })).toBe(BigInt(10)); + const w = f.owner.agentic.wallet(made.wallet); + expect(await w.info()).toMatchObject({ + owner: f.ownerAddress, + index: made.index, + label: 'e2e-prefunded-identity', + deployed: true, + rulesCount: 0, + }); + expect(await w.owner()).toEqual({ owner: f.ownerAddress }); + expect((await f.owner.agentic.list()).wallets).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + address: made.wallet, + index: made.index, + label: 'e2e-prefunded-identity', + }), + ]) + ); + expect(await f.owner.agentic.derive({ index: made.index })).toMatchObject({ + address: made.wallet, + deployed: true, + }); + f.evidence('extended-prefunding', { + wallet: made.wallet, + index: made.index, + txHash: made.tx.hash, + }); + }); + it('2. same-agent multiplicity is ambiguous before signing and selective revoke restores uncached lookup', async () => { + const made = await f.owner.agentic.create('e2e-ambiguous', { + rules: [rule(), rule()], + }); + await f.fundPC(made.wallet, BigInt(10)); + const agent = await f.agent(made.wallet), + nonce = await f.push.getTransactionCount({ address: f.agentAddress }); + await expect( + agent.universal.sendTransaction({ to: f.ownerAddress, value: BigInt(1) }) + ).rejects.toMatchObject({ + code: 'AMBIGUOUS_RULE', + details: { rulesIds: expect.arrayContaining(made.rulesIds) }, + }); + expect(await f.push.getTransactionCount({ address: f.agentAddress })).toBe( + nonce + ); + await ( + await f.owner.agentic.wallet(made.wallet).rules.revoke([made.rulesIds[0]]) + ).wait(); + const tx = await agent.universal.sendTransaction({ + to: f.ownerAddress, + value: BigInt(1), + }); + expect((await tx.wait()).status).toBe(1); + expect(tx.agentic?.rulesId).toBe(made.rulesIds[1]); + f.evidence('extended-uncached-lookup', { + wallet: made.wallet, + removed: made.rulesIds[0], + selected: made.rulesIds[1], + txHash: tx.hash, + }); + }); + it('3. multi-rule add and revoke are atomic batches with exact checkpoint counts', async () => { + const made = await f.owner.agentic.create('e2e-management-batches', { + rules: [], + }), + w = f.owner.agentic.wallet(made.wallet); + const added = await w.rules.add([ + rule(), + rule(getAddress('0x000000000000000000000000000000000000bEEF')), + ]); + expect(await count(made.wallet)).toBe(BigInt(4)); + expect(new Set(added.rulesIds).size).toBe(2); + expect((await w.rules.list()).rules.map((r) => r.rulesId)).toEqual( + expect.arrayContaining(added.rulesIds) + ); + await (await w.rules.revoke(added.rulesIds)).wait(); + expect(await count(made.wallet)).toBe(BigInt(8)); + expect((await w.rules.list()).rules).toEqual([]); + const cp = await w.checkpoints({ sinceBlock: added.tx.blockNumber }); + expect(cp.checkpoints).toHaveLength(8); + f.evidence('extended-management-batches', { + wallet: made.wallet, + rulesIds: added.rulesIds, + addHash: added.tx.hash, + checkpoints: 8, + }); + }); + it('4. invalid revoke targets preserve enabled rules and signer nonce', async () => { + const made = await f.owner.agentic.create('e2e-revoke-guards', { + rules: [rule()], + }), + w = f.owner.agentic.wallet(made.wallet), + nonce = await f.push.getTransactionCount({ address: f.ownerAddress }); + await expect(w.rules.revoke([])).rejects.toMatchObject({ + code: 'REVOKE_NEEDS_TARGET', + }); + await expect( + w.rules.revoke([made.rulesIds[0], made.rulesIds[0]]) + ).rejects.toMatchObject({ code: 'INVALID_RULE' }); + await expect( + w.rules.revoke([`0x${'12'.repeat(32)}`]) + ).rejects.toMatchObject({ code: 'RULE_NOT_FOUND' }); + expect(await f.push.getTransactionCount({ address: f.ownerAddress })).toBe( + nonce + ); + expect((await w.rules.list()).rules.map((r) => r.rulesId)).toEqual( + made.rulesIds + ); + }); + it('5. intervening agent spend refuses a stale replacement without changing grants or checkpoints', async () => { + const made = await f.owner.agentic.create('e2e-live-stale-update', { + rules: [rule()], + }); + await f.fundPC(made.wallet, BigInt(10)); + const agent = await f.agent(made.wallet), + rt = runtime(f.owner), + original = rt.execute; + let injected = false, + hash: string | undefined; + const before = await count(made.wallet), + grantNonce = await f.push.readContract({ + address: made.wallet, + abi: v4.abis.wallet, + functionName: 'grantNonce', + }); + rt.execute = async (params, opts) => { + if (!injected && params.to === made.wallet) { + injected = true; + const tx = await agent.universal.sendTransaction({ + to: f.ownerAddress, + value: BigInt(1), + }); + await tx.wait(); + hash = tx.hash; + } + return original(params, opts); + }; + try { + const error = await f.owner.agentic + .wallet(made.wallet) + .rules.update({ rules: [{ rulesId: made.rulesIds[0], rule: rule() }] }) + .then( + () => undefined, + (e: unknown) => e + ); + expect(error).toMatchObject({ + decodedError: { name: expect.stringContaining('SpentMismatch') }, + }); + expect(injected).toBe(true); + } finally { + rt.execute = original; + } + expect(await count(made.wallet)).toBe(before); + expect( + await f.push.readContract({ + address: made.wallet, + abi: v4.abis.wallet, + functionName: 'grantNonce', + }) + ).toBe(grantNonce); + expect( + (await f.owner.agentic.wallet(made.wallet).rules.list()).rules.map( + (r) => r.rulesId + ) + ).toEqual(made.rulesIds); + expect( + await readNativeCounters( + f.push, + f.manifest.addresses, + made.wallet, + made.rulesIds[0] + ) + ).toMatchObject({ valueSpent: BigInt(1), callsUsed: 1 }); + f.evidence('extended-stale-update', { + wallet: made.wallet, + rulesId: made.rulesIds[0], + spendHash: hash, + checkpoints: before, + grantNonce, + }); + }); + it('6. index race commits no grants to the competing wallet and retry takes the next slot', async () => { + const expectedNext = await f.owner.agentic.derive(); + const rt = runtime(f.owner), + original = rt.execute; + let competing: + | Awaited> + | undefined, + injected = false; + rt.execute = async (params, opts) => { + if (!injected && Array.isArray(params.data)) { + injected = true; + competing = await f.owner.agentic.create('e2e-race-winner', { + rules: [], + }); + } + return original(params, opts); + }; + let raceError: unknown; + try { + await f.owner.agentic.create('e2e-race-loser', { rules: [rule()] }); + } catch (error) { + raceError = error; + } + try { + const afterRace = await f.owner.agentic.derive(); + const competingRules = competing + ? (await f.owner.agentic.wallet(competing.wallet).rules.list()).rules + : undefined; + f.evidence('extended-index-race-error', { + code: (raceError as { code?: string } | undefined)?.code, + expectedWallet: expectedNext.address, + expectedIndex: expectedNext.index, + competingWallet: competing?.wallet, + competingIndex: competing?.index, + nextAfterRace: afterRace, + competingRuleIds: competingRules?.map((r) => r.rulesId), + }); + expect(raceError).toMatchObject({ + code: 'INDEX_RACE', + details: { committed: false }, + }); + } finally { + rt.execute = original; + } + if (!competing) throw new Error('Race injection did not run'); + expect( + (await f.owner.agentic.wallet(competing.wallet).rules.list()).rules + ).toEqual([]); + const retried = await f.owner.agentic.create('e2e-race-retry', { + rules: [rule()], + }); + expect(retried.index).toBe(competing.index + 1); + expect(retried.wallet).not.toBe(competing.wallet); + f.evidence('extended-index-race', { + competing: competing.wallet, + winnerHash: competing.tx.hash, + retried: retried.wallet, + retryHash: retried.tx.hash, + }); + }); +}); diff --git a/packages/core/__e2e__/agw-extended/native-policy.spec.ts b/packages/core/__e2e__/agw-extended/native-policy.spec.ts new file mode 100644 index 00000000..40917e56 --- /dev/null +++ b/packages/core/__e2e__/agw-extended/native-policy.spec.ts @@ -0,0 +1,210 @@ +/** Explicit limits only: these cases do not choose pending omission defaults or raw-input policy. */ +import { PushChain, AgenticRevertError } from '../../src'; +import { encodeFunctionData, erc20Abi, type Address } from 'viem'; +import { getNativePRC20ForChain } from '../../src/lib/orchestrator/internals/helpers'; +import { readNativeCounters } from '../shared/agw-state'; +import { CHAIN } from '../../src/lib/constants/enums'; +import { setupAgw, inSeconds, type AgwFixture } from '../agw/_fixture'; + +const d = process.env['AGW_EXTENDED_E2E'] === '1' ? describe : describe.skip; +const chain = PushChain.CONSTANTS.CHAIN.PUSH_TESTNET_DONUT; + +d('agw extended native policy', () => { + let f: AgwFixture, token: Address; + beforeAll(async () => { + f = await setupAgw(); + token = getNativePRC20ForChain(CHAIN.ETHEREUM_SEPOLIA, f.manifest.network); + }, 300_000); + afterAll(() => f?.teardown()); + const transfer = (to: Address, amount: bigint) => + encodeFunctionData({ + abi: erc20Abi, + functionName: 'transfer', + args: [to, amount], + }); + async function fixture( + balance = BigInt(50), + maxCalls = 2, + total = BigInt(15) + ) { + const rule = { + agent: f.agentAddress, + target: token, + selector: 'transfer(address,uint256)' as const, + validUntil: inSeconds(3600), + maxValuePerCall: BigInt(0), + maxValueTotal: BigInt(0), + maxCalls, + pins: [{ arg: 0, expected: f.ownerAddress }], + amount: { arg: 1, maxPerCall: BigInt(10), maxTotal: total }, + }; + const made = await f.owner.agentic.create('e2e-native-meter', { + rules: [rule], + }); + if (balance) + await ( + await f.owner.universal.sendTransaction({ + to: token, + data: transfer(made.wallet, balance), + }) + ).wait(); + const agent = await f.agent(made.wallet); + const counters = () => + readNativeCounters( + f.push, + f.manifest.addresses, + made.wallet, + made.rulesIds[0] + ); + const tokenBalance = () => + f.push.readContract({ + address: token, + abi: erc20Abi, + functionName: 'balanceOf', + args: [made.wallet], + }); + const send = (amount: bigint, to = f.ownerAddress, value = BigInt(0)) => + agent.universal.sendTransaction({ + to: { address: token, chain }, + value, + data: transfer(to, amount), + }); + return { ...made, agent, counters, tokenBalance, send }; + } + async function refused( + s: Awaited>, + action: () => Promise, + gate?: string + ) { + const before = await s.counters(), + balance = await s.tokenBalance(); + const error = await action().then( + () => undefined, + (e: unknown) => e + ); + expect(error).toBeInstanceOf(AgenticRevertError); + if (gate) + expect((error as AgenticRevertError).decodedError?.name).toBe( + `PolicyCheckReverted(${gate})` + ); + expect(await s.counters()).toEqual(before); + expect(await s.tokenBalance()).toBe(balance); + f.evidence('extended-native-refusal', { + wallet: s.wallet, + rulesId: s.rulesIds[0], + gate: gate ?? 'callee/engine', + counters: before, + tokenBalance: balance, + }); + } + it('1. pinned recipient and metered amount decode losslessly and transfer through explicit Push chain', async () => { + const s = await fixture(); + const record = await f.owner.agentic + .wallet(s.wallet) + .rules.get(s.rulesIds[0]); + expect(record.rule).toMatchObject({ + pins: [ + { + offset: 4, + expected: `0x${f.ownerAddress + .slice(2) + .toLowerCase() + .padStart(64, '0')}`, + }, + ], + amount: { offset: 36, maxPerCall: BigInt(10), maxTotal: BigInt(15) }, + }); + const before = await f.push.readContract({ + address: token, + abi: erc20Abi, + functionName: 'balanceOf', + args: [f.ownerAddress], + }); + const tx = await s.send(BigInt(10)); + expect((await tx.wait()).status).toBe(1); + expect(await s.tokenBalance()).toBe(BigInt(40)); + expect(await s.counters()).toMatchObject({ + valueSpent: BigInt(0), + amountSpent: BigInt(10), + callsUsed: 1, + }); + expect( + await f.push.readContract({ + address: token, + abi: erc20Abi, + functionName: 'balanceOf', + args: [f.ownerAddress], + }) + ).toBe(before + BigInt(10)); + const replay = await f.owner.universal.trackTransaction(tx.hash); + expect(replay.from).toBe(s.wallet); + expect(replay.agentic?.rulesId).toBe(s.rulesIds[0]); + f.evidence('extended-native-meter', { + wallet: s.wallet, + rulesId: s.rulesIds[0], + txHash: tx.hash, + }); + }); + it('2. wrong recipient pin is refused with unchanged token balance and counters', async () => { + const s = await fixture(); + await refused(s, () => s.send(BigInt(1), f.agentAddress), 'ArgPinMismatch'); + }); + it('3. per-call amount cap refuses cap plus one', async () => { + const s = await fixture(); + await refused(s, () => s.send(BigInt(11)), 'NativeAmountExceedsCap'); + }); + it('4. cumulative amount accepts the exact total and refuses the next unit', async () => { + const s = await fixture(BigInt(50), 10); + await (await s.send(BigInt(10))).wait(); + await (await s.send(BigInt(5))).wait(); + expect((await s.counters()).amountSpent).toBe(BigInt(15)); + await refused(s, () => s.send(BigInt(1)), 'TotalNativeAmountExceeded'); + }); + it('5. call count accepts the exact count and refuses a zero-amount extra call', async () => { + const s = await fixture(); + await (await s.send(BigInt(1))).wait(); + await (await s.send(BigInt(1))).wait(); + expect((await s.counters()).callsUsed).toBe(2); + await refused(s, () => s.send(BigInt(0)), 'CallLimitReached'); + }); + it('6. explicit zero total forbids positive amount but permits a metered zero call', async () => { + const s = await fixture(BigInt(50), 10, BigInt(0)); + await refused(s, () => s.send(BigInt(1)), 'TotalNativeAmountExceeded'); + await (await s.send(BigInt(0))).wait(); + expect(await s.counters()).toMatchObject({ + amountSpent: BigInt(0), + callsUsed: 1, + }); + }); + it('7. failed token callee leaves all policy counters unchanged', async () => { + const s = await fixture(BigInt(5)); + await refused(s, () => s.send(BigInt(10))); + }); + it('8. an ungranted selector is refused without changing balances or allowance', async () => { + const s = await fixture(); + const before = await f.push.readContract({ + address: token, + abi: erc20Abi, + functionName: 'allowance', + args: [s.wallet, f.agentAddress], + }); + await refused(s, () => + s.agent.universal.sendTransaction({ + to: token, + data: encodeFunctionData({ + abi: erc20Abi, + functionName: 'approve', + args: [f.agentAddress, BigInt(1)], + }), + }) + ); + expect( + await f.push.readContract({ + address: token, + abi: erc20Abi, + functionName: 'allowance', + args: [s.wallet, f.agentAddress], + }) + ).toBe(before); + }); +}); diff --git a/packages/core/__e2e__/ci/preflight.ts b/packages/core/__e2e__/ci/preflight.ts index b3a46c64..2a3c1f29 100644 --- a/packages/core/__e2e__/ci/preflight.ts +++ b/packages/core/__e2e__/ci/preflight.ts @@ -336,7 +336,7 @@ function renderTable(rows: Row[]): void { // The agw group needs a verified compatible AGW deployment (plan/agw A07). // Check it read-only BEFORE any balance work so nothing is ever funded for // a run that cannot exercise a real deployment. - if (scenarios.some((s) => s.group === 'agw' || s.group === 'agw-svm-wire')) { + if (scenarios.some((s) => s.group.startsWith('agw'))) { try { await verifyAgwManifest(push, loadAgwManifest()); console.log('AGW deployment manifest verified on-chain.'); diff --git a/packages/core/__e2e__/ci/run.ts b/packages/core/__e2e__/ci/run.ts index 06b48485..a2939f94 100644 --- a/packages/core/__e2e__/ci/run.ts +++ b/packages/core/__e2e__/ci/run.ts @@ -7,7 +7,7 @@ * * --group One of: all (default), smoke, evm-r1, evm-r2, evm-r3, * svm-r1, svm-r2r3, pc20, push, cross-chain, read, - * known-fail, agw, agw-svm-wire, agw-svm-replay + * known-fail, agw, agw-extended, agw-svm-wire, agw-svm-replay * (`all` excludes known-fail and AGW groups — ask by name; * agw uses the checked Donut v4 manifest by default, see __e2e__/agw/_manifest.ts) * --list Print the selection and the jest argv, run nothing diff --git a/packages/core/__e2e__/ci/suite.ts b/packages/core/__e2e__/ci/suite.ts index 9f39c796..5ad1feec 100644 --- a/packages/core/__e2e__/ci/suite.ts +++ b/packages/core/__e2e__/ci/suite.ts @@ -35,6 +35,7 @@ export const GROUPS = [ 'read', 'known-fail', 'agw', + 'agw-extended', 'agw-svm-wire', 'agw-svm-replay', ] as const; @@ -160,6 +161,8 @@ const F = { agwUniversal: '__e2e__/agw/universal-evm.spec.ts', agwIdentity: '__e2e__/agw/identity-gas.spec.ts', agwResponses: '__e2e__/agw/responses-hooks.spec.ts', + agwExtendedManagement: '__e2e__/agw-extended/management.spec.ts', + agwExtendedNative: '__e2e__/agw-extended/native-policy.spec.ts', } as const; export const SCENARIOS: Scenario[] = [ @@ -1037,6 +1040,31 @@ export const SCENARIOS: Scenario[] = [ needs: { masterPC: '0.5' }, env: { AGW_E2E: '1' }, }, + + // Extended AGW tests are opt-in and use bounded per-scenario testnet budgets. + ...[ + ['prefunding', '1\\. prefunding', '11'], + ['ambiguous-rules', '2\\. same-agent multiplicity', '11'], + ['batched-lifecycle', '3\\. multi-rule add', '0.5'], + ['invalid-revoke', '4\\. invalid revoke', '0.5'], + ['stale-update', '5\\. intervening agent spend', '11'], + ['index-race', '6\\. index race', '1'], + ].map(([slug, grep, pc]) => ({ + id: `agw-extended-${slug}`, + group: 'agw-extended' as const, + file: F.agwExtendedManagement, + grep: `agw extended management ${grep}`, + needs: { masterPC: pc }, + env: { AGW_EXTENDED_E2E: '1' }, + })), + ...Array.from({ length: 8 }, (_, i) => ({ + id: `agw-extended-native-policy-${i + 1}`, + group: 'agw-extended' as const, + file: F.agwExtendedNative, + grep: `agw extended native policy ${i + 1}\\.`, + needs: { masterPC: '0.25', masterPETH: '0.000000000001' }, + env: { AGW_EXTENDED_E2E: '1' }, + })), ]; /** diff --git a/packages/core/src/lib/agentic/__tests__/management.spec.ts b/packages/core/src/lib/agentic/__tests__/management.spec.ts index 321ecff1..9a2d672b 100644 --- a/packages/core/src/lib/agentic/__tests__/management.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/management.spec.ts @@ -9,7 +9,6 @@ import { PUSH_NETWORK } from '../../constants/enums'; import { PushChainBatchExecutionError } from '../../orchestrator/internals/errors'; import type { MultiCall } from '../../orchestrator/orchestrator.types'; import { PROGRESS_HOOK } from '../../progress-hook/progress-hook.types'; -import { AgenticCapability } from '../capabilities'; import { currentGeneration, resetAgenticGenerations } from '../deployments'; import { AGW_ABI, @@ -357,6 +356,29 @@ describe('agentic.create', () => { expect(err.details).toMatchObject({ committed: false }); }); + it('a generic send error is still identified as a race when the fresh slot label proves another create won', async () => { + const fake = new FakeChain(); + const rt = mockRuntime(fake, { + signer: ADDR.owner, + execute: (async () => { + fake.addWallet(ADDR.owner, 'competing-create'); + throw new Error('opaque sender failure'); + }) as never, + }); + const err = await createWallet(rt, 'this-create', { + rules: [rule()], + }).catch((e) => e); + expect(err).toMatchObject({ + code: AGENTIC_ERROR_CODE.INDEX_RACE, + details: { + wallet: nextWallet, + index: 0, + committed: false, + competingLabel: 'competing-create', + }, + }); + }); + it('a slot that is already deployed is refused before signing', async () => { const fake = new FakeChain(); fake.predictOverride = (owner, index) => diff --git a/packages/core/src/lib/agentic/management/create.ts b/packages/core/src/lib/agentic/management/create.ts index 6ab32770..d76009b0 100644 --- a/packages/core/src/lib/agentic/management/create.ts +++ b/packages/core/src/lib/agentic/management/create.ts @@ -10,7 +10,7 @@ import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; import type { AgenticRuntime } from '../runtime'; import type { CreateOptions, CreateResult } from '../agentic.types'; import { Snapshot } from '../reads/snapshot'; -import { walletCount } from '../reads/wallets'; +import { walletCount, walletInfo } from '../reads/wallets'; import { assertCanSign, confirmedLogs, @@ -142,6 +142,8 @@ export async function createWallet( gen, wallet, Number(index), + owner, + label, err ); emitFailure(runtime, hook, wrapped); @@ -157,6 +159,8 @@ export async function createWallet( gen, wallet, Number(index), + owner, + label, err ); emitFailure(runtime, hook, wrapped); @@ -239,6 +243,8 @@ async function createFailure( gen: ReturnType, wallet: Address, index: number, + owner: Address, + label: string, err: unknown ): Promise { const wrapped = wrapSendError(err); @@ -270,6 +276,49 @@ async function createFailure( ); } if (confirmed.length === 0 && !pending && !receiptUnavailable) { + // Some send paths flatten the factory revert to a generic execution + // error, losing the IndexMismatch selector. If the owner's next index has + // moved and immutable deployment metadata proves another label owns the + // predicted slot, this call could not have deployed or granted. + try { + const next = await walletCount( + await Snapshot.at(runtime.reader), + gen, + owner + ); + if (next > BigInt(index)) { + const competing = await walletInfo(runtime.reader, gen, wallet); + if ( + competing.deployed && + competing.index === index && + getAddress(competing.owner) === owner && + competing.label !== label + ) { + return new AgenticError( + AGENTIC_ERROR_CODE.INDEX_RACE, + 'wallet slot ' + index + ' was consumed by a concurrent deployment', + { + hint: + 'Slot ' + + index + + ' belongs to "' + + competing.label + + '". No wallet or rules from this create call were committed; retry agentic.create to use the next slot.', + details: { + wallet, + index, + committed: false, + competingLabel: competing.label, + }, + cause: wrapped, + } + ); + } + } + } catch { + // If the owner counter/event cannot be reconciled, preserve the original + // error; never infer that a retry is safe from an incomplete read. + } // Nothing was confirmed (pre-broadcast failure or a reverted atomic batch). return wrapped; } diff --git a/plan/agw/README.md b/plan/agw/README.md index fb847bdc..33f5fd8f 100644 --- a/plan/agw/README.md +++ b/plan/agw/README.md @@ -2,7 +2,9 @@ This package contains the SDK implementation plan, source snapshots, open decisions and validation evidence. Current work is on feat/agw-sdk-v4. Runtime commits are a66ff7d (v4/SVM foundations) and b68bab7 (gas headroom); current validation is linked below. Native/EVM support now uses the checked Donut v4 deployment; old runtime adapters/ABIs/fixtures were removed. All 25 registered AGW scenarios have passing bounded live coverage, including native/UEA identities and Sepolia outbound success/failure. -Latest: [live acceptance and fixes](research/live-acceptance-2026-10-06/README.md), following the [v4 migration](research/v4-implementation-2026-10-06/README.md). The unrestricted full core unit run passes 1,981 tests; the actual-contract harness passes 75. Build and four typechecks pass. Native defaults/raw-offset API/multi-rule selection decisions, absent ref/labels, public SVM integration and release scope remain explicit. +Latest E2E expansion: [extended AGW live coverage](research/extended-e2e-2026-10-06/README.md) adds 14 opt-in funded scenarios. All 14 pass; the wallet-index race caught and fixed an SDK error-classification gap. The default E2E selection remains unchanged. + +Latest: [live acceptance and fixes](research/live-acceptance-2026-10-06/README.md), following the [v4 migration](research/v4-implementation-2026-10-06/README.md). The unrestricted full core unit run passes 1,982 tests; the actual-contract harness passes 75. Build and four typechecks pass. Native defaults/raw-offset API/multi-rule selection decisions, absent ref/labels, public SVM integration and release scope remain explicit. The public target remains [Notion page 5](notion/5-sdk-agw.md), qualified by [Harsh's replies](product-decisions-2026-10-04.md) and [live comments](research/notion-comments-2026-10-05.md). The [v4 deployment/owner-guide review](research/deployment-review-2026-10-06/README.md) records the supplied deployed wire definitions. Historical adapter-absence statements in that review describe the pre-migration inspection, not current implementation. diff --git a/plan/agw/current-baseline.md b/plan/agw/current-baseline.md index 694f346e..bb28e7ab 100644 --- a/plan/agw/current-baseline.md +++ b/plan/agw/current-baseline.md @@ -1,6 +1,6 @@ # Current validated AGW baseline -Updated October 6, 2026 after the v4 deployment notice, source/ABI inspection and read-only Donut probe. **The v4 deployment and native/EVM SDK adapter/codecs are now integrated locally. All 25 registered AGW live scenarios have passing selected-run coverage.** [Full review and evidence](research/deployment-review-2026-10-06/README.md). +Updated October 6, 2026 after the v4 deployment notice, source/ABI inspection, read-only Donut probe and extended E2E run. **The v4 deployment and native/EVM SDK adapter/codecs are integrated locally. The 25 standard AGW scenarios and 14 new opt-in extended scenarios have passing live coverage.** [Extended E2E evidence](research/extended-e2e-2026-10-06/README.md); [full deployment review](research/deployment-review-2026-10-06/README.md). The public SDK target remains Notion page 5, qualified by Harsh's later replies/comments. The new owner guide establishes deployed wire behavior; mismatches in public ref/labels/defaults/selection remain explicit. [Prior October 3–5 baseline](research/deployment-review-2026-10-06/previous-current-baseline.md) is retained as historical evidence. @@ -61,7 +61,7 @@ The ABI comparison found matching factory/wallet/engine function/event/error sig Four checks passed: version-1 envelope round-trip/old first-word incompatibility; synthetic ordered two-asset tuple round-trip; live v4 getConfig decode with old-ABI rejection; array assertion encoding. [Results and limits](research/deployment-review-2026-10-06/wire-checks.json). This is not a rule-grant, stale-spend transaction or funded E2E proof. -The unrestricted run passes 1,981 unit and 75 actual-contract tests. All five explorer ABI sets match the isolated build. Donut is registered and all 25 registered native/EVM/identity cases have passing coverage. [Current acceptance evidence](research/live-acceptance-2026-10-06/README.md). +The unrestricted run passes 1,982 unit and 75 actual-contract tests. All five explorer ABI sets match the isolated build. Donut is registered and all 25 standard AGW native/EVM/identity cases plus 14 extended management/native-policy cases have passing live coverage. The extended suite remains opt-in; default `all` remains 76 scenarios. [Extended E2E evidence](research/extended-e2e-2026-10-06/README.md); [prior acceptance evidence](research/live-acceptance-2026-10-06/README.md). ## Remaining decisions and acceptance diff --git a/plan/agw/gaps.md b/plan/agw/gaps.md index 3efe33b3..dfadb447 100644 --- a/plan/agw/gaps.md +++ b/plan/agw/gaps.md @@ -2,7 +2,7 @@ Updated October 6, 2026 after the [v4 deployment/owner-guide review](research/deployment-review-2026-10-06/README.md), [Harsh’s replies](product-decisions-2026-10-04.md), v4 implementation on feat/agw-sdk-v4, and [live Notion comments](research/notion-comments-2026-10-05.md). This register distinguishes unresolved dependencies, implemented SDK work, deferred scope and historical corrections. G01–G26 are tracking IDs, not a count of open defects. -Evidence: [current baseline](current-baseline.md), [implementation status](implementation-status.md), [product alignment validation](research/product-alignment-2026-10-04/README.md). The unrestricted v4 SDK run passes 1,981 unit tests and 75 local-contract tests. All 25 registered live scenarios have passing coverage. The independent SDK follow-up adds delayed-index actual-contract checks and consumer documentation; public SVM destinations remain gated. +Evidence: [current baseline](current-baseline.md), [implementation status](implementation-status.md), [product alignment validation](research/product-alignment-2026-10-04/README.md), and [extended live E2Es](research/extended-e2e-2026-10-06/README.md). The unrestricted v4 SDK run passes 1,982 unit tests and 75 local-contract tests. The 25 standard AGW plus 14 extended live scenarios pass; default E2E selection remains unchanged. Public SVM destinations remain gated. Current contract baseline: reported deployed source `e8db748`, documentation head `deploy-agw@10a24f1` (src unchanged between them). Donut v4 addresses/code/wiring and URP 3.1.0 were checked at block 23931055; verified ABIs were saved. The SDK now uses v4 only, registers Donut and has a ported actual-contract harness. [Implementation evidence](research/v4-implementation-2026-10-06/README.md). Core marketplace cb69e0b and gateway bcbf7df remain prior source pins; they were not freshly fetched. Notion bodies were not refreshed in this pass. @@ -28,7 +28,7 @@ P0 blocks agreed authorization/accounting or safe final integration. P1 affects | ID | Priority | Status | Current finding or resolution | Remaining action | | --- | --- | --- | --- | --- | -| G01 | P1 | V4 registered; live coverage passes | Checked new deployment and reproduced ABIs are integrated in the Donut-only registry; no legacy adapter fallback. | All 25 registered AGW scenarios have passing live coverage. Refresh wiring/source for future releases. | +| G01 | P1 | V4 registered; live coverage passes | Checked new deployment and reproduced ABIs are integrated in the Donut-only registry; no legacy adapter fallback. | All 25 standard and 14 extended AGW scenarios have passing live coverage. Refresh wiring/source for future releases. | | G02 | P0 | Source deployed; native/UEA acceptance passes | D3 executeAsAgent/agentOf and sender adapter exist in v4; documented wiring matches live reads. SmartSession is unchanged. | Sender-binding/alternate-path tests and live native/UEA/7702 acceptance pass; do not reopen the engine-fork proposal. | | G03 | P1 | SDK question resolved and implemented | Validator/nonce ID calculation and generation-specific derivation are internal. Public generation-context helpers were removed per Harsh H4.1. IDs remain wallet-scoped and receipt-confirmed. | V4 vectors and receipt-confirmed IDs are verified; no public context-signature approval is needed. | | G04 | P1 | ABI history corrected; release note | Six-field main is older; inspected current gateway and historical Donut dispatcher use eight fields. A hypothetical future field removal is not a present SDK blocker. | Encode the selected manifest’s gateway ABI and track any actual migration with that deployment. | @@ -40,7 +40,7 @@ P0 blocks agreed authorization/accounting or safe final integration. P1 affects | G10 | P1 | Downstream marketplace scope | Current marketplace binds one EVM chain and one rulesId; broader card binding remains unresolved downstream. | Align future marketplace/job cardinality. Standalone AGW does not invent multi-rule job bindings. | | G11 | P1 | Downstream job dependency | Payment-token selection differs between the target job SDK and the one-token-per-deployment kernel. | Align selected K-12/deployment design in the job track. | | G12 | P1 | Downstream evaluator/hook delivery | Current start/fund guards exist; evaluator baseline/submit integration is incomplete. | Verify lifecycle placement and bypasses in the separate marketplace/job/evaluator work. | -| G13 | P1 | SDK implemented locally; spec wording stale | Core supports native 7702 batching with a sequential fallback. Creation uses actual capability, index-bound deployment and receipt/recovery metadata. | Correct the stale factory-batch requirement in source docs when maintained; Native creation and UEA identity acceptance pass on the verified deployment. | +| G13 | P1 | SDK implemented locally; race classification verified live | Core supports native 7702 batching with a sequential fallback. Creation uses actual capability, index-bound deployment and receipt/recovery metadata. The extended live race test verifies no rules reach the competing wallet, reports `INDEX_RACE`, and retries at the next slot. | Correct the stale factory-batch requirement in source docs when maintained; native creation and UEA identity acceptance pass on the verified deployment. | | G14 | P1 | V4 native/EVM update implemented locally | Ordered all-token assertions precede revoke/grant; actual second-token spend races roll back the entire update and checkpoints. Native per-action guards retained. | Native/EVM updates pass live. Public SVM wrapper remains. | | G15 | P2 | SDK implemented locally | create deploys/grants only; funding is separate. No required new createWallet factory method. Index binding prevents grants on a raced wallet; partial recovery preserves operation receipts and unknown state. | Final-generation events/native batching and UEA identities are verified; do not restore removed funding inputs. | | G16 | P1 | Implemented; migration documentation supplied | READ.CHAIN.WEB2 is web2. Legacy web2:https input is normalized to unchanged wire identity. Deprecated aliases now use the new public value. | The consumer guide documents the alias/literal migration; Web2 normalization/read-source tests pass. | @@ -57,7 +57,7 @@ P0 blocks agreed authorization/accounting or safe final integration. P1 affects ## Validation and release boundaries -The [current acceptance evidence](research/live-acceptance-2026-10-06/README.md) records 1,981 passing unit tests, 75 actual-contract tests, build/four typechecks and seven existing lint errors. All 25 opt-in AGW scenarios have passing bounded selected-run coverage; default all remains 76. Native/UEA/7702, lifecycle, allowance, responses and Sepolia success/failure pass. The initial positive-amount Push transaction exposed insufficient gas headroom. A tested 20% headroom fix passes the bounded retry, including token debit, allowance reduction, destination receipt/CEA balance and replay checks. Destination-revert classification also passes. +The [existing acceptance evidence](research/live-acceptance-2026-10-06/README.md) records the original native/EVM coverage. The [extended report](research/extended-e2e-2026-10-06/README.md) records 1,982 passing unit tests, build/typechecks, and 14/14 additional funded tests; default all remains 76. Extended cases cover management races/batching and native policy pins, caps and rollback. Public Solana destination coverage remains outstanding. Local batch proof uses actual AGW/factory/engine/policy and real Anvil EIP-7702 transactions, with a small fixture executor. UEA shaping/replay is unit-tested and reuses the existing transport; all registered native/EVM/UEA acceptance scenarios now pass. Public Solana destination coverage remains outstanding. diff --git a/plan/agw/implementation-status.md b/plan/agw/implementation-status.md index 798f0e03..25f6429f 100644 --- a/plan/agw/implementation-status.md +++ b/plan/agw/implementation-status.md @@ -1,6 +1,6 @@ # AGW SDK implementation status -> Latest: [funded acceptance and fixes](research/live-acceptance-2026-10-06/README.md). Full permissions are restored: 1,981 unfiltered unit tests, all 75 Anvil cases, build and four typechecks pass. All 25 registered AGW scenarios pass across selected live runs, including UEA identities, native 7702 batches, lifecycle and Sepolia success/failure. Public SVM destinations remain gated. +> Latest: [extended AGW live coverage](research/extended-e2e-2026-10-06/README.md). The unfiltered unit suite passes 1,982 tests; all 75 Anvil cases and the core build pass. All 25 standard AGW scenarios and 14 additional opt-in management/native-policy scenarios have passing live coverage. Public SVM destinations remain gated. Updated October 6, 2026. Branch feat/agw-sdk-v4; runtime commits a66ff7d and b68bab7. The native/EVM migration uses deployed source e8db748. Runtime/test e704d5b adapters, ABIs and fixtures were removed at Shoaib's request; historical review documents are evidence only. [Full handoff, commands and validation](research/v4-implementation-2026-10-06/README.md). @@ -8,14 +8,14 @@ Updated October 6, 2026. Branch feat/agw-sdk-v4; runtime commits a66ff7d and b68 | Level | Current evidence | | --- | --- | -| Unit | 1,981 passed, 0 failed; 12 skipped; 115 suites passed, 1 skipped | +| Unit | 1,982 passed, 0 failed; 12 skipped; 116 suites passed, 1 skipped | | Local actual contracts | 75 passed, 0 failed; 10 suites against e8db748 on Anvil | | ABI reproduction | All 5 explorer ABI entry sets match the isolated build, ignoring array order | | Runtime matrix | Node 20.19.2 and 24.14.0 pass full units, local contracts and package/API checks | | Build/typechecks | Build and lib/spec/local/AGW-E2E typechecks pass | | Lint | 7 pre-existing errors in unchanged files; no new errors | -| E2E selection | AGW: 25 scenarios/9 files/25 tests; default all unchanged at 76/40/81 | -| Funded live | All 25 registered scenarios have passing selected-run coverage; 0 outstanding native/EVM scenario failures | +| E2E selection | Standard AGW: 25 scenarios/9 files/25 tests; extended: 14 scenarios/2 files/14 tests; default all unchanged at 76/40/81 | +| Funded live | Standard 25 plus extended 14 scenarios have passing selected-run coverage; 0 outstanding native/EVM scenario failures | Local gateway/core/token/executor and CEA lookup are fixtures. Actual AGW/factory/engine/validator/URP enforce the rules; native type-4 tests use real transactions. This does not prove production gateway, Cosmos/TSS, UEA or destination execution. @@ -36,7 +36,7 @@ Local gateway/core/token/executor and CEA lookup are fixtures. Actual AGW/factor | 11 | EVM outbound | V4 asset membership, maxGasPerCall, wallet CEA/refunds, signer gas and responses | Release review; Sepolia success/failure and UEA cases verified | | 12 | SVM destinations | Internal live positive delivery and later terminal-rejection replay verified; public capability gated | Public mapping/display/dispatch agreement, adapters and public acceptance; rejection retry timing is documented separately | | 13 | Responses/progress/errors | V4 ABIs and prior canonical replay/wait fixes retained | Delayed-index replay/polling tested with real contracts/receipts; no remaining SDK-owned response gap | -| 14 | E2E | 25 opt-in scenarios registered; public universal setup and new two-token/call-only cases | Completed native/EVM live coverage; public SVM acceptance after integration | +| 14 | E2E | 25 standard and 14 extended opt-in scenarios registered; extended management/policy cases pass live | Completed native/EVM live coverage; public SVM acceptance after integration | | 15 | Web2 | Prior implementation retained and included in full unit run | Consumer migration notes supplied; existing Web2 unit acceptance passes | | 16 | compileCard | Outside standalone AGW; absent public export | Future marketplace scope | | 17 | Documentation/release | Current status/gaps/handoff updated | Product scope decisions and public SVM integration/release review | diff --git a/plan/agw/research/extended-e2e-2026-10-06/README.md b/plan/agw/research/extended-e2e-2026-10-06/README.md new file mode 100644 index 00000000..b0f62b5e --- /dev/null +++ b/plan/agw/research/extended-e2e-2026-10-06/README.md @@ -0,0 +1,56 @@ +# Extended AGW E2E coverage — October 6, 2026 + +Branch `feat/agw-sdk-v4`. This follow-up adds 14 opt-in Donut/Sepolia E2E scenarios in the `agw-extended` group. They exercise wallet identity and management races, atomic rule lifecycle behavior, and native policy enforcement against the deployed v4 contracts. The cases use bounded testnet funds and create fresh test wallets. + +## Coverage + +| File | Scenarios | Checks | +| ---------------------------------------------------------- | --------: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `packages/core/__e2e__/agw-extended/management.spec.ts` | 6 | Prefunding a derived wallet, label/index reads, same-agent multiplicity and ambiguous-send refusal, batched add/revoke checkpoint counts, invalid revoke guards, stale update rollback after an intervening agent spend, and owner wallet-index race recovery. | +| `packages/core/__e2e__/agw-extended/native-policy.spec.ts` | 8 | Lossless raw-offset decode and recipient delivery, pin mismatch, per-call and cumulative amount caps, exact call count, explicit zero total, failed-callee rollback, and ungranted selector refusal without allowance change. | + +Every refusal test checks that balances and policy counters remain unchanged. The update-race test also checks that grants, checkpoint count and grant nonce remain unchanged after rollback. + +## Race found and correction + +The first funded run passed 13 of 14 scenarios. The wallet-index race proved that the losing create did not grant rules to the competing wallet, and the retry used the next slot, but the SDK returned a generic execution error instead of its documented `INDEX_RACE` result. + +The create flow now classifies this narrow case from fresh factory/wallet reads: it requires an uncommitted failure, an advanced owner index, and a deployed wallet at the predicted slot with the same owner/index but a different immutable label. If reads are unavailable or evidence is ambiguous, the SDK preserves the original error. A unit regression and isolated live race pass. This is an internal error-classification correction; it does not change the public API. + +## Validation + +| Check | Result | +| ------------------------------------------------------- | ---------------------------------------------------------------- | +| Funded live `agw-extended` group | 14 passed, 0 failed (6 management + 8 native policy) | +| Full core unit suite after the correction | 1,982 passed, 0 failed; 12 skipped; 116 suites passed, 1 skipped | +| Focused management unit suite | 19 passed | +| `core` build | Passed | +| `tsconfig.lib.json` and `tsconfig.spec.json` typechecks | Passed | +| Default E2E selection | Unchanged: 76 scenarios / 40 files / 81 tests | +| Standard AGW selection | Unchanged: 25 scenarios; the new 14 are opt-in only | + +The E2E group is registered as `--group agw-extended`, requires the verified AGW manifest, and is excluded from `all`. Reproduce selection (no transactions): + +```sh +cd packages/core +npx ts-node --transpile-only __e2e__/ci/run.ts --verify --group agw-extended +``` + +Running the group itself broadcasts testnet transactions and spends testnet funds: + +```sh +cd packages/core +npx ts-node --transpile-only __e2e__/ci/preflight.ts --group agw-extended --dry-run +AGW_EXTENDED_E2E=1 npx ts-node --transpile-only __e2e__/ci/run.ts --group agw-extended +``` + +Use the existing test environment and preflight procedure before a rerun. Logs below are sanitized; private keys and environment values are not included. + +## Logs + +- [Final full funded run](../live-svm-wire-2026-10-06/logs/live-agw-extended-final.log) +- [Initial index-race reproduction](../live-svm-wire-2026-10-06/logs/live-agw-extended-index-race.log) +- [Initial full run](../live-svm-wire-2026-10-06/logs/live-agw-extended.log) +- [Unit suite](../live-svm-wire-2026-10-06/logs/unit-final.log) +- [Focused management unit suite](../live-svm-wire-2026-10-06/logs/management-unit.log) +- [Build](../live-svm-wire-2026-10-06/logs/build-final.log) diff --git a/plan/agw/research/live-svm-wire-2026-10-06/logs/build-final.log b/plan/agw/research/live-svm-wire-2026-10-06/logs/build-final.log new file mode 100644 index 00000000..3ef7e788 --- /dev/null +++ b/plan/agw/research/live-svm-wire-2026-10-06/logs/build-final.log @@ -0,0 +1,11 @@ + +> nx run core:build + +Compiling TypeScript files for project "core"... +Done compiling TypeScript files for project "core". +(node:79325) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. +(Use `node --trace-warnings ...` to show where the warning was created) + + + + NX Successfully ran target build for project core diff --git a/plan/agw/research/live-svm-wire-2026-10-06/logs/live-agw-extended-final.log b/plan/agw/research/live-svm-wire-2026-10-06/logs/live-agw-extended-final.log new file mode 100644 index 00000000..b712a88d --- /dev/null +++ b/plan/agw/research/live-svm-wire-2026-10-06/logs/live-agw-extended-final.log @@ -0,0 +1,11 @@ +Running 14 scenarios (group: agw-extended) across 2 spec files. + +PASS core-e2e __e2e__/agw-extended/native-policy.spec.ts (275.511 s) +PASS core-e2e __e2e__/agw-extended/management.spec.ts (276.819 s) + +Test Suites: 2 passed, 2 total +Tests: 14 passed, 14 total +Snapshots: 0 total +Time: 552.361 s +Ran all test suites within paths "__e2e__/agw-extended/management.spec.ts", "__e2e__/agw-extended/native-policy.spec.ts". +Force exiting Jest: Have you considered using `--detectOpenHandles` to detect async operations that kept running after all tests finished? diff --git a/plan/agw/research/live-svm-wire-2026-10-06/logs/live-agw-extended-index-race.log b/plan/agw/research/live-svm-wire-2026-10-06/logs/live-agw-extended-index-race.log new file mode 100644 index 00000000..ad8d7067 --- /dev/null +++ b/plan/agw/research/live-svm-wire-2026-10-06/logs/live-agw-extended-index-race.log @@ -0,0 +1,225 @@ +node:internal/modules/cjs/loader:1215 + throw err; + ^ + +Error: Cannot find module '/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/node_modules/jest/bin/jest.js' + at Module._resolveFilename (node:internal/modules/cjs/loader:1212:15) + at Module._load (node:internal/modules/cjs/loader:1043:27) + at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:164:12) + at node:internal/main/run_main_module:28:49 { + code: 'MODULE_NOT_FOUND', + requireStack: [] +} + +Node.js v20.19.2 +FAIL core-e2e packages/core/__e2e__/agw-extended/management.spec.ts + ● Test suite failed to run + + packages/core/__e2e__/agw-extended/management.spec.ts:104:5 - error TS1005: 'try' expected. + + 104 finally { rt.execute = original; } +    ~~~~~~~ + +Test Suites: 1 failed, 1 total +Tests: 0 total +Snapshots: 0 total +Time: 0.532 s, estimated 239 s +Ran all test suites within paths "packages/core/__e2e__/agw-extended/management.spec.ts". +Force exiting Jest: Have you considered using `--detectOpenHandles` to detect async operations that kept running after all tests finished? +FAIL core-e2e packages/core/__e2e__/agw-extended/management.spec.ts (32.417 s) + agw extended management + ✕ 6. index race commits no grants to the competing wallet and retry takes the next slot (19822 ms) + ○ skipped 1. prefunding a derived address survives deployment and info/list keep owner index and label + ○ skipped 2. same-agent multiplicity is ambiguous before signing and selective revoke restores uncached lookup + ○ skipped 3. multi-rule add and revoke are atomic batches with exact checkpoint counts + ○ skipped 4. invalid revoke targets preserve enabled rules and signer nonce + ○ skipped 5. intervening agent spend refuses a stale replacement without changing grants or checkpoints + + ● agw extended management › 6. index race commits no grants to the competing wallet and retry takes the next slot + + expect(received).toMatchObject(expected) + + - Expected - 4 + + Received + 1 + + Object { + - "code": "INDEX_RACE", + - "details": Object { + - "committed": false, + - }, + + "code": "PUSH_CHAIN_EXECUTION_FAILED", + } + + 102 | causeDecodedErrorName: observed?.cause?.decodedError?.name, + 103 | }); + > 104 | expect(raceError).toMatchObject({ code: 'INDEX_RACE', details: { committed: false } }); + | ^ + 105 | } finally { rt.execute = original; } + 106 | if (!competing) throw new Error('Race injection did not run'); + 107 | expect((await f.owner.agentic.wallet(competing.wallet).rules.list()).rules).toEqual([]); + + at Object. (__e2e__/agw-extended/management.spec.ts:104:23) + +Test Suites: 1 failed, 1 total +Tests: 1 failed, 5 skipped, 6 total +Snapshots: 0 total +Time: 32.442 s +Ran all test suites within paths "packages/core/__e2e__/agw-extended/management.spec.ts". +Force exiting Jest: Have you considered using `--detectOpenHandles` to detect async operations that kept running after all tests finished? +FAIL core-e2e packages/core/__e2e__/agw-extended/management.spec.ts (30.927 s) + agw extended management + ✕ 6. index race commits no grants to the competing wallet and retry takes the next slot (18356 ms) + ○ skipped 1. prefunding a derived address survives deployment and info/list keep owner index and label + ○ skipped 2. same-agent multiplicity is ambiguous before signing and selective revoke restores uncached lookup + ○ skipped 3. multi-rule add and revoke are atomic batches with exact checkpoint counts + ○ skipped 4. invalid revoke targets preserve enabled rules and signer nonce + ○ skipped 5. intervening agent spend refuses a stale replacement without changing grants or checkpoints + + ● agw extended management › 6. index race commits no grants to the competing wallet and retry takes the next slot + + expect(received).toMatchObject(expected) + + - Expected - 4 + + Received + 1 + + Object { + - "code": "INDEX_RACE", + - "details": Object { + - "committed": false, + - }, + + "code": "PUSH_CHAIN_EXECUTION_FAILED", + } + + 113 | errorLayers, + 114 | }); + > 115 | expect(raceError).toMatchObject({ code: 'INDEX_RACE', details: { committed: false } }); + | ^ + 116 | } finally { rt.execute = original; } + 117 | if (!competing) throw new Error('Race injection did not run'); + 118 | expect((await f.owner.agentic.wallet(competing.wallet).rules.list()).rules).toEqual([]); + + at Object. (__e2e__/agw-extended/management.spec.ts:115:23) + +Test Suites: 1 failed, 1 total +Tests: 1 failed, 5 skipped, 6 total +Snapshots: 0 total +Time: 30.944 s, estimated 33 s +Ran all test suites within paths "packages/core/__e2e__/agw-extended/management.spec.ts". +Force exiting Jest: Have you considered using `--detectOpenHandles` to detect async operations that kept running after all tests finished? +FAIL core-e2e packages/core/__e2e__/agw-extended/management.spec.ts (28.745 s) + agw extended management + ✕ 6. index race commits no grants to the competing wallet and retry takes the next slot (17599 ms) + ○ skipped 1. prefunding a derived address survives deployment and info/list keep owner index and label + ○ skipped 2. same-agent multiplicity is ambiguous before signing and selective revoke restores uncached lookup + ○ skipped 3. multi-rule add and revoke are atomic batches with exact checkpoint counts + ○ skipped 4. invalid revoke targets preserve enabled rules and signer nonce + ○ skipped 5. intervening agent spend refuses a stale replacement without changing grants or checkpoints + + ● agw extended management › 6. index race commits no grants to the competing wallet and retry takes the next slot + + expect(received).toMatchObject(expected) + + - Expected - 4 + + Received + 1 + + Object { + - "code": "INDEX_RACE", + - "details": Object { + - "committed": false, + - }, + + "code": "PUSH_CHAIN_EXECUTION_FAILED", + } + + 114 | nestedDecodedErrorName: observed?.cause?.cause?.decodedError?.name, + 115 | }); + > 116 | expect(raceError).toMatchObject({ code: 'INDEX_RACE', details: { committed: false } }); + | ^ + 117 | } finally { rt.execute = original; } + 118 | if (!competing) throw new Error('Race injection did not run'); + 119 | expect((await f.owner.agentic.wallet(competing.wallet).rules.list()).rules).toEqual([]); + + at Object. (__e2e__/agw-extended/management.spec.ts:116:23) + +Test Suites: 1 failed, 1 total +Tests: 1 failed, 5 skipped, 6 total +Snapshots: 0 total +Time: 28.767 s, estimated 31 s +Ran all test suites within paths "packages/core/__e2e__/agw-extended/management.spec.ts". +Force exiting Jest: Have you considered using `--detectOpenHandles` to detect async operations that kept running after all tests finished? +FAIL core-e2e packages/core/__e2e__/agw-extended/management.spec.ts + ● Test suite failed to run + + packages/core/__e2e__/agw-extended/management.spec.ts:95:38 - error TS2339: Property 'message' does not exist on type '{ code?: string | undefined; name?: string | undefined; details?: Record | undefined; transactionHashes?: `0x${string}`[] | undefined; pendingTransactionHash?: `0x${string}` | undefined; decodedError?: { ...; } | undefined; cause?: { ...; } | undefined; }'. + + 95 const messageLayers = [observed?.message, observed?.cause?.message, observed?.cause?.cause?.message] +    ~~~~~~~ + packages/core/__e2e__/agw-extended/management.spec.ts:95:64 - error TS2339: Property 'message' does not exist on type '{ name?: string | undefined; decodedError?: { name?: string | undefined; } | undefined; gatewayTxHash?: `0x${string}` | undefined; transactionHashes?: `0x${string}`[] | undefined; cause?: { name?: string | undefined; decodedError?: { ...; } | undefined; } | undefined; }'. + + 95 const messageLayers = [observed?.message, observed?.cause?.message, observed?.cause?.cause?.message] +    ~~~~~~~ + packages/core/__e2e__/agw-extended/management.spec.ts:95:97 - error TS2339: Property 'message' does not exist on type '{ name?: string | undefined; decodedError?: { name?: string | undefined; } | undefined; }'. + + 95 const messageLayers = [observed?.message, observed?.cause?.message, observed?.cause?.cause?.message] +    ~~~~~~~ + +Test Suites: 1 failed, 1 total +Tests: 0 total +Snapshots: 0 total +Time: 0.48 s, estimated 29 s +Ran all test suites within paths "packages/core/__e2e__/agw-extended/management.spec.ts". +Force exiting Jest: Have you considered using `--detectOpenHandles` to detect async operations that kept running after all tests finished? +FAIL core-e2e packages/core/__e2e__/agw-extended/management.spec.ts (38.232 s) + agw extended management + ✕ 6. index race commits no grants to the competing wallet and retry takes the next slot (23598 ms) + ○ skipped 1. prefunding a derived address survives deployment and info/list keep owner index and label + ○ skipped 2. same-agent multiplicity is ambiguous before signing and selective revoke restores uncached lookup + ○ skipped 3. multi-rule add and revoke are atomic batches with exact checkpoint counts + ○ skipped 4. invalid revoke targets preserve enabled rules and signer nonce + ○ skipped 5. intervening agent spend refuses a stale replacement without changing grants or checkpoints + + ● agw extended management › 6. index race commits no grants to the competing wallet and retry takes the next slot + + expect(received).toMatchObject(expected) + + - Expected - 4 + + Received + 1 + + Object { + - "code": "INDEX_RACE", + - "details": Object { + - "committed": false, + - }, + + "code": "PUSH_CHAIN_EXECUTION_FAILED", + } + + 124 | customErrorSelectors, + 125 | }); + > 126 | expect(raceError).toMatchObject({ code: 'INDEX_RACE', details: { committed: false } }); + | ^ + 127 | } finally { rt.execute = original; } + 128 | if (!competing) throw new Error('Race injection did not run'); + 129 | expect((await f.owner.agentic.wallet(competing.wallet).rules.list()).rules).toEqual([]); + + at Object. (__e2e__/agw-extended/management.spec.ts:126:23) + +Test Suites: 1 failed, 1 total +Tests: 1 failed, 5 skipped, 6 total +Snapshots: 0 total +Time: 38.253 s +Ran all test suites within paths "packages/core/__e2e__/agw-extended/management.spec.ts". +Force exiting Jest: Have you considered using `--detectOpenHandles` to detect async operations that kept running after all tests finished? +PASS core-e2e packages/core/__e2e__/agw-extended/management.spec.ts (67.19 s) + agw extended management + ✓ 6. index race commits no grants to the competing wallet and retry takes the next slot (50016 ms) + ○ skipped 1. prefunding a derived address survives deployment and info/list keep owner index and label + ○ skipped 2. same-agent multiplicity is ambiguous before signing and selective revoke restores uncached lookup + ○ skipped 3. multi-rule add and revoke are atomic batches with exact checkpoint counts + ○ skipped 4. invalid revoke targets preserve enabled rules and signer nonce + ○ skipped 5. intervening agent spend refuses a stale replacement without changing grants or checkpoints + +Test Suites: 1 passed, 1 total +Tests: 5 skipped, 1 passed, 6 total +Snapshots: 0 total +Time: 67.209 s +Ran all test suites within paths "packages/core/__e2e__/agw-extended/management.spec.ts". +Force exiting Jest: Have you considered using `--detectOpenHandles` to detect async operations that kept running after all tests finished? diff --git a/plan/agw/research/live-svm-wire-2026-10-06/logs/live-agw-extended.log b/plan/agw/research/live-svm-wire-2026-10-06/logs/live-agw-extended.log new file mode 100644 index 00000000..da8b5e61 --- /dev/null +++ b/plan/agw/research/live-svm-wire-2026-10-06/logs/live-agw-extended.log @@ -0,0 +1,37 @@ +Running 14 scenarios (group: agw-extended) across 2 spec files. + +FAIL core-e2e __e2e__/agw-extended/management.spec.ts (238.257 s) + ● agw extended management › 6. index race commits no grants to the competing wallet and retry takes the next slot + + expect(received).rejects.toMatchObject(expected) + + - Expected - 4 + + Received + 1 + + Object { + - "code": "INDEX_RACE", + - "details": Object { + - "committed": false, + - }, + + "code": "PUSH_CHAIN_EXECUTION_FAILED", + } + + 76 | return original(params, opts); + 77 | }; + > 78 | try { await expect(f.owner.agentic.create('e2e-race-loser', { rules: [rule()] })).rejects.toMatchObject({ code: 'INDEX_RACE', details: { committed: false } }); } + | ^ + 79 | finally { rt.execute = original; } + 80 | if (!competing) throw new Error('Race injection did not run'); + 81 | expect((await f.owner.agentic.wallet(competing.wallet).rules.list()).rules).toEqual([]); + + at Object.toMatchObject (../../node_modules/expect/build/index.js:218:22) + at Object. (__e2e__/agw-extended/management.spec.ts:78:95) + +PASS core-e2e __e2e__/agw-extended/native-policy.spec.ts (296.801 s) + +Test Suites: 1 failed, 1 passed, 2 total +Tests: 1 failed, 13 passed, 14 total +Snapshots: 0 total +Time: 535.098 s +Ran all test suites within paths "__e2e__/agw-extended/management.spec.ts", "__e2e__/agw-extended/native-policy.spec.ts". +Force exiting Jest: Have you considered using `--detectOpenHandles` to detect async operations that kept running after all tests finished? diff --git a/plan/agw/research/live-svm-wire-2026-10-06/logs/management-unit.log b/plan/agw/research/live-svm-wire-2026-10-06/logs/management-unit.log new file mode 100644 index 00000000..ac595771 --- /dev/null +++ b/plan/agw/research/live-svm-wire-2026-10-06/logs/management-unit.log @@ -0,0 +1,29 @@ +PASS core packages/core/src/lib/agentic/__tests__/management.spec.ts + agentic.create + ✓ validates first, then sends deploy + grants in input order and returns receipt IDs (9 ms) + ✓ a bare wallet is one deployWallet call, no funding + ✓ invalid input never reaches the signer + ✓ refuses a changed URP version before grant signing + ✓ a different wallet in the receipt is an INDEX_RACE with full details (1 ms) + ✓ IDs that differ from the input order are a RECEIPT_MISMATCH, not a silent reorder (2 ms) + ✓ a sequential failure after deployment is CREATE_PARTIAL; what committed comes from this call’s receipts (2 ms) + ✓ a pending hash keeps an unconfirmed deployment unknown (1 ms) + ✓ failed recovery reads report unknown state, never "not deployed" (1 ms) + ✓ a receipt that cannot be read after submission keeps the hash and reports unknown state (1 ms) + ✓ the deploy is index-bound: a raced slot reverts and is reported as INDEX_RACE with nothing committed (2 ms) + ✓ a generic send error is still identified as a race when the fresh slot label proves another create won (1 ms) + ✓ a slot that is already deployed is refused before signing (1 ms) + rules.add / rules.revoke + ✓ add: owner-only, same-agent grants allowed, IDs from the grant nonce + ✓ add: several rules are one atomic owner execute batch (one signature on any signer) (2 ms) + ✓ revoke: bare and empty are refused; unknown IDs fail before signing; several IDs are one atomic owner execute (2 ms) + rules.update — one owner batch: assert → revoke → grant + ✓ builds exactly one execute(batch) with the observed spend asserted per pair (2 ms) + ✓ universal replacement asserts every asset in stored order before revoke/grant (2 ms) + ✓ replacement may name another live agent, but may not repeat an old ID (4 ms) + +Test Suites: 1 passed, 1 total +Tests: 19 passed, 19 total +Snapshots: 0 total +Time: 3.115 s +Ran all test suites within paths "packages/core/src/lib/agentic/__tests__/management.spec.ts". diff --git a/plan/agw/research/live-svm-wire-2026-10-06/logs/unit-final.log b/plan/agw/research/live-svm-wire-2026-10-06/logs/unit-final.log new file mode 100644 index 00000000..1b1198ff --- /dev/null +++ b/plan/agw/research/live-svm-wire-2026-10-06/logs/unit-final.log @@ -0,0 +1,169 @@ +PASS core packages/core/src/lib/universal/account/account.spec.ts + ● Console + + console.warn + [PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead. + + 207 | ): Promise { + 208 | if (!_convertOriginToExecutorWarned) { + > 209 | console.warn( + | ^ + 210 | '[PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead.' + 211 | ); + 212 | _convertOriginToExecutorWarned = true; + + at Object.convertOriginToExecutor (src/lib/universal/account/account.ts:209:13) + at Object. (src/lib/universal/account/account.spec.ts:80:52) + + console.warn + [PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead. + + 425 | ): Promise { + 426 | if (!options?._internal && !_convertExecutorToOriginWarned) { + > 427 | console.warn( + | ^ + 428 | '[PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead.' + 429 | ); + 430 | _convertExecutorToOriginWarned = true; + + at convertExecutorToOrigin (src/lib/universal/account/account.ts:427:13) + at Object. (src/lib/universal/account/account.spec.ts:106:38) + +PASS core packages/core/src/lib/agentic/__tests__/management.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/block-results-client.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/source-hash-resolution.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-tx-retry.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/execute-standard-required-funds.spec.ts +PASS core packages/core/src/lib/push-client/push-client.archive-fallback.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gateway-uea-account.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-confirmation-gate.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/inbound-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-svm-r3.spec.ts +PASS core packages/core/src/lib/universal/signer/signer.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-timeout-clamp.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/signing-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-svm-confirmation.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r2-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/rescue-svm-confirmation.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-backend.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-composition.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/scenarios.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/context-helpers-tracker.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/send-transaction-progress-hook.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-usd-sizer.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r2-outbound-revert-flow.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/cascade.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-request-recipient.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/inbound-tracker-derivation.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/svm-rent.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/response-builder-push-revert.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-svm-rent.spec.ts +PASS core packages/core/src/lib/utils.spec.ts + ● Console + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:973:17) + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:977:17) + + console.log + 1.23 + + at Object. (src/lib/utils.spec.ts:982:17) + +PASS core packages/core/src/lib/orchestrator/__tests__/track-transaction-guard.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/multichain-hooks.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-builder-progress-hook.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/account-status.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/resolver.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/response-invariant.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/registry.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-tracker.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/chain-namespace.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/gate.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-executor.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/web2-compat.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/payload-builders.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/response-surface.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-detector.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/read-tx-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-gas.spec.ts +PASS core packages/core/src/lib/push-client/push-client.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/send.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r3-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-calculator.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-multichain.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm-rent-pc20.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/resolve.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-native-multicall.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/__tests__/signing.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/svm-account.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-emission.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-evm-r3-native-eoa.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-event-hook-bridge.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/build-payload.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/public-surface.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/export.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/funds-only-burn-guard.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r1-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/terminal-suppression.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/revalidate-read.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-params.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/spec-builder.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-wire-fixture.spec.ts +PASS core packages/core/src/lib/constants/__tests__/token-constants.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/normalize.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm-log-index.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/result-decoder.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-svm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-evm.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/address-codec.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/codec.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/reads-context.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/auto-detect.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/validate.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/child-inbounds.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.chain-symbol.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/abi-selectors.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-types.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/ucallback-codec.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg-svm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-events.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-web2.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.dynamic-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/ix-encoder.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/registry.spec.ts +PASS core packages/core/src/lib/constants/__tests__/svm-gateway-idl.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/normalize-address.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/max-pc-for-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/error-decoder.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-execute-order.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/classify.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/tracking.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/budget.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/errors.spec.ts +PASS core packages/core/src/lib/formatters.spec.ts + +Test Suites: 1 skipped, 116 passed, 116 of 117 total +Tests: 12 skipped, 1982 passed, 1994 total +Snapshots: 0 total +Time: 28.266 s, estimated 37 s +Ran all test suites. diff --git a/plan/agw/research/live-svm-wire-2026-10-06/run-redacted.cjs b/plan/agw/research/live-svm-wire-2026-10-06/run-redacted.cjs index 0d51e039..d72a7787 100644 --- a/plan/agw/research/live-svm-wire-2026-10-06/run-redacted.cjs +++ b/plan/agw/research/live-svm-wire-2026-10-06/run-redacted.cjs @@ -10,10 +10,12 @@ const secrets = [...new Set(Object.entries(env) .flatMap(([, value]) => [value, ...(value.startsWith('0x') ? [value.slice(2)] : [])]))] .sort((a, b) => b.length - a.length); const redact = (text) => secrets.reduce((result, secret) => result.split(secret).join('[REDACTED]'), text); -const name = process.argv[2] ?? 'live.log'; +const group = process.argv[2] ?? 'agw-svm-wire'; +const name = process.argv[3] ?? `${group}.log`; +if (!['agw-svm-wire', 'agw-extended'].includes(group)) throw new Error('Unsupported funded AGW test group'); if (!/^[a-z0-9-]+\.log$/.test(name)) throw new Error('Use a simple log filename'); const child = spawn(process.execPath, ['../../node_modules/ts-node/dist/bin.js', '--transpile-only', - '__e2e__/ci/run.ts', '--group', 'agw-svm-wire'], { + '__e2e__/ci/run.ts', '--group', group], { cwd: path.join(root, 'packages/core'), env, stdio: ['ignore', 'pipe', 'pipe'], }); let log = ''; From 1625053bf6ab8dc6be987e7fd37bac8a682e53de Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Tue, 6 Oct 2026 17:22:31 +0530 Subject: [PATCH 28/68] chore(agw): consolidate e2e coverage and ABI sources --- .../__agw-local__/agw-local-races.spec.ts | 2 +- .../management-extended.spec.ts} | 4 +- .../native-policy-extended.spec.ts} | 4 +- packages/core/__e2e__/ci/preflight.ts | 2 +- packages/core/__e2e__/ci/run.ts | 2 +- packages/core/__e2e__/ci/suite.ts | 17 +- .../core/scripts/agw-local/abis/engine.json | 1957 +++++++++++++++ .../core/scripts/agw-local/abis/factory.json | 1105 +++++++++ .../core/scripts/agw-local/abis/manifest.json | 12 + .../core/scripts/agw-local/abis/policy.json | 2157 +++++++++++++++++ .../scripts/agw-local/abis/validator.json | 141 ++ .../core/scripts/agw-local/abis/wallet.json | 1550 ++++++++++++ packages/core/scripts/agw-local/gen-abi.mjs | 15 +- .../core/src/lib/agentic/agentic.types.ts | 4 +- packages/core/src/lib/agentic/capabilities.ts | 4 +- .../core/src/lib/agentic/codec/defaults.ts | 4 +- .../contracts/abi/v4/agent-validator.ts | 2 +- .../agentic/contracts/abi/v4/agw-factory.ts | 2 +- .../src/lib/agentic/contracts/abi/v4/agw.ts | 2 +- .../agentic/contracts/abi/v4/smart-session.ts | 2 +- .../abi/v4/universal-rules-policy.ts | 2 +- plan/agw/README.md | 2 +- plan/agw/current-baseline.md | 4 +- plan/agw/gaps.md | 4 +- plan/agw/implementation-status.md | 8 +- .../extended-e2e-2026-10-06/README.md | 20 +- 26 files changed, 6977 insertions(+), 51 deletions(-) rename packages/core/__e2e__/{agw-extended/management.spec.ts => agw/management-extended.spec.ts} (98%) rename packages/core/__e2e__/{agw-extended/native-policy.spec.ts => agw/native-policy-extended.spec.ts} (97%) create mode 100644 packages/core/scripts/agw-local/abis/engine.json create mode 100644 packages/core/scripts/agw-local/abis/factory.json create mode 100644 packages/core/scripts/agw-local/abis/manifest.json create mode 100644 packages/core/scripts/agw-local/abis/policy.json create mode 100644 packages/core/scripts/agw-local/abis/validator.json create mode 100644 packages/core/scripts/agw-local/abis/wallet.json diff --git a/packages/core/__agw-local__/agw-local-races.spec.ts b/packages/core/__agw-local__/agw-local-races.spec.ts index bbc3c9f0..3121007d 100644 --- a/packages/core/__agw-local__/agw-local-races.spec.ts +++ b/packages/core/__agw-local__/agw-local-races.spec.ts @@ -1,5 +1,5 @@ /** - * Race regressions from the implementation review (plan/agw/implementation-review), + * Race regressions found during independent SDK review, * against the real pinned v4 contracts on local anvil. * R1 — a concurrent creation must never let this create() grant on a wallet it * did not deploy (the deploy is index-bound through deployWalletWithSig). diff --git a/packages/core/__e2e__/agw-extended/management.spec.ts b/packages/core/__e2e__/agw/management-extended.spec.ts similarity index 98% rename from packages/core/__e2e__/agw-extended/management.spec.ts rename to packages/core/__e2e__/agw/management-extended.spec.ts index 70778529..1b2b6b05 100644 --- a/packages/core/__e2e__/agw-extended/management.spec.ts +++ b/packages/core/__e2e__/agw/management-extended.spec.ts @@ -2,10 +2,10 @@ import { PushChain } from '../../src'; import { getAddress, type Address } from 'viem'; import type { AgenticRuntime } from '../../src/lib/agentic/runtime'; import { v4 } from '../../src/lib/agentic/contracts/v4'; -import { setupAgw, inSeconds, type AgwFixture } from '../agw/_fixture'; +import { setupAgw, inSeconds, type AgwFixture } from './_fixture'; import { readNativeCounters } from '../shared/agw-state'; -const d = process.env['AGW_EXTENDED_E2E'] === '1' ? describe : describe.skip; +const d = process.env['AGW_E2E'] === '1' ? describe : describe.skip; const runtime = (client: PushChain) => (client as unknown as { agenticRuntime: AgenticRuntime }).agenticRuntime; diff --git a/packages/core/__e2e__/agw-extended/native-policy.spec.ts b/packages/core/__e2e__/agw/native-policy-extended.spec.ts similarity index 97% rename from packages/core/__e2e__/agw-extended/native-policy.spec.ts rename to packages/core/__e2e__/agw/native-policy-extended.spec.ts index 40917e56..544a2a1e 100644 --- a/packages/core/__e2e__/agw-extended/native-policy.spec.ts +++ b/packages/core/__e2e__/agw/native-policy-extended.spec.ts @@ -4,9 +4,9 @@ import { encodeFunctionData, erc20Abi, type Address } from 'viem'; import { getNativePRC20ForChain } from '../../src/lib/orchestrator/internals/helpers'; import { readNativeCounters } from '../shared/agw-state'; import { CHAIN } from '../../src/lib/constants/enums'; -import { setupAgw, inSeconds, type AgwFixture } from '../agw/_fixture'; +import { setupAgw, inSeconds, type AgwFixture } from './_fixture'; -const d = process.env['AGW_EXTENDED_E2E'] === '1' ? describe : describe.skip; +const d = process.env['AGW_E2E'] === '1' ? describe : describe.skip; const chain = PushChain.CONSTANTS.CHAIN.PUSH_TESTNET_DONUT; d('agw extended native policy', () => { diff --git a/packages/core/__e2e__/ci/preflight.ts b/packages/core/__e2e__/ci/preflight.ts index 2a3c1f29..37b04763 100644 --- a/packages/core/__e2e__/ci/preflight.ts +++ b/packages/core/__e2e__/ci/preflight.ts @@ -333,7 +333,7 @@ function renderTable(rows: Row[]): void { }) as PublicClient; // -- AGW gate ------------------------------------------------------------ - // The agw group needs a verified compatible AGW deployment (plan/agw A07). + // Every AGW group needs a verified compatible AGW deployment. // Check it read-only BEFORE any balance work so nothing is ever funded for // a run that cannot exercise a real deployment. if (scenarios.some((s) => s.group.startsWith('agw'))) { diff --git a/packages/core/__e2e__/ci/run.ts b/packages/core/__e2e__/ci/run.ts index a2939f94..06b48485 100644 --- a/packages/core/__e2e__/ci/run.ts +++ b/packages/core/__e2e__/ci/run.ts @@ -7,7 +7,7 @@ * * --group One of: all (default), smoke, evm-r1, evm-r2, evm-r3, * svm-r1, svm-r2r3, pc20, push, cross-chain, read, - * known-fail, agw, agw-extended, agw-svm-wire, agw-svm-replay + * known-fail, agw, agw-svm-wire, agw-svm-replay * (`all` excludes known-fail and AGW groups — ask by name; * agw uses the checked Donut v4 manifest by default, see __e2e__/agw/_manifest.ts) * --list Print the selection and the jest argv, run nothing diff --git a/packages/core/__e2e__/ci/suite.ts b/packages/core/__e2e__/ci/suite.ts index 5ad1feec..f09ce1db 100644 --- a/packages/core/__e2e__/ci/suite.ts +++ b/packages/core/__e2e__/ci/suite.ts @@ -35,7 +35,6 @@ export const GROUPS = [ 'read', 'known-fail', 'agw', - 'agw-extended', 'agw-svm-wire', 'agw-svm-replay', ] as const; @@ -161,8 +160,8 @@ const F = { agwUniversal: '__e2e__/agw/universal-evm.spec.ts', agwIdentity: '__e2e__/agw/identity-gas.spec.ts', agwResponses: '__e2e__/agw/responses-hooks.spec.ts', - agwExtendedManagement: '__e2e__/agw-extended/management.spec.ts', - agwExtendedNative: '__e2e__/agw-extended/native-policy.spec.ts', + agwExtendedManagement: '__e2e__/agw/management-extended.spec.ts', + agwExtendedNative: '__e2e__/agw/native-policy-extended.spec.ts', } as const; export const SCENARIOS: Scenario[] = [ @@ -835,7 +834,7 @@ export const SCENARIOS: Scenario[] = [ // ------------------------------------------------------------------------- // agw — agentic wallets. EXCLUDED from `all`: every spec's beforeAll fails // its prerequisite gate until a verified compatible AGW deployment manifest - // (AGW_DEPLOYMENT_MANIFEST) exists — plan/agw assumption A07. Preflight + // (AGW_DEPLOYMENT_MANIFEST) exists. Preflight // refuses to fund the group without it. Budgets are per run: the Push master // (owner) pays setup gas, wallet PC and the bounded fresh-agent funding; // the EVM master's UEA pays external-agent gas; pETH funds the outbound. @@ -1051,25 +1050,25 @@ export const SCENARIOS: Scenario[] = [ ['index-race', '6\\. index race', '1'], ].map(([slug, grep, pc]) => ({ id: `agw-extended-${slug}`, - group: 'agw-extended' as const, + group: 'agw' as const, file: F.agwExtendedManagement, grep: `agw extended management ${grep}`, needs: { masterPC: pc }, - env: { AGW_EXTENDED_E2E: '1' }, + env: { AGW_E2E: '1' }, })), ...Array.from({ length: 8 }, (_, i) => ({ id: `agw-extended-native-policy-${i + 1}`, - group: 'agw-extended' as const, + group: 'agw' as const, file: F.agwExtendedNative, grep: `agw extended native policy ${i + 1}\\.`, needs: { masterPC: '0.25', masterPETH: '0.000000000001' }, - env: { AGW_EXTENDED_E2E: '1' }, + env: { AGW_E2E: '1' }, })), ]; /** * Scenarios for a group. `all` means "everything that should pass" — it deliberately - * excludes `known-fail`, `agw` and `agw-svm-wire`, which must be requested by name. + * excludes `known-fail` and every AGW group, which must be requested by name. */ export function scenariosFor(group: string | undefined): Scenario[] { if (!group || group === 'all') { diff --git a/packages/core/scripts/agw-local/abis/engine.json b/packages/core/scripts/agw-local/abis/engine.json new file mode 100644 index 00000000..61100bd3 --- /dev/null +++ b/packages/core/scripts/agw-local/abis/engine.json @@ -0,0 +1,1957 @@ +[ + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "AssociatedArray_OutOfBounds", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint64", + "name": "providedChainId", + "type": "uint64" + } + ], + "name": "ChainIdMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint64", + "name": "providedChainId", + "type": "uint64" + } + ], + "name": "ChainIdMismatch", + "type": "error" + }, + { + "inputs": [], + "name": "ForbiddenValidationData", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "HashIndexOutOfBounds", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "providedHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "computedHash", + "type": "bytes32" + } + ], + "name": "HashMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "providedHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "computedHash", + "type": "bytes32" + } + ], + "name": "HashMismatch", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidActionId", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidCallTarget", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidData", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "hash", + "type": "bytes32" + } + ], + "name": "InvalidEnableSignature", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "contract ISessionValidator", + "name": "sessionValidator", + "type": "address" + } + ], + "name": "InvalidISessionValidator", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidMode", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + } + ], + "name": "InvalidPermissionId", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidSelfCall", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + } + ], + "name": "InvalidSession", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "sessionValidator", + "type": "address" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "userOpHash", + "type": "bytes32" + } + ], + "name": "InvalidSessionKeySignature", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidTarget", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "InvalidUserOpSender", + "type": "error" + }, + { + "inputs": [], + "name": "NoExecutionsInBatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + } + ], + "name": "NoPoliciesSet", + "type": "error" + }, + { + "inputs": [], + "name": "PartlyEnabledActions", + "type": "error" + }, + { + "inputs": [], + "name": "PartlyEnabledPolicies", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + } + ], + "name": "PaymasterValidationNotEnabled", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "policy", + "type": "address" + } + ], + "name": "PolicyViolation", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "SignerNotFound", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "SignerNotFound", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "SmartSessionModuleAlreadyInstalled", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "CallType", + "name": "callType", + "type": "bytes1" + } + ], + "name": "UnsupportedCallType", + "type": "error" + }, + { + "inputs": [], + "name": "UnsupportedExecutionType", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + } + ], + "name": "UnsupportedPolicy", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "enum SmartSessionMode", + "name": "mode", + "type": "uint8" + } + ], + "name": "UnsupportedSmartSessionMode", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "ActionId", + "name": "actionId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "address", + "name": "smartAccount", + "type": "address" + } + ], + "name": "ActionIdDisabled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newValue", + "type": "uint256" + } + ], + "name": "NonceIterated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "address", + "name": "smartAccount", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "enabled", + "type": "bool" + } + ], + "name": "PermissionIdPermit4337Paymaster", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "enum PolicyType", + "name": "policyType", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "smartAccount", + "type": "address" + } + ], + "name": "PolicyDisabled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "enum PolicyType", + "name": "policyType", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "smartAccount", + "type": "address" + } + ], + "name": "PolicyEnabled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "SessionCreated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "address", + "name": "smartAccount", + "type": "address" + } + ], + "name": "SessionRemoved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "address", + "name": "sessionValidator", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "smartAccount", + "type": "address" + } + ], + "name": "SessionValidatorDisabled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "address", + "name": "sessionValidator", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "smartAccount", + "type": "address" + } + ], + "name": "SessionValidatorEnabled", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "components": [ + { + "internalType": "bytes4", + "name": "actionTargetSelector", + "type": "bytes4" + }, + { + "internalType": "address", + "name": "actionTarget", + "type": "address" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "actionPolicies", + "type": "tuple[]" + } + ], + "internalType": "struct ActionData[]", + "name": "actions", + "type": "tuple[]" + } + ], + "name": "areActionsEnabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "erc1271Policies", + "type": "tuple[]" + } + ], + "name": "areERC1271PoliciesEnabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "userOpPolicies", + "type": "tuple[]" + } + ], + "name": "areUserOpPoliciesEnabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "internalType": "ActionId", + "name": "actionId", + "type": "bytes32" + } + ], + "name": "disableActionId", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "internalType": "ActionId", + "name": "actionId", + "type": "bytes32" + }, + { + "internalType": "address[]", + "name": "policies", + "type": "address[]" + } + ], + "name": "disableActionPolicies", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "internalType": "address[]", + "name": "policies", + "type": "address[]" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "appDomainSeparator", + "type": "bytes32" + }, + { + "internalType": "string[]", + "name": "contentNames", + "type": "string[]" + } + ], + "internalType": "struct ERC7739Context[]", + "name": "contexts", + "type": "tuple[]" + } + ], + "name": "disableERC1271Policies", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "internalType": "address[]", + "name": "policies", + "type": "address[]" + } + ], + "name": "disableUserOpPolicies", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "components": [ + { + "internalType": "bytes4", + "name": "actionTargetSelector", + "type": "bytes4" + }, + { + "internalType": "address", + "name": "actionTarget", + "type": "address" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "actionPolicies", + "type": "tuple[]" + } + ], + "internalType": "struct ActionData[]", + "name": "actionPolicies", + "type": "tuple[]" + } + ], + "name": "enableActionPolicies", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "components": [ + { + "components": [ + { + "internalType": "bytes32", + "name": "appDomainSeparator", + "type": "bytes32" + }, + { + "internalType": "string[]", + "name": "contentNames", + "type": "string[]" + } + ], + "internalType": "struct ERC7739Context[]", + "name": "allowedERC7739Content", + "type": "tuple[]" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "erc1271Policies", + "type": "tuple[]" + } + ], + "internalType": "struct ERC7739Data", + "name": "erc1271Policies", + "type": "tuple" + } + ], + "name": "enableERC1271Policies", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "contract ISessionValidator", + "name": "sessionValidator", + "type": "address" + }, + { + "internalType": "bytes", + "name": "sessionValidatorInitData", + "type": "bytes" + }, + { + "internalType": "bytes32", + "name": "salt", + "type": "bytes32" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "userOpPolicies", + "type": "tuple[]" + }, + { + "components": [ + { + "components": [ + { + "internalType": "bytes32", + "name": "appDomainSeparator", + "type": "bytes32" + }, + { + "internalType": "string[]", + "name": "contentNames", + "type": "string[]" + } + ], + "internalType": "struct ERC7739Context[]", + "name": "allowedERC7739Content", + "type": "tuple[]" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "erc1271Policies", + "type": "tuple[]" + } + ], + "internalType": "struct ERC7739Data", + "name": "erc7739Policies", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "bytes4", + "name": "actionTargetSelector", + "type": "bytes4" + }, + { + "internalType": "address", + "name": "actionTarget", + "type": "address" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "actionPolicies", + "type": "tuple[]" + } + ], + "internalType": "struct ActionData[]", + "name": "actions", + "type": "tuple[]" + }, + { + "internalType": "bool", + "name": "permitERC4337Paymaster", + "type": "bool" + } + ], + "internalType": "struct Session[]", + "name": "sessions", + "type": "tuple[]" + } + ], + "name": "enableSessions", + "outputs": [ + { + "internalType": "PermissionId[]", + "name": "permissionIds", + "type": "bytes32[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "userOpPolicies", + "type": "tuple[]" + } + ], + "name": "enableUserOpPolicies", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "internalType": "ActionId", + "name": "actionId", + "type": "bytes32" + } + ], + "name": "getActionPolicies", + "outputs": [ + { + "internalType": "address[]", + "name": "", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + } + ], + "name": "getERC1271Policies", + "outputs": [ + { + "internalType": "address[]", + "name": "", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + } + ], + "name": "getEnabledActions", + "outputs": [ + { + "internalType": "bytes32[]", + "name": "", + "type": "bytes32[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + } + ], + "name": "getEnabledERC7739Content", + "outputs": [ + { + "components": [ + { + "internalType": "bytes32", + "name": "appDomainSeparator", + "type": "bytes32" + }, + { + "internalType": "bytes32[]", + "name": "contentNameHashes", + "type": "bytes32[]" + } + ], + "internalType": "struct ERC7739ContextHashes[]", + "name": "enabledERC7739ContentHashes", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "getNonce", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "getPermissionIDs", + "outputs": [ + { + "internalType": "PermissionId[]", + "name": "permissionIds", + "type": "bytes32[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "contract ISessionValidator", + "name": "sessionValidator", + "type": "address" + }, + { + "internalType": "bytes", + "name": "sessionValidatorInitData", + "type": "bytes" + }, + { + "internalType": "bytes32", + "name": "salt", + "type": "bytes32" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "userOpPolicies", + "type": "tuple[]" + }, + { + "components": [ + { + "components": [ + { + "internalType": "bytes32", + "name": "appDomainSeparator", + "type": "bytes32" + }, + { + "internalType": "string[]", + "name": "contentNames", + "type": "string[]" + } + ], + "internalType": "struct ERC7739Context[]", + "name": "allowedERC7739Content", + "type": "tuple[]" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "erc1271Policies", + "type": "tuple[]" + } + ], + "internalType": "struct ERC7739Data", + "name": "erc7739Policies", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "bytes4", + "name": "actionTargetSelector", + "type": "bytes4" + }, + { + "internalType": "address", + "name": "actionTarget", + "type": "address" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "actionPolicies", + "type": "tuple[]" + } + ], + "internalType": "struct ActionData[]", + "name": "actions", + "type": "tuple[]" + }, + { + "internalType": "bool", + "name": "permitERC4337Paymaster", + "type": "bool" + } + ], + "internalType": "struct Session", + "name": "session", + "type": "tuple" + } + ], + "name": "getPermissionId", + "outputs": [ + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "components": [ + { + "internalType": "contract ISessionValidator", + "name": "sessionValidator", + "type": "address" + }, + { + "internalType": "bytes", + "name": "sessionValidatorInitData", + "type": "bytes" + }, + { + "internalType": "bytes32", + "name": "salt", + "type": "bytes32" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "userOpPolicies", + "type": "tuple[]" + }, + { + "components": [ + { + "components": [ + { + "internalType": "bytes32", + "name": "appDomainSeparator", + "type": "bytes32" + }, + { + "internalType": "string[]", + "name": "contentNames", + "type": "string[]" + } + ], + "internalType": "struct ERC7739Context[]", + "name": "allowedERC7739Content", + "type": "tuple[]" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "erc1271Policies", + "type": "tuple[]" + } + ], + "internalType": "struct ERC7739Data", + "name": "erc7739Policies", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "bytes4", + "name": "actionTargetSelector", + "type": "bytes4" + }, + { + "internalType": "address", + "name": "actionTarget", + "type": "address" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "actionPolicies", + "type": "tuple[]" + } + ], + "internalType": "struct ActionData[]", + "name": "actions", + "type": "tuple[]" + }, + { + "internalType": "bool", + "name": "permitERC4337Paymaster", + "type": "bool" + } + ], + "internalType": "struct Session", + "name": "data", + "type": "tuple" + }, + { + "internalType": "enum SmartSessionMode", + "name": "mode", + "type": "uint8" + } + ], + "name": "getSessionDigest", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + } + ], + "name": "getSessionValidatorAndConfig", + "outputs": [ + { + "internalType": "address", + "name": "sessionValidator", + "type": "address" + }, + { + "internalType": "bytes", + "name": "sessionValidatorData", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + } + ], + "name": "getUserOpPolicies", + "outputs": [ + { + "internalType": "address[]", + "name": "", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "internalType": "ActionId", + "name": "actionId", + "type": "bytes32" + } + ], + "name": "isActionIdEnabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "internalType": "ActionId", + "name": "actionId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "policy", + "type": "address" + } + ], + "name": "isActionPolicyEnabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "policy", + "type": "address" + } + ], + "name": "isERC1271PolicyEnabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "appDomainSeparator", + "type": "bytes32" + }, + { + "internalType": "string", + "name": "content", + "type": "string" + } + ], + "name": "isERC7739ContentEnabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "isISessionValidatorSet", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "smartAccount", + "type": "address" + } + ], + "name": "isInitialized", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "typeID", + "type": "uint256" + } + ], + "name": "isModuleType", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "isPermissionEnabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "policy", + "type": "address" + } + ], + "name": "isUserOpPolicyEnabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "hash", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "name": "isValidSignatureWithSender", + "outputs": [ + { + "internalType": "bytes4", + "name": "result", + "type": "bytes4" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "onInstall", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "name": "onUninstall", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + } + ], + "name": "removeSession", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + } + ], + "name": "revokeEnableSignature", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "PermissionId", + "name": "permissionId", + "type": "bytes32" + }, + { + "internalType": "bool", + "name": "enabled", + "type": "bool" + } + ], + "name": "setPermit4337Paymaster", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "initCode", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "callData", + "type": "bytes" + }, + { + "internalType": "bytes32", + "name": "accountGasLimits", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "preVerificationGas", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "gasFees", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "paymasterAndData", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "internalType": "struct PackedUserOperation", + "name": "userOp", + "type": "tuple" + }, + { + "internalType": "bytes32", + "name": "userOpHash", + "type": "bytes32" + } + ], + "name": "validateUserOp", + "outputs": [ + { + "internalType": "ValidationData", + "name": "vd", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/packages/core/scripts/agw-local/abis/factory.json b/packages/core/scripts/agw-local/abis/factory.json new file mode 100644 index 00000000..c2bf3eb7 --- /dev/null +++ b/packages/core/scripts/agw-local/abis/factory.json @@ -0,0 +1,1105 @@ +[ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "AccessControlBadConfirmation", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint48", + "name": "schedule", + "type": "uint48" + } + ], + "name": "AccessControlEnforcedDefaultAdminDelay", + "type": "error" + }, + { + "inputs": [], + "name": "AccessControlEnforcedDefaultAdminRules", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "defaultAdmin", + "type": "address" + } + ], + "name": "AccessControlInvalidDefaultAdmin", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "neededRole", + "type": "bytes32" + } + ], + "name": "AccessControlUnauthorizedAccount", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "target", + "type": "address" + } + ], + "name": "AddressEmptyCode", + "type": "error" + }, + { + "inputs": [], + "name": "CloneArgumentsTooLong", + "type": "error" + }, + { + "inputs": [], + "name": "Create2EmptyBytecode", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "ERC1967InvalidImplementation", + "type": "error" + }, + { + "inputs": [], + "name": "ERC1967NonPayable", + "type": "error" + }, + { + "inputs": [], + "name": "EnforcedPause", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "expected", + "type": "address" + }, + { + "internalType": "address", + "name": "actual", + "type": "address" + } + ], + "name": "ExecutorMismatch", + "type": "error" + }, + { + "inputs": [], + "name": "ExpectedPause", + "type": "error" + }, + { + "inputs": [], + "name": "FailedCall", + "type": "error" + }, + { + "inputs": [], + "name": "FailedDeployment", + "type": "error" + }, + { + "inputs": [], + "name": "ImplementationNotSet", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint96", + "name": "expected", + "type": "uint96" + }, + { + "internalType": "uint96", + "name": "provided", + "type": "uint96" + } + ], + "name": "IndexMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "next", + "type": "uint256" + } + ], + "name": "IndexOutOfRange", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "needed", + "type": "uint256" + } + ], + "name": "InsufficientBalance", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "expected", + "type": "address" + }, + { + "internalType": "address", + "name": "provided", + "type": "address" + } + ], + "name": "IntentWalletMismatch", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidInitialization", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidOwnerSignature", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "NotAWallet", + "type": "error" + }, + { + "inputs": [], + "name": "NotInitializing", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint8", + "name": "bits", + "type": "uint8" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "SafeCastOverflowedUintDowncast", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint48", + "name": "deadline", + "type": "uint48" + } + ], + "name": "SignatureExpired", + "type": "error" + }, + { + "inputs": [], + "name": "UUPSUnauthorizedCallContext", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "slot", + "type": "bytes32" + } + ], + "name": "UUPSUnsupportedProxiableUUID", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroAddress", + "type": "error" + }, + { + "anonymous": false, + "inputs": [], + "name": "DefaultAdminDelayChangeCanceled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint48", + "name": "newDelay", + "type": "uint48" + }, + { + "indexed": false, + "internalType": "uint48", + "name": "effectSchedule", + "type": "uint48" + } + ], + "name": "DefaultAdminDelayChangeScheduled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "DefaultAdminTransferCanceled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "newAdmin", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint48", + "name": "acceptSchedule", + "type": "uint48" + } + ], + "name": "DefaultAdminTransferScheduled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint64", + "name": "version", + "type": "uint64" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Paused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "previousAdminRole", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "newAdminRole", + "type": "bytes32" + } + ], + "name": "RoleAdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleGranted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleRevoked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Unpaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "Upgraded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "index", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "wallet", + "type": "address" + }, + { + "indexed": false, + "internalType": "string", + "name": "label", + "type": "string" + } + ], + "name": "WalletDeployed", + "type": "event" + }, + { + "inputs": [], + "name": "DEFAULT_ADMIN_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "OPERATOR_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "PAUSER_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "UPGRADE_INTERFACE_VERSION", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "acceptDefaultAdminTransfer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "beginDefaultAdminTransfer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "cancelDefaultAdminTransfer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint48", + "name": "newDelay", + "type": "uint48" + } + ], + "name": "changeDefaultAdminDelay", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "defaultAdmin", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "defaultAdminDelay", + "outputs": [ + { + "internalType": "uint48", + "name": "", + "type": "uint48" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "defaultAdminDelayIncreaseWait", + "outputs": [ + { + "internalType": "uint48", + "name": "", + "type": "uint48" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "label", + "type": "string" + } + ], + "name": "deployWallet", + "outputs": [ + { + "internalType": "address", + "name": "wallet", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "wallet", + "type": "address" + }, + { + "internalType": "address", + "name": "executor", + "type": "address" + }, + { + "internalType": "uint96", + "name": "index", + "type": "uint96" + }, + { + "internalType": "bytes32", + "name": "sessionHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "mode", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "execCalldataHash", + "type": "bytes32" + }, + { + "internalType": "uint192", + "name": "nonceKey", + "type": "uint192" + }, + { + "internalType": "uint64", + "name": "nonceSeq", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "grantNonce", + "type": "uint64" + }, + { + "internalType": "uint48", + "name": "deadline", + "type": "uint48" + }, + { + "internalType": "uint256", + "name": "signerChainId", + "type": "uint256" + } + ], + "internalType": "struct OwnerIntent", + "name": "intent", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "sig", + "type": "bytes" + }, + { + "internalType": "string", + "name": "label", + "type": "string" + } + ], + "name": "deployWalletWithSig", + "outputs": [ + { + "internalType": "address", + "name": "wallet", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "signerChainId", + "type": "uint256" + } + ], + "name": "domainSeparator", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + } + ], + "name": "getRoleAdmin", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "grantRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "hasRole", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "wallet", + "type": "address" + } + ], + "name": "indexOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "admin", + "type": "address" + }, + { + "internalType": "address", + "name": "walletImplementation_", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "isWallet", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "wallet", + "type": "address" + } + ], + "name": "ownerOf", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pendingDefaultAdmin", + "outputs": [ + { + "internalType": "address", + "name": "newAdmin", + "type": "address" + }, + { + "internalType": "uint48", + "name": "schedule", + "type": "uint48" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pendingDefaultAdminDelay", + "outputs": [ + { + "internalType": "uint48", + "name": "newDelay", + "type": "uint48" + }, + { + "internalType": "uint48", + "name": "schedule", + "type": "uint48" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "predictWallet", + "outputs": [ + { + "internalType": "address", + "name": "wallet", + "type": "address" + }, + { + "internalType": "bool", + "name": "deployed", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proxiableUUID", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "renounceRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "revokeRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "rollbackDefaultAdminDelay", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "unpause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "upgradeToAndCall", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "walletCount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "walletImplementation", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } +] diff --git a/packages/core/scripts/agw-local/abis/manifest.json b/packages/core/scripts/agw-local/abis/manifest.json new file mode 100644 index 00000000..7a3af5d2 --- /dev/null +++ b/packages/core/scripts/agw-local/abis/manifest.json @@ -0,0 +1,12 @@ +{ + "sourceRepository": "https://github.com/pushchain/push-agentic-wallets", + "sourceCommit": "e8db74815cfbbf5389593805e464fe8d85f7f735", + "deployedAbiEvidence": "AGW v4 Donut deployment; copied from the October 6 planning evidence snapshot", + "files": { + "engine.json": "32e7f3e48db6719306c436a0c81d80a2c5bcb3283b208ae043c460d483bc0180", + "factory.json": "c58ac31b81a64b4ab5b89c5aef3f6d01a405607395af71b5466d55fe9c1d5b99", + "policy.json": "b40e2a91eaa9c09cbe214621259fb7d12def00d12c756e2fd659eff4e26277c0", + "validator.json": "d2555b2f54d56ed24268af650b19ad10f2d34906b2e0c4ff78dd6de54ba34cc2", + "wallet.json": "ba68ef8f86e7154df29c4bb3ec9b90ae0d8a5193cad6e34772276475a2846ebe" + } +} diff --git a/packages/core/scripts/agw-local/abis/policy.json b/packages/core/scripts/agw-local/abis/policy.json new file mode 100644 index 00000000..c8f2f576 --- /dev/null +++ b/packages/core/scripts/agw-local/abis/policy.json @@ -0,0 +1,2157 @@ +[ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "length", + "type": "uint256" + } + ], + "name": "AllowListOutOfRange", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "outboundTxId", + "type": "bytes32" + } + ], + "name": "AlreadyCredited", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "ConfigId", + "name": "id", + "type": "bytes32" + } + ], + "name": "AlreadyInitialized", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "i", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "j", + "type": "uint256" + } + ], + "name": "AmbiguousRule", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "cap", + "type": "uint256" + } + ], + "name": "AmountExceedsCap", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "AmountExceedsU64", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "actual", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "expected", + "type": "bytes32" + } + ], + "name": "ArgPinMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "length", + "type": "uint256" + } + ], + "name": "AssetListOutOfRange", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "name": "AssetNotAllowed", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "expected", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "actual", + "type": "uint256" + } + ], + "name": "AssetSpentMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "count", + "type": "uint256" + } + ], + "name": "BatchSizeOutOfRange", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "expected", + "type": "address" + }, + { + "internalType": "address", + "name": "actual", + "type": "address" + } + ], + "name": "BeneficiaryMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint32", + "name": "callsUsed", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "maxCalls", + "type": "uint32" + } + ], + "name": "CallLimitReached", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "bytes4", + "name": "selector", + "type": "bytes4" + } + ], + "name": "CallNotAllowed", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "length", + "type": "uint256" + } + ], + "name": "CalldataTooShort", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "actualLength", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "needed", + "type": "uint256" + } + ], + "name": "CalldataTooShortForAmount", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "actualLength", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "needed", + "type": "uint256" + } + ], + "name": "CalldataTooShortForPin", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "CallerIsNotUEModule", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "accountIndex", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "account", + "type": "bytes32" + } + ], + "name": "CeaAccountAtUnpinnedIndex", + "type": "error" + }, + { + "inputs": [], + "name": "CeaAccountsMissExpectedCEA", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "declared", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "assetChain", + "type": "bytes32" + } + ], + "name": "ChainMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "rule", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "len", + "type": "uint8" + } + ], + "name": "DiscriminatorLenOutOfRange", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "name": "DuplicateAsset", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "first", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "second", + "type": "uint256" + } + ], + "name": "DuplicateSvmPin", + "type": "error" + }, + { + "inputs": [], + "name": "EmptyChain", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "target", + "type": "address" + } + ], + "name": "ForbiddenInnerTarget", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "rule", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "program", + "type": "bytes32" + } + ], + "name": "ForbiddenProgramInAllowList", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "program", + "type": "bytes32" + } + ], + "name": "ForbiddenTargetProgram", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxValue", + "type": "uint256" + } + ], + "name": "InnerValueExceedsAllowance", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "asset", + "type": "address" + } + ], + "name": "InvalidAsset", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "InvalidCeaAccount", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidConfigField", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint48", + "name": "validUntil", + "type": "uint48" + } + ], + "name": "InvalidExpiry", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidInitialization", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "expected", + "type": "address" + }, + { + "internalType": "address", + "name": "actual", + "type": "address" + } + ], + "name": "InvalidRevertRecipient", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "selector", + "type": "bytes4" + } + ], + "name": "InvalidSelector", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidSvmConfigField", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "target", + "type": "address" + } + ], + "name": "InvalidTarget", + "type": "error" + }, + { + "inputs": [], + "name": "MalformedInnerCalldata", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "length", + "type": "uint256" + } + ], + "name": "MalformedOutboundRequest", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint8", + "name": "code", + "type": "uint8" + } + ], + "name": "MalformedSvmPayload", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "cap", + "type": "uint256" + } + ], + "name": "NativeAmountExceedsCap", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "target", + "type": "address" + } + ], + "name": "NativeTargetIsGateway", + "type": "error" + }, + { + "inputs": [], + "name": "NativeTargetZero", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "ConfigId", + "name": "id", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "NotInitialized", + "type": "error" + }, + { + "inputs": [], + "name": "NotInitializing", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "cap", + "type": "uint256" + } + ], + "name": "PCValueExceedsCap", + "type": "error" + }, + { + "inputs": [], + "name": "PayloadNotMulticall", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "ConfigId", + "name": "id", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "multiplexer", + "type": "address" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "PolicyNotInitialized", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "length", + "type": "uint256" + } + ], + "name": "ProgramListOutOfRange", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "program", + "type": "bytes32" + }, + { + "internalType": "bytes8", + "name": "discriminator", + "type": "bytes8" + } + ], + "name": "ProgramNotAllowed", + "type": "error" + }, + { + "inputs": [], + "name": "RecipientMustBeEmpty", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "length", + "type": "uint256" + } + ], + "name": "RecipientNotPubkey", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "recipient", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "target", + "type": "bytes32" + } + ], + "name": "RecipientTargetMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "rule", + "type": "uint256" + } + ], + "name": "RuleWithoutPin", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint48", + "name": "validUntil", + "type": "uint48" + } + ], + "name": "RulesExpired", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "actual", + "type": "bytes4" + }, + { + "internalType": "bytes4", + "name": "expected", + "type": "bytes4" + } + ], + "name": "SelectorMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "expected", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "actual", + "type": "uint256" + } + ], + "name": "SpentLengthMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "expected", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "actual", + "type": "uint256" + } + ], + "name": "SpentMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "pin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "count", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "needed", + "type": "uint8" + } + ], + "name": "SvmAccountCountBelowPin", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "count", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "expected", + "type": "uint8" + } + ], + "name": "SvmAccountCountMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "pin", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "accountIndex", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "expected", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "actual", + "type": "bytes32" + } + ], + "name": "SvmAccountPinMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "count", + "type": "uint256" + } + ], + "name": "SvmAccountsOutOfRange", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "pin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "actual", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "ceiling", + "type": "uint256" + } + ], + "name": "SvmDataCeilingExceeded", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "pin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "actual", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "floor", + "type": "uint256" + } + ], + "name": "SvmDataFloorNotMet", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "pin", + "type": "uint256" + } + ], + "name": "SvmDataPinInvalid", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "pin", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "expected", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "actual", + "type": "bytes32" + } + ], + "name": "SvmDataPinMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "pin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "a", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "b", + "type": "uint256" + }, + { + "internalType": "uint64", + "name": "num", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "den", + "type": "uint64" + } + ], + "name": "SvmDataRatioNotMet", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "pin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "ixLen", + "type": "uint256" + } + ], + "name": "SvmDataTooShortForPin", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint8", + "name": "instructionId", + "type": "uint8" + } + ], + "name": "SvmInstructionNotExecute", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "length", + "type": "uint256" + } + ], + "name": "SvmIxDataTooLong", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "rule", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "maxAccounts", + "type": "uint8" + } + ], + "name": "SvmMaxAccountsOutOfRange", + "type": "error" + }, + { + "inputs": [], + "name": "SvmPayloadEmpty", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "pin", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "accountIndex", + "type": "uint8" + } + ], + "name": "SvmPinIndexOutOfRange", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "pin", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "rule", + "type": "uint8" + } + ], + "name": "SvmPinRuleOutOfRange", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "actual", + "type": "address" + }, + { + "internalType": "address", + "name": "expected", + "type": "address" + } + ], + "name": "TargetMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "count", + "type": "uint256" + } + ], + "name": "TooManyCeaAccounts", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "count", + "type": "uint256" + } + ], + "name": "TooManyPins", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "count", + "type": "uint256" + } + ], + "name": "TooManySvmDataPins", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "count", + "type": "uint256" + } + ], + "name": "TooManySvmPins", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newSpent", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "cap", + "type": "uint256" + } + ], + "name": "TotalNativeAmountExceeded", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "wouldBeTotal", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "cap", + "type": "uint256" + } + ], + "name": "TotalSpendCapExceeded", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newSpent", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "cap", + "type": "uint256" + } + ], + "name": "TotalValueExceeded", + "type": "error" + }, + { + "inputs": [], + "name": "UncappedGasSwapRejected", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "version", + "type": "uint256" + } + ], + "name": "UnsupportedEnvelopeVersion", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "chainHash", + "type": "bytes32" + } + ], + "name": "UnsupportedNamespace", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "cap", + "type": "uint256" + } + ], + "name": "ValueExceedsCap", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "length", + "type": "uint256" + } + ], + "name": "ValueOnlyCalldataNotEmpty", + "type": "error" + }, + { + "inputs": [], + "name": "ValueOnlyWithAmountRule", + "type": "error" + }, + { + "inputs": [], + "name": "ValueOnlyWithPins", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "enum RulesType", + "name": "actual", + "type": "uint8" + } + ], + "name": "WrongModeForCall", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "enum VmFamily", + "name": "actual", + "type": "uint8" + } + ], + "name": "WrongVmForCall", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroAddress", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint64", + "name": "version", + "type": "uint64" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "ConfigId", + "name": "id", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "multiplexer", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "NativeCallMetered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "ConfigId", + "name": "id", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "multiplexer", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "OutboundMetered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "ConfigId", + "name": "id", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "address", + "name": "multiplexer", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "PolicySet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "outboundTxId", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "ConfigId", + "name": "id", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amountApplied", + "type": "uint256" + } + ], + "name": "RevertCredited", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "ConfigId", + "name": "id", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "multiplexer", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "enum RulesType", + "name": "mode", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "enum VmFamily", + "name": "vm", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "chainHash", + "type": "bytes32" + } + ], + "name": "RulesConfigured", + "type": "event" + }, + { + "inputs": [], + "name": "SEND_OUTBOUND_SELECTOR", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "SESSION_ENGINE", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "UNIVERSAL_EXECUTOR_MODULE", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "UNIVERSAL_GATEWAY_PC", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "ConfigId", + "name": "id", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "expectedValueSpent", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expectedAmountSpent", + "type": "uint256" + }, + { + "internalType": "uint32", + "name": "expectedCalls", + "type": "uint32" + } + ], + "name": "assertSpent", + "outputs": [], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "ConfigId", + "name": "id", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256[]", + "name": "expectedSpent", + "type": "uint256[]" + } + ], + "name": "assertSpent", + "outputs": [], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "ConfigId", + "name": "id", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "checkAction", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "ConfigId", + "name": "id", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "outboundTxId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "creditRevert", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "ConfigId", + "name": "id", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "getConfig", + "outputs": [ + { + "components": [ + { + "internalType": "bool", + "name": "initialized", + "type": "bool" + }, + { + "internalType": "uint48", + "name": "validUntil", + "type": "uint48" + }, + { + "internalType": "address", + "name": "expectedCEA", + "type": "address" + }, + { + "internalType": "uint256", + "name": "maxGasPerCall", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "maxPerCall", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxTotal", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "spent", + "type": "uint256" + } + ], + "internalType": "struct AssetCapState[]", + "name": "assets", + "type": "tuple[]" + }, + { + "components": [ + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "bytes4", + "name": "selector", + "type": "bytes4" + }, + { + "internalType": "uint16", + "name": "beneficiaryOffset", + "type": "uint16" + }, + { + "internalType": "bool", + "name": "hasBeneficiary", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "maxValue", + "type": "uint256" + } + ], + "internalType": "struct AllowedCall[]", + "name": "allowedCalls", + "type": "tuple[]" + } + ], + "internalType": "struct Config", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "ConfigId", + "name": "id", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "getMode", + "outputs": [ + { + "components": [ + { + "internalType": "bool", + "name": "initialized", + "type": "bool" + }, + { + "internalType": "enum RulesType", + "name": "mode", + "type": "uint8" + }, + { + "internalType": "enum VmFamily", + "name": "vm", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "chainHash", + "type": "bytes32" + } + ], + "internalType": "struct ModeSlot", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "ConfigId", + "name": "id", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "getNativeConfig", + "outputs": [ + { + "components": [ + { + "internalType": "bool", + "name": "initialized", + "type": "bool" + }, + { + "internalType": "uint48", + "name": "validUntil", + "type": "uint48" + }, + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "bytes4", + "name": "selector", + "type": "bytes4" + }, + { + "internalType": "uint256", + "name": "maxValuePerCall", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxValueTotal", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "valueSpent", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "bool", + "name": "enabled", + "type": "bool" + }, + { + "internalType": "uint16", + "name": "offset", + "type": "uint16" + }, + { + "internalType": "uint256", + "name": "maxPerCall", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxTotal", + "type": "uint256" + } + ], + "internalType": "struct AmountRule", + "name": "amount", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "amountSpent", + "type": "uint256" + }, + { + "internalType": "uint32", + "name": "maxCalls", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "callsUsed", + "type": "uint32" + }, + { + "components": [ + { + "internalType": "uint16", + "name": "offset", + "type": "uint16" + }, + { + "internalType": "bytes32", + "name": "expected", + "type": "bytes32" + } + ], + "internalType": "struct ArgPin[]", + "name": "pins", + "type": "tuple[]" + } + ], + "internalType": "struct NativeConfig", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "ConfigId", + "name": "id", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "getSvmConfig", + "outputs": [ + { + "components": [ + { + "internalType": "bool", + "name": "initialized", + "type": "bool" + }, + { + "internalType": "uint48", + "name": "validUntil", + "type": "uint48" + }, + { + "internalType": "bytes32", + "name": "expectedCEA", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "gatewayProgram", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "maxGasPerCall", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "maxPerCall", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxTotal", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "spent", + "type": "uint256" + } + ], + "internalType": "struct AssetCapState[]", + "name": "assets", + "type": "tuple[]" + }, + { + "internalType": "bytes32[]", + "name": "ceaAccounts", + "type": "bytes32[]" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "program", + "type": "bytes32" + }, + { + "internalType": "bytes8", + "name": "discriminator", + "type": "bytes8" + }, + { + "internalType": "uint8", + "name": "discriminatorLen", + "type": "uint8" + }, + { + "internalType": "bool", + "name": "dataless", + "type": "bool" + }, + { + "internalType": "uint8", + "name": "maxAccounts", + "type": "uint8" + } + ], + "internalType": "struct AllowedProgram[]", + "name": "programs", + "type": "tuple[]" + }, + { + "components": [ + { + "internalType": "uint8", + "name": "ruleIndex", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "accountIndex", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "expected", + "type": "bytes32" + } + ], + "internalType": "struct SvmAccountPin[]", + "name": "pins", + "type": "tuple[]" + }, + { + "components": [ + { + "internalType": "uint8", + "name": "ruleIndex", + "type": "uint8" + }, + { + "internalType": "bool", + "name": "fromEnd", + "type": "bool" + }, + { + "internalType": "uint16", + "name": "offset", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "offsetB", + "type": "uint16" + }, + { + "internalType": "uint8", + "name": "len", + "type": "uint8" + }, + { + "internalType": "enum SvmDataPinMode", + "name": "mode", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "expected", + "type": "bytes32" + }, + { + "internalType": "uint64", + "name": "num", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "den", + "type": "uint64" + } + ], + "internalType": "struct SvmDataPin[]", + "name": "dataPins", + "type": "tuple[]" + } + ], + "internalType": "struct SvmConfig", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "universalGatewayPC", + "type": "address" + }, + { + "internalType": "address", + "name": "universalExecutorModule", + "type": "address" + }, + { + "internalType": "address", + "name": "sessionEngine", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "ConfigId", + "name": "configId", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "name": "initializeWithMultiplexer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "outboundTxId", + "type": "bytes32" + } + ], + "name": "isCredited", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pushChainHash", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "iid", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "version", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "pure", + "type": "function" + } +] diff --git a/packages/core/scripts/agw-local/abis/validator.json b/packages/core/scripts/agw-local/abis/validator.json new file mode 100644 index 00000000..d043841a --- /dev/null +++ b/packages/core/scripts/agw-local/abis/validator.json @@ -0,0 +1,141 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "smartAccount", + "type": "address" + } + ], + "name": "AlreadyInitialized", + "type": "error" + }, + { + "inputs": [], + "name": "MalformedConfig", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "smartAccount", + "type": "address" + } + ], + "name": "NotInitialized", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "isInitialized", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "moduleTypeId", + "type": "uint256" + } + ], + "name": "isModuleType", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "name": "onInstall", + "outputs": [], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "name": "onUninstall", + "outputs": [], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "validateConfig", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "sig", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "validateSignatureWithData", + "outputs": [ + { + "internalType": "bool", + "name": "validSig", + "type": "bool" + } + ], + "stateMutability": "pure", + "type": "function" + } +] diff --git a/packages/core/scripts/agw-local/abis/wallet.json b/packages/core/scripts/agw-local/abis/wallet.json new file mode 100644 index 00000000..4f12c4b4 --- /dev/null +++ b/packages/core/scripts/agw-local/abis/wallet.json @@ -0,0 +1,1550 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "sessionEngine_", + "type": "address" + }, + { + "internalType": "address", + "name": "rulesPolicy_", + "type": "address" + }, + { + "internalType": "address", + "name": "sessionValidator_", + "type": "address" + }, + { + "internalType": "address", + "name": "universalGatewayPC_", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "AlreadyInitialized", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "rulesId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "CallerIsNotAgent", + "type": "error" + }, + { + "inputs": [], + "name": "CallerIsNotFactory", + "type": "error" + }, + { + "inputs": [], + "name": "CallerIsNotOwner", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "bytes4", + "name": "selector", + "type": "bytes4" + } + ], + "name": "DuplicateAction", + "type": "error" + }, + { + "inputs": [], + "name": "EmptyChain", + "type": "error" + }, + { + "inputs": [], + "name": "EngineStillHoldsPermissions", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "expected", + "type": "address" + }, + { + "internalType": "address", + "name": "actual", + "type": "address" + } + ], + "name": "ExecutorMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "selector", + "type": "bytes4" + } + ], + "name": "ForbiddenActionSelector", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "target", + "type": "address" + } + ], + "name": "ForbiddenActionTarget", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "target", + "type": "address" + } + ], + "name": "ForbiddenDispatchTarget", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "actionIndex", + "type": "uint256" + } + ], + "name": "InconsistentChain", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "actualCalldataHash", + "type": "bytes32" + } + ], + "name": "IntentExecMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint64", + "name": "expected", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "provided", + "type": "uint64" + } + ], + "name": "IntentGrantNonceMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "actual", + "type": "bytes32" + } + ], + "name": "IntentSessionMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "expected", + "type": "address" + }, + { + "internalType": "address", + "name": "provided", + "type": "address" + } + ], + "name": "IntentWalletMismatch", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidModuleAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint192", + "name": "nonceKey", + "type": "uint192" + }, + { + "internalType": "uint64", + "name": "expected", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "provided", + "type": "uint64" + } + ], + "name": "InvalidNonce", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidOwnerSignature", + "type": "error" + }, + { + "inputs": [], + "name": "MalformedBatchCalldata", + "type": "error" + }, + { + "inputs": [], + "name": "MalformedSessionShape", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "module", + "type": "address" + } + ], + "name": "ModuleAlreadyInstalled", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint48", + "name": "validAfter", + "type": "uint48" + }, + { + "internalType": "uint48", + "name": "validUntil", + "type": "uint48" + } + ], + "name": "OutsideTimeWindow", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint192", + "name": "nonceKey", + "type": "uint192" + } + ], + "name": "OwnerLaneRequired", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint48", + "name": "deadline", + "type": "uint48" + } + ], + "name": "OwnerSigExpired", + "type": "error" + }, + { + "inputs": [], + "name": "ReentrancyGuardReentrantCall", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "enum RulesType", + "name": "derived", + "type": "uint8" + }, + { + "internalType": "uint256", + "name": "actionIndex", + "type": "uint256" + }, + { + "internalType": "address", + "name": "target", + "type": "address" + } + ], + "name": "RulesTypeMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "count", + "type": "uint256" + } + ], + "name": "TooManyActions", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "rulesId", + "type": "bytes32" + } + ], + "name": "UnknownPermission", + "type": "error" + }, + { + "inputs": [], + "name": "UnsupportedExecutionMode", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "moduleTypeId", + "type": "uint256" + } + ], + "name": "UnsupportedModuleType", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "authorizer", + "type": "address" + } + ], + "name": "ValidationFailed", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "validator", + "type": "address" + } + ], + "name": "ValidatorNotInstalled", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "engine", + "type": "address" + } + ], + "name": "AccountInitialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint64", + "name": "seq", + "type": "uint64" + }, + { + "indexed": false, + "internalType": "enum CheckpointKind", + "name": "kind", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "ref", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "uint64", + "name": "blockNumber", + "type": "uint64" + } + ], + "name": "Checkpointed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "moduleTypeId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "module", + "type": "address" + } + ], + "name": "ModuleInstalled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "moduleTypeId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "module", + "type": "address" + } + ], + "name": "ModuleUninstalled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "mode", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "executionCalldataHash", + "type": "bytes32" + } + ], + "name": "OwnerExecuted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "mode", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "executionCalldataHash", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "uint192", + "name": "nonceKey", + "type": "uint192" + }, + { + "indexed": false, + "internalType": "uint64", + "name": "nonceSeq", + "type": "uint64" + } + ], + "name": "OwnerExecutedWithSig", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "rulesId", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "agent", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "callsHash", + "type": "bytes32" + } + ], + "name": "RulesActionAuthorized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "rulesId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "enum RulesType", + "name": "mode", + "type": "uint8" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "chainHash", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "string", + "name": "chainNamespace", + "type": "string" + } + ], + "name": "RulesGranted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "rulesId", + "type": "bytes32" + } + ], + "name": "RulesRevoked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "module", + "type": "address" + } + ], + "name": "UninstallCallbackFailed", + "type": "event" + }, + { + "inputs": [], + "name": "RULES_POLICY", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "SESSION_ENGINE", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "SESSION_VALIDATOR", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "UNIVERSAL_GATEWAY_PC", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "accountId", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "rulesId", + "type": "bytes32" + } + ], + "name": "agentOf", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "checkpointCount", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "signerChainId", + "type": "uint256" + } + ], + "name": "domainSeparator", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "mode", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "executionCalldata", + "type": "bytes" + } + ], + "name": "execute", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "rulesId", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "mode", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "executionCalldata", + "type": "bytes" + } + ], + "name": "executeAsAgent", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "mode", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "executionCalldata", + "type": "bytes" + }, + { + "components": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "wallet", + "type": "address" + }, + { + "internalType": "address", + "name": "executor", + "type": "address" + }, + { + "internalType": "uint96", + "name": "index", + "type": "uint96" + }, + { + "internalType": "bytes32", + "name": "sessionHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "mode", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "execCalldataHash", + "type": "bytes32" + }, + { + "internalType": "uint192", + "name": "nonceKey", + "type": "uint192" + }, + { + "internalType": "uint64", + "name": "nonceSeq", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "grantNonce", + "type": "uint64" + }, + { + "internalType": "uint48", + "name": "deadline", + "type": "uint48" + }, + { + "internalType": "uint256", + "name": "signerChainId", + "type": "uint256" + } + ], + "internalType": "struct OwnerIntent", + "name": "intent", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "sig", + "type": "bytes" + } + ], + "name": "executeWithSig", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "factory", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint192", + "name": "nonceKey", + "type": "uint192" + } + ], + "name": "getNonce", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "grantNonce", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "contract ISessionValidator", + "name": "sessionValidator", + "type": "address" + }, + { + "internalType": "bytes", + "name": "sessionValidatorInitData", + "type": "bytes" + }, + { + "internalType": "bytes32", + "name": "salt", + "type": "bytes32" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "userOpPolicies", + "type": "tuple[]" + }, + { + "components": [ + { + "components": [ + { + "internalType": "bytes32", + "name": "appDomainSeparator", + "type": "bytes32" + }, + { + "internalType": "string[]", + "name": "contentNames", + "type": "string[]" + } + ], + "internalType": "struct ERC7739Context[]", + "name": "allowedERC7739Content", + "type": "tuple[]" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "erc1271Policies", + "type": "tuple[]" + } + ], + "internalType": "struct ERC7739Data", + "name": "erc7739Policies", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "bytes4", + "name": "actionTargetSelector", + "type": "bytes4" + }, + { + "internalType": "address", + "name": "actionTarget", + "type": "address" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "actionPolicies", + "type": "tuple[]" + } + ], + "internalType": "struct ActionData[]", + "name": "actions", + "type": "tuple[]" + }, + { + "internalType": "bool", + "name": "permitERC4337Paymaster", + "type": "bool" + } + ], + "internalType": "struct Session", + "name": "session", + "type": "tuple" + } + ], + "name": "grantRules", + "outputs": [ + { + "internalType": "bytes32", + "name": "rulesId", + "type": "bytes32" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "contract ISessionValidator", + "name": "sessionValidator", + "type": "address" + }, + { + "internalType": "bytes", + "name": "sessionValidatorInitData", + "type": "bytes" + }, + { + "internalType": "bytes32", + "name": "salt", + "type": "bytes32" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "userOpPolicies", + "type": "tuple[]" + }, + { + "components": [ + { + "components": [ + { + "internalType": "bytes32", + "name": "appDomainSeparator", + "type": "bytes32" + }, + { + "internalType": "string[]", + "name": "contentNames", + "type": "string[]" + } + ], + "internalType": "struct ERC7739Context[]", + "name": "allowedERC7739Content", + "type": "tuple[]" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "erc1271Policies", + "type": "tuple[]" + } + ], + "internalType": "struct ERC7739Data", + "name": "erc7739Policies", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "bytes4", + "name": "actionTargetSelector", + "type": "bytes4" + }, + { + "internalType": "address", + "name": "actionTarget", + "type": "address" + }, + { + "components": [ + { + "internalType": "address", + "name": "policy", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "internalType": "struct PolicyData[]", + "name": "actionPolicies", + "type": "tuple[]" + } + ], + "internalType": "struct ActionData[]", + "name": "actions", + "type": "tuple[]" + }, + { + "internalType": "bool", + "name": "permitERC4337Paymaster", + "type": "bool" + } + ], + "internalType": "struct Session", + "name": "session", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "wallet", + "type": "address" + }, + { + "internalType": "address", + "name": "executor", + "type": "address" + }, + { + "internalType": "uint96", + "name": "index", + "type": "uint96" + }, + { + "internalType": "bytes32", + "name": "sessionHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "mode", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "execCalldataHash", + "type": "bytes32" + }, + { + "internalType": "uint192", + "name": "nonceKey", + "type": "uint192" + }, + { + "internalType": "uint64", + "name": "nonceSeq", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "grantNonce", + "type": "uint64" + }, + { + "internalType": "uint48", + "name": "deadline", + "type": "uint48" + }, + { + "internalType": "uint256", + "name": "signerChainId", + "type": "uint256" + } + ], + "internalType": "struct OwnerIntent", + "name": "intent", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "sig", + "type": "bytes" + } + ], + "name": "grantRulesWithSig", + "outputs": [ + { + "internalType": "bytes32", + "name": "rulesId", + "type": "bytes32" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "initializeAccount", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "moduleTypeId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "module", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initData", + "type": "bytes" + } + ], + "name": "installModule", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "moduleTypeId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "module", + "type": "address" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "name": "isModuleInstalled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "name": "isValidSignature", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "lastCheckpointBlock", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "name": "onERC1155BatchReceived", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "name": "onERC1155Received", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "name": "onERC721Received", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "revokeAllRules", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "rulesId", + "type": "bytes32" + } + ], + "name": "revokeRules", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "mode", + "type": "bytes32" + } + ], + "name": "supportsExecutionMode", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "moduleTypeId", + "type": "uint256" + } + ], + "name": "supportsModule", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "moduleTypeId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "module", + "type": "address" + }, + { + "internalType": "bytes", + "name": "deInitData", + "type": "bytes" + } + ], + "name": "uninstallModule", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } +] diff --git a/packages/core/scripts/agw-local/gen-abi.mjs b/packages/core/scripts/agw-local/gen-abi.mjs index f663e3c7..829c7e45 100644 --- a/packages/core/scripts/agw-local/gen-abi.mjs +++ b/packages/core/scripts/agw-local/gen-abi.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env node // Regenerates packages/core/src/lib/agentic/contracts/abi/v4/*.ts from the -// pinned ABI evidence in plan/agw/research/deployment-review-2026-10-06/abis/. The source -// JSON is the reviewed artifact set; this script only re-serialises it as +// pinned ABI snapshots in ./abis/. The JSON files are the source artifact set; +// this script only re-serialises them as // `as const` TypeScript so viem can infer types. Run from the repo root: // node packages/core/scripts/agw-local/gen-abi.mjs import { createHash } from 'node:crypto'; @@ -11,7 +11,7 @@ import { fileURLToPath } from 'node:url'; const here = dirname(fileURLToPath(import.meta.url)); const repo = resolve(here, '../../../..'); -const src = join(repo, 'plan/agw/research/deployment-review-2026-10-06/abis'); +const src = join(here, 'abis'); const dst = join(repo, 'packages/core/src/lib/agentic/contracts/abi/v4'); const PIN = 'e8db74815cfbbf5389593805e464fe8d85f7f735'; @@ -32,18 +32,23 @@ const files = { SmartSession: ['SMART_SESSION_ABI', 'smart-session.ts'], AgentValidator: ['AGENT_VALIDATOR_ABI', 'agent-validator.ts'], }; +const manifest = JSON.parse(readFileSync(join(src, 'manifest.json'), 'utf8')); mkdirSync(dst, { recursive: true }); const exports = []; for (const [name, [constName, file]] of Object.entries(files)) { - const raw = readFileSync(join(src, `${sourceNames[name]}.json`)); + const sourceFile = `${sourceNames[name]}.json`; + const raw = readFileSync(join(src, sourceFile)); const sha = createHash('sha256').update(raw).digest('hex'); + if (sha !== manifest.files[sourceFile]) { + throw new Error(`ABI source hash mismatch: ${sourceFile}`); + } const abi = JSON.parse(raw.toString()).filter( (e) => e.type !== 'constructor' ); const body = `// GENERATED by packages/core/scripts/agw-local/gen-abi.mjs — do not edit.\n` + - `// Source: plan/agw/research/deployment-review-2026-10-06/abis/${name}.json\n` + + `// Source: packages/core/scripts/agw-local/abis/${sourceFile}\n` + `// push-agentic-wallets@${PIN}\n` + `// sha256(${name}.json) = ${sha}\n` + `export const ${constName} = ${JSON.stringify(abi, null, 2)} as const;\n`; diff --git a/packages/core/src/lib/agentic/agentic.types.ts b/packages/core/src/lib/agentic/agentic.types.ts index c4c6a34d..07b07580 100644 --- a/packages/core/src/lib/agentic/agentic.types.ts +++ b/packages/core/src/lib/agentic/agentic.types.ts @@ -1,8 +1,8 @@ /** * Public AGW types — AGW SDK page section 3 (Notion export 2026-10-03 13:23 IST). * - * Provisional items are tagged with the plan assumption that must close before - * they are final (plan/agw/implementation-plan.md, A01–A08). + * Provisional public choices are documented on the affected properties and + * remain subject to product and contract confirmation. */ import type { MoveableToken } from '../constants/tokens'; import type { UniversalTxResponse } from '../orchestrator/orchestrator.types'; diff --git a/packages/core/src/lib/agentic/capabilities.ts b/packages/core/src/lib/agentic/capabilities.ts index f8564176..0aa78796 100644 --- a/packages/core/src/lib/agentic/capabilities.ts +++ b/packages/core/src/lib/agentic/capabilities.ts @@ -3,8 +3,8 @@ import { capabilityUnavailable } from './errors'; /** * Internal capability flags for an AGW contract generation. A method whose * capability is absent fails before any signature. Each unresolved target - * feature names the plan assumption (A01–A08, plan/agw/implementation-plan.md) - * or artifact that must close before it can be advertised. + * feature identifies the contract or product capability that must be verified + * before it can be advertised. */ export enum AgenticCapability { /** Factory derive/list/deploy and wallet owner/info reads. */ diff --git a/packages/core/src/lib/agentic/codec/defaults.ts b/packages/core/src/lib/agentic/codec/defaults.ts index aa915230..27cee24b 100644 --- a/packages/core/src/lib/agentic/codec/defaults.ts +++ b/packages/core/src/lib/agentic/codec/defaults.ts @@ -1,6 +1,6 @@ /** - * THE single home for omitted-limit defaults. PROVISIONAL — assumption A03 - * (Harsh H3, plan/agw/questions-harsh.md). Nothing else in the SDK may invent + * THE single home for omitted-limit defaults. Native defaults remain + * provisional pending product confirmation. Nothing else in the SDK may invent * a fallback for these fields; change a row here once the decision lands. * * Explicit zero always stays zero. In the native policy a zero value/amount diff --git a/packages/core/src/lib/agentic/contracts/abi/v4/agent-validator.ts b/packages/core/src/lib/agentic/contracts/abi/v4/agent-validator.ts index 56db7e9c..d5924e33 100644 --- a/packages/core/src/lib/agentic/contracts/abi/v4/agent-validator.ts +++ b/packages/core/src/lib/agentic/contracts/abi/v4/agent-validator.ts @@ -1,5 +1,5 @@ // GENERATED by packages/core/scripts/agw-local/gen-abi.mjs — do not edit. -// Source: plan/agw/research/deployment-review-2026-10-06/abis/AgentValidator.json +// Source: packages/core/scripts/agw-local/abis/validator.json // push-agentic-wallets@e8db74815cfbbf5389593805e464fe8d85f7f735 // sha256(AgentValidator.json) = d2555b2f54d56ed24268af650b19ad10f2d34906b2e0c4ff78dd6de54ba34cc2 export const AGENT_VALIDATOR_ABI = [ diff --git a/packages/core/src/lib/agentic/contracts/abi/v4/agw-factory.ts b/packages/core/src/lib/agentic/contracts/abi/v4/agw-factory.ts index 38da9c0b..c355b370 100644 --- a/packages/core/src/lib/agentic/contracts/abi/v4/agw-factory.ts +++ b/packages/core/src/lib/agentic/contracts/abi/v4/agw-factory.ts @@ -1,5 +1,5 @@ // GENERATED by packages/core/scripts/agw-local/gen-abi.mjs — do not edit. -// Source: plan/agw/research/deployment-review-2026-10-06/abis/AGWFactory.json +// Source: packages/core/scripts/agw-local/abis/factory.json // push-agentic-wallets@e8db74815cfbbf5389593805e464fe8d85f7f735 // sha256(AGWFactory.json) = c58ac31b81a64b4ab5b89c5aef3f6d01a405607395af71b5466d55fe9c1d5b99 export const AGW_FACTORY_ABI = [ diff --git a/packages/core/src/lib/agentic/contracts/abi/v4/agw.ts b/packages/core/src/lib/agentic/contracts/abi/v4/agw.ts index 3407d5ad..37c654c3 100644 --- a/packages/core/src/lib/agentic/contracts/abi/v4/agw.ts +++ b/packages/core/src/lib/agentic/contracts/abi/v4/agw.ts @@ -1,5 +1,5 @@ // GENERATED by packages/core/scripts/agw-local/gen-abi.mjs — do not edit. -// Source: plan/agw/research/deployment-review-2026-10-06/abis/AGW.json +// Source: packages/core/scripts/agw-local/abis/wallet.json // push-agentic-wallets@e8db74815cfbbf5389593805e464fe8d85f7f735 // sha256(AGW.json) = ba68ef8f86e7154df29c4bb3ec9b90ae0d8a5193cad6e34772276475a2846ebe export const AGW_ABI = [ diff --git a/packages/core/src/lib/agentic/contracts/abi/v4/smart-session.ts b/packages/core/src/lib/agentic/contracts/abi/v4/smart-session.ts index e1efc670..faf9d38e 100644 --- a/packages/core/src/lib/agentic/contracts/abi/v4/smart-session.ts +++ b/packages/core/src/lib/agentic/contracts/abi/v4/smart-session.ts @@ -1,5 +1,5 @@ // GENERATED by packages/core/scripts/agw-local/gen-abi.mjs — do not edit. -// Source: plan/agw/research/deployment-review-2026-10-06/abis/SmartSession.json +// Source: packages/core/scripts/agw-local/abis/engine.json // push-agentic-wallets@e8db74815cfbbf5389593805e464fe8d85f7f735 // sha256(SmartSession.json) = 32e7f3e48db6719306c436a0c81d80a2c5bcb3283b208ae043c460d483bc0180 export const SMART_SESSION_ABI = [ diff --git a/packages/core/src/lib/agentic/contracts/abi/v4/universal-rules-policy.ts b/packages/core/src/lib/agentic/contracts/abi/v4/universal-rules-policy.ts index 1ffd395a..0c9d783c 100644 --- a/packages/core/src/lib/agentic/contracts/abi/v4/universal-rules-policy.ts +++ b/packages/core/src/lib/agentic/contracts/abi/v4/universal-rules-policy.ts @@ -1,5 +1,5 @@ // GENERATED by packages/core/scripts/agw-local/gen-abi.mjs — do not edit. -// Source: plan/agw/research/deployment-review-2026-10-06/abis/UniversalRulesPolicy.json +// Source: packages/core/scripts/agw-local/abis/policy.json // push-agentic-wallets@e8db74815cfbbf5389593805e464fe8d85f7f735 // sha256(UniversalRulesPolicy.json) = b40e2a91eaa9c09cbe214621259fb7d12def00d12c756e2fd659eff4e26277c0 export const UNIVERSAL_RULES_POLICY_ABI = [ diff --git a/plan/agw/README.md b/plan/agw/README.md index 33f5fd8f..282fa4db 100644 --- a/plan/agw/README.md +++ b/plan/agw/README.md @@ -2,7 +2,7 @@ This package contains the SDK implementation plan, source snapshots, open decisions and validation evidence. Current work is on feat/agw-sdk-v4. Runtime commits are a66ff7d (v4/SVM foundations) and b68bab7 (gas headroom); current validation is linked below. Native/EVM support now uses the checked Donut v4 deployment; old runtime adapters/ABIs/fixtures were removed. All 25 registered AGW scenarios have passing bounded live coverage, including native/UEA identities and Sepolia outbound success/failure. -Latest E2E expansion: [extended AGW live coverage](research/extended-e2e-2026-10-06/README.md) adds 14 opt-in funded scenarios. All 14 pass; the wallet-index race caught and fixed an SDK error-classification gap. The default E2E selection remains unchanged. +Latest E2E expansion: [extended AGW live coverage](research/extended-e2e-2026-10-06/README.md) adds 14 funded scenarios to the existing opt-in `agw` group. All 14 pass; the wallet-index race caught and fixed an SDK error-classification gap. The default E2E selection remains unchanged. Latest: [live acceptance and fixes](research/live-acceptance-2026-10-06/README.md), following the [v4 migration](research/v4-implementation-2026-10-06/README.md). The unrestricted full core unit run passes 1,982 tests; the actual-contract harness passes 75. Build and four typechecks pass. Native defaults/raw-offset API/multi-rule selection decisions, absent ref/labels, public SVM integration and release scope remain explicit. diff --git a/plan/agw/current-baseline.md b/plan/agw/current-baseline.md index bb28e7ab..39192803 100644 --- a/plan/agw/current-baseline.md +++ b/plan/agw/current-baseline.md @@ -1,6 +1,6 @@ # Current validated AGW baseline -Updated October 6, 2026 after the v4 deployment notice, source/ABI inspection, read-only Donut probe and extended E2E run. **The v4 deployment and native/EVM SDK adapter/codecs are integrated locally. The 25 standard AGW scenarios and 14 new opt-in extended scenarios have passing live coverage.** [Extended E2E evidence](research/extended-e2e-2026-10-06/README.md); [full deployment review](research/deployment-review-2026-10-06/README.md). +Updated October 6, 2026 after the v4 deployment notice, source/ABI inspection, read-only Donut probe and extended E2E run. **The v4 deployment and native/EVM SDK adapter/codecs are integrated locally. The 25 previously registered AGW scenarios and 14 added management/policy scenarios are all part of the opt-in `agw` group and have passing selected-run live coverage.** [Extended E2E evidence](research/extended-e2e-2026-10-06/README.md); [full deployment review](research/deployment-review-2026-10-06/README.md). The public SDK target remains Notion page 5, qualified by Harsh's later replies/comments. The new owner guide establishes deployed wire behavior; mismatches in public ref/labels/defaults/selection remain explicit. [Prior October 3–5 baseline](research/deployment-review-2026-10-06/previous-current-baseline.md) is retained as historical evidence. @@ -61,7 +61,7 @@ The ABI comparison found matching factory/wallet/engine function/event/error sig Four checks passed: version-1 envelope round-trip/old first-word incompatibility; synthetic ordered two-asset tuple round-trip; live v4 getConfig decode with old-ABI rejection; array assertion encoding. [Results and limits](research/deployment-review-2026-10-06/wire-checks.json). This is not a rule-grant, stale-spend transaction or funded E2E proof. -The unrestricted run passes 1,982 unit and 75 actual-contract tests. All five explorer ABI sets match the isolated build. Donut is registered and all 25 standard AGW native/EVM/identity cases plus 14 extended management/native-policy cases have passing live coverage. The extended suite remains opt-in; default `all` remains 76 scenarios. [Extended E2E evidence](research/extended-e2e-2026-10-06/README.md); [prior acceptance evidence](research/live-acceptance-2026-10-06/README.md). +The unrestricted run passes 1,982 unit and 75 actual-contract tests. All five explorer ABI sets match the isolated build. Donut is registered and all 39 AGW native/EVM/identity/management/policy cases have passing selected-run live coverage. The `agw` group remains opt-in; default `all` remains 76 scenarios. [Extended E2E evidence](research/extended-e2e-2026-10-06/README.md); [prior acceptance evidence](research/live-acceptance-2026-10-06/README.md). ## Remaining decisions and acceptance diff --git a/plan/agw/gaps.md b/plan/agw/gaps.md index dfadb447..4235354e 100644 --- a/plan/agw/gaps.md +++ b/plan/agw/gaps.md @@ -2,7 +2,7 @@ Updated October 6, 2026 after the [v4 deployment/owner-guide review](research/deployment-review-2026-10-06/README.md), [Harsh’s replies](product-decisions-2026-10-04.md), v4 implementation on feat/agw-sdk-v4, and [live Notion comments](research/notion-comments-2026-10-05.md). This register distinguishes unresolved dependencies, implemented SDK work, deferred scope and historical corrections. G01–G26 are tracking IDs, not a count of open defects. -Evidence: [current baseline](current-baseline.md), [implementation status](implementation-status.md), [product alignment validation](research/product-alignment-2026-10-04/README.md), and [extended live E2Es](research/extended-e2e-2026-10-06/README.md). The unrestricted v4 SDK run passes 1,982 unit tests and 75 local-contract tests. The 25 standard AGW plus 14 extended live scenarios pass; default E2E selection remains unchanged. Public SVM destinations remain gated. +Evidence: [current baseline](current-baseline.md), [implementation status](implementation-status.md), [product alignment validation](research/product-alignment-2026-10-04/README.md), and [extended live E2Es](research/extended-e2e-2026-10-06/README.md). The unrestricted v4 SDK run passes 1,982 unit tests and 75 local-contract tests. All 39 scenarios in the opt-in AGW group pass selected-run live coverage; default E2E selection remains unchanged. Public SVM destinations remain gated. Current contract baseline: reported deployed source `e8db748`, documentation head `deploy-agw@10a24f1` (src unchanged between them). Donut v4 addresses/code/wiring and URP 3.1.0 were checked at block 23931055; verified ABIs were saved. The SDK now uses v4 only, registers Donut and has a ported actual-contract harness. [Implementation evidence](research/v4-implementation-2026-10-06/README.md). Core marketplace cb69e0b and gateway bcbf7df remain prior source pins; they were not freshly fetched. Notion bodies were not refreshed in this pass. @@ -28,7 +28,7 @@ P0 blocks agreed authorization/accounting or safe final integration. P1 affects | ID | Priority | Status | Current finding or resolution | Remaining action | | --- | --- | --- | --- | --- | -| G01 | P1 | V4 registered; live coverage passes | Checked new deployment and reproduced ABIs are integrated in the Donut-only registry; no legacy adapter fallback. | All 25 standard and 14 extended AGW scenarios have passing live coverage. Refresh wiring/source for future releases. | +| G01 | P1 | V4 registered; live coverage passes | Checked new deployment and reproduced ABIs are integrated in the Donut-only registry; no legacy adapter fallback. | All 39 AGW scenarios have passing live coverage. Refresh wiring/source for future releases. | | G02 | P0 | Source deployed; native/UEA acceptance passes | D3 executeAsAgent/agentOf and sender adapter exist in v4; documented wiring matches live reads. SmartSession is unchanged. | Sender-binding/alternate-path tests and live native/UEA/7702 acceptance pass; do not reopen the engine-fork proposal. | | G03 | P1 | SDK question resolved and implemented | Validator/nonce ID calculation and generation-specific derivation are internal. Public generation-context helpers were removed per Harsh H4.1. IDs remain wallet-scoped and receipt-confirmed. | V4 vectors and receipt-confirmed IDs are verified; no public context-signature approval is needed. | | G04 | P1 | ABI history corrected; release note | Six-field main is older; inspected current gateway and historical Donut dispatcher use eight fields. A hypothetical future field removal is not a present SDK blocker. | Encode the selected manifest’s gateway ABI and track any actual migration with that deployment. | diff --git a/plan/agw/implementation-status.md b/plan/agw/implementation-status.md index 25f6429f..23d42e0c 100644 --- a/plan/agw/implementation-status.md +++ b/plan/agw/implementation-status.md @@ -1,6 +1,6 @@ # AGW SDK implementation status -> Latest: [extended AGW live coverage](research/extended-e2e-2026-10-06/README.md). The unfiltered unit suite passes 1,982 tests; all 75 Anvil cases and the core build pass. All 25 standard AGW scenarios and 14 additional opt-in management/native-policy scenarios have passing live coverage. Public SVM destinations remain gated. +> Latest: [extended AGW live coverage](research/extended-e2e-2026-10-06/README.md). The unfiltered unit suite passes 1,982 tests; all 75 Anvil cases and the core build pass. All 39 opt-in AGW scenarios, including the 14 management/native-policy additions, have passing selected-run live coverage. Public SVM destinations remain gated. Updated October 6, 2026. Branch feat/agw-sdk-v4; runtime commits a66ff7d and b68bab7. The native/EVM migration uses deployed source e8db748. Runtime/test e704d5b adapters, ABIs and fixtures were removed at Shoaib's request; historical review documents are evidence only. [Full handoff, commands and validation](research/v4-implementation-2026-10-06/README.md). @@ -14,8 +14,8 @@ Updated October 6, 2026. Branch feat/agw-sdk-v4; runtime commits a66ff7d and b68 | Runtime matrix | Node 20.19.2 and 24.14.0 pass full units, local contracts and package/API checks | | Build/typechecks | Build and lib/spec/local/AGW-E2E typechecks pass | | Lint | 7 pre-existing errors in unchanged files; no new errors | -| E2E selection | Standard AGW: 25 scenarios/9 files/25 tests; extended: 14 scenarios/2 files/14 tests; default all unchanged at 76/40/81 | -| Funded live | Standard 25 plus extended 14 scenarios have passing selected-run coverage; 0 outstanding native/EVM scenario failures | +| E2E selection | AGW: 39 scenarios/11 files/39 tests; default all unchanged at 76/40/81 | +| Funded live | All 39 AGW scenarios have passing selected-run coverage; 0 outstanding native/EVM scenario failures | Local gateway/core/token/executor and CEA lookup are fixtures. Actual AGW/factory/engine/validator/URP enforce the rules; native type-4 tests use real transactions. This does not prove production gateway, Cosmos/TSS, UEA or destination execution. @@ -36,7 +36,7 @@ Local gateway/core/token/executor and CEA lookup are fixtures. Actual AGW/factor | 11 | EVM outbound | V4 asset membership, maxGasPerCall, wallet CEA/refunds, signer gas and responses | Release review; Sepolia success/failure and UEA cases verified | | 12 | SVM destinations | Internal live positive delivery and later terminal-rejection replay verified; public capability gated | Public mapping/display/dispatch agreement, adapters and public acceptance; rejection retry timing is documented separately | | 13 | Responses/progress/errors | V4 ABIs and prior canonical replay/wait fixes retained | Delayed-index replay/polling tested with real contracts/receipts; no remaining SDK-owned response gap | -| 14 | E2E | 25 standard and 14 extended opt-in scenarios registered; extended management/policy cases pass live | Completed native/EVM live coverage; public SVM acceptance after integration | +| 14 | E2E | 39 opt-in scenarios registered; added management/policy cases pass live | Completed native/EVM live coverage; public SVM acceptance after integration | | 15 | Web2 | Prior implementation retained and included in full unit run | Consumer migration notes supplied; existing Web2 unit acceptance passes | | 16 | compileCard | Outside standalone AGW; absent public export | Future marketplace scope | | 17 | Documentation/release | Current status/gaps/handoff updated | Product scope decisions and public SVM integration/release review | diff --git a/plan/agw/research/extended-e2e-2026-10-06/README.md b/plan/agw/research/extended-e2e-2026-10-06/README.md index b0f62b5e..69670770 100644 --- a/plan/agw/research/extended-e2e-2026-10-06/README.md +++ b/plan/agw/research/extended-e2e-2026-10-06/README.md @@ -1,13 +1,13 @@ # Extended AGW E2E coverage — October 6, 2026 -Branch `feat/agw-sdk-v4`. This follow-up adds 14 opt-in Donut/Sepolia E2E scenarios in the `agw-extended` group. They exercise wallet identity and management races, atomic rule lifecycle behavior, and native policy enforcement against the deployed v4 contracts. The cases use bounded testnet funds and create fresh test wallets. +Branch `feat/agw-sdk-v4`. This follow-up adds 14 additional Donut/Sepolia E2E scenarios in the opt-in `agw` group. They exercise wallet identity and management races, atomic rule lifecycle behavior, and native policy enforcement against the deployed v4 contracts. The cases use bounded testnet funds and create fresh test wallets. ## Coverage | File | Scenarios | Checks | | ---------------------------------------------------------- | --------: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `packages/core/__e2e__/agw-extended/management.spec.ts` | 6 | Prefunding a derived wallet, label/index reads, same-agent multiplicity and ambiguous-send refusal, batched add/revoke checkpoint counts, invalid revoke guards, stale update rollback after an intervening agent spend, and owner wallet-index race recovery. | -| `packages/core/__e2e__/agw-extended/native-policy.spec.ts` | 8 | Lossless raw-offset decode and recipient delivery, pin mismatch, per-call and cumulative amount caps, exact call count, explicit zero total, failed-callee rollback, and ungranted selector refusal without allowance change. | +| `packages/core/__e2e__/agw/management-extended.spec.ts` | 6 | Prefunding a derived wallet, label/index reads, same-agent multiplicity and ambiguous-send refusal, batched add/revoke checkpoint counts, invalid revoke guards, stale update rollback after an intervening agent spend, and owner wallet-index race recovery. | +| `packages/core/__e2e__/agw/native-policy-extended.spec.ts` | 8 | Lossless raw-offset decode and recipient delivery, pin mismatch, per-call and cumulative amount caps, exact call count, explicit zero total, failed-callee rollback, and ungranted selector refusal without allowance change. | Every refusal test checks that balances and policy counters remain unchanged. The update-race test also checks that grants, checkpoint count and grant nonce remain unchanged after rollback. @@ -21,27 +21,27 @@ The create flow now classifies this narrow case from fresh factory/wallet reads: | Check | Result | | ------------------------------------------------------- | ---------------------------------------------------------------- | -| Funded live `agw-extended` group | 14 passed, 0 failed (6 management + 8 native policy) | +| Funded live run before consolidation | 14 passed, 0 failed (6 management + 8 native policy) | | Full core unit suite after the correction | 1,982 passed, 0 failed; 12 skipped; 116 suites passed, 1 skipped | | Focused management unit suite | 19 passed | | `core` build | Passed | | `tsconfig.lib.json` and `tsconfig.spec.json` typechecks | Passed | | Default E2E selection | Unchanged: 76 scenarios / 40 files / 81 tests | -| Standard AGW selection | Unchanged: 25 scenarios; the new 14 are opt-in only | +| AGW selection after consolidation | 39 scenarios/11 files/39 tests; all 14 additions are opt-in with the AGW group | -The E2E group is registered as `--group agw-extended`, requires the verified AGW manifest, and is excluded from `all`. Reproduce selection (no transactions): +The 14 cases now live under `packages/core/__e2e__/agw/` and share the existing `--group agw`. They remain excluded from `all`, which still selects 76 scenarios. The combined group is guarded by the same verified manifest. Reproduce selection (no transactions): ```sh cd packages/core -npx ts-node --transpile-only __e2e__/ci/run.ts --verify --group agw-extended +npx ts-node --transpile-only __e2e__/ci/run.ts --verify --group agw ``` -Running the group itself broadcasts testnet transactions and spends testnet funds: +Running the group broadcasts testnet transactions and spends testnet funds. It can be selected from the E2E workflow dispatch: ```sh cd packages/core -npx ts-node --transpile-only __e2e__/ci/preflight.ts --group agw-extended --dry-run -AGW_EXTENDED_E2E=1 npx ts-node --transpile-only __e2e__/ci/run.ts --group agw-extended +npx ts-node --transpile-only __e2e__/ci/preflight.ts --group agw --dry-run +npx ts-node --transpile-only __e2e__/ci/run.ts --group agw ``` Use the existing test environment and preflight procedure before a rerun. Logs below are sanitized; private keys and environment values are not included. From b1df55796afd21bd1d90bf32d453fa89e5fe55f5 Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Tue, 6 Oct 2026 20:04:01 +0530 Subject: [PATCH 29/68] docs(agw): clarify team questions with concrete examples --- plan/agw/gaps.md | 8 +-- plan/agw/implementation-status.md | 4 +- plan/agw/questions-harsh.md | 94 ++++++++++++++++++++++++------- plan/agw/questions-zaryab.md | 21 +++++-- 4 files changed, 95 insertions(+), 32 deletions(-) diff --git a/plan/agw/gaps.md b/plan/agw/gaps.md index 4235354e..a8d1b2b3 100644 --- a/plan/agw/gaps.md +++ b/plan/agw/gaps.md @@ -10,8 +10,8 @@ Current contract baseline: reported deployed source `e8db748`, documentation hea | Dependency | Owner | Related IDs | | --- | --- | --- | -| Native PC omission defaults and token wording; current target retains maxValueTotal | [Harsh H3](questions-harsh.md#h3) | G19 | -| Public Solana authoring/read model; wire/backend supplied | [Harsh H4.4 with Zaryab](questions-harsh.md#h4-4) | G22 | +| Token-model wording; Harsh now prefers zero native PC defaults, Zaryab invited to comment | [Harsh H3](questions-harsh.md#h3) | G19 | +| Public Solana authoring/read model; redirected to Zaryab | [Zaryab H4.4](questions-zaryab.md#h4-4) | G22 | | Public raw-offset read/write representation | [Harsh H4.5](questions-harsh.md#h4-5) | G25 | | Multiple-rule send selection (same-agent capacity is supplied) | [Harsh H6](questions-harsh.md#h6) | G26 | | V1 ref/label scope | [Zaryab Z1.3 with Harsh](questions-zaryab.md#z1-3) | G08 | @@ -46,7 +46,7 @@ P0 blocks agreed authorization/accounting or safe final integration. P1 affects | G16 | P1 | Implemented; migration documentation supplied | READ.CHAIN.WEB2 is web2. Legacy web2:https input is normalized to unchanged wire identity. Deprecated aliases now use the new public value. | The consumer guide documents the alias/literal migration; Web2 normalization/read-source tests pass. | | G17 | P1 | SDK decision implemented locally | Read-only write guards and explicit agenticWallet selection on reinitialize are implemented. Signer/network/wallet changes rebuild role/capability context. | Preserve compatibility coverage and verify with the release deployment. | | G18 | P1 | SDK behavior implemented locally; selection under review | Initialization uses enabled-rule identity; sends perform uncached lookup without expiry filtering. Missing/ambiguous candidates fail before signing. Public list is enabled-only; unknown/revoked get returns RULE_NOT_FOUND. The October 5 multiple-rules comment may change selection/cardinality assumptions. | Resolve G26 before treating uniqueness/ambiguous-candidate behavior as final. Verify final-generation and live permission-change cases; public history is deferred. | -| G19 | P0/P1 | Universal defaults implemented; H3 native PC choices open | Universal omission uses maxUint256 and explicit zero is hard zero; empty input gets a gas-token 0/0 route. Native PC omission remains provisional at 0. Current live NativeRule retains maxValueTotal; wire sentinel meanings are supplied. | Confirm omitted native PC limits and intended token model; preserve the current field unless an explicit revision is supplied. | +| G19 | P0/P1 | Defaults match Harsh’s latest preference; token wording open | Universal omission uses maxUint256 and explicit zero is hard zero; empty input gets a gas-token 0/0 route. Harsh’s October 6 reply prefers native PC omission at 0, matching the SDK, and invites Zaryab’s comment. Current live NativeRule retains maxValueTotal; wire sentinel meanings are supplied. | Clarify the intended token model and record any Zaryab qualification; preserve the current field unless an explicit revision is supplied. | | G20 | P1 | V4 composer/response and live EVM acceptance pass | Uses selected listed token, maxGasPerCall, wallet CEA/refund context, separate allowance and signer gas. Local requests pass actual URP with fixture gateway. | Production token debit, node/TSS delivery, CEA execution attribution/balance, replay identity and destination-revert classification pass. Public SVM integration remains tracked under G22. | | G21 | P1 | Product direction resolved; batching implemented locally | NativeRule remains one action. Arrays use a sender-preserving UEA/7702 outer batch of single executeAsAgent calls, each checked by policy. Native sequential fallback is prohibited. Local real-type-4 tests prove sender identity, cumulative counters and mined rollback. | Release-deployment UEA identities and native 7702 batch/rollback cases pass. The local executor is a fixture; arbitrary forwarding helpers are not a substitute for the agent account. | | G22 | P1 | Internal SVM delivery and terminal replay verified; public integration pending | Actual CEA transfer/CPI, replay and deployed policy refusals pass. Initial rejection wait timed out; the same outbound later became REVERTED and replay returned failed. Public capability stays gated. | H4.4: agree public authoring/read mapping, connect adapters and complete public acceptance. Z1.4 fixture delivery is closed; terminalization timing is an operational follow-up, not a newly inferred delivery blocker. | @@ -68,7 +68,7 @@ Local batch proof uses actual AGW/factory/engine/policy and real Anvil EIP-7702 - expectedCEA derives from AGW plus destination context. Signer CEA and arbitrary pasted addresses are not substitutes. - Checkpoint consumers compare counts; allowance-driven balance changes are not always checkpointed. Current single replacement adds five ticks. - Internal spend assertions remain required even when public spend records are removed. -- H3 native defaults and raw-offset representation remain open. Universal total semantics are now supplied; the old zero/unlimited row must not carry into v4. +- Harsh now prefers zero native PC defaults; the implementation matches and omission is unit-tested. Token-model wording and raw-offset representation remain open. Universal total semantics are now supplied; the old zero/unlimited row must not carry into v4. - H6 remains a send-selection choice. Same-agent capacity is supplied; uniqueness validation is provisional/stale. Token-independence wording is a product follow-up, not permission to remove policy checks. - Harsh’s replies have been received. The linked question documents now contain remaining follow-ups; no outbound team messages were sent by this agent. diff --git a/plan/agw/implementation-status.md b/plan/agw/implementation-status.md index 23d42e0c..ba03a811 100644 --- a/plan/agw/implementation-status.md +++ b/plan/agw/implementation-status.md @@ -28,7 +28,7 @@ Local gateway/core/token/executor and CEA lookup are fixtures. Actual AGW/factor | 3 | Signer/wallet context | Owner/agent/read-only/identity guards retained | Release review; UEA identity cases pass | | 4 | Registry/adapter | Donut v4 registered; unsupported networks fail | Release review; no legacy fallback | | 5 | Wallet/checkpoint/rule reads | Native and EVM reads implemented; source tokens/beneficiary offsets reconstructed | Metadata scope; public SVM mapping (internal reads complete) | -| 6 | Normalization/codecs | Native/EVM envelope 1, ordered caps, hard-zero/max total, empty-list routing | Native H3 defaults; SVM public mapping | +| 6 | Normalization/codecs | Native/EVM envelope 1, ordered caps, hard-zero/max total, empty-list routing | H3 token wording; SVM public mapping | | 7 | Create/add/revoke | Index-bound create, partial recovery, atomic writes; same-agent multiples allowed | Release review; deployed create/identity/batching paths verified | | 8 | Atomic update | Native per-action and universal all-token assertions before revoke/grant | Public SVM authoring wrapper (internal lifecycle complete) | | 9 | Owner/allowance | Owner path unrestricted; explicit separate allowance retained | Release review; production allowance/token debit and delivery verified | @@ -45,6 +45,6 @@ Local gateway/core/token/executor and CEA lookup are fixtures. Actual AGW/factor A01 approval policy, A04 internal generation details, A06 history deferral and A08 compiler scope remain settled. A02 native batching is implemented locally. A05 wire/accounting is delivered and implemented for EVM. A07 deployment/registry is supplied; grant ref and editable label remain absent and capability-gated. -H3 is narrowed to native PC omission defaults/token wording; current target retains maxValueTotal. H4.4 is joint public SVM representation, with [concrete proposals](public-api-proposals.md) ready. H4.5 covers raw-offset representation, and H6 send selection. [Harsh draft](questions-harsh.md); [Zaryab metadata draft](questions-zaryab.md). The fixture request is closed with [our live wire evidence](research/live-svm-wire-2026-10-06/README.md), including later terminal rejection after the initial timeout. +Harsh’s October 6 reply prefers zero native PC omission defaults, matching the SDK, and invites Zaryab’s input. H3 token wording still needs an example-based clarification; current target retains maxValueTotal. Harsh redirected H4.4 public SVM representation to Zaryab, with [concrete proposals](public-api-proposals.md) ready. H4.5 covers raw-offset representation, and H6 send selection. [Harsh draft](questions-harsh.md); [Zaryab metadata draft](questions-zaryab.md). The fixture request is closed with [our live wire evidence](research/live-svm-wire-2026-10-06/README.md), including later terminal rejection after the initial timeout. No public spent/history/compiler feature is reopened. Rule updates reset counters as agreed. Ordinary inflows do not restore spent; creditRevert remains a platform dependency. diff --git a/plan/agw/questions-harsh.md b/plan/agw/questions-harsh.md index 81dcf4b1..3bf39d5c 100644 --- a/plan/agw/questions-harsh.md +++ b/plan/agw/questions-harsh.md @@ -1,52 +1,104 @@ # AGW SDK — questions for Harsh -Updated October 6, 2026. Please reply by question ID. These are the remaining product/API decisions. +Updated October 6, 2026 after Harsh’s reply. Numbers 2–5 below match the chat questions; existing H IDs are retained for tracking. + +**Question 1 — native PC defaults:** Harsh now prefers `0` for omitted `maxValuePerCall` and `maxValueTotal`, with Zaryab invited to comment. The SDK already uses `0`, so no behavior change is needed. These fields limit native PC value attached to agent calls; they do not set the sender’s transaction gas budget. -## H3. Native defaults and token model +## 2. What should “tokens independent” mean? — H3, Harsh + +**Where this came from:** your comment on the [validation paragraph in 5. SDK: AGW](https://app.notion.com/p/pushprotocol/5-SDK-AGW-3e9188aea7f481cf8e8de324956549b9#af9c3fac35d94f2585cb27310271c1d8), recorded during our October 5 comment review: + +> “we usually want the tokens to be independent and not attached to this” -**1. Should omitted native PC limits mean unlimited?** +**Current model:** the owner grants one rule containing an `assets[]` list and an allowed-call list. Each asset has its own outbound amount limits. For example: -| Field | Proposed default | Current SDK | +| Asset | Maximum per outbound | Maximum total under this rule | | --- | --- | --- | -| `maxValuePerCall` | `maxUint256` (unlimited) | `0`, provisional | -| `maxValueTotal` | `maxUint256` (unlimited) | `0`, provisional | +| USDC | 10 | 100 | +| USDT | 20 | 200 | -Explicit `0` would still forbid value movement. We retain `maxValueTotal`, which is still in the SDK spec. +After an outbound spends 10 USDC, the USDC budget has 90 remaining; the USDT budget still has 200. These are illustrative token units; SDK amounts use base-unit integers. -**2. Does your “tokens independent” comment mean the current `assets[]` model should stay?** +The allowed calls might be `swap()` and `deposit()`. The rule does not associate one token exclusively with one call: either listed asset may be used with either allowed call, provided the request satisfies the other policy checks. These limits do not automatically constrain every token movement performed inside a destination contract. -The delivered model has independent limits per token; each listed token can be used with every allowed call. If you intended a different SDK input model, please provide one example. +**Decision needed:** did you mean that each token should have its own budget, which this model already supports? Or should token permissions live outside the rule entirely? If you meant something else, one intended developer example would help us distinguish it. We propose retaining the current `assets[]` model until that is clarified. -## H4.4. Public Solana rules — with Zaryab +## 3. How should developers describe a Solana rule? — H4.4, Zaryab + +Harsh redirected this question to Zaryab. The contract’s Solana constraint format is available; we need to agree on the developer-facing input the SDK compiles into that format. + +**Example intent:** “Allow the agent to call a vault’s `deposit` instruction, only for Alice’s specified destination account, with an amount no greater than 10.” There are two ways a developer could express this: -**Should public Solana rules use IDL-based authoring, or explicit raw constraints?** +| Option | What the developer supplies | What the SDK does | +| --- | --- | --- | +| Named inputs using an IDL | Program address, IDL (the program’s interface description), instruction name `deposit`, named accounts and constraints on fields such as `amount` | Resolves the discriminator, account positions and data offsets from the supported IDL layout, then builds the contract constraints | +| Explicit raw constraints | Program address, instruction discriminator, account positions/expected addresses, and data byte offsets/comparisons | Validates and encodes the supplied constraints without requiring an IDL | + +In both options, the SDK derives the wallet’s destination CEA and protected token accounts internally. Reading a stored rule returns its exact constraints; the contract does not store the original IDL or field names. -Our proposal is a Solana-specific `Rule` with instruction/account/field inputs compiled from an IDL. The SDK derives the gateway, wallet CEA and protected token accounts internally. Decoded records preserve the exact stored constraints. +**Recommendation:** support named IDL inputs for layouts the SDK can verify. Unsupported layouts must fail clearly rather than guess offsets. -The alternative is to let callers author explicit program, account-pin and data-pin constraints. Please agree on the input/read model together. [Proposed types and examples](public-api-proposals.md#h44-solana-rule-inputs-and-decoded-records). +**Decision needed from Zaryab:** should v1 expose IDL-based inputs, raw constraints, or both? If both, raw input should be an explicit advanced form. [Proposed types and boundaries](public-api-proposals.md#h44-solana-rule-inputs-and-decoded-records). -## H4.5. Argument indexes versus raw offsets +## 4. What should rule inputs and reads expose? — H4.5, Harsh + +**Example:** a developer wants to restrict `transfer(address recipient, uint256 amount)` to Alice. The convenient input is: + +```ts +pins: [{ arg: 0, expected: alice }] +``` + +`arg: 0` means the first function argument. For this function’s ABI layout, the SDK converts it to byte offset `4`, immediately after the four-byte function selector. The second argument, `amount`, starts at offset `36`. -**May callers use both ABI argument indexes and raw byte offsets, or should authoring and decoded records have separate types?** +**The read-back problem:** the contract stores offsets and exact values, without the original ABI. Therefore `rules.get()` returns a pin shaped like: -This covers native pins/amount limits and EVM `beneficiaryOffset`. Contracts store offsets without an ABI, so reads cannot reliably recover argument indexes. +```ts +pins: [{ offset: 4, expected: aliceAs32ByteWord }] +``` -**Recommendation:** keep the tested dual input form and exact raw-offset reads. If public authoring must be ABI-only, we will separate decoded records. [Options and examples](public-api-proposals.md#h45-nativeevm-raw-authoring-and-decoding). +Here `aliceAs32ByteWord` is Alice’s address padded to a 32-byte ABI word. An offset is not an argument number; arbitrary ABI layouts cannot be reconstructed just by dividing the offset by 32. + +**Decision needed:** which public model do you want? + +| Option | Creating a rule | Reusing a rule returned by `rules.get()` | +| --- | --- | --- | +| Both input forms — recommended | Accept either `arg` or an explicit `offset`; reject conflicting forms | Exact decoded offsets can be reused in `rules.add/update` | +| Separate input and read types | New authoring accepts ABI argument indexes only | Return a distinct decoded type; require a defined conversion using a verified ABI before reuse | + +The first option is already implemented and tested, but extends the spec’s public input shape and needs approval. In either option, reads preserve exact stored offsets. The same issue applies to native amount limits and EVM beneficiary constraints. [Detailed options](public-api-proposals.md#h45-nativeevm-raw-authoring-and-decoding). -## H6. Selecting among multiple rules +## 5. Who chooses the rule for an agent transaction? — H6, Harsh + +**Example:** the same agent has two enabled rules on the same wallet and chain: + +| Rule | Permission | +| --- | --- | +| A | Call app A within its configured limits | +| B | Call app B within its configured limits | + +The agent now wants to call app A. Currently the SDK sees two candidate rules and returns `AMBIGUOUS_RULE` before signing. It does not simulate every rule to choose one, even when only one would permit the requested call. + +**Proposal:** let the caller identify the intended rule. The following is proposed syntax, not currently supported: + +```ts +await agent.universal.sendTransaction( + { to: appA, data }, + { agentic: { rulesId: ruleA } } +); +``` -**Can we add explicit per-send rule selection, or do you want an automatic strategy?** +The SDK checks that the selected rule belongs to this wallet, agent and destination chain and is enabled. The contract still enforces its permissions, expiry and budgets. -**Proposal:** optional `rulesId` for one action/outbound; ordered `rulesIds` for a native batch using different rules. An EVM destination call array uses one rule for the entire outbound. +For a native batch `[callAppA, callAppB]`, propose ordered IDs `[ruleA, ruleB]`, one per action, with atomic execution. An EVM destination call array uses one rule for the whole outbound; permissions from different rules are not combined. If there is only one candidate, existing sends continue to work without an explicit ID. -Today, multiple matching rules produce `AMBIGUOUS_RULE` before signing. If you prefer automatic selection, please define how overlapping rules are chosen. [Proposed options and examples](public-api-proposals.md#h6-rule-selection-for-sends). +**Decision needed:** approve explicit rule selection, or specify an automatic selection policy. For example, if two rules both permit the same call but have different remaining budgets, which should the SDK consume? We recommend explicit selection so the caller controls this choice. [Detailed proposal](public-api-proposals.md#h6-rule-selection-for-sends). [SDK spec](https://app.notion.com/p/pushprotocol/5-SDK-AGW-3e9188aea7f481cf8e8de324956549b9) · [Questions for Zaryab](questions-zaryab.md) diff --git a/plan/agw/questions-zaryab.md b/plan/agw/questions-zaryab.md index c8679af5..0c4c6a7c 100644 --- a/plan/agw/questions-zaryab.md +++ b/plan/agw/questions-zaryab.md @@ -1,6 +1,6 @@ # AGW SDK — questions for Zaryab -Updated October 6, 2026. Please confirm the release scope below and review the shared Solana API choice with Harsh. +Updated October 6, 2026. Please confirm the release scope below and answer the Solana API question Harsh redirected to you on October 6. @@ -20,12 +20,23 @@ If deferred, please agree the v1 scope with Harsh so we can align the public SDK -## H4.4. Public Solana rules — with Harsh +## 3. How should developers describe a Solana rule? — H4.4, Zaryab -**Should public Solana rules use IDL-based authoring, or explicit raw constraints?** +Harsh redirected this question to Zaryab. The contract’s Solana constraint format is available; we need to agree on the developer-facing input the SDK compiles into that format. -Our proposal compiles instruction/account/field inputs from an IDL and keeps gateway/CEA/token-account derivation internal. Decoded records preserve exact stored constraints. +**Example intent:** “Allow the agent to call a vault’s `deposit` instruction, only for Alice’s specified destination account, with an amount no greater than 10.” There are two ways a developer could express this: -Please review the [proposed types and examples](public-api-proposals.md#h44-solana-rule-inputs-and-decoded-records) with Harsh. This is the same [H4.4 question](questions-harsh.md#h4-4) in his document. +| Option | What the developer supplies | What the SDK does | +| --- | --- | --- | +| Named inputs using an IDL | Program address, IDL (the program’s interface description), instruction name `deposit`, named accounts and constraints on fields such as `amount` | Resolves the discriminator, account positions and data offsets from the supported IDL layout, then builds the contract constraints | +| Explicit raw constraints | Program address, instruction discriminator, account positions/expected addresses, and data byte offsets/comparisons | Validates and encodes the supplied constraints without requiring an IDL | + +In both options, the SDK derives the wallet’s destination CEA and protected token accounts internally. Reading a stored rule returns its exact constraints; the contract does not store the original IDL or field names. + +**Recommendation:** support named IDL inputs for layouts the SDK can verify. Unsupported layouts must fail clearly rather than guess offsets. + +**Decision needed from Zaryab:** should v1 expose IDL-based inputs, raw constraints, or both? If both, raw input should be an explicit advanced form. [Proposed types and boundaries](public-api-proposals.md#h44-solana-rule-inputs-and-decoded-records). + +Harsh also now prefers `0` for omitted native `maxValuePerCall` and `maxValueTotal` and invited your input. The SDK already uses those defaults; flag any contract-side concern. [Current contract guide](https://github.com/pushchain/push-agentic-wallets/blob/10a24f101e2e6e0a9b76517b29f5cdb1aa967796/docs/5_SDK_Owner_Integration.md) · [SDK spec](https://app.notion.com/p/pushprotocol/5-SDK-AGW-3e9188aea7f481cf8e8de324956549b9) From 898eda17911133faa155899ac8e1276a589c4564 Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Wed, 7 Oct 2026 15:48:43 +0530 Subject: [PATCH 30/68] feat(agw): implement confirmed SDK decisions and public Solana flows --- packages/core/AGW.md | 58 +++- .../__agw-local__/agw-local-batch.spec.ts | 42 ++- .../core/__agw-local__/svm-backend.spec.ts | 4 +- .../core/__agw-local__/svm-public.spec.ts | 282 +++++++++++++++++ .../core/__e2e__/agw/multi-asset-svm.spec.ts | 12 - .../agw/native-policy-extended.spec.ts | 77 ++++- packages/core/__e2e__/agw/svm-public.spec.ts | 290 ++++++++++++++++++ .../core/__e2e__/agw/v4-multiasset.spec.ts | 3 +- packages/core/__e2e__/ci/preflight.ts | 2 +- packages/core/__e2e__/ci/suite.ts | 8 +- packages/core/scripts/agw-verify.js | 2 +- .../src/lib/agentic/__tests__/codec.spec.ts | 18 +- .../agentic/__tests__/rules-policy.spec.ts | 23 +- .../src/lib/agentic/__tests__/send.spec.ts | 5 +- .../src/lib/agentic/__tests__/svm-idl.spec.ts | 177 +++++++++++ .../core/src/lib/agentic/agentic.types.ts | 94 ++++-- packages/core/src/lib/agentic/capabilities.ts | 8 +- .../core/src/lib/agentic/codec/defaults.ts | 18 +- packages/core/src/lib/agentic/codec/ids.ts | 2 +- packages/core/src/lib/agentic/codec/native.ts | 15 +- packages/core/src/lib/agentic/codec/rules.ts | 66 +++- .../core/src/lib/agentic/codec/svm-idl.ts | 269 ++++++++++++++++ packages/core/src/lib/agentic/deployments.ts | 1 + .../src/lib/agentic/execution/outbound.ts | 2 +- .../core/src/lib/agentic/execution/send.ts | 6 + .../src/lib/agentic/execution/svm-payload.ts | 2 +- .../src/lib/agentic/execution/svm-public.ts | 264 ++++++++++++++++ .../src/lib/agentic/execution/svm-send.ts | 4 +- packages/core/src/lib/agentic/index.ts | 5 + .../src/lib/agentic/management/prepare.ts | 16 +- .../src/lib/agentic/management/rules-write.ts | 2 +- .../src/lib/agentic/management/svm-public.ts | 114 +++++++ packages/core/src/lib/agentic/reads/rules.ts | 71 ++++- packages/core/src/lib/agentic/reads/svm.ts | 2 +- packages/core/src/lib/agentic/response.ts | 44 ++- packages/core/src/lib/agentic/runtime.ts | 14 +- packages/core/src/lib/agentic/utils.ts | 60 +++- packages/core/src/lib/index.ts | 5 + .../vm-client/evm-client.batch-gas.spec.ts | 75 +++++ packages/core/src/lib/vm-client/evm-client.ts | 34 +- plan/agw/README.md | 22 +- plan/agw/current-baseline.md | 27 +- plan/agw/external-blockers.md | 56 +--- plan/agw/gaps.md | 46 ++- plan/agw/implementation-status.md | 44 ++- plan/agw/product-decisions-2026-10-04.md | 18 ++ plan/agw/public-api-proposals.md | 2 + plan/agw/questions-harsh.md | 101 +----- plan/agw/questions-zaryab.md | 40 +-- .../decision-alignment-2026-10-07/README.md | 43 +++ .../batch-gas.json | 18 ++ .../live-evidence.json | 86 ++++++ .../logs/build.log | 11 + .../logs/local-contracts.log | 29 ++ .../logs/native-default-refusal-live.log | 20 ++ .../logs/native-live.log | 20 ++ .../logs/svm-public-initial-gas-failure.log | 153 +++++++++ .../logs/svm-public-live.log | 13 + .../logs/units.log | 171 +++++++++++ 59 files changed, 2721 insertions(+), 395 deletions(-) create mode 100644 packages/core/__agw-local__/svm-public.spec.ts delete mode 100644 packages/core/__e2e__/agw/multi-asset-svm.spec.ts create mode 100644 packages/core/__e2e__/agw/svm-public.spec.ts create mode 100644 packages/core/src/lib/agentic/__tests__/svm-idl.spec.ts create mode 100644 packages/core/src/lib/agentic/codec/svm-idl.ts create mode 100644 packages/core/src/lib/agentic/execution/svm-public.ts create mode 100644 packages/core/src/lib/agentic/management/svm-public.ts create mode 100644 packages/core/src/lib/vm-client/evm-client.batch-gas.spec.ts create mode 100644 plan/agw/research/decision-alignment-2026-10-07/README.md create mode 100644 plan/agw/research/decision-alignment-2026-10-07/batch-gas.json create mode 100644 plan/agw/research/decision-alignment-2026-10-07/live-evidence.json create mode 100644 plan/agw/research/decision-alignment-2026-10-07/logs/build.log create mode 100644 plan/agw/research/decision-alignment-2026-10-07/logs/local-contracts.log create mode 100644 plan/agw/research/decision-alignment-2026-10-07/logs/native-default-refusal-live.log create mode 100644 plan/agw/research/decision-alignment-2026-10-07/logs/native-live.log create mode 100644 plan/agw/research/decision-alignment-2026-10-07/logs/svm-public-initial-gas-failure.log create mode 100644 plan/agw/research/decision-alignment-2026-10-07/logs/svm-public-live.log create mode 100644 plan/agw/research/decision-alignment-2026-10-07/logs/units.log diff --git a/packages/core/AGW.md b/packages/core/AGW.md index 494ce68e..f767595c 100644 --- a/packages/core/AGW.md +++ b/packages/core/AGW.md @@ -1,6 +1,6 @@ # Agentic wallets on Push Chain -This guide describes AGW v4 in this SDK branch. Donut is the configured deployment. Native Push and EVM destination rules are supported; public Solana destination rules are not enabled yet. Solana-origin signers can already act through their Push UEA. +This guide describes AGW v4 in this SDK branch. Donut is the configured deployment. Native Push, EVM destination rules and named-IDL Solana devnet rules are supported. Solana-origin signers can already act through their Push UEA. An AGW holds assets. Its owner grants or revokes rules and can execute unrestricted owner calls. An agent executes through its own Push identity, and each agent call must pass the granted policy. A Push-native key's identity is its EOA; an external key's identity is its Push UEA for that origin chain. @@ -24,6 +24,7 @@ import { AgenticError, type NativeRule, type UniversalRule, + type SolanaRule, } from '@pushchain/core'; import { createWalletClient, @@ -257,14 +258,65 @@ A successful Push receipt does not mean destination success. Check `externalStat | `INDEX_RACE` | This create committed nothing; derive/retry the next slot. | | `CREATE_PARTIAL` | Inspect `details.walletDeployed`, `grantedRulesIds`, `confirmedHashes` and `pendingHash`. Reconcile unknown/pending outcomes. If deployed, finish missing grants with `rules.add`; do not create a replacement wallet blindly. | | `NO_RULES_FOR_CHAIN` | Grant a suitable enabled rule before the agent sends. | -| `AMBIGUOUS_RULE` | Inspect candidate IDs in `details.rulesIds`. The SDK does not pick or revoke a rule arbitrarily; the public selection API is still being agreed. | +| `AMBIGUOUS_RULE` | Multiple enabled rules match the agent and chain. No transaction is submitted. Inspect `details.rulesIds` and have the owner resolve the overlap; the SDK does not pick or revoke a rule arbitrarily. | | `GATEWAY_ALLOWANCE_INSUFFICIENT` | The owner must explicitly establish a sufficient allowance. | | `CAPABILITY_UNAVAILABLE` / `GENERATION_UNSUPPORTED` | Inspect the capability/deployment details; no compatible operation was submitted. | Ordinary returned funds do not lower policy spend. `creditRevert` still needs platform executor support. Revoking rules stops agent authorization but does not remove ERC20 allowances; the owner manages those separately. +## Solana rules using named IDL inputs + +Use `SolanaRule` with an Anchor IDL, instruction name, named account restrictions and field constraints. Addresses accept base58 or 32-byte hex. `walletCEA` and `walletATA` references are derived from the AGW and configured cluster; declare output mints in `outputTokens` when their wallet ATAs also need protection. + +```ts +import type { Idl } from '@coral-xyz/anchor'; + +async function createSolanaWallet( + owner: PushChain, agent: Address, program: string, + idl: Idl, recipient: string, counter: string, +) { + const rule: SolanaRule = { + agent, + chainNamespace: PushChain.CONSTANTS.CHAIN.SOLANA_DEVNET, + validUntil: Math.floor(Date.now() / 1000) + 3600, + assets: [{ token: '0x0000000000000000000000000000000000000000', maxPerCall: BigInt(10_000), maxTotal: BigInt(20_000) }], + maxGasPerCall: parseEther('20'), + allowedInstructions: [{ + program, + instruction: { idl, name: 'receive_sol' }, + accounts: [ + { name: 'counter', expected: { kind: 'address', address: counter } }, + { name: 'recipient', expected: { kind: 'address', address: recipient } }, + { name: 'cea_authority', expected: { kind: 'walletCEA' } }, + { name: 'system_program', expected: { kind: 'address', address: '11111111111111111111111111111111' } }, + ], + fields: [{ name: 'amount', max: BigInt(10_000) }], + }], + }; + return owner.agentic.create('solana-wallet', { rules: [rule] }); +} + +async function sendSolanaInstruction(agent: PushChain, program: string, idl: Idl) { + const data = PushChain.utils.helpers.encodeTxData({ + abi: idl, functionName: 'receive_sol', args: [BigInt(10_000)], + }); + return agent.universal.sendTransaction({ + to: { address: program, chain: PushChain.CONSTANTS.CHAIN.SOLANA_DEVNET }, + data, value: BigInt(10_000), + }); +} +``` + +These examples assume the supplied IDL describes `receive_sol` with those accounts and a `u64` amount. The send resolver needs matching account addresses/PDA definitions in its IDL. Fund the wallet and set a separate bounded gateway allowance before sending. Native SOL amounts are lamports; the wallet burns its corresponding PRC20. `assets: []` creates a zero-amount gas-token routing cap. + +Supported rule layouts have an eight-byte discriminator, top-level non-optional accounts, and fixed-width primitive/fixed-array arguments. Field comparisons support exact bytes (at most 32 bytes), unsigned integer min/max (up to `u64`), and same-width unsigned ratio floors. Variable-length or nested/defined argument layouts and optional/nested accounts are rejected before signing. An IDL describes encoding; it does not prove what the program does with those accounts. + +Public SVM sends support one instruction encoded with `encodeTxData` (which registers the IDL), or data matching an already registered IDL. Arrays and funds-only sends are rejected. Reads return `DecodedSolanaRule` with `format: 'decoded'` and exact stored program/account/data constraints. They cannot reconstruct an IDL; use a named `SolanaRule` input to add or replace it. Native/EVM decoded rules remain reusable in raw-offset form. + +Responses expose `agentic.destinationInstruction` and the wallet’s destination CEA. Check `externalStatus` and replay the same transaction hash after a timeout. + ## Current API boundaries -Grant `ref` and editable `setLabel` are unavailable on this deployed generation. Public Solana destination mapping/dispatch remains gated. Revoked history, public spend records, public generation context and `compileCard` are outside standalone v1. Native omission defaults, raw-offset authoring and multiple-rule send selection remain open; the examples use explicit native limits and one matching rule. +Rule `ref` is removed from public inputs and records; supplying it is rejected. Checkpoint `ref` is a separate existing event field and is preserved. Editable `setLabel` awaits a verified contract interface/deployment. Contract permission enforcement is already present: unauthorized actions under the supplied rule are rejected, and the SDK maps the errors. Revoked history, public spend records, public generation context and `compileCard` are outside standalone v1. Omitted native PC value limits are zero. Native argument-index and raw-offset inputs are both supported; decoded native/EVM rules preserve exact offsets. Use `PushChain.CONSTANTS.READ.CHAIN.WEB2` for Web2 reads. Its value is `web2`; the old literal `web2:https` is still accepted and normalizes to the same wire identity. Literal comparisons against the older spelling need updating. Web2 is a read source, not a transaction destination. diff --git a/packages/core/__agw-local__/agw-local-batch.spec.ts b/packages/core/__agw-local__/agw-local-batch.spec.ts index 378959a8..ae5071df 100644 --- a/packages/core/__agw-local__/agw-local-batch.spec.ts +++ b/packages/core/__agw-local__/agw-local-batch.spec.ts @@ -10,6 +10,7 @@ import { import { AgenticRevertError, CHAIN, type PushChain } from '../src'; import { PUSH_BATCH_EXECUTOR_ADDRESS } from '../src/lib/constants/chain'; import { startHarness, type Harness } from './harness'; +import { EvmClient } from '../src/lib/vm-client/evm-client'; import { readNativeCounters } from '../__e2e__/shared/agw-state'; const ABI = parseAbi([ @@ -97,9 +98,29 @@ it('failure of a later native action rolls back the earlier call and its counter const nonceBefore = await h.publicClient.getTransactionCount({ address: h.wallets[1].account!.address, }); - await expect( - agent.universal.sendTransaction({ to: h.addresses.target, data: calls() }) - ).rejects.toBeInstanceOf(AgenticRevertError); + // Normal estimation now refuses this invalid batch before broadcast. For + // this separate rollback proof, override only the test estimate so the real + // signed type-4 transaction reaches the real contracts and reverts there. + const original = EvmClient.prototype.sendBatch7702; + const send = jest + .spyOn(EvmClient.prototype, 'sendBatch7702') + .mockImplementation(async function (this: EvmClient, params) { + const estimate = jest + .spyOn(this.publicClient, 'estimateGas') + .mockResolvedValue(BigInt(2_000_000)); + try { + return await original.call(this, params); + } finally { + estimate.mockRestore(); + } + }); + try { + await expect( + agent.universal.sendTransaction({ to: h.addresses.target, data: calls() }) + ).rejects.toBeInstanceOf(AgenticRevertError); + } finally { + send.mockRestore(); + } // Prove this was a mined transaction failure, not an early SDK rejection. expect( await h.publicClient.getTransactionCount({ @@ -116,3 +137,18 @@ it('failure of a later native action rolls back the earlier call and its counter ) ).toMatchObject({ callsUsed: 0 }); }); + +it('normal estimation refuses an invalid native batch before broadcasting', async () => { + const { agent } = await walletFor(1); + const nonce = await h.publicClient.getTransactionCount({ + address: h.wallets[1].account!.address, + }); + await expect( + agent.universal.sendTransaction({ to: h.addresses.target, data: calls() }) + ).rejects.toBeInstanceOf(AgenticRevertError); + expect( + await h.publicClient.getTransactionCount({ + address: h.wallets[1].account!.address, + }) + ).toBe(nonce); +}); diff --git a/packages/core/__agw-local__/svm-backend.spec.ts b/packages/core/__agw-local__/svm-backend.spec.ts index f6fc5ef4..59e27564 100644 --- a/packages/core/__agw-local__/svm-backend.spec.ts +++ b/packages/core/__agw-local__/svm-backend.spec.ts @@ -199,7 +199,7 @@ describe('internal prepared SVM backend on v4', () => { }); return { wallet, id: grant.rulesId, input, agent, request }; } - it('reads all source assets/counters/pins losslessly while public SVM remains gated', async () => { + it('reads all source assets/counters/pins losslessly through public SVM reads', async () => { const s = await setup(), stored = await cfg(s.wallet, s.id); expect(stored.config.assets.map((a) => a.token)).toEqual(tokens); @@ -212,7 +212,7 @@ describe('internal prepared SVM backend on v4', () => { expect(stored.chainNamespace).toBe(CHAIN.SOLANA_DEVNET); await expect( owner.agentic.wallet(s.wallet).rules.get(s.id) - ).rejects.toMatchObject({ code: 'CAPABILITY_UNAVAILABLE' }); + ).resolves.toMatchObject({ rule: { format: 'decoded', pins: s.input.terms.pins } }); }); it('runs context, IDL, quote, allowance, wrapping and real token pull/burn as the agent', async () => { const s = await setup(); diff --git a/packages/core/__agw-local__/svm-public.spec.ts b/packages/core/__agw-local__/svm-public.spec.ts new file mode 100644 index 00000000..522ed560 --- /dev/null +++ b/packages/core/__agw-local__/svm-public.spec.ts @@ -0,0 +1,282 @@ +/** Public named-IDL API against actual AGW/URP; destination/gateway are fixtures. */ +import { PublicKey } from '@solana/web3.js'; +import type { Idl } from '@coral-xyz/anchor'; +import { + encodeFunctionData, + parseAbi, + zeroAddress, + type Address, + type Hex, +} from 'viem'; +import { CHAIN, PushChain, type SolanaRule } from '../src'; +import type { AgenticRuntime } from '../src/lib/agentic/runtime'; +import { v4 } from '../src/lib/agentic/contracts/v4'; +import { clearRegistry } from '../src/lib/orchestrator/svm-idl/registry'; +import { startHarness, type Harness } from './harness'; +const program = new PublicKey(Buffer.alloc(32, 51)).toBase58(); +const gateway = new PublicKey(Buffer.alloc(32, 34)).toBase58(); +const idl: Idl = { + address: program, + metadata: { name: 'named', version: '1', spec: '0.1.0' }, + instructions: [ + { + name: 'deposit', + discriminator: [1, 2, 3, 4, 5, 6, 7, 8], + accounts: [{ name: 'cea_authority', writable: true }], + args: [{ name: 'amount', type: 'u64' }], + }, + ], +}; +const TOKEN = parseAbi([ + 'function mint(address,uint256)', + 'function setSourceTokenAddress(string)', + 'function approve(address,uint256) returns (bool)', +]); +const CORE = parseAbi(['function setGasToken(string,address)']); +const rt = (c: PushChain) => + (c as unknown as { agenticRuntime: AgenticRuntime }).agenticRuntime; +describe('public Solana IDL rules on actual v4', () => { + let h: Harness, owner: PushChain, token: Address; + beforeAll(async () => { + h = await startHarness(18561); + owner = await h.client(0); + token = await h.deploy(0, 'HarnessPRC20', 'HarnessFixtures.sol', [ + CHAIN.SOLANA_DEVNET, + 9, + ]); + await h.write(0, token, TOKEN, 'setSourceTokenAddress', ['']); + await h.write(0, h.addresses.universalCore, CORE, 'setGasToken', [ + CHAIN.SOLANA_DEVNET, + token, + ]); + configure(owner); + }); + afterAll(async () => { + clearRegistry(); + await h?.stop(); + }); + function configure(client: PushChain) { + Object.assign(rt(client), { + svmMetadata: { + gateway: async (chain: string) => ({ + chainNamespace: chain, + program: gateway, + }), + mint: async () => { + throw new Error('native-only fixture'); + }, + }, + resolvePrc20: () => token, + quoteOutbound: async () => ({ + protocolFee: BigInt(10) ** BigInt(14), + nativeValueForGas: BigInt(10) ** BigInt(15), + gasLimitUsed: BigInt(100000), + }), + }); + } + const rule = (): SolanaRule => ({ + agent: h.wallets[1].account!.address, + chainNamespace: CHAIN.SOLANA_DEVNET, + validUntil: Math.floor(Date.now() / 1000) + 3600, + maxGasPerCall: BigInt(10) ** BigInt(17), + assets: [ + { token: zeroAddress, maxPerCall: BigInt(5), maxTotal: BigInt(10) }, + ], + allowedInstructions: [ + { + program, + instruction: { idl, name: 'deposit' }, + accounts: [{ name: 'cea_authority', expected: { kind: 'walletCEA' } }], + fields: [{ name: 'amount', max: BigInt(5) }], + }, + ], + }); + it('create/get/list/update/revoke use public named inputs and exact stored reads', async () => { + const made = await owner.agentic.create('public-svm', { rules: [rule()] }); + const wallet = owner.agentic.wallet(made.wallet); + const record = await wallet.rules.get(made.rulesIds[0]); + expect(record).not.toHaveProperty('ref'); + expect(record.rule).toMatchObject({ + format: 'decoded', + dataPins: [{ offset: 8, len: 8, mode: 2 }], + }); + expect((await wallet.rules.list()).rules).toHaveLength(1); + const update = await wallet.rules.update({ + rules: [{ rulesId: made.rulesIds[0], rule: rule() }], + }); + expect(update.rules[0].rulesId).not.toBe(made.rulesIds[0]); + await (await wallet.rules.revoke([update.rules[0].rulesId])).wait(); + expect((await wallet.rules.list()).rules).toHaveLength(0); + }); + it('agent public send uses wallet context, mapped errors and replay metadata', async () => { + const made = await owner.agentic.create('public-send', { rules: [rule()] }); + await h.publicClient.waitForTransactionReceipt({ + hash: await h.wallets[4].sendTransaction({ + to: made.wallet, + value: BigInt(10) ** BigInt(18), + account: h.wallets[4].account!, + chain: h.wallets[4].chain, + }), + }); + await h.write(0, token, TOKEN, 'mint', [made.wallet, BigInt(20)]); + await h.write(0, made.wallet, v4.abis.wallet, 'execute', [ + `0x${'00'.repeat(32)}`, + v4.packSingle({ + target: token, + value: BigInt(0), + data: encodeFunctionData({ + abi: TOKEN, + functionName: 'approve', + args: [h.addresses.gateway, BigInt(20)], + }), + }), + ]); + const agent = await h.client(1, { agenticWallet: made.wallet }); + configure(agent); + const data = (n: bigint) => + PushChain.utils.helpers.encodeTxData({ + abi: idl, + functionName: 'deposit', + args: [n], + }); + const tx = await agent.universal.sendTransaction({ + to: { chain: CHAIN.SOLANA_DEVNET, address: program }, + data: data(BigInt(5)), + value: BigInt(5), + }); + expect(tx.from).toBe(made.wallet); + expect(tx.agentic?.destinationInstruction?.data).toBe(data(BigInt(5))); + expect( + (await h.publicClient.getTransactionReceipt({ hash: tx.hash as Hex })) + .status + ).toBe('success'); + const { adaptTrackedResponse } = await import( + '../src/lib/agentic/response' + ); + const raw: typeof tx = { + ...tx, + agentic: undefined, + from: tx.raw!.from, + to: tx.raw!.to, + data: tx.raw!.data, + }; + await adaptTrackedResponse(rt(agent), raw); + expect(raw.agentic?.destinationInstruction).toEqual( + tx.agentic?.destinationInstruction + ); + await expect( + agent.universal.sendTransaction({ + to: { chain: CHAIN.SOLANA_DEVNET, address: program }, + data: data(BigInt(6)), + value: BigInt(5), + }) + ).rejects.toThrow('SvmDataCeilingExceeded'); + }); + it('owner sends use the wallet CEA without requiring an agent rule', async () => { + const made = await owner.agentic.create('svm-owner', { rules: [] }); + await h.publicClient.waitForTransactionReceipt({ + hash: await h.wallets[4].sendTransaction({ + to: made.wallet, + value: BigInt(10) ** BigInt(18), + account: h.wallets[4].account!, + chain: h.wallets[4].chain, + }), + }); + const sender = await h.client(0, { agenticWallet: made.wallet }); + configure(sender); + const tx = await sender.universal.sendTransaction({ + to: { chain: CHAIN.SOLANA_DEVNET, address: program }, + data: PushChain.utils.helpers.encodeTxData({ + abi: idl, + functionName: 'deposit', + args: [BigInt(0)], + }), + }); + expect(tx.agentic?.door).toBe('owner'); + expect(tx.agentic?.rulesId).toBeUndefined(); + expect( + (await h.publicClient.getTransactionReceipt({ hash: tx.hash as Hex })) + .status + ).toBe('success'); + }); + it('SPL and output mints derive protected wallet ATAs through public grants', async () => { + const mint = new PublicKey(Buffer.alloc(32, 68)).toBase58(); + const output = new PublicKey(Buffer.alloc(32, 85)).toBase58(); + const spl = await h.deploy(0, 'HarnessPRC20', 'HarnessFixtures.sol', [ + CHAIN.SOLANA_DEVNET, + 6, + ]); + await h.write(0, spl, TOKEN, 'setSourceTokenAddress', [mint]); + const source = await h.client(0); + configure(source); + Object.assign(rt(source), { + resolvePrc20: () => spl, + svmMetadata: { + gateway: async (chain: string) => ({ + chainNamespace: chain, + program: gateway, + }), + mint: async (_chain: string, address: string) => ({ + mint: address, + tokenProgram: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', + }), + }, + }); + const input = rule(); + input.assets = [{ token: mint, maxPerCall: BigInt(5) }]; + input.outputTokens = [output]; + input.allowedInstructions[0].instruction = { + idl: { + ...idl, + instructions: [ + { + ...idl.instructions[0], + accounts: [ + { name: 'cea_authority' }, + { name: 'inputAta', writable: true }, + { name: 'outputAta', writable: true }, + ], + }, + ], + }, + name: 'deposit', + }; + input.allowedInstructions[0].accounts.push( + { name: 'inputAta', expected: { kind: 'walletATA', token: mint } }, + { name: 'outputAta', expected: { kind: 'walletATA', token: output } } + ); + const made = await source.agentic.create('public-spl', { rules: [input] }); + const read = await source.agentic + .wallet(made.wallet) + .rules.get(made.rulesIds[0]); + if (!('format' in read.rule)) + throw new Error('expected decoded Solana rule'); + expect(read.rule.ceaAccounts).toHaveLength(3); + expect(read.rule.pins.map((p) => p.expected)).toEqual( + read.rule.ceaAccounts + ); + expect(read.rule.assets[0].maxTotal).toBe( + BigInt(2) ** BigInt(256) - BigInt(1) + ); + }); + it('invalid named input and removed ref never submit a transaction', async () => { + const before = await h.publicClient.getTransactionCount({ + address: h.wallets[0].account!.address, + }); + const r = rule(); + r.allowedInstructions[0].accounts[0].name = 'typo'; + await expect( + owner.agentic.create('invalid', { rules: [r] }) + ).rejects.toThrow('unknown IDL account'); + await expect( + owner.agentic.create('removed-ref', { + rules: [{ ...rule(), ref: `0x${'11'.repeat(32)}` } as never], + }) + ).rejects.toThrow('ref is not supported'); + expect( + await h.publicClient.getTransactionCount({ + address: h.wallets[0].account!.address, + }) + ).toBe(before); + }); +}); diff --git a/packages/core/__e2e__/agw/multi-asset-svm.spec.ts b/packages/core/__e2e__/agw/multi-asset-svm.spec.ts deleted file mode 100644 index f7a9e281..00000000 --- a/packages/core/__e2e__/agw/multi-asset-svm.spec.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** SVM public mapping/cluster acceptance remains pending; wire structs are delivered. */ -const d = process.env['AGW_E2E'] === '1' ? describe : describe.skip; - -d('agw pending svm', () => { - it.todo( - 'svm: wallet CEA PDA / token accounts derived from the wallet and registry gateway' - ); - it.todo( - 'svm: program/discriminator allow-list and account/data pins enforced on a real destination' - ); - it.todo('svm: aggregator substitution and ratio floors rejected'); -}); diff --git a/packages/core/__e2e__/agw/native-policy-extended.spec.ts b/packages/core/__e2e__/agw/native-policy-extended.spec.ts index 544a2a1e..72c31502 100644 --- a/packages/core/__e2e__/agw/native-policy-extended.spec.ts +++ b/packages/core/__e2e__/agw/native-policy-extended.spec.ts @@ -1,5 +1,5 @@ -/** Explicit limits only: these cases do not choose pending omission defaults or raw-input policy. */ -import { PushChain, AgenticRevertError } from '../../src'; +/** Native policy limits, confirmed zero defaults and lossless raw-offset reuse. */ +import { PushChain, AgenticRevertError, type NativeRule } from '../../src'; import { encodeFunctionData, erc20Abi, type Address } from 'viem'; import { getNativePRC20ForChain } from '../../src/lib/orchestrator/internals/helpers'; import { readNativeCounters } from '../shared/agw-state'; @@ -25,15 +25,17 @@ d('agw extended native policy', () => { async function fixture( balance = BigInt(50), maxCalls = 2, - total = BigInt(15) + total = BigInt(15), + omitPc = false ) { const rule = { agent: f.agentAddress, target: token, selector: 'transfer(address,uint256)' as const, validUntil: inSeconds(3600), - maxValuePerCall: BigInt(0), - maxValueTotal: BigInt(0), + ...(omitPc + ? {} + : { maxValuePerCall: BigInt(0), maxValueTotal: BigInt(0) }), maxCalls, pins: [{ arg: 0, expected: f.ownerAddress }], amount: { arg: 1, maxPerCall: BigInt(10), maxTotal: total }, @@ -207,4 +209,69 @@ d('agw extended native policy', () => { }) ).toBe(before); }); + it('9. omitted PC limits forbid value while still allowing a token transfer', async () => { + const s = await fixture(BigInt(5), 3, BigInt(15), true); + await f.fundPC(s.wallet, BigInt(10)); + const record = await f.owner.agentic + .wallet(s.wallet) + .rules.get(s.rulesIds[0]); + expect(record.rule).toMatchObject({ + maxValuePerCall: BigInt(0), + maxValueTotal: BigInt(0), + }); + await refused(s, () => s.send(BigInt(1), f.ownerAddress, BigInt(1)), 'ValueExceedsCap'); + const sent = await s.send(BigInt(1)); + expect((await sent.wait()).status).toBe(1); + expect(await s.counters()).toMatchObject({ + valueSpent: BigInt(0), + amountSpent: BigInt(1), + }); + f.evidence('zero-pc-defaults', { wallet: s.wallet, txHash: sent.hash }); + }); + it('10. decoded raw-offset rules can be granted again without fabricated ref metadata', async () => { + const s = await fixture(BigInt(0)); + const original = await f.owner.agentic + .wallet(s.wallet) + .rules.get(s.rulesIds[0]); + expect(original).not.toHaveProperty('ref'); + const made = await f.owner.agentic.create('raw-offset-reuse', { + rules: [original.rule as NativeRule], + }); + const reread = await f.owner.agentic + .wallet(made.wallet) + .rules.get(made.rulesIds[0]); + expect(reread.rule).toEqual(original.rule); + expect(reread).not.toHaveProperty('ref'); + f.evidence('raw-offset-reuse', { + wallet: made.wallet, + txHash: made.tx.hash, + }); + }); + it('11. removed ref and conflicting argument-offset inputs fail before signing', async () => { + const nonce = await f.push.getTransactionCount({ address: f.ownerAddress }); + const rule = { + agent: f.agentAddress, + target: token, + selector: 'transfer(address,uint256)', + validUntil: inSeconds(3600), + }; + await expect( + f.owner.agentic.create('invalid-ref', { + rules: [{ ...rule, ref: `0x${'11'.repeat(32)}` } as never], + }) + ).rejects.toMatchObject({ code: 'INVALID_RULE' }); + await expect( + f.owner.agentic.create('invalid-pin', { + rules: [ + { + ...rule, + pins: [{ arg: 0, offset: 4, expected: `0x${'00'.repeat(32)}` }], + } as never, + ], + }) + ).rejects.toMatchObject({ code: 'INVALID_RULE' }); + expect(await f.push.getTransactionCount({ address: f.ownerAddress })).toBe( + nonce + ); + }); }); diff --git a/packages/core/__e2e__/agw/svm-public.spec.ts b/packages/core/__e2e__/agw/svm-public.spec.ts new file mode 100644 index 00000000..fb2bcb00 --- /dev/null +++ b/packages/core/__e2e__/agw/svm-public.spec.ts @@ -0,0 +1,290 @@ +/** Public named-IDL lifecycle and destination delivery on Donut/Solana devnet. */ +import '@e2e/shared/setup'; +import { PushChain, type SolanaRule } from '../../src'; +import type { Idl } from '@coral-xyz/anchor'; +import { PublicKey, Keypair } from '@solana/web3.js'; +import bs58 from 'bs58'; +import { + createPublicClient, + http, + erc20Abi, + encodeFunctionData, + parseAbi, + parseEther, + zeroAddress, + type Address, + type Hex, +} from 'viem'; +import { privateKeyToAccount } from 'viem/accounts'; +import { CHAIN, PUSH_NETWORK } from '../../src/lib/constants/enums'; +import { CHAIN_INFO, getPushViemChain } from '../../src/lib/constants/chain'; +import counterIdl from '../../src/lib/orchestrator/svm-idl/__fixtures__/test_counter.idl.json'; +import { setupAgw, evmClient, inSeconds, type AgwFixture } from './_fixture'; +import { loadAgwManifest, verifyAgwManifest } from './_manifest'; +import { + inspectSvmWirePrograms, + svmWireConnection, + SVM_WIRE_CHAIN, + SVM_WIRE_PROGRAM, + SVM_WIRE_COUNTER, +} from '../shared/agw-svm-preflight'; + +const d = process.env['AGW_E2E'] === '1' ? describe : describe.skip; +const amount = BigInt(10_000), + pc = parseEther('21'); +d('agw public svm', () => { + let f: AgwFixture, + wallet: Address, + id: Hex, + token: Address, + agent: PushChain, + recipient: PublicKey, + cea: PublicKey, + idl: Idl; + const sol = svmWireConnection(); + const rule = (): SolanaRule => ({ + agent: f.agentAddress, + chainNamespace: SVM_WIRE_CHAIN, + validUntil: inSeconds(3600), + assets: [{ token: zeroAddress, maxPerCall: amount, maxTotal: amount }], + maxGasPerCall: parseEther('20'), + allowedInstructions: [ + { + program: SVM_WIRE_PROGRAM, + instruction: { idl, name: 'receive_sol' }, + accounts: [ + { + name: 'counter', + expected: { kind: 'address', address: SVM_WIRE_COUNTER.toBase58() }, + }, + { + name: 'recipient', + expected: { kind: 'address', address: recipient.toBase58() }, + }, + { name: 'cea_authority', expected: { kind: 'walletCEA' } }, + { + name: 'system_program', + expected: { + kind: 'address', + address: PublicKey.default.toBase58(), + }, + }, + ], + fields: [{ name: 'amount', max: amount }], + }, + ], + }); + const data = (value = amount, source = idl) => + PushChain.utils.helpers.encodeTxData({ + abi: source, + functionName: 'receive_sol', + args: [value], + }); + beforeAll(async () => { + await inspectSvmWirePrograms(sol); + const manifest = loadAgwManifest(); + if (manifest.network !== PUSH_NETWORK.TESTNET_DONUT) + throw new Error('Public SVM fixture requires Donut'); + if ( + parseEther(process.env['AGW_E2E_AGENT_PC'] ?? '0.5') > parseEther('0.5') + ) + throw new Error('Agent funding exceeds fixture budget'); + const key = process.env['SOLANA_PRIVATE_KEY']; + if (!key) throw new Error('Missing recipient identity'); + try { + recipient = Keypair.fromSecretKey(bs58.decode(key)).publicKey; + } catch { + recipient = Keypair.fromSecretKey( + Uint8Array.from(JSON.parse(key)) + ).publicKey; + } + const recipientInfo = await sol.getAccountInfo(recipient); + if ( + !recipientInfo || + recipientInfo.executable || + !recipientInfo.owner.equals(PublicKey.default) + ) + throw new Error('Owned recipient must be an existing System account'); + const push = createPublicClient({ + chain: getPushViemChain(CHAIN.PUSH_TESTNET_DONUT), + transport: http(CHAIN_INFO[CHAIN.PUSH_TESTNET_DONUT].defaultRPC[0]), + }); + await verifyAgwManifest(push, manifest); + const ownerKey = process.env['PUSH_PRIVATE_KEY'] as Hex; + if (!ownerKey) throw new Error('Missing owner'); + const ownerAddress = privateKeyToAccount(ownerKey).address; + token = await push.readContract({ + address: '0x00000000000000000000000000000000000000C0', + abi: parseAbi([ + 'function gasTokenPRC20ByChainNamespace(string) view returns (address)', + ]), + functionName: 'gasTokenPRC20ByChainNamespace', + args: [SVM_WIRE_CHAIN], + }); + if ( + (await push.getBalance({ address: ownerAddress })) < + pc + parseEther('2') || + (await push.readContract({ + address: token, + abi: erc20Abi, + functionName: 'balanceOf', + args: [ownerAddress], + })) < amount + ) + throw new Error('Insufficient bounded fixture funds'); + idl = JSON.parse(JSON.stringify(counterIdl)) as Idl; + const receive = idl.instructions.find((i) => i.name === 'receive_sol')!; + const destination = receive.accounts.find((a) => a.name === 'recipient')!; + Object.assign(destination, { address: recipient.toBase58() }); + f = await setupAgw(); + const made = await f.owner.agentic.create('public-idl-svm', { + rules: [rule()], + }); + wallet = made.wallet; + id = made.rulesIds[0]; + const record = await f.owner.agentic.wallet(wallet).rules.get(id); + if (!('expectedCEA' in record.rule)) + throw new Error('Missing decoded destination account'); + cea = new PublicKey(Buffer.from(record.rule.expectedCEA.slice(2), 'hex')); + await f.fundPC(wallet, pc); + await ( + await f.owner.universal.sendTransaction({ + to: token, + data: encodeFunctionData({ + abi: erc20Abi, + functionName: 'transfer', + args: [wallet, amount], + }), + }) + ).wait(); + const owner = await evmClient( + ownerKey, + CHAIN.PUSH_TESTNET_DONUT, + manifest.network, + wallet + ); + await ( + await owner.universal.sendTransaction({ + to: token, + data: encodeFunctionData({ + abi: erc20Abi, + functionName: 'approve', + args: [manifest.addresses.gateway, amount], + }), + }) + ).wait(); + agent = await f.agent(wallet); + f.evidence('public-svm-setup', { + wallet, + id, + grantHash: made.tx.hash, + cea: cea.toBase58(), + recipient: recipient.toBase58(), + }); + }, 900_000); + afterAll(() => f?.teardown()); + it('1. named IDL grant reads exact constraints and replaces atomically', async () => { + const handle = f.owner.agentic.wallet(wallet), + record = await handle.rules.get(id); + expect(record).not.toHaveProperty('ref'); + expect(record.rule).toMatchObject({ + format: 'decoded', + dataPins: [{ offset: 8, len: 8, mode: 2 }], + }); + const count = (await handle.checkpoints()).checkpoints.length; + const updated = await handle.rules.update({ + rules: [{ rulesId: id, rule: rule() }], + }); + const previous = id; + id = updated.rules[0].rulesId; + await expect(handle.rules.get(previous)).rejects.toMatchObject({ + code: 'RULE_NOT_FOUND', + }); + expect((await handle.checkpoints()).checkpoints.length).toBe(count + 5); + f.evidence('public-svm-replacement', { + wallet, + id, + txHash: updated.tx.hash, + }); + }); + it('2. public send confirms actual CEA transfer and preserves replay identity', async () => { + const tx = await agent.universal.sendTransaction({ + to: { chain: SVM_WIRE_CHAIN, address: SVM_WIRE_PROGRAM }, + value: amount, + gasLimit: BigInt(0), + data: data(), + }); + f.evidence('public-svm-submitted', { wallet, id, hash: tx.hash }); + const receipt = await tx.wait({ outboundTimeoutMs: 600_000 }); + expect(receipt.externalStatus).toBe('success'); + expect(receipt.from).toBe(wallet); + const destination = await sol.getParsedTransaction( + receipt.externalTxHash!, + { commitment: 'confirmed', maxSupportedTransactionVersion: 0 } + ); + expect(destination?.meta?.err).toBeNull(); + expect( + destination?.meta?.innerInstructions?.some((g) => + g.instructions.some( + (ix) => + 'parsed' in ix && + ix.program === 'system' && + ix.parsed.type === 'transfer' && + ix.parsed.info.source === cea.toBase58() && + ix.parsed.info.destination === recipient.toBase58() && + BigInt(ix.parsed.info.lamports) === amount + ) + ) + ).toBe(true); + const replay = await f.owner.universal.trackTransaction(tx.hash); + expect(replay.from).toBe(wallet); + expect(replay.agentic?.destinationInstruction).toEqual( + tx.agentic?.destinationInstruction + ); + expect( + (await replay.wait({ outboundTimeoutMs: 600_000 })).externalTxHash + ).toBe(receipt.externalTxHash); + f.evidence('public-svm-delivered', { + wallet, + hash: tx.hash, + destinationHash: receipt.externalTxHash, + instruction: tx.agentic?.destinationInstruction, + }); + }, 900_000); + it('3. substituted named accounts and excessive instruction amounts fail before signing', async () => { + const nonce = await f.push.getTransactionCount({ address: f.agentAddress }); + const wrong = JSON.parse(JSON.stringify(idl)) as Idl; + Object.assign( + wrong.instructions + .find((i) => i.name === 'receive_sol')! + .accounts.find((a) => a.name === 'recipient')!, + { address: PublicKey.default.toBase58() } + ); + await expect( + agent.universal.sendTransaction({ + to: { chain: SVM_WIRE_CHAIN, address: SVM_WIRE_PROGRAM }, + data: data(BigInt(1), wrong), + }) + ).rejects.toThrow('SvmAccountPinMismatch'); + await expect( + agent.universal.sendTransaction({ + to: { chain: SVM_WIRE_CHAIN, address: SVM_WIRE_PROGRAM }, + data: data(amount + BigInt(1)), + }) + ).rejects.toThrow('SvmDataCeilingExceeded'); + expect(await f.push.getTransactionCount({ address: f.agentAddress })).toBe( + nonce + ); + }); + it('4. public revoke removes the Solana rule and subsequent sends are refused', async () => { + const handle = f.owner.agentic.wallet(wallet); + await (await handle.rules.revoke([id])).wait(); + expect((await handle.rules.list()).rules).toHaveLength(0); + await expect( + agent.universal.sendTransaction({ + to: { chain: SVM_WIRE_CHAIN, address: SVM_WIRE_PROGRAM }, + data: data(), + }) + ).rejects.toMatchObject({ code: 'NO_RULES_FOR_CHAIN' }); + }); +}); diff --git a/packages/core/__e2e__/agw/v4-multiasset.spec.ts b/packages/core/__e2e__/agw/v4-multiasset.spec.ts index 1d673b1c..2e0b30ba 100644 --- a/packages/core/__e2e__/agw/v4-multiasset.spec.ts +++ b/packages/core/__e2e__/agw/v4-multiasset.spec.ts @@ -1,4 +1,5 @@ /** Opt-in funded Donut acceptance. Nothing in this file runs in unit/local validation. */ +import type { UniversalRule } from '../../src'; import { parseEther } from 'viem'; import { CHAIN } from '../../src/lib/constants/enums'; import { MOVEABLE_TOKEN_CONSTANTS } from '../../src/lib/constants/tokens'; @@ -24,7 +25,7 @@ d('agw v4 multi-asset', () => { }); afterAll(() => f?.teardown()); it('1. public create reads and replaces an ordered two-token rule', async () => { - const rule = { + const rule: UniversalRule = { agent: f.agentAddress, chainNamespace: chain, validUntil: inSeconds(3600), diff --git a/packages/core/__e2e__/ci/preflight.ts b/packages/core/__e2e__/ci/preflight.ts index 37b04763..f5e08334 100644 --- a/packages/core/__e2e__/ci/preflight.ts +++ b/packages/core/__e2e__/ci/preflight.ts @@ -346,7 +346,7 @@ function renderTable(rows: Row[]): void { process.exit(1); } } - if (scenarios.some((s) => s.group === 'agw-svm-wire')) { + if (scenarios.some((s) => s.group === 'agw-svm-wire' || s.file === '__e2e__/agw/svm-public.spec.ts')) { const { inspectSvmWirePrograms, svmWireConnection } = await import('../shared/agw-svm-preflight'); await inspectSvmWirePrograms(svmWireConnection(solRpc)); console.log('Solana wire fixture verified read-only before funding.'); diff --git a/packages/core/__e2e__/ci/suite.ts b/packages/core/__e2e__/ci/suite.ts index f09ce1db..8154079e 100644 --- a/packages/core/__e2e__/ci/suite.ts +++ b/packages/core/__e2e__/ci/suite.ts @@ -1040,6 +1040,12 @@ export const SCENARIOS: Scenario[] = [ env: { AGW_E2E: '1' }, }, + ...Array.from({ length: 4 }, (_, i) => ({ + id: `agw-public-svm-${i + 1}`, group: 'agw' as const, + file: '__e2e__/agw/svm-public.spec.ts', grep: `agw public svm ${i + 1}\\.`, + needs: { masterPC: '25', masterPSOL: '0.00001' }, env: { AGW_E2E: '1' }, + })), + // Extended AGW tests are opt-in and use bounded per-scenario testnet budgets. ...[ ['prefunding', '1\\. prefunding', '11'], @@ -1056,7 +1062,7 @@ export const SCENARIOS: Scenario[] = [ needs: { masterPC: pc }, env: { AGW_E2E: '1' }, })), - ...Array.from({ length: 8 }, (_, i) => ({ + ...Array.from({ length: 11 }, (_, i) => ({ id: `agw-extended-native-policy-${i + 1}`, group: 'agw' as const, file: F.agwExtendedNative, diff --git a/packages/core/scripts/agw-verify.js b/packages/core/scripts/agw-verify.js index ada651e2..3ac74f72 100644 --- a/packages/core/scripts/agw-verify.js +++ b/packages/core/scripts/agw-verify.js @@ -28,7 +28,7 @@ run('units', node, [ '--config', 'packages/core/jest.config.ts', '--runInBand', - '--testPathPattern=agentic|outbound-(confirmation-gate|svm-confirmation)|svm-idl', + '--testPathPattern=agentic|outbound-(confirmation-gate|svm-confirmation)|svm-idl|evm-client.batch-gas', ]); for (const kind of ['lib', 'spec', 'agw-local']) run(`types-${kind}`, node, [ diff --git a/packages/core/src/lib/agentic/__tests__/codec.spec.ts b/packages/core/src/lib/agentic/__tests__/codec.spec.ts index 5f715dcf..b5d2260e 100644 --- a/packages/core/src/lib/agentic/__tests__/codec.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/codec.spec.ts @@ -22,7 +22,7 @@ import { } from '../codec/session'; import { parseSelector, VALUE_ONLY_SELECTOR } from '../codec/selectors'; import { argumentOffset, headSize } from '../codec/abi-layout'; -import { AGENTIC_DEFAULTS, UINT256_MAX } from '../codec/defaults'; +import { UINT256_MAX } from '../codec/defaults'; import { v4 } from '../contracts/v4'; import { AGW_ABI } from '../contracts/abi/v4'; import { AGENTIC_ERROR_CODE } from '../errors'; @@ -139,7 +139,7 @@ describe('native rule codec', () => { expect(env.chainNamespace).toBe(v.nativeChain); const back = decodeNativeTerms(env.body); expect(back).toEqual({ ...terms, validUntil: terms.validUntil }); - const rule = nativeTermsToRule(back, v.rule.agent, `0x${'00'.repeat(32)}`); + const rule = nativeTermsToRule(back, v.rule.agent); // Stored terms carry offsets, not an ABI: decoded rules report the raw offset form. expect(rule.pins).toEqual([ { offset: 4, expected: terms.pins[0].expected.toLowerCase() }, @@ -149,7 +149,7 @@ describe('native rule codec', () => { maxPerCall: BigInt(10), maxTotal: BigInt(100), }); - expect(rule.ref).toBeUndefined(); + expect(rule).not.toHaveProperty('ref'); // …and the decoded rule re-encodes to identical terms with only its 4-byte selector. expect(nativeRuleToTerms(rule, { nowSeconds: NOW }).terms).toEqual(terms); }); @@ -164,7 +164,7 @@ describe('native rule codec', () => { }; const { terms } = nativeRuleToTerms(input, { nowSeconds: NOW }); expect(terms.pins[0].offset).toBe(4 + 64); - const decoded = nativeTermsToRule(terms, agent, `0x${'00'.repeat(32)}`); + const decoded = nativeTermsToRule(terms, agent); expect(decoded.pins).toEqual([ { offset: 68, expected: terms.pins[0].expected }, ]); @@ -224,7 +224,7 @@ describe('native rule codec', () => { ).toEqual([{ offset: 36, expected: `0x${'00'.repeat(31)}01` }]); }); - it('applies the single provisional A03 defaults table for omitted limits', () => { + it('applies confirmed zero PC defaults and independent token/call defaults', () => { const { terms } = nativeRuleToTerms( { agent, @@ -236,13 +236,19 @@ describe('native rule codec', () => { { nowSeconds: NOW } ); expect(terms.maxValuePerCall).toBe( - AGENTIC_DEFAULTS.native.maxValuePerCall.value + BigInt(0) ); expect(terms.maxValueTotal).toBe(BigInt(0)); expect(terms.maxCalls).toBe(0); expect(terms.amount.maxTotal).toBe(UINT256_MAX); }); + it('rejects ambiguous arg-plus-offset authoring for both pins and amount', () => { + const rule = { agent, target, selector: 'transfer(address,uint256)' as const, validUntil: NOW + 10 }; + expect(() => nativeRuleToTerms({ ...rule, pins: [{ arg: 0, offset: 4, expected: `0x${'00'.repeat(32)}` } as never] }, { nowSeconds: NOW })).toThrow('mutually exclusive'); + expect(() => nativeRuleToTerms({ ...rule, amount: { arg: 1, offset: 36, maxPerCall: BigInt(1) } as never }, { nowSeconds: NOW })).toThrow('mutually exclusive'); + }); + it('keeps an explicit zero as zero', () => { const { terms } = nativeRuleToTerms( { diff --git a/packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts b/packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts index 970a7f5a..477d94e8 100644 --- a/packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts @@ -4,7 +4,6 @@ import { MOVEABLE_TOKEN_CONSTANTS } from '../../constants/tokens'; import { getPRC20Address } from '../../universal/prc20-address'; import { encodeUniversalTerms } from '../codec/universal-terms'; import { buildSession, encodeEnvelope, encodeSession } from '../codec/session'; -import { AgenticCapability } from '../capabilities'; import { prepareRules } from '../codec/rules'; import { validateUniversalRuleShape } from '../codec/universal'; import { V4_CAPABILITIES } from '../deployments'; @@ -104,17 +103,9 @@ describe('prepareRules — spec 1.b checks before any signature', () => { ]); }); - it('a ref is refused (never silently dropped) without the grant-ref capability (A07)', () => { - expect(() => - prepareRules([native({ ref: `0x${'99'.repeat(32)}` })], ctx) - ).toThrow( - expect.objectContaining({ - code: AGENTIC_ERROR_CODE.CAPABILITY_UNAVAILABLE, - details: expect.objectContaining({ - capability: AgenticCapability.GRANT_REF, - }), - }) - ); + it('removed ref inputs fail explicitly instead of being silently dropped', () => { + expect(() => prepareRules([{ ...native(), ref: `0x${'99'.repeat(32)}` } as never], ctx)) + .toThrow(expect.objectContaining({ code: AGENTIC_ERROR_CODE.INVALID_RULE })); }); it('refuses infrastructure targets the contracts would reject', () => { @@ -227,7 +218,7 @@ describe('universal rules — validated, then capability-gated (A01, A05)', () = ).toThrow(/signature/); }); - it('requires resolved wallet/token context; SVM mapping stays explicitly gated', () => { + it('requires resolved wallet/token context and named SVM IDL inputs', () => { expect(() => prepareRules([universal()], ctx)).toThrow( expect.objectContaining({ code: AGENTIC_ERROR_CODE.INVALID_RULE, @@ -237,16 +228,14 @@ describe('universal rules — validated, then capability-gated (A01, A05)', () = prepareRules( [ universal({ - chainNamespace: 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1', + chainNamespace: 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1' as never, }), ], ctx ) ).toThrow( expect.objectContaining({ - details: expect.objectContaining({ - capability: AgenticCapability.UNIVERSAL_SVM_RULES, - }), + code: AGENTIC_ERROR_CODE.INVALID_RULE, }) ); }); diff --git a/packages/core/src/lib/agentic/__tests__/send.spec.ts b/packages/core/src/lib/agentic/__tests__/send.spec.ts index 71b24327..2f459d28 100644 --- a/packages/core/src/lib/agentic/__tests__/send.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/send.spec.ts @@ -11,7 +11,6 @@ import { CHAIN, PUSH_NETWORK } from '../../constants/enums'; import { UNIVERSAL_GATEWAY_PC, ERC20_EVM } from '../../constants/abi'; import { PushChainExecutionError } from '../../orchestrator/internals/errors'; import { PROGRESS_HOOK } from '../../progress-hook/progress-hook.types'; -import { AgenticCapability } from '../capabilities'; import type { AgenticExecutionContext } from '../context'; import { currentGeneration, resetAgenticGenerations } from '../deployments'; import { v4 } from '../contracts/v4'; @@ -478,7 +477,7 @@ describe('EVM outbound composition from the wallet', () => { ); }); - it('SVM destinations are capability-gated', async () => { + it('SVM destinations reject EVM-width program addresses', async () => { const s = universalSetup(); const rt = mockRuntime(s.fake, { signer: ADDR.agent }); await expect( @@ -488,7 +487,7 @@ describe('EVM outbound composition from the wallet', () => { { to: { address: ADDR.target, chain: CHAIN.SOLANA_DEVNET }, data } ) ).rejects.toMatchObject({ - details: { capability: AgenticCapability.UNIVERSAL_SVM_RULES }, + code: AGENTIC_ERROR_CODE.INVALID_RULE, }); }); diff --git a/packages/core/src/lib/agentic/__tests__/svm-idl.spec.ts b/packages/core/src/lib/agentic/__tests__/svm-idl.spec.ts new file mode 100644 index 00000000..e752336d --- /dev/null +++ b/packages/core/src/lib/agentic/__tests__/svm-idl.spec.ts @@ -0,0 +1,177 @@ +import type { Idl } from '@coral-xyz/anchor'; +import { PublicKey } from '@solana/web3.js'; +import { encodeAnchorIxData } from '../../orchestrator/svm-idl/ix-encoder'; +import type { SolanaRule } from '../agentic.types'; +import { compileSvmIdlRule, type SvmResolvedContext } from '../codec/svm-idl'; +import { SvmDataPinMode } from '../codec/svm-terms'; +import { + encodeAgwSvmPayload, + validateAgwSvmPayload, +} from '../execution/svm-payload'; +import { ADDR } from './fake-chain'; +import type { Hex } from 'viem'; +const key = (c: string) => `0x${c.repeat(64)}` as Hex; +const program = key('3'), + cea = key('4'), + mint = key('5'), + ata = key('6'); +const idl: Idl = { + address: new PublicKey(Buffer.from(program.slice(2), 'hex')).toBase58(), + metadata: { name: 'test', version: '1', spec: '0.1.0' }, + instructions: [ + { + name: 'deposit', + discriminator: [1, 2, 3, 4, 5, 6, 7, 8], + accounts: [ + { name: 'cea', writable: true }, + { name: 'token', writable: true }, + ], + args: [ + { name: 'flag', type: 'u8' }, + { name: 'amount', type: 'u64' }, + { name: 'minimum', type: 'u64' }, + ], + }, + ], +}; +const ctx: SvmResolvedContext = { + expectedCEA: cea, + gatewayProgram: key('2'), + ceaAccounts: [cea, ata], + assets: [ + { token: ADDR.target, maxPerCall: BigInt(10), maxTotal: BigInt(100) }, + ], + tokenAccounts: new Map([[mint, ata]]), +}; +const input = (): SolanaRule => ({ + agent: ADDR.agent, + chainNamespace: 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1', + validUntil: 100, + assets: [], + maxGasPerCall: BigInt(10), + allowedInstructions: [ + { + program, + instruction: { idl, name: 'deposit' }, + accounts: [ + { name: 'cea', expected: { kind: 'walletCEA' } }, + { name: 'token', expected: { kind: 'walletATA', token: mint } }, + ], + fields: [ + { name: 'flag', equals: BigInt(1) }, + { name: 'amount', max: BigInt(10) }, + { + numerator: 'amount', + denominator: 'minimum', + minRatio: { num: BigInt(2), den: BigInt(1) }, + }, + ], + }, + ], +}); +describe('named SVM IDL rule compilation', () => { + it('enforces named constraints against independently Borsh-encoded data', () => { + const terms = compileSvmIdlRule(input(), ctx, 0); + expect(terms.pins.map((p) => p.expected)).toEqual([cea, ata]); + expect(terms.dataPins.map((p) => [p.offset, p.len, p.mode])).toEqual([ + [8, 1, SvmDataPinMode.EQ], + [9, 8, SvmDataPinMode.LTE_LE], + [9, 8, SvmDataPinMode.RATIO_GTE_LE], + ]); + const payload = (amount: bigint, minimum: bigint) => + encodeAgwSvmPayload( + program, + [ + { pubkey: cea, isWritable: true }, + { pubkey: ata, isWritable: true }, + ], + encodeAnchorIxData(idl, 'deposit', [1, amount, minimum]) + ); + expect( + validateAgwSvmPayload(terms, program, payload(BigInt(10), BigInt(5))) + ).toBe(0); + expect(() => + validateAgwSvmPayload(terms, program, payload(BigInt(11), BigInt(5))) + ).toThrow('SvmDataCeilingExceeded'); + expect(() => + validateAgwSvmPayload(terms, program, payload(BigInt(9), BigInt(5))) + ).toThrow('SvmDataRatioNotMet'); + }); + it.each([ + [ + 'unknown account', + (r: SolanaRule) => { + r.allowedInstructions[0].accounts[0].name = 'wrong'; + }, + ], + [ + 'unlisted ATA', + (r: SolanaRule) => { + r.allowedInstructions[0].accounts[1].expected = { + kind: 'walletATA', + token: key('7'), + }; + }, + ], + [ + 'unknown field', + (r: SolanaRule) => { + r.allowedInstructions[0].fields = [{ name: 'wrong', max: BigInt(2) }]; + }, + ], + [ + 'overflow', + (r: SolanaRule) => { + r.allowedInstructions[0].fields = [{ name: 'flag', max: BigInt(256) }]; + }, + ], + [ + 'duplicate instruction', + (r: SolanaRule) => { + r.allowedInstructions.push(r.allowedInstructions[0]); + }, + ], + [ + 'mismatched program', + (r: SolanaRule) => { + r.allowedInstructions[0].program = key('8'); + }, + ], + [ + 'conflicting comparison', + (r: SolanaRule) => { + r.allowedInstructions[0].fields = [ + { name: 'flag', min: BigInt(0), max: BigInt(1) } as never, + ]; + }, + ], + ])('rejects %s', (_name, mutate) => { + const r = input(); + mutate(r); + expect(() => compileSvmIdlRule(r, ctx, 0)).toThrow(); + }); + it.each(['bytes', 'string', { vec: 'u8' }, { defined: { name: 'Unknown' } }])( + 'refuses unsupported layouts %j', + (type) => { + const r = input(); + r.allowedInstructions[0].instruction.idl = { + ...idl, + instructions: [ + { + ...idl.instructions[0], + args: [ + { name: 'prefix', type: type as never }, + ...idl.instructions[0].args, + ], + }, + ], + }; + expect(() => compileSvmIdlRule(r, ctx, 0)).toThrow('layout'); + } + ); + it('does not mutate the caller IDL', () => { + const before = JSON.stringify(idl); + compileSvmIdlRule(input(), ctx, 0); + expect(JSON.stringify(idl)).toBe(before); + }); +}); diff --git a/packages/core/src/lib/agentic/agentic.types.ts b/packages/core/src/lib/agentic/agentic.types.ts index 07b07580..97c8e9b9 100644 --- a/packages/core/src/lib/agentic/agentic.types.ts +++ b/packages/core/src/lib/agentic/agentic.types.ts @@ -1,9 +1,11 @@ /** * Public AGW types — AGW SDK page section 3 (Notion export 2026-10-03 13:23 IST). * - * Provisional public choices are documented on the affected properties and - * remain subject to product and contract confirmation. + * Named-IDL Solana inputs and native/EVM raw offsets follow the October 7 + * decisions. Contract-dependent label editing remains capability-gated. */ +import type { Idl } from '@coral-xyz/anchor'; +import type { SvmTermsWire } from './codec/svm-terms'; import type { MoveableToken } from '../constants/tokens'; import type { UniversalTxResponse } from '../orchestrator/orchestrator.types'; import type { ProgressEvent } from '../progress-hook/progress-hook.types'; @@ -19,22 +21,20 @@ export type Selector = AgenticHex | `${string}(${string})`; export interface NativeRule { /** Push address: an EOA, or the UEA of an external key. Never the owner. */ agent: AgenticAddress; - /** Emitted in RulesGranted when the generation supports it (A07). */ - ref?: AgenticHex; /** Omitted = the connected Push chain. */ chainNamespace?: never; target: AgenticAddress; selector: Selector | 'value-only'; /** Unix seconds. */ validUntil: number; - /** Default 0 (no native value) — provisional, A03. */ + /** Default 0: no native PC value allowance. */ maxValuePerCall?: bigint; - /** Default 0 (no native value) — provisional, A03. */ + /** Default 0: no native PC value allowance. */ maxValueTotal?: bigint; - /** Default 0 (unlimited calls until expiry) — provisional, A03. */ + /** Default 0 (unlimited calls until expiry). */ maxCalls?: number; pins?: ArgPin[]; - /** `maxTotal` default uint256 max (unlimited total) — provisional, A03. */ + /** `maxTotal` default uint256 max (unlimited total). */ amount?: AmountLimit; } @@ -43,13 +43,20 @@ export interface NativeRule { * the selector signature (requires the signature form of `selector`). * `offset` is the raw calldata byte offset, selector included — the form the * contracts store; decoded rules (rules.get/list, decodeRules) always use it - * because stored terms carry no ABI. SDK extension of the page-5 shape. + * because stored terms carry no ABI. Advanced input form; ABI argument indexes are preferred for authoring. */ export type ArgPin = - | { arg: number; expected: AgenticHex | AgenticAddress | bigint } - | { offset: number; expected: AgenticHex }; + | { + arg: number; + offset?: never; + expected: AgenticHex | AgenticAddress | bigint; + } + | { offset: number; arg?: never; expected: AgenticHex }; -export type AmountLimit = ({ arg: number } | { offset: number }) & { +export type AmountLimit = ( + | { arg: number; offset?: never } + | { offset: number; arg?: never } +) & { maxPerCall: bigint; maxTotal?: bigint; }; @@ -67,16 +74,15 @@ export interface AllowedCall { selector: Selector; /** Argument index whose address must be the wallet's destination account. */ beneficiary?: number; - /** Exact stored calldata offset for lossless decoded rules; mutually exclusive with beneficiary. Public form pending H4.5. */ + /** Exact stored calldata offset for lossless decoded rules; mutually exclusive with beneficiary. Approved advanced input form. */ beneficiaryOffset?: number; - /** Default 0 — provisional, A03. */ + /** Default 0. */ maxValue?: bigint; } export interface UniversalRule { agent: AgenticAddress; - ref?: AgenticHex; - chainNamespace: ForeignChainNamespace; + chainNamespace: `eip155:${string}`; assets: AssetCap[]; /** PC (wei) per outbound for the destination leg. */ maxGasPerCall: bigint; @@ -85,7 +91,50 @@ export interface UniversalRule { allowedCalls: AllowedCall[]; } -export type Rule = NativeRule | UniversalRule; +/** An address may be base58 or a 32-byte hex Solana public key. */ +export type SvmAccountRef = + | { kind: 'walletCEA' } + | { kind: 'walletATA'; token: string } + | { kind: 'address'; address: string }; +export type SvmFieldConstraint = + | { name: string; equals: AgenticHex | bigint | boolean } + | { name: string; min: bigint } + | { name: string; max: bigint } + | { + numerator: string; + denominator: string; + minRatio: { num: bigint; den: bigint }; + }; +export interface SvmInstructionRule { + program: string; + instruction: { idl: Idl; name: string }; + /** Top-level account names from a supported Anchor IDL; optional/nested accounts are rejected. */ + accounts: { name: string; expected: SvmAccountRef }[]; + /** Fixed-width fields only; unsupported/variable layouts fail before signing. */ + fields?: SvmFieldConstraint[]; +} +export interface SolanaRule { + agent: AgenticAddress; + chainNamespace: `solana:${string}`; + validUntil: number; + assets: { + token: MoveableToken | string; + maxPerCall: bigint; + maxTotal?: bigint; + }[]; + maxGasPerCall: bigint; + /** Additional output mints whose wallet ATAs must be protected. */ + outputTokens?: string[]; + allowedInstructions: SvmInstructionRule[]; +} +/** Stored constraints contain no IDL; supply a named SolanaRule when replacing. */ +export interface DecodedSolanaRule extends Omit { + format: 'decoded'; + agent: AgenticAddress; + chainNamespace: `solana:${string}`; + assets: { token: string; maxPerCall: bigint; maxTotal: bigint }[]; +} +export type Rule = NativeRule | UniversalRule | SolanaRule; export interface RulesRecord { rulesId: AgenticHex; @@ -93,8 +142,7 @@ export interface RulesRecord { chainNamespace: string; agent: AgenticAddress; validUntil: number; - ref: AgenticHex; - rule: Rule; + rule: Rule | DecodedSolanaRule; } export interface CreateOptions { @@ -140,7 +188,7 @@ export interface AgenticWallet { address: AgenticAddress; info(): Promise; owner(): Promise<{ owner: AgenticAddress }>; - /** PROPOSED (page 1 item 10); capability-gated, A07. */ + /** Pending contract delivery; unavailable on the currently registered deployment. */ setLabel( label: string, opts?: { progressHook?: AgenticProgressHook } @@ -208,6 +256,12 @@ export interface AgenticTxMetadata { data: AgenticHex; value: bigint; }[]; + /** SVM instruction executed by the wallet's destination CEA. */ + destinationInstruction?: { + program: AgenticHex; + data: AgenticHex; + accounts: readonly { pubkey: AgenticHex; isWritable: boolean }[]; + }; /** Ordered actions in a native agent batch; to/data/value summarize its first action. */ nativeCalls?: readonly { to: AgenticAddress; diff --git a/packages/core/src/lib/agentic/capabilities.ts b/packages/core/src/lib/agentic/capabilities.ts index 0aa78796..c3d3b5b0 100644 --- a/packages/core/src/lib/agentic/capabilities.ts +++ b/packages/core/src/lib/agentic/capabilities.ts @@ -27,10 +27,8 @@ export enum AgenticCapability { UNIVERSAL_EVM_RULES = 'universalEvmRules', /** Per-token expected-spend assertion for universal replacement. A05. */ ASSERT_SPENT_UNIVERSAL_MULTI = 'assertSpentUniversalMulti', - /** SVM destination rulebook through the public Rule type. A05/A07, Harsh H4.4. */ + /** Named-IDL Solana authoring, exact decoded reads and instruction execution. */ UNIVERSAL_SVM_RULES = 'universalSvmRules', - /** Grant reference emitted in RulesGranted. A07. */ - GRANT_REF = 'grantRef', /** Editable wallet label (setLabel / LabelSet). A07. */ SET_LABEL = 'setLabel', } @@ -58,9 +56,7 @@ export const CAPABILITY_DEPENDENCY: Record = { [AgenticCapability.ASSERT_SPENT_UNIVERSAL_MULTI]: 'universal expected-spend assertions are unavailable for this configuration', [AgenticCapability.UNIVERSAL_SVM_RULES]: - 'SVM wire types are delivered; public SDK mapping/composition remains pending (H4.4)', - [AgenticCapability.GRANT_REF]: - 'the selected generation has no grant reference parameter/event (A07)', + 'SVM rules are unavailable for this generation', [AgenticCapability.SET_LABEL]: 'the selected generation has no editable label (A07; labels are deploy-time only)', }; diff --git a/packages/core/src/lib/agentic/codec/defaults.ts b/packages/core/src/lib/agentic/codec/defaults.ts index 27cee24b..fdf04fe3 100644 --- a/packages/core/src/lib/agentic/codec/defaults.ts +++ b/packages/core/src/lib/agentic/codec/defaults.ts @@ -1,7 +1,7 @@ /** - * THE single home for omitted-limit defaults. Native defaults remain - * provisional pending product confirmation. Nothing else in the SDK may invent - * a fallback for these fields; change a row here once the decision lands. + * THE single home for omitted-limit defaults. Native PC defaults are zero as + * confirmed on October 7. Nothing else in the SDK may invent + * a fallback for these fields; update this table for future changes. * * Explicit zero always stays zero. In the native policy a zero value/amount * cap forbids positive value/amount, while maxCalls = 0 means unlimited. @@ -11,7 +11,7 @@ export const UINT256_MAX = BigInt(2) ** BigInt(256) - BigInt(1); export interface DefaultRow { value: bigint; meaning: string; - source: 'A03' | 'v4'; + source: 'product' | 'v4'; } export const AGENTIC_DEFAULTS = { @@ -19,22 +19,22 @@ export const AGENTIC_DEFAULTS = { maxValuePerCall: { value: BigInt(0), meaning: 'no native value transfer', - source: 'A03', + source: 'product', }, maxValueTotal: { value: BigInt(0), meaning: 'no native value transfer', - source: 'A03', + source: 'product', }, amountMaxTotal: { value: UINT256_MAX, meaning: 'unlimited metered total', - source: 'A03', + source: 'product', }, maxCalls: { value: BigInt(0), meaning: 'unlimited calls until expiry', - source: 'A03', + source: 'product', }, }, universal: { @@ -46,7 +46,7 @@ export const AGENTIC_DEFAULTS = { allowedCallMaxValue: { value: BigInt(0), meaning: 'no native value attached to the destination call', - source: 'A03', + source: 'product', }, }, } as const satisfies Record>; diff --git a/packages/core/src/lib/agentic/codec/ids.ts b/packages/core/src/lib/agentic/codec/ids.ts index 49448711..a33267ef 100644 --- a/packages/core/src/lib/agentic/codec/ids.ts +++ b/packages/core/src/lib/agentic/codec/ids.ts @@ -16,7 +16,7 @@ import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; * smartsessions IdLib.toActionId / toConfigId / toPermissionId and * AGWFactory._predict (OZ Clones immutable-args CREATE2). * Every input that changes the result is explicit — validator, factory and - * implementation are generation context (provisional public signature A04). + * implementation are internal generation context. */ /** keccak256(abi.encodePacked(address target, bytes4 selector)). */ diff --git a/packages/core/src/lib/agentic/codec/native.ts b/packages/core/src/lib/agentic/codec/native.ts index 81e5b160..2b3ae2da 100644 --- a/packages/core/src/lib/agentic/codec/native.ts +++ b/packages/core/src/lib/agentic/codec/native.ts @@ -129,7 +129,9 @@ export function nativeRuleToTerms( } const pins = pinsIn.map((p, i) => { - if ('offset' in p) { + if (p.arg !== undefined && p.offset !== undefined) + throw invalid('pin arg and offset are mutually exclusive'); + if (p.offset !== undefined) { if ( typeof p.expected !== 'string' || !isHex(p.expected) || @@ -144,6 +146,7 @@ export function nativeRuleToTerms( expected: p.expected.toLowerCase() as Hex, }; } + if (typeof p.arg !== 'number') throw invalid('pin requires arg or offset'); const offset = argumentOffset(parsed.inputs, p.arg, `pins[${i}]`); const param = (parsed.inputs as readonly AbiParameter[])[p.arg]; return { offset, expected: encodeArgWord(param, p.expected, `pins[${i}]`) }; @@ -160,9 +163,13 @@ export function nativeRuleToTerms( }; if (rule.amount) { let offset: number; - if ('offset' in rule.amount) { + if (rule.amount.arg !== undefined && rule.amount.offset !== undefined) + throw invalid('amount arg and offset are mutually exclusive'); + if (rule.amount.offset !== undefined) { offset = rawOffset(rule.amount.offset, 'amount'); } else { + if (typeof rule.amount.arg !== 'number') + throw invalid('amount requires arg or offset'); offset = argumentOffset(parsed.inputs, rule.amount.arg, 'amount'); const param = (parsed.inputs as readonly AbiParameter[])[rule.amount.arg]; if (!/^uint\d*$/.test(param.type)) { @@ -236,8 +243,7 @@ export function decodeNativeTerms(body: Hex): NativeTermsWire { */ export function nativeTermsToRule( terms: NativeTermsWire, - agent: Address, - ref: AgenticHex + agent: Address ): NativeRule { const rule: NativeRule = { agent: getAddress(agent), @@ -251,7 +257,6 @@ export function nativeTermsToRule( maxValueTotal: terms.maxValueTotal, maxCalls: Number(terms.maxCalls), }; - if (!/^0x0{64}$/i.test(ref)) rule.ref = ref; if (terms.pins.length > 0) { rule.pins = terms.pins.map((p) => ({ offset: Number(p.offset), diff --git a/packages/core/src/lib/agentic/codec/rules.ts b/packages/core/src/lib/agentic/codec/rules.ts index 54b981c8..e9b2fc2a 100644 --- a/packages/core/src/lib/agentic/codec/rules.ts +++ b/packages/core/src/lib/agentic/codec/rules.ts @@ -8,7 +8,12 @@ import { } from 'viem'; import { AgenticCapability, requireCapability } from '../capabilities'; import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; -import type { NativeRule, Rule, UniversalRule } from '../agentic.types'; +import type { + NativeRule, + Rule, + UniversalRule, + SolanaRule, +} from '../agentic.types'; import { encodeNativeTerms, nativeRuleToTerms, @@ -16,15 +21,28 @@ import { } from './native'; import { buildSession, encodeEnvelope, type SessionWire } from './session'; import { encodeUniversalRule, type ResolvedUniversalRule } from './universal'; +import { encodeSvmTerms, type SvmTermsWire } from './svm-terms'; +import { SEND_OUTBOUND_SELECTOR } from '../contracts/v4'; import type { UniversalTermsWire } from './universal-terms'; +export function isSolanaRule(rule: Rule): rule is SolanaRule { + return ( + typeof (rule as SolanaRule).chainNamespace === 'string' && + (rule as SolanaRule).chainNamespace.startsWith('solana:') + ); +} + export function isUniversalRule(rule: Rule): rule is UniversalRule { - return (rule as UniversalRule).chainNamespace !== undefined; + return ( + (rule as UniversalRule).chainNamespace !== undefined && !isSolanaRule(rule) + ); } /** CAIP-2 chain a rule governs: omitted = the connected Push chain. */ export function ruleChain(rule: Rule, pushChainNamespace: string): string { - return isUniversalRule(rule) ? rule.chainNamespace : pushChainNamespace; + return ( + (rule as UniversalRule | SolanaRule).chainNamespace ?? pushChainNamespace + ); } export function chainHash(chainNamespace: string): Hex { @@ -40,6 +58,7 @@ export interface RuleEncodeContext { nowSeconds: number; gateway?: Address; universal?: ReadonlyMap; + svm?: ReadonlyMap; /** * Addresses a native rule may never target (AGW _requireGrantableTarget / * URP NativeTargetIsGateway): wallet, engine, policy, validator, factory, @@ -56,6 +75,7 @@ export interface PreparedRule { /** Native terms when the rule is native (used for previews and assertions). */ nativeTerms?: NativeTermsWire; universalTerms?: UniversalTermsWire; + svmTerms?: SvmTermsWire; } /** Validate before signing. V4 permits several grants for the same agent/chain. */ @@ -105,10 +125,46 @@ export function prepareRules( `rules[${i}] names the connected Push chain; omit chainNamespace for a native rule` ); } - if (rule.ref !== undefined) { - requireCapability(ctx.capabilities, AgenticCapability.GRANT_REF); + if ('ref' in rule) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'Rule ref is not supported; remove it from the input' + ); } + if (isSolanaRule(rule)) { + requireCapability( + ctx.capabilities, + AgenticCapability.UNIVERSAL_SVM_RULES + ); + const terms = ctx.svm?.get(rule); + if (!terms || !ctx.gateway) + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'SVM rules require resolved wallet context and named IDL inputs' + ); + return { + rule, + agent, + chainNamespace, + svmTerms: terms, + session: buildSession({ + validator: ctx.validator, + rulesPolicy: ctx.rulesPolicy, + agent, + actions: [ + { + target: ctx.gateway, + selector: SEND_OUTBOUND_SELECTOR, + initData: encodeEnvelope( + chainNamespace, + encodeSvmTerms(terms, ctx.nowSeconds) + ), + }, + ], + }), + }; + } if (isUniversalRule(rule)) { return encodeUniversalRule(rule, ctx); } diff --git a/packages/core/src/lib/agentic/codec/svm-idl.ts b/packages/core/src/lib/agentic/codec/svm-idl.ts new file mode 100644 index 00000000..4e7f22f4 --- /dev/null +++ b/packages/core/src/lib/agentic/codec/svm-idl.ts @@ -0,0 +1,269 @@ +/** Compile named Anchor IDL constraints. Unsupported layouts are never guessed. */ +import type { Idl } from '@coral-xyz/anchor'; +import { bytesToHex, hexToBytes, type Hex } from 'viem'; +import type { SolanaRule, SvmAccountRef } from '../agentic.types'; +import { svmKey } from './svm-accounts'; +import { + SvmDataPinMode, + svmInvalid, + validateSvmTerms, + type SvmTermsWire, + type SvmDataPinWire, +} from './svm-terms'; + +export type SvmResolvedContext = Pick< + SvmTermsWire, + 'assets' | 'expectedCEA' | 'gatewayProgram' | 'ceaAccounts' +> & { + /** Verified mint -> wallet ATA mapping, including output mints. */ + tokenAccounts: ReadonlyMap; +}; +type Field = { offset: number; len: number; type: unknown }; +const widths: Record = { + bool: 1, + u8: 1, + i8: 1, + u16: 2, + i16: 2, + u32: 4, + i32: 4, + f32: 4, + u64: 8, + i64: 8, + f64: 8, + u128: 16, + i128: 16, + u256: 32, + i256: 32, + pubkey: 32, +}; +function width(type: unknown): number { + if (typeof type === 'string' && widths[type]) return widths[type]; + if (type && typeof type === 'object' && 'array' in type) { + const a = (type as { array: unknown }).array; + if ( + Array.isArray(a) && + a.length === 2 && + Number.isSafeInteger(a[1]) && + a[1] > 0 + ) { + const size = width(a[0]) * a[1]; + if (size <= 1024) return size; + } + } + throw svmInvalid( + 'IDL field layout is not supported: use fixed-width primitives or fixed arrays' + ); +} +export function svmIdlInstruction(idl: Idl, name: string) { + if (!idl || !Array.isArray(idl.instructions) || typeof name !== 'string') + throw svmInvalid('instruction requires an Anchor IDL and name'); + const found = idl.instructions.filter((i) => i.name === name); + if (found.length !== 1) + throw svmInvalid(`IDL instruction ${name} must exist exactly once`); + const ix = found[0]; + if ( + !Array.isArray(ix.discriminator) || + ix.discriminator.length !== 8 || + ix.discriminator.some((b) => !Number.isInteger(b) || b < 0 || b > 255) + ) + throw svmInvalid('Anchor IDL discriminator must contain eight bytes'); + return ix; +} +function accountNames(accounts: unknown[], prefix = ''): string[] { + return accounts.flatMap((entry) => { + if ( + !entry || + typeof entry !== 'object' || + !('name' in entry) || + typeof entry.name !== 'string' + ) + throw svmInvalid('invalid IDL account'); + const name = prefix + entry.name; + if ('accounts' in entry) + throw svmInvalid( + 'nested IDL accounts are not supported by the instruction resolver' + ); + if ('optional' in entry && entry.optional) + throw svmInvalid('optional IDL accounts are not supported for rules'); + return [name]; + }); +} +function resolveAccount(ref: SvmAccountRef, ctx: SvmResolvedContext): Hex { + if (!ref || typeof ref !== 'object') + throw svmInvalid('invalid named account reference'); + if (ref.kind === 'walletCEA') return ctx.expectedCEA; + if (ref.kind === 'address') return svmKey(ref.address); + if (ref.kind === 'walletATA') { + const ata = ctx.tokenAccounts.get(svmKey(ref.token)); + if (!ata) + throw svmInvalid( + 'walletATA mint must be listed in assets or outputTokens' + ); + return ata; + } + throw svmInvalid('unknown named account reference'); +} +function unsigned(f: Field): void { + if (typeof f.type !== 'string' || !/^u(8|16|32|64)$/.test(f.type)) + throw svmInvalid( + 'range/ratio constraints require unsigned integer fields of at most eight bytes' + ); +} +function bound(v: bigint, len: number): Hex { + if ( + typeof v !== 'bigint' || + v < BigInt(0) || + v >= BigInt(1) << BigInt(len * 8) + ) + throw svmInvalid('field constraint exceeds its unsigned width'); + return `0x${v.toString(16).padStart(64, '0')}`; +} +export function compileSvmIdlRule( + rule: SolanaRule, + ctx: SvmResolvedContext, + now: number +): SvmTermsWire { + if ( + !Array.isArray(rule.allowedInstructions) || + !rule.allowedInstructions.length || + rule.allowedInstructions.length > 32 + ) + throw svmInvalid('allowedInstructions must contain 1..32 entries'); + const terms: SvmTermsWire = { + validUntil: rule.validUntil, + maxGasPerCall: rule.maxGasPerCall, + assets: ctx.assets, + expectedCEA: ctx.expectedCEA, + gatewayProgram: ctx.gatewayProgram, + ceaAccounts: ctx.ceaAccounts, + programs: [], + pins: [], + dataPins: [], + }; + const programs = [], + pins = [], + dataPins: SvmDataPinWire[] = []; + for (const [ruleIndex, entry] of rule.allowedInstructions.entries()) { + const ix = svmIdlInstruction( + entry.instruction?.idl, + entry.instruction?.name + ); + const program = svmKey(entry.program); + if (svmKey(entry.instruction.idl.address) !== program) + throw svmInvalid('IDL address differs from rule program'); + if (!Array.isArray(ix.accounts) || !Array.isArray(entry.accounts)) + throw svmInvalid('instruction accounts are required'); + const names = accountNames(ix.accounts); + if (new Set(names).size !== names.length) + throw svmInvalid('duplicate IDL account names'); + programs.push({ + program, + discriminator: bytesToHex( + Uint8Array.from([ + ...ix.discriminator, + ...Array(8 - ix.discriminator.length).fill(0), + ]) + ), + discriminatorLen: ix.discriminator.length, + dataless: false, + maxAccounts: names.length, + }); + for (const a of entry.accounts) { + const accountIndex = names.indexOf(a.name); + if (accountIndex < 0) throw svmInvalid(`unknown IDL account ${a.name}`); + pins.push({ + ruleIndex, + accountIndex, + expected: resolveAccount(a.expected, ctx), + }); + } + const fields = new Map(); + let offset = ix.discriminator.length; + // Reject variable/nested-defined layouts rather than claiming a reliable offset. + for (const arg of ix.args) { + if (fields.has(arg.name)) throw svmInvalid('duplicate IDL field name'); + const len = width(arg.type); + fields.set(arg.name, { offset, len, type: arg.type }); + offset += len; + } + if (offset > 1024) + throw svmInvalid('IDL instruction data exceeds the policy limit'); + const field = (name: string) => { + const f = fields.get(name); + if (!f) throw svmInvalid(`unknown IDL field ${name}`); + return f; + }; + if (entry.fields !== undefined && !Array.isArray(entry.fields)) + throw svmInvalid('fields must be an array'); + for (const constraint of entry.fields ?? []) { + const keys = ['equals', 'min', 'max', 'minRatio'].filter( + (k) => k in constraint + ); + if (keys.length !== 1) + throw svmInvalid( + 'each field constraint must specify exactly one comparison' + ); + const f = field( + 'numerator' in constraint ? constraint.numerator : constraint.name + ); + const p: SvmDataPinWire = { + ruleIndex, + fromEnd: false, + offset: f.offset, + offsetB: 0, + len: f.len, + mode: SvmDataPinMode.EQ, + expected: `0x${'00'.repeat(32)}`, + num: BigInt(0), + den: BigInt(0), + }; + if ('minRatio' in constraint) { + unsigned(f); + const b = field(constraint.denominator); + unsigned(b); + if (f.len !== b.len) + throw svmInvalid('ratio fields must have the same width'); + Object.assign(p, { + mode: SvmDataPinMode.RATIO_GTE_LE, + offsetB: b.offset, + num: constraint.minRatio.num, + den: constraint.minRatio.den, + }); + } else if ('min' in constraint || 'max' in constraint) { + unsigned(f); + const min = 'min' in constraint; + p.mode = min ? SvmDataPinMode.GTE_LE : SvmDataPinMode.LTE_LE; + p.expected = bound(min ? constraint.min : constraint.max, f.len); + } else { + let bytes: Uint8Array; + if (typeof constraint.equals === 'bigint') { + unsigned(f); + bound(constraint.equals, f.len); + bytes = Uint8Array.from({ length: f.len }, (_, i) => + Number( + ((constraint.equals as bigint) >> BigInt(8 * i)) & BigInt(255) + ) + ); + } else if (typeof constraint.equals === 'boolean') { + if (f.type !== 'bool') + throw svmInvalid('boolean equality requires a bool field'); + bytes = Uint8Array.of(constraint.equals ? 1 : 0); + } else { + if (!/^0x(?:[a-fA-F0-9]{2})*$/.test(constraint.equals)) + throw svmInvalid('equality requires exact hex bytes'); + bytes = hexToBytes(constraint.equals); + } + if (bytes.length !== f.len || f.len > 32) + throw svmInvalid( + 'equality value must match field width (at most 32 bytes)' + ); + p.expected = `0x${bytesToHex(bytes).slice(2).padEnd(64, '0')}`; + } + dataPins.push(p); + } + } + Object.assign(terms, { programs, pins, dataPins }); + validateSvmTerms(terms, now); + return terms; +} diff --git a/packages/core/src/lib/agentic/deployments.ts b/packages/core/src/lib/agentic/deployments.ts index 779fb502..3ffbe434 100644 --- a/packages/core/src/lib/agentic/deployments.ts +++ b/packages/core/src/lib/agentic/deployments.ts @@ -51,6 +51,7 @@ export const V4_CAPABILITIES: ReadonlySet = new Set([ AgenticCapability.CHECKPOINTS, AgenticCapability.UNIVERSAL_EVM_OUTBOUND, AgenticCapability.UNIVERSAL_EVM_RULES, + AgenticCapability.UNIVERSAL_SVM_RULES, AgenticCapability.ASSERT_SPENT_UNIVERSAL_MULTI, ]); diff --git a/packages/core/src/lib/agentic/execution/outbound.ts b/packages/core/src/lib/agentic/execution/outbound.ts index 479b9ff2..4c1a6826 100644 --- a/packages/core/src/lib/agentic/execution/outbound.ts +++ b/packages/core/src/lib/agentic/execution/outbound.ts @@ -143,7 +143,7 @@ export async function composeOutbound( if (info.vm !== VM.EVM) { throw capabilityUnavailable( AgenticCapability.UNIVERSAL_SVM_RULES, - 'SVM destinations are not enabled for agentic wallets (A05/A07, H4.4)' + 'This composer accepts EVM destinations; use the Solana instruction route' ); } const funds = params.funds; diff --git a/packages/core/src/lib/agentic/execution/send.ts b/packages/core/src/lib/agentic/execution/send.ts index 88dfb978..1cabdcce 100644 --- a/packages/core/src/lib/agentic/execution/send.ts +++ b/packages/core/src/lib/agentic/execution/send.ts @@ -1,3 +1,4 @@ +import { sendPublicSvm } from './svm-public'; import { getAddress, type Address, type Hex } from 'viem'; import type { CHAIN } from '../../constants/enums'; import { ERC20_EVM } from '../../constants/abi'; @@ -155,6 +156,11 @@ export async function agenticSend( ); } + if (outbound && destination.startsWith('solana:')) { + await enforceSignerGas(runtime, undefined); + return sendPublicSvm(runtime, actx, p, options); + } + let wrappedData: Hex; let agentBatch: MultiCall[] | undefined; let nativeCalls: Call[] | undefined; diff --git a/packages/core/src/lib/agentic/execution/svm-payload.ts b/packages/core/src/lib/agentic/execution/svm-payload.ts index d69fa4cc..da76d7ee 100644 --- a/packages/core/src/lib/agentic/execution/svm-payload.ts +++ b/packages/core/src/lib/agentic/execution/svm-payload.ts @@ -1,4 +1,4 @@ -/** Internal parser/validator for the deployed S12–S18 grammar. Public SVM sends remain gated. */ +/** Parser/validator for the deployed S12–S18 instruction grammar. */ import { bytesToHex, hexToBytes, type Hex } from 'viem'; import { encodeSvmExecutePayload } from '../../orchestrator/payload-builders'; import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; diff --git a/packages/core/src/lib/agentic/execution/svm-public.ts b/packages/core/src/lib/agentic/execution/svm-public.ts new file mode 100644 index 00000000..7af6139b --- /dev/null +++ b/packages/core/src/lib/agentic/execution/svm-public.ts @@ -0,0 +1,264 @@ +import { PRC20_SOURCE_ABI } from '../contracts/prc20-metadata'; +import { PROGRESS_HOOK } from '../../progress-hook/progress-hook.types'; +import { emitAgentic } from '../management/common'; +import { + bytesToHex, + hexToBytes, + encodeFunctionData, + erc20Abi, + getAddress, + type Hex, +} from 'viem'; +import type { CHAIN } from '../../constants/enums'; +import { UNIVERSAL_GATEWAY_PC } from '../../constants/abi'; +import { + isPC20Reference, + type UniversalExecuteParams, + type TransactionExecutionOptions, +} from '../../orchestrator/orchestrator.types'; +import { resolveSvmCallForCea } from '../../orchestrator/svm-idl/resolve'; +import type { AgenticRuntime } from '../runtime'; +import type { AgenticExecutionContext } from '../context'; +import { AgenticCapability, requireCapability } from '../capabilities'; +import { selectRuleForSend } from '../reads/rules'; +import { readSvmConfig } from '../reads/svm'; +import { Snapshot } from '../reads/snapshot'; +import { svmMetadata } from '../management/svm-public'; +import { wrapSendError } from '../management/common'; +import type { MoveableToken } from '../../constants/tokens'; +import { svmKey, deriveAgwSvmCea } from '../codec/svm-accounts'; +import { svmInvalid, UINT64_MAX } from '../codec/svm-terms'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; +import { prepareSvmAgentExecution } from './svm-send'; +import { encodeAgwSvmPayload } from './svm-payload'; +import { adaptAgenticResponse } from '../response'; + +/** Public single-instruction route; the contract enforces the supplied rule. */ +export async function sendPublicSvm( + runtime: AgenticRuntime, + actx: AgenticExecutionContext, + p: UniversalExecuteParams, + options?: TransactionExecutionOptions +) { + const gen = actx.generation, + wallet = actx.wallet; + requireCapability(gen.capabilities, AgenticCapability.UNIVERSAL_SVM_RULES); + requireCapability( + gen.capabilities, + actx.door === 'agent' + ? AgenticCapability.AGENT_EXECUTE + : AgenticCapability.OWNER_EXECUTE + ); + const to = p.to as { address: string; chain: CHAIN }; + const program = svmKey(to.address); + if ( + Array.isArray(p.data) || + typeof p.data !== 'string' || + !/^0x(?:[0-9a-fA-F]{2})+$/.test(p.data) + ) + throw svmInvalid( + 'Solana AGW sends require one encoded instruction; arrays and funds-only sends are unsupported' + ); + if (p.funds && isPC20Reference(p.funds.token)) + throw svmInvalid('PC20 SVM outbound is not supported'); + if (p.funds && (p.value ?? BigInt(0)) !== BigInt(0)) + throw svmInvalid('use either funds or value for the bridged amount'); + const amount = p.funds?.amount ?? p.value ?? BigInt(0); + if (typeof amount !== 'bigint' || amount < BigInt(0) || amount > UINT64_MAX) + throw svmInvalid('Solana outbound amount must fit uint64'); + const metadata = svmMetadata(runtime), + snap = await Snapshot.at(runtime.reader); + let rulesId: Hex | undefined, data: Hex, instruction, cea: Hex; + const gasLimit = p.gasLimit ?? BigInt(1_000_000); + if (actx.door === 'agent') { + const active = await selectRuleForSend( + snap, + gen, + wallet, + actx.signerPushAccount, + to.chain + ); + const stored = await readSvmConfig( + snap, + gen, + wallet, + active, + runtime.pushChainNamespace + ); + const token = + p.funds || amount > BigInt(0) + ? runtime.resolvePrc20( + p.funds?.token as MoveableToken | undefined, + to.chain + ) + : getAddress(stored.config.assets[0].token); + const prepared = await prepareSvmAgentExecution( + runtime, + gen, + { + wallet, + rulesId: active.rulesId, + token, + amount, + gasLimit, + program, + instructionData: hexToBytes(p.data), + }, + metadata + ); + data = prepared.data; + instruction = prepared.instruction; + cea = stored.config.expectedCEA; + rulesId = active.rulesId; + } else { + const gateway = await metadata.gateway(to.chain as `solana:${string}`); + cea = deriveAgwSvmCea(wallet, gateway.program).address; + const resolved = resolveSvmCallForCea( + { + programAddress: program, + data: hexToBytes(p.data), + senderUea: wallet, + targetChain: to.chain, + }, + cea + ); + instruction = { + recipient: resolved.targetProgram, + instructionData: resolved.ixData, + accounts: resolved.accounts, + }; + const token = runtime.resolvePrc20( + p.funds?.token as MoveableToken | undefined, + to.chain + ); + if ( + (await snap.read( + token, + PRC20_SOURCE_ABI, + 'SOURCE_CHAIN_NAMESPACE' + )) !== to.chain + ) + throw svmInvalid('outbound asset belongs to another chain'); + const quote = await runtime.quoteOutbound(token, gasLimit, to.chain); + const [pc, balance, allowance] = await Promise.all([ + runtime.reader.getBalance({ + address: wallet, + blockNumber: snap.blockNumber, + }), + snap.read(token, erc20Abi, 'balanceOf', [wallet]), + snap.read(token, erc20Abi, 'allowance', [ + wallet, + gen.addresses.gateway, + ]), + ]); + const value = quote.protocolFee + quote.nativeValueForGas; + if (pc < value || balance < amount) + throw new AgenticError( + AGENTIC_ERROR_CODE.WALLET_BALANCE_INSUFFICIENT, + 'wallet cannot cover Solana outbound' + ); + if (allowance < amount) + throw new AgenticError( + AGENTIC_ERROR_CODE.GATEWAY_ALLOWANCE_INSUFFICIENT, + 'set the wallet gateway allowance separately' + ); + data = gen.contracts.encodeExecute([ + { + target: gen.addresses.gateway, + value, + data: encodeFunctionData({ + abi: UNIVERSAL_GATEWAY_PC, + functionName: 'sendUniversalTxOutbound', + args: [ + { + token, + amount, + recipient: resolved.targetProgram, + payload: encodeAgwSvmPayload( + resolved.targetProgram, + resolved.accounts, + resolved.ixData + ), + gasLimit: quote.gasLimitUsed, + gasPrice: BigInt(0), + maxPCForGas: quote.nativeValueForGas, + revertRecipient: wallet, + }, + ], + }), + }, + ]); + } + const hook = options?.progressHook ?? p.progressHook; + emitAgentic( + runtime, + hook, + PROGRESS_HOOK.AGENTIC_TX_107, + rulesId, + to.chain, + actx.door + ); + let response; + try { + response = await runtime.execute( + { + to: wallet, + value: BigInt(0), + data, + ...(p.nonce === undefined ? {} : { nonce: p.nonce }), + ...(p.maxFeePerGas === undefined + ? {} + : { maxFeePerGas: p.maxFeePerGas }), + ...(p.maxPriorityFeePerGas === undefined + ? {} + : { maxPriorityFeePerGas: p.maxPriorityFeePerGas }), + ...(p.deadline === undefined ? {} : { deadline: p.deadline }), + ...(p.feeLockTxHash === undefined + ? {} + : { feeLockTxHash: p.feeLockTxHash }), + }, + { ...options, progressHook: options?.progressHook ?? p.progressHook } + ); + } catch (error) { + const wrapped = wrapSendError(error) as AgenticError & { + decodedError?: unknown; + }; + emitAgentic( + runtime, + hook, + PROGRESS_HOOK.AGENTIC_TX_199_02, + 'sendTransaction', + wrapped.code ?? 'UNKNOWN', + wrapped.message, + wrapped.decodedError + ); + throw wrapped; + } + const result = adaptAgenticResponse(response, { + wallet, + door: actx.door, + rulesId, + chainNamespace: to.chain, + chain: to.chain, + route: 'UOA_TO_CEA', + destinationAccount: cea, + destinationInstruction: { + program: instruction.recipient, + data: bytesToHex(instruction.instructionData), + accounts: instruction.accounts, + }, + logical: { + to: instruction.recipient, + data: bytesToHex(instruction.instructionData), + value: BigInt(0), + }, + }); + emitAgentic( + runtime, + hook, + PROGRESS_HOOK.AGENTIC_TX_199_01, + 'sendTransaction', + response.hash + ); + return result; +} diff --git a/packages/core/src/lib/agentic/execution/svm-send.ts b/packages/core/src/lib/agentic/execution/svm-send.ts index aa9cb162..e7cb61fa 100644 --- a/packages/core/src/lib/agentic/execution/svm-send.ts +++ b/packages/core/src/lib/agentic/execution/svm-send.ts @@ -1,4 +1,4 @@ -/** Prepared-wire agent execution. Public SVM entry points remain disabled. */ +/** Prepared-wire agent execution used by the public Solana route. */ import { getAddress, erc20Abi, type Address, type Hex } from 'viem'; import { CHAIN } from '../../constants/enums'; import type { AgenticGeneration } from '../deployments'; @@ -169,7 +169,7 @@ export async function sendSvmAgentWire( data: prepared.data, }); // Return the ordinary signer response and explicit wire context internally. - // Public display/Rule mapping is deliberately not invented here. + // The public wrapper applies the response presentation. return { tx, context: prepared.stored, instruction: prepared.instruction }; } catch (error) { throw wrapSendError(error); diff --git a/packages/core/src/lib/agentic/index.ts b/packages/core/src/lib/agentic/index.ts index 7e1ca3c6..0bfceff3 100644 --- a/packages/core/src/lib/agentic/index.ts +++ b/packages/core/src/lib/agentic/index.ts @@ -14,6 +14,11 @@ export type { CreateResult, ForeignChainNamespace, NativeRule, + SolanaRule, + DecodedSolanaRule, + SvmInstructionRule, + SvmAccountRef, + SvmFieldConstraint, Rule, RulesRecord, Selector, diff --git a/packages/core/src/lib/agentic/management/prepare.ts b/packages/core/src/lib/agentic/management/prepare.ts index 7c797d52..d2019629 100644 --- a/packages/core/src/lib/agentic/management/prepare.ts +++ b/packages/core/src/lib/agentic/management/prepare.ts @@ -1,8 +1,10 @@ +import { preparePublicSvmRule } from './svm-public'; +import type { SvmTermsWire } from '../codec/svm-terms'; import { getAddress, zeroAddress, type Address } from 'viem'; import { CHAIN, VM } from '../../constants/enums'; import { CHAIN_INFO } from '../../constants/chain'; import { AGENTIC_DEFAULTS, withDefault } from '../codec/defaults'; -import { isUniversalRule, prepareRules } from '../codec/rules'; +import { isUniversalRule, isSolanaRule, prepareRules } from '../codec/rules'; import { validateUniversalRuleShape, type ResolvedUniversalRule, @@ -14,7 +16,7 @@ import { } from '../deployments'; import { AgenticCapability, requireCapability } from '../capabilities'; import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; -import type { Rule, UniversalRule } from '../agentic.types'; +import type { Rule, UniversalRule, SolanaRule } from '../agentic.types'; import type { AgenticRuntime } from '../runtime'; import { Snapshot } from '../reads/snapshot'; @@ -34,8 +36,17 @@ export async function prepareWalletRules( snap: Snapshot ) { if (rules.length) await verifyPolicyVersion(runtime.reader, gen); + const svm = new Map(); const universal = new Map(); for (const rule of rules) { + if (rule && isSolanaRule(rule)) { + requireCapability( + gen.capabilities, + AgenticCapability.UNIVERSAL_SVM_RULES + ); + svm.set(rule, await preparePublicSvmRule(runtime, snap, wallet, rule)); + continue; + } if (!isUniversalRule(rule)) continue; if (rule.chainNamespace.startsWith('solana:')) requireCapability( @@ -128,5 +139,6 @@ export async function prepareWalletRules( nowSeconds: runtime.nowSeconds(), forbiddenTargets: forbiddenTargets(gen, wallet), universal, + svm, }); } diff --git a/packages/core/src/lib/agentic/management/rules-write.ts b/packages/core/src/lib/agentic/management/rules-write.ts index 4ff2e792..a77f4e64 100644 --- a/packages/core/src/lib/agentic/management/rules-write.ts +++ b/packages/core/src/lib/agentic/management/rules-write.ts @@ -414,7 +414,7 @@ function sameIds(a: readonly Hex[], b: readonly Hex[]): boolean { ); } -/** w.setLabel — PROPOSED; no generation implements an editable label (A07). */ +/** w.setLabel — approved, awaiting a verified contract interface/deployment. */ export async function setLabel( _runtime: AgenticRuntime, gen: AgenticGeneration, diff --git a/packages/core/src/lib/agentic/management/svm-public.ts b/packages/core/src/lib/agentic/management/svm-public.ts new file mode 100644 index 00000000..d66c9936 --- /dev/null +++ b/packages/core/src/lib/agentic/management/svm-public.ts @@ -0,0 +1,114 @@ +import { getAddress, zeroAddress } from 'viem'; +import type { Address, Hex } from 'viem'; +import { CHAIN, VM } from '../../constants/enums'; +import { CHAIN_INFO } from '../../constants/chain'; +import type { SolanaRule } from '../agentic.types'; +import type { AgenticRuntime } from '../runtime'; +import type { Snapshot } from '../reads/snapshot'; +import { readGasPrc20 } from '../contracts/prc20-metadata'; +import { resolveSvmContext } from './svm-context'; +import { createSvmMetadataProvider } from './svm-metadata'; +import { deriveAgwSvmAta, svmKey } from '../codec/svm-accounts'; +import { compileSvmIdlRule } from '../codec/svm-idl'; +import { svmInvalid } from '../codec/svm-terms'; +import { UINT256_MAX } from '../codec/defaults'; + +export function svmMetadata(runtime: AgenticRuntime) { + return ( + runtime.svmMetadata ?? + createSvmMetadataProvider({ + [CHAIN.SOLANA_DEVNET]: { + gatewayProgram: CHAIN_INFO[CHAIN.SOLANA_DEVNET].lockerContract ?? '', + rpcUrls: CHAIN_INFO[CHAIN.SOLANA_DEVNET].defaultRPC, + }, + }) + ); +} +export async function preparePublicSvmRule( + runtime: AgenticRuntime, + snap: Snapshot, + wallet: Address, + rule: SolanaRule +) { + const chain = rule.chainNamespace as CHAIN; + if (CHAIN_INFO[chain]?.vm !== VM.SVM) + throw svmInvalid('unknown Solana chain'); + if (!Array.isArray(rule.assets) || rule.assets.length > 8) + throw svmInvalid('assets must contain at most eight entries'); + if (rule.outputTokens !== undefined && !Array.isArray(rule.outputTokens)) + throw svmInvalid('outputTokens must be an array of mint addresses'); + const metadata = svmMetadata(runtime); + const requested = rule.assets.length + ? rule.assets + : [{ token: zeroAddress, maxPerCall: BigInt(0), maxTotal: BigInt(0) }]; + const caps: { token: Address; maxPerCall: bigint; maxTotal: bigint }[] = []; + const tokenAccounts = new Map(), + mints = new Set(); + const sources: { key?: Hex; token: Address }[] = []; + for (const asset of requested) { + const source = + typeof asset.token === 'string' ? asset.token : asset.token?.address; + if (typeof source !== 'string') + throw svmInvalid('asset token requires an address'); + if ( + typeof asset.token !== 'string' && + 'chain' in asset.token && + asset.token.chain !== chain + ) + throw svmInvalid('asset token belongs to another chain'); + const native = + source === zeroAddress || + /^0x0{64}$/.test(source) || + source === '11111111111111111111111111111111'; + const key = native ? undefined : svmKey(source); + const token = native + ? await readGasPrc20(snap, chain) + : runtime.resolvePrc20(asset.token, chain); + if (caps.some((c) => c.token === getAddress(token))) + throw svmInvalid('duplicate SVM asset'); + caps.push({ + token: getAddress(token), + maxPerCall: asset.maxPerCall, + maxTotal: asset.maxTotal ?? UINT256_MAX, + }); + sources.push({ key, token }); + if (key) mints.add(key); + } + const outputs = (rule.outputTokens ?? []).map((mint) => ({ mint })); + outputs.forEach((o) => mints.add(svmKey(o.mint))); + const ctx = await resolveSvmContext( + snap, + wallet, + rule.chainNamespace, + caps, + metadata, + outputs + ); + // Validate the PRC20 actually represents the requested source mint, not merely its chain. + const { resolveSvmAssets } = await import('./svm-context'); + const resolved = await resolveSvmAssets( + snap, + rule.chainNamespace, + caps, + metadata + ); + resolved.forEach((a, i) => { + if ( + sources[i].key + ? a.kind !== 'spl' || svmKey(a.mint) !== sources[i].key + : a.kind !== 'native' + ) + throw svmInvalid('PRC20 source does not match requested asset'); + }); + for (const mint of mints) { + const token = await metadata.mint(rule.chainNamespace, mint); + if (svmKey(token.mint) !== mint) + throw svmInvalid('mint resolver returned another mint'); + tokenAccounts.set(mint, deriveAgwSvmAta(ctx.expectedCEA, token)); + } + return compileSvmIdlRule( + rule, + { ...ctx, tokenAccounts }, + runtime.nowSeconds() + ); +} diff --git a/packages/core/src/lib/agentic/reads/rules.ts b/packages/core/src/lib/agentic/reads/rules.ts index 6b55072e..cecab2e3 100644 --- a/packages/core/src/lib/agentic/reads/rules.ts +++ b/packages/core/src/lib/agentic/reads/rules.ts @@ -1,6 +1,8 @@ +import { readSvmConfig } from './svm'; +import { PRC20_SOURCE_ABI, readGasPrc20 } from '../contracts/prc20-metadata'; +import { svmKey } from '../codec/svm-accounts'; import { getAddress, - isAddress, zeroAddress, type Address, type Hex, @@ -8,7 +10,6 @@ import { import { CHAIN } from '../../constants/enums'; import { AgenticCapability, - CAPABILITY_DEPENDENCY, requireCapability, } from '../capabilities'; import type { AgenticGeneration } from '../deployments'; @@ -25,12 +26,10 @@ import { chainHash } from '../codec/rules'; import { AGENTIC_ERROR_CODE, AgenticError, - capabilityUnavailable, } from '../errors'; import type { AgenticHex, RulesRecord } from '../agentic.types'; import { Snapshot } from './snapshot'; -const ZERO_REF = `0x${'00'.repeat(32)}` as AgenticHex; const MODE_UNIVERSAL = 0; const MODE_NATIVE = 1; @@ -159,7 +158,7 @@ export async function selectRuleForSend( AGENTIC_ERROR_CODE.AMBIGUOUS_RULE, `${matches.length} enabled rules on ${wallet} name ${agent} for ${destinationChain}`, { - hint: 'Multi-rule selection is pending H6. Candidate IDs are listed in details.rulesIds; the SDK will not pick one arbitrarily.', + hint: 'Multiple enabled rules match this agent and chain. Inspect details.rulesIds and ask the owner to resolve the overlap; no transaction was submitted.', details: { rulesIds: matches.map((m) => m.rulesId) }, } ); @@ -176,10 +175,62 @@ export async function decodeActiveRule( pushChainNamespace: string ): Promise { if (rule.mode === MODE_UNIVERSAL) { + if (rule.vm === 1) { + requireCapability( + gen.capabilities, + AgenticCapability.UNIVERSAL_SVM_RULES + ); + const stored = await readSvmConfig( + snap, + gen, + wallet, + rule, + pushChainNamespace + ); + const cfg = stored.config; + const gas = await readGasPrc20(snap, stored.chainNamespace); + const assets = await Promise.all( + cfg.assets.map(async (a) => ({ + token: + getAddress(a.token) === gas + ? zeroAddress + : svmKey( + await snap.read( + a.token, + PRC20_SOURCE_ABI, + 'SOURCE_TOKEN_ADDRESS' + ) + ), + maxPerCall: a.maxPerCall, + maxTotal: a.maxTotal, + })) + ); + return { + rulesId: rule.rulesId, + enabled: true, + agent: rule.agent, + chainNamespace: stored.chainNamespace, + validUntil: Number(cfg.validUntil), + rule: { + format: 'decoded', + agent: rule.agent, + chainNamespace: stored.chainNamespace, + validUntil: Number(cfg.validUntil), + expectedCEA: cfg.expectedCEA, + gatewayProgram: cfg.gatewayProgram, + maxGasPerCall: cfg.maxGasPerCall, + assets, + ceaAccounts: cfg.ceaAccounts, + programs: cfg.programs, + pins: cfg.pins, + dataPins: cfg.dataPins, + }, + }; + } if (rule.vm !== 0) - throw capabilityUnavailable( - AgenticCapability.UNIVERSAL_SVM_RULES, - 'SVM public rule mapping is not settled (H4.4)' + throw new AgenticError( + AGENTIC_ERROR_CODE.RULE_READ_FAILED, + 'unknown universal VM' ); requireCapability(gen.capabilities, AgenticCapability.UNIVERSAL_EVM_RULES); const chain = chainFromHash(rule.chainHash, pushChainNamespace); @@ -219,7 +270,6 @@ export async function decodeActiveRule( chainNamespace: chain, agent: rule.agent, validUntil: Number(cfg.validUntil), - ref: ZERO_REF, rule: universalTermsToRule( cfg, rule.agent, @@ -264,8 +314,7 @@ export async function decodeActiveRule( chainNamespace: pushChainNamespace, agent: rule.agent, validUntil: Number(cfg.validUntil), - ref: ZERO_REF, - rule: nativeTermsToRule(cfg, rule.agent, ZERO_REF), + rule: nativeTermsToRule(cfg, rule.agent), }; } diff --git a/packages/core/src/lib/agentic/reads/svm.ts b/packages/core/src/lib/agentic/reads/svm.ts index 99b8649b..a68141f1 100644 --- a/packages/core/src/lib/agentic/reads/svm.ts +++ b/packages/core/src/lib/agentic/reads/svm.ts @@ -1,4 +1,4 @@ -/** Internal lossless SVM state. Public Rule mapping stays capability-gated. */ +/** Internal lossless SVM state shared by public reads and execution. */ import type { Address, Hex } from 'viem'; import type { AgenticGeneration } from '../deployments'; import type { SvmConfigRead } from '../contracts/v4'; diff --git a/packages/core/src/lib/agentic/response.ts b/packages/core/src/lib/agentic/response.ts index 921ce8e0..f7e9490e 100644 --- a/packages/core/src/lib/agentic/response.ts +++ b/packages/core/src/lib/agentic/response.ts @@ -1,3 +1,7 @@ +import { parseAgwSvmPayload } from './execution/svm-payload'; +import { deriveAgwSvmCea } from './codec/svm-accounts'; +import { CHAIN_INFO } from '../constants/chain'; +import { bytesToHex } from 'viem'; import { decodeAbiParameters, decodeFunctionData, @@ -82,6 +86,9 @@ export function adaptAgenticResponse( ...(meta.destinationCalls ? { destinationCalls: meta.destinationCalls.map((call) => ({ ...call })) } : {}), + ...(meta.destinationInstruction + ? { destinationInstruction: meta.destinationInstruction } + : {}), ...(meta.nativeCalls ? { nativeCalls: meta.nativeCalls.map((call) => ({ ...call })) } : {}), @@ -139,6 +146,40 @@ export async function adaptTrackedResponse( if (outbound) { const out = decodeOutbound(outbound.data); const chain = await tokenChain(runtime, out.token); + if (chain?.startsWith('solana:')) { + try { + const instruction = parseAgwSvmPayload(out.payload); + const destinationInstruction = { + program: instruction.program, + accounts: instruction.accounts.map(({ pubkey, isWritable }) => ({ + pubkey, + isWritable, + })), + data: bytesToHex(instruction.instructionData), + }; + return adaptAgenticResponse(resp, { + wallet, + door, + rulesId, + chainNamespace: chain, + chain: chain as CHAIN, + route: 'UOA_TO_CEA', + destinationInstruction, + destinationAccount: deriveAgwSvmCea( + wallet, + CHAIN_INFO[chain as CHAIN].lockerContract ?? '' + ).address, + logical: { + to: instruction.program, + data: destinationInstruction.data, + value: BigInt(0), + }, + }); + } catch { + // Historical owner calls may use another payload format. Preserve the + // actual gateway call below instead of inventing instruction metadata. + } + } // The decoded wallet call is authoritative: core may have inferred a // Push-only route from an incomplete Cosmos record, which would stop // wait() from polling the destination leg. @@ -282,6 +323,7 @@ export function outboundResponseCall( } function decodeOutbound(data: Hex): { + payload: Hex; token: Address; calls: { to: Address; value: bigint; data: Hex }[]; } { @@ -312,7 +354,7 @@ function decodeOutbound(data: Hex): { calls = []; } } - return { token: getAddress(req.token), calls }; + return { token: getAddress(req.token), payload: req.payload, calls }; } async function tokenChain( diff --git a/packages/core/src/lib/agentic/runtime.ts b/packages/core/src/lib/agentic/runtime.ts index 19d63e4e..cf4c5ce1 100644 --- a/packages/core/src/lib/agentic/runtime.ts +++ b/packages/core/src/lib/agentic/runtime.ts @@ -25,6 +25,9 @@ import { chainReaderFromPublicClient, type ChainReader, } from './contracts/reader'; +import type { SvmMetadataProvider } from './management/svm-context'; +import { createSvmMetadataProvider } from './management/svm-metadata'; +import { CHAIN_INFO } from '../constants/chain'; import type { AgenticProgressHook } from './agentic.types'; /** @@ -39,6 +42,7 @@ export interface AgenticRuntime { readonly pushChainNamespace: string; readonly reader: ChainReader; readonly isReadOnly: boolean; + readonly svmMetadata?: SvmMetadataProvider; /** Connected signer's Push identity: its EOA, or its UEA for its actual origin chain. */ signerPushAccount(): Address; /** Connected signer's origin account (universal.origin). */ @@ -74,7 +78,7 @@ export interface AgenticRuntime { chain: CHAIN ): Promise<{ cea: Address; isDeployed: boolean }>; resolvePrc20( - token: MoveableToken | Address | undefined, + token: MoveableToken | string | undefined, chain: CHAIN ): Address; nowSeconds(): number; @@ -94,6 +98,14 @@ export function createAgenticRuntime( return chainReaderFromPublicClient(ctx.pushClient.publicClient); }, isReadOnly, + svmMetadata: createSvmMetadataProvider({ + [CHAIN.SOLANA_DEVNET]: { + gatewayProgram: CHAIN_INFO[CHAIN.SOLANA_DEVNET].lockerContract ?? '', + rpcUrls: + orchestrator.getRpcUrls()[CHAIN.SOLANA_DEVNET] ?? + CHAIN_INFO[CHAIN.SOLANA_DEVNET].defaultRPC, + }, + }), signerPushAccount: () => getAddress(computeUEAOffchain(ctx)), signerOrigin: () => orchestrator.getUOA(), signerIsPushNative: () => isPushChain(ctx.universalSigner.account.chain), diff --git a/packages/core/src/lib/agentic/utils.ts b/packages/core/src/lib/agentic/utils.ts index 7ec2070e..3ecb421e 100644 --- a/packages/core/src/lib/agentic/utils.ts +++ b/packages/core/src/lib/agentic/utils.ts @@ -1,3 +1,5 @@ +import { decodeSvmTerms, validateSvmTerms } from './codec/svm-terms'; +import { svmKey } from './codec/svm-accounts'; import { getAddress, isHex, zeroAddress, type Address, type Hex } from 'viem'; import { CHAIN, PUSH_NETWORK } from '../constants/enums'; import { MOVEABLE_TOKENS } from '../constants/tokens'; @@ -22,7 +24,12 @@ import { import { pushChainNamespaceFor } from './chain'; import { decodeUniversalTerms } from './codec/universal-terms'; import { universalTermsToRule } from './codec/universal'; -import type { AgenticHex, Rule, Selector } from './agentic.types'; +import type { + AgenticHex, + Rule, + Selector, + DecodedSolanaRule, +} from './agentic.types'; import type { UniversalRule } from './agentic.types'; import type { ResolvedUniversalRule } from './codec/universal'; @@ -115,7 +122,7 @@ export const internalAgenticUtils = { decodeRules( bytes: Hex, ctx: { network?: PUSH_NETWORK; pushChainNamespace?: string } = {} - ): Rule { + ): Rule | DecodedSolanaRule { if (!isHex(bytes)) throw new AgenticError( AGENTIC_ERROR_CODE.INVALID_RULE, @@ -138,10 +145,51 @@ export const internalAgenticUtils = { session.actions[0].actionPolicies[0].initData ); if (chainNamespace !== nativeNamespace(ctx)) { + if (chainNamespace.startsWith('solana:')) { + const terms = decodeSvmTerms(body); + validateSvmTerms(terms, -1); + const assets = terms.assets.map((a) => { + const chain = chainNamespace as CHAIN; + const token = (MOVEABLE_TOKENS[chain] ?? []).find((candidate) => { + try { + return ( + getAddress( + getPRC20Address( + { chain, address: candidate.address }, + { network: ctx.network ?? PUSH_NETWORK.TESTNET_DONUT } + ).address + ) === getAddress(a.token) + ); + } catch { + return false; + } + }); + if (!token) + throw new AgenticError( + AGENTIC_ERROR_CODE.RULE_READ_FAILED, + 'SVM source token is absent from the static registry; use wallet.rules.get()' + ); + return { + token: + token.mechanism === 'native' + ? zeroAddress + : svmKey(token.address), + maxPerCall: a.maxPerCall, + maxTotal: a.maxTotal, + }; + }); + return { + ...terms, + format: 'decoded', + agent, + chainNamespace: chainNamespace as `solana:${string}`, + assets, + }; + } if (!chainNamespace.startsWith('eip155:')) throw capabilityUnavailable( AgenticCapability.UNIVERSAL_SVM_RULES, - 'SVM public decoding is pending' + 'unsupported universal chain namespace' ); let terms; try { @@ -189,11 +237,7 @@ export const internalAgenticUtils = { tokens ); } - return nativeTermsToRule( - decodeNativeTerms(body), - agent, - `0x${'00'.repeat(32)}` - ); + return nativeTermsToRule(decodeNativeTerms(body), agent); }, }; diff --git a/packages/core/src/lib/index.ts b/packages/core/src/lib/index.ts index 688b72f0..940cf4c4 100644 --- a/packages/core/src/lib/index.ts +++ b/packages/core/src/lib/index.ts @@ -207,6 +207,11 @@ export type { CreateResult, ForeignChainNamespace, NativeRule, + SolanaRule, + DecodedSolanaRule, + SvmInstructionRule, + SvmAccountRef, + SvmFieldConstraint, Rule, RulesRecord, Selector, diff --git a/packages/core/src/lib/vm-client/evm-client.batch-gas.spec.ts b/packages/core/src/lib/vm-client/evm-client.batch-gas.spec.ts new file mode 100644 index 00000000..d117592e --- /dev/null +++ b/packages/core/src/lib/vm-client/evm-client.batch-gas.spec.ts @@ -0,0 +1,75 @@ +import { bytesToHex, parseTransaction } from 'viem'; +import { EvmClient } from './evm-client'; +import { CHAIN } from '../constants/enums'; +import type { UniversalSigner } from '../universal/universal.types'; +const account = '0x3333333333333333333333333333333333333333', + executor = '0x4444444444444444444444444444444444444444'; +function fixture() { + const client = new EvmClient({ rpcUrls: ['http://localhost:8545'] }); + const estimateGas = jest.fn(), + send = jest + .fn, [Uint8Array]>() + .mockResolvedValue(new Uint8Array(32)); + client.publicClient = { + estimateGas, + getCode: jest.fn().mockResolvedValue('0xef0100' + executor.slice(2)), + estimateFeesPerGas: jest.fn().mockResolvedValue({ + maxFeePerGas: BigInt(10), + maxPriorityFeePerGas: BigInt(1), + }), + getChainId: jest.fn().mockResolvedValue(42101), + getTransactionCount: jest.fn().mockResolvedValue(5), + } as never; + const signer: UniversalSigner = { + account: { chain: CHAIN.PUSH_TESTNET_DONUT, address: account }, + signMessage: async (x) => x, + signAuthorization: jest.fn().mockResolvedValue({ + address: executor, + chainId: 42101, + nonce: 6, + yParity: 0, + r: '0x' + '11'.repeat(32), + s: '0x' + '22'.repeat(32), + }), + signAndSendTransaction: send, + }; + const run = () => + client.sendBatch7702({ + executor, + signer, + calls: [ + { to: executor, value: BigInt(0), data: '0x12345678' }, + { to: executor, value: BigInt(0), data: '0x12345678' }, + ], + }); + return { client, estimateGas, send, run }; +} +describe('7702 estimation without guessed per-call ceilings', () => { + it('uses a real estimate for an already delegated account when authorization RPC support is absent', async () => { + const f = fixture(); + f.estimateGas + .mockRejectedValueOnce(new Error('unsupported auth list')) + .mockResolvedValueOnce(BigInt(1_400_000)); + await f.run(); + const tx = parseTransaction(bytesToHex(f.send.mock.calls[0][0])); + expect(tx.gas).toBe(BigInt(1_705_000)); + expect(f.estimateGas.mock.calls[1][0]).not.toHaveProperty('stateOverride'); + }); + it('uses a delegation override for a fresh account only when authorization estimation fails', async () => { + const f = fixture(); + (f.client.publicClient.getCode as jest.Mock).mockResolvedValue('0x'); + f.estimateGas + .mockRejectedValueOnce(new Error('unsupported')) + .mockResolvedValueOnce(BigInt(2_000_000)); + await f.run(); + expect(f.estimateGas.mock.calls[1][0].stateOverride[0].code).toBe( + '0xef0100' + executor.slice(2) + ); + }); + it('does not broadcast a guessed gas budget when all supported estimates fail', async () => { + const f = fixture(); + f.estimateGas.mockRejectedValue(new Error('execution rejected')); + await expect(f.run()).rejects.toThrow('execution rejected'); + expect(f.send).not.toHaveBeenCalled(); + }); +}); diff --git a/packages/core/src/lib/vm-client/evm-client.ts b/packages/core/src/lib/vm-client/evm-client.ts index 5d66c4b6..88e365ea 100644 --- a/packages/core/src/lib/vm-client/evm-client.ts +++ b/packages/core/src/lib/vm-client/evm-client.ts @@ -428,29 +428,35 @@ export class EvmClient { throw new EIP7702NotSupportedError(err); } - // Estimate gas against the delegated account: override the EOA's code with - // the 7702 delegation designator (0xef0100 || executor) so estimation runs - // the executor. Fall back to a safe ceiling if the node rejects overrides. + // Prefer authorization-aware estimation of the actual type-4 transaction. + // Some RPCs reject that format or state overrides. An ordinary estimate is + // valid only if the account is already delegated to this exact executor. + // Never guess a per-call ceiling: contract deployment/grants vary in cost. + const delegation = ('0xef0100' + executor.slice(2)) as Hex; let gas: bigint; try { gas = await this.publicClient.estimateGas({ account, to: account, data, - stateOverride: [ - { - address: account, - code: ('0xef0100' + executor.slice(2)) as Hex, - }, - ], + authorizationList: [authorization as never], }); - gas = (gas * BigInt(120)) / BigInt(100); // headroom for delegation + auth } catch { - // Estimation unavailable (e.g. node rejects state overrides). Scale the - // ceiling with the batch size so large batches don't OOG — the legacy - // per-call loop budgeted ~500k gas per call; mirror that plus overhead. - gas = BigInt(500_000) * BigInt(calls.length) + BigInt(100_000); + const code = await this.publicClient.getCode({ address: account }); + if (code?.toLowerCase() === delegation.toLowerCase()) { + gas = await this.publicClient.estimateGas({ account, to: account, data }); + } else { + gas = await this.publicClient.estimateGas({ + account, + to: account, + data, + stateOverride: [{ address: account, code: delegation }], + }); + } } + // The fallback estimates omit authorization processing (25k intrinsic). + // Include it conservatively on every path, plus 20% execution headroom. + gas = (gas * BigInt(120) + BigInt(99)) / BigInt(100) + BigInt(25_000); const unsignedTx = serializeTransaction({ chainId, diff --git a/plan/agw/README.md b/plan/agw/README.md index 282fa4db..344a51d1 100644 --- a/plan/agw/README.md +++ b/plan/agw/README.md @@ -1,24 +1,12 @@ # AGW SDK planning -This package contains the SDK implementation plan, source snapshots, open decisions and validation evidence. Current work is on feat/agw-sdk-v4. Runtime commits are a66ff7d (v4/SVM foundations) and b68bab7 (gas headroom); current validation is linked below. Native/EVM support now uses the checked Donut v4 deployment; old runtime adapters/ABIs/fixtures were removed. All 25 registered AGW scenarios have passing bounded live coverage, including native/UEA identities and Sepolia outbound success/failure. +This package contains planning, source snapshots and review evidence for `feat/agw-sdk-v4`. Current runtime uses Donut v4 source `e8db748`; legacy runtime adapters have been removed. -Latest E2E expansion: [extended AGW live coverage](research/extended-e2e-2026-10-06/README.md) adds 14 funded scenarios to the existing opt-in `agw` group. All 14 pass; the wallet-index race caught and fixed an SDK error-classification gap. The default E2E selection remains unchanged. +**October 7:** product decisions are settled. Public named-IDL Solana lifecycle/sends/reads/replay are implemented, rule `ref` is removed, zero native PC defaults are confirmed, and native/EVM raw-offset authoring is approved. Seven additional E2Es passed on Donut/devnet, bringing the opt-in AGW group to 46 scenarios with selected-run live coverage. The final local/unit/build results are in [implementation status](implementation-status.md). -Latest: [live acceptance and fixes](research/live-acceptance-2026-10-06/README.md), following the [v4 migration](research/v4-implementation-2026-10-06/README.md). The unrestricted full core unit run passes 1,982 tests; the actual-contract harness passes 75. Build and four typechecks pass. Native defaults/raw-offset API/multi-rule selection decisions, absent ref/labels, public SVM integration and release scope remain explicit. +The remaining AGW contract delivery item is editable labels. The existing agent door already validates the supplied rule; the SDK retains its ambiguity guard when several candidates match. [Zaryab delivery items](questions-zaryab.md); [confirmed decisions](questions-harsh.md). -The public target remains [Notion page 5](notion/5-sdk-agw.md), qualified by [Harsh's replies](product-decisions-2026-10-04.md) and [live comments](research/notion-comments-2026-10-05.md). The [v4 deployment/owner-guide review](research/deployment-review-2026-10-06/README.md) records the supplied deployed wire definitions. Historical adapter-absence statements in that review describe the pre-migration inspection, not current implementation. - -Latest SVM work: [internal codec/account/payload foundation](research/svm-internals-2026-10-06/README.md) now passes 23 unit and 10 in-process actual-contract checks. Public mapping/dispatch remains gated. Network permissions are restored. All seven SVM Anvil tests now pass and the unfiltered core unit suite passes, including the four previously network-blocked titles. Public Solana execution remains untested. - -Latest SDK-owned work: [delayed-index contract acceptance and checked consumer guide](research/sdk-independent-followup-2026-10-06/README.md). No public API decision was changed by this follow-up. - -Latest: [all nine SDK-owned items completed](research/sdk-independent-completion-2026-10-06/README.md). Internal SVM integration, Solana confirmation, CI and package/API checks are complete; public SVM remains gated. - -Latest validation: [selected differential/race/API/runtime hardening](research/sdk-hardening-2026-10-06/README.md). Both Node 20/24 pass; existing live E2E receipts are independently rechecked. - -Before sharing: [October 6 question source recheck](research/question-source-recheck-2026-10-06/README.md) confirms unchanged contract heads and re-inspects live pages 1/5 and All discussions. Drafts now ask only remaining public/release decisions; the Solana fixture is explicitly optional, and internal wire-level validation can proceed independently. - -Latest independent work: [live internal Solana wire validation](research/live-svm-wire-2026-10-06/README.md) verifies actual CEA transfer/CPI, receipts/replay and policy refusals. The initial funded run is 2 passed / 1 ten-minute timeout; that request later reached REVERTED and read-only replay verified failed. Public SVM stays gated. [Concrete API proposals](public-api-proposals.md) are ready; Zaryab's fixture request is closed. +Consumer documentation lives in [packages/core/AGW.md](../../packages/core/AGW.md). Earlier dated reports below are historical evidence; their pending-capability statements describe those earlier revisions. ## Start here @@ -38,7 +26,7 @@ Latest independent work: [live internal Solana wire validation](research/live-sv | [External blockers](external-blockers.md) | Remaining defaults/type clarification and contract/deployment dependencies | | [Questions for Harsh](questions-harsh.md) | Product decisions and recommendations | | [Questions for Zaryab](questions-zaryab.md) | Ref/label v1 scope and joint Solana review; fixture request closed | -| [Public API proposals](public-api-proposals.md) | Concrete Solana input/read and raw-offset/selection choices for review | +| [Public API proposals](public-api-proposals.md) | Historical proposals with their final dispositions | | [Review summary](review-summary.md) | Consequential independent-review corrections | ## Sources and evidence diff --git a/plan/agw/current-baseline.md b/plan/agw/current-baseline.md index 39192803..d7568499 100644 --- a/plan/agw/current-baseline.md +++ b/plan/agw/current-baseline.md @@ -1,8 +1,8 @@ # Current validated AGW baseline -Updated October 6, 2026 after the v4 deployment notice, source/ABI inspection, read-only Donut probe and extended E2E run. **The v4 deployment and native/EVM SDK adapter/codecs are integrated locally. The 25 previously registered AGW scenarios and 14 added management/policy scenarios are all part of the opt-in `agw` group and have passing selected-run live coverage.** [Extended E2E evidence](research/extended-e2e-2026-10-06/README.md); [full deployment review](research/deployment-review-2026-10-06/README.md). +Updated October 7, 2026 after confirmed product decisions, fresh contract refs, and public Solana/native acceptance. **The v4 deployment and native/EVM SDK adapter/codecs are integrated locally. The opt-in `agw` group now includes 46 scenarios with selected-run live coverage: 39 previous cases and seven decision-alignment cases.** [Extended E2E evidence](research/extended-e2e-2026-10-06/README.md); [full deployment review](research/deployment-review-2026-10-06/README.md). -The public SDK target remains Notion page 5, qualified by Harsh's later replies/comments. The new owner guide establishes deployed wire behavior; mismatches in public ref/labels/defaults/selection remain explicit. [Prior October 3–5 baseline](research/deployment-review-2026-10-06/previous-current-baseline.md) is retained as historical evidence. +The public SDK target remains Notion page 5, qualified by Harsh's later replies/comments. The new owner guide establishes deployed wire behavior; the October 7 decisions remove rule ref, confirm defaults and existing ambiguity handling, and leave editable labels pending contract delivery. [Prior October 3–5 baseline](research/deployment-review-2026-10-06/previous-current-baseline.md) is retained as historical evidence. ## Pinned sources @@ -43,13 +43,13 @@ The earlier supplied historical addresses are superseded for new v4 integrations | All policy envelopes | uint16 version=1, chainNamespace, body | Envelope 1 implemented; old envelope rejected by actual contracts | | Universal EVM | 1–8 ordered AssetCaps, maxGasPerCall, address expectedCEA | Implemented, including source-chain/token identity validation and v4 reads | | No-movement rules | One destination gas PRC20 cap at 0/0 when user assets empty | Implemented; actual-contract call-only case passes | -| Total ceilings | maxUint256 unlimited, zero hard zero | Universal max default/explicit zero implemented; native omission choices partly open | +| Total ceilings | maxUint256 unlimited, zero hard zero | Universal max default/explicit zero and confirmed zero native PC defaults implemented | | Internal replacement guard | assertSpent(configId,wallet,uint256[]) compares all totals in asset order | SDK implemented; second-token intervening spend rolls back replacement | | Native terms | Same body layout, one config per action; envelope changed | V4 native tests pass; ABI offset validation retained | -| Multiple rules | Several same-agent/same-chain grants supported | Management permits multiplicity; ambiguous sends fail; H6 selection remains | +| Multiple rules | Several same-agent/same-chain grants supported | Management permits multiplicity; ambiguous sends are refused by the SDK, and the contract enforces the supplied rule | | Checkpoints | Stored count/last block, three event kinds, per-owner-call/lifecycle ticks | Local and registered live native/EVM lifecycle acceptance pass | -| Grant ref / label | Grant has no ref; label is deployment event only; no setLabel | Explicit capability gates; Z1.3 asks v1 scope/delivery | -| SVM | Full multi-asset terms/program/account/data pins supplied | Internal live CEA transfer/CPI, replay and policy refusals pass. Initial rejection timed out, then REVERTED/failed replay was verified. Public mapping/dispatch remains gated. | +| Grant ref / label | Grant has no ref; label is deployment event only; no setLabel | Rule ref removed from SDK scope; editable labels await contract delivery | +| SVM | Full multi-asset terms/program/account/data pins supplied | Public named-IDL grants/reads/replacement/sends/revoke pass live, including destination CEA transfer and replay; unsupported IDL layouts are rejected explicitly. Prior internal rejection/terminal replay evidence remains valid. | | Gateway request | Eight-field live implementation, selector 0x77b86bec | Dedicated context, listed-token choice and maxGasPerCall implemented | | Allowance | Consume separate owner-established allowance | Keep existing race-safe behavior; Live allowance/token debit passes; remaining identity coverage explicit | | Refund spend credit | creditRevert gains token; executor still does not call it | Known Push-core dependency; ordinary returns do not lower spent | @@ -61,15 +61,16 @@ The ABI comparison found matching factory/wallet/engine function/event/error sig Four checks passed: version-1 envelope round-trip/old first-word incompatibility; synthetic ordered two-asset tuple round-trip; live v4 getConfig decode with old-ABI rejection; array assertion encoding. [Results and limits](research/deployment-review-2026-10-06/wire-checks.json). This is not a rule-grant, stale-spend transaction or funded E2E proof. -The unrestricted run passes 1,982 unit and 75 actual-contract tests. All five explorer ABI sets match the isolated build. Donut is registered and all 39 AGW native/EVM/identity/management/policy cases have passing selected-run live coverage. The `agw` group remains opt-in; default `all` remains 76 scenarios. [Extended E2E evidence](research/extended-e2e-2026-10-06/README.md); [prior acceptance evidence](research/live-acceptance-2026-10-06/README.md). +See [implementation status](implementation-status.md) for the final unit and actual-contract counts. All five explorer ABI sets match the isolated build. Donut is registered and all 46 AGW native/EVM/identity/management/policy/public-Solana cases have passing selected-run live coverage. The `agw` group remains opt-in; default `all` remains 76 scenarios. [Extended E2E evidence](research/extended-e2e-2026-10-06/README.md); [prior acceptance evidence](research/live-acceptance-2026-10-06/README.md). -## Remaining decisions and acceptance +## Remaining delivery and acceptance -- Harsh: native PC omission defaults/token intent, raw-offset authoring/read model, multi-rule send selection and joint public Solana representation. Current target retains maxValueTotal. [Open draft](questions-harsh.md). -- Zaryab: ref/label v1 scope and joint Solana SDK review. Z1.4 fixture is closed with our own verified live example. [Open draft](questions-zaryab.md). -- SDK: native/EVM migration is implemented and locally validated. Public SVM mapping/composition and release scope decisions remain. No legacy runtime adapter is retained. -- Live: registered native/EVM/UEA/7702 and Sepolia success/failure scenarios pass. Internal Solana delivery, policy refusals and replay pass; later terminal rejection is verified through read-only replay after the initial ten-minute timeout. Public SVM destination acceptance remains after integration. [Wire evidence and limits](research/live-svm-wire-2026-10-06/README.md). +Product choices are settled: zero native PC defaults, current token budgets, named IDL Solana authoring, dual native/EVM argument-index/raw-offset inputs, and removal of rule ref. The implementation and seven new selected live cases cover these choices. + +Zaryab delivery is still needed for editable labels. The existing contract already enforces the supplied rule and rejects unauthorized actions. Keep AMBIGUOUS_RULE for multiple candidates; no automatic-selection interface or caller-facing selector is required. [Delivery items](questions-zaryab.md). + +Public Solana acceptance now passes. Source-authoring supports fixed Anchor layouts, one instruction per send, and configured devnet. See the [consumer guide](../../packages/core/AGW.md) for exact limits. The destination failure/retry and creditRevert platform limitations remain as recorded in the historical wire report. Checkpoint count semantics remain per action, not per transaction: assert/revoke/grant adds five ticks; failed transactions unwind ticks; agent calls do not tick. Pre-existing allowances may change balances without checkpoints. Preserve internal spend assertions even though public spent records are removed. -The [question source recheck](research/question-source-recheck-2026-10-06/README.md) freshly confirms unchanged deploy-agw/pushAgenticWallet_v3 heads. It records answered definitions separately from remaining public decisions and SDK-owned fixture validation; it does not claim a fresh live bytecode probe. +The historical [October 6 source recheck](research/question-source-recheck-2026-10-06/README.md) records unchanged contract heads; the October 7 fetch confirmed the same refs. It records answered definitions separately from remaining public decisions and SDK-owned fixture validation; it does not claim a fresh live bytecode probe. diff --git a/plan/agw/external-blockers.md b/plan/agw/external-blockers.md index 37dfc196..8607cf16 100644 --- a/plan/agw/external-blockers.md +++ b/plan/agw/external-blockers.md @@ -1,55 +1,13 @@ -# Remaining external dependencies for AGW +# Remaining AGW external dependencies -Rechecked October 6, 2026 against live Notion pages 1/5 and All discussions, all saved sources, freshly fetched contract refs and SDK code. [Question dispositions and evidence](research/question-source-recheck-2026-10-06/README.md). Contract wire/accounting definitions and deployment addresses are supplied; distinguish remaining decisions from SDK implementation and live acceptance. +Updated October 7, 2026. Product decisions are settled: keep zero native PC defaults and the current token model; use named IDL inputs for Solana; retain dual native/EVM argument-index/raw-offset inputs; remove rule `ref`. -## Remaining team input - -| Area | Owner | Remaining answer | +| Dependency | Owner | Needed artifact | | --- | --- | --- | -| Native PC optional-input defaults/token intent | Harsh H3 | Exact omitted maxValuePerCall/maxValueTotal behavior and whether token-independence requests a public-model change; current target retains maxValueTotal | -| Public Solana representation | Harsh H4.4 with Zaryab | Solana-specific authoring/read shape, explicit program/account/data constraints versus higher-level IDL inputs; wire structs are supplied | -| Decoded-rule representation | Harsh H4.5 | Public native/EVM raw-offset authoring versus separate decoded records | -| Multiple-rule execution | Harsh H6 | Explicit caller rule selection versus a defined automatic strategy, including arrays/overlapping rules; same-agent capacity is supplied | -| Metadata scope | Zaryab Z1.3 with Harsh | Whether absent grant ref/editable label will be delivered or explicitly deferred from v1 | - -Zaryab Z1.4 is now **closed with SDK-owned evidence**: the configured devnet gateway and counter IDL were checked against actual deployed accounts, and internal AGW delivery/receipt/replay passed. [Live Solana wire report](research/live-svm-wire-2026-10-06/README.md). No external fixture is needed for that baseline. [Concrete public API proposals](public-api-proposals.md) are ready for H4.4/H4.5/H6 review. - -The owner guide retains assets[] on the rule, with each listed token usable by every allowed call. Harsh's token-independence comment is not treated as permission to remove token limits. SVM wire types are supplied; the remaining fixture request does not reopen struct delivery. - -## Delivered — now SDK work - -- V4 factory/URP addresses and implementation/engine/validator wiring: checked read-only on Donut block 23931055. The new book supersedes the earlier historical address table for new integrations. -- Multi-asset EVM/SVM wire layouts, envelope version 1, address EVM expectedCEA and per-asset spend reads/assertions: delivered and verified ABIs saved. -- Universal total encoding: maxUint256 means no total limit; explicit zero permits no movement. Empty user assets need one destination gas PRC20 routing cap at 0/0, not an empty wire array. -- Multiple same-agent/same-chain rules: contract guide explicitly permits them; product accepts multiplicity. Choosing the rule for a send remains H6. -- Separate owner allowance, immutable-wallet generations, internal accounting and sender-preserving native batching: preserve the existing design while migrating to v4. - -Native/EVM v4 migration and the internal SVM read/context/instruction/lifecycle/execution backend are implemented. The actual-contract harness is ported; runtime/test legacy artifacts were removed. [Backend evidence](research/sdk-independent-completion-2026-10-06/README.md). Public SVM adapters/presentation and live destination acceptance remain SDK work after agreeing the public model; internal wire-level validation can proceed independently. - -## Previously settled scope - -Approval screening belongs to UI/marketplace; structural/ABI validation remains in the SDK. Generation details and spend stay internal, public revoked history is deferred, and compileCard remains outside standalone AGW. Native arrays use atomic sender-preserving UEA/7702 batching, with explicit failure when unavailable. No request for those answered choices is reopened. - -## Platform and release gates - -creditRevert still depends on Push-core executor integration; the source explicitly says failures are not yet credited. Ordinary money returning does not lower spent. No-code at the module account is not by itself evidence of a defect. - -All 25 registered AGW live scenarios have passing bounded selected-run coverage, including UEA/7702 identities/batching, lifecycle, allowance, response hooks/replay and Sepolia outbound success/failure. This resolves the outstanding native/EVM acceptance tasks; public Solana destinations still need integration and live coverage. External product/scope decisions above remain separate. [Current evidence](research/live-acceptance-2026-10-06/README.md). - -**SVM negative acceptance:** the initial ten-minute wait returned timeout while the outbound was pending. The same request subsequently became REVERTED, and read-only SDK replay returned failed with Push status 1. Terminal classification is now supplied/verified; no new hard delivery blocker is inferred. Retry/terminalization timing and richer program-error reporting are optional [operational follow-ups](research/live-svm-wire-2026-10-06/platform-followup.md). Returned funds still do not lower the rule's spend, consistent with the separate creditRevert dependency. - -## Freshness - -Fresh fetch confirms AGW source e8db748 and documentation head deploy-agw@10a24f1, with identical src. The earlier verified ABIs/probe remain in the [review bundle](research/deployment-review-2026-10-06/README.md); subsequent [wire preflight and acceptance](research/live-svm-wire-2026-10-06/README.md) recheck live wiring and both networks. Full units now pass 1,981; prior unchanged local-contract evidence is 75 passes, and native/EVM live coverage is 25 scenarios. New Solana wire/replay outcomes are recorded separately, including the initial timeout and later terminal failure. Core/gateway source pins were not refreshed. - -Notion's last full export remains October 3, with October 4 body comparison, October 5 comments and a fresh October 6 live inspection of pages 1/5 and All discussions. The GitHub guide supplies deployed wire behavior; the target public API remains qualified by Harsh's replies. - -## SVM foundation and current execution environment - -[SVM internals](research/svm-internals-2026-10-06/README.md) are implemented and tested, including all seven Anvil cases. Full permissions and RPC access are restored. Authorized bounded Donut tests have completed; networking and test funding are no longer blockers. Public SVM destination mapping/dispatch and live Solana acceptance remain separate work. +| Editable labels | Zaryab | Implemented owner-only label function/event ABI and compatible deployment | -## SDK-owned follow-up completed +Fresh fetch still shows `deploy-agw@10a24f1` / source `e8db748`. Its agent door already enforces the supplied `rulesId`. The SDK retains AMBIGUOUS_RULE for multiple candidates and maps contract rejections. No automatic-selection interface is requested. Only setLabel needs a new AGW interface/deployment. -The [independent SDK follow-up](research/sdk-independent-followup-2026-10-06/README.md) closes deliberate delayed-index replay/wait coverage using real local transactions/receipts and controlled indexer responses. The consumer AGW guide and public-export example checker are supplied. Neither change chooses unresolved defaults, raw-offset authoring or a multiple-rule selection API. +Public Solana SDK integration is now implemented. Its supported IDL layouts and validation are documented in the [consumer guide](../../packages/core/AGW.md). See [implementation status](implementation-status.md) for test results. -The [nine-item completion report](research/sdk-independent-completion-2026-10-06/README.md) records the finished internal SVM integration and automated checks. These are no longer missing SDK backend components; public adapters/capability enablement and live destination acceptance remain after the external decisions. +`creditRevert` remains a separate Push-core executor dependency. Returned funds do not restore policy spend. This does not require a new product decision or permit the SDK to decrement counters itself. diff --git a/plan/agw/gaps.md b/plan/agw/gaps.md index a8d1b2b3..a09378e7 100644 --- a/plan/agw/gaps.md +++ b/plan/agw/gaps.md @@ -1,8 +1,10 @@ # AGW contract and SDK gap register -Updated October 6, 2026 after the [v4 deployment/owner-guide review](research/deployment-review-2026-10-06/README.md), [Harsh’s replies](product-decisions-2026-10-04.md), v4 implementation on feat/agw-sdk-v4, and [live Notion comments](research/notion-comments-2026-10-05.md). This register distinguishes unresolved dependencies, implemented SDK work, deferred scope and historical corrections. G01–G26 are tracking IDs, not a count of open defects. +**October 7 alignment:** all product choices are settled. Named-IDL Solana integration and removal of rule `ref` are implemented; raw-offset inputs remain supported. Editable labels await Zaryab’s interface/deployment. Contract validation already exists; retain the SDK ambiguity guard. [Current delivery items](questions-zaryab.md). -Evidence: [current baseline](current-baseline.md), [implementation status](implementation-status.md), [product alignment validation](research/product-alignment-2026-10-04/README.md), and [extended live E2Es](research/extended-e2e-2026-10-06/README.md). The unrestricted v4 SDK run passes 1,982 unit tests and 75 local-contract tests. All 39 scenarios in the opt-in AGW group pass selected-run live coverage; default E2E selection remains unchanged. Public SVM destinations remain gated. +Updated October 7, 2026 following the clarified contract-enforcement decision, the [v4 deployment/owner-guide review](research/deployment-review-2026-10-06/README.md), [Harsh’s replies](product-decisions-2026-10-04.md), v4 implementation on feat/agw-sdk-v4, and [live Notion comments](research/notion-comments-2026-10-05.md). This register distinguishes unresolved dependencies, implemented SDK work, deferred scope and historical corrections. G01–G26 are tracking IDs, not a count of open defects. + +Evidence: [current baseline](current-baseline.md), [implementation status](implementation-status.md), [product alignment validation](research/product-alignment-2026-10-04/README.md), and [extended live E2Es](research/extended-e2e-2026-10-06/README.md). The final validation counts are in [implementation status](implementation-status.md). The opt-in AGW group now registers 46 cases; seven new cases passed on Donut/devnet. Default `all` remains unchanged. Current contract baseline: reported deployed source `e8db748`, documentation head `deploy-agw@10a24f1` (src unchanged between them). Donut v4 addresses/code/wiring and URP 3.1.0 were checked at block 23931055; verified ABIs were saved. The SDK now uses v4 only, registers Donut and has a ported actual-contract harness. [Implementation evidence](research/v4-implementation-2026-10-06/README.md). Core marketplace cb69e0b and gateway bcbf7df remain prior source pins; they were not freshly fetched. Notion bodies were not refreshed in this pass. @@ -10,15 +12,11 @@ Current contract baseline: reported deployed source `e8db748`, documentation hea | Dependency | Owner | Related IDs | | --- | --- | --- | -| Token-model wording; Harsh now prefers zero native PC defaults, Zaryab invited to comment | [Harsh H3](questions-harsh.md#h3) | G19 | -| Public Solana authoring/read model; redirected to Zaryab | [Zaryab H4.4](questions-zaryab.md#h4-4) | G22 | -| Public raw-offset read/write representation | [Harsh H4.5](questions-harsh.md#h4-5) | G25 | -| Multiple-rule send selection (same-agent capacity is supplied) | [Harsh H6](questions-harsh.md#h6) | G26 | -| V1 ref/label scope | [Zaryab Z1.3 with Harsh](questions-zaryab.md#z1-3) | G08 | +| Editable labels: contract ABI/deployment | [Zaryab](questions-zaryab.md#z1-3) | G08 | The [October 6 source recheck](research/question-source-recheck-2026-10-06/README.md) narrowed the questions. Subsequent [live wire validation](research/live-svm-wire-2026-10-06/README.md) supplies our own Solana fixture and successful delivery/replay, closing Z1.4. The rejected outbound initially timed out, then reached REVERTED and read-only replay classified it failed. [Concrete API proposals](public-api-proposals.md) are ready; retry/terminalization timing is an operational follow-up. -Multi-asset wire/read/assertion ABI, EVM CEA width, envelope version and SVM wire layouts are now supplied. G23/G24 and the native/EVM adapter/registry migration are implemented locally; SVM mapping/live acceptance remain SDK work; do not keep asking for those delivered definitions. +Multi-asset wire/read/assertion ABI, EVM CEA width, envelope version and SVM wire layouts are now supplied. G23/G24 and the native/EVM adapter/registry migration are implemented locally; public SVM mapping and selected live acceptance are implemented; do not keep asking for those delivered definitions. Approval screening, public generation context, public spend shape, revoked-history reconstruction and compileCard are no longer unresolved standalone product questions. Native agent batching is implemented through a sender-preserving outer transport; it does not require a new batch-mode AGW agent entry point. @@ -28,38 +26,38 @@ P0 blocks agreed authorization/accounting or safe final integration. P1 affects | ID | Priority | Status | Current finding or resolution | Remaining action | | --- | --- | --- | --- | --- | -| G01 | P1 | V4 registered; live coverage passes | Checked new deployment and reproduced ABIs are integrated in the Donut-only registry; no legacy adapter fallback. | All 39 AGW scenarios have passing live coverage. Refresh wiring/source for future releases. | +| G01 | P1 | V4 registered; live coverage passes | Checked new deployment and reproduced ABIs are integrated in the Donut-only registry; no legacy adapter fallback. | All 46 AGW scenarios have passing live coverage. Refresh wiring/source for future releases. | | G02 | P0 | Source deployed; native/UEA acceptance passes | D3 executeAsAgent/agentOf and sender adapter exist in v4; documented wiring matches live reads. SmartSession is unchanged. | Sender-binding/alternate-path tests and live native/UEA/7702 acceptance pass; do not reopen the engine-fork proposal. | | G03 | P1 | SDK question resolved and implemented | Validator/nonce ID calculation and generation-specific derivation are internal. Public generation-context helpers were removed per Harsh H4.1. IDs remain wallet-scoped and receipt-confirmed. | V4 vectors and receipt-confirmed IDs are verified; no public context-signature approval is needed. | | G04 | P1 | ABI history corrected; release note | Six-field main is older; inspected current gateway and historical Donut dispatcher use eight fields. A hypothetical future field removal is not a present SDK blocker. | Encode the selected manifest’s gateway ABI and track any actual migration with that deployment. | | G05 | P1 | Downstream marketplace alignment | Core cb69e0b requires rule/job expiry equality; supporting Notion pages have conflicting inequalities. | Align the marketplace/compiler track. Do not impose job equality on every standalone AGW rule. | | G06 | P2 | Closed for v1 | Binder was never in the reviewed code and is dropped for v1. | No binder implementation or binder-dependent lifecycle requirement in standalone AGW. Preserve historical snapshots as evidence. | | G07 | P1 | Known platform dependency | creditRevert depends on Push-core executor work. Until delivered, a far-side failure can leave spend inflated. | Track platform delivery and document/test the limitation. This is not an unanswered AGW redesign question. | -| G08 | P1 | Metadata scope still open | V4 keeps checkpoints but still has no grant ref or setLabel; label is event-only at deployment. Revoked history is deferred. | Confirm ref/label v1 scope with Zaryab/Harsh. Keep absent capabilities explicit; do not fabricate storage/events or request additions solely for historical reads. | +| G08 | P1 | Label delivery pending; ref removed | Public rule ref has been removed; checkpoint refs remain. Editable labels are approved but absent from the inspected ABI. | Verify Zaryab’s label interface/deployment before enabling. | | G09 | P1 | Deferred from standalone AGW | Canonical card schema/encoding remains a marketplace issue. Harsh H5 removes compileCard from standalone AGW; its public stub was removed. | Resume schema/compiler vectors under the future marketplace scope, not as an AGW release blocker. | | G10 | P1 | Downstream marketplace scope | Current marketplace binds one EVM chain and one rulesId; broader card binding remains unresolved downstream. | Align future marketplace/job cardinality. Standalone AGW does not invent multi-rule job bindings. | | G11 | P1 | Downstream job dependency | Payment-token selection differs between the target job SDK and the one-token-per-deployment kernel. | Align selected K-12/deployment design in the job track. | | G12 | P1 | Downstream evaluator/hook delivery | Current start/fund guards exist; evaluator baseline/submit integration is incomplete. | Verify lifecycle placement and bypasses in the separate marketplace/job/evaluator work. | | G13 | P1 | SDK implemented locally; race classification verified live | Core supports native 7702 batching with a sequential fallback. Creation uses actual capability, index-bound deployment and receipt/recovery metadata. The extended live race test verifies no rules reach the competing wallet, reports `INDEX_RACE`, and retries at the next slot. | Correct the stale factory-batch requirement in source docs when maintained; native creation and UEA identity acceptance pass on the verified deployment. | -| G14 | P1 | V4 native/EVM update implemented locally | Ordered all-token assertions precede revoke/grant; actual second-token spend races roll back the entire update and checkpoints. Native per-action guards retained. | Native/EVM updates pass live. Public SVM wrapper remains. | +| G14 | P1 | V4 native/EVM update implemented locally | Ordered all-token assertions precede revoke/grant; actual second-token spend races roll back the entire update and checkpoints. Native per-action guards retained. | Native/EVM/SVM updates pass selected live coverage. | | G15 | P2 | SDK implemented locally | create deploys/grants only; funding is separate. No required new createWallet factory method. Index binding prevents grants on a raced wallet; partial recovery preserves operation receipts and unknown state. | Final-generation events/native batching and UEA identities are verified; do not restore removed funding inputs. | | G16 | P1 | Implemented; migration documentation supplied | READ.CHAIN.WEB2 is web2. Legacy web2:https input is normalized to unchanged wire identity. Deprecated aliases now use the new public value. | The consumer guide documents the alias/literal migration; Web2 normalization/read-source tests pass. | | G17 | P1 | SDK decision implemented locally | Read-only write guards and explicit agenticWallet selection on reinitialize are implemented. Signer/network/wallet changes rebuild role/capability context. | Preserve compatibility coverage and verify with the release deployment. | -| G18 | P1 | SDK behavior implemented locally; selection under review | Initialization uses enabled-rule identity; sends perform uncached lookup without expiry filtering. Missing/ambiguous candidates fail before signing. Public list is enabled-only; unknown/revoked get returns RULE_NOT_FOUND. The October 5 multiple-rules comment may change selection/cardinality assumptions. | Resolve G26 before treating uniqueness/ambiguous-candidate behavior as final. Verify final-generation and live permission-change cases; public history is deferred. | -| G19 | P0/P1 | Defaults match Harsh’s latest preference; token wording open | Universal omission uses maxUint256 and explicit zero is hard zero; empty input gets a gas-token 0/0 route. Harsh’s October 6 reply prefers native PC omission at 0, matching the SDK, and invites Zaryab’s comment. Current live NativeRule retains maxValueTotal; wire sentinel meanings are supplied. | Clarify the intended token model and record any Zaryab qualification; preserve the current field unless an explicit revision is supplied. | -| G20 | P1 | V4 composer/response and live EVM acceptance pass | Uses selected listed token, maxGasPerCall, wallet CEA/refund context, separate allowance and signer gas. Local requests pass actual URP with fixture gateway. | Production token debit, node/TSS delivery, CEA execution attribution/balance, replay identity and destination-revert classification pass. Public SVM integration remains tracked under G22. | +| G18 | P1 | SDK behavior confirmed and implemented | Initialization uses enabled-rule identity; sends perform uncached lookup without expiry filtering. Missing/ambiguous candidates fail before signing. A single selected rule is enforced by the contract. Public list is enabled-only; unknown/revoked get returns RULE_NOT_FOUND. | Preserve ambiguity, uncached lookup and contract-error mapping coverage; public history is deferred. | +| G19 | P1 | Product choice settled; SDK aligned | Omitted native PC limits are zero. Current assets model and independent token budgets remain. | New omission-default E2E passes; retain boundary tests. | +| G20 | P1 | V4 composer/response and live EVM acceptance pass | Uses selected listed token, maxGasPerCall, wallet CEA/refund context, separate allowance and signer gas. Local requests pass actual URP with fixture gateway. | Production token debit, node/TSS delivery, CEA execution attribution/balance, replay identity and destination-revert classification pass. Public SVM acceptance is recorded under G22. | | G21 | P1 | Product direction resolved; batching implemented locally | NativeRule remains one action. Arrays use a sender-preserving UEA/7702 outer batch of single executeAsAgent calls, each checked by policy. Native sequential fallback is prohibited. Local real-type-4 tests prove sender identity, cumulative counters and mined rollback. | Release-deployment UEA identities and native 7702 batch/rollback cases pass. The local executor is a fixture; arbitrary forwarding helpers are not a substitute for the agent account. | -| G22 | P1 | Internal SVM delivery and terminal replay verified; public integration pending | Actual CEA transfer/CPI, replay and deployed policy refusals pass. Initial rejection wait timed out; the same outbound later became REVERTED and replay returned failed. Public capability stays gated. | H4.4: agree public authoring/read mapping, connect adapters and complete public acceptance. Z1.4 fixture delivery is closed; terminalization timing is an operational follow-up, not a newly inferred delivery blocker. | -| G23 | P0 | V4 EVM integration verified locally and live | Multi-asset codecs/reads/outbound, envelope 1, source chain/token identity, hard-zero semantics and empty-input routing are implemented. Old adapter/ABIs/fixtures removed. | Registered EVM acceptance passes. Public SVM SDK mapping/composition remains. | -| G24 | P1 | Internal per-token update verified locally and live | Reads/stores every expected counter in asset order; array assertion catches intervening second-token spend. Public spent stays absent. | Live two-asset replacement passes; public SVM integration remains. | -| G25 | P1 | Public raw-offset decision open | Exact native pin/amount offsets and EVM beneficiaryOffset are returned/accepted losslessly; no invented argument indexes. This extends the target input shape. | H4.5: public raw authoring versus separate decoded wire records. | -| G26 | P1 | Management implemented; send selection open | Same-agent/same-chain grants are accepted. Multiple matching send candidates fail with AMBIGUOUS_RULE and their IDs. | H6: choose explicit versus automatic selection, including arrays/overlapping rules; never arbitrarily select or revoke. | +| G22 | P1 | Public IDL integration implemented | Named Anchor IDL authoring, exact stored reads, wallet context, sends and replay are wired. Unsupported layouts are explicitly rejected. | Four public Solana E2Es pass, including real destination transfer and replay. Maintain supported-layout limits. | +| G23 | P0 | V4 EVM integration verified locally and live | Multi-asset codecs/reads/outbound, envelope 1, source chain/token identity, hard-zero semantics and empty-input routing are implemented. Old adapter/ABIs/fixtures removed. | Registered EVM acceptance passes. Public SVM mapping/composition now passes local and selected live acceptance. | +| G24 | P1 | Internal per-token update verified locally and live | Reads/stores every expected counter in asset order; array assertion catches intervening second-token spend. Public spent stays absent. | Live EVM two-asset and public SVM replacement pass. | +| G25 | P1 | SDK choice approved and implemented | Native/EVM authoring accepts argument indexes or raw offsets; reads preserve exact values. Conflicting forms are rejected. | Decoded native rule re-grant E2E passes. | +| G26 | P1 | Closed: existing selection behavior retained | The SDK refuses multiple matching candidates with AMBIGUOUS_RULE. The contract validates the supplied rule and rejects unauthorized actions; errors are mapped. | Maintain ambiguity and rejection coverage. No selection ABI change is required. | ## Validation and release boundaries -The [existing acceptance evidence](research/live-acceptance-2026-10-06/README.md) records the original native/EVM coverage. The [extended report](research/extended-e2e-2026-10-06/README.md) records 1,982 passing unit tests, build/typechecks, and 14/14 additional funded tests; default all remains 76. Extended cases cover management races/batching and native policy pins, caps and rollback. Public Solana destination coverage remains outstanding. +The [existing acceptance evidence](research/live-acceptance-2026-10-06/README.md) records the original native/EVM coverage. The [extended report](research/extended-e2e-2026-10-06/README.md) records 1,982 passing unit tests, build/typechecks, and 14/14 additional funded tests; default all remains 76. Extended cases cover management races/batching and native policy pins, caps and rollback. Public Solana destination transfer, rule lifecycle, refusals and replay now pass selected live coverage. -Local batch proof uses actual AGW/factory/engine/policy and real Anvil EIP-7702 transactions, with a small fixture executor. UEA shaping/replay is unit-tested and reuses the existing transport; all registered native/EVM/UEA acceptance scenarios now pass. Public Solana destination coverage remains outstanding. +Local batch proof uses actual AGW/factory/engine/policy and real Anvil EIP-7702 transactions, with a small fixture executor. UEA shaping/replay is unit-tested and reuses the existing transport; all registered native/EVM/UEA acceptance scenarios now pass. Public Solana destination transfer, rule lifecycle, refusals and replay now pass selected live coverage. ## Rules for closure @@ -68,8 +66,8 @@ Local batch proof uses actual AGW/factory/engine/policy and real Anvil EIP-7702 - expectedCEA derives from AGW plus destination context. Signer CEA and arbitrary pasted addresses are not substitutes. - Checkpoint consumers compare counts; allowance-driven balance changes are not always checkpointed. Current single replacement adds five ticks. - Internal spend assertions remain required even when public spend records are removed. -- Harsh now prefers zero native PC defaults; the implementation matches and omission is unit-tested. Token-model wording and raw-offset representation remain open. Universal total semantics are now supplied; the old zero/unlimited row must not carry into v4. -- H6 remains a send-selection choice. Same-agent capacity is supplied; uniqueness validation is provisional/stale. Token-independence wording is a product follow-up, not permission to remove policy checks. +- Zero native PC defaults, the current token model and dual raw-offset/index inputs are approved and covered by tests. Universal total semantics are now supplied; the old zero/unlimited row must not carry into v4. +- H6 is resolved: retain AMBIGUOUS_RULE and contract enforcement/error mapping. The earlier automatic-selection dependency was an assistant misinterpretation. - Harsh’s replies have been received. The linked question documents now contain remaining follow-ups; no outbound team messages were sent by this agent. -The October 5 historical table is superseded for new integrations by the October 6 v4 completion notice and address book. Contract delivery/code/wiring checks are recorded in the review; Native/EVM migration and registered funded acceptance pass. Delayed-index local acceptance and consumer documentation are complete; public SVM destination integration remains. +The October 5 historical table is superseded for new integrations by the October 6 v4 completion notice and address book. Contract delivery/code/wiring checks are recorded in the review; Native/EVM migration and registered funded acceptance pass. Delayed-index local acceptance and consumer documentation are complete; public SVM destination integration and selected acceptance now pass. diff --git a/plan/agw/implementation-status.md b/plan/agw/implementation-status.md index ba03a811..7a357122 100644 --- a/plan/agw/implementation-status.md +++ b/plan/agw/implementation-status.md @@ -1,50 +1,44 @@ # AGW SDK implementation status -> Latest: [extended AGW live coverage](research/extended-e2e-2026-10-06/README.md). The unfiltered unit suite passes 1,982 tests; all 75 Anvil cases and the core build pass. All 39 opt-in AGW scenarios, including the 14 management/native-policy additions, have passing selected-run live coverage. Public SVM destinations remain gated. - -Updated October 6, 2026. Branch feat/agw-sdk-v4; runtime commits a66ff7d and b68bab7. The native/EVM migration uses deployed source e8db748. Runtime/test e704d5b adapters, ABIs and fixtures were removed at Shoaib's request; historical review documents are evidence only. [Full handoff, commands and validation](research/v4-implementation-2026-10-06/README.md). +> October 7: [decision alignment and acceptance](research/decision-alignment-2026-10-07/README.md). All settled SDK choices are implemented. The remaining AGW contract delivery item is editable labels. ## Validation | Level | Current evidence | | --- | --- | -| Unit | 1,982 passed, 0 failed; 12 skipped; 116 suites passed, 1 skipped | -| Local actual contracts | 75 passed, 0 failed; 10 suites against e8db748 on Anvil | -| ABI reproduction | All 5 explorer ABI entry sets match the isolated build, ignoring array order | -| Runtime matrix | Node 20.19.2 and 24.14.0 pass full units, local contracts and package/API checks | -| Build/typechecks | Build and lib/spec/local/AGW-E2E typechecks pass | -| Lint | 7 pre-existing errors in unchanged files; no new errors | -| E2E selection | AGW: 39 scenarios/11 files/39 tests; default all unchanged at 76/40/81 | -| Funded live | All 39 AGW scenarios have passing selected-run coverage; 0 outstanding native/EVM scenario failures | +| Unit | 1,999 passed, 0 failed; 12 skipped | +| Actual contracts | 81 passed, 0 failed across 11 Anvil suites | +| New funded tests | 3 native cases + 4 public Solana cases pass; exact default-policy refusal rerun passes | +| Build/typechecks | Build and lib/spec/local/AGW-E2E checks pass | +| Consumer checks | Package imports, compiled declarations, API comparison and guide examples pass | +| E2E selection | AGW: 46 scenarios/12 files/46 tests; default all remains 76/40/81 | -Local gateway/core/token/executor and CEA lookup are fixtures. Actual AGW/factory/engine/validator/URP enforce the rules; native type-4 tests use real transactions. This does not prove production gateway, Cosmos/TSS, UEA or destination execution. +These are selected live runs: 39 prior cases plus seven additions, not a new single 46-case invocation. See the linked report for the initial 7702 gas failure and verified fix, public API changes, IDL-layout limits and test evidence. ## Per-step matrix | Step | Deliverable | Current status | Remaining work | | --- | --- | --- | --- | | 1 | Source/capability contract | V4 deployed source/ABIs pinned and reproduced | Refresh for future releases | -| 2 | Namespace/types/errors | Implemented; AMBIGUOUS_RULE replaces duplicate-authoring rejection | H4.5 public raw-offset boundary | +| 2 | Namespace/types/errors | Implemented; AMBIGUOUS_RULE replaces duplicate-authoring rejection | Approved dual input forms; no pending type decision | | 3 | Signer/wallet context | Owner/agent/read-only/identity guards retained | Release review; UEA identity cases pass | | 4 | Registry/adapter | Donut v4 registered; unsupported networks fail | Release review; no legacy fallback | -| 5 | Wallet/checkpoint/rule reads | Native and EVM reads implemented; source tokens/beneficiary offsets reconstructed | Metadata scope; public SVM mapping (internal reads complete) | -| 6 | Normalization/codecs | Native/EVM envelope 1, ordered caps, hard-zero/max total, empty-list routing | H3 token wording; SVM public mapping | +| 5 | Wallet/checkpoint/rule reads | Native and EVM reads implemented; source tokens/beneficiary offsets reconstructed | Editable labels await contract delivery; ref removed | +| 6 | Normalization/codecs | Native/EVM envelope 1, ordered caps, hard-zero/max total, empty-list routing | Confirmed defaults; named-IDL compiler implemented | | 7 | Create/add/revoke | Index-bound create, partial recovery, atomic writes; same-agent multiples allowed | Release review; deployed create/identity/batching paths verified | -| 8 | Atomic update | Native per-action and universal all-token assertions before revoke/grant | Public SVM authoring wrapper (internal lifecycle complete) | +| 8 | Atomic update | Native per-action and universal all-token assertions before revoke/grant | Public native/EVM/SVM lifecycle implemented | | 9 | Owner/allowance | Owner path unrestricted; explicit separate allowance retained | Release review; production allowance/token debit and delivery verified | -| 10 | Native agent sends | Sender-preserving atomic batches retained | H6 selection for multiple matching rules | +| 10 | Native agent sends | Sender-preserving atomic batches retained | Existing ambiguity guard retained; contract validation/error mapping verified | | 11 | EVM outbound | V4 asset membership, maxGasPerCall, wallet CEA/refunds, signer gas and responses | Release review; Sepolia success/failure and UEA cases verified | -| 12 | SVM destinations | Internal live positive delivery and later terminal-rejection replay verified; public capability gated | Public mapping/display/dispatch agreement, adapters and public acceptance; rejection retry timing is documented separately | +| 12 | SVM destinations | Public named-IDL lifecycle, send and replay implemented; four new public cases pass live | Maintain documented supported-layout limits; prior failure retry timing remains operational follow-up | | 13 | Responses/progress/errors | V4 ABIs and prior canonical replay/wait fixes retained | Delayed-index replay/polling tested with real contracts/receipts; no remaining SDK-owned response gap | -| 14 | E2E | 39 opt-in scenarios registered; added management/policy cases pass live | Completed native/EVM live coverage; public SVM acceptance after integration | +| 14 | E2E | 46 opt-in scenarios registered; all seven new decision-alignment cases pass live | Selected native/EVM/SVM acceptance complete | | 15 | Web2 | Prior implementation retained and included in full unit run | Consumer migration notes supplied; existing Web2 unit acceptance passes | | 16 | compileCard | Outside standalone AGW; absent public export | Future marketplace scope | -| 17 | Documentation/release | Current status/gaps/handoff updated | Product scope decisions and public SVM integration/release review | - -## Open product/contract choices +| 17 | Documentation/release | Current status/gaps/handoff updated | Label delivery and release review | -A01 approval policy, A04 internal generation details, A06 history deferral and A08 compiler scope remain settled. A02 native batching is implemented locally. A05 wire/accounting is delivered and implemented for EVM. A07 deployment/registry is supplied; grant ref and editable label remain absent and capability-gated. +## Remaining dependencies -Harsh’s October 6 reply prefers zero native PC omission defaults, matching the SDK, and invites Zaryab’s input. H3 token wording still needs an example-based clarification; current target retains maxValueTotal. Harsh redirected H4.4 public SVM representation to Zaryab, with [concrete proposals](public-api-proposals.md) ready. H4.5 covers raw-offset representation, and H6 send selection. [Harsh draft](questions-harsh.md); [Zaryab metadata draft](questions-zaryab.md). The fixture request is closed with [our live wire evidence](research/live-svm-wire-2026-10-06/README.md), including later terminal rejection after the initial timeout. +Product choices are settled. Rule ref is removed; zero native PC defaults and the current token model are retained; dual native/EVM raw/index inputs are approved; named IDL Solana authoring is implemented. Contract validation is authoritative; AMBIGUOUS_RULE remains the SDK response to multiple candidates. No selection interface change is required. -No public spent/history/compiler feature is reopened. Rule updates reset counters as agreed. Ordinary inflows do not restore spent; creditRevert remains a platform dependency. +Freshly fetched contracts already validate explicit rulesIds and reject unauthorized actions. They lack setLabel, which remains gated until its ABI/deployment is verified. [Contract delivery items](questions-zaryab.md). `creditRevert` remains a separate Push-core executor dependency; ordinary returned funds do not lower policy spend. diff --git a/plan/agw/product-decisions-2026-10-04.md b/plan/agw/product-decisions-2026-10-04.md index d1c8e125..708667e2 100644 --- a/plan/agw/product-decisions-2026-10-04.md +++ b/plan/agw/product-decisions-2026-10-04.md @@ -57,3 +57,21 @@ Existing implementation at a852777 still contains provisional approval/default r ## Implementation follow-through The subsequent alignment implements the clear decisions: generation-dependent helpers and spend counters are internal, active-only v1 reads use RULE_NOT_FOUND for unknown/revoked IDs, compileCard is removed, approval policy is external, and native agent arrays use sender-preserving atomic UEA/7702 transport. H3 defaults and the raw-offset public-type question remain unchanged/pending. See [validation and limits](research/product-alignment-2026-10-04/README.md). The earlier a852777 statements above record the pre-alignment state. + +## October 7 follow-up — user-relayed team answers + +This update supersedes the earlier pending status for these decisions. It records reported decisions, not completed implementation. + +- Omitted native `maxValuePerCall` and `maxValueTotal` remain `0`: no native PC value allowance. Existing SDK behavior matches. +- Keep the current `assets[]` model and independent token budgets. +- Public Solana authoring will use named inputs from an IDL. The public adapter and its acceptance tests still need implementation; stored reads must preserve exact constraints because the contract does not store the IDL. +- Rule `ref` is removed from scope. Remove its public input/capability stub during SDK alignment. +- `setLabel` will be fixed by Zaryab. Keep it gated until the contract surface and deployment are verified. +- Contract validation is authoritative; SDK error mapping should expose refusals. Freshly fetched `deploy-agw@10a24f1` still requires an explicit `rulesId` in `executeAsAgent` (`src/AGW.sol:823`). It checks the agent, validates that selected rule, then dispatches (`828–834`). It does not choose among rules. The later clarification retains AMBIGUOUS_RULE for multiple candidates. Reverted action/state does not imply a mined transaction costs no gas. +- No new answer was supplied for H4.5 (native/EVM argument-index versus raw-offset public types). + +## October 7 final decisions and implementation + +Shoaib approved dual native/EVM argument-index/raw-offset authoring with exact decoded reads. The assistant initially misinterpreted the contract-validation reply as a request for automatic rule selection; Shoaib corrected that interpretation. H6 retains AMBIGUOUS_RULE for multiple candidates, with existing contract validation and SDK error mapping. No automatic-selection interface/deployment is required. + +SDK alignment now removes public rule `ref` inputs/records/capability, rejects stale ref inputs, preserves checkpoint `ref`, and implements named-IDL Solana authoring through public create/add/update/read/send paths. Supported fixed layouts fail explicitly on unsupported dynamic/optional/nested schemas. The public guide documents scope. `setLabel` remains gated pending contract delivery. Existing rule selection and contract enforcement remain in place. diff --git a/plan/agw/public-api-proposals.md b/plan/agw/public-api-proposals.md index eaeabad5..58728a4f 100644 --- a/plan/agw/public-api-proposals.md +++ b/plan/agw/public-api-proposals.md @@ -1,5 +1,7 @@ # AGW public API proposals for team review +**October 7 disposition:** named-IDL Solana authoring and dual native/EVM raw-offset/index inputs were approved and implemented (supported fixed layouts documented in the consumer guide). H6’s caller-selector proposal is not being implemented. The clarified decision retains AMBIGUOUS_RULE and relies on existing contract enforcement/error mapping; no automatic-selection contract change is requested. The sketches below preserve the proposal history; use current exported types and `packages/core/AGW.md` for implementation. + October 6, 2026. These are proposals for H4.4/H4.5/H6, not implemented public contracts. Native/EVM methods remain as implemented; public Solana capability stays gated. The [source recheck](research/question-source-recheck-2026-10-06/README.md) separates supplied wire definitions from these remaining SDK choices. ## H4.4 Solana rule inputs and decoded records diff --git a/plan/agw/questions-harsh.md b/plan/agw/questions-harsh.md index 3bf39d5c..7b6a1639 100644 --- a/plan/agw/questions-harsh.md +++ b/plan/agw/questions-harsh.md @@ -1,104 +1,25 @@ -# AGW SDK — questions for Harsh +# AGW SDK — product decisions confirmed -Updated October 6, 2026 after Harsh’s reply. Numbers 2–5 below match the chat questions; existing H IDs are retained for tracking. - -**Question 1 — native PC defaults:** Harsh now prefers `0` for omitted `maxValuePerCall` and `maxValueTotal`, with Zaryab invited to comment. The SDK already uses `0`, so no behavior change is needed. These fields limit native PC value attached to agent calls; they do not set the sender’s transaction gas budget. +Updated October 7, 2026 from Shoaib’s relayed team answers and SDK-owned decision approval. There are no remaining product questions in this document. +## 1–2. Defaults and token model -## 2. What should “tokens independent” mean? — H3, Harsh - -**Where this came from:** your comment on the [validation paragraph in 5. SDK: AGW](https://app.notion.com/p/pushprotocol/5-SDK-AGW-3e9188aea7f481cf8e8de324956549b9#af9c3fac35d94f2585cb27310271c1d8), recorded during our October 5 comment review: - -> “we usually want the tokens to be independent and not attached to this” - -**Current model:** the owner grants one rule containing an `assets[]` list and an allowed-call list. Each asset has its own outbound amount limits. For example: - -| Asset | Maximum per outbound | Maximum total under this rule | -| --- | --- | --- | -| USDC | 10 | 100 | -| USDT | 20 | 200 | - -After an outbound spends 10 USDC, the USDC budget has 90 remaining; the USDT budget still has 200. These are illustrative token units; SDK amounts use base-unit integers. - -The allowed calls might be `swap()` and `deposit()`. The rule does not associate one token exclusively with one call: either listed asset may be used with either allowed call, provided the request satisfies the other policy checks. These limits do not automatically constrain every token movement performed inside a destination contract. - -**Decision needed:** did you mean that each token should have its own budget, which this model already supports? Or should token permissions live outside the rule entirely? If you meant something else, one intended developer example would help us distinguish it. We propose retaining the current `assets[]` model until that is clarified. +Omitted native `maxValuePerCall` and `maxValueTotal` are `0`: no native PC value allowance. Retain the current `assets[]` model and independent per-token budgets. The SDK matches these decisions. +## 3. Solana rules -## 3. How should developers describe a Solana rule? — H4.4, Zaryab - -Harsh redirected this question to Zaryab. The contract’s Solana constraint format is available; we need to agree on the developer-facing input the SDK compiles into that format. - -**Example intent:** “Allow the agent to call a vault’s `deposit` instruction, only for Alice’s specified destination account, with an amount no greater than 10.” There are two ways a developer could express this: - -| Option | What the developer supplies | What the SDK does | -| --- | --- | --- | -| Named inputs using an IDL | Program address, IDL (the program’s interface description), instruction name `deposit`, named accounts and constraints on fields such as `amount` | Resolves the discriminator, account positions and data offsets from the supported IDL layout, then builds the contract constraints | -| Explicit raw constraints | Program address, instruction discriminator, account positions/expected addresses, and data byte offsets/comparisons | Validates and encodes the supplied constraints without requiring an IDL | - -In both options, the SDK derives the wallet’s destination CEA and protected token accounts internally. Reading a stored rule returns its exact constraints; the contract does not store the original IDL or field names. - -**Recommendation:** support named IDL inputs for layouts the SDK can verify. Unsupported layouts must fail clearly rather than guess offsets. - -**Decision needed from Zaryab:** should v1 expose IDL-based inputs, raw constraints, or both? If both, raw input should be an explicit advanced form. [Proposed types and boundaries](public-api-proposals.md#h44-solana-rule-inputs-and-decoded-records). +Use named inputs from an IDL. The SDK now exposes `SolanaRule`, compiles supported Anchor layouts, derives wallet accounts, and returns exact decoded constraints. Unsupported layouts fail explicitly. See the [consumer guide](../../packages/core/AGW.md#solana-rules-using-named-idl-inputs). +## 4. Native/EVM argument restrictions -## 4. What should rule inputs and reads expose? — H4.5, Harsh - -**Example:** a developer wants to restrict `transfer(address recipient, uint256 amount)` to Alice. The convenient input is: - -```ts -pins: [{ arg: 0, expected: alice }] -``` - -`arg: 0` means the first function argument. For this function’s ABI layout, the SDK converts it to byte offset `4`, immediately after the four-byte function selector. The second argument, `amount`, starts at offset `36`. - -**The read-back problem:** the contract stores offsets and exact values, without the original ABI. Therefore `rules.get()` returns a pin shaped like: - -```ts -pins: [{ offset: 4, expected: aliceAs32ByteWord }] -``` - -Here `aliceAs32ByteWord` is Alice’s address padded to a 32-byte ABI word. An offset is not an argument number; arbitrary ABI layouts cannot be reconstructed just by dividing the offset by 32. - -**Decision needed:** which public model do you want? - -| Option | Creating a rule | Reusing a rule returned by `rules.get()` | -| --- | --- | --- | -| Both input forms — recommended | Accept either `arg` or an explicit `offset`; reject conflicting forms | Exact decoded offsets can be reused in `rules.add/update` | -| Separate input and read types | New authoring accepts ABI argument indexes only | Return a distinct decoded type; require a defined conversion using a verified ABI before reuse | - -The first option is already implemented and tested, but extends the spec’s public input shape and needs approval. In either option, reads preserve exact stored offsets. The same issue applies to native amount limits and EVM beneficiary constraints. [Detailed options](public-api-proposals.md#h45-nativeevm-raw-authoring-and-decoding). +Keep both ABI argument-index and raw-offset inputs, with exact offsets on reads. Shoaib approved this SDK-owned choice. Inputs that specify both forms are rejected; normal examples should prefer argument indexes. +## 5. Contract validation and SDK errors — clarified -## 5. Who chooses the rule for an agent transaction? — H6, Harsh - -**Example:** the same agent has two enabled rules on the same wallet and chain: - -| Rule | Permission | -| --- | --- | -| A | Call app A within its configured limits | -| B | Call app B within its configured limits | - -The agent now wants to call app A. Currently the SDK sees two candidate rules and returns `AMBIGUOUS_RULE` before signing. It does not simulate every rule to choose one, even when only one would permit the requested call. - -**Proposal:** let the caller identify the intended rule. The following is proposed syntax, not currently supported: - -```ts -await agent.universal.sendTransaction( - { to: appA, data }, - { agentic: { rulesId: ruleA } } -); -``` - -The SDK checks that the selected rule belongs to this wallet, agent and destination chain and is enabled. The contract still enforces its permissions, expiry and budgets. - -For a native batch `[callAppA, callAppB]`, propose ordered IDs `[ruleA, ruleB]`, one per action, with atomic execution. An EVM destination call array uses one rule for the whole outbound; permissions from different rules are not combined. If there is only one candidate, existing sends continue to work without an explicit ID. - -**Decision needed:** approve explicit rule selection, or specify an automatic selection policy. For example, if two rules both permit the same call but have different remaining budgets, which should the SDK consume? We recommend explicit selection so the caller controls this choice. [Detailed proposal](public-api-proposals.md#h6-rule-selection-for-sends). +The intended behavior is that the existing contract rejects unauthorized functions/actions under the supplied rule, and the SDK maps those errors. This does not request automatic rule selection or a new contract interface. The SDK retains `AMBIGUOUS_RULE` when multiple enabled rules match the agent and chain, without submitting a transaction. No caller-facing rule selector is being added. -[SDK spec](https://app.notion.com/p/pushprotocol/5-SDK-AGW-3e9188aea7f481cf8e8de324956549b9) · [Questions for Zaryab](questions-zaryab.md) +Rule `ref` is removed from scope; editable labels remain pending contract delivery. [Zaryab delivery items](questions-zaryab.md). diff --git a/plan/agw/questions-zaryab.md b/plan/agw/questions-zaryab.md index 0c4c6a7c..dd4bef74 100644 --- a/plan/agw/questions-zaryab.md +++ b/plan/agw/questions-zaryab.md @@ -1,42 +1,16 @@ -# AGW SDK — questions for Zaryab +# AGW SDK — remaining contract delivery items -Updated October 6, 2026. Please confirm the release scope below and answer the Solana API question Harsh redirected to you on October 6. +Updated October 7, 2026. Product direction is settled; the SDK needs the label interface to finish integration. Freshly fetched `deploy-agw@10a24f1` and `pushAgenticWallet_v3@e8db748` still lack an editable-label interface. +## Editable wallet labels -## Z1.3. Rule references and editable labels - -**For each item, is it included in v1 or deferred?** - -| Item | SDK target | Current contracts | -| --- | --- | --- | -| Rule `ref` | Optional job/card reference on a grant | `grantRules(Session)` and `RulesGranted` have no job reference | -| Editable label | Owner calls `w.setLabel(label)` | Label is emitted at deployment; `setLabel` is absent | - -If included, please confirm the existing [page-1 proposal](https://app.notion.com/p/pushprotocol/1-AGW-Contract-Changes-nomenclature-standard-change-set-3e9188aea7f4813aa31fc95ceb4e684d) remains the target and share the updated ABI when ready. Signed grants must bind the rule `ref`. - -If deferred, please agree the v1 scope with Harsh so we can align the public SDK. +`setLabel` will be fixed by Zaryab. Please share the implemented function/event ABI and compatible deployment so the SDK can enable owner-only label updates and verify subsequent reads. The current contracts expose only a deployment label. +## Settled scope -## 3. How should developers describe a Solana rule? — H4.4, Zaryab - -Harsh redirected this question to Zaryab. The contract’s Solana constraint format is available; we need to agree on the developer-facing input the SDK compiles into that format. - -**Example intent:** “Allow the agent to call a vault’s `deposit` instruction, only for Alice’s specified destination account, with an amount no greater than 10.” There are two ways a developer could express this: - -| Option | What the developer supplies | What the SDK does | -| --- | --- | --- | -| Named inputs using an IDL | Program address, IDL (the program’s interface description), instruction name `deposit`, named accounts and constraints on fields such as `amount` | Resolves the discriminator, account positions and data offsets from the supported IDL layout, then builds the contract constraints | -| Explicit raw constraints | Program address, instruction discriminator, account positions/expected addresses, and data byte offsets/comparisons | Validates and encodes the supplied constraints without requiring an IDL | - -In both options, the SDK derives the wallet’s destination CEA and protected token accounts internally. Reading a stored rule returns its exact constraints; the contract does not store the original IDL or field names. - -**Recommendation:** support named IDL inputs for layouts the SDK can verify. Unsupported layouts must fail clearly rather than guess offsets. - -**Decision needed from Zaryab:** should v1 expose IDL-based inputs, raw constraints, or both? If both, raw input should be an explicit advanced form. [Proposed types and boundaries](public-api-proposals.md#h44-solana-rule-inputs-and-decoded-records). - -Harsh also now prefers `0` for omitted native `maxValuePerCall` and `maxValueTotal` and invited your input. The SDK already uses those defaults; flag any contract-side concern. +Named IDL inputs are approved for public Solana authoring. Rule `ref` is removed. Zero native PC defaults and the existing token model are retained. Native/EVM inputs accept argument indexes or raw offsets, and reads preserve exact offsets. Existing contract validation rejects unauthorized actions and the SDK maps errors. AMBIGUOUS_RULE remains for multiple candidates; no automatic-selection contract change is requested. -[Current contract guide](https://github.com/pushchain/push-agentic-wallets/blob/10a24f101e2e6e0a9b76517b29f5cdb1aa967796/docs/5_SDK_Owner_Integration.md) · [SDK spec](https://app.notion.com/p/pushprotocol/5-SDK-AGW-3e9188aea7f481cf8e8de324956549b9) +[Inspected contract source](https://github.com/pushchain/push-agentic-wallets/blob/10a24f101e2e6e0a9b76517b29f5cdb1aa967796/src/AGW.sol#L823) · [Consumer SDK guide](../../packages/core/AGW.md). diff --git a/plan/agw/research/decision-alignment-2026-10-07/README.md b/plan/agw/research/decision-alignment-2026-10-07/README.md new file mode 100644 index 00000000..291aa257 --- /dev/null +++ b/plan/agw/research/decision-alignment-2026-10-07/README.md @@ -0,0 +1,43 @@ +# October 7 decisions — SDK alignment and acceptance + +The approved decisions are implemented: native PC omission stays zero; token budgets stay independent; rule `ref` is removed; native/EVM argument indexes and raw offsets are both accepted; public Solana authoring uses named Anchor IDL inputs. + +## Public changes + +- New exported types: `SolanaRule`, `DecodedSolanaRule`, `SvmInstructionRule`, `SvmAccountRef`, `SvmFieldConstraint`. +- Existing create/add/update/get/list/revoke methods now support Solana rules. Reads preserve stored constraints and cannot recover the original IDL. +- The ordinary agentic `sendTransaction` path supports one Solana instruction, including owner sends, wallet-specific account derivation, gateway allowance/balance checks, errors, progress events and replay. Response metadata adds `destinationInstruction`. +- `NativeRule`/`UniversalRule`/`RulesRecord` no longer expose rule `ref`; old runtime inputs containing it are rejected. Checkpoint `ref` remains an existing, separate event field. +- EVM `UniversalRule.chainNamespace` is now EVM-specific; use `SolanaRule` for Solana. Both native argument/offset forms remain supported, with conflicting inputs rejected. +- The consumer guide documents fixed primitive/fixed-array Anchor layouts, eight-byte discriminators, top-level non-optional accounts, supported comparisons, and unsupported-layout failures. Public Solana execution currently uses configured devnet; no public raw-wire rule-authoring API was added. + +## Contract delivery still pending + +Fresh fetch: `deploy-agw@10a24f1`, `pushAgenticWallet_v3@e8db748`. These expose `executeAsAgent(rulesId,...)`, which already enforces permissions, and no `setLabel`. Only editable labels await AGW contract delivery. The SDK retains AMBIGUOUS_RULE when multiple candidates match and maps contract rejections; no automatic-selection interface or caller-facing selector is required. The previously recorded automatic-selection dependency was an assistant misinterpretation, corrected by Shoaib. + +## Validation + +| Check | Result | +| --- | --- | +| Full core unit suite | 1,999 passed, 0 failed; 12 existing skips | +| Actual v4 contract harness | 81 passed, 0 failed across 11 suites | +| New native funded cases | 3/3 pass; zero-default case additionally rerun with exact `ValueExceedsCap` assertion | +| Public Solana funded cases | 4/4 pass after the gas-estimation fix | +| Build | Pass | +| Typechecks | lib/spec/local-contract/AGW-E2E pass | +| Package/API/docs | Compiled exports match source; packed CJS/ESM imports and guide examples pass | +| E2E manifest | AGW: 46 scenarios/12 files/46 tests; default all remains 76/40/81 | + +The 46 AGW cases have selected-run live coverage (39 historical cases plus these seven additions), not one new combined 46-case execution. The local harness uses actual AGW/factory/engine/validator/URP contracts and fixture gateway/core/token components; public live delivery independently checks the real Solana receipt and CEA-to-recipient transfer. [Live evidence](live-evidence.json), [sanitized logs](logs/). + +New native cases cover omitted PC limits with a valid token transfer, raw-offset read/re-grant equality, and removed/conflicting inputs rejected before signing. Public Solana cases cover named-IDL grant/read/atomic replacement, actual destination transfer plus wait/replay, substituted account/oversized instruction refusals, and revoke followed by send refusal. A destination failure was previously tested through the internal wire backend; the new public suite does not claim a separate failing-program run. + +## Live issue found and fixed + +The initial public Solana create+grant reverted under the existing EIP-7702 fallback budget of 1,100,000 gas. Read-only replay at the preceding block failed at that limit and passed at 2,200,000. The fallback guessed 500k per call when state-override estimation failed, which was insufficient for this grant. + +`sendBatch7702` now estimates the actual signed authorization transaction first. If that RPC form is unsupported, it estimates ordinary execution only when the sender already delegates to the exact executor, otherwise attempts the delegation state override. If all valid estimation paths fail, it refuses to broadcast instead of inventing a gas ceiling. Estimates receive execution headroom plus authorization overhead. The live retry succeeded with gas limit 1,732,532 and gas used 1,171,408. [Receipts](batch-gas.json). + +Tests cover authorization-estimate fallback, fresh-account override, and refusal when estimation fails. The local batch rollback test explicitly overrides only its gas estimate to force a mined revert; a separate test verifies the normal pre-broadcast refusal path. Contract validation remains authoritative. + +No contract deployment, mainnet transaction or team message was sent. The funded runs used bounded, previously authorized testnet fixtures; environment secrets are absent from the saved evidence. diff --git a/plan/agw/research/decision-alignment-2026-10-07/batch-gas.json b/plan/agw/research/decision-alignment-2026-10-07/batch-gas.json new file mode 100644 index 00000000..88ffb3ec --- /dev/null +++ b/plan/agw/research/decision-alignment-2026-10-07/batch-gas.json @@ -0,0 +1,18 @@ +[ + { + "hash": "0x3b434310de5fd2542a0a062c3cd2734abcc07ce921b0f497bb32cc1284853d76", + "block": "23988191", + "gas": "1100000", + "gasUsed": "1047582", + "status": "reverted", + "type": "eip7702" + }, + { + "hash": "0x168f42b92fd9f5396cc68d9e6cf0b41cfbb869d6dd8892e0029f6e728acf9368", + "block": "23988300", + "gas": "1732532", + "gasUsed": "1171408", + "status": "success", + "type": "eip7702" + } +] diff --git a/plan/agw/research/decision-alignment-2026-10-07/live-evidence.json b/plan/agw/research/decision-alignment-2026-10-07/live-evidence.json new file mode 100644 index 00000000..7e899542 --- /dev/null +++ b/plan/agw/research/decision-alignment-2026-10-07/live-evidence.json @@ -0,0 +1,86 @@ +[ + { + "name": "zero-pc-defaults", + "at": "2026-10-07T09:36:31.118Z", + "network": "TESTNET_DONUT", + "sourceCommit": "e8db74815cfbbf5389593805e464fe8d85f7f735", + "wallet": "0x1213f3b8785598621E49FdEd94D1E8973A478041", + "txHash": "0x5486e5723e14c396751931a4ecd3271bb0a907667f0e9d873dbd5837ddf5d067" + }, + { + "name": "raw-offset-reuse", + "at": "2026-10-07T09:36:55.598Z", + "network": "TESTNET_DONUT", + "sourceCommit": "e8db74815cfbbf5389593805e464fe8d85f7f735", + "wallet": "0x39E46010A46A24F48Df05337276242Bc8d4DB864", + "txHash": "0xccbb3e31d51b8c1e976c5818ee850d31287ad43170518838fff73861dc2a0c59" + }, + { + "name": "public-svm-setup", + "at": "2026-10-07T09:42:42.568Z", + "network": "TESTNET_DONUT", + "sourceCommit": "e8db74815cfbbf5389593805e464fe8d85f7f735", + "wallet": "0x93dd8A0224e0acD40793a7796cB4dC98fE623657", + "id": "0x1e2dceea3b903fd4b12ce69ed511ae46a4a28d7c5ddf88374466c6610c006465", + "grantHash": "0x168f42b92fd9f5396cc68d9e6cf0b41cfbb869d6dd8892e0029f6e728acf9368", + "cea": "CHtieGAwhxzLX9p5vikpEzdCvTfYdwMgKRaL8BxsbNaM", + "recipient": "3nK8X1re4zLNrgz9Y3xKS4g2fKPJ6M3N9BhNuFfkjwAb" + }, + { + "name": "public-svm-replacement", + "at": "2026-10-07T09:44:25.367Z", + "network": "TESTNET_DONUT", + "sourceCommit": "e8db74815cfbbf5389593805e464fe8d85f7f735", + "wallet": "0x93dd8A0224e0acD40793a7796cB4dC98fE623657", + "id": "0x5409d54790e0682c1ad30c7fc2c72c64689d9ba45e77b091d5f3cb11278ae2c0", + "txHash": "0x9387695709ff660f718ef2381825be25f310cebedc1099cdffa058169930d4a8" + }, + { + "name": "public-svm-submitted", + "at": "2026-10-07T09:44:39.162Z", + "network": "TESTNET_DONUT", + "sourceCommit": "e8db74815cfbbf5389593805e464fe8d85f7f735", + "wallet": "0x93dd8A0224e0acD40793a7796cB4dC98fE623657", + "id": "0x5409d54790e0682c1ad30c7fc2c72c64689d9ba45e77b091d5f3cb11278ae2c0", + "hash": "0x1bff1696e1808d4aba472f622be4b6d98120b4ea559c89063c09bf3a320036ca" + }, + { + "name": "public-svm-delivered", + "at": "2026-10-07T09:46:05.379Z", + "network": "TESTNET_DONUT", + "sourceCommit": "e8db74815cfbbf5389593805e464fe8d85f7f735", + "wallet": "0x93dd8A0224e0acD40793a7796cB4dC98fE623657", + "hash": "0x1bff1696e1808d4aba472f622be4b6d98120b4ea559c89063c09bf3a320036ca", + "destinationHash": "43bAGg9ZRnPyQfbiLv7UFdXmW27AZuUMYzm1x4idHeUVKAMTVdydLK1FqEb2AoN7PqgZXMDD5xqzEMdfbxCagrQc", + "instruction": { + "program": "0x7673075a980bfd5d6b1dffe99c31f63e8938519cc1c2af009dda5e568a94460d", + "data": "0x79f4fa0308e5e1011027000000000000", + "accounts": [ + { + "pubkey": "0x4f12fe6816ae7e33ebf7db0b154ec3b09e3bf1a7690481e8e9477d5a278ad3af", + "isWritable": true + }, + { + "pubkey": "0x2953026d328218b107268efe60f7d98635af1ff535a91731f75ca7cf8a859044", + "isWritable": true + }, + { + "pubkey": "0xa7c453ab5fcff6b1738264ac9bf5d4a89036e75e8873e614589c35cc75431c52", + "isWritable": true + }, + { + "pubkey": "0x0000000000000000000000000000000000000000000000000000000000000000", + "isWritable": false + } + ] + } + }, + { + "name": "zero-pc-defaults", + "at": "2026-10-07T09:50:52.432Z", + "network": "TESTNET_DONUT", + "sourceCommit": "e8db74815cfbbf5389593805e464fe8d85f7f735", + "wallet": "0xC245d7509116841788d66840De87b4C377308B16", + "txHash": "0xdc5ef369d0ef06bbb21ae4d7c286c25910a5aa8c2df055c70486466729f69c4e" + } +] diff --git a/plan/agw/research/decision-alignment-2026-10-07/logs/build.log b/plan/agw/research/decision-alignment-2026-10-07/logs/build.log new file mode 100644 index 00000000..96dfaa76 --- /dev/null +++ b/plan/agw/research/decision-alignment-2026-10-07/logs/build.log @@ -0,0 +1,11 @@ + +> nx run core:build + +Compiling TypeScript files for project "core"... +Done compiling TypeScript files for project "core". +(node:13252) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. +(Use `node --trace-warnings ...` to show where the warning was created) + + + + NX Successfully ran target build for project core diff --git a/plan/agw/research/decision-alignment-2026-10-07/logs/local-contracts.log b/plan/agw/research/decision-alignment-2026-10-07/logs/local-contracts.log new file mode 100644 index 00000000..57db0d34 --- /dev/null +++ b/plan/agw/research/decision-alignment-2026-10-07/logs/local-contracts.log @@ -0,0 +1,29 @@ +PASS core-agw-local packages/core/__agw-local__/svm-backend.spec.ts (11.868 s) +PASS core-agw-local packages/core/__agw-local__/agw-local-advanced.spec.ts (5.429 s) +PASS core-agw-local packages/core/__agw-local__/v4-multiasset.spec.ts +PASS core-agw-local packages/core/__agw-local__/svm-differential.spec.ts + ● Console + + console.log + {"corpus":"svm-grant","seed":23063,"cases":107,"accepted":38,"rejected":69,"mismatches":[]} + + at Object. (__agw-local__/svm-differential.spec.ts:226:13) + + console.log + {"corpus":"svm-payload","seed":23063,"cases":88,"accepted":6,"rejected":82,"mismatches":[]} + + at Object. (__agw-local__/svm-differential.spec.ts:407:13) + +PASS core-agw-local packages/core/__agw-local__/agw-local-batch.spec.ts +PASS core-agw-local packages/core/__agw-local__/svm-public.spec.ts +PASS core-agw-local packages/core/__agw-local__/agw-local-races.spec.ts +PASS core-agw-local packages/core/__agw-local__/svm-internals.spec.ts +PASS core-agw-local packages/core/__agw-local__/delayed-index.spec.ts +PASS core-agw-local packages/core/__agw-local__/agw-local.spec.ts +PASS core-agw-local packages/core/__agw-local__/vectors.spec.ts + +Test Suites: 11 passed, 11 total +Tests: 81 passed, 81 total +Snapshots: 0 total +Time: 33.814 s, estimated 63 s +Ran all test suites. diff --git a/plan/agw/research/decision-alignment-2026-10-07/logs/native-default-refusal-live.log b/plan/agw/research/decision-alignment-2026-10-07/logs/native-default-refusal-live.log new file mode 100644 index 00000000..bd0c08d5 --- /dev/null +++ b/plan/agw/research/decision-alignment-2026-10-07/logs/native-default-refusal-live.log @@ -0,0 +1,20 @@ +PASS core-e2e __e2e__/agw/native-policy-extended.spec.ts (78.747 s) + agw extended native policy + ✓ 9. omitted PC limits forbid value while still allowing a token transfer (57656 ms) + ○ skipped 1. pinned recipient and metered amount decode losslessly and transfer through explicit Push chain + ○ skipped 2. wrong recipient pin is refused with unchanged token balance and counters + ○ skipped 3. per-call amount cap refuses cap plus one + ○ skipped 4. cumulative amount accepts the exact total and refuses the next unit + ○ skipped 5. call count accepts the exact count and refuses a zero-amount extra call + ○ skipped 6. explicit zero total forbids positive amount but permits a metered zero call + ○ skipped 7. failed token callee leaves all policy counters unchanged + ○ skipped 8. an ungranted selector is refused without changing balances or allowance + ○ skipped 10. decoded raw-offset rules can be granted again without fabricated ref metadata + ○ skipped 11. removed ref and conflicting argument-offset inputs fail before signing + +Test Suites: 1 passed, 1 total +Tests: 10 skipped, 1 passed, 11 total +Snapshots: 0 total +Time: 78.782 s, estimated 96 s +Ran all test suites within paths "__e2e__/agw/native-policy-extended.spec.ts". +Force exiting Jest: Have you considered using `--detectOpenHandles` to detect async operations that kept running after all tests finished? diff --git a/plan/agw/research/decision-alignment-2026-10-07/logs/native-live.log b/plan/agw/research/decision-alignment-2026-10-07/logs/native-live.log new file mode 100644 index 00000000..b91f38b2 --- /dev/null +++ b/plan/agw/research/decision-alignment-2026-10-07/logs/native-live.log @@ -0,0 +1,20 @@ +PASS core-e2e __e2e__/agw/native-policy-extended.spec.ts (95.792 s) + agw extended native policy + ✓ 9. omitted PC limits forbid value while still allowing a token transfer (50635 ms) + ✓ 10. decoded raw-offset rules can be granted again without fabricated ref metadata (24480 ms) + ✓ 11. removed ref and conflicting argument-offset inputs fail before signing (4191 ms) + ○ skipped 1. pinned recipient and metered amount decode losslessly and transfer through explicit Push chain + ○ skipped 2. wrong recipient pin is refused with unchanged token balance and counters + ○ skipped 3. per-call amount cap refuses cap plus one + ○ skipped 4. cumulative amount accepts the exact total and refuses the next unit + ○ skipped 5. call count accepts the exact count and refuses a zero-amount extra call + ○ skipped 6. explicit zero total forbids positive amount but permits a metered zero call + ○ skipped 7. failed token callee leaves all policy counters unchanged + ○ skipped 8. an ungranted selector is refused without changing balances or allowance + +Test Suites: 1 passed, 1 total +Tests: 8 skipped, 3 passed, 11 total +Snapshots: 0 total +Time: 95.811 s +Ran all test suites within paths "__e2e__/agw/native-policy-extended.spec.ts". +Force exiting Jest: Have you considered using `--detectOpenHandles` to detect async operations that kept running after all tests finished? diff --git a/plan/agw/research/decision-alignment-2026-10-07/logs/svm-public-initial-gas-failure.log b/plan/agw/research/decision-alignment-2026-10-07/logs/svm-public-initial-gas-failure.log new file mode 100644 index 00000000..bfba7056 --- /dev/null +++ b/plan/agw/research/decision-alignment-2026-10-07/logs/svm-public-initial-gas-failure.log @@ -0,0 +1,153 @@ +FAIL core-e2e __e2e__/agw/svm-public.spec.ts (34.947 s) + agw public svm + ✕ 1. named IDL grant reads exact constraints and replaces atomically (1 ms) + ✕ 2. public send confirms actual CEA transfer and preserves replay identity + ✕ 3. substituted named accounts and excessive instruction amounts fail before signing + ✕ 4. public revoke removes the Solana rule and subsequent sends are refused + + ● agw public svm › 1. named IDL grant reads exact constraints and replaces atomically + + AgenticRevertError: sendPushTx — Push Chain transaction 0x3b434310de5fd2542a0a062c3cd2734abcc07ce921b0f497bb32cc1284853d76 reverted + + 135 | if (decoded || err instanceof PushChainExecutionError) { + 136 | const e = err as { message?: string; gatewayTxHash?: string; decodedError?: DecodedErrorPayload }; + > 137 | return new AgenticRevertError(e?.message ?? decoded?.name ?? 'AGW revert', { + | ^ + 138 | decodedError: decoded ?? e?.decodedError, + 139 | gatewayTxHash: e?.gatewayTxHash, + 140 | agenticCode: decoded?.name, + + at wrapSendError (src/lib/agentic/management/common.ts:137:12) + at createFailure (src/lib/agentic/management/create.ts:250:32) + at createWallet (src/lib/agentic/management/create.ts:140:27) + at async Object. (__e2e__/agw/svm-public.spec.ts:140:18) + + Cause: + PushChainExecutionError: sendPushTx — Push Chain transaction 0x3b434310de5fd2542a0a062c3cd2734abcc07ce921b0f497bb32cc1284853d76 reverted + + 76 | receiptWaited = true; + 77 | if (receipt.status === 'reverted') { + > 78 | throw new PushChainExecutionError( + | ^ + 79 | `${label} — Push Chain transaction ${txHash} reverted` + 80 | ); + 81 | } + + at getIndexedPushTransaction (src/lib/orchestrator/internals/push-chain-tx.ts:78:17) + at async sendPushTx (src/lib/orchestrator/internals/push-chain-tx.ts:162:28) + at async executeStandardPayload (src/lib/orchestrator/internals/execute-standard.ts:173:12) + at async Orchestrator.executeWithPolicy (src/lib/orchestrator/orchestrator.ts:471:11) + at async createWallet (src/lib/agentic/management/create.ts:138:10) + at async Object. (__e2e__/agw/svm-public.spec.ts:140:18) + + ● agw public svm › 2. public send confirms actual CEA transfer and preserves replay identity + + AgenticRevertError: sendPushTx — Push Chain transaction 0x3b434310de5fd2542a0a062c3cd2734abcc07ce921b0f497bb32cc1284853d76 reverted + + 135 | if (decoded || err instanceof PushChainExecutionError) { + 136 | const e = err as { message?: string; gatewayTxHash?: string; decodedError?: DecodedErrorPayload }; + > 137 | return new AgenticRevertError(e?.message ?? decoded?.name ?? 'AGW revert', { + | ^ + 138 | decodedError: decoded ?? e?.decodedError, + 139 | gatewayTxHash: e?.gatewayTxHash, + 140 | agenticCode: decoded?.name, + + at wrapSendError (src/lib/agentic/management/common.ts:137:12) + at createFailure (src/lib/agentic/management/create.ts:250:32) + at createWallet (src/lib/agentic/management/create.ts:140:27) + at async Object. (__e2e__/agw/svm-public.spec.ts:140:18) + + Cause: + PushChainExecutionError: sendPushTx — Push Chain transaction 0x3b434310de5fd2542a0a062c3cd2734abcc07ce921b0f497bb32cc1284853d76 reverted + + 76 | receiptWaited = true; + 77 | if (receipt.status === 'reverted') { + > 78 | throw new PushChainExecutionError( + | ^ + 79 | `${label} — Push Chain transaction ${txHash} reverted` + 80 | ); + 81 | } + + at getIndexedPushTransaction (src/lib/orchestrator/internals/push-chain-tx.ts:78:17) + at async sendPushTx (src/lib/orchestrator/internals/push-chain-tx.ts:162:28) + at async executeStandardPayload (src/lib/orchestrator/internals/execute-standard.ts:173:12) + at async Orchestrator.executeWithPolicy (src/lib/orchestrator/orchestrator.ts:471:11) + at async createWallet (src/lib/agentic/management/create.ts:138:10) + at async Object. (__e2e__/agw/svm-public.spec.ts:140:18) + + ● agw public svm › 3. substituted named accounts and excessive instruction amounts fail before signing + + AgenticRevertError: sendPushTx — Push Chain transaction 0x3b434310de5fd2542a0a062c3cd2734abcc07ce921b0f497bb32cc1284853d76 reverted + + 135 | if (decoded || err instanceof PushChainExecutionError) { + 136 | const e = err as { message?: string; gatewayTxHash?: string; decodedError?: DecodedErrorPayload }; + > 137 | return new AgenticRevertError(e?.message ?? decoded?.name ?? 'AGW revert', { + | ^ + 138 | decodedError: decoded ?? e?.decodedError, + 139 | gatewayTxHash: e?.gatewayTxHash, + 140 | agenticCode: decoded?.name, + + at wrapSendError (src/lib/agentic/management/common.ts:137:12) + at createFailure (src/lib/agentic/management/create.ts:250:32) + at createWallet (src/lib/agentic/management/create.ts:140:27) + at async Object. (__e2e__/agw/svm-public.spec.ts:140:18) + + Cause: + PushChainExecutionError: sendPushTx — Push Chain transaction 0x3b434310de5fd2542a0a062c3cd2734abcc07ce921b0f497bb32cc1284853d76 reverted + + 76 | receiptWaited = true; + 77 | if (receipt.status === 'reverted') { + > 78 | throw new PushChainExecutionError( + | ^ + 79 | `${label} — Push Chain transaction ${txHash} reverted` + 80 | ); + 81 | } + + at getIndexedPushTransaction (src/lib/orchestrator/internals/push-chain-tx.ts:78:17) + at async sendPushTx (src/lib/orchestrator/internals/push-chain-tx.ts:162:28) + at async executeStandardPayload (src/lib/orchestrator/internals/execute-standard.ts:173:12) + at async Orchestrator.executeWithPolicy (src/lib/orchestrator/orchestrator.ts:471:11) + at async createWallet (src/lib/agentic/management/create.ts:138:10) + at async Object. (__e2e__/agw/svm-public.spec.ts:140:18) + + ● agw public svm › 4. public revoke removes the Solana rule and subsequent sends are refused + + AgenticRevertError: sendPushTx — Push Chain transaction 0x3b434310de5fd2542a0a062c3cd2734abcc07ce921b0f497bb32cc1284853d76 reverted + + 135 | if (decoded || err instanceof PushChainExecutionError) { + 136 | const e = err as { message?: string; gatewayTxHash?: string; decodedError?: DecodedErrorPayload }; + > 137 | return new AgenticRevertError(e?.message ?? decoded?.name ?? 'AGW revert', { + | ^ + 138 | decodedError: decoded ?? e?.decodedError, + 139 | gatewayTxHash: e?.gatewayTxHash, + 140 | agenticCode: decoded?.name, + + at wrapSendError (src/lib/agentic/management/common.ts:137:12) + at createFailure (src/lib/agentic/management/create.ts:250:32) + at createWallet (src/lib/agentic/management/create.ts:140:27) + at async Object. (__e2e__/agw/svm-public.spec.ts:140:18) + + Cause: + PushChainExecutionError: sendPushTx — Push Chain transaction 0x3b434310de5fd2542a0a062c3cd2734abcc07ce921b0f497bb32cc1284853d76 reverted + + 76 | receiptWaited = true; + 77 | if (receipt.status === 'reverted') { + > 78 | throw new PushChainExecutionError( + | ^ + 79 | `${label} — Push Chain transaction ${txHash} reverted` + 80 | ); + 81 | } + + at getIndexedPushTransaction (src/lib/orchestrator/internals/push-chain-tx.ts:78:17) + at async sendPushTx (src/lib/orchestrator/internals/push-chain-tx.ts:162:28) + at async executeStandardPayload (src/lib/orchestrator/internals/execute-standard.ts:173:12) + at async Orchestrator.executeWithPolicy (src/lib/orchestrator/orchestrator.ts:471:11) + at async createWallet (src/lib/agentic/management/create.ts:138:10) + at async Object. (__e2e__/agw/svm-public.spec.ts:140:18) + +Test Suites: 1 failed, 1 total +Tests: 4 failed, 4 total +Snapshots: 0 total +Time: 34.965 s +Ran all test suites within paths "__e2e__/agw/svm-public.spec.ts". +Force exiting Jest: Have you considered using `--detectOpenHandles` to detect async operations that kept running after all tests finished? diff --git a/plan/agw/research/decision-alignment-2026-10-07/logs/svm-public-live.log b/plan/agw/research/decision-alignment-2026-10-07/logs/svm-public-live.log new file mode 100644 index 00000000..658b03f7 --- /dev/null +++ b/plan/agw/research/decision-alignment-2026-10-07/logs/svm-public-live.log @@ -0,0 +1,13 @@ +PASS core-e2e __e2e__/agw/svm-public.spec.ts (283.2 s) + agw public svm + ✓ 1. named IDL grant reads exact constraints and replaces atomically (102799 ms) + ✓ 2. public send confirms actual CEA transfer and preserves replay identity (100011 ms) + ✓ 3. substituted named accounts and excessive instruction amounts fail before signing (15315 ms) + ✓ 4. public revoke removes the Solana rule and subsequent sends are refused (9725 ms) + +Test Suites: 1 passed, 1 total +Tests: 4 passed, 4 total +Snapshots: 0 total +Time: 283.218 s +Ran all test suites within paths "__e2e__/agw/svm-public.spec.ts". +Force exiting Jest: Have you considered using `--detectOpenHandles` to detect async operations that kept running after all tests finished? diff --git a/plan/agw/research/decision-alignment-2026-10-07/logs/units.log b/plan/agw/research/decision-alignment-2026-10-07/logs/units.log new file mode 100644 index 00000000..c05da5e3 --- /dev/null +++ b/plan/agw/research/decision-alignment-2026-10-07/logs/units.log @@ -0,0 +1,171 @@ +PASS core packages/core/src/lib/universal/account/account.spec.ts (6.113 s) + ● Console + + console.warn + [PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead. + + 207 | ): Promise { + 208 | if (!_convertOriginToExecutorWarned) { + > 209 | console.warn( + | ^ + 210 | '[PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead.' + 211 | ); + 212 | _convertOriginToExecutorWarned = true; + + at Object.convertOriginToExecutor (src/lib/universal/account/account.ts:209:13) + at Object. (src/lib/universal/account/account.spec.ts:80:52) + + console.warn + [PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead. + + 425 | ): Promise { + 426 | if (!options?._internal && !_convertExecutorToOriginWarned) { + > 427 | console.warn( + | ^ + 428 | '[PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead.' + 429 | ); + 430 | _convertExecutorToOriginWarned = true; + + at convertExecutorToOrigin (src/lib/universal/account/account.ts:427:13) + at Object. (src/lib/universal/account/account.spec.ts:106:38) + +PASS core packages/core/src/lib/vm-client/evm-client.batch-gas.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/block-results-client.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-tx-retry.spec.ts +PASS core packages/core/src/lib/push-client/push-client.archive-fallback.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-confirmation-gate.spec.ts +PASS core packages/core/src/lib/utils.spec.ts + ● Console + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:973:17) + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:977:17) + + console.log + 1.23 + + at Object. (src/lib/utils.spec.ts:982:17) + +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-evm-r3-native-eoa.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/send.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/scenarios.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-detector.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/payload-builders.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-composition.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-executor.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-timeout-clamp.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-native-multicall.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r2-outbound-revert-flow.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/signing-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-svm-r3.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/context-helpers-tracker.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-types.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/rescue-svm-confirmation.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gateway-uea-account.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-builder-progress-hook.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-multichain.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-svm-rent.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/public-surface.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/response-builder-push-revert.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/send-transaction-progress-hook.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/web2-compat.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/gate.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-request-recipient.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/inbound-tracker-derivation.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/account-status.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/inbound-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/funds-only-burn-guard.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/codec.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-svm-confirmation.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/terminal-suppression.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/source-hash-resolution.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r1-spec-strings.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/ucallback-codec.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-error-classification.spec.ts +PASS core packages/core/src/lib/universal/signer/signer.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/response-invariant.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-tracker.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-wire-fixture.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/ix-encoder.spec.ts +PASS core packages/core/src/lib/constants/__tests__/svm-gateway-idl.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/build-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/registry.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/reads-context.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/resolve.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/management.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/response-surface.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/read-tx-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/normalize-address.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/max-pc-for-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/tracking.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/cascade.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r3-spec-strings.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/error-decoder.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-execute-order.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-event-hook-bridge.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/registry.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/resolver.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/svm-rent.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-backend.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/export.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm-rent-pc20.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/formatters.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-usd-sizer.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/track-transaction-guard.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/chain-namespace.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/multichain-hooks.spec.ts +PASS core packages/core/src/lib/push-client/push-client.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/execute-standard-required-funds.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-calculator.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r2-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-error-classification.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-idl.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-emission.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/svm-account.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/spec-builder.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-params.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/revalidate-read.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/result-decoder.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-evm.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/__tests__/signing.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-svm.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm-log-index.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/address-codec.spec.ts +PASS core packages/core/src/lib/constants/__tests__/token-constants.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/child-inbounds.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/normalize.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/abi-selectors.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/auto-detect.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.chain-symbol.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg-svm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/validate.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-events.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-web2.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.dynamic-gas.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/budget.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/classify.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/errors.spec.ts + +Test Suites: 1 skipped, 118 passed, 118 of 119 total +Tests: 12 skipped, 1999 passed, 2011 total +Snapshots: 0 total +Time: 63.777 s +Ran all test suites. From 719956b7446e8d19e8f2ea9c7796504ce18c64c3 Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Wed, 7 Oct 2026 20:10:07 +0530 Subject: [PATCH 31/68] feat(core): support AGW v5 labels and complete destination coverage Replace the v4 adapter and fixtures with the deployed Donut v5 suite. Enable stored label reads and owner rename/reset, preserving create-race recovery. Support owner funds-only Solana transfers, resolve registered SPL mints when precompile metadata is absent, and surface contract policy errors. Expand registered AGW coverage to 58 scenarios and retain source snapshots and validation evidence. Validation: 2014 unit tests and 90 actual-contract tests pass; 20 selected live E2Es pass across separate runs. Build, typechecks, package checks and E2E registration pass. Document the fresh-CEA destination-gas default follow-up. --- packages/core/AGW.md | 52 +- packages/core/README.md | 2 +- .../__agw-local__/agw-local-advanced.spec.ts | 8 +- .../__agw-local__/agw-local-races.spec.ts | 8 +- packages/core/__agw-local__/agw-local.spec.ts | 4 +- .../core/__agw-local__/delayed-index.spec.ts | 2 +- packages/core/__agw-local__/harness.ts | 6 +- packages/core/__agw-local__/labels.spec.ts | 141 + .../core/__agw-local__/svm-backend.spec.ts | 34 +- .../__agw-local__/svm-differential.spec.ts | 16 +- .../core/__agw-local__/svm-internals.spec.ts | 30 +- .../core/__agw-local__/svm-public.spec.ts | 258 +- ...ltiasset.spec.ts => v5-multiasset.spec.ts} | 8 +- packages/core/__agw-local__/vectors.spec.ts | 6 +- .../__e2e__/agw-svm-wire/outbound.spec.ts | 12 +- .../core/__e2e__/agw-svm-wire/replay.spec.ts | 6 +- packages/core/__e2e__/agw/_fixture.ts | 3 + packages/core/__e2e__/agw/_manifest.ts | 72 +- packages/core/__e2e__/agw/create.spec.ts | 4 +- packages/core/__e2e__/agw/labels.spec.ts | 461 + packages/core/__e2e__/agw/lifecycle.spec.ts | 4 +- .../__e2e__/agw/management-extended.spec.ts | 8 +- packages/core/__e2e__/agw/svm-public.spec.ts | 169 +- .../core/__e2e__/agw/svm-spl-transfer.spec.ts | 224 + .../core/__e2e__/agw/universal-evm.spec.ts | 21 +- .../core/__e2e__/agw/v4-multiasset.spec.ts | 138 - .../core/__e2e__/agw/v5-multiasset.spec.ts | 344 + packages/core/__e2e__/ci/preflight.ts | 9 +- packages/core/__e2e__/ci/run.ts | 2 +- packages/core/__e2e__/ci/suite.ts | 38 +- packages/core/__e2e__/shared/agw-state.ts | 6 +- .../__e2e__/shared/agw-svm-policy-probe.ts | 4 +- packages/core/jest.agw-local.config.ts | 2 +- .../core/scripts/agw-local/abis/engine.json | 2778 ++-- .../core/scripts/agw-local/abis/factory.json | 1458 +- .../core/scripts/agw-local/abis/manifest.json | 14 +- .../core/scripts/agw-local/abis/policy.json | 3094 ++--- .../scripts/agw-local/abis/validator.json | 138 +- .../core/scripts/agw-local/abis/wallet.json | 2312 ++-- packages/core/scripts/agw-local/gen-abi.mjs | 14 +- packages/core/scripts/agw-local/prepare.sh | 4 +- .../{v4-vectors.json => v5-vectors.json} | 2 +- .../src/lib/agentic/__tests__/codec.spec.ts | 20 +- .../src/lib/agentic/__tests__/fake-chain.ts | 15 +- .../src/lib/agentic/__tests__/labels.spec.ts | 115 + .../lib/agentic/__tests__/management.spec.ts | 43 +- .../__tests__/native-batch-response.spec.ts | 8 +- .../__tests__/outbound-response.spec.ts | 6 +- .../agentic/__tests__/reads-context.spec.ts | 25 +- .../__tests__/response-surface.spec.ts | 14 +- .../agentic/__tests__/rules-policy.spec.ts | 6 +- .../src/lib/agentic/__tests__/send.spec.ts | 28 +- .../agentic/__tests__/svm-internals.spec.ts | 2 +- .../lib/agentic/__tests__/svm-quote.spec.ts | 251 + .../core/src/lib/agentic/agentic.types.ts | 8 +- packages/core/src/lib/agentic/capabilities.ts | 2 +- .../core/src/lib/agentic/codec/defaults.ts | 4 +- packages/core/src/lib/agentic/codec/ids.ts | 2 +- packages/core/src/lib/agentic/codec/native.ts | 4 +- packages/core/src/lib/agentic/codec/rules.ts | 4 +- .../core/src/lib/agentic/codec/session.ts | 6 +- .../core/src/lib/agentic/codec/svm-terms.ts | 2 +- .../core/src/lib/agentic/codec/universal.ts | 2 +- packages/core/src/lib/agentic/constants.ts | 8 +- .../abi/{v4 => v5}/agent-validator.ts | 142 +- .../contracts/abi/{v4 => v5}/agw-factory.ts | 1458 +- .../agentic/contracts/abi/{v4 => v5}/agw.ts | 2296 ++-- .../agentic/contracts/abi/{v4 => v5}/index.ts | 4 +- .../contracts/abi/{v4 => v5}/smart-session.ts | 2782 ++-- .../abi/{v4 => v5}/universal-rules-policy.ts | 3094 ++--- .../src/lib/agentic/contracts/donut-v4.ts | 13 - .../src/lib/agentic/contracts/donut-v5.ts | 13 + .../lib/agentic/contracts/prc20-metadata.ts | 64 + .../lib/agentic/contracts/{v4.ts => v5.ts} | 33 +- packages/core/src/lib/agentic/deployments.ts | 45 +- .../src/lib/agentic/execution/outbound.ts | 16 +- .../core/src/lib/agentic/execution/send.ts | 12 +- .../lib/agentic/execution/svm-instruction.ts | 16 +- .../src/lib/agentic/execution/svm-outbound.ts | 34 +- .../src/lib/agentic/execution/svm-public.ts | 174 +- .../src/lib/agentic/execution/svm-quote.ts | 51 + .../src/lib/agentic/execution/svm-send.ts | 37 +- .../core/src/lib/agentic/management/create.ts | 40 +- .../core/src/lib/agentic/management/label.ts | 21 + .../src/lib/agentic/management/rules-write.ts | 46 +- .../src/lib/agentic/management/svm-context.ts | 49 +- .../src/lib/agentic/management/svm-public.ts | 15 +- .../core/src/lib/agentic/management/svm.ts | 2 +- packages/core/src/lib/agentic/reads/rules.ts | 33 +- packages/core/src/lib/agentic/reads/svm.ts | 4 +- .../core/src/lib/agentic/reads/wallets.ts | 87 +- packages/core/src/lib/agentic/response.ts | 65 +- packages/core/src/lib/agentic/revert.ts | 2 +- packages/core/src/lib/agentic/runtime.ts | 20 +- packages/core/src/lib/agentic/utils.ts | 4 +- packages/core/src/lib/agentic/wallet.ts | 104 +- packages/core/src/lib/constants/index.ts | 2 +- plan/agw/README.md | 12 +- plan/agw/SOURCES.md | 12 +- plan/agw/current-baseline.md | 44 +- plan/agw/gaps.md | 28 +- plan/agw/implementation-plan.md | 6 +- plan/agw/implementation-status.md | 32 +- plan/agw/latest-refresh.json | 35 +- plan/agw/notion/5-sdk-agw.md | 1 - .../20261007T102718466408Z/export-1.zip | Bin 0 -> 50237 bytes .../20261007T102718466408Z/export-2.zip | Bin 0 -> 26729 bytes .../20261007T102718466408Z/export-3.zip | Bin 0 -> 1105 bytes .../20261007T102718466408Z/export-4.zip | Bin 0 -> 9356 bytes .../20261007T102718466408Z/5-sdk-agw.diff | 10 + .../20261007T102718466408Z/5-sdk-agw.md | 732 + .../manifest-before.json | 178 + .../20261007T102718466408Z/refresh.json | 124 + plan/agw/questions-harsh.md | 2 +- plan/agw/questions-zaryab.md | 14 +- .../deployment-review-2026-10-07-v5/README.md | 54 + .../donut-probe.json | 167 + .../label-check.cjs | 29 + .../label-readonly-check.json | 61 + .../deployment-review-2026-10-07-v5/probe.cjs | 10 + .../address-book-v5/push_agw_contracts.json | 128 + .../source/docs/5_SDK_Owner_Integration.md | 523 + .../source/docs/addresses/donut.md | 109 + .../source/src/AGW.sol | 1224 ++ .../source/src/AGWFactory.sol | 355 + .../source/src/interfaces/IAGW.sol | 213 + .../source/src/libraries/Errors.sol | 407 + .../source/src/libraries/Types.sol | 550 + .../source/test/unit/29_walletLabel.t.sol | 275 + .../extended-v5-e2e-2026-10-07/README.md | 54 + .../api-comparison.json | 11460 ++++++++++++++++ .../credential-scan.json | 4 + .../evm-explicit-cosmos.json | 1 + .../evm-explicit-gas-events-raw.json | 1 + .../evm-explicit-gas-events.json | 1 + .../evm-explicit-node-records.json | 1 + .../evm-explicit-success.json | 7 + .../evm-failed-destination.json | 45 + .../evm-failure-followup.json | 14 + .../live-evidence.jsonl | 32 + .../logs/actual-contracts.log | 30 + .../extended-v5-e2e-2026-10-07/logs/api.log | 1 + .../extended-v5-e2e-2026-10-07/logs/build.log | 11 + .../logs/default-manifest.log | 79 + .../logs/destinations-final-evm-spl.log | 25 + .../logs/destinations-initial-default.log | 36 + .../logs/destinations-initial-explicit.log | 144 + .../extended-v5-e2e-2026-10-07/logs/docs.log | 1 + .../logs/full-unit.log | 173 + .../logs/funding-preflight-dry-run.log | 27 + .../logs/labels-live.log | 16 + .../extended-v5-e2e-2026-10-07/logs/lint.log | 11 + .../logs/manifest.log | 61 + .../logs/native-sol-final.log | 14 + .../logs/package.log | 1 + .../extended-v5-e2e-2026-10-07/logs/types.log | 0 .../spl-metadata-probe.json | 7 + .../sdk-alignment-fixes-2026-10-07/README.md | 48 + .../live-evidence.json | 38 + .../logs/build.log | 11 + .../logs/lint.log | 43 + .../logs/live-contract-refusals-final.log | 15 + .../logs/live-error-types-recheck.log | 15 + .../logs/live-initial.log | 41 + .../logs/local-contracts.log | 29 + .../logs/unit-timeout-recheck.log | 10 + .../logs/unit-timing-assertion-initial.log | 209 + .../logs/units.log | 172 + .../source-refresh-2026-10-07/README.md | 90 + .../contract-refresh.json | 82 + .../push-agentic-wallets/docs/1_AGW.md | 570 + .../docs/2_UniversalRulesPolicy.md | 326 + .../docs/3_Universal_Flow.md | 394 + .../docs/4_Native_Flow.md | 422 + .../docs/5_SDK_Owner_Integration.md | 488 + .../docs/addresses/donut.md | 83 + .../push-agentic-wallets/src/AGW.sol | 1176 ++ .../push-agentic-wallets/src/AGWFactory.sol | 355 + .../src/libraries/Types.sol | 544 + .../src/policies/UniversalRulesPolicy.sol | 1881 +++ .../docs/universalmarketplace/README.md | 645 + .../docs/universalmarketplace/criteria.md | 324 + .../docs/universalmarketplace/reference.md | 426 + .../donut-probe.json | 167 + .../reproduce-sdk-findings.cjs | 35 + .../sdk-findings.json | 34 + .../solana-probe.json | 36 + .../v5-implementation-2026-10-07/README.md | 44 + .../abi-signature-changes.json | 30 + .../api-comparison.json | 11460 ++++++++++++++++ .../credential-scan.json | 4 + .../live-evidence.jsonl | 11 + .../logs/actual-contracts.log | 30 + .../v5-implementation-2026-10-07/logs/api.log | 1 + .../logs/build.log | 11 + .../logs/docs.log | 1 + .../logs/e2e-default-manifest.log | 79 + .../logs/e2e-manifest.log | 56 + .../logs/final-type-lib.log | 0 .../logs/final-type-spec.log | 0 .../logs/full-unit.log | 173 + .../logs/golden-check.log | 9 + .../logs/lint.log | 143 + .../logs/live-acceptance-main.log | 44 + .../logs/live-agent-refusal.log | 13 + .../logs/live-labels-initial.log | 29 + .../logs/package.log | 1 + .../logs/type-lib.log | 0 .../logs/type-local.log | 0 .../logs/type-spec.log | 0 plan/agw/source-manifest.json | 85 +- 211 files changed, 51225 insertions(+), 10569 deletions(-) create mode 100644 packages/core/__agw-local__/labels.spec.ts rename packages/core/__agw-local__/{v4-multiasset.spec.ts => v5-multiasset.spec.ts} (98%) create mode 100644 packages/core/__e2e__/agw/labels.spec.ts create mode 100644 packages/core/__e2e__/agw/svm-spl-transfer.spec.ts delete mode 100644 packages/core/__e2e__/agw/v4-multiasset.spec.ts create mode 100644 packages/core/__e2e__/agw/v5-multiasset.spec.ts rename packages/core/src/lib/agentic/__fixtures__/{v4-vectors.json => v5-vectors.json} (99%) create mode 100644 packages/core/src/lib/agentic/__tests__/labels.spec.ts create mode 100644 packages/core/src/lib/agentic/__tests__/svm-quote.spec.ts rename packages/core/src/lib/agentic/contracts/abi/{v4 => v5}/agent-validator.ts (50%) rename packages/core/src/lib/agentic/contracts/abi/{v4 => v5}/agw-factory.ts (51%) rename packages/core/src/lib/agentic/contracts/abi/{v4 => v5}/agw.ts (50%) rename packages/core/src/lib/agentic/contracts/abi/{v4 => v5}/index.ts (69%) rename packages/core/src/lib/agentic/contracts/abi/{v4 => v5}/smart-session.ts (53%) rename packages/core/src/lib/agentic/contracts/abi/{v4 => v5}/universal-rules-policy.ts (50%) delete mode 100644 packages/core/src/lib/agentic/contracts/donut-v4.ts create mode 100644 packages/core/src/lib/agentic/contracts/donut-v5.ts rename packages/core/src/lib/agentic/contracts/{v4.ts => v5.ts} (93%) create mode 100644 packages/core/src/lib/agentic/execution/svm-quote.ts create mode 100644 packages/core/src/lib/agentic/management/label.ts create mode 100644 plan/agw/notion/exports/20261007T102718466408Z/export-1.zip create mode 100644 plan/agw/notion/exports/20261007T102718466408Z/export-2.zip create mode 100644 plan/agw/notion/exports/20261007T102718466408Z/export-3.zip create mode 100644 plan/agw/notion/exports/20261007T102718466408Z/export-4.zip create mode 100644 plan/agw/notion/history/20261007T102718466408Z/5-sdk-agw.diff create mode 100644 plan/agw/notion/history/20261007T102718466408Z/5-sdk-agw.md create mode 100644 plan/agw/notion/history/20261007T102718466408Z/manifest-before.json create mode 100644 plan/agw/notion/history/20261007T102718466408Z/refresh.json create mode 100644 plan/agw/research/deployment-review-2026-10-07-v5/README.md create mode 100644 plan/agw/research/deployment-review-2026-10-07-v5/donut-probe.json create mode 100644 plan/agw/research/deployment-review-2026-10-07-v5/label-check.cjs create mode 100644 plan/agw/research/deployment-review-2026-10-07-v5/label-readonly-check.json create mode 100644 plan/agw/research/deployment-review-2026-10-07-v5/probe.cjs create mode 100644 plan/agw/research/deployment-review-2026-10-07-v5/source/deployments/address-book-v5/push_agw_contracts.json create mode 100644 plan/agw/research/deployment-review-2026-10-07-v5/source/docs/5_SDK_Owner_Integration.md create mode 100644 plan/agw/research/deployment-review-2026-10-07-v5/source/docs/addresses/donut.md create mode 100644 plan/agw/research/deployment-review-2026-10-07-v5/source/src/AGW.sol create mode 100644 plan/agw/research/deployment-review-2026-10-07-v5/source/src/AGWFactory.sol create mode 100644 plan/agw/research/deployment-review-2026-10-07-v5/source/src/interfaces/IAGW.sol create mode 100644 plan/agw/research/deployment-review-2026-10-07-v5/source/src/libraries/Errors.sol create mode 100644 plan/agw/research/deployment-review-2026-10-07-v5/source/src/libraries/Types.sol create mode 100644 plan/agw/research/deployment-review-2026-10-07-v5/source/test/unit/29_walletLabel.t.sol create mode 100644 plan/agw/research/extended-v5-e2e-2026-10-07/README.md create mode 100644 plan/agw/research/extended-v5-e2e-2026-10-07/api-comparison.json create mode 100644 plan/agw/research/extended-v5-e2e-2026-10-07/credential-scan.json create mode 100644 plan/agw/research/extended-v5-e2e-2026-10-07/evm-explicit-cosmos.json create mode 100644 plan/agw/research/extended-v5-e2e-2026-10-07/evm-explicit-gas-events-raw.json create mode 100644 plan/agw/research/extended-v5-e2e-2026-10-07/evm-explicit-gas-events.json create mode 100644 plan/agw/research/extended-v5-e2e-2026-10-07/evm-explicit-node-records.json create mode 100644 plan/agw/research/extended-v5-e2e-2026-10-07/evm-explicit-success.json create mode 100644 plan/agw/research/extended-v5-e2e-2026-10-07/evm-failed-destination.json create mode 100644 plan/agw/research/extended-v5-e2e-2026-10-07/evm-failure-followup.json create mode 100644 plan/agw/research/extended-v5-e2e-2026-10-07/live-evidence.jsonl create mode 100644 plan/agw/research/extended-v5-e2e-2026-10-07/logs/actual-contracts.log create mode 100644 plan/agw/research/extended-v5-e2e-2026-10-07/logs/api.log create mode 100644 plan/agw/research/extended-v5-e2e-2026-10-07/logs/build.log create mode 100644 plan/agw/research/extended-v5-e2e-2026-10-07/logs/default-manifest.log create mode 100644 plan/agw/research/extended-v5-e2e-2026-10-07/logs/destinations-final-evm-spl.log create mode 100644 plan/agw/research/extended-v5-e2e-2026-10-07/logs/destinations-initial-default.log create mode 100644 plan/agw/research/extended-v5-e2e-2026-10-07/logs/destinations-initial-explicit.log create mode 100644 plan/agw/research/extended-v5-e2e-2026-10-07/logs/docs.log create mode 100644 plan/agw/research/extended-v5-e2e-2026-10-07/logs/full-unit.log create mode 100644 plan/agw/research/extended-v5-e2e-2026-10-07/logs/funding-preflight-dry-run.log create mode 100644 plan/agw/research/extended-v5-e2e-2026-10-07/logs/labels-live.log create mode 100644 plan/agw/research/extended-v5-e2e-2026-10-07/logs/lint.log create mode 100644 plan/agw/research/extended-v5-e2e-2026-10-07/logs/manifest.log create mode 100644 plan/agw/research/extended-v5-e2e-2026-10-07/logs/native-sol-final.log create mode 100644 plan/agw/research/extended-v5-e2e-2026-10-07/logs/package.log create mode 100644 plan/agw/research/extended-v5-e2e-2026-10-07/logs/types.log create mode 100644 plan/agw/research/extended-v5-e2e-2026-10-07/spl-metadata-probe.json create mode 100644 plan/agw/research/sdk-alignment-fixes-2026-10-07/README.md create mode 100644 plan/agw/research/sdk-alignment-fixes-2026-10-07/live-evidence.json create mode 100644 plan/agw/research/sdk-alignment-fixes-2026-10-07/logs/build.log create mode 100644 plan/agw/research/sdk-alignment-fixes-2026-10-07/logs/lint.log create mode 100644 plan/agw/research/sdk-alignment-fixes-2026-10-07/logs/live-contract-refusals-final.log create mode 100644 plan/agw/research/sdk-alignment-fixes-2026-10-07/logs/live-error-types-recheck.log create mode 100644 plan/agw/research/sdk-alignment-fixes-2026-10-07/logs/live-initial.log create mode 100644 plan/agw/research/sdk-alignment-fixes-2026-10-07/logs/local-contracts.log create mode 100644 plan/agw/research/sdk-alignment-fixes-2026-10-07/logs/unit-timeout-recheck.log create mode 100644 plan/agw/research/sdk-alignment-fixes-2026-10-07/logs/unit-timing-assertion-initial.log create mode 100644 plan/agw/research/sdk-alignment-fixes-2026-10-07/logs/units.log create mode 100644 plan/agw/research/source-refresh-2026-10-07/README.md create mode 100644 plan/agw/research/source-refresh-2026-10-07/contract-refresh.json create mode 100644 plan/agw/research/source-refresh-2026-10-07/contracts/push-agentic-wallets/docs/1_AGW.md create mode 100644 plan/agw/research/source-refresh-2026-10-07/contracts/push-agentic-wallets/docs/2_UniversalRulesPolicy.md create mode 100644 plan/agw/research/source-refresh-2026-10-07/contracts/push-agentic-wallets/docs/3_Universal_Flow.md create mode 100644 plan/agw/research/source-refresh-2026-10-07/contracts/push-agentic-wallets/docs/4_Native_Flow.md create mode 100644 plan/agw/research/source-refresh-2026-10-07/contracts/push-agentic-wallets/docs/5_SDK_Owner_Integration.md create mode 100644 plan/agw/research/source-refresh-2026-10-07/contracts/push-agentic-wallets/docs/addresses/donut.md create mode 100644 plan/agw/research/source-refresh-2026-10-07/contracts/push-agentic-wallets/src/AGW.sol create mode 100644 plan/agw/research/source-refresh-2026-10-07/contracts/push-agentic-wallets/src/AGWFactory.sol create mode 100644 plan/agw/research/source-refresh-2026-10-07/contracts/push-agentic-wallets/src/libraries/Types.sol create mode 100644 plan/agw/research/source-refresh-2026-10-07/contracts/push-agentic-wallets/src/policies/UniversalRulesPolicy.sol create mode 100644 plan/agw/research/source-refresh-2026-10-07/contracts/push-chain-core-contracts/docs/universalmarketplace/README.md create mode 100644 plan/agw/research/source-refresh-2026-10-07/contracts/push-chain-core-contracts/docs/universalmarketplace/criteria.md create mode 100644 plan/agw/research/source-refresh-2026-10-07/contracts/push-chain-core-contracts/docs/universalmarketplace/reference.md create mode 100644 plan/agw/research/source-refresh-2026-10-07/donut-probe.json create mode 100644 plan/agw/research/source-refresh-2026-10-07/reproduce-sdk-findings.cjs create mode 100644 plan/agw/research/source-refresh-2026-10-07/sdk-findings.json create mode 100644 plan/agw/research/source-refresh-2026-10-07/solana-probe.json create mode 100644 plan/agw/research/v5-implementation-2026-10-07/README.md create mode 100644 plan/agw/research/v5-implementation-2026-10-07/abi-signature-changes.json create mode 100644 plan/agw/research/v5-implementation-2026-10-07/api-comparison.json create mode 100644 plan/agw/research/v5-implementation-2026-10-07/credential-scan.json create mode 100644 plan/agw/research/v5-implementation-2026-10-07/live-evidence.jsonl create mode 100644 plan/agw/research/v5-implementation-2026-10-07/logs/actual-contracts.log create mode 100644 plan/agw/research/v5-implementation-2026-10-07/logs/api.log create mode 100644 plan/agw/research/v5-implementation-2026-10-07/logs/build.log create mode 100644 plan/agw/research/v5-implementation-2026-10-07/logs/docs.log create mode 100644 plan/agw/research/v5-implementation-2026-10-07/logs/e2e-default-manifest.log create mode 100644 plan/agw/research/v5-implementation-2026-10-07/logs/e2e-manifest.log create mode 100644 plan/agw/research/v5-implementation-2026-10-07/logs/final-type-lib.log create mode 100644 plan/agw/research/v5-implementation-2026-10-07/logs/final-type-spec.log create mode 100644 plan/agw/research/v5-implementation-2026-10-07/logs/full-unit.log create mode 100644 plan/agw/research/v5-implementation-2026-10-07/logs/golden-check.log create mode 100644 plan/agw/research/v5-implementation-2026-10-07/logs/lint.log create mode 100644 plan/agw/research/v5-implementation-2026-10-07/logs/live-acceptance-main.log create mode 100644 plan/agw/research/v5-implementation-2026-10-07/logs/live-agent-refusal.log create mode 100644 plan/agw/research/v5-implementation-2026-10-07/logs/live-labels-initial.log create mode 100644 plan/agw/research/v5-implementation-2026-10-07/logs/package.log create mode 100644 plan/agw/research/v5-implementation-2026-10-07/logs/type-lib.log create mode 100644 plan/agw/research/v5-implementation-2026-10-07/logs/type-local.log create mode 100644 plan/agw/research/v5-implementation-2026-10-07/logs/type-spec.log diff --git a/packages/core/AGW.md b/packages/core/AGW.md index f767595c..8945327b 100644 --- a/packages/core/AGW.md +++ b/packages/core/AGW.md @@ -1,6 +1,6 @@ # Agentic wallets on Push Chain -This guide describes AGW v4 in this SDK branch. Donut is the configured deployment. Native Push, EVM destination rules and named-IDL Solana devnet rules are supported. Solana-origin signers can already act through their Push UEA. +This guide describes AGW v5 in this SDK branch. Donut is the configured deployment. Native Push, EVM destination rules and named-IDL Solana devnet rules are supported. Solana-origin signers can already act through their Push UEA. An AGW holds assets. Its owner grants or revokes rules and can execute unrestricted owner calls. An agent executes through its own Push identity, and each agent call must pass the granted policy. A Push-native key's identity is its EOA; an external key's identity is its Push UEA for that origin chain. @@ -153,6 +153,24 @@ Replacement asserts the old spend, revokes and grants in one owner transaction. `rules.list()` returns enabled rules, including enabled rules whose expiry has passed. Expiry is enforced on execution. Revoked-history reconstruction is outside v1. Rule IDs are wallet-scoped; do not treat an ID alone as a globally unique permission. +## Wallet labels + +Donut uses the v5 factory `0x8137F96A50EBF41d904e3678c84c391a0D1BCcc5`. Wallet labels are stored on-chain; `info()` and `list()` read the current value. An empty deployment label defaults to `AGW `. + +```ts +async function renameWallet(owner: PushChain, wallet: Address) { + const handle = owner.agentic.wallet(wallet); + const renamed = await handle.setLabel('Trading'); + const info = await handle.info(); + const reset = await handle.setLabel(''); + return { renamed, info, reset }; +} +``` + +Create and rename labels accept at most **64 UTF-8 bytes**, including spaces; 16 four-byte emoji fit. Empty rename resets the default. The SDK renames through the owner door for EOA and UEA owners, emits progress through the supplied hook and records one owner-action checkpoint. The contract's direct `setLabel` call itself records no checkpoint. Agent and read-only clients cannot rename. + +New wallets use v5 only. Existing v4 wallets do not acquire label functions and are unsupported by this SDK adapter. Wallet predictions and EIP-712 intent domains use the new factory; do not reuse old predicted addresses or signatures. On relayed signed deployment, the contract does not include the cosmetic label in `OwnerIntent`; the owner can correct it afterward. + ## Grant an EVM destination rule The destination token identifies an asset on that destination chain. The SDK resolves the mapped PRC20 held by the AGW. Limits use the token's smallest units; `maxGasPerCall` uses PC wei. A rule may list several assets, but each outbound request moves one listed token. @@ -220,11 +238,12 @@ async function sendToSepolia(agent: PushChain, counter: Address, amount: bigint) to: { address: counter, chain: SEPOLIA }, data: [{ to: counter, value: BigInt(0), data: '0xd09de08a' }], funds: { amount, token: ETH }, + gasLimit: BigInt(2_000_000), // includes fresh CEA finalization in this example }); } ``` -The 20/21-PC values are example budgets, not fee estimates. Fees and gas are quoted for the current request. Approval safety is the application's responsibility; the SDK validates structure and contract limits rather than deciding whether a grant is appropriate. +The current core default of 500,000 destination gas was insufficient for fresh Sepolia CEA finalization in our live test (~1.3 million estimated). The example supplies a bounded two-million-gas limit; choose a budget appropriate for your destination calls. The 20/21-PC values are example budgets, not fee estimates. Fees and gas are quoted for the current request. Approval safety is the application's responsibility; the SDK validates structure and contract limits rather than deciding whether a grant is appropriate. ## Wait, replay and recover @@ -311,12 +330,37 @@ These examples assume the supplied IDL describes `receive_sol` with those accoun Supported rule layouts have an eight-byte discriminator, top-level non-optional accounts, and fixed-width primitive/fixed-array arguments. Field comparisons support exact bytes (at most 32 bytes), unsigned integer min/max (up to `u64`), and same-width unsigned ratio floors. Variable-length or nested/defined argument layouts and optional/nested accounts are rejected before signing. An IDL describes encoding; it does not prove what the program does with those accounts. -Public SVM sends support one instruction encoded with `encodeTxData` (which registers the IDL), or data matching an already registered IDL. Arrays and funds-only sends are rejected. Reads return `DecodedSolanaRule` with `format: 'decoded'` and exact stored program/account/data constraints. They cannot reconstruct an IDL; use a named `SolanaRule` input to add or replace it. Native/EVM decoded rules remain reusable in raw-offset form. +Agent SVM sends require one instruction encoded with `encodeTxData` (which registers the IDL), or data matching an already registered IDL. Instruction arrays remain unsupported. Owners can also send funds without any IDL or instruction: + +```ts +async function transferSolanaFunds(ownerWallet: PushChain, recipient: string) { + return ownerWallet.universal.sendTransaction({ + to: { address: recipient, chain: PushChain.CONSTANTS.CHAIN.SOLANA_DEVNET }, + value: BigInt(10_000), // native SOL, in lamports + }); +} + +async function transferSolanaUsdt(ownerWallet: PushChain, recipient: string) { + return ownerWallet.universal.sendTransaction({ + to: { address: recipient, chain: PushChain.CONSTANTS.CHAIN.SOLANA_DEVNET }, + funds: { + token: PushChain.CONSTANTS.MOVEABLE.TOKEN.SOLANA_DEVNET.USDT, + amount: BigInt(1), // 0.000001 USDT at six decimals + }, + }); +} +``` + +`ownerWallet` is initialized with the owner signer and `agenticWallet`. As with instruction sends, fund the wallet with PC/PRC20 and establish a separate bounded gateway allowance. Transfers use an empty payload and the requested recipient; the SDK applies core’s Solana finalization/rent budget using the wallet identity. Send either `value` for SOL or `funds` for a token, not both. A zero-amount funds-only send is rejected. + +Funds-only responses expose `agentic.destinationTransfer` with the recipient, burned Push PRC20 token, and amount. They have no `destinationInstruction`; replay uses the same representation. Native SOL transfers show their amount in `value`, while SPL transfers carry the amount in transfer metadata and show zero native value. + +Structural/context/funding failures are SDK `AgenticError`s. Granted permissions, expiry and spend limits are enforced by the contract. Refusals obtained during contract simulation or execution are mapped to `AgenticRevertError` with `decodedError`; simulation failure does not broadcast a transaction. Reads return `DecodedSolanaRule` with `format: 'decoded'` and exact stored program/account/data constraints. They cannot reconstruct an IDL; use a named `SolanaRule` input to add or replace it. Native/EVM decoded rules remain reusable in raw-offset form. Responses expose `agentic.destinationInstruction` and the wallet’s destination CEA. Check `externalStatus` and replay the same transaction hash after a timeout. ## Current API boundaries -Rule `ref` is removed from public inputs and records; supplying it is rejected. Checkpoint `ref` is a separate existing event field and is preserved. Editable `setLabel` awaits a verified contract interface/deployment. Contract permission enforcement is already present: unauthorized actions under the supplied rule are rejected, and the SDK maps the errors. Revoked history, public spend records, public generation context and `compileCard` are outside standalone v1. Omitted native PC value limits are zero. Native argument-index and raw-offset inputs are both supported; decoded native/EVM rules preserve exact offsets. +Rule `ref` is removed from public inputs and records; supplying it is rejected. Checkpoint `ref` is a separate existing event field and is preserved. Editable labels are implemented against the checked v5 deployment. Contract permission enforcement is already present: unauthorized actions under the supplied rule are rejected, and the SDK maps the errors. Revoked history, public spend records, public generation context and `compileCard` are outside standalone v1. Omitted native PC value limits are zero. Native argument-index and raw-offset inputs are both supported; decoded native/EVM rules preserve exact offsets. Use `PushChain.CONSTANTS.READ.CHAIN.WEB2` for Web2 reads. Its value is `web2`; the old literal `web2:https` is still accepted and normalizes to the same wire identity. Literal comparisons against the older spelling need updating. Web2 is a read source, not a transaction destination. diff --git a/packages/core/README.md b/packages/core/README.md index d5f44027..d65a3a00 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -8,7 +8,7 @@ Push Chain is a true universal L1 that is 100% EVM compatible. It allows develop ## Documentation -For AGW v4 in this branch, see the [agentic wallet integration guide](AGW.md) for creation, rules, funding, execution and recovery. +For AGW v5 in this branch, see the [agentic wallet integration guide](AGW.md) for creation, rules, funding, execution and recovery. For full documentation, API references, and guides, visit: 👉 [Push Chain Developer Docs](https://push.org/docs) diff --git a/packages/core/__agw-local__/agw-local-advanced.spec.ts b/packages/core/__agw-local__/agw-local-advanced.spec.ts index d9e26e3b..83817f1b 100644 --- a/packages/core/__agw-local__/agw-local-advanced.spec.ts +++ b/packages/core/__agw-local__/agw-local-advanced.spec.ts @@ -1,6 +1,6 @@ import { readNativeCounters } from '../__e2e__/shared/agw-state'; /** - * Real-contract checks for the harder AGW paths (pinned v4 on anvil). + * Real-contract checks for the harder AGW paths (pinned v5 on anvil). * The universal-outbound block drives the SDK's composer with a runtime whose * CEA and fee quote are local stand-ins (no destination chain or price feeds * exist here); URP still decides every gate on the composed request. @@ -74,7 +74,7 @@ const fund = (h: Harness, to: Address, value: bigint) => chain: h.wallets[4].chain, }); -describe('AGW advanced paths against real v4 contracts', () => { +describe('AGW advanced paths against real v5 contracts', () => { let h: Harness; let owner: PushChain; let agentAddr: Address; @@ -356,7 +356,7 @@ describe('AGW advanced paths against real v4 contracts', () => { }); }); - describe('agent EVM outbound (v4 multi-asset terms, stub gateway)', () => { + describe('agent EVM outbound (v5 multi-asset terms, stub gateway)', () => { const SEPOLIA = CHAIN.ETHEREUM_SEPOLIA; const CEA = getAddress('0x000000000000000000000000000000000000cea1'); const destTarget = getAddress('0x00000000000000000000000000000000000d0d0d'); @@ -378,7 +378,7 @@ describe('AGW advanced paths against real v4 contracts', () => { await h.publicClient.waitForTransactionReceipt({ hash: await fund(h, wallet, BigInt(10) ** BigInt(17)), }); - // Fixture setup (raw owner call): grant a v4 multi-asset universal rule. + // Fixture setup (raw owner call): grant a v5 multi-asset universal rule. const terms = encodeUniversalTerms({ validUntil: (await chainNow(h)) + 3600, expectedCEA: CEA, diff --git a/packages/core/__agw-local__/agw-local-races.spec.ts b/packages/core/__agw-local__/agw-local-races.spec.ts index 3121007d..dd106d64 100644 --- a/packages/core/__agw-local__/agw-local-races.spec.ts +++ b/packages/core/__agw-local__/agw-local-races.spec.ts @@ -1,6 +1,6 @@ /** * Race regressions found during independent SDK review, - * against the real pinned v4 contracts on local anvil. + * against the real pinned v5 contracts on local anvil. * R1 — a concurrent creation must never let this create() grant on a wallet it * did not deploy (the deploy is index-bound through deployWalletWithSig). * R4 — an owner outbound must never restore an allowance revoked after the @@ -9,7 +9,7 @@ import { encodeFunctionData, parseAbi, type Address } from 'viem'; import { AgenticRevertError, CHAIN, type PushChain } from '../src'; import type { AgenticRuntime } from '../src/lib/agentic/runtime'; -import { v4 } from '../src/lib/agentic/contracts/v4'; +import { v5 } from '../src/lib/agentic/contracts/v5'; import { AGENTIC_ERROR_CODE } from '../src/lib/agentic/errors'; import { startHarness, type Harness } from './harness'; @@ -21,7 +21,7 @@ const TOKEN = parseAbi([ const internalsOf = (c: PushChain) => (c as unknown as { agenticRuntime: AgenticRuntime }).agenticRuntime; -describe('AGW race regressions (real v4 contracts)', () => { +describe('AGW race regressions (real v5 contracts)', () => { let h: Harness; let owner: PushChain; beforeAll(async () => { @@ -125,7 +125,7 @@ describe('AGW race regressions (real v4 contracts)', () => { const execute = rt.execute; rt.execute = async (params, options) => { rt.execute = execute; - const revoke = v4.encodeExecute([ + const revoke = v5.encodeExecute([ { target: token, value: BigInt(0), diff --git a/packages/core/__agw-local__/agw-local.spec.ts b/packages/core/__agw-local__/agw-local.spec.ts index 5a9fd2a6..93f0a3db 100644 --- a/packages/core/__agw-local__/agw-local.spec.ts +++ b/packages/core/__agw-local__/agw-local.spec.ts @@ -1,6 +1,6 @@ import { readNativeCounters } from '../__e2e__/shared/agw-state'; /** - * Real-contract checks of the AGW SDK against the pinned v4 contracts on a + * Real-contract checks of the AGW SDK against the pinned v5 contracts on a * local anvil chain (see harness.ts for scope and limits). Every assertion * about authorization, atomicity, counters and checkpoints is decided by the * real contracts; the only stubbed component is the gateway. @@ -35,7 +35,7 @@ const WALLET_ABI = parseAbi([ const inAnHour = () => Math.floor(Date.now() / 1000) + 3600; -describe('AGW SDK against real v4 contracts (local anvil)', () => { +describe('AGW SDK against real v5 contracts (local anvil)', () => { let h: Harness; let owner: PushChain; let ownerAddr: Address; diff --git a/packages/core/__agw-local__/delayed-index.spec.ts b/packages/core/__agw-local__/delayed-index.spec.ts index ea7c2a28..958bf8c3 100644 --- a/packages/core/__agw-local__/delayed-index.spec.ts +++ b/packages/core/__agw-local__/delayed-index.spec.ts @@ -1,4 +1,4 @@ -/** Real v4 execution/receipts; only origin mapping and Cosmos indexing are fixtures. */ +/** Real v5 execution/receipts; only origin mapping and Cosmos indexing are fixtures. */ import { getAddress, parseAbi, type Address, type Hex } from 'viem'; import { CHAIN, type PushChain } from '../src'; import * as account from '../src/lib/universal/account/account'; diff --git a/packages/core/__agw-local__/harness.ts b/packages/core/__agw-local__/harness.ts index a34e199f..22ad9328 100644 --- a/packages/core/__agw-local__/harness.ts +++ b/packages/core/__agw-local__/harness.ts @@ -2,7 +2,7 @@ * Local AGW contract harness — REVIEW ONLY. * * Starts anvil as a stand-in Push LOCALNET (chainId 9000, the SDK's - * CHAIN_INFO[PUSH_LOCALNET].chainId), deploys the REAL pinned v4 + * CHAIN_INFO[PUSH_LOCALNET].chainId), deploys the REAL pinned v5 * contracts (SmartSession, AgentValidator, UniversalRulesPolicy behind a * TransparentUpgradeableProxy, AGW implementation, AGWFactory behind an * ERC1967Proxy) from an isolated build prepared by @@ -353,8 +353,8 @@ async function deployHarness( resetAgenticGenerations(); const generation = registerAgenticGeneration({ - id: 'v4', - sourceCommit: 'e8db74815cfbbf5389593805e464fe8d85f7f735', + id: 'v5', + sourceCommit: '2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb', network: PUSH_NETWORK.LOCALNET, advertised: false, addresses: { diff --git a/packages/core/__agw-local__/labels.spec.ts b/packages/core/__agw-local__/labels.spec.ts new file mode 100644 index 00000000..86786d7e --- /dev/null +++ b/packages/core/__agw-local__/labels.spec.ts @@ -0,0 +1,141 @@ +/** Real v5 wallet/factory label state; no bridge or destination simulation. */ +import { decodeEventLog, type Address } from 'viem'; +import { PushChain } from '../src'; +import { v5 } from '../src/lib/agentic/contracts/v5'; +import { AGENTIC_ERROR_CODE } from '../src/lib/agentic/errors'; +import { startHarness, type Harness } from './harness'; + +describe('v5 label SDK against real contracts', () => { + let h: Harness; + let owner: PushChain; + beforeAll(async () => { + h = await startHarness(18565); + owner = await h.client(0); + }); + afterAll(async () => { + await h?.stop(); + }); + const count = (address: Address) => + h.publicClient.readContract({ + address, + abi: v5.abis.wallet, + functionName: 'checkpointCount', + }); + + it('stores custom deploy labels and defaults empty labels per owner index', async () => { + const first = await owner.agentic.create('', { rules: [] }); + const second = await owner.agentic.create('custom', { rules: [] }); + const other = await h.client(2); + const theirs = await other.agentic.create('', { rules: [] }); + expect((await owner.agentic.wallet(first.wallet).info()).label).toBe( + `AGW ${first.index + 1}` + ); + expect((await owner.agentic.wallet(second.wallet).info()).label).toBe( + 'custom' + ); + expect((await other.agentic.wallet(theirs.wallet).info()).label).toBe( + 'AGW 1' + ); + expect(await count(first.wallet)).toBe(BigInt(0)); + }); + + it('renames and resets through public SDK; fresh info/list and checkpoints agree', async () => { + const made = await owner.agentic.create('before', { rules: [] }); + const w = owner.agentic.wallet(made.wallet); + const hook = jest.fn(); + const before = await count(made.wallet); + const tx = await w.setLabel('after', { progressHook: hook }); + const receipt = await tx.wait(); + const labelEvents = receipt.logs.flatMap((log) => { + if (log.address.toLowerCase() !== made.wallet.toLowerCase()) return []; + try { + const ev = decodeEventLog({ + abi: v5.abis.wallet, + data: log.data, + topics: log.topics, + }); + return ev.eventName === 'LabelSet' ? [ev.args.label] : []; + } catch { + return []; + } + }); + expect(labelEvents).toEqual(['after']); + expect((await w.info()).label).toBe('after'); + expect( + (await owner.agentic.list()).wallets.find( + (x) => x.address === made.wallet + )?.label + ).toBe('after'); + expect(await count(made.wallet)).toBe(before + BigInt(1)); + expect(hook).toHaveBeenCalledWith( + expect.objectContaining({ id: 'AGENTIC-TX-199-01' }) + ); + await w.setLabel(''); + expect((await w.info()).label).toBe(`AGW ${made.index + 1}`); + expect(await count(made.wallet)).toBe(before + BigInt(2)); + }); + + it('direct contract rename changes no checkpoint; subsequent SDK reads show it', async () => { + const made = await owner.agentic.create('before', { rules: [] }); + const before = await count(made.wallet); + await h.write(0, made.wallet, v5.abis.wallet, 'setLabel', ['direct']); + expect(await count(made.wallet)).toBe(before); + expect((await owner.agentic.wallet(made.wallet).info()).label).toBe( + 'direct' + ); + }); + + it('accepts exactly 64 UTF-8 bytes and rejects invalid create/rename without changing count or state', async () => { + const unicode = '🙂'.repeat(16); + const made = await owner.agentic.create(unicode, { rules: [] }); + const w = owner.agentic.wallet(made.wallet); + await w.setLabel('a'.repeat(64)); + const before = await count(made.wallet); + const next = await owner.agentic.derive(); + for (const invalid of ['a'.repeat(65), '🙂'.repeat(17)]) { + await expect(w.setLabel(invalid)).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.INVALID_RULE, + }); + await expect( + owner.agentic.create(invalid, { rules: [] }) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.INVALID_RULE }); + await expect( + h.publicClient.simulateContract({ + address: made.wallet, + abi: v5.abis.wallet, + functionName: 'setLabel', + args: [invalid], + account: h.wallets[0].account!.address, + }) + ).rejects.toThrow('LabelTooLong'); + } + expect(await owner.agentic.derive()).toEqual(next); + expect(await count(made.wallet)).toBe(before); + expect((await w.info()).label).toBe('a'.repeat(64)); + }); + + it('non-owner and read-only SDK calls cannot rename; actual contract also rejects non-owner', async () => { + const made = await owner.agentic.create('owner-only', { rules: [] }); + const agent = await h.client(1); + await expect( + agent.agentic.wallet(made.wallet).setLabel('attack') + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.NOT_WALLET_OWNER }); + const ro = await h.readOnlyClient(0); + await expect( + ro.agentic.wallet(made.wallet).setLabel('attack') + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.READ_ONLY }); + await expect( + h.publicClient.simulateContract({ + address: made.wallet, + abi: v5.abis.wallet, + functionName: 'setLabel', + args: ['attack'], + account: h.wallets[1].account!.address, + }) + ).rejects.toThrow('CallerIsNotOwner'); + expect((await owner.agentic.wallet(made.wallet).info()).label).toBe( + 'owner-only' + ); + expect(await count(made.wallet)).toBe(BigInt(0)); + }); +}); diff --git a/packages/core/__agw-local__/svm-backend.spec.ts b/packages/core/__agw-local__/svm-backend.spec.ts index 59e27564..98e22be9 100644 --- a/packages/core/__agw-local__/svm-backend.spec.ts +++ b/packages/core/__agw-local__/svm-backend.spec.ts @@ -1,4 +1,4 @@ -/** Internal SVM lifecycle/execution on actual v4 contracts; no Solana/TSS simulation. */ +/** Internal SVM lifecycle/execution on actual v5 contracts; no Solana/TSS simulation. */ import { PublicKey } from '@solana/web3.js'; import { encodeFunctionData, @@ -29,7 +29,7 @@ import { registerIdl, clearRegistry, } from '../src/lib/orchestrator/svm-idl/registry'; -import { v4 } from '../src/lib/agentic/contracts/v4'; +import { v5 } from '../src/lib/agentic/contracts/v5'; import { wrapSendError } from '../src/lib/agentic/management/common'; import { startHarness, type Harness } from './harness'; @@ -60,7 +60,7 @@ const metadata: SvmMetadataProvider = { }), }; -describe('internal prepared SVM backend on v4', () => { +describe('internal prepared SVM backend on v5', () => { let h: Harness, owner: PushChain, tokens: Address[]; beforeAll(async () => { h = await startHarness(18554); @@ -173,9 +173,9 @@ describe('internal prepared SVM backend on v4', () => { }); for (const token of tokens) { await h.write(0, token, TOKEN, 'mint', [wallet, BigInt(100)]); - await h.write(0, wallet, v4.abis.wallet, 'execute', [ + await h.write(0, wallet, v5.abis.wallet, 'execute', [ key('00'), - v4.packSingle({ + v5.packSingle({ target: token, value: BigInt(0), data: encodeFunctionData({ @@ -241,9 +241,9 @@ describe('internal prepared SVM backend on v4', () => { }); it('requires separate allowance and never writes an approval on the agent path', async () => { const s = await setup(); - await h.write(0, s.wallet, v4.abis.wallet, 'execute', [ + await h.write(0, s.wallet, v5.abis.wallet, 'execute', [ key('00'), - v4.packSingle({ + v5.packSingle({ target: tokens[2], value: BigInt(0), data: encodeFunctionData({ @@ -266,7 +266,7 @@ describe('internal prepared SVM backend on v4', () => { ).tx.wait(); const before = await h.publicClient.readContract({ address: s.wallet, - abi: v4.abis.wallet, + abi: v5.abis.wallet, functionName: 'checkpointCount', }); const next = await replaceSvmWire( @@ -285,7 +285,7 @@ describe('internal prepared SVM backend on v4', () => { expect( await h.publicClient.readContract({ address: s.wallet, - abi: v4.abis.wallet, + abi: v5.abis.wallet, functionName: 'checkpointCount', }) ).toBe(before + BigInt(5)); @@ -309,7 +309,7 @@ describe('internal prepared SVM backend on v4', () => { ).tx.wait(); const before = await h.publicClient.readContract({ address: s.wallet, - abi: v4.abis.wallet, + abi: v5.abis.wallet, functionName: 'checkpointCount', }); const error = await rt(owner) @@ -322,7 +322,7 @@ describe('internal prepared SVM backend on v4', () => { expect( await h.publicClient.readContract({ address: s.wallet, - abi: v4.abis.wallet, + abi: v5.abis.wallet, functionName: 'checkpointCount', }) ).toBe(before); @@ -410,9 +410,9 @@ describe('internal prepared SVM backend on v4', () => { await owner.agentic.wallet(s.wallet).rules.revoke([s.id]) ).wait(); else - await h.write(0, s.wallet, v4.abis.wallet, 'execute', [ + await h.write(0, s.wallet, v5.abis.wallet, 'execute', [ key('00'), - v4.packSingle({ + v5.packSingle({ target: tokens[2], value: BigInt(0), data: encodeFunctionData({ @@ -432,7 +432,7 @@ describe('internal prepared SVM backend on v4', () => { ]); ticks = await h.publicClient.readContract({ address: s.wallet, - abi: v4.abis.wallet, + abi: v5.abis.wallet, functionName: 'checkpointCount', }); return original(params, options); @@ -457,7 +457,7 @@ describe('internal prepared SVM backend on v4', () => { } const stored = await h.publicClient.readContract({ address: h.addresses.rulesPolicy, - abi: v4.abis.policy, + abi: v5.abis.policy, functionName: 'getSvmConfig', args: [before.configId, s.wallet], }); @@ -475,7 +475,7 @@ describe('internal prepared SVM backend on v4', () => { expect( await h.publicClient.readContract({ address: s.wallet, - abi: v4.abis.wallet, + abi: v5.abis.wallet, functionName: 'checkpointCount', }) ).toBe(ticks); @@ -535,7 +535,7 @@ describe('internal prepared SVM backend on v4', () => { expect( await h.publicClient.readContract({ address: s.wallet, - abi: v4.abis.wallet, + abi: v5.abis.wallet, functionName: 'grantNonce', }) ).toBe(BigInt(2)); diff --git a/packages/core/__agw-local__/svm-differential.spec.ts b/packages/core/__agw-local__/svm-differential.spec.ts index 5dc93cfd..52026155 100644 --- a/packages/core/__agw-local__/svm-differential.spec.ts +++ b/packages/core/__agw-local__/svm-differential.spec.ts @@ -16,7 +16,7 @@ import { encodeAgwSvmPayload, validateAgwSvmPayload, } from '../src/lib/agentic/execution/svm-payload'; -import { v4 } from '../src/lib/agentic/contracts/v4'; +import { v5 } from '../src/lib/agentic/contracts/v5'; import { deriveAgwSvmValueAccounts } from '../src/lib/agentic/codec/svm-accounts'; import { decodeAgenticRevert } from '../src/lib/agentic/revert'; import { startHarness, type Harness } from './harness'; @@ -208,7 +208,7 @@ describe('seeded SVM differential validation', () => { try { await h.publicClient.call({ to: wallet, - data: v4.encodeGrantRules(session(c.terms)), + data: v5.encodeGrantRules(session(c.terms)), account: h.wallets[0].account!.address, }); } catch (e) { @@ -251,10 +251,10 @@ describe('seeded SVM differential validation', () => { den: BigInt(0), }, ]; - await h.write(0, wallet, v4.abis.wallet, 'grantRules', [session(t)]); + await h.write(0, wallet, v5.abis.wallet, 'grantRules', [session(t)]); const [id] = await h.publicClient.readContract({ address: h.addresses.engine, - abi: v4.abis.engine, + abi: v5.abis.engine, functionName: 'getPermissionIDs', args: [wallet], }); @@ -267,9 +267,9 @@ describe('seeded SVM differential validation', () => { }), }); await h.write(0, token, TOKEN, 'mint', [wallet, BigInt(100)]); - await h.write(0, wallet, v4.abis.wallet, 'execute', [ + await h.write(0, wallet, v5.abis.wallet, 'execute', [ key('00'), - v4.packSingle({ + v5.packSingle({ target: token, value: BigInt(0), data: encodeFunctionData({ @@ -370,12 +370,12 @@ describe('seeded SVM differential validation', () => { try { await h.publicClient.simulateContract({ address: wallet, - abi: v4.abis.wallet, + abi: v5.abis.wallet, functionName: 'executeAsAgent', args: [ id, key('00'), - v4.packSingle({ + v5.packSingle({ target: h.addresses.gateway, value: BigInt(11) * BigInt(10) ** BigInt(14), data, diff --git a/packages/core/__agw-local__/svm-internals.spec.ts b/packages/core/__agw-local__/svm-internals.spec.ts index 43bc6485..24163e4d 100644 --- a/packages/core/__agw-local__/svm-internals.spec.ts +++ b/packages/core/__agw-local__/svm-internals.spec.ts @@ -1,4 +1,4 @@ -/** Actual v4 SVM URP checks on Anvil. No Solana execution/TSS is simulated. */ +/** Actual v5 SVM URP checks on Anvil. No Solana execution/TSS is simulated. */ import { encodeFunctionData, parseAbi, type Address, type Hex } from 'viem'; import { CHAIN } from '../src/lib/constants/enums'; import { buildSession, encodeEnvelope } from '../src/lib/agentic/codec/session'; @@ -12,7 +12,7 @@ import { import { deriveAgwSvmValueAccounts } from '../src/lib/agentic/codec/svm-accounts'; import { encodeAgwSvmPayload } from '../src/lib/agentic/execution/svm-payload'; import { composeAgwSvmAction } from '../src/lib/agentic/execution/svm-outbound'; -import { v4, type SvmConfigRead } from '../src/lib/agentic/contracts/v4'; +import { v5, type SvmConfigRead } from '../src/lib/agentic/contracts/v5'; import { startHarness, type Harness } from './harness'; const key = (b: string) => `0x${b.repeat(32)}` as Hex; @@ -25,7 +25,7 @@ const TOKEN = parseAbi([ ]); const UINT256_MAX = BigInt(2) ** BigInt(256) - BigInt(1); -describe('internal SVM codec/payloads against actual v4 contracts', () => { +describe('internal SVM codec/payloads against actual v5 contracts', () => { let h: Harness, token: Address; beforeAll(async () => { h = await startHarness(18552); @@ -92,23 +92,23 @@ describe('internal SVM codec/payloads against actual v4 contracts', () => { }, ], }); - await h.write(0, wallet, v4.abis.wallet, 'grantRules', [session]); + await h.write(0, wallet, v5.abis.wallet, 'grantRules', [session]); const [id] = await h.publicClient.readContract({ address: h.addresses.engine, - abi: v4.abis.engine, + abi: v5.abis.engine, functionName: 'getPermissionIDs', args: [wallet], }); const [action] = await h.publicClient.readContract({ address: h.addresses.engine, - abi: v4.abis.engine, + abi: v5.abis.engine, functionName: 'getEnabledActions', args: [wallet, id], }); const cid = configId(wallet, id, action); const cfg = (await h.publicClient.readContract({ address: h.addresses.rulesPolicy, - abi: v4.abis.policy, + abi: v5.abis.policy, functionName: 'getSvmConfig', args: [cid, wallet], })) as SvmConfigRead; @@ -121,9 +121,9 @@ describe('internal SVM codec/payloads against actual v4 contracts', () => { }), }); await h.write(0, token, TOKEN, 'mint', [wallet, BigInt(100)]); - await h.write(0, wallet, v4.abis.wallet, 'execute', [ + await h.write(0, wallet, v5.abis.wallet, 'execute', [ key('00'), - v4.packSingle({ + v5.packSingle({ target: token, value: BigInt(0), data: encodeFunctionData({ @@ -175,12 +175,12 @@ describe('internal SVM codec/payloads against actual v4 contracts', () => { }); return h.publicClient.simulateContract({ address: wallet, - abi: v4.abis.wallet, + abi: v5.abis.wallet, functionName: 'executeAsAgent', args: [ id, key('00'), - v4.packSingle({ + v5.packSingle({ target: h.addresses.gateway, value: call.value, data, @@ -242,14 +242,14 @@ describe('internal SVM codec/payloads against actual v4 contracts', () => { }); it('the internal composed call passes actual S1–S18 and meters its token', async () => { const { wallet, id, cid, call } = await setup(); - await h.write(1, wallet, v4.abis.wallet, 'executeAsAgent', [ + await h.write(1, wallet, v5.abis.wallet, 'executeAsAgent', [ id, key('00'), - v4.packSingle(call), + v5.packSingle(call), ]); const cfg = await h.publicClient.readContract({ address: h.addresses.rulesPolicy, - abi: v4.abis.policy, + abi: v5.abis.policy, functionName: 'getSvmConfig', args: [cid, wallet], }); @@ -319,7 +319,7 @@ describe('internal SVM codec/payloads against actual v4 contracts', () => { ); const cfg = await h.publicClient.readContract({ address: h.addresses.rulesPolicy, - abi: v4.abis.policy, + abi: v5.abis.policy, functionName: 'getSvmConfig', args: [s.cid, s.wallet], }); diff --git a/packages/core/__agw-local__/svm-public.spec.ts b/packages/core/__agw-local__/svm-public.spec.ts index 522ed560..1e8c423d 100644 --- a/packages/core/__agw-local__/svm-public.spec.ts +++ b/packages/core/__agw-local__/svm-public.spec.ts @@ -8,9 +8,9 @@ import { type Address, type Hex, } from 'viem'; -import { CHAIN, PushChain, type SolanaRule } from '../src'; +import { CHAIN, PushChain, AgenticRevertError, type SolanaRule } from '../src'; import type { AgenticRuntime } from '../src/lib/agentic/runtime'; -import { v4 } from '../src/lib/agentic/contracts/v4'; +import { v5 } from '../src/lib/agentic/contracts/v5'; import { clearRegistry } from '../src/lib/orchestrator/svm-idl/registry'; import { startHarness, type Harness } from './harness'; const program = new PublicKey(Buffer.alloc(32, 51)).toBase58(); @@ -35,7 +35,7 @@ const TOKEN = parseAbi([ const CORE = parseAbi(['function setGasToken(string,address)']); const rt = (c: PushChain) => (c as unknown as { agenticRuntime: AgenticRuntime }).agenticRuntime; -describe('public Solana IDL rules on actual v4', () => { +describe('public Solana IDL rules on actual v5', () => { let h: Harness, owner: PushChain, token: Address; beforeAll(async () => { h = await startHarness(18561); @@ -119,9 +119,9 @@ describe('public Solana IDL rules on actual v4', () => { }), }); await h.write(0, token, TOKEN, 'mint', [made.wallet, BigInt(20)]); - await h.write(0, made.wallet, v4.abis.wallet, 'execute', [ + await h.write(0, made.wallet, v5.abis.wallet, 'execute', [ `0x${'00'.repeat(32)}`, - v4.packSingle({ + v5.packSingle({ target: token, value: BigInt(0), data: encodeFunctionData({ @@ -170,7 +170,10 @@ describe('public Solana IDL rules on actual v4', () => { data: data(BigInt(6)), value: BigInt(5), }) - ).rejects.toThrow('SvmDataCeilingExceeded'); + ).rejects.toMatchObject({ + name: 'AgenticRevertError', + decodedError: { name: 'PolicyCheckReverted(SvmDataCeilingExceeded)' }, + }); }); it('owner sends use the wallet CEA without requiring an agent rule', async () => { const made = await owner.agentic.create('svm-owner', { rules: [] }); @@ -199,6 +202,133 @@ describe('public Solana IDL rules on actual v4', () => { .status ).toBe('success'); }); + it('owner funds-only sends use an empty payload and preserve transfer metadata in replay', async () => { + const made = await owner.agentic.create('svm-owner-transfer', { + rules: [], + }); + await h.publicClient.waitForTransactionReceipt({ + hash: await h.wallets[4].sendTransaction({ + to: made.wallet, + value: BigInt(10) ** BigInt(18), + account: h.wallets[4].account!, + chain: h.wallets[4].chain, + }), + }); + await h.write(0, token, TOKEN, 'mint', [made.wallet, BigInt(10)]); + await h.write(0, made.wallet, v5.abis.wallet, 'execute', [ + `0x${'00'.repeat(32)}`, + v5.packSingle({ + target: token, + value: BigInt(0), + data: encodeFunctionData({ + abi: TOKEN, + functionName: 'approve', + args: [h.addresses.gateway, BigInt(10)], + }), + }), + ]); + const sender = await h.client(0, { agenticWallet: made.wallet }); + configure(sender); + clearRegistry(); // A simple transfer needs no program IDL. + const tx = await sender.universal.sendTransaction({ + to: { chain: CHAIN.SOLANA_DEVNET, address: program }, + value: BigInt(5), + }); + expect(tx.to).toBe('0x' + Buffer.alloc(32, 51).toString('hex')); + expect(tx.value).toBe(BigInt(5)); + expect(tx.agentic?.destinationInstruction).toBeUndefined(); + expect(tx.agentic?.destinationTransfer).toMatchObject({ + token, + amount: BigInt(5), + }); + const raw: typeof tx = { + ...tx, + agentic: undefined, + from: tx.raw!.from, + to: tx.raw!.to, + data: tx.raw!.data, + route: 'UOA_TO_PUSH', + }; + const { adaptTrackedResponse } = await import( + '../src/lib/agentic/response' + ); + await adaptTrackedResponse(rt(sender), raw); + expect(raw.to).toBe(tx.to); + expect(raw.data).toBe('0x'); + expect(raw.value).toBe(BigInt(5)); + expect(raw.agentic?.destinationTransfer).toEqual( + tx.agentic?.destinationTransfer + ); + expect(raw.route).toBe('UOA_TO_CEA'); + const baseReader = rt(sender).reader; + const unavailable = { + ...baseReader, + readContract: async ( + params: Parameters[0] + ) => { + if (params.functionName === 'gasTokenPRC20ByChainNamespace') + throw new Error('historical metadata unavailable'); + return baseReader.readContract(params); + }, + }; + const fallback: typeof tx = { + ...tx, + agentic: undefined, + from: tx.raw!.from, + to: tx.raw!.to, + data: tx.raw!.data, + route: 'UOA_TO_PUSH', + }; + await adaptTrackedResponse( + { network: rt(sender).network, reader: unavailable }, + fallback + ); + expect(fallback.route).toBe('UOA_TO_CEA'); + expect(fallback.agentic?.destinationTransfer).toBeUndefined(); + + expect( + (await h.publicClient.getTransactionReceipt({ hash: tx.hash as Hex })) + .status + ).toBe('success'); + }); + it('actual policy refusals return mapped contract errors and preserve counters', async () => { + const made = await owner.agentic.create('svm-policy-errors', { + rules: [rule()], + }); + await h.publicClient.waitForTransactionReceipt({ + hash: await h.wallets[4].sendTransaction({ + to: made.wallet, + value: BigInt(10) ** BigInt(18), + account: h.wallets[4].account!, + chain: h.wallets[4].chain, + }), + }); + const agent = await h.client(1, { agenticWallet: made.wallet }); + configure(agent); + const handle = owner.agentic.wallet(made.wallet), + before = await handle.rules.get(made.rulesIds[0]); + const error = await agent.universal + .sendTransaction({ + to: { chain: CHAIN.SOLANA_DEVNET, address: program }, + data: PushChain.utils.helpers.encodeTxData({ + abi: idl, + functionName: 'deposit', + args: [BigInt(6)], + }), + }) + .catch((e) => e); + expect(error).toBeInstanceOf(AgenticRevertError); + expect(error.decodedError.name).toBe( + 'PolicyCheckReverted(SvmDataCeilingExceeded)' + ); + expect(await handle.rules.get(made.rulesIds[0])).toEqual(before); + await expect( + agent.universal.sendTransaction({ + to: { chain: CHAIN.SOLANA_DEVNET, address: program }, + value: BigInt(1), + }) + ).rejects.toMatchObject({ code: 'INVALID_RULE' }); + }); it('SPL and output mints derive protected wallet ATAs through public grants', async () => { const mint = new PublicKey(Buffer.alloc(32, 68)).toBase58(); const output = new PublicKey(Buffer.alloc(32, 85)).toBase58(); @@ -258,6 +388,60 @@ describe('public Solana IDL rules on actual v4', () => { expect(read.rule.assets[0].maxTotal).toBe( BigInt(2) ** BigInt(256) - BigInt(1) ); + await h.publicClient.waitForTransactionReceipt({ + hash: await h.wallets[4].sendTransaction({ + to: made.wallet, + value: BigInt(10) ** BigInt(18), + account: h.wallets[4].account!, + chain: h.wallets[4].chain, + }), + }); + await h.write(0, spl, TOKEN, 'mint', [made.wallet, BigInt(10)]); + await h.write(0, made.wallet, v5.abis.wallet, 'execute', [ + `0x${'00'.repeat(32)}`, + v5.packSingle({ + target: spl, + value: BigInt(0), + data: encodeFunctionData({ + abi: TOKEN, + functionName: 'approve', + args: [h.addresses.gateway, BigInt(10)], + }), + }), + ]); + const sender = await h.client(0, { agenticWallet: made.wallet }); + Object.assign(rt(sender), { + svmMetadata: rt(source).svmMetadata, + resolvePrc20: rt(source).resolvePrc20, + quoteOutbound: rt(source).quoteOutbound, + }); + const quote = jest.spyOn(rt(sender), 'quoteOutbound'); + const tx = await sender.universal.sendTransaction({ + to: { chain: CHAIN.SOLANA_DEVNET, address: program }, + funds: { + token: { + address: mint, + symbol: 'MOCK', + decimals: 6, + mechanism: 'approve', + }, + amount: BigInt(5), + }, + }); + expect(tx.value).toBe(BigInt(0)); + expect(tx.agentic?.destinationTransfer).toMatchObject({ + token: spl, + amount: BigInt(5), + }); + expect(quote.mock.calls[0][3]).toMatchObject({ + wallet: made.wallet, + splMintBase58: mint, + burnAmount: BigInt(5), + }); + expect( + (await h.publicClient.getTransactionReceipt({ hash: tx.hash as Hex })) + .status + ).toBe('success'); }); it('invalid named input and removed ref never submit a transaction', async () => { const before = await h.publicClient.getTransactionCount({ @@ -279,4 +463,66 @@ describe('public Solana IDL rules on actual v4', () => { }) ).toBe(before); }); + it('the contract rejects an outbound above its PC cap through the same error mapper', async () => { + const input = rule(); + input.maxGasPerCall = BigInt(1); + const made = await owner.agentic.create('svm-pc-cap', { rules: [input] }); + await h.publicClient.waitForTransactionReceipt({ + hash: await h.wallets[4].sendTransaction({ + to: made.wallet, + value: BigInt(10) ** BigInt(18), + account: h.wallets[4].account!, + chain: h.wallets[4].chain, + }), + }); + const agent = await h.client(1, { agenticWallet: made.wallet }); + configure(agent); + const error = await agent.universal + .sendTransaction({ + to: { chain: CHAIN.SOLANA_DEVNET, address: program }, + data: PushChain.utils.helpers.encodeTxData({ + abi: idl, + functionName: 'deposit', + args: [BigInt(0)], + }), + }) + .catch((e) => e); + expect(error).toBeInstanceOf(AgenticRevertError); + expect(error.decodedError.name).toBe( + 'PolicyCheckReverted(PCValueExceedsCap)' + ); + }); + it('expired SVM permissions are refused by the actual contract rather than a local policy check', async () => { + const input = rule(); + input.validUntil = + Number((await h.publicClient.getBlock()).timestamp) + 120; + const made = await owner.agentic.create('svm-expired', { rules: [input] }); + await h.publicClient.waitForTransactionReceipt({ + hash: await h.wallets[4].sendTransaction({ + to: made.wallet, + value: BigInt(10) ** BigInt(18), + account: h.wallets[4].account!, + chain: h.wallets[4].chain, + }), + }); + const agent = await h.client(1, { agenticWallet: made.wallet }); + configure(agent); + await h.publicClient.request({ + method: 'evm_setNextBlockTimestamp' as never, + params: [input.validUntil + 1] as never, + }); + await h.publicClient.request({ method: 'evm_mine' as never }); + const error = await agent.universal + .sendTransaction({ + to: { chain: CHAIN.SOLANA_DEVNET, address: program }, + data: PushChain.utils.helpers.encodeTxData({ + abi: idl, + functionName: 'deposit', + args: [BigInt(0)], + }), + }) + .catch((e) => e); + expect(error).toBeInstanceOf(AgenticRevertError); + expect(error.decodedError.name).toBe('PolicyCheckReverted(RulesExpired)'); + }); }); diff --git a/packages/core/__agw-local__/v4-multiasset.spec.ts b/packages/core/__agw-local__/v5-multiasset.spec.ts similarity index 98% rename from packages/core/__agw-local__/v4-multiasset.spec.ts rename to packages/core/__agw-local__/v5-multiasset.spec.ts index d5ba28af..0d5f04fe 100644 --- a/packages/core/__agw-local__/v4-multiasset.spec.ts +++ b/packages/core/__agw-local__/v5-multiasset.spec.ts @@ -1,4 +1,4 @@ -/** Actual v4 AGW/URP/engine. Token/core/gateway and destination lookup are local fixtures; no bridge/TSS proof. */ +/** Actual v5 AGW/URP/engine. Token/core/gateway and destination lookup are local fixtures; no bridge/TSS proof. */ import { encodeFunctionData, getAddress, @@ -33,7 +33,7 @@ const DEST = getAddress('0x0000000000000000000000000000000000001234'); const internal = (c: PushChain) => (c as unknown as { agenticRuntime: AgenticRuntime }).agenticRuntime; -describe('v4 multi-asset SDK management and execution', () => { +describe('v5 multi-asset SDK management and execution', () => { let h: Harness, owner: PushChain, a: Address, b: Address; beforeAll(async () => { h = await startHarness(18551); @@ -84,7 +84,7 @@ describe('v4 multi-asset SDK management and execution', () => { }; } async function setup(input = rule()) { - const created = await owner.agentic.create('v4', { rules: [input] }); + const created = await owner.agentic.create('v5', { rules: [input] }); const wallet = created.wallet, id = created.rulesIds[0]; await h.publicClient.waitForTransactionReceipt({ @@ -317,7 +317,7 @@ describe('v4 multi-asset SDK management and execution', () => { }) ).rejects.toMatchObject({ code: 'AMBIGUOUS_RULE' }); }); - it('a legacy two-field envelope is refused by the actual v4 grant path', async () => { + it('a legacy two-field envelope is refused by the actual v5 grant path', async () => { const bare = await owner.agentic.create('old-envelope', { rules: [] }); const { encodeAbiParameters } = await import('viem'); const terms = nativeRuleToTerms( diff --git a/packages/core/__agw-local__/vectors.spec.ts b/packages/core/__agw-local__/vectors.spec.ts index d8e2cf57..ed603c0d 100644 --- a/packages/core/__agw-local__/vectors.spec.ts +++ b/packages/core/__agw-local__/vectors.spec.ts @@ -3,7 +3,7 @@ * below is computed BY THE PINNED CONTRACTS (pure engine/factory views, or * state read back after a real grant), never by the SDK under test. * - * AGW_WRITE_VECTORS=1 → (re)write src/lib/agentic/__fixtures__/v4-vectors.json + * AGW_WRITE_VECTORS=1 → (re)write src/lib/agentic/__fixtures__/v5-vectors.json * otherwise → assert the committed file still matches the contracts */ import { execSync } from 'node:child_process'; @@ -30,7 +30,7 @@ const FIXTURE = join( 'lib', 'agentic', '__fixtures__', - 'v4-vectors.json' + 'v5-vectors.json' ); const bigintJson = (v: unknown) => JSON.stringify( @@ -39,7 +39,7 @@ const bigintJson = (v: unknown) => 2 ); -describe('contract-generated AGW vectors (v4)', () => { +describe('contract-generated AGW vectors (v5)', () => { let h: Harness; beforeAll(async () => { h = await startHarness(18548); diff --git a/packages/core/__e2e__/agw-svm-wire/outbound.spec.ts b/packages/core/__e2e__/agw-svm-wire/outbound.spec.ts index c4dd168d..67359498 100644 --- a/packages/core/__e2e__/agw-svm-wire/outbound.spec.ts +++ b/packages/core/__e2e__/agw-svm-wire/outbound.spec.ts @@ -1,4 +1,4 @@ -/** Internal wire acceptance only. Public Solana Rule/send capability stays disabled. */ +/** Internal wire acceptance alongside public Solana coverage. Policy refusals come from URP simulation. */ import '@e2e/shared/setup'; import { PushChain } from '../../src'; import { Keypair, PublicKey, type ParsedTransactionWithMeta } from '@solana/web3.js'; @@ -18,7 +18,7 @@ import { sendSvmAgentWire, prepareSvmAgentExecution, type PreparedSvmRequest } f import { SvmDataPinMode, type SvmTermsWire } from '../../src/lib/agentic/codec/svm-terms'; import { svmKey } from '../../src/lib/agentic/codec/svm-accounts'; import { adaptTrackedResponse } from '../../src/lib/agentic/response'; -import { v4 } from '../../src/lib/agentic/contracts/v4'; +import { v5 } from '../../src/lib/agentic/contracts/v5'; import { setupAgw, evmClient, inSeconds, type AgwFixture } from '../agw/_fixture'; import { loadAgwManifest, verifyAgwManifest } from '../agw/_manifest'; import { inspectSvmWirePrograms, svmWireConnection, SVM_WIRE_CHAIN, SVM_WIRE_GATEWAY, SVM_WIRE_PROGRAM, SVM_WIRE_COUNTER, decodeWireCounter } from '../shared/agw-svm-preflight'; @@ -112,7 +112,7 @@ d('agw svm wire', () => { it('1. positive outbound: actual CEA transfer and counter execution, receipt and replay', async () => { const before = decodeWireCounter((await sol.getAccountInfo(SVM_WIRE_COUNTER))!.data).value; - const count = await f.push.readContract({ address: wallet, abi: v4.abis.wallet, functionName: 'checkpointCount' }); + const count = await f.push.readContract({ address: wallet, abi: v5.abis.wallet, functionName: 'checkpointCount' }); const { tx } = await sendSvmAgentWire(rt(agent), gen, request(), metadata); f.evidence('svm-wire-positive-submitted', { wallet, rulesId, hash: tx.hash }); // Existing verified-wallet replay adaptation enables normal outbound wait; @@ -132,7 +132,7 @@ d('agw svm wire', () => { ))).toBe(true); expect(decodeWireCounter((await sol.getAccountInfo(SVM_WIRE_COUNTER))!.data).value).toBeGreaterThanOrEqual(before + AMOUNT); expect((await stored()).config.assets[0].spent).toBe(AMOUNT); - expect(await f.push.readContract({ address: wallet, abi: v4.abis.wallet, functionName: 'checkpointCount' })).toBe(count); + expect(await f.push.readContract({ address: wallet, abi: v5.abis.wallet, functionName: 'checkpointCount' })).toBe(count); const replay = await f.owner.universal.trackTransaction(tx.hash); expect(replay.from).toBe(wallet); expect(replay.route).toBe('UOA_TO_CEA'); expect(replay.agentic).toMatchObject({ door: 'agent', rulesId }); @@ -145,8 +145,8 @@ d('agw svm wire', () => { const base = request(); const wrong = [...base.accounts!]; wrong[2] = { ...wrong[2], pubkey: svmKey(recipient.toBase58()) }; const nonce = await f.push.getTransactionCount({ address: f.agentAddress }); - await expect(prepareSvmAgentExecution(rt(agent), gen, { ...base, accounts: wrong }, metadata)).rejects.toThrow(); - await expect(prepareSvmAgentExecution(rt(agent), gen, { ...base, instructionData: ixData(RECEIVE, AMOUNT + BigInt(1)) }, metadata)).rejects.toThrow(); + await expect(sendSvmAgentWire(rt(agent), gen, { ...base, accounts: wrong }, metadata)).rejects.toMatchObject({ name: 'AgenticRevertError', decodedError: { name: 'PolicyCheckReverted(SvmAccountPinMismatch)' } }); + await expect(sendSvmAgentWire(rt(agent), gen, { ...base, instructionData: ixData(RECEIVE, AMOUNT + BigInt(1)) }, metadata)).rejects.toMatchObject({ name: 'AgenticRevertError', decodedError: { name: 'PolicyCheckReverted(SvmDataCeilingExceeded)' } }); const prepared = await prepareSvmAgentExecution(rt(agent), gen, base, metadata); const policy = await probeSvmWirePolicies(f.push, { from: f.agentAddress, wallet, rulesId, call: prepared.call, blockNumber: await f.push.getBlockNumber() }); expect(await f.push.getTransactionCount({ address: f.agentAddress })).toBe(nonce); diff --git a/packages/core/__e2e__/agw-svm-wire/replay.spec.ts b/packages/core/__e2e__/agw-svm-wire/replay.spec.ts index d0009036..3ea2196c 100644 --- a/packages/core/__e2e__/agw-svm-wire/replay.spec.ts +++ b/packages/core/__e2e__/agw-svm-wire/replay.spec.ts @@ -3,7 +3,7 @@ import { PushChain } from '../../src'; import { createPublicClient, http, type Hex } from 'viem'; import { CHAIN_INFO, getPushViemChain } from '../../src/lib/constants/chain'; import { CHAIN, PUSH_NETWORK } from '../../src/lib/constants/enums'; -import { v4 } from '../../src/lib/agentic/contracts/v4'; +import { v5 } from '../../src/lib/agentic/contracts/v5'; import { chainReaderFromPublicClient } from '../../src/lib/agentic/contracts/reader'; import { resolveWalletGeneration } from '../../src/lib/agentic/deployments'; import { Snapshot } from '../../src/lib/agentic/reads/snapshot'; @@ -18,11 +18,11 @@ const EXTERNAL = 'kGUaPUfASg9Poo93aMsztHJjUk27MKuRJBfDZK1WP3FFSaXSYcoPcxjUMFyDxa d('agw svm recorded replay', () => { const push = createPublicClient({ chain: getPushViemChain(CHAIN.PUSH_TESTNET_DONUT), transport: http(CHAIN_INFO[CHAIN.PUSH_TESTNET_DONUT].defaultRPC[0]) }); let source: Awaited>; - let decoded: Extract>, { kind: 'executeAsAgent' }>; + let decoded: Extract>, { kind: 'executeAsAgent' }>; let client: PushChain; beforeAll(async () => { source = await push.getTransaction({ hash: POSITIVE }); - const call = v4.decodeWalletCall(source.input); + const call = v5.decodeWalletCall(source.input); if (!source.to || call?.kind !== 'executeAsAgent') throw new Error('Recorded fixture is not an AGW agent call'); decoded = call; client = await PushChain.initialize({ chain: PushChain.CONSTANTS.CHAIN.PUSH_TESTNET_DONUT, address: source.from }, { network: PUSH_NETWORK.TESTNET_DONUT }); diff --git a/packages/core/__e2e__/agw/_fixture.ts b/packages/core/__e2e__/agw/_fixture.ts index 4cf7b6e4..649ccbb2 100644 --- a/packages/core/__e2e__/agw/_fixture.ts +++ b/packages/core/__e2e__/agw/_fixture.ts @@ -48,6 +48,9 @@ const pushChainFor = (network: PUSH_NETWORK) => */ export async function setupAgw(): Promise { const manifest = loadAgwManifest(); + if (manifest.network !== PUSH_NETWORK.TESTNET_DONUT) { + throw new AgwPrerequisiteError('live AGW fixtures require Donut'); + } const pushKey = process.env['PUSH_PRIVATE_KEY'] as Hex | undefined; if (!pushKey) throw new AgwPrerequisiteError('PUSH_PRIVATE_KEY is not set'); const chain = pushChainFor(manifest.network); diff --git a/packages/core/__e2e__/agw/_manifest.ts b/packages/core/__e2e__/agw/_manifest.ts index e1be5691..d3dc1efc 100644 --- a/packages/core/__e2e__/agw/_manifest.ts +++ b/packages/core/__e2e__/agw/_manifest.ts @@ -1,12 +1,12 @@ /** * AGW deployment manifest for live E2E — READ-ONLY. Loaded from the JSON file - * optionally named by AGW_DEPLOYMENT_MANIFEST, otherwise the built-in Donut v4 + * optionally named by AGW_DEPLOYMENT_MANIFEST, otherwise the built-in Donut v5 * manifest. Code/wiring/version are verified before tests or preflight funding. * * Manifest shape: * { * "network": "TESTNET_DONUT", - * "generation": "v4", + * "generation": "v5", * "sourceCommit": "<40-hex AGW commit>", * "startBlock": "", * "accountId": "push.agw.1.0.0", @@ -16,24 +16,30 @@ * } */ import { readFileSync } from 'node:fs'; -import { getAddress, isAddress, type Address, type PublicClient } from 'viem'; +import { + getAddress, + isAddress, + type Address, + type PublicClient, + toFunctionSelector, +} from 'viem'; import { PUSH_NETWORK } from '../../src/lib/constants/enums'; import { AgenticCapability } from '../../src/lib/agentic/capabilities'; -import { V4_CAPABILITIES } from '../../src/lib/agentic/deployments'; -import { v4 } from '../../src/lib/agentic/contracts/v4'; +import { V5_CAPABILITIES } from '../../src/lib/agentic/deployments'; +import { v5 } from '../../src/lib/agentic/contracts/v5'; import { - DONUT_V4_ADDRESSES, - DONUT_V4_START_BLOCK, - V4_SOURCE_COMMIT, -} from '../../src/lib/agentic/contracts/donut-v4'; + DONUT_V5_ADDRESSES, + DONUT_V5_START_BLOCK, + V5_SOURCE_COMMIT, +} from '../../src/lib/agentic/contracts/donut-v5'; export const AGW_PREREQ_HINT = - 'AGW live E2E needs checked v4 wiring, signer keys and testnet funding. ' + - 'The default is the checked Donut v4 manifest; custom manifests must match the v4 source.'; + 'AGW live E2E needs checked v5 wiring, signer keys and testnet funding. ' + + 'The default is the checked Donut v5 manifest; custom manifests must match the v5 source.'; export interface AgwManifest { network: PUSH_NETWORK; - generation: 'v4'; + generation: 'v5'; sourceCommit: string; startBlock: bigint; accountId: string; @@ -61,12 +67,12 @@ export function loadAgwManifest( if (!path) return { network: PUSH_NETWORK.TESTNET_DONUT, - generation: 'v4', - sourceCommit: V4_SOURCE_COMMIT, - startBlock: DONUT_V4_START_BLOCK, + generation: 'v5', + sourceCommit: V5_SOURCE_COMMIT, + startBlock: DONUT_V5_START_BLOCK, accountId: 'push.agw.1.0.0', - addresses: DONUT_V4_ADDRESSES, - capabilities: V4_CAPABILITIES, + addresses: DONUT_V5_ADDRESSES, + capabilities: V5_CAPABILITIES, }; let raw: Record; try { @@ -79,14 +85,14 @@ export function loadAgwManifest( const network = raw['network'] as PUSH_NETWORK; if (!Object.values(PUSH_NETWORK).includes(network)) throw new AgwPrerequisiteError(`unknown network ${String(network)}`); - if (raw['generation'] !== v4.id) { + if (raw['generation'] !== v5.id) { throw new AgwPrerequisiteError( `generation ${String(raw['generation'])} has no SDK adapter` ); } - if (raw['sourceCommit'] !== V4_SOURCE_COMMIT) { + if (raw['sourceCommit'] !== V5_SOURCE_COMMIT) { throw new AgwPrerequisiteError( - 'sourceCommit must match the supported v4 source pin' + 'sourceCommit must match the supported v5 source pin' ); } const a = (raw['addresses'] ?? {}) as Record; @@ -105,15 +111,15 @@ export function loadAgwManifest( const caps = Array.isArray(raw['capabilities']) ? new Set( (raw['capabilities'] as string[]).map((c) => { - if (!V4_CAPABILITIES.has(c as AgenticCapability)) + if (!V5_CAPABILITIES.has(c as AgenticCapability)) throw new AgwPrerequisiteError(`unknown capability ${c}`); return c as AgenticCapability; }) ) - : V4_CAPABILITIES; + : V5_CAPABILITIES; return { network, - generation: 'v4', + generation: 'v5', sourceCommit: raw['sourceCommit'], startBlock: BigInt(String(raw['startBlock'] ?? '0')), accountId: String(raw['accountId'] ?? 'push.agw.1.0.0'), @@ -148,7 +154,7 @@ export async function verifyAgwManifest( const impl = getAddress( (await read( m.addresses.factory, - v4.abis.factory, + v5.abis.factory, 'walletImplementation' )) as string ); @@ -157,6 +163,18 @@ export async function verifyAgwManifest( `factory implementation is ${impl}, manifest says ${m.addresses.walletImplementation}` ); } + const implementationCode = await client.getCode({ address: impl }); + for (const signature of [ + 'label()', + 'setLabel(string)', + 'initializeAccount(string)', + ]) { + if (!implementationCode?.includes(toFunctionSelector(signature).slice(2))) { + throw new AgwPrerequisiteError( + `implementation is missing the v5 ${signature} selector` + ); + } + } const wiring: [string, Address][] = [ ['SESSION_ENGINE', m.addresses.sessionEngine], ['RULES_POLICY', m.addresses.rulesPolicy], @@ -164,7 +182,7 @@ export async function verifyAgwManifest( ['UNIVERSAL_GATEWAY_PC', m.addresses.gateway], ]; for (const [fn, expected] of wiring) { - const got = getAddress((await read(impl, v4.abis.wallet, fn)) as string); + const got = getAddress((await read(impl, v5.abis.wallet, fn)) as string); if (got !== expected) throw new AgwPrerequisiteError( `implementation ${fn} is ${got}, manifest says ${expected}` @@ -172,14 +190,14 @@ export async function verifyAgwManifest( } const policyVersion = await read( m.addresses.rulesPolicy, - v4.abis.policy, + v5.abis.policy, 'version' ); if (policyVersion !== '3.1.0') throw new AgwPrerequisiteError( `unsupported URP version ${String(policyVersion)}` ); - const accountId = (await read(impl, v4.abis.wallet, 'accountId')) as string; + const accountId = (await read(impl, v5.abis.wallet, 'accountId')) as string; if (accountId !== m.accountId) throw new AgwPrerequisiteError(`implementation accountId is ${accountId}`); } diff --git a/packages/core/__e2e__/agw/create.spec.ts b/packages/core/__e2e__/agw/create.spec.ts index 5e778af3..177f7201 100644 --- a/packages/core/__e2e__/agw/create.spec.ts +++ b/packages/core/__e2e__/agw/create.spec.ts @@ -4,7 +4,7 @@ * it is missing so a selected run cannot pass vacuously. */ import { getAddress, type Address } from 'viem'; -import { v4 } from '../../src/lib/agentic/contracts/v4'; +import { v5 } from '../../src/lib/agentic/contracts/v5'; import { AGW_E2E_ENABLED, inSeconds, @@ -27,7 +27,7 @@ d('agw create', () => { expect(created.wallet).toBe(before.address); expect(created.index).toBe(before.index); expect(created.rulesIds).toEqual([]); - const factoryAbi = v4.abis.factory; + const factoryAbi = v5.abis.factory; const [ownerOf, indexOf, balance] = await Promise.all([ f.push.readContract({ address: f.manifest.addresses.factory, diff --git a/packages/core/__e2e__/agw/labels.spec.ts b/packages/core/__e2e__/agw/labels.spec.ts new file mode 100644 index 00000000..8940c1ea --- /dev/null +++ b/packages/core/__e2e__/agw/labels.spec.ts @@ -0,0 +1,461 @@ +/** Public SDK labels against checked Donut v5; fresh wallets only. */ +import { + decodeEventLog, + createWalletClient, + http, + getAddress, + parseEther, + type Address, + type Hex, +} from 'viem'; +import { Keypair } from '@solana/web3.js'; +import bs58 from 'bs58'; +import { CHAIN_INFO, getPushViemChain } from '../../src/lib/constants/chain'; +import { readNativeCounters } from '@e2e/shared/agw-state'; +import { privateKeyToAccount } from 'viem/accounts'; +import { PushChain } from '../../src'; +import { CHAIN } from '../../src/lib/constants/enums'; +import { v5, MODE_SINGLE } from '../../src/lib/agentic/contracts/v5'; +import { decodeAgenticRevert } from '../../src/lib/agentic/revert'; +import { + AGW_E2E_ENABLED, + evmClient, + inSeconds, + setupAgw, + type AgwFixture, +} from './_fixture'; + +const d = AGW_E2E_ENABLED ? describe : describe.skip; +d('agw labels', () => { + let f: AgwFixture; + beforeAll(async () => { + f = await setupAgw(); + }, 300_000); + afterAll(() => f?.teardown()); + const count = (address: Address) => + f.push.readContract({ + address, + abi: v5.abis.wallet, + functionName: 'checkpointCount', + }); + + it('1. default and custom deployment labels are stored and listed', async () => { + const empty = await f.owner.agentic.create('', { rules: [] }); + const custom = await f.owner.agentic.create('e2e-v5-custom', { rules: [] }); + expect((await f.owner.agentic.wallet(empty.wallet).info()).label).toBe( + `AGW ${empty.index + 1}` + ); + expect((await f.owner.agentic.wallet(custom.wallet).info()).label).toBe( + 'e2e-v5-custom' + ); + const { wallets } = await f.owner.agentic.list(); + expect(wallets.find((w) => w.address === empty.wallet)?.label).toBe( + `AGW ${empty.index + 1}` + ); + expect(wallets.find((w) => w.address === custom.wallet)?.label).toBe( + 'e2e-v5-custom' + ); + const renamed = await f.owner.agentic + .wallet(custom.wallet) + .setLabel('isolated-rename'); + expect((await f.owner.agentic.wallet(custom.wallet).info()).label).toBe( + 'isolated-rename' + ); + expect((await f.owner.agentic.wallet(empty.wallet).info()).label).toBe( + `AGW ${empty.index + 1}` + ); + expect(await count(empty.wallet)).toBe(BigInt(0)); + expect(await count(custom.wallet)).toBe(BigInt(1)); + f.evidence('v5-label-default-custom', { + wallets: [empty.wallet, custom.wallet], + indices: [empty.index, custom.index], + hashes: [empty.tx.hash, custom.tx.hash, renamed.hash], + }); + }); + + it('2. owner rename and empty reset update info/list, emit LabelSet and tick the owner door', async () => { + const made = await f.owner.agentic.create('before', { rules: [] }); + const w = f.owner.agentic.wallet(made.wallet), + before = await count(made.wallet), + hook = jest.fn(); + const tx = await w.setLabel('after', { progressHook: hook }); + const receipt = await tx.wait(); + const labels = receipt.logs.flatMap((log) => { + if (log.address.toLowerCase() !== made.wallet.toLowerCase()) return []; + try { + const ev = decodeEventLog({ + abi: v5.abis.wallet, + data: log.data, + topics: log.topics, + }); + return ev.eventName === 'LabelSet' ? [ev.args.label] : []; + } catch { + return []; + } + }); + expect(labels).toEqual(['after']); + expect((await w.info()).label).toBe('after'); + expect( + (await f.owner.agentic.list()).wallets.find( + (x) => x.address === made.wallet + )?.label + ).toBe('after'); + expect(await count(made.wallet)).toBe(before + BigInt(1)); + expect(hook).toHaveBeenCalledWith( + expect.objectContaining({ id: 'AGENTIC-TX-199-01' }) + ); + const reset = await w.setLabel(''); + expect((await w.info()).label).toBe(`AGW ${made.index + 1}`); + expect(await count(made.wallet)).toBe(before + BigInt(2)); + f.evidence('v5-label-rename-reset', { + wallet: made.wallet, + hashes: [tx.hash, reset.hash], + checkpointsBefore: before, + checkpointsAfter: await count(made.wallet), + }); + }); + + it('3. UTF-8 byte boundaries are accepted or rejected without changing wallet state', async () => { + const made = await f.owner.agentic.create('🙂'.repeat(16), { rules: [] }); + const w = f.owner.agentic.wallet(made.wallet); + await w.setLabel('a'.repeat(64)); + const before = await count(made.wallet), + next = await f.owner.agentic.derive(); + for (const label of ['a'.repeat(65), '🙂'.repeat(17)]) { + await expect(w.setLabel(label)).rejects.toMatchObject({ + code: 'INVALID_RULE', + }); + await expect( + f.owner.agentic.create(label, { rules: [] }) + ).rejects.toMatchObject({ code: 'INVALID_RULE' }); + await expect( + f.push.simulateContract({ + address: made.wallet, + abi: v5.abis.wallet, + functionName: 'setLabel', + args: [label], + account: f.ownerAddress, + }) + ).rejects.toThrow('LabelTooLong'); + } + expect(await f.owner.agentic.derive()).toEqual(next); + expect((await w.info()).label).toBe('a'.repeat(64)); + expect(await count(made.wallet)).toBe(before); + f.evidence('v5-label-byte-boundary', { + wallet: made.wallet, + checkpoints: before, + unchangedNextSlot: next.index, + }); + }); + + it('4. an agent cannot rename through either the SDK or the contract', async () => { + const made = await f.owner.agentic.create('owner-only', { + rules: [ + { + agent: f.agentAddress, + target: f.ownerAddress, + selector: 'value-only', + validUntil: inSeconds(3600), + }, + ], + }); + const before = await count(made.wallet); + const agent = await f.agent(made.wallet); + await expect( + agent.agentic.wallet(made.wallet).setLabel('attack') + ).rejects.toMatchObject({ code: 'NOT_WALLET_OWNER' }); + await expect( + f.push.simulateContract({ + address: made.wallet, + abi: v5.abis.wallet, + functionName: 'setLabel', + args: ['attack'], + account: f.agentAddress, + }) + ).rejects.toThrow('CallerIsNotOwner'); + const agentDoorError = await f.push + .simulateContract({ + address: made.wallet, + abi: v5.abis.wallet, + functionName: 'executeAsAgent', + args: [ + made.rulesIds[0], + MODE_SINGLE, + v5.packSingle({ + target: made.wallet, + value: BigInt(0), + data: v5.encodeSetLabel('attack'), + }), + ], + account: f.agentAddress, + }) + .then( + () => undefined, + (error: unknown) => error + ); + // Normal grants cannot authorize wallet-self: the engine rejects the + // absent action policy before the wallet's additional dispatch guard. + expect(decodeAgenticRevert(agentDoorError)).toMatchObject({ + name: 'NoPoliciesSet', + }); + expect((await f.owner.agentic.wallet(made.wallet).info()).label).toBe( + 'owner-only' + ); + expect(await count(made.wallet)).toBe(before); + f.evidence('v5-label-agent-refused', { + wallet: made.wallet, + checkpoints: before, + }); + }); + + it('5. an external EVM owner creates and renames through its UEA', async () => { + const key = process.env['EVM_PRIVATE_KEY'] as Hex; + if (!key) throw new Error('EVM_PRIVATE_KEY is required'); + const origin = privateKeyToAccount(key).address; + const uea = getAddress( + ( + await PushChain.utils.account.deriveExecutorAccount( + PushChain.utils.account.toUniversal(origin, { + chain: CHAIN.ETHEREUM_SEPOLIA, + }), + { skipNetworkCheck: true } + ) + ).address + ); + await f.fundPC(uea, parseEther('3')); + const owner = await evmClient( + key, + CHAIN.ETHEREUM_SEPOLIA, + f.manifest.network + ); + const made = await owner.agentic.create('e2e-uea-before', { rules: [] }); + const w = owner.agentic.wallet(made.wallet); + expect((await w.owner()).owner).toBe(uea); + const before = await count(made.wallet); + const rename = await w.setLabel('e2e-uea-after'); + expect((await w.info()).label).toBe('e2e-uea-after'); + expect( + (await owner.agentic.list()).wallets.find( + (entry) => entry.address === made.wallet + )?.label + ).toBe('e2e-uea-after'); + const reset = await w.setLabel(''); + expect((await w.info()).label).toBe(`AGW ${made.index + 1}`); + expect(await count(made.wallet)).toBe(before + BigInt(2)); + f.evidence('v5-label-uea-owner', { + wallet: made.wallet, + owner: uea, + hashes: [made.tx.hash, rename.hash, reset.hash], + checkpointsBefore: before, + checkpointsAfter: await count(made.wallet), + }); + }); + it('6. a Solana-origin owner creates, renames and resets through its UEA', async () => { + const raw = process.env['SOLANA_PRIVATE_KEY']; + if (!raw) throw new Error('SOLANA_PRIVATE_KEY is required'); + let kp: Keypair; + try { + kp = Keypair.fromSecretKey(bs58.decode(raw)); + } catch { + kp = Keypair.fromSecretKey(Uint8Array.from(JSON.parse(raw))); + } + const uea = getAddress( + ( + await PushChain.utils.account.deriveExecutorAccount( + PushChain.utils.account.toUniversal(kp.publicKey.toBase58(), { + chain: CHAIN.SOLANA_DEVNET, + }), + { skipNetworkCheck: true } + ) + ).address + ); + await f.fundPC(uea, parseEther('3')); + const signer = await PushChain.utils.signer.toUniversalFromKeypair(kp, { + chain: CHAIN.SOLANA_DEVNET, + library: PushChain.CONSTANTS.LIBRARY.SOLANA_WEB3JS, + }); + const owner = await PushChain.initialize(signer, { + network: f.manifest.network, + }); + const made = await owner.agentic.create('', { rules: [] }); + const w = owner.agentic.wallet(made.wallet); + expect((await w.info()).label).toBe(`AGW ${made.index + 1}`); + expect((await w.owner()).owner).toBe(uea); + const before = await count(made.wallet); + const rename = await w.setLabel('Solana owner'); + expect((await w.info()).label).toBe('Solana owner'); + expect( + (await owner.agentic.list()).wallets.find( + (entry) => entry.address === made.wallet + )?.label + ).toBe('Solana owner'); + const reset = await w.setLabel(''); + expect((await w.info()).label).toBe(`AGW ${made.index + 1}`); + expect(await count(made.wallet)).toBe(before + BigInt(2)); + f.evidence('v5-label-solana-owner', { + wallet: made.wallet, + owner: uea, + hashes: [made.tx.hash, rename.hash, reset.hash], + checkpointsBefore: before, + checkpointsAfter: await count(made.wallet), + }); + }, 600_000); + + it('7. renaming an active wallet preserves rules, spend and remaining agent budget', async () => { + const made = await f.owner.agentic.create('active-before', { + rules: [ + { + agent: f.agentAddress, + target: f.ownerAddress, + selector: 'value-only', + validUntil: inSeconds(3600), + maxValuePerCall: BigInt(1), + maxValueTotal: BigInt(2), + maxCalls: 3, + }, + ], + }); + await f.fundPC(made.wallet, BigInt(10)); + const w = f.owner.agentic.wallet(made.wallet), + agent = await f.agent(made.wallet); + const first = await agent.universal.sendTransaction({ + to: f.ownerAddress, + value: BigInt(1), + }); + await first.wait(); + const ruleBefore = await w.rules.get(made.rulesIds[0]); + const spendBefore = await readNativeCounters( + f.push, + f.manifest.addresses, + made.wallet, + made.rulesIds[0] + ); + const checkpointsBefore = await count(made.wallet); + const nonceBefore = await f.push.readContract({ + address: made.wallet, + abi: v5.abis.wallet, + functionName: 'grantNonce', + }); + const rename = await w.setLabel('active-after'); + expect((await w.info()).label).toBe('active-after'); + expect(await w.rules.get(made.rulesIds[0])).toEqual(ruleBefore); + expect( + await readNativeCounters( + f.push, + f.manifest.addresses, + made.wallet, + made.rulesIds[0] + ) + ).toEqual(spendBefore); + expect( + await f.push.readContract({ + address: made.wallet, + abi: v5.abis.wallet, + functionName: 'grantNonce', + }) + ).toBe(nonceBefore); + expect(await count(made.wallet)).toBe(checkpointsBefore + BigInt(1)); + const second = await agent.universal.sendTransaction({ + to: f.ownerAddress, + value: BigInt(1), + }); + await second.wait(); + expect(second.agentic?.rulesId).toBe(made.rulesIds[0]); + const spendAfter = await readNativeCounters( + f.push, + f.manifest.addresses, + made.wallet, + made.rulesIds[0] + ); + expect(spendAfter).toMatchObject({ callsUsed: 2, valueSpent: BigInt(2) }); + const agentNonce = await f.push.getTransactionCount({ + address: f.agentAddress, + }); + await expect( + agent.universal.sendTransaction({ to: f.ownerAddress, value: BigInt(1) }) + ).rejects.toMatchObject({ + decodedError: { name: 'PolicyCheckReverted(TotalValueExceeded)' }, + }); + expect(await f.push.getTransactionCount({ address: f.agentAddress })).toBe( + agentNonce + ); + expect( + await readNativeCounters( + f.push, + f.manifest.addresses, + made.wallet, + made.rulesIds[0] + ) + ).toEqual(spendAfter); + expect(await count(made.wallet)).toBe(checkpointsBefore + BigInt(1)); + f.evidence('v5-label-active-rule', { + wallet: made.wallet, + rulesId: made.rulesIds[0], + hashes: [first.hash, rename.hash, second.hash], + spendBefore, + spendAfter, + grantNonce: nonceBefore, + }); + }); + + it('8. a failed owner batch rolls back the earlier rename and all checkpoints', async () => { + const made = await f.owner.agentic.create('batch-before', { rules: [] }); + const w = f.owner.agentic.wallet(made.wallet), + before = await count(made.wallet); + const key = process.env['PUSH_PRIVATE_KEY'] as Hex; + const owner = await evmClient( + key, + CHAIN.PUSH_TESTNET_DONUT, + f.manifest.network, + made.wallet + ); + const calls = [ + { + to: made.wallet, + value: BigInt(0), + data: v5.encodeSetLabel('temporary'), + }, + { + to: made.wallet, + value: BigInt(0), + data: v5.encodeSetLabel('a'.repeat(65)), + }, + ]; + await expect( + owner.universal.sendTransaction({ to: made.wallet, data: calls }) + ).rejects.toMatchObject({ decodedError: { name: 'LabelTooLong' } }); + expect((await w.info()).label).toBe('batch-before'); + // The SDK refuses this during simulation. A bounded raw transaction using + // the same SDK encoding additionally proves rollback in a mined receipt. + const client = createWalletClient({ + account: privateKeyToAccount(key), + chain: getPushViemChain(CHAIN.PUSH_TESTNET_DONUT), + transport: http(CHAIN_INFO[CHAIN.PUSH_TESTNET_DONUT].defaultRPC[0]), + }); + const hash = await client.sendTransaction({ + chain: client.chain, + to: made.wallet, + gas: BigInt(400_000), + data: v5.encodeExecute( + calls.map((call) => ({ + target: call.to, + value: call.value, + data: call.data, + })) + ), + }); + const receipt = await f.push.waitForTransactionReceipt({ hash }); + expect(receipt.status).toBe('reverted'); + expect(receipt.logs).toHaveLength(0); + expect((await w.info()).label).toBe('batch-before'); + expect(await count(made.wallet)).toBe(before); + f.evidence('v5-label-batch-rollback', { + wallet: made.wallet, + hash, + block: receipt.blockNumber, + gasUsed: receipt.gasUsed, + status: receipt.status, + checkpoints: before, + }); + }); +}); diff --git a/packages/core/__e2e__/agw/lifecycle.spec.ts b/packages/core/__e2e__/agw/lifecycle.spec.ts index 492143ff..105a5ea2 100644 --- a/packages/core/__e2e__/agw/lifecycle.spec.ts +++ b/packages/core/__e2e__/agw/lifecycle.spec.ts @@ -5,7 +5,7 @@ import { readNativeCounters } from '@e2e/shared/agw-state'; * The stale-spend race (intervening agent spend) is verified against the * real contracts in the local harness; it cannot be timed reliably live. */ -import { v4 } from '../../src/lib/agentic/contracts/v4'; +import { v5 } from '../../src/lib/agentic/contracts/v5'; import { getAddress, parseEther, type Address, type Hex } from 'viem'; import { AGENTIC_ERROR_CODE } from '../../src/lib/agentic/errors'; import { @@ -33,7 +33,7 @@ d('agw lifecycle', () => { const count = () => f.push.readContract({ address: wallet, - abi: v4.abis.wallet, + abi: v5.abis.wallet, functionName: 'checkpointCount', }) as Promise; diff --git a/packages/core/__e2e__/agw/management-extended.spec.ts b/packages/core/__e2e__/agw/management-extended.spec.ts index 1b2b6b05..6c5bb6b3 100644 --- a/packages/core/__e2e__/agw/management-extended.spec.ts +++ b/packages/core/__e2e__/agw/management-extended.spec.ts @@ -1,7 +1,7 @@ import { PushChain } from '../../src'; import { getAddress, type Address } from 'viem'; import type { AgenticRuntime } from '../../src/lib/agentic/runtime'; -import { v4 } from '../../src/lib/agentic/contracts/v4'; +import { v5 } from '../../src/lib/agentic/contracts/v5'; import { setupAgw, inSeconds, type AgwFixture } from './_fixture'; import { readNativeCounters } from '../shared/agw-state'; @@ -27,7 +27,7 @@ d('agw extended management', () => { const count = (wallet: Address) => f.push.readContract({ address: wallet, - abi: v4.abis.wallet, + abi: v5.abis.wallet, functionName: 'checkpointCount', }); it('1. prefunding a derived address survives deployment and info/list keep owner index and label', async () => { @@ -161,7 +161,7 @@ d('agw extended management', () => { const before = await count(made.wallet), grantNonce = await f.push.readContract({ address: made.wallet, - abi: v4.abis.wallet, + abi: v5.abis.wallet, functionName: 'grantNonce', }); rt.execute = async (params, opts) => { @@ -195,7 +195,7 @@ d('agw extended management', () => { expect( await f.push.readContract({ address: made.wallet, - abi: v4.abis.wallet, + abi: v5.abis.wallet, functionName: 'grantNonce', }) ).toBe(grantNonce); diff --git a/packages/core/__e2e__/agw/svm-public.spec.ts b/packages/core/__e2e__/agw/svm-public.spec.ts index fb2bcb00..79ff9089 100644 --- a/packages/core/__e2e__/agw/svm-public.spec.ts +++ b/packages/core/__e2e__/agw/svm-public.spec.ts @@ -19,6 +19,7 @@ import { privateKeyToAccount } from 'viem/accounts'; import { CHAIN, PUSH_NETWORK } from '../../src/lib/constants/enums'; import { CHAIN_INFO, getPushViemChain } from '../../src/lib/constants/chain'; import counterIdl from '../../src/lib/orchestrator/svm-idl/__fixtures__/test_counter.idl.json'; +import { v5 } from '../../src/lib/agentic/contracts/v5'; import { setupAgw, evmClient, inSeconds, type AgwFixture } from './_fixture'; import { loadAgwManifest, verifyAgwManifest } from './_manifest'; import { @@ -31,7 +32,7 @@ import { const d = process.env['AGW_E2E'] === '1' ? describe : describe.skip; const amount = BigInt(10_000), - pc = parseEther('21'); + pc = parseEther('41'); d('agw public svm', () => { let f: AgwFixture, wallet: Address, @@ -129,7 +130,8 @@ d('agw public svm', () => { abi: erc20Abi, functionName: 'balanceOf', args: [ownerAddress], - })) < amount + })) < + amount * BigInt(2) + BigInt(1) ) throw new Error('Insufficient bounded fixture funds'); idl = JSON.parse(JSON.stringify(counterIdl)) as Idl; @@ -153,7 +155,7 @@ d('agw public svm', () => { data: encodeFunctionData({ abi: erc20Abi, functionName: 'transfer', - args: [wallet, amount], + args: [wallet, amount * BigInt(2)], }), }) ).wait(); @@ -169,7 +171,7 @@ d('agw public svm', () => { data: encodeFunctionData({ abi: erc20Abi, functionName: 'approve', - args: [manifest.addresses.gateway, amount], + args: [manifest.addresses.gateway, amount * BigInt(2)], }), }) ).wait(); @@ -251,7 +253,44 @@ d('agw public svm', () => { instruction: tx.agentic?.destinationInstruction, }); }, 900_000); - it('3. substituted named accounts and excessive instruction amounts fail before signing', async () => { + it('3. contract simulation maps account and data refusals without state changes', async () => { + const config = PushChain.utils.agentic.configId( + wallet, + id, + PushChain.utils.agentic.actionId( + f.manifest.addresses.gateway, + '0x77b86bec' + ) + ); + const state = async () => { + const [tokens, pcBalance, checkpoints, cfg] = await Promise.all([ + f.push.readContract({ + address: token, + abi: erc20Abi, + functionName: 'balanceOf', + args: [wallet], + }), + f.push.getBalance({ address: wallet }), + f.push.readContract({ + address: wallet, + abi: v5.abis.wallet, + functionName: 'checkpointCount', + }), + f.push.readContract({ + address: f.manifest.addresses.rulesPolicy, + abi: v5.abis.policy, + functionName: 'getSvmConfig', + args: [config, wallet], + }), + ]); + return { + tokens, + pcBalance, + checkpoints, + spent: cfg.assets.map((a) => a.spent), + }; + }; + const before = await state(); const nonce = await f.push.getTransactionCount({ address: f.agentAddress }); const wrong = JSON.parse(JSON.stringify(idl)) as Idl; Object.assign( @@ -263,18 +302,33 @@ d('agw public svm', () => { await expect( agent.universal.sendTransaction({ to: { chain: SVM_WIRE_CHAIN, address: SVM_WIRE_PROGRAM }, + gasLimit: BigInt(0), data: data(BigInt(1), wrong), }) - ).rejects.toThrow('SvmAccountPinMismatch'); + ).rejects.toMatchObject({ + name: 'AgenticRevertError', + decodedError: { name: 'PolicyCheckReverted(SvmAccountPinMismatch)' }, + }); await expect( agent.universal.sendTransaction({ to: { chain: SVM_WIRE_CHAIN, address: SVM_WIRE_PROGRAM }, + gasLimit: BigInt(0), data: data(amount + BigInt(1)), }) - ).rejects.toThrow('SvmDataCeilingExceeded'); + ).rejects.toMatchObject({ + name: 'AgenticRevertError', + decodedError: { name: 'PolicyCheckReverted(SvmDataCeilingExceeded)' }, + }); expect(await f.push.getTransactionCount({ address: f.agentAddress })).toBe( nonce ); + expect(await state()).toEqual(before); + f.evidence('public-svm-contract-refusals', { + wallet, + id, + agentNonce: nonce, + state: before, + }); }); it('4. public revoke removes the Solana rule and subsequent sends are refused', async () => { const handle = f.owner.agentic.wallet(wallet); @@ -287,4 +341,105 @@ d('agw public svm', () => { }) ).rejects.toMatchObject({ code: 'NO_RULES_FOR_CHAIN' }); }); + it('5. owner funds-only transfer reaches the recipient and replays with the same amount', async () => { + const ownerKey = process.env['PUSH_PRIVATE_KEY'] as Hex; + const sender = await evmClient( + ownerKey, + CHAIN.PUSH_TESTNET_DONUT, + f.manifest.network, + wallet + ); + const before = await sol.getBalance(recipient); + const balance = await f.push.readContract({ + address: token, + abi: erc20Abi, + functionName: 'balanceOf', + args: [wallet], + }); + const tx = await sender.universal.sendTransaction({ + to: { chain: SVM_WIRE_CHAIN, address: recipient.toBase58() }, + value: amount, + gasLimit: BigInt(0), + }); + f.evidence('public-svm-owner-transfer-submitted', { + wallet, + hash: tx.hash, + }); + expect(tx.agentic?.door).toBe('owner'); + expect(tx.agentic?.rulesId).toBeUndefined(); + expect(tx.agentic?.destinationInstruction).toBeUndefined(); + expect(tx.agentic?.destinationTransfer).toMatchObject({ token, amount }); + const receipt = await tx.wait({ outboundTimeoutMs: 600_000 }); + expect(receipt.externalStatus).toBe('success'); + expect(receipt.from).toBe(wallet); + expect(await sol.getBalance(recipient)).toBe(before + Number(amount)); + expect( + await f.push.readContract({ + address: token, + abi: erc20Abi, + functionName: 'balanceOf', + args: [wallet], + }) + ).toBe(balance - amount); + const replay = await f.owner.universal.trackTransaction(tx.hash); + expect(replay.to).toBe(tx.to); + expect(replay.data).toBe('0x'); + expect(replay.value).toBe(amount); + expect(replay.agentic?.destinationTransfer).toEqual( + tx.agentic?.destinationTransfer + ); + expect( + (await replay.wait({ outboundTimeoutMs: 600_000 })).externalTxHash + ).toBe(receipt.externalTxHash); + f.evidence('public-svm-owner-transfer-delivered', { + wallet, + hash: tx.hash, + destinationHash: receipt.externalTxHash, + recipient: recipient.toBase58(), + amount, + }); + }, 900_000); + it('6. agents still require an instruction and owner allowance failures do not sign', async () => { + const agentNonce = await f.push.getTransactionCount({ + address: f.agentAddress, + }); + await expect( + agent.universal.sendTransaction({ + to: { chain: SVM_WIRE_CHAIN, address: recipient.toBase58() }, + value: amount, + }) + ).rejects.toMatchObject({ code: 'INVALID_RULE' }); + expect(await f.push.getTransactionCount({ address: f.agentAddress })).toBe( + agentNonce + ); + // Both funded sends have consumed the bounded allowance. Funding only the + // token lets this case isolate the separate allowance guard. + await ( + await f.owner.universal.sendTransaction({ + to: token, + data: encodeFunctionData({ + abi: erc20Abi, + functionName: 'transfer', + args: [wallet, BigInt(1)], + }), + }) + ).wait(); + const sender = await evmClient( + process.env['PUSH_PRIVATE_KEY'] as Hex, + CHAIN.PUSH_TESTNET_DONUT, + f.manifest.network, + wallet + ); + const nonce = await f.push.getTransactionCount({ address: f.ownerAddress }); + await expect( + sender.universal.sendTransaction({ + to: { chain: SVM_WIRE_CHAIN, address: recipient.toBase58() }, + value: BigInt(1), + gasLimit: BigInt(0), + }) + ).rejects.toMatchObject({ code: 'GATEWAY_ALLOWANCE_INSUFFICIENT' }); + expect(await f.push.getTransactionCount({ address: f.ownerAddress })).toBe( + nonce + ); + }); }); diff --git a/packages/core/__e2e__/agw/svm-spl-transfer.spec.ts b/packages/core/__e2e__/agw/svm-spl-transfer.spec.ts new file mode 100644 index 00000000..e35a1110 --- /dev/null +++ b/packages/core/__e2e__/agw/svm-spl-transfer.spec.ts @@ -0,0 +1,224 @@ +/** Funds-only SPL delivery through the public AGW owner path on Donut/devnet. */ +import '@e2e/shared/setup'; +import { Keypair, PublicKey } from '@solana/web3.js'; +import bs58 from 'bs58'; +import { encodeFunctionData, erc20Abi, parseEther, type Hex } from 'viem'; +import { CHAIN, PUSH_NETWORK } from '../../src/lib/constants/enums'; +import { MOVEABLE_TOKEN_CONSTANTS } from '../../src/lib/constants/tokens'; +import { getPRC20Address } from '../../src/lib/universal/prc20-address'; +import { v5 } from '../../src/lib/agentic/contracts/v5'; +import { + AGW_E2E_ENABLED, + evmClient, + setupAgw, + type AgwFixture, +} from './_fixture'; +import { loadAgwManifest } from './_manifest'; +import { + inspectSvmWirePrograms, + svmWireConnection, +} from '@e2e/shared/agw-svm-preflight'; + +const d = AGW_E2E_ENABLED ? describe : describe.skip; +const TOKEN_PROGRAM = new PublicKey( + 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA' +); +const ATA_PROGRAM = new PublicKey( + 'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL' +); +const amount = BigInt(1000); // 0.001 USDT; fixture funding is bounded to this. + +d('agw svm spl transfer', () => { + let f: AgwFixture; + beforeAll(async () => { + if (loadAgwManifest().network !== PUSH_NETWORK.TESTNET_DONUT) + throw new Error('SPL fixture requires Donut'); + await inspectSvmWirePrograms(svmWireConnection()); + f = await setupAgw(); + }, 300_000); + afterAll(() => f?.teardown()); + + it('1. owner funds-only SPL delivery credits the recipient ATA and preserves burn, allowance and replay', async () => { + const sol = svmWireConnection(), + raw = process.env['SOLANA_PRIVATE_KEY']; + if (!raw) throw new Error('SOLANA_PRIVATE_KEY is required'); + let kp: Keypair; + try { + kp = Keypair.fromSecretKey(bs58.decode(raw)); + } catch { + kp = Keypair.fromSecretKey(Uint8Array.from(JSON.parse(raw))); + } + const recipient = kp.publicKey, + asset = MOVEABLE_TOKEN_CONSTANTS.SOLANA_DEVNET.USDT; + const mint = new PublicKey(asset.address); + const mintInfo = await sol.getAccountInfo(mint); + if (!mintInfo?.owner.equals(TOKEN_PROGRAM)) + throw new Error('Fixture mint is not a standard SPL mint'); + const ata = PublicKey.findProgramAddressSync( + [recipient.toBuffer(), TOKEN_PROGRAM.toBuffer(), mint.toBuffer()], + ATA_PROGRAM + )[0]; + const recipientBalance = async () => { + const info = await sol.getAccountInfo(ata); + if (!info) return BigInt(0); + if (!info.owner.equals(TOKEN_PROGRAM)) + throw new Error('Recipient ATA has unexpected owner'); + return BigInt((await sol.getTokenAccountBalance(ata)).value.amount); + }; + const token = getPRC20Address( + { chain: CHAIN.SOLANA_DEVNET, address: asset.address }, + { network: f.manifest.network } + ).address; + if ( + (await f.push.readContract({ + address: token, + abi: erc20Abi, + functionName: 'balanceOf', + args: [f.ownerAddress], + })) < amount + ) + throw new Error('Insufficient mapped SPL fixture funds'); + if ( + (await f.push.getBalance({ address: f.ownerAddress })) < parseEther('22') + ) + throw new Error('Insufficient bounded PC fixture funds'); + const made = await f.owner.agentic.create('v5-spl-owner-transfer', { + rules: [], + }); + await f.fundPC(made.wallet, parseEther('21')); + await ( + await f.owner.universal.sendTransaction({ + to: token, + data: encodeFunctionData({ + abi: erc20Abi, + functionName: 'transfer', + args: [made.wallet, amount], + }), + }) + ).wait(); + const owner = await evmClient( + process.env['PUSH_PRIVATE_KEY'] as Hex, + CHAIN.PUSH_TESTNET_DONUT, + f.manifest.network, + made.wallet + ); + await ( + await owner.universal.sendTransaction({ + to: token, + data: encodeFunctionData({ + abi: erc20Abi, + functionName: 'approve', + args: [f.manifest.addresses.gateway, amount], + }), + }) + ).wait(); + const beforeRecipient = await recipientBalance(); + const beforeCheckpoints = await f.push.readContract({ + address: made.wallet, + abi: v5.abis.wallet, + functionName: 'checkpointCount', + }); + const tx = await owner.universal.sendTransaction({ + to: { chain: CHAIN.SOLANA_DEVNET, address: recipient.toBase58() }, + funds: { token: asset, amount }, + gasLimit: BigInt(0), + }); + expect(tx.value).toBe(BigInt(0)); + expect(tx.agentic).toMatchObject({ + door: 'owner', + destinationTransfer: { + recipient: `0x${recipient.toBuffer().toString('hex')}`, + token, + amount, + }, + }); + expect(tx.agentic?.destinationInstruction).toBeUndefined(); + f.evidence('v5-spl-owner-submitted', { + wallet: made.wallet, + hash: tx.hash, + mint: mint.toBase58(), + recipient: recipient.toBase58(), + ata: ata.toBase58(), + amount, + }); + const receipt = await tx.wait({ outboundTimeoutMs: 600_000 }); + expect(receipt.externalStatus).toBe('success'); + expect(receipt.from).toBe(made.wallet); + expect(await recipientBalance()).toBe(beforeRecipient + amount); + expect( + await f.push.readContract({ + address: token, + abi: erc20Abi, + functionName: 'balanceOf', + args: [made.wallet], + }) + ).toBe(BigInt(0)); + expect( + await f.push.readContract({ + address: token, + abi: erc20Abi, + functionName: 'allowance', + args: [made.wallet, f.manifest.addresses.gateway], + }) + ).toBe(BigInt(0)); + expect( + await f.push.readContract({ + address: made.wallet, + abi: v5.abis.wallet, + functionName: 'checkpointCount', + }) + ).toBe(beforeCheckpoints + BigInt(1)); + let external = await sol.getParsedTransaction(receipt.externalTxHash!, { + commitment: 'confirmed', + maxSupportedTransactionVersion: 0, + }); + for (let retry = 0; !external && retry < 5; retry++) { + await new Promise((resolve) => setTimeout(resolve, 2000)); + external = await sol.getParsedTransaction(receipt.externalTxHash!, { + commitment: 'confirmed', + maxSupportedTransactionVersion: 0, + }); + } + expect(external?.meta?.err).toBeNull(); + const accountIndex = external?.transaction.message.accountKeys.findIndex( + (entry) => entry.pubkey.equals(ata) + ); + expect(accountIndex).toBeGreaterThanOrEqual(0); + const prior = external?.meta?.preTokenBalances?.find( + (balance) => + balance.accountIndex === accountIndex && + balance.mint === mint.toBase58() + ); + const credited = external?.meta?.postTokenBalances?.find( + (balance) => + balance.accountIndex === accountIndex && + balance.mint === mint.toBase58() + ); + expect(credited?.owner).toBe(recipient.toBase58()); + expect( + BigInt(credited?.uiTokenAmount.amount ?? '0') - + BigInt(prior?.uiTokenAmount.amount ?? '0') + ).toBe(amount); + const replay = await f.owner.universal.trackTransaction(tx.hash); + expect(replay.from).toBe(made.wallet); + expect(replay.to).toBe(tx.to); + expect(replay.value).toBe(BigInt(0)); + expect(replay.agentic?.destinationTransfer).toEqual( + tx.agentic?.destinationTransfer + ); + expect( + (await replay.wait({ outboundTimeoutMs: 600_000 })).externalTxHash + ).toBe(receipt.externalTxHash); + f.evidence('v5-spl-owner-delivered', { + wallet: made.wallet, + hash: tx.hash, + destinationHash: receipt.externalTxHash, + mint: mint.toBase58(), + recipient: recipient.toBase58(), + ata: ata.toBase58(), + beforeRecipient, + afterRecipient: await recipientBalance(), + amount, + }); + }, 900_000); +}); diff --git a/packages/core/__e2e__/agw/universal-evm.spec.ts b/packages/core/__e2e__/agw/universal-evm.spec.ts index 7e3fd39d..a617a178 100644 --- a/packages/core/__e2e__/agw/universal-evm.spec.ts +++ b/packages/core/__e2e__/agw/universal-evm.spec.ts @@ -2,7 +2,7 @@ * Scenarios 7 and 8 — positive-amount EVM universal execution from the * wallet, and destination failure classification. * - * Rules are created through the public v4 UniversalRule SDK path. Destination + * Rules are created through the public v5 UniversalRule SDK path. Destination * receipt/replay checks remain opt-in funded live tests. * * creditRevert accounting is inert on the current executor (gap G07): a @@ -26,7 +26,7 @@ import { CHAIN_INFO } from '../../src/lib/constants/chain'; import { MOVEABLE_TOKEN_CONSTANTS } from '../../src/lib/constants/tokens'; import { getCEAAddress } from '../../src/lib/orchestrator/cea-utils'; import { getNativePRC20ForChain } from '../../src/lib/orchestrator/internals/helpers'; -import { v4 } from '../../src/lib/agentic/contracts/v4'; +import { v5 } from '../../src/lib/agentic/contracts/v5'; import { EVM_CHAIN_FIXTURES } from '@e2e/shared/chain-fixtures'; import { COUNTER_ABI } from '@e2e/shared/outbound-helpers'; import { verifyExternalTransaction } from '@e2e/shared/external-tx-verifier'; @@ -45,6 +45,10 @@ const counter = EVM_CHAIN_FIXTURES.find((x) => x.chain === SEPOLIA)!.contracts const INCREMENT = '0xd09de08a' as Hex; const MISSING = '0xdeadbeef' as Hex; // not implemented by the counter → destination revert const AMOUNT = BigInt(10) ** BigInt(12); // 0.000001 pETH +// Fresh CEA finalization currently needs ~1.3m gas on Sepolia; the core +// default of 500k was independently shown to revert. Keep a bounded explicit +// destination budget and preserve that default-budget evidence separately. +const DESTINATION_GAS = BigInt(2_000_000); const MAX_PC = parseEther(process.env['AGW_E2E_MAX_PC_PER_CALL'] ?? '20'); d('agw universal evm', () => { @@ -134,11 +138,12 @@ d('agw universal evm', () => { const agent = await f.agent(wallet); const ceaBefore = await sep.getBalance({ address: cea }); // Explicit call array: the bridged ETH lands in the wallet's CEA and the - // allow-listed call runs as given (a single `data` would forward the value - // to the non-payable counter, as Route 2 does for ordinary accounts). + // allow-listed call runs with zero value. A single `data` follows ordinary + // Route 2 semantics and forwards the bridged value to the target. const tx = await agent.universal.sendTransaction({ to: { address: counter, chain: SEPOLIA }, data: [{ to: counter, value: BigInt(0), data: INCREMENT }], + gasLimit: DESTINATION_GAS, funds: { amount: AMOUNT, token: MOVEABLE_TOKEN_CONSTANTS.ETHEREUM_SEPOLIA.ETH, @@ -150,9 +155,16 @@ d('agw universal evm', () => { rulesId, destinationAccount: cea, }); + f.evidence('v5-evm-outbound-submitted', { + wallet, + cea, + pushTx: tx.hash, + destinationGasLimit: DESTINATION_GAS, + }); const receipt = await tx.wait({ outboundTimeoutMs: 600_000 }); expect(receipt.status).toBe(1); expect(receipt.from).toBe(wallet); + expect(receipt.externalStatus).toBe('success'); expect(receipt.externalTxHash).toBeTruthy(); await verifyExternalTransaction(receipt.externalTxHash as string, SEPOLIA); const destinationReceipt = await sep.getTransactionReceipt({ @@ -218,6 +230,7 @@ d('agw universal evm', () => { const tx = await agent.universal.sendTransaction({ to: { address: counter, chain: SEPOLIA }, data: MISSING, + gasLimit: DESTINATION_GAS, }); const receipt = await tx.wait({ outboundTimeoutMs: 600_000 }); expect(receipt.status).toBe(1); diff --git a/packages/core/__e2e__/agw/v4-multiasset.spec.ts b/packages/core/__e2e__/agw/v4-multiasset.spec.ts deleted file mode 100644 index 2e0b30ba..00000000 --- a/packages/core/__e2e__/agw/v4-multiasset.spec.ts +++ /dev/null @@ -1,138 +0,0 @@ -/** Opt-in funded Donut acceptance. Nothing in this file runs in unit/local validation. */ -import type { UniversalRule } from '../../src'; -import { parseEther } from 'viem'; -import { CHAIN } from '../../src/lib/constants/enums'; -import { MOVEABLE_TOKEN_CONSTANTS } from '../../src/lib/constants/tokens'; -import { v4 } from '../../src/lib/agentic/contracts/v4'; -import { EVM_CHAIN_FIXTURES } from '@e2e/shared/chain-fixtures'; -import { verifyExternalTransaction } from '@e2e/shared/external-tx-verifier'; -import { - AGW_E2E_ENABLED, - inSeconds, - setupAgw, - type AgwFixture, -} from './_fixture'; - -const d = AGW_E2E_ENABLED ? describe : describe.skip; -const chain = CHAIN.ETHEREUM_SEPOLIA; -const counter = EVM_CHAIN_FIXTURES.find((x) => x.chain === chain)!.contracts - .counter as `0x${string}`; - -d('agw v4 multi-asset', () => { - let f: AgwFixture; - beforeAll(async () => { - f = await setupAgw(); - }); - afterAll(() => f?.teardown()); - it('1. public create reads and replaces an ordered two-token rule', async () => { - const rule: UniversalRule = { - agent: f.agentAddress, - chainNamespace: chain, - validUntil: inSeconds(3600), - maxGasPerCall: parseEther('20'), - assets: [ - { - token: MOVEABLE_TOKEN_CONSTANTS.ETHEREUM_SEPOLIA.ETH, - maxPerCall: BigInt(1000), - }, - { - token: MOVEABLE_TOKEN_CONSTANTS.ETHEREUM_SEPOLIA.USDC, - maxPerCall: BigInt(10), - maxTotal: BigInt(100), - }, - ], - allowedCalls: [{ target: counter, selector: 'increment()' as const }], - }; - const created = await f.owner.agentic.create('v4-two-token', { - rules: [rule], - }); - const w = f.owner.agentic.wallet(created.wallet); - const before = await w.rules.get(created.rulesIds[0]); - expect(before.rule).toMatchObject({ - assets: [ - { - maxPerCall: BigInt(1000), - maxTotal: BigInt(2) ** BigInt(256) - BigInt(1), - }, - { maxPerCall: BigInt(10), maxTotal: BigInt(100) }, - ], - }); - expect(before).not.toHaveProperty('spent'); - const count = await f.push.readContract({ - address: created.wallet, - abi: v4.abis.wallet, - functionName: 'checkpointCount', - }); - const replacement = await w.rules.update({ - rules: [{ rulesId: created.rulesIds[0], rule }], - }); - expect( - await f.push.readContract({ - address: created.wallet, - abi: v4.abis.wallet, - functionName: 'checkpointCount', - }) - ).toBe(count + BigInt(5)); - expect((await w.rules.list()).rules.map((x) => x.rulesId)).toEqual([ - replacement.rules[0].rulesId, - ]); - f.evidence('v4-two-token-replacement', { - wallet: created.wallet, - oldId: created.rulesIds[0], - newId: replacement.rules[0].rulesId, - txHash: replacement.tx.hash, - }); - }); - it('2. empty user assets routes a call-only outbound with zero token spend', async () => { - const created = await f.owner.agentic.create('v4-call-only', { - rules: [ - { - agent: f.agentAddress, - chainNamespace: chain, - assets: [], - validUntil: inSeconds(3600), - maxGasPerCall: parseEther('20'), - allowedCalls: [{ target: counter, selector: 'increment()' }], - }, - ], - }); - const record = await f.owner.agentic - .wallet(created.wallet) - .rules.get(created.rulesIds[0]); - expect(record.rule).toMatchObject({ - assets: [{ maxPerCall: BigInt(0), maxTotal: BigInt(0) }], - }); - await f.fundPC(created.wallet, parseEther('21')); - const agent = await f.agent(created.wallet); - const tx = await agent.universal.sendTransaction({ - to: { address: counter, chain }, - data: '0xd09de08a', - }); - const receipt = await tx.wait({ outboundTimeoutMs: 600_000 }); - expect(receipt.status).toBe(1); - expect(receipt.externalTxHash).toBeTruthy(); - await verifyExternalTransaction(receipt.externalTxHash as string, chain); - const [action] = await f.push.readContract({ - address: f.manifest.addresses.sessionEngine, - abi: v4.abis.engine, - functionName: 'getEnabledActions', - args: [created.wallet, created.rulesIds[0]], - }); - const { configId } = await import('../../src/lib/agentic/codec/ids'); - const cfg = await f.push.readContract({ - address: f.manifest.addresses.rulesPolicy, - abi: v4.abis.policy, - functionName: 'getConfig', - args: [ - configId(created.wallet, created.rulesIds[0], action), - created.wallet, - ], - }); - expect(cfg.assets.map((x) => x.spent)).toEqual([BigInt(0)]); - f.evidence('v4-call-only', { - wallet: created.wallet, - pushTx: tx.hash, - externalTx: receipt.externalTxHash, - }); - }, 900_000); -}); diff --git a/packages/core/__e2e__/agw/v5-multiasset.spec.ts b/packages/core/__e2e__/agw/v5-multiasset.spec.ts new file mode 100644 index 00000000..8c3a3cb4 --- /dev/null +++ b/packages/core/__e2e__/agw/v5-multiasset.spec.ts @@ -0,0 +1,344 @@ +/** Opt-in funded Donut acceptance. Nothing in this file runs in unit/local validation. */ +import type { UniversalRule } from '../../src'; +import { + createPublicClient, + encodeFunctionData, + erc20Abi, + fallback, + http, + parseAbi, + parseEventLogs, + parseEther, + type Address, + type Hex, +} from 'viem'; +import { sepolia } from 'viem/chains'; +import { CHAIN_INFO } from '../../src/lib/constants/chain'; +import { getPRC20Address } from '../../src/lib/universal/prc20-address'; +import { getCEAAddress } from '../../src/lib/orchestrator/cea-utils'; +import { configId } from '../../src/lib/agentic/codec/ids'; +import { CHAIN } from '../../src/lib/constants/enums'; +import { MOVEABLE_TOKEN_CONSTANTS } from '../../src/lib/constants/tokens'; +import { v5 } from '../../src/lib/agentic/contracts/v5'; +import { EVM_CHAIN_FIXTURES } from '@e2e/shared/chain-fixtures'; +import { verifyExternalTransaction } from '@e2e/shared/external-tx-verifier'; +import { + AGW_E2E_ENABLED, + evmClient, + inSeconds, + setupAgw, + type AgwFixture, +} from './_fixture'; + +const d = AGW_E2E_ENABLED ? describe : describe.skip; +const chain = CHAIN.ETHEREUM_SEPOLIA; +const counter = EVM_CHAIN_FIXTURES.find((x) => x.chain === chain)!.contracts + .counter as `0x${string}`; + +d('agw v5 multi-asset', () => { + let f: AgwFixture; + beforeAll(async () => { + f = await setupAgw(); + }); + afterAll(() => f?.teardown()); + it('1. public create reads and replaces an ordered two-token rule', async () => { + const rule: UniversalRule = { + agent: f.agentAddress, + chainNamespace: chain, + validUntil: inSeconds(3600), + maxGasPerCall: parseEther('20'), + assets: [ + { + token: MOVEABLE_TOKEN_CONSTANTS.ETHEREUM_SEPOLIA.ETH, + maxPerCall: BigInt(1000), + }, + { + token: MOVEABLE_TOKEN_CONSTANTS.ETHEREUM_SEPOLIA.USDC, + maxPerCall: BigInt(10), + maxTotal: BigInt(100), + }, + ], + allowedCalls: [{ target: counter, selector: 'increment()' as const }], + }; + const created = await f.owner.agentic.create('v5-two-token', { + rules: [rule], + }); + const w = f.owner.agentic.wallet(created.wallet); + const before = await w.rules.get(created.rulesIds[0]); + expect(before.rule).toMatchObject({ + assets: [ + { + maxPerCall: BigInt(1000), + maxTotal: BigInt(2) ** BigInt(256) - BigInt(1), + }, + { maxPerCall: BigInt(10), maxTotal: BigInt(100) }, + ], + }); + expect(before).not.toHaveProperty('spent'); + const count = await f.push.readContract({ + address: created.wallet, + abi: v5.abis.wallet, + functionName: 'checkpointCount', + }); + const replacement = await w.rules.update({ + rules: [{ rulesId: created.rulesIds[0], rule }], + }); + expect( + await f.push.readContract({ + address: created.wallet, + abi: v5.abis.wallet, + functionName: 'checkpointCount', + }) + ).toBe(count + BigInt(5)); + expect((await w.rules.list()).rules.map((x) => x.rulesId)).toEqual([ + replacement.rules[0].rulesId, + ]); + f.evidence('v5-two-token-replacement', { + wallet: created.wallet, + oldId: created.rulesIds[0], + newId: replacement.rules[0].rulesId, + txHash: replacement.tx.hash, + }); + }); + it('2. empty user assets routes a call-only outbound with zero token spend', async () => { + const created = await f.owner.agentic.create('v5-call-only', { + rules: [ + { + agent: f.agentAddress, + chainNamespace: chain, + assets: [], + validUntil: inSeconds(3600), + maxGasPerCall: parseEther('20'), + allowedCalls: [{ target: counter, selector: 'increment()' }], + }, + ], + }); + const record = await f.owner.agentic + .wallet(created.wallet) + .rules.get(created.rulesIds[0]); + expect(record.rule).toMatchObject({ + assets: [{ maxPerCall: BigInt(0), maxTotal: BigInt(0) }], + }); + await f.fundPC(created.wallet, parseEther('21')); + const agent = await f.agent(created.wallet); + const tx = await agent.universal.sendTransaction({ + to: { address: counter, chain }, + data: '0xd09de08a', + gasLimit: BigInt(2_000_000), + }); + const receipt = await tx.wait({ outboundTimeoutMs: 600_000 }); + expect(receipt.status).toBe(1); + expect(receipt.externalTxHash).toBeTruthy(); + await verifyExternalTransaction(receipt.externalTxHash as string, chain); + const [action] = await f.push.readContract({ + address: f.manifest.addresses.sessionEngine, + abi: v5.abis.engine, + functionName: 'getEnabledActions', + args: [created.wallet, created.rulesIds[0]], + }); + const { configId } = await import('../../src/lib/agentic/codec/ids'); + const cfg = await f.push.readContract({ + address: f.manifest.addresses.rulesPolicy, + abi: v5.abis.policy, + functionName: 'getConfig', + args: [ + configId(created.wallet, created.rulesIds[0], action), + created.wallet, + ], + }); + expect(cfg.assets.map((x) => x.spent)).toEqual([BigInt(0)]); + f.evidence('v5-call-only', { + wallet: created.wallet, + pushTx: tx.hash, + externalTx: receipt.externalTxHash, + }); + }, 900_000); + it('3. both assets execute independently after one token budget is exhausted', async () => { + const eth = MOVEABLE_TOKEN_CONSTANTS.ETHEREUM_SEPOLIA.ETH; + const usdc = MOVEABLE_TOKEN_CONSTANTS.ETHEREUM_SEPOLIA.USDC; + const amounts = [BigInt(10) ** BigInt(12), BigInt(10)]; + const tokens = [eth, usdc].map( + (token) => + getPRC20Address( + { chain, address: token.address }, + { network: f.manifest.network } + ).address + ); + // Keep an extra token unit and allowance available so total-limit failures + // reach URP instead of being masked by the SDK balance/allowance checks. + for (let i = 0; i < tokens.length; i++) { + const available = await f.push.readContract({ + address: tokens[i], + abi: erc20Abi, + functionName: 'balanceOf', + args: [f.ownerAddress], + }); + if (available < amounts[i] + BigInt(1)) + throw new Error('Insufficient master funds for two-asset fixture'); + } + const made = await f.owner.agentic.create('v5-independent-budgets', { + rules: [ + { + agent: f.agentAddress, + chainNamespace: chain, + validUntil: inSeconds(3600), + maxGasPerCall: parseEther('20'), + assets: [eth, usdc].map((token, i) => ({ + token, + maxPerCall: amounts[i], + maxTotal: amounts[i], + })), + allowedCalls: [{ target: counter, selector: 'increment()' }], + }, + ], + }); + await f.fundPC(made.wallet, parseEther('41')); + const owner = await evmClient( + process.env['PUSH_PRIVATE_KEY'] as Hex, + CHAIN.PUSH_TESTNET_DONUT, + f.manifest.network, + made.wallet + ); + for (let i = 0; i < tokens.length; i++) { + await ( + await f.owner.universal.sendTransaction({ + to: tokens[i], + data: encodeFunctionData({ + abi: erc20Abi, + functionName: 'transfer', + args: [made.wallet, amounts[i] + BigInt(1)], + }), + }) + ).wait(); + await ( + await owner.universal.sendTransaction({ + to: tokens[i], + data: encodeFunctionData({ + abi: erc20Abi, + functionName: 'approve', + args: [f.manifest.addresses.gateway, amounts[i] + BigInt(1)], + }), + }) + ).wait(); + } + const agent = await f.agent(made.wallet); + const [action] = await f.push.readContract({ + address: f.manifest.addresses.sessionEngine, + abi: v5.abis.engine, + functionName: 'getEnabledActions', + args: [made.wallet, made.rulesIds[0]], + }); + const key = configId(made.wallet, made.rulesIds[0], action); + const spent = async () => + ( + await f.push.readContract({ + address: f.manifest.addresses.rulesPolicy, + abi: v5.abis.policy, + functionName: 'getConfig', + args: [key, made.wallet], + }) + ).assets.map((asset) => asset.spent); + const sep = createPublicClient({ + chain: sepolia, + transport: fallback(CHAIN_INFO[chain].defaultRPC.map((url) => http(url))), + }); + const cea = (await getCEAAddress(made.wallet, chain)).cea as Address; + const params = (i: number, amount = amounts[i]) => ({ + to: { address: counter, chain }, + data: [{ to: counter, value: BigInt(0), data: '0xd09de08a' as Hex }], + funds: { token: [eth, usdc][i], amount }, + gasLimit: BigInt(2_000_000), + }); + const hashes: string[] = []; + expect(await spent()).toEqual([BigInt(0), BigInt(0)]); + for (let i = 0; i < tokens.length; i++) { + const beforeDestination = + i === 0 + ? await sep.getBalance({ address: cea }) + : await sep.readContract({ + address: usdc.address as Address, + abi: erc20Abi, + functionName: 'balanceOf', + args: [cea], + }); + const tx = await agent.universal.sendTransaction(params(i)); + f.evidence('v5-budget-outbound-submitted', { + wallet: made.wallet, + rulesId: made.rulesIds[0], + token: tokens[i], + amount: amounts[i], + pushTx: tx.hash, + }); + const receipt = await tx.wait({ outboundTimeoutMs: 600_000 }); + expect(receipt.externalStatus).toBe('success'); + await verifyExternalTransaction(receipt.externalTxHash!, chain); + const external = await sep.getTransactionReceipt({ + hash: receipt.externalTxHash as Hex, + }); + const executed = parseEventLogs({ + abi: parseAbi([ + 'event UniversalTxExecuted(bytes32 indexed subTxId, bytes32 indexed universalTxId, address indexed originCaller, address target, bytes data)', + ]), + logs: external.logs, + }); + expect( + executed.some( + (event) => + event.address.toLowerCase() === cea.toLowerCase() && + event.args.originCaller.toLowerCase() === + made.wallet.toLowerCase() && + event.args.target.toLowerCase() === counter.toLowerCase() + ) + ).toBe(true); + const afterDestination = + i === 0 + ? await sep.getBalance({ address: cea }) + : await sep.readContract({ + address: usdc.address as Address, + abi: erc20Abi, + functionName: 'balanceOf', + args: [cea], + }); + expect(afterDestination).toBe(beforeDestination + amounts[i]); + expect( + await f.push.readContract({ + address: tokens[i], + abi: erc20Abi, + functionName: 'balanceOf', + args: [made.wallet], + }) + ).toBe(BigInt(1)); + expect( + await f.push.readContract({ + address: tokens[i], + abi: erc20Abi, + functionName: 'allowance', + args: [made.wallet, f.manifest.addresses.gateway], + }) + ).toBe(BigInt(1)); + const expected = i === 0 ? [amounts[0], BigInt(0)] : amounts; + expect(await spent()).toEqual(expected); + const nonce = await f.push.getTransactionCount({ + address: f.agentAddress, + }); + await expect( + agent.universal.sendTransaction(params(i, BigInt(1))) + ).rejects.toMatchObject({ + decodedError: { name: 'PolicyCheckReverted(TotalSpendCapExceeded)' }, + }); + expect( + await f.push.getTransactionCount({ address: f.agentAddress }) + ).toBe(nonce); + expect(await spent()).toEqual(expected); + hashes.push(tx.hash, receipt.externalTxHash!); + } + f.evidence('v5-independent-token-budgets', { + wallet: made.wallet, + rulesId: made.rulesIds[0], + tokens, + amounts, + spent: await spent(), + hashes, + }); + }, 1_800_000); +}); diff --git a/packages/core/__e2e__/ci/preflight.ts b/packages/core/__e2e__/ci/preflight.ts index f5e08334..e7bc8c5e 100644 --- a/packages/core/__e2e__/ci/preflight.ts +++ b/packages/core/__e2e__/ci/preflight.ts @@ -415,18 +415,19 @@ function renderTable(rows: Row[]): void { return BigInt(r?.value.amount ?? '0'); }); - const [dUsdtSep, dPeth, dUsdtEth, dPsol, dUsdtSol] = await Promise.all([ + const [dUsdtSep, dPeth, dUsdtEth, dPsol, dUsdtSol, dUsdcEth] = await Promise.all([ decimalsOf(usdtSepolia, sep), decimalsOf(s.pETH, push), decimalsOf(s.USDT_ETH, push), decimalsOf(s.pSOL, push), decimalsOf(s.USDT_SOL, push), + decimalsOf(s.USDC_ETH, push), ]); const dPc20 = pc20Push ? await decimalsOf(pc20Push, push) : 18; const [ sepEth, sepUsdt, - mPC, mPeth, mUsdtEth, mPsol, mUsdtSol, mPc20, + mPC, mPeth, mUsdtEth, mPsol, mUsdtSol, mUsdcEth, mPc20, uPC, uPeth, uUsdtEth, uPsol, uUsdtSol, uPc20, solBal, solUsdt, ceaSol, ceaUsdt, ] = await Promise.all([ @@ -438,6 +439,7 @@ function renderTable(rows: Row[]): void { erc20(s.USDT_ETH, pushAcc.address, push), erc20(s.pSOL, pushAcc.address, push), erc20(s.USDT_SOL, pushAcc.address, push), + erc20(s.USDC_ETH, pushAcc.address, push), pc20Push ? erc20(pc20Push, pushAcc.address, push) : Promise.resolve(BigInt(0)), retry(() => push.getBalance({ address: uea })), @@ -484,7 +486,8 @@ function renderTable(rows: Row[]): void { { scope: 'Push master (Donut)', asset: 'pETH', need: units(target('masterPETH'), dPeth) + deficit('ueaPETH'), have: mPeth, decimals: dPeth, tier: 'master' }, { scope: 'Push master (Donut)', asset: 'pUSDT.eth', need: deficit('ueaUsdtEth'), have: mUsdtEth, decimals: dUsdtEth, tier: 'master' }, { scope: 'Push master (Donut)', asset: 'pSOL', need: units(target('masterPSOL'), dPsol) + deficit('ueaPSOL'), have: mPsol, decimals: dPsol, tier: 'master' }, - { scope: 'Push master (Donut)', asset: 'pUSDT.sol', need: deficit('ueaUsdtSol'), have: mUsdtSol, decimals: dUsdtSol, tier: 'master' }, + { scope: 'Push master (Donut)', asset: 'pUSDT.sol', need: units(target('masterUsdtSol'), dUsdtSol) + deficit('ueaUsdtSol'), have: mUsdtSol, decimals: dUsdtSol, tier: 'master' }, + { scope: 'Push master (Donut)', asset: 'pUSDC.eth', need: units(target('masterUsdcEth'), dUsdcEth), have: mUsdcEth, decimals: dUsdcEth, tier: 'master' }, { scope: 'Push master (Donut)', asset: 'PC20', need: deficit('ueaPC20'), have: mPc20, decimals: dPc20, tier: 'master' }, { scope: 'Solana master (Devnet)', asset: 'SOL', need: units(target('solanaSOL'), 9) + deficit('ceaSvmSOL'), have: solBal, decimals: 9, tier: 'master' }, { scope: 'Solana master (Devnet)', asset: 'USDT', need: units(target('solanaUsdt'), 6) + deficit('ceaSvmUsdt'), have: solUsdt, decimals: 6, tier: 'master' }, diff --git a/packages/core/__e2e__/ci/run.ts b/packages/core/__e2e__/ci/run.ts index 06b48485..5ff82702 100644 --- a/packages/core/__e2e__/ci/run.ts +++ b/packages/core/__e2e__/ci/run.ts @@ -9,7 +9,7 @@ * svm-r1, svm-r2r3, pc20, push, cross-chain, read, * known-fail, agw, agw-svm-wire, agw-svm-replay * (`all` excludes known-fail and AGW groups — ask by name; - * agw uses the checked Donut v4 manifest by default, see __e2e__/agw/_manifest.ts) + * agw uses the checked Donut v5 manifest by default, see __e2e__/agw/_manifest.ts) * --list Print the selection and the jest argv, run nothing * --verify Check every `grep` against the real spec titles and exit * non-zero if any fragment matches 0 or >1 tests in its file diff --git a/packages/core/__e2e__/ci/suite.ts b/packages/core/__e2e__/ci/suite.ts index 8154079e..3bc27a74 100644 --- a/packages/core/__e2e__/ci/suite.ts +++ b/packages/core/__e2e__/ci/suite.ts @@ -73,6 +73,8 @@ export type Asset = | 'masterPC' | 'masterPETH' | 'masterPSOL' + | 'masterUsdcEth' + | 'masterUsdtSol' // The EVM master's UEA on Push Donut — Routes 2/3 on both VMs, and PC20 | 'ueaPC' | 'ueaPETH' @@ -976,18 +978,18 @@ export const SCENARIOS: Scenario[] = [ env: { AGW_E2E: '1' }, }, { - id: 'agw-v4-multi-asset', + id: 'agw-v5-multi-asset', group: 'agw', - file: '__e2e__/agw/v4-multiasset.spec.ts', - grep: 'agw v4 multi-asset 1\\. public create', + file: '__e2e__/agw/v5-multiasset.spec.ts', + grep: 'agw v5 multi-asset 1\\. public create', needs: { masterPC: '2' }, env: { AGW_E2E: '1' }, }, { - id: 'agw-v4-call-only', + id: 'agw-v5-call-only', group: 'agw', - file: '__e2e__/agw/v4-multiasset.spec.ts', - grep: 'agw v4 multi-asset 2\\. empty user assets', + file: '__e2e__/agw/v5-multiasset.spec.ts', + grep: 'agw v5 multi-asset 2\\. empty user assets', needs: { masterPC: '25' }, env: { AGW_E2E: '1' }, }, @@ -1040,12 +1042,32 @@ export const SCENARIOS: Scenario[] = [ env: { AGW_E2E: '1' }, }, - ...Array.from({ length: 4 }, (_, i) => ({ + ...Array.from({ length: 6 }, (_, i) => ({ id: `agw-public-svm-${i + 1}`, group: 'agw' as const, file: '__e2e__/agw/svm-public.spec.ts', grep: `agw public svm ${i + 1}\\.`, - needs: { masterPC: '25', masterPSOL: '0.00001' }, env: { AGW_E2E: '1' }, + needs: { masterPC: '45', masterPSOL: '0.000020001' }, env: { AGW_E2E: '1' }, })), + ...Array.from({ length: 8 }, (_, i) => ({ + id: `agw-labels-${i + 1}`, group: 'agw' as const, + file: '__e2e__/agw/labels.spec.ts', grep: `agw labels ${i + 1}\\.`, + needs: i === 4 ? { masterPC: '4', sepoliaEth: '0.003' } : i === 5 ? { masterPC: '4', solanaSOL: '0.003' } : { masterPC: '1' }, + env: { AGW_E2E: '1' }, + })), + + { + id: 'agw-v5-independent-token-budgets', group: 'agw', + file: '__e2e__/agw/v5-multiasset.spec.ts', grep: 'agw v5 multi-asset 3\\.', + needs: { masterPC: '45', masterPETH: '0.000001000000000001', masterUsdcEth: '0.000011' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-owner-spl-transfer', group: 'agw', + file: '__e2e__/agw/svm-spl-transfer.spec.ts', grep: 'agw svm spl transfer 1\\.', + needs: { masterPC: '23', masterUsdtSol: '0.001' }, + env: { AGW_E2E: '1' }, + }, + // Extended AGW tests are opt-in and use bounded per-scenario testnet budgets. ...[ ['prefunding', '1\\. prefunding', '11'], diff --git a/packages/core/__e2e__/shared/agw-state.ts b/packages/core/__e2e__/shared/agw-state.ts index 54033f7f..2c633e03 100644 --- a/packages/core/__e2e__/shared/agw-state.ts +++ b/packages/core/__e2e__/shared/agw-state.ts @@ -1,6 +1,6 @@ /** Independent contract-state assertions for AGW tests; never part of the public SDK. */ import type { Address, Hex, PublicClient } from 'viem'; -import { v4 } from '../../src/lib/agentic/contracts/v4'; +import { v5 } from '../../src/lib/agentic/contracts/v5'; import { configId } from '../../src/lib/agentic/codec/ids'; export async function readNativeCounters( @@ -11,7 +11,7 @@ export async function readNativeCounters( ) { const actions = await client.readContract({ address: addresses.sessionEngine, - abi: v4.abis.engine, + abi: v5.abis.engine, functionName: 'getEnabledActions', args: [wallet, rulesId], }); @@ -19,7 +19,7 @@ export async function readNativeCounters( throw new Error('Native counter fixture expects one action'); const cfg = await client.readContract({ address: addresses.rulesPolicy, - abi: v4.abis.policy, + abi: v5.abis.policy, functionName: 'getNativeConfig', args: [configId(wallet, rulesId, actions[0]), wallet], }); diff --git a/packages/core/__e2e__/shared/agw-svm-policy-probe.ts b/packages/core/__e2e__/shared/agw-svm-policy-probe.ts index 0a8044aa..8b5b0d6c 100644 --- a/packages/core/__e2e__/shared/agw-svm-policy-probe.ts +++ b/packages/core/__e2e__/shared/agw-svm-policy-probe.ts @@ -1,7 +1,7 @@ /** Bypass SDK validation to verify the deployed URP refuses the same mutations. eth_call only. */ import { decodeFunctionData, encodeFunctionData, type Address, type Hex, type PublicClient } from 'viem'; import { UNIVERSAL_GATEWAY_PC } from '../../src/lib/constants/abi'; -import { v4, type Call } from '../../src/lib/agentic/contracts/v4'; +import { v5, type Call } from '../../src/lib/agentic/contracts/v5'; import { parseAgwSvmPayload, encodeAgwSvmPayload } from '../../src/lib/agentic/execution/svm-payload'; import { decodeAgenticRevert } from '../../src/lib/agentic/revert'; @@ -22,7 +22,7 @@ export async function probeSvmWirePolicies(push: PublicClient, input: { view.setBigUint64(8, view.getBigUint64(8, true) + BigInt(1), true); } const altered = { ...request, payload: encodeAgwSvmPayload(parsed.program, accounts, data) }; - const packet = v4.encodeExecuteAsAgent(input.rulesId, { ...input.call, + const packet = v5.encodeExecuteAsAgent(input.rulesId, { ...input.call, data: encodeFunctionData({ abi: UNIVERSAL_GATEWAY_PC, functionName: 'sendUniversalTxOutbound', args: [altered] }) }); let decoded; try { await push.call({ account: input.from, to: input.wallet, data: packet, blockNumber: input.blockNumber }); } diff --git a/packages/core/jest.agw-local.config.ts b/packages/core/jest.agw-local.config.ts index 8d332245..c2e22b0c 100644 --- a/packages/core/jest.agw-local.config.ts +++ b/packages/core/jest.agw-local.config.ts @@ -1,6 +1,6 @@ /** * Local AGW contract harness (review-only). Runs the SDK against the real - * pinned v4 contracts on anvil. Requires Foundry and AGW_LOCAL_DIR from + * pinned v5 contracts on anvil. Requires Foundry and AGW_LOCAL_DIR from * scripts/agw-local/prepare.sh. Never part of the unit or E2E runs. * * AGW_LOCAL_DIR=$(packages/core/scripts/agw-local/prepare.sh | tail -1) \ diff --git a/packages/core/scripts/agw-local/abis/engine.json b/packages/core/scripts/agw-local/abis/engine.json index 61100bd3..bdf678eb 100644 --- a/packages/core/scripts/agw-local/abis/engine.json +++ b/packages/core/scripts/agw-local/abis/engine.json @@ -1,1957 +1,1957 @@ [ { + "type": "function", + "name": "areActionsEnabled", "inputs": [ { - "internalType": "uint256", - "name": "index", - "type": "uint256" - } - ], - "name": "AssociatedArray_OutOfBounds", - "type": "error" - }, - { - "inputs": [ + "name": "account", + "type": "address", + "internalType": "address" + }, { - "internalType": "uint64", - "name": "providedChainId", - "type": "uint64" - } - ], - "name": "ChainIdMismatch", - "type": "error" - }, - { - "inputs": [ + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, { - "internalType": "uint64", - "name": "providedChainId", - "type": "uint64" + "name": "actions", + "type": "tuple[]", + "internalType": "struct ActionData[]", + "components": [ + { + "name": "actionTargetSelector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "actionTarget", + "type": "address", + "internalType": "address" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] } ], - "name": "ChainIdMismatch", - "type": "error" - }, - { - "inputs": [], - "name": "ForbiddenValidationData", - "type": "error" - }, - { - "inputs": [ + "outputs": [ { - "internalType": "uint256", - "name": "index", - "type": "uint256" + "name": "", + "type": "bool", + "internalType": "bool" } ], - "name": "HashIndexOutOfBounds", - "type": "error" + "stateMutability": "view" }, { + "type": "function", + "name": "areERC1271PoliciesEnabled", "inputs": [ { - "internalType": "bytes32", - "name": "providedHash", - "type": "bytes32" + "name": "account", + "type": "address", + "internalType": "address" }, { - "internalType": "bytes32", - "name": "computedHash", - "type": "bytes32" + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] } ], - "name": "HashMismatch", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "providedHash", - "type": "bytes32" - }, + "outputs": [ { - "internalType": "bytes32", - "name": "computedHash", - "type": "bytes32" + "name": "", + "type": "bool", + "internalType": "bool" } ], - "name": "HashMismatch", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidActionId", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCallTarget", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidData", - "type": "error" + "stateMutability": "view" }, { + "type": "function", + "name": "areUserOpPoliciesEnabled", "inputs": [ { - "internalType": "address", "name": "account", - "type": "address" + "type": "address", + "internalType": "address" }, { - "internalType": "bytes32", - "name": "hash", - "type": "bytes32" - } - ], - "name": "InvalidEnableSignature", - "type": "error" - }, - { - "inputs": [ + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, { - "internalType": "contract ISessionValidator", - "name": "sessionValidator", - "type": "address" + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] } ], - "name": "InvalidISessionValidator", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidMode", - "type": "error" - }, - { - "inputs": [ + "outputs": [ { - "internalType": "PermissionId", - "name": "permissionId", - "type": "bytes32" + "name": "", + "type": "bool", + "internalType": "bool" } ], - "name": "InvalidPermissionId", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidSelfCall", - "type": "error" + "stateMutability": "view" }, { + "type": "function", + "name": "disableActionId", "inputs": [ { - "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32" + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "actionId", + "type": "bytes32", + "internalType": "ActionId" } ], - "name": "InvalidSession", - "type": "error" + "outputs": [], + "stateMutability": "nonpayable" }, { + "type": "function", + "name": "disableActionPolicies", "inputs": [ { - "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32" + "type": "bytes32", + "internalType": "PermissionId" }, { - "internalType": "address", - "name": "sessionValidator", - "type": "address" - }, - { - "internalType": "address", - "name": "account", - "type": "address" + "name": "actionId", + "type": "bytes32", + "internalType": "ActionId" }, { - "internalType": "bytes32", - "name": "userOpHash", - "type": "bytes32" - } - ], - "name": "InvalidSessionKeySignature", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidTarget", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "sender", - "type": "address" + "name": "policies", + "type": "address[]", + "internalType": "address[]" } ], - "name": "InvalidUserOpSender", - "type": "error" - }, - { - "inputs": [], - "name": "NoExecutionsInBatch", - "type": "error" + "outputs": [], + "stateMutability": "nonpayable" }, { + "type": "function", + "name": "disableERC1271Policies", "inputs": [ { - "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32" - } - ], - "name": "NoPoliciesSet", - "type": "error" - }, - { - "inputs": [], - "name": "PartlyEnabledActions", - "type": "error" - }, - { - "inputs": [], - "name": "PartlyEnabledPolicies", - "type": "error" - }, - { - "inputs": [ + "type": "bytes32", + "internalType": "PermissionId" + }, { - "internalType": "PermissionId", - "name": "permissionId", - "type": "bytes32" + "name": "policies", + "type": "address[]", + "internalType": "address[]" + }, + { + "name": "contexts", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNames", + "type": "string[]", + "internalType": "string[]" + } + ] } ], - "name": "PaymasterValidationNotEnabled", - "type": "error" + "outputs": [], + "stateMutability": "nonpayable" }, { + "type": "function", + "name": "disableUserOpPolicies", "inputs": [ { - "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32" + "type": "bytes32", + "internalType": "PermissionId" }, { - "internalType": "address", - "name": "policy", - "type": "address" + "name": "policies", + "type": "address[]", + "internalType": "address[]" } ], - "name": "PolicyViolation", - "type": "error" + "outputs": [], + "stateMutability": "nonpayable" }, { + "type": "function", + "name": "enableActionPolicies", "inputs": [ { - "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32" + "type": "bytes32", + "internalType": "PermissionId" }, { - "internalType": "address", - "name": "account", - "type": "address" + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct ActionData[]", + "components": [ + { + "name": "actionTargetSelector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "actionTarget", + "type": "address", + "internalType": "address" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] } ], - "name": "SignerNotFound", - "type": "error" + "outputs": [], + "stateMutability": "nonpayable" }, { + "type": "function", + "name": "enableERC1271Policies", "inputs": [ { - "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32" + "type": "bytes32", + "internalType": "PermissionId" }, { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "SignerNotFound", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" + "name": "erc1271Policies", + "type": "tuple", + "internalType": "struct ERC7739Data", + "components": [ + { + "name": "allowedERC7739Content", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNames", + "type": "string[]", + "internalType": "string[]" + } + ] + }, + { + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] } ], - "name": "SmartSessionModuleAlreadyInstalled", - "type": "error" + "outputs": [], + "stateMutability": "nonpayable" }, { + "type": "function", + "name": "enableSessions", "inputs": [ { - "internalType": "CallType", - "name": "callType", - "type": "bytes1" - } - ], - "name": "UnsupportedCallType", - "type": "error" - }, - { - "inputs": [], - "name": "UnsupportedExecutionType", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "policy", - "type": "address" + "name": "sessions", + "type": "tuple[]", + "internalType": "struct Session[]", + "components": [ + { + "name": "sessionValidator", + "type": "address", + "internalType": "contract ISessionValidator" + }, + { + "name": "sessionValidatorInitData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "erc7739Policies", + "type": "tuple", + "internalType": "struct ERC7739Data", + "components": [ + { + "name": "allowedERC7739Content", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNames", + "type": "string[]", + "internalType": "string[]" + } + ] + }, + { + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "actions", + "type": "tuple[]", + "internalType": "struct ActionData[]", + "components": [ + { + "name": "actionTargetSelector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "actionTarget", + "type": "address", + "internalType": "address" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "permitERC4337Paymaster", + "type": "bool", + "internalType": "bool" + } + ] } ], - "name": "UnsupportedPolicy", - "type": "error" - }, - { - "inputs": [ + "outputs": [ { - "internalType": "enum SmartSessionMode", - "name": "mode", - "type": "uint8" + "name": "permissionIds", + "type": "bytes32[]", + "internalType": "PermissionId[]" } ], - "name": "UnsupportedSmartSessionMode", - "type": "error" + "stateMutability": "nonpayable" }, { - "anonymous": false, + "type": "function", + "name": "enableUserOpPolicies", "inputs": [ { - "indexed": false, - "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32" + "type": "bytes32", + "internalType": "PermissionId" }, { - "indexed": false, - "internalType": "ActionId", - "name": "actionId", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "address", - "name": "smartAccount", - "type": "address" + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] } ], - "name": "ActionIdDisabled", - "type": "event" + "outputs": [], + "stateMutability": "nonpayable" }, { - "anonymous": false, + "type": "function", + "name": "getActionPolicies", "inputs": [ { - "indexed": false, - "internalType": "PermissionId", - "name": "permissionId", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "address", "name": "account", - "type": "address" + "type": "address", + "internalType": "address" }, { - "indexed": false, - "internalType": "uint256", - "name": "newValue", - "type": "uint256" - } - ], - "name": "NonceIterated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32" + "type": "bytes32", + "internalType": "PermissionId" }, { - "indexed": false, - "internalType": "address", - "name": "smartAccount", - "type": "address" - }, + "name": "actionId", + "type": "bytes32", + "internalType": "ActionId" + } + ], + "outputs": [ { - "indexed": false, - "internalType": "bool", - "name": "enabled", - "type": "bool" + "name": "", + "type": "address[]", + "internalType": "address[]" } ], - "name": "PermissionIdPermit4337Paymaster", - "type": "event" + "stateMutability": "view" }, { - "anonymous": false, + "type": "function", + "name": "getERC1271Policies", "inputs": [ { - "indexed": false, - "internalType": "PermissionId", - "name": "permissionId", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "enum PolicyType", - "name": "policyType", - "type": "uint8" + "name": "account", + "type": "address", + "internalType": "address" }, { - "indexed": false, - "internalType": "address", - "name": "policy", - "type": "address" - }, + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ], + "outputs": [ { - "indexed": false, - "internalType": "address", - "name": "smartAccount", - "type": "address" + "name": "", + "type": "address[]", + "internalType": "address[]" } ], - "name": "PolicyDisabled", - "type": "event" + "stateMutability": "view" }, { - "anonymous": false, + "type": "function", + "name": "getEnabledActions", "inputs": [ { - "indexed": false, - "internalType": "PermissionId", - "name": "permissionId", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "enum PolicyType", - "name": "policyType", - "type": "uint8" + "name": "account", + "type": "address", + "internalType": "address" }, { - "indexed": false, - "internalType": "address", - "name": "policy", - "type": "address" - }, + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ], + "outputs": [ { - "indexed": false, - "internalType": "address", - "name": "smartAccount", - "type": "address" + "name": "", + "type": "bytes32[]", + "internalType": "bytes32[]" } ], - "name": "PolicyEnabled", - "type": "event" + "stateMutability": "view" }, { - "anonymous": false, + "type": "function", + "name": "getEnabledERC7739Content", "inputs": [ { - "indexed": false, - "internalType": "PermissionId", - "name": "permissionId", - "type": "bytes32" + "name": "account", + "type": "address", + "internalType": "address" }, { - "indexed": false, - "internalType": "address", - "name": "account", - "type": "address" + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" } ], - "name": "SessionCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "PermissionId", - "name": "permissionId", - "type": "bytes32" - }, + "outputs": [ { - "indexed": false, - "internalType": "address", - "name": "smartAccount", - "type": "address" + "name": "enabledERC7739ContentHashes", + "type": "tuple[]", + "internalType": "struct ERC7739ContextHashes[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNameHashes", + "type": "bytes32[]", + "internalType": "bytes32[]" + } + ] } ], - "name": "SessionRemoved", - "type": "event" + "stateMutability": "view" }, { - "anonymous": false, + "type": "function", + "name": "getNonce", "inputs": [ { - "indexed": false, - "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32" + "type": "bytes32", + "internalType": "PermissionId" }, { - "indexed": false, - "internalType": "address", - "name": "sessionValidator", - "type": "address" - }, + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ { - "indexed": false, - "internalType": "address", - "name": "smartAccount", - "type": "address" + "name": "", + "type": "uint256", + "internalType": "uint256" } ], - "name": "SessionValidatorDisabled", - "type": "event" + "stateMutability": "view" }, { - "anonymous": false, + "type": "function", + "name": "getPermissionIDs", "inputs": [ { - "indexed": false, - "internalType": "PermissionId", - "name": "permissionId", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "address", - "name": "sessionValidator", - "type": "address" - }, + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ { - "indexed": false, - "internalType": "address", - "name": "smartAccount", - "type": "address" + "name": "permissionIds", + "type": "bytes32[]", + "internalType": "PermissionId[]" } ], - "name": "SessionValidatorEnabled", - "type": "event" + "stateMutability": "view" }, { + "type": "function", + "name": "getPermissionId", "inputs": [ { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "PermissionId", - "name": "permissionId", - "type": "bytes32" - }, - { + "name": "session", + "type": "tuple", + "internalType": "struct Session", "components": [ { - "internalType": "bytes4", - "name": "actionTargetSelector", - "type": "bytes4" + "name": "sessionValidator", + "type": "address", + "internalType": "contract ISessionValidator" }, { - "internalType": "address", - "name": "actionTarget", - "type": "address" + "name": "sessionValidatorInitData", + "type": "bytes", + "internalType": "bytes" }, { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", "components": [ { - "internalType": "address", "name": "policy", - "type": "address" + "type": "address", + "internalType": "address" }, { - "internalType": "bytes", "name": "initData", - "type": "bytes" + "type": "bytes", + "internalType": "bytes" } - ], - "internalType": "struct PolicyData[]", - "name": "actionPolicies", - "type": "tuple[]" - } - ], - "internalType": "struct ActionData[]", - "name": "actions", - "type": "tuple[]" - } - ], - "name": "areActionsEnabled", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "PermissionId", - "name": "permissionId", - "type": "bytes32" - }, - { - "components": [ - { - "internalType": "address", - "name": "policy", - "type": "address" - }, - { - "internalType": "bytes", - "name": "initData", - "type": "bytes" - } - ], - "internalType": "struct PolicyData[]", - "name": "erc1271Policies", - "type": "tuple[]" - } - ], - "name": "areERC1271PoliciesEnabled", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "PermissionId", - "name": "permissionId", - "type": "bytes32" - }, - { - "components": [ - { - "internalType": "address", - "name": "policy", - "type": "address" - }, - { - "internalType": "bytes", - "name": "initData", - "type": "bytes" - } - ], - "internalType": "struct PolicyData[]", - "name": "userOpPolicies", - "type": "tuple[]" - } - ], - "name": "areUserOpPoliciesEnabled", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "PermissionId", - "name": "permissionId", - "type": "bytes32" - }, - { - "internalType": "ActionId", - "name": "actionId", - "type": "bytes32" - } - ], - "name": "disableActionId", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "PermissionId", - "name": "permissionId", - "type": "bytes32" - }, - { - "internalType": "ActionId", - "name": "actionId", - "type": "bytes32" - }, - { - "internalType": "address[]", - "name": "policies", - "type": "address[]" - } - ], - "name": "disableActionPolicies", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "PermissionId", - "name": "permissionId", - "type": "bytes32" - }, - { - "internalType": "address[]", - "name": "policies", - "type": "address[]" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "appDomainSeparator", - "type": "bytes32" - }, - { - "internalType": "string[]", - "name": "contentNames", - "type": "string[]" - } - ], - "internalType": "struct ERC7739Context[]", - "name": "contexts", - "type": "tuple[]" - } - ], - "name": "disableERC1271Policies", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "PermissionId", - "name": "permissionId", - "type": "bytes32" - }, - { - "internalType": "address[]", - "name": "policies", - "type": "address[]" - } - ], - "name": "disableUserOpPolicies", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "PermissionId", - "name": "permissionId", - "type": "bytes32" - }, - { - "components": [ - { - "internalType": "bytes4", - "name": "actionTargetSelector", - "type": "bytes4" - }, - { - "internalType": "address", - "name": "actionTarget", - "type": "address" + ] }, { + "name": "erc7739Policies", + "type": "tuple", + "internalType": "struct ERC7739Data", "components": [ { - "internalType": "address", - "name": "policy", - "type": "address" + "name": "allowedERC7739Content", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNames", + "type": "string[]", + "internalType": "string[]" + } + ] }, { - "internalType": "bytes", - "name": "initData", - "type": "bytes" + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] } - ], - "internalType": "struct PolicyData[]", - "name": "actionPolicies", - "type": "tuple[]" - } - ], - "internalType": "struct ActionData[]", - "name": "actionPolicies", - "type": "tuple[]" - } - ], - "name": "enableActionPolicies", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "PermissionId", - "name": "permissionId", - "type": "bytes32" - }, - { - "components": [ + ] + }, { + "name": "actions", + "type": "tuple[]", + "internalType": "struct ActionData[]", "components": [ { - "internalType": "bytes32", - "name": "appDomainSeparator", - "type": "bytes32" + "name": "actionTargetSelector", + "type": "bytes4", + "internalType": "bytes4" }, { - "internalType": "string[]", - "name": "contentNames", - "type": "string[]" - } - ], - "internalType": "struct ERC7739Context[]", - "name": "allowedERC7739Content", - "type": "tuple[]" - }, - { - "components": [ - { - "internalType": "address", - "name": "policy", - "type": "address" + "name": "actionTarget", + "type": "address", + "internalType": "address" }, { - "internalType": "bytes", - "name": "initData", - "type": "bytes" + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] } - ], - "internalType": "struct PolicyData[]", - "name": "erc1271Policies", - "type": "tuple[]" + ] + }, + { + "name": "permitERC4337Paymaster", + "type": "bool", + "internalType": "bool" } - ], - "internalType": "struct ERC7739Data", - "name": "erc1271Policies", - "type": "tuple" + ] } ], - "name": "enableERC1271Policies", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "outputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ], + "stateMutability": "pure" }, { + "type": "function", + "name": "getSessionDigest", "inputs": [ { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "data", + "type": "tuple", + "internalType": "struct Session", "components": [ { - "internalType": "contract ISessionValidator", "name": "sessionValidator", - "type": "address" + "type": "address", + "internalType": "contract ISessionValidator" }, { - "internalType": "bytes", "name": "sessionValidatorInitData", - "type": "bytes" + "type": "bytes", + "internalType": "bytes" }, { - "internalType": "bytes32", "name": "salt", - "type": "bytes32" + "type": "bytes32", + "internalType": "bytes32" }, { + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", "components": [ { - "internalType": "address", "name": "policy", - "type": "address" + "type": "address", + "internalType": "address" }, { - "internalType": "bytes", "name": "initData", - "type": "bytes" + "type": "bytes", + "internalType": "bytes" } - ], - "internalType": "struct PolicyData[]", - "name": "userOpPolicies", - "type": "tuple[]" + ] }, { + "name": "erc7739Policies", + "type": "tuple", + "internalType": "struct ERC7739Data", "components": [ { + "name": "allowedERC7739Content", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", "components": [ { - "internalType": "bytes32", "name": "appDomainSeparator", - "type": "bytes32" + "type": "bytes32", + "internalType": "bytes32" }, { - "internalType": "string[]", "name": "contentNames", - "type": "string[]" + "type": "string[]", + "internalType": "string[]" } - ], - "internalType": "struct ERC7739Context[]", - "name": "allowedERC7739Content", - "type": "tuple[]" + ] }, { + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", "components": [ { - "internalType": "address", "name": "policy", - "type": "address" + "type": "address", + "internalType": "address" }, { - "internalType": "bytes", "name": "initData", - "type": "bytes" + "type": "bytes", + "internalType": "bytes" } - ], - "internalType": "struct PolicyData[]", - "name": "erc1271Policies", - "type": "tuple[]" + ] } - ], - "internalType": "struct ERC7739Data", - "name": "erc7739Policies", - "type": "tuple" + ] }, { + "name": "actions", + "type": "tuple[]", + "internalType": "struct ActionData[]", "components": [ { - "internalType": "bytes4", "name": "actionTargetSelector", - "type": "bytes4" + "type": "bytes4", + "internalType": "bytes4" }, { - "internalType": "address", "name": "actionTarget", - "type": "address" + "type": "address", + "internalType": "address" }, { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", "components": [ { - "internalType": "address", "name": "policy", - "type": "address" + "type": "address", + "internalType": "address" }, { - "internalType": "bytes", "name": "initData", - "type": "bytes" + "type": "bytes", + "internalType": "bytes" } - ], - "internalType": "struct PolicyData[]", - "name": "actionPolicies", - "type": "tuple[]" + ] } - ], - "internalType": "struct ActionData[]", - "name": "actions", - "type": "tuple[]" + ] }, { - "internalType": "bool", "name": "permitERC4337Paymaster", - "type": "bool" + "type": "bool", + "internalType": "bool" } - ], - "internalType": "struct Session[]", - "name": "sessions", - "type": "tuple[]" + ] + }, + { + "name": "mode", + "type": "uint8", + "internalType": "enum SmartSessionMode" } ], - "name": "enableSessions", "outputs": [ { - "internalType": "PermissionId[]", - "name": "permissionIds", - "type": "bytes32[]" + "name": "", + "type": "bytes32", + "internalType": "bytes32" } ], - "stateMutability": "nonpayable", - "type": "function" + "stateMutability": "view" }, { + "type": "function", + "name": "getSessionValidatorAndConfig", "inputs": [ { - "internalType": "PermissionId", - "name": "permissionId", - "type": "bytes32" + "name": "account", + "type": "address", + "internalType": "address" }, { - "components": [ - { - "internalType": "address", - "name": "policy", - "type": "address" - }, - { - "internalType": "bytes", - "name": "initData", - "type": "bytes" - } - ], - "internalType": "struct PolicyData[]", - "name": "userOpPolicies", - "type": "tuple[]" + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" } ], - "name": "enableUserOpPolicies", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "outputs": [ + { + "name": "sessionValidator", + "type": "address", + "internalType": "address" + }, + { + "name": "sessionValidatorData", + "type": "bytes", + "internalType": "bytes" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getUserOpPolicies", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ], + "outputs": [ + { + "name": "", + "type": "address[]", + "internalType": "address[]" + } + ], + "stateMutability": "view" }, { + "type": "function", + "name": "isActionIdEnabled", "inputs": [ { - "internalType": "address", "name": "account", - "type": "address" + "type": "address", + "internalType": "address" }, { - "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32" + "type": "bytes32", + "internalType": "PermissionId" }, { - "internalType": "ActionId", "name": "actionId", - "type": "bytes32" + "type": "bytes32", + "internalType": "ActionId" } ], - "name": "getActionPolicies", "outputs": [ { - "internalType": "address[]", "name": "", - "type": "address[]" + "type": "bool", + "internalType": "bool" } ], - "stateMutability": "view", - "type": "function" + "stateMutability": "view" }, { + "type": "function", + "name": "isActionPolicyEnabled", "inputs": [ { - "internalType": "address", "name": "account", - "type": "address" + "type": "address", + "internalType": "address" }, { - "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32" + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "actionId", + "type": "bytes32", + "internalType": "ActionId" + }, + { + "name": "policy", + "type": "address", + "internalType": "address" } ], - "name": "getERC1271Policies", "outputs": [ { - "internalType": "address[]", "name": "", - "type": "address[]" + "type": "bool", + "internalType": "bool" } ], - "stateMutability": "view", - "type": "function" + "stateMutability": "view" }, { + "type": "function", + "name": "isERC1271PolicyEnabled", "inputs": [ { - "internalType": "address", "name": "account", - "type": "address" + "type": "address", + "internalType": "address" }, { - "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32" + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "policy", + "type": "address", + "internalType": "address" } ], - "name": "getEnabledActions", "outputs": [ { - "internalType": "bytes32[]", "name": "", - "type": "bytes32[]" + "type": "bool", + "internalType": "bool" } ], - "stateMutability": "view", - "type": "function" + "stateMutability": "view" }, { + "type": "function", + "name": "isERC7739ContentEnabled", "inputs": [ { - "internalType": "address", "name": "account", - "type": "address" + "type": "address", + "internalType": "address" }, { - "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32" + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "content", + "type": "string", + "internalType": "string" } ], - "name": "getEnabledERC7739Content", "outputs": [ { - "components": [ - { - "internalType": "bytes32", - "name": "appDomainSeparator", - "type": "bytes32" - }, - { - "internalType": "bytes32[]", - "name": "contentNameHashes", - "type": "bytes32[]" - } - ], - "internalType": "struct ERC7739ContextHashes[]", - "name": "enabledERC7739ContentHashes", - "type": "tuple[]" + "name": "", + "type": "bool", + "internalType": "bool" } ], - "stateMutability": "view", - "type": "function" + "stateMutability": "view" }, { + "type": "function", + "name": "isISessionValidatorSet", "inputs": [ { - "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32" + "type": "bytes32", + "internalType": "PermissionId" }, { - "internalType": "address", "name": "account", - "type": "address" + "type": "address", + "internalType": "address" } ], - "name": "getNonce", "outputs": [ { - "internalType": "uint256", "name": "", - "type": "uint256" + "type": "bool", + "internalType": "bool" } ], - "stateMutability": "view", - "type": "function" + "stateMutability": "view" }, { + "type": "function", + "name": "isInitialized", "inputs": [ { - "internalType": "address", - "name": "account", - "type": "address" + "name": "smartAccount", + "type": "address", + "internalType": "address" } ], - "name": "getPermissionIDs", "outputs": [ { - "internalType": "PermissionId[]", - "name": "permissionIds", - "type": "bytes32[]" + "name": "", + "type": "bool", + "internalType": "bool" } ], - "stateMutability": "view", - "type": "function" + "stateMutability": "view" }, { + "type": "function", + "name": "isModuleType", "inputs": [ { - "components": [ - { - "internalType": "contract ISessionValidator", - "name": "sessionValidator", - "type": "address" - }, - { - "internalType": "bytes", - "name": "sessionValidatorInitData", - "type": "bytes" - }, - { - "internalType": "bytes32", - "name": "salt", - "type": "bytes32" - }, - { - "components": [ - { - "internalType": "address", - "name": "policy", - "type": "address" - }, - { - "internalType": "bytes", - "name": "initData", - "type": "bytes" - } - ], - "internalType": "struct PolicyData[]", - "name": "userOpPolicies", - "type": "tuple[]" - }, - { - "components": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "appDomainSeparator", - "type": "bytes32" - }, - { - "internalType": "string[]", - "name": "contentNames", - "type": "string[]" - } - ], - "internalType": "struct ERC7739Context[]", - "name": "allowedERC7739Content", - "type": "tuple[]" - }, - { - "components": [ - { - "internalType": "address", - "name": "policy", - "type": "address" - }, - { - "internalType": "bytes", - "name": "initData", - "type": "bytes" - } - ], - "internalType": "struct PolicyData[]", - "name": "erc1271Policies", - "type": "tuple[]" - } - ], - "internalType": "struct ERC7739Data", - "name": "erc7739Policies", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "bytes4", - "name": "actionTargetSelector", - "type": "bytes4" - }, - { - "internalType": "address", - "name": "actionTarget", - "type": "address" - }, - { - "components": [ - { - "internalType": "address", - "name": "policy", - "type": "address" - }, - { - "internalType": "bytes", - "name": "initData", - "type": "bytes" - } - ], - "internalType": "struct PolicyData[]", - "name": "actionPolicies", - "type": "tuple[]" - } - ], - "internalType": "struct ActionData[]", - "name": "actions", - "type": "tuple[]" - }, - { - "internalType": "bool", - "name": "permitERC4337Paymaster", - "type": "bool" - } - ], - "internalType": "struct Session", - "name": "session", - "type": "tuple" + "name": "typeID", + "type": "uint256", + "internalType": "uint256" } ], - "name": "getPermissionId", "outputs": [ { - "internalType": "PermissionId", - "name": "permissionId", - "type": "bytes32" + "name": "", + "type": "bool", + "internalType": "bool" } ], - "stateMutability": "pure", - "type": "function" + "stateMutability": "pure" }, { + "type": "function", + "name": "isPermissionEnabled", "inputs": [ { - "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32" + "type": "bytes32", + "internalType": "PermissionId" }, { - "internalType": "address", "name": "account", - "type": "address" + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isUserOpPolicyEnabled", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" }, { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "policy", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isValidSignatureWithSender", + "inputs": [ + { + "name": "sender", + "type": "address", + "internalType": "address" + }, + { + "name": "hash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "signature", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "result", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "onInstall", + "inputs": [ + { + "name": "data", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "onUninstall", + "inputs": [ + { + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "removeSession", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "revokeEnableSignature", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setPermit4337Paymaster", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "enabled", + "type": "bool", + "internalType": "bool" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "validateUserOp", + "inputs": [ + { + "name": "userOp", + "type": "tuple", + "internalType": "struct PackedUserOperation", "components": [ { - "internalType": "contract ISessionValidator", - "name": "sessionValidator", - "type": "address" + "name": "sender", + "type": "address", + "internalType": "address" }, { - "internalType": "bytes", - "name": "sessionValidatorInitData", - "type": "bytes" + "name": "nonce", + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "bytes32", - "name": "salt", - "type": "bytes32" + "name": "initCode", + "type": "bytes", + "internalType": "bytes" }, { - "components": [ - { - "internalType": "address", - "name": "policy", - "type": "address" - }, - { - "internalType": "bytes", - "name": "initData", - "type": "bytes" - } - ], - "internalType": "struct PolicyData[]", - "name": "userOpPolicies", - "type": "tuple[]" + "name": "callData", + "type": "bytes", + "internalType": "bytes" }, { - "components": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "appDomainSeparator", - "type": "bytes32" - }, - { - "internalType": "string[]", - "name": "contentNames", - "type": "string[]" - } - ], - "internalType": "struct ERC7739Context[]", - "name": "allowedERC7739Content", - "type": "tuple[]" - }, - { - "components": [ - { - "internalType": "address", - "name": "policy", - "type": "address" - }, - { - "internalType": "bytes", - "name": "initData", - "type": "bytes" - } - ], - "internalType": "struct PolicyData[]", - "name": "erc1271Policies", - "type": "tuple[]" - } - ], - "internalType": "struct ERC7739Data", - "name": "erc7739Policies", - "type": "tuple" + "name": "accountGasLimits", + "type": "bytes32", + "internalType": "bytes32" }, { - "components": [ - { - "internalType": "bytes4", - "name": "actionTargetSelector", - "type": "bytes4" - }, - { - "internalType": "address", - "name": "actionTarget", - "type": "address" - }, - { - "components": [ - { - "internalType": "address", - "name": "policy", - "type": "address" - }, - { - "internalType": "bytes", - "name": "initData", - "type": "bytes" - } - ], - "internalType": "struct PolicyData[]", - "name": "actionPolicies", - "type": "tuple[]" - } - ], - "internalType": "struct ActionData[]", - "name": "actions", - "type": "tuple[]" + "name": "preVerificationGas", + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "bool", - "name": "permitERC4337Paymaster", - "type": "bool" + "name": "gasFees", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "paymasterAndData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "signature", + "type": "bytes", + "internalType": "bytes" } - ], - "internalType": "struct Session", - "name": "data", - "type": "tuple" + ] }, { - "internalType": "enum SmartSessionMode", - "name": "mode", - "type": "uint8" + "name": "userOpHash", + "type": "bytes32", + "internalType": "bytes32" } ], - "name": "getSessionDigest", "outputs": [ { - "internalType": "bytes32", - "name": "", - "type": "bytes32" + "name": "vd", + "type": "uint256", + "internalType": "ValidationData" } ], - "stateMutability": "view", - "type": "function" + "stateMutability": "nonpayable" }, { + "type": "event", + "name": "ActionIdDisabled", "inputs": [ { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32" - } - ], - "name": "getSessionValidatorAndConfig", - "outputs": [ + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" + }, { - "internalType": "address", - "name": "sessionValidator", - "type": "address" + "name": "actionId", + "type": "bytes32", + "indexed": false, + "internalType": "ActionId" }, { - "internalType": "bytes", - "name": "sessionValidatorData", - "type": "bytes" + "name": "smartAccount", + "type": "address", + "indexed": false, + "internalType": "address" } ], - "stateMutability": "view", - "type": "function" + "anonymous": false }, { + "type": "event", + "name": "NonceIterated", "inputs": [ { - "internalType": "address", + "name": "permissionId", + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" + }, + { "name": "account", - "type": "address" + "type": "address", + "indexed": false, + "internalType": "address" }, { - "internalType": "PermissionId", - "name": "permissionId", - "type": "bytes32" + "name": "newValue", + "type": "uint256", + "indexed": false, + "internalType": "uint256" } ], - "name": "getUserOpPolicies", - "outputs": [ + "anonymous": false + }, + { + "type": "event", + "name": "PermissionIdPermit4337Paymaster", + "inputs": [ { - "internalType": "address[]", - "name": "", - "type": "address[]" + "name": "permissionId", + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" + }, + { + "name": "smartAccount", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "enabled", + "type": "bool", + "indexed": false, + "internalType": "bool" } ], - "stateMutability": "view", - "type": "function" + "anonymous": false }, { + "type": "event", + "name": "PolicyDisabled", "inputs": [ { - "internalType": "address", - "name": "account", - "type": "address" + "name": "permissionId", + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" }, { - "internalType": "PermissionId", - "name": "permissionId", - "type": "bytes32" + "name": "policyType", + "type": "uint8", + "indexed": false, + "internalType": "enum PolicyType" }, { - "internalType": "ActionId", - "name": "actionId", - "type": "bytes32" - } - ], - "name": "isActionIdEnabled", - "outputs": [ + "name": "policy", + "type": "address", + "indexed": false, + "internalType": "address" + }, { - "internalType": "bool", - "name": "", - "type": "bool" + "name": "smartAccount", + "type": "address", + "indexed": false, + "internalType": "address" } ], - "stateMutability": "view", - "type": "function" + "anonymous": false }, { + "type": "event", + "name": "PolicyEnabled", "inputs": [ { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32" + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" }, { - "internalType": "ActionId", - "name": "actionId", - "type": "bytes32" + "name": "policyType", + "type": "uint8", + "indexed": false, + "internalType": "enum PolicyType" }, { - "internalType": "address", "name": "policy", - "type": "address" + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "smartAccount", + "type": "address", + "indexed": false, + "internalType": "address" } ], - "name": "isActionPolicyEnabled", - "outputs": [ + "anonymous": false + }, + { + "type": "event", + "name": "SessionCreated", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" + }, + { + "name": "account", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "SessionRemoved", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" + }, { - "internalType": "bool", - "name": "", - "type": "bool" + "name": "smartAccount", + "type": "address", + "indexed": false, + "internalType": "address" } ], - "stateMutability": "view", - "type": "function" + "anonymous": false }, { + "type": "event", + "name": "SessionValidatorDisabled", "inputs": [ { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32" + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" }, { - "internalType": "address", - "name": "policy", - "type": "address" - } - ], - "name": "isERC1271PolicyEnabled", - "outputs": [ + "name": "sessionValidator", + "type": "address", + "indexed": false, + "internalType": "address" + }, { - "internalType": "bool", - "name": "", - "type": "bool" + "name": "smartAccount", + "type": "address", + "indexed": false, + "internalType": "address" } ], - "stateMutability": "view", - "type": "function" + "anonymous": false }, { + "type": "event", + "name": "SessionValidatorEnabled", "inputs": [ { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32" + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" }, { - "internalType": "bytes32", - "name": "appDomainSeparator", - "type": "bytes32" + "name": "sessionValidator", + "type": "address", + "indexed": false, + "internalType": "address" }, { - "internalType": "string", - "name": "content", - "type": "string" + "name": "smartAccount", + "type": "address", + "indexed": false, + "internalType": "address" } ], - "name": "isERC7739ContentEnabled", - "outputs": [ + "anonymous": false + }, + { + "type": "error", + "name": "AssociatedArray_OutOfBounds", + "inputs": [ { - "internalType": "bool", - "name": "", - "type": "bool" + "name": "index", + "type": "uint256", + "internalType": "uint256" } - ], - "stateMutability": "view", - "type": "function" + ] }, { + "type": "error", + "name": "ChainIdMismatch", "inputs": [ { - "internalType": "PermissionId", - "name": "permissionId", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "account", - "type": "address" + "name": "providedChainId", + "type": "uint64", + "internalType": "uint64" } - ], - "name": "isISessionValidatorSet", - "outputs": [ + ] + }, + { + "type": "error", + "name": "ChainIdMismatch", + "inputs": [ { - "internalType": "bool", - "name": "", - "type": "bool" + "name": "providedChainId", + "type": "uint64", + "internalType": "uint64" } - ], - "stateMutability": "view", - "type": "function" + ] + }, + { + "type": "error", + "name": "ForbiddenValidationData", + "inputs": [] }, { + "type": "error", + "name": "HashIndexOutOfBounds", "inputs": [ { - "internalType": "address", - "name": "smartAccount", - "type": "address" + "name": "index", + "type": "uint256", + "internalType": "uint256" } - ], - "name": "isInitialized", - "outputs": [ + ] + }, + { + "type": "error", + "name": "HashMismatch", + "inputs": [ { - "internalType": "bool", - "name": "", - "type": "bool" + "name": "providedHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "computedHash", + "type": "bytes32", + "internalType": "bytes32" } - ], - "stateMutability": "view", - "type": "function" + ] }, { + "type": "error", + "name": "HashMismatch", "inputs": [ { - "internalType": "uint256", - "name": "typeID", - "type": "uint256" - } - ], - "name": "isModuleType", - "outputs": [ + "name": "providedHash", + "type": "bytes32", + "internalType": "bytes32" + }, { - "internalType": "bool", - "name": "", - "type": "bool" + "name": "computedHash", + "type": "bytes32", + "internalType": "bytes32" } - ], - "stateMutability": "pure", - "type": "function" + ] + }, + { + "type": "error", + "name": "InvalidActionId", + "inputs": [] }, { + "type": "error", + "name": "InvalidCallTarget", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidData", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidEnableSignature", "inputs": [ { - "internalType": "PermissionId", - "name": "permissionId", - "type": "bytes32" + "name": "account", + "type": "address", + "internalType": "address" }, { - "internalType": "address", - "name": "account", - "type": "address" + "name": "hash", + "type": "bytes32", + "internalType": "bytes32" } - ], - "name": "isPermissionEnabled", - "outputs": [ + ] + }, + { + "type": "error", + "name": "InvalidISessionValidator", + "inputs": [ { - "internalType": "bool", - "name": "", - "type": "bool" + "name": "sessionValidator", + "type": "address", + "internalType": "contract ISessionValidator" } - ], - "stateMutability": "view", - "type": "function" + ] + }, + { + "type": "error", + "name": "InvalidMode", + "inputs": [] }, { + "type": "error", + "name": "InvalidPermissionId", "inputs": [ { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "policy", - "type": "address" + "type": "bytes32", + "internalType": "PermissionId" } - ], - "name": "isUserOpPolicyEnabled", - "outputs": [ + ] + }, + { + "type": "error", + "name": "InvalidSelfCall", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidSession", + "inputs": [ { - "internalType": "bool", - "name": "", - "type": "bool" + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" } - ], - "stateMutability": "view", - "type": "function" + ] }, { + "type": "error", + "name": "InvalidSessionKeySignature", "inputs": [ { - "internalType": "address", - "name": "sender", - "type": "address" + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" }, { - "internalType": "bytes32", - "name": "hash", - "type": "bytes32" + "name": "sessionValidator", + "type": "address", + "internalType": "address" }, { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - } - ], - "name": "isValidSignatureWithSender", - "outputs": [ + "name": "account", + "type": "address", + "internalType": "address" + }, { - "internalType": "bytes4", - "name": "result", - "type": "bytes4" + "name": "userOpHash", + "type": "bytes32", + "internalType": "bytes32" } - ], - "stateMutability": "view", - "type": "function" + ] + }, + { + "type": "error", + "name": "InvalidTarget", + "inputs": [] }, { + "type": "error", + "name": "InvalidUserOpSender", "inputs": [ { - "internalType": "bytes", - "name": "data", - "type": "bytes" + "name": "sender", + "type": "address", + "internalType": "address" } - ], - "name": "onInstall", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + ] }, { + "type": "error", + "name": "NoExecutionsInBatch", + "inputs": [] + }, + { + "type": "error", + "name": "NoPoliciesSet", "inputs": [ { - "internalType": "bytes", - "name": "", - "type": "bytes" + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" } - ], - "name": "onUninstall", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + ] + }, + { + "type": "error", + "name": "PartlyEnabledActions", + "inputs": [] }, { + "type": "error", + "name": "PartlyEnabledPolicies", + "inputs": [] + }, + { + "type": "error", + "name": "PaymasterValidationNotEnabled", "inputs": [ { - "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32" + "type": "bytes32", + "internalType": "PermissionId" } - ], - "name": "removeSession", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + ] }, { + "type": "error", + "name": "PolicyViolation", "inputs": [ { - "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32" + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "policy", + "type": "address", + "internalType": "address" } - ], - "name": "revokeEnableSignature", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + ] }, { + "type": "error", + "name": "SignerNotFound", "inputs": [ { - "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32" + "type": "bytes32", + "internalType": "PermissionId" }, { - "internalType": "bool", - "name": "enabled", - "type": "bool" + "name": "account", + "type": "address", + "internalType": "address" } - ], - "name": "setPermit4337Paymaster", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + ] }, { + "type": "error", + "name": "SignerNotFound", "inputs": [ { - "components": [ - { - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "initCode", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "callData", - "type": "bytes" - }, - { - "internalType": "bytes32", - "name": "accountGasLimits", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "preVerificationGas", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "gasFees", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "paymasterAndData", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - } - ], - "internalType": "struct PackedUserOperation", - "name": "userOp", - "type": "tuple" + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" }, { - "internalType": "bytes32", - "name": "userOpHash", - "type": "bytes32" + "name": "account", + "type": "address", + "internalType": "address" } - ], - "name": "validateUserOp", - "outputs": [ + ] + }, + { + "type": "error", + "name": "SmartSessionModuleAlreadyInstalled", + "inputs": [ { - "internalType": "ValidationData", - "name": "vd", - "type": "uint256" + "name": "account", + "type": "address", + "internalType": "address" } - ], - "stateMutability": "nonpayable", - "type": "function" + ] + }, + { + "type": "error", + "name": "UnsupportedCallType", + "inputs": [ + { + "name": "callType", + "type": "bytes1", + "internalType": "CallType" + } + ] + }, + { + "type": "error", + "name": "UnsupportedExecutionType", + "inputs": [] + }, + { + "type": "error", + "name": "UnsupportedPolicy", + "inputs": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "UnsupportedSmartSessionMode", + "inputs": [ + { + "name": "mode", + "type": "uint8", + "internalType": "enum SmartSessionMode" + } + ] } ] diff --git a/packages/core/scripts/agw-local/abis/factory.json b/packages/core/scripts/agw-local/abis/factory.json index c2bf3eb7..30435540 100644 --- a/packages/core/scripts/agw-local/abis/factory.json +++ b/packages/core/scripts/agw-local/abis/factory.json @@ -1,1105 +1,1105 @@ [ { + "type": "constructor", "inputs": [], - "stateMutability": "nonpayable", - "type": "constructor" + "stateMutability": "nonpayable" }, { + "type": "function", + "name": "DEFAULT_ADMIN_ROLE", "inputs": [], - "name": "AccessControlBadConfirmation", - "type": "error" - }, - { - "inputs": [ + "outputs": [ { - "internalType": "uint48", - "name": "schedule", - "type": "uint48" + "name": "", + "type": "bytes32", + "internalType": "bytes32" } ], - "name": "AccessControlEnforcedDefaultAdminDelay", - "type": "error" + "stateMutability": "view" }, { + "type": "function", + "name": "OPERATOR_ROLE", "inputs": [], - "name": "AccessControlEnforcedDefaultAdminRules", - "type": "error" - }, - { - "inputs": [ + "outputs": [ { - "internalType": "address", - "name": "defaultAdmin", - "type": "address" + "name": "", + "type": "bytes32", + "internalType": "bytes32" } ], - "name": "AccessControlInvalidDefaultAdmin", - "type": "error" + "stateMutability": "view" }, { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, + "type": "function", + "name": "PAUSER_ROLE", + "inputs": [], + "outputs": [ { - "internalType": "bytes32", - "name": "neededRole", - "type": "bytes32" + "name": "", + "type": "bytes32", + "internalType": "bytes32" } ], - "name": "AccessControlUnauthorizedAccount", - "type": "error" + "stateMutability": "view" }, { - "inputs": [ + "type": "function", + "name": "UPGRADE_INTERFACE_VERSION", + "inputs": [], + "outputs": [ { - "internalType": "address", - "name": "target", - "type": "address" + "name": "", + "type": "string", + "internalType": "string" } ], - "name": "AddressEmptyCode", - "type": "error" - }, - { - "inputs": [], - "name": "CloneArgumentsTooLong", - "type": "error" + "stateMutability": "view" }, { + "type": "function", + "name": "acceptDefaultAdminTransfer", "inputs": [], - "name": "Create2EmptyBytecode", - "type": "error" + "outputs": [], + "stateMutability": "nonpayable" }, { + "type": "function", + "name": "beginDefaultAdminTransfer", "inputs": [ { - "internalType": "address", - "name": "implementation", - "type": "address" + "name": "newAdmin", + "type": "address", + "internalType": "address" } ], - "name": "ERC1967InvalidImplementation", - "type": "error" - }, - { - "inputs": [], - "name": "ERC1967NonPayable", - "type": "error" + "outputs": [], + "stateMutability": "nonpayable" }, { + "type": "function", + "name": "cancelDefaultAdminTransfer", "inputs": [], - "name": "EnforcedPause", - "type": "error" + "outputs": [], + "stateMutability": "nonpayable" }, { + "type": "function", + "name": "changeDefaultAdminDelay", "inputs": [ { - "internalType": "address", - "name": "expected", - "type": "address" - }, - { - "internalType": "address", - "name": "actual", - "type": "address" + "name": "newDelay", + "type": "uint48", + "internalType": "uint48" } ], - "name": "ExecutorMismatch", - "type": "error" - }, - { - "inputs": [], - "name": "ExpectedPause", - "type": "error" + "outputs": [], + "stateMutability": "nonpayable" }, { + "type": "function", + "name": "defaultAdmin", "inputs": [], - "name": "FailedCall", - "type": "error" + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" }, { + "type": "function", + "name": "defaultAdminDelay", "inputs": [], - "name": "FailedDeployment", - "type": "error" + "outputs": [ + { + "name": "", + "type": "uint48", + "internalType": "uint48" + } + ], + "stateMutability": "view" }, { + "type": "function", + "name": "defaultAdminDelayIncreaseWait", "inputs": [], - "name": "ImplementationNotSet", - "type": "error" + "outputs": [ + { + "name": "", + "type": "uint48", + "internalType": "uint48" + } + ], + "stateMutability": "view" }, { + "type": "function", + "name": "deployWallet", "inputs": [ { - "internalType": "uint96", - "name": "expected", - "type": "uint96" - }, + "name": "label", + "type": "string", + "internalType": "string" + } + ], + "outputs": [ { - "internalType": "uint96", - "name": "provided", - "type": "uint96" + "name": "wallet", + "type": "address", + "internalType": "address" } ], - "name": "IndexMismatch", - "type": "error" + "stateMutability": "nonpayable" }, { + "type": "function", + "name": "deployWalletWithSig", "inputs": [ { - "internalType": "uint256", - "name": "index", - "type": "uint256" + "name": "intent", + "type": "tuple", + "internalType": "struct OwnerIntent", + "components": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "wallet", + "type": "address", + "internalType": "address" + }, + { + "name": "executor", + "type": "address", + "internalType": "address" + }, + { + "name": "index", + "type": "uint96", + "internalType": "uint96" + }, + { + "name": "sessionHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "mode", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "execCalldataHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "nonceKey", + "type": "uint192", + "internalType": "uint192" + }, + { + "name": "nonceSeq", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "grantNonce", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "deadline", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "signerChainId", + "type": "uint256", + "internalType": "uint256" + } + ] }, { - "internalType": "uint256", - "name": "next", - "type": "uint256" + "name": "sig", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "label", + "type": "string", + "internalType": "string" } ], - "name": "IndexOutOfRange", - "type": "error" + "outputs": [ + { + "name": "wallet", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "nonpayable" }, { + "type": "function", + "name": "domainSeparator", "inputs": [ { - "internalType": "uint256", - "name": "balance", - "type": "uint256" - }, + "name": "signerChainId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ { - "internalType": "uint256", - "name": "needed", - "type": "uint256" + "name": "", + "type": "bytes32", + "internalType": "bytes32" } ], - "name": "InsufficientBalance", - "type": "error" + "stateMutability": "view" }, { + "type": "function", + "name": "getRoleAdmin", "inputs": [ { - "internalType": "address", - "name": "expected", - "type": "address" - }, + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [ { - "internalType": "address", - "name": "provided", - "type": "address" + "name": "", + "type": "bytes32", + "internalType": "bytes32" } ], - "name": "IntentWalletMismatch", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidInitialization", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidOwnerSignature", - "type": "error" + "stateMutability": "view" }, { + "type": "function", + "name": "grantRole", "inputs": [ { - "internalType": "address", + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + }, + { "name": "account", - "type": "address" + "type": "address", + "internalType": "address" } ], - "name": "NotAWallet", - "type": "error" - }, - { - "inputs": [], - "name": "NotInitializing", - "type": "error" + "outputs": [], + "stateMutability": "nonpayable" }, { + "type": "function", + "name": "hasRole", "inputs": [ { - "internalType": "uint8", - "name": "bits", - "type": "uint8" + "name": "role", + "type": "bytes32", + "internalType": "bytes32" }, { - "internalType": "uint256", - "name": "value", - "type": "uint256" + "name": "account", + "type": "address", + "internalType": "address" } ], - "name": "SafeCastOverflowedUintDowncast", - "type": "error" - }, - { - "inputs": [ + "outputs": [ { - "internalType": "uint48", - "name": "deadline", - "type": "uint48" + "name": "", + "type": "bool", + "internalType": "bool" } ], - "name": "SignatureExpired", - "type": "error" - }, - { - "inputs": [], - "name": "UUPSUnauthorizedCallContext", - "type": "error" + "stateMutability": "view" }, { + "type": "function", + "name": "indexOf", "inputs": [ { - "internalType": "bytes32", - "name": "slot", - "type": "bytes32" + "name": "wallet", + "type": "address", + "internalType": "address" } ], - "name": "UUPSUnsupportedProxiableUUID", - "type": "error" - }, - { - "inputs": [], - "name": "ZeroAddress", - "type": "error" - }, - { - "anonymous": false, - "inputs": [], - "name": "DefaultAdminDelayChangeCanceled", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint48", - "name": "newDelay", - "type": "uint48" - }, + "outputs": [ { - "indexed": false, - "internalType": "uint48", - "name": "effectSchedule", - "type": "uint48" + "name": "", + "type": "uint256", + "internalType": "uint256" } ], - "name": "DefaultAdminDelayChangeScheduled", - "type": "event" - }, - { - "anonymous": false, - "inputs": [], - "name": "DefaultAdminTransferCanceled", - "type": "event" + "stateMutability": "view" }, { - "anonymous": false, + "type": "function", + "name": "initialize", "inputs": [ { - "indexed": true, - "internalType": "address", - "name": "newAdmin", - "type": "address" + "name": "admin", + "type": "address", + "internalType": "address" }, { - "indexed": false, - "internalType": "uint48", - "name": "acceptSchedule", - "type": "uint48" + "name": "walletImplementation_", + "type": "address", + "internalType": "address" } ], - "name": "DefaultAdminTransferScheduled", - "type": "event" + "outputs": [], + "stateMutability": "nonpayable" }, { - "anonymous": false, + "type": "function", + "name": "isWallet", "inputs": [ { - "indexed": false, - "internalType": "uint64", - "name": "version", - "type": "uint64" + "name": "account", + "type": "address", + "internalType": "address" } ], - "name": "Initialized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ + "outputs": [ { - "indexed": false, - "internalType": "address", - "name": "account", - "type": "address" + "name": "", + "type": "bool", + "internalType": "bool" } ], - "name": "Paused", - "type": "event" + "stateMutability": "view" }, { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "previousAdminRole", - "type": "bytes32" - }, + "type": "function", + "name": "owner", + "inputs": [], + "outputs": [ { - "indexed": true, - "internalType": "bytes32", - "name": "newAdminRole", - "type": "bytes32" + "name": "", + "type": "address", + "internalType": "address" } ], - "name": "RoleAdminChanged", - "type": "event" + "stateMutability": "view" }, { - "anonymous": false, + "type": "function", + "name": "ownerOf", "inputs": [ { - "indexed": true, - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, + "name": "wallet", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ { - "indexed": true, - "internalType": "address", - "name": "sender", - "type": "address" + "name": "", + "type": "address", + "internalType": "address" } ], - "name": "RoleGranted", - "type": "event" + "stateMutability": "view" }, { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, + "type": "function", + "name": "pause", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "paused", + "inputs": [], + "outputs": [ { - "indexed": true, - "internalType": "address", - "name": "sender", - "type": "address" + "name": "", + "type": "bool", + "internalType": "bool" } ], - "name": "RoleRevoked", - "type": "event" + "stateMutability": "view" }, { - "anonymous": false, - "inputs": [ + "type": "function", + "name": "pendingDefaultAdmin", + "inputs": [], + "outputs": [ { - "indexed": false, - "internalType": "address", - "name": "account", - "type": "address" + "name": "newAdmin", + "type": "address", + "internalType": "address" + }, + { + "name": "schedule", + "type": "uint48", + "internalType": "uint48" } ], - "name": "Unpaused", - "type": "event" + "stateMutability": "view" }, { - "anonymous": false, - "inputs": [ + "type": "function", + "name": "pendingDefaultAdminDelay", + "inputs": [], + "outputs": [ { - "indexed": true, - "internalType": "address", - "name": "implementation", - "type": "address" + "name": "newDelay", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "schedule", + "type": "uint48", + "internalType": "uint48" } ], - "name": "Upgraded", - "type": "event" + "stateMutability": "view" }, { - "anonymous": false, + "type": "function", + "name": "predictWallet", "inputs": [ { - "indexed": true, - "internalType": "address", "name": "owner", - "type": "address" + "type": "address", + "internalType": "address" }, { - "indexed": true, - "internalType": "uint256", "name": "index", - "type": "uint256" - }, + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ { - "indexed": true, - "internalType": "address", "name": "wallet", - "type": "address" + "type": "address", + "internalType": "address" }, { - "indexed": false, - "internalType": "string", - "name": "label", - "type": "string" + "name": "deployed", + "type": "bool", + "internalType": "bool" } ], - "name": "WalletDeployed", - "type": "event" + "stateMutability": "view" }, { + "type": "function", + "name": "proxiableUUID", "inputs": [], - "name": "DEFAULT_ADMIN_ROLE", "outputs": [ { - "internalType": "bytes32", "name": "", - "type": "bytes32" + "type": "bytes32", + "internalType": "bytes32" } ], - "stateMutability": "view", - "type": "function" + "stateMutability": "view" }, { - "inputs": [], - "name": "OPERATOR_ROLE", - "outputs": [ + "type": "function", + "name": "renounceRole", + "inputs": [ { - "internalType": "bytes32", - "name": "", - "type": "bytes32" + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "internalType": "address" } ], - "stateMutability": "view", - "type": "function" + "outputs": [], + "stateMutability": "nonpayable" }, { - "inputs": [], - "name": "PAUSER_ROLE", - "outputs": [ + "type": "function", + "name": "revokeRole", + "inputs": [ { - "internalType": "bytes32", - "name": "", - "type": "bytes32" + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "internalType": "address" } ], - "stateMutability": "view", - "type": "function" + "outputs": [], + "stateMutability": "nonpayable" }, { + "type": "function", + "name": "rollbackDefaultAdminDelay", "inputs": [], - "name": "UPGRADE_INTERFACE_VERSION", + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "supportsInterface", + "inputs": [ + { + "name": "interfaceId", + "type": "bytes4", + "internalType": "bytes4" + } + ], "outputs": [ { - "internalType": "string", "name": "", - "type": "string" + "type": "bool", + "internalType": "bool" } ], - "stateMutability": "view", - "type": "function" + "stateMutability": "view" }, { + "type": "function", + "name": "unpause", "inputs": [], - "name": "acceptDefaultAdminTransfer", "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "stateMutability": "nonpayable" }, { + "type": "function", + "name": "upgradeToAndCall", "inputs": [ { - "internalType": "address", - "name": "newAdmin", - "type": "address" + "name": "newImplementation", + "type": "address", + "internalType": "address" + }, + { + "name": "data", + "type": "bytes", + "internalType": "bytes" } ], - "name": "beginDefaultAdminTransfer", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "cancelDefaultAdminTransfer", "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "stateMutability": "payable" }, { + "type": "function", + "name": "walletCount", "inputs": [ { - "internalType": "uint48", - "name": "newDelay", - "type": "uint48" + "name": "owner", + "type": "address", + "internalType": "address" } ], - "name": "changeDefaultAdminDelay", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "defaultAdmin", "outputs": [ { - "internalType": "address", "name": "", - "type": "address" + "type": "uint256", + "internalType": "uint256" } ], - "stateMutability": "view", - "type": "function" + "stateMutability": "view" }, { + "type": "function", + "name": "walletImplementation", "inputs": [], - "name": "defaultAdminDelay", "outputs": [ { - "internalType": "uint48", "name": "", - "type": "uint48" + "type": "address", + "internalType": "address" } ], - "stateMutability": "view", - "type": "function" + "stateMutability": "view" }, { + "type": "event", + "name": "DefaultAdminDelayChangeCanceled", "inputs": [], - "name": "defaultAdminDelayIncreaseWait", - "outputs": [ - { - "internalType": "uint48", - "name": "", - "type": "uint48" - } - ], - "stateMutability": "view", - "type": "function" + "anonymous": false }, { + "type": "event", + "name": "DefaultAdminDelayChangeScheduled", "inputs": [ { - "internalType": "string", - "name": "label", - "type": "string" - } - ], - "name": "deployWallet", - "outputs": [ + "name": "newDelay", + "type": "uint48", + "indexed": false, + "internalType": "uint48" + }, { - "internalType": "address", - "name": "wallet", - "type": "address" + "name": "effectSchedule", + "type": "uint48", + "indexed": false, + "internalType": "uint48" } ], - "stateMutability": "nonpayable", - "type": "function" + "anonymous": false }, { + "type": "event", + "name": "DefaultAdminTransferCanceled", + "inputs": [], + "anonymous": false + }, + { + "type": "event", + "name": "DefaultAdminTransferScheduled", "inputs": [ { - "components": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "wallet", - "type": "address" - }, - { - "internalType": "address", - "name": "executor", - "type": "address" - }, - { - "internalType": "uint96", - "name": "index", - "type": "uint96" - }, - { - "internalType": "bytes32", - "name": "sessionHash", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "mode", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "execCalldataHash", - "type": "bytes32" - }, - { - "internalType": "uint192", - "name": "nonceKey", - "type": "uint192" - }, - { - "internalType": "uint64", - "name": "nonceSeq", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "grantNonce", - "type": "uint64" - }, - { - "internalType": "uint48", - "name": "deadline", - "type": "uint48" - }, - { - "internalType": "uint256", - "name": "signerChainId", - "type": "uint256" - } - ], - "internalType": "struct OwnerIntent", - "name": "intent", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "sig", - "type": "bytes" + "name": "newAdmin", + "type": "address", + "indexed": true, + "internalType": "address" }, { - "internalType": "string", - "name": "label", - "type": "string" - } - ], - "name": "deployWalletWithSig", - "outputs": [ - { - "internalType": "address", - "name": "wallet", - "type": "address" + "name": "acceptSchedule", + "type": "uint48", + "indexed": false, + "internalType": "uint48" } ], - "stateMutability": "nonpayable", - "type": "function" + "anonymous": false }, { + "type": "event", + "name": "Initialized", "inputs": [ { - "internalType": "uint256", - "name": "signerChainId", - "type": "uint256" - } - ], - "name": "domainSeparator", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" + "name": "version", + "type": "uint64", + "indexed": false, + "internalType": "uint64" } ], - "stateMutability": "view", - "type": "function" + "anonymous": false }, { + "type": "event", + "name": "Paused", "inputs": [ { - "internalType": "bytes32", - "name": "role", - "type": "bytes32" + "name": "account", + "type": "address", + "indexed": false, + "internalType": "address" } ], - "name": "getRoleAdmin", - "outputs": [ + "anonymous": false + }, + { + "type": "event", + "name": "RoleAdminChanged", + "inputs": [ { - "internalType": "bytes32", - "name": "", - "type": "bytes32" + "name": "role", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "previousAdminRole", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "newAdminRole", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" } ], - "stateMutability": "view", - "type": "function" + "anonymous": false }, { + "type": "event", + "name": "RoleGranted", "inputs": [ { - "internalType": "bytes32", "name": "role", - "type": "bytes32" + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" }, { - "internalType": "address", "name": "account", - "type": "address" + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" } ], - "name": "grantRole", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "anonymous": false }, { + "type": "event", + "name": "RoleRevoked", "inputs": [ { - "internalType": "bytes32", "name": "role", - "type": "bytes32" + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" }, { - "internalType": "address", "name": "account", - "type": "address" - } - ], - "name": "hasRole", - "outputs": [ + "type": "address", + "indexed": true, + "internalType": "address" + }, { - "internalType": "bool", - "name": "", - "type": "bool" + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" } ], - "stateMutability": "view", - "type": "function" + "anonymous": false }, { + "type": "event", + "name": "Unpaused", "inputs": [ { - "internalType": "address", - "name": "wallet", - "type": "address" + "name": "account", + "type": "address", + "indexed": false, + "internalType": "address" } ], - "name": "indexOf", - "outputs": [ + "anonymous": false + }, + { + "type": "event", + "name": "Upgraded", + "inputs": [ { - "internalType": "uint256", - "name": "", - "type": "uint256" + "name": "implementation", + "type": "address", + "indexed": true, + "internalType": "address" } ], - "stateMutability": "view", - "type": "function" + "anonymous": false }, { + "type": "event", + "name": "WalletDeployed", "inputs": [ { - "internalType": "address", - "name": "admin", - "type": "address" + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" }, { - "internalType": "address", - "name": "walletImplementation_", - "type": "address" + "name": "index", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "wallet", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "label", + "type": "string", + "indexed": false, + "internalType": "string" } ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "anonymous": false }, { + "type": "error", + "name": "AccessControlBadConfirmation", + "inputs": [] + }, + { + "type": "error", + "name": "AccessControlEnforcedDefaultAdminDelay", "inputs": [ { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "isWallet", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" + "name": "schedule", + "type": "uint48", + "internalType": "uint48" } - ], - "stateMutability": "view", - "type": "function" + ] }, { - "inputs": [], - "name": "owner", - "outputs": [ + "type": "error", + "name": "AccessControlEnforcedDefaultAdminRules", + "inputs": [] + }, + { + "type": "error", + "name": "AccessControlInvalidDefaultAdmin", + "inputs": [ { - "internalType": "address", - "name": "", - "type": "address" + "name": "defaultAdmin", + "type": "address", + "internalType": "address" } - ], - "stateMutability": "view", - "type": "function" + ] }, { + "type": "error", + "name": "AccessControlUnauthorizedAccount", "inputs": [ { - "internalType": "address", - "name": "wallet", - "type": "address" + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "neededRole", + "type": "bytes32", + "internalType": "bytes32" } - ], - "name": "ownerOf", - "outputs": [ + ] + }, + { + "type": "error", + "name": "AddressEmptyCode", + "inputs": [ { - "internalType": "address", - "name": "", - "type": "address" + "name": "target", + "type": "address", + "internalType": "address" } - ], - "stateMutability": "view", - "type": "function" + ] }, { - "inputs": [], - "name": "pause", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "type": "error", + "name": "CloneArgumentsTooLong", + "inputs": [] }, { - "inputs": [], - "name": "paused", - "outputs": [ + "type": "error", + "name": "Create2EmptyBytecode", + "inputs": [] + }, + { + "type": "error", + "name": "ERC1967InvalidImplementation", + "inputs": [ { - "internalType": "bool", - "name": "", - "type": "bool" + "name": "implementation", + "type": "address", + "internalType": "address" } - ], - "stateMutability": "view", - "type": "function" + ] }, { - "inputs": [], - "name": "pendingDefaultAdmin", - "outputs": [ + "type": "error", + "name": "ERC1967NonPayable", + "inputs": [] + }, + { + "type": "error", + "name": "EnforcedPause", + "inputs": [] + }, + { + "type": "error", + "name": "ExecutorMismatch", + "inputs": [ { - "internalType": "address", - "name": "newAdmin", - "type": "address" + "name": "expected", + "type": "address", + "internalType": "address" }, { - "internalType": "uint48", - "name": "schedule", - "type": "uint48" + "name": "actual", + "type": "address", + "internalType": "address" } - ], - "stateMutability": "view", - "type": "function" + ] }, { - "inputs": [], - "name": "pendingDefaultAdminDelay", - "outputs": [ + "type": "error", + "name": "ExpectedPause", + "inputs": [] + }, + { + "type": "error", + "name": "FailedCall", + "inputs": [] + }, + { + "type": "error", + "name": "FailedDeployment", + "inputs": [] + }, + { + "type": "error", + "name": "ImplementationNotSet", + "inputs": [] + }, + { + "type": "error", + "name": "IndexMismatch", + "inputs": [ { - "internalType": "uint48", - "name": "newDelay", - "type": "uint48" + "name": "expected", + "type": "uint96", + "internalType": "uint96" }, { - "internalType": "uint48", - "name": "schedule", - "type": "uint48" + "name": "provided", + "type": "uint96", + "internalType": "uint96" } - ], - "stateMutability": "view", - "type": "function" + ] }, { + "type": "error", + "name": "IndexOutOfRange", "inputs": [ { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "uint256", "name": "index", - "type": "uint256" - } - ], - "name": "predictWallet", - "outputs": [ - { - "internalType": "address", - "name": "wallet", - "type": "address" + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "bool", - "name": "deployed", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" + "name": "next", + "type": "uint256", + "internalType": "uint256" } - ], - "stateMutability": "view", - "type": "function" + ] }, { + "type": "error", + "name": "InsufficientBalance", "inputs": [ { - "internalType": "bytes32", - "name": "role", - "type": "bytes32" + "name": "balance", + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "address", - "name": "account", - "type": "address" + "name": "needed", + "type": "uint256", + "internalType": "uint256" } - ], - "name": "renounceRole", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + ] }, { + "type": "error", + "name": "IntentWalletMismatch", "inputs": [ { - "internalType": "bytes32", - "name": "role", - "type": "bytes32" + "name": "expected", + "type": "address", + "internalType": "address" }, { - "internalType": "address", - "name": "account", - "type": "address" + "name": "provided", + "type": "address", + "internalType": "address" } - ], - "name": "revokeRole", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + ] }, { - "inputs": [], - "name": "rollbackDefaultAdminDelay", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "type": "error", + "name": "InvalidInitialization", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidOwnerSignature", + "inputs": [] }, { + "type": "error", + "name": "NotAWallet", "inputs": [ { - "internalType": "bytes4", - "name": "interfaceId", - "type": "bytes4" - } - ], - "name": "supportsInterface", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" + "name": "account", + "type": "address", + "internalType": "address" } - ], - "stateMutability": "view", - "type": "function" + ] }, { - "inputs": [], - "name": "unpause", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "type": "error", + "name": "NotInitializing", + "inputs": [] }, { + "type": "error", + "name": "SafeCastOverflowedUintDowncast", "inputs": [ { - "internalType": "address", - "name": "newImplementation", - "type": "address" + "name": "bits", + "type": "uint8", + "internalType": "uint8" }, { - "internalType": "bytes", - "name": "data", - "type": "bytes" + "name": "value", + "type": "uint256", + "internalType": "uint256" } - ], - "name": "upgradeToAndCall", - "outputs": [], - "stateMutability": "payable", - "type": "function" + ] }, { + "type": "error", + "name": "SignatureExpired", "inputs": [ { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "walletCount", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" + "name": "deadline", + "type": "uint48", + "internalType": "uint48" } - ], - "stateMutability": "view", - "type": "function" + ] }, { - "inputs": [], - "name": "walletImplementation", - "outputs": [ + "type": "error", + "name": "UUPSUnauthorizedCallContext", + "inputs": [] + }, + { + "type": "error", + "name": "UUPSUnsupportedProxiableUUID", + "inputs": [ { - "internalType": "address", - "name": "", - "type": "address" + "name": "slot", + "type": "bytes32", + "internalType": "bytes32" } - ], - "stateMutability": "view", - "type": "function" + ] + }, + { + "type": "error", + "name": "ZeroAddress", + "inputs": [] } ] diff --git a/packages/core/scripts/agw-local/abis/manifest.json b/packages/core/scripts/agw-local/abis/manifest.json index 7a3af5d2..7c13c7e0 100644 --- a/packages/core/scripts/agw-local/abis/manifest.json +++ b/packages/core/scripts/agw-local/abis/manifest.json @@ -1,12 +1,12 @@ { "sourceRepository": "https://github.com/pushchain/push-agentic-wallets", - "sourceCommit": "e8db74815cfbbf5389593805e464fe8d85f7f735", - "deployedAbiEvidence": "AGW v4 Donut deployment; copied from the October 6 planning evidence snapshot", + "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", + "deployedAbiEvidence": "Donut v5 source compiled in an isolated tree; deployment wiring checked at block 23991912; URP/engine/validator reused from v4", "files": { - "engine.json": "32e7f3e48db6719306c436a0c81d80a2c5bcb3283b208ae043c460d483bc0180", - "factory.json": "c58ac31b81a64b4ab5b89c5aef3f6d01a405607395af71b5466d55fe9c1d5b99", - "policy.json": "b40e2a91eaa9c09cbe214621259fb7d12def00d12c756e2fd659eff4e26277c0", - "validator.json": "d2555b2f54d56ed24268af650b19ad10f2d34906b2e0c4ff78dd6de54ba34cc2", - "wallet.json": "ba68ef8f86e7154df29c4bb3ec9b90ae0d8a5193cad6e34772276475a2846ebe" + "wallet.json": "6a145964d6c43eaa6223dc8f3d59a540ac0c2f447f25c3a99007eea25de9c695", + "factory.json": "b65f66a1556d2a9ddf9aabe9f595c685c2aada436772892f5a40fb1eec846397", + "policy.json": "c7e3cd5c7f8e47be217c77ebebde4c090903cea7db63024838e434eb6f1fd77b", + "engine.json": "6e5d9cea4dbed01f06af913c1e093743b86b7432195f4a4bf90fb94b282c51b2", + "validator.json": "a4570ddc373241580de8742cbb3d9f2c837094c65bfd1cdd52243ca0c38196fd" } } diff --git a/packages/core/scripts/agw-local/abis/policy.json b/packages/core/scripts/agw-local/abis/policy.json index c8f2f576..88e39505 100644 --- a/packages/core/scripts/agw-local/abis/policy.json +++ b/packages/core/scripts/agw-local/abis/policy.json @@ -1,2157 +1,2157 @@ [ { + "type": "constructor", "inputs": [], - "stateMutability": "nonpayable", - "type": "constructor" + "stateMutability": "nonpayable" }, { - "inputs": [ + "type": "function", + "name": "SEND_OUTBOUND_SELECTOR", + "inputs": [], + "outputs": [ { - "internalType": "uint256", - "name": "length", - "type": "uint256" + "name": "", + "type": "bytes4", + "internalType": "bytes4" } ], - "name": "AllowListOutOfRange", - "type": "error" + "stateMutability": "view" }, { - "inputs": [ + "type": "function", + "name": "SESSION_ENGINE", + "inputs": [], + "outputs": [ { - "internalType": "bytes32", - "name": "outboundTxId", - "type": "bytes32" + "name": "", + "type": "address", + "internalType": "address" } ], - "name": "AlreadyCredited", - "type": "error" + "stateMutability": "view" }, { - "inputs": [ + "type": "function", + "name": "UNIVERSAL_EXECUTOR_MODULE", + "inputs": [], + "outputs": [ { - "internalType": "ConfigId", - "name": "id", - "type": "bytes32" + "name": "", + "type": "address", + "internalType": "address" } ], - "name": "AlreadyInitialized", - "type": "error" + "stateMutability": "view" }, { - "inputs": [ - { - "internalType": "uint256", - "name": "i", - "type": "uint256" - }, + "type": "function", + "name": "UNIVERSAL_GATEWAY_PC", + "inputs": [], + "outputs": [ { - "internalType": "uint256", - "name": "j", - "type": "uint256" + "name": "", + "type": "address", + "internalType": "address" } ], - "name": "AmbiguousRule", - "type": "error" + "stateMutability": "view" }, { + "type": "function", + "name": "assertSpent", "inputs": [ { - "internalType": "uint256", - "name": "amount", - "type": "uint256" + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" }, { - "internalType": "uint256", - "name": "cap", - "type": "uint256" - } - ], - "name": "AmountExceedsCap", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "AmountExceedsU64", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "actual", - "type": "bytes32" + "name": "account", + "type": "address", + "internalType": "address" }, { - "internalType": "uint256", - "name": "index", - "type": "uint256" + "name": "expectedValueSpent", + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "bytes32", - "name": "expected", - "type": "bytes32" - } - ], - "name": "ArgPinMismatch", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "length", - "type": "uint256" - } - ], - "name": "AssetListOutOfRange", - "type": "error" - }, - { - "inputs": [ + "name": "expectedAmountSpent", + "type": "uint256", + "internalType": "uint256" + }, { - "internalType": "address", - "name": "token", - "type": "address" + "name": "expectedCalls", + "type": "uint32", + "internalType": "uint32" } ], - "name": "AssetNotAllowed", - "type": "error" + "outputs": [], + "stateMutability": "view" }, { + "type": "function", + "name": "assertSpent", "inputs": [ { - "internalType": "address", - "name": "token", - "type": "address" + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" }, { - "internalType": "uint256", - "name": "expected", - "type": "uint256" + "name": "account", + "type": "address", + "internalType": "address" }, { - "internalType": "uint256", - "name": "actual", - "type": "uint256" - } - ], - "name": "AssetSpentMismatch", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "count", - "type": "uint256" + "name": "expectedSpent", + "type": "uint256[]", + "internalType": "uint256[]" } ], - "name": "BatchSizeOutOfRange", - "type": "error" + "outputs": [], + "stateMutability": "view" }, { + "type": "function", + "name": "checkAction", "inputs": [ { - "internalType": "address", - "name": "expected", - "type": "address" + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" }, { - "internalType": "address", - "name": "actual", - "type": "address" - } - ], - "name": "BeneficiaryMismatch", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint32", - "name": "callsUsed", - "type": "uint32" + "name": "account", + "type": "address", + "internalType": "address" }, { - "internalType": "uint32", - "name": "maxCalls", - "type": "uint32" - } - ], - "name": "CallLimitReached", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", "name": "target", - "type": "address" + "type": "address", + "internalType": "address" }, { - "internalType": "bytes4", - "name": "selector", - "type": "bytes4" + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "data", + "type": "bytes", + "internalType": "bytes" } ], - "name": "CallNotAllowed", - "type": "error" - }, - { - "inputs": [ + "outputs": [ { - "internalType": "uint256", - "name": "length", - "type": "uint256" + "name": "", + "type": "uint256", + "internalType": "uint256" } ], - "name": "CalldataTooShort", - "type": "error" + "stateMutability": "nonpayable" }, { + "type": "function", + "name": "creditRevert", "inputs": [ { - "internalType": "uint256", - "name": "actualLength", - "type": "uint256" + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" }, { - "internalType": "uint256", - "name": "needed", - "type": "uint256" - } - ], - "name": "CalldataTooShortForAmount", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "actualLength", - "type": "uint256" + "name": "account", + "type": "address", + "internalType": "address" }, { - "internalType": "uint256", - "name": "index", - "type": "uint256" + "name": "outboundTxId", + "type": "bytes32", + "internalType": "bytes32" }, { - "internalType": "uint256", - "name": "needed", - "type": "uint256" - } - ], - "name": "CalldataTooShortForPin", - "type": "error" - }, - { - "inputs": [ + "name": "token", + "type": "address", + "internalType": "address" + }, { - "internalType": "address", - "name": "caller", - "type": "address" + "name": "amount", + "type": "uint256", + "internalType": "uint256" } ], - "name": "CallerIsNotUEModule", - "type": "error" + "outputs": [], + "stateMutability": "nonpayable" }, { + "type": "function", + "name": "getConfig", "inputs": [ { - "internalType": "uint256", - "name": "accountIndex", - "type": "uint256" + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" }, { - "internalType": "bytes32", "name": "account", - "type": "bytes32" + "type": "address", + "internalType": "address" } ], - "name": "CeaAccountAtUnpinnedIndex", - "type": "error" - }, - { - "inputs": [], - "name": "CeaAccountsMissExpectedCEA", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "declared", - "type": "bytes32" - }, + "outputs": [ { - "internalType": "bytes32", - "name": "assetChain", - "type": "bytes32" + "name": "", + "type": "tuple", + "internalType": "struct Config", + "components": [ + { + "name": "initialized", + "type": "bool", + "internalType": "bool" + }, + { + "name": "validUntil", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "expectedCEA", + "type": "address", + "internalType": "address" + }, + { + "name": "maxGasPerCall", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "assets", + "type": "tuple[]", + "internalType": "struct AssetCapState[]", + "components": [ + { + "name": "token", + "type": "address", + "internalType": "address" + }, + { + "name": "maxPerCall", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxTotal", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "spent", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "allowedCalls", + "type": "tuple[]", + "internalType": "struct AllowedCall[]", + "components": [ + { + "name": "target", + "type": "address", + "internalType": "address" + }, + { + "name": "selector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "beneficiaryOffset", + "type": "uint16", + "internalType": "uint16" + }, + { + "name": "hasBeneficiary", + "type": "bool", + "internalType": "bool" + }, + { + "name": "maxValue", + "type": "uint256", + "internalType": "uint256" + } + ] + } + ] } ], - "name": "ChainMismatch", - "type": "error" + "stateMutability": "view" }, { + "type": "function", + "name": "getMode", "inputs": [ { - "internalType": "uint256", - "name": "rule", - "type": "uint256" + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" }, { - "internalType": "uint8", - "name": "len", - "type": "uint8" + "name": "account", + "type": "address", + "internalType": "address" } ], - "name": "DiscriminatorLenOutOfRange", - "type": "error" - }, - { - "inputs": [ + "outputs": [ { - "internalType": "address", - "name": "token", - "type": "address" + "name": "", + "type": "tuple", + "internalType": "struct ModeSlot", + "components": [ + { + "name": "initialized", + "type": "bool", + "internalType": "bool" + }, + { + "name": "mode", + "type": "uint8", + "internalType": "enum RulesType" + }, + { + "name": "vm", + "type": "uint8", + "internalType": "enum VmFamily" + }, + { + "name": "chainHash", + "type": "bytes32", + "internalType": "bytes32" + } + ] } ], - "name": "DuplicateAsset", - "type": "error" + "stateMutability": "view" }, { + "type": "function", + "name": "getNativeConfig", "inputs": [ { - "internalType": "uint256", - "name": "first", - "type": "uint256" + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" }, { - "internalType": "uint256", - "name": "second", - "type": "uint256" + "name": "account", + "type": "address", + "internalType": "address" } ], - "name": "DuplicateSvmPin", - "type": "error" - }, - { - "inputs": [], - "name": "EmptyChain", - "type": "error" - }, - { - "inputs": [ + "outputs": [ { - "internalType": "address", - "name": "target", - "type": "address" + "name": "", + "type": "tuple", + "internalType": "struct NativeConfig", + "components": [ + { + "name": "initialized", + "type": "bool", + "internalType": "bool" + }, + { + "name": "validUntil", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "target", + "type": "address", + "internalType": "address" + }, + { + "name": "selector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "maxValuePerCall", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxValueTotal", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "valueSpent", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amount", + "type": "tuple", + "internalType": "struct AmountRule", + "components": [ + { + "name": "enabled", + "type": "bool", + "internalType": "bool" + }, + { + "name": "offset", + "type": "uint16", + "internalType": "uint16" + }, + { + "name": "maxPerCall", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxTotal", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "amountSpent", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxCalls", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "callsUsed", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "pins", + "type": "tuple[]", + "internalType": "struct ArgPin[]", + "components": [ + { + "name": "offset", + "type": "uint16", + "internalType": "uint16" + }, + { + "name": "expected", + "type": "bytes32", + "internalType": "bytes32" + } + ] + } + ] } ], - "name": "ForbiddenInnerTarget", - "type": "error" + "stateMutability": "view" }, { + "type": "function", + "name": "getSvmConfig", "inputs": [ { - "internalType": "uint256", - "name": "rule", - "type": "uint256" + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" }, { - "internalType": "bytes32", - "name": "program", - "type": "bytes32" + "name": "account", + "type": "address", + "internalType": "address" } ], - "name": "ForbiddenProgramInAllowList", - "type": "error" - }, - { - "inputs": [ + "outputs": [ { - "internalType": "bytes32", - "name": "program", - "type": "bytes32" + "name": "", + "type": "tuple", + "internalType": "struct SvmConfig", + "components": [ + { + "name": "initialized", + "type": "bool", + "internalType": "bool" + }, + { + "name": "validUntil", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "expectedCEA", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "gatewayProgram", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "maxGasPerCall", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "assets", + "type": "tuple[]", + "internalType": "struct AssetCapState[]", + "components": [ + { + "name": "token", + "type": "address", + "internalType": "address" + }, + { + "name": "maxPerCall", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxTotal", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "spent", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "ceaAccounts", + "type": "bytes32[]", + "internalType": "bytes32[]" + }, + { + "name": "programs", + "type": "tuple[]", + "internalType": "struct AllowedProgram[]", + "components": [ + { + "name": "program", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "discriminator", + "type": "bytes8", + "internalType": "bytes8" + }, + { + "name": "discriminatorLen", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "dataless", + "type": "bool", + "internalType": "bool" + }, + { + "name": "maxAccounts", + "type": "uint8", + "internalType": "uint8" + } + ] + }, + { + "name": "pins", + "type": "tuple[]", + "internalType": "struct SvmAccountPin[]", + "components": [ + { + "name": "ruleIndex", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "accountIndex", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "expected", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "name": "dataPins", + "type": "tuple[]", + "internalType": "struct SvmDataPin[]", + "components": [ + { + "name": "ruleIndex", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "fromEnd", + "type": "bool", + "internalType": "bool" + }, + { + "name": "offset", + "type": "uint16", + "internalType": "uint16" + }, + { + "name": "offsetB", + "type": "uint16", + "internalType": "uint16" + }, + { + "name": "len", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "mode", + "type": "uint8", + "internalType": "enum SvmDataPinMode" + }, + { + "name": "expected", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "num", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "den", + "type": "uint64", + "internalType": "uint64" + } + ] + } + ] } ], - "name": "ForbiddenTargetProgram", - "type": "error" + "stateMutability": "view" }, { + "type": "function", + "name": "initialize", "inputs": [ { - "internalType": "uint256", - "name": "index", - "type": "uint256" + "name": "universalGatewayPC", + "type": "address", + "internalType": "address" }, { - "internalType": "uint256", - "name": "value", - "type": "uint256" + "name": "universalExecutorModule", + "type": "address", + "internalType": "address" }, { - "internalType": "uint256", - "name": "maxValue", - "type": "uint256" + "name": "sessionEngine", + "type": "address", + "internalType": "address" } ], - "name": "InnerValueExceedsAllowance", - "type": "error" + "outputs": [], + "stateMutability": "nonpayable" }, { + "type": "function", + "name": "initializeWithMultiplexer", "inputs": [ { - "internalType": "address", - "name": "asset", - "type": "address" + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "configId", + "type": "bytes32", + "internalType": "ConfigId" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" } ], - "name": "InvalidAsset", - "type": "error" + "outputs": [], + "stateMutability": "nonpayable" }, { + "type": "function", + "name": "isCredited", "inputs": [ { - "internalType": "uint256", - "name": "index", - "type": "uint256" + "name": "outboundTxId", + "type": "bytes32", + "internalType": "bytes32" } ], - "name": "InvalidCeaAccount", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidConfigField", - "type": "error" - }, - { - "inputs": [ + "outputs": [ { - "internalType": "uint48", - "name": "validUntil", - "type": "uint48" + "name": "", + "type": "bool", + "internalType": "bool" } ], - "name": "InvalidExpiry", - "type": "error" + "stateMutability": "view" }, { + "type": "function", + "name": "pushChainHash", "inputs": [], - "name": "InvalidInitialization", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "expected", - "type": "address" - }, + "outputs": [ { - "internalType": "address", - "name": "actual", - "type": "address" + "name": "", + "type": "bytes32", + "internalType": "bytes32" } ], - "name": "InvalidRevertRecipient", - "type": "error" + "stateMutability": "view" }, { + "type": "function", + "name": "supportsInterface", "inputs": [ { - "internalType": "bytes4", - "name": "selector", - "type": "bytes4" + "name": "iid", + "type": "bytes4", + "internalType": "bytes4" } ], - "name": "InvalidSelector", - "type": "error" + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "pure" }, { + "type": "function", + "name": "version", "inputs": [], - "name": "InvalidSvmConfigField", - "type": "error" + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "pure" }, { + "type": "event", + "name": "Initialized", "inputs": [ { - "internalType": "address", - "name": "target", - "type": "address" + "name": "version", + "type": "uint64", + "indexed": false, + "internalType": "uint64" } ], - "name": "InvalidTarget", - "type": "error" - }, - { - "inputs": [], - "name": "MalformedInnerCalldata", - "type": "error" + "anonymous": false }, { + "type": "event", + "name": "NativeCallMetered", "inputs": [ { - "internalType": "uint256", - "name": "length", - "type": "uint256" - } - ], - "name": "MalformedOutboundRequest", - "type": "error" - }, - { - "inputs": [ + "name": "id", + "type": "bytes32", + "indexed": true, + "internalType": "ConfigId" + }, { - "internalType": "uint8", - "name": "code", - "type": "uint8" - } - ], - "name": "MalformedSvmPayload", - "type": "error" - }, - { - "inputs": [ + "name": "multiplexer", + "type": "address", + "indexed": true, + "internalType": "address" + }, { - "internalType": "uint256", - "name": "amount", - "type": "uint256" + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" }, { - "internalType": "uint256", - "name": "cap", - "type": "uint256" + "name": "value", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" } ], - "name": "NativeAmountExceedsCap", - "type": "error" + "anonymous": false }, { + "type": "event", + "name": "OutboundMetered", "inputs": [ { - "internalType": "address", - "name": "target", - "type": "address" + "name": "id", + "type": "bytes32", + "indexed": true, + "internalType": "ConfigId" + }, + { + "name": "multiplexer", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "token", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" } ], - "name": "NativeTargetIsGateway", - "type": "error" - }, - { - "inputs": [], - "name": "NativeTargetZero", - "type": "error" + "anonymous": false }, { + "type": "event", + "name": "PolicySet", "inputs": [ { - "internalType": "ConfigId", "name": "id", - "type": "bytes32" + "type": "bytes32", + "indexed": false, + "internalType": "ConfigId" + }, + { + "name": "multiplexer", + "type": "address", + "indexed": false, + "internalType": "address" }, { - "internalType": "address", "name": "account", - "type": "address" + "type": "address", + "indexed": false, + "internalType": "address" } ], - "name": "NotInitialized", - "type": "error" - }, - { - "inputs": [], - "name": "NotInitializing", - "type": "error" + "anonymous": false }, { + "type": "event", + "name": "RevertCredited", "inputs": [ { - "internalType": "uint256", - "name": "value", - "type": "uint256" + "name": "outboundTxId", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" }, { - "internalType": "uint256", - "name": "cap", - "type": "uint256" + "name": "id", + "type": "bytes32", + "indexed": true, + "internalType": "ConfigId" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "token", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "amountApplied", + "type": "uint256", + "indexed": false, + "internalType": "uint256" } ], - "name": "PCValueExceedsCap", - "type": "error" - }, - { - "inputs": [], - "name": "PayloadNotMulticall", - "type": "error" + "anonymous": false }, { + "type": "event", + "name": "RulesConfigured", "inputs": [ { - "internalType": "ConfigId", "name": "id", - "type": "bytes32" + "type": "bytes32", + "indexed": true, + "internalType": "ConfigId" }, { - "internalType": "address", "name": "multiplexer", - "type": "address" + "type": "address", + "indexed": true, + "internalType": "address" }, { - "internalType": "address", "name": "account", - "type": "address" + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "mode", + "type": "uint8", + "indexed": false, + "internalType": "enum RulesType" + }, + { + "name": "vm", + "type": "uint8", + "indexed": false, + "internalType": "enum VmFamily" + }, + { + "name": "chainHash", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" } ], - "name": "PolicyNotInitialized", - "type": "error" + "anonymous": false }, { + "type": "error", + "name": "AllowListOutOfRange", "inputs": [ { - "internalType": "uint256", "name": "length", - "type": "uint256" + "type": "uint256", + "internalType": "uint256" } - ], - "name": "ProgramListOutOfRange", - "type": "error" + ] }, { + "type": "error", + "name": "AlreadyCredited", "inputs": [ { - "internalType": "bytes32", - "name": "program", - "type": "bytes32" - }, - { - "internalType": "bytes8", - "name": "discriminator", - "type": "bytes8" + "name": "outboundTxId", + "type": "bytes32", + "internalType": "bytes32" } - ], - "name": "ProgramNotAllowed", - "type": "error" - }, - { - "inputs": [], - "name": "RecipientMustBeEmpty", - "type": "error" + ] }, { + "type": "error", + "name": "AlreadyInitialized", "inputs": [ { - "internalType": "uint256", - "name": "length", - "type": "uint256" + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" } - ], - "name": "RecipientNotPubkey", - "type": "error" + ] }, { + "type": "error", + "name": "AmbiguousRule", "inputs": [ { - "internalType": "bytes32", - "name": "recipient", - "type": "bytes32" + "name": "i", + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "bytes32", - "name": "target", - "type": "bytes32" + "name": "j", + "type": "uint256", + "internalType": "uint256" } - ], - "name": "RecipientTargetMismatch", - "type": "error" + ] }, { + "type": "error", + "name": "AmountExceedsCap", "inputs": [ { - "internalType": "uint256", - "name": "rule", - "type": "uint256" + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "cap", + "type": "uint256", + "internalType": "uint256" } - ], - "name": "RuleWithoutPin", - "type": "error" + ] }, { + "type": "error", + "name": "AmountExceedsU64", "inputs": [ { - "internalType": "uint48", - "name": "validUntil", - "type": "uint48" + "name": "amount", + "type": "uint256", + "internalType": "uint256" } - ], - "name": "RulesExpired", - "type": "error" + ] }, { + "type": "error", + "name": "ArgPinMismatch", "inputs": [ { - "internalType": "bytes4", "name": "actual", - "type": "bytes4" + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "index", + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "bytes4", "name": "expected", - "type": "bytes4" + "type": "bytes32", + "internalType": "bytes32" } - ], - "name": "SelectorMismatch", - "type": "error" + ] }, { + "type": "error", + "name": "AssetListOutOfRange", "inputs": [ { - "internalType": "uint256", - "name": "expected", - "type": "uint256" - }, + "name": "length", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "AssetNotAllowed", + "inputs": [ { - "internalType": "uint256", - "name": "actual", - "type": "uint256" + "name": "token", + "type": "address", + "internalType": "address" } - ], - "name": "SpentLengthMismatch", - "type": "error" + ] }, { + "type": "error", + "name": "AssetSpentMismatch", "inputs": [ { - "internalType": "uint256", + "name": "token", + "type": "address", + "internalType": "address" + }, + { "name": "expected", - "type": "uint256" + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "uint256", "name": "actual", - "type": "uint256" + "type": "uint256", + "internalType": "uint256" } - ], - "name": "SpentMismatch", - "type": "error" + ] }, { + "type": "error", + "name": "BatchSizeOutOfRange", "inputs": [ { - "internalType": "uint256", - "name": "pin", - "type": "uint256" - }, - { - "internalType": "uint256", "name": "count", - "type": "uint256" - }, - { - "internalType": "uint8", - "name": "needed", - "type": "uint8" + "type": "uint256", + "internalType": "uint256" } - ], - "name": "SvmAccountCountBelowPin", - "type": "error" + ] }, { + "type": "error", + "name": "BeneficiaryMismatch", "inputs": [ { - "internalType": "uint256", - "name": "count", - "type": "uint256" + "name": "expected", + "type": "address", + "internalType": "address" }, { - "internalType": "uint8", - "name": "expected", - "type": "uint8" + "name": "actual", + "type": "address", + "internalType": "address" } - ], - "name": "SvmAccountCountMismatch", - "type": "error" + ] }, { + "type": "error", + "name": "CallLimitReached", "inputs": [ { - "internalType": "uint256", - "name": "pin", - "type": "uint256" + "name": "callsUsed", + "type": "uint32", + "internalType": "uint32" }, { - "internalType": "uint8", - "name": "accountIndex", - "type": "uint8" - }, + "name": "maxCalls", + "type": "uint32", + "internalType": "uint32" + } + ] + }, + { + "type": "error", + "name": "CallNotAllowed", + "inputs": [ { - "internalType": "bytes32", - "name": "expected", - "type": "bytes32" + "name": "target", + "type": "address", + "internalType": "address" }, { - "internalType": "bytes32", - "name": "actual", - "type": "bytes32" + "name": "selector", + "type": "bytes4", + "internalType": "bytes4" } - ], - "name": "SvmAccountPinMismatch", - "type": "error" + ] }, { + "type": "error", + "name": "CalldataTooShort", "inputs": [ { - "internalType": "uint256", - "name": "count", - "type": "uint256" + "name": "length", + "type": "uint256", + "internalType": "uint256" } - ], - "name": "SvmAccountsOutOfRange", - "type": "error" + ] }, { + "type": "error", + "name": "CalldataTooShortForAmount", "inputs": [ { - "internalType": "uint256", - "name": "pin", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "actual", - "type": "uint256" + "name": "actualLength", + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "uint256", - "name": "ceiling", - "type": "uint256" + "name": "needed", + "type": "uint256", + "internalType": "uint256" } - ], - "name": "SvmDataCeilingExceeded", - "type": "error" + ] }, { + "type": "error", + "name": "CalldataTooShortForPin", "inputs": [ { - "internalType": "uint256", - "name": "pin", - "type": "uint256" + "name": "actualLength", + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "uint256", - "name": "actual", - "type": "uint256" + "name": "index", + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "uint256", - "name": "floor", - "type": "uint256" + "name": "needed", + "type": "uint256", + "internalType": "uint256" } - ], - "name": "SvmDataFloorNotMet", - "type": "error" + ] }, { + "type": "error", + "name": "CallerIsNotUEModule", "inputs": [ { - "internalType": "uint256", - "name": "pin", - "type": "uint256" + "name": "caller", + "type": "address", + "internalType": "address" } - ], - "name": "SvmDataPinInvalid", - "type": "error" + ] }, { + "type": "error", + "name": "CeaAccountAtUnpinnedIndex", "inputs": [ { - "internalType": "uint256", - "name": "pin", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "expected", - "type": "bytes32" + "name": "accountIndex", + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "bytes32", - "name": "actual", - "type": "bytes32" + "name": "account", + "type": "bytes32", + "internalType": "bytes32" } - ], - "name": "SvmDataPinMismatch", - "type": "error" + ] + }, + { + "type": "error", + "name": "CeaAccountsMissExpectedCEA", + "inputs": [] }, { + "type": "error", + "name": "ChainMismatch", "inputs": [ { - "internalType": "uint256", - "name": "pin", - "type": "uint256" + "name": "declared", + "type": "bytes32", + "internalType": "bytes32" }, { - "internalType": "uint256", - "name": "a", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "b", - "type": "uint256" - }, + "name": "assetChain", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "DiscriminatorLenOutOfRange", + "inputs": [ { - "internalType": "uint64", - "name": "num", - "type": "uint64" + "name": "rule", + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "uint64", - "name": "den", - "type": "uint64" + "name": "len", + "type": "uint8", + "internalType": "uint8" } - ], - "name": "SvmDataRatioNotMet", - "type": "error" + ] }, { + "type": "error", + "name": "DuplicateAsset", "inputs": [ { - "internalType": "uint256", - "name": "pin", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "ixLen", - "type": "uint256" + "name": "token", + "type": "address", + "internalType": "address" } - ], - "name": "SvmDataTooShortForPin", - "type": "error" + ] }, { + "type": "error", + "name": "DuplicateSvmPin", "inputs": [ { - "internalType": "uint8", - "name": "instructionId", - "type": "uint8" + "name": "first", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "second", + "type": "uint256", + "internalType": "uint256" } - ], - "name": "SvmInstructionNotExecute", - "type": "error" + ] + }, + { + "type": "error", + "name": "EmptyChain", + "inputs": [] }, { + "type": "error", + "name": "ForbiddenInnerTarget", "inputs": [ { - "internalType": "uint256", - "name": "length", - "type": "uint256" + "name": "target", + "type": "address", + "internalType": "address" } - ], - "name": "SvmIxDataTooLong", - "type": "error" + ] }, { + "type": "error", + "name": "ForbiddenProgramInAllowList", "inputs": [ { - "internalType": "uint256", "name": "rule", - "type": "uint256" + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "uint8", - "name": "maxAccounts", - "type": "uint8" + "name": "program", + "type": "bytes32", + "internalType": "bytes32" } - ], - "name": "SvmMaxAccountsOutOfRange", - "type": "error" + ] }, { - "inputs": [], - "name": "SvmPayloadEmpty", - "type": "error" + "type": "error", + "name": "ForbiddenTargetProgram", + "inputs": [ + { + "name": "program", + "type": "bytes32", + "internalType": "bytes32" + } + ] }, { + "type": "error", + "name": "InnerValueExceedsAllowance", "inputs": [ { - "internalType": "uint256", - "name": "pin", - "type": "uint256" + "name": "index", + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "uint8", - "name": "accountIndex", - "type": "uint8" + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxValue", + "type": "uint256", + "internalType": "uint256" } - ], - "name": "SvmPinIndexOutOfRange", - "type": "error" + ] + }, + { + "type": "error", + "name": "InvalidAsset", + "inputs": [ + { + "name": "asset", + "type": "address", + "internalType": "address" + } + ] }, { + "type": "error", + "name": "InvalidCeaAccount", "inputs": [ { - "internalType": "uint256", - "name": "pin", - "type": "uint256" - }, + "name": "index", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "InvalidConfigField", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidExpiry", + "inputs": [ { - "internalType": "uint8", - "name": "rule", - "type": "uint8" + "name": "validUntil", + "type": "uint48", + "internalType": "uint48" } - ], - "name": "SvmPinRuleOutOfRange", - "type": "error" + ] + }, + { + "type": "error", + "name": "InvalidInitialization", + "inputs": [] }, { + "type": "error", + "name": "InvalidRevertRecipient", "inputs": [ { - "internalType": "address", - "name": "actual", - "type": "address" + "name": "expected", + "type": "address", + "internalType": "address" }, { - "internalType": "address", - "name": "expected", - "type": "address" + "name": "actual", + "type": "address", + "internalType": "address" } - ], - "name": "TargetMismatch", - "type": "error" + ] }, { + "type": "error", + "name": "InvalidSelector", "inputs": [ { - "internalType": "uint256", - "name": "count", - "type": "uint256" + "name": "selector", + "type": "bytes4", + "internalType": "bytes4" } - ], - "name": "TooManyCeaAccounts", - "type": "error" + ] + }, + { + "type": "error", + "name": "InvalidSvmConfigField", + "inputs": [] }, { + "type": "error", + "name": "InvalidTarget", "inputs": [ { - "internalType": "uint256", - "name": "count", - "type": "uint256" + "name": "target", + "type": "address", + "internalType": "address" } - ], - "name": "TooManyPins", - "type": "error" + ] + }, + { + "type": "error", + "name": "MalformedInnerCalldata", + "inputs": [] }, { + "type": "error", + "name": "MalformedOutboundRequest", "inputs": [ { - "internalType": "uint256", - "name": "count", - "type": "uint256" + "name": "length", + "type": "uint256", + "internalType": "uint256" } - ], - "name": "TooManySvmDataPins", - "type": "error" + ] }, { + "type": "error", + "name": "MalformedSvmPayload", "inputs": [ { - "internalType": "uint256", - "name": "count", - "type": "uint256" + "name": "code", + "type": "uint8", + "internalType": "uint8" } - ], - "name": "TooManySvmPins", - "type": "error" + ] }, { + "type": "error", + "name": "NativeAmountExceedsCap", "inputs": [ { - "internalType": "uint256", - "name": "newSpent", - "type": "uint256" + "name": "amount", + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "uint256", "name": "cap", - "type": "uint256" + "type": "uint256", + "internalType": "uint256" } - ], - "name": "TotalNativeAmountExceeded", - "type": "error" + ] + }, + { + "type": "error", + "name": "NativeTargetIsGateway", + "inputs": [ + { + "name": "target", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "NativeTargetZero", + "inputs": [] }, { + "type": "error", + "name": "NotInitialized", "inputs": [ { - "internalType": "uint256", - "name": "wouldBeTotal", - "type": "uint256" + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" }, { - "internalType": "uint256", - "name": "cap", - "type": "uint256" + "name": "account", + "type": "address", + "internalType": "address" } - ], - "name": "TotalSpendCapExceeded", - "type": "error" + ] }, { + "type": "error", + "name": "NotInitializing", + "inputs": [] + }, + { + "type": "error", + "name": "PCValueExceedsCap", "inputs": [ { - "internalType": "uint256", - "name": "newSpent", - "type": "uint256" + "name": "value", + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "uint256", "name": "cap", - "type": "uint256" + "type": "uint256", + "internalType": "uint256" } - ], - "name": "TotalValueExceeded", - "type": "error" + ] }, { - "inputs": [], - "name": "UncappedGasSwapRejected", - "type": "error" + "type": "error", + "name": "PayloadNotMulticall", + "inputs": [] }, { + "type": "error", + "name": "PolicyNotInitialized", "inputs": [ { - "internalType": "uint256", - "name": "version", - "type": "uint256" + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" + }, + { + "name": "multiplexer", + "type": "address", + "internalType": "address" + }, + { + "name": "account", + "type": "address", + "internalType": "address" } - ], - "name": "UnsupportedEnvelopeVersion", - "type": "error" + ] }, { + "type": "error", + "name": "ProgramListOutOfRange", "inputs": [ { - "internalType": "bytes32", - "name": "chainHash", - "type": "bytes32" + "name": "length", + "type": "uint256", + "internalType": "uint256" } - ], - "name": "UnsupportedNamespace", - "type": "error" + ] }, { + "type": "error", + "name": "ProgramNotAllowed", "inputs": [ { - "internalType": "uint256", - "name": "value", - "type": "uint256" + "name": "program", + "type": "bytes32", + "internalType": "bytes32" }, { - "internalType": "uint256", - "name": "cap", - "type": "uint256" + "name": "discriminator", + "type": "bytes8", + "internalType": "bytes8" } - ], - "name": "ValueExceedsCap", - "type": "error" + ] + }, + { + "type": "error", + "name": "RecipientMustBeEmpty", + "inputs": [] }, { + "type": "error", + "name": "RecipientNotPubkey", "inputs": [ { - "internalType": "uint256", "name": "length", - "type": "uint256" + "type": "uint256", + "internalType": "uint256" } - ], - "name": "ValueOnlyCalldataNotEmpty", - "type": "error" + ] }, { - "inputs": [], - "name": "ValueOnlyWithAmountRule", - "type": "error" + "type": "error", + "name": "RecipientTargetMismatch", + "inputs": [ + { + "name": "recipient", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "target", + "type": "bytes32", + "internalType": "bytes32" + } + ] }, { - "inputs": [], - "name": "ValueOnlyWithPins", - "type": "error" + "type": "error", + "name": "RuleWithoutPin", + "inputs": [ + { + "name": "rule", + "type": "uint256", + "internalType": "uint256" + } + ] }, { + "type": "error", + "name": "RulesExpired", "inputs": [ { - "internalType": "enum RulesType", - "name": "actual", - "type": "uint8" + "name": "validUntil", + "type": "uint48", + "internalType": "uint48" } - ], - "name": "WrongModeForCall", - "type": "error" + ] }, { + "type": "error", + "name": "SelectorMismatch", "inputs": [ { - "internalType": "enum VmFamily", "name": "actual", - "type": "uint8" + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "expected", + "type": "bytes4", + "internalType": "bytes4" } - ], - "name": "WrongVmForCall", - "type": "error" - }, - { - "inputs": [], - "name": "ZeroAddress", - "type": "error" + ] }, { - "anonymous": false, + "type": "error", + "name": "SpentLengthMismatch", "inputs": [ { - "indexed": false, - "internalType": "uint64", - "name": "version", - "type": "uint64" + "name": "expected", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "actual", + "type": "uint256", + "internalType": "uint256" } - ], - "name": "Initialized", - "type": "event" + ] }, { - "anonymous": false, + "type": "error", + "name": "SpentMismatch", "inputs": [ { - "indexed": true, - "internalType": "ConfigId", - "name": "id", - "type": "bytes32" + "name": "expected", + "type": "uint256", + "internalType": "uint256" }, { - "indexed": true, - "internalType": "address", - "name": "multiplexer", - "type": "address" - }, + "name": "actual", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "SvmAccountCountBelowPin", + "inputs": [ { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" + "name": "pin", + "type": "uint256", + "internalType": "uint256" }, { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" + "name": "count", + "type": "uint256", + "internalType": "uint256" }, { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" + "name": "needed", + "type": "uint8", + "internalType": "uint8" } - ], - "name": "NativeCallMetered", - "type": "event" + ] }, { - "anonymous": false, + "type": "error", + "name": "SvmAccountCountMismatch", "inputs": [ { - "indexed": true, - "internalType": "ConfigId", - "name": "id", - "type": "bytes32" + "name": "count", + "type": "uint256", + "internalType": "uint256" }, { - "indexed": true, - "internalType": "address", - "name": "multiplexer", - "type": "address" - }, + "name": "expected", + "type": "uint8", + "internalType": "uint8" + } + ] + }, + { + "type": "error", + "name": "SvmAccountPinMismatch", + "inputs": [ { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" + "name": "pin", + "type": "uint256", + "internalType": "uint256" }, { - "indexed": false, - "internalType": "address", - "name": "token", - "type": "address" + "name": "accountIndex", + "type": "uint8", + "internalType": "uint8" }, { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" + "name": "expected", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "actual", + "type": "bytes32", + "internalType": "bytes32" } - ], - "name": "OutboundMetered", - "type": "event" + ] }, { - "anonymous": false, + "type": "error", + "name": "SvmAccountsOutOfRange", "inputs": [ { - "indexed": false, - "internalType": "ConfigId", - "name": "id", - "type": "bytes32" + "name": "count", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "SvmDataCeilingExceeded", + "inputs": [ + { + "name": "pin", + "type": "uint256", + "internalType": "uint256" }, { - "indexed": false, - "internalType": "address", - "name": "multiplexer", - "type": "address" + "name": "actual", + "type": "uint256", + "internalType": "uint256" }, { - "indexed": false, - "internalType": "address", - "name": "account", - "type": "address" + "name": "ceiling", + "type": "uint256", + "internalType": "uint256" } - ], - "name": "PolicySet", - "type": "event" + ] }, { - "anonymous": false, + "type": "error", + "name": "SvmDataFloorNotMet", "inputs": [ { - "indexed": true, - "internalType": "bytes32", - "name": "outboundTxId", - "type": "bytes32" + "name": "pin", + "type": "uint256", + "internalType": "uint256" }, { - "indexed": true, - "internalType": "ConfigId", - "name": "id", - "type": "bytes32" + "name": "actual", + "type": "uint256", + "internalType": "uint256" }, { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" + "name": "floor", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "SvmDataPinInvalid", + "inputs": [ + { + "name": "pin", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "SvmDataPinMismatch", + "inputs": [ + { + "name": "pin", + "type": "uint256", + "internalType": "uint256" }, { - "indexed": false, - "internalType": "address", - "name": "token", - "type": "address" + "name": "expected", + "type": "bytes32", + "internalType": "bytes32" }, { - "indexed": false, - "internalType": "uint256", - "name": "amountApplied", - "type": "uint256" + "name": "actual", + "type": "bytes32", + "internalType": "bytes32" } - ], - "name": "RevertCredited", - "type": "event" + ] }, { - "anonymous": false, + "type": "error", + "name": "SvmDataRatioNotMet", "inputs": [ { - "indexed": true, - "internalType": "ConfigId", - "name": "id", - "type": "bytes32" - }, - { - "indexed": true, - "internalType": "address", - "name": "multiplexer", - "type": "address" + "name": "pin", + "type": "uint256", + "internalType": "uint256" }, { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" + "name": "a", + "type": "uint256", + "internalType": "uint256" }, { - "indexed": false, - "internalType": "enum RulesType", - "name": "mode", - "type": "uint8" + "name": "b", + "type": "uint256", + "internalType": "uint256" }, { - "indexed": false, - "internalType": "enum VmFamily", - "name": "vm", - "type": "uint8" + "name": "num", + "type": "uint64", + "internalType": "uint64" }, { - "indexed": false, - "internalType": "bytes32", - "name": "chainHash", - "type": "bytes32" + "name": "den", + "type": "uint64", + "internalType": "uint64" } - ], - "name": "RulesConfigured", - "type": "event" + ] }, { - "inputs": [], - "name": "SEND_OUTBOUND_SELECTOR", - "outputs": [ + "type": "error", + "name": "SvmDataTooShortForPin", + "inputs": [ { - "internalType": "bytes4", - "name": "", - "type": "bytes4" + "name": "pin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "ixLen", + "type": "uint256", + "internalType": "uint256" } - ], - "stateMutability": "view", - "type": "function" + ] }, { - "inputs": [], - "name": "SESSION_ENGINE", - "outputs": [ + "type": "error", + "name": "SvmInstructionNotExecute", + "inputs": [ { - "internalType": "address", - "name": "", - "type": "address" + "name": "instructionId", + "type": "uint8", + "internalType": "uint8" } - ], - "stateMutability": "view", - "type": "function" + ] }, { - "inputs": [], - "name": "UNIVERSAL_EXECUTOR_MODULE", - "outputs": [ + "type": "error", + "name": "SvmIxDataTooLong", + "inputs": [ { - "internalType": "address", - "name": "", - "type": "address" + "name": "length", + "type": "uint256", + "internalType": "uint256" } - ], - "stateMutability": "view", - "type": "function" + ] }, { - "inputs": [], - "name": "UNIVERSAL_GATEWAY_PC", - "outputs": [ + "type": "error", + "name": "SvmMaxAccountsOutOfRange", + "inputs": [ { - "internalType": "address", - "name": "", - "type": "address" + "name": "rule", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxAccounts", + "type": "uint8", + "internalType": "uint8" } - ], - "stateMutability": "view", - "type": "function" + ] + }, + { + "type": "error", + "name": "SvmPayloadEmpty", + "inputs": [] }, { + "type": "error", + "name": "SvmPinIndexOutOfRange", "inputs": [ { - "internalType": "ConfigId", - "name": "id", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "account", - "type": "address" + "name": "pin", + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "uint256", - "name": "expectedValueSpent", - "type": "uint256" - }, + "name": "accountIndex", + "type": "uint8", + "internalType": "uint8" + } + ] + }, + { + "type": "error", + "name": "SvmPinRuleOutOfRange", + "inputs": [ { - "internalType": "uint256", - "name": "expectedAmountSpent", - "type": "uint256" + "name": "pin", + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "uint32", - "name": "expectedCalls", - "type": "uint32" + "name": "rule", + "type": "uint8", + "internalType": "uint8" } - ], - "name": "assertSpent", - "outputs": [], - "stateMutability": "view", - "type": "function" + ] }, { + "type": "error", + "name": "TargetMismatch", "inputs": [ { - "internalType": "ConfigId", - "name": "id", - "type": "bytes32" + "name": "actual", + "type": "address", + "internalType": "address" }, { - "internalType": "address", - "name": "account", - "type": "address" - }, + "name": "expected", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "TooManyCeaAccounts", + "inputs": [ { - "internalType": "uint256[]", - "name": "expectedSpent", - "type": "uint256[]" + "name": "count", + "type": "uint256", + "internalType": "uint256" } - ], - "name": "assertSpent", - "outputs": [], - "stateMutability": "view", - "type": "function" + ] }, { + "type": "error", + "name": "TooManyPins", "inputs": [ { - "internalType": "ConfigId", - "name": "id", - "type": "bytes32" - }, + "name": "count", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "TooManySvmDataPins", + "inputs": [ { - "internalType": "address", - "name": "account", - "type": "address" - }, + "name": "count", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "TooManySvmPins", + "inputs": [ { - "internalType": "address", - "name": "target", - "type": "address" - }, + "name": "count", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "TotalNativeAmountExceeded", + "inputs": [ { - "internalType": "uint256", - "name": "value", - "type": "uint256" + "name": "newSpent", + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "checkAction", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" + "name": "cap", + "type": "uint256", + "internalType": "uint256" } - ], - "stateMutability": "nonpayable", - "type": "function" + ] }, { + "type": "error", + "name": "TotalSpendCapExceeded", "inputs": [ { - "internalType": "ConfigId", - "name": "id", - "type": "bytes32" + "name": "wouldBeTotal", + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "address", - "name": "account", - "type": "address" - }, + "name": "cap", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "TotalValueExceeded", + "inputs": [ { - "internalType": "bytes32", - "name": "outboundTxId", - "type": "bytes32" + "name": "newSpent", + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "address", - "name": "token", - "type": "address" - }, + "name": "cap", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "UncappedGasSwapRejected", + "inputs": [] + }, + { + "type": "error", + "name": "UnsupportedEnvelopeVersion", + "inputs": [ { - "internalType": "uint256", - "name": "amount", - "type": "uint256" + "name": "version", + "type": "uint256", + "internalType": "uint256" } - ], - "name": "creditRevert", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + ] }, { + "type": "error", + "name": "UnsupportedNamespace", "inputs": [ { - "internalType": "ConfigId", - "name": "id", - "type": "bytes32" + "name": "chainHash", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "ValueExceedsCap", + "inputs": [ + { + "name": "value", + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "address", - "name": "account", - "type": "address" + "name": "cap", + "type": "uint256", + "internalType": "uint256" } - ], - "name": "getConfig", - "outputs": [ + ] + }, + { + "type": "error", + "name": "ValueOnlyCalldataNotEmpty", + "inputs": [ { - "components": [ - { - "internalType": "bool", - "name": "initialized", - "type": "bool" - }, - { - "internalType": "uint48", - "name": "validUntil", - "type": "uint48" - }, - { - "internalType": "address", - "name": "expectedCEA", - "type": "address" - }, - { - "internalType": "uint256", - "name": "maxGasPerCall", - "type": "uint256" - }, - { - "components": [ - { - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "internalType": "uint256", - "name": "maxPerCall", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "maxTotal", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "spent", - "type": "uint256" - } - ], - "internalType": "struct AssetCapState[]", - "name": "assets", - "type": "tuple[]" - }, - { - "components": [ - { - "internalType": "address", - "name": "target", - "type": "address" - }, - { - "internalType": "bytes4", - "name": "selector", - "type": "bytes4" - }, - { - "internalType": "uint16", - "name": "beneficiaryOffset", - "type": "uint16" - }, - { - "internalType": "bool", - "name": "hasBeneficiary", - "type": "bool" - }, - { - "internalType": "uint256", - "name": "maxValue", - "type": "uint256" - } - ], - "internalType": "struct AllowedCall[]", - "name": "allowedCalls", - "type": "tuple[]" - } - ], - "internalType": "struct Config", - "name": "", - "type": "tuple" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "ConfigId", - "name": "id", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getMode", - "outputs": [ - { - "components": [ - { - "internalType": "bool", - "name": "initialized", - "type": "bool" - }, - { - "internalType": "enum RulesType", - "name": "mode", - "type": "uint8" - }, - { - "internalType": "enum VmFamily", - "name": "vm", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "chainHash", - "type": "bytes32" - } - ], - "internalType": "struct ModeSlot", - "name": "", - "type": "tuple" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "ConfigId", - "name": "id", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getNativeConfig", - "outputs": [ - { - "components": [ - { - "internalType": "bool", - "name": "initialized", - "type": "bool" - }, - { - "internalType": "uint48", - "name": "validUntil", - "type": "uint48" - }, - { - "internalType": "address", - "name": "target", - "type": "address" - }, - { - "internalType": "bytes4", - "name": "selector", - "type": "bytes4" - }, - { - "internalType": "uint256", - "name": "maxValuePerCall", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "maxValueTotal", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "valueSpent", - "type": "uint256" - }, - { - "components": [ - { - "internalType": "bool", - "name": "enabled", - "type": "bool" - }, - { - "internalType": "uint16", - "name": "offset", - "type": "uint16" - }, - { - "internalType": "uint256", - "name": "maxPerCall", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "maxTotal", - "type": "uint256" - } - ], - "internalType": "struct AmountRule", - "name": "amount", - "type": "tuple" - }, - { - "internalType": "uint256", - "name": "amountSpent", - "type": "uint256" - }, - { - "internalType": "uint32", - "name": "maxCalls", - "type": "uint32" - }, - { - "internalType": "uint32", - "name": "callsUsed", - "type": "uint32" - }, - { - "components": [ - { - "internalType": "uint16", - "name": "offset", - "type": "uint16" - }, - { - "internalType": "bytes32", - "name": "expected", - "type": "bytes32" - } - ], - "internalType": "struct ArgPin[]", - "name": "pins", - "type": "tuple[]" - } - ], - "internalType": "struct NativeConfig", - "name": "", - "type": "tuple" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "ConfigId", - "name": "id", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getSvmConfig", - "outputs": [ - { - "components": [ - { - "internalType": "bool", - "name": "initialized", - "type": "bool" - }, - { - "internalType": "uint48", - "name": "validUntil", - "type": "uint48" - }, - { - "internalType": "bytes32", - "name": "expectedCEA", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "gatewayProgram", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "maxGasPerCall", - "type": "uint256" - }, - { - "components": [ - { - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "internalType": "uint256", - "name": "maxPerCall", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "maxTotal", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "spent", - "type": "uint256" - } - ], - "internalType": "struct AssetCapState[]", - "name": "assets", - "type": "tuple[]" - }, - { - "internalType": "bytes32[]", - "name": "ceaAccounts", - "type": "bytes32[]" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "program", - "type": "bytes32" - }, - { - "internalType": "bytes8", - "name": "discriminator", - "type": "bytes8" - }, - { - "internalType": "uint8", - "name": "discriminatorLen", - "type": "uint8" - }, - { - "internalType": "bool", - "name": "dataless", - "type": "bool" - }, - { - "internalType": "uint8", - "name": "maxAccounts", - "type": "uint8" - } - ], - "internalType": "struct AllowedProgram[]", - "name": "programs", - "type": "tuple[]" - }, - { - "components": [ - { - "internalType": "uint8", - "name": "ruleIndex", - "type": "uint8" - }, - { - "internalType": "uint8", - "name": "accountIndex", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "expected", - "type": "bytes32" - } - ], - "internalType": "struct SvmAccountPin[]", - "name": "pins", - "type": "tuple[]" - }, - { - "components": [ - { - "internalType": "uint8", - "name": "ruleIndex", - "type": "uint8" - }, - { - "internalType": "bool", - "name": "fromEnd", - "type": "bool" - }, - { - "internalType": "uint16", - "name": "offset", - "type": "uint16" - }, - { - "internalType": "uint16", - "name": "offsetB", - "type": "uint16" - }, - { - "internalType": "uint8", - "name": "len", - "type": "uint8" - }, - { - "internalType": "enum SvmDataPinMode", - "name": "mode", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "expected", - "type": "bytes32" - }, - { - "internalType": "uint64", - "name": "num", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "den", - "type": "uint64" - } - ], - "internalType": "struct SvmDataPin[]", - "name": "dataPins", - "type": "tuple[]" - } - ], - "internalType": "struct SvmConfig", - "name": "", - "type": "tuple" + "name": "length", + "type": "uint256", + "internalType": "uint256" } - ], - "stateMutability": "view", - "type": "function" + ] }, { - "inputs": [ - { - "internalType": "address", - "name": "universalGatewayPC", - "type": "address" - }, - { - "internalType": "address", - "name": "universalExecutorModule", - "type": "address" - }, - { - "internalType": "address", - "name": "sessionEngine", - "type": "address" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "type": "error", + "name": "ValueOnlyWithAmountRule", + "inputs": [] }, { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "ConfigId", - "name": "configId", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "initData", - "type": "bytes" - } - ], - "name": "initializeWithMultiplexer", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "type": "error", + "name": "ValueOnlyWithPins", + "inputs": [] }, { + "type": "error", + "name": "WrongModeForCall", "inputs": [ { - "internalType": "bytes32", - "name": "outboundTxId", - "type": "bytes32" - } - ], - "name": "isCredited", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "pushChainHash", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" + "name": "actual", + "type": "uint8", + "internalType": "enum RulesType" } - ], - "stateMutability": "view", - "type": "function" + ] }, { + "type": "error", + "name": "WrongVmForCall", "inputs": [ { - "internalType": "bytes4", - "name": "iid", - "type": "bytes4" - } - ], - "name": "supportsInterface", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" + "name": "actual", + "type": "uint8", + "internalType": "enum VmFamily" } - ], - "stateMutability": "pure", - "type": "function" + ] }, { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "pure", - "type": "function" + "type": "error", + "name": "ZeroAddress", + "inputs": [] } ] diff --git a/packages/core/scripts/agw-local/abis/validator.json b/packages/core/scripts/agw-local/abis/validator.json index d043841a..86830881 100644 --- a/packages/core/scripts/agw-local/abis/validator.json +++ b/packages/core/scripts/agw-local/abis/validator.json @@ -1,141 +1,141 @@ [ { + "type": "function", + "name": "isInitialized", "inputs": [ { - "internalType": "address", - "name": "smartAccount", - "type": "address" - } - ], - "name": "AlreadyInitialized", - "type": "error" - }, - { - "inputs": [], - "name": "MalformedConfig", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "smartAccount", - "type": "address" - } - ], - "name": "NotInitialized", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", "name": "", - "type": "address" + "type": "address", + "internalType": "address" } ], - "name": "isInitialized", "outputs": [ { - "internalType": "bool", "name": "", - "type": "bool" + "type": "bool", + "internalType": "bool" } ], - "stateMutability": "pure", - "type": "function" + "stateMutability": "pure" }, { + "type": "function", + "name": "isModuleType", "inputs": [ { - "internalType": "uint256", "name": "moduleTypeId", - "type": "uint256" + "type": "uint256", + "internalType": "uint256" } ], - "name": "isModuleType", "outputs": [ { - "internalType": "bool", "name": "", - "type": "bool" + "type": "bool", + "internalType": "bool" } ], - "stateMutability": "pure", - "type": "function" + "stateMutability": "pure" }, { + "type": "function", + "name": "onInstall", "inputs": [ { - "internalType": "bytes", "name": "", - "type": "bytes" + "type": "bytes", + "internalType": "bytes" } ], - "name": "onInstall", "outputs": [], - "stateMutability": "pure", - "type": "function" + "stateMutability": "pure" }, { + "type": "function", + "name": "onUninstall", "inputs": [ { - "internalType": "bytes", "name": "", - "type": "bytes" + "type": "bytes", + "internalType": "bytes" } ], - "name": "onUninstall", "outputs": [], - "stateMutability": "pure", - "type": "function" + "stateMutability": "pure" }, { + "type": "function", + "name": "validateConfig", "inputs": [ { - "internalType": "bytes", "name": "data", - "type": "bytes" + "type": "bytes", + "internalType": "bytes" } ], - "name": "validateConfig", "outputs": [ { - "internalType": "bool", "name": "", - "type": "bool" + "type": "bool", + "internalType": "bool" } ], - "stateMutability": "pure", - "type": "function" + "stateMutability": "pure" }, { + "type": "function", + "name": "validateSignatureWithData", "inputs": [ { - "internalType": "bytes32", "name": "", - "type": "bytes32" + "type": "bytes32", + "internalType": "bytes32" }, { - "internalType": "bytes", "name": "sig", - "type": "bytes" + "type": "bytes", + "internalType": "bytes" }, { - "internalType": "bytes", "name": "data", - "type": "bytes" + "type": "bytes", + "internalType": "bytes" } ], - "name": "validateSignatureWithData", "outputs": [ { - "internalType": "bool", "name": "validSig", - "type": "bool" + "type": "bool", + "internalType": "bool" } ], - "stateMutability": "pure", - "type": "function" + "stateMutability": "pure" + }, + { + "type": "error", + "name": "AlreadyInitialized", + "inputs": [ + { + "name": "smartAccount", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "MalformedConfig", + "inputs": [] + }, + { + "type": "error", + "name": "NotInitialized", + "inputs": [ + { + "name": "smartAccount", + "type": "address", + "internalType": "address" + } + ] } ] diff --git a/packages/core/scripts/agw-local/abis/wallet.json b/packages/core/scripts/agw-local/abis/wallet.json index 4f12c4b4..5d5f6612 100644 --- a/packages/core/scripts/agw-local/abis/wallet.json +++ b/packages/core/scripts/agw-local/abis/wallet.json @@ -1,1550 +1,1606 @@ [ { + "type": "constructor", "inputs": [ { - "internalType": "address", "name": "sessionEngine_", - "type": "address" + "type": "address", + "internalType": "address" }, { - "internalType": "address", "name": "rulesPolicy_", - "type": "address" + "type": "address", + "internalType": "address" }, { - "internalType": "address", "name": "sessionValidator_", - "type": "address" + "type": "address", + "internalType": "address" }, { - "internalType": "address", "name": "universalGatewayPC_", - "type": "address" + "type": "address", + "internalType": "address" } ], - "stateMutability": "nonpayable", - "type": "constructor" + "stateMutability": "nonpayable" }, { - "inputs": [], - "name": "AlreadyInitialized", - "type": "error" + "type": "receive", + "stateMutability": "payable" }, { - "inputs": [ - { - "internalType": "bytes32", - "name": "rulesId", - "type": "bytes32" - }, + "type": "function", + "name": "RULES_POLICY", + "inputs": [], + "outputs": [ { - "internalType": "address", - "name": "caller", - "type": "address" + "name": "", + "type": "address", + "internalType": "address" } ], - "name": "CallerIsNotAgent", - "type": "error" - }, - { - "inputs": [], - "name": "CallerIsNotFactory", - "type": "error" + "stateMutability": "view" }, { + "type": "function", + "name": "SESSION_ENGINE", "inputs": [], - "name": "CallerIsNotOwner", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "target", - "type": "address" - }, + "outputs": [ { - "internalType": "bytes4", - "name": "selector", - "type": "bytes4" + "name": "", + "type": "address", + "internalType": "address" } ], - "name": "DuplicateAction", - "type": "error" - }, - { - "inputs": [], - "name": "EmptyChain", - "type": "error" + "stateMutability": "view" }, { + "type": "function", + "name": "SESSION_VALIDATOR", "inputs": [], - "name": "EngineStillHoldsPermissions", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "expected", - "type": "address" - }, + "outputs": [ { - "internalType": "address", - "name": "actual", - "type": "address" + "name": "", + "type": "address", + "internalType": "address" } ], - "name": "ExecutorMismatch", - "type": "error" + "stateMutability": "view" }, { - "inputs": [ + "type": "function", + "name": "UNIVERSAL_GATEWAY_PC", + "inputs": [], + "outputs": [ { - "internalType": "bytes4", - "name": "selector", - "type": "bytes4" + "name": "", + "type": "address", + "internalType": "address" } ], - "name": "ForbiddenActionSelector", - "type": "error" + "stateMutability": "view" }, { - "inputs": [ + "type": "function", + "name": "accountId", + "inputs": [], + "outputs": [ { - "internalType": "address", - "name": "target", - "type": "address" + "name": "", + "type": "string", + "internalType": "string" } ], - "name": "ForbiddenActionTarget", - "type": "error" + "stateMutability": "pure" }, { + "type": "function", + "name": "agentOf", "inputs": [ { - "internalType": "address", - "name": "target", - "type": "address" + "name": "rulesId", + "type": "bytes32", + "internalType": "bytes32" } ], - "name": "ForbiddenDispatchTarget", - "type": "error" - }, - { - "inputs": [ + "outputs": [ { - "internalType": "uint256", - "name": "actionIndex", - "type": "uint256" + "name": "", + "type": "address", + "internalType": "address" } ], - "name": "InconsistentChain", - "type": "error" + "stateMutability": "view" }, { - "inputs": [ + "type": "function", + "name": "checkpointCount", + "inputs": [], + "outputs": [ { - "internalType": "bytes32", - "name": "actualCalldataHash", - "type": "bytes32" + "name": "", + "type": "uint64", + "internalType": "uint64" } ], - "name": "IntentExecMismatch", - "type": "error" + "stateMutability": "view" }, { + "type": "function", + "name": "domainSeparator", "inputs": [ { - "internalType": "uint64", - "name": "expected", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "provided", - "type": "uint64" + "name": "signerChainId", + "type": "uint256", + "internalType": "uint256" } ], - "name": "IntentGrantNonceMismatch", - "type": "error" - }, - { - "inputs": [ + "outputs": [ { - "internalType": "bytes32", - "name": "actual", - "type": "bytes32" + "name": "", + "type": "bytes32", + "internalType": "bytes32" } ], - "name": "IntentSessionMismatch", - "type": "error" + "stateMutability": "view" }, { + "type": "function", + "name": "execute", "inputs": [ { - "internalType": "address", - "name": "expected", - "type": "address" + "name": "mode", + "type": "bytes32", + "internalType": "bytes32" }, { - "internalType": "address", - "name": "provided", - "type": "address" + "name": "executionCalldata", + "type": "bytes", + "internalType": "bytes" } ], - "name": "IntentWalletMismatch", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidModuleAddress", - "type": "error" + "outputs": [], + "stateMutability": "payable" }, { + "type": "function", + "name": "executeAsAgent", "inputs": [ { - "internalType": "uint192", - "name": "nonceKey", - "type": "uint192" + "name": "rulesId", + "type": "bytes32", + "internalType": "bytes32" }, { - "internalType": "uint64", - "name": "expected", - "type": "uint64" + "name": "mode", + "type": "bytes32", + "internalType": "bytes32" }, { - "internalType": "uint64", - "name": "provided", - "type": "uint64" - } - ], - "name": "InvalidNonce", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidOwnerSignature", - "type": "error" - }, - { - "inputs": [], - "name": "MalformedBatchCalldata", - "type": "error" - }, - { - "inputs": [], - "name": "MalformedSessionShape", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "module", - "type": "address" + "name": "executionCalldata", + "type": "bytes", + "internalType": "bytes" } ], - "name": "ModuleAlreadyInstalled", - "type": "error" + "outputs": [], + "stateMutability": "nonpayable" }, { + "type": "function", + "name": "executeWithSig", "inputs": [ { - "internalType": "uint48", - "name": "validAfter", - "type": "uint48" + "name": "mode", + "type": "bytes32", + "internalType": "bytes32" }, { - "internalType": "uint48", - "name": "validUntil", - "type": "uint48" - } - ], - "name": "OutsideTimeWindow", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint192", - "name": "nonceKey", - "type": "uint192" - } - ], - "name": "OwnerLaneRequired", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint48", - "name": "deadline", - "type": "uint48" - } - ], - "name": "OwnerSigExpired", - "type": "error" - }, - { - "inputs": [], - "name": "ReentrancyGuardReentrantCall", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "enum RulesType", - "name": "derived", - "type": "uint8" + "name": "executionCalldata", + "type": "bytes", + "internalType": "bytes" }, { - "internalType": "uint256", - "name": "actionIndex", - "type": "uint256" + "name": "intent", + "type": "tuple", + "internalType": "struct OwnerIntent", + "components": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "wallet", + "type": "address", + "internalType": "address" + }, + { + "name": "executor", + "type": "address", + "internalType": "address" + }, + { + "name": "index", + "type": "uint96", + "internalType": "uint96" + }, + { + "name": "sessionHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "mode", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "execCalldataHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "nonceKey", + "type": "uint192", + "internalType": "uint192" + }, + { + "name": "nonceSeq", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "grantNonce", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "deadline", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "signerChainId", + "type": "uint256", + "internalType": "uint256" + } + ] }, { - "internalType": "address", - "name": "target", - "type": "address" - } - ], - "name": "RulesTypeMismatch", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "count", - "type": "uint256" - } - ], - "name": "TooManyActions", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "rulesId", - "type": "bytes32" + "name": "sig", + "type": "bytes", + "internalType": "bytes" } ], - "name": "UnknownPermission", - "type": "error" + "outputs": [], + "stateMutability": "nonpayable" }, { + "type": "function", + "name": "factory", "inputs": [], - "name": "UnsupportedExecutionMode", - "type": "error" - }, - { - "inputs": [ + "outputs": [ { - "internalType": "uint256", - "name": "moduleTypeId", - "type": "uint256" + "name": "", + "type": "address", + "internalType": "address" } ], - "name": "UnsupportedModuleType", - "type": "error" + "stateMutability": "view" }, { + "type": "function", + "name": "getNonce", "inputs": [ { - "internalType": "address", - "name": "authorizer", - "type": "address" + "name": "nonceKey", + "type": "uint192", + "internalType": "uint192" } ], - "name": "ValidationFailed", - "type": "error" - }, - { - "inputs": [ + "outputs": [ { - "internalType": "address", - "name": "validator", - "type": "address" + "name": "", + "type": "uint64", + "internalType": "uint64" } ], - "name": "ValidatorNotInstalled", - "type": "error" + "stateMutability": "view" }, { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, + "type": "function", + "name": "grantNonce", + "inputs": [], + "outputs": [ { - "indexed": true, - "internalType": "address", - "name": "engine", - "type": "address" + "name": "", + "type": "uint64", + "internalType": "uint64" } ], - "name": "AccountInitialized", - "type": "event" + "stateMutability": "view" }, { - "anonymous": false, + "type": "function", + "name": "grantRules", "inputs": [ { - "indexed": true, - "internalType": "uint64", - "name": "seq", - "type": "uint64" - }, + "name": "session", + "type": "tuple", + "internalType": "struct Session", + "components": [ + { + "name": "sessionValidator", + "type": "address", + "internalType": "contract ISessionValidator" + }, + { + "name": "sessionValidatorInitData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "erc7739Policies", + "type": "tuple", + "internalType": "struct ERC7739Data", + "components": [ + { + "name": "allowedERC7739Content", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNames", + "type": "string[]", + "internalType": "string[]" + } + ] + }, + { + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "actions", + "type": "tuple[]", + "internalType": "struct ActionData[]", + "components": [ + { + "name": "actionTargetSelector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "actionTarget", + "type": "address", + "internalType": "address" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "permitERC4337Paymaster", + "type": "bool", + "internalType": "bool" + } + ] + } + ], + "outputs": [ { - "indexed": false, - "internalType": "enum CheckpointKind", - "name": "kind", - "type": "uint8" + "name": "rulesId", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "grantRulesWithSig", + "inputs": [ + { + "name": "session", + "type": "tuple", + "internalType": "struct Session", + "components": [ + { + "name": "sessionValidator", + "type": "address", + "internalType": "contract ISessionValidator" + }, + { + "name": "sessionValidatorInitData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "erc7739Policies", + "type": "tuple", + "internalType": "struct ERC7739Data", + "components": [ + { + "name": "allowedERC7739Content", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNames", + "type": "string[]", + "internalType": "string[]" + } + ] + }, + { + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "actions", + "type": "tuple[]", + "internalType": "struct ActionData[]", + "components": [ + { + "name": "actionTargetSelector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "actionTarget", + "type": "address", + "internalType": "address" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "permitERC4337Paymaster", + "type": "bool", + "internalType": "bool" + } + ] }, { - "indexed": false, - "internalType": "bytes32", - "name": "ref", - "type": "bytes32" + "name": "intent", + "type": "tuple", + "internalType": "struct OwnerIntent", + "components": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "wallet", + "type": "address", + "internalType": "address" + }, + { + "name": "executor", + "type": "address", + "internalType": "address" + }, + { + "name": "index", + "type": "uint96", + "internalType": "uint96" + }, + { + "name": "sessionHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "mode", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "execCalldataHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "nonceKey", + "type": "uint192", + "internalType": "uint192" + }, + { + "name": "nonceSeq", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "grantNonce", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "deadline", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "signerChainId", + "type": "uint256", + "internalType": "uint256" + } + ] }, { - "indexed": false, - "internalType": "uint64", - "name": "blockNumber", - "type": "uint64" + "name": "sig", + "type": "bytes", + "internalType": "bytes" } ], - "name": "Checkpointed", - "type": "event" + "outputs": [ + { + "name": "rulesId", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "nonpayable" }, { - "anonymous": false, + "type": "function", + "name": "initializeAccount", "inputs": [ { - "indexed": false, - "internalType": "uint256", - "name": "moduleTypeId", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "module", - "type": "address" + "name": "label_", + "type": "string", + "internalType": "string" } ], - "name": "ModuleInstalled", - "type": "event" + "outputs": [], + "stateMutability": "nonpayable" }, { - "anonymous": false, + "type": "function", + "name": "installModule", "inputs": [ { - "indexed": false, - "internalType": "uint256", "name": "moduleTypeId", - "type": "uint256" + "type": "uint256", + "internalType": "uint256" }, { - "indexed": false, - "internalType": "address", "name": "module", - "type": "address" + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" } ], - "name": "ModuleUninstalled", - "type": "event" + "outputs": [], + "stateMutability": "nonpayable" }, { - "anonymous": false, + "type": "function", + "name": "isModuleInstalled", "inputs": [ { - "indexed": true, - "internalType": "bytes32", - "name": "mode", - "type": "bytes32" + "name": "moduleTypeId", + "type": "uint256", + "internalType": "uint256" }, { - "indexed": false, - "internalType": "bytes32", - "name": "executionCalldataHash", - "type": "bytes32" + "name": "module", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "bytes", + "internalType": "bytes" } ], - "name": "OwnerExecuted", - "type": "event" + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" }, { - "anonymous": false, + "type": "function", + "name": "isValidSignature", "inputs": [ { - "indexed": true, - "internalType": "bytes32", - "name": "mode", - "type": "bytes32" + "name": "", + "type": "bytes32", + "internalType": "bytes32" }, { - "indexed": false, - "internalType": "bytes32", - "name": "executionCalldataHash", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "uint192", - "name": "nonceKey", - "type": "uint192" - }, + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ { - "indexed": false, - "internalType": "uint64", - "name": "nonceSeq", - "type": "uint64" + "name": "", + "type": "bytes4", + "internalType": "bytes4" } ], - "name": "OwnerExecutedWithSig", - "type": "event" + "stateMutability": "pure" }, { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "bytes32", - "name": "rulesId", - "type": "bytes32" - }, + "type": "function", + "name": "label", + "inputs": [], + "outputs": [ { - "indexed": true, - "internalType": "address", - "name": "agent", - "type": "address" - }, + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "lastCheckpointBlock", + "inputs": [], + "outputs": [ { - "indexed": false, - "internalType": "bytes32", - "name": "callsHash", - "type": "bytes32" + "name": "", + "type": "uint64", + "internalType": "uint64" } ], - "name": "RulesActionAuthorized", - "type": "event" + "stateMutability": "view" }, { - "anonymous": false, + "type": "function", + "name": "onERC1155BatchReceived", "inputs": [ { - "indexed": true, - "internalType": "bytes32", - "name": "rulesId", - "type": "bytes32" + "name": "", + "type": "address", + "internalType": "address" }, { - "indexed": false, - "internalType": "enum RulesType", - "name": "mode", - "type": "uint8" + "name": "", + "type": "address", + "internalType": "address" }, { - "indexed": true, - "internalType": "bytes32", - "name": "chainHash", - "type": "bytes32" + "name": "", + "type": "uint256[]", + "internalType": "uint256[]" }, { - "indexed": false, - "internalType": "string", - "name": "chainNamespace", - "type": "string" + "name": "", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "", + "type": "bytes", + "internalType": "bytes" } ], - "name": "RulesGranted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ + "outputs": [ { - "indexed": true, - "internalType": "bytes32", - "name": "rulesId", - "type": "bytes32" + "name": "", + "type": "bytes4", + "internalType": "bytes4" } ], - "name": "RulesRevoked", - "type": "event" + "stateMutability": "pure" }, { - "anonymous": false, + "type": "function", + "name": "onERC1155Received", "inputs": [ { - "indexed": false, - "internalType": "address", - "name": "module", - "type": "address" + "name": "", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "", + "type": "bytes", + "internalType": "bytes" } ], - "name": "UninstallCallbackFailed", - "type": "event" - }, - { - "inputs": [], - "name": "RULES_POLICY", "outputs": [ { - "internalType": "address", "name": "", - "type": "address" + "type": "bytes4", + "internalType": "bytes4" } ], - "stateMutability": "view", - "type": "function" + "stateMutability": "pure" }, { - "inputs": [], - "name": "SESSION_ENGINE", + "type": "function", + "name": "onERC721Received", + "inputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], "outputs": [ { - "internalType": "address", "name": "", - "type": "address" + "type": "bytes4", + "internalType": "bytes4" } ], - "stateMutability": "view", - "type": "function" + "stateMutability": "pure" }, { + "type": "function", + "name": "owner", "inputs": [], - "name": "SESSION_VALIDATOR", "outputs": [ { - "internalType": "address", "name": "", - "type": "address" + "type": "address", + "internalType": "address" } ], - "stateMutability": "view", - "type": "function" + "stateMutability": "view" }, { + "type": "function", + "name": "revokeAllRules", "inputs": [], - "name": "UNIVERSAL_GATEWAY_PC", - "outputs": [ + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "revokeRules", + "inputs": [ { - "internalType": "address", - "name": "", - "type": "address" + "name": "rulesId", + "type": "bytes32", + "internalType": "bytes32" } ], - "stateMutability": "view", - "type": "function" + "outputs": [], + "stateMutability": "nonpayable" }, { - "inputs": [], - "name": "accountId", - "outputs": [ + "type": "function", + "name": "setLabel", + "inputs": [ { - "internalType": "string", - "name": "", - "type": "string" + "name": "label_", + "type": "string", + "internalType": "string" } ], - "stateMutability": "pure", - "type": "function" + "outputs": [], + "stateMutability": "nonpayable" }, { + "type": "function", + "name": "supportsExecutionMode", "inputs": [ { - "internalType": "bytes32", - "name": "rulesId", - "type": "bytes32" + "name": "mode", + "type": "bytes32", + "internalType": "bytes32" } ], - "name": "agentOf", "outputs": [ { - "internalType": "address", "name": "", - "type": "address" + "type": "bool", + "internalType": "bool" } ], - "stateMutability": "view", - "type": "function" + "stateMutability": "pure" }, { - "inputs": [], - "name": "checkpointCount", + "type": "function", + "name": "supportsInterface", + "inputs": [ + { + "name": "interfaceId", + "type": "bytes4", + "internalType": "bytes4" + } + ], "outputs": [ { - "internalType": "uint64", "name": "", - "type": "uint64" + "type": "bool", + "internalType": "bool" } ], - "stateMutability": "view", - "type": "function" + "stateMutability": "pure" }, { + "type": "function", + "name": "supportsModule", "inputs": [ { - "internalType": "uint256", - "name": "signerChainId", - "type": "uint256" + "name": "moduleTypeId", + "type": "uint256", + "internalType": "uint256" } ], - "name": "domainSeparator", "outputs": [ { - "internalType": "bytes32", "name": "", - "type": "bytes32" + "type": "bool", + "internalType": "bool" } ], - "stateMutability": "view", - "type": "function" + "stateMutability": "pure" }, { + "type": "function", + "name": "uninstallModule", "inputs": [ { - "internalType": "bytes32", - "name": "mode", - "type": "bytes32" + "name": "moduleTypeId", + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "bytes", - "name": "executionCalldata", - "type": "bytes" + "name": "module", + "type": "address", + "internalType": "address" + }, + { + "name": "deInitData", + "type": "bytes", + "internalType": "bytes" } ], - "name": "execute", "outputs": [], - "stateMutability": "payable", - "type": "function" + "stateMutability": "nonpayable" }, { + "type": "event", + "name": "AccountInitialized", "inputs": [ { - "internalType": "bytes32", - "name": "rulesId", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "mode", - "type": "bytes32" + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" }, { - "internalType": "bytes", - "name": "executionCalldata", - "type": "bytes" + "name": "engine", + "type": "address", + "indexed": true, + "internalType": "address" } ], - "name": "executeAsAgent", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "anonymous": false }, { + "type": "event", + "name": "Checkpointed", "inputs": [ { - "internalType": "bytes32", - "name": "mode", - "type": "bytes32" + "name": "seq", + "type": "uint64", + "indexed": true, + "internalType": "uint64" }, { - "internalType": "bytes", - "name": "executionCalldata", - "type": "bytes" + "name": "kind", + "type": "uint8", + "indexed": false, + "internalType": "enum CheckpointKind" }, { - "components": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "wallet", - "type": "address" - }, - { - "internalType": "address", - "name": "executor", - "type": "address" - }, - { - "internalType": "uint96", - "name": "index", - "type": "uint96" - }, - { - "internalType": "bytes32", - "name": "sessionHash", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "mode", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "execCalldataHash", - "type": "bytes32" - }, - { - "internalType": "uint192", - "name": "nonceKey", - "type": "uint192" - }, - { - "internalType": "uint64", - "name": "nonceSeq", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "grantNonce", - "type": "uint64" - }, - { - "internalType": "uint48", - "name": "deadline", - "type": "uint48" - }, - { - "internalType": "uint256", - "name": "signerChainId", - "type": "uint256" - } - ], - "internalType": "struct OwnerIntent", - "name": "intent", - "type": "tuple" + "name": "ref", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" }, { - "internalType": "bytes", - "name": "sig", - "type": "bytes" + "name": "blockNumber", + "type": "uint64", + "indexed": false, + "internalType": "uint64" } ], - "name": "executeWithSig", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "anonymous": false }, { - "inputs": [], - "name": "factory", - "outputs": [ + "type": "event", + "name": "LabelSet", + "inputs": [ { - "internalType": "address", - "name": "", - "type": "address" + "name": "label", + "type": "string", + "indexed": false, + "internalType": "string" } ], - "stateMutability": "view", - "type": "function" + "anonymous": false }, { + "type": "event", + "name": "ModuleInstalled", "inputs": [ { - "internalType": "uint192", - "name": "nonceKey", - "type": "uint192" + "name": "moduleTypeId", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "module", + "type": "address", + "indexed": false, + "internalType": "address" } ], - "name": "getNonce", - "outputs": [ + "anonymous": false + }, + { + "type": "event", + "name": "ModuleUninstalled", + "inputs": [ { - "internalType": "uint64", - "name": "", - "type": "uint64" + "name": "moduleTypeId", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "module", + "type": "address", + "indexed": false, + "internalType": "address" } ], - "stateMutability": "view", - "type": "function" + "anonymous": false }, { - "inputs": [], - "name": "grantNonce", - "outputs": [ + "type": "event", + "name": "OwnerExecuted", + "inputs": [ { - "internalType": "uint64", - "name": "", - "type": "uint64" + "name": "mode", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "executionCalldataHash", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" } ], - "stateMutability": "view", - "type": "function" + "anonymous": false }, { + "type": "event", + "name": "OwnerExecutedWithSig", "inputs": [ { - "components": [ - { - "internalType": "contract ISessionValidator", - "name": "sessionValidator", - "type": "address" - }, - { - "internalType": "bytes", - "name": "sessionValidatorInitData", - "type": "bytes" - }, - { - "internalType": "bytes32", - "name": "salt", - "type": "bytes32" - }, - { - "components": [ - { - "internalType": "address", - "name": "policy", - "type": "address" - }, - { - "internalType": "bytes", - "name": "initData", - "type": "bytes" - } - ], - "internalType": "struct PolicyData[]", - "name": "userOpPolicies", - "type": "tuple[]" - }, - { - "components": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "appDomainSeparator", - "type": "bytes32" - }, - { - "internalType": "string[]", - "name": "contentNames", - "type": "string[]" - } - ], - "internalType": "struct ERC7739Context[]", - "name": "allowedERC7739Content", - "type": "tuple[]" - }, - { - "components": [ - { - "internalType": "address", - "name": "policy", - "type": "address" - }, - { - "internalType": "bytes", - "name": "initData", - "type": "bytes" - } - ], - "internalType": "struct PolicyData[]", - "name": "erc1271Policies", - "type": "tuple[]" - } - ], - "internalType": "struct ERC7739Data", - "name": "erc7739Policies", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "bytes4", - "name": "actionTargetSelector", - "type": "bytes4" - }, - { - "internalType": "address", - "name": "actionTarget", - "type": "address" - }, - { - "components": [ - { - "internalType": "address", - "name": "policy", - "type": "address" - }, - { - "internalType": "bytes", - "name": "initData", - "type": "bytes" - } - ], - "internalType": "struct PolicyData[]", - "name": "actionPolicies", - "type": "tuple[]" - } - ], - "internalType": "struct ActionData[]", - "name": "actions", - "type": "tuple[]" - }, - { - "internalType": "bool", - "name": "permitERC4337Paymaster", - "type": "bool" - } - ], - "internalType": "struct Session", - "name": "session", - "type": "tuple" + "name": "mode", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "executionCalldataHash", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + }, + { + "name": "nonceKey", + "type": "uint192", + "indexed": false, + "internalType": "uint192" + }, + { + "name": "nonceSeq", + "type": "uint64", + "indexed": false, + "internalType": "uint64" } ], - "name": "grantRules", - "outputs": [ + "anonymous": false + }, + { + "type": "event", + "name": "RulesActionAuthorized", + "inputs": [ { - "internalType": "bytes32", "name": "rulesId", - "type": "bytes32" + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "agent", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "callsHash", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" } ], - "stateMutability": "nonpayable", - "type": "function" + "anonymous": false }, { + "type": "event", + "name": "RulesGranted", "inputs": [ { - "components": [ - { - "internalType": "contract ISessionValidator", - "name": "sessionValidator", - "type": "address" - }, - { - "internalType": "bytes", - "name": "sessionValidatorInitData", - "type": "bytes" - }, - { - "internalType": "bytes32", - "name": "salt", - "type": "bytes32" - }, - { - "components": [ - { - "internalType": "address", - "name": "policy", - "type": "address" - }, - { - "internalType": "bytes", - "name": "initData", - "type": "bytes" - } - ], - "internalType": "struct PolicyData[]", - "name": "userOpPolicies", - "type": "tuple[]" - }, - { - "components": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "appDomainSeparator", - "type": "bytes32" - }, - { - "internalType": "string[]", - "name": "contentNames", - "type": "string[]" - } - ], - "internalType": "struct ERC7739Context[]", - "name": "allowedERC7739Content", - "type": "tuple[]" - }, - { - "components": [ - { - "internalType": "address", - "name": "policy", - "type": "address" - }, - { - "internalType": "bytes", - "name": "initData", - "type": "bytes" - } - ], - "internalType": "struct PolicyData[]", - "name": "erc1271Policies", - "type": "tuple[]" - } - ], - "internalType": "struct ERC7739Data", - "name": "erc7739Policies", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "bytes4", - "name": "actionTargetSelector", - "type": "bytes4" - }, - { - "internalType": "address", - "name": "actionTarget", - "type": "address" - }, - { - "components": [ - { - "internalType": "address", - "name": "policy", - "type": "address" - }, - { - "internalType": "bytes", - "name": "initData", - "type": "bytes" - } - ], - "internalType": "struct PolicyData[]", - "name": "actionPolicies", - "type": "tuple[]" - } - ], - "internalType": "struct ActionData[]", - "name": "actions", - "type": "tuple[]" - }, - { - "internalType": "bool", - "name": "permitERC4337Paymaster", - "type": "bool" - } - ], - "internalType": "struct Session", - "name": "session", - "type": "tuple" + "name": "rulesId", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" }, { - "components": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "wallet", - "type": "address" - }, - { - "internalType": "address", - "name": "executor", - "type": "address" - }, - { - "internalType": "uint96", - "name": "index", - "type": "uint96" - }, - { - "internalType": "bytes32", - "name": "sessionHash", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "mode", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "execCalldataHash", - "type": "bytes32" - }, - { - "internalType": "uint192", - "name": "nonceKey", - "type": "uint192" - }, - { - "internalType": "uint64", - "name": "nonceSeq", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "grantNonce", - "type": "uint64" - }, - { - "internalType": "uint48", - "name": "deadline", - "type": "uint48" - }, - { - "internalType": "uint256", - "name": "signerChainId", - "type": "uint256" - } - ], - "internalType": "struct OwnerIntent", - "name": "intent", - "type": "tuple" + "name": "mode", + "type": "uint8", + "indexed": false, + "internalType": "enum RulesType" }, { - "internalType": "bytes", - "name": "sig", - "type": "bytes" + "name": "chainHash", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "chainNamespace", + "type": "string", + "indexed": false, + "internalType": "string" } ], - "name": "grantRulesWithSig", - "outputs": [ + "anonymous": false + }, + { + "type": "event", + "name": "RulesRevoked", + "inputs": [ { - "internalType": "bytes32", "name": "rulesId", - "type": "bytes32" + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" } ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "initializeAccount", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "anonymous": false }, { + "type": "event", + "name": "UninstallCallbackFailed", "inputs": [ { - "internalType": "uint256", - "name": "moduleTypeId", - "type": "uint256" - }, - { - "internalType": "address", "name": "module", - "type": "address" - }, - { - "internalType": "bytes", - "name": "initData", - "type": "bytes" + "type": "address", + "indexed": false, + "internalType": "address" } ], - "name": "installModule", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "anonymous": false + }, + { + "type": "error", + "name": "AlreadyInitialized", + "inputs": [] }, { + "type": "error", + "name": "CallerIsNotAgent", "inputs": [ { - "internalType": "uint256", - "name": "moduleTypeId", - "type": "uint256" - }, - { - "internalType": "address", - "name": "module", - "type": "address" + "name": "rulesId", + "type": "bytes32", + "internalType": "bytes32" }, { - "internalType": "bytes", - "name": "", - "type": "bytes" + "name": "caller", + "type": "address", + "internalType": "address" } - ], - "name": "isModuleInstalled", - "outputs": [ + ] + }, + { + "type": "error", + "name": "CallerIsNotFactory", + "inputs": [] + }, + { + "type": "error", + "name": "CallerIsNotOwner", + "inputs": [] + }, + { + "type": "error", + "name": "DuplicateAction", + "inputs": [ { - "internalType": "bool", - "name": "", - "type": "bool" + "name": "target", + "type": "address", + "internalType": "address" + }, + { + "name": "selector", + "type": "bytes4", + "internalType": "bytes4" } - ], - "stateMutability": "view", - "type": "function" + ] + }, + { + "type": "error", + "name": "EmptyChain", + "inputs": [] }, { + "type": "error", + "name": "EngineStillHoldsPermissions", + "inputs": [] + }, + { + "type": "error", + "name": "ExecutorMismatch", "inputs": [ { - "internalType": "bytes32", - "name": "", - "type": "bytes32" + "name": "expected", + "type": "address", + "internalType": "address" }, { - "internalType": "bytes", - "name": "", - "type": "bytes" + "name": "actual", + "type": "address", + "internalType": "address" } - ], - "name": "isValidSignature", - "outputs": [ + ] + }, + { + "type": "error", + "name": "ForbiddenActionSelector", + "inputs": [ { - "internalType": "bytes4", - "name": "", - "type": "bytes4" + "name": "selector", + "type": "bytes4", + "internalType": "bytes4" } - ], - "stateMutability": "pure", - "type": "function" + ] }, { - "inputs": [], - "name": "lastCheckpointBlock", - "outputs": [ + "type": "error", + "name": "ForbiddenActionTarget", + "inputs": [ { - "internalType": "uint64", - "name": "", - "type": "uint64" + "name": "target", + "type": "address", + "internalType": "address" } - ], - "stateMutability": "view", - "type": "function" + ] }, { + "type": "error", + "name": "ForbiddenDispatchTarget", "inputs": [ { - "internalType": "address", - "name": "", - "type": "address" - }, + "name": "target", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "InconsistentChain", + "inputs": [ { - "internalType": "address", - "name": "", - "type": "address" - }, + "name": "actionIndex", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "IntentExecMismatch", + "inputs": [ { - "internalType": "uint256[]", - "name": "", - "type": "uint256[]" - }, + "name": "actualCalldataHash", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "IntentGrantNonceMismatch", + "inputs": [ { - "internalType": "uint256[]", - "name": "", - "type": "uint256[]" + "name": "expected", + "type": "uint64", + "internalType": "uint64" }, { - "internalType": "bytes", - "name": "", - "type": "bytes" + "name": "provided", + "type": "uint64", + "internalType": "uint64" } - ], - "name": "onERC1155BatchReceived", - "outputs": [ + ] + }, + { + "type": "error", + "name": "IntentSessionMismatch", + "inputs": [ { - "internalType": "bytes4", - "name": "", - "type": "bytes4" + "name": "actual", + "type": "bytes32", + "internalType": "bytes32" } - ], - "stateMutability": "pure", - "type": "function" + ] }, { + "type": "error", + "name": "IntentWalletMismatch", "inputs": [ { - "internalType": "address", - "name": "", - "type": "address" + "name": "expected", + "type": "address", + "internalType": "address" }, { - "internalType": "address", - "name": "", - "type": "address" - }, + "name": "provided", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "InvalidModuleAddress", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidNonce", + "inputs": [ { - "internalType": "uint256", - "name": "", - "type": "uint256" + "name": "nonceKey", + "type": "uint192", + "internalType": "uint192" }, { - "internalType": "uint256", - "name": "", - "type": "uint256" + "name": "expected", + "type": "uint64", + "internalType": "uint64" }, { - "internalType": "bytes", - "name": "", - "type": "bytes" + "name": "provided", + "type": "uint64", + "internalType": "uint64" } - ], - "name": "onERC1155Received", - "outputs": [ + ] + }, + { + "type": "error", + "name": "InvalidOwnerSignature", + "inputs": [] + }, + { + "type": "error", + "name": "LabelTooLong", + "inputs": [ { - "internalType": "bytes4", - "name": "", - "type": "bytes4" + "name": "length", + "type": "uint256", + "internalType": "uint256" } - ], - "stateMutability": "pure", - "type": "function" + ] }, { + "type": "error", + "name": "MalformedBatchCalldata", + "inputs": [] + }, + { + "type": "error", + "name": "MalformedSessionShape", + "inputs": [] + }, + { + "type": "error", + "name": "ModuleAlreadyInstalled", "inputs": [ { - "internalType": "address", - "name": "", - "type": "address" - }, - { - "internalType": "address", - "name": "", - "type": "address" - }, + "name": "module", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "OutsideTimeWindow", + "inputs": [ { - "internalType": "uint256", - "name": "", - "type": "uint256" + "name": "validAfter", + "type": "uint48", + "internalType": "uint48" }, { - "internalType": "bytes", - "name": "", - "type": "bytes" + "name": "validUntil", + "type": "uint48", + "internalType": "uint48" } - ], - "name": "onERC721Received", - "outputs": [ + ] + }, + { + "type": "error", + "name": "OwnerLaneRequired", + "inputs": [ { - "internalType": "bytes4", - "name": "", - "type": "bytes4" + "name": "nonceKey", + "type": "uint192", + "internalType": "uint192" } - ], - "stateMutability": "pure", - "type": "function" + ] }, { - "inputs": [], - "name": "owner", - "outputs": [ + "type": "error", + "name": "OwnerSigExpired", + "inputs": [ { - "internalType": "address", - "name": "", - "type": "address" + "name": "deadline", + "type": "uint48", + "internalType": "uint48" } - ], - "stateMutability": "view", - "type": "function" + ] }, { - "inputs": [], - "name": "revokeAllRules", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "type": "error", + "name": "ReentrancyGuardReentrantCall", + "inputs": [] }, { + "type": "error", + "name": "RulesTypeMismatch", "inputs": [ { - "internalType": "bytes32", - "name": "rulesId", - "type": "bytes32" + "name": "derived", + "type": "uint8", + "internalType": "enum RulesType" + }, + { + "name": "actionIndex", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "target", + "type": "address", + "internalType": "address" } - ], - "name": "revokeRules", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + ] }, { + "type": "error", + "name": "TooManyActions", "inputs": [ { - "internalType": "bytes32", - "name": "mode", - "type": "bytes32" - } - ], - "name": "supportsExecutionMode", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" + "name": "count", + "type": "uint256", + "internalType": "uint256" } - ], - "stateMutability": "pure", - "type": "function" + ] }, { + "type": "error", + "name": "UnknownPermission", "inputs": [ { - "internalType": "bytes4", - "name": "interfaceId", - "type": "bytes4" - } - ], - "name": "supportsInterface", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" + "name": "rulesId", + "type": "bytes32", + "internalType": "bytes32" } - ], - "stateMutability": "pure", - "type": "function" + ] }, { + "type": "error", + "name": "UnsupportedExecutionMode", + "inputs": [] + }, + { + "type": "error", + "name": "UnsupportedModuleType", "inputs": [ { - "internalType": "uint256", "name": "moduleTypeId", - "type": "uint256" + "type": "uint256", + "internalType": "uint256" } - ], - "name": "supportsModule", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "pure", - "type": "function" + ] }, { + "type": "error", + "name": "ValidationFailed", "inputs": [ { - "internalType": "uint256", - "name": "moduleTypeId", - "type": "uint256" - }, - { - "internalType": "address", - "name": "module", - "type": "address" - }, - { - "internalType": "bytes", - "name": "deInitData", - "type": "bytes" + "name": "authorizer", + "type": "address", + "internalType": "address" } - ], - "name": "uninstallModule", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + ] }, { - "stateMutability": "payable", - "type": "receive" + "type": "error", + "name": "ValidatorNotInstalled", + "inputs": [ + { + "name": "validator", + "type": "address", + "internalType": "address" + } + ] } ] diff --git a/packages/core/scripts/agw-local/gen-abi.mjs b/packages/core/scripts/agw-local/gen-abi.mjs index 829c7e45..0430e31a 100644 --- a/packages/core/scripts/agw-local/gen-abi.mjs +++ b/packages/core/scripts/agw-local/gen-abi.mjs @@ -1,5 +1,5 @@ #!/usr/bin/env node -// Regenerates packages/core/src/lib/agentic/contracts/abi/v4/*.ts from the +// Regenerates packages/core/src/lib/agentic/contracts/abi/v5/*.ts from the // pinned ABI snapshots in ./abis/. The JSON files are the source artifact set; // this script only re-serialises them as // `as const` TypeScript so viem can infer types. Run from the repo root: @@ -12,8 +12,8 @@ import { fileURLToPath } from 'node:url'; const here = dirname(fileURLToPath(import.meta.url)); const repo = resolve(here, '../../../..'); const src = join(here, 'abis'); -const dst = join(repo, 'packages/core/src/lib/agentic/contracts/abi/v4'); -const PIN = 'e8db74815cfbbf5389593805e464fe8d85f7f735'; +const dst = join(repo, 'packages/core/src/lib/agentic/contracts/abi/v5'); +const PIN = '2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb'; const sourceNames = { AGW: 'wallet', @@ -33,6 +33,10 @@ const files = { AgentValidator: ['AGENT_VALIDATOR_ABI', 'agent-validator.ts'], }; const manifest = JSON.parse(readFileSync(join(src, 'manifest.json'), 'utf8')); +if (manifest.sourceCommit !== PIN) { + throw new Error('ABI source commit does not match the supported generation'); +} + mkdirSync(dst, { recursive: true }); const exports = []; @@ -60,8 +64,8 @@ for (const [name, [constName, file]] of Object.entries(files)) { writeFileSync( join(dst, 'index.ts'), `// GENERATED by packages/core/scripts/agw-local/gen-abi.mjs — do not edit.\n` + - `// Review generation v4: Donut v4 deployment; source e8db748.\n` + - `export const V4_SOURCE_COMMIT = '${PIN}' as const;\n` + + `// Review generation v5: Donut v5 deployment; source 2e61e13.\n` + + `export const V5_SOURCE_COMMIT = '${PIN}' as const;\n` + exports.join('\n') + '\n' ); diff --git a/packages/core/scripts/agw-local/prepare.sh b/packages/core/scripts/agw-local/prepare.sh index 806f09bd..9cd1923c 100755 --- a/packages/core/scripts/agw-local/prepare.sh +++ b/packages/core/scripts/agw-local/prepare.sh @@ -5,7 +5,7 @@ # AGW_REPO path to a push-agentic-wallets clone (default: ../../../../push-agentic-wallets # relative to this script). Only `git archive` / `git ls-tree` are run against it, # so the clone's working tree, branches and index are never touched. -# AGW_PIN commit to extract (default: the reviewed v4). +# AGW_PIN commit to extract (default: the reviewed v5). # OUT destination directory (default: $TMPDIR/push-agw-local-). # # The script extracts the pinned tree, fetches each git submodule at the exact @@ -15,7 +15,7 @@ set -euo pipefail HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" AGW_REPO="${AGW_REPO:-$HERE/../../../../../push-agentic-wallets}" -AGW_PIN="${AGW_PIN:-e8db74815cfbbf5389593805e464fe8d85f7f735}" +AGW_PIN="${AGW_PIN:-2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb}" OUT="${OUT:-${TMPDIR:-/tmp}/push-agw-local-${AGW_PIN:0:7}}" command -v forge >/dev/null || { echo "forge not found (install Foundry)" >&2; exit 1; } diff --git a/packages/core/src/lib/agentic/__fixtures__/v4-vectors.json b/packages/core/src/lib/agentic/__fixtures__/v5-vectors.json similarity index 99% rename from packages/core/src/lib/agentic/__fixtures__/v4-vectors.json rename to packages/core/src/lib/agentic/__fixtures__/v5-vectors.json index 1219a092..3f037d15 100644 --- a/packages/core/src/lib/agentic/__fixtures__/v4-vectors.json +++ b/packages/core/src/lib/agentic/__fixtures__/v5-vectors.json @@ -1,6 +1,6 @@ { "provenance": { - "agwCommit": "e8db74815cfbbf5389593805e464fe8d85f7f735", + "agwCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "generatedBy": "packages/core/__agw-local__/vectors.spec.ts", "toolchain": "forge Version: 1.5.1-stable", "chainId": 9000, diff --git a/packages/core/src/lib/agentic/__tests__/codec.spec.ts b/packages/core/src/lib/agentic/__tests__/codec.spec.ts index b5d2260e..6721ad68 100644 --- a/packages/core/src/lib/agentic/__tests__/codec.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/codec.spec.ts @@ -1,5 +1,5 @@ import { decodeFunctionData, getAddress, type Address, type Hex } from 'viem'; -import vectorsJson from '../__fixtures__/v4-vectors.json'; +import vectorsJson from '../__fixtures__/v5-vectors.json'; import { actionId, agentConfig, @@ -23,8 +23,8 @@ import { import { parseSelector, VALUE_ONLY_SELECTOR } from '../codec/selectors'; import { argumentOffset, headSize } from '../codec/abi-layout'; import { UINT256_MAX } from '../codec/defaults'; -import { v4 } from '../contracts/v4'; -import { AGW_ABI } from '../contracts/abi/v4'; +import { v5 } from '../contracts/v5'; +import { AGW_ABI } from '../contracts/abi/v5'; import { AGENTIC_ERROR_CODE } from '../errors'; import type { NativeRule } from '../agentic.types'; @@ -69,7 +69,7 @@ const NOW = 1_700_000_000; const target = getAddress('0x0000000000000000000000000000000000007a76'); const agent = getAddress('0x00000000000000000000000000000000000000a9'); -describe('IDs against contract-generated vectors (v4)', () => { +describe('IDs against contract-generated vectors (v5)', () => { it.each(vectors.rulesId)( 'rulesId(agent, nonce) = engine.getPermissionId — nonce $grantNonce', (v) => { @@ -403,12 +403,12 @@ describe('wallet call encoders decode back to the same calls', () => { const call = { target, value: BigInt(7), data: '0xd09de08a' as Hex }; it('execute single uses packed ERC-7579 calldata', () => { - const data = v4.encodeExecute([call]); + const data = v5.encodeExecute([call]); const { functionName, args } = decodeFunctionData({ abi: AGW_ABI, data }); expect(functionName).toBe('execute'); expect(args[0]).toBe(`0x${'00'.repeat(32)}`); expect((args[1] as Hex).length).toBe(2 + 2 * (20 + 32 + 4)); - expect(v4.decodeWalletCall(data)).toEqual({ + expect(v5.decodeWalletCall(data)).toEqual({ kind: 'execute', mode: args[0], calls: [call], @@ -416,8 +416,8 @@ describe('wallet call encoders decode back to the same calls', () => { }); it('execute batch uses abi.encode(Execution[])', () => { - const data = v4.encodeExecute([call, { ...call, value: BigInt(0) }]); - const decoded = v4.decodeWalletCall(data); + const data = v5.encodeExecute([call, { ...call, value: BigInt(0) }]); + const decoded = v5.decodeWalletCall(data); expect(decoded).toMatchObject({ kind: 'execute', mode: `0x01${'00'.repeat(31)}`, @@ -430,7 +430,7 @@ describe('wallet call encoders decode back to the same calls', () => { it('executeAsAgent carries the rule ID and one packed call', () => { const id = `0x${'42'.repeat(32)}` as Hex; - expect(v4.decodeWalletCall(v4.encodeExecuteAsAgent(id, call))).toEqual({ + expect(v5.decodeWalletCall(v5.encodeExecuteAsAgent(id, call))).toEqual({ kind: 'executeAsAgent', rulesId: id, mode: `0x${'00'.repeat(32)}`, @@ -439,6 +439,6 @@ describe('wallet call encoders decode back to the same calls', () => { }); it('unknown calldata is not mistaken for a wallet call', () => { - expect(v4.decodeWalletCall('0xdeadbeef')).toBeNull(); + expect(v5.decodeWalletCall('0xdeadbeef')).toBeNull(); }); }); diff --git a/packages/core/src/lib/agentic/__tests__/fake-chain.ts b/packages/core/src/lib/agentic/__tests__/fake-chain.ts index 258fb646..d56212bf 100644 --- a/packages/core/src/lib/agentic/__tests__/fake-chain.ts +++ b/packages/core/src/lib/agentic/__tests__/fake-chain.ts @@ -18,7 +18,7 @@ import { type TransactionReceipt, } from 'viem'; import { PUSH_NETWORK } from '../../constants/enums'; -import { v4 } from '../contracts/v4'; +import { v5 } from '../contracts/v5'; import type { ChainReader } from '../contracts/reader'; import { actionId, configId, deriveWallet } from '../codec/ids'; import { @@ -26,7 +26,7 @@ import { resetAgenticGenerations, type AgenticGeneration, } from '../deployments'; -import type { NativeConfigRead } from '../contracts/v4'; +import type { NativeConfigRead } from '../contracts/v5'; export const ADDR = { factory: getAddress('0x00000000000000000000000000000000000fac70'), @@ -111,7 +111,7 @@ export class FakeChain implements ChainReader { this.extraLogs.push( log( ADDR.factory, - v4.events.walletDeployed, + v5.events.walletDeployed, { owner, index, wallet: address }, { label }, BigInt(10) @@ -174,6 +174,9 @@ export class FakeChain implements ChainReader { case 'factory': if (!wallet) throw new Error('no factory()'); return ADDR.factory; + case 'label': + if (!wallet) throw new Error('not a wallet'); + return wallet.label || `AGW ${wallet.index + BigInt(1)}`; case 'owner': if (!wallet) throw new Error('not a wallet'); return wallet.owner; @@ -376,7 +379,7 @@ export function checkpointLog( ): Log { return log( wallet, - v4.events.checkpointed, + v5.events.checkpointed, { seq: BigInt(seq) }, { kind, ref: `0x${'11'.repeat(32)}`, blockNumber: block }, block, @@ -390,8 +393,8 @@ export function registerFakeGeneration( ): AgenticGeneration { resetAgenticGenerations(); return registerAgenticGeneration({ - id: 'v4', - sourceCommit: 'e8db74815cfbbf5389593805e464fe8d85f7f735', + id: 'v5', + sourceCommit: '2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb', network, advertised: false, addresses: { diff --git a/packages/core/src/lib/agentic/__tests__/labels.spec.ts b/packages/core/src/lib/agentic/__tests__/labels.spec.ts new file mode 100644 index 00000000..9688dc4b --- /dev/null +++ b/packages/core/src/lib/agentic/__tests__/labels.spec.ts @@ -0,0 +1,115 @@ +import { decodeFunctionData, encodeErrorResult } from 'viem'; +import { PUSH_NETWORK } from '../../constants/enums'; +import { PROGRESS_HOOK } from '../../progress-hook/progress-hook.types'; +import { v5 } from '../contracts/v5'; +import { currentGeneration, resetAgenticGenerations } from '../deployments'; +import { AGENTIC_ERROR_CODE } from '../errors'; +import { createWallet } from '../management/create'; +import { assertLabel } from '../management/label'; +import { setLabel } from '../management/rules-write'; +import { decodeAgwErrorData } from '../revert'; +import { AgenticWalletHandle } from '../wallet'; +import { ADDR, FakeChain, registerFakeGeneration } from './fake-chain'; +import { mockRuntime } from './mock-runtime'; + +beforeEach(() => { + registerFakeGeneration(); +}); +afterEach(resetAgenticGenerations); +const gen = () => currentGeneration(PUSH_NETWORK.TESTNET_DONUT); + +describe('v5 wallet labels', () => { + it('allows empty, 64 ASCII bytes and sixteen four-byte emoji without altering the label', () => { + for (const label of ['', 'a'.repeat(64), '🙂'.repeat(16), ' label ']) { + expect(() => assertLabel(label)).not.toThrow(); + } + }); + + it('refuses non-strings and overlong UTF-8 labels before a create reads or signs', async () => { + const chain = new FakeChain(); + const rt = mockRuntime(chain, { signer: ADDR.owner }); + for (const label of [null, 123, 'a'.repeat(65), '🙂'.repeat(17)]) { + await expect( + createWallet(rt, label as never, { rules: [] }) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.INVALID_RULE }); + } + expect(rt.executeMock).not.toHaveBeenCalled(); + expect(chain.calls).toEqual([]); + }); + + it('encodes a reset through the owner door and forwards the per-call progress hook', async () => { + const chain = new FakeChain(); + const w = chain.addWallet(ADDR.owner, 'custom'); + const rt = mockRuntime(chain, { signer: ADDR.owner }); + const hook = jest.fn(); + const tx = await new AgenticWalletHandle(rt, w.address).setLabel('', { + progressHook: hook, + }); + const sent = rt.executeMock.mock.calls[0][0]; + expect(sent).toMatchObject({ to: w.address, value: BigInt(0) }); + const outer = v5.decodeWalletCall(sent.data); + expect(outer?.kind).toBe('execute'); + if (outer?.kind !== 'execute') throw new Error('expected owner execute'); + expect(outer.calls).toHaveLength(1); + expect(outer.calls[0].target).toBe(w.address); + expect( + decodeFunctionData({ abi: v5.abis.wallet, data: outer.calls[0].data }) + ).toMatchObject({ functionName: 'setLabel', args: [''] }); + expect(hook).toHaveBeenCalledWith( + expect.objectContaining({ id: PROGRESS_HOOK.AGENTIC_TX_199_01 }) + ); + expect(tx.hash).toBeTruthy(); + }); + + it('refuses non-owner and read-only renames before signing', async () => { + const chain = new FakeChain(); + const w = chain.addWallet(ADDR.owner, 'x'); + const stranger = mockRuntime(chain, { signer: ADDR.agent }); + await expect( + setLabel(stranger, gen(), w.address, 'y') + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.NOT_WALLET_OWNER }); + const readOnly = mockRuntime(chain, { signer: ADDR.owner, readOnly: true }); + await expect( + setLabel(readOnly, gen(), w.address, 'y') + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.READ_ONLY }); + expect(stranger.executeMock).not.toHaveBeenCalled(); + expect(readOnly.executeMock).not.toHaveBeenCalled(); + }); + + it('uses the same owner door for an external owner identity', async () => { + const chain = new FakeChain(); + const w = chain.addWallet(ADDR.owner, 'x'); + const rt = mockRuntime(chain, { + signer: ADDR.owner, + signerIsPushNative: () => false, + }); + await setLabel(rt, gen(), w.address, 'UEA label'); + expect( + v5.decodeWalletCall(rt.executeMock.mock.calls[0][0].data)?.kind + ).toBe('execute'); + }); + + it('maps the new contract length error and emits a failed operation hook', async () => { + const chain = new FakeChain(); + const w = chain.addWallet(ADDR.owner, 'x'); + const data = encodeErrorResult({ + abi: v5.abis.wallet, + errorName: 'LabelTooLong', + args: [BigInt(65)], + }); + expect(decodeAgwErrorData(data)).toMatchObject({ + name: 'LabelTooLong', + decoded: '["65"]', + }); + const rt = mockRuntime(chain, { + signer: ADDR.owner, + execute: async () => { + throw new Error(`reverted ${data}`); + }, + }); + await expect(setLabel(rt, gen(), w.address, 'valid')).rejects.toMatchObject( + { decodedError: { name: 'LabelTooLong' } } + ); + expect(rt.events.at(-1)?.id).toBe(PROGRESS_HOOK.AGENTIC_TX_199_02); + }); +}); diff --git a/packages/core/src/lib/agentic/__tests__/management.spec.ts b/packages/core/src/lib/agentic/__tests__/management.spec.ts index 9a2d672b..d9726b6a 100644 --- a/packages/core/src/lib/agentic/__tests__/management.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/management.spec.ts @@ -14,8 +14,8 @@ import { AGW_ABI, AGW_FACTORY_ABI, UNIVERSAL_RULES_POLICY_ABI, -} from '../contracts/abi/v4'; -import { v4 } from '../contracts/v4'; +} from '../contracts/abi/v5'; +import { v5 } from '../contracts/v5'; import { deriveWallet, rulesId as computeRulesId } from '../codec/ids'; import { AGENTIC_ERROR_CODE } from '../errors'; import { createWallet } from '../management/create'; @@ -41,13 +41,13 @@ const rule = (agent = ADDR.agent): NativeRule => ({ const granted = (wallet: `0x${string}`, id: Hex, block = BigInt(101)) => log( wallet, - v4.events.rulesGranted, + v5.events.rulesGranted, { rulesId: id, chainHash: `0x${'00'.repeat(32)}` }, { mode: 1, chainNamespace: PUSH_NS }, block ); const revoked = (wallet: `0x${string}`, id: Hex) => - log(wallet, v4.events.rulesRevoked, { rulesId: id }, {}, BigInt(101)); + log(wallet, v5.events.rulesRevoked, { rulesId: id }, {}, BigInt(101)); function withLogs(logs: Log[], over = {}) { const r = fakeResponse(over); @@ -82,7 +82,7 @@ describe('agentic.create', () => { withLogs([ log( ADDR.factory, - v4.events.walletDeployed, + v5.events.walletDeployed, { owner: ADDR.owner, index: BigInt(0), wallet: nextWallet }, { label: 'ops' }, BigInt(101) @@ -127,7 +127,7 @@ describe('agentic.create', () => { return withLogs([ log( ADDR.factory, - v4.events.walletDeployed, + v5.events.walletDeployed, { owner: ADDR.owner, index: BigInt(0), wallet: nextWallet }, { label: '' }, BigInt(101) @@ -184,7 +184,7 @@ describe('agentic.create', () => { withLogs([ log( ADDR.factory, - v4.events.walletDeployed, + v5.events.walletDeployed, { owner: ADDR.owner, index: BigInt(1), wallet: elsewhere }, { label: '' }, BigInt(101) @@ -204,7 +204,7 @@ describe('agentic.create', () => { withLogs([ log( ADDR.factory, - v4.events.walletDeployed, + v5.events.walletDeployed, { owner: ADDR.owner, index: BigInt(0), wallet: nextWallet }, { label: '' }, BigInt(101) @@ -232,7 +232,7 @@ describe('agentic.create', () => { receipt([ log( ADDR.factory, - v4.events.walletDeployed, + v5.events.walletDeployed, { owner: ADDR.owner, index: BigInt(0), wallet: nextWallet }, { label: 'ops' }, BigInt(101) @@ -361,7 +361,8 @@ describe('agentic.create', () => { const rt = mockRuntime(fake, { signer: ADDR.owner, execute: (async () => { - fake.addWallet(ADDR.owner, 'competing-create'); + const winner = fake.addWallet(ADDR.owner, 'competing-create'); + winner.label = 'this-create'; // mutable view cannot erase the deploy evidence throw new Error('opaque sender failure'); }) as never, }); @@ -379,6 +380,20 @@ describe('agentic.create', () => { }); }); + it('a later rename alone does not establish a competing creation', async () => { + const fake = new FakeChain(); + const failure = new Error('opaque sender failure'); + const rt = mockRuntime(fake, { + signer: ADDR.owner, + execute: (async () => { + const w = fake.addWallet(ADDR.owner, 'this-create'); + w.label = 'renamed-after-deploy'; + throw failure; + }) as never, + }); + await expect(createWallet(rt, 'this-create', { rules: [rule()] })).rejects.toBe(failure); + }); + it('a slot that is already deployed is refused before signing', async () => { const fake = new FakeChain(); fake.predictOverride = (owner, index) => @@ -453,7 +468,7 @@ describe('rules.add / rules.revoke', () => { ).toEqual(ids); const sent = exec.mock.calls[0][0] as { to: string; data: Hex }; expect(Array.isArray(sent.data)).toBe(false); - const outer = v4.decodeWalletCall(sent.data) as { + const outer = v5.decodeWalletCall(sent.data) as { kind: string; calls: { target: string; data: Hex }[]; }; @@ -494,7 +509,7 @@ describe('rules.add / rules.revoke', () => { await revokeRules(rt, gen(), w.address, [ruleId(1), ruleId(2)]); const sent = exec.mock.calls[0][0] as { to: string; data: Hex }; expect(sent.to).toBe(w.address); - const decoded = v4.decodeWalletCall(sent.data) as { + const decoded = v5.decodeWalletCall(sent.data) as { kind: string; calls: { target: string; data: Hex }[]; }; @@ -548,7 +563,7 @@ describe('rules.update — one owner batch: assert → revoke → grant', () => expect(exec).toHaveBeenCalledTimes(1); const sent = exec.mock.calls[0][0] as { to: string; data: Hex }; expect(Array.isArray(sent.data)).toBe(false); // never a sequential multi-tx batch - const outer = v4.decodeWalletCall(sent.data) as { + const outer = v5.decodeWalletCall(sent.data) as { kind: string; mode: Hex; calls: { target: string; data: Hex }[]; @@ -614,7 +629,7 @@ describe('rules.update — one owner batch: assert → revoke → grant', () => rules: [{ rulesId: ruleId(1), rule: rule() }], }); const data = (exec.mock.calls[0][0] as { data: Hex }).data; - const outer = v4.decodeWalletCall(data) as { calls: { data: Hex }[] }; + const outer = v5.decodeWalletCall(data) as { calls: { data: Hex }[] }; const assertion = decodeFunctionData({ abi: UNIVERSAL_RULES_POLICY_ABI, data: outer.calls[0].data, diff --git a/packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts b/packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts index 1bd6462c..ab65c14f 100644 --- a/packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts @@ -3,7 +3,7 @@ import { CHAIN, PUSH_NETWORK } from '../../constants/enums'; import { PUSH_BATCH_EXECUTOR_ADDRESS } from '../../constants/chain'; import { convertExecutorToOrigin } from '../../universal/account/account'; import { adaptTrackedResponse } from '../response'; -import { v4, UEA_MULTICALL_PREFIX } from '../contracts/v4'; +import { v5, UEA_MULTICALL_PREFIX } from '../contracts/v5'; import { resetAgenticGenerations } from '../deployments'; import { ADDR, FakeChain, registerFakeGeneration, ruleId } from './fake-chain'; import { fakeResponse, mockRuntime } from './mock-runtime'; @@ -27,7 +27,7 @@ function fixture() { const outer = actions.map((c) => ({ target: wallet.address, value: BigInt(0), - data: v4.encodeExecuteAsAgent(ruleId(1), c), + data: v5.encodeExecuteAsAgent(ruleId(1), c), })); const runtime = mockRuntime(fake); return { fake, wallet, actions, outer, runtime }; @@ -47,7 +47,7 @@ it('recognizes a verified 7702 self-call and retains every native agent action', fakeResponse({ from: ADDR.agent, to: ADDR.agent, - data: v4.encodeExecute(outer), + data: v5.encodeExecute(outer), }) ); expect(result).toMatchObject({ @@ -112,7 +112,7 @@ it('does not label an arbitrary forwarding contract as a trusted sender batch', const response = fakeResponse({ from: ADDR.agent, to: ADDR.other, - data: v4.encodeExecute(outer), + data: v5.encodeExecute(outer), }); expect(await adaptTrackedResponse(runtime, response)).toBe(response); expect(response.agentic).toBeUndefined(); diff --git a/packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts b/packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts index 6a4c9ab1..9064b48f 100644 --- a/packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts @@ -8,7 +8,7 @@ import { transformToUniversalTxResponse } from '../../orchestrator/internals/res import { adaptTrackedResponse } from '../response'; import { composeOutbound, type DestinationCall } from '../execution/outbound'; import { agenticSend } from '../execution/send'; -import { v4 } from '../contracts/v4'; +import { v5 } from '../contracts/v5'; import { currentGeneration, resetAgenticGenerations } from '../deployments'; import type { AgenticExecutionContext } from '../context'; import { ADDR, FakeChain, registerFakeGeneration, ruleId } from './fake-chain'; @@ -187,8 +187,8 @@ describe.each(['owner', 'agent'] as const)( ); const input = door === 'owner' - ? v4.encodeExecute([out.gatewayCall]) - : v4.encodeExecuteAsAgent(ruleId(1), out.gatewayCall); + ? v5.encodeExecute([out.gatewayCall]) + : v5.encodeExecuteAsAgent(ruleId(1), out.gatewayCall); const signer = door === 'owner' ? ADDR.owner : ADDR.agent; const tx = { hash: PUSH_HASH, diff --git a/packages/core/src/lib/agentic/__tests__/reads-context.spec.ts b/packages/core/src/lib/agentic/__tests__/reads-context.spec.ts index 619c1ffc..15dc1217 100644 --- a/packages/core/src/lib/agentic/__tests__/reads-context.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/reads-context.spec.ts @@ -18,16 +18,16 @@ import { ruleId, } from './fake-chain'; import { mockRuntime } from './mock-runtime'; -import { v4 } from '../contracts/v4'; +import { v5 } from '../contracts/v5'; import { readOriginToken } from '../contracts/prc20-metadata'; describe('generation registry', () => { afterEach(() => resetAgenticGenerations()); - it('ships Donut v4 only; other networks are unsupported', () => { + it('ships Donut v5 only; other networks are unsupported', () => { resetAgenticGenerations(); expect(currentGeneration(PUSH_NETWORK.TESTNET_DONUT)).toMatchObject({ - id: 'v4', + id: 'v5', advertised: true, }); for (const n of Object.values(PUSH_NETWORK).filter( @@ -61,7 +61,7 @@ describe('Donut log-range limit', () => { const getLogs = jest.spyOn(fake, 'getLogs'); await scanLogs( fake, - { address: ADDR.factory, event: v4.events.walletDeployed }, + { address: ADDR.factory, event: v5.events.walletDeployed }, BigInt(10), BigInt(2010) ); @@ -388,7 +388,7 @@ describe('rules.list / rules.get', () => { fake.extraLogs.push( log( w.address, - v4.events.rulesRevoked, + v5.events.rulesRevoked, { rulesId: ruleId(9) }, {}, BigInt(50) @@ -446,7 +446,7 @@ describe('wallet reads', () => { wallets.map((w) => [w.index, w.label, w.deployed, w.rulesCount]) ).toEqual([ [0, 'first', true, 1], - [1, '', true, 0], + [1, 'AGW 2', true, 0], [2, '', false, 0], ]); }); @@ -462,12 +462,15 @@ describe('wallet reads', () => { ]); }); - it('a missing deployment event is an inconsistency, not an empty label', async () => { - const w = fake.addWallet(ADDR.owner, 'x'); + it('reads current labels without depending on deployment logs', async () => { + const w = fake.addWallet(ADDR.owner, 'original'); + w.label = 'renamed'; fake.extraLogs = []; - await expect(walletInfo(fake, gen(), w.address)).rejects.toMatchObject({ - code: AGENTIC_ERROR_CODE.INCONSISTENT_READ, - }); + expect(await walletInfo(fake, gen(), w.address)).toMatchObject({ label: 'renamed' }); + expect((await listForOwner(fake, gen(), ADDR.owner))[0].label).toBe('renamed'); + expect(fake.calls.filter((c) => c.functionName === 'label')).toHaveLength(2); + w.label = ''; + expect(await walletInfo(fake, gen(), w.address)).toMatchObject({ label: 'AGW 1' }); }); it('info of the signer’s next slot describes it as undeployed; other undeployed addresses are refused', async () => { diff --git a/packages/core/src/lib/agentic/__tests__/response-surface.spec.ts b/packages/core/src/lib/agentic/__tests__/response-surface.spec.ts index 9ae2fcaf..3b508a49 100644 --- a/packages/core/src/lib/agentic/__tests__/response-surface.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/response-surface.spec.ts @@ -10,8 +10,8 @@ import { PUSH_NETWORK } from '../../constants/enums'; import { UNIVERSAL_GATEWAY_PC } from '../../constants/abi'; import { PushChainExecutionError } from '../../orchestrator/internals/errors'; import { Utils } from '../../utils'; -import { AGW_ABI } from '../contracts/abi/v4'; -import { v4 } from '../contracts/v4'; +import { AGW_ABI } from '../contracts/abi/v5'; +import { v5 } from '../contracts/v5'; import { resetAgenticGenerations } from '../deployments'; import { AgenticRevertError } from '../errors'; import { adaptAgenticResponse, adaptTrackedResponse } from '../response'; @@ -58,7 +58,7 @@ describe('response identity', () => { registerFakeGeneration(); const fake = new FakeChain(); const w = fake.addWallet(ADDR.owner, 'w'); - const data = v4.encodeExecuteAsAgent(ruleId(4), { + const data = v5.encodeExecuteAsAgent(ruleId(4), { target: ADDR.target, value: BigInt(0), data: '0xd09de08a', @@ -120,7 +120,7 @@ describe('response identity', () => { }, ], }); - const data = v4.encodeExecuteAsAgent(ruleId(4), { + const data = v5.encodeExecuteAsAgent(ruleId(4), { target: ADDR.gateway, value: BigInt(5), data: gatewayCall, @@ -155,7 +155,7 @@ describe('response identity', () => { registerFakeGeneration(); const spoof = fakeResponse({ to: ADDR.target, - data: v4.encodeExecute([ + data: v5.encodeExecute([ { target: ADDR.other, value: BigInt(0), data: '0x' }, ]), }); @@ -225,9 +225,9 @@ describe('public surface', () => { expect(new AgenticRevertError('x', { cause: 'c' }).cause).toBe('c'); }); - it('CONSTANTS.AGENTIC carries the checked Donut v4 proxies', () => { + it('CONSTANTS.AGENTIC carries the checked Donut v5 proxies', () => { expect(CONSTANTS.AGENTIC.TESTNET_DONUT).toMatchObject({ - FACTORY: '0xaF88D0FD947afAe7bBb8F34e8417DCfc165e1aaF', + FACTORY: '0x8137F96A50EBF41d904e3678c84c391a0D1BCcc5', RULES_POLICY: '0x603E7f0aF6e1aAFf46DDfb28b1e99364f8BC59af', ENVELOPE_VERSION: 1, }); diff --git a/packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts b/packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts index 477d94e8..fe301376 100644 --- a/packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts @@ -6,7 +6,7 @@ import { encodeUniversalTerms } from '../codec/universal-terms'; import { buildSession, encodeEnvelope, encodeSession } from '../codec/session'; import { prepareRules } from '../codec/rules'; import { validateUniversalRuleShape } from '../codec/universal'; -import { V4_CAPABILITIES } from '../deployments'; +import { V5_CAPABILITIES } from '../deployments'; import { AGENTIC_ERROR_CODE } from '../errors'; import { internalAgenticUtils } from '../utils'; import type { NativeRule, UniversalRule } from '../agentic.types'; @@ -18,7 +18,7 @@ const ctx = { pushChainNamespace: PUSH_NS, validator: ADDR.validator, rulesPolicy: ADDR.policy, - capabilities: V4_CAPABILITIES, + capabilities: V5_CAPABILITIES, nowSeconds: NOW, forbiddenTargets: [ ADDR.factory, @@ -285,7 +285,7 @@ describe('internal generation codecs (pure)', () => { ); }); - it('pure decoding resolves known v4 assets and preserves the exact beneficiary offset', () => { + it('pure decoding resolves known v5 assets and preserves the exact beneficiary offset', () => { const inputToken = MOVEABLE_TOKEN_CONSTANTS.ETHEREUM_SEPOLIA.USDC; const prc20 = getPRC20Address(inputToken, { network: PUSH_NETWORK.TESTNET_DONUT, diff --git a/packages/core/src/lib/agentic/__tests__/send.spec.ts b/packages/core/src/lib/agentic/__tests__/send.spec.ts index 2f459d28..5291fac1 100644 --- a/packages/core/src/lib/agentic/__tests__/send.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/send.spec.ts @@ -13,7 +13,7 @@ import { PushChainExecutionError } from '../../orchestrator/internals/errors'; import { PROGRESS_HOOK } from '../../progress-hook/progress-hook.types'; import type { AgenticExecutionContext } from '../context'; import { currentGeneration, resetAgenticGenerations } from '../deployments'; -import { v4 } from '../contracts/v4'; +import { v5 } from '../contracts/v5'; import { actionId } from '../codec/ids'; import { AGENTIC_ERROR_CODE, AgenticRevertError } from '../errors'; import { agenticSend } from '../execution/send'; @@ -111,7 +111,7 @@ describe('guards fail before the signer is ever invoked', () => { data: Hex; }[]; expect(batch.map((c) => c.to)).toEqual([ctx.wallet, ctx.wallet]); - expect(batch.map((c) => v4.decodeWalletCall(c.data))).toEqual( + expect(batch.map((c) => v5.decodeWalletCall(c.data))).toEqual( calls.map((c) => ({ kind: 'executeAsAgent', rulesId: ruleId(1), @@ -186,7 +186,7 @@ describe('explicit Push destinations', () => { data, }); expect( - v4.decodeWalletCall(rt.executeMock.mock.calls[0][0].data) + v5.decodeWalletCall(rt.executeMock.mock.calls[0][0].data) ).toMatchObject({ kind: 'executeAsAgent', rulesId: ruleId(1) }); expect(tx.route).not.toBe('UOA_TO_CEA'); expect(tx.to).toBe(ADDR.target); @@ -199,7 +199,7 @@ describe('explicit Push destinations', () => { data, }); expect( - v4.decodeWalletCall(rt.executeMock.mock.calls[0][0].data) + v5.decodeWalletCall(rt.executeMock.mock.calls[0][0].data) ).toMatchObject({ kind: 'execute', calls: [{ target: ADDR.target }] }); }); @@ -228,7 +228,7 @@ describe('native wrapping and logical identity', () => { const sent = rt.executeMock.mock.calls[0][0]; expect(sent.to).toBe(w.address); expect(sent.value).toBe(BigInt(0)); - expect(v4.decodeWalletCall(sent.data)).toEqual({ + expect(v5.decodeWalletCall(sent.data)).toEqual({ kind: 'executeAsAgent', rulesId: ruleId(1), mode: `0x${'00'.repeat(32)}`, @@ -267,7 +267,7 @@ describe('native wrapping and logical identity', () => { { to: ADDR.other, value: BigInt(1), data: '0x' }, ], }); - const decoded = v4.decodeWalletCall(rt.executeMock.mock.calls[0][0].data); + const decoded = v5.decodeWalletCall(rt.executeMock.mock.calls[0][0].data); expect(decoded).toMatchObject({ kind: 'execute', mode: `0x01${'00'.repeat(31)}`, @@ -366,7 +366,7 @@ describe('EVM outbound composition from the wallet', () => { s.w.address, CHAIN.ETHEREUM_SEPOLIA ); - const outer = v4.decodeWalletCall(rt.executeMock.mock.calls[0][0].data) as { + const outer = v5.decodeWalletCall(rt.executeMock.mock.calls[0][0].data) as { kind: string; rulesId: Hex; calls: { target: Address; value: bigint; data: Hex }[]; @@ -421,7 +421,7 @@ describe('EVM outbound composition from the wallet', () => { expect(rt.executeMock).not.toHaveBeenCalled(); }); - it('wallet PC below protocol fee + gas cap, or over the rule PC cap, fails before signing', async () => { + it('wallet funding is checked locally; rule PC limits are enforced by the contract', async () => { const s = universalSetup(); s.fake.balances.set(`pc:${s.w.address.toLowerCase()}`, BigInt(10)); const rt = mockRuntime(s.fake, { @@ -441,9 +441,9 @@ describe('EVM outbound composition from the wallet', () => { gasLimitUsed: BigInt(1), }), }); - await expect(agenticSend(pricey, s2.ctx, send())).rejects.toMatchObject({ - code: AGENTIC_ERROR_CODE.RULE_LIMIT_EXCEEDED, - }); + const response = await agenticSend(pricey, s2.ctx, send()); + expect(pricey.executeMock).toHaveBeenCalledTimes(1); + expect(response.agentic?.rulesId).toBe(ruleId(5)); }); it('a committed destination account that no longer matches derivation is drift, not a send', async () => { @@ -500,7 +500,7 @@ describe('EVM outbound composition from the wallet', () => { resolvePrc20: () => token, }); await agenticSend(rt, s.ctx, send(BigInt(100))); - const outer = v4.decodeWalletCall(rt.executeMock.mock.calls[0][0].data) as { + const outer = v5.decodeWalletCall(rt.executeMock.mock.calls[0][0].data) as { kind: string; calls: { target: Address; data: Hex }[]; }; @@ -558,7 +558,7 @@ describe('EVM outbound composition from the wallet', () => { to: { address: recipient, chain: CHAIN.ETHEREUM_SEPOLIA }, funds: { amount: BigInt(100), token: usdc }, }); - const outer = v4.decodeWalletCall(rt.executeMock.mock.calls[0][0].data) as { + const outer = v5.decodeWalletCall(rt.executeMock.mock.calls[0][0].data) as { calls: { data: Hex }[]; }; const { args } = decodeFunctionData({ @@ -606,7 +606,7 @@ describe('EVM outbound composition from the wallet', () => { to: { address: ADDR.other, chain: CHAIN.ETHEREUM_SEPOLIA }, value: BigInt(7), }); - const outer = v4.decodeWalletCall(rt.executeMock.mock.calls[0][0].data) as { + const outer = v5.decodeWalletCall(rt.executeMock.mock.calls[0][0].data) as { calls: { data: Hex }[]; }; const req = decodeFunctionData({ diff --git a/packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts b/packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts index aeaef84d..0d7317fc 100644 --- a/packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts @@ -58,7 +58,7 @@ const accounts = [ { pubkey: ATA, isWritable: true }, ]; -describe('v4 internal SVM wire codec', () => { +describe('v5 internal SVM wire codec', () => { it('round-trips ordered per-token caps and all four data-pin modes', () => { const t = base(); t.dataPins = [ diff --git a/packages/core/src/lib/agentic/__tests__/svm-quote.spec.ts b/packages/core/src/lib/agentic/__tests__/svm-quote.spec.ts new file mode 100644 index 00000000..766135cd --- /dev/null +++ b/packages/core/src/lib/agentic/__tests__/svm-quote.spec.ts @@ -0,0 +1,251 @@ +import { + decodeFunctionResult, + encodeAbiParameters, + type Abi, + type Hex, +} from 'viem'; +import { preparePublicSvmRule } from '../management/svm-public'; +import { resolveSvmAssets } from '../management/svm-context'; +import { readSvmSourceToken } from '../contracts/prc20-metadata'; +import { PublicKey } from '@solana/web3.js'; +import { MOVEABLE_TOKEN_CONSTANTS } from '../../constants/tokens'; +import { getPRC20Address } from '../../universal/prc20-address'; +import { CHAIN } from '../../constants/enums'; +import { Snapshot } from '../reads/snapshot'; +import { quoteSvmRequest } from '../execution/svm-quote'; +import { ADDR, FakeChain } from './fake-chain'; +import { mockRuntime } from './mock-runtime'; +const mint = '0x' + '33'.repeat(32); +function fixture(chain = CHAIN.SOLANA_DEVNET) { + const fake = new FakeChain(); + fake.readContract = async ({ functionName }) => + functionName === 'gasTokenPRC20ByChainNamespace' + ? ADDR.other + : functionName === 'SOURCE_CHAIN_NAMESPACE' + ? chain + : mint; + const quoteOutbound = jest.fn().mockResolvedValue({ + protocolFee: BigInt(1), + nativeValueForGas: BigInt(10), + gasLimitUsed: BigInt(100), + }); + return { + snap: new Snapshot(fake, BigInt(1)), + rt: mockRuntime(fake, { quoteOutbound }), + quoteOutbound, + }; +} +describe('AGW Solana finalization quote context', () => { + it('uses the wallet identity and actual source mint for SPL rent budgeting', async () => { + const f = fixture(); + await quoteSvmRequest( + f.rt, + f.snap, + ADDR.owner, + ADDR.target, + CHAIN.SOLANA_DEVNET, + BigInt(0), + BigInt(5) + ); + expect(f.quoteOutbound).toHaveBeenCalledWith( + ADDR.target, + BigInt(0), + CHAIN.SOLANA_DEVNET, + { + wallet: ADDR.owner, + splMintBase58: new PublicKey( + Buffer.from(mint.slice(2), 'hex') + ).toBase58(), + burnAmount: BigInt(5), + } + ); + }); + it('native transfers carry no SPL mint or ATA requirement', async () => { + const f = fixture(); + const q = await quoteSvmRequest( + f.rt, + f.snap, + ADDR.owner, + ADDR.other, + CHAIN.SOLANA_DEVNET, + BigInt(0), + BigInt(5) + ); + expect(q.isNative).toBe(true); + expect(f.quoteOutbound.mock.calls[0][3].splMintBase58).toBeUndefined(); + }); + it('zero-burn instruction quotes do not add a transfer ATA requirement', async () => { + const f = fixture(); + await quoteSvmRequest( + f.rt, + f.snap, + ADDR.owner, + ADDR.target, + CHAIN.SOLANA_DEVNET, + BigInt(0), + BigInt(0) + ); + expect(f.quoteOutbound.mock.calls[0][3].splMintBase58).toBeUndefined(); + }); + it('an asset from another chain fails route validation without a quote', async () => { + const f = fixture(CHAIN.ETHEREUM_SEPOLIA); + await expect( + quoteSvmRequest( + f.rt, + f.snap, + ADDR.owner, + ADDR.target, + CHAIN.SOLANA_DEVNET, + BigInt(0), + BigInt(5) + ) + ).rejects.toMatchObject({ code: 'ASSET_CHAIN_MISMATCH' }); + expect(f.quoteOutbound).not.toHaveBeenCalled(); + }); + it('decodes the real precompile word when a Solidity string ABI cannot decode it', async () => { + const f = fixture(); + const read = f.snap.reader.readContract; + const outputTypes: string[] = []; + f.snap.reader.readContract = async (args) => { + if (args.functionName !== 'SOURCE_TOKEN_ADDRESS') return read(args); + const fn = (args.abi as Abi).find( + (entry) => entry.type === 'function' && entry.name === args.functionName + ); + if (fn?.type !== 'function') throw new Error('missing metadata ABI'); + outputTypes.push(fn.outputs[0].type); + return decodeFunctionResult({ + abi: args.abi as Abi, + functionName: args.functionName, + data: encodeAbiParameters([{ type: 'bytes32' }], [mint as Hex]), + }); + }; + await quoteSvmRequest( + f.rt, + f.snap, + ADDR.owner, + ADDR.target, + CHAIN.SOLANA_DEVNET, + BigInt(0), + BigInt(5) + ); + expect(outputTypes).toEqual(['string', 'bytes32']); + const expected = new PublicKey( + Buffer.from(mint.slice(2), 'hex') + ).toBase58(); + expect(f.quoteOutbound.mock.calls[0][3].splMintBase58).toBe(expected); + const metadata = { + gateway: jest.fn(), + mint: jest.fn().mockResolvedValue({ + mint: expected, + tokenProgram: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', + }), + }; + const assets = await resolveSvmAssets( + f.snap, + CHAIN.SOLANA_DEVNET, + [{ token: ADDR.target, maxPerCall: BigInt(5), maxTotal: BigInt(5) }], + metadata + ); + expect(assets[0]).toMatchObject({ kind: 'spl', mint: expected }); + expect(metadata.mint).toHaveBeenCalledWith(CHAIN.SOLANA_DEVNET, mint); + }); + + it('does not fabricate a mint when both metadata representations fail', async () => { + const f = fixture(); + f.snap.reader.readContract = async () => { + throw new Error('RPC unavailable'); + }; + await expect( + readSvmSourceToken(f.snap, ADDR.target, CHAIN.SOLANA_DEVNET) + ).rejects.toMatchObject({ + code: 'RULE_READ_FAILED', + cause: { message: 'RPC unavailable' }, + }); + expect(f.quoteOutbound).not.toHaveBeenCalled(); + }); + it('uses the current registered SPL mint when Donut metadata returns a zero word', async () => { + const f = fixture(); + const asset = MOVEABLE_TOKEN_CONSTANTS.SOLANA_DEVNET.USDT; + const token = getPRC20Address({ + chain: CHAIN.SOLANA_DEVNET, + address: asset.address, + }).address; + const read = f.snap.reader.readContract; + f.snap.reader.readContract = async (args) => { + if (args.functionName !== 'SOURCE_TOKEN_ADDRESS') return read(args); + return decodeFunctionResult({ + abi: args.abi as Abi, + functionName: args.functionName, + data: encodeAbiParameters( + [{ type: 'bytes32' }], + [`0x${'00'.repeat(32)}`] + ), + }); + }; + await quoteSvmRequest( + f.rt, + f.snap, + ADDR.owner, + token, + CHAIN.SOLANA_DEVNET, + BigInt(0), + BigInt(1000) + ); + expect(f.quoteOutbound.mock.calls[0][3].splMintBase58).toBe(asset.address); + await expect( + readSvmSourceToken(f.snap, ADDR.target, CHAIN.SOLANA_DEVNET) + ).rejects.toMatchObject({ code: 'INVALID_RULE' }); + }); + it('canonicalizes a decoded SPL mint before resolving its PRC20 mapping', async () => { + const f = fixture(); + const expected = new PublicKey( + Buffer.from(mint.slice(2), 'hex') + ).toBase58(); + const program = `0x${'44'.repeat(32)}` as Hex; + const rt = { + ...f.rt, + resolvePrc20: jest.fn().mockReturnValue(ADDR.target), + svmMetadata: { + gateway: async () => ({ + chainNamespace: CHAIN.SOLANA_DEVNET, + program: `0x${'22'.repeat(32)}`, + }), + mint: async () => ({ + mint: expected, + tokenProgram: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', + }), + }, + }; + await preparePublicSvmRule(rt, f.snap, ADDR.owner, { + agent: ADDR.agent, + chainNamespace: CHAIN.SOLANA_DEVNET, + assets: [{ token: mint, maxPerCall: BigInt(5), maxTotal: BigInt(5) }], + validUntil: f.rt.nowSeconds() + 3600, + maxGasPerCall: BigInt(10), + allowedInstructions: [ + { + program, + accounts: [{ name: 'authority', expected: { kind: 'walletCEA' } }], + instruction: { + name: 'ping', + idl: { + address: new PublicKey( + Buffer.from(program.slice(2), 'hex') + ).toBase58(), + metadata: { name: 'fixture', version: '1', spec: '0.1.0' }, + instructions: [ + { + name: 'ping', + discriminator: [1, 2, 3, 4, 5, 6, 7, 8], + accounts: [{ name: 'authority', signer: true }], + args: [], + }, + ], + }, + }, + }, + ], + }); + expect(rt.resolvePrc20).toHaveBeenCalledWith(expected, CHAIN.SOLANA_DEVNET); + }); +}); diff --git a/packages/core/src/lib/agentic/agentic.types.ts b/packages/core/src/lib/agentic/agentic.types.ts index 97c8e9b9..a0d1b6b2 100644 --- a/packages/core/src/lib/agentic/agentic.types.ts +++ b/packages/core/src/lib/agentic/agentic.types.ts @@ -188,7 +188,7 @@ export interface AgenticWallet { address: AgenticAddress; info(): Promise; owner(): Promise<{ owner: AgenticAddress }>; - /** Pending contract delivery; unavailable on the currently registered deployment. */ + /** Owner-only rename, at most 64 UTF-8 bytes. Empty resets the default label. */ setLabel( label: string, opts?: { progressHook?: AgenticProgressHook } @@ -262,6 +262,12 @@ export interface AgenticTxMetadata { data: AgenticHex; accounts: readonly { pubkey: AgenticHex; isWritable: boolean }[]; }; + /** Funds-only Solana transfer. token is the burned PRC20 on Push. */ + destinationTransfer?: { + recipient: AgenticHex; + token: AgenticAddress; + amount: bigint; + }; /** Ordered actions in a native agent batch; to/data/value summarize its first action. */ nativeCalls?: readonly { to: AgenticAddress; diff --git a/packages/core/src/lib/agentic/capabilities.ts b/packages/core/src/lib/agentic/capabilities.ts index c3d3b5b0..6e481d07 100644 --- a/packages/core/src/lib/agentic/capabilities.ts +++ b/packages/core/src/lib/agentic/capabilities.ts @@ -21,7 +21,7 @@ export enum AgenticCapability { ASSERT_SPENT_NATIVE = 'assertSpentNative', /** checkpointCount + Checkpointed events. */ CHECKPOINTS = 'checkpoints', - /** Agent-door EVM outbound composition against v4 per-token caps. */ + /** Agent-door EVM outbound composition against v5 per-token caps. */ UNIVERSAL_EVM_OUTBOUND = 'universalEvmOutbound', /** Target UniversalRule (assets[] / maxGasPerCall) encode/decode. A05/A07. */ UNIVERSAL_EVM_RULES = 'universalEvmRules', diff --git a/packages/core/src/lib/agentic/codec/defaults.ts b/packages/core/src/lib/agentic/codec/defaults.ts index fdf04fe3..cc652c46 100644 --- a/packages/core/src/lib/agentic/codec/defaults.ts +++ b/packages/core/src/lib/agentic/codec/defaults.ts @@ -11,7 +11,7 @@ export const UINT256_MAX = BigInt(2) ** BigInt(256) - BigInt(1); export interface DefaultRow { value: bigint; meaning: string; - source: 'product' | 'v4'; + source: 'product' | 'v5'; } export const AGENTIC_DEFAULTS = { @@ -41,7 +41,7 @@ export const AGENTIC_DEFAULTS = { assetMaxTotal: { value: UINT256_MAX, meaning: 'unlimited total; explicit zero forbids movement', - source: 'v4', + source: 'v5', }, allowedCallMaxValue: { value: BigInt(0), diff --git a/packages/core/src/lib/agentic/codec/ids.ts b/packages/core/src/lib/agentic/codec/ids.ts index a33267ef..56c4f473 100644 --- a/packages/core/src/lib/agentic/codec/ids.ts +++ b/packages/core/src/lib/agentic/codec/ids.ts @@ -12,7 +12,7 @@ import { import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; /** - * Pure identity helpers mirroring the pinned AGW generation (v4): + * Pure identity helpers mirroring the pinned AGW generation (v5): * smartsessions IdLib.toActionId / toConfigId / toPermissionId and * AGWFactory._predict (OZ Clones immutable-args CREATE2). * Every input that changes the result is explicit — validator, factory and diff --git a/packages/core/src/lib/agentic/codec/native.ts b/packages/core/src/lib/agentic/codec/native.ts index 2b3ae2da..b1197685 100644 --- a/packages/core/src/lib/agentic/codec/native.ts +++ b/packages/core/src/lib/agentic/codec/native.ts @@ -18,12 +18,12 @@ import { type ParsedSelector, } from './selectors'; -/** URP native limits at v4 (Types.sol MAX_PINS, AGW MAX_NATIVE_ACTIONS). */ +/** URP native limits at v5 (Types.sol MAX_PINS, AGW MAX_NATIVE_ACTIONS). */ export const MAX_PINS = 8; const UINT32_MAX = 2 ** 32 - 1; const UINT48_MAX = 2 ** 48 - 1; -/** NativeTerms (Types.sol:354-363 at v4). */ +/** NativeTerms (Types.sol:354-363 at v5). */ export interface NativeTermsWire { validUntil: number; target: Address; diff --git a/packages/core/src/lib/agentic/codec/rules.ts b/packages/core/src/lib/agentic/codec/rules.ts index e9b2fc2a..0d5364b8 100644 --- a/packages/core/src/lib/agentic/codec/rules.ts +++ b/packages/core/src/lib/agentic/codec/rules.ts @@ -22,7 +22,7 @@ import { import { buildSession, encodeEnvelope, type SessionWire } from './session'; import { encodeUniversalRule, type ResolvedUniversalRule } from './universal'; import { encodeSvmTerms, type SvmTermsWire } from './svm-terms'; -import { SEND_OUTBOUND_SELECTOR } from '../contracts/v4'; +import { SEND_OUTBOUND_SELECTOR } from '../contracts/v5'; import type { UniversalTermsWire } from './universal-terms'; export function isSolanaRule(rule: Rule): rule is SolanaRule { @@ -78,7 +78,7 @@ export interface PreparedRule { svmTerms?: SvmTermsWire; } -/** Validate before signing. V4 permits several grants for the same agent/chain. */ +/** Validate before signing. V5 permits several grants for the same agent/chain. */ export function prepareRules( rules: readonly Rule[], ctx: RuleEncodeContext & { diff --git a/packages/core/src/lib/agentic/codec/session.ts b/packages/core/src/lib/agentic/codec/session.ts index 0cbe5d0a..fc98c1f6 100644 --- a/packages/core/src/lib/agentic/codec/session.ts +++ b/packages/core/src/lib/agentic/codec/session.ts @@ -6,13 +6,13 @@ import { type Address, type Hex, } from 'viem'; -import { AGW_ABI } from '../contracts/abi/v4'; +import { AGW_ABI } from '../contracts/abi/v5'; import { agentConfig } from './ids'; import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; /** * The smartsessions `Session` a grant carries (DataTypes.sol:56-86, pinned - * v4). The wallet overwrites `salt` with its grant nonce, so the value + * v5). The wallet overwrites `salt` with its grant nonce, so the value * sent is irrelevant; it is always zero here. */ export interface SessionWire { @@ -44,7 +44,7 @@ const ZERO_SALT = `0x${'00'.repeat(32)}` as Hex; export const ENVELOPE_VERSION = 1; -/** V4 URP envelope: abi.encode(uint16(1), string chainNamespace, bytes body). */ +/** V5 URP envelope: abi.encode(uint16(1), string chainNamespace, bytes body). */ export function encodeEnvelope(chainNamespace: string, body: Hex): Hex { return encodeAbiParameters( [{ type: 'uint16' }, { type: 'string' }, { type: 'bytes' }], diff --git a/packages/core/src/lib/agentic/codec/svm-terms.ts b/packages/core/src/lib/agentic/codec/svm-terms.ts index 2a096257..dfae8ad7 100644 --- a/packages/core/src/lib/agentic/codec/svm-terms.ts +++ b/packages/core/src/lib/agentic/codec/svm-terms.ts @@ -1,4 +1,4 @@ -/** Internal v4 SVM wire representation; not a proposed public Rule API. */ +/** Internal v5 SVM wire representation; not a proposed public Rule API. */ import { decodeAbiParameters, encodeAbiParameters, diff --git a/packages/core/src/lib/agentic/codec/universal.ts b/packages/core/src/lib/agentic/codec/universal.ts index 2d20db24..d27b48ff 100644 --- a/packages/core/src/lib/agentic/codec/universal.ts +++ b/packages/core/src/lib/agentic/codec/universal.ts @@ -7,7 +7,7 @@ import { argumentOffset, rawOffset } from './abi-layout'; import { parseSelector } from './selectors'; import { AGENTIC_DEFAULTS, UINT256_MAX, withDefault } from './defaults'; import { buildSession, encodeEnvelope } from './session'; -import { SEND_OUTBOUND_SELECTOR } from '../contracts/v4'; +import { SEND_OUTBOUND_SELECTOR } from '../contracts/v5'; import { encodeUniversalTerms, type AssetCapWire, diff --git a/packages/core/src/lib/agentic/constants.ts b/packages/core/src/lib/agentic/constants.ts index 89d39e0b..f2f7d24b 100644 --- a/packages/core/src/lib/agentic/constants.ts +++ b/packages/core/src/lib/agentic/constants.ts @@ -1,7 +1,7 @@ import { PUSH_NETWORK } from '../constants/enums'; -import { DONUT_V4_ADDRESSES } from './contracts/donut-v4'; +import { DONUT_V5_ADDRESSES } from './contracts/donut-v5'; -/** Checked Donut v4 proxies. Unsupported networks are absent. */ +/** Checked Donut v5 proxies. Unsupported networks are absent. */ export interface AgenticNetworkConstants { FACTORY: `0x${string}`; RULES_POLICY: `0x${string}`; @@ -14,8 +14,8 @@ export const AGENTIC: Readonly< Partial> > = Object.freeze({ [PUSH_NETWORK.TESTNET_DONUT]: Object.freeze({ - FACTORY: DONUT_V4_ADDRESSES.factory, - RULES_POLICY: DONUT_V4_ADDRESSES.rulesPolicy, + FACTORY: DONUT_V5_ADDRESSES.factory, + RULES_POLICY: DONUT_V5_ADDRESSES.rulesPolicy, MAX_PINS: 8, MAX_ALLOWED_CALLS: 32, ENVELOPE_VERSION: 1, diff --git a/packages/core/src/lib/agentic/contracts/abi/v4/agent-validator.ts b/packages/core/src/lib/agentic/contracts/abi/v5/agent-validator.ts similarity index 50% rename from packages/core/src/lib/agentic/contracts/abi/v4/agent-validator.ts rename to packages/core/src/lib/agentic/contracts/abi/v5/agent-validator.ts index d5924e33..069206f6 100644 --- a/packages/core/src/lib/agentic/contracts/abi/v4/agent-validator.ts +++ b/packages/core/src/lib/agentic/contracts/abi/v5/agent-validator.ts @@ -1,145 +1,145 @@ // GENERATED by packages/core/scripts/agw-local/gen-abi.mjs — do not edit. // Source: packages/core/scripts/agw-local/abis/validator.json -// push-agentic-wallets@e8db74815cfbbf5389593805e464fe8d85f7f735 -// sha256(AgentValidator.json) = d2555b2f54d56ed24268af650b19ad10f2d34906b2e0c4ff78dd6de54ba34cc2 +// push-agentic-wallets@2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb +// sha256(AgentValidator.json) = a4570ddc373241580de8742cbb3d9f2c837094c65bfd1cdd52243ca0c38196fd export const AGENT_VALIDATOR_ABI = [ { + "type": "function", + "name": "isInitialized", "inputs": [ { - "internalType": "address", - "name": "smartAccount", - "type": "address" - } - ], - "name": "AlreadyInitialized", - "type": "error" - }, - { - "inputs": [], - "name": "MalformedConfig", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "smartAccount", - "type": "address" - } - ], - "name": "NotInitialized", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", "name": "", - "type": "address" + "type": "address", + "internalType": "address" } ], - "name": "isInitialized", "outputs": [ { - "internalType": "bool", "name": "", - "type": "bool" + "type": "bool", + "internalType": "bool" } ], - "stateMutability": "pure", - "type": "function" + "stateMutability": "pure" }, { + "type": "function", + "name": "isModuleType", "inputs": [ { - "internalType": "uint256", "name": "moduleTypeId", - "type": "uint256" + "type": "uint256", + "internalType": "uint256" } ], - "name": "isModuleType", "outputs": [ { - "internalType": "bool", "name": "", - "type": "bool" + "type": "bool", + "internalType": "bool" } ], - "stateMutability": "pure", - "type": "function" + "stateMutability": "pure" }, { + "type": "function", + "name": "onInstall", "inputs": [ { - "internalType": "bytes", "name": "", - "type": "bytes" + "type": "bytes", + "internalType": "bytes" } ], - "name": "onInstall", "outputs": [], - "stateMutability": "pure", - "type": "function" + "stateMutability": "pure" }, { + "type": "function", + "name": "onUninstall", "inputs": [ { - "internalType": "bytes", "name": "", - "type": "bytes" + "type": "bytes", + "internalType": "bytes" } ], - "name": "onUninstall", "outputs": [], - "stateMutability": "pure", - "type": "function" + "stateMutability": "pure" }, { + "type": "function", + "name": "validateConfig", "inputs": [ { - "internalType": "bytes", "name": "data", - "type": "bytes" + "type": "bytes", + "internalType": "bytes" } ], - "name": "validateConfig", "outputs": [ { - "internalType": "bool", "name": "", - "type": "bool" + "type": "bool", + "internalType": "bool" } ], - "stateMutability": "pure", - "type": "function" + "stateMutability": "pure" }, { + "type": "function", + "name": "validateSignatureWithData", "inputs": [ { - "internalType": "bytes32", "name": "", - "type": "bytes32" + "type": "bytes32", + "internalType": "bytes32" }, { - "internalType": "bytes", "name": "sig", - "type": "bytes" + "type": "bytes", + "internalType": "bytes" }, { - "internalType": "bytes", "name": "data", - "type": "bytes" + "type": "bytes", + "internalType": "bytes" } ], - "name": "validateSignatureWithData", "outputs": [ { - "internalType": "bool", "name": "validSig", - "type": "bool" + "type": "bool", + "internalType": "bool" } ], - "stateMutability": "pure", - "type": "function" + "stateMutability": "pure" + }, + { + "type": "error", + "name": "AlreadyInitialized", + "inputs": [ + { + "name": "smartAccount", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "MalformedConfig", + "inputs": [] + }, + { + "type": "error", + "name": "NotInitialized", + "inputs": [ + { + "name": "smartAccount", + "type": "address", + "internalType": "address" + } + ] } ] as const; diff --git a/packages/core/src/lib/agentic/contracts/abi/v4/agw-factory.ts b/packages/core/src/lib/agentic/contracts/abi/v5/agw-factory.ts similarity index 51% rename from packages/core/src/lib/agentic/contracts/abi/v4/agw-factory.ts rename to packages/core/src/lib/agentic/contracts/abi/v5/agw-factory.ts index c355b370..45519e58 100644 --- a/packages/core/src/lib/agentic/contracts/abi/v4/agw-factory.ts +++ b/packages/core/src/lib/agentic/contracts/abi/v5/agw-factory.ts @@ -1,1104 +1,1104 @@ // GENERATED by packages/core/scripts/agw-local/gen-abi.mjs — do not edit. // Source: packages/core/scripts/agw-local/abis/factory.json -// push-agentic-wallets@e8db74815cfbbf5389593805e464fe8d85f7f735 -// sha256(AGWFactory.json) = c58ac31b81a64b4ab5b89c5aef3f6d01a405607395af71b5466d55fe9c1d5b99 +// push-agentic-wallets@2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb +// sha256(AGWFactory.json) = b65f66a1556d2a9ddf9aabe9f595c685c2aada436772892f5a40fb1eec846397 export const AGW_FACTORY_ABI = [ { + "type": "function", + "name": "DEFAULT_ADMIN_ROLE", "inputs": [], - "name": "AccessControlBadConfirmation", - "type": "error" - }, - { - "inputs": [ + "outputs": [ { - "internalType": "uint48", - "name": "schedule", - "type": "uint48" + "name": "", + "type": "bytes32", + "internalType": "bytes32" } ], - "name": "AccessControlEnforcedDefaultAdminDelay", - "type": "error" + "stateMutability": "view" }, { + "type": "function", + "name": "OPERATOR_ROLE", "inputs": [], - "name": "AccessControlEnforcedDefaultAdminRules", - "type": "error" - }, - { - "inputs": [ + "outputs": [ { - "internalType": "address", - "name": "defaultAdmin", - "type": "address" + "name": "", + "type": "bytes32", + "internalType": "bytes32" } ], - "name": "AccessControlInvalidDefaultAdmin", - "type": "error" + "stateMutability": "view" }, { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, + "type": "function", + "name": "PAUSER_ROLE", + "inputs": [], + "outputs": [ { - "internalType": "bytes32", - "name": "neededRole", - "type": "bytes32" + "name": "", + "type": "bytes32", + "internalType": "bytes32" } ], - "name": "AccessControlUnauthorizedAccount", - "type": "error" + "stateMutability": "view" }, { - "inputs": [ + "type": "function", + "name": "UPGRADE_INTERFACE_VERSION", + "inputs": [], + "outputs": [ { - "internalType": "address", - "name": "target", - "type": "address" + "name": "", + "type": "string", + "internalType": "string" } ], - "name": "AddressEmptyCode", - "type": "error" - }, - { - "inputs": [], - "name": "CloneArgumentsTooLong", - "type": "error" + "stateMutability": "view" }, { + "type": "function", + "name": "acceptDefaultAdminTransfer", "inputs": [], - "name": "Create2EmptyBytecode", - "type": "error" + "outputs": [], + "stateMutability": "nonpayable" }, { + "type": "function", + "name": "beginDefaultAdminTransfer", "inputs": [ { - "internalType": "address", - "name": "implementation", - "type": "address" + "name": "newAdmin", + "type": "address", + "internalType": "address" } ], - "name": "ERC1967InvalidImplementation", - "type": "error" - }, - { - "inputs": [], - "name": "ERC1967NonPayable", - "type": "error" + "outputs": [], + "stateMutability": "nonpayable" }, { + "type": "function", + "name": "cancelDefaultAdminTransfer", "inputs": [], - "name": "EnforcedPause", - "type": "error" + "outputs": [], + "stateMutability": "nonpayable" }, { + "type": "function", + "name": "changeDefaultAdminDelay", "inputs": [ { - "internalType": "address", - "name": "expected", - "type": "address" - }, - { - "internalType": "address", - "name": "actual", - "type": "address" + "name": "newDelay", + "type": "uint48", + "internalType": "uint48" } ], - "name": "ExecutorMismatch", - "type": "error" - }, - { - "inputs": [], - "name": "ExpectedPause", - "type": "error" + "outputs": [], + "stateMutability": "nonpayable" }, { + "type": "function", + "name": "defaultAdmin", "inputs": [], - "name": "FailedCall", - "type": "error" + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" }, { + "type": "function", + "name": "defaultAdminDelay", "inputs": [], - "name": "FailedDeployment", - "type": "error" + "outputs": [ + { + "name": "", + "type": "uint48", + "internalType": "uint48" + } + ], + "stateMutability": "view" }, { + "type": "function", + "name": "defaultAdminDelayIncreaseWait", "inputs": [], - "name": "ImplementationNotSet", - "type": "error" + "outputs": [ + { + "name": "", + "type": "uint48", + "internalType": "uint48" + } + ], + "stateMutability": "view" }, { + "type": "function", + "name": "deployWallet", "inputs": [ { - "internalType": "uint96", - "name": "expected", - "type": "uint96" - }, + "name": "label", + "type": "string", + "internalType": "string" + } + ], + "outputs": [ { - "internalType": "uint96", - "name": "provided", - "type": "uint96" + "name": "wallet", + "type": "address", + "internalType": "address" } ], - "name": "IndexMismatch", - "type": "error" + "stateMutability": "nonpayable" }, { + "type": "function", + "name": "deployWalletWithSig", "inputs": [ { - "internalType": "uint256", - "name": "index", - "type": "uint256" + "name": "intent", + "type": "tuple", + "internalType": "struct OwnerIntent", + "components": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "wallet", + "type": "address", + "internalType": "address" + }, + { + "name": "executor", + "type": "address", + "internalType": "address" + }, + { + "name": "index", + "type": "uint96", + "internalType": "uint96" + }, + { + "name": "sessionHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "mode", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "execCalldataHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "nonceKey", + "type": "uint192", + "internalType": "uint192" + }, + { + "name": "nonceSeq", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "grantNonce", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "deadline", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "signerChainId", + "type": "uint256", + "internalType": "uint256" + } + ] }, { - "internalType": "uint256", - "name": "next", - "type": "uint256" + "name": "sig", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "label", + "type": "string", + "internalType": "string" } ], - "name": "IndexOutOfRange", - "type": "error" + "outputs": [ + { + "name": "wallet", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "nonpayable" }, { + "type": "function", + "name": "domainSeparator", "inputs": [ { - "internalType": "uint256", - "name": "balance", - "type": "uint256" - }, + "name": "signerChainId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ { - "internalType": "uint256", - "name": "needed", - "type": "uint256" + "name": "", + "type": "bytes32", + "internalType": "bytes32" } ], - "name": "InsufficientBalance", - "type": "error" + "stateMutability": "view" }, { + "type": "function", + "name": "getRoleAdmin", "inputs": [ { - "internalType": "address", - "name": "expected", - "type": "address" - }, + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [ { - "internalType": "address", - "name": "provided", - "type": "address" + "name": "", + "type": "bytes32", + "internalType": "bytes32" } ], - "name": "IntentWalletMismatch", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidInitialization", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidOwnerSignature", - "type": "error" + "stateMutability": "view" }, { + "type": "function", + "name": "grantRole", "inputs": [ { - "internalType": "address", + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + }, + { "name": "account", - "type": "address" + "type": "address", + "internalType": "address" } ], - "name": "NotAWallet", - "type": "error" - }, - { - "inputs": [], - "name": "NotInitializing", - "type": "error" + "outputs": [], + "stateMutability": "nonpayable" }, { + "type": "function", + "name": "hasRole", "inputs": [ { - "internalType": "uint8", - "name": "bits", - "type": "uint8" + "name": "role", + "type": "bytes32", + "internalType": "bytes32" }, { - "internalType": "uint256", - "name": "value", - "type": "uint256" + "name": "account", + "type": "address", + "internalType": "address" } ], - "name": "SafeCastOverflowedUintDowncast", - "type": "error" - }, - { - "inputs": [ + "outputs": [ { - "internalType": "uint48", - "name": "deadline", - "type": "uint48" + "name": "", + "type": "bool", + "internalType": "bool" } ], - "name": "SignatureExpired", - "type": "error" - }, - { - "inputs": [], - "name": "UUPSUnauthorizedCallContext", - "type": "error" + "stateMutability": "view" }, { + "type": "function", + "name": "indexOf", "inputs": [ { - "internalType": "bytes32", - "name": "slot", - "type": "bytes32" + "name": "wallet", + "type": "address", + "internalType": "address" } ], - "name": "UUPSUnsupportedProxiableUUID", - "type": "error" - }, - { - "inputs": [], - "name": "ZeroAddress", - "type": "error" - }, - { - "anonymous": false, - "inputs": [], - "name": "DefaultAdminDelayChangeCanceled", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint48", - "name": "newDelay", - "type": "uint48" - }, + "outputs": [ { - "indexed": false, - "internalType": "uint48", - "name": "effectSchedule", - "type": "uint48" + "name": "", + "type": "uint256", + "internalType": "uint256" } ], - "name": "DefaultAdminDelayChangeScheduled", - "type": "event" - }, - { - "anonymous": false, - "inputs": [], - "name": "DefaultAdminTransferCanceled", - "type": "event" + "stateMutability": "view" }, { - "anonymous": false, + "type": "function", + "name": "initialize", "inputs": [ { - "indexed": true, - "internalType": "address", - "name": "newAdmin", - "type": "address" + "name": "admin", + "type": "address", + "internalType": "address" }, { - "indexed": false, - "internalType": "uint48", - "name": "acceptSchedule", - "type": "uint48" + "name": "walletImplementation_", + "type": "address", + "internalType": "address" } ], - "name": "DefaultAdminTransferScheduled", - "type": "event" + "outputs": [], + "stateMutability": "nonpayable" }, { - "anonymous": false, + "type": "function", + "name": "isWallet", "inputs": [ { - "indexed": false, - "internalType": "uint64", - "name": "version", - "type": "uint64" + "name": "account", + "type": "address", + "internalType": "address" } ], - "name": "Initialized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ + "outputs": [ { - "indexed": false, - "internalType": "address", - "name": "account", - "type": "address" + "name": "", + "type": "bool", + "internalType": "bool" } ], - "name": "Paused", - "type": "event" + "stateMutability": "view" }, { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "previousAdminRole", - "type": "bytes32" - }, + "type": "function", + "name": "owner", + "inputs": [], + "outputs": [ { - "indexed": true, - "internalType": "bytes32", - "name": "newAdminRole", - "type": "bytes32" + "name": "", + "type": "address", + "internalType": "address" } ], - "name": "RoleAdminChanged", - "type": "event" + "stateMutability": "view" }, { - "anonymous": false, + "type": "function", + "name": "ownerOf", "inputs": [ { - "indexed": true, - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, + "name": "wallet", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ { - "indexed": true, - "internalType": "address", - "name": "sender", - "type": "address" + "name": "", + "type": "address", + "internalType": "address" } ], - "name": "RoleGranted", - "type": "event" + "stateMutability": "view" }, { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, + "type": "function", + "name": "pause", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "paused", + "inputs": [], + "outputs": [ { - "indexed": true, - "internalType": "address", - "name": "sender", - "type": "address" + "name": "", + "type": "bool", + "internalType": "bool" } ], - "name": "RoleRevoked", - "type": "event" + "stateMutability": "view" }, { - "anonymous": false, - "inputs": [ + "type": "function", + "name": "pendingDefaultAdmin", + "inputs": [], + "outputs": [ { - "indexed": false, - "internalType": "address", - "name": "account", - "type": "address" + "name": "newAdmin", + "type": "address", + "internalType": "address" + }, + { + "name": "schedule", + "type": "uint48", + "internalType": "uint48" } ], - "name": "Unpaused", - "type": "event" + "stateMutability": "view" }, { - "anonymous": false, - "inputs": [ + "type": "function", + "name": "pendingDefaultAdminDelay", + "inputs": [], + "outputs": [ { - "indexed": true, - "internalType": "address", - "name": "implementation", - "type": "address" + "name": "newDelay", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "schedule", + "type": "uint48", + "internalType": "uint48" } ], - "name": "Upgraded", - "type": "event" + "stateMutability": "view" }, { - "anonymous": false, + "type": "function", + "name": "predictWallet", "inputs": [ { - "indexed": true, - "internalType": "address", "name": "owner", - "type": "address" + "type": "address", + "internalType": "address" }, { - "indexed": true, - "internalType": "uint256", "name": "index", - "type": "uint256" - }, + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ { - "indexed": true, - "internalType": "address", "name": "wallet", - "type": "address" + "type": "address", + "internalType": "address" }, { - "indexed": false, - "internalType": "string", - "name": "label", - "type": "string" + "name": "deployed", + "type": "bool", + "internalType": "bool" } ], - "name": "WalletDeployed", - "type": "event" + "stateMutability": "view" }, { + "type": "function", + "name": "proxiableUUID", "inputs": [], - "name": "DEFAULT_ADMIN_ROLE", "outputs": [ { - "internalType": "bytes32", "name": "", - "type": "bytes32" + "type": "bytes32", + "internalType": "bytes32" } ], - "stateMutability": "view", - "type": "function" + "stateMutability": "view" }, { - "inputs": [], - "name": "OPERATOR_ROLE", - "outputs": [ + "type": "function", + "name": "renounceRole", + "inputs": [ { - "internalType": "bytes32", - "name": "", - "type": "bytes32" + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "internalType": "address" } ], - "stateMutability": "view", - "type": "function" + "outputs": [], + "stateMutability": "nonpayable" }, { - "inputs": [], - "name": "PAUSER_ROLE", - "outputs": [ + "type": "function", + "name": "revokeRole", + "inputs": [ { - "internalType": "bytes32", - "name": "", - "type": "bytes32" + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "internalType": "address" } ], - "stateMutability": "view", - "type": "function" + "outputs": [], + "stateMutability": "nonpayable" }, { + "type": "function", + "name": "rollbackDefaultAdminDelay", "inputs": [], - "name": "UPGRADE_INTERFACE_VERSION", + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "supportsInterface", + "inputs": [ + { + "name": "interfaceId", + "type": "bytes4", + "internalType": "bytes4" + } + ], "outputs": [ { - "internalType": "string", "name": "", - "type": "string" + "type": "bool", + "internalType": "bool" } ], - "stateMutability": "view", - "type": "function" + "stateMutability": "view" }, { + "type": "function", + "name": "unpause", "inputs": [], - "name": "acceptDefaultAdminTransfer", "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "stateMutability": "nonpayable" }, { + "type": "function", + "name": "upgradeToAndCall", "inputs": [ { - "internalType": "address", - "name": "newAdmin", - "type": "address" + "name": "newImplementation", + "type": "address", + "internalType": "address" + }, + { + "name": "data", + "type": "bytes", + "internalType": "bytes" } ], - "name": "beginDefaultAdminTransfer", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "cancelDefaultAdminTransfer", "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "stateMutability": "payable" }, { + "type": "function", + "name": "walletCount", "inputs": [ { - "internalType": "uint48", - "name": "newDelay", - "type": "uint48" + "name": "owner", + "type": "address", + "internalType": "address" } ], - "name": "changeDefaultAdminDelay", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "defaultAdmin", "outputs": [ { - "internalType": "address", "name": "", - "type": "address" + "type": "uint256", + "internalType": "uint256" } ], - "stateMutability": "view", - "type": "function" + "stateMutability": "view" }, { + "type": "function", + "name": "walletImplementation", "inputs": [], - "name": "defaultAdminDelay", "outputs": [ { - "internalType": "uint48", "name": "", - "type": "uint48" + "type": "address", + "internalType": "address" } ], - "stateMutability": "view", - "type": "function" + "stateMutability": "view" }, { + "type": "event", + "name": "DefaultAdminDelayChangeCanceled", "inputs": [], - "name": "defaultAdminDelayIncreaseWait", - "outputs": [ - { - "internalType": "uint48", - "name": "", - "type": "uint48" - } - ], - "stateMutability": "view", - "type": "function" + "anonymous": false }, { + "type": "event", + "name": "DefaultAdminDelayChangeScheduled", "inputs": [ { - "internalType": "string", - "name": "label", - "type": "string" - } - ], - "name": "deployWallet", - "outputs": [ + "name": "newDelay", + "type": "uint48", + "indexed": false, + "internalType": "uint48" + }, { - "internalType": "address", - "name": "wallet", - "type": "address" + "name": "effectSchedule", + "type": "uint48", + "indexed": false, + "internalType": "uint48" } ], - "stateMutability": "nonpayable", - "type": "function" + "anonymous": false }, { + "type": "event", + "name": "DefaultAdminTransferCanceled", + "inputs": [], + "anonymous": false + }, + { + "type": "event", + "name": "DefaultAdminTransferScheduled", "inputs": [ { - "components": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "wallet", - "type": "address" - }, - { - "internalType": "address", - "name": "executor", - "type": "address" - }, - { - "internalType": "uint96", - "name": "index", - "type": "uint96" - }, - { - "internalType": "bytes32", - "name": "sessionHash", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "mode", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "execCalldataHash", - "type": "bytes32" - }, - { - "internalType": "uint192", - "name": "nonceKey", - "type": "uint192" - }, - { - "internalType": "uint64", - "name": "nonceSeq", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "grantNonce", - "type": "uint64" - }, - { - "internalType": "uint48", - "name": "deadline", - "type": "uint48" - }, - { - "internalType": "uint256", - "name": "signerChainId", - "type": "uint256" - } - ], - "internalType": "struct OwnerIntent", - "name": "intent", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "sig", - "type": "bytes" + "name": "newAdmin", + "type": "address", + "indexed": true, + "internalType": "address" }, { - "internalType": "string", - "name": "label", - "type": "string" - } - ], - "name": "deployWalletWithSig", - "outputs": [ - { - "internalType": "address", - "name": "wallet", - "type": "address" + "name": "acceptSchedule", + "type": "uint48", + "indexed": false, + "internalType": "uint48" } ], - "stateMutability": "nonpayable", - "type": "function" + "anonymous": false }, { + "type": "event", + "name": "Initialized", "inputs": [ { - "internalType": "uint256", - "name": "signerChainId", - "type": "uint256" - } - ], - "name": "domainSeparator", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" + "name": "version", + "type": "uint64", + "indexed": false, + "internalType": "uint64" } ], - "stateMutability": "view", - "type": "function" + "anonymous": false }, { + "type": "event", + "name": "Paused", "inputs": [ { - "internalType": "bytes32", - "name": "role", - "type": "bytes32" + "name": "account", + "type": "address", + "indexed": false, + "internalType": "address" } ], - "name": "getRoleAdmin", - "outputs": [ + "anonymous": false + }, + { + "type": "event", + "name": "RoleAdminChanged", + "inputs": [ { - "internalType": "bytes32", - "name": "", - "type": "bytes32" + "name": "role", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "previousAdminRole", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "newAdminRole", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" } ], - "stateMutability": "view", - "type": "function" + "anonymous": false }, { + "type": "event", + "name": "RoleGranted", "inputs": [ { - "internalType": "bytes32", "name": "role", - "type": "bytes32" + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" }, { - "internalType": "address", "name": "account", - "type": "address" + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" } ], - "name": "grantRole", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "anonymous": false }, { + "type": "event", + "name": "RoleRevoked", "inputs": [ { - "internalType": "bytes32", "name": "role", - "type": "bytes32" + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" }, { - "internalType": "address", "name": "account", - "type": "address" - } - ], - "name": "hasRole", - "outputs": [ + "type": "address", + "indexed": true, + "internalType": "address" + }, { - "internalType": "bool", - "name": "", - "type": "bool" + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" } ], - "stateMutability": "view", - "type": "function" + "anonymous": false }, { + "type": "event", + "name": "Unpaused", "inputs": [ { - "internalType": "address", - "name": "wallet", - "type": "address" + "name": "account", + "type": "address", + "indexed": false, + "internalType": "address" } ], - "name": "indexOf", - "outputs": [ + "anonymous": false + }, + { + "type": "event", + "name": "Upgraded", + "inputs": [ { - "internalType": "uint256", - "name": "", - "type": "uint256" + "name": "implementation", + "type": "address", + "indexed": true, + "internalType": "address" } ], - "stateMutability": "view", - "type": "function" + "anonymous": false }, { + "type": "event", + "name": "WalletDeployed", "inputs": [ { - "internalType": "address", - "name": "admin", - "type": "address" + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" }, { - "internalType": "address", - "name": "walletImplementation_", - "type": "address" + "name": "index", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "wallet", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "label", + "type": "string", + "indexed": false, + "internalType": "string" } ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "anonymous": false }, { + "type": "error", + "name": "AccessControlBadConfirmation", + "inputs": [] + }, + { + "type": "error", + "name": "AccessControlEnforcedDefaultAdminDelay", "inputs": [ { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "isWallet", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" + "name": "schedule", + "type": "uint48", + "internalType": "uint48" } - ], - "stateMutability": "view", - "type": "function" + ] }, { - "inputs": [], - "name": "owner", - "outputs": [ + "type": "error", + "name": "AccessControlEnforcedDefaultAdminRules", + "inputs": [] + }, + { + "type": "error", + "name": "AccessControlInvalidDefaultAdmin", + "inputs": [ { - "internalType": "address", - "name": "", - "type": "address" + "name": "defaultAdmin", + "type": "address", + "internalType": "address" } - ], - "stateMutability": "view", - "type": "function" + ] }, { + "type": "error", + "name": "AccessControlUnauthorizedAccount", "inputs": [ { - "internalType": "address", - "name": "wallet", - "type": "address" + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "neededRole", + "type": "bytes32", + "internalType": "bytes32" } - ], - "name": "ownerOf", - "outputs": [ + ] + }, + { + "type": "error", + "name": "AddressEmptyCode", + "inputs": [ { - "internalType": "address", - "name": "", - "type": "address" + "name": "target", + "type": "address", + "internalType": "address" } - ], - "stateMutability": "view", - "type": "function" + ] }, { - "inputs": [], - "name": "pause", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "type": "error", + "name": "CloneArgumentsTooLong", + "inputs": [] }, { - "inputs": [], - "name": "paused", - "outputs": [ + "type": "error", + "name": "Create2EmptyBytecode", + "inputs": [] + }, + { + "type": "error", + "name": "ERC1967InvalidImplementation", + "inputs": [ { - "internalType": "bool", - "name": "", - "type": "bool" + "name": "implementation", + "type": "address", + "internalType": "address" } - ], - "stateMutability": "view", - "type": "function" + ] }, { - "inputs": [], - "name": "pendingDefaultAdmin", - "outputs": [ + "type": "error", + "name": "ERC1967NonPayable", + "inputs": [] + }, + { + "type": "error", + "name": "EnforcedPause", + "inputs": [] + }, + { + "type": "error", + "name": "ExecutorMismatch", + "inputs": [ { - "internalType": "address", - "name": "newAdmin", - "type": "address" + "name": "expected", + "type": "address", + "internalType": "address" }, { - "internalType": "uint48", - "name": "schedule", - "type": "uint48" + "name": "actual", + "type": "address", + "internalType": "address" } - ], - "stateMutability": "view", - "type": "function" + ] }, { - "inputs": [], - "name": "pendingDefaultAdminDelay", - "outputs": [ + "type": "error", + "name": "ExpectedPause", + "inputs": [] + }, + { + "type": "error", + "name": "FailedCall", + "inputs": [] + }, + { + "type": "error", + "name": "FailedDeployment", + "inputs": [] + }, + { + "type": "error", + "name": "ImplementationNotSet", + "inputs": [] + }, + { + "type": "error", + "name": "IndexMismatch", + "inputs": [ { - "internalType": "uint48", - "name": "newDelay", - "type": "uint48" + "name": "expected", + "type": "uint96", + "internalType": "uint96" }, { - "internalType": "uint48", - "name": "schedule", - "type": "uint48" + "name": "provided", + "type": "uint96", + "internalType": "uint96" } - ], - "stateMutability": "view", - "type": "function" + ] }, { + "type": "error", + "name": "IndexOutOfRange", "inputs": [ { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "uint256", "name": "index", - "type": "uint256" - } - ], - "name": "predictWallet", - "outputs": [ - { - "internalType": "address", - "name": "wallet", - "type": "address" + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "bool", - "name": "deployed", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" + "name": "next", + "type": "uint256", + "internalType": "uint256" } - ], - "stateMutability": "view", - "type": "function" + ] }, { + "type": "error", + "name": "InsufficientBalance", "inputs": [ { - "internalType": "bytes32", - "name": "role", - "type": "bytes32" + "name": "balance", + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "address", - "name": "account", - "type": "address" + "name": "needed", + "type": "uint256", + "internalType": "uint256" } - ], - "name": "renounceRole", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + ] }, { + "type": "error", + "name": "IntentWalletMismatch", "inputs": [ { - "internalType": "bytes32", - "name": "role", - "type": "bytes32" + "name": "expected", + "type": "address", + "internalType": "address" }, { - "internalType": "address", - "name": "account", - "type": "address" + "name": "provided", + "type": "address", + "internalType": "address" } - ], - "name": "revokeRole", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + ] }, { - "inputs": [], - "name": "rollbackDefaultAdminDelay", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "type": "error", + "name": "InvalidInitialization", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidOwnerSignature", + "inputs": [] }, { + "type": "error", + "name": "NotAWallet", "inputs": [ { - "internalType": "bytes4", - "name": "interfaceId", - "type": "bytes4" - } - ], - "name": "supportsInterface", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" + "name": "account", + "type": "address", + "internalType": "address" } - ], - "stateMutability": "view", - "type": "function" + ] }, { - "inputs": [], - "name": "unpause", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "type": "error", + "name": "NotInitializing", + "inputs": [] }, { + "type": "error", + "name": "SafeCastOverflowedUintDowncast", "inputs": [ { - "internalType": "address", - "name": "newImplementation", - "type": "address" + "name": "bits", + "type": "uint8", + "internalType": "uint8" }, { - "internalType": "bytes", - "name": "data", - "type": "bytes" + "name": "value", + "type": "uint256", + "internalType": "uint256" } - ], - "name": "upgradeToAndCall", - "outputs": [], - "stateMutability": "payable", - "type": "function" + ] }, { + "type": "error", + "name": "SignatureExpired", "inputs": [ { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "walletCount", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" + "name": "deadline", + "type": "uint48", + "internalType": "uint48" } - ], - "stateMutability": "view", - "type": "function" + ] }, { - "inputs": [], - "name": "walletImplementation", - "outputs": [ + "type": "error", + "name": "UUPSUnauthorizedCallContext", + "inputs": [] + }, + { + "type": "error", + "name": "UUPSUnsupportedProxiableUUID", + "inputs": [ { - "internalType": "address", - "name": "", - "type": "address" + "name": "slot", + "type": "bytes32", + "internalType": "bytes32" } - ], - "stateMutability": "view", - "type": "function" + ] + }, + { + "type": "error", + "name": "ZeroAddress", + "inputs": [] } ] as const; diff --git a/packages/core/src/lib/agentic/contracts/abi/v4/agw.ts b/packages/core/src/lib/agentic/contracts/abi/v5/agw.ts similarity index 50% rename from packages/core/src/lib/agentic/contracts/abi/v4/agw.ts rename to packages/core/src/lib/agentic/contracts/abi/v5/agw.ts index 37c654c3..d3bed329 100644 --- a/packages/core/src/lib/agentic/contracts/abi/v4/agw.ts +++ b/packages/core/src/lib/agentic/contracts/abi/v5/agw.ts @@ -1,1528 +1,1584 @@ // GENERATED by packages/core/scripts/agw-local/gen-abi.mjs — do not edit. // Source: packages/core/scripts/agw-local/abis/wallet.json -// push-agentic-wallets@e8db74815cfbbf5389593805e464fe8d85f7f735 -// sha256(AGW.json) = ba68ef8f86e7154df29c4bb3ec9b90ae0d8a5193cad6e34772276475a2846ebe +// push-agentic-wallets@2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb +// sha256(AGW.json) = 6a145964d6c43eaa6223dc8f3d59a540ac0c2f447f25c3a99007eea25de9c695 export const AGW_ABI = [ { - "inputs": [], - "name": "AlreadyInitialized", - "type": "error" + "type": "receive", + "stateMutability": "payable" }, { - "inputs": [ - { - "internalType": "bytes32", - "name": "rulesId", - "type": "bytes32" - }, + "type": "function", + "name": "RULES_POLICY", + "inputs": [], + "outputs": [ { - "internalType": "address", - "name": "caller", - "type": "address" + "name": "", + "type": "address", + "internalType": "address" } ], - "name": "CallerIsNotAgent", - "type": "error" - }, - { - "inputs": [], - "name": "CallerIsNotFactory", - "type": "error" + "stateMutability": "view" }, { + "type": "function", + "name": "SESSION_ENGINE", "inputs": [], - "name": "CallerIsNotOwner", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "target", - "type": "address" - }, + "outputs": [ { - "internalType": "bytes4", - "name": "selector", - "type": "bytes4" + "name": "", + "type": "address", + "internalType": "address" } ], - "name": "DuplicateAction", - "type": "error" - }, - { - "inputs": [], - "name": "EmptyChain", - "type": "error" + "stateMutability": "view" }, { + "type": "function", + "name": "SESSION_VALIDATOR", "inputs": [], - "name": "EngineStillHoldsPermissions", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "expected", - "type": "address" - }, + "outputs": [ { - "internalType": "address", - "name": "actual", - "type": "address" + "name": "", + "type": "address", + "internalType": "address" } ], - "name": "ExecutorMismatch", - "type": "error" + "stateMutability": "view" }, { - "inputs": [ + "type": "function", + "name": "UNIVERSAL_GATEWAY_PC", + "inputs": [], + "outputs": [ { - "internalType": "bytes4", - "name": "selector", - "type": "bytes4" + "name": "", + "type": "address", + "internalType": "address" } ], - "name": "ForbiddenActionSelector", - "type": "error" + "stateMutability": "view" }, { - "inputs": [ + "type": "function", + "name": "accountId", + "inputs": [], + "outputs": [ { - "internalType": "address", - "name": "target", - "type": "address" + "name": "", + "type": "string", + "internalType": "string" } ], - "name": "ForbiddenActionTarget", - "type": "error" + "stateMutability": "pure" }, { + "type": "function", + "name": "agentOf", "inputs": [ { - "internalType": "address", - "name": "target", - "type": "address" + "name": "rulesId", + "type": "bytes32", + "internalType": "bytes32" } ], - "name": "ForbiddenDispatchTarget", - "type": "error" - }, - { - "inputs": [ + "outputs": [ { - "internalType": "uint256", - "name": "actionIndex", - "type": "uint256" + "name": "", + "type": "address", + "internalType": "address" } ], - "name": "InconsistentChain", - "type": "error" + "stateMutability": "view" }, { - "inputs": [ + "type": "function", + "name": "checkpointCount", + "inputs": [], + "outputs": [ { - "internalType": "bytes32", - "name": "actualCalldataHash", - "type": "bytes32" + "name": "", + "type": "uint64", + "internalType": "uint64" } ], - "name": "IntentExecMismatch", - "type": "error" + "stateMutability": "view" }, { + "type": "function", + "name": "domainSeparator", "inputs": [ { - "internalType": "uint64", - "name": "expected", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "provided", - "type": "uint64" + "name": "signerChainId", + "type": "uint256", + "internalType": "uint256" } ], - "name": "IntentGrantNonceMismatch", - "type": "error" - }, - { - "inputs": [ + "outputs": [ { - "internalType": "bytes32", - "name": "actual", - "type": "bytes32" + "name": "", + "type": "bytes32", + "internalType": "bytes32" } ], - "name": "IntentSessionMismatch", - "type": "error" + "stateMutability": "view" }, { + "type": "function", + "name": "execute", "inputs": [ { - "internalType": "address", - "name": "expected", - "type": "address" + "name": "mode", + "type": "bytes32", + "internalType": "bytes32" }, { - "internalType": "address", - "name": "provided", - "type": "address" + "name": "executionCalldata", + "type": "bytes", + "internalType": "bytes" } ], - "name": "IntentWalletMismatch", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidModuleAddress", - "type": "error" + "outputs": [], + "stateMutability": "payable" }, { + "type": "function", + "name": "executeAsAgent", "inputs": [ { - "internalType": "uint192", - "name": "nonceKey", - "type": "uint192" + "name": "rulesId", + "type": "bytes32", + "internalType": "bytes32" }, { - "internalType": "uint64", - "name": "expected", - "type": "uint64" + "name": "mode", + "type": "bytes32", + "internalType": "bytes32" }, { - "internalType": "uint64", - "name": "provided", - "type": "uint64" - } - ], - "name": "InvalidNonce", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidOwnerSignature", - "type": "error" - }, - { - "inputs": [], - "name": "MalformedBatchCalldata", - "type": "error" - }, - { - "inputs": [], - "name": "MalformedSessionShape", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "module", - "type": "address" + "name": "executionCalldata", + "type": "bytes", + "internalType": "bytes" } ], - "name": "ModuleAlreadyInstalled", - "type": "error" + "outputs": [], + "stateMutability": "nonpayable" }, { + "type": "function", + "name": "executeWithSig", "inputs": [ { - "internalType": "uint48", - "name": "validAfter", - "type": "uint48" + "name": "mode", + "type": "bytes32", + "internalType": "bytes32" }, { - "internalType": "uint48", - "name": "validUntil", - "type": "uint48" - } - ], - "name": "OutsideTimeWindow", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint192", - "name": "nonceKey", - "type": "uint192" - } - ], - "name": "OwnerLaneRequired", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint48", - "name": "deadline", - "type": "uint48" - } - ], - "name": "OwnerSigExpired", - "type": "error" - }, - { - "inputs": [], - "name": "ReentrancyGuardReentrantCall", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "enum RulesType", - "name": "derived", - "type": "uint8" + "name": "executionCalldata", + "type": "bytes", + "internalType": "bytes" }, { - "internalType": "uint256", - "name": "actionIndex", - "type": "uint256" + "name": "intent", + "type": "tuple", + "internalType": "struct OwnerIntent", + "components": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "wallet", + "type": "address", + "internalType": "address" + }, + { + "name": "executor", + "type": "address", + "internalType": "address" + }, + { + "name": "index", + "type": "uint96", + "internalType": "uint96" + }, + { + "name": "sessionHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "mode", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "execCalldataHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "nonceKey", + "type": "uint192", + "internalType": "uint192" + }, + { + "name": "nonceSeq", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "grantNonce", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "deadline", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "signerChainId", + "type": "uint256", + "internalType": "uint256" + } + ] }, { - "internalType": "address", - "name": "target", - "type": "address" - } - ], - "name": "RulesTypeMismatch", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "count", - "type": "uint256" - } - ], - "name": "TooManyActions", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "rulesId", - "type": "bytes32" + "name": "sig", + "type": "bytes", + "internalType": "bytes" } ], - "name": "UnknownPermission", - "type": "error" + "outputs": [], + "stateMutability": "nonpayable" }, { + "type": "function", + "name": "factory", "inputs": [], - "name": "UnsupportedExecutionMode", - "type": "error" - }, - { - "inputs": [ + "outputs": [ { - "internalType": "uint256", - "name": "moduleTypeId", - "type": "uint256" + "name": "", + "type": "address", + "internalType": "address" } ], - "name": "UnsupportedModuleType", - "type": "error" + "stateMutability": "view" }, { + "type": "function", + "name": "getNonce", "inputs": [ { - "internalType": "address", - "name": "authorizer", - "type": "address" + "name": "nonceKey", + "type": "uint192", + "internalType": "uint192" } ], - "name": "ValidationFailed", - "type": "error" - }, - { - "inputs": [ + "outputs": [ { - "internalType": "address", - "name": "validator", - "type": "address" + "name": "", + "type": "uint64", + "internalType": "uint64" } ], - "name": "ValidatorNotInstalled", - "type": "error" + "stateMutability": "view" }, { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, + "type": "function", + "name": "grantNonce", + "inputs": [], + "outputs": [ { - "indexed": true, - "internalType": "address", - "name": "engine", - "type": "address" + "name": "", + "type": "uint64", + "internalType": "uint64" } ], - "name": "AccountInitialized", - "type": "event" + "stateMutability": "view" }, { - "anonymous": false, + "type": "function", + "name": "grantRules", "inputs": [ { - "indexed": true, - "internalType": "uint64", - "name": "seq", - "type": "uint64" - }, + "name": "session", + "type": "tuple", + "internalType": "struct Session", + "components": [ + { + "name": "sessionValidator", + "type": "address", + "internalType": "contract ISessionValidator" + }, + { + "name": "sessionValidatorInitData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "erc7739Policies", + "type": "tuple", + "internalType": "struct ERC7739Data", + "components": [ + { + "name": "allowedERC7739Content", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNames", + "type": "string[]", + "internalType": "string[]" + } + ] + }, + { + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "actions", + "type": "tuple[]", + "internalType": "struct ActionData[]", + "components": [ + { + "name": "actionTargetSelector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "actionTarget", + "type": "address", + "internalType": "address" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "permitERC4337Paymaster", + "type": "bool", + "internalType": "bool" + } + ] + } + ], + "outputs": [ { - "indexed": false, - "internalType": "enum CheckpointKind", - "name": "kind", - "type": "uint8" + "name": "rulesId", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "grantRulesWithSig", + "inputs": [ + { + "name": "session", + "type": "tuple", + "internalType": "struct Session", + "components": [ + { + "name": "sessionValidator", + "type": "address", + "internalType": "contract ISessionValidator" + }, + { + "name": "sessionValidatorInitData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "erc7739Policies", + "type": "tuple", + "internalType": "struct ERC7739Data", + "components": [ + { + "name": "allowedERC7739Content", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNames", + "type": "string[]", + "internalType": "string[]" + } + ] + }, + { + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "actions", + "type": "tuple[]", + "internalType": "struct ActionData[]", + "components": [ + { + "name": "actionTargetSelector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "actionTarget", + "type": "address", + "internalType": "address" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "permitERC4337Paymaster", + "type": "bool", + "internalType": "bool" + } + ] }, { - "indexed": false, - "internalType": "bytes32", - "name": "ref", - "type": "bytes32" + "name": "intent", + "type": "tuple", + "internalType": "struct OwnerIntent", + "components": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "wallet", + "type": "address", + "internalType": "address" + }, + { + "name": "executor", + "type": "address", + "internalType": "address" + }, + { + "name": "index", + "type": "uint96", + "internalType": "uint96" + }, + { + "name": "sessionHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "mode", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "execCalldataHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "nonceKey", + "type": "uint192", + "internalType": "uint192" + }, + { + "name": "nonceSeq", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "grantNonce", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "deadline", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "signerChainId", + "type": "uint256", + "internalType": "uint256" + } + ] }, { - "indexed": false, - "internalType": "uint64", - "name": "blockNumber", - "type": "uint64" + "name": "sig", + "type": "bytes", + "internalType": "bytes" } ], - "name": "Checkpointed", - "type": "event" + "outputs": [ + { + "name": "rulesId", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "nonpayable" }, { - "anonymous": false, + "type": "function", + "name": "initializeAccount", "inputs": [ { - "indexed": false, - "internalType": "uint256", - "name": "moduleTypeId", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "module", - "type": "address" + "name": "label_", + "type": "string", + "internalType": "string" } ], - "name": "ModuleInstalled", - "type": "event" + "outputs": [], + "stateMutability": "nonpayable" }, { - "anonymous": false, + "type": "function", + "name": "installModule", "inputs": [ { - "indexed": false, - "internalType": "uint256", "name": "moduleTypeId", - "type": "uint256" + "type": "uint256", + "internalType": "uint256" }, { - "indexed": false, - "internalType": "address", "name": "module", - "type": "address" + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" } ], - "name": "ModuleUninstalled", - "type": "event" + "outputs": [], + "stateMutability": "nonpayable" }, { - "anonymous": false, + "type": "function", + "name": "isModuleInstalled", "inputs": [ { - "indexed": true, - "internalType": "bytes32", - "name": "mode", - "type": "bytes32" + "name": "moduleTypeId", + "type": "uint256", + "internalType": "uint256" }, { - "indexed": false, - "internalType": "bytes32", - "name": "executionCalldataHash", - "type": "bytes32" + "name": "module", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "bytes", + "internalType": "bytes" } ], - "name": "OwnerExecuted", - "type": "event" + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" }, { - "anonymous": false, + "type": "function", + "name": "isValidSignature", "inputs": [ { - "indexed": true, - "internalType": "bytes32", - "name": "mode", - "type": "bytes32" + "name": "", + "type": "bytes32", + "internalType": "bytes32" }, { - "indexed": false, - "internalType": "bytes32", - "name": "executionCalldataHash", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "uint192", - "name": "nonceKey", - "type": "uint192" - }, + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ { - "indexed": false, - "internalType": "uint64", - "name": "nonceSeq", - "type": "uint64" + "name": "", + "type": "bytes4", + "internalType": "bytes4" } ], - "name": "OwnerExecutedWithSig", - "type": "event" + "stateMutability": "pure" }, { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "bytes32", - "name": "rulesId", - "type": "bytes32" - }, + "type": "function", + "name": "label", + "inputs": [], + "outputs": [ { - "indexed": true, - "internalType": "address", - "name": "agent", - "type": "address" - }, + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "lastCheckpointBlock", + "inputs": [], + "outputs": [ { - "indexed": false, - "internalType": "bytes32", - "name": "callsHash", - "type": "bytes32" + "name": "", + "type": "uint64", + "internalType": "uint64" } ], - "name": "RulesActionAuthorized", - "type": "event" + "stateMutability": "view" }, { - "anonymous": false, + "type": "function", + "name": "onERC1155BatchReceived", "inputs": [ { - "indexed": true, - "internalType": "bytes32", - "name": "rulesId", - "type": "bytes32" + "name": "", + "type": "address", + "internalType": "address" }, { - "indexed": false, - "internalType": "enum RulesType", - "name": "mode", - "type": "uint8" + "name": "", + "type": "address", + "internalType": "address" }, { - "indexed": true, - "internalType": "bytes32", - "name": "chainHash", - "type": "bytes32" + "name": "", + "type": "uint256[]", + "internalType": "uint256[]" }, { - "indexed": false, - "internalType": "string", - "name": "chainNamespace", - "type": "string" + "name": "", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "", + "type": "bytes", + "internalType": "bytes" } ], - "name": "RulesGranted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ + "outputs": [ { - "indexed": true, - "internalType": "bytes32", - "name": "rulesId", - "type": "bytes32" + "name": "", + "type": "bytes4", + "internalType": "bytes4" } ], - "name": "RulesRevoked", - "type": "event" + "stateMutability": "pure" }, { - "anonymous": false, + "type": "function", + "name": "onERC1155Received", "inputs": [ { - "indexed": false, - "internalType": "address", - "name": "module", - "type": "address" + "name": "", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "", + "type": "bytes", + "internalType": "bytes" } ], - "name": "UninstallCallbackFailed", - "type": "event" - }, - { - "inputs": [], - "name": "RULES_POLICY", "outputs": [ { - "internalType": "address", "name": "", - "type": "address" + "type": "bytes4", + "internalType": "bytes4" } ], - "stateMutability": "view", - "type": "function" + "stateMutability": "pure" }, { - "inputs": [], - "name": "SESSION_ENGINE", + "type": "function", + "name": "onERC721Received", + "inputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], "outputs": [ { - "internalType": "address", "name": "", - "type": "address" + "type": "bytes4", + "internalType": "bytes4" } ], - "stateMutability": "view", - "type": "function" + "stateMutability": "pure" }, { + "type": "function", + "name": "owner", "inputs": [], - "name": "SESSION_VALIDATOR", "outputs": [ { - "internalType": "address", "name": "", - "type": "address" + "type": "address", + "internalType": "address" } ], - "stateMutability": "view", - "type": "function" + "stateMutability": "view" }, { + "type": "function", + "name": "revokeAllRules", "inputs": [], - "name": "UNIVERSAL_GATEWAY_PC", - "outputs": [ + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "revokeRules", + "inputs": [ { - "internalType": "address", - "name": "", - "type": "address" + "name": "rulesId", + "type": "bytes32", + "internalType": "bytes32" } ], - "stateMutability": "view", - "type": "function" + "outputs": [], + "stateMutability": "nonpayable" }, { - "inputs": [], - "name": "accountId", - "outputs": [ + "type": "function", + "name": "setLabel", + "inputs": [ { - "internalType": "string", - "name": "", - "type": "string" + "name": "label_", + "type": "string", + "internalType": "string" } ], - "stateMutability": "pure", - "type": "function" + "outputs": [], + "stateMutability": "nonpayable" }, { + "type": "function", + "name": "supportsExecutionMode", "inputs": [ { - "internalType": "bytes32", - "name": "rulesId", - "type": "bytes32" + "name": "mode", + "type": "bytes32", + "internalType": "bytes32" } ], - "name": "agentOf", "outputs": [ { - "internalType": "address", "name": "", - "type": "address" + "type": "bool", + "internalType": "bool" } ], - "stateMutability": "view", - "type": "function" + "stateMutability": "pure" }, { - "inputs": [], - "name": "checkpointCount", + "type": "function", + "name": "supportsInterface", + "inputs": [ + { + "name": "interfaceId", + "type": "bytes4", + "internalType": "bytes4" + } + ], "outputs": [ { - "internalType": "uint64", "name": "", - "type": "uint64" + "type": "bool", + "internalType": "bool" } ], - "stateMutability": "view", - "type": "function" + "stateMutability": "pure" }, { + "type": "function", + "name": "supportsModule", "inputs": [ { - "internalType": "uint256", - "name": "signerChainId", - "type": "uint256" + "name": "moduleTypeId", + "type": "uint256", + "internalType": "uint256" } ], - "name": "domainSeparator", "outputs": [ { - "internalType": "bytes32", "name": "", - "type": "bytes32" + "type": "bool", + "internalType": "bool" } ], - "stateMutability": "view", - "type": "function" + "stateMutability": "pure" }, { + "type": "function", + "name": "uninstallModule", "inputs": [ { - "internalType": "bytes32", - "name": "mode", - "type": "bytes32" + "name": "moduleTypeId", + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "bytes", - "name": "executionCalldata", - "type": "bytes" + "name": "module", + "type": "address", + "internalType": "address" + }, + { + "name": "deInitData", + "type": "bytes", + "internalType": "bytes" } ], - "name": "execute", "outputs": [], - "stateMutability": "payable", - "type": "function" + "stateMutability": "nonpayable" }, { + "type": "event", + "name": "AccountInitialized", "inputs": [ { - "internalType": "bytes32", - "name": "rulesId", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "mode", - "type": "bytes32" + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" }, { - "internalType": "bytes", - "name": "executionCalldata", - "type": "bytes" + "name": "engine", + "type": "address", + "indexed": true, + "internalType": "address" } ], - "name": "executeAsAgent", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "anonymous": false }, { + "type": "event", + "name": "Checkpointed", "inputs": [ { - "internalType": "bytes32", - "name": "mode", - "type": "bytes32" + "name": "seq", + "type": "uint64", + "indexed": true, + "internalType": "uint64" }, { - "internalType": "bytes", - "name": "executionCalldata", - "type": "bytes" + "name": "kind", + "type": "uint8", + "indexed": false, + "internalType": "enum CheckpointKind" }, { - "components": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "wallet", - "type": "address" - }, - { - "internalType": "address", - "name": "executor", - "type": "address" - }, - { - "internalType": "uint96", - "name": "index", - "type": "uint96" - }, - { - "internalType": "bytes32", - "name": "sessionHash", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "mode", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "execCalldataHash", - "type": "bytes32" - }, - { - "internalType": "uint192", - "name": "nonceKey", - "type": "uint192" - }, - { - "internalType": "uint64", - "name": "nonceSeq", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "grantNonce", - "type": "uint64" - }, - { - "internalType": "uint48", - "name": "deadline", - "type": "uint48" - }, - { - "internalType": "uint256", - "name": "signerChainId", - "type": "uint256" - } - ], - "internalType": "struct OwnerIntent", - "name": "intent", - "type": "tuple" + "name": "ref", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" }, { - "internalType": "bytes", - "name": "sig", - "type": "bytes" + "name": "blockNumber", + "type": "uint64", + "indexed": false, + "internalType": "uint64" } ], - "name": "executeWithSig", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "anonymous": false }, { - "inputs": [], - "name": "factory", - "outputs": [ + "type": "event", + "name": "LabelSet", + "inputs": [ { - "internalType": "address", - "name": "", - "type": "address" + "name": "label", + "type": "string", + "indexed": false, + "internalType": "string" } ], - "stateMutability": "view", - "type": "function" + "anonymous": false }, { + "type": "event", + "name": "ModuleInstalled", "inputs": [ { - "internalType": "uint192", - "name": "nonceKey", - "type": "uint192" + "name": "moduleTypeId", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "module", + "type": "address", + "indexed": false, + "internalType": "address" } ], - "name": "getNonce", - "outputs": [ + "anonymous": false + }, + { + "type": "event", + "name": "ModuleUninstalled", + "inputs": [ { - "internalType": "uint64", - "name": "", - "type": "uint64" + "name": "moduleTypeId", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "module", + "type": "address", + "indexed": false, + "internalType": "address" } ], - "stateMutability": "view", - "type": "function" + "anonymous": false }, { - "inputs": [], - "name": "grantNonce", - "outputs": [ + "type": "event", + "name": "OwnerExecuted", + "inputs": [ { - "internalType": "uint64", - "name": "", - "type": "uint64" + "name": "mode", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "executionCalldataHash", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" } ], - "stateMutability": "view", - "type": "function" + "anonymous": false }, { + "type": "event", + "name": "OwnerExecutedWithSig", "inputs": [ { - "components": [ - { - "internalType": "contract ISessionValidator", - "name": "sessionValidator", - "type": "address" - }, - { - "internalType": "bytes", - "name": "sessionValidatorInitData", - "type": "bytes" - }, - { - "internalType": "bytes32", - "name": "salt", - "type": "bytes32" - }, - { - "components": [ - { - "internalType": "address", - "name": "policy", - "type": "address" - }, - { - "internalType": "bytes", - "name": "initData", - "type": "bytes" - } - ], - "internalType": "struct PolicyData[]", - "name": "userOpPolicies", - "type": "tuple[]" - }, - { - "components": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "appDomainSeparator", - "type": "bytes32" - }, - { - "internalType": "string[]", - "name": "contentNames", - "type": "string[]" - } - ], - "internalType": "struct ERC7739Context[]", - "name": "allowedERC7739Content", - "type": "tuple[]" - }, - { - "components": [ - { - "internalType": "address", - "name": "policy", - "type": "address" - }, - { - "internalType": "bytes", - "name": "initData", - "type": "bytes" - } - ], - "internalType": "struct PolicyData[]", - "name": "erc1271Policies", - "type": "tuple[]" - } - ], - "internalType": "struct ERC7739Data", - "name": "erc7739Policies", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "bytes4", - "name": "actionTargetSelector", - "type": "bytes4" - }, - { - "internalType": "address", - "name": "actionTarget", - "type": "address" - }, - { - "components": [ - { - "internalType": "address", - "name": "policy", - "type": "address" - }, - { - "internalType": "bytes", - "name": "initData", - "type": "bytes" - } - ], - "internalType": "struct PolicyData[]", - "name": "actionPolicies", - "type": "tuple[]" - } - ], - "internalType": "struct ActionData[]", - "name": "actions", - "type": "tuple[]" - }, - { - "internalType": "bool", - "name": "permitERC4337Paymaster", - "type": "bool" - } - ], - "internalType": "struct Session", - "name": "session", - "type": "tuple" + "name": "mode", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "executionCalldataHash", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + }, + { + "name": "nonceKey", + "type": "uint192", + "indexed": false, + "internalType": "uint192" + }, + { + "name": "nonceSeq", + "type": "uint64", + "indexed": false, + "internalType": "uint64" } ], - "name": "grantRules", - "outputs": [ + "anonymous": false + }, + { + "type": "event", + "name": "RulesActionAuthorized", + "inputs": [ { - "internalType": "bytes32", "name": "rulesId", - "type": "bytes32" + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "agent", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "callsHash", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" } ], - "stateMutability": "nonpayable", - "type": "function" + "anonymous": false }, { + "type": "event", + "name": "RulesGranted", "inputs": [ { - "components": [ - { - "internalType": "contract ISessionValidator", - "name": "sessionValidator", - "type": "address" - }, - { - "internalType": "bytes", - "name": "sessionValidatorInitData", - "type": "bytes" - }, - { - "internalType": "bytes32", - "name": "salt", - "type": "bytes32" - }, - { - "components": [ - { - "internalType": "address", - "name": "policy", - "type": "address" - }, - { - "internalType": "bytes", - "name": "initData", - "type": "bytes" - } - ], - "internalType": "struct PolicyData[]", - "name": "userOpPolicies", - "type": "tuple[]" - }, - { - "components": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "appDomainSeparator", - "type": "bytes32" - }, - { - "internalType": "string[]", - "name": "contentNames", - "type": "string[]" - } - ], - "internalType": "struct ERC7739Context[]", - "name": "allowedERC7739Content", - "type": "tuple[]" - }, - { - "components": [ - { - "internalType": "address", - "name": "policy", - "type": "address" - }, - { - "internalType": "bytes", - "name": "initData", - "type": "bytes" - } - ], - "internalType": "struct PolicyData[]", - "name": "erc1271Policies", - "type": "tuple[]" - } - ], - "internalType": "struct ERC7739Data", - "name": "erc7739Policies", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "bytes4", - "name": "actionTargetSelector", - "type": "bytes4" - }, - { - "internalType": "address", - "name": "actionTarget", - "type": "address" - }, - { - "components": [ - { - "internalType": "address", - "name": "policy", - "type": "address" - }, - { - "internalType": "bytes", - "name": "initData", - "type": "bytes" - } - ], - "internalType": "struct PolicyData[]", - "name": "actionPolicies", - "type": "tuple[]" - } - ], - "internalType": "struct ActionData[]", - "name": "actions", - "type": "tuple[]" - }, - { - "internalType": "bool", - "name": "permitERC4337Paymaster", - "type": "bool" - } - ], - "internalType": "struct Session", - "name": "session", - "type": "tuple" + "name": "rulesId", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" }, { - "components": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "wallet", - "type": "address" - }, - { - "internalType": "address", - "name": "executor", - "type": "address" - }, - { - "internalType": "uint96", - "name": "index", - "type": "uint96" - }, - { - "internalType": "bytes32", - "name": "sessionHash", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "mode", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "execCalldataHash", - "type": "bytes32" - }, - { - "internalType": "uint192", - "name": "nonceKey", - "type": "uint192" - }, - { - "internalType": "uint64", - "name": "nonceSeq", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "grantNonce", - "type": "uint64" - }, - { - "internalType": "uint48", - "name": "deadline", - "type": "uint48" - }, - { - "internalType": "uint256", - "name": "signerChainId", - "type": "uint256" - } - ], - "internalType": "struct OwnerIntent", - "name": "intent", - "type": "tuple" + "name": "mode", + "type": "uint8", + "indexed": false, + "internalType": "enum RulesType" }, { - "internalType": "bytes", - "name": "sig", - "type": "bytes" + "name": "chainHash", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "chainNamespace", + "type": "string", + "indexed": false, + "internalType": "string" } ], - "name": "grantRulesWithSig", - "outputs": [ + "anonymous": false + }, + { + "type": "event", + "name": "RulesRevoked", + "inputs": [ { - "internalType": "bytes32", "name": "rulesId", - "type": "bytes32" + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" } ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "initializeAccount", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "anonymous": false }, { + "type": "event", + "name": "UninstallCallbackFailed", "inputs": [ { - "internalType": "uint256", - "name": "moduleTypeId", - "type": "uint256" - }, - { - "internalType": "address", "name": "module", - "type": "address" - }, - { - "internalType": "bytes", - "name": "initData", - "type": "bytes" + "type": "address", + "indexed": false, + "internalType": "address" } ], - "name": "installModule", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "anonymous": false + }, + { + "type": "error", + "name": "AlreadyInitialized", + "inputs": [] }, { + "type": "error", + "name": "CallerIsNotAgent", "inputs": [ { - "internalType": "uint256", - "name": "moduleTypeId", - "type": "uint256" - }, - { - "internalType": "address", - "name": "module", - "type": "address" + "name": "rulesId", + "type": "bytes32", + "internalType": "bytes32" }, { - "internalType": "bytes", - "name": "", - "type": "bytes" + "name": "caller", + "type": "address", + "internalType": "address" } - ], - "name": "isModuleInstalled", - "outputs": [ + ] + }, + { + "type": "error", + "name": "CallerIsNotFactory", + "inputs": [] + }, + { + "type": "error", + "name": "CallerIsNotOwner", + "inputs": [] + }, + { + "type": "error", + "name": "DuplicateAction", + "inputs": [ { - "internalType": "bool", - "name": "", - "type": "bool" + "name": "target", + "type": "address", + "internalType": "address" + }, + { + "name": "selector", + "type": "bytes4", + "internalType": "bytes4" } - ], - "stateMutability": "view", - "type": "function" + ] + }, + { + "type": "error", + "name": "EmptyChain", + "inputs": [] }, { + "type": "error", + "name": "EngineStillHoldsPermissions", + "inputs": [] + }, + { + "type": "error", + "name": "ExecutorMismatch", "inputs": [ { - "internalType": "bytes32", - "name": "", - "type": "bytes32" + "name": "expected", + "type": "address", + "internalType": "address" }, { - "internalType": "bytes", - "name": "", - "type": "bytes" + "name": "actual", + "type": "address", + "internalType": "address" } - ], - "name": "isValidSignature", - "outputs": [ + ] + }, + { + "type": "error", + "name": "ForbiddenActionSelector", + "inputs": [ { - "internalType": "bytes4", - "name": "", - "type": "bytes4" + "name": "selector", + "type": "bytes4", + "internalType": "bytes4" } - ], - "stateMutability": "pure", - "type": "function" + ] }, { - "inputs": [], - "name": "lastCheckpointBlock", - "outputs": [ + "type": "error", + "name": "ForbiddenActionTarget", + "inputs": [ { - "internalType": "uint64", - "name": "", - "type": "uint64" + "name": "target", + "type": "address", + "internalType": "address" } - ], - "stateMutability": "view", - "type": "function" + ] }, { + "type": "error", + "name": "ForbiddenDispatchTarget", "inputs": [ { - "internalType": "address", - "name": "", - "type": "address" - }, + "name": "target", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "InconsistentChain", + "inputs": [ { - "internalType": "address", - "name": "", - "type": "address" - }, + "name": "actionIndex", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "IntentExecMismatch", + "inputs": [ { - "internalType": "uint256[]", - "name": "", - "type": "uint256[]" - }, + "name": "actualCalldataHash", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "IntentGrantNonceMismatch", + "inputs": [ { - "internalType": "uint256[]", - "name": "", - "type": "uint256[]" + "name": "expected", + "type": "uint64", + "internalType": "uint64" }, { - "internalType": "bytes", - "name": "", - "type": "bytes" + "name": "provided", + "type": "uint64", + "internalType": "uint64" } - ], - "name": "onERC1155BatchReceived", - "outputs": [ + ] + }, + { + "type": "error", + "name": "IntentSessionMismatch", + "inputs": [ { - "internalType": "bytes4", - "name": "", - "type": "bytes4" + "name": "actual", + "type": "bytes32", + "internalType": "bytes32" } - ], - "stateMutability": "pure", - "type": "function" + ] }, { + "type": "error", + "name": "IntentWalletMismatch", "inputs": [ { - "internalType": "address", - "name": "", - "type": "address" + "name": "expected", + "type": "address", + "internalType": "address" }, { - "internalType": "address", - "name": "", - "type": "address" - }, + "name": "provided", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "InvalidModuleAddress", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidNonce", + "inputs": [ { - "internalType": "uint256", - "name": "", - "type": "uint256" + "name": "nonceKey", + "type": "uint192", + "internalType": "uint192" }, { - "internalType": "uint256", - "name": "", - "type": "uint256" + "name": "expected", + "type": "uint64", + "internalType": "uint64" }, { - "internalType": "bytes", - "name": "", - "type": "bytes" + "name": "provided", + "type": "uint64", + "internalType": "uint64" } - ], - "name": "onERC1155Received", - "outputs": [ + ] + }, + { + "type": "error", + "name": "InvalidOwnerSignature", + "inputs": [] + }, + { + "type": "error", + "name": "LabelTooLong", + "inputs": [ { - "internalType": "bytes4", - "name": "", - "type": "bytes4" + "name": "length", + "type": "uint256", + "internalType": "uint256" } - ], - "stateMutability": "pure", - "type": "function" + ] }, { + "type": "error", + "name": "MalformedBatchCalldata", + "inputs": [] + }, + { + "type": "error", + "name": "MalformedSessionShape", + "inputs": [] + }, + { + "type": "error", + "name": "ModuleAlreadyInstalled", "inputs": [ { - "internalType": "address", - "name": "", - "type": "address" - }, - { - "internalType": "address", - "name": "", - "type": "address" - }, + "name": "module", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "OutsideTimeWindow", + "inputs": [ { - "internalType": "uint256", - "name": "", - "type": "uint256" + "name": "validAfter", + "type": "uint48", + "internalType": "uint48" }, { - "internalType": "bytes", - "name": "", - "type": "bytes" + "name": "validUntil", + "type": "uint48", + "internalType": "uint48" } - ], - "name": "onERC721Received", - "outputs": [ + ] + }, + { + "type": "error", + "name": "OwnerLaneRequired", + "inputs": [ { - "internalType": "bytes4", - "name": "", - "type": "bytes4" + "name": "nonceKey", + "type": "uint192", + "internalType": "uint192" } - ], - "stateMutability": "pure", - "type": "function" + ] }, { - "inputs": [], - "name": "owner", - "outputs": [ + "type": "error", + "name": "OwnerSigExpired", + "inputs": [ { - "internalType": "address", - "name": "", - "type": "address" + "name": "deadline", + "type": "uint48", + "internalType": "uint48" } - ], - "stateMutability": "view", - "type": "function" + ] }, { - "inputs": [], - "name": "revokeAllRules", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "type": "error", + "name": "ReentrancyGuardReentrantCall", + "inputs": [] }, { + "type": "error", + "name": "RulesTypeMismatch", "inputs": [ { - "internalType": "bytes32", - "name": "rulesId", - "type": "bytes32" + "name": "derived", + "type": "uint8", + "internalType": "enum RulesType" + }, + { + "name": "actionIndex", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "target", + "type": "address", + "internalType": "address" } - ], - "name": "revokeRules", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + ] }, { + "type": "error", + "name": "TooManyActions", "inputs": [ { - "internalType": "bytes32", - "name": "mode", - "type": "bytes32" - } - ], - "name": "supportsExecutionMode", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" + "name": "count", + "type": "uint256", + "internalType": "uint256" } - ], - "stateMutability": "pure", - "type": "function" + ] }, { + "type": "error", + "name": "UnknownPermission", "inputs": [ { - "internalType": "bytes4", - "name": "interfaceId", - "type": "bytes4" - } - ], - "name": "supportsInterface", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" + "name": "rulesId", + "type": "bytes32", + "internalType": "bytes32" } - ], - "stateMutability": "pure", - "type": "function" + ] }, { + "type": "error", + "name": "UnsupportedExecutionMode", + "inputs": [] + }, + { + "type": "error", + "name": "UnsupportedModuleType", "inputs": [ { - "internalType": "uint256", "name": "moduleTypeId", - "type": "uint256" + "type": "uint256", + "internalType": "uint256" } - ], - "name": "supportsModule", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "pure", - "type": "function" + ] }, { + "type": "error", + "name": "ValidationFailed", "inputs": [ { - "internalType": "uint256", - "name": "moduleTypeId", - "type": "uint256" - }, - { - "internalType": "address", - "name": "module", - "type": "address" - }, - { - "internalType": "bytes", - "name": "deInitData", - "type": "bytes" + "name": "authorizer", + "type": "address", + "internalType": "address" } - ], - "name": "uninstallModule", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + ] }, { - "stateMutability": "payable", - "type": "receive" + "type": "error", + "name": "ValidatorNotInstalled", + "inputs": [ + { + "name": "validator", + "type": "address", + "internalType": "address" + } + ] } ] as const; diff --git a/packages/core/src/lib/agentic/contracts/abi/v4/index.ts b/packages/core/src/lib/agentic/contracts/abi/v5/index.ts similarity index 69% rename from packages/core/src/lib/agentic/contracts/abi/v4/index.ts rename to packages/core/src/lib/agentic/contracts/abi/v5/index.ts index 05446292..fa7ddd6a 100644 --- a/packages/core/src/lib/agentic/contracts/abi/v4/index.ts +++ b/packages/core/src/lib/agentic/contracts/abi/v5/index.ts @@ -1,6 +1,6 @@ // GENERATED by packages/core/scripts/agw-local/gen-abi.mjs — do not edit. -// Review generation v4: Donut v4 deployment; source e8db748. -export const V4_SOURCE_COMMIT = 'e8db74815cfbbf5389593805e464fe8d85f7f735' as const; +// Review generation v5: Donut v5 deployment; source 2e61e13. +export const V5_SOURCE_COMMIT = '2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb' as const; export { AGW_ABI } from './agw'; export { AGW_FACTORY_ABI } from './agw-factory'; export { UNIVERSAL_RULES_POLICY_ABI } from './universal-rules-policy'; diff --git a/packages/core/src/lib/agentic/contracts/abi/v4/smart-session.ts b/packages/core/src/lib/agentic/contracts/abi/v5/smart-session.ts similarity index 53% rename from packages/core/src/lib/agentic/contracts/abi/v4/smart-session.ts rename to packages/core/src/lib/agentic/contracts/abi/v5/smart-session.ts index faf9d38e..20e207b1 100644 --- a/packages/core/src/lib/agentic/contracts/abi/v4/smart-session.ts +++ b/packages/core/src/lib/agentic/contracts/abi/v5/smart-session.ts @@ -1,1961 +1,1961 @@ // GENERATED by packages/core/scripts/agw-local/gen-abi.mjs — do not edit. // Source: packages/core/scripts/agw-local/abis/engine.json -// push-agentic-wallets@e8db74815cfbbf5389593805e464fe8d85f7f735 -// sha256(SmartSession.json) = 32e7f3e48db6719306c436a0c81d80a2c5bcb3283b208ae043c460d483bc0180 +// push-agentic-wallets@2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb +// sha256(SmartSession.json) = 6e5d9cea4dbed01f06af913c1e093743b86b7432195f4a4bf90fb94b282c51b2 export const SMART_SESSION_ABI = [ { + "type": "function", + "name": "areActionsEnabled", "inputs": [ { - "internalType": "uint256", - "name": "index", - "type": "uint256" - } - ], - "name": "AssociatedArray_OutOfBounds", - "type": "error" - }, - { - "inputs": [ + "name": "account", + "type": "address", + "internalType": "address" + }, { - "internalType": "uint64", - "name": "providedChainId", - "type": "uint64" - } - ], - "name": "ChainIdMismatch", - "type": "error" - }, - { - "inputs": [ + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, { - "internalType": "uint64", - "name": "providedChainId", - "type": "uint64" + "name": "actions", + "type": "tuple[]", + "internalType": "struct ActionData[]", + "components": [ + { + "name": "actionTargetSelector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "actionTarget", + "type": "address", + "internalType": "address" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] } ], - "name": "ChainIdMismatch", - "type": "error" - }, - { - "inputs": [], - "name": "ForbiddenValidationData", - "type": "error" - }, - { - "inputs": [ + "outputs": [ { - "internalType": "uint256", - "name": "index", - "type": "uint256" + "name": "", + "type": "bool", + "internalType": "bool" } ], - "name": "HashIndexOutOfBounds", - "type": "error" + "stateMutability": "view" }, { + "type": "function", + "name": "areERC1271PoliciesEnabled", "inputs": [ { - "internalType": "bytes32", - "name": "providedHash", - "type": "bytes32" + "name": "account", + "type": "address", + "internalType": "address" }, { - "internalType": "bytes32", - "name": "computedHash", - "type": "bytes32" + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] } ], - "name": "HashMismatch", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "providedHash", - "type": "bytes32" - }, + "outputs": [ { - "internalType": "bytes32", - "name": "computedHash", - "type": "bytes32" + "name": "", + "type": "bool", + "internalType": "bool" } ], - "name": "HashMismatch", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidActionId", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCallTarget", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidData", - "type": "error" + "stateMutability": "view" }, { + "type": "function", + "name": "areUserOpPoliciesEnabled", "inputs": [ { - "internalType": "address", "name": "account", - "type": "address" + "type": "address", + "internalType": "address" }, { - "internalType": "bytes32", - "name": "hash", - "type": "bytes32" - } - ], - "name": "InvalidEnableSignature", - "type": "error" - }, - { - "inputs": [ + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, { - "internalType": "contract ISessionValidator", - "name": "sessionValidator", - "type": "address" + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] } ], - "name": "InvalidISessionValidator", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidMode", - "type": "error" - }, - { - "inputs": [ + "outputs": [ { - "internalType": "PermissionId", - "name": "permissionId", - "type": "bytes32" + "name": "", + "type": "bool", + "internalType": "bool" } ], - "name": "InvalidPermissionId", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidSelfCall", - "type": "error" + "stateMutability": "view" }, { + "type": "function", + "name": "disableActionId", "inputs": [ { - "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32" + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "actionId", + "type": "bytes32", + "internalType": "ActionId" } ], - "name": "InvalidSession", - "type": "error" + "outputs": [], + "stateMutability": "nonpayable" }, { + "type": "function", + "name": "disableActionPolicies", "inputs": [ { - "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32" + "type": "bytes32", + "internalType": "PermissionId" }, { - "internalType": "address", - "name": "sessionValidator", - "type": "address" - }, - { - "internalType": "address", - "name": "account", - "type": "address" + "name": "actionId", + "type": "bytes32", + "internalType": "ActionId" }, { - "internalType": "bytes32", - "name": "userOpHash", - "type": "bytes32" - } - ], - "name": "InvalidSessionKeySignature", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidTarget", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "sender", - "type": "address" + "name": "policies", + "type": "address[]", + "internalType": "address[]" } ], - "name": "InvalidUserOpSender", - "type": "error" - }, - { - "inputs": [], - "name": "NoExecutionsInBatch", - "type": "error" + "outputs": [], + "stateMutability": "nonpayable" }, { + "type": "function", + "name": "disableERC1271Policies", "inputs": [ { - "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32" - } - ], - "name": "NoPoliciesSet", - "type": "error" - }, - { - "inputs": [], - "name": "PartlyEnabledActions", - "type": "error" - }, - { - "inputs": [], - "name": "PartlyEnabledPolicies", - "type": "error" - }, - { - "inputs": [ + "type": "bytes32", + "internalType": "PermissionId" + }, { - "internalType": "PermissionId", - "name": "permissionId", - "type": "bytes32" + "name": "policies", + "type": "address[]", + "internalType": "address[]" + }, + { + "name": "contexts", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNames", + "type": "string[]", + "internalType": "string[]" + } + ] } ], - "name": "PaymasterValidationNotEnabled", - "type": "error" + "outputs": [], + "stateMutability": "nonpayable" }, { + "type": "function", + "name": "disableUserOpPolicies", "inputs": [ { - "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32" + "type": "bytes32", + "internalType": "PermissionId" }, { - "internalType": "address", - "name": "policy", - "type": "address" + "name": "policies", + "type": "address[]", + "internalType": "address[]" } ], - "name": "PolicyViolation", - "type": "error" + "outputs": [], + "stateMutability": "nonpayable" }, { + "type": "function", + "name": "enableActionPolicies", "inputs": [ { - "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32" + "type": "bytes32", + "internalType": "PermissionId" }, { - "internalType": "address", - "name": "account", - "type": "address" + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct ActionData[]", + "components": [ + { + "name": "actionTargetSelector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "actionTarget", + "type": "address", + "internalType": "address" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] } ], - "name": "SignerNotFound", - "type": "error" + "outputs": [], + "stateMutability": "nonpayable" }, { + "type": "function", + "name": "enableERC1271Policies", "inputs": [ { - "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32" + "type": "bytes32", + "internalType": "PermissionId" }, { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "SignerNotFound", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" + "name": "erc1271Policies", + "type": "tuple", + "internalType": "struct ERC7739Data", + "components": [ + { + "name": "allowedERC7739Content", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNames", + "type": "string[]", + "internalType": "string[]" + } + ] + }, + { + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] } ], - "name": "SmartSessionModuleAlreadyInstalled", - "type": "error" + "outputs": [], + "stateMutability": "nonpayable" }, { + "type": "function", + "name": "enableSessions", "inputs": [ { - "internalType": "CallType", - "name": "callType", - "type": "bytes1" - } - ], - "name": "UnsupportedCallType", - "type": "error" - }, - { - "inputs": [], - "name": "UnsupportedExecutionType", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "policy", - "type": "address" + "name": "sessions", + "type": "tuple[]", + "internalType": "struct Session[]", + "components": [ + { + "name": "sessionValidator", + "type": "address", + "internalType": "contract ISessionValidator" + }, + { + "name": "sessionValidatorInitData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "erc7739Policies", + "type": "tuple", + "internalType": "struct ERC7739Data", + "components": [ + { + "name": "allowedERC7739Content", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNames", + "type": "string[]", + "internalType": "string[]" + } + ] + }, + { + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "actions", + "type": "tuple[]", + "internalType": "struct ActionData[]", + "components": [ + { + "name": "actionTargetSelector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "actionTarget", + "type": "address", + "internalType": "address" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "permitERC4337Paymaster", + "type": "bool", + "internalType": "bool" + } + ] } ], - "name": "UnsupportedPolicy", - "type": "error" - }, - { - "inputs": [ + "outputs": [ { - "internalType": "enum SmartSessionMode", - "name": "mode", - "type": "uint8" + "name": "permissionIds", + "type": "bytes32[]", + "internalType": "PermissionId[]" } ], - "name": "UnsupportedSmartSessionMode", - "type": "error" + "stateMutability": "nonpayable" }, { - "anonymous": false, + "type": "function", + "name": "enableUserOpPolicies", "inputs": [ { - "indexed": false, - "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32" + "type": "bytes32", + "internalType": "PermissionId" }, { - "indexed": false, - "internalType": "ActionId", - "name": "actionId", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "address", - "name": "smartAccount", - "type": "address" + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] } ], - "name": "ActionIdDisabled", - "type": "event" + "outputs": [], + "stateMutability": "nonpayable" }, { - "anonymous": false, + "type": "function", + "name": "getActionPolicies", "inputs": [ { - "indexed": false, - "internalType": "PermissionId", - "name": "permissionId", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "address", "name": "account", - "type": "address" + "type": "address", + "internalType": "address" }, { - "indexed": false, - "internalType": "uint256", - "name": "newValue", - "type": "uint256" - } - ], - "name": "NonceIterated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32" + "type": "bytes32", + "internalType": "PermissionId" }, { - "indexed": false, - "internalType": "address", - "name": "smartAccount", - "type": "address" - }, + "name": "actionId", + "type": "bytes32", + "internalType": "ActionId" + } + ], + "outputs": [ { - "indexed": false, - "internalType": "bool", - "name": "enabled", - "type": "bool" + "name": "", + "type": "address[]", + "internalType": "address[]" } ], - "name": "PermissionIdPermit4337Paymaster", - "type": "event" + "stateMutability": "view" }, { - "anonymous": false, + "type": "function", + "name": "getERC1271Policies", "inputs": [ { - "indexed": false, - "internalType": "PermissionId", - "name": "permissionId", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "enum PolicyType", - "name": "policyType", - "type": "uint8" + "name": "account", + "type": "address", + "internalType": "address" }, { - "indexed": false, - "internalType": "address", - "name": "policy", - "type": "address" - }, + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ], + "outputs": [ { - "indexed": false, - "internalType": "address", - "name": "smartAccount", - "type": "address" + "name": "", + "type": "address[]", + "internalType": "address[]" } ], - "name": "PolicyDisabled", - "type": "event" + "stateMutability": "view" }, { - "anonymous": false, + "type": "function", + "name": "getEnabledActions", "inputs": [ { - "indexed": false, - "internalType": "PermissionId", - "name": "permissionId", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "enum PolicyType", - "name": "policyType", - "type": "uint8" + "name": "account", + "type": "address", + "internalType": "address" }, { - "indexed": false, - "internalType": "address", - "name": "policy", - "type": "address" - }, + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ], + "outputs": [ { - "indexed": false, - "internalType": "address", - "name": "smartAccount", - "type": "address" + "name": "", + "type": "bytes32[]", + "internalType": "bytes32[]" } ], - "name": "PolicyEnabled", - "type": "event" + "stateMutability": "view" }, { - "anonymous": false, + "type": "function", + "name": "getEnabledERC7739Content", "inputs": [ { - "indexed": false, - "internalType": "PermissionId", - "name": "permissionId", - "type": "bytes32" + "name": "account", + "type": "address", + "internalType": "address" }, { - "indexed": false, - "internalType": "address", - "name": "account", - "type": "address" + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" } ], - "name": "SessionCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "PermissionId", - "name": "permissionId", - "type": "bytes32" - }, + "outputs": [ { - "indexed": false, - "internalType": "address", - "name": "smartAccount", - "type": "address" + "name": "enabledERC7739ContentHashes", + "type": "tuple[]", + "internalType": "struct ERC7739ContextHashes[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNameHashes", + "type": "bytes32[]", + "internalType": "bytes32[]" + } + ] } ], - "name": "SessionRemoved", - "type": "event" + "stateMutability": "view" }, { - "anonymous": false, + "type": "function", + "name": "getNonce", "inputs": [ { - "indexed": false, - "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32" + "type": "bytes32", + "internalType": "PermissionId" }, { - "indexed": false, - "internalType": "address", - "name": "sessionValidator", - "type": "address" - }, + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ { - "indexed": false, - "internalType": "address", - "name": "smartAccount", - "type": "address" + "name": "", + "type": "uint256", + "internalType": "uint256" } ], - "name": "SessionValidatorDisabled", - "type": "event" + "stateMutability": "view" }, { - "anonymous": false, + "type": "function", + "name": "getPermissionIDs", "inputs": [ { - "indexed": false, - "internalType": "PermissionId", - "name": "permissionId", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "address", - "name": "sessionValidator", - "type": "address" - }, + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ { - "indexed": false, - "internalType": "address", - "name": "smartAccount", - "type": "address" + "name": "permissionIds", + "type": "bytes32[]", + "internalType": "PermissionId[]" } ], - "name": "SessionValidatorEnabled", - "type": "event" + "stateMutability": "view" }, { + "type": "function", + "name": "getPermissionId", "inputs": [ { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "PermissionId", - "name": "permissionId", - "type": "bytes32" - }, - { + "name": "session", + "type": "tuple", + "internalType": "struct Session", "components": [ { - "internalType": "bytes4", - "name": "actionTargetSelector", - "type": "bytes4" + "name": "sessionValidator", + "type": "address", + "internalType": "contract ISessionValidator" }, { - "internalType": "address", - "name": "actionTarget", - "type": "address" + "name": "sessionValidatorInitData", + "type": "bytes", + "internalType": "bytes" }, { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", "components": [ { - "internalType": "address", "name": "policy", - "type": "address" + "type": "address", + "internalType": "address" }, { - "internalType": "bytes", "name": "initData", - "type": "bytes" + "type": "bytes", + "internalType": "bytes" } - ], - "internalType": "struct PolicyData[]", - "name": "actionPolicies", - "type": "tuple[]" - } - ], - "internalType": "struct ActionData[]", - "name": "actions", - "type": "tuple[]" - } - ], - "name": "areActionsEnabled", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "PermissionId", - "name": "permissionId", - "type": "bytes32" - }, - { - "components": [ - { - "internalType": "address", - "name": "policy", - "type": "address" - }, - { - "internalType": "bytes", - "name": "initData", - "type": "bytes" - } - ], - "internalType": "struct PolicyData[]", - "name": "erc1271Policies", - "type": "tuple[]" - } - ], - "name": "areERC1271PoliciesEnabled", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "PermissionId", - "name": "permissionId", - "type": "bytes32" - }, - { - "components": [ - { - "internalType": "address", - "name": "policy", - "type": "address" - }, - { - "internalType": "bytes", - "name": "initData", - "type": "bytes" - } - ], - "internalType": "struct PolicyData[]", - "name": "userOpPolicies", - "type": "tuple[]" - } - ], - "name": "areUserOpPoliciesEnabled", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "PermissionId", - "name": "permissionId", - "type": "bytes32" - }, - { - "internalType": "ActionId", - "name": "actionId", - "type": "bytes32" - } - ], - "name": "disableActionId", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "PermissionId", - "name": "permissionId", - "type": "bytes32" - }, - { - "internalType": "ActionId", - "name": "actionId", - "type": "bytes32" - }, - { - "internalType": "address[]", - "name": "policies", - "type": "address[]" - } - ], - "name": "disableActionPolicies", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "PermissionId", - "name": "permissionId", - "type": "bytes32" - }, - { - "internalType": "address[]", - "name": "policies", - "type": "address[]" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "appDomainSeparator", - "type": "bytes32" - }, - { - "internalType": "string[]", - "name": "contentNames", - "type": "string[]" - } - ], - "internalType": "struct ERC7739Context[]", - "name": "contexts", - "type": "tuple[]" - } - ], - "name": "disableERC1271Policies", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "PermissionId", - "name": "permissionId", - "type": "bytes32" - }, - { - "internalType": "address[]", - "name": "policies", - "type": "address[]" - } - ], - "name": "disableUserOpPolicies", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "PermissionId", - "name": "permissionId", - "type": "bytes32" - }, - { - "components": [ - { - "internalType": "bytes4", - "name": "actionTargetSelector", - "type": "bytes4" - }, - { - "internalType": "address", - "name": "actionTarget", - "type": "address" + ] }, { + "name": "erc7739Policies", + "type": "tuple", + "internalType": "struct ERC7739Data", "components": [ { - "internalType": "address", - "name": "policy", - "type": "address" + "name": "allowedERC7739Content", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNames", + "type": "string[]", + "internalType": "string[]" + } + ] }, { - "internalType": "bytes", - "name": "initData", - "type": "bytes" + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] } - ], - "internalType": "struct PolicyData[]", - "name": "actionPolicies", - "type": "tuple[]" - } - ], - "internalType": "struct ActionData[]", - "name": "actionPolicies", - "type": "tuple[]" - } - ], - "name": "enableActionPolicies", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "PermissionId", - "name": "permissionId", - "type": "bytes32" - }, - { - "components": [ + ] + }, { + "name": "actions", + "type": "tuple[]", + "internalType": "struct ActionData[]", "components": [ { - "internalType": "bytes32", - "name": "appDomainSeparator", - "type": "bytes32" + "name": "actionTargetSelector", + "type": "bytes4", + "internalType": "bytes4" }, { - "internalType": "string[]", - "name": "contentNames", - "type": "string[]" - } - ], - "internalType": "struct ERC7739Context[]", - "name": "allowedERC7739Content", - "type": "tuple[]" - }, - { - "components": [ - { - "internalType": "address", - "name": "policy", - "type": "address" + "name": "actionTarget", + "type": "address", + "internalType": "address" }, { - "internalType": "bytes", - "name": "initData", - "type": "bytes" + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] } - ], - "internalType": "struct PolicyData[]", - "name": "erc1271Policies", - "type": "tuple[]" + ] + }, + { + "name": "permitERC4337Paymaster", + "type": "bool", + "internalType": "bool" } - ], - "internalType": "struct ERC7739Data", - "name": "erc1271Policies", - "type": "tuple" + ] } ], - "name": "enableERC1271Policies", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "outputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ], + "stateMutability": "pure" }, { + "type": "function", + "name": "getSessionDigest", "inputs": [ { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "data", + "type": "tuple", + "internalType": "struct Session", "components": [ { - "internalType": "contract ISessionValidator", "name": "sessionValidator", - "type": "address" + "type": "address", + "internalType": "contract ISessionValidator" }, { - "internalType": "bytes", "name": "sessionValidatorInitData", - "type": "bytes" + "type": "bytes", + "internalType": "bytes" }, { - "internalType": "bytes32", "name": "salt", - "type": "bytes32" + "type": "bytes32", + "internalType": "bytes32" }, { + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", "components": [ { - "internalType": "address", "name": "policy", - "type": "address" + "type": "address", + "internalType": "address" }, { - "internalType": "bytes", "name": "initData", - "type": "bytes" + "type": "bytes", + "internalType": "bytes" } - ], - "internalType": "struct PolicyData[]", - "name": "userOpPolicies", - "type": "tuple[]" + ] }, { + "name": "erc7739Policies", + "type": "tuple", + "internalType": "struct ERC7739Data", "components": [ { + "name": "allowedERC7739Content", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", "components": [ { - "internalType": "bytes32", "name": "appDomainSeparator", - "type": "bytes32" + "type": "bytes32", + "internalType": "bytes32" }, { - "internalType": "string[]", "name": "contentNames", - "type": "string[]" + "type": "string[]", + "internalType": "string[]" } - ], - "internalType": "struct ERC7739Context[]", - "name": "allowedERC7739Content", - "type": "tuple[]" + ] }, { + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", "components": [ { - "internalType": "address", "name": "policy", - "type": "address" + "type": "address", + "internalType": "address" }, { - "internalType": "bytes", "name": "initData", - "type": "bytes" + "type": "bytes", + "internalType": "bytes" } - ], - "internalType": "struct PolicyData[]", - "name": "erc1271Policies", - "type": "tuple[]" + ] } - ], - "internalType": "struct ERC7739Data", - "name": "erc7739Policies", - "type": "tuple" + ] }, { + "name": "actions", + "type": "tuple[]", + "internalType": "struct ActionData[]", "components": [ { - "internalType": "bytes4", "name": "actionTargetSelector", - "type": "bytes4" + "type": "bytes4", + "internalType": "bytes4" }, { - "internalType": "address", "name": "actionTarget", - "type": "address" + "type": "address", + "internalType": "address" }, { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", "components": [ { - "internalType": "address", "name": "policy", - "type": "address" + "type": "address", + "internalType": "address" }, { - "internalType": "bytes", "name": "initData", - "type": "bytes" + "type": "bytes", + "internalType": "bytes" } - ], - "internalType": "struct PolicyData[]", - "name": "actionPolicies", - "type": "tuple[]" + ] } - ], - "internalType": "struct ActionData[]", - "name": "actions", - "type": "tuple[]" + ] }, { - "internalType": "bool", "name": "permitERC4337Paymaster", - "type": "bool" + "type": "bool", + "internalType": "bool" } - ], - "internalType": "struct Session[]", - "name": "sessions", - "type": "tuple[]" + ] + }, + { + "name": "mode", + "type": "uint8", + "internalType": "enum SmartSessionMode" } ], - "name": "enableSessions", "outputs": [ { - "internalType": "PermissionId[]", - "name": "permissionIds", - "type": "bytes32[]" + "name": "", + "type": "bytes32", + "internalType": "bytes32" } ], - "stateMutability": "nonpayable", - "type": "function" + "stateMutability": "view" }, { + "type": "function", + "name": "getSessionValidatorAndConfig", "inputs": [ { - "internalType": "PermissionId", - "name": "permissionId", - "type": "bytes32" + "name": "account", + "type": "address", + "internalType": "address" }, { - "components": [ - { - "internalType": "address", - "name": "policy", - "type": "address" - }, - { - "internalType": "bytes", - "name": "initData", - "type": "bytes" - } - ], - "internalType": "struct PolicyData[]", - "name": "userOpPolicies", - "type": "tuple[]" + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" } ], - "name": "enableUserOpPolicies", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "outputs": [ + { + "name": "sessionValidator", + "type": "address", + "internalType": "address" + }, + { + "name": "sessionValidatorData", + "type": "bytes", + "internalType": "bytes" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getUserOpPolicies", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ], + "outputs": [ + { + "name": "", + "type": "address[]", + "internalType": "address[]" + } + ], + "stateMutability": "view" }, { + "type": "function", + "name": "isActionIdEnabled", "inputs": [ { - "internalType": "address", "name": "account", - "type": "address" + "type": "address", + "internalType": "address" }, { - "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32" + "type": "bytes32", + "internalType": "PermissionId" }, { - "internalType": "ActionId", "name": "actionId", - "type": "bytes32" + "type": "bytes32", + "internalType": "ActionId" } ], - "name": "getActionPolicies", "outputs": [ { - "internalType": "address[]", "name": "", - "type": "address[]" + "type": "bool", + "internalType": "bool" } ], - "stateMutability": "view", - "type": "function" + "stateMutability": "view" }, { + "type": "function", + "name": "isActionPolicyEnabled", "inputs": [ { - "internalType": "address", "name": "account", - "type": "address" + "type": "address", + "internalType": "address" }, { - "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32" + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "actionId", + "type": "bytes32", + "internalType": "ActionId" + }, + { + "name": "policy", + "type": "address", + "internalType": "address" } ], - "name": "getERC1271Policies", "outputs": [ { - "internalType": "address[]", "name": "", - "type": "address[]" + "type": "bool", + "internalType": "bool" } ], - "stateMutability": "view", - "type": "function" + "stateMutability": "view" }, { + "type": "function", + "name": "isERC1271PolicyEnabled", "inputs": [ { - "internalType": "address", "name": "account", - "type": "address" + "type": "address", + "internalType": "address" }, { - "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32" + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "policy", + "type": "address", + "internalType": "address" } ], - "name": "getEnabledActions", "outputs": [ { - "internalType": "bytes32[]", "name": "", - "type": "bytes32[]" + "type": "bool", + "internalType": "bool" } ], - "stateMutability": "view", - "type": "function" + "stateMutability": "view" }, { + "type": "function", + "name": "isERC7739ContentEnabled", "inputs": [ { - "internalType": "address", "name": "account", - "type": "address" + "type": "address", + "internalType": "address" }, { - "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32" + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "content", + "type": "string", + "internalType": "string" } ], - "name": "getEnabledERC7739Content", "outputs": [ { - "components": [ - { - "internalType": "bytes32", - "name": "appDomainSeparator", - "type": "bytes32" - }, - { - "internalType": "bytes32[]", - "name": "contentNameHashes", - "type": "bytes32[]" - } - ], - "internalType": "struct ERC7739ContextHashes[]", - "name": "enabledERC7739ContentHashes", - "type": "tuple[]" + "name": "", + "type": "bool", + "internalType": "bool" } ], - "stateMutability": "view", - "type": "function" + "stateMutability": "view" }, { + "type": "function", + "name": "isISessionValidatorSet", "inputs": [ { - "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32" + "type": "bytes32", + "internalType": "PermissionId" }, { - "internalType": "address", "name": "account", - "type": "address" + "type": "address", + "internalType": "address" } ], - "name": "getNonce", "outputs": [ { - "internalType": "uint256", "name": "", - "type": "uint256" + "type": "bool", + "internalType": "bool" } ], - "stateMutability": "view", - "type": "function" + "stateMutability": "view" }, { + "type": "function", + "name": "isInitialized", "inputs": [ { - "internalType": "address", - "name": "account", - "type": "address" + "name": "smartAccount", + "type": "address", + "internalType": "address" } ], - "name": "getPermissionIDs", "outputs": [ { - "internalType": "PermissionId[]", - "name": "permissionIds", - "type": "bytes32[]" + "name": "", + "type": "bool", + "internalType": "bool" } ], - "stateMutability": "view", - "type": "function" + "stateMutability": "view" }, { + "type": "function", + "name": "isModuleType", "inputs": [ { - "components": [ - { - "internalType": "contract ISessionValidator", - "name": "sessionValidator", - "type": "address" - }, - { - "internalType": "bytes", - "name": "sessionValidatorInitData", - "type": "bytes" - }, - { - "internalType": "bytes32", - "name": "salt", - "type": "bytes32" - }, - { - "components": [ - { - "internalType": "address", - "name": "policy", - "type": "address" - }, - { - "internalType": "bytes", - "name": "initData", - "type": "bytes" - } - ], - "internalType": "struct PolicyData[]", - "name": "userOpPolicies", - "type": "tuple[]" - }, - { - "components": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "appDomainSeparator", - "type": "bytes32" - }, - { - "internalType": "string[]", - "name": "contentNames", - "type": "string[]" - } - ], - "internalType": "struct ERC7739Context[]", - "name": "allowedERC7739Content", - "type": "tuple[]" - }, - { - "components": [ - { - "internalType": "address", - "name": "policy", - "type": "address" - }, - { - "internalType": "bytes", - "name": "initData", - "type": "bytes" - } - ], - "internalType": "struct PolicyData[]", - "name": "erc1271Policies", - "type": "tuple[]" - } - ], - "internalType": "struct ERC7739Data", - "name": "erc7739Policies", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "bytes4", - "name": "actionTargetSelector", - "type": "bytes4" - }, - { - "internalType": "address", - "name": "actionTarget", - "type": "address" - }, - { - "components": [ - { - "internalType": "address", - "name": "policy", - "type": "address" - }, - { - "internalType": "bytes", - "name": "initData", - "type": "bytes" - } - ], - "internalType": "struct PolicyData[]", - "name": "actionPolicies", - "type": "tuple[]" - } - ], - "internalType": "struct ActionData[]", - "name": "actions", - "type": "tuple[]" - }, - { - "internalType": "bool", - "name": "permitERC4337Paymaster", - "type": "bool" - } - ], - "internalType": "struct Session", - "name": "session", - "type": "tuple" + "name": "typeID", + "type": "uint256", + "internalType": "uint256" } ], - "name": "getPermissionId", "outputs": [ { - "internalType": "PermissionId", - "name": "permissionId", - "type": "bytes32" + "name": "", + "type": "bool", + "internalType": "bool" } ], - "stateMutability": "pure", - "type": "function" + "stateMutability": "pure" }, { + "type": "function", + "name": "isPermissionEnabled", "inputs": [ { - "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32" + "type": "bytes32", + "internalType": "PermissionId" }, { - "internalType": "address", "name": "account", - "type": "address" + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isUserOpPolicyEnabled", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" }, { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "policy", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isValidSignatureWithSender", + "inputs": [ + { + "name": "sender", + "type": "address", + "internalType": "address" + }, + { + "name": "hash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "signature", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "result", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "onInstall", + "inputs": [ + { + "name": "data", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "onUninstall", + "inputs": [ + { + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "removeSession", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "revokeEnableSignature", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setPermit4337Paymaster", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "enabled", + "type": "bool", + "internalType": "bool" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "validateUserOp", + "inputs": [ + { + "name": "userOp", + "type": "tuple", + "internalType": "struct PackedUserOperation", "components": [ { - "internalType": "contract ISessionValidator", - "name": "sessionValidator", - "type": "address" + "name": "sender", + "type": "address", + "internalType": "address" }, { - "internalType": "bytes", - "name": "sessionValidatorInitData", - "type": "bytes" + "name": "nonce", + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "bytes32", - "name": "salt", - "type": "bytes32" + "name": "initCode", + "type": "bytes", + "internalType": "bytes" }, { - "components": [ - { - "internalType": "address", - "name": "policy", - "type": "address" - }, - { - "internalType": "bytes", - "name": "initData", - "type": "bytes" - } - ], - "internalType": "struct PolicyData[]", - "name": "userOpPolicies", - "type": "tuple[]" + "name": "callData", + "type": "bytes", + "internalType": "bytes" }, { - "components": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "appDomainSeparator", - "type": "bytes32" - }, - { - "internalType": "string[]", - "name": "contentNames", - "type": "string[]" - } - ], - "internalType": "struct ERC7739Context[]", - "name": "allowedERC7739Content", - "type": "tuple[]" - }, - { - "components": [ - { - "internalType": "address", - "name": "policy", - "type": "address" - }, - { - "internalType": "bytes", - "name": "initData", - "type": "bytes" - } - ], - "internalType": "struct PolicyData[]", - "name": "erc1271Policies", - "type": "tuple[]" - } - ], - "internalType": "struct ERC7739Data", - "name": "erc7739Policies", - "type": "tuple" + "name": "accountGasLimits", + "type": "bytes32", + "internalType": "bytes32" }, { - "components": [ - { - "internalType": "bytes4", - "name": "actionTargetSelector", - "type": "bytes4" - }, - { - "internalType": "address", - "name": "actionTarget", - "type": "address" - }, - { - "components": [ - { - "internalType": "address", - "name": "policy", - "type": "address" - }, - { - "internalType": "bytes", - "name": "initData", - "type": "bytes" - } - ], - "internalType": "struct PolicyData[]", - "name": "actionPolicies", - "type": "tuple[]" - } - ], - "internalType": "struct ActionData[]", - "name": "actions", - "type": "tuple[]" + "name": "preVerificationGas", + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "bool", - "name": "permitERC4337Paymaster", - "type": "bool" + "name": "gasFees", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "paymasterAndData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "signature", + "type": "bytes", + "internalType": "bytes" } - ], - "internalType": "struct Session", - "name": "data", - "type": "tuple" + ] }, { - "internalType": "enum SmartSessionMode", - "name": "mode", - "type": "uint8" + "name": "userOpHash", + "type": "bytes32", + "internalType": "bytes32" } ], - "name": "getSessionDigest", "outputs": [ { - "internalType": "bytes32", - "name": "", - "type": "bytes32" + "name": "vd", + "type": "uint256", + "internalType": "ValidationData" } ], - "stateMutability": "view", - "type": "function" + "stateMutability": "nonpayable" }, { + "type": "event", + "name": "ActionIdDisabled", "inputs": [ { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32" - } - ], - "name": "getSessionValidatorAndConfig", - "outputs": [ + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" + }, { - "internalType": "address", - "name": "sessionValidator", - "type": "address" + "name": "actionId", + "type": "bytes32", + "indexed": false, + "internalType": "ActionId" }, { - "internalType": "bytes", - "name": "sessionValidatorData", - "type": "bytes" + "name": "smartAccount", + "type": "address", + "indexed": false, + "internalType": "address" } ], - "stateMutability": "view", - "type": "function" + "anonymous": false }, { + "type": "event", + "name": "NonceIterated", "inputs": [ { - "internalType": "address", + "name": "permissionId", + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" + }, + { "name": "account", - "type": "address" + "type": "address", + "indexed": false, + "internalType": "address" }, { - "internalType": "PermissionId", - "name": "permissionId", - "type": "bytes32" + "name": "newValue", + "type": "uint256", + "indexed": false, + "internalType": "uint256" } ], - "name": "getUserOpPolicies", - "outputs": [ + "anonymous": false + }, + { + "type": "event", + "name": "PermissionIdPermit4337Paymaster", + "inputs": [ { - "internalType": "address[]", - "name": "", - "type": "address[]" + "name": "permissionId", + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" + }, + { + "name": "smartAccount", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "enabled", + "type": "bool", + "indexed": false, + "internalType": "bool" } ], - "stateMutability": "view", - "type": "function" + "anonymous": false }, { + "type": "event", + "name": "PolicyDisabled", "inputs": [ { - "internalType": "address", - "name": "account", - "type": "address" + "name": "permissionId", + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" }, { - "internalType": "PermissionId", - "name": "permissionId", - "type": "bytes32" + "name": "policyType", + "type": "uint8", + "indexed": false, + "internalType": "enum PolicyType" }, { - "internalType": "ActionId", - "name": "actionId", - "type": "bytes32" - } - ], - "name": "isActionIdEnabled", - "outputs": [ + "name": "policy", + "type": "address", + "indexed": false, + "internalType": "address" + }, { - "internalType": "bool", - "name": "", - "type": "bool" + "name": "smartAccount", + "type": "address", + "indexed": false, + "internalType": "address" } ], - "stateMutability": "view", - "type": "function" + "anonymous": false }, { + "type": "event", + "name": "PolicyEnabled", "inputs": [ { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32" + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" }, { - "internalType": "ActionId", - "name": "actionId", - "type": "bytes32" + "name": "policyType", + "type": "uint8", + "indexed": false, + "internalType": "enum PolicyType" }, { - "internalType": "address", "name": "policy", - "type": "address" + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "smartAccount", + "type": "address", + "indexed": false, + "internalType": "address" } ], - "name": "isActionPolicyEnabled", - "outputs": [ + "anonymous": false + }, + { + "type": "event", + "name": "SessionCreated", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" + }, + { + "name": "account", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "SessionRemoved", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" + }, { - "internalType": "bool", - "name": "", - "type": "bool" + "name": "smartAccount", + "type": "address", + "indexed": false, + "internalType": "address" } ], - "stateMutability": "view", - "type": "function" + "anonymous": false }, { + "type": "event", + "name": "SessionValidatorDisabled", "inputs": [ { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32" + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" }, { - "internalType": "address", - "name": "policy", - "type": "address" - } - ], - "name": "isERC1271PolicyEnabled", - "outputs": [ + "name": "sessionValidator", + "type": "address", + "indexed": false, + "internalType": "address" + }, { - "internalType": "bool", - "name": "", - "type": "bool" + "name": "smartAccount", + "type": "address", + "indexed": false, + "internalType": "address" } ], - "stateMutability": "view", - "type": "function" + "anonymous": false }, { + "type": "event", + "name": "SessionValidatorEnabled", "inputs": [ { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32" + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" }, { - "internalType": "bytes32", - "name": "appDomainSeparator", - "type": "bytes32" + "name": "sessionValidator", + "type": "address", + "indexed": false, + "internalType": "address" }, { - "internalType": "string", - "name": "content", - "type": "string" + "name": "smartAccount", + "type": "address", + "indexed": false, + "internalType": "address" } ], - "name": "isERC7739ContentEnabled", - "outputs": [ + "anonymous": false + }, + { + "type": "error", + "name": "AssociatedArray_OutOfBounds", + "inputs": [ { - "internalType": "bool", - "name": "", - "type": "bool" + "name": "index", + "type": "uint256", + "internalType": "uint256" } - ], - "stateMutability": "view", - "type": "function" + ] }, { + "type": "error", + "name": "ChainIdMismatch", "inputs": [ { - "internalType": "PermissionId", - "name": "permissionId", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "account", - "type": "address" + "name": "providedChainId", + "type": "uint64", + "internalType": "uint64" } - ], - "name": "isISessionValidatorSet", - "outputs": [ + ] + }, + { + "type": "error", + "name": "ChainIdMismatch", + "inputs": [ { - "internalType": "bool", - "name": "", - "type": "bool" + "name": "providedChainId", + "type": "uint64", + "internalType": "uint64" } - ], - "stateMutability": "view", - "type": "function" + ] + }, + { + "type": "error", + "name": "ForbiddenValidationData", + "inputs": [] }, { + "type": "error", + "name": "HashIndexOutOfBounds", "inputs": [ { - "internalType": "address", - "name": "smartAccount", - "type": "address" + "name": "index", + "type": "uint256", + "internalType": "uint256" } - ], - "name": "isInitialized", - "outputs": [ + ] + }, + { + "type": "error", + "name": "HashMismatch", + "inputs": [ { - "internalType": "bool", - "name": "", - "type": "bool" + "name": "providedHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "computedHash", + "type": "bytes32", + "internalType": "bytes32" } - ], - "stateMutability": "view", - "type": "function" + ] }, { + "type": "error", + "name": "HashMismatch", "inputs": [ { - "internalType": "uint256", - "name": "typeID", - "type": "uint256" - } - ], - "name": "isModuleType", - "outputs": [ + "name": "providedHash", + "type": "bytes32", + "internalType": "bytes32" + }, { - "internalType": "bool", - "name": "", - "type": "bool" + "name": "computedHash", + "type": "bytes32", + "internalType": "bytes32" } - ], - "stateMutability": "pure", - "type": "function" + ] + }, + { + "type": "error", + "name": "InvalidActionId", + "inputs": [] }, { + "type": "error", + "name": "InvalidCallTarget", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidData", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidEnableSignature", "inputs": [ { - "internalType": "PermissionId", - "name": "permissionId", - "type": "bytes32" + "name": "account", + "type": "address", + "internalType": "address" }, { - "internalType": "address", - "name": "account", - "type": "address" + "name": "hash", + "type": "bytes32", + "internalType": "bytes32" } - ], - "name": "isPermissionEnabled", - "outputs": [ + ] + }, + { + "type": "error", + "name": "InvalidISessionValidator", + "inputs": [ { - "internalType": "bool", - "name": "", - "type": "bool" + "name": "sessionValidator", + "type": "address", + "internalType": "contract ISessionValidator" } - ], - "stateMutability": "view", - "type": "function" + ] + }, + { + "type": "error", + "name": "InvalidMode", + "inputs": [] }, { + "type": "error", + "name": "InvalidPermissionId", "inputs": [ { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "policy", - "type": "address" + "type": "bytes32", + "internalType": "PermissionId" } - ], - "name": "isUserOpPolicyEnabled", - "outputs": [ + ] + }, + { + "type": "error", + "name": "InvalidSelfCall", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidSession", + "inputs": [ { - "internalType": "bool", - "name": "", - "type": "bool" + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" } - ], - "stateMutability": "view", - "type": "function" + ] }, { + "type": "error", + "name": "InvalidSessionKeySignature", "inputs": [ { - "internalType": "address", - "name": "sender", - "type": "address" + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" }, { - "internalType": "bytes32", - "name": "hash", - "type": "bytes32" + "name": "sessionValidator", + "type": "address", + "internalType": "address" }, { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - } - ], - "name": "isValidSignatureWithSender", - "outputs": [ + "name": "account", + "type": "address", + "internalType": "address" + }, { - "internalType": "bytes4", - "name": "result", - "type": "bytes4" + "name": "userOpHash", + "type": "bytes32", + "internalType": "bytes32" } - ], - "stateMutability": "view", - "type": "function" + ] + }, + { + "type": "error", + "name": "InvalidTarget", + "inputs": [] }, { + "type": "error", + "name": "InvalidUserOpSender", "inputs": [ { - "internalType": "bytes", - "name": "data", - "type": "bytes" + "name": "sender", + "type": "address", + "internalType": "address" } - ], - "name": "onInstall", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + ] }, { + "type": "error", + "name": "NoExecutionsInBatch", + "inputs": [] + }, + { + "type": "error", + "name": "NoPoliciesSet", "inputs": [ { - "internalType": "bytes", - "name": "", - "type": "bytes" + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" } - ], - "name": "onUninstall", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + ] + }, + { + "type": "error", + "name": "PartlyEnabledActions", + "inputs": [] }, { + "type": "error", + "name": "PartlyEnabledPolicies", + "inputs": [] + }, + { + "type": "error", + "name": "PaymasterValidationNotEnabled", "inputs": [ { - "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32" + "type": "bytes32", + "internalType": "PermissionId" } - ], - "name": "removeSession", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + ] }, { + "type": "error", + "name": "PolicyViolation", "inputs": [ { - "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32" + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "policy", + "type": "address", + "internalType": "address" } - ], - "name": "revokeEnableSignature", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + ] }, { + "type": "error", + "name": "SignerNotFound", "inputs": [ { - "internalType": "PermissionId", "name": "permissionId", - "type": "bytes32" + "type": "bytes32", + "internalType": "PermissionId" }, { - "internalType": "bool", - "name": "enabled", - "type": "bool" + "name": "account", + "type": "address", + "internalType": "address" } - ], - "name": "setPermit4337Paymaster", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + ] }, { + "type": "error", + "name": "SignerNotFound", "inputs": [ { - "components": [ - { - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "initCode", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "callData", - "type": "bytes" - }, - { - "internalType": "bytes32", - "name": "accountGasLimits", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "preVerificationGas", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "gasFees", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "paymasterAndData", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - } - ], - "internalType": "struct PackedUserOperation", - "name": "userOp", - "type": "tuple" + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" }, { - "internalType": "bytes32", - "name": "userOpHash", - "type": "bytes32" + "name": "account", + "type": "address", + "internalType": "address" } - ], - "name": "validateUserOp", - "outputs": [ + ] + }, + { + "type": "error", + "name": "SmartSessionModuleAlreadyInstalled", + "inputs": [ { - "internalType": "ValidationData", - "name": "vd", - "type": "uint256" + "name": "account", + "type": "address", + "internalType": "address" } - ], - "stateMutability": "nonpayable", - "type": "function" + ] + }, + { + "type": "error", + "name": "UnsupportedCallType", + "inputs": [ + { + "name": "callType", + "type": "bytes1", + "internalType": "CallType" + } + ] + }, + { + "type": "error", + "name": "UnsupportedExecutionType", + "inputs": [] + }, + { + "type": "error", + "name": "UnsupportedPolicy", + "inputs": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "UnsupportedSmartSessionMode", + "inputs": [ + { + "name": "mode", + "type": "uint8", + "internalType": "enum SmartSessionMode" + } + ] } ] as const; diff --git a/packages/core/src/lib/agentic/contracts/abi/v4/universal-rules-policy.ts b/packages/core/src/lib/agentic/contracts/abi/v5/universal-rules-policy.ts similarity index 50% rename from packages/core/src/lib/agentic/contracts/abi/v4/universal-rules-policy.ts rename to packages/core/src/lib/agentic/contracts/abi/v5/universal-rules-policy.ts index 0c9d783c..5b0e2f34 100644 --- a/packages/core/src/lib/agentic/contracts/abi/v4/universal-rules-policy.ts +++ b/packages/core/src/lib/agentic/contracts/abi/v5/universal-rules-policy.ts @@ -1,2156 +1,2156 @@ // GENERATED by packages/core/scripts/agw-local/gen-abi.mjs — do not edit. // Source: packages/core/scripts/agw-local/abis/policy.json -// push-agentic-wallets@e8db74815cfbbf5389593805e464fe8d85f7f735 -// sha256(UniversalRulesPolicy.json) = b40e2a91eaa9c09cbe214621259fb7d12def00d12c756e2fd659eff4e26277c0 +// push-agentic-wallets@2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb +// sha256(UniversalRulesPolicy.json) = c7e3cd5c7f8e47be217c77ebebde4c090903cea7db63024838e434eb6f1fd77b export const UNIVERSAL_RULES_POLICY_ABI = [ { - "inputs": [ + "type": "function", + "name": "SEND_OUTBOUND_SELECTOR", + "inputs": [], + "outputs": [ { - "internalType": "uint256", - "name": "length", - "type": "uint256" + "name": "", + "type": "bytes4", + "internalType": "bytes4" } ], - "name": "AllowListOutOfRange", - "type": "error" + "stateMutability": "view" }, { - "inputs": [ + "type": "function", + "name": "SESSION_ENGINE", + "inputs": [], + "outputs": [ { - "internalType": "bytes32", - "name": "outboundTxId", - "type": "bytes32" + "name": "", + "type": "address", + "internalType": "address" } ], - "name": "AlreadyCredited", - "type": "error" + "stateMutability": "view" }, { - "inputs": [ + "type": "function", + "name": "UNIVERSAL_EXECUTOR_MODULE", + "inputs": [], + "outputs": [ { - "internalType": "ConfigId", - "name": "id", - "type": "bytes32" + "name": "", + "type": "address", + "internalType": "address" } ], - "name": "AlreadyInitialized", - "type": "error" + "stateMutability": "view" }, { - "inputs": [ - { - "internalType": "uint256", - "name": "i", - "type": "uint256" - }, + "type": "function", + "name": "UNIVERSAL_GATEWAY_PC", + "inputs": [], + "outputs": [ { - "internalType": "uint256", - "name": "j", - "type": "uint256" + "name": "", + "type": "address", + "internalType": "address" } ], - "name": "AmbiguousRule", - "type": "error" + "stateMutability": "view" }, { + "type": "function", + "name": "assertSpent", "inputs": [ { - "internalType": "uint256", - "name": "amount", - "type": "uint256" + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" }, { - "internalType": "uint256", - "name": "cap", - "type": "uint256" - } - ], - "name": "AmountExceedsCap", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "AmountExceedsU64", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "actual", - "type": "bytes32" + "name": "account", + "type": "address", + "internalType": "address" }, { - "internalType": "uint256", - "name": "index", - "type": "uint256" + "name": "expectedValueSpent", + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "bytes32", - "name": "expected", - "type": "bytes32" - } - ], - "name": "ArgPinMismatch", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "length", - "type": "uint256" - } - ], - "name": "AssetListOutOfRange", - "type": "error" - }, - { - "inputs": [ + "name": "expectedAmountSpent", + "type": "uint256", + "internalType": "uint256" + }, { - "internalType": "address", - "name": "token", - "type": "address" + "name": "expectedCalls", + "type": "uint32", + "internalType": "uint32" } ], - "name": "AssetNotAllowed", - "type": "error" + "outputs": [], + "stateMutability": "view" }, { + "type": "function", + "name": "assertSpent", "inputs": [ { - "internalType": "address", - "name": "token", - "type": "address" + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" }, { - "internalType": "uint256", - "name": "expected", - "type": "uint256" + "name": "account", + "type": "address", + "internalType": "address" }, { - "internalType": "uint256", - "name": "actual", - "type": "uint256" - } - ], - "name": "AssetSpentMismatch", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "count", - "type": "uint256" + "name": "expectedSpent", + "type": "uint256[]", + "internalType": "uint256[]" } ], - "name": "BatchSizeOutOfRange", - "type": "error" + "outputs": [], + "stateMutability": "view" }, { + "type": "function", + "name": "checkAction", "inputs": [ { - "internalType": "address", - "name": "expected", - "type": "address" + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" }, { - "internalType": "address", - "name": "actual", - "type": "address" - } - ], - "name": "BeneficiaryMismatch", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint32", - "name": "callsUsed", - "type": "uint32" + "name": "account", + "type": "address", + "internalType": "address" }, { - "internalType": "uint32", - "name": "maxCalls", - "type": "uint32" - } - ], - "name": "CallLimitReached", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", "name": "target", - "type": "address" + "type": "address", + "internalType": "address" }, { - "internalType": "bytes4", - "name": "selector", - "type": "bytes4" + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "data", + "type": "bytes", + "internalType": "bytes" } ], - "name": "CallNotAllowed", - "type": "error" - }, - { - "inputs": [ + "outputs": [ { - "internalType": "uint256", - "name": "length", - "type": "uint256" + "name": "", + "type": "uint256", + "internalType": "uint256" } ], - "name": "CalldataTooShort", - "type": "error" + "stateMutability": "nonpayable" }, { + "type": "function", + "name": "creditRevert", "inputs": [ { - "internalType": "uint256", - "name": "actualLength", - "type": "uint256" + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" }, { - "internalType": "uint256", - "name": "needed", - "type": "uint256" - } - ], - "name": "CalldataTooShortForAmount", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "actualLength", - "type": "uint256" + "name": "account", + "type": "address", + "internalType": "address" }, { - "internalType": "uint256", - "name": "index", - "type": "uint256" + "name": "outboundTxId", + "type": "bytes32", + "internalType": "bytes32" }, { - "internalType": "uint256", - "name": "needed", - "type": "uint256" - } - ], - "name": "CalldataTooShortForPin", - "type": "error" - }, - { - "inputs": [ + "name": "token", + "type": "address", + "internalType": "address" + }, { - "internalType": "address", - "name": "caller", - "type": "address" + "name": "amount", + "type": "uint256", + "internalType": "uint256" } ], - "name": "CallerIsNotUEModule", - "type": "error" + "outputs": [], + "stateMutability": "nonpayable" }, { + "type": "function", + "name": "getConfig", "inputs": [ { - "internalType": "uint256", - "name": "accountIndex", - "type": "uint256" + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" }, { - "internalType": "bytes32", "name": "account", - "type": "bytes32" + "type": "address", + "internalType": "address" } ], - "name": "CeaAccountAtUnpinnedIndex", - "type": "error" - }, - { - "inputs": [], - "name": "CeaAccountsMissExpectedCEA", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "declared", - "type": "bytes32" - }, + "outputs": [ { - "internalType": "bytes32", - "name": "assetChain", - "type": "bytes32" + "name": "", + "type": "tuple", + "internalType": "struct Config", + "components": [ + { + "name": "initialized", + "type": "bool", + "internalType": "bool" + }, + { + "name": "validUntil", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "expectedCEA", + "type": "address", + "internalType": "address" + }, + { + "name": "maxGasPerCall", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "assets", + "type": "tuple[]", + "internalType": "struct AssetCapState[]", + "components": [ + { + "name": "token", + "type": "address", + "internalType": "address" + }, + { + "name": "maxPerCall", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxTotal", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "spent", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "allowedCalls", + "type": "tuple[]", + "internalType": "struct AllowedCall[]", + "components": [ + { + "name": "target", + "type": "address", + "internalType": "address" + }, + { + "name": "selector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "beneficiaryOffset", + "type": "uint16", + "internalType": "uint16" + }, + { + "name": "hasBeneficiary", + "type": "bool", + "internalType": "bool" + }, + { + "name": "maxValue", + "type": "uint256", + "internalType": "uint256" + } + ] + } + ] } ], - "name": "ChainMismatch", - "type": "error" + "stateMutability": "view" }, { + "type": "function", + "name": "getMode", "inputs": [ { - "internalType": "uint256", - "name": "rule", - "type": "uint256" + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" }, { - "internalType": "uint8", - "name": "len", - "type": "uint8" + "name": "account", + "type": "address", + "internalType": "address" } ], - "name": "DiscriminatorLenOutOfRange", - "type": "error" - }, - { - "inputs": [ + "outputs": [ { - "internalType": "address", - "name": "token", - "type": "address" + "name": "", + "type": "tuple", + "internalType": "struct ModeSlot", + "components": [ + { + "name": "initialized", + "type": "bool", + "internalType": "bool" + }, + { + "name": "mode", + "type": "uint8", + "internalType": "enum RulesType" + }, + { + "name": "vm", + "type": "uint8", + "internalType": "enum VmFamily" + }, + { + "name": "chainHash", + "type": "bytes32", + "internalType": "bytes32" + } + ] } ], - "name": "DuplicateAsset", - "type": "error" + "stateMutability": "view" }, { + "type": "function", + "name": "getNativeConfig", "inputs": [ { - "internalType": "uint256", - "name": "first", - "type": "uint256" + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" }, { - "internalType": "uint256", - "name": "second", - "type": "uint256" + "name": "account", + "type": "address", + "internalType": "address" } ], - "name": "DuplicateSvmPin", - "type": "error" - }, - { - "inputs": [], - "name": "EmptyChain", - "type": "error" - }, - { - "inputs": [ + "outputs": [ { - "internalType": "address", - "name": "target", - "type": "address" + "name": "", + "type": "tuple", + "internalType": "struct NativeConfig", + "components": [ + { + "name": "initialized", + "type": "bool", + "internalType": "bool" + }, + { + "name": "validUntil", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "target", + "type": "address", + "internalType": "address" + }, + { + "name": "selector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "maxValuePerCall", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxValueTotal", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "valueSpent", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amount", + "type": "tuple", + "internalType": "struct AmountRule", + "components": [ + { + "name": "enabled", + "type": "bool", + "internalType": "bool" + }, + { + "name": "offset", + "type": "uint16", + "internalType": "uint16" + }, + { + "name": "maxPerCall", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxTotal", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "amountSpent", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxCalls", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "callsUsed", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "pins", + "type": "tuple[]", + "internalType": "struct ArgPin[]", + "components": [ + { + "name": "offset", + "type": "uint16", + "internalType": "uint16" + }, + { + "name": "expected", + "type": "bytes32", + "internalType": "bytes32" + } + ] + } + ] } ], - "name": "ForbiddenInnerTarget", - "type": "error" + "stateMutability": "view" }, { + "type": "function", + "name": "getSvmConfig", "inputs": [ { - "internalType": "uint256", - "name": "rule", - "type": "uint256" + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" }, { - "internalType": "bytes32", - "name": "program", - "type": "bytes32" + "name": "account", + "type": "address", + "internalType": "address" } ], - "name": "ForbiddenProgramInAllowList", - "type": "error" - }, - { - "inputs": [ + "outputs": [ { - "internalType": "bytes32", - "name": "program", - "type": "bytes32" + "name": "", + "type": "tuple", + "internalType": "struct SvmConfig", + "components": [ + { + "name": "initialized", + "type": "bool", + "internalType": "bool" + }, + { + "name": "validUntil", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "expectedCEA", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "gatewayProgram", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "maxGasPerCall", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "assets", + "type": "tuple[]", + "internalType": "struct AssetCapState[]", + "components": [ + { + "name": "token", + "type": "address", + "internalType": "address" + }, + { + "name": "maxPerCall", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxTotal", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "spent", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "ceaAccounts", + "type": "bytes32[]", + "internalType": "bytes32[]" + }, + { + "name": "programs", + "type": "tuple[]", + "internalType": "struct AllowedProgram[]", + "components": [ + { + "name": "program", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "discriminator", + "type": "bytes8", + "internalType": "bytes8" + }, + { + "name": "discriminatorLen", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "dataless", + "type": "bool", + "internalType": "bool" + }, + { + "name": "maxAccounts", + "type": "uint8", + "internalType": "uint8" + } + ] + }, + { + "name": "pins", + "type": "tuple[]", + "internalType": "struct SvmAccountPin[]", + "components": [ + { + "name": "ruleIndex", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "accountIndex", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "expected", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "name": "dataPins", + "type": "tuple[]", + "internalType": "struct SvmDataPin[]", + "components": [ + { + "name": "ruleIndex", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "fromEnd", + "type": "bool", + "internalType": "bool" + }, + { + "name": "offset", + "type": "uint16", + "internalType": "uint16" + }, + { + "name": "offsetB", + "type": "uint16", + "internalType": "uint16" + }, + { + "name": "len", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "mode", + "type": "uint8", + "internalType": "enum SvmDataPinMode" + }, + { + "name": "expected", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "num", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "den", + "type": "uint64", + "internalType": "uint64" + } + ] + } + ] } ], - "name": "ForbiddenTargetProgram", - "type": "error" + "stateMutability": "view" }, { + "type": "function", + "name": "initialize", "inputs": [ { - "internalType": "uint256", - "name": "index", - "type": "uint256" + "name": "universalGatewayPC", + "type": "address", + "internalType": "address" }, { - "internalType": "uint256", - "name": "value", - "type": "uint256" + "name": "universalExecutorModule", + "type": "address", + "internalType": "address" }, { - "internalType": "uint256", - "name": "maxValue", - "type": "uint256" + "name": "sessionEngine", + "type": "address", + "internalType": "address" } ], - "name": "InnerValueExceedsAllowance", - "type": "error" + "outputs": [], + "stateMutability": "nonpayable" }, { + "type": "function", + "name": "initializeWithMultiplexer", "inputs": [ { - "internalType": "address", - "name": "asset", - "type": "address" + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "configId", + "type": "bytes32", + "internalType": "ConfigId" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" } ], - "name": "InvalidAsset", - "type": "error" + "outputs": [], + "stateMutability": "nonpayable" }, { + "type": "function", + "name": "isCredited", "inputs": [ { - "internalType": "uint256", - "name": "index", - "type": "uint256" + "name": "outboundTxId", + "type": "bytes32", + "internalType": "bytes32" } ], - "name": "InvalidCeaAccount", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidConfigField", - "type": "error" - }, - { - "inputs": [ + "outputs": [ { - "internalType": "uint48", - "name": "validUntil", - "type": "uint48" + "name": "", + "type": "bool", + "internalType": "bool" } ], - "name": "InvalidExpiry", - "type": "error" + "stateMutability": "view" }, { + "type": "function", + "name": "pushChainHash", "inputs": [], - "name": "InvalidInitialization", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "expected", - "type": "address" - }, + "outputs": [ { - "internalType": "address", - "name": "actual", - "type": "address" + "name": "", + "type": "bytes32", + "internalType": "bytes32" } ], - "name": "InvalidRevertRecipient", - "type": "error" + "stateMutability": "view" }, { + "type": "function", + "name": "supportsInterface", "inputs": [ { - "internalType": "bytes4", - "name": "selector", - "type": "bytes4" + "name": "iid", + "type": "bytes4", + "internalType": "bytes4" } ], - "name": "InvalidSelector", - "type": "error" + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "pure" }, { + "type": "function", + "name": "version", "inputs": [], - "name": "InvalidSvmConfigField", - "type": "error" + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "pure" }, { + "type": "event", + "name": "Initialized", "inputs": [ { - "internalType": "address", - "name": "target", - "type": "address" + "name": "version", + "type": "uint64", + "indexed": false, + "internalType": "uint64" } ], - "name": "InvalidTarget", - "type": "error" - }, - { - "inputs": [], - "name": "MalformedInnerCalldata", - "type": "error" + "anonymous": false }, { + "type": "event", + "name": "NativeCallMetered", "inputs": [ { - "internalType": "uint256", - "name": "length", - "type": "uint256" - } - ], - "name": "MalformedOutboundRequest", - "type": "error" - }, - { - "inputs": [ + "name": "id", + "type": "bytes32", + "indexed": true, + "internalType": "ConfigId" + }, { - "internalType": "uint8", - "name": "code", - "type": "uint8" - } - ], - "name": "MalformedSvmPayload", - "type": "error" - }, - { - "inputs": [ + "name": "multiplexer", + "type": "address", + "indexed": true, + "internalType": "address" + }, { - "internalType": "uint256", - "name": "amount", - "type": "uint256" + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" }, { - "internalType": "uint256", - "name": "cap", - "type": "uint256" + "name": "value", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" } ], - "name": "NativeAmountExceedsCap", - "type": "error" + "anonymous": false }, { + "type": "event", + "name": "OutboundMetered", "inputs": [ { - "internalType": "address", - "name": "target", - "type": "address" + "name": "id", + "type": "bytes32", + "indexed": true, + "internalType": "ConfigId" + }, + { + "name": "multiplexer", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "token", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" } ], - "name": "NativeTargetIsGateway", - "type": "error" - }, - { - "inputs": [], - "name": "NativeTargetZero", - "type": "error" + "anonymous": false }, { + "type": "event", + "name": "PolicySet", "inputs": [ { - "internalType": "ConfigId", "name": "id", - "type": "bytes32" + "type": "bytes32", + "indexed": false, + "internalType": "ConfigId" + }, + { + "name": "multiplexer", + "type": "address", + "indexed": false, + "internalType": "address" }, { - "internalType": "address", "name": "account", - "type": "address" + "type": "address", + "indexed": false, + "internalType": "address" } ], - "name": "NotInitialized", - "type": "error" - }, - { - "inputs": [], - "name": "NotInitializing", - "type": "error" + "anonymous": false }, { + "type": "event", + "name": "RevertCredited", "inputs": [ { - "internalType": "uint256", - "name": "value", - "type": "uint256" + "name": "outboundTxId", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" }, { - "internalType": "uint256", - "name": "cap", - "type": "uint256" + "name": "id", + "type": "bytes32", + "indexed": true, + "internalType": "ConfigId" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "token", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "amountApplied", + "type": "uint256", + "indexed": false, + "internalType": "uint256" } ], - "name": "PCValueExceedsCap", - "type": "error" - }, - { - "inputs": [], - "name": "PayloadNotMulticall", - "type": "error" + "anonymous": false }, { + "type": "event", + "name": "RulesConfigured", "inputs": [ { - "internalType": "ConfigId", "name": "id", - "type": "bytes32" + "type": "bytes32", + "indexed": true, + "internalType": "ConfigId" }, { - "internalType": "address", "name": "multiplexer", - "type": "address" + "type": "address", + "indexed": true, + "internalType": "address" }, { - "internalType": "address", "name": "account", - "type": "address" + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "mode", + "type": "uint8", + "indexed": false, + "internalType": "enum RulesType" + }, + { + "name": "vm", + "type": "uint8", + "indexed": false, + "internalType": "enum VmFamily" + }, + { + "name": "chainHash", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" } ], - "name": "PolicyNotInitialized", - "type": "error" + "anonymous": false }, { + "type": "error", + "name": "AllowListOutOfRange", "inputs": [ { - "internalType": "uint256", "name": "length", - "type": "uint256" + "type": "uint256", + "internalType": "uint256" } - ], - "name": "ProgramListOutOfRange", - "type": "error" + ] }, { + "type": "error", + "name": "AlreadyCredited", "inputs": [ { - "internalType": "bytes32", - "name": "program", - "type": "bytes32" - }, - { - "internalType": "bytes8", - "name": "discriminator", - "type": "bytes8" + "name": "outboundTxId", + "type": "bytes32", + "internalType": "bytes32" } - ], - "name": "ProgramNotAllowed", - "type": "error" - }, - { - "inputs": [], - "name": "RecipientMustBeEmpty", - "type": "error" + ] }, { + "type": "error", + "name": "AlreadyInitialized", "inputs": [ { - "internalType": "uint256", - "name": "length", - "type": "uint256" + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" } - ], - "name": "RecipientNotPubkey", - "type": "error" + ] }, { + "type": "error", + "name": "AmbiguousRule", "inputs": [ { - "internalType": "bytes32", - "name": "recipient", - "type": "bytes32" + "name": "i", + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "bytes32", - "name": "target", - "type": "bytes32" + "name": "j", + "type": "uint256", + "internalType": "uint256" } - ], - "name": "RecipientTargetMismatch", - "type": "error" + ] }, { + "type": "error", + "name": "AmountExceedsCap", "inputs": [ { - "internalType": "uint256", - "name": "rule", - "type": "uint256" + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "cap", + "type": "uint256", + "internalType": "uint256" } - ], - "name": "RuleWithoutPin", - "type": "error" + ] }, { + "type": "error", + "name": "AmountExceedsU64", "inputs": [ { - "internalType": "uint48", - "name": "validUntil", - "type": "uint48" + "name": "amount", + "type": "uint256", + "internalType": "uint256" } - ], - "name": "RulesExpired", - "type": "error" + ] }, { + "type": "error", + "name": "ArgPinMismatch", "inputs": [ { - "internalType": "bytes4", "name": "actual", - "type": "bytes4" + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "index", + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "bytes4", "name": "expected", - "type": "bytes4" + "type": "bytes32", + "internalType": "bytes32" } - ], - "name": "SelectorMismatch", - "type": "error" + ] }, { + "type": "error", + "name": "AssetListOutOfRange", "inputs": [ { - "internalType": "uint256", - "name": "expected", - "type": "uint256" - }, + "name": "length", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "AssetNotAllowed", + "inputs": [ { - "internalType": "uint256", - "name": "actual", - "type": "uint256" + "name": "token", + "type": "address", + "internalType": "address" } - ], - "name": "SpentLengthMismatch", - "type": "error" + ] }, { + "type": "error", + "name": "AssetSpentMismatch", "inputs": [ { - "internalType": "uint256", + "name": "token", + "type": "address", + "internalType": "address" + }, + { "name": "expected", - "type": "uint256" + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "uint256", "name": "actual", - "type": "uint256" + "type": "uint256", + "internalType": "uint256" } - ], - "name": "SpentMismatch", - "type": "error" + ] }, { + "type": "error", + "name": "BatchSizeOutOfRange", "inputs": [ { - "internalType": "uint256", - "name": "pin", - "type": "uint256" - }, - { - "internalType": "uint256", "name": "count", - "type": "uint256" - }, - { - "internalType": "uint8", - "name": "needed", - "type": "uint8" + "type": "uint256", + "internalType": "uint256" } - ], - "name": "SvmAccountCountBelowPin", - "type": "error" + ] }, { + "type": "error", + "name": "BeneficiaryMismatch", "inputs": [ { - "internalType": "uint256", - "name": "count", - "type": "uint256" + "name": "expected", + "type": "address", + "internalType": "address" }, { - "internalType": "uint8", - "name": "expected", - "type": "uint8" + "name": "actual", + "type": "address", + "internalType": "address" } - ], - "name": "SvmAccountCountMismatch", - "type": "error" + ] }, { + "type": "error", + "name": "CallLimitReached", "inputs": [ { - "internalType": "uint256", - "name": "pin", - "type": "uint256" + "name": "callsUsed", + "type": "uint32", + "internalType": "uint32" }, { - "internalType": "uint8", - "name": "accountIndex", - "type": "uint8" - }, + "name": "maxCalls", + "type": "uint32", + "internalType": "uint32" + } + ] + }, + { + "type": "error", + "name": "CallNotAllowed", + "inputs": [ { - "internalType": "bytes32", - "name": "expected", - "type": "bytes32" + "name": "target", + "type": "address", + "internalType": "address" }, { - "internalType": "bytes32", - "name": "actual", - "type": "bytes32" + "name": "selector", + "type": "bytes4", + "internalType": "bytes4" } - ], - "name": "SvmAccountPinMismatch", - "type": "error" + ] }, { + "type": "error", + "name": "CalldataTooShort", "inputs": [ { - "internalType": "uint256", - "name": "count", - "type": "uint256" + "name": "length", + "type": "uint256", + "internalType": "uint256" } - ], - "name": "SvmAccountsOutOfRange", - "type": "error" + ] }, { + "type": "error", + "name": "CalldataTooShortForAmount", "inputs": [ { - "internalType": "uint256", - "name": "pin", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "actual", - "type": "uint256" + "name": "actualLength", + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "uint256", - "name": "ceiling", - "type": "uint256" + "name": "needed", + "type": "uint256", + "internalType": "uint256" } - ], - "name": "SvmDataCeilingExceeded", - "type": "error" + ] }, { + "type": "error", + "name": "CalldataTooShortForPin", "inputs": [ { - "internalType": "uint256", - "name": "pin", - "type": "uint256" + "name": "actualLength", + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "uint256", - "name": "actual", - "type": "uint256" + "name": "index", + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "uint256", - "name": "floor", - "type": "uint256" + "name": "needed", + "type": "uint256", + "internalType": "uint256" } - ], - "name": "SvmDataFloorNotMet", - "type": "error" + ] }, { + "type": "error", + "name": "CallerIsNotUEModule", "inputs": [ { - "internalType": "uint256", - "name": "pin", - "type": "uint256" + "name": "caller", + "type": "address", + "internalType": "address" } - ], - "name": "SvmDataPinInvalid", - "type": "error" + ] }, { + "type": "error", + "name": "CeaAccountAtUnpinnedIndex", "inputs": [ { - "internalType": "uint256", - "name": "pin", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "expected", - "type": "bytes32" + "name": "accountIndex", + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "bytes32", - "name": "actual", - "type": "bytes32" + "name": "account", + "type": "bytes32", + "internalType": "bytes32" } - ], - "name": "SvmDataPinMismatch", - "type": "error" + ] + }, + { + "type": "error", + "name": "CeaAccountsMissExpectedCEA", + "inputs": [] }, { + "type": "error", + "name": "ChainMismatch", "inputs": [ { - "internalType": "uint256", - "name": "pin", - "type": "uint256" + "name": "declared", + "type": "bytes32", + "internalType": "bytes32" }, { - "internalType": "uint256", - "name": "a", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "b", - "type": "uint256" - }, + "name": "assetChain", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "DiscriminatorLenOutOfRange", + "inputs": [ { - "internalType": "uint64", - "name": "num", - "type": "uint64" + "name": "rule", + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "uint64", - "name": "den", - "type": "uint64" + "name": "len", + "type": "uint8", + "internalType": "uint8" } - ], - "name": "SvmDataRatioNotMet", - "type": "error" + ] }, { + "type": "error", + "name": "DuplicateAsset", "inputs": [ { - "internalType": "uint256", - "name": "pin", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "ixLen", - "type": "uint256" + "name": "token", + "type": "address", + "internalType": "address" } - ], - "name": "SvmDataTooShortForPin", - "type": "error" + ] }, { + "type": "error", + "name": "DuplicateSvmPin", "inputs": [ { - "internalType": "uint8", - "name": "instructionId", - "type": "uint8" + "name": "first", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "second", + "type": "uint256", + "internalType": "uint256" } - ], - "name": "SvmInstructionNotExecute", - "type": "error" + ] + }, + { + "type": "error", + "name": "EmptyChain", + "inputs": [] }, { + "type": "error", + "name": "ForbiddenInnerTarget", "inputs": [ { - "internalType": "uint256", - "name": "length", - "type": "uint256" + "name": "target", + "type": "address", + "internalType": "address" } - ], - "name": "SvmIxDataTooLong", - "type": "error" + ] }, { + "type": "error", + "name": "ForbiddenProgramInAllowList", "inputs": [ { - "internalType": "uint256", "name": "rule", - "type": "uint256" + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "uint8", - "name": "maxAccounts", - "type": "uint8" + "name": "program", + "type": "bytes32", + "internalType": "bytes32" } - ], - "name": "SvmMaxAccountsOutOfRange", - "type": "error" + ] }, { - "inputs": [], - "name": "SvmPayloadEmpty", - "type": "error" + "type": "error", + "name": "ForbiddenTargetProgram", + "inputs": [ + { + "name": "program", + "type": "bytes32", + "internalType": "bytes32" + } + ] }, { + "type": "error", + "name": "InnerValueExceedsAllowance", "inputs": [ { - "internalType": "uint256", - "name": "pin", - "type": "uint256" + "name": "index", + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "uint8", - "name": "accountIndex", - "type": "uint8" + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxValue", + "type": "uint256", + "internalType": "uint256" } - ], - "name": "SvmPinIndexOutOfRange", - "type": "error" + ] + }, + { + "type": "error", + "name": "InvalidAsset", + "inputs": [ + { + "name": "asset", + "type": "address", + "internalType": "address" + } + ] }, { + "type": "error", + "name": "InvalidCeaAccount", "inputs": [ { - "internalType": "uint256", - "name": "pin", - "type": "uint256" - }, + "name": "index", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "InvalidConfigField", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidExpiry", + "inputs": [ { - "internalType": "uint8", - "name": "rule", - "type": "uint8" + "name": "validUntil", + "type": "uint48", + "internalType": "uint48" } - ], - "name": "SvmPinRuleOutOfRange", - "type": "error" + ] + }, + { + "type": "error", + "name": "InvalidInitialization", + "inputs": [] }, { + "type": "error", + "name": "InvalidRevertRecipient", "inputs": [ { - "internalType": "address", - "name": "actual", - "type": "address" + "name": "expected", + "type": "address", + "internalType": "address" }, { - "internalType": "address", - "name": "expected", - "type": "address" + "name": "actual", + "type": "address", + "internalType": "address" } - ], - "name": "TargetMismatch", - "type": "error" + ] }, { + "type": "error", + "name": "InvalidSelector", "inputs": [ { - "internalType": "uint256", - "name": "count", - "type": "uint256" + "name": "selector", + "type": "bytes4", + "internalType": "bytes4" } - ], - "name": "TooManyCeaAccounts", - "type": "error" + ] + }, + { + "type": "error", + "name": "InvalidSvmConfigField", + "inputs": [] }, { + "type": "error", + "name": "InvalidTarget", "inputs": [ { - "internalType": "uint256", - "name": "count", - "type": "uint256" + "name": "target", + "type": "address", + "internalType": "address" } - ], - "name": "TooManyPins", - "type": "error" + ] + }, + { + "type": "error", + "name": "MalformedInnerCalldata", + "inputs": [] }, { + "type": "error", + "name": "MalformedOutboundRequest", "inputs": [ { - "internalType": "uint256", - "name": "count", - "type": "uint256" + "name": "length", + "type": "uint256", + "internalType": "uint256" } - ], - "name": "TooManySvmDataPins", - "type": "error" + ] }, { + "type": "error", + "name": "MalformedSvmPayload", "inputs": [ { - "internalType": "uint256", - "name": "count", - "type": "uint256" + "name": "code", + "type": "uint8", + "internalType": "uint8" } - ], - "name": "TooManySvmPins", - "type": "error" + ] }, { + "type": "error", + "name": "NativeAmountExceedsCap", "inputs": [ { - "internalType": "uint256", - "name": "newSpent", - "type": "uint256" + "name": "amount", + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "uint256", "name": "cap", - "type": "uint256" + "type": "uint256", + "internalType": "uint256" } - ], - "name": "TotalNativeAmountExceeded", - "type": "error" + ] + }, + { + "type": "error", + "name": "NativeTargetIsGateway", + "inputs": [ + { + "name": "target", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "NativeTargetZero", + "inputs": [] }, { + "type": "error", + "name": "NotInitialized", "inputs": [ { - "internalType": "uint256", - "name": "wouldBeTotal", - "type": "uint256" + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" }, { - "internalType": "uint256", - "name": "cap", - "type": "uint256" + "name": "account", + "type": "address", + "internalType": "address" } - ], - "name": "TotalSpendCapExceeded", - "type": "error" + ] }, { + "type": "error", + "name": "NotInitializing", + "inputs": [] + }, + { + "type": "error", + "name": "PCValueExceedsCap", "inputs": [ { - "internalType": "uint256", - "name": "newSpent", - "type": "uint256" + "name": "value", + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "uint256", "name": "cap", - "type": "uint256" + "type": "uint256", + "internalType": "uint256" } - ], - "name": "TotalValueExceeded", - "type": "error" + ] }, { - "inputs": [], - "name": "UncappedGasSwapRejected", - "type": "error" + "type": "error", + "name": "PayloadNotMulticall", + "inputs": [] }, { + "type": "error", + "name": "PolicyNotInitialized", "inputs": [ { - "internalType": "uint256", - "name": "version", - "type": "uint256" + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" + }, + { + "name": "multiplexer", + "type": "address", + "internalType": "address" + }, + { + "name": "account", + "type": "address", + "internalType": "address" } - ], - "name": "UnsupportedEnvelopeVersion", - "type": "error" + ] }, { + "type": "error", + "name": "ProgramListOutOfRange", "inputs": [ { - "internalType": "bytes32", - "name": "chainHash", - "type": "bytes32" + "name": "length", + "type": "uint256", + "internalType": "uint256" } - ], - "name": "UnsupportedNamespace", - "type": "error" + ] }, { + "type": "error", + "name": "ProgramNotAllowed", "inputs": [ { - "internalType": "uint256", - "name": "value", - "type": "uint256" + "name": "program", + "type": "bytes32", + "internalType": "bytes32" }, { - "internalType": "uint256", - "name": "cap", - "type": "uint256" + "name": "discriminator", + "type": "bytes8", + "internalType": "bytes8" } - ], - "name": "ValueExceedsCap", - "type": "error" + ] + }, + { + "type": "error", + "name": "RecipientMustBeEmpty", + "inputs": [] }, { + "type": "error", + "name": "RecipientNotPubkey", "inputs": [ { - "internalType": "uint256", "name": "length", - "type": "uint256" + "type": "uint256", + "internalType": "uint256" } - ], - "name": "ValueOnlyCalldataNotEmpty", - "type": "error" + ] }, { - "inputs": [], - "name": "ValueOnlyWithAmountRule", - "type": "error" + "type": "error", + "name": "RecipientTargetMismatch", + "inputs": [ + { + "name": "recipient", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "target", + "type": "bytes32", + "internalType": "bytes32" + } + ] }, { - "inputs": [], - "name": "ValueOnlyWithPins", - "type": "error" + "type": "error", + "name": "RuleWithoutPin", + "inputs": [ + { + "name": "rule", + "type": "uint256", + "internalType": "uint256" + } + ] }, { + "type": "error", + "name": "RulesExpired", "inputs": [ { - "internalType": "enum RulesType", - "name": "actual", - "type": "uint8" + "name": "validUntil", + "type": "uint48", + "internalType": "uint48" } - ], - "name": "WrongModeForCall", - "type": "error" + ] }, { + "type": "error", + "name": "SelectorMismatch", "inputs": [ { - "internalType": "enum VmFamily", "name": "actual", - "type": "uint8" + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "expected", + "type": "bytes4", + "internalType": "bytes4" } - ], - "name": "WrongVmForCall", - "type": "error" - }, - { - "inputs": [], - "name": "ZeroAddress", - "type": "error" + ] }, { - "anonymous": false, + "type": "error", + "name": "SpentLengthMismatch", "inputs": [ { - "indexed": false, - "internalType": "uint64", - "name": "version", - "type": "uint64" + "name": "expected", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "actual", + "type": "uint256", + "internalType": "uint256" } - ], - "name": "Initialized", - "type": "event" + ] }, { - "anonymous": false, + "type": "error", + "name": "SpentMismatch", "inputs": [ { - "indexed": true, - "internalType": "ConfigId", - "name": "id", - "type": "bytes32" + "name": "expected", + "type": "uint256", + "internalType": "uint256" }, { - "indexed": true, - "internalType": "address", - "name": "multiplexer", - "type": "address" - }, + "name": "actual", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "SvmAccountCountBelowPin", + "inputs": [ { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" + "name": "pin", + "type": "uint256", + "internalType": "uint256" }, { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" + "name": "count", + "type": "uint256", + "internalType": "uint256" }, { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" + "name": "needed", + "type": "uint8", + "internalType": "uint8" } - ], - "name": "NativeCallMetered", - "type": "event" + ] }, { - "anonymous": false, + "type": "error", + "name": "SvmAccountCountMismatch", "inputs": [ { - "indexed": true, - "internalType": "ConfigId", - "name": "id", - "type": "bytes32" + "name": "count", + "type": "uint256", + "internalType": "uint256" }, { - "indexed": true, - "internalType": "address", - "name": "multiplexer", - "type": "address" - }, + "name": "expected", + "type": "uint8", + "internalType": "uint8" + } + ] + }, + { + "type": "error", + "name": "SvmAccountPinMismatch", + "inputs": [ { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" + "name": "pin", + "type": "uint256", + "internalType": "uint256" }, { - "indexed": false, - "internalType": "address", - "name": "token", - "type": "address" + "name": "accountIndex", + "type": "uint8", + "internalType": "uint8" }, { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" + "name": "expected", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "actual", + "type": "bytes32", + "internalType": "bytes32" } - ], - "name": "OutboundMetered", - "type": "event" + ] }, { - "anonymous": false, + "type": "error", + "name": "SvmAccountsOutOfRange", "inputs": [ { - "indexed": false, - "internalType": "ConfigId", - "name": "id", - "type": "bytes32" + "name": "count", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "SvmDataCeilingExceeded", + "inputs": [ + { + "name": "pin", + "type": "uint256", + "internalType": "uint256" }, { - "indexed": false, - "internalType": "address", - "name": "multiplexer", - "type": "address" + "name": "actual", + "type": "uint256", + "internalType": "uint256" }, { - "indexed": false, - "internalType": "address", - "name": "account", - "type": "address" + "name": "ceiling", + "type": "uint256", + "internalType": "uint256" } - ], - "name": "PolicySet", - "type": "event" + ] }, { - "anonymous": false, + "type": "error", + "name": "SvmDataFloorNotMet", "inputs": [ { - "indexed": true, - "internalType": "bytes32", - "name": "outboundTxId", - "type": "bytes32" + "name": "pin", + "type": "uint256", + "internalType": "uint256" }, { - "indexed": true, - "internalType": "ConfigId", - "name": "id", - "type": "bytes32" + "name": "actual", + "type": "uint256", + "internalType": "uint256" }, { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" + "name": "floor", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "SvmDataPinInvalid", + "inputs": [ + { + "name": "pin", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "SvmDataPinMismatch", + "inputs": [ + { + "name": "pin", + "type": "uint256", + "internalType": "uint256" }, { - "indexed": false, - "internalType": "address", - "name": "token", - "type": "address" + "name": "expected", + "type": "bytes32", + "internalType": "bytes32" }, { - "indexed": false, - "internalType": "uint256", - "name": "amountApplied", - "type": "uint256" + "name": "actual", + "type": "bytes32", + "internalType": "bytes32" } - ], - "name": "RevertCredited", - "type": "event" + ] }, { - "anonymous": false, + "type": "error", + "name": "SvmDataRatioNotMet", "inputs": [ { - "indexed": true, - "internalType": "ConfigId", - "name": "id", - "type": "bytes32" - }, - { - "indexed": true, - "internalType": "address", - "name": "multiplexer", - "type": "address" + "name": "pin", + "type": "uint256", + "internalType": "uint256" }, { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" + "name": "a", + "type": "uint256", + "internalType": "uint256" }, { - "indexed": false, - "internalType": "enum RulesType", - "name": "mode", - "type": "uint8" + "name": "b", + "type": "uint256", + "internalType": "uint256" }, { - "indexed": false, - "internalType": "enum VmFamily", - "name": "vm", - "type": "uint8" + "name": "num", + "type": "uint64", + "internalType": "uint64" }, { - "indexed": false, - "internalType": "bytes32", - "name": "chainHash", - "type": "bytes32" + "name": "den", + "type": "uint64", + "internalType": "uint64" } - ], - "name": "RulesConfigured", - "type": "event" + ] }, { - "inputs": [], - "name": "SEND_OUTBOUND_SELECTOR", - "outputs": [ + "type": "error", + "name": "SvmDataTooShortForPin", + "inputs": [ { - "internalType": "bytes4", - "name": "", - "type": "bytes4" + "name": "pin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "ixLen", + "type": "uint256", + "internalType": "uint256" } - ], - "stateMutability": "view", - "type": "function" + ] }, { - "inputs": [], - "name": "SESSION_ENGINE", - "outputs": [ + "type": "error", + "name": "SvmInstructionNotExecute", + "inputs": [ { - "internalType": "address", - "name": "", - "type": "address" + "name": "instructionId", + "type": "uint8", + "internalType": "uint8" } - ], - "stateMutability": "view", - "type": "function" + ] }, { - "inputs": [], - "name": "UNIVERSAL_EXECUTOR_MODULE", - "outputs": [ + "type": "error", + "name": "SvmIxDataTooLong", + "inputs": [ { - "internalType": "address", - "name": "", - "type": "address" + "name": "length", + "type": "uint256", + "internalType": "uint256" } - ], - "stateMutability": "view", - "type": "function" + ] }, { - "inputs": [], - "name": "UNIVERSAL_GATEWAY_PC", - "outputs": [ + "type": "error", + "name": "SvmMaxAccountsOutOfRange", + "inputs": [ { - "internalType": "address", - "name": "", - "type": "address" + "name": "rule", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxAccounts", + "type": "uint8", + "internalType": "uint8" } - ], - "stateMutability": "view", - "type": "function" + ] + }, + { + "type": "error", + "name": "SvmPayloadEmpty", + "inputs": [] }, { + "type": "error", + "name": "SvmPinIndexOutOfRange", "inputs": [ { - "internalType": "ConfigId", - "name": "id", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "account", - "type": "address" + "name": "pin", + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "uint256", - "name": "expectedValueSpent", - "type": "uint256" - }, + "name": "accountIndex", + "type": "uint8", + "internalType": "uint8" + } + ] + }, + { + "type": "error", + "name": "SvmPinRuleOutOfRange", + "inputs": [ { - "internalType": "uint256", - "name": "expectedAmountSpent", - "type": "uint256" + "name": "pin", + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "uint32", - "name": "expectedCalls", - "type": "uint32" + "name": "rule", + "type": "uint8", + "internalType": "uint8" } - ], - "name": "assertSpent", - "outputs": [], - "stateMutability": "view", - "type": "function" + ] }, { + "type": "error", + "name": "TargetMismatch", "inputs": [ { - "internalType": "ConfigId", - "name": "id", - "type": "bytes32" + "name": "actual", + "type": "address", + "internalType": "address" }, { - "internalType": "address", - "name": "account", - "type": "address" - }, + "name": "expected", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "TooManyCeaAccounts", + "inputs": [ { - "internalType": "uint256[]", - "name": "expectedSpent", - "type": "uint256[]" + "name": "count", + "type": "uint256", + "internalType": "uint256" } - ], - "name": "assertSpent", - "outputs": [], - "stateMutability": "view", - "type": "function" + ] }, { + "type": "error", + "name": "TooManyPins", "inputs": [ { - "internalType": "ConfigId", - "name": "id", - "type": "bytes32" - }, + "name": "count", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "TooManySvmDataPins", + "inputs": [ { - "internalType": "address", - "name": "account", - "type": "address" - }, + "name": "count", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "TooManySvmPins", + "inputs": [ { - "internalType": "address", - "name": "target", - "type": "address" - }, + "name": "count", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "TotalNativeAmountExceeded", + "inputs": [ { - "internalType": "uint256", - "name": "value", - "type": "uint256" + "name": "newSpent", + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "checkAction", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" + "name": "cap", + "type": "uint256", + "internalType": "uint256" } - ], - "stateMutability": "nonpayable", - "type": "function" + ] }, { + "type": "error", + "name": "TotalSpendCapExceeded", "inputs": [ { - "internalType": "ConfigId", - "name": "id", - "type": "bytes32" + "name": "wouldBeTotal", + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "address", - "name": "account", - "type": "address" - }, + "name": "cap", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "TotalValueExceeded", + "inputs": [ { - "internalType": "bytes32", - "name": "outboundTxId", - "type": "bytes32" + "name": "newSpent", + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "address", - "name": "token", - "type": "address" - }, + "name": "cap", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "UncappedGasSwapRejected", + "inputs": [] + }, + { + "type": "error", + "name": "UnsupportedEnvelopeVersion", + "inputs": [ { - "internalType": "uint256", - "name": "amount", - "type": "uint256" + "name": "version", + "type": "uint256", + "internalType": "uint256" } - ], - "name": "creditRevert", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + ] }, { + "type": "error", + "name": "UnsupportedNamespace", "inputs": [ { - "internalType": "ConfigId", - "name": "id", - "type": "bytes32" + "name": "chainHash", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "ValueExceedsCap", + "inputs": [ + { + "name": "value", + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "address", - "name": "account", - "type": "address" + "name": "cap", + "type": "uint256", + "internalType": "uint256" } - ], - "name": "getConfig", - "outputs": [ + ] + }, + { + "type": "error", + "name": "ValueOnlyCalldataNotEmpty", + "inputs": [ { - "components": [ - { - "internalType": "bool", - "name": "initialized", - "type": "bool" - }, - { - "internalType": "uint48", - "name": "validUntil", - "type": "uint48" - }, - { - "internalType": "address", - "name": "expectedCEA", - "type": "address" - }, - { - "internalType": "uint256", - "name": "maxGasPerCall", - "type": "uint256" - }, - { - "components": [ - { - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "internalType": "uint256", - "name": "maxPerCall", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "maxTotal", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "spent", - "type": "uint256" - } - ], - "internalType": "struct AssetCapState[]", - "name": "assets", - "type": "tuple[]" - }, - { - "components": [ - { - "internalType": "address", - "name": "target", - "type": "address" - }, - { - "internalType": "bytes4", - "name": "selector", - "type": "bytes4" - }, - { - "internalType": "uint16", - "name": "beneficiaryOffset", - "type": "uint16" - }, - { - "internalType": "bool", - "name": "hasBeneficiary", - "type": "bool" - }, - { - "internalType": "uint256", - "name": "maxValue", - "type": "uint256" - } - ], - "internalType": "struct AllowedCall[]", - "name": "allowedCalls", - "type": "tuple[]" - } - ], - "internalType": "struct Config", - "name": "", - "type": "tuple" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "ConfigId", - "name": "id", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getMode", - "outputs": [ - { - "components": [ - { - "internalType": "bool", - "name": "initialized", - "type": "bool" - }, - { - "internalType": "enum RulesType", - "name": "mode", - "type": "uint8" - }, - { - "internalType": "enum VmFamily", - "name": "vm", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "chainHash", - "type": "bytes32" - } - ], - "internalType": "struct ModeSlot", - "name": "", - "type": "tuple" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "ConfigId", - "name": "id", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getNativeConfig", - "outputs": [ - { - "components": [ - { - "internalType": "bool", - "name": "initialized", - "type": "bool" - }, - { - "internalType": "uint48", - "name": "validUntil", - "type": "uint48" - }, - { - "internalType": "address", - "name": "target", - "type": "address" - }, - { - "internalType": "bytes4", - "name": "selector", - "type": "bytes4" - }, - { - "internalType": "uint256", - "name": "maxValuePerCall", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "maxValueTotal", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "valueSpent", - "type": "uint256" - }, - { - "components": [ - { - "internalType": "bool", - "name": "enabled", - "type": "bool" - }, - { - "internalType": "uint16", - "name": "offset", - "type": "uint16" - }, - { - "internalType": "uint256", - "name": "maxPerCall", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "maxTotal", - "type": "uint256" - } - ], - "internalType": "struct AmountRule", - "name": "amount", - "type": "tuple" - }, - { - "internalType": "uint256", - "name": "amountSpent", - "type": "uint256" - }, - { - "internalType": "uint32", - "name": "maxCalls", - "type": "uint32" - }, - { - "internalType": "uint32", - "name": "callsUsed", - "type": "uint32" - }, - { - "components": [ - { - "internalType": "uint16", - "name": "offset", - "type": "uint16" - }, - { - "internalType": "bytes32", - "name": "expected", - "type": "bytes32" - } - ], - "internalType": "struct ArgPin[]", - "name": "pins", - "type": "tuple[]" - } - ], - "internalType": "struct NativeConfig", - "name": "", - "type": "tuple" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "ConfigId", - "name": "id", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getSvmConfig", - "outputs": [ - { - "components": [ - { - "internalType": "bool", - "name": "initialized", - "type": "bool" - }, - { - "internalType": "uint48", - "name": "validUntil", - "type": "uint48" - }, - { - "internalType": "bytes32", - "name": "expectedCEA", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "gatewayProgram", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "maxGasPerCall", - "type": "uint256" - }, - { - "components": [ - { - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "internalType": "uint256", - "name": "maxPerCall", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "maxTotal", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "spent", - "type": "uint256" - } - ], - "internalType": "struct AssetCapState[]", - "name": "assets", - "type": "tuple[]" - }, - { - "internalType": "bytes32[]", - "name": "ceaAccounts", - "type": "bytes32[]" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "program", - "type": "bytes32" - }, - { - "internalType": "bytes8", - "name": "discriminator", - "type": "bytes8" - }, - { - "internalType": "uint8", - "name": "discriminatorLen", - "type": "uint8" - }, - { - "internalType": "bool", - "name": "dataless", - "type": "bool" - }, - { - "internalType": "uint8", - "name": "maxAccounts", - "type": "uint8" - } - ], - "internalType": "struct AllowedProgram[]", - "name": "programs", - "type": "tuple[]" - }, - { - "components": [ - { - "internalType": "uint8", - "name": "ruleIndex", - "type": "uint8" - }, - { - "internalType": "uint8", - "name": "accountIndex", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "expected", - "type": "bytes32" - } - ], - "internalType": "struct SvmAccountPin[]", - "name": "pins", - "type": "tuple[]" - }, - { - "components": [ - { - "internalType": "uint8", - "name": "ruleIndex", - "type": "uint8" - }, - { - "internalType": "bool", - "name": "fromEnd", - "type": "bool" - }, - { - "internalType": "uint16", - "name": "offset", - "type": "uint16" - }, - { - "internalType": "uint16", - "name": "offsetB", - "type": "uint16" - }, - { - "internalType": "uint8", - "name": "len", - "type": "uint8" - }, - { - "internalType": "enum SvmDataPinMode", - "name": "mode", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "expected", - "type": "bytes32" - }, - { - "internalType": "uint64", - "name": "num", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "den", - "type": "uint64" - } - ], - "internalType": "struct SvmDataPin[]", - "name": "dataPins", - "type": "tuple[]" - } - ], - "internalType": "struct SvmConfig", - "name": "", - "type": "tuple" + "name": "length", + "type": "uint256", + "internalType": "uint256" } - ], - "stateMutability": "view", - "type": "function" + ] }, { - "inputs": [ - { - "internalType": "address", - "name": "universalGatewayPC", - "type": "address" - }, - { - "internalType": "address", - "name": "universalExecutorModule", - "type": "address" - }, - { - "internalType": "address", - "name": "sessionEngine", - "type": "address" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "type": "error", + "name": "ValueOnlyWithAmountRule", + "inputs": [] }, { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "ConfigId", - "name": "configId", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "initData", - "type": "bytes" - } - ], - "name": "initializeWithMultiplexer", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "type": "error", + "name": "ValueOnlyWithPins", + "inputs": [] }, { + "type": "error", + "name": "WrongModeForCall", "inputs": [ { - "internalType": "bytes32", - "name": "outboundTxId", - "type": "bytes32" - } - ], - "name": "isCredited", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "pushChainHash", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" + "name": "actual", + "type": "uint8", + "internalType": "enum RulesType" } - ], - "stateMutability": "view", - "type": "function" + ] }, { + "type": "error", + "name": "WrongVmForCall", "inputs": [ { - "internalType": "bytes4", - "name": "iid", - "type": "bytes4" - } - ], - "name": "supportsInterface", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" + "name": "actual", + "type": "uint8", + "internalType": "enum VmFamily" } - ], - "stateMutability": "pure", - "type": "function" + ] }, { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "pure", - "type": "function" + "type": "error", + "name": "ZeroAddress", + "inputs": [] } ] as const; diff --git a/packages/core/src/lib/agentic/contracts/donut-v4.ts b/packages/core/src/lib/agentic/contracts/donut-v4.ts deleted file mode 100644 index 63a75170..00000000 --- a/packages/core/src/lib/agentic/contracts/donut-v4.ts +++ /dev/null @@ -1,13 +0,0 @@ -import type { Address } from 'viem'; - -/** Source e8db748; code/proxy wiring checked at Donut block 23931055. */ -export const V4_SOURCE_COMMIT = 'e8db74815cfbbf5389593805e464fe8d85f7f735'; -export const DONUT_V4_START_BLOCK = BigInt(23923806); -export const DONUT_V4_ADDRESSES = { - factory: '0xaF88D0FD947afAe7bBb8F34e8417DCfc165e1aaF', - walletImplementation: '0x96D69ec7e6cDdaD414e656B5c9DCA24587DF713c', - sessionEngine: '0x165A5E6782f39D30B38c7D97e1303e4CB2aD102a', - rulesPolicy: '0x603E7f0aF6e1aAFf46DDfb28b1e99364f8BC59af', - sessionValidator: '0x068EE2388475A98EE1f5a434C58bFF3444fffFe6', - gateway: '0x00000000000000000000000000000000000000C1', -} as const satisfies Record; diff --git a/packages/core/src/lib/agentic/contracts/donut-v5.ts b/packages/core/src/lib/agentic/contracts/donut-v5.ts new file mode 100644 index 00000000..c75425ea --- /dev/null +++ b/packages/core/src/lib/agentic/contracts/donut-v5.ts @@ -0,0 +1,13 @@ +import type { Address } from 'viem'; + +/** Source 2e61e13; code/proxy wiring checked at Donut block 23991912. */ +export const V5_SOURCE_COMMIT = '2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb'; +export const DONUT_V5_START_BLOCK = BigInt(23989983); +export const DONUT_V5_ADDRESSES = { + factory: '0x8137F96A50EBF41d904e3678c84c391a0D1BCcc5', + walletImplementation: '0x4D459Da499C14548aa16c46c57fD92880A88EBb4', + sessionEngine: '0x165A5E6782f39D30B38c7D97e1303e4CB2aD102a', + rulesPolicy: '0x603E7f0aF6e1aAFf46DDfb28b1e99364f8BC59af', + sessionValidator: '0x068EE2388475A98EE1f5a434C58bFF3444fffFe6', + gateway: '0x00000000000000000000000000000000000000C1', +} as const satisfies Record; diff --git a/packages/core/src/lib/agentic/contracts/prc20-metadata.ts b/packages/core/src/lib/agentic/contracts/prc20-metadata.ts index 9f29dc62..332bb0b6 100644 --- a/packages/core/src/lib/agentic/contracts/prc20-metadata.ts +++ b/packages/core/src/lib/agentic/contracts/prc20-metadata.ts @@ -4,10 +4,15 @@ import { parseAbi, zeroAddress, type Address, + type Hex, } from 'viem'; import { UNIVERSAL_CORE_EVM } from '../../constants/abi/prc20.evm'; import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; import type { Snapshot } from '../reads/snapshot'; +import { CHAIN, PUSH_NETWORK } from '../../constants/enums'; +import { MOVEABLE_TOKENS } from '../../constants/tokens'; +import { getPRC20Address } from '../../universal/prc20-address'; +import { svmKey } from '../codec/svm-accounts'; export const PRC20_SOURCE_ABI = parseAbi([ 'function SOURCE_CHAIN_NAMESPACE() view returns (string)', @@ -16,6 +21,65 @@ export const PRC20_SOURCE_ABI = parseAbi([ const NATIVE_SOURCE_ABI = parseAbi([ 'function SOURCE_TOKEN_ADDRESS() view returns (address)', ]); +const SVM_SOURCE_WORD_ABI = parseAbi([ + 'function SOURCE_TOKEN_ADDRESS() view returns (bytes32)', +]); + +/** Resolve the SVM source mint from metadata or the current chain-specific token registry. */ +export async function readSvmSourceToken( + snap: Snapshot, + token: Address, + chain: string, + network: PUSH_NETWORK = PUSH_NETWORK.TESTNET_DONUT +): Promise { + let source: string; + try { + source = await snap.read( + token, + PRC20_SOURCE_ABI, + 'SOURCE_TOKEN_ADDRESS' + ); + } catch (cause) { + try { + source = await snap.read( + token, + SVM_SOURCE_WORD_ABI, + 'SOURCE_TOKEN_ADDRESS' + ); + } catch { + throw cause; + } + } + const zeroKey = `0x${'00'.repeat(32)}` as Hex; + if ( + source === '' || + source.toLowerCase() === zeroAddress || + source.toLowerCase() === zeroKey + ) { + if (getAddress(token) === (await readGasPrc20(snap, chain))) return zeroKey; + // Current Donut SVM synthetic metadata exposes a zero word for SPL assets. + // Ordinary Route 2 already resolves these through the same token registry. + // Match both full origin chain and exact PRC20; never infer an unknown mint. + for (const asset of MOVEABLE_TOKENS[chain as CHAIN] ?? []) { + if (asset.mechanism === 'native') continue; + try { + const resolved = getPRC20Address( + { chain, address: asset.address }, + { network } + ); + if (getAddress(resolved.address) === getAddress(token)) + return svmKey(asset.address); + } catch { + // A token without a deployment in this network is not a candidate. + } + } + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + `source mint unavailable for PRC20 ${token} on ${chain}; no registered mapping matches` + ); + } + return svmKey(source); +} export const CORE_ADDRESS = '0x00000000000000000000000000000000000000C0' as Address; export async function readGasPrc20( diff --git a/packages/core/src/lib/agentic/contracts/v4.ts b/packages/core/src/lib/agentic/contracts/v5.ts similarity index 93% rename from packages/core/src/lib/agentic/contracts/v4.ts rename to packages/core/src/lib/agentic/contracts/v5.ts index 7d6dc094..444dc5de 100644 --- a/packages/core/src/lib/agentic/contracts/v4.ts +++ b/packages/core/src/lib/agentic/contracts/v5.ts @@ -18,7 +18,7 @@ import { AGW_FACTORY_ABI, SMART_SESSION_ABI, UNIVERSAL_RULES_POLICY_ABI, -} from './abi/v4'; +} from './abi/v5'; import type { SessionWire } from '../codec/session'; import type { CheckpointKind } from '../agentic.types'; import type { NativeTermsWire } from '../codec/native'; @@ -26,7 +26,7 @@ import type { UniversalTermsWire } from '../codec/universal-terms'; import type { SvmTermsWire } from '../codec/svm-terms'; /** - * Contract adapter for the reviewed v4 ABI generation. All version- + * Contract adapter for the reviewed v5 ABI generation. All version- * sensitive encoding, decoding and view names live here; callers never touch * a raw ABI. A future generation gets its own adapter implementing the same * interface. @@ -104,8 +104,8 @@ const EXECUTION_TUPLE = [ }, ] as const; -export const v4 = { - id: 'v4', +export const v5 = { + id: 'v5', abis: { wallet: AGW_ABI, factory: AGW_FACTORY_ABI, @@ -199,6 +199,13 @@ export const v4 = { args: [], }); }, + encodeSetLabel(label: string): Hex { + return encodeFunctionData({ + abi: AGW_ABI, + functionName: 'setLabel', + args: [label], + }); + }, /** ERC-7579 single execution calldata: abi.encodePacked(target, value, callData). */ packSingle(call: Call): Hex { return encodePacked( @@ -212,7 +219,7 @@ export const v4 = { return encodeFunctionData({ abi: AGW_ABI, functionName: 'execute', - args: [MODE_SINGLE, v4.packSingle(calls[0])], + args: [MODE_SINGLE, v5.packSingle(calls[0])], }); } const batch = encodeAbiParameters(EXECUTION_TUPLE, [ @@ -232,7 +239,7 @@ export const v4 = { return encodeFunctionData({ abi: AGW_ABI, functionName: 'executeAsAgent', - args: [rulesId, MODE_SINGLE, v4.packSingle(call)], + args: [rulesId, MODE_SINGLE, v5.packSingle(call)], }); }, encodeAssertSpentNative( @@ -305,7 +312,7 @@ export const v4 = { return k; }, parseWalletDeployed(logs: readonly Log[], factory: Address) { - return decodeMatching(logs, factory, v4.events.walletDeployed).map( + return decodeMatching(logs, factory, v5.events.walletDeployed).map( (args) => ({ owner: getAddress(args['owner'] as Address), index: BigInt(args['index'] as bigint), @@ -315,14 +322,14 @@ export const v4 = { ); }, parseRulesGranted(logs: readonly Log[], wallet: Address) { - return decodeMatching(logs, wallet, v4.events.rulesGranted).map((args) => ({ + return decodeMatching(logs, wallet, v5.events.rulesGranted).map((args) => ({ rulesId: args['rulesId'] as Hex, mode: Number(args['mode']), chainNamespace: args['chainNamespace'] as string, })); }, parseRulesRevoked(logs: readonly Log[], wallet: Address) { - return decodeMatching(logs, wallet, v4.events.rulesRevoked).map((args) => ({ + return decodeMatching(logs, wallet, v5.events.rulesRevoked).map((args) => ({ rulesId: args['rulesId'] as Hex, })); }, @@ -332,12 +339,12 @@ export const v4 = { (l) => sameAddress(l.address, wallet) && l.topics[0]?.toLowerCase() === - toEventSelector(v4.events.checkpointed).toLowerCase() + toEventSelector(v5.events.checkpointed).toLowerCase() ) .flatMap((log) => { try { const ev = decodeEventLog({ - abi: [v4.events.checkpointed], + abi: [v5.events.checkpointed], ...log, strict: true, }); @@ -348,7 +355,7 @@ export const v4 = { }) .map(({ log, args }) => ({ seq: Number(args['seq']), - kind: v4.decodeCheckpointKind(Number(args['kind'])), + kind: v5.decodeCheckpointKind(Number(args['kind'])), ref: args['ref'] as Hex, blockNumber: BigInt(log.blockNumber ?? BigInt(0)), txHash: log.transactionHash as Hex, @@ -412,4 +419,4 @@ function decodeMatching( return out; } -export type AgwContracts = typeof v4; +export type AgwContracts = typeof v5; diff --git a/packages/core/src/lib/agentic/deployments.ts b/packages/core/src/lib/agentic/deployments.ts index 3ffbe434..421a0a02 100644 --- a/packages/core/src/lib/agentic/deployments.ts +++ b/packages/core/src/lib/agentic/deployments.ts @@ -1,14 +1,14 @@ import { getAddress, type Address } from 'viem'; import { PUSH_NETWORK } from '../constants/enums'; import { AgenticCapability } from './capabilities'; -import { v4, type AgwContracts } from './contracts/v4'; +import { v5, type AgwContracts } from './contracts/v5'; import type { ChainReader } from './contracts/reader'; import { AGENTIC_ERROR_CODE, AgenticError } from './errors'; import { - DONUT_V4_ADDRESSES, - DONUT_V4_START_BLOCK, - V4_SOURCE_COMMIT, -} from './contracts/donut-v4'; + DONUT_V5_ADDRESSES, + DONUT_V5_START_BLOCK, + V5_SOURCE_COMMIT, +} from './contracts/donut-v5'; /** * A verified AGW contract generation on one Push network. The registry is the @@ -17,7 +17,7 @@ import { * are NOT registered because they do not implement this ABI. */ export interface AgenticGeneration { - /** Stable identifier, e.g. 'v4'. */ + /** Stable identifier, e.g. 'v5'. */ id: string; /** Contract source commit the ABI was generated from. */ sourceCommit: string; @@ -40,8 +40,8 @@ export interface AgenticGeneration { contracts: AgwContracts; } -/** Capabilities the v4 ABI actually implements. Target-only features are absent. */ -export const V4_CAPABILITIES: ReadonlySet = new Set([ +/** Capabilities the v5 ABI actually implements. Target-only features are absent. */ +export const V5_CAPABILITIES: ReadonlySet = new Set([ AgenticCapability.WALLET_READS, AgenticCapability.ACTIVE_RULE_READS, AgenticCapability.OWNER_EXECUTE, @@ -53,22 +53,23 @@ export const V4_CAPABILITIES: ReadonlySet = new Set([ AgenticCapability.UNIVERSAL_EVM_RULES, AgenticCapability.UNIVERSAL_SVM_RULES, AgenticCapability.ASSERT_SPENT_UNIVERSAL_MULTI, + AgenticCapability.SET_LABEL, ]); /** - * V4 only. Unsupported networks fail before signing; no legacy adapter fallback. + * V5 only. Unsupported networks fail before signing; no legacy adapter fallback. */ const VERIFIED_DEPLOYMENTS: readonly AgenticGeneration[] = [ { - id: 'v4', - sourceCommit: V4_SOURCE_COMMIT, + id: 'v5', + sourceCommit: V5_SOURCE_COMMIT, network: PUSH_NETWORK.TESTNET_DONUT, advertised: true, - addresses: DONUT_V4_ADDRESSES, - startBlock: DONUT_V4_START_BLOCK, + addresses: DONUT_V5_ADDRESSES, + startBlock: DONUT_V5_START_BLOCK, accountId: 'push.agw.1.0.0', - capabilities: V4_CAPABILITIES, - contracts: v4, + capabilities: V5_CAPABILITIES, + contracts: v5, }, ]; @@ -84,7 +85,7 @@ export function registerAgenticGeneration( capabilities?: ReadonlySet; } ): AgenticGeneration { - if (input.id !== v4.id || input.sourceCommit !== V4_SOURCE_COMMIT) { + if (input.id !== v5.id || input.sourceCommit !== V5_SOURCE_COMMIT) { throw new AgenticError( AGENTIC_ERROR_CODE.GENERATION_UNSUPPORTED, `no contract adapter for generation "${input.id}"` @@ -100,8 +101,8 @@ export function registerAgenticGeneration( sessionValidator: getAddress(input.addresses.sessionValidator), gateway: getAddress(input.addresses.gateway), }, - capabilities: input.capabilities ?? V4_CAPABILITIES, - contracts: v4, + capabilities: input.capabilities ?? V5_CAPABILITIES, + contracts: v5, }; const existing = registry.findIndex( (g) => @@ -113,7 +114,7 @@ export function registerAgenticGeneration( return gen; } -/** @internal Test/harness cleanup. Restores the checked Donut v4 registry. */ +/** @internal Test/harness cleanup. Restores the checked Donut v5 registry. */ export function resetAgenticGenerations(): void { registry.splice(0, registry.length, ...VERIFIED_DEPLOYMENTS); verifiedWiring.clear(); @@ -132,7 +133,7 @@ export async function verifyPolicyVersion( if (version !== '3.1.0') throw new AgenticError( AGENTIC_ERROR_CODE.GENERATION_UNSUPPORTED, - `URP version ${String(version)} is not supported by the v4 adapter` + `URP version ${String(version)} is not supported by the v5 adapter` ); } @@ -151,7 +152,7 @@ export function currentGeneration(network: PUSH_NETWORK): AgenticGeneration { AGENTIC_ERROR_CODE.GENERATION_UNSUPPORTED, `no verified AGW deployment is registered for ${network}`, { - hint: 'AGW v4 is configured on Donut only; this Push network has no registered v4 deployment.', + hint: 'AGW v5 is configured on Donut only; this Push network has no registered v5 deployment.', details: { network, assumption: 'A07' }, } ); @@ -232,7 +233,7 @@ export async function resolveWalletGeneration( factory = getAddress( (await reader.readContract({ address: wallet, - abi: v4.abis.wallet, + abi: v5.abis.wallet, functionName: 'factory', })) as Address ); diff --git a/packages/core/src/lib/agentic/execution/outbound.ts b/packages/core/src/lib/agentic/execution/outbound.ts index 4c1a6826..ab78059f 100644 --- a/packages/core/src/lib/agentic/execution/outbound.ts +++ b/packages/core/src/lib/agentic/execution/outbound.ts @@ -18,8 +18,8 @@ import { isPC20Reference } from '../../orchestrator/orchestrator.types'; import { resolveR2DestinationFundsToken } from '../../orchestrator/internals/route-handlers'; import { AgenticCapability, requireCapability } from '../capabilities'; import type { AgenticGeneration } from '../deployments'; -import type { Call } from '../contracts/v4'; -import { UEA_MULTICALL_PREFIX } from '../contracts/v4'; +import type { Call } from '../contracts/v5'; +import { UEA_MULTICALL_PREFIX } from '../contracts/v5'; import { AGENTIC_ERROR_CODE, AgenticError, @@ -27,7 +27,7 @@ import { } from '../errors'; import type { AgenticRuntime } from '../runtime'; -/** URP MAX_ACTIONS_PER_REQUEST at v4. */ +/** URP MAX_ACTIONS_PER_REQUEST at v5. */ export const MAX_DESTINATION_CALLS = 10; const MULTICALL_TUPLE = [ @@ -186,16 +186,6 @@ export async function composeOutbound( } else { token = runtime.resolvePrc20(undefined, chain); } - if ( - opts.ruleAssets && - !opts.ruleAssets.some((a) => getAddress(a) === token) - ) { - throw new AgenticError( - AGENTIC_ERROR_CODE.RULE_LIMIT_EXCEEDED, - `the selected rule does not list asset ${token}` - ); - } - const resolved = await runtime.resolveCEA(wallet, chain); const cea = getAddress(resolved.cea); const calls = destinationCalls(params, { cea, fundsToken }); diff --git a/packages/core/src/lib/agentic/execution/send.ts b/packages/core/src/lib/agentic/execution/send.ts index 1cabdcce..6f18a4ca 100644 --- a/packages/core/src/lib/agentic/execution/send.ts +++ b/packages/core/src/lib/agentic/execution/send.ts @@ -17,8 +17,8 @@ import { } from '../../orchestrator/internals/helpers'; import { AgenticCapability, requireCapability } from '../capabilities'; import type { AgenticExecutionContext } from '../context'; -import type { Call, UniversalConfigRead } from '../contracts/v4'; -import { SEND_OUTBOUND_SELECTOR } from '../contracts/v4'; +import type { Call, UniversalConfigRead } from '../contracts/v5'; +import { SEND_OUTBOUND_SELECTOR } from '../contracts/v5'; import { actionId, configId } from '../codec/ids'; import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; import { @@ -213,7 +213,6 @@ export async function agenticSend( : { to: wallet, data: wrappedData, value: BigInt(0) }; } else { let ruleAssets: readonly Address[] | undefined; - let maxGasPerCall: bigint | undefined; let expectedCEA: Address | undefined; const snap = await Snapshot.at(runtime.reader); if (actx.door === 'agent') { @@ -245,7 +244,6 @@ export async function agenticSend( ] ); ruleAssets = cfg.assets.map((a) => getAddress(a.token)); - maxGasPerCall = cfg.maxGasPerCall; expectedCEA = getAddress(cfg.expectedCEA); } const out = await composeOutbound(runtime, gen, wallet, p, { @@ -308,12 +306,6 @@ export async function agenticSend( } ); } - if (maxGasPerCall !== undefined && out.value > maxGasPerCall) { - throw new AgenticError( - AGENTIC_ERROR_CODE.RULE_LIMIT_EXCEEDED, - `this outbound needs ${out.value} PC wei but the rule caps the wallet's PC per call at ${maxGasPerCall}` - ); - } wrappedData = gen.contracts.encodeExecuteAsAgent( rulesId as Hex, out.gatewayCall diff --git a/packages/core/src/lib/agentic/execution/svm-instruction.ts b/packages/core/src/lib/agentic/execution/svm-instruction.ts index 26a57a54..3d81bcd5 100644 --- a/packages/core/src/lib/agentic/execution/svm-instruction.ts +++ b/packages/core/src/lib/agentic/execution/svm-instruction.ts @@ -9,8 +9,8 @@ import { } from './svm-payload'; import type { Address } from 'viem'; -/** Existing IDL encoding, with the wallet's authority and strict policy checks. */ -export function prepareAgwSvmInstruction( +/** Resolve IDL accounts with the wallet authority; granted permissions are checked by URP. */ +export function resolveAgwSvmInstruction( input: { wallet: Address; chain: CHAIN; @@ -27,7 +27,6 @@ export function prepareAgwSvmInstruction( input.accounts, input.instructionData ); - validateAgwSvmPayload(terms, program, payload); return { recipient: program, payload, @@ -49,7 +48,6 @@ export function prepareAgwSvmInstruction( resolved.accounts, resolved.ixData ); - validateAgwSvmPayload(terms, program, payload); return { recipient: program, payload, @@ -57,3 +55,13 @@ export function prepareAgwSvmInstruction( instructionData: resolved.ixData, }; } + +/** Diagnostic-only local policy preview. Sends use the resolver and contract enforcement. */ +export function prepareAgwSvmInstruction( + input: Parameters[0], + terms: SvmTermsWire +) { + const resolved = resolveAgwSvmInstruction(input, terms); + validateAgwSvmPayload(terms, resolved.recipient, resolved.payload); + return resolved; +} diff --git a/packages/core/src/lib/agentic/execution/svm-outbound.ts b/packages/core/src/lib/agentic/execution/svm-outbound.ts index d0435b9c..6f35c58f 100644 --- a/packages/core/src/lib/agentic/execution/svm-outbound.ts +++ b/packages/core/src/lib/agentic/execution/svm-outbound.ts @@ -1,8 +1,8 @@ -/** Internal SVM action builder. No public Rule/export or capability enablement. */ +/** Outbound encoding plus a diagnostic-only policy preview. */ import { encodeFunctionData, getAddress, type Address, type Hex } from 'viem'; import { UNIVERSAL_GATEWAY_PC } from '../../constants/abi'; import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; -import type { Call, SvmConfigRead } from '../contracts/v4'; +import type { Call, SvmConfigRead } from '../contracts/v5'; import { UINT256_MAX } from '../codec/defaults'; import { UINT64_MAX } from '../codec/svm-terms'; import { validateAgwSvmPayload } from './svm-payload'; @@ -18,6 +18,7 @@ export interface SvmOutboundInput { protocolFee: bigint; maxPCForGas: bigint; } +/** Diagnostic-only local preview; production sends use buildAgwSvmAction. */ export function composeAgwSvmAction( input: SvmOutboundInput, config: SvmConfigRead, @@ -50,6 +51,35 @@ export function composeAgwSvmAction( fail('PCValueExceedsCap'); if (!input.maxPCForGas) fail('UncappedGasSwapRejected'); validateAgwSvmPayload(config, input.recipient, input.payload); + return buildAgwSvmAction(input); +} + +/** Encode an outbound without evaluating the granted policy; the wallet/URP enforces it. */ +export function buildAgwSvmAction(input: SvmOutboundInput): Call { + for (const [name, value] of Object.entries({ + amount: input.amount, + gasLimit: input.gasLimit, + protocolFee: input.protocolFee, + maxPCForGas: input.maxPCForGas, + })) { + if (typeof value !== 'bigint' || value < BigInt(0) || value > UINT256_MAX) + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + `${name} must fit uint256` + ); + } + if (input.amount > UINT64_MAX) + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'Solana amount must fit uint64' + ); + const value = input.protocolFee + input.maxPCForGas; + if (value > UINT256_MAX || input.maxPCForGas === BigInt(0)) + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'invalid outbound gas quote' + ); + const token = getAddress(input.token); const request = { recipient: input.recipient, token, diff --git a/packages/core/src/lib/agentic/execution/svm-public.ts b/packages/core/src/lib/agentic/execution/svm-public.ts index 7af6139b..00c9b347 100644 --- a/packages/core/src/lib/agentic/execution/svm-public.ts +++ b/packages/core/src/lib/agentic/execution/svm-public.ts @@ -1,16 +1,7 @@ -import { PRC20_SOURCE_ABI } from '../contracts/prc20-metadata'; import { PROGRESS_HOOK } from '../../progress-hook/progress-hook.types'; import { emitAgentic } from '../management/common'; -import { - bytesToHex, - hexToBytes, - encodeFunctionData, - erc20Abi, - getAddress, - type Hex, -} from 'viem'; +import { bytesToHex, hexToBytes, erc20Abi, getAddress, type Hex } from 'viem'; import type { CHAIN } from '../../constants/enums'; -import { UNIVERSAL_GATEWAY_PC } from '../../constants/abi'; import { isPC20Reference, type UniversalExecuteParams, @@ -31,6 +22,9 @@ import { svmInvalid, UINT64_MAX } from '../codec/svm-terms'; import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; import { prepareSvmAgentExecution } from './svm-send'; import { encodeAgwSvmPayload } from './svm-payload'; +import { quoteSvmRequest } from './svm-quote'; +import { buildAgwSvmAction } from './svm-outbound'; +import type { AgenticTxMetadata } from '../agentic.types'; import { adaptAgenticResponse } from '../response'; /** Public single-instruction route; the contract enforces the supplied rule. */ @@ -50,15 +44,17 @@ export async function sendPublicSvm( : AgenticCapability.OWNER_EXECUTE ); const to = p.to as { address: string; chain: CHAIN }; - const program = svmKey(to.address); + const target = svmKey(to.address); + if (Array.isArray(p.data)) + throw svmInvalid('Solana AGW sends do not support instruction arrays'); + const hasInstruction = p.data !== undefined && p.data !== '0x'; if ( - Array.isArray(p.data) || - typeof p.data !== 'string' || - !/^0x(?:[0-9a-fA-F]{2})+$/.test(p.data) + hasInstruction && + (typeof p.data !== 'string' || !/^0x(?:[0-9a-fA-F]{2})+$/.test(p.data)) ) - throw svmInvalid( - 'Solana AGW sends require one encoded instruction; arrays and funds-only sends are unsupported' - ); + throw svmInvalid('invalid Solana instruction bytes'); + if (!hasInstruction && actx.door === 'agent') + throw svmInvalid('Solana agent sends require an encoded instruction'); if (p.funds && isPC20Reference(p.funds.token)) throw svmInvalid('PC20 SVM outbound is not supported'); if (p.funds && (p.value ?? BigInt(0)) !== BigInt(0)) @@ -66,9 +62,22 @@ export async function sendPublicSvm( const amount = p.funds?.amount ?? p.value ?? BigInt(0); if (typeof amount !== 'bigint' || amount < BigInt(0) || amount > UINT64_MAX) throw svmInvalid('Solana outbound amount must fit uint64'); + if (!hasInstruction && amount === BigInt(0)) + throw svmInvalid('a funds-only send requires a positive amount'); const metadata = svmMetadata(runtime), snap = await Snapshot.at(runtime.reader); - let rulesId: Hex | undefined, data: Hex, instruction, cea: Hex; + let rulesId: Hex | undefined, + data: Hex, + instruction: + | { + recipient: Hex; + instructionData: Uint8Array; + accounts: readonly { pubkey: Hex; isWritable: boolean }[]; + } + | undefined, + cea: Hex; + let destinationTransfer: AgenticTxMetadata['destinationTransfer']; + let transferValue = BigInt(0); const gasLimit = p.gasLimit ?? BigInt(1_000_000); if (actx.door === 'agent') { const active = await selectRuleForSend( @@ -101,8 +110,8 @@ export async function sendPublicSvm( token, amount, gasLimit, - program, - instructionData: hexToBytes(p.data), + program: target, + instructionData: hexToBytes(p.data as Hex), }, metadata ); @@ -113,33 +122,40 @@ export async function sendPublicSvm( } else { const gateway = await metadata.gateway(to.chain as `solana:${string}`); cea = deriveAgwSvmCea(wallet, gateway.program).address; - const resolved = resolveSvmCallForCea( - { - programAddress: program, - data: hexToBytes(p.data), - senderUea: wallet, - targetChain: to.chain, - }, - cea - ); - instruction = { - recipient: resolved.targetProgram, - instructionData: resolved.ixData, - accounts: resolved.accounts, - }; + const resolved = hasInstruction + ? resolveSvmCallForCea( + { + programAddress: target, + data: hexToBytes(p.data as Hex), + senderUea: wallet, + targetChain: to.chain, + }, + cea + ) + : undefined; + if (resolved) + instruction = { + recipient: resolved.targetProgram, + instructionData: resolved.ixData, + accounts: resolved.accounts, + }; const token = runtime.resolvePrc20( p.funds?.token as MoveableToken | undefined, to.chain ); - if ( - (await snap.read( - token, - PRC20_SOURCE_ABI, - 'SOURCE_CHAIN_NAMESPACE' - )) !== to.chain - ) - throw svmInvalid('outbound asset belongs to another chain'); - const quote = await runtime.quoteOutbound(token, gasLimit, to.chain); + const quote = await quoteSvmRequest( + runtime, + snap, + wallet, + token, + to.chain, + gasLimit, + amount + ); + if (!hasInstruction) { + destinationTransfer = { recipient: target, token, amount }; + transferValue = quote.isNative ? amount : BigInt(0); + } const [pc, balance, allowance] = await Promise.all([ runtime.reader.getBalance({ address: wallet, @@ -162,32 +178,24 @@ export async function sendPublicSvm( AGENTIC_ERROR_CODE.GATEWAY_ALLOWANCE_INSUFFICIENT, 'set the wallet gateway allowance separately' ); - data = gen.contracts.encodeExecute([ - { - target: gen.addresses.gateway, - value, - data: encodeFunctionData({ - abi: UNIVERSAL_GATEWAY_PC, - functionName: 'sendUniversalTxOutbound', - args: [ - { - token, - amount, - recipient: resolved.targetProgram, - payload: encodeAgwSvmPayload( - resolved.targetProgram, - resolved.accounts, - resolved.ixData - ), - gasLimit: quote.gasLimitUsed, - gasPrice: BigInt(0), - maxPCForGas: quote.nativeValueForGas, - revertRecipient: wallet, - }, - ], - }), - }, - ]); + const call = buildAgwSvmAction({ + wallet, + gateway: gen.addresses.gateway, + token, + amount, + recipient: target, + payload: resolved + ? encodeAgwSvmPayload( + resolved.targetProgram, + resolved.accounts, + resolved.ixData + ) + : '0x', + gasLimit: quote.gasLimitUsed, + protocolFee: quote.protocolFee, + maxPCForGas: quote.nativeValueForGas, + }); + data = gen.contracts.encodeExecute([call]); } const hook = options?.progressHook ?? p.progressHook; emitAgentic( @@ -241,17 +249,23 @@ export async function sendPublicSvm( chainNamespace: to.chain, chain: to.chain, route: 'UOA_TO_CEA', - destinationAccount: cea, - destinationInstruction: { - program: instruction.recipient, - data: bytesToHex(instruction.instructionData), - accounts: instruction.accounts, - }, - logical: { - to: instruction.recipient, - data: bytesToHex(instruction.instructionData), - value: BigInt(0), - }, + ...(instruction + ? { + destinationAccount: cea, + destinationInstruction: { + program: instruction.recipient, + data: bytesToHex(instruction.instructionData), + accounts: instruction.accounts, + }, + } + : { destinationTransfer }), + logical: instruction + ? { + to: instruction.recipient, + data: bytesToHex(instruction.instructionData), + value: BigInt(0), + } + : { to: target, data: '0x', value: transferValue }, }); emitAgentic( runtime, diff --git a/packages/core/src/lib/agentic/execution/svm-quote.ts b/packages/core/src/lib/agentic/execution/svm-quote.ts new file mode 100644 index 00000000..f78fa563 --- /dev/null +++ b/packages/core/src/lib/agentic/execution/svm-quote.ts @@ -0,0 +1,51 @@ +import { PublicKey } from '@solana/web3.js'; +import { getAddress, hexToBytes, type Address } from 'viem'; +import type { CHAIN } from '../../constants/enums'; +import { + PRC20_SOURCE_ABI, + readGasPrc20, + readSvmSourceToken, +} from '../contracts/prc20-metadata'; +import type { AgenticRuntime } from '../runtime'; +import type { Snapshot } from '../reads/snapshot'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; + +/** Route/fee validation, independent of the selected rule's permissions. */ +export async function quoteSvmRequest( + runtime: AgenticRuntime, + snap: Snapshot, + wallet: Address, + token: Address, + chain: CHAIN, + gasLimit: bigint, + amount: bigint +) { + if ( + (await snap.read( + token, + PRC20_SOURCE_ABI, + 'SOURCE_CHAIN_NAMESPACE' + )) !== chain + ) { + throw new AgenticError( + AGENTIC_ERROR_CODE.ASSET_CHAIN_MISMATCH, + 'outbound asset belongs to another chain' + ); + } + const isNative = + getAddress(token) === getAddress(await readGasPrc20(snap, chain)); + const splMintBase58 = + !isNative && amount > BigInt(0) + ? new PublicKey( + hexToBytes( + await readSvmSourceToken(snap, token, chain, runtime.network) + ) + ).toBase58() + : undefined; + const quote = await runtime.quoteOutbound(token, gasLimit, chain, { + wallet, + splMintBase58, + burnAmount: amount, + }); + return { ...quote, isNative }; +} diff --git a/packages/core/src/lib/agentic/execution/svm-send.ts b/packages/core/src/lib/agentic/execution/svm-send.ts index e7cb61fa..b28d80d7 100644 --- a/packages/core/src/lib/agentic/execution/svm-send.ts +++ b/packages/core/src/lib/agentic/execution/svm-send.ts @@ -1,3 +1,4 @@ +import { quoteSvmRequest } from './svm-quote'; /** Prepared-wire agent execution used by the public Solana route. */ import { getAddress, erc20Abi, type Address, type Hex } from 'viem'; import { CHAIN } from '../../constants/enums'; @@ -10,8 +11,8 @@ import { resolveSvmContext, type SvmMetadataProvider, } from '../management/svm-context'; -import { composeAgwSvmAction } from './svm-outbound'; -import { prepareAgwSvmInstruction } from './svm-instruction'; +import { buildAgwSvmAction } from './svm-outbound'; +import { resolveAgwSvmInstruction } from './svm-instruction'; import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; import { verifySvmWallet } from '../management/svm'; import type { SvmPayloadAccount } from './svm-payload'; @@ -73,7 +74,7 @@ export async function prepareSvmAgentExecution( AGENTIC_ERROR_CODE.INVALID_RULE, 'stored SVM context does not cover the wallet and every asset' ); - const instruction = prepareAgwSvmInstruction( + const instruction = resolveAgwSvmInstruction( { wallet: input.wallet, chain, @@ -83,24 +84,24 @@ export async function prepareSvmAgentExecution( }, stored.config ); - const quote = await runtime.quoteOutbound( + const quote = await quoteSvmRequest( + runtime, + snap, + input.wallet, getAddress(input.token), + chain, input.gasLimit, - chain - ); - const call = composeAgwSvmAction( - { - ...input, - gateway: gen.addresses.gateway, - recipient: instruction.recipient, - payload: instruction.payload, - gasLimit: quote.gasLimitUsed, - protocolFee: quote.protocolFee, - maxPCForGas: quote.nativeValueForGas, - }, - stored.config, - runtime.nowSeconds() + input.amount ); + const call = buildAgwSvmAction({ + ...input, + gateway: gen.addresses.gateway, + recipient: instruction.recipient, + payload: instruction.payload, + gasLimit: quote.gasLimitUsed, + protocolFee: quote.protocolFee, + maxPCForGas: quote.nativeValueForGas, + }); const walletPc = await runtime.reader.getBalance({ address: input.wallet, blockNumber: snap.blockNumber, diff --git a/packages/core/src/lib/agentic/management/create.ts b/packages/core/src/lib/agentic/management/create.ts index d76009b0..3ed82950 100644 --- a/packages/core/src/lib/agentic/management/create.ts +++ b/packages/core/src/lib/agentic/management/create.ts @@ -6,10 +6,11 @@ import { AgenticCapability, requireCapability } from '../capabilities'; import { currentGeneration, verifyFactoryWiring } from '../deployments'; import { deriveWallet, rulesId as computeRulesId } from '../codec/ids'; import { prepareWalletRules } from './prepare'; +import { assertLabel } from './label'; import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; import type { AgenticRuntime } from '../runtime'; import type { CreateOptions, CreateResult } from '../agentic.types'; -import { Snapshot } from '../reads/snapshot'; +import { Snapshot, scanLogs } from '../reads/snapshot'; import { walletCount, walletInfo } from '../reads/wallets'; import { assertCanSign, @@ -38,12 +39,7 @@ export async function createWallet( options: CreateOptions ): Promise { const hook = options?.progressHook; - if (typeof label !== 'string') { - throw new AgenticError( - AGENTIC_ERROR_CODE.INVALID_RULE, - 'label must be a string' - ); - } + assertLabel(label); if (!options || !Array.isArray(options.rules)) { throw new AgenticError( AGENTIC_ERROR_CODE.INVALID_RULE, @@ -281,18 +277,32 @@ async function createFailure( // moved and immutable deployment metadata proves another label owns the // predicted slot, this call could not have deployed or granted. try { - const next = await walletCount( - await Snapshot.at(runtime.reader), - gen, - owner - ); + const snap = await Snapshot.at(runtime.reader); + const next = await walletCount(snap, gen, owner); if (next > BigInt(index)) { const competing = await walletInfo(runtime.reader, gen, wallet); + // label() is mutable in v5: only the immutable deploy event proves + // which creation occupied this slot. A later rename proves nothing. + const logs = await scanLogs( + runtime.reader, + { + address: gen.addresses.factory, + event: gen.contracts.events.walletDeployed, + args: { wallet }, + }, + gen.startBlock, + snap.blockNumber + ); + const deployed = gen.contracts + .parseWalletDeployed(logs, gen.addresses.factory) + .find((entry) => entry.wallet === wallet); + const competingLabel = deployed?.label; if ( competing.deployed && competing.index === index && getAddress(competing.owner) === owner && - competing.label !== label + competingLabel !== undefined && + competingLabel !== label ) { return new AgenticError( AGENTIC_ERROR_CODE.INDEX_RACE, @@ -302,13 +312,13 @@ async function createFailure( 'Slot ' + index + ' belongs to "' + - competing.label + + competingLabel + '". No wallet or rules from this create call were committed; retry agentic.create to use the next slot.', details: { wallet, index, committed: false, - competingLabel: competing.label, + competingLabel, }, cause: wrapped, } diff --git a/packages/core/src/lib/agentic/management/label.ts b/packages/core/src/lib/agentic/management/label.ts new file mode 100644 index 00000000..a63e2b30 --- /dev/null +++ b/packages/core/src/lib/agentic/management/label.ts @@ -0,0 +1,21 @@ +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; + +/** AGW MAX_LABEL_BYTES. Empty resets the default; lengths count UTF-8 bytes. */ +export const MAX_LABEL_BYTES = 64; + +export function assertLabel(label: string): void { + if (typeof label !== 'string') { + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'label must be a string' + ); + } + const length = new TextEncoder().encode(label).length; + if (length > MAX_LABEL_BYTES) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + `label must be at most ${MAX_LABEL_BYTES} UTF-8 bytes (received ${length})`, + { details: { length, maxLength: MAX_LABEL_BYTES } } + ); + } +} diff --git a/packages/core/src/lib/agentic/management/rules-write.ts b/packages/core/src/lib/agentic/management/rules-write.ts index a77f4e64..96d5fcb7 100644 --- a/packages/core/src/lib/agentic/management/rules-write.ts +++ b/packages/core/src/lib/agentic/management/rules-write.ts @@ -8,6 +8,7 @@ import { AgenticCapability, requireCapability } from '../capabilities'; import { type AgenticGeneration } from '../deployments'; import { rulesId as computeRulesId } from '../codec/ids'; import { prepareWalletRules } from './prepare'; +import { assertLabel } from './label'; import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; import type { AgenticRuntime } from '../runtime'; import type { AgenticHex, AgenticProgressHook, Rule } from '../agentic.types'; @@ -414,22 +415,37 @@ function sameIds(a: readonly Hex[], b: readonly Hex[]): boolean { ); } -/** w.setLabel — approved, awaiting a verified contract interface/deployment. */ +/** Owner rename through the owner door; empty resets the default label. */ export async function setLabel( - _runtime: AgenticRuntime, + runtime: AgenticRuntime, gen: AgenticGeneration, - _wallet: Address, - label: string -): Promise { - if (typeof label !== 'string') { - throw new AgenticError( - AGENTIC_ERROR_CODE.INVALID_RULE, - 'label must be a string' - ); - } + wallet: Address, + label: string, + hook?: AgenticProgressHook +): Promise { + assertLabel(label); + assertCanSign(runtime, 'setLabel'); requireCapability(gen.capabilities, AgenticCapability.SET_LABEL); - throw new AgenticError( - AGENTIC_ERROR_CODE.CAPABILITY_UNAVAILABLE, - 'setLabel has no adapter implementation' - ); + return finish(runtime, hook, 'setLabel', async () => { + await assertOwner(runtime, gen, wallet, await Snapshot.at(runtime.reader)); + const tx = await sendOwnerCalls( + runtime, + [ + { + to: wallet, + value: BigInt(0), + data: gen.contracts.encodeExecute([ + { + target: wallet, + value: BigInt(0), + data: gen.contracts.encodeSetLabel(label), + }, + ]), + }, + ], + hook + ); + await confirmedLogs(runtime, tx); + return { tx }; + }).then(({ tx }) => tx); } diff --git a/packages/core/src/lib/agentic/management/svm-context.ts b/packages/core/src/lib/agentic/management/svm-context.ts index 72f7ed80..2187712c 100644 --- a/packages/core/src/lib/agentic/management/svm-context.ts +++ b/packages/core/src/lib/agentic/management/svm-context.ts @@ -1,13 +1,12 @@ /** Internal resolved context; no public Rule schema or cluster assumptions. */ -import { - getAddress, - parseAbi, - zeroAddress, - type Address, - type Hex, -} from 'viem'; +import { getAddress, type Address, type Hex } from 'viem'; +import { PUSH_NETWORK } from '../../constants/enums'; import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; -import { PRC20_SOURCE_ABI, readGasPrc20 } from '../contracts/prc20-metadata'; +import { + PRC20_SOURCE_ABI, + readGasPrc20, + readSvmSourceToken, +} from '../contracts/prc20-metadata'; import { svmKey, resolveAgwSvmRuleContext, @@ -29,16 +28,14 @@ export interface SvmMetadataProvider { ): Promise<{ mint: string; tokenProgram: string }>; } -const NATIVE_SOURCE = parseAbi([ - 'function SOURCE_TOKEN_ADDRESS() view returns (address)', -]); const ZERO_KEY = `0x${'00'.repeat(32)}` as Hex; export async function resolveSvmAssets( snap: Snapshot, chain: `solana:${string}`, caps: readonly AssetCapWire[], - metadata: SvmMetadataProvider + metadata: SvmMetadataProvider, + network: PUSH_NETWORK = PUSH_NETWORK.TESTNET_DONUT ): Promise { const gas = await readGasPrc20(snap, chain); const out: ResolvedSvmAsset[] = []; @@ -54,27 +51,8 @@ export async function resolveSvmAssets( AGENTIC_ERROR_CODE.ASSET_CHAIN_MISMATCH, `PRC20 ${token} belongs to ${namespace}, not ${chain}` ); - let source: string; - try { - source = await snap.read( - token, - PRC20_SOURCE_ABI, - 'SOURCE_TOKEN_ADDRESS' - ); - } catch (cause) { - if (token !== gas) throw cause; - const native = await snap.read
( - token, - NATIVE_SOURCE, - 'SOURCE_TOKEN_ADDRESS' - ); - if (getAddress(native) !== zeroAddress) throw cause; - source = ''; - } - const native = - source === '' || - source.toLowerCase() === zeroAddress || - source.toLowerCase() === ZERO_KEY; + const source = await readSvmSourceToken(snap, token, chain, network); + const native = source === ZERO_KEY; if (native) { if (token !== gas) throw new AgenticError( @@ -102,7 +80,8 @@ export async function resolveSvmContext( chain: `solana:${string}`, caps: readonly AssetCapWire[], metadata: SvmMetadataProvider, - outputs: readonly SvmTokenAccountInput[] = [] + outputs: readonly SvmTokenAccountInput[] = [], + network: PUSH_NETWORK = PUSH_NETWORK.TESTNET_DONUT ) { const gateway = await metadata.gateway(chain); if (gateway.chainNamespace !== chain) @@ -110,7 +89,7 @@ export async function resolveSvmContext( AGENTIC_ERROR_CODE.INVALID_RULE, 'gateway registry cluster mismatch' ); - const assets = await resolveSvmAssets(snap, chain, caps, metadata); + const assets = await resolveSvmAssets(snap, chain, caps, metadata, network); const resolvedOutputs = []; for (const output of outputs) { const key = svmKey(output.mint); diff --git a/packages/core/src/lib/agentic/management/svm-public.ts b/packages/core/src/lib/agentic/management/svm-public.ts index d66c9936..f74d996b 100644 --- a/packages/core/src/lib/agentic/management/svm-public.ts +++ b/packages/core/src/lib/agentic/management/svm-public.ts @@ -1,4 +1,5 @@ -import { getAddress, zeroAddress } from 'viem'; +import { PublicKey } from '@solana/web3.js'; +import { getAddress, hexToBytes, zeroAddress } from 'viem'; import type { Address, Hex } from 'viem'; import { CHAIN, VM } from '../../constants/enums'; import { CHAIN_INFO } from '../../constants/chain'; @@ -61,9 +62,13 @@ export async function preparePublicSvmRule( /^0x0{64}$/.test(source) || source === '11111111111111111111111111111111'; const key = native ? undefined : svmKey(source); + const sourceToken = + typeof asset.token === 'string' && key + ? new PublicKey(hexToBytes(key)).toBase58() + : asset.token; const token = native ? await readGasPrc20(snap, chain) - : runtime.resolvePrc20(asset.token, chain); + : runtime.resolvePrc20(sourceToken, chain); if (caps.some((c) => c.token === getAddress(token))) throw svmInvalid('duplicate SVM asset'); caps.push({ @@ -82,7 +87,8 @@ export async function preparePublicSvmRule( rule.chainNamespace, caps, metadata, - outputs + outputs, + runtime.network ); // Validate the PRC20 actually represents the requested source mint, not merely its chain. const { resolveSvmAssets } = await import('./svm-context'); @@ -90,7 +96,8 @@ export async function preparePublicSvmRule( snap, rule.chainNamespace, caps, - metadata + metadata, + runtime.network ); resolved.forEach((a, i) => { if ( diff --git a/packages/core/src/lib/agentic/management/svm.ts b/packages/core/src/lib/agentic/management/svm.ts index 680bd620..685b661a 100644 --- a/packages/core/src/lib/agentic/management/svm.ts +++ b/packages/core/src/lib/agentic/management/svm.ts @@ -17,7 +17,7 @@ import { import { encodeSvmTerms, type SvmTermsWire } from '../codec/svm-terms'; import { buildSession, encodeEnvelope } from '../codec/session'; import { rulesId as predictRulesId } from '../codec/ids'; -import { SEND_OUTBOUND_SELECTOR } from '../contracts/v4'; +import { SEND_OUTBOUND_SELECTOR } from '../contracts/v5'; import { deriveAgwSvmCea } from '../codec/svm-accounts'; import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; import { PRC20_SOURCE_ABI } from '../contracts/prc20-metadata'; diff --git a/packages/core/src/lib/agentic/reads/rules.ts b/packages/core/src/lib/agentic/reads/rules.ts index cecab2e3..0c4dcc85 100644 --- a/packages/core/src/lib/agentic/reads/rules.ts +++ b/packages/core/src/lib/agentic/reads/rules.ts @@ -1,32 +1,20 @@ import { readSvmConfig } from './svm'; -import { PRC20_SOURCE_ABI, readGasPrc20 } from '../contracts/prc20-metadata'; -import { svmKey } from '../codec/svm-accounts'; -import { - getAddress, - zeroAddress, - type Address, - type Hex, -} from 'viem'; +import { readGasPrc20, readSvmSourceToken } from '../contracts/prc20-metadata'; +import { getAddress, zeroAddress, type Address, type Hex } from 'viem'; import { CHAIN } from '../../constants/enums'; -import { - AgenticCapability, - requireCapability, -} from '../capabilities'; +import { AgenticCapability, requireCapability } from '../capabilities'; import type { AgenticGeneration } from '../deployments'; import type { NativeConfigRead, ModeRead, UniversalConfigRead, -} from '../contracts/v4'; +} from '../contracts/v5'; import { configId } from '../codec/ids'; import { nativeTermsToRule } from '../codec/native'; import { universalTermsToRule } from '../codec/universal'; import { readOriginToken } from '../contracts/prc20-metadata'; import { chainHash } from '../codec/rules'; -import { - AGENTIC_ERROR_CODE, - AgenticError, -} from '../errors'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; import type { AgenticHex, RulesRecord } from '../agentic.types'; import { Snapshot } from './snapshot'; @@ -194,12 +182,11 @@ export async function decodeActiveRule( token: getAddress(a.token) === gas ? zeroAddress - : svmKey( - await snap.read( - a.token, - PRC20_SOURCE_ABI, - 'SOURCE_TOKEN_ADDRESS' - ) + : await readSvmSourceToken( + snap, + a.token, + stored.chainNamespace, + gen.network ), maxPerCall: a.maxPerCall, maxTotal: a.maxTotal, diff --git a/packages/core/src/lib/agentic/reads/svm.ts b/packages/core/src/lib/agentic/reads/svm.ts index a68141f1..56767cff 100644 --- a/packages/core/src/lib/agentic/reads/svm.ts +++ b/packages/core/src/lib/agentic/reads/svm.ts @@ -1,10 +1,10 @@ /** Internal lossless SVM state shared by public reads and execution. */ import type { Address, Hex } from 'viem'; import type { AgenticGeneration } from '../deployments'; -import type { SvmConfigRead } from '../contracts/v4'; +import type { SvmConfigRead } from '../contracts/v5'; import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; import { actionId, configId } from '../codec/ids'; -import { SEND_OUTBOUND_SELECTOR } from '../contracts/v4'; +import { SEND_OUTBOUND_SELECTOR } from '../contracts/v5'; import { validateSvmTerms } from '../codec/svm-terms'; import { chainFromHash, readActiveRules, type ActiveRule } from './rules'; import type { Snapshot } from './snapshot'; diff --git a/packages/core/src/lib/agentic/reads/wallets.ts b/packages/core/src/lib/agentic/reads/wallets.ts index 4bd0941a..fd0c33f1 100644 --- a/packages/core/src/lib/agentic/reads/wallets.ts +++ b/packages/core/src/lib/agentic/reads/wallets.ts @@ -4,7 +4,7 @@ import type { ChainReader } from '../contracts/reader'; import { deriveWallet } from '../codec/ids'; import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; import type { WalletInfo, WalletSummary } from '../agentic.types'; -import { Snapshot, scanLogs } from './snapshot'; +import { Snapshot } from './snapshot'; /** Factory-predicted address for (owner, index), cross-checked against the pure mirror. */ async function predict( @@ -36,9 +36,18 @@ async function predict( return { address: getAddress(address), deployed }; } -export async function walletCount(snap: Snapshot, gen: AgenticGeneration, owner: Address): Promise { +export async function walletCount( + snap: Snapshot, + gen: AgenticGeneration, + owner: Address +): Promise { return BigInt( - await snap.read(gen.addresses.factory, gen.contracts.abis.factory, 'walletCount', [owner]) + await snap.read( + gen.addresses.factory, + gen.contracts.abis.factory, + 'walletCount', + [owner] + ) ); } @@ -54,7 +63,10 @@ export async function deriveForOwner( let target = next; if (index !== undefined) { if (!Number.isInteger(index) || index < 0) { - throw new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, 'index must be a non-negative integer'); + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'index must be a non-negative integer' + ); } target = BigInt(index); if (target > next) { @@ -68,27 +80,11 @@ export async function deriveForOwner( return { address: p.address, index: Number(target), deployed: p.deployed }; } -/** Deploy-time labels for the owner's wallets from WalletDeployed events. */ -async function labelsFor( - reader: ChainReader, - gen: AgenticGeneration, +export async function rulesCount( snap: Snapshot, - filter: { owner?: Address; wallet?: Address } -): Promise> { - const logs = await scanLogs( - reader, - { address: gen.addresses.factory, event: gen.contracts.events.walletDeployed, args: filter }, - gen.startBlock, - snap.blockNumber - ); - const map = new Map(); - for (const ev of gen.contracts.parseWalletDeployed(logs, gen.addresses.factory)) { - map.set(ev.wallet.toLowerCase(), ev.label); - } - return map; -} - -export async function rulesCount(snap: Snapshot, gen: AgenticGeneration, wallet: Address): Promise { + gen: AgenticGeneration, + wallet: Address +): Promise { const ids = await snap.read( gen.addresses.sessionEngine, gen.contracts.abis.engine, @@ -109,7 +105,6 @@ export async function listForOwner( ): Promise { const snap = await Snapshot.at(reader); const count = await walletCount(snap, gen, owner); - const labels = count > BigInt(0) ? await labelsFor(reader, gen, snap, { owner }) : new Map(); const out: WalletSummary[] = []; for (let i = BigInt(0); i <= count; i++) { const p = await predict(snap, gen, owner, i); @@ -120,17 +115,13 @@ export async function listForOwner( `factory reports slot ${i} deployed=${p.deployed} but walletCount is ${count}` ); } - const label = deployed ? labels.get(p.address.toLowerCase()) : ''; - if (deployed && label === undefined) { - throw new AgenticError( - AGENTIC_ERROR_CODE.INCONSISTENT_READ, - `no WalletDeployed event found for ${p.address} since block ${gen.startBlock}` - ); - } + const label = deployed + ? await snap.read(p.address, gen.contracts.abis.wallet, 'label') + : ''; out.push({ address: p.address, index: Number(i), - label: label ?? '', + label, deployed, rulesCount: deployed ? await rulesCount(snap, gen, p.address) : 0, }); @@ -139,9 +130,15 @@ export async function listForOwner( } /** w.owner(): the owner as the wallet stores it. */ -export async function walletOwner(reader: ChainReader, gen: AgenticGeneration, wallet: Address): Promise
{ +export async function walletOwner( + reader: ChainReader, + gen: AgenticGeneration, + wallet: Address +): Promise
{ const snap = await Snapshot.at(reader); - return getAddress(await snap.read
(wallet, gen.contracts.abis.wallet, 'owner')); + return getAddress( + await snap.read
(wallet, gen.contracts.abis.wallet, 'owner') + ); } /** @@ -178,16 +175,18 @@ export async function walletInfo( } const [owner, index] = await Promise.all([ snap.read
(wallet, gen.contracts.abis.wallet, 'owner'), - snap.read(gen.addresses.factory, gen.contracts.abis.factory, 'indexOf', [wallet]), + snap.read( + gen.addresses.factory, + gen.contracts.abis.factory, + 'indexOf', + [wallet] + ), ]); - const labels = await labelsFor(reader, gen, snap, { wallet }); - const label = labels.get(wallet.toLowerCase()); - if (label === undefined) { - throw new AgenticError( - AGENTIC_ERROR_CODE.INCONSISTENT_READ, - `no WalletDeployed event found for ${wallet} since block ${gen.startBlock}` - ); - } + const label = await snap.read( + wallet, + gen.contracts.abis.wallet, + 'label' + ); return { address: getAddress(wallet), label, diff --git a/packages/core/src/lib/agentic/response.ts b/packages/core/src/lib/agentic/response.ts index f7e9490e..111fdf28 100644 --- a/packages/core/src/lib/agentic/response.ts +++ b/packages/core/src/lib/agentic/response.ts @@ -1,3 +1,5 @@ +import { Snapshot } from './reads/snapshot'; +import { readGasPrc20 } from './contracts/prc20-metadata'; import { parseAgwSvmPayload } from './execution/svm-payload'; import { deriveAgwSvmCea } from './codec/svm-accounts'; import { CHAIN_INFO } from '../constants/chain'; @@ -20,11 +22,11 @@ import type { UniversalTxResponse, } from '../orchestrator/orchestrator.types'; import { - v4, + v5, SEND_OUTBOUND_SELECTOR, UEA_MULTICALL_PREFIX, type Call, -} from './contracts/v4'; +} from './contracts/v5'; import { generationsFor, resolveWalletGeneration } from './deployments'; import type { AgenticRuntime } from './runtime'; import type { @@ -89,6 +91,9 @@ export function adaptAgenticResponse( ...(meta.destinationInstruction ? { destinationInstruction: meta.destinationInstruction } : {}), + ...(meta.destinationTransfer + ? { destinationTransfer: { ...meta.destinationTransfer } } + : {}), ...(meta.nativeCalls ? { nativeCalls: meta.nativeCalls.map((call) => ({ ...call })) } : {}), @@ -110,7 +115,7 @@ export async function adaptTrackedResponse( if (resp.agentic || generationsFor(runtime.network).length === 0) return resp; const batch = await adaptNativeAgentBatch(runtime, resp); if (batch) return batch; - const decoded = v4.decodeWalletCall(resp.data as Hex); + const decoded = v5.decodeWalletCall(resp.data as Hex); if ( !decoded || (decoded.kind !== 'execute' && decoded.kind !== 'executeAsAgent') @@ -147,6 +152,39 @@ export async function adaptTrackedResponse( const out = decodeOutbound(outbound.data); const chain = await tokenChain(runtime, out.token); if (chain?.startsWith('solana:')) { + if ( + door === 'owner' && + out.payload === '0x' && + out.amount > BigInt(0) && + /^0x[0-9a-fA-F]{64}$/.test(out.recipient) + ) { + try { + const gas = await readGasPrc20( + new Snapshot(runtime.reader, resp.blockNumber), + chain + ); + return adaptAgenticResponse(resp, { + wallet, + door, + chainNamespace: chain, + chain: chain as CHAIN, + route: 'UOA_TO_CEA', + destinationTransfer: { + recipient: out.recipient, + token: out.token, + amount: out.amount, + }, + logical: { + to: out.recipient, + data: '0x', + value: getAddress(gas) === out.token ? out.amount : BigInt(0), + }, + }); + } catch { + // Preserve the actual gateway summary when historical token metadata + // cannot be read; destination polling below still uses the known chain. + } + } try { const instruction = parseAgwSvmPayload(out.payload); const destinationInstruction = { @@ -238,7 +276,7 @@ async function adaptNativeAgentBatch( data: c.data, })); } else { - const batch = v4.decodeWalletCall(resp.data as Hex); + const batch = v5.decodeWalletCall(resp.data as Hex); if (batch?.kind !== 'execute' || batch.mode !== `0x01${'00'.repeat(31)}`) return; outer = batch.calls; @@ -248,7 +286,7 @@ async function adaptNativeAgentBatch( outer.some((c) => c.value !== BigInt(0) || c.target !== outer[0].target) ) return; - const inner = outer.map((c) => v4.decodeWalletCall(c.data)); + const inner = outer.map((c) => v5.decodeWalletCall(c.data)); const first = inner[0]; if (first?.kind !== 'executeAsAgent' || first.calls.length !== 1) return; const nativeCalls: { to: Address; value: bigint; data: Hex }[] = []; @@ -324,11 +362,18 @@ export function outboundResponseCall( function decodeOutbound(data: Hex): { payload: Hex; + recipient: Hex; + amount: bigint; token: Address; calls: { to: Address; value: bigint; data: Hex }[]; } { const { args } = decodeFunctionData({ abi: UNIVERSAL_GATEWAY_PC, data }); - const req = args?.[0] as { token: Address; payload: Hex }; + const req = args?.[0] as { + token: Address; + payload: Hex; + recipient: Hex; + amount: bigint; + }; let calls: { to: Address; value: bigint; data: Hex }[] = []; if (req.payload.toLowerCase().startsWith(UEA_MULTICALL_PREFIX)) { try { @@ -354,7 +399,13 @@ function decodeOutbound(data: Hex): { calls = []; } } - return { token: getAddress(req.token), payload: req.payload, calls }; + return { + token: getAddress(req.token), + payload: req.payload, + recipient: req.recipient, + amount: req.amount, + calls, + }; } async function tokenChain( diff --git a/packages/core/src/lib/agentic/revert.ts b/packages/core/src/lib/agentic/revert.ts index d70f2aab..a6a07daa 100644 --- a/packages/core/src/lib/agentic/revert.ts +++ b/packages/core/src/lib/agentic/revert.ts @@ -11,7 +11,7 @@ import { AGW_FACTORY_ABI, SMART_SESSION_ABI, UNIVERSAL_RULES_POLICY_ABI, -} from './contracts/abi/v4'; +} from './contracts/abi/v5'; /** URP reverts reached through the engine are truncated to this wrapper. */ export const POLICY_CHECK_REVERTED_SELECTOR = '0xf4270752'; diff --git a/packages/core/src/lib/agentic/runtime.ts b/packages/core/src/lib/agentic/runtime.ts index cf4c5ce1..0068f20e 100644 --- a/packages/core/src/lib/agentic/runtime.ts +++ b/packages/core/src/lib/agentic/runtime.ts @@ -14,6 +14,7 @@ import type { ProgressEvent } from '../progress-hook/progress-hook.types'; import { getCEAAddress } from '../orchestrator/cea-utils'; import type { OrchestratorContext } from '../orchestrator/internals/context'; import { computeUEAOffchain } from '../orchestrator/internals/uea-manager'; +import { ensureSvmFinalizeGasBudgetQuote } from '../orchestrator/internals/svm-rent'; import { queryOutboundGasFee } from '../orchestrator/internals/gas-calculator'; import { getNativePRC20ForChain, @@ -67,7 +68,8 @@ export interface AgenticRuntime { quoteOutbound( prc20: Address, gasLimit: bigint, - chain: CHAIN + chain: CHAIN, + svm?: { wallet: Address; splMintBase58?: string; burnAmount: bigint } ): Promise<{ protocolFee: bigint; nativeValueForGas: bigint; @@ -132,8 +134,20 @@ export function createAgenticRuntime( }, signerBalance: () => ctx.pushClient.getBalance(computeUEAOffchain(ctx)), getGasPrice: () => ctx.pushClient.getGasPrice(), - quoteOutbound: async (prc20, gasLimit, chain) => { - const q = await queryOutboundGasFee(ctx, prc20, gasLimit, chain); + quoteOutbound: async (prc20, gasLimit, chain, svm) => { + let q = await queryOutboundGasFee(ctx, prc20, gasLimit, chain); + if (svm) { + q = await ensureSvmFinalizeGasBudgetQuote({ + ctx, + ueaAddress: svm.wallet, + targetChain: chain, + prc20Token: prc20, + quote: q, + splMintBase58: svm.splMintBase58, + burnAmount: svm.burnAmount, + pathTag: 'AGW_SVM', + }); + } return { protocolFee: q.protocolFee, nativeValueForGas: q.nativeValueForGas, diff --git a/packages/core/src/lib/agentic/utils.ts b/packages/core/src/lib/agentic/utils.ts index 3ecb421e..2c863bd2 100644 --- a/packages/core/src/lib/agentic/utils.ts +++ b/packages/core/src/lib/agentic/utils.ts @@ -5,7 +5,7 @@ import { CHAIN, PUSH_NETWORK } from '../constants/enums'; import { MOVEABLE_TOKENS } from '../constants/tokens'; import { getPRC20Address } from '../universal/prc20-address'; import { AgenticCapability } from './capabilities'; -import { V4_CAPABILITIES } from './deployments'; +import { V5_CAPABILITIES } from './deployments'; import { actionId as actionIdRaw, configId as configIdRaw, @@ -113,7 +113,7 @@ export const internalAgenticUtils = { rulesPolicy: getAddress(ctx.rulesPolicy), gateway: ctx.gateway, universal: ctx.universal, - capabilities: V4_CAPABILITIES, + capabilities: V5_CAPABILITIES, nowSeconds: ctx.nowSeconds ?? Math.floor(Date.now() / 1000), }).map((p) => encodeSession(p.session) as AgenticHex); }, diff --git a/packages/core/src/lib/agentic/wallet.ts b/packages/core/src/lib/agentic/wallet.ts index e8b65f86..ddecd3a6 100644 --- a/packages/core/src/lib/agentic/wallet.ts +++ b/packages/core/src/lib/agentic/wallet.ts @@ -25,6 +25,7 @@ import type { } from './agentic.types'; import type { UniversalTxResponse } from '../orchestrator/orchestrator.types'; import { currentGeneration } from './deployments'; +import { assertLabel } from './management/label'; /** * Management handle for one wallet (spec 1.d). Reads work for any wallet; @@ -40,20 +41,40 @@ export class AgenticWalletHandle implements AgenticWallet { try { this.address = getAddress(address) as AgenticAddress; } catch (cause) { - throw new AgenticError(AGENTIC_ERROR_CODE.NOT_AGENTIC_WALLET, `"${address}" is not an address`, { cause }); + throw new AgenticError( + AGENTIC_ERROR_CODE.NOT_AGENTIC_WALLET, + `"${address}" is not an address`, + { cause } + ); } this.rules = { list: () => this.listRules(), get: (rulesId) => this.getRule(rulesId), - add: async (rules, opts) => addRules(this.runtime, await this.gen(), this.address, rules, opts?.progressHook), - update: async (params) => updateRules(this.runtime, await this.gen(), this.address, params), + add: async (rules, opts) => + addRules( + this.runtime, + await this.gen(), + this.address, + rules, + opts?.progressHook + ), + update: async (params) => + updateRules(this.runtime, await this.gen(), this.address, params), revoke: (async ( - target: AgenticHex[] | { all: true; progressHook?: AgenticProgressHook }, + target: + | AgenticHex[] + | { all: true; progressHook?: AgenticProgressHook }, opts?: { progressHook?: AgenticProgressHook } ) => { // Validate the target shape before any RPC so a bare revoke costs nothing. assertRevokeTarget(target); - return revokeRules(this.runtime, await this.gen(), this.address, target, opts?.progressHook); + return revokeRules( + this.runtime, + await this.gen(), + this.address, + target, + opts?.progressHook + ); }) as AgenticWallet['rules']['revoke'], }; } @@ -61,7 +82,11 @@ export class AgenticWalletHandle implements AgenticWallet { /** Deployed wallets resolve their own generation; undeployed ones use the network's current one. */ private gen(): Promise { if (!this.generation) { - this.generation = resolveWalletGeneration(this.runtime.reader, this.runtime.network, this.address); + this.generation = resolveWalletGeneration( + this.runtime.reader, + this.runtime.network, + this.address + ); this.generation.catch(() => { this.generation = undefined; }); @@ -74,44 +99,91 @@ export class AgenticWalletHandle implements AgenticWallet { try { gen = await this.gen(); } catch (err) { - if (err instanceof AgenticError && err.code === AGENTIC_ERROR_CODE.WALLET_NOT_DEPLOYED) { + if ( + err instanceof AgenticError && + err.code === AGENTIC_ERROR_CODE.WALLET_NOT_DEPLOYED + ) { gen = currentGeneration(this.runtime.network); } else { throw err; } } requireCapability(gen.capabilities, AgenticCapability.WALLET_READS); - return walletInfo(this.runtime.reader, gen, this.address, this.signerIdentity()); + return walletInfo( + this.runtime.reader, + gen, + this.address, + this.signerIdentity() + ); } async owner(): Promise<{ owner: AgenticAddress }> { const gen = await this.gen(); - return { owner: (await walletOwner(this.runtime.reader, gen, this.address)) as AgenticAddress }; + return { + owner: (await walletOwner( + this.runtime.reader, + gen, + this.address + )) as AgenticAddress, + }; } - async setLabel(label: string, _opts?: { progressHook?: AgenticProgressHook }): Promise { - return setLabel(this.runtime, await this.gen(), this.address, label); + async setLabel( + label: string, + opts?: { progressHook?: AgenticProgressHook } + ): Promise { + assertLabel(label); + return setLabel( + this.runtime, + await this.gen(), + this.address, + label, + opts?.progressHook + ); } - async checkpoints(opts?: { sinceBlock?: bigint }): Promise<{ checkpoints: Checkpoint[] }> { + async checkpoints(opts?: { + sinceBlock?: bigint; + }): Promise<{ checkpoints: Checkpoint[] }> { const gen = await this.gen(); - const { checkpoints } = await readCheckpoints(this.runtime.reader, gen, this.address, opts?.sinceBlock); + const { checkpoints } = await readCheckpoints( + this.runtime.reader, + gen, + this.address, + opts?.sinceBlock + ); return { checkpoints }; } private async listRules(): Promise<{ rules: RulesRecord[] }> { const gen = await this.gen(); const snap = await Snapshot.at(this.runtime.reader); - return { rules: await listRules(snap, gen, this.address, this.runtime.pushChainNamespace) }; + return { + rules: await listRules( + snap, + gen, + this.address, + this.runtime.pushChainNamespace + ), + }; } private async getRule(rulesId: AgenticHex): Promise { if (typeof rulesId !== 'string' || !/^0x[0-9a-fA-F]{64}$/.test(rulesId)) { - throw new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, 'rulesId must be a 32-byte hex string'); + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'rulesId must be a 32-byte hex string' + ); } const gen = await this.gen(); const snap = await Snapshot.at(this.runtime.reader); - return getRule(snap, gen, this.address, rulesId, this.runtime.pushChainNamespace); + return getRule( + snap, + gen, + this.address, + rulesId, + this.runtime.pushChainNamespace + ); } private signerIdentity(): Address | undefined { diff --git a/packages/core/src/lib/constants/index.ts b/packages/core/src/lib/constants/index.ts index 9eb7cdcf..a9ee4211 100644 --- a/packages/core/src/lib/constants/index.ts +++ b/packages/core/src/lib/constants/index.ts @@ -71,7 +71,7 @@ export const CONSTANTS = { MOVEABLE: { TOKEN: MOVEABLE_TOKEN_CONSTANTS }, PAYABLE: { TOKEN: PAYABLE_TOKEN_CONSTANTS }, READ: READ_CONSTANTS, - /** Checked v4 agentic wallet deployments by Push network (Donut only). */ + /** Checked v5 agentic wallet deployments by Push network (Donut only). */ AGENTIC, }; diff --git a/plan/agw/README.md b/plan/agw/README.md index 344a51d1..b03aa8d3 100644 --- a/plan/agw/README.md +++ b/plan/agw/README.md @@ -1,13 +1,15 @@ # AGW SDK planning -This package contains planning, source snapshots and review evidence for `feat/agw-sdk-v4`. Current runtime uses Donut v4 source `e8db748`; legacy runtime adapters have been removed. +This package contains planning, source snapshots and review evidence for `feat/agw-sdk-v4`. Current runtime uses Donut v5 source `2e61e13`; legacy runtime adapters have been removed. -**October 7:** product decisions are settled. Public named-IDL Solana lifecycle/sends/reads/replay are implemented, rule `ref` is removed, zero native PC defaults are confirmed, and native/EVM raw-offset authoring is approved. Seven additional E2Es passed on Donut/devnet, bringing the opt-in AGW group to 46 scenarios with selected-run live coverage. The final local/unit/build results are in [implementation status](implementation-status.md). +**October 7:** product decisions are settled. Public named-IDL Solana lifecycle/sends/reads/replay are implemented, rule `ref` is removed, zero native PC defaults are confirmed, and native/EVM raw-offset authoring is approved. Seven additional E2Es passed on Donut/devnet, bringing the opt-in AGW group to 46 scenarios at that checkpoint; the subsequent fixes extend it to 48 scenarios with selected-run live coverage. The final local/unit/build results are in [implementation status](implementation-status.md). -The remaining AGW contract delivery item is editable labels. The existing agent door already validates the supplied rule; the SDK retains its ambiguity guard when several candidates match. [Zaryab delivery items](questions-zaryab.md); [confirmed decisions](questions-harsh.md). +Editable labels are now delivered and integrated through v5; no standalone contract delivery item remains. The existing agent door already validates the supplied rule; the SDK retains its ambiguity guard when several candidates match. [Zaryab delivery items](questions-zaryab.md); [confirmed decisions](questions-harsh.md). Consumer documentation lives in [packages/core/AGW.md](../../packages/core/AGW.md). Earlier dated reports below are historical evidence; their pending-capability statements describe those earlier revisions. +Latest source check: [full October 7 Notion/contract refresh](research/source-refresh-2026-10-07/README.md). Only the create-example ref line changed in that Notion export; a later v5 deployment adds stored wallet labels. See [v5 migration](research/v5-implementation-2026-10-07/README.md). G27/G28 are now closed by [SDK alignment fixes](research/sdk-alignment-fixes-2026-10-07/README.md): contract-derived policy errors and public owner funds-only SOL/SPL requests. + ## Start here | Document | Purpose | @@ -15,7 +17,7 @@ Consumer documentation lives in [packages/core/AGW.md](../../packages/core/AGW.m | [Consumer AGW guide](../../packages/core/AGW.md) | Public SDK examples for creation, funding, rules, execution and recovery | | [Current baseline](current-baseline.md) | Source revisions, capabilities and remaining differences | | [SDK design review](sdk-design-review.md) | Proposed internal architecture and execution flows | -| [Gap register](gaps.md) | Current G01–G26 findings and closure criteria | +| [Gap register](gaps.md) | Current G01–G28 findings and closure criteria | | [SDK owned review](sdk-owned-review.md) | Internal decisions, existing-code evidence and 183 passing unit tests | | [Implementation plan](implementation-plan.md) | Complete 17-step roadmap, module layout, assumptions, API coverage and PR sequence | | [Implementation agent prompt](implementation-agent-prompt.md) | Handoff instructions, unit/E2E requirements and existing runner conventions | @@ -39,3 +41,5 @@ Consumer documentation lives in [packages/core/AGW.md](../../packages/core/AGW.m Older planning revisions, duplicated exports, superseded validation runs and the full independent-review working package were archived locally outside this repository. The review summary preserves the key corrections. Historical paths in the retained prior manifest describe the earlier pull and may refer to pruned archives. Before sharing questions, refresh remote refs and Notion again, record exact revisions and remove questions answered by newer evidence. No team messages or contract deployments have been sent by this work. Authorized, bounded testnet transactions are recorded in the live acceptance evidence. + +Latest coverage: [five added v5 E2Es and metadata fix](research/extended-v5-e2e-2026-10-07/README.md). All five new scenarios have live passing evidence. The AGW group registers 58 cases; default `all` is unchanged. Fresh Sepolia CEA delivery currently uses an explicit destination-gas budget in tests/examples; the upstream default remains a follow-up. diff --git a/plan/agw/SOURCES.md b/plan/agw/SOURCES.md index f9f7a793..aa9eb455 100644 --- a/plan/agw/SOURCES.md +++ b/plan/agw/SOURCES.md @@ -1,8 +1,12 @@ # AGW source links and refresh procedure +**Latest refresh — October 7, 2026:** all 12 Notion pages downloaded/imported (1 changed, 11 unchanged), current discussions inspected where exposed, and all three contract repositories fetched. AGW/gateway code is unchanged; core marketplace head `9479aef` adds docs only over `cb69e0b`. Donut code/wiring and Solana program fingerprints match prior probes. [Refresh report, evidence and SDK alignment findings](research/source-refresh-2026-10-07/README.md). + +The dated entries below preserve earlier observations and decisions; use the October 7 report and current decision documents for present status. + October 6 contract refresh: fetched deploy-agw@10a24f101e2e6e0a9b76517b29f5cdb1aa967796; address book/owner guide report deployed source e8db74815cfbbf5389593805e464fe8d85f7f735, with no src difference between those commits. [GitHub snapshots/hashes, verified ABIs, Donut read-only evidence and SDK review](research/deployment-review-2026-10-06/README.md). This does not replace the Notion full-export manifest or imply SDK v4 support is already registered. -Latest complete Notion export: October 3, 2026 at 13:23 IST. All 12 pages were imported; pages 1 and 5 changed. Page 5 defines the target public SDK API. Native exports omit comment threads. +Latest complete Notion export: October 7, 2026 at 15:57 IST. All 12 pages were imported; only page 5 changed (create-example ref removed). Page 5 defines the target public SDK API. Native exports omit comment threads. Focused October 4 recheck: page 5 was downloaded again; its body matches the saved snapshot after normalizing links. [Comparison evidence](research/notion-check-2026-10-04/comparison.json). This was not a full refresh and does not replace the full-import manifest. Harsh’s newer replies are recorded separately in [product decisions](product-decisions-2026-10-04.md). @@ -33,8 +37,8 @@ The [manifest](source-manifest.json) stores stable page IDs, pull times and hash ## Contract sources -- **Current deployment source:** [AGW e8db748](https://github.com/pushchain/push-agentic-wallets/tree/e8db74815cfbbf5389593805e464fe8d85f7f735). -- **Current documentation:** [owner SDK guide](https://github.com/pushchain/push-agentic-wallets/blob/10a24f101e2e6e0a9b76517b29f5cdb1aa967796/docs/5_SDK_Owner_Integration.md), [v4 Donut address book](https://github.com/pushchain/push-agentic-wallets/blob/10a24f101e2e6e0a9b76517b29f5cdb1aa967796/docs/addresses/donut.md). Refreshable branch links: [guide](https://github.com/pushchain/push-agentic-wallets/blob/deploy-agw/docs/5_SDK_Owner_Integration.md), [addresses](https://github.com/pushchain/push-agentic-wallets/blob/deploy-agw/docs/addresses/donut.md). +- **Current deployment source:** [AGW 2e61e13](https://github.com/pushchain/push-agentic-wallets/tree/2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb). +- **Current documentation:** [owner SDK guide](https://github.com/pushchain/push-agentic-wallets/blob/bd230d20dbf778d9994b1f1082f79b1a8829a10f/docs/5_SDK_Owner_Integration.md), [v5 Donut address book](https://github.com/pushchain/push-agentic-wallets/blob/bd230d20dbf778d9994b1f1082f79b1a8829a10f/docs/addresses/donut.md). Refreshable branch links: [guide](https://github.com/pushchain/push-agentic-wallets/blob/deploy-agw/docs/5_SDK_Owner_Integration.md), [addresses](https://github.com/pushchain/push-agentic-wallets/blob/deploy-agw/docs/addresses/donut.md). - **Earlier SDK fixture source:** [AGW e704d5b](https://github.com/pushchain/push-agentic-wallets/tree/e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9); nomenclature-changes was merged and deleted. - [AGW design](https://github.com/pushchain/push-agentic-wallets/blob/e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9/docs/1_AGW.md) and [policy design](https://github.com/pushchain/push-agentic-wallets/blob/e704d5b58fd1d30ce02bc0ad74dccfbdb37804f9/docs/2_UniversalRulesPolicy.md). - [Core marketplace cb69e0b](https://github.com/pushchain/push-chain-core-contracts/tree/cb69e0ba101bef1bb4440e54b2c45396be3e92ce). @@ -61,3 +65,5 @@ python3 plan/agw/scripts/import-notion-exports.py overview.zip legacy-sdk.zip ad Use actual ZIP paths. The script does not download or authenticate to Notion. It rejects conflicting inputs or locally edited snapshots, requires all registered pages unless --partial is explicitly used, and reports unexpected page IDs. Last-edited observations are not inferred from download time. No scheduled refresh is configured. The historical SDK refers to AGW-SDK-v1-agent.md, 05-universal-marketplace-startjob.md and SDK_HELPER.md. Their source URLs/files were not included in its export; those original unresolved references remain as written. + +October 7 v5 deployment: label contract dependency delivered. [New source snapshots and live read-only check](research/deployment-review-2026-10-07-v5/README.md); [SDK implementation and test evidence](research/v5-implementation-2026-10-07/README.md). Earlier dated deployment statements above are historical. diff --git a/plan/agw/current-baseline.md b/plan/agw/current-baseline.md index d7568499..40fbc3f3 100644 --- a/plan/agw/current-baseline.md +++ b/plan/agw/current-baseline.md @@ -1,38 +1,38 @@ # Current validated AGW baseline -Updated October 7, 2026 after confirmed product decisions, fresh contract refs, and public Solana/native acceptance. **The v4 deployment and native/EVM SDK adapter/codecs are integrated locally. The opt-in `agw` group now includes 46 scenarios with selected-run live coverage: 39 previous cases and seven decision-alignment cases.** [Extended E2E evidence](research/extended-e2e-2026-10-06/README.md); [full deployment review](research/deployment-review-2026-10-06/README.md). +Updated October 7, 2026 after confirmed product decisions, fresh contract refs, and public Solana/native acceptance. **The v5 deployment and native/EVM SDK adapter/codecs are integrated locally. The opt-in `agw` group now includes 58 scenarios with selected-run live coverage, including owner funds-only Solana transfers and mapped policy refusals.** [Extended E2E evidence](research/extended-e2e-2026-10-06/README.md); [full deployment review](research/deployment-review-2026-10-06/README.md). -The public SDK target remains Notion page 5, qualified by Harsh's later replies/comments. The new owner guide establishes deployed wire behavior; the October 7 decisions remove rule ref, confirm defaults and existing ambiguity handling, and leave editable labels pending contract delivery. [Prior October 3–5 baseline](research/deployment-review-2026-10-06/previous-current-baseline.md) is retained as historical evidence. +The public SDK target remains Notion page 5, qualified by Harsh's later replies/comments. The new owner guide establishes deployed wire behavior; the October 7 decisions remove rule ref, confirm defaults and existing ambiguity handling, and include the delivered v5 editable-label interface. [Prior October 3–5 baseline](research/deployment-review-2026-10-06/previous-current-baseline.md) is retained as historical evidence. ## Pinned sources | Source | Revision and role | | --- | --- | -| AGW deployment source | e8db74815cfbbf5389593805e464fe8d85f7f735, reported by address book/owner guide | -| AGW documentation | deploy-agw@10a24f101e2e6e0a9b76517b29f5cdb1aa967796; src identical to e8db748 | -| SDK contract adapter | V4 only (e8db748); Donut registry populated; old runtime/test generation removed | -| Core marketplace | Prior pin cb69e0ba101bef1bb4440e54b2c45396be3e92ce; not freshly fetched | -| Gateway source | Prior eight-field pin bcbf7df42e8e6dd11088a43bcc0b056a54ea0a18; live implementation slot checked | -| Notion | Last full export October 3 at 13:23 IST; October 4 body comparison, October 5 comments, October 6 live pages 1/5 and All discussions inspection; no new export | +| AGW deployment source | 2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb, reported by address book/owner guide | +| AGW documentation | deploy-agw@bd230d20dbf778d9994b1f1082f79b1a8829a10f; includes the v5 deployment and label docs | +| SDK contract adapter | V5 only (2e61e13); Donut registry populated; old runtime/test generation removed | +| Core marketplace | Refreshed universalMarketplace_v1@9479aeff5291bb06fa306f7efa98be9c45324cb0; docs-only advance over cb69e0b, source unchanged | +| Gateway source | Refreshed pc20-3rd-iteration@bcbf7df42e8e6dd11088a43bcc0b056a54ea0a18; code and live implementation slot unchanged | +| Notion | Full 12-page export October 7 at 15:57 IST; page 5 create-example ref removed; current primary discussions reviewed | -[Saved GitHub sources and hashes](research/deployment-review-2026-10-06/source-manifest.json) are separate from the Notion manifest. [Verified ABIs](research/deployment-review-2026-10-06/abis/) came from the explorer. This review did not locally rebuild runtime bytecode or rerun the full contract/SDK suites. +[Saved GitHub sources and hashes](research/deployment-review-2026-10-06/source-manifest.json) are separate from the Notion manifest. [Verified ABIs](research/deployment-review-2026-10-06/abis/) came from the explorer. The earlier October 6 wire review is historical. [V5 SDK migration and acceptance](research/v5-implementation-2026-10-07/README.md) records the latest rebuild and test results. -## Donut v4 deployment +## Donut v5 deployment -Chain 42101, RPC https://evm.donut.rpc.push.org/, pinned block **23931055**. [Probe](research/deployment-review-2026-10-06/donut-probe.json). +Chain 42101, RPC https://evm.donut.rpc.push.org/, pinned block **23991912**. [Probe](research/deployment-review-2026-10-07-v5/donut-probe.json). | Component | Address | | --- | --- | -| Factory proxy | 0xaF88D0FD947afAe7bBb8F34e8417DCfc165e1aaF | +| Factory proxy | 0x8137F96A50EBF41d904e3678c84c391a0D1BCcc5 | | URP proxy | 0x603E7f0aF6e1aAFf46DDfb28b1e99364f8BC59af | -| Wallet implementation | 0x96D69ec7e6cDdaD414e656B5c9DCA24587DF713c | +| Wallet implementation | 0x4D459Da499C14548aa16c46c57fD92880A88EBb4 | | AgentValidator | 0x068EE2388475A98EE1f5a434C58bFF3444fffFe6 | | SmartSession | 0x165A5E6782f39D30B38c7D97e1303e4CB2aD102a | | Gateway | 0x00000000000000000000000000000000000000C1 | -Code sizes, factory/policy implementation slots, policy admin and wallet/policy wiring match the new book. Factory is unpaused; URP version is 3.1.0; pushChainHash matches eip155:42101. Wallet accountId remains push.agw.1.0.0 and is insufficient to distinguish envelope generations. Address book reports deployment blocks 23923806–23923810; release manifest should preserve deployment/log provenance. +Code sizes, factory/policy implementation slots, policy admin and wallet/policy wiring match the new book. Factory is unpaused; URP version is 3.1.0; pushChainHash matches eip155:42101. Wallet accountId remains push.agw.1.0.0 and is insufficient to distinguish envelope generations. Address book reports deployment blocks 23989983–23989987; release manifest should preserve deployment/log provenance. -The earlier supplied historical addresses are superseded for new v4 integrations. Wallet clones remain generation-specific and do not migrate; prediction is stable within its factory context, not globally across factories. +The earlier supplied historical addresses are superseded for new v5 integrations. Wallet clones remain generation-specific and do not migrate; prediction is stable within its factory context, not globally across factories. ## Compatibility and remaining work @@ -41,30 +41,32 @@ The earlier supplied historical addresses are superseded for new v4 integrations | Owner/agent doors | execute and sender-gated executeAsAgent; unchanged SmartSession | Preserve model, adapt/test selected generation; no engine fork | | Session/IDs | abi.encode(agent), salt overwritten by grantNonce; rulesId wallet-scoped | Existing identity logic retained, new validator context | | All policy envelopes | uint16 version=1, chainNamespace, body | Envelope 1 implemented; old envelope rejected by actual contracts | -| Universal EVM | 1–8 ordered AssetCaps, maxGasPerCall, address expectedCEA | Implemented, including source-chain/token identity validation and v4 reads | +| Universal EVM | 1–8 ordered AssetCaps, maxGasPerCall, address expectedCEA | Implemented, including source-chain/token identity validation and v5 reads | | No-movement rules | One destination gas PRC20 cap at 0/0 when user assets empty | Implemented; actual-contract call-only case passes | | Total ceilings | maxUint256 unlimited, zero hard zero | Universal max default/explicit zero and confirmed zero native PC defaults implemented | | Internal replacement guard | assertSpent(configId,wallet,uint256[]) compares all totals in asset order | SDK implemented; second-token intervening spend rolls back replacement | -| Native terms | Same body layout, one config per action; envelope changed | V4 native tests pass; ABI offset validation retained | +| Native terms | Same body layout, one config per action; envelope changed | V5 native tests pass; ABI offset validation retained | | Multiple rules | Several same-agent/same-chain grants supported | Management permits multiplicity; ambiguous sends are refused by the SDK, and the contract enforces the supplied rule | | Checkpoints | Stored count/last block, three event kinds, per-owner-call/lifecycle ticks | Local and registered live native/EVM lifecycle acceptance pass | -| Grant ref / label | Grant has no ref; label is deployment event only; no setLabel | Rule ref removed from SDK scope; editable labels await contract delivery | +| Grant ref / label | Grant has no ref; label stored on wallet; owner/self setLabel, 64-byte cap, empty reset | Ref removed; v5 labels implemented. SDK owner-door rename adds one checkpoint | | SVM | Full multi-asset terms/program/account/data pins supplied | Public named-IDL grants/reads/replacement/sends/revoke pass live, including destination CEA transfer and replay; unsupported IDL layouts are rejected explicitly. Prior internal rejection/terminal replay evidence remains valid. | | Gateway request | Eight-field live implementation, selector 0x77b86bec | Dedicated context, listed-token choice and maxGasPerCall implemented | | Allowance | Consume separate owner-established allowance | Keep existing race-safe behavior; Live allowance/token debit passes; remaining identity coverage explicit | | Refund spend credit | creditRevert gains token; executor still does not call it | Known Push-core dependency; ordinary returns do not lower spent | | Tracking/events | Metered/revert events include token | ABIs/imports updated; live call-only, positive-amount and external-failure tracking pass | -The ABI comparison found matching factory/wallet/engine function/event/error signatures and return shapes, but changed policy getters, assertions, credit and events. Same wallet ABI does not imply same semantics: its envelope decoder changed. [Comparison](research/deployment-review-2026-10-06/abi-comparison.json). +The historical v3-to-v4 ABI comparison found changed policy getters, assertions, credit and events. [Comparison](research/deployment-review-2026-10-06/abi-comparison.json). V5 additionally changes the wallet initializer and adds label functions/event/error; those updated ABIs are generated from the isolated v5 build. ## Focused verification Four checks passed: version-1 envelope round-trip/old first-word incompatibility; synthetic ordered two-asset tuple round-trip; live v4 getConfig decode with old-ABI rejection; array assertion encoding. [Results and limits](research/deployment-review-2026-10-06/wire-checks.json). This is not a rule-grant, stale-spend transaction or funded E2E proof. -See [implementation status](implementation-status.md) for the final unit and actual-contract counts. All five explorer ABI sets match the isolated build. Donut is registered and all 46 AGW native/EVM/identity/management/policy/public-Solana cases have passing selected-run live coverage. The `agw` group remains opt-in; default `all` remains 76 scenarios. [Extended E2E evidence](research/extended-e2e-2026-10-06/README.md); [prior acceptance evidence](research/live-acceptance-2026-10-06/README.md). +See [implementation status](implementation-status.md) for the final unit and actual-contract counts. All five explorer ABI sets match the isolated build. Donut is registered and all 48 registered AGW native/EVM/identity/management/policy/public-Solana cases have passing selected-run live coverage. The `agw` group remains opt-in; default `all` remains 76 scenarios. [Extended E2E evidence](research/extended-e2e-2026-10-06/README.md); [prior acceptance evidence](research/live-acceptance-2026-10-06/README.md). ## Remaining delivery and acceptance +The [full source refresh](research/source-refresh-2026-10-07/README.md) found SDK alignment follow-ups G27/G28: policy-preflight/error parity and Solana owner funds-only support. Both are now fixed and validated in the [follow-up report](research/sdk-alignment-fixes-2026-10-07/README.md). Contract/code deployment drift was not found. + Product choices are settled: zero native PC defaults, current token budgets, named IDL Solana authoring, dual native/EVM argument-index/raw-offset inputs, and removal of rule ref. The implementation and seven new selected live cases cover these choices. Zaryab delivery is still needed for editable labels. The existing contract already enforces the supplied rule and rejects unauthorized actions. Keep AMBIGUOUS_RULE for multiple candidates; no automatic-selection interface or caller-facing selector is required. [Delivery items](questions-zaryab.md). @@ -74,3 +76,5 @@ Public Solana acceptance now passes. Source-authoring supports fixed Anchor layo Checkpoint count semantics remain per action, not per transaction: assert/revoke/grant adds five ticks; failed transactions unwind ticks; agent calls do not tick. Pre-existing allowances may change balances without checkpoints. Preserve internal spend assertions even though public spent records are removed. The historical [October 6 source recheck](research/question-source-recheck-2026-10-06/README.md) records unchanged contract heads; the October 7 fetch confirmed the same refs. It records answered definitions separately from remaining public decisions and SDK-owned fixture validation; it does not claim a fresh live bytecode probe. + +Current v5 acceptance: 2,014 units and 90 actual-contract SDK cases pass. Expanded live evidence covers labels, native/lifecycle behavior, EVM, native SOL and SPL destinations; the full 58-case group has not run in one invocation. [Expanded results](research/extended-v5-e2e-2026-10-07/README.md). Fresh Sepolia CEA positive cases use an explicit 2m destination-gas budget; the current upstream 500k default was insufficient. SPL quoting/authoring/reads now handle absent source-mint metadata through the existing verified-chain token registry. diff --git a/plan/agw/gaps.md b/plan/agw/gaps.md index a09378e7..0b64428d 100644 --- a/plan/agw/gaps.md +++ b/plan/agw/gaps.md @@ -1,18 +1,16 @@ # AGW contract and SDK gap register -**October 7 alignment:** all product choices are settled. Named-IDL Solana integration and removal of rule `ref` are implemented; raw-offset inputs remain supported. Editable labels await Zaryab’s interface/deployment. Contract validation already exists; retain the SDK ambiguity guard. [Current delivery items](questions-zaryab.md). +**October 7 alignment:** all product choices are settled. Named-IDL Solana integration and removal of rule `ref` are implemented; raw-offset inputs remain supported. Editable labels are delivered and implemented against v5. Contract validation already exists; retain the SDK ambiguity guard. [Current delivery items](questions-zaryab.md). -Updated October 7, 2026 following the clarified contract-enforcement decision, the [v4 deployment/owner-guide review](research/deployment-review-2026-10-06/README.md), [Harsh’s replies](product-decisions-2026-10-04.md), v4 implementation on feat/agw-sdk-v4, and [live Notion comments](research/notion-comments-2026-10-05.md). This register distinguishes unresolved dependencies, implemented SDK work, deferred scope and historical corrections. G01–G26 are tracking IDs, not a count of open defects. +Updated October 7, 2026 following the clarified contract-enforcement decision, the [v4 deployment/owner-guide review](research/deployment-review-2026-10-06/README.md), [Harsh’s replies](product-decisions-2026-10-04.md), v4 implementation on feat/agw-sdk-v4, and [live Notion comments](research/notion-comments-2026-10-05.md). This register distinguishes unresolved dependencies, implemented SDK work, deferred scope and historical corrections. G01–G30 are tracking IDs, not a count of open defects. -Evidence: [current baseline](current-baseline.md), [implementation status](implementation-status.md), [product alignment validation](research/product-alignment-2026-10-04/README.md), and [extended live E2Es](research/extended-e2e-2026-10-06/README.md). The final validation counts are in [implementation status](implementation-status.md). The opt-in AGW group now registers 46 cases; seven new cases passed on Donut/devnet. Default `all` remains unchanged. +Evidence: [current baseline](current-baseline.md), [implementation status](implementation-status.md), [product alignment validation](research/product-alignment-2026-10-04/README.md), and [extended live E2Es](research/extended-e2e-2026-10-06/README.md). The final validation counts are in [implementation status](implementation-status.md). The opt-in AGW group now registers 58 cases; seven new cases passed on Donut/devnet. Default `all` remains unchanged. -Current contract baseline: reported deployed source `e8db748`, documentation head `deploy-agw@10a24f1` (src unchanged between them). Donut v4 addresses/code/wiring and URP 3.1.0 were checked at block 23931055; verified ABIs were saved. The SDK now uses v4 only, registers Donut and has a ported actual-contract harness. [Implementation evidence](research/v4-implementation-2026-10-06/README.md). Core marketplace cb69e0b and gateway bcbf7df remain prior source pins; they were not freshly fetched. Notion bodies were not refreshed in this pass. +Current contract baseline: deployed source `2e61e13`, documentation head `deploy-agw@bd230d2`. Donut v5 code, wiring and the unchanged URP 3.1.0 were checked at block 23991912. The SDK uses v5 only; labels are read on-chain and owner renames are implemented. [Verification](research/deployment-review-2026-10-07-v5/README.md); [SDK migration](research/v5-implementation-2026-10-07/README.md). Core marketplace `9479aef` is a docs-only advance over `cb69e0b`; gateway `bcbf7df` is unchanged. All 12 Notion bodies were refreshed earlier on October 7; that export predates this label delivery. ## Remaining standalone external dependencies -| Dependency | Owner | Related IDs | -| --- | --- | --- | -| Editable labels: contract ABI/deployment | [Zaryab](questions-zaryab.md#z1-3) | G08 | +None for the implemented standalone SDK surface. G08 is closed by the delivered v5 labels and SDK integration. Refund spend credit and retry/terminalization timing remain separate downstream dependencies. The [October 6 source recheck](research/question-source-recheck-2026-10-06/README.md) narrowed the questions. Subsequent [live wire validation](research/live-svm-wire-2026-10-06/README.md) supplies our own Solana fixture and successful delivery/replay, closing Z1.4. The rejected outbound initially timed out, then reached REVERTED and read-only replay classified it failed. [Concrete API proposals](public-api-proposals.md) are ready; retry/terminalization timing is an operational follow-up. @@ -33,7 +31,7 @@ P0 blocks agreed authorization/accounting or safe final integration. P1 affects | G05 | P1 | Downstream marketplace alignment | Core cb69e0b requires rule/job expiry equality; supporting Notion pages have conflicting inequalities. | Align the marketplace/compiler track. Do not impose job equality on every standalone AGW rule. | | G06 | P2 | Closed for v1 | Binder was never in the reviewed code and is dropped for v1. | No binder implementation or binder-dependent lifecycle requirement in standalone AGW. Preserve historical snapshots as evidence. | | G07 | P1 | Known platform dependency | creditRevert depends on Push-core executor work. Until delivered, a far-side failure can leave spend inflated. | Track platform delivery and document/test the limitation. This is not an unanswered AGW redesign question. | -| G08 | P1 | Label delivery pending; ref removed | Public rule ref has been removed; checkpoint refs remain. Editable labels are approved but absent from the inspected ABI. | Verify Zaryab’s label interface/deployment before enabling. | +| G08 | P1 | Closed: v5 labels implemented; ref removed | Stored labels, empty reset and a 64 UTF-8 byte cap are delivered; SDK reads and owner writes are implemented. Checkpoint refs remain. | Unit/local and selected live v5 acceptance are recorded in the migration report. | | G09 | P1 | Deferred from standalone AGW | Canonical card schema/encoding remains a marketplace issue. Harsh H5 removes compileCard from standalone AGW; its public stub was removed. | Resume schema/compiler vectors under the future marketplace scope, not as an AGW release blocker. | | G10 | P1 | Downstream marketplace scope | Current marketplace binds one EVM chain and one rulesId; broader card binding remains unresolved downstream. | Align future marketplace/job cardinality. Standalone AGW does not invent multi-rule job bindings. | | G11 | P1 | Downstream job dependency | Payment-token selection differs between the target job SDK and the one-token-per-deployment kernel. | Align selected K-12/deployment design in the job track. | @@ -53,6 +51,20 @@ P0 blocks agreed authorization/accounting or safe final integration. P1 affects | G25 | P1 | SDK choice approved and implemented | Native/EVM authoring accepts argument indexes or raw offsets; reads preserve exact values. Conflicting forms are rejected. | Decoded native rule re-grant E2E passes. | | G26 | P1 | Closed: existing selection behavior retained | The SDK refuses multiple matching candidates with AMBIGUOUS_RULE. The contract validates the supplied rule and rejects unauthorized actions; errors are mapped. | Maintain ambiguity and rejection coverage. No selection ABI change is required. | +The [October 7 full source refresh](research/source-refresh-2026-10-07/README.md) identified two SDK-owned alignment follow-ups. Both are now implemented and validated; see the [fix report](research/sdk-alignment-fixes-2026-10-07/README.md). They add no contract-delivery questions. + +| ID | Priority | Status | Finding | Action | +| --- | --- | --- | --- | --- | +| G27 | P1 | Closed: contract-derived policy errors | Production SVM sends build requests without evaluating granted policy. The contract/simulation enforces expiry, amounts and account/data constraints; refusals use AgenticRevertError and decodedError. EVM local PC-cap/asset-membership rejection was removed. | Maintain real-contract/live error-type and no-state-change coverage. Structural/context/funding guards remain SDK errors. | +| G28 | P2 | Closed: owner funds-only route | Owners can send SOL/SPL funds without an instruction/IDL, with separate allowance/balance guards, wallet-specific finalize/rent quote and destinationTransfer metadata. Agents still require an instruction. | SOL and SPL delivery, wallet debit, allowance consumption and replay pass live on v5. | + +The [expanded v5 acceptance](research/extended-v5-e2e-2026-10-07/README.md) added five scenarios and found these additional integration details: + +| ID | Priority | Status | Finding | Action | +| --- | --- | --- | --- | --- | +| G29 | P1 | SDK caller workaround verified; default gas remains upstream | The Core/relayer default of 500k destination gas failed fresh Sepolia CEA finalization; the identical call estimated ~1.3m. Positive cases with explicit 2m gas passed. | Keep the explicit destination budget in examples/tests. Core/gateway should revisit its fresh-CEA default; no new AGW interface is needed. One explicit-budget run also timed out before a later fresh-fixture pass; latency is not a confirmed SDK defect. | +| G30 | P1 | Closed: SVM source-mint resolution | The SPL precompile's mint getter returns a zero word, incompatible with string decoding. SDK metadata/quote/authoring/reads now resolve known mappings from the existing chain-specific registry and reject unknown mappings. Hex mint inputs normalize to base58 for PRC20 lookup. | Regression units, actual-contract suites and the funded SPL transfer/replay pass. No mint or token-program address is guessed. | + ## Validation and release boundaries The [existing acceptance evidence](research/live-acceptance-2026-10-06/README.md) records the original native/EVM coverage. The [extended report](research/extended-e2e-2026-10-06/README.md) records 1,982 passing unit tests, build/typechecks, and 14/14 additional funded tests; default all remains 76. Extended cases cover management races/batching and native policy pins, caps and rollback. Public Solana destination transfer, rule lifecycle, refusals and replay now pass selected live coverage. diff --git a/plan/agw/implementation-plan.md b/plan/agw/implementation-plan.md index 5e90616b..1c7a993c 100644 --- a/plan/agw/implementation-plan.md +++ b/plan/agw/implementation-plan.md @@ -1,4 +1,8 @@ -# Complete AGW SDK implementation plan +# AGW SDK implementation plan + +**Current implementation, October 7:** runtime and contract harness use v5 source `2e61e13`. Public named-IDL SVM, owner funds-only sends and contract error mapping are implemented. Stored wallet labels and `setLabel` are now implemented. Ref, compileCard and historical reads remain outside standalone v1. See [current status](implementation-status.md) and [v5 acceptance](research/v5-implementation-2026-10-07/README.md); older dated steps and validation counts below describe the original handoff. + +## Original handoff — October 6 (historical) Updated October 6, 2026. The v4-only native/EVM implementation uses deployed source e8db748 and the Donut manifest. Old runtime/test adapters and single-asset codecs are removed. The unfiltered unit suite passes 1,981 tests; all 75 actual-contract Anvil cases pass; build and four typechecks pass. All 25 registered AGW live scenarios pass across selected runs; remaining work is public SVM integration and release scope decisions. [Current acceptance and remaining coverage](research/live-acceptance-2026-10-06/README.md). diff --git a/plan/agw/implementation-status.md b/plan/agw/implementation-status.md index 7a357122..2a3b9519 100644 --- a/plan/agw/implementation-status.md +++ b/plan/agw/implementation-status.md @@ -1,38 +1,42 @@ # AGW SDK implementation status -> October 7: [decision alignment and acceptance](research/decision-alignment-2026-10-07/README.md). All settled SDK choices are implemented. The remaining AGW contract delivery item is editable labels. +**Latest v5 integration:** the new factory, source/artifacts, stored label reads and owner-only rename/reset are integrated. [V5 validation](research/v5-implementation-2026-10-07/README.md) distinguishes current tests from earlier v4 evidence. + +**Fresh alignment review:** [October 7 source refresh](research/source-refresh-2026-10-07/README.md) confirms stable deployed code and identified SDK follow-ups G27 (policy-preflight/error parity) and G28 (Solana owner funds-only support). Both are now fixed; [follow-up validation](research/sdk-alignment-fixes-2026-10-07/README.md) records contract-derived errors and actual SOL transfer/replay. + +> October 7: [decision alignment and acceptance](research/decision-alignment-2026-10-07/README.md). All settled SDK choices are implemented. Editable labels are now delivered and implemented against v5; no standalone contract delivery item remains. ## Validation | Level | Current evidence | | --- | --- | -| Unit | 1,999 passed, 0 failed; 12 skipped | -| Actual contracts | 81 passed, 0 failed across 11 Anvil suites | -| New funded tests | 3 native cases + 4 public Solana cases pass; exact default-policy refusal rerun passes | +| Unit | 2,014 passed, 0 failed; 12 skipped | +| Actual contracts | 90 passed, 0 failed across 12 Anvil suites | +| New funded tests | Expanded v5 labels, native/lifecycle, EVM, SOL and SPL cases pass across selected runs; [new report](research/extended-v5-e2e-2026-10-07/README.md) records individual runs and the gas-default issue | | Build/typechecks | Build and lib/spec/local/AGW-E2E checks pass | | Consumer checks | Package imports, compiled declarations, API comparison and guide examples pass | -| E2E selection | AGW: 46 scenarios/12 files/46 tests; default all remains 76/40/81 | +| E2E selection | AGW: 58 scenarios/14 files/58 tests; default all remains 76/40/81 | -These are selected live runs: 39 prior cases plus seven additions, not a new single 46-case invocation. See the linked report for the initial 7702 gas failure and verified fix, public API changes, IDL-layout limits and test evidence. +These are selected live runs. Latest expansion verified 20 distinct labels/EVM/multi-asset/SOL/SPL scenarios across selected runs; earlier v5 native/lifecycle evidence adds ten distinct cases. This is not a full 58-case invocation. Older v4 evidence includes 39 prior cases plus seven additions. See the linked report for the initial 7702 gas failure and verified fix, public API changes, IDL-layout limits and test evidence. ## Per-step matrix | Step | Deliverable | Current status | Remaining work | | --- | --- | --- | --- | -| 1 | Source/capability contract | V4 deployed source/ABIs pinned and reproduced | Refresh for future releases | +| 1 | Source/capability contract | V5 deployed source/ABIs pinned and reproduced | Refresh for future releases | | 2 | Namespace/types/errors | Implemented; AMBIGUOUS_RULE replaces duplicate-authoring rejection | Approved dual input forms; no pending type decision | | 3 | Signer/wallet context | Owner/agent/read-only/identity guards retained | Release review; UEA identity cases pass | -| 4 | Registry/adapter | Donut v4 registered; unsupported networks fail | Release review; no legacy fallback | -| 5 | Wallet/checkpoint/rule reads | Native and EVM reads implemented; source tokens/beneficiary offsets reconstructed | Editable labels await contract delivery; ref removed | +| 4 | Registry/adapter | Donut v5 registered; unsupported networks fail | Release review; no legacy fallback | +| 5 | Wallet/checkpoint/rule reads | Native and EVM reads implemented; source tokens/beneficiary offsets reconstructed | Stored label reads and owner rename/reset implemented; ref removed | | 6 | Normalization/codecs | Native/EVM envelope 1, ordered caps, hard-zero/max total, empty-list routing | Confirmed defaults; named-IDL compiler implemented | | 7 | Create/add/revoke | Index-bound create, partial recovery, atomic writes; same-agent multiples allowed | Release review; deployed create/identity/batching paths verified | | 8 | Atomic update | Native per-action and universal all-token assertions before revoke/grant | Public native/EVM/SVM lifecycle implemented | | 9 | Owner/allowance | Owner path unrestricted; explicit separate allowance retained | Release review; production allowance/token debit and delivery verified | | 10 | Native agent sends | Sender-preserving atomic batches retained | Existing ambiguity guard retained; contract validation/error mapping verified | -| 11 | EVM outbound | V4 asset membership, maxGasPerCall, wallet CEA/refunds, signer gas and responses | Release review; Sepolia success/failure and UEA cases verified | +| 11 | EVM outbound | V5 asset membership, maxGasPerCall, wallet CEA/refunds, signer gas and responses | Release review; Sepolia success/failure and UEA cases verified | | 12 | SVM destinations | Public named-IDL lifecycle, send and replay implemented; four new public cases pass live | Maintain documented supported-layout limits; prior failure retry timing remains operational follow-up | -| 13 | Responses/progress/errors | V4 ABIs and prior canonical replay/wait fixes retained | Delayed-index replay/polling tested with real contracts/receipts; no remaining SDK-owned response gap | -| 14 | E2E | 46 opt-in scenarios registered; all seven new decision-alignment cases pass live | Selected native/EVM/SVM acceptance complete | +| 13 | Responses/progress/errors | V5 ABIs and prior canonical replay/wait fixes retained | Delayed-index replay/polling tested with real contracts/receipts; no remaining SDK-owned response gap | +| 14 | E2E | 48 opt-in scenarios registered; selected coverage includes public owner transfers and mapped simulation errors | Selected native/EVM/SVM acceptance complete | | 15 | Web2 | Prior implementation retained and included in full unit run | Consumer migration notes supplied; existing Web2 unit acceptance passes | | 16 | compileCard | Outside standalone AGW; absent public export | Future marketplace scope | | 17 | Documentation/release | Current status/gaps/handoff updated | Label delivery and release review | @@ -41,4 +45,6 @@ These are selected live runs: 39 prior cases plus seven additions, not a new sin Product choices are settled. Rule ref is removed; zero native PC defaults and the current token model are retained; dual native/EVM raw/index inputs are approved; named IDL Solana authoring is implemented. Contract validation is authoritative; AMBIGUOUS_RULE remains the SDK response to multiple candidates. No selection interface change is required. -Freshly fetched contracts already validate explicit rulesIds and reject unauthorized actions. They lack setLabel, which remains gated until its ABI/deployment is verified. [Contract delivery items](questions-zaryab.md). `creditRevert` remains a separate Push-core executor dependency; ordinary returned funds do not lower policy spend. +Freshly fetched contracts already validate explicit rulesIds and reject unauthorized actions. V5 supplies stored labels and setLabel, now enabled by the SDK. [Contract delivery items](questions-zaryab.md). `creditRevert` remains a separate Push-core executor dependency; ordinary returned funds do not lower policy spend. + +Latest coverage expansion: five additional registered E2Es, wallet-isolation and UEA intermediate-read assertions, live independent token budgets and SPL recipient credit. The source-mint resolver fix adds four regression units; no caller-facing API changed. [Evidence and gas-default follow-up](research/extended-v5-e2e-2026-10-07/README.md). diff --git a/plan/agw/latest-refresh.json b/plan/agw/latest-refresh.json index b0897513..b0d1334c 100644 --- a/plan/agw/latest-refresh.json +++ b/plan/agw/latest-refresh.json @@ -1,14 +1,14 @@ { - "run_id": "20261003T075310278902Z", - "pulled_at": "2026-10-03T07:53:10.278902+00:00", + "run_id": "20261007T102718466408Z", + "pulled_at": "2026-10-07T10:27:18.466408+00:00", "complete": true, "missing_page_ids": [], "unknown_export_entries": [], "archives": [ - "notion/exports/20261003T075310278902Z/export-1.zip", - "notion/exports/20261003T075310278902Z/export-2.zip", - "notion/exports/20261003T075310278902Z/export-3.zip", - "notion/exports/20261003T075310278902Z/export-4.zip" + "notion/exports/20261007T102718466408Z/export-1.zip", + "notion/exports/20261007T102718466408Z/export-2.zip", + "notion/exports/20261007T102718466408Z/export-3.zip", + "notion/exports/20261007T102718466408Z/export-4.zip" ], "pages": [ { @@ -24,8 +24,8 @@ "page_id": "3e9188aea7f4813aa31fc95ceb4e684d", "title": "1 AGW Contract Changes", "local_file": "notion/1-agw-contract-changes.md", - "changed": true, - "previous_sha256": "22fa37bdd52e903c632760f4b7fa77cd7be89a7c5a124eba3f6866c00b5632c6", + "changed": false, + "previous_sha256": "f1301d8ff1cf370968b90a3d53037ece8fa4c6783c45a402f9be6998928e3631", "sha256": "f1301d8ff1cf370968b90a3d53037ece8fa4c6783c45a402f9be6998928e3631", "raw_export_sha256": "f1301d8ff1cf370968b90a3d53037ece8fa4c6783c45a402f9be6998928e3631" }, @@ -61,9 +61,9 @@ "title": "5 SDK AGW", "local_file": "notion/5-sdk-agw.md", "changed": true, - "previous_sha256": "9ce90fb84826c989b4fec22066da0776121f9195e27bc6679aaac538995f4653", - "sha256": "e407ee77cdf874db7ef4697f84e9945ff3a12a2f2e07e8a7f90bd24e93ea32f1", - "raw_export_sha256": "9a16f8aed79fac09818ec216fb4c69dc79f2fa0cffe0af611af956eb0e69f33f" + "previous_sha256": "e407ee77cdf874db7ef4697f84e9945ff3a12a2f2e07e8a7f90bd24e93ea32f1", + "sha256": "d3bc55b08a37d762c49173149fd8d554a8551682c0956de3e91394a54bfed9a6", + "raw_export_sha256": "8d024eb2bd2955fc772d2194f50a02d601a2d5bf903b0c9cc74882ee11348130" }, { "page_id": "3ea188aea7f481e2961ed97129f3a4e6", @@ -120,5 +120,16 @@ "raw_export_sha256": "d4a922fd1d33da5a7042f26053e8df0e496c3ccd4cb0044b0892948ac509c3a0" } ], - "review_status": "Review required" + "review_status": "Review required", + "contract_deployment_followup": { + "checked_on": "2026-10-07", + "documentation_commit": "bd230d20dbf778d9994b1f1082f79b1a8829a10f", + "deployed_source_commit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", + "generation": "v5", + "chain_id": 42101, + "readonly_block": 23991912, + "evidence": "research/deployment-review-2026-10-07-v5/README.md", + "sdk_validation": "research/v5-implementation-2026-10-07/README.md", + "notion_reexported_for_this_followup": false + } } diff --git a/plan/agw/notion/5-sdk-agw.md b/plan/agw/notion/5-sdk-agw.md index 823222c1..06c7346f 100644 --- a/plan/agw/notion/5-sdk-agw.md +++ b/plan/agw/notion/5-sdk-agw.md @@ -99,7 +99,6 @@ const created = await client.agentic.create(label, { options }) const created = await client.agentic.create('aave-optimiser', { // wallet with one cross-chain rule rules: [{ // one entry per chain per agent agent: '0xAgentOnPush', // a Push address: the agent's EOA, or its UEA if the key lives on another chain. Never the owner - ref: jobRef, // emitted in RulesGranted, not interpreted chainNamespace: CHAIN.ETHEREUM_SEPOLIA, // foreign chain => universal rulebook assets: [ { token: MOVEABLE.TOKEN.ETHEREUM_SEPOLIA.USDC, maxPerCall: parseUnits('100', 6), maxTotal: parseUnits('1000', 6) }, diff --git a/plan/agw/notion/exports/20261007T102718466408Z/export-1.zip b/plan/agw/notion/exports/20261007T102718466408Z/export-1.zip new file mode 100644 index 0000000000000000000000000000000000000000..29a25ac0b2583bd996c223d759480dc1fefc66cc GIT binary patch literal 50237 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%0ARORAyf3H(kr*jGTeGSXCbiqk#$0 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 Y-P0&}DNwM#G(mn}FyD7roqxUhKe@{1;{X5v literal 0 HcmV?d00001 diff --git a/plan/agw/notion/exports/20261007T102718466408Z/export-2.zip b/plan/agw/notion/exports/20261007T102718466408Z/export-2.zip new file mode 100644 index 0000000000000000000000000000000000000000..6377c37e6be54d84632860fc9b78d2da90d02b0a GIT binary patch literal 26729 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 literal 0 HcmV?d00001 diff --git a/plan/agw/notion/exports/20261007T102718466408Z/export-3.zip b/plan/agw/notion/exports/20261007T102718466408Z/export-3.zip new file mode 100644 index 0000000000000000000000000000000000000000..d24179afd9268b3da9399156be141b031092e38b GIT binary patch literal 1105 zcmWIWW@Zs#-~d8{VE0%CBoF{(2NY$NC6=Trs3`$a46r~myD>&un zXDjF`1UM_WW<08d_K+rY4%FnOGR4q$DMoB&M0A7^J2p85tU;n(5`HOr3f< z@3EOk+xJQ?rkhI|jTMj1zA<-QGm~zD!i<@&feu?Lrf?{Gx2gC)I@Eo$)4@zdAJl`HC5Vk-D+W3N6qA!vT@?%ju%>gWA<_HEmW zfE};-U+=576xqK0$@%m9AAG7~FtWSK{4(mmQRSce7U)}cOQZ*F)-nn83e8w?g)3xc zkQ!^UlGmdhJmyFF&HW$mklwd%f4N0TzAS6~xbwCBz1y0Xem|{>fA~|5d;b2v zC0!ZI{%xyXbGqryg65wh?e||t9&OvHa%0NQ!Ua2nMM_Q{)(LScmeNw)(Yb@`^U^im zU;q4k*cJS1*0-Bxygm1G%6W4Z%D#;#*9}^KaoP((al1M9&cAS*rE_(vQB(e$$y(2* zc?-Ksruu{haAvP$TQ+@>{?*UVjdxA**_U>I`UdA~<(}K-F>XD%(r>4kVbq!yE@Qz< z4pB$VIwxKVP;Oq3@-pba(yD(oTe&Rj&zdJ(T`>23Zm@Ot%$jdsAI6_H-rcigqmfo` z!KB20UUF1?=-bjN_2O`=A4>Y?-bDV6*xvAfKl*lm`X|wq8=^cG z#!3bV9F=L9))Xeu6xf!`;VIYM@!G-opu(Z<2U_M{+?#LwX|4MAMpq;4@1`Gn$Mdpx^3av#4L5&H&*v|U#k4hc=g%6a+UXOneQL5g}u4` zOZZE3?!8-r^WH9Wu#Nv;a#26gJ2y(jUHDn&cmf-lCOv6@sLu~}T>`;681OY`nO zIO>0*qPZeeNzWLS@Z(n>x5_j||2|w*}br5ywlboC(@~>#e!~LH{4jftiW}jr|SNA{hH)m%abLv00 z;2G!S2P}E*T#~XT*V1(_AJjTxXFp+fgGIH(vb)*cn}wgRGynMF`1kt(-s~K=YERqP uGczzeU6v21NEnkwePL5GJ)VbAUH18^~lvAglw@dx5TEU;qH5vhVr; literal 0 HcmV?d00001 diff --git a/plan/agw/notion/exports/20261007T102718466408Z/export-4.zip b/plan/agw/notion/exports/20261007T102718466408Z/export-4.zip new file mode 100644 index 0000000000000000000000000000000000000000..538ca01259388b5379870b66e61ac0e78c41cd1b GIT binary patch literal 9356 zcmcI~RZ|=c%q~`(;#S<h^!$M^5$GY-=xlDuXrjY`FgbunSuFI7G+EZL~C45E0jbF*zKbG3Gt zNwF~2P|Bx~H3mGSL>472xl6ue#1rhS;>m|jzw zTlhAPe0tkI4%WA(S6)XxNLLoBULnGeCl!uhJn2ZjqS?Voe;50`C&5@DyS@j1fq?W( z4PK=8m1k!Twuw2SudyTU7bT4u*Wcx{3ORLR!*sI~vq%bBWX{~<>;`<`aYw!yr6;>^ z2uzLignp6NLmL@SV|%S|VP~l)639QdA&m)DKB!3;iJlx?t1Pe_KE>y}+vGvvN)TA6 z-}sr42ALU+8cXi*%C>JS%6zVDPV%vH&p38JKeDH*SiH`b}lvk?X^VD>$2|C zdZZ0q;cm<}3oj)pi9gzbX=GqveXex=`}*td$eukSnSGlKt!(-%f$T)PPgeS~wGcN2 z>YBCsp+>qEkXMZ5cF2W?jbd4h9`lc?-tV!_&Apnu%NsmMT{{n>6vI*Fd3Tngq6+RE)Dm&{o@om^MK9pbZTv?9tu>rO33FA|G?q$0MOIv7MY49z z1egqO!3T*aOTUVv*7BDs& zb!4tEZv3^r#l3HX$?`HRK#HM#cLAz9Y@{qosl6h?784gCy^eHIIug1 ztYjX7+I)y1ab|c%n})4kGSBASiC7YA3rXi%y5zY65lY=msjO;~-YV#gqAFP#d$Z5~ zn9&}MKp5+3$RyqCQi$Q^VVO^R z<8@c)7XEvKD8t#`YlX& z@DY6ghtCLXyoXm42r=@2;A@WSF_Y#mU!Ap|gdl@d-gtE5Yc{+mUh49N&OV%{RUnY# zvAsE|d~Kh?EX*c=(lI-$lczr{lT++QpRf%HJ90tnsr+VM_4|I)!nhGAuROBbK>oHc zhiOqCc)eynVQBnhZ9aT4)qAProMvai`;D#2ST4zA!@Tl6fV(_Lwu+u#JfOlGtr==_ zZVzl1^Ev9wl6CB^+J^1khNJMd1vUmS2m_ya zK4+uuy~wS|p2}MwmNK8uA^8+EmUItu(e>se^3<;BWsFMN570cHruSUg=7slw?c7VO zyrCht&s$XwTvAeOah3`5@aAi*#462h=0qRQngaQ(rT}ZCJo#W2gVJdEi-=xK(r6q- ztgZFYYht_5tU8-JC$9Eu)he^>EOXKWO5G4EcVAecoOl;jg8FZ(gb5Q^eQ^^o@DjAi z(g_o1!wQqR0BIs_+10JE0$ImN&I^s$HG9|Js5F>A4Id_2o}|5X)0#^th4PqPQ9oE? z18m%@DAE-QY1hX_%M)rx6u}73{{DIOyr-j$w2(Z*H<)z7Wi~6;zuFyVtLy}tzE%=- zd%J$`E6t6i_X-_eT*lS-ZoQH;nH^@65qq6bqwdpju{DNU|K0#m>sj$YcBP!o1F=vm z`s^(tQ2XHyh8{NpufP)N;R3M)N5*as5+H~I1h=pZm>iZ}==vF-wYpIphkr%&^_DqM zqZ?vxWa^vKkE7|3lzsh8Ez91d#D`HTC zJZWl(8XG;3x;3N_JYh|{;2L(hY_C9Ho)OEQ{>5@})RH2|Cj(b{kC7>Hli;kK*U5T2 zMee69{fWk}VwAOTwwriUUv?30!qi^ zb_$;@XU6)y^0FzTcsF=1SpFdo6Diw;@acKDre8bO!7qaiJKE&zQ&AR&hl6TCyECU5 zm~!6T&{9GLccP@9WFLnspTa@`z4!D&n;%u5Eqy$Qg}-N;0p=+s8m*0SCrmZlD9a5^ zVYpk+b&q^r%OXa7;i3hKG4ccxd1RVwy_NA725|BQ&Lh8i0p29{{I#6le=(LatYJMl zElVyw$psTdaQZQX;#QeGMKg|>N%Bk~#w}N++SA%dUwrb&MdLw%ql_hwO*Aviww9e) z;D{fg$X6i{y{0UdydJ;FKpT>e^E1BBYUnXc7%Ziz1xY6+)j^D2pQfJc=8qC52WB-i z!akbD_wTT&F}? zpJ3Hd<0vz0Yi$YpT0&?Cs$MWt$h+KBwRKt>ZDPD_;rn>~kcc`0Kg^*@6SBN&8eHA) z=EoQCpc(goySiJ(^nKhbDw0GWzFB#l9UMM2lyB#PO%i4hy$rt0%>=?87D-ZY1Xk(- zE|-eku60KUq&k@5{w1nrfL`Quo|}ts6pqQg%At5yTThXifM}Z8EXJV{s zk*Tgzg?ob$F+R98J!iN`U%vVjXZD_F9DjLU82CERqgU&Gsm6%`3s6CyfH{1YmsSI& zXFcJ7dMFIYDMbMNM%v$s4%CDh22xLj=E3AMUn0pT3y0yx>CP?`rqLz1#{&kE2>wXj z4JMeW-UmTe-@_@<=XG4zW0BSV0=_zy`TI4=N8ENR31Lth zdvj`Z?2zp?>q68p>AHj?Imd@C`_3~dk2pfM>y5FF5v@2WOq8Id8sj4)%7oY|(ZH=# zsS$I7Hln3r9q}4H@b&`Ov|rIvE7Kze^uMlY=Q#$(ET|7teJ$nQb%?jlJJpSIPRg9L zfeFQb?g3DHuHG=xvaNd)RYFcKtZVY)tKt6xP+q)KYet`BYO0ZCe+I{Xj=`Hf?*p!Z zh^*H{n##8=yK2Q&%rvPxgz!zq;uCWyIeKl|m1W2oPPGx|1dHWUsLh~<201)g=&6_# z8^L@}@(#xrWOknGcsuo^y=A_U(Hg!&;pNQ^3fT);!c(iMRBECjir1bPT6KP2Y{H-9&>)r|9!B3cGN9@=$9*)uVFIJX@?4muNeT-$SSL z656_XBq*rF`~~ZAc<*=&+$8iT z$zb{9hU3MIo|K?>8ki40f>~h#`S8EJ-9muBh0gq>4Vr`?-JkY*Gv|=POY@4+pH1E7 zvZd@8ny)PxHyw}W?R_mc*l>?Sd_|wHJ@Esn^+OMuK>yhKYrW7K>Y<#6!C8cOVBG=; zzhH~zoCd{4$tXxw78I=gq5SUHyy+xV)1T2uplL1^kx`mxvVF9lME7C9l!HYTfM; z+9r8EUD|23W^*whNNc}zweu}vp8Y34ZxT<*S$6@AZ~EqfIty6+13{7c9_DFc+fgW}0= zu;&VDn?TqBmI6FmNx*er`Umu(&(~R@T^FY(iPgCTXVbI;^5z8}7x$B?xMT?#V?T*hm%^dH{Q~BJRed0Cr!N0Wt40S|@-+{CiKCqMl` z>dtxeyrri20=}GSX@ljk12VKJBT`691r`?V`n~enW;+Wsl|S`0Mkn!qTQy%ns^G_* zQQQ*cea>Pb!g~paciUo%FIt`DnEY=XEtqj353k5Y5@m3eTjt@=C)1C7sGux#C@vi> z$Gr`-*wIzwWh=x+xcs|r9d1rCE-7?M&=dluE*PT~4lTvK8axq0&o|D(=)Srjtq)Z{ zPi0_T-MsT97GzpCFG?(3w}w3iLr*dIY^V%?z?snacwl`c2Ml3;J_ZW@)NI>K?Y7|x z){BX!=kqa%STZ$S1M=OhNSH2S+{Tpld0--kor%i!)1T|d&dEQUtNG1kiH*pyjfJ+C zCI-a`;fV>p#wRJ=^jGuTwdJJ^i2{Z(ZcU+oKfY?hALQ%_8LG__+?zVVZ&R|i#3<|2 z_mLg$crs;JVd!kUQh+rq1NMM7qO$K(#XGd@7;3XH+v;!A0<=S@u(kJpawo2JHMpe` z!o;HFaHh!@8mM91$9Jekbj6!i<&d-1v~x3viSw^Ob7UOD7d=8oXEDP8#Ru$B#}A*809RH{$9?E(`g>Wv8FnwZCI;KxUy z2? z4cP4vZNAh2kgSSE@+Oq$P`NXVVM2%3WrskEzm1~6bP*zJvtcih1}FyHRj}Aj*WD@M zyN=|I*^YHzeeL7nSGuk}-RZc>V`4NnEB5kd{%tXC9M7>BzLT@ZRWfET*N`|9hnL>h zq%6JPi&h3ZbC{SVS&z|8&9sK^0AxXCFWJ&&Vh69xX7^%8z;<_v1n9w6a~Ch;INaoV zjozF;@y1W(_Gb_~QD}_JF^##n#D+n%y2raMDJ~7bSkkR@DwQW!beB8c?)}j$N*!X; zq4ZvpmrF%gNO`PVuNV#ISCVDJBU2f6Q3ki>e+meiHNOdGgKPcPOMhF%Bu#c0J)ZYn zcyumf_778pS{h>f{eZx=L=5jx8NszKfq+5VD356B^6_BgKD!zWxvee7tLm#ZxWmUP zl)=7C@@%ckYa%ukM=64yMo~{+r>#LX+&|9LLHOGc^m$sjSr71bhA03s9q2L;kzh< zPsq9Gc7%bxfY(hUL;a=mx;am&@#*Lz_$QOk>xbrmZ_0Q|$kEv?U~C2`LkRT82=t|O zu4{i9y}_X#culf@AMEQZq;vl4aTM)v;K+Bz23}1gc@enz;|AKH{u|sVMEiZ1g0=eC zil3dU+99T2@s++cm@>KerhoxUaL-n18{^;O8^}o@#->I|nUfu-_qKJ|fMqR4M#4+%G{$c?RMI z6@SN*KlVo7;|CnQ=OH9Xq>aD!xfZ7&1jdR9el^%1N=qMq=1X;5S!?BVJuE&tHETEb zsSb$b-GsyD<$~x)&2)XonmO^yuPRvxe*pK@pCS%z&t0eF|DxM64+QP1D|q8pl(^1% z^{JAT+Y|kOz3(_8iLQL=sq4XTx$I;XVN#>A8n!XX-YwaN4PL3rg%o%?my8#+P3t!C z7kZsGSx*(E5PUVdFR-s_yQ3F+^9?$36?E39&Gwz+k^Sqd#WMc7Z8RHj3+x?zMH5Ir z|4#WT44>jy*%SQcRC6YKK-pWZdTh-8Ro-+O!BQOk*DZbY0eG0_7EV6))mGq+l9nf^ z2$fwkbNf%M97i~YulY?fY7??!eWYZXi2iWpp?(@MHH)yYdG>e-j z_H_*SF?wbo^h}yGV|$qKMOr#<1+LbOAkX2en*q70c@`v%nrA7Lxu4-YJ$6a(Ualla z_ushRLsO(Y>#XE+5oNo!x`?oY-L0#H)vckD$Q@J&j@&}@rU~Y2LZ(ZY6q@SDt)ljd zhtZ0Ei2_&*TB);Hp|0)qs!mDir;1|>9V`z%2nvh~PqI2c<8Py7n_Er=c{mmG?6 zaXkK72_wSgHhGF|VIb5l8$kP42>_NY{Y`f1dpQpy>rVWyzsAruHuot{(!+AEvWuC{ zqJ=q~L?XSQF^Twp*jKBpGy~uFO5H4__0C}{0TNhzl)0ts)fjh|nz}laWtEH4{pQa- z+=iz|8hE~)kn{48{47PjPRSKKQQR@Hh~|@mNy8i)umF{+zCO7 zpnHoUwg`Dw?WMSzOCnmECXA+9Qj~Ti%Ik-8k)n!LBOShqXfN6O+4w~*1d)(|DpuI; zSz`!d?6ndW4D;(t>n3cBSk>FgUKL7c#?>m)+)N+=TCE+EM@@I+b-|n58pl**6&a$Z zJHCQ?>6ngt!@)+yYVK^O_>Cl1$_pkI8AD90oj7Kt0cCmL8xuq>k#R5D6TF2-W5prF zR2vO9{983F7*(e$K1l0SF=QEqnJL`R!IlEo_Lam9U_7*VMm!xff3gvS!q-1RISc$C zZ=s+08u*ym#=z5-<&o^$u4Y!cJ;PHfG|80Trs6f+ipJ2U=i9aj)BfiEx;B#u0R}$p z`}A$m*J9N40vdm6T8#YuQF8D82s`h)wF(1FE0ZIYc97;4^Y$AsdgB9bVXI}_c`3(g zs%b+YOEX^`5gqXsBA+pNUe81Ee(d$E)-wOGZv5N&hl{KrR&`cabK**u)`&1>+Q*$- zW+KS~E@cAdx6<|KK~qh=(W^?3gUCcI93$7S1ztuN9~weP1cq(H$M|4?pvE`NC*<iSn$50E1&Z+pA1l5x~A1*NT$9f8KI?ixkJK9_8F z+*pPQipGQ3SXx~O8nZS&D8ig-jV#t+CKS~Tg z63*+%hevI%FjQ+!qrTAeG!7`twB&2OGKlWcHB|G15K8O5VV8xmb-6vfU&xmcjS7Pa~V_ zr1l=wfj*5=L8sm{`Z5z@G=+Bi$`eqr>42<~Av;w!HaT2XJkj=DM4_|>ImNqBtT>01 zi^_q9Fij0;m5SP>hTo9B+^D`4|K&XLfr#%^o!(70vqeZR#sxJ339oyAqbNdNx3Dm_ zRV15d(CsW*&I!Aq*$k?iocV%Zq#EkAgH!EJ%-M-?)mQOsjuJTWH~!a{mm+W zDUD);MAq0rHnku5kuaz}vcH*EdWaev*ZY(7X7D#!Y?JH$nK4HZPzicA_P8WPADrd% zOcXTPZfnKfGdz=%6yfHYi**;0K${kyUO=1x5eXI?$FD1Ef^AG{;ASzK)*Nf~90h6z)ZE-;4^_6`Xgx-8fX3DphoB1RS#8WX~ZOI zC0rt$auLn}oqrwp9b?yZxJz~q+$v6-1LO?{X8yBT3~KDuKGlhS+Df%kxq0y;pyFQa z$yr!375iY*RF0+-D|iPABw9=CVf4S6d{Imn%Q|Xidjb51+Z>W43o<{`(D+qDw6HVL zVta{bV%1OF8zlGJ%5HJSx*s8OLL7#fPrsn{GiuU_`%UJHzLG#aMhK;?9d*~vn_{dB zPE(5TV$uBfC4w@iX(~?hV!4pp&a>#&ij{3-Dvt&s+1+tR*pu+IcrjH4(^sXTX(m+V zY~F~e;z-C|cH*OczJ{YW#c!2Dtc{vc2Kaxyhkr?|&gP36~SEnM_RHJ@T z(+FyCmS2h2kLyzY%>Eg*So=k0bWpOQcJRB&v%U8vCrzFc6g*>6Q=5bxr;7?Pg@wcP zR9{oU<}vg_(U!ZvIoly9{jr!k7FUAa3_xRH*G>OWgiEPIv{nrnPZ;82#(iKKSSx>t zUJ{uNahF#B$*?&?UHkLs9lM{9$O+1tF?pEtK}~g(@2W>KluE+#CK~${MtvXp&S~mO zbhyyHh2$svsgwe2Vbai-U-N|Ie0Wq*6HY!=FmW5BpufBZz)Lxuun4lwiGmN&^qVM`1R(pu zGSp|x=#?uT0^6*gD_C7J2k}p6+Se6*j#~>QzGtML6~j?hT=qlvkQ6V{N;OJfrOV^b zTXdUbmA$hui&L7-CNSyJ1G};~+&N-9Nk_3K489yp(eA1=m)Z!DW><2E%pU5V@0p1t z>`wjre{V+NsPTZS+vi!|XUs-BMD)cf32{UsQ$(`~JhO>jc+8fLD6A~k0#r8L{O{5= z$ZgO`N;2y6D(GlQb0g=~^j`hoeK-2#h`NJZCg0*4NXFED#Hv3_bielXbqcO-yzEv) z9o4(H4JSH(23@BsS12?+FCdlLZ6K@|`2O{}`}_7T)AKx3s@8PBL#Bd9h{92+`J7AZ zOL>MnDhKrS&bL_Id^3%uMn*$;>1cUTC%d`yiavj}xNQeneg4zR{6zWjB2sW)2t>=g ze0S6Ld6fAqZSJRSXLrX8SUj34Tk1y3^Yz>5Gk<2&UtXzB=x!s69W}5RW>G3oO!a@f zp-#jkVY(o`0@yO|tk-KjNf78u+7d{*yh{OGOgG>GgiO@>)E3=Vnff1%uMhEaQq6G*1Im zU_SO>sohfg;%j2g;um^ekxR7m@0Kof8ZDu}$BLVW>gwL<73+if}}V9+2iES_EQ#Tf{tW>fkz!3 zxYz1e)a%7CpF4S$_sI>$oYB!rZp6GmNktt$$>0v#Db0%bUU#4nGQ#*#V^80|Q+y=m zROqP+H)L{M&}`<%=isovv${0t zwACmJ6dZN9AH0W^9C#mvoIoDG-nVPr$iF(b>i1cBNMqGjS-9Fp0=>B9^m+sE>Dwn# zV=h@BXh<{Ft?1WV(AJgK?R0XF_jI%0b;l_E3igD<%#o}DAKDfCiuDGA%dXS`vW1Uz zJKg_m3TddA4odVtKl%tXc`1g$nLpmwa8Bjr;Tj58E-7>R9_9YLmP9>*w!^zt%wk)% z*5%7kuC3x1O)dXXy*}0W$<|7<0E4CanrL=>+Y6W7NrX?O3?ouuC>nia?tlJvIQrJ| zA#BzVXfpODKy4&AQJvE)xqn)^ZPt||5|&;*=3EhP(NlbM*1Kw!7PkGnaO;#cAa|~; z1H;U6qW>NaRD&3}$$ssNdhG*(ue@05EyTj^x4T^LoL>wa-LCm(tL1gwgYLG&V(~fs zw{NAirNCb3eaZ3lMz!I6s|9Cq*Zo@LFVJ5L)uRk4h)d)`1`Rj0?Z`C7w=~fpbN>A+ znVQkU@&gKurM(GRZykE$l~&W<5ZeduLr_iad!RB10nrYi?(Iqi1vRGoAFBrh4Z{NU me_22OJN7@UpZ{0>e{g`5L0{nirwa6c8uFjL`>!)7sQ&{BwJgE_ literal 0 HcmV?d00001 diff --git a/plan/agw/notion/history/20261007T102718466408Z/5-sdk-agw.diff b/plan/agw/notion/history/20261007T102718466408Z/5-sdk-agw.diff new file mode 100644 index 00000000..17d35d7a --- /dev/null +++ b/plan/agw/notion/history/20261007T102718466408Z/5-sdk-agw.diff @@ -0,0 +1,10 @@ +--- notion/5-sdk-agw.md (previous) ++++ notion/5-sdk-agw.md (refreshed) +@@ -99,7 +99,6 @@ + const created = await client.agentic.create('aave-optimiser', { // wallet with one cross-chain rule + rules: [{ // one entry per chain per agent + agent: '0xAgentOnPush', // a Push address: the agent's EOA, or its UEA if the key lives on another chain. Never the owner +- ref: jobRef, // emitted in RulesGranted, not interpreted + chainNamespace: CHAIN.ETHEREUM_SEPOLIA, // foreign chain => universal rulebook + assets: [ + { token: MOVEABLE.TOKEN.ETHEREUM_SEPOLIA.USDC, maxPerCall: parseUnits('100', 6), maxTotal: parseUnits('1000', 6) }, diff --git a/plan/agw/notion/history/20261007T102718466408Z/5-sdk-agw.md b/plan/agw/notion/history/20261007T102718466408Z/5-sdk-agw.md new file mode 100644 index 00000000..823222c1 --- /dev/null +++ b/plan/agw/notion/history/20261007T102718466408Z/5-sdk-agw.md @@ -0,0 +1,732 @@ +# 5. SDK: AGW + + + +# List of changes + +New + +- `client.agentic.derive` +- `client.agentic.create` +- `client.agentic.list` +- `client.agentic.wallet`, + - a management handle with + - `info`, + - `owner`, + - `setLabel` (PROPOSED), + - `checkpoints`, + - `rules.list`, + - `rules.get`, + - `rules.add`, + - `rules.update`, + - `rules.revoke` +- `PushChain.CONSTANTS.AGENTIC` +- `PushChain.utils.agentic` + +Updated + +- `PushChain.initialize`, new option `agenticWallet` +- `PushChain.CONSTANTS.READ.CHAIN`, outside change confirmed 2026-09-28 + +Initialize is unchanged on the owner side: + +```tsx +const client = await PushChain.initialize(universalSigner, { network: PushChain.CONSTANTS.PUSH_NETWORK.TESTNET }); +``` + +| Signer | Door | Rules checked | +| --- | --- | --- | +| The wallet's owner | Owner door (`execute`) | No. Every send is recorded as a checkpoint | +| An address named as `agent` in one of the wallet's rules | Agent door (`executeAsAgent`) | Yes, by URP (UniversalRulesPolicy, the on-chain rule checker) | +| Anyone else | None | Never reached: `initialize` throws `NOT_OWNER_OR_AGENT` | + +An agentic wallet involves three parties, and it helps to have them straight before reading the functions. + +The **owner** is whoever created the wallet. When the owner sends through the wallet, no rules are checked; this is called the owner door, and the contract records every such action as a checkpoint so that an evaluator can later tell whether the owner touched anything mid-job. + +The **agent** is the address the owner allows to act on its behalf. It is always a Push address. If the agent's key is a Push EOA, that EOA is the agent. If the key lives on another chain (an EVM key on Ethereum, a Solana key, anything else), the agent is that key's UEA on Push, which exists deterministically for every external key. The SDK never asks for a curve, a chain or a key type. When the agent sends through the wallet, the rules are checked; this is the agent door. + +The **rules** say what an agent may do. Each rule names its agent and its destination chain, and there is one rule per chain per agent, so a wallet can have one agent for Ethereum and a different one for Solana. The `chainNamespace` on a rule decides which rulebook applies: leave it out and the rule governs calls on Push itself; set it to an `eip155` or `solana` chain and the rule governs cross-chain calls to that chain. + +Two ways to touch a wallet from the SDK. `PushChain.initialize(signer, { agenticWallet })` returns a client that acts as the wallet, and whether it goes through the owner door or the agent door depends on who the signer is. `client.agentic.wallet(address)` returns a handle for managing the wallet (rules, label, checkpoints) and never sends as it. + +# 1. Owner side, by example + +The owner side is everything the person who owns the wallet does: create it, fund it, write and revoke the rules, look at what happened. The agent side (section 2) is what the agent does: act through the wallet within those rules. + +### 1.a Derive an agentic wallet address - `client.agentic.derive` + +Gives you the address a wallet will have before it is deployed. The address depends only on the owner and an index. + +```tsx +// Function +const first = await client.agentic.derive({ options? }) + +// Usage and Params +const next = await client.agentic.derive(); // the owner's next wallet +const first = await client.agentic.derive({ index: 0 }); // a specific slot +// options.index number, optional which wallet slot to derive; default is the owner's next unused index + +// Returns +// { address, index, deployed } +{ + address: '0x2Fd904d6f2C0b34d58426C8Ae9c5267E845CE98f', + index: 0, + deployed: false +} +``` + +Because the address depends only on the owner and an index, it is the same whether you deploy first or later. That lets you send funds to it first (from any chain) and deploy afterwards, or show the address in a UI before anything is on-chain. Same idea as `deriveExecutorAccount` for a UEA. + +### 1.b Create an agentic wallet - `client.agentic.create` + +Deploys the wallet and grants the rules. The label is the only wallet-level input; the agent and an optional `ref` are named on each rule, because that is where the contract binds them. + +```tsx +// Function +const created = await client.agentic.create(label, { options }) + +// Usage and Params +const created = await client.agentic.create('aave-optimiser', { // wallet with one cross-chain rule + rules: [{ // one entry per chain per agent + agent: '0xAgentOnPush', // a Push address: the agent's EOA, or its UEA if the key lives on another chain. Never the owner + ref: jobRef, // emitted in RulesGranted, not interpreted + chainNamespace: CHAIN.ETHEREUM_SEPOLIA, // foreign chain => universal rulebook + assets: [ + { token: MOVEABLE.TOKEN.ETHEREUM_SEPOLIA.USDC, maxPerCall: parseUnits('100', 6), maxTotal: parseUnits('1000', 6) }, + { token: MOVEABLE.TOKEN.ETHEREUM_SEPOLIA.WETH, maxPerCall: parseUnits('0.5', 18) }, + ], + maxGasPerCall: parseUnits('1', 18), // PC (wei) per outbound for the destination leg + validUntil: now + 30 * 86400, + allowedCalls: [ + { target: aavePool, selector: 'supply(address,uint256,address,uint16)', beneficiary: 2 }, // arg index, not offset: onBehalfOf must be the AGW's CEA + { target: usdcSepolia, selector: 'approve(address,uint256)' }, + ], + }], + progressHook: (p) => console.log(p.id, p.message), // AGENTIC-TX-1xx +}); +const bare = await client.agentic.create('scratch', { rules: [] }); // wallet first, rules later with rules.add +// label string, required shown in list() and info(); the contract stores it +// options.rules Rule[], required one per chain per agent, may be empty; each rule carries its own agent and optional ref +// options.progressHook function, optional progress events, AGENTIC-TX-1xx; default none +// rules[].agent Address, required the Push address allowed to act under this rule; never the owner +// rules[].ref Hex, optional emitted in RulesGranted, not interpreted; default zero +// rules[].assets AssetCap[], required on a universal rule tokens the agent may move, as the other chain's address (MOVEABLE constants); the SDK resolves each to its PRC20 on Push; each cap is { token, maxPerCall, maxTotal? } +// rules[].maxGasPerCall bigint, required on a universal rule PC (wei) the wallet may spend per outbound for the destination leg + +// Returns +// { wallet, index, rulesIds, tx } +{ + wallet: '0x2Fd904d6f2C0b34d58426C8Ae9c5267E845CE98f', + index: 0, + rulesIds: ['0x9c1e...'], // in the order of the rules you passed; empty for rules: [] + tx: { // UniversalTxResponse + hash: '0xb527...', + origin: 'eip155:11155111:0x31dC...', // the owner's key, CAIP-10 + from: '0xFd6C2fE69bE13d8bE379CCB6c9306e74193EC1A9', // the owner's Push account + blockNumber: 1290n, + wait // await tx.wait() for the receipt; status lives on the receipt + } +} +``` + +One rule per chain per agent. A wallet may have different agents on different chains. If an agent needs to act on two chains, `rules` has two entries with the same `agent`; two agents on one chain are two entries with the same `chainNamespace`. Nobody states a rule type; the SDK reads it from `chainNamespace`. `rules: []` is allowed: create the wallet first and grant rules later with `rules.add` (1.k). + +Before asking for a signature the SDK checks that no rule's agent is the owner (`AGENT_IS_OWNER`), that no two rules share both agent and chain (`DUPLICATE_RULE`), that every `allowedCalls[].target` is on the rule's chain (`TARGET_NOT_ON_RULE_CHAIN`), and that every `assets[].token` resolves to a PRC20 whose `SOURCE_CHAIN_NAMESPACE` matches the rule's chain (`ASSET_CHAIN_MISMATCH`). + +Under the hood this is `deployWallet` (or reuse of a derived address) and one `grantRules` per rule. For an external owner they go as one UEA multicall under one signature. Funding is not part of `create`: the wallet is a normal Push account, so send tokens and PC to its address the way you would to any account (1.a shows the address before deployment). + +For a Push EOA owner the same thing needs a batching entry on the factory, because core rejects multicall from a Push-native sender: [1. AGW Contract Changes (nomenclature standard + change set)](1-agw-contract-changes.md) item 11, **PROPOSED** (`createWallet(label, rules[])` on the factory). Until it lands the SDK sends deploy and grant as separate transactions and says so through progress events (AGENTIC-TX-102 and 104); `tx` is then the last of them. + +A `progressHook` passed to `PushChain.initialize` receives the same events alongside the per-call one, as in core. + +Warning for an agent whose key lives on another chain: the same EVM key initialized against two chains yields two UEAs, because a UEA is derived from namespace, chainId and owner. Grant the rule to the UEA of the chain the agent will run against. `PushChain.utils.account.deriveExecutorAccount(PushChain.utils.account.toUniversal(address, { chain }))` gives it. + +### 1.c List an owner's wallets - `client.agentic.list` + +Lists the wallets owned by the connected signer. It takes no arguments and only reads the connected account. + +```tsx +// Function +const res = await client.agentic.list() + +// Usage and Params +const { wallets } = await client.agentic.list(); // the connected signer's wallets +// no params + +// Returns +// { wallets: Array<{ address, index, label, deployed, rulesCount }> } +{ + wallets: [ + { address: '0x2Fd9...', index: 0, label: 'aave-optimiser', deployed: true, rulesCount: 1 }, + { address: '0x81aB...', index: 1, label: '', deployed: false, rulesCount: 0 }, + ] +} +``` + +Client methods act on the connected account; reads about any other account live in `PushChain.utils`. If a read-only view is needed later (a marketplace or explorer page showing the wallets of an address with no signer), it becomes `PushChain.utils.agentic.wallets(owner: Address)` taking a Push address; an external owner passes its UEA. Not in v1. + +### 1.d Get a wallet handle - `client.agentic.wallet` + +Returns a handle for one wallet: the reads that are specific to an agentic wallet, plus the rule writes only an owner can do. It is not a client and never sends as the wallet. + +```tsx +// Function +const w = client.agentic.wallet(address) + +// Usage and Params +const w = client.agentic.wallet('0xWallet'); // handle for one wallet; nothing is sent +// address Address, required the AGW to manage, a Push address + +// Returns +// { address, info(), owner(), setLabel(), checkpoints(), rules.* } +{ + address: '0xWallet', + info, owner, setLabel, checkpoints, // 1.e to 1.h + rules: { list, get, add, update, revoke } // 1.i to 1.m +} +``` + +There is one way to send as the wallet: `PushChain.initialize(signer, { agenticWallet })` (section 2). The handle only manages. To send as the wallet, move funds, reach the wallet's CEA on another chain, or read balances, initialize with `agenticWallet` and use the normal account tooling: `sendTransaction`, `universal.read`, or viem and ethers against `client.universal.account`. That gives the owner the full `sendTransaction` with every route the SDK already has, the same receipts, and the wallet's CEA reachable exactly as it is for any other account. + +Balance reads are deliberately not on the handle: they are not agentic, and every account is read the same way. There is no `w.execute` for the same reason. The handle stays what its name says: management. + +### 1.e Read wallet info - `w.info` + +Returns the wallet's summary in one read: the fields `list()` shows for each wallet, plus the owner. It is how you read the label from the handle. + +```tsx +// Function +const info = await w.info() + +// Usage and Params +const { label, deployed } = await w.info(); // one wallet's summary +// no params + +// Returns +// { address, label, index, owner, deployed, rulesCount } +{ + address: '0x2Fd904d6f2C0b34d58426C8Ae9c5267E845CE98f', + label: 'aave-optimiser', + index: 0, + owner: '0xFd6C2fE69bE13d8bE379CCB6c9306e74193EC1A9', + deployed: true, + rulesCount: 1 +} +``` + +### 1.f Read the owner - `w.owner` + +Returns the owner's Push address, as the contract stores it. + +```tsx +// Function +const res = await w.owner() + +// Usage and Params +const { owner } = await w.owner(); // the Push address stored as owner +// no params + +// Returns +// { owner } +{ + owner: '0xFd6C2fE69bE13d8bE379CCB6c9306e74193EC1A9' +} +``` + +If the owner is a UEA and you need the controlling origin behind it (the chain and the external key), use `resolveControllerAccount` on the returned address. + +Page rule: identities going in and out of the agentic namespace are Push addresses (owner, agent, wallet). + +### 1.g Set the wallet label - `w.setLabel` + +**PROPOSED**, contract change, see [1. AGW Contract Changes (nomenclature standard + change set)](1-agw-contract-changes.md) item 10. Changes the label shown in `list()` and `info()`; owner only. + +```tsx +// Function +const tx = await w.setLabel(label, { options? }) + +// Usage and Params +const tx = await w.setLabel('aave-optimiser-v2'); // rename the wallet +const tracked = await w.setLabel('aave-optimiser-v2', { progressHook: (p) => console.log(p.id) }); // with progress events +// label string, required the new label; stored by the contract and emitted in LabelSet +// options.progressHook function, optional progress events, AGENTIC-TX-106; default none + +// Returns +// { hash, origin, from, to, blockNumber, wait() } +{ + hash: '0x3b8d...', + origin: 'eip155:11155111:0x31dC...', // the owner's key, CAIP-10 + from: '0xFd6C2fE69bE13d8bE379CCB6c9306e74193EC1A9', // the owner's Push account + to: '0x2Fd904d6f2C0b34d58426C8Ae9c5267E845CE98f', // the wallet + blockNumber: 1488n, + wait // await tx.wait() for the receipt; status lives on the receipt +} +``` + +Emits `LabelSet(string label)`. It is not a checkpoint: the label is cosmetic metadata and evaluators ignore it. Today the label can only be set once, at `deployWallet`, and is emitted in `WalletDeployed`. + +### 1.h Read checkpoints - `w.checkpoints` + +Every owner-side change the wallet has recorded: owner-door sends, rules granted, rules revoked. An evaluator reads these to know whether the owner changed anything after a job started (page 4). + +```tsx +// Function +const res = await w.checkpoints({ options? }) + +// Usage and Params +const all = await w.checkpoints(); // every checkpoint +const recent = await w.checkpoints({ sinceBlock: 1234n }); // from a block onward +// options.sinceBlock bigint, optional only checkpoints at or after this block; default all + +// Returns +// { checkpoints: Array<{ seq, kind, ref, blockNumber, txHash }> } +{ + checkpoints: [ + { seq: 3, kind: 'RULES_GRANTED', ref: '0x9c1e...', blockNumber: 1290n, txHash: '0x...' }, + { seq: 4, kind: 'OWNER_ACTION', ref: '0x5a7b...', blockNumber: 1402n, txHash: '0x...' }, + ] +} +``` + +### 1.i List rules - `w.rules.list` + +Returns every rule on the wallet as a decoded record, including what each rule has spent so far. + +```tsx +// Function +const res = await w.rules.list() + +// Usage and Params +const { rules } = await w.rules.list(); // the wallet's rules +// no params + +// Returns +// { rules: RulesRecord[] } +{ + rules: [ + { + rulesId: '0x9c1e...', + enabled: true, + chainNamespace: 'eip155:11155111', + agent: '0xAgentOnPush', + validUntil: 1767225600, + ref: '0x4a2f...', + rule: { /* decoded UniversalRule, as passed to create */ }, + spent: { kind: 'universal', amountSpent: 25000000n } // shape PROPOSED, see 3.b + } + ] +} +``` + +### 1.j Get one rule - `w.rules.get` + +Returns one rule by id, decoded, with what it has spent. + +```tsx +// Function +const record = await w.rules.get(rulesId) + +// Usage and Params +const record = await w.rules.get('0x9c1e...'); // one rule by id +// rulesId Hex, required the id returned by create or rules.add + +// Returns +// RulesRecord +{ + rulesId: '0x9c1e...', + enabled: true, + chainNamespace: 'eip155:11155111', + agent: '0xAgentOnPush', + validUntil: 1767225600, + ref: '0x4a2f...', + rule: { /* decoded UniversalRule */ }, + spent: { kind: 'universal', amountSpent: 25000000n } // shape PROPOSED, see 3.b +} +``` + +`spent` is a field on the record, so `get` and `list` both carry it. There is no separate spent call. + +### 1.k Add rules - `w.rules.add` + +Grants new rules on an existing wallet under one signature. The rules array comes first; `agent` and `ref` live on each rule. + +```tsx +// Function +const res = await w.rules.add(rules, { options? }) + +// Usage and Params +const one = await w.rules.add([nativeRule]); // one rule +const many = await w.rules.add([ruleOnSepolia, ruleOnPush]); // several rules, one signature +const tracked = await w.rules.add([nativeRule], { progressHook: (p) => console.log(p.id, p.message) }); // with progress events +// rules Rule[], required one per chain per agent; each rule carries its own agent and optional ref +// options.progressHook function, optional progress events, AGENTIC-TX-104; default none + +// Returns +// { rulesIds, tx } +{ + rulesIds: ['0x7d3a...'], // in the order of the rules you passed + tx: { // UniversalTxResponse + hash: '0x4c19...', + origin: 'eip155:11155111:0x31dC...', + from: '0xFd6C2fE69bE13d8bE379CCB6c9306e74193EC1A9', + blockNumber: 1501n, + wait + } +} +``` + +Records a `RULES_GRANTED` checkpoint. + +### 1.l Update rules - `w.rules.update` + +Replaces rules in a batch: each pair names one old rule and the one new rule that takes its place. + +```tsx +// Function +const res = await w.rules.update({ rules, progressHook? }) + +// Usage and Params +const one = await w.rules.update({ rules: [{ rulesId: '0x9c1e...', rule: newRule }] }); // replace one rule +const many = await w.rules.update({ rules: [{ rulesId: idA, rule: ruleA }, { rulesId: idB, rule: ruleB }] }); // replace several, one signature +const tracked = await w.rules.update({ rules: [{ rulesId: idA, rule: ruleA }], progressHook: (p) => console.log(p.id) }); // with progress events +// rules Array<{ rulesId, rule }>, required one old rule to one new rule per pair +// rules[].rulesId Hex, required the rule being replaced +// rules[].rule Rule, required the replacement; one rule per agent per chain still applies +// progressHook function, optional progress events, AGENTIC-TX-105 and 104; default none + +// Returns +// { rules: Array<{ rulesId, replaced }>, tx } +{ + rules: [ + { rulesId: '0x51c0...', replaced: '0x9c1e...' }, // new id, old id + ], + tx: { // UniversalTxResponse + hash: '0x7a02...', + origin: 'eip155:11155111:0x31dC...', + from: '0xFd6C2fE69bE13d8bE379CCB6c9306e74193EC1A9', + blockNumber: 1507n, + wait + } +} +``` + +Rules are immutable on-chain, so an update is a revoke plus a grant: for each pair the SDK asserts the old rule's spend, revokes it and grants the new one, all pairs in one multicall. The result is a new `rulesId` per pair, and the spend counters reset on the new rule: what the old rule had spent does not carry over. This is accepted for v1 (open item 1); an in-place update would be a contract change and there is no demand for it yet. + +### 1.m Revoke rules - `w.rules.revoke` + +Revokes some rules by id, or all of them in one atomic call. + +```tsx +// Function +const tx = await w.rules.revoke(rulesIds, { options? }) +const tx = await w.rules.revoke({ all, progressHook? }) + +// Usage and Params +const some = await w.rules.revoke(['0x9c1e...', '0x7d3a...']); // revoke these rules +const all = await w.rules.revoke({ all: true }); // revoke every rule, on-chain revokeAllRules +const tracked = await w.rules.revoke(['0x9c1e...'], { progressHook: (p) => console.log(p.id) }); // with progress events +// rulesIds Hex[], required unless all is set the rules to revoke +// options.progressHook function, optional progress events, AGENTIC-TX-105; default none +// all true, required unless rulesIds given revoke every rule on the wallet in one atomic call +// progressHook function, optional same events, in the { all: true } form; default none + +// Returns +// { hash, origin, from, to, blockNumber, wait() } +{ + hash: '0x8e01...', + origin: 'eip155:11155111:0x31dC...', // the owner's key, CAIP-10 + from: '0xFd6C2fE69bE13d8bE379CCB6c9306e74193EC1A9', // the owner's Push account + to: '0x2Fd904d6f2C0b34d58426C8Ae9c5267E845CE98f', // the wallet + blockNumber: 1512n, + wait // await tx.wait() for the receipt; status lives on the receipt +} +``` + +A bare `revoke()` is not allowed and throws `REVOKE_NEEDS_TARGET`: a call with no argument that wipes every rule is too easy to make by mistake. Records `RULES_REVOKED` checkpoints. + +# 2. Agent side, by example + +There is no new method on the agent side. The agent uses its own signer and tells `initialize` which wallet to act through. It does not name a rule: which rule applies is decided per transaction, from the destination chain. + +### 2.a Act as the wallet - `PushChain.initialize` with `agenticWallet` (updated) + +Returns a client whose account is the wallet. Whether its sends go through the owner door or the agent door depends on who the signer is. + +```tsx +// Function +const client = await PushChain.initialize(signer, { options }) + +// Usage and Params +const agentClient = await PushChain.initialize(agentSigner, { // agent door: the signer is named as agent in a rule + network: PushChain.CONSTANTS.PUSH_NETWORK.TESTNET, + agenticWallet: '0xWallet', +}); +const ownerClient = await PushChain.initialize(ownerSigner, { // owner door: the signer owns the wallet + network: PushChain.CONSTANTS.PUSH_NETWORK.TESTNET, + agenticWallet: '0xWallet', +}); +``` + +`agentSigner` is any signer `initialize` accepts today. If the key lives on another chain, the SDK derives its UEA and everything goes through that, as it does for every external user. + +Which door the client uses depends on who the signer is. If the signer is the wallet's owner, sends go through the owner door: no rules, and every send is recorded as a checkpoint. If the signer is an address named as agent in one of the wallet's rules, sends go through the agent door and the rules apply. If it is neither, `initialize` throws `NOT_OWNER_OR_AGENT`. If the address has no wallet deployed yet it throws `WALLET_NOT_DEPLOYED`, and if the address is not an agentic wallet it throws `NOT_AGENTIC_WALLET`. This is also how an owner acts as the wallet with the full client: `PushChain.initialize(ownerSigner, { agenticWallet })`. There is one way to send as a wallet and the signer decides the door. + +On the agent door the SDK sends; URP on-chain is the only rule checker. Before sending, the SDK only looks up the `rulesId` for the destination chain: the rule that is enabled, whose `agent` equals the signer, and whose `chainNamespace` equals the destination. The lookup is one read on every send, not cached at initialize. If none is found it throws `NO_RULES_FOR_CHAIN` before any signature, so it costs nothing; otherwise it calls `executeAsAgent(rulesId, ...)` on the wallet. That is the agent door from D3 on [1. AGW Contract Changes (nomenclature standard + change set)](1-agw-contract-changes.md): there is no session validator, and the wallet only checks that `msg.sender` is the rule's agent. There is one rule per (agent, chain), so a signer and a destination match at most one rule. If the action breaks a rule, it reverts on-chain and the agent pays that gas. `sendTransaction` then throws `AgenticRevertError`, which extends core's `PushChainExecutionError` and carries URP's custom error in `decodedError`, so the agent sees which gate failed (3.f). + +From an external key, the call arrives through the agent's UEA. If the agent's UEA is not yet deployed, the first action takes the origin-chain fee lock once (minimum $1), which deploys the UEA and funds it with PC. Every later action requires PC in the UEA and is a direct Push transaction paid from that balance, with no origin transaction and no cross-chain wait. + +Two things for whoever runs the agent. The agent's UEA is a second balance to keep funded: the AGW's PC covers the wallet's outbound fees, not the agent's gas. And in `agenticWallet` mode the SDK turns `enforceGasCheck` on for every action except that one first action while the agent's UEA is not yet deployed, so an empty UEA fails loudly instead of silently falling back to a $1 origin lock and a confirmation wait on every action. + +Routing. In `agenticWallet` mode every send is wrapped as `executeAsAgent` (agent door) or `execute` (owner door), and for cross-chain legs the AGW itself calls the gateway. So the AGW's CEA executes on the destination and the AGW's PC pays as `msg.value`. The SDK never uses the signer's own Route 2, which would run through the agent's CEA instead of the wallet's. Any `from` (Routes 3 and 4) is rejected in `agenticWallet` mode with `FROM_NOT_ALLOWED`: it makes `msg.sender` a CEA, and the agent door check fails. + +What changes on the client in this mode: + +- `universal.account` is the wallet address string, so receipts show the AGW as `from`. `universal.origin` stays the signer's origin account. +- `getAccountStatus()` reports the signer's own UEA, not the wallet. +- The signer is whatever was passed to `initialize`. To top up the agent's UEA, find it with `PushChain.utils.account.deriveExecutorAccount(signer.account)` and send PC to it from a client initialized without `agenticWallet`. +- A Solana-keyed agent can act on Push and `eip155` destinations now, and on `solana:` destinations once the SVM rulebook ships. +- Agents read their own rules through `client.agentic.wallet(addr).rules.list()`. +- `tx.data` arrays and `tx.funds` (moving the AGW's PRC20) work as they do for any account. +- `payGasWith`, `migrateCEA`, `rescueFunds`, `prepareTransaction` and `executeTransactions` throw `NOT_ALLOWED_IN_AGENTIC_MODE`. + +```tsx +const tx = await agentClient.universal.sendTransaction({ // agent door, rule picked by the destination chain + to: { address: aavePool, chain: CHAIN.ETHEREUM_SEPOLIA }, + data: supplyData, +}); + +// tx: UniversalTxResponse +{ + hash: '0x6f2a...', + origin: 'eip155:11155111:0x7Be1...', // the agent's key, CAIP-10 + from: '0xWallet', // the AGW, not the signer + blockNumber: 1530n, + wait +} + +const receipt = await tx.wait(); +// receipt: UniversalTxReceipt +{ + status: 1, + hash: '0x6f2a...', + from: '0xWallet', + blockNumber: 1530n, + externalTxHash: '0x91c4...' // the leg executed by the AGW's CEA on Sepolia +} +``` + +The same EVM key initialized against two chains yields two UEAs (derived from namespace, chainId and owner), so the rule must name the UEA of the chain this client initializes against (see 1.b). + +# 3. Types + +### 3.a Client, options and namespace + +```tsx +type Address = `0x${string}`; +type Hex = `0x${string}`; +type ForeignChainNamespace = `eip155:${string}` | `solana:${string}`; +type ProgressHook = (p: ProgressEvent) => void; // ProgressEvent is core's shape: { id, title, message, level, response, timestamp } + +interface PushChainClient { + universal: UniversalNamespace; // in agenticWallet mode: account is the wallet + agentic: AgenticNamespace; // this page + market: MarketNamespace; // page 6 + job: JobNamespace; // page 7 + evaluation: EvaluationNamespace; // page 8 +} + +interface InitializeOptions { + network?: PUSH_NETWORK; + rpcUrls?: Partial>; + agenticWallet?: Address; // NEW: act as the wallet; door chosen by the signer's Push address + // enforceGasCheck is on when agenticWallet is set, except for the first action while the agent's UEA is not yet deployed (2.a) +} + +interface AgenticNamespace { + derive(opts?: { index?: number }): Promise<{ address: Address; index: number; deployed: boolean }>; + create(label: string, options: CreateOptions): Promise; + list(): Promise<{ wallets: WalletSummary[] }>; // connected signer only + wallet(address: Address): AgenticWallet; +} + +interface CreateOptions { + rules: Rule[]; // one entry per chain per agent, may be empty; each rule names its agent and optional ref + progressHook?: ProgressHook; // AGENTIC-TX-1xx +} + +// No AgentKey type, no curve, no chain. The agent is a Push address. A native key is its own EOA; any external key +// (EVM, Solana, anything) is its UEA, deterministic from (chain, owner), deployed lazily on first use. The AGW's agent +// door checks msg.sender == rules.agent; cross-VM signature verification already happened inside the UEA (page 1, D3). + +interface CreateResult { wallet: Address; index: number; rulesIds: Hex[]; tx: UniversalTxResponse } +interface WalletSummary { address: Address; index: number; label: string; deployed: boolean; rulesCount: number } +``` + +### 3.b Rules + +```tsx +type Rule = NativeRule | UniversalRule; // chainNamespace decides the rulebook: omitted = native, foreign = universal + +interface NativeRule { + agent: Address; // Push address: EOA, or the UEA of an external key (PushChain.utils.account.deriveExecutorAccount) + ref?: Hex; // emitted in RulesGranted, not interpreted + chainNamespace?: never; // omitted = the connected Push chain + target: Address; + selector: Selector | 'value-only'; + validUntil: number; + maxValuePerCall?: bigint; maxValueTotal?: bigint; maxCalls?: number; + pins?: { arg: number; expected: Hex | Address | bigint }[]; + amount?: { arg: number; maxPerCall: bigint; maxTotal?: bigint }; +} + +interface UniversalRule { + agent: Address; // same as NativeRule.agent + ref?: Hex; // same as NativeRule.ref + chainNamespace: ForeignChainNamespace; // "eip155:..." now; "solana:..." once the SVM rulebook ships + assets: AssetCap[]; // tokens the agent may move on chainNamespace; SDK resolves each to its PRC20 and asserts SOURCE_CHAIN_NAMESPACE + maxGasPerCall: bigint; // PC (wei) per outbound for the destination leg + validUntil: number; + allowedCalls: AllowedCall[]; // 1..32, all on chainNamespace +} + +interface AssetCap { + token: MoveableToken | Address; // the other chain's token address (MOVEABLE.TOKEN..) or the native marker; the contract stores the PRC20 + maxPerCall: bigint; + maxTotal?: bigint; +} + +type Selector = Hex | `${string}(${string})`; // '0x617ba037' or 'supply(address,uint256,address,uint16)' + +interface AllowedCall { target: Address; selector: Selector; beneficiary?: number; maxValue?: bigint } // beneficiary = arg index + +interface RulesRecord { + rulesId: Hex; + enabled: boolean; + chainNamespace: string; + agent: Address; // the Push address granted + validUntil: number; + ref: Hex; + rule: Rule; // decoded terms; NativeRule or UniversalRule + spent: Spent; // carried by rules.get and rules.list; no separate call +} + +type Spent = { kind: 'universal'; amountSpent: bigint } | { kind: 'native'; valueSpent: bigint; amountSpent: bigint; callsUsed: number }; // PROPOSED: one self-describing object, readable without knowing the rulebook +``` + +### 3.c Wallet handle and checkpoints + +```tsx +interface AgenticWallet { + address: Address; + info(): Promise; + owner(): Promise<{ owner: Address }>; // Push address as stored + setLabel(label: string, opts?: { progressHook?: ProgressHook }): Promise; // PROPOSED, page 1 item 10 + checkpoints(opts?: { sinceBlock?: bigint }): Promise<{ checkpoints: Checkpoint[] }>; + rules: { + list(): Promise<{ rules: RulesRecord[] }>; + get(rulesId: Hex): Promise; + add(rules: Rule[], opts?: { progressHook?: ProgressHook }): Promise<{ rulesIds: Hex[]; tx: UniversalTxResponse }>; + update(params: { rules: { rulesId: Hex; rule: Rule }[]; progressHook?: ProgressHook }): Promise<{ rules: { rulesId: Hex; replaced: Hex }[]; tx: UniversalTxResponse }>; // revoke plus grant; spend counters reset + revoke(rulesIds: Hex[], opts?: { progressHook?: ProgressHook }): Promise; + revoke(params: { all: true; progressHook?: ProgressHook }): Promise; + }; +} + +interface WalletInfo { address: Address; label: string; index: number; owner: Address; deployed: boolean; rulesCount: number } + +interface Checkpoint { seq: number; kind: 'OWNER_ACTION' | 'RULES_GRANTED' | 'RULES_REVOKED'; ref: Hex; blockNumber: bigint; txHash: Hex } +``` + +### 3.d Constants, PushChain.CONSTANTS.AGENTIC (new) + +```tsx +PushChain.CONSTANTS.AGENTIC[PUSH_NETWORK.TESTNET_DONUT] = { + FACTORY, RULES_POLICY, // RULES_POLICY is URP; no validator address (page 1, D3) + MAX_PINS: 8, MAX_ALLOWED_CALLS: 32, ENVELOPE_VERSION: 1, +}; +``` + +### 3.e Helpers, PushChain.utils.agentic (new) + +Pure functions with the same output as the on-chain views. + +```tsx +PushChain.utils.agentic = { + rulesId(agent, chainNamespace, grantNonce), // the id a grant produces, same as the contract assigns + actionId(target, selector), // id of one allowed call: hash of its target and selector + configId(wallet, rulesId, actionId), // key of one allowed call's stored config, under one rule on one wallet + encodeRules(rules, ctx), // ctx = wallet and chain context needed to resolve beneficiary offsets + decodeRules(bytes), + deriveWallet(owner, index), // any-owner variant of client.agentic.derive + compileCard(card, userInput, ctx), // used by page 6; lives here because it produces Rule[] +}; +``` + +### 3.f Errors and progress + +```tsx +class AgenticError extends Error { code: string; hint?: string } +class AgenticRevertError extends PushChainExecutionError {} +// decoded custom error from the AGW, URP or the factory; uses core's fields: +// code string +// decodedError { name, hint, selector, decoded } + +// codes +// create: AGENT_IS_OWNER, DUPLICATE_RULE, TARGET_NOT_ON_RULE_CHAIN, ASSET_CHAIN_MISMATCH +// initialize (agenticWallet): NOT_OWNER_OR_AGENT, WALLET_NOT_DEPLOYED, NOT_AGENTIC_WALLET +// rules.revoke: REVOKE_NEEDS_TARGET (bare revoke) +// sendTransaction: NO_RULES_FOR_CHAIN, FROM_NOT_ALLOWED (any from, Routes 3 and 4) +// agentic mode: NOT_ALLOWED_IN_AGENTIC_MODE (prepareTransaction, executeTransactions, payGasWith, migrateCEA, rescueFunds) + +// progress events, AGENTIC-TX (PROPOSED) +// AGENTIC-TX-101 wallet derived { address, index, deployed } +// AGENTIC-TX-102 deploy step added +// AGENTIC-TX-104 rules granted { rulesIds } +// AGENTIC-TX-105 rules revoked { rulesIds | all } +// AGENTIC-TX-106 label set +// AGENTIC-TX-107 rule resolved for a send { rulesId, chainNamespace, door } +// AGENTIC-TX-199-01 done +// AGENTIC-TX-199-02 failed { code, decodedError } +// The Push leg of any agentic send also emits core's SEND-TX-1xx events. +// A cross-chain leg sent by the AGW emits 209-xx and 299-xx, never 201 to 204 (the signer's own Route 2 is never used). +``` + +**PROPOSED:** the AGENTIC-TX event list. Every write (`create`, `setLabel`, `rules.add`, `rules.update`, `rules.revoke`) takes a per-call `progressHook`; a `progressHook` passed to `PushChain.initialize` runs alongside it, as in core. + +`NO_RULES_FOR_CHAIN` is thrown before any signature and costs nothing. The rules lookup is one read on every send, not cached at initialize. A URP revert is thrown from `sendTransaction` as `AgenticRevertError` and also lands as `decodedError` on AGENTIC-TX-199-02. A destination-chain revert after URP passed still counts the spend, because the spend is counted when the outbound leaves Push; whether it is credited back depends on [1. AGW Contract Changes (nomenclature standard + change set)](1-agw-contract-changes.md) item 6 (`creditRevert`). + +# 4. Outside change: [PushChain.CONSTANTS.READ](http://PushChain.CONSTANTS.READ).CHAIN (confirmed 2026-09-28) + +Problem: `read()` takes `chain: PushChain.CONSTANTS.CHAIN.X`, but `CHAIN` is the set of blockchains the SDK signs for and routes to. Web2 is not one, so `CHAIN.WEB2` exists as a hidden (non-enumerable) member: it works if you know it is there and never appears in any listing. Reads have a wider domain than transactions: anything validators can observe. + +Change: a read-specific constant that is a superset of `CHAIN`. The field name stays `chain`, so nothing breaks, and `CHAIN` values remain valid because the strings are identical. + +```tsx +PushChain.CONSTANTS.READ.CHAIN = { + ...PushChain.CONSTANTS.CHAIN, // every real chain, same string values + WEB2: 'web2', // non-chain source, first-class here, enumerable +}; +type ReadChain = CHAIN | 'web2'; // ReadParams.chain: ReadChain + +read({ chain: PushChain.CONSTANTS.READ.CHAIN.WEB2, ... }) +read({ chain: PushChain.CONSTANTS.CHAIN.ETHEREUM_SEPOLIA, ... }) // still compiles +``` + +- `CHAIN.WEB2` becomes a deprecated alias of `READ.CHAIN.WEB2` for one release (the docs listed it on 2026-09-22), then goes. +- Anything that iterates `CHAIN` stops seeing a fake chain; anything that iterates `READ.CHAIN` sees every read source. +- The evaluator's `Read.chain` (page 8) takes the same values, so `READ.CHAIN` is the one constant the read SDK and the criteria compiler share. + +# 5. Open for review + +1. `rules.update` resets spend counters because it is revoke plus grant. Accepted for v1 and stated in 1.l; an in-place update is a contract change with no demand yet. +2. `setLabel` assumes [1. AGW Contract Changes (nomenclature standard + change set)](1-agw-contract-changes.md) item 10 lands. Pointer for the team. \ No newline at end of file diff --git a/plan/agw/notion/history/20261007T102718466408Z/manifest-before.json b/plan/agw/notion/history/20261007T102718466408Z/manifest-before.json new file mode 100644 index 00000000..2d3a634a --- /dev/null +++ b/plan/agw/notion/history/20261007T102718466408Z/manifest-before.json @@ -0,0 +1,178 @@ +{ + "schema_version": 1, + "snapshot_date": "2026-10-03", + "notes": "Page content preserved; known intra-export links normalized to local filenames. Comment threads excluded by Notion export. Null edit dates mean not observed. Original bundle retained.", + "sources": [ + { + "title": "AGW design overview", + "page_id": "3e9188aea7f481c8b38ccba332b0afa2", + "notion_url": "https://app.notion.com/p/pushprotocol/AGW-UniversalMarketplace-8183-UniversalEvaluator-3e9188aea7f481c8b38ccba332b0afa2", + "local_file": "notion/overview.md", + "pulled_on": "2026-10-03", + "observed_last_edited_date": "2026-10-01", + "authority": "Supporting design", + "sha256": "f2d7954e018324a937282ca190f397cc12a27973a07c891f3edfd6e89383c53e", + "export_entry": "Private & Shared/AGW + UniversalMarketplace + 8183 + UniversalEvalu 3e9188aea7f481c8b38ccba332b0afa2.md", + "raw_export_sha256": "99b727bd58cf588b2c766dc1b93eff402c47e918718b69c2a456b119ad43435b", + "archive": "notion/exports/20261003T075310278902Z/export-1.zip", + "pulled_at": "2026-10-03T07:53:10.278902+00:00" + }, + { + "title": "1 AGW Contract Changes", + "page_id": "3e9188aea7f4813aa31fc95ceb4e684d", + "notion_url": "https://app.notion.com/p/pushprotocol/1-AGW-Contract-Changes-nomenclature-standard-change-set-3e9188aea7f4813aa31fc95ceb4e684d", + "local_file": "notion/1-agw-contract-changes.md", + "pulled_on": "2026-10-03", + "observed_last_edited_date": "2026-10-02", + "authority": "WIP contract target", + "sha256": "f1301d8ff1cf370968b90a3d53037ece8fa4c6783c45a402f9be6998928e3631", + "export_entry": "Private & Shared/AGW + UniversalMarketplace + 8183 + UniversalEvalu/1 AGW Contract Changes (nomenclature standard + ch 3e9188aea7f4813aa31fc95ceb4e684d.md", + "raw_export_sha256": "f1301d8ff1cf370968b90a3d53037ece8fa4c6783c45a402f9be6998928e3631", + "archive": "notion/exports/20261003T075310278902Z/export-1.zip", + "pulled_at": "2026-10-03T07:53:10.278902+00:00", + "observed_last_edited_at": "2026-10-02T20:50:00+05:30" + }, + { + "title": "2 Universal Marketplace", + "page_id": "3e9188aea7f48118b90ac9b267496295", + "notion_url": "https://app.notion.com/p/pushprotocol/2-Universal-Marketplace-3e9188aea7f48118b90ac9b267496295", + "local_file": "notion/2-universal-marketplace.md", + "pulled_on": "2026-10-03", + "observed_last_edited_date": null, + "authority": "Supporting WIP design", + "sha256": "5ddfd9e8980faae9eec85e3959cc99edbb3b115565af289c5603a91df0b78d18", + "export_entry": "Private & Shared/AGW + UniversalMarketplace + 8183 + UniversalEvalu/2 Universal Marketplace 3e9188aea7f48118b90ac9b267496295.md", + "raw_export_sha256": "5ddfd9e8980faae9eec85e3959cc99edbb3b115565af289c5603a91df0b78d18", + "archive": "notion/exports/20261003T075310278902Z/export-1.zip", + "pulled_at": "2026-10-03T07:53:10.278902+00:00" + }, + { + "title": "3 ERC-8183 job kernel and hook", + "page_id": "3e9188aea7f48188a838c3a740d8c858", + "notion_url": "https://app.notion.com/p/pushprotocol/3-8183-job-kernel-and-hook-3e9188aea7f48188a838c3a740d8c858", + "local_file": "notion/3-8183-job-kernel-and-hook.md", + "pulled_on": "2026-10-03", + "observed_last_edited_date": null, + "authority": "Supporting WIP design", + "sha256": "3c805db465f2d39db8d34179ac1dd864db1abf7b1b3e93f38074fbf393093f90", + "export_entry": "Private & Shared/AGW + UniversalMarketplace + 8183 + UniversalEvalu/3 8183 (job kernel and hook) 3e9188aea7f48188a838c3a740d8c858.md", + "raw_export_sha256": "3c805db465f2d39db8d34179ac1dd864db1abf7b1b3e93f38074fbf393093f90", + "archive": "notion/exports/20261003T075310278902Z/export-1.zip", + "pulled_at": "2026-10-03T07:53:10.278902+00:00" + }, + { + "title": "4 Universal Evaluation", + "page_id": "3e9188aea7f4817bb03ef4c78c883f8b", + "notion_url": "https://app.notion.com/p/pushprotocol/4-Universal-Evaluation-3e9188aea7f4817bb03ef4c78c883f8b", + "local_file": "notion/4-universal-evaluation.md", + "pulled_on": "2026-10-03", + "observed_last_edited_date": null, + "authority": "Supporting WIP design", + "sha256": "a2f1c93a75b8631c9628c06f1be135fa0198f00f096a765ce808dd5e544b2d6f", + "export_entry": "Private & Shared/AGW + UniversalMarketplace + 8183 + UniversalEvalu/4 Universal Evaluation 3e9188aea7f4817bb03ef4c78c883f8b.md", + "raw_export_sha256": "a2f1c93a75b8631c9628c06f1be135fa0198f00f096a765ce808dd5e544b2d6f", + "archive": "notion/exports/20261003T075310278902Z/export-1.zip", + "pulled_at": "2026-10-03T07:53:10.278902+00:00" + }, + { + "title": "5 SDK AGW", + "page_id": "3e9188aea7f481cf8e8de324956549b9", + "notion_url": "https://app.notion.com/p/pushprotocol/5-SDK-AGW-3e9188aea7f481cf8e8de324956549b9", + "local_file": "notion/5-sdk-agw.md", + "pulled_on": "2026-10-03", + "observed_last_edited_date": null, + "authority": "Primary SDK API target", + "sha256": "e407ee77cdf874db7ef4697f84e9945ff3a12a2f2e07e8a7f90bd24e93ea32f1", + "export_entry": "Private & Shared/AGW + UniversalMarketplace + 8183 + UniversalEvalu/5 SDK AGW 3e9188aea7f481cf8e8de324956549b9.md", + "raw_export_sha256": "9a16f8aed79fac09818ec216fb4c69dc79f2fa0cffe0af611af956eb0e69f33f", + "archive": "notion/exports/20261003T075310278902Z/export-1.zip", + "pulled_at": "2026-10-03T07:53:10.278902+00:00", + "previous_observed_last_edited_date": "2026-10-01" + }, + { + "title": "6 SDK Universal Marketplace", + "page_id": "3ea188aea7f481e2961ed97129f3a4e6", + "notion_url": "https://app.notion.com/p/pushprotocol/6-SDK-Universal-Marketplace-3ea188aea7f481e2961ed97129f3a4e6", + "local_file": "notion/6-sdk-universal-marketplace.md", + "pulled_on": "2026-10-03", + "observed_last_edited_date": "2026-09-30", + "authority": "Supporting WIP SDK", + "sha256": "e7298952f2ba9adb218b4ef0459b8fa696a2072167dc5f655060b69788cf528c", + "export_entry": "Private & Shared/AGW + UniversalMarketplace + 8183 + UniversalEvalu/6 SDK Universal Marketplace 3ea188aea7f481e2961ed97129f3a4e6.md", + "raw_export_sha256": "e7298952f2ba9adb218b4ef0459b8fa696a2072167dc5f655060b69788cf528c", + "archive": "notion/exports/20261003T075310278902Z/export-1.zip", + "pulled_at": "2026-10-03T07:53:10.278902+00:00" + }, + { + "title": "7 SDK ERC-8183 Job", + "page_id": "3ea188aea7f481e0a137f5a896723376", + "notion_url": "https://app.notion.com/p/pushprotocol/7-SDK-8183-Job-3ea188aea7f481e0a137f5a896723376", + "local_file": "notion/7-sdk-8183-job.md", + "pulled_on": "2026-10-03", + "observed_last_edited_date": null, + "authority": "Supporting WIP SDK", + "sha256": "dbf1ff539f5df944e5f5f55710f5f6d3359469a141038cec2604e7c33392752c", + "export_entry": "Private & Shared/AGW + UniversalMarketplace + 8183 + UniversalEvalu/7 SDK 8183 Job 3ea188aea7f481e0a137f5a896723376.md", + "raw_export_sha256": "dbf1ff539f5df944e5f5f55710f5f6d3359469a141038cec2604e7c33392752c", + "archive": "notion/exports/20261003T075310278902Z/export-1.zip", + "pulled_at": "2026-10-03T07:53:10.278902+00:00" + }, + { + "title": "8 SDK Universal Evaluation", + "page_id": "3ea188aea7f48197a3b3cfdedfa74fee", + "notion_url": "https://app.notion.com/p/pushprotocol/8-SDK-Universal-Evaluation-3ea188aea7f48197a3b3cfdedfa74fee", + "local_file": "notion/8-sdk-universal-evaluation.md", + "pulled_on": "2026-10-03", + "observed_last_edited_date": null, + "authority": "Supporting WIP SDK", + "sha256": "eb2e584bd76aeea06c0dd03b3c8802b2340acf955e1ea75bf7768ebf9d2ab34e", + "export_entry": "Private & Shared/AGW + UniversalMarketplace + 8183 + UniversalEvalu/8 SDK Universal Evaluation 3ea188aea7f48197a3b3cfdedfa74fee.md", + "raw_export_sha256": "eb2e584bd76aeea06c0dd03b3c8802b2340acf955e1ea75bf7768ebf9d2ab34e", + "archive": "notion/exports/20261003T075310278902Z/export-1.zip", + "pulled_at": "2026-10-03T07:53:10.278902+00:00" + }, + { + "title": "Legacy PUSH AGW SDK Doc v1", + "page_id": "d2d188aea7f4825cbcea81ef86eca607", + "notion_url": "https://app.notion.com/p/pushprotocol/PUSH-AGW-SDK-Doc-v1-d2d188aea7f4825cbcea81ef86eca607", + "local_file": "notion/legacy-agw-sdk-v1.md", + "pulled_on": "2026-10-03", + "observed_last_edited_date": "2026-09-22", + "authority": "Historical encoding and deployment reference", + "sha256": "9e6569ef9b76d59cb411d65305d67333c6766abc2e9c80a35ae6f56f12f70916", + "raw_export_sha256": "9e6569ef9b76d59cb411d65305d67333c6766abc2e9c80a35ae6f56f12f70916", + "pulled_at": "2026-10-03T07:53:10.278902+00:00", + "archive": "notion/exports/20261003T075310278902Z/export-2.zip", + "export_entry": "Private & Shared/PUSH AGW SDK Doc - v1 d2d188aea7f4825cbcea81ef86eca607.md" + }, + { + "title": "AGW Address Book PC Donut", + "page_id": "3d1188aea7f480ddbb4af6d0efb211e6", + "notion_url": "https://app.notion.com/p/pushprotocol/AGW-Address-Book-PC-Donut-3d1188aea7f480ddbb4af6d0efb211e6", + "local_file": "notion/agw-address-book-donut-2026-09-04.md", + "pulled_on": "2026-10-03", + "observed_last_edited_date": "2026-09-04", + "authority": "Historical deployment", + "sha256": "5c5017d6b4a58af0fa8854ef550b054c1f33d57a812ea51a16f31f7c33e79742", + "raw_export_sha256": "5c5017d6b4a58af0fa8854ef550b054c1f33d57a812ea51a16f31f7c33e79742", + "pulled_at": "2026-10-03T07:53:10.278902+00:00", + "archive": "notion/exports/20261003T075310278902Z/export-3.zip", + "export_entry": "Private & Shared/AGW Address Book - PC Donut 3d1188aea7f480ddbb4af6d0efb211e6.md" + }, + { + "title": "Agentic wallet flow updated", + "page_id": "3d1188aea7f4801f9cb3fbd9318ec536", + "notion_url": "https://app.notion.com/p/pushprotocol/agentic_wallet_flow-updated-3d1188aea7f4801f9cb3fbd9318ec536", + "local_file": "notion/agentic-wallet-flow-2026-09-07.md", + "pulled_on": "2026-10-03", + "observed_last_edited_date": "2026-09-07", + "authority": "Historical validator-based flow", + "sha256": "d4a922fd1d33da5a7042f26053e8df0e496c3ccd4cb0044b0892948ac509c3a0", + "raw_export_sha256": "d4a922fd1d33da5a7042f26053e8df0e496c3ccd4cb0044b0892948ac509c3a0", + "pulled_at": "2026-10-03T07:53:10.278902+00:00", + "archive": "notion/exports/20261003T075310278902Z/export-4.zip", + "export_entry": "Private & Shared/agentic_wallet_flow ( updated ) 3d1188aea7f4801f9cb3fbd9318ec536.md" + } + ], + "last_refresh_at": "2026-10-03T07:53:10.278902+00:00" +} diff --git a/plan/agw/notion/history/20261007T102718466408Z/refresh.json b/plan/agw/notion/history/20261007T102718466408Z/refresh.json new file mode 100644 index 00000000..411ca31f --- /dev/null +++ b/plan/agw/notion/history/20261007T102718466408Z/refresh.json @@ -0,0 +1,124 @@ +{ + "run_id": "20261007T102718466408Z", + "pulled_at": "2026-10-07T10:27:18.466408+00:00", + "complete": true, + "missing_page_ids": [], + "unknown_export_entries": [], + "archives": [ + "notion/exports/20261007T102718466408Z/export-1.zip", + "notion/exports/20261007T102718466408Z/export-2.zip", + "notion/exports/20261007T102718466408Z/export-3.zip", + "notion/exports/20261007T102718466408Z/export-4.zip" + ], + "pages": [ + { + "page_id": "3e9188aea7f481c8b38ccba332b0afa2", + "title": "AGW design overview", + "local_file": "notion/overview.md", + "changed": false, + "previous_sha256": "f2d7954e018324a937282ca190f397cc12a27973a07c891f3edfd6e89383c53e", + "sha256": "f2d7954e018324a937282ca190f397cc12a27973a07c891f3edfd6e89383c53e", + "raw_export_sha256": "99b727bd58cf588b2c766dc1b93eff402c47e918718b69c2a456b119ad43435b" + }, + { + "page_id": "3e9188aea7f4813aa31fc95ceb4e684d", + "title": "1 AGW Contract Changes", + "local_file": "notion/1-agw-contract-changes.md", + "changed": false, + "previous_sha256": "f1301d8ff1cf370968b90a3d53037ece8fa4c6783c45a402f9be6998928e3631", + "sha256": "f1301d8ff1cf370968b90a3d53037ece8fa4c6783c45a402f9be6998928e3631", + "raw_export_sha256": "f1301d8ff1cf370968b90a3d53037ece8fa4c6783c45a402f9be6998928e3631" + }, + { + "page_id": "3e9188aea7f48118b90ac9b267496295", + "title": "2 Universal Marketplace", + "local_file": "notion/2-universal-marketplace.md", + "changed": false, + "previous_sha256": "5ddfd9e8980faae9eec85e3959cc99edbb3b115565af289c5603a91df0b78d18", + "sha256": "5ddfd9e8980faae9eec85e3959cc99edbb3b115565af289c5603a91df0b78d18", + "raw_export_sha256": "5ddfd9e8980faae9eec85e3959cc99edbb3b115565af289c5603a91df0b78d18" + }, + { + "page_id": "3e9188aea7f48188a838c3a740d8c858", + "title": "3 ERC-8183 job kernel and hook", + "local_file": "notion/3-8183-job-kernel-and-hook.md", + "changed": false, + "previous_sha256": "3c805db465f2d39db8d34179ac1dd864db1abf7b1b3e93f38074fbf393093f90", + "sha256": "3c805db465f2d39db8d34179ac1dd864db1abf7b1b3e93f38074fbf393093f90", + "raw_export_sha256": "3c805db465f2d39db8d34179ac1dd864db1abf7b1b3e93f38074fbf393093f90" + }, + { + "page_id": "3e9188aea7f4817bb03ef4c78c883f8b", + "title": "4 Universal Evaluation", + "local_file": "notion/4-universal-evaluation.md", + "changed": false, + "previous_sha256": "a2f1c93a75b8631c9628c06f1be135fa0198f00f096a765ce808dd5e544b2d6f", + "sha256": "a2f1c93a75b8631c9628c06f1be135fa0198f00f096a765ce808dd5e544b2d6f", + "raw_export_sha256": "a2f1c93a75b8631c9628c06f1be135fa0198f00f096a765ce808dd5e544b2d6f" + }, + { + "page_id": "3e9188aea7f481cf8e8de324956549b9", + "title": "5 SDK AGW", + "local_file": "notion/5-sdk-agw.md", + "changed": true, + "previous_sha256": "e407ee77cdf874db7ef4697f84e9945ff3a12a2f2e07e8a7f90bd24e93ea32f1", + "sha256": "d3bc55b08a37d762c49173149fd8d554a8551682c0956de3e91394a54bfed9a6", + "raw_export_sha256": "8d024eb2bd2955fc772d2194f50a02d601a2d5bf903b0c9cc74882ee11348130" + }, + { + "page_id": "3ea188aea7f481e2961ed97129f3a4e6", + "title": "6 SDK Universal Marketplace", + "local_file": "notion/6-sdk-universal-marketplace.md", + "changed": false, + "previous_sha256": "e7298952f2ba9adb218b4ef0459b8fa696a2072167dc5f655060b69788cf528c", + "sha256": "e7298952f2ba9adb218b4ef0459b8fa696a2072167dc5f655060b69788cf528c", + "raw_export_sha256": "e7298952f2ba9adb218b4ef0459b8fa696a2072167dc5f655060b69788cf528c" + }, + { + "page_id": "3ea188aea7f481e0a137f5a896723376", + "title": "7 SDK ERC-8183 Job", + "local_file": "notion/7-sdk-8183-job.md", + "changed": false, + "previous_sha256": "dbf1ff539f5df944e5f5f55710f5f6d3359469a141038cec2604e7c33392752c", + "sha256": "dbf1ff539f5df944e5f5f55710f5f6d3359469a141038cec2604e7c33392752c", + "raw_export_sha256": "dbf1ff539f5df944e5f5f55710f5f6d3359469a141038cec2604e7c33392752c" + }, + { + "page_id": "3ea188aea7f48197a3b3cfdedfa74fee", + "title": "8 SDK Universal Evaluation", + "local_file": "notion/8-sdk-universal-evaluation.md", + "changed": false, + "previous_sha256": "eb2e584bd76aeea06c0dd03b3c8802b2340acf955e1ea75bf7768ebf9d2ab34e", + "sha256": "eb2e584bd76aeea06c0dd03b3c8802b2340acf955e1ea75bf7768ebf9d2ab34e", + "raw_export_sha256": "eb2e584bd76aeea06c0dd03b3c8802b2340acf955e1ea75bf7768ebf9d2ab34e" + }, + { + "page_id": "d2d188aea7f4825cbcea81ef86eca607", + "title": "Legacy PUSH AGW SDK Doc v1", + "local_file": "notion/legacy-agw-sdk-v1.md", + "changed": false, + "previous_sha256": "9e6569ef9b76d59cb411d65305d67333c6766abc2e9c80a35ae6f56f12f70916", + "sha256": "9e6569ef9b76d59cb411d65305d67333c6766abc2e9c80a35ae6f56f12f70916", + "raw_export_sha256": "9e6569ef9b76d59cb411d65305d67333c6766abc2e9c80a35ae6f56f12f70916" + }, + { + "page_id": "3d1188aea7f480ddbb4af6d0efb211e6", + "title": "AGW Address Book PC Donut", + "local_file": "notion/agw-address-book-donut-2026-09-04.md", + "changed": false, + "previous_sha256": "5c5017d6b4a58af0fa8854ef550b054c1f33d57a812ea51a16f31f7c33e79742", + "sha256": "5c5017d6b4a58af0fa8854ef550b054c1f33d57a812ea51a16f31f7c33e79742", + "raw_export_sha256": "5c5017d6b4a58af0fa8854ef550b054c1f33d57a812ea51a16f31f7c33e79742" + }, + { + "page_id": "3d1188aea7f4801f9cb3fbd9318ec536", + "title": "Agentic wallet flow updated", + "local_file": "notion/agentic-wallet-flow-2026-09-07.md", + "changed": false, + "previous_sha256": "d4a922fd1d33da5a7042f26053e8df0e496c3ccd4cb0044b0892948ac509c3a0", + "sha256": "d4a922fd1d33da5a7042f26053e8df0e496c3ccd4cb0044b0892948ac509c3a0", + "raw_export_sha256": "d4a922fd1d33da5a7042f26053e8df0e496c3ccd4cb0044b0892948ac509c3a0" + } + ], + "review_status": "Review required" +} diff --git a/plan/agw/questions-harsh.md b/plan/agw/questions-harsh.md index 7b6a1639..612b716a 100644 --- a/plan/agw/questions-harsh.md +++ b/plan/agw/questions-harsh.md @@ -22,4 +22,4 @@ Keep both ABI argument-index and raw-offset inputs, with exact offsets on reads. The intended behavior is that the existing contract rejects unauthorized functions/actions under the supplied rule, and the SDK maps those errors. This does not request automatic rule selection or a new contract interface. The SDK retains `AMBIGUOUS_RULE` when multiple enabled rules match the agent and chain, without submitting a transaction. No caller-facing rule selector is being added. -Rule `ref` is removed from scope; editable labels remain pending contract delivery. [Zaryab delivery items](questions-zaryab.md). +Rule `ref` is removed from scope; editable labels are delivered and implemented against v5. [Zaryab delivery items](questions-zaryab.md). diff --git a/plan/agw/questions-zaryab.md b/plan/agw/questions-zaryab.md index dd4bef74..dc44347a 100644 --- a/plan/agw/questions-zaryab.md +++ b/plan/agw/questions-zaryab.md @@ -1,16 +1,12 @@ -# AGW SDK — remaining contract delivery items +# AGW SDK — contract delivery status -Updated October 7, 2026. Product direction is settled; the SDK needs the label interface to finish integration. Freshly fetched `deploy-agw@10a24f1` and `pushAgenticWallet_v3@e8db748` still lack an editable-label interface. +Updated October 7, 2026 after the v5 deployment. **No remaining standalone AGW contract question needs an answer from Zaryab.** -## Editable wallet labels - -`setLabel` will be fixed by Zaryab. Please share the implemented function/event ABI and compatible deployment so the SDK can enable owner-only label updates and verify subsequent reads. The current contracts expose only a deployment label. +The label interface and compatible deployment are delivered in `deploy-agw@bd230d2` (deployed source `2e61e13`). The SDK now uses the new factory, reads stored labels and implements owner-only `setLabel` with empty reset and the 64-byte limit. [Deployment verification](research/deployment-review-2026-10-07-v5/README.md) · [SDK migration and acceptance](research/v5-implementation-2026-10-07/README.md). -## Settled scope - -Named IDL inputs are approved for public Solana authoring. Rule `ref` is removed. Zero native PC defaults and the existing token model are retained. Native/EVM inputs accept argument indexes or raw offsets, and reads preserve exact offsets. Existing contract validation rejects unauthorized actions and the SDK maps errors. AMBIGUOUS_RULE remains for multiple candidates; no automatic-selection contract change is requested. +Named-IDL Solana authoring, removal of rule `ref`, zero native PC defaults and the existing token model remain settled. Native/EVM inputs accept argument indexes or raw offsets. The SDK retains AMBIGUOUS_RULE; the contract validates the supplied rule. No automatic-selection interface change is requested. -[Inspected contract source](https://github.com/pushchain/push-agentic-wallets/blob/10a24f101e2e6e0a9b76517b29f5cdb1aa967796/src/AGW.sol#L823) · [Consumer SDK guide](../../packages/core/AGW.md). +Push-core spend credit and bridge retry timing remain separate downstream follow-ups. They do not block the label integration. diff --git a/plan/agw/research/deployment-review-2026-10-07-v5/README.md b/plan/agw/research/deployment-review-2026-10-07-v5/README.md new file mode 100644 index 00000000..47d3be4a --- /dev/null +++ b/plan/agw/research/deployment-review-2026-10-07-v5/README.md @@ -0,0 +1,54 @@ +# Donut v5 deployment check — 7 October 2026 + +The label contract dependency is delivered. SDK migration and label implementation remain to be done. This check changes no production SDK code and broadcasts no transactions. + +## Sources + +- [Current address book](https://github.com/pushchain/push-agentic-wallets/blob/bd230d20dbf778d9994b1f1082f79b1a8829a10f/docs/addresses/donut.md). +- [Owner integration guide](https://github.com/pushchain/push-agentic-wallets/blob/bd230d20dbf778d9994b1f1082f79b1a8829a10f/docs/5_SDK_Owner_Integration.md). +- Fetched `origin/deploy-agw`: `bd230d20dbf778d9994b1f1082f79b1a8829a10f` (PR #17). +- Address book identifies deployed contract source as `2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb`. Later commits deploy the suite, update docs and remove earlier deployment books. +- Exact inspected files are copied under [source/](source/). + +## Read-only network verification + +Donut RPC `https://evm.donut.rpc.push.org/`, chain ID 42101, pinned block **23991912**. See [donut-probe.json](donut-probe.json) and [label-readonly-check.json](label-readonly-check.json). + +| Component | Address | Result | +| --- | --- | --- | +| New factory proxy | `0x8137F96A50EBF41d904e3678c84c391a0D1BCcc5` | Code exists; unpaused; implementation slot points to the new factory logic | +| New factory logic | `0xe549d3D4e85cB16F687448D7acA21D9d13A7cD0f` | 10,013 runtime bytes | +| New wallet implementation | `0x4D459Da499C14548aa16c46c57fD92880A88EBb4` | 17,584 runtime bytes; factory getter agrees; label/init selectors present | +| URP proxy | `0x603E7f0aF6e1aAFf46DDfb28b1e99364f8BC59af` | Same bytecode, implementation/admin slots and version 3.1.0 as the prior probe | +| Engine / validator / gateway | See probe | Bytecode and inspected wiring unchanged | + +The wallet implementation's `accountId()` is still `push.agw.1.0.0`; it cannot identify label capability by itself. + +The SDK's existing clone derivation formula, supplied with the new factory and implementation, matches live `predictWallet(owner, 0)`. Immutable clone arguments and salt formula are unchanged. Addresses change because the factory and implementation change, not because the label is part of the address. + +`eth_call` simulations of the live factory's `deployWallet` succeed for an empty label, 64 ASCII bytes, and 16 four-byte emoji. Labels of 65 ASCII bytes and 17 emoji revert with `LabelTooLong(65)` and `LabelTooLong(68)` respectively. No wallets were actually created. + +There were no `WalletDeployed` events from this factory between its deployment and the pinned block. Therefore successful rename/reset transactions, actual clone label reads and their checkpoint effects have **not** been exercised on a live wallet. Source and the contract team's label tests establish the intended semantics; this check is not a full source-bytecode equivalence proof or security audit. + +Probe `unchanged` fields compare against the older v4 probe: a false value for new factory logic, wallet implementation or factory wiring is expected. The proxy runtime itself is identical despite the changed address. Initial log scan exceeded the RPC's 1,000-block range limit; the completed scan uses bounded pages. + +## Label behavior in exact source + +- `label()` returns the stored custom label, otherwise `AGW `. +- Owner or wallet-self may call `setLabel(string)`; wallet-self enables signed owner-door execution. Agent dispatch cannot target the wallet. +- Empty string resets the default. Maximum length is **64 UTF-8 bytes**, not 64 characters. +- `LabelSet(string)` emits the supplied string, including empty on reset. +- Direct setter adds no checkpoint. A rename through `execute` or `executeWithSig` adds the normal owner-action checkpoint. +- Initialization changed from `initializeAccount()` to `initializeAccount(string)`; factory stores the supplied label through initialization. +- Signed deployment still does **not** bind the label in OwnerIntent. The relayer can choose this cosmetic value; the owner can rename afterward. This is documented and deliberately tested upstream. +- v4 wallets stay at their existing addresses and do not gain label methods. + +## SDK changes needed + +1. Replace the v4-only deployment binding with v5, including addresses, source pin, start block, EIP-712 factory domain and verification fixtures. Preserve the unchanged rule encoding and selection behavior. +2. Refresh durable ABI/artifact snapshots and local real-contract harness for the new initializer, label views/setter/event and `LabelTooLong` error. +3. Implement the existing public `wallet.setLabel()` method using the owner authorization path. Validate the UTF-8 byte cap consistently for create and rename; permit empty reset. +4. Read current labels through `label()` in wallet `info()` and `list()`, replacing deploy-event label lookup. +5. Add unit/local/live E2Es for default numbering, custom deployment labels, rename/reset, boundaries and Unicode, owner authorization, agent refusal, signed owner execution, checkpoints and v5 address/domain derivation. + +No new caller-facing method is needed: `setLabel` is already exposed but currently throws capability unavailable. Following the user's existing no-legacy-baggage direction, migration should target the current v5 suite rather than add a second v4 adapter. Existing uncommitted SVM alignment work was preserved. diff --git a/plan/agw/research/deployment-review-2026-10-07-v5/donut-probe.json b/plan/agw/research/deployment-review-2026-10-07-v5/donut-probe.json new file mode 100644 index 00000000..c5ea09ce --- /dev/null +++ b/plan/agw/research/deployment-review-2026-10-07-v5/donut-probe.json @@ -0,0 +1,167 @@ +{ + "checked_at": "2026-10-07T12:11:18.493Z", + "rpc": "https://evm.donut.rpc.push.org/", + "chain_id": 42101, + "block": "23991912", + "block_hash": "0x7ca084b733e457669ec0d87d4e67ca833014d64550d8d9a631fb398dd95bfc4f", + "code": { + "factory": { + "address": "0x8137F96A50EBF41d904e3678c84c391a0D1BCcc5", + "bytes": 141, + "sha256": "c621e945a17be2361dfc247326991d732ede3e25c8ecd8b48ee2025c10ca17eb", + "unchanged": true + }, + "gateway": { + "address": "0x00000000000000000000000000000000000000C1", + "bytes": 1551, + "sha256": "3e78a5778be1383f2612556becde8019c22388d7157574c90fb40e1060d450ca", + "unchanged": true + }, + "proxyAdmin": { + "address": "0x0b7a31ec85117892aEA90AA5cB6514e2F97c2295", + "bytes": 926, + "sha256": "3feda633be447e268d618b40cbfcd9dfe9346ebadec981f4f3efea0fbc07cd35", + "unchanged": true + }, + "executor": { + "address": "0x14191Ea54B4c176fCf86f51b0FAc7CB1E71Df7d7", + "bytes": 0, + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "unchanged": true + }, + "validator": { + "address": "0x068EE2388475A98EE1f5a434C58bFF3444fffFe6", + "bytes": 806, + "sha256": "7a8e45814fd8a0a6c9b9e115d797da078718f9f6358fa576e1e218ffd93db59e", + "unchanged": true + }, + "policy": { + "address": "0x603E7f0aF6e1aAFf46DDfb28b1e99364f8BC59af", + "bytes": 830, + "sha256": "039e9bca120a30980a0131552966575b30349654f23746f309fe98adfd2308ae", + "unchanged": true + }, + "core": { + "address": "0x00000000000000000000000000000000000000C0", + "bytes": 1551, + "sha256": "2036ba987ed029f1bc576d020ba11582934583c7eaaa7c00aefc2e0d53053486", + "unchanged": true + }, + "factoryLogic": { + "address": "0xe549d3D4e85cB16F687448D7acA21D9d13A7cD0f", + "bytes": 10013, + "sha256": "674c57210c4c0889e01491aedb5133e54f3e78c6450dcadf3c7d1aec54d1e50c", + "unchanged": false + }, + "walletImplementation": { + "address": "0x4D459Da499C14548aa16c46c57fD92880A88EBb4", + "bytes": 17584, + "sha256": "3354d9c2c4f97574748850910625a89793874b6b6a86682f3b131ec20a9df35e", + "unchanged": false + }, + "engine": { + "address": "0x165A5E6782f39D30B38c7D97e1303e4CB2aD102a", + "bytes": 22581, + "sha256": "c4b9fc7b045d9f33953079a91fcb7ae883dd858d9cde827a9cc3df6043bc2d0b", + "unchanged": true + }, + "policyImplementation": { + "address": "0xA2391eee4C9EA1B32AEB3A460B77296EA709F02F", + "bytes": 24326, + "sha256": "1694277b24a023615b3693730ea0581e7a6fc209f533e65416d5075ef927df76", + "unchanged": true + } + }, + "slots": { + "factory": { + "implementation": { + "value": "0x000000000000000000000000e549d3d4e85cb16f687448d7aca21d9d13a7cd0f", + "unchanged": false + } + }, + "policy": { + "implementation": { + "value": "0x000000000000000000000000a2391eee4c9ea1b32aeb3a460b77296ea709f02f", + "unchanged": true + }, + "admin": { + "value": "0x0000000000000000000000000b7a31ec85117892aea90aa5cb6514e2f97c2295", + "unchanged": true + } + }, + "gateway": { + "implementation": { + "value": "0x0000000000000000000000001e412939780f2b834dc42c7ac58d9f99888da659", + "unchanged": true + } + } + }, + "reads": [ + { + "contract": "factory", + "signature": "walletImplementation()(address)", + "value": "0x4D459Da499C14548aa16c46c57fD92880A88EBb4", + "unchanged": false + }, + { + "contract": "factory", + "signature": "paused()(bool)", + "value": "false", + "unchanged": true + }, + { + "contract": "policy", + "signature": "version()(string)", + "value": "3.1.0", + "unchanged": true + }, + { + "contract": "policy", + "signature": "pushChainHash()(bytes32)", + "value": "0x3d6bc1f1d3fb03065860265a8e93840b586e57075d956cd41b4319d040be87f9", + "unchanged": true + }, + { + "contract": "policy", + "signature": "UNIVERSAL_GATEWAY_PC()(address)", + "value": "0x00000000000000000000000000000000000000C1", + "unchanged": true + }, + { + "contract": "policy", + "signature": "UNIVERSAL_EXECUTOR_MODULE()(address)", + "value": "0x14191Ea54B4c176fCf86f51b0FAc7CB1E71Df7d7", + "unchanged": true + }, + { + "contract": "walletImplementation", + "signature": "accountId()(string)", + "value": "push.agw.1.0.0", + "unchanged": true + }, + { + "contract": "walletImplementation", + "signature": "SESSION_ENGINE()(address)", + "value": "0x165A5E6782f39D30B38c7D97e1303e4CB2aD102a", + "unchanged": true + }, + { + "contract": "walletImplementation", + "signature": "RULES_POLICY()(address)", + "value": "0x603E7f0aF6e1aAFf46DDfb28b1e99364f8BC59af", + "unchanged": true + }, + { + "contract": "walletImplementation", + "signature": "SESSION_VALIDATOR()(address)", + "value": "0x068EE2388475A98EE1f5a434C58bFF3444fffFe6", + "unchanged": true + }, + { + "contract": "walletImplementation", + "signature": "UNIVERSAL_GATEWAY_PC()(address)", + "value": "0x00000000000000000000000000000000000000C1", + "unchanged": true + } + ] +} diff --git a/plan/agw/research/deployment-review-2026-10-07-v5/label-check.cjs b/plan/agw/research/deployment-review-2026-10-07-v5/label-check.cjs new file mode 100644 index 00000000..0e636faf --- /dev/null +++ b/plan/agw/research/deployment-review-2026-10-07-v5/label-check.cjs @@ -0,0 +1,29 @@ +const fs=require('fs'),path=require('path'); +const {createPublicClient,http,parseAbi,parseAbiItem,toFunctionSelector,encodeAbiParameters,encodePacked,keccak256,concat,numberToHex,getContractAddress}=require(path.join(process.cwd(),'node_modules/viem')); +const dir='plan/agw/research/deployment-review-2026-10-07-v5'; +const probe=JSON.parse(fs.readFileSync(dir+'/donut-probe.json')); const block=BigInt(probe.block),factory=probe.code.factory.address,implementation=probe.code.walletImplementation.address; +const client=createPublicClient({transport:http(probe.rpc)}); +(async()=>{ +const logs=[]; for(let start=23989983n;start<=block;start+=1000n) {const end=start+999n>block?block:start+999n; logs.push(...await client.getLogs({address:factory,event:parseAbiItem('event WalletDeployed(address indexed owner, uint256 indexed index, address indexed wallet, string label)'),fromBlock:start,toBlock:end}));} +const code=await client.getCode({address:implementation,blockNumber:block}); +const result={block:String(block),selectors:Object.fromEntries(['label()','setLabel(string)','initializeAccount(string)'].map(s=>[s,{selector:toFunctionSelector(s),presentInRuntime:code.includes(toFunctionSelector(s).slice(2))}])),wallets:[]}; +for(const log of logs.slice(0,5)) { +const {owner,index,wallet,label}=log.args; +const abi=parseAbi(['function label() view returns (string)','function checkpointCount() view returns (uint64)','function setLabel(string)','error LabelTooLong(uint256 length)','error CallerIsNotOwner()']); +const reads={label:await client.readContract({address:wallet,abi,functionName:'label',blockNumber:block}),checkpointCount:String(await client.readContract({address:wallet,abi,functionName:'checkpointCount',blockNumber:block}))}; +const simulations=[]; +for(const [name,account,newLabel] of [['owner',owner,'SDK review'],['emptyReset',owner,''],['over64Bytes',owner,'a'.repeat(65)],['nonOwner','0x0000000000000000000000000000000000000001','SDK review']]) { +try {await client.simulateContract({address:wallet,abi,functionName:'setLabel',args:[newLabel],account,blockNumber:block});simulations.push({name,success:true});}catch(e){let c=e;while(c.cause)c=c.cause;simulations.push({name,success:false,errorName:c.data?.errorName||null,args:c.data?.args?.map(String)||[],message:e.shortMessage});}} +result.wallets.push({owner,index:String(index),wallet,deployLabel:label,reads,simulations}); +} +const sampleOwner=logs[0]?.args.owner||'0xa89523351BE1e2De64937AA9AF61Ae06eAd199C7'; +const count=await client.readContract({address:factory,abi:parseAbi(['function walletCount(address) view returns (uint256)']),functionName:'walletCount',args:[sampleOwner],blockNumber:block}); +const salt=keccak256(encodeAbiParameters([{type:'address'},{type:'uint96'}],[sampleOwner,count])); +const args=encodePacked(['address','address'],[sampleOwner,factory]); +const bytecode=concat(['0x61',numberToHex(85,{size:2}),'0x3d81600a3d39f3363d3d373d3d3d363d73',implementation,'0x5af43d82803e903d91602b57fd5bf3',args]); +const local=getContractAddress({opcode:'CREATE2',from:factory,salt,bytecodeHash:keccak256(bytecode)}); +const prediction=await client.readContract({address:factory,abi:parseAbi(['function predictWallet(address,uint256) view returns (address,bool)']),functionName:'predictWallet',args:[sampleOwner,count],blockNumber:block}); +result.derivation={owner:sampleOwner,index:String(count),local,predicted:prediction[0],matches:local.toLowerCase()===prediction[0].toLowerCase()}; +result.deploySimulations=[];for(const [name,label]of [['default',''],['64Bytes','a'.repeat(64)],['65Bytes','a'.repeat(65)],['16Emoji','🙂'.repeat(16)],['17Emoji','🙂'.repeat(17)]]){try{const simulated=await client.simulateContract({address:factory,abi:parseAbi(['function deployWallet(string) returns (address)','error LabelTooLong(uint256 length)']),functionName:'deployWallet',args:[label],account:sampleOwner,blockNumber:block});result.deploySimulations.push({name,success:true,wallet:simulated.result});}catch(e){const c=e.walk?.(x=>x.name==='ContractFunctionRevertedError');result.deploySimulations.push({name,success:false,errorName:c?.data?.errorName||null,args:c?.data?.args?.map(String)||[],message:e.shortMessage});}} +result.totalDeployedWalletEvents=logs.length;fs.writeFileSync(dir+'/label-readonly-check.json',JSON.stringify(result,null,2)+'\n');console.log(JSON.stringify(result,null,2)); +})(); diff --git a/plan/agw/research/deployment-review-2026-10-07-v5/label-readonly-check.json b/plan/agw/research/deployment-review-2026-10-07-v5/label-readonly-check.json new file mode 100644 index 00000000..bf9c9128 --- /dev/null +++ b/plan/agw/research/deployment-review-2026-10-07-v5/label-readonly-check.json @@ -0,0 +1,61 @@ +{ + "block": "23991912", + "selectors": { + "label()": { + "selector": "0xcb4774c4", + "presentInRuntime": true + }, + "setLabel(string)": { + "selector": "0xbf530969", + "presentInRuntime": true + }, + "initializeAccount(string)": { + "selector": "0x767df6cb", + "presentInRuntime": true + } + }, + "wallets": [], + "derivation": { + "owner": "0xa89523351BE1e2De64937AA9AF61Ae06eAd199C7", + "index": "0", + "local": "0x9E1e228d5Fb19e4c33fd8aF96de8492Ef59b6612", + "predicted": "0x9E1e228d5Fb19e4c33fd8aF96de8492Ef59b6612", + "matches": true + }, + "deploySimulations": [ + { + "name": "default", + "success": true, + "wallet": "0x9E1e228d5Fb19e4c33fd8aF96de8492Ef59b6612" + }, + { + "name": "64Bytes", + "success": true, + "wallet": "0x9E1e228d5Fb19e4c33fd8aF96de8492Ef59b6612" + }, + { + "name": "65Bytes", + "success": false, + "errorName": "LabelTooLong", + "args": [ + "65" + ], + "message": "The contract function \"deployWallet\" reverted." + }, + { + "name": "16Emoji", + "success": true, + "wallet": "0x9E1e228d5Fb19e4c33fd8aF96de8492Ef59b6612" + }, + { + "name": "17Emoji", + "success": false, + "errorName": "LabelTooLong", + "args": [ + "68" + ], + "message": "The contract function \"deployWallet\" reverted." + } + ], + "totalDeployedWalletEvents": 0 +} diff --git a/plan/agw/research/deployment-review-2026-10-07-v5/probe.cjs b/plan/agw/research/deployment-review-2026-10-07-v5/probe.cjs new file mode 100644 index 00000000..b3d2ccf3 --- /dev/null +++ b/plan/agw/research/deployment-review-2026-10-07-v5/probe.cjs @@ -0,0 +1,10 @@ +const fs=require('fs'),path=require('path'),crypto=require('crypto');const root=process.cwd();const {createPublicClient,http,parseAbi}=require(path.join(root,'node_modules/viem')); +const prior=JSON.parse(fs.readFileSync('plan/agw/research/deployment-review-2026-10-06/donut-probe.json')); +prior.code.factory.address='0x8137F96A50EBF41d904e3678c84c391a0D1BCcc5'; prior.code.factoryLogic.address='0xe549d3D4e85cB16F687448D7acA21D9d13A7cD0f'; prior.code.walletImplementation.address='0x4D459Da499C14548aa16c46c57fD92880A88EBb4'; +const client=createPublicClient({transport:http(prior.rpc)}); +(async()=>{const block=await client.getBlock();const result={checked_at:new Date().toISOString(),rpc:prior.rpc,chain_id:await client.getChainId(),block:String(block.number),block_hash:block.hash,code:{},slots:{},reads:[]}; +await Promise.all(Object.entries(prior.code).map(async([name,item])=>{const data=await client.getCode({address:item.address,blockNumber:block.number})||'0x';const bytes=Buffer.from(data.slice(2),'hex');const sha256=crypto.createHash('sha256').update(bytes).digest('hex');result.code[name]={address:item.address,bytes:bytes.length,sha256,unchanged:sha256===item.sha256};})); +const slots={implementation:'0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc',admin:'0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103'}; +for(const [name,rows]of Object.entries(prior.slots)){result.slots[name]={};for(const [kind,value]of Object.entries(rows)){const actual=await client.getStorageAt({address:prior.code[name].address,slot:slots[kind],blockNumber:block.number});result.slots[name][kind]={value:actual,unchanged:actual?.toLowerCase()===value.toLowerCase()};}} +for(const row of prior.reads){const name=row.signature.split('(')[0],type=row.signature.split(')(')[1].slice(0,-1);try{const value=await client.readContract({address:prior.code[row.contract].address,abi:parseAbi([`function ${name}() view returns (${type})`]),functionName:name,blockNumber:block.number});result.reads.push({contract:row.contract,signature:row.signature,value:String(value),unchanged:String(value).toLowerCase()===row.output.replaceAll('"','').toLowerCase()});}catch(e){result.reads.push({contract:row.contract,signature:row.signature,error:e.shortMessage||e.message});}} +fs.writeFileSync('plan/agw/research/deployment-review-2026-10-07-v5/donut-probe.json',JSON.stringify(result,null,2)+'\n');console.log(JSON.stringify({block:result.block,codeChanged:Object.entries(result.code).filter(([,v])=>!v.unchanged).map(([k])=>k),slots:result.slots,readMismatches:result.reads.filter(r=>!r.unchanged)}));})(); diff --git a/plan/agw/research/deployment-review-2026-10-07-v5/source/deployments/address-book-v5/push_agw_contracts.json b/plan/agw/research/deployment-review-2026-10-07-v5/source/deployments/address-book-v5/push_agw_contracts.json new file mode 100644 index 00000000..b35caae4 --- /dev/null +++ b/plan/agw/research/deployment-review-2026-10-07-v5/source/deployments/address-book-v5/push_agw_contracts.json @@ -0,0 +1,128 @@ +{ + "network": "push-donut-testnet", + "chainId": 42101, + "generation": "v5", + "explorer": "https://donut.push.network", + "commit": "git:2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", + "engineForkCommit": "7dc20e4", + "forge": "1.5.1-stable", + "deployer": "0xa89523351BE1e2De64937AA9AF61Ae06eAd199C7", + "deployScript": "script/DeployWalletAndFactory.s.sol", + "blocks": [ + 23989983, + 23989987 + ], + "deploymentGas": 6357076, + "deploymentCostPC": "0.0071517105", + "summary": "New AGW implementation (wallet label) and a new factory proxy + logic. The engine, URP (proxy, implementation, ProxyAdmin) and AgentValidator are reused from v4 unchanged: none stores a factory or wallet-implementation address, and their state is keyed per wallet.", + "contracts": { + "factoryProxy": { + "address": "0x8137F96A50EBF41d904e3678c84c391a0D1BCcc5", + "contract": "ERC1967Proxy (UUPS)", + "sizeBytes": 141, + "verified": true, + "explorer": "https://donut.push.network/address/0x8137F96A50EBF41d904e3678c84c391a0D1BCcc5", + "deployTx": "0x7294e0aff89cda3a3197e419e3c3273aa7a0ce3e29e2a66bbe56479226dc0ca9", + "note": "PERMANENT, user-facing: deploy and look up wallets here. Also the EIP-712 verifyingContract for every OwnerIntent." + }, + "factoryLogic": { + "address": "0xe549d3D4e85cB16F687448D7acA21D9d13A7cD0f", + "contract": "AGWFactory", + "sizeBytes": 10013, + "verified": true, + "explorer": "https://donut.push.network/address/0xe549d3D4e85cB16F687448D7acA21D9d13A7cD0f", + "deployTx": "0x3def7e525fb9a205597351bf2c2c386cd8e668ef8d1138afb2bcc2c6cb0cd502" + }, + "walletImplementation": { + "address": "0x4D459Da499C14548aa16c46c57fD92880A88EBb4", + "contract": "AGW", + "sizeBytes": 17584, + "verified": true, + "explorer": "https://donut.push.network/address/0x4D459Da499C14548aa16c46c57fD92880A88EBb4", + "deployTx": "0x8dfa2be6d1fd7266bc4685487693360d2bee67ab1272ab97bc3ba86cabecd389", + "note": "Clone target; accountId push.agw.1.0.0. Adds the wallet label: label(), setLabel(string), LabelSet, initializeAccount(string)." + }, + "urp": { + "address": "0x603E7f0aF6e1aAFf46DDfb28b1e99364f8BC59af", + "contract": "TransparentUpgradeableProxy", + "sizeBytes": 830, + "verified": true, + "explorer": "https://donut.push.network/address/0x603E7f0aF6e1aAFf46DDfb28b1e99364f8BC59af", + "deployTx": "0xa52689e41f70b2d72d938f3c62f4dd6db0bf3595e9f89f44889ae17ff7692655", + "note": "PERMANENT: every wallet pins it; every rule names it as its only action policy.", + "reusedFrom": "v4" + }, + "urpImplementation": { + "address": "0xA2391eee4C9EA1B32AEB3A460B77296EA709F02F", + "contract": "UniversalRulesPolicy 3.1.0", + "sizeBytes": 24326, + "verified": true, + "explorer": "https://donut.push.network/address/0xA2391eee4C9EA1B32AEB3A460B77296EA709F02F", + "deployTx": "0x6b5705fccec7f68c0ac71294a4cf6b1f4d509b8c1b1645658c502f2bca917a91", + "reusedFrom": "v4" + }, + "urpProxyAdmin": { + "address": "0x0b7a31ec85117892aEA90AA5cB6514e2F97c2295", + "contract": "ProxyAdmin", + "sizeBytes": 926, + "verified": true, + "explorer": "https://donut.push.network/address/0x0b7a31ec85117892aEA90AA5cB6514e2F97c2295", + "note": "KEEP: no URP upgrade is possible without it. Created internally by the TUP; read from the ERC-1967 admin slot.", + "reusedFrom": "v4" + }, + "sessionValidator": { + "address": "0x068EE2388475A98EE1f5a434C58bFF3444fffFe6", + "contract": "AgentValidator", + "sizeBytes": 806, + "verified": true, + "explorer": "https://donut.push.network/address/0x068EE2388475A98EE1f5a434C58bFF3444fffFe6", + "deployTx": "0xb7c736e905952354201767da3287eb4769870029f29db7baeab732ac9db73e35", + "reusedFrom": "v4" + }, + "sessionEngine": { + "address": "0x165A5E6782f39D30B38c7D97e1303e4CB2aD102a", + "contract": "SmartSession (fork 7dc20e4)", + "sizeBytes": 22581, + "verified": true, + "explorer": "https://donut.push.network/address/0x165A5E6782f39D30B38c7D97e1303e4CB2aD102a", + "deployTx": "0xf36a57a8a626e6918cd80ffc0a635a15afac68e643b576fd3891c482e27c9fd7", + "reusedFrom": "v4" + } + }, + "external": { + "universalGateway": "0x00000000000000000000000000000000000000C1", + "universalCore": "0x00000000000000000000000000000000000000C0", + "ueaFactory": "0x00000000000000000000000000000000000000eA", + "universalExecutorModule": "0x14191Ea54B4c176fCf86f51b0FAc7CB1E71Df7d7", + "gatewayImplementationAtDeploy": "0x1e412939780f2b834DC42C7AC58d9f99888Da659", + "gatewayOutboundSelector": "0x77b86bec" + }, + "adminState": { + "factoryDefaultAdmin": "0xa89523351BE1e2De64937AA9AF61Ae06eAd199C7", + "defaultAdminDelaySeconds": 172800, + "urpProxyAdminOwner": "0xa89523351BE1e2De64937AA9AF61Ae06eAd199C7", + "pauserRole": "none", + "operatorRole": "none", + "note": "Testnet: the new factory's default admin and the (reused) URP ProxyAdmin owner are both the deployer EOA. PAUSER_ROLE and OPERATOR_ROLE are unassigned on the new factory; grant them before it can be paused." + }, + "ruleEncoding": { + "initData": "abi.encode(uint16 version, string chainNamespace, bytes body), version 1", + "universalTermsTuple": "(uint48,address,(address,uint256,uint256)[],uint256,(address,bytes4,uint16,bool,uint256)[])", + "tokens": "PRC20 addresses on Push, 1..8 per cross-chain rule; type(uint256).max = unlimited, 0 = nothing", + "pushChainHash": "0x3d6bc1f1d3fb03065860265a8e93840b586e57075d956cd41b4319d040be87f9" + }, + "walletLabel": { + "default": "AGW , the owner's own factory index", + "maxBytes": 64, + "reset": "setLabel(\"\") restores the default", + "checkpoint": "none", + "signedInDeployWalletWithSig": false + }, + "supersedes": { + "generation": "v4", + "factoryProxy": "0xaF88D0FD947afAe7bBb8F34e8417DCfc165e1aaF", + "factoryLogic": "0xe138Dc6EfC10233BE1e6c8aF1Caf8cABe599cfC2", + "walletImplementation": "0x96D69ec7e6cDdaD414e656B5c9DCA24587DF713c", + "note": "v4 wallets keep working against the same URP and engine but have no label functions. Earlier address books are in git history." + } +} diff --git a/plan/agw/research/deployment-review-2026-10-07-v5/source/docs/5_SDK_Owner_Integration.md b/plan/agw/research/deployment-review-2026-10-07-v5/source/docs/5_SDK_Owner_Integration.md new file mode 100644 index 00000000..2b24c609 --- /dev/null +++ b/plan/agw/research/deployment-review-2026-10-07-v5/source/docs/5_SDK_Owner_Integration.md @@ -0,0 +1,523 @@ +# AGW for the SDK — owner side + +What the SDK needs to create agentic wallets, grant and revoke rules, act as the owner, and read state, against the +**v5 deployment on Donut**. Owner side only: the agent side (`executeAsAgent`, building outbound requests) is out of +scope here. + +Everything below is taken from the deployed contracts (commit `2e61e13`). ABIs: use the verified contracts on +[donut.push.network](https://donut.push.network), or the build artifacts in this repo (`out/.sol/.json`). +Full address book: [`docs/addresses/donut.md`](addresses/donut.md). + +**What changed from v4:** +- **New factory:** `0x8137F96A50EBF41d904e3678c84c391a0D1BCcc5`. It is also the EIP-712 `verifyingContract`, so every + `OwnerIntent` must be signed for the new address (§7). +- **New wallet implementation**, with a stored label (§3, [Label](#label)). +- URP, SmartSession and AgentValidator keep their addresses, and rule encoding is unchanged. +- Wallets from the v4 factory (`0xaF88…1aaF`) still work but have no label functions. Deploy new wallets only through + the v5 factory. + +--- + +## 1. The contracts the SDK talks to + +| Contract | Address (Donut, chain id `42101`) | What the SDK does with it | +|---|---|---| +| **AGWFactory** (proxy) | `0x8137F96A50EBF41d904e3678c84c391a0D1BCcc5` | Predict, deploy and look up wallets | +| **AGW** (one per user) | address from `predictWallet` | Grant / revoke rules, owner actions, reads | +| **URP** (proxy) | `0x603E7f0aF6e1aAFf46DDfb28b1e99364f8BC59af` | Named inside every rule; read rule terms and spend | +| **SmartSession** (engine) | `0x165A5E6782f39D30B38c7D97e1303e4CB2aD102a` | Read only: list a wallet's rules | +| **AgentValidator** | `0x068EE2388475A98EE1f5a434C58bFF3444fffFe6` | Named inside every rule; never called | +| UniversalGatewayPC (Push core) | `0x00000000000000000000000000000000000000C1` | Named as the target of every cross-chain rule | +| UniversalCore (Push core) | `0x00000000000000000000000000000000000000C0` | Look up a chain's gas token (`gasTokenPRC20ByChainNamespace`) | + +`AGW.SESSION_ENGINE()`, `AGW.RULES_POLICY()`, `AGW.SESSION_VALIDATOR()` and `AGW.UNIVERSAL_GATEWAY_PC()` return the +engine, URP, validator and gateway a wallet expects. Prefer reading them from the wallet over hard-coding. + +## 2. Five terms + +- **Owner**: the Push address that owns a wallet (an EOA, or the UEA of an external key). Fixed at deploy. +- **Wallet (AGW)**: a small contract account. It holds the funds the agent may use; its balance is the hard ceiling. +- **Rule**: what one agent may do from one wallet. Granted by the owner, stored in the engine and URP, immutable once + granted. Identified by a `rulesId` (`bytes32`). +- **Agent**: the Push address a rule names (an EOA, or the UEA of an external key). Never the owner. +- **Checkpoint**: a counter on the wallet that moves on every owner-side action (owner calls, grants, revokes), never + on agent actions. Evaluators compare it before and after a job. + +--- + +## 3. Wallets: predict, fund, deploy + +### Predict + +```solidity +function walletCount(address owner) external view returns (uint256); // also the next index +function predictWallet(address owner, uint256 index) external view returns (address wallet, bool deployed); +``` + +The address depends only on `(owner, index)` and never changes, so it can be shown and **funded before deployment** +(PC and PRC20s sent to it are there when it deploys). The next wallet is `predictWallet(owner, walletCount(owner))`. +`index` may be at most `walletCount(owner)`: predicting further ahead reverts `IndexOutOfRange(index, next)`. + +### Deploy + +```solidity +function deployWallet(string calldata label) external returns (address wallet); // caller = owner +function deployWalletWithSig(OwnerIntent calldata intent, bytes calldata sig, string calldata label) + external returns (address wallet); // relayed, see §7 +``` + +- `deployWallet` makes **the caller** the owner; there is no owner parameter. +- `label` is optional (`""` for the default) and is **stored on the wallet** (see [Label](#label)). It is also + emitted in `WalletDeployed`. Over 64 bytes, the deploy reverts `LabelTooLong(length)`. +- Deploys revert while the factory is paused (`EnforcedPause`). + +### Look up + +```solidity +function isWallet(address account) external view returns (bool); +function ownerOf(address wallet) external view returns (address); // address(0) if not a factory wallet +function indexOf(address wallet) external view returns (uint256); // reverts NotAWallet for a non-wallet +``` + +To list an owner's wallets: indices `0 .. walletCount(owner)-1` through `predictWallet`, or the `WalletDeployed` +events filtered by `owner`. + +### Label + +> Wallets from the retired v4 factory (`0xaF88…1aaF`) have no `label()` / `setLabel`; calling them reverts. + +```solidity +function label() external view returns (string memory); // on the wallet +function setLabel(string calldata label) external; // on the wallet; owner (or the wallet itself) +event LabelSet(string label); +``` + +- **Every wallet has a label.** With none set, `label()` returns `"AGW "`, using the owner's own index: + an owner's wallets read `AGW 1`, `AGW 2`, … and another owner's first wallet is also `AGW 1`. +- `setLabel` renames; `setLabel("")` resets to the default. At most **64 bytes** (bytes, not characters: 16 + four-byte emoji fit), else `LabelTooLong(length)`. Anyone but the owner gets `CallerIsNotOwner`. +- **Not a checkpoint.** A direct `setLabel` moves no counter. Sent through `execute` / `executeWithSig` (how a UEA + owner renames: an execute whose single call targets the wallet's own `setLabel`), only the owner-door call ticks. +- `LabelSet` carries the label as passed (`""` on a reset). The deploy-time label is in `WalletDeployed`. +- **The label is not signed in `deployWalletWithSig`**: the relayer passes it, so it can differ from what the owner + chose. It is cosmetic; the owner can fix it with `setLabel`. +- `list()` / `info()` need one `eth_call` per wallet: `label()`. No event scan. + +--- + +## 4. Granting a rule + +```solidity +function grantRules(Session calldata session) external returns (bytes32 rulesId); // owner, or the wallet itself +``` + +One call grants one rule. A rule is a **`Session`** (the engine's struct) whose one policy is URP, carrying the terms +in an **envelope**. + +### 4.1 The Session, field by field + +```solidity +struct Session { + address sessionValidator; // AgentValidator 0x068E…FfFe6 (must equal wallet.SESSION_VALIDATOR()) + bytes sessionValidatorInitData; // abi.encode(address agent), agent != address(0) + bytes32 salt; // anything; the wallet overwrites it with its grant nonce + PolicyData[] userOpPolicies; // MUST be empty + ERC7739Data erc7739Policies; // MUST be empty: { allowedERC7739Content: [], erc1271Policies: [] } + ActionData[] actions; // see below + bool permitERC4337Paymaster; // MUST be false +} +struct PolicyData { address policy; bytes initData; } +struct ActionData { bytes4 actionTargetSelector; address actionTarget; PolicyData[] actionPolicies; } +struct ERC7739Data { ERC7739Context[] allowedERC7739Content; PolicyData[] erc1271Policies; } +struct ERC7739Context { bytes32 appDomainSeparator; string[] contentNames; } +``` + +Every action has **exactly one** policy: `{ policy: URP, initData: }`. Anything else reverts +`MalformedSessionShape`. + +Actions by rule kind: + +| Kind | `actions` | +|---|---| +| **Cross-chain** (EVM or Solana destination) | Exactly 1 action: `actionTarget = UniversalGatewayPC`, `actionTargetSelector = 0x77b86bec` (the gateway's `sendUniversalTxOutbound`) | +| **Native** (Push-side calls) | 1 to 8 actions, one per `(target, selector)` the agent may call; no duplicates; every action's envelope names the same chain | + +The **kind is never declared**: it is derived from the envelope's chain string. This chain (`"eip155:42101"`) means +native; any other `eip155:` or `solana:` chain means cross-chain. + +### 4.2 The envelope (`initData` of the URP policy) + +```solidity +initData = abi.encode(uint16 version, string chainNamespace, bytes body) +``` + +- `version` = **1** (`ENVELOPE_VERSION`). Anything else is refused (`UnsupportedEnvelopeVersion`). +- `chainNamespace`: CAIP-2 string, byte-exact. Destination chain for cross-chain rules (e.g. `"eip155:11155111"`, + `"solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1"`); `"eip155:42101"` for native rules on Donut. + (`URP.pushChainHash()` returns `keccak256("eip155:42101")` if you want to confirm.) +- `body`: `abi.encode(UniversalTerms)`, `abi.encode(SvmTerms)` or `abi.encode(NativeTerms)`, by kind. + +### 4.3 Cross-chain rule, EVM destination: `UniversalTerms` + +```solidity +struct UniversalTerms { + uint48 validUntil; // unix seconds, in the future; "never" = type(uint48).max + address expectedCEA; // the wallet's account on the destination chain + AssetCap[] assets; // 1..8 tokens the agent may move + uint256 maxGasPerCall; // PC (wei) the wallet may spend per outbound (protocol fee + gas) + AllowedCall[] allowedCalls; // 1..32 destination-chain calls the agent may make +} +struct AssetCap { + address token; // PRC20 ON PUSH (e.g. USDC.eth), never the destination chain's address + uint256 maxPerCall; // per request; 0 = this token can never move + uint256 maxTotal; // lifetime amount sent out; type(uint256).max = unlimited; 0 = nothing +} +struct AllowedCall { + address target; // destination-chain contract + bytes4 selector; // destination-chain function + uint16 beneficiaryOffset; // byte offset of the beneficiary argument: 4 + 32 * argIndex + bool hasBeneficiary; // if true, that argument must equal expectedCEA + uint256 maxValue; // native value per call, in DESTINATION-chain units; 0 = non-payable +} +``` + +ABI tuple: `(uint48,address,(address,uint256,uint256)[],uint256,(address,bytes4,uint16,bool,uint256)[])` + +Rules the contracts enforce at grant (each with a named error, §10): + +- **At least one token, at most 8, no duplicates.** A rule with no token is refused (`AssetListOutOfRange(0)`): the + gateway picks the destination chain from the request's token, so a rule without a token has no chain. +- **Every token's chain must equal the rule's chain**: URP calls `token.SOURCE_CHAIN_NAMESPACE()` and compares + (`ChainMismatch`, `InvalidAsset`). It checks the chain, **not which token**, so picking the right PRC20 is the SDK's job. +- `expectedCEA` non-zero; `allowedCalls` 1..32; `validUntil` non-zero and in the future. + +What the SDK has to resolve: + +- **Token → PRC20**: users give the destination chain's token (e.g. `MOVEABLE.TOKEN.ETHEREUM_SEPOLIA.USDC`); convert + with `PushChain.utils.tokens.getPRC20Address(...)` and confirm `SOURCE_CHAIN_NAMESPACE()` equals the rule's chain. +- **A rule that moves no tokens**: the contracts refuse an empty list, so the SDK adds the destination chain's gas + token with both limits at 0: `UniversalCore.gasTokenPRC20ByChainNamespace(chain)` (Sepolia: pETH + `0x2971824Db68229D087931155C2b8bB820B275809`). Add it only when the user lists no token, or it would duplicate. +- **"No total limit"**: encode `maxTotal = type(uint256).max`. Do not encode 0; 0 means nothing may move. +- **`expectedCEA`**: the wallet's CEA on the destination chain, from that chain's CEA factory: + `getCEAForPushAccount(walletAddress) returns (address cea, bool isDeployed)`. +- **`beneficiaryOffset`**: from the function ABI, `4 + 32 * argIndex` (e.g. Aave `supply(address,uint256,address,uint16)`, + `onBehalfOf` is argument 2, offset 68). + +One rule may list several tokens and several protocols. Limits are **per token**; there is no combined limit across +tokens, and every listed token may be used with every allowed call. Different scopes need separate rules. + +### 4.4 Cross-chain rule, Solana destination: `SvmTerms` + +```solidity +struct SvmTerms { + uint48 validUntil; + bytes32 expectedCEA; // PDA(["push_identity", wallet], gatewayProgram) + bytes32 gatewayProgram; // the Push gateway program on that cluster (from the chain registry) + AssetCap[] assets; // 1..8, same as §4.3; request amounts must fit u64 + uint256 maxGasPerCall; + bytes32[] ceaAccounts; // the CEA's value-holding accounts, max 16, MUST include expectedCEA + AllowedProgram[] programs; // 1..32 allowed (program, instruction) pairs + SvmAccountPin[] pins; // max 16 account pins + SvmDataPin[] dataPins; // max 8 instruction-data pins +} +struct AllowedProgram { bytes32 program; bytes8 discriminator; uint8 discriminatorLen; bool dataless; uint8 maxAccounts; } +struct SvmAccountPin { uint8 ruleIndex; uint8 accountIndex; bytes32 expected; } +struct SvmDataPin { uint8 ruleIndex; bool fromEnd; uint16 offset; uint16 offsetB; uint8 len; + uint8 mode /* 0 EQ, 1 GTE_LE, 2 LTE_LE, 3 RATIO_GTE_LE */; bytes32 expected; uint64 num; uint64 den; } +``` + +What the SDK must get right (all checked at grant, named errors): + +- `ceaAccounts`: the CEA plus **the CEA's token account for every listed token** and any swap-output accounts. URP + cannot derive Solana token accounts, so it cannot check this; an unlisted account is unprotected. +- **One rule per (program, instruction).** Each position takes one pinned key, so if a swap rule pins its input to the + USDC account, USDT cannot be that instruction's input. Plan Solana rules so different tokens use different instructions. +- Every program rule needs at least one account pin; `discriminatorLen` is 1..8, or 0 exactly when `dataless`. +- System, SPL Token, Token-2022, Stake, the upgradeable loader, the lookup-table program, the gateway program and the + CEA itself can never be allowed programs. + +Field-level detail: `docs/2_UniversalRulesPolicy.md` §1.2c. + +### 4.5 Native rule (Push-side calls): `NativeTerms`, one per action + +```solidity +struct NativeTerms { + uint48 validUntil; + address target; // MUST equal this action's actionTarget + bytes4 selector; // MUST equal this action's actionTargetSelector; 0xFFFFFFFF = plain PC transfer + uint256 maxValuePerCall; // PC (wei) per call + uint256 maxValueTotal; // lifetime PC; type(uint256).max = unlimited + AmountRule amount; // optional metering of one uint256 argument + uint32 maxCalls; // 0 = unlimited + ArgPin[] pins; // 0..8 arguments that must equal a fixed word +} +struct AmountRule { bool enabled; uint16 offset; uint256 maxPerCall; uint256 maxTotal; } +struct ArgPin { uint16 offset; bytes32 expected; } // offset counts from byte 0, selector included: 4 = first argument +``` + +ABI tuple: `(uint48,address,bytes4,uint256,uint256,(bool,uint16,uint256,uint256),uint32,(uint16,bytes32)[])` + +- `target`/`selector` must match the action they sit in. The contracts do not cross-check at grant, and a mismatch + makes the rule unusable. +- Targets that can never be granted: the gateway (use a cross-chain rule), the wallet, the factory, the engine, URP, + the validator, `address(0)`, `address(1)`. +- A plain PC transfer (`0xFFFFFFFF`) carries no pins and no amount rule. + +### 4.6 The `rulesId` + +`grantRules` returns it, and `RulesGranted(rulesId, …)` carries it. It is also predictable before sending: + +``` +rulesId = keccak256(abi.encode(address sessionValidator, bytes sessionValidatorInitData, bytes32(grantNonce))) + // grantNonce = wallet.grantNonce() at the moment of the grant; it advances by 1 on every grant +``` + +Equivalently, call `SmartSession.getPermissionId(session)` with `salt = bytes32(grantNonce)`. Ids never repeat, even +for byte-identical rules granted twice. + +### 4.7 Encoding a cross-chain rule (viem) + +```ts +import { encodeAbiParameters, parseAbiParameters, parseEther, maxUint256, zeroHash } from 'viem'; + +const terms = encodeAbiParameters( + parseAbiParameters('(uint48,address,(address,uint256,uint256)[],uint256,(address,bytes4,uint16,bool,uint256)[])'), + [[validUntil, expectedCEA, + [[USDC_ETH, 100_000000n, 1000_000000n], [USDT_ETH, 50_000000n, maxUint256]], + parseEther('1'), + [[aavePool, '0x617ba037', 68, true, 0n], [usdcSepolia, '0x095ea7b3', 0, false, 0n]]]], +); +const initData = encodeAbiParameters(parseAbiParameters('uint16, string, bytes'), [1, 'eip155:11155111', terms]); + +const session = { + sessionValidator: wallet.SESSION_VALIDATOR, // 0x068E…FfFe6 + sessionValidatorInitData: encodeAbiParameters([{ type: 'address' }], [agent]), + salt: zeroHash, + userOpPolicies: [], + erc7739Policies: { allowedERC7739Content: [], erc1271Policies: [] }, + actions: [{ + actionTargetSelector: '0x77b86bec', // gateway sendUniversalTxOutbound + actionTarget: '0x00000000000000000000000000000000000000C1', // UniversalGatewayPC + actionPolicies: [{ policy: URP, initData }], + }], + permitERC4337Paymaster: false, +}; +// wallet.grantRules(session), from the owner +``` + +--- + +## 5. Revoking and replacing rules + +```solidity +function revokeRules(bytes32 rulesId) external; // owner, or the wallet itself; UnknownPermission if not live +function revokeAllRules() external; // owner, or the wallet itself +``` + +Revocation is immediate on Push and cannot be blocked. An outbound already sent across the bridge still completes. + +**Rules are immutable.** To "update" one, the owner sends **one batch through the owner door** (§6): + +1. `URP.assertSpent(configId, wallet, expectedSpent)` — reverts if the agent spent since the SDK read the counters; +2. `wallet.revokeRules(oldRulesId)`; +3. `wallet.grantRules(newSession)`. + +If step 1 reverts, nothing changes. Counters start at zero on the new rule. `assertSpent` forms: + +```solidity +// cross-chain (EVM or Solana): one expected value per listed token, IN THE ORDER THE RULE LISTED THEM +function assertSpent(ConfigId id, address account, uint256[] calldata expectedSpent) external view; +// native: per action +function assertSpent(ConfigId id, address account, uint256 expectedValueSpent, uint256 expectedAmountSpent, uint32 expectedCalls) + external view; +``` + +--- + +## 6. The owner door: `execute` + +```solidity +function execute(bytes32 mode, bytes calldata executionCalldata) external payable; // owner only +``` + +The owner acts as the wallet with **no rule checked**: withdraw, approve, call anything, or call the wallet's own +`grantRules` / `revokeRules` in a batch. + +| | `mode` | `executionCalldata` | +|---|---|---| +| Single call | `0x0000…00` (32 zero bytes) | `abi.encodePacked(address target, uint256 value, bytes callData)` | +| Batch | `0x01` followed by 31 zero bytes | `abi.encode(Execution[])`, `Execution = (address target, uint256 value, bytes callData)` | + +Other modes (delegatecall, try) revert `UnsupportedExecutionMode`. Every call in an owner action records one +checkpoint. Withdraw PC: single call to the destination address with `value = amount, callData = 0x`. Withdraw a +token: single call to the token with `transfer(to, amount)`. + +--- + +## 7. Relayed owner actions: `OwnerIntent` + +For owners who sign but do not send (a Push EOA without gas, or a relayer-driven flow). The owner signs one EIP-712 +`OwnerIntent`; the named `executor` submits it. + +```solidity +struct OwnerIntent { + address owner; // the wallet owner + address wallet; // the wallet (its predicted address if not deployed yet) + address executor; // the ONLY address allowed to submit this intent + uint96 index; // deploy: must equal factory.walletCount(owner) + bytes32 sessionHash; // grant: keccak256(abi.encode(session)) of the session AS SUBMITTED; 0 = no grant + bytes32 mode; // execute: the mode word + bytes32 execCalldataHash; // execute: keccak256(executionCalldata); 0 = no execute + uint192 nonceKey; // execute: lane key; the top bit (1 << 191) MUST be set + uint64 nonceSeq; // execute: must equal wallet.getNonce(nonceKey) + uint64 grantNonce; // grant: must equal wallet.grantNonce() + uint48 deadline; // unix seconds; every door rejects after it + uint256 signerChainId; // the chain id the owner's wallet signs under (their home chain) +} +``` + +EIP-712 type string (fields in this order): + +``` +OwnerIntent(address owner,address wallet,address executor,uint96 index,bytes32 sessionHash,bytes32 mode,bytes32 execCalldataHash,uint192 nonceKey,uint64 nonceSeq,uint64 grantNonce,uint48 deadline,uint256 signerChainId) +``` + +Domain: `name "AGWFactory"`, `version "1"`, `chainId = signerChainId`, `verifyingContract = factory proxy` +(`0x8137F96A50EBF41d904e3678c84c391a0D1BCcc5`, also for wallet doors), `salt = bytes32(uint256(42101))`. Check the local derivation against +`factory.domainSeparator(signerChainId)` (or `wallet.domainSeparator(...)`, identical) before prompting. + +| Door | Contract | Fields it checks | +|---|---|---| +| `deployWalletWithSig(intent, sig, label)` | factory | `owner`, `index`, `wallet` (= predicted), `executor`, `deadline` | +| `grantRulesWithSig(session, intent, sig)` | wallet | `wallet`, `owner`, `executor`, `deadline`, `sessionHash`, `grantNonce` | +| `executeWithSig(mode, executionCalldata, intent, sig)` | wallet | `wallet`, `owner`, `executor`, `deadline`, `mode`, `execCalldataHash`, `nonceKey`, `nonceSeq` | + +- **One signature can cover all three doors**: each door checks only its own fields, and each is single-use (deploy: + the index advances; grant: the grant nonce advances; execute: the lane sequence advances). +- **Several rules in one signature**: put a batch of the wallet's own `grantRules` calls in `executeWithSig` + (`grantRulesWithSig` grants exactly one). +- `executeWithSig` is **not payable**; value comes from the wallet's balance. +- Signature check: an owner with no code is verified by ECDSA; a contract owner by its UEA method + (`verifyUniversalPayloadSignature`), then ERC-1271. A **Solana-key owner's UEA must already exist on Push** before + its first signed intent. +- If the owner calls `deployWalletWithSig` directly, no signature is needed. + +--- + +## 8. "Create a wallet with rules" in practice + +| Owner | How | +|---|---| +| **UEA** (external key) | One UEA multicall, one signature: `factory.deployWallet(label)` then `predictedWallet.grantRules(session)` per rule. | +| **Push EOA**, sends its own txs | Two transactions: `factory.deployWallet(label)`, then `wallet.execute(batch of wallet.grantRules(...))`. | +| **Push EOA via a relayer** | One signature: an `OwnerIntent` with the deploy fields plus an execute batch of self-grants. The relayer sends `deployWalletWithSig`, then `executeWithSig`. | + +Fund the wallet with PC (for the agent's per-call fees) and the tokens the rules allow, at its address, before or after +deployment. + +--- + +## 9. Reading state + +| To get | Call | +|---|---| +| A wallet's live rules | `SmartSession.getPermissionIDs(wallet)` → `bytes32[]` | +| Is a rule live | `SmartSession.isPermissionEnabled(rulesId, wallet)` | +| The rule's agent | `wallet.agentOf(rulesId)` (zero if revoked or unknown) | +| Kind, VM family, chain | `URP.getMode(configId, wallet)` → `{initialized, mode (0 cross-chain, 1 native), vm (0 EVM, 1 Solana), chainHash}` | +| Cross-chain EVM terms + spend | `URP.getConfig(configId, wallet)` → `{initialized, validUntil, expectedCEA, maxGasPerCall, assets[], allowedCalls[]}`, each asset `{token, maxPerCall, maxTotal, spent}` | +| Solana terms + spend | `URP.getSvmConfig(configId, wallet)` (same `assets[]` with `spent`) | +| Native terms + spend | `URP.getNativeConfig(configId, wallet)` → `{…, valueSpent, amountSpent, callsUsed, …}` | +| Checkpoints | `wallet.checkpointCount()`, `wallet.lastCheckpointBlock()`, `Checkpointed` events | +| Owner / factory | `wallet.owner()`, `wallet.factory()` | +| Label | `wallet.label()` (the default `AGW ` when none is set) | +| Next grant nonce | `wallet.grantNonce()` | +| Owner lane position | `wallet.getNonce(nonceKey)` | + +**`configId`** (the key URP reads take), per action: + +``` +actionId = keccak256(abi.encodePacked(address target, bytes4 selector)) +actionPolicyId = keccak256(abi.encodePacked(bytes32 rulesId, actionId)) +configId = keccak256(abi.encodePacked(address wallet, actionPolicyId)) +``` + +- Cross-chain rule: one action, `target = UniversalGatewayPC`, `selector = 0x77b86bec`, so the `configId` follows from + `rulesId` alone. +- Native rule: one `configId` per action; use each action's `(target, selector)` from the session the SDK built (or + decode the grant transaction's input). +- `getConfig` reverts `WrongModeForCall` / `WrongVmForCall` if called on the wrong kind; call `getMode` first when + unsure. An empty slot returns a zeroed struct. +- `spent` counts what was **sent out**. Money coming back to the wallet does not lower it. + +The contracts do not enforce one rule per agent per chain. A wallet can hold several rules for the same agent and +chain, so a lookup by `(agent, chain)` can return more than one. + +--- + +## 10. Events + +| Contract | Event | Notes | +|---|---|---| +| Factory | `WalletDeployed(address indexed owner, uint256 indexed index, address indexed wallet, string label)` | The label as passed at deploy (`""` = default) | +| Wallet | `AccountInitialized(address indexed owner, address indexed engine)` | Emitted once at deploy | +| Wallet | `LabelSet(string label)` | `setLabel`; `""` = reset to the default | +| Wallet | `RulesGranted(bytes32 indexed rulesId, uint8 mode, bytes32 indexed chainHash, string chainNamespace)` | `mode`: 0 cross-chain, 1 native | +| Wallet | `RulesRevoked(bytes32 indexed rulesId)` | Once per revoked id | +| Wallet | `OwnerExecuted(bytes32 indexed mode, bytes32 executionCalldataHash)` | `execute` | +| Wallet | `OwnerExecutedWithSig(bytes32 indexed mode, bytes32 executionCalldataHash, uint192 nonceKey, uint64 nonceSeq)` | `executeWithSig` | +| Wallet | `Checkpointed(uint64 indexed seq, uint8 kind, bytes32 ref, uint64 blockNumber)` | `kind`: 0 owner action (`ref` = `keccak256(abi.encode(target, value, callData))`), 1 rules granted, 2 rules revoked (`ref` = `rulesId`) | +| Wallet | `RulesActionAuthorized(bytes32 indexed rulesId, address indexed agent, bytes32 callsHash)` | An agent action passed (agent side) | +| URP | `OutboundMetered(bytes32 indexed id, address indexed multiplexer, address indexed account, address token, uint256 amount)` | A cross-chain spend was counted | +| URP | `NativeCallMetered(bytes32 indexed id, address indexed multiplexer, address indexed account, uint256 value, uint256 amount)` | A native call was counted | + +--- + +## 11. Errors the owner side can hit + +All are custom errors with arguments; decode with the contract ABIs. URP errors raised during a grant reach the caller +in full (they come through the wallet). + +| When | Errors | +|---|---| +| **Deploy** | `IndexMismatch(expected, provided)`, `IntentWalletMismatch`, `ExecutorMismatch`, `SignatureExpired`, `InvalidOwnerSignature`, `EnforcedPause`, `LabelTooLong(length)` | +| **Label** | `LabelTooLong(length)`, `CallerIsNotOwner` | +| **Grant: session shape** (wallet) | `MalformedSessionShape`, `TooManyActions(n)`, `DuplicateAction(target, selector)`, `ForbiddenActionTarget(target)`, `ForbiddenActionSelector(selector)`, `RulesTypeMismatch(mode, actionIndex, target)`, `EmptyChain`, `InconsistentChain(actionIndex)`, `CallerIsNotOwner` | +| **Grant: envelope** (URP) | `UnsupportedEnvelopeVersion(firstWord)`, `EmptyChain`, `UnsupportedNamespace(chainHash)` (chain is neither `eip155:` nor `solana:`; declared in `PushChainLib`) | +| **Grant: cross-chain terms** (URP) | `AssetListOutOfRange(length)`, `DuplicateAsset(token)`, `InvalidAsset(token)`, `ChainMismatch(declared, assetChain)`, `InvalidConfigField`, `AllowListOutOfRange(length)`, `InvalidExpiry(validUntil)` | +| **Grant: Solana terms** (URP) | `InvalidSvmConfigField`, `ProgramListOutOfRange`, `TooManySvmPins`, `TooManySvmDataPins`, `TooManyCeaAccounts`, `DiscriminatorLenOutOfRange`, `AmbiguousRule`, `ForbiddenProgramInAllowList`, `SvmPinRuleOutOfRange`, `SvmPinIndexOutOfRange`, `SvmMaxAccountsOutOfRange`, `DuplicateSvmPin`, `InvalidCeaAccount`, `CeaAccountsMissExpectedCEA`, `SvmDataPinInvalid`, `RuleWithoutPin` | +| **Grant: native terms** (URP) | `NativeTargetZero`, `NativeTargetIsGateway`, `TooManyPins`, `ValueOnlyWithPins`, `ValueOnlyWithAmountRule`, `InvalidExpiry` | +| **Revoke** | `UnknownPermission(rulesId)`, `CallerIsNotOwner` | +| **Update batch** | `AssetSpentMismatch(token, expected, actual)`, `SpentLengthMismatch(expected, actual)`, `SpentMismatch(expected, actual)` (native), `NotInitialized`, `WrongModeForCall` | +| **Owner door / signed doors** | `CallerIsNotOwner`, `UnsupportedExecutionMode`, `MalformedBatchCalldata`, `OwnerSigExpired`, `IntentWalletMismatch`, `ExecutorMismatch`, `InvalidOwnerSignature`, `IntentSessionMismatch`, `IntentGrantNonceMismatch`, `IntentExecMismatch`, `OwnerLaneRequired`, `InvalidNonce` | +| **Reads** | `WrongModeForCall(actual)`, `WrongVmForCall(actual)`, `NotAWallet(account)`, `IndexOutOfRange(index, next)` | + +A call made inside an owner action that reverts bubbles its own revert data up unchanged. + +--- + +## 12. Limits + +| Limit | Value | +|---|---| +| Tokens per cross-chain rule | 1 to 8 | +| Allowed calls per EVM rule | 1 to 32 | +| Actions per native rule | 1 to 8 | +| Argument pins per native action | 0 to 8 | +| Solana: programs / account pins / data pins / value-holding accounts | 1–32 / ≤16 / ≤8 / ≤16 | +| `validUntil` | non-zero, in the future; `type(uint48).max` = never | +| Unlimited total | `type(uint256).max` (0 means nothing) | +| Envelope version | 1 | +| Wallet label | 0 to 64 bytes (`""` = the default `AGW `) | + +## 13. Checklist before sending a grant + +- [ ] `sessionValidator` is the wallet's `SESSION_VALIDATOR()`; `sessionValidatorInitData = abi.encode(agent)`; agent ≠ owner. +- [ ] Every action has exactly one policy, URP, with a version-1 envelope. +- [ ] Cross-chain: one action, gateway + `0x77b86bec`; 1–8 PRC20 tokens, each on the rule's chain; a gas-token entry + at 0/0 if the user listed none; `maxTotal` is `type(uint256).max` when the user set no total. +- [ ] `expectedCEA` is the wallet's CEA on that chain; beneficiary offsets are `4 + 32 * argIndex`. +- [ ] Native: each `NativeTerms.target/selector` equals its action's. +- [ ] Solana: `ceaAccounts` includes the CEA and the CEA's account for every listed token. +- [ ] Record the `rulesId` from the receipt (or predict it from `grantNonce`) and keep the token order for `assertSpent`. diff --git a/plan/agw/research/deployment-review-2026-10-07-v5/source/docs/addresses/donut.md b/plan/agw/research/deployment-review-2026-10-07-v5/source/docs/addresses/donut.md new file mode 100644 index 00000000..7a77961e --- /dev/null +++ b/plan/agw/research/deployment-review-2026-10-07-v5/source/docs/addresses/donut.md @@ -0,0 +1,109 @@ +# Push Agentic Wallet — deployed addresses (Donut) + +**Generation `v5` (wallet label)** · Chain ID `42101` · explorer [donut.push.network](https://donut.push.network) · +new factory and wallet implementation deployed in blocks `23989983`–`23989987` · commit `2e61e13` (branch +`wallet-label`) · `script/DeployWalletAndFactory.s.sol` · `forge 1.5.1-stable` + +v5 deployed **three** contracts: the AGW wallet implementation, the AGWFactory logic and a new factory proxy. The +engine, URP (proxy, implementation, ProxyAdmin) and AgentValidator are **the v4 contracts, unchanged**: none of them +stores a factory or wallet-implementation address, and their state is keyed per wallet. + +## The two addresses you need + +| | Address | +| ------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------- | +| **Factory**: deploy and look up wallets | [`0x8137F96A50EBF41d904e3678c84c391a0D1BCcc5`](https://donut.push.network/address/0x8137F96A50EBF41d904e3678c84c391a0D1BCcc5) | +| **URP**: name this as every rule's action policy | [`0x603E7f0aF6e1aAFf46DDfb28b1e99364f8BC59af`](https://donut.push.network/address/0x603E7f0aF6e1aAFf46DDfb28b1e99364f8BC59af) | + +Both are **proxies**. Point integrations at these, never at an implementation. + +## Everything + +| Contract | Address | Size (B) | Verified | +| -------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | -------: | :------: | +| `factoryProxy` (ERC-1967, UUPS) — **new in v5** | [`0x8137F96A50EBF41d904e3678c84c391a0D1BCcc5`](https://donut.push.network/address/0x8137F96A50EBF41d904e3678c84c391a0D1BCcc5) | 141 | ✅ | +| `factoryLogic` (`AGWFactory`) — **new in v5** | [`0xe549d3D4e85cB16F687448D7acA21D9d13A7cD0f`](https://donut.push.network/address/0xe549d3D4e85cB16F687448D7acA21D9d13A7cD0f) | 10,013 | ✅ | +| `walletImplementation` (`AGW`) — **new in v5** | [`0x4D459Da499C14548aa16c46c57fD92880A88EBb4`](https://donut.push.network/address/0x4D459Da499C14548aa16c46c57fD92880A88EBb4) | 17,584 | ✅ | +| `urp` (Transparent proxy) | [`0x603E7f0aF6e1aAFf46DDfb28b1e99364f8BC59af`](https://donut.push.network/address/0x603E7f0aF6e1aAFf46DDfb28b1e99364f8BC59af) | 830 | ✅ | +| `urpImplementation` (`UniversalRulesPolicy` 3.1.0) | [`0xA2391eee4C9EA1B32AEB3A460B77296EA709F02F`](https://donut.push.network/address/0xA2391eee4C9EA1B32AEB3A460B77296EA709F02F) | 24,326 | ✅ | +| `urpProxyAdmin` (`ProxyAdmin`) | [`0x0b7a31ec85117892aEA90AA5cB6514e2F97c2295`](https://donut.push.network/address/0x0b7a31ec85117892aEA90AA5cB6514e2F97c2295) | 926 | ✅ | +| `sessionValidator` (`AgentValidator`) | [`0x068EE2388475A98EE1f5a434C58bFF3444fffFe6`](https://donut.push.network/address/0x068EE2388475A98EE1f5a434C58bFF3444fffFe6) | 806 | ✅ | +| `sessionEngine` (`SmartSession`, fork `7dc20e4`) | [`0x165A5E6782f39D30B38c7D97e1303e4CB2aD102a`](https://donut.push.network/address/0x165A5E6782f39D30B38c7D97e1303e4CB2aD102a) | 22,581 | ✅ | + +**All eight verified** on Blockscout. The five rows not marked new are the v4 contracts, reused as they are. Keep +`urpProxyAdmin`: without it URP can never be upgraded. + +Check the wiring yourself: `cast call 'walletImplementation()(address)'` returns the +`walletImplementation` above, and that implementation's `SESSION_ENGINE()`, `RULES_POLICY()` and `SESSION_VALIDATOR()` +return the engine, URP and validator in this table. + +### Push core contracts this deployment points at (not deployed by this repo) + +| | Address | +| --------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | +| `UniversalGatewayPC` | `0x00000000000000000000000000000000000000C1` (implementation `0x1e41…a659`, 8-field outbound request, selector `0x77b86bec`) | +| `UniversalCore` | `0x00000000000000000000000000000000000000C0` | +| `UEAFactory` | `0x00000000000000000000000000000000000000eA` | +| `UNIVERSAL_EXECUTOR_MODULE` | `0x14191Ea54B4c176fCf86f51b0FAc7CB1E71Df7d7` (the address core's UniversalCore and PRC20s use; an account with no code) | + +## What changed from v4 + +| | v4 | v5 | +| ------------------------ | ---------------------------------------- | ----------------------------------------------------------------------------------------------------- | +| Factory proxy | `0xaF88…1aaF` | **`0x8137…Ccc5`** | +| Wallet implementation | `0x96D6…713c` | **`0x4D45…EBb4`** | +| Wallet label | emitted in `WalletDeployed`, not stored | **stored on the wallet**: `label()` (default `AGW `), owner-only `setLabel(string)`, `LabelSet` event, 64 bytes max | +| `OwnerIntent` signatures | domain `verifyingContract` = `0xaF88…1aaF` | domain `verifyingContract` = **`0x8137…Ccc5`**: intents must be signed for the new factory | +| URP, engine, validator | `0x603E…59af`, `0x165A…102a`, `0x068E…fFe6` | **the same** | +| Rule encoding | as below | **unchanged** | + +## How to grant a rule (what changed from v3.2 to v4, still current) + +| | v3.2 | v4 | +| --------------------------- | --------------------------------------------------------- | ----------------------------------------------------------------------------------------- | +| Policy `initData` | `abi.encode(string chainNamespace, bytes body)` | **`abi.encode(uint16 version, string chainNamespace, bytes body)`**, `version = 1` | +| Tokens per cross-chain rule | exactly 1 (`asset`, `maxAmountPerCall`, `maxAmountTotal`) | **1 to 8** (`assets: AssetCap[]`), each with its own limits and spend counter | +| PC fee limit | `maxPCPerCall` | **`maxGasPerCall`** (same meaning: PC per outbound for protocol fee + gas) | +| Agent door | session signature through a validator | **`executeAsAgent(rulesId, mode, executionCalldata)`**, callable only by the rule's agent | +| Owner-side changes | not recorded | **checkpoint counter** (`checkpointCount()`, `Checkpointed` event) | + +Cross-chain body (EVM destination): + +```solidity +struct AssetCap { address token; uint256 maxPerCall; uint256 maxTotal; } // token = PRC20 on Push +struct UniversalTerms { + uint48 validUntil; address expectedCEA; AssetCap[] assets; uint256 maxGasPerCall; AllowedCall[] allowedCalls; +} +// ABI tuple: (uint48,address,(address,uint256,uint256)[],uint256,(address,bytes4,uint16,bool,uint256)[]) +``` + +``` +cast call 0x603E7f0aF6e1aAFf46DDfb28b1e99364f8BC59af 'pushChainHash()(bytes32)' --rpc-url +# -> 0x3d6bc1f1d3fb03065860265a8e93840b586e57075d956cd41b4319d040be87f9 == keccak256("eip155:42101") +``` + +Full design notes: `docs/1_AGW.md`, `docs/2_UniversalRulesPolicy.md`, `docs/multi-asset-review.md`. + +## Admin + +| Authority | Holder | How to change it | +| ----------------------------------------------- | --------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | +| Factory `DEFAULT_ADMIN_ROLE` (factory upgrades) | deployer EOA `0xa89523351BE1e2De64937AA9AF61Ae06eAd199C7` | `beginDefaultAdminTransfer(new)`, then the new admin calls `acceptDefaultAdminTransfer()` after the **48-hour** delay | +| URP `ProxyAdmin` owner (URP upgrades) | deployer EOA `0xa89523351BE1e2De64937AA9AF61Ae06eAd199C7` | `transferOwnership(new)` on `0x0b7a…2295`, immediate | +| Factory `PAUSER_ROLE` / `OPERATOR_ROLE` | **nobody yet** | the default admin must `grantRole` before the factory can be paused or unpaused | + +These are different powers, and for production they belong in different multisigs: the factory admin can strand +counterfactually funded addresses; the URP ProxyAdmin owner can rewrite every gate in the security boundary. + + +## Previous generations (retired) + +- **`v4`** (factory `0xaF88D0FD947afAe7bBb8F34e8417DCfc165e1aaF`, wallet implementation + `0x96D69ec7e6cDdaD414e656B5c9DCA24587DF713c`) is no longer current. Deploy new wallets only through the v5 factory. + v4 wallets keep working, because URP and the engine are shared, but they have no `label()` / `setLabel`. +- **`v3.2`** (factory `0x2578041963f692f8b51A137A1c7ddc0c84a8226A`, URP `0xeAd99E254ACD64219d057400cdC2A2390bC74372`) + stays on chain but is no longer current. Its wallets and rules do not carry over; owners withdraw through the owner + door. + +Only the current deployment's book is kept in the repo (`deployments/address-book-v5/`). Earlier generations' books are +in git history. diff --git a/plan/agw/research/deployment-review-2026-10-07-v5/source/src/AGW.sol b/plan/agw/research/deployment-review-2026-10-07-v5/source/src/AGW.sol new file mode 100644 index 00000000..f10108ef --- /dev/null +++ b/plan/agw/research/deployment-review-2026-10-07-v5/source/src/AGW.sol @@ -0,0 +1,1224 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import { Clones } from "@openzeppelin/contracts/proxy/Clones.sol"; +import { ReentrancyGuardTransient } from "@openzeppelin/contracts/utils/ReentrancyGuardTransient.sol"; +import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; +import { IERC165 } from "forge-std/interfaces/IERC165.sol"; + +import { ISmartSession } from "smartsessions/ISmartSession.sol"; +import { Session, ActionData, PermissionId, ValidationData, SmartSessionMode } from "smartsessions/DataTypes.sol"; +import { PackedUserOperation } from "account-abstraction/interfaces/PackedUserOperation.sol"; +import { IModule as IERC7579Module } from "erc7579/interfaces/IERC7579Module.sol"; + +import { IAgentValidator } from "./interfaces/IAgentValidator.sol"; +import { IAGW } from "./interfaces/IAGW.sol"; +import { IAGWFactory } from "./interfaces/IAGWFactory.sol"; +import { ISmartSessionConfigReader } from "./interfaces/ISmartSessionConfigReader.sol"; +import { AGWErrors } from "./libraries/Errors.sol"; +import { AgentConfigLib } from "./libraries/AgentConfigLib.sol"; +import { PushChainLib } from "./libraries/PushChainLib.sol"; +import { OwnerAuthLib } from "./libraries/OwnerAuthLib.sol"; +import { + OwnerIntent, + OWNER_LANE_FLAG, + SEND_OUTBOUND_SELECTOR, + RulesType, + CheckpointKind, + MAX_LABEL_BYTES, + ENGINE_FALLBACK_TARGET, + ENGINE_FALLBACK_SELECTOR, + ENGINE_FALLBACK_SELECTOR_SMARTSESSION +} from "./libraries/Types.sol"; +import { + ModeCode, + CallType, + ExecType, + ModeLib, + CALLTYPE_SINGLE, + CALLTYPE_BATCH, + EXECTYPE_DEFAULT +} from "./libraries/ModeLib.sol"; +import { ExecutionLib, Execution } from "./libraries/ExecutionLib.sol"; + +/** + * @title AGW — Agentic Wallet + * @notice The user's per-purpose agent wallet on Push Chain. It holds the budgeted funds and is + * `msg.sender` at the gateway, which is what binds it to its destination-chain account. + * + * @dev - Push Chain has no ERC-4337 EntryPoint, so this wallet builds the operation and enforces + * the engine's verdict itself in `executeAsAgent`. + * - An ERC-7579 modular account restricted to validator modules; executor, fallback and + * hook modules are refused. A hook would run on the owner path and could block it. + * - `execute` is the owner door: no policy is ever consulted on it. + * - `executeAsAgent` is the agent door: callable only by the rules set's agent — a Push + * address (an EOA, or the UEA of an external key) — and every call is checked by the + * rules set's policy. + * - Deliberately near-stateless. A request exists only for the transaction that carries it. + */ +contract AGW is IAGW, ReentrancyGuardTransient { + using ModeLib for ModeCode; + + /// @dev ERC-7579 account id, in vendor.account.semver form. + string internal constant ACCOUNT_ID = "push.agw.1.0.0"; + + /// @dev The only ERC-7579 module type this account supports. + uint256 internal constant MODULE_TYPE_VALIDATOR = 1; + + /// @dev Gas stipend for a module's uninstall callback. + uint256 internal constant UNINSTALL_CALLBACK_GAS_STIPEND = 100_000; + + /// @dev Gas cap on the pre-uninstall state probe of the session engine. + uint256 internal constant ENGINE_STATE_PROBE_GAS = 30_000; + + /** + * @dev Maximum actions in one NATIVE rules set. `UNIVERSAL` is always exactly one. + * + * A SANITY BOUND, NOT A GAS BOUND — measured, a maximal 8x8 grant sits far inside the + * budget. It caps the O(n^2) duplicate scan below, the per-rules-set audit and UI surface a + * human has to reason about, and `revokeRules`'s engine-side cleanup cost. + * + * Lives HERE, not in `Types.sol`, because it is a wallet policy number that URP never + * reads — unlike the engine mirrors, which are shared. Do not confuse it with URP's + * `MAX_ACTIONS_PER_REQUEST` (10): that bounds multicall ENTRIES inside one universal + * payload, two layers down. Different layers, different numbers, never conflated. + */ + uint256 internal constant MAX_NATIVE_ACTIONS = 8; + + // The four wiring addresses, read through their UPPER_CASE() auto-getters. Resolved from the + // implementation's runtime bytecode, so every clone reads them correctly through delegatecall. + + /// @notice The permission engine this wallet installs as its default validator. + address public immutable SESSION_ENGINE; + + /// @notice The canonical action policy (URP) every rules set on this wallet must name. + address public immutable RULES_POLICY; + + /// @notice The canonical session validator every rules set on this wallet must name — the sender + /// validator that confirms the caller is the rules set's agent. + address public immutable SESSION_VALIDATOR; + + /// @notice The Push-side outbound gateway, the only target a universal agent action may reach. + address public immutable UNIVERSAL_GATEWAY_PC; + + /// @dev One-shot latch for initializeAccount. + bool private _initialized; + + /// @dev Monotonic salt source for permission ids; never reused. + uint64 private _grantNonce; + + /// @dev Owner-side checkpoints so far; also the `seq` of the latest `Checkpointed`. Packed in slot 0. + uint64 private _checkpointCount; + + /// @dev `block.number` of the latest checkpoint; zero before the first. Packed in slot 0. + uint64 private _lastCheckpointBlock; + + /// @dev The account's entire module registry. + mapping(address => bool) private _installedValidators; + + /// @dev Owner replay lanes for `executeWithSig`: lane key => next expected sequence number. + mapping(uint192 => uint64) private _nonces; + + /// @dev The owner's label for this wallet; empty means the default `AGW `. + string private _label; + + /** + * @notice Sets the wallet's permanent wiring and locks the implementation itself. + * + * @dev - Reverts with `InvalidModuleAddress` if any of the four addresses is zero. + * - Sets the initialised latch, so the implementation can never be initialised or + * driven directly; only clones of it can. + * + * @param sessionEngine_ Permission engine installed as the default validator. + * @param rulesPolicy_ Canonical action policy every rules set must name. + * @param sessionValidator_ Canonical session validator every rules set must name. + * @param universalGatewayPC_ Push-side outbound gateway. + */ + constructor(address sessionEngine_, address rulesPolicy_, address sessionValidator_, address universalGatewayPC_) { + if ( + sessionEngine_ == address(0) || rulesPolicy_ == address(0) || sessionValidator_ == address(0) + || universalGatewayPC_ == address(0) + ) { + revert AGWErrors.InvalidModuleAddress(); + } + SESSION_ENGINE = sessionEngine_; + RULES_POLICY = rulesPolicy_; + SESSION_VALIDATOR = sessionValidator_; + UNIVERSAL_GATEWAY_PC = universalGatewayPC_; + + _initialized = true; + } + + /// @dev Reverts unless the caller is the clone's immutable-args owner. + modifier onlyOwner() { + if (msg.sender != _owner()) revert AGWErrors.CallerIsNotOwner(); + _; + } + + /** + * @dev Reverts unless the caller is the owner or the wallet itself. Applied to the three + * lifecycle functions and `setLabel` only. + * + * - A batch entry targeting the wallet arrives with `msg.sender == address(this)`, so + * without this the owner's own one-signature change batch reverts against itself. + * - Widening to self is safe because self is reachable only through the owner door. From + * the agent door it is refused FOUR ways, in the order they fire: + * (a) at grant time, by `_requireGrantableTarget` — the wallet is never a grantable + * native action target; + * (b) at dispatch time, by the guard in `_gateAndDispatch` — which holds even for a + * session the owner enabled on the engine directly through the owner door, + * bypassing `grantRules` entirely; + * (c) by the engine's `NoPoliciesSet`, because (a) guarantees the wallet is never a + * configured action — true regardless of how many actions a rules set holds; + * (d) by the engine's `InvalidSelfCall`, for the `execute` selector specifically. + * (a) and (b) are never-delete tests. + * - Not applied to installModule or uninstallModule; nothing needs them batched. + */ + modifier onlyOwnerOrSelf() { + if (msg.sender != _owner() && msg.sender != address(this)) revert AGWErrors.CallerIsNotOwner(); + _; + } + + /** + * @dev Reads the owner out of the clone's immutable args. + * + * - Clone args are 40 bytes: owner at 0-19, factory at 20-39. + * - Read from bytecode on every call and never cached; a storage mirror of an immutable is + * drift surface. + * - Meaningful only on a clone. `Clones.fetchCloneArgs` is undefined on a non-clone, and on + * the implementation it returns a slice of that contract's own runtime bytecode. + * - No guard is added for the implementation case: every door on the implementation is + * already inert for an independent reason. + * + * @return The clone's owner. + */ + function _owner() internal view returns (address) { + return address(bytes20(Clones.fetchCloneArgs(address(this)))); + } + + /** + * @dev Reads the deploying factory out of the clone's immutable args. + * @return The factory recorded at clone creation. + */ + function _factory() internal view returns (address) { + bytes memory args = Clones.fetchCloneArgs(address(this)); + return address(bytes20(_slice20(args, 20))); + } + + /** + * @dev Reads 20 bytes at `start` out of a memory blob, without assuming a length. The + * short-blob branch is unreachable from the single call site and is expected to show as + * uncovered. + * + * @param data Blob to read from. + * @param start Byte offset to read at. + * @return out The 20 bytes at `start`, or zero if the blob is too short. + */ + function _slice20(bytes memory data, uint256 start) private pure returns (bytes20 out) { + if (data.length < start + 20) return bytes20(0); + assembly { + out := mload(add(add(data, 0x20), start)) + } + } + + /** + * @notice Factory-only, callable exactly once. Installs the session engine as the account's + * sole validator. + * + * @dev - Reverts with `CallerIsNotFactory` unless the caller is the clone's recorded factory. + * - Reverts with `AlreadyInitialized` if the latch is already set. + * - Sets the latch, marks the engine installed, then calls `onInstall("")` with full gas + * and bubbles any revert, so the factory's deploy transaction unwinds atomically. + * - Emits `ModuleInstalled`, then `AccountInitialized`. + * - Session data is never passed here; grants travel only through `grantRules`. + * - Stores `label_` when it is non-empty; an empty label costs no write and reads as the + * default. An over-long label reverts `LabelTooLong` and unwinds the whole deploy. + * + * @param label_ The deploy-time label; empty for the default `AGW `. + */ + function initializeAccount(string calldata label_) external { + if (msg.sender != _factory()) revert AGWErrors.CallerIsNotFactory(); + if (_initialized) revert AGWErrors.AlreadyInitialized(); + + _initialized = true; + if (bytes(label_).length != 0) _setLabel(label_); + _installedValidators[SESSION_ENGINE] = true; + + IERC7579Module(SESSION_ENGINE).onInstall(""); + + emit ModuleInstalled(MODULE_TYPE_VALIDATOR, SESSION_ENGINE); + emit AccountInitialized(_owner(), SESSION_ENGINE); + } + + /** + * @notice The owner door. Executes a single call or a batch on the owner's behalf; no policy is + * ever consulted. + * + * @dev - Reverts unless the caller is the owner; reentrancy-guarded. + * - Reverts on any execution type other than default, and on any call type other than + * single or batch. + * - Reads no module, policy or engine state — only the immutable-args owner, its calldata, + * and the wallet's own checkpoint slot — so the door still works with the engine + * uninstalled, with a hostile validator installed, or in ghost-rules state. + * - Records one checkpoint per call, before the call (`_checkpointOwnerCall`). The write + * cannot revert. + * - The signature is frozen at `execute(bytes32,bytes)`: the session engine branches on + * this exact selector, and any other shape routes validation down a path where the + * action policy sees a hardcoded zero value instead of the real one. + * - Batch is required product surface: the permission-change flow is one owner signature + * batching a spend assertion, a revoke and a grant. + * - Dispatches through `_execute` and emits `OwnerExecuted`. + * - There is no separate withdraw function; withdrawal, revocation escort and incident + * response all run through this door. + * + * @param mode ERC-7579 mode word; call type and execution type are decoded from it. + * @param executionCalldata Encoded execution, single or batch according to `mode`. + */ + function execute(bytes32 mode, bytes calldata executionCalldata) external payable onlyOwner nonReentrant { + ModeCode m = ModeCode.wrap(mode); + (CallType callType, ExecType execType,,) = m.decode(); + + if (execType != EXECTYPE_DEFAULT) revert AGWErrors.UnsupportedExecutionMode(); + if (callType == CALLTYPE_SINGLE) { + (address target, uint256 value, bytes calldata callData) = ExecutionLib.decodeSingle(executionCalldata); + _checkpointOwnerCall(target, value, callData); + _execute(target, value, callData); + } else if (callType == CALLTYPE_BATCH) { + Execution[] calldata execs = ExecutionLib.decodeBatch(executionCalldata); + uint256 len = execs.length; + for (uint256 i; i < len;) { + _checkpointOwnerCall(execs[i].target, execs[i].value, execs[i].callData); + _execute(execs[i].target, execs[i].value, execs[i].callData); + unchecked { + ++i; + } + } + } else { + revert AGWErrors.UnsupportedExecutionMode(); + } + + emit OwnerExecuted(mode, keccak256(executionCalldata)); + } + + /** + * @dev Plain call, bubbling the callee's revert data verbatim. Shared by both doors so the agent + * path executes the exact validated bytes. + * + * @param target Address to call. + * @param value Native PC to send with the call. + * @param callData Calldata to pass, forwarded unchanged. + */ + function _execute(address target, uint256 value, bytes calldata callData) internal { + (bool ok, bytes memory ret) = target.call{ value: value }(callData); + if (!ok) { + assembly { + revert(add(ret, 0x20), mload(ret)) + } + } + } + + /** + * @dev Records one owner-side change: advances the counter, stamps the block, emits `Checkpointed`. + * + * - CANNOT REVERT except by running out of gas: an unchecked increment of a uint64 that cannot + * realistically reach 2^64, one write to the wallet's own slot 0, one event. No external call. + * That is what lets it sit on the owner doors and on the revocation path. + * - NEVER called from `_execute` or anywhere the agent door reaches. A checkpoint means "the + * owner side touched this wallet"; an agent that could tick it could always fake owner + * interference. + * + * @param kind What changed. + * @param ref Per-kind reference (see `IAGW.Checkpointed`). + */ + function _checkpoint(CheckpointKind kind, bytes32 ref) private { + uint64 seq; + unchecked { + seq = _checkpointCount + 1; + } + // forge-lint: disable-next-line(unsafe-typecast) + uint64 blockNumber = uint64(block.number); // a block number does not exceed 2^64 in practice + _checkpointCount = seq; + _lastCheckpointBlock = blockNumber; + emit Checkpointed(seq, kind, ref, blockNumber); + } + + /** + * @dev The owner-door tick for one call, taken BEFORE the call runs, so a consumer snapshotting the + * counter during that call already sees it, and any later call in the same batch moves it again. + * + * @param target The call's target. + * @param value The call's native value. + * @param callData The call's calldata. + */ + function _checkpointOwnerCall(address target, uint256 value, bytes calldata callData) private { + _checkpoint(CheckpointKind.OWNER_ACTION, keccak256(abi.encode(target, value, callData))); + } + + /** + * @notice The owner door, authorised by a signed OwnerIntent instead of `msg.sender`. Relayable. + * + * @dev - A THIRD door, separate from `execute`. `execute` reads no module, policy or engine + * state — only the immutable-args owner, its calldata and its own checkpoint slot — and + * remains the unblockable fallback. This door reads storage (the nonce lane) and may + * therefore fail where `execute` cannot. + * - The mode switch below is DUPLICATED from `execute`, not shared with it, so that no + * refactor can ever add a check to `execute`. + * - Checks, in order: deadline · `intent.wallet == this` · owner · presenter is + * `intent.executor` · owner lane · `mode` and a non-zero `execCalldataHash` match · + * nonce (consumed before the signature check; any revert unwinds it) · the owner's + * signature under the FACTORY's domain. + * - Single or batch, default exec type. No dispatch guard: this is owner authority, so a + * batch may call the wallet's own lifecycle functions through `onlyOwnerOrSelf`. + * - Records one checkpoint per call, before the call, exactly as `execute` does. + * - Emits `OwnerExecutedWithSig`. + * + * @param mode ERC-7579 mode word; must equal `intent.mode`. + * @param executionCalldata Encoded execution; its hash must equal `intent.execCalldataHash`. + * @param intent The owner's intent; the grant fields are ignored here. + * @param sig The owner's signature over `intent`. + */ + function executeWithSig( + bytes32 mode, + bytes calldata executionCalldata, + OwnerIntent calldata intent, + bytes calldata sig + ) external nonReentrant { + address owner_ = _requireIntentPresenter(intent); + + uint192 nonceKey = intent.nonceKey; + if (nonceKey & OWNER_LANE_FLAG == 0) revert AGWErrors.OwnerLaneRequired(nonceKey); + + bytes32 calldataHash = keccak256(executionCalldata); + if (intent.execCalldataHash == bytes32(0) || intent.execCalldataHash != calldataHash || intent.mode != mode) { + revert AGWErrors.IntentExecMismatch(calldataHash); + } + + uint64 expected = _nonces[nonceKey]; + if (intent.nonceSeq != expected) revert AGWErrors.InvalidNonce(nonceKey, expected, intent.nonceSeq); + _nonces[nonceKey] = expected + 1; + + _requireOwnerSig(owner_, intent, sig); + + (CallType callType, ExecType execType,,) = ModeCode.wrap(mode).decode(); + if (execType != EXECTYPE_DEFAULT) revert AGWErrors.UnsupportedExecutionMode(); + if (callType == CALLTYPE_SINGLE) { + (address target, uint256 value, bytes calldata callData) = ExecutionLib.decodeSingle(executionCalldata); + _checkpointOwnerCall(target, value, callData); + _execute(target, value, callData); + } else if (callType == CALLTYPE_BATCH) { + Execution[] calldata execs = ExecutionLib.decodeBatch(executionCalldata); + uint256 len = execs.length; + for (uint256 i; i < len;) { + _checkpointOwnerCall(execs[i].target, execs[i].value, execs[i].callData); + _execute(execs[i].target, execs[i].value, execs[i].callData); + unchecked { + ++i; + } + } + } else { + revert AGWErrors.UnsupportedExecutionMode(); + } + + emit OwnerExecutedWithSig(mode, calldataHash, nonceKey, intent.nonceSeq); + } + + /** + * @dev The checks every intent door shares, in order: deadline, wallet, owner, presenter. + * Returns the owner so the caller does not re-read the immutable args. + */ + function _requireIntentPresenter(OwnerIntent calldata intent) internal view returns (address owner_) { + if (block.timestamp > intent.deadline) revert AGWErrors.OwnerSigExpired(intent.deadline); + if (intent.wallet != address(this)) { + revert AGWErrors.IntentWalletMismatch(address(this), intent.wallet); + } + owner_ = _owner(); + if (intent.owner != owner_) revert AGWErrors.CallerIsNotOwner(); + if (intent.executor == address(0) || msg.sender != intent.executor) { + revert AGWErrors.ExecutorMismatch(intent.executor, msg.sender); + } + } + + /// @dev The owner's signature over `intent`, under the factory's domain. Last check before effects. + function _requireOwnerSig(address owner_, OwnerIntent calldata intent, bytes calldata sig) internal view { + if (!OwnerAuthLib.isOwnerSig(owner_, OwnerAuthLib.intentDigest(_factory(), intent), sig)) { + revert AGWErrors.InvalidOwnerSignature(); + } + } + + /** + * @notice Sets the wallet's label. `""` resets it to the default `AGW `. + * + * @dev - Reverts unless the caller is the owner or the wallet itself, so a UEA owner can rename + * through `executeWithSig`. The agent door never reaches it: its dispatch guard refuses + * the wallet as a target. + * - Reverts `LabelTooLong` above `MAX_LABEL_BYTES` bytes. + * - Cosmetic metadata: writes NO checkpoint (a rename sent through `execute` still ticks + * once, for the owner-door call itself). Makes no external call. + * - Emits `LabelSet` with the label as passed. + * + * @param label_ The new label, or `""` for the default. + */ + function setLabel(string calldata label_) external onlyOwnerOrSelf { + _setLabel(label_); + emit LabelSet(label_); + } + + /// @dev The one place the label is written and its length checked; the deploy path and `setLabel` + /// both come through here, so the cap cannot diverge between them. + function _setLabel(string calldata label_) private { + uint256 length = bytes(label_).length; + if (length > MAX_LABEL_BYTES) revert AGWErrors.LabelTooLong(length); + _label = label_; + } + + /** + * @notice Grants one rules set to an agent. One of exactly two lifecycle operations. + * + * @dev - Reverts unless the caller is the owner or the wallet itself. + * - Rejects any session that is not the one shape this wallet permits, all with + * `MalformedSessionShape`: any user-op policy present, any ERC-7739 content or policy, + * the ERC-4337 paymaster permit set, an action count other than one, an action whose + * target is not the gateway or whose selector is not the outbound send, an action + * policy set that is not exactly the canonical policy, or a session validator that is + * not the canonical one. + * - Rejects an agent config the session validator does not accept — anything but + * `abi.encode(address agent)` with a non-zero agent. The canonical validator's check + * never reverts; the call is still wrapped in a bare catch rather than a typed one, so a + * future validator's revert or compiler panic is absorbed as a refusal. Wrapping is + * correct here only because the external call already exists; the action policy's own + * decode is deliberately not wrapped, since there it would introduce one. + * - Refusing the paymaster permit keeps dead surface dead: setting it would write a live + * permit row into engine storage, and that row decides whether a non-empty + * `paymasterAndData` is rejected outright or instead requires a user-op policy to run, + * which this shape forbids. + * - Overwrites the caller's salt with the wallet's monotonic grant counter, so identical + * terms granted twice yield distinct permission ids and a replaced id never recurs. + * That is what makes a request built for a revoked rules set die on regrant. + * - Enables the session on the engine and emits `RulesGranted`. + * - Records a checkpoint (`RULES_GRANTED`). + * - Validates the session's shape only. The caps, allow-list and expiry inside the policy + * config are the policy's own concern; do not extend this into term validation. + * - Carries no reentrancy guard: the guard would trip on the owner's own change batch, + * and the engine's enable path never calls back into the account. + * + * - TAKES NO MANDATE TYPE. The kind of a rules set is DERIVED, not declared: each action's + * URP policy envelope is `abi.encode(uint16 version, string chain, bytes body)`, and the chain decides + * the rulebook — this chain means a Push-side call (NATIVE), any other means a call + * through the gateway (UNIVERSAL). The owner states a chain once, where they were + * already stating the terms; nobody states a mode anywhere. Every action must name the + * same chain, which is what makes a mixed rules set unrepresentable rather than merely + * forbidden. + * - The envelope is NOT REWRITTEN. The wallet reads one field and passes the caller's + * bytes to the engine untouched, so what URP validates is exactly what the owner + * reviewed. + * + * @param session The session to enable. Its `salt` field is ignored and overwritten. + * @return rulesId The engine's id for the newly enabled rules set. + * + * `rulesId` is the engine's `permissionId`. + */ + function grantRules(Session calldata session) external onlyOwnerOrSelf returns (bytes32 rulesId) { + return _grantRules(session); + } + + /** + * @notice `grantRules`, authorised by the owner's signed OwnerIntent instead of `msg.sender`. + * + * @dev - Checks, in order: deadline · `intent.wallet == this` · `intent.owner` is this wallet's + * owner · presenter is `intent.executor` (non-zero) · `sessionHash` is non-zero and is the + * hash of `session` · `grantNonce` is the current `_grantNonce` · the owner's signature under + * the FACTORY's domain. Then the entire `grantRules` body, unchanged. + * - `_grantNonce` advances on every grant, so an intent grants at most once and dies on any + * other grant. No new storage. + * - `sessionHash` covers the session AS SUPPLIED, salt included; the salt is then overwritten + * with the grant nonce exactly as on the owner path. + * - Unreachable from the agent door: the wallet is never a grantable action target, and the + * dispatch guard refuses `address(this)` whatever the selector. + * - No reentrancy guard, for the same reason `grantRules` has none. + * + * @param session The session to enable. + * @param intent The owner's intent; the exec fields are ignored here. + * @param sig The owner's signature over `intent`. + * @return rulesId The engine's id for the newly enabled rules set. + * + * `rulesId` is the engine's `permissionId`. + */ + function grantRulesWithSig(Session calldata session, OwnerIntent calldata intent, bytes calldata sig) + external + returns (bytes32 rulesId) + { + address owner_ = _requireIntentPresenter(intent); + + bytes32 sessionHash = keccak256(abi.encode(session)); + if (intent.sessionHash == bytes32(0) || intent.sessionHash != sessionHash) { + revert AGWErrors.IntentSessionMismatch(sessionHash); + } + if (intent.grantNonce != _grantNonce) { + revert AGWErrors.IntentGrantNonceMismatch(_grantNonce, intent.grantNonce); + } + _requireOwnerSig(owner_, intent, sig); + + return _grantRules(session); + } + + /** + * @dev The entire body `grantRules` always had, moved here unchanged so both entry points run the + * same checks in the same order with the same errors. See `grantRules` for the rules. + */ + function _grantRules(Session calldata session) internal returns (bytes32 rulesId) { + // ─── rules COMMON to both types, first ─── + + if (session.userOpPolicies.length != 0) revert AGWErrors.MalformedSessionShape(); + + if ( + session.erc7739Policies.allowedERC7739Content.length != 0 + || session.erc7739Policies.erc1271Policies.length != 0 + ) revert AGWErrors.MalformedSessionShape(); + + if (session.permitERC4337Paymaster) revert AGWErrors.MalformedSessionShape(); + + uint256 n = session.actions.length; + + // BEFORE THE DECODE, AND FOR BOTH MODES. The mode is derived from action 0's envelope, so + // action 0 must exist before anything can be derived: with no actions there is no envelope, + // no chain, and therefore no mode to report. A universal session with zero actions + // consequently reports `TooManyActions(0)`, not `MalformedSessionShape`. + if (n == 0) revert AGWErrors.TooManyActions(0); + + // THE POLICY-SHAPE CHECK RUNS BEFORE THE DECODE, ALWAYS. Decoding first would read an + // arbitrary policy's `initData` as though it were URP's. This ordering is load-bearing. + _requirePolicyShape(session.actions[0]); + (string memory chain, bytes32 chainHash) = _chainNamespaceOf(session.actions[0]); + + // ─── THE ENTIRE MODE DECISION. Nobody declared it. ─── + RulesType mode = PushChainLib.deriveMode(chainHash); + + // THE INVARIANT, STATED ONCE: a wrong POLICY is always `MalformedSessionShape`; a target + // wrong FOR THE DERIVED TYPE is always `RulesTypeMismatch`. Between the two branches + // there is no shape in which a gateway call reaches a native config, and none in which a + // native call reaches a universal one — which, with URP's N3 and gate 3 at runtime, is the + // whole consistency argument. One chain per rules set makes mixed rules sets unrepresentable. + + if (mode == RulesType.UNIVERSAL) { + // `n != 1` BEFORE the target check, as before. A malformed chain string on a + // multi-action session therefore reports `MalformedSessionShape`, not a type mismatch. + if (n != 1) revert AGWErrors.MalformedSessionShape(); + + ActionData calldata a = session.actions[0]; + if (a.actionTarget != UNIVERSAL_GATEWAY_PC || a.actionTargetSelector != SEND_OUTBOUND_SELECTOR) { + revert AGWErrors.RulesTypeMismatch(mode, 0, a.actionTarget); + } + } else { + if (n > MAX_NATIVE_ACTIONS) revert AGWErrors.TooManyActions(n); + + // Hoisted: `_factory()` does an extcodecopy of the clone's own bytecode on every call. + address factoryAddr = _factory(); + + for (uint256 i; i < n;) { + ActionData calldata a = session.actions[i]; + + _requireGrantableTarget(a.actionTarget, factoryAddr, i); + _requireGrantableSelector(a.actionTargetSelector); + + // Action 0's shape and chain were read above; re-reading would waste ~900 gas. + // EVERY action must name the same chain — that is what makes "one rules set, one + // mode" true by construction rather than by a rule. + if (i != 0) { + _requirePolicyShape(a); + (, bytes32 h) = _chainNamespaceOf(a); + if (h != chainHash) revert AGWErrors.InconsistentChain(i); + } + + // O(n^2) by design: 28 comparisons at the n=8 ceiling, which beats a mapping and its + // clear-down. Two identical (target, selector) pairs would hash to one actionId. + for (uint256 j; j < i;) { + if ( + session.actions[j].actionTarget == a.actionTarget + && session.actions[j].actionTargetSelector == a.actionTargetSelector + ) { + revert AGWErrors.DuplicateAction(a.actionTarget, a.actionTargetSelector); + } + unchecked { + ++j; + } + } + + unchecked { + ++i; + } + } + } + + if (address(session.sessionValidator) != SESSION_VALIDATOR) { + revert AGWErrors.MalformedSessionShape(); + } + + try IAgentValidator(SESSION_VALIDATOR).validateConfig(session.sessionValidatorInitData) returns (bool ok) { + if (!ok) revert AGWErrors.MalformedSessionShape(); + } catch { + revert AGWErrors.MalformedSessionShape(); + } + + Session memory sessionMem = session; + sessionMem.salt = bytes32(uint256(_grantNonce)); + // Checked on purpose: a wrapping counter would mean silent salt reuse. + _grantNonce++; + + Session[] memory sessions = new Session[](1); + sessions[0] = sessionMem; + PermissionId[] memory ids = ISmartSession(SESSION_ENGINE).enableSessions(sessions); + + rulesId = PermissionId.unwrap(ids[0]); + _checkpoint(CheckpointKind.RULES_GRANTED, rulesId); + emit RulesGranted(rulesId, mode, chainHash, chain); + } + + /** + * @dev The policy-shape rule, hoisted so it can run before each envelope decode. + * + * A SHAPE rule, so it raises `MalformedSessionShape` like every other shape rule. It is + * also the precondition for `_chainNamespaceOf`: without it, the decode below would be reading an + * arbitrary policy's `initData` as though URP had authored it. + * + * @param a The action whose policy slot is vetted. + */ + function _requirePolicyShape(ActionData calldata a) internal view { + if (a.actionPolicies.length != 1 || a.actionPolicies[0].policy != RULES_POLICY) { + revert AGWErrors.MalformedSessionShape(); + } + } + + /** + * @dev Reads ONE field of the policy envelope — the bounded exception to "the skeleton, not the + * organs". + * + * WHAT THIS IS NOT: it is not term validation. The wallet does not check caps, expiry, + * allow-list contents or anything else inside the body, and must never start. It reads the + * label on the jar: the one field that decides WHICH RULEBOOK the action belongs to, which + * is the wallet's own business because the wallet's target rules depend on it. URP + * re-derives the same value from the same bytes and remains the sole judge of the terms. + * + * CALLER MUST HAVE RUN `_requirePolicyShape` FIRST. + * + * Same decoder as URP's, deliberately (`abi.decode(initData, (uint16, string, bytes))`): + * two different readers of one security-relevant field is the drift this design exists to + * prevent. A malformed envelope reverts here, unnamed, and fails closed. The version is + * URP's to judge: it refuses anything but `ENVELOPE_VERSION` at init, inside this grant. + * + * @param a The action to read. + * @return chain The declared CAIP-2 string, e.g. `"eip155:11155111"`. + * @return chainHash Its keccak256, the value everything downstream compares. + */ + function _chainNamespaceOf(ActionData calldata a) internal pure returns (string memory chain, bytes32 chainHash) { + (, chain,) = abi.decode(a.actionPolicies[0].initData, (uint16, string, bytes)); + if (bytes(chain).length == 0) revert AGWErrors.EmptyChain(); + chainHash = keccak256(bytes(chain)); + } + + /** + * @dev Every grant-time target rule for a NATIVE action, in one place. + * + * TWO RULES, TWO ERRORS, AND THE DISTINCTION IS THE POINT: + * + * - **The gateway → `RulesTypeMismatch`.** The session is well-formed; the CHAIN the + * envelope declares is this chain, and a gateway call is not a Push-side call. A gateway + * target is perfectly grantable — under a foreign chain, as `UNIVERSAL`. Carries the + * action index, because with up to eight actions "something was wrong" is not a usable + * diagnostic. This is one half of the consistency lock; URP's N3 is the runtime mirror. + * - **The other seven → `ForbiddenActionTarget`.** Never grantable, under any type. + * + * Of those seven the severe pair is the wallet and the engine: from the agent door, + * `_execute(wallet, 0, grantRules(...))` would arrive with `msg.sender == address(this)`, + * pass `onlyOwnerOrSelf`, and the agent would have granted itself a rules set of its own + * design. `revokeAllRules` is the mirror. + * + * LAYER CREDIT, so nobody deletes the wrong one as redundant: the engine independently + * refuses `address(0)` and ITSELF at enable time (`ConfigLib.sol:139-143`), but it does NOT + * refuse `address(1)` there — only at check time. **This is the only grant-time layer for + * the fallback flag.** + * + * The action-policy check is deliberately NOT here. That is a SHAPE rule — it raises + * `MalformedSessionShape`, and the UNIVERSAL branch and the common rules raise the same + * error for the same class of defect. It belongs with them, not inside a target helper. + * + * @param t Action target to vet. + * @param factoryAddr The clone's factory, hoisted by the caller so the loop reads it once. + * `_factory()` does an extcodecopy of the clone's own bytecode; the other + * six comparands are immutables and are free to read here. + * @param index Index of this action, reported by `RulesTypeMismatch`. + */ + function _requireGrantableTarget(address t, address factoryAddr, uint256 index) internal view { + if (t == UNIVERSAL_GATEWAY_PC) { + revert AGWErrors.RulesTypeMismatch(RulesType.NATIVE, index, t); + } + if ( + t == address(0) || t == ENGINE_FALLBACK_TARGET || t == address(this) || t == SESSION_ENGINE + || t == RULES_POLICY || t == SESSION_VALIDATOR || t == factoryAddr + ) { + revert AGWErrors.ForbiddenActionTarget(t); + } + } + + /** + * @dev The grant-time forbidden-selector list for NATIVE actions. + * + * Refuses the engine's two fallback selectors by name. `0xFFFFFFFF` (value-only) is + * PERMITTED and is deliberately not on this list. + * + * @param s Action selector to vet. + */ + function _requireGrantableSelector(bytes4 s) internal pure { + if (s == ENGINE_FALLBACK_SELECTOR || s == ENGINE_FALLBACK_SELECTOR_SMARTSESSION) { + revert AGWErrors.ForbiddenActionSelector(s); + } + } + + /** + * @notice Revoke one rules set. The other lifecycle operation, and the emergency lever. + * + * @dev - Reverts unless the caller is the owner or the wallet itself. + * - Reverts with `UnknownPermission` if the id is not enabled, because the upstream + * removal silently no-ops on a ghost id and an operator must never read "revoked" + * while the rules set lives. + * - Removes the session and emits `RulesRevoked`. Revocation is immediate: removal clears + * the agent, so any request under the id fails `CallerIsNotAgent`. + * - Deliberately carries no reentrancy guard and no health probe: nothing that can fail + * belongs on the stop path, since blockable removal is the one regression this + * function can develop. It records a checkpoint (`RULES_REVOKED`) per removed id; that + * write cannot revert. + * + * @param rulesId The rules set to revoke. + * + * `rulesId` is the engine's `permissionId`. + */ + function revokeRules(bytes32 rulesId) external onlyOwnerOrSelf { + if (!ISmartSession(SESSION_ENGINE).isPermissionEnabled(PermissionId.wrap(rulesId), address(this))) { + revert AGWErrors.UnknownPermission(rulesId); + } + + ISmartSession(SESSION_ENGINE).removeSession(PermissionId.wrap(rulesId)); + + _checkpoint(CheckpointKind.RULES_REVOKED, rulesId); + emit RulesRevoked(rulesId); + } + + /** + * @notice Revokes every rules set on this wallet in one call. The incident-response lever. + * + * @dev - Reverts unless the caller is the owner or the wallet itself. + * - Snapshots the permission ids, removes each by id, and emits `RulesRevoked` per id. + * Removal is by id, so engine-side array shifting cannot disturb the snapshot. + * - Deliberately carries no reentrancy guard and no health probe, for the same reason as + * `revokeRules`. It records a checkpoint (`RULES_REVOKED`) per removed id; that write + * cannot revert. + * - Gas grows with permission count; wallets hold few permissions by design. + */ + function revokeAllRules() external onlyOwnerOrSelf { + PermissionId[] memory ids = ISmartSession(SESSION_ENGINE).getPermissionIDs(address(this)); + + uint256 len = ids.length; + for (uint256 i; i < len;) { + ISmartSession(SESSION_ENGINE).removeSession(ids[i]); + _checkpoint(CheckpointKind.RULES_REVOKED, PermissionId.unwrap(ids[i])); + emit RulesRevoked(PermissionId.unwrap(ids[i])); + unchecked { + ++i; + } + } + } + + /** + * @notice The agent door. Callable only by the rules set's agent; every call is checked by the + * rules set's policy before it runs. + * + * @dev This chain has no EntryPoint, so this function does the EntryPoint's work, in order: + * 1. reject if the session engine is no longer installed + * 2. reject unless `msg.sender` is the agent `rulesId` names on this wallet + * 3. build the operation, validate it through the engine, and enforce the verdict + * 4. reject any mode other than single and default, and the two forbidden targets + * 5. dispatch the exact validated bytes + * 6. emit `RulesActionAuthorized` + * + * - The agent is a Push address. An external key (EVM, Solana, anything) acts through its + * UEA, which verifies that key before calling here; this wallet verifies no signature. + * - Replay protection is the sender's own transaction nonce (an EOA's nonce, or the UEA + * payload's nonce). Expiry is the rules set's own (policy gate 2 / N2 / S2); an EOA + * transaction carries no per-request expiry, a UEA payload carries its `deadline`. + * - A request against a revoked rules set fails at step 2: removal clears the agent. + * - Not payable, but a validated request does move PC out of the wallet's own balance, + * bounded by the policy's per-call ceiling. + * - Any revert unwinds the whole transaction, including the policy's counters; dispatch + * is never wrapped in try/catch. + * - Mode is single-only here: batching lives inside the multicall payload, bounded by the + * policy. + * + * @param rulesId The rules set this call acts under. `rulesId` is the engine's + * `permissionId`. + * @param mode ERC-7579 mode word; must decode to single and default. + * @param executionCalldata Encoded single execution, dispatched byte-for-byte once validated. + */ + function executeAsAgent(bytes32 rulesId, bytes32 mode, bytes calldata executionCalldata) external nonReentrant { + if (!_installedValidators[SESSION_ENGINE]) { + revert AGWErrors.ValidatorNotInstalled(SESSION_ENGINE); + } + + if (msg.sender != _agentOf(rulesId)) revert AGWErrors.CallerIsNotAgent(rulesId, msg.sender); + + bytes32 callsHash = keccak256(executionCalldata); + + _validate(rulesId, mode, executionCalldata, callsHash); + + _gateAndDispatch(mode, executionCalldata); + + emit RulesActionAuthorized(rulesId, msg.sender, callsHash); + } + + /** + * @dev Gates the mode to single and default, then dispatches the validated execution unchanged. + * + * - The agent path never batches at the ERC-7579 layer; batching lives inside the multicall + * payload instead, bounded by the policy. + * - Split out for stack depth only. Inlined, this does not compile with the optimizer off, + * which is the configuration `forge coverage` uses. + * + * @param mode ERC-7579 mode word. + * @param executionCalldata Encoded single execution to dispatch. + */ + function _gateAndDispatch(bytes32 mode, bytes calldata executionCalldata) internal { + (CallType callType, ExecType execType,,) = ModeCode.wrap(mode).decode(); + if (callType != CALLTYPE_SINGLE || execType != EXECTYPE_DEFAULT) { + revert AGWErrors.UnsupportedExecutionMode(); + } + (address target, uint256 value, bytes calldata callData) = ExecutionLib.decodeSingle(executionCalldata); + + // ⚠️ THE DISPATCH GUARD — never-delete, and it belongs HERE, after validation. + // + // Two comparisons, no storage, no module or policy state. It holds regardless of how the + // session was enabled — including a session the owner enabled on the engine DIRECTLY + // through the owner door, bypassing `grantRules` and its forbidden-target list entirely. + // That path exists today and is legitimate; this is what stops it reaching the wallet's own + // lifecycle functions from the agent side. + // + // DO NOT MOVE IT BEFORE `_validate`. Placed earlier it would pre-empt the engine's own + // refusals and change which error surfaces, and the engine-target case only ever reaches + // this point through the fallback sentinel, which validation has to run to resolve. + if (target == address(this) || target == SESSION_ENGINE) { + revert AGWErrors.ForbiddenDispatchTarget(target); + } + + _execute(target, value, callData); + } + + /** + * @dev Builds the operation, validates it through the engine, and enforces the verdict. + * + * - Builds a `PackedUserOperation` for its ABI shape only, since there is no EntryPoint. The + * engine requires `sender` to equal `msg.sender` (the wallet); that is what makes the + * signature field below unforgeable. + * - The callData selector must be `execute(bytes32,bytes)`, because that is the only engine + * branch that decodes the mode and forwards the real decoded value to the action policy. + * Every other selector reaches the policy with the account as target and a hardcoded zero + * value, which would make the policy's value gate compare against nothing. + * - The signature field is `USE ‖ rulesId ‖ msg.sender`, written here and nowhere else. The + * session validator accepts it only when those 20 bytes are the rules set's agent. + * - `callsHash` is passed as the operation hash. Nothing verifies a signature over it; it is + * what the engine forwards to the validator, which ignores it. + * - Gas fields are zero and `paymasterAndData` must stay empty, or the engine's paymaster + * permit check reverts. The nonce field is zero: replay protection is the sender's own. + * - Enforces the returned authorizer and time window itself — the EntryPoint's job, and what + * makes the policy's expiry gate real rather than decorative. + * - The engine runs the action policy before it consults the session validator, so policies + * still see calldata the engine has not yet authenticated; the wallet's own agent check + * has already run by then. + * - Performs exactly one external call, to the engine. Split out for stack depth. + * + * @param rulesId The rules set, written into the signature field. + * @param mode ERC-7579 mode word, re-encoded into the operation's calldata. + * @param executionCalldata Execution calldata, re-encoded into the operation's calldata. + * @param callsHash `keccak256(executionCalldata)`, passed as the operation hash. + */ + function _validate(bytes32 rulesId, bytes32 mode, bytes calldata executionCalldata, bytes32 callsHash) internal { + PackedUserOperation memory op; + op.sender = address(this); + op.nonce = 0; + op.initCode = ""; + op.callData = abi.encodeWithSelector(this.execute.selector, mode, executionCalldata); + op.accountGasLimits = bytes32(0); + op.preVerificationGas = 0; + op.gasFees = bytes32(0); + op.paymasterAndData = ""; + op.signature = abi.encodePacked(SmartSessionMode.USE, rulesId, msg.sender); + + uint256 vd = ValidationData.unwrap(ISmartSession(SESSION_ENGINE).validateUserOp(op, callsHash)); + + address authorizer = address(uint160(vd)); + uint48 validUntil = uint48(vd >> 160); // 0 = unbounded + uint48 validAfter = uint48(vd >> 208); + + if (authorizer != address(0)) revert AGWErrors.ValidationFailed(authorizer); + if (block.timestamp < validAfter) revert AGWErrors.OutsideTimeWindow(validAfter, validUntil); + if (validUntil != 0 && block.timestamp > validUntil) { + revert AGWErrors.OutsideTimeWindow(validAfter, validUntil); + } + } + + /** + * @dev The agent `rulesId` names on this wallet, or `address(0)` if it names none. + * Zero when the id is unknown or revoked (removal clears the config), when its session + * validator is not the canonical one, or when its config is malformed. One external view + * call to the engine; decodes through the same library the validator enforces with. + * @param rulesId The rules set to look up. + * @return The agent's Push address, or zero. + */ + function _agentOf(bytes32 rulesId) internal view returns (address) { + (address sessionValidator_, bytes memory config) = ISmartSessionConfigReader(SESSION_ENGINE) + .getSessionValidatorAndConfig(address(this), PermissionId.wrap(rulesId)); + if (sessionValidator_ != SESSION_VALIDATOR) return address(0); + return AgentConfigLib.decode(config); + } + + /** + * @notice Installs a validator module. + * + * @dev - Reverts unless the caller is the owner; reentrancy-guarded. + * - Rejects any module type but validator, the zero address, an address with no code, + * and a module that is already installed. + * - Marks the module installed, calls `onInstall` with full gas and bubbles any revert, + * then emits `ModuleInstalled`. + * - Exists as the recovery lever: a corrected validator can be installed on an existing + * wallet without moving addresses or funds. + * + * @param moduleTypeId ERC-7579 module type; only the validator type is accepted. + * @param module Module to install. + * @param initData Opaque data forwarded to the module's `onInstall`. + */ + function installModule(uint256 moduleTypeId, address module, bytes calldata initData) + external + onlyOwner + nonReentrant + { + if (moduleTypeId != MODULE_TYPE_VALIDATOR) { + revert AGWErrors.UnsupportedModuleType(moduleTypeId); + } + if (module == address(0) || module.code.length == 0) revert AGWErrors.InvalidModuleAddress(); + if (_installedValidators[module]) revert AGWErrors.ModuleAlreadyInstalled(module); + + _installedValidators[module] = true; + + IERC7579Module(module).onInstall(initData); + + emit ModuleInstalled(moduleTypeId, module); + } + + /** + * @notice Uninstalls a validator module. Removal always proceeds. + * + * @dev - Reverts unless the caller is the owner; reentrancy-guarded. + * - Rejects any module type but validator, and a module that is not installed. + * - If and only if the module is the session engine, probes its initialised state under + * a gas cap and refuses removal while it still holds permissions. Uninstalling the + * engine with live permissions would run its cleanup loop out of gas and leave rows it + * then refuses to reinstall over, so the guard forces a `revokeAllRules` first. + * - Unmarks the module before calling back, so a module can never block its own removal. + * - Calls `onUninstall` under a stipend inside try/catch, emitting + * `UninstallCallbackFailed` if it reverts or exhausts the stipend, then emits + * `ModuleUninstalled`. + * - The probe is scoped to the engine alone, so a hostile third-party validator can + * never block its own removal. + * - A probe that reverts or runs out of gas proceeds with removal: the guard exists to + * prevent an ordering mistake, not to make a broken engine permanent. + * + * @param moduleTypeId ERC-7579 module type; only the validator type is accepted. + * @param module Module to uninstall. + * @param deInitData Opaque data forwarded to the module's `onUninstall`. + */ + function uninstallModule(uint256 moduleTypeId, address module, bytes calldata deInitData) + external + onlyOwner + nonReentrant + { + if (moduleTypeId != MODULE_TYPE_VALIDATOR) { + revert AGWErrors.UnsupportedModuleType(moduleTypeId); + } + if (!_installedValidators[module]) revert AGWErrors.ValidatorNotInstalled(module); + + if (module == SESSION_ENGINE) { + (bool ok, bytes memory ret) = module.staticcall{ gas: ENGINE_STATE_PROBE_GAS }( + abi.encodeCall(ISmartSession.isInitialized, (address(this))) + ); + if (ok && ret.length >= 32 && abi.decode(ret, (bool))) { + revert AGWErrors.EngineStillHoldsPermissions(); + } + } + + _installedValidators[module] = false; + + try IERC7579Module(module).onUninstall{ gas: UNINSTALL_CALLBACK_GAS_STIPEND }(deInitData) { } + catch { + emit UninstallCallbackFailed(module); + } + + emit ModuleUninstalled(moduleTypeId, module); + } + + /** + * @notice Whether `module` is installed under `moduleTypeId`. + * @param moduleTypeId ERC-7579 module type to query. + * @param module Module to query. + * @return True only for an installed validator. + */ + function isModuleInstalled(uint256 moduleTypeId, address module, bytes calldata) external view returns (bool) { + return moduleTypeId == MODULE_TYPE_VALIDATOR && _installedValidators[module]; + } + + /** + * @notice Whether this account supports an ERC-7579 module type. + * @param moduleTypeId Module type to query. + * @return True only for the validator type. + */ + function supportsModule(uint256 moduleTypeId) external pure returns (bool) { + return moduleTypeId == MODULE_TYPE_VALIDATOR; + } + + /** + * @notice Whether this account supports an ERC-7579 execution mode. + * @dev Answers for the account as a whole; the agent door additionally restricts itself to + * single calls. + * @param mode ERC-7579 mode word to query. + * @return True for default execution in single or batch call type. + */ + function supportsExecutionMode(bytes32 mode) external pure returns (bool) { + (CallType callType, ExecType execType,,) = ModeCode.wrap(mode).decode(); + if (execType != EXECTYPE_DEFAULT) return false; + return callType == CALLTYPE_SINGLE || callType == CALLTYPE_BATCH; + } + + /// @notice The wallet's owner, read from the clone's immutable args. + function owner() external view returns (address) { + return _owner(); + } + + /// @notice The factory that deployed this wallet. + function factory() external view returns (address) { + return _factory(); + } + + /** + * @notice The wallet's label: the owner's, or `AGW ` when none is set. + * @dev The default is computed, never stored, from the factory's per-owner index — so an + * owner's wallets read `AGW 1`, `AGW 2`, … A view only: no door ever calls it. + * @return The label. + */ + function label() external view returns (string memory) { + if (bytes(_label).length != 0) return _label; + return string.concat("AGW ", Strings.toString(IAGWFactory(_factory()).indexOf(address(this)) + 1)); + } + + /** + * @notice Next expected sequence number in an owner lane (`OWNER_LANE_FLAG` set), consumed by + * `executeWithSig`. The agent door uses no nonce lanes. + * @param nonceKey Replay lane to query. + * @return The sequence number the next intent in that lane must carry. + */ + function getNonce(uint192 nonceKey) external view returns (uint64) { + return _nonces[nonceKey]; + } + + /// @notice The salt the next grant will use. + function grantNonce() external view returns (uint64) { + return _grantNonce; + } + + /** + * @notice The agent a rules set names on this wallet, or zero if it names none. + * @dev Zero for an unknown or revoked id, for a session the owner enabled on the engine + * directly with a non-canonical session validator, and for a malformed config. Such a + * rules set cannot be used through `executeAsAgent`. + * @param rulesId The rules set to look up. `rulesId` is the engine's `permissionId`. + * @return The agent's Push address, or zero. + */ + function agentOf(bytes32 rulesId) external view returns (address) { + return _agentOf(rulesId); + } + + /** + * @notice Owner-side checkpoints so far. Compare against a snapshot to learn whether the owner side + * touched this wallet since: any owner-door call, grant or revoke moves it; agent actions + * never do. + * @return The number of checkpoints recorded. + */ + function checkpointCount() external view returns (uint64) { + return _checkpointCount; + } + + /** + * @notice `block.number` of the latest checkpoint, or zero if none. A convenience only: consumers + * must compare COUNTS, because several checkpoints can share a block with their snapshot. + * @return The block number of the latest checkpoint. + */ + function lastCheckpointBlock() external view returns (uint64) { + return _lastCheckpointBlock; + } + + /// @notice The OwnerIntent domain separator this wallet verifies against, for a signer on + /// `signerChainId`. Identical to the factory's: the factory is the verifying contract. + function domainSeparator(uint256 signerChainId) external view returns (bytes32) { + return OwnerAuthLib.domainSeparator(_factory(), signerChainId); + } + + /// @notice The ERC-7579 account id, in vendor.account.semver form. + function accountId() external pure returns (string memory) { + return ACCOUNT_ID; + } + + /// @dev Accepts PC with no logic; the wallet pays outbound gas swaps from its own balance and + /// refunds land here. + receive() external payable { } + + /// @notice Accepts ERC-721 transfers, so destination-side refunds and NFTs can land. + function onERC721Received(address, address, uint256, bytes calldata) external pure returns (bytes4) { + return this.onERC721Received.selector; + } + + /// @notice Accepts ERC-1155 transfers, so destination-side refunds and NFTs can land. + function onERC1155Received(address, address, uint256, uint256, bytes calldata) external pure returns (bytes4) { + return this.onERC1155Received.selector; + } + + /// @notice Accepts batched ERC-1155 transfers, so destination-side refunds and NFTs can land. + function onERC1155BatchReceived(address, address, uint256[] calldata, uint256[] calldata, bytes calldata) + external + pure + returns (bytes4) + { + return this.onERC1155BatchReceived.selector; + } + + /** + * @notice ERC-165 support check. + * + * @dev - Reports ERC-165 and the two token-receiver interfaces only. + * - Deliberately does not report `IERC7579Account`: this account implements that + * interface partially, so advertising it would mislead the tooling that probes for it. + * Tooling detects the account through `accountId`, `supportsModule` and + * `supportsExecutionMode` instead. + * + * @param interfaceId Interface id to query. + * @return True for the three supported interfaces. + */ + function supportsInterface(bytes4 interfaceId) external pure returns (bool) { + return interfaceId == type(IERC165).interfaceId // 0x01ffc9a7 + || interfaceId == 0x150b7a02 // IERC721Receiver + || interfaceId == 0x4e2312e0; // IERC1155Receiver + } + + /** + * @notice Always invalid: the wallet never signs as an ERC-1271 party. + * @dev A constant return, with no logic and no future hook. This is also what makes the + * engine's enable-mode grant path dead on these wallets. + * @return The ERC-1271 failure magic value. + */ + function isValidSignature(bytes32, bytes calldata) external pure returns (bytes4) { + return 0xffffffff; + } +} diff --git a/plan/agw/research/deployment-review-2026-10-07-v5/source/src/AGWFactory.sol b/plan/agw/research/deployment-review-2026-10-07-v5/source/src/AGWFactory.sol new file mode 100644 index 00000000..73308aa7 --- /dev/null +++ b/plan/agw/research/deployment-review-2026-10-07-v5/source/src/AGWFactory.sol @@ -0,0 +1,355 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import { AGWFactoryErrors } from "./libraries/Errors.sol"; + +import { Clones } from "@openzeppelin/contracts/proxy/Clones.sol"; + +import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import { + AccessControlDefaultAdminRulesUpgradeable +} from "@openzeppelin/contracts-upgradeable/access/extensions/AccessControlDefaultAdminRulesUpgradeable.sol"; +import { PausableUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol"; +import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +import { IAGWFactory } from "./interfaces/IAGWFactory.sol"; +import { IAGWInit } from "./interfaces/IAGWInit.sol"; +import { OwnerIntent } from "./libraries/Types.sol"; +import { OwnerAuthLib } from "./libraries/OwnerAuthLib.sol"; + +/** + * @title AGWFactory + * @notice Deploys `AGW` clones at addresses computable before deployment, and is the + * root of trust for wallet identity. + * + * @dev - Wallet addresses are deterministic and predictable before deployment, so counterfactual + * funding is a supported flow. + * - This registry is the only proof of a wallet's provenance: anyone can deploy a contract + * with a lying `owner()` view. The audit chain is destination account, wallet, this + * registry, owner. + * - The owner is the caller, or the signer of an `OwnerIntent` naming this owner, index and + * wallet, presented by the intent's `executor`. Deploying a wallet owned by someone else + * without that owner's signature is impossible. + * - Holds no funds, never touches a wallet after deployment, and has no setter for the + * wallet implementation. + * - Deployed behind an ERC-1967 UUPS proxy; the proxy address is the permanent, + * user-facing factory address and never changes across logic upgrades. + */ +contract AGWFactory is + Initializable, + AccessControlDefaultAdminRulesUpgradeable, + PausableUpgradeable, + UUPSUpgradeable, + IAGWFactory +{ + /// @dev Holder may pause wallet deployment. + bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); + + /// @dev Holder may unpause wallet deployment. + bytes32 public constant OPERATOR_ROLE = keccak256("OPERATOR_ROLE"); + + /** + * @dev Delay on the two-step admin transfer. + * + * - The admin's one real power is authorising a UUPS upgrade of this logic, which is the + * single action that can permanently strand counterfactually funded addresses. + * - The extension makes `grantRole` and `renounceRole` on the admin role revert, forcing + * the scheduled flow. + */ + uint48 internal constant DEFAULT_ADMIN_DELAY = 2 days; + + /// @dev All bases use ERC-7201 namespaced storage, so these three variables occupy slots 0, 1 + /// and 2. Order is frozen, and a layout test asserts it from `forge inspect` output. + + /// @dev owner => wallets deployed for them, doubling as the next index so a count and an index + /// can never drift apart. `uint96` matches `WalletRecord.index`, so no narrowing cast + /// exists anywhere in this contract. + mapping(address => uint96) internal _walletCount; + + /// @dev wallet => its record; a zero owner means not deployed by this factory. This is the + /// entire registry: existence, owner and index from one packed slot per wallet. + mapping(address => IAGWFactory.WalletRecord) internal _records; + + /** + * @notice The canonical AGW logic contract all clones delegate to. + * + * @dev - Written once, in `initialize`. There is no setter: a function able to rewrite this + * would silently move every predicted address and strand counterfactually funded + * wallets, with no migration path to recover them. + * - Declared last and appended to only. Every future variable goes after it, and nothing + * is inserted or reordered before it, or address derivation breaks with no remedy. + * - `internal`, exposed only through `walletImplementation()`, so no second + * auto-generated getter with a different selector exists. + */ + address internal _walletImplementation; + + // No storage gap: this is a leaf UUPS implementation, so a future version simply appends after + // _walletImplementation. + + /// @dev Locks the logic contract so it can never be initialised directly. + constructor() { + _disableInitializers(); + } + + /** + * @notice Configures the proxy. Callable once, at deployment. + * + * @dev - Reverts with `ZeroAddress` if either address is zero. + * - Sets the admin with the two-day transfer delay, initialises pausable, and records + * the wallet implementation. + * - Makes no external calls and deploys nothing. Pauser and operator membership are + * granted afterwards by the admin through the standard `grantRole`. + * + * @param admin Receives the default admin role. + * @param walletImplementation_ Logic contract every wallet clone will delegate to. + */ + function initialize(address admin, address walletImplementation_) external initializer { + if (admin == address(0) || walletImplementation_ == address(0)) revert AGWFactoryErrors.ZeroAddress(); + + __AccessControlDefaultAdminRules_init(DEFAULT_ADMIN_DELAY, admin); + __Pausable_init(); + // UUPSUpgradeable in OZ 5.7.0 has no initializer; calling one does not compile. + + _walletImplementation = walletImplementation_; + } + + /** + * @notice Deploys the caller's next agent wallet and initialises it. + * + * @dev - Reverts while paused, and with `ImplementationNotSet` if the wallet implementation + * is unset. The latter is reachable only on a proxy deployed without its atomic init + * call; without it, `Clones` would deploy a permanently uninitialisable clone. + * - Advances the caller's wallet count and writes the registry record before the single + * external call, which is what makes a reentrant deploy unable to reuse an index. + * There is deliberately no reentrancy guard; the effect ordering is the protection. + * - Salt is the owner and the factory-assigned sequential index only. Nothing + * rules-related enters the derivation. + * - The owner appears twice, in the salt and in the immutable args, on purpose; + * removing either changes every future address. + * - Calls `initializeAccount` on the new clone. Any revert bubbles and the whole + * deployment unwinds, so an uninitialised wallet can never exist on-chain. + * - Emits `WalletDeployed`. + * + * @param label Free-form label, emitted in the event and stored on the wallet (`AGW.label`). + * @return wallet Address of the newly deployed wallet. + */ + function deployWallet(string calldata label) external whenNotPaused returns (address wallet) { + address implementation = _walletImplementation; + if (implementation == address(0)) revert AGWFactoryErrors.ImplementationNotSet(); + + address owner = msg.sender; + wallet = _deploy(implementation, owner, _walletCount[owner], label); + } + + /** + * @notice Deploys wallet `intent.index` for `intent.owner`, on the owner's signature. + * + * @dev - The index is EXPLICIT and must equal the owner's current count, and `intent.wallet` must + * be the address this call deploys. So a signed intent is idempotent and unmovable: a + * replay fails on the index, and nobody can advance an owner's count without the owner's + * signature. + * - `msg.sender == intent.owner` needs no signature (the caller is the owner, exactly as in + * the single-argument form). Any other caller must be `intent.executor` (non-zero) and + * must carry the owner's signature, before the deadline. + * - Grant and exec fields of the intent are ignored here; the wallet checks those. + * - Every check runs before `_deploy`, which advances the count before its one external + * call — the same effect ordering the single-argument form relies on. + * + * @param intent The owner's intent. Only `owner`, `wallet`, `executor`, `index`, `deadline` and + * `signerChainId` are read here. + * @param sig The owner's signature over `intent`; ignored when the caller is the owner. + * @param label Free-form label, emitted, and stored on the wallet (`AGW.label`). Not signed. + * @return wallet The deployed wallet. + */ + function deployWalletWithSig(OwnerIntent calldata intent, bytes calldata sig, string calldata label) + external + whenNotPaused + returns (address wallet) + { + address implementation = _walletImplementation; + if (implementation == address(0)) revert AGWFactoryErrors.ImplementationNotSet(); + + address owner = intent.owner; + if (owner == address(0)) revert AGWFactoryErrors.ZeroAddress(); + + uint96 index = intent.index; + uint96 next = _walletCount[owner]; + if (index != next) revert AGWFactoryErrors.IndexMismatch(next, index); + + address predicted = _predict(implementation, owner, index); + if (intent.wallet != predicted) revert AGWFactoryErrors.IntentWalletMismatch(predicted, intent.wallet); + + if (msg.sender != owner) { + if (intent.executor == address(0) || msg.sender != intent.executor) { + revert AGWFactoryErrors.ExecutorMismatch(intent.executor, msg.sender); + } + if (block.timestamp > intent.deadline) revert AGWFactoryErrors.SignatureExpired(intent.deadline); + if (!OwnerAuthLib.isOwnerSig(owner, OwnerAuthLib.intentDigest(address(this), intent), sig)) { + revert AGWFactoryErrors.InvalidOwnerSignature(); + } + } + + wallet = _deploy(implementation, owner, index, label); + } + + /// @inheritdoc IAGWFactory + function domainSeparator(uint256 signerChainId) external view returns (bytes32) { + return OwnerAuthLib.domainSeparator(address(this), signerChainId); + } + + /** + * @dev The deployment tail shared by `deployWallet` and `deployWalletWithSig`. BYTE-FOR-BYTE the logic the + * single-argument form always had: count advance → salt → args → clone → record → + * initializeAccount → event. Every caller has run all of its checks before calling this. + * + * - The count advances and the record is written before the single external call, which is + * what makes a reentrant deploy unable to reuse an index. + * - Salt and args are frozen forever: counterfactual funding relies on them. + */ + function _deploy(address implementation, address owner, uint96 index, string calldata label) + internal + returns (address wallet) + { + _walletCount[owner] = index + 1; + + bytes32 salt = keccak256(abi.encode(owner, index)); + // 40 bytes: owner at 0-19, factory at 20-39. Frozen forever. + bytes memory args = abi.encodePacked(owner, address(this)); + + wallet = Clones.cloneDeterministicWithImmutableArgs(implementation, args, salt); + + _records[wallet] = WalletRecord({ owner: owner, index: index }); + + IAGWInit(wallet).initializeAccount(label); + + emit WalletDeployed(owner, index, wallet, label); + } + + /** + * @dev The address derivation, shared by `predictWallet` and `deployWalletWithSig`. + * Mirrors `_deploy`'s salt and args exactly; any divergence is a critical bug. + */ + function _predict(address implementation, address owner, uint96 index) internal view returns (address) { + bytes32 salt = keccak256(abi.encode(owner, index)); + bytes memory args = abi.encodePacked(owner, address(this)); + return Clones.predictDeterministicAddressWithImmutableArgs(implementation, args, salt, address(this)); + } + + /** + * @notice The address wallet `index` of `owner` has, or will have. + * + * @dev - Reverts with `ImplementationNotSet` if the implementation is unset, and with + * `IndexOutOfRange` if `index` is beyond the next deployable one. Funding an address + * further out than that would put money in a permanent hole. + * - Mirrors `deployWallet`'s salt and args derivation exactly. Any divergence between + * the two is a critical bug, because counterfactual funding relies on this answer. + * - `deployed` is derived from the sequential index rather than `extcodesize`, which + * would misreport during construction and cost more. + * + * @param owner Wallet owner to predict for. + * @param index Wallet index under that owner. + * @return wallet The deterministic address for that owner and index. + * @return deployed True if that wallet already exists. + */ + function predictWallet(address owner, uint256 index) external view returns (address wallet, bool deployed) { + address implementation = _walletImplementation; + if (implementation == address(0)) revert AGWFactoryErrors.ImplementationNotSet(); + + uint256 next = _walletCount[owner]; + if (index > next) revert AGWFactoryErrors.IndexOutOfRange(index, next); + + wallet = _predict(implementation, owner, uint96(index)); + deployed = index < next; + } + + /** + * @notice How many wallets `owner` has; also the index the next deploy will use. + * @dev Full enumeration is this call plus `predictWallet(owner, 0..count-1)`, which is why no + * per-owner wallet array is stored: it cannot be lost or desynced. + * @param owner Owner to count wallets for. + * @return The number of wallets deployed for that owner. + */ + function walletCount(address owner) external view returns (uint256) { + return _walletCount[owner]; + } + + /** + * @notice The owner of `wallet`, or address(0) if this factory did not deploy it. + * @param wallet Wallet to look up. + * @return The recorded owner, or the zero address. + */ + function ownerOf(address wallet) external view returns (address) { + return _records[wallet].owner; + } + + /** + * @notice True only for wallets this factory deployed. + * @param account Address to test. + * @return Whether this factory deployed it. + */ + function isWallet(address account) external view returns (bool) { + return _records[account].owner != address(0); + } + + /** + * @notice The wallet's index under its owner. + * @dev Reverts with `NotAWallet` rather than returning zero, because zero is a valid index. + * @param wallet Wallet to look up. + * @return Its index under its owner. + */ + function indexOf(address wallet) external view returns (uint256) { + WalletRecord memory record = _records[wallet]; + if (record.owner == address(0)) revert AGWFactoryErrors.NotAWallet(wallet); + return record.index; + } + + /** + * @notice The canonical wallet logic contract. + * @dev The only getter for it; the variable is `internal` precisely so no second, + * auto-generated getter exists. Exposed so the SDK can verify its local derivation + * mirror before showing a user an address to fund. + * @return The wallet implementation every clone delegates to. + */ + function walletImplementation() external view returns (address) { + return _walletImplementation; + } + + /** + * @notice Pauses wallet deployment. + * @dev - Gates `deployWallet` only. Views are never gated, and deployed wallets are + * unaffected, since the factory has no reach into them. + * - While paused, a user who funded a predicted address cannot deploy it. Availability + * only; funds are never lost. + */ + function pause() external onlyRole(PAUSER_ROLE) { + _pause(); + } + + /** + * @notice Resumes wallet deployment. + * @dev The role split is deliberate: pause is a cheap panic button, unpause a considered + * operational act. A pauser cannot unpause, and an operator cannot pause. + */ + function unpause() external onlyRole(OPERATOR_ROLE) { + _unpause(); + } + + /** + * @dev Authorises a UUPS upgrade of this logic contract. + * + * - Restricted to the default admin role; reverts with `ZeroAddress` on a zero + * implementation. + * - Every future logic upgrade must leave the salt formula, the immutable-args encoding, + * the value of `_walletImplementation` and the storage layout unchanged. Upgrades exist + * for logic bugs only; the address derivation is frozen forever. + * - New variables are appended after `_walletImplementation`; base contracts are never + * added, removed or reordered, and nothing may come to share that slot. + * - Not `view` although solc suggests it: the base declares `_authorizeUpgrade` non-view, + * and an override cannot add mutability restrictions the base does not have. + * + * @param newImplementation The logic contract being upgraded to. + */ + function _authorizeUpgrade(address newImplementation) internal override onlyRole(DEFAULT_ADMIN_ROLE) { + if (newImplementation == address(0)) revert AGWFactoryErrors.ZeroAddress(); + } +} diff --git a/plan/agw/research/deployment-review-2026-10-07-v5/source/src/interfaces/IAGW.sol b/plan/agw/research/deployment-review-2026-10-07-v5/source/src/interfaces/IAGW.sol new file mode 100644 index 00000000..cc532786 --- /dev/null +++ b/plan/agw/research/deployment-review-2026-10-07-v5/source/src/interfaces/IAGW.sol @@ -0,0 +1,213 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import { Session } from "smartsessions/DataTypes.sol"; + +import { OwnerIntent, RulesType, CheckpointKind } from "../libraries/Types.sol"; + +/** + * @title IAGW — the Agentic Wallet's external surface. + * @notice The wallet's complete external surface. `AGW is IAGW`, so the compiler rejects any function + * declared here that the contract does not implement with the identical signature — this file + * cannot drift from the contract. Errors live in `AGWErrors` (`libraries/Errors.sol`); types in + * `libraries/Types.sol`. + * + * @dev `rulesId` is the engine's `permissionId`: `rulesId == permissionId` for every rules set this + * wallet grants. SmartSession's own vocabulary (`Session`, `PermissionId`) is kept at the engine + * boundary. + * + * @dev The events are a CONSUMED WIRE FORMAT. Changing a name, a parameter type, or which parameters + * are indexed changes the topic hash and silently breaks every deployed indexer and monitoring + * rule reading the old one. Add events freely; alter an existing one only as a deliberate, + * announced break. + */ +interface IAGW { + // ═══════════════════════════════ AGW_1: EVENTS ═══════════════════════════════ + + /// @notice The one-shot factory initialisation completed; the wallet is live. + event AccountInitialized(address indexed owner, address indexed engine); + + /// @notice The owner executed directly, with no policy consulted. + /// @dev The calldata is hashed rather than logged: an owner batch can be large, and the + /// hash is what an observer needs to tie the event to the transaction it came from. + event OwnerExecuted(bytes32 indexed mode, bytes32 executionCalldataHash); + + /// @notice The owner executed through `executeWithSig`, authorised by a signed OwnerIntent. + /// @dev A separate event from `OwnerExecuted` so an indexer can tell a relayed owner action + /// from one the owner submitted directly. The lane position ties it to the intent. + event OwnerExecutedWithSig(bytes32 indexed mode, bytes32 executionCalldataHash, uint192 nonceKey, uint64 nonceSeq); + + /// @notice A validator module was installed. + event ModuleInstalled(uint256 moduleTypeId, address module); + + /// @notice A validator module was uninstalled. + event ModuleUninstalled(uint256 moduleTypeId, address module); + + /// @notice A module's uninstall callback reverted or exhausted its gas stipend. + /// @dev THE MODULE WAS STILL REMOVED. This is the audit trail for a module that tried to + /// resist its own removal, not a failure of the uninstall. + event UninstallCallbackFailed(address module); + + /// @notice A rules set was granted. + /// @dev `mode` and `chainHash` are DERIVED from the policy envelope's chain namespace, not + /// declared by anyone — nobody in this system states a rules set's kind. The hash is + /// INDEXED so an indexer can filter rules by chain without decoding; the string is carried + /// as data because the wallet already holds it in memory after the action-0 decode + /// (~200 gas) and it makes every explorer record human-readable. + event RulesGranted(bytes32 indexed rulesId, RulesType mode, bytes32 indexed chainHash, string chainNamespace); + + /// @notice A rules set was revoked. + event RulesRevoked(bytes32 indexed rulesId); + + /// @notice An agent request passed validation and was dispatched. + /// @dev Rules-level attribution on the Push side, without touching the gateway's own frozen + /// event. `agent` is the sender (always equal to the rules set's agent). `callsHash` is + /// `keccak256(executionCalldata)` — what ties this record to the exact call executed. + /// A deliberate wire-format break from the earlier `(rulesId, nonceKey, nonceSeq, opHash)` + /// shape; it ships with the new deployment. + event RulesActionAuthorized(bytes32 indexed rulesId, address indexed agent, bytes32 callsHash); + + /// @notice The owner side of this wallet changed. The wallet's checkpoint counter is now `seq`. + /// @dev Emitted once per owner-door call (before the call runs), once per grant and once per + /// revoked id. Never emitted by the agent door. On-chain consumers compare + /// `checkpointCount()` against a snapshot; `kind` and `ref` are for indexers — `ref` is + /// `keccak256(abi.encode(target, value, callData))` for `OWNER_ACTION` and the `rulesId` + /// for `RULES_GRANTED` / `RULES_REVOKED`. + event Checkpointed(uint64 indexed seq, CheckpointKind kind, bytes32 ref, uint64 blockNumber); + + /// @notice The owner renamed the wallet. Fired by `setLabel` only, with the label as passed. + /// @dev `""` means the label was reset to the default `AGW `. The label chosen at + /// deployment is carried by the factory's `WalletDeployed`, not by this event. + event LabelSet(string label); + + // ═══════════════════════════════ AGW_2: OWNER DOOR ═══════════════════════════════ + + /// @notice The owner door: executes a single call or a batch on the owner's behalf. No policy is + /// ever consulted. Owner only. + function execute(bytes32 mode, bytes calldata executionCalldata) external payable; + + /// @notice The owner door, authorised by a signed OwnerIntent instead of `msg.sender`. Relayable by + /// `intent.executor` only. + function executeWithSig( + bytes32 mode, + bytes calldata executionCalldata, + OwnerIntent calldata intent, + bytes calldata sig + ) external; + + /// @notice Sets the wallet's label; `""` resets it to the default `AGW `. Owner or the + /// wallet itself. At most `MAX_LABEL_BYTES` bytes. Cosmetic: writes no checkpoint. + function setLabel(string calldata label) external; + + // ═══════════════════════════════ AGW_3: AGENT DOOR ═══════════════════════════════ + + /// @notice The agent door. Callable only by the agent `rulesId` names — a Push address (an EOA, or + /// the UEA of an external key); every call is checked by the rules set's policy. + function executeAsAgent(bytes32 rulesId, bytes32 mode, bytes calldata executionCalldata) external; + + /// @notice The agent a rules set names on this wallet, or zero if it names none (unknown or + /// revoked id, non-canonical session validator, malformed config). + function agentOf(bytes32 rulesId) external view returns (address); + + // ═══════════════════════════════ AGW_4: RULES LIFECYCLE ═══════════════════════════════ + + /// @notice Grants one rules set to an agent. Owner or the wallet itself. + /// @return rulesId The engine's `permissionId` for the new rules set. + function grantRules(Session calldata session) external returns (bytes32 rulesId); + + /// @notice `grantRules`, authorised by the owner's signed OwnerIntent. + /// @return rulesId The engine's `permissionId` for the new rules set. + function grantRulesWithSig(Session calldata session, OwnerIntent calldata intent, bytes calldata sig) + external + returns (bytes32 rulesId); + + /// @notice Revokes one rules set. Owner or the wallet itself. + function revokeRules(bytes32 rulesId) external; + + /// @notice Revokes every rules set on this wallet. Owner or the wallet itself. + function revokeAllRules() external; + + /// @notice Factory-only, once: stores the deploy-time label (if any) and installs the session + /// engine as the account's sole validator. + function initializeAccount(string calldata label) external; + + /// @notice Installs a validator module. Owner only. + function installModule(uint256 moduleTypeId, address module, bytes calldata initData) external; + + /// @notice Uninstalls a validator module. Owner only; removal always proceeds. + function uninstallModule(uint256 moduleTypeId, address module, bytes calldata deInitData) external; + + // ═══════════════════════════════ AGW_5: VIEWS ═══════════════════════════════ + + /// @notice Whether `module` is installed under `moduleTypeId`. + function isModuleInstalled(uint256 moduleTypeId, address module, bytes calldata) external view returns (bool); + + /// @notice Whether this account supports an ERC-7579 module type. True only for validators. + function supportsModule(uint256 moduleTypeId) external pure returns (bool); + + /// @notice Whether this account supports an ERC-7579 execution mode. + function supportsExecutionMode(bytes32 mode) external pure returns (bool); + + /// @notice The wallet's owner, read from the clone's immutable args. + function owner() external view returns (address); + + /// @notice The wallet's label: the owner's, or `AGW ` if none is set (the index is the + /// factory's per-owner index, so an owner's wallets read `AGW 1`, `AGW 2`, …). + function label() external view returns (string memory); + + /// @notice The factory that deployed this wallet. + function factory() external view returns (address); + + /// @notice Next expected sequence number in an owner lane (`OWNER_LANE_FLAG` set), consumed by + /// `executeWithSig`. + function getNonce(uint192 nonceKey) external view returns (uint64); + + /// @notice The salt the next grant will use. + function grantNonce() external view returns (uint64); + + /// @notice Owner-side checkpoints so far. Any owner-door call, grant or revoke moves it; agent + /// actions never do. + function checkpointCount() external view returns (uint64); + + /// @notice `block.number` of the latest checkpoint, or zero if none. Consumers compare counts, not + /// blocks: several checkpoints can share a block. + function lastCheckpointBlock() external view returns (uint64); + + /// @notice The OwnerIntent EIP-712 domain separator for a signer on `signerChainId`. Identical to + /// the factory's: the factory is the verifying contract. + function domainSeparator(uint256 signerChainId) external view returns (bytes32); + + /// @notice The ERC-7579 account id, in vendor.account.semver form. + function accountId() external pure returns (string memory); + + /// @notice The permission engine this wallet installs as its default validator. + function SESSION_ENGINE() external view returns (address); + + /// @notice The canonical action policy (URP) every rules set on this wallet must name. + function RULES_POLICY() external view returns (address); + + /// @notice The canonical session validator every rules set on this wallet must name — the sender + /// validator that confirms the caller is the rules set's agent. + function SESSION_VALIDATOR() external view returns (address); + + /// @notice The Push-side gateway this wallet's agents send through. + function UNIVERSAL_GATEWAY_PC() external view returns (address); + + /// @notice ERC-165 support check: ERC-165 and the two token-receiver interfaces only. + function supportsInterface(bytes4 interfaceId) external pure returns (bool); + + /// @notice Always the ERC-1271 failure value: the wallet never signs as an ERC-1271 party. + function isValidSignature(bytes32, bytes calldata) external pure returns (bytes4); + + /// @notice Accepts ERC-721 transfers. + function onERC721Received(address, address, uint256, bytes calldata) external pure returns (bytes4); + + /// @notice Accepts ERC-1155 transfers. + function onERC1155Received(address, address, uint256, uint256, bytes calldata) external pure returns (bytes4); + + /// @notice Accepts batched ERC-1155 transfers. + function onERC1155BatchReceived(address, address, uint256[] calldata, uint256[] calldata, bytes calldata) + external + pure + returns (bytes4); +} diff --git a/plan/agw/research/deployment-review-2026-10-07-v5/source/src/libraries/Errors.sol b/plan/agw/research/deployment-review-2026-10-07-v5/source/src/libraries/Errors.sol new file mode 100644 index 00000000..c572e53c --- /dev/null +++ b/plan/agw/research/deployment-review-2026-10-07-v5/source/src/libraries/Errors.sol @@ -0,0 +1,407 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import { ConfigId } from "smartsessions/DataTypes.sol"; + +import { RulesType, VmFamily } from "./Types.sol"; + +/** + * @title Errors — every custom error in the AGW system, one library per contract. + * @notice `AGWErrors` (the wallet), `AGWFactoryErrors`, `UniversalRulesPolicyErrors` (URP) and + * `AgentValidatorErrors`. Moving an error into a library does not change its selector: a + * selector is `bytes4(keccak256(name ‖ argument types))`, independent of where the error + * is declared. + */ + +/// @title AGWErrors +/// @notice Custom errors of the AGW (wallet). +/// @dev Errors used by ExecutionLib live here too, so the libraries do not need an error home +/// of their own. +/// @dev THE ERRORS BELOW ARE NEVER TRUNCATED. They revert directly from the wallet, not through +/// the engine's 32-byte `PolicyCheckReverted` wrapper, so every argument survives intact. +/// URP's diagnostic-first argument ordering (which exists only because of that truncation) +/// deliberately does NOT apply here — do not reorder these for consistency with it. +library AGWErrors { + // ───────────────────── access control ───────────────────── + + error CallerIsNotOwner(); + error CallerIsNotFactory(); + + // ─────────────────── initialisation ─────────────────── + + error AlreadyInitialized(); + /// @dev Zero address, or a codeless target on install. Also raised by the wallet's constructor + /// when any of the four wiring addresses is zero. + error InvalidModuleAddress(); + + // ──────────────────────── label ──────────────────────── + + /// @dev `setLabel`, or a deploy with a label: the label is longer than `MAX_LABEL_BYTES` bytes. + error LabelTooLong(uint256 length); + + // ──────────────────── module manager ──────────────────── + + error ModuleAlreadyInstalled(address module); + error UnsupportedModuleType(uint256 moduleTypeId); + error ValidatorNotInstalled(address validator); + /// @dev The engine-scoped uninstall guard: uninstalling the permission engine while it still + /// holds live permissions would strand rows it then refuses to reinstall over. Revoke + /// everything first. + error EngineStillHoldsPermissions(); + + // ──────────────────── execution modes ──────────────────── + + /// @dev ONE error for every rejected mode — delegatecall, static, try-exec, and, on the agent + /// door specifically, batch. + error UnsupportedExecutionMode(); + + // ──────────────────── the agent door ──────────────────── + + /// @dev `executeAsAgent`: the caller is not the agent named by `rulesId` on this wallet — + /// including when the id is unknown, revoked, or names a session validator other than the + /// canonical one (all of which have no agent). Carries both values: this error is raised by + /// the wallet directly and is never truncated. + error CallerIsNotAgent(bytes32 rulesId, address caller); + /// @dev `executeWithSig`: the intent's sequence number is not the owner lane's next one. + error InvalidNonce(uint192 nonceKey, uint64 expected, uint64 provided); + error ValidationFailed(address authorizer); + error OutsideTimeWindow(uint48 validAfter, uint48 validUntil); + + // ──────────────────── rules set lifecycle ──────────────────── + + error UnknownPermission(bytes32 rulesId); + /// @dev Raised by grantRules's canonical-shape check — the granted session deviates from the + /// shape this system accepts for the DERIVED `RulesType`. Stays for the rules COMMON to + /// both types: user-op policies, ERC-7739, the paymaster permit, the session validator, and + /// the action-policy count. A target that is wrong FOR THE DERIVED TYPE is + /// `RulesTypeMismatch` instead — that distinction is the invariant, stated once. + error MalformedSessionShape(); + + // ──────────────────── native rules set shape (grantRules) ──────────────────── + + /// @dev Action count outside 1..MAX_NATIVE_ACTIONS. Zero is refused too: a rules set that + /// authorises nothing is a misconfiguration, not a valid ascetic grant. + /// + /// ZERO IS NOW CHECKED FOR BOTH MODES, BEFORE THE MODE IS KNOWN. The mode is derived from + /// action 0's envelope, so action 0 must exist before anything can be derived — with no + /// actions there is no envelope, no chain, and therefore no mode. A universal session with + /// zero actions consequently reports `TooManyActions(0)` rather than + /// `MalformedSessionShape`. + error TooManyActions(uint256 count); + + /// @dev The same (target, selector) pair twice in one rules set. Both would hash to one actionId, + /// so the second config would overwrite the first — or be refused — depending on engine + /// internals. Refused here instead, where the error can name the pair. + error DuplicateAction(address target, bytes4 selector); + + /// @dev A NATIVE action naming a target no rules set may ever reach: the zero address, the + /// engine's fallback flag, the wallet itself, the engine, URP, the validator, or the + /// factory. Self and engine are the severe ones — both would let an agent reach the + /// wallet's own lifecycle functions through `onlyOwnerOrSelf`. + error ForbiddenActionTarget(address target); + + /// @dev A NATIVE action naming one of the engine's fallback selectors. `0xFFFFFFFF` + /// (value-only) is permitted and is not one of these. + error ForbiddenActionSelector(bytes4 selector); + + /// @dev The type DERIVED from the envelope's chain does not match the action set: a gateway + /// target under the Push chain, or a non-gateway target under a foreign chain. Carries the + /// offending action's index and target, which is why it is distinct from + /// `MalformedSessionShape` — with up to eight actions, "something was wrong" is not a + /// usable diagnostic. + /// + /// IF YOU MEANT A NATIVE MANDATE AND SEE `UNIVERSAL` HERE, THE CHAIN STRING IS NOT + /// BYTE-EXACT `eip155:` OF THIS CHAIN. `"EIP155:42101"`, `"eip155:042101"` and a + /// leading space all hash to not-Push and therefore derive UNIVERSAL. That is deliberate: + /// the hash comparison is the whole rule, and a string parser would be a second rulebook + /// and a heuristic. The SDK prechecks this so a user sees the real cause. + /// + /// ORDER NOTE: under UNIVERSAL the `n != 1` shape rule runs BEFORE the target check, so a + /// malformed chain string on a multi-action session reports `MalformedSessionShape`. + error RulesTypeMismatch(RulesType derived, uint256 actionIndex, address target); + + /// @dev `grantRules`: action 0's policy envelope declares an empty chain string. The wallet + /// performs no other validation of it — a malformed non-empty string derives UNIVERSAL and + /// is then refused against the targets, or against the asset by URP at init. + error EmptyChain(); + + /// @dev `grantRules`: action `actionIndex` declares a different chain than action 0. A rules set + /// is one thing, on one chain, in one mode — which is what makes mixed rules sets impossible + /// by construction rather than by a rule. + error InconsistentChain(uint256 actionIndex); + + // ──────────────────── the agent door, dispatch ──────────────────── + + /// @dev The validated execution's target is the wallet itself or the engine. Fires in + /// `_gateAndDispatch`, AFTER validation — it is the last layer, and it holds even for a + /// session the owner enabled directly on the engine through the owner door, bypassing + /// `grantRules` entirely. Do not move this check before `_validate`. + error ForbiddenDispatchTarget(address target); + + // ─────────────────── the owner-intent doors ─────────────────── + // + // One shape per name, shared with AGWFactory and UniversalMarketplace, so a test encodes one + // selector whichever contract reverts first. + + /// @dev `intent.deadline` has passed. + error OwnerSigExpired(uint48 deadline); + /// @dev The signature is not the owner's over the intent. + error InvalidOwnerSignature(); + /// @dev `intent.wallet` is not this wallet. + error IntentWalletMismatch(address expected, address provided); + /// @dev Presented by someone other than `intent.executor`, or `intent.executor` is zero. + error ExecutorMismatch(address expected, address actual); + /// @dev `intent.sessionHash` is zero or is not the hash of the session being granted. + error IntentSessionMismatch(bytes32 actual); + /// @dev `intent.grantNonce` is not the wallet's current grant nonce. + error IntentGrantNonceMismatch(uint64 expected, uint64 provided); + /// @dev `intent.execCalldataHash` is zero or does not match, or `intent.mode` does not match. + error IntentExecMismatch(bytes32 actualCalldataHash); + /// @dev `executeWithSig` on a nonce key without `OWNER_LANE_FLAG`. + error OwnerLaneRequired(uint192 nonceKey); + + // ──────────────────── used by ExecutionLib ──────────────────── + + /// @dev ExecutionLib.decodeBatch — the only error any library in src/ actually references. + error MalformedBatchCalldata(); +} + +/// @title AGWFactoryErrors +/// @notice Custom errors of `AGWFactory`. +library AGWFactoryErrors { + /// @dev initialize: admin or implementation is zero. + error ZeroAddress(); + /// @dev deploy/predict called on an uninitialised factory. + error ImplementationNotSet(); + /// @dev indexOf on an address this factory did not deploy. + error NotAWallet(address account); + /// @dev predictWallet beyond the next deployable index. + error IndexOutOfRange(uint256 index, uint256 next); + /// @dev deployWalletWithSig: `intent.index` is not the owner's next index. + error IndexMismatch(uint96 expected, uint96 provided); + /// @dev deployWalletWithSig: `intent.wallet` is not the address this call would deploy. + error IntentWalletMismatch(address expected, address provided); + /// @dev deployWalletWithSig: signature path presented by someone other than `intent.executor`, + /// or `intent.executor` is zero. + error ExecutorMismatch(address expected, address actual); + /// @dev deployWalletWithSig: signature path after `intent.deadline`. + error SignatureExpired(uint48 deadline); + /// @dev deployWalletWithSig: the signature is not the owner's over the intent. + error InvalidOwnerSignature(); +} + +/// @title UniversalRulesPolicyErrors +/// @notice Custom errors of the Universal Rules Policy (URP). +/// @dev Revert data truncates to 32 bytes through the engine (`PolicyLib.sol:139-152`, +/// `_maxCopy: 32`, surfacing as `PolicyCheckReverted(bytes32)`). The 4-byte selector +/// survives; multi-argument custom errors do not round-trip to the caller. Errors below +/// still carry their arguments because URP is also called directly (owner path, executor +/// module, init) where they do survive. +library UniversalRulesPolicyErrors { + error ZeroAddress(); + error NotInitialized(ConfigId id, address account); + error AlreadyInitialized(ConfigId id); + /// @dev init: zero, or not in the future. + error InvalidExpiry(uint48 validUntil); + /// @dev init: zero expectedCEA. + error InvalidConfigField(); + /// @dev init, universal (EVM and SVM): the asset list is empty or longer than MAX_ASSETS. Empty is + /// refused because the token is what pins the destination chain: the gateway routes by it. + error AssetListOutOfRange(uint256 length); + /// @dev init, universal: the same token listed twice — the second entry's caps would be dead. + error DuplicateAsset(address token); + /// @dev init: 0 or > MAX_ALLOWED_CALLS. + error AllowListOutOfRange(uint256 length); + error RulesExpired(uint48 validUntil); + error InvalidTarget(address target); + /// @dev Gate 4a. Distinct from InvalidSelector: there is no selector to report, and a zero + /// sentinel would be indistinguishable from a genuine all-zero-selector payload. + error CalldataTooShort(uint256 length); + error InvalidSelector(bytes4 selector); + /// @dev Gate 4c — body below MIN_OUTBOUND_BODY_LEN. + error MalformedOutboundRequest(uint256 length); + /// @dev Gate 5: the request's token is not in the rules set's asset list. Checked on EVERY request, + /// zero amount included — the token decides the destination chain, so an unlisted token is a + /// chain the owner never approved. + error AssetNotAllowed(address token); + error AmountExceedsCap(uint256 amount, uint256 cap); + error TotalSpendCapExceeded(uint256 wouldBeTotal, uint256 cap); + error PCValueExceedsCap(uint256 value, uint256 cap); + error UncappedGasSwapRejected(); + error InvalidRevertRecipient(address expected, address actual); + error RecipientMustBeEmpty(); + error PayloadNotMulticall(); + error BatchSizeOutOfRange(uint256 count); + error ForbiddenInnerTarget(address target); + error CallNotAllowed(address target, bytes4 selector); + error BeneficiaryMismatch(address expected, address actual); + error InnerValueExceedsAllowance(uint256 index, uint256 value, uint256 maxValue); + error MalformedInnerCalldata(); + error SpentMismatch(uint256 expected, uint256 actual); + /// @dev Universal `assertSpent`: one token's counter differs from what the caller composed against. + error AssetSpentMismatch(address token, uint256 expected, uint256 actual); + /// @dev Universal `assertSpent`: the expected array does not have one entry per listed asset. + error SpentLengthMismatch(uint256 expected, uint256 actual); + error CallerIsNotUEModule(address caller); + error AlreadyCredited(bytes32 outboundTxId); + + // ───────────────────────── native mode errors ───────────────────────── + // + // DIAGNOSTIC VALUE FIRST. The engine truncates policy revert data to 32 bytes + // (`PolicyLib.sol:145`), so a caller sees the 4-byte selector plus only the first 28 bytes of + // the FIRST argument. Putting an index or a length first would surface 28 zero bytes and tell + // nobody anything; putting the offending value first surfaces the thing you debug with. + // This ordering applies to URP errors only — wallet errors are never truncated. + + // init + // + // NOT TRUNCATED. The 28-byte rule above applies to `checkAction`, which the engine wraps in + // `PolicyCheckReverted`. `initializeWithMultiplexer` is a plain high-level call from + // `ConfigLib.sol:98-101` inside `enableSessions`, so init reverts BUBBLE WITH FULL DATA. Tests + // assert these with a plain `vm.expectRevert(abi.encodeWithSelector(...))` carrying every + // argument — never `expectUrpGate`. + + /// @dev init: the envelope's `chain` string is empty. The only validation URP performs on the + /// string itself; a malformed non-empty string derives UNIVERSAL and is caught by the + /// asset check instead. + error EmptyChain(); + /// @dev init: the envelope's first word is not `ENVELOPE_VERSION`. Read before anything else is + /// decoded, so most malformed or pre-version blobs land here, named: a two-field + /// `(string, bytes)` envelope starts with its string offset and reports version 64. + error UnsupportedEnvelopeVersion(uint256 version); + + /// @dev init, universal: the asset reports a different source chain than the envelope declares. + /// `declared` first because it is the value the owner can act on. + error ChainMismatch(bytes32 declared, bytes32 assetChain); + + /// @dev init, universal: the asset has no code, is an EOA, or REVERTED when asked for + /// `SOURCE_CHAIN_NAMESPACE()`. + /// + /// AN ASSET THAT *ANSWERS* WITH A NON-STRING, OR WITH NOTHING, REVERTS UNNAMED INSTEAD — + /// the returndata fails ABI decoding in URP's own frame, which `catch` does not see. The + /// no-code and EOA cases are named only because an explicit `code.length` guard runs first; + /// since solc 0.8.10 the compiler omits the `extcodesize` check when return data is + /// expected, so `try/catch` alone would let both through as unnamed reverts. Measured. + error InvalidAsset(address asset); + /// @dev init: native config with a zero target. + error NativeTargetZero(); + /// @dev init AND gate N3. A native config may never name the gateway, and a native config may + /// never be reached by a gateway-targeted request. The mirror of universal gate 3. + error NativeTargetIsGateway(address target); + /// @dev init: a value-only config (`selector == 0xFFFFFFFF`) carrying pins. Refused rather than + /// left to fail closed at N7: such a config can NEVER authorise anything, so it is a + /// misconfiguration the owner believes they granted, not a valid ascetic config. + error ValueOnlyWithPins(); + /// @dev init: a value-only config carrying an amount rule. Same reasoning. + error ValueOnlyWithAmountRule(); + /// @dev init: pins.length > MAX_PINS. + error TooManyPins(uint256 count); + + // check + error TargetMismatch(address actual, address expected); + error SelectorMismatch(bytes4 actual, bytes4 expected); + /// @dev N5: a value-only action carrying 1..3 bytes of calldata. The engine buckets those under + /// `VALUE_SELECTOR` too; URP is where "value-only means empty calldata" becomes true. + error ValueOnlyCalldataNotEmpty(uint256 length); + error ValueExceedsCap(uint256 value, uint256 cap); + error TotalValueExceeded(uint256 newSpent, uint256 cap); + error CalldataTooShortForPin(uint256 actualLength, uint256 index, uint256 needed); + error ArgPinMismatch(bytes32 actual, uint256 index, bytes32 expected); + error CalldataTooShortForAmount(uint256 actualLength, uint256 needed); + error NativeAmountExceedsCap(uint256 amount, uint256 cap); + error TotalNativeAmountExceeded(uint256 newSpent, uint256 cap); + error CallLimitReached(uint32 callsUsed, uint32 maxCalls); + + // views / assertions + /// @dev A getter or assertion was called against the wrong rulebook — `getConfig` on a native + /// slot, or the five-argument `assertSpent` on a universal one. Carries the mode the config + /// ACTUALLY is. An EMPTY slot is not this error: it returns a zeroed struct exactly as + /// before, because an empty slot is a state while a wrong-mode read is a caller bug. + error WrongModeForCall(RulesType actual); + /// @dev A getter or assertion was called against the wrong VM family — `getConfig` on an SVM + /// slot, `getSvmConfig` on an EVM one. Carries the family the config ACTUALLY is. + error WrongVmForCall(VmFamily actual); + + // ───────────────────────── svm mode errors ───────────────────────── + + // init + /// @dev init: zero expectedCEA or gatewayProgram. + error InvalidSvmConfigField(); + /// @dev init: 0 or > MAX_ALLOWED_PROGRAMS. + error ProgramListOutOfRange(uint256 length); + error TooManySvmPins(uint256 count); + error TooManySvmDataPins(uint256 count); + error TooManyCeaAccounts(uint256 count); + /// @dev init: `discriminatorLen` is 0 without `dataless`, non-zero with it, or above 8. + error DiscriminatorLenOutOfRange(uint256 rule, uint8 len); + /// @dev init: two rules on one program that a single request could both match. First-match + /// must be EXACT, or the stricter rule is dead and its pins never run. + error AmbiguousRule(uint256 i, uint256 j); + /// @dev init: a program the rulebook forbids as a target can never be allow-listed either. + error ForbiddenProgramInAllowList(uint256 rule, bytes32 program); + error SvmPinRuleOutOfRange(uint256 pin, uint8 rule); + /// @dev init: account index at or beyond MAX_SVM_ACCOUNTS, or beyond the rule's `maxAccounts`. + error SvmPinIndexOutOfRange(uint256 pin, uint8 accountIndex); + /// @dev init: a rule's fixed account count exceeds the S13 bound, so no request could meet it. + error SvmMaxAccountsOutOfRange(uint256 rule, uint8 maxAccounts); + /// @dev init: two account pins name the same (rule, index). + error DuplicateSvmPin(uint256 first, uint256 second); + /// @dev init: a `ceaAccounts` entry is zero, repeated, or equal to an allow-listed program. + error InvalidCeaAccount(uint256 index); + /// @dev init: `ceaAccounts` does not contain `expectedCEA`, which would switch S18 off for the + /// one account that always holds value. + error CeaAccountsMissExpectedCEA(); + /// @dev init: a data pin with an impossible shape, or a vacuous / impossible comparison value + /// (a ceiling or floor outside the field's range, a zero ratio term, an EQ value with bytes + /// past `len`). See `SvmDataPin` and `URP._dataPinValueValid`. + error SvmDataPinInvalid(uint256 pin); + /// @dev init: every rule must own at least one account pin. HYGIENE, not a guarantee: one + /// authority pin always passes. Which positions must be pinned is the compiler's job. + error RuleWithoutPin(uint256 rule); + + // check + /// @dev S6b. Solana amounts are u64; the node would truncate. Defence in depth. + error AmountExceedsU64(uint256 amount); + /// @dev S11. The recipient must be a 32-byte, non-zero pubkey — the target program. + error RecipientNotPubkey(uint256 length); + /// @dev S12. Execute-only: an empty payload is a funds-only withdraw, never admitted (parity + /// with EVM gate 12). + error SvmPayloadEmpty(); + /// @dev S12. 1 = short header, 2 = short account list, 3 = short ix_data, 4 = trailing bytes. + /// The grammar is the node's `decodePayload`, byte for byte. + error MalformedSvmPayload(uint8 code); + /// @dev S13. Only instruction_id 2 (execute) is admitted. + error SvmInstructionNotExecute(uint8 instructionId); + error SvmAccountsOutOfRange(uint256 count); + error SvmIxDataTooLong(uint256 length); + /// @dev S14. The node signs the payload's target but finalises with the recipient; they must + /// agree or the TSS check fails on Solana at the owner's expense. + error RecipientTargetMismatch(bytes32 recipient, bytes32 target); + /// @dev S15. System, SPL Token, Token-2022, Stake, BPF Loader Upgradeable, Address Lookup Table, + /// the gateway program and the CEA itself. + error ForbiddenTargetProgram(bytes32 program); + /// @dev S16. No rule matches (program, discriminator). Carries the first 8 bytes of ix_data. + error ProgramNotAllowed(bytes32 program, bytes8 discriminator); + /// @dev S16. The rule fixes the account count and the request's differs. + error SvmAccountCountMismatch(uint256 count, uint8 expected); + /// @dev S17. A pinned index does not exist in the request. + error SvmAccountCountBelowPin(uint256 pin, uint256 count, uint8 needed); + error SvmAccountPinMismatch(uint256 pin, uint8 accountIndex, bytes32 expected, bytes32 actual); + /// @dev S17. ix_data is too short for the pin's field. + error SvmDataTooShortForPin(uint256 pin, uint256 ixLen); + error SvmDataPinMismatch(uint256 pin, bytes32 expected, bytes32 actual); + error SvmDataFloorNotMet(uint256 pin, uint256 actual, uint256 floor); + error SvmDataCeilingExceeded(uint256 pin, uint256 actual, uint256 ceiling); + error SvmDataRatioNotMet(uint256 pin, uint256 a, uint256 b, uint64 num, uint64 den); + /// @dev S18. A CEA-controlled account appears at a position the matched rule does not pin to it. + error CeaAccountAtUnpinnedIndex(uint256 accountIndex, bytes32 account); +} + +/// @title AgentValidatorErrors +/// @notice Custom errors of the session validator. +library AgentValidatorErrors { + /// @dev The stored config is not exactly `abi.encode(address agent)` with a non-zero agent. + /// Unreachable through the wallet's grant path, which runs `validateConfig` first; reachable + /// only for a session the owner enabled on the engine directly. + error MalformedConfig(); +} diff --git a/plan/agw/research/deployment-review-2026-10-07-v5/source/src/libraries/Types.sol b/plan/agw/research/deployment-review-2026-10-07-v5/source/src/libraries/Types.sol new file mode 100644 index 00000000..494a0dab --- /dev/null +++ b/plan/agw/research/deployment-review-2026-10-07-v5/source/src/libraries/Types.sol @@ -0,0 +1,550 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +/** + * @notice Mirror of push-chain-gateway .../libraries/TypesUGPC.sol + * @dev MUST match field-for-field and in order. Verified against + * contracts/evm-gateway/src/libraries/TypesUGPC.sol. + */ +struct UniversalOutboundTxRequest { + bytes recipient; // raw destination address on source chain (bytes for SVM compat) + address token; // PRC20 token address on Push Chain + uint256 amount; // amount to withdraw (burn on Push, unlock at origin) + uint256 gasLimit; // gas limit for fee quote; 0 = per-chain default + uint256 gasPrice; // gas price override; 0 = per-chain default + uint256 maxPCForGas; // max native PC for gas swap; 0 = no cap + bytes payload; // ABI-encoded calldata to execute on origin chain + address revertRecipient; // address to receive funds in case of revert +} + +/** + * @notice Mirror of push-chain-core .../libraries/Types.sol + * @dev Batch call entry for multicall execution. + */ +struct Multicall { + address to; + uint256 value; + bytes data; +} + +/// @dev bytes4(keccak256("UEA_MULTICALL")) — magic prefix for multicall payloads. +bytes4 constant MULTICALL_SELECTOR = bytes4(keccak256("UEA_MULTICALL")); + +/** + * @dev The two kinds of rules set. Declared by the owner at grant, asserted by the wallet, stored by + * URP as the config's mode. + * + * DECLARED ONCE, HERE, AND IMPORTED BY BOTH THE WALLET AND `IUniversalRulesPolicy`. Two enums with identical + * values that must always agree is the duplication this file exists to prevent — see the note + * on `SEND_OUTBOUND_SELECTOR` below. The wallet asserts the declared type against the action + * set at grant; URP stores it and branches on it at validation. They must be the same type. + * + * `UNIVERSAL` is the zero value, so an uninitialised slot reads as `UNIVERSAL`. That is why + * URP's `ModeSlot` carries an explicit `initialized` flag and never infers emptiness from the + * mode alone. + */ +enum RulesType { + UNIVERSAL, + NATIVE +} + +/** + * @dev Which destination VM a UNIVERSAL rules set targets. Derived by URP from the envelope's chain + * namespace prefix (`eip155:` / `solana:`) at config init; the wallet never reads it, because + * its grant rules are identical for every non-Push chain. + * + * `EVM` MUST STAY THE ZERO VALUE. URP's `ModeSlot` entries written before this enum existed + * read 0 in the byte that now holds it, and every one of them is an EVM rules set. + */ +enum VmFamily { + EVM, + SVM +} + +/** + * @dev Mirrors of engine constants that are not importable — `IdLib.VALUE_SELECTOR` is `internal` + * to a library, and the fallback flags are file-level constants in the vendored fork. + * + * MIRRORED, NOT GUESSED: each is pinned by a constant-mirror test against the upstream value, + * exactly as `MULTICALL_SELECTOR` is. If the fork moves, the test fails rather than the wallet + * silently permitting an action it means to forbid. + */ + +/// @dev `IdLib.VALUE_SELECTOR` — the action selector the engine assigns when calldata is under four +/// bytes. A native action carrying this selector is a value-only transfer with EMPTY calldata; +/// a no-argument function like `unstake()` still carries its own four bytes and is a normal +/// selector action. +bytes4 constant VALUE_SELECTOR = 0xFFFFFFFF; + +/// @dev `DataTypes.FALLBACK_TARGET_FLAG`. Refused by name at grant time: the engine does NOT reject +/// it at enable time (only at check time, `PolicyLib.sol:200`), so the wallet is the only +/// grant-time layer for this value. +address constant ENGINE_FALLBACK_TARGET = address(1); + +/// @dev `DataTypes.FALLBACK_TARGET_SELECTOR_FLAG` — the wildcard action's selector. +bytes4 constant ENGINE_FALLBACK_SELECTOR = 0x00000001; + +/// @dev `DataTypes.FALLBACK_TARGET_SELECTOR_FLAG_PERMITTED_TO_CALL_SMARTSESSION` — the sentinel that +/// routes a request to the engine itself. An agent reaching this could configure sessions. +bytes4 constant ENGINE_FALLBACK_SELECTOR_SMARTSESSION = 0x00000002; + +/** + * @dev The gateway's outbound entry point — the ONE selector an agent rules set may ever name. + * + * DECLARED HERE, BESIDE THE STRUCT IT TAKES, AND NOWHERE ELSE. The wallet's grant-shape check + * and the policy's request-decode gate must agree on this value exactly: the wallet refuses to + * grant a rules set naming any other selector, and the policy refuses to validate a request + * carrying any other selector. Two independently hand-typed copies of the same signature + * string is the kind of duplication that stays correct only until one of them is edited, and + * the failure would be silent in the safe direction for one contract and open in the other. + * + * The signature string spells out `UniversalOutboundTxRequest` field-for-field because that is + * how Solidity encodes a struct parameter into a selector. It is therefore load-bearing on the + * mirror above: reorder or retype a field there without editing this string and the selector + * silently stops matching the deployed gateway. + */ +bytes4 constant SEND_OUTBOUND_SELECTOR = + bytes4(keccak256("sendUniversalTxOutbound((bytes,address,uint256,uint256,uint256,uint256,bytes,address))")); + +/** + * @dev The owner's signed authorisation for up to three actions: deploy, grant, execute. + * + * SIGNED ONCE under the FACTORY's EIP-712 domain and verified by the factory and by every wallet + * it deploys. Each door checks only its own fields and advances its own nonce, so one signature + * serves each door exactly once. + * + * - Presentable ONLY by `executor`: every door, on its signature path, requires + * `intent.executor != address(0) && msg.sender == intent.executor`. Without that, anyone who saw + * the intent in calldata could drive the doors out of order and burn the owner's signature. + * - A zero `sessionHash` / `execCalldataHash` means "not authorised for that action". + * - EVERY FIELD IS IN THE TYPEHASH, IN DECLARATION ORDER. A field outside the typed data would + * guarantee the SDK and the contract disagree about what was signed. + * + * DECLARED HERE, beside the other values the factory and the wallet must agree on exactly. + */ +struct OwnerIntent { + address owner; // the wallet owner (UEA or EOA) + address wallet; // the wallet this intent is for — the predicted address if not yet deployed + address executor; // the ONLY msg.sender allowed to present this intent to a door + uint96 index; // wallet index under owner; deployWallet requires index == walletCount(owner) + bytes32 sessionHash; // keccak256(abi.encode(Session)) for grantRulesWithSig; 0 = no grant + bytes32 mode; // ERC-7579 mode word for executeWithSig + bytes32 execCalldataHash; // keccak256(executionCalldata) for executeWithSig; 0 = no exec + uint192 nonceKey; // owner lane for executeWithSig; must have OWNER_LANE_FLAG set + uint64 nonceSeq; // expected _nonces[nonceKey] at execution + uint64 grantNonce; // expected _grantNonce at grant + uint48 deadline; // unix seconds; all three doors reject after this + uint256 signerChainId; // EIP-712 domain.chainId the signer's wallet accepts — the owner's HOME chain +} + +/// @dev The struct string must list every OwnerIntent field, in declaration order, with its exact type. +bytes32 constant OWNER_INTENT_TYPEHASH = keccak256( + "OwnerIntent(address owner,address wallet,address executor,uint96 index,bytes32 sessionHash," + "bytes32 mode,bytes32 execCalldataHash,uint192 nonceKey,uint64 nonceSeq,uint64 grantNonce," + "uint48 deadline,uint256 signerChainId)" +); + +/** + * @dev The intent's EIP-712 domain. Five fields: + * - `chainId` is the SIGNER's home chain (`intent.signerChainId`), not Push: MetaMask refuses to + * sign typed data whose `domain.chainId` differs from the active chain. + * - `salt` is `bytes32(block.chainid)` — the Push chain id — which is what isolates one Push chain + * from another. + * - `verifyingContract` is the FACTORY PROXY for both the factory and every wallet; the wallet + * reads it from its immutable args. The `wallet` field stops cross-wallet replay. + */ +bytes32 constant OWNER_INTENT_DOMAIN_TYPEHASH = + keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract,bytes32 salt)"); +bytes32 constant OWNER_INTENT_DOMAIN_NAME_HASH = keccak256("AGWFactory"); +bytes32 constant OWNER_INTENT_DOMAIN_VERSION_HASH = keccak256("1"); + +/** + * @dev Top bit of a uint192 nonce key. `executeWithSig` requires it SET: only owner lanes are ever + * consumed, and keys with it CLEAR are never touched. The agent door uses no nonce lanes at all — + * its replay protection is the sender's own transaction nonce. + */ +uint192 constant OWNER_LANE_FLAG = uint192(1) << 191; + +/** + * @dev The kinds of owner-side change the wallet records as a checkpoint (`IAGW.Checkpointed`). + * + * ORDINALS ARE A FROZEN WIRE FORMAT: indexers and evaluators read them. Append only — never + * reorder, never remove. A future kind (e.g. a binder) is appended as the next ordinal. + */ +enum CheckpointKind { + OWNER_ACTION, + RULES_GRANTED, + RULES_REVOKED +} + +// ─────────────────────── policy types (moved from IURP) ─────────────────────── + +/** + * @dev Maximum pinned arguments per native action. Bounds the N7 loop. + * + * FILE-LEVEL, NOT INSIDE THE INTERFACE — Solidity forbids variables in interfaces (solc 8274), + * and unlike `MAX_ACTIONS_PER_REQUEST` / `MAX_ALLOWED_CALLS` (which are `internal` to URP + * because they bound loops nobody off-chain constructs) this one bounds an array THE SDK + * BUILDS, so an encoder has to be able to see it. Parallel to `MULTICALL_SELECTOR` in + * `Types.sol`. + */ +uint256 constant MAX_PINS = 8; + +/** + * @dev Maximum tokens one UNIVERSAL rules set may list (EVM and SVM alike). Bounds the init duplicate + * check and the gate-5 scan. + * + * FILE-LEVEL FOR THE SAME REASON AS `MAX_PINS`: it bounds an array THE SDK BUILDS. + */ +uint256 constant MAX_ASSETS = 8; + +/** + * @dev Longest wallet label, in BYTES (not characters). `AGW.setLabel` and the deploy path refuse a + * longer one, so every `label()` read is bounded. FILE-LEVEL so the SDK can see it. + */ +uint256 constant MAX_LABEL_BYTES = 64; + +/** + * @dev The rules-envelope version URP accepts. Every action policy's `initData` is + * `abi.encode(uint16 version, string chainNamespace, bytes body)`, the same shape in every mode. + * URP reads the version from the FIRST WORD before decoding anything else and refuses any other + * value, so a body layout can change later under a new version without being misread. + * FILE-LEVEL so the SDK, which writes the envelope, can read it. + */ +uint16 constant ENVELOPE_VERSION = 1; + +/** + * @notice WIRE TYPE — one token a UNIVERSAL rules set may move, with its own caps. + * @param token The PRC20 ON PUSH (e.g. USDC.eth), never the destination chain's address: the + * gateway request carries the PRC20 and routes by it. Its `SOURCE_CHAIN_NAMESPACE()` + * must equal the rules set's chain, checked at init for every entry. + * @param maxPerCall Per-request ceiling, PRC20 base units. ZERO IS LEGAL and means "this token may + * route a request but never moves": the move-nothing rules set is one entry with a + * zero `maxPerCall`, never an empty list (an empty list would pin no chain). + * @param maxTotal Lifetime ceiling on the amount SENT OUT in this token. `type(uint256).max` = + * unlimited, with no special branch; zero means nothing may move. + */ +struct AssetCap { + address token; + uint256 maxPerCall; + uint256 maxTotal; +} + +/** + * @notice STORAGE TYPE — an `AssetCap` plus the counter URP owns. Never a wire type: a caller-set + * counter would be a granted head start on the cap. + * @param spent Lifetime amount sent out in this token, recorded before dispatch. Money coming back + * to the wallet never lowers it (URP cannot see inflows, and could not tell an agent's + * return from the owner's top-up); only `creditRevert` does. + */ +struct AssetCapState { + address token; + uint256 maxPerCall; + uint256 maxTotal; + uint256 spent; +} + +/// @param target far-chain contract +/// @param selector far-chain function +/// @param beneficiaryOffset byte offset of the beneficiary word in the inner calldata +/// @param hasBeneficiary false for calls with no beneficiary argument +/// @param maxValue per-entry native ceiling, DESTINATION-chain units (0 = non-payable) +struct AllowedCall { + address target; + bytes4 selector; + uint16 beneficiaryOffset; + bool hasBeneficiary; + uint256 maxValue; +} + +/** + * @notice WIRE TYPE — what a UNIVERSAL envelope's body encodes. Not a storage type. + * + * @dev ABSENT BY DESIGN, and each absence is the point: `initialized` (URP sets it), `spent` + * (URP owns it), and the chain (the envelope carries it, exactly once). The SDK used to + * type all three and URP overwrote them — a field whose only legal value is a + * placeholder is a field the caller fills in believing it matters. + * + * Mapped field-by-field onto the storage `Config` by `_store`. The storage struct's + * layout never moves; this one is free to change with the wire format. + */ +struct UniversalTerms { + uint48 validUntil; + address expectedCEA; + AssetCap[] assets; + uint256 maxGasPerCall; + AllowedCall[] allowedCalls; +} + +/// @param initialized set once, at initialisation; re-initialisation is refused +/// @param validUntil non-zero always (enforced at init); "never" = type(uint48).max, explicit +/// @param expectedCEA the wallet's destination account, committed at grant. The rules set's +/// chain is not stored here: it lives on `getMode(id, account).chainHash` +/// @param maxGasPerCall Push-native per-call ceiling on `msg.value`, in PC wei. It pays the protocol +/// fee AND the gas swap, despite the name (renamed from `maxPCPerCall` to +/// match the SDK) +/// @param assets 1..MAX_ASSETS permitted PRC20s, each with its own caps and its own `spent` +struct Config { + bool initialized; + uint48 validUntil; + address expectedCEA; + uint256 maxGasPerCall; + AssetCapState[] assets; + AllowedCall[] allowedCalls; +} + +// ───────────────────────── native mode structs ───────────────────────── + +/** + * @dev Per-config mode record. THE MODE DISCRIMINATOR, and the reason it is a struct rather than + * a bare enum: `RulesType.UNIVERSAL` is the zero value, so an empty storage slot reads as + * `UNIVERSAL` and could not be told apart from a real universal rules set. `initialized` is + * authoritative; `mode` is MEANINGLESS when it is false. + * @param initialized true once any rulebook has been written for this config + * @param mode which rulebook; only meaningful when `initialized` + * @param vm which destination VM a UNIVERSAL config targets; meaningless for NATIVE + */ +struct ModeSlot { + bool initialized; + RulesType mode; + /// @dev ADDED for the SVM rulebook, PLACED HERE ON PURPOSE. Declared between `mode` and + /// `chainHash` it packs into slot 0 at byte 2 — a byte no earlier implementation ever + /// wrote, so every existing entry reads 0 = `EVM`, which is what every existing entry + /// is. No existing member moves: `chainHash` stays at slot 1. Appending it after + /// `chainHash` would be equally safe and cost one more slot per grant; the layout test + /// pins label, slot, offset and type of all four members either way. + VmFamily vm; + /// @dev keccak256(bytes(chain)) as declared in the policy envelope. THE single chain record + /// for BOTH modes — universal stores the destination chain, native stores this chain's + /// own hash. Written at init, never zero on an initialised entry. + bytes32 chainHash; +} + +/** + * @dev One pinned argument of a native call. + * @param offset ABSOLUTE byte offset from byte 0 of the calldata, SELECTOR INCLUDED — so 4 is + * the first argument word, 36 the second, and so on. + * @param expected The full 32-byte word that must appear there. An address argument is + * left-padded by the ABI, so a non-zero high half is a MISMATCH, deliberately: + * full-word equality also proves the padding is clean, which masking would + * silently accept. + */ +struct ArgPin { + uint16 offset; + bytes32 expected; +} + +/** + * @dev Optional metering of a `uint256` argument read out of native calldata. + * @param enabled Whether to meter at all. A BOOL rather than "offset 0 means off", because + * offset 0 is a legal position — it just points inside the selector. + * @param offset Absolute byte offset of the amount word, selector included. + * @param maxPerCall Per-call ceiling. Zero is legal (a call that must carry amount zero). + * @param maxTotal Lifetime ceiling; `type(uint256).max` = unlimited, with no special branch. + */ +struct AmountRule { + bool enabled; + uint16 offset; + uint256 maxPerCall; + uint256 maxTotal; +} + +/** + * @dev The native rulebook for ONE (target, selector) action. One of these per action, so a + * rules set with eight actions holds eight of them under eight distinct config ids. + * + * @param initialized set once; re-initialisation is refused, as in universal mode + * @param validUntil non-zero and future (enforced at init); "never" = type(uint48).max + * @param target defensive copy of the action target, asserted at N4 + * @param selector defensive copy, asserted at N5. `0xFFFFFFFF` = value-only, which means + * EMPTY calldata — a no-argument function still carries four bytes + * @param maxValuePerCall Push-native per-call ceiling + * @param maxValueTotal Push-native lifetime ceiling; type(uint256).max = unlimited + * @param valueSpent lifetime native value metered, written effects-last + * @param amount optional calldata-amount metering + * @param amountSpent lifetime metered amount, written effects-last + * @param maxCalls 0 = unlimited; otherwise the lifetime call ceiling + * @param callsUsed calls consumed. ALWAYS increments on a successful check, including a + * zero-value zero-amount call — a call is a use, and the alternative + * makes `maxCalls` bypassable + * @param pins 0..MAX_PINS pinned argument words + */ +struct NativeConfig { + bool initialized; + uint48 validUntil; + address target; + bytes4 selector; + uint256 maxValuePerCall; + uint256 maxValueTotal; + uint256 valueSpent; + AmountRule amount; + uint256 amountSpent; + uint32 maxCalls; + uint32 callsUsed; + ArgPin[] pins; +} + +/** + * @notice WIRE TYPE — what a NATIVE envelope's body encodes. Not a storage type. + * + * @dev ABSENT BY DESIGN: `initialized`, `valueSpent`, `amountSpent` and `callsUsed` are all + * URP's own counters, zeroed at init. The SDK had to type four zeroes it did not own. + * + * SPLIT EVEN THOUGH ONLY THE UNIVERSAL SIDE FORCES IT. The SDK builds both; one struct + * with dead input fields sitting beside one without is precisely the inconsistency that + * let a since-removed chain field acquire four different conventions in one repository. + */ +struct NativeTerms { + uint48 validUntil; + address target; + bytes4 selector; + uint256 maxValuePerCall; + uint256 maxValueTotal; + AmountRule amount; + uint32 maxCalls; + ArgPin[] pins; +} + +// ───────────────────────── svm mode structs ───────────────────────── +// +// The third rulebook: a UNIVERSAL rules set whose destination is a `solana:*` chain. On Solana an +// outbound is ONE cross-program invocation — a target program, an ordered account list, and an +// instruction byte string — signed by the wallet's CEA (a PDA), not an EVM multicall. Every +// EVM-shaped gate (multicall walk, `address` target, `bytes4` selector, beneficiary word, per-entry +// value) is replaced by the shapes below. See `URP._checkSvm` for the gate list. + +/** + * @dev One allow-listed (program, instruction) pair. + * @param program Target program id, 32 bytes. + * @param discriminator Left-aligned instruction tag; only the first `discriminatorLen` bytes + * are compared. 8 for Anchor (`sha256("global:")[..8]`), 1 for + * SPL-style instruction indexes. + * @param discriminatorLen 1..8, or 0 iff `dataless`. + * @param dataless The instruction carries NO data. The only way to get a length-0 tag, + * and it forces `ix_data` to be EMPTY at check time — so a rule can never + * match an instruction its pins were not written for. + * @param maxAccounts 0 = unbounded; otherwise the request's account count must EQUAL it. + * Set to the IDL count for fixed-layout instructions so nothing can be + * appended behind the pinned positions. + */ +struct AllowedProgram { + bytes32 program; + bytes8 discriminator; + uint8 discriminatorLen; + bool dataless; + uint8 maxAccounts; +} + +/** + * @dev `accounts[accountIndex]` of a request matching rule `ruleIndex` must equal `expected`. + * The SVM counterpart of the EVM beneficiary pin: programs read accounts by POSITION, so a + * value-carrying position is pinned to an owner-committed key (the CEA, or one of its ATAs). + */ +struct SvmAccountPin { + uint8 ruleIndex; + uint8 accountIndex; + bytes32 expected; +} + +/// @dev How an `SvmDataPin` compares. Integers are LITTLE-ENDIAN (Borsh), `len` bytes wide. +enum SvmDataPinMode { + EQ, + GTE_LE, + LTE_LE, + RATIO_GTE_LE +} + +/** + * @dev A constraint on the `ix_data` of a request matching rule `ruleIndex`. + * - EQ `ix_data[off : off+len] == expected[0 : len]`, `len` 1..32, raw bytes, + * LEFT-ALIGNED: bytes of `expected` past `len` must be zero. + * - GTE_LE `uintLE(ix_data[off : off+len]) >= uint256(expected)`, `len` 1..8, + * RIGHT-ALIGNED integer: `expected` must fit in `len` bytes. + * - LTE_LE `uintLE(ix_data[off : off+len]) <= uint256(expected)`, same encoding. + * - RATIO_GTE_LE `uintLE(A) * den >= uintLE(B) * num`, A at `offset`, B at `offsetB`, both + * `len` bytes and both addressed with the same `fromEnd`; `expected` unused; + * `num` and `den` both non-zero. + * This is the min-out floor RELATIVE to the input amount — a static floor on + * the output alone is bypassed by an input equal to the whole balance. + * - fromEnd `offset` counts back from the END of `ix_data` to the field's START. + * Borsh serialises vectors before scalars, so trailing scalar arguments have + * stable from-end offsets and unstable from-start ones. Requires + * `offset >= len`. + */ +struct SvmDataPin { + uint8 ruleIndex; + bool fromEnd; + uint16 offset; + uint16 offsetB; + uint8 len; + SvmDataPinMode mode; + bytes32 expected; + uint64 num; + uint64 den; +} + +/** + * @notice WIRE TYPE — what a `solana:*` UNIVERSAL envelope's body encodes. Not a storage type. + * + * @dev ABSENT BY DESIGN, as in `UniversalTerms`: `initialized` and `spent` are URP's. + * + * @param validUntil non-zero, in the future (enforced at init); "never" = type(uint48).max + * @param expectedCEA the wallet's CEA on the destination: `PDA(["push_identity", wallet], + * gatewayProgram)`. Owner-committed — Solidity cannot derive a PDA. + * @param gatewayProgram the Push gateway program on the declared cluster. Owner-committed; the + * SDK sources it from the chain registry. Forbidden as a target: that + * route only returns the permitted asset to the owner's wallet, at the + * owner's rate-limit and gas cost. + * @param assets 1..MAX_ASSETS permitted PRC20s with their caps, exactly as `UniversalTerms`; + * amounts are PRC20 base units (lamports / SPL base units), and a request's + * amount must also fit Solana's u64 (S6b) + * @param maxGasPerCall Push-native per-call ceiling (protocol fee + gas swap budget), PC wei + * @param ceaAccounts every CEA-controlled account that HOLDS VALUE: the CEA, its ATA for EACH + * listed asset, its ATAs for allowed outputs. At most MAX_CEA_ACCOUNTS (16, + * the CEA included: room for all 8 assets plus 7 outputs). Each may appear in + * a request ONLY at a position the matched rule pins to it; a listed account + * no rule pins can never be passed at all. Unlisted accounts are not + * protected — the list is the owner's statement of what is worth taking. + * URP CANNOT CHECK that each listed asset's ATA is here (it cannot derive a + * Solana token account, and does not know a PRC20's mint): listing them is + * the SDK's job. Must contain `expectedCEA`; no zero, duplicate, or program + * entries. + * @param programs the allow-list; first match wins, made exact by the init ambiguity rule. + * ONE RULE PER (program, instruction), so ONE PINNED KEY PER POSITION: if a + * swap rule pins its input to the USDC account, USDT can never be that + * instruction's input. Using several listed tokens through one instruction + * means leaving the input unpinned and those token accounts unlisted, so + * only the output and price pins protect them. Multi-asset on Solana is + * strongest when different tokens are used by different instructions. + * @param pins account pins, each naming its rule + * @param dataPins `ix_data` pins, each naming its rule + */ +struct SvmTerms { + uint48 validUntil; + bytes32 expectedCEA; + bytes32 gatewayProgram; + AssetCap[] assets; + uint256 maxGasPerCall; + bytes32[] ceaAccounts; + AllowedProgram[] programs; + SvmAccountPin[] pins; + SvmDataPin[] dataPins; +} + +/** + * @dev The SVM rulebook — STORAGE type, lives inside `_svm`. + * @param initialized set once; re-initialisation is refused + * @param assets per-token caps and per-token `spent`, exactly as `Config.assets` + */ +struct SvmConfig { + bool initialized; + uint48 validUntil; + bytes32 expectedCEA; + bytes32 gatewayProgram; + uint256 maxGasPerCall; + AssetCapState[] assets; + bytes32[] ceaAccounts; + AllowedProgram[] programs; + SvmAccountPin[] pins; + SvmDataPin[] dataPins; +} diff --git a/plan/agw/research/deployment-review-2026-10-07-v5/source/test/unit/29_walletLabel.t.sol b/plan/agw/research/deployment-review-2026-10-07-v5/source/test/unit/29_walletLabel.t.sol new file mode 100644 index 00000000..99dc886a --- /dev/null +++ b/plan/agw/research/deployment-review-2026-10-07-v5/source/test/unit/29_walletLabel.t.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import { BaseTest } from "../Base.t.sol"; +import { PermissivePolicy } from "./4_agentDoor.t.sol"; +import { AGW } from "../../src/AGW.sol"; +import { IAGW } from "../../src/interfaces/IAGW.sol"; +import { IAGWFactory } from "../../src/interfaces/IAGWFactory.sol"; +import { AGWErrors } from "../../src/libraries/Errors.sol"; +import { ModeLib, ModeCode } from "../../src/libraries/ModeLib.sol"; +import { ExecutionLib, Execution } from "../../src/libraries/ExecutionLib.sol"; +import { OwnerIntent, MAX_LABEL_BYTES } from "../../src/libraries/Types.sol"; +import { Session, PermissionId } from "smartsessions/DataTypes.sol"; + +/** + * @title Wallet label — L01–L13 (PRD `docs-internal/sdk-first-changes/L-wallet-label_prd.md`). + * @notice The label is stored on the wallet, editable by the owner, capped at `MAX_LABEL_BYTES` bytes, + * and reads as `AGW ` (the factory's per-owner index) while none is set. + */ +contract WalletLabelTest is BaseTest { + address internal ownerAddr; + uint256 internal ownerPk; + address internal EXECUTOR; + AGW internal wallet; + + function setUp() public override { + super.setUp(); + (ownerAddr, ownerPk) = ecdsaKey("labelOwner"); + EXECUTOR = makeAddr("executor"); + wallet = newWallet(ownerAddr); + } + + // ─────────────────────────────── helpers ─────────────────────────────── + + function _single() internal pure returns (bytes32) { + return ModeCode.unwrap(ModeLib.encodeSimpleSingle()); + } + + function _batch() internal pure returns (bytes32) { + return ModeCode.unwrap(ModeLib.encodeSimpleBatch()); + } + + function _setLabelCall(string memory l) internal pure returns (bytes memory) { + return abi.encodeCall(AGW.setLabel, (l)); + } + + /// @dev A string of `n` copies of `unit`. + function _repeat(string memory unit, uint256 n) internal pure returns (string memory out) { + for (uint256 i; i < n; ++i) { + out = string.concat(out, unit); + } + } + + // ═══════════════════════════════════ L01 ═══════════════════════════════════ + + /// The default is `AGW `, numbered per owner. + function test_L01_DefaultIsAGWIndexPlusOne() public { + assertEq(wallet.label(), "AGW 1", "owner A, index 0"); + AGW second = newWallet(ownerAddr); + assertEq(second.label(), "AGW 2", "owner A, index 1"); + assertEq(wallet.label(), "AGW 1", "the first is unaffected"); + + AGW bobs = newWallet(makeAddr("bob")); + assertEq(bobs.label(), "AGW 1", "owner B counts from 1 on their own index"); + } + + // ═══════════════════════════════════ L02 ═══════════════════════════════════ + + /// A label passed at deploy is stored, and `WalletDeployed` still carries it. + function test_L02_DeployLabelIsStored() public { + (address predicted, uint96 index) = nextWallet(ownerAddr); + vm.expectEmit(true, true, true, true, FACTORY); + emit IAGWFactory.WalletDeployed(ownerAddr, index, predicted, "prediction-market-account"); + + vm.prank(ownerAddr); + AGW w = AGW(payable(factory.deployWallet("prediction-market-account"))); + + assertEq(address(w), predicted, "deployed at the predicted address"); + assertEq(w.label(), "prediction-market-account", "stored"); + } + + // ═══════════════════════════════════ L03 ═══════════════════════════════════ + + /// The owner sets a label: stored, `LabelSet` emitted, no checkpoint. + function test_L03_OwnerSetsLabel() public { + uint64 before = wallet.checkpointCount(); + + vm.expectEmit(false, false, false, true, address(wallet)); + emit IAGW.LabelSet("x"); + vm.prank(ownerAddr); + wallet.setLabel("x"); + + assertEq(wallet.label(), "x", "stored"); + assertEq(wallet.checkpointCount(), before, "a rename is not a checkpoint"); + } + + // ═══════════════════════════════════ L04 ═══════════════════════════════════ + + /// `""` resets to the default, and the event carries the empty string. + function test_L04_EmptyResetsToDefault() public { + vm.prank(ownerAddr); + wallet.setLabel("x"); + + vm.expectEmit(false, false, false, true, address(wallet)); + emit IAGW.LabelSet(""); + vm.prank(ownerAddr); + wallet.setLabel(""); + + assertEq(wallet.label(), "AGW 1", "back to the default"); + } + + // ═══════════════════════════════════ L05 ═══════════════════════════════════ + + /// Nobody but the owner (or the wallet itself) can rename. + function test_L05_NonOwnerRefused() public { + address[3] memory callers = [AGENT, makeAddr("stranger"), FACTORY]; + for (uint256 i; i < callers.length; ++i) { + vm.prank(callers[i]); + vm.expectRevert(AGWErrors.CallerIsNotOwner.selector); + wallet.setLabel("hijacked"); + } + assertEq(wallet.label(), "AGW 1", "unchanged"); + } + + // ═══════════════════════════════════ L06 ═══════════════════════════════════ + + /// A rename through the owner door works; only the owner-door calls tick, `setLabel` adds nothing. + function test_L06_RenameThroughExecute() public { + uint64 c0 = wallet.checkpointCount(); + + vm.prank(ownerAddr); + wallet.execute(_single(), ExecutionLib.encodeSingle(address(wallet), 0, _setLabelCall("one"))); + assertEq(wallet.label(), "one", "single"); + assertEq(wallet.checkpointCount(), c0 + 1, "one owner-door call, one tick"); + + Execution[] memory batch = new Execution[](2); + batch[0] = Execution({ target: address(wallet), value: 0, callData: _setLabelCall("two") }); + batch[1] = Execution({ target: address(wallet), value: 0, callData: _setLabelCall("three") }); + vm.prank(ownerAddr); + wallet.execute(_batch(), ExecutionLib.encodeBatch(batch)); + assertEq(wallet.label(), "three", "the last entry wins"); + assertEq(wallet.checkpointCount(), c0 + 3, "two batch entries, two ticks - none from setLabel"); + } + + // ═══════════════════════════════════ L07 ═══════════════════════════════════ + + /// A relayer renames on the owner's signature (the UEA owner's route). + function test_L07_RenameThroughExecuteWithSig() public { + bytes memory ecd = ExecutionLib.encodeSingle(address(wallet), 0, _setLabelCall("relayed")); + OwnerIntent memory i = blankIntent(ownerAddr, address(wallet), EXECUTOR); + i.mode = _single(); + i.execCalldataHash = keccak256(ecd); + i.nonceSeq = wallet.getNonce(i.nonceKey); + bytes memory sig = signIntent(ownerPk, i); + + vm.prank(EXECUTOR); + wallet.executeWithSig(_single(), ecd, i, sig); + + assertEq(wallet.label(), "relayed", "stored via the signed owner door"); + } + + // ═══════════════════════════════════ L08 ═══════════════════════════════════ + + /// The agent door cannot reach `setLabel`, even under a session enabled directly on the engine + /// with a policy that approves everything: the dispatch guard refuses the wallet as a target. + function test_L08_AgentDoorCannotRename() public { + PermissivePolicy permissive = new PermissivePolicy(); + Session memory bypass = sessionWithPolicy(address(permissive), agentConfig(AGENT), ""); + bypass.actions[0].actionTarget = address(wallet); + bypass.actions[0].actionTargetSelector = AGW.setLabel.selector; + Session[] memory arr = new Session[](1); + arr[0] = bypass; + vm.prank(address(wallet)); + bytes32 pid = PermissionId.unwrap(engine.enableSessions(arr)[0]); + + bytes memory ecd = ExecutionLib.encodeSingle(address(wallet), 0, _setLabelCall("agent-was-here")); + vm.prank(AGENT); + vm.expectRevert(abi.encodeWithSelector(AGWErrors.ForbiddenDispatchTarget.selector, address(wallet))); + wallet.executeAsAgent(pid, _single(), ecd); + + assertEq(wallet.label(), "AGW 1", "unchanged"); + } + + // ═══════════════════════════════════ L09 ═══════════════════════════════════ + + /// 64 bytes is the cap, on the setter and on the deploy path alike. + function test_L09_MaxLength() public { + string memory atCap = _repeat("a", MAX_LABEL_BYTES); + string memory overCap = _repeat("a", MAX_LABEL_BYTES + 1); + + vm.prank(ownerAddr); + wallet.setLabel(atCap); + assertEq(wallet.label(), atCap, "64 bytes is accepted"); + + vm.prank(ownerAddr); + vm.expectRevert(abi.encodeWithSelector(AGWErrors.LabelTooLong.selector, MAX_LABEL_BYTES + 1)); + wallet.setLabel(overCap); + assertEq(wallet.label(), atCap, "a refused rename leaves the old label"); + + // The deploy path: the wallet's revert bubbles through the factory with full data, and the + // whole deploy unwinds — the owner's count does not move. + uint256 countBefore = factory.walletCount(ownerAddr); + vm.prank(ownerAddr); + vm.expectRevert(abi.encodeWithSelector(AGWErrors.LabelTooLong.selector, MAX_LABEL_BYTES + 1)); + factory.deployWallet(overCap); + assertEq(factory.walletCount(ownerAddr), countBefore, "no wallet deployed"); + } + + // ═══════════════════════════════════ L10 ═══════════════════════════════════ + + /// The cap counts BYTES: sixteen 4-byte characters fit, seventeen do not. + function test_L10_LengthIsBytesNotChars() public { + string memory fourByteChar = unicode"🙂"; + assertEq(bytes(fourByteChar).length, 4, "fixture: a 4-byte UTF-8 character"); + + vm.prank(ownerAddr); + wallet.setLabel(_repeat(fourByteChar, 16)); + assertEq(wallet.label(), _repeat(fourByteChar, 16), "64 bytes, 16 characters"); + + vm.prank(ownerAddr); + vm.expectRevert(abi.encodeWithSelector(AGWErrors.LabelTooLong.selector, 68)); + wallet.setLabel(_repeat(fourByteChar, 17)); + } + + // ═══════════════════════════════════ L11 ═══════════════════════════════════ + + /// KNOWN LIMITATION, pinned: the label is not part of the owner's signature, so the relayer of a + /// `deployWalletWithSig` chooses it. Cosmetic; the owner can rename with `setLabel`. + function test_L11_SignedDeployLabelIsUnsigned() public { + address owner2; + uint256 pk2; + (owner2, pk2) = ecdsaKey("signedDeployOwner"); + (address predicted, uint96 index) = nextWallet(owner2); + OwnerIntent memory i = blankIntent(owner2, predicted, EXECUTOR); + i.index = index; + bytes memory sig = signIntent(pk2, i); + + vm.prank(EXECUTOR); + AGW w = AGW(payable(factory.deployWalletWithSig(i, sig, "relayer-chose-this"))); + + assertEq(w.label(), "relayer-chose-this", "the relayer's label is stored"); + + vm.prank(owner2); + w.setLabel(""); + assertEq(w.label(), "AGW 1", "and the owner can reset it"); + } + + // ═══════════════════════════════════ L12 ═══════════════════════════════════ + + /// Any 1..64-byte label round-trips unchanged. + function testFuzz_L12_RoundTrip(bytes memory raw) public { + vm.assume(raw.length != 0); + uint256 n = raw.length > MAX_LABEL_BYTES ? MAX_LABEL_BYTES : raw.length; + bytes memory b = new bytes(n); + for (uint256 k; k < n; ++k) { + b[k] = raw[k]; + } + + vm.prank(ownerAddr); + wallet.setLabel(string(b)); + assertEq(bytes(wallet.label()), b, "round-trip"); + } + + // ═══════════════════════════════════ L13 ═══════════════════════════════════ + + /// The default follows the owner's own index, not how many wallets the factory has deployed. + function test_L13_DefaultFollowsIndexNotGlobalCount() public { + AGW bobs = newWallet(makeAddr("bob")); + AGW second = newWallet(ownerAddr); + + assertEq(wallet.label(), "AGW 1", "A's first"); + assertEq(bobs.label(), "AGW 1", "B's first"); + assertEq(second.label(), "AGW 2", "A's second is AGW 2, not AGW 3"); + } +} diff --git a/plan/agw/research/extended-v5-e2e-2026-10-07/README.md b/plan/agw/research/extended-v5-e2e-2026-10-07/README.md new file mode 100644 index 00000000..50802ec6 --- /dev/null +++ b/plan/agw/research/extended-v5-e2e-2026-10-07/README.md @@ -0,0 +1,54 @@ +# Expanded v5 E2E coverage — October 7, 2026 + +Added the five requested scenarios. The opt-in AGW group now registers **58 scenarios across 14 files**; default `all` remains **76 scenarios / 40 files / 81 tests**. This report records validation performed before commit and push. + +## Coverage added + +| Scenario | Independent assertions | +| --- | --- | +| Solana-origin owner create / rename / reset | Correct UEA ownership, stored label, list visibility, default reset and two owner checkpoints | +| Rename with an active rule | Same rule ID/config/grant nonce and spend after rename; agent consumes its remaining budget; further value is rejected without signing | +| Failing owner batch after rename | SDK simulation maps `LabelTooLong`; a bounded mined transaction with the same SDK encoding reverts with no logs, preserving label and checkpoint count | +| Two assets used under one universal rule | Both ETH and USDC reach this wallet's CEA; each allowance/balance/spend changes independently; exhausted ETH does not prevent USDC; extra units are rejected by URP with nonce and counters unchanged | +| Owner funds-only SPL export | Recipient USDT ATA credit, per-transaction token delta, wallet burn, allowance consumption, owner checkpoint and response/replay identity | + +Existing label tests now check isolation between two wallets and the intermediate renamed label through an EVM UEA owner, before reset. Destination receipts remain required: a successful Push leg alone cannot pass a delivery test. + +## SDK defect found and fixed + +The new SPL test failed **before signing** when `SOURCE_TOKEN_ADDRESS()` was decoded as a Solidity string. A read-only raw probe showed that the current SVM synthetic precompile returns a **zero word**, not a source mint string. It must not be interpreted as the mint of a non-native token. + +The shared SVM metadata resolver now: + +- Accepts populated string/word metadata when supplied. +- Treats a zero marker as native only for the registered gas PRC20. +- Resolves a known non-native mapping using the SDK's existing registry, matching the full origin chain, network and exact PRC20 address, as ordinary Route 2 already does. +- Rejects unknown mappings instead of guessing a mint. +- Serves quoting, authoring and rule reads consistently; decoded hexadecimal mint inputs normalize to base58 for registry lookup. + +Four added regression units cover real ABI decoding, unavailable metadata, the live zero-word/registered-mint case, and hexadecimal mint authoring. The subsequent funded SPL test delivered exactly **1,000 raw USDT units** to the intended ATA and passed replay checks. No public API or permission-selection behavior changed. + +## EVM destination gas finding + +The existing positive EVM case initially reached Sepolia and **reverted** with a 500,000-gas transaction. Replaying its exact call with 500,000 gas failed; five million gas succeeded; `eth_estimateGas` returned **1,304,470** for fresh CEA finalization. This was not evidence of malformed SDK payloads or a gas-limit safety bypass. + +Positive EVM tests and the guide now supply an explicit **2,000,000 destination-gas budget**. A later fresh-fixture run succeeded with that exact gas limit, using **1,265,746 gas**, and independently verified the wallet's CEA, caller, target, ETH credit and replay. The two-token case also passed both real deliveries. + +One explicit-budget run timed out after ten minutes before the later successful run. Its timeout is retained as delivery-latency evidence; we have not established its root cause. The SDK's default is **not silently raised**. Core/gateway should revisit the default for fresh CEA deployment; the caller workaround is verified. See [failed transaction](evm-failed-destination.json), [read-only gas checks](evm-failure-followup.json), and [successful explicit budget](evm-explicit-success.json). + +## Validation and execution limits + +- Full unit suite: **2,014 passed / 12 skipped / 0 failed**. +- Actual v5 contract harness: **90 passed**, 12 suites, retaining the documented gateway/core/token/destination fixtures. +- Typecheck, build, package imports/declarations, API comparison, guide examples, scenario manifests and scoped lint pass; lint has test non-null warnings, not errors. +- Funding preflight `--dry-run` passes with explicit new master-USDC and master-SPL requirements. This check does not fund anything. +- Live labels: **8/8 passed**, including a genuinely mined reverted owner batch. +- Live multi-asset suite: **3/3 passed** with explicit destination gas, including the new independent-budget case. +- Final EVM/SPL rerun: **3/3 passed** (EVM positive, intentional destination failure, SPL transfer). +- Native SOL public suite: **6/6 passed again after the metadata resolver fix**, including actual agent delivery, owner funds-only SOL delivery and replay. + +These are selected runs, not a single complete 58-case run. Across this expansion, 20 distinct live scenarios are covered (8 labels, 3 multi-asset, 2 EVM, 6 native SOL, 1 SPL). Earlier v5 native/lifecycle acceptance adds ten further distinct cases; it is not a fresh rerun of every scenario. + +Initial default-gas EVM failure, an explicit-gas timeout and the pre-fix SPL decoding failure remain in the logs. Failed delivery is never accepted as success. All actual broadcasts were on Donut, Sepolia or Solana devnet, using fresh AGWs and bounded fixture funding. No mainnet transaction, contract deployment, team message, publication or credential dump occurred. + +Evidence: [logs/](logs/), [live records](live-evidence.jsonl), [raw SPL metadata](spl-metadata-probe.json), [API comparison](api-comparison.json). Some diagnostic event/search files contain no matches; those empty results are not proof that no outbound exists. diff --git a/plan/agw/research/extended-v5-e2e-2026-10-07/api-comparison.json b/plan/agw/research/extended-v5-e2e-2026-10-07/api-comparison.json new file mode 100644 index 00000000..2454ca5e --- /dev/null +++ b/plan/agw/research/extended-v5-e2e-2026-10-07/api-comparison.json @@ -0,0 +1,11460 @@ +{ + "baseline": "b1597b91a25dbf7f691f589b4e1e154add604315", + "head": "898eda17911133faa155899ac8e1276a589c4564", + "compiledMatchesSource": true, + "initializeSignatureChanged": false, + "addedExports": [ + "DecodedSolanaRule", + "SolanaRule", + "SvmAccountRef", + "SvmFieldConstraint", + "SvmInstructionRule" + ], + "removedExports": [], + "changedAgwTypes": [ + "AgenticError", + "AGENTIC_ERROR_CODE", + "NativeRule", + "AllowedCall", + "UniversalRule", + "RulesRecord", + "AgenticTxMetadata" + ], + "publicTypeChanges": [ + "AGENTIC_ERROR_CODE", + "AgenticError", + "AgenticErrorCode", + "AgenticNetworkConstants", + "AgenticTxMetadata", + "AllowedCall", + "NativeRule", + "SolanaRule", + "DecodedSolanaRule", + "SvmInstructionRule", + "SvmAccountRef", + "SvmFieldConstraint", + "Rule", + "RulesRecord", + "UniversalRule" + ], + "transactionMethodChanges": [], + "instanceMethodChanges": [], + "agwConstantsChanged": true, + "before": { + "exports": [ + "AGENTIC_ERROR_CODE", + "AccountRole", + "AccountStatus", + "AccountType", + "AgenticAddress", + "AgenticDoor", + "AgenticError", + "AgenticErrorCode", + "AgenticHex", + "AgenticNamespace", + "AgenticNetworkConstants", + "AgenticProgressHook", + "AgenticRevertError", + "AgenticTxMetadata", + "AgenticWallet", + "AllowedCall", + "AssetCap", + "BatchReadResponse", + "BuildReadSpecParams", + "CHAIN", + "CONTRACT_REQUEST_STATUS", + "CascadeCompletionResult", + "CascadeHopInfo", + "CascadeProgressEvent", + "CascadeTrackOptions", + "CascadedTxResponse", + "ChainSource", + "ChainTarget", + "Checkpoint", + "CheckpointKind", + "ConversionQuote", + "CreateOptions", + "CreateResult", + "DEFAULT_MAX_PC_FOR_GAS_BUFFER_BPS", + "DecodedErrorPayload", + "DecodedReadResult", + "DerivedExecutorAccount", + "EncodedReadQuery", + "EvmReadQuery", + "ForeignChainNamespace", + "FulfilOutcome", + "FundsToken", + "InsufficientPC20BalanceError", + "InvalidPC20AddressError", + "InvalidPC20MetadataError", + "InvalidReadQueryError", + "InvalidReadSpecError", + "MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT", + "MaxPCForGasCapFromNativeValueInput", + "MaxPCForGasCapInput", + "MaxPCForGasCapQuote", + "MultiChainTxResponse", + "NativeRule", + "OutboundTxDetails", + "PC20AddressResult", + "PC20AmbiguousAddressError", + "PC20Error", + "PC20ExpectedButPRC20Error", + "PC20ExportRevertedError", + "PC20FactoryMismatchError", + "PC20RegistryEntry", + "PC20RegistryMismatchError", + "PC20TokenChainMismatchError", + "PC20TokenReference", + "PC20UnknownChainNamespaceError", + "PC20UnsafeEmptyPayloadError", + "PC20WrapperNotRegisteredError", + "PC20WrapperPredictionUnavailableError", + "ParsedReadRequest", + "PreparedRead", + "PreparedUniversalTx", + "PushChain", + "PushChainBatchExecutionError", + "PushChainExecutionError", + "PushChainInitializeOptions", + "READ_ERROR_CODE", + "READ_OUTCOME", + "READ_STATUS", + "ReadCallback", + "ReadCallbackOptions", + "ReadChain", + "ReadDecodeError", + "ReadDestination", + "ReadExecuteOptions", + "ReadFees", + "ReadHeightUnavailableError", + "ReadLifecycleOptions", + "ReadNotFoundError", + "ReadOptions", + "ReadPreflight", + "ReadPrepareOptions", + "ReadQuery", + "ReadQueryOptions", + "ReadRef", + "ReadRegistryUnavailableError", + "ReadResponseTuple", + "ReadResultShape", + "ReadSpec", + "ReadSpecTuple", + "ReadSpecViolation", + "ReadStateError", + "ReadTimeoutError", + "ReadTrackOptions", + "ReadValue", + "ReadWeb2Options", + "ReceiptLike", + "RescueFundsParams", + "ResolvedAccount", + "ResolvedControllerAccounts", + "ResolvedDestination", + "Rule", + "RulesRecord", + "Selector", + "SignAuthorizationParams", + "SignedAuthorization", + "SimulateReadResult", + "SvmExecutePayloadFields", + "SvmGatewayAccountMeta", + "SvmReadQuery", + "TERMINAL_READ_STATUSES", + "TransactionRoute", + "TransactionRouteType", + "UEAStatus", + "UNIVERSAL_CALLBACK_EVM", + "UNIVERSAL_READ_REGISTRY_EVM", + "UNIVERSAL_READ_STATUS", + "UniversalAccount", + "UniversalExecuteParams", + "UniversalOutboundTxRequest", + "UniversalReadResponse", + "UniversalRule", + "UniversalSigner", + "UniversalSignerSkeleton", + "UniversalTo", + "UnsupportedPC20DestinationError", + "UnsupportedReadDestinationError", + "ValidateReadCall", + "WaitForOutboundOptions", + "WalletInfo", + "WalletSummary", + "Web2Extract", + "Web2ReadQuery", + "Web2ValueType", + "buildErc20WithdrawalMulticall", + "buildMigrationPayload", + "buildReadSpecFromPreflight", + "chainSupportsCEA", + "chainSupportsOutbound", + "decodeReadResult", + "detectRoute", + "encodeReadQuery", + "encodeSvmExecutePayload", + "getAllCEAAddresses", + "getCEAAddress", + "getCEAFactoryAddress", + "getPushAccountForCEA", + "inferResultShape", + "isCEA", + "isChainTarget", + "isPC20Reference", + "isSvmChain", + "isValidSolanaHexAddress", + "parseFulfilOutcome", + "parseReadRequestsFromReceipt", + "parseUEAVersion", + "quoteMaxPCForGasCap", + "quoteMaxPCForGasCapFromNativeValue", + "resolveDestination", + "sizeCallbackBudget", + "toCallData", + "toReadQuery", + "toRequestIdHex", + "validateReadSpec" + ], + "agw": { + "AgenticNamespace": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace", + "members": { + "create": { + "optional": false, + "readonly": false, + "type": "(label: string, options: import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions) => Promise" + }, + "derive": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n index?: number;\n}) => Promise<{\n address: `0x${string}`;\n deployed: boolean;\n index: number;\n}>" + }, + "list": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n wallets: import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary[];\n}>" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "(address: `0x${string}`) => import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet" + } + } + }, + "AgenticWallet": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "checkpoints": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n sinceBlock?: bigint;\n}) => Promise<{\n checkpoints: import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint[];\n}>" + }, + "info": { + "optional": false, + "readonly": false, + "type": "() => Promise" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n owner: `0x${string}`;\n}>" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "{\n add(rules: import(\"sdk/src/lib/agentic/agentic.types\").Rule[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise<{\n rulesIds: `0x${string}`[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n get(rulesId: `0x${string}`): Promise;\n list(): Promise<{\n rules: import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord[];\n }>;\n revoke(rulesIds: `0x${string}`[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n revoke(params: {\n all: true;\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n update(params: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n rules: {\n rule: import(\"sdk/src/lib/agentic/agentic.types\").Rule;\n rulesId: `0x${string}`;\n }[];\n }): Promise<{\n rules: {\n replaced: `0x${string}`;\n rulesId: `0x${string}`;\n }[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n}" + }, + "setLabel": { + "optional": false, + "readonly": false, + "type": "(label: string, opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n}) => Promise" + } + } + }, + "AgenticError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"CREATE_PARTIAL\" | \"DUPLICATE_RULE\" | \"FROM_NOT_ALLOWED\" | \"GATEWAY_ALLOWANCE_INSUFFICIENT\" | \"GENERATION_UNSUPPORTED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"REVOKE_NEEDS_TARGET\" | \"RULE_LIMIT_EXCEEDED\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"" + }, + "details": { + "optional": true, + "readonly": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "AgenticRevertError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticRevertError", + "members": { + "agenticCode": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + } + } + }, + "AGENTIC_ERROR_CODE": { + "type": "{\n readonly AGENT_GAS_INSUFFICIENT: \"AGENT_GAS_INSUFFICIENT\";\n readonly AGENT_IS_OWNER: \"AGENT_IS_OWNER\";\n readonly ASSET_CHAIN_MISMATCH: \"ASSET_CHAIN_MISMATCH\";\n readonly CAPABILITY_UNAVAILABLE: \"CAPABILITY_UNAVAILABLE\";\n readonly CREATE_PARTIAL: \"CREATE_PARTIAL\";\n readonly DUPLICATE_RULE: \"DUPLICATE_RULE\";\n readonly FROM_NOT_ALLOWED: \"FROM_NOT_ALLOWED\";\n readonly GATEWAY_ALLOWANCE_INSUFFICIENT: \"GATEWAY_ALLOWANCE_INSUFFICIENT\";\n readonly GENERATION_UNSUPPORTED: \"GENERATION_UNSUPPORTED\";\n readonly INCONSISTENT_READ: \"INCONSISTENT_READ\";\n readonly INDEX_RACE: \"INDEX_RACE\";\n readonly INVALID_RULE: \"INVALID_RULE\";\n readonly NO_RULES_FOR_CHAIN: \"NO_RULES_FOR_CHAIN\";\n readonly NOT_AGENTIC_WALLET: \"NOT_AGENTIC_WALLET\";\n readonly NOT_ALLOWED_IN_AGENTIC_MODE: \"NOT_ALLOWED_IN_AGENTIC_MODE\";\n readonly NOT_OWNER_OR_AGENT: \"NOT_OWNER_OR_AGENT\";\n readonly NOT_WALLET_OWNER: \"NOT_WALLET_OWNER\";\n readonly READ_ONLY: \"READ_ONLY\";\n readonly RECEIPT_MISMATCH: \"RECEIPT_MISMATCH\";\n readonly RECEIPT_UNAVAILABLE: \"RECEIPT_UNAVAILABLE\";\n readonly REVOKE_NEEDS_TARGET: \"REVOKE_NEEDS_TARGET\";\n readonly RULE_LIMIT_EXCEEDED: \"RULE_LIMIT_EXCEEDED\";\n readonly RULE_NOT_FOUND: \"RULE_NOT_FOUND\";\n readonly RULE_READ_FAILED: \"RULE_READ_FAILED\";\n readonly TARGET_NOT_ON_RULE_CHAIN: \"TARGET_NOT_ON_RULE_CHAIN\";\n readonly WALLET_BALANCE_INSUFFICIENT: \"WALLET_BALANCE_INSUFFICIENT\";\n readonly WALLET_NOT_DEPLOYED: \"WALLET_NOT_DEPLOYED\";\n}", + "members": { + "AGENT_GAS_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\"" + }, + "AGENT_IS_OWNER": { + "optional": false, + "readonly": true, + "type": "\"AGENT_IS_OWNER\"" + }, + "ASSET_CHAIN_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"ASSET_CHAIN_MISMATCH\"" + }, + "CAPABILITY_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"CAPABILITY_UNAVAILABLE\"" + }, + "CREATE_PARTIAL": { + "optional": false, + "readonly": true, + "type": "\"CREATE_PARTIAL\"" + }, + "DUPLICATE_RULE": { + "optional": false, + "readonly": true, + "type": "\"DUPLICATE_RULE\"" + }, + "FROM_NOT_ALLOWED": { + "optional": false, + "readonly": true, + "type": "\"FROM_NOT_ALLOWED\"" + }, + "GATEWAY_ALLOWANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"GATEWAY_ALLOWANCE_INSUFFICIENT\"" + }, + "GENERATION_UNSUPPORTED": { + "optional": false, + "readonly": true, + "type": "\"GENERATION_UNSUPPORTED\"" + }, + "INCONSISTENT_READ": { + "optional": false, + "readonly": true, + "type": "\"INCONSISTENT_READ\"" + }, + "INDEX_RACE": { + "optional": false, + "readonly": true, + "type": "\"INDEX_RACE\"" + }, + "INVALID_RULE": { + "optional": false, + "readonly": true, + "type": "\"INVALID_RULE\"" + }, + "NO_RULES_FOR_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"NO_RULES_FOR_CHAIN\"" + }, + "NOT_AGENTIC_WALLET": { + "optional": false, + "readonly": true, + "type": "\"NOT_AGENTIC_WALLET\"" + }, + "NOT_ALLOWED_IN_AGENTIC_MODE": { + "optional": false, + "readonly": true, + "type": "\"NOT_ALLOWED_IN_AGENTIC_MODE\"" + }, + "NOT_OWNER_OR_AGENT": { + "optional": false, + "readonly": true, + "type": "\"NOT_OWNER_OR_AGENT\"" + }, + "NOT_WALLET_OWNER": { + "optional": false, + "readonly": true, + "type": "\"NOT_WALLET_OWNER\"" + }, + "READ_ONLY": { + "optional": false, + "readonly": true, + "type": "\"READ_ONLY\"" + }, + "RECEIPT_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_MISMATCH\"" + }, + "RECEIPT_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_UNAVAILABLE\"" + }, + "REVOKE_NEEDS_TARGET": { + "optional": false, + "readonly": true, + "type": "\"REVOKE_NEEDS_TARGET\"" + }, + "RULE_LIMIT_EXCEEDED": { + "optional": false, + "readonly": true, + "type": "\"RULE_LIMIT_EXCEEDED\"" + }, + "RULE_NOT_FOUND": { + "optional": false, + "readonly": true, + "type": "\"RULE_NOT_FOUND\"" + }, + "RULE_READ_FAILED": { + "optional": false, + "readonly": true, + "type": "\"RULE_READ_FAILED\"" + }, + "TARGET_NOT_ON_RULE_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"TARGET_NOT_ON_RULE_CHAIN\"" + }, + "WALLET_BALANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"WALLET_BALANCE_INSUFFICIENT\"" + }, + "WALLET_NOT_DEPLOYED": { + "optional": false, + "readonly": true, + "type": "\"WALLET_NOT_DEPLOYED\"" + } + } + }, + "NativeRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "amount": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AmountLimit | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "maxCalls": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValuePerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxValueTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "pins": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ArgPin[] | undefined" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "AssetCap": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap", + "members": { + "maxPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/constants/tokens\").MoveableToken" + } + } + }, + "AllowedCall": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall", + "members": { + "beneficiary": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValue": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "`${string}(${string})` | `0x${string}`" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "UniversalRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall[]" + }, + "assets": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap[]" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "`eip155:${string}` | `solana:${string}`" + }, + "maxGasPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "RulesRecord": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "enabled": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "ref": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "rule": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule | import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule" + }, + "rulesId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "CreateOptions": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions", + "members": { + "progressHook": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook | undefined" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Rule[]" + } + } + }, + "CreateResult": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateResult", + "members": { + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "rulesIds": { + "optional": false, + "readonly": false, + "type": "`0x${string}`[]" + }, + "tx": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticTxMetadata": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticTxMetadata", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destinationAccount": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "destinationCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "door": { + "optional": false, + "readonly": false, + "type": "\"agent\" | \"owner\"" + }, + "nativeCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "rawData": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rawTo": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesId": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + } + }, + "publicSurface": { + "CHAIN": { + "type": "typeof import(\"sdk/src/lib/constants/enums\").CHAIN", + "members": { + "ARBITRUM_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA" + }, + "BASE_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA" + }, + "BNB_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET" + }, + "ETHEREUM_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET" + }, + "ETHEREUM_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA" + }, + "PUSH_LOCALNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET" + }, + "PUSH_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET" + }, + "PUSH_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET" + }, + "PUSH_TESTNET_DONUT": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET" + }, + "SOLANA_DEVNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET" + }, + "SOLANA_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET" + }, + "SOLANA_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET" + }, + "WEB2": { + "optional": false, + "readonly": false, + "type": "\"web2\"" + } + } + }, + "ConversionQuote": { + "type": "import(\"sdk/src/lib/constants/tokens\").ConversionQuote", + "members": { + "amountIn": { + "optional": false, + "readonly": false, + "type": "string" + }, + "amountOut": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rate": { + "optional": false, + "readonly": false, + "type": "number" + }, + "route": { + "optional": true, + "readonly": false, + "type": "string[] | undefined" + }, + "timestamp": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "UniversalSigner": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalSigner", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "signAndSendTransaction": { + "optional": false, + "readonly": false, + "type": "(unsignedTx: Uint8Array) => Promise" + }, + "signAuthorization": { + "optional": true, + "readonly": false, + "type": "((params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise) | undefined" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": true, + "readonly": false, + "type": "(({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise) | undefined" + } + } + }, + "UniversalAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "UniversalSignerSkeleton": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "signAndSendTransaction": { + "optional": false, + "readonly": false, + "type": "(unsignedTx: Uint8Array) => Promise" + }, + "signAuthorization": { + "optional": true, + "readonly": false, + "type": "((params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise) | undefined" + }, + "signerId": { + "optional": false, + "readonly": false, + "type": "string" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": true, + "readonly": false, + "type": "(({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise) | undefined" + } + } + }, + "SignAuthorizationParams": { + "type": "{\n chainId?: number;\n contractAddress: `0x${string}`;\n executor?: \"self\";\n nonce?: number;\n}", + "members": { + "chainId": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "contractAddress": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "executor": { + "optional": true, + "readonly": false, + "type": "\"self\" | undefined" + }, + "nonce": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "SignedAuthorization": { + "type": "{\n address: `0x${string}`;\n chainId: number;\n nonce: number;\n r: `0x${string}`;\n s: `0x${string}`;\n v?: bigint;\n yParity: number;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainId": { + "optional": false, + "readonly": false, + "type": "number" + }, + "nonce": { + "optional": false, + "readonly": false, + "type": "number" + }, + "r": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "s": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "v": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "yParity": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "DerivedExecutorAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").DerivedExecutorAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean | null" + } + } + }, + "ResolvedAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainName": { + "optional": false, + "readonly": false, + "type": "string" + }, + "exists": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "role": { + "optional": true, + "readonly": false, + "type": "\"controller\" | undefined" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"cea\" | \"uea\" | \"uoa\"" + } + } + }, + "ResolvedControllerAccounts": { + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedControllerAccounts", + "members": { + "accounts": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedAccount[]" + } + } + }, + "AccountType": { + "type": "\"cea\" | \"uea\" | \"uoa\"", + "members": {} + }, + "AccountRole": { + "type": "\"controller\"", + "members": {} + }, + "PC20TokenReference": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "FundsToken": { + "type": "import(\"sdk/src/lib/constants/tokens\").MoveableToken | import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20TokenReference", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "PC20RegistryEntry": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "chainName": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "PC20AddressResult": { + "type": "{\n address: `0x${string}`;\n decimals: number;\n name: string;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n registry: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20RegistryEntry[];\n symbol: string;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "decimals": { + "optional": false, + "readonly": false, + "type": "number" + }, + "name": { + "optional": false, + "readonly": false, + "type": "string" + }, + "network": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "registry": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20RegistryEntry[]" + }, + "symbol": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "isPC20Reference": { + "type": "(token: import(\"sdk/src/lib/orchestrator/orchestrator.types\").FundsToken | undefined) => token is import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20TokenReference", + "members": {} + }, + "PC20Error": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20Error", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidPC20AddressError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InvalidPC20AddressError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20TokenChainMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20TokenChainMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20WrapperNotRegisteredError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20WrapperNotRegisteredError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20RegistryMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20RegistryMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20FactoryMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20FactoryMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidPC20MetadataError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InvalidPC20MetadataError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20ExpectedButPRC20Error": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20ExpectedButPRC20Error", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20AmbiguousAddressError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20AmbiguousAddressError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "candidates": { + "optional": false, + "readonly": true, + "type": "{\n chain: string;\n pushAddress: string;\n}[]" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "UnsupportedPC20DestinationError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").UnsupportedPC20DestinationError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InsufficientPC20BalanceError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InsufficientPC20BalanceError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20UnknownChainNamespaceError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20UnknownChainNamespaceError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20WrapperPredictionUnavailableError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20WrapperPredictionUnavailableError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20ExportRevertedError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20ExportRevertedError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "lockedAmount": { + "optional": true, + "readonly": true, + "type": "bigint | undefined" + }, + "outboundTxId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "revertRecipient": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20UnsafeEmptyPayloadError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20UnsafeEmptyPayloadError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ChainTarget": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "ChainSource": { + "type": "{\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "UniversalTo": { + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget", + "members": {} + }, + "TransactionRouteType": { + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"", + "members": {} + }, + "UniversalExecuteParams": { + "type": "{\n from?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainSource;\n migration?: boolean;\n to: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTo;\n} & Omit", + "members": { + "_minimumDepositUsd": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "_requiredFundsOverride": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "_skipFeeLocking": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "_ueaStatus": { + "optional": true, + "readonly": false, + "type": "{\n balance: bigint;\n isDeployed: boolean;\n nonce: bigint;\n} | undefined" + }, + "data": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiCall[] | undefined" + }, + "deadline": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "feeLockTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "from": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainSource | undefined" + }, + "funds": { + "optional": true, + "readonly": false, + "type": "{\n amount: bigint;\n token?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").FundsToken;\n} | undefined" + }, + "gasLimit": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFeePerGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxPCForGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxPriorityFeePerGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "migration": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "nonce": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "options": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions | undefined" + }, + "payGasWith": { + "optional": true, + "readonly": false, + "type": "{\n minAmountOut?: bigint | string;\n slippageBps?: number;\n token?: import(\"sdk/src/lib/constants/tokens\").PayableToken;\n} | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "to": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget" + }, + "value": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "UniversalOutboundTxRequest": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalOutboundTxRequest", + "members": { + "amount": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gasPrice": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxPCForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "payload": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "recipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "revertRecipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "PreparedUniversalTx": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx", + "members": { + "_hop": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").HopDescriptor" + }, + "deadline": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "estimatedGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gatewayRequest": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalOutboundTxRequest | import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxRequest" + }, + "nonce": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "payload": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + } + } + }, + "CascadedTxResponse": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadedTxResponse", + "members": { + "finalTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hopCount": { + "optional": false, + "readonly": false, + "type": "number" + }, + "hops": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo[]" + }, + "initialTxHash": { + "optional": false, + "readonly": false, + "type": "string" + }, + "initialTxResponse": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions) => Promise" + }, + "waitForAll": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions) => Promise" + } + } + }, + "CascadeHopInfo": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo", + "members": { + "executionChain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "expectedSubTxId": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hopIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "outboundDetails": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").OutboundTxDetails | undefined" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + }, + "status": { + "optional": false, + "readonly": false, + "type": "\"confirmed\" | \"failed\" | \"pending\" | \"submitted\"" + }, + "txHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "CascadeTrackOptions": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions", + "members": { + "eventHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeProgressEvent) => void) | undefined" + }, + "timeout": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "CascadeProgressEvent": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeProgressEvent", + "members": { + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "elapsed": { + "optional": false, + "readonly": false, + "type": "number" + }, + "hopIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + }, + "status": { + "optional": false, + "readonly": false, + "type": "\"confirmed\" | \"failed\" | \"found\" | \"polling\" | \"timeout\" | \"waiting\"" + }, + "txHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "CascadeCompletionResult": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeCompletionResult", + "members": { + "failedAt": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "finalTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "finalTxResponse": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadedTxResponse | undefined" + }, + "hops": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo[]" + }, + "success": { + "optional": false, + "readonly": false, + "type": "boolean" + } + } + }, + "MultiChainTxResponse": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiChainTxResponse", + "members": { + "chains": { + "optional": false, + "readonly": false, + "type": "{\n blockNumber: bigint;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n hash: string;\n status: \"confirmed\" | \"failed\" | \"pending\";\n}[]" + }, + "transactions": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse[]" + } + } + }, + "OutboundTxDetails": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").OutboundTxDetails", + "members": { + "amount": { + "optional": false, + "readonly": false, + "type": "string" + }, + "assetAddr": { + "optional": false, + "readonly": false, + "type": "string" + }, + "destinationChain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "explorerUrl": { + "optional": false, + "readonly": false, + "type": "string" + }, + "externalTxHash": { + "optional": false, + "readonly": false, + "type": "string" + }, + "recipient": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "WaitForOutboundOptions": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").WaitForOutboundOptions", + "members": { + "_expectedDestinationChain": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "_outboundIndex": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "_resolvedSubTxId": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "initialWaitMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: {\n elapsed: number;\n status: \"failed\" | \"found\" | \"polling\" | \"timeout\" | \"waiting\";\n}) => void) | undefined" + }, + "timeout": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "SvmGatewayAccountMeta": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmGatewayAccountMeta", + "members": { + "isWritable": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "pubkey": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "SvmExecutePayloadFields": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmExecutePayloadFields", + "members": { + "accounts": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmGatewayAccountMeta[]" + }, + "instructionId": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "ixData": { + "optional": false, + "readonly": false, + "type": "Uint8Array" + }, + "targetProgram": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AccountStatus": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus", + "members": { + "mode": { + "optional": false, + "readonly": false, + "type": "\"read-only\" | \"signer\"" + }, + "uea": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UEAStatus" + } + } + }, + "UEAStatus": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UEAStatus", + "members": { + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "loaded": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "minRequiredVersion": { + "optional": false, + "readonly": false, + "type": "string" + }, + "requiresUpgrade": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "version": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "RescueFundsParams": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").RescueFundsParams", + "members": { + "prc20": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "universalTxId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "parseUEAVersion": { + "type": "(version: string) => number", + "members": {} + }, + "TransactionRoute": { + "type": "typeof import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute", + "members": { + "CEA_TO_CEA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.CEA_TO_CEA" + }, + "CEA_TO_PUSH": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.CEA_TO_PUSH" + }, + "UOA_TO_CEA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.UOA_TO_CEA" + }, + "UOA_TO_PUSH": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.UOA_TO_PUSH" + } + } + }, + "detectRoute": { + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams) => import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute", + "members": {} + }, + "isChainTarget": { + "type": "(to: unknown) => to is import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget", + "members": {} + }, + "DEFAULT_MAX_PC_FOR_GAS_BUFFER_BPS": { + "type": "1000", + "members": {} + }, + "MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT": { + "type": "10000", + "members": {} + }, + "quoteMaxPCForGasCap": { + "type": "(input: import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapInput) => import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": {} + }, + "quoteMaxPCForGasCapFromNativeValue": { + "type": "(input: import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapFromNativeValueInput) => import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": {} + }, + "MaxPCForGasCapInput": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapInput", + "members": { + "bufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "gasLegNativePc": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "MaxPCForGasCapFromNativeValueInput": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapFromNativeValueInput", + "members": { + "bufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "nativeValueForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "MaxPCForGasCapQuote": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": { + "bufferBps": { + "optional": false, + "readonly": false, + "type": "number" + }, + "gasLegNativePc": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxPCForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "nativeValueForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "getCEAAddress": { + "type": "(ueaAddress: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise", + "members": {} + }, + "getPushAccountForCEA": { + "type": "(ceaAddress: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise<`0x${string}`>", + "members": {} + }, + "isCEA": { + "type": "(address: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise", + "members": {} + }, + "chainSupportsCEA": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "chainSupportsOutbound": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "getCEAFactoryAddress": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => `0x${string}` | undefined", + "members": {} + }, + "getAllCEAAddresses": { + "type": "(ueaAddress: `0x${string}`, rpcUrls?: Partial>) => Promise", + "members": {} + }, + "encodeSvmExecutePayload": { + "type": "(fields: import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmExecutePayloadFields) => `0x${string}`", + "members": {} + }, + "isSvmChain": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "isValidSolanaHexAddress": { + "type": "(address: string) => boolean", + "members": {} + }, + "buildMigrationPayload": { + "type": "() => `0x${string}`", + "members": {} + }, + "buildErc20WithdrawalMulticall": { + "type": "(tokenAddress: `0x${string}`, recipientAddress: `0x${string}`, amount: bigint) => import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiCall[]", + "members": {} + }, + "ReadChain": { + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain", + "members": {} + }, + "ReadDestination": { + "type": "{\n chain: import(\"sdk/src/lib/read-state/read-state.types\").ReadChain;\n} | {\n chainId: string;\n chainNamespace: string;\n}", + "members": {} + }, + "ResolvedDestination": { + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}", + "members": { + "caip2": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainId": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "namespace": { + "optional": false, + "readonly": false, + "type": "\"eip155\" | \"solana\" | \"web2\"" + } + } + }, + "ReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").SvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery", + "members": { + "type": { + "optional": false, + "readonly": false, + "type": "\"accountBalance\" | \"contractCall\" | \"http\" | \"lamportBalance\" | \"rawAccountData\" | \"splTokenAccount\" | \"storageSlot\"" + } + } + }, + "EvmReadQuery": { + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n target: `0x${string}`;\n type: \"contractCall\";\n} | {\n callData: `0x${string}`;\n target: `0x${string}`;\n type: \"contractCall\";\n} | {\n slot: `0x${string}` | bigint;\n target: `0x${string}`;\n type: \"storageSlot\";\n} | {\n target: `0x${string}`;\n type: \"accountBalance\";\n}", + "members": { + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"accountBalance\" | \"contractCall\" | \"storageSlot\"" + } + } + }, + "SvmReadQuery": { + "type": "{\n account: string | Uint8Array;\n accountName?: string;\n idl?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n type: \"rawAccountData\";\n} | {\n account: string | Uint8Array;\n type: \"lamportBalance\";\n} | {\n account: string | Uint8Array;\n type: \"splTokenAccount\";\n}", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "string | Uint8Array" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"lamportBalance\" | \"rawAccountData\" | \"splTokenAccount\"" + } + } + }, + "Web2ReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery", + "members": { + "body": { + "optional": true, + "readonly": false, + "type": "string | Uint8Array | undefined" + }, + "extract": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[]" + }, + "headers": { + "optional": true, + "readonly": false, + "type": "Record | undefined" + }, + "method": { + "optional": true, + "readonly": false, + "type": "\"GET\" | \"POST\" | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"http\"" + }, + "url": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "Web2Extract": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract", + "members": { + "decimals": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "path": { + "optional": false, + "readonly": false, + "type": "string" + }, + "valueType": { + "optional": false, + "readonly": false, + "type": "\"bool\" | \"bytes\" | \"int256\" | \"string\" | \"uint256\"" + } + } + }, + "Web2ValueType": { + "type": "\"bool\" | \"bytes\" | \"int256\" | \"string\" | \"uint256\"", + "members": {} + }, + "EncodedReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery", + "members": { + "blockRef": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "encoded": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "namespace": { + "optional": false, + "readonly": false, + "type": "\"eip155\" | \"solana\" | \"web2\"" + }, + "ownerBytes": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "queryType": { + "optional": false, + "readonly": false, + "type": "number" + }, + "resultShape": { + "optional": false, + "readonly": false, + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}" + }, + "warnings": { + "optional": false, + "readonly": false, + "type": "string[]" + } + } + }, + "ReadResultShape": { + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"bytes32\" | \"evmCall\" | \"raw\" | \"svmAccount\" | \"uint256\" | \"web2\"" + } + } + }, + "DecodedReadResult": { + "type": "{\n accountName: string;\n kind: \"svmAccount\";\n value: unknown;\n} | {\n kind: \"bytes32\";\n value: `0x${string}`;\n} | {\n kind: \"evmCall\";\n value: unknown;\n} | {\n kind: \"raw\";\n value: `0x${string}`;\n} | {\n kind: \"uint256\";\n value: bigint;\n} | {\n kind: \"web2\";\n values: readonly unknown[];\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"bytes32\" | \"evmCall\" | \"raw\" | \"svmAccount\" | \"uint256\" | \"web2\"" + } + } + }, + "ReadPreflight": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight", + "members": { + "destination": { + "optional": false, + "readonly": false, + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}" + }, + "fetchedAt": { + "optional": false, + "readonly": false, + "type": "number" + }, + "observedChainHeight": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pushBlockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pushGasPrice": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "universalCallback": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "universalCore": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ReadSpec": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "{\n chainId: string;\n chainNamespace: string;\n owner: `0x${string}`;\n}" + }, + "blockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "expiryPushChainHeight": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "minConfirmations": { + "optional": false, + "readonly": false, + "type": "number" + }, + "query": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "revertRecipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ReadSpecTuple": { + "type": "readonly [\n readonly [\n string,\n string,\n `0x${string}`\n ],\n `0x${string}`,\n number,\n bigint,\n bigint,\n bigint,\n `0x${string}`\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "readonly [\n string,\n string,\n `0x${string}`\n]" + }, + "1": { + "optional": false, + "readonly": true, + "type": "`0x${string}`" + }, + "2": { + "optional": false, + "readonly": true, + "type": "number" + }, + "3": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "4": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "5": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "6": { + "optional": false, + "readonly": true, + "type": "`0x${string}`" + }, + "length": { + "optional": false, + "readonly": true, + "type": "7" + } + } + }, + "BuildReadSpecParams": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").BuildReadSpecParams", + "members": { + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "budgetBuffer": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback | undefined" + }, + "callbackBudget": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "destination": { + "optional": false, + "readonly": false, + "type": "{\n chain: import(\"sdk/src/lib/read-state/read-state.types\").ReadChain;\n} | {\n chainId: string;\n chainNamespace: string;\n}" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "expiryPushChainHeight": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFeeBufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "owner": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "query": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").SvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "PreparedRead": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead", + "members": { + "__@preparedReadValue": { + "optional": true, + "readonly": true, + "type": "T | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback | undefined" + }, + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "encodedQuery": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery" + }, + "encodedSpec": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "fees": { + "optional": false, + "readonly": false, + "type": "{\n callbackBudget: bigint;\n protocolFee: bigint;\n total: bigint;\n}" + }, + "preflight": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "queryKey": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "resultShape": { + "optional": false, + "readonly": false, + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}" + }, + "spec": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec" + }, + "specTuple": { + "optional": false, + "readonly": false, + "type": "readonly [\n readonly [\n string,\n string,\n `0x${string}`\n ],\n `0x${string}`,\n number,\n bigint,\n bigint,\n bigint,\n `0x${string}`\n]" + }, + "value": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "warnings": { + "optional": false, + "readonly": false, + "type": "string[]" + } + } + }, + "ReadCallback": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "((spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpecTuple, callbackGasLimit: bigint) => readonly unknown[]) | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "gasLimit": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "target": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "SimulateReadResult": { + "type": "{\n args?: readonly unknown[];\n error: string;\n errorName?: string;\n ok: false;\n} | {\n ok: true;\n}", + "members": { + "ok": { + "optional": false, + "readonly": false, + "type": "boolean" + } + } + }, + "ParsedReadRequest": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ParsedReadRequest", + "members": { + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackTarget": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "logIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "originalFunder": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "requestId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "requestIdUint": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "spec": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec" + }, + "totalPaid": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "FulfilOutcome": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").FulfilOutcome", + "members": { + "burned": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "delivered": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "expired": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "failReason": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "gasReported": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refunded": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refundFailed": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "ReceiptLike": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike", + "members": { + "logs": { + "optional": false, + "readonly": false, + "type": "readonly {\n address: string;\n data: string;\n logIndex?: number | string;\n topics: readonly string[];\n}[]" + } + } + }, + "ReadRef": { + "type": "{\n requestId: `0x${string}` | bigint;\n} | {\n txHash: `0x${string}`;\n}", + "members": {} + }, + "ReadLifecycleOptions": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadLifecycleOptions", + "members": { + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "resultShape": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadFees": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadFees", + "members": { + "burned": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "paid": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "refunded": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refundFailed": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + } + } + }, + "UniversalReadResponse": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse", + "members": { + "callbackDelivered": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "callbackFailReason": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "decoded": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").DecodedReadResult | undefined" + }, + "decodeError": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destination": { + "optional": false, + "readonly": false, + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}" + }, + "errorMsg": { + "optional": false, + "readonly": false, + "type": "string" + }, + "explorerUrl": { + "optional": false, + "readonly": false, + "type": "string" + }, + "fees": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadFees" + }, + "isTerminal": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "outcome": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME" + }, + "pcTx": { + "optional": false, + "readonly": false, + "type": "readonly {\n blockHeight: number;\n errorMsg: string;\n status: string;\n txHash: `0x${string}`;\n}[]" + }, + "raw": { + "optional": false, + "readonly": false, + "type": "{\n errorCode: import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n resultData: `0x${string}`;\n status: import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n} | null" + }, + "refresh": { + "optional": false, + "readonly": false, + "type": "() => Promise>" + }, + "request": { + "optional": false, + "readonly": false, + "type": "{\n callbackGasLimit: bigint;\n callbackTarget: `0x${string}`;\n createdAtHeight: bigint;\n logIndex: number;\n originalFunder: `0x${string}`;\n refundTo: `0x${string}`;\n spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec;\n}" + }, + "requestId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "requestIdUint": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "status": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "value": { + "optional": true, + "readonly": false, + "type": "T | undefined" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/read-state/read-state.types\").ReadLifecycleOptions) => Promise>" + } + } + }, + "ReadResponseTuple": { + "type": "{\n -readonly [K in keyof R]: import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse ? T : unknown>;\n}", + "members": {} + }, + "BatchReadResponse": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").BatchReadResponse", + "members": { + "atomic": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "count": { + "optional": false, + "readonly": false, + "type": "number" + }, + "reads": { + "optional": false, + "readonly": false, + "type": "{\n -readonly [K in keyof R]: import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse ? T : unknown>;\n}" + }, + "transactionHashes": { + "optional": true, + "readonly": false, + "type": "readonly `0x${string}`[] | undefined" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: Omit) => Promise>" + } + } + }, + "ReadOptions": { + "type": "((import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">)) & {\n callback?: (Pick & Required>) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n };\n}", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "advanced": { + "optional": true, + "readonly": false, + "type": "{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n} | undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "({\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} & {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n}) | ({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick & Pick & Required>) | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadPrepareOptions": { + "type": "((((({\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\">) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n}) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">)) & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n}) | ((({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n}) | ({\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\">)) & {\n blockNumber?: never;\n minConfirmations?: never;\n})) & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n}) & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "advanced": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadQueryOptions": { + "type": "({\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\">) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n}) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n}) | ({\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\">)", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadCallbackOptions": { + "type": "{\n callback?: ({\n gasLimit?: bigint;\n target: `0x${string}`;\n } & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n };\n}", + "members": { + "callback": { + "optional": true, + "readonly": false, + "type": "({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} | undefined" + } + } + }, + "ReadValue": { + "type": "O extends {\n abi: infer A extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: infer F extends string;\n} ? number extends A[\"length\"] ? unknown : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, O extends {\n args: infer Args extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n} ? Args : readonly [\n] extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> ? import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> & readonly [\n] : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>> extends infer Selected ? Selected extends {\n outputs: readonly unknown[];\n type: \"function\";\n} & import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiFunction ? {\n [key in keyof {\n [key in keyof import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"]]: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterToPrimitiveType, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"][key], import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterKind>;\n }]: {\n [key in keyof import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"]]: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterToPrimitiveType, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"][key], import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterKind>;\n }[key];\n} extends infer types ? types extends readonly [\n] ? void : types extends readonly [\n infer type\n] ? type : types : never : never : never : O extends {\n web2: {\n extract: infer E extends readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n };\n} ? {\n readonly [K in keyof E]: {\n bool: boolean;\n bytes: `0x${string}`;\n int256: bigint;\n string: string;\n uint256: bigint;\n }[E[K][\"valueType\"]];\n} : O extends {\n storageSlot: unknown;\n} ? `0x${string}` : O extends {\n idl: infer I extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} ? string extends Extract, string> ? unknown : (O extends {\n functionName: infer N extends string;\n} ? N : undefined) extends string ? import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/index\").IdlAccounts[{\n [K in Extract, string>]: Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : K> extends Lowercase<(O extends {\n functionName: infer N extends string;\n } ? N : undefined) & string extends `${infer H}_${infer T}` ? `${H}${Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : (O extends {\n functionName: infer N extends string;\n } ? N : undefined) & string> ? K : never;\n}[Extract, string>]] : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/index\").IdlAccounts[Extract, string>] : bigint", + "members": {} + }, + "ValidateReadCall": { + "type": "O extends {\n abi: infer A extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: infer F extends string;\n} ? (readonly [\n] extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> ? {\n args?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n} : {\n args: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n}) & {\n functionName: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionName;\n} : O extends {\n functionName: infer N extends string;\n idl: infer I extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} ? string extends Extract, string> ? unknown : [\n {\n [K in Extract, string>]: Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : K> extends Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : N> ? K : never;\n }[Extract, string>]\n] extends [\n never\n] ? {\n functionName: Extract, string>;\n} : unknown : unknown", + "members": {} + }, + "ReadWeb2Options": { + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options", + "members": { + "body": { + "optional": true, + "readonly": false, + "type": "string | Uint8Array | undefined" + }, + "extract": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[]" + }, + "headers": { + "optional": true, + "readonly": false, + "type": "Record | undefined" + }, + "method": { + "optional": true, + "readonly": false, + "type": "\"GET\" | \"POST\" | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadTrackOptions": { + "type": "{\n advanced?: Omit, \"enforceGasCheck\">;\n resultShape?: import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape;\n}", + "members": { + "advanced": { + "optional": true, + "readonly": false, + "type": "Omit<{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n}, \"enforceGasCheck\"> | undefined" + }, + "resultShape": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape | undefined" + } + } + }, + "ReadExecuteOptions": { + "type": "{\n advanced?: {\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n } | undefined;\n progressHook?: ((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined;\n waitForCompletion?: boolean | undefined;\n}", + "members": { + "advanced": { + "optional": true, + "readonly": false, + "type": "{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n} | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + } + } + }, + "UNIVERSAL_READ_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS", + "members": { + "ABORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.ABORTED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.EXPIRED" + }, + "FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.FAILED" + }, + "FULFILLED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.FULFILLED" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.PENDING" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.UNSPECIFIED" + }, + "VOTING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.VOTING" + } + } + }, + "READ_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS", + "members": { + "ERROR": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.ERROR" + }, + "SUCCESS": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.SUCCESS" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.UNSPECIFIED" + } + } + }, + "READ_ERROR_CODE": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE", + "members": { + "INVALID_QUERY": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.INVALID_QUERY" + }, + "INVALID_RESULT": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.INVALID_RESULT" + }, + "NOT_FOUND": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.NOT_FOUND" + }, + "REJECTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.REJECTED" + }, + "REVERTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.REVERTED" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.UNSPECIFIED" + }, + "UNSUPPORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.UNSUPPORTED" + } + } + }, + "READ_OUTCOME": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME", + "members": { + "ABORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.ABORTED" + }, + "CALLBACK_FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.CALLBACK_FAILED" + }, + "DECODE_FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.DECODE_FAILED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.EXPIRED" + }, + "FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.FAILED" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.PENDING" + }, + "SOURCE_ERROR": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.SOURCE_ERROR" + }, + "SUCCESS": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.SUCCESS" + }, + "UNKNOWN": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.UNKNOWN" + } + } + }, + "CONTRACT_REQUEST_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS", + "members": { + "EXECUTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.EXECUTED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.EXPIRED" + }, + "NONE": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.NONE" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.PENDING" + }, + "SETTLED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.SETTLED" + } + } + }, + "TERMINAL_READ_STATUSES": { + "type": "ReadonlySet", + "members": {} + }, + "ReadStateError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadStateError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidReadQueryError": { + "type": "import(\"sdk/src/lib/read-state/errors\").InvalidReadQueryError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidReadSpecError": { + "type": "import(\"sdk/src/lib/read-state/errors\").InvalidReadSpecError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "violations": { + "optional": false, + "readonly": true, + "type": "readonly import(\"sdk/src/lib/read-state/errors\").ReadSpecViolation[]" + } + } + }, + "ReadHeightUnavailableError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadHeightUnavailableError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "UnsupportedReadDestinationError": { + "type": "import(\"sdk/src/lib/read-state/errors\").UnsupportedReadDestinationError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadDecodeError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadDecodeError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadTimeoutError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadTimeoutError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "lastStatus": { + "optional": false, + "readonly": true, + "type": "number" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadNotFoundError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadNotFoundError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadRegistryUnavailableError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadRegistryUnavailableError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadSpecViolation": { + "type": "\"CALLBACK_GAS_LIMIT_EXCEEDED\" | \"DOMAIN_BLOCKED\" | \"EMPTY_QUERY\" | \"EXCESSIVE_FEE\" | \"INSUFFICIENT_CALLBACK_BUDGET\" | \"INSUFFICIENT_FEE\" | \"INVALID_ACCOUNT_ID\" | \"INVALID_BLOCK_NUMBER\" | \"INVALID_EXPIRY_HEIGHT\" | \"INVALID_MIN_CONFIRMATIONS\" | \"SVM_OWNER_NOT_32_BYTES\" | \"ZERO_CALLBACK_BUDGET\" | \"ZERO_CALLBACK_GAS_LIMIT\" | \"ZERO_REVERT_RECIPIENT\"", + "members": {} + }, + "resolveDestination": { + "type": "(dest: import(\"sdk/src/lib/read-state/read-state.types\").ReadDestination) => import(\"sdk/src/lib/read-state/read-state.types\").ResolvedDestination", + "members": {} + }, + "encodeReadQuery": { + "type": "(destination: import(\"sdk/src/lib/read-state/read-state.types\").ReadDestination, query: import(\"sdk/src/lib/read-state/read-state.types\").ReadQuery, options?: {\n blockNumber?: bigint;\n minSlot?: bigint;\n}) => import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery", + "members": {} + }, + "decodeReadResult": { + "type": "(resultData: `0x${string}`, shape: import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape) => import(\"sdk/src/lib/read-state/read-state.types\").DecodedReadResult", + "members": {} + }, + "parseReadRequestsFromReceipt": { + "type": "(receipt: import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike, universalCallback: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").ParsedReadRequest[]", + "members": {} + }, + "parseFulfilOutcome": { + "type": "(receipt: import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike, universalCallback: `0x${string}`, requestId: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").FulfilOutcome", + "members": {} + }, + "buildReadSpecFromPreflight": { + "type": "(preflight: import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight, params: import(\"sdk/src/lib/read-state/read-state.types\").BuildReadSpecParams, defaults?: {\n refundTo?: `0x${string}`;\n}) => import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead", + "members": {} + }, + "validateReadSpec": { + "type": "(input: import(\"sdk/src/lib/read-state/validate\").ValidateReadSpecInput) => {\n ok: false;\n violations: import(\"sdk/src/lib/read-state/errors\").ReadSpecViolation[];\n} | {\n ok: true;\n}", + "members": {} + }, + "toCallData": { + "type": "(prepared: import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead, target: {\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: (spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpecTuple, callbackGasLimit: bigint) => readonly unknown[];\n functionName: string;\n}) => {\n data: `0x${string}`;\n value: bigint;\n}", + "members": {} + }, + "sizeCallbackBudget": { + "type": "(callbackGasLimit: bigint, pushGasPrice: bigint, buffer?: number) => bigint", + "members": {} + }, + "inferResultShape": { + "type": "(namespace: string, query: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape", + "members": {} + }, + "toRequestIdHex": { + "type": "(id: `0x${string}` | bigint) => `0x${string}`", + "members": {} + }, + "toReadQuery": { + "type": "(subject: string, o: ReadOptionsInput, resolvedTokenProgram?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@solana/web3.js/lib/index\").PublicKey) => import(\"sdk/src/lib/read-state/read-state.types\").ReadQuery", + "members": {} + }, + "UNIVERSAL_CALLBACK_EVM": { + "type": "readonly [\n {\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"requestExternalReadSelf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"estimateFee\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"statusOf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"enum RequestStatus\";\n readonly name: \"\";\n readonly type: \"uint8\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"isFulfilled\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getPendingRead\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly internalType: \"struct PendingRead\";\n readonly name: \"\";\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"totalEscrowed\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"blockedDomains\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly indexed: false;\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"readSpec\";\n readonly type: \"tuple\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"totalPaid\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"protocolFee\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ReadRequested\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"ReadFulfilled\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"reason\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"CallbackFailed\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"gasReported\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"burned\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"CallbackGasReported\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundSent\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundFailed\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RequestExpired\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"vaultPC\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ProtocolFeeDistributed\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidAccountId\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"EmptyQuery\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidMinConfirmations\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"DomainBlocked\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidBlockNumber\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidExpiryHeight\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroRevertRecipient\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroCallbackGasLimit\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint64\";\n readonly name: \"provided\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"max\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"CallbackGasLimitExceeded\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"required\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"InsufficientFee\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ExcessiveFee\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"actual\";\n readonly type: \"uint8\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"expected\";\n readonly type: \"uint8\";\n }\n ];\n readonly name: \"InvalidRequestStatus\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ContractIsPaused\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"CallerIsNotUCallbackModule\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n }\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"requestExternalReadSelf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n}" + }, + "1": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"estimateFee\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "2": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"statusOf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"enum RequestStatus\";\n readonly name: \"\";\n readonly type: \"uint8\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "3": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"isFulfilled\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "4": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getPendingRead\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly internalType: \"struct PendingRead\";\n readonly name: \"\";\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "5": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"totalEscrowed\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "6": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"blockedDomains\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "7": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly indexed: false;\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"readSpec\";\n readonly type: \"tuple\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"totalPaid\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"protocolFee\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ReadRequested\";\n readonly type: \"event\";\n}" + }, + "8": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"ReadFulfilled\";\n readonly type: \"event\";\n}" + }, + "9": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"reason\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"CallbackFailed\";\n readonly type: \"event\";\n}" + }, + "10": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"gasReported\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"burned\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"CallbackGasReported\";\n readonly type: \"event\";\n}" + }, + "11": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundSent\";\n readonly type: \"event\";\n}" + }, + "12": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundFailed\";\n readonly type: \"event\";\n}" + }, + "13": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RequestExpired\";\n readonly type: \"event\";\n}" + }, + "14": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"vaultPC\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ProtocolFeeDistributed\";\n readonly type: \"event\";\n}" + }, + "15": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidAccountId\";\n readonly type: \"error\";\n}" + }, + "16": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"EmptyQuery\";\n readonly type: \"error\";\n}" + }, + "17": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidMinConfirmations\";\n readonly type: \"error\";\n}" + }, + "18": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"DomainBlocked\";\n readonly type: \"error\";\n}" + }, + "19": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidBlockNumber\";\n readonly type: \"error\";\n}" + }, + "20": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidExpiryHeight\";\n readonly type: \"error\";\n}" + }, + "21": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroRevertRecipient\";\n readonly type: \"error\";\n}" + }, + "22": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroCallbackGasLimit\";\n readonly type: \"error\";\n}" + }, + "23": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint64\";\n readonly name: \"provided\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"max\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"CallbackGasLimitExceeded\";\n readonly type: \"error\";\n}" + }, + "24": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"required\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"InsufficientFee\";\n readonly type: \"error\";\n}" + }, + "25": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ExcessiveFee\";\n readonly type: \"error\";\n}" + }, + "26": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"actual\";\n readonly type: \"uint8\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"expected\";\n readonly type: \"uint8\";\n }\n ];\n readonly name: \"InvalidRequestStatus\";\n readonly type: \"error\";\n}" + }, + "27": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ContractIsPaused\";\n readonly type: \"error\";\n}" + }, + "28": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"CallerIsNotUCallbackModule\";\n readonly type: \"error\";\n}" + }, + "29": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n}" + }, + "length": { + "optional": false, + "readonly": true, + "type": "30" + } + } + }, + "UNIVERSAL_READ_REGISTRY_EVM": { + "type": "readonly [\n {\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n },\n {\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"read\";\n readonly outputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"universalCallback_\";\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"constructor\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"initialize\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getLocalContext\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"hasResult\";\n readonly outputs: readonly [\n {\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"onUniversalData\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"queryKeyOf\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes32\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"readerOf\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"requestOrderOf\";\n readonly outputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"universalCallback\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"resultByRequestId\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"latestResult\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"version\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"Initialized\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadRequested\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadStored\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidInitialization\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"NotInitializing\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroAddressInit\";\n readonly type: \"error\";\n }\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n },\n {\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"read\";\n readonly outputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n}" + }, + "1": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"universalCallback_\";\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"constructor\";\n}" + }, + "2": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"initialize\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n}" + }, + "3": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getLocalContext\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "4": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"hasResult\";\n readonly outputs: readonly [\n {\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "5": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"onUniversalData\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n}" + }, + "6": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"queryKeyOf\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes32\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "7": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"readerOf\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "8": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"requestOrderOf\";\n readonly outputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "9": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"universalCallback\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "10": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"resultByRequestId\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "11": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"latestResult\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "12": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"version\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"Initialized\";\n readonly type: \"event\";\n}" + }, + "13": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadRequested\";\n readonly type: \"event\";\n}" + }, + "14": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadStored\";\n readonly type: \"event\";\n}" + }, + "15": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidInitialization\";\n readonly type: \"error\";\n}" + }, + "16": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"NotInitializing\";\n readonly type: \"error\";\n}" + }, + "17": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n}" + }, + "18": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroAddressInit\";\n readonly type: \"error\";\n}" + }, + "length": { + "optional": false, + "readonly": true, + "type": "19" + } + } + }, + "PushChainExecutionError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").PushChainExecutionError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PushChainBatchExecutionError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").PushChainBatchExecutionError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": false, + "readonly": true, + "type": "`0x${string}`[]" + } + } + }, + "DecodedErrorPayload": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload", + "members": { + "decoded": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "name": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "selector": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "PushChainInitializeOptions": { + "type": "import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions", + "members": { + "agenticWallet": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "blockExplorers": { + "optional": true, + "readonly": false, + "type": "Partial> | undefined" + }, + "network": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "printTraces": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "rpcUrls": { + "optional": true, + "readonly": false, + "type": "Partial> | undefined" + } + } + }, + "AGENTIC_ERROR_CODE": { + "type": "{\n readonly AGENT_GAS_INSUFFICIENT: \"AGENT_GAS_INSUFFICIENT\";\n readonly AGENT_IS_OWNER: \"AGENT_IS_OWNER\";\n readonly ASSET_CHAIN_MISMATCH: \"ASSET_CHAIN_MISMATCH\";\n readonly CAPABILITY_UNAVAILABLE: \"CAPABILITY_UNAVAILABLE\";\n readonly CREATE_PARTIAL: \"CREATE_PARTIAL\";\n readonly DUPLICATE_RULE: \"DUPLICATE_RULE\";\n readonly FROM_NOT_ALLOWED: \"FROM_NOT_ALLOWED\";\n readonly GATEWAY_ALLOWANCE_INSUFFICIENT: \"GATEWAY_ALLOWANCE_INSUFFICIENT\";\n readonly GENERATION_UNSUPPORTED: \"GENERATION_UNSUPPORTED\";\n readonly INCONSISTENT_READ: \"INCONSISTENT_READ\";\n readonly INDEX_RACE: \"INDEX_RACE\";\n readonly INVALID_RULE: \"INVALID_RULE\";\n readonly NO_RULES_FOR_CHAIN: \"NO_RULES_FOR_CHAIN\";\n readonly NOT_AGENTIC_WALLET: \"NOT_AGENTIC_WALLET\";\n readonly NOT_ALLOWED_IN_AGENTIC_MODE: \"NOT_ALLOWED_IN_AGENTIC_MODE\";\n readonly NOT_OWNER_OR_AGENT: \"NOT_OWNER_OR_AGENT\";\n readonly NOT_WALLET_OWNER: \"NOT_WALLET_OWNER\";\n readonly READ_ONLY: \"READ_ONLY\";\n readonly RECEIPT_MISMATCH: \"RECEIPT_MISMATCH\";\n readonly RECEIPT_UNAVAILABLE: \"RECEIPT_UNAVAILABLE\";\n readonly REVOKE_NEEDS_TARGET: \"REVOKE_NEEDS_TARGET\";\n readonly RULE_LIMIT_EXCEEDED: \"RULE_LIMIT_EXCEEDED\";\n readonly RULE_NOT_FOUND: \"RULE_NOT_FOUND\";\n readonly RULE_READ_FAILED: \"RULE_READ_FAILED\";\n readonly TARGET_NOT_ON_RULE_CHAIN: \"TARGET_NOT_ON_RULE_CHAIN\";\n readonly WALLET_BALANCE_INSUFFICIENT: \"WALLET_BALANCE_INSUFFICIENT\";\n readonly WALLET_NOT_DEPLOYED: \"WALLET_NOT_DEPLOYED\";\n}", + "members": { + "AGENT_GAS_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\"" + }, + "AGENT_IS_OWNER": { + "optional": false, + "readonly": true, + "type": "\"AGENT_IS_OWNER\"" + }, + "ASSET_CHAIN_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"ASSET_CHAIN_MISMATCH\"" + }, + "CAPABILITY_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"CAPABILITY_UNAVAILABLE\"" + }, + "CREATE_PARTIAL": { + "optional": false, + "readonly": true, + "type": "\"CREATE_PARTIAL\"" + }, + "DUPLICATE_RULE": { + "optional": false, + "readonly": true, + "type": "\"DUPLICATE_RULE\"" + }, + "FROM_NOT_ALLOWED": { + "optional": false, + "readonly": true, + "type": "\"FROM_NOT_ALLOWED\"" + }, + "GATEWAY_ALLOWANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"GATEWAY_ALLOWANCE_INSUFFICIENT\"" + }, + "GENERATION_UNSUPPORTED": { + "optional": false, + "readonly": true, + "type": "\"GENERATION_UNSUPPORTED\"" + }, + "INCONSISTENT_READ": { + "optional": false, + "readonly": true, + "type": "\"INCONSISTENT_READ\"" + }, + "INDEX_RACE": { + "optional": false, + "readonly": true, + "type": "\"INDEX_RACE\"" + }, + "INVALID_RULE": { + "optional": false, + "readonly": true, + "type": "\"INVALID_RULE\"" + }, + "NO_RULES_FOR_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"NO_RULES_FOR_CHAIN\"" + }, + "NOT_AGENTIC_WALLET": { + "optional": false, + "readonly": true, + "type": "\"NOT_AGENTIC_WALLET\"" + }, + "NOT_ALLOWED_IN_AGENTIC_MODE": { + "optional": false, + "readonly": true, + "type": "\"NOT_ALLOWED_IN_AGENTIC_MODE\"" + }, + "NOT_OWNER_OR_AGENT": { + "optional": false, + "readonly": true, + "type": "\"NOT_OWNER_OR_AGENT\"" + }, + "NOT_WALLET_OWNER": { + "optional": false, + "readonly": true, + "type": "\"NOT_WALLET_OWNER\"" + }, + "READ_ONLY": { + "optional": false, + "readonly": true, + "type": "\"READ_ONLY\"" + }, + "RECEIPT_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_MISMATCH\"" + }, + "RECEIPT_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_UNAVAILABLE\"" + }, + "REVOKE_NEEDS_TARGET": { + "optional": false, + "readonly": true, + "type": "\"REVOKE_NEEDS_TARGET\"" + }, + "RULE_LIMIT_EXCEEDED": { + "optional": false, + "readonly": true, + "type": "\"RULE_LIMIT_EXCEEDED\"" + }, + "RULE_NOT_FOUND": { + "optional": false, + "readonly": true, + "type": "\"RULE_NOT_FOUND\"" + }, + "RULE_READ_FAILED": { + "optional": false, + "readonly": true, + "type": "\"RULE_READ_FAILED\"" + }, + "TARGET_NOT_ON_RULE_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"TARGET_NOT_ON_RULE_CHAIN\"" + }, + "WALLET_BALANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"WALLET_BALANCE_INSUFFICIENT\"" + }, + "WALLET_NOT_DEPLOYED": { + "optional": false, + "readonly": true, + "type": "\"WALLET_NOT_DEPLOYED\"" + } + } + }, + "AgenticError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"CREATE_PARTIAL\" | \"DUPLICATE_RULE\" | \"FROM_NOT_ALLOWED\" | \"GATEWAY_ALLOWANCE_INSUFFICIENT\" | \"GENERATION_UNSUPPORTED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"REVOKE_NEEDS_TARGET\" | \"RULE_LIMIT_EXCEEDED\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"" + }, + "details": { + "optional": true, + "readonly": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "AgenticRevertError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticRevertError", + "members": { + "agenticCode": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + } + } + }, + "AgenticAddress": { + "type": "`0x${string}`", + "members": {} + }, + "AgenticDoor": { + "type": "\"agent\" | \"owner\"", + "members": {} + }, + "AgenticErrorCode": { + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"CREATE_PARTIAL\" | \"DUPLICATE_RULE\" | \"FROM_NOT_ALLOWED\" | \"GATEWAY_ALLOWANCE_INSUFFICIENT\" | \"GENERATION_UNSUPPORTED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"REVOKE_NEEDS_TARGET\" | \"RULE_LIMIT_EXCEEDED\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"", + "members": {} + }, + "AgenticHex": { + "type": "`0x${string}`", + "members": {} + }, + "AgenticNamespace": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace", + "members": { + "create": { + "optional": false, + "readonly": false, + "type": "(label: string, options: import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions) => Promise" + }, + "derive": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n index?: number;\n}) => Promise<{\n address: `0x${string}`;\n deployed: boolean;\n index: number;\n}>" + }, + "list": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n wallets: import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary[];\n}>" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "(address: `0x${string}`) => import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet" + } + } + }, + "AgenticNetworkConstants": { + "type": "import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants", + "members": { + "ENVELOPE_VERSION": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "FACTORY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "MAX_ALLOWED_CALLS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "MAX_PINS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "RULES_POLICY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticProgressHook": { + "type": "(event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void", + "members": {} + }, + "AgenticTxMetadata": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticTxMetadata", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destinationAccount": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "destinationCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "door": { + "optional": false, + "readonly": false, + "type": "\"agent\" | \"owner\"" + }, + "nativeCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "rawData": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rawTo": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesId": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticWallet": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "checkpoints": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n sinceBlock?: bigint;\n}) => Promise<{\n checkpoints: import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint[];\n}>" + }, + "info": { + "optional": false, + "readonly": false, + "type": "() => Promise" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n owner: `0x${string}`;\n}>" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "{\n add(rules: import(\"sdk/src/lib/agentic/agentic.types\").Rule[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise<{\n rulesIds: `0x${string}`[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n get(rulesId: `0x${string}`): Promise;\n list(): Promise<{\n rules: import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord[];\n }>;\n revoke(rulesIds: `0x${string}`[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n revoke(params: {\n all: true;\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n update(params: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n rules: {\n rule: import(\"sdk/src/lib/agentic/agentic.types\").Rule;\n rulesId: `0x${string}`;\n }[];\n }): Promise<{\n rules: {\n replaced: `0x${string}`;\n rulesId: `0x${string}`;\n }[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n}" + }, + "setLabel": { + "optional": false, + "readonly": false, + "type": "(label: string, opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n}) => Promise" + } + } + }, + "AllowedCall": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall", + "members": { + "beneficiary": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValue": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "`${string}(${string})` | `0x${string}`" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AssetCap": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap", + "members": { + "maxPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/constants/tokens\").MoveableToken" + } + } + }, + "Checkpoint": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint", + "members": { + "blockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "kind": { + "optional": false, + "readonly": false, + "type": "\"OWNER_ACTION\" | \"RULES_GRANTED\" | \"RULES_REVOKED\"" + }, + "ref": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "seq": { + "optional": false, + "readonly": false, + "type": "number" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "CheckpointKind": { + "type": "\"OWNER_ACTION\" | \"RULES_GRANTED\" | \"RULES_REVOKED\"", + "members": {} + }, + "CreateOptions": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions", + "members": { + "progressHook": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook | undefined" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Rule[]" + } + } + }, + "CreateResult": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateResult", + "members": { + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "rulesIds": { + "optional": false, + "readonly": false, + "type": "`0x${string}`[]" + }, + "tx": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ForeignChainNamespace": { + "type": "`eip155:${string}` | `solana:${string}`", + "members": {} + }, + "NativeRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "amount": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AmountLimit | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "maxCalls": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValuePerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxValueTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "pins": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ArgPin[] | undefined" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Rule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule | import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "RulesRecord": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "enabled": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "ref": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "rule": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule | import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule" + }, + "rulesId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Selector": { + "type": "`${string}(${string})` | `0x${string}`", + "members": {} + }, + "UniversalRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall[]" + }, + "assets": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap[]" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "`eip155:${string}` | `solana:${string}`" + }, + "maxGasPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "WalletInfo": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").WalletInfo", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "label": { + "optional": false, + "readonly": false, + "type": "string" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "rulesCount": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "WalletSummary": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "label": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesCount": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "PushChain": { + "type": "import(\"sdk/src/lib/push-chain/push-chain\").PushChain", + "members": { + "accountStatus": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus" + }, + "accountStatusReady": { + "optional": false, + "readonly": false, + "type": "Promise" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace" + }, + "explorer": { + "optional": false, + "readonly": false, + "type": "{\n getTransactionUrl: (txHash: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n listAllUrls: () => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n listUrls: (options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n}" + }, + "funds": { + "optional": false, + "readonly": false, + "type": "{\n getConversionQuote: (amountIn: bigint, options: {\n from: import(\"sdk/src/lib/constants/tokens\").PayableToken | undefined;\n to: import(\"sdk/src/lib/constants/tokens\").MoveableToken | undefined;\n }) => Promise;\n}" + }, + "getAccountStatus": { + "optional": false, + "readonly": false, + "type": "(options?: {\n forceRefresh?: boolean;\n}) => Promise" + }, + "isReadMode": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "moveable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").MoveableTokenAccessor;\n}" + }, + "payable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").PayableTokenAccessor;\n}" + }, + "reinitialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "universal": { + "optional": false, + "readonly": false, + "type": "{\n readonly account: `0x${string}`;\n executeReads: (reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>;\n executeTransactions: (txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise;\n migrateCEA: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"migrateCEA\"];\n readonly origin: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n prepareRead: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n prepareTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"prepareTransaction\"];\n read: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n rescueFunds: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"rescueFunds\"];\n sendTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"execute\"];\n signMessage: (data: Uint8Array) => Promise;\n signTypedData: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n trackRead: {\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n };\n trackTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"trackTransaction\"];\n}" + }, + "upgradeAccount": { + "optional": false, + "readonly": false, + "type": "(options?: {\n progressHook?: (progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n}) => Promise" + } + } + } + }, + "pushChainStatic": { + "CONSTANTS": { + "optional": false, + "readonly": false, + "type": "{\n AGENTIC: Readonly>>;\n CHAIN: typeof import(\"sdk/src/lib/constants/enums\").CHAIN;\n LIBRARY: typeof import(\"sdk/src/lib/constants/enums\").LIBRARY;\n MOVEABLE: {\n TOKEN: import(\"sdk/src/lib/constants/tokens\").MoveableTokenConstantsMap;\n };\n PAYABLE: {\n TOKEN: import(\"sdk/src/lib/constants/tokens\").PayableTokenConstantsMap;\n };\n PUSH_NETWORK: typeof import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n READ: {\n readonly CALLBACK_BUDGET_BUFFER: 3;\n readonly CHAIN: {\n readonly WEB2: \"web2\";\n } & Readonly<{\n readonly ARBITRUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA;\n readonly BASE_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA;\n readonly BNB_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET;\n readonly ETHEREUM_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET;\n readonly ETHEREUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA;\n readonly PUSH_LOCALNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET;\n readonly PUSH_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET;\n readonly PUSH_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly PUSH_TESTNET_DONUT: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly SOLANA_DEVNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET;\n readonly SOLANA_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET;\n readonly SOLANA_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n readonly WEB2: \"web2\";\n }>;\n readonly DEFAULT_EXPIRY_BLOCKS: 300n;\n readonly ERROR_CODE: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n readonly MAX_CALLBACK_GAS_LIMIT: 1000000n;\n readonly MIN_CONFIRMATIONS_FLOOR: 1;\n readonly NAMESPACE: {\n readonly EVM: \"eip155\";\n readonly SVM: \"solana\";\n readonly WEB2: \"web2\";\n };\n readonly OUTCOME: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME;\n readonly REGISTRY_CALLBACK_GAS: 500000n;\n readonly RESULT_STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n readonly STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS;\n readonly UNIVERSAL_CALLBACK_ADDRESSES: Record;\n readonly UNIVERSAL_CORE_ADDRESSES: Record;\n readonly UNIVERSAL_READ_REGISTRY_ADDRESS: {\n readonly TESTNET_DONUT: \"0x00000000000000000000000000000000000000b2\";\n };\n readonly WEB2: \"web2\";\n readonly WEB2_DEFAULT_TIMEOUT_MS: 5000;\n readonly WEB2_MAX_EXTRACT_ENTRIES: 16;\n };\n}" + }, + "initialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "utils": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/utils\").Utils" + } + }, + "pushChainInstance": { + "accountStatus": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus" + }, + "accountStatusReady": { + "optional": false, + "readonly": false, + "type": "Promise" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace" + }, + "explorer": { + "optional": false, + "readonly": false, + "type": "{\n getTransactionUrl: (txHash: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n listAllUrls: () => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n listUrls: (options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n}" + }, + "funds": { + "optional": false, + "readonly": false, + "type": "{\n getConversionQuote: (amountIn: bigint, options: {\n from: import(\"sdk/src/lib/constants/tokens\").PayableToken | undefined;\n to: import(\"sdk/src/lib/constants/tokens\").MoveableToken | undefined;\n }) => Promise;\n}" + }, + "getAccountStatus": { + "optional": false, + "readonly": false, + "type": "(options?: {\n forceRefresh?: boolean;\n}) => Promise" + }, + "isReadMode": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "moveable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").MoveableTokenAccessor;\n}" + }, + "payable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").PayableTokenAccessor;\n}" + }, + "reinitialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "universal": { + "optional": false, + "readonly": false, + "type": "{\n readonly account: `0x${string}`;\n executeReads: (reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>;\n executeTransactions: (txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise;\n migrateCEA: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"migrateCEA\"];\n readonly origin: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n prepareRead: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n prepareTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"prepareTransaction\"];\n read: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n rescueFunds: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"rescueFunds\"];\n sendTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"execute\"];\n signMessage: (data: Uint8Array) => Promise;\n signTypedData: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n trackRead: {\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n };\n trackTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"trackTransaction\"];\n}" + }, + "upgradeAccount": { + "optional": false, + "readonly": false, + "type": "(options?: {\n progressHook?: (progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n}) => Promise" + } + }, + "transactionMethods": { + "account": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "executeReads": { + "optional": false, + "readonly": false, + "type": "(reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>" + }, + "executeTransactions": { + "optional": false, + "readonly": false, + "type": "(txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise" + }, + "migrateCEA": { + "optional": false, + "readonly": false, + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => Promise" + }, + "origin": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "prepareRead": { + "optional": false, + "readonly": false, + "type": "(subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>" + }, + "prepareTransaction": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions) => Promise" + }, + "read": { + "optional": false, + "readonly": false, + "type": "(subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>" + }, + "rescueFunds": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").RescueFundsParams) => Promise" + }, + "sendTransaction": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").ExecuteParams | import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions) => Promise" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": false, + "readonly": false, + "type": "({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise" + }, + "trackRead": { + "optional": false, + "readonly": false, + "type": "{\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n}" + }, + "trackTransaction": { + "optional": false, + "readonly": false, + "type": "(txHash: string, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TrackTransactionOptions) => Promise" + } + }, + "utilityMethods": { + "account": { + "optional": false, + "readonly": false, + "type": "{\n convertExecutorToOriginAccount: (ueaAddress: `0x${string}`, options?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n }) => Promise;\n convertOriginToExecutor: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n onlyCompute?: boolean;\n }) => Promise;\n deriveExecutorAccount: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n skipNetworkCheck?: boolean;\n }) => Promise;\n fromChainAgnostic: (caip: string) => import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n resolveControllerAccount: (address: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n skipNetworkCheck?: boolean;\n }) => Promise;\n toChainAgnostic: (address: string, options: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n toUniversal: (address: string, options: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n}" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "{\n actionId: (target: `0x${string}`, selector: \"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector) => `0x${string}`;\n configId: (wallet: `0x${string}`, rulesId: `0x${string}`, actionId: `0x${string}`) => `0x${string}`;\n decodeRules: (bytes: `0x${string}`, ctx?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n pushChainNamespace?: string;\n }) => import(\"sdk/src/lib/agentic/agentic.types\").Rule;\n}" + }, + "chains": { + "optional": false, + "readonly": false, + "type": "{\n getChainName: (chainNamespace: string) => string | undefined;\n getChainNamespace: (chainName: string) => string | undefined;\n getSupportedChains: (network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK) => {\n chains: import(\"sdk/src/lib/constants/enums\").CHAIN[];\n };\n getSupportedChainsByName: (network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK) => {\n chains: string[];\n };\n}" + }, + "conversion": { + "optional": false, + "readonly": false, + "type": "{\n slippageToMinAmount(amount: string, options: {\n slippageBps: number;\n }): string;\n}" + }, + "helpers": { + "optional": false, + "readonly": false, + "type": "{\n encodeTxData({ abi, idl, functionName, args, }: {\n abi?: any;\n args?: any[];\n functionName: string;\n idl?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n }): `0x${string}`;\n formatUnits(value: bigint | string, decimalsOrOptions: {\n decimals: number;\n precision?: number;\n } | number): string;\n getChainName: (chainName: string) => string | undefined;\n parseUnits(value: string, exponent: {\n decimals: number;\n } | number): bigint;\n}" + }, + "signer": { + "optional": false, + "readonly": false, + "type": "{\n construct: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options: {\n signAndSendTransaction: (unsignedTx: Uint8Array) => Promise;\n signAuthorization?: (params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise;\n signMessage: (data: Uint8Array) => Promise;\n signTypedData?: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n }) => import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton;\n toUniversal: (signer: import(\"sdk/src/lib/universal/universal.types\").EthersV5SignerType | import(\"sdk/src/lib/universal/universal.types\").EthersV6SignerType | import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton | import(\"sdk/src/lib/universal/universal.types\").ViemSignerType) => Promise;\n toUniversalFromKeypair: (clientOrAccount: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@solana/web3.js/lib/index\").Keypair | import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").WalletClient | import(\"sdk/src/lib/universal/universal.types\").EthersV6SignerType, { chain, library }: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n library: import(\"sdk/src/lib/constants/enums\").LIBRARY;\n }) => Promise;\n}" + }, + "svm": { + "optional": false, + "readonly": false, + "type": "{\n getRegisteredIdls: () => Array<{\n address: `0x${string}`;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n }>;\n registerIdl: (idl: unknown) => void;\n}" + }, + "tokens": { + "optional": false, + "readonly": false, + "type": "{\n getMoveableTokens(chainOrClient?: import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/push-chain/push-chain\").PushChain): {\n tokens: Array<{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n decimals: number;\n mechanism: \"approve\" | \"native\" | \"permit2\";\n prc20Address?: `0x${string}`;\n sourceChain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n symbol: string;\n }>;\n };\n getPayableTokens(chainOrClient?: import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/push-chain/push-chain\").PushChain): {\n tokens: Array<{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n decimals: number;\n mechanism: \"approve\" | \"native\" | \"permit2\";\n symbol: string;\n }>;\n };\n getPC20Address(address: string, options: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n rpcUrls?: Partial>;\n strict?: boolean;\n }): Promise;\n getPRC20Address(token: {\n address: string;\n chain: string;\n } | import(\"sdk/src/lib/constants/tokens\").MoveableToken, options?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n }): {\n address: `0x${string}`;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n decimals: number;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n symbol: string;\n };\n}" + } + }, + "initialize": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise", + "agwConstants": { + "ENVELOPE_VERSION": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "FACTORY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "MAX_ALLOWED_CALLS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "MAX_PINS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "RULES_POLICY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + }, + "constants": { + "AGENTIC": { + "optional": false, + "readonly": false, + "type": "{\n readonly LOCALNET?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n readonly MAINNET?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n readonly TESTNET?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n readonly TESTNET_DONUT?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n}" + }, + "CHAIN": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "LIBRARY": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").LIBRARY" + }, + "MOVEABLE": { + "optional": false, + "readonly": false, + "type": "{\n TOKEN: import(\"sdk/src/lib/constants/tokens\").MoveableTokenConstantsMap;\n}" + }, + "PAYABLE": { + "optional": false, + "readonly": false, + "type": "{\n TOKEN: import(\"sdk/src/lib/constants/tokens\").PayableTokenConstantsMap;\n}" + }, + "PUSH_NETWORK": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "READ": { + "optional": false, + "readonly": false, + "type": "{\n readonly CALLBACK_BUDGET_BUFFER: 3;\n readonly CHAIN: {\n readonly WEB2: \"web2\";\n } & Readonly<{\n readonly ARBITRUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA;\n readonly BASE_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA;\n readonly BNB_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET;\n readonly ETHEREUM_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET;\n readonly ETHEREUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA;\n readonly PUSH_LOCALNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET;\n readonly PUSH_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET;\n readonly PUSH_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly PUSH_TESTNET_DONUT: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly SOLANA_DEVNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET;\n readonly SOLANA_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET;\n readonly SOLANA_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n readonly WEB2: \"web2\";\n }>;\n readonly DEFAULT_EXPIRY_BLOCKS: 300n;\n readonly ERROR_CODE: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n readonly MAX_CALLBACK_GAS_LIMIT: 1000000n;\n readonly MIN_CONFIRMATIONS_FLOOR: 1;\n readonly NAMESPACE: {\n readonly EVM: \"eip155\";\n readonly SVM: \"solana\";\n readonly WEB2: \"web2\";\n };\n readonly OUTCOME: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME;\n readonly REGISTRY_CALLBACK_GAS: 500000n;\n readonly RESULT_STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n readonly STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS;\n readonly UNIVERSAL_CALLBACK_ADDRESSES: Record;\n readonly UNIVERSAL_CORE_ADDRESSES: Record;\n readonly UNIVERSAL_READ_REGISTRY_ADDRESS: {\n readonly TESTNET_DONUT: \"0x00000000000000000000000000000000000000b2\";\n };\n readonly WEB2: \"web2\";\n readonly WEB2_DEFAULT_TIMEOUT_MS: 5000;\n readonly WEB2_MAX_EXTRACT_ENTRIES: 16;\n}" + } + } + }, + "after": { + "exports": [ + "AGENTIC_ERROR_CODE", + "AccountRole", + "AccountStatus", + "AccountType", + "AgenticAddress", + "AgenticDoor", + "AgenticError", + "AgenticErrorCode", + "AgenticHex", + "AgenticNamespace", + "AgenticNetworkConstants", + "AgenticProgressHook", + "AgenticRevertError", + "AgenticTxMetadata", + "AgenticWallet", + "AllowedCall", + "AssetCap", + "BatchReadResponse", + "BuildReadSpecParams", + "CHAIN", + "CONTRACT_REQUEST_STATUS", + "CascadeCompletionResult", + "CascadeHopInfo", + "CascadeProgressEvent", + "CascadeTrackOptions", + "CascadedTxResponse", + "ChainSource", + "ChainTarget", + "Checkpoint", + "CheckpointKind", + "ConversionQuote", + "CreateOptions", + "CreateResult", + "DEFAULT_MAX_PC_FOR_GAS_BUFFER_BPS", + "DecodedErrorPayload", + "DecodedReadResult", + "DecodedSolanaRule", + "DerivedExecutorAccount", + "EncodedReadQuery", + "EvmReadQuery", + "ForeignChainNamespace", + "FulfilOutcome", + "FundsToken", + "InsufficientPC20BalanceError", + "InvalidPC20AddressError", + "InvalidPC20MetadataError", + "InvalidReadQueryError", + "InvalidReadSpecError", + "MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT", + "MaxPCForGasCapFromNativeValueInput", + "MaxPCForGasCapInput", + "MaxPCForGasCapQuote", + "MultiChainTxResponse", + "NativeRule", + "OutboundTxDetails", + "PC20AddressResult", + "PC20AmbiguousAddressError", + "PC20Error", + "PC20ExpectedButPRC20Error", + "PC20ExportRevertedError", + "PC20FactoryMismatchError", + "PC20RegistryEntry", + "PC20RegistryMismatchError", + "PC20TokenChainMismatchError", + "PC20TokenReference", + "PC20UnknownChainNamespaceError", + "PC20UnsafeEmptyPayloadError", + "PC20WrapperNotRegisteredError", + "PC20WrapperPredictionUnavailableError", + "ParsedReadRequest", + "PreparedRead", + "PreparedUniversalTx", + "PushChain", + "PushChainBatchExecutionError", + "PushChainExecutionError", + "PushChainInitializeOptions", + "READ_ERROR_CODE", + "READ_OUTCOME", + "READ_STATUS", + "ReadCallback", + "ReadCallbackOptions", + "ReadChain", + "ReadDecodeError", + "ReadDestination", + "ReadExecuteOptions", + "ReadFees", + "ReadHeightUnavailableError", + "ReadLifecycleOptions", + "ReadNotFoundError", + "ReadOptions", + "ReadPreflight", + "ReadPrepareOptions", + "ReadQuery", + "ReadQueryOptions", + "ReadRef", + "ReadRegistryUnavailableError", + "ReadResponseTuple", + "ReadResultShape", + "ReadSpec", + "ReadSpecTuple", + "ReadSpecViolation", + "ReadStateError", + "ReadTimeoutError", + "ReadTrackOptions", + "ReadValue", + "ReadWeb2Options", + "ReceiptLike", + "RescueFundsParams", + "ResolvedAccount", + "ResolvedControllerAccounts", + "ResolvedDestination", + "Rule", + "RulesRecord", + "Selector", + "SignAuthorizationParams", + "SignedAuthorization", + "SimulateReadResult", + "SolanaRule", + "SvmAccountRef", + "SvmExecutePayloadFields", + "SvmFieldConstraint", + "SvmGatewayAccountMeta", + "SvmInstructionRule", + "SvmReadQuery", + "TERMINAL_READ_STATUSES", + "TransactionRoute", + "TransactionRouteType", + "UEAStatus", + "UNIVERSAL_CALLBACK_EVM", + "UNIVERSAL_READ_REGISTRY_EVM", + "UNIVERSAL_READ_STATUS", + "UniversalAccount", + "UniversalExecuteParams", + "UniversalOutboundTxRequest", + "UniversalReadResponse", + "UniversalRule", + "UniversalSigner", + "UniversalSignerSkeleton", + "UniversalTo", + "UnsupportedPC20DestinationError", + "UnsupportedReadDestinationError", + "ValidateReadCall", + "WaitForOutboundOptions", + "WalletInfo", + "WalletSummary", + "Web2Extract", + "Web2ReadQuery", + "Web2ValueType", + "buildErc20WithdrawalMulticall", + "buildMigrationPayload", + "buildReadSpecFromPreflight", + "chainSupportsCEA", + "chainSupportsOutbound", + "decodeReadResult", + "detectRoute", + "encodeReadQuery", + "encodeSvmExecutePayload", + "getAllCEAAddresses", + "getCEAAddress", + "getCEAFactoryAddress", + "getPushAccountForCEA", + "inferResultShape", + "isCEA", + "isChainTarget", + "isPC20Reference", + "isSvmChain", + "isValidSolanaHexAddress", + "parseFulfilOutcome", + "parseReadRequestsFromReceipt", + "parseUEAVersion", + "quoteMaxPCForGasCap", + "quoteMaxPCForGasCapFromNativeValue", + "resolveDestination", + "sizeCallbackBudget", + "toCallData", + "toReadQuery", + "toRequestIdHex", + "validateReadSpec" + ], + "agw": { + "AgenticNamespace": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace", + "members": { + "create": { + "optional": false, + "readonly": false, + "type": "(label: string, options: import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions) => Promise" + }, + "derive": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n index?: number;\n}) => Promise<{\n address: `0x${string}`;\n deployed: boolean;\n index: number;\n}>" + }, + "list": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n wallets: import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary[];\n}>" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "(address: `0x${string}`) => import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet" + } + } + }, + "AgenticWallet": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "checkpoints": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n sinceBlock?: bigint;\n}) => Promise<{\n checkpoints: import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint[];\n}>" + }, + "info": { + "optional": false, + "readonly": false, + "type": "() => Promise" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n owner: `0x${string}`;\n}>" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "{\n add(rules: import(\"sdk/src/lib/agentic/agentic.types\").Rule[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise<{\n rulesIds: `0x${string}`[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n get(rulesId: `0x${string}`): Promise;\n list(): Promise<{\n rules: import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord[];\n }>;\n revoke(rulesIds: `0x${string}`[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n revoke(params: {\n all: true;\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n update(params: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n rules: {\n rule: import(\"sdk/src/lib/agentic/agentic.types\").Rule;\n rulesId: `0x${string}`;\n }[];\n }): Promise<{\n rules: {\n replaced: `0x${string}`;\n rulesId: `0x${string}`;\n }[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n}" + }, + "setLabel": { + "optional": false, + "readonly": false, + "type": "(label: string, opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n}) => Promise" + } + } + }, + "AgenticError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"AMBIGUOUS_RULE\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"CREATE_PARTIAL\" | \"FROM_NOT_ALLOWED\" | \"GATEWAY_ALLOWANCE_INSUFFICIENT\" | \"GENERATION_UNSUPPORTED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"REVOKE_NEEDS_TARGET\" | \"RULE_LIMIT_EXCEEDED\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"" + }, + "details": { + "optional": true, + "readonly": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "AgenticRevertError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticRevertError", + "members": { + "agenticCode": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + } + } + }, + "AGENTIC_ERROR_CODE": { + "type": "{\n readonly AGENT_GAS_INSUFFICIENT: \"AGENT_GAS_INSUFFICIENT\";\n readonly AGENT_IS_OWNER: \"AGENT_IS_OWNER\";\n readonly AMBIGUOUS_RULE: \"AMBIGUOUS_RULE\";\n readonly ASSET_CHAIN_MISMATCH: \"ASSET_CHAIN_MISMATCH\";\n readonly CAPABILITY_UNAVAILABLE: \"CAPABILITY_UNAVAILABLE\";\n readonly CREATE_PARTIAL: \"CREATE_PARTIAL\";\n readonly FROM_NOT_ALLOWED: \"FROM_NOT_ALLOWED\";\n readonly GATEWAY_ALLOWANCE_INSUFFICIENT: \"GATEWAY_ALLOWANCE_INSUFFICIENT\";\n readonly GENERATION_UNSUPPORTED: \"GENERATION_UNSUPPORTED\";\n readonly INCONSISTENT_READ: \"INCONSISTENT_READ\";\n readonly INDEX_RACE: \"INDEX_RACE\";\n readonly INVALID_RULE: \"INVALID_RULE\";\n readonly NO_RULES_FOR_CHAIN: \"NO_RULES_FOR_CHAIN\";\n readonly NOT_AGENTIC_WALLET: \"NOT_AGENTIC_WALLET\";\n readonly NOT_ALLOWED_IN_AGENTIC_MODE: \"NOT_ALLOWED_IN_AGENTIC_MODE\";\n readonly NOT_OWNER_OR_AGENT: \"NOT_OWNER_OR_AGENT\";\n readonly NOT_WALLET_OWNER: \"NOT_WALLET_OWNER\";\n readonly READ_ONLY: \"READ_ONLY\";\n readonly RECEIPT_MISMATCH: \"RECEIPT_MISMATCH\";\n readonly RECEIPT_UNAVAILABLE: \"RECEIPT_UNAVAILABLE\";\n readonly REVOKE_NEEDS_TARGET: \"REVOKE_NEEDS_TARGET\";\n readonly RULE_LIMIT_EXCEEDED: \"RULE_LIMIT_EXCEEDED\";\n readonly RULE_NOT_FOUND: \"RULE_NOT_FOUND\";\n readonly RULE_READ_FAILED: \"RULE_READ_FAILED\";\n readonly TARGET_NOT_ON_RULE_CHAIN: \"TARGET_NOT_ON_RULE_CHAIN\";\n readonly WALLET_BALANCE_INSUFFICIENT: \"WALLET_BALANCE_INSUFFICIENT\";\n readonly WALLET_NOT_DEPLOYED: \"WALLET_NOT_DEPLOYED\";\n}", + "members": { + "AGENT_GAS_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\"" + }, + "AGENT_IS_OWNER": { + "optional": false, + "readonly": true, + "type": "\"AGENT_IS_OWNER\"" + }, + "AMBIGUOUS_RULE": { + "optional": false, + "readonly": true, + "type": "\"AMBIGUOUS_RULE\"" + }, + "ASSET_CHAIN_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"ASSET_CHAIN_MISMATCH\"" + }, + "CAPABILITY_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"CAPABILITY_UNAVAILABLE\"" + }, + "CREATE_PARTIAL": { + "optional": false, + "readonly": true, + "type": "\"CREATE_PARTIAL\"" + }, + "FROM_NOT_ALLOWED": { + "optional": false, + "readonly": true, + "type": "\"FROM_NOT_ALLOWED\"" + }, + "GATEWAY_ALLOWANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"GATEWAY_ALLOWANCE_INSUFFICIENT\"" + }, + "GENERATION_UNSUPPORTED": { + "optional": false, + "readonly": true, + "type": "\"GENERATION_UNSUPPORTED\"" + }, + "INCONSISTENT_READ": { + "optional": false, + "readonly": true, + "type": "\"INCONSISTENT_READ\"" + }, + "INDEX_RACE": { + "optional": false, + "readonly": true, + "type": "\"INDEX_RACE\"" + }, + "INVALID_RULE": { + "optional": false, + "readonly": true, + "type": "\"INVALID_RULE\"" + }, + "NO_RULES_FOR_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"NO_RULES_FOR_CHAIN\"" + }, + "NOT_AGENTIC_WALLET": { + "optional": false, + "readonly": true, + "type": "\"NOT_AGENTIC_WALLET\"" + }, + "NOT_ALLOWED_IN_AGENTIC_MODE": { + "optional": false, + "readonly": true, + "type": "\"NOT_ALLOWED_IN_AGENTIC_MODE\"" + }, + "NOT_OWNER_OR_AGENT": { + "optional": false, + "readonly": true, + "type": "\"NOT_OWNER_OR_AGENT\"" + }, + "NOT_WALLET_OWNER": { + "optional": false, + "readonly": true, + "type": "\"NOT_WALLET_OWNER\"" + }, + "READ_ONLY": { + "optional": false, + "readonly": true, + "type": "\"READ_ONLY\"" + }, + "RECEIPT_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_MISMATCH\"" + }, + "RECEIPT_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_UNAVAILABLE\"" + }, + "REVOKE_NEEDS_TARGET": { + "optional": false, + "readonly": true, + "type": "\"REVOKE_NEEDS_TARGET\"" + }, + "RULE_LIMIT_EXCEEDED": { + "optional": false, + "readonly": true, + "type": "\"RULE_LIMIT_EXCEEDED\"" + }, + "RULE_NOT_FOUND": { + "optional": false, + "readonly": true, + "type": "\"RULE_NOT_FOUND\"" + }, + "RULE_READ_FAILED": { + "optional": false, + "readonly": true, + "type": "\"RULE_READ_FAILED\"" + }, + "TARGET_NOT_ON_RULE_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"TARGET_NOT_ON_RULE_CHAIN\"" + }, + "WALLET_BALANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"WALLET_BALANCE_INSUFFICIENT\"" + }, + "WALLET_NOT_DEPLOYED": { + "optional": false, + "readonly": true, + "type": "\"WALLET_NOT_DEPLOYED\"" + } + } + }, + "NativeRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "amount": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AmountLimit | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "maxCalls": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValuePerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxValueTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "pins": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ArgPin[] | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "AssetCap": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap", + "members": { + "maxPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/constants/tokens\").MoveableToken" + } + } + }, + "AllowedCall": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall", + "members": { + "beneficiary": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "beneficiaryOffset": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValue": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "`${string}(${string})` | `0x${string}`" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "UniversalRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall[]" + }, + "assets": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap[]" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "`eip155:${string}`" + }, + "maxGasPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "RulesRecord": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "enabled": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "rule": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").DecodedSolanaRule | import(\"sdk/src/lib/agentic/agentic.types\").Rule" + }, + "rulesId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "CreateOptions": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions", + "members": { + "progressHook": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook | undefined" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Rule[]" + } + } + }, + "CreateResult": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateResult", + "members": { + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "rulesIds": { + "optional": false, + "readonly": false, + "type": "`0x${string}`[]" + }, + "tx": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticTxMetadata": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticTxMetadata", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destinationAccount": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "destinationCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "destinationInstruction": { + "optional": true, + "readonly": false, + "type": "{\n accounts: readonly {\n isWritable: boolean;\n pubkey: `0x${string}`;\n }[];\n data: `0x${string}`;\n program: `0x${string}`;\n} | undefined" + }, + "destinationTransfer": { + "optional": true, + "readonly": false, + "type": "{\n amount: bigint;\n recipient: `0x${string}`;\n token: `0x${string}`;\n} | undefined" + }, + "door": { + "optional": false, + "readonly": false, + "type": "\"agent\" | \"owner\"" + }, + "nativeCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "rawData": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rawTo": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesId": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + } + }, + "publicSurface": { + "CHAIN": { + "type": "typeof import(\"sdk/src/lib/constants/enums\").CHAIN", + "members": { + "ARBITRUM_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA" + }, + "BASE_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA" + }, + "BNB_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET" + }, + "ETHEREUM_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET" + }, + "ETHEREUM_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA" + }, + "PUSH_LOCALNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET" + }, + "PUSH_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET" + }, + "PUSH_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET" + }, + "PUSH_TESTNET_DONUT": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET" + }, + "SOLANA_DEVNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET" + }, + "SOLANA_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET" + }, + "SOLANA_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET" + }, + "WEB2": { + "optional": false, + "readonly": false, + "type": "\"web2\"" + } + } + }, + "ConversionQuote": { + "type": "import(\"sdk/src/lib/constants/tokens\").ConversionQuote", + "members": { + "amountIn": { + "optional": false, + "readonly": false, + "type": "string" + }, + "amountOut": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rate": { + "optional": false, + "readonly": false, + "type": "number" + }, + "route": { + "optional": true, + "readonly": false, + "type": "string[] | undefined" + }, + "timestamp": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "UniversalSigner": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalSigner", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "signAndSendTransaction": { + "optional": false, + "readonly": false, + "type": "(unsignedTx: Uint8Array) => Promise" + }, + "signAuthorization": { + "optional": true, + "readonly": false, + "type": "((params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise) | undefined" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": true, + "readonly": false, + "type": "(({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise) | undefined" + } + } + }, + "UniversalAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "UniversalSignerSkeleton": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "signAndSendTransaction": { + "optional": false, + "readonly": false, + "type": "(unsignedTx: Uint8Array) => Promise" + }, + "signAuthorization": { + "optional": true, + "readonly": false, + "type": "((params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise) | undefined" + }, + "signerId": { + "optional": false, + "readonly": false, + "type": "string" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": true, + "readonly": false, + "type": "(({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise) | undefined" + } + } + }, + "SignAuthorizationParams": { + "type": "{\n chainId?: number;\n contractAddress: `0x${string}`;\n executor?: \"self\";\n nonce?: number;\n}", + "members": { + "chainId": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "contractAddress": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "executor": { + "optional": true, + "readonly": false, + "type": "\"self\" | undefined" + }, + "nonce": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "SignedAuthorization": { + "type": "{\n address: `0x${string}`;\n chainId: number;\n nonce: number;\n r: `0x${string}`;\n s: `0x${string}`;\n v?: bigint;\n yParity: number;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainId": { + "optional": false, + "readonly": false, + "type": "number" + }, + "nonce": { + "optional": false, + "readonly": false, + "type": "number" + }, + "r": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "s": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "v": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "yParity": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "DerivedExecutorAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").DerivedExecutorAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean | null" + } + } + }, + "ResolvedAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainName": { + "optional": false, + "readonly": false, + "type": "string" + }, + "exists": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "role": { + "optional": true, + "readonly": false, + "type": "\"controller\" | undefined" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"cea\" | \"uea\" | \"uoa\"" + } + } + }, + "ResolvedControllerAccounts": { + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedControllerAccounts", + "members": { + "accounts": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedAccount[]" + } + } + }, + "AccountType": { + "type": "\"cea\" | \"uea\" | \"uoa\"", + "members": {} + }, + "AccountRole": { + "type": "\"controller\"", + "members": {} + }, + "PC20TokenReference": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "FundsToken": { + "type": "import(\"sdk/src/lib/constants/tokens\").MoveableToken | import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20TokenReference", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "PC20RegistryEntry": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "chainName": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "PC20AddressResult": { + "type": "{\n address: `0x${string}`;\n decimals: number;\n name: string;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n registry: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20RegistryEntry[];\n symbol: string;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "decimals": { + "optional": false, + "readonly": false, + "type": "number" + }, + "name": { + "optional": false, + "readonly": false, + "type": "string" + }, + "network": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "registry": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20RegistryEntry[]" + }, + "symbol": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "isPC20Reference": { + "type": "(token: import(\"sdk/src/lib/orchestrator/orchestrator.types\").FundsToken | undefined) => token is import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20TokenReference", + "members": {} + }, + "PC20Error": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20Error", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidPC20AddressError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InvalidPC20AddressError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20TokenChainMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20TokenChainMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20WrapperNotRegisteredError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20WrapperNotRegisteredError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20RegistryMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20RegistryMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20FactoryMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20FactoryMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidPC20MetadataError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InvalidPC20MetadataError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20ExpectedButPRC20Error": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20ExpectedButPRC20Error", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20AmbiguousAddressError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20AmbiguousAddressError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "candidates": { + "optional": false, + "readonly": true, + "type": "{\n chain: string;\n pushAddress: string;\n}[]" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "UnsupportedPC20DestinationError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").UnsupportedPC20DestinationError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InsufficientPC20BalanceError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InsufficientPC20BalanceError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20UnknownChainNamespaceError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20UnknownChainNamespaceError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20WrapperPredictionUnavailableError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20WrapperPredictionUnavailableError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20ExportRevertedError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20ExportRevertedError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "lockedAmount": { + "optional": true, + "readonly": true, + "type": "bigint | undefined" + }, + "outboundTxId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "revertRecipient": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20UnsafeEmptyPayloadError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20UnsafeEmptyPayloadError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ChainTarget": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "ChainSource": { + "type": "{\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "UniversalTo": { + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget", + "members": {} + }, + "TransactionRouteType": { + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"", + "members": {} + }, + "UniversalExecuteParams": { + "type": "{\n from?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainSource;\n migration?: boolean;\n to: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTo;\n} & Omit", + "members": { + "_minimumDepositUsd": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "_requiredFundsOverride": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "_skipFeeLocking": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "_ueaStatus": { + "optional": true, + "readonly": false, + "type": "{\n balance: bigint;\n isDeployed: boolean;\n nonce: bigint;\n} | undefined" + }, + "data": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiCall[] | undefined" + }, + "deadline": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "feeLockTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "from": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainSource | undefined" + }, + "funds": { + "optional": true, + "readonly": false, + "type": "{\n amount: bigint;\n token?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").FundsToken;\n} | undefined" + }, + "gasLimit": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFeePerGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxPCForGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxPriorityFeePerGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "migration": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "nonce": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "options": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions | undefined" + }, + "payGasWith": { + "optional": true, + "readonly": false, + "type": "{\n minAmountOut?: bigint | string;\n slippageBps?: number;\n token?: import(\"sdk/src/lib/constants/tokens\").PayableToken;\n} | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "to": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget" + }, + "value": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "UniversalOutboundTxRequest": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalOutboundTxRequest", + "members": { + "amount": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gasPrice": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxPCForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "payload": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "recipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "revertRecipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "PreparedUniversalTx": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx", + "members": { + "_hop": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").HopDescriptor" + }, + "deadline": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "estimatedGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gatewayRequest": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalOutboundTxRequest | import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxRequest" + }, + "nonce": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "payload": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + } + } + }, + "CascadedTxResponse": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadedTxResponse", + "members": { + "finalTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hopCount": { + "optional": false, + "readonly": false, + "type": "number" + }, + "hops": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo[]" + }, + "initialTxHash": { + "optional": false, + "readonly": false, + "type": "string" + }, + "initialTxResponse": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions) => Promise" + }, + "waitForAll": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions) => Promise" + } + } + }, + "CascadeHopInfo": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo", + "members": { + "executionChain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "expectedSubTxId": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hopIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "outboundDetails": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").OutboundTxDetails | undefined" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + }, + "status": { + "optional": false, + "readonly": false, + "type": "\"confirmed\" | \"failed\" | \"pending\" | \"submitted\"" + }, + "txHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "CascadeTrackOptions": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions", + "members": { + "eventHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeProgressEvent) => void) | undefined" + }, + "timeout": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "CascadeProgressEvent": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeProgressEvent", + "members": { + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "elapsed": { + "optional": false, + "readonly": false, + "type": "number" + }, + "hopIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + }, + "status": { + "optional": false, + "readonly": false, + "type": "\"confirmed\" | \"failed\" | \"found\" | \"polling\" | \"timeout\" | \"waiting\"" + }, + "txHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "CascadeCompletionResult": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeCompletionResult", + "members": { + "failedAt": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "finalTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "finalTxResponse": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadedTxResponse | undefined" + }, + "hops": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo[]" + }, + "success": { + "optional": false, + "readonly": false, + "type": "boolean" + } + } + }, + "MultiChainTxResponse": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiChainTxResponse", + "members": { + "chains": { + "optional": false, + "readonly": false, + "type": "{\n blockNumber: bigint;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n hash: string;\n status: \"confirmed\" | \"failed\" | \"pending\";\n}[]" + }, + "transactions": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse[]" + } + } + }, + "OutboundTxDetails": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").OutboundTxDetails", + "members": { + "amount": { + "optional": false, + "readonly": false, + "type": "string" + }, + "assetAddr": { + "optional": false, + "readonly": false, + "type": "string" + }, + "destinationChain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "explorerUrl": { + "optional": false, + "readonly": false, + "type": "string" + }, + "externalTxHash": { + "optional": false, + "readonly": false, + "type": "string" + }, + "recipient": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "WaitForOutboundOptions": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").WaitForOutboundOptions", + "members": { + "_expectedDestinationChain": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "_outboundIndex": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "_resolvedSubTxId": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "initialWaitMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: {\n elapsed: number;\n status: \"failed\" | \"found\" | \"polling\" | \"timeout\" | \"waiting\";\n}) => void) | undefined" + }, + "timeout": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "SvmGatewayAccountMeta": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmGatewayAccountMeta", + "members": { + "isWritable": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "pubkey": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "SvmExecutePayloadFields": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmExecutePayloadFields", + "members": { + "accounts": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmGatewayAccountMeta[]" + }, + "instructionId": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "ixData": { + "optional": false, + "readonly": false, + "type": "Uint8Array" + }, + "targetProgram": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AccountStatus": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus", + "members": { + "mode": { + "optional": false, + "readonly": false, + "type": "\"read-only\" | \"signer\"" + }, + "uea": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UEAStatus" + } + } + }, + "UEAStatus": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UEAStatus", + "members": { + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "loaded": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "minRequiredVersion": { + "optional": false, + "readonly": false, + "type": "string" + }, + "requiresUpgrade": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "version": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "RescueFundsParams": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").RescueFundsParams", + "members": { + "prc20": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "universalTxId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "parseUEAVersion": { + "type": "(version: string) => number", + "members": {} + }, + "TransactionRoute": { + "type": "typeof import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute", + "members": { + "CEA_TO_CEA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.CEA_TO_CEA" + }, + "CEA_TO_PUSH": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.CEA_TO_PUSH" + }, + "UOA_TO_CEA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.UOA_TO_CEA" + }, + "UOA_TO_PUSH": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.UOA_TO_PUSH" + } + } + }, + "detectRoute": { + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams) => import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute", + "members": {} + }, + "isChainTarget": { + "type": "(to: unknown) => to is import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget", + "members": {} + }, + "DEFAULT_MAX_PC_FOR_GAS_BUFFER_BPS": { + "type": "1000", + "members": {} + }, + "MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT": { + "type": "10000", + "members": {} + }, + "quoteMaxPCForGasCap": { + "type": "(input: import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapInput) => import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": {} + }, + "quoteMaxPCForGasCapFromNativeValue": { + "type": "(input: import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapFromNativeValueInput) => import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": {} + }, + "MaxPCForGasCapInput": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapInput", + "members": { + "bufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "gasLegNativePc": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "MaxPCForGasCapFromNativeValueInput": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapFromNativeValueInput", + "members": { + "bufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "nativeValueForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "MaxPCForGasCapQuote": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": { + "bufferBps": { + "optional": false, + "readonly": false, + "type": "number" + }, + "gasLegNativePc": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxPCForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "nativeValueForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "getCEAAddress": { + "type": "(ueaAddress: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise", + "members": {} + }, + "getPushAccountForCEA": { + "type": "(ceaAddress: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise<`0x${string}`>", + "members": {} + }, + "isCEA": { + "type": "(address: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise", + "members": {} + }, + "chainSupportsCEA": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "chainSupportsOutbound": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "getCEAFactoryAddress": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => `0x${string}` | undefined", + "members": {} + }, + "getAllCEAAddresses": { + "type": "(ueaAddress: `0x${string}`, rpcUrls?: Partial>) => Promise", + "members": {} + }, + "encodeSvmExecutePayload": { + "type": "(fields: import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmExecutePayloadFields) => `0x${string}`", + "members": {} + }, + "isSvmChain": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "isValidSolanaHexAddress": { + "type": "(address: string) => boolean", + "members": {} + }, + "buildMigrationPayload": { + "type": "() => `0x${string}`", + "members": {} + }, + "buildErc20WithdrawalMulticall": { + "type": "(tokenAddress: `0x${string}`, recipientAddress: `0x${string}`, amount: bigint) => import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiCall[]", + "members": {} + }, + "ReadChain": { + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain", + "members": {} + }, + "ReadDestination": { + "type": "{\n chain: import(\"sdk/src/lib/read-state/read-state.types\").ReadChain;\n} | {\n chainId: string;\n chainNamespace: string;\n}", + "members": {} + }, + "ResolvedDestination": { + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}", + "members": { + "caip2": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainId": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "namespace": { + "optional": false, + "readonly": false, + "type": "\"eip155\" | \"solana\" | \"web2\"" + } + } + }, + "ReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").SvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery", + "members": { + "type": { + "optional": false, + "readonly": false, + "type": "\"accountBalance\" | \"contractCall\" | \"http\" | \"lamportBalance\" | \"rawAccountData\" | \"splTokenAccount\" | \"storageSlot\"" + } + } + }, + "EvmReadQuery": { + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n target: `0x${string}`;\n type: \"contractCall\";\n} | {\n callData: `0x${string}`;\n target: `0x${string}`;\n type: \"contractCall\";\n} | {\n slot: `0x${string}` | bigint;\n target: `0x${string}`;\n type: \"storageSlot\";\n} | {\n target: `0x${string}`;\n type: \"accountBalance\";\n}", + "members": { + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"accountBalance\" | \"contractCall\" | \"storageSlot\"" + } + } + }, + "SvmReadQuery": { + "type": "{\n account: string | Uint8Array;\n accountName?: string;\n idl?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n type: \"rawAccountData\";\n} | {\n account: string | Uint8Array;\n type: \"lamportBalance\";\n} | {\n account: string | Uint8Array;\n type: \"splTokenAccount\";\n}", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "string | Uint8Array" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"lamportBalance\" | \"rawAccountData\" | \"splTokenAccount\"" + } + } + }, + "Web2ReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery", + "members": { + "body": { + "optional": true, + "readonly": false, + "type": "string | Uint8Array | undefined" + }, + "extract": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[]" + }, + "headers": { + "optional": true, + "readonly": false, + "type": "Record | undefined" + }, + "method": { + "optional": true, + "readonly": false, + "type": "\"GET\" | \"POST\" | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"http\"" + }, + "url": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "Web2Extract": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract", + "members": { + "decimals": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "path": { + "optional": false, + "readonly": false, + "type": "string" + }, + "valueType": { + "optional": false, + "readonly": false, + "type": "\"bool\" | \"bytes\" | \"int256\" | \"string\" | \"uint256\"" + } + } + }, + "Web2ValueType": { + "type": "\"bool\" | \"bytes\" | \"int256\" | \"string\" | \"uint256\"", + "members": {} + }, + "EncodedReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery", + "members": { + "blockRef": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "encoded": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "namespace": { + "optional": false, + "readonly": false, + "type": "\"eip155\" | \"solana\" | \"web2\"" + }, + "ownerBytes": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "queryType": { + "optional": false, + "readonly": false, + "type": "number" + }, + "resultShape": { + "optional": false, + "readonly": false, + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}" + }, + "warnings": { + "optional": false, + "readonly": false, + "type": "string[]" + } + } + }, + "ReadResultShape": { + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"bytes32\" | \"evmCall\" | \"raw\" | \"svmAccount\" | \"uint256\" | \"web2\"" + } + } + }, + "DecodedReadResult": { + "type": "{\n accountName: string;\n kind: \"svmAccount\";\n value: unknown;\n} | {\n kind: \"bytes32\";\n value: `0x${string}`;\n} | {\n kind: \"evmCall\";\n value: unknown;\n} | {\n kind: \"raw\";\n value: `0x${string}`;\n} | {\n kind: \"uint256\";\n value: bigint;\n} | {\n kind: \"web2\";\n values: readonly unknown[];\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"bytes32\" | \"evmCall\" | \"raw\" | \"svmAccount\" | \"uint256\" | \"web2\"" + } + } + }, + "ReadPreflight": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight", + "members": { + "destination": { + "optional": false, + "readonly": false, + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}" + }, + "fetchedAt": { + "optional": false, + "readonly": false, + "type": "number" + }, + "observedChainHeight": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pushBlockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pushGasPrice": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "universalCallback": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "universalCore": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ReadSpec": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "{\n chainId: string;\n chainNamespace: string;\n owner: `0x${string}`;\n}" + }, + "blockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "expiryPushChainHeight": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "minConfirmations": { + "optional": false, + "readonly": false, + "type": "number" + }, + "query": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "revertRecipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ReadSpecTuple": { + "type": "readonly [\n readonly [\n string,\n string,\n `0x${string}`\n ],\n `0x${string}`,\n number,\n bigint,\n bigint,\n bigint,\n `0x${string}`\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "readonly [\n string,\n string,\n `0x${string}`\n]" + }, + "1": { + "optional": false, + "readonly": true, + "type": "`0x${string}`" + }, + "2": { + "optional": false, + "readonly": true, + "type": "number" + }, + "3": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "4": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "5": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "6": { + "optional": false, + "readonly": true, + "type": "`0x${string}`" + }, + "length": { + "optional": false, + "readonly": true, + "type": "7" + } + } + }, + "BuildReadSpecParams": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").BuildReadSpecParams", + "members": { + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "budgetBuffer": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback | undefined" + }, + "callbackBudget": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "destination": { + "optional": false, + "readonly": false, + "type": "{\n chain: import(\"sdk/src/lib/read-state/read-state.types\").ReadChain;\n} | {\n chainId: string;\n chainNamespace: string;\n}" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "expiryPushChainHeight": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFeeBufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "owner": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "query": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").SvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "PreparedRead": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead", + "members": { + "__@preparedReadValue": { + "optional": true, + "readonly": true, + "type": "T | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback | undefined" + }, + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "encodedQuery": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery" + }, + "encodedSpec": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "fees": { + "optional": false, + "readonly": false, + "type": "{\n callbackBudget: bigint;\n protocolFee: bigint;\n total: bigint;\n}" + }, + "preflight": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "queryKey": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "resultShape": { + "optional": false, + "readonly": false, + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}" + }, + "spec": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec" + }, + "specTuple": { + "optional": false, + "readonly": false, + "type": "readonly [\n readonly [\n string,\n string,\n `0x${string}`\n ],\n `0x${string}`,\n number,\n bigint,\n bigint,\n bigint,\n `0x${string}`\n]" + }, + "value": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "warnings": { + "optional": false, + "readonly": false, + "type": "string[]" + } + } + }, + "ReadCallback": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "((spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpecTuple, callbackGasLimit: bigint) => readonly unknown[]) | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "gasLimit": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "target": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "SimulateReadResult": { + "type": "{\n args?: readonly unknown[];\n error: string;\n errorName?: string;\n ok: false;\n} | {\n ok: true;\n}", + "members": { + "ok": { + "optional": false, + "readonly": false, + "type": "boolean" + } + } + }, + "ParsedReadRequest": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ParsedReadRequest", + "members": { + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackTarget": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "logIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "originalFunder": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "requestId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "requestIdUint": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "spec": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec" + }, + "totalPaid": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "FulfilOutcome": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").FulfilOutcome", + "members": { + "burned": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "delivered": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "expired": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "failReason": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "gasReported": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refunded": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refundFailed": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "ReceiptLike": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike", + "members": { + "logs": { + "optional": false, + "readonly": false, + "type": "readonly {\n address: string;\n data: string;\n logIndex?: number | string;\n topics: readonly string[];\n}[]" + } + } + }, + "ReadRef": { + "type": "{\n requestId: `0x${string}` | bigint;\n} | {\n txHash: `0x${string}`;\n}", + "members": {} + }, + "ReadLifecycleOptions": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadLifecycleOptions", + "members": { + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "resultShape": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadFees": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadFees", + "members": { + "burned": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "paid": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "refunded": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refundFailed": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + } + } + }, + "UniversalReadResponse": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse", + "members": { + "callbackDelivered": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "callbackFailReason": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "decoded": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").DecodedReadResult | undefined" + }, + "decodeError": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destination": { + "optional": false, + "readonly": false, + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}" + }, + "errorMsg": { + "optional": false, + "readonly": false, + "type": "string" + }, + "explorerUrl": { + "optional": false, + "readonly": false, + "type": "string" + }, + "fees": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadFees" + }, + "isTerminal": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "outcome": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME" + }, + "pcTx": { + "optional": false, + "readonly": false, + "type": "readonly {\n blockHeight: number;\n errorMsg: string;\n status: string;\n txHash: `0x${string}`;\n}[]" + }, + "raw": { + "optional": false, + "readonly": false, + "type": "{\n errorCode: import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n resultData: `0x${string}`;\n status: import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n} | null" + }, + "refresh": { + "optional": false, + "readonly": false, + "type": "() => Promise>" + }, + "request": { + "optional": false, + "readonly": false, + "type": "{\n callbackGasLimit: bigint;\n callbackTarget: `0x${string}`;\n createdAtHeight: bigint;\n logIndex: number;\n originalFunder: `0x${string}`;\n refundTo: `0x${string}`;\n spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec;\n}" + }, + "requestId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "requestIdUint": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "status": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "value": { + "optional": true, + "readonly": false, + "type": "T | undefined" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/read-state/read-state.types\").ReadLifecycleOptions) => Promise>" + } + } + }, + "ReadResponseTuple": { + "type": "{\n -readonly [K in keyof R]: import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse ? T : unknown>;\n}", + "members": {} + }, + "BatchReadResponse": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").BatchReadResponse", + "members": { + "atomic": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "count": { + "optional": false, + "readonly": false, + "type": "number" + }, + "reads": { + "optional": false, + "readonly": false, + "type": "{\n -readonly [K in keyof R]: import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse ? T : unknown>;\n}" + }, + "transactionHashes": { + "optional": true, + "readonly": false, + "type": "readonly `0x${string}`[] | undefined" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: Omit) => Promise>" + } + } + }, + "ReadOptions": { + "type": "((import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">)) & {\n callback?: (Pick & Required>) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n };\n}", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "advanced": { + "optional": true, + "readonly": false, + "type": "{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n} | undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "({\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} & {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n}) | ({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick & Pick & Required>) | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadPrepareOptions": { + "type": "((((({\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\">) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n}) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">)) & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n}) | ((({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n}) | ({\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\">)) & {\n blockNumber?: never;\n minConfirmations?: never;\n})) & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n}) & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "advanced": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadQueryOptions": { + "type": "({\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\">) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n}) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n}) | ({\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\">)", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadCallbackOptions": { + "type": "{\n callback?: ({\n gasLimit?: bigint;\n target: `0x${string}`;\n } & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n };\n}", + "members": { + "callback": { + "optional": true, + "readonly": false, + "type": "({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} | undefined" + } + } + }, + "ReadValue": { + "type": "O extends {\n abi: infer A extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: infer F extends string;\n} ? number extends A[\"length\"] ? unknown : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, O extends {\n args: infer Args extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n} ? Args : readonly [\n] extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> ? import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> & readonly [\n] : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>> extends infer Selected ? Selected extends {\n outputs: readonly unknown[];\n type: \"function\";\n} & import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiFunction ? {\n [key in keyof {\n [key in keyof import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"]]: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterToPrimitiveType, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"][key], import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterKind>;\n }]: {\n [key in keyof import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"]]: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterToPrimitiveType, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"][key], import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterKind>;\n }[key];\n} extends infer types ? types extends readonly [\n] ? void : types extends readonly [\n infer type\n] ? type : types : never : never : never : O extends {\n web2: {\n extract: infer E extends readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n };\n} ? {\n readonly [K in keyof E]: {\n bool: boolean;\n bytes: `0x${string}`;\n int256: bigint;\n string: string;\n uint256: bigint;\n }[E[K][\"valueType\"]];\n} : O extends {\n storageSlot: unknown;\n} ? `0x${string}` : O extends {\n idl: infer I extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} ? string extends Extract, string> ? unknown : (O extends {\n functionName: infer N extends string;\n} ? N : undefined) extends string ? import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/index\").IdlAccounts[{\n [K in Extract, string>]: Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : K> extends Lowercase<(O extends {\n functionName: infer N extends string;\n } ? N : undefined) & string extends `${infer H}_${infer T}` ? `${H}${Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : (O extends {\n functionName: infer N extends string;\n } ? N : undefined) & string> ? K : never;\n}[Extract, string>]] : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/index\").IdlAccounts[Extract, string>] : bigint", + "members": {} + }, + "ValidateReadCall": { + "type": "O extends {\n abi: infer A extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: infer F extends string;\n} ? (readonly [\n] extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> ? {\n args?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n} : {\n args: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n}) & {\n functionName: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionName;\n} : O extends {\n functionName: infer N extends string;\n idl: infer I extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} ? string extends Extract, string> ? unknown : [\n {\n [K in Extract, string>]: Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : K> extends Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : N> ? K : never;\n }[Extract, string>]\n] extends [\n never\n] ? {\n functionName: Extract, string>;\n} : unknown : unknown", + "members": {} + }, + "ReadWeb2Options": { + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options", + "members": { + "body": { + "optional": true, + "readonly": false, + "type": "string | Uint8Array | undefined" + }, + "extract": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[]" + }, + "headers": { + "optional": true, + "readonly": false, + "type": "Record | undefined" + }, + "method": { + "optional": true, + "readonly": false, + "type": "\"GET\" | \"POST\" | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadTrackOptions": { + "type": "{\n advanced?: Omit, \"enforceGasCheck\">;\n resultShape?: import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape;\n}", + "members": { + "advanced": { + "optional": true, + "readonly": false, + "type": "Omit<{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n}, \"enforceGasCheck\"> | undefined" + }, + "resultShape": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape | undefined" + } + } + }, + "ReadExecuteOptions": { + "type": "{\n advanced?: {\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n } | undefined;\n progressHook?: ((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined;\n waitForCompletion?: boolean | undefined;\n}", + "members": { + "advanced": { + "optional": true, + "readonly": false, + "type": "{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n} | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + } + } + }, + "UNIVERSAL_READ_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS", + "members": { + "ABORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.ABORTED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.EXPIRED" + }, + "FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.FAILED" + }, + "FULFILLED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.FULFILLED" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.PENDING" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.UNSPECIFIED" + }, + "VOTING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.VOTING" + } + } + }, + "READ_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS", + "members": { + "ERROR": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.ERROR" + }, + "SUCCESS": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.SUCCESS" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.UNSPECIFIED" + } + } + }, + "READ_ERROR_CODE": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE", + "members": { + "INVALID_QUERY": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.INVALID_QUERY" + }, + "INVALID_RESULT": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.INVALID_RESULT" + }, + "NOT_FOUND": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.NOT_FOUND" + }, + "REJECTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.REJECTED" + }, + "REVERTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.REVERTED" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.UNSPECIFIED" + }, + "UNSUPPORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.UNSUPPORTED" + } + } + }, + "READ_OUTCOME": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME", + "members": { + "ABORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.ABORTED" + }, + "CALLBACK_FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.CALLBACK_FAILED" + }, + "DECODE_FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.DECODE_FAILED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.EXPIRED" + }, + "FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.FAILED" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.PENDING" + }, + "SOURCE_ERROR": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.SOURCE_ERROR" + }, + "SUCCESS": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.SUCCESS" + }, + "UNKNOWN": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.UNKNOWN" + } + } + }, + "CONTRACT_REQUEST_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS", + "members": { + "EXECUTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.EXECUTED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.EXPIRED" + }, + "NONE": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.NONE" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.PENDING" + }, + "SETTLED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.SETTLED" + } + } + }, + "TERMINAL_READ_STATUSES": { + "type": "ReadonlySet", + "members": {} + }, + "ReadStateError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadStateError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidReadQueryError": { + "type": "import(\"sdk/src/lib/read-state/errors\").InvalidReadQueryError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidReadSpecError": { + "type": "import(\"sdk/src/lib/read-state/errors\").InvalidReadSpecError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "violations": { + "optional": false, + "readonly": true, + "type": "readonly import(\"sdk/src/lib/read-state/errors\").ReadSpecViolation[]" + } + } + }, + "ReadHeightUnavailableError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadHeightUnavailableError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "UnsupportedReadDestinationError": { + "type": "import(\"sdk/src/lib/read-state/errors\").UnsupportedReadDestinationError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadDecodeError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadDecodeError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadTimeoutError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadTimeoutError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "lastStatus": { + "optional": false, + "readonly": true, + "type": "number" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadNotFoundError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadNotFoundError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadRegistryUnavailableError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadRegistryUnavailableError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadSpecViolation": { + "type": "\"CALLBACK_GAS_LIMIT_EXCEEDED\" | \"DOMAIN_BLOCKED\" | \"EMPTY_QUERY\" | \"EXCESSIVE_FEE\" | \"INSUFFICIENT_CALLBACK_BUDGET\" | \"INSUFFICIENT_FEE\" | \"INVALID_ACCOUNT_ID\" | \"INVALID_BLOCK_NUMBER\" | \"INVALID_EXPIRY_HEIGHT\" | \"INVALID_MIN_CONFIRMATIONS\" | \"SVM_OWNER_NOT_32_BYTES\" | \"ZERO_CALLBACK_BUDGET\" | \"ZERO_CALLBACK_GAS_LIMIT\" | \"ZERO_REVERT_RECIPIENT\"", + "members": {} + }, + "resolveDestination": { + "type": "(dest: import(\"sdk/src/lib/read-state/read-state.types\").ReadDestination) => import(\"sdk/src/lib/read-state/read-state.types\").ResolvedDestination", + "members": {} + }, + "encodeReadQuery": { + "type": "(destination: import(\"sdk/src/lib/read-state/read-state.types\").ReadDestination, query: import(\"sdk/src/lib/read-state/read-state.types\").ReadQuery, options?: {\n blockNumber?: bigint;\n minSlot?: bigint;\n}) => import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery", + "members": {} + }, + "decodeReadResult": { + "type": "(resultData: `0x${string}`, shape: import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape) => import(\"sdk/src/lib/read-state/read-state.types\").DecodedReadResult", + "members": {} + }, + "parseReadRequestsFromReceipt": { + "type": "(receipt: import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike, universalCallback: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").ParsedReadRequest[]", + "members": {} + }, + "parseFulfilOutcome": { + "type": "(receipt: import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike, universalCallback: `0x${string}`, requestId: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").FulfilOutcome", + "members": {} + }, + "buildReadSpecFromPreflight": { + "type": "(preflight: import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight, params: import(\"sdk/src/lib/read-state/read-state.types\").BuildReadSpecParams, defaults?: {\n refundTo?: `0x${string}`;\n}) => import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead", + "members": {} + }, + "validateReadSpec": { + "type": "(input: import(\"sdk/src/lib/read-state/validate\").ValidateReadSpecInput) => {\n ok: false;\n violations: import(\"sdk/src/lib/read-state/errors\").ReadSpecViolation[];\n} | {\n ok: true;\n}", + "members": {} + }, + "toCallData": { + "type": "(prepared: import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead, target: {\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: (spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpecTuple, callbackGasLimit: bigint) => readonly unknown[];\n functionName: string;\n}) => {\n data: `0x${string}`;\n value: bigint;\n}", + "members": {} + }, + "sizeCallbackBudget": { + "type": "(callbackGasLimit: bigint, pushGasPrice: bigint, buffer?: number) => bigint", + "members": {} + }, + "inferResultShape": { + "type": "(namespace: string, query: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape", + "members": {} + }, + "toRequestIdHex": { + "type": "(id: `0x${string}` | bigint) => `0x${string}`", + "members": {} + }, + "toReadQuery": { + "type": "(subject: string, o: ReadOptionsInput, resolvedTokenProgram?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@solana/web3.js/lib/index\").PublicKey) => import(\"sdk/src/lib/read-state/read-state.types\").ReadQuery", + "members": {} + }, + "UNIVERSAL_CALLBACK_EVM": { + "type": "readonly [\n {\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"requestExternalReadSelf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"estimateFee\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"statusOf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"enum RequestStatus\";\n readonly name: \"\";\n readonly type: \"uint8\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"isFulfilled\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getPendingRead\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly internalType: \"struct PendingRead\";\n readonly name: \"\";\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"totalEscrowed\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"blockedDomains\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly indexed: false;\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"readSpec\";\n readonly type: \"tuple\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"totalPaid\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"protocolFee\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ReadRequested\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"ReadFulfilled\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"reason\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"CallbackFailed\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"gasReported\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"burned\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"CallbackGasReported\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundSent\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundFailed\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RequestExpired\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"vaultPC\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ProtocolFeeDistributed\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidAccountId\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"EmptyQuery\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidMinConfirmations\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"DomainBlocked\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidBlockNumber\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidExpiryHeight\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroRevertRecipient\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroCallbackGasLimit\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint64\";\n readonly name: \"provided\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"max\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"CallbackGasLimitExceeded\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"required\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"InsufficientFee\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ExcessiveFee\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"actual\";\n readonly type: \"uint8\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"expected\";\n readonly type: \"uint8\";\n }\n ];\n readonly name: \"InvalidRequestStatus\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ContractIsPaused\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"CallerIsNotUCallbackModule\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n }\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"requestExternalReadSelf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n}" + }, + "1": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"estimateFee\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "2": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"statusOf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"enum RequestStatus\";\n readonly name: \"\";\n readonly type: \"uint8\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "3": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"isFulfilled\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "4": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getPendingRead\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly internalType: \"struct PendingRead\";\n readonly name: \"\";\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "5": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"totalEscrowed\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "6": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"blockedDomains\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "7": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly indexed: false;\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"readSpec\";\n readonly type: \"tuple\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"totalPaid\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"protocolFee\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ReadRequested\";\n readonly type: \"event\";\n}" + }, + "8": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"ReadFulfilled\";\n readonly type: \"event\";\n}" + }, + "9": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"reason\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"CallbackFailed\";\n readonly type: \"event\";\n}" + }, + "10": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"gasReported\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"burned\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"CallbackGasReported\";\n readonly type: \"event\";\n}" + }, + "11": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundSent\";\n readonly type: \"event\";\n}" + }, + "12": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundFailed\";\n readonly type: \"event\";\n}" + }, + "13": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RequestExpired\";\n readonly type: \"event\";\n}" + }, + "14": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"vaultPC\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ProtocolFeeDistributed\";\n readonly type: \"event\";\n}" + }, + "15": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidAccountId\";\n readonly type: \"error\";\n}" + }, + "16": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"EmptyQuery\";\n readonly type: \"error\";\n}" + }, + "17": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidMinConfirmations\";\n readonly type: \"error\";\n}" + }, + "18": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"DomainBlocked\";\n readonly type: \"error\";\n}" + }, + "19": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidBlockNumber\";\n readonly type: \"error\";\n}" + }, + "20": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidExpiryHeight\";\n readonly type: \"error\";\n}" + }, + "21": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroRevertRecipient\";\n readonly type: \"error\";\n}" + }, + "22": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroCallbackGasLimit\";\n readonly type: \"error\";\n}" + }, + "23": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint64\";\n readonly name: \"provided\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"max\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"CallbackGasLimitExceeded\";\n readonly type: \"error\";\n}" + }, + "24": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"required\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"InsufficientFee\";\n readonly type: \"error\";\n}" + }, + "25": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ExcessiveFee\";\n readonly type: \"error\";\n}" + }, + "26": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"actual\";\n readonly type: \"uint8\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"expected\";\n readonly type: \"uint8\";\n }\n ];\n readonly name: \"InvalidRequestStatus\";\n readonly type: \"error\";\n}" + }, + "27": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ContractIsPaused\";\n readonly type: \"error\";\n}" + }, + "28": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"CallerIsNotUCallbackModule\";\n readonly type: \"error\";\n}" + }, + "29": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n}" + }, + "length": { + "optional": false, + "readonly": true, + "type": "30" + } + } + }, + "UNIVERSAL_READ_REGISTRY_EVM": { + "type": "readonly [\n {\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n },\n {\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"read\";\n readonly outputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"universalCallback_\";\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"constructor\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"initialize\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getLocalContext\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"hasResult\";\n readonly outputs: readonly [\n {\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"onUniversalData\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"queryKeyOf\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes32\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"readerOf\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"requestOrderOf\";\n readonly outputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"universalCallback\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"resultByRequestId\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"latestResult\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"version\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"Initialized\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadRequested\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadStored\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidInitialization\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"NotInitializing\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroAddressInit\";\n readonly type: \"error\";\n }\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n },\n {\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"read\";\n readonly outputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n}" + }, + "1": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"universalCallback_\";\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"constructor\";\n}" + }, + "2": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"initialize\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n}" + }, + "3": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getLocalContext\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "4": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"hasResult\";\n readonly outputs: readonly [\n {\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "5": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"onUniversalData\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n}" + }, + "6": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"queryKeyOf\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes32\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "7": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"readerOf\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "8": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"requestOrderOf\";\n readonly outputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "9": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"universalCallback\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "10": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"resultByRequestId\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "11": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"latestResult\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "12": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"version\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"Initialized\";\n readonly type: \"event\";\n}" + }, + "13": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadRequested\";\n readonly type: \"event\";\n}" + }, + "14": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadStored\";\n readonly type: \"event\";\n}" + }, + "15": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidInitialization\";\n readonly type: \"error\";\n}" + }, + "16": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"NotInitializing\";\n readonly type: \"error\";\n}" + }, + "17": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n}" + }, + "18": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroAddressInit\";\n readonly type: \"error\";\n}" + }, + "length": { + "optional": false, + "readonly": true, + "type": "19" + } + } + }, + "PushChainExecutionError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").PushChainExecutionError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PushChainBatchExecutionError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").PushChainBatchExecutionError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": false, + "readonly": true, + "type": "`0x${string}`[]" + } + } + }, + "DecodedErrorPayload": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload", + "members": { + "decoded": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "name": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "selector": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "PushChainInitializeOptions": { + "type": "import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions", + "members": { + "agenticWallet": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "blockExplorers": { + "optional": true, + "readonly": false, + "type": "Partial> | undefined" + }, + "network": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "printTraces": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "rpcUrls": { + "optional": true, + "readonly": false, + "type": "Partial> | undefined" + } + } + }, + "AGENTIC_ERROR_CODE": { + "type": "{\n readonly AGENT_GAS_INSUFFICIENT: \"AGENT_GAS_INSUFFICIENT\";\n readonly AGENT_IS_OWNER: \"AGENT_IS_OWNER\";\n readonly AMBIGUOUS_RULE: \"AMBIGUOUS_RULE\";\n readonly ASSET_CHAIN_MISMATCH: \"ASSET_CHAIN_MISMATCH\";\n readonly CAPABILITY_UNAVAILABLE: \"CAPABILITY_UNAVAILABLE\";\n readonly CREATE_PARTIAL: \"CREATE_PARTIAL\";\n readonly FROM_NOT_ALLOWED: \"FROM_NOT_ALLOWED\";\n readonly GATEWAY_ALLOWANCE_INSUFFICIENT: \"GATEWAY_ALLOWANCE_INSUFFICIENT\";\n readonly GENERATION_UNSUPPORTED: \"GENERATION_UNSUPPORTED\";\n readonly INCONSISTENT_READ: \"INCONSISTENT_READ\";\n readonly INDEX_RACE: \"INDEX_RACE\";\n readonly INVALID_RULE: \"INVALID_RULE\";\n readonly NO_RULES_FOR_CHAIN: \"NO_RULES_FOR_CHAIN\";\n readonly NOT_AGENTIC_WALLET: \"NOT_AGENTIC_WALLET\";\n readonly NOT_ALLOWED_IN_AGENTIC_MODE: \"NOT_ALLOWED_IN_AGENTIC_MODE\";\n readonly NOT_OWNER_OR_AGENT: \"NOT_OWNER_OR_AGENT\";\n readonly NOT_WALLET_OWNER: \"NOT_WALLET_OWNER\";\n readonly READ_ONLY: \"READ_ONLY\";\n readonly RECEIPT_MISMATCH: \"RECEIPT_MISMATCH\";\n readonly RECEIPT_UNAVAILABLE: \"RECEIPT_UNAVAILABLE\";\n readonly REVOKE_NEEDS_TARGET: \"REVOKE_NEEDS_TARGET\";\n readonly RULE_LIMIT_EXCEEDED: \"RULE_LIMIT_EXCEEDED\";\n readonly RULE_NOT_FOUND: \"RULE_NOT_FOUND\";\n readonly RULE_READ_FAILED: \"RULE_READ_FAILED\";\n readonly TARGET_NOT_ON_RULE_CHAIN: \"TARGET_NOT_ON_RULE_CHAIN\";\n readonly WALLET_BALANCE_INSUFFICIENT: \"WALLET_BALANCE_INSUFFICIENT\";\n readonly WALLET_NOT_DEPLOYED: \"WALLET_NOT_DEPLOYED\";\n}", + "members": { + "AGENT_GAS_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\"" + }, + "AGENT_IS_OWNER": { + "optional": false, + "readonly": true, + "type": "\"AGENT_IS_OWNER\"" + }, + "AMBIGUOUS_RULE": { + "optional": false, + "readonly": true, + "type": "\"AMBIGUOUS_RULE\"" + }, + "ASSET_CHAIN_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"ASSET_CHAIN_MISMATCH\"" + }, + "CAPABILITY_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"CAPABILITY_UNAVAILABLE\"" + }, + "CREATE_PARTIAL": { + "optional": false, + "readonly": true, + "type": "\"CREATE_PARTIAL\"" + }, + "FROM_NOT_ALLOWED": { + "optional": false, + "readonly": true, + "type": "\"FROM_NOT_ALLOWED\"" + }, + "GATEWAY_ALLOWANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"GATEWAY_ALLOWANCE_INSUFFICIENT\"" + }, + "GENERATION_UNSUPPORTED": { + "optional": false, + "readonly": true, + "type": "\"GENERATION_UNSUPPORTED\"" + }, + "INCONSISTENT_READ": { + "optional": false, + "readonly": true, + "type": "\"INCONSISTENT_READ\"" + }, + "INDEX_RACE": { + "optional": false, + "readonly": true, + "type": "\"INDEX_RACE\"" + }, + "INVALID_RULE": { + "optional": false, + "readonly": true, + "type": "\"INVALID_RULE\"" + }, + "NO_RULES_FOR_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"NO_RULES_FOR_CHAIN\"" + }, + "NOT_AGENTIC_WALLET": { + "optional": false, + "readonly": true, + "type": "\"NOT_AGENTIC_WALLET\"" + }, + "NOT_ALLOWED_IN_AGENTIC_MODE": { + "optional": false, + "readonly": true, + "type": "\"NOT_ALLOWED_IN_AGENTIC_MODE\"" + }, + "NOT_OWNER_OR_AGENT": { + "optional": false, + "readonly": true, + "type": "\"NOT_OWNER_OR_AGENT\"" + }, + "NOT_WALLET_OWNER": { + "optional": false, + "readonly": true, + "type": "\"NOT_WALLET_OWNER\"" + }, + "READ_ONLY": { + "optional": false, + "readonly": true, + "type": "\"READ_ONLY\"" + }, + "RECEIPT_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_MISMATCH\"" + }, + "RECEIPT_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_UNAVAILABLE\"" + }, + "REVOKE_NEEDS_TARGET": { + "optional": false, + "readonly": true, + "type": "\"REVOKE_NEEDS_TARGET\"" + }, + "RULE_LIMIT_EXCEEDED": { + "optional": false, + "readonly": true, + "type": "\"RULE_LIMIT_EXCEEDED\"" + }, + "RULE_NOT_FOUND": { + "optional": false, + "readonly": true, + "type": "\"RULE_NOT_FOUND\"" + }, + "RULE_READ_FAILED": { + "optional": false, + "readonly": true, + "type": "\"RULE_READ_FAILED\"" + }, + "TARGET_NOT_ON_RULE_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"TARGET_NOT_ON_RULE_CHAIN\"" + }, + "WALLET_BALANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"WALLET_BALANCE_INSUFFICIENT\"" + }, + "WALLET_NOT_DEPLOYED": { + "optional": false, + "readonly": true, + "type": "\"WALLET_NOT_DEPLOYED\"" + } + } + }, + "AgenticError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"AMBIGUOUS_RULE\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"CREATE_PARTIAL\" | \"FROM_NOT_ALLOWED\" | \"GATEWAY_ALLOWANCE_INSUFFICIENT\" | \"GENERATION_UNSUPPORTED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"REVOKE_NEEDS_TARGET\" | \"RULE_LIMIT_EXCEEDED\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"" + }, + "details": { + "optional": true, + "readonly": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "AgenticRevertError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticRevertError", + "members": { + "agenticCode": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + } + } + }, + "AgenticAddress": { + "type": "`0x${string}`", + "members": {} + }, + "AgenticDoor": { + "type": "\"agent\" | \"owner\"", + "members": {} + }, + "AgenticErrorCode": { + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"AMBIGUOUS_RULE\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"CREATE_PARTIAL\" | \"FROM_NOT_ALLOWED\" | \"GATEWAY_ALLOWANCE_INSUFFICIENT\" | \"GENERATION_UNSUPPORTED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"REVOKE_NEEDS_TARGET\" | \"RULE_LIMIT_EXCEEDED\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"", + "members": {} + }, + "AgenticHex": { + "type": "`0x${string}`", + "members": {} + }, + "AgenticNamespace": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace", + "members": { + "create": { + "optional": false, + "readonly": false, + "type": "(label: string, options: import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions) => Promise" + }, + "derive": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n index?: number;\n}) => Promise<{\n address: `0x${string}`;\n deployed: boolean;\n index: number;\n}>" + }, + "list": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n wallets: import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary[];\n}>" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "(address: `0x${string}`) => import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet" + } + } + }, + "AgenticNetworkConstants": { + "type": "import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants", + "members": { + "ENVELOPE_VERSION": { + "optional": false, + "readonly": false, + "type": "number" + }, + "FACTORY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "MAX_ALLOWED_CALLS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "MAX_PINS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "RULES_POLICY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticProgressHook": { + "type": "(event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void", + "members": {} + }, + "AgenticTxMetadata": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticTxMetadata", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destinationAccount": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "destinationCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "destinationInstruction": { + "optional": true, + "readonly": false, + "type": "{\n accounts: readonly {\n isWritable: boolean;\n pubkey: `0x${string}`;\n }[];\n data: `0x${string}`;\n program: `0x${string}`;\n} | undefined" + }, + "destinationTransfer": { + "optional": true, + "readonly": false, + "type": "{\n amount: bigint;\n recipient: `0x${string}`;\n token: `0x${string}`;\n} | undefined" + }, + "door": { + "optional": false, + "readonly": false, + "type": "\"agent\" | \"owner\"" + }, + "nativeCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "rawData": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rawTo": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesId": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticWallet": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "checkpoints": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n sinceBlock?: bigint;\n}) => Promise<{\n checkpoints: import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint[];\n}>" + }, + "info": { + "optional": false, + "readonly": false, + "type": "() => Promise" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n owner: `0x${string}`;\n}>" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "{\n add(rules: import(\"sdk/src/lib/agentic/agentic.types\").Rule[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise<{\n rulesIds: `0x${string}`[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n get(rulesId: `0x${string}`): Promise;\n list(): Promise<{\n rules: import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord[];\n }>;\n revoke(rulesIds: `0x${string}`[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n revoke(params: {\n all: true;\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n update(params: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n rules: {\n rule: import(\"sdk/src/lib/agentic/agentic.types\").Rule;\n rulesId: `0x${string}`;\n }[];\n }): Promise<{\n rules: {\n replaced: `0x${string}`;\n rulesId: `0x${string}`;\n }[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n}" + }, + "setLabel": { + "optional": false, + "readonly": false, + "type": "(label: string, opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n}) => Promise" + } + } + }, + "AllowedCall": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall", + "members": { + "beneficiary": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "beneficiaryOffset": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValue": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "`${string}(${string})` | `0x${string}`" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AssetCap": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap", + "members": { + "maxPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/constants/tokens\").MoveableToken" + } + } + }, + "Checkpoint": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint", + "members": { + "blockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "kind": { + "optional": false, + "readonly": false, + "type": "\"OWNER_ACTION\" | \"RULES_GRANTED\" | \"RULES_REVOKED\"" + }, + "ref": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "seq": { + "optional": false, + "readonly": false, + "type": "number" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "CheckpointKind": { + "type": "\"OWNER_ACTION\" | \"RULES_GRANTED\" | \"RULES_REVOKED\"", + "members": {} + }, + "CreateOptions": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions", + "members": { + "progressHook": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook | undefined" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Rule[]" + } + } + }, + "CreateResult": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateResult", + "members": { + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "rulesIds": { + "optional": false, + "readonly": false, + "type": "`0x${string}`[]" + }, + "tx": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ForeignChainNamespace": { + "type": "`eip155:${string}` | `solana:${string}`", + "members": {} + }, + "NativeRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "amount": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AmountLimit | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "maxCalls": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValuePerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxValueTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "pins": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ArgPin[] | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "SolanaRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").SolanaRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "allowedInstructions": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").SvmInstructionRule[]" + }, + "assets": { + "optional": false, + "readonly": false, + "type": "{\n maxPerCall: bigint;\n maxTotal?: bigint;\n token: import(\"sdk/src/lib/constants/tokens\").MoveableToken | string;\n}[]" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "`solana:${string}`" + }, + "maxGasPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "outputTokens": { + "optional": true, + "readonly": false, + "type": "string[] | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "DecodedSolanaRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").DecodedSolanaRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "assets": { + "optional": false, + "readonly": false, + "type": "{\n maxPerCall: bigint;\n maxTotal: bigint;\n token: string;\n}[]" + }, + "ceaAccounts": { + "optional": false, + "readonly": false, + "type": "readonly `0x${string}`[]" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "`solana:${string}`" + }, + "dataPins": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/agentic/codec/svm-terms\").SvmDataPinWire[]" + }, + "expectedCEA": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "format": { + "optional": false, + "readonly": false, + "type": "\"decoded\"" + }, + "gatewayProgram": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "maxGasPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pins": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/agentic/codec/svm-terms\").SvmAccountPinWire[]" + }, + "programs": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/agentic/codec/svm-terms\").AllowedProgramWire[]" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "SvmInstructionRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").SvmInstructionRule", + "members": { + "accounts": { + "optional": false, + "readonly": false, + "type": "{\n expected: import(\"sdk/src/lib/agentic/agentic.types\").SvmAccountRef;\n name: string;\n}[]" + }, + "fields": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").SvmFieldConstraint[] | undefined" + }, + "instruction": { + "optional": false, + "readonly": false, + "type": "{\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n name: string;\n}" + }, + "program": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "SvmAccountRef": { + "type": "{\n address: string;\n kind: \"address\";\n} | {\n kind: \"walletATA\";\n token: string;\n} | {\n kind: \"walletCEA\";\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"address\" | \"walletATA\" | \"walletCEA\"" + } + } + }, + "SvmFieldConstraint": { + "type": "{\n denominator: string;\n minRatio: {\n den: bigint;\n num: bigint;\n };\n numerator: string;\n} | {\n equals: `0x${string}` | bigint | boolean;\n name: string;\n} | {\n max: bigint;\n name: string;\n} | {\n min: bigint;\n name: string;\n}", + "members": {} + }, + "Rule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule | import(\"sdk/src/lib/agentic/agentic.types\").SolanaRule | import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "`eip155:${string}` | `solana:${string}` | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "RulesRecord": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "enabled": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "rule": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").DecodedSolanaRule | import(\"sdk/src/lib/agentic/agentic.types\").Rule" + }, + "rulesId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Selector": { + "type": "`${string}(${string})` | `0x${string}`", + "members": {} + }, + "UniversalRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall[]" + }, + "assets": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap[]" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "`eip155:${string}`" + }, + "maxGasPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "WalletInfo": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").WalletInfo", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "label": { + "optional": false, + "readonly": false, + "type": "string" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "rulesCount": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "WalletSummary": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "label": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesCount": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "PushChain": { + "type": "import(\"sdk/src/lib/push-chain/push-chain\").PushChain", + "members": { + "accountStatus": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus" + }, + "accountStatusReady": { + "optional": false, + "readonly": false, + "type": "Promise" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace" + }, + "explorer": { + "optional": false, + "readonly": false, + "type": "{\n getTransactionUrl: (txHash: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n listAllUrls: () => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n listUrls: (options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n}" + }, + "funds": { + "optional": false, + "readonly": false, + "type": "{\n getConversionQuote: (amountIn: bigint, options: {\n from: import(\"sdk/src/lib/constants/tokens\").PayableToken | undefined;\n to: import(\"sdk/src/lib/constants/tokens\").MoveableToken | undefined;\n }) => Promise;\n}" + }, + "getAccountStatus": { + "optional": false, + "readonly": false, + "type": "(options?: {\n forceRefresh?: boolean;\n}) => Promise" + }, + "isReadMode": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "moveable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").MoveableTokenAccessor;\n}" + }, + "payable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").PayableTokenAccessor;\n}" + }, + "reinitialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "universal": { + "optional": false, + "readonly": false, + "type": "{\n readonly account: `0x${string}`;\n executeReads: (reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>;\n executeTransactions: (txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise;\n migrateCEA: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"migrateCEA\"];\n readonly origin: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n prepareRead: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n prepareTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"prepareTransaction\"];\n read: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n rescueFunds: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"rescueFunds\"];\n sendTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"execute\"];\n signMessage: (data: Uint8Array) => Promise;\n signTypedData: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n trackRead: {\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n };\n trackTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"trackTransaction\"];\n}" + }, + "upgradeAccount": { + "optional": false, + "readonly": false, + "type": "(options?: {\n progressHook?: (progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n}) => Promise" + } + } + } + }, + "pushChainStatic": { + "CONSTANTS": { + "optional": false, + "readonly": false, + "type": "{\n AGENTIC: Readonly>>;\n CHAIN: typeof import(\"sdk/src/lib/constants/enums\").CHAIN;\n LIBRARY: typeof import(\"sdk/src/lib/constants/enums\").LIBRARY;\n MOVEABLE: {\n TOKEN: import(\"sdk/src/lib/constants/tokens\").MoveableTokenConstantsMap;\n };\n PAYABLE: {\n TOKEN: import(\"sdk/src/lib/constants/tokens\").PayableTokenConstantsMap;\n };\n PUSH_NETWORK: typeof import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n READ: {\n readonly CALLBACK_BUDGET_BUFFER: 3;\n readonly CHAIN: {\n readonly WEB2: \"web2\";\n } & Readonly<{\n readonly ARBITRUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA;\n readonly BASE_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA;\n readonly BNB_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET;\n readonly ETHEREUM_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET;\n readonly ETHEREUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA;\n readonly PUSH_LOCALNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET;\n readonly PUSH_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET;\n readonly PUSH_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly PUSH_TESTNET_DONUT: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly SOLANA_DEVNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET;\n readonly SOLANA_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET;\n readonly SOLANA_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n readonly WEB2: \"web2\";\n }>;\n readonly DEFAULT_EXPIRY_BLOCKS: 300n;\n readonly ERROR_CODE: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n readonly MAX_CALLBACK_GAS_LIMIT: 1000000n;\n readonly MIN_CONFIRMATIONS_FLOOR: 1;\n readonly NAMESPACE: {\n readonly EVM: \"eip155\";\n readonly SVM: \"solana\";\n readonly WEB2: \"web2\";\n };\n readonly OUTCOME: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME;\n readonly REGISTRY_CALLBACK_GAS: 500000n;\n readonly RESULT_STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n readonly STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS;\n readonly UNIVERSAL_CALLBACK_ADDRESSES: Record;\n readonly UNIVERSAL_CORE_ADDRESSES: Record;\n readonly UNIVERSAL_READ_REGISTRY_ADDRESS: {\n readonly TESTNET_DONUT: \"0x00000000000000000000000000000000000000b2\";\n };\n readonly WEB2: \"web2\";\n readonly WEB2_DEFAULT_TIMEOUT_MS: 5000;\n readonly WEB2_MAX_EXTRACT_ENTRIES: 16;\n };\n}" + }, + "initialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "utils": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/utils\").Utils" + } + }, + "pushChainInstance": { + "accountStatus": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus" + }, + "accountStatusReady": { + "optional": false, + "readonly": false, + "type": "Promise" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace" + }, + "explorer": { + "optional": false, + "readonly": false, + "type": "{\n getTransactionUrl: (txHash: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n listAllUrls: () => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n listUrls: (options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n}" + }, + "funds": { + "optional": false, + "readonly": false, + "type": "{\n getConversionQuote: (amountIn: bigint, options: {\n from: import(\"sdk/src/lib/constants/tokens\").PayableToken | undefined;\n to: import(\"sdk/src/lib/constants/tokens\").MoveableToken | undefined;\n }) => Promise;\n}" + }, + "getAccountStatus": { + "optional": false, + "readonly": false, + "type": "(options?: {\n forceRefresh?: boolean;\n}) => Promise" + }, + "isReadMode": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "moveable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").MoveableTokenAccessor;\n}" + }, + "payable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").PayableTokenAccessor;\n}" + }, + "reinitialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "universal": { + "optional": false, + "readonly": false, + "type": "{\n readonly account: `0x${string}`;\n executeReads: (reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>;\n executeTransactions: (txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise;\n migrateCEA: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"migrateCEA\"];\n readonly origin: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n prepareRead: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n prepareTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"prepareTransaction\"];\n read: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n rescueFunds: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"rescueFunds\"];\n sendTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"execute\"];\n signMessage: (data: Uint8Array) => Promise;\n signTypedData: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n trackRead: {\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n };\n trackTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"trackTransaction\"];\n}" + }, + "upgradeAccount": { + "optional": false, + "readonly": false, + "type": "(options?: {\n progressHook?: (progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n}) => Promise" + } + }, + "transactionMethods": { + "account": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "executeReads": { + "optional": false, + "readonly": false, + "type": "(reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>" + }, + "executeTransactions": { + "optional": false, + "readonly": false, + "type": "(txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise" + }, + "migrateCEA": { + "optional": false, + "readonly": false, + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => Promise" + }, + "origin": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "prepareRead": { + "optional": false, + "readonly": false, + "type": "(subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>" + }, + "prepareTransaction": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions) => Promise" + }, + "read": { + "optional": false, + "readonly": false, + "type": "(subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>" + }, + "rescueFunds": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").RescueFundsParams) => Promise" + }, + "sendTransaction": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").ExecuteParams | import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions) => Promise" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": false, + "readonly": false, + "type": "({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise" + }, + "trackRead": { + "optional": false, + "readonly": false, + "type": "{\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n}" + }, + "trackTransaction": { + "optional": false, + "readonly": false, + "type": "(txHash: string, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TrackTransactionOptions) => Promise" + } + }, + "utilityMethods": { + "account": { + "optional": false, + "readonly": false, + "type": "{\n convertExecutorToOriginAccount: (ueaAddress: `0x${string}`, options?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n }) => Promise;\n convertOriginToExecutor: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n onlyCompute?: boolean;\n }) => Promise;\n deriveExecutorAccount: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n skipNetworkCheck?: boolean;\n }) => Promise;\n fromChainAgnostic: (caip: string) => import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n resolveControllerAccount: (address: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n skipNetworkCheck?: boolean;\n }) => Promise;\n toChainAgnostic: (address: string, options: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n toUniversal: (address: string, options: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n}" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "{\n actionId: (target: `0x${string}`, selector: \"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector) => `0x${string}`;\n configId: (wallet: `0x${string}`, rulesId: `0x${string}`, actionId: `0x${string}`) => `0x${string}`;\n decodeRules: (bytes: `0x${string}`, ctx?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n pushChainNamespace?: string;\n }) => import(\"sdk/src/lib/agentic/agentic.types\").DecodedSolanaRule | import(\"sdk/src/lib/agentic/agentic.types\").Rule;\n}" + }, + "chains": { + "optional": false, + "readonly": false, + "type": "{\n getChainName: (chainNamespace: string) => string | undefined;\n getChainNamespace: (chainName: string) => string | undefined;\n getSupportedChains: (network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK) => {\n chains: import(\"sdk/src/lib/constants/enums\").CHAIN[];\n };\n getSupportedChainsByName: (network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK) => {\n chains: string[];\n };\n}" + }, + "conversion": { + "optional": false, + "readonly": false, + "type": "{\n slippageToMinAmount(amount: string, options: {\n slippageBps: number;\n }): string;\n}" + }, + "helpers": { + "optional": false, + "readonly": false, + "type": "{\n encodeTxData({ abi, idl, functionName, args, }: {\n abi?: any;\n args?: any[];\n functionName: string;\n idl?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n }): `0x${string}`;\n formatUnits(value: bigint | string, decimalsOrOptions: {\n decimals: number;\n precision?: number;\n } | number): string;\n getChainName: (chainName: string) => string | undefined;\n parseUnits(value: string, exponent: {\n decimals: number;\n } | number): bigint;\n}" + }, + "signer": { + "optional": false, + "readonly": false, + "type": "{\n construct: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options: {\n signAndSendTransaction: (unsignedTx: Uint8Array) => Promise;\n signAuthorization?: (params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise;\n signMessage: (data: Uint8Array) => Promise;\n signTypedData?: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n }) => import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton;\n toUniversal: (signer: import(\"sdk/src/lib/universal/universal.types\").EthersV5SignerType | import(\"sdk/src/lib/universal/universal.types\").EthersV6SignerType | import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton | import(\"sdk/src/lib/universal/universal.types\").ViemSignerType) => Promise;\n toUniversalFromKeypair: (clientOrAccount: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@solana/web3.js/lib/index\").Keypair | import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").WalletClient | import(\"sdk/src/lib/universal/universal.types\").EthersV6SignerType, { chain, library }: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n library: import(\"sdk/src/lib/constants/enums\").LIBRARY;\n }) => Promise;\n}" + }, + "svm": { + "optional": false, + "readonly": false, + "type": "{\n getRegisteredIdls: () => Array<{\n address: `0x${string}`;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n }>;\n registerIdl: (idl: unknown) => void;\n}" + }, + "tokens": { + "optional": false, + "readonly": false, + "type": "{\n getMoveableTokens(chainOrClient?: import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/push-chain/push-chain\").PushChain): {\n tokens: Array<{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n decimals: number;\n mechanism: \"approve\" | \"native\" | \"permit2\";\n prc20Address?: `0x${string}`;\n sourceChain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n symbol: string;\n }>;\n };\n getPayableTokens(chainOrClient?: import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/push-chain/push-chain\").PushChain): {\n tokens: Array<{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n decimals: number;\n mechanism: \"approve\" | \"native\" | \"permit2\";\n symbol: string;\n }>;\n };\n getPC20Address(address: string, options: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n rpcUrls?: Partial>;\n strict?: boolean;\n }): Promise;\n getPRC20Address: (token: {\n address: string;\n chain: string;\n } | import(\"sdk/src/lib/constants/tokens\").MoveableToken, options?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n }) => {\n address: `0x${string}`;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n decimals: number;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n symbol: string;\n };\n}" + } + }, + "initialize": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise", + "agwConstants": { + "ENVELOPE_VERSION": { + "optional": false, + "readonly": false, + "type": "number" + }, + "FACTORY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "MAX_ALLOWED_CALLS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "MAX_PINS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "RULES_POLICY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + }, + "constants": { + "AGENTIC": { + "optional": false, + "readonly": false, + "type": "{\n readonly LOCALNET?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n readonly MAINNET?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n readonly TESTNET?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n readonly TESTNET_DONUT?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n}" + }, + "CHAIN": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "LIBRARY": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").LIBRARY" + }, + "MOVEABLE": { + "optional": false, + "readonly": false, + "type": "{\n TOKEN: import(\"sdk/src/lib/constants/tokens\").MoveableTokenConstantsMap;\n}" + }, + "PAYABLE": { + "optional": false, + "readonly": false, + "type": "{\n TOKEN: import(\"sdk/src/lib/constants/tokens\").PayableTokenConstantsMap;\n}" + }, + "PUSH_NETWORK": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "READ": { + "optional": false, + "readonly": false, + "type": "{\n readonly CALLBACK_BUDGET_BUFFER: 3;\n readonly CHAIN: {\n readonly WEB2: \"web2\";\n } & Readonly<{\n readonly ARBITRUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA;\n readonly BASE_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA;\n readonly BNB_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET;\n readonly ETHEREUM_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET;\n readonly ETHEREUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA;\n readonly PUSH_LOCALNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET;\n readonly PUSH_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET;\n readonly PUSH_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly PUSH_TESTNET_DONUT: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly SOLANA_DEVNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET;\n readonly SOLANA_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET;\n readonly SOLANA_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n readonly WEB2: \"web2\";\n }>;\n readonly DEFAULT_EXPIRY_BLOCKS: 300n;\n readonly ERROR_CODE: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n readonly MAX_CALLBACK_GAS_LIMIT: 1000000n;\n readonly MIN_CONFIRMATIONS_FLOOR: 1;\n readonly NAMESPACE: {\n readonly EVM: \"eip155\";\n readonly SVM: \"solana\";\n readonly WEB2: \"web2\";\n };\n readonly OUTCOME: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME;\n readonly REGISTRY_CALLBACK_GAS: 500000n;\n readonly RESULT_STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n readonly STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS;\n readonly UNIVERSAL_CALLBACK_ADDRESSES: Record;\n readonly UNIVERSAL_CORE_ADDRESSES: Record;\n readonly UNIVERSAL_READ_REGISTRY_ADDRESS: {\n readonly TESTNET_DONUT: \"0x00000000000000000000000000000000000000b2\";\n };\n readonly WEB2: \"web2\";\n readonly WEB2_DEFAULT_TIMEOUT_MS: 5000;\n readonly WEB2_MAX_EXTRACT_ENTRIES: 16;\n}" + } + } + }, + "scope": "All root exports and declared public members, PushChain static/instance members, universal transaction methods, utility groups, readonly/optional markers and constants. Behavior/default/deployment changes need the written session review." +} diff --git a/plan/agw/research/extended-v5-e2e-2026-10-07/credential-scan.json b/plan/agw/research/extended-v5-e2e-2026-10-07/credential-scan.json new file mode 100644 index 00000000..2638f264 --- /dev/null +++ b/plan/agw/research/extended-v5-e2e-2026-10-07/credential-scan.json @@ -0,0 +1,4 @@ +{ + "scanned": 204, + "credentialMatches": [] +} diff --git a/plan/agw/research/extended-v5-e2e-2026-10-07/evm-explicit-cosmos.json b/plan/agw/research/extended-v5-e2e-2026-10-07/evm-explicit-cosmos.json new file mode 100644 index 00000000..fe51488c --- /dev/null +++ b/plan/agw/research/extended-v5-e2e-2026-10-07/evm-explicit-cosmos.json @@ -0,0 +1 @@ +[] diff --git a/plan/agw/research/extended-v5-e2e-2026-10-07/evm-explicit-gas-events-raw.json b/plan/agw/research/extended-v5-e2e-2026-10-07/evm-explicit-gas-events-raw.json new file mode 100644 index 00000000..fe51488c --- /dev/null +++ b/plan/agw/research/extended-v5-e2e-2026-10-07/evm-explicit-gas-events-raw.json @@ -0,0 +1 @@ +[] diff --git a/plan/agw/research/extended-v5-e2e-2026-10-07/evm-explicit-gas-events.json b/plan/agw/research/extended-v5-e2e-2026-10-07/evm-explicit-gas-events.json new file mode 100644 index 00000000..fe51488c --- /dev/null +++ b/plan/agw/research/extended-v5-e2e-2026-10-07/evm-explicit-gas-events.json @@ -0,0 +1 @@ +[] diff --git a/plan/agw/research/extended-v5-e2e-2026-10-07/evm-explicit-node-records.json b/plan/agw/research/extended-v5-e2e-2026-10-07/evm-explicit-node-records.json new file mode 100644 index 00000000..fe51488c --- /dev/null +++ b/plan/agw/research/extended-v5-e2e-2026-10-07/evm-explicit-node-records.json @@ -0,0 +1 @@ +[] diff --git a/plan/agw/research/extended-v5-e2e-2026-10-07/evm-explicit-success.json b/plan/agw/research/extended-v5-e2e-2026-10-07/evm-explicit-success.json new file mode 100644 index 00000000..d0aaf607 --- /dev/null +++ b/plan/agw/research/extended-v5-e2e-2026-10-07/evm-explicit-success.json @@ -0,0 +1,7 @@ +{ + "hash": "0x05842ed536ce0c298233bec9afd807a8c721513fc9092d079cccd916ac70f7bb", + "gasLimit": "2000000", + "gasUsed": "1265746", + "status": "success", + "block": "11863465" +} diff --git a/plan/agw/research/extended-v5-e2e-2026-10-07/evm-failed-destination.json b/plan/agw/research/extended-v5-e2e-2026-10-07/evm-failed-destination.json new file mode 100644 index 00000000..8e411185 --- /dev/null +++ b/plan/agw/research/extended-v5-e2e-2026-10-07/evm-failed-destination.json @@ -0,0 +1,45 @@ +{ + "tx": { + "blockHash": "0x73efb0b0598f4256b2074f08c9f8831f4da12add7486ea7ca7aef2a57f549ca0", + "blockNumber": "11863151", + "blockTimestamp": "0x6ac64298", + "from": "0x9fed6f778a956244c06a3b905ba45bdb2ec3afea", + "gas": "500000", + "gasPrice": "1100026", + "hash": "0xf91e4cc9e2605ff9f27d575ceb9e928dadddd1755a428112021ef9983738abb7", + "input": "0x40a31fe2ba8aafd675f92c2cd74ae627bf430338a54ec81894cc078bfea235fb67f4dcaec042fcac8ebeb211a83218f0e55acc33e1658f90e825b08ae8dd3b9860f09f290000000000000000000000003c461162312c8a55e65c3f3905afda4b92a14d7900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e8d4a5100000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001042cc2842d000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000f1552ed5ac48c273570500bd10b10c00e1c418bb000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000004d09de08a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "nonce": 50083, + "to": "0xd019eb12d0d6ef8d299661f22b4b7d262ed4b965", + "transactionIndex": 100, + "value": "1000000000000", + "type": "legacy", + "chainId": 11155111, + "v": "22310257", + "r": "0xb6339cf288b8ac60e2378202304c4e3cc980780b1e56b1b4fa58448e9c7d59bf", + "s": "0x62f709a2cb6bd1fd0647e6304c3178d5f228814f35ac8e4968008e0cf1c5d4a1", + "typeHex": "0x0" + }, + "receipt": { + "blockHash": "0x73efb0b0598f4256b2074f08c9f8831f4da12add7486ea7ca7aef2a57f549ca0", + "blockNumber": "11863151", + "contractAddress": null, + "cumulativeGasUsed": "77674744", + "effectiveGasPrice": "1100026", + "from": "0x9fed6f778a956244c06a3b905ba45bdb2ec3afea", + "gasUsed": "222972", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "status": "reverted", + "to": "0xd019eb12d0d6ef8d299661f22b4b7d262ed4b965", + "transactionHash": "0xf91e4cc9e2605ff9f27d575ceb9e928dadddd1755a428112021ef9983738abb7", + "transactionIndex": 100, + "type": "legacy" + }, + "trace": { + "error": "HTTP request failed." + }, + "call": { + "error": "Execution reverted for an unknown reason.", + "details": "execution reverted" + } +} diff --git a/plan/agw/research/extended-v5-e2e-2026-10-07/evm-failure-followup.json b/plan/agw/research/extended-v5-e2e-2026-10-07/evm-failure-followup.json new file mode 100644 index 00000000..98ceb1ca --- /dev/null +++ b/plan/agw/research/extended-v5-e2e-2026-10-07/evm-failure-followup.json @@ -0,0 +1,14 @@ +{ + "VAULT": "0xD019Eb12D0d6eF8D299661f22B4B7d262eD4b965", + "CEA_PROXY_IMPLEMENTATION": "0x425291f35BA1A94Bd2dcC2dC097c2B55700A1fB6", + "CEA_IMPLEMENTATION": "0x1972646e4208c5Fe20914c3E09Ba339df43D9CB0", + "deploy": { + "result": "0xFA06Ea99a62c760d11d40B787eAd7225b69d3aCf" + }, + "call500000": { + "error": "Execution reverted for an unknown reason.", + "details": "execution reverted" + }, + "call5000000": {}, + "estimatedFreshCeaFinalizationGas": "1304470" +} diff --git a/plan/agw/research/extended-v5-e2e-2026-10-07/live-evidence.jsonl b/plan/agw/research/extended-v5-e2e-2026-10-07/live-evidence.jsonl new file mode 100644 index 00000000..18785013 --- /dev/null +++ b/plan/agw/research/extended-v5-e2e-2026-10-07/live-evidence.jsonl @@ -0,0 +1,32 @@ +{"name": "universal-destination-revert", "at": "2026-10-07T13:03:30.315Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0x3c461162312c8A55e65C3F3905aFDa4B92A14D79", "pushTx": "0xd6ef67aee6697f753c1353cb72bbc3a7f7adef9ce2c05bb7b79dfb544e2b9d42", "externalStatus": "failed"} +{"name": "public-svm-setup", "at": "2026-10-07T13:04:31.162Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0xC905D911FB11Cf7490E61Ae7A19396b9BD9d440b", "id": "0x8b9814f4b460d740c3bf7b1218093867e7b27965fc88067819684ec501f2b10c", "grantHash": "0xada541d69a65a8ba61808c8c221e893ee2ff34ed8eb6ae4bf9dcfc6649383775", "cea": "FsyabVBzK46spbndEZwsXS8UgR5PQ93HtcqpK5AQ1R9v", "recipient": "3nK8X1re4zLNrgz9Y3xKS4g2fKPJ6M3N9BhNuFfkjwAb"} +{"name": "public-svm-replacement", "at": "2026-10-07T13:04:50.171Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0xC905D911FB11Cf7490E61Ae7A19396b9BD9d440b", "id": "0xdf5a44a59a7a70fac2c38b7c9d170fd8610d9787fa8531f34522a707b0808e92", "txHash": "0x822598e1d2eab4e7f86655ba8cf0979737edb4c7c5e5fe97f4dc162cd53c6ef0"} +{"name": "public-svm-submitted", "at": "2026-10-07T13:05:06.779Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0xC905D911FB11Cf7490E61Ae7A19396b9BD9d440b", "id": "0xdf5a44a59a7a70fac2c38b7c9d170fd8610d9787fa8531f34522a707b0808e92", "hash": "0x1b525875791e4172d1643ca2725ca4933e13a0e9433c7c4c9c78a952dae3ea86"} +{"name": "public-svm-delivered", "at": "2026-10-07T13:06:20.641Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0xC905D911FB11Cf7490E61Ae7A19396b9BD9d440b", "hash": "0x1b525875791e4172d1643ca2725ca4933e13a0e9433c7c4c9c78a952dae3ea86", "destinationHash": "4Eo6hZoh5Ro5GrLRpz7bkv9bwdP2efcaNwLNH9xjRfn1Cgtfhvf2KVbak1to2xxvyBKRWD56YyEMRGqYYuYvQFUk", "instruction": {"program": "0x7673075a980bfd5d6b1dffe99c31f63e8938519cc1c2af009dda5e568a94460d", "data": "0x79f4fa0308e5e1011027000000000000", "accounts": [{"pubkey": "0x4f12fe6816ae7e33ebf7db0b154ec3b09e3bf1a7690481e8e9477d5a278ad3af", "isWritable": true}, {"pubkey": "0x2953026d328218b107268efe60f7d98635af1ff535a91731f75ca7cf8a859044", "isWritable": true}, {"pubkey": "0xdd12a1ba3121401d0c0e0ed20c5ce07f90ca11399714739a1387510418a6d575", "isWritable": true}, {"pubkey": "0x0000000000000000000000000000000000000000000000000000000000000000", "isWritable": false}]}} +{"name": "public-svm-contract-refusals", "at": "2026-10-07T13:06:41.535Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0xC905D911FB11Cf7490E61Ae7A19396b9BD9d440b", "id": "0xdf5a44a59a7a70fac2c38b7c9d170fd8610d9787fa8531f34522a707b0808e92", "agentNonce": 1, "state": {"tokens": "10000", "pcBalance": "40369379674144047445", "checkpoints": "7", "spent": ["10000"]}} +{"name": "public-svm-owner-transfer-submitted", "at": "2026-10-07T13:07:04.001Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0xC905D911FB11Cf7490E61Ae7A19396b9BD9d440b", "hash": "0xf5ac64f229a285985da031342aaabba904af4a1afb9717013eb158ae8c25fcde"} +{"name": "public-svm-owner-transfer-delivered", "at": "2026-10-07T13:08:23.087Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0xC905D911FB11Cf7490E61Ae7A19396b9BD9d440b", "hash": "0xf5ac64f229a285985da031342aaabba904af4a1afb9717013eb158ae8c25fcde", "destinationHash": "3xKuVZ3rvFLYWgmKbhPVLFEZpYcHpVybZfdogRpSJYsAodomANRjQaiyVyNLCCEkaqxQ34EBvT8Xfe1f5EeJAr2D", "recipient": "3nK8X1re4zLNrgz9Y3xKS4g2fKPJ6M3N9BhNuFfkjwAb", "amount": "10000"} +{"name": "v5-label-default-custom", "at": "2026-10-07T13:15:15.082Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallets": ["0xb70e13E47651ea9ebB26b62C5530204e1a1Ecde9", "0x5Da80edA2e48fda6C997585E5253beaF6D4e52DE"], "indices": [16, 17], "hashes": ["0x8f54c5b9c403335897ae25dd985e65f2702679054c8a586053237489b1e11e8e", "0x35681c3076eb8da6c7bd0e879759222b3fd3b0ca6b7f5116708f35eff0b37f3f", "0x1d5e3e0240484171cd35319cec6f60989a6b0915f226d01e2c86f5221c45a03d"]} +{"name": "v5-label-rename-reset", "at": "2026-10-07T13:15:59.178Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0xD5499dCa4082374Ac6e7B82e0d0086aacB34097c", "hashes": ["0x31ccecf6a76372035650e5570ee057cea376f882772e86aa934f7412c5f0a80b", "0x555b99c02a1e1774fda0685f4a4af3bd3f4c51f311a9108c45d50f2bc15cdd14"], "checkpointsBefore": "0", "checkpointsAfter": "2"} +{"name": "v5-label-byte-boundary", "at": "2026-10-07T13:16:21.411Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0xBb790C48045afEb9878bA1f648Eb895825fCb596", "checkpoints": "1", "unchangedNextSlot": 20} +{"name": "v5-label-agent-refused", "at": "2026-10-07T13:16:39.031Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0x3D407438b1dbB2EF6d66aD3D94Bb402F39D6306F", "checkpoints": "1"} +{"name": "v5-label-uea-owner", "at": "2026-10-07T13:17:31.930Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0x19b64878E52658a4390DAAC7D5Dd52E8466FbAB9", "owner": "0x5C70C864Cf1aDfB04A0e107fFA248ba3600EAb8D", "hashes": ["0x70025b20c360d4b8db40de326621a88fce0cf9b207374a824f6253e6d3c827f5", "0xf29404374074848939c38c88920c9819409775b07b95f558676a3f7286c7943e", "0x19be422a1de88b9fdd177d4b37d43e88a0fbfe74f3b10828173854fd4320c548"], "checkpointsBefore": "0", "checkpointsAfter": "2"} +{"name": "v5-label-solana-owner", "at": "2026-10-07T13:18:20.716Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0x23F2e20a3D6CBA6AD3a1C3364C41d1FDe4FEe8C5", "owner": "0xad977a75D8BEd06579D6498b7e2e3885f9D31F15", "hashes": ["0xf3321b6f170317e219c2ca13e0b1401ef08c79d40cfc86d697b00b4912947fd1", "0x0cce0bcec7f9bfe07c41ef22e12b0d38621ca132b0df5f93c314592f3d393235", "0xe0ec10679fbe860f9d9ccf69a0626775ed1e6d4cf497c162c649c1dd755f34eb"], "checkpointsBefore": "0", "checkpointsAfter": "2"} +{"name": "v5-label-active-rule", "at": "2026-10-07T13:19:07.570Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0x3F6680B891248900A9eb6D886C27911F211CFb4B", "rulesId": "0x305bda56c59c99c050a007f4a7166bf4b3f29cd302982771363f7240ba0fead6", "hashes": ["0x581feba3171b7d99b4d25babd674e8b030d6e8a120cb21b65946774080092606", "0x053f9d887791edf2f41bcc5da4d742dfe510b0430bf0419b3632438ba6800a04", "0xe4371b01237750c1f4e6cadf0ea4cd918329924eeff8c3bd4e66c3018302b449"], "spendBefore": {"valueSpent": "1", "amountSpent": "0", "callsUsed": 1}, "spendAfter": {"valueSpent": "2", "amountSpent": "0", "callsUsed": 2}, "grantNonce": "1"} +{"name": "v5-label-batch-rollback", "at": "2026-10-07T13:19:23.779Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0x02288178E780d54a53a4E4170b370CeE9d324300", "hash": "0x0904eb583e188945a07aeb4542d9f82b01cc18186bc13da5e07215d3b5c4c0f6", "block": "23993562", "gasUsed": "200000", "status": "reverted", "checkpoints": "0"} +{"name": "universal-destination-revert", "at": "2026-10-07T13:34:11.642Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0xb045C61F185718a0DB614B355CCada4d99fD0510", "pushTx": "0x7a1544ffaf26c1d8807a20d19991f59d0abe2e6b5f82a7e3ef2fb6ff0e2e08b2", "externalStatus": "failed"} +{"name": "v5-two-token-replacement", "at": "2026-10-07T13:34:52.255Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0x6cD97f78a5d8EDb669be1A472dC30716fc39F148", "oldId": "0x7bec5118b772d5c509dbc72661cddf97135465db88fd1571e0b95e8cc9806556", "newId": "0x5e9fab71dc21352e55ec76e52c5217025b809757716f56dbf0cbe0b11525ca21", "txHash": "0x7c5d096e3182558125a0c9cc463fdbed394720335f8b723518e37d83fda6ed08"} +{"name": "v5-call-only", "at": "2026-10-07T13:36:41.334Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0x3f3cE51de56544d9f6a655DD2E31729C2e1D2B4f", "pushTx": "0x7b19c1405da5ec099db77c9324f2f4f6ab252631497aca0e0872ef8b4570b5c0", "externalTx": "0x418ca768b33baf4ba472ac8b9349dad42dd02d99ff3c045a0fe76d34722902cd"} +{"name": "v5-independent-token-budgets", "at": "2026-10-07T13:40:25.774Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0x8611fD4cdD2f66e46c1Fd662d0BE07D09c7589D5", "rulesId": "0x7bec5118b772d5c509dbc72661cddf97135465db88fd1571e0b95e8cc9806556", "tokens": ["0x2971824Db68229D087931155C2b8bB820B275809", "0x7A58048036206bB898008b5bBDA85697DB1e5d66"], "amounts": ["1000000000000", "10"], "spent": ["1000000000000", "10"], "hashes": ["0xfaaf5856b068ba9b78556216072f0456e3b28ba14f3f2aab4bea5674784628fe", "0xa984c11996b92faacad565f4762dcf5dfdccf114060d9d2ba75b570e093fcbed", "0xa727fdd8d2423ceb1d8a605725815336a6ab67a05eddbd057eb70d78ea713df5", "0x5e2c328d16d3c6a9c728683ad1988698d69f9c5310ede64b56aa43d18add327d"]} +{"name": "v5-evm-outbound-submitted", "at": "2026-10-07T14:03:38.215Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0x8a92851E2672E728B078Ed672DF3Ba95839Ed045", "cea": "0xF8662bBb2c3a6490114A13Bd5CC3A1Fd09d5faB1", "pushTx": "0xc7c481e856eb84dfc4970a81ef25eed0aad21e6d2ccc1183cce15546159ae8bb", "destinationGasLimit": "2000000"} +{"name": "universal-outbound", "at": "2026-10-07T14:05:07.101Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0x8a92851E2672E728B078Ed672DF3Ba95839Ed045", "cea": "0xF8662bBb2c3a6490114A13Bd5CC3A1Fd09d5faB1", "rulesId": "0x7f1b3e73f18cfaddba4c22f6a3fd7b360ef7ce9282bec9d65ab38883697ff54b", "pushTx": "0xc7c481e856eb84dfc4970a81ef25eed0aad21e6d2ccc1183cce15546159ae8bb", "externalTx": "0x05842ed536ce0c298233bec9afd807a8c721513fc9092d079cccd916ac70f7bb", "amount": "1000000000000"} +{"name": "universal-destination-revert", "at": "2026-10-07T14:07:13.191Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0x8a92851E2672E728B078Ed672DF3Ba95839Ed045", "pushTx": "0xaf1d3eea7f3b281ef4586b629fe4c021419a2e4a10f4270f12adddb6e50c2fc9", "externalStatus": "failed"} +{"name": "v5-spl-owner-submitted", "at": "2026-10-07T14:08:10.674Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0xC4635F40A0925f8adf2c2B0B0C021F9330b28AF0", "hash": "0xdd0ae0081a55e5e8ebbda2b5e3c37e616ba74c94985b8e17d47536aeb3547cfb", "mint": "EiXDnrAg9ea2Q6vEPV7E5TpTU1vh41jcuZqKjU5Dc4ZF", "recipient": "3nK8X1re4zLNrgz9Y3xKS4g2fKPJ6M3N9BhNuFfkjwAb", "ata": "oVL4eb7hqoq4iJEZ4mPf9Hgd5ys3EzaXuCpZ434aRRt", "amount": "1000"} +{"name": "v5-spl-owner-delivered", "at": "2026-10-07T14:09:36.083Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0xC4635F40A0925f8adf2c2B0B0C021F9330b28AF0", "hash": "0xdd0ae0081a55e5e8ebbda2b5e3c37e616ba74c94985b8e17d47536aeb3547cfb", "destinationHash": "5UVT2JFJqEuAeGb5NUsn63sUCE7xJkypR8qwJrqgDFm2JTiSWoGZy62R5uX75C9vDJHbr8Tcy9YF7XRJcmzv3xCF", "mint": "EiXDnrAg9ea2Q6vEPV7E5TpTU1vh41jcuZqKjU5Dc4ZF", "recipient": "3nK8X1re4zLNrgz9Y3xKS4g2fKPJ6M3N9BhNuFfkjwAb", "ata": "oVL4eb7hqoq4iJEZ4mPf9Hgd5ys3EzaXuCpZ434aRRt", "beforeRecipient": "9995959000", "afterRecipient": "9995960000", "amount": "1000"} +{"name": "public-svm-setup", "at": "2026-10-07T14:22:29.834Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0xE6BEcbb5FB2463099A10f535242Fdc29650DBAA6", "id": "0xa4cd3c6c7d9db29c19784a91d92e4127f9c80070c20d89f0694c08e19eed6da6", "grantHash": "0xea31b4d3b89d1672fc727bd71e45610b9c7ab4ca640c278c10923b9b3146a174", "cea": "3Mqez5ddDU9VVMy12gEpWDCe6Lqw4yaRGvf6k3jPQEwe", "recipient": "3nK8X1re4zLNrgz9Y3xKS4g2fKPJ6M3N9BhNuFfkjwAb"} +{"name": "public-svm-replacement", "at": "2026-10-07T14:22:54.795Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0xE6BEcbb5FB2463099A10f535242Fdc29650DBAA6", "id": "0xef27e402c9d606935e5048768c146af3da2ff4a60e81c77f656029f09663d842", "txHash": "0xca808841b002042c2848f1480b62ceecc7880aed045ca78053d45caa2843139d"} +{"name": "public-svm-submitted", "at": "2026-10-07T14:23:15.756Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0xE6BEcbb5FB2463099A10f535242Fdc29650DBAA6", "id": "0xef27e402c9d606935e5048768c146af3da2ff4a60e81c77f656029f09663d842", "hash": "0x4fa10b1edfb832a895c16d7fbcde733ba398e6bcb3eae344737223a2f8b31bf9"} +{"name": "public-svm-delivered", "at": "2026-10-07T14:24:30.636Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0xE6BEcbb5FB2463099A10f535242Fdc29650DBAA6", "hash": "0x4fa10b1edfb832a895c16d7fbcde733ba398e6bcb3eae344737223a2f8b31bf9", "destinationHash": "23t5UMQxKvBzoXk7uZAQc5xqpnCN6gioqm6gkBNGHDywo2pm1BRSNrMwAvXWwPe6rZLBTQZDitq2LaGC6TjDDrFR", "instruction": {"program": "0x7673075a980bfd5d6b1dffe99c31f63e8938519cc1c2af009dda5e568a94460d", "data": "0x79f4fa0308e5e1011027000000000000", "accounts": [{"pubkey": "0x4f12fe6816ae7e33ebf7db0b154ec3b09e3bf1a7690481e8e9477d5a278ad3af", "isWritable": true}, {"pubkey": "0x2953026d328218b107268efe60f7d98635af1ff535a91731f75ca7cf8a859044", "isWritable": true}, {"pubkey": "0x230e011a0d2f4e49884464a5078c5b83cff464fc757ab6b3b5e9fc32df81f96d", "isWritable": true}, {"pubkey": "0x0000000000000000000000000000000000000000000000000000000000000000", "isWritable": false}]}} +{"name": "public-svm-contract-refusals", "at": "2026-10-07T14:24:53.102Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0xE6BEcbb5FB2463099A10f535242Fdc29650DBAA6", "id": "0xef27e402c9d606935e5048768c146af3da2ff4a60e81c77f656029f09663d842", "agentNonce": 1, "state": {"tokens": "10000", "pcBalance": "40369379595049366856", "checkpoints": "7", "spent": ["10000"]}} +{"name": "public-svm-owner-transfer-submitted", "at": "2026-10-07T14:25:23.143Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0xE6BEcbb5FB2463099A10f535242Fdc29650DBAA6", "hash": "0x134ecf6fe57d4cfe796660ec7179930bb22570b303c38f92f87b16bf857b5e95"} +{"name": "public-svm-owner-transfer-delivered", "at": "2026-10-07T14:26:58.875Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0xE6BEcbb5FB2463099A10f535242Fdc29650DBAA6", "hash": "0x134ecf6fe57d4cfe796660ec7179930bb22570b303c38f92f87b16bf857b5e95", "destinationHash": "5RC9jrEyyGEZYYqiYmzmWKqG5woFMiKjjeq14Rt1p49nuVLfw3sgurduqQbFkgePftfzn3wNCufFy7BsusA1H8eD", "recipient": "3nK8X1re4zLNrgz9Y3xKS4g2fKPJ6M3N9BhNuFfkjwAb", "amount": "10000"} diff --git a/plan/agw/research/extended-v5-e2e-2026-10-07/logs/actual-contracts.log b/plan/agw/research/extended-v5-e2e-2026-10-07/logs/actual-contracts.log new file mode 100644 index 00000000..f84c63cf --- /dev/null +++ b/plan/agw/research/extended-v5-e2e-2026-10-07/logs/actual-contracts.log @@ -0,0 +1,30 @@ +PASS core-agw-local packages/core/__agw-local__/v5-multiasset.spec.ts (7.919 s) +PASS core-agw-local packages/core/__agw-local__/svm-backend.spec.ts (7.71 s) +PASS core-agw-local packages/core/__agw-local__/vectors.spec.ts +PASS core-agw-local packages/core/__agw-local__/svm-public.spec.ts (5.087 s) +PASS core-agw-local packages/core/__agw-local__/agw-local-advanced.spec.ts +PASS core-agw-local packages/core/__agw-local__/svm-differential.spec.ts + ● Console + + console.log + {"corpus":"svm-grant","seed":23063,"cases":107,"accepted":38,"rejected":69,"mismatches":[]} + + at Object. (__agw-local__/svm-differential.spec.ts:226:13) + + console.log + {"corpus":"svm-payload","seed":23063,"cases":88,"accepted":6,"rejected":82,"mismatches":[]} + + at Object. (__agw-local__/svm-differential.spec.ts:407:13) + +PASS core-agw-local packages/core/__agw-local__/labels.spec.ts +PASS core-agw-local packages/core/__agw-local__/agw-local-batch.spec.ts +PASS core-agw-local packages/core/__agw-local__/delayed-index.spec.ts +PASS core-agw-local packages/core/__agw-local__/agw-local-races.spec.ts +PASS core-agw-local packages/core/__agw-local__/agw-local.spec.ts +PASS core-agw-local packages/core/__agw-local__/svm-internals.spec.ts + +Test Suites: 12 passed, 12 total +Tests: 90 passed, 90 total +Snapshots: 0 total +Time: 38.992 s, estimated 44 s +Ran all test suites. diff --git a/plan/agw/research/extended-v5-e2e-2026-10-07/logs/api.log b/plan/agw/research/extended-v5-e2e-2026-10-07/logs/api.log new file mode 100644 index 00000000..0b5c2eee --- /dev/null +++ b/plan/agw/research/extended-v5-e2e-2026-10-07/logs/api.log @@ -0,0 +1 @@ +{"compiledMatchesSource":true,"addedExports":["DecodedSolanaRule","SolanaRule","SvmAccountRef","SvmFieldConstraint","SvmInstructionRule"],"removedExports":[],"changedAgwTypes":["AgenticError","AGENTIC_ERROR_CODE","NativeRule","AllowedCall","UniversalRule","RulesRecord","AgenticTxMetadata"],"publicTypeChanges":["AGENTIC_ERROR_CODE","AgenticError","AgenticErrorCode","AgenticNetworkConstants","AgenticTxMetadata","AllowedCall","NativeRule","SolanaRule","DecodedSolanaRule","SvmInstructionRule","SvmAccountRef","SvmFieldConstraint","Rule","RulesRecord","UniversalRule"],"transactionMethodChanges":[],"instanceMethodChanges":[],"initializeSignatureChanged":false,"agwConstantsChanged":true} diff --git a/plan/agw/research/extended-v5-e2e-2026-10-07/logs/build.log b/plan/agw/research/extended-v5-e2e-2026-10-07/logs/build.log new file mode 100644 index 00000000..7742e881 --- /dev/null +++ b/plan/agw/research/extended-v5-e2e-2026-10-07/logs/build.log @@ -0,0 +1,11 @@ + +> nx run core:build + +Compiling TypeScript files for project "core"... +Done compiling TypeScript files for project "core". +(node:1508) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. +(Use `node --trace-warnings ...` to show where the warning was created) + + + + NX Successfully ran target build for project core diff --git a/plan/agw/research/extended-v5-e2e-2026-10-07/logs/default-manifest.log b/plan/agw/research/extended-v5-e2e-2026-10-07/logs/default-manifest.log new file mode 100644 index 00000000..dfa5f250 --- /dev/null +++ b/plan/agw/research/extended-v5-e2e-2026-10-07/logs/default-manifest.log @@ -0,0 +1,79 @@ +✓ smoke-uea-derive-evm 1 test +✓ smoke-read-track-lookup 1 test +✓ smoke-cea-derive-evm 1 test +✓ smoke-roundtrip-evm 1 test +✓ smoke-roundtrip-svm 1 test +✓ smoke-cea-pda-svm 1 test +✓ smoke-gasfee-reads 2 tests +✓ smoke-gas-sizer 2 tests +✓ smoke-pc20-registry 2 tests +✓ smoke-pc20-resolve 1 test +✓ evm-r1-transfer 1 test +✓ evm-r1-funds-usdt 1 test +✓ evm-r1-funds-native 1 test +✓ evm-r1-value-funds-data 1 test +✓ evm-r1-bridge-multicall 1 test +✓ evm-r1-fresh-value-native 1 test +✓ evm-r2-funds-erc20 1 test +✓ evm-r2-payload 1 test +✓ evm-r2-multicall 1 test +✓ evm-r2-funds-payload 1 test +✓ evm-r2-native-funds 1 test +✓ evm-r2-native-funds-payload 1 test +✓ evm-r3-funds-erc20 1 test +✓ evm-r3-payload 1 test +✓ evm-r3-multicall 1 test +✓ evm-r3-funds-payload 1 test +✓ evm-r3-native-funds 1 test +✓ evm-r3-eoa-native-funds 1 test +✓ svm-r1-transfer 1 test +✓ svm-r1-funds-sol-self 1 test +✓ svm-r1-value-self 1 test +✓ svm-r1-data-contract 1 test +✓ svm-r1-fresh-key-repro 1 test +✓ svm-r2-funds-sol 1 test +✓ svm-r2-funds-spl 1 test +✓ svm-r2-payload-cpi 1 test +✓ svm-r2-sol-cpi 1 test +✓ svm-r3-drain-sol 1 test +✓ svm-r3-drain-spl 1 test +✓ pc20-export-deployed-wrapper 1 test +✓ pc20-export-predicts-wrapper 1 test +✓ pc20-inbound-burn-unlock 1 test +✓ pc20-r3-cea-burn 1 test +✓ pc20-svm-r1-direct-burn 1 test +✓ pc20-svm-r3-cea-ata-burn 1 test +✓ push-send-transaction 1 test +✓ push-value-own-uea 1 test +✓ push-multicall-no-funds 1 test +✓ push-track-r1-sepolia-parity 1 test +✓ push-track-r3-funds-roundtrip 1 test +✓ push-track-source-leg-hashes 2 tests +✓ xc-multi-child-r3 1 test +✓ xc-fresh-wallet-r3 1 test +✓ xc-peth-bridge-back 1 test +✓ xc-cascade-6hop 1 test +✓ read-evm-balance-eoa 1 test +✓ read-canonical-registry 1 test +✓ read-evm-balance-uea 1 test +✓ read-evm-contract-call 1 test +✓ read-evm-callback-reverts 1 test +✓ read-expiry 1 test +✓ read-svm-lamports 1 test +✓ read-web2-json 1 test +✓ read-docs-example 1 test +✓ read-docs-evm-balance 1 test +✓ read-docs-batch 1 test +✓ read-docs-resume 2 tests +✓ read-app-batch-eoa 1 test +✓ read-app-batch-uea 1 test +✓ read-app-batch-recovery 1 test +✓ read-api-token 1 test +✓ read-api-mixed-outcomes 1 test +✓ read-svm-token-auto 1 test +✓ read-svm-idl 1 test +✓ read-evm-any-mutability 1 test +✓ read-svm-raw 1 test + +76 scenarios, 40 spec files, 81 distinct tests. +Manifest is consistent with the specs. diff --git a/plan/agw/research/extended-v5-e2e-2026-10-07/logs/destinations-final-evm-spl.log b/plan/agw/research/extended-v5-e2e-2026-10-07/logs/destinations-final-evm-spl.log new file mode 100644 index 00000000..9bcfcc3f --- /dev/null +++ b/plan/agw/research/extended-v5-e2e-2026-10-07/logs/destinations-final-evm-spl.log @@ -0,0 +1,25 @@ +PASS core-e2e packages/core/__e2e__/agw/universal-evm.spec.ts (279.893 s) + ● Console + + console.log + [ExternalTxVerifier] Verifying EVM tx on eip155:11155111: 0x05842ed536ce0c298233bec9afd807a8c721513fc9092d079cccd916ac70f7bb + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [ExternalTxVerifier] EVM tx 0x05842ed536ce0c298233bec9afd807a8c721513fc9092d079cccd916ac70f7bb on eip155:11155111: status=0x1 + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [ExternalTxVerifier] EVM tx CONFIRMED SUCCESS on eip155:11155111 + + at console.log (__e2e__/shared/logger.ts:42:5) + +PASS core-e2e packages/core/__e2e__/agw/svm-spl-transfer.spec.ts (142.869 s) + +Test Suites: 2 passed, 2 total +Tests: 3 passed, 3 total +Snapshots: 0 total +Time: 422.795 s, estimated 807 s +Ran all test suites within paths "packages/core/__e2e__/agw/svm-spl-transfer.spec.ts", "packages/core/__e2e__/agw/universal-evm.spec.ts". diff --git a/plan/agw/research/extended-v5-e2e-2026-10-07/logs/destinations-initial-default.log b/plan/agw/research/extended-v5-e2e-2026-10-07/logs/destinations-initial-default.log new file mode 100644 index 00000000..da8be10a --- /dev/null +++ b/plan/agw/research/extended-v5-e2e-2026-10-07/logs/destinations-initial-default.log @@ -0,0 +1,36 @@ +FAIL core-e2e packages/core/__e2e__/agw/universal-evm.spec.ts (245.031 s) + ● Console + + console.log + [ExternalTxVerifier] Verifying EVM tx on eip155:11155111: 0xf91e4cc9e2605ff9f27d575ceb9e928dadddd1755a428112021ef9983738abb7 + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [ExternalTxVerifier] EVM tx 0xf91e4cc9e2605ff9f27d575ceb9e928dadddd1755a428112021ef9983738abb7 on eip155:11155111: status=0x0 + + at console.log (__e2e__/shared/logger.ts:42:5) + + ● agw universal evm › 1. positive-amount outbound: allowance pull/burn, the wallet CEA executes on Sepolia, receipts and replay identity + + ExternalTxFailedError: [ExternalTxVerifier] EVM tx 0xf91e4cc9e2605ff9f27d575ceb9e928dadddd1755a428112021ef9983738abb7 on eip155:11155111 FAILED on-chain: receipt status=0x0 (expected 0x1). The external chain transaction reverted. + + 78 | // Definitive failure — receipt exists but tx reverted. No point retrying. + 79 | if (status !== '0x1') { + > 80 | throw new ExternalTxFailedError( + | ^ + 81 | `[ExternalTxVerifier] EVM tx ${txHash} on ${chainName} FAILED on-chain: receipt status=${status} (expected 0x1). The external chain transaction reverted.` + 82 | ); + 83 | } + + at verifyEvmTransaction (__e2e__/shared/external-tx-verifier.ts:80:15) + at async verifyExternalTransaction (__e2e__/shared/external-tx-verifier.ts:221:5) + at async Object. (__e2e__/agw/universal-evm.spec.ts:157:5) + +PASS core-e2e packages/core/__e2e__/agw/svm-public.spec.ts (304.031 s) + +Test Suites: 1 failed, 1 passed, 2 total +Tests: 1 failed, 7 passed, 8 total +Snapshots: 0 total +Time: 549.097 s +Ran all test suites within paths "packages/core/__e2e__/agw/universal-evm.spec.ts", "packages/core/__e2e__/agw/svm-public.spec.ts". diff --git a/plan/agw/research/extended-v5-e2e-2026-10-07/logs/destinations-initial-explicit.log b/plan/agw/research/extended-v5-e2e-2026-10-07/logs/destinations-initial-explicit.log new file mode 100644 index 00000000..e11df0a8 --- /dev/null +++ b/plan/agw/research/extended-v5-e2e-2026-10-07/logs/destinations-initial-explicit.log @@ -0,0 +1,144 @@ +FAIL core-e2e packages/core/__e2e__/agw/universal-evm.spec.ts (759.246 s) + ● agw universal evm › 1. positive-amount outbound: allowance pull/burn, the wallet CEA executes on Sepolia, receipts and replay identity + + expect(received).toBe(expected) // Object.is equality + + Expected: "success" + Received: "timeout" + + 159 | expect(receipt.status).toBe(1); + 160 | expect(receipt.from).toBe(wallet); + > 161 | expect(receipt.externalStatus).toBe('success'); + | ^ + 162 | expect(receipt.externalTxHash).toBeTruthy(); + 163 | await verifyExternalTransaction(receipt.externalTxHash as string, SEPOLIA); + 164 | const destinationReceipt = await sep.getTransactionReceipt({ + + at Object. (__e2e__/agw/universal-evm.spec.ts:161:36) + +PASS core-e2e packages/core/__e2e__/agw/v5-multiasset.spec.ts (374.118 s) + ● Console + + console.log + [ExternalTxVerifier] Verifying EVM tx on eip155:11155111: 0x418ca768b33baf4ba472ac8b9349dad42dd02d99ff3c045a0fe76d34722902cd + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [ExternalTxVerifier] Attempt 1 failed, retrying in 10000ms... + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [ExternalTxVerifier] EVM tx 0x418ca768b33baf4ba472ac8b9349dad42dd02d99ff3c045a0fe76d34722902cd on eip155:11155111: status=0x1 + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [ExternalTxVerifier] EVM tx CONFIRMED SUCCESS on eip155:11155111 + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [ExternalTxVerifier] Verifying EVM tx on eip155:11155111: 0xa984c11996b92faacad565f4762dcf5dfdccf114060d9d2ba75b570e093fcbed + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [ExternalTxVerifier] EVM tx 0xa984c11996b92faacad565f4762dcf5dfdccf114060d9d2ba75b570e093fcbed on eip155:11155111: status=0x1 + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [ExternalTxVerifier] EVM tx CONFIRMED SUCCESS on eip155:11155111 + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [ExternalTxVerifier] Verifying EVM tx on eip155:11155111: 0x5e2c328d16d3c6a9c728683ad1988698d69f9c5310ede64b56aa43d18add327d + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [ExternalTxVerifier] EVM tx 0x5e2c328d16d3c6a9c728683ad1988698d69f9c5310ede64b56aa43d18add327d on eip155:11155111: status=0x1 + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [ExternalTxVerifier] EVM tx CONFIRMED SUCCESS on eip155:11155111 + + at console.log (__e2e__/shared/logger.ts:42:5) + +FAIL core-e2e packages/core/__e2e__/agw/svm-spl-transfer.spec.ts (47.75 s) + ● agw svm spl transfer › 1. owner funds-only SPL delivery credits the recipient ATA and preserves burn, allowance and replay + + AgenticError: SOURCE_TOKEN_ADDRESS read on 0x4f1A3D22d170a2F4Bddb37845a962322e24f4e34 failed at block 23994097 + + 51 | })) as T; + 52 | } catch (cause) { + > 53 | throw new AgenticError( + | ^ + 54 | this.failCode, + 55 | `${functionName} read on ${address} failed at block ${this.blockNumber}`, + 56 | { + + at Snapshot.read (src/lib/agentic/reads/snapshot.ts:53:13) + at async quoteSvmRequest (src/lib/agentic/execution/svm-quote.ts:39:15) + at async sendPublicSvm (src/lib/agentic/execution/svm-public.ts:146:19) + at async Object. (__e2e__/agw/svm-spl-transfer.spec.ts:121:16) + + Cause: + ContractFunctionExecutionError: Position `32` is out of bounds (`0 < position < 32`). + + Contract Call: + address: 0x4f1A3D22d170a2F4Bddb37845a962322e24f4e34 + function: SOURCE_TOKEN_ADDRESS() + + Docs: https://viem.sh/docs/contract/readContract + Version: viem@2.27.2 + + 43 | ): Promise { + 44 | try { + > 45 | return (await this.reader.readContract({ + | ^ + 46 | address, + 47 | abi, + 48 | functionName, + + at getContractError (../../node_modules/viem/utils/errors/getContractError.ts:78:10) + at readContract (../../node_modules/viem/actions/public/readContract.ts:136:27) + at async Snapshot.read (src/lib/agentic/reads/snapshot.ts:45:15) + at async quoteSvmRequest (src/lib/agentic/execution/svm-quote.ts:39:15) + at async sendPublicSvm (src/lib/agentic/execution/svm-public.ts:146:19) + at async Object. (__e2e__/agw/svm-spl-transfer.spec.ts:121:16) + + Cause: + PositionOutOfBoundsError: Position `32` is out of bounds (`0 < position < 32`). + + Version: viem@2.27.2 + + 43 | ): Promise { + 44 | try { + > 45 | return (await this.reader.readContract({ + | ^ + 46 | address, + 47 | abi, + 48 | functionName, + + at Object.assertPosition (../../node_modules/viem/utils/cursor.ts:79:13) + at Object.setPosition (../../node_modules/viem/utils/cursor.ts:210:10) + at decodeString (../../node_modules/viem/utils/abi/decodeAbiParameters.ts:357:12) + at decodeParameter (../../node_modules/viem/utils/abi/decodeAbiParameters.ts:113:39) + at decodeAbiParameters (../../node_modules/viem/utils/abi/decodeAbiParameters.ts:75:31) + at decodeFunctionResult (../../node_modules/viem/utils/abi/decodeFunctionResult.ts:161:37) + at readContract (../../node_modules/viem/actions/public/readContract.ts:129:32) + at async Snapshot.read (src/lib/agentic/reads/snapshot.ts:45:15) + at async quoteSvmRequest (src/lib/agentic/execution/svm-quote.ts:39:15) + at async sendPublicSvm (src/lib/agentic/execution/svm-public.ts:146:19) + at async Object. (__e2e__/agw/svm-spl-transfer.spec.ts:121:16) + +Test Suites: 2 failed, 1 passed, 3 total +Tests: 2 failed, 4 passed, 6 total +Snapshots: 0 total +Time: 1181.178 s +Ran all test suites within paths "packages/core/__e2e__/agw/universal-evm.spec.ts", "packages/core/__e2e__/agw/v5-multiasset.spec.ts", "packages/core/__e2e__/agw/svm-spl-transfer.spec.ts". diff --git a/plan/agw/research/extended-v5-e2e-2026-10-07/logs/docs.log b/plan/agw/research/extended-v5-e2e-2026-10-07/logs/docs.log new file mode 100644 index 00000000..8d1582db --- /dev/null +++ b/plan/agw/research/extended-v5-e2e-2026-10-07/logs/docs.log @@ -0,0 +1 @@ +AGW guide: 10 TypeScript blocks typechecked against public exports; no examples executed. diff --git a/plan/agw/research/extended-v5-e2e-2026-10-07/logs/full-unit.log b/plan/agw/research/extended-v5-e2e-2026-10-07/logs/full-unit.log new file mode 100644 index 00000000..b73697e7 --- /dev/null +++ b/plan/agw/research/extended-v5-e2e-2026-10-07/logs/full-unit.log @@ -0,0 +1,173 @@ +PASS core packages/core/src/lib/agentic/__tests__/svm-quote.spec.ts +PASS core packages/core/src/lib/universal/account/account.spec.ts (9.962 s) + ● Console + + console.warn + [PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead. + + 207 | ): Promise { + 208 | if (!_convertOriginToExecutorWarned) { + > 209 | console.warn( + | ^ + 210 | '[PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead.' + 211 | ); + 212 | _convertOriginToExecutorWarned = true; + + at Object.convertOriginToExecutor (src/lib/universal/account/account.ts:209:13) + at Object. (src/lib/universal/account/account.spec.ts:80:52) + + console.warn + [PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead. + + 425 | ): Promise { + 426 | if (!options?._internal && !_convertExecutorToOriginWarned) { + > 427 | console.warn( + | ^ + 428 | '[PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead.' + 429 | ); + 430 | _convertExecutorToOriginWarned = true; + + at convertExecutorToOrigin (src/lib/universal/account/account.ts:427:13) + at Object. (src/lib/universal/account/account.spec.ts:106:38) + +PASS core packages/core/src/lib/read-state/__tests__/block-results-client.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-tx-retry.spec.ts +PASS core packages/core/src/lib/push-client/push-client.archive-fallback.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-confirmation-gate.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/labels.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/response-surface.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/management.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-timeout-clamp.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r2-outbound-revert-flow.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-evm-r3-native-eoa.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/send.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/rescue-svm-confirmation.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-tracker.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/codec.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/source-hash-resolution.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/response-invariant.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/context-helpers-tracker.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-composition.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-svm-confirmation.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/reads-context.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/inbound-tracker-derivation.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-backend.spec.ts +PASS core packages/core/src/lib/universal/signer/signer.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/payload-builders.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/public-surface.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/account-status.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/resolve.spec.ts +PASS core packages/core/src/lib/utils.spec.ts + ● Console + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:973:17) + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:977:17) + + console.log + 1.23 + + at Object. (src/lib/utils.spec.ts:982:17) + +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm-rent-pc20.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/registry.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/cascade.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-svm-r3.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/track-transaction-guard.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gateway-uea-account.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-request-recipient.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-executor.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/signing-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-native-multicall.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/export.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/web2-compat.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/scenarios.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/gate.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r1-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/terminal-suppression.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-usd-sizer.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-multichain.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-detector.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/resolver.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-svm-rent.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/read-tx-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-builder-progress-hook.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r3-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/svm-rent.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/response-builder-push-revert.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/chain-namespace.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/funds-only-burn-guard.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/build-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-error-classification.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-idl.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/send-transaction-progress-hook.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r2-spec-strings.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/multichain-hooks.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-emission.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/execute-standard-required-funds.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-event-hook-bridge.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-calculator.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/inbound-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-classification.spec.ts +PASS core packages/core/src/lib/push-client/push-client.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-svm.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/address-codec.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-params.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/svm-account.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/spec-builder.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/child-inbounds.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/revalidate-read.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-wire-fixture.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/result-decoder.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-evm.spec.ts +PASS core packages/core/src/lib/constants/__tests__/token-constants.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm-log-index.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/__tests__/signing.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/normalize.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/abi-selectors.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/auto-detect.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.chain-symbol.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/ucallback-codec.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg-svm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/validate.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-events.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.batch-gas.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-web2.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.dynamic-gas.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-types.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/registry.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/ix-encoder.spec.ts +PASS core packages/core/src/lib/constants/__tests__/svm-gateway-idl.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/error-decoder.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/tracking.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/classify.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/normalize-address.spec.ts +PASS core packages/core/src/lib/formatters.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-execute-order.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/max-pc-for-gas.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/budget.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/errors.spec.ts + +Test Suites: 1 skipped, 120 passed, 120 of 121 total +Tests: 12 skipped, 2014 passed, 2026 total +Snapshots: 0 total +Time: 31.572 s +Ran all test suites. diff --git a/plan/agw/research/extended-v5-e2e-2026-10-07/logs/funding-preflight-dry-run.log b/plan/agw/research/extended-v5-e2e-2026-10-07/logs/funding-preflight-dry-run.log new file mode 100644 index 00000000..ba4db232 --- /dev/null +++ b/plan/agw/research/extended-v5-e2e-2026-10-07/logs/funding-preflight-dry-run.log @@ -0,0 +1,27 @@ +AGW deployment manifest verified on-chain. +Solana wire fixture verified read-only before funding. + +Wallets + EVM master (Sepolia) 0x0A16CBa65FfCAa4C2282b27b027Ab4A2fE46E0Bf + Push master (Donut) 0x0A16CBa65FfCAa4C2282b27b027Ab4A2fE46E0Bf + Solana master (Devnet) 3nK8X1re4zLNrgz9Y3xKS4g2fKPJ6M3N9BhNuFfkjwAb + Shared UEA (Donut) 0x5C70C864Cf1aDfB04A0e107fFA248ba3600EAb8D + UEA CEA PDA (Devnet) Fqp8UeJxEWvN1Ciu5jqrA3opGXwNvRL2HfJxNQotj3Qh + +Group "agw" — 58 scenarios, headroom ×1.25. + +┌────────────────────────┬───────────┬──────────┬─────────────┬────────┐ +│ Scope │ Asset │ Need │ Have │ Status │ +├────────────────────────┼───────────┼──────────┼─────────────┼────────┤ +│ EVM master (Sepolia) │ ETH │ 0.027500 │ 3.8372 │ ✓ │ +│ Push master (Donut) │ PC │ 588.8125 │ 969762.3672 │ ✓ │ +│ Push master (Donut) │ pETH │ 0.000014 │ 434.3115 │ ✓ │ +│ Push master (Donut) │ pSOL │ 0.000150 │ 5.7690 │ ✓ │ +│ Push master (Donut) │ pUSDT.sol │ 0.001250 │ 10006.8169 │ ✓ │ +│ Push master (Donut) │ pUSDC.eth │ 0.000014 │ 44642.9077 │ ✓ │ +│ Solana master (Devnet) │ SOL │ 0.013750 │ 0.615391 │ ✓ │ +│ UEA (Donut) │ PC │ 15.0000 │ 6193.4999 │ ✓ │ +└────────────────────────┴───────────┴──────────┴─────────────┴────────┘ + +All master wallets can cover this run. +Derived accounts are already at target. Ready to run. diff --git a/plan/agw/research/extended-v5-e2e-2026-10-07/logs/labels-live.log b/plan/agw/research/extended-v5-e2e-2026-10-07/logs/labels-live.log new file mode 100644 index 00000000..eeca3068 --- /dev/null +++ b/plan/agw/research/extended-v5-e2e-2026-10-07/logs/labels-live.log @@ -0,0 +1,16 @@ +PASS core-e2e packages/core/__e2e__/agw/labels.spec.ts (317.919 s) + agw labels + ✓ 1. default and custom deployment labels are stored and listed (57364 ms) + ✓ 2. owner rename and empty reset update info/list, emit LabelSet and tick the owner door (44096 ms) + ✓ 3. UTF-8 byte boundaries are accepted or rejected without changing wallet state (22232 ms) + ✓ 4. an agent cannot rename through either the SDK or the contract (17619 ms) + ✓ 5. an external EVM owner creates and renames through its UEA (52898 ms) + ✓ 6. a Solana-origin owner creates, renames and resets through its UEA (48788 ms) + ✓ 7. renaming an active wallet preserves rules, spend and remaining agent budget (46853 ms) + ✓ 8. a failed owner batch rolls back the earlier rename and all checkpoints (16207 ms) + +Test Suites: 1 passed, 1 total +Tests: 8 passed, 8 total +Snapshots: 0 total +Time: 317.944 s +Ran all test suites within paths "packages/core/__e2e__/agw/labels.spec.ts". diff --git a/plan/agw/research/extended-v5-e2e-2026-10-07/logs/lint.log b/plan/agw/research/extended-v5-e2e-2026-10-07/logs/lint.log new file mode 100644 index 00000000..b494a098 --- /dev/null +++ b/plan/agw/research/extended-v5-e2e-2026-10-07/logs/lint.log @@ -0,0 +1,11 @@ + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/agw/svm-spl-transfer.spec.ts + 171:51 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 177:49 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/agw/v5-multiasset.spec.ts + 35:17 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 274:39 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 333:28 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +✖ 5 problems (0 errors, 5 warnings) diff --git a/plan/agw/research/extended-v5-e2e-2026-10-07/logs/manifest.log b/plan/agw/research/extended-v5-e2e-2026-10-07/logs/manifest.log new file mode 100644 index 00000000..ac1e6f4f --- /dev/null +++ b/plan/agw/research/extended-v5-e2e-2026-10-07/logs/manifest.log @@ -0,0 +1,61 @@ +✓ agw-create-bare 1 test +✓ agw-create-rules 1 test +✓ agw-funding-pc 1 test +✓ agw-funding-allowance 1 test +✓ agw-native-batch 1 test +✓ agw-native-batch-rollback 1 test +✓ agw-native-agent 1 test +✓ agw-native-owner 1 test +✓ agw-native-over-cap 1 test +✓ agw-native-stranger 1 test +✓ agw-native-revoked 1 test +✓ agw-native-expired 1 test +✓ agw-lifecycle-add 1 test +✓ agw-lifecycle-update 1 test +✓ agw-lifecycle-checkpoints 1 test +✓ agw-lifecycle-revoke-all 1 test +✓ agw-universal-outbound 1 test +✓ agw-v5-multi-asset 1 test +✓ agw-v5-call-only 1 test +✓ agw-universal-dest-revert 1 test +✓ agw-identity-evm 1 test +✓ agw-identity-first-use 1 test +✓ agw-identity-solana 1 test +✓ agw-responses-hooks 1 test +✓ agw-responses-replay 1 test +✓ agw-public-svm-1 1 test +✓ agw-public-svm-2 1 test +✓ agw-public-svm-3 1 test +✓ agw-public-svm-4 1 test +✓ agw-public-svm-5 1 test +✓ agw-public-svm-6 1 test +✓ agw-labels-1 1 test +✓ agw-labels-2 1 test +✓ agw-labels-3 1 test +✓ agw-labels-4 1 test +✓ agw-labels-5 1 test +✓ agw-labels-6 1 test +✓ agw-labels-7 1 test +✓ agw-labels-8 1 test +✓ agw-v5-independent-token-budgets 1 test +✓ agw-owner-spl-transfer 1 test +✓ agw-extended-prefunding 1 test +✓ agw-extended-ambiguous-rules 1 test +✓ agw-extended-batched-lifecycle 1 test +✓ agw-extended-invalid-revoke 1 test +✓ agw-extended-stale-update 1 test +✓ agw-extended-index-race 1 test +✓ agw-extended-native-policy-1 1 test +✓ agw-extended-native-policy-2 1 test +✓ agw-extended-native-policy-3 1 test +✓ agw-extended-native-policy-4 1 test +✓ agw-extended-native-policy-5 1 test +✓ agw-extended-native-policy-6 1 test +✓ agw-extended-native-policy-7 1 test +✓ agw-extended-native-policy-8 1 test +✓ agw-extended-native-policy-9 1 test +✓ agw-extended-native-policy-10 1 test +✓ agw-extended-native-policy-11 1 test + +58 scenarios, 14 spec files, 58 distinct tests. +Manifest is consistent with the specs. diff --git a/plan/agw/research/extended-v5-e2e-2026-10-07/logs/native-sol-final.log b/plan/agw/research/extended-v5-e2e-2026-10-07/logs/native-sol-final.log new file mode 100644 index 00000000..9755829b --- /dev/null +++ b/plan/agw/research/extended-v5-e2e-2026-10-07/logs/native-sol-final.log @@ -0,0 +1,14 @@ +PASS core-e2e packages/core/__e2e__/agw/svm-public.spec.ts (337.85 s) + agw public svm + ✓ 1. named IDL grant reads exact constraints and replaces atomically (24961 ms) + ✓ 2. public send confirms actual CEA transfer and preserves replay identity (95840 ms) + ✓ 3. contract simulation maps account and data refusals without state changes (22467 ms) + ✓ 4. public revoke removes the Solana rule and subsequent sends are refused (14659 ms) + ✓ 5. owner funds-only transfer reaches the recipient and replays with the same amount (111114 ms) + ✓ 6. agents still require an instruction and owner allowance failures do not sign (11055 ms) + +Test Suites: 1 passed, 1 total +Tests: 6 passed, 6 total +Snapshots: 0 total +Time: 337.879 s +Ran all test suites within paths "packages/core/__e2e__/agw/svm-public.spec.ts". diff --git a/plan/agw/research/extended-v5-e2e-2026-10-07/logs/package.log b/plan/agw/research/extended-v5-e2e-2026-10-07/logs/package.log new file mode 100644 index 00000000..8e1b97e4 --- /dev/null +++ b/plan/agw/research/extended-v5-e2e-2026-10-07/logs/package.log @@ -0,0 +1 @@ +AGW package: CJS/ESM imports, compiled declaration examples and npm contents pass. No examples executed/published. diff --git a/plan/agw/research/extended-v5-e2e-2026-10-07/logs/types.log b/plan/agw/research/extended-v5-e2e-2026-10-07/logs/types.log new file mode 100644 index 00000000..e69de29b diff --git a/plan/agw/research/extended-v5-e2e-2026-10-07/spl-metadata-probe.json b/plan/agw/research/extended-v5-e2e-2026-10-07/spl-metadata-probe.json new file mode 100644 index 00000000..fd05e141 --- /dev/null +++ b/plan/agw/research/extended-v5-e2e-2026-10-07/spl-metadata-probe.json @@ -0,0 +1,7 @@ +{ + "block": "23994422", + "token": "0x4f1A3D22d170a2F4Bddb37845a962322e24f4e34", + "rawReturn": "0x0000000000000000000000000000000000000000000000000000000000000000", + "mintHex": "0x0000000000000000000000000000000000000000000000000000000000000000", + "mintBase58": "11111111111111111111111111111111" +} diff --git a/plan/agw/research/sdk-alignment-fixes-2026-10-07/README.md b/plan/agw/research/sdk-alignment-fixes-2026-10-07/README.md new file mode 100644 index 00000000..29161d8d --- /dev/null +++ b/plan/agw/research/sdk-alignment-fixes-2026-10-07/README.md @@ -0,0 +1,48 @@ +# SDK alignment fixes — G27/G28 + +Both findings from the [source refresh](../source-refresh-2026-10-07/README.md) are implemented. No contract changes or new team questions are required. `setLabel` remains gated on its verified ABI/deployment. + +## Behavior + +**G27:** production Solana sends resolve and encode the request without evaluating granted expiry, amounts, account pins, data pins or program allow-lists locally. The contract/simulation enforces the chosen rule. Refusals flow through `wrapSendError` to `AgenticRevertError` with `decodedError`. EVM local PC-cap and asset-membership rejection was also removed; actual contract failures use the mapper there too. + +SDK shape, context, asset-chain, wallet/signer balance and gateway-allowance guards remain. These are `AgenticError`s and do not pretend to be contract reverts. The strict pure SVM validators remain internal diagnostic tools; production sends do not use them to decide permissions. + +**G28:** the owner door can send native SOL or SPL funds without an IDL/instruction. Requests have the specified 32-byte recipient, a positive amount and empty payload. The agent door still requires an encoded instruction. Neither door changes allowances automatically. + +Send/wait/replay preserve wallet identity. Funds-only metadata adds `agentic.destinationTransfer = {recipient, token, amount}`; token is the burned Push PRC20. Native SOL transfers show the amount in `value`, SPL transfers show zero native value. Instruction metadata is absent for funds-only sends. A historical metadata-read failure retains the actual gateway summary and outbound polling rather than inventing transfer details. + +Solana fee quoting now reuses core's finalization/rent budget with the AGW as execution identity and the actual source SPL mint. This covers conditional token-account rent without accidentally quoting the signer's CEA. + +## Validation + +| Check | Result | +| --- | --- | +| Full units | 2,003 passed, 0 failed; 12 existing skips | +| Actual contract harness | 85 passed, 0 failed; 11 suites | +| Public Solana live suite | Six scenarios have passing selected-run coverage | +| Owner funds-only SOL delivery | Passed: recipient balance increase, wallet debit, successful external receipt, wait/replay identity and amount | +| Contract refusal mapping | Passed live: account/data gates decoded as AgenticRevertError; balances, spend counters, checkpoints and nonce unchanged | +| Owner SPL funds-only | Passed locally: actual wallet/gateway pull+burn, quote mint/wallet context and zero native display value; no new live SPL transfer claimed | +| Build and types | Core build; lib/spec/local-contract/AGW-E2E typechecks pass | +| Package/API/docs | Packed imports, declarations, compiled API comparison and nine guide TypeScript blocks pass | +| Lint | Zero errors in changed TypeScript files; test-fixture non-null assertion warnings retained | +| Manifest | AGW: 48 scenarios/12 files/48 tests; default all remains 76/40/81 | + +The first full six-case live run passed five cases, including funds-only delivery, and failed the refusal case with a non-policy SDK AgenticError while using an omitted/default gasLimit instead of the successful request’s gasLimit=0. Matching the quote parameters isolated the intended policy gate. The original assertion output did not record the SDK error code, so no more specific cause is claimed. The targeted retry passed with exact error-type/decoded-gate and state invariants. This is selected-run coverage, not a claimed single six-pass invocation. [Logs](logs/), [public evidence](live-evidence.json). + +One intermediate full unit run hit the existing wall-clock timeout assertion (5,101ms against a 1,500ms limit). Its focused recheck and the final full run passed; no code in that timeout path was changed. Both logs are retained. + +The actual-contract harness proves data-limit, PC-cap and expiry refusals using the real AGW/engine/URP. Its gateway/core/token are fixtures and do not prove relay/destination execution. Live SOL transfer checks independently prove the real destination result. Internal wire refusal E2Es were updated to assert mapped simulation errors; the historical three-case wire group was not rerun funded during this follow-up. + +The live scenarios used previously authorized bounded Donut/devnet funds. Unit and local-contract runs were unfunded. No mainnet action, deployment, publication or team message was sent. Environment secrets are absent from the evidence. + +## Reproduction + +```sh +node node_modules/jest/bin/jest.js --config packages/core/jest.config.ts --runInBand +AGW_LOCAL_DIR=/path/to/isolated-v4-build node node_modules/jest/bin/jest.js --config packages/core/jest.agw-local.config.ts --runInBand +node node_modules/ts-node/dist/bin.js --transpile-only packages/core/__e2e__/ci/run.ts --verify --group agw +``` + +Use the established verified manifest and preflight before a funded E2E rerun; the `agw` group remains opt-in. The SDK consumer guide contains the public SOL/SPL transfer examples and supported-layout limits. diff --git a/plan/agw/research/sdk-alignment-fixes-2026-10-07/live-evidence.json b/plan/agw/research/sdk-alignment-fixes-2026-10-07/live-evidence.json new file mode 100644 index 00000000..6dc255d2 --- /dev/null +++ b/plan/agw/research/sdk-alignment-fixes-2026-10-07/live-evidence.json @@ -0,0 +1,38 @@ +[ + { + "name": "public-svm-owner-transfer-submitted", + "at": "2026-10-07T11:06:05.551Z", + "network": "TESTNET_DONUT", + "sourceCommit": "e8db74815cfbbf5389593805e464fe8d85f7f735", + "wallet": "0x5cB3010690333eeb45e58E15642Ba9B729A8d5dF", + "hash": "0xa0075b4de284986f8fbd52fd971caccd36472e8753a81c5427485aa34a69e8a4" + }, + { + "name": "public-svm-owner-transfer-delivered", + "at": "2026-10-07T11:07:17.900Z", + "network": "TESTNET_DONUT", + "sourceCommit": "e8db74815cfbbf5389593805e464fe8d85f7f735", + "wallet": "0x5cB3010690333eeb45e58E15642Ba9B729A8d5dF", + "hash": "0xa0075b4de284986f8fbd52fd971caccd36472e8753a81c5427485aa34a69e8a4", + "destinationHash": "5ZbGd54mA92QzFGvFzBQsMQSW6CTxXamygfjcXUmojUgeLf37oD2G4DX8xxrGdr8zjdYnUFA81YSeV41v6h7Tvwm", + "recipient": "3nK8X1re4zLNrgz9Y3xKS4g2fKPJ6M3N9BhNuFfkjwAb", + "amount": "10000" + }, + { + "name": "public-svm-contract-refusals", + "at": "2026-10-07T11:15:29.566Z", + "network": "TESTNET_DONUT", + "sourceCommit": "e8db74815cfbbf5389593805e464fe8d85f7f735", + "wallet": "0x698f72F39B62C3eb7132B2fC09fe4F075231f48f", + "id": "0x3cd5a73a0e021dd2e63e004169565050e92400e8ccf0e7f78c5e98fc9b9d8e82", + "agentNonce": 0, + "state": { + "tokens": "20000", + "pcBalance": "41000000000000000000", + "checkpoints": "2", + "spent": [ + "0" + ] + } + } +] diff --git a/plan/agw/research/sdk-alignment-fixes-2026-10-07/logs/build.log b/plan/agw/research/sdk-alignment-fixes-2026-10-07/logs/build.log new file mode 100644 index 00000000..25bafda6 --- /dev/null +++ b/plan/agw/research/sdk-alignment-fixes-2026-10-07/logs/build.log @@ -0,0 +1,11 @@ + +> nx run core:build + +Compiling TypeScript files for project "core"... +Done compiling TypeScript files for project "core". +(node:54370) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. +(Use `node --trace-warnings ...` to show where the warning was created) + + + + NX Successfully ran target build for project core diff --git a/plan/agw/research/sdk-alignment-fixes-2026-10-07/logs/lint.log b/plan/agw/research/sdk-alignment-fixes-2026-10-07/logs/lint.log new file mode 100644 index 00000000..34b187df --- /dev/null +++ b/plan/agw/research/sdk-alignment-fixes-2026-10-07/logs/lint.log @@ -0,0 +1,43 @@ + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__agw-local__/svm-public.spec.ts + 78:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 117:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 159:13 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 160:11 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 161:13 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 184:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 213:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 247:13 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 248:11 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 249:13 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 277:13 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 278:11 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 279:13 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 302:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 395:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 448:16 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 462:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 474:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 504:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/agw-svm-wire/outbound.spec.ts + 114:38 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 126:56 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 127:48 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 127:48 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 128:28 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 129:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 129:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 133:30 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 146:23 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 170:50 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 170:50 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/agw/svm-public.spec.ts + 138:21 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 139:25 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 224:7 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 297:7 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 297:7 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +✖ 35 problems (0 errors, 35 warnings) diff --git a/plan/agw/research/sdk-alignment-fixes-2026-10-07/logs/live-contract-refusals-final.log b/plan/agw/research/sdk-alignment-fixes-2026-10-07/logs/live-contract-refusals-final.log new file mode 100644 index 00000000..9b178165 --- /dev/null +++ b/plan/agw/research/sdk-alignment-fixes-2026-10-07/logs/live-contract-refusals-final.log @@ -0,0 +1,15 @@ +PASS core-e2e __e2e__/agw/svm-public.spec.ts (120.743 s) + agw public svm + ✓ 3. contract simulation maps account and data refusals without state changes (22204 ms) + ○ skipped 1. named IDL grant reads exact constraints and replaces atomically + ○ skipped 2. public send confirms actual CEA transfer and preserves replay identity + ○ skipped 4. public revoke removes the Solana rule and subsequent sends are refused + ○ skipped 5. owner funds-only transfer reaches the recipient and replays with the same amount + ○ skipped 6. agents still require an instruction and owner allowance failures do not sign + +Test Suites: 1 passed, 1 total +Tests: 5 skipped, 1 passed, 6 total +Snapshots: 0 total +Time: 120.764 s +Ran all test suites within paths "__e2e__/agw/svm-public.spec.ts". +Force exiting Jest: Have you considered using `--detectOpenHandles` to detect async operations that kept running after all tests finished? diff --git a/plan/agw/research/sdk-alignment-fixes-2026-10-07/logs/live-error-types-recheck.log b/plan/agw/research/sdk-alignment-fixes-2026-10-07/logs/live-error-types-recheck.log new file mode 100644 index 00000000..6521f568 --- /dev/null +++ b/plan/agw/research/sdk-alignment-fixes-2026-10-07/logs/live-error-types-recheck.log @@ -0,0 +1,15 @@ +PASS core-e2e __e2e__/agw/svm-public.spec.ts (117.578 s) + agw public svm + ✓ 3. contract simulation maps account and data refusals without state changes (33789 ms) + ○ skipped 1. named IDL grant reads exact constraints and replaces atomically + ○ skipped 2. public send confirms actual CEA transfer and preserves replay identity + ○ skipped 4. public revoke removes the Solana rule and subsequent sends are refused + ○ skipped 5. owner funds-only transfer reaches the recipient and replays with the same amount + ○ skipped 6. agents still require an instruction and owner allowance failures do not sign + +Test Suites: 1 passed, 1 total +Tests: 5 skipped, 1 passed, 6 total +Snapshots: 0 total +Time: 117.603 s, estimated 366 s +Ran all test suites within paths "__e2e__/agw/svm-public.spec.ts". +Force exiting Jest: Have you considered using `--detectOpenHandles` to detect async operations that kept running after all tests finished? diff --git a/plan/agw/research/sdk-alignment-fixes-2026-10-07/logs/live-initial.log b/plan/agw/research/sdk-alignment-fixes-2026-10-07/logs/live-initial.log new file mode 100644 index 00000000..63c493c6 --- /dev/null +++ b/plan/agw/research/sdk-alignment-fixes-2026-10-07/logs/live-initial.log @@ -0,0 +1,41 @@ +FAIL core-e2e __e2e__/agw/svm-public.spec.ts (365.387 s) + agw public svm + ✓ 1. named IDL grant reads exact constraints and replaces atomically (94872 ms) + ✓ 2. public send confirms actual CEA transfer and preserves replay identity (85612 ms) + ✕ 3. contract simulation maps account and data refusals without state changes (8726 ms) + ✓ 4. public revoke removes the Solana rule and subsequent sends are refused (9615 ms) + ✓ 5. owner funds-only transfer reaches the recipient and replays with the same amount (87056 ms) + ✓ 6. agents still require an instruction and owner allowance failures do not sign (14818 ms) + + ● agw public svm › 3. contract simulation maps account and data refusals without state changes + + expect(received).rejects.toMatchObject(expected) + + - Expected - 4 + + Received + 1 + + Object { + - "decodedError": Object { + - "name": "PolicyCheckReverted(SvmAccountPinMismatch)", + - }, + - "name": "AgenticRevertError", + + "name": "AgenticError", + } + + 266 | to: { chain: SVM_WIRE_CHAIN, address: SVM_WIRE_PROGRAM }, + 267 | data: data(BigInt(1), wrong), + > 268 | }) + | ^ + 269 | ).rejects.toMatchObject({ + 270 | name: 'AgenticRevertError', + 271 | decodedError: { name: 'PolicyCheckReverted(SvmAccountPinMismatch)' }, + + at Object.toMatchObject (../../node_modules/expect/build/index.js:218:22) + at Object. (__e2e__/agw/svm-public.spec.ts:268:15) + +Test Suites: 1 failed, 1 total +Tests: 1 failed, 5 passed, 6 total +Snapshots: 0 total +Time: 365.408 s +Ran all test suites within paths "__e2e__/agw/svm-public.spec.ts". +Force exiting Jest: Have you considered using `--detectOpenHandles` to detect async operations that kept running after all tests finished? diff --git a/plan/agw/research/sdk-alignment-fixes-2026-10-07/logs/local-contracts.log b/plan/agw/research/sdk-alignment-fixes-2026-10-07/logs/local-contracts.log new file mode 100644 index 00000000..635e8dd4 --- /dev/null +++ b/plan/agw/research/sdk-alignment-fixes-2026-10-07/logs/local-contracts.log @@ -0,0 +1,29 @@ +PASS core-agw-local packages/core/__agw-local__/svm-public.spec.ts (8.425 s) +PASS core-agw-local packages/core/__agw-local__/svm-backend.spec.ts (8.839 s) +PASS core-agw-local packages/core/__agw-local__/v4-multiasset.spec.ts +PASS core-agw-local packages/core/__agw-local__/agw-local-advanced.spec.ts (5.947 s) +PASS core-agw-local packages/core/__agw-local__/svm-differential.spec.ts + ● Console + + console.log + {"corpus":"svm-grant","seed":23063,"cases":107,"accepted":38,"rejected":69,"mismatches":[]} + + at Object. (__agw-local__/svm-differential.spec.ts:226:13) + + console.log + {"corpus":"svm-payload","seed":23063,"cases":88,"accepted":6,"rejected":82,"mismatches":[]} + + at Object. (__agw-local__/svm-differential.spec.ts:407:13) + +PASS core-agw-local packages/core/__agw-local__/agw-local-races.spec.ts +PASS core-agw-local packages/core/__agw-local__/delayed-index.spec.ts +PASS core-agw-local packages/core/__agw-local__/svm-internals.spec.ts +PASS core-agw-local packages/core/__agw-local__/agw-local-batch.spec.ts +PASS core-agw-local packages/core/__agw-local__/agw-local.spec.ts +PASS core-agw-local packages/core/__agw-local__/vectors.spec.ts + +Test Suites: 11 passed, 11 total +Tests: 85 passed, 85 total +Snapshots: 0 total +Time: 40.453 s +Ran all test suites. diff --git a/plan/agw/research/sdk-alignment-fixes-2026-10-07/logs/unit-timeout-recheck.log b/plan/agw/research/sdk-alignment-fixes-2026-10-07/logs/unit-timeout-recheck.log new file mode 100644 index 00000000..cf80019e --- /dev/null +++ b/plan/agw/research/sdk-alignment-fixes-2026-10-07/logs/unit-timeout-recheck.log @@ -0,0 +1,10 @@ +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-timeout-clamp.spec.ts + waitForOutboundTx initial-wait clamp + ✓ throws OutboundTimeoutError within the clamped budget (100ms) (102 ms) + ✓ throws with elapsedMs matching the override (not the default) (201 ms) + +Test Suites: 1 passed, 1 total +Tests: 2 passed, 2 total +Snapshots: 0 total +Time: 2.606 s, estimated 6 s +Ran all test suites within paths "packages/core/src/lib/orchestrator/__tests__/outbound-timeout-clamp.spec.ts". diff --git a/plan/agw/research/sdk-alignment-fixes-2026-10-07/logs/unit-timing-assertion-initial.log b/plan/agw/research/sdk-alignment-fixes-2026-10-07/logs/unit-timing-assertion-initial.log new file mode 100644 index 00000000..4e5dfd65 --- /dev/null +++ b/plan/agw/research/sdk-alignment-fixes-2026-10-07/logs/unit-timing-assertion-initial.log @@ -0,0 +1,209 @@ +PASS core packages/core/src/lib/universal/account/account.spec.ts + ● Console + + console.warn + [PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead. + + 207 | ): Promise { + 208 | if (!_convertOriginToExecutorWarned) { + > 209 | console.warn( + | ^ + 210 | '[PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead.' + 211 | ); + 212 | _convertOriginToExecutorWarned = true; + + at Object.convertOriginToExecutor (src/lib/universal/account/account.ts:209:13) + at Object. (src/lib/universal/account/account.spec.ts:80:52) + + console.warn + [PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead. + + 425 | ): Promise { + 426 | if (!options?._internal && !_convertExecutorToOriginWarned) { + > 427 | console.warn( + | ^ + 428 | '[PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead.' + 429 | ); + 430 | _convertExecutorToOriginWarned = true; + + at convertExecutorToOrigin (src/lib/universal/account/account.ts:427:13) + at Object. (src/lib/universal/account/account.spec.ts:106:38) + +PASS core packages/core/src/lib/read-state/__tests__/block-results-client.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-tx-retry.spec.ts +PASS core packages/core/src/lib/push-client/push-client.archive-fallback.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-confirmation-gate.spec.ts +PASS core packages/core/src/lib/utils.spec.ts + ● Console + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:973:17) + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:977:17) + + console.log + 1.23 + + at Object. (src/lib/utils.spec.ts:982:17) + +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/export.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/source-hash-resolution.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-tracker.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/send.spec.ts +FAIL core packages/core/src/lib/orchestrator/__tests__/outbound-timeout-clamp.spec.ts (5.455 s) + ● waitForOutboundTx initial-wait clamp › throws OutboundTimeoutError within the clamped budget (100ms) + + expect(received).toBeLessThan(expected) + + Expected: < 1500 + Received: 5101 + + 51 | // Allow generous slack for jest scheduler jitter — the point is that + 52 | // elapsed should be FAR less than the default 20s initial wait. + > 53 | expect(elapsed).toBeLessThan(1_500); + | ^ + 54 | }); + 55 | + 56 | it('throws with elapsedMs matching the override (not the default)', async () => { + + at Object. (src/lib/orchestrator/__tests__/outbound-timeout-clamp.spec.ts:53:21) + +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-composition.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r2-outbound-revert-flow.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-builder-progress-hook.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/signing-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/response-builder-push-revert.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/svm-rent.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-request-recipient.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/inbound-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-multichain.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-executor.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/funds-only-burn-guard.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/rescue-svm-confirmation.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/management.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/web2-compat.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/inbound-tracker-derivation.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/reads-context.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-svm-confirmation.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/response-surface.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/payload-builders.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-detector.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/cascade.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gateway-uea-account.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/track-transaction-guard.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-evm-r3-native-eoa.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/context-helpers-tracker.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/scenarios.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.chain-symbol.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/chain-namespace.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-native-multicall.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/terminal-suppression.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-emission.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-svm-rent.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-svm-r3.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/gate.spec.ts +PASS core packages/core/src/lib/push-client/push-client.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/send-transaction-progress-hook.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-usd-sizer.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/account-status.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-calculator.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm-rent-pc20.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/execute-standard-required-funds.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/build-payload.spec.ts +PASS core packages/core/src/lib/universal/signer/signer.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/response-invariant.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/__tests__/signing.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-quote.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.dynamic-gas.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/child-inbounds.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-idl.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/read-tx-spec-strings.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/public-surface.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-event-hook-bridge.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/spec-builder.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r1-spec-strings.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/multichain-hooks.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/resolve.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r2-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/resolver.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-error-classification.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-backend.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/registry.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r3-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg-svm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/svm-account.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-params.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/revalidate-read.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-wire-fixture.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-evm.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm-log-index.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/result-decoder.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/address-codec.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-events.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-svm.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/normalize.spec.ts +PASS core packages/core/src/lib/constants/__tests__/token-constants.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/abi-selectors.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/codec.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/auto-detect.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-web2.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/ucallback-codec.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/validate.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-types.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.batch-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/registry.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/ix-encoder.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/max-pc-for-gas.spec.ts +PASS core packages/core/src/lib/constants/__tests__/svm-gateway-idl.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/error-decoder.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/normalize-address.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/tracking.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/classify.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-execute-order.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/budget.spec.ts +PASS core packages/core/src/lib/formatters.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/errors.spec.ts + +Summary of all failing tests +FAIL src/lib/orchestrator/__tests__/outbound-timeout-clamp.spec.ts (5.455 s) + ● waitForOutboundTx initial-wait clamp › throws OutboundTimeoutError within the clamped budget (100ms) + + expect(received).toBeLessThan(expected) + + Expected: < 1500 + Received: 5101 + + 51 | // Allow generous slack for jest scheduler jitter — the point is that + 52 | // elapsed should be FAR less than the default 20s initial wait. + > 53 | expect(elapsed).toBeLessThan(1_500); + | ^ + 54 | }); + 55 | + 56 | it('throws with elapsedMs matching the override (not the default)', async () => { + + at Object. (src/lib/orchestrator/__tests__/outbound-timeout-clamp.spec.ts:53:21) + + +Test Suites: 1 failed, 1 skipped, 118 passed, 119 of 120 total +Tests: 1 failed, 12 skipped, 2002 passed, 2015 total +Snapshots: 0 total +Time: 44.161 s +Ran all test suites. diff --git a/plan/agw/research/sdk-alignment-fixes-2026-10-07/logs/units.log b/plan/agw/research/sdk-alignment-fixes-2026-10-07/logs/units.log new file mode 100644 index 00000000..86e64c8d --- /dev/null +++ b/plan/agw/research/sdk-alignment-fixes-2026-10-07/logs/units.log @@ -0,0 +1,172 @@ +PASS core packages/core/src/lib/universal/account/account.spec.ts (7.392 s) + ● Console + + console.warn + [PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead. + + 207 | ): Promise { + 208 | if (!_convertOriginToExecutorWarned) { + > 209 | console.warn( + | ^ + 210 | '[PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead.' + 211 | ); + 212 | _convertOriginToExecutorWarned = true; + + at Object.convertOriginToExecutor (src/lib/universal/account/account.ts:209:13) + at Object. (src/lib/universal/account/account.spec.ts:80:52) + + console.warn + [PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead. + + 425 | ): Promise { + 426 | if (!options?._internal && !_convertExecutorToOriginWarned) { + > 427 | console.warn( + | ^ + 428 | '[PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead.' + 429 | ); + 430 | _convertExecutorToOriginWarned = true; + + at convertExecutorToOrigin (src/lib/universal/account/account.ts:427:13) + at Object. (src/lib/universal/account/account.spec.ts:106:38) + +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-timeout-clamp.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/block-results-client.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-tx-retry.spec.ts +PASS core packages/core/src/lib/push-client/push-client.archive-fallback.spec.ts +PASS core packages/core/src/lib/utils.spec.ts + ● Console + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:973:17) + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:977:17) + + console.log + 1.23 + + at Object. (src/lib/utils.spec.ts:982:17) + +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-emission.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-confirmation-gate.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/response-surface.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r2-outbound-revert-flow.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-svm-r3.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/source-hash-resolution.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/public-surface.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/send.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/svm-rent.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-builder-progress-hook.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/terminal-suppression.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/resolve.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/signing-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/inbound-tracker-derivation.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-backend.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/response-builder-push-revert.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-multichain.spec.ts +PASS core packages/core/src/lib/push-client/push-client.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/response-invariant.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm-rent-pc20.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/registry.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/management.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-evm-r3-native-eoa.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-svm-confirmation.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-svm-rent.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-composition.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gateway-uea-account.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-native-multicall.spec.ts +PASS core packages/core/src/lib/universal/signer/signer.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/chain-namespace.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/payload-builders.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-event-hook-bridge.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-calculator.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/web2-compat.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-tracker.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/scenarios.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/track-transaction-guard.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r1-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/resolver.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r2-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-error-classification.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-executor.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/context-helpers-tracker.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/execute-standard-required-funds.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-idl.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/read-tx-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-detector.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/gate.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/send-transaction-progress-hook.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/export.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/multichain-hooks.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/build-payload.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/cascade.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-request-recipient.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-usd-sizer.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/rescue-svm-confirmation.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/account-status.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/funds-only-burn-guard.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-events.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/inbound-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/__tests__/signing.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r3-spec-strings.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-wire-fixture.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/address-codec.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/spec-builder.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-evm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/svm-account.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.chain-symbol.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm-log-index.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/auto-detect.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/result-decoder.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-params.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/reads-context.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/revalidate-read.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-svm.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/child-inbounds.spec.ts +PASS core packages/core/src/lib/constants/__tests__/token-constants.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-quote.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/codec.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/normalize.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/abi-selectors.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-web2.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/ucallback-codec.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/validate.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg-svm.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/registry.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/ix-encoder.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.dynamic-gas.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.batch-gas.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-types.spec.ts +PASS core packages/core/src/lib/constants/__tests__/svm-gateway-idl.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/normalize-address.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/max-pc-for-gas.spec.ts +PASS core packages/core/src/lib/formatters.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/classify.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/tracking.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-execute-order.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/error-decoder.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/budget.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/errors.spec.ts + +Test Suites: 1 skipped, 119 passed, 119 of 120 total +Tests: 12 skipped, 2003 passed, 2015 total +Snapshots: 0 total +Time: 29.984 s, estimated 36 s +Ran all test suites. diff --git a/plan/agw/research/source-refresh-2026-10-07/README.md b/plan/agw/research/source-refresh-2026-10-07/README.md new file mode 100644 index 00000000..4d233be7 --- /dev/null +++ b/plan/agw/research/source-refresh-2026-10-07/README.md @@ -0,0 +1,90 @@ +# AGW source refresh and SDK alignment — October 7, 2026 + +Reviewed SDK `898eda17` against fresh Notion exports, fetched AGW/core/gateway refs, and read-only deployment probes. No runtime files were changed and no transactions were broadcast during this review. + +**Review baseline/result:** no new AGW contract/deployment drift. `setLabel` remains the only pending standalone AGW contract-delivery item. At that reviewed commit, two SDK-owned alignment follow-ups were found: policy-preflight/error consistency and Solana owner funds-only parity. Several Notion sections also lag the agreed decisions. + +**Subsequent disposition:** G27/G28 have been fixed and validated. [SDK fix report](../sdk-alignment-fixes-2026-10-07/README.md). The findings and reproduction below preserve the pre-fix evidence; they do not describe current production send paths. + +## Freshness and evidence + +| Source | Fresh result | +| --- | --- | +| All 12 registered Notion bodies | Exported and imported at 2026-10-07 10:27:18 UTC (15:57 IST); 1 changed, 11 unchanged; no missing/unknown pages | +| SDK page 5 | Only body change: removal of `ref: jobRef` from the create example | +| Primary Notion discussions | Pages 1 and 5, including resolved threads, inspected through All discussions | +| AGW | `deploy-agw@10a24f1`, source `pushAgenticWallet_v3@e8db748`; unchanged | +| Core marketplace | `universalMarketplace_v1@9479aef`; only three documentation files added since prior pin `cb69e0b`; code unchanged | +| Gateway | `pc20-3rd-iteration@bcbf7df`; unchanged. All remote refs were fetched; the alternative SVM audit branch is not assumed to replace the configured deployment | +| Donut | Chain 42101, block 23989371: code hashes, proxy slots, version, pause state and wiring match the prior probe | +| Solana devnet | Slot 508426857: gateway and test-counter ProgramData fingerprints match October 6; gateway remains unpaused | + +[Notion comparison and hashes](../../notion/history/20261007T102718466408Z/refresh.json), [page-5 body diff](../../notion/history/20261007T102718466408Z/5-sdk-agw.diff), [raw exports](../../notion/exports/20261007T102718466408Z/), [contract refs/diffs](contract-refresh.json), [Donut probe](donut-probe.json), [Solana probe](solana-probe.json). + +The new core docs clarify the already-reviewed per-token caps, job/rule expiry equality and marketplace rejection of approval selectors. They do not change standalone AGW contract behavior. Current copies are retained under [contracts/](contracts/). + +## SDK findings at reviewed commit 898eda17 + +### G27 — Policy preflight and error shape differ from the spec (SDK-owned, P1) + +The refreshed SDK spec §2.a says URP is the rule checker and rule failures surface as `AgenticRevertError` with `decodedError`. The user’s latest clarification also puts rule enforcement at the contract, with SDK error mapping. + +The public Solana route evaluates stored policy constraints locally before entering its send/error-mapping block: + +- `execution/svm-public.ts:95` awaits `prepareSvmAgentExecution`; its `wrapSendError` catch is later, around the actual execution (`222`). +- `execution/svm-outbound.ts:26–50` evaluates expiry, asset amounts, cumulative spend and PC limits. Refusals are `AgenticError` / `RULE_LIMIT_EXCEEDED`, with a string in `details.contractError`. +- `execution/svm-payload.ts:22–25, 102–135` evaluates allowed programs and account/data pins. Refusals are `AgenticError` / `INVALID_RULE`, without `decodedError`. +- The EVM route also performs a local `maxGasPerCall` check in `execution/send.ts`; align the distinction consistently across both VMs. + +Reproduced expiry and wrong-account refusals: neither is an `AgenticRevertError`, and `decodedError` is absent. This concerns validation placement and the public error contract; authorization is still enforced by URP. Existing passing refusal E2Es do not establish error-type parity because some assert only the message. + +**Recommended SDK action:** retain structural/context/funding validation, but obtain policy rejections from the contract/simulation and pass them through the existing mapper. Do not fabricate an on-chain revert for a purely local decision. Add public-path tests for error class, decoded gate and no state change. If retaining local policy checks deliberately, their distinct behavior needs an explicit documented public contract rather than a claim of spec parity. + +### G28 — Solana owner funds-only sends are unavailable (SDK-owned scope gap, P2) + +The spec §1.d promises the owner ordinary wallet send tooling. The contract owner door checks no policy (`docs/5_SDK_Owner_Integration.md:307–323`). Gateway classification already supports amount > 0 with an empty payload as FUNDS. + +`execution/svm-public.ts:54–61` rejects absent instruction data for both owner and agent doors. A public owner-route reproduction with funds and no instruction returns `INVALID_RULE` before execution. The ordinary core SVM payload builder accepts the corresponding no-execution shape. Our consumer guide already discloses this restriction, so it is an existing scope limitation rather than a newly broken deployment. + +**Recommended SDK action:** support funds-only sends on the owner door using the normal gateway route, with balance/allowance checks and receipt/replay coverage. Preserve the agent rulebook’s instruction requirement. No contract change is needed for the owner route. + +[Read-only source reproductions](reproduce-sdk-findings.cjs), [results](sdk-findings.json). These isolate SDK branches with local inputs; they are not additional live delivery tests. Run against an isolated SDK checkout at `898eda17` using AGW_REVIEW_SDK_ROOT; the public path has since changed: + +```sh +AGW_REVIEW_SDK_ROOT=/path/to/isolated-sdk-at-898eda17 TS_NODE_PROJECT=packages/core/tsconfig.lib.json node -r ts-node/register/transpile-only plan/agw/research/source-refresh-2026-10-07/reproduce-sdk-findings.cjs +``` + +## Notion text needing reconciliation + +The new “omitting ref” comment and example edit agree with our removal. However, page 5 still contains: + +| Stale text | Current agreed/implemented position | +| --- | --- | +| `ref` in NativeRule, UniversalRule, RulesRecord and prose | Rule ref removed; checkpoint ref retained | +| One rule per agent/chain and `DUPLICATE_RULE` | Multiple grants allowed; SDK retains AMBIGUOUS_RULE when lookup finds several candidates | +| Public `spent` and `compileCard` | Excluded from standalone v1 by Harsh’s earlier replies | +| Public generation-dependent helpers | Kept internal under the earlier approved scope | +| Push EOAs cannot batch / require a new factory method | Existing sender-preserving 7702 batching is implemented and tested | +| Solana rulebook “once it ships,” without final public IDL types | v4 rulebook deployed; public supported-IDL integration implemented | +| No validator at all | Sender-bound AgentValidator remains as the SmartSession adapter; no engine fork | + +Page 1 still describes the previously corrected six-field gateway migration direction. Fresh sources and live slots support the currently integrated eight-field request. Its proposed grant refs also lag the removal decision. These are documentation corrections, not reasons to revert the SDK to historical behavior. + +The contract owner guide’s `beneficiaryOffset = 4 + 32 * argIndex` is valid for the simple scalar ABI example, but is not a general formula for arbitrary static arrays/tuples. Keep the SDK’s ABI-layout calculation and exact offset reads. + +## Visible discussion review + +- Page 5: new Harsh comment “omitting ref,” shown as 2h old, attached to the create-example thread. The earlier multiple-rules, token-independence and deleted-content limit discussions remain visible. No newer substantive answer changes the user-relayed decisions. +- Page 1: latest visible substantive label comment remains October 1: owner-only setLabel / LabelSet, not a checkpoint. No delivery announcement/ABI appears in the thread. +- Overview and pages 2/3/4/6/7/8: loaded header showed no Comments button. This is a visibility observation, not proof that no hidden/resolved discussions exist. +- Historical SDK: September 18 WIP comment; no current-scope change. +- Historical address book: no Comments button; body still describes an older deployment and is kept historical. +- Historical wallet flow: September 7 tooling question, no new reply. + +Native exports exclude comments; these observations are separate evidence and no comment was posted or edited. + +## Remaining external work and limits + +`setLabel` still needs Zaryab’s implemented ABI/deployment. Automatic-selection delivery is **not** requested; existing contract enforcement and SDK ambiguity handling remain the clarified design. `creditRevert` remains a separate platform executor dependency, with ordinary refunds not restoring spent. + +Supported public IDL layouts remain a documented subset (fixed Anchor fields, flat non-optional accounts, eight-byte discriminators; one instruction per SVM send). This refresh did not expand that scope or rerun funded suites. It is an alignment review, not a full security audit. diff --git a/plan/agw/research/source-refresh-2026-10-07/contract-refresh.json b/plan/agw/research/source-refresh-2026-10-07/contract-refresh.json new file mode 100644 index 00000000..b957509d --- /dev/null +++ b/plan/agw/research/source-refresh-2026-10-07/contract-refresh.json @@ -0,0 +1,82 @@ +{ + "fetched_at": "2026-10-07T10:26:01.543177+00:00", + "sdk_commit": "898eda17911133faa155899ac8e1276a589c4564", + "repositories": [ + { + "repository": "push-agentic-wallets", + "ref": "origin/deploy-agw", + "commit": "10a24f101e2e6e0a9b76517b29f5cdb1aa967796", + "previous_pin": "10a24f101e2e6e0a9b76517b29f5cdb1aa967796", + "diff_stat": "", + "source_changed": false, + "remote_refs": [ + "origin 9ddd95402b9a2dbf494f6ebfdb477e9a0fb1408a", + "origin/demo-v1 94e0ad21f5dcf353bc792b3fbf5ae31f63949483", + "origin/demo-v1-backup b3f53297bb38176b72611e0b58487f20a68f6912", + "origin/deploy-agw 10a24f101e2e6e0a9b76517b29f5cdb1aa967796", + "origin/main 9ddd95402b9a2dbf494f6ebfdb477e9a0fb1408a", + "origin/pushAgenticWallet_v1 7dc20e4f3087810be107294350c97e723cb64e8d", + "origin/pushAgenticWallet_v2 83d568cc484b28f86113a5dd954d06a7ac540232", + "origin/pushAgenticWallet_v3 e8db74815cfbbf5389593805e464fe8d85f7f735", + "origin/urp-fixes eb5961721017475042d5199687cb46f4733fe3a8" + ] + }, + { + "repository": "push-chain-core-contracts", + "ref": "origin/universalMarketplace_v1", + "commit": "9479aeff5291bb06fa306f7efa98be9c45324cb0", + "previous_pin": "cb69e0ba101bef1bb4440e54b2c45396be3e92ce", + "diff_stat": " docs/universalmarketplace/README.md | 645 +++++++++++++++++++++++++++++++++\n docs/universalmarketplace/criteria.md | 324 +++++++++++++++++\n docs/universalmarketplace/reference.md | 426 ++++++++++++++++++++++\n 3 files changed, 1395 insertions(+)\n", + "source_changed": false, + "remote_refs": [ + "origin/8183-v1 01439d1eea61b03d9bf478cc238fce3423081b46", + "origin b2f22241681c6587a1c130e638949856dfcbd33f", + "origin/audit-main 15b70544feba1586f488a90e38650bf33ea3c634", + "origin/audit-main-e2e 72052a449588e6be387e0bfa60395ecc1cebba6c", + "origin/audit-main-fixes 281acf7c28f824926e6a2f9443f3bfd9babcbeb1", + "origin/audit-main-test 0e22d52de7e7e710e099303e35937e393d1bf656", + "origin/core-testnet 2edec979eefd0dee1baad1571e1f5457a9d05190", + "origin/deployment-v2 bf5de2ba88002fd9ce7ac56c1e21974a80907825", + "origin/e2e-push-node 49bbd35c9eb9bd602f6d9eff57ee2056327981ec", + "origin/feat-cea-as-origin 7d1144a45632d68fc8c295276df9e365eea640ed", + "origin/feat-read-state b5f5fbfd62d914d2a42b082f6043c75dd2ad3587", + "origin/main b2f22241681c6587a1c130e638949856dfcbd33f", + "origin/node-e2e 71e88ab335a4fc24586806049f287ac6e62ddfd1", + "origin/pc20-3rd-iteration c4f9c51f463a74ba84ad4a28dc467bf100486b0c", + "origin/read-state-fixes-v1 833ae81702e7a8933b71b770c5e837445023136d", + "origin/temp/e2e-test 205970d6cf13b32b777c9f2f486083e3108015c7", + "origin/temp/outbound-local-creation 80104f4f4ace8643467feedd02c939cba81d553c", + "origin/universalMarketplace_v1 9479aeff5291bb06fa306f7efa98be9c45324cb0" + ] + }, + { + "repository": "push-chain-gateway-contracts", + "ref": "origin/pc20-3rd-iteration", + "commit": "bcbf7df42e8e6dd11088a43bcc0b056a54ea0a18", + "previous_pin": "bcbf7df42e8e6dd11088a43bcc0b056a54ea0a18", + "diff_stat": "", + "source_changed": false, + "remote_refs": [ + "origin/121_pc20_feature d68d5ab2078c4cce070f2d0d5976b6f7a8e816ac", + "origin/14-add-multichain-support 1550cd9af457f4cd443256aff386a7e4bcb0659a", + "origin d02070dc11aeb3a081d5d6363aa0d75d63eb7c1c", + "origin/audit-main d40c1b9dccd01dbb6f38d1797bf90580aec554c3", + "origin/audit-main-e2e 483ee4c8a36c0a9f208b34bc55a6385bef7ccf9d", + "origin/audit-main-fixes 6062f9f80445fa1261aa602b891c0a0af26ff7bf", + "origin/deployment-main 8962a8168c05fd2cae7bc028bb9cff3eb004d5d5", + "origin/docs/examples 8dfbfff32daafe7a746c22f1e14df11be0e0dfd2", + "origin/e2e-push-node 47fbab3e608d799a188fdea7987832f8a1fbffdc", + "origin/gateway-testnet b205770f2c65df090eb282fd2f3b4234d30faa1f", + "origin/main d02070dc11aeb3a081d5d6363aa0d75d63eb7c1c", + "origin/optimized-gateway-testnet-pc20 1c1ea609629366fe3a9c4e478e8c921f0ea8405a", + "origin/pc20-3rd-iteration bcbf7df42e8e6dd11088a43bcc0b056a54ea0a18", + "origin/pc20-token-implementation 60fdcd012b997227a6105aa151df493231d8186d", + "origin/pc20Metadata_removal 5655a10a61a2f063ebc4766ac745f844856afe46", + "origin/rate-limit-outbound 9cab39905209915b3c38c4618f71bf001b9fe106", + "origin/svm-hacken-proof-fixes 9f49df8c28a0234054155007f0797486bbb01a11", + "origin/svm-outbound-flow 76bcba1610e1b52484c6cc03c74ec0ff32ed0a0e", + "origin/temp/outbound-local-creation eb78f1a0c9e39d09d829cd9f8c2560da68109377" + ] + } + ] +} diff --git a/plan/agw/research/source-refresh-2026-10-07/contracts/push-agentic-wallets/docs/1_AGW.md b/plan/agw/research/source-refresh-2026-10-07/contracts/push-agentic-wallets/docs/1_AGW.md new file mode 100644 index 00000000..a77beaac --- /dev/null +++ b/plan/agw/research/source-refresh-2026-10-07/contracts/push-agentic-wallets/docs/1_AGW.md @@ -0,0 +1,570 @@ +# AGW (Agentic Wallet) — v3 Architecture + +# 1 · What this is +## The problem +- A user wants to let an automated agent trade or move funds for them, with the user's money — on another blockchain, or on Push Chain itself — without handing over their account. +- The user needs three things at once: +\t- The agent can act **without asking the user each time**. +\t- The agent can never spend **more than the user allowed**, on anything the user did not allow, for longer than the user allowed. +\t- The user can **shut it off instantly**, and take their money out at any time, no matter what state anything else is in. +- All of this runs on Push Chain, which reaches other blockchains through its own cross-chain gateway. Push Chain has no shared "transaction entry point" contract of the kind other chains use for smart accounts — so our wallet must do that job itself. +## The shape of the answer +- The user gets a **dedicated agent wallet** — a small, cheap contract created just for one purpose. It is not the user's main account. It only ever holds the money the user chooses to put at risk. +- The user grants the wallet a **permission**: a fixed bundle of limits binding one agent. A permission is one of **two kinds**, and the user never states which: they name the **chain** the permission is for, and the kind follows from it — Push Chain itself means native, anywhere else means universal. It is fixed at grant and never changes. A **universal** permission bounds cross-chain actions: which token, which destination protocol and functions, how much per action, how much in total, and until when. The far chain may be an EVM chain or Solana; the chain's namespace decides which, and with it the format in which the far-chain action is written and checked. A **native** permission bounds actions on Push Chain itself: which Push contracts and functions, which arguments are pinned to which values, how much native value, how many calls, and until when. +- Every action the agent takes is checked against that permission **by contracts, at execution time**. The agent's honesty is never assumed and never needed. +- The single most important contract in the system is **URP — the Universal Rules Policy**. It carries three rulebooks: two for universal permissions — one for EVM destination chains, one for Solana, because the far-chain action inside the call is written in that chain's own format — and one for native permissions. For a universal permission, every agent action, whatever it claims to be, is one and the same kind of call on Push Chain — the wallet calling the cross-chain gateway — and only URP looks inside that call to check what the agent is *really* doing on the far chain. For a native permission the target and function are already visible to the engine, and URP checks the three things the engine cannot see: the arguments, the value, and the count. `2_UniversalRulesPolicy.md` is devoted to it. +## What we build, and what we adopt +| Piece | Build or adopt | What it is | +| -------------------------------------------- | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Wallet factory** (AGWFactory) | Build | Creates agent wallets at predictable addresses | +| **Agent wallet** (AGW) | Build | The account itself: holds funds, admits only the permission's agent, executes | +| **URP** | **Build — the only genuinely novel contract** | The policy that inspects and limits every agent action — cross-chain through its universal rulebooks (EVM chains, Solana), Push-native through its native rulebook | +| **Session validator** (AgentValidator) | Carry forward — stateless sender validator | Confirms the caller the wallet names is the permission's agent. Verifies no signature | +| **SmartSession** | Adopt, unmodified | An existing open-source permission engine that stores permissions and runs policies | +| **Cross-chain gateway** | Adopt (Push Chain's) | The contract that carries value and instructions to other chains | +| **Destination account** | Adopt (Push Chain's) | The user's account on the far chain, controlled from Push Chain. Universal permissions only | +| **Push-native protocol** | Adopt (whatever the owner names) | Any contract on Push Chain a native permission allows the agent to call — a staking pool, a vault, a token. Nothing is built or trusted; the wallet simply calls it | +## What this system deliberately does not have +Read this list before reading anything else. None of these is an oversight. +- **No editing of a granted permission.** A permission is frozen at grant. Any change means revoking it and granting a new one — in one combined step. +- **No upgrade of a deployed wallet.** A wallet's code is fixed forever at creation. A new wallet version means creating a fresh wallet. +- **No guardian, no recovery contact, and no pause on any wallet.** Nobody but the owner can act on a wallet, and nobody at all can freeze one. *(The **factory** has an operational pause that can stop **new wallets being created**. It cannot touch a wallet that exists, its funds, or its rules sets — see chapter 9, item 22.)* +- **No paymaster and no gas sponsorship.** The agent calls the wallet itself and pays its own gas — an EOA agent from its own balance, a UEA agent through its UEA's gas path. +- **No deny-list.** The permission names what is allowed; everything else is refused. There is no list of specially forbidden functions. *(The fixed targets URP refuses even when allow-listed — the loopbacks of gate 14, and on Solana the programs of gate S15 — are not a deny-list of functions: each is a target that would hand the agent the destination account itself.)* +- **No limit on how far in the future a permission may expire.** The user's choice of expiry is respected as given. +- **No mixed permission.** A permission is universal or native, never both. An owner who wants an agent to do both grants two permissions on the same wallet — they coexist, meter independently, and are revoked independently. +## Glossary +| Term | Meaning | +| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Owner** | The user's own key. Created the wallet, controls it absolutely. | +| **Agent** | An automated service identified by a Push address — its own EOA, or the UEA of an external key. It calls the agent door itself; it never holds the user's funds. | +| **Agent wallet** | The contract this document is about. Holds the budgeted funds on Push Chain. | +| **Permission** | One frozen bundle of limits binding one agent, of one **kind** — universal or native. A wallet can hold several, of either kind. | +| **Universal permission** | A permission whose every action travels through the gateway to a far chain. One token, one destination chain, an allow-list of far-chain calls, one destination account. The far chain is an EVM chain or Solana. | +| **Destination family** | Which kind of far chain a universal permission targets — EVM or Solana. Derived from the chain's namespace (`eip155:` or `solana:`); any other namespace is refused at grant. It decides which universal rulebook runs. | +| **Account pin** | A Solana limit: the account at a fixed position in an instruction's account list must equal a key frozen at grant. The Solana counterpart of the beneficiary check — how a source, a destination or an authority is locked. | +| **Data pin** | A Solana limit on an instruction's data: a little-endian integer at a fixed offset must equal, stay at or above, stay at or below a frozen value, or stand in a minimum ratio to another field. How a fee, a slippage ceiling or a price floor is locked. | +| **Native permission** | A permission whose actions are calls to contracts on Push Chain itself. One to eight (contract, function) pairs, each with its own pins, caps and call limit. Nothing leaves Push Chain. | +| **Action** | One (contract, function) pair the engine recognises as a unit. A universal permission has exactly one — the gateway's send. A native permission has one to eight. | +| **Argument pin** | A native limit: a 32-byte word at a fixed position in a call's data that must equal a value frozen at grant. This is how a beneficiary, a spender or a pool id is locked. | +| **Policy** | A contract that checks one aspect of a request. URP is the main one. | +| **SmartSession** | The adopted engine that stores permissions and calls each policy in turn. | +| **Gateway** | Push Chain's cross-chain transport. The only thing a **universal** action is ever allowed to call — and the one thing a **native** action never may. | +| **Destination account** | The user's account on the far chain. Its address is known in advance: on an EVM chain Push Chain computes it; on Solana it is a program-derived address of the gateway program, derived by tooling. | +| **PC** | Push Chain's native token, used for gas. | +--- +# 2 · The pieces +Six things make up the system. This chapter says what each one is, what it stores, and where it runs. How they interact comes in chapters 3 to 6. +## 2.1 The wallet factory +- A single contract on Push Chain that creates agent wallets. +- Whoever calls it becomes the owner of the wallet it creates. There is no way to create a wallet owned by someone else — the factory does not accept an owner as input; it uses the caller's address, full stop. +- Wallet addresses are **predictable before creation**. The factory uses deterministic deployment (CREATE2): the address is computed from the owner's address plus a per-owner counter. Creating two wallets in a row gives two different, but individually predictable, addresses. +- The factory itself sits behind an upgradeable proxy, so its logic can be improved — **but the address computation must never change**. If it changed, any address a user had computed in advance (and possibly already sent funds to) would become unreachable. A permanent regression test pins this. +- The factory stores: the wallet implementation address, and each owner's wallet counter. +## 2.2 The agent wallet +- A **minimal clone**: a tiny contract that delegates all logic to one fixed implementation. Cheap to create, and **not upgradeable — ever**. The owner's address is baked into the clone's own bytecode at creation and can never be reassigned. +- It is a modular smart account following an existing standard (ERC-7579), reduced to the minimum: it supports exactly **one kind of module — a validator** (a contract that checks signatures and permissions). Attempts to install any other module kind (executors, hooks, fallbacks) are refused by the wallet itself. +- It has two doors: +\t- **The owner door.** The owner can make the wallet do anything, send anything anywhere, with no checks at all. This is deliberate and is covered in chapter 3. +\t- **The agent door** — a function called `executeAsAgent`. Only the permission's agent may call it, and the call only passes if every check in chapters 5 and 6 passes. +- What the wallet stores: a grant counter used to make every permission unique (chapter 4), replay counters used only by the owner's own relayable signed-intent door, and a checkpoint counter that every owner-side change advances (chapter 4.5). The agent door keeps no state of its own. +- What it holds: the budgeted funds — the tokens the owner has decided to put under agent management, plus a little PC for gas on cross-chain calls. +## 2.3 The permission +- A permission is **not a single record in one place**. It is written across three storage locations in one grant transaction: +\t- **SmartSession's storage** holds: that the permission exists, which agent may act under it — the agent's Push address — and the list of policy contracts to run. +\t- **URP's storage** holds everything about what the agent may actually do, in one of three shapes chosen by the permission's kind and, for a universal permission, its destination family. For a universal permission to an EVM chain: the allowed protocol functions on the far chain, the token, the caps, the counters, and the destination account address. For a universal permission to Solana: the same token, caps and counters, the destination account and the gateway program, the allowed (program, instruction) rules with their account and data pins, and the list of destination-side accounts that hold value. For a native permission, one record **per action**: the Push contract and function, the argument pins, the value and amount caps, the call limit, and the counters. `2_UniversalRulesPolicy.md` lists every field of all three. +\t- **URP also records the kind itself**, in a small mode record written in the same transaction — and, for a universal permission, the destination family beside it. On every later request URP consults that record — not the shape of the data — to choose which rulebook runs. +\t- *(There is no separate time-window policy in v3: the expiry lives inside URP, so URP is the sole action policy — see `2_UniversalRulesPolicy.md` §1.1.)* +- A permission is identified by a unique id computed from its contents plus a salt the wallet supplies from its own grant counter. Granting the same terms twice therefore produces two distinct permissions — they never collide, and revoking one never touches the other. +- A permission is **immutable**. Nothing in the system can modify one after grant. The only operations that exist are: create one, and remove one. +## 2.4 The agent +- An agent is a **Push address**. A Push-native key is its own EOA; any external key — EVM, Solana, anything Push Chain supports — acts through its UEA, the account Push Chain derives for that key, which verifies the key's signature before it ever calls the wallet. The wallet itself verifies no signature: it checks only who the caller is. +- Any address may be an agent, including a smart contract such as a multisig. +- **An agent is attached to one permission, not to the wallet.** A wallet with three permissions can have three different agents, each locked to its own limits. There is no wallet-level "the agent" and no way to swap the agent inside an existing permission — a new agent means a new permission. +- The agent holds no funds of the user's and has no standing power. Its only ability is to call the agent door, naming one of its permissions, and have the wallet check that call. +## 2.5 URP — introduced +- URP is the contract where the user's real intent is enforced: *this protocol, these functions, this token, this much, for me, until then*. +- It exists because of a structural blind spot in the adopted engine, explained fully in `2_UniversalRulesPolicy.md`: from Push Chain's point of view, every agent action looks identical — a call to the gateway. URP is the contract that opens that call up and inspects what is inside — an EVM instruction list for an EVM chain, a single program instruction for Solana. +- For a native permission it does the complementary job: the engine already sees the target and function, so URP checks how the function is called — which arguments are pinned, how much value rides along, how much of a metered amount, and how many times. +- It is the one contract in the system that is **upgradeable** — it sits behind a proxy at a permanent address, so its rules can be corrected or extended without moving any wallet or reissuing any permission. That is a deliberate trade, and it is what limit 27 in chapter 9 is about: the address is fixed forever, the logic behind it is not. +- One paragraph is all it gets here. **`2_UniversalRulesPolicy.md` is its chapter.** +## 2.6 The destination account +- *(Universal permissions only. A native permission has no destination account: its actions never leave Push Chain, and whatever they produce is credited to the wallet itself.)* +- The user's account on the far chain (Ethereum, Solana, or any chain Push supports). Push Chain's existing infrastructure creates it and controls it; we adopt it as-is. +- **On an EVM chain** its address is **computable in advance** on Push Chain, before the account even exists on the far chain (`getCEAForPushAccount` forward, `ceaToPushAccount` reverse). +- **On Solana** it is a program-derived address of the gateway program, seeded by the wallet's own Push address (`["push_identity", wallet]`). A Solidity contract cannot run that derivation, so the tooling derives it — along with the destination account's token accounts for each mint the permission touches — and the owner commits the 32-byte keys at grant. A wrong key fails closed: the pins never match. +- At grant time, the tooling computes this address and freezes it into the permission. From then on, URP requires that everything the agent does on the far chain benefits **that address and no other**. The agent can trade with the user's money; everything it buys lands in the user's own far-chain account — on Solana, in that account's own token accounts. +- **On Solana the destination account is also the signer.** The gateway hands it the bridged funds and then makes one call into the target program with the destination account as the only signer — and that signing authority carries into whatever the target program itself calls. `2_UniversalRulesPolicy.md` §1.4c is how URP narrows what that authority can reach; chapter 9 states what it cannot narrow. +## 2.7 The Push-native protocol +- Any contract on Push Chain that a native permission names: a staking pool, a vault, a token, a registry. Nothing is built, adopted or trusted — it is whatever the owner chose to allow. +- The wallet calls it **directly, as itself**. The protocol sees the wallet as the caller, so whatever the call produces — a staked position, shares, a claim — is the wallet's, never the agent's. This is the native counterpart of the destination account's "for the user only" rule, one hop shorter. +- To the engine it is an (address, function) pair and nothing more. To URP it is that pair plus the pins, caps and counters the owner attached. Neither contract knows what the function *means*; both only know what the owner allowed. +## Diagram — the system map +```mermaid +flowchart TB + subgraph PUSH["Push Chain"] + OWNER["Owner\ +(the user's key)"] + FACTORY["Wallet factory\ +(upgradeable, frozen address math)"] + WALLET["Agent wallet\ +(minimal clone, never upgradeable)\ +owner door + agent door"] + SS["SmartSession\ +(adopted permission engine)"] + URP["URP\ +(the limits — 2_UniversalRulesPolicy.md)\ +upgradeable behind a proxy"] + VAL["Session validator\ +(confirms the caller is the agent)"] + GW["Cross-chain gateway\ +(adopted transport)"] + NP["Push-native protocol\ +(any contract a native permission names)"] + end + subgraph FAR["Destination chain"] + CEA["Destination account\ +(the user's far-chain account)"] + PROTO["Allowed protocol\ +(e.g. a market, a lending pool)"] + end + AGENT["Agent\ +(a Push address: an EOA,\ +or the UEA of an external key)"] + + OWNER -- "creates, one call" --> FACTORY + FACTORY -- "deploys" --> WALLET + OWNER -- "grants / revokes permissions\ +and can execute anything" --> WALLET + AGENT -- "calls the agent door itself" --> WALLET + WALLET -- "asks: is this allowed?" --> SS + SS --> URP + SS --> VAL + WALLET -- "universal action, only if every check passed" --> GW + WALLET -- "native action, only if every check passed\ +(the wallet is the caller)" --> NP + GW -- "bridges value + instruction" --> CEA + CEA -- "calls, for the user's benefit only" --> PROTO +``` +--- +# 3 · Who controls what +## The single chain of authority +There is exactly one chain of control in this system, and it starts and ends with the user. +- **The user's key owns the wallet.** Ownership is fixed at creation, inside the wallet's own bytecode. It cannot be transferred, stolen by code, or reassigned by any function — no function to do so exists. +- **The wallet owns its permissions.** Only the owner, through the wallet, can create or remove a permission. An agent cannot grant itself anything, extend anything, or remove anything. +- **A permission bounds one agent.** The agent can call the agent door within the permission's limits. That is the entirety of its power. +- **The wallet's Push-side identity owns the destination account.** The far-chain account obeys instructions that arrive through Push Chain's gateway from the wallet. The agent never controls the destination account; it can only cause the wallet to send it instructions that URP has already approved. +- **For a native permission the same rule holds one hop shorter.** The wallet calls the Push contract as itself, so the position, the shares, the claim — whatever the call produces — is credited to the wallet. The agent never controls the target contract; it can only cause the wallet to call it in exactly the way URP has already approved, with the arguments the owner pinned. +## The owner door has no checks — on purpose +- The owner can execute anything from the wallet at any time: withdraw every token, send to any address, call any contract, on Push or (via the gateway) beyond. +- **No policy, no cap, no expiry, no destination rule applies to the owner.** All of `2_UniversalRulesPolicy.md` applies to the agent door only. +- Why: every safety mechanism on the owner's own exit is also a way for the owner to be locked out of their own money. The design refuses that trade. The wallet must remain drainable *by its owner* in every degraded state the rest of the system could ever reach — engine misconfigured, policy bricked, permission wedged, bridge down. A standing test executes an owner withdrawal in each of these states and must always pass. +- The cost of this choice is stated plainly: **a stolen owner key drains the wallet completely.** There is no guardian and no delay to stop it. Defence against key theft belongs to the layer that holds keys — the user's identity and key-management setup — not to this wallet. This is the first entry in chapter 9's list of accepted limits. +- **The owner door records, but never asks.** Each call through it advances the wallet's checkpoint counter (chapter 4.5), so a job's evaluator can tell whether the owner touched the wallet during the job. The write consults nothing and cannot revert, so the door stays unblockable. +## What the agent's call is — and is not +- The agent's authority is **being the sender**. The wallet admits a call only from the address the named permission records as its agent, so there is no bearer request: nothing the agent produces can be submitted by anyone else. +- A call grants nothing durable. Each one spends from the permission's remaining budget once, as the transaction it is; replay is prevented by the sender's own nonce (chapter 5). +- The agent never touches custody. At no point in any flow do funds sit in an account the agent controls. Universally, they move from the wallet, through the gateway, to the user's own destination account, and anything bought lands in that same account. Natively, they move from the wallet straight into a Push contract as the wallet's own position, and come back to the wallet. +## Diagram — the chain of ownership +```mermaid +flowchart TB + KEY["The user's key\ +absolute control, no checks on its path"] + W["Agent wallet on Push Chain\ +owner fixed at creation, forever"] + P1["Permission 1\ +agent A · its own limits"] + P2["Permission 2\ +agent B · its own limits"] + CEA["Destination account on the far chain\ +obeys the wallet, via the gateway"] + NP["Push-native protocol\ +credits whoever calls it — the wallet"] + A1["Agent A — may only act\ +within Permission 1"] + A2["Agent B — may only act\ +within Permission 2"] + + KEY -- "owns, unconditionally" --> W + W -- "creates / removes" --> P1 + W -- "creates / removes" --> P2 + P1 -.-> A1 + P2 -.-> A2 + W -- "its Push identity controls" --> CEA + A1 -. "universal: can only trigger wallet→gateway calls\ +that URP approves, benefiting the\ +destination account only" .-> CEA + A2 -. "native: can only trigger wallet→contract calls\ +that URP approves, with the owner's pins,\ +credited to the wallet only" .-> NP +``` +--- +# 4 · The life of a permission +## 4.1 Birth — the grant +- The owner (or the tooling acting for the owner, with the owner signing) composes the terms. **The first term is the chain** — a CAIP-2 identifier such as `eip155:11155111` or `solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1` — and it decides the kind and, for a universal permission, the destination family, which together decide the shape of everything after it. Common to both kinds: +\t- the agent's Push address — its own EOA, or the UEA of its external key; +\t- the expiry — one value, held inside URP. +- **For a universal permission to an EVM chain:** +\t- the far-chain protocol: each allowed contract address and function, and — for each function — where in its arguments the *beneficiary* sits, so URP can later check that the beneficiary is the user's destination account. These argument positions are **generated from the protocol's interface by tooling, never typed by hand** (a promise the contracts cannot check — chapter 10); +\t- one token, and with it one destination chain — a permission never spans tokens or chains; +\t- the caps: a per-action maximum, a lifetime maximum, and a maximum of native PC per action; +\t- the destination account's computed address. +- **For a universal permission to Solana:** +\t- the same token, the same three caps, and the expiry — these terms do not depend on the far chain; +\t- the destination account and the **gateway program** on the declared cluster — both 32-byte keys, both supplied by tooling: the destination account derived from the wallet's address, the gateway program taken from the chain registry, never from user input; +\t- one to thirty-two **program rules**, each a far-chain program and one instruction on it, identified by its leading bytes — eight for an Anchor program, one for an SPL-style program — or marked as an instruction that carries no data. A rule may also fix the instruction's exact account count; +\t- up to sixteen **account pins**: for a given rule, the account at a given position in the instruction's account list must be a given key. This is how the destination account is locked in as the authority, its token account as the source, and its token accounts as every destination. Every rule must carry at least one; +\t- up to eight **data pins** on the instruction data: a little-endian integer at a fixed offset — from the start, or from the end, because Borsh puts variable-length fields first — compared for equality, a floor, a ceiling, or a minimum ratio against a second field. This is how a fee is locked at zero, slippage is capped, and a swap's output is held to a floor *relative to its input*; +\t- up to eight **destination-side accounts that hold value** — the destination account itself, which must be on the list, and its token accounts. At validation, any of these that appears in a request's account list must sit exactly where the matched rule pins it; +\t- **all of it is generated from the program's published interface by tooling, never typed by hand** (chapter 10). A wrong pin fails closed; a missing pin guards nothing. +- **For a native permission:** +\t- one to **eight** actions — eight is a fixed wallet constant, a sanity bound rather than a gas bound — each a Push contract and one function on it. A function may be *value-only*: a bare transfer of native PC with empty call data; +\t- per action, the **argument pins**: up to eight positions in the call data, each frozen to the exact 32-byte word that must appear there. This is how a beneficiary is locked to the wallet, a spender to one contract, a pool to one id. **Positions are generated from the contract's interface by tooling, never typed by hand** (chapter 10) — a wrong position fails closed, but a *missing* pin guards nothing; +\t- per action, the native-value caps: a per-call maximum and a lifetime maximum; +\t- per action, optionally, a **metered amount**: one argument position read as a number, with its own per-call and lifetime maximum — the native counterpart of the bridged-amount cap; +\t- per action, a **call limit**: how many times the action may run, where zero means unlimited; +\t- and nothing else. There is no token, no destination chain, and no destination account: a native permission has no far side. +- The owner sends one transaction through the wallet. The wallet supplies a salt from its internal grant counter — this is what makes every permission unique — and calls the engine's standard enable function. In the same transaction, URP's configuration — including the permission's expiry — is written: one record for a universal permission, one record **per action** for a native one, and beside them the record of which kind this is. +- **Before anything reaches the engine, the wallet derives the kind from the chain and asserts it against the actions.** Every action must name the same chain, or the grant is refused naming the action that differs — which is what makes a mixed permission unrepresentable rather than merely forbidden. A universal permission must name exactly one action, and it must be the gateway's outbound send — whatever its destination family; the wallet never tells an EVM permission from a Solana one, and does not need to. A native permission may name anything on Push Chain **except** the gateway — and except seven addresses that would turn the agent into the owner: the zero address, the engine's wildcard marker, the wallet itself, the engine, URP, the validator, and the factory. It may not name the engine's two wildcard function markers, and it may not name the same (contract, function) pair twice. Every one of these refusals carries its own named error, and the two that matter most — the wallet and the engine as targets — are pinned by permanent tests. +- The wallet exposes exactly **two** permission operations to the owner: *enable* and *remove*. The engine underneath offers more; the wallet deliberately does not surface them. *Enable* takes the session and nothing else; it records the **derived** kind and the chain in the grant event, so an indexer can tell a native permission from a universal one, and which chain it is for, without opening the session. +- A failed grant does not undo a wallet. A wallet with zero permissions is a valid, safe object: with no permission there is no agent authority of any kind, and every agent request fails before any policy even runs. +## 4.2 Life — what the counters mean +- **The lifetime cap counts what is bridged, not what is deployed.** When the agent moves 40 of an allowed 100 to the far chain, the counter reads 40. If it then trades those 40 into 80 and back again on the far chain, the counter still reads 40 — redeployment at the destination is not new spending from the wallet. The cap bounds the user's exposure *from the wallet*; the expiry bounds how long the agent can keep working with what is already across. +- **An unlimited cap is allowed and is expressed as the largest representable number.** There is no special "unlimited" flag; the comparison simply never trips. The product must display this honestly — "unlimited", never a huge number (chapter 10). The one exception is a native action's **call limit, where zero means unlimited** — a call limit of zero calls would be a permission that authorises nothing. +- **A native action keeps three counters, not one:** native value sent, the metered amount (if the action has one), and calls made. **Every successful call counts as a call, even one that sends no value and meters no amount.** A call limit that zero-value calls could slip past would be advisory, so the counter always moves — this is the one place the native rulebook deliberately differs from the universal one, whose counter does not move on a zero-amount request. +- *(Universal only.)* **If a cross-chain action fails on the far side, the spent amount is credited back** — the wallet's funds return and the counter should not stay inflated. This credit is issued by Push Chain's own executor module calling URP. It is **designed but not yet functional**: it needs a change on the Push core side that has not landed. Until it lands, a failed far-side action leaves the counter inflated, and the remedy is to revoke and regrant. Both halves of this are stated again in chapters 9 and 11. +## 4.3 Change — there is no change +- **A permission is never edited. Every "change" is: revoke the old one, grant a new one, in one atomic owner transaction.** If any part fails, the whole transaction fails, and the old permission remains exactly as it was. There is no window where the wallet is half-configured. +- One race is guarded explicitly. Between the owner composing the change and the transaction landing, the agent may spend. The owner's change transaction therefore begins with an **assertion of the expected spent amount**: "I am replacing this permission believing it has consumed X." If the agent moved money in the gap, the assertion fails, the whole change reverts, and the owner re-reads and retries with current numbers. Stale beliefs never silently become new budgets. For a native action the assertion names **all three counters** — value, amount, calls — and every one must match exactly; and it refuses to run against a permission of the other kind, or against one that does not exist, so a stale belief can never pass by reading zeros from the wrong place. +- **Counters restart from zero on the new permission.** This is a real, accepted sharp edge: replacing a 100-cap permission that had 80 spent with a "tighter" 50-cap permission yields 50 of *fresh* authority — more than the 20 that remained. The contracts do not compensate for prior spend, and the product is obliged to show the owner what the old permission had consumed before the new cap is chosen (chapter 10). +- Because no permission can ever be widened in place, an entire class of problems disappears structurally: there is no "widening inside the expiry window" to delay, timelock, or guard. The mechanism that would have needed guarding does not exist. +## 4.4 Death — revocation and expiry +- **Revocation is one owner call, effective immediately on Push Chain.** The permission's storage is removed; the very next agent request against it fails. Nothing the agent does can delay or contest this. Removal performs pure storage deletion — it calls out to nothing, so no external contract can make revocation fail (`SmartSessionBase.sol:329-355`, `ConfigLib.sol:274-284`). +- **One honest limit:** revocation stops new instructions. An instruction that already left through the gateway — already in flight across the bridge — still completes on the far chain. The window is bridge latency. The revoke screen must say this (chapter 10). +- **Expiry needs no transaction.** Past the expiry, URP's expiry gate — the second gate of every rulebook (2, N2, S2) — fails every request. The permission's storage still exists until removed, but it is inert. +- Removing a permission also ends its agent's power under it: removal clears the agent the permission named, so the very next call under that id is refused before any policy runs. A regrant produces a new id — the wallet's grant counter salts it — so a request built for the old id fails against the new permission too. A permanent test pins this. +## 4.5 Checkpoints — what the owner side did, for whoever needs to know +- The wallet keeps one **checkpoint counter**, read through `checkpointCount()`, with the block of the latest checkpoint beside it (`lastCheckpointBlock()`). A job records the count when it is funded; its evaluator compares later. Same number: the result is the agent's alone. Different number: the owner side touched the wallet. +- **What advances it:** every call made through an owner door — `execute` or `executeWithSig`, one tick per call, a batch of five ticks five times — every grant, and every revoked permission (once per id). **What never does:** the agent door and everything it dispatches, module install and uninstall, factory set-up, and any call that reverts. +- **One tick per call, taken before the call.** A job is funded from inside an owner-door call — the wallet itself calls the job contract — and the job's hook reads the counter during that call. Ticking before each call means a clean funding batch ends exactly at the hook's snapshot, while a withdrawal batched after the funding call moves the counter past it. A tick once per batch would either make every job look tampered with or hide that withdrawal. +- **Compare counts, not blocks.** Several checkpoints can share a block — including the funding call's own — so "anything after block N" misses them; a changed count never does. +- **It cannot block anything.** A tick is one write to the wallet's own storage and one event: no external call, no condition that can fail. The owner door and revocation stay unblockable. +- One counter for every kind of change. The event (`Checkpointed`) also carries the kind — `OWNER_ACTION`, `RULES_GRANTED` or `RULES_REVOKED` — and a reference (the call's hash, or the permission's id) for indexers. +## Diagram — the permission lifecycle +```mermaid +stateDiagram-v2 + [*] --> Composed: owner + tooling assemble terms + Composed --> Active: one grant transaction\ +(engine + URP + expiry written together) + Active --> Active: agent request passes\ +counters advance + Active --> Active: far-side failure\ +credit back (designed — not yet functional) + Active --> Expired: expiry passes\ +no transaction needed + Active --> Removed: owner revokes\ +immediate, unconditional + Active --> Replaced: CHANGE = revoke + regrant\ +one atomic transaction,\ +gated by the spent-amount assertion + Replaced --> [*]: old id dead — requests for it die with it\ +new permission starts at zero + Expired --> Removed: cleanup, optional + Removed --> [*] +``` +--- +# 5 · One action, end to end +This chapter walks a single agent action from the agent's call to funds moving. It is the spine of the whole system; `2_UniversalRulesPolicy.md` then zooms into the deepest step. +## 5.1 Why the wallet does so much itself +- On chains that follow the account-abstraction standard, a shared system contract (the "EntryPoint") receives signed account operations, checks replay protection, and dispatches them. **Push Chain has no such contract.** So our wallet performs those jobs itself, inside one function — the agent door, `executeAsAgent`. +- The wallet keeps the standard's *packaging* (the operation format), because the adopted permission engine speaks it. But the packaging is just a shape; there is no shared dispatcher behind it. The wallet is its own dispatcher and never leaves the call stack — which has one important consequence used later: **when the wallet finally calls the gateway, the gateway sees the wallet itself as the caller**, not the agent. +## 5.2 The request the agent sends +What the agent sends depends on the permission's kind — but only in the innermost part. The call around it is identical for both. +**A universal request has nested layers.** The agent composes the action innermost first: +- **Innermost — the far-chain call.** The actual thing the user wanted: for example, *buy these shares, for this much of the token, with the user's destination account as beneficiary*. +- **Around it — the instruction list.** The far-chain calls are packed as an instruction list for the destination account, between one and **ten** entries — ten is a fixed contract constant. Each entry is: a target address, a native-value amount, and call data. +- **Around that — the gateway request.** The message to Push Chain's gateway: which token and how much to bridge, the instruction list as payload, and two routing fields URP will pin (`2_UniversalRulesPolicy.md`): the bridged-funds recipient field, and the refund destination. +- **Outermost — the execution payload.** The gateway request as the single call the wallet will make: the gateway as target, the PC for far-side gas as value. +**A universal request to Solana has the same layers, with a different middle.** There is no instruction list: the gateway makes exactly one call into one program per request, so the payload is a **single Solana instruction** — the account list (each a key and a writable flag), the instruction data, and the target program — in the byte format Push Chain's validators decode, not ABI. The gateway request's recipient field, which must be empty for an EVM chain, carries the **target program** here, and must equal the program named inside the payload. A flow that needs two instructions is two requests, the later ones bridging nothing. +**A native request has one layer.** There is no far-chain call, no instruction list and no gateway request. The agent names a Push contract, a native-value amount, and the call data — and that flat call *is* the execution payload. Three nested envelopes become one call; nothing else changes. +Then the agent calls the agent door itself with three things: **the permission's id, the execution mode, and the execution payload.** There is no signature to attach — the agent's authority is being the sender. +## 5.3 Who may call — the sender check +- The wallet looks up the agent the named permission records — the address stored in it at grant — and compares it with the caller. Anyone else is refused, by name, before the engine is ever called: the owner, a stranger, another permission's agent. An id that is unknown, revoked, or names a session validator other than the canonical one records no agent, so a call under it is refused the same way. +- **An external key acts through its UEA.** The UEA verifies the key — secp256k1, Ed25519 or whatever that chain uses — and then calls the wallet; the UEA is the agent the permission names. The external key calling the wallet directly is just another stranger. +- The wallet then writes the caller's address into the operation it hands the engine, in the field the engine treats as the signature. Nobody outside the wallet can supply that field: the engine accepts an operation only from the account it is for, so only the wallet can obtain a verdict for the wallet. At the end of validation the session validator compares that address with the agent stored in the permission — a second, independent check behind the first. +## 5.4 Replay protection — the sender's own +- Each agent action is a transaction of the agent's own. An EOA agent's transaction carries its nonce; a UEA agent's action is a UEA payload with its own nonce and deadline. A transaction that has been mined cannot be mined again, so no request runs twice — and the wallet keeps no replay state for agents at all. +- The same call submitted twice is two actions: each is checked against the permission and each is metered. +- If execution reverts, the whole transaction unwinds — every counter, everything — leaving no half-spent state. A failed action costs the agent gas and changes nothing else. +- Expiry is the permission's own, checked inside URP. There is no separate per-request deadline at the wallet; a UEA payload carries one, an EOA transaction does not. +- One honest note: an EOA agent has a single sequential nonce, so a stuck transaction blocks that agent's next one until it is mined or replaced. Accepted, and an agent-side problem only. +## 5.5 The walk, in order +What happens when the agent calls, step by step. Every step is on Push Chain, inside one transaction, until the bridge. +1. **The agent calls the agent door**, naming the permission. **The wallet's first acts are to confirm the engine is still installed — the owner switches the agent door off entirely by revoking everything and uninstalling it — and that the caller is the agent the permission names.** Both are checked before anything else costs gas; a wrong caller is refused by name. +2. **The wallet builds the operation**: the execution as an `execute` call, and in the signature field the use-mode marker, the permission's id and the caller's address — written by the wallet, never supplied from outside. +3. **The wallet asks the permission engine to validate.** SmartSession looks up the permission by its id: does it exist on this wallet? Which policies are attached? +4. **The engine runs every attached policy, in order, on the raw request.** First it identifies the action by the call's target and function; a native request naming any pair the permission did not grant dies here, at the engine, before any policy runs. Then, for this system, exactly one policy: **URP — the whole of `2_UniversalRulesPolicy.md`**, which reads the permission's kind and runs the matching rulebook, and which carries the expiry check itself. Every policy must pass; any failure ends everything with nothing spent. Two engine facts matter here: +\t- **Action policies have a minimum count of one, but the engine's other policy class (checks on the outer operation) has a minimum of zero** (`SmartSession.sol:237-247, 285-299`). Rule for this system: **no mandatory guarantee may live only in that zero-minimum class**, because a configuration with none of them is legal. Everything mandatory lives in URP. +\t- **Policies run before the session validator is consulted** — an engine ordering we adopt, not choose (`SmartSession.sol:340-352`). The wallet has already checked the caller at step 1, but the rule stands for every policy: it must be safe to run on arbitrary calldata the engine has not yet authenticated. URP holds no state that validation mutates, so a bad request can waste gas and nothing else. +5. **The session validator is consulted last.** It compares the address the wallet wrote into the signature field with the agent stored in the permission. Wrong address, no execution. +6. **The wallet enforces the verdict explicitly.** Because there is no EntryPoint to do it, the wallet itself unpacks the engine's answer and enforces both the pass/fail result and the validity window it returns. +7. **The wallet refuses two targets whatever the engine said.** After validation and before dispatch, if the approved call targets the wallet itself or the engine, the wallet reverts. Neither can ever be granted (chapter 4.1), so on a permission the wallet created this never fires — it exists for a permission the owner enabled on the engine *directly*, bypassing the wallet's grant check, which the owner door permits. It is the last of four independent refusals of a self-call, it runs deliberately **after** validation and not before (chapter 11), and two permanent tests pin it — one of them reaching the engine as a target through the engine's own wildcard. +8. **The wallet makes the approved call, with the exact validated bytes.** For a universal permission that is **the gateway**: it sees the wallet as the caller, pulls the bridged token amount from the wallet's balance, takes the PC provided for far-side gas, and emits the cross-chain message. For a native permission it is **the named Push contract**, called by the wallet as itself, carrying the approved value and call data: the contract sees the wallet as the caller, and whatever the call produces is the wallet's. **A native action is complete here** — one Push transaction, no bridge, nothing in flight. The two steps below are universal only. +9. **On the far chain**, the destination account receives the message and runs the instruction list, entry by entry, each call made *by the user's own account* — which is why anything bought lands as the user's. **On Solana** the gateway moves the bridged funds to the destination account and makes the one approved call into the target program, with the destination account as signer; whatever the instruction produces lands in the token accounts the pins named. +10. **If the far side fails**, the funds return through Push Chain's infrastructure, and the credit path of chapter 4.2 applies (designed — not yet functional). Gas is never refunded: it was genuinely consumed. **A refund credit must not move any gas counter** — a permanent rule. +## Diagram — one agent action +```mermaid +sequenceDiagram + participant AG as Agent (EOA, or UEA of an external key) + participant W as Agent wallet + participant SS as SmartSession (engine) + participant U as URP + participant V as Session validator + participant GW as Gateway + participant DA as Destination account (far chain) + participant NP as Push-native protocol + + AG->>AG: universal (EVM): build nested layers:
far-chain call → instruction list (≤10) → gateway request → payload
universal (Solana): one program instruction → gateway request → payload
native: one flat call (contract, value, data) = payload + AG->>W: executeAsAgent(permission id, mode, payload) — the agent is the sender + W->>W: 1. engine still installed? caller == the permission's agent?
(refused by name otherwise, before the engine runs) + W->>W: 2. build the operation; write USE ‖ id ‖ caller into the signature field + W->>SS: 3. validate against the named permission + SS->>SS: identify the action by (target, function);
an ungranted pair dies here + SS->>U: 4. the whole of 2_UniversalRulesPolicy.md —
read the kind, run its rulebook, check every limit + U-->>SS: pass / fail (nothing spent on fail) + SS->>V: 5. LAST: is the address in the signature field the permission's agent? + V-->>SS: agent confirmed / rejected + SS-->>W: verdict + W->>W: 6. enforce the verdict and its validity window itself + W->>W: 7. refuse the wallet or the engine as target, whatever the verdict + alt universal permission + W->>GW: 8. call with the exact approved payload
(gateway sees the WALLET as caller) + GW->>DA: bridge token + instruction list + DA->>DA: EVM: run each instruction as the user's own account
Solana: one call into the target program, the user's account signing + Note over U,DA: far-side failure → funds return, spend credited back
(designed — not yet functional) · gas never refunded + else native permission + W->>NP: 8. call the named Push contract with the exact approved bytes
(the WALLET is the caller) + NP-->>W: whatever the call produced is the wallet's — done, one transaction + end +``` +--- +# 6 · The rules policy +URP — the Universal Rules Policy (`UniversalRulesPolicy`) — has its own document: [`2_UniversalRulesPolicy.md`](2_UniversalRulesPolicy.md). It covers why the contract exists, what it stores for each kind of rules set, what it opens, every gate of the universal EVM, Solana and native rulebooks, what it counts, what it deliberately does not do, and how a rules set's kind is fixed — with the flow diagrams. +--- +# 7 · What we adopted, and what that costs +Four external systems are load-bearing. For each: what we rely on it for, and the exact exposure that reliance creates. Nothing here is hidden as a footnote. +## 7.1 The permission engine (SmartSession) +- **Relied on for:** storing permissions and each one's agent, deriving their ids, running every policy, and consulting the session validator — the whole of chapter 5, steps 3–5. +- **What we get for free:** battle-tested storage and lifecycle code; removal that is pure storage deletion and cannot be blocked by any external call (`SmartSessionBase.sol:329-355`, `ConfigLib.sol:274-284`). +- **The costs, each one carried knowingly:** +\t- **Policies run before authentication** (`SmartSession.sol:340-352`). Every policy we ever attach must be safe on arbitrary calldata from anyone. This is a standing constraint on all future policy work, not just on URP. The wallet authenticates the sender before the engine runs, but the engine's own ordering is unchanged. +\t- **One policy class may legally be empty** (`SmartSession.sol:237-247`) — hence the wiring rule that nothing mandatory lives there. +\t- **The engine ships an owner-only function that resets a policy's counters in place.** v3 tooling never calls it, and the agent structurally cannot (it is owner-path only) — a named test proves the agent cannot reach it. But it survives upstream, and a future tool that called it would silently refill a budget. +\t- **At grant, the engine refuses only two targets: the zero address and itself** (`ConfigLib.sol:139-143`). It does **not** refuse its own wildcard marker at grant — only at validation. The wallet is therefore the only grant-time layer keeping that marker, and the two wildcard function markers, out of a native permission. The wallet refuses all three by name; a constant-mirror test pins each value against the vendored engine so a fork bump cannot silently move them. +\t- **The engine identifies an action by (contract, function) alone**, so two entries naming the same pair collapse to one configuration, and the second initialisation would be refused by URP with an error naming an opaque id. The wallet refuses duplicates first, naming the pair. +\t- **The engine truncates a policy's revert data to 32 bytes** before re-wrapping it — a selector and 28 bytes of the first argument. Every native-rulebook error is therefore ordered with its diagnostic value first (`2_UniversalRulesPolicy.md` §1.4b). Wallet errors do not pass through the engine and are not truncated. +## 7.2 The cross-chain gateway +- **Relied on for:** carrying value and instructions to the far chain, and being the *only* thing a universal agent action can touch (gate 3) — and the one thing a native action never may (gate N3, and the wallet's grant check). +- **The costs:** +\t- We inherit the gateway's availability and its bridge latency — the revocation window of chapter 4.4 is exactly this latency. +\t- The gateway's refund behaviour for our outbound direction is documented for the *inbound* direction only (`Revert_Handling.md:14` covers inbound; outbound is handled by Push core's own modules). Our exposure analysis of refund edge-cases is complete except for this one gap, recorded as an open question (chapter 11). It blocks nothing we build. +\t- **On Solana the far side is Push Chain's gateway program**, whose id differs per cluster. URP has no registry for it, so it is committed by the owner at grant from the chain registry (chapter 10). A wrong value weakens only that owner's permission, and fails closed on the pins. +\t- **On Solana the gateway makes one call per outbound.** A flow that needs two instructions — create a token account, then swap — is two outbounds, the later ones bridging nothing. A limit of the gateway, not of URP. +\t- **On Solana URP must parse exactly what Push Chain's validators parse.** The payload grammar of `2_UniversalRulesPolicy.md` §1.3 is theirs; a change to it on their side is a change URP must follow, and until it does every Solana request fails closed at S12. +## 7.3 The destination-account system +- **Relied on for:** the user's far-chain account — its creation, its address computation in both directions, and its obedience to gateway messages. +- **The costs, inherited not owned:** +\t- **Its factory is upgradeable by Push governance,** and the account templates can be rotated. Our guarantee that "the committed destination address is the user's account" is therefore inherited from Push's own governance discipline. We accept this on admin trust — Push's governance is our platform, not our adversary. One operational duty watches it (chapter 10): monitoring compares each permission's committed destination address against the current prediction, so a rotation that changes derivations is *detected* even though nothing on-chain prevents it. +\t- **A paused destination-account factory blocks a first outbound to a chain where the user's account does not yet exist.** Availability only; no funds at risk. +\t- **The account's own instruction loop is unbounded** in Push's code — our ten-entry bound (gate 13) is enforced on our side, and a note is open with Push core about theirs (chapter 11). +\t- **On Solana the destination account is a signer, not a caller.** Whatever program it is handed may act with its signature on every account in the list, including through that program's own inner calls. This is the one way the Solana rulebook is structurally weaker than the EVM one; `2_UniversalRulesPolicy.md` §1.4c's S17 and S18 narrow it, and chapter 9 states the remainder. +\t- **On Solana only the bridged token's account is created for the user automatically.** The gateway creates the destination account's token account for the bridged mint on first use; any other token account — a swap's output, say — must exist beforehand (chapter 10). +## 7.4 Push Chain's executor module +- **Relied on for:** the credit-back path — it is the one caller URP will believe about far-side failure. +- **The costs:** +\t- The whole credit-back feature is **gated on Push core work that has not landed** — the module does not yet call URP on failure. Until it does, the feature is inert and the counter-inflation limit of chapter 9 applies. +\t- Its on-chain address is written in Push's platform code (`UniversalCore.sol:50`) but **unconfirmed against a live deployment** — one of the two facts that must be confirmed before URP hardcodes anything (chapter 11). +\t- URP cannot verify the amounts it reports — trusted, with damage bounded by once-per-id and never-below-zero. +--- +# 8 · Guarantees +Every promise the system makes, with the mechanism behind it and the test that proves it. A promise with no mechanism is marketing; each of these names its enforcement. +| The promise | The mechanism | Proven by | +| ---------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | +| Nobody but you can ever own your wallet | Owner = creator, baked into the clone's bytecode; no function to change it | No code path accepts another owner — deployment attempts prove it | +| The agent can never spend a token you did not name | Gate 5: the one-token pin | A request naming any other token reverts | +| …never more per action than you set | Gate 6 | An over-cap request reverts | +| …never more in total than you set | Gate 7 + spend recorded before dispatch | Requests summing past the cap revert at the crossing point | +| …never for anyone's benefit but yours | Gate 15's beneficiary pin; on Solana, gate S17's account pins | A request naming any other beneficiary — on Solana, any other destination token account — reverts | +| …never touching any protocol you did not allow | Gate 15: the allow-list — on Solana, gate S16's exact (program, instruction) match | A request to an unlisted target or function — on Solana, an unlisted program or instruction — reverts | +| …never after the end date | Gate 2 — the expiry inside URP (N2 native, S2 on Solana) | A request after expiry reverts with no state change | +| …never instructing your far-chain account directly | Gate 14, including the destination account, checked before the allow-list; on Solana, gate S15, which adds the token, system, stake, loader and lookup-table programs and the gateway program | **Must revert even when that address is in the allow-list** — permanent tests, at grant and at validation on Solana | +| *Solana:* …never handing your account's other balances to the program | Gate S18: every value-holding account appears only where the matched rule pins it; the list always contains the destination account | A value-holding account at an unpinned position reverts — permanent test; a list without the destination account is refused at grant — permanent test | +| *Solana:* …never swapping below the floor you set | Gate S17's data pins — a floor relative to the input, a slippage ceiling, a zero fee | A swap whose output falls short of the ratio reverts, including one that raises the input to beat a static floor — permanent test | +| *Solana:* …never more per action than Solana can carry | Gate S6b | An amount above 64 bits reverts | +| A "failed" action can never deliver funds to the agent | Gate 10 (refunds come home) + gate 11 (no side recipient); on Solana, S10 + S11 and S14 (the recipient is the target program, nothing else) | A request with any of these fields wrong reverts | +| Only the permission's agent can act under it | The wallet checks the caller against the agent the permission names before the engine runs; the session validator checks the address the wallet wrote, last | Every other caller — the owner included — is refused by name | +| No request runs twice | Each agent action is the agent's own transaction — an EOA's nonce, or the UEA payload's nonce; the wallet keeps no agent replay state | A mined transaction cannot be mined again; the same call sent twice is two actions, each checked and metered | +| A request dies with its permission | Removal clears the permission's agent; a regrant gets a new id from the wallet's grant counter | **A request for the old id fails after revoke-and-regrant** — permanent test | +| One permission's request can never be charged to another | The call names its permission, whose agent must be the caller; URP keys every counter on that id | An agent acting under another agent's permission reverts | +| Revocation is immediate and unblockable | One owner call; removal is pure storage deletion, no external calls | Revocation succeeds with a hostile policy installed; next request fails | +| A change never mixes old and new states | Atomic revoke + regrant; spent-amount assertion gates it | The change reverts when the agent spent in the composition window | +| A failed action costs gas and nothing else | Whole-transaction revert unwinds every counter | Counters identical before and after a failed action | +| You can always withdraw everything | The owner door has no checks | Owner withdrawal succeeds in every degraded state we can construct | +| A module can never block its own removal | The uninstall callback runs defensively with a fixed 100,000-gas stipend; on revert or burn-out an event is emitted and removal proceeds anyway | A callback that reverts and one that burns all its gas are both still removed | +| The agent can never refill its own budget | The engine's reset is owner-path only; v3 tooling never invokes it | **The agent-cannot-reset negative test** — permanent | +| Your wallet address, once computed, stays valid | Address math frozen across factory upgrades | **The address-stability regression test** — permanent | +| *Native:* the agent can never call a Push contract or function you did not name | The engine's action identity, plus gates N4 and N5 asserting URP's own copies | A request to an ungranted pair dies at the engine; a mismatched copy reverts at URP | +| *Native:* …never with a pinned argument set to anything else | Gate N7 — full 32-byte equality at the frozen position | A request with any pinned word different reverts, including a correct address with dirty padding | +| *Native:* …never more native value, per call or in total | Gate N6 | An over-cap call reverts; calls summing past the lifetime cap revert at the crossing point | +| *Native:* …never more of a metered amount, per call or in total | Gate N8 | The same, on the metered argument | +| *Native:* …never more calls than you allowed | Gate N9, with every successful call counted | The (n+1)th call reverts; a zero-value call still consumes one | +| The agent can never make your wallet call itself or its engine | Refused at grant — never grantable — and refused again at dispatch, after validation, whatever the engine said | **Two permanent tests**, one of which reaches the engine as a target through the engine's own wildcard, enabled through the owner door | +| A native permission can never reach the gateway; a universal one can never reach anything else | The kind is derived from the chain and asserted against every target at grant; gate 3 and gate N3 mirror it at validation | A gateway target under this chain, and a non-gateway target under a foreign chain, both revert at grant — **permanent tests** | +| Two permissions of different kinds on one wallet never touch each other's counters | Separate storage per kind, keyed by action id | A native call moves no universal counter — asserted on the raw storage slot, not through a getter | +| A permission for a chain URP cannot check is never granted | The destination family is derived from the chain's namespace at grant; any namespace but `eip155:` and `solana:` is refused | A grant naming any other namespace reverts at initialisation | +| An 8183 evaluator can tell whether the owner touched the wallet during a job | Checkpoint counter: every owner-door call, grant and revoke advances it, before the call; agent actions never do | The checkpoint suite, including three permanent tests | +## The permanent tests +Thirty-one tests across the build documents and suites are marked permanent — **never to be deleted or weakened**. The four below are the ones this table's universal promises rest on directly. The other twenty-seven pin promises made elsewhere in this document: the owner path surviving every degraded state; the two routing pins; the session validator calling nothing — both of its entry points are pure, so no external call can reach the agent check; the agent door never touching the owner's replay lanes; the owner door touching only the checkpoint slot; the checkpoint taken before each owner call; a withdrawal batched after a snapshot made visible; agent actions never moving the checkpoint; the enable-mode-is-dead test; the request-body length constant; the seven native-permission tests (the wallet and the engine refused as targets at grant, the wallet and the engine refused at dispatch, a gateway target refused as native, a non-gateway target refused as universal, the wildcard markers refused, and gate N3 proven live); URP's exact external-function set; the refusal to re-initialise a universal configuration that has no mode record; and the eight Solana-rulebook tests (forbidden programs refused at grant, and again at validation; the value-holding list must contain the destination account; vacuous or impossible data-pin values refused; a redirected destination token account refused; the price floor relative to the input; a value-holding account at an unpinned position refused; and the forbidden program ids pinned against their published base58 forms). Each is the only thing pinning a promise that some future refactor will be tempted to break: +1. **Address stability** — the factory's address math never changes. Breaking it strands counterfactually funded addresses, with no migration remedy in existence. +2. **The forbidden destination-account rule beats the allow-list** — remove this and one owner mistake (allow-listing their own far-chain account) hands the agent everything that account holds. On Solana the same rule covers the forbidden programs of gate S15. +3. **A request for a revoked permission fails after regrant** — remove this and a revoke-and-regrant could leave the old id usable against the new budget. +4. **The agent cannot reset counters** — remove this and the lifetime cap is advisory. +--- +# 9 · What this system does not protect against +Thirty-four accepted limits. Each is a deliberate choice, stated without softening. A builder who "fixes" one of these is reverting a decision, not fixing a bug. Where an open question could change one, it is named in plain words. +## Keys and people +1. **A stolen owner key drains the wallet completely.** Deliberate: any brake on the owner is also a lock-out of the owner. Defence belongs to the user's key-management and identity layer — and what that layer actually guarantees is itself still an open question (chapter 11). +2. **Nobody can act while the owner is unreachable.** No guardian, no emergency contact. Deliberate. The open question "should an emergency contact return?" would change this. +3. ~~Whoever holds a signed request may submit it.~~ **CLOSED.** The agent door admits only the permission's agent as the caller; there is no signed request for anyone else to hold. +## Timing +4. **Revocation cannot recall an instruction already in flight.** The window is bridge latency. Deliberate — physics of bridging. The revoke screen must disclose it. +5. **There is no ceiling on how far ahead a permission may expire.** The user's choice is respected as given. The residual is the agent acting late within the authorised window — never theft, never an amount or target the user did not allow. Deliberate. +## Budgets +6. **Replacing a permission starts its counters at zero — tightening a cap can increase remaining authority.** Deliberate: silent compensation was judged worse than an honest reset. The product must show prior consumption before a new cap is set. +7. **The lifetime cap bounds bridging, not redeployment.** Money already across can be redeployed endlessly until expiry. Deliberate — the cap is exposure-from-the-wallet; the expiry is the time bound. +8. **The adopted engine contains an owner-only counter reset that survives upstream.** Our tooling never calls it; the agent structurally cannot. Deliberate adoption cost, held by a permanent test. +9. **There is no deny-list, so an owner may allow-list a token-approval function** — which hands the agent spending power outside every cap. Deliberate: the model is allow-list-only, and the owner's list is the owner's responsibility. The open question "should the contract refuse approval-granting functions?" would change this. +10. **Until Push core's failure-reporting lands, a failed far-side action leaves the spent counter inflated.** Deliberate and *temporary*. Remedy meanwhile: revoke and regrant. +11. **A refund credit's amount cannot be verified by URP.** Trusted from Push core; damage bounded by once-per-id and never-below-zero. +12. **Gas is never credited back on failure.** The gas was genuinely consumed. Deliberate, with a rule that no credit path may ever touch a gas counter. +## Mechanics +13. **An EOA agent has one sequential nonce and no per-request expiry.** A stuck transaction blocks that agent's next one, and a broadcast transaction stays valid until it is mined or replaced. Bounded by the permission's own expiry and by revocation; a UEA agent's payloads carry the UEA's own nonce and a deadline. Deliberate: replay protection is the sender's own, and the wallet keeps none for agents. +14. ~~Two relayers racing the same request: the loser wastes its gas.~~ **CLOSED.** There are no relayers on the agent door: only the agent submits its own call. +15. **Policies run before the engine consults the session validator** — an adopted-engine ordering. The wallet has already checked the caller, but the standing constraint holds: every policy, forever, must be safe on arbitrary calldata from any caller. +## Platform inheritance +16. **The destination-account templates can be rotated by Push governance.** Accepted on admin trust; monitoring detects derivation changes; nothing on-chain prevents them. +17. **The destination-account factory is upgradeable — our address-verifiability guarantee is inherited, not owned.** Accepted: Push governance is our platform. +18. **A paused destination-account factory blocks a first outbound to a new chain.** Availability only; funds are never at risk. +## Permanence +19. **If the wallet's creation bytecode ever drifted, every pre-computed and pre-funded address would be stranded, with no remedy.** That is why the address-stability test is permanent and the address math is frozen forever. +20. **Deployed v3 wallets can never be migrated.** No upgrade path exists by construction. The open question "when does that stop being acceptable?" records the revisit trigger — nothing more. +21. **Adding any wallet-wide guard later means every user moves to a fresh wallet.** The direct consequence of shipping a validator-only wallet. The product obligation to walk users through far-chain balances exists for exactly this future. + +## Operations + +22. **The factory can be paused, which temporarily blocks new wallet creation.** A user who computed and funded a wallet address in advance cannot deploy it while the pause is on, so those funds are unreachable until it is lifted. **Availability only** — nothing is lost, no existing wallet is affected, and no deployed wallet can be frozen by anyone. Deliberate: it is the system's only incident lever, and its blast radius is limited to signups. + +23. **A misbehaving agent can burn the wallet's native gas balance in fees, within its caps.** Every action costs the wallet native gas up to the per-action ceiling, and a redeploy-only rules set lets an agent act repeatedly without ever moving the spend counter. Bounded by exactly two things: **the gas balance the owner funded, and the expiry.** Deliberate — the alternative is a second counter on a second asset, and the wallet's own funding is already the honest limit. Obligation 15 makes the number visible before the user commits. + +## The limits contract itself + +27. **URP is upgradeable, so whoever holds its proxy admin can rewrite every limit in this document.** This is the most powerful role in the system, and it is stated here rather than left to be discovered. What that role *can* do: replace URP's logic, and with it every gate, cap and pin described in `2_UniversalRulesPolicy.md`. What it *cannot* do: reach into a permission's stored configuration or its counters directly, or touch a wallet's funds — an existing permission keeps its caps until new logic says otherwise, and the owner door never consults URP at all. The trust anchors URP was initialised with (the gateway, the credit-back caller, the engine) have no setter; the only route to changing them is a full implementation swap. **Deliberate, and a genuine trade:** URP previously held those anchors in bytecode and needed no admin trust at all, but a policy that cannot be corrected is a policy whose first mistake is permanent — and its storage layout is frozen and append-only precisely so that a correction cannot silently reinterpret permissions already granted. The mitigation is procedural, not structural: the admin should be a multisig behind a timelock, so a change is visible before it lands. Until it is, this item reads exactly as written. + +## Native permissions + +24. **An unpinned argument guards nothing.** The native rulebook locks the words the owner pinned and nothing else; an argument the owner did not pin is the agent's to choose. Allow-listing a token approval without pinning the spender hands the agent that approval — the native form of the no-deny-list rule (item 9). Deliberate: the contract compares words, it does not understand functions. Obligation 16 makes the SDK refuse to emit the unpinned form. +25. ~~The kind the wallet was told and the kind URP recorded can disagree.~~ **CLOSED.** The premise was that the wallet never decodes URP's initialisation data. It now decodes exactly one field of it — the chain — and both contracts derive the kind from that same value, so there is nothing for them to disagree about and the grant event reports a derived fact rather than a claim. The narrow exception this required is bounded and stated in `2_UniversalRulesPolicy.md` §1.7: one field, read only after the policy has been proven to be URP's, used only to choose which shape rules apply. The terms themselves remain URP's sole business. +26. **A native call limit counts calls, not effects.** An action with a call limit of ten lets the agent spend those ten on calls that move nothing. Deliberate — the alternative, not counting a zero-value call, makes the limit bypassable by exactly such calls. Obligation 18 says so on the grant screen. + +## Solana permissions + +28. **An account pin bounds where value is delivered, not what an allow-listed program may take.** On Solana the destination account signs the whole call, and that authority carries into every call the target program makes on the accounts it is handed. The forbidden set guards the top-level target only. S18, the data pins and a fixed account count narrow what the program is handed; obligation 20 narrows which programs are allowed at all. The remainder is trust in the allow-listed program's code — and Solana programs are commonly upgradeable, the same class of trust as an EVM proxy. +29. **The loss ceiling on Solana is not the lifetime cap.** The caps meter what is bridged per request. Swap outputs, leftovers, and anything anyone sends to the destination account or its token accounts are reachable by any allow-listed program handed those accounts. The honest ceiling is the wallet's balance plus everything the destination account holds. Accounts the owner did not list as value-holding are not judged by S18 at all — deliberately: the list is the owner's statement of what is worth protecting. +30. **A price floor is policy without an oracle.** A ratio floor set at grant goes stale as the market moves — refusing honest trades in one direction, permitting worse ones in the other. Deliberate: URP holds no price feed and makes no external call at validation. The remedy is a regrant, and obligation 21 makes the cadence part of the grant. +31. **Rent is a leak.** A program that creates accounts with the destination account as payer spends its SOL. Not preventable by pins; bounded only by which programs the owner allows. +32. **Swap outputs stay on Solana until the owner brings them home.** Gate S5 pins the outbound token to the permission's listed assets, so the agent can repatriate only a listed asset, never what it bought. The owner door can repatriate anything. Deliberate. Whether listing the output token as a second asset is a safe remedy is open — see `docs/multi-asset-review.md`. + +## Checkpoints + +33. **The checkpoint counter is coarse.** Any owner-door call advances it, harmless or not; the wallet cannot tell whether an arbitrary call moved value. Deliberate. +34. **The checkpoint counter is blind to what needs no wallet call.** An allowance the wallet granted before a job's snapshot can be pulled without the owner touching the wallet, and plain transfers in never tick. The evaluator decides how to treat balances. Deliberate. +--- +# 10 · What the product must do that the contracts cannot +Twenty-three obligations. The contracts cannot check any of them; each names what goes wrong if it is skipped. **Twenty-one of the twenty-three currently have no test anywhere — this is the largest untested surface in the design, and it is the surface users actually experience.** +## The grant and change screens +1. **Argument positions for beneficiary checks are generated from each protocol's interface by tooling — never typed by hand.** A wrong position makes gate 15's beneficiary pin check the wrong bytes: the beneficiary pin silently guards nothing. +2. **Every newly supported protocol ships a rejection test** — a wrong beneficiary and an oversized amount must be shown to revert before that protocol is offered to users. This obligation is itself the test for the previous one. +3. **The destination account address is derived by tooling, never pasted, and the grant screen shows it — and whether it is deployed yet.** A pasted address puts the beneficiary pin under a typo's control. +4. **The grant screen gives the expiry the same prominence as the cap.** Users who see "100" but not "90 days" are authorising more time than they know. +5. **The grant screen shows the destination account's current idle balance.** The agent's instructions can use whatever sits there — the user should see the real exposure, not just the new budget. +6. **An unlimited cap is displayed unmistakably as unlimited — never as a huge number.** A number that means "no limit" printed as digits is a deception. +7. **On a change, show what the old permission consumed before the owner picks the new cap.** Without it, the counters-reset edge (chapter 9, item 6) catches owners silently. The change flow's stale-state assertion forces the tooling to read the old value anyway — showing it costs nothing. +8. **The change flow must never silently shrink the owner's chosen new cap to compensate for prior spend.** The reset is honest; a hidden adjustment would be a lie in the other direction. +9. **The revoke screen states that an already-dispatched instruction still completes.** Otherwise revocation reads as a guarantee it is not (chapter 9, item 4). +## Partners and operations +10. **Launch partners are told, before integration, that rotating an agent's key means a new agent address — revoking and regranting every permission naming the old one, counters resetting with it.** A partner who rotates keys casually will burn its users' budgets. +11. **The agent funds its own gas** — an EOA agent holds PC, a UEA agent's gas path is funded — separate from any wallet balance. If it runs dry, every user's agent stops at once: an outage, not a security event, but an outage the product owns. +12. **A user moving to a new wallet version is told their far-chain balances do not move automatically, and is walked through each one.** No tooling for this exists yet; until it does, this is a support-ticket generator (and chapter 9, item 21, is why it will happen). +13. **Monitoring compares each permission's committed destination address against the current derivation.** This is the detection half of the admin-trust acceptances (chapter 9, items 16–17): drift is caught by operations, or not at all. + +## Wallet creation + +14. **At wallet creation, the interface shows the destination-chain account address this wallet will have on each supported chain.** Every new wallet the user creates means a new account on every chain they may reach. If that cost is not shown before they commit, they discover it later — usually when they find balances stranded on a wallet they stopped using. + +## Gas funding + +15. **The grant screen states how much native gas token the wallet holds, and how many actions that funds at the chosen per-action gas ceiling.** The wallet spends its own gas balance on every cross-chain action — **including actions that bridge nothing**, which is the redeployment path. So the gas balance is a second, independent budget that no cap in the rules set bounds. A user who funds a wallet generously with gas and grants a long expiry has authorised more agent activity than the token caps alone suggest. + +## Native permissions + +16. **Argument pins are generated from the Push contract's interface by tooling — never typed by hand — and an approval-granting function is refused unless its spender argument is pinned.** A wrong pin position fails closed: the word will not match and every call reverts. A *missing* pin fails open: the argument is unchecked (chapter 9, item 24). The SDK is the layer that knows what a function means; the contract only knows what was pinned. +17. **The chain is stated once, and the tooling states it exactly as the asset reports it.** The kind is no longer a variable tooling can carry two copies of — it is derived, by both contracts, from the one chain string in the policy blob (`2_UniversalRulesPolicy.md` §1.7). What remains is a *transcription* obligation: for a universal permission the string must be byte-exact what the asset's own chain view returns, or the grant is refused at initialisation; for a native one it is this chain's own identifier. A near-miss such as a different letter case is not corrected — it derives the other kind and is refused against the targets. +18. **The native grant screen shows, per action, the contract, the function, every pinned argument in human terms, the value and amount caps, and the call limit — and states that a call limit is consumed by any successful call, including one that moves nothing.** Eight actions with eight pins each is the ceiling on what a user may be asked to approve at once; the ceiling exists so that this screen stays readable, not for gas. + +## Solana permissions + +19. **Program rules, account pins and data pins are compiled from the program's interface, fetched at grant — never typed by hand — and the interface's hash is recorded on the grant.** Rules are exact to one instruction and never share a data-pin set with a sibling instruction: two instructions with fields of the same widths at the same offsets can mean opposite things. Every value-carrying account — the authority, the source, every destination, every fee account — is pinned, and every fixed-layout instruction has its exact account count set. An instruction whose value-carrying accounts, input amount or minimum output cannot be identified from the interface, or whose scalar fields sit between two variable-length fields, is refused rather than approximated. A program upgrade that shifts an instruction's layout silently moves every pin measured from the end; the pins are re-verified after any upgrade of an allow-listed program. A missing pin fails open (chapter 9, item 28); URP's "every rule has a pin" check is hygiene, not completeness. +20. **An aggregator is allowed only through its shared-accounts instruction**, so that the inner legs run under the aggregator's own authority and the destination account is never handed to a downstream exchange as signer. The variants that put the user's intermediate token accounts in the account list are never allowed. Each aggregator card is gated on a fork test showing the aggregator refuses a substituted downstream program. +21. **Every swap rule carries a price floor relative to its input, a slippage ceiling, and a zero fee** — a ratio floor (or an exact input plus a floor), an at-most pin on slippage, an equal-zero pin on every fee field. A static floor on the output alone is beaten by raising the input. The grant screen states the floor as a price and the regrant cadence it implies (chapter 9, item 30). +22. **The destination account and its token accounts are derived by tooling from the wallet's address and the gateway program, and the gateway program is taken from the chain registry — never from user input.** The value-holding list is the destination account plus its token account for the asset and for every output token the permission allows. A pasted key puts every pin under a typo's control. +23. **Output token accounts exist before the agent needs them.** The gateway creates only the bridged token's account. Others are created off-band, or by allowing the associated-token program's idempotent create instruction in one exact shape — fixed account count, the owner position pinned to the destination account and the mint position pinned to one allowed output token, one rule per token. Never as an instruction-less rule, which would match the program's other instructions too. +--- +# 11 · Open questions, and what must not be "fixed" +## 11.1 The two items that gate implementation +These are facts to confirm, not decisions to make. Nothing else in this chapter blocks code — only the executor module's address still gates implementation. +- **RESOLVED — the Ed25519 precompile is no longer used by this system.** A Solana-keyed agent acts through its UEA, which verifies the key itself; the wallet verifies no signature. +- **The executor module's address.** Written in Push's platform code but unconfirmed against a live deployment. Confirm before URP hardcodes its one trusted caller. +## 11.2 Design questions for the team — none blocks v3 +- **Should the contract refuse approval-granting functions outright?** Would close chapter 9, items 9 and 24 — for a native permission, the unpinned-spender form. Today: allow-list-only, owner's responsibility, with the SDK refusing the unpinned form (obligation 16). +- **Should an emergency contact return to the design?** Would close chapter 9, item 2. +- **Should the destination and refund locks also exist at the gateway layer?** Our layer locks both regardless; a second lock would be belt-and-braces. +- **When does "no wallet migration, ever" stop being acceptable?** The recorded revisit trigger for chapter 9, item 20. +## 11.3 With Push core +- **The executor module must call URP on outbound failure.** The one piece of Push-core work the credit-back feature waits on. Not agentic-wallet work. +- **The destination account's own instruction loop is unbounded** in Push's code. Ours is bounded at ten; theirs should be bounded too. +- **The gateway's refund behaviour for the outbound direction** is undocumented in the public revert-handling notes (inbound only). Completeness of our exposure analysis, nothing more. +- **Two admin-only paths can pay an agent-chosen refund destination for funds coming back from a destination account.** Push Chain never issues an automatic refund for an inbound that originates at a destination account, so on every automatic path the agent's choice of refund destination is never used. But the stuck-inbound revert and the rescue path, both of which need an admin action, pay that destination without checking where the inbound came from. The agent cannot trigger either alone. The fix is node-side — for such inbounds, refund to the destination account of the originating Push account, or refuse — and is not URP work. +## 11.4 Conventions and text +- **A UEA agent's payload deadline: 15 minutes recommended.** A convention of the agent's own tooling, not a wallet rule — the wallet sees only the sender. +- **The identity layer's recovery guarantees are not yet enumerated.** They are the only defence against chapter 9, item 1. Not this system's work, but this system's users' exposure. +- **One sentence in the internal rules document still overclaims** that no counter reset exists anywhere; it must be narrowed to "no agent-reachable reset" (chapter 7.1 has the truth). +## 11.5 Do not "fix" these +Sixteen things in this design look like mistakes to a fresh reader. Each is a decision. Every implementation task touching one of these must carry this list. +1. **Gas is never credited back on a failed action** — and no refund path may touch a gas counter. The asymmetry is correct: the gas was consumed. +2. **There is no paymaster and none is planned.** Agents submit their own calls and pay their own gas. Do not add sponsorship. +3. **The empty-recipient pin (gate 11) guards a path the current far-side code does not even read.** It is defence in depth against that code changing. Do not remove it as "dead". On Solana the same field is required and is the target program (S11, S14) — the opposite rule for the same field is correct for each family. +4. **The forbidden-target rule compares against the destination account, and it beats the allow-list.** Not a bug that it overrides the owner's own list — the permanent test demands exactly that. +5. **Widening and narrowing a permission share one path: revoke and regrant.** There is no separate, "safer" narrow-only edit. Do not add one. +6. **The configured destination chain is stored but never compared at validation.** The chain is pinned transitively by the token. The unused field is known and documented (`2_UniversalRulesPolicy.md` §1.6), not forgotten. +7. **The wallet's refusal of itself and the engine as dispatch targets runs after validation, not before.** Placed earlier it would pre-empt the engine's own refusals and change which error surfaces, and the engine-as-target case is only reachable at all through the engine's wildcard, which validation has to resolve first. Two permanent tests pin its position; do not move it. +8. **A native call limit is consumed by a call that sends no value and meters nothing.** Not a metering bug. The universal counter ignores a zero-amount request because it counts bridging; the native call counter counts calls, and a limit zero-value calls could slip past would be advisory. +9. **A value-only native action accepts empty call data and nothing else.** The engine buckets one to three bytes under the same action id; URP refuses them by name. That is what value-only means, not overreach. +10. **URP's kind-specific getters revert on a record of the other kind, and return zeros on an empty slot.** Both halves are deliberate: an empty slot is a state, a wrong-kind read is a caller bug. The mode getter never reverts and is the first call for anything that does not already know the kind. +11. **Eight actions, eight pins, thirty-two allow-list entries are sanity bounds, not gas bounds** — and so are a Solana permission's thirty-two program rules, sixteen account pins, eight data pins and eight value-holding accounts. They cap what a human is asked to approve and audit at once. Raising any of them is a design change, not a tuning. +12. **The gateway program is a forbidden Solana target, although calling it is not a drain.** It returns the permission's asset to the owner's own wallet, and the agent's refund destination is never paid on that path. It stays forbidden because under a one-asset permission it can bring home only leftover input — never what the agent bought — while spending the owner's gas and inbound capacity for nothing. Outputs come home through the owner door. A permanent test refuses it at grant and at validation. +13. **URP refuses a Solana rule with no account pin, though a single pin proves nothing.** One authority pin always passes. The check is hygiene; completeness is the tooling's job (obligation 19). A test deliberately grants a rule with one useless pin and shows URP accepts it, so nobody reads the check as a guarantee. +14. **A Solana permission's value-holding list must contain the destination account.** That is what keeps gate S18 always on. Do not relax it to allow an empty list "for simple permissions" — an empty list switches the defence off silently. Permanent test. +15. **Two Solana rules that could match the same instruction are refused at grant, though first-match would simply pick one.** It would pick the first, and the second rule's pins would never run — an owner would believe they had granted limits that do not exist. +16. **The owner door writes one storage slot — the checkpoint.** That is the only exception to "the owner door touches nothing"; it consults nothing and cannot revert, and a permanent test pins that it touches slot 0 and nothing else. +--- +*End of the architecture document. The decision register holds the checkable form of every ruling above; the phase planning document holds the reasoning. Changes to this document follow the same rule as the system it describes: nothing is edited silently — a change names the ruling it implements.* diff --git a/plan/agw/research/source-refresh-2026-10-07/contracts/push-agentic-wallets/docs/2_UniversalRulesPolicy.md b/plan/agw/research/source-refresh-2026-10-07/contracts/push-agentic-wallets/docs/2_UniversalRulesPolicy.md new file mode 100644 index 00000000..b1909996 --- /dev/null +++ b/plan/agw/research/source-refresh-2026-10-07/contracts/push-agentic-wallets/docs/2_UniversalRulesPolicy.md @@ -0,0 +1,326 @@ +# UniversalRulesPolicy (URP) + +*The rules-policy chapter of the AGW architecture, kept as its own document. References to other chapters point to [`1_AGW.md`](1_AGW.md).* + +# 1 · URP — where the limits live +*URP — the Universal Rules Policy. One contract, three rulebooks: the **universal EVM** rulebook (§1.2–§1.4) descends from a v2 contract that has since been removed from the repository; the line references in those sections point into that removed file and are kept only as provenance for the reviewed logic URP reproduces. The **native** rulebook (§1.2b, §1.4b) and the **universal Solana** rulebook (§1.2c, §1.4c) are referenced by function name into `src/policies/UniversalRulesPolicy.sol`. **The authoritative specification is the contract itself, `src/policies/UniversalRulesPolicy.sol`, together with its test suite.** Every v3 extension to the universal rulebook is marked below.* +## 1.1 Why this contract exists +- The adopted permission engine identifies "what action is this?" by hashing **the target contract and the function being called on Push Chain**. +- But every agent action in this system is the *same* Push-side call: the wallet calling the gateway's send function. A market trade, a lending deposit, a transfer to a thief's address — **identical**, from the engine's point of view. +- The things the user actually cares about — which protocol, which function, whose benefit, how much — live *inside the call's data*, nested two layers deep, where the engine never looks. +- **URP is the contract that looks.** It is registered as the action policy for the one action that exists, and it unwraps the call data and checks everything inside — in the far chain's own format: an EVM instruction list for an EVM chain, a Solana instruction for Solana. Remove URP and the user's real limits are not enforced anywhere. That is why the engine's own floor — **at least one action policy per action** (`SmartSession.sol:285-299`) — combined with URP being that one policy, means the system fails closed: strip URP from a permission and the permission validates nothing at all, so every request dies. +- **For a native permission the blind spot is different, and smaller.** Here the engine's identity — the Push contract and the function — is exactly what the user cares about, so the engine itself already refuses a call to any contract or function the permission did not name. What the engine still cannot see is *how* the function is called: the arguments, the value attached, and how many times. URP's native rulebook checks those three. It is registered as the action policy on **each** of the permission's one to eight actions, and the fail-closed property is identical and per action: strip URP from any action and that action validates nothing. +- **URP decides which rulebook to run from a record it wrote at grant, not from the request.** §1.7 explains how that record is set, and why a request can never reach the wrong rulebook. +- Two wiring rules protect the fail-closed property. **Both are enforced in code, by the wallet's grant-shape check — a grant violating either one reverts:** +\t- **Never configure a fallback action policy** on an agent wallet. The engine supports a wildcard policy that catches unmatched actions; installing one would absorb requests that should die. For a universal permission this follows from the one-action shape; for a native permission the wallet refuses the engine's wildcard target and its two wildcard function markers **by name**, because the engine itself does not refuse the wildcard target at grant time (`1_AGW.md` chapter 7.1). +\t- **Never rely on the engine's other policy class** (checks on the outer operation) for anything mandatory — that class is allowed to be empty (`SmartSession.sol:237-247`). Everything mandatory lives in URP. +## 1.2 What URP stores — a universal permission's configuration (EVM chains) +Frozen at grant, per permission, written at initialisation: +| Field | Meaning | +| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| the tokens | One to eight PRC20s on Push (`assets`, at most `MAX_ASSETS`), each with its own caps and its own spent counter. No token twice. Every request must name one of them, **even at zero amount**: the token is what pins the destination chain — see §1.5. A permission with no token is refused at grant, on every grant path; a permission that should move nothing lists one token (the chain's gas token) with both limits at zero | +| per-action cap, per token | The most that one request may bridge in that token. Zero is legal: the token may route a request but never moves (the move-nothing permission) | +| lifetime cap, per token | The most that all requests together may bridge in that token. The largest representable number means unlimited; zero means nothing may move | +| PC-per-action cap | `maxGasPerCall`: the most native PC one request may carry — it pays the protocol fee and the gas swap, despite the name | +| the spent counters | One per token: the running total bridged in that token. Starts at zero. Money coming back to the wallet never lowers it | +| the expiry | The permission's end. Held **inside URP** so this one contract carries the complete mandatory set — no other policy needs to exist for the user to be safe | +| the destination account address | Computed and committed at grant. Everything must benefit this address | +| the allowed-calls list | Per entry: a far-chain contract address, a function on it, where that function's beneficiary argument sits, whether it has one, and a per-entry native-value cap. One to thirty-two entries | +## 1.2b What URP stores — a native permission's configuration, per action +A native permission holds one of these records **per action** — a permission with eight actions holds eight, each under its own action id. Frozen at grant, written at initialisation: +| Field | Meaning | +| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| the target | A defensive copy of the action's Push contract. The engine already routes by it; URP asserts it again at N4 so a mis-wired engine entry cannot pair one contract's rules with another's call | +| the function | A defensive copy of the action's function selector, asserted at N5. The value `0xFFFFFFFF` means **value-only**: a bare transfer of PC with **empty** call data — a function that merely takes no arguments is a normal four-byte selector, not value-only | +| the argument pins | Zero to eight. Each is a byte position in the call data — counted from byte zero, selector included, so 4 is the first argument — and the exact 32-byte word that must sit there. **Full-word equality**, so an address argument with anything in its upper twelve bytes is a mismatch, deliberately: the pin proves the padding is clean as well as the value | +| per-call value cap | The most native PC one call may carry | +| lifetime value cap | The most all calls together may carry. Largest number means unlimited | +| the value-spent counter | Running total of native PC sent. Starts at zero | +| the metered amount | Optional: on/off, a position in the call data read as a number, a per-call cap and a lifetime cap. Off is a flag, not "position zero" — position zero is a legal position, inside the selector | +| the amount-spent counter | Running total of the metered amount. Starts at zero | +| the call limit | How many successful calls the action permits. **Zero means unlimited** — the one cap in the system where zero is not "nothing" | +| the calls-used counter | Successful calls so far. **Moves on every successful call**, including one that sends no value and meters nothing | +| the expiry | The permission's end, held inside URP for the same reason as in the universal rulebook | +Two refusals happen at grant, not at validation: a native record may never name the gateway as its target, and a value-only record may carry neither pins nor a metered amount — such a record could never authorise anything, so it is a misconfiguration the owner believes they granted, not a valid strict one. +## 1.2c What URP stores — a universal permission's configuration (Solana) +Frozen at grant, per permission, written at initialisation. The first five fields mean exactly what they mean in §1.2; everything after them replaces §1.2's destination account and allowed-calls list: +| Field | Meaning | +| ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| the tokens | One to eight, with per-token caps and counters, exactly as in §1.2. Each pins the destination chain | +| per-action and lifetime caps | In the token's base units — on Solana, lamports or the SPL token's base units | +| PC-per-action cap | The most native gas value one request may carry | +| the spent counters | One per token, as in §1.2 | +| the expiry | The permission's end, held inside URP | +| the destination account | The 32-byte key of the wallet's Solana account, derived by tooling and committed by the owner. Never a valid target | +| the gateway program | The 32-byte id of the gateway program on the declared cluster, from the chain registry. Never a valid target | +| the program rules | One to thirty-two. Per rule: a program, an instruction tag (its leading one to eight bytes) or the marker that the instruction carries no data, and optionally the exact account count the instruction must have | +| the account pins | Up to sixteen. Per pin: which rule, which position in the account list, and the key that must sit there. Every rule must carry at least one, and a position may be pinned only once per rule | +| the data pins | Up to eight. Per pin: which rule, an offset — from the start or from the end of the instruction data — a width of one to eight bytes (up to thirty-two for equality), and a comparison: equal, at least, at most, or a minimum ratio to a second field at its own offset | +| the value-holding accounts | Up to sixteen destination-side accounts the owner declares worth protecting: the destination account itself, which must be present, one token account per listed token and up to seven swap-output accounts. Each may appear in a request only where the matched rule pins it; a listed account no rule pins can never be passed. URP cannot check that every listed token's account is here (it cannot derive Solana token accounts), so tooling must list them. Gas grows with the number listed: about 6,000 per extra account on a ten-account request | +Refusals at grant, each with its own named error: no program rule may name a program the rulebook forbids as a target (§1.4c, gate S15); two rules on one program may not both be able to match the same instruction — an instruction-less rule against another instruction-less rule, or one tag a prefix of the other — so the first-match lookup is always exact; a fixed account count may not exceed the request bound, and no pin may sit beyond it; a data pin may not sit on an instruction-less rule, and its comparison value must be one the field can actually fail — a ceiling above the field's range, a ratio with a zero numerator, or an equality value encoded in the wrong alignment is refused; and the value-holding list may not contain the zero key, a duplicate, or an allow-listed program, and must contain the destination account. + +**One input per instruction.** Because two rules may not match the same instruction, each (program, instruction) has exactly one rule, and each position one pinned key. If a swap rule pins its input to the USDC account, USDT can never be that instruction's input. Using several listed tokens through one instruction means leaving the input position unpinned and those token accounts off the value-holding list, so only the output and price pins protect them. Several tokens in one Solana permission work best when different tokens are used by different instructions. +**And, beside any of the three configurations, the mode record**: whether this permission's URP record exists at all, which kind it is, and — for a universal permission — which destination family. §1.7. +## 1.3 What URP opens +Each validation performs a **two-level unwrap**: +- **Level one — the gateway request.** URP decodes the wallet's call to the gateway: the token, the amount, the native value, the routing fields, and the payload. +- **Level two — the instruction list.** Inside the payload sits the destination account's instruction list: up to **ten** entries of *(target, value, data)*. URP walks **every** entry. One bad entry — even the last — kills the whole request. +- **For Solana, level two is one instruction, not a list.** URP parses the payload in exactly the byte grammar Push Chain's validators decode — a four-byte account count, that many 33-byte account entries, a four-byte data length, the instruction data, an instruction id and the target program — and requires it to be **consumed exactly**: a short field or a trailing byte is refused, so URP and the validators can never read the same bytes two ways. Every length is checked before the read it guards; the parse is bounded at sixty-four accounts and 1,024 bytes of instruction data. Writable flags are read past, never judged — a wrong flag fails on Solana, not here. +- **A native validation opens nothing.** The call is already flat. URP reads 32-byte words out of the call data at the positions the permission froze, and never decodes it as a structure — it does not know, and does not need to know, what the function's arguments mean. Every read is bounds-checked in 256-bit arithmetic, so a crafted position can neither wrap nor read past the end. +## 1.4 The universal gauntlet — every gate, in order (EVM chains) +Run for a universal permission whose destination family is EVM (`_checkUniversal`). Each gate: what it demands, and what it stops. Any failure reverts the whole request with nothing spent. +| # | Gate | Demands | Stops | +| --- | ----------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| 1 | **Configured** | This permission's configuration exists and is initialised (`:141`) | Requests against ghosts — ids never granted on this wallet | +| 2 | **Not expired** | The permission's own end date has not passed — **the expiry lives here, in URP** | Everything, after the deadline the user set. This is why URP alone is the complete mandatory set | +| 3 | **Gateway only** | The Push-side call target is the gateway, nothing else (`:143`) | The agent calling any Push contract directly — a token, the wallet, anything. The entire far-chain rulebook below is only sound because *everything* must pass through the gateway | +| 4 | **Send function only** | The gateway function is the outbound send, nothing else (`:145-147`) | Reaching any other gateway capability | +| 5 | **A listed token** | The bridged token is one of the permission's tokens — on **every** request, zero amount included | Spending any asset the user did not budget, and — because the gateway routes by the token — sending the permission's calls to a chain the user never approved | +| 6 | **Per-action cap** | Amount within **that token's** per-action cap | One oversized request | +| 7 | **Lifetime cap** | Amount plus everything already spent **in that token** within that token's lifetime cap | Death by a thousand cuts — many small requests. One token running out never limits another | +| 8 | **Gas-value cap** | Native PC attached within its cap (`:177`) | Draining the wallet's gas balance through the value field | +| 9 | **No uncapped gas swap** | The request's own gas-swap ceiling is non-zero *(v3 addition)* | An agent authoring the field's "no cap" value. The **owner** may set unlimited caps in the rules set; an **agent** may not author an unlimited request field | +| 10 | **Refunds come home** | The refund destination is the wallet itself (`:178-180`) | A "failed" transfer whose refund lands at the agent's address — failure as an exfiltration route | +| 11 | **No side recipient** | The bridged-funds recipient field is empty — funds may only travel with the instruction payload *(v3 addition)* | Any use of the gateway's direct-transfer mode. Defence in depth: the current far-side code ignores this field on the payload path, but URP does not lean on that staying true | +| 12 | **Instruction list only** | The payload is exactly a destination-account instruction list | Smuggling any other payload shape past the gates below | +| 13 | **At most ten** | Between one and ten instructions *(v3 constant)* | Unbounded lists that could exhaust validation gas | +| 14 | **No loopbacks** | No instruction may target the wallet, URP itself, the gateway — **or the destination account** (`:253-255`; the last is a v3 addition). **Checked before gate 15** | Self-calls and re-entry tricks; and — the v3 addition — the agent instructing the user's own account directly, which would hand it arbitrary control of everything that account holds. **This gate wins even if the owner allow-listed that address** — a permanent test pins exactly that | +| 15 | **The allow-list, and for the user only** | Every instruction's far-chain target *and* function appear in the allowed-calls list; and where the matched rule names a beneficiary argument, that argument equals the destination account (`:264-265`) | Everything. This is the only place in the entire system that checks the far-chain destination — and the beneficiary pin is what stops the agent trading honestly but making *itself* the beneficiary | +| 16 | **Per-entry value cap** | Each instruction's native value within its own cap | Value-draining through individual entries | + +> **There is no zero-amount gate.** v2 rejected a bridged amount of zero; v3 permits it, because that is the *redeployment* path — instructions travelling to capital already at the destination, with nothing new bridged. The counter correctly does not move. Without it an agent could buy but never sell. + +After every gate passes, URP **records the spend before the bridge is called** — effects first, so no ordering trick can spend twice against a stale counter. +## 1.4b The native gates — every gate, in order +Run only for a native permission (`_checkNative`). The same discipline as the universal gauntlet, for the same reason: this runs before the engine consults the session validator, on call data the engine has not yet authenticated. The wallet has already checked that the caller is the permission's agent, but URP does not rely on that. No external calls; every counter written last; any failure reverts the whole request with nothing spent. +| # | Gate | Demands | Stops | +| --- | ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| N1 | **Configured** | This action's native record exists and is initialised | Requests against ghosts — action ids never granted on this wallet | +| N2 | **Not expired** | The permission's end date has not passed — the expiry lives here, as in the universal rulebook | Everything, after the deadline the user set | +| N3 | **Never the gateway** | The call's target is not the gateway | The mirror of gate 3. A native permission cannot be written against the gateway (§1.2b), so on a permission the wallet created this cannot fire — it is defence in depth against a mis-wired grant, and a named test manufactures the state the wallet forbids to prove the gate is live | +| N4 | **The named contract** | The call's target equals the record's own copy of the target | A record reached through any action id but its own | +| N5 | **The named function** | The call's function equals the record's copy. Call data under four bytes counts as value-only — matching how the engine itself buckets short calls — and **a value-only call must carry empty call data, not one to three stray bytes** | Reaching any function but the one granted; and smuggling bytes under a value-only action | +| N6 | **Value caps** | Native PC attached within the per-call cap; attached plus everything already sent within the lifetime cap | Draining the wallet's PC through one large or many small calls | +| N7 | **The argument pins** | For every pin: the call data is long enough to hold the word at that position, and the word there equals the frozen value exactly | A beneficiary that is not the wallet; a spender that is not the intended contract; a pool id the owner did not choose; a correct address with dirty padding. **This is the only place a native call's arguments are checked**, and a missing pin is an unchecked argument (`1_AGW.md` chapter 9) | +| N8 | **The metered amount** | If the action meters an amount: the call data reaches it, the amount is within the per-call cap, and amount plus everything already metered is within the lifetime cap | Staking, approving, transferring or depositing more than the user allowed, per call or over the permission's life | +| N9 | **The call limit** | If the action has a limit: calls used so far are below it | The (n+1)th call — including a zero-value one, because every successful call counts | +After every gate passes, URP writes all three counters — value, amount, calls — **and only then**, so a request that fails at N9 has moved nothing at N6 or N8. It emits a metering event on every success, even when both value and amount are zero, because the call counter still moved. +**Every native error puts the value you debug with first.** The engine truncates a policy's revert data to 32 bytes — a selector plus 28 bytes of the first argument (`1_AGW.md` chapter 7.1). A native error therefore leads with the offending value (the word that did not match, the amount that was too large) rather than an index or a length, which would surface as zeros and tell nobody anything. The universal rulebook's errors predate this ordering and keep their reviewed shape; wallet errors are not truncated at all and do not follow it. +## 1.4c The Solana gauntlet — every gate, in order +Run for a universal permission whose destination family is Solana (`_checkSvm`). The same discipline as the other two: no external calls, the spend written last, any failure reverts the whole request with nothing spent. **Gates S1–S10 are gates 1–10 of §1.4, unchanged in meaning** — configured, not expired, gateway only, send function only, a listed token, the per-action cap, the lifetime cap, the gas-value cap, no uncapped gas swap, refunds come home — run against the Solana configuration. They do not depend on the far chain. From S11 on, the gates replace §1.4's 11–16: +| # | Gate | Demands | Stops | +| --- | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| S6b | **Fits Solana's amount** | The bridged amount fits in 64 bits — Solana's amount type | An amount the far side would truncate. Runs beside S6 | +| S11 | **Recipient is a program** | The recipient field is exactly 32 bytes and not zero | The inverse of gate 11: on Solana the recipient is required, and is the program to call. An address in any other form — including a base58 string — fails closed | +| S12 | **One well-formed instruction** | The payload is non-empty and parses exactly in the validators' grammar (§1.3) — no short field, no trailing byte | A funds-only outbound, and any payload URP and the validators could read differently | +| S13 | **Execute only, within bounds** | The instruction id is *execute*; at most sixty-four accounts and 1,024 bytes of instruction data | The *withdraw* form, which no rule below can inspect — the Solana counterpart of gate 12 — and unbounded parsing | +| S14 | **Recipient and target agree** | The program named in the payload equals the recipient field | An ambiguity in the far-side path: the validators sign over one and build the transaction from the other. Two different values fail on Solana at the owner's gas cost; URP refuses the shape instead | +| S15 | **Never a forbidden program** | The target is not the System program, SPL Token, Token-2022, Stake, the upgradeable BPF loader, the address lookup table program, **the gateway program, or the destination account**. **Checked before S16** | Direct drains: each of these, called with the destination account as signer, can move or burn what it holds. The gateway program routes funds back to Push and is refused for the reason in 11.5. **This gate wins even if the owner allow-listed the program** — grant refuses it too, and a permanent test pins both | +| S16 | **The allow-list — exact match** | The (program, instruction tag) matches a rule; an instruction-less rule matches only empty instruction data; and if the rule fixes an account count, the request has exactly that many | Every program and instruction the owner did not name. Because grant forbids two rules that could match the same instruction, the first match is the only match — a rule can never be reached by an instruction its pins were not written for | +| S17 | **Account pins and data pins** | Every account pin of the matched rule: the position exists and holds the frozen key. Every data pin: the instruction data reaches the field, and the field equals, meets the floor, stays under the ceiling, or meets the ratio | A destination that is not the user's token account, an authority that is not the destination account; a non-zero fee, an over-wide slippage, a price floor not met. **The ratio form is what a swap needs**: a static floor on the output is beaten by raising the input to the whole balance | +| S18 | **Value-holding accounts only where pinned** | Any account on the permission's value-holding list that appears anywhere in the account list sits at a position the matched rule pins | Handing the program the destination account's *other* balances as extra accounts. On Solana the destination account signs the whole call, so an account passed is an account the program may spend from. The list must contain the destination account, so this gate is never off | +> **There is no zero-amount gate here either.** A zero-amount request is the Solana counterpart of the redeployment path — one instruction acting on capital already at the destination — and the counter does not move. + +After every gate passes, URP **records the spend** — the same counter discipline as §1.4. +## 1.5 What URP counts +- **The spent counters** — one per listed token — advance by the bridged amount, before dispatch, and only count bridging — `1_AGW.md` chapter 4.2's "bridged, not deployed" rule lives here. **They count what was sent out, never what came back**: URP cannot see money arriving at the wallet, and could not tell an agent's return from the owner's top-up, so a limit of 1000 with 600 sent and 300 returned leaves 400. Everything in this section applies to EVM and Solana alike. +- **The credit-back** *(v3 addition — designed, not yet functional)*: when a far-side execution fails and Push Chain's executor module reports it, URP reduces the named token's spent counter by the failed amount (the module passes the token; a credit can never touch another token's counter). Three properties bound this path: +\t- **module-only** — a single fixed caller, Push Chain's own executor module, may invoke it; the agent cannot fabricate a failure; +\t- **idempotent** — each failed cross-chain transaction id credits at most once; a second credit for the same id reverts (a named test); +\t- **saturating** — the counter never goes below zero. +\t- One honest limit: URP cannot verify the *amount* the module hands it; it trusts Push core. Idempotency and saturation bound the damage of a wrong amount. This is an accepted limit (`1_AGW.md` chapter 9). +- **Gas is never credited.** A failed action's gas was genuinely consumed. **A refund credit must not move any gas counter** — a permanent rule with its own test. +- **A native action counts three things**, all written after every gate passes: native value sent, the metered amount if the action has one, and calls. There is no credit-back and nothing to credit: a native call either succeeds or reverts inside one Push transaction, and a revert unwinds every counter with it. The credit-back path refuses to run against a native record. +## 1.6 What URP deliberately does not do +- **No expiry-distance ceiling.** It rejects the expired; it never rejects the distant-future. The user's chosen horizon is respected as given. +- **No deny-list.** Nothing rejects a function by name. If an owner allow-lists a token-approval function, that is permitted — and hands the agent spending power outside every cap. The product must warn; the contract will not refuse. Gate S15's forbidden programs are the Solana form of gate 14's loopbacks, not an exception: on Solana the token programs *are* the destination account's balances, so calling them directly with its signature is instructing that account directly. (An open question records whether this should change — `1_AGW.md` chapter 11.) +- **No direct destination-chain check.** The configured chain is stored but not compared at validation. The chain is pinned *transitively*: the one allowed token is a Push-side mirror specific to one origin chain, so fixing the token fixes the chain. A builder who notices the stored-but-unchecked field has found a known fact, not a bug. +- **No opinion about the owner.** URP runs only on the agent door. The owner's door never meets it. +- **No verification of Solana keys.** The destination account, its token accounts and the gateway program are 32-byte keys the owner commits; URP cannot run Solana's address derivation and does not try. A wrong key fails closed — the pins never match. +- **No bound on what an allow-listed Solana program does inside its own call.** Account pins bound *where value is delivered*; they cannot bound what a program the owner allow-listed takes from the accounts it is handed, because the destination account's signature carries into every call that program makes. The forbidden set guards the top-level target only. S18, the data pins and the fixed account count narrow this; the rest is trust in the allow-listed program's code — the same trust an EVM allow-list already expresses (`1_AGW.md` chapter 9). +- **No reading of Solana writable flags.** A pinned account passed read-only fails on Solana, not here. +- **No understanding of native calls.** The native rulebook compares words at positions; it does not know what a function does. A pinned argument is locked; an unpinned one is the agent's to choose. So allow-listing a token approval without pinning its spender hands the agent that approval — the native form of the no-deny-list rule. The SDK refuses to emit an unpinned approval (`1_AGW.md` chapter 10); the contract will not. +## 1.7 Which rulebook — how the kind is fixed, and locked three ways +- **The chain travels inside URP's initialisation data, and the kind is derived from it.** The engine passes each policy an opaque blob at grant; URP's blob is a chain identifier followed by the configuration body. URP hashes the chain, compares it to this chain's own identifier — computed from the chain id, never configured — and derives the kind exactly as the wallet did, from the same bytes. An empty chain produces a named error; a blob in any other shape reverts rather than mis-decoding. +- **For a universal permission URP derives one more thing: the destination family.** It reads the chain's namespace — the first seven bytes, `eip155:` or `solana:` — and chooses the EVM or the Solana configuration body and rulebook accordingly. Any other namespace is refused at grant with a named error, so a permission for a chain URP has no rulebook for can never be granted and then fail every request. The kind still comes from the full chain hash; the family is a second, narrower classification inside the universal kind, and URP never asks it of a native chain. The wallet does not derive the family at all: both universal families look identical to it — one action, the gateway's send. +- **URP writes a mode record beside the configuration** — initialised, which kind, and for a universal permission which destination family — and consults that record on every validation. It does not infer the kind from the data's shape, and it does not trust the request. Universal is the record's zero value, so an *empty* record cannot be told from a universal one by its kind field alone; the initialised flag is what is authoritative, and the mode field is meaningless without it. EVM is likewise the family's zero value, so a universal record whose family was never written is an EVM one — which is what every such record is. +- **A permission initialised as one kind can never be re-initialised as the other, or as itself.** The re-initialisation refusal reads the mode record and, beneath it, the universal configuration — so a universal configuration written before its mode record existed is still recognised, and is still protected. URP is upgradeable behind a proxy and its storage is append-only: the universal configuration, the credit-back set, the mode record, the native configuration and the Solana configuration each hold their own slot, and a later implementation may add state only after them. +- **The wallet and URP cannot disagree about the kind, because neither one authors it.** Both derive it from the same chain string in the same blob, with the same rule. The wallet reads that one field — and only that field, only after it has proven the policy is URP's — to choose which shape rules to apply; it still never inspects the terms, which remain URP's sole business. There is therefore no second author for the two to disagree with, and the grant event now reports a derived fact rather than a claim. +- **Three further layers remain, as defence in depth.** Gate 3 requires a universal request to target the gateway. Gate N3 refuses a native request that does. Native initialisation refuses a gateway target outright. Between them there is no shape in which a gateway call reaches a native record, and none in which a native call reaches a universal one. +- **And for a universal permission the chain is checked against the money** — identically for both families, which is what makes a Solana permission over an EVM chain's asset impossible to grant. At initialisation URP asks the asset which chain it came from — the same view the gateway reads on every outbound to decide where to route — and refuses the grant if it disagrees with the declared chain, or if the asset cannot answer. Because every request then pins that same asset, one check at grant makes the declared chain true for the permission's whole life, with no external call at validation time. +- **The mode is readable.** A getter returns the mode record — kind, family and chain — and never reverts; it is the documented first call for anything that does not already know a permission's kind. The universal EVM, universal Solana and native getters each revert, with the actual kind or family named, when asked about a record of another shape — a wrong-kind read is a caller bug — and each returns an all-zero record for an empty slot, which is a state, not an error. +## Diagram — the full agentic flow, Push Chain to an EVM chain, every gate +```mermaid +flowchart TB + subgraph OFF["Off-chain"] + AG["Agent builds the request\ +and calls the agent door itself"] + end + subgraph PUSH["Push Chain — one transaction"] + DOOR["Wallet: agent door\ +caller must be the permission's agent"] + ENG["Permission engine: look up the permission,\ +run its policies"] + subgraph GAUNTLET["URP — the gauntlet (any failure: revert, nothing spent)"] + G1["1 configured?"] --> G2["2 NOT EXPIRED"] --> G3["3 gateway only"] + G3 --> G4["4 send function only"] --> G5["5 the one token"] --> G6["6 per-action cap"] + G6 --> G7["7 lifetime cap"] --> G8["8 gas-value cap"] --> G9["9 gas-swap field non-zero"] + G9 --> G10["10 refunds come home"] --> G11["11 recipient EMPTY"] --> G12["12 instruction list only"] + G12 --> G13["13 at most ten entries"] + G13 --> G14["14 no loopbacks —\ +not the wallet, not URP, not the gateway,\ +not the destination account · BEFORE the allow-list"] + G14 --> G15["15 the allow-list + beneficiary:\ +target + function every entry,\ +beneficiary = destination account"] + G15 --> G16["16 per-entry value cap"] + end + SIGN["Session validator LAST:\ +the sender is the permission's agent"] + SPEND["URP records the spend\ +(before the bridge)"] + GW["Gateway: pulls the token,\ +emits the cross-chain message"] + end + subgraph FARC["Destination chain"] + DA["Destination account\ +runs each instruction as the user"] + PR["Allowed protocol\ +(the only reachable far-chain code)"] + end + EXE["Push Chain's executor module"] + + AG --> DOOR --> ENG --> G1 + G16 --> SIGN --> SPEND --> GW --> DA --> PR + DA -. "far-side failure: funds return" .-> EXE + EXE -. "credit the spend back\ +(module-only · once per tx id · never below zero)\ +DESIGNED — NOT YET FUNCTIONAL" .-> SPEND +``` +## Diagram — the native flow, every gate +```mermaid +flowchart TB + subgraph OFF["Off-chain"] + AG["Agent builds the request — one flat call —\ +and calls the agent door itself"] + end + subgraph PUSH["Push Chain — one transaction, start to finish"] + DOOR["Wallet: agent door\ +caller must be the permission's agent"] + ENG["Permission engine: identify the action by\ +(contract, function) — an ungranted pair dies here"] + subgraph NGATES["URP — the native gates (any failure: revert, nothing spent)"] + N1["N1 configured?"] --> N2["N2 NOT EXPIRED"] --> N3["N3 never the gateway"] + N3 --> N4["N4 the named contract\ +(record's own copy)"] --> N5["N5 the named function\ +value-only = EMPTY call data"] + N5 --> N6["N6 value caps\ +per call · lifetime"] + N6 --> N7["N7 every argument pin:\ +in bounds · exact 32-byte word"] + N7 --> N8["N8 metered amount:\ +in bounds · per call · lifetime"] + N8 --> N9["N9 call limit\ +(every call counts)"] + end + SIGN["Session validator LAST:\ +the sender is the permission's agent"] + METER["URP writes value · amount · calls\ +(all three, after every gate)"] + GUARD["Wallet refuses the wallet or the engine\ +as target, whatever the verdict"] + NP["The named Push contract\ +called by the WALLET, as itself"] + RES["Position · shares · claim →\ +credited to the wallet. Done."] + end + + AG --> DOOR --> ENG --> N1 + N9 --> SIGN --> METER --> GUARD --> NP --> RES +``` +## Diagram — the Solana flow, every gate +```mermaid +flowchart TB + subgraph OFF["Off-chain"] + AG["Agent builds the request — one Solana instruction —\ +and calls the agent door itself"] + end + subgraph PUSH["Push Chain — one transaction"] + DOOR["Wallet: agent door\ +caller must be the permission's agent"] + ENG["Permission engine: look up the permission,\ +run its policies"] + subgraph SGATES["URP — the Solana gauntlet (any failure: revert, nothing spent)"] + S1["S1–S10 = gates 1–10\ +configured · NOT EXPIRED · gateway · send ·\ +token · caps · gas · refunds home"] --> S6b["S6b amount fits 64 bits"] + S6b --> S11["S11 recipient = a 32-byte program"] --> S12["S12 one instruction,\ +parsed exactly"] + S12 --> S13["S13 execute only · bounded"] --> S14["S14 recipient = target program"] + S14 --> S15["S15 never a forbidden program —\ +system, token, stake, loader, lookup table,\ +gateway program, destination account · BEFORE the allow-list"] + S15 --> S16["S16 the allow-list:\ +(program, tag) exact match · account count"] + S16 --> S17["S17 account pins + data pins\ +(source · destination · authority ·\ +fee · slippage · price floor)"] + S17 --> S18["S18 value-holding accounts\ +only where pinned"] + end + SIGN["Session validator LAST:\ +the sender is the permission's agent"] + SPEND["URP records the spend"] + GW["Gateway: pulls the token,\ +emits the cross-chain message"] + end + subgraph SOL["Solana"] + DA["Destination account\ +(gateway PDA of the wallet) receives the funds"] + PR["The one allow-listed program,\ +called with the destination account signing"] + end + EXE["Push Chain's executor module"] + + AG --> DOOR --> ENG --> S1 + S18 --> SIGN --> SPEND --> GW --> DA --> PR + DA -. "far-side failure: funds return" .-> EXE + EXE -. "credit the spend back\ +DESIGNED — NOT YET FUNCTIONAL" .-> SPEND +``` +## Diagram — when things fail +```mermaid +flowchart TB + REQ["Agent request submitted"] + V{"Validation on Push Chain\ +(the agent check, gates 1–16, S1–S18 or N1–N9,\ +expiry, the session validator)"} + REV["Whole transaction reverts.\ +Nothing bridged, nothing spent,\ +counters unwound.\ +The agent paid gas — nothing else happened."] + OK["Dispatched through the gateway.\ +Spend recorded. Token bridged."] + NOK["Native: the Push contract was called.\ +Value · amount · calls recorded.\ +Complete — nothing in flight, nothing to credit."] + F{"Far-chain execution"} + DONE["Instructions ran as the user's account.\ +Proceeds sit in the user's destination account\ +(on Solana, its pinned token accounts)."] + FAIL["Far side failed.\ +Funds return via Push infrastructure."] + CREDIT["Executor module reports the failure to URP →\ +spent counter credited back.\ +DESIGNED — NOT YET FUNCTIONAL.\ +Until it lands: counter stays inflated;\ +remedy is revoke + regrant.\ +Gas is never credited — it was consumed."] + + REQ --> V + V -- "any gate fails" --> REV + V -- "all pass · native" --> NOK + V -- "all pass · universal" --> OK --> F + F -- "succeeds" --> DONE + F -- "fails" --> FAIL --> CREDIT +``` diff --git a/plan/agw/research/source-refresh-2026-10-07/contracts/push-agentic-wallets/docs/3_Universal_Flow.md b/plan/agw/research/source-refresh-2026-10-07/contracts/push-agentic-wallets/docs/3_Universal_Flow.md new file mode 100644 index 00000000..652d5b79 --- /dev/null +++ b/plan/agw/research/source-refresh-2026-10-07/contracts/push-agentic-wallets/docs/3_Universal_Flow.md @@ -0,0 +1,394 @@ +# Bob Lends 100 USDC — End-to-End Flow on Push Chain (Architecture v3) + +**Assumes:** the v3 contract set is live — `AGWFactory` + `AGW` + `SmartSession` (adopted) + `URP` + `AgentValidator`. + +**Bob's intent:** *"Find the best-yielding stablecoin lending vault and deploy 100 USDC into it."* + +> **This is one of the two agentic workflows v3 supports — the UNIVERSAL one.** Bob's agent acts on a *far* chain, through Push Chain's gateway, under a `UNIVERSAL` rules set. The other workflow — the agent acting on *Push Chain itself*, under a `NATIVE` rules set, with no gateway and no far side — is walked in `4_Native_Flow.md`. The wallet, the engine, URP and the validator are the same contracts in both; what differs is the kind of rules set Bob grants, which of URP's rulebooks runs, and where the money ends up. Both kinds may live on one wallet at once. +> +> **Bob's far chain here is an EVM chain.** A universal rules set for Solana walks the same seven stages through the same contracts; what changes is inside URP. The `solana:` namespace selects URP's Solana rulebook instead of the EVM one, the payload is a single program instruction instead of an instruction list, and account and data pins take the place of beneficiary offsets. `2_UniversalRulesPolicy.md` §1.2c and §1.4c walk it gate by gate. + +> **⚠ THIS DOCUMENT IS v3. It supersedes every earlier flow description.** +> If anything you read elsewhere in this repo contradicts this file, this file wins. In particular: **there is no OutboundExecutor module, no wallet-level "provider" slot, no guardian, no pause on any wallet, and no in-place editing of a granted permission.** *(The factory alone has a pause, and it only blocks new wallet creation.)* The companion document `1_AGW.md` carries the full reasoning. + +--- + +## Cast + +| Handle | What it is | Where | +| --- | --- | --- | +| `0xbob` | Bob's EOA — holds USDC | Ethereum | +| `0xbobuea` | Bob's Universal Executor Account — his identity | Push Chain | +| `0xbobagw` | Bob's **agent wallet** — holds the budgeted funds, owned by `0xbobuea`. **One of several Bob may own** | Push Chain | +| `0xbobagwcea` | `0xbobagw`'s Chain Executor Account — the execution hand | Ethereum | +| `0xagent` | The agent's **Push address** — its own EOA, or the UEA of an external key (EVM, Solana, …). It calls the agent door itself | Push Chain | +| `AGWFactory` | Deploys agent wallets at predictable addresses; the registry of record | Push Chain | +| `SmartSession` | The adopted permission engine — the wallet's only installed module | Push Chain | +| `URP` | Universal Rules Policy — **the only contract that inspects what the agent really does on the far chain.** Its universal EVM rulebook runs here; its Solana rulebook is in `2_UniversalRulesPolicy.md` §1.4c, its native rulebook is the other document's subject | Push Chain | +| `AgentValidator` | Stateless sender validator — confirms the sender is the agent. **Never installed** — named inside each permission | Push Chain | +| `UniversalGatewayPC` | The frozen outbound gateway — the only thing a **universal** agent action may call, and the one thing a native action never may | Push Chain | + +All of Bob's addresses are **deterministic and computable before anything is deployed.** + +**Not in v3, and deliberately absent from this flow:** any executor module (module type 2 is refused by the wallet), any hook or fallback module, any job/escrow/evaluator layer, any fee split. Those are separate product concerns with no contract in the v3 set. + +--- + +## STAGE 1 — Intent capture *(off-chain, zero transactions)* + +- Bob types his intent. The tooling resolves `0xbobuea`, and — critically — **asks Bob a v3-specific question**: + + > *"Put this in a **new** agent wallet, or add it as another rules set on an **existing** one?"* + + A new wallet is a new blast-radius boundary and a new account on every external chain. An extra rules set on an existing wallet shares the pool and the accounts. **This choice is Bob's, and it exists only in v3** (Rule 1). + +- The tooling also settles the rules set's **kind** from the intent, and it is not a question Bob is asked: the vaults are on Ethereum, so this is a `UNIVERSAL` rules set — gateway, bridge, destination account. Had the vault been on Push Chain, it would be `NATIVE`, and the rest of this document would read as the other one does. + +- Bob chooses a new wallet. The tooling derives `0xbobagw` from `(owner, index)` via `AGWFactory.predictWallet`, then derives `0xbobagwcea` from it — **before either exists**. +- The tooling composes the rules set. Every line below becomes an on-chain policy parameter inside URP: + + | | | + | --- | --- | + | Capital | 100 USDC into a wallet only Bob can withdraw from | + | Agent may call | `supply()` on Aave v3 / Morpho Blue / Spark — Ethereum only | + | Ceiling | 100 USDC lifetime, 100 USDC per action | + | Gas ceiling | a bounded amount of PC per action | + | Expires | 60 minutes — **an explicit, non-zero value**; URP rejects a zero or past expiry at grant | + | Beneficiary | forced to `0xbobagwcea` — derived, never typed | + | Revoke | instantly, one signature, unblockable | + +- **Argument offsets are generated from each protocol's ABI by tooling, never hand-typed** — a wrong offset silently disarms the beneficiary check. +- The tooling calls `AgentValidator.validateConfig` on the agent config, and shows Bob the resolved `0xbobagwcea` and whether it is deployed yet. +- Bob reviews and approves. **This is the last human decision point.** + +--- + +## STAGE 2 — One signature on Ethereum + +**💰 FUND MOVEMENT #1 — USDC leaves Bob's wallet** + +- Bob signs a single EIP-712 payload in his own wallet. +- `UniversalGateway.sendUniversalTx()` on Ethereum locks **100 USDC** into the Vault, takes a small extra amount auto-swapped to $PC for gas, and carries the Push Chain payload. + +``` +0xbob ──100 USDC──▶ UniversalGateway (Ethereum) [LOCKED] +``` + +- **Bob needs no $PC, never visits Push Chain, and signs exactly once.** + +--- + +## STAGE 3 — Inbound: identity, wallet, rules set — one atomic multicall + +- Universal Validators observe the Ethereum event → ballot reaches quorum → `x/uexecutor` dispatches: + - `UEAFactory.deployUEA()` → **`0xbobuea` created** (first time only) + - gas auto-swapped to $PC, UEA credited + - **100 pUSDC minted to `0xbobuea`** + - `0xbobuea.executeUniversalTx(payload, sig)` → signature verified → multicall runs + +**💰 FUND MOVEMENT #2 — 100 USDC arrives as 100 pUSDC** + +### The multicall, step by step + +| # | Call | Effect | +| --- | --- | --- | +| 1 | `AGWFactory.deployWallet("lending")` | **`0xbobagw` deployed** at the predicted address; owner = `0xbobuea`, baked into bytecode. **Inside the same call the factory invokes `initializeAccount()`, which installs SmartSession** — atomic, no uninitialised state | +| 2 | `0xbobagw.grantRules(session)` | 🔑 **RULES GRANTED** — see below | +| 3 | `pUSDC.transfer(0xbobagw, 100e6)` | 💰 funds → the agent wallet | +| 4 | `PC.transfer(0xbobagw, …)` | ⛽ the wallet needs its own PC — it pays for the outbound gas swap | + +**There is no `installModule(2, OutboundExecutor)` step.** v3 supports **module type 1 only**. The wallet calls the gateway itself; nothing else is installed, ever. + +### 🔑 The rules set grant (step 2) in detail + +`grantRules` takes **one argument**. Nobody tells it what kind of rules set this is: it reads the **chain** the policy envelope declares, and derives the kind from that. Sepolia is not Push, so this is a `UNIVERSAL` rules set — one that leaves the chain through the gateway. URP then reads the namespace: `eip155:` means an EVM destination and URP's EVM rulebook (`solana:` would select its Solana rulebook). The wallet makes no such distinction; to it, both are the same one-action gateway rules set. + +It then does exactly three things: it **overwrites the salt** with the wallet's own monotonic `grantNonce`, it **enforces the canonical session shape** for the derived kind, and it **asserts that kind against the action** — under `UNIVERSAL`, exactly one action, and it must be the gateway's outbound send. A wrong policy, an extra action or a stray user-op policy reverts `MalformedSessionShape`; a target that is wrong *for the kind* — anything but the gateway here — reverts `RulesTypeMismatch(UNIVERSAL, 0, target)`, naming what was tried. + +**Why the chain and not a flag.** Bob is choosing a chain, a contract, some functions and a budget. The kind of rules set that implies is a *consequence*, not a fifth decision — so the system computes it rather than asking. It used to be declared twice, once to the wallet and once inside the policy data, with nothing comparing the two at grant; a mismatch produced a rules set that looked granted, described itself wrongly in its own event, and died at first use. + +``` +sessionValidator = AgentValidator +sessionValidatorInitData = abi.encode(0xagent) ← the agent's Push address +salt = bytes32(grantNonce++) ← WALLET-SUPPLIED, never the caller's + +userOpPolicies: [ ] ← ALWAYS EMPTY (that class has a floor of zero) +erc7739Policies: [ ] ← ALWAYS EMPTY +permitERC4337Paymaster: false ← ALWAYS FALSE + +actions: [ EXACTLY ONE — the UNIVERSAL shape ] + actionTarget = UniversalGatewayPC + actionTargetSelector = sendUniversalTxOutbound.selector + actionPolicies: [ URP AND ONLY URP ] + initData = (version = 1, chainNamespace = "eip155:11155111", body = ↓) ← THE CHAIN. Not Push ⇒ UNIVERSAL; eip155: ⇒ EVM rulebook. + validUntil = now + 60 min ← THE EXPIRY LIVES INSIDE URP + expectedCEA = 0xbobagwcea ← DERIVED at grant, committed forever + assets = [ { token: PRC20_USDC, maxPerCall: 100e6, maxTotal: 100e6 } ] + ← 1..8 tokens; EACH checked AT GRANT against the declared chain + maxGasPerCall = ← PC per outbound: protocol fee + gas swap + allowedCalls = { Aave v3, Morpho Blue, Spark } × { supply } + beneficiary offsets +``` + +**The chain is not just a label — it is checked against the money.** When URP writes this config it asks the asset itself which chain it came from (`PRC20_USDC.SOURCE_CHAIN_NAMESPACE()`, the very view the gateway reads on every outbound to decide where to route) and **refuses the grant** if that disagrees with the declared chain (`ChainMismatch`), or if the asset cannot answer at all (`InvalidAsset`). So Bob cannot accidentally authorise "Sepolia" while funding the rules set with a token bound somewhere else. And because gate 5 pins the token on every request, that one check at grant makes the chain true for the rules set's whole life — with no extra work at execution time. + +**Why URP is the *only* action policy.** The engine requires at least one action policy per action. With URP as the only one, **removing URP leaves zero policies and every request dies**. Add a second policy — a separate time-window policy, say — and that property is gone: stripping URP would leave one policy standing and the request would pass. **This is why the expiry lives inside URP and not in a policy of its own.** + +**The rules set identity.** `permissionId = keccak256(sessionValidator, initData, salt)`. Because the wallet supplies the salt, granting byte-identical terms twice yields two independent rules sets. Because the agent config is in the hash, **the agent cannot be swapped inside a rules set — a different agent is a different rules set** (Rule 4). + +**What the agent can do:** exactly one function, on exactly one Push contract, for one asset, up to two ceilings, into three possible pools, until the expiry, with the beneficiary forced to Bob's own CEA. + +**What it cannot do:** move funds anywhere else · call any other contract · redirect the position · exceed either cap · act after expiry · install or remove modules · call the wallet, URP, the gateway, **or `0xbobagwcea` itself** · touch `0xbobuea` · grant or extend anything · **call anything on Push Chain directly** — that is what a `NATIVE` rules set is for, and this one is not that. + +### State after Stage 3 + +``` +0xbobuea : 0 pUSDC ← identity only, clean +0xbobagw : 100 pUSDC + PC ← owned by 0xbobuea; one rules set live +URP.assets[0].spent : 0 +``` + +**Bob signed once. He has an identity, an agent wallet, a bounded rules set, and zero exposure beyond 100 USDC.** + +--- + +## STAGE 4 — The agent works *(off-chain, no funds move)* + +- The agent's runtime researches yields off-chain → **Morpho Blue USDC vault, 5.2% APY**. +- It composes the request as **four nested layers**, innermost first: + +``` +Layer 4 the far-chain call supply(USDC, 100e6, 0xbobagwcea, 0) +Layer 3 the instruction list Multicall[] — 1 to 10 entries, mandatory envelope +Layer 2 the gateway request token, amount, EMPTY recipient, revertRecipient = 0xbobagw, + non-zero maxPCForGas, payload = layer 3 +Layer 1 the execution payload one single call: target = the gateway, value = PC for far-side gas +``` + +- **It composes instructions; it does not move money.** It signs nothing for the wallet: its authority is being the sender. + +--- + +## STAGE 5 — Execution via the agent door + +**🔑 THE AGENT ACTS — the only time it acts in the entire lifecycle** + +- The agent **cannot** call `UniversalGatewayPC` itself. If it did, `msg.sender` would be the agent, the Vault would derive the *agent's* CEA, and the agent would hold Bob's position. Structurally blocked. +- Instead it calls **Bob's wallet** itself — from `0xagent`, or, for an external key, by driving its UEA, which verifies that key and then calls the wallet. + +> **The caller is the authority.** +> `executeAsAgent` admits only the agent the named rules set records. Anyone else — Bob included — is refused `CallerIsNotAgent` before the engine runs. There is no signature and no relayer: the agent pays the Push gas itself (an EOA from its own PC balance, a UEA through its gas path) — a separate balance from the wallet's. + +``` +0xagent + └─▶ 0xbobagw.executeAsAgent(rulesId, mode, execCalldata) + │ + │ ── THE WALLET DOES THE ENTRYPOINT'S JOBS ITSELF (Push Chain has none) ── + ├─ 1. session engine still installed? ✓ + ├─ 2. msg.sender == agentOf(rulesId)? else CallerIsNotAgent — before the engine runs + ├─ 3. build PackedUserOperation in memory (ABI shape only) + │ sender = address(this) · paymasterAndData = "" · gas fields and nonce zeroed + │ signature = USE ‖ rulesId ‖ msg.sender ← written by the wallet, never supplied + │ + └─▶ SmartSession.validateUserOp + ├─ permission enabled? + ├─ URP.checkAction ── reads the mode record: UNIVERSAL · EVM ── + │ ── the 16-gate gauntlet, in order ── + │ 1 configured · 2 NOT EXPIRED · 3 gateway only · 4 send selector + │ 5 token == USDC · 6 per-call cap · 7 lifetime cap · 8 PC value cap + │ 9 maxPCForGas != 0 · 10 revertRecipient == wallet · 11 recipient EMPTY + │ 12 multicall envelope · 13 1..10 entries + │ per entry: 14 not wallet/URP/gateway/CEA ← beats the allow-list + │ 15 (target, selector) allow-listed + beneficiary == 0xbobagwcea + │ 16 per-entry value cap + │ EFFECTS LAST: spent += amount · emit OutboundMetered + │ + └─ AgentValidator.validateSignatureWithData ← LAST, after every policy + the 20 bytes the wallet wrote == the agent stored in the rules set? + │ + ├─ 4. the wallet enforces the verdict itself (authorizer, validAfter/validUntil) + ├─ 5. the wallet refuses itself and the engine as target, whatever the verdict + ├─▶ 6. dispatch THE EXACT VALIDATED BYTES ──▶ UniversalGatewayPC.sendUniversalTxOutbound + │ ▲ + │ msg.sender == 0xbobagw + │ ← decides which CEA executes + └─ 7. emit RulesActionAuthorized(rulesId, 0xagent, keccak256(execCalldata)) +``` + +- **Any single gate failing reverts the whole transaction** — counters, everything. A failed action costs the agent gas and changes nothing else. The agent's runtime is never trusted; URP is the trust boundary. +- **Replay** is the sender's own nonce — the EOA's, or the UEA payload's. The wallet keeps no agent replay state: the same call sent twice is two actions, each checked and metered. +- **Ordering note that looks wrong and is not:** the engine consults the session validator **after** the policies. The wallet has already checked the caller, but every policy, forever, must still be safe against arbitrary calldata the engine has not yet authenticated. URP is safe by construction: no external calls, effects last, revert on every failure. + +### 💰 FUND MOVEMENT #3 — 100 pUSDC burns on Push Chain + +``` +0xbobagw [100 pUSDC] ──BURN──▶ ∅ emit UniversalTxOutbound(sender = 0xbobagw, …) +URP.assets[0].spent: 0 → 100e6 emit OutboundMetered(..., token, amount) ← the correlation record +``` + +--- + +## STAGE 6 — Cross-chain settlement + +- `PostTxProcessing` creates a pending outbound; Universal Validators produce a **DKLS23 threshold signature**; TSS calls `Vault.finalizeUniversalTx(pushAccount = 0xbobagw, …)` on Ethereum. + +### 💰 FUND MOVEMENT #4 — 100 USDC released to the wallet's CEA + +- Vault: `getCEAForPushAccount(0xbobagw)` → not deployed → **deploys `0xbobagwcea`** (first contact) +- Vault: `USDC.safeTransfer(0xbobagwcea, 100e6)` +- Vault: `CEA.executeUniversalTx(..., originCaller = 0xbobagw, payload)` → checks `originCaller == pushAccount` ✓ → runs the instruction list: + +| # | Call | Result | +| --- | --- | --- | +| 1 | `USDC.approve(MORPHO_BLUE, 100e6)` | allowance set | +| 2 | `MORPHO_BLUE.supply(USDC, 100e6, 0xbobagwcea, 0)` | **deposit executed** | + +### 🎯 What Morpho sees + +``` +msg.sender = 0xbobagwcea · onBehalfOf = 0xbobagwcea · shares → 0xbobagwcea +``` + +**The agent appears nowhere.** It never held a cent, never appeared as depositor, and cannot withdraw. + +### If the far side fails + +- Funds return to `0xbobagw` — because URP pinned `revertRecipient` to the wallet, gate 10. +- Push's Universal Executor Module then calls `URP.creditRevert(...)`, which reduces `spent` — **module-only, once per outbound id, saturating**. +- **STATUS: designed and shipped, NOT YET FUNCTIONAL** — the Push-core callback has not landed. Until it does, a failed far leg leaves `spent` inflated and the remedy is revoke-and-regrant. **Gas is never credited back; it was genuinely consumed.** + +--- + +## STAGE 7 — After the action + +### The control chain — transitive, and single-parent at every hop + +``` +0xbobuea ──owns──▶ 0xbobagw ──is pushAccount of──▶ 0xbobagwcea + (identity) (agent wallet) (Ethereum hand) +``` + +- **The UEA cannot command the CEA directly.** To withdraw from Morpho, `0xbobuea` calls `0xbobagw.execute(...)`, which originates an outbound, which the TSS routes to `0xbobagwcea`. Always two hops. +- **The agent cannot withdraw** — `withdraw()` is not in the allow-list, so the owner path is the only exit by construction. +- **The CEA has no independent security.** It is a projection of the agent wallet, not a second line of defence. + +| Actor | Can do | Cannot do | +| --- | --- | --- | +| **`0xbobuea`** (Bob) | anything, unconditionally — withdraw anywhere, revoke, replace a rules set, install/uninstall a validator | — | +| **`0xagent`** | exactly what the rules set permits, until expiry | everything else | +| **Push governance** | — | reach `0xbobagwcea`; the only path in is a TSS outbound originating from `0xbobagw` | + +### The owner's three operations, in full + +- **Withdraw** — `execute([...])`. **There is no `withdraw()` function**; the owner path *is* withdrawal, with no destination restriction and no policy in the path. It must succeed in every degraded state — zero rules sets, engine uninstalled, hostile validator installed. +- **Revoke** — `revokeRules(pid)` (existence-checked, so a typo reverts loudly instead of silently "succeeding") or `revokeAllRules()`. Immediate on Push, unblockable, no callbacks on the path. **One honest limit:** an instruction already dispatched across the bridge still completes. +- **Change a rules set** — **it cannot be edited.** A change is one owner transaction batching: `URP.assertSpent(expected[] — one per token)` → `revokeRules(old)` → `grantRules(new)`. If the agent spent in the composition window, the assertion reverts the whole change. **Counters restart at zero on the new rules set**, and any request for the old id is dead: removal cleared its agent, and the new rules set has a new id. +- **Every one of these advances the wallet's checkpoint counter** — one tick per owner-door call, per grant and per revoked id — so a job's evaluator can tell the owner acted. Agent actions never move it. + +### STAGE 7b — the second action, and why it may carry zero USDC + +- Bob's agent later wants to move the position from Morpho into Aave. **No new USDC is bridged** — the capital is already at `0xbobagwcea`. +- So the outbound carries `amount == 0` with a payload of allow-listed instructions. **v3 permits this**; `spent` does not move, because the lifetime cap counts what is **bridged**, not what is **redeployed**. +- The exposure is bounded elsewhere: the per-call PC ceiling, the requirement that every instruction be allow-listed, and the wallet's own small PC balance. + +--- + +## Fund movement — the whole ledger + +| # | Stage | Movement | Amount | +| --- | --- | --- | --- | +| 1 | 2 | `0xbob` → UniversalGateway (Ethereum) | 100 USDC locked | +| 2 | 3 | mint on Push Chain → `0xbobuea` | 100 pUSDC | +| 3 | 3 | `0xbobuea` → `0xbobagw` | 100 pUSDC + PC for gas | +| 4 | 5 | `0xbobagw` burn | −100 pUSDC | +| 5 | 6 | Ethereum Vault → `0xbobagwcea` | 100 USDC | +| 6 | 6 | `0xbobagwcea` → Morpho Blue | 100 USDC → vault shares | + +**The agent never appears as a holder in any row.** + +--- + +## Diagram + +``` + ┌─────────────────────────────────────────┐ + STAGE 1 intent │ Bob: "best stablecoin yield, 100 USDC" │ + (off-chain) └──────────────────┬──────────────────────┘ + │ NEW wallet or EXISTING? ← v3 choice + │ derive addresses · compose rules set + ▼ + ┌───────────────────┐ + │ Bob approves │ ← last human decision + │ ONE SIGNATURE │ + └─────────┬─────────┘ +═══════ ETHEREUM ═══════════════════════════════════════│═══════════════════════════════ + STAGE 2 ▼ + 0xbob ──────100 USDC──────▶ UniversalGateway ────[LOCKED in Vault] + │ emit UniversalTx +═══════ PUSH CHAIN ═════════════════════│═══════════════════════════════════════════════ + STAGE 3 ▼ + Universal Validators ──vote──▶ quorum ──▶ x/uexecutor + │ + ┌─────────────────────────────────────┘ + ▼ + deploy 0xbobuea + mint 100 pUSDC + credit gas + │ + │ ONE ATOMIC MULTICALL + ├──1─▶ AGWFactory.deployWallet → 0xbobagw (owner baked in) + │ └─ factory calls initializeAccount() → SmartSession installed + │ NO executor module · NO hook · NO fallback + ├──2─▶ 🔑 grantRules(session) — kind DERIVED from the chain, + │ salt from grantNonce, shape enforced + │ URP: expiry · asset · caps · allow-list · expectedCEA + ├──3─▶ 💰 100 pUSDC ──▶ 0xbobagw + └──4─▶ ⛽ PC ──▶ 0xbobagw (pays its own outbound gas swap) + + STAGE 4 agent researches off-chain · composes 4 nested layers + │ + STAGE 5 ▼ + 0xagent calls ──▶ 0xbobagw.executeAsAgent(rulesId, …) + │ + ┌───────────┴────────────────────────┐ + │ WALLET: engine installed · │ + │ caller == the agent · userOp │ + ├────────────────────────────────────┤ + │ URP: 16 gates, fail closed │ + │ gateway only · asset · caps │ + │ recipient EMPTY · refund → wallet │ + │ ≤10 entries · NOT the CEA │ + │ allow-list · beneficiary == CEA │ + ├────────────────────────────────────┤ + │ SENDER CHECKED AGAIN, LAST │ + └───────────┬────────────────────────┘ + ▼ + UniversalGatewayPC.sendUniversalTxOutbound + 💰 BURN 100 pUSDC (msg.sender = 0xbobagw) + │ + Universal Validators ──▶ DKLS23 TSS signature +═══════ ETHEREUM ═══════════════│═══════════════════════════════════════════════════════ + STAGE 6 ▼ + Vault.finalizeUniversalTx(pushAccount = 0xbobagw) + ├─▶ deploy 0xbobagwcea (first contact) + ├─▶ 💰 100 USDC ──▶ 0xbobagwcea + └─▶ CEA multicall: approve + supply + │ + ┌───────────────▼────────────────┐ + │ MORPHO BLUE │ + │ msg.sender = 0xbobagwcea │ + │ shares → 0xbobagwcea │ + │ the agent appears NOWHERE │ + └────────────────────────────────┘ +``` + +--- + +## The five things to remember + +1. **One signature — and the wallet is Bob's forever.** Identity, wallet, rules set and funding land atomically. The wallet's owner is baked into its bytecode at creation and can never be reassigned. +2. **The agent authorises; it never holds.** It triggers one function under sixteen simultaneous gates. Funds move only from Bob's own accounts, only to Bob's own CEA. +3. **The caller is the authority.** `executeAsAgent` admits only the agent the rules set names; an external key acts through its UEA, which verifies the key. There is no bearer request and no relayer. +4. **`msg.sender` at the gateway decides everything.** Because `0xbobagw` originates the outbound, the CEA is Bob's — so Morpho credits Bob. Had the agent originated it, the position would have been the agent's. **That single fact is the design.** +5. **URP is the only contract that can see what the agent is really doing.** To the engine, every universal agent action looks identical — the wallet calling the gateway. Everything Bob actually cares about lives two decode levels down, and URP is what opens it. Remove URP and the rules set enforces nothing. + +--- + +*This document walked the universal workflow. For the same wallet, the same engine and the same URP running a Push-native rules set — no gateway, no bridge, no destination account, the agent's every argument pinned by the owner — read `4_Native_Flow.md`.* diff --git a/plan/agw/research/source-refresh-2026-10-07/contracts/push-agentic-wallets/docs/4_Native_Flow.md b/plan/agw/research/source-refresh-2026-10-07/contracts/push-agentic-wallets/docs/4_Native_Flow.md new file mode 100644 index 00000000..e78da6f1 --- /dev/null +++ b/plan/agw/research/source-refresh-2026-10-07/contracts/push-agentic-wallets/docs/4_Native_Flow.md @@ -0,0 +1,422 @@ +# Bob Stakes 100 USDC on Push Chain — End-to-End Native Flow (Architecture v3) + +**Assumes:** the v3 contract set is live — `AGWFactory` + `AGW` + `SmartSession` (adopted) + `URP` + `AgentValidator`. + +**Bob's intent:** *"Put 100 USDC to work in a Push-native staking vault and let an agent manage the position — stake, claim, compound — without ever holding my keys."* + +> **This is one of the two agentic workflows v3 supports — the PUSH-NATIVE one.** Bob's agent acts on *Push Chain itself*, calling a Push contract directly from Bob's wallet, under a `NATIVE` rules set. There is no gateway, no bridge, no far chain and no destination account anywhere in this document. The other workflow — the agent acting on a *far* chain through the gateway, under a `UNIVERSAL` rules set — is walked in `3_Universal_Flow.md`. The wallet, the engine, URP and the validator are the same contracts in both; what differs is the kind of rules set Bob grants, which of URP's rulebooks runs — native here; for a universal rules set, the EVM or the Solana one, according to the far chain — and where the money ends up. Both kinds may live on one wallet at once. + +> **⚠ THIS DOCUMENT IS v3.** If anything you read elsewhere in this repo contradicts this file, this file wins. In particular: **there is no OutboundExecutor module, no wallet-level "provider" slot, no guardian, no pause on any wallet, and no in-place editing of a granted permission.** The companion document `1_AGW.md` carries the full reasoning. + +--- + +## Cast + +| Handle | What it is | Where | +| --- | --- | --- | +| `0xbob` | Bob's EOA — holds USDC | Ethereum | +| `0xbobuea` | Bob's Universal Executor Account — his identity | Push Chain | +| `0xbobagw` | Bob's **agent wallet** — holds the budgeted funds, owned by `0xbobuea`. **One of several Bob may own** | Push Chain | +| `0xagent` | The agent's **Push address** — its own EOA, or the UEA of an external key (EVM, Solana, …). It calls the agent door itself | Push Chain | +| `0xpushstake` | **The Push-native protocol** — a staking vault on Push Chain. Any contract Bob chooses to name; nothing about it is built, adopted or trusted | Push Chain | +| `pUSDC` | Bob's USDC, as it exists on Push Chain | Push Chain | +| `AGWFactory` | Deploys agent wallets at predictable addresses; the registry of record | Push Chain | +| `SmartSession` | The adopted permission engine — the wallet's only installed module | Push Chain | +| `URP` | Universal Rules Policy — **the only contract that checks how the agent calls a Push contract: which arguments, how much value, how many times.** Its native rulebook runs here | Push Chain | +| `AgentValidator` | Stateless sender validator — confirms the sender is the agent. **Never installed** — named inside each permission | Push Chain | + +**Deliberately absent from this cast, and from every stage below:** `UniversalGatewayPC` and `0xbobagwcea`. A native rules set may never name the gateway — the wallet refuses it at grant and URP refuses it again at validation — and without the gateway there is no outbound, no TSS, no destination account and no far side. **Everything in this document happens on Push Chain, and every agent action is one Push transaction, start to finish.** + +**Not in v3, and deliberately absent from this flow:** any executor module (module type 2 is refused by the wallet), any hook or fallback module, any job/escrow/evaluator layer, any fee split. + +--- + +## STAGE 1 — Intent capture *(off-chain, zero transactions)* + +- Bob types his intent. The tooling resolves `0xbobuea`, and asks Bob the v3 question: + + > *"Put this in a **new** agent wallet, or add it as another rules set on an **existing** one?"* + + A new wallet is a new blast-radius boundary. An extra rules set on an existing wallet shares the pool. **This choice is Bob's** (Rule 1). + +- The tooling also settles the rules set's **kind** from the intent, and it is not a question Bob is asked: the vault is on Push Chain, so this is a `NATIVE` rules set — the wallet calls `0xpushstake` directly, as itself. Had the vault been on Ethereum, it would be `UNIVERSAL`, and the rest of this document would read as the other one does. + +- Bob chooses a new wallet. The tooling derives `0xbobagw` from `(owner, index)` via `AGWFactory.predictWallet` — **before it exists**. There is no second address to derive: a native rules set has no far-chain hand. + +- The tooling composes the rules set. A native rules set is **one to eight actions**, each a `(contract, function)` pair with its own rulebook. Bob's has five: + + | # | Agent may call | Pinned arguments | Caps | Call limit | + | --- | --- | --- | --- | --- | + | 1 | `0xpushstake.stakeFor(beneficiary, amount)` | `beneficiary` **= `0xbobagw`** — forced, never typed | `amount` ≤ 50 pUSDC per call, 60 pUSDC lifetime | unlimited | + | 2 | `0xpushstake.unstake()` | — | — | **2** | + | 3 | `0xpushstake.claim()` | — | — | unlimited | + | 4 | `0xpushstake.depositFor(beneficiary)` *payable* | `beneficiary` **= `0xbobagw`** | ≤ 5 PC per call, 20 PC lifetime | unlimited | + | 5 | a bare PC transfer to `0xpushstake` — **value-only, empty calldata** | — | ≤ 5 PC per call, 20 PC lifetime | unlimited | + + | | | + | --- | --- | + | Capital | 100 pUSDC in a wallet only Bob can withdraw from | + | Expires | 7 days — **an explicit, non-zero value**; URP rejects a zero or past expiry at grant | + | Revoke | instantly, one signature, unblockable | + +- **Argument pins — the position and the exact 32-byte word — are generated from `0xpushstake`'s ABI by tooling, never hand-typed.** A wrong position fails closed (the word will never match); a *missing* pin fails open (that argument is the agent's to choose). Note what is **not** granted: `pUSDC.approve`. Bob approves the vault himself, once, through the owner door in Stage 3. Had the agent needed an approval, the SDK would have insisted on pinning the spender — an unpinned approval is the native form of allow-listing `approve` on the far chain. +- The tooling calls `AgentValidator.validateConfig` on the agent config, and shows Bob the five actions in human terms — contract, function, every pin, every cap, and that **a call limit is consumed by any successful call, even one that moves nothing**. +- Bob reviews and approves. **This is the last human decision point.** + +--- + +## STAGE 2 — One signature on Ethereum + +**💰 FUND MOVEMENT #1 — USDC leaves Bob's wallet** + +- Bob signs a single EIP-712 payload in his own wallet. +- `UniversalGateway.sendUniversalTx()` on Ethereum locks **100 USDC** into the Vault, takes a small extra amount auto-swapped to $PC for gas, and carries the Push Chain payload. + +``` +0xbob ──100 USDC──▶ UniversalGateway (Ethereum) [LOCKED] +``` + +- **Bob needs no $PC, never visits Push Chain, and signs exactly once.** This is the only moment the gateway appears in this document — on the way *in*, funding Bob. The agent will never touch it. + +--- + +## STAGE 3 — Inbound: identity, wallet, rules set, approval — one atomic multicall + +- Universal Validators observe the Ethereum event → ballot reaches quorum → `x/uexecutor` dispatches: + - `UEAFactory.deployUEA()` → **`0xbobuea` created** (first time only) + - gas auto-swapped to $PC, UEA credited + - **100 pUSDC minted to `0xbobuea`** + - `0xbobuea.executeUniversalTx(payload, sig)` → signature verified → multicall runs + +**💰 FUND MOVEMENT #2 — 100 USDC arrives as 100 pUSDC** + +### The multicall, step by step + +| # | Call | Effect | +| --- | --- | --- | +| 1 | `AGWFactory.deployWallet("staking")` | **`0xbobagw` deployed** at the predicted address; owner = `0xbobuea`, baked into bytecode. **Inside the same call the factory invokes `initializeAccount()`, which installs SmartSession** — atomic, no uninitialised state | +| 2 | `0xbobagw.grantRules(session)` | 🔑 **RULES GRANTED** — see below | +| 3 | `pUSDC.transfer(0xbobagw, 100e6)` | 💰 funds → the agent wallet | +| 4 | `PC.transfer(0xbobagw, …)` | ⛽ PC for the two payable actions — the wallet's own value, capped per action by URP | +| 5 | `0xbobagw.execute(pUSDC.approve(0xpushstake, 100e6))` | 🔓 **the owner approves the vault, through the owner door.** No policy in the path — the owner may do anything. The agent was never granted `approve` | + +**There is no `installModule(2, OutboundExecutor)` step.** v3 supports **module type 1 only**. The wallet calls the vault itself; nothing else is installed, ever. + +### 🔑 The rules set grant (step 2) in detail + +`grantRules` takes **one argument**. Nobody tells it what kind of rules set this is: it reads the **chain** each action's policy envelope declares, and derives the kind from that. These actions declare Push's own chain, so this is a `NATIVE` rules set — one that never leaves the chain. + +It then does exactly three things: it **overwrites the salt** with the wallet's own monotonic `grantNonce`, it **enforces the canonical session shape** for the derived kind, and it **asserts that kind against every action** — under `NATIVE`, one to eight actions, none of them the gateway. + +**Every action must name the same chain**, or the grant reverts `InconsistentChain(i)` naming the odd one out. That is what makes a mixed rules set *unrepresentable* rather than merely forbidden: one chain per rules set means one kind per rules set, so there is no shape in which a cross-chain action could hide among Push-side ones. + +``` +sessionValidator = AgentValidator +sessionValidatorInitData = abi.encode(0xagent) ← the agent's Push address +salt = bytes32(grantNonce++) ← WALLET-SUPPLIED, never the caller's + +userOpPolicies: [ ] ← ALWAYS EMPTY (that class has a floor of zero) +erc7739Policies: [ ] ← ALWAYS EMPTY +permitERC4337Paymaster: false ← ALWAYS FALSE + +actions: [ ONE TO EIGHT — the NATIVE shape; five here ] + + [0] actionTarget = 0xpushstake · actionTargetSelector = stakeFor.selector + actionPolicies: [ URP AND ONLY URP ] + initData = (chainNamespace = "eip155:42101", body = ↓) ← THIS chain ⇒ NATIVE + validUntil = now + 7 days ← THE EXPIRY LIVES INSIDE URP, per action + target, selector = 0xpushstake, stakeFor ← defensive copies, asserted again at N4/N5 + pins = [ { offset 4, expected = 0xbobagw } ] ← the beneficiary, FORCED + amount = { on, offset 36, maxPerCall 50e6, maxTotal 60e6 } + maxValuePerCall = 0 · maxValueTotal = 0 ← stakeFor is not payable + maxCalls = 0 ← zero means UNLIMITED + + [1] unstake() — no pins, no amount, maxCalls = 2 + [2] claim() — no pins, no amount, no value, no limit: the strictest shape there is — + only the expiry, and the function may take no arguments at all + [3] depositFor(beneficiary) payable — pin beneficiary = 0xbobagw · 5 PC per call · 20 PC lifetime + [4] VALUE-ONLY — selector 0xFFFFFFFF, meaning EMPTY calldata · 5 PC per call · 20 PC lifetime + (a bare PC transfer; NOT the same as a function with no arguments) +``` + +**What the wallet refuses before the engine ever sees the session.** Every native action's target is checked against seven addresses that would turn the agent into the owner — the zero address, the engine's wildcard marker `address(1)`, **the wallet itself**, **the engine**, URP, the validator, the factory — and any of them reverts `ForbiddenActionTarget`, naming it. The engine's two wildcard function markers revert `ForbiddenActionSelector`. The gateway reverts `RulesTypeMismatch(NATIVE, i, gateway)` — a gateway target is not *forbidden*, it is the wrong kind for the chain these actions declare. The same target under a foreign chain is perfectly grantable; it would simply be a `UNIVERSAL` rules set. The same `(contract, function)` twice reverts `DuplicateAction`. A wrong policy, an extra user-op policy, a wrong validator: `MalformedSessionShape`, exactly as under `UNIVERSAL`. Zero actions or nine: `TooManyActions(n)`. + +**Why URP is the *only* action policy — per action.** The engine requires at least one action policy per action. With URP as the only one on each of the five, **removing URP from any action leaves that action with zero policies and every request against it dies**. The property is per action; a rules set holding eight of them holds it eight times over. + +**What URP refuses at initialisation.** A native config may not name the gateway as its target (the mirror of the wallet's check, one layer down). A value-only config may carry neither pins nor an amount rule — it could never authorise anything, so it is a misconfiguration Bob believes he granted, not a valid strict one. More than eight pins, a zero target, a zero or past expiry: refused, each by name. + +**The rules set identity.** `permissionId = keccak256(sessionValidator, initData, salt)`. Because the wallet supplies the salt, granting byte-identical terms twice yields two independent rules sets. Because the agent config is in the hash, **the agent cannot be swapped inside a rules set — a different agent is a different rules set** (Rule 4). Each of the five actions has its own action id under that one permission id, and its own URP record under that action id. + +**What the agent can do:** five functions, on exactly one Push contract, with the beneficiary forced to Bob's own wallet wherever there is one, up to two amount ceilings and two value ceilings, at most two unstakes, until the expiry. + +**What it cannot do:** call any other contract · call any sixth function · stake for anyone but the wallet · deposit for anyone but the wallet · exceed any cap · unstake a third time · act after expiry · call `approve` at all · install or remove modules · call the wallet, the engine, URP, the validator, the factory, **or the gateway** · touch `0xbobuea` · grant or extend anything. + +### State after Stage 3 + +``` +0xbobuea : 0 pUSDC ← identity only, clean +0xbobagw : 100 pUSDC + PC ← owned by 0xbobuea; one NATIVE rules set live (five actions) +pUSDC : allowance(0xbobagw → 0xpushstake) = 100e6 ← the OWNER's approval, not the agent's +URP.stakeFor: amountSpent 0 · callsUsed 0 (and four more records, all at zero) +``` + +**Bob signed once. He has an identity, an agent wallet, a five-action bounded rules set, and zero exposure beyond 100 pUSDC and the PC he funded.** + +--- + +## STAGE 4 — The agent works *(off-chain, no funds move)* + +- The agent's runtime decides to stake **40 pUSDC** now and keep 60 in reserve. +- It composes the request as **one flat call** — there are no nested layers, no instruction list and no gateway envelope in the native workflow: + +``` +Layer 1 the execution payload mode = single · executionCalldata = (0xpushstake, value 0, stakeFor(0xbobagw, 40e6)) +``` + +- **It composes a call; it does not move money.** It signs nothing for the wallet — exactly as in the universal workflow, its authority is being the sender. + +--- + +## STAGE 5 — Execution via the agent door + +**🔑 THE AGENT ACTS — the only time it acts in the entire lifecycle** + +- The agent **cannot** call `0xpushstake` itself. If it did, `msg.sender` would be the agent, `stakeFor` would pull pUSDC from the *agent's* balance — it has none — and any position would be the agent's. Structurally pointless and structurally blocked. +- Instead it calls **Bob's wallet** itself — from `0xagent`, or, for an external key, by driving its UEA, which verifies that key and then calls the wallet. + +> **The caller is the authority.** +> `executeAsAgent` admits only the agent the named rules set records. Anyone else — Bob included — is refused `CallerIsNotAgent` before the engine runs. There is no signature and no relayer: the agent pays the Push transaction gas itself; the wallet pays only the `value` URP allowed. + +``` +0xagent + └─▶ 0xbobagw.executeAsAgent(rulesId, mode, execCalldata) + │ + │ ── THE WALLET DOES THE ENTRYPOINT'S JOBS ITSELF (Push Chain has none) ── + ├─ 1. session engine still installed? ✓ + ├─ 2. msg.sender == agentOf(rulesId)? else CallerIsNotAgent — before the engine runs + ├─ 3. build PackedUserOperation in memory (ABI shape only) + │ signature = USE ‖ rulesId ‖ msg.sender ← written by the wallet, never supplied + │ + └─▶ SmartSession.validateUserOp + ├─ permission enabled? + ├─ actionId = keccak(0xpushstake, stakeFor) ← THE ENGINE ROUTES BY (contract, function) + │ an ungranted pair dies HERE, before any policy runs + ├─ URP.checkAction ── reads the mode record: NATIVE ── + │ ── the native gates, in order ── + │ N1 configured · N2 NOT EXPIRED · N3 never the gateway + │ N4 target == the record's own copy · N5 selector == the record's copy + │ (under 4 bytes = value-only, and value-only demands EMPTY calldata) + │ N6 value ≤ per-call cap · value + valueSpent ≤ lifetime cap + │ N7 every pin: calldata long enough · word at offset 4 == 0xbobagw, ALL 32 BYTES + │ N8 amount at offset 36 ≤ 50e6 · amount + amountSpent ≤ 60e6 + │ N9 callsUsed < maxCalls (0 = unlimited) + │ EFFECTS LAST: valueSpent · amountSpent += 40e6 · callsUsed += 1 + │ emit NativeCallMetered(id, …, value 0, amount 40e6) + │ + └─ AgentValidator.validateSignatureWithData ← LAST, after every policy + the 20 bytes the wallet wrote == the agent stored in the rules set? + │ + ├─ 4. the wallet enforces the verdict itself (authorizer, validAfter/validUntil) + ├─ 5. the wallet refuses ITSELF and THE ENGINE as target, whatever the verdict + ├─▶ 6. dispatch THE EXACT VALIDATED BYTES ──▶ 0xpushstake.stakeFor(0xbobagw, 40e6) + │ ▲ + │ msg.sender == 0xbobagw + │ ← the vault pulls pUSDC from the WALLET + │ and credits the WALLET + └─ 7. emit RulesActionAuthorized(rulesId, 0xagent, keccak256(execCalldata)) +``` + +- **Any single gate failing reverts the whole transaction** — counters, everything. A failed action costs the agent gas and changes nothing else. The agent's runtime is never trusted; URP is the trust boundary. +- **The engine does half the work here that URP does in the universal flow.** Because the call is flat, its target and function are the engine's own action identity: a request to `0xpushstake.withdrawAll()` or to any other contract never reaches URP at all — it dies at the engine with `NoPoliciesSet`. URP's job is what the engine cannot see: the arguments, the value, the count. +- **Ordering note that looks wrong and is not:** the engine consults the session validator **after** the policies. The wallet has already checked the caller, but URP's native gates still treat the calldata as unauthenticated — so, like the universal gauntlet, they make no external calls, write every counter last, and revert on every failure. Every pin and the metered amount are read straight out of the calldata at a frozen position, bounds-checked in 256-bit arithmetic; nothing is decoded as a structure. +- **Step 5 is the last of four refusals of a self-call.** The wallet and the engine were refused at grant (Stage 3); the engine's own minimum-one-policy floor refuses them a second way; and here the wallet refuses them a fourth time, **after** validation, whatever the engine concluded. This one exists for a session the owner enabled on the engine *directly*, bypassing `grantRules` — a thing the owner door permits. Two permanent tests pin it, one of them reaching the engine as a target through the engine's own wildcard. Do not move it before validation. +- **How a failure surfaces.** The engine re-wraps a policy's revert as `PolicyCheckReverted(bytes32)` and keeps only 32 bytes — the URP error's selector and the first 28 bytes of its first argument. That is why every native error leads with the value you debug with: `ArgPinMismatch(actual, index, expected)` shows you the word that did not match; `NativeAmountExceedsCap(amount, cap)` shows you the amount. + +### 💰 FUND MOVEMENT #3 — 40 pUSDC moves from the wallet into the vault + +``` +0xbobagw [100 pUSDC] ──transferFrom, under the OWNER's approval──▶ 0xpushstake [40 pUSDC, credited to 0xbobagw] +URP.stakeFor: amountSpent 0 → 40e6 · callsUsed 0 → 1 emit NativeCallMetered(...) ← the correlation record +``` + +--- + +## STAGE 6 — There is no Stage 6 + +- In the universal workflow, Stage 6 is cross-chain settlement: validators, a threshold signature, a Vault on the far chain, a destination account deployed on first contact. **None of that exists here.** The agent action was one Push transaction, and it is over. + +| | Universal | Native | +| --- | --- | --- | +| After Stage 5 | a burn, an event, and a pending outbound | **the position exists, credited to the wallet** | +| Something in flight? | yes — bridge latency | **no** | +| A far side that can fail? | yes — funds return, spend credited back (designed, not yet functional) | **no** — the call either succeeded inside the transaction or the whole transaction reverted, counters included | +| Gas on failure | consumed, never credited | consumed by the agent, never credited | +| Revocation window | bridge latency | **zero** — the next request is refused | + +### 🎯 What `0xpushstake` sees + +``` +msg.sender = 0xbobagw · beneficiary = 0xbobagw · stake credited → 0xbobagw +``` + +**The agent appears nowhere.** It never held a cent, never appeared as staker, and cannot unstake to itself — `unstake()` returns funds to `msg.sender`, and `msg.sender` is always the wallet. + +### If the call fails + +- `stakeFor` reverts inside the vault — insufficient allowance, a paused vault, anything — and **the whole wallet transaction reverts with it**: all three counters, the metering event, everything. Nothing to credit back, because nothing was recorded. The agent paid gas; that is the entire consequence. + +--- + +## STAGE 7 — After the action + +### The control chain — one hop shorter than universal + +``` +0xbobuea ──owns──▶ 0xbobagw ──is msg.sender at──▶ 0xpushstake (position credited to 0xbobagw) + (identity) (agent wallet) (the Push-native protocol) +``` + +- **The UEA cannot command the vault directly** — it is not the staker. To unstake, `0xbobuea` calls `0xbobagw.execute(0xpushstake.unstake())` through the owner door, with no policy in the path, and the pUSDC lands back in the wallet. Always one hop, always the wallet. +- **The agent can unstake, twice, to the wallet only** — `unstake()` is granted with a call limit of two, and it pays `msg.sender`, which is the wallet. It cannot redirect the proceeds because there is no argument to redirect. +- **The vault has no idea a rules set exists.** It sees an ordinary contract calling it. All of the enforcement is behind that call, in the wallet, the engine and URP. + +| Actor | Can do | Cannot do | +| --- | --- | --- | +| **`0xbobuea`** (Bob) | anything, unconditionally — unstake, withdraw anywhere, revoke, replace a rules set, install/uninstall a validator | — | +| **`0xagent`** | exactly the five actions, under their pins, caps and limits, until expiry | everything else — including a sixth function on the same contract | +| **`0xpushstake`** | credit and pay whoever calls it | tell the agent from the owner — both arrive as `0xbobagw` | + +### The owner's three operations, in full + +- **Withdraw** — `execute([...])`. **There is no `withdraw()` function**; the owner path *is* withdrawal. `execute(0xpushstake.unstake())` then `execute(pUSDC.transfer(anywhere, …))`, with no destination restriction and no policy in the path. It must succeed in every degraded state — zero rules sets, engine uninstalled, hostile validator installed. +- **Revoke** — `revokeRules(pid)` (existence-checked, so a typo reverts loudly instead of silently "succeeding") or `revokeAllRules()`. Immediate, unblockable, no callbacks on the path. Removing the permission removes all five action records' standing at once. **There is no in-flight window** — a native rules set has nothing in flight. +- **Change a rules set** — **it cannot be edited.** A change is one owner transaction batching: `URP.assertSpent(id, wallet, valueSpent, amountSpent, calls)` → `revokeRules(old)` → `grantRules(new)`. The native assertion names **all three counters** of the action being replaced and every one must match exactly; it refuses to run against a universal record or a ghost, so a stale belief can never pass by reading zeros from the wrong place. If the agent acted in the composition window, the assertion reverts the whole change. **Counters restart at zero on the new rules set**, and any request for the old id is dead: removal cleared its agent, and the new rules set has a new id. +- **Every one of these advances the wallet's checkpoint counter** — one tick per owner-door call, per grant and per revoked id — so a job's evaluator can tell the owner acted. Agent actions never move it. + +### STAGE 7b — the second action, and why it still counts + +- A week on, the agent calls `claim()` to harvest rewards into the wallet. `claim()` takes no arguments, sends no value, meters no amount. It is the strictest native shape: only the expiry stands between the agent and the call. +- **The call counter still moves.** `claim()` has no limit, so it does not matter here — but it would on `unstake()`, whose limit is two: a zero-value, zero-amount `unstake()` consumes one of the two. **Every successful call is a use.** A limit that a zero-value call could slip past would be advisory, and this is the one place the native rulebook deliberately differs from the universal one, whose spend counter ignores a zero-amount request. + +### STAGE 7c — the six requests that fail, and where + +| The agent tries | Dies at | Error, as the agent sees it | +| --- | --- | --- | +| `stakeFor(0xagent, 10e6)` — stake for itself | URP, gate **N7** | `ArgPinMismatch(0xagent…, 0, …)` — the pin is what stops the agent staking to itself | +| `stakeFor(0xbobagw, 25e6)` after 40 already staked | URP, gate **N8** | `TotalNativeAmountExceeded(65e6, 60e6)` — the lifetime amount cap | +| a third `unstake()` | URP, gate **N9** | `CallLimitReached(2, 2)` | +| `0xpushstake.withdrawAll()` — a function Bob never granted | **the engine**, before URP | `NoPoliciesSet(pid)` — no action id, no policy, nothing to run | +| `pUSDC.approve(0xagent, …)` — a contract Bob never granted | **the engine**, before URP | the same | +| `0xbobagw.grantRules(…)` — the wallet itself | **the wallet, at grant** — it was never grantable; and again at dispatch if it were somehow enabled | `ForbiddenActionTarget(0xbobagw)` · `ForbiddenDispatchTarget(0xbobagw)` | + +--- + +## Fund movement — the whole ledger + +| # | Stage | Movement | Amount | +| --- | --- | --- | --- | +| 1 | 2 | `0xbob` → UniversalGateway (Ethereum) | 100 USDC locked | +| 2 | 3 | mint on Push Chain → `0xbobuea` | 100 pUSDC | +| 3 | 3 | `0xbobuea` → `0xbobagw` | 100 pUSDC + PC | +| 4 | 5 | `0xbobagw` → `0xpushstake`, **credited to `0xbobagw`** | 40 pUSDC | +| 5 | 7b | `0xpushstake` → `0xbobagw` | rewards | + +**The agent never appears as a holder in any row. Rows 1–3 are Bob funding himself; rows 4–5 are the wallet moving its own money in and out of a Push contract, on the agent's call, under Bob's pins.** + +--- + +## Diagram + +``` + ┌─────────────────────────────────────────┐ + STAGE 1 intent │ Bob: "stake 100 USDC on Push, agent │ + (off-chain) │ manages the position" │ + └──────────────────┬──────────────────────┘ + │ NEW wallet or EXISTING? ← v3 choice + │ kind = NATIVE (the vault is on Push) + │ derive 0xbobagw · compose 5 actions + pins + ▼ + ┌───────────────────┐ + │ Bob approves │ ← last human decision + │ ONE SIGNATURE │ + └─────────┬─────────┘ +═══════ ETHEREUM ═══════════════════════════════════════│═══════════════════════════════ + STAGE 2 ▼ + 0xbob ──────100 USDC──────▶ UniversalGateway ────[LOCKED in Vault] + │ emit UniversalTx ← the gateway's ONLY appearance +═══════ PUSH CHAIN ═════════════════════│═══════════════════════════════════════════════ + STAGE 3 ▼ + Universal Validators ──vote──▶ quorum ──▶ x/uexecutor + │ + ┌─────────────────────────────────────┘ + ▼ + deploy 0xbobuea + mint 100 pUSDC + credit gas + │ + │ ONE ATOMIC MULTICALL + ├──1─▶ AGWFactory.deployWallet → 0xbobagw (owner baked in) + │ └─ factory calls initializeAccount() → SmartSession installed + ├──2─▶ 🔑 grantRules(session) — NATIVE derived from the chain, + │ salt from grantNonce + │ wallet: 5 actions · none the gateway · none the wallet/engine/URP/… + │ URP: 5 records — expiry · pins · caps · call limits · kind = NATIVE + ├──3─▶ 💰 100 pUSDC ──▶ 0xbobagw + ├──4─▶ ⛽ PC ──▶ 0xbobagw (for the two payable actions) + └──5─▶ 🔓 OWNER DOOR: pUSDC.approve(0xpushstake) ← Bob's, not the agent's + + STAGE 4 agent decides · composes ONE FLAT CALL + │ + STAGE 5 ▼ + 0xagent calls ──▶ 0xbobagw.executeAsAgent(rulesId, …) + │ + ┌───────────┴────────────────────────┐ + │ WALLET: engine installed · │ + │ caller == the agent · userOp │ + ├────────────────────────────────────┤ + │ ENGINE: actionId = (0xpushstake, │ + │ stakeFor) — ungranted pair dies │ + ├────────────────────────────────────┤ + │ URP: mode = NATIVE · 9 gates │ + │ never the gateway · target copy │ + │ selector copy · value caps │ + │ PINS (beneficiary = 0xbobagw) │ + │ amount caps · call limit │ + │ EFFECTS LAST: 3 counters │ + ├────────────────────────────────────┤ + │ SENDER CHECKED AGAIN, LAST │ + ├────────────────────────────────────┤ + │ WALLET: not itself, not the engine │ + └───────────┬────────────────────────┘ + ▼ + 0xpushstake.stakeFor(0xbobagw, 40e6) + 💰 40 pUSDC wallet ──▶ vault (msg.sender = 0xbobagw) + │ + ┌───────────▼────────────────────┐ + │ 0xpushstake │ + │ msg.sender = 0xbobagw │ + │ stake credited → 0xbobagw │ + │ the agent appears NOWHERE │ + └────────────────────────────────┘ + │ + ONE TRANSACTION. DONE. + no bridge · no TSS · no far side · nothing in flight +``` + +--- + +## Both kinds on one wallet + +Bob may hold this native rules set and the universal one from `3_Universal_Flow.md` on the **same** wallet, granted by the same owner, naming the same agent or different ones. They meter in disjoint storage — a native call moves no universal counter, and the reverse — and revoking one leaves the other enabled. The only thing they share is the wallet's balance, which is exactly the blast-radius boundary Bob chose in Stage 1. + +--- + +## The five things to remember + +1. **One signature — and the wallet is Bob's forever.** Identity, wallet, rules set, funding and the owner's approval land atomically. The wallet's owner is baked into its bytecode at creation and can never be reassigned. +2. **The agent authorises; it never holds.** It triggers five named functions on one named contract, under nine simultaneous gates each. Funds move only from Bob's own wallet, only into positions credited to Bob's own wallet. +3. **The caller is the authority.** `executeAsAgent` admits only the agent the rules set names; an external key acts through its UEA, which verifies the key. There is no bearer request and no relayer. +4. **`msg.sender` at the protocol decides everything.** Because `0xbobagw` makes the call, the vault credits `0xbobagw`. Had the agent called the vault, the position would have been the agent's — and it has nothing to stake. **That single fact is the design, one hop shorter than universal.** +5. **The engine sees the door; URP sees what walks through it.** The engine already knows which contract and which function — that is its action identity, and an ungranted pair never reaches URP. What the engine cannot see is *how* the function is called: URP's native rulebook pins the arguments, caps the value and the amount, and counts the calls. Remove URP from an action and that action enforces nothing. + +--- + +*This document walked the Push-native workflow. For the same wallet, the same engine and the same URP running a universal rules set — the gateway, the bridge, the destination account on the far chain, and URP's sixteen-gate gauntlet opening the payload two levels deep — read `3_Universal_Flow.md`.* diff --git a/plan/agw/research/source-refresh-2026-10-07/contracts/push-agentic-wallets/docs/5_SDK_Owner_Integration.md b/plan/agw/research/source-refresh-2026-10-07/contracts/push-agentic-wallets/docs/5_SDK_Owner_Integration.md new file mode 100644 index 00000000..264778d6 --- /dev/null +++ b/plan/agw/research/source-refresh-2026-10-07/contracts/push-agentic-wallets/docs/5_SDK_Owner_Integration.md @@ -0,0 +1,488 @@ +# AGW for the SDK — owner side + +What the SDK needs to create agentic wallets, grant and revoke rules, act as the owner, and read state, against the +**v4 deployment on Donut**. Owner side only: the agent side (`executeAsAgent`, building outbound requests) is out of +scope here. + +Everything below is taken from the deployed contracts (commit `e8db748`). ABIs: use the verified contracts on +[donut.push.network](https://donut.push.network), or the build artifacts in this repo (`out/.sol/.json`). + +--- + +## 1. The contracts the SDK talks to + +| Contract | Address (Donut, chain id `42101`) | What the SDK does with it | +|---|---|---| +| **AGWFactory** (proxy) | `0xaF88D0FD947afAe7bBb8F34e8417DCfc165e1aaF` | Predict, deploy and look up wallets | +| **AGW** (one per user) | address from `predictWallet` | Grant / revoke rules, owner actions, reads | +| **URP** (proxy) | `0x603E7f0aF6e1aAFf46DDfb28b1e99364f8BC59af` | Named inside every rule; read rule terms and spend | +| **SmartSession** (engine) | `0x165A5E6782f39D30B38c7D97e1303e4CB2aD102a` | Read only: list a wallet's rules | +| **AgentValidator** | `0x068EE2388475A98EE1f5a434C58bFF3444fffFe6` | Named inside every rule; never called | +| UniversalGatewayPC (Push core) | `0x00000000000000000000000000000000000000C1` | Named as the target of every cross-chain rule | +| UniversalCore (Push core) | `0x00000000000000000000000000000000000000C0` | Look up a chain's gas token (`gasTokenPRC20ByChainNamespace`) | + +`AGW.SESSION_ENGINE()`, `AGW.RULES_POLICY()`, `AGW.SESSION_VALIDATOR()` and `AGW.UNIVERSAL_GATEWAY_PC()` return the +engine, URP, validator and gateway a wallet expects. Prefer reading them from the wallet over hard-coding. + +## 2. Five terms + +- **Owner**: the Push address that owns a wallet (an EOA, or the UEA of an external key). Fixed at deploy. +- **Wallet (AGW)**: a small contract account. It holds the funds the agent may use; its balance is the hard ceiling. +- **Rule**: what one agent may do from one wallet. Granted by the owner, stored in the engine and URP, immutable once + granted. Identified by a `rulesId` (`bytes32`). +- **Agent**: the Push address a rule names (an EOA, or the UEA of an external key). Never the owner. +- **Checkpoint**: a counter on the wallet that moves on every owner-side action (owner calls, grants, revokes), never + on agent actions. Evaluators compare it before and after a job. + +--- + +## 3. Wallets: predict, fund, deploy + +### Predict + +```solidity +function walletCount(address owner) external view returns (uint256); // also the next index +function predictWallet(address owner, uint256 index) external view returns (address wallet, bool deployed); +``` + +The address depends only on `(owner, index)` and never changes, so it can be shown and **funded before deployment** +(PC and PRC20s sent to it are there when it deploys). The next wallet is `predictWallet(owner, walletCount(owner))`. +`index` may be at most `walletCount(owner)`: predicting further ahead reverts `IndexOutOfRange(index, next)`. + +### Deploy + +```solidity +function deployWallet(string calldata label) external returns (address wallet); // caller = owner +function deployWalletWithSig(OwnerIntent calldata intent, bytes calldata sig, string calldata label) + external returns (address wallet); // relayed, see §7 +``` + +- `deployWallet` makes **the caller** the owner; there is no owner parameter. +- `label` is emitted in `WalletDeployed`, **not stored** on-chain. Read it from events. +- Deploys revert while the factory is paused (`EnforcedPause`). + +### Look up + +```solidity +function isWallet(address account) external view returns (bool); +function ownerOf(address wallet) external view returns (address); // address(0) if not a factory wallet +function indexOf(address wallet) external view returns (uint256); // reverts NotAWallet for a non-wallet +``` + +To list an owner's wallets: indices `0 .. walletCount(owner)-1` through `predictWallet`, or the `WalletDeployed` +events filtered by `owner`. + +--- + +## 4. Granting a rule + +```solidity +function grantRules(Session calldata session) external returns (bytes32 rulesId); // owner, or the wallet itself +``` + +One call grants one rule. A rule is a **`Session`** (the engine's struct) whose one policy is URP, carrying the terms +in an **envelope**. + +### 4.1 The Session, field by field + +```solidity +struct Session { + address sessionValidator; // AgentValidator 0x068E…FfFe6 (must equal wallet.SESSION_VALIDATOR()) + bytes sessionValidatorInitData; // abi.encode(address agent), agent != address(0) + bytes32 salt; // anything; the wallet overwrites it with its grant nonce + PolicyData[] userOpPolicies; // MUST be empty + ERC7739Data erc7739Policies; // MUST be empty: { allowedERC7739Content: [], erc1271Policies: [] } + ActionData[] actions; // see below + bool permitERC4337Paymaster; // MUST be false +} +struct PolicyData { address policy; bytes initData; } +struct ActionData { bytes4 actionTargetSelector; address actionTarget; PolicyData[] actionPolicies; } +struct ERC7739Data { ERC7739Context[] allowedERC7739Content; PolicyData[] erc1271Policies; } +struct ERC7739Context { bytes32 appDomainSeparator; string[] contentNames; } +``` + +Every action has **exactly one** policy: `{ policy: URP, initData: }`. Anything else reverts +`MalformedSessionShape`. + +Actions by rule kind: + +| Kind | `actions` | +|---|---| +| **Cross-chain** (EVM or Solana destination) | Exactly 1 action: `actionTarget = UniversalGatewayPC`, `actionTargetSelector = 0x77b86bec` (the gateway's `sendUniversalTxOutbound`) | +| **Native** (Push-side calls) | 1 to 8 actions, one per `(target, selector)` the agent may call; no duplicates; every action's envelope names the same chain | + +The **kind is never declared**: it is derived from the envelope's chain string. This chain (`"eip155:42101"`) means +native; any other `eip155:` or `solana:` chain means cross-chain. + +### 4.2 The envelope (`initData` of the URP policy) + +```solidity +initData = abi.encode(uint16 version, string chainNamespace, bytes body) +``` + +- `version` = **1** (`ENVELOPE_VERSION`). Anything else is refused (`UnsupportedEnvelopeVersion`). +- `chainNamespace`: CAIP-2 string, byte-exact. Destination chain for cross-chain rules (e.g. `"eip155:11155111"`, + `"solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1"`); `"eip155:42101"` for native rules on Donut. + (`URP.pushChainHash()` returns `keccak256("eip155:42101")` if you want to confirm.) +- `body`: `abi.encode(UniversalTerms)`, `abi.encode(SvmTerms)` or `abi.encode(NativeTerms)`, by kind. + +### 4.3 Cross-chain rule, EVM destination: `UniversalTerms` + +```solidity +struct UniversalTerms { + uint48 validUntil; // unix seconds, in the future; "never" = type(uint48).max + address expectedCEA; // the wallet's account on the destination chain + AssetCap[] assets; // 1..8 tokens the agent may move + uint256 maxGasPerCall; // PC (wei) the wallet may spend per outbound (protocol fee + gas) + AllowedCall[] allowedCalls; // 1..32 destination-chain calls the agent may make +} +struct AssetCap { + address token; // PRC20 ON PUSH (e.g. USDC.eth), never the destination chain's address + uint256 maxPerCall; // per request; 0 = this token can never move + uint256 maxTotal; // lifetime amount sent out; type(uint256).max = unlimited; 0 = nothing +} +struct AllowedCall { + address target; // destination-chain contract + bytes4 selector; // destination-chain function + uint16 beneficiaryOffset; // byte offset of the beneficiary argument: 4 + 32 * argIndex + bool hasBeneficiary; // if true, that argument must equal expectedCEA + uint256 maxValue; // native value per call, in DESTINATION-chain units; 0 = non-payable +} +``` + +ABI tuple: `(uint48,address,(address,uint256,uint256)[],uint256,(address,bytes4,uint16,bool,uint256)[])` + +Rules the contracts enforce at grant (each with a named error, §10): + +- **At least one token, at most 8, no duplicates.** A rule with no token is refused (`AssetListOutOfRange(0)`): the + gateway picks the destination chain from the request's token, so a rule without a token has no chain. +- **Every token's chain must equal the rule's chain**: URP calls `token.SOURCE_CHAIN_NAMESPACE()` and compares + (`ChainMismatch`, `InvalidAsset`). It checks the chain, **not which token**, so picking the right PRC20 is the SDK's job. +- `expectedCEA` non-zero; `allowedCalls` 1..32; `validUntil` non-zero and in the future. + +What the SDK has to resolve: + +- **Token → PRC20**: users give the destination chain's token (e.g. `MOVEABLE.TOKEN.ETHEREUM_SEPOLIA.USDC`); convert + with `PushChain.utils.tokens.getPRC20Address(...)` and confirm `SOURCE_CHAIN_NAMESPACE()` equals the rule's chain. +- **A rule that moves no tokens**: the contracts refuse an empty list, so the SDK adds the destination chain's gas + token with both limits at 0: `UniversalCore.gasTokenPRC20ByChainNamespace(chain)` (Sepolia: pETH + `0x2971824Db68229D087931155C2b8bB820B275809`). Add it only when the user lists no token, or it would duplicate. +- **"No total limit"**: encode `maxTotal = type(uint256).max`. Do not encode 0; 0 means nothing may move. +- **`expectedCEA`**: the wallet's CEA on the destination chain, from that chain's CEA factory: + `getCEAForPushAccount(walletAddress) returns (address cea, bool isDeployed)`. +- **`beneficiaryOffset`**: from the function ABI, `4 + 32 * argIndex` (e.g. Aave `supply(address,uint256,address,uint16)`, + `onBehalfOf` is argument 2, offset 68). + +One rule may list several tokens and several protocols. Limits are **per token**; there is no combined limit across +tokens, and every listed token may be used with every allowed call. Different scopes need separate rules. + +### 4.4 Cross-chain rule, Solana destination: `SvmTerms` + +```solidity +struct SvmTerms { + uint48 validUntil; + bytes32 expectedCEA; // PDA(["push_identity", wallet], gatewayProgram) + bytes32 gatewayProgram; // the Push gateway program on that cluster (from the chain registry) + AssetCap[] assets; // 1..8, same as §4.3; request amounts must fit u64 + uint256 maxGasPerCall; + bytes32[] ceaAccounts; // the CEA's value-holding accounts, max 16, MUST include expectedCEA + AllowedProgram[] programs; // 1..32 allowed (program, instruction) pairs + SvmAccountPin[] pins; // max 16 account pins + SvmDataPin[] dataPins; // max 8 instruction-data pins +} +struct AllowedProgram { bytes32 program; bytes8 discriminator; uint8 discriminatorLen; bool dataless; uint8 maxAccounts; } +struct SvmAccountPin { uint8 ruleIndex; uint8 accountIndex; bytes32 expected; } +struct SvmDataPin { uint8 ruleIndex; bool fromEnd; uint16 offset; uint16 offsetB; uint8 len; + uint8 mode /* 0 EQ, 1 GTE_LE, 2 LTE_LE, 3 RATIO_GTE_LE */; bytes32 expected; uint64 num; uint64 den; } +``` + +What the SDK must get right (all checked at grant, named errors): + +- `ceaAccounts`: the CEA plus **the CEA's token account for every listed token** and any swap-output accounts. URP + cannot derive Solana token accounts, so it cannot check this; an unlisted account is unprotected. +- **One rule per (program, instruction).** Each position takes one pinned key, so if a swap rule pins its input to the + USDC account, USDT cannot be that instruction's input. Plan Solana rules so different tokens use different instructions. +- Every program rule needs at least one account pin; `discriminatorLen` is 1..8, or 0 exactly when `dataless`. +- System, SPL Token, Token-2022, Stake, the upgradeable loader, the lookup-table program, the gateway program and the + CEA itself can never be allowed programs. + +Field-level detail: `docs/2_UniversalRulesPolicy.md` §1.2c. + +### 4.5 Native rule (Push-side calls): `NativeTerms`, one per action + +```solidity +struct NativeTerms { + uint48 validUntil; + address target; // MUST equal this action's actionTarget + bytes4 selector; // MUST equal this action's actionTargetSelector; 0xFFFFFFFF = plain PC transfer + uint256 maxValuePerCall; // PC (wei) per call + uint256 maxValueTotal; // lifetime PC; type(uint256).max = unlimited + AmountRule amount; // optional metering of one uint256 argument + uint32 maxCalls; // 0 = unlimited + ArgPin[] pins; // 0..8 arguments that must equal a fixed word +} +struct AmountRule { bool enabled; uint16 offset; uint256 maxPerCall; uint256 maxTotal; } +struct ArgPin { uint16 offset; bytes32 expected; } // offset counts from byte 0, selector included: 4 = first argument +``` + +ABI tuple: `(uint48,address,bytes4,uint256,uint256,(bool,uint16,uint256,uint256),uint32,(uint16,bytes32)[])` + +- `target`/`selector` must match the action they sit in. The contracts do not cross-check at grant, and a mismatch + makes the rule unusable. +- Targets that can never be granted: the gateway (use a cross-chain rule), the wallet, the factory, the engine, URP, + the validator, `address(0)`, `address(1)`. +- A plain PC transfer (`0xFFFFFFFF`) carries no pins and no amount rule. + +### 4.6 The `rulesId` + +`grantRules` returns it, and `RulesGranted(rulesId, …)` carries it. It is also predictable before sending: + +``` +rulesId = keccak256(abi.encode(address sessionValidator, bytes sessionValidatorInitData, bytes32(grantNonce))) + // grantNonce = wallet.grantNonce() at the moment of the grant; it advances by 1 on every grant +``` + +Equivalently, call `SmartSession.getPermissionId(session)` with `salt = bytes32(grantNonce)`. Ids never repeat, even +for byte-identical rules granted twice. + +### 4.7 Encoding a cross-chain rule (viem) + +```ts +import { encodeAbiParameters, parseAbiParameters, parseEther, maxUint256, zeroHash } from 'viem'; + +const terms = encodeAbiParameters( + parseAbiParameters('(uint48,address,(address,uint256,uint256)[],uint256,(address,bytes4,uint16,bool,uint256)[])'), + [[validUntil, expectedCEA, + [[USDC_ETH, 100_000000n, 1000_000000n], [USDT_ETH, 50_000000n, maxUint256]], + parseEther('1'), + [[aavePool, '0x617ba037', 68, true, 0n], [usdcSepolia, '0x095ea7b3', 0, false, 0n]]]], +); +const initData = encodeAbiParameters(parseAbiParameters('uint16, string, bytes'), [1, 'eip155:11155111', terms]); + +const session = { + sessionValidator: wallet.SESSION_VALIDATOR, // 0x068E…FfFe6 + sessionValidatorInitData: encodeAbiParameters([{ type: 'address' }], [agent]), + salt: zeroHash, + userOpPolicies: [], + erc7739Policies: { allowedERC7739Content: [], erc1271Policies: [] }, + actions: [{ + actionTargetSelector: '0x77b86bec', // gateway sendUniversalTxOutbound + actionTarget: '0x00000000000000000000000000000000000000C1', // UniversalGatewayPC + actionPolicies: [{ policy: URP, initData }], + }], + permitERC4337Paymaster: false, +}; +// wallet.grantRules(session), from the owner +``` + +--- + +## 5. Revoking and replacing rules + +```solidity +function revokeRules(bytes32 rulesId) external; // owner, or the wallet itself; UnknownPermission if not live +function revokeAllRules() external; // owner, or the wallet itself +``` + +Revocation is immediate on Push and cannot be blocked. An outbound already sent across the bridge still completes. + +**Rules are immutable.** To "update" one, the owner sends **one batch through the owner door** (§6): + +1. `URP.assertSpent(configId, wallet, expectedSpent)` — reverts if the agent spent since the SDK read the counters; +2. `wallet.revokeRules(oldRulesId)`; +3. `wallet.grantRules(newSession)`. + +If step 1 reverts, nothing changes. Counters start at zero on the new rule. `assertSpent` forms: + +```solidity +// cross-chain (EVM or Solana): one expected value per listed token, IN THE ORDER THE RULE LISTED THEM +function assertSpent(ConfigId id, address account, uint256[] calldata expectedSpent) external view; +// native: per action +function assertSpent(ConfigId id, address account, uint256 expectedValueSpent, uint256 expectedAmountSpent, uint32 expectedCalls) + external view; +``` + +--- + +## 6. The owner door: `execute` + +```solidity +function execute(bytes32 mode, bytes calldata executionCalldata) external payable; // owner only +``` + +The owner acts as the wallet with **no rule checked**: withdraw, approve, call anything, or call the wallet's own +`grantRules` / `revokeRules` in a batch. + +| | `mode` | `executionCalldata` | +|---|---|---| +| Single call | `0x0000…00` (32 zero bytes) | `abi.encodePacked(address target, uint256 value, bytes callData)` | +| Batch | `0x01` followed by 31 zero bytes | `abi.encode(Execution[])`, `Execution = (address target, uint256 value, bytes callData)` | + +Other modes (delegatecall, try) revert `UnsupportedExecutionMode`. Every call in an owner action records one +checkpoint. Withdraw PC: single call to the destination address with `value = amount, callData = 0x`. Withdraw a +token: single call to the token with `transfer(to, amount)`. + +--- + +## 7. Relayed owner actions: `OwnerIntent` + +For owners who sign but do not send (a Push EOA without gas, or a relayer-driven flow). The owner signs one EIP-712 +`OwnerIntent`; the named `executor` submits it. + +```solidity +struct OwnerIntent { + address owner; // the wallet owner + address wallet; // the wallet (its predicted address if not deployed yet) + address executor; // the ONLY address allowed to submit this intent + uint96 index; // deploy: must equal factory.walletCount(owner) + bytes32 sessionHash; // grant: keccak256(abi.encode(session)) of the session AS SUBMITTED; 0 = no grant + bytes32 mode; // execute: the mode word + bytes32 execCalldataHash; // execute: keccak256(executionCalldata); 0 = no execute + uint192 nonceKey; // execute: lane key; the top bit (1 << 191) MUST be set + uint64 nonceSeq; // execute: must equal wallet.getNonce(nonceKey) + uint64 grantNonce; // grant: must equal wallet.grantNonce() + uint48 deadline; // unix seconds; every door rejects after it + uint256 signerChainId; // the chain id the owner's wallet signs under (their home chain) +} +``` + +EIP-712 type string (fields in this order): + +``` +OwnerIntent(address owner,address wallet,address executor,uint96 index,bytes32 sessionHash,bytes32 mode,bytes32 execCalldataHash,uint192 nonceKey,uint64 nonceSeq,uint64 grantNonce,uint48 deadline,uint256 signerChainId) +``` + +Domain: `name "AGWFactory"`, `version "1"`, `chainId = signerChainId`, `verifyingContract = factory proxy` +(`0xaF88…1aaF`, also for wallet doors), `salt = bytes32(uint256(42101))`. Check the local derivation against +`factory.domainSeparator(signerChainId)` (or `wallet.domainSeparator(...)`, identical) before prompting. + +| Door | Contract | Fields it checks | +|---|---|---| +| `deployWalletWithSig(intent, sig, label)` | factory | `owner`, `index`, `wallet` (= predicted), `executor`, `deadline` | +| `grantRulesWithSig(session, intent, sig)` | wallet | `wallet`, `owner`, `executor`, `deadline`, `sessionHash`, `grantNonce` | +| `executeWithSig(mode, executionCalldata, intent, sig)` | wallet | `wallet`, `owner`, `executor`, `deadline`, `mode`, `execCalldataHash`, `nonceKey`, `nonceSeq` | + +- **One signature can cover all three doors**: each door checks only its own fields, and each is single-use (deploy: + the index advances; grant: the grant nonce advances; execute: the lane sequence advances). +- **Several rules in one signature**: put a batch of the wallet's own `grantRules` calls in `executeWithSig` + (`grantRulesWithSig` grants exactly one). +- `executeWithSig` is **not payable**; value comes from the wallet's balance. +- Signature check: an owner with no code is verified by ECDSA; a contract owner by its UEA method + (`verifyUniversalPayloadSignature`), then ERC-1271. A **Solana-key owner's UEA must already exist on Push** before + its first signed intent. +- If the owner calls `deployWalletWithSig` directly, no signature is needed. + +--- + +## 8. "Create a wallet with rules" in practice + +| Owner | How | +|---|---| +| **UEA** (external key) | One UEA multicall, one signature: `factory.deployWallet(label)` then `predictedWallet.grantRules(session)` per rule. | +| **Push EOA**, sends its own txs | Two transactions: `factory.deployWallet(label)`, then `wallet.execute(batch of wallet.grantRules(...))`. | +| **Push EOA via a relayer** | One signature: an `OwnerIntent` with the deploy fields plus an execute batch of self-grants. The relayer sends `deployWalletWithSig`, then `executeWithSig`. | + +Fund the wallet with PC (for the agent's per-call fees) and the tokens the rules allow, at its address, before or after +deployment. + +--- + +## 9. Reading state + +| To get | Call | +|---|---| +| A wallet's live rules | `SmartSession.getPermissionIDs(wallet)` → `bytes32[]` | +| Is a rule live | `SmartSession.isPermissionEnabled(rulesId, wallet)` | +| The rule's agent | `wallet.agentOf(rulesId)` (zero if revoked or unknown) | +| Kind, VM family, chain | `URP.getMode(configId, wallet)` → `{initialized, mode (0 cross-chain, 1 native), vm (0 EVM, 1 Solana), chainHash}` | +| Cross-chain EVM terms + spend | `URP.getConfig(configId, wallet)` → `{initialized, validUntil, expectedCEA, maxGasPerCall, assets[], allowedCalls[]}`, each asset `{token, maxPerCall, maxTotal, spent}` | +| Solana terms + spend | `URP.getSvmConfig(configId, wallet)` (same `assets[]` with `spent`) | +| Native terms + spend | `URP.getNativeConfig(configId, wallet)` → `{…, valueSpent, amountSpent, callsUsed, …}` | +| Checkpoints | `wallet.checkpointCount()`, `wallet.lastCheckpointBlock()`, `Checkpointed` events | +| Owner / factory | `wallet.owner()`, `wallet.factory()` | +| Next grant nonce | `wallet.grantNonce()` | +| Owner lane position | `wallet.getNonce(nonceKey)` | + +**`configId`** (the key URP reads take), per action: + +``` +actionId = keccak256(abi.encodePacked(address target, bytes4 selector)) +actionPolicyId = keccak256(abi.encodePacked(bytes32 rulesId, actionId)) +configId = keccak256(abi.encodePacked(address wallet, actionPolicyId)) +``` + +- Cross-chain rule: one action, `target = UniversalGatewayPC`, `selector = 0x77b86bec`, so the `configId` follows from + `rulesId` alone. +- Native rule: one `configId` per action; use each action's `(target, selector)` from the session the SDK built (or + decode the grant transaction's input). +- `getConfig` reverts `WrongModeForCall` / `WrongVmForCall` if called on the wrong kind; call `getMode` first when + unsure. An empty slot returns a zeroed struct. +- `spent` counts what was **sent out**. Money coming back to the wallet does not lower it. + +The contracts do not enforce one rule per agent per chain. A wallet can hold several rules for the same agent and +chain, so a lookup by `(agent, chain)` can return more than one. + +--- + +## 10. Events + +| Contract | Event | Notes | +|---|---|---| +| Factory | `WalletDeployed(address indexed owner, uint256 indexed index, address indexed wallet, string label)` | The only place `label` lives | +| Wallet | `AccountInitialized(address indexed owner, address indexed engine)` | Emitted once at deploy | +| Wallet | `RulesGranted(bytes32 indexed rulesId, uint8 mode, bytes32 indexed chainHash, string chainNamespace)` | `mode`: 0 cross-chain, 1 native | +| Wallet | `RulesRevoked(bytes32 indexed rulesId)` | Once per revoked id | +| Wallet | `OwnerExecuted(bytes32 indexed mode, bytes32 executionCalldataHash)` | `execute` | +| Wallet | `OwnerExecutedWithSig(bytes32 indexed mode, bytes32 executionCalldataHash, uint192 nonceKey, uint64 nonceSeq)` | `executeWithSig` | +| Wallet | `Checkpointed(uint64 indexed seq, uint8 kind, bytes32 ref, uint64 blockNumber)` | `kind`: 0 owner action (`ref` = `keccak256(abi.encode(target, value, callData))`), 1 rules granted, 2 rules revoked (`ref` = `rulesId`) | +| Wallet | `RulesActionAuthorized(bytes32 indexed rulesId, address indexed agent, bytes32 callsHash)` | An agent action passed (agent side) | +| URP | `OutboundMetered(bytes32 indexed id, address indexed multiplexer, address indexed account, address token, uint256 amount)` | A cross-chain spend was counted | +| URP | `NativeCallMetered(bytes32 indexed id, address indexed multiplexer, address indexed account, uint256 value, uint256 amount)` | A native call was counted | + +--- + +## 11. Errors the owner side can hit + +All are custom errors with arguments; decode with the contract ABIs. URP errors raised during a grant reach the caller +in full (they come through the wallet). + +| When | Errors | +|---|---| +| **Deploy** | `IndexMismatch(expected, provided)`, `IntentWalletMismatch`, `ExecutorMismatch`, `SignatureExpired`, `InvalidOwnerSignature`, `EnforcedPause` | +| **Grant: session shape** (wallet) | `MalformedSessionShape`, `TooManyActions(n)`, `DuplicateAction(target, selector)`, `ForbiddenActionTarget(target)`, `ForbiddenActionSelector(selector)`, `RulesTypeMismatch(mode, actionIndex, target)`, `EmptyChain`, `InconsistentChain(actionIndex)`, `CallerIsNotOwner` | +| **Grant: envelope** (URP) | `UnsupportedEnvelopeVersion(firstWord)`, `EmptyChain`, `UnsupportedNamespace(chainHash)` (chain is neither `eip155:` nor `solana:`; declared in `PushChainLib`) | +| **Grant: cross-chain terms** (URP) | `AssetListOutOfRange(length)`, `DuplicateAsset(token)`, `InvalidAsset(token)`, `ChainMismatch(declared, assetChain)`, `InvalidConfigField`, `AllowListOutOfRange(length)`, `InvalidExpiry(validUntil)` | +| **Grant: Solana terms** (URP) | `InvalidSvmConfigField`, `ProgramListOutOfRange`, `TooManySvmPins`, `TooManySvmDataPins`, `TooManyCeaAccounts`, `DiscriminatorLenOutOfRange`, `AmbiguousRule`, `ForbiddenProgramInAllowList`, `SvmPinRuleOutOfRange`, `SvmPinIndexOutOfRange`, `SvmMaxAccountsOutOfRange`, `DuplicateSvmPin`, `InvalidCeaAccount`, `CeaAccountsMissExpectedCEA`, `SvmDataPinInvalid`, `RuleWithoutPin` | +| **Grant: native terms** (URP) | `NativeTargetZero`, `NativeTargetIsGateway`, `TooManyPins`, `ValueOnlyWithPins`, `ValueOnlyWithAmountRule`, `InvalidExpiry` | +| **Revoke** | `UnknownPermission(rulesId)`, `CallerIsNotOwner` | +| **Update batch** | `AssetSpentMismatch(token, expected, actual)`, `SpentLengthMismatch(expected, actual)`, `SpentMismatch(expected, actual)` (native), `NotInitialized`, `WrongModeForCall` | +| **Owner door / signed doors** | `CallerIsNotOwner`, `UnsupportedExecutionMode`, `MalformedBatchCalldata`, `OwnerSigExpired`, `IntentWalletMismatch`, `ExecutorMismatch`, `InvalidOwnerSignature`, `IntentSessionMismatch`, `IntentGrantNonceMismatch`, `IntentExecMismatch`, `OwnerLaneRequired`, `InvalidNonce` | +| **Reads** | `WrongModeForCall(actual)`, `WrongVmForCall(actual)`, `NotAWallet(account)`, `IndexOutOfRange(index, next)` | + +A call made inside an owner action that reverts bubbles its own revert data up unchanged. + +--- + +## 12. Limits + +| Limit | Value | +|---|---| +| Tokens per cross-chain rule | 1 to 8 | +| Allowed calls per EVM rule | 1 to 32 | +| Actions per native rule | 1 to 8 | +| Argument pins per native action | 0 to 8 | +| Solana: programs / account pins / data pins / value-holding accounts | 1–32 / ≤16 / ≤8 / ≤16 | +| `validUntil` | non-zero, in the future; `type(uint48).max` = never | +| Unlimited total | `type(uint256).max` (0 means nothing) | +| Envelope version | 1 | + +## 13. Checklist before sending a grant + +- [ ] `sessionValidator` is the wallet's `SESSION_VALIDATOR()`; `sessionValidatorInitData = abi.encode(agent)`; agent ≠ owner. +- [ ] Every action has exactly one policy, URP, with a version-1 envelope. +- [ ] Cross-chain: one action, gateway + `0x77b86bec`; 1–8 PRC20 tokens, each on the rule's chain; a gas-token entry + at 0/0 if the user listed none; `maxTotal` is `type(uint256).max` when the user set no total. +- [ ] `expectedCEA` is the wallet's CEA on that chain; beneficiary offsets are `4 + 32 * argIndex`. +- [ ] Native: each `NativeTerms.target/selector` equals its action's. +- [ ] Solana: `ceaAccounts` includes the CEA and the CEA's account for every listed token. +- [ ] Record the `rulesId` from the receipt (or predict it from `grantNonce`) and keep the token order for `assertSpent`. diff --git a/plan/agw/research/source-refresh-2026-10-07/contracts/push-agentic-wallets/docs/addresses/donut.md b/plan/agw/research/source-refresh-2026-10-07/contracts/push-agentic-wallets/docs/addresses/donut.md new file mode 100644 index 00000000..b153465a --- /dev/null +++ b/plan/agw/research/source-refresh-2026-10-07/contracts/push-agentic-wallets/docs/addresses/donut.md @@ -0,0 +1,83 @@ +# Push Agentic Wallet — deployed addresses (Donut) + +**Generation `v4` (multi-asset rules, versioned envelope, agent sender door, checkpoints)** · Chain ID `42101` · +explorer [donut.push.network](https://donut.push.network) · deployed in blocks `23923806`–`23923810` · +commit `e8db748` (branch `deploy-agw` = `pushAgenticWallet_v3`) · `forge 1.5.1-stable` + +## The two addresses you need + +| | Address | +| ------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------- | +| **Factory**: deploy and look up wallets | [`0xaF88D0FD947afAe7bBb8F34e8417DCfc165e1aaF`](https://donut.push.network/address/0xaF88D0FD947afAe7bBb8F34e8417DCfc165e1aaF) | +| **URP**: name this as every rule's action policy | [`0x603E7f0aF6e1aAFf46DDfb28b1e99364f8BC59af`](https://donut.push.network/address/0x603E7f0aF6e1aAFf46DDfb28b1e99364f8BC59af) | + +Both are **proxies**. Point integrations at these, never at an implementation. + +## Everything + +| Contract | Address | Size (B) | Verified | +| -------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | -------: | :------: | +| `factoryProxy` (ERC-1967, UUPS) | [`0xaF88D0FD947afAe7bBb8F34e8417DCfc165e1aaF`](https://donut.push.network/address/0xaF88D0FD947afAe7bBb8F34e8417DCfc165e1aaF) | 141 | ✅ | +| `factoryLogic` (`AGWFactory`) | [`0xe138Dc6EfC10233BE1e6c8aF1Caf8cABe599cfC2`](https://donut.push.network/address/0xe138Dc6EfC10233BE1e6c8aF1Caf8cABe599cfC2) | 9,992 | ✅ | +| `walletImplementation` (`AGW`) | [`0x96D69ec7e6cDdaD414e656B5c9DCA24587DF713c`](https://donut.push.network/address/0x96D69ec7e6cDdaD414e656B5c9DCA24587DF713c) | 16,564 | ✅ | +| `urp` (Transparent proxy) | [`0x603E7f0aF6e1aAFf46DDfb28b1e99364f8BC59af`](https://donut.push.network/address/0x603E7f0aF6e1aAFf46DDfb28b1e99364f8BC59af) | 830 | ✅ | +| `urpImplementation` (`UniversalRulesPolicy` 3.1.0) | [`0xA2391eee4C9EA1B32AEB3A460B77296EA709F02F`](https://donut.push.network/address/0xA2391eee4C9EA1B32AEB3A460B77296EA709F02F) | 24,326 | ✅ | +| `urpProxyAdmin` (`ProxyAdmin`) | [`0x0b7a31ec85117892aEA90AA5cB6514e2F97c2295`](https://donut.push.network/address/0x0b7a31ec85117892aEA90AA5cB6514e2F97c2295) | 926 | ✅ | +| `sessionValidator` (`AgentValidator`) | [`0x068EE2388475A98EE1f5a434C58bFF3444fffFe6`](https://donut.push.network/address/0x068EE2388475A98EE1f5a434C58bFF3444fffFe6) | 806 | ✅ | +| `sessionEngine` (`SmartSession`, fork `7dc20e4`) | [`0x165A5E6782f39D30B38c7D97e1303e4CB2aD102a`](https://donut.push.network/address/0x165A5E6782f39D30B38c7D97e1303e4CB2aD102a) | 22,581 | ✅ | + +**All eight verified** on Blockscout. Keep `urpProxyAdmin`: without it URP can never be upgraded. + +### Push core contracts this deployment points at (not deployed by this repo) + +| | Address | +| --------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | +| `UniversalGatewayPC` | `0x00000000000000000000000000000000000000C1` (implementation `0x1e41…a659`, 8-field outbound request, selector `0x77b86bec`) | +| `UniversalCore` | `0x00000000000000000000000000000000000000C0` | +| `UEAFactory` | `0x00000000000000000000000000000000000000eA` | +| `UNIVERSAL_EXECUTOR_MODULE` | `0x14191Ea54B4c176fCf86f51b0FAc7CB1E71Df7d7` (the address core's UniversalCore and PRC20s use; an account with no code) | + +## How to grant a rule (what changed from v3.2) + +| | v3.2 | v4 | +| --------------------------- | --------------------------------------------------------- | ----------------------------------------------------------------------------------------- | +| Policy `initData` | `abi.encode(string chainNamespace, bytes body)` | **`abi.encode(uint16 version, string chainNamespace, bytes body)`**, `version = 1` | +| Tokens per cross-chain rule | exactly 1 (`asset`, `maxAmountPerCall`, `maxAmountTotal`) | **1 to 8** (`assets: AssetCap[]`), each with its own limits and spend counter | +| PC fee limit | `maxPCPerCall` | **`maxGasPerCall`** (same meaning: PC per outbound for protocol fee + gas) | +| Agent door | session signature through a validator | **`executeAsAgent(rulesId, mode, executionCalldata)`**, callable only by the rule's agent | +| Owner-side changes | not recorded | **checkpoint counter** (`checkpointCount()`, `Checkpointed` event) | + +Cross-chain body (EVM destination): + +```solidity +struct AssetCap { address token; uint256 maxPerCall; uint256 maxTotal; } // token = PRC20 on Push +struct UniversalTerms { + uint48 validUntil; address expectedCEA; AssetCap[] assets; uint256 maxGasPerCall; AllowedCall[] allowedCalls; +} +// ABI tuple: (uint48,address,(address,uint256,uint256)[],uint256,(address,bytes4,uint16,bool,uint256)[]) +``` + +``` +cast call 0x603E7f0aF6e1aAFf46DDfb28b1e99364f8BC59af 'pushChainHash()(bytes32)' --rpc-url +# -> 0x3d6bc1f1d3fb03065860265a8e93840b586e57075d956cd41b4319d040be87f9 == keccak256("eip155:42101") +``` + +Full design notes: `docs/1_AGW.md`, `docs/2_UniversalRulesPolicy.md`, `docs/multi-asset-review.md`. + +## Admin + +| Authority | Holder | How to change it | +| ----------------------------------------------- | --------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | +| Factory `DEFAULT_ADMIN_ROLE` (factory upgrades) | deployer EOA `0xa89523351BE1e2De64937AA9AF61Ae06eAd199C7` | `beginDefaultAdminTransfer(new)`, then the new admin calls `acceptDefaultAdminTransfer()` after the **48-hour** delay | +| URP `ProxyAdmin` owner (URP upgrades) | deployer EOA `0xa89523351BE1e2De64937AA9AF61Ae06eAd199C7` | `transferOwnership(new)` on `0x0b7a…2295`, immediate | +| Factory `PAUSER_ROLE` / `OPERATOR_ROLE` | **nobody yet** | the default admin must `grantRole` before the factory can be paused or unpaused | + +These are different powers, and for production they belong in different multisigs: the factory admin can strand +counterfactually funded addresses; the URP ProxyAdmin owner can rewrite every gate in the security boundary. + + +## Previous generation (retired) + +`v3.2` (factory `0x2578041963f692f8b51A137A1c7ddc0c84a8226A`, URP `0xeAd99E254ACD64219d057400cdC2A2390bC74372`) stays on +chain but is no longer current. Its wallets and rules do not carry over; owners withdraw through the owner door. Its +record is in `deployments/address-book-v3/`. diff --git a/plan/agw/research/source-refresh-2026-10-07/contracts/push-agentic-wallets/src/AGW.sol b/plan/agw/research/source-refresh-2026-10-07/contracts/push-agentic-wallets/src/AGW.sol new file mode 100644 index 00000000..e0f635a5 --- /dev/null +++ b/plan/agw/research/source-refresh-2026-10-07/contracts/push-agentic-wallets/src/AGW.sol @@ -0,0 +1,1176 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import { Clones } from "@openzeppelin/contracts/proxy/Clones.sol"; +import { ReentrancyGuardTransient } from "@openzeppelin/contracts/utils/ReentrancyGuardTransient.sol"; +import { IERC165 } from "forge-std/interfaces/IERC165.sol"; + +import { ISmartSession } from "smartsessions/ISmartSession.sol"; +import { Session, ActionData, PermissionId, ValidationData, SmartSessionMode } from "smartsessions/DataTypes.sol"; +import { PackedUserOperation } from "account-abstraction/interfaces/PackedUserOperation.sol"; +import { IModule as IERC7579Module } from "erc7579/interfaces/IERC7579Module.sol"; + +import { IAgentValidator } from "./interfaces/IAgentValidator.sol"; +import { IAGW } from "./interfaces/IAGW.sol"; +import { ISmartSessionConfigReader } from "./interfaces/ISmartSessionConfigReader.sol"; +import { AGWErrors } from "./libraries/Errors.sol"; +import { AgentConfigLib } from "./libraries/AgentConfigLib.sol"; +import { PushChainLib } from "./libraries/PushChainLib.sol"; +import { OwnerAuthLib } from "./libraries/OwnerAuthLib.sol"; +import { + OwnerIntent, + OWNER_LANE_FLAG, + SEND_OUTBOUND_SELECTOR, + RulesType, + CheckpointKind, + ENGINE_FALLBACK_TARGET, + ENGINE_FALLBACK_SELECTOR, + ENGINE_FALLBACK_SELECTOR_SMARTSESSION +} from "./libraries/Types.sol"; +import { + ModeCode, + CallType, + ExecType, + ModeLib, + CALLTYPE_SINGLE, + CALLTYPE_BATCH, + EXECTYPE_DEFAULT +} from "./libraries/ModeLib.sol"; +import { ExecutionLib, Execution } from "./libraries/ExecutionLib.sol"; + +/** + * @title AGW — Agentic Wallet + * @notice The user's per-purpose agent wallet on Push Chain. It holds the budgeted funds and is + * `msg.sender` at the gateway, which is what binds it to its destination-chain account. + * + * @dev - Push Chain has no ERC-4337 EntryPoint, so this wallet builds the operation and enforces + * the engine's verdict itself in `executeAsAgent`. + * - An ERC-7579 modular account restricted to validator modules; executor, fallback and + * hook modules are refused. A hook would run on the owner path and could block it. + * - `execute` is the owner door: no policy is ever consulted on it. + * - `executeAsAgent` is the agent door: callable only by the rules set's agent — a Push + * address (an EOA, or the UEA of an external key) — and every call is checked by the + * rules set's policy. + * - Deliberately near-stateless. A request exists only for the transaction that carries it. + */ +contract AGW is IAGW, ReentrancyGuardTransient { + using ModeLib for ModeCode; + + /// @dev ERC-7579 account id, in vendor.account.semver form. + string internal constant ACCOUNT_ID = "push.agw.1.0.0"; + + /// @dev The only ERC-7579 module type this account supports. + uint256 internal constant MODULE_TYPE_VALIDATOR = 1; + + /// @dev Gas stipend for a module's uninstall callback. + uint256 internal constant UNINSTALL_CALLBACK_GAS_STIPEND = 100_000; + + /// @dev Gas cap on the pre-uninstall state probe of the session engine. + uint256 internal constant ENGINE_STATE_PROBE_GAS = 30_000; + + /** + * @dev Maximum actions in one NATIVE rules set. `UNIVERSAL` is always exactly one. + * + * A SANITY BOUND, NOT A GAS BOUND — measured, a maximal 8x8 grant sits far inside the + * budget. It caps the O(n^2) duplicate scan below, the per-rules-set audit and UI surface a + * human has to reason about, and `revokeRules`'s engine-side cleanup cost. + * + * Lives HERE, not in `Types.sol`, because it is a wallet policy number that URP never + * reads — unlike the engine mirrors, which are shared. Do not confuse it with URP's + * `MAX_ACTIONS_PER_REQUEST` (10): that bounds multicall ENTRIES inside one universal + * payload, two layers down. Different layers, different numbers, never conflated. + */ + uint256 internal constant MAX_NATIVE_ACTIONS = 8; + + // The four wiring addresses, read through their UPPER_CASE() auto-getters. Resolved from the + // implementation's runtime bytecode, so every clone reads them correctly through delegatecall. + + /// @notice The permission engine this wallet installs as its default validator. + address public immutable SESSION_ENGINE; + + /// @notice The canonical action policy (URP) every rules set on this wallet must name. + address public immutable RULES_POLICY; + + /// @notice The canonical session validator every rules set on this wallet must name — the sender + /// validator that confirms the caller is the rules set's agent. + address public immutable SESSION_VALIDATOR; + + /// @notice The Push-side outbound gateway, the only target a universal agent action may reach. + address public immutable UNIVERSAL_GATEWAY_PC; + + /// @dev One-shot latch for initializeAccount. + bool private _initialized; + + /// @dev Monotonic salt source for permission ids; never reused. + uint64 private _grantNonce; + + /// @dev Owner-side checkpoints so far; also the `seq` of the latest `Checkpointed`. Packed in slot 0. + uint64 private _checkpointCount; + + /// @dev `block.number` of the latest checkpoint; zero before the first. Packed in slot 0. + uint64 private _lastCheckpointBlock; + + /// @dev The account's entire module registry. + mapping(address => bool) private _installedValidators; + + /// @dev Owner replay lanes for `executeWithSig`: lane key => next expected sequence number. + mapping(uint192 => uint64) private _nonces; + + /** + * @notice Sets the wallet's permanent wiring and locks the implementation itself. + * + * @dev - Reverts with `InvalidModuleAddress` if any of the four addresses is zero. + * - Sets the initialised latch, so the implementation can never be initialised or + * driven directly; only clones of it can. + * + * @param sessionEngine_ Permission engine installed as the default validator. + * @param rulesPolicy_ Canonical action policy every rules set must name. + * @param sessionValidator_ Canonical session validator every rules set must name. + * @param universalGatewayPC_ Push-side outbound gateway. + */ + constructor(address sessionEngine_, address rulesPolicy_, address sessionValidator_, address universalGatewayPC_) { + if ( + sessionEngine_ == address(0) || rulesPolicy_ == address(0) || sessionValidator_ == address(0) + || universalGatewayPC_ == address(0) + ) { + revert AGWErrors.InvalidModuleAddress(); + } + SESSION_ENGINE = sessionEngine_; + RULES_POLICY = rulesPolicy_; + SESSION_VALIDATOR = sessionValidator_; + UNIVERSAL_GATEWAY_PC = universalGatewayPC_; + + _initialized = true; + } + + /// @dev Reverts unless the caller is the clone's immutable-args owner. + modifier onlyOwner() { + if (msg.sender != _owner()) revert AGWErrors.CallerIsNotOwner(); + _; + } + + /** + * @dev Reverts unless the caller is the owner or the wallet itself. Applied to the three + * lifecycle functions only. + * + * - A batch entry targeting the wallet arrives with `msg.sender == address(this)`, so + * without this the owner's own one-signature change batch reverts against itself. + * - Widening to self is safe because self is reachable only through the owner door. From + * the agent door it is refused FOUR ways, in the order they fire: + * (a) at grant time, by `_requireGrantableTarget` — the wallet is never a grantable + * native action target; + * (b) at dispatch time, by the guard in `_gateAndDispatch` — which holds even for a + * session the owner enabled on the engine directly through the owner door, + * bypassing `grantRules` entirely; + * (c) by the engine's `NoPoliciesSet`, because (a) guarantees the wallet is never a + * configured action — true regardless of how many actions a rules set holds; + * (d) by the engine's `InvalidSelfCall`, for the `execute` selector specifically. + * (a) and (b) are never-delete tests. + * - Not applied to installModule or uninstallModule; nothing needs them batched. + */ + modifier onlyOwnerOrSelf() { + if (msg.sender != _owner() && msg.sender != address(this)) revert AGWErrors.CallerIsNotOwner(); + _; + } + + /** + * @dev Reads the owner out of the clone's immutable args. + * + * - Clone args are 40 bytes: owner at 0-19, factory at 20-39. + * - Read from bytecode on every call and never cached; a storage mirror of an immutable is + * drift surface. + * - Meaningful only on a clone. `Clones.fetchCloneArgs` is undefined on a non-clone, and on + * the implementation it returns a slice of that contract's own runtime bytecode. + * - No guard is added for the implementation case: every door on the implementation is + * already inert for an independent reason. + * + * @return The clone's owner. + */ + function _owner() internal view returns (address) { + return address(bytes20(Clones.fetchCloneArgs(address(this)))); + } + + /** + * @dev Reads the deploying factory out of the clone's immutable args. + * @return The factory recorded at clone creation. + */ + function _factory() internal view returns (address) { + bytes memory args = Clones.fetchCloneArgs(address(this)); + return address(bytes20(_slice20(args, 20))); + } + + /** + * @dev Reads 20 bytes at `start` out of a memory blob, without assuming a length. The + * short-blob branch is unreachable from the single call site and is expected to show as + * uncovered. + * + * @param data Blob to read from. + * @param start Byte offset to read at. + * @return out The 20 bytes at `start`, or zero if the blob is too short. + */ + function _slice20(bytes memory data, uint256 start) private pure returns (bytes20 out) { + if (data.length < start + 20) return bytes20(0); + assembly { + out := mload(add(add(data, 0x20), start)) + } + } + + /** + * @notice Factory-only, callable exactly once. Installs the session engine as the account's + * sole validator. + * + * @dev - Reverts with `CallerIsNotFactory` unless the caller is the clone's recorded factory. + * - Reverts with `AlreadyInitialized` if the latch is already set. + * - Sets the latch, marks the engine installed, then calls `onInstall("")` with full gas + * and bubbles any revert, so the factory's deploy transaction unwinds atomically. + * - Emits `ModuleInstalled`, then `AccountInitialized`. + * - Session data is never passed here; grants travel only through `grantRules`. + */ + function initializeAccount() external { + if (msg.sender != _factory()) revert AGWErrors.CallerIsNotFactory(); + if (_initialized) revert AGWErrors.AlreadyInitialized(); + + _initialized = true; + _installedValidators[SESSION_ENGINE] = true; + + IERC7579Module(SESSION_ENGINE).onInstall(""); + + emit ModuleInstalled(MODULE_TYPE_VALIDATOR, SESSION_ENGINE); + emit AccountInitialized(_owner(), SESSION_ENGINE); + } + + /** + * @notice The owner door. Executes a single call or a batch on the owner's behalf; no policy is + * ever consulted. + * + * @dev - Reverts unless the caller is the owner; reentrancy-guarded. + * - Reverts on any execution type other than default, and on any call type other than + * single or batch. + * - Reads no module, policy or engine state — only the immutable-args owner, its calldata, + * and the wallet's own checkpoint slot — so the door still works with the engine + * uninstalled, with a hostile validator installed, or in ghost-rules state. + * - Records one checkpoint per call, before the call (`_checkpointOwnerCall`). The write + * cannot revert. + * - The signature is frozen at `execute(bytes32,bytes)`: the session engine branches on + * this exact selector, and any other shape routes validation down a path where the + * action policy sees a hardcoded zero value instead of the real one. + * - Batch is required product surface: the permission-change flow is one owner signature + * batching a spend assertion, a revoke and a grant. + * - Dispatches through `_execute` and emits `OwnerExecuted`. + * - There is no separate withdraw function; withdrawal, revocation escort and incident + * response all run through this door. + * + * @param mode ERC-7579 mode word; call type and execution type are decoded from it. + * @param executionCalldata Encoded execution, single or batch according to `mode`. + */ + function execute(bytes32 mode, bytes calldata executionCalldata) external payable onlyOwner nonReentrant { + ModeCode m = ModeCode.wrap(mode); + (CallType callType, ExecType execType,,) = m.decode(); + + if (execType != EXECTYPE_DEFAULT) revert AGWErrors.UnsupportedExecutionMode(); + if (callType == CALLTYPE_SINGLE) { + (address target, uint256 value, bytes calldata callData) = ExecutionLib.decodeSingle(executionCalldata); + _checkpointOwnerCall(target, value, callData); + _execute(target, value, callData); + } else if (callType == CALLTYPE_BATCH) { + Execution[] calldata execs = ExecutionLib.decodeBatch(executionCalldata); + uint256 len = execs.length; + for (uint256 i; i < len;) { + _checkpointOwnerCall(execs[i].target, execs[i].value, execs[i].callData); + _execute(execs[i].target, execs[i].value, execs[i].callData); + unchecked { + ++i; + } + } + } else { + revert AGWErrors.UnsupportedExecutionMode(); + } + + emit OwnerExecuted(mode, keccak256(executionCalldata)); + } + + /** + * @dev Plain call, bubbling the callee's revert data verbatim. Shared by both doors so the agent + * path executes the exact validated bytes. + * + * @param target Address to call. + * @param value Native PC to send with the call. + * @param callData Calldata to pass, forwarded unchanged. + */ + function _execute(address target, uint256 value, bytes calldata callData) internal { + (bool ok, bytes memory ret) = target.call{ value: value }(callData); + if (!ok) { + assembly { + revert(add(ret, 0x20), mload(ret)) + } + } + } + + /** + * @dev Records one owner-side change: advances the counter, stamps the block, emits `Checkpointed`. + * + * - CANNOT REVERT except by running out of gas: an unchecked increment of a uint64 that cannot + * realistically reach 2^64, one write to the wallet's own slot 0, one event. No external call. + * That is what lets it sit on the owner doors and on the revocation path. + * - NEVER called from `_execute` or anywhere the agent door reaches. A checkpoint means "the + * owner side touched this wallet"; an agent that could tick it could always fake owner + * interference. + * + * @param kind What changed. + * @param ref Per-kind reference (see `IAGW.Checkpointed`). + */ + function _checkpoint(CheckpointKind kind, bytes32 ref) private { + uint64 seq; + unchecked { + seq = _checkpointCount + 1; + } + // forge-lint: disable-next-line(unsafe-typecast) + uint64 blockNumber = uint64(block.number); // a block number does not exceed 2^64 in practice + _checkpointCount = seq; + _lastCheckpointBlock = blockNumber; + emit Checkpointed(seq, kind, ref, blockNumber); + } + + /** + * @dev The owner-door tick for one call, taken BEFORE the call runs, so a consumer snapshotting the + * counter during that call already sees it, and any later call in the same batch moves it again. + * + * @param target The call's target. + * @param value The call's native value. + * @param callData The call's calldata. + */ + function _checkpointOwnerCall(address target, uint256 value, bytes calldata callData) private { + _checkpoint(CheckpointKind.OWNER_ACTION, keccak256(abi.encode(target, value, callData))); + } + + /** + * @notice The owner door, authorised by a signed OwnerIntent instead of `msg.sender`. Relayable. + * + * @dev - A THIRD door, separate from `execute`. `execute` reads no module, policy or engine + * state — only the immutable-args owner, its calldata and its own checkpoint slot — and + * remains the unblockable fallback. This door reads storage (the nonce lane) and may + * therefore fail where `execute` cannot. + * - The mode switch below is DUPLICATED from `execute`, not shared with it, so that no + * refactor can ever add a check to `execute`. + * - Checks, in order: deadline · `intent.wallet == this` · owner · presenter is + * `intent.executor` · owner lane · `mode` and a non-zero `execCalldataHash` match · + * nonce (consumed before the signature check; any revert unwinds it) · the owner's + * signature under the FACTORY's domain. + * - Single or batch, default exec type. No dispatch guard: this is owner authority, so a + * batch may call the wallet's own lifecycle functions through `onlyOwnerOrSelf`. + * - Records one checkpoint per call, before the call, exactly as `execute` does. + * - Emits `OwnerExecutedWithSig`. + * + * @param mode ERC-7579 mode word; must equal `intent.mode`. + * @param executionCalldata Encoded execution; its hash must equal `intent.execCalldataHash`. + * @param intent The owner's intent; the grant fields are ignored here. + * @param sig The owner's signature over `intent`. + */ + function executeWithSig( + bytes32 mode, + bytes calldata executionCalldata, + OwnerIntent calldata intent, + bytes calldata sig + ) external nonReentrant { + address owner_ = _requireIntentPresenter(intent); + + uint192 nonceKey = intent.nonceKey; + if (nonceKey & OWNER_LANE_FLAG == 0) revert AGWErrors.OwnerLaneRequired(nonceKey); + + bytes32 calldataHash = keccak256(executionCalldata); + if (intent.execCalldataHash == bytes32(0) || intent.execCalldataHash != calldataHash || intent.mode != mode) { + revert AGWErrors.IntentExecMismatch(calldataHash); + } + + uint64 expected = _nonces[nonceKey]; + if (intent.nonceSeq != expected) revert AGWErrors.InvalidNonce(nonceKey, expected, intent.nonceSeq); + _nonces[nonceKey] = expected + 1; + + _requireOwnerSig(owner_, intent, sig); + + (CallType callType, ExecType execType,,) = ModeCode.wrap(mode).decode(); + if (execType != EXECTYPE_DEFAULT) revert AGWErrors.UnsupportedExecutionMode(); + if (callType == CALLTYPE_SINGLE) { + (address target, uint256 value, bytes calldata callData) = ExecutionLib.decodeSingle(executionCalldata); + _checkpointOwnerCall(target, value, callData); + _execute(target, value, callData); + } else if (callType == CALLTYPE_BATCH) { + Execution[] calldata execs = ExecutionLib.decodeBatch(executionCalldata); + uint256 len = execs.length; + for (uint256 i; i < len;) { + _checkpointOwnerCall(execs[i].target, execs[i].value, execs[i].callData); + _execute(execs[i].target, execs[i].value, execs[i].callData); + unchecked { + ++i; + } + } + } else { + revert AGWErrors.UnsupportedExecutionMode(); + } + + emit OwnerExecutedWithSig(mode, calldataHash, nonceKey, intent.nonceSeq); + } + + /** + * @dev The checks every intent door shares, in order: deadline, wallet, owner, presenter. + * Returns the owner so the caller does not re-read the immutable args. + */ + function _requireIntentPresenter(OwnerIntent calldata intent) internal view returns (address owner_) { + if (block.timestamp > intent.deadline) revert AGWErrors.OwnerSigExpired(intent.deadline); + if (intent.wallet != address(this)) { + revert AGWErrors.IntentWalletMismatch(address(this), intent.wallet); + } + owner_ = _owner(); + if (intent.owner != owner_) revert AGWErrors.CallerIsNotOwner(); + if (intent.executor == address(0) || msg.sender != intent.executor) { + revert AGWErrors.ExecutorMismatch(intent.executor, msg.sender); + } + } + + /// @dev The owner's signature over `intent`, under the factory's domain. Last check before effects. + function _requireOwnerSig(address owner_, OwnerIntent calldata intent, bytes calldata sig) internal view { + if (!OwnerAuthLib.isOwnerSig(owner_, OwnerAuthLib.intentDigest(_factory(), intent), sig)) { + revert AGWErrors.InvalidOwnerSignature(); + } + } + + /** + * @notice Grants one rules set to an agent. One of exactly two lifecycle operations. + * + * @dev - Reverts unless the caller is the owner or the wallet itself. + * - Rejects any session that is not the one shape this wallet permits, all with + * `MalformedSessionShape`: any user-op policy present, any ERC-7739 content or policy, + * the ERC-4337 paymaster permit set, an action count other than one, an action whose + * target is not the gateway or whose selector is not the outbound send, an action + * policy set that is not exactly the canonical policy, or a session validator that is + * not the canonical one. + * - Rejects an agent config the session validator does not accept — anything but + * `abi.encode(address agent)` with a non-zero agent. The canonical validator's check + * never reverts; the call is still wrapped in a bare catch rather than a typed one, so a + * future validator's revert or compiler panic is absorbed as a refusal. Wrapping is + * correct here only because the external call already exists; the action policy's own + * decode is deliberately not wrapped, since there it would introduce one. + * - Refusing the paymaster permit keeps dead surface dead: setting it would write a live + * permit row into engine storage, and that row decides whether a non-empty + * `paymasterAndData` is rejected outright or instead requires a user-op policy to run, + * which this shape forbids. + * - Overwrites the caller's salt with the wallet's monotonic grant counter, so identical + * terms granted twice yield distinct permission ids and a replaced id never recurs. + * That is what makes a request built for a revoked rules set die on regrant. + * - Enables the session on the engine and emits `RulesGranted`. + * - Records a checkpoint (`RULES_GRANTED`). + * - Validates the session's shape only. The caps, allow-list and expiry inside the policy + * config are the policy's own concern; do not extend this into term validation. + * - Carries no reentrancy guard: the guard would trip on the owner's own change batch, + * and the engine's enable path never calls back into the account. + * + * - TAKES NO MANDATE TYPE. The kind of a rules set is DERIVED, not declared: each action's + * URP policy envelope is `abi.encode(uint16 version, string chain, bytes body)`, and the chain decides + * the rulebook — this chain means a Push-side call (NATIVE), any other means a call + * through the gateway (UNIVERSAL). The owner states a chain once, where they were + * already stating the terms; nobody states a mode anywhere. Every action must name the + * same chain, which is what makes a mixed rules set unrepresentable rather than merely + * forbidden. + * - The envelope is NOT REWRITTEN. The wallet reads one field and passes the caller's + * bytes to the engine untouched, so what URP validates is exactly what the owner + * reviewed. + * + * @param session The session to enable. Its `salt` field is ignored and overwritten. + * @return rulesId The engine's id for the newly enabled rules set. + * + * `rulesId` is the engine's `permissionId`. + */ + function grantRules(Session calldata session) external onlyOwnerOrSelf returns (bytes32 rulesId) { + return _grantRules(session); + } + + /** + * @notice `grantRules`, authorised by the owner's signed OwnerIntent instead of `msg.sender`. + * + * @dev - Checks, in order: deadline · `intent.wallet == this` · `intent.owner` is this wallet's + * owner · presenter is `intent.executor` (non-zero) · `sessionHash` is non-zero and is the + * hash of `session` · `grantNonce` is the current `_grantNonce` · the owner's signature under + * the FACTORY's domain. Then the entire `grantRules` body, unchanged. + * - `_grantNonce` advances on every grant, so an intent grants at most once and dies on any + * other grant. No new storage. + * - `sessionHash` covers the session AS SUPPLIED, salt included; the salt is then overwritten + * with the grant nonce exactly as on the owner path. + * - Unreachable from the agent door: the wallet is never a grantable action target, and the + * dispatch guard refuses `address(this)` whatever the selector. + * - No reentrancy guard, for the same reason `grantRules` has none. + * + * @param session The session to enable. + * @param intent The owner's intent; the exec fields are ignored here. + * @param sig The owner's signature over `intent`. + * @return rulesId The engine's id for the newly enabled rules set. + * + * `rulesId` is the engine's `permissionId`. + */ + function grantRulesWithSig(Session calldata session, OwnerIntent calldata intent, bytes calldata sig) + external + returns (bytes32 rulesId) + { + address owner_ = _requireIntentPresenter(intent); + + bytes32 sessionHash = keccak256(abi.encode(session)); + if (intent.sessionHash == bytes32(0) || intent.sessionHash != sessionHash) { + revert AGWErrors.IntentSessionMismatch(sessionHash); + } + if (intent.grantNonce != _grantNonce) { + revert AGWErrors.IntentGrantNonceMismatch(_grantNonce, intent.grantNonce); + } + _requireOwnerSig(owner_, intent, sig); + + return _grantRules(session); + } + + /** + * @dev The entire body `grantRules` always had, moved here unchanged so both entry points run the + * same checks in the same order with the same errors. See `grantRules` for the rules. + */ + function _grantRules(Session calldata session) internal returns (bytes32 rulesId) { + // ─── rules COMMON to both types, first ─── + + if (session.userOpPolicies.length != 0) revert AGWErrors.MalformedSessionShape(); + + if ( + session.erc7739Policies.allowedERC7739Content.length != 0 + || session.erc7739Policies.erc1271Policies.length != 0 + ) revert AGWErrors.MalformedSessionShape(); + + if (session.permitERC4337Paymaster) revert AGWErrors.MalformedSessionShape(); + + uint256 n = session.actions.length; + + // BEFORE THE DECODE, AND FOR BOTH MODES. The mode is derived from action 0's envelope, so + // action 0 must exist before anything can be derived: with no actions there is no envelope, + // no chain, and therefore no mode to report. A universal session with zero actions + // consequently reports `TooManyActions(0)`, not `MalformedSessionShape`. + if (n == 0) revert AGWErrors.TooManyActions(0); + + // THE POLICY-SHAPE CHECK RUNS BEFORE THE DECODE, ALWAYS. Decoding first would read an + // arbitrary policy's `initData` as though it were URP's. This ordering is load-bearing. + _requirePolicyShape(session.actions[0]); + (string memory chain, bytes32 chainHash) = _chainNamespaceOf(session.actions[0]); + + // ─── THE ENTIRE MODE DECISION. Nobody declared it. ─── + RulesType mode = PushChainLib.deriveMode(chainHash); + + // THE INVARIANT, STATED ONCE: a wrong POLICY is always `MalformedSessionShape`; a target + // wrong FOR THE DERIVED TYPE is always `RulesTypeMismatch`. Between the two branches + // there is no shape in which a gateway call reaches a native config, and none in which a + // native call reaches a universal one — which, with URP's N3 and gate 3 at runtime, is the + // whole consistency argument. One chain per rules set makes mixed rules sets unrepresentable. + + if (mode == RulesType.UNIVERSAL) { + // `n != 1` BEFORE the target check, as before. A malformed chain string on a + // multi-action session therefore reports `MalformedSessionShape`, not a type mismatch. + if (n != 1) revert AGWErrors.MalformedSessionShape(); + + ActionData calldata a = session.actions[0]; + if (a.actionTarget != UNIVERSAL_GATEWAY_PC || a.actionTargetSelector != SEND_OUTBOUND_SELECTOR) { + revert AGWErrors.RulesTypeMismatch(mode, 0, a.actionTarget); + } + } else { + if (n > MAX_NATIVE_ACTIONS) revert AGWErrors.TooManyActions(n); + + // Hoisted: `_factory()` does an extcodecopy of the clone's own bytecode on every call. + address factoryAddr = _factory(); + + for (uint256 i; i < n;) { + ActionData calldata a = session.actions[i]; + + _requireGrantableTarget(a.actionTarget, factoryAddr, i); + _requireGrantableSelector(a.actionTargetSelector); + + // Action 0's shape and chain were read above; re-reading would waste ~900 gas. + // EVERY action must name the same chain — that is what makes "one rules set, one + // mode" true by construction rather than by a rule. + if (i != 0) { + _requirePolicyShape(a); + (, bytes32 h) = _chainNamespaceOf(a); + if (h != chainHash) revert AGWErrors.InconsistentChain(i); + } + + // O(n^2) by design: 28 comparisons at the n=8 ceiling, which beats a mapping and its + // clear-down. Two identical (target, selector) pairs would hash to one actionId. + for (uint256 j; j < i;) { + if ( + session.actions[j].actionTarget == a.actionTarget + && session.actions[j].actionTargetSelector == a.actionTargetSelector + ) { + revert AGWErrors.DuplicateAction(a.actionTarget, a.actionTargetSelector); + } + unchecked { + ++j; + } + } + + unchecked { + ++i; + } + } + } + + if (address(session.sessionValidator) != SESSION_VALIDATOR) { + revert AGWErrors.MalformedSessionShape(); + } + + try IAgentValidator(SESSION_VALIDATOR).validateConfig(session.sessionValidatorInitData) returns (bool ok) { + if (!ok) revert AGWErrors.MalformedSessionShape(); + } catch { + revert AGWErrors.MalformedSessionShape(); + } + + Session memory sessionMem = session; + sessionMem.salt = bytes32(uint256(_grantNonce)); + // Checked on purpose: a wrapping counter would mean silent salt reuse. + _grantNonce++; + + Session[] memory sessions = new Session[](1); + sessions[0] = sessionMem; + PermissionId[] memory ids = ISmartSession(SESSION_ENGINE).enableSessions(sessions); + + rulesId = PermissionId.unwrap(ids[0]); + _checkpoint(CheckpointKind.RULES_GRANTED, rulesId); + emit RulesGranted(rulesId, mode, chainHash, chain); + } + + /** + * @dev The policy-shape rule, hoisted so it can run before each envelope decode. + * + * A SHAPE rule, so it raises `MalformedSessionShape` like every other shape rule. It is + * also the precondition for `_chainNamespaceOf`: without it, the decode below would be reading an + * arbitrary policy's `initData` as though URP had authored it. + * + * @param a The action whose policy slot is vetted. + */ + function _requirePolicyShape(ActionData calldata a) internal view { + if (a.actionPolicies.length != 1 || a.actionPolicies[0].policy != RULES_POLICY) { + revert AGWErrors.MalformedSessionShape(); + } + } + + /** + * @dev Reads ONE field of the policy envelope — the bounded exception to "the skeleton, not the + * organs". + * + * WHAT THIS IS NOT: it is not term validation. The wallet does not check caps, expiry, + * allow-list contents or anything else inside the body, and must never start. It reads the + * label on the jar: the one field that decides WHICH RULEBOOK the action belongs to, which + * is the wallet's own business because the wallet's target rules depend on it. URP + * re-derives the same value from the same bytes and remains the sole judge of the terms. + * + * CALLER MUST HAVE RUN `_requirePolicyShape` FIRST. + * + * Same decoder as URP's, deliberately (`abi.decode(initData, (uint16, string, bytes))`): + * two different readers of one security-relevant field is the drift this design exists to + * prevent. A malformed envelope reverts here, unnamed, and fails closed. The version is + * URP's to judge: it refuses anything but `ENVELOPE_VERSION` at init, inside this grant. + * + * @param a The action to read. + * @return chain The declared CAIP-2 string, e.g. `"eip155:11155111"`. + * @return chainHash Its keccak256, the value everything downstream compares. + */ + function _chainNamespaceOf(ActionData calldata a) internal pure returns (string memory chain, bytes32 chainHash) { + (, chain,) = abi.decode(a.actionPolicies[0].initData, (uint16, string, bytes)); + if (bytes(chain).length == 0) revert AGWErrors.EmptyChain(); + chainHash = keccak256(bytes(chain)); + } + + /** + * @dev Every grant-time target rule for a NATIVE action, in one place. + * + * TWO RULES, TWO ERRORS, AND THE DISTINCTION IS THE POINT: + * + * - **The gateway → `RulesTypeMismatch`.** The session is well-formed; the CHAIN the + * envelope declares is this chain, and a gateway call is not a Push-side call. A gateway + * target is perfectly grantable — under a foreign chain, as `UNIVERSAL`. Carries the + * action index, because with up to eight actions "something was wrong" is not a usable + * diagnostic. This is one half of the consistency lock; URP's N3 is the runtime mirror. + * - **The other seven → `ForbiddenActionTarget`.** Never grantable, under any type. + * + * Of those seven the severe pair is the wallet and the engine: from the agent door, + * `_execute(wallet, 0, grantRules(...))` would arrive with `msg.sender == address(this)`, + * pass `onlyOwnerOrSelf`, and the agent would have granted itself a rules set of its own + * design. `revokeAllRules` is the mirror. + * + * LAYER CREDIT, so nobody deletes the wrong one as redundant: the engine independently + * refuses `address(0)` and ITSELF at enable time (`ConfigLib.sol:139-143`), but it does NOT + * refuse `address(1)` there — only at check time. **This is the only grant-time layer for + * the fallback flag.** + * + * The action-policy check is deliberately NOT here. That is a SHAPE rule — it raises + * `MalformedSessionShape`, and the UNIVERSAL branch and the common rules raise the same + * error for the same class of defect. It belongs with them, not inside a target helper. + * + * @param t Action target to vet. + * @param factoryAddr The clone's factory, hoisted by the caller so the loop reads it once. + * `_factory()` does an extcodecopy of the clone's own bytecode; the other + * six comparands are immutables and are free to read here. + * @param index Index of this action, reported by `RulesTypeMismatch`. + */ + function _requireGrantableTarget(address t, address factoryAddr, uint256 index) internal view { + if (t == UNIVERSAL_GATEWAY_PC) { + revert AGWErrors.RulesTypeMismatch(RulesType.NATIVE, index, t); + } + if ( + t == address(0) || t == ENGINE_FALLBACK_TARGET || t == address(this) || t == SESSION_ENGINE + || t == RULES_POLICY || t == SESSION_VALIDATOR || t == factoryAddr + ) { + revert AGWErrors.ForbiddenActionTarget(t); + } + } + + /** + * @dev The grant-time forbidden-selector list for NATIVE actions. + * + * Refuses the engine's two fallback selectors by name. `0xFFFFFFFF` (value-only) is + * PERMITTED and is deliberately not on this list. + * + * @param s Action selector to vet. + */ + function _requireGrantableSelector(bytes4 s) internal pure { + if (s == ENGINE_FALLBACK_SELECTOR || s == ENGINE_FALLBACK_SELECTOR_SMARTSESSION) { + revert AGWErrors.ForbiddenActionSelector(s); + } + } + + /** + * @notice Revoke one rules set. The other lifecycle operation, and the emergency lever. + * + * @dev - Reverts unless the caller is the owner or the wallet itself. + * - Reverts with `UnknownPermission` if the id is not enabled, because the upstream + * removal silently no-ops on a ghost id and an operator must never read "revoked" + * while the rules set lives. + * - Removes the session and emits `RulesRevoked`. Revocation is immediate: removal clears + * the agent, so any request under the id fails `CallerIsNotAgent`. + * - Deliberately carries no reentrancy guard and no health probe: nothing that can fail + * belongs on the stop path, since blockable removal is the one regression this + * function can develop. It records a checkpoint (`RULES_REVOKED`) per removed id; that + * write cannot revert. + * + * @param rulesId The rules set to revoke. + * + * `rulesId` is the engine's `permissionId`. + */ + function revokeRules(bytes32 rulesId) external onlyOwnerOrSelf { + if (!ISmartSession(SESSION_ENGINE).isPermissionEnabled(PermissionId.wrap(rulesId), address(this))) { + revert AGWErrors.UnknownPermission(rulesId); + } + + ISmartSession(SESSION_ENGINE).removeSession(PermissionId.wrap(rulesId)); + + _checkpoint(CheckpointKind.RULES_REVOKED, rulesId); + emit RulesRevoked(rulesId); + } + + /** + * @notice Revokes every rules set on this wallet in one call. The incident-response lever. + * + * @dev - Reverts unless the caller is the owner or the wallet itself. + * - Snapshots the permission ids, removes each by id, and emits `RulesRevoked` per id. + * Removal is by id, so engine-side array shifting cannot disturb the snapshot. + * - Deliberately carries no reentrancy guard and no health probe, for the same reason as + * `revokeRules`. It records a checkpoint (`RULES_REVOKED`) per removed id; that write + * cannot revert. + * - Gas grows with permission count; wallets hold few permissions by design. + */ + function revokeAllRules() external onlyOwnerOrSelf { + PermissionId[] memory ids = ISmartSession(SESSION_ENGINE).getPermissionIDs(address(this)); + + uint256 len = ids.length; + for (uint256 i; i < len;) { + ISmartSession(SESSION_ENGINE).removeSession(ids[i]); + _checkpoint(CheckpointKind.RULES_REVOKED, PermissionId.unwrap(ids[i])); + emit RulesRevoked(PermissionId.unwrap(ids[i])); + unchecked { + ++i; + } + } + } + + /** + * @notice The agent door. Callable only by the rules set's agent; every call is checked by the + * rules set's policy before it runs. + * + * @dev This chain has no EntryPoint, so this function does the EntryPoint's work, in order: + * 1. reject if the session engine is no longer installed + * 2. reject unless `msg.sender` is the agent `rulesId` names on this wallet + * 3. build the operation, validate it through the engine, and enforce the verdict + * 4. reject any mode other than single and default, and the two forbidden targets + * 5. dispatch the exact validated bytes + * 6. emit `RulesActionAuthorized` + * + * - The agent is a Push address. An external key (EVM, Solana, anything) acts through its + * UEA, which verifies that key before calling here; this wallet verifies no signature. + * - Replay protection is the sender's own transaction nonce (an EOA's nonce, or the UEA + * payload's nonce). Expiry is the rules set's own (policy gate 2 / N2 / S2); an EOA + * transaction carries no per-request expiry, a UEA payload carries its `deadline`. + * - A request against a revoked rules set fails at step 2: removal clears the agent. + * - Not payable, but a validated request does move PC out of the wallet's own balance, + * bounded by the policy's per-call ceiling. + * - Any revert unwinds the whole transaction, including the policy's counters; dispatch + * is never wrapped in try/catch. + * - Mode is single-only here: batching lives inside the multicall payload, bounded by the + * policy. + * + * @param rulesId The rules set this call acts under. `rulesId` is the engine's + * `permissionId`. + * @param mode ERC-7579 mode word; must decode to single and default. + * @param executionCalldata Encoded single execution, dispatched byte-for-byte once validated. + */ + function executeAsAgent(bytes32 rulesId, bytes32 mode, bytes calldata executionCalldata) external nonReentrant { + if (!_installedValidators[SESSION_ENGINE]) { + revert AGWErrors.ValidatorNotInstalled(SESSION_ENGINE); + } + + if (msg.sender != _agentOf(rulesId)) revert AGWErrors.CallerIsNotAgent(rulesId, msg.sender); + + bytes32 callsHash = keccak256(executionCalldata); + + _validate(rulesId, mode, executionCalldata, callsHash); + + _gateAndDispatch(mode, executionCalldata); + + emit RulesActionAuthorized(rulesId, msg.sender, callsHash); + } + + /** + * @dev Gates the mode to single and default, then dispatches the validated execution unchanged. + * + * - The agent path never batches at the ERC-7579 layer; batching lives inside the multicall + * payload instead, bounded by the policy. + * - Split out for stack depth only. Inlined, this does not compile with the optimizer off, + * which is the configuration `forge coverage` uses. + * + * @param mode ERC-7579 mode word. + * @param executionCalldata Encoded single execution to dispatch. + */ + function _gateAndDispatch(bytes32 mode, bytes calldata executionCalldata) internal { + (CallType callType, ExecType execType,,) = ModeCode.wrap(mode).decode(); + if (callType != CALLTYPE_SINGLE || execType != EXECTYPE_DEFAULT) { + revert AGWErrors.UnsupportedExecutionMode(); + } + (address target, uint256 value, bytes calldata callData) = ExecutionLib.decodeSingle(executionCalldata); + + // ⚠️ THE DISPATCH GUARD — never-delete, and it belongs HERE, after validation. + // + // Two comparisons, no storage, no module or policy state. It holds regardless of how the + // session was enabled — including a session the owner enabled on the engine DIRECTLY + // through the owner door, bypassing `grantRules` and its forbidden-target list entirely. + // That path exists today and is legitimate; this is what stops it reaching the wallet's own + // lifecycle functions from the agent side. + // + // DO NOT MOVE IT BEFORE `_validate`. Placed earlier it would pre-empt the engine's own + // refusals and change which error surfaces, and the engine-target case only ever reaches + // this point through the fallback sentinel, which validation has to run to resolve. + if (target == address(this) || target == SESSION_ENGINE) { + revert AGWErrors.ForbiddenDispatchTarget(target); + } + + _execute(target, value, callData); + } + + /** + * @dev Builds the operation, validates it through the engine, and enforces the verdict. + * + * - Builds a `PackedUserOperation` for its ABI shape only, since there is no EntryPoint. The + * engine requires `sender` to equal `msg.sender` (the wallet); that is what makes the + * signature field below unforgeable. + * - The callData selector must be `execute(bytes32,bytes)`, because that is the only engine + * branch that decodes the mode and forwards the real decoded value to the action policy. + * Every other selector reaches the policy with the account as target and a hardcoded zero + * value, which would make the policy's value gate compare against nothing. + * - The signature field is `USE ‖ rulesId ‖ msg.sender`, written here and nowhere else. The + * session validator accepts it only when those 20 bytes are the rules set's agent. + * - `callsHash` is passed as the operation hash. Nothing verifies a signature over it; it is + * what the engine forwards to the validator, which ignores it. + * - Gas fields are zero and `paymasterAndData` must stay empty, or the engine's paymaster + * permit check reverts. The nonce field is zero: replay protection is the sender's own. + * - Enforces the returned authorizer and time window itself — the EntryPoint's job, and what + * makes the policy's expiry gate real rather than decorative. + * - The engine runs the action policy before it consults the session validator, so policies + * still see calldata the engine has not yet authenticated; the wallet's own agent check + * has already run by then. + * - Performs exactly one external call, to the engine. Split out for stack depth. + * + * @param rulesId The rules set, written into the signature field. + * @param mode ERC-7579 mode word, re-encoded into the operation's calldata. + * @param executionCalldata Execution calldata, re-encoded into the operation's calldata. + * @param callsHash `keccak256(executionCalldata)`, passed as the operation hash. + */ + function _validate(bytes32 rulesId, bytes32 mode, bytes calldata executionCalldata, bytes32 callsHash) internal { + PackedUserOperation memory op; + op.sender = address(this); + op.nonce = 0; + op.initCode = ""; + op.callData = abi.encodeWithSelector(this.execute.selector, mode, executionCalldata); + op.accountGasLimits = bytes32(0); + op.preVerificationGas = 0; + op.gasFees = bytes32(0); + op.paymasterAndData = ""; + op.signature = abi.encodePacked(SmartSessionMode.USE, rulesId, msg.sender); + + uint256 vd = ValidationData.unwrap(ISmartSession(SESSION_ENGINE).validateUserOp(op, callsHash)); + + address authorizer = address(uint160(vd)); + uint48 validUntil = uint48(vd >> 160); // 0 = unbounded + uint48 validAfter = uint48(vd >> 208); + + if (authorizer != address(0)) revert AGWErrors.ValidationFailed(authorizer); + if (block.timestamp < validAfter) revert AGWErrors.OutsideTimeWindow(validAfter, validUntil); + if (validUntil != 0 && block.timestamp > validUntil) { + revert AGWErrors.OutsideTimeWindow(validAfter, validUntil); + } + } + + /** + * @dev The agent `rulesId` names on this wallet, or `address(0)` if it names none. + * Zero when the id is unknown or revoked (removal clears the config), when its session + * validator is not the canonical one, or when its config is malformed. One external view + * call to the engine; decodes through the same library the validator enforces with. + * @param rulesId The rules set to look up. + * @return The agent's Push address, or zero. + */ + function _agentOf(bytes32 rulesId) internal view returns (address) { + (address sessionValidator_, bytes memory config) = ISmartSessionConfigReader(SESSION_ENGINE) + .getSessionValidatorAndConfig(address(this), PermissionId.wrap(rulesId)); + if (sessionValidator_ != SESSION_VALIDATOR) return address(0); + return AgentConfigLib.decode(config); + } + + /** + * @notice Installs a validator module. + * + * @dev - Reverts unless the caller is the owner; reentrancy-guarded. + * - Rejects any module type but validator, the zero address, an address with no code, + * and a module that is already installed. + * - Marks the module installed, calls `onInstall` with full gas and bubbles any revert, + * then emits `ModuleInstalled`. + * - Exists as the recovery lever: a corrected validator can be installed on an existing + * wallet without moving addresses or funds. + * + * @param moduleTypeId ERC-7579 module type; only the validator type is accepted. + * @param module Module to install. + * @param initData Opaque data forwarded to the module's `onInstall`. + */ + function installModule(uint256 moduleTypeId, address module, bytes calldata initData) + external + onlyOwner + nonReentrant + { + if (moduleTypeId != MODULE_TYPE_VALIDATOR) { + revert AGWErrors.UnsupportedModuleType(moduleTypeId); + } + if (module == address(0) || module.code.length == 0) revert AGWErrors.InvalidModuleAddress(); + if (_installedValidators[module]) revert AGWErrors.ModuleAlreadyInstalled(module); + + _installedValidators[module] = true; + + IERC7579Module(module).onInstall(initData); + + emit ModuleInstalled(moduleTypeId, module); + } + + /** + * @notice Uninstalls a validator module. Removal always proceeds. + * + * @dev - Reverts unless the caller is the owner; reentrancy-guarded. + * - Rejects any module type but validator, and a module that is not installed. + * - If and only if the module is the session engine, probes its initialised state under + * a gas cap and refuses removal while it still holds permissions. Uninstalling the + * engine with live permissions would run its cleanup loop out of gas and leave rows it + * then refuses to reinstall over, so the guard forces a `revokeAllRules` first. + * - Unmarks the module before calling back, so a module can never block its own removal. + * - Calls `onUninstall` under a stipend inside try/catch, emitting + * `UninstallCallbackFailed` if it reverts or exhausts the stipend, then emits + * `ModuleUninstalled`. + * - The probe is scoped to the engine alone, so a hostile third-party validator can + * never block its own removal. + * - A probe that reverts or runs out of gas proceeds with removal: the guard exists to + * prevent an ordering mistake, not to make a broken engine permanent. + * + * @param moduleTypeId ERC-7579 module type; only the validator type is accepted. + * @param module Module to uninstall. + * @param deInitData Opaque data forwarded to the module's `onUninstall`. + */ + function uninstallModule(uint256 moduleTypeId, address module, bytes calldata deInitData) + external + onlyOwner + nonReentrant + { + if (moduleTypeId != MODULE_TYPE_VALIDATOR) { + revert AGWErrors.UnsupportedModuleType(moduleTypeId); + } + if (!_installedValidators[module]) revert AGWErrors.ValidatorNotInstalled(module); + + if (module == SESSION_ENGINE) { + (bool ok, bytes memory ret) = module.staticcall{ gas: ENGINE_STATE_PROBE_GAS }( + abi.encodeCall(ISmartSession.isInitialized, (address(this))) + ); + if (ok && ret.length >= 32 && abi.decode(ret, (bool))) { + revert AGWErrors.EngineStillHoldsPermissions(); + } + } + + _installedValidators[module] = false; + + try IERC7579Module(module).onUninstall{ gas: UNINSTALL_CALLBACK_GAS_STIPEND }(deInitData) { } + catch { + emit UninstallCallbackFailed(module); + } + + emit ModuleUninstalled(moduleTypeId, module); + } + + /** + * @notice Whether `module` is installed under `moduleTypeId`. + * @param moduleTypeId ERC-7579 module type to query. + * @param module Module to query. + * @return True only for an installed validator. + */ + function isModuleInstalled(uint256 moduleTypeId, address module, bytes calldata) external view returns (bool) { + return moduleTypeId == MODULE_TYPE_VALIDATOR && _installedValidators[module]; + } + + /** + * @notice Whether this account supports an ERC-7579 module type. + * @param moduleTypeId Module type to query. + * @return True only for the validator type. + */ + function supportsModule(uint256 moduleTypeId) external pure returns (bool) { + return moduleTypeId == MODULE_TYPE_VALIDATOR; + } + + /** + * @notice Whether this account supports an ERC-7579 execution mode. + * @dev Answers for the account as a whole; the agent door additionally restricts itself to + * single calls. + * @param mode ERC-7579 mode word to query. + * @return True for default execution in single or batch call type. + */ + function supportsExecutionMode(bytes32 mode) external pure returns (bool) { + (CallType callType, ExecType execType,,) = ModeCode.wrap(mode).decode(); + if (execType != EXECTYPE_DEFAULT) return false; + return callType == CALLTYPE_SINGLE || callType == CALLTYPE_BATCH; + } + + /// @notice The wallet's owner, read from the clone's immutable args. + function owner() external view returns (address) { + return _owner(); + } + + /// @notice The factory that deployed this wallet. + function factory() external view returns (address) { + return _factory(); + } + + /** + * @notice Next expected sequence number in an owner lane (`OWNER_LANE_FLAG` set), consumed by + * `executeWithSig`. The agent door uses no nonce lanes. + * @param nonceKey Replay lane to query. + * @return The sequence number the next intent in that lane must carry. + */ + function getNonce(uint192 nonceKey) external view returns (uint64) { + return _nonces[nonceKey]; + } + + /// @notice The salt the next grant will use. + function grantNonce() external view returns (uint64) { + return _grantNonce; + } + + /** + * @notice The agent a rules set names on this wallet, or zero if it names none. + * @dev Zero for an unknown or revoked id, for a session the owner enabled on the engine + * directly with a non-canonical session validator, and for a malformed config. Such a + * rules set cannot be used through `executeAsAgent`. + * @param rulesId The rules set to look up. `rulesId` is the engine's `permissionId`. + * @return The agent's Push address, or zero. + */ + function agentOf(bytes32 rulesId) external view returns (address) { + return _agentOf(rulesId); + } + + /** + * @notice Owner-side checkpoints so far. Compare against a snapshot to learn whether the owner side + * touched this wallet since: any owner-door call, grant or revoke moves it; agent actions + * never do. + * @return The number of checkpoints recorded. + */ + function checkpointCount() external view returns (uint64) { + return _checkpointCount; + } + + /** + * @notice `block.number` of the latest checkpoint, or zero if none. A convenience only: consumers + * must compare COUNTS, because several checkpoints can share a block with their snapshot. + * @return The block number of the latest checkpoint. + */ + function lastCheckpointBlock() external view returns (uint64) { + return _lastCheckpointBlock; + } + + /// @notice The OwnerIntent domain separator this wallet verifies against, for a signer on + /// `signerChainId`. Identical to the factory's: the factory is the verifying contract. + function domainSeparator(uint256 signerChainId) external view returns (bytes32) { + return OwnerAuthLib.domainSeparator(_factory(), signerChainId); + } + + /// @notice The ERC-7579 account id, in vendor.account.semver form. + function accountId() external pure returns (string memory) { + return ACCOUNT_ID; + } + + /// @dev Accepts PC with no logic; the wallet pays outbound gas swaps from its own balance and + /// refunds land here. + receive() external payable { } + + /// @notice Accepts ERC-721 transfers, so destination-side refunds and NFTs can land. + function onERC721Received(address, address, uint256, bytes calldata) external pure returns (bytes4) { + return this.onERC721Received.selector; + } + + /// @notice Accepts ERC-1155 transfers, so destination-side refunds and NFTs can land. + function onERC1155Received(address, address, uint256, uint256, bytes calldata) external pure returns (bytes4) { + return this.onERC1155Received.selector; + } + + /// @notice Accepts batched ERC-1155 transfers, so destination-side refunds and NFTs can land. + function onERC1155BatchReceived(address, address, uint256[] calldata, uint256[] calldata, bytes calldata) + external + pure + returns (bytes4) + { + return this.onERC1155BatchReceived.selector; + } + + /** + * @notice ERC-165 support check. + * + * @dev - Reports ERC-165 and the two token-receiver interfaces only. + * - Deliberately does not report `IERC7579Account`: this account implements that + * interface partially, so advertising it would mislead the tooling that probes for it. + * Tooling detects the account through `accountId`, `supportsModule` and + * `supportsExecutionMode` instead. + * + * @param interfaceId Interface id to query. + * @return True for the three supported interfaces. + */ + function supportsInterface(bytes4 interfaceId) external pure returns (bool) { + return interfaceId == type(IERC165).interfaceId // 0x01ffc9a7 + || interfaceId == 0x150b7a02 // IERC721Receiver + || interfaceId == 0x4e2312e0; // IERC1155Receiver + } + + /** + * @notice Always invalid: the wallet never signs as an ERC-1271 party. + * @dev A constant return, with no logic and no future hook. This is also what makes the + * engine's enable-mode grant path dead on these wallets. + * @return The ERC-1271 failure magic value. + */ + function isValidSignature(bytes32, bytes calldata) external pure returns (bytes4) { + return 0xffffffff; + } +} diff --git a/plan/agw/research/source-refresh-2026-10-07/contracts/push-agentic-wallets/src/AGWFactory.sol b/plan/agw/research/source-refresh-2026-10-07/contracts/push-agentic-wallets/src/AGWFactory.sol new file mode 100644 index 00000000..704f1068 --- /dev/null +++ b/plan/agw/research/source-refresh-2026-10-07/contracts/push-agentic-wallets/src/AGWFactory.sol @@ -0,0 +1,355 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import { AGWFactoryErrors } from "./libraries/Errors.sol"; + +import { Clones } from "@openzeppelin/contracts/proxy/Clones.sol"; + +import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import { + AccessControlDefaultAdminRulesUpgradeable +} from "@openzeppelin/contracts-upgradeable/access/extensions/AccessControlDefaultAdminRulesUpgradeable.sol"; +import { PausableUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol"; +import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +import { IAGWFactory } from "./interfaces/IAGWFactory.sol"; +import { IAGWInit } from "./interfaces/IAGWInit.sol"; +import { OwnerIntent } from "./libraries/Types.sol"; +import { OwnerAuthLib } from "./libraries/OwnerAuthLib.sol"; + +/** + * @title AGWFactory + * @notice Deploys `AGW` clones at addresses computable before deployment, and is the + * root of trust for wallet identity. + * + * @dev - Wallet addresses are deterministic and predictable before deployment, so counterfactual + * funding is a supported flow. + * - This registry is the only proof of a wallet's provenance: anyone can deploy a contract + * with a lying `owner()` view. The audit chain is destination account, wallet, this + * registry, owner. + * - The owner is the caller, or the signer of an `OwnerIntent` naming this owner, index and + * wallet, presented by the intent's `executor`. Deploying a wallet owned by someone else + * without that owner's signature is impossible. + * - Holds no funds, never touches a wallet after deployment, and has no setter for the + * wallet implementation. + * - Deployed behind an ERC-1967 UUPS proxy; the proxy address is the permanent, + * user-facing factory address and never changes across logic upgrades. + */ +contract AGWFactory is + Initializable, + AccessControlDefaultAdminRulesUpgradeable, + PausableUpgradeable, + UUPSUpgradeable, + IAGWFactory +{ + /// @dev Holder may pause wallet deployment. + bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); + + /// @dev Holder may unpause wallet deployment. + bytes32 public constant OPERATOR_ROLE = keccak256("OPERATOR_ROLE"); + + /** + * @dev Delay on the two-step admin transfer. + * + * - The admin's one real power is authorising a UUPS upgrade of this logic, which is the + * single action that can permanently strand counterfactually funded addresses. + * - The extension makes `grantRole` and `renounceRole` on the admin role revert, forcing + * the scheduled flow. + */ + uint48 internal constant DEFAULT_ADMIN_DELAY = 2 days; + + /// @dev All bases use ERC-7201 namespaced storage, so these three variables occupy slots 0, 1 + /// and 2. Order is frozen, and a layout test asserts it from `forge inspect` output. + + /// @dev owner => wallets deployed for them, doubling as the next index so a count and an index + /// can never drift apart. `uint96` matches `WalletRecord.index`, so no narrowing cast + /// exists anywhere in this contract. + mapping(address => uint96) internal _walletCount; + + /// @dev wallet => its record; a zero owner means not deployed by this factory. This is the + /// entire registry: existence, owner and index from one packed slot per wallet. + mapping(address => IAGWFactory.WalletRecord) internal _records; + + /** + * @notice The canonical AGW logic contract all clones delegate to. + * + * @dev - Written once, in `initialize`. There is no setter: a function able to rewrite this + * would silently move every predicted address and strand counterfactually funded + * wallets, with no migration path to recover them. + * - Declared last and appended to only. Every future variable goes after it, and nothing + * is inserted or reordered before it, or address derivation breaks with no remedy. + * - `internal`, exposed only through `walletImplementation()`, so no second + * auto-generated getter with a different selector exists. + */ + address internal _walletImplementation; + + // No storage gap: this is a leaf UUPS implementation, so a future version simply appends after + // _walletImplementation. + + /// @dev Locks the logic contract so it can never be initialised directly. + constructor() { + _disableInitializers(); + } + + /** + * @notice Configures the proxy. Callable once, at deployment. + * + * @dev - Reverts with `ZeroAddress` if either address is zero. + * - Sets the admin with the two-day transfer delay, initialises pausable, and records + * the wallet implementation. + * - Makes no external calls and deploys nothing. Pauser and operator membership are + * granted afterwards by the admin through the standard `grantRole`. + * + * @param admin Receives the default admin role. + * @param walletImplementation_ Logic contract every wallet clone will delegate to. + */ + function initialize(address admin, address walletImplementation_) external initializer { + if (admin == address(0) || walletImplementation_ == address(0)) revert AGWFactoryErrors.ZeroAddress(); + + __AccessControlDefaultAdminRules_init(DEFAULT_ADMIN_DELAY, admin); + __Pausable_init(); + // UUPSUpgradeable in OZ 5.7.0 has no initializer; calling one does not compile. + + _walletImplementation = walletImplementation_; + } + + /** + * @notice Deploys the caller's next agent wallet and initialises it. + * + * @dev - Reverts while paused, and with `ImplementationNotSet` if the wallet implementation + * is unset. The latter is reachable only on a proxy deployed without its atomic init + * call; without it, `Clones` would deploy a permanently uninitialisable clone. + * - Advances the caller's wallet count and writes the registry record before the single + * external call, which is what makes a reentrant deploy unable to reuse an index. + * There is deliberately no reentrancy guard; the effect ordering is the protection. + * - Salt is the owner and the factory-assigned sequential index only. Nothing + * rules-related enters the derivation. + * - The owner appears twice, in the salt and in the immutable args, on purpose; + * removing either changes every future address. + * - Calls `initializeAccount` on the new clone. Any revert bubbles and the whole + * deployment unwinds, so an uninitialised wallet can never exist on-chain. + * - Emits `WalletDeployed`. + * + * @param label Free-form label, emitted in the event and never stored. + * @return wallet Address of the newly deployed wallet. + */ + function deployWallet(string calldata label) external whenNotPaused returns (address wallet) { + address implementation = _walletImplementation; + if (implementation == address(0)) revert AGWFactoryErrors.ImplementationNotSet(); + + address owner = msg.sender; + wallet = _deploy(implementation, owner, _walletCount[owner], label); + } + + /** + * @notice Deploys wallet `intent.index` for `intent.owner`, on the owner's signature. + * + * @dev - The index is EXPLICIT and must equal the owner's current count, and `intent.wallet` must + * be the address this call deploys. So a signed intent is idempotent and unmovable: a + * replay fails on the index, and nobody can advance an owner's count without the owner's + * signature. + * - `msg.sender == intent.owner` needs no signature (the caller is the owner, exactly as in + * the single-argument form). Any other caller must be `intent.executor` (non-zero) and + * must carry the owner's signature, before the deadline. + * - Grant and exec fields of the intent are ignored here; the wallet checks those. + * - Every check runs before `_deploy`, which advances the count before its one external + * call — the same effect ordering the single-argument form relies on. + * + * @param intent The owner's intent. Only `owner`, `wallet`, `executor`, `index`, `deadline` and + * `signerChainId` are read here. + * @param sig The owner's signature over `intent`; ignored when the caller is the owner. + * @param label Free-form label, emitted and never stored. Not signed. + * @return wallet The deployed wallet. + */ + function deployWalletWithSig(OwnerIntent calldata intent, bytes calldata sig, string calldata label) + external + whenNotPaused + returns (address wallet) + { + address implementation = _walletImplementation; + if (implementation == address(0)) revert AGWFactoryErrors.ImplementationNotSet(); + + address owner = intent.owner; + if (owner == address(0)) revert AGWFactoryErrors.ZeroAddress(); + + uint96 index = intent.index; + uint96 next = _walletCount[owner]; + if (index != next) revert AGWFactoryErrors.IndexMismatch(next, index); + + address predicted = _predict(implementation, owner, index); + if (intent.wallet != predicted) revert AGWFactoryErrors.IntentWalletMismatch(predicted, intent.wallet); + + if (msg.sender != owner) { + if (intent.executor == address(0) || msg.sender != intent.executor) { + revert AGWFactoryErrors.ExecutorMismatch(intent.executor, msg.sender); + } + if (block.timestamp > intent.deadline) revert AGWFactoryErrors.SignatureExpired(intent.deadline); + if (!OwnerAuthLib.isOwnerSig(owner, OwnerAuthLib.intentDigest(address(this), intent), sig)) { + revert AGWFactoryErrors.InvalidOwnerSignature(); + } + } + + wallet = _deploy(implementation, owner, index, label); + } + + /// @inheritdoc IAGWFactory + function domainSeparator(uint256 signerChainId) external view returns (bytes32) { + return OwnerAuthLib.domainSeparator(address(this), signerChainId); + } + + /** + * @dev The deployment tail shared by `deployWallet` and `deployWalletWithSig`. BYTE-FOR-BYTE the logic the + * single-argument form always had: count advance → salt → args → clone → record → + * initializeAccount → event. Every caller has run all of its checks before calling this. + * + * - The count advances and the record is written before the single external call, which is + * what makes a reentrant deploy unable to reuse an index. + * - Salt and args are frozen forever: counterfactual funding relies on them. + */ + function _deploy(address implementation, address owner, uint96 index, string calldata label) + internal + returns (address wallet) + { + _walletCount[owner] = index + 1; + + bytes32 salt = keccak256(abi.encode(owner, index)); + // 40 bytes: owner at 0-19, factory at 20-39. Frozen forever. + bytes memory args = abi.encodePacked(owner, address(this)); + + wallet = Clones.cloneDeterministicWithImmutableArgs(implementation, args, salt); + + _records[wallet] = WalletRecord({ owner: owner, index: index }); + + IAGWInit(wallet).initializeAccount(); + + emit WalletDeployed(owner, index, wallet, label); + } + + /** + * @dev The address derivation, shared by `predictWallet` and `deployWalletWithSig`. + * Mirrors `_deploy`'s salt and args exactly; any divergence is a critical bug. + */ + function _predict(address implementation, address owner, uint96 index) internal view returns (address) { + bytes32 salt = keccak256(abi.encode(owner, index)); + bytes memory args = abi.encodePacked(owner, address(this)); + return Clones.predictDeterministicAddressWithImmutableArgs(implementation, args, salt, address(this)); + } + + /** + * @notice The address wallet `index` of `owner` has, or will have. + * + * @dev - Reverts with `ImplementationNotSet` if the implementation is unset, and with + * `IndexOutOfRange` if `index` is beyond the next deployable one. Funding an address + * further out than that would put money in a permanent hole. + * - Mirrors `deployWallet`'s salt and args derivation exactly. Any divergence between + * the two is a critical bug, because counterfactual funding relies on this answer. + * - `deployed` is derived from the sequential index rather than `extcodesize`, which + * would misreport during construction and cost more. + * + * @param owner Wallet owner to predict for. + * @param index Wallet index under that owner. + * @return wallet The deterministic address for that owner and index. + * @return deployed True if that wallet already exists. + */ + function predictWallet(address owner, uint256 index) external view returns (address wallet, bool deployed) { + address implementation = _walletImplementation; + if (implementation == address(0)) revert AGWFactoryErrors.ImplementationNotSet(); + + uint256 next = _walletCount[owner]; + if (index > next) revert AGWFactoryErrors.IndexOutOfRange(index, next); + + wallet = _predict(implementation, owner, uint96(index)); + deployed = index < next; + } + + /** + * @notice How many wallets `owner` has; also the index the next deploy will use. + * @dev Full enumeration is this call plus `predictWallet(owner, 0..count-1)`, which is why no + * per-owner wallet array is stored: it cannot be lost or desynced. + * @param owner Owner to count wallets for. + * @return The number of wallets deployed for that owner. + */ + function walletCount(address owner) external view returns (uint256) { + return _walletCount[owner]; + } + + /** + * @notice The owner of `wallet`, or address(0) if this factory did not deploy it. + * @param wallet Wallet to look up. + * @return The recorded owner, or the zero address. + */ + function ownerOf(address wallet) external view returns (address) { + return _records[wallet].owner; + } + + /** + * @notice True only for wallets this factory deployed. + * @param account Address to test. + * @return Whether this factory deployed it. + */ + function isWallet(address account) external view returns (bool) { + return _records[account].owner != address(0); + } + + /** + * @notice The wallet's index under its owner. + * @dev Reverts with `NotAWallet` rather than returning zero, because zero is a valid index. + * @param wallet Wallet to look up. + * @return Its index under its owner. + */ + function indexOf(address wallet) external view returns (uint256) { + WalletRecord memory record = _records[wallet]; + if (record.owner == address(0)) revert AGWFactoryErrors.NotAWallet(wallet); + return record.index; + } + + /** + * @notice The canonical wallet logic contract. + * @dev The only getter for it; the variable is `internal` precisely so no second, + * auto-generated getter exists. Exposed so the SDK can verify its local derivation + * mirror before showing a user an address to fund. + * @return The wallet implementation every clone delegates to. + */ + function walletImplementation() external view returns (address) { + return _walletImplementation; + } + + /** + * @notice Pauses wallet deployment. + * @dev - Gates `deployWallet` only. Views are never gated, and deployed wallets are + * unaffected, since the factory has no reach into them. + * - While paused, a user who funded a predicted address cannot deploy it. Availability + * only; funds are never lost. + */ + function pause() external onlyRole(PAUSER_ROLE) { + _pause(); + } + + /** + * @notice Resumes wallet deployment. + * @dev The role split is deliberate: pause is a cheap panic button, unpause a considered + * operational act. A pauser cannot unpause, and an operator cannot pause. + */ + function unpause() external onlyRole(OPERATOR_ROLE) { + _unpause(); + } + + /** + * @dev Authorises a UUPS upgrade of this logic contract. + * + * - Restricted to the default admin role; reverts with `ZeroAddress` on a zero + * implementation. + * - Every future logic upgrade must leave the salt formula, the immutable-args encoding, + * the value of `_walletImplementation` and the storage layout unchanged. Upgrades exist + * for logic bugs only; the address derivation is frozen forever. + * - New variables are appended after `_walletImplementation`; base contracts are never + * added, removed or reordered, and nothing may come to share that slot. + * - Not `view` although solc suggests it: the base declares `_authorizeUpgrade` non-view, + * and an override cannot add mutability restrictions the base does not have. + * + * @param newImplementation The logic contract being upgraded to. + */ + function _authorizeUpgrade(address newImplementation) internal override onlyRole(DEFAULT_ADMIN_ROLE) { + if (newImplementation == address(0)) revert AGWFactoryErrors.ZeroAddress(); + } +} diff --git a/plan/agw/research/source-refresh-2026-10-07/contracts/push-agentic-wallets/src/libraries/Types.sol b/plan/agw/research/source-refresh-2026-10-07/contracts/push-agentic-wallets/src/libraries/Types.sol new file mode 100644 index 00000000..efef214a --- /dev/null +++ b/plan/agw/research/source-refresh-2026-10-07/contracts/push-agentic-wallets/src/libraries/Types.sol @@ -0,0 +1,544 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +/** + * @notice Mirror of push-chain-gateway .../libraries/TypesUGPC.sol + * @dev MUST match field-for-field and in order. Verified against + * contracts/evm-gateway/src/libraries/TypesUGPC.sol. + */ +struct UniversalOutboundTxRequest { + bytes recipient; // raw destination address on source chain (bytes for SVM compat) + address token; // PRC20 token address on Push Chain + uint256 amount; // amount to withdraw (burn on Push, unlock at origin) + uint256 gasLimit; // gas limit for fee quote; 0 = per-chain default + uint256 gasPrice; // gas price override; 0 = per-chain default + uint256 maxPCForGas; // max native PC for gas swap; 0 = no cap + bytes payload; // ABI-encoded calldata to execute on origin chain + address revertRecipient; // address to receive funds in case of revert +} + +/** + * @notice Mirror of push-chain-core .../libraries/Types.sol + * @dev Batch call entry for multicall execution. + */ +struct Multicall { + address to; + uint256 value; + bytes data; +} + +/// @dev bytes4(keccak256("UEA_MULTICALL")) — magic prefix for multicall payloads. +bytes4 constant MULTICALL_SELECTOR = bytes4(keccak256("UEA_MULTICALL")); + +/** + * @dev The two kinds of rules set. Declared by the owner at grant, asserted by the wallet, stored by + * URP as the config's mode. + * + * DECLARED ONCE, HERE, AND IMPORTED BY BOTH THE WALLET AND `IUniversalRulesPolicy`. Two enums with identical + * values that must always agree is the duplication this file exists to prevent — see the note + * on `SEND_OUTBOUND_SELECTOR` below. The wallet asserts the declared type against the action + * set at grant; URP stores it and branches on it at validation. They must be the same type. + * + * `UNIVERSAL` is the zero value, so an uninitialised slot reads as `UNIVERSAL`. That is why + * URP's `ModeSlot` carries an explicit `initialized` flag and never infers emptiness from the + * mode alone. + */ +enum RulesType { + UNIVERSAL, + NATIVE +} + +/** + * @dev Which destination VM a UNIVERSAL rules set targets. Derived by URP from the envelope's chain + * namespace prefix (`eip155:` / `solana:`) at config init; the wallet never reads it, because + * its grant rules are identical for every non-Push chain. + * + * `EVM` MUST STAY THE ZERO VALUE. URP's `ModeSlot` entries written before this enum existed + * read 0 in the byte that now holds it, and every one of them is an EVM rules set. + */ +enum VmFamily { + EVM, + SVM +} + +/** + * @dev Mirrors of engine constants that are not importable — `IdLib.VALUE_SELECTOR` is `internal` + * to a library, and the fallback flags are file-level constants in the vendored fork. + * + * MIRRORED, NOT GUESSED: each is pinned by a constant-mirror test against the upstream value, + * exactly as `MULTICALL_SELECTOR` is. If the fork moves, the test fails rather than the wallet + * silently permitting an action it means to forbid. + */ + +/// @dev `IdLib.VALUE_SELECTOR` — the action selector the engine assigns when calldata is under four +/// bytes. A native action carrying this selector is a value-only transfer with EMPTY calldata; +/// a no-argument function like `unstake()` still carries its own four bytes and is a normal +/// selector action. +bytes4 constant VALUE_SELECTOR = 0xFFFFFFFF; + +/// @dev `DataTypes.FALLBACK_TARGET_FLAG`. Refused by name at grant time: the engine does NOT reject +/// it at enable time (only at check time, `PolicyLib.sol:200`), so the wallet is the only +/// grant-time layer for this value. +address constant ENGINE_FALLBACK_TARGET = address(1); + +/// @dev `DataTypes.FALLBACK_TARGET_SELECTOR_FLAG` — the wildcard action's selector. +bytes4 constant ENGINE_FALLBACK_SELECTOR = 0x00000001; + +/// @dev `DataTypes.FALLBACK_TARGET_SELECTOR_FLAG_PERMITTED_TO_CALL_SMARTSESSION` — the sentinel that +/// routes a request to the engine itself. An agent reaching this could configure sessions. +bytes4 constant ENGINE_FALLBACK_SELECTOR_SMARTSESSION = 0x00000002; + +/** + * @dev The gateway's outbound entry point — the ONE selector an agent rules set may ever name. + * + * DECLARED HERE, BESIDE THE STRUCT IT TAKES, AND NOWHERE ELSE. The wallet's grant-shape check + * and the policy's request-decode gate must agree on this value exactly: the wallet refuses to + * grant a rules set naming any other selector, and the policy refuses to validate a request + * carrying any other selector. Two independently hand-typed copies of the same signature + * string is the kind of duplication that stays correct only until one of them is edited, and + * the failure would be silent in the safe direction for one contract and open in the other. + * + * The signature string spells out `UniversalOutboundTxRequest` field-for-field because that is + * how Solidity encodes a struct parameter into a selector. It is therefore load-bearing on the + * mirror above: reorder or retype a field there without editing this string and the selector + * silently stops matching the deployed gateway. + */ +bytes4 constant SEND_OUTBOUND_SELECTOR = + bytes4(keccak256("sendUniversalTxOutbound((bytes,address,uint256,uint256,uint256,uint256,bytes,address))")); + +/** + * @dev The owner's signed authorisation for up to three actions: deploy, grant, execute. + * + * SIGNED ONCE under the FACTORY's EIP-712 domain and verified by the factory and by every wallet + * it deploys. Each door checks only its own fields and advances its own nonce, so one signature + * serves each door exactly once. + * + * - Presentable ONLY by `executor`: every door, on its signature path, requires + * `intent.executor != address(0) && msg.sender == intent.executor`. Without that, anyone who saw + * the intent in calldata could drive the doors out of order and burn the owner's signature. + * - A zero `sessionHash` / `execCalldataHash` means "not authorised for that action". + * - EVERY FIELD IS IN THE TYPEHASH, IN DECLARATION ORDER. A field outside the typed data would + * guarantee the SDK and the contract disagree about what was signed. + * + * DECLARED HERE, beside the other values the factory and the wallet must agree on exactly. + */ +struct OwnerIntent { + address owner; // the wallet owner (UEA or EOA) + address wallet; // the wallet this intent is for — the predicted address if not yet deployed + address executor; // the ONLY msg.sender allowed to present this intent to a door + uint96 index; // wallet index under owner; deployWallet requires index == walletCount(owner) + bytes32 sessionHash; // keccak256(abi.encode(Session)) for grantRulesWithSig; 0 = no grant + bytes32 mode; // ERC-7579 mode word for executeWithSig + bytes32 execCalldataHash; // keccak256(executionCalldata) for executeWithSig; 0 = no exec + uint192 nonceKey; // owner lane for executeWithSig; must have OWNER_LANE_FLAG set + uint64 nonceSeq; // expected _nonces[nonceKey] at execution + uint64 grantNonce; // expected _grantNonce at grant + uint48 deadline; // unix seconds; all three doors reject after this + uint256 signerChainId; // EIP-712 domain.chainId the signer's wallet accepts — the owner's HOME chain +} + +/// @dev The struct string must list every OwnerIntent field, in declaration order, with its exact type. +bytes32 constant OWNER_INTENT_TYPEHASH = keccak256( + "OwnerIntent(address owner,address wallet,address executor,uint96 index,bytes32 sessionHash," + "bytes32 mode,bytes32 execCalldataHash,uint192 nonceKey,uint64 nonceSeq,uint64 grantNonce," + "uint48 deadline,uint256 signerChainId)" +); + +/** + * @dev The intent's EIP-712 domain. Five fields: + * - `chainId` is the SIGNER's home chain (`intent.signerChainId`), not Push: MetaMask refuses to + * sign typed data whose `domain.chainId` differs from the active chain. + * - `salt` is `bytes32(block.chainid)` — the Push chain id — which is what isolates one Push chain + * from another. + * - `verifyingContract` is the FACTORY PROXY for both the factory and every wallet; the wallet + * reads it from its immutable args. The `wallet` field stops cross-wallet replay. + */ +bytes32 constant OWNER_INTENT_DOMAIN_TYPEHASH = + keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract,bytes32 salt)"); +bytes32 constant OWNER_INTENT_DOMAIN_NAME_HASH = keccak256("AGWFactory"); +bytes32 constant OWNER_INTENT_DOMAIN_VERSION_HASH = keccak256("1"); + +/** + * @dev Top bit of a uint192 nonce key. `executeWithSig` requires it SET: only owner lanes are ever + * consumed, and keys with it CLEAR are never touched. The agent door uses no nonce lanes at all — + * its replay protection is the sender's own transaction nonce. + */ +uint192 constant OWNER_LANE_FLAG = uint192(1) << 191; + +/** + * @dev The kinds of owner-side change the wallet records as a checkpoint (`IAGW.Checkpointed`). + * + * ORDINALS ARE A FROZEN WIRE FORMAT: indexers and evaluators read them. Append only — never + * reorder, never remove. A future kind (e.g. a binder) is appended as the next ordinal. + */ +enum CheckpointKind { + OWNER_ACTION, + RULES_GRANTED, + RULES_REVOKED +} + +// ─────────────────────── policy types (moved from IURP) ─────────────────────── + +/** + * @dev Maximum pinned arguments per native action. Bounds the N7 loop. + * + * FILE-LEVEL, NOT INSIDE THE INTERFACE — Solidity forbids variables in interfaces (solc 8274), + * and unlike `MAX_ACTIONS_PER_REQUEST` / `MAX_ALLOWED_CALLS` (which are `internal` to URP + * because they bound loops nobody off-chain constructs) this one bounds an array THE SDK + * BUILDS, so an encoder has to be able to see it. Parallel to `MULTICALL_SELECTOR` in + * `Types.sol`. + */ +uint256 constant MAX_PINS = 8; + +/** + * @dev Maximum tokens one UNIVERSAL rules set may list (EVM and SVM alike). Bounds the init duplicate + * check and the gate-5 scan. + * + * FILE-LEVEL FOR THE SAME REASON AS `MAX_PINS`: it bounds an array THE SDK BUILDS. + */ +uint256 constant MAX_ASSETS = 8; + +/** + * @dev The rules-envelope version URP accepts. Every action policy's `initData` is + * `abi.encode(uint16 version, string chainNamespace, bytes body)`, the same shape in every mode. + * URP reads the version from the FIRST WORD before decoding anything else and refuses any other + * value, so a body layout can change later under a new version without being misread. + * FILE-LEVEL so the SDK, which writes the envelope, can read it. + */ +uint16 constant ENVELOPE_VERSION = 1; + +/** + * @notice WIRE TYPE — one token a UNIVERSAL rules set may move, with its own caps. + * @param token The PRC20 ON PUSH (e.g. USDC.eth), never the destination chain's address: the + * gateway request carries the PRC20 and routes by it. Its `SOURCE_CHAIN_NAMESPACE()` + * must equal the rules set's chain, checked at init for every entry. + * @param maxPerCall Per-request ceiling, PRC20 base units. ZERO IS LEGAL and means "this token may + * route a request but never moves": the move-nothing rules set is one entry with a + * zero `maxPerCall`, never an empty list (an empty list would pin no chain). + * @param maxTotal Lifetime ceiling on the amount SENT OUT in this token. `type(uint256).max` = + * unlimited, with no special branch; zero means nothing may move. + */ +struct AssetCap { + address token; + uint256 maxPerCall; + uint256 maxTotal; +} + +/** + * @notice STORAGE TYPE — an `AssetCap` plus the counter URP owns. Never a wire type: a caller-set + * counter would be a granted head start on the cap. + * @param spent Lifetime amount sent out in this token, recorded before dispatch. Money coming back + * to the wallet never lowers it (URP cannot see inflows, and could not tell an agent's + * return from the owner's top-up); only `creditRevert` does. + */ +struct AssetCapState { + address token; + uint256 maxPerCall; + uint256 maxTotal; + uint256 spent; +} + +/// @param target far-chain contract +/// @param selector far-chain function +/// @param beneficiaryOffset byte offset of the beneficiary word in the inner calldata +/// @param hasBeneficiary false for calls with no beneficiary argument +/// @param maxValue per-entry native ceiling, DESTINATION-chain units (0 = non-payable) +struct AllowedCall { + address target; + bytes4 selector; + uint16 beneficiaryOffset; + bool hasBeneficiary; + uint256 maxValue; +} + +/** + * @notice WIRE TYPE — what a UNIVERSAL envelope's body encodes. Not a storage type. + * + * @dev ABSENT BY DESIGN, and each absence is the point: `initialized` (URP sets it), `spent` + * (URP owns it), and the chain (the envelope carries it, exactly once). The SDK used to + * type all three and URP overwrote them — a field whose only legal value is a + * placeholder is a field the caller fills in believing it matters. + * + * Mapped field-by-field onto the storage `Config` by `_store`. The storage struct's + * layout never moves; this one is free to change with the wire format. + */ +struct UniversalTerms { + uint48 validUntil; + address expectedCEA; + AssetCap[] assets; + uint256 maxGasPerCall; + AllowedCall[] allowedCalls; +} + +/// @param initialized set once, at initialisation; re-initialisation is refused +/// @param validUntil non-zero always (enforced at init); "never" = type(uint48).max, explicit +/// @param expectedCEA the wallet's destination account, committed at grant. The rules set's +/// chain is not stored here: it lives on `getMode(id, account).chainHash` +/// @param maxGasPerCall Push-native per-call ceiling on `msg.value`, in PC wei. It pays the protocol +/// fee AND the gas swap, despite the name (renamed from `maxPCPerCall` to +/// match the SDK) +/// @param assets 1..MAX_ASSETS permitted PRC20s, each with its own caps and its own `spent` +struct Config { + bool initialized; + uint48 validUntil; + address expectedCEA; + uint256 maxGasPerCall; + AssetCapState[] assets; + AllowedCall[] allowedCalls; +} + +// ───────────────────────── native mode structs ───────────────────────── + +/** + * @dev Per-config mode record. THE MODE DISCRIMINATOR, and the reason it is a struct rather than + * a bare enum: `RulesType.UNIVERSAL` is the zero value, so an empty storage slot reads as + * `UNIVERSAL` and could not be told apart from a real universal rules set. `initialized` is + * authoritative; `mode` is MEANINGLESS when it is false. + * @param initialized true once any rulebook has been written for this config + * @param mode which rulebook; only meaningful when `initialized` + * @param vm which destination VM a UNIVERSAL config targets; meaningless for NATIVE + */ +struct ModeSlot { + bool initialized; + RulesType mode; + /// @dev ADDED for the SVM rulebook, PLACED HERE ON PURPOSE. Declared between `mode` and + /// `chainHash` it packs into slot 0 at byte 2 — a byte no earlier implementation ever + /// wrote, so every existing entry reads 0 = `EVM`, which is what every existing entry + /// is. No existing member moves: `chainHash` stays at slot 1. Appending it after + /// `chainHash` would be equally safe and cost one more slot per grant; the layout test + /// pins label, slot, offset and type of all four members either way. + VmFamily vm; + /// @dev keccak256(bytes(chain)) as declared in the policy envelope. THE single chain record + /// for BOTH modes — universal stores the destination chain, native stores this chain's + /// own hash. Written at init, never zero on an initialised entry. + bytes32 chainHash; +} + +/** + * @dev One pinned argument of a native call. + * @param offset ABSOLUTE byte offset from byte 0 of the calldata, SELECTOR INCLUDED — so 4 is + * the first argument word, 36 the second, and so on. + * @param expected The full 32-byte word that must appear there. An address argument is + * left-padded by the ABI, so a non-zero high half is a MISMATCH, deliberately: + * full-word equality also proves the padding is clean, which masking would + * silently accept. + */ +struct ArgPin { + uint16 offset; + bytes32 expected; +} + +/** + * @dev Optional metering of a `uint256` argument read out of native calldata. + * @param enabled Whether to meter at all. A BOOL rather than "offset 0 means off", because + * offset 0 is a legal position — it just points inside the selector. + * @param offset Absolute byte offset of the amount word, selector included. + * @param maxPerCall Per-call ceiling. Zero is legal (a call that must carry amount zero). + * @param maxTotal Lifetime ceiling; `type(uint256).max` = unlimited, with no special branch. + */ +struct AmountRule { + bool enabled; + uint16 offset; + uint256 maxPerCall; + uint256 maxTotal; +} + +/** + * @dev The native rulebook for ONE (target, selector) action. One of these per action, so a + * rules set with eight actions holds eight of them under eight distinct config ids. + * + * @param initialized set once; re-initialisation is refused, as in universal mode + * @param validUntil non-zero and future (enforced at init); "never" = type(uint48).max + * @param target defensive copy of the action target, asserted at N4 + * @param selector defensive copy, asserted at N5. `0xFFFFFFFF` = value-only, which means + * EMPTY calldata — a no-argument function still carries four bytes + * @param maxValuePerCall Push-native per-call ceiling + * @param maxValueTotal Push-native lifetime ceiling; type(uint256).max = unlimited + * @param valueSpent lifetime native value metered, written effects-last + * @param amount optional calldata-amount metering + * @param amountSpent lifetime metered amount, written effects-last + * @param maxCalls 0 = unlimited; otherwise the lifetime call ceiling + * @param callsUsed calls consumed. ALWAYS increments on a successful check, including a + * zero-value zero-amount call — a call is a use, and the alternative + * makes `maxCalls` bypassable + * @param pins 0..MAX_PINS pinned argument words + */ +struct NativeConfig { + bool initialized; + uint48 validUntil; + address target; + bytes4 selector; + uint256 maxValuePerCall; + uint256 maxValueTotal; + uint256 valueSpent; + AmountRule amount; + uint256 amountSpent; + uint32 maxCalls; + uint32 callsUsed; + ArgPin[] pins; +} + +/** + * @notice WIRE TYPE — what a NATIVE envelope's body encodes. Not a storage type. + * + * @dev ABSENT BY DESIGN: `initialized`, `valueSpent`, `amountSpent` and `callsUsed` are all + * URP's own counters, zeroed at init. The SDK had to type four zeroes it did not own. + * + * SPLIT EVEN THOUGH ONLY THE UNIVERSAL SIDE FORCES IT. The SDK builds both; one struct + * with dead input fields sitting beside one without is precisely the inconsistency that + * let a since-removed chain field acquire four different conventions in one repository. + */ +struct NativeTerms { + uint48 validUntil; + address target; + bytes4 selector; + uint256 maxValuePerCall; + uint256 maxValueTotal; + AmountRule amount; + uint32 maxCalls; + ArgPin[] pins; +} + +// ───────────────────────── svm mode structs ───────────────────────── +// +// The third rulebook: a UNIVERSAL rules set whose destination is a `solana:*` chain. On Solana an +// outbound is ONE cross-program invocation — a target program, an ordered account list, and an +// instruction byte string — signed by the wallet's CEA (a PDA), not an EVM multicall. Every +// EVM-shaped gate (multicall walk, `address` target, `bytes4` selector, beneficiary word, per-entry +// value) is replaced by the shapes below. See `URP._checkSvm` for the gate list. + +/** + * @dev One allow-listed (program, instruction) pair. + * @param program Target program id, 32 bytes. + * @param discriminator Left-aligned instruction tag; only the first `discriminatorLen` bytes + * are compared. 8 for Anchor (`sha256("global:")[..8]`), 1 for + * SPL-style instruction indexes. + * @param discriminatorLen 1..8, or 0 iff `dataless`. + * @param dataless The instruction carries NO data. The only way to get a length-0 tag, + * and it forces `ix_data` to be EMPTY at check time — so a rule can never + * match an instruction its pins were not written for. + * @param maxAccounts 0 = unbounded; otherwise the request's account count must EQUAL it. + * Set to the IDL count for fixed-layout instructions so nothing can be + * appended behind the pinned positions. + */ +struct AllowedProgram { + bytes32 program; + bytes8 discriminator; + uint8 discriminatorLen; + bool dataless; + uint8 maxAccounts; +} + +/** + * @dev `accounts[accountIndex]` of a request matching rule `ruleIndex` must equal `expected`. + * The SVM counterpart of the EVM beneficiary pin: programs read accounts by POSITION, so a + * value-carrying position is pinned to an owner-committed key (the CEA, or one of its ATAs). + */ +struct SvmAccountPin { + uint8 ruleIndex; + uint8 accountIndex; + bytes32 expected; +} + +/// @dev How an `SvmDataPin` compares. Integers are LITTLE-ENDIAN (Borsh), `len` bytes wide. +enum SvmDataPinMode { + EQ, + GTE_LE, + LTE_LE, + RATIO_GTE_LE +} + +/** + * @dev A constraint on the `ix_data` of a request matching rule `ruleIndex`. + * - EQ `ix_data[off : off+len] == expected[0 : len]`, `len` 1..32, raw bytes, + * LEFT-ALIGNED: bytes of `expected` past `len` must be zero. + * - GTE_LE `uintLE(ix_data[off : off+len]) >= uint256(expected)`, `len` 1..8, + * RIGHT-ALIGNED integer: `expected` must fit in `len` bytes. + * - LTE_LE `uintLE(ix_data[off : off+len]) <= uint256(expected)`, same encoding. + * - RATIO_GTE_LE `uintLE(A) * den >= uintLE(B) * num`, A at `offset`, B at `offsetB`, both + * `len` bytes and both addressed with the same `fromEnd`; `expected` unused; + * `num` and `den` both non-zero. + * This is the min-out floor RELATIVE to the input amount — a static floor on + * the output alone is bypassed by an input equal to the whole balance. + * - fromEnd `offset` counts back from the END of `ix_data` to the field's START. + * Borsh serialises vectors before scalars, so trailing scalar arguments have + * stable from-end offsets and unstable from-start ones. Requires + * `offset >= len`. + */ +struct SvmDataPin { + uint8 ruleIndex; + bool fromEnd; + uint16 offset; + uint16 offsetB; + uint8 len; + SvmDataPinMode mode; + bytes32 expected; + uint64 num; + uint64 den; +} + +/** + * @notice WIRE TYPE — what a `solana:*` UNIVERSAL envelope's body encodes. Not a storage type. + * + * @dev ABSENT BY DESIGN, as in `UniversalTerms`: `initialized` and `spent` are URP's. + * + * @param validUntil non-zero, in the future (enforced at init); "never" = type(uint48).max + * @param expectedCEA the wallet's CEA on the destination: `PDA(["push_identity", wallet], + * gatewayProgram)`. Owner-committed — Solidity cannot derive a PDA. + * @param gatewayProgram the Push gateway program on the declared cluster. Owner-committed; the + * SDK sources it from the chain registry. Forbidden as a target: that + * route only returns the permitted asset to the owner's wallet, at the + * owner's rate-limit and gas cost. + * @param assets 1..MAX_ASSETS permitted PRC20s with their caps, exactly as `UniversalTerms`; + * amounts are PRC20 base units (lamports / SPL base units), and a request's + * amount must also fit Solana's u64 (S6b) + * @param maxGasPerCall Push-native per-call ceiling (protocol fee + gas swap budget), PC wei + * @param ceaAccounts every CEA-controlled account that HOLDS VALUE: the CEA, its ATA for EACH + * listed asset, its ATAs for allowed outputs. At most MAX_CEA_ACCOUNTS (16, + * the CEA included: room for all 8 assets plus 7 outputs). Each may appear in + * a request ONLY at a position the matched rule pins to it; a listed account + * no rule pins can never be passed at all. Unlisted accounts are not + * protected — the list is the owner's statement of what is worth taking. + * URP CANNOT CHECK that each listed asset's ATA is here (it cannot derive a + * Solana token account, and does not know a PRC20's mint): listing them is + * the SDK's job. Must contain `expectedCEA`; no zero, duplicate, or program + * entries. + * @param programs the allow-list; first match wins, made exact by the init ambiguity rule. + * ONE RULE PER (program, instruction), so ONE PINNED KEY PER POSITION: if a + * swap rule pins its input to the USDC account, USDT can never be that + * instruction's input. Using several listed tokens through one instruction + * means leaving the input unpinned and those token accounts unlisted, so + * only the output and price pins protect them. Multi-asset on Solana is + * strongest when different tokens are used by different instructions. + * @param pins account pins, each naming its rule + * @param dataPins `ix_data` pins, each naming its rule + */ +struct SvmTerms { + uint48 validUntil; + bytes32 expectedCEA; + bytes32 gatewayProgram; + AssetCap[] assets; + uint256 maxGasPerCall; + bytes32[] ceaAccounts; + AllowedProgram[] programs; + SvmAccountPin[] pins; + SvmDataPin[] dataPins; +} + +/** + * @dev The SVM rulebook — STORAGE type, lives inside `_svm`. + * @param initialized set once; re-initialisation is refused + * @param assets per-token caps and per-token `spent`, exactly as `Config.assets` + */ +struct SvmConfig { + bool initialized; + uint48 validUntil; + bytes32 expectedCEA; + bytes32 gatewayProgram; + uint256 maxGasPerCall; + AssetCapState[] assets; + bytes32[] ceaAccounts; + AllowedProgram[] programs; + SvmAccountPin[] pins; + SvmDataPin[] dataPins; +} diff --git a/plan/agw/research/source-refresh-2026-10-07/contracts/push-agentic-wallets/src/policies/UniversalRulesPolicy.sol b/plan/agw/research/source-refresh-2026-10-07/contracts/push-agentic-wallets/src/policies/UniversalRulesPolicy.sol new file mode 100644 index 00000000..17799758 --- /dev/null +++ b/plan/agw/research/source-refresh-2026-10-07/contracts/push-agentic-wallets/src/policies/UniversalRulesPolicy.sol @@ -0,0 +1,1881 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import { UniversalRulesPolicyErrors } from "../libraries/Errors.sol"; + +import { VALIDATION_SUCCESS } from "erc7579/interfaces/IERC7579Module.sol"; +import { ConfigId } from "smartsessions/DataTypes.sol"; +import { IActionPolicy, IPolicy } from "smartsessions/interfaces/IPolicy.sol"; +import { IERC165 } from "forge-std/interfaces/IERC165.sol"; +import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; + +import { IUniversalRulesPolicy } from "../interfaces/IUniversalRulesPolicy.sol"; +import { IPRC20Source } from "../interfaces/IPRC20Source.sol"; +import { PushChainLib } from "../libraries/PushChainLib.sol"; +import { + AllowedCall, + AllowedProgram, + ArgPin, + AssetCap, + AssetCapState, + Config, + MAX_ASSETS, + ENVELOPE_VERSION, + MAX_PINS, + ModeSlot, + Multicall, + MULTICALL_SELECTOR, + NativeConfig, + NativeTerms, + RulesType, + SEND_OUTBOUND_SELECTOR as GATEWAY_SEND_OUTBOUND_SELECTOR, + SvmAccountPin, + SvmConfig, + SvmDataPin, + SvmDataPinMode, + SvmTerms, + UniversalOutboundTxRequest, + UniversalTerms, + VALUE_SELECTOR, + VmFamily +} from "../libraries/Types.sol"; + +// Cluster-independent Solana program ids, never targets. Decoded from their base58 ids by tooling and +// pinned by `test_svm_forbiddenProgramConstantsMatchBase58` — do not hand-edit a hex word. FILE-LEVEL, +// not inside the contract, so that test can import them without inheriting all of URP: a harness that +// did so grew past the 24,576-byte limit and failed `make sizes`. Inlined either way; no runtime cost. +/// @dev `11111111111111111111111111111111` — a system transfer with the CEA as funder drains it. +bytes32 constant SYSTEM_PROGRAM = bytes32(0); +/// @dev `TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA` — transfer/approve/close with CEA authority. +bytes32 constant SPL_TOKEN_PROGRAM = 0x06ddf6e1d765a193d9cbe146ceeb79ac1cb485ed5f5b37913a8cf5857eff00a9; +/// @dev `TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb` — the same surface on Token-2022. +bytes32 constant TOKEN_2022_PROGRAM = 0x06ddf6e1ee758fde18425dbce46ccddab61afc4d83b90d27febdf928d8a18bfc; +/// @dev `Stake11111111111111111111111111111111111111` — withdraw with the CEA as authority. +bytes32 constant STAKE_PROGRAM = 0x06a1d8179137542a983437bdfe2a7ab2557f535c8a78722b68a49dc000000000; +/// @dev `BPFLoaderUpgradeab1e11111111111111111111111` — never a CEA action; refused outright. +bytes32 constant BPF_LOADER_UPGRADEABLE = 0x02a8f6914e88a1b0e210153ef763ae2b00c2b93d16c124d2c0537a1004800000; +/// @dev `AddressLookupTab1e1111111111111111111111111` — rent drain with the CEA as payer. +bytes32 constant ADDRESS_LOOKUP_TABLE = 0x0277a6af97339b7ac88d1892c90446f50002309266f62e53c118244982000000; + +/** + * @title UniversalRulesPolicy (URP) + * @notice The security boundary of the whole system: the only contract that ever inspects what an + * agent really does on the far chain. Everything else routes, stores, or signs. + * + * @dev - The engine identifies actions by hashing the Push-side target and selector, and every + * agent action is the same Push-side call, so to the engine a trade, a deposit and a theft + * are identical. What the user actually authorised lives two decode levels down, inside + * the payload. This policy opens it. + * - It is the fail-closed anchor: the engine requires at least one action policy per action + * (`PolicyLib.check`), so removing this one does not weaken a rules set, it kills every + * request under it. + * - No owner, no setters, no pause. Its three trust anchors are written once, at + * initialisation, and there is no function that can change them afterwards. + * - It never makes an external call, and writes only after every gate has passed. + * + * UPGRADEABLE, BEHIND A TRANSPARENT PROXY, AND THAT IS A DELIBERATE TRADE. This contract + * used to hold its trust anchors in immutables and describe itself as needing no trust at + * all. Immutables live in the implementation's bytecode, which a `delegatecall` never + * executes the constructor of, so upgradeability and immutables are mutually exclusive — + * they had to become storage. The consequence is worth stating plainly rather than + * discovering later: **URP's guarantees now hold subject to the proxy admin not being + * malicious.** An admin able to install new logic can rewrite every gate in this file. + * + * What that means in practice, and what it does NOT mean: + * - No function here can move `SESSION_ENGINE`, the gateway or the executor module. The + * only route to changing them is a full implementation swap by the admin. + * - The admin cannot reach `_configs` or `_credited` directly; it can only replace the code + * that reads them. Existing rules sets keep their caps until an upgrade says otherwise. + * - Storage layout is therefore load-bearing FOREVER. See the layout note on `__gap`. + * + * THE IMPLEMENTATION MUST NEVER BE INITIALISED DIRECTLY. Its constructor disables the + * initialiser for exactly that reason; an initialised implementation is a contract with a + * live config that the proxy does not know about. + */ +contract UniversalRulesPolicy is IUniversalRulesPolicy, Initializable { + /// @dev Maximum inner calls in one request. Bounds the gate-13 loop. + uint256 internal constant MAX_ACTIONS_PER_REQUEST = 10; + + /// @dev Maximum allow-list entries per config. Bounds the allow-list scan. + uint256 internal constant MAX_ALLOWED_CALLS = 32; + + /// @notice The gateway selector every agent action must carry. + /// @dev Part of this contract's ABI, so it stays a public constant. The value comes from the + /// shared gateway constant, so this policy and the wallet's grant-shape check cannot + /// disagree. + bytes4 public constant SEND_OUTBOUND_SELECTOR = GATEWAY_SEND_OUTBOUND_SELECTOR; + + /// @dev Smallest valid ABI encoding of a UniversalOutboundTxRequest argument list: + /// 32 (outer offset) + 256 (eight head words) + 32 + 32 (length words for the two empty + /// bytes fields). Do not hand-maintain: a test pins this against abi.encode of an empty + /// request, so a new struct field fails the build rather than loosening gate 4c. + uint256 internal constant MIN_OUTBOUND_BODY_LEN = 352; + + // ───────────────────────────── svm rulebook bounds ───────────────────────────── + + /// @dev Maximum allow-list entries per SVM config. Mirrors MAX_ALLOWED_CALLS. + uint256 internal constant MAX_ALLOWED_PROGRAMS = 32; + /// @dev Maximum account pins per SVM config. Bounds the S17 and S18 loops. + uint256 internal constant MAX_SVM_PINS = 16; + /// @dev Maximum ix_data pins per SVM config. + uint256 internal constant MAX_SVM_DATA_PINS = 8; + /// @dev Maximum CEA-controlled accounts an owner may list. Bounds the S18 loop. 16 = the CEA, one + /// token account per listed asset (MAX_ASSETS = 8) and up to 7 swap-output accounts. S18 gas + /// grows with the number actually listed, never with this bound. + uint256 internal constant MAX_CEA_ACCOUNTS = 16; + /// @dev Loop bound on a request's account list. Solana's transaction size limit bites first. + uint256 internal constant MAX_SVM_ACCOUNTS = 64; + /// @dev Loop bound on a request's instruction data. + uint256 internal constant MAX_SVM_IX_DATA = 1024; + + // The SVM payload grammar — the node's `decodePayload`, byte for byte: + // [u32 BE count][count × (pubkey32 ‖ is_writable u8)][u32 BE len][ix_data][u8 id][target32] + uint256 internal constant SVM_HEADER_LEN = 4; + uint256 internal constant SVM_ACCOUNT_LEN = 33; + uint256 internal constant SVM_LEN_FIELD = 4; + uint256 internal constant SVM_TRAILER_LEN = 33; + uint8 internal constant SVM_INSTRUCTION_EXECUTE = 2; + + // ───────────────────────────────── storage ───────────────────────────────── + // + // THE LAYOUT BELOW IS FROZEN. Behind a proxy, storage belongs to the proxy and outlives every + // implementation, so a new version may only APPEND — never reorder, never remove, never change + // a type. Doing so does not fail the build: it silently reinterprets live rules sets, which is + // the worst failure mode this system has. + // + // slot 0 UNIVERSAL_GATEWAY_PC + // slot 1 UNIVERSAL_EXECUTOR_MODULE + // slot 2 SESSION_ENGINE + // slot 3 _configs + // slot 4 _credited + // slot 5 _mode APPENDED 2026-09-09 (native mode) + // slot 6 _native APPENDED 2026-09-09 (native mode) + // slot 7 _svm APPENDED 2026-09-30 (svm rulebook) + // slots 8..49 __gap (uint256[42]) + // + // THE 2026-09-09 APPEND, AND WHY IT IS SAFE. `_mode` and `_native` were added AFTER `_credited` + // and `__gap` was shrunk 45 -> 43 in the same commit, so slots 0-4 are byte-identical to the + // deployed layout and `__gap` still ends at slot 49. Nothing that holds data moved. The + // alternative that was rejected — renaming `_configs` to `_universal` and inserting `_native` + // beside it — would have shifted `_credited` and silently reinterpreted the live idempotency + // set. Measured with `forge inspect` before the change, not assumed. + // + // `Initializable` adds nothing here: OZ 5.x keeps its initialisation flags in an ERC-7201 + // namespaced slot, not slot 0. A test pins this exact layout against solc's own output. + + /// @notice The one Push-side target any agent action may reach. + /// @dev Written once by `initialize`. No setter exists, here or anywhere. + address public UNIVERSAL_GATEWAY_PC; + + /// @notice The sole caller permitted to credit a failed outbound. + /// @dev Address unconfirmed against a live deployment; confirm before mainnet. It is an + /// initialiser argument, so nothing about building or testing depends on the real one. + address public UNIVERSAL_EXECUTOR_MODULE; + + /// @notice The multiplexer this contract trusts on every non-engine-driven path. + /// @dev Never accepted as a call argument: a wrong value would silently address an empty + /// slice. It is set once at initialisation and read from storage thereafter. + address public SESSION_ENGINE; + + /// @dev configId => multiplexer (the engine) => account (the wallet) => config. + /// @dev The configId already binds the account and the permission, so the middle level isolates + /// callers, not permissions. + /// @dev On the two engine-driven entry points the multiplexer is msg.sender; every other + /// function keys on SESSION_ENGINE. + mapping(ConfigId => mapping(address => mapping(address => Config))) internal _configs; + + /// @dev outbound tx id => credited already; idempotency for the refund path. + mapping(bytes32 => bool) internal _credited; + + /// @dev configId => multiplexer => account => which rulebook this config uses. + /// @dev THE MODE DISCRIMINATOR. Stored rather than derived from `_native[...].initialized`, + /// because a one-bit derived mode cannot grow: URP is upgradeable behind a proxy, and the + /// register's extensibility item points at MORE MODES. `ModeSlot.initialized` is + /// authoritative for emptiness; `mode` is meaningless when it is false. + mapping(ConfigId => mapping(address => mapping(address => ModeSlot))) internal _mode; + + /// @dev configId => multiplexer => account => the native rulebook. + /// @dev One entry per ACTION, not per rules set: a native rules set with eight actions writes eight + /// of these under eight distinct config ids. + mapping(ConfigId => mapping(address => mapping(address => NativeConfig))) internal _native; + + /// @dev configId => multiplexer => account => the SVM rulebook. + /// @dev APPENDED 2026-09-30 after `_native`; `__gap` shrunk 43 -> 42 in the same commit so it + /// still ends at slot 49. Slots 0-6 are byte-identical to the deployed layout. `ModeSlot` + /// gained a packed byte in the same change (see `ModeSlot.vm`); no member of any live + /// struct moved. Measured with the layout tests, not assumed. + mapping(ConfigId => mapping(address => mapping(address => SvmConfig))) internal _svm; + + /** + * @dev Reserved so a later version can add state without shifting anything above. + * + * Adding a variable means DECREMENTING this by exactly the number of slots consumed, in + * the same commit. A mapping or dynamic array costs one slot; a struct costs its packed + * size. `Config` itself lives inside a mapping, so APPENDING a field to that struct is + * safe and costs nothing here — reordering or removing one is not. + * + * Was `uint256[45]` before the 2026-09-09 native-mode append; `_mode` and `_native` took + * two slots, so it became 43. `_svm` took one more on 2026-09-30, so it is 42. `__gap` + * still ends at slot 49. + */ + uint256[42] private __gap; + + /** + * @notice Locks the implementation so it can never be initialised in its own context. + * + * @dev An implementation left initialisable is a live contract holding a config the proxy + * has no knowledge of. This is the standard guard and it is not optional. + */ + constructor() { + _disableInitializers(); + } + + /** + * @notice Pins the three addresses this policy trusts for its whole lifetime. + * + * @dev Runs once, in the PROXY's context, immediately after deployment. Reverts with + * `ZeroAddress` if any argument is zero, and with `InvalidInitialization` on any + * second call. + * + * Deploy and initialise atomically — pass this call as the TransparentUpgradeableProxy + * constructor's `_data`. A proxy deployed uninitialised is front-runnable: whoever + * calls `initialize` first chooses the engine this policy trusts. + * + * @param universalGatewayPC The one Push-side target agent actions may reach. + * @param universalExecutorModule The only caller permitted to credit a failed outbound. + * @param sessionEngine The multiplexer trusted on non-engine-driven paths. + */ + function initialize(address universalGatewayPC, address universalExecutorModule, address sessionEngine) + external + initializer + { + if (universalGatewayPC == address(0)) revert UniversalRulesPolicyErrors.ZeroAddress(); + if (universalExecutorModule == address(0)) revert UniversalRulesPolicyErrors.ZeroAddress(); + if (sessionEngine == address(0)) revert UniversalRulesPolicyErrors.ZeroAddress(); + + UNIVERSAL_GATEWAY_PC = universalGatewayPC; + UNIVERSAL_EXECUTOR_MODULE = universalExecutorModule; + SESSION_ENGINE = sessionEngine; + } + + /** + * @dev The mode of a config, from its `ModeSlot`, which every init writes. Read by every + * mode-sensitive entry point that is not `checkAction`. + * + * @return initialized true once any rulebook has been written for this config + * @return mode the rulebook; meaningless when `initialized` is false + */ + function _modeOf(ConfigId id, address mux, address account) + internal + view + returns (bool initialized, RulesType mode) + { + ModeSlot storage slot = _mode[id][mux][account]; + return (slot.initialized, slot.mode); + } + + /// @dev The family of a UNIVERSAL config. Meaningless for NATIVE and for empty slots; callers check + /// the mode first. + function _vmOf(ConfigId id, address mux, address account) internal view returns (VmFamily) { + return _mode[id][mux][account].vm; + } + + /** + * @notice Writes one permission's configuration. Reached inside `enableSessions` during the + * wallet's `grantRules`, where `msg.sender` becomes the multiplexer key. + * + * @dev - Refuses re-initialisation, a deliberate deviation from the upstream policy + * interface, which says a repeat call must overwrite. Do not restore overwrite + * semantics for interface fidelity. + * - This cannot break a legitimate regrant: the wallet supplies a fresh salt on every + * grant, so a regranted rules set has a new permission id and therefore an untouched + * config slot. The refusal only ever fires on a path this system does not use. + * - Rejects an allow-list that is empty or longer than the cap, an expiry that is zero + * or already past, a zero expected destination account, and an asset list that is + * empty, longer than MAX_ASSETS, repeats a token, or names a token whose source chain + * is not the declared chain. An owner consent term has no meaningful silence, so + * "never expires" is written as the maximum value. + * - Deliberately does not validate cap values (zero and max are both legal, a zero + * per-call cap being a valid move-nothing entry), `beneficiaryOffset`, or + * allow-list contents. A wrong offset fails closed at validation time; it cannot widen + * a rules set, only break it. Offsets must be generated from each protocol's ABI by + * tooling rather than hand-typed, and each newly supported protocol must ship a test + * rejecting a wrong beneficiary and an oversized amount. + * - Anyone may call this with themselves as the multiplexer; that writes into their own + * keyed slice and the engine never reads it. + * - Writes the config, sets the initialised flag, and emits `RulesConfigured` and + * `PolicySet`. + * + * - THE ENVELOPE. `initData` is `abi.encode(uint16 version, string chain, bytes body)` — + * IDENTICAL IN SHAPE FOR EVERY MODE, which is what lets the chain be read before the + * mode is known. Nobody declares the mode: URP derives it from the chain with + * `PushChainLib.deriveMode`, and the wallet derived the same value from the same bytes + * at grant. There is no mode byte and therefore no `InvalidPolicyMode`. + * - THE VERSION is read from the first word BEFORE anything else is decoded, and anything + * but `ENVELOPE_VERSION` is refused `UnsupportedEnvelopeVersion`. So a body layout can + * change later under a new version, and almost every malformed or pre-version blob is + * refused NAMED: a two-field `(string, bytes)` envelope reports version 64 (its string + * offset), a bare struct 32, a zeroed blob 0. Blobs shorter than one word, and a + * version-1 envelope whose body is the wrong `Terms` type, revert unnamed. Nothing + * mis-decodes into a live config — measured, one test per shape. + * - Re-initialisation is refused ACROSS MODES, and the guard runs BEFORE the decode, so + * a malformed blob aimed at a live config still gets a named `AlreadyInitialized`. + * + * @param account The wallet this config belongs to. + * @param configId Engine-derived id binding the account and the permission. + * @param initData `abi.encode(uint16 version, string chain, bytes body)`, body being + * `abi.encode(UniversalTerms)`, `abi.encode(SvmTerms)` or `abi.encode(NativeTerms)` + * according to the DERIVED mode and family. + */ + function initializeWithMultiplexer(address account, ConfigId configId, bytes calldata initData) external { + ModeSlot storage slot = _mode[configId][msg.sender][account]; + + // Re-initialisation would let the owner door reset a spend counter or flip a mode. + if (slot.initialized) revert UniversalRulesPolicyErrors.AlreadyInitialized(configId); + + // THE VERSION, from the first word, before anything else is decoded. + uint256 envelopeVersion = uint256(bytes32(initData[0:32])); + if (envelopeVersion != ENVELOPE_VERSION) { + revert UniversalRulesPolicyErrors.UnsupportedEnvelopeVersion(envelopeVersion); + } + + // THE ENVELOPE, decoded exactly as the wallet decoded it at grant — same expression, same + // bytes. That identity is the whole consistency argument: there is no second author of the + // discriminator, so there is nothing for the two contracts to disagree about. + (, string memory chainNamespace, bytes memory body) = abi.decode(initData, (uint16, string, bytes)); + if (bytes(chainNamespace).length == 0) revert UniversalRulesPolicyErrors.EmptyChain(); + + bytes32 chainHash = keccak256(bytes(chainNamespace)); + RulesType mode = PushChainLib.deriveMode(chainHash); + + // THE FAMILY, derived only for UNIVERSAL. A native string is `eip155:` too and would classify + // EVM, but NATIVE has no family and must not carry a meaningless one. `deriveVm` refuses any + // namespace without a rulebook, so a `cosmos:` grant fails here, named, instead of producing + // a rules set that passes init and rejects every request. + VmFamily vm = VmFamily.EVM; + if (mode == RulesType.UNIVERSAL) { + vm = PushChainLib.deriveVm(chainNamespace); + if (vm == VmFamily.EVM) { + _initUniversal(_configs[configId][msg.sender][account], body, chainHash); + } else { + _initSvm(_svm[configId][msg.sender][account], body, chainHash); + } + } else { + _initNative(_native[configId][msg.sender][account], body); + } + + slot.initialized = true; + slot.mode = mode; + slot.vm = vm; + slot.chainHash = chainHash; + + emit RulesConfigured(configId, msg.sender, account, mode, vm, chainHash); + emit PolicySet(configId, msg.sender, account); + } + + /// @inheritdoc IUniversalRulesPolicy + function pushChainHash() external view returns (bytes32) { + return PushChainLib.selfChainHash(); + } + + /** + * @dev The universal init guards — unchanged from the single-mode contract, only relocated. + * @param cfg Storage slot to write. + * @param body `abi.encode(Config)`. + */ + function _initUniversal(Config storage cfg, bytes memory body, bytes32 chainHash) internal { + UniversalTerms memory incoming = abi.decode(body, (UniversalTerms)); + + uint256 listLength = incoming.allowedCalls.length; + if (listLength == 0 || listLength > MAX_ALLOWED_CALLS) { + revert UniversalRulesPolicyErrors.AllowListOutOfRange(listLength); + } + + if (incoming.validUntil == 0 || incoming.validUntil <= block.timestamp) { + revert UniversalRulesPolicyErrors.InvalidExpiry(incoming.validUntil); + } + if (incoming.expectedCEA == address(0)) revert UniversalRulesPolicyErrors.InvalidConfigField(); + + // ─── THE TEETH ─── + // + // After every decode and guard, before every write. Effects last, as everywhere else here. + // + // WHY THIS MAKES THE DECLARED CHAIN TRUE AT RUNTIME. `SOURCE_CHAIN_NAMESPACE()` is the exact + // view the gateway reads on every outbound, through `UniversalCore.getOutboundTxGasAndFees`, + // to decide where to route. Gate 5 pins `req.token` to a LISTED asset on every request, zero + // amount included. So asserting it here, for EVERY listed asset, binds the owner's declared + // chain to the chain the gateway will actually use — with no runtime change and no external + // call in `checkAction`. It is also why the list may never be empty: an empty list would pin + // no token, and the agent would choose the chain. + // + // WHY AN EXTERNAL CALL IS SAFE HERE AND NOWHERE ELSE: this runs at INIT, inside the owner's + // own grant transaction, never in `checkAction` and never on a removal path. A failure + // blocks a grant; it can never block a revocation or an execution. The `try/catch` is + // permitted because the external call ALREADY EXISTS — do not extend that reasoning to + // `checkAction`'s decode, which has no external call to hide behind. + // + // A `view` call compiles to STATICCALL, so the callee cannot write state: reentrancy from a + // hostile asset is structurally impossible, not merely unreachable. + // + // ⚠️ THE `code.length` GUARD IS NOT REDUNDANT WITH THE `catch`. MEASURED: + // callee reverts -> catch fires -> named InvalidAsset + // no code at the address, or EOA -> catch does NOT -> UNNAMED, empty revert + // answers with a non-string -> catch does NOT -> UNNAMED, empty revert + // Since solc 0.8.10 the compiler omits the extcodesize check when return data is + // expected; the call to a codeless address then SUCCEEDS with empty returndata and the + // failure happens when THIS frame tries to ABI-decode it — outside the try/catch. Without + // this line a typo'd asset address, the likeliest real mistake, reverts unnamed. + _requireAssets(incoming.assets, chainHash); + + _store(cfg, incoming); + cfg.initialized = true; + } + + /** + * @dev The asset-list guards, shared by both universal families: 1..MAX_ASSETS entries, no token + * twice, and THE TEETH for every entry. A zero token fails the teeth as `InvalidAsset(0)`. + * O(n^2) duplicate check at n <= 8. + */ + function _requireAssets(AssetCap[] memory assets, bytes32 chainHash) internal view { + uint256 n = assets.length; + if (n == 0 || n > MAX_ASSETS) revert UniversalRulesPolicyErrors.AssetListOutOfRange(n); + for (uint256 i; i < n;) { + address token = assets[i].token; + for (uint256 j; j < i;) { + if (assets[j].token == token) revert UniversalRulesPolicyErrors.DuplicateAsset(token); + unchecked { + ++j; + } + } + _requireAssetOnChain(token, chainHash); + unchecked { + ++i; + } + } + } + + /** + * @dev THE TEETH, shared by both universal families. Reverts `InvalidAsset` for a codeless + * address, a reverting callee or a non-string answer, and `ChainMismatch` when the asset's + * own `SOURCE_CHAIN_NAMESPACE()` hash differs from the declared chain. See the long note + * in `_initUniversal` for why this external call is safe at init and nowhere else. + */ + function _requireAssetOnChain(address asset, bytes32 chainHash) internal view { + if (asset.code.length == 0) revert UniversalRulesPolicyErrors.InvalidAsset(asset); + + try IPRC20Source(asset).SOURCE_CHAIN_NAMESPACE() returns (string memory ns) { + bytes32 assetChain = keccak256(bytes(ns)); + if (assetChain != chainHash) revert UniversalRulesPolicyErrors.ChainMismatch(chainHash, assetChain); + } catch { + revert UniversalRulesPolicyErrors.InvalidAsset(asset); + } + } + + /** + * @dev The native init guards. + * + * - Refuses a zero target, and the GATEWAY as a target: the mirror of gate 3, and half of + * the consistency lock. A native config can never be written against the gateway. + * - Refuses a value-only config carrying pins or an amount rule. That combination can never + * authorise anything — every request under it would die at N7/N8 — so it is a + * misconfiguration the owner believes they granted, not a valid ascetic config. Same + * reasoning as the empty-allow-list refusal in universal mode. + * - Deliberately does NOT validate cap values (zero and max are both legal), pin offsets or + * `amount.offset` — they cannot be checked against calldata that does not exist yet, and a + * wrong offset fails closed at N7/N8 rather than widening anything. Nor the selector + * against the engine's fallback flags: the wallet refuses those at grant, and a + * stranger-slice config the engine never reads is harmless. + * + * - MAKES NO EXTERNAL CALL. A native rules set has no asset, so there is nothing to verify the + * chain against — and nothing to verify: the chain IS this chain, which is what made the + * mode NATIVE in the first place. The universal branch's teeth have no native counterpart + * and must not acquire one. + * + * @param cfg Storage slot to write. + * @param body `abi.encode(NativeTerms)`. + */ + function _initNative(NativeConfig storage cfg, bytes memory body) internal { + NativeTerms memory incoming = abi.decode(body, (NativeTerms)); + + if (incoming.validUntil == 0 || incoming.validUntil <= block.timestamp) { + revert UniversalRulesPolicyErrors.InvalidExpiry(incoming.validUntil); + } + if (incoming.target == address(0)) revert UniversalRulesPolicyErrors.NativeTargetZero(); + if (incoming.target == UNIVERSAL_GATEWAY_PC) { + revert UniversalRulesPolicyErrors.NativeTargetIsGateway(incoming.target); + } + if (incoming.pins.length > MAX_PINS) revert UniversalRulesPolicyErrors.TooManyPins(incoming.pins.length); + + if (incoming.selector == VALUE_SELECTOR) { + if (incoming.pins.length != 0) revert UniversalRulesPolicyErrors.ValueOnlyWithPins(); + if (incoming.amount.enabled) revert UniversalRulesPolicyErrors.ValueOnlyWithAmountRule(); + } + + _storeNative(cfg, incoming); + cfg.initialized = true; + } + + /** + * @dev The SVM init guards — the `solana:*` counterpart of `_initUniversal`. + * - Shape bounds first, then expiry and the three identity fields, then the allow-list + * rules, then the pins, then the teeth. Same discipline as the universal branch: every + * decode and guard before any write. + * - The teeth are IDENTICAL to the universal branch and for the same reason: each listed + * asset's `SOURCE_CHAIN_NAMESPACE()` is what the gateway routes on, so binding the declared + * chain to every one of them here is what makes a `solana:` grant with an EVM asset impossible. + * @param cfg Storage slot to write. + * @param body `abi.encode(SvmTerms)`. + * @param chainHash keccak256 of the declared chain string, verified against every listed asset. + */ + function _initSvm(SvmConfig storage cfg, bytes memory body, bytes32 chainHash) internal { + SvmTerms memory incoming = abi.decode(body, (SvmTerms)); + + uint256 ruleCount = incoming.programs.length; + if (ruleCount == 0 || ruleCount > MAX_ALLOWED_PROGRAMS) { + revert UniversalRulesPolicyErrors.ProgramListOutOfRange(ruleCount); + } + if (incoming.pins.length > MAX_SVM_PINS) { + revert UniversalRulesPolicyErrors.TooManySvmPins(incoming.pins.length); + } + if (incoming.dataPins.length > MAX_SVM_DATA_PINS) { + revert UniversalRulesPolicyErrors.TooManySvmDataPins(incoming.dataPins.length); + } + if (incoming.ceaAccounts.length > MAX_CEA_ACCOUNTS) { + revert UniversalRulesPolicyErrors.TooManyCeaAccounts(incoming.ceaAccounts.length); + } + + if (incoming.validUntil == 0 || incoming.validUntil <= block.timestamp) { + revert UniversalRulesPolicyErrors.InvalidExpiry(incoming.validUntil); + } + if (incoming.expectedCEA == bytes32(0) || incoming.gatewayProgram == bytes32(0)) { + revert UniversalRulesPolicyErrors.InvalidSvmConfigField(); + } + + _checkSvmRules(incoming); + _checkSvmPinShapes(incoming); + _checkCeaAccountList(incoming); + + _requireAssets(incoming.assets, chainHash); + + _storeSvm(cfg, incoming); + cfg.initialized = true; + } + + /** + * @dev Allow-list rule guards: tag shape, forbidden programs, and pairwise exactness. + * - A rule is `dataless` XOR has a 1..8-byte tag. + * - A fixed account count, if set, is within the S13 bound. + * - A program the check path forbids as a target is refused here too; S15 is then defence + * in depth against state this guard makes unreachable. + * - Two rules on one program must not both match one request, or first-match makes the + * later rule dead and its pins never run. O(n^2) at n <= 32. + */ + function _checkSvmRules(SvmTerms memory t) internal pure { + uint256 n = t.programs.length; + for (uint256 i; i < n;) { + AllowedProgram memory r = t.programs[i]; + bool badLen = r.dataless ? r.discriminatorLen != 0 : (r.discriminatorLen == 0 || r.discriminatorLen > 8); + if (badLen) revert UniversalRulesPolicyErrors.DiscriminatorLenOutOfRange(i, r.discriminatorLen); + // A fixed count above the S13 loop bound can never be met: every request would fail + // S13 or S16. Refused here so the owner never grants a rule that is dead on arrival. + if (r.maxAccounts > MAX_SVM_ACCOUNTS) { + revert UniversalRulesPolicyErrors.SvmMaxAccountsOutOfRange(i, r.maxAccounts); + } + if (_isForbiddenProgram(r.program, t.gatewayProgram, t.expectedCEA)) { + revert UniversalRulesPolicyErrors.ForbiddenProgramInAllowList(i, r.program); + } + for (uint256 j; j < i;) { + if (_rulesCollide(t.programs[j], r)) revert UniversalRulesPolicyErrors.AmbiguousRule(j, i); + unchecked { + ++j; + } + } + unchecked { + ++i; + } + } + } + + /// @dev Two rules collide when a single request could match both: same program and either both + /// dataless, or neither dataless with one tag a prefix of the other. A dataless rule and a + /// tagged rule never collide — one needs empty ix_data, the other needs at least the tag. + function _rulesCollide(AllowedProgram memory a, AllowedProgram memory b) internal pure returns (bool) { + if (a.program != b.program) return false; + if (a.dataless || b.dataless) return a.dataless && b.dataless; + uint256 shorter = a.discriminatorLen < b.discriminatorLen ? a.discriminatorLen : b.discriminatorLen; + bytes8 mask = _prefixMask8(shorter); + return (a.discriminator & mask) == (b.discriminator & mask); + } + + /** + * @dev Pin shape guards, both kinds. + * - Account pins: rule in range; index below the loop bound and, when the rule fixes its + * account count, below that too. Every rule must own at least one — HYGIENE: an + * authority-only pin always passes, and which positions must be pinned is the compiler's + * responsibility, not this contract's. + * One pin per (rule, index). + * - Data pins: rule in range and not dataless; `len` 1..32 for EQ, 1..8 otherwise; from-end + * offsets must reach at least `len` back; every offset stays inside the ix_data bound; + * the comparison value must be one the field can actually be compared against + * (`_dataPinValueValid`). + */ + function _checkSvmPinShapes(SvmTerms memory t) internal pure { + uint256 ruleCount = t.programs.length; + bool[] memory covered = new bool[](ruleCount); // rule i has at least one account pin + + uint256 n = t.pins.length; + for (uint256 i; i < n;) { + SvmAccountPin memory pin = t.pins[i]; + if (pin.ruleIndex >= ruleCount) revert UniversalRulesPolicyErrors.SvmPinRuleOutOfRange(i, pin.ruleIndex); + uint8 cap = t.programs[pin.ruleIndex].maxAccounts; + if (pin.accountIndex >= MAX_SVM_ACCOUNTS || (cap != 0 && pin.accountIndex >= cap)) { + revert UniversalRulesPolicyErrors.SvmPinIndexOutOfRange(i, pin.accountIndex); + } + // One position, one pin. Two pins on a (rule, index) are either redundant or + // contradictory, and a contradictory pair makes the rule unsatisfiable. O(n^2), n <= 16. + for (uint256 j; j < i;) { + if (t.pins[j].ruleIndex == pin.ruleIndex && t.pins[j].accountIndex == pin.accountIndex) { + revert UniversalRulesPolicyErrors.DuplicateSvmPin(j, i); + } + unchecked { + ++j; + } + } + covered[pin.ruleIndex] = true; + unchecked { + ++i; + } + } + for (uint256 r; r < ruleCount;) { + if (!covered[r]) revert UniversalRulesPolicyErrors.RuleWithoutPin(r); + unchecked { + ++r; + } + } + + n = t.dataPins.length; + for (uint256 i; i < n;) { + SvmDataPin memory dp = t.dataPins[i]; + if (dp.ruleIndex >= ruleCount || t.programs[dp.ruleIndex].dataless) { + revert UniversalRulesPolicyErrors.SvmDataPinInvalid(i); + } + uint256 maxLen = dp.mode == SvmDataPinMode.EQ ? 32 : 8; + if (dp.len == 0 || dp.len > maxLen) revert UniversalRulesPolicyErrors.SvmDataPinInvalid(i); + if (!_offsetValid(dp.fromEnd, dp.offset, dp.len)) revert UniversalRulesPolicyErrors.SvmDataPinInvalid(i); + if (!_dataPinValueValid(dp)) revert UniversalRulesPolicyErrors.SvmDataPinInvalid(i); + unchecked { + ++i; + } + } + } + + /// @dev A from-start field must end inside the bound; a from-end field must start at least `len` + /// back and no further back than the bound. + function _offsetValid(bool fromEnd, uint16 offset, uint8 len) internal pure returns (bool) { + if (fromEnd) return uint256(offset) >= len && uint256(offset) <= MAX_SVM_IX_DATA; + return uint256(offset) + len <= MAX_SVM_IX_DATA; + } + + /** + * @dev Refuses a data pin whose comparison is vacuous or impossible, and the encoding mistake that + * would make it so. The two value encodings differ by mode — EQ compares LEFT-ALIGNED raw + * bytes, the integer modes compare a RIGHT-ALIGNED integer — and each mis-encoding of one + * as the other is caught here, at grant, instead of producing a pin that silently never + * fails (a ceiling above the field's range) or never passes. + * - EQ: every byte of `expected` past `len` must be zero (a right-aligned integer would + * leave its value there). + * - GTE / LTE: `expected` must fit in `len` bytes, i.e. `< 2^(8·len)`. + * - RATIO: `num` and `den` non-zero (`num == 0` makes `a·den >= 0` always true), and the + * second field's offset valid. + */ + function _dataPinValueValid(SvmDataPin memory dp) internal pure returns (bool) { + if (dp.mode == SvmDataPinMode.EQ) return dp.expected & ~_prefixMask32(dp.len) == bytes32(0); + if (dp.mode == SvmDataPinMode.RATIO_GTE_LE) { + return dp.num != 0 && dp.den != 0 && _offsetValid(dp.fromEnd, dp.offsetB, dp.len); + } + return uint256(dp.expected) >> (8 * uint256(dp.len)) == 0; + } + + /** + * @dev The CEA-controlled account list that S18 enforces. + * - Must contain `expectedCEA`. The CEA always holds value (it is the signer, and pSOL lands + * on it), so an empty or CEA-less list would silently switch the aliasing defence off. + * - No zero entry: `bytes32(0)` is the System program's id, present in most account lists, + * and would make every request fail. + * - No entry equal to an allow-listed program: Anchor passes the program's own account in + * many instructions, and listing it would make every such request fail. + * - No duplicates. + * All four fail closed at check time anyway; refusing them here means an owner never grants + * a rules set that can never be used. + */ + function _checkCeaAccountList(SvmTerms memory t) internal pure { + uint256 n = t.ceaAccounts.length; + bool hasCea; + for (uint256 i; i < n;) { + bytes32 key = t.ceaAccounts[i]; + if (key == bytes32(0)) revert UniversalRulesPolicyErrors.InvalidCeaAccount(i); + if (key == t.expectedCEA) hasCea = true; + for (uint256 j; j < i;) { + if (t.ceaAccounts[j] == key) revert UniversalRulesPolicyErrors.InvalidCeaAccount(i); + unchecked { + ++j; + } + } + uint256 rules = t.programs.length; + for (uint256 r; r < rules;) { + if (t.programs[r].program == key) revert UniversalRulesPolicyErrors.InvalidCeaAccount(i); + unchecked { + ++r; + } + } + unchecked { + ++i; + } + } + if (!hasCea) revert UniversalRulesPolicyErrors.CeaAccountsMissExpectedCEA(); + } + + /// @dev The programs an SVM rules set may never target, directly. Inner CPIs are the allow-listed + /// program's own business — this set guards the top level only. + function _isForbiddenProgram(bytes32 program, bytes32 gatewayProgram, bytes32 cea) internal pure returns (bool) { + return program == SYSTEM_PROGRAM || program == SPL_TOKEN_PROGRAM || program == TOKEN_2022_PROGRAM + || program == STAKE_PROGRAM || program == BPF_LOADER_UPGRADEABLE || program == ADDRESS_LOOKUP_TABLE + || program == gatewayProgram || program == cea; + } + + /** + * @notice Runs every gate a cross-chain agent request must pass. Order is fixed; any failure + * reverts with nothing written. + * + * @dev - Not `view`: gate 7 accumulates spend, and the engine invokes this with a real call + * so the write persists. + * - Runs before the session signature is verified, on unauthenticated calldata from an + * arbitrary caller. It is safe because it makes no external call, applies all effects + * last, and reverts on every failure. Do not introduce an external call here. + * - Replayed signatures cannot burn budget through this door; they die at the wallet's + * nonce gate first. + * + * The gates, in order: + * 1. the config is initialised + * 2. the rules set has not expired + * 3. the target is the gateway + * 4. calldata is at least four bytes; the selector is the outbound send; the body is at + * least the minimum encoded length + * 5. the token is one of the listed assets — on EVERY request, zero amount included, + * because the token is what the gateway routes by + * 6. the amount is within THAT asset's per-call cap + * 7. THAT asset's running total is within its lifetime cap + * 8. the Push-native value is within the per-call ceiling (`maxGasPerCall`) + * 9. the request does not ask for an uncapped gas swap + * 10. the revert recipient is the wallet + * 11. the recipient field is empty + * 12. the payload is a multicall + * 13. the inner call count is between one and the maximum + * 14. no inner call targets the wallet, this policy, the gateway or the destination + * account + * 15. each inner target and selector is allow-listed, and where the rule declares a + * beneficiary it matches the expected destination account + * 16. each inner value is within its rule's allowance + * + * - A zero amount passes gate 6 and writes nothing: zero-amount is the redeployment + * path, acting on capital already at the destination. There is no zero-amount gate and + * one must not be added. + * - `abi.decode` ignores trailing bytes, so gate 4c is a length floor and not a + * canonical-encoding check. There is no exploit: the whole execution calldata is bound + * into the wallet's operation hash, and the signature is verified last. + * - A body of correct length carrying malformed internal offsets reverts with a compiler + * panic rather than a named error. It cannot be given a named error without wrapping + * the decode in an external call, which this function must not have. + * - Spend accumulation is optimistic but atomic: it is written during validation and + * survives only because validation and dispatch share one transaction. Splitting them + * breaks the accounting silently. + * - Gate 14 runs before gate 15 on purpose, so a forbidden destination beats the + * allow-list: an owner who allow-listed their own destination account still cannot + * hand the agent direct control of it. + * + * @param id Config id identifying the rules set. + * @param account The wallet. The engine passes its own caller through as this parameter, so it + * is never the engine itself. + * @param target Push-side call target; must be the gateway. + * @param value Push-native value attached to the call. + * @param data The gateway calldata, opened and walked by the gates above. + * @return The engine's success sentinel. + */ + function checkAction(ConfigId id, address account, address target, uint256 value, bytes calldata data) + external + returns (uint256) + { + // MODE ROUTING. An EMPTY slot falls through to the universal path, whose gate 1 reverts + // `NotInitialized` — fail-closed either way. The `initialized &&` conjunction is what makes + // that safe: `RulesType.UNIVERSAL` is the zero value, so testing `mode` alone could not + // tell an empty slot from a real universal one. + ModeSlot storage slot = _mode[id][msg.sender][account]; + if (slot.initialized) { + if (slot.mode == RulesType.NATIVE) return _checkNative(id, account, target, value, data); + // The family byte was never written by earlier implementations, so it reads 0 = EVM on + // every pre-existing universal slot — those keep routing exactly where they always did. + if (slot.vm == VmFamily.SVM) return _checkSvm(id, account, target, value, data); + } + return _checkUniversal(id, account, target, value, data); + } + + /** + * @dev The universal gauntlet — gates 1 to 16, unchanged from the single-mode contract. Only the + * function name and visibility changed; the body is byte-for-byte what `checkAction` was. + * + * @param id Config id identifying the rules set. + * @param account The wallet. + * @param target Push-side call target; must be the gateway. + * @param value Push-native value attached to the call. + * @param data The gateway calldata. + * @return The engine's success sentinel. + */ + function _checkUniversal(ConfigId id, address account, address target, uint256 value, bytes calldata data) + internal + returns (uint256) + { + Config storage cfg = _configs[id][msg.sender][account]; + + if (!cfg.initialized) revert UniversalRulesPolicyErrors.NotInitialized(id, account); + + if (block.timestamp > cfg.validUntil) revert UniversalRulesPolicyErrors.RulesExpired(cfg.validUntil); + + if (target != UNIVERSAL_GATEWAY_PC) revert UniversalRulesPolicyErrors.InvalidTarget(target); + + if (data.length < 4) revert UniversalRulesPolicyErrors.CalldataTooShort(data.length); + + if (bytes4(data[0:4]) != SEND_OUTBOUND_SELECTOR) { + revert UniversalRulesPolicyErrors.InvalidSelector(bytes4(data[0:4])); + } + + if (data.length < 4 + MIN_OUTBOUND_BODY_LEN) { + revert UniversalRulesPolicyErrors.MalformedOutboundRequest(data.length); + } + UniversalOutboundTxRequest memory req = abi.decode(data[4:], (UniversalOutboundTxRequest)); + + AssetCapState storage cap = _assetFor(cfg.assets, req.token); + + if (req.amount > cap.maxPerCall) { + revert UniversalRulesPolicyErrors.AmountExceedsCap(req.amount, cap.maxPerCall); + } + + uint256 newSpent = cap.spent + req.amount; + if (newSpent > cap.maxTotal) revert UniversalRulesPolicyErrors.TotalSpendCapExceeded(newSpent, cap.maxTotal); + + if (value > cfg.maxGasPerCall) revert UniversalRulesPolicyErrors.PCValueExceedsCap(value, cfg.maxGasPerCall); + + if (req.maxPCForGas == 0) revert UniversalRulesPolicyErrors.UncappedGasSwapRejected(); + + if (req.revertRecipient != account) { + revert UniversalRulesPolicyErrors.InvalidRevertRecipient(account, req.revertRecipient); + } + + if (req.recipient.length != 0) revert UniversalRulesPolicyErrors.RecipientMustBeEmpty(); + + _checkInnerCalls(cfg, account, req.payload); + + if (req.amount > 0) { + cap.spent = newSpent; + emit OutboundMetered(id, msg.sender, account, req.token, req.amount); + } + + return VALIDATION_SUCCESS; + } + + /** + * @dev The native gauntlet — gates N1 to N9, then effects. The same discipline as the universal + * path and for the same reason: this runs BEFORE the session signature is verified, on + * unauthenticated calldata from an arbitrary caller. + * + * - NO EXTERNAL CALLS. Pins and the metered amount are read by slicing `data` directly, + * never through `_slice` into memory and never through a helper that calls out. + * - ALL EFFECTS LAST. `newValueSpent` and `newAmountSpent` are computed at N6/N8 and + * assigned only after N9 passes, exactly as `_checkUniversal` handles `newSpent`. A + * request that fails at N7 leaves every counter untouched. + * - BOUNDS ARITHMETIC IS DONE IN `uint256`. `pin.offset` is `uint16`, so + * `uint256(offset) + 32` cannot wrap — but written as `uint16` arithmetic it would, and + * the check would pass on a crafted offset. Do not "simplify" the cast away. + * - `callsUsed` ALWAYS increments on success, including on a zero-value zero-amount call. + * A call is a use; mirroring universal's zero-amount rule (which writes nothing) would + * make `maxCalls` bypassable by zero-value calls, i.e. advisory. This is the one + * deliberate divergence between the two rulebooks. + * - Value-only configs carry no pins and no amount rule — init refuses that combination — + * so with `data.length == 0` the N7 loop does not execute and N8 is skipped. + * + * @param id Config id identifying the rules set. + * @param account The wallet. + * @param target Push-side call target; must be the configured native target. + * @param value Push-native value attached to the call. + * @param data The native calldata, read but never decoded as a structure. + * @return The engine's success sentinel. + */ + function _checkNative(ConfigId id, address account, address target, uint256 value, bytes calldata data) + internal + returns (uint256) + { + NativeConfig storage cfg = _native[id][msg.sender][account]; + + // N1 + if (!cfg.initialized) revert UniversalRulesPolicyErrors.NotInitialized(id, account); + + // N2 + if (block.timestamp > cfg.validUntil) revert UniversalRulesPolicyErrors.RulesExpired(cfg.validUntil); + + // N3 — the consistency lock, mirror of universal gate 3. Init refuses a gateway target, so + // this can only fire on state the wallet's grant check makes unreachable. It is defence in + // depth against a mis-wired grant, not dead code. + if (target == UNIVERSAL_GATEWAY_PC) revert UniversalRulesPolicyErrors.NativeTargetIsGateway(target); + + // N4 + if (target != cfg.target) revert UniversalRulesPolicyErrors.TargetMismatch(target, cfg.target); + + // N5 — under four bytes is the engine's value-only selector; four or more is a real one. + bytes4 sel = data.length < 4 ? VALUE_SELECTOR : bytes4(data[0:4]); + if (sel != cfg.selector) revert UniversalRulesPolicyErrors.SelectorMismatch(sel, cfg.selector); + // Value-only means EMPTY calldata (register N-46). The engine buckets 1..3 bytes under the + // same actionId, so URP is the layer that makes the documented meaning true. + if (sel == VALUE_SELECTOR && data.length != 0) { + revert UniversalRulesPolicyErrors.ValueOnlyCalldataNotEmpty(data.length); + } + + // N6 + if (value > cfg.maxValuePerCall) revert UniversalRulesPolicyErrors.ValueExceedsCap(value, cfg.maxValuePerCall); + uint256 newValueSpent = cfg.valueSpent + value; + if (newValueSpent > cfg.maxValueTotal) { + revert UniversalRulesPolicyErrors.TotalValueExceeded(newValueSpent, cfg.maxValueTotal); + } + + // N7 + uint256 pinCount = cfg.pins.length; + for (uint256 i; i < pinCount;) { + ArgPin storage pin = cfg.pins[i]; + uint256 needed = uint256(pin.offset) + 32; + if (data.length < needed) revert UniversalRulesPolicyErrors.CalldataTooShortForPin(data.length, i, needed); + + bytes32 actual = bytes32(data[pin.offset:needed]); + if (actual != pin.expected) revert UniversalRulesPolicyErrors.ArgPinMismatch(actual, i, pin.expected); + + unchecked { + ++i; + } + } + + // N8 + uint256 amt; + uint256 newAmountSpent = cfg.amountSpent; + if (cfg.amount.enabled) { + uint256 neededAmt = uint256(cfg.amount.offset) + 32; + if (data.length < neededAmt) { + revert UniversalRulesPolicyErrors.CalldataTooShortForAmount(data.length, neededAmt); + } + + amt = uint256(bytes32(data[cfg.amount.offset:neededAmt])); + if (amt > cfg.amount.maxPerCall) { + revert UniversalRulesPolicyErrors.NativeAmountExceedsCap(amt, cfg.amount.maxPerCall); + } + + newAmountSpent = cfg.amountSpent + amt; + if (newAmountSpent > cfg.amount.maxTotal) { + revert UniversalRulesPolicyErrors.TotalNativeAmountExceeded(newAmountSpent, cfg.amount.maxTotal); + } + } + + // N9 + if (cfg.maxCalls != 0 && cfg.callsUsed >= cfg.maxCalls) { + revert UniversalRulesPolicyErrors.CallLimitReached(cfg.callsUsed, cfg.maxCalls); + } + + // Effects, last. + cfg.valueSpent = newValueSpent; + cfg.amountSpent = newAmountSpent; + unchecked { + // Bounded by N9 when maxCalls != 0; when it is 0 the counter is informational and a + // uint32 overflow is unreachable at any realistic call volume. + cfg.callsUsed = cfg.callsUsed + 1; + } + emit NativeCallMetered(id, msg.sender, account, value, amt); + + return VALIDATION_SUCCESS; + } + + /** + * @dev Implements gates 12 to 16 of `checkAction`'s list. + * + * - Split out for stack depth only. It makes no external call and writes no storage, so the + * caller's effects-last property holds. + * - Gate 12 is not merely a format check: the destination account dispatches on the payload + * prefix, and only the multicall branch has entries that gates 13 to 16 can walk. Its + * other branches re-target the account itself or call an arbitrary target with the raw + * payload, bypassing the allow-list, the beneficiary pin and the per-entry value cap. + * Do not weaken this gate, or the agent picks its own branch. + * - A payload that is exactly the multicall selector, or the selector followed by malformed + * bytes, reverts inside the ABI decoder rather than with a named error. No minimum-length + * pre-check is added: unlike gate 4c, this decode sits behind eleven gates on an already + * constrained request, so a second hand-derived constant would be more surface than the + * named error is worth. It fails closed either way. + * + * @param cfg Config to validate against. + * @param account The wallet, used as the forbidden self-target and the refund destination. + * @param payload The multicall payload carried by the outbound request. + */ + function _checkInnerCalls(Config storage cfg, address account, bytes memory payload) internal view { + if (payload.length < 4 || bytes4(_slice(payload, 0, 4)) != MULTICALL_SELECTOR) { + revert UniversalRulesPolicyErrors.PayloadNotMulticall(); + } + + Multicall[] memory calls = abi.decode(_slice(payload, 4, payload.length - 4), (Multicall[])); + + uint256 count = calls.length; + if (count == 0 || count > MAX_ACTIONS_PER_REQUEST) { + revert UniversalRulesPolicyErrors.BatchSizeOutOfRange(count); + } + + address expectedCEA = cfg.expectedCEA; + + for (uint256 i; i < count;) { + Multicall memory entry = calls[i]; + + if ( + entry.to == account || entry.to == address(this) || entry.to == UNIVERSAL_GATEWAY_PC + || entry.to == expectedCEA + ) { + revert UniversalRulesPolicyErrors.ForbiddenInnerTarget(entry.to); + } + if (entry.data.length < 4) revert UniversalRulesPolicyErrors.MalformedInnerCalldata(); + + AllowedCall memory rule = _requireAllowed(cfg, entry.to, bytes4(_slice(entry.data, 0, 4))); + if (rule.hasBeneficiary) { + address beneficiary = _extractBeneficiary(entry.data, rule.beneficiaryOffset); + if (beneficiary != expectedCEA) { + revert UniversalRulesPolicyErrors.BeneficiaryMismatch(expectedCEA, beneficiary); + } + } + + // Destination-chain native units, never the Push-side value: two assets on two chains. + if (entry.value > rule.maxValue) { + revert UniversalRulesPolicyErrors.InnerValueExceedsAllowance(i, entry.value, rule.maxValue); + } + + unchecked { + ++i; + } + } + } + + /** + * @dev The SVM gauntlet — S1 to S18, then effects. Same discipline as the other two: it runs + * BEFORE the session signature is verified, on unauthenticated calldata from an arbitrary + * caller, so it makes no external call, applies all effects last, and reverts on every + * failure. + * + * S1-S10 are the universal gates 1-10 restated against `SvmConfig` — they are chain- + * independent. S6b is Solana's u64 amount. S11 onwards replace gates 11-16: + * + * S11 the recipient is a 32-byte, non-zero pubkey (the target program) + * S12 the payload is non-empty and parses as the node's execute grammar, exactly + * S13 instruction_id is 2 (execute); account count and ix_data length are within bounds + * S14 the payload's target program equals the recipient + * S15 the target is not a forbidden program + * S16 a rule matches (program, tag) — first match — and its account count, if fixed, holds + * S17 every account pin and every data pin of that rule holds + * S18 every CEA-controlled account in the list sits only where that rule pins it + * + * - A zero amount passes S6/S7 and writes nothing: on SVM that is a payload-only call + * acting on capital already at the destination, the analogue of the EVM redeploy path. + * - The forbidden-program check runs before the allow-list, as gate 14 runs before 15. + */ + function _checkSvm(ConfigId id, address account, address target, uint256 value, bytes calldata data) + internal + returns (uint256) + { + SvmConfig storage cfg = _svm[id][msg.sender][account]; + + if (!cfg.initialized) revert UniversalRulesPolicyErrors.NotInitialized(id, account); + + if (block.timestamp > cfg.validUntil) revert UniversalRulesPolicyErrors.RulesExpired(cfg.validUntil); + + if (target != UNIVERSAL_GATEWAY_PC) revert UniversalRulesPolicyErrors.InvalidTarget(target); + + if (data.length < 4) revert UniversalRulesPolicyErrors.CalldataTooShort(data.length); + + if (bytes4(data[0:4]) != SEND_OUTBOUND_SELECTOR) { + revert UniversalRulesPolicyErrors.InvalidSelector(bytes4(data[0:4])); + } + + if (data.length < 4 + MIN_OUTBOUND_BODY_LEN) { + revert UniversalRulesPolicyErrors.MalformedOutboundRequest(data.length); + } + UniversalOutboundTxRequest memory req = abi.decode(data[4:], (UniversalOutboundTxRequest)); + + AssetCapState storage cap = _assetFor(cfg.assets, req.token); + + if (req.amount > cap.maxPerCall) { + revert UniversalRulesPolicyErrors.AmountExceedsCap(req.amount, cap.maxPerCall); + } + + if (req.amount > type(uint64).max) revert UniversalRulesPolicyErrors.AmountExceedsU64(req.amount); + + uint256 newSpent = cap.spent + req.amount; + if (newSpent > cap.maxTotal) revert UniversalRulesPolicyErrors.TotalSpendCapExceeded(newSpent, cap.maxTotal); + + if (value > cfg.maxGasPerCall) revert UniversalRulesPolicyErrors.PCValueExceedsCap(value, cfg.maxGasPerCall); + + if (req.maxPCForGas == 0) revert UniversalRulesPolicyErrors.UncappedGasSwapRejected(); + + if (req.revertRecipient != account) { + revert UniversalRulesPolicyErrors.InvalidRevertRecipient(account, req.revertRecipient); + } + + // S11 — a zero pubkey is reported with the length it has (32): the shape is right, the value + // is not, and both are "not a pubkey". + if (req.recipient.length != 32) revert UniversalRulesPolicyErrors.RecipientNotPubkey(req.recipient.length); + bytes32 recipient = _loadWord(req.recipient, 0); + if (recipient == bytes32(0)) revert UniversalRulesPolicyErrors.RecipientNotPubkey(32); + + _checkSvmPayload(cfg, recipient, req.payload); + + if (req.amount > 0) { + cap.spent = newSpent; + emit OutboundMetered(id, msg.sender, account, req.token, req.amount); + } + + return VALIDATION_SUCCESS; + } + + /// @dev The parsed shape of an execute payload. Memory only; never stored. + struct SvmPayloadView { + uint256 count; + uint256 ixOff; + uint256 ixLen; + bytes32 target; + } + + /** + * @dev S12 to S18. Split out for stack depth; makes no external call, writes no storage. + * @param cfg Config to validate against. + * @param recipient The request's recipient, already proven to be a non-zero pubkey. + * @param payload The execute payload carried by the outbound request. + */ + function _checkSvmPayload(SvmConfig storage cfg, bytes32 recipient, bytes memory payload) internal view { + SvmPayloadView memory v = _parseSvmPayload(payload); + + if (v.target != recipient) revert UniversalRulesPolicyErrors.RecipientTargetMismatch(recipient, v.target); + + if (_isForbiddenProgram(v.target, cfg.gatewayProgram, cfg.expectedCEA)) { + revert UniversalRulesPolicyErrors.ForbiddenTargetProgram(v.target); + } + + uint256 rule = _matchSvmRule(cfg, payload, v); + + _checkSvmAccountPins(cfg, payload, v, rule); + _checkSvmDataPins(cfg, payload, v, rule); + _checkCeaAccounts(cfg, payload, v, rule); + } + + /** + * @dev S12/S13 — the node's `decodePayload` grammar, byte for byte, including "consumed exactly": + * `[u32 BE count][count × (pubkey32 ‖ writable u8)][u32 BE len][ix_data][u8 id][target32]`. + * Every length is checked before the read it guards. `is_writable` bytes are read past, + * never judged — a wrong flag fails on Solana, not here. + */ + function _parseSvmPayload(bytes memory p) internal pure returns (SvmPayloadView memory v) { + if (p.length == 0) revert UniversalRulesPolicyErrors.SvmPayloadEmpty(); + if (p.length < SVM_HEADER_LEN + SVM_LEN_FIELD + SVM_TRAILER_LEN) { + revert UniversalRulesPolicyErrors.MalformedSvmPayload(1); + } + + v.count = _u32be(p, 0); + if (v.count > MAX_SVM_ACCOUNTS) revert UniversalRulesPolicyErrors.SvmAccountsOutOfRange(v.count); + + uint256 lenOff = SVM_HEADER_LEN + v.count * SVM_ACCOUNT_LEN; + if (p.length < lenOff + SVM_LEN_FIELD) revert UniversalRulesPolicyErrors.MalformedSvmPayload(2); + + v.ixLen = _u32be(p, lenOff); + if (v.ixLen > MAX_SVM_IX_DATA) revert UniversalRulesPolicyErrors.SvmIxDataTooLong(v.ixLen); + v.ixOff = lenOff + SVM_LEN_FIELD; + + uint256 expected = v.ixOff + v.ixLen + SVM_TRAILER_LEN; + if (p.length < expected) revert UniversalRulesPolicyErrors.MalformedSvmPayload(3); + if (p.length > expected) revert UniversalRulesPolicyErrors.MalformedSvmPayload(4); + + uint8 id = uint8(p[v.ixOff + v.ixLen]); + if (id != SVM_INSTRUCTION_EXECUTE) revert UniversalRulesPolicyErrors.SvmInstructionNotExecute(id); + + v.target = _loadWord(p, v.ixOff + v.ixLen + 1); + } + + /** + * @dev S16 — first rule whose program equals the target and whose tag matches: a dataless rule + * matches only empty ix_data; a tagged rule needs at least `discriminatorLen` bytes and a + * prefix-equal tag. Init guarantees at most one rule can match, so first-match is exact. + * Then the rule's fixed account count, if any. + */ + function _matchSvmRule(SvmConfig storage cfg, bytes memory p, SvmPayloadView memory v) + internal + view + returns (uint256) + { + uint256 n = cfg.programs.length; + for (uint256 i; i < n;) { + AllowedProgram storage r = cfg.programs[i]; + if (r.program == v.target && _tagMatches(r, p, v)) { + uint8 cap = r.maxAccounts; + if (cap != 0 && v.count != cap) { + revert UniversalRulesPolicyErrors.SvmAccountCountMismatch(v.count, cap); + } + return i; + } + unchecked { + ++i; + } + } + uint256 shown = v.ixLen < 8 ? v.ixLen : 8; + revert UniversalRulesPolicyErrors.ProgramNotAllowed( + v.target, bytes8(_loadWord(p, v.ixOff)) & _prefixMask8(shown) + ); + } + + function _tagMatches(AllowedProgram storage r, bytes memory p, SvmPayloadView memory v) + internal + view + returns (bool) + { + if (r.dataless) return v.ixLen == 0; + uint8 len = r.discriminatorLen; + if (v.ixLen < len) return false; + bytes8 mask = _prefixMask8(len); + return (bytes8(_loadWord(p, v.ixOff)) & mask) == (r.discriminator & mask); + } + + /// @dev S17, account half: every pin of the matched rule names an index that exists and holds + /// the expected key. + function _checkSvmAccountPins(SvmConfig storage cfg, bytes memory p, SvmPayloadView memory v, uint256 rule) + internal + view + { + uint256 n = cfg.pins.length; + for (uint256 i; i < n;) { + SvmAccountPin storage pin = cfg.pins[i]; + if (pin.ruleIndex == rule) { + if (v.count <= pin.accountIndex) { + revert UniversalRulesPolicyErrors.SvmAccountCountBelowPin(i, v.count, pin.accountIndex); + } + bytes32 actual = _svmAccount(p, pin.accountIndex); + if (actual != pin.expected) { + revert UniversalRulesPolicyErrors.SvmAccountPinMismatch(i, pin.accountIndex, pin.expected, actual); + } + } + unchecked { + ++i; + } + } + } + + /// @dev S17, data half. Offsets resolve from the start or the end of ix_data; init proved the + /// from-end shape reaches at least `len` back, so only the length floor is checked here. + /// Integer reads are little-endian, `len` bytes; the ratio is computed in uint256 and cannot + /// overflow (both operands are at most 64 bits wide). + function _checkSvmDataPins(SvmConfig storage cfg, bytes memory p, SvmPayloadView memory v, uint256 rule) + internal + view + { + uint256 n = cfg.dataPins.length; + for (uint256 i; i < n;) { + SvmDataPin storage dp = cfg.dataPins[i]; + if (dp.ruleIndex == rule) _checkOneDataPin(dp, p, v, i); + unchecked { + ++i; + } + } + } + + function _checkOneDataPin(SvmDataPin storage dp, bytes memory p, SvmPayloadView memory v, uint256 i) internal view { + uint256 off = _resolveOffset(dp.fromEnd, dp.offset, dp.len, v.ixLen, i); + uint256 at = v.ixOff + off; + SvmDataPinMode mode = dp.mode; + + if (mode == SvmDataPinMode.EQ) { + bytes32 mask = _prefixMask32(dp.len); + bytes32 actual = _loadWord(p, at) & mask; + bytes32 want = dp.expected & mask; + if (actual != want) revert UniversalRulesPolicyErrors.SvmDataPinMismatch(i, want, actual); + return; + } + + uint256 a = _uintLE(p, at, dp.len); + if (mode == SvmDataPinMode.GTE_LE) { + if (a < uint256(dp.expected)) { + revert UniversalRulesPolicyErrors.SvmDataFloorNotMet(i, a, uint256(dp.expected)); + } + } else if (mode == SvmDataPinMode.LTE_LE) { + if (a > uint256(dp.expected)) { + revert UniversalRulesPolicyErrors.SvmDataCeilingExceeded(i, a, uint256(dp.expected)); + } + } else { + uint256 offB = _resolveOffset(dp.fromEnd, dp.offsetB, dp.len, v.ixLen, i); + uint256 b = _uintLE(p, v.ixOff + offB, dp.len); + if (a * dp.den < b * dp.num) revert UniversalRulesPolicyErrors.SvmDataRatioNotMet(i, a, b, dp.num, dp.den); + } + } + + /// @dev The field's start relative to ix_data, or `SvmDataTooShortForPin` if ix_data cannot hold it. + function _resolveOffset(bool fromEnd, uint16 offset, uint8 len, uint256 ixLen, uint256 pin) + internal + pure + returns (uint256) + { + if (fromEnd) { + if (ixLen < offset) revert UniversalRulesPolicyErrors.SvmDataTooShortForPin(pin, ixLen); + return ixLen - offset; + } + if (ixLen < uint256(offset) + len) revert UniversalRulesPolicyErrors.SvmDataTooShortForPin(pin, ixLen); + return offset; + } + + /** + * @dev S18 — a CEA-controlled account may appear only where the matched rule pins it. Any other + * occurrence hands a program, running with the CEA's signature, an account it was not + * granted. Accounts absent from `ceaAccounts` are not judged: the list is the owner's + * statement of what holds value. O(count × |ceaAccounts| × |pins|), all bounded. + */ + function _checkCeaAccounts(SvmConfig storage cfg, bytes memory p, SvmPayloadView memory v, uint256 rule) + internal + view + { + // Never empty: init requires `expectedCEA` in the list (`_checkCeaAccountList`). + uint256 listed = cfg.ceaAccounts.length; + for (uint256 i; i < v.count;) { + bytes32 key = _svmAccount(p, i); + for (uint256 c; c < listed;) { + if (cfg.ceaAccounts[c] == key && !_pinnedAt(cfg, rule, i)) { + revert UniversalRulesPolicyErrors.CeaAccountAtUnpinnedIndex(i, key); + } + unchecked { + ++c; + } + } + unchecked { + ++i; + } + } + } + + /// @dev Whether the matched rule pins `index` at all. S17 has already proved that every pinned + /// position holds its expected key, so "pinned" and "pinned to this key" are the same fact + /// here and the key is not re-compared. + function _pinnedAt(SvmConfig storage cfg, uint256 rule, uint256 index) internal view returns (bool) { + uint256 n = cfg.pins.length; + for (uint256 i; i < n;) { + SvmAccountPin storage pin = cfg.pins[i]; + if (pin.ruleIndex == rule && pin.accountIndex == index) return true; + unchecked { + ++i; + } + } + return false; + } + + // ───────────────────────── svm byte helpers (pure, memory only) ───────────────────────── + + /// @dev The pubkey of account `i` in a parsed payload. Callers bound `i` by the parsed count. + function _svmAccount(bytes memory p, uint256 i) internal pure returns (bytes32) { + return _loadWord(p, SVM_HEADER_LEN + i * SVM_ACCOUNT_LEN); + } + + /// @dev Loads 32 bytes at `off`. Every caller has already proved the bytes it USES are inside + /// `b`; bytes past the end are masked away by the caller, never compared. + function _loadWord(bytes memory b, uint256 off) internal pure returns (bytes32 w) { + // solhint-disable-next-line no-inline-assembly + assembly ("memory-safe") { + w := mload(add(add(b, 0x20), off)) + } + } + + function _u32be(bytes memory b, uint256 off) internal pure returns (uint256) { + return uint256(uint32(bytes4(_loadWord(b, off)))); + } + + /// @dev Little-endian unsigned integer of `len` bytes (1..8) starting at `off`. + function _uintLE(bytes memory b, uint256 off, uint256 len) internal pure returns (uint256 v) { + bytes32 w = _loadWord(b, off); + for (uint256 i; i < len;) { + v |= uint256(uint8(w[i])) << (8 * i); + unchecked { + ++i; + } + } + } + + /// @dev Keeps the top `len` bytes of a bytes8. `len` 8 keeps all (a shift by >= 64 is zero). + function _prefixMask8(uint256 len) internal pure returns (bytes8) { + return bytes8(~(type(uint64).max >> (8 * len))); + } + + /// @dev Keeps the top `len` bytes of a bytes32. `len` 32 keeps all. + function _prefixMask32(uint256 len) internal pure returns (bytes32) { + return bytes32(~(type(uint256).max >> (8 * len))); + } + + /** + * @notice Exact-equality assertion on every per-asset spend counter; the change-flow race guard. + * + * @dev - Intended as the first entry of the owner's atomic change batch: assert, revoke, + * grant. A mismatch reverts the whole change. + * - Reverts if the config is not initialised. Reading zero from a ghost config is + * indistinguishable from reading zero from a real unused rules set, and this function + * exists to catch stale belief, so it must not have a silent-pass mode. + * - One expected value per listed asset, in list order; a different count reverts + * `SpentLengthMismatch` rather than checking a prefix. + * - Exact equality in both directions, so a credit landing between read and submit also + * forces recomposition. + * - Callable by anyone; it is a pure read. + * + * @param id Config id identifying the rules set. + * @param account The wallet the rules set belongs to. + * @param expectedSpent The per-asset spend totals the caller composed its change against. + */ + function assertSpent(ConfigId id, address account, uint256[] calldata expectedSpent) external view { + (bool init, RulesType mode) = _modeOf(id, SESSION_ENGINE, account); + if (init && mode == RulesType.NATIVE) revert UniversalRulesPolicyErrors.WrongModeForCall(RulesType.NATIVE); + + AssetCapState[] storage assets = _universalAssets(id, account); + + uint256 n = assets.length; + if (expectedSpent.length != n) revert UniversalRulesPolicyErrors.SpentLengthMismatch(n, expectedSpent.length); + for (uint256 i; i < n;) { + AssetCapState storage a = assets[i]; + if (a.spent != expectedSpent[i]) { + revert UniversalRulesPolicyErrors.AssetSpentMismatch(a.token, expectedSpent[i], a.spent); + } + unchecked { + ++i; + } + } + } + + /** + * @notice The native change-flow race guard: exact equality on all three counters. + * + * @dev - The native counterpart of the universal `assertSpent`, and the same intent: the + * first entry of the owner's atomic change batch — assert, revoke, grant. + * - Reverts `WrongModeForCall(UNIVERSAL)` on a universal config and `NotInitialized` on + * a ghost. It must not have a silent-pass mode: reading zero from a ghost config is + * indistinguishable from reading zero from a real unused rules set, and this function + * exists to catch stale belief. + * - Exact equality on every counter, in both directions. + * - Callable by anyone; it is a pure read. + * + * @param id Config id identifying the rules set. + * @param account The wallet the rules set belongs to. + * @param expectedValueSpent Native value total the caller composed against. + * @param expectedAmountSpent Metered calldata-amount total the caller composed against. + * @param expectedCalls Call count the caller composed against. + */ + function assertSpent( + ConfigId id, + address account, + uint256 expectedValueSpent, + uint256 expectedAmountSpent, + uint32 expectedCalls + ) external view { + (bool init, RulesType mode) = _modeOf(id, SESSION_ENGINE, account); + + if (!init) revert UniversalRulesPolicyErrors.NotInitialized(id, account); + if (mode != RulesType.NATIVE) revert UniversalRulesPolicyErrors.WrongModeForCall(RulesType.UNIVERSAL); + + NativeConfig storage cfg = _native[id][SESSION_ENGINE][account]; + + if (cfg.valueSpent != expectedValueSpent) { + revert UniversalRulesPolicyErrors.SpentMismatch(expectedValueSpent, cfg.valueSpent); + } + if (cfg.amountSpent != expectedAmountSpent) { + revert UniversalRulesPolicyErrors.SpentMismatch(expectedAmountSpent, cfg.amountSpent); + } + if (cfg.callsUsed != expectedCalls) { + revert UniversalRulesPolicyErrors.SpentMismatch(expectedCalls, cfg.callsUsed); + } + } + + /** + * @notice Credits a confirmed far-side failure back to one asset's spend counter. + * + * @dev - Callable only by the executor module; nobody else can fabricate a failure. + * - A ghost config reverts `NotInitialized` and an unlisted token `AssetNotAllowed`; the + * revert rolls the idempotency flag back, so a misrouted credit stays retryable. Both are + * resolved BEFORE the flag is checked, so an already-credited id sent with an unlisted + * token reports the token, the actionable mistake. + * - Reverts if the id was already credited. + * - Subtracts saturating, since the amount is trusted from Push core and cannot be + * verified here. Idempotency and saturation bound a wrong value, PER ASSET: a credit + * can never lower another token's counter. + * - `token` is trusted from the caller as much as `amount` is: URP never learns the + * outbound id at check time, so it cannot map an id to the token it metered. + * - Emits the amount actually applied, not the amount claimed, so monitoring can detect + * divergence between the two. + * - Not yet functional: the executor module does not yet call this on outbound failure, + * so until that lands a failed far leg leaves `spent` inflated and the remedy is + * revoke-and-regrant. + * - There is no gas counter and this path must never introduce one, because gas consumed + * on a failed outbound was genuinely consumed. + * + * @param id Config id identifying the rules set. + * @param account The wallet the rules set belongs to. + * @param outboundTxId Push-core transaction id, the idempotency key. + * @param token The listed asset whose counter is credited. + * @param amount Amount claimed as failed, credited saturating. + */ + function creditRevert(ConfigId id, address account, bytes32 outboundTxId, address token, uint256 amount) external { + if (msg.sender != UNIVERSAL_EXECUTOR_MODULE) revert UniversalRulesPolicyErrors.CallerIsNotUEModule(msg.sender); + + AssetCapState storage cap = _assetFor(_universalAssets(id, account), token); + + if (_credited[outboundTxId]) revert UniversalRulesPolicyErrors.AlreadyCredited(outboundTxId); + _credited[outboundTxId] = true; + + uint256 applied = cap.spent > amount ? amount : cap.spent; + cap.spent -= applied; + + emit RevertCredited(outboundTxId, id, account, token, applied); + } + + /** + * @dev The engine-keyed asset list of a UNIVERSAL config, either family. Reverts `NotInitialized` + * on an empty EVM slot; an SVM family byte is only ever written together with an initialised + * `SvmConfig`, so that branch needs no check. Shared by `assertSpent` and `creditRevert`. + */ + function _universalAssets(ConfigId id, address account) internal view returns (AssetCapState[] storage) { + if (_vmOf(id, SESSION_ENGINE, account) == VmFamily.SVM) return _svm[id][SESSION_ENGINE][account].assets; + + Config storage cfg = _configs[id][SESSION_ENGINE][account]; + if (!cfg.initialized) revert UniversalRulesPolicyErrors.NotInitialized(id, account); + return cfg.assets; + } + + /** + * @dev Gate 5: the entry for `token` in a listed-asset array, or `AssetNotAllowed`. A linear scan + * at n <= MAX_ASSETS, so up to eight cold reads on a miss. Makes no external call. + */ + function _assetFor(AssetCapState[] storage assets, address token) internal view returns (AssetCapState storage) { + uint256 n = assets.length; + for (uint256 i; i < n;) { + AssetCapState storage a = assets[i]; + if (a.token == token) return a; + unchecked { + ++i; + } + } + revert UniversalRulesPolicyErrors.AssetNotAllowed(token); + } + + /** + * @notice The full universal config including the allow-list, keyed on the session engine. + * + * @dev Reverts `WrongModeForCall(NATIVE)` on a native slot. An EMPTY slot returns the zeroed + * struct exactly as it always has — an empty slot is a STATE, a wrong-mode read is a + * CALLER BUG, and only the second is worth a revert. `getMode` is the documented first + * call for anything that does not already know a rules set's mode. + * + * @param id Config id identifying the rules set. + * @param account The wallet the rules set belongs to. + * @return The stored config. + */ + function getConfig(ConfigId id, address account) external view returns (Config memory) { + (bool init, RulesType mode) = _modeOf(id, SESSION_ENGINE, account); + if (init && mode == RulesType.NATIVE) revert UniversalRulesPolicyErrors.WrongModeForCall(RulesType.NATIVE); + if (init && _vmOf(id, SESSION_ENGINE, account) == VmFamily.SVM) { + revert UniversalRulesPolicyErrors.WrongVmForCall(VmFamily.SVM); + } + + return _configs[id][SESSION_ENGINE][account]; + } + + /** + * @notice The full SVM config including its rules and pins, keyed on the session engine. + * @dev Reverts `WrongModeForCall(NATIVE)` on a native slot and `WrongVmForCall(EVM)` on an EVM + * universal slot; an empty slot returns the zeroed struct. See `getConfig`. + * @param id Config id identifying the rules set. + * @param account The wallet the rules set belongs to. + * @return The stored SVM config. + */ + function getSvmConfig(ConfigId id, address account) external view returns (SvmConfig memory) { + (bool init, RulesType mode) = _modeOf(id, SESSION_ENGINE, account); + if (init && mode == RulesType.NATIVE) revert UniversalRulesPolicyErrors.WrongModeForCall(RulesType.NATIVE); + if (init && _vmOf(id, SESSION_ENGINE, account) == VmFamily.EVM) { + revert UniversalRulesPolicyErrors.WrongVmForCall(VmFamily.EVM); + } + + return _svm[id][SESSION_ENGINE][account]; + } + + /** + * @notice The full native config including its pins, keyed on the session engine. + * @dev Reverts `WrongModeForCall(UNIVERSAL)` on a universal slot; an empty slot returns the + * zeroed struct. See `getConfig`. + * @param id Config id identifying the rules set. + * @param account The wallet the rules set belongs to. + * @return The stored native config. + */ + function getNativeConfig(ConfigId id, address account) external view returns (NativeConfig memory) { + (bool init, RulesType mode) = _modeOf(id, SESSION_ENGINE, account); + if (init && mode == RulesType.UNIVERSAL) { + revert UniversalRulesPolicyErrors.WrongModeForCall(RulesType.UNIVERSAL); + } + + return _native[id][SESSION_ENGINE][account]; + } + + /** + * @notice Which rulebook a config uses, and which chain it was granted for. NEVER REVERTS. + * @dev The documented first call for any integrator that does not already know a rules set's + * mode. An empty slot returns `(initialized: false, mode: UNIVERSAL, chainHash: 0)` — and + * the mode value is MEANINGLESS when `initialized` is false, because `UNIVERSAL` is the + * enum's zero value. Read `initialized` first, always. + * + * `chainHash` is the rules set's chain, recorded at init (and, for a universal rules set, + * verified against every listed asset). It is THE chain record; there is no other. + * @param id Config id identifying the rules set. + * @param account The wallet the rules set belongs to. + * @return The stored mode record. + */ + function getMode(ConfigId id, address account) external view returns (ModeSlot memory) { + return _mode[id][SESSION_ENGINE][account]; + } + + /** + * @notice Exposes the idempotency set for monitoring. + * @param outboundTxId Push-core transaction id to query. + * @return Whether that id has already been credited. + */ + function isCredited(bytes32 outboundTxId) external view returns (bool) { + return _credited[outboundTxId]; + } + + /** + * @notice The implementation's version, readable THROUGH the proxy. + * + * @dev The proxy has no version of its own — it delegates, so this answers with whichever + * implementation is currently installed. That makes it the cheapest possible check that + * an upgrade actually took effect: read it before, upgrade, read it again. + * + * A `constant` in bytecode, deliberately not storage: it must change with the CODE, and + * a storage value could drift from the logic it claims to describe. + * + * BUMP THIS IN THE SAME COMMIT AS ANY LOGIC CHANGE. + */ + function version() external pure returns (string memory) { + return "3.1.0"; + } + + /** + * @notice ERC-165 support check. + * @param iid Interface id to query. + * @return True for the action-policy, policy and ERC-165 interfaces. + */ + function supportsInterface(bytes4 iid) external pure returns (bool) { + return + iid == type(IActionPolicy).interfaceId || iid == type(IPolicy).interfaceId + || iid == type(IERC165).interfaceId; + } + + /** + * @dev Reads the 32-byte word at `offset` and returns its low 20 bytes. Bounds-checked because + * reading past the end of a short blob would return adjacent memory, which could be + * manipulated to pass the beneficiary check. + * + * @param data Inner call calldata to read from. + * @param offset Byte offset of the beneficiary word, taken from config and never the request. + * @return The address encoded at that offset. + */ + function _extractBeneficiary(bytes memory data, uint16 offset) internal pure returns (address) { + if (uint256(offset) + 32 > data.length) revert UniversalRulesPolicyErrors.MalformedInnerCalldata(); + bytes32 word; + assembly { + word := mload(add(add(data, 0x20), offset)) + } + return address(uint160(uint256(word))); + } + + /** + * @dev The target and selector pair must appear in the allow-list. + * @param cfg Config whose allow-list is scanned. + * @param to Inner call target. + * @param selector Inner call selector. + * @return The matching rule; reverts with `CallNotAllowed` if there is none. + */ + function _requireAllowed(Config storage cfg, address to, bytes4 selector) + internal + view + returns (AllowedCall memory) + { + uint256 len = cfg.allowedCalls.length; + for (uint256 i; i < len;) { + AllowedCall storage rule = cfg.allowedCalls[i]; + if (rule.target == to && rule.selector == selector) { + return + AllowedCall(rule.target, rule.selector, rule.beneficiaryOffset, rule.hasBeneficiary, rule.maxValue); + } + unchecked { + ++i; + } + } + revert UniversalRulesPolicyErrors.CallNotAllowed(to, selector); + } + + /** + * @dev Memory slice helper. The bounds branch is unreachable from the three call sites, which + * are all length-guarded by gates 12 and 14, and is expected to show as uncovered. It stays + * because this is a `pure` helper whose safety must not depend on every future caller. + * + * @param data Blob to slice. + * @param start Byte offset to start at. + * @param len Number of bytes to copy. + * @return out The requested slice. + */ + function _slice(bytes memory data, uint256 start, uint256 len) internal pure returns (bytes memory out) { + if (start + len > data.length) revert UniversalRulesPolicyErrors.MalformedInnerCalldata(); + out = new bytes(len); + // MCOPY requires evm_version = "cancun"; lowering the EVM target breaks this silently at + // deploy time rather than loudly at compile time. + assembly ("memory-safe") { + mcopy(add(out, 0x20), add(add(data, 0x20), start), len) + } + } + + /** + * @dev Copies decoded WIRE terms into the STORAGE config. The two are deliberately different + * types: the wire shape is free to change, the storage layout is frozen forever + * (see the layout note on `__gap`). + * + * - Forces every asset's `spent` to zero. It is not a wire field at all — URP owns it. + * - Stores no chain: the chain of every rules set lives on `ModeSlot.chainHash`, where it has + * been verified against every listed asset. + * - Clears and repopulates the allow-list. + * - Does not set `initialized`; the caller does, immediately after this returns. + * + * @param cfg Storage slot to write into. + * @param incoming Decoded wire terms to copy from. + */ + function _store(Config storage cfg, UniversalTerms memory incoming) internal { + cfg.validUntil = incoming.validUntil; + cfg.expectedCEA = incoming.expectedCEA; + cfg.maxGasPerCall = incoming.maxGasPerCall; + delete cfg.assets; + _storeAssets(cfg.assets, incoming.assets); + + // Re-initialisation is refused, so in production this array is always empty here. The + // delete is kept for the stranger-slice path and for tests. + delete cfg.allowedCalls; + uint256 len = incoming.allowedCalls.length; + for (uint256 i; i < len;) { + cfg.allowedCalls.push(incoming.allowedCalls[i]); + unchecked { + ++i; + } + } + } + + /// @dev Wire asset caps into storage, element by element, every `spent` forced to zero. Shared by + /// both universal families. The caller deletes `dst` first, as for every other array. + function _storeAssets(AssetCapState[] storage dst, AssetCap[] memory src) internal { + uint256 len = src.length; + for (uint256 i; i < len;) { + dst.push( + AssetCapState({ + token: src[i].token, maxPerCall: src[i].maxPerCall, maxTotal: src[i].maxTotal, spent: 0 + }) + ); + unchecked { + ++i; + } + } + } + + /** + * @dev Copies a decoded native config into storage. The native counterpart of `_store`. + * + * - Forces `valueSpent`, `amountSpent` and `callsUsed` to zero, ignoring anything the + * caller supplied. A caller-set counter would be a granted head start on every cap. + * - `amount` is a value struct with no dynamic members, so it assigns wholesale. + * - `pins` must be copied ELEMENT BY ELEMENT: Solidity cannot assign a memory dynamic array + * into a storage struct field. Same shape as `allowedCalls` above, same reason. + * - Does not set `initialized`; the caller does, immediately after this returns. + * + * @param cfg Storage slot to write into. + * @param incoming Decoded native wire terms to copy from. + */ + function _storeNative(NativeConfig storage cfg, NativeTerms memory incoming) internal { + cfg.validUntil = incoming.validUntil; + cfg.target = incoming.target; + cfg.selector = incoming.selector; + cfg.maxValuePerCall = incoming.maxValuePerCall; + cfg.maxValueTotal = incoming.maxValueTotal; + cfg.valueSpent = 0; + cfg.amount = incoming.amount; + cfg.amountSpent = 0; + cfg.maxCalls = incoming.maxCalls; + cfg.callsUsed = 0; + + // Re-initialisation is refused, so in production this array is always empty here. The + // delete is kept for the stranger-slice path and for tests. + delete cfg.pins; + uint256 len = incoming.pins.length; + for (uint256 i; i < len;) { + cfg.pins.push(incoming.pins[i]); + unchecked { + ++i; + } + } + } + + /** + * @dev Copies decoded SVM wire terms into storage. The SVM counterpart of `_store`. + * - Forces every asset's `spent` to zero; URP owns it. + * - Every dynamic member is copied ELEMENT BY ELEMENT, same shape and same reason as + * `allowedCalls` and `pins`. + * - Does not set `initialized`; the caller does, immediately after this returns. + */ + function _storeSvm(SvmConfig storage cfg, SvmTerms memory incoming) internal { + cfg.validUntil = incoming.validUntil; + cfg.expectedCEA = incoming.expectedCEA; + cfg.gatewayProgram = incoming.gatewayProgram; + cfg.maxGasPerCall = incoming.maxGasPerCall; + delete cfg.assets; + _storeAssets(cfg.assets, incoming.assets); + + delete cfg.ceaAccounts; + uint256 len = incoming.ceaAccounts.length; + for (uint256 i; i < len;) { + cfg.ceaAccounts.push(incoming.ceaAccounts[i]); + unchecked { + ++i; + } + } + + delete cfg.programs; + len = incoming.programs.length; + for (uint256 i; i < len;) { + cfg.programs.push(incoming.programs[i]); + unchecked { + ++i; + } + } + + delete cfg.pins; + len = incoming.pins.length; + for (uint256 i; i < len;) { + cfg.pins.push(incoming.pins[i]); + unchecked { + ++i; + } + } + + delete cfg.dataPins; + len = incoming.dataPins.length; + for (uint256 i; i < len;) { + cfg.dataPins.push(incoming.dataPins[i]); + unchecked { + ++i; + } + } + } +} diff --git a/plan/agw/research/source-refresh-2026-10-07/contracts/push-chain-core-contracts/docs/universalmarketplace/README.md b/plan/agw/research/source-refresh-2026-10-07/contracts/push-chain-core-contracts/docs/universalmarketplace/README.md new file mode 100644 index 00000000..ebb83de4 --- /dev/null +++ b/plan/agw/research/source-refresh-2026-10-07/contracts/push-chain-core-contracts/docs/universalmarketplace/README.md @@ -0,0 +1,645 @@ +# Universal Marketplace + +How the Universal Marketplace contracts work, end to end. Written for a reviewer: every guarantee is tied to the +code that enforces it, and every assumption the code makes about something else is stated. + +| Doc | Contents | +|---|---| +| **This file** | What the marketplace is, its parts, the card lifecycle, `startJob` step by step, the rules check, the criteria, admin powers, upgradeability, trust model, limitations, tests, reviewer checklist | +| [`reference.md`](./reference.md) | Every function, event, error and storage slot, one by one | +| [`criteria.md`](./criteria.md) | The criteria template format, how a job's `JobSpec` is built from it, and a worked example | + +Code as of commit `cb69e0b` (branch `universalMarketplace_v1`). + +--- + +## Contract locations + +| Contract | Path | Kind | +|---|---|---| +| **UniversalMarketplace** | [`src/agentic-commerce-8183/UniversalMarketplace.sol`](../../src/agentic-commerce-8183/UniversalMarketplace.sol) | Upgradeable (TransparentUpgradeableProxy), stateful. The only contract users and providers call. | +| **UniversalMarketplaceTerms** | [`src/agentic-commerce-8183/UniversalMarketplaceTerms.sol`](../../src/agentic-commerce-8183/UniversalMarketplaceTerms.sol) | Stateless, `pure`, not upgradeable. The rules-side checks. | +| **JobSpecBuilder** | [`src/agentic-commerce-8183/libraries/JobSpecBuilder.sol`](../../src/agentic-commerce-8183/libraries/JobSpecBuilder.sol) | External library, linked into the marketplace and called by `DELEGATECALL`. Builds each job's criteria. | +| Types | [`src/agentic-commerce-8183/libraries/Types.sol`](../../src/agentic-commerce-8183/libraries/Types.sol) | Every struct and enum of the package (file-level). | +| Errors | [`src/agentic-commerce-8183/libraries/Errors.sol`](../../src/agentic-commerce-8183/libraries/Errors.sol) | `UniversalMarketplaceErrors` (37 errors), `RulesBindingHookErrors`, `ERC8183HookErrors`. | +| JobSpecTypes | [`src/agentic-commerce-8183/libraries/JobSpecTypes.sol`](../../src/agentic-commerce-8183/libraries/JobSpecTypes.sol) | The built criteria (`JobSpec`): the wire format shared with the future UniversalHook and UniversalEvaluator. | +| IUniversalMarketplace | [`src/agentic-commerce-8183/interfaces/IUniversalMarketplace.sol`](../../src/agentic-commerce-8183/interfaces/IUniversalMarketplace.sol) | The marketplace's events and functions. | +| IUniversalMarketplaceTerms | [`src/agentic-commerce-8183/interfaces/IUniversalMarketplaceTerms.sol`](../../src/agentic-commerce-8183/interfaces/IUniversalMarketplaceTerms.sol) | The Terms helper's two functions. | +| AGW mirrors | [`interfaces/external/IAGW.sol`](../../src/agentic-commerce-8183/interfaces/external/IAGW.sol), [`IAGWFactory.sol`](../../src/agentic-commerce-8183/interfaces/external/IAGWFactory.sol), [`ISmartSession.sol`](../../src/agentic-commerce-8183/interfaces/external/ISmartSession.sol) | Byte-exact mirrors of the Push Agentic Wallet (AGW) types and functions the package calls. | + +Contracts the marketplace works with, but which are **not** part of it: + +| Contract | Where | Role | +|---|---|---| +| **AgenticCommerce** (the "kernel") | [`src/agentic-commerce-8183/AgenticCommerce.sol`](../../src/agentic-commerce-8183/AgenticCommerce.sol) | The ERC-8183 job kernel: jobs, budgets, escrow, payout. The marketplace only creates jobs on it (through the user's wallet). | +| **RulesBindingHook** | [`src/agentic-commerce-8183/hooks/RulesBindingHook.sol`](../../src/agentic-commerce-8183/hooks/RulesBindingHook.sol) | The interim 8183 hook every marketplace job is created with. At `fund` it binds the job to the wallet's live rules set and allows one live job per wallet. | +| **AGW + AGWFactory** | `push-agentic-wallet` repo | The user's agentic wallet (an ERC-7579 account with SmartSession) and its factory. Verifies the owner's signature. | +| **UniversalRulesPolicy (URP)** | `push-agentic-wallet` repo | The SmartSession policy that enforces the agent's rules when the agent sends outbound calls through the gateway. | +| **CEAFactory** | destination chain (`src/cea/CEAFactory.sol` here) | Deploys each user's Chain Executor Account (CEA) on the destination chain. The marketplace only predicts CEA addresses. | +| UniversalHook, UniversalEvaluator (V2) | not built yet | The intended long-term hook and evaluator. Until they ship, jobs use RulesBindingHook and a Push-controlled evaluator address. | + +--- + +## 1 · What the marketplace is + +The Universal Marketplace is a registry of **agent cards** plus one entry point, **`startJob`**. + +- **An agent card** is a standing offer from one provider (an AI agent's address). It covers one job type on one + EVM execution chain. It says who the agent is, what it does, what it needs permission to do there (the + **rules**), and how "done" is judged (the **criteria template**). +- **`startJob`** is one relayed call. On a single signature from the user, it: + 1. deploys the user's agentic wallet (AGW) if needed; + 2. grants the AGW the card's rules, so the agent can act from it; and + 3. creates an ERC-8183 job on the kernel, with the AGW as client, the card's provider as provider, the + marketplace's configured evaluator and hook, and **criteria built on-chain from the card**. + +What the marketplace deliberately does **not** do: + +| Not done | Where it happens instead | +|---|---| +| Move any funds | The user funds the AGW in a separate transaction. The provider prices the job with `setBudget`; the AGW funds it with `fund`. Both are kernel calls. | +| Execute the card's token approvals | The owner executes them in the funding transaction the SDK builds. The card only declares them (`Approval[]`). | +| Judge whether the criteria make sense | Nobody, on-chain. The admin's **verified tag** is the review. | +| Evaluate the job | The job's evaluator (the UniversalEvaluator, once shipped). | +| Enforce the agent's rules at execution | The AGW's SmartSession engine and URP. | + +The marketplace never holds tokens or native PC. Tests `test_MS02_movesNoFunds` and the invariants +`MI02_marketplaceHoldsNothing` and `MI05_userBalanceNeverMovedByStartJob` check this. + +--- + +## 2 · Glossary + +| Term | Meaning | +|---|---| +| **Provider / agent** | One address. It registers the card, is the 8183 job's `provider` (and fee recipient), and is the agent the rules authorise (`sessionValidatorInitData == abi.encode(provider)`). | +| **User / owner** | The person starting a job. Signs one `OwnerIntent`; owns the AGW. | +| **AGW** | Agentic Wallet: the user's smart account, deployed by the AGW factory at an address derived from `(owner, index)`. The job's client. | +| **CEA** | Chain Executor Account: the AGW's account on the destination chain, at an address derived from the AGW. It is where the agent's outbound calls execute and where the criteria read balances. | +| **Rules** | The SmartSession `Session` granted to the agent on the AGW. Its one action carries the URP policy with `UniversalTerms` (asset, caps, allowed calls, expected CEA, expiry). `rulesId` is the engine's `permissionId`. | +| **OwnerIntent** | The single owner-signed message (AGW type). One signature authorises the wallet deploy, the rules grant and the `createJob` execution. | +| **Criteria template** | `EvaluationTemplate`: the V2 `JobSpec` with holes. Stored on the card. | +| **JobSpec** | The built criteria for one job: reads on the execution chain, checks against targets, and an AND/OR tree. `abi.encode(JobSpec)` is the 8183 job's `description`. | +| **Card version** | 1 at registration, +1 per modification. Bound into every job's criteria, so an intent signed against one version can't start a job on another. | +| **Verified tag** | An admin label: "this card, at this version, was reviewed". A tag, not a gate. | +| **chainHash** | `keccak256` of a CAIP-2 string such as `"eip155:11155111"`. The key for chain configuration. | +| **pushChainHash** | `keccak256("eip155:" ‖ block.chainid)`: Push Chain itself. No card may name it. | + +--- + +## 3 · The parts and how they fit + +```mermaid +flowchart LR + Provider -- registerCard / modifyAgentCard --> MKT[UniversalMarketplace] + Relayer -- startJob --> MKT + MKT -- validateRulesTerms / verifySession --> TERMS[UniversalMarketplaceTerms] + MKT -- DELEGATECALL build --> JSB[JobSpecBuilder] + JSB -. expectedCEAOf .-> MKT + MKT -- predictWallet / deployWalletWithSig / ownerOf --> FACT[AGWFactory] + MKT -- grantRulesWithSig / executeWithSig --> AGW[User's AGW] + AGW -- createJob --> KERNEL[AgenticCommerce kernel] + MKT -- jobCounter / getJob / whitelistedHooks --> KERNEL + KERNEL -- beforeAction / afterAction --> HOOK[RulesBindingHook] +``` + +- **The marketplace** holds the cards and runs `startJob`. It is the `executor` named in the user's intent: the + factory and the wallet accept that intent only from it. +- **The Terms helper** is pure logic, split out for the EIP-170 size limit. It validates a card's rules at + registration and checks the user's session against the card at `startJob`. +- **JobSpecBuilder** is an external library. It turns the card's template plus the job's inputs into the job's + `JobSpec`. It runs in the marketplace's context, so it reads CEAs from the marketplace's own `expectedCEAOf`. +- **The AGW** does the work that needs the owner's authority: it verifies the owner's signature, grants the rules, + and calls `createJob` itself, so the kernel records the AGW as the client. + +--- + +## 4 · The agent card + +### 4.1 What a card holds + +A card is three things stored on-chain together: + +1. **`AgentCard`**, the listing. Who: `provider`. What: `jobType`, `metadataURI` and `metadataHash` (off-chain + JSON with the name, summary, ABIs, criteria in words and param units). Where: `chainNamespace`, a full CAIP-2 + string `"eip155:"`. Commercials and windows: `fee` (reference price), `principalMin` / `principalMax`, + `minDuration` / `maxDuration`, `minExecuteWindow`, `settleWindow`. And an `active` switch. +2. **Rules terms**, `abi.encode(RulesCardTerms)`: the rules `asset` (a PRC20 of the card's chain), `maxPCPerCall`, + the `allowedCalls` the agent may make, and the `approvals` the owner must make first. +3. **Criteria template**, `abi.encode(EvaluationTemplate)`: see [`criteria.md`](./criteria.md). + +`getCard(cardId)` returns all three, the version and both tags in one call (`CardView`). + +### 4.2 What registration checks + +`registerCard` (and `modifyAgentCard`) run `_validateCard`, in this order. The first failure reverts. + +| # | Check | Error | +|---|---|---| +| 1 | `jobType != 0` | `InvalidCard("job type zero")` | +| 2 | `metadataURI` not empty | `InvalidCard("metadata uri empty")` | +| 3 | `metadataHash != 0` | `InvalidCard("metadata hash zero")` | +| 4 | `chainNamespace` starts with `"eip155:"` and is longer than 7 bytes | `InvalidCard("chain namespace")` | +| 5 | the chain is not Push, and has a CEA deployment (`setCEADeployment`) | `ChainNotSupported(chainHash)` | +| 6 | the caller is not the marketplace's evaluator | `InvalidCard("provider is evaluator")` | +| 7 | `principalMax != 0` and `principalMin ≤ principalMax` | `InvalidCard("principal range")` | +| 8 | `1 hour ≤ minDuration ≤ maxDuration` | `InvalidCard("duration range")` | +| 9 | `settleWindow != 0` | `InvalidCard("settle window")` | +| 10 | `minExecuteWindow + settleWindow ≤ maxDuration` | `InvalidCard("execute window")` | +| 11 | the rules terms pass `Terms.validateRulesTerms` (§6.1) | `InvalidCard(...)` from Terms | +| 12 | the rules asset's `SOURCE_CHAIN_NAMESPACE()` is a well-formed string equal to the card's chain | `InvalidCard("asset")` / `InvalidCard("asset chain")` | + +**The criteria template is stored as given; it is not checked.** Whether the evaluator can run it is the +provider's responsibility. A malformed template fails only when a job is built from it (§7.3). + +Check 12 uses a raw `staticcall` plus an ABI-shape check, not `try/catch`: a `try` clause cannot catch the +decoding of its own return data, so a non-string answer would otherwise revert with an opaque error. A codeless +asset answers empty and fails the length check. + +### 4.3 Lifecycle + +```mermaid +stateDiagram-v2 + [*] --> Active: registerCard (version 1, unverified) + Active --> Inactive: setCardActive(false) by provider + Inactive --> Active: setCardActive(true) by provider + Active --> Active: modifyAgentCard (version +1, tag cleared) + Inactive --> Inactive: modifyAgentCard (version +1, tag cleared) + Active --> Disabled: adminDisableCard + Inactive --> Disabled: adminDisableCard + Disabled --> [*] +``` + +| Action | Who | Effect | +|---|---|---| +| `registerCard` | anyone (becomes the provider) | Stores the card, version 1, active, unverified. The contract writes `provider = msg.sender` and `active = true`, ignoring the caller's values. | +| `modifyAgentCard` | the provider | Replaces every field except `provider`, `chainNamespace` and `active`, and both blobs. Version +1, verified tag cleared. **The chain cannot change** (`CardIdentityImmutable`): another chain is another card. Refused for an admin-disabled card. | +| `setCardActive` | the provider | Switches the card on or off. An admin-disabled card cannot be switched back on. | +| `verifyAgentCard(cardId, version)` | admin | Sets the verified tag. `version` must be the current version (`CardVersionMismatch`), so a provider who modifies after review makes it revert. Refused for an admin-disabled card; allowed for an inactive one. | +| `revokeAgentCardVerification` | admin | Clears the tag. Idempotent: emits only if there was a tag. | +| `adminDisableCard` | admin | Permanent kill switch: disabled, inactive, tag cleared. The provider cannot undo it. | + +**Modification and signed intents.** The card version is hashed into every job's `origin`, which is inside the +`createJob` calldata the owner signs. After a modification, an intent signed against the old version fails at +`CardVersionMismatch` (stale `p.cardVersion`) or at `IntentExecMismatch` (current version, old intent). A provider +therefore cannot swap the card under a user's signature. Jobs already started are untouched. + +**The verified tag is a tag, not a gate.** `startJob` treats verified and unverified cards alike. The SDK shows it. + +--- + +## 5 · End-to-end flow + +```mermaid +sequenceDiagram + autonumber + actor P as Provider (agent) + actor U as User (owner) + participant SDK + participant M as UniversalMarketplace + participant F as AGWFactory + participant W as User's AGW + participant K as Kernel (AgenticCommerce) + participant H as RulesBindingHook + + P->>M: registerCard(card, rulesTerms, template) + U->>SDK: pick a card, principal, times, params + SDK->>M: previewIntent(request, session) + M-->>SDK: OwnerIntent (calldata hash binds the built criteria) + U->>SDK: sign the OwnerIntent once + SDK->>M: startJob(params) via a relayer + M->>F: deployWalletWithSig(intent, sig) [if new] + M->>W: grantRulesWithSig(session, intent, sig) + M->>W: executeWithSig(createJob calldata, intent, sig) + W->>K: createJob(provider, evaluator, expiredAt, JobSpec, hook) + Note over M,K: job is Open, budget 0. Nothing has moved. + U->>W: funding tx (SDK-built): principal, PC, fee, approvals + P->>K: setBudget(jobId, card.fee) + W->>K: fund(jobId, card.fee, abi.encode(rulesId)) + K->>H: beforeAction(fund): bind job to the live rules set + P->>W: act within the rules (URP-enforced outbound calls) + P->>K: submit; evaluator completes or rejects +``` + +1. **The provider registers a card** (§4). +2. **The user starts a job.** The SDK calls `previewIntent`, the user signs the returned `OwnerIntent` once, and a + relayer calls `startJob`. The AGW is deployed (if new), granted the rules, and creates the job in **Open** + with budget 0. +3. **The user funds**, in one transaction from their account, built by the SDK. It moves the principal (in the + rules asset), PC for gas and the fee into the AGW, and runs the card's approvals as the owner. +4. **The provider prices** the job: `kernel.setBudget(jobId, card.fee)`. +5. **The AGW funds** the job: `kernel.fund(jobId, card.fee, abi.encode(rulesId))`. The kernel calls the hook, which + checks the AGW is a factory wallet, the rules set is live, and the AGW has no other live job. A provider who + prices above the card's fee cannot be funded, because the owner's `expectedBudget` is the card fee + (`BudgetMismatch`); `test_MS17_8183Continuation_feeEnforcedAtFund` covers this. +6. **The agent executes** within the rules, submits, and the evaluator completes or rejects (kernel). + +Steps 3–6 are outside the marketplace. They are shown because the marketplace's design depends on them. + +--- + +## 6 · The rules: card ⊆ session + +The owner signs a SmartSession `Session` the SDK builds, which they cannot read. The marketplace proves it is +exactly the card's rules, for the card's agent, bound to this job. Both checks live in the Terms helper. + +### 6.1 At registration: `validateRulesTerms` + +| Check | Error | +|---|---| +| `asset != 0` | `InvalidCard("asset zero")` | +| 1 to 32 allowed calls (URP's bound) | `InvalidCard("allow-list size")` | +| no duplicate `(target, selector)` | `InvalidCard("duplicate call")` | +| no `approve` or `increaseAllowance` in the allow-list (approvals are the owner's, never agent authority) | `InvalidCard("erc20 approval")` | +| `transfer` must pin its recipient at offset 4 | `InvalidCard("erc20 transfer recipient")` | +| `transferFrom` must pin its recipient at offset 36 | `InvalidCard("erc20 transferFrom recipient")` | +| at most 8 approvals | `InvalidCard("approval count")` | +| each approval names a token and a spender | `InvalidCard("approval token")` / `("approval spender")` | +| `capIsPrincipal` ⇒ `cap == 0`; otherwise `cap > 0` | `InvalidCard("approval cap")` | +| no duplicate `(token, spender)` | `InvalidCard("duplicate approval")` | + +The function returns the asset, which the marketplace then checks against the card's chain (§4.2, check 12). + +### 6.2 At `startJob`: `verifySession` + +In order; the first mismatch reverts. + +| # | The session must… | Error | +|---|---|---| +| 1 | name the card's provider as its agent: `sessionValidatorInitData == abi.encode(provider)` | `AgentMismatch()` | +| 2 | have exactly one action | `ActionCount()` | +| 3 | with exactly one policy | `PolicyShape(0)` | +| 4 | whose envelope `abi.decode(initData, (string chainNamespace, bytes body))` names the card's chain | `ChainMismatch(0)` | +| 5 | carry `UniversalTerms` with the card's `asset` | `AssetMismatch()` | +| 6 | and the card's `maxPCPerCall` | `PCCapMismatch()` | +| 7 | and the card's `allowedCalls`, byte-equal (same calls, same order, same caps) | `ActionsMismatch()` | +| 8 | with `maxAmountTotal == principal` and `maxAmountPerCall ≤ principal` | `CapMismatch()` | +| 9 | expiring with the job: `validUntil == expiredAt` | `ExpiryMismatch()` | +| 10 | paying only the AGW's own CEA on that chain: `expectedCEA == expectedCEAOf(agw, chainHash)` | `ExpectedCEAMismatch(expected, actual)` | + +The card's `approvals` are not compared: they are the owner's actions, never agent authority. A session that adds +an approval to the agent's allow-list fails check 7 (`test_MB05_approvalsNotInSession`). + +What check 10 protects: URP pins every beneficiary-pinned call to `expectedCEA`, so funds the agent moves can only +land in the user's own CEA. The marketplace derives the CEA itself (§9); the SDK derives it independently from the +destination `CEAFactory`. A disagreement fails closed before anything happens. + +Fields the marketplace does **not** check are listed in §13.2. + +--- + +## 7 · The criteria: card ⊆ job + +### 7.1 Why they are built on-chain + +If the SDK or relayer supplied the job's criteria, nothing would guarantee they are the card's: a relayer could +swap in easier ones. Instead, `startJob` builds the criteria from the card's **stored** template and the job's +inputs. The result goes into the `createJob` calldata, which the owner's intent hashes (`execCalldataHash`). So +the owner's single signature covers the exact criteria, and the marketplace re-derives them before executing. + +### 7.2 What building does + +`JobSpecBuilder.build(template, ctx)` fills the template's holes: + +| Hole | Filled with | +|---|---| +| a `Fill` with source `CEA` in a read's args | the AGW's CEA **on that read's chain** | +| a `Fill` with source `PARAM` | one of the job's `params` (two's complement for negatives) | +| a check target `FIXED` | the template's value | +| a check target `PRINCIPAL_BPS` | `principal × bps / 10 000`, rounded down | +| a check target `PARAM` | one of the job's `params` | +| a check target `CEA` | the AGW's CEA on the check's read chain | +| `executeBy` | the job's `executeBy` | +| `failFinalAt` | `executeBy + card.settleWindow` | +| `origin` | `keccak256(abi.encode(marketplace, cardId, cardVersion, principal))` | + +`nodes` (the AND/OR tree) and every other read field are copied verbatim. The full format and a worked example +are in [`criteria.md`](./criteria.md). + +### 7.3 What building checks, and what it doesn't + +The template is **not judged**. Building checks only what building needs: + +| Check | Error | +|---|---| +| one param per template param | `ParamCountMismatch(expected, actual)` | +| each param inside its inclusive bounds | `ParamOutOfRange(index, value)` | +| each fill writes inside its read's args | `FillOutOfBounds(read, fill)` | +| `principal × bps` fits in uint256 | `TargetOverflow(check)` | +| a CEA is asked only for a chain with a CEA deployment | `ChainNotSupported(chainHash)` | + +Anything else malformed reverts on its own when a job is built (an index out of range panics, undecodable bytes +fail in `abi.decode`). A template the evaluator could not run, such as a read no check uses or an unreachable +node, **builds without complaint** (`test_JB08_doesNotJudgeTheTemplate`). The verified tag is the review. + +--- + +## 8 · `startJob`, step by step + +`startJob(StartJobParams p)` is `whenNotPaused` and `nonReentrant`. **Every check runs before the first state +change**, so a refusal leaves no wallet, no grant and no job (`test_MS13_intentSessionMismatch_noStateOnFailure`). + +| Step | What | Code | Error on failure | +|---|---|---|---| +| 1 | Card exists and is active; its chain is not paused | `_checkCardAndJob` | `CardInactive()` · `ChainPaused(chainHash)` | +| 2 | `p.cardVersion` is the card's current version | `_checkCardAndJob` | `CardVersionMismatch(provided, current)` | +| 3 | `principalMin ≤ principal ≤ principalMax` | `_checkJobWindows` | `PrincipalOutOfRange()` | +| 4 | `now + minDuration ≤ expiredAt ≤ now + maxDuration` | `_checkJobWindows` | `ExpiryOutOfRange()` | +| 5 | `executeBy ≥ now + minExecuteWindow` and `executeBy + settleWindow ≤ expiredAt` | `_checkJobWindows` | `ExecuteByOutOfRange()` | +| 6 | the card's provider is not the current evaluator (it may have changed since registration) | `_checkCardAndJob` | `ProviderIsEvaluator()` | +| 7 | `agw = AGW_FACTORY.predictWallet(intent.owner, intent.index)`; the intent names that wallet and this marketplace as executor | `_resolveWallet` | `IntentWalletMismatch(expected, provided)` · `ExecutorMismatch(expected, actual)` | +| 8 | the AGW has no live job started here | `isAGWFree` | `AGWBusy(agw, lastJobId)` | +| 9 | build the job's criteria from the card's template | `_buildCreateJob` → `JobSpecBuilder.build` | §7.3 errors | +| 10 | encode `createJob(provider, evaluator, expiredAt, description, hook)` as an ERC-7579 single execution: `abi.encodePacked(kernel, 0, call)` | `_buildCreateJob` | — | +| 11 | the intent's `mode`, `execCalldataHash` and `nonceKey` (the startJob owner lane) are exactly this execution, and its `sessionHash` is this session | `_bindIntent` | `IntentExecMismatch(expectedHash)` · `IntentSessionMismatch(expectedHash)` | +| 12 | the session is the card's rules (§6.2) | `_verifyRules` → `TERMS.verifySession` | §6.2 errors | +| — | *first state change* | | | +| 13 | deploy the predicted wallet (`deployWalletWithSig`) and require it landed at the prediction; or, for an existing wallet, require the factory's `ownerOf` is the intent's owner | `_deployOrCheckOwner` | `AGWMismatch(expected, actual)` · `WalletOwnerMismatch(expected, actual)` | +| 14 | `rulesId = AGW.grantRulesWithSig(session, intent, sig)` | `startJob` | the AGW's own errors | +| 15 | `AGW.executeWithSig(mode, calldata, intent, sig)`; exactly one new kernel job; its client is the AGW and its provider, hook and evaluator are the expected ones | `_createJob` | `UnexpectedJobCount(before, after)` · `JobMismatch()` | +| 16 | record `lastJobOf`, `cardOfJob`, `agwOfJob`, `rulesOfJob`; emit `JobStarted` | `startJob` | — | + +**What one signature binds.** The owner signs one `OwnerIntent`. Through it: + +| Bound value | How | +|---|---| +| principal, `executeBy`, params, card version, the wallet (through its CEA) | inside the built `JobSpec`, inside the `createJob` calldata → `execCalldataHash` | +| `expiredAt`, provider, evaluator, hook | `createJob` arguments → `execCalldataHash` | +| the rules (asset, caps, calls, CEA, expiry) | the `Session` → `sessionHash` | +| which wallet, which executor | `wallet`, `executor` fields | +| replay | `nonceKey` / `nonceSeq` (the owner lane) and `grantNonce`, checked by the AGW | + +`test_MS12_intentExecMismatch_everyBoundInput` changes each bound input in turn and expects `IntentExecMismatch`. + +**Who checks the signature.** Not the marketplace. The factory and the wallet verify the owner's signature +themselves and accept the intent only from its `executor` (this contract). The marketplace's own checks +(steps 7 and 11) mirror the wallet's, so a mismatch fails early with a named error before any state change. + +**Previewing.** `previewIntent(request, session)` returns the exact `OwnerIntent` to sign: it predicts the wallet, +builds the same calldata `startJob` will, hashes it, and reads the wallet's live nonces (0 for a wallet not yet +deployed). `buildCreateJobCalldata` returns the execution itself. Both revert `CardInactive` for an unknown card, +and both revert exactly as step 9 would on a bad template. `test_MV04_buildCreateJobCalldata` asserts that what +`startJob` executes equals this view's answer. + +**Front-running.** `startJob` can be called by anyone holding the signed parameters; the relayer has no power. A +third party who submits them first starts exactly the job the owner signed. The AGW's nonces make it one-shot. + +--- + +## 9 · Chains and CEAs + +A card's chain must be configured before any card can name it: + +- **`setCEADeployment(chainHash, ceaFactory, ceaProxyImpl)`** (admin) records the destination chain's CEA factory + and proxy implementation. A chain without one cannot carry cards (`ChainNotSupported`), and the builder cannot + ask for a CEA on it. +- **`expectedCEAOf(agw, chainHash)`** mirrors `CEAFactory._computeCEAInternal`: an OZ minimal proxy of + `ceaProxyImpl`, salt `keccak256(abi.encode(agw))`, deployed by the CEA factory + (`test_MV02_expectedCEAOf` checks it against the real `CEAFactory`). +- **Push itself is never a card chain** (`pushChainHash`, set at `initialize` from `block.chainid`). + +**CEA implementation rotation.** If the destination rotates its CEA proxy implementation, `expectedCEAOf` goes +stale. An honest SDK then signs the new CEA, and `startJob` refuses it with `ExpectedCEAMismatch` until the admin +updates the deployment (`test_MV03_ceaRotation_staleCaught`). Runbook: + +1. `setUniversalPaused(chainHash, true)` stops `startJob` for that chain's cards (`ChainPaused`). +2. Rotate the implementation on the destination chain. +3. `setCEADeployment(chainHash, factory, newImpl)`. +4. `setUniversalPaused(chainHash, false)`. + +The CEA value is security-relevant: it is the beneficiary pin of every rules grant on that chain (§6.2 check 10). +A wrong entry still cannot silently redirect funds, because the SDK derives the CEA independently and the two +must agree. + +--- + +## 10 · One live job per wallet + +Two rules, at two moments: + +| Rule | Where | Busy when | +|---|---|---| +| `isAGWFree(agw)` | marketplace, `startJob` step 8 | the last job **started here** for the AGW is Funded, Submitted, or Open and not yet expired | +| `AGWHasLiveJob` | RulesBindingHook, at `fund` | the AGW's last job **bound by the hook** is Funded or Submitted | + +The marketplace's rule is stronger: an Open, unexpired job also blocks, so a user cannot stack unfunded jobs on +one wallet. An Open job frees the wallet once it expires or is rejected; a Funded or Submitted job frees it once +it is completed, rejected or refunded (`test_MS14_oneLiveJob`). + +Jobs created directly on the kernel, not through the marketplace, are invisible to `isAGWFree`. The hook's rule +still covers any job that names the hook. + +--- + +## 11 · Admin powers + +Roles (OpenZeppelin AccessControl): `DEFAULT_ADMIN_ROLE` manages roles; `ADMIN_ROLE` runs every admin function. +Both go to `InitParams.admin`. Upgrades are separate: they belong to the ProxyAdmin owner. + +| Function | Effect | Limits | +|---|---|---| +| `setHook(hook)` | hook of every **new** job | must be non-zero and whitelisted on the kernel; existing jobs keep theirs | +| `setEvaluator(evaluator)` | evaluator of every **new** job | non-zero; a card whose provider is the new evaluator can't start jobs (`ProviderIsEvaluator`) | +| `setCEADeployment(chainHash, factory, impl)` | enables a chain, sets its CEA derivation | both non-zero | +| `setUniversalPaused(chainHash, bool)` | stops or resumes `startJob` for one chain | — | +| `pause()` / `unpause()` | stops or resumes `registerCard`, `modifyAgentCard`, `startJob` | admin functions, `setCardActive` and views stay live | +| `adminDisableCard(cardId)` | permanently disables a card | cannot re-enable | +| `verifyAgentCard(cardId, version)` / `revokeAgentCardVerification(cardId)` | the verified tag | version-bound | + +The admin cannot move funds (the marketplace holds none), cannot change a started job (the kernel fixed its +provider, evaluator, hook and description at creation), and cannot re-enable a disabled card. + +The admin **can** influence future jobs: the evaluator decides completion, and the hook gates funding. Both are +trust points of the deployment. + +--- + +## 12 · Deployment, upgradeability and build + +### 12.1 Wiring + +1. Deploy `UniversalMarketplaceTerms` (no constructor arguments). +2. Deploy the `JobSpecBuilder` library and link it into `UniversalMarketplace`. Foundry links it automatically in + tests and scripts. +3. Deploy the `UniversalMarketplace` implementation; its constructor disables initializers. +4. Deploy a `TransparentUpgradeableProxy` calling `initialize(InitParams{agwFactory, kernel, hook, evaluator, + terms, admin})`. Every field must be non-zero, and the hook must be whitelisted on the kernel. +5. `setCEADeployment` for each supported destination chain. + +Interim configuration (until the V2 UniversalHook and UniversalEvaluator ship): `hook` = RulesBindingHook, +`evaluator` = a Push-controlled address. + +### 12.2 Upgradeability + +- **The marketplace** sits behind a `TransparentUpgradeableProxy`. Its storage is append-only (slots 0–18, then + a 30-slot gap, 19–48; see [`reference.md`](./reference.md#storage-layout)). OZ upgradeable bases use ERC-7201 + namespaced storage, so they don't occupy these slots. `test_MV09_storageLayout_bySlot` pins every slot by + position, and `test_MV10_upgrade_preservesState` upgrades through the ProxyAdmin. +- **Terms and JobSpecBuilder** are not upgradeable. A rule change is a new deployment plus a marketplace upgrade + that points at it. Terms is an `initialize`-time address (`TERMS`); the library's address is linked into the + implementation's bytecode. + +### 12.3 Build configuration + +- solc 0.8.26, `via_ir`, EVM `shanghai`. +- **`UniversalMarketplace.sol` compiles at 1 000 optimizer runs**; every other contract uses 99 999. This is the + `compilation_restrictions` entry in `foundry.toml`. At 99 999 runs the inliner puts the marketplace over the + EIP-170 limit. +- Coverage must run with `FOUNDRY_PROFILE=coverage`, which drops that restriction. Otherwise contracts tested + from both compile jobs exist twice, and coverage keeps the hits of only one. + +| Contract | Runtime size | Margin to EIP-170 | +|---|---|---| +| UniversalMarketplace (1 000 runs) | 21,283 B | 3,293 B | +| JobSpecBuilder | 6,452 B | 18,124 B | +| UniversalMarketplaceTerms | 5,383 B | 19,193 B | +| RulesBindingHook | 4,539 B | 20,037 B | + +--- + +## 13 · Trust model and security notes + +### 13.1 What the marketplace guarantees + +| Guarantee | Enforced by | Tested by | +|---|---|---| +| The rules granted are exactly the card's, for the card's agent, bound to this job's principal, expiry and CEA | `verifySession` (§6.2) | `MB01`–`MB05`, `MT04`–`MT07` | +| The job's criteria are exactly the card's template, filled with this job's inputs | `_buildCreateJob` + intent binding (§7, §8) | `MS01`, `ML13`, `MV04`, `MC01`–`MC04` | +| The job is created by the user's own wallet, with the card's provider, the configured evaluator and hook | `_createJob` | `MS15` | +| A provider can't change a card under a user's signature | card version in `origin` | `ML11` | +| Nothing moves through the marketplace | no transfer code; no payable function | `MS02`, `MI02`, `MI05` | +| One live job per wallet | `isAGWFree` (§10) | `MS14`, `MI01` | +| Every refusal happens before any state change | step order (§8) | `MS13` | + +### 13.2 What the marketplace relies on, or does not check + +1. **The AGW and its factory verify the owner's signature** and accept the intent only from its executor. They + also enforce deadlines, nonces and the signer chain. The marketplace's mirror checks only name the error + early. The package's own tests use `MockAGW` / `MockAGWFactory`, which verify no signature; the AGW repo's + end-to-end suite runs the real stack. +2. **SmartSession and URP enforce the rules at execution.** The marketplace checks the rules' *content* at grant + time; it does not execute or watch them. +3. **`verifySession` checks the policy's configuration, not which contracts interpret it.** These `Session` + fields are **not** compared to anything: + - `sessionValidator`, the contract that decides who the agent is; + - `actions[0].actionTarget` and `actionTargetSelector`, the call the policy applies to; + - `actions[0].actionPolicies[0].policy`, which policy contract reads the envelope; + - `userOpPolicies`, `erc7739Policies` (ERC-1271 signing permissions), `permitERC4337Paymaster`, `salt`. + + They are inside the owner-signed session (`sessionHash`), so they are what the owner's SDK built. But a + malicious or buggy SDK could name, for example, a permissive validator or policy, or add ERC-7739 signing + rights, and the marketplace would not notice. Pinning them would need marketplace-configured expected values + (for example the URP, validator and gateway addresses). This is listed as a review question in §16. +4. **The criteria are not judged** (§7.3). A provider can register criteria the evaluator cannot run, or that + are trivially satisfied. The verified tag is the review, and the SDK must render every check in words before + the user signs. +5. **The asset check is a sanity check, not a security property.** The asset contract chooses its own + `SOURCE_CHAIN_NAMESPACE()` answer. What binds the asset is URP: the session's asset must equal the card's. +6. **`fee` is a reference price.** The marketplace never enforces it; the kernel does, at `fund`, through the + owner's `expectedBudget`. +7. **`createJob`'s `description` and `expiredAt` are not re-read after creation.** Step 15 checks the new job's + client, provider, hook and evaluator. The description and expiry are trusted to the AGW executing exactly the + signed calldata (its `execCalldataHash` check). +8. **The evaluator and hook are admin-set trust points** for new jobs (§11). + +### 13.3 Reentrancy and external calls + +`startJob` is `nonReentrant` and makes its external calls only after every check: + +1. `AGW_FACTORY.deployWalletWithSig`, a factory the deployment chose; +2. `AGW.grantRulesWithSig`, `AGW.executeWithSig`, on the predicted wallet; +3. `KERNEL.jobCounter`, `KERNEL.getJob`. + +The wallet is the factory's deterministic deployment for the intent's owner, re-checked by `AGWMismatch` / +`WalletOwnerMismatch`. The marketplace holds no value, so a reentrant path has nothing to drain. The views call +`AGW_FACTORY.predictWallet`, the wallet's nonces and the kernel. + +### 13.4 Known limitations of v1 + +| Limitation | Note | +|---|---| +| **The AGW must ship agent identity (AGW "D3")** | `verifySession` requires `sessionValidatorInitData == abi.encode(provider)`. The AGW's current validator expects a different config format, so a real `startJob` fails at `grantRulesWithSig` until the AGW implements D3. The package's tests use `MockAGW`. | +| **EVM destinations only** | Cards name `eip155:*` chains, never Push. Solana and native (Push-side) cards are out of v1. | +| **Interim hook and evaluator** | RulesBindingHook and a Push-controlled evaluator until the V2 UniversalHook and UniversalEvaluator ship. The `JobSpec` description is inert to RulesBindingHook. | +| **Approvals are declared, not executed** | The owner runs them in the SDK-built funding transaction; nothing on-chain checks they ran. | +| **A card can be internally inconsistent** | Registration checks `minExecuteWindow + settleWindow ≤ maxDuration` only. A card whose `minDuration` is shorter than that sum simply can't start jobs at its shortest expiry (`ExecuteByOutOfRange`). | +| **Error decoding** | Each contract's ABI lists only the errors it raises itself. Decode marketplace reverts, including Terms and builder errors that bubble through `startJob`, with the `UniversalMarketplaceErrors` artifact, which lists all 37. | + +--- + +## 14 · Invariants + +Fuzzed by [`UniversalMarketplace.invariants.t.sol`](../../test/8183-tests/UniversalMarketplace.invariants.t.sol): +64 runs × depth 100 per invariant. The handler starts jobs through honest and misbehaving wallets, modifies the +card, cancels jobs and moves time. + +| Invariant | Property | +|---|---| +| `MI01_lastJobOfIsTheAgwsOwnJob` | A recorded job always belongs to the AGW it is recorded under | +| `MI02_marketplaceHoldsNothing` | The marketplace's token, rules-asset and native balances are always 0 | +| `MI03_outcomesExactlyExpected` | An honest start on a free wallet always succeeds; a misbehaving wallet (two jobs, foreign client) is always refused with its own named error | +| `MI04_everyJobIsWellFormed` | Every started job's description decodes as a `JobSpec` with the recorded `origin`, and has the configured evaluator and hook | +| `MI05_userBalanceNeverMovedByStartJob` | The user's tokens and PC never change | +| `afterInvariant` | Liveness: at least one honest start and one refused misbehaviour happened, so none of the above held vacuously | + +--- + +## 15 · Tests + +`forge test --match-path 'test/8183-tests/*'`: 236 tests, all passing. The marketplace-related suites: + +| Suite | Tests | Covers | +|---|---|---| +| [`UniversalMarketplace.t.sol`](../../test/8183-tests/UniversalMarketplace.t.sol) | 57 | Registration (MR), card lifecycle (ML), `startJob` (MS), rules ⊆ card through the marketplace (MB), views, admin, initialize, storage layout, upgrade (MV) | +| [`UniversalMarketplaceTerms.t.sol`](../../test/8183-tests/UniversalMarketplaceTerms.t.sol) | 7 | Terms directly: allow-list, approvals, each `verifySession` error, malformed input, fuzzed caps | +| [`JobSpecBuilder.t.sol`](../../test/8183-tests/JobSpecBuilder.t.sol) | 11 | Fills, targets, timing and origin, params, overflow, fill bounds, unsupported chains, "does not judge", fuzz | +| [`UniversalMarketplace.conformance.t.sol`](../../test/8183-tests/UniversalMarketplace.conformance.t.sol) | 4 | Built criteria equal the Universal Evaluator V2 design doc's hand-written examples, field by field; every built read decodes in a copy of the V2 evaluator's decoder | +| [`UniversalMarketplace.invariants.t.sol`](../../test/8183-tests/UniversalMarketplace.invariants.t.sol) | 5 | §14 | +| [`Naming.t.sol`](../../test/8183-tests/Naming.t.sol) | 5 | Renamed selectors, topics and getters pinned to literal signatures; no retired names in ABIs | +| [`RulesBindingHook.t.sol`](../../test/8183-tests/RulesBindingHook.t.sol) | 31 | The interim hook | + +Test fixtures use the real kernel, the real RulesBindingHook, the real Terms helper and builder library, and the +real `CEAFactory`. The AGW factory and wallet are mocks: they enforce the rules the marketplace relies on +(executor, hashes, nonces) and verify no signature. `MockAGW` has misbehaving modes (two jobs, foreign client, +rewritten evaluator) to test the marketplace's post-creation checks. + +**Coverage** (`FOUNDRY_PROFILE=coverage`, `--ir-minimum`, gas test excluded): + +| Contract | Lines | Statements | Branches | Functions | +|---|---|---|---|---| +| UniversalMarketplace | 97.49% (233/239) | 98.02% (297/303) | 100% (48/48) | 100% (35/35) | +| UniversalMarketplaceTerms | 100% (50/50) | 100% (87/87) | 100% (21/21) | 100% (4/4) | +| JobSpecBuilder | 98.25% (56/57) | 98.78% (81/82) | 100% (12/12) | 100% (7/7) | + +The marketplace's uncovered lines are executed but not attributed by `--ir-minimum`: the constructor's +`_disableInitializers()`, the three OZ `__*_init()` calls in `initialize`, and the `_pause()` / `_unpause()` +bodies. The audited kernel `AgenticCommerce` shows the same six lines unattributed. JobSpecBuilder's one inline +`mstore` line is the same case. + +**Mutation testing.** 52 hand-written mutants were run against the suites: 12 on JobSpecBuilder, 28 on the +marketplace and 12 on Terms. Each removes a check, shifts a bound, or breaks a computed value. Every one was +killed by a named test. That run predates the naming-standard change (`cb69e0b`), which renamed labels only. + +**Gas ceilings** (`test_MS18_gasCeilings`, mock wallet and factory): `registerCard` (lending card) ≤ 2.46 M, +`startJob` on a fresh wallet ≤ 3.49 M, on an existing wallet ≤ 2.09 M. `registerCard` is dominated by storing the +two content blobs; `startJob` by the wallet deploy and the kernel storing the description. + +--- + +## 16 · Reviewer checklist + +Where to look first: + +1. **`startJob` ordering** (§8): every check before the first state change; the intent's `execCalldataHash` + covers everything per-job. +2. **`verifySession` completeness** (§6.2, §13.2 item 3): which `Session` fields are pinned and which are not. + **Open question:** should the marketplace pin `sessionValidator`, the action target and selector, the policy + address, and reject non-empty `userOpPolicies` and `erc7739Policies`? +3. **CEA derivation** (§9): `expectedCEAOf` against `CEAFactory`; the rotation runbook. +4. **`JobSpecBuilder`** ([`criteria.md`](./criteria.md)): the only inline assembly (`mstore` of a fill) and its + bounds check; the PRINCIPAL_BPS overflow argument; the `DELEGATECALL` context (`address(this)` is the + marketplace). +5. **`_requireAssetOnChain`**: the raw `staticcall` ABI-shape check. +6. **Storage layout and upgrade safety** (§12.2, [`reference.md`](./reference.md#storage-layout)). +7. **Admin trust points** (§11): evaluator, hook, CEA deployments. +8. **The interim hook** (`RulesBindingHook`): the `fund`-time binding and the busy rule. diff --git a/plan/agw/research/source-refresh-2026-10-07/contracts/push-chain-core-contracts/docs/universalmarketplace/criteria.md b/plan/agw/research/source-refresh-2026-10-07/contracts/push-chain-core-contracts/docs/universalmarketplace/criteria.md new file mode 100644 index 00000000..57f7cfa0 --- /dev/null +++ b/plan/agw/research/source-refresh-2026-10-07/contracts/push-chain-core-contracts/docs/universalmarketplace/criteria.md @@ -0,0 +1,324 @@ +# Universal Marketplace — Job criteria + +How a card says what counts as "done", and how `startJob` turns that into one job's criteria. For where this fits +in the whole flow, see [`README.md`](./README.md) §7. + +- [Two formats: template and JobSpec](#two-formats-template-and-jobspec) +- [The JobSpec](#the-jobspec) +- [The template](#the-template) +- [Building a JobSpec](#building-a-jobspec) +- [Worked example: a lending card](#worked-example-a-lending-card) +- [Worked example: a swap card with a user param](#worked-example-a-swap-card-with-a-user-param) +- [What the SDK must do](#what-the-sdk-must-do) + +--- + +## Two formats: template and JobSpec + +| | Template (`EvaluationTemplate`) | Criteria (`JobSpec`) | +|---|---|---| +| Where | stored on the card (`abi.encode`d, as given) | the 8183 job's `description` (`abi.encode(JobSpec)`) | +| Written by | the provider, once per card version | `JobSpecBuilder`, once per job | +| Holds | everything that is the same for every job, plus **holes** | concrete values for this job | +| Read by | the marketplace, at `startJob` / previews | the hook (at `fund`) and the evaluator (at verify) | +| Defined in | [`libraries/Types.sol`](../../src/agentic-commerce-8183/libraries/Types.sol) | [`libraries/JobSpecTypes.sol`](../../src/agentic-commerce-8183/libraries/JobSpecTypes.sol) | + +The `JobSpec` is the format of the Universal Evaluator V2 design, plus one field, `origin`. JobSpecTypes is the one +definition shared by everything that writes or reads a job's criteria. Its field order is ABI: reordering or +inserting a field changes every description. + +--- + +## The JobSpec + +```solidity +struct JobSpec { + uint64 executeBy; // the provider must execute before this + uint64 failFinalAt; // a FAIL only counts from a verify started after this + Read[] reads; + Check[] checks; + Node[] nodes; // nodes[0] is the root: the job passes if it passes + bytes32 origin; // keccak256(abi.encode(marketplace, cardId, cardVersion, principal)) +} +``` + +### Reads: what to look at + +```solidity +struct Read { + string chainNamespace; // namespace only, "eip155" + string chainId; // decimal, e.g. "11155111" + uint16 minConfirmations; // confirmations before the answer counts + address target; // the contract to call + bytes4 selector; // the view function + bytes args; // abi-encoded arguments + bytes outputs; // the function's return types, as type codes + uint8[] field; // which returned value, by ABI position +} +``` + +A read is one view call on one chain. **`chainNamespace` here is the namespace only** (`"eip155"`), with +`chainId` separate: the Read State split of the V2 design. That differs from `AgentCard.chainNamespace`, which is +the full CAIP-2 string `"eip155:"`. + +`outputs` describes the return types so the evaluator can find one value in the answer. Codes: + +| Code | Type | Code | Type | +|---|---|---|---| +| 1 `T_UINT` | `uintN` | 6 `T_BYTES` | `bytes` | +| 2 `T_INT` | `intN` | 7 `T_STRING` | `string` | +| 3 `T_BOOL` | `bool` | 8 `T_TUPLE` | tuple / struct: followed by its field count, then each field's type | +| 4 `T_ADDRESS` | `address` | 9 `T_ARRAY` | `T[]`: followed by the element type | +| 5 `T_BYTESN` | `bytesN` | 10 `T_FIXED_ARRAY` | `T[k]`: followed by `k`, then the element type | + +The top level is always a tuple of the return values. For example, `balanceOf(address) returns (uint256)` is +`[T_TUPLE, 1, T_UINT]`. + +`field` is the path to the value: at a tuple, the field index; at an array, the element index. `[0]` is the first +return value; `[0, 2]` is the first return value's third field. + +How the evaluator turns the selected value into a number (from the V2 design; a test-only copy of its decoder is +[`test/8183-tests/helpers/V2Decoder.sol`](../../test/8183-tests/helpers/V2Decoder.sol)): + +| Leaf | Value compared | +|---|---| +| uint / int | the number (a uint above `int256.max` is "can't tell") | +| bool | 0 or 1 | +| address, bytesN | the raw word (compare with EQ / NEQ) | +| bytes, string | `keccak256` of the content | +| array | its length | + +### Checks: what to compare + +```solidity +struct Check { + uint8 read; // index into reads + EvalType evalType; + Op op; // EQ, NEQ, GT, GTE, LT, LTE + int256 target; // in the contract's own units +} +``` + +| `EvalType` | Compares | +|---|---| +| `BOOL` | the value now, as a bool | +| `CMP` | the value now | +| `NUM` | the change since the snapshot the hook takes at `fund` (V2 UniversalHook) | +| `PCT` | the percentage change since that snapshot | + +### Nodes: the pass logic + +```solidity +struct Node { + NodeKind kind; // CHECK, ALL, ANY, AT_LEAST + uint8 check; // CHECK only: index into checks + uint8[] children; // ALL / ANY / AT_LEAST: indexes into nodes, each greater than this node's own + uint8 k; // AT_LEAST only: how many children must pass +} +``` + +`nodes[0]` is the root. `ALL` is AND, `ANY` is OR, `AT_LEAST k` is any `k` of the children. Children always have +a higher index than their parent, so the tree has no cycles and can be evaluated from the last node to the first. + +### Timing + +- **`executeBy`**: the provider must have executed by then. +- **`failFinalAt = executeBy + card.settleWindow`**: a FAIL verdict only counts from a verify started after this, + so slow settlement on the destination chain is not misread as failure. + +The marketplace guarantees `executeBy ≥ now + minExecuteWindow` and `failFinalAt ≤ expiredAt` (`startJob` step 5). + +### `origin` + +`keccak256(abi.encode(marketplace, cardId, cardVersion, principal))`. The hook and evaluator ignore it. It ties +the job to the card version it was started from, and it is what makes an intent signed against one version +unusable on another: the version is inside the signed calldata. + +--- + +## The template + +```solidity +struct EvaluationTemplate { + ReadTemplate[] reads; + CheckTemplate[] checks; + Node[] nodes; // copied verbatim + ParamBounds[] params; // one entry per per-job number the user supplies +} +``` + +### ReadTemplate: a Read with fills + +```solidity +struct ReadTemplate { + string chainNamespace; // "eip155" + string chainId; + uint16 minConfirmations; + address target; + bytes4 selector; + bytes args; // with placeholder words + Fill[] fills; // what to write into args per job + bytes outputs; + uint8[] field; +} + +enum FillSource { CEA, PARAM } + +struct Fill { + uint8 word; // overwrites args[32·word : 32·word + 32] + FillSource source; + uint8 param; // PARAM only: index into the job's params +} +``` + +| Fill source | Word written | +|---|---| +| `CEA` | the AGW's CEA **on this read's chain**, as a 32-byte word | +| `PARAM` | the job's `params[param]`, as a 32-byte word (two's complement for negatives) | + +A CEA fill is how criteria name "this user's account": `balanceOf(CEA)`, `ownerOf(tokenId) == CEA`, and so on. +The CEA is derived per read chain, so one template can read two chains, each with that chain's CEA. + +### CheckTemplate: a Check with a target source + +```solidity +enum TargetSource { FIXED, PRINCIPAL_BPS, PARAM, CEA } + +struct CheckTemplate { + uint8 read; + EvalType evalType; + Op op; + TargetSource source; + int256 value; +} +``` + +| Source | `value` means | Target | +|---|---|---| +| `FIXED` | the target | `value` | +| `PRINCIPAL_BPS` | basis points of the principal | `principal × value / 10 000`, rounded down | +| `PARAM` | an index into the job's params | `params[value]` | +| `CEA` | unused | the AGW's CEA on the check's read chain, as `int256(uint160(cea))` | + +`PRINCIPAL_BPS` is how criteria scale with the job's size ("at least 99.99% of the principal arrived"). + +### ParamBounds: per-job numbers + +```solidity +struct ParamBounds { int256 min; int256 max; } // inclusive +``` + +A template may declare numbers the user picks per job (a minimum swap output, a tick range, …). The job supplies +exactly one value per entry, each inside its bounds. The values feed `PARAM` fills and `PARAM` targets. Units are +the provider's, described in the card's metadata. + +--- + +## Building a JobSpec + +[`JobSpecBuilder.build`](../../src/agentic-commerce-8183/libraries/JobSpecBuilder.sol), called at `startJob` +step 9 and by both preview views: + +1. **Decode** the template. Undecodable bytes revert in `abi.decode`. +2. **Params**: `params.length == template.params.length`, else `ParamCountMismatch(expected, actual)`; each + `min ≤ params[i] ≤ max`, else `ParamOutOfRange(i, value)`. +3. **CEAs**: for each read with a CEA fill, and each read a `CEA`-target check names, get + `expectedCEAOf(agw, keccak256(namespace ":" chainId))` from the marketplace, once per read. A chain without a + CEA deployment reverts `ChainNotSupported(chainHash)`. +4. **Reads**: copy each read; copy its `args` into a fresh buffer; apply each fill. A fill must satisfy + `32·word + 32 ≤ args.length`, else `FillOutOfBounds(read, fill)`. This bound check is what makes the one + inline-assembly `mstore` safe. +5. **Checks**: copy `read`, `evalType`, `op`; resolve the target. For `PRINCIPAL_BPS`, if + `principal > type(uint256).max / bps`, revert `TargetOverflow(check)`. Once the product fits, the quotient is at + most `uint256.max / 10 000`, which always fits in `int256`, so the cast cannot truncate. +6. **Nodes** copied verbatim. `executeBy`, `failFinalAt = executeBy + settleWindow`, `origin`. +7. Return `abi.encode(spec)`. + +**Not checked:** whether the criteria make sense or can be run. That covers caps on the number of reads, checks +or nodes; outputs that are not valid type codes; fields that point nowhere; reads no check uses; unreachable +nodes; and trivially true criteria. All of these build as given (`test_JB08_doesNotJudgeTheTemplate`). The caps +`MAX_READS` (16), `MAX_CHECKS` (16) and `MAX_NODES` (32) in JobSpecTypes are the evaluator's, not enforced here. +An out-of-range index (a check's `read`, a fill's `param`, a `PARAM` target) panics. Anything that reverts here +makes `startJob` and both previews of that card revert. + +The result is deterministic for a given card version, job inputs and CEA configuration +(`testFuzz_JB11_deterministic`). + +--- + +## Worked example: a lending card + +"Deposit the principal into Aave v3 on Sepolia, at a supply rate of at least 4%." This is the test fixture's card +(`_lendingTemplate` in [`UniversalMarketplace.t.sol`](../../test/8183-tests/UniversalMarketplace.t.sol)) and the V2 +design doc's lending example. + +**Card:** `chainNamespace = "eip155:11155111"`, `settleWindow = 2 h`. + +**Rules:** asset pUSDC (Sepolia); one allowed call `Pool.supply(address,uint256,address,uint16)` with the +beneficiary (`onBehalfOf`) pinned at offset 68; one approval, USDC → Pool, `capIsPrincipal`. + +**Template:** + +``` +reads[0] eip155 / 11155111, 12 confirmations + aUSDC.balanceOf(address) args = 32 zero bytes fills = [word 0 ← CEA] + outputs = [TUPLE 1, UINT] field = [0] +reads[1] eip155 / 11155111, 12 confirmations + Pool.getReserveData(address) args = abi.encode(USDC) fills = [] + outputs = [TUPLE 1, TUPLE 15, (TUPLE 1, UINT), UINT×7, ADDRESS×4, UINT×3] + field = [0, 2] (the struct's 3rd field: currentLiquidityRate) +checks[0] read 0, CMP, GTE, PRINCIPAL_BPS, 9999 "deposited ≥ 99.99% of principal" +checks[1] read 1, CMP, GTE, FIXED, 0.04e27 "rate ≥ 4% (ray)" +nodes [ ALL(1, 2), CHECK 0, CHECK 1 ] +params [] +``` + +**A job:** principal 500 USDC (`500e6`), `executeBy = now + 1 h`, for wallet 0 of the user. + +**Built JobSpec:** + +``` +reads[0].args = abi.encode(CEA(agw, "eip155:11155111")) +checks[0].target = 500e6 × 9999 / 10 000 = 499 950 000 +checks[1].target = 0.04e27 +nodes = [ ALL(1, 2), CHECK 0, CHECK 1 ] +executeBy = now + 1 h +failFinalAt = now + 3 h +origin = keccak256(abi.encode(marketplace, cardId, 1, 500e6)) +``` + +The evaluator later passes the job if both checks pass: the CEA's aUSDC balance is at least 499.95 USDC, and +Aave's current supply rate is at least 4%. + +`test_MC01_lendingExample_equalsV2Doc` builds the same template on Ethereum (the design doc's chain) and compares +the result, field by field, with the V2 design doc's hand-written JobSpec. + +## Worked example: a swap card with a user param + +"The CEA receives at least `minOut` WETH." `minOut` is chosen by the user per job. + +``` +reads[0] eip155 / 11155111, 3 confirmations + WETH.balanceOf(address) args = 32 zero bytes fills = [word 0 ← CEA] + outputs = [TUPLE 1, UINT] field = [0] +checks[0] read 0, NUM, GTE, PARAM, 0 "balance grew by ≥ params[0]" +nodes [ CHECK 0 ] +params [ {min: 1, max: 1e30} ] +``` + +A job with `params = [0.38e18]` gets `checks[0].target = 0.38e18`. `NUM` compares the change since the snapshot +the V2 UniversalHook takes at `fund`, so WETH the CEA already held doesn't count. (The interim RulesBindingHook +takes no snapshot; `NUM` and `PCT` checks need the V2 hook.) A job with `params = [0]` reverts +`ParamOutOfRange(0, 0)`; one with no params reverts `ParamCountMismatch(1, 0)`. + +--- + +## What the SDK must do + +- **Build templates from ABIs**: `outputs` and `field` from the function's ABI and the chosen return field, and + CEA fills where the CEA appears in the arguments. +- **Render every check in words before the user signs.** The template is not judged on-chain; what the user sees + is their protection, together with the verified tag. +- **Use `previewIntent`** to get the exact intent to sign, so the signed calldata hash covers the built criteria. +- **Derive the CEA independently** from the destination `CEAFactory` for the session's `expectedCEA`, and treat a + disagreement with `expectedCEAOf` as an error. diff --git a/plan/agw/research/source-refresh-2026-10-07/contracts/push-chain-core-contracts/docs/universalmarketplace/reference.md b/plan/agw/research/source-refresh-2026-10-07/contracts/push-chain-core-contracts/docs/universalmarketplace/reference.md new file mode 100644 index 00000000..68bcf8db --- /dev/null +++ b/plan/agw/research/source-refresh-2026-10-07/contracts/push-chain-core-contracts/docs/universalmarketplace/reference.md @@ -0,0 +1,426 @@ +# Universal Marketplace — Reference + +Every function, event, error, type and storage slot of the Universal Marketplace package. For how they fit +together, read [`README.md`](./README.md) first. Section numbers like "§8" refer to that file. + +- [UniversalMarketplace](#universalmarketplace) + - [Initialization](#initialization) + - [Admin functions](#admin-functions) + - [Card functions](#card-functions) + - [startJob](#startjob) + - [Views](#views) + - [Constants](#constants) + - [Storage layout](#storage-layout) +- [UniversalMarketplaceTerms](#universalmarketplaceterms) +- [JobSpecBuilder](#jobspecbuilder) +- [RulesBindingHook (interim hook)](#rulesbindinghook-interim-hook) +- [Types](#types) +- [Events](#events) +- [Errors](#errors) + +--- + +## UniversalMarketplace + +[`src/agentic-commerce-8183/UniversalMarketplace.sol`](../../src/agentic-commerce-8183/UniversalMarketplace.sol). +Inherits OZ `Initializable`, `AccessControlUpgradeable`, `PausableUpgradeable`, `ReentrancyGuardUpgradeable` and +`IUniversalMarketplace`. Deployed behind a `TransparentUpgradeableProxy`. It has no payable function and holds +no funds. + +### Initialization + +#### `constructor()` +Calls `_disableInitializers()`, so the implementation itself can never be initialized. + +#### `initialize(InitParams calldata p)` — `initializer` + +| Step | Effect | +|---|---| +| 1 | Reverts `ZeroAddress()` if `agwFactory`, `kernel`, `terms` or `admin` is zero. | +| 2 | Initializes AccessControl, Pausable and ReentrancyGuard. | +| 3 | Stores `AGW_FACTORY`, `KERNEL`, `TERMS`. | +| 4 | `pushChainHash = keccak256("eip155:" ‖ decimal(block.chainid))`. | +| 5 | `_setHook(p.hook)`: `ZeroAddress()` if zero, `HookNotWhitelisted()` unless `KERNEL.whitelistedHooks(hook)`; emits `HookUpdated`. | +| 6 | `_setEvaluator(p.evaluator)`: `ZeroAddress()` if zero; emits `EvaluatorUpdated`. | +| 7 | Grants `DEFAULT_ADMIN_ROLE` and `ADMIN_ROLE` to `p.admin`. | + +A second call reverts `InvalidInitialization()` (OZ). + +### Admin functions + +All are `onlyRole(ADMIN_ROLE)`; a non-admin caller gets `AccessControlUnauthorizedAccount(caller, ADMIN_ROLE)`. +None is pausable. + +#### `setHook(address hook)` +Sets the hook every **new** job is created with. Reverts `ZeroAddress()` or `HookNotWhitelisted()`. Emits +`HookUpdated(hook)`. Existing jobs keep the hook the kernel recorded at creation. + +#### `setEvaluator(address evaluator)` +Sets the evaluator every **new** job is created with. Reverts `ZeroAddress()`. Emits `EvaluatorUpdated(evaluator)`. +Not checked against providers: a card whose provider is now the evaluator is refused at `startJob` +(`ProviderIsEvaluator()`). + +#### `setCEADeployment(bytes32 chainHash, address ceaFactory, address ceaProxyImpl)` +Records a destination chain's CEA factory and proxy implementation. This enables the chain for cards and for +criteria reads, and sets the CEA derivation (§9). Reverts `ZeroAddress()` if either address is zero. Emits +`CEADeploymentSet(chainHash, ceaFactory, ceaProxyImpl)`. A deployment cannot be removed, only replaced. + +#### `setUniversalPaused(bytes32 chainHash, bool paused)` +Pauses or resumes `startJob` for cards on `chainHash` (`ChainPaused(chainHash)`). Card registration on that chain +is not affected. Emits `UniversalChainPaused(chainHash, paused)`. + +#### `pause()` / `unpause()` +OZ Pausable. While paused, `registerCard`, `modifyAgentCard` and `startJob` revert `EnforcedPause()`. Admin +functions, `setCardActive` and every view stay live. + +#### `adminDisableCard(uint256 cardId)` +Permanently disables a card: `isCardAdminDisabled = true`, `active = false`, verified tag cleared. Reverts +`CardInactive()` for an unknown card. Emits `CardVerificationRevoked(cardId)` (only if it was verified), then +`CardDisabledByAdmin(cardId)`. Nothing re-enables it. + +#### `verifyAgentCard(uint256 cardId, uint256 version)` +Sets the verified tag for the card's current version. + +| Revert | When | +|---|---| +| `CardInactive()` | unknown card | +| `CardAdminDisabled(cardId)` | admin-disabled card | +| `CardVersionMismatch(version, current)` | `version` is not the current version, e.g. the card changed after review | + +Allowed for a card its provider switched off. Emits `CardVerified(cardId, version)`. + +#### `revokeAgentCardVerification(uint256 cardId)` +Clears the tag. Reverts `CardInactive()` for an unknown card. Idempotent: emits `CardVerificationRevoked(cardId)` +only if the card was verified. + +### Card functions + +#### `registerCard(AgentCard calldata c, bytes calldata rulesTerms, bytes calldata evaluation) returns (uint256 cardId)` — `whenNotPaused` + +| Step | Effect | +|---|---| +| 1 | `_validateCard(c, rulesTerms)`: the 12 checks of §4.2, in order. | +| 2 | `cardId = ++cardCount` (ids start at 1). | +| 3 | Stores the card, then overwrites `provider = msg.sender` and `active = true`. | +| 4 | Stores both blobs as given; `cardVersion = 1`. | +| 5 | Emits `CardRegistered(cardId, msg.sender, jobType, chainNamespace, keccak256(rulesTerms), keccak256(evaluation), metadataHash, fee)`. | + +`evaluation` is **not** checked (§7.3). `rulesTerms` must decode as `RulesCardTerms`; undecodable bytes revert +in `abi.decode` with no data. + +#### `modifyAgentCard(uint256 cardId, AgentCard calldata c, bytes calldata rulesTerms, bytes calldata evaluation)` — `whenNotPaused` + +| Step | Effect / revert | +|---|---| +| 1 | `CallerIsNotProvider()` unless the card exists and `msg.sender` is its provider. | +| 2 | `CardAdminDisabled(cardId)` if admin-disabled. | +| 3 | `CardIdentityImmutable()` if `c.chainNamespace` differs from the stored one. | +| 4 | `_validateCard(c, rulesTerms)`, as at registration. | +| 5 | Writes every field except `provider`, `chainNamespace` and `active`; replaces both blobs. | +| 6 | `version = ++cardVersion[cardId]`; clears the verified tag (emits `CardVerificationRevoked` if there was one). | +| 7 | Emits `CardModified(cardId, version, keccak256(rulesTerms), keccak256(evaluation), metadataHash, fee)`. | + +Started jobs are untouched (`test_ML12`). Intents signed against the previous version stop working (§4.3). + +#### `setCardActive(uint256 cardId, bool active)` +Provider only (`CallerIsNotProvider()`, also for an unknown card). Switching on an admin-disabled card reverts +`CardAdminDisabled(cardId)`; switching it off is allowed. Emits `CardStatusChanged(cardId, active)`. Not pausable. + +### startJob + +#### `startJob(StartJobParams calldata p) returns (uint256 jobId, address agw, bytes32 rulesId)` — `whenNotPaused nonReentrant` + +Deploys the AGW if needed, grants it the card's rules and creates the job. The 16 steps, checks and errors are in +§8. Emits `JobStarted(cardId, intent.owner, agw, jobId, rulesId, principal, cardVersion)`. + +`StartJobParams`: + +| Field | Meaning | +|---|---| +| `cardId` | the card | +| `cardVersion` | the version the owner signed against; must equal the current version | +| `job` | `JobInputs{principal, expiredAt, executeBy, params}` | +| `session` | the rules (SmartSession `Session`) the owner signed | +| `intent` | the owner-signed `OwnerIntent` (from `previewIntent`) | +| `sig` | the owner's signature over the intent | +| `label` | wallet label, used only when deploying a new wallet | + +Calls made, in order, after every check: `AGW_FACTORY.deployWalletWithSig` (new wallet) or +`AGW_FACTORY.ownerOf` (existing wallet); `AGW.grantRulesWithSig`; `KERNEL.jobCounter`; `AGW.executeWithSig`; +`KERNEL.jobCounter`; `KERNEL.getJob`. + +### Views + +| View | Returns | Notes | +|---|---|---| +| `getCard(uint256 cardId)` | `CardView{card, rulesTerms, evaluation, version, verified, adminDisabled}` | All zero for an unknown card. | +| `isCardVerified(uint256 cardId)` | `bool` | Verified at the current version. | +| `isCardAdminDisabled(uint256 cardId)` | `bool` | | +| `isUniversalPaused(bytes32 chainHash)` | `bool` | | +| `cardVersion(uint256 cardId)` | `uint256` | 1 at registration, +1 per modification, 0 if unknown. | +| `cardCount()` | `uint256` | The last card id. | +| `ceaDeployment(bytes32 chainHash)` | `(address ceaFactory, address ceaProxyImpl)` | Zero if unconfigured. | +| `lastJobOf(address agw)` | `uint256` | The AGW's last job started here; 0 if none. | +| `cardOfJob(uint256 jobId)` / `agwOfJob` / `rulesOfJob` | card id / AGW / `rulesId` | Recorded by `startJob`; zero for jobs not started here. | +| `AGW_FACTORY()`, `KERNEL()`, `TERMS()` | addresses | Set once at `initialize`. | +| `hook()`, `evaluator()` | addresses | Admin-settable. | +| `pushChainHash()` | `bytes32` | `keccak256("eip155:" ‖ block.chainid)` at initialization. | +| `isAGWFree(address agw)` | `bool` | False while the AGW's last job started here is Funded, Submitted, or Open and unexpired (§10). | +| `expectedCEAOf(address agw, bytes32 chainHash)` | `address` | The AGW's CEA on that chain (§9). Reverts `ChainNotSupported(chainHash)` if unconfigured. | +| `buildCreateJobCalldata(uint256 cardId, address owner, uint96 index, JobInputs job)` | `(bytes32 mode, bytes executionCalldata)` | Exactly what `startJob` executes for wallet `index` of `owner`. Reverts `CardInactive()` for an unknown card, and like step 9 on a bad template or bad inputs. | +| `previewIntent(IntentRequest r, Session s)` | `OwnerIntent` | The intent to sign (§8). Nonces are read from the wallet, or 0 if not yet deployed. Reverts like `buildCreateJobCalldata`. | +| `hasRole`, `paused`, … | | OZ AccessControl and Pausable views. | + +`previewIntent` output: + +| Field | Value | +|---|---| +| `owner`, `index`, `deadline`, `signerChainId` | from the request | +| `wallet` | `AGW_FACTORY.predictWallet(owner, index)` | +| `executor` | the marketplace | +| `sessionHash` | `keccak256(abi.encode(session))` | +| `mode` | `MODE_SINGLE` (0) | +| `execCalldataHash` | `keccak256(buildCreateJobCalldata(...))` | +| `nonceKey` | `STARTJOB_LANE` | +| `nonceSeq` | `AGW.getNonce(STARTJOB_LANE)` if deployed, else 0 | +| `grantNonce` | `AGW.grantNonce()` if deployed, else 0 | + +### Constants + +| Constant | Value | Use | +|---|---|---| +| `ADMIN_ROLE` | `keccak256("ADMIN_ROLE")` | every admin function | +| `STARTJOB_LANE` | `OWNER_LANE_FLAG` (`1 << 191`) | the AGW nonce lane `startJob`'s execution uses (owner lane, key 0) | +| `MODE_SINGLE` | `bytes32(0)` | ERC-7579 single call, default exec type | +| `MIN_DURATION` (internal) | `1 hours` | lower bound on a card's `minDuration` | +| `EVM_PREFIX` (internal) | `"eip155:"` | required prefix of a card's `chainNamespace` | + +### Storage layout + +Append-only from this layout. OZ upgradeable bases use ERC-7201 namespaced storage and occupy none of these +slots. Pinned by `test_MV09_storageLayout_bySlot`. + +| Slot | Variable | Type | +|---|---|---| +| 0 | `AGW_FACTORY` | `IAGWFactory` | +| 1 | `KERNEL` | `IAgenticCommerce` | +| 2 | `hook` | `address` | +| 3 | `evaluator` | `address` | +| 4 | `pushChainHash` | `bytes32` | +| 5 | `TERMS` | `IUniversalMarketplaceTerms` | +| 6 | `cardCount` | `uint256` | +| 7 | `_cards` | `mapping(uint256 => AgentCard)` | +| 8 | `_rulesTerms` | `mapping(uint256 => bytes)` | +| 9 | `_evaluations` | `mapping(uint256 => bytes)` | +| 10 | `cardVersion` | `mapping(uint256 => uint256)` | +| 11 | `isCardVerified` | `mapping(uint256 => bool)` | +| 12 | `isCardAdminDisabled` | `mapping(uint256 => bool)` | +| 13 | `ceaDeployment` | `mapping(bytes32 => CEADeployment)` | +| 14 | `isUniversalPaused` | `mapping(bytes32 => bool)` | +| 15 | `lastJobOf` | `mapping(address => uint256)` | +| 16 | `cardOfJob` | `mapping(uint256 => uint256)` | +| 17 | `agwOfJob` | `mapping(uint256 => address)` | +| 18 | `rulesOfJob` | `mapping(uint256 => bytes32)` | +| 19–48 | `__gap` | `uint256[30]` | + +--- + +## UniversalMarketplaceTerms + +[`src/agentic-commerce-8183/UniversalMarketplaceTerms.sol`](../../src/agentic-commerce-8183/UniversalMarketplaceTerms.sol). +Stateless and `pure`, with no admin and no upgrade. Split out of the marketplace for EIP-170. Reverts with +`UniversalMarketplaceErrors`, so its reverts bubble through the marketplace unchanged. + +| Constant | Value | +|---|---| +| `MAX_ALLOWED_CALLS` | 32 (URP's allow-list bound) | +| `MAX_APPROVALS` | 8 | +| `ERC20_TRANSFER` / `ERC20_APPROVE` / `ERC20_TRANSFER_FROM` | `IERC20.transfer/approve/transferFrom.selector` (`0xa9059cbb` / `0x095ea7b3` / `0x23b872dd`) | +| `ERC20_INCREASE_ALLOWANCE` | `bytes4(keccak256("increaseAllowance(address,uint256)"))` (`0x39509351`) | + +#### `validateRulesTerms(bytes calldata rulesTerms) external pure returns (address asset)` +Decodes `RulesCardTerms` and runs the registration guards of §6.1. Returns the rules asset. Undecodable bytes +revert in `abi.decode`. + +#### `verifySession(bytes calldata rulesTerms, Session calldata s, SessionContext calldata ctx) external pure` +The rules ⊆ card check of §6.2, ten checks in order. `ctx` is +`SessionContext{agent, chainHash, principal, expiredAt, expectedCEA}`, filled by the marketplace from the card, +the job and `expectedCEAOf`. The fields it does not compare are listed in §13.2. + +--- + +## JobSpecBuilder + +[`src/agentic-commerce-8183/libraries/JobSpecBuilder.sol`](../../src/agentic-commerce-8183/libraries/JobSpecBuilder.sol). +An external library: deployed once, linked into the marketplace, called by `DELEGATECALL`. Inlined, it would put +the marketplace over the size limit. + +#### `build(bytes memory evaluation, BuildContext memory ctx) public view returns (bytes memory)` +Returns `abi.encode(JobSpec)` for one job: the 8183 job's description. Algorithm and checks are in +[`criteria.md`](./criteria.md#building-a-jobspec). + +`BuildContext{agw, principal, executeBy, settleWindow, params, origin}` comes from the job's inputs, the card's +`settleWindow`, and `origin = keccak256(abi.encode(marketplace, cardId, cardVersion, principal))`. + +The library reads CEAs with `IUniversalMarketplace(address(this)).expectedCEAOf(agw, chainHash)`. Under +`DELEGATECALL`, `address(this)` is the marketplace proxy, so this is an external call back into the marketplace. +Called directly (not through the marketplace), a template that needs a CEA reverts, because the library would ask +itself. It has no storage. + +--- + +## RulesBindingHook (interim hook) + +[`src/agentic-commerce-8183/hooks/RulesBindingHook.sol`](../../src/agentic-commerce-8183/hooks/RulesBindingHook.sol), +on [`BaseERC8183Hook`](../../src/agentic-commerce-8183/hooks/BaseERC8183Hook.sol). Not part of the marketplace, +but every marketplace job is created with it until the V2 UniversalHook ships. Behind a +`TransparentUpgradeableProxy`; storage continues the base at slot 50. + +| Item | Behaviour | +|---|---| +| `initialize(address kernel, address agwFactory, address sessionEngine)` | All non-zero (`ERC8183HookErrors.ZeroAddress()`). Sets `KERNEL`, `AGW_FACTORY`, `SESSION_ENGINE`. | +| `beforeAction` / `afterAction` | Kernel only (`CallerIsNotKernel(caller)`). Acts only in `beforeAction(fund)`; every other action passes through. | +| `beforeAction(fund)` | In order: `fund.optParams` is exactly 32 bytes, `abi.encode(rulesId)` (`InvalidOptParams(length)`); the client is a factory AGW (`CallerIsNotAGW(caller)`); `SESSION_ENGINE.isPermissionEnabled(rulesId, client)` (`RulesNotLive(agw, rulesId)`); the AGW has no Funded or Submitted job under this hook (`AGWHasLiveJob(agw, liveJobId)`). Then records `rulesOf[jobId] = {agw, rulesId}`, `liveJobOf[agw] = jobId`, and emits `RulesBound(jobId, agw, rulesId)`. | +| `isAGWBusy(address agw)` | Whether the AGW's bound job is Funded or Submitted. | +| `rulesOf(uint256 jobId)` | `(address agw, bytes32 rulesId)` bound at `fund`. | +| `liveJobOf(address agw)` | The last job bound for the AGW. | + +Because the hook runs in `beforeAction`, any revert leaves the job Open with no escrow moved. A wallet is freed +by reading the kernel's job status, so an unhooked `claimRefund` frees it too. + +--- + +## Types + +All in [`libraries/Types.sol`](../../src/agentic-commerce-8183/libraries/Types.sol), file-level. The built +criteria (`JobSpec`, `Read`, `Check`, `Node` and the enums) are in +[`libraries/JobSpecTypes.sol`](../../src/agentic-commerce-8183/libraries/JobSpecTypes.sol). The AGW and +SmartSession types (`OwnerIntent`, `Session`, `AllowedCall`, `UniversalTerms`, …) are mirrored in +[`interfaces/external/IAGW.sol`](../../src/agentic-commerce-8183/interfaces/external/IAGW.sol). + +| Type | Fields | Notes | +|---|---|---| +| `AgentCard` | `provider`, `jobType`, `metadataURI`, `metadataHash`, `chainNamespace`, `fee`, `principalMin`, `principalMax`, `minDuration`, `maxDuration`, `minExecuteWindow`, `settleWindow`, `active` | `provider` and `active` are contract-written. `chainNamespace` is the full CAIP-2 string `"eip155:"`, immutable after registration. `fee` is in the kernel's payment token; principal is in the rules asset's units; durations and windows in seconds. | +| `Approval` | `token`, `spender`, `capIsPrincipal`, `cap` | An owner approval on the execution chain. `capIsPrincipal` ⇒ amount = principal, `cap == 0`; else amount = `cap > 0`. | +| `RulesCardTerms` | `asset`, `maxPCPerCall`, `allowedCalls`, `approvals` | `abi.encode`d into the card's `rulesTerms`. | +| `CEADeployment` | `ceaFactory`, `ceaProxyImpl` | Per destination chain. | +| `CardView` | `card`, `rulesTerms`, `evaluation`, `version`, `verified`, `adminDisabled` | `getCard`'s return. | +| `JobInputs` | `principal`, `expiredAt` (uint48), `executeBy` (uint48), `params` (int256[]) | Per-job inputs the owner signs. | +| `StartJobParams` | `cardId`, `cardVersion`, `job`, `session`, `intent`, `sig`, `label` | `startJob`'s argument. | +| `IntentRequest` | `cardId`, `owner`, `index`, `job`, `deadline`, `signerChainId` | `previewIntent`'s argument. | +| `InitParams` | `agwFactory`, `kernel`, `hook`, `evaluator`, `terms`, `admin` | `initialize`'s argument. | +| `SessionContext` | `agent`, `chainHash`, `principal`, `expiredAt`, `expectedCEA` | Terms' per-job context. | +| `FillSource`, `Fill`, `ReadTemplate`, `TargetSource`, `CheckTemplate`, `ParamBounds`, `EvaluationTemplate`, `BuildContext` | | The criteria template; see [`criteria.md`](./criteria.md). | + +--- + +## Events + +Emitted by the marketplace (declared in `IUniversalMarketplace`): + +| Event | Emitted by | +|---|---| +| `CardRegistered(uint256 indexed cardId, address indexed provider, bytes32 indexed jobType, string chainNamespace, bytes32 rulesHash, bytes32 evaluationHash, bytes32 metadataHash, uint256 fee)` | `registerCard` | +| `CardModified(uint256 indexed cardId, uint256 version, bytes32 rulesHash, bytes32 evaluationHash, bytes32 metadataHash, uint256 fee)` | `modifyAgentCard` | +| `CardStatusChanged(uint256 indexed cardId, bool active)` | `setCardActive` | +| `CardDisabledByAdmin(uint256 indexed cardId)` | `adminDisableCard` | +| `CardVerified(uint256 indexed cardId, uint256 version)` | `verifyAgentCard` | +| `CardVerificationRevoked(uint256 indexed cardId)` | `revokeAgentCardVerification`, `modifyAgentCard`, `adminDisableCard` (only when a tag is cleared) | +| `HookUpdated(address hook)` | `initialize`, `setHook` | +| `EvaluatorUpdated(address evaluator)` | `initialize`, `setEvaluator` | +| `CEADeploymentSet(bytes32 indexed chainHash, address ceaFactory, address ceaProxyImpl)` | `setCEADeployment` | +| `UniversalChainPaused(bytes32 indexed chainHash, bool paused)` | `setUniversalPaused` | +| `JobStarted(uint256 indexed cardId, address indexed owner, address indexed agw, uint256 jobId, bytes32 rulesId, uint256 principal, uint256 cardVersion)` | `startJob` | + +`rulesHash = keccak256(rulesTerms)` and `evaluationHash = keccak256(evaluation)`, so an indexer can check the +blobs returned by `getCard`. The hook emits `RulesBound(uint256 indexed jobId, address indexed agw, bytes32 indexed rulesId)`. +OZ emits `RoleGranted`, `Paused`, `Unpaused`, `Initialized`. + +--- + +## Errors + +All marketplace, Terms and builder errors are in the `UniversalMarketplaceErrors` library +([`libraries/Errors.sol`](../../src/agentic-commerce-8183/libraries/Errors.sol)). A library error has the same +selector wherever it is raised, so a Terms or builder revert bubbles through `startJob` unchanged. + +Each contract's ABI lists only the errors that contract itself raises. **Decode marketplace reverts with the +`UniversalMarketplaceErrors` artifact**, which lists all 37. + +### Config and cards + +| Error | Raised by | When | +|---|---|---| +| `ZeroAddress()` | marketplace | a zero address in `initialize`, `setHook`, `setEvaluator`, `setCEADeployment` | +| `HookNotWhitelisted()` | marketplace | the hook is not whitelisted on the kernel | +| `CardInactive()` | marketplace | `startJob` on an unknown or inactive card; `adminDisableCard`, `verifyAgentCard`, `revokeAgentCardVerification`, `buildCreateJobCalldata`, `previewIntent` on an unknown card | +| `CallerIsNotProvider()` | marketplace | `modifyAgentCard` / `setCardActive` by anyone but the provider, or on an unknown card | +| `CardAdminDisabled(uint256 cardId)` | marketplace | modify, verify or switch on an admin-disabled card | +| `ChainNotSupported(bytes32 chainHash)` | marketplace, builder | a card on Push or on an unconfigured chain; `expectedCEAOf` for an unconfigured chain | +| `ChainPaused(bytes32 chainHash)` | marketplace | `startJob` on a paused chain | +| `InvalidCard(string reason)` | marketplace, Terms | a registration / modification check failed; the reasons are below | +| `CardVersionMismatch(uint256 provided, uint256 current)` | marketplace | `startJob` or `verifyAgentCard` with a stale version | +| `CardIdentityImmutable()` | marketplace | `modifyAgentCard` changing `chainNamespace` | + +`InvalidCard` reasons: + +| Raised by | Reasons | +|---|---| +| marketplace | `job type zero`, `metadata uri empty`, `metadata hash zero`, `chain namespace`, `provider is evaluator`, `principal range`, `duration range`, `settle window`, `execute window`, `asset`, `asset chain` | +| Terms | `asset zero`, `allow-list size`, `duplicate call`, `erc20 approval`, `erc20 transfer recipient`, `erc20 transferFrom recipient`, `approval count`, `approval token`, `approval spender`, `approval cap`, `duplicate approval` | + +### startJob: the job + +| Error | Raised by | When | +|---|---|---| +| `PrincipalOutOfRange()` | marketplace | principal outside the card's range | +| `ExpiryOutOfRange()` | marketplace | `expiredAt` outside `[now + minDuration, now + maxDuration]` | +| `ExecuteByOutOfRange()` | marketplace | `executeBy < now + minExecuteWindow` or `executeBy + settleWindow > expiredAt` | +| `ProviderIsEvaluator()` | marketplace | the card's provider is the current evaluator | +| `ParamCountMismatch(uint256 expected, uint256 actual)` | builder | wrong number of params | +| `ParamOutOfRange(uint256 index, int256 value)` | builder | a param outside its bounds | +| `TargetOverflow(uint256 check)` | builder | `principal × bps` overflows | +| `FillOutOfBounds(uint256 read, uint256 fill)` | builder | a fill writes outside its read's args | + +### startJob: wallet and intent + +Same shapes as the AGW's errors of the same name. + +| Error | When | +|---|---| +| `IntentWalletMismatch(address expected, address provided)` | the intent's wallet is not `predictWallet(owner, index)` | +| `ExecutorMismatch(address expected, address actual)` | the intent's executor is not the marketplace | +| `IntentSessionMismatch(bytes32 actual)` | the intent's `sessionHash` is not this session's hash (argument: the expected hash) | +| `IntentExecMismatch(bytes32 actualCalldataHash)` | the intent's mode, calldata hash or nonce lane is not this job's (argument: the expected calldata hash) | +| `AGWBusy(address agw, uint256 jobId)` | the AGW has a live job started here | +| `AGWMismatch(address expected, address actual)` | the factory deployed somewhere other than the prediction | +| `WalletOwnerMismatch(address expected, address actual)` | the existing wallet's factory owner is not the intent's owner | + +### startJob: rules ⊆ card (Terms) + +| Error | When | +|---|---| +| `AgentMismatch()` | `sessionValidatorInitData != abi.encode(card.provider)` | +| `ActionCount()` | the session has not exactly one action | +| `PolicyShape(uint256 i)` | the action has not exactly one policy | +| `ChainMismatch(uint256 i)` | the envelope names another chain | +| `AssetMismatch()` | another asset | +| `PCCapMismatch()` | another `maxPCPerCall` | +| `ActionsMismatch()` | the allowed calls are not byte-equal to the card's | +| `CapMismatch()` | `maxAmountTotal != principal` or `maxAmountPerCall > principal` | +| `ExpiryMismatch()` | `validUntil != expiredAt` | +| `ExpectedCEAMismatch(address expected, address actual)` | the session's CEA is not `expectedCEAOf(agw, chainHash)` | + +### startJob: the created job + +| Error | When | +|---|---| +| `UnexpectedJobCount(uint256 before, uint256 afterCount)` | the wallet's execution did not create exactly one job | +| `JobMismatch()` | the new job's client, provider, hook or evaluator is not the expected one | + +### Hook errors + +| Library | Error | +|---|---| +| `RulesBindingHookErrors` | `InvalidOptParams(uint256 length)`, `CallerIsNotAGW(address caller)`, `RulesNotLive(address agw, bytes32 rulesId)`, `AGWHasLiveJob(address agw, uint256 liveJobId)` | +| `ERC8183HookErrors` | `CallerIsNotKernel(address caller)`, `ZeroAddress()` | diff --git a/plan/agw/research/source-refresh-2026-10-07/donut-probe.json b/plan/agw/research/source-refresh-2026-10-07/donut-probe.json new file mode 100644 index 00000000..2e54066d --- /dev/null +++ b/plan/agw/research/source-refresh-2026-10-07/donut-probe.json @@ -0,0 +1,167 @@ +{ + "checked_at": "2026-10-07T10:26:27.725Z", + "rpc": "https://evm.donut.rpc.push.org/", + "chain_id": 42101, + "block": "23989371", + "block_hash": "0x6dcdb58bdb4434a67f65128b4def2175a2fe4ce693e56f5c1ae23bca6bbd3162", + "code": { + "factory": { + "address": "0xaF88D0FD947afAe7bBb8F34e8417DCfc165e1aaF", + "bytes": 141, + "sha256": "c621e945a17be2361dfc247326991d732ede3e25c8ecd8b48ee2025c10ca17eb", + "unchanged": true + }, + "validator": { + "address": "0x068EE2388475A98EE1f5a434C58bFF3444fffFe6", + "bytes": 806, + "sha256": "7a8e45814fd8a0a6c9b9e115d797da078718f9f6358fa576e1e218ffd93db59e", + "unchanged": true + }, + "core": { + "address": "0x00000000000000000000000000000000000000C0", + "bytes": 1551, + "sha256": "2036ba987ed029f1bc576d020ba11582934583c7eaaa7c00aefc2e0d53053486", + "unchanged": true + }, + "executor": { + "address": "0x14191Ea54B4c176fCf86f51b0FAc7CB1E71Df7d7", + "bytes": 0, + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "unchanged": true + }, + "proxyAdmin": { + "address": "0x0b7a31ec85117892aEA90AA5cB6514e2F97c2295", + "bytes": 926, + "sha256": "3feda633be447e268d618b40cbfcd9dfe9346ebadec981f4f3efea0fbc07cd35", + "unchanged": true + }, + "walletImplementation": { + "address": "0x96D69ec7e6cDdaD414e656B5c9DCA24587DF713c", + "bytes": 16564, + "sha256": "b26d74bdac5c936e25c694394be9b17bc350325d62ba103d262882b0605a0be1", + "unchanged": true + }, + "policyImplementation": { + "address": "0xA2391eee4C9EA1B32AEB3A460B77296EA709F02F", + "bytes": 24326, + "sha256": "1694277b24a023615b3693730ea0581e7a6fc209f533e65416d5075ef927df76", + "unchanged": true + }, + "policy": { + "address": "0x603E7f0aF6e1aAFf46DDfb28b1e99364f8BC59af", + "bytes": 830, + "sha256": "039e9bca120a30980a0131552966575b30349654f23746f309fe98adfd2308ae", + "unchanged": true + }, + "gateway": { + "address": "0x00000000000000000000000000000000000000C1", + "bytes": 1551, + "sha256": "3e78a5778be1383f2612556becde8019c22388d7157574c90fb40e1060d450ca", + "unchanged": true + }, + "factoryLogic": { + "address": "0xe138Dc6EfC10233BE1e6c8aF1Caf8cABe599cfC2", + "bytes": 9992, + "sha256": "69cc6b0cfae87debb1da55ba152f0129a8f24e80a740199ab29277811b106ecf", + "unchanged": true + }, + "engine": { + "address": "0x165A5E6782f39D30B38c7D97e1303e4CB2aD102a", + "bytes": 22581, + "sha256": "c4b9fc7b045d9f33953079a91fcb7ae883dd858d9cde827a9cc3df6043bc2d0b", + "unchanged": true + } + }, + "slots": { + "factory": { + "implementation": { + "value": "0x000000000000000000000000e138dc6efc10233be1e6c8af1caf8cabe599cfc2", + "unchanged": true + } + }, + "policy": { + "implementation": { + "value": "0x000000000000000000000000a2391eee4c9ea1b32aeb3a460b77296ea709f02f", + "unchanged": true + }, + "admin": { + "value": "0x0000000000000000000000000b7a31ec85117892aea90aa5cb6514e2f97c2295", + "unchanged": true + } + }, + "gateway": { + "implementation": { + "value": "0x0000000000000000000000001e412939780f2b834dc42c7ac58d9f99888da659", + "unchanged": true + } + } + }, + "reads": [ + { + "contract": "factory", + "signature": "walletImplementation()(address)", + "value": "0x96D69ec7e6cDdaD414e656B5c9DCA24587DF713c", + "unchanged": true + }, + { + "contract": "factory", + "signature": "paused()(bool)", + "value": "false", + "unchanged": true + }, + { + "contract": "policy", + "signature": "version()(string)", + "value": "3.1.0", + "unchanged": true + }, + { + "contract": "policy", + "signature": "pushChainHash()(bytes32)", + "value": "0x3d6bc1f1d3fb03065860265a8e93840b586e57075d956cd41b4319d040be87f9", + "unchanged": true + }, + { + "contract": "policy", + "signature": "UNIVERSAL_GATEWAY_PC()(address)", + "value": "0x00000000000000000000000000000000000000C1", + "unchanged": true + }, + { + "contract": "policy", + "signature": "UNIVERSAL_EXECUTOR_MODULE()(address)", + "value": "0x14191Ea54B4c176fCf86f51b0FAc7CB1E71Df7d7", + "unchanged": true + }, + { + "contract": "walletImplementation", + "signature": "accountId()(string)", + "value": "push.agw.1.0.0", + "unchanged": true + }, + { + "contract": "walletImplementation", + "signature": "SESSION_ENGINE()(address)", + "value": "0x165A5E6782f39D30B38c7D97e1303e4CB2aD102a", + "unchanged": true + }, + { + "contract": "walletImplementation", + "signature": "RULES_POLICY()(address)", + "value": "0x603E7f0aF6e1aAFf46DDfb28b1e99364f8BC59af", + "unchanged": true + }, + { + "contract": "walletImplementation", + "signature": "SESSION_VALIDATOR()(address)", + "value": "0x068EE2388475A98EE1f5a434C58bFF3444fffFe6", + "unchanged": true + }, + { + "contract": "walletImplementation", + "signature": "UNIVERSAL_GATEWAY_PC()(address)", + "value": "0x00000000000000000000000000000000000000C1", + "unchanged": true + } + ] +} diff --git a/plan/agw/research/source-refresh-2026-10-07/reproduce-sdk-findings.cjs b/plan/agw/research/source-refresh-2026-10-07/reproduce-sdk-findings.cjs new file mode 100644 index 00000000..ec213a8a --- /dev/null +++ b/plan/agw/research/source-refresh-2026-10-07/reproduce-sdk-findings.cjs @@ -0,0 +1,35 @@ +/** Read-only source-level reproductions. No RPC, signer, funding or .env use. */ +const path = require('node:path'); +const assert = require('node:assert/strict'); +const root = process.env.AGW_REVIEW_SDK_ROOT || path.resolve(__dirname, '../../../..'); +const { AgenticRevertError } = require(path.join(root, 'packages/core/src')); +const { composeAgwSvmAction } = require(path.join(root, 'packages/core/src/lib/agentic/execution/svm-outbound')); +const { encodeAgwSvmPayload, validateAgwSvmPayload } = require(path.join(root, 'packages/core/src/lib/agentic/execution/svm-payload')); +const { sendPublicSvm } = require(path.join(root, 'packages/core/src/lib/agentic/execution/svm-public')); +const { buildSvmPayloadFromParams } = require(path.join(root, 'packages/core/src/lib/orchestrator/svm-idl/build-payload')); +const hex = c => '0x' + c.repeat(32); +const program = hex('33'), token = '0x'+'55'.repeat(20); +const terms = { + initialized:true, validUntil:1700000100, expectedCEA:hex('44'), gatewayProgram:hex('22'), + assets:[{token,maxPerCall:5n,maxTotal:50n,spent:0n}], maxGasPerCall:10n, + programs:[{program,discriminator:'0x0102030405060708',discriminatorLen:8,dataless:false,maxAccounts:1}], + pins:[{ruleIndex:0,accountIndex:0,expected:hex('44')}], dataPins:[], ceaAccounts:[hex('44')], +}; +const instruction = Uint8Array.from([1,2,3,4,5,6,7,8]); +const allowedPayload = encodeAgwSvmPayload(program,[{pubkey:hex('44'),isWritable:true}],instruction); +const request = {wallet:'0x'+'11'.repeat(20),gateway:'0x00000000000000000000000000000000000000c1',token,amount:1n,recipient:program,payload:allowedPayload,gasLimit:200000n,protocolFee:1n,maxPCForGas:1n}; +function capture(fn) { try { fn(); throw Error('expected refusal'); } catch(e) { return { name:e.name, code:e.code, message:e.message, isAgenticRevertError:e instanceof AgenticRevertError, decodedError:e.decodedError??null, details:e.details }; } } +(async()=>{ + const expired = capture(()=>composeAgwSvmAction(request, terms, 1700000101)); + assert.equal(expired.code,'RULE_LIMIT_EXCEEDED'); assert.equal(expired.isAgenticRevertError,false); assert.equal(expired.decodedError,null); + const payload=encodeAgwSvmPayload(program,[{pubkey:hex('66'),isWritable:true}],Uint8Array.from([1,2,3,4,5,6,7,8])); + const wrongAccount=capture(()=>validateAgwSvmPayload(terms,program,payload)); + assert.equal(wrongAccount.details.contractError,'SvmAccountPinMismatch'); assert.equal(wrongAccount.isAgenticRevertError,false); assert.equal(wrongAccount.decodedError,null); + const p={to:{address:program,chain:'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1'},funds:{amount:1n}}; + let executions=0,ownerFundsOnly; + try{await sendPublicSvm({execute:()=>{executions++;throw Error('must not execute');}},{wallet:'0x'+'11'.repeat(20),door:'owner',generation:{capabilities:new Set(['universalSvmRules','ownerExecute'])}},p);}catch(e){ownerFundsOnly={code:e.code,message:e.message,executions};} + assert.equal(ownerFundsOnly.code,'INVALID_RULE');assert.equal(executions,0); + const ordinary=buildSvmPayloadFromParams({...p,senderUea:'0x'+'11'.repeat(20)}); + assert.equal(ordinary.hasExecute,false);assert.equal(ordinary.svmPayload,'0x'); + console.log(JSON.stringify({sdkCommit:'898eda17',scope:'source-level, no transactions',expired,wrongAccount,ownerFundsOnly,ordinaryFundsOnlyPayload:ordinary},null,2)); +})(); diff --git a/plan/agw/research/source-refresh-2026-10-07/sdk-findings.json b/plan/agw/research/source-refresh-2026-10-07/sdk-findings.json new file mode 100644 index 00000000..b2dea338 --- /dev/null +++ b/plan/agw/research/source-refresh-2026-10-07/sdk-findings.json @@ -0,0 +1,34 @@ +{ + "sdkCommit": "898eda17", + "scope": "source-level, no transactions", + "expired": { + "name": "AgenticError", + "code": "RULE_LIMIT_EXCEEDED", + "message": "RulesExpired", + "isAgenticRevertError": false, + "decodedError": null, + "details": { + "contractError": "RulesExpired" + } + }, + "wrongAccount": { + "name": "AgenticError", + "code": "INVALID_RULE", + "message": "SvmAccountPinMismatch", + "isAgenticRevertError": false, + "decodedError": null, + "details": { + "contractError": "SvmAccountPinMismatch" + } + }, + "ownerFundsOnly": { + "code": "INVALID_RULE", + "message": "Solana AGW sends require one encoded instruction; arrays and funds-only sends are unsupported", + "executions": 0 + }, + "ordinaryFundsOnlyPayload": { + "svmPayload": "0x", + "targetBytes": "0x3333333333333333333333333333333333333333333333333333333333333333", + "hasExecute": false + } +} diff --git a/plan/agw/research/source-refresh-2026-10-07/solana-probe.json b/plan/agw/research/source-refresh-2026-10-07/solana-probe.json new file mode 100644 index 00000000..461cbde7 --- /dev/null +++ b/plan/agw/research/source-refresh-2026-10-07/solana-probe.json @@ -0,0 +1,36 @@ +{ + "checkedAt": "2026-10-07T10:37:51.814Z", + "chain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "genesis": "EtWTRABZaYq6iMfeYKouRu166VU2xqa1wcaWoxPkrZBG", + "slot": 508426857, + "programDataSlot": 508426857, + "programs": [ + { + "address": "CFVSincHYbETh2k7w6u1ENEkjbSLtveRCEBupKidw2VS", + "programData": "DqeV1giGX9UPbTCsUaqau4ZaTqmjxKeRa4TQdbLiUCYC", + "lastUpgradeSlot": "496655369", + "dataLength": 724997, + "dataSha256": "2633943f479debc6bf0cba19861f90dfd01a09ecba206b2ce941c97281b8a95d" + }, + { + "address": "8yNqjrMnFiFbVTVQcKij8tNWWTMdFkrDf9abCGgc2sgx", + "programData": "GQmC7eueNLqazwr7U9fR3s4VwbXUtNf1HL6UCXuSWvaN", + "lastUpgradeSlot": "447956626", + "dataLength": 279709, + "dataSha256": "6887b9299b53bcaede79facbe9d9a53c9a0ba78e2c109322caef070b57637f95" + } + ], + "gatewayConfig": { + "address": "2urirovTZSgpEAEFyf2dMWjMTqfkgg1J3piTBeSEwV5P", + "paused": false, + "dataSha256": "1f7595b955ae35e2ea577db04d3e73f30d7284d9536910065e0fc7b078b6ae33" + }, + "counter": { + "address": "6Kg1NF5RRytjGwR6USttBLEYJrqwm65xtJzdPbbFwJKg", + "value": "201909018", + "authority": "BesWssuCiGE3EqeGRFamuouvAxJDUCdWH6NPHpAFPMBa", + "dataSha256": "a496e0cf4db5b48523ebbf917e7d021abd5d9651775ef8f5c5943aca35c22a7a" + }, + "counterIdlSha256": "493678d103afab762cc1668d02c641226125166ba8b4d7df46b67fec52b3a9ca", + "gatewayIdlSha256": "62d7792d04c657e1224f7c64d13b68e2f49dd39fdd6da0088deca0c32a5fb042" +} diff --git a/plan/agw/research/v5-implementation-2026-10-07/README.md b/plan/agw/research/v5-implementation-2026-10-07/README.md new file mode 100644 index 00000000..dc8e10e1 --- /dev/null +++ b/plan/agw/research/v5-implementation-2026-10-07/README.md @@ -0,0 +1,44 @@ +# SDK v5 integration and label acceptance — October 7, 2026 + +The SDK now targets the current Donut v5 suite only. The existing `wallet.setLabel(label, opts?)` method is enabled. There is no new caller-facing method or automatic rule-selection change. Validation ran locally before commit and push. No contracts were deployed and no package was published during this implementation. + +## Implementation + +- Replaced the v4 deployment/adapter/ABI directories and fixtures with v5. Default source is `2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb`; factory is `0x8137F96A50EBF41d904e3678c84c391a0D1BCcc5`, wallet implementation is `0x4D459Da499C14548aa16c46c57fD92880A88EBb4`, first scan block is 23989983. Existing v4 wallets are unsupported by this adapter, in accordance with the user's no-legacy direction. +- Durable ABI snapshots come from an isolated build of the exact v5 source. The local harness and ABI generator use that pin. [ABI signature changes](abi-signature-changes.json): wallet adds `label`, `setLabel`, `LabelSet` and `LabelTooLong`, and changes `initializeAccount()` to `initializeAccount(string)`. Factory, URP, engine and validator signatures are unchanged. This signature comparison does not itself prove bytecode equivalence. +- Wallet `info()` and `list()` read current labels at their snapshot block via `label()`, without deployment-event lookup. Custom labels and computed defaults are preserved. Undeployed preview slots still have an empty label. +- Public renames validate the 64 UTF-8 byte cap and signer ownership before signing, permit empty reset, use a single owner `execute` call targeting the wallet's own setter, await confirmation and forward the per-call progress hook. This works for EOA and UEA owners. It records **one owner-action checkpoint**; the underlying setter itself records none. +- Create validates the same byte cap before any RPC/signature. Create-race recovery uses the immutable deploy-event label, rather than the now-mutable label view. Regression tests cover a competing wallet renamed to match the requested label and a same-label deployment renamed afterward. +- `LabelTooLong` participates in the existing decoded contract error mapping. Source address/domain context and deterministic wallet prediction use the new factory. No rule encoding, ambiguity handling or authorization policy is changed. +- Added five registered public label E2Es and five actual-contract SDK label tests; updated shared E2E manifest verification to check the v5 selectors because `accountId()` has not changed. Updated the consumer guide, current planning status and team delivery documents. +- Existing uncommitted SVM alignment changes were preserved. Their prior proof remains recorded separately; no new live Solana delivery is claimed here. + +## Validation + +| Check | Result | +| --- | --- | +| Full core units | **2,010 passed, 12 skipped, 0 failed**; 120 passing suites | +| SDK against actual pinned v5 contracts on Anvil | **90 passed**, 12 suites; gateway/core/token/destination fixtures retain their documented limits | +| Regenerated contract vectors | Separate read-only comparison against the saved v5 fixture passed | +| Typechecks | Library, spec (including E2Es), local-contract harness passed; final library/spec checks also passed | +| Build | `core:build --skip-nx-cache` passed | +| Consumer/package | CJS/ESM imports on Node 20, compiled declarations, npm dry-run contents and 10 guide blocks passed; no legacy v4 contract directory remains in built output | +| API comparison | Compiled declarations match source; no transaction method, instance method or initialize-signature change against the checker baseline. Broader type changes in its report also include the earlier SVM work | +| Lint | Scoped AGW code/tests: 0 errors, 95 warnings (primarily existing test assertions and unused test imports); not claimed warning-free | +| E2E registration | **53 AGW scenarios / 13 files / 53 tests**; default `all` unchanged at **76 / 40 / 81** | +| Live Donut v5 | **15 scenarios verified across selected runs**: five labels, six native execution, four rule lifecycle | +| Integrity | `git diff --check` passed; changed/new text files checked for the available test credentials with no matches | + +See [logs/](logs/), [live-evidence.jsonl](live-evidence.jsonl), and [api-comparison.json](api-comparison.json). [Read-only deployment/source verification](../deployment-review-2026-10-07-v5/README.md) preceded these funded SDK tests. + +## Live run details and limits + +The main run of labels, native execution and lifecycle finished **14 passed / 1 failed**. The failure was a test assertion expecting the later dispatch guard: a normal granted rule has no policy for wallet-self `setLabel`, so SmartSession correctly reverts earlier with `NoPoliciesSet`. Exact source confirms validation precedes dispatch. The assertion now decodes that engine error, and its focused rerun passed with label and checkpoint state unchanged. The other four label tests passed in the main run, including UEA ownership, rename and reset. This is not a claim of one unfiltered 15-pass invocation. + +An earlier labels-only run was **4 passed / 1 failed** because its agent test created a wallet with no agent rule, so initialization correctly refused that signer. The corrected fixture grants an ordinary native rule. Both initial logs are retained rather than hidden. One multi-file run printed Jest's open-handle notice after completion and subsequently exited; no claim of a completely silent test runner is made. + +Funded runs used only Donut and the existing Sepolia-origin test signer, fresh v5 wallets and fresh native agents. Each fixture funds its agent with the configured default 0.5 PC; the external-owner label case funds its UEA with a bounded 3 PC. Native fixture wallets receive 0.01 PC and bounded additional expiry-test value. No mainnet transaction, deployment or external team message was sent, and no credential was saved in the evidence. + +The current source passes all 90 local contract cases, including EVM/SVM codecs, composition, accounting and rollback. Full live destination suites were **not rerun on v5**: prior v4 destination delivery evidence must not be represented as v5 delivery. Refund spend-credit wiring and bridge retry timing remain downstream operational dependencies. Node 24's full runtime matrix was not rerun in this pass. + +The upstream signed-deploy label is still cosmetic and unsigned in OwnerIntent; this documented contract behavior is preserved. Successful rename transactions and actual wallet label/checkpoint reads are now verified live, extending the earlier read-only deployment review which had no existing clone to inspect. diff --git a/plan/agw/research/v5-implementation-2026-10-07/abi-signature-changes.json b/plan/agw/research/v5-implementation-2026-10-07/abi-signature-changes.json new file mode 100644 index 00000000..45143d5e --- /dev/null +++ b/plan/agw/research/v5-implementation-2026-10-07/abi-signature-changes.json @@ -0,0 +1,30 @@ +{ + "wallet": { + "added": [ + "function:initializeAccount(string)", + "function:label()", + "function:setLabel(string)", + "event:LabelSet(string)", + "error:LabelTooLong(uint256)" + ], + "removed": [ + "function:initializeAccount()" + ] + }, + "factory": { + "added": [], + "removed": [] + }, + "engine": { + "added": [], + "removed": [] + }, + "policy": { + "added": [], + "removed": [] + }, + "validator": { + "added": [], + "removed": [] + } +} diff --git a/plan/agw/research/v5-implementation-2026-10-07/api-comparison.json b/plan/agw/research/v5-implementation-2026-10-07/api-comparison.json new file mode 100644 index 00000000..2454ca5e --- /dev/null +++ b/plan/agw/research/v5-implementation-2026-10-07/api-comparison.json @@ -0,0 +1,11460 @@ +{ + "baseline": "b1597b91a25dbf7f691f589b4e1e154add604315", + "head": "898eda17911133faa155899ac8e1276a589c4564", + "compiledMatchesSource": true, + "initializeSignatureChanged": false, + "addedExports": [ + "DecodedSolanaRule", + "SolanaRule", + "SvmAccountRef", + "SvmFieldConstraint", + "SvmInstructionRule" + ], + "removedExports": [], + "changedAgwTypes": [ + "AgenticError", + "AGENTIC_ERROR_CODE", + "NativeRule", + "AllowedCall", + "UniversalRule", + "RulesRecord", + "AgenticTxMetadata" + ], + "publicTypeChanges": [ + "AGENTIC_ERROR_CODE", + "AgenticError", + "AgenticErrorCode", + "AgenticNetworkConstants", + "AgenticTxMetadata", + "AllowedCall", + "NativeRule", + "SolanaRule", + "DecodedSolanaRule", + "SvmInstructionRule", + "SvmAccountRef", + "SvmFieldConstraint", + "Rule", + "RulesRecord", + "UniversalRule" + ], + "transactionMethodChanges": [], + "instanceMethodChanges": [], + "agwConstantsChanged": true, + "before": { + "exports": [ + "AGENTIC_ERROR_CODE", + "AccountRole", + "AccountStatus", + "AccountType", + "AgenticAddress", + "AgenticDoor", + "AgenticError", + "AgenticErrorCode", + "AgenticHex", + "AgenticNamespace", + "AgenticNetworkConstants", + "AgenticProgressHook", + "AgenticRevertError", + "AgenticTxMetadata", + "AgenticWallet", + "AllowedCall", + "AssetCap", + "BatchReadResponse", + "BuildReadSpecParams", + "CHAIN", + "CONTRACT_REQUEST_STATUS", + "CascadeCompletionResult", + "CascadeHopInfo", + "CascadeProgressEvent", + "CascadeTrackOptions", + "CascadedTxResponse", + "ChainSource", + "ChainTarget", + "Checkpoint", + "CheckpointKind", + "ConversionQuote", + "CreateOptions", + "CreateResult", + "DEFAULT_MAX_PC_FOR_GAS_BUFFER_BPS", + "DecodedErrorPayload", + "DecodedReadResult", + "DerivedExecutorAccount", + "EncodedReadQuery", + "EvmReadQuery", + "ForeignChainNamespace", + "FulfilOutcome", + "FundsToken", + "InsufficientPC20BalanceError", + "InvalidPC20AddressError", + "InvalidPC20MetadataError", + "InvalidReadQueryError", + "InvalidReadSpecError", + "MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT", + "MaxPCForGasCapFromNativeValueInput", + "MaxPCForGasCapInput", + "MaxPCForGasCapQuote", + "MultiChainTxResponse", + "NativeRule", + "OutboundTxDetails", + "PC20AddressResult", + "PC20AmbiguousAddressError", + "PC20Error", + "PC20ExpectedButPRC20Error", + "PC20ExportRevertedError", + "PC20FactoryMismatchError", + "PC20RegistryEntry", + "PC20RegistryMismatchError", + "PC20TokenChainMismatchError", + "PC20TokenReference", + "PC20UnknownChainNamespaceError", + "PC20UnsafeEmptyPayloadError", + "PC20WrapperNotRegisteredError", + "PC20WrapperPredictionUnavailableError", + "ParsedReadRequest", + "PreparedRead", + "PreparedUniversalTx", + "PushChain", + "PushChainBatchExecutionError", + "PushChainExecutionError", + "PushChainInitializeOptions", + "READ_ERROR_CODE", + "READ_OUTCOME", + "READ_STATUS", + "ReadCallback", + "ReadCallbackOptions", + "ReadChain", + "ReadDecodeError", + "ReadDestination", + "ReadExecuteOptions", + "ReadFees", + "ReadHeightUnavailableError", + "ReadLifecycleOptions", + "ReadNotFoundError", + "ReadOptions", + "ReadPreflight", + "ReadPrepareOptions", + "ReadQuery", + "ReadQueryOptions", + "ReadRef", + "ReadRegistryUnavailableError", + "ReadResponseTuple", + "ReadResultShape", + "ReadSpec", + "ReadSpecTuple", + "ReadSpecViolation", + "ReadStateError", + "ReadTimeoutError", + "ReadTrackOptions", + "ReadValue", + "ReadWeb2Options", + "ReceiptLike", + "RescueFundsParams", + "ResolvedAccount", + "ResolvedControllerAccounts", + "ResolvedDestination", + "Rule", + "RulesRecord", + "Selector", + "SignAuthorizationParams", + "SignedAuthorization", + "SimulateReadResult", + "SvmExecutePayloadFields", + "SvmGatewayAccountMeta", + "SvmReadQuery", + "TERMINAL_READ_STATUSES", + "TransactionRoute", + "TransactionRouteType", + "UEAStatus", + "UNIVERSAL_CALLBACK_EVM", + "UNIVERSAL_READ_REGISTRY_EVM", + "UNIVERSAL_READ_STATUS", + "UniversalAccount", + "UniversalExecuteParams", + "UniversalOutboundTxRequest", + "UniversalReadResponse", + "UniversalRule", + "UniversalSigner", + "UniversalSignerSkeleton", + "UniversalTo", + "UnsupportedPC20DestinationError", + "UnsupportedReadDestinationError", + "ValidateReadCall", + "WaitForOutboundOptions", + "WalletInfo", + "WalletSummary", + "Web2Extract", + "Web2ReadQuery", + "Web2ValueType", + "buildErc20WithdrawalMulticall", + "buildMigrationPayload", + "buildReadSpecFromPreflight", + "chainSupportsCEA", + "chainSupportsOutbound", + "decodeReadResult", + "detectRoute", + "encodeReadQuery", + "encodeSvmExecutePayload", + "getAllCEAAddresses", + "getCEAAddress", + "getCEAFactoryAddress", + "getPushAccountForCEA", + "inferResultShape", + "isCEA", + "isChainTarget", + "isPC20Reference", + "isSvmChain", + "isValidSolanaHexAddress", + "parseFulfilOutcome", + "parseReadRequestsFromReceipt", + "parseUEAVersion", + "quoteMaxPCForGasCap", + "quoteMaxPCForGasCapFromNativeValue", + "resolveDestination", + "sizeCallbackBudget", + "toCallData", + "toReadQuery", + "toRequestIdHex", + "validateReadSpec" + ], + "agw": { + "AgenticNamespace": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace", + "members": { + "create": { + "optional": false, + "readonly": false, + "type": "(label: string, options: import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions) => Promise" + }, + "derive": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n index?: number;\n}) => Promise<{\n address: `0x${string}`;\n deployed: boolean;\n index: number;\n}>" + }, + "list": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n wallets: import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary[];\n}>" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "(address: `0x${string}`) => import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet" + } + } + }, + "AgenticWallet": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "checkpoints": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n sinceBlock?: bigint;\n}) => Promise<{\n checkpoints: import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint[];\n}>" + }, + "info": { + "optional": false, + "readonly": false, + "type": "() => Promise" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n owner: `0x${string}`;\n}>" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "{\n add(rules: import(\"sdk/src/lib/agentic/agentic.types\").Rule[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise<{\n rulesIds: `0x${string}`[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n get(rulesId: `0x${string}`): Promise;\n list(): Promise<{\n rules: import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord[];\n }>;\n revoke(rulesIds: `0x${string}`[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n revoke(params: {\n all: true;\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n update(params: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n rules: {\n rule: import(\"sdk/src/lib/agentic/agentic.types\").Rule;\n rulesId: `0x${string}`;\n }[];\n }): Promise<{\n rules: {\n replaced: `0x${string}`;\n rulesId: `0x${string}`;\n }[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n}" + }, + "setLabel": { + "optional": false, + "readonly": false, + "type": "(label: string, opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n}) => Promise" + } + } + }, + "AgenticError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"CREATE_PARTIAL\" | \"DUPLICATE_RULE\" | \"FROM_NOT_ALLOWED\" | \"GATEWAY_ALLOWANCE_INSUFFICIENT\" | \"GENERATION_UNSUPPORTED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"REVOKE_NEEDS_TARGET\" | \"RULE_LIMIT_EXCEEDED\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"" + }, + "details": { + "optional": true, + "readonly": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "AgenticRevertError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticRevertError", + "members": { + "agenticCode": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + } + } + }, + "AGENTIC_ERROR_CODE": { + "type": "{\n readonly AGENT_GAS_INSUFFICIENT: \"AGENT_GAS_INSUFFICIENT\";\n readonly AGENT_IS_OWNER: \"AGENT_IS_OWNER\";\n readonly ASSET_CHAIN_MISMATCH: \"ASSET_CHAIN_MISMATCH\";\n readonly CAPABILITY_UNAVAILABLE: \"CAPABILITY_UNAVAILABLE\";\n readonly CREATE_PARTIAL: \"CREATE_PARTIAL\";\n readonly DUPLICATE_RULE: \"DUPLICATE_RULE\";\n readonly FROM_NOT_ALLOWED: \"FROM_NOT_ALLOWED\";\n readonly GATEWAY_ALLOWANCE_INSUFFICIENT: \"GATEWAY_ALLOWANCE_INSUFFICIENT\";\n readonly GENERATION_UNSUPPORTED: \"GENERATION_UNSUPPORTED\";\n readonly INCONSISTENT_READ: \"INCONSISTENT_READ\";\n readonly INDEX_RACE: \"INDEX_RACE\";\n readonly INVALID_RULE: \"INVALID_RULE\";\n readonly NO_RULES_FOR_CHAIN: \"NO_RULES_FOR_CHAIN\";\n readonly NOT_AGENTIC_WALLET: \"NOT_AGENTIC_WALLET\";\n readonly NOT_ALLOWED_IN_AGENTIC_MODE: \"NOT_ALLOWED_IN_AGENTIC_MODE\";\n readonly NOT_OWNER_OR_AGENT: \"NOT_OWNER_OR_AGENT\";\n readonly NOT_WALLET_OWNER: \"NOT_WALLET_OWNER\";\n readonly READ_ONLY: \"READ_ONLY\";\n readonly RECEIPT_MISMATCH: \"RECEIPT_MISMATCH\";\n readonly RECEIPT_UNAVAILABLE: \"RECEIPT_UNAVAILABLE\";\n readonly REVOKE_NEEDS_TARGET: \"REVOKE_NEEDS_TARGET\";\n readonly RULE_LIMIT_EXCEEDED: \"RULE_LIMIT_EXCEEDED\";\n readonly RULE_NOT_FOUND: \"RULE_NOT_FOUND\";\n readonly RULE_READ_FAILED: \"RULE_READ_FAILED\";\n readonly TARGET_NOT_ON_RULE_CHAIN: \"TARGET_NOT_ON_RULE_CHAIN\";\n readonly WALLET_BALANCE_INSUFFICIENT: \"WALLET_BALANCE_INSUFFICIENT\";\n readonly WALLET_NOT_DEPLOYED: \"WALLET_NOT_DEPLOYED\";\n}", + "members": { + "AGENT_GAS_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\"" + }, + "AGENT_IS_OWNER": { + "optional": false, + "readonly": true, + "type": "\"AGENT_IS_OWNER\"" + }, + "ASSET_CHAIN_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"ASSET_CHAIN_MISMATCH\"" + }, + "CAPABILITY_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"CAPABILITY_UNAVAILABLE\"" + }, + "CREATE_PARTIAL": { + "optional": false, + "readonly": true, + "type": "\"CREATE_PARTIAL\"" + }, + "DUPLICATE_RULE": { + "optional": false, + "readonly": true, + "type": "\"DUPLICATE_RULE\"" + }, + "FROM_NOT_ALLOWED": { + "optional": false, + "readonly": true, + "type": "\"FROM_NOT_ALLOWED\"" + }, + "GATEWAY_ALLOWANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"GATEWAY_ALLOWANCE_INSUFFICIENT\"" + }, + "GENERATION_UNSUPPORTED": { + "optional": false, + "readonly": true, + "type": "\"GENERATION_UNSUPPORTED\"" + }, + "INCONSISTENT_READ": { + "optional": false, + "readonly": true, + "type": "\"INCONSISTENT_READ\"" + }, + "INDEX_RACE": { + "optional": false, + "readonly": true, + "type": "\"INDEX_RACE\"" + }, + "INVALID_RULE": { + "optional": false, + "readonly": true, + "type": "\"INVALID_RULE\"" + }, + "NO_RULES_FOR_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"NO_RULES_FOR_CHAIN\"" + }, + "NOT_AGENTIC_WALLET": { + "optional": false, + "readonly": true, + "type": "\"NOT_AGENTIC_WALLET\"" + }, + "NOT_ALLOWED_IN_AGENTIC_MODE": { + "optional": false, + "readonly": true, + "type": "\"NOT_ALLOWED_IN_AGENTIC_MODE\"" + }, + "NOT_OWNER_OR_AGENT": { + "optional": false, + "readonly": true, + "type": "\"NOT_OWNER_OR_AGENT\"" + }, + "NOT_WALLET_OWNER": { + "optional": false, + "readonly": true, + "type": "\"NOT_WALLET_OWNER\"" + }, + "READ_ONLY": { + "optional": false, + "readonly": true, + "type": "\"READ_ONLY\"" + }, + "RECEIPT_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_MISMATCH\"" + }, + "RECEIPT_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_UNAVAILABLE\"" + }, + "REVOKE_NEEDS_TARGET": { + "optional": false, + "readonly": true, + "type": "\"REVOKE_NEEDS_TARGET\"" + }, + "RULE_LIMIT_EXCEEDED": { + "optional": false, + "readonly": true, + "type": "\"RULE_LIMIT_EXCEEDED\"" + }, + "RULE_NOT_FOUND": { + "optional": false, + "readonly": true, + "type": "\"RULE_NOT_FOUND\"" + }, + "RULE_READ_FAILED": { + "optional": false, + "readonly": true, + "type": "\"RULE_READ_FAILED\"" + }, + "TARGET_NOT_ON_RULE_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"TARGET_NOT_ON_RULE_CHAIN\"" + }, + "WALLET_BALANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"WALLET_BALANCE_INSUFFICIENT\"" + }, + "WALLET_NOT_DEPLOYED": { + "optional": false, + "readonly": true, + "type": "\"WALLET_NOT_DEPLOYED\"" + } + } + }, + "NativeRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "amount": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AmountLimit | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "maxCalls": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValuePerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxValueTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "pins": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ArgPin[] | undefined" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "AssetCap": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap", + "members": { + "maxPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/constants/tokens\").MoveableToken" + } + } + }, + "AllowedCall": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall", + "members": { + "beneficiary": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValue": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "`${string}(${string})` | `0x${string}`" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "UniversalRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall[]" + }, + "assets": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap[]" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "`eip155:${string}` | `solana:${string}`" + }, + "maxGasPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "RulesRecord": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "enabled": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "ref": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "rule": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule | import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule" + }, + "rulesId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "CreateOptions": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions", + "members": { + "progressHook": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook | undefined" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Rule[]" + } + } + }, + "CreateResult": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateResult", + "members": { + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "rulesIds": { + "optional": false, + "readonly": false, + "type": "`0x${string}`[]" + }, + "tx": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticTxMetadata": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticTxMetadata", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destinationAccount": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "destinationCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "door": { + "optional": false, + "readonly": false, + "type": "\"agent\" | \"owner\"" + }, + "nativeCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "rawData": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rawTo": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesId": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + } + }, + "publicSurface": { + "CHAIN": { + "type": "typeof import(\"sdk/src/lib/constants/enums\").CHAIN", + "members": { + "ARBITRUM_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA" + }, + "BASE_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA" + }, + "BNB_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET" + }, + "ETHEREUM_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET" + }, + "ETHEREUM_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA" + }, + "PUSH_LOCALNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET" + }, + "PUSH_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET" + }, + "PUSH_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET" + }, + "PUSH_TESTNET_DONUT": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET" + }, + "SOLANA_DEVNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET" + }, + "SOLANA_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET" + }, + "SOLANA_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET" + }, + "WEB2": { + "optional": false, + "readonly": false, + "type": "\"web2\"" + } + } + }, + "ConversionQuote": { + "type": "import(\"sdk/src/lib/constants/tokens\").ConversionQuote", + "members": { + "amountIn": { + "optional": false, + "readonly": false, + "type": "string" + }, + "amountOut": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rate": { + "optional": false, + "readonly": false, + "type": "number" + }, + "route": { + "optional": true, + "readonly": false, + "type": "string[] | undefined" + }, + "timestamp": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "UniversalSigner": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalSigner", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "signAndSendTransaction": { + "optional": false, + "readonly": false, + "type": "(unsignedTx: Uint8Array) => Promise" + }, + "signAuthorization": { + "optional": true, + "readonly": false, + "type": "((params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise) | undefined" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": true, + "readonly": false, + "type": "(({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise) | undefined" + } + } + }, + "UniversalAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "UniversalSignerSkeleton": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "signAndSendTransaction": { + "optional": false, + "readonly": false, + "type": "(unsignedTx: Uint8Array) => Promise" + }, + "signAuthorization": { + "optional": true, + "readonly": false, + "type": "((params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise) | undefined" + }, + "signerId": { + "optional": false, + "readonly": false, + "type": "string" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": true, + "readonly": false, + "type": "(({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise) | undefined" + } + } + }, + "SignAuthorizationParams": { + "type": "{\n chainId?: number;\n contractAddress: `0x${string}`;\n executor?: \"self\";\n nonce?: number;\n}", + "members": { + "chainId": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "contractAddress": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "executor": { + "optional": true, + "readonly": false, + "type": "\"self\" | undefined" + }, + "nonce": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "SignedAuthorization": { + "type": "{\n address: `0x${string}`;\n chainId: number;\n nonce: number;\n r: `0x${string}`;\n s: `0x${string}`;\n v?: bigint;\n yParity: number;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainId": { + "optional": false, + "readonly": false, + "type": "number" + }, + "nonce": { + "optional": false, + "readonly": false, + "type": "number" + }, + "r": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "s": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "v": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "yParity": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "DerivedExecutorAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").DerivedExecutorAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean | null" + } + } + }, + "ResolvedAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainName": { + "optional": false, + "readonly": false, + "type": "string" + }, + "exists": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "role": { + "optional": true, + "readonly": false, + "type": "\"controller\" | undefined" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"cea\" | \"uea\" | \"uoa\"" + } + } + }, + "ResolvedControllerAccounts": { + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedControllerAccounts", + "members": { + "accounts": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedAccount[]" + } + } + }, + "AccountType": { + "type": "\"cea\" | \"uea\" | \"uoa\"", + "members": {} + }, + "AccountRole": { + "type": "\"controller\"", + "members": {} + }, + "PC20TokenReference": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "FundsToken": { + "type": "import(\"sdk/src/lib/constants/tokens\").MoveableToken | import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20TokenReference", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "PC20RegistryEntry": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "chainName": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "PC20AddressResult": { + "type": "{\n address: `0x${string}`;\n decimals: number;\n name: string;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n registry: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20RegistryEntry[];\n symbol: string;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "decimals": { + "optional": false, + "readonly": false, + "type": "number" + }, + "name": { + "optional": false, + "readonly": false, + "type": "string" + }, + "network": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "registry": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20RegistryEntry[]" + }, + "symbol": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "isPC20Reference": { + "type": "(token: import(\"sdk/src/lib/orchestrator/orchestrator.types\").FundsToken | undefined) => token is import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20TokenReference", + "members": {} + }, + "PC20Error": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20Error", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidPC20AddressError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InvalidPC20AddressError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20TokenChainMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20TokenChainMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20WrapperNotRegisteredError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20WrapperNotRegisteredError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20RegistryMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20RegistryMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20FactoryMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20FactoryMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidPC20MetadataError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InvalidPC20MetadataError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20ExpectedButPRC20Error": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20ExpectedButPRC20Error", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20AmbiguousAddressError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20AmbiguousAddressError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "candidates": { + "optional": false, + "readonly": true, + "type": "{\n chain: string;\n pushAddress: string;\n}[]" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "UnsupportedPC20DestinationError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").UnsupportedPC20DestinationError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InsufficientPC20BalanceError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InsufficientPC20BalanceError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20UnknownChainNamespaceError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20UnknownChainNamespaceError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20WrapperPredictionUnavailableError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20WrapperPredictionUnavailableError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20ExportRevertedError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20ExportRevertedError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "lockedAmount": { + "optional": true, + "readonly": true, + "type": "bigint | undefined" + }, + "outboundTxId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "revertRecipient": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20UnsafeEmptyPayloadError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20UnsafeEmptyPayloadError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ChainTarget": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "ChainSource": { + "type": "{\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "UniversalTo": { + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget", + "members": {} + }, + "TransactionRouteType": { + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"", + "members": {} + }, + "UniversalExecuteParams": { + "type": "{\n from?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainSource;\n migration?: boolean;\n to: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTo;\n} & Omit", + "members": { + "_minimumDepositUsd": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "_requiredFundsOverride": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "_skipFeeLocking": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "_ueaStatus": { + "optional": true, + "readonly": false, + "type": "{\n balance: bigint;\n isDeployed: boolean;\n nonce: bigint;\n} | undefined" + }, + "data": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiCall[] | undefined" + }, + "deadline": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "feeLockTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "from": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainSource | undefined" + }, + "funds": { + "optional": true, + "readonly": false, + "type": "{\n amount: bigint;\n token?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").FundsToken;\n} | undefined" + }, + "gasLimit": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFeePerGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxPCForGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxPriorityFeePerGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "migration": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "nonce": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "options": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions | undefined" + }, + "payGasWith": { + "optional": true, + "readonly": false, + "type": "{\n minAmountOut?: bigint | string;\n slippageBps?: number;\n token?: import(\"sdk/src/lib/constants/tokens\").PayableToken;\n} | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "to": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget" + }, + "value": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "UniversalOutboundTxRequest": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalOutboundTxRequest", + "members": { + "amount": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gasPrice": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxPCForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "payload": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "recipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "revertRecipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "PreparedUniversalTx": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx", + "members": { + "_hop": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").HopDescriptor" + }, + "deadline": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "estimatedGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gatewayRequest": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalOutboundTxRequest | import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxRequest" + }, + "nonce": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "payload": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + } + } + }, + "CascadedTxResponse": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadedTxResponse", + "members": { + "finalTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hopCount": { + "optional": false, + "readonly": false, + "type": "number" + }, + "hops": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo[]" + }, + "initialTxHash": { + "optional": false, + "readonly": false, + "type": "string" + }, + "initialTxResponse": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions) => Promise" + }, + "waitForAll": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions) => Promise" + } + } + }, + "CascadeHopInfo": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo", + "members": { + "executionChain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "expectedSubTxId": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hopIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "outboundDetails": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").OutboundTxDetails | undefined" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + }, + "status": { + "optional": false, + "readonly": false, + "type": "\"confirmed\" | \"failed\" | \"pending\" | \"submitted\"" + }, + "txHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "CascadeTrackOptions": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions", + "members": { + "eventHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeProgressEvent) => void) | undefined" + }, + "timeout": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "CascadeProgressEvent": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeProgressEvent", + "members": { + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "elapsed": { + "optional": false, + "readonly": false, + "type": "number" + }, + "hopIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + }, + "status": { + "optional": false, + "readonly": false, + "type": "\"confirmed\" | \"failed\" | \"found\" | \"polling\" | \"timeout\" | \"waiting\"" + }, + "txHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "CascadeCompletionResult": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeCompletionResult", + "members": { + "failedAt": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "finalTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "finalTxResponse": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadedTxResponse | undefined" + }, + "hops": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo[]" + }, + "success": { + "optional": false, + "readonly": false, + "type": "boolean" + } + } + }, + "MultiChainTxResponse": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiChainTxResponse", + "members": { + "chains": { + "optional": false, + "readonly": false, + "type": "{\n blockNumber: bigint;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n hash: string;\n status: \"confirmed\" | \"failed\" | \"pending\";\n}[]" + }, + "transactions": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse[]" + } + } + }, + "OutboundTxDetails": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").OutboundTxDetails", + "members": { + "amount": { + "optional": false, + "readonly": false, + "type": "string" + }, + "assetAddr": { + "optional": false, + "readonly": false, + "type": "string" + }, + "destinationChain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "explorerUrl": { + "optional": false, + "readonly": false, + "type": "string" + }, + "externalTxHash": { + "optional": false, + "readonly": false, + "type": "string" + }, + "recipient": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "WaitForOutboundOptions": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").WaitForOutboundOptions", + "members": { + "_expectedDestinationChain": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "_outboundIndex": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "_resolvedSubTxId": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "initialWaitMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: {\n elapsed: number;\n status: \"failed\" | \"found\" | \"polling\" | \"timeout\" | \"waiting\";\n}) => void) | undefined" + }, + "timeout": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "SvmGatewayAccountMeta": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmGatewayAccountMeta", + "members": { + "isWritable": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "pubkey": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "SvmExecutePayloadFields": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmExecutePayloadFields", + "members": { + "accounts": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmGatewayAccountMeta[]" + }, + "instructionId": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "ixData": { + "optional": false, + "readonly": false, + "type": "Uint8Array" + }, + "targetProgram": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AccountStatus": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus", + "members": { + "mode": { + "optional": false, + "readonly": false, + "type": "\"read-only\" | \"signer\"" + }, + "uea": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UEAStatus" + } + } + }, + "UEAStatus": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UEAStatus", + "members": { + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "loaded": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "minRequiredVersion": { + "optional": false, + "readonly": false, + "type": "string" + }, + "requiresUpgrade": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "version": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "RescueFundsParams": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").RescueFundsParams", + "members": { + "prc20": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "universalTxId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "parseUEAVersion": { + "type": "(version: string) => number", + "members": {} + }, + "TransactionRoute": { + "type": "typeof import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute", + "members": { + "CEA_TO_CEA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.CEA_TO_CEA" + }, + "CEA_TO_PUSH": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.CEA_TO_PUSH" + }, + "UOA_TO_CEA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.UOA_TO_CEA" + }, + "UOA_TO_PUSH": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.UOA_TO_PUSH" + } + } + }, + "detectRoute": { + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams) => import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute", + "members": {} + }, + "isChainTarget": { + "type": "(to: unknown) => to is import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget", + "members": {} + }, + "DEFAULT_MAX_PC_FOR_GAS_BUFFER_BPS": { + "type": "1000", + "members": {} + }, + "MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT": { + "type": "10000", + "members": {} + }, + "quoteMaxPCForGasCap": { + "type": "(input: import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapInput) => import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": {} + }, + "quoteMaxPCForGasCapFromNativeValue": { + "type": "(input: import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapFromNativeValueInput) => import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": {} + }, + "MaxPCForGasCapInput": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapInput", + "members": { + "bufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "gasLegNativePc": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "MaxPCForGasCapFromNativeValueInput": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapFromNativeValueInput", + "members": { + "bufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "nativeValueForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "MaxPCForGasCapQuote": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": { + "bufferBps": { + "optional": false, + "readonly": false, + "type": "number" + }, + "gasLegNativePc": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxPCForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "nativeValueForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "getCEAAddress": { + "type": "(ueaAddress: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise", + "members": {} + }, + "getPushAccountForCEA": { + "type": "(ceaAddress: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise<`0x${string}`>", + "members": {} + }, + "isCEA": { + "type": "(address: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise", + "members": {} + }, + "chainSupportsCEA": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "chainSupportsOutbound": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "getCEAFactoryAddress": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => `0x${string}` | undefined", + "members": {} + }, + "getAllCEAAddresses": { + "type": "(ueaAddress: `0x${string}`, rpcUrls?: Partial>) => Promise", + "members": {} + }, + "encodeSvmExecutePayload": { + "type": "(fields: import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmExecutePayloadFields) => `0x${string}`", + "members": {} + }, + "isSvmChain": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "isValidSolanaHexAddress": { + "type": "(address: string) => boolean", + "members": {} + }, + "buildMigrationPayload": { + "type": "() => `0x${string}`", + "members": {} + }, + "buildErc20WithdrawalMulticall": { + "type": "(tokenAddress: `0x${string}`, recipientAddress: `0x${string}`, amount: bigint) => import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiCall[]", + "members": {} + }, + "ReadChain": { + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain", + "members": {} + }, + "ReadDestination": { + "type": "{\n chain: import(\"sdk/src/lib/read-state/read-state.types\").ReadChain;\n} | {\n chainId: string;\n chainNamespace: string;\n}", + "members": {} + }, + "ResolvedDestination": { + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}", + "members": { + "caip2": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainId": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "namespace": { + "optional": false, + "readonly": false, + "type": "\"eip155\" | \"solana\" | \"web2\"" + } + } + }, + "ReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").SvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery", + "members": { + "type": { + "optional": false, + "readonly": false, + "type": "\"accountBalance\" | \"contractCall\" | \"http\" | \"lamportBalance\" | \"rawAccountData\" | \"splTokenAccount\" | \"storageSlot\"" + } + } + }, + "EvmReadQuery": { + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n target: `0x${string}`;\n type: \"contractCall\";\n} | {\n callData: `0x${string}`;\n target: `0x${string}`;\n type: \"contractCall\";\n} | {\n slot: `0x${string}` | bigint;\n target: `0x${string}`;\n type: \"storageSlot\";\n} | {\n target: `0x${string}`;\n type: \"accountBalance\";\n}", + "members": { + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"accountBalance\" | \"contractCall\" | \"storageSlot\"" + } + } + }, + "SvmReadQuery": { + "type": "{\n account: string | Uint8Array;\n accountName?: string;\n idl?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n type: \"rawAccountData\";\n} | {\n account: string | Uint8Array;\n type: \"lamportBalance\";\n} | {\n account: string | Uint8Array;\n type: \"splTokenAccount\";\n}", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "string | Uint8Array" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"lamportBalance\" | \"rawAccountData\" | \"splTokenAccount\"" + } + } + }, + "Web2ReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery", + "members": { + "body": { + "optional": true, + "readonly": false, + "type": "string | Uint8Array | undefined" + }, + "extract": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[]" + }, + "headers": { + "optional": true, + "readonly": false, + "type": "Record | undefined" + }, + "method": { + "optional": true, + "readonly": false, + "type": "\"GET\" | \"POST\" | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"http\"" + }, + "url": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "Web2Extract": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract", + "members": { + "decimals": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "path": { + "optional": false, + "readonly": false, + "type": "string" + }, + "valueType": { + "optional": false, + "readonly": false, + "type": "\"bool\" | \"bytes\" | \"int256\" | \"string\" | \"uint256\"" + } + } + }, + "Web2ValueType": { + "type": "\"bool\" | \"bytes\" | \"int256\" | \"string\" | \"uint256\"", + "members": {} + }, + "EncodedReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery", + "members": { + "blockRef": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "encoded": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "namespace": { + "optional": false, + "readonly": false, + "type": "\"eip155\" | \"solana\" | \"web2\"" + }, + "ownerBytes": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "queryType": { + "optional": false, + "readonly": false, + "type": "number" + }, + "resultShape": { + "optional": false, + "readonly": false, + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}" + }, + "warnings": { + "optional": false, + "readonly": false, + "type": "string[]" + } + } + }, + "ReadResultShape": { + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"bytes32\" | \"evmCall\" | \"raw\" | \"svmAccount\" | \"uint256\" | \"web2\"" + } + } + }, + "DecodedReadResult": { + "type": "{\n accountName: string;\n kind: \"svmAccount\";\n value: unknown;\n} | {\n kind: \"bytes32\";\n value: `0x${string}`;\n} | {\n kind: \"evmCall\";\n value: unknown;\n} | {\n kind: \"raw\";\n value: `0x${string}`;\n} | {\n kind: \"uint256\";\n value: bigint;\n} | {\n kind: \"web2\";\n values: readonly unknown[];\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"bytes32\" | \"evmCall\" | \"raw\" | \"svmAccount\" | \"uint256\" | \"web2\"" + } + } + }, + "ReadPreflight": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight", + "members": { + "destination": { + "optional": false, + "readonly": false, + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}" + }, + "fetchedAt": { + "optional": false, + "readonly": false, + "type": "number" + }, + "observedChainHeight": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pushBlockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pushGasPrice": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "universalCallback": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "universalCore": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ReadSpec": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "{\n chainId: string;\n chainNamespace: string;\n owner: `0x${string}`;\n}" + }, + "blockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "expiryPushChainHeight": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "minConfirmations": { + "optional": false, + "readonly": false, + "type": "number" + }, + "query": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "revertRecipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ReadSpecTuple": { + "type": "readonly [\n readonly [\n string,\n string,\n `0x${string}`\n ],\n `0x${string}`,\n number,\n bigint,\n bigint,\n bigint,\n `0x${string}`\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "readonly [\n string,\n string,\n `0x${string}`\n]" + }, + "1": { + "optional": false, + "readonly": true, + "type": "`0x${string}`" + }, + "2": { + "optional": false, + "readonly": true, + "type": "number" + }, + "3": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "4": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "5": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "6": { + "optional": false, + "readonly": true, + "type": "`0x${string}`" + }, + "length": { + "optional": false, + "readonly": true, + "type": "7" + } + } + }, + "BuildReadSpecParams": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").BuildReadSpecParams", + "members": { + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "budgetBuffer": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback | undefined" + }, + "callbackBudget": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "destination": { + "optional": false, + "readonly": false, + "type": "{\n chain: import(\"sdk/src/lib/read-state/read-state.types\").ReadChain;\n} | {\n chainId: string;\n chainNamespace: string;\n}" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "expiryPushChainHeight": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFeeBufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "owner": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "query": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").SvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "PreparedRead": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead", + "members": { + "__@preparedReadValue": { + "optional": true, + "readonly": true, + "type": "T | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback | undefined" + }, + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "encodedQuery": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery" + }, + "encodedSpec": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "fees": { + "optional": false, + "readonly": false, + "type": "{\n callbackBudget: bigint;\n protocolFee: bigint;\n total: bigint;\n}" + }, + "preflight": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "queryKey": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "resultShape": { + "optional": false, + "readonly": false, + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}" + }, + "spec": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec" + }, + "specTuple": { + "optional": false, + "readonly": false, + "type": "readonly [\n readonly [\n string,\n string,\n `0x${string}`\n ],\n `0x${string}`,\n number,\n bigint,\n bigint,\n bigint,\n `0x${string}`\n]" + }, + "value": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "warnings": { + "optional": false, + "readonly": false, + "type": "string[]" + } + } + }, + "ReadCallback": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "((spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpecTuple, callbackGasLimit: bigint) => readonly unknown[]) | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "gasLimit": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "target": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "SimulateReadResult": { + "type": "{\n args?: readonly unknown[];\n error: string;\n errorName?: string;\n ok: false;\n} | {\n ok: true;\n}", + "members": { + "ok": { + "optional": false, + "readonly": false, + "type": "boolean" + } + } + }, + "ParsedReadRequest": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ParsedReadRequest", + "members": { + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackTarget": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "logIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "originalFunder": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "requestId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "requestIdUint": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "spec": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec" + }, + "totalPaid": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "FulfilOutcome": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").FulfilOutcome", + "members": { + "burned": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "delivered": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "expired": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "failReason": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "gasReported": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refunded": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refundFailed": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "ReceiptLike": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike", + "members": { + "logs": { + "optional": false, + "readonly": false, + "type": "readonly {\n address: string;\n data: string;\n logIndex?: number | string;\n topics: readonly string[];\n}[]" + } + } + }, + "ReadRef": { + "type": "{\n requestId: `0x${string}` | bigint;\n} | {\n txHash: `0x${string}`;\n}", + "members": {} + }, + "ReadLifecycleOptions": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadLifecycleOptions", + "members": { + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "resultShape": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadFees": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadFees", + "members": { + "burned": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "paid": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "refunded": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refundFailed": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + } + } + }, + "UniversalReadResponse": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse", + "members": { + "callbackDelivered": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "callbackFailReason": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "decoded": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").DecodedReadResult | undefined" + }, + "decodeError": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destination": { + "optional": false, + "readonly": false, + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}" + }, + "errorMsg": { + "optional": false, + "readonly": false, + "type": "string" + }, + "explorerUrl": { + "optional": false, + "readonly": false, + "type": "string" + }, + "fees": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadFees" + }, + "isTerminal": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "outcome": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME" + }, + "pcTx": { + "optional": false, + "readonly": false, + "type": "readonly {\n blockHeight: number;\n errorMsg: string;\n status: string;\n txHash: `0x${string}`;\n}[]" + }, + "raw": { + "optional": false, + "readonly": false, + "type": "{\n errorCode: import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n resultData: `0x${string}`;\n status: import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n} | null" + }, + "refresh": { + "optional": false, + "readonly": false, + "type": "() => Promise>" + }, + "request": { + "optional": false, + "readonly": false, + "type": "{\n callbackGasLimit: bigint;\n callbackTarget: `0x${string}`;\n createdAtHeight: bigint;\n logIndex: number;\n originalFunder: `0x${string}`;\n refundTo: `0x${string}`;\n spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec;\n}" + }, + "requestId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "requestIdUint": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "status": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "value": { + "optional": true, + "readonly": false, + "type": "T | undefined" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/read-state/read-state.types\").ReadLifecycleOptions) => Promise>" + } + } + }, + "ReadResponseTuple": { + "type": "{\n -readonly [K in keyof R]: import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse ? T : unknown>;\n}", + "members": {} + }, + "BatchReadResponse": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").BatchReadResponse", + "members": { + "atomic": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "count": { + "optional": false, + "readonly": false, + "type": "number" + }, + "reads": { + "optional": false, + "readonly": false, + "type": "{\n -readonly [K in keyof R]: import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse ? T : unknown>;\n}" + }, + "transactionHashes": { + "optional": true, + "readonly": false, + "type": "readonly `0x${string}`[] | undefined" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: Omit) => Promise>" + } + } + }, + "ReadOptions": { + "type": "((import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">)) & {\n callback?: (Pick & Required>) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n };\n}", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "advanced": { + "optional": true, + "readonly": false, + "type": "{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n} | undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "({\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} & {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n}) | ({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick & Pick & Required>) | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadPrepareOptions": { + "type": "((((({\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\">) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n}) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">)) & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n}) | ((({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n}) | ({\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\">)) & {\n blockNumber?: never;\n minConfirmations?: never;\n})) & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n}) & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "advanced": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadQueryOptions": { + "type": "({\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\">) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n}) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n}) | ({\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\">)", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadCallbackOptions": { + "type": "{\n callback?: ({\n gasLimit?: bigint;\n target: `0x${string}`;\n } & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n };\n}", + "members": { + "callback": { + "optional": true, + "readonly": false, + "type": "({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} | undefined" + } + } + }, + "ReadValue": { + "type": "O extends {\n abi: infer A extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: infer F extends string;\n} ? number extends A[\"length\"] ? unknown : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, O extends {\n args: infer Args extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n} ? Args : readonly [\n] extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> ? import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> & readonly [\n] : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>> extends infer Selected ? Selected extends {\n outputs: readonly unknown[];\n type: \"function\";\n} & import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiFunction ? {\n [key in keyof {\n [key in keyof import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"]]: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterToPrimitiveType, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"][key], import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterKind>;\n }]: {\n [key in keyof import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"]]: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterToPrimitiveType, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"][key], import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterKind>;\n }[key];\n} extends infer types ? types extends readonly [\n] ? void : types extends readonly [\n infer type\n] ? type : types : never : never : never : O extends {\n web2: {\n extract: infer E extends readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n };\n} ? {\n readonly [K in keyof E]: {\n bool: boolean;\n bytes: `0x${string}`;\n int256: bigint;\n string: string;\n uint256: bigint;\n }[E[K][\"valueType\"]];\n} : O extends {\n storageSlot: unknown;\n} ? `0x${string}` : O extends {\n idl: infer I extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} ? string extends Extract, string> ? unknown : (O extends {\n functionName: infer N extends string;\n} ? N : undefined) extends string ? import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/index\").IdlAccounts[{\n [K in Extract, string>]: Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : K> extends Lowercase<(O extends {\n functionName: infer N extends string;\n } ? N : undefined) & string extends `${infer H}_${infer T}` ? `${H}${Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : (O extends {\n functionName: infer N extends string;\n } ? N : undefined) & string> ? K : never;\n}[Extract, string>]] : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/index\").IdlAccounts[Extract, string>] : bigint", + "members": {} + }, + "ValidateReadCall": { + "type": "O extends {\n abi: infer A extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: infer F extends string;\n} ? (readonly [\n] extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> ? {\n args?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n} : {\n args: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n}) & {\n functionName: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionName;\n} : O extends {\n functionName: infer N extends string;\n idl: infer I extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} ? string extends Extract, string> ? unknown : [\n {\n [K in Extract, string>]: Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : K> extends Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : N> ? K : never;\n }[Extract, string>]\n] extends [\n never\n] ? {\n functionName: Extract, string>;\n} : unknown : unknown", + "members": {} + }, + "ReadWeb2Options": { + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options", + "members": { + "body": { + "optional": true, + "readonly": false, + "type": "string | Uint8Array | undefined" + }, + "extract": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[]" + }, + "headers": { + "optional": true, + "readonly": false, + "type": "Record | undefined" + }, + "method": { + "optional": true, + "readonly": false, + "type": "\"GET\" | \"POST\" | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadTrackOptions": { + "type": "{\n advanced?: Omit, \"enforceGasCheck\">;\n resultShape?: import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape;\n}", + "members": { + "advanced": { + "optional": true, + "readonly": false, + "type": "Omit<{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n}, \"enforceGasCheck\"> | undefined" + }, + "resultShape": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape | undefined" + } + } + }, + "ReadExecuteOptions": { + "type": "{\n advanced?: {\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n } | undefined;\n progressHook?: ((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined;\n waitForCompletion?: boolean | undefined;\n}", + "members": { + "advanced": { + "optional": true, + "readonly": false, + "type": "{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n} | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + } + } + }, + "UNIVERSAL_READ_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS", + "members": { + "ABORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.ABORTED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.EXPIRED" + }, + "FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.FAILED" + }, + "FULFILLED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.FULFILLED" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.PENDING" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.UNSPECIFIED" + }, + "VOTING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.VOTING" + } + } + }, + "READ_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS", + "members": { + "ERROR": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.ERROR" + }, + "SUCCESS": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.SUCCESS" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.UNSPECIFIED" + } + } + }, + "READ_ERROR_CODE": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE", + "members": { + "INVALID_QUERY": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.INVALID_QUERY" + }, + "INVALID_RESULT": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.INVALID_RESULT" + }, + "NOT_FOUND": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.NOT_FOUND" + }, + "REJECTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.REJECTED" + }, + "REVERTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.REVERTED" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.UNSPECIFIED" + }, + "UNSUPPORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.UNSUPPORTED" + } + } + }, + "READ_OUTCOME": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME", + "members": { + "ABORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.ABORTED" + }, + "CALLBACK_FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.CALLBACK_FAILED" + }, + "DECODE_FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.DECODE_FAILED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.EXPIRED" + }, + "FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.FAILED" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.PENDING" + }, + "SOURCE_ERROR": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.SOURCE_ERROR" + }, + "SUCCESS": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.SUCCESS" + }, + "UNKNOWN": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.UNKNOWN" + } + } + }, + "CONTRACT_REQUEST_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS", + "members": { + "EXECUTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.EXECUTED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.EXPIRED" + }, + "NONE": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.NONE" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.PENDING" + }, + "SETTLED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.SETTLED" + } + } + }, + "TERMINAL_READ_STATUSES": { + "type": "ReadonlySet", + "members": {} + }, + "ReadStateError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadStateError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidReadQueryError": { + "type": "import(\"sdk/src/lib/read-state/errors\").InvalidReadQueryError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidReadSpecError": { + "type": "import(\"sdk/src/lib/read-state/errors\").InvalidReadSpecError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "violations": { + "optional": false, + "readonly": true, + "type": "readonly import(\"sdk/src/lib/read-state/errors\").ReadSpecViolation[]" + } + } + }, + "ReadHeightUnavailableError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadHeightUnavailableError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "UnsupportedReadDestinationError": { + "type": "import(\"sdk/src/lib/read-state/errors\").UnsupportedReadDestinationError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadDecodeError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadDecodeError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadTimeoutError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadTimeoutError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "lastStatus": { + "optional": false, + "readonly": true, + "type": "number" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadNotFoundError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadNotFoundError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadRegistryUnavailableError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadRegistryUnavailableError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadSpecViolation": { + "type": "\"CALLBACK_GAS_LIMIT_EXCEEDED\" | \"DOMAIN_BLOCKED\" | \"EMPTY_QUERY\" | \"EXCESSIVE_FEE\" | \"INSUFFICIENT_CALLBACK_BUDGET\" | \"INSUFFICIENT_FEE\" | \"INVALID_ACCOUNT_ID\" | \"INVALID_BLOCK_NUMBER\" | \"INVALID_EXPIRY_HEIGHT\" | \"INVALID_MIN_CONFIRMATIONS\" | \"SVM_OWNER_NOT_32_BYTES\" | \"ZERO_CALLBACK_BUDGET\" | \"ZERO_CALLBACK_GAS_LIMIT\" | \"ZERO_REVERT_RECIPIENT\"", + "members": {} + }, + "resolveDestination": { + "type": "(dest: import(\"sdk/src/lib/read-state/read-state.types\").ReadDestination) => import(\"sdk/src/lib/read-state/read-state.types\").ResolvedDestination", + "members": {} + }, + "encodeReadQuery": { + "type": "(destination: import(\"sdk/src/lib/read-state/read-state.types\").ReadDestination, query: import(\"sdk/src/lib/read-state/read-state.types\").ReadQuery, options?: {\n blockNumber?: bigint;\n minSlot?: bigint;\n}) => import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery", + "members": {} + }, + "decodeReadResult": { + "type": "(resultData: `0x${string}`, shape: import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape) => import(\"sdk/src/lib/read-state/read-state.types\").DecodedReadResult", + "members": {} + }, + "parseReadRequestsFromReceipt": { + "type": "(receipt: import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike, universalCallback: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").ParsedReadRequest[]", + "members": {} + }, + "parseFulfilOutcome": { + "type": "(receipt: import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike, universalCallback: `0x${string}`, requestId: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").FulfilOutcome", + "members": {} + }, + "buildReadSpecFromPreflight": { + "type": "(preflight: import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight, params: import(\"sdk/src/lib/read-state/read-state.types\").BuildReadSpecParams, defaults?: {\n refundTo?: `0x${string}`;\n}) => import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead", + "members": {} + }, + "validateReadSpec": { + "type": "(input: import(\"sdk/src/lib/read-state/validate\").ValidateReadSpecInput) => {\n ok: false;\n violations: import(\"sdk/src/lib/read-state/errors\").ReadSpecViolation[];\n} | {\n ok: true;\n}", + "members": {} + }, + "toCallData": { + "type": "(prepared: import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead, target: {\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: (spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpecTuple, callbackGasLimit: bigint) => readonly unknown[];\n functionName: string;\n}) => {\n data: `0x${string}`;\n value: bigint;\n}", + "members": {} + }, + "sizeCallbackBudget": { + "type": "(callbackGasLimit: bigint, pushGasPrice: bigint, buffer?: number) => bigint", + "members": {} + }, + "inferResultShape": { + "type": "(namespace: string, query: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape", + "members": {} + }, + "toRequestIdHex": { + "type": "(id: `0x${string}` | bigint) => `0x${string}`", + "members": {} + }, + "toReadQuery": { + "type": "(subject: string, o: ReadOptionsInput, resolvedTokenProgram?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@solana/web3.js/lib/index\").PublicKey) => import(\"sdk/src/lib/read-state/read-state.types\").ReadQuery", + "members": {} + }, + "UNIVERSAL_CALLBACK_EVM": { + "type": "readonly [\n {\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"requestExternalReadSelf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"estimateFee\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"statusOf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"enum RequestStatus\";\n readonly name: \"\";\n readonly type: \"uint8\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"isFulfilled\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getPendingRead\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly internalType: \"struct PendingRead\";\n readonly name: \"\";\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"totalEscrowed\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"blockedDomains\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly indexed: false;\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"readSpec\";\n readonly type: \"tuple\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"totalPaid\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"protocolFee\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ReadRequested\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"ReadFulfilled\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"reason\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"CallbackFailed\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"gasReported\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"burned\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"CallbackGasReported\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundSent\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundFailed\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RequestExpired\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"vaultPC\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ProtocolFeeDistributed\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidAccountId\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"EmptyQuery\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidMinConfirmations\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"DomainBlocked\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidBlockNumber\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidExpiryHeight\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroRevertRecipient\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroCallbackGasLimit\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint64\";\n readonly name: \"provided\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"max\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"CallbackGasLimitExceeded\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"required\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"InsufficientFee\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ExcessiveFee\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"actual\";\n readonly type: \"uint8\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"expected\";\n readonly type: \"uint8\";\n }\n ];\n readonly name: \"InvalidRequestStatus\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ContractIsPaused\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"CallerIsNotUCallbackModule\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n }\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"requestExternalReadSelf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n}" + }, + "1": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"estimateFee\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "2": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"statusOf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"enum RequestStatus\";\n readonly name: \"\";\n readonly type: \"uint8\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "3": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"isFulfilled\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "4": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getPendingRead\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly internalType: \"struct PendingRead\";\n readonly name: \"\";\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "5": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"totalEscrowed\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "6": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"blockedDomains\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "7": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly indexed: false;\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"readSpec\";\n readonly type: \"tuple\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"totalPaid\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"protocolFee\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ReadRequested\";\n readonly type: \"event\";\n}" + }, + "8": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"ReadFulfilled\";\n readonly type: \"event\";\n}" + }, + "9": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"reason\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"CallbackFailed\";\n readonly type: \"event\";\n}" + }, + "10": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"gasReported\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"burned\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"CallbackGasReported\";\n readonly type: \"event\";\n}" + }, + "11": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundSent\";\n readonly type: \"event\";\n}" + }, + "12": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundFailed\";\n readonly type: \"event\";\n}" + }, + "13": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RequestExpired\";\n readonly type: \"event\";\n}" + }, + "14": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"vaultPC\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ProtocolFeeDistributed\";\n readonly type: \"event\";\n}" + }, + "15": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidAccountId\";\n readonly type: \"error\";\n}" + }, + "16": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"EmptyQuery\";\n readonly type: \"error\";\n}" + }, + "17": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidMinConfirmations\";\n readonly type: \"error\";\n}" + }, + "18": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"DomainBlocked\";\n readonly type: \"error\";\n}" + }, + "19": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidBlockNumber\";\n readonly type: \"error\";\n}" + }, + "20": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidExpiryHeight\";\n readonly type: \"error\";\n}" + }, + "21": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroRevertRecipient\";\n readonly type: \"error\";\n}" + }, + "22": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroCallbackGasLimit\";\n readonly type: \"error\";\n}" + }, + "23": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint64\";\n readonly name: \"provided\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"max\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"CallbackGasLimitExceeded\";\n readonly type: \"error\";\n}" + }, + "24": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"required\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"InsufficientFee\";\n readonly type: \"error\";\n}" + }, + "25": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ExcessiveFee\";\n readonly type: \"error\";\n}" + }, + "26": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"actual\";\n readonly type: \"uint8\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"expected\";\n readonly type: \"uint8\";\n }\n ];\n readonly name: \"InvalidRequestStatus\";\n readonly type: \"error\";\n}" + }, + "27": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ContractIsPaused\";\n readonly type: \"error\";\n}" + }, + "28": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"CallerIsNotUCallbackModule\";\n readonly type: \"error\";\n}" + }, + "29": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n}" + }, + "length": { + "optional": false, + "readonly": true, + "type": "30" + } + } + }, + "UNIVERSAL_READ_REGISTRY_EVM": { + "type": "readonly [\n {\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n },\n {\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"read\";\n readonly outputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"universalCallback_\";\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"constructor\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"initialize\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getLocalContext\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"hasResult\";\n readonly outputs: readonly [\n {\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"onUniversalData\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"queryKeyOf\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes32\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"readerOf\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"requestOrderOf\";\n readonly outputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"universalCallback\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"resultByRequestId\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"latestResult\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"version\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"Initialized\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadRequested\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadStored\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidInitialization\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"NotInitializing\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroAddressInit\";\n readonly type: \"error\";\n }\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n },\n {\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"read\";\n readonly outputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n}" + }, + "1": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"universalCallback_\";\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"constructor\";\n}" + }, + "2": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"initialize\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n}" + }, + "3": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getLocalContext\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "4": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"hasResult\";\n readonly outputs: readonly [\n {\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "5": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"onUniversalData\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n}" + }, + "6": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"queryKeyOf\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes32\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "7": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"readerOf\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "8": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"requestOrderOf\";\n readonly outputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "9": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"universalCallback\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "10": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"resultByRequestId\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "11": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"latestResult\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "12": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"version\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"Initialized\";\n readonly type: \"event\";\n}" + }, + "13": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadRequested\";\n readonly type: \"event\";\n}" + }, + "14": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadStored\";\n readonly type: \"event\";\n}" + }, + "15": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidInitialization\";\n readonly type: \"error\";\n}" + }, + "16": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"NotInitializing\";\n readonly type: \"error\";\n}" + }, + "17": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n}" + }, + "18": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroAddressInit\";\n readonly type: \"error\";\n}" + }, + "length": { + "optional": false, + "readonly": true, + "type": "19" + } + } + }, + "PushChainExecutionError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").PushChainExecutionError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PushChainBatchExecutionError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").PushChainBatchExecutionError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": false, + "readonly": true, + "type": "`0x${string}`[]" + } + } + }, + "DecodedErrorPayload": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload", + "members": { + "decoded": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "name": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "selector": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "PushChainInitializeOptions": { + "type": "import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions", + "members": { + "agenticWallet": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "blockExplorers": { + "optional": true, + "readonly": false, + "type": "Partial> | undefined" + }, + "network": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "printTraces": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "rpcUrls": { + "optional": true, + "readonly": false, + "type": "Partial> | undefined" + } + } + }, + "AGENTIC_ERROR_CODE": { + "type": "{\n readonly AGENT_GAS_INSUFFICIENT: \"AGENT_GAS_INSUFFICIENT\";\n readonly AGENT_IS_OWNER: \"AGENT_IS_OWNER\";\n readonly ASSET_CHAIN_MISMATCH: \"ASSET_CHAIN_MISMATCH\";\n readonly CAPABILITY_UNAVAILABLE: \"CAPABILITY_UNAVAILABLE\";\n readonly CREATE_PARTIAL: \"CREATE_PARTIAL\";\n readonly DUPLICATE_RULE: \"DUPLICATE_RULE\";\n readonly FROM_NOT_ALLOWED: \"FROM_NOT_ALLOWED\";\n readonly GATEWAY_ALLOWANCE_INSUFFICIENT: \"GATEWAY_ALLOWANCE_INSUFFICIENT\";\n readonly GENERATION_UNSUPPORTED: \"GENERATION_UNSUPPORTED\";\n readonly INCONSISTENT_READ: \"INCONSISTENT_READ\";\n readonly INDEX_RACE: \"INDEX_RACE\";\n readonly INVALID_RULE: \"INVALID_RULE\";\n readonly NO_RULES_FOR_CHAIN: \"NO_RULES_FOR_CHAIN\";\n readonly NOT_AGENTIC_WALLET: \"NOT_AGENTIC_WALLET\";\n readonly NOT_ALLOWED_IN_AGENTIC_MODE: \"NOT_ALLOWED_IN_AGENTIC_MODE\";\n readonly NOT_OWNER_OR_AGENT: \"NOT_OWNER_OR_AGENT\";\n readonly NOT_WALLET_OWNER: \"NOT_WALLET_OWNER\";\n readonly READ_ONLY: \"READ_ONLY\";\n readonly RECEIPT_MISMATCH: \"RECEIPT_MISMATCH\";\n readonly RECEIPT_UNAVAILABLE: \"RECEIPT_UNAVAILABLE\";\n readonly REVOKE_NEEDS_TARGET: \"REVOKE_NEEDS_TARGET\";\n readonly RULE_LIMIT_EXCEEDED: \"RULE_LIMIT_EXCEEDED\";\n readonly RULE_NOT_FOUND: \"RULE_NOT_FOUND\";\n readonly RULE_READ_FAILED: \"RULE_READ_FAILED\";\n readonly TARGET_NOT_ON_RULE_CHAIN: \"TARGET_NOT_ON_RULE_CHAIN\";\n readonly WALLET_BALANCE_INSUFFICIENT: \"WALLET_BALANCE_INSUFFICIENT\";\n readonly WALLET_NOT_DEPLOYED: \"WALLET_NOT_DEPLOYED\";\n}", + "members": { + "AGENT_GAS_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\"" + }, + "AGENT_IS_OWNER": { + "optional": false, + "readonly": true, + "type": "\"AGENT_IS_OWNER\"" + }, + "ASSET_CHAIN_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"ASSET_CHAIN_MISMATCH\"" + }, + "CAPABILITY_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"CAPABILITY_UNAVAILABLE\"" + }, + "CREATE_PARTIAL": { + "optional": false, + "readonly": true, + "type": "\"CREATE_PARTIAL\"" + }, + "DUPLICATE_RULE": { + "optional": false, + "readonly": true, + "type": "\"DUPLICATE_RULE\"" + }, + "FROM_NOT_ALLOWED": { + "optional": false, + "readonly": true, + "type": "\"FROM_NOT_ALLOWED\"" + }, + "GATEWAY_ALLOWANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"GATEWAY_ALLOWANCE_INSUFFICIENT\"" + }, + "GENERATION_UNSUPPORTED": { + "optional": false, + "readonly": true, + "type": "\"GENERATION_UNSUPPORTED\"" + }, + "INCONSISTENT_READ": { + "optional": false, + "readonly": true, + "type": "\"INCONSISTENT_READ\"" + }, + "INDEX_RACE": { + "optional": false, + "readonly": true, + "type": "\"INDEX_RACE\"" + }, + "INVALID_RULE": { + "optional": false, + "readonly": true, + "type": "\"INVALID_RULE\"" + }, + "NO_RULES_FOR_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"NO_RULES_FOR_CHAIN\"" + }, + "NOT_AGENTIC_WALLET": { + "optional": false, + "readonly": true, + "type": "\"NOT_AGENTIC_WALLET\"" + }, + "NOT_ALLOWED_IN_AGENTIC_MODE": { + "optional": false, + "readonly": true, + "type": "\"NOT_ALLOWED_IN_AGENTIC_MODE\"" + }, + "NOT_OWNER_OR_AGENT": { + "optional": false, + "readonly": true, + "type": "\"NOT_OWNER_OR_AGENT\"" + }, + "NOT_WALLET_OWNER": { + "optional": false, + "readonly": true, + "type": "\"NOT_WALLET_OWNER\"" + }, + "READ_ONLY": { + "optional": false, + "readonly": true, + "type": "\"READ_ONLY\"" + }, + "RECEIPT_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_MISMATCH\"" + }, + "RECEIPT_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_UNAVAILABLE\"" + }, + "REVOKE_NEEDS_TARGET": { + "optional": false, + "readonly": true, + "type": "\"REVOKE_NEEDS_TARGET\"" + }, + "RULE_LIMIT_EXCEEDED": { + "optional": false, + "readonly": true, + "type": "\"RULE_LIMIT_EXCEEDED\"" + }, + "RULE_NOT_FOUND": { + "optional": false, + "readonly": true, + "type": "\"RULE_NOT_FOUND\"" + }, + "RULE_READ_FAILED": { + "optional": false, + "readonly": true, + "type": "\"RULE_READ_FAILED\"" + }, + "TARGET_NOT_ON_RULE_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"TARGET_NOT_ON_RULE_CHAIN\"" + }, + "WALLET_BALANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"WALLET_BALANCE_INSUFFICIENT\"" + }, + "WALLET_NOT_DEPLOYED": { + "optional": false, + "readonly": true, + "type": "\"WALLET_NOT_DEPLOYED\"" + } + } + }, + "AgenticError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"CREATE_PARTIAL\" | \"DUPLICATE_RULE\" | \"FROM_NOT_ALLOWED\" | \"GATEWAY_ALLOWANCE_INSUFFICIENT\" | \"GENERATION_UNSUPPORTED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"REVOKE_NEEDS_TARGET\" | \"RULE_LIMIT_EXCEEDED\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"" + }, + "details": { + "optional": true, + "readonly": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "AgenticRevertError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticRevertError", + "members": { + "agenticCode": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + } + } + }, + "AgenticAddress": { + "type": "`0x${string}`", + "members": {} + }, + "AgenticDoor": { + "type": "\"agent\" | \"owner\"", + "members": {} + }, + "AgenticErrorCode": { + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"CREATE_PARTIAL\" | \"DUPLICATE_RULE\" | \"FROM_NOT_ALLOWED\" | \"GATEWAY_ALLOWANCE_INSUFFICIENT\" | \"GENERATION_UNSUPPORTED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"REVOKE_NEEDS_TARGET\" | \"RULE_LIMIT_EXCEEDED\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"", + "members": {} + }, + "AgenticHex": { + "type": "`0x${string}`", + "members": {} + }, + "AgenticNamespace": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace", + "members": { + "create": { + "optional": false, + "readonly": false, + "type": "(label: string, options: import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions) => Promise" + }, + "derive": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n index?: number;\n}) => Promise<{\n address: `0x${string}`;\n deployed: boolean;\n index: number;\n}>" + }, + "list": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n wallets: import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary[];\n}>" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "(address: `0x${string}`) => import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet" + } + } + }, + "AgenticNetworkConstants": { + "type": "import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants", + "members": { + "ENVELOPE_VERSION": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "FACTORY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "MAX_ALLOWED_CALLS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "MAX_PINS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "RULES_POLICY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticProgressHook": { + "type": "(event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void", + "members": {} + }, + "AgenticTxMetadata": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticTxMetadata", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destinationAccount": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "destinationCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "door": { + "optional": false, + "readonly": false, + "type": "\"agent\" | \"owner\"" + }, + "nativeCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "rawData": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rawTo": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesId": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticWallet": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "checkpoints": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n sinceBlock?: bigint;\n}) => Promise<{\n checkpoints: import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint[];\n}>" + }, + "info": { + "optional": false, + "readonly": false, + "type": "() => Promise" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n owner: `0x${string}`;\n}>" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "{\n add(rules: import(\"sdk/src/lib/agentic/agentic.types\").Rule[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise<{\n rulesIds: `0x${string}`[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n get(rulesId: `0x${string}`): Promise;\n list(): Promise<{\n rules: import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord[];\n }>;\n revoke(rulesIds: `0x${string}`[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n revoke(params: {\n all: true;\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n update(params: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n rules: {\n rule: import(\"sdk/src/lib/agentic/agentic.types\").Rule;\n rulesId: `0x${string}`;\n }[];\n }): Promise<{\n rules: {\n replaced: `0x${string}`;\n rulesId: `0x${string}`;\n }[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n}" + }, + "setLabel": { + "optional": false, + "readonly": false, + "type": "(label: string, opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n}) => Promise" + } + } + }, + "AllowedCall": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall", + "members": { + "beneficiary": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValue": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "`${string}(${string})` | `0x${string}`" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AssetCap": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap", + "members": { + "maxPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/constants/tokens\").MoveableToken" + } + } + }, + "Checkpoint": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint", + "members": { + "blockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "kind": { + "optional": false, + "readonly": false, + "type": "\"OWNER_ACTION\" | \"RULES_GRANTED\" | \"RULES_REVOKED\"" + }, + "ref": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "seq": { + "optional": false, + "readonly": false, + "type": "number" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "CheckpointKind": { + "type": "\"OWNER_ACTION\" | \"RULES_GRANTED\" | \"RULES_REVOKED\"", + "members": {} + }, + "CreateOptions": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions", + "members": { + "progressHook": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook | undefined" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Rule[]" + } + } + }, + "CreateResult": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateResult", + "members": { + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "rulesIds": { + "optional": false, + "readonly": false, + "type": "`0x${string}`[]" + }, + "tx": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ForeignChainNamespace": { + "type": "`eip155:${string}` | `solana:${string}`", + "members": {} + }, + "NativeRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "amount": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AmountLimit | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "maxCalls": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValuePerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxValueTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "pins": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ArgPin[] | undefined" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Rule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule | import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "RulesRecord": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "enabled": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "ref": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "rule": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule | import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule" + }, + "rulesId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Selector": { + "type": "`${string}(${string})` | `0x${string}`", + "members": {} + }, + "UniversalRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall[]" + }, + "assets": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap[]" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "`eip155:${string}` | `solana:${string}`" + }, + "maxGasPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "WalletInfo": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").WalletInfo", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "label": { + "optional": false, + "readonly": false, + "type": "string" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "rulesCount": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "WalletSummary": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "label": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesCount": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "PushChain": { + "type": "import(\"sdk/src/lib/push-chain/push-chain\").PushChain", + "members": { + "accountStatus": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus" + }, + "accountStatusReady": { + "optional": false, + "readonly": false, + "type": "Promise" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace" + }, + "explorer": { + "optional": false, + "readonly": false, + "type": "{\n getTransactionUrl: (txHash: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n listAllUrls: () => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n listUrls: (options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n}" + }, + "funds": { + "optional": false, + "readonly": false, + "type": "{\n getConversionQuote: (amountIn: bigint, options: {\n from: import(\"sdk/src/lib/constants/tokens\").PayableToken | undefined;\n to: import(\"sdk/src/lib/constants/tokens\").MoveableToken | undefined;\n }) => Promise;\n}" + }, + "getAccountStatus": { + "optional": false, + "readonly": false, + "type": "(options?: {\n forceRefresh?: boolean;\n}) => Promise" + }, + "isReadMode": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "moveable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").MoveableTokenAccessor;\n}" + }, + "payable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").PayableTokenAccessor;\n}" + }, + "reinitialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "universal": { + "optional": false, + "readonly": false, + "type": "{\n readonly account: `0x${string}`;\n executeReads: (reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>;\n executeTransactions: (txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise;\n migrateCEA: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"migrateCEA\"];\n readonly origin: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n prepareRead: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n prepareTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"prepareTransaction\"];\n read: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n rescueFunds: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"rescueFunds\"];\n sendTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"execute\"];\n signMessage: (data: Uint8Array) => Promise;\n signTypedData: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n trackRead: {\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n };\n trackTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"trackTransaction\"];\n}" + }, + "upgradeAccount": { + "optional": false, + "readonly": false, + "type": "(options?: {\n progressHook?: (progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n}) => Promise" + } + } + } + }, + "pushChainStatic": { + "CONSTANTS": { + "optional": false, + "readonly": false, + "type": "{\n AGENTIC: Readonly>>;\n CHAIN: typeof import(\"sdk/src/lib/constants/enums\").CHAIN;\n LIBRARY: typeof import(\"sdk/src/lib/constants/enums\").LIBRARY;\n MOVEABLE: {\n TOKEN: import(\"sdk/src/lib/constants/tokens\").MoveableTokenConstantsMap;\n };\n PAYABLE: {\n TOKEN: import(\"sdk/src/lib/constants/tokens\").PayableTokenConstantsMap;\n };\n PUSH_NETWORK: typeof import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n READ: {\n readonly CALLBACK_BUDGET_BUFFER: 3;\n readonly CHAIN: {\n readonly WEB2: \"web2\";\n } & Readonly<{\n readonly ARBITRUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA;\n readonly BASE_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA;\n readonly BNB_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET;\n readonly ETHEREUM_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET;\n readonly ETHEREUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA;\n readonly PUSH_LOCALNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET;\n readonly PUSH_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET;\n readonly PUSH_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly PUSH_TESTNET_DONUT: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly SOLANA_DEVNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET;\n readonly SOLANA_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET;\n readonly SOLANA_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n readonly WEB2: \"web2\";\n }>;\n readonly DEFAULT_EXPIRY_BLOCKS: 300n;\n readonly ERROR_CODE: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n readonly MAX_CALLBACK_GAS_LIMIT: 1000000n;\n readonly MIN_CONFIRMATIONS_FLOOR: 1;\n readonly NAMESPACE: {\n readonly EVM: \"eip155\";\n readonly SVM: \"solana\";\n readonly WEB2: \"web2\";\n };\n readonly OUTCOME: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME;\n readonly REGISTRY_CALLBACK_GAS: 500000n;\n readonly RESULT_STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n readonly STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS;\n readonly UNIVERSAL_CALLBACK_ADDRESSES: Record;\n readonly UNIVERSAL_CORE_ADDRESSES: Record;\n readonly UNIVERSAL_READ_REGISTRY_ADDRESS: {\n readonly TESTNET_DONUT: \"0x00000000000000000000000000000000000000b2\";\n };\n readonly WEB2: \"web2\";\n readonly WEB2_DEFAULT_TIMEOUT_MS: 5000;\n readonly WEB2_MAX_EXTRACT_ENTRIES: 16;\n };\n}" + }, + "initialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "utils": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/utils\").Utils" + } + }, + "pushChainInstance": { + "accountStatus": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus" + }, + "accountStatusReady": { + "optional": false, + "readonly": false, + "type": "Promise" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace" + }, + "explorer": { + "optional": false, + "readonly": false, + "type": "{\n getTransactionUrl: (txHash: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n listAllUrls: () => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n listUrls: (options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n}" + }, + "funds": { + "optional": false, + "readonly": false, + "type": "{\n getConversionQuote: (amountIn: bigint, options: {\n from: import(\"sdk/src/lib/constants/tokens\").PayableToken | undefined;\n to: import(\"sdk/src/lib/constants/tokens\").MoveableToken | undefined;\n }) => Promise;\n}" + }, + "getAccountStatus": { + "optional": false, + "readonly": false, + "type": "(options?: {\n forceRefresh?: boolean;\n}) => Promise" + }, + "isReadMode": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "moveable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").MoveableTokenAccessor;\n}" + }, + "payable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").PayableTokenAccessor;\n}" + }, + "reinitialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "universal": { + "optional": false, + "readonly": false, + "type": "{\n readonly account: `0x${string}`;\n executeReads: (reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>;\n executeTransactions: (txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise;\n migrateCEA: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"migrateCEA\"];\n readonly origin: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n prepareRead: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n prepareTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"prepareTransaction\"];\n read: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n rescueFunds: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"rescueFunds\"];\n sendTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"execute\"];\n signMessage: (data: Uint8Array) => Promise;\n signTypedData: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n trackRead: {\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n };\n trackTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"trackTransaction\"];\n}" + }, + "upgradeAccount": { + "optional": false, + "readonly": false, + "type": "(options?: {\n progressHook?: (progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n}) => Promise" + } + }, + "transactionMethods": { + "account": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "executeReads": { + "optional": false, + "readonly": false, + "type": "(reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>" + }, + "executeTransactions": { + "optional": false, + "readonly": false, + "type": "(txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise" + }, + "migrateCEA": { + "optional": false, + "readonly": false, + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => Promise" + }, + "origin": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "prepareRead": { + "optional": false, + "readonly": false, + "type": "(subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>" + }, + "prepareTransaction": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions) => Promise" + }, + "read": { + "optional": false, + "readonly": false, + "type": "(subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>" + }, + "rescueFunds": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").RescueFundsParams) => Promise" + }, + "sendTransaction": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").ExecuteParams | import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions) => Promise" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": false, + "readonly": false, + "type": "({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise" + }, + "trackRead": { + "optional": false, + "readonly": false, + "type": "{\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n}" + }, + "trackTransaction": { + "optional": false, + "readonly": false, + "type": "(txHash: string, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TrackTransactionOptions) => Promise" + } + }, + "utilityMethods": { + "account": { + "optional": false, + "readonly": false, + "type": "{\n convertExecutorToOriginAccount: (ueaAddress: `0x${string}`, options?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n }) => Promise;\n convertOriginToExecutor: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n onlyCompute?: boolean;\n }) => Promise;\n deriveExecutorAccount: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n skipNetworkCheck?: boolean;\n }) => Promise;\n fromChainAgnostic: (caip: string) => import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n resolveControllerAccount: (address: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n skipNetworkCheck?: boolean;\n }) => Promise;\n toChainAgnostic: (address: string, options: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n toUniversal: (address: string, options: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n}" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "{\n actionId: (target: `0x${string}`, selector: \"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector) => `0x${string}`;\n configId: (wallet: `0x${string}`, rulesId: `0x${string}`, actionId: `0x${string}`) => `0x${string}`;\n decodeRules: (bytes: `0x${string}`, ctx?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n pushChainNamespace?: string;\n }) => import(\"sdk/src/lib/agentic/agentic.types\").Rule;\n}" + }, + "chains": { + "optional": false, + "readonly": false, + "type": "{\n getChainName: (chainNamespace: string) => string | undefined;\n getChainNamespace: (chainName: string) => string | undefined;\n getSupportedChains: (network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK) => {\n chains: import(\"sdk/src/lib/constants/enums\").CHAIN[];\n };\n getSupportedChainsByName: (network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK) => {\n chains: string[];\n };\n}" + }, + "conversion": { + "optional": false, + "readonly": false, + "type": "{\n slippageToMinAmount(amount: string, options: {\n slippageBps: number;\n }): string;\n}" + }, + "helpers": { + "optional": false, + "readonly": false, + "type": "{\n encodeTxData({ abi, idl, functionName, args, }: {\n abi?: any;\n args?: any[];\n functionName: string;\n idl?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n }): `0x${string}`;\n formatUnits(value: bigint | string, decimalsOrOptions: {\n decimals: number;\n precision?: number;\n } | number): string;\n getChainName: (chainName: string) => string | undefined;\n parseUnits(value: string, exponent: {\n decimals: number;\n } | number): bigint;\n}" + }, + "signer": { + "optional": false, + "readonly": false, + "type": "{\n construct: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options: {\n signAndSendTransaction: (unsignedTx: Uint8Array) => Promise;\n signAuthorization?: (params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise;\n signMessage: (data: Uint8Array) => Promise;\n signTypedData?: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n }) => import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton;\n toUniversal: (signer: import(\"sdk/src/lib/universal/universal.types\").EthersV5SignerType | import(\"sdk/src/lib/universal/universal.types\").EthersV6SignerType | import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton | import(\"sdk/src/lib/universal/universal.types\").ViemSignerType) => Promise;\n toUniversalFromKeypair: (clientOrAccount: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@solana/web3.js/lib/index\").Keypair | import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").WalletClient | import(\"sdk/src/lib/universal/universal.types\").EthersV6SignerType, { chain, library }: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n library: import(\"sdk/src/lib/constants/enums\").LIBRARY;\n }) => Promise;\n}" + }, + "svm": { + "optional": false, + "readonly": false, + "type": "{\n getRegisteredIdls: () => Array<{\n address: `0x${string}`;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n }>;\n registerIdl: (idl: unknown) => void;\n}" + }, + "tokens": { + "optional": false, + "readonly": false, + "type": "{\n getMoveableTokens(chainOrClient?: import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/push-chain/push-chain\").PushChain): {\n tokens: Array<{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n decimals: number;\n mechanism: \"approve\" | \"native\" | \"permit2\";\n prc20Address?: `0x${string}`;\n sourceChain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n symbol: string;\n }>;\n };\n getPayableTokens(chainOrClient?: import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/push-chain/push-chain\").PushChain): {\n tokens: Array<{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n decimals: number;\n mechanism: \"approve\" | \"native\" | \"permit2\";\n symbol: string;\n }>;\n };\n getPC20Address(address: string, options: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n rpcUrls?: Partial>;\n strict?: boolean;\n }): Promise;\n getPRC20Address(token: {\n address: string;\n chain: string;\n } | import(\"sdk/src/lib/constants/tokens\").MoveableToken, options?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n }): {\n address: `0x${string}`;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n decimals: number;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n symbol: string;\n };\n}" + } + }, + "initialize": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise", + "agwConstants": { + "ENVELOPE_VERSION": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "FACTORY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "MAX_ALLOWED_CALLS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "MAX_PINS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "RULES_POLICY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + }, + "constants": { + "AGENTIC": { + "optional": false, + "readonly": false, + "type": "{\n readonly LOCALNET?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n readonly MAINNET?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n readonly TESTNET?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n readonly TESTNET_DONUT?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n}" + }, + "CHAIN": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "LIBRARY": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").LIBRARY" + }, + "MOVEABLE": { + "optional": false, + "readonly": false, + "type": "{\n TOKEN: import(\"sdk/src/lib/constants/tokens\").MoveableTokenConstantsMap;\n}" + }, + "PAYABLE": { + "optional": false, + "readonly": false, + "type": "{\n TOKEN: import(\"sdk/src/lib/constants/tokens\").PayableTokenConstantsMap;\n}" + }, + "PUSH_NETWORK": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "READ": { + "optional": false, + "readonly": false, + "type": "{\n readonly CALLBACK_BUDGET_BUFFER: 3;\n readonly CHAIN: {\n readonly WEB2: \"web2\";\n } & Readonly<{\n readonly ARBITRUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA;\n readonly BASE_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA;\n readonly BNB_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET;\n readonly ETHEREUM_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET;\n readonly ETHEREUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA;\n readonly PUSH_LOCALNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET;\n readonly PUSH_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET;\n readonly PUSH_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly PUSH_TESTNET_DONUT: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly SOLANA_DEVNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET;\n readonly SOLANA_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET;\n readonly SOLANA_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n readonly WEB2: \"web2\";\n }>;\n readonly DEFAULT_EXPIRY_BLOCKS: 300n;\n readonly ERROR_CODE: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n readonly MAX_CALLBACK_GAS_LIMIT: 1000000n;\n readonly MIN_CONFIRMATIONS_FLOOR: 1;\n readonly NAMESPACE: {\n readonly EVM: \"eip155\";\n readonly SVM: \"solana\";\n readonly WEB2: \"web2\";\n };\n readonly OUTCOME: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME;\n readonly REGISTRY_CALLBACK_GAS: 500000n;\n readonly RESULT_STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n readonly STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS;\n readonly UNIVERSAL_CALLBACK_ADDRESSES: Record;\n readonly UNIVERSAL_CORE_ADDRESSES: Record;\n readonly UNIVERSAL_READ_REGISTRY_ADDRESS: {\n readonly TESTNET_DONUT: \"0x00000000000000000000000000000000000000b2\";\n };\n readonly WEB2: \"web2\";\n readonly WEB2_DEFAULT_TIMEOUT_MS: 5000;\n readonly WEB2_MAX_EXTRACT_ENTRIES: 16;\n}" + } + } + }, + "after": { + "exports": [ + "AGENTIC_ERROR_CODE", + "AccountRole", + "AccountStatus", + "AccountType", + "AgenticAddress", + "AgenticDoor", + "AgenticError", + "AgenticErrorCode", + "AgenticHex", + "AgenticNamespace", + "AgenticNetworkConstants", + "AgenticProgressHook", + "AgenticRevertError", + "AgenticTxMetadata", + "AgenticWallet", + "AllowedCall", + "AssetCap", + "BatchReadResponse", + "BuildReadSpecParams", + "CHAIN", + "CONTRACT_REQUEST_STATUS", + "CascadeCompletionResult", + "CascadeHopInfo", + "CascadeProgressEvent", + "CascadeTrackOptions", + "CascadedTxResponse", + "ChainSource", + "ChainTarget", + "Checkpoint", + "CheckpointKind", + "ConversionQuote", + "CreateOptions", + "CreateResult", + "DEFAULT_MAX_PC_FOR_GAS_BUFFER_BPS", + "DecodedErrorPayload", + "DecodedReadResult", + "DecodedSolanaRule", + "DerivedExecutorAccount", + "EncodedReadQuery", + "EvmReadQuery", + "ForeignChainNamespace", + "FulfilOutcome", + "FundsToken", + "InsufficientPC20BalanceError", + "InvalidPC20AddressError", + "InvalidPC20MetadataError", + "InvalidReadQueryError", + "InvalidReadSpecError", + "MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT", + "MaxPCForGasCapFromNativeValueInput", + "MaxPCForGasCapInput", + "MaxPCForGasCapQuote", + "MultiChainTxResponse", + "NativeRule", + "OutboundTxDetails", + "PC20AddressResult", + "PC20AmbiguousAddressError", + "PC20Error", + "PC20ExpectedButPRC20Error", + "PC20ExportRevertedError", + "PC20FactoryMismatchError", + "PC20RegistryEntry", + "PC20RegistryMismatchError", + "PC20TokenChainMismatchError", + "PC20TokenReference", + "PC20UnknownChainNamespaceError", + "PC20UnsafeEmptyPayloadError", + "PC20WrapperNotRegisteredError", + "PC20WrapperPredictionUnavailableError", + "ParsedReadRequest", + "PreparedRead", + "PreparedUniversalTx", + "PushChain", + "PushChainBatchExecutionError", + "PushChainExecutionError", + "PushChainInitializeOptions", + "READ_ERROR_CODE", + "READ_OUTCOME", + "READ_STATUS", + "ReadCallback", + "ReadCallbackOptions", + "ReadChain", + "ReadDecodeError", + "ReadDestination", + "ReadExecuteOptions", + "ReadFees", + "ReadHeightUnavailableError", + "ReadLifecycleOptions", + "ReadNotFoundError", + "ReadOptions", + "ReadPreflight", + "ReadPrepareOptions", + "ReadQuery", + "ReadQueryOptions", + "ReadRef", + "ReadRegistryUnavailableError", + "ReadResponseTuple", + "ReadResultShape", + "ReadSpec", + "ReadSpecTuple", + "ReadSpecViolation", + "ReadStateError", + "ReadTimeoutError", + "ReadTrackOptions", + "ReadValue", + "ReadWeb2Options", + "ReceiptLike", + "RescueFundsParams", + "ResolvedAccount", + "ResolvedControllerAccounts", + "ResolvedDestination", + "Rule", + "RulesRecord", + "Selector", + "SignAuthorizationParams", + "SignedAuthorization", + "SimulateReadResult", + "SolanaRule", + "SvmAccountRef", + "SvmExecutePayloadFields", + "SvmFieldConstraint", + "SvmGatewayAccountMeta", + "SvmInstructionRule", + "SvmReadQuery", + "TERMINAL_READ_STATUSES", + "TransactionRoute", + "TransactionRouteType", + "UEAStatus", + "UNIVERSAL_CALLBACK_EVM", + "UNIVERSAL_READ_REGISTRY_EVM", + "UNIVERSAL_READ_STATUS", + "UniversalAccount", + "UniversalExecuteParams", + "UniversalOutboundTxRequest", + "UniversalReadResponse", + "UniversalRule", + "UniversalSigner", + "UniversalSignerSkeleton", + "UniversalTo", + "UnsupportedPC20DestinationError", + "UnsupportedReadDestinationError", + "ValidateReadCall", + "WaitForOutboundOptions", + "WalletInfo", + "WalletSummary", + "Web2Extract", + "Web2ReadQuery", + "Web2ValueType", + "buildErc20WithdrawalMulticall", + "buildMigrationPayload", + "buildReadSpecFromPreflight", + "chainSupportsCEA", + "chainSupportsOutbound", + "decodeReadResult", + "detectRoute", + "encodeReadQuery", + "encodeSvmExecutePayload", + "getAllCEAAddresses", + "getCEAAddress", + "getCEAFactoryAddress", + "getPushAccountForCEA", + "inferResultShape", + "isCEA", + "isChainTarget", + "isPC20Reference", + "isSvmChain", + "isValidSolanaHexAddress", + "parseFulfilOutcome", + "parseReadRequestsFromReceipt", + "parseUEAVersion", + "quoteMaxPCForGasCap", + "quoteMaxPCForGasCapFromNativeValue", + "resolveDestination", + "sizeCallbackBudget", + "toCallData", + "toReadQuery", + "toRequestIdHex", + "validateReadSpec" + ], + "agw": { + "AgenticNamespace": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace", + "members": { + "create": { + "optional": false, + "readonly": false, + "type": "(label: string, options: import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions) => Promise" + }, + "derive": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n index?: number;\n}) => Promise<{\n address: `0x${string}`;\n deployed: boolean;\n index: number;\n}>" + }, + "list": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n wallets: import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary[];\n}>" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "(address: `0x${string}`) => import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet" + } + } + }, + "AgenticWallet": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "checkpoints": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n sinceBlock?: bigint;\n}) => Promise<{\n checkpoints: import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint[];\n}>" + }, + "info": { + "optional": false, + "readonly": false, + "type": "() => Promise" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n owner: `0x${string}`;\n}>" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "{\n add(rules: import(\"sdk/src/lib/agentic/agentic.types\").Rule[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise<{\n rulesIds: `0x${string}`[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n get(rulesId: `0x${string}`): Promise;\n list(): Promise<{\n rules: import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord[];\n }>;\n revoke(rulesIds: `0x${string}`[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n revoke(params: {\n all: true;\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n update(params: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n rules: {\n rule: import(\"sdk/src/lib/agentic/agentic.types\").Rule;\n rulesId: `0x${string}`;\n }[];\n }): Promise<{\n rules: {\n replaced: `0x${string}`;\n rulesId: `0x${string}`;\n }[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n}" + }, + "setLabel": { + "optional": false, + "readonly": false, + "type": "(label: string, opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n}) => Promise" + } + } + }, + "AgenticError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"AMBIGUOUS_RULE\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"CREATE_PARTIAL\" | \"FROM_NOT_ALLOWED\" | \"GATEWAY_ALLOWANCE_INSUFFICIENT\" | \"GENERATION_UNSUPPORTED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"REVOKE_NEEDS_TARGET\" | \"RULE_LIMIT_EXCEEDED\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"" + }, + "details": { + "optional": true, + "readonly": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "AgenticRevertError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticRevertError", + "members": { + "agenticCode": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + } + } + }, + "AGENTIC_ERROR_CODE": { + "type": "{\n readonly AGENT_GAS_INSUFFICIENT: \"AGENT_GAS_INSUFFICIENT\";\n readonly AGENT_IS_OWNER: \"AGENT_IS_OWNER\";\n readonly AMBIGUOUS_RULE: \"AMBIGUOUS_RULE\";\n readonly ASSET_CHAIN_MISMATCH: \"ASSET_CHAIN_MISMATCH\";\n readonly CAPABILITY_UNAVAILABLE: \"CAPABILITY_UNAVAILABLE\";\n readonly CREATE_PARTIAL: \"CREATE_PARTIAL\";\n readonly FROM_NOT_ALLOWED: \"FROM_NOT_ALLOWED\";\n readonly GATEWAY_ALLOWANCE_INSUFFICIENT: \"GATEWAY_ALLOWANCE_INSUFFICIENT\";\n readonly GENERATION_UNSUPPORTED: \"GENERATION_UNSUPPORTED\";\n readonly INCONSISTENT_READ: \"INCONSISTENT_READ\";\n readonly INDEX_RACE: \"INDEX_RACE\";\n readonly INVALID_RULE: \"INVALID_RULE\";\n readonly NO_RULES_FOR_CHAIN: \"NO_RULES_FOR_CHAIN\";\n readonly NOT_AGENTIC_WALLET: \"NOT_AGENTIC_WALLET\";\n readonly NOT_ALLOWED_IN_AGENTIC_MODE: \"NOT_ALLOWED_IN_AGENTIC_MODE\";\n readonly NOT_OWNER_OR_AGENT: \"NOT_OWNER_OR_AGENT\";\n readonly NOT_WALLET_OWNER: \"NOT_WALLET_OWNER\";\n readonly READ_ONLY: \"READ_ONLY\";\n readonly RECEIPT_MISMATCH: \"RECEIPT_MISMATCH\";\n readonly RECEIPT_UNAVAILABLE: \"RECEIPT_UNAVAILABLE\";\n readonly REVOKE_NEEDS_TARGET: \"REVOKE_NEEDS_TARGET\";\n readonly RULE_LIMIT_EXCEEDED: \"RULE_LIMIT_EXCEEDED\";\n readonly RULE_NOT_FOUND: \"RULE_NOT_FOUND\";\n readonly RULE_READ_FAILED: \"RULE_READ_FAILED\";\n readonly TARGET_NOT_ON_RULE_CHAIN: \"TARGET_NOT_ON_RULE_CHAIN\";\n readonly WALLET_BALANCE_INSUFFICIENT: \"WALLET_BALANCE_INSUFFICIENT\";\n readonly WALLET_NOT_DEPLOYED: \"WALLET_NOT_DEPLOYED\";\n}", + "members": { + "AGENT_GAS_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\"" + }, + "AGENT_IS_OWNER": { + "optional": false, + "readonly": true, + "type": "\"AGENT_IS_OWNER\"" + }, + "AMBIGUOUS_RULE": { + "optional": false, + "readonly": true, + "type": "\"AMBIGUOUS_RULE\"" + }, + "ASSET_CHAIN_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"ASSET_CHAIN_MISMATCH\"" + }, + "CAPABILITY_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"CAPABILITY_UNAVAILABLE\"" + }, + "CREATE_PARTIAL": { + "optional": false, + "readonly": true, + "type": "\"CREATE_PARTIAL\"" + }, + "FROM_NOT_ALLOWED": { + "optional": false, + "readonly": true, + "type": "\"FROM_NOT_ALLOWED\"" + }, + "GATEWAY_ALLOWANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"GATEWAY_ALLOWANCE_INSUFFICIENT\"" + }, + "GENERATION_UNSUPPORTED": { + "optional": false, + "readonly": true, + "type": "\"GENERATION_UNSUPPORTED\"" + }, + "INCONSISTENT_READ": { + "optional": false, + "readonly": true, + "type": "\"INCONSISTENT_READ\"" + }, + "INDEX_RACE": { + "optional": false, + "readonly": true, + "type": "\"INDEX_RACE\"" + }, + "INVALID_RULE": { + "optional": false, + "readonly": true, + "type": "\"INVALID_RULE\"" + }, + "NO_RULES_FOR_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"NO_RULES_FOR_CHAIN\"" + }, + "NOT_AGENTIC_WALLET": { + "optional": false, + "readonly": true, + "type": "\"NOT_AGENTIC_WALLET\"" + }, + "NOT_ALLOWED_IN_AGENTIC_MODE": { + "optional": false, + "readonly": true, + "type": "\"NOT_ALLOWED_IN_AGENTIC_MODE\"" + }, + "NOT_OWNER_OR_AGENT": { + "optional": false, + "readonly": true, + "type": "\"NOT_OWNER_OR_AGENT\"" + }, + "NOT_WALLET_OWNER": { + "optional": false, + "readonly": true, + "type": "\"NOT_WALLET_OWNER\"" + }, + "READ_ONLY": { + "optional": false, + "readonly": true, + "type": "\"READ_ONLY\"" + }, + "RECEIPT_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_MISMATCH\"" + }, + "RECEIPT_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_UNAVAILABLE\"" + }, + "REVOKE_NEEDS_TARGET": { + "optional": false, + "readonly": true, + "type": "\"REVOKE_NEEDS_TARGET\"" + }, + "RULE_LIMIT_EXCEEDED": { + "optional": false, + "readonly": true, + "type": "\"RULE_LIMIT_EXCEEDED\"" + }, + "RULE_NOT_FOUND": { + "optional": false, + "readonly": true, + "type": "\"RULE_NOT_FOUND\"" + }, + "RULE_READ_FAILED": { + "optional": false, + "readonly": true, + "type": "\"RULE_READ_FAILED\"" + }, + "TARGET_NOT_ON_RULE_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"TARGET_NOT_ON_RULE_CHAIN\"" + }, + "WALLET_BALANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"WALLET_BALANCE_INSUFFICIENT\"" + }, + "WALLET_NOT_DEPLOYED": { + "optional": false, + "readonly": true, + "type": "\"WALLET_NOT_DEPLOYED\"" + } + } + }, + "NativeRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "amount": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AmountLimit | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "maxCalls": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValuePerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxValueTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "pins": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ArgPin[] | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "AssetCap": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap", + "members": { + "maxPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/constants/tokens\").MoveableToken" + } + } + }, + "AllowedCall": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall", + "members": { + "beneficiary": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "beneficiaryOffset": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValue": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "`${string}(${string})` | `0x${string}`" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "UniversalRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall[]" + }, + "assets": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap[]" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "`eip155:${string}`" + }, + "maxGasPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "RulesRecord": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "enabled": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "rule": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").DecodedSolanaRule | import(\"sdk/src/lib/agentic/agentic.types\").Rule" + }, + "rulesId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "CreateOptions": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions", + "members": { + "progressHook": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook | undefined" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Rule[]" + } + } + }, + "CreateResult": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateResult", + "members": { + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "rulesIds": { + "optional": false, + "readonly": false, + "type": "`0x${string}`[]" + }, + "tx": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticTxMetadata": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticTxMetadata", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destinationAccount": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "destinationCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "destinationInstruction": { + "optional": true, + "readonly": false, + "type": "{\n accounts: readonly {\n isWritable: boolean;\n pubkey: `0x${string}`;\n }[];\n data: `0x${string}`;\n program: `0x${string}`;\n} | undefined" + }, + "destinationTransfer": { + "optional": true, + "readonly": false, + "type": "{\n amount: bigint;\n recipient: `0x${string}`;\n token: `0x${string}`;\n} | undefined" + }, + "door": { + "optional": false, + "readonly": false, + "type": "\"agent\" | \"owner\"" + }, + "nativeCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "rawData": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rawTo": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesId": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + } + }, + "publicSurface": { + "CHAIN": { + "type": "typeof import(\"sdk/src/lib/constants/enums\").CHAIN", + "members": { + "ARBITRUM_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA" + }, + "BASE_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA" + }, + "BNB_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET" + }, + "ETHEREUM_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET" + }, + "ETHEREUM_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA" + }, + "PUSH_LOCALNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET" + }, + "PUSH_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET" + }, + "PUSH_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET" + }, + "PUSH_TESTNET_DONUT": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET" + }, + "SOLANA_DEVNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET" + }, + "SOLANA_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET" + }, + "SOLANA_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET" + }, + "WEB2": { + "optional": false, + "readonly": false, + "type": "\"web2\"" + } + } + }, + "ConversionQuote": { + "type": "import(\"sdk/src/lib/constants/tokens\").ConversionQuote", + "members": { + "amountIn": { + "optional": false, + "readonly": false, + "type": "string" + }, + "amountOut": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rate": { + "optional": false, + "readonly": false, + "type": "number" + }, + "route": { + "optional": true, + "readonly": false, + "type": "string[] | undefined" + }, + "timestamp": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "UniversalSigner": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalSigner", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "signAndSendTransaction": { + "optional": false, + "readonly": false, + "type": "(unsignedTx: Uint8Array) => Promise" + }, + "signAuthorization": { + "optional": true, + "readonly": false, + "type": "((params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise) | undefined" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": true, + "readonly": false, + "type": "(({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise) | undefined" + } + } + }, + "UniversalAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "UniversalSignerSkeleton": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "signAndSendTransaction": { + "optional": false, + "readonly": false, + "type": "(unsignedTx: Uint8Array) => Promise" + }, + "signAuthorization": { + "optional": true, + "readonly": false, + "type": "((params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise) | undefined" + }, + "signerId": { + "optional": false, + "readonly": false, + "type": "string" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": true, + "readonly": false, + "type": "(({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise) | undefined" + } + } + }, + "SignAuthorizationParams": { + "type": "{\n chainId?: number;\n contractAddress: `0x${string}`;\n executor?: \"self\";\n nonce?: number;\n}", + "members": { + "chainId": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "contractAddress": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "executor": { + "optional": true, + "readonly": false, + "type": "\"self\" | undefined" + }, + "nonce": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "SignedAuthorization": { + "type": "{\n address: `0x${string}`;\n chainId: number;\n nonce: number;\n r: `0x${string}`;\n s: `0x${string}`;\n v?: bigint;\n yParity: number;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainId": { + "optional": false, + "readonly": false, + "type": "number" + }, + "nonce": { + "optional": false, + "readonly": false, + "type": "number" + }, + "r": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "s": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "v": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "yParity": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "DerivedExecutorAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").DerivedExecutorAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean | null" + } + } + }, + "ResolvedAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainName": { + "optional": false, + "readonly": false, + "type": "string" + }, + "exists": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "role": { + "optional": true, + "readonly": false, + "type": "\"controller\" | undefined" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"cea\" | \"uea\" | \"uoa\"" + } + } + }, + "ResolvedControllerAccounts": { + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedControllerAccounts", + "members": { + "accounts": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedAccount[]" + } + } + }, + "AccountType": { + "type": "\"cea\" | \"uea\" | \"uoa\"", + "members": {} + }, + "AccountRole": { + "type": "\"controller\"", + "members": {} + }, + "PC20TokenReference": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "FundsToken": { + "type": "import(\"sdk/src/lib/constants/tokens\").MoveableToken | import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20TokenReference", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "PC20RegistryEntry": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "chainName": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "PC20AddressResult": { + "type": "{\n address: `0x${string}`;\n decimals: number;\n name: string;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n registry: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20RegistryEntry[];\n symbol: string;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "decimals": { + "optional": false, + "readonly": false, + "type": "number" + }, + "name": { + "optional": false, + "readonly": false, + "type": "string" + }, + "network": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "registry": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20RegistryEntry[]" + }, + "symbol": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "isPC20Reference": { + "type": "(token: import(\"sdk/src/lib/orchestrator/orchestrator.types\").FundsToken | undefined) => token is import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20TokenReference", + "members": {} + }, + "PC20Error": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20Error", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidPC20AddressError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InvalidPC20AddressError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20TokenChainMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20TokenChainMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20WrapperNotRegisteredError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20WrapperNotRegisteredError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20RegistryMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20RegistryMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20FactoryMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20FactoryMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidPC20MetadataError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InvalidPC20MetadataError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20ExpectedButPRC20Error": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20ExpectedButPRC20Error", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20AmbiguousAddressError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20AmbiguousAddressError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "candidates": { + "optional": false, + "readonly": true, + "type": "{\n chain: string;\n pushAddress: string;\n}[]" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "UnsupportedPC20DestinationError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").UnsupportedPC20DestinationError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InsufficientPC20BalanceError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InsufficientPC20BalanceError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20UnknownChainNamespaceError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20UnknownChainNamespaceError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20WrapperPredictionUnavailableError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20WrapperPredictionUnavailableError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20ExportRevertedError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20ExportRevertedError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "lockedAmount": { + "optional": true, + "readonly": true, + "type": "bigint | undefined" + }, + "outboundTxId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "revertRecipient": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20UnsafeEmptyPayloadError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20UnsafeEmptyPayloadError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ChainTarget": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "ChainSource": { + "type": "{\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "UniversalTo": { + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget", + "members": {} + }, + "TransactionRouteType": { + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"", + "members": {} + }, + "UniversalExecuteParams": { + "type": "{\n from?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainSource;\n migration?: boolean;\n to: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTo;\n} & Omit", + "members": { + "_minimumDepositUsd": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "_requiredFundsOverride": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "_skipFeeLocking": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "_ueaStatus": { + "optional": true, + "readonly": false, + "type": "{\n balance: bigint;\n isDeployed: boolean;\n nonce: bigint;\n} | undefined" + }, + "data": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiCall[] | undefined" + }, + "deadline": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "feeLockTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "from": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainSource | undefined" + }, + "funds": { + "optional": true, + "readonly": false, + "type": "{\n amount: bigint;\n token?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").FundsToken;\n} | undefined" + }, + "gasLimit": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFeePerGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxPCForGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxPriorityFeePerGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "migration": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "nonce": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "options": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions | undefined" + }, + "payGasWith": { + "optional": true, + "readonly": false, + "type": "{\n minAmountOut?: bigint | string;\n slippageBps?: number;\n token?: import(\"sdk/src/lib/constants/tokens\").PayableToken;\n} | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "to": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget" + }, + "value": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "UniversalOutboundTxRequest": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalOutboundTxRequest", + "members": { + "amount": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gasPrice": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxPCForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "payload": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "recipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "revertRecipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "PreparedUniversalTx": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx", + "members": { + "_hop": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").HopDescriptor" + }, + "deadline": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "estimatedGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gatewayRequest": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalOutboundTxRequest | import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxRequest" + }, + "nonce": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "payload": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + } + } + }, + "CascadedTxResponse": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadedTxResponse", + "members": { + "finalTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hopCount": { + "optional": false, + "readonly": false, + "type": "number" + }, + "hops": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo[]" + }, + "initialTxHash": { + "optional": false, + "readonly": false, + "type": "string" + }, + "initialTxResponse": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions) => Promise" + }, + "waitForAll": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions) => Promise" + } + } + }, + "CascadeHopInfo": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo", + "members": { + "executionChain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "expectedSubTxId": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hopIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "outboundDetails": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").OutboundTxDetails | undefined" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + }, + "status": { + "optional": false, + "readonly": false, + "type": "\"confirmed\" | \"failed\" | \"pending\" | \"submitted\"" + }, + "txHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "CascadeTrackOptions": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions", + "members": { + "eventHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeProgressEvent) => void) | undefined" + }, + "timeout": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "CascadeProgressEvent": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeProgressEvent", + "members": { + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "elapsed": { + "optional": false, + "readonly": false, + "type": "number" + }, + "hopIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + }, + "status": { + "optional": false, + "readonly": false, + "type": "\"confirmed\" | \"failed\" | \"found\" | \"polling\" | \"timeout\" | \"waiting\"" + }, + "txHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "CascadeCompletionResult": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeCompletionResult", + "members": { + "failedAt": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "finalTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "finalTxResponse": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadedTxResponse | undefined" + }, + "hops": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo[]" + }, + "success": { + "optional": false, + "readonly": false, + "type": "boolean" + } + } + }, + "MultiChainTxResponse": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiChainTxResponse", + "members": { + "chains": { + "optional": false, + "readonly": false, + "type": "{\n blockNumber: bigint;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n hash: string;\n status: \"confirmed\" | \"failed\" | \"pending\";\n}[]" + }, + "transactions": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse[]" + } + } + }, + "OutboundTxDetails": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").OutboundTxDetails", + "members": { + "amount": { + "optional": false, + "readonly": false, + "type": "string" + }, + "assetAddr": { + "optional": false, + "readonly": false, + "type": "string" + }, + "destinationChain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "explorerUrl": { + "optional": false, + "readonly": false, + "type": "string" + }, + "externalTxHash": { + "optional": false, + "readonly": false, + "type": "string" + }, + "recipient": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "WaitForOutboundOptions": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").WaitForOutboundOptions", + "members": { + "_expectedDestinationChain": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "_outboundIndex": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "_resolvedSubTxId": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "initialWaitMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: {\n elapsed: number;\n status: \"failed\" | \"found\" | \"polling\" | \"timeout\" | \"waiting\";\n}) => void) | undefined" + }, + "timeout": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "SvmGatewayAccountMeta": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmGatewayAccountMeta", + "members": { + "isWritable": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "pubkey": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "SvmExecutePayloadFields": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmExecutePayloadFields", + "members": { + "accounts": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmGatewayAccountMeta[]" + }, + "instructionId": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "ixData": { + "optional": false, + "readonly": false, + "type": "Uint8Array" + }, + "targetProgram": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AccountStatus": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus", + "members": { + "mode": { + "optional": false, + "readonly": false, + "type": "\"read-only\" | \"signer\"" + }, + "uea": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UEAStatus" + } + } + }, + "UEAStatus": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UEAStatus", + "members": { + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "loaded": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "minRequiredVersion": { + "optional": false, + "readonly": false, + "type": "string" + }, + "requiresUpgrade": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "version": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "RescueFundsParams": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").RescueFundsParams", + "members": { + "prc20": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "universalTxId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "parseUEAVersion": { + "type": "(version: string) => number", + "members": {} + }, + "TransactionRoute": { + "type": "typeof import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute", + "members": { + "CEA_TO_CEA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.CEA_TO_CEA" + }, + "CEA_TO_PUSH": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.CEA_TO_PUSH" + }, + "UOA_TO_CEA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.UOA_TO_CEA" + }, + "UOA_TO_PUSH": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.UOA_TO_PUSH" + } + } + }, + "detectRoute": { + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams) => import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute", + "members": {} + }, + "isChainTarget": { + "type": "(to: unknown) => to is import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget", + "members": {} + }, + "DEFAULT_MAX_PC_FOR_GAS_BUFFER_BPS": { + "type": "1000", + "members": {} + }, + "MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT": { + "type": "10000", + "members": {} + }, + "quoteMaxPCForGasCap": { + "type": "(input: import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapInput) => import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": {} + }, + "quoteMaxPCForGasCapFromNativeValue": { + "type": "(input: import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapFromNativeValueInput) => import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": {} + }, + "MaxPCForGasCapInput": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapInput", + "members": { + "bufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "gasLegNativePc": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "MaxPCForGasCapFromNativeValueInput": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapFromNativeValueInput", + "members": { + "bufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "nativeValueForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "MaxPCForGasCapQuote": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": { + "bufferBps": { + "optional": false, + "readonly": false, + "type": "number" + }, + "gasLegNativePc": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxPCForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "nativeValueForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "getCEAAddress": { + "type": "(ueaAddress: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise", + "members": {} + }, + "getPushAccountForCEA": { + "type": "(ceaAddress: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise<`0x${string}`>", + "members": {} + }, + "isCEA": { + "type": "(address: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise", + "members": {} + }, + "chainSupportsCEA": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "chainSupportsOutbound": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "getCEAFactoryAddress": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => `0x${string}` | undefined", + "members": {} + }, + "getAllCEAAddresses": { + "type": "(ueaAddress: `0x${string}`, rpcUrls?: Partial>) => Promise", + "members": {} + }, + "encodeSvmExecutePayload": { + "type": "(fields: import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmExecutePayloadFields) => `0x${string}`", + "members": {} + }, + "isSvmChain": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "isValidSolanaHexAddress": { + "type": "(address: string) => boolean", + "members": {} + }, + "buildMigrationPayload": { + "type": "() => `0x${string}`", + "members": {} + }, + "buildErc20WithdrawalMulticall": { + "type": "(tokenAddress: `0x${string}`, recipientAddress: `0x${string}`, amount: bigint) => import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiCall[]", + "members": {} + }, + "ReadChain": { + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain", + "members": {} + }, + "ReadDestination": { + "type": "{\n chain: import(\"sdk/src/lib/read-state/read-state.types\").ReadChain;\n} | {\n chainId: string;\n chainNamespace: string;\n}", + "members": {} + }, + "ResolvedDestination": { + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}", + "members": { + "caip2": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainId": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "namespace": { + "optional": false, + "readonly": false, + "type": "\"eip155\" | \"solana\" | \"web2\"" + } + } + }, + "ReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").SvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery", + "members": { + "type": { + "optional": false, + "readonly": false, + "type": "\"accountBalance\" | \"contractCall\" | \"http\" | \"lamportBalance\" | \"rawAccountData\" | \"splTokenAccount\" | \"storageSlot\"" + } + } + }, + "EvmReadQuery": { + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n target: `0x${string}`;\n type: \"contractCall\";\n} | {\n callData: `0x${string}`;\n target: `0x${string}`;\n type: \"contractCall\";\n} | {\n slot: `0x${string}` | bigint;\n target: `0x${string}`;\n type: \"storageSlot\";\n} | {\n target: `0x${string}`;\n type: \"accountBalance\";\n}", + "members": { + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"accountBalance\" | \"contractCall\" | \"storageSlot\"" + } + } + }, + "SvmReadQuery": { + "type": "{\n account: string | Uint8Array;\n accountName?: string;\n idl?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n type: \"rawAccountData\";\n} | {\n account: string | Uint8Array;\n type: \"lamportBalance\";\n} | {\n account: string | Uint8Array;\n type: \"splTokenAccount\";\n}", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "string | Uint8Array" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"lamportBalance\" | \"rawAccountData\" | \"splTokenAccount\"" + } + } + }, + "Web2ReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery", + "members": { + "body": { + "optional": true, + "readonly": false, + "type": "string | Uint8Array | undefined" + }, + "extract": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[]" + }, + "headers": { + "optional": true, + "readonly": false, + "type": "Record | undefined" + }, + "method": { + "optional": true, + "readonly": false, + "type": "\"GET\" | \"POST\" | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"http\"" + }, + "url": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "Web2Extract": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract", + "members": { + "decimals": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "path": { + "optional": false, + "readonly": false, + "type": "string" + }, + "valueType": { + "optional": false, + "readonly": false, + "type": "\"bool\" | \"bytes\" | \"int256\" | \"string\" | \"uint256\"" + } + } + }, + "Web2ValueType": { + "type": "\"bool\" | \"bytes\" | \"int256\" | \"string\" | \"uint256\"", + "members": {} + }, + "EncodedReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery", + "members": { + "blockRef": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "encoded": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "namespace": { + "optional": false, + "readonly": false, + "type": "\"eip155\" | \"solana\" | \"web2\"" + }, + "ownerBytes": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "queryType": { + "optional": false, + "readonly": false, + "type": "number" + }, + "resultShape": { + "optional": false, + "readonly": false, + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}" + }, + "warnings": { + "optional": false, + "readonly": false, + "type": "string[]" + } + } + }, + "ReadResultShape": { + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"bytes32\" | \"evmCall\" | \"raw\" | \"svmAccount\" | \"uint256\" | \"web2\"" + } + } + }, + "DecodedReadResult": { + "type": "{\n accountName: string;\n kind: \"svmAccount\";\n value: unknown;\n} | {\n kind: \"bytes32\";\n value: `0x${string}`;\n} | {\n kind: \"evmCall\";\n value: unknown;\n} | {\n kind: \"raw\";\n value: `0x${string}`;\n} | {\n kind: \"uint256\";\n value: bigint;\n} | {\n kind: \"web2\";\n values: readonly unknown[];\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"bytes32\" | \"evmCall\" | \"raw\" | \"svmAccount\" | \"uint256\" | \"web2\"" + } + } + }, + "ReadPreflight": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight", + "members": { + "destination": { + "optional": false, + "readonly": false, + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}" + }, + "fetchedAt": { + "optional": false, + "readonly": false, + "type": "number" + }, + "observedChainHeight": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pushBlockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pushGasPrice": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "universalCallback": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "universalCore": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ReadSpec": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "{\n chainId: string;\n chainNamespace: string;\n owner: `0x${string}`;\n}" + }, + "blockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "expiryPushChainHeight": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "minConfirmations": { + "optional": false, + "readonly": false, + "type": "number" + }, + "query": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "revertRecipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ReadSpecTuple": { + "type": "readonly [\n readonly [\n string,\n string,\n `0x${string}`\n ],\n `0x${string}`,\n number,\n bigint,\n bigint,\n bigint,\n `0x${string}`\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "readonly [\n string,\n string,\n `0x${string}`\n]" + }, + "1": { + "optional": false, + "readonly": true, + "type": "`0x${string}`" + }, + "2": { + "optional": false, + "readonly": true, + "type": "number" + }, + "3": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "4": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "5": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "6": { + "optional": false, + "readonly": true, + "type": "`0x${string}`" + }, + "length": { + "optional": false, + "readonly": true, + "type": "7" + } + } + }, + "BuildReadSpecParams": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").BuildReadSpecParams", + "members": { + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "budgetBuffer": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback | undefined" + }, + "callbackBudget": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "destination": { + "optional": false, + "readonly": false, + "type": "{\n chain: import(\"sdk/src/lib/read-state/read-state.types\").ReadChain;\n} | {\n chainId: string;\n chainNamespace: string;\n}" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "expiryPushChainHeight": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFeeBufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "owner": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "query": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").SvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "PreparedRead": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead", + "members": { + "__@preparedReadValue": { + "optional": true, + "readonly": true, + "type": "T | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback | undefined" + }, + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "encodedQuery": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery" + }, + "encodedSpec": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "fees": { + "optional": false, + "readonly": false, + "type": "{\n callbackBudget: bigint;\n protocolFee: bigint;\n total: bigint;\n}" + }, + "preflight": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "queryKey": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "resultShape": { + "optional": false, + "readonly": false, + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}" + }, + "spec": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec" + }, + "specTuple": { + "optional": false, + "readonly": false, + "type": "readonly [\n readonly [\n string,\n string,\n `0x${string}`\n ],\n `0x${string}`,\n number,\n bigint,\n bigint,\n bigint,\n `0x${string}`\n]" + }, + "value": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "warnings": { + "optional": false, + "readonly": false, + "type": "string[]" + } + } + }, + "ReadCallback": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "((spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpecTuple, callbackGasLimit: bigint) => readonly unknown[]) | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "gasLimit": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "target": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "SimulateReadResult": { + "type": "{\n args?: readonly unknown[];\n error: string;\n errorName?: string;\n ok: false;\n} | {\n ok: true;\n}", + "members": { + "ok": { + "optional": false, + "readonly": false, + "type": "boolean" + } + } + }, + "ParsedReadRequest": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ParsedReadRequest", + "members": { + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackTarget": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "logIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "originalFunder": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "requestId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "requestIdUint": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "spec": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec" + }, + "totalPaid": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "FulfilOutcome": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").FulfilOutcome", + "members": { + "burned": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "delivered": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "expired": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "failReason": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "gasReported": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refunded": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refundFailed": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "ReceiptLike": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike", + "members": { + "logs": { + "optional": false, + "readonly": false, + "type": "readonly {\n address: string;\n data: string;\n logIndex?: number | string;\n topics: readonly string[];\n}[]" + } + } + }, + "ReadRef": { + "type": "{\n requestId: `0x${string}` | bigint;\n} | {\n txHash: `0x${string}`;\n}", + "members": {} + }, + "ReadLifecycleOptions": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadLifecycleOptions", + "members": { + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "resultShape": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadFees": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadFees", + "members": { + "burned": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "paid": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "refunded": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refundFailed": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + } + } + }, + "UniversalReadResponse": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse", + "members": { + "callbackDelivered": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "callbackFailReason": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "decoded": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").DecodedReadResult | undefined" + }, + "decodeError": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destination": { + "optional": false, + "readonly": false, + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}" + }, + "errorMsg": { + "optional": false, + "readonly": false, + "type": "string" + }, + "explorerUrl": { + "optional": false, + "readonly": false, + "type": "string" + }, + "fees": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadFees" + }, + "isTerminal": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "outcome": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME" + }, + "pcTx": { + "optional": false, + "readonly": false, + "type": "readonly {\n blockHeight: number;\n errorMsg: string;\n status: string;\n txHash: `0x${string}`;\n}[]" + }, + "raw": { + "optional": false, + "readonly": false, + "type": "{\n errorCode: import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n resultData: `0x${string}`;\n status: import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n} | null" + }, + "refresh": { + "optional": false, + "readonly": false, + "type": "() => Promise>" + }, + "request": { + "optional": false, + "readonly": false, + "type": "{\n callbackGasLimit: bigint;\n callbackTarget: `0x${string}`;\n createdAtHeight: bigint;\n logIndex: number;\n originalFunder: `0x${string}`;\n refundTo: `0x${string}`;\n spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec;\n}" + }, + "requestId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "requestIdUint": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "status": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "value": { + "optional": true, + "readonly": false, + "type": "T | undefined" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/read-state/read-state.types\").ReadLifecycleOptions) => Promise>" + } + } + }, + "ReadResponseTuple": { + "type": "{\n -readonly [K in keyof R]: import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse ? T : unknown>;\n}", + "members": {} + }, + "BatchReadResponse": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").BatchReadResponse", + "members": { + "atomic": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "count": { + "optional": false, + "readonly": false, + "type": "number" + }, + "reads": { + "optional": false, + "readonly": false, + "type": "{\n -readonly [K in keyof R]: import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse ? T : unknown>;\n}" + }, + "transactionHashes": { + "optional": true, + "readonly": false, + "type": "readonly `0x${string}`[] | undefined" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: Omit) => Promise>" + } + } + }, + "ReadOptions": { + "type": "((import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">)) & {\n callback?: (Pick & Required>) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n };\n}", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "advanced": { + "optional": true, + "readonly": false, + "type": "{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n} | undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "({\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} & {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n}) | ({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick & Pick & Required>) | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadPrepareOptions": { + "type": "((((({\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\">) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n}) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">)) & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n}) | ((({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n}) | ({\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\">)) & {\n blockNumber?: never;\n minConfirmations?: never;\n})) & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n}) & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "advanced": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadQueryOptions": { + "type": "({\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\">) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n}) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n}) | ({\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\">)", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadCallbackOptions": { + "type": "{\n callback?: ({\n gasLimit?: bigint;\n target: `0x${string}`;\n } & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n };\n}", + "members": { + "callback": { + "optional": true, + "readonly": false, + "type": "({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} | undefined" + } + } + }, + "ReadValue": { + "type": "O extends {\n abi: infer A extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: infer F extends string;\n} ? number extends A[\"length\"] ? unknown : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, O extends {\n args: infer Args extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n} ? Args : readonly [\n] extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> ? import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> & readonly [\n] : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>> extends infer Selected ? Selected extends {\n outputs: readonly unknown[];\n type: \"function\";\n} & import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiFunction ? {\n [key in keyof {\n [key in keyof import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"]]: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterToPrimitiveType, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"][key], import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterKind>;\n }]: {\n [key in keyof import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"]]: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterToPrimitiveType, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"][key], import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterKind>;\n }[key];\n} extends infer types ? types extends readonly [\n] ? void : types extends readonly [\n infer type\n] ? type : types : never : never : never : O extends {\n web2: {\n extract: infer E extends readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n };\n} ? {\n readonly [K in keyof E]: {\n bool: boolean;\n bytes: `0x${string}`;\n int256: bigint;\n string: string;\n uint256: bigint;\n }[E[K][\"valueType\"]];\n} : O extends {\n storageSlot: unknown;\n} ? `0x${string}` : O extends {\n idl: infer I extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} ? string extends Extract, string> ? unknown : (O extends {\n functionName: infer N extends string;\n} ? N : undefined) extends string ? import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/index\").IdlAccounts[{\n [K in Extract, string>]: Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : K> extends Lowercase<(O extends {\n functionName: infer N extends string;\n } ? N : undefined) & string extends `${infer H}_${infer T}` ? `${H}${Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : (O extends {\n functionName: infer N extends string;\n } ? N : undefined) & string> ? K : never;\n}[Extract, string>]] : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/index\").IdlAccounts[Extract, string>] : bigint", + "members": {} + }, + "ValidateReadCall": { + "type": "O extends {\n abi: infer A extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: infer F extends string;\n} ? (readonly [\n] extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> ? {\n args?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n} : {\n args: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n}) & {\n functionName: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionName;\n} : O extends {\n functionName: infer N extends string;\n idl: infer I extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} ? string extends Extract, string> ? unknown : [\n {\n [K in Extract, string>]: Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : K> extends Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : N> ? K : never;\n }[Extract, string>]\n] extends [\n never\n] ? {\n functionName: Extract, string>;\n} : unknown : unknown", + "members": {} + }, + "ReadWeb2Options": { + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options", + "members": { + "body": { + "optional": true, + "readonly": false, + "type": "string | Uint8Array | undefined" + }, + "extract": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[]" + }, + "headers": { + "optional": true, + "readonly": false, + "type": "Record | undefined" + }, + "method": { + "optional": true, + "readonly": false, + "type": "\"GET\" | \"POST\" | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadTrackOptions": { + "type": "{\n advanced?: Omit, \"enforceGasCheck\">;\n resultShape?: import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape;\n}", + "members": { + "advanced": { + "optional": true, + "readonly": false, + "type": "Omit<{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n}, \"enforceGasCheck\"> | undefined" + }, + "resultShape": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape | undefined" + } + } + }, + "ReadExecuteOptions": { + "type": "{\n advanced?: {\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n } | undefined;\n progressHook?: ((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined;\n waitForCompletion?: boolean | undefined;\n}", + "members": { + "advanced": { + "optional": true, + "readonly": false, + "type": "{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n} | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + } + } + }, + "UNIVERSAL_READ_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS", + "members": { + "ABORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.ABORTED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.EXPIRED" + }, + "FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.FAILED" + }, + "FULFILLED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.FULFILLED" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.PENDING" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.UNSPECIFIED" + }, + "VOTING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.VOTING" + } + } + }, + "READ_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS", + "members": { + "ERROR": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.ERROR" + }, + "SUCCESS": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.SUCCESS" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.UNSPECIFIED" + } + } + }, + "READ_ERROR_CODE": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE", + "members": { + "INVALID_QUERY": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.INVALID_QUERY" + }, + "INVALID_RESULT": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.INVALID_RESULT" + }, + "NOT_FOUND": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.NOT_FOUND" + }, + "REJECTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.REJECTED" + }, + "REVERTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.REVERTED" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.UNSPECIFIED" + }, + "UNSUPPORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.UNSUPPORTED" + } + } + }, + "READ_OUTCOME": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME", + "members": { + "ABORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.ABORTED" + }, + "CALLBACK_FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.CALLBACK_FAILED" + }, + "DECODE_FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.DECODE_FAILED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.EXPIRED" + }, + "FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.FAILED" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.PENDING" + }, + "SOURCE_ERROR": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.SOURCE_ERROR" + }, + "SUCCESS": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.SUCCESS" + }, + "UNKNOWN": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.UNKNOWN" + } + } + }, + "CONTRACT_REQUEST_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS", + "members": { + "EXECUTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.EXECUTED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.EXPIRED" + }, + "NONE": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.NONE" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.PENDING" + }, + "SETTLED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.SETTLED" + } + } + }, + "TERMINAL_READ_STATUSES": { + "type": "ReadonlySet", + "members": {} + }, + "ReadStateError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadStateError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidReadQueryError": { + "type": "import(\"sdk/src/lib/read-state/errors\").InvalidReadQueryError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidReadSpecError": { + "type": "import(\"sdk/src/lib/read-state/errors\").InvalidReadSpecError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "violations": { + "optional": false, + "readonly": true, + "type": "readonly import(\"sdk/src/lib/read-state/errors\").ReadSpecViolation[]" + } + } + }, + "ReadHeightUnavailableError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadHeightUnavailableError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "UnsupportedReadDestinationError": { + "type": "import(\"sdk/src/lib/read-state/errors\").UnsupportedReadDestinationError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadDecodeError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadDecodeError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadTimeoutError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadTimeoutError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "lastStatus": { + "optional": false, + "readonly": true, + "type": "number" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadNotFoundError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadNotFoundError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadRegistryUnavailableError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadRegistryUnavailableError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadSpecViolation": { + "type": "\"CALLBACK_GAS_LIMIT_EXCEEDED\" | \"DOMAIN_BLOCKED\" | \"EMPTY_QUERY\" | \"EXCESSIVE_FEE\" | \"INSUFFICIENT_CALLBACK_BUDGET\" | \"INSUFFICIENT_FEE\" | \"INVALID_ACCOUNT_ID\" | \"INVALID_BLOCK_NUMBER\" | \"INVALID_EXPIRY_HEIGHT\" | \"INVALID_MIN_CONFIRMATIONS\" | \"SVM_OWNER_NOT_32_BYTES\" | \"ZERO_CALLBACK_BUDGET\" | \"ZERO_CALLBACK_GAS_LIMIT\" | \"ZERO_REVERT_RECIPIENT\"", + "members": {} + }, + "resolveDestination": { + "type": "(dest: import(\"sdk/src/lib/read-state/read-state.types\").ReadDestination) => import(\"sdk/src/lib/read-state/read-state.types\").ResolvedDestination", + "members": {} + }, + "encodeReadQuery": { + "type": "(destination: import(\"sdk/src/lib/read-state/read-state.types\").ReadDestination, query: import(\"sdk/src/lib/read-state/read-state.types\").ReadQuery, options?: {\n blockNumber?: bigint;\n minSlot?: bigint;\n}) => import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery", + "members": {} + }, + "decodeReadResult": { + "type": "(resultData: `0x${string}`, shape: import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape) => import(\"sdk/src/lib/read-state/read-state.types\").DecodedReadResult", + "members": {} + }, + "parseReadRequestsFromReceipt": { + "type": "(receipt: import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike, universalCallback: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").ParsedReadRequest[]", + "members": {} + }, + "parseFulfilOutcome": { + "type": "(receipt: import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike, universalCallback: `0x${string}`, requestId: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").FulfilOutcome", + "members": {} + }, + "buildReadSpecFromPreflight": { + "type": "(preflight: import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight, params: import(\"sdk/src/lib/read-state/read-state.types\").BuildReadSpecParams, defaults?: {\n refundTo?: `0x${string}`;\n}) => import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead", + "members": {} + }, + "validateReadSpec": { + "type": "(input: import(\"sdk/src/lib/read-state/validate\").ValidateReadSpecInput) => {\n ok: false;\n violations: import(\"sdk/src/lib/read-state/errors\").ReadSpecViolation[];\n} | {\n ok: true;\n}", + "members": {} + }, + "toCallData": { + "type": "(prepared: import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead, target: {\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: (spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpecTuple, callbackGasLimit: bigint) => readonly unknown[];\n functionName: string;\n}) => {\n data: `0x${string}`;\n value: bigint;\n}", + "members": {} + }, + "sizeCallbackBudget": { + "type": "(callbackGasLimit: bigint, pushGasPrice: bigint, buffer?: number) => bigint", + "members": {} + }, + "inferResultShape": { + "type": "(namespace: string, query: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape", + "members": {} + }, + "toRequestIdHex": { + "type": "(id: `0x${string}` | bigint) => `0x${string}`", + "members": {} + }, + "toReadQuery": { + "type": "(subject: string, o: ReadOptionsInput, resolvedTokenProgram?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@solana/web3.js/lib/index\").PublicKey) => import(\"sdk/src/lib/read-state/read-state.types\").ReadQuery", + "members": {} + }, + "UNIVERSAL_CALLBACK_EVM": { + "type": "readonly [\n {\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"requestExternalReadSelf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"estimateFee\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"statusOf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"enum RequestStatus\";\n readonly name: \"\";\n readonly type: \"uint8\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"isFulfilled\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getPendingRead\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly internalType: \"struct PendingRead\";\n readonly name: \"\";\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"totalEscrowed\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"blockedDomains\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly indexed: false;\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"readSpec\";\n readonly type: \"tuple\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"totalPaid\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"protocolFee\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ReadRequested\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"ReadFulfilled\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"reason\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"CallbackFailed\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"gasReported\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"burned\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"CallbackGasReported\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundSent\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundFailed\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RequestExpired\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"vaultPC\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ProtocolFeeDistributed\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidAccountId\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"EmptyQuery\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidMinConfirmations\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"DomainBlocked\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidBlockNumber\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidExpiryHeight\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroRevertRecipient\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroCallbackGasLimit\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint64\";\n readonly name: \"provided\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"max\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"CallbackGasLimitExceeded\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"required\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"InsufficientFee\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ExcessiveFee\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"actual\";\n readonly type: \"uint8\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"expected\";\n readonly type: \"uint8\";\n }\n ];\n readonly name: \"InvalidRequestStatus\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ContractIsPaused\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"CallerIsNotUCallbackModule\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n }\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"requestExternalReadSelf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n}" + }, + "1": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"estimateFee\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "2": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"statusOf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"enum RequestStatus\";\n readonly name: \"\";\n readonly type: \"uint8\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "3": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"isFulfilled\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "4": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getPendingRead\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly internalType: \"struct PendingRead\";\n readonly name: \"\";\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "5": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"totalEscrowed\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "6": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"blockedDomains\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "7": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly indexed: false;\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"readSpec\";\n readonly type: \"tuple\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"totalPaid\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"protocolFee\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ReadRequested\";\n readonly type: \"event\";\n}" + }, + "8": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"ReadFulfilled\";\n readonly type: \"event\";\n}" + }, + "9": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"reason\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"CallbackFailed\";\n readonly type: \"event\";\n}" + }, + "10": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"gasReported\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"burned\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"CallbackGasReported\";\n readonly type: \"event\";\n}" + }, + "11": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundSent\";\n readonly type: \"event\";\n}" + }, + "12": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundFailed\";\n readonly type: \"event\";\n}" + }, + "13": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RequestExpired\";\n readonly type: \"event\";\n}" + }, + "14": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"vaultPC\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ProtocolFeeDistributed\";\n readonly type: \"event\";\n}" + }, + "15": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidAccountId\";\n readonly type: \"error\";\n}" + }, + "16": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"EmptyQuery\";\n readonly type: \"error\";\n}" + }, + "17": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidMinConfirmations\";\n readonly type: \"error\";\n}" + }, + "18": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"DomainBlocked\";\n readonly type: \"error\";\n}" + }, + "19": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidBlockNumber\";\n readonly type: \"error\";\n}" + }, + "20": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidExpiryHeight\";\n readonly type: \"error\";\n}" + }, + "21": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroRevertRecipient\";\n readonly type: \"error\";\n}" + }, + "22": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroCallbackGasLimit\";\n readonly type: \"error\";\n}" + }, + "23": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint64\";\n readonly name: \"provided\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"max\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"CallbackGasLimitExceeded\";\n readonly type: \"error\";\n}" + }, + "24": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"required\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"InsufficientFee\";\n readonly type: \"error\";\n}" + }, + "25": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ExcessiveFee\";\n readonly type: \"error\";\n}" + }, + "26": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"actual\";\n readonly type: \"uint8\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"expected\";\n readonly type: \"uint8\";\n }\n ];\n readonly name: \"InvalidRequestStatus\";\n readonly type: \"error\";\n}" + }, + "27": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ContractIsPaused\";\n readonly type: \"error\";\n}" + }, + "28": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"CallerIsNotUCallbackModule\";\n readonly type: \"error\";\n}" + }, + "29": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n}" + }, + "length": { + "optional": false, + "readonly": true, + "type": "30" + } + } + }, + "UNIVERSAL_READ_REGISTRY_EVM": { + "type": "readonly [\n {\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n },\n {\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"read\";\n readonly outputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"universalCallback_\";\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"constructor\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"initialize\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getLocalContext\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"hasResult\";\n readonly outputs: readonly [\n {\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"onUniversalData\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"queryKeyOf\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes32\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"readerOf\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"requestOrderOf\";\n readonly outputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"universalCallback\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"resultByRequestId\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"latestResult\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"version\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"Initialized\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadRequested\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadStored\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidInitialization\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"NotInitializing\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroAddressInit\";\n readonly type: \"error\";\n }\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n },\n {\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"read\";\n readonly outputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n}" + }, + "1": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"universalCallback_\";\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"constructor\";\n}" + }, + "2": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"initialize\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n}" + }, + "3": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getLocalContext\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "4": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"hasResult\";\n readonly outputs: readonly [\n {\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "5": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"onUniversalData\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n}" + }, + "6": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"queryKeyOf\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes32\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "7": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"readerOf\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "8": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"requestOrderOf\";\n readonly outputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "9": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"universalCallback\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "10": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"resultByRequestId\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "11": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"latestResult\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "12": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"version\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"Initialized\";\n readonly type: \"event\";\n}" + }, + "13": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadRequested\";\n readonly type: \"event\";\n}" + }, + "14": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadStored\";\n readonly type: \"event\";\n}" + }, + "15": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidInitialization\";\n readonly type: \"error\";\n}" + }, + "16": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"NotInitializing\";\n readonly type: \"error\";\n}" + }, + "17": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n}" + }, + "18": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroAddressInit\";\n readonly type: \"error\";\n}" + }, + "length": { + "optional": false, + "readonly": true, + "type": "19" + } + } + }, + "PushChainExecutionError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").PushChainExecutionError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PushChainBatchExecutionError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").PushChainBatchExecutionError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": false, + "readonly": true, + "type": "`0x${string}`[]" + } + } + }, + "DecodedErrorPayload": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload", + "members": { + "decoded": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "name": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "selector": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "PushChainInitializeOptions": { + "type": "import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions", + "members": { + "agenticWallet": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "blockExplorers": { + "optional": true, + "readonly": false, + "type": "Partial> | undefined" + }, + "network": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "printTraces": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "rpcUrls": { + "optional": true, + "readonly": false, + "type": "Partial> | undefined" + } + } + }, + "AGENTIC_ERROR_CODE": { + "type": "{\n readonly AGENT_GAS_INSUFFICIENT: \"AGENT_GAS_INSUFFICIENT\";\n readonly AGENT_IS_OWNER: \"AGENT_IS_OWNER\";\n readonly AMBIGUOUS_RULE: \"AMBIGUOUS_RULE\";\n readonly ASSET_CHAIN_MISMATCH: \"ASSET_CHAIN_MISMATCH\";\n readonly CAPABILITY_UNAVAILABLE: \"CAPABILITY_UNAVAILABLE\";\n readonly CREATE_PARTIAL: \"CREATE_PARTIAL\";\n readonly FROM_NOT_ALLOWED: \"FROM_NOT_ALLOWED\";\n readonly GATEWAY_ALLOWANCE_INSUFFICIENT: \"GATEWAY_ALLOWANCE_INSUFFICIENT\";\n readonly GENERATION_UNSUPPORTED: \"GENERATION_UNSUPPORTED\";\n readonly INCONSISTENT_READ: \"INCONSISTENT_READ\";\n readonly INDEX_RACE: \"INDEX_RACE\";\n readonly INVALID_RULE: \"INVALID_RULE\";\n readonly NO_RULES_FOR_CHAIN: \"NO_RULES_FOR_CHAIN\";\n readonly NOT_AGENTIC_WALLET: \"NOT_AGENTIC_WALLET\";\n readonly NOT_ALLOWED_IN_AGENTIC_MODE: \"NOT_ALLOWED_IN_AGENTIC_MODE\";\n readonly NOT_OWNER_OR_AGENT: \"NOT_OWNER_OR_AGENT\";\n readonly NOT_WALLET_OWNER: \"NOT_WALLET_OWNER\";\n readonly READ_ONLY: \"READ_ONLY\";\n readonly RECEIPT_MISMATCH: \"RECEIPT_MISMATCH\";\n readonly RECEIPT_UNAVAILABLE: \"RECEIPT_UNAVAILABLE\";\n readonly REVOKE_NEEDS_TARGET: \"REVOKE_NEEDS_TARGET\";\n readonly RULE_LIMIT_EXCEEDED: \"RULE_LIMIT_EXCEEDED\";\n readonly RULE_NOT_FOUND: \"RULE_NOT_FOUND\";\n readonly RULE_READ_FAILED: \"RULE_READ_FAILED\";\n readonly TARGET_NOT_ON_RULE_CHAIN: \"TARGET_NOT_ON_RULE_CHAIN\";\n readonly WALLET_BALANCE_INSUFFICIENT: \"WALLET_BALANCE_INSUFFICIENT\";\n readonly WALLET_NOT_DEPLOYED: \"WALLET_NOT_DEPLOYED\";\n}", + "members": { + "AGENT_GAS_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\"" + }, + "AGENT_IS_OWNER": { + "optional": false, + "readonly": true, + "type": "\"AGENT_IS_OWNER\"" + }, + "AMBIGUOUS_RULE": { + "optional": false, + "readonly": true, + "type": "\"AMBIGUOUS_RULE\"" + }, + "ASSET_CHAIN_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"ASSET_CHAIN_MISMATCH\"" + }, + "CAPABILITY_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"CAPABILITY_UNAVAILABLE\"" + }, + "CREATE_PARTIAL": { + "optional": false, + "readonly": true, + "type": "\"CREATE_PARTIAL\"" + }, + "FROM_NOT_ALLOWED": { + "optional": false, + "readonly": true, + "type": "\"FROM_NOT_ALLOWED\"" + }, + "GATEWAY_ALLOWANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"GATEWAY_ALLOWANCE_INSUFFICIENT\"" + }, + "GENERATION_UNSUPPORTED": { + "optional": false, + "readonly": true, + "type": "\"GENERATION_UNSUPPORTED\"" + }, + "INCONSISTENT_READ": { + "optional": false, + "readonly": true, + "type": "\"INCONSISTENT_READ\"" + }, + "INDEX_RACE": { + "optional": false, + "readonly": true, + "type": "\"INDEX_RACE\"" + }, + "INVALID_RULE": { + "optional": false, + "readonly": true, + "type": "\"INVALID_RULE\"" + }, + "NO_RULES_FOR_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"NO_RULES_FOR_CHAIN\"" + }, + "NOT_AGENTIC_WALLET": { + "optional": false, + "readonly": true, + "type": "\"NOT_AGENTIC_WALLET\"" + }, + "NOT_ALLOWED_IN_AGENTIC_MODE": { + "optional": false, + "readonly": true, + "type": "\"NOT_ALLOWED_IN_AGENTIC_MODE\"" + }, + "NOT_OWNER_OR_AGENT": { + "optional": false, + "readonly": true, + "type": "\"NOT_OWNER_OR_AGENT\"" + }, + "NOT_WALLET_OWNER": { + "optional": false, + "readonly": true, + "type": "\"NOT_WALLET_OWNER\"" + }, + "READ_ONLY": { + "optional": false, + "readonly": true, + "type": "\"READ_ONLY\"" + }, + "RECEIPT_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_MISMATCH\"" + }, + "RECEIPT_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_UNAVAILABLE\"" + }, + "REVOKE_NEEDS_TARGET": { + "optional": false, + "readonly": true, + "type": "\"REVOKE_NEEDS_TARGET\"" + }, + "RULE_LIMIT_EXCEEDED": { + "optional": false, + "readonly": true, + "type": "\"RULE_LIMIT_EXCEEDED\"" + }, + "RULE_NOT_FOUND": { + "optional": false, + "readonly": true, + "type": "\"RULE_NOT_FOUND\"" + }, + "RULE_READ_FAILED": { + "optional": false, + "readonly": true, + "type": "\"RULE_READ_FAILED\"" + }, + "TARGET_NOT_ON_RULE_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"TARGET_NOT_ON_RULE_CHAIN\"" + }, + "WALLET_BALANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"WALLET_BALANCE_INSUFFICIENT\"" + }, + "WALLET_NOT_DEPLOYED": { + "optional": false, + "readonly": true, + "type": "\"WALLET_NOT_DEPLOYED\"" + } + } + }, + "AgenticError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"AMBIGUOUS_RULE\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"CREATE_PARTIAL\" | \"FROM_NOT_ALLOWED\" | \"GATEWAY_ALLOWANCE_INSUFFICIENT\" | \"GENERATION_UNSUPPORTED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"REVOKE_NEEDS_TARGET\" | \"RULE_LIMIT_EXCEEDED\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"" + }, + "details": { + "optional": true, + "readonly": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "AgenticRevertError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticRevertError", + "members": { + "agenticCode": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + } + } + }, + "AgenticAddress": { + "type": "`0x${string}`", + "members": {} + }, + "AgenticDoor": { + "type": "\"agent\" | \"owner\"", + "members": {} + }, + "AgenticErrorCode": { + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"AMBIGUOUS_RULE\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"CREATE_PARTIAL\" | \"FROM_NOT_ALLOWED\" | \"GATEWAY_ALLOWANCE_INSUFFICIENT\" | \"GENERATION_UNSUPPORTED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"REVOKE_NEEDS_TARGET\" | \"RULE_LIMIT_EXCEEDED\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"", + "members": {} + }, + "AgenticHex": { + "type": "`0x${string}`", + "members": {} + }, + "AgenticNamespace": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace", + "members": { + "create": { + "optional": false, + "readonly": false, + "type": "(label: string, options: import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions) => Promise" + }, + "derive": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n index?: number;\n}) => Promise<{\n address: `0x${string}`;\n deployed: boolean;\n index: number;\n}>" + }, + "list": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n wallets: import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary[];\n}>" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "(address: `0x${string}`) => import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet" + } + } + }, + "AgenticNetworkConstants": { + "type": "import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants", + "members": { + "ENVELOPE_VERSION": { + "optional": false, + "readonly": false, + "type": "number" + }, + "FACTORY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "MAX_ALLOWED_CALLS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "MAX_PINS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "RULES_POLICY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticProgressHook": { + "type": "(event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void", + "members": {} + }, + "AgenticTxMetadata": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticTxMetadata", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destinationAccount": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "destinationCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "destinationInstruction": { + "optional": true, + "readonly": false, + "type": "{\n accounts: readonly {\n isWritable: boolean;\n pubkey: `0x${string}`;\n }[];\n data: `0x${string}`;\n program: `0x${string}`;\n} | undefined" + }, + "destinationTransfer": { + "optional": true, + "readonly": false, + "type": "{\n amount: bigint;\n recipient: `0x${string}`;\n token: `0x${string}`;\n} | undefined" + }, + "door": { + "optional": false, + "readonly": false, + "type": "\"agent\" | \"owner\"" + }, + "nativeCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "rawData": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rawTo": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesId": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticWallet": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "checkpoints": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n sinceBlock?: bigint;\n}) => Promise<{\n checkpoints: import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint[];\n}>" + }, + "info": { + "optional": false, + "readonly": false, + "type": "() => Promise" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n owner: `0x${string}`;\n}>" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "{\n add(rules: import(\"sdk/src/lib/agentic/agentic.types\").Rule[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise<{\n rulesIds: `0x${string}`[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n get(rulesId: `0x${string}`): Promise;\n list(): Promise<{\n rules: import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord[];\n }>;\n revoke(rulesIds: `0x${string}`[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n revoke(params: {\n all: true;\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n update(params: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n rules: {\n rule: import(\"sdk/src/lib/agentic/agentic.types\").Rule;\n rulesId: `0x${string}`;\n }[];\n }): Promise<{\n rules: {\n replaced: `0x${string}`;\n rulesId: `0x${string}`;\n }[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n}" + }, + "setLabel": { + "optional": false, + "readonly": false, + "type": "(label: string, opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n}) => Promise" + } + } + }, + "AllowedCall": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall", + "members": { + "beneficiary": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "beneficiaryOffset": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValue": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "`${string}(${string})` | `0x${string}`" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AssetCap": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap", + "members": { + "maxPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/constants/tokens\").MoveableToken" + } + } + }, + "Checkpoint": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint", + "members": { + "blockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "kind": { + "optional": false, + "readonly": false, + "type": "\"OWNER_ACTION\" | \"RULES_GRANTED\" | \"RULES_REVOKED\"" + }, + "ref": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "seq": { + "optional": false, + "readonly": false, + "type": "number" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "CheckpointKind": { + "type": "\"OWNER_ACTION\" | \"RULES_GRANTED\" | \"RULES_REVOKED\"", + "members": {} + }, + "CreateOptions": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions", + "members": { + "progressHook": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook | undefined" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Rule[]" + } + } + }, + "CreateResult": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateResult", + "members": { + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "rulesIds": { + "optional": false, + "readonly": false, + "type": "`0x${string}`[]" + }, + "tx": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ForeignChainNamespace": { + "type": "`eip155:${string}` | `solana:${string}`", + "members": {} + }, + "NativeRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "amount": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AmountLimit | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "maxCalls": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValuePerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxValueTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "pins": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ArgPin[] | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "SolanaRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").SolanaRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "allowedInstructions": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").SvmInstructionRule[]" + }, + "assets": { + "optional": false, + "readonly": false, + "type": "{\n maxPerCall: bigint;\n maxTotal?: bigint;\n token: import(\"sdk/src/lib/constants/tokens\").MoveableToken | string;\n}[]" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "`solana:${string}`" + }, + "maxGasPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "outputTokens": { + "optional": true, + "readonly": false, + "type": "string[] | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "DecodedSolanaRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").DecodedSolanaRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "assets": { + "optional": false, + "readonly": false, + "type": "{\n maxPerCall: bigint;\n maxTotal: bigint;\n token: string;\n}[]" + }, + "ceaAccounts": { + "optional": false, + "readonly": false, + "type": "readonly `0x${string}`[]" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "`solana:${string}`" + }, + "dataPins": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/agentic/codec/svm-terms\").SvmDataPinWire[]" + }, + "expectedCEA": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "format": { + "optional": false, + "readonly": false, + "type": "\"decoded\"" + }, + "gatewayProgram": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "maxGasPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pins": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/agentic/codec/svm-terms\").SvmAccountPinWire[]" + }, + "programs": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/agentic/codec/svm-terms\").AllowedProgramWire[]" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "SvmInstructionRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").SvmInstructionRule", + "members": { + "accounts": { + "optional": false, + "readonly": false, + "type": "{\n expected: import(\"sdk/src/lib/agentic/agentic.types\").SvmAccountRef;\n name: string;\n}[]" + }, + "fields": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").SvmFieldConstraint[] | undefined" + }, + "instruction": { + "optional": false, + "readonly": false, + "type": "{\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n name: string;\n}" + }, + "program": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "SvmAccountRef": { + "type": "{\n address: string;\n kind: \"address\";\n} | {\n kind: \"walletATA\";\n token: string;\n} | {\n kind: \"walletCEA\";\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"address\" | \"walletATA\" | \"walletCEA\"" + } + } + }, + "SvmFieldConstraint": { + "type": "{\n denominator: string;\n minRatio: {\n den: bigint;\n num: bigint;\n };\n numerator: string;\n} | {\n equals: `0x${string}` | bigint | boolean;\n name: string;\n} | {\n max: bigint;\n name: string;\n} | {\n min: bigint;\n name: string;\n}", + "members": {} + }, + "Rule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule | import(\"sdk/src/lib/agentic/agentic.types\").SolanaRule | import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "`eip155:${string}` | `solana:${string}` | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "RulesRecord": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "enabled": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "rule": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").DecodedSolanaRule | import(\"sdk/src/lib/agentic/agentic.types\").Rule" + }, + "rulesId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Selector": { + "type": "`${string}(${string})` | `0x${string}`", + "members": {} + }, + "UniversalRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall[]" + }, + "assets": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap[]" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "`eip155:${string}`" + }, + "maxGasPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "WalletInfo": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").WalletInfo", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "label": { + "optional": false, + "readonly": false, + "type": "string" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "rulesCount": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "WalletSummary": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "label": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesCount": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "PushChain": { + "type": "import(\"sdk/src/lib/push-chain/push-chain\").PushChain", + "members": { + "accountStatus": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus" + }, + "accountStatusReady": { + "optional": false, + "readonly": false, + "type": "Promise" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace" + }, + "explorer": { + "optional": false, + "readonly": false, + "type": "{\n getTransactionUrl: (txHash: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n listAllUrls: () => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n listUrls: (options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n}" + }, + "funds": { + "optional": false, + "readonly": false, + "type": "{\n getConversionQuote: (amountIn: bigint, options: {\n from: import(\"sdk/src/lib/constants/tokens\").PayableToken | undefined;\n to: import(\"sdk/src/lib/constants/tokens\").MoveableToken | undefined;\n }) => Promise;\n}" + }, + "getAccountStatus": { + "optional": false, + "readonly": false, + "type": "(options?: {\n forceRefresh?: boolean;\n}) => Promise" + }, + "isReadMode": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "moveable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").MoveableTokenAccessor;\n}" + }, + "payable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").PayableTokenAccessor;\n}" + }, + "reinitialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "universal": { + "optional": false, + "readonly": false, + "type": "{\n readonly account: `0x${string}`;\n executeReads: (reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>;\n executeTransactions: (txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise;\n migrateCEA: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"migrateCEA\"];\n readonly origin: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n prepareRead: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n prepareTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"prepareTransaction\"];\n read: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n rescueFunds: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"rescueFunds\"];\n sendTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"execute\"];\n signMessage: (data: Uint8Array) => Promise;\n signTypedData: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n trackRead: {\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n };\n trackTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"trackTransaction\"];\n}" + }, + "upgradeAccount": { + "optional": false, + "readonly": false, + "type": "(options?: {\n progressHook?: (progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n}) => Promise" + } + } + } + }, + "pushChainStatic": { + "CONSTANTS": { + "optional": false, + "readonly": false, + "type": "{\n AGENTIC: Readonly>>;\n CHAIN: typeof import(\"sdk/src/lib/constants/enums\").CHAIN;\n LIBRARY: typeof import(\"sdk/src/lib/constants/enums\").LIBRARY;\n MOVEABLE: {\n TOKEN: import(\"sdk/src/lib/constants/tokens\").MoveableTokenConstantsMap;\n };\n PAYABLE: {\n TOKEN: import(\"sdk/src/lib/constants/tokens\").PayableTokenConstantsMap;\n };\n PUSH_NETWORK: typeof import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n READ: {\n readonly CALLBACK_BUDGET_BUFFER: 3;\n readonly CHAIN: {\n readonly WEB2: \"web2\";\n } & Readonly<{\n readonly ARBITRUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA;\n readonly BASE_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA;\n readonly BNB_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET;\n readonly ETHEREUM_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET;\n readonly ETHEREUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA;\n readonly PUSH_LOCALNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET;\n readonly PUSH_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET;\n readonly PUSH_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly PUSH_TESTNET_DONUT: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly SOLANA_DEVNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET;\n readonly SOLANA_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET;\n readonly SOLANA_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n readonly WEB2: \"web2\";\n }>;\n readonly DEFAULT_EXPIRY_BLOCKS: 300n;\n readonly ERROR_CODE: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n readonly MAX_CALLBACK_GAS_LIMIT: 1000000n;\n readonly MIN_CONFIRMATIONS_FLOOR: 1;\n readonly NAMESPACE: {\n readonly EVM: \"eip155\";\n readonly SVM: \"solana\";\n readonly WEB2: \"web2\";\n };\n readonly OUTCOME: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME;\n readonly REGISTRY_CALLBACK_GAS: 500000n;\n readonly RESULT_STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n readonly STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS;\n readonly UNIVERSAL_CALLBACK_ADDRESSES: Record;\n readonly UNIVERSAL_CORE_ADDRESSES: Record;\n readonly UNIVERSAL_READ_REGISTRY_ADDRESS: {\n readonly TESTNET_DONUT: \"0x00000000000000000000000000000000000000b2\";\n };\n readonly WEB2: \"web2\";\n readonly WEB2_DEFAULT_TIMEOUT_MS: 5000;\n readonly WEB2_MAX_EXTRACT_ENTRIES: 16;\n };\n}" + }, + "initialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "utils": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/utils\").Utils" + } + }, + "pushChainInstance": { + "accountStatus": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus" + }, + "accountStatusReady": { + "optional": false, + "readonly": false, + "type": "Promise" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace" + }, + "explorer": { + "optional": false, + "readonly": false, + "type": "{\n getTransactionUrl: (txHash: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n listAllUrls: () => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n listUrls: (options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n}" + }, + "funds": { + "optional": false, + "readonly": false, + "type": "{\n getConversionQuote: (amountIn: bigint, options: {\n from: import(\"sdk/src/lib/constants/tokens\").PayableToken | undefined;\n to: import(\"sdk/src/lib/constants/tokens\").MoveableToken | undefined;\n }) => Promise;\n}" + }, + "getAccountStatus": { + "optional": false, + "readonly": false, + "type": "(options?: {\n forceRefresh?: boolean;\n}) => Promise" + }, + "isReadMode": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "moveable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").MoveableTokenAccessor;\n}" + }, + "payable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").PayableTokenAccessor;\n}" + }, + "reinitialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "universal": { + "optional": false, + "readonly": false, + "type": "{\n readonly account: `0x${string}`;\n executeReads: (reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>;\n executeTransactions: (txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise;\n migrateCEA: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"migrateCEA\"];\n readonly origin: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n prepareRead: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n prepareTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"prepareTransaction\"];\n read: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n rescueFunds: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"rescueFunds\"];\n sendTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"execute\"];\n signMessage: (data: Uint8Array) => Promise;\n signTypedData: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n trackRead: {\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n };\n trackTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"trackTransaction\"];\n}" + }, + "upgradeAccount": { + "optional": false, + "readonly": false, + "type": "(options?: {\n progressHook?: (progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n}) => Promise" + } + }, + "transactionMethods": { + "account": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "executeReads": { + "optional": false, + "readonly": false, + "type": "(reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>" + }, + "executeTransactions": { + "optional": false, + "readonly": false, + "type": "(txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise" + }, + "migrateCEA": { + "optional": false, + "readonly": false, + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => Promise" + }, + "origin": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "prepareRead": { + "optional": false, + "readonly": false, + "type": "(subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>" + }, + "prepareTransaction": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions) => Promise" + }, + "read": { + "optional": false, + "readonly": false, + "type": "(subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>" + }, + "rescueFunds": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").RescueFundsParams) => Promise" + }, + "sendTransaction": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").ExecuteParams | import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions) => Promise" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": false, + "readonly": false, + "type": "({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise" + }, + "trackRead": { + "optional": false, + "readonly": false, + "type": "{\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n}" + }, + "trackTransaction": { + "optional": false, + "readonly": false, + "type": "(txHash: string, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TrackTransactionOptions) => Promise" + } + }, + "utilityMethods": { + "account": { + "optional": false, + "readonly": false, + "type": "{\n convertExecutorToOriginAccount: (ueaAddress: `0x${string}`, options?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n }) => Promise;\n convertOriginToExecutor: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n onlyCompute?: boolean;\n }) => Promise;\n deriveExecutorAccount: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n skipNetworkCheck?: boolean;\n }) => Promise;\n fromChainAgnostic: (caip: string) => import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n resolveControllerAccount: (address: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n skipNetworkCheck?: boolean;\n }) => Promise;\n toChainAgnostic: (address: string, options: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n toUniversal: (address: string, options: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n}" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "{\n actionId: (target: `0x${string}`, selector: \"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector) => `0x${string}`;\n configId: (wallet: `0x${string}`, rulesId: `0x${string}`, actionId: `0x${string}`) => `0x${string}`;\n decodeRules: (bytes: `0x${string}`, ctx?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n pushChainNamespace?: string;\n }) => import(\"sdk/src/lib/agentic/agentic.types\").DecodedSolanaRule | import(\"sdk/src/lib/agentic/agentic.types\").Rule;\n}" + }, + "chains": { + "optional": false, + "readonly": false, + "type": "{\n getChainName: (chainNamespace: string) => string | undefined;\n getChainNamespace: (chainName: string) => string | undefined;\n getSupportedChains: (network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK) => {\n chains: import(\"sdk/src/lib/constants/enums\").CHAIN[];\n };\n getSupportedChainsByName: (network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK) => {\n chains: string[];\n };\n}" + }, + "conversion": { + "optional": false, + "readonly": false, + "type": "{\n slippageToMinAmount(amount: string, options: {\n slippageBps: number;\n }): string;\n}" + }, + "helpers": { + "optional": false, + "readonly": false, + "type": "{\n encodeTxData({ abi, idl, functionName, args, }: {\n abi?: any;\n args?: any[];\n functionName: string;\n idl?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n }): `0x${string}`;\n formatUnits(value: bigint | string, decimalsOrOptions: {\n decimals: number;\n precision?: number;\n } | number): string;\n getChainName: (chainName: string) => string | undefined;\n parseUnits(value: string, exponent: {\n decimals: number;\n } | number): bigint;\n}" + }, + "signer": { + "optional": false, + "readonly": false, + "type": "{\n construct: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options: {\n signAndSendTransaction: (unsignedTx: Uint8Array) => Promise;\n signAuthorization?: (params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise;\n signMessage: (data: Uint8Array) => Promise;\n signTypedData?: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n }) => import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton;\n toUniversal: (signer: import(\"sdk/src/lib/universal/universal.types\").EthersV5SignerType | import(\"sdk/src/lib/universal/universal.types\").EthersV6SignerType | import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton | import(\"sdk/src/lib/universal/universal.types\").ViemSignerType) => Promise;\n toUniversalFromKeypair: (clientOrAccount: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@solana/web3.js/lib/index\").Keypair | import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").WalletClient | import(\"sdk/src/lib/universal/universal.types\").EthersV6SignerType, { chain, library }: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n library: import(\"sdk/src/lib/constants/enums\").LIBRARY;\n }) => Promise;\n}" + }, + "svm": { + "optional": false, + "readonly": false, + "type": "{\n getRegisteredIdls: () => Array<{\n address: `0x${string}`;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n }>;\n registerIdl: (idl: unknown) => void;\n}" + }, + "tokens": { + "optional": false, + "readonly": false, + "type": "{\n getMoveableTokens(chainOrClient?: import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/push-chain/push-chain\").PushChain): {\n tokens: Array<{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n decimals: number;\n mechanism: \"approve\" | \"native\" | \"permit2\";\n prc20Address?: `0x${string}`;\n sourceChain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n symbol: string;\n }>;\n };\n getPayableTokens(chainOrClient?: import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/push-chain/push-chain\").PushChain): {\n tokens: Array<{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n decimals: number;\n mechanism: \"approve\" | \"native\" | \"permit2\";\n symbol: string;\n }>;\n };\n getPC20Address(address: string, options: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n rpcUrls?: Partial>;\n strict?: boolean;\n }): Promise;\n getPRC20Address: (token: {\n address: string;\n chain: string;\n } | import(\"sdk/src/lib/constants/tokens\").MoveableToken, options?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n }) => {\n address: `0x${string}`;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n decimals: number;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n symbol: string;\n };\n}" + } + }, + "initialize": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise", + "agwConstants": { + "ENVELOPE_VERSION": { + "optional": false, + "readonly": false, + "type": "number" + }, + "FACTORY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "MAX_ALLOWED_CALLS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "MAX_PINS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "RULES_POLICY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + }, + "constants": { + "AGENTIC": { + "optional": false, + "readonly": false, + "type": "{\n readonly LOCALNET?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n readonly MAINNET?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n readonly TESTNET?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n readonly TESTNET_DONUT?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n}" + }, + "CHAIN": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "LIBRARY": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").LIBRARY" + }, + "MOVEABLE": { + "optional": false, + "readonly": false, + "type": "{\n TOKEN: import(\"sdk/src/lib/constants/tokens\").MoveableTokenConstantsMap;\n}" + }, + "PAYABLE": { + "optional": false, + "readonly": false, + "type": "{\n TOKEN: import(\"sdk/src/lib/constants/tokens\").PayableTokenConstantsMap;\n}" + }, + "PUSH_NETWORK": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "READ": { + "optional": false, + "readonly": false, + "type": "{\n readonly CALLBACK_BUDGET_BUFFER: 3;\n readonly CHAIN: {\n readonly WEB2: \"web2\";\n } & Readonly<{\n readonly ARBITRUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA;\n readonly BASE_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA;\n readonly BNB_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET;\n readonly ETHEREUM_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET;\n readonly ETHEREUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA;\n readonly PUSH_LOCALNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET;\n readonly PUSH_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET;\n readonly PUSH_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly PUSH_TESTNET_DONUT: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly SOLANA_DEVNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET;\n readonly SOLANA_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET;\n readonly SOLANA_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n readonly WEB2: \"web2\";\n }>;\n readonly DEFAULT_EXPIRY_BLOCKS: 300n;\n readonly ERROR_CODE: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n readonly MAX_CALLBACK_GAS_LIMIT: 1000000n;\n readonly MIN_CONFIRMATIONS_FLOOR: 1;\n readonly NAMESPACE: {\n readonly EVM: \"eip155\";\n readonly SVM: \"solana\";\n readonly WEB2: \"web2\";\n };\n readonly OUTCOME: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME;\n readonly REGISTRY_CALLBACK_GAS: 500000n;\n readonly RESULT_STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n readonly STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS;\n readonly UNIVERSAL_CALLBACK_ADDRESSES: Record;\n readonly UNIVERSAL_CORE_ADDRESSES: Record;\n readonly UNIVERSAL_READ_REGISTRY_ADDRESS: {\n readonly TESTNET_DONUT: \"0x00000000000000000000000000000000000000b2\";\n };\n readonly WEB2: \"web2\";\n readonly WEB2_DEFAULT_TIMEOUT_MS: 5000;\n readonly WEB2_MAX_EXTRACT_ENTRIES: 16;\n}" + } + } + }, + "scope": "All root exports and declared public members, PushChain static/instance members, universal transaction methods, utility groups, readonly/optional markers and constants. Behavior/default/deployment changes need the written session review." +} diff --git a/plan/agw/research/v5-implementation-2026-10-07/credential-scan.json b/plan/agw/research/v5-implementation-2026-10-07/credential-scan.json new file mode 100644 index 00000000..ba9eab8b --- /dev/null +++ b/plan/agw/research/v5-implementation-2026-10-07/credential-scan.json @@ -0,0 +1,4 @@ +{ + "scanned": 170, + "credentialMatches": [] +} diff --git a/plan/agw/research/v5-implementation-2026-10-07/live-evidence.jsonl b/plan/agw/research/v5-implementation-2026-10-07/live-evidence.jsonl new file mode 100644 index 00000000..de1d9251 --- /dev/null +++ b/plan/agw/research/v5-implementation-2026-10-07/live-evidence.jsonl @@ -0,0 +1,11 @@ +{"name": "v5-label-default-custom", "at": "2026-10-07T12:30:38.086Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallets": ["0x8915950eeaa7cd6c890c307a755157442fa0D248", "0x7951b49116c33321bdD600bd2C618bDD37D35f2F"], "indices": [0, 1], "hashes": ["0xc462c0784ab48fb563d686cd525d0700b6760b9cdf35f4d81a3b66e00ac55ef4", "0x80b5ccd5033880ee100278bdd347350250b59230002f1ca2ac28921ab49f00bc"]} +{"name": "v5-label-rename-reset", "at": "2026-10-07T12:31:11.346Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0xa0348fCC4e4a7932771836183A2e85cd04a18B02", "hashes": ["0x283884ab7ac614c566bf517613c98035d75746bf1e47ea5d72b1fc21bbcc7306", "0x018cf54fc627132377d4268f998a7d466079b0f43eabfb06e1802bd663f151ad"], "checkpointsBefore": "0", "checkpointsAfter": "2"} +{"name": "v5-label-byte-boundary", "at": "2026-10-07T12:31:32.321Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0x2aEA90A36ba5f0247cBaf8C0Ac71489B138a569A", "checkpoints": "1", "unchangedNextSlot": 4} +{"name": "v5-label-uea-owner", "at": "2026-10-07T12:32:21.339Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0x0619a84b55B9743Eb88b004246feA2D083a37F64", "owner": "0x5C70C864Cf1aDfB04A0e107fFA248ba3600EAb8D", "hashes": ["0x2d64e68ce50245ebc3ac556823f9f590210c0f602b0bb909d86a368e403624cd", "0x894de318d6d8ef12aaeae277d6c579b2944e18a95790c974ba71e9f1210c4fed", "0x0e982cc74e77e5ae0291df95e8a31294c4f3f7a168a9432405b442829cfbf8d6"], "checkpointsBefore": "0", "checkpointsAfter": "2"} +{"name": "v5-label-default-custom", "at": "2026-10-07T12:34:30.310Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallets": ["0x15Ce8553298cD0bd4A396C1c0f2f5c583d869a38", "0x218F609a52ee49CaBAD34b3550e0a50aB6199AE5"], "indices": [5, 6], "hashes": ["0x0154e6a32e3b531f7c8dad28e27f3c94ebb535f4f4563b6f8f100656ca5f31c5", "0xbb5c89ba1076d2931514876dd4bd21a697bf8088e42efb38ff6b8556ab010f82"]} +{"name": "v5-label-rename-reset", "at": "2026-10-07T12:35:08.263Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0x42b3217bE18A735e85dAb2A652c40ae54f640E14", "hashes": ["0x0b802fbd0e901d80857e768b0fa1f18775c0801671f6703e1217bf41337b8941", "0x3e3a4c0b0c7fb7cb8e95e9298f15dd993c44170939d07161f06ec3dc08505458"], "checkpointsBefore": "0", "checkpointsAfter": "2"} +{"name": "v5-label-byte-boundary", "at": "2026-10-07T12:35:31.973Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0x0A0FB68FF8dfeBf9efbd47105F200E5ecE0617ff", "checkpoints": "1", "unchangedNextSlot": 9} +{"name": "v5-label-uea-owner", "at": "2026-10-07T12:36:31.446Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0xCCed74226320b5fBf2a9C79f2E82738A11305a1A", "owner": "0x5C70C864Cf1aDfB04A0e107fFA248ba3600EAb8D", "hashes": ["0x2b3214a82327892cc3ad881fc4a6bddfed449bdccbacc7faf714326b61c94ce4", "0x732b9484496c61e12be8a3e1f217e60553223f132358814f5dd07cc19e1b4249", "0x1bf77a081a0275622a91748d27e23780cdf1abe445f06a1fe89700ebd5ff7752"], "checkpointsBefore": "0", "checkpointsAfter": "2"} +{"name": "native-agent-send", "at": "2026-10-07T12:37:07.483Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0x848D24fB43d19D7bf2384B8157A505a30bd0E3b2", "rulesId": "0xad49e1f5b6252d3d174404502c74414857d7f3398b63cfd784bec555b574b6ca", "tx": "0x55c842b0e18fb0030298d8c64c6a39ff160d95d8eefa6df6e0e1cd4de74e5cc2", "block": "23992536"} +{"name": "rules-update", "at": "2026-10-07T12:40:03.325Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0xDb9B9F16155080C519982a748844d60706bAD2AD", "original": "0x25fc2f28f58fe9ab0561e73b5ecc4a8e8054f0f2b059f63c414a7093e84bca4e", "replacement": "0x5d39e07ec12f83faf7a843f29d7dcaa55d0d77ce4a9ccf4659dec202ff6da692", "tx": "0x1e229372253e5199ae042e97c699ba4fb034599ce831188c8380cdb2c0d99d45", "checkpointDelta": 5} +{"name": "v5-label-agent-refused", "at": "2026-10-07T12:41:33.428Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0x01f79B99F1E369758d3A09b0A03962cab689D3De", "checkpoints": "1"} diff --git a/plan/agw/research/v5-implementation-2026-10-07/logs/actual-contracts.log b/plan/agw/research/v5-implementation-2026-10-07/logs/actual-contracts.log new file mode 100644 index 00000000..e64db0e9 --- /dev/null +++ b/plan/agw/research/v5-implementation-2026-10-07/logs/actual-contracts.log @@ -0,0 +1,30 @@ +PASS core-agw-local packages/core/__agw-local__/v5-multiasset.spec.ts (8.915 s) +PASS core-agw-local packages/core/__agw-local__/labels.spec.ts +PASS core-agw-local packages/core/__agw-local__/svm-backend.spec.ts (7.016 s) +PASS core-agw-local packages/core/__agw-local__/svm-public.spec.ts +PASS core-agw-local packages/core/__agw-local__/agw-local-advanced.spec.ts +PASS core-agw-local packages/core/__agw-local__/svm-differential.spec.ts + ● Console + + console.log + {"corpus":"svm-grant","seed":23063,"cases":107,"accepted":38,"rejected":69,"mismatches":[]} + + at Object. (__agw-local__/svm-differential.spec.ts:226:13) + + console.log + {"corpus":"svm-payload","seed":23063,"cases":88,"accepted":6,"rejected":82,"mismatches":[]} + + at Object. (__agw-local__/svm-differential.spec.ts:407:13) + +PASS core-agw-local packages/core/__agw-local__/agw-local-races.spec.ts +PASS core-agw-local packages/core/__agw-local__/delayed-index.spec.ts +PASS core-agw-local packages/core/__agw-local__/agw-local.spec.ts +PASS core-agw-local packages/core/__agw-local__/svm-internals.spec.ts +PASS core-agw-local packages/core/__agw-local__/agw-local-batch.spec.ts +PASS core-agw-local packages/core/__agw-local__/vectors.spec.ts + +Test Suites: 12 passed, 12 total +Tests: 90 passed, 90 total +Snapshots: 0 total +Time: 38.433 s +Ran all test suites. diff --git a/plan/agw/research/v5-implementation-2026-10-07/logs/api.log b/plan/agw/research/v5-implementation-2026-10-07/logs/api.log new file mode 100644 index 00000000..0b5c2eee --- /dev/null +++ b/plan/agw/research/v5-implementation-2026-10-07/logs/api.log @@ -0,0 +1 @@ +{"compiledMatchesSource":true,"addedExports":["DecodedSolanaRule","SolanaRule","SvmAccountRef","SvmFieldConstraint","SvmInstructionRule"],"removedExports":[],"changedAgwTypes":["AgenticError","AGENTIC_ERROR_CODE","NativeRule","AllowedCall","UniversalRule","RulesRecord","AgenticTxMetadata"],"publicTypeChanges":["AGENTIC_ERROR_CODE","AgenticError","AgenticErrorCode","AgenticNetworkConstants","AgenticTxMetadata","AllowedCall","NativeRule","SolanaRule","DecodedSolanaRule","SvmInstructionRule","SvmAccountRef","SvmFieldConstraint","Rule","RulesRecord","UniversalRule"],"transactionMethodChanges":[],"instanceMethodChanges":[],"initializeSignatureChanged":false,"agwConstantsChanged":true} diff --git a/plan/agw/research/v5-implementation-2026-10-07/logs/build.log b/plan/agw/research/v5-implementation-2026-10-07/logs/build.log new file mode 100644 index 00000000..55e0899d --- /dev/null +++ b/plan/agw/research/v5-implementation-2026-10-07/logs/build.log @@ -0,0 +1,11 @@ + +> nx run core:build + +Compiling TypeScript files for project "core"... +Done compiling TypeScript files for project "core". +(node:67452) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. +(Use `node --trace-warnings ...` to show where the warning was created) + + + + NX Successfully ran target build for project core diff --git a/plan/agw/research/v5-implementation-2026-10-07/logs/docs.log b/plan/agw/research/v5-implementation-2026-10-07/logs/docs.log new file mode 100644 index 00000000..8d1582db --- /dev/null +++ b/plan/agw/research/v5-implementation-2026-10-07/logs/docs.log @@ -0,0 +1 @@ +AGW guide: 10 TypeScript blocks typechecked against public exports; no examples executed. diff --git a/plan/agw/research/v5-implementation-2026-10-07/logs/e2e-default-manifest.log b/plan/agw/research/v5-implementation-2026-10-07/logs/e2e-default-manifest.log new file mode 100644 index 00000000..dfa5f250 --- /dev/null +++ b/plan/agw/research/v5-implementation-2026-10-07/logs/e2e-default-manifest.log @@ -0,0 +1,79 @@ +✓ smoke-uea-derive-evm 1 test +✓ smoke-read-track-lookup 1 test +✓ smoke-cea-derive-evm 1 test +✓ smoke-roundtrip-evm 1 test +✓ smoke-roundtrip-svm 1 test +✓ smoke-cea-pda-svm 1 test +✓ smoke-gasfee-reads 2 tests +✓ smoke-gas-sizer 2 tests +✓ smoke-pc20-registry 2 tests +✓ smoke-pc20-resolve 1 test +✓ evm-r1-transfer 1 test +✓ evm-r1-funds-usdt 1 test +✓ evm-r1-funds-native 1 test +✓ evm-r1-value-funds-data 1 test +✓ evm-r1-bridge-multicall 1 test +✓ evm-r1-fresh-value-native 1 test +✓ evm-r2-funds-erc20 1 test +✓ evm-r2-payload 1 test +✓ evm-r2-multicall 1 test +✓ evm-r2-funds-payload 1 test +✓ evm-r2-native-funds 1 test +✓ evm-r2-native-funds-payload 1 test +✓ evm-r3-funds-erc20 1 test +✓ evm-r3-payload 1 test +✓ evm-r3-multicall 1 test +✓ evm-r3-funds-payload 1 test +✓ evm-r3-native-funds 1 test +✓ evm-r3-eoa-native-funds 1 test +✓ svm-r1-transfer 1 test +✓ svm-r1-funds-sol-self 1 test +✓ svm-r1-value-self 1 test +✓ svm-r1-data-contract 1 test +✓ svm-r1-fresh-key-repro 1 test +✓ svm-r2-funds-sol 1 test +✓ svm-r2-funds-spl 1 test +✓ svm-r2-payload-cpi 1 test +✓ svm-r2-sol-cpi 1 test +✓ svm-r3-drain-sol 1 test +✓ svm-r3-drain-spl 1 test +✓ pc20-export-deployed-wrapper 1 test +✓ pc20-export-predicts-wrapper 1 test +✓ pc20-inbound-burn-unlock 1 test +✓ pc20-r3-cea-burn 1 test +✓ pc20-svm-r1-direct-burn 1 test +✓ pc20-svm-r3-cea-ata-burn 1 test +✓ push-send-transaction 1 test +✓ push-value-own-uea 1 test +✓ push-multicall-no-funds 1 test +✓ push-track-r1-sepolia-parity 1 test +✓ push-track-r3-funds-roundtrip 1 test +✓ push-track-source-leg-hashes 2 tests +✓ xc-multi-child-r3 1 test +✓ xc-fresh-wallet-r3 1 test +✓ xc-peth-bridge-back 1 test +✓ xc-cascade-6hop 1 test +✓ read-evm-balance-eoa 1 test +✓ read-canonical-registry 1 test +✓ read-evm-balance-uea 1 test +✓ read-evm-contract-call 1 test +✓ read-evm-callback-reverts 1 test +✓ read-expiry 1 test +✓ read-svm-lamports 1 test +✓ read-web2-json 1 test +✓ read-docs-example 1 test +✓ read-docs-evm-balance 1 test +✓ read-docs-batch 1 test +✓ read-docs-resume 2 tests +✓ read-app-batch-eoa 1 test +✓ read-app-batch-uea 1 test +✓ read-app-batch-recovery 1 test +✓ read-api-token 1 test +✓ read-api-mixed-outcomes 1 test +✓ read-svm-token-auto 1 test +✓ read-svm-idl 1 test +✓ read-evm-any-mutability 1 test +✓ read-svm-raw 1 test + +76 scenarios, 40 spec files, 81 distinct tests. +Manifest is consistent with the specs. diff --git a/plan/agw/research/v5-implementation-2026-10-07/logs/e2e-manifest.log b/plan/agw/research/v5-implementation-2026-10-07/logs/e2e-manifest.log new file mode 100644 index 00000000..1e6c5ee6 --- /dev/null +++ b/plan/agw/research/v5-implementation-2026-10-07/logs/e2e-manifest.log @@ -0,0 +1,56 @@ +✓ agw-create-bare 1 test +✓ agw-create-rules 1 test +✓ agw-funding-pc 1 test +✓ agw-funding-allowance 1 test +✓ agw-native-batch 1 test +✓ agw-native-batch-rollback 1 test +✓ agw-native-agent 1 test +✓ agw-native-owner 1 test +✓ agw-native-over-cap 1 test +✓ agw-native-stranger 1 test +✓ agw-native-revoked 1 test +✓ agw-native-expired 1 test +✓ agw-lifecycle-add 1 test +✓ agw-lifecycle-update 1 test +✓ agw-lifecycle-checkpoints 1 test +✓ agw-lifecycle-revoke-all 1 test +✓ agw-universal-outbound 1 test +✓ agw-v5-multi-asset 1 test +✓ agw-v5-call-only 1 test +✓ agw-universal-dest-revert 1 test +✓ agw-identity-evm 1 test +✓ agw-identity-first-use 1 test +✓ agw-identity-solana 1 test +✓ agw-responses-hooks 1 test +✓ agw-responses-replay 1 test +✓ agw-public-svm-1 1 test +✓ agw-public-svm-2 1 test +✓ agw-public-svm-3 1 test +✓ agw-public-svm-4 1 test +✓ agw-public-svm-5 1 test +✓ agw-public-svm-6 1 test +✓ agw-labels-1 1 test +✓ agw-labels-2 1 test +✓ agw-labels-3 1 test +✓ agw-labels-4 1 test +✓ agw-labels-5 1 test +✓ agw-extended-prefunding 1 test +✓ agw-extended-ambiguous-rules 1 test +✓ agw-extended-batched-lifecycle 1 test +✓ agw-extended-invalid-revoke 1 test +✓ agw-extended-stale-update 1 test +✓ agw-extended-index-race 1 test +✓ agw-extended-native-policy-1 1 test +✓ agw-extended-native-policy-2 1 test +✓ agw-extended-native-policy-3 1 test +✓ agw-extended-native-policy-4 1 test +✓ agw-extended-native-policy-5 1 test +✓ agw-extended-native-policy-6 1 test +✓ agw-extended-native-policy-7 1 test +✓ agw-extended-native-policy-8 1 test +✓ agw-extended-native-policy-9 1 test +✓ agw-extended-native-policy-10 1 test +✓ agw-extended-native-policy-11 1 test + +53 scenarios, 13 spec files, 53 distinct tests. +Manifest is consistent with the specs. diff --git a/plan/agw/research/v5-implementation-2026-10-07/logs/final-type-lib.log b/plan/agw/research/v5-implementation-2026-10-07/logs/final-type-lib.log new file mode 100644 index 00000000..e69de29b diff --git a/plan/agw/research/v5-implementation-2026-10-07/logs/final-type-spec.log b/plan/agw/research/v5-implementation-2026-10-07/logs/final-type-spec.log new file mode 100644 index 00000000..e69de29b diff --git a/plan/agw/research/v5-implementation-2026-10-07/logs/full-unit.log b/plan/agw/research/v5-implementation-2026-10-07/logs/full-unit.log new file mode 100644 index 00000000..0f4a9bab --- /dev/null +++ b/plan/agw/research/v5-implementation-2026-10-07/logs/full-unit.log @@ -0,0 +1,173 @@ +PASS core packages/core/src/lib/agentic/__tests__/labels.spec.ts (5.881 s) +PASS core packages/core/src/lib/universal/account/account.spec.ts + ● Console + + console.warn + [PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead. + + 207 | ): Promise { + 208 | if (!_convertOriginToExecutorWarned) { + > 209 | console.warn( + | ^ + 210 | '[PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead.' + 211 | ); + 212 | _convertOriginToExecutorWarned = true; + + at Object.convertOriginToExecutor (src/lib/universal/account/account.ts:209:13) + at Object. (src/lib/universal/account/account.spec.ts:80:52) + + console.warn + [PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead. + + 425 | ): Promise { + 426 | if (!options?._internal && !_convertExecutorToOriginWarned) { + > 427 | console.warn( + | ^ + 428 | '[PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead.' + 429 | ); + 430 | _convertExecutorToOriginWarned = true; + + at convertExecutorToOrigin (src/lib/universal/account/account.ts:427:13) + at Object. (src/lib/universal/account/account.spec.ts:106:38) + +PASS core packages/core/src/lib/agentic/__tests__/response-surface.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/block-results-client.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-tx-retry.spec.ts +PASS core packages/core/src/lib/push-client/push-client.archive-fallback.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-confirmation-gate.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-tracker.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/management.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/send.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-timeout-clamp.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r1-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r2-outbound-revert-flow.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/account-status.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/send-transaction-progress-hook.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/codec.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-idl.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-executor.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/reads-context.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-backend.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/web2-compat.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/signing-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/inbound-tracker-derivation.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-multichain.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-svm-confirmation.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/scenarios.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-svm-rent.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/chain-namespace.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/source-hash-resolution.spec.ts +PASS core packages/core/src/lib/universal/signer/signer.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/svm-rent.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/cascade.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/registry.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-emission.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r3-spec-strings.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-evm.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/read-tx-spec-strings.spec.ts +PASS core packages/core/src/lib/utils.spec.ts + ● Console + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:973:17) + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:977:17) + + console.log + 1.23 + + at Object. (src/lib/utils.spec.ts:982:17) + +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/rescue-svm-confirmation.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/inbound-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/context-helpers-tracker.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/gate.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/resolver.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-svm-r3.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/funds-only-burn-guard.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-composition.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/response-invariant.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/payload-builders.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/spec-builder.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/execute-standard-required-funds.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-detector.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-calculator.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/export.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/track-transaction-guard.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-params.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-usd-sizer.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gateway-uea-account.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/multichain-hooks.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/build-payload.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r2-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-request-recipient.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-builder-progress-hook.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-native-multicall.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg-svm.spec.ts +PASS core packages/core/src/lib/push-client/push-client.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-event-hook-bridge.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm-rent-pc20.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/public-surface.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/resolve.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/terminal-suppression.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-evm-r3-native-eoa.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/response-builder-push-revert.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/registry.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/abi-selectors.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/svm-account.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/revalidate-read.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/address-codec.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/result-decoder.spec.ts +PASS core packages/core/src/lib/constants/__tests__/token-constants.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm-log-index.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-svm.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-wire-fixture.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.chain-symbol.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/child-inbounds.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/auto-detect.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/__tests__/signing.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/normalize.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/normalize-address.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/ucallback-codec.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-quote.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/classify.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/validate.spec.ts +PASS core packages/core/src/lib/constants/__tests__/svm-gateway-idl.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-types.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/ix-encoder.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-web2.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-events.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/max-pc-for-gas.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.dynamic-gas.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.batch-gas.spec.ts +PASS core packages/core/src/lib/formatters.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/errors.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/budget.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/error-decoder.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/tracking.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-execute-order.spec.ts + +Test Suites: 1 skipped, 120 passed, 120 of 121 total +Tests: 12 skipped, 2010 passed, 2022 total +Snapshots: 0 total +Time: 34.949 s, estimated 35 s +Ran all test suites. diff --git a/plan/agw/research/v5-implementation-2026-10-07/logs/golden-check.log b/plan/agw/research/v5-implementation-2026-10-07/logs/golden-check.log new file mode 100644 index 00000000..ff14031d --- /dev/null +++ b/plan/agw/research/v5-implementation-2026-10-07/logs/golden-check.log @@ -0,0 +1,9 @@ +PASS core-agw-local packages/core/__agw-local__/vectors.spec.ts (6.446 s) + contract-generated AGW vectors (v5) + ✓ matches the committed fixture (or writes it) (650 ms) + +Test Suites: 1 passed, 1 total +Tests: 1 passed, 1 total +Snapshots: 0 total +Time: 6.484 s +Ran all test suites within paths "packages/core/__agw-local__/vectors.spec.ts". diff --git a/plan/agw/research/v5-implementation-2026-10-07/logs/lint.log b/plan/agw/research/v5-implementation-2026-10-07/logs/lint.log new file mode 100644 index 00000000..e385115d --- /dev/null +++ b/plan/agw/research/v5-implementation-2026-10-07/logs/lint.log @@ -0,0 +1,143 @@ + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__agw-local__/agw-local-advanced.spec.ts + 73:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 85:17 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 295:22 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 311:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 337:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 426:13 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__agw-local__/agw-local-batch.spec.ts + 45:16 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 91:37 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 92:46 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 99:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 127:16 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 144:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 151:16 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__agw-local__/agw-local-races.spec.ts + 54:20 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 99:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 117:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 145:20 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__agw-local__/agw-local.spec.ts + 47:17 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 48:17 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__agw-local__/delayed-index.spec.ts + 81:20 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 95:20 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 112:9 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 194:24 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 246:26 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 254:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__agw-local__/harness.ts + 234:16 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 253:16 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 262:17 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 400:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__agw-local__/labels.spec.ts + 108:20 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 133:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__agw-local__/svm-backend.spec.ts + 142:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 170:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 229:28 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 403:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 427:23 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 471:22 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 543:61 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__agw-local__/svm-differential.spec.ts + 74:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 212:20 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 265:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 384:20 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__agw-local__/svm-internals.spec.ts + 86:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 119:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 189:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__agw-local__/svm-public.spec.ts + 78:12 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 117:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 159:13 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 160:11 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 161:13 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 184:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 213:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 247:13 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 248:11 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 249:13 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 277:13 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 278:11 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 279:13 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 302:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 395:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 448:16 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 462:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 474:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 504:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__agw-local__/v5-multiasset.spec.ts + 12:10 warning 'createWallet' is defined but never used @typescript-eslint/no-unused-vars + 78:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 92:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 176:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 188:16 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 325:16 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 335:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 353:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__agw-local__/vectors.spec.ts + 56:7 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 57:7 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 98:7 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 207:25 warning '_a' is assigned a value but never used @typescript-eslint/no-unused-vars + 208:25 warning '_b' is assigned a value but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/agw/identity-gas.spec.ts + 112:16 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/agw/svm-public.spec.ts + 138:21 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 139:25 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 224:7 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 297:7 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 297:7 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/agw/universal-evm.spec.ts + 29:10 warning 'v5' is defined but never used @typescript-eslint/no-unused-vars + 43:17 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/agw/v5-multiasset.spec.ts + 18:17 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/codec.spec.ts + 379:21 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts + 2:17 warning 'PUSH_NETWORK' is defined but never used @typescript-eslint/no-unused-vars + 41:21 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/reads-context.spec.ts + 374:5 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/response-surface.spec.ts + 4:3 warning 'getAddress' is defined but never used @typescript-eslint/no-unused-vars + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts + 457:21 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/svm-wire-fixture.spec.ts + 41:50 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 46:45 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 50:45 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +✖ 95 problems (0 errors, 95 warnings) diff --git a/plan/agw/research/v5-implementation-2026-10-07/logs/live-acceptance-main.log b/plan/agw/research/v5-implementation-2026-10-07/logs/live-acceptance-main.log new file mode 100644 index 00000000..21d13932 --- /dev/null +++ b/plan/agw/research/v5-implementation-2026-10-07/logs/live-acceptance-main.log @@ -0,0 +1,44 @@ +FAIL core-e2e packages/core/__e2e__/agw/labels.spec.ts (172.119 s) + ● agw labels › 4. an agent cannot rename through either the SDK or the contract + + expect(received).rejects.toThrow(expected) + + Expected substring: "ForbiddenDispatchTarget" + Received message: "The contract function \"executeAsAgent\" reverted with the following signature: + 0x1c792c05· + Unable to decode signature \"0x1c792c05\" as it was not found on the provided ABI. + Make sure you are using the correct ABI and that the error exists on it. + You can look up the decoded signature here: https://openchain.xyz/signatures?query=0x1c792c05.·· + Contract Call: + address: 0xe5579a19Fbb5e23814c993b61f9787647C0ef724 + function: executeAsAgent(bytes32 rulesId, bytes32 mode, bytes executionCalldata) + args: (0xc14cf8098cdf3e85b71d1fab16e606608ea31e67d1a78a72eda939bd39e78d8b, 0x0000000000000000000000000000000000000000000000000000000000000000, 0xe5579a19fbb5e23814c993b61f9787647c0ef7240000000000000000000000000000000000000000000000000000000000000000bf5309690000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000661747461636b0000000000000000000000000000000000000000000000000000) + sender: 0xE28544d09E80004E68cfEE4C97Ce47664Af1D718· + Docs: https://viem.sh/docs/contract/decodeErrorResult + Version: viem@2.27.2" + + 157 | }) + 158 | ).rejects.toThrow('CallerIsNotOwner'); + > 159 | await expect( + | ^ + 160 | f.push.simulateContract({ + 161 | address: made.wallet, + 162 | abi: v5.abis.wallet, + + at getContractError (../../node_modules/viem/utils/errors/getContractError.ts:78:10) + at simulateContract (../../node_modules/viem/actions/public/simulateContract.ts:308:27) + at async Object. (__e2e__/agw/labels.spec.ts:159:5) + at Object.toThrow (../../node_modules/expect/build/index.js:218:22) + at Object. (__e2e__/agw/labels.spec.ts:175:15) + +PASS core-e2e packages/core/__e2e__/agw/native-exec.spec.ts (142.36 s) +PASS core-e2e packages/core/__e2e__/agw/lifecycle.spec.ts (84.523 s) + +Test Suites: 1 failed, 2 passed, 3 total +Tests: 1 failed, 14 passed, 15 total +Snapshots: 0 total +Time: 399.036 s +Ran all test suites within paths "packages/core/__e2e__/agw/labels.spec.ts", "packages/core/__e2e__/agw/native-exec.spec.ts", "packages/core/__e2e__/agw/lifecycle.spec.ts". +Jest did not exit one second after the test run has completed. + +'This usually means that there are asynchronous operations that weren't stopped in your tests. Consider running Jest with `--detectOpenHandles` to troubleshoot this issue. diff --git a/plan/agw/research/v5-implementation-2026-10-07/logs/live-agent-refusal.log b/plan/agw/research/v5-implementation-2026-10-07/logs/live-agent-refusal.log new file mode 100644 index 00000000..73007125 --- /dev/null +++ b/plan/agw/research/v5-implementation-2026-10-07/logs/live-agent-refusal.log @@ -0,0 +1,13 @@ +PASS core-e2e packages/core/__e2e__/agw/labels.spec.ts (27.098 s) + agw labels + ✓ 4. an agent cannot rename through either the SDK or the contract (17146 ms) + ○ skipped 1. default and custom deployment labels are stored and listed + ○ skipped 2. owner rename and empty reset update info/list, emit LabelSet and tick the owner door + ○ skipped 3. UTF-8 byte boundaries are accepted or rejected without changing wallet state + ○ skipped 5. an external EVM owner creates and renames through its UEA + +Test Suites: 1 passed, 1 total +Tests: 4 skipped, 1 passed, 5 total +Snapshots: 0 total +Time: 27.117 s, estimated 173 s +Ran all test suites within paths "packages/core/__e2e__/agw/labels.spec.ts". diff --git a/plan/agw/research/v5-implementation-2026-10-07/logs/live-labels-initial.log b/plan/agw/research/v5-implementation-2026-10-07/logs/live-labels-initial.log new file mode 100644 index 00000000..3a50a50c --- /dev/null +++ b/plan/agw/research/v5-implementation-2026-10-07/logs/live-labels-initial.log @@ -0,0 +1,29 @@ +FAIL core-e2e packages/core/__e2e__/agw/labels.spec.ts (149.394 s) + agw labels + ✓ 1. default and custom deployment labels are stored and listed (29006 ms) + ✓ 2. owner rename and empty reset update info/list, emit LabelSet and tick the owner door (33261 ms) + ✓ 3. UTF-8 byte boundaries are accepted or rejected without changing wallet state (20975 ms) + ✕ 4. an agent cannot rename through either the SDK or the contract (8338 ms) + ✓ 5. an external EVM owner creates and renames through its UEA (40675 ms) + + ● agw labels › 4. an agent cannot rename through either the SDK or the contract + + AgenticError: 0x330E269534acA1c0e0E735bba31124CDd16c1bD7 is neither the owner of 0x3fB84292fc6093F40008542dE3412581340D2feD nor the agent of an enabled rule + + 56 | const active = await readActiveRules(snap, generation, wallet); + 57 | if (!active.some((r) => r.agent === signerPushAccount)) { + > 58 | throw new AgenticError( + | ^ + 59 | AGENTIC_ERROR_CODE.NOT_OWNER_OR_AGENT, + 60 | `${signerPushAccount} is neither the owner of ${wallet} nor the agent of an enabled rule`, + 61 | { + + at resolveAgenticContext (src/lib/agentic/context.ts:58:13) + at async Function.createInstance (src/lib/push-chain/push-chain.ts:841:33) + at async Object. (__e2e__/agw/labels.spec.ts:66:19) + +Test Suites: 1 failed, 1 total +Tests: 1 failed, 4 passed, 5 total +Snapshots: 0 total +Time: 149.412 s +Ran all test suites within paths "packages/core/__e2e__/agw/labels.spec.ts". diff --git a/plan/agw/research/v5-implementation-2026-10-07/logs/package.log b/plan/agw/research/v5-implementation-2026-10-07/logs/package.log new file mode 100644 index 00000000..8e1b97e4 --- /dev/null +++ b/plan/agw/research/v5-implementation-2026-10-07/logs/package.log @@ -0,0 +1 @@ +AGW package: CJS/ESM imports, compiled declaration examples and npm contents pass. No examples executed/published. diff --git a/plan/agw/research/v5-implementation-2026-10-07/logs/type-lib.log b/plan/agw/research/v5-implementation-2026-10-07/logs/type-lib.log new file mode 100644 index 00000000..e69de29b diff --git a/plan/agw/research/v5-implementation-2026-10-07/logs/type-local.log b/plan/agw/research/v5-implementation-2026-10-07/logs/type-local.log new file mode 100644 index 00000000..e69de29b diff --git a/plan/agw/research/v5-implementation-2026-10-07/logs/type-spec.log b/plan/agw/research/v5-implementation-2026-10-07/logs/type-spec.log new file mode 100644 index 00000000..e69de29b diff --git a/plan/agw/source-manifest.json b/plan/agw/source-manifest.json index 2d3a634a..a84e12c0 100644 --- a/plan/agw/source-manifest.json +++ b/plan/agw/source-manifest.json @@ -1,6 +1,6 @@ { "schema_version": 1, - "snapshot_date": "2026-10-03", + "snapshot_date": "2026-10-07", "notes": "Page content preserved; known intra-export links normalized to local filenames. Comment threads excluded by Notion export. Null edit dates mean not observed. Original bundle retained.", "sources": [ { @@ -8,28 +8,28 @@ "page_id": "3e9188aea7f481c8b38ccba332b0afa2", "notion_url": "https://app.notion.com/p/pushprotocol/AGW-UniversalMarketplace-8183-UniversalEvaluator-3e9188aea7f481c8b38ccba332b0afa2", "local_file": "notion/overview.md", - "pulled_on": "2026-10-03", + "pulled_on": "2026-10-07", "observed_last_edited_date": "2026-10-01", "authority": "Supporting design", "sha256": "f2d7954e018324a937282ca190f397cc12a27973a07c891f3edfd6e89383c53e", "export_entry": "Private & Shared/AGW + UniversalMarketplace + 8183 + UniversalEvalu 3e9188aea7f481c8b38ccba332b0afa2.md", "raw_export_sha256": "99b727bd58cf588b2c766dc1b93eff402c47e918718b69c2a456b119ad43435b", - "archive": "notion/exports/20261003T075310278902Z/export-1.zip", - "pulled_at": "2026-10-03T07:53:10.278902+00:00" + "archive": "notion/exports/20261007T102718466408Z/export-1.zip", + "pulled_at": "2026-10-07T10:27:18.466408+00:00" }, { "title": "1 AGW Contract Changes", "page_id": "3e9188aea7f4813aa31fc95ceb4e684d", "notion_url": "https://app.notion.com/p/pushprotocol/1-AGW-Contract-Changes-nomenclature-standard-change-set-3e9188aea7f4813aa31fc95ceb4e684d", "local_file": "notion/1-agw-contract-changes.md", - "pulled_on": "2026-10-03", + "pulled_on": "2026-10-07", "observed_last_edited_date": "2026-10-02", "authority": "WIP contract target", "sha256": "f1301d8ff1cf370968b90a3d53037ece8fa4c6783c45a402f9be6998928e3631", "export_entry": "Private & Shared/AGW + UniversalMarketplace + 8183 + UniversalEvalu/1 AGW Contract Changes (nomenclature standard + ch 3e9188aea7f4813aa31fc95ceb4e684d.md", "raw_export_sha256": "f1301d8ff1cf370968b90a3d53037ece8fa4c6783c45a402f9be6998928e3631", - "archive": "notion/exports/20261003T075310278902Z/export-1.zip", - "pulled_at": "2026-10-03T07:53:10.278902+00:00", + "archive": "notion/exports/20261007T102718466408Z/export-1.zip", + "pulled_at": "2026-10-07T10:27:18.466408+00:00", "observed_last_edited_at": "2026-10-02T20:50:00+05:30" }, { @@ -37,112 +37,113 @@ "page_id": "3e9188aea7f48118b90ac9b267496295", "notion_url": "https://app.notion.com/p/pushprotocol/2-Universal-Marketplace-3e9188aea7f48118b90ac9b267496295", "local_file": "notion/2-universal-marketplace.md", - "pulled_on": "2026-10-03", + "pulled_on": "2026-10-07", "observed_last_edited_date": null, "authority": "Supporting WIP design", "sha256": "5ddfd9e8980faae9eec85e3959cc99edbb3b115565af289c5603a91df0b78d18", "export_entry": "Private & Shared/AGW + UniversalMarketplace + 8183 + UniversalEvalu/2 Universal Marketplace 3e9188aea7f48118b90ac9b267496295.md", "raw_export_sha256": "5ddfd9e8980faae9eec85e3959cc99edbb3b115565af289c5603a91df0b78d18", - "archive": "notion/exports/20261003T075310278902Z/export-1.zip", - "pulled_at": "2026-10-03T07:53:10.278902+00:00" + "archive": "notion/exports/20261007T102718466408Z/export-1.zip", + "pulled_at": "2026-10-07T10:27:18.466408+00:00" }, { "title": "3 ERC-8183 job kernel and hook", "page_id": "3e9188aea7f48188a838c3a740d8c858", "notion_url": "https://app.notion.com/p/pushprotocol/3-8183-job-kernel-and-hook-3e9188aea7f48188a838c3a740d8c858", "local_file": "notion/3-8183-job-kernel-and-hook.md", - "pulled_on": "2026-10-03", + "pulled_on": "2026-10-07", "observed_last_edited_date": null, "authority": "Supporting WIP design", "sha256": "3c805db465f2d39db8d34179ac1dd864db1abf7b1b3e93f38074fbf393093f90", "export_entry": "Private & Shared/AGW + UniversalMarketplace + 8183 + UniversalEvalu/3 8183 (job kernel and hook) 3e9188aea7f48188a838c3a740d8c858.md", "raw_export_sha256": "3c805db465f2d39db8d34179ac1dd864db1abf7b1b3e93f38074fbf393093f90", - "archive": "notion/exports/20261003T075310278902Z/export-1.zip", - "pulled_at": "2026-10-03T07:53:10.278902+00:00" + "archive": "notion/exports/20261007T102718466408Z/export-1.zip", + "pulled_at": "2026-10-07T10:27:18.466408+00:00" }, { "title": "4 Universal Evaluation", "page_id": "3e9188aea7f4817bb03ef4c78c883f8b", "notion_url": "https://app.notion.com/p/pushprotocol/4-Universal-Evaluation-3e9188aea7f4817bb03ef4c78c883f8b", "local_file": "notion/4-universal-evaluation.md", - "pulled_on": "2026-10-03", + "pulled_on": "2026-10-07", "observed_last_edited_date": null, "authority": "Supporting WIP design", "sha256": "a2f1c93a75b8631c9628c06f1be135fa0198f00f096a765ce808dd5e544b2d6f", "export_entry": "Private & Shared/AGW + UniversalMarketplace + 8183 + UniversalEvalu/4 Universal Evaluation 3e9188aea7f4817bb03ef4c78c883f8b.md", "raw_export_sha256": "a2f1c93a75b8631c9628c06f1be135fa0198f00f096a765ce808dd5e544b2d6f", - "archive": "notion/exports/20261003T075310278902Z/export-1.zip", - "pulled_at": "2026-10-03T07:53:10.278902+00:00" + "archive": "notion/exports/20261007T102718466408Z/export-1.zip", + "pulled_at": "2026-10-07T10:27:18.466408+00:00" }, { "title": "5 SDK AGW", "page_id": "3e9188aea7f481cf8e8de324956549b9", "notion_url": "https://app.notion.com/p/pushprotocol/5-SDK-AGW-3e9188aea7f481cf8e8de324956549b9", "local_file": "notion/5-sdk-agw.md", - "pulled_on": "2026-10-03", - "observed_last_edited_date": null, + "pulled_on": "2026-10-07", + "observed_last_edited_date": "2026-10-07", "authority": "Primary SDK API target", - "sha256": "e407ee77cdf874db7ef4697f84e9945ff3a12a2f2e07e8a7f90bd24e93ea32f1", + "sha256": "d3bc55b08a37d762c49173149fd8d554a8551682c0956de3e91394a54bfed9a6", "export_entry": "Private & Shared/AGW + UniversalMarketplace + 8183 + UniversalEvalu/5 SDK AGW 3e9188aea7f481cf8e8de324956549b9.md", - "raw_export_sha256": "9a16f8aed79fac09818ec216fb4c69dc79f2fa0cffe0af611af956eb0e69f33f", - "archive": "notion/exports/20261003T075310278902Z/export-1.zip", - "pulled_at": "2026-10-03T07:53:10.278902+00:00", - "previous_observed_last_edited_date": "2026-10-01" + "raw_export_sha256": "8d024eb2bd2955fc772d2194f50a02d601a2d5bf903b0c9cc74882ee11348130", + "archive": "notion/exports/20261007T102718466408Z/export-1.zip", + "pulled_at": "2026-10-07T10:27:18.466408+00:00", + "previous_observed_last_edited_date": "2026-10-01", + "observed_last_edited_ui": "Edited 2h ago (observed October 7)" }, { "title": "6 SDK Universal Marketplace", "page_id": "3ea188aea7f481e2961ed97129f3a4e6", "notion_url": "https://app.notion.com/p/pushprotocol/6-SDK-Universal-Marketplace-3ea188aea7f481e2961ed97129f3a4e6", "local_file": "notion/6-sdk-universal-marketplace.md", - "pulled_on": "2026-10-03", + "pulled_on": "2026-10-07", "observed_last_edited_date": "2026-09-30", "authority": "Supporting WIP SDK", "sha256": "e7298952f2ba9adb218b4ef0459b8fa696a2072167dc5f655060b69788cf528c", "export_entry": "Private & Shared/AGW + UniversalMarketplace + 8183 + UniversalEvalu/6 SDK Universal Marketplace 3ea188aea7f481e2961ed97129f3a4e6.md", "raw_export_sha256": "e7298952f2ba9adb218b4ef0459b8fa696a2072167dc5f655060b69788cf528c", - "archive": "notion/exports/20261003T075310278902Z/export-1.zip", - "pulled_at": "2026-10-03T07:53:10.278902+00:00" + "archive": "notion/exports/20261007T102718466408Z/export-1.zip", + "pulled_at": "2026-10-07T10:27:18.466408+00:00" }, { "title": "7 SDK ERC-8183 Job", "page_id": "3ea188aea7f481e0a137f5a896723376", "notion_url": "https://app.notion.com/p/pushprotocol/7-SDK-8183-Job-3ea188aea7f481e0a137f5a896723376", "local_file": "notion/7-sdk-8183-job.md", - "pulled_on": "2026-10-03", + "pulled_on": "2026-10-07", "observed_last_edited_date": null, "authority": "Supporting WIP SDK", "sha256": "dbf1ff539f5df944e5f5f55710f5f6d3359469a141038cec2604e7c33392752c", "export_entry": "Private & Shared/AGW + UniversalMarketplace + 8183 + UniversalEvalu/7 SDK 8183 Job 3ea188aea7f481e0a137f5a896723376.md", "raw_export_sha256": "dbf1ff539f5df944e5f5f55710f5f6d3359469a141038cec2604e7c33392752c", - "archive": "notion/exports/20261003T075310278902Z/export-1.zip", - "pulled_at": "2026-10-03T07:53:10.278902+00:00" + "archive": "notion/exports/20261007T102718466408Z/export-1.zip", + "pulled_at": "2026-10-07T10:27:18.466408+00:00" }, { "title": "8 SDK Universal Evaluation", "page_id": "3ea188aea7f48197a3b3cfdedfa74fee", "notion_url": "https://app.notion.com/p/pushprotocol/8-SDK-Universal-Evaluation-3ea188aea7f48197a3b3cfdedfa74fee", "local_file": "notion/8-sdk-universal-evaluation.md", - "pulled_on": "2026-10-03", + "pulled_on": "2026-10-07", "observed_last_edited_date": null, "authority": "Supporting WIP SDK", "sha256": "eb2e584bd76aeea06c0dd03b3c8802b2340acf955e1ea75bf7768ebf9d2ab34e", "export_entry": "Private & Shared/AGW + UniversalMarketplace + 8183 + UniversalEvalu/8 SDK Universal Evaluation 3ea188aea7f48197a3b3cfdedfa74fee.md", "raw_export_sha256": "eb2e584bd76aeea06c0dd03b3c8802b2340acf955e1ea75bf7768ebf9d2ab34e", - "archive": "notion/exports/20261003T075310278902Z/export-1.zip", - "pulled_at": "2026-10-03T07:53:10.278902+00:00" + "archive": "notion/exports/20261007T102718466408Z/export-1.zip", + "pulled_at": "2026-10-07T10:27:18.466408+00:00" }, { "title": "Legacy PUSH AGW SDK Doc v1", "page_id": "d2d188aea7f4825cbcea81ef86eca607", "notion_url": "https://app.notion.com/p/pushprotocol/PUSH-AGW-SDK-Doc-v1-d2d188aea7f4825cbcea81ef86eca607", "local_file": "notion/legacy-agw-sdk-v1.md", - "pulled_on": "2026-10-03", + "pulled_on": "2026-10-07", "observed_last_edited_date": "2026-09-22", "authority": "Historical encoding and deployment reference", "sha256": "9e6569ef9b76d59cb411d65305d67333c6766abc2e9c80a35ae6f56f12f70916", "raw_export_sha256": "9e6569ef9b76d59cb411d65305d67333c6766abc2e9c80a35ae6f56f12f70916", - "pulled_at": "2026-10-03T07:53:10.278902+00:00", - "archive": "notion/exports/20261003T075310278902Z/export-2.zip", + "pulled_at": "2026-10-07T10:27:18.466408+00:00", + "archive": "notion/exports/20261007T102718466408Z/export-2.zip", "export_entry": "Private & Shared/PUSH AGW SDK Doc - v1 d2d188aea7f4825cbcea81ef86eca607.md" }, { @@ -150,13 +151,13 @@ "page_id": "3d1188aea7f480ddbb4af6d0efb211e6", "notion_url": "https://app.notion.com/p/pushprotocol/AGW-Address-Book-PC-Donut-3d1188aea7f480ddbb4af6d0efb211e6", "local_file": "notion/agw-address-book-donut-2026-09-04.md", - "pulled_on": "2026-10-03", + "pulled_on": "2026-10-07", "observed_last_edited_date": "2026-09-04", "authority": "Historical deployment", "sha256": "5c5017d6b4a58af0fa8854ef550b054c1f33d57a812ea51a16f31f7c33e79742", "raw_export_sha256": "5c5017d6b4a58af0fa8854ef550b054c1f33d57a812ea51a16f31f7c33e79742", - "pulled_at": "2026-10-03T07:53:10.278902+00:00", - "archive": "notion/exports/20261003T075310278902Z/export-3.zip", + "pulled_at": "2026-10-07T10:27:18.466408+00:00", + "archive": "notion/exports/20261007T102718466408Z/export-3.zip", "export_entry": "Private & Shared/AGW Address Book - PC Donut 3d1188aea7f480ddbb4af6d0efb211e6.md" }, { @@ -164,15 +165,15 @@ "page_id": "3d1188aea7f4801f9cb3fbd9318ec536", "notion_url": "https://app.notion.com/p/pushprotocol/agentic_wallet_flow-updated-3d1188aea7f4801f9cb3fbd9318ec536", "local_file": "notion/agentic-wallet-flow-2026-09-07.md", - "pulled_on": "2026-10-03", + "pulled_on": "2026-10-07", "observed_last_edited_date": "2026-09-07", "authority": "Historical validator-based flow", "sha256": "d4a922fd1d33da5a7042f26053e8df0e496c3ccd4cb0044b0892948ac509c3a0", "raw_export_sha256": "d4a922fd1d33da5a7042f26053e8df0e496c3ccd4cb0044b0892948ac509c3a0", - "pulled_at": "2026-10-03T07:53:10.278902+00:00", - "archive": "notion/exports/20261003T075310278902Z/export-4.zip", + "pulled_at": "2026-10-07T10:27:18.466408+00:00", + "archive": "notion/exports/20261007T102718466408Z/export-4.zip", "export_entry": "Private & Shared/agentic_wallet_flow ( updated ) 3d1188aea7f4801f9cb3fbd9318ec536.md" } ], - "last_refresh_at": "2026-10-03T07:53:10.278902+00:00" + "last_refresh_at": "2026-10-07T10:27:18.466408+00:00" } From cc72c64d28d29145a5af8d152ee1556fc4836d52 Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Wed, 7 Oct 2026 20:31:56 +0530 Subject: [PATCH 32/68] feat(core): add AGW v5 wallet and rules SDK Add wallet creation, labels and rules management, owner and agent execution, and EVM/Solana destination composition and tracking. Include independent token budgets, SPL source-mint resolution, raw-offset rule support and the READ.CHAIN.WEB2 alias. Keep runtime bindings, consumer documentation, ABI snapshots, local-contract tests, opt-in funded E2Es and validation scripts together. Align CI with the deployed v5 source. Exclude all planning-folder changes. --- .github/workflows/agw-sdk-validation.yml | 45 + .github/workflows/e2e.yml | 1 + .gitignore | 3 + packages/core/.eslintrc.json | 3 + packages/core/AGW.md | 366 +++ packages/core/README.md | 2 + .../__agw-local__/agw-local-advanced.spec.ts | 610 +++++ .../__agw-local__/agw-local-batch.spec.ts | 154 ++ .../__agw-local__/agw-local-races.spec.ts | 166 ++ packages/core/__agw-local__/agw-local.spec.ts | 447 ++++ .../core/__agw-local__/delayed-index.spec.ts | 257 ++ packages/core/__agw-local__/harness.ts | 444 ++++ packages/core/__agw-local__/labels.spec.ts | 141 ++ packages/core/__agw-local__/setup.ts | 18 + .../core/__agw-local__/svm-backend.spec.ts | 549 +++++ .../__agw-local__/svm-differential.spec.ts | 418 ++++ .../core/__agw-local__/svm-internals.spec.ts | 328 +++ .../core/__agw-local__/svm-public.spec.ts | 528 ++++ .../core/__agw-local__/v5-multiasset.spec.ts | 367 +++ packages/core/__agw-local__/vectors.spec.ts | 220 ++ .../__e2e__/agw-svm-wire/outbound.spec.ts | 174 ++ .../core/__e2e__/agw-svm-wire/replay.spec.ts | 59 + packages/core/__e2e__/agw/_fixture.ts | 138 ++ packages/core/__e2e__/agw/_manifest.ts | 203 ++ packages/core/__e2e__/agw/create.spec.ts | 87 + .../__e2e__/agw/funding-allowance.spec.ts | 47 + .../core/__e2e__/agw/identity-gas.spec.ts | 164 ++ packages/core/__e2e__/agw/labels.spec.ts | 461 ++++ packages/core/__e2e__/agw/lifecycle.spec.ts | 127 + .../__e2e__/agw/management-extended.spec.ts | 283 +++ .../core/__e2e__/agw/native-batch.spec.ts | 99 + packages/core/__e2e__/agw/native-exec.spec.ts | 101 + .../agw/native-policy-extended.spec.ts | 277 +++ .../core/__e2e__/agw/responses-hooks.spec.ts | 51 + packages/core/__e2e__/agw/svm-public.spec.ts | 445 ++++ .../core/__e2e__/agw/svm-spl-transfer.spec.ts | 224 ++ .../core/__e2e__/agw/universal-evm.spec.ts | 244 ++ .../core/__e2e__/agw/v5-multiasset.spec.ts | 344 +++ packages/core/__e2e__/ci/agw-svm-preflight.ts | 30 + packages/core/__e2e__/ci/preflight.ts | 36 +- packages/core/__e2e__/ci/run.ts | 50 +- packages/core/__e2e__/ci/suite.ts | 389 ++- packages/core/__e2e__/shared/agw-state.ts | 31 + .../__e2e__/shared/agw-svm-policy-probe.ts | 34 + .../core/__e2e__/shared/agw-svm-preflight.ts | 73 + packages/core/jest.agw-local.config.ts | 23 + packages/core/package.json | 6 + .../core/scripts/agw-local/abis/engine.json | 1957 +++++++++++++++ .../core/scripts/agw-local/abis/factory.json | 1105 +++++++++ .../core/scripts/agw-local/abis/manifest.json | 12 + .../core/scripts/agw-local/abis/policy.json | 2157 +++++++++++++++++ .../scripts/agw-local/abis/validator.json | 141 ++ .../core/scripts/agw-local/abis/wallet.json | 1606 ++++++++++++ .../agw-local/contracts/HarnessFixtures.sol | 197 ++ packages/core/scripts/agw-local/gen-abi.mjs | 72 + packages/core/scripts/agw-local/prepare.sh | 48 + packages/core/scripts/agw-verify.js | 74 + packages/core/scripts/check-agw-api.js | 424 ++++ packages/core/scripts/check-agw-docs.js | 50 + packages/core/scripts/check-agw-package.js | 74 + packages/core/scripts/check-agw-runtimes.js | 93 + .../lib/agentic/__fixtures__/v5-vectors.json | 181 ++ .../src/lib/agentic/__tests__/codec.spec.ts | 444 ++++ .../src/lib/agentic/__tests__/fake-chain.ts | 415 ++++ .../src/lib/agentic/__tests__/labels.spec.ts | 115 + .../lib/agentic/__tests__/management.spec.ts | 685 ++++++ .../src/lib/agentic/__tests__/mock-runtime.ts | 102 + .../__tests__/native-batch-response.spec.ts | 119 + .../__tests__/outbound-response.spec.ts | 300 +++ .../agentic/__tests__/reads-context.spec.ts | 548 +++++ .../__tests__/response-surface.spec.ts | 254 ++ .../agentic/__tests__/rules-policy.spec.ts | 348 +++ .../src/lib/agentic/__tests__/send.spec.ts | 680 ++++++ .../lib/agentic/__tests__/svm-backend.spec.ts | 323 +++ .../src/lib/agentic/__tests__/svm-idl.spec.ts | 177 ++ .../agentic/__tests__/svm-internals.spec.ts | 502 ++++ .../lib/agentic/__tests__/svm-quote.spec.ts | 251 ++ .../__tests__/svm-wire-fixture.spec.ts | 59 + packages/core/src/lib/agentic/agentic.ts | 49 + .../core/src/lib/agentic/agentic.types.ts | 281 +++ packages/core/src/lib/agentic/capabilities.ts | 79 + packages/core/src/lib/agentic/chain.ts | 13 + .../core/src/lib/agentic/codec/abi-layout.ts | 139 ++ .../core/src/lib/agentic/codec/defaults.ts | 59 + packages/core/src/lib/agentic/codec/ids.ts | 112 + packages/core/src/lib/agentic/codec/native.ts | 278 +++ packages/core/src/lib/agentic/codec/rules.ts | 198 ++ .../core/src/lib/agentic/codec/selectors.ts | 77 + .../core/src/lib/agentic/codec/session.ts | 116 + .../src/lib/agentic/codec/svm-accounts.ts | 104 + .../core/src/lib/agentic/codec/svm-idl.ts | 269 ++ .../core/src/lib/agentic/codec/svm-terms.ts | 303 +++ .../src/lib/agentic/codec/universal-terms.ts | 60 + .../core/src/lib/agentic/codec/universal.ts | 214 ++ packages/core/src/lib/agentic/constants.ts | 23 + packages/core/src/lib/agentic/context.ts | 78 + .../contracts/abi/v5/agent-validator.ts | 145 ++ .../agentic/contracts/abi/v5/agw-factory.ts | 1104 +++++++++ .../src/lib/agentic/contracts/abi/v5/agw.ts | 1584 ++++++++++++ .../src/lib/agentic/contracts/abi/v5/index.ts | 8 + .../agentic/contracts/abi/v5/smart-session.ts | 1961 +++++++++++++++ .../abi/v5/universal-rules-policy.ts | 2156 ++++++++++++++++ .../src/lib/agentic/contracts/donut-v5.ts | 13 + .../lib/agentic/contracts/prc20-metadata.ts | 128 + .../core/src/lib/agentic/contracts/reader.ts | 42 + packages/core/src/lib/agentic/contracts/v5.ts | 422 ++++ packages/core/src/lib/agentic/deployments.ts | 299 +++ packages/core/src/lib/agentic/errors.ts | 124 + .../core/src/lib/agentic/execution/guards.ts | 46 + .../src/lib/agentic/execution/outbound.ts | 263 ++ .../core/src/lib/agentic/execution/send.ts | 401 +++ .../lib/agentic/execution/svm-instruction.ts | 67 + .../src/lib/agentic/execution/svm-outbound.ts | 102 + .../src/lib/agentic/execution/svm-payload.ts | 146 ++ .../src/lib/agentic/execution/svm-public.ts | 278 +++ .../src/lib/agentic/execution/svm-quote.ts | 51 + .../src/lib/agentic/execution/svm-send.ts | 178 ++ packages/core/src/lib/agentic/index.ts | 33 + .../core/src/lib/agentic/management/common.ts | 145 ++ .../core/src/lib/agentic/management/create.ts | 403 +++ .../core/src/lib/agentic/management/label.ts | 21 + .../src/lib/agentic/management/prepare.ts | 144 ++ .../src/lib/agentic/management/rules-write.ts | 451 ++++ .../src/lib/agentic/management/svm-context.ts | 115 + .../lib/agentic/management/svm-metadata.ts | 75 + .../src/lib/agentic/management/svm-public.ts | 121 + .../core/src/lib/agentic/management/svm.ts | 254 ++ .../core/src/lib/agentic/reads/checkpoints.ts | 85 + packages/core/src/lib/agentic/reads/rules.ts | 398 +++ .../core/src/lib/agentic/reads/snapshot.ts | 112 + packages/core/src/lib/agentic/reads/svm.ts | 98 + .../core/src/lib/agentic/reads/wallets.ts | 198 ++ packages/core/src/lib/agentic/response.ts | 432 ++++ packages/core/src/lib/agentic/revert.ts | 131 + packages/core/src/lib/agentic/runtime.ts | 176 ++ packages/core/src/lib/agentic/utils.ts | 249 ++ packages/core/src/lib/agentic/wallet.ts | 196 ++ packages/core/src/lib/constants/enums.ts | 9 +- packages/core/src/lib/constants/index.ts | 20 +- packages/core/src/lib/constants/read-state.ts | 13 + packages/core/src/lib/index.ts | 45 + .../outbound-svm-confirmation.spec.ts | 127 + .../push-chain-native-multicall.spec.ts | 44 + .../src/lib/orchestrator/internals/errors.ts | 13 +- .../internals/execute-standard.ts | 7 +- .../orchestrator/internals/outbound-sync.ts | 69 +- .../orchestrator/internals/push-chain-tx.ts | 17 +- .../core/src/lib/orchestrator/orchestrator.ts | 23 +- .../lib/orchestrator/orchestrator.types.ts | 9 + .../src/lib/orchestrator/route-detector.ts | 5 +- .../src/lib/orchestrator/svm-idl/resolve.ts | 16 +- .../__tests__/response-invariant.spec.ts | 9 + .../src/lib/progress-hook/progress-hook.ts | 75 + .../lib/progress-hook/progress-hook.types.ts | 21 + .../core/src/lib/push-chain/push-chain.ts | 130 +- .../__tests__/public-surface.spec.ts | 10 +- .../read-state/__tests__/web2-compat.spec.ts | 69 + .../core/src/lib/read-state/destination.ts | 8 +- .../core/src/lib/read-state/read-params.ts | 13 +- .../src/lib/read-state/read-state.types.ts | 4 +- .../core/src/lib/read-state/read-tracker.ts | 6 +- .../core/src/lib/read-state/spec-builder.ts | 4 +- .../core/src/lib/universal/prc20-address.ts | 168 ++ packages/core/src/lib/utils.ts | 187 +- .../vm-client/evm-client.batch-gas.spec.ts | 75 + .../vm-client/evm-client.dynamic-gas.spec.ts | 51 +- packages/core/src/lib/vm-client/evm-client.ts | 44 +- packages/core/tsconfig.agw-local.json | 9 + 168 files changed, 39570 insertions(+), 317 deletions(-) create mode 100644 .github/workflows/agw-sdk-validation.yml create mode 100644 packages/core/AGW.md create mode 100644 packages/core/__agw-local__/agw-local-advanced.spec.ts create mode 100644 packages/core/__agw-local__/agw-local-batch.spec.ts create mode 100644 packages/core/__agw-local__/agw-local-races.spec.ts create mode 100644 packages/core/__agw-local__/agw-local.spec.ts create mode 100644 packages/core/__agw-local__/delayed-index.spec.ts create mode 100644 packages/core/__agw-local__/harness.ts create mode 100644 packages/core/__agw-local__/labels.spec.ts create mode 100644 packages/core/__agw-local__/setup.ts create mode 100644 packages/core/__agw-local__/svm-backend.spec.ts create mode 100644 packages/core/__agw-local__/svm-differential.spec.ts create mode 100644 packages/core/__agw-local__/svm-internals.spec.ts create mode 100644 packages/core/__agw-local__/svm-public.spec.ts create mode 100644 packages/core/__agw-local__/v5-multiasset.spec.ts create mode 100644 packages/core/__agw-local__/vectors.spec.ts create mode 100644 packages/core/__e2e__/agw-svm-wire/outbound.spec.ts create mode 100644 packages/core/__e2e__/agw-svm-wire/replay.spec.ts create mode 100644 packages/core/__e2e__/agw/_fixture.ts create mode 100644 packages/core/__e2e__/agw/_manifest.ts create mode 100644 packages/core/__e2e__/agw/create.spec.ts create mode 100644 packages/core/__e2e__/agw/funding-allowance.spec.ts create mode 100644 packages/core/__e2e__/agw/identity-gas.spec.ts create mode 100644 packages/core/__e2e__/agw/labels.spec.ts create mode 100644 packages/core/__e2e__/agw/lifecycle.spec.ts create mode 100644 packages/core/__e2e__/agw/management-extended.spec.ts create mode 100644 packages/core/__e2e__/agw/native-batch.spec.ts create mode 100644 packages/core/__e2e__/agw/native-exec.spec.ts create mode 100644 packages/core/__e2e__/agw/native-policy-extended.spec.ts create mode 100644 packages/core/__e2e__/agw/responses-hooks.spec.ts create mode 100644 packages/core/__e2e__/agw/svm-public.spec.ts create mode 100644 packages/core/__e2e__/agw/svm-spl-transfer.spec.ts create mode 100644 packages/core/__e2e__/agw/universal-evm.spec.ts create mode 100644 packages/core/__e2e__/agw/v5-multiasset.spec.ts create mode 100644 packages/core/__e2e__/ci/agw-svm-preflight.ts create mode 100644 packages/core/__e2e__/shared/agw-state.ts create mode 100644 packages/core/__e2e__/shared/agw-svm-policy-probe.ts create mode 100644 packages/core/__e2e__/shared/agw-svm-preflight.ts create mode 100644 packages/core/jest.agw-local.config.ts create mode 100644 packages/core/scripts/agw-local/abis/engine.json create mode 100644 packages/core/scripts/agw-local/abis/factory.json create mode 100644 packages/core/scripts/agw-local/abis/manifest.json create mode 100644 packages/core/scripts/agw-local/abis/policy.json create mode 100644 packages/core/scripts/agw-local/abis/validator.json create mode 100644 packages/core/scripts/agw-local/abis/wallet.json create mode 100644 packages/core/scripts/agw-local/contracts/HarnessFixtures.sol create mode 100644 packages/core/scripts/agw-local/gen-abi.mjs create mode 100755 packages/core/scripts/agw-local/prepare.sh create mode 100644 packages/core/scripts/agw-verify.js create mode 100644 packages/core/scripts/check-agw-api.js create mode 100644 packages/core/scripts/check-agw-docs.js create mode 100644 packages/core/scripts/check-agw-package.js create mode 100644 packages/core/scripts/check-agw-runtimes.js create mode 100644 packages/core/src/lib/agentic/__fixtures__/v5-vectors.json create mode 100644 packages/core/src/lib/agentic/__tests__/codec.spec.ts create mode 100644 packages/core/src/lib/agentic/__tests__/fake-chain.ts create mode 100644 packages/core/src/lib/agentic/__tests__/labels.spec.ts create mode 100644 packages/core/src/lib/agentic/__tests__/management.spec.ts create mode 100644 packages/core/src/lib/agentic/__tests__/mock-runtime.ts create mode 100644 packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts create mode 100644 packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts create mode 100644 packages/core/src/lib/agentic/__tests__/reads-context.spec.ts create mode 100644 packages/core/src/lib/agentic/__tests__/response-surface.spec.ts create mode 100644 packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts create mode 100644 packages/core/src/lib/agentic/__tests__/send.spec.ts create mode 100644 packages/core/src/lib/agentic/__tests__/svm-backend.spec.ts create mode 100644 packages/core/src/lib/agentic/__tests__/svm-idl.spec.ts create mode 100644 packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts create mode 100644 packages/core/src/lib/agentic/__tests__/svm-quote.spec.ts create mode 100644 packages/core/src/lib/agentic/__tests__/svm-wire-fixture.spec.ts create mode 100644 packages/core/src/lib/agentic/agentic.ts create mode 100644 packages/core/src/lib/agentic/agentic.types.ts create mode 100644 packages/core/src/lib/agentic/capabilities.ts create mode 100644 packages/core/src/lib/agentic/chain.ts create mode 100644 packages/core/src/lib/agentic/codec/abi-layout.ts create mode 100644 packages/core/src/lib/agentic/codec/defaults.ts create mode 100644 packages/core/src/lib/agentic/codec/ids.ts create mode 100644 packages/core/src/lib/agentic/codec/native.ts create mode 100644 packages/core/src/lib/agentic/codec/rules.ts create mode 100644 packages/core/src/lib/agentic/codec/selectors.ts create mode 100644 packages/core/src/lib/agentic/codec/session.ts create mode 100644 packages/core/src/lib/agentic/codec/svm-accounts.ts create mode 100644 packages/core/src/lib/agentic/codec/svm-idl.ts create mode 100644 packages/core/src/lib/agentic/codec/svm-terms.ts create mode 100644 packages/core/src/lib/agentic/codec/universal-terms.ts create mode 100644 packages/core/src/lib/agentic/codec/universal.ts create mode 100644 packages/core/src/lib/agentic/constants.ts create mode 100644 packages/core/src/lib/agentic/context.ts create mode 100644 packages/core/src/lib/agentic/contracts/abi/v5/agent-validator.ts create mode 100644 packages/core/src/lib/agentic/contracts/abi/v5/agw-factory.ts create mode 100644 packages/core/src/lib/agentic/contracts/abi/v5/agw.ts create mode 100644 packages/core/src/lib/agentic/contracts/abi/v5/index.ts create mode 100644 packages/core/src/lib/agentic/contracts/abi/v5/smart-session.ts create mode 100644 packages/core/src/lib/agentic/contracts/abi/v5/universal-rules-policy.ts create mode 100644 packages/core/src/lib/agentic/contracts/donut-v5.ts create mode 100644 packages/core/src/lib/agentic/contracts/prc20-metadata.ts create mode 100644 packages/core/src/lib/agentic/contracts/reader.ts create mode 100644 packages/core/src/lib/agentic/contracts/v5.ts create mode 100644 packages/core/src/lib/agentic/deployments.ts create mode 100644 packages/core/src/lib/agentic/errors.ts create mode 100644 packages/core/src/lib/agentic/execution/guards.ts create mode 100644 packages/core/src/lib/agentic/execution/outbound.ts create mode 100644 packages/core/src/lib/agentic/execution/send.ts create mode 100644 packages/core/src/lib/agentic/execution/svm-instruction.ts create mode 100644 packages/core/src/lib/agentic/execution/svm-outbound.ts create mode 100644 packages/core/src/lib/agentic/execution/svm-payload.ts create mode 100644 packages/core/src/lib/agentic/execution/svm-public.ts create mode 100644 packages/core/src/lib/agentic/execution/svm-quote.ts create mode 100644 packages/core/src/lib/agentic/execution/svm-send.ts create mode 100644 packages/core/src/lib/agentic/index.ts create mode 100644 packages/core/src/lib/agentic/management/common.ts create mode 100644 packages/core/src/lib/agentic/management/create.ts create mode 100644 packages/core/src/lib/agentic/management/label.ts create mode 100644 packages/core/src/lib/agentic/management/prepare.ts create mode 100644 packages/core/src/lib/agentic/management/rules-write.ts create mode 100644 packages/core/src/lib/agentic/management/svm-context.ts create mode 100644 packages/core/src/lib/agentic/management/svm-metadata.ts create mode 100644 packages/core/src/lib/agentic/management/svm-public.ts create mode 100644 packages/core/src/lib/agentic/management/svm.ts create mode 100644 packages/core/src/lib/agentic/reads/checkpoints.ts create mode 100644 packages/core/src/lib/agentic/reads/rules.ts create mode 100644 packages/core/src/lib/agentic/reads/snapshot.ts create mode 100644 packages/core/src/lib/agentic/reads/svm.ts create mode 100644 packages/core/src/lib/agentic/reads/wallets.ts create mode 100644 packages/core/src/lib/agentic/response.ts create mode 100644 packages/core/src/lib/agentic/revert.ts create mode 100644 packages/core/src/lib/agentic/runtime.ts create mode 100644 packages/core/src/lib/agentic/utils.ts create mode 100644 packages/core/src/lib/agentic/wallet.ts create mode 100644 packages/core/src/lib/orchestrator/__tests__/outbound-svm-confirmation.spec.ts create mode 100644 packages/core/src/lib/read-state/__tests__/web2-compat.spec.ts create mode 100644 packages/core/src/lib/universal/prc20-address.ts create mode 100644 packages/core/src/lib/vm-client/evm-client.batch-gas.spec.ts create mode 100644 packages/core/tsconfig.agw-local.json diff --git a/.github/workflows/agw-sdk-validation.yml b/.github/workflows/agw-sdk-validation.yml new file mode 100644 index 00000000..af1d14ef --- /dev/null +++ b/.github/workflows/agw-sdk-validation.yml @@ -0,0 +1,45 @@ +name: AGW SDK validation (unfunded) +on: + pull_request: + paths: ['packages/core/**', 'tsconfig.base.json', 'yarn.lock', '.github/workflows/agw-sdk-validation.yml'] + workflow_dispatch: +permissions: + contents: read +concurrency: + group: agw-validation-${{ github.ref }} + cancel-in-progress: true +jobs: + validate: + runs-on: ubuntu-latest + timeout-minutes: 30 + env: + NX_DAEMON: 'false' + AGW_REPO: ${{ github.workspace }}/.ci-contracts + AGW_LOCAL_DIR: ${{ runner.temp }}/agw-v5-build + steps: + - uses: actions/checkout@v5 + with: + persist-credentials: false + - uses: actions/checkout@v5 + with: + repository: pushchain/push-agentic-wallets + ref: 2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb + path: .ci-contracts + persist-credentials: false + - uses: actions/setup-node@v6 + with: + node-version: '24.18.0' + package-manager-cache: false + - uses: foundry-rs/foundry-toolchain@v1 + with: + version: v1.5.1 + - run: corepack enable + - run: yarn install --immutable + - name: Unit, contracts, types, docs and package checks + run: node packages/core/scripts/agw-verify.js + - uses: actions/upload-artifact@v4 + if: always() + with: + name: agw-unfunded-validation + path: .agw-validation/ + if-no-files-found: ignore diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index a4794fe4..e4e2eee7 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -25,6 +25,7 @@ on: - cross-chain - read - known-fail + - agw dry_run: description: 'Pre-flight only — report balances, fund nothing, run no tests' required: true diff --git a/.gitignore b/.gitignore index 20499081..a3622c68 100644 --- a/.gitignore +++ b/.gitignore @@ -59,3 +59,6 @@ e2e-logs/ /packages/core/outbound-test-logs /packages/core/__e2e__/graphify-out /graphify-out +.agw-validation/ +.ci-contracts/ +.agw-runtime-validation/ diff --git a/packages/core/.eslintrc.json b/packages/core/.eslintrc.json index 4096b286..cc65fded 100644 --- a/packages/core/.eslintrc.json +++ b/packages/core/.eslintrc.json @@ -23,6 +23,9 @@ { "ignoredFiles": [ "{projectRoot}/eslint.config.{js,cjs,mjs}", + "{projectRoot}/scripts/check-agw-docs.js", + "{projectRoot}/scripts/check-agw-package.js", + "{projectRoot}/scripts/check-agw-api.js", "{projectRoot}/**/*.spec.ts" ], "ignoredDependencies": [ diff --git a/packages/core/AGW.md b/packages/core/AGW.md new file mode 100644 index 00000000..8945327b --- /dev/null +++ b/packages/core/AGW.md @@ -0,0 +1,366 @@ +# Agentic wallets on Push Chain + +This guide describes AGW v5 in this SDK branch. Donut is the configured deployment. Native Push, EVM destination rules and named-IDL Solana devnet rules are supported. Solana-origin signers can already act through their Push UEA. + +An AGW holds assets. Its owner grants or revokes rules and can execute unrestricted owner calls. An agent executes through its own Push identity, and each agent call must pass the granted policy. A Push-native key's identity is its EOA; an external key's identity is its Push UEA for that origin chain. + +```mermaid +flowchart LR + Owner[Owner EOA or UEA] -->|create, grant, update, revoke| Wallet[AGW] + Owner -->|owner execution| Wallet + Agent[Agent EOA or UEA] -->|agent execution| Wallet + Wallet -->|agent calls checked| Policy[Engine and rules policy] + Policy --> Native[Push target] + Policy --> Gateway[Gateway and destination account] +``` + +## Connect a Push-native signer + +Pass a key from your application's key management. The functions below do not load `.env` files or run automatically. They use `viem` and the SDK's public exports. From the SDK checkout, check all TypeScript blocks together with `node packages/core/scripts/check-agw-docs.js` (or `yarn docs:check:agw` from packages/core). + +```ts +import { + PushChain, + AgenticError, + type NativeRule, + type UniversalRule, + type SolanaRule, +} from '@pushchain/core'; +import { + createWalletClient, + http, + parseEther, + encodeFunctionData, + erc20Abi, + type Address, + type Hex, +} from 'viem'; +import { privateKeyToAccount } from 'viem/accounts'; + +type WalletTransaction = Awaited>; + +const NETWORK = PushChain.CONSTANTS.PUSH_NETWORK.TESTNET_DONUT; +const PUSH = PushChain.CONSTANTS.CHAIN.PUSH_TESTNET_DONUT; +const SEPOLIA = PushChain.CONSTANTS.CHAIN.ETHEREUM_SEPOLIA; +const ETH = PushChain.CONSTANTS.MOVEABLE.TOKEN.ETHEREUM_SEPOLIA.ETH; + +async function connectPush(key: Hex, wallet?: Address): Promise { + const walletClient = createWalletClient({ + account: privateKeyToAccount(key), + transport: http('https://evm.donut.rpc.push.org/'), + }); + const signer = await PushChain.utils.signer.toUniversalFromKeypair( + walletClient, + { chain: PUSH, library: PushChain.CONSTANTS.LIBRARY.ETHEREUM_VIEM }, + ); + return PushChain.initialize(signer, { + network: NETWORK, + ...(wallet ? { agenticWallet: wallet } : {}), + }); +} +``` + +`connectPush(ownerKey)` creates an ordinary owner client for management and funding. `connectPush(key, wallet)` sends from that AGW. The SDK determines the owner or agent door from the connected signer; the caller does not select a door. + +## Create a wallet and grant a native rule + +This example permits ten value transfers to one recipient before expiry, with explicit per-call and total limits. Explicit limits avoid relying on native omission defaults that are still being finalized. + +```ts +async function createNativeWallet( + owner: PushChain, + agent: Address, + recipient: Address, +) { + const rule: NativeRule = { + agent, + target: recipient, + selector: 'value-only', + validUntil: Math.floor(Date.now() / 1000) + 3600, + maxValuePerCall: parseEther('0.001'), + maxValueTotal: parseEther('0.01'), + maxCalls: 10, + }; + const prediction = await owner.agentic.derive(); + const created = await owner.agentic.create('native-transfers', { + rules: [rule], + }); + return { prediction, created, rule }; +} +``` + +Create confirms deployment/grant receipts and returns `wallet`, `index`, `rulesIds` and transaction metadata. It does not fund the wallet or agent. A concurrent owner creation can invalidate a predicted index; the index-bound deployment refuses that race instead of granting on another wallet. + +## Fund separately, then send as the agent + +The wallet pays the transfer value. The agent pays Push transaction gas from its own EOA/UEA. Cross-chain sends also need PC in the wallet for the outbound budget. These are separate balances. + +```ts +async function fundAndSendNative( + owner: PushChain, + wallet: Address, + agentKey: Hex, + recipient: Address, +) { + await (await owner.universal.sendTransaction({ + to: wallet, + value: parseEther('0.02'), + })).wait(); + // Fund the agent's Push identity separately if it needs transaction gas. + const agent = await connectPush(agentKey, wallet); + const response = await agent.universal.sendTransaction({ + to: recipient, + value: parseEther('0.001'), + }); + return response.wait(); +} +``` + +For an external signer, grant to its derived Push UEA rather than its origin-chain address. Use `PushChain.utils.account.deriveExecutorAccount` with the signer’s actual origin chain. First-use external UEA gas handling uses that origin; changing the origin chain changes the UEA identity. + +Native agent arrays use an atomic UEA/EIP-7702 transport that preserves the agent sender. Each action is checked individually. An unavailable atomic transport fails explicitly; the SDK does not submit the agent batch sequentially. + +## Read, replace and revoke rules + +A management handle is `owner.agentic.wallet(wallet)`. It reads and writes rules but does not switch the owner's transaction execution identity to the wallet. + +```ts +async function inspectWallet(owner: PushChain, wallet: Address) { + const handle = owner.agentic.wallet(wallet); + const [info, ownerRecord, rules] = await Promise.all([ + handle.info(), handle.owner(), handle.rules.list(), + ]); + return { info, owner: ownerRecord.owner, rules: rules.rules }; +} + +async function replaceNativeRule( + owner: PushChain, + wallet: Address, + rulesId: Hex, + replacement: NativeRule, +) { + return owner.agentic.wallet(wallet).rules.update({ + rules: [{ rulesId, rule: replacement }], + }); +} + +async function revokeRule(owner: PushChain, wallet: Address, rulesId: Hex) { + return (await owner.agentic.wallet(wallet).rules.revoke([rulesId])).wait(); +} +``` + +Replacement asserts the old spend, revokes and grants in one owner transaction. Intervening agent spending makes the whole replacement revert. The new rule gets a new ID and fresh counters. A single replacement records five checkpoints. Failed transactions unwind their checkpoints; agent calls do not tick the owner checkpoint count. + +`rules.list()` returns enabled rules, including enabled rules whose expiry has passed. Expiry is enforced on execution. Revoked-history reconstruction is outside v1. Rule IDs are wallet-scoped; do not treat an ID alone as a globally unique permission. + +## Wallet labels + +Donut uses the v5 factory `0x8137F96A50EBF41d904e3678c84c391a0D1BCcc5`. Wallet labels are stored on-chain; `info()` and `list()` read the current value. An empty deployment label defaults to `AGW `. + +```ts +async function renameWallet(owner: PushChain, wallet: Address) { + const handle = owner.agentic.wallet(wallet); + const renamed = await handle.setLabel('Trading'); + const info = await handle.info(); + const reset = await handle.setLabel(''); + return { renamed, info, reset }; +} +``` + +Create and rename labels accept at most **64 UTF-8 bytes**, including spaces; 16 four-byte emoji fit. Empty rename resets the default. The SDK renames through the owner door for EOA and UEA owners, emits progress through the supplied hook and records one owner-action checkpoint. The contract's direct `setLabel` call itself records no checkpoint. Agent and read-only clients cannot rename. + +New wallets use v5 only. Existing v4 wallets do not acquire label functions and are unsupported by this SDK adapter. Wallet predictions and EIP-712 intent domains use the new factory; do not reuse old predicted addresses or signatures. On relayed signed deployment, the contract does not include the cosmetic label in `OwnerIntent`; the owner can correct it afterward. + +## Grant an EVM destination rule + +The destination token identifies an asset on that destination chain. The SDK resolves the mapped PRC20 held by the AGW. Limits use the token's smallest units; `maxGasPerCall` uses PC wei. A rule may list several assets, but each outbound request moves one listed token. + +The example below bridges at most 0.000001 ETH per call and permits a counter's `increment()` call. The explicit zero-value call leaves the bridged ETH in the wallet's CEA. Use a target that actually implements that selector. + +```ts +async function createSepoliaWallet( + owner: PushChain, + agent: Address, + counter: Address, +) { + const rule: UniversalRule = { + agent, + chainNamespace: SEPOLIA, + assets: [{ + token: ETH, + maxPerCall: BigInt(10) ** BigInt(12), + maxTotal: BigInt(10) ** BigInt(13), + }], + maxGasPerCall: parseEther('20'), + validUntil: Math.floor(Date.now() / 1000) + 3600, + allowedCalls: [{ target: counter, selector: 'increment()', maxValue: BigInt(0) }], + }; + return owner.agentic.create('sepolia-counter', { rules: [rule] }); +} +``` + +An omitted universal asset total uses uint256 maximum; explicit zero forbids movement. `assets: []` is a call-only rule, represented internally by a zero-cap destination gas token. The SDK derives `expectedCEA` from the wallet, not the agent. + +## Fund the PRC20 and set a bounded allowance + +The gateway pulls the selected PRC20 from the AGW. Set the allowance through the owner door as a separate, explicit action. Neither owner nor agent outbound sends change allowances automatically. + +```ts +async function prepareSepoliaWallet( + owner: PushChain, + ownerKey: Hex, + wallet: Address, + amount: bigint, +) { + const prc20 = PushChain.utils.tokens.getPRC20Address(ETH, { network: NETWORK }); + // The ordinary owner account must already hold the mapped PRC20. + await (await owner.universal.sendTransaction({ + to: wallet, value: parseEther('21'), + })).wait(); + await (await owner.universal.sendTransaction({ + to: prc20.address, + data: encodeFunctionData({ + abi: erc20Abi, functionName: 'transfer', args: [wallet, amount], + }), + })).wait(); + const ownerDoor = await connectPush(ownerKey, wallet); + const gateway = '0x00000000000000000000000000000000000000C1' as Address; + await (await ownerDoor.universal.sendTransaction({ + to: prc20.address, + data: encodeFunctionData({ + abi: erc20Abi, functionName: 'approve', args: [gateway, amount], + }), + })).wait(); +} + +async function sendToSepolia(agent: PushChain, counter: Address, amount: bigint) { + return agent.universal.sendTransaction({ + to: { address: counter, chain: SEPOLIA }, + data: [{ to: counter, value: BigInt(0), data: '0xd09de08a' }], + funds: { amount, token: ETH }, + gasLimit: BigInt(2_000_000), // includes fresh CEA finalization in this example + }); +} +``` + +The current core default of 500,000 destination gas was insufficient for fresh Sepolia CEA finalization in our live test (~1.3 million estimated). The example supplies a bounded two-million-gas limit; choose a budget appropriate for your destination calls. The 20/21-PC values are example budgets, not fee estimates. Fees and gas are quoted for the current request. Approval safety is the application's responsibility; the SDK validates structure and contract limits rather than deciding whether a grant is appropriate. + +## Wait, replay and recover + +`from` is the AGW and `origin` is the signer. For EVM outbounds, `to/data/value` describe the first destination call; `agentic.destinationCalls` preserves all destination calls. `agentic.rawTo/rawData` retain the wrapped Push call. + +```ts +async function waitForDelivery(response: WalletTransaction) { + const receipt = await response.wait({ outboundTimeoutMs: 600_000 }); + return { + pushSucceeded: receipt.status === 1, + destinationStatus: receipt.externalStatus, + externalTxHash: receipt.externalTxHash, + }; +} + +async function replay(owner: PushChain, hash: string) { + const response = await owner.universal.trackTransaction(hash); + return response.wait({ outboundTimeoutMs: 600_000 }); +} + +function recoveryDetails(error: unknown) { + if (!(error instanceof AgenticError)) throw error; + return { code: error.code, hint: error.hint, details: error.details }; +} +``` + +A successful Push receipt does not mean destination success. Check `externalStatus`. A timeout can mean the relay is still processing; track the same hash rather than assuming the transaction failed. Reverted Push roots do not start destination polling. Wrapped outbounds are recognized from their calldata even if the indexer initially reports only the Push leg. + +| Result | Application action | +| --- | --- | +| `INDEX_RACE` | This create committed nothing; derive/retry the next slot. | +| `CREATE_PARTIAL` | Inspect `details.walletDeployed`, `grantedRulesIds`, `confirmedHashes` and `pendingHash`. Reconcile unknown/pending outcomes. If deployed, finish missing grants with `rules.add`; do not create a replacement wallet blindly. | +| `NO_RULES_FOR_CHAIN` | Grant a suitable enabled rule before the agent sends. | +| `AMBIGUOUS_RULE` | Multiple enabled rules match the agent and chain. No transaction is submitted. Inspect `details.rulesIds` and have the owner resolve the overlap; the SDK does not pick or revoke a rule arbitrarily. | +| `GATEWAY_ALLOWANCE_INSUFFICIENT` | The owner must explicitly establish a sufficient allowance. | +| `CAPABILITY_UNAVAILABLE` / `GENERATION_UNSUPPORTED` | Inspect the capability/deployment details; no compatible operation was submitted. | + +Ordinary returned funds do not lower policy spend. `creditRevert` still needs platform executor support. Revoking rules stops agent authorization but does not remove ERC20 allowances; the owner manages those separately. + +## Solana rules using named IDL inputs + +Use `SolanaRule` with an Anchor IDL, instruction name, named account restrictions and field constraints. Addresses accept base58 or 32-byte hex. `walletCEA` and `walletATA` references are derived from the AGW and configured cluster; declare output mints in `outputTokens` when their wallet ATAs also need protection. + +```ts +import type { Idl } from '@coral-xyz/anchor'; + +async function createSolanaWallet( + owner: PushChain, agent: Address, program: string, + idl: Idl, recipient: string, counter: string, +) { + const rule: SolanaRule = { + agent, + chainNamespace: PushChain.CONSTANTS.CHAIN.SOLANA_DEVNET, + validUntil: Math.floor(Date.now() / 1000) + 3600, + assets: [{ token: '0x0000000000000000000000000000000000000000', maxPerCall: BigInt(10_000), maxTotal: BigInt(20_000) }], + maxGasPerCall: parseEther('20'), + allowedInstructions: [{ + program, + instruction: { idl, name: 'receive_sol' }, + accounts: [ + { name: 'counter', expected: { kind: 'address', address: counter } }, + { name: 'recipient', expected: { kind: 'address', address: recipient } }, + { name: 'cea_authority', expected: { kind: 'walletCEA' } }, + { name: 'system_program', expected: { kind: 'address', address: '11111111111111111111111111111111' } }, + ], + fields: [{ name: 'amount', max: BigInt(10_000) }], + }], + }; + return owner.agentic.create('solana-wallet', { rules: [rule] }); +} + +async function sendSolanaInstruction(agent: PushChain, program: string, idl: Idl) { + const data = PushChain.utils.helpers.encodeTxData({ + abi: idl, functionName: 'receive_sol', args: [BigInt(10_000)], + }); + return agent.universal.sendTransaction({ + to: { address: program, chain: PushChain.CONSTANTS.CHAIN.SOLANA_DEVNET }, + data, value: BigInt(10_000), + }); +} +``` + +These examples assume the supplied IDL describes `receive_sol` with those accounts and a `u64` amount. The send resolver needs matching account addresses/PDA definitions in its IDL. Fund the wallet and set a separate bounded gateway allowance before sending. Native SOL amounts are lamports; the wallet burns its corresponding PRC20. `assets: []` creates a zero-amount gas-token routing cap. + +Supported rule layouts have an eight-byte discriminator, top-level non-optional accounts, and fixed-width primitive/fixed-array arguments. Field comparisons support exact bytes (at most 32 bytes), unsigned integer min/max (up to `u64`), and same-width unsigned ratio floors. Variable-length or nested/defined argument layouts and optional/nested accounts are rejected before signing. An IDL describes encoding; it does not prove what the program does with those accounts. + +Agent SVM sends require one instruction encoded with `encodeTxData` (which registers the IDL), or data matching an already registered IDL. Instruction arrays remain unsupported. Owners can also send funds without any IDL or instruction: + +```ts +async function transferSolanaFunds(ownerWallet: PushChain, recipient: string) { + return ownerWallet.universal.sendTransaction({ + to: { address: recipient, chain: PushChain.CONSTANTS.CHAIN.SOLANA_DEVNET }, + value: BigInt(10_000), // native SOL, in lamports + }); +} + +async function transferSolanaUsdt(ownerWallet: PushChain, recipient: string) { + return ownerWallet.universal.sendTransaction({ + to: { address: recipient, chain: PushChain.CONSTANTS.CHAIN.SOLANA_DEVNET }, + funds: { + token: PushChain.CONSTANTS.MOVEABLE.TOKEN.SOLANA_DEVNET.USDT, + amount: BigInt(1), // 0.000001 USDT at six decimals + }, + }); +} +``` + +`ownerWallet` is initialized with the owner signer and `agenticWallet`. As with instruction sends, fund the wallet with PC/PRC20 and establish a separate bounded gateway allowance. Transfers use an empty payload and the requested recipient; the SDK applies core’s Solana finalization/rent budget using the wallet identity. Send either `value` for SOL or `funds` for a token, not both. A zero-amount funds-only send is rejected. + +Funds-only responses expose `agentic.destinationTransfer` with the recipient, burned Push PRC20 token, and amount. They have no `destinationInstruction`; replay uses the same representation. Native SOL transfers show their amount in `value`, while SPL transfers carry the amount in transfer metadata and show zero native value. + +Structural/context/funding failures are SDK `AgenticError`s. Granted permissions, expiry and spend limits are enforced by the contract. Refusals obtained during contract simulation or execution are mapped to `AgenticRevertError` with `decodedError`; simulation failure does not broadcast a transaction. Reads return `DecodedSolanaRule` with `format: 'decoded'` and exact stored program/account/data constraints. They cannot reconstruct an IDL; use a named `SolanaRule` input to add or replace it. Native/EVM decoded rules remain reusable in raw-offset form. + +Responses expose `agentic.destinationInstruction` and the wallet’s destination CEA. Check `externalStatus` and replay the same transaction hash after a timeout. + +## Current API boundaries + +Rule `ref` is removed from public inputs and records; supplying it is rejected. Checkpoint `ref` is a separate existing event field and is preserved. Editable labels are implemented against the checked v5 deployment. Contract permission enforcement is already present: unauthorized actions under the supplied rule are rejected, and the SDK maps the errors. Revoked history, public spend records, public generation context and `compileCard` are outside standalone v1. Omitted native PC value limits are zero. Native argument-index and raw-offset inputs are both supported; decoded native/EVM rules preserve exact offsets. + +Use `PushChain.CONSTANTS.READ.CHAIN.WEB2` for Web2 reads. Its value is `web2`; the old literal `web2:https` is still accepted and normalizes to the same wire identity. Literal comparisons against the older spelling need updating. Web2 is a read source, not a transaction destination. diff --git a/packages/core/README.md b/packages/core/README.md index e19eeebe..d65a3a00 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -8,6 +8,8 @@ Push Chain is a true universal L1 that is 100% EVM compatible. It allows develop ## Documentation +For AGW v5 in this branch, see the [agentic wallet integration guide](AGW.md) for creation, rules, funding, execution and recovery. + For full documentation, API references, and guides, visit: 👉 [Push Chain Developer Docs](https://push.org/docs) diff --git a/packages/core/__agw-local__/agw-local-advanced.spec.ts b/packages/core/__agw-local__/agw-local-advanced.spec.ts new file mode 100644 index 00000000..83817f1b --- /dev/null +++ b/packages/core/__agw-local__/agw-local-advanced.spec.ts @@ -0,0 +1,610 @@ +import { readNativeCounters } from '../__e2e__/shared/agw-state'; +/** + * Real-contract checks for the harder AGW paths (pinned v5 on anvil). + * The universal-outbound block drives the SDK's composer with a runtime whose + * CEA and fee quote are local stand-ins (no destination chain or price feeds + * exist here); URP still decides every gate on the composed request. + */ +import { + encodeAbiParameters, + encodeFunctionData, + getAddress, + keccak256, + parseAbi, + toBytes, + type Address, + type Hex, +} from 'viem'; +import { AgenticRevertError, CHAIN, type PushChain } from '../src'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../src/lib/agentic/errors'; +import { agenticSend } from '../src/lib/agentic/execution/send'; +import { updateRules } from '../src/lib/agentic/management/rules-write'; +import type { AgenticRuntime } from '../src/lib/agentic/runtime'; +import type { AgenticExecutionContext } from '../src/lib/agentic/context'; +import { buildSession, encodeEnvelope } from '../src/lib/agentic/codec/session'; +import { encodeUniversalTerms } from '../src/lib/agentic/codec/universal-terms'; +import { startHarness, type Harness } from './harness'; + +const TARGET_ABI = parseAbi([ + 'function increment()', + 'function deposit(address beneficiary, uint256 amount) payable', + 'function lastBeneficiary() view returns (address)', + 'function counter() view returns (uint256)', +]); +const TOKEN_ABI = parseAbi([ + 'function mint(address to, uint256 amount)', + 'function balanceOf(address) view returns (uint256)', + 'function allowance(address,address) view returns (uint256)', + 'function approve(address,uint256) returns (bool)', + 'function totalSupply() view returns (uint256)', +]); +const GATEWAY_ABI = parseAbi([ + 'function outboundCount() view returns (uint256)', + 'function lastSender() view returns (address)', + 'function lastRequestHash() view returns (bytes32)', +]); +const CORE_ABI = parseAbi([ + 'function getOutboundTxGasAndFees(address,uint256) view returns (address,uint256,uint256,uint256,string,uint256)', +]); + +type Internals = { + agenticRuntime: AgenticRuntime; + agenticContext?: AgenticExecutionContext; +}; +const internals = (c: PushChain) => c as unknown as Internals; + +async function chainNow(h: Harness): Promise { + return Number((await h.publicClient.getBlock()).timestamp); +} +async function warp(h: Harness, seconds: number): Promise { + await h.publicClient.request({ + method: 'evm_increaseTime' as never, + params: [seconds] as never, + }); + await h.publicClient.request({ + method: 'evm_mine' as never, + params: [] as never, + }); +} +const fund = (h: Harness, to: Address, value: bigint) => + h.wallets[4].sendTransaction({ + to, + value, + account: h.wallets[4].account!, + chain: h.wallets[4].chain, + }); + +describe('AGW advanced paths against real v5 contracts', () => { + let h: Harness; + let owner: PushChain; + let agentAddr: Address; + + beforeAll(async () => { + h = await startHarness(18547); + owner = await h.client(0); + agentAddr = h.wallets[1].account!.address; + }); + afterAll(async () => { + await h?.stop(); + }); + + describe('native pins, amount and value caps', () => { + let wallet: Address; + let agent: PushChain; + const beneficiary = getAddress( + '0x00000000000000000000000000000000000b0b0b' + ); + + beforeAll(async () => { + const created = await owner.agentic.create('pins', { + rules: [ + { + agent: agentAddr, + target: h.addresses.target, + selector: 'deposit(address,uint256)', + validUntil: (await chainNow(h)) + 3600, + pins: [{ arg: 0, expected: beneficiary }], + amount: { arg: 1, maxPerCall: BigInt(10), maxTotal: BigInt(15) }, + maxValuePerCall: BigInt(1000), + maxValueTotal: BigInt(1000), + }, + ], + }); + wallet = created.wallet; + await h.publicClient.waitForTransactionReceipt({ + hash: await fund(h, wallet, BigInt(10) ** BigInt(18)), + }); + agent = await h.client(1, { agenticWallet: wallet }); + }); + + const deposit = (to: Address, amount: bigint, value = BigInt(0)) => + agent.universal.sendTransaction({ + to: h.addresses.target, + value, + data: encodeFunctionData({ + abi: TARGET_ABI, + functionName: 'deposit', + args: [to, amount], + }), + }); + + it('a pinned beneficiary and an in-cap amount pass', async () => { + await (await deposit(beneficiary, BigInt(5), BigInt(10))).wait(); + expect( + await h.publicClient.readContract({ + address: h.addresses.target, + abi: TARGET_ABI, + functionName: 'lastBeneficiary', + }) + ).toBe(beneficiary); + }); + + it('a wrong beneficiary is rejected by URP with a decoded error and no state change', async () => { + const err = await deposit(agentAddr, BigInt(5)).catch((e) => e); + expect(err).toBeInstanceOf(AgenticRevertError); + expect(err.decodedError?.name).toBe( + 'PolicyCheckReverted(ArgPinMismatch)' + ); + const rec = await owner.agentic.wallet(wallet).rules.list(); + expect(rec.rules[0]).not.toHaveProperty('spent'); + expect( + await readNativeCounters( + h.publicClient, + h.generation.addresses, + wallet, + rec.rules[0].rulesId + ) + ).toMatchObject({ amountSpent: BigInt(5), callsUsed: 1 }); + }); + + it('per-call and lifetime amount caps are enforced on-chain', async () => { + await expect(deposit(beneficiary, BigInt(11))).rejects.toBeInstanceOf( + AgenticRevertError + ); + await (await deposit(beneficiary, BigInt(10))).wait(); + await expect(deposit(beneficiary, BigInt(1))).rejects.toBeInstanceOf( + AgenticRevertError + ); + }); + + it('the decoded native terms carry the pins and caps as stored', async () => { + const { rules } = await owner.agentic.wallet(wallet).rules.list(); + expect(rules[0].rule).toMatchObject({ + pins: [ + { + offset: 4, + expected: `0x${'0'.repeat(24)}${beneficiary + .slice(2) + .toLowerCase()}`, + }, + ], + amount: { offset: 36, maxPerCall: BigInt(10), maxTotal: BigInt(15) }, + maxValuePerCall: BigInt(1000), + }); + }); + }); + + describe('stale-spend replacement race', () => { + it('an agent spend between the read and inclusion reverts the whole replacement atomically', async () => { + const created = await owner.agentic.create('race', { + rules: [ + { + agent: agentAddr, + target: h.addresses.target, + selector: 'increment()', + validUntil: (await chainNow(h)) + 3600, + }, + ], + }); + const wallet = created.wallet; + const oldId = created.rulesIds[0]; + const agent = await h.client(1, { agenticWallet: wallet }); + const rt = internals(owner).agenticRuntime; + const cpBefore = await h.publicClient.readContract({ + address: wallet, + abi: parseAbi(['function checkpointCount() view returns (uint64)']), + functionName: 'checkpointCount', + }); + const racing: AgenticRuntime = { + ...rt, + reader: rt.reader, + execute: async (params, options) => { + // The agent spends after the SDK read the counters, before the owner's tx lands. + await ( + await agent.universal.sendTransaction({ + to: h.addresses.target, + data: encodeFunctionData({ + abi: TARGET_ABI, + functionName: 'increment', + }), + }) + ).wait(); + return rt.execute(params, options); + }, + }; + const err = await updateRules(racing, h.generation, wallet, { + rules: [ + { + rulesId: oldId, + rule: { + agent: agentAddr, + target: h.addresses.target, + selector: 'increment()', + validUntil: (await chainNow(h)) + 3600, + }, + }, + ], + }).catch((e) => e); + expect(err).toBeInstanceOf(AgenticRevertError); + // Nothing changed: the old rule is still the only enabled rule and no checkpoint landed. + const { rules } = await owner.agentic.wallet(wallet).rules.list(); + expect(rules.map((r) => r.rulesId)).toEqual([oldId]); + expect( + await h.publicClient.readContract({ + address: wallet, + abi: parseAbi(['function checkpointCount() view returns (uint64)']), + functionName: 'checkpointCount', + }) + ).toBe(cpBefore); + }); + }); + + describe('expiry', () => { + it('an expired-but-enabled rule still identifies the agent; the send fails on-chain', async () => { + const created = await owner.agentic.create('expiring', { + rules: [ + { + agent: agentAddr, + target: h.addresses.target, + selector: 'increment()', + validUntil: (await chainNow(h)) + 600, + }, + ], + }); + await warp(h, 1200); + const agent = await h.client(1, { agenticWallet: created.wallet }); + const err = await agent.universal + .sendTransaction({ + to: h.addresses.target, + data: encodeFunctionData({ + abi: TARGET_ABI, + functionName: 'increment', + }), + }) + .catch((e) => e); + expect(err).toBeInstanceOf(AgenticRevertError); + expect(err.decodedError?.name).toBe('PolicyCheckReverted(RulesExpired)'); + }); + }); + + describe('sequential create partial failure and recovery', () => { + it('reports CREATE_PARTIAL with the deployed wallet and granted IDs; rules.add finishes it', async () => { + // Chain time runs ahead of the local clock: the SDK accepts validUntil, the policy does not. + const skewedValidUntil = Math.floor(Date.now() / 1000) + 600; + await warp(h, 7200); + const err = await owner.agentic + .create('partial', { + rules: [ + { + agent: agentAddr, + target: h.addresses.target, + selector: 'increment()', + validUntil: (await chainNow(h)) + 3600, + }, + { + agent: h.wallets[3].account!.address, + target: h.addresses.target, + selector: 'increment()', + validUntil: skewedValidUntil, + }, + ], + }) + .catch((e) => e); + expect(err).toBeInstanceOf(AgenticError); + expect(err.code).toBe(AGENTIC_ERROR_CODE.CREATE_PARTIAL); + expect(err.details.walletDeployed).toBe(true); + expect(err.details.grantedRulesIds).toHaveLength(1); + expect(err.details.confirmedHashes.length).toBeGreaterThanOrEqual(2); + const wallet = err.details.wallet as Address; + const added = await owner.agentic.wallet(wallet).rules.add([ + { + agent: h.wallets[3].account!.address, + target: h.addresses.target, + selector: 'increment()', + validUntil: (await chainNow(h)) + 3600, + }, + ]); + expect(added.rulesIds).toHaveLength(1); + const { rules } = await owner.agentic.wallet(wallet).rules.list(); + expect(rules).toHaveLength(2); + }); + + it('rules.add with several rules is one atomic owner batch: OWNER_ACTION + RULES_GRANTED per rule', async () => { + const created = await owner.agentic.create('multi-add', { rules: [] }); + const before = await h.publicClient.readContract({ + address: created.wallet, + abi: parseAbi(['function checkpointCount() view returns (uint64)']), + functionName: 'checkpointCount', + }); + const added = await owner.agentic.wallet(created.wallet).rules.add([ + { + agent: agentAddr, + target: h.addresses.target, + selector: 'increment()', + validUntil: (await chainNow(h)) + 3600, + }, + { + agent: h.wallets[3].account!.address, + target: h.addresses.target, + selector: 'increment()', + validUntil: (await chainNow(h)) + 3600, + }, + ]); + expect(added.rulesIds).toHaveLength(2); + expect(added.tx.atomic).toBe(true); + const { checkpoints } = await owner.agentic + .wallet(created.wallet) + .checkpoints({ sinceBlock: added.tx.blockNumber }); + expect(BigInt(checkpoints.length)).toBe(BigInt(4)); + expect(checkpoints.map((c) => c.kind)).toEqual([ + 'OWNER_ACTION', + 'RULES_GRANTED', + 'OWNER_ACTION', + 'RULES_GRANTED', + ]); + expect(before).toBe(BigInt(0)); + }); + }); + + describe('agent EVM outbound (v5 multi-asset terms, stub gateway)', () => { + const SEPOLIA = CHAIN.ETHEREUM_SEPOLIA; + const CEA = getAddress('0x000000000000000000000000000000000000cea1'); + const destTarget = getAddress('0x00000000000000000000000000000000000d0d0d'); + let token: Address; + let wallet: Address; + let rulesId: Hex; + let runtime: AgenticRuntime; + let ctx: AgenticExecutionContext; + let ownerAgw: PushChain; + + beforeAll(async () => { + token = await h.deploy(0, 'HarnessPRC20', 'HarnessFixtures.sol', [ + SEPOLIA, + 6, + ]); + const created = await owner.agentic.create('outbound', { rules: [] }); + wallet = created.wallet; + await h.write(0, token, TOKEN_ABI, 'mint', [wallet, BigInt(1_000_000)]); + await h.publicClient.waitForTransactionReceipt({ + hash: await fund(h, wallet, BigInt(10) ** BigInt(17)), + }); + // Fixture setup (raw owner call): grant a v5 multi-asset universal rule. + const terms = encodeUniversalTerms({ + validUntil: (await chainNow(h)) + 3600, + expectedCEA: CEA, + assets: [ + { token: token, maxPerCall: BigInt(1000), maxTotal: BigInt(1500) }, + ], + maxGasPerCall: BigInt(10) ** BigInt(16), + allowedCalls: [ + { + target: destTarget, + selector: '0xd09de08a', + beneficiaryOffset: 0, + hasBeneficiary: false, + maxValue: BigInt(0), + }, + ], + }); + const session = buildSession({ + validator: h.addresses.validator, + agent: agentAddr, + rulesPolicy: h.addresses.rulesPolicy, + actions: [ + { + target: h.addresses.gateway, + selector: '0x77b86bec', + initData: encodeEnvelope(SEPOLIA, terms), + }, + ], + }); + await h.write( + 0, + wallet, + h.generation.contracts.abis.wallet as never, + 'grantRules', + [session] + ); + [rulesId] = (await h.publicClient.readContract({ + address: h.addresses.engine, + abi: h.generation.contracts.abis.engine, + functionName: 'getPermissionIDs', + args: [wallet], + })) as Hex[]; + + const agent = await h.client(1, { agenticWallet: wallet }); + ctx = internals(agent).agenticContext!; + const base = internals(agent).agenticRuntime; + runtime = { + ...base, + reader: base.reader, + resolveCEA: async () => ({ cea: CEA, isDeployed: false }), + resolvePrc20: () => token, + quoteOutbound: async (prc20, gasLimit) => { + const [, gasFee, protocolFee, , , gasLimitUsed] = + (await h.publicClient.readContract({ + address: h.addresses.universalCore, + abi: CORE_ABI, + functionName: 'getOutboundTxGasAndFees', + args: [prc20, gasLimit], + })) as readonly [Address, bigint, bigint, bigint, string, bigint]; + return { protocolFee, nativeValueForGas: gasFee, gasLimitUsed }; + }, + }; + ownerAgw = await h.client(0, { agenticWallet: wallet }); + }); + + // Explicit call array: the funds land in the wallet's CEA and the listed + // call runs as given (a single `data` would also prepend transfer(target)). + const send = (amount: bigint) => + agenticSend(runtime, ctx, { + to: { address: destTarget, chain: SEPOLIA }, + data: [{ to: destTarget, value: BigInt(0), data: '0xd09de08a' }], + funds: { + amount, + token: { + symbol: 'USDC', + decimals: 6, + address: token, + mechanism: 'approve', + }, + }, + }); + + it('fails before signing when the owner has not set a gateway allowance', async () => { + await expect(send(BigInt(100))).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.GATEWAY_ALLOWANCE_INSUFFICIENT, + }); + }); + + it('owner sets a bounded allowance with an ordinary owner-door send; the agent outbound passes URP, pulls and burns', async () => { + await ( + await ownerAgw.universal.sendTransaction({ + to: token, + data: encodeFunctionData({ + abi: TOKEN_ABI, + functionName: 'approve', + args: [h.addresses.gateway, BigInt(300)], + }), + }) + ).wait(); + const supplyBefore = (await h.publicClient.readContract({ + address: token, + abi: TOKEN_ABI, + functionName: 'totalSupply', + })) as bigint; + const tx = await send(BigInt(100)); + const receipt = await h.publicClient.waitForTransactionReceipt({ + hash: tx.hash as Hex, + }); + expect(receipt.status).toBe('success'); + expect( + await h.publicClient.readContract({ + address: h.addresses.gateway, + abi: GATEWAY_ABI, + functionName: 'lastSender', + }) + ).toBe(wallet); + expect( + await h.publicClient.readContract({ + address: token, + abi: TOKEN_ABI, + functionName: 'totalSupply', + }) + ).toBe(supplyBefore - BigInt(100)); + expect( + await h.publicClient.readContract({ + address: token, + abi: TOKEN_ABI, + functionName: 'allowance', + args: [wallet, h.addresses.gateway], + }) + ).toBe(BigInt(200)); + // The request the wallet sent: empty recipient, wallet refund, nonzero gas cap, multicall payload. + const payload = `0x2cc2842d${encodeAbiParameters( + [ + { + type: 'tuple[]', + components: [ + { name: 'to', type: 'address' }, + { name: 'value', type: 'uint256' }, + { name: 'data', type: 'bytes' }, + ], + }, + ], + [[{ to: destTarget, value: BigInt(0), data: '0xd09de08a' }]] + ).slice(2)}` as Hex; + const expected = keccak256( + encodeAbiParameters( + [ + { + type: 'tuple', + components: [ + { name: 'recipient', type: 'bytes' }, + { name: 'token', type: 'address' }, + { name: 'amount', type: 'uint256' }, + { name: 'gasLimit', type: 'uint256' }, + { name: 'gasPrice', type: 'uint256' }, + { name: 'maxPCForGas', type: 'uint256' }, + { name: 'payload', type: 'bytes' }, + { name: 'revertRecipient', type: 'address' }, + ], + }, + ], + [ + { + recipient: '0x', + token, + amount: BigInt(100), + gasLimit: BigInt(200_000), + gasPrice: BigInt(0), + maxPCForGas: BigInt(10) ** BigInt(15), + payload, + revertRecipient: wallet, + }, + ] + ) + ); + expect( + await h.publicClient.readContract({ + address: h.addresses.gateway, + abi: GATEWAY_ABI, + functionName: 'lastRequestHash', + }) + ).toBe(expected); + expect(tx.from).toBe(wallet); + expect(tx.route).toBe('UOA_TO_CEA'); + expect(tx.agentic).toMatchObject({ + door: 'agent', + rulesId, + destinationAccount: CEA, + chainNamespace: SEPOLIA, + }); + expect(keccak256(toBytes(SEPOLIA))).toBeTruthy(); + }); + + it('owner can remove the allowance; the agent is stopped before signing again', async () => { + await ( + await ownerAgw.universal.sendTransaction({ + to: token, + data: encodeFunctionData({ + abi: TOKEN_ABI, + functionName: 'approve', + args: [h.addresses.gateway, BigInt(0)], + }), + }) + ).wait(); + await expect(send(BigInt(10))).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.GATEWAY_ALLOWANCE_INSUFFICIENT, + }); + }); + + it('a call outside the allow-list is rejected by URP on-chain', async () => { + await ( + await ownerAgw.universal.sendTransaction({ + to: token, + data: encodeFunctionData({ + abi: TOKEN_ABI, + functionName: 'approve', + args: [h.addresses.gateway, BigInt(50)], + }), + }) + ).wait(); + const err = await agenticSend(runtime, ctx, { + to: { address: destTarget, chain: SEPOLIA }, + data: '0x12345678', + }).catch((e) => e); + expect(err).toBeInstanceOf(AgenticRevertError); + }); + }); +}); diff --git a/packages/core/__agw-local__/agw-local-batch.spec.ts b/packages/core/__agw-local__/agw-local-batch.spec.ts new file mode 100644 index 00000000..ae5071df --- /dev/null +++ b/packages/core/__agw-local__/agw-local-batch.spec.ts @@ -0,0 +1,154 @@ +/** Real EIP-7702 self-delegation and real AGW/engine/policy; executor is a small + * test-only ERC-7821-shaped CALL dispatcher. No UEA relay or live network. */ +import { + encodeFunctionData, + getAddress, + parseAbi, + type Address, + type Hex, +} from 'viem'; +import { AgenticRevertError, CHAIN, type PushChain } from '../src'; +import { PUSH_BATCH_EXECUTOR_ADDRESS } from '../src/lib/constants/chain'; +import { startHarness, type Harness } from './harness'; +import { EvmClient } from '../src/lib/vm-client/evm-client'; +import { readNativeCounters } from '../__e2e__/shared/agw-state'; + +const ABI = parseAbi([ + 'function increment()', + 'function counter() view returns(uint256)', +]); +let h: Harness; +let owner: PushChain; +let previous: Address | undefined; + +beforeAll(async () => { + h = await startHarness(18552); + previous = PUSH_BATCH_EXECUTOR_ADDRESS[CHAIN.PUSH_LOCALNET]; + const executor = await h.deploy( + 0, + 'HarnessAtomicExecutor', + 'HarnessFixtures.sol' + ); + PUSH_BATCH_EXECUTOR_ADDRESS[CHAIN.PUSH_LOCALNET] = executor; + owner = await h.client(0); +}); +afterAll(async () => { + if (previous) PUSH_BATCH_EXECUTOR_ADDRESS[CHAIN.PUSH_LOCALNET] = previous; + else delete PUSH_BATCH_EXECUTOR_ADDRESS[CHAIN.PUSH_LOCALNET]; + await h?.stop(); +}); + +async function walletFor(maxCalls: number) { + const result = await owner.agentic.create('native-batch', { + rules: [ + { + agent: h.wallets[1].account!.address, + target: h.addresses.target, + selector: 'increment()', + validUntil: Number((await h.publicClient.getBlock()).timestamp) + 3600, + maxCalls, + }, + ], + }); + const agent = await h.client(1, { agenticWallet: result.wallet }); + return { ...result, agent }; +} +const calls = () => + Array.from({ length: 2 }, () => ({ + to: h.addresses.target, + value: BigInt(0), + data: encodeFunctionData({ abi: ABI, functionName: 'increment' }), + })); +const counter = () => + h.publicClient.readContract({ + address: h.addresses.target, + abi: ABI, + functionName: 'counter', + }); + +it('atomic native agent array preserves the agent sender and meters both actions', async () => { + const { wallet, rulesIds, agent } = await walletFor(3); + const before = await counter(); + const tx = await agent.universal.sendTransaction({ + to: h.addresses.target, + data: calls(), + }); + expect((await tx.wait()).status).toBe(1); + expect(tx.from).toBe(wallet); + expect(tx.agentic?.nativeCalls).toHaveLength(2); + expect(await counter()).toBe(before + BigInt(2)); + expect( + await readNativeCounters( + h.publicClient, + h.generation.addresses, + wallet, + rulesIds[0] + ) + ).toMatchObject({ callsUsed: 2 }); + // Verify actual type-4 outer transaction and its signer identity independently. + const raw = await h.publicClient.getTransaction({ hash: tx.hash as Hex }); + expect(raw.type).toBe('eip7702'); + expect(getAddress(raw.from)).toBe(h.wallets[1].account!.address); + expect(getAddress(raw.to as Address)).toBe(h.wallets[1].account!.address); +}); + +it('failure of a later native action rolls back the earlier call and its counters', async () => { + const { wallet, rulesIds, agent } = await walletFor(1); + const before = await counter(); + const nonceBefore = await h.publicClient.getTransactionCount({ + address: h.wallets[1].account!.address, + }); + // Normal estimation now refuses this invalid batch before broadcast. For + // this separate rollback proof, override only the test estimate so the real + // signed type-4 transaction reaches the real contracts and reverts there. + const original = EvmClient.prototype.sendBatch7702; + const send = jest + .spyOn(EvmClient.prototype, 'sendBatch7702') + .mockImplementation(async function (this: EvmClient, params) { + const estimate = jest + .spyOn(this.publicClient, 'estimateGas') + .mockResolvedValue(BigInt(2_000_000)); + try { + return await original.call(this, params); + } finally { + estimate.mockRestore(); + } + }); + try { + await expect( + agent.universal.sendTransaction({ to: h.addresses.target, data: calls() }) + ).rejects.toBeInstanceOf(AgenticRevertError); + } finally { + send.mockRestore(); + } + // Prove this was a mined transaction failure, not an early SDK rejection. + expect( + await h.publicClient.getTransactionCount({ + address: h.wallets[1].account!.address, + }) + ).toBeGreaterThan(nonceBefore); + expect(await counter()).toBe(before); + expect( + await readNativeCounters( + h.publicClient, + h.generation.addresses, + wallet, + rulesIds[0] + ) + ).toMatchObject({ callsUsed: 0 }); +}); + +it('normal estimation refuses an invalid native batch before broadcasting', async () => { + const { agent } = await walletFor(1); + const nonce = await h.publicClient.getTransactionCount({ + address: h.wallets[1].account!.address, + }); + await expect( + agent.universal.sendTransaction({ to: h.addresses.target, data: calls() }) + ).rejects.toBeInstanceOf(AgenticRevertError); + expect( + await h.publicClient.getTransactionCount({ + address: h.wallets[1].account!.address, + }) + ).toBe(nonce); +}); diff --git a/packages/core/__agw-local__/agw-local-races.spec.ts b/packages/core/__agw-local__/agw-local-races.spec.ts new file mode 100644 index 00000000..dd106d64 --- /dev/null +++ b/packages/core/__agw-local__/agw-local-races.spec.ts @@ -0,0 +1,166 @@ +/** + * Race regressions found during independent SDK review, + * against the real pinned v5 contracts on local anvil. + * R1 — a concurrent creation must never let this create() grant on a wallet it + * did not deploy (the deploy is index-bound through deployWalletWithSig). + * R4 — an owner outbound must never restore an allowance revoked after the + * SDK read it (the SDK never writes allowances). + */ +import { encodeFunctionData, parseAbi, type Address } from 'viem'; +import { AgenticRevertError, CHAIN, type PushChain } from '../src'; +import type { AgenticRuntime } from '../src/lib/agentic/runtime'; +import { v5 } from '../src/lib/agentic/contracts/v5'; +import { AGENTIC_ERROR_CODE } from '../src/lib/agentic/errors'; +import { startHarness, type Harness } from './harness'; + +const TOKEN = parseAbi([ + 'function mint(address,uint256)', + 'function approve(address,uint256) returns (bool)', + 'function allowance(address,address) view returns (uint256)', +]); +const internalsOf = (c: PushChain) => + (c as unknown as { agenticRuntime: AgenticRuntime }).agenticRuntime; + +describe('AGW race regressions (real v5 contracts)', () => { + let h: Harness; + let owner: PushChain; + beforeAll(async () => { + h = await startHarness(18549); + owner = await h.client(0); + }); + afterAll(async () => { + await h?.stop(); + }); + + it('R1 a concurrent creation makes create() fail with nothing granted on either wallet', async () => { + const expected = await owner.agentic.derive(); + const rt = internalsOf(owner); + const execute = rt.execute; + rt.execute = async (params, options) => { + rt.execute = execute; + await h.write( + 0, + h.addresses.factory, + h.generation.contracts.abis.factory, + 'deployWallet', + ['other-purpose-wallet'] + ); + return execute(params, options); + }; + const err = await owner.agentic + .create('intended', { + rules: [ + { + agent: h.wallets[1].account!.address, + target: h.addresses.target, + selector: 'increment()', + validUntil: + Number((await h.publicClient.getBlock()).timestamp) + 3600, + }, + ], + }) + .catch((e) => e) + .finally(() => { + rt.execute = execute; + }); + expect(err).toMatchObject({ + code: AGENTIC_ERROR_CODE.INDEX_RACE, + details: { committed: false }, + }); + const permissionIds = (address: Address) => + h.publicClient.readContract({ + address: h.addresses.engine, + abi: h.generation.contracts.abis.engine, + functionName: 'getPermissionIDs', + args: [address], + }); + expect(await permissionIds(expected.address)).toHaveLength(0); + const next = await owner.agentic.derive(); + expect(next.index).toBe(expected.index + 1); + expect(await permissionIds(next.address)).toHaveLength(0); + // A retry re-reads the slot and succeeds. + const retried = await owner.agentic.create('intended', { rules: [] }); + expect(retried.index).toBe(next.index); + }); + + it('R4 an allowance revoked after the SDK read it stays revoked; the outbound fails on-chain', async () => { + const { wallet } = await owner.agentic.create('allowance-race', { + rules: [], + }); + const token = await h.deploy(0, 'HarnessPRC20', 'HarnessFixtures.sol', [ + CHAIN.ETHEREUM_SEPOLIA, + 6, + ]); + await h.write(0, token, TOKEN, 'mint', [wallet, BigInt(1000)]); + await h.publicClient.waitForTransactionReceipt({ + hash: await h.wallets[0].sendTransaction({ + to: wallet, + value: BigInt(10) ** BigInt(17), + account: h.wallets[0].account!, + chain: h.wallets[0].chain, + }), + }); + const c = await h.client(0, { agenticWallet: wallet }); + await ( + await c.universal.sendTransaction({ + to: token, + data: encodeFunctionData({ + abi: TOKEN, + functionName: 'approve', + args: [h.addresses.gateway, BigInt(50)], + }), + }) + ).wait(); + const rt = internalsOf(c); + rt.resolvePrc20 = () => token; + rt.resolveCEA = async () => ({ + cea: h.wallets[2].account!.address, + isDeployed: true, + }); + rt.quoteOutbound = async () => ({ + protocolFee: BigInt(10) ** BigInt(14), + nativeValueForGas: BigInt(10) ** BigInt(15), + gasLimitUsed: BigInt(200000), + }); + const execute = rt.execute; + rt.execute = async (params, options) => { + rt.execute = execute; + const revoke = v5.encodeExecute([ + { + target: token, + value: BigInt(0), + data: encodeFunctionData({ + abi: TOKEN, + functionName: 'approve', + args: [h.addresses.gateway, BigInt(0)], + }), + }, + ]); + await (await execute({ to: wallet, data: revoke })).wait(); + return execute(params, options); + }; + const err = await c.universal + .sendTransaction({ + to: { + address: h.wallets[3].account!.address as Address, + chain: CHAIN.ETHEREUM_SEPOLIA, + }, + data: '0xd09de08a', + funds: { amount: BigInt(10) }, + }) + .catch((e) => e) + .finally(() => { + rt.execute = execute; + }); + expect(err).toBeInstanceOf(AgenticRevertError); + expect(err.message).toContain('0x10bad147'); // LowAllowance() — the token refused the pull + expect( + await h.publicClient.readContract({ + address: token, + abi: TOKEN, + functionName: 'allowance', + args: [wallet, h.addresses.gateway], + }) + ).toBe(BigInt(0)); + }); +}); diff --git a/packages/core/__agw-local__/agw-local.spec.ts b/packages/core/__agw-local__/agw-local.spec.ts new file mode 100644 index 00000000..93f0a3db --- /dev/null +++ b/packages/core/__agw-local__/agw-local.spec.ts @@ -0,0 +1,447 @@ +import { readNativeCounters } from '../__e2e__/shared/agw-state'; +/** + * Real-contract checks of the AGW SDK against the pinned v5 contracts on a + * local anvil chain (see harness.ts for scope and limits). Every assertion + * about authorization, atomicity, counters and checkpoints is decided by the + * real contracts; the only stubbed component is the gateway. + */ +import { + encodeFunctionData, + getAddress, + parseAbi, + type Address, + type Hex, +} from 'viem'; +import { + AgenticError, + AgenticRevertError, + CHAIN, + type PushChain, +} from '../src'; +import { AGENTIC_ERROR_CODE } from '../src/lib/agentic/errors'; +import { startHarness, type Harness } from './harness'; + +const TARGET_ABI = parseAbi([ + 'function increment()', + 'function counter() view returns (uint256)', + 'function deposit(address beneficiary, uint256 amount) payable', + 'function lastBeneficiary() view returns (address)', +]); +const WALLET_ABI = parseAbi([ + 'function checkpointCount() view returns (uint64)', + 'function agentOf(bytes32) view returns (address)', + 'function owner() view returns (address)', +]); + +const inAnHour = () => Math.floor(Date.now() / 1000) + 3600; + +describe('AGW SDK against real v5 contracts (local anvil)', () => { + let h: Harness; + let owner: PushChain; + let ownerAddr: Address; + let agentAddr: Address; + + beforeAll(async () => { + h = await startHarness(); + owner = await h.client(0); + ownerAddr = h.wallets[0].account!.address; + agentAddr = h.wallets[1].account!.address; + }); + afterAll(async () => { + await h?.stop(); + }); + + const counter = () => + h.publicClient.readContract({ + address: h.addresses.target, + abi: TARGET_ABI, + functionName: 'counter', + }); + const checkpointCount = (wallet: Address) => + h.publicClient.readContract({ + address: wallet, + abi: WALLET_ABI, + functionName: 'checkpointCount', + }); + + it('derive() predicts slot 0 from the signer identity and matches the factory', async () => { + const d = await owner.agentic.derive(); + expect(d.index).toBe(0); + expect(d.deployed).toBe(false); + const [predicted] = (await h.publicClient.readContract({ + address: h.addresses.factory, + abi: h.generation.contracts.abis.factory, + functionName: 'predictWallet', + args: [ownerAddr, BigInt(0)], + })) as readonly [Address, boolean]; + expect(d.address).toBe(getAddress(predicted)); + }); + + let bare: Address; + it('create(label, { rules: [] }) deploys a bare wallet without funding it', async () => { + const created = await owner.agentic.create('scratch', { rules: [] }); + bare = created.wallet; + expect(created.index).toBe(0); + expect(created.rulesIds).toEqual([]); + expect(await h.publicClient.getBalance({ address: bare })).toBe(BigInt(0)); + const info = await owner.agentic.wallet(bare).info(); + expect(info).toMatchObject({ + label: 'scratch', + index: 0, + owner: ownerAddr, + deployed: true, + rulesCount: 0, + }); + }); + + let wallet: Address; + let rule1: Hex; + it('create with a native rule returns the receipt-confirmed ID; grant order and IDs match the contract', async () => { + const created = await owner.agentic.create('ops', { + rules: [ + { + agent: agentAddr, + target: h.addresses.target, + selector: 'increment()', + validUntil: inAnHour(), + maxCalls: 2, + }, + ], + }); + wallet = created.wallet; + rule1 = created.rulesIds[0]; + expect(created.index).toBe(1); + expect(created.rulesIds).toHaveLength(1); + const agentOf = await h.publicClient.readContract({ + address: wallet, + abi: WALLET_ABI, + functionName: 'agentOf', + args: [rule1], + }); + expect(agentOf).toBe(agentAddr); + // Sequential fallback on a 7702-less localnet is reported honestly. + expect(typeof created.tx.atomic).toBe('boolean'); + }); + + it('list() returns both deployed wallets plus the next undeployed slot', async () => { + const { wallets } = await owner.agentic.list(); + expect( + wallets.map((w) => [w.index, w.label, w.deployed, w.rulesCount]) + ).toEqual([ + [0, 'scratch', true, 0], + [1, 'ops', true, 1], + [2, '', false, 0], + ]); + }); + + it('rules.get / rules.list decode active terms without exposing internal spend', async () => { + const rec = await owner.agentic.wallet(wallet).rules.get(rule1); + expect(rec.agent).toBe(agentAddr); + expect(rec.rule).toMatchObject({ + target: h.addresses.target, + maxCalls: 2, + maxValuePerCall: BigInt(0), + }); + expect(rec).not.toHaveProperty('spent'); + expect( + await readNativeCounters( + h.publicClient, + h.generation.addresses, + wallet, + rule1 + ) + ).toEqual({ valueSpent: BigInt(0), amountSpent: BigInt(0), callsUsed: 0 }); + const { rules } = await owner.agentic.wallet(wallet).rules.list(); + expect(rules.map((r) => r.rulesId)).toEqual([rule1]); + }); + + let agent: PushChain; + it('agent client: universal.account is the wallet, origin stays the signer, sends go through executeAsAgent', async () => { + agent = await h.client(1, { agenticWallet: wallet }); + expect(agent.universal.account).toBe(wallet); + expect(agent.universal.origin.address.toLowerCase()).toBe( + agentAddr.toLowerCase() + ); + const before = await counter(); + const tx = await agent.universal.sendTransaction({ + to: h.addresses.target, + data: encodeFunctionData({ abi: TARGET_ABI, functionName: 'increment' }), + }); + const receipt = await tx.wait(); + expect(receipt.status).toBe(1); + expect(await counter()).toBe(before + BigInt(1)); + expect(tx.from).toBe(wallet); + expect(receipt.from).toBe(wallet); + expect(tx.to).toBe(h.addresses.target); + expect(tx.agentic).toMatchObject({ wallet, door: 'agent', rulesId: rule1 }); + expect(tx.agentic?.rawTo?.toLowerCase()).toBe(wallet.toLowerCase()); + }); + + it('agent sends do not tick checkpoints; the policy enforces maxCalls on-chain', async () => { + const cpBefore = await checkpointCount(wallet); + await ( + await agent.universal.sendTransaction({ + to: h.addresses.target, + data: encodeFunctionData({ + abi: TARGET_ABI, + functionName: 'increment', + }), + }) + ).wait(); + expect(await checkpointCount(wallet)).toBe(cpBefore); + const rec = await owner.agentic.wallet(wallet).rules.get(rule1); + expect(rec).not.toHaveProperty('spent'); + expect( + await readNativeCounters( + h.publicClient, + h.generation.addresses, + wallet, + rule1 + ) + ).toMatchObject({ callsUsed: 2 }); + const err = await agent.universal + .sendTransaction({ + to: h.addresses.target, + data: encodeFunctionData({ + abi: TARGET_ABI, + functionName: 'increment', + }), + }) + .catch((e) => e); + expect(err).toBeInstanceOf(AgenticRevertError); + expect(err.decodedError?.name).toBe( + 'PolicyCheckReverted(CallLimitReached)' + ); + }); + + it('a stranger cannot initialize against the wallet', async () => { + await expect(h.client(2, { agenticWallet: wallet })).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.NOT_OWNER_OR_AGENT, + }); + }); + + it('owner client goes through execute and ticks one OWNER_ACTION checkpoint per call', async () => { + const ownerAgw = await h.client(0, { agenticWallet: wallet }); + const before = await checkpointCount(wallet); + const data = encodeFunctionData({ + abi: TARGET_ABI, + functionName: 'increment', + }); + const tx = await ownerAgw.universal.sendTransaction({ + to: h.addresses.target, + data: [ + { to: h.addresses.target, value: BigInt(0), data }, + { to: h.addresses.target, value: BigInt(0), data }, + ], + }); + await tx.wait(); + expect(await checkpointCount(wallet)).toBe(before + BigInt(2)); + expect(tx.agentic?.door).toBe('owner'); + const { checkpoints } = await owner.agentic + .wallet(wallet) + .checkpoints({ sinceBlock: tx.blockNumber }); + expect(checkpoints.map((c) => c.kind)).toEqual([ + 'OWNER_ACTION', + 'OWNER_ACTION', + ]); + }); + + it('native agent arrays require an available atomic executor instead of sequential fallback', async () => { + const data = encodeFunctionData({ + abi: TARGET_ABI, + functionName: 'increment', + }); + await expect( + agent.universal.sendTransaction({ + to: h.addresses.target, + data: [ + { to: h.addresses.target, value: BigInt(0), data }, + { to: h.addresses.target, value: BigInt(0), data }, + ], + }) + ).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.CAPABILITY_UNAVAILABLE, + }); + }); + + let rule2: Hex; + it('rules.update replaces atomically: five checkpoints, old disabled, new usable with reset counters', async () => { + const before = await checkpointCount(wallet); + const res = await owner.agentic.wallet(wallet).rules.update({ + rules: [ + { + rulesId: rule1, + rule: { + agent: agentAddr, + target: h.addresses.target, + selector: 'increment()', + validUntil: inAnHour(), + maxCalls: 1, + }, + }, + ], + }); + rule2 = res.rules[0].rulesId; + expect(res.rules[0].replaced).toBe(rule1); + expect(await checkpointCount(wallet)).toBe(before + BigInt(5)); + const { checkpoints } = await owner.agentic + .wallet(wallet) + .checkpoints({ sinceBlock: res.tx.blockNumber }); + expect(checkpoints.map((c) => c.kind)).toEqual([ + 'OWNER_ACTION', + 'OWNER_ACTION', + 'RULES_REVOKED', + 'OWNER_ACTION', + 'RULES_GRANTED', + ]); + const rec = await owner.agentic.wallet(wallet).rules.get(rule2); + expect(rec).not.toHaveProperty('spent'); + expect( + await readNativeCounters( + h.publicClient, + h.generation.addresses, + wallet, + rule2 + ) + ).toMatchObject({ callsUsed: 0 }); + await expect( + owner.agentic.wallet(wallet).rules.get(rule1) + ).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.RULE_NOT_FOUND, + }); + const tx = await agent.universal.sendTransaction({ + to: h.addresses.target, + data: encodeFunctionData({ abi: TARGET_ABI, functionName: 'increment' }), + }); + expect(tx.agentic?.rulesId).toBe(rule2); + }); + + it('full checkpoint history is contiguous and matches checkpointCount()', async () => { + const { checkpoints } = await owner.agentic.wallet(wallet).checkpoints(); + expect(checkpoints.map((c) => c.seq)).toEqual( + checkpoints.map((_, i) => i + 1) + ); + expect(BigInt(checkpoints.length)).toBe(await checkpointCount(wallet)); + expect(checkpoints[0].kind).toBe('RULES_GRANTED'); + }); + + it('bare revoke is refused; revoke({ all: true }) disables every rule', async () => { + await expect( + owner.agentic.wallet(wallet).rules.revoke(undefined as unknown as Hex[]) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.REVOKE_NEEDS_TARGET }); + await expect( + owner.agentic.wallet(wallet).rules.revoke([]) + ).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.REVOKE_NEEDS_TARGET, + }); + await ( + await owner.agentic.wallet(wallet).rules.revoke({ all: true }) + ).wait(); + const { rules } = await owner.agentic.wallet(wallet).rules.list(); + expect(rules).toEqual([]); + await expect( + agent.universal.sendTransaction({ + to: h.addresses.target, + data: encodeFunctionData({ + abi: TARGET_ABI, + functionName: 'increment', + }), + }) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.NO_RULES_FOR_CHAIN }); + }); + + it('a non-owner cannot write rules (fails before signing)', async () => { + const stranger = await h.client(2); + await expect( + stranger.agentic.wallet(wallet).rules.add([ + { + agent: agentAddr, + target: h.addresses.target, + selector: 'increment()', + validUntil: inAnHour(), + }, + ]) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.NOT_WALLET_OWNER }); + }); + + it('a read-only client can read but never sign, even with the owner address', async () => { + const ro = await h.readOnlyClient(0, { agenticWallet: wallet }); + expect(ro.universal.account).toBe(wallet); + expect((await ro.agentic.wallet(wallet).owner()).owner).toBe(ownerAddr); + await expect( + ro.agentic.wallet(wallet).rules.add([ + { + agent: agentAddr, + target: h.addresses.target, + selector: 'increment()', + validUntil: inAnHour(), + }, + ]) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.READ_ONLY }); + expect(() => + ro.universal.sendTransaction({ to: h.addresses.target, data: '0x' }) + ).toThrow(/Read only/); + }); + + it('reinitialize without agenticWallet returns an ordinary client', async () => { + const ownerAgw = await h.client(0, { agenticWallet: wallet }); + const plain = await ownerAgw.reinitialize( + await import('../src').then((m) => + m.PushChain.utils.signer.toUniversalFromKeypair(h.wallets[0], { + chain: m.CHAIN.PUSH_LOCALNET, + library: m.PushChain.CONSTANTS.LIBRARY.ETHEREUM_VIEM, + }) + ) + ); + expect(plain.universal.account.toLowerCase()).toBe(ownerAddr.toLowerCase()); + }); + + it('signer-level and cascade entry points are closed in agentic mode', async () => { + const ownerAgw = await h.client(0, { agenticWallet: wallet }); + const code = AGENTIC_ERROR_CODE.NOT_ALLOWED_IN_AGENTIC_MODE; + expect(() => + ownerAgw.universal.prepareTransaction({ + to: h.addresses.target, + data: '0x', + }) + ).toThrow(expect.objectContaining({ code })); + await expect( + ownerAgw.universal.executeTransactions([]) + ).rejects.toMatchObject({ code }); + expect(() => ownerAgw.universal.migrateCEA(CHAIN.ETHEREUM_SEPOLIA)).toThrow( + expect.objectContaining({ code }) + ); + expect(() => + ownerAgw.universal.rescueFunds({ + universalTxId: `0x${'00'.repeat(32)}`, + prc20: h.addresses.target, + }) + ).toThrow(expect.objectContaining({ code })); + await expect( + ownerAgw.universal.sendTransaction({ + to: h.addresses.target, + data: '0x', + payGasWith: {}, + }) + ).rejects.toMatchObject({ code }); + await expect( + ownerAgw.universal.sendTransaction({ + to: { address: h.addresses.target, chain: CHAIN.PUSH_LOCALNET }, + from: { chain: CHAIN.ETHEREUM_SEPOLIA }, + }) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.FROM_NOT_ALLOWED }); + }); + + it('getAccountStatus stays signer-scoped in agentic mode', async () => { + const ownerAgw = await h.client(0, { agenticWallet: wallet }); + const status = await ownerAgw.getAccountStatus(); + expect(status.mode).toBe('signer'); + expect(ownerAgw.universal.account).toBe(wallet); + }); + + it('errors from the agentic surface are typed', () => { + expect( + new AgenticError(AGENTIC_ERROR_CODE.AMBIGUOUS_RULE, 'x') + ).toBeInstanceOf(Error); + }); +}); diff --git a/packages/core/__agw-local__/delayed-index.spec.ts b/packages/core/__agw-local__/delayed-index.spec.ts new file mode 100644 index 00000000..958bf8c3 --- /dev/null +++ b/packages/core/__agw-local__/delayed-index.spec.ts @@ -0,0 +1,257 @@ +/** Real v5 execution/receipts; only origin mapping and Cosmos indexing are fixtures. */ +import { getAddress, parseAbi, type Address, type Hex } from 'viem'; +import { CHAIN, type PushChain } from '../src'; +import * as account from '../src/lib/universal/account/account'; +import type { AgenticRuntime } from '../src/lib/agentic/runtime'; +import type { OrchestratorContext } from '../src/lib/orchestrator/internals/context'; +import { detectRouteFromUniversalTxData } from '../src/lib/orchestrator/internals/tx-transformer'; +import { UniversalTxStatus } from '../src/lib/generated/uexecutor/v1/types'; +import { + OutboundStatus, + UniversalTxV2Codec, + OutboundTxV2Codec, +} from '../src/lib/generated/uexecutor/v2/types'; +import type { ProgressEvent } from '../src/lib/progress-hook/progress-hook.types'; +import { startHarness, type Harness } from './harness'; + +const DEST = getAddress('0x0000000000000000000000000000000000001234'); +const CEA = getAddress('0x000000000000000000000000000000000000cea1'); +const EXTERNAL_HASH = `0x${'ef'.repeat(32)}` as Hex; +const CORE = parseAbi([ + 'function setGasToken(string,address)', + 'function getOutboundTxGasAndFees(address,uint256) view returns (address,uint256,uint256,uint256,string,uint256)', +]); +const runtime = (c: PushChain) => + (c as unknown as { agenticRuntime: AgenticRuntime }).agenticRuntime; +const context = (c: PushChain) => + (c as unknown as { orchestrator: { ctx: OrchestratorContext } }).orchestrator + .ctx; + +describe('AGW replay with delayed Cosmos indexing', () => { + let h: Harness, token: Address; + beforeAll(async () => { + h = await startHarness(18553); + token = await h.deploy(0, 'HarnessPRC20', 'HarnessFixtures.sol', [ + CHAIN.ETHEREUM_SEPOLIA, + 18, + ]); + await h.write(0, h.addresses.universalCore, CORE, 'setGasToken', [ + CHAIN.ETHEREUM_SEPOLIA, + token, + ]); + }); + afterEach(() => jest.restoreAllMocks()); + afterAll(async () => h?.stop()); + + function configure(c: PushChain) { + runtime(c).resolvePrc20 = () => token; + runtime(c).resolveCEA = async () => ({ cea: CEA, isDeployed: false }); + runtime(c).quoteOutbound = async (asset, limit) => { + const [, nativeValueForGas, protocolFee, , , gasLimitUsed] = + await h.publicClient.readContract({ + address: h.addresses.universalCore, + abi: CORE, + functionName: 'getOutboundTxGasAndFees', + args: [asset, limit], + }); + return { nativeValueForGas, protocolFee, gasLimitUsed }; + }; + } + + it.each([ + ['owner', 'success'], + ['agent', 'success'], + ['owner', 'failed'], + ['agent', 'failed'], + ['owner', 'timeout'], + ['agent', 'timeout'], + ] as const)( + '%s door: real Push receipt then delayed external %s', + async (door, outcome) => { + // No UEA factory is present locally. Preserve real EVM RPC and contract + // verification, while isolating the unrelated UEA origin lookup. + jest + .spyOn(account, 'convertExecutorToOrigin') + .mockResolvedValue({ account: null, exists: false }); + const owner = await h.client(0); + configure(owner); + const created = await owner.agentic.create('delayed-index', { + rules: [ + { + agent: h.wallets[1].account!.address, + chainNamespace: CHAIN.ETHEREUM_SEPOLIA, + assets: [], + maxGasPerCall: BigInt(10) ** BigInt(16), + validUntil: Math.floor(Date.now() / 1000) + 3600, + allowedCalls: [{ target: DEST, selector: 'increment()' }], + }, + ], + }); + const wallet = created.wallet; + await h.publicClient.waitForTransactionReceipt({ + hash: await h.wallets[4].sendTransaction({ + to: wallet, + value: BigInt(10) ** BigInt(18), + account: h.wallets[4].account!, + chain: h.wallets[4].chain, + }), + }); + const sender = await h.client(door === 'owner' ? 0 : 1, { + agenticWallet: wallet, + }); + configure(sender); + const sent = await sender.universal.sendTransaction({ + to: { address: DEST, chain: CHAIN.ETHEREUM_SEPOLIA }, + data: [{ to: DEST, value: BigInt(0), data: '0xd09de08a' }], + }); + const root = await h.publicClient.waitForTransactionReceipt({ + hash: sent.hash as Hex, + }); + expect(root.status).toBe('success'); + expect(getAddress(root.from)).toBe( + h.wallets[door === 'owner' ? 0 : 1].account!.address + ); + + const init: ProgressEvent[] = [], + perCall: ProgressEvent[] = []; + const tracker = await h.client(0, { + progressHook: (e) => init.push(e as ProgressEvent), + }); + const ctx = context(tracker); + const partial = UniversalTxV2Codec.fromPartial({ + id: 'delayed-record', + universalStatus: UniversalTxStatus.PC_EXECUTED_SUCCESS, + pcTx: [ + { + txHash: sent.hash, + status: 'SUCCESS', + sender: wallet, + gasUsed: 0, + blockHeight: Number(root.blockNumber), + errorMsg: '', + }, + ], + }); + expect(detectRouteFromUniversalTxData(partial)).toBe('UOA_TO_PUSH'); + let waiting = false, + polls = 0; + const lookup = jest + .spyOn(ctx.pushClient, 'getUniversalTxByIdV2') + .mockImplementation(async () => { + if (!waiting) return { universalTx: partial }; + polls++; + // Missing record, then root-only record, then the destination observation. + if (polls === 1) return { universalTx: undefined }; + if (polls === 2 || outcome === 'timeout') + return { universalTx: partial }; + return { + universalTx: UniversalTxV2Codec.fromPartial({ + ...partial, + universalStatus: UniversalTxStatus.OUTBOUND_PENDING, + outboundTx: [ + OutboundTxV2Codec.fromPartial({ + destinationChain: CHAIN.ETHEREUM_SEPOLIA, + sender: wallet, + recipient: CEA, + amount: '0', + prc20AssetAddr: token, + externalAssetAddr: token, + outboundStatus: + outcome === 'success' + ? OutboundStatus.OBSERVED + : OutboundStatus.REVERTED, + observedTx: { + txHash: EXTERNAL_HASH, + success: outcome === 'success', + errorMsg: + outcome === 'failed' ? 'fixture destination revert' : '', + blockHeight: 1, + gasFeeUsed: '', + pc20WrapperAddress: '', + }, + }), + ], + }), + }; + }); + const cosmos = jest + .spyOn(ctx.pushClient, 'getCosmosTx') + .mockResolvedValue({ + events: [], + height: Number(root.blockNumber), + txIndex: 0, + code: 0, + transactionHash: sent.hash, + msgResponses: [], + gasWanted: BigInt(0), + gasUsed: BigInt(0), + }); + const signerNonces = await Promise.all( + h.wallets + .slice(0, 2) + .map((signer) => + h.publicClient.getTransactionCount({ + address: signer.account!.address, + blockTag: 'pending', + }) + ) + ); + const replay = await tracker.universal.trackTransaction(sent.hash, { + progressHook: (e) => perCall.push(e), + }); + expect(lookup).toHaveBeenCalledTimes(1); + expect(polls).toBe(0); + expect(replay).toMatchObject({ + from: wallet, + origin: sent.origin, + to: DEST, + data: '0xd09de08a', + route: 'UOA_TO_CEA', + chain: CHAIN.ETHEREUM_SEPOLIA, + }); + expect(replay.agentic).toMatchObject({ wallet, door }); + waiting = true; + const receipt = await replay.wait({ + outboundInitialWaitMs: 0, + outboundPollingIntervalMs: 1, + outboundTimeoutMs: outcome === 'timeout' ? 100 : 1000, + }); + expect(receipt).toMatchObject({ + status: 1, + from: wallet, + externalStatus: outcome, + }); + expect(cosmos).toHaveBeenCalledTimes(1); + expect(polls).toBeGreaterThanOrEqual(outcome === 'timeout' ? 1 : 3); + if (outcome !== 'timeout') + expect(receipt.externalTxHash).toBe(EXTERNAL_HASH); + else expect(receipt.externalTxHash).toBeUndefined(); + const terminal = + outcome === 'success' + ? 'SEND-TX-299-01' + : outcome === 'failed' + ? 'SEND-TX-299-02' + : 'SEND-TX-299-03'; + for (const events of [init, perCall]) { + expect(events.filter((event) => event.id === terminal)).toHaveLength(1); + } + expect(perCall.map((e) => e.id)).toEqual(init.map((e) => e.id)); + // wait reuses the mined root; it does not sign or send a replacement. + expect( + await Promise.all( + h.wallets + .slice(0, 2) + .map((signer) => + h.publicClient.getTransactionCount({ + address: signer.account!.address, + blockTag: 'pending', + }) + ) + ) + ).toEqual(signerNonces); + expect( + (await h.publicClient.getTransaction({ hash: sent.hash as Hex })).input + ).toBe(sent.agentic!.rawData); + } + ); +}); diff --git a/packages/core/__agw-local__/harness.ts b/packages/core/__agw-local__/harness.ts new file mode 100644 index 00000000..22ad9328 --- /dev/null +++ b/packages/core/__agw-local__/harness.ts @@ -0,0 +1,444 @@ +/** + * Local AGW contract harness — REVIEW ONLY. + * + * Starts anvil as a stand-in Push LOCALNET (chainId 9000, the SDK's + * CHAIN_INFO[PUSH_LOCALNET].chainId), deploys the REAL pinned v5 + * contracts (SmartSession, AgentValidator, UniversalRulesPolicy behind a + * TransparentUpgradeableProxy, AGW implementation, AGWFactory behind an + * ERC1967Proxy) from an isolated build prepared by + * scripts/agw-local/prepare.sh, and installs a stub gateway at the + * UniversalGatewayPC precompile address. It registers that deployment as a + * NON-advertised generation so the SDK can be driven end to end. + * + * Limits: no UEA factory / precompiles / Cosmos module, so only Push-EOA + * signers are exercised; the gateway is a stub (pull + burn + fee arithmetic); + * no TSS, relay or destination execution happens. + */ +import { spawn, type ChildProcess } from 'node:child_process'; +import { readFileSync, existsSync } from 'node:fs'; +import { join } from 'node:path'; +import { + createPublicClient, + createWalletClient, + defineChain, + encodeFunctionData, + getAddress, + http, + type Abi, + type Address, + type Hex, + type PublicClient, + type WalletClient, +} from 'viem'; +import { privateKeyToAccount } from 'viem/accounts'; +import { PushChain } from '../src'; +import { CHAIN, PUSH_NETWORK } from '../src/lib/constants/enums'; +import { LIBRARY } from '../src/lib/constants/enums'; +import { + registerAgenticGeneration, + resetAgenticGenerations, + type AgenticGeneration, +} from '../src/lib/agentic/deployments'; + +export const CHAIN_ID = 9000; +export const GATEWAY_PRECOMPILE = getAddress( + '0x00000000000000000000000000000000000000c1' +); +export const EXECUTOR_MODULE = getAddress( + '0x00000000000000000000000000000000000000e1' +); +export const ACCOUNT_ID = 'push.agw.1.0.0'; + +/** Anvil's well-known development keys (public test material, not secrets). */ +export const DEV_KEYS: Hex[] = [ + '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80', + '0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d', + '0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a', + '0x7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6', + '0x47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a', +]; + +export function buildDir(): string { + const dir = process.env['AGW_LOCAL_DIR']; + if (!dir || !existsSync(join(dir, 'out', 'AGW.sol', 'AGW.json'))) { + throw new Error( + 'AGW_LOCAL_DIR must point at a build produced by packages/core/scripts/agw-local/prepare.sh' + ); + } + return dir; +} + +function artifact( + dir: string, + file: string, + name: string +): { abi: Abi; bytecode: Hex } { + const json = JSON.parse( + readFileSync(join(dir, 'out', file, `${name}.json`), 'utf8') + ); + return { abi: json.abi as Abi, bytecode: json.bytecode.object as Hex }; +} + +export interface Harness { + rpcUrl: string; + anvil: ChildProcess; + publicClient: PublicClient; + wallets: WalletClient[]; + generation: AgenticGeneration; + addresses: { + engine: Address; + validator: Address; + rulesPolicy: Address; + walletImplementation: Address; + factory: Address; + universalCore: Address; + gateway: Address; + target: Address; + }; + deploy( + walletIndex: number, + name: string, + file: string, + args?: readonly unknown[] + ): Promise
; + write( + walletIndex: number, + to: Address, + abi: Abi, + functionName: string, + args: readonly unknown[], + value?: bigint + ): Promise; + client( + walletIndex: number, + opts?: { agenticWallet?: Address; progressHook?: (e: unknown) => void } + ): Promise; + readOnlyClient( + walletIndex: number, + opts?: { agenticWallet?: Address } + ): Promise; + stop(): Promise; + dir: string; +} + +const localChain = (rpcUrl: string) => + defineChain({ + id: CHAIN_ID, + name: 'push-localnet-harness', + nativeCurrency: { name: 'PC', symbol: 'PC', decimals: 18 }, + rpcUrls: { default: { http: [rpcUrl] } }, + }); + +async function waitForRpc(url: string, timeoutMs = 20_000): Promise { + const start = Date.now(); + for (;;) { + try { + const res = await fetch(url, { + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify({ + jsonrpc: '2.0', + id: 1, + method: 'eth_chainId', + params: [], + }), + }); + if (res.ok) return; + } catch { + // not yet listening + } + if (Date.now() - start > timeoutMs) + throw new Error(`anvil did not start at ${url}`); + await new Promise((r) => setTimeout(r, 200)); + } +} + +export async function startHarness(port = 18545): Promise { + const dir = buildDir(); + const rpcUrl = `http://127.0.0.1:${port}`; + const anvil = spawn( + 'anvil', + [ + '--port', + String(port), + '--chain-id', + String(CHAIN_ID), + '--hardfork', + 'prague', + '--silent', + ], + { stdio: 'ignore' } + ); + try { + return await deployHarness(dir, rpcUrl, anvil); + } catch (err) { + await stopAnvil(anvil); + throw err; + } +} + +/** Wait for the child to release its port; never leave cleanup to Jest exit. */ +async function stopAnvil(child: ChildProcess): Promise { + if (child.exitCode !== null || child.signalCode !== null) return; + await new Promise((resolve, reject) => { + const killTimer = setTimeout(() => child.kill('SIGKILL'), 2000); + const deadline = setTimeout(() => { + cleanup(); + reject(new Error('Anvil did not exit after SIGTERM/SIGKILL')); + }, 5000); + const cleanup = () => { + clearTimeout(killTimer); + clearTimeout(deadline); + child.off('exit', exited); + }; + const exited = () => { + cleanup(); + resolve(); + }; + child.once('exit', exited); + child.kill('SIGTERM'); + }); +} + +async function deployHarness( + dir: string, + rpcUrl: string, + anvil: ChildProcess +): Promise { + await waitForRpc(rpcUrl); + const chain = localChain(rpcUrl); + const publicClient = createPublicClient({ + chain, + transport: http(rpcUrl), + }) as PublicClient; + const wallets = DEV_KEYS.map((k) => + createWalletClient({ + account: privateKeyToAccount(k), + chain, + transport: http(rpcUrl), + }) + ); + const clients = new Set(); + + const deploy = async ( + walletIndex: number, + name: string, + file: string, + args: readonly unknown[] = [] + ) => { + const art = artifact(dir, file, name); + const hash = await wallets[walletIndex].deployContract({ + abi: art.abi, + bytecode: art.bytecode, + args: args as unknown[], + account: wallets[walletIndex].account!, + chain, + }); + const receipt = await publicClient.waitForTransactionReceipt({ hash }); + if (!receipt.contractAddress) throw new Error(`deploy ${name} failed`); + return getAddress(receipt.contractAddress); + }; + const write = async ( + walletIndex: number, + to: Address, + abi: Abi, + functionName: string, + args: readonly unknown[], + value?: bigint + ) => { + const hash = await wallets[walletIndex].sendTransaction({ + to, + data: encodeFunctionData({ abi, functionName, args: args as unknown[] }), + value, + account: wallets[walletIndex].account!, + chain, + }); + const receipt = await publicClient.waitForTransactionReceipt({ hash }); + if (receipt.status !== 'success') + throw new Error(`${functionName} reverted`); + return hash; + }; + + const admin = wallets[0].account!.address; + const engine = await deploy(0, 'SmartSession', 'SmartSession.sol'); + const validator = await deploy(0, 'AgentValidator', 'AgentValidator.sol'); + const urpLogic = await deploy( + 0, + 'UniversalRulesPolicy', + 'UniversalRulesPolicy.sol' + ); + const urpAbi = artifact( + dir, + 'UniversalRulesPolicy.sol', + 'UniversalRulesPolicy' + ).abi; + const rulesPolicy = await deploy( + 0, + 'TransparentUpgradeableProxy', + 'TransparentUpgradeableProxy.sol', + [ + urpLogic, + admin, + encodeFunctionData({ + abi: urpAbi, + functionName: 'initialize', + args: [GATEWAY_PRECOMPILE, EXECUTOR_MODULE, engine], + }), + ] + ); + const coreLogic = await deploy( + 0, + 'HarnessUniversalCore', + 'HarnessFixtures.sol' + ); + const universalCore = getAddress( + '0x00000000000000000000000000000000000000c0' + ); + await publicClient.request({ + method: 'anvil_setCode' as never, + params: [ + universalCore, + await publicClient.getCode({ address: coreLogic }), + ] as never, + }); + // The stub's storage initializers are not installed by etching code. + await publicClient.request({ + method: 'anvil_setStorageAt' as never, + params: [ + universalCore, + `0x${'00'.repeat(32)}`, + `0x${BigInt(10 ** 15) + .toString(16) + .padStart(64, '0')}`, + ] as never, + }); + await publicClient.request({ + method: 'anvil_setStorageAt' as never, + params: [ + universalCore, + `0x${'00'.repeat(31)}01`, + `0x${BigInt(10 ** 14) + .toString(16) + .padStart(64, '0')}`, + ] as never, + }); + const gatewayImpl = await deploy( + 0, + 'HarnessGatewayPC', + 'HarnessFixtures.sol', + [universalCore] + ); + const gatewayCode = await publicClient.getCode({ address: gatewayImpl }); + await publicClient.request({ + method: 'anvil_setCode' as never, + params: [GATEWAY_PRECOMPILE, gatewayCode] as never, + }); + const walletImplementation = await deploy(0, 'AGW', 'AGW.sol', [ + engine, + rulesPolicy, + validator, + GATEWAY_PRECOMPILE, + ]); + const factoryLogic = await deploy(0, 'AGWFactory', 'AGWFactory.sol'); + const factoryAbi = artifact(dir, 'AGWFactory.sol', 'AGWFactory').abi; + const factory = await deploy(0, 'ERC1967Proxy', 'ERC1967Proxy.sol', [ + factoryLogic, + encodeFunctionData({ + abi: factoryAbi, + functionName: 'initialize', + args: [admin, walletImplementation], + }), + ]); + const target = await deploy(0, 'HarnessTarget', 'HarnessFixtures.sol'); + + resetAgenticGenerations(); + const generation = registerAgenticGeneration({ + id: 'v5', + sourceCommit: '2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb', + network: PUSH_NETWORK.LOCALNET, + advertised: false, + addresses: { + factory, + walletImplementation, + sessionEngine: engine, + rulesPolicy, + sessionValidator: validator, + gateway: GATEWAY_PRECOMPILE, + }, + startBlock: BigInt(0), + accountId: ACCOUNT_ID, + }); + + const signerFor = (walletIndex: number) => + PushChain.utils.signer.toUniversalFromKeypair(wallets[walletIndex], { + chain: CHAIN.PUSH_LOCALNET, + library: LIBRARY.ETHEREUM_VIEM, + }); + + const client = async ( + walletIndex: number, + opts: { agenticWallet?: Address; progressHook?: (e: unknown) => void } = {} + ) => { + const c = await PushChain.initialize(await signerFor(walletIndex), { + network: PUSH_NETWORK.LOCALNET, + rpcUrls: { [CHAIN.PUSH_LOCALNET]: [rpcUrl] }, + ...(opts.agenticWallet ? { agenticWallet: opts.agenticWallet } : {}), + ...(opts.progressHook + ? { progressHook: opts.progressHook as never } + : {}), + }); + clients.add(c); + return c; + }; + + const readOnlyClient = async ( + walletIndex: number, + opts: { agenticWallet?: Address } = {} + ) => { + const c = await PushChain.initialize( + { + address: wallets[walletIndex].account!.address, + chain: CHAIN.PUSH_LOCALNET, + }, + { + network: PUSH_NETWORK.LOCALNET, + rpcUrls: { [CHAIN.PUSH_LOCALNET]: [rpcUrl] }, + ...(opts.agenticWallet ? { agenticWallet: opts.agenticWallet } : {}), + } + ); + clients.add(c); + return c; + }; + + return { + rpcUrl, + anvil, + publicClient, + wallets, + generation, + addresses: { + engine, + validator, + rulesPolicy, + walletImplementation, + factory, + universalCore, + gateway: GATEWAY_PRECOMPILE, + target, + }, + deploy, + write, + client, + readOnlyClient, + dir, + stop: async () => { + await Promise.allSettled([...clients].map((c) => c.accountStatusReady)); + resetAgenticGenerations(); + await stopAnvil(anvil); + }, + }; +} + +export function artifactAbi(dir: string, file: string, name: string): Abi { + return artifact(dir, file, name).abi; +} diff --git a/packages/core/__agw-local__/labels.spec.ts b/packages/core/__agw-local__/labels.spec.ts new file mode 100644 index 00000000..86786d7e --- /dev/null +++ b/packages/core/__agw-local__/labels.spec.ts @@ -0,0 +1,141 @@ +/** Real v5 wallet/factory label state; no bridge or destination simulation. */ +import { decodeEventLog, type Address } from 'viem'; +import { PushChain } from '../src'; +import { v5 } from '../src/lib/agentic/contracts/v5'; +import { AGENTIC_ERROR_CODE } from '../src/lib/agentic/errors'; +import { startHarness, type Harness } from './harness'; + +describe('v5 label SDK against real contracts', () => { + let h: Harness; + let owner: PushChain; + beforeAll(async () => { + h = await startHarness(18565); + owner = await h.client(0); + }); + afterAll(async () => { + await h?.stop(); + }); + const count = (address: Address) => + h.publicClient.readContract({ + address, + abi: v5.abis.wallet, + functionName: 'checkpointCount', + }); + + it('stores custom deploy labels and defaults empty labels per owner index', async () => { + const first = await owner.agentic.create('', { rules: [] }); + const second = await owner.agentic.create('custom', { rules: [] }); + const other = await h.client(2); + const theirs = await other.agentic.create('', { rules: [] }); + expect((await owner.agentic.wallet(first.wallet).info()).label).toBe( + `AGW ${first.index + 1}` + ); + expect((await owner.agentic.wallet(second.wallet).info()).label).toBe( + 'custom' + ); + expect((await other.agentic.wallet(theirs.wallet).info()).label).toBe( + 'AGW 1' + ); + expect(await count(first.wallet)).toBe(BigInt(0)); + }); + + it('renames and resets through public SDK; fresh info/list and checkpoints agree', async () => { + const made = await owner.agentic.create('before', { rules: [] }); + const w = owner.agentic.wallet(made.wallet); + const hook = jest.fn(); + const before = await count(made.wallet); + const tx = await w.setLabel('after', { progressHook: hook }); + const receipt = await tx.wait(); + const labelEvents = receipt.logs.flatMap((log) => { + if (log.address.toLowerCase() !== made.wallet.toLowerCase()) return []; + try { + const ev = decodeEventLog({ + abi: v5.abis.wallet, + data: log.data, + topics: log.topics, + }); + return ev.eventName === 'LabelSet' ? [ev.args.label] : []; + } catch { + return []; + } + }); + expect(labelEvents).toEqual(['after']); + expect((await w.info()).label).toBe('after'); + expect( + (await owner.agentic.list()).wallets.find( + (x) => x.address === made.wallet + )?.label + ).toBe('after'); + expect(await count(made.wallet)).toBe(before + BigInt(1)); + expect(hook).toHaveBeenCalledWith( + expect.objectContaining({ id: 'AGENTIC-TX-199-01' }) + ); + await w.setLabel(''); + expect((await w.info()).label).toBe(`AGW ${made.index + 1}`); + expect(await count(made.wallet)).toBe(before + BigInt(2)); + }); + + it('direct contract rename changes no checkpoint; subsequent SDK reads show it', async () => { + const made = await owner.agentic.create('before', { rules: [] }); + const before = await count(made.wallet); + await h.write(0, made.wallet, v5.abis.wallet, 'setLabel', ['direct']); + expect(await count(made.wallet)).toBe(before); + expect((await owner.agentic.wallet(made.wallet).info()).label).toBe( + 'direct' + ); + }); + + it('accepts exactly 64 UTF-8 bytes and rejects invalid create/rename without changing count or state', async () => { + const unicode = '🙂'.repeat(16); + const made = await owner.agentic.create(unicode, { rules: [] }); + const w = owner.agentic.wallet(made.wallet); + await w.setLabel('a'.repeat(64)); + const before = await count(made.wallet); + const next = await owner.agentic.derive(); + for (const invalid of ['a'.repeat(65), '🙂'.repeat(17)]) { + await expect(w.setLabel(invalid)).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.INVALID_RULE, + }); + await expect( + owner.agentic.create(invalid, { rules: [] }) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.INVALID_RULE }); + await expect( + h.publicClient.simulateContract({ + address: made.wallet, + abi: v5.abis.wallet, + functionName: 'setLabel', + args: [invalid], + account: h.wallets[0].account!.address, + }) + ).rejects.toThrow('LabelTooLong'); + } + expect(await owner.agentic.derive()).toEqual(next); + expect(await count(made.wallet)).toBe(before); + expect((await w.info()).label).toBe('a'.repeat(64)); + }); + + it('non-owner and read-only SDK calls cannot rename; actual contract also rejects non-owner', async () => { + const made = await owner.agentic.create('owner-only', { rules: [] }); + const agent = await h.client(1); + await expect( + agent.agentic.wallet(made.wallet).setLabel('attack') + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.NOT_WALLET_OWNER }); + const ro = await h.readOnlyClient(0); + await expect( + ro.agentic.wallet(made.wallet).setLabel('attack') + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.READ_ONLY }); + await expect( + h.publicClient.simulateContract({ + address: made.wallet, + abi: v5.abis.wallet, + functionName: 'setLabel', + args: ['attack'], + account: h.wallets[1].account!.address, + }) + ).rejects.toThrow('CallerIsNotOwner'); + expect((await owner.agentic.wallet(made.wallet).info()).label).toBe( + 'owner-only' + ); + expect(await count(made.wallet)).toBe(BigInt(0)); + }); +}); diff --git a/packages/core/__agw-local__/setup.ts b/packages/core/__agw-local__/setup.ts new file mode 100644 index 00000000..c35a8fc5 --- /dev/null +++ b/packages/core/__agw-local__/setup.ts @@ -0,0 +1,18 @@ +/** Actual RPC/actions with a local poll interval, not mocked transactions. */ +jest.mock('viem', () => { + const actual = jest.requireActual('viem'); + return { + ...actual, + // viem 2.27 poll() leaves an already-scheduled wait alive after unwatch. + // Its production 4s default needlessly delays local Jest shutdown. Keep + // real receipt/replacement logic, and configure short local polling. + createPublicClient: (options: { + pollingInterval?: number; + [key: string]: unknown; + }) => + actual.createPublicClient({ + ...options, + pollingInterval: options?.pollingInterval ?? 25, + }), + }; +}); diff --git a/packages/core/__agw-local__/svm-backend.spec.ts b/packages/core/__agw-local__/svm-backend.spec.ts new file mode 100644 index 00000000..98e22be9 --- /dev/null +++ b/packages/core/__agw-local__/svm-backend.spec.ts @@ -0,0 +1,549 @@ +/** Internal SVM lifecycle/execution on actual v5 contracts; no Solana/TSS simulation. */ +import { PublicKey } from '@solana/web3.js'; +import { + encodeFunctionData, + encodeErrorResult, + parseAbi, + type Address, + type Hex, +} from 'viem'; +import { CHAIN, type PushChain } from '../src'; +import type { AgenticRuntime } from '../src/lib/agentic/runtime'; +import { Snapshot } from '../src/lib/agentic/reads/snapshot'; +import { readSvmRule } from '../src/lib/agentic/reads/svm'; +import { + grantSvmWire, + prepareSvmReplacement, + replaceSvmWire, + type SvmWireGrant, +} from '../src/lib/agentic/management/svm'; +import { + resolveSvmContext, + type SvmMetadataProvider, +} from '../src/lib/agentic/management/svm-context'; +import { + prepareSvmAgentExecution, + sendSvmAgentWire, +} from '../src/lib/agentic/execution/svm-send'; +import { + registerIdl, + clearRegistry, +} from '../src/lib/orchestrator/svm-idl/registry'; +import { v5 } from '../src/lib/agentic/contracts/v5'; +import { wrapSendError } from '../src/lib/agentic/management/common'; +import { startHarness, type Harness } from './harness'; + +const key = (b: string) => `0x${b.repeat(32)}` as Hex; +const GATEWAY = key('22'), + PROGRAM = key('33'), + MINT = key('44'), + MINT2 = key('55'); +const SPL = 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', + TOKEN2022 = 'TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb'; +const TOKEN = parseAbi([ + 'function mint(address,uint256)', + 'function approve(address,uint256) returns (bool)', + 'function setSourceTokenAddress(string)', + 'function setSourceChainNamespace(string)', +]); +const CORE = parseAbi([ + 'function setGasToken(string,address)', + 'function getOutboundTxGasAndFees(address,uint256) view returns (address,uint256,uint256,uint256,string,uint256)', +]); +const rt = (c: PushChain) => + (c as unknown as { agenticRuntime: AgenticRuntime }).agenticRuntime; +const metadata: SvmMetadataProvider = { + gateway: async (chain) => ({ chainNamespace: chain, program: GATEWAY }), + mint: async (_chain, address) => ({ + mint: address, + tokenProgram: address === MINT2 ? TOKEN2022 : SPL, + }), +}; + +describe('internal prepared SVM backend on v5', () => { + let h: Harness, owner: PushChain, tokens: Address[]; + beforeAll(async () => { + h = await startHarness(18554); + owner = await h.client(0); + tokens = []; + for (const source of ['', MINT, MINT2]) { + const token = await h.deploy(0, 'HarnessPRC20', 'HarnessFixtures.sol', [ + CHAIN.SOLANA_DEVNET, + 9, + ]); + await h.write(0, token, TOKEN, 'setSourceTokenAddress', [source]); + tokens.push(token); + } + await h.write(0, h.addresses.universalCore, CORE, 'setGasToken', [ + CHAIN.SOLANA_DEVNET, + tokens[0], + ]); + }); + afterEach(() => { + jest.restoreAllMocks(); + clearRegistry(); + }); + afterAll(async () => h?.stop()); + const cfg = async (wallet: Address, id: Hex) => + readSvmRule( + await Snapshot.at(rt(owner).reader), + h.generation, + wallet, + id, + rt(owner).pushChainNamespace + ); + function configure(runtime: AgenticRuntime) { + runtime.quoteOutbound = async (token, limit) => { + const [, nativeValueForGas, protocolFee, , , gasLimitUsed] = + await h.publicClient.readContract({ + address: h.addresses.universalCore, + abi: CORE, + functionName: 'getOutboundTxGasAndFees', + args: [token, limit], + }); + return { nativeValueForGas, protocolFee, gasLimitUsed }; + }; + } + async function setup() { + const { wallet } = await owner.agentic.create('svm-backend', { rules: [] }); + const caps = tokens.map((token) => ({ + token, + maxPerCall: BigInt(5), + maxTotal: BigInt(10), + })); + const resolved = await resolveSvmContext( + await Snapshot.at(rt(owner).reader), + wallet, + CHAIN.SOLANA_DEVNET, + caps, + metadata + ); + const terms = { + ...resolved, + validUntil: Math.floor(Date.now() / 1000) + 3600, + maxGasPerCall: BigInt(10) ** BigInt(16), + programs: [ + { + program: PROGRAM, + discriminator: '0x0102030405060708' as Hex, + discriminatorLen: 8, + dataless: false, + maxAccounts: 3, + }, + ], + pins: resolved.ceaAccounts.map((expected, accountIndex) => ({ + ruleIndex: 0, + accountIndex, + expected, + })), + dataPins: [], + }; + const input: SvmWireGrant = { + agent: h.wallets[1].account!.address, + chainNamespace: CHAIN.SOLANA_DEVNET, + terms, + }; + const grant = await grantSvmWire(rt(owner), h.generation, wallet, input); + registerIdl({ + address: new PublicKey(Buffer.from(PROGRAM.slice(2), 'hex')).toBase58(), + metadata: { name: 'fixture', version: '1', spec: '0.1.0' }, + instructions: [ + { + name: 'go', + discriminator: [1, 2, 3, 4, 5, 6, 7, 8], + accounts: [ + { name: 'cea_authority', writable: true }, + ...resolved.ceaAccounts.slice(1).map((k, i) => ({ + name: `ata${i}`, + writable: true, + address: new PublicKey(Buffer.from(k.slice(2), 'hex')).toBase58(), + })), + ], + args: [], + }, + ], + }); + await h.publicClient.waitForTransactionReceipt({ + hash: await h.wallets[4].sendTransaction({ + to: wallet, + value: BigInt(10) ** BigInt(18), + account: h.wallets[4].account!, + chain: h.wallets[4].chain, + }), + }); + for (const token of tokens) { + await h.write(0, token, TOKEN, 'mint', [wallet, BigInt(100)]); + await h.write(0, wallet, v5.abis.wallet, 'execute', [ + key('00'), + v5.packSingle({ + target: token, + value: BigInt(0), + data: encodeFunctionData({ + abi: TOKEN, + functionName: 'approve', + args: [h.addresses.gateway, BigInt(100)], + }), + }), + ]); + } + const agent = await h.client(1); + configure(rt(agent)); + const request = (token = tokens[2], amount = BigInt(5)) => ({ + wallet, + rulesId: grant.rulesId, + token, + amount, + gasLimit: BigInt(200_000), + program: PROGRAM, + instructionData: new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]), + }); + return { wallet, id: grant.rulesId, input, agent, request }; + } + it('reads all source assets/counters/pins losslessly through public SVM reads', async () => { + const s = await setup(), + stored = await cfg(s.wallet, s.id); + expect(stored.config.assets.map((a) => a.token)).toEqual(tokens); + expect(stored.config.assets.map((a) => a.spent)).toEqual([ + BigInt(0), + BigInt(0), + BigInt(0), + ]); + expect(stored.config.pins).toEqual(s.input.terms.pins); + expect(stored.chainNamespace).toBe(CHAIN.SOLANA_DEVNET); + await expect( + owner.agentic.wallet(s.wallet).rules.get(s.id) + ).resolves.toMatchObject({ rule: { format: 'decoded', pins: s.input.terms.pins } }); + }); + it('runs context, IDL, quote, allowance, wrapping and real token pull/burn as the agent', async () => { + const s = await setup(); + const sent = await sendSvmAgentWire( + rt(s.agent), + h.generation, + s.request(), + metadata + ); + expect((await sent.tx.wait()).status).toBe(1); + const root = await h.publicClient.getTransactionReceipt({ + hash: sent.tx.hash as Hex, + }); + expect(root.from).toBe(h.wallets[1].account!.address.toLowerCase()); + expect( + (await cfg(s.wallet, s.id)).config.assets.map((a) => a.spent) + ).toEqual([BigInt(0), BigInt(0), BigInt(5)]); + }); + it('refuses the wrong signer before execute', async () => { + const s = await setup(), + execute = jest.spyOn(rt(owner), 'execute'); + await expect( + prepareSvmAgentExecution(rt(owner), h.generation, s.request(), metadata) + ).rejects.toMatchObject({ code: 'NOT_OWNER_OR_AGENT' }); + expect(execute).not.toHaveBeenCalled(); + }); + it('requires separate allowance and never writes an approval on the agent path', async () => { + const s = await setup(); + await h.write(0, s.wallet, v5.abis.wallet, 'execute', [ + key('00'), + v5.packSingle({ + target: tokens[2], + value: BigInt(0), + data: encodeFunctionData({ + abi: TOKEN, + functionName: 'approve', + args: [h.addresses.gateway, BigInt(0)], + }), + }), + ]); + const execute = jest.spyOn(rt(s.agent), 'execute'); + await expect( + sendSvmAgentWire(rt(s.agent), h.generation, s.request(), metadata) + ).rejects.toMatchObject({ code: 'GATEWAY_ALLOWANCE_INSUFFICIENT' }); + expect(execute).not.toHaveBeenCalled(); + }); + it('atomically replaces and resets every asset, recording five checkpoints', async () => { + const s = await setup(); + await ( + await sendSvmAgentWire(rt(s.agent), h.generation, s.request(), metadata) + ).tx.wait(); + const before = await h.publicClient.readContract({ + address: s.wallet, + abi: v5.abis.wallet, + functionName: 'checkpointCount', + }); + const next = await replaceSvmWire( + rt(owner), + h.generation, + s.wallet, + s.id, + s.input + ); + expect( + (await cfg(s.wallet, next.rulesId)).config.assets.map((a) => a.spent) + ).toEqual([BigInt(0), BigInt(0), BigInt(0)]); + await expect(cfg(s.wallet, s.id)).rejects.toMatchObject({ + code: 'RULE_NOT_FOUND', + }); + expect( + await h.publicClient.readContract({ + address: s.wallet, + abi: v5.abis.wallet, + functionName: 'checkpointCount', + }) + ).toBe(before + BigInt(5)); + }); + it('a second-asset spend after snapshot rolls back revoke/grant/checkpoints', async () => { + const s = await setup(), + prepared = await prepareSvmReplacement( + rt(owner), + h.generation, + s.wallet, + s.id, + s.input + ); + await ( + await sendSvmAgentWire( + rt(s.agent), + h.generation, + s.request(tokens[1]), + metadata + ) + ).tx.wait(); + const before = await h.publicClient.readContract({ + address: s.wallet, + abi: v5.abis.wallet, + functionName: 'checkpointCount', + }); + const error = await rt(owner) + .execute({ to: s.wallet, value: BigInt(0), data: prepared.data }) + .catch(wrapSendError); + expect(error).toMatchObject({ + decodedError: { name: 'AssetSpentMismatch' }, + }); + expect((await cfg(s.wallet, s.id)).config.assets[1].spent).toBe(BigInt(5)); + expect( + await h.publicClient.readContract({ + address: s.wallet, + abi: v5.abis.wallet, + functionName: 'checkpointCount', + }) + ).toBe(before); + }); + it('grant initialization failure after revoke rolls back the old rule', async () => { + const s = await setup(); + const alternate = await h.deploy(0, 'HarnessPRC20', 'HarnessFixtures.sol', [ + CHAIN.SOLANA_DEVNET, + 9, + ]); + const input = { + ...s.input, + terms: { + ...s.input.terms, + assets: [ + { token: alternate, maxPerCall: BigInt(5), maxTotal: BigInt(10) }, + ], + }, + }; + const prepared = await prepareSvmReplacement( + rt(owner), + h.generation, + s.wallet, + s.id, + input + ); + await h.write(0, alternate, TOKEN, 'setSourceChainNamespace', [ + CHAIN.ETHEREUM_SEPOLIA, + ]); + const error = await rt(owner) + .execute({ to: s.wallet, value: BigInt(0), data: prepared.data }) + .catch(wrapSendError); + expect(error).toMatchObject({ decodedError: { name: 'ChainMismatch' } }); + expect((await cfg(s.wallet, s.id)).config.assets).toHaveLength(3); + }); + it('generic owner revocation disables a SVM rule without public decoding', async () => { + const s = await setup(); + await (await owner.agentic.wallet(s.wallet).rules.revoke([s.id])).wait(); + await expect(cfg(s.wallet, s.id)).rejects.toMatchObject({ + code: 'RULE_NOT_FOUND', + }); + }); + it('returns the receipt ID when another owner grant advances the nonce during replacement', async () => { + const s = await setup(), + execute = rt(owner).execute; + let intercepted = false; + rt(owner).execute = async (params, opts) => { + if (!intercepted) { + intercepted = true; + await grantSvmWire(rt(owner), h.generation, s.wallet, s.input); + } + return execute(params, opts); + }; + try { + const next = await replaceSvmWire( + rt(owner), + h.generation, + s.wallet, + s.id, + s.input + ); + expect((await cfg(s.wallet, next.rulesId)).config.assets).toHaveLength(3); + await expect(cfg(s.wallet, s.id)).rejects.toMatchObject({ + code: 'RULE_NOT_FOUND', + }); + } finally { + rt(owner).execute = execute; + } + }); + it.each(['allowance', 'balance', 'revocation'])( + 'on-chain %s change after preflight refuses submission without metering', + async (kind) => { + const s = await setup(), + runtime = rt(s.agent), + original = runtime.execute; + const before = await cfg(s.wallet, s.id); + const nonce = await h.publicClient.getTransactionCount({ + address: h.wallets[1].account!.address, + blockTag: 'pending', + }); + let ticks: bigint | undefined; + runtime.execute = async (params, options) => { + if (kind === 'revocation') + await ( + await owner.agentic.wallet(s.wallet).rules.revoke([s.id]) + ).wait(); + else + await h.write(0, s.wallet, v5.abis.wallet, 'execute', [ + key('00'), + v5.packSingle({ + target: tokens[2], + value: BigInt(0), + data: encodeFunctionData({ + abi: parseAbi([ + 'function approve(address,uint256) returns(bool)', + 'function transfer(address,uint256) returns(bool)', + ]), + functionName: kind === 'allowance' ? 'approve' : 'transfer', + args: [ + kind === 'allowance' + ? h.addresses.gateway + : h.wallets[0].account!.address, + kind === 'allowance' ? BigInt(0) : BigInt(100), + ], + }), + }), + ]); + ticks = await h.publicClient.readContract({ + address: s.wallet, + abi: v5.abis.wallet, + functionName: 'checkpointCount', + }); + return original(params, options); + }; + try { + const error = await sendSvmAgentWire( + runtime, + h.generation, + s.request(), + metadata + ).catch((e) => e); + expect(error.name).toBe('AgenticRevertError'); + if (kind === 'revocation') + expect(error.decodedError?.name).toBe('CallerIsNotAgent'); + else { + const name = kind === 'allowance' ? 'LowAllowance' : 'LowBalance'; + const data = encodeErrorResult({ + abi: parseAbi([`error ${name}()`]), + errorName: name, + }); + expect(error.message).toContain(data); + } + const stored = await h.publicClient.readContract({ + address: h.addresses.rulesPolicy, + abi: v5.abis.policy, + functionName: 'getSvmConfig', + args: [before.configId, s.wallet], + }); + expect(stored.assets.map((a) => a.spent)).toEqual([ + BigInt(0), + BigInt(0), + BigInt(0), + ]); + expect( + await h.publicClient.getTransactionCount({ + address: h.wallets[1].account!.address, + blockTag: 'pending', + }) + ).toBe(nonce); + expect( + await h.publicClient.readContract({ + address: s.wallet, + abi: v5.abis.wallet, + functionName: 'checkpointCount', + }) + ).toBe(ticks); + } finally { + runtime.execute = original; + } + } + ); + it('an RPC outage during rule reads fails before execute or signing', async () => { + const s = await setup(), + runtime = rt(s.agent), + reader = runtime.reader, + read = reader.readContract.bind(reader); + const execute = jest.spyOn(runtime, 'execute'); + const failedReader = { + ...reader, + readContract: async (args: Parameters[0]) => { + if (args.functionName === 'getSvmConfig') + throw new Error('fixture RPC outage'); + return read(args); + }, + }; + const failed = { ...runtime, reader: failedReader }; + await expect( + sendSvmAgentWire(failed, h.generation, s.request(), metadata) + ).rejects.toMatchObject({ code: 'RULE_READ_FAILED' }); + expect(execute).not.toHaveBeenCalled(); + expect( + (await cfg(s.wallet, s.id)).config.assets.map((a) => a.spent) + ).toEqual([BigInt(0), BigInt(0), BigInt(0)]); + }); + it('receipt failure after a mined grant retains the hash and does not retry', async () => { + const s = await setup(), + runtime = rt(owner), + original = runtime.execute; + let hash: Hex | undefined, + submissions = 0; + runtime.execute = async (params, options) => { + submissions++; + const tx = await original(params, options); + hash = tx.hash as Hex; + await h.publicClient.waitForTransactionReceipt({ hash }); + tx.wait = async () => { + throw new Error('fixture receipt outage'); + }; + return tx; + }; + try { + await expect( + grantSvmWire(runtime, h.generation, s.wallet, s.input) + ).rejects.toMatchObject({ + code: 'RECEIPT_UNAVAILABLE', + details: { txHash: expect.any(String) }, + }); + expect(submissions).toBe(1); + expect(hash).toBeDefined(); + expect( + await h.publicClient.readContract({ + address: s.wallet, + abi: v5.abis.wallet, + functionName: 'grantNonce', + }) + ).toBe(BigInt(2)); + expect( + (await h.publicClient.getTransactionReceipt({ hash: hash! })).status + ).toBe('success'); + } finally { + runtime.execute = original; + } + }); +}); diff --git a/packages/core/__agw-local__/svm-differential.spec.ts b/packages/core/__agw-local__/svm-differential.spec.ts new file mode 100644 index 00000000..52026155 --- /dev/null +++ b/packages/core/__agw-local__/svm-differential.spec.ts @@ -0,0 +1,418 @@ +/** Seeded, independent SDK-vs-contract comparisons. No live transport/funding. */ +import { + encodeAbiParameters, + encodeFunctionData, + parseAbi, + type Hex, +} from 'viem'; +import { CHAIN } from '../src/lib/constants/enums'; +import { buildSession, encodeEnvelope } from '../src/lib/agentic/codec/session'; +import { + SVM_TERMS_PARAM, + validateSvmTerms, + type SvmTermsWire, +} from '../src/lib/agentic/codec/svm-terms'; +import { + encodeAgwSvmPayload, + validateAgwSvmPayload, +} from '../src/lib/agentic/execution/svm-payload'; +import { v5 } from '../src/lib/agentic/contracts/v5'; +import { deriveAgwSvmValueAccounts } from '../src/lib/agentic/codec/svm-accounts'; +import { decodeAgenticRevert } from '../src/lib/agentic/revert'; +import { startHarness, type Harness } from './harness'; +const key = (b: string) => `0x${b.repeat(32)}` as Hex; +const GATEWAY = key('22'), + PROGRAM = key('33'); +const TOKEN = parseAbi([ + 'function mint(address,uint256)', + 'function approve(address,uint256) returns(bool)', +]); +const seed = 0x5a17; +let rng = seed; +function random(n: number) { + rng = (Math.imul(rng, 1664525) + 1013904223) >>> 0; + return rng % n; +} +const clone = (t: T): T => structuredClone(t); + +describe('seeded SVM differential validation', () => { + let h: Harness, wallet: `0x${string}`, token: `0x${string}`; + let terms: SvmTermsWire; + beforeAll(async () => { + h = await startHarness(18555); + token = await h.deploy(0, 'HarnessPRC20', 'HarnessFixtures.sol', [ + CHAIN.SOLANA_DEVNET, + 9, + ]); + wallet = ( + await (await h.client(0)).agentic.create('differential', { rules: [] }) + ).wallet; + const derived = deriveAgwSvmValueAccounts(wallet, GATEWAY, []); + terms = { + ...derived, + validUntil: Math.floor(Date.now() / 1000) + 3600, + assets: [{ token, maxPerCall: BigInt(10), maxTotal: BigInt(100) }], + maxGasPerCall: BigInt(10) ** BigInt(16), + programs: [ + { + program: PROGRAM, + discriminator: '0x0100000000000000', + discriminatorLen: 1, + dataless: false, + maxAccounts: 1, + }, + ], + pins: [{ ruleIndex: 0, accountIndex: 0, expected: derived.expectedCEA }], + dataPins: [], + }; + }); + afterAll(async () => h?.stop()); + const session = (t: SvmTermsWire) => + buildSession({ + validator: h.addresses.validator, + rulesPolicy: h.addresses.rulesPolicy, + agent: h.wallets[1].account!.address, + actions: [ + { + target: h.addresses.gateway, + selector: '0x77b86bec', + initData: encodeEnvelope( + CHAIN.SOLANA_DEVNET, + encodeAbiParameters([SVM_TERMS_PARAM], [t]) + ), + }, + ], + }); + + it('grant-shape corpus agrees with the actual URP initializer', async () => { + const cases: { name: string; terms: SvmTermsWire }[] = []; + const add = (name: string, mutate: (t: SvmTermsWire) => void) => { + const t = clone(terms); + mutate(t); + cases.push({ name, terms: t }); + }; + add('base', () => { + /* Keep the baseline unchanged for the first comparison. */ + }); + for (const per of [ + BigInt(0), + BigInt(1), + (BigInt(1) << BigInt(64)) - BigInt(1), + (BigInt(1) << BigInt(256)) - BigInt(1), + ]) + for (const total of [ + BigInt(0), + BigInt(1), + (BigInt(1) << BigInt(64)) - BigInt(1), + (BigInt(1) << BigInt(256)) - BigInt(1), + ]) + add(`caps-${per}-${total}`, (t) => { + t.assets = [{ token, maxPerCall: per, maxTotal: total }]; + }); + add('zero-pc-hard-cap', (t) => { + t.maxGasPerCall = BigInt(0); + }); + add('zero-assets', (t) => { + t.assets = []; + }); + add('duplicate-asset', (t) => { + t.assets = [...t.assets, t.assets[0]]; + }); + add('zero-token', (t) => { + t.assets = [ + { ...t.assets[0], token: '0x0000000000000000000000000000000000000000' }, + ]; + }); + add('empty-programs', (t) => { + t.programs = []; + }); + add('zero-cea', (t) => { + t.expectedCEA = key('00'); + }); + add('zero-gateway', (t) => { + t.gatewayProgram = key('00'); + }); + add('zero-expiry', (t) => { + t.validUntil = 0; + }); + add('no-pins', (t) => { + t.pins = []; + }); + add('duplicate-pin', (t) => { + t.pins = [...t.pins, t.pins[0]]; + }); + add('pin-rule-outside', (t) => { + t.pins[0].ruleIndex = 1; + }); + add('pin-index-outside', (t) => { + t.pins[0].accountIndex = 64; + }); + add('no-cea-coverage', (t) => { + t.ceaAccounts = []; + }); + add('duplicate-cea', (t) => { + t.ceaAccounts = [t.expectedCEA, t.expectedCEA]; + }); + add('forbidden-program', (t) => { + t.programs[0].program = t.gatewayProgram; + }); + add('overlapping-program-rules', (t) => { + t.programs = [...t.programs, { ...t.programs[0] }]; + t.pins = [...t.pins, { ...t.pins[0], ruleIndex: 1 }]; + }); + for (const count of [0, 1, 63, 64, 65]) + add(`account-count-${count}`, (t) => { + t.programs[0].maxAccounts = count; + }); + for (const len of [0, 1, 8, 9]) + add(`tag-len-${len}`, (t) => { + t.programs[0].discriminatorLen = len; + }); + add('dataless', (t) => { + t.programs[0].dataless = true; + t.programs[0].discriminatorLen = 0; + }); + for (let i = 0; i < 64; i++) { + const mode = random(4), + width = [0, 1, 2, 8, 9, 32, 33][random(7)], + fromEnd = Boolean(random(2)); + const offset = [0, 1, width, 1024 - width, 1024, 1025][random(6)]; + add(`pin-seed-${i}`, (t) => { + t.dataPins = [ + { + ruleIndex: 0, + fromEnd, + offset, + offsetB: width, + len: width, + mode, + expected: key('00'), + num: BigInt(mode === 3 ? random(2) : 0), + den: BigInt(mode === 3 ? random(2) : 0), + }, + ]; + }); + } + const mismatches: string[] = []; + let accepted = 0, + rejected = 0; + const now = Number((await h.publicClient.getBlock()).timestamp); + for (const c of cases) { + let sdk = true, + contract = true; + try { + validateSvmTerms(c.terms, now); + } catch { + sdk = false; + } + try { + await h.publicClient.call({ + to: wallet, + data: v5.encodeGrantRules(session(c.terms)), + account: h.wallets[0].account!.address, + }); + } catch (e) { + contract = false; + expect(decodeAgenticRevert(e)).toBeDefined(); + } + if (contract) accepted++; + else rejected++; + if (sdk !== contract) + mismatches.push(c.name + `: sdk=${sdk},contract=${contract}`); + } + expect(accepted).toBeGreaterThan(0); + expect(rejected).toBeGreaterThan(0); + expect(mismatches).toEqual([]); + console.log( + JSON.stringify({ + corpus: 'svm-grant', + seed, + cases: cases.length, + accepted, + rejected, + mismatches, + }) + ); + }); + + it('payload mutation corpus agrees with actual URP authorization and rejects without metering', async () => { + const t = clone(terms); + t.programs[0].maxAccounts = 0; + t.dataPins = [ + { + ruleIndex: 0, + fromEnd: false, + offset: 1, + offsetB: 0, + len: 1, + mode: 1, + expected: `0x${'00'.repeat(31)}05`, + num: BigInt(0), + den: BigInt(0), + }, + ]; + await h.write(0, wallet, v5.abis.wallet, 'grantRules', [session(t)]); + const [id] = await h.publicClient.readContract({ + address: h.addresses.engine, + abi: v5.abis.engine, + functionName: 'getPermissionIDs', + args: [wallet], + }); + await h.publicClient.waitForTransactionReceipt({ + hash: await h.wallets[4].sendTransaction({ + to: wallet, + value: BigInt(10) ** BigInt(18), + account: h.wallets[4].account!, + chain: h.wallets[4].chain, + }), + }); + await h.write(0, token, TOKEN, 'mint', [wallet, BigInt(100)]); + await h.write(0, wallet, v5.abis.wallet, 'execute', [ + key('00'), + v5.packSingle({ + target: token, + value: BigInt(0), + data: encodeFunctionData({ + abi: TOKEN, + functionName: 'approve', + args: [h.addresses.gateway, BigInt(100)], + }), + }), + ]); + const base = encodeAgwSvmPayload( + PROGRAM, + [{ pubkey: t.expectedCEA, isWritable: true }], + new Uint8Array([1, 5]) + ); + const cases: { name: string; payload: Hex }[] = [ + { name: 'base', payload: base }, + ]; + for (const amount of [0, 4, 5, 6, 255]) + cases.push({ + name: `floor-${amount}`, + payload: encodeAgwSvmPayload( + PROGRAM, + [{ pubkey: t.expectedCEA, isWritable: true }], + new Uint8Array([1, amount]) + ), + }); + cases.push({ + name: 'uncovered-cea-alias', + payload: encodeAgwSvmPayload( + PROGRAM, + [ + { pubkey: t.expectedCEA, isWritable: true }, + { pubkey: t.expectedCEA, isWritable: false }, + ], + new Uint8Array([1, 5]) + ), + }); + cases.push({ + name: 'pin-substitution', + payload: encodeAgwSvmPayload( + PROGRAM, + [{ pubkey: key('66'), isWritable: true }], + new Uint8Array([1, 5]) + ), + }); + for (let i = 0; i < 80; i++) { + const bytes = Buffer.from(base.slice(2), 'hex'); + if (i % 4 === 0) + cases.push({ + name: `truncate-${i}`, + payload: `0x${bytes + .subarray(0, random(bytes.length)) + .toString('hex')}`, + }); + else if (i % 4 === 1) + cases.push({ + name: `trailing-${i}`, + payload: `${base}${random(256).toString(16).padStart(2, '0')}` as Hex, + }); + else { + const at = random(bytes.length); + bytes[at] ^= 1 << random(8); + cases.push({ + name: `flip-${i}-${at}`, + payload: `0x${bytes.toString('hex')}`, + }); + } + } + const mismatches: string[] = []; + let accepted = 0, + rejected = 0; + for (const c of cases) { + let sdk = true, + contract = true; + try { + validateAgwSvmPayload(t, PROGRAM, c.payload); + } catch { + sdk = false; + } + const data = encodeFunctionData({ + abi: parseAbi([ + 'function sendUniversalTxOutbound((bytes recipient,address token,uint256 amount,uint256 gasLimit,uint256 gasPrice,uint256 maxPCForGas,bytes payload,address revertRecipient) req) payable', + ]), + functionName: 'sendUniversalTxOutbound', + args: [ + { + recipient: PROGRAM, + token, + amount: BigInt(1), + gasLimit: BigInt(200_000), + gasPrice: BigInt(0), + maxPCForGas: BigInt(10) ** BigInt(15), + payload: c.payload, + revertRecipient: wallet, + }, + ], + }); + try { + await h.publicClient.simulateContract({ + address: wallet, + abi: v5.abis.wallet, + functionName: 'executeAsAgent', + args: [ + id, + key('00'), + v5.packSingle({ + target: h.addresses.gateway, + value: BigInt(11) * BigInt(10) ** BigInt(14), + data, + }), + ], + account: h.wallets[1].account!.address, + }); + } catch (e) { + contract = false; + expect(decodeAgenticRevert(e)).toBeDefined(); + } + if (contract) accepted++; + else rejected++; + if (sdk !== contract) + mismatches.push(c.name + `: sdk=${sdk},contract=${contract}`); + } + expect(accepted).toBeGreaterThan(0); + expect(rejected).toBeGreaterThan(0); + expect(mismatches).toEqual([]); + // Every case used eth_call; even successful probes cannot spend an asset. + expect( + await h.publicClient.readContract({ + address: token, + abi: parseAbi(['function balanceOf(address) view returns(uint256)']), + functionName: 'balanceOf', + args: [wallet], + }) + ).toBe(BigInt(100)); + console.log( + JSON.stringify({ + corpus: 'svm-payload', + seed, + cases: cases.length, + accepted, + rejected, + mismatches, + }) + ); + }); +}); diff --git a/packages/core/__agw-local__/svm-internals.spec.ts b/packages/core/__agw-local__/svm-internals.spec.ts new file mode 100644 index 00000000..24163e4d --- /dev/null +++ b/packages/core/__agw-local__/svm-internals.spec.ts @@ -0,0 +1,328 @@ +/** Actual v5 SVM URP checks on Anvil. No Solana execution/TSS is simulated. */ +import { encodeFunctionData, parseAbi, type Address, type Hex } from 'viem'; +import { CHAIN } from '../src/lib/constants/enums'; +import { buildSession, encodeEnvelope } from '../src/lib/agentic/codec/session'; +import { configId } from '../src/lib/agentic/codec/ids'; +import { + encodeSvmTerms, + SvmDataPinMode, + UINT64_MAX, + type SvmTermsWire, +} from '../src/lib/agentic/codec/svm-terms'; +import { deriveAgwSvmValueAccounts } from '../src/lib/agentic/codec/svm-accounts'; +import { encodeAgwSvmPayload } from '../src/lib/agentic/execution/svm-payload'; +import { composeAgwSvmAction } from '../src/lib/agentic/execution/svm-outbound'; +import { v5, type SvmConfigRead } from '../src/lib/agentic/contracts/v5'; +import { startHarness, type Harness } from './harness'; + +const key = (b: string) => `0x${b.repeat(32)}` as Hex; +const GATEWAY_PROGRAM = key('22'), + PROGRAM = key('33'), + MINT = key('44'); +const TOKEN = parseAbi([ + 'function mint(address,uint256)', + 'function approve(address,uint256) returns (bool)', +]); +const UINT256_MAX = BigInt(2) ** BigInt(256) - BigInt(1); + +describe('internal SVM codec/payloads against actual v5 contracts', () => { + let h: Harness, token: Address; + beforeAll(async () => { + h = await startHarness(18552); + token = await h.deploy(0, 'HarnessPRC20', 'HarnessFixtures.sol', [ + CHAIN.SOLANA_DEVNET, + 9, + ]); + }); + afterAll(async () => { + await h?.stop(); + }); + async function setup( + options: { dataless?: boolean; maxAccounts?: number } = {} + ) { + const owner = await h.client(0), + created = await owner.agentic.create('svm-internal', { rules: [] }); + const wallet = created.wallet; + const derived = deriveAgwSvmValueAccounts(wallet, GATEWAY_PROGRAM, [ + { mint: MINT }, + ]); + const t: SvmTermsWire = { + ...derived, + validUntil: Math.floor(Date.now() / 1000) + 3600, + assets: [{ token, maxPerCall: UINT256_MAX, maxTotal: UINT256_MAX }], + maxGasPerCall: BigInt(10) ** BigInt(16), + programs: [ + { + program: PROGRAM, + discriminator: '0x0100000000000000', + discriminatorLen: options.dataless ? 0 : 1, + dataless: options.dataless ?? false, + maxAccounts: options.maxAccounts ?? 0, + }, + ], + pins: [ + { ruleIndex: 0, accountIndex: 0, expected: derived.expectedCEA }, + { ruleIndex: 0, accountIndex: 1, expected: derived.ceaAccounts[1] }, + ], + dataPins: options.dataless + ? [] + : [ + { + ruleIndex: 0, + fromEnd: true, + offset: 4, + offsetB: 2, + len: 2, + mode: SvmDataPinMode.RATIO_GTE_LE, + expected: key('00'), + num: BigInt(9), + den: BigInt(10), + }, + ], + }; + const session = buildSession({ + validator: h.addresses.validator, + rulesPolicy: h.addresses.rulesPolicy, + agent: h.wallets[1].account!.address, + actions: [ + { + target: h.addresses.gateway, + selector: '0x77b86bec', + initData: encodeEnvelope(CHAIN.SOLANA_DEVNET, encodeSvmTerms(t, 0)), + }, + ], + }); + await h.write(0, wallet, v5.abis.wallet, 'grantRules', [session]); + const [id] = await h.publicClient.readContract({ + address: h.addresses.engine, + abi: v5.abis.engine, + functionName: 'getPermissionIDs', + args: [wallet], + }); + const [action] = await h.publicClient.readContract({ + address: h.addresses.engine, + abi: v5.abis.engine, + functionName: 'getEnabledActions', + args: [wallet, id], + }); + const cid = configId(wallet, id, action); + const cfg = (await h.publicClient.readContract({ + address: h.addresses.rulesPolicy, + abi: v5.abis.policy, + functionName: 'getSvmConfig', + args: [cid, wallet], + })) as SvmConfigRead; + await h.publicClient.waitForTransactionReceipt({ + hash: await h.wallets[4].sendTransaction({ + to: wallet, + value: BigInt(10) ** BigInt(18), + account: h.wallets[4].account!, + chain: h.wallets[4].chain, + }), + }); + await h.write(0, token, TOKEN, 'mint', [wallet, BigInt(100)]); + await h.write(0, wallet, v5.abis.wallet, 'execute', [ + key('00'), + v5.packSingle({ + target: token, + value: BigInt(0), + data: encodeFunctionData({ + abi: TOKEN, + functionName: 'approve', + args: [h.addresses.gateway, BigInt(100)], + }), + }), + ]); + const accounts = [ + { pubkey: t.expectedCEA, isWritable: true }, + { pubkey: t.ceaAccounts[1], isWritable: true }, + ]; + const payload = encodeAgwSvmPayload( + PROGRAM, + accounts, + options.dataless ? new Uint8Array() : new Uint8Array([1, 90, 0, 100, 0]) + ); + const input = { + wallet, + gateway: h.addresses.gateway, + token, + amount: BigInt(5), + recipient: PROGRAM, + payload, + gasLimit: BigInt(200_000), + protocolFee: BigInt(10) ** BigInt(14), + maxPCForGas: BigInt(10) ** BigInt(15), + }; + const call = composeAgwSvmAction(input, cfg, 0); + const simulate = (p: Hex, recipient = PROGRAM, amount = BigInt(5)) => { + const data = encodeFunctionData({ + abi: parseAbi([ + 'function sendUniversalTxOutbound((bytes recipient,address token,uint256 amount,uint256 gasLimit,uint256 gasPrice,uint256 maxPCForGas,bytes payload,address revertRecipient) req) payable', + ]), + functionName: 'sendUniversalTxOutbound', + args: [ + { + recipient, + token, + amount, + gasLimit: BigInt(200_000), + gasPrice: BigInt(0), + maxPCForGas: input.maxPCForGas, + payload: p, + revertRecipient: wallet, + }, + ], + }); + return h.publicClient.simulateContract({ + address: wallet, + abi: v5.abis.wallet, + functionName: 'executeAsAgent', + args: [ + id, + key('00'), + v5.packSingle({ + target: h.addresses.gateway, + value: call.value, + data, + }), + ], + account: h.wallets[1].account!.address, + }); + }; + async function reject( + p: Hex, + name: string, + recipient = PROGRAM, + amount = BigInt(5) + ) { + try { + await simulate(p, recipient, amount); + throw new Error('Expected policy rejection'); + } catch (error) { + const { decodeAgenticRevert } = await import( + '../src/lib/agentic/revert' + ); + expect(decodeAgenticRevert(error)?.name).toBe( + `PolicyCheckReverted(${name})` + ); + } + } + return { + wallet, + id, + cid, + t, + cfg, + accounts, + payload, + call, + simulate, + reject, + }; + } + it('grants SDK-encoded SVM terms and preserves every field/account', async () => { + const { cfg, t } = await setup(); + expect(cfg).toMatchObject({ + initialized: true, + expectedCEA: t.expectedCEA, + gatewayProgram: t.gatewayProgram, + ceaAccounts: t.ceaAccounts, + programs: t.programs, + pins: t.pins, + dataPins: t.dataPins, + assets: [ + { + token, + maxPerCall: UINT256_MAX, + maxTotal: UINT256_MAX, + spent: BigInt(0), + }, + ], + }); + }); + it('the internal composed call passes actual S1–S18 and meters its token', async () => { + const { wallet, id, cid, call } = await setup(); + await h.write(1, wallet, v5.abis.wallet, 'executeAsAgent', [ + id, + key('00'), + v5.packSingle(call), + ]); + const cfg = await h.publicClient.readContract({ + address: h.addresses.rulesPolicy, + abi: v5.abis.policy, + functionName: 'getSvmConfig', + args: [cid, wallet], + }); + expect(cfg.assets[0].spent).toBe(BigInt(5)); + }); + it('account substitution and CEA aliasing are rejected by URP', async () => { + const s = await setup(); + await s.reject( + encodeAgwSvmPayload( + PROGRAM, + [{ ...s.accounts[0], pubkey: key('77') }, s.accounts[1]], + new Uint8Array([1, 90, 0, 100, 0]) + ), + 'SvmAccountPinMismatch' + ); + await s.reject( + encodeAgwSvmPayload( + PROGRAM, + [...s.accounts, s.accounts[0]], + new Uint8Array([1, 90, 0, 100, 0]) + ), + 'CeaAccountAtUnpinnedIndex' + ); + }); + it('relative price floor and recipient/program identity are enforced on-chain', async () => { + const s = await setup(); + await s.reject( + encodeAgwSvmPayload( + PROGRAM, + s.accounts, + new Uint8Array([1, 89, 0, 100, 0]) + ), + 'SvmDataRatioNotMet' + ); + await s.reject(s.payload, 'RecipientTargetMismatch', key('66')); + }); + it('trailing bytes, non-execute IDs and u64 overflow are rejected', async () => { + const s = await setup(); + await s.reject(`${s.payload}00`, 'MalformedSvmPayload'); + const bytes = Buffer.from(s.payload.slice(2), 'hex'); + bytes[bytes.length - 33] = 1; + await s.reject(`0x${bytes.toString('hex')}`, 'SvmInstructionNotExecute'); + await s.reject( + s.payload, + 'AmountExceedsU64', + PROGRAM, + UINT64_MAX + BigInt(1) + ); + }); + it('dataless rules accept only empty instruction data', async () => { + const s = await setup({ dataless: true }); + await expect(s.simulate(s.payload)).resolves.toBeDefined(); + await s.reject( + encodeAgwSvmPayload(PROGRAM, s.accounts, new Uint8Array([1])), + 'ProgramNotAllowed' + ); + }); + it('fixed account counts reject appended accounts and failed calls do not change spend', async () => { + const s = await setup({ maxAccounts: 2 }); + await s.reject( + encodeAgwSvmPayload( + PROGRAM, + [...s.accounts, { pubkey: key('55'), isWritable: false }], + new Uint8Array([1, 90, 0, 100, 0]) + ), + 'SvmAccountCountMismatch' + ); + const cfg = await h.publicClient.readContract({ + address: h.addresses.rulesPolicy, + abi: v5.abis.policy, + functionName: 'getSvmConfig', + args: [s.cid, s.wallet], + }); + expect(cfg.assets[0].spent).toBe(BigInt(0)); + }); +}); diff --git a/packages/core/__agw-local__/svm-public.spec.ts b/packages/core/__agw-local__/svm-public.spec.ts new file mode 100644 index 00000000..1e8c423d --- /dev/null +++ b/packages/core/__agw-local__/svm-public.spec.ts @@ -0,0 +1,528 @@ +/** Public named-IDL API against actual AGW/URP; destination/gateway are fixtures. */ +import { PublicKey } from '@solana/web3.js'; +import type { Idl } from '@coral-xyz/anchor'; +import { + encodeFunctionData, + parseAbi, + zeroAddress, + type Address, + type Hex, +} from 'viem'; +import { CHAIN, PushChain, AgenticRevertError, type SolanaRule } from '../src'; +import type { AgenticRuntime } from '../src/lib/agentic/runtime'; +import { v5 } from '../src/lib/agentic/contracts/v5'; +import { clearRegistry } from '../src/lib/orchestrator/svm-idl/registry'; +import { startHarness, type Harness } from './harness'; +const program = new PublicKey(Buffer.alloc(32, 51)).toBase58(); +const gateway = new PublicKey(Buffer.alloc(32, 34)).toBase58(); +const idl: Idl = { + address: program, + metadata: { name: 'named', version: '1', spec: '0.1.0' }, + instructions: [ + { + name: 'deposit', + discriminator: [1, 2, 3, 4, 5, 6, 7, 8], + accounts: [{ name: 'cea_authority', writable: true }], + args: [{ name: 'amount', type: 'u64' }], + }, + ], +}; +const TOKEN = parseAbi([ + 'function mint(address,uint256)', + 'function setSourceTokenAddress(string)', + 'function approve(address,uint256) returns (bool)', +]); +const CORE = parseAbi(['function setGasToken(string,address)']); +const rt = (c: PushChain) => + (c as unknown as { agenticRuntime: AgenticRuntime }).agenticRuntime; +describe('public Solana IDL rules on actual v5', () => { + let h: Harness, owner: PushChain, token: Address; + beforeAll(async () => { + h = await startHarness(18561); + owner = await h.client(0); + token = await h.deploy(0, 'HarnessPRC20', 'HarnessFixtures.sol', [ + CHAIN.SOLANA_DEVNET, + 9, + ]); + await h.write(0, token, TOKEN, 'setSourceTokenAddress', ['']); + await h.write(0, h.addresses.universalCore, CORE, 'setGasToken', [ + CHAIN.SOLANA_DEVNET, + token, + ]); + configure(owner); + }); + afterAll(async () => { + clearRegistry(); + await h?.stop(); + }); + function configure(client: PushChain) { + Object.assign(rt(client), { + svmMetadata: { + gateway: async (chain: string) => ({ + chainNamespace: chain, + program: gateway, + }), + mint: async () => { + throw new Error('native-only fixture'); + }, + }, + resolvePrc20: () => token, + quoteOutbound: async () => ({ + protocolFee: BigInt(10) ** BigInt(14), + nativeValueForGas: BigInt(10) ** BigInt(15), + gasLimitUsed: BigInt(100000), + }), + }); + } + const rule = (): SolanaRule => ({ + agent: h.wallets[1].account!.address, + chainNamespace: CHAIN.SOLANA_DEVNET, + validUntil: Math.floor(Date.now() / 1000) + 3600, + maxGasPerCall: BigInt(10) ** BigInt(17), + assets: [ + { token: zeroAddress, maxPerCall: BigInt(5), maxTotal: BigInt(10) }, + ], + allowedInstructions: [ + { + program, + instruction: { idl, name: 'deposit' }, + accounts: [{ name: 'cea_authority', expected: { kind: 'walletCEA' } }], + fields: [{ name: 'amount', max: BigInt(5) }], + }, + ], + }); + it('create/get/list/update/revoke use public named inputs and exact stored reads', async () => { + const made = await owner.agentic.create('public-svm', { rules: [rule()] }); + const wallet = owner.agentic.wallet(made.wallet); + const record = await wallet.rules.get(made.rulesIds[0]); + expect(record).not.toHaveProperty('ref'); + expect(record.rule).toMatchObject({ + format: 'decoded', + dataPins: [{ offset: 8, len: 8, mode: 2 }], + }); + expect((await wallet.rules.list()).rules).toHaveLength(1); + const update = await wallet.rules.update({ + rules: [{ rulesId: made.rulesIds[0], rule: rule() }], + }); + expect(update.rules[0].rulesId).not.toBe(made.rulesIds[0]); + await (await wallet.rules.revoke([update.rules[0].rulesId])).wait(); + expect((await wallet.rules.list()).rules).toHaveLength(0); + }); + it('agent public send uses wallet context, mapped errors and replay metadata', async () => { + const made = await owner.agentic.create('public-send', { rules: [rule()] }); + await h.publicClient.waitForTransactionReceipt({ + hash: await h.wallets[4].sendTransaction({ + to: made.wallet, + value: BigInt(10) ** BigInt(18), + account: h.wallets[4].account!, + chain: h.wallets[4].chain, + }), + }); + await h.write(0, token, TOKEN, 'mint', [made.wallet, BigInt(20)]); + await h.write(0, made.wallet, v5.abis.wallet, 'execute', [ + `0x${'00'.repeat(32)}`, + v5.packSingle({ + target: token, + value: BigInt(0), + data: encodeFunctionData({ + abi: TOKEN, + functionName: 'approve', + args: [h.addresses.gateway, BigInt(20)], + }), + }), + ]); + const agent = await h.client(1, { agenticWallet: made.wallet }); + configure(agent); + const data = (n: bigint) => + PushChain.utils.helpers.encodeTxData({ + abi: idl, + functionName: 'deposit', + args: [n], + }); + const tx = await agent.universal.sendTransaction({ + to: { chain: CHAIN.SOLANA_DEVNET, address: program }, + data: data(BigInt(5)), + value: BigInt(5), + }); + expect(tx.from).toBe(made.wallet); + expect(tx.agentic?.destinationInstruction?.data).toBe(data(BigInt(5))); + expect( + (await h.publicClient.getTransactionReceipt({ hash: tx.hash as Hex })) + .status + ).toBe('success'); + const { adaptTrackedResponse } = await import( + '../src/lib/agentic/response' + ); + const raw: typeof tx = { + ...tx, + agentic: undefined, + from: tx.raw!.from, + to: tx.raw!.to, + data: tx.raw!.data, + }; + await adaptTrackedResponse(rt(agent), raw); + expect(raw.agentic?.destinationInstruction).toEqual( + tx.agentic?.destinationInstruction + ); + await expect( + agent.universal.sendTransaction({ + to: { chain: CHAIN.SOLANA_DEVNET, address: program }, + data: data(BigInt(6)), + value: BigInt(5), + }) + ).rejects.toMatchObject({ + name: 'AgenticRevertError', + decodedError: { name: 'PolicyCheckReverted(SvmDataCeilingExceeded)' }, + }); + }); + it('owner sends use the wallet CEA without requiring an agent rule', async () => { + const made = await owner.agentic.create('svm-owner', { rules: [] }); + await h.publicClient.waitForTransactionReceipt({ + hash: await h.wallets[4].sendTransaction({ + to: made.wallet, + value: BigInt(10) ** BigInt(18), + account: h.wallets[4].account!, + chain: h.wallets[4].chain, + }), + }); + const sender = await h.client(0, { agenticWallet: made.wallet }); + configure(sender); + const tx = await sender.universal.sendTransaction({ + to: { chain: CHAIN.SOLANA_DEVNET, address: program }, + data: PushChain.utils.helpers.encodeTxData({ + abi: idl, + functionName: 'deposit', + args: [BigInt(0)], + }), + }); + expect(tx.agentic?.door).toBe('owner'); + expect(tx.agentic?.rulesId).toBeUndefined(); + expect( + (await h.publicClient.getTransactionReceipt({ hash: tx.hash as Hex })) + .status + ).toBe('success'); + }); + it('owner funds-only sends use an empty payload and preserve transfer metadata in replay', async () => { + const made = await owner.agentic.create('svm-owner-transfer', { + rules: [], + }); + await h.publicClient.waitForTransactionReceipt({ + hash: await h.wallets[4].sendTransaction({ + to: made.wallet, + value: BigInt(10) ** BigInt(18), + account: h.wallets[4].account!, + chain: h.wallets[4].chain, + }), + }); + await h.write(0, token, TOKEN, 'mint', [made.wallet, BigInt(10)]); + await h.write(0, made.wallet, v5.abis.wallet, 'execute', [ + `0x${'00'.repeat(32)}`, + v5.packSingle({ + target: token, + value: BigInt(0), + data: encodeFunctionData({ + abi: TOKEN, + functionName: 'approve', + args: [h.addresses.gateway, BigInt(10)], + }), + }), + ]); + const sender = await h.client(0, { agenticWallet: made.wallet }); + configure(sender); + clearRegistry(); // A simple transfer needs no program IDL. + const tx = await sender.universal.sendTransaction({ + to: { chain: CHAIN.SOLANA_DEVNET, address: program }, + value: BigInt(5), + }); + expect(tx.to).toBe('0x' + Buffer.alloc(32, 51).toString('hex')); + expect(tx.value).toBe(BigInt(5)); + expect(tx.agentic?.destinationInstruction).toBeUndefined(); + expect(tx.agentic?.destinationTransfer).toMatchObject({ + token, + amount: BigInt(5), + }); + const raw: typeof tx = { + ...tx, + agentic: undefined, + from: tx.raw!.from, + to: tx.raw!.to, + data: tx.raw!.data, + route: 'UOA_TO_PUSH', + }; + const { adaptTrackedResponse } = await import( + '../src/lib/agentic/response' + ); + await adaptTrackedResponse(rt(sender), raw); + expect(raw.to).toBe(tx.to); + expect(raw.data).toBe('0x'); + expect(raw.value).toBe(BigInt(5)); + expect(raw.agentic?.destinationTransfer).toEqual( + tx.agentic?.destinationTransfer + ); + expect(raw.route).toBe('UOA_TO_CEA'); + const baseReader = rt(sender).reader; + const unavailable = { + ...baseReader, + readContract: async ( + params: Parameters[0] + ) => { + if (params.functionName === 'gasTokenPRC20ByChainNamespace') + throw new Error('historical metadata unavailable'); + return baseReader.readContract(params); + }, + }; + const fallback: typeof tx = { + ...tx, + agentic: undefined, + from: tx.raw!.from, + to: tx.raw!.to, + data: tx.raw!.data, + route: 'UOA_TO_PUSH', + }; + await adaptTrackedResponse( + { network: rt(sender).network, reader: unavailable }, + fallback + ); + expect(fallback.route).toBe('UOA_TO_CEA'); + expect(fallback.agentic?.destinationTransfer).toBeUndefined(); + + expect( + (await h.publicClient.getTransactionReceipt({ hash: tx.hash as Hex })) + .status + ).toBe('success'); + }); + it('actual policy refusals return mapped contract errors and preserve counters', async () => { + const made = await owner.agentic.create('svm-policy-errors', { + rules: [rule()], + }); + await h.publicClient.waitForTransactionReceipt({ + hash: await h.wallets[4].sendTransaction({ + to: made.wallet, + value: BigInt(10) ** BigInt(18), + account: h.wallets[4].account!, + chain: h.wallets[4].chain, + }), + }); + const agent = await h.client(1, { agenticWallet: made.wallet }); + configure(agent); + const handle = owner.agentic.wallet(made.wallet), + before = await handle.rules.get(made.rulesIds[0]); + const error = await agent.universal + .sendTransaction({ + to: { chain: CHAIN.SOLANA_DEVNET, address: program }, + data: PushChain.utils.helpers.encodeTxData({ + abi: idl, + functionName: 'deposit', + args: [BigInt(6)], + }), + }) + .catch((e) => e); + expect(error).toBeInstanceOf(AgenticRevertError); + expect(error.decodedError.name).toBe( + 'PolicyCheckReverted(SvmDataCeilingExceeded)' + ); + expect(await handle.rules.get(made.rulesIds[0])).toEqual(before); + await expect( + agent.universal.sendTransaction({ + to: { chain: CHAIN.SOLANA_DEVNET, address: program }, + value: BigInt(1), + }) + ).rejects.toMatchObject({ code: 'INVALID_RULE' }); + }); + it('SPL and output mints derive protected wallet ATAs through public grants', async () => { + const mint = new PublicKey(Buffer.alloc(32, 68)).toBase58(); + const output = new PublicKey(Buffer.alloc(32, 85)).toBase58(); + const spl = await h.deploy(0, 'HarnessPRC20', 'HarnessFixtures.sol', [ + CHAIN.SOLANA_DEVNET, + 6, + ]); + await h.write(0, spl, TOKEN, 'setSourceTokenAddress', [mint]); + const source = await h.client(0); + configure(source); + Object.assign(rt(source), { + resolvePrc20: () => spl, + svmMetadata: { + gateway: async (chain: string) => ({ + chainNamespace: chain, + program: gateway, + }), + mint: async (_chain: string, address: string) => ({ + mint: address, + tokenProgram: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', + }), + }, + }); + const input = rule(); + input.assets = [{ token: mint, maxPerCall: BigInt(5) }]; + input.outputTokens = [output]; + input.allowedInstructions[0].instruction = { + idl: { + ...idl, + instructions: [ + { + ...idl.instructions[0], + accounts: [ + { name: 'cea_authority' }, + { name: 'inputAta', writable: true }, + { name: 'outputAta', writable: true }, + ], + }, + ], + }, + name: 'deposit', + }; + input.allowedInstructions[0].accounts.push( + { name: 'inputAta', expected: { kind: 'walletATA', token: mint } }, + { name: 'outputAta', expected: { kind: 'walletATA', token: output } } + ); + const made = await source.agentic.create('public-spl', { rules: [input] }); + const read = await source.agentic + .wallet(made.wallet) + .rules.get(made.rulesIds[0]); + if (!('format' in read.rule)) + throw new Error('expected decoded Solana rule'); + expect(read.rule.ceaAccounts).toHaveLength(3); + expect(read.rule.pins.map((p) => p.expected)).toEqual( + read.rule.ceaAccounts + ); + expect(read.rule.assets[0].maxTotal).toBe( + BigInt(2) ** BigInt(256) - BigInt(1) + ); + await h.publicClient.waitForTransactionReceipt({ + hash: await h.wallets[4].sendTransaction({ + to: made.wallet, + value: BigInt(10) ** BigInt(18), + account: h.wallets[4].account!, + chain: h.wallets[4].chain, + }), + }); + await h.write(0, spl, TOKEN, 'mint', [made.wallet, BigInt(10)]); + await h.write(0, made.wallet, v5.abis.wallet, 'execute', [ + `0x${'00'.repeat(32)}`, + v5.packSingle({ + target: spl, + value: BigInt(0), + data: encodeFunctionData({ + abi: TOKEN, + functionName: 'approve', + args: [h.addresses.gateway, BigInt(10)], + }), + }), + ]); + const sender = await h.client(0, { agenticWallet: made.wallet }); + Object.assign(rt(sender), { + svmMetadata: rt(source).svmMetadata, + resolvePrc20: rt(source).resolvePrc20, + quoteOutbound: rt(source).quoteOutbound, + }); + const quote = jest.spyOn(rt(sender), 'quoteOutbound'); + const tx = await sender.universal.sendTransaction({ + to: { chain: CHAIN.SOLANA_DEVNET, address: program }, + funds: { + token: { + address: mint, + symbol: 'MOCK', + decimals: 6, + mechanism: 'approve', + }, + amount: BigInt(5), + }, + }); + expect(tx.value).toBe(BigInt(0)); + expect(tx.agentic?.destinationTransfer).toMatchObject({ + token: spl, + amount: BigInt(5), + }); + expect(quote.mock.calls[0][3]).toMatchObject({ + wallet: made.wallet, + splMintBase58: mint, + burnAmount: BigInt(5), + }); + expect( + (await h.publicClient.getTransactionReceipt({ hash: tx.hash as Hex })) + .status + ).toBe('success'); + }); + it('invalid named input and removed ref never submit a transaction', async () => { + const before = await h.publicClient.getTransactionCount({ + address: h.wallets[0].account!.address, + }); + const r = rule(); + r.allowedInstructions[0].accounts[0].name = 'typo'; + await expect( + owner.agentic.create('invalid', { rules: [r] }) + ).rejects.toThrow('unknown IDL account'); + await expect( + owner.agentic.create('removed-ref', { + rules: [{ ...rule(), ref: `0x${'11'.repeat(32)}` } as never], + }) + ).rejects.toThrow('ref is not supported'); + expect( + await h.publicClient.getTransactionCount({ + address: h.wallets[0].account!.address, + }) + ).toBe(before); + }); + it('the contract rejects an outbound above its PC cap through the same error mapper', async () => { + const input = rule(); + input.maxGasPerCall = BigInt(1); + const made = await owner.agentic.create('svm-pc-cap', { rules: [input] }); + await h.publicClient.waitForTransactionReceipt({ + hash: await h.wallets[4].sendTransaction({ + to: made.wallet, + value: BigInt(10) ** BigInt(18), + account: h.wallets[4].account!, + chain: h.wallets[4].chain, + }), + }); + const agent = await h.client(1, { agenticWallet: made.wallet }); + configure(agent); + const error = await agent.universal + .sendTransaction({ + to: { chain: CHAIN.SOLANA_DEVNET, address: program }, + data: PushChain.utils.helpers.encodeTxData({ + abi: idl, + functionName: 'deposit', + args: [BigInt(0)], + }), + }) + .catch((e) => e); + expect(error).toBeInstanceOf(AgenticRevertError); + expect(error.decodedError.name).toBe( + 'PolicyCheckReverted(PCValueExceedsCap)' + ); + }); + it('expired SVM permissions are refused by the actual contract rather than a local policy check', async () => { + const input = rule(); + input.validUntil = + Number((await h.publicClient.getBlock()).timestamp) + 120; + const made = await owner.agentic.create('svm-expired', { rules: [input] }); + await h.publicClient.waitForTransactionReceipt({ + hash: await h.wallets[4].sendTransaction({ + to: made.wallet, + value: BigInt(10) ** BigInt(18), + account: h.wallets[4].account!, + chain: h.wallets[4].chain, + }), + }); + const agent = await h.client(1, { agenticWallet: made.wallet }); + configure(agent); + await h.publicClient.request({ + method: 'evm_setNextBlockTimestamp' as never, + params: [input.validUntil + 1] as never, + }); + await h.publicClient.request({ method: 'evm_mine' as never }); + const error = await agent.universal + .sendTransaction({ + to: { chain: CHAIN.SOLANA_DEVNET, address: program }, + data: PushChain.utils.helpers.encodeTxData({ + abi: idl, + functionName: 'deposit', + args: [BigInt(0)], + }), + }) + .catch((e) => e); + expect(error).toBeInstanceOf(AgenticRevertError); + expect(error.decodedError.name).toBe('PolicyCheckReverted(RulesExpired)'); + }); +}); diff --git a/packages/core/__agw-local__/v5-multiasset.spec.ts b/packages/core/__agw-local__/v5-multiasset.spec.ts new file mode 100644 index 00000000..0d5f04fe --- /dev/null +++ b/packages/core/__agw-local__/v5-multiasset.spec.ts @@ -0,0 +1,367 @@ +/** Actual v5 AGW/URP/engine. Token/core/gateway and destination lookup are local fixtures; no bridge/TSS proof. */ +import { + encodeFunctionData, + getAddress, + parseAbi, + type Address, + type Hex, +} from 'viem'; +import { CHAIN, type PushChain, type UniversalRule } from '../src'; +import type { AgenticRuntime } from '../src/lib/agentic/runtime'; +import { updateRules } from '../src/lib/agentic/management/rules-write'; +import { createWallet } from '../src/lib/agentic/management/create'; +import { configId } from '../src/lib/agentic/codec/ids'; +import { UINT256_MAX } from '../src/lib/agentic/codec/defaults'; +import { buildSession } from '../src/lib/agentic/codec/session'; +import { + encodeNativeTerms, + nativeRuleToTerms, +} from '../src/lib/agentic/codec/native'; +import { startHarness, type Harness } from './harness'; + +const TOKEN = parseAbi([ + 'function mint(address,uint256)', + 'function approve(address,uint256) returns (bool)', +]); +const CORE = parseAbi([ + 'function setGasToken(string,address)', + 'function getOutboundTxGasAndFees(address,uint256) view returns (address,uint256,uint256,uint256,string,uint256)', +]); +const CHAIN_NS = CHAIN.ETHEREUM_SEPOLIA; +const CEA = getAddress('0x000000000000000000000000000000000000cea1'); +const DEST = getAddress('0x0000000000000000000000000000000000001234'); +const internal = (c: PushChain) => + (c as unknown as { agenticRuntime: AgenticRuntime }).agenticRuntime; + +describe('v5 multi-asset SDK management and execution', () => { + let h: Harness, owner: PushChain, a: Address, b: Address; + beforeAll(async () => { + h = await startHarness(18551); + owner = await h.client(0); + a = await h.deploy(0, 'HarnessPRC20', 'HarnessFixtures.sol', [CHAIN_NS, 6]); + b = await h.deploy(0, 'HarnessPRC20', 'HarnessFixtures.sol', [ + CHAIN_NS, + 18, + ]); + await h.write(0, h.addresses.universalCore, CORE, 'setGasToken', [ + CHAIN_NS, + a, + ]); + configure(internal(owner)); + }); + afterAll(async () => { + await h?.stop(); + }); + function configure(rt: AgenticRuntime) { + // Fixture source token addresses equal fixture PRC20s; production uses the token registry. + rt.resolvePrc20 = (token) => + getAddress(typeof token === 'string' ? token : token?.address ?? a); + rt.resolveCEA = async () => ({ cea: CEA, isDeployed: false }); + rt.quoteOutbound = async (token, limit) => { + const [, nativeValueForGas, protocolFee, , , gasLimitUsed] = + await h.publicClient.readContract({ + address: h.addresses.universalCore, + abi: CORE, + functionName: 'getOutboundTxGasAndFees', + args: [token, limit], + }); + return { nativeValueForGas, protocolFee, gasLimitUsed }; + }; + } + function rule( + assets: UniversalRule['assets'] = [ + { token: a, maxPerCall: BigInt(5), maxTotal: BigInt(7) }, + { token: b, maxPerCall: BigInt(9), maxTotal: BigInt(30) }, + ] + ): UniversalRule { + return { + agent: h.wallets[1].account!.address, + chainNamespace: CHAIN_NS, + assets, + validUntil: Math.floor(Date.now() / 1000) + 3600, + maxGasPerCall: BigInt(10) ** BigInt(16), + allowedCalls: [{ target: DEST, selector: 'increment()' }], + }; + } + async function setup(input = rule()) { + const created = await owner.agentic.create('v5', { rules: [input] }); + const wallet = created.wallet, + id = created.rulesIds[0]; + await h.publicClient.waitForTransactionReceipt({ + hash: await h.wallets[4].sendTransaction({ + account: h.wallets[4].account!, + chain: h.wallets[4].chain, + to: wallet, + value: BigInt(10) ** BigInt(18), + }), + }); + for (const token of [a, b]) { + await h.write(0, token, TOKEN, 'mint', [wallet, BigInt(1000)]); + const w = await h.client(0, { agenticWallet: wallet }); + await ( + await w.universal.sendTransaction({ + to: token, + data: encodeFunctionData({ + abi: TOKEN, + functionName: 'approve', + args: [h.addresses.gateway, BigInt(1000)], + }), + }) + ).wait(); + } + const agent = await h.client(1, { agenticWallet: wallet }); + configure(internal(agent)); + const send = (token: Address, amount: bigint) => + agent.universal.sendTransaction({ + to: { address: DEST, chain: CHAIN_NS }, + funds: { + amount, + token: { + symbol: 'fixture', + decimals: 6, + address: token, + mechanism: 'approve', + }, + }, + data: [{ to: DEST, data: '0xd09de08a', value: BigInt(0) }], + }); + return { wallet, id, agent, send }; + } + async function waitPush( + tx: ReturnType + ) { + const response = await tx; + return h.publicClient.waitForTransactionReceipt({ + hash: response.hash as Hex, + }); + } + async function stored(wallet: Address, id: Hex) { + const [action] = await h.publicClient.readContract({ + address: h.addresses.engine, + abi: h.generation.contracts.abis.engine, + functionName: 'getEnabledActions', + args: [wallet, id], + }); + return h.publicClient.readContract({ + address: h.addresses.rulesPolicy, + abi: h.generation.contracts.abis.policy, + functionName: 'getConfig', + args: [configId(wallet, id, action), wallet], + }); + } + it('public create encodes two ordered assets; public get reconstructs source-token caps', async () => { + const { wallet, id } = await setup(); + expect((await stored(wallet, id)).assets.map((x) => x.token)).toEqual([ + a, + b, + ]); + expect( + (await owner.agentic.wallet(wallet).rules.get(id)).rule + ).toMatchObject({ + assets: [ + { token: a, maxPerCall: BigInt(5), maxTotal: BigInt(7) }, + { token: b, maxPerCall: BigInt(9), maxTotal: BigInt(30) }, + ], + }); + }); + it('a token from the wrong chain fails before deployment', async () => { + const wrong = await h.deploy(0, 'HarnessPRC20', 'HarnessFixtures.sol', [ + 'eip155:1', + 6, + ]); + const count = await h.publicClient.readContract({ + address: h.addresses.factory, + abi: h.generation.contracts.abis.factory, + functionName: 'walletCount', + args: [h.wallets[0].account!.address], + }); + await expect( + owner.agentic.create('wrong-chain', { + rules: [rule([{ token: wrong, maxPerCall: BigInt(1) }])], + }) + ).rejects.toMatchObject({ code: 'ASSET_CHAIN_MISMATCH' }); + expect( + await h.publicClient.readContract({ + address: h.addresses.factory, + abi: h.generation.contracts.abis.factory, + functionName: 'walletCount', + args: [h.wallets[0].account!.address], + }) + ).toBe(count); + }); + it('a same-chain registry identity mismatch fails before deployment', async () => { + const rt = internal(owner); + const resolve = rt.resolvePrc20; + rt.resolvePrc20 = () => b; + try { + await expect( + owner.agentic.create('wrong-identity', { + rules: [rule([{ token: a, maxPerCall: BigInt(1) }])], + }) + ).rejects.toMatchObject({ code: 'INVALID_RULE' }); + } finally { + rt.resolvePrc20 = resolve; + } + }); + it('both tokens execute under one rule and keep independent counters/limits', async () => { + const { wallet, id, send } = await setup(); + await waitPush(send(a, BigInt(5))); + await expect(send(a, BigInt(3))).rejects.toMatchObject({ + decodedError: { name: 'PolicyCheckReverted(TotalSpendCapExceeded)' }, + }); + await waitPush(send(b, BigInt(9))); + expect((await stored(wallet, id)).assets.map((x) => x.spent)).toEqual([ + BigInt(5), + BigInt(9), + ]); + }); + it('omitted total encodes maxUint256; explicit zero prohibits movement', async () => { + const { wallet, id, send } = await setup( + rule([ + { token: a, maxPerCall: BigInt(5) }, + { token: b, maxPerCall: BigInt(9), maxTotal: BigInt(0) }, + ]) + ); + expect((await stored(wallet, id)).assets.map((x) => x.maxTotal)).toEqual([ + UINT256_MAX, + BigInt(0), + ]); + await expect(send(b, BigInt(1))).rejects.toMatchObject({ + decodedError: { name: 'PolicyCheckReverted(TotalSpendCapExceeded)' }, + }); + expect((await stored(wallet, id)).assets[1].spent).toBe(BigInt(0)); + }); + it('empty user assets grants one zero-cap gas token and executes a call-only request', async () => { + const { wallet, id, send } = await setup(rule([])); + expect((await stored(wallet, id)).assets).toEqual([ + { + token: a, + maxPerCall: BigInt(0), + maxTotal: BigInt(0), + spent: BigInt(0), + }, + ]); + await waitPush(send(a, BigInt(0))); + await expect(send(a, BigInt(1))).rejects.toMatchObject({ + decodedError: { name: 'PolicyCheckReverted(AmountExceedsCap)' }, + }); + }); + it('public update resets both counters in one batch and records five checkpoints', async () => { + const { wallet, id, send } = await setup(); + await waitPush(send(b, BigInt(4))); + const count = await h.publicClient.readContract({ + address: wallet, + abi: h.generation.contracts.abis.wallet, + functionName: 'checkpointCount', + }); + const result = await owner.agentic + .wallet(wallet) + .rules.update({ rules: [{ rulesId: id, rule: rule() }] }); + expect( + (await stored(wallet, result.rules[0].rulesId)).assets.map((x) => x.spent) + ).toEqual([BigInt(0), BigInt(0)]); + expect( + await h.publicClient.readContract({ + address: wallet, + abi: h.generation.contracts.abis.wallet, + functionName: 'checkpointCount', + }) + ).toBe(count + BigInt(5)); + }); + it('spend on the second asset after snapshot rolls back revoke/grant and checkpoint writes', async () => { + const { wallet, id, send } = await setup(); + const base = internal(owner); + const count = await h.publicClient.readContract({ + address: wallet, + abi: h.generation.contracts.abis.wallet, + functionName: 'checkpointCount', + }); + const racing = { + ...base, + execute: async (...args: Parameters) => { + await waitPush(send(b, BigInt(1))); + return base.execute(...args); + }, + }; + await expect( + updateRules(racing, h.generation, wallet, { + rules: [{ rulesId: id, rule: rule() }], + }) + ).rejects.toMatchObject({ decodedError: { name: 'AssetSpentMismatch' } }); + expect( + await h.publicClient.readContract({ + address: h.addresses.engine, + abi: h.generation.contracts.abis.engine, + functionName: 'getPermissionIDs', + args: [wallet], + }) + ).toEqual([id]); + expect( + await h.publicClient.readContract({ + address: wallet, + abi: h.generation.contracts.abis.wallet, + functionName: 'checkpointCount', + }) + ).toBe(count); + }); + it('duplicate grants are allowed, but an ambiguous send fails before any signature', async () => { + const created = await owner.agentic.create('multiple', { + rules: [rule(), rule()], + }); + expect(new Set(created.rulesIds).size).toBe(2); + const agent = await h.client(1, { agenticWallet: created.wallet }); + await expect( + agent.universal.sendTransaction({ + to: { address: DEST, chain: CHAIN_NS }, + data: '0xd09de08a', + }) + ).rejects.toMatchObject({ code: 'AMBIGUOUS_RULE' }); + }); + it('a legacy two-field envelope is refused by the actual v5 grant path', async () => { + const bare = await owner.agentic.create('old-envelope', { rules: [] }); + const { encodeAbiParameters } = await import('viem'); + const terms = nativeRuleToTerms( + { + agent: h.wallets[1].account!.address, + target: h.addresses.target, + selector: 'increment()', + validUntil: Math.floor(Date.now() / 1000) + 3600, + }, + { nowSeconds: 0 } + ).terms; + const session = buildSession({ + validator: h.addresses.validator, + rulesPolicy: h.addresses.rulesPolicy, + agent: h.wallets[1].account!.address, + actions: [ + { + target: terms.target, + selector: terms.selector, + initData: encodeAbiParameters( + [{ type: 'string' }, { type: 'bytes' }], + ['eip155:9000', encodeNativeTerms(terms)] + ), + }, + ], + }); + await expect( + h.publicClient.simulateContract({ + address: bare.wallet, + abi: h.generation.contracts.abis.wallet, + functionName: 'grantRules', + args: [session as never], + account: h.wallets[0].account!.address, + }) + ).rejects.toMatchObject({ + cause: { data: { errorName: 'Panic', args: [BigInt(65)] } }, + }); + expect( + await h.publicClient.readContract({ + address: h.addresses.engine, + abi: h.generation.contracts.abis.engine, + functionName: 'getPermissionIDs', + args: [bare.wallet], + }) + ).toEqual([]); + }); +}); diff --git a/packages/core/__agw-local__/vectors.spec.ts b/packages/core/__agw-local__/vectors.spec.ts new file mode 100644 index 00000000..ed603c0d --- /dev/null +++ b/packages/core/__agw-local__/vectors.spec.ts @@ -0,0 +1,220 @@ +/** + * Contract-generated vectors for the pure AGW codecs. Every `expected` value + * below is computed BY THE PINNED CONTRACTS (pure engine/factory views, or + * state read back after a real grant), never by the SDK under test. + * + * AGW_WRITE_VECTORS=1 → (re)write src/lib/agentic/__fixtures__/v5-vectors.json + * otherwise → assert the committed file still matches the contracts + */ +import { execSync } from 'node:child_process'; +import { readFileSync, writeFileSync, mkdirSync } from 'node:fs'; +import { join } from 'node:path'; +import { getAddress, numberToHex, type Address, type Hex } from 'viem'; +import { buildSession } from '../src/lib/agentic/codec/session'; +import { agentConfig } from '../src/lib/agentic/codec/ids'; +import { + encodeNativeTerms, + nativeRuleToTerms, +} from '../src/lib/agentic/codec/native'; +import { + encodeEnvelope, + encodeSession, +} from '../src/lib/agentic/codec/session'; +import type { NativeRule } from '../src/lib/agentic/agentic.types'; +import { startHarness, type Harness } from './harness'; + +const FIXTURE = join( + __dirname, + '..', + 'src', + 'lib', + 'agentic', + '__fixtures__', + 'v5-vectors.json' +); +const bigintJson = (v: unknown) => + JSON.stringify( + v, + (_k, x) => (typeof x === 'bigint' ? { $bigint: x.toString() } : x), + 2 + ); + +describe('contract-generated AGW vectors (v5)', () => { + let h: Harness; + beforeAll(async () => { + h = await startHarness(18548); + }); + afterAll(async () => { + await h?.stop(); + }); + + it('matches the committed fixture (or writes it)', async () => { + const pc = h.publicClient; + const gen = h.generation; + const validator = h.addresses.validator; + const agents: Address[] = [ + h.wallets[1].account!.address, + h.wallets[2].account!.address, + getAddress('0x00000000000000000000000000000000000000ff'), + ]; + + // rulesId: SmartSession.getPermissionId is pure over (validator, initData, salt). + const rulesId = []; + for (const agent of agents) { + for (const grantNonce of [ + BigInt(0), + BigInt(1), + BigInt(7), + BigInt(2) ** BigInt(63), + ]) { + const session = { + ...buildSession({ + validator, + agent, + rulesPolicy: h.addresses.rulesPolicy, + actions: [], + }), + salt: numberToHex(grantNonce, { size: 32 }), + }; + const expected = (await pc.readContract({ + address: h.addresses.engine, + abi: gen.contracts.abis.engine, + functionName: 'getPermissionId', + args: [session as never], + })) as Hex; + rulesId.push({ + validator, + agent, + grantNonce, + agentConfig: agentConfig(agent), + expected, + }); + } + } + + // deriveWallet: factory.predictWallet for fresh owners (index 0) and a used owner (0..next). + const deriveWallet = []; + const owners: Address[] = [ + h.wallets[3].account!.address, + getAddress('0x1111111111111111111111111111111111111111'), + ]; + for (const owner of owners) { + const [expected] = (await pc.readContract({ + address: h.addresses.factory, + abi: gen.contracts.abis.factory, + functionName: 'predictWallet', + args: [owner, BigInt(0)], + })) as readonly [Address, boolean]; + deriveWallet.push({ + factory: h.addresses.factory, + walletImplementation: h.addresses.walletImplementation, + owner, + index: 0, + expected, + }); + } + + // Native session round trip: SDK-encoded grant, contract-stored terms and IDs. + const owner = await h.client(0); + const rule: NativeRule = { + agent: agents[0], + target: h.addresses.target, + selector: 'deposit(address,uint256)', + validUntil: 4102444800, // 2100-01-01, fixed so the vector is reproducible + pins: [{ arg: 0, expected: agents[1] }], + amount: { arg: 1, maxPerCall: BigInt(10), maxTotal: BigInt(100) }, + maxValuePerCall: BigInt(5), + maxValueTotal: BigInt(50), + maxCalls: 3, + }; + const created = await owner.agentic.create('vectors', { rules: [rule] }); + const wallet = created.wallet; + const rid = created.rulesIds[0]; + const [actionId] = (await pc.readContract({ + address: h.addresses.engine, + abi: gen.contracts.abis.engine, + functionName: 'getEnabledActions', + args: [wallet, rid], + })) as Hex[]; + const { terms } = nativeRuleToTerms(rule, { nowSeconds: 0 }); + const nativeChain = `eip155:${await pc.getChainId()}`; + const session = buildSession({ + validator, + agent: rule.agent, + rulesPolicy: h.addresses.rulesPolicy, + actions: [ + { + target: terms.target, + selector: terms.selector, + initData: encodeEnvelope(nativeChain, encodeNativeTerms(terms)), + }, + ], + }); + // configId is recovered by searching what the policy accepts: the stored config is only + // initialized under the correct key, so a successful read proves the derivation. + const { configId } = await import('../src/lib/agentic/codec/ids'); + const cid = configId(wallet, rid, actionId); + const stored = (await pc.readContract({ + address: h.addresses.rulesPolicy, + abi: gen.contracts.abis.policy, + functionName: 'getNativeConfig', + args: [cid, wallet], + })) as { + initialized: boolean; + target: Address; + selector: Hex; + pins: readonly { offset: number; expected: Hex }[]; + amount: { offset: number }; + }; + const native = { + rule, + nativeChain, + wallet, + rulesId: rid, + actionId, + configId: cid, + configInitialized: stored.initialized, + storedTarget: stored.target, + storedSelector: stored.selector, + storedPins: stored.pins.map((p) => ({ + offset: Number(p.offset), + expected: p.expected, + })), + storedAmountOffset: Number(stored.amount.offset), + encodedSession: encodeSession(session), + }; + + const vectors = { + provenance: { + agwCommit: h.generation.sourceCommit, + generatedBy: 'packages/core/__agw-local__/vectors.spec.ts', + toolchain: safe( + () => execSync('forge --version').toString().split('\n')[0] + ), + chainId: await pc.getChainId(), + note: 'Addresses are deterministic for a fresh anvil + the harness deploy order.', + }, + rulesId, + deriveWallet, + native, + }; + + if (process.env['AGW_WRITE_VECTORS'] === '1') { + mkdirSync(join(FIXTURE, '..'), { recursive: true }); + writeFileSync(FIXTURE, bigintJson(vectors) + '\n'); + } + const committed = JSON.parse(readFileSync(FIXTURE, 'utf8')); + const { provenance: _a, ...current } = JSON.parse(bigintJson(vectors)); + const { provenance: _b, ...saved } = committed; + expect(current).toEqual(saved); + expect(native.configInitialized).toBe(true); + }); +}); + +function safe(f: () => string): string { + try { + return f(); + } catch { + return 'unknown'; + } +} diff --git a/packages/core/__e2e__/agw-svm-wire/outbound.spec.ts b/packages/core/__e2e__/agw-svm-wire/outbound.spec.ts new file mode 100644 index 00000000..67359498 --- /dev/null +++ b/packages/core/__e2e__/agw-svm-wire/outbound.spec.ts @@ -0,0 +1,174 @@ +/** Internal wire acceptance alongside public Solana coverage. Policy refusals come from URP simulation. */ +import '@e2e/shared/setup'; +import { PushChain } from '../../src'; +import { Keypair, PublicKey, type ParsedTransactionWithMeta } from '@solana/web3.js'; +import bs58 from 'bs58'; +import { bytesToHex, createPublicClient, http, encodeFunctionData, erc20Abi, parseAbi, parseEther, type Address, type Hex } from 'viem'; +import { privateKeyToAccount } from 'viem/accounts'; +import { CHAIN, PUSH_NETWORK } from '../../src/lib/constants/enums'; +import { CHAIN_INFO, getPushViemChain } from '../../src/lib/constants/chain'; +import type { AgenticRuntime } from '../../src/lib/agentic/runtime'; +import { resolveWalletGeneration } from '../../src/lib/agentic/deployments'; +import { Snapshot } from '../../src/lib/agentic/reads/snapshot'; +import { readSvmRule } from '../../src/lib/agentic/reads/svm'; +import { grantSvmWire } from '../../src/lib/agentic/management/svm'; +import { createSvmMetadataProvider } from '../../src/lib/agentic/management/svm-metadata'; +import { resolveSvmContext } from '../../src/lib/agentic/management/svm-context'; +import { sendSvmAgentWire, prepareSvmAgentExecution, type PreparedSvmRequest } from '../../src/lib/agentic/execution/svm-send'; +import { SvmDataPinMode, type SvmTermsWire } from '../../src/lib/agentic/codec/svm-terms'; +import { svmKey } from '../../src/lib/agentic/codec/svm-accounts'; +import { adaptTrackedResponse } from '../../src/lib/agentic/response'; +import { v5 } from '../../src/lib/agentic/contracts/v5'; +import { setupAgw, evmClient, inSeconds, type AgwFixture } from '../agw/_fixture'; +import { loadAgwManifest, verifyAgwManifest } from '../agw/_manifest'; +import { inspectSvmWirePrograms, svmWireConnection, SVM_WIRE_CHAIN, SVM_WIRE_GATEWAY, SVM_WIRE_PROGRAM, SVM_WIRE_COUNTER, decodeWireCounter } from '../shared/agw-svm-preflight'; +import { probeSvmWirePolicies } from '../shared/agw-svm-policy-probe'; + +const d = process.env['AGW_SVM_WIRE_E2E'] === '1' ? describe : describe.skip; +// Load the public entry point before internal modules (the existing harness +// does the same); keeping this runtime use prevents TypeScript erasing it. +if (PushChain.CONSTANTS.CHAIN.SOLANA_DEVNET !== SVM_WIRE_CHAIN) throw new Error('Solana fixture chain mismatch'); +const AMOUNT = BigInt(10_000); // 0.00001 SOL, twice at most per run. +const MAX_PC = parseEther('20'); +const RECEIVE = '0x79f4fa0308e5e101' as Hex; +const DECREMENT = '0x6ae3a83bf81b9665' as Hex; +const ZERO = `0x${'00'.repeat(32)}` as Hex; +const rt = (c: PushChain) => (c as unknown as { agenticRuntime: AgenticRuntime }).agenticRuntime; +const ixData = (disc: Hex, amount: bigint) => { + const b = Buffer.alloc(16); Buffer.from(disc.slice(2), 'hex').copy(b); b.writeBigUInt64LE(amount, 8); return b; +}; + +function transferFromCea(tx: ParsedTransactionWithMeta, cea: string, recipient: string, amount: bigint) { + return tx.meta?.innerInstructions?.some((group) => group.instructions.some((ix) => + 'parsed' in ix && ix.program === 'system' && ix.parsed.type === 'transfer' && + ix.parsed.info.source === cea && ix.parsed.info.destination === recipient && + BigInt(ix.parsed.info.lamports) === amount + )); +} + +d('agw svm wire', () => { + let f: AgwFixture, wallet: Address, token: Address, rulesId: Hex, agent: PushChain; + let gen: Awaited>; + let recipient: PublicKey, cea: PublicKey; + const sol = svmWireConnection(); + const metadata = createSvmMetadataProvider({ [SVM_WIRE_CHAIN]: { + gatewayProgram: SVM_WIRE_GATEWAY, rpcUrls: CHAIN_INFO[SVM_WIRE_CHAIN].defaultRPC, + } }, (url) => svmWireConnection(url)); + const accounts = (failure = false) => failure + ? [{ pubkey: svmKey(SVM_WIRE_COUNTER.toBase58()), isWritable: true }, { pubkey: svmKey(cea.toBase58()), isWritable: false }] + : [{ pubkey: svmKey(SVM_WIRE_COUNTER.toBase58()), isWritable: true }, { pubkey: svmKey(recipient.toBase58()), isWritable: true }, { pubkey: svmKey(cea.toBase58()), isWritable: true }, { pubkey: ZERO, isWritable: false }]; + const request = (failure = false): PreparedSvmRequest => ({ wallet, rulesId, token, amount: AMOUNT, gasLimit: BigInt(0), + program: SVM_WIRE_PROGRAM, instructionData: ixData(failure ? DECREMENT : RECEIVE, failure ? BigInt(1) : AMOUNT), accounts: accounts(failure) }); + const stored = () => Snapshot.at(rt(f.owner).reader).then((snap) => readSvmRule(snap, gen, wallet, rulesId, rt(f.owner).pushChainNamespace)); + + beforeAll(async () => { + // Every cluster/program check runs before setupAgw can fund anything. + const preflight = await inspectSvmWirePrograms(sol); + const key = process.env['SOLANA_PRIVATE_KEY']; + if (!key) throw new Error('SOLANA_PRIVATE_KEY is needed only to identify the owned recipient'); + try { recipient = Keypair.fromSecretKey(bs58.decode(key)).publicKey; } + catch { recipient = Keypair.fromSecretKey(Uint8Array.from(JSON.parse(key))).publicKey; } + const destination = await sol.getAccountInfo(recipient); + if (!destination || destination.executable || !destination.owner.equals(PublicKey.default)) throw new Error('Owned recipient must be an existing System account'); + if (parseEther(process.env['AGW_E2E_AGENT_PC'] ?? '0.5') > parseEther('0.5')) throw new Error('Wire suite agent funding is bounded to 0.5 PC'); + const manifest = loadAgwManifest(); + if (manifest.network !== PUSH_NETWORK.TESTNET_DONUT) throw new Error('Wire suite is restricted to Donut'); + const push = createPublicClient({ chain: getPushViemChain(CHAIN.PUSH_TESTNET_DONUT), transport: http(CHAIN_INFO[CHAIN.PUSH_TESTNET_DONUT].defaultRPC[0]) }); + await verifyAgwManifest(push, manifest); + const ownerKey = process.env['PUSH_PRIVATE_KEY'] as Hex | undefined; + if (!ownerKey) throw new Error('PUSH_PRIVATE_KEY is required'); + const ownerAddress = privateKeyToAccount(ownerKey).address; + token = await push.readContract({ address: '0x00000000000000000000000000000000000000C0', + abi: parseAbi(['function gasTokenPRC20ByChainNamespace(string) view returns (address)']), + functionName: 'gasTokenPRC20ByChainNamespace', args: [SVM_WIRE_CHAIN] }); + const ownerTokens = await push.readContract({ address: token, abi: erc20Abi, functionName: 'balanceOf', args: [ownerAddress] }); + if (ownerTokens < AMOUNT * BigInt(2)) throw new Error('Push owner needs 0.00002 pSOL for this bounded suite'); + if (await push.getBalance({ address: ownerAddress }) < parseEther('45')) throw new Error('Push owner needs 45 PC to cover bounded setup and outbound budgets'); + f = await setupAgw(); + f.evidence('svm-wire-program-preflight', preflight); + wallet = (await f.owner.agentic.create('e2e-internal-svm-wire', { rules: [] })).wallet; + gen = await resolveWalletGeneration(rt(f.owner).reader, f.manifest.network, wallet); + const resolved = await resolveSvmContext(await Snapshot.at(rt(f.owner).reader), wallet, SVM_WIRE_CHAIN, + [{ token, maxPerCall: AMOUNT, maxTotal: AMOUNT * BigInt(2) }], metadata); + cea = new PublicKey(Buffer.from(resolved.expectedCEA.slice(2), 'hex')); + if (cea.toBase58() === preflight.counter.authority) throw new Error('Failure fixture requires a counter authority different from the fresh AGW CEA'); + const terms: SvmTermsWire = { ...resolved, validUntil: inSeconds(7200), maxGasPerCall: MAX_PC, + programs: [RECEIVE, DECREMENT].map((discriminator, i) => ({ program: svmKey(SVM_WIRE_PROGRAM), discriminator, + discriminatorLen: 8, dataless: false, maxAccounts: i === 0 ? 4 : 2 })), + pins: [false, true].flatMap((failure, ruleIndex) => accounts(failure).map((a, accountIndex) => ({ ruleIndex, accountIndex, expected: a.pubkey }))), + dataPins: [AMOUNT, BigInt(1)].map((limit, ruleIndex) => ({ ruleIndex, fromEnd: false, offset: 8, offsetB: 0, len: 8, + mode: SvmDataPinMode.LTE_LE, expected: `0x${limit.toString(16).padStart(64, '0')}`, num: BigInt(0), den: BigInt(0) })), + }; + const grant = await grantSvmWire(rt(f.owner), gen, wallet, { agent: f.agentAddress, chainNamespace: SVM_WIRE_CHAIN, terms }); + rulesId = grant.rulesId; + await f.fundPC(wallet, MAX_PC * BigInt(2) + parseEther('1')); + await (await f.owner.universal.sendTransaction({ to: token, data: encodeFunctionData({ abi: erc20Abi, functionName: 'transfer', args: [wallet, AMOUNT * BigInt(2)] }) })).wait(); + const ownerWallet = await evmClient(process.env['PUSH_PRIVATE_KEY'] as Hex, CHAIN.PUSH_TESTNET_DONUT, f.manifest.network, wallet); + await (await ownerWallet.universal.sendTransaction({ to: token, data: encodeFunctionData({ abi: erc20Abi, functionName: 'approve', args: [f.manifest.addresses.gateway, AMOUNT * BigInt(2)] }) })).wait(); + agent = await f.agent(wallet); + f.evidence('svm-wire-setup', { wallet, rulesId, grantHash: grant.tx.hash, agent: f.agentAddress, recipient: recipient.toBase58(), cea: cea.toBase58(), token, terms, walletPCFunded: MAX_PC * BigInt(2) + parseEther('1'), tokenFunded: AMOUNT * BigInt(2) }); + }, 900_000); + afterAll(() => f?.teardown()); + + it('1. positive outbound: actual CEA transfer and counter execution, receipt and replay', async () => { + const before = decodeWireCounter((await sol.getAccountInfo(SVM_WIRE_COUNTER))!.data).value; + const count = await f.push.readContract({ address: wallet, abi: v5.abis.wallet, functionName: 'checkpointCount' }); + const { tx } = await sendSvmAgentWire(rt(agent), gen, request(), metadata); + f.evidence('svm-wire-positive-submitted', { wallet, rulesId, hash: tx.hash }); + // Existing verified-wallet replay adaptation enables normal outbound wait; + // it uses the gateway wire call as the logical summary, not a new SVM API. + await adaptTrackedResponse(rt(agent), tx); + expect(tx.from).toBe(wallet); expect(tx.route).toBe('UOA_TO_CEA'); + const receipt = await tx.wait({ outboundTimeoutMs: 600_000 }); + f.evidence('svm-wire-positive-receipt', { hash: tx.hash, receipt }); + expect(receipt.status).toBe(1); expect(receipt.externalStatus).toBe('success'); + expect(receipt.from).toBe(wallet); expect(receipt.externalChain).toBe(SVM_WIRE_CHAIN); + const destination = await sol.getParsedTransaction(receipt.externalTxHash!, { commitment: 'confirmed', maxSupportedTransactionVersion: 0 }); + expect(destination).not.toBeNull(); expect(destination!.meta!.err).toBeNull(); + expect(transferFromCea(destination!, cea.toBase58(), recipient.toBase58(), AMOUNT)).toBe(true); + expect(destination!.meta!.innerInstructions?.some((g) => g.instructions.some((ix) => + 'data' in ix && ix.programId.toBase58() === SVM_WIRE_PROGRAM && bytesToHex(bs58.decode(ix.data)) === bytesToHex(ixData(RECEIVE, AMOUNT)) && + ix.accounts.some((a) => a.equals(cea)) + ))).toBe(true); + expect(decodeWireCounter((await sol.getAccountInfo(SVM_WIRE_COUNTER))!.data).value).toBeGreaterThanOrEqual(before + AMOUNT); + expect((await stored()).config.assets[0].spent).toBe(AMOUNT); + expect(await f.push.readContract({ address: wallet, abi: v5.abis.wallet, functionName: 'checkpointCount' })).toBe(count); + const replay = await f.owner.universal.trackTransaction(tx.hash); + expect(replay.from).toBe(wallet); expect(replay.route).toBe('UOA_TO_CEA'); + expect(replay.agentic).toMatchObject({ door: 'agent', rulesId }); + const replayReceipt = await replay.wait({ outboundTimeoutMs: 600_000 }); + expect(replayReceipt.externalTxHash).toBe(receipt.externalTxHash); + f.evidence('svm-wire-positive-destination', { hash: tx.hash, externalTxHash: receipt.externalTxHash, destination, replayReceipt }); + }, 900_000); + + it('2. substituted account and oversized instruction amount fail before submission', async () => { + const base = request(); + const wrong = [...base.accounts!]; wrong[2] = { ...wrong[2], pubkey: svmKey(recipient.toBase58()) }; + const nonce = await f.push.getTransactionCount({ address: f.agentAddress }); + await expect(sendSvmAgentWire(rt(agent), gen, { ...base, accounts: wrong }, metadata)).rejects.toMatchObject({ name: 'AgenticRevertError', decodedError: { name: 'PolicyCheckReverted(SvmAccountPinMismatch)' } }); + await expect(sendSvmAgentWire(rt(agent), gen, { ...base, instructionData: ixData(RECEIVE, AMOUNT + BigInt(1)) }, metadata)).rejects.toMatchObject({ name: 'AgenticRevertError', decodedError: { name: 'PolicyCheckReverted(SvmDataCeilingExceeded)' } }); + const prepared = await prepareSvmAgentExecution(rt(agent), gen, base, metadata); + const policy = await probeSvmWirePolicies(f.push, { from: f.agentAddress, wallet, rulesId, call: prepared.call, blockNumber: await f.push.getBlockNumber() }); + expect(await f.push.getTransactionCount({ address: f.agentAddress })).toBe(nonce); + f.evidence('svm-wire-preflight-refusals', { wallet, rulesId, nonce, policy, transactionsSent: 0 }); + }); + + it('3. destination program failure is classified and does not restore policy spend', async () => { + const prior = (await stored()).config.assets[0].spent; + const { tx } = await sendSvmAgentWire(rt(agent), gen, request(true), metadata); + f.evidence('svm-wire-failure-submitted', { wallet, rulesId, hash: tx.hash }); + await adaptTrackedResponse(rt(agent), tx); + // The observed node rejection lifecycle exceeded ten minutes. Keep the + // failed assertion strict while allowing the bounded terminalization window. + const receipt = await tx.wait({ outboundTimeoutMs: 1_200_000 }); + f.evidence('svm-wire-failure-receipt', { hash: tx.hash, receipt }); + const pushReceipt = await f.push.getTransactionReceipt({ hash: tx.hash as Hex }); + expect(pushReceipt.status).toBe('success'); expect(receipt.externalStatus).toBe('failed'); + expect((await stored()).config.assets[0].spent).toBe(prior + AMOUNT); + if (receipt.externalTxHash) { + const destination = await sol.getParsedTransaction(receipt.externalTxHash, { commitment: 'confirmed', maxSupportedTransactionVersion: 0 }); + expect(destination).not.toBeNull(); expect(destination!.meta!.err).not.toBeNull(); + f.evidence('svm-wire-failure-destination', { hash: tx.hash, externalTxHash: receipt.externalTxHash, destination }); + } + }, 1_500_000); +}); diff --git a/packages/core/__e2e__/agw-svm-wire/replay.spec.ts b/packages/core/__e2e__/agw-svm-wire/replay.spec.ts new file mode 100644 index 00000000..3ea2196c --- /dev/null +++ b/packages/core/__e2e__/agw-svm-wire/replay.spec.ts @@ -0,0 +1,59 @@ +/** Read-only acceptance of recorded wire transactions; no signer or funding required. */ +import { PushChain } from '../../src'; +import { createPublicClient, http, type Hex } from 'viem'; +import { CHAIN_INFO, getPushViemChain } from '../../src/lib/constants/chain'; +import { CHAIN, PUSH_NETWORK } from '../../src/lib/constants/enums'; +import { v5 } from '../../src/lib/agentic/contracts/v5'; +import { chainReaderFromPublicClient } from '../../src/lib/agentic/contracts/reader'; +import { resolveWalletGeneration } from '../../src/lib/agentic/deployments'; +import { Snapshot } from '../../src/lib/agentic/reads/snapshot'; +import { readSvmRule } from '../../src/lib/agentic/reads/svm'; +import { probeSvmWirePolicies } from '../shared/agw-svm-policy-probe'; + +const d = process.env['AGW_SVM_WIRE_REPLAY_E2E'] === '1' ? describe : describe.skip; +const POSITIVE = '0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8' as Hex; +const REJECTED = '0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc' as Hex; +const EXTERNAL = 'kGUaPUfASg9Poo93aMsztHJjUk27MKuRJBfDZK1WP3FFSaXSYcoPcxjUMFyDxaK6aU6mQkZeowSu3MtvK5PXKgK'; + +d('agw svm recorded replay', () => { + const push = createPublicClient({ chain: getPushViemChain(CHAIN.PUSH_TESTNET_DONUT), transport: http(CHAIN_INFO[CHAIN.PUSH_TESTNET_DONUT].defaultRPC[0]) }); + let source: Awaited>; + let decoded: Extract>, { kind: 'executeAsAgent' }>; + let client: PushChain; + beforeAll(async () => { + source = await push.getTransaction({ hash: POSITIVE }); + const call = v5.decodeWalletCall(source.input); + if (!source.to || call?.kind !== 'executeAsAgent') throw new Error('Recorded fixture is not an AGW agent call'); + decoded = call; + client = await PushChain.initialize({ chain: PushChain.CONSTANTS.CHAIN.PUSH_TESTNET_DONUT, address: source.from }, { network: PUSH_NETWORK.TESTNET_DONUT }); + expect(client.isReadMode).toBe(true); + }); + it('1. positive replay retains wallet, signer origin and actual Solana signature', async () => { + const tx = await client.universal.trackTransaction(POSITIVE); + expect(tx.from.toLowerCase()).toBe(source.to!.toLowerCase()); + expect(tx.origin.toLowerCase()).toBe(`eip155:42101:${source.from}`.toLowerCase()); + expect(tx.agentic?.rulesId).toBe(decoded.rulesId); expect(tx.route).toBe('UOA_TO_CEA'); + const receipt = await tx.wait({ outboundTimeoutMs: 30_000 }); + expect(receipt.status).toBe(1); expect(receipt.externalStatus).toBe('success'); expect(receipt.externalTxHash).toBe(EXTERNAL); + }, 120_000); + it('2. later terminal rejection is failed, while the source succeeded and spend remains charged', async () => { + const tx = await client.universal.trackTransaction(REJECTED); + const receipt = await tx.wait({ outboundTimeoutMs: 30_000 }); + expect(receipt.status).toBe(1); expect(receipt.externalStatus).toBe('failed'); + expect(receipt.externalError).toContain('tx not executed on destination chain'); + expect(tx.from.toLowerCase()).toBe(source.to!.toLowerCase()); + // Historical snapshot after the actual refund block, immune to later owner changes. + const reader = chainReaderFromPublicClient(push); + const gen = await resolveWalletGeneration(reader, PUSH_NETWORK.TESTNET_DONUT, source.to!); + const snapshot = new Snapshot(reader, BigInt(23950160)); + const rule = await readSvmRule(snapshot, gen, source.to!, decoded.rulesId, 'eip155:42101'); + expect(rule.config.assets[0].spent).toBe(BigInt(20_000)); + }, 120_000); + it('3. pinned live policy calls refuse account and data mutations without submitting', async () => { + const receipt = await push.getTransactionReceipt({ hash: POSITIVE }); + const result = await probeSvmWirePolicies(push, { from: source.from, wallet: source.to!, rulesId: decoded.rulesId, call: decoded.calls[0], blockNumber: receipt.blockNumber }); + expect(result.transactionsSent).toBe(0); expect(result.observations.map((r) => r.decoded.name)).toEqual([ + 'PolicyCheckReverted(SvmAccountPinMismatch)', 'PolicyCheckReverted(SvmDataCeilingExceeded)', + ]); + }); +}); diff --git a/packages/core/__e2e__/agw/_fixture.ts b/packages/core/__e2e__/agw/_fixture.ts new file mode 100644 index 00000000..649ccbb2 --- /dev/null +++ b/packages/core/__e2e__/agw/_fixture.ts @@ -0,0 +1,138 @@ +/** + * Shared AGW E2E fixture. Everything here is setup: the behaviour under test + * is always exercised through public SDK methods in the specs. + * + * Accounts (never logged): + * PUSH_PRIVATE_KEY Push-native owner (the Push master); pays owner gas, + * wallet PC and the bounded per-run agent funding. + * EVM_PRIVATE_KEY external EVM agent, acting through its Sepolia-origin UEA. + * SOLANA_PRIVATE_KEY Solana-origin agent through its UEA (Push-destination only). + * A fresh Push-native agent key is generated per run and funded with at most + * AGW_E2E_AGENT_PC (default 0.5 PC). Wallets are fresh per run; nothing shared + * is revoked or drained. + */ +import '@e2e/shared/setup'; +import { appendFileSync, mkdirSync } from 'node:fs'; +import { join } from 'node:path'; +import { createPublicClient, createWalletClient, defineChain, http, parseEther, type Address, type Hex, type PublicClient } from 'viem'; +import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts'; +import { PushChain } from '../../src'; +import { CHAIN_INFO } from '../../src/lib/constants/chain'; +import { CHAIN, PUSH_NETWORK } from '../../src/lib/constants/enums'; +import { registerAgenticGeneration, resetAgenticGenerations } from '../../src/lib/agentic/deployments'; +import { createEvmPushClient } from '@e2e/shared/evm-client'; +import { AgwPrerequisiteError, loadAgwManifest, verifyAgwManifest, type AgwManifest } from './_manifest'; + +export const AGW_E2E_ENABLED = process.env['AGW_E2E'] === '1'; + +export interface AgwFixture { + manifest: AgwManifest; + push: PublicClient; + owner: PushChain; + ownerAddress: Address; + agentKey: Hex; + agentAddress: Address; + agent(wallet: Address, progressHook?: (e: unknown) => void): Promise; + fundPC(to: Address, amount: bigint): Promise; + evidence(name: string, data: Record): void; + teardown(): void; +} + +const pushChainFor = (network: PUSH_NETWORK) => + network === PUSH_NETWORK.MAINNET ? CHAIN.PUSH_MAINNET : network === PUSH_NETWORK.LOCALNET ? CHAIN.PUSH_LOCALNET : CHAIN.PUSH_TESTNET_DONUT; + +/** + * Strict prerequisite gate: throws (failing beforeAll, hence every test) when + * the manifest, keys or wiring are missing. A selected agw run can never pass + * without exercising a verified deployment. + */ +export async function setupAgw(): Promise { + const manifest = loadAgwManifest(); + if (manifest.network !== PUSH_NETWORK.TESTNET_DONUT) { + throw new AgwPrerequisiteError('live AGW fixtures require Donut'); + } + const pushKey = process.env['PUSH_PRIVATE_KEY'] as Hex | undefined; + if (!pushKey) throw new AgwPrerequisiteError('PUSH_PRIVATE_KEY is not set'); + const chain = pushChainFor(manifest.network); + const info = CHAIN_INFO[chain]; + const push = createPublicClient({ + chain: defineChain({ + id: Number(info.chainId), + name: 'push', + nativeCurrency: { name: 'PC', symbol: 'PC', decimals: 18 }, + rpcUrls: { default: { http: info.defaultRPC } }, + }), + transport: http(info.defaultRPC[0]), + }) as PublicClient; + await verifyAgwManifest(push, manifest); + resetAgenticGenerations(); + registerAgenticGeneration({ + id: manifest.generation, + sourceCommit: manifest.sourceCommit, + network: manifest.network, + advertised: false, + addresses: manifest.addresses, + startBlock: manifest.startBlock, + accountId: manifest.accountId, + capabilities: manifest.capabilities, + }); + + const { pushClient: owner, account } = await createEvmPushClient({ chain, privateKey: pushKey, network: manifest.network }); + const agentKey = generatePrivateKey(); + const agentAddress = privateKeyToAccount(agentKey).address; + const fundPC = async (to: Address, amount: bigint) => { + const tx = await owner.universal.sendTransaction({ to, value: amount }); + const r = await tx.wait(); + if (r.status !== 1) throw new Error(`funding ${to} failed`); + }; + await fundPC(agentAddress, parseEther(process.env['AGW_E2E_AGENT_PC'] ?? '0.5')); + + const logDir = join(__dirname, '..', '..', 'e2e-logs'); + mkdirSync(logDir, { recursive: true }); + const evidence = (name: string, data: Record) => + appendFileSync( + join(logDir, 'agw-evidence.jsonl'), + JSON.stringify( + { name, at: new Date().toISOString(), network: manifest.network, sourceCommit: manifest.sourceCommit, ...data }, + (_k, v) => (typeof v === 'bigint' ? v.toString() : v) + ) + '\n' + ); + + return { + manifest, + push, + owner, + ownerAddress: account.address, + agentKey, + agentAddress, + agent: (wallet, progressHook) => evmClient(agentKey, chain, manifest.network, wallet, progressHook), + fundPC, + evidence, + teardown: () => resetAgenticGenerations(), + }; +} + +export const inSeconds = (s: number) => Math.floor(Date.now() / 1000) + s; + +/** A client for an EVM key on `origin` (Push-native or external), optionally acting as an AGW. */ +export async function evmClient( + key: Hex, + origin: CHAIN, + network: PUSH_NETWORK, + agenticWallet?: Address, + progressHook?: (e: unknown) => void +): Promise { + const walletClient = createWalletClient({ + account: privateKeyToAccount(key), + transport: http(CHAIN_INFO[origin].defaultRPC[0]), + }); + const signer = await PushChain.utils.signer.toUniversalFromKeypair(walletClient, { + chain: origin, + library: PushChain.CONSTANTS.LIBRARY.ETHEREUM_VIEM, + }); + return PushChain.initialize(signer, { + network, + ...(agenticWallet ? { agenticWallet } : {}), + ...(progressHook ? { progressHook: progressHook as never } : {}), + }); +} diff --git a/packages/core/__e2e__/agw/_manifest.ts b/packages/core/__e2e__/agw/_manifest.ts new file mode 100644 index 00000000..d3dc1efc --- /dev/null +++ b/packages/core/__e2e__/agw/_manifest.ts @@ -0,0 +1,203 @@ +/** + * AGW deployment manifest for live E2E — READ-ONLY. Loaded from the JSON file + * optionally named by AGW_DEPLOYMENT_MANIFEST, otherwise the built-in Donut v5 + * manifest. Code/wiring/version are verified before tests or preflight funding. + * + * Manifest shape: + * { + * "network": "TESTNET_DONUT", + * "generation": "v5", + * "sourceCommit": "<40-hex AGW commit>", + * "startBlock": "", + * "accountId": "push.agw.1.0.0", + * "addresses": { "factory", "walletImplementation", "sessionEngine", + * "rulesPolicy", "sessionValidator", "gateway" }, + * "capabilities": ["nativeRules", ...] // optional; defaults to the generation's + * } + */ +import { readFileSync } from 'node:fs'; +import { + getAddress, + isAddress, + type Address, + type PublicClient, + toFunctionSelector, +} from 'viem'; +import { PUSH_NETWORK } from '../../src/lib/constants/enums'; +import { AgenticCapability } from '../../src/lib/agentic/capabilities'; +import { V5_CAPABILITIES } from '../../src/lib/agentic/deployments'; +import { v5 } from '../../src/lib/agentic/contracts/v5'; +import { + DONUT_V5_ADDRESSES, + DONUT_V5_START_BLOCK, + V5_SOURCE_COMMIT, +} from '../../src/lib/agentic/contracts/donut-v5'; + +export const AGW_PREREQ_HINT = + 'AGW live E2E needs checked v5 wiring, signer keys and testnet funding. ' + + 'The default is the checked Donut v5 manifest; custom manifests must match the v5 source.'; + +export interface AgwManifest { + network: PUSH_NETWORK; + generation: 'v5'; + sourceCommit: string; + startBlock: bigint; + accountId: string; + addresses: { + factory: Address; + walletImplementation: Address; + sessionEngine: Address; + rulesPolicy: Address; + sessionValidator: Address; + gateway: Address; + }; + capabilities: ReadonlySet; +} + +export class AgwPrerequisiteError extends Error { + constructor(reason: string) { + super(`AGW prerequisite not met: ${reason}. ${AGW_PREREQ_HINT}`); + this.name = 'AgwPrerequisiteError'; + } +} + +export function loadAgwManifest( + path = process.env['AGW_DEPLOYMENT_MANIFEST'] +): AgwManifest { + if (!path) + return { + network: PUSH_NETWORK.TESTNET_DONUT, + generation: 'v5', + sourceCommit: V5_SOURCE_COMMIT, + startBlock: DONUT_V5_START_BLOCK, + accountId: 'push.agw.1.0.0', + addresses: DONUT_V5_ADDRESSES, + capabilities: V5_CAPABILITIES, + }; + let raw: Record; + try { + raw = JSON.parse(readFileSync(path, 'utf8')); + } catch (cause) { + throw new AgwPrerequisiteError( + `cannot read manifest ${path}: ${(cause as Error).message}` + ); + } + const network = raw['network'] as PUSH_NETWORK; + if (!Object.values(PUSH_NETWORK).includes(network)) + throw new AgwPrerequisiteError(`unknown network ${String(network)}`); + if (raw['generation'] !== v5.id) { + throw new AgwPrerequisiteError( + `generation ${String(raw['generation'])} has no SDK adapter` + ); + } + if (raw['sourceCommit'] !== V5_SOURCE_COMMIT) { + throw new AgwPrerequisiteError( + 'sourceCommit must match the supported v5 source pin' + ); + } + const a = (raw['addresses'] ?? {}) as Record; + const keys = [ + 'factory', + 'walletImplementation', + 'sessionEngine', + 'rulesPolicy', + 'sessionValidator', + 'gateway', + ] as const; + for (const k of keys) { + if (!isAddress(a[k] ?? '', { strict: false })) + throw new AgwPrerequisiteError(`addresses.${k} is missing or invalid`); + } + const caps = Array.isArray(raw['capabilities']) + ? new Set( + (raw['capabilities'] as string[]).map((c) => { + if (!V5_CAPABILITIES.has(c as AgenticCapability)) + throw new AgwPrerequisiteError(`unknown capability ${c}`); + return c as AgenticCapability; + }) + ) + : V5_CAPABILITIES; + return { + network, + generation: 'v5', + sourceCommit: raw['sourceCommit'], + startBlock: BigInt(String(raw['startBlock'] ?? '0')), + accountId: String(raw['accountId'] ?? 'push.agw.1.0.0'), + addresses: Object.fromEntries( + keys.map((k) => [k, getAddress(a[k])]) + ) as AgwManifest['addresses'], + capabilities: caps, + }; +} + +/** Read-only on-chain check that the manifest's wiring is what it claims. */ +export async function verifyAgwManifest( + client: PublicClient, + m: AgwManifest +): Promise { + const read = ( + address: Address, + abi: readonly unknown[], + functionName: string + ) => + client.readContract({ + address, + abi: abi as never, + functionName: functionName as never, + } as never) as Promise; + for (const [name, addr] of Object.entries(m.addresses)) { + if (name === 'gateway') continue; // a precompile may report no code + const code = await client.getCode({ address: addr }); + if (!code || code === '0x') + throw new AgwPrerequisiteError(`${name} ${addr} has no code`); + } + const impl = getAddress( + (await read( + m.addresses.factory, + v5.abis.factory, + 'walletImplementation' + )) as string + ); + if (impl !== m.addresses.walletImplementation) { + throw new AgwPrerequisiteError( + `factory implementation is ${impl}, manifest says ${m.addresses.walletImplementation}` + ); + } + const implementationCode = await client.getCode({ address: impl }); + for (const signature of [ + 'label()', + 'setLabel(string)', + 'initializeAccount(string)', + ]) { + if (!implementationCode?.includes(toFunctionSelector(signature).slice(2))) { + throw new AgwPrerequisiteError( + `implementation is missing the v5 ${signature} selector` + ); + } + } + const wiring: [string, Address][] = [ + ['SESSION_ENGINE', m.addresses.sessionEngine], + ['RULES_POLICY', m.addresses.rulesPolicy], + ['SESSION_VALIDATOR', m.addresses.sessionValidator], + ['UNIVERSAL_GATEWAY_PC', m.addresses.gateway], + ]; + for (const [fn, expected] of wiring) { + const got = getAddress((await read(impl, v5.abis.wallet, fn)) as string); + if (got !== expected) + throw new AgwPrerequisiteError( + `implementation ${fn} is ${got}, manifest says ${expected}` + ); + } + const policyVersion = await read( + m.addresses.rulesPolicy, + v5.abis.policy, + 'version' + ); + if (policyVersion !== '3.1.0') + throw new AgwPrerequisiteError( + `unsupported URP version ${String(policyVersion)}` + ); + const accountId = (await read(impl, v5.abis.wallet, 'accountId')) as string; + if (accountId !== m.accountId) + throw new AgwPrerequisiteError(`implementation accountId is ${accountId}`); +} diff --git a/packages/core/__e2e__/agw/create.spec.ts b/packages/core/__e2e__/agw/create.spec.ts new file mode 100644 index 00000000..177f7201 --- /dev/null +++ b/packages/core/__e2e__/agw/create.spec.ts @@ -0,0 +1,87 @@ +/** + * Scenario 1 — create: bare wallet and wallet with rules. Strictly gated on a + * verified AGW deployment manifest (see _manifest.ts); beforeAll throws when + * it is missing so a selected run cannot pass vacuously. + */ +import { getAddress, type Address } from 'viem'; +import { v5 } from '../../src/lib/agentic/contracts/v5'; +import { + AGW_E2E_ENABLED, + inSeconds, + setupAgw, + type AgwFixture, +} from './_fixture'; + +const d = AGW_E2E_ENABLED ? describe : describe.skip; + +d('agw create', () => { + let f: AgwFixture; + beforeAll(async () => { + f = await setupAgw(); + }, 300_000); + afterAll(() => f?.teardown()); + + it('1. bare wallet: factory records the owner and index, no rules, no implicit funding', async () => { + const before = await f.owner.agentic.derive(); + const created = await f.owner.agentic.create('e2e-bare', { rules: [] }); + expect(created.wallet).toBe(before.address); + expect(created.index).toBe(before.index); + expect(created.rulesIds).toEqual([]); + const factoryAbi = v5.abis.factory; + const [ownerOf, indexOf, balance] = await Promise.all([ + f.push.readContract({ + address: f.manifest.addresses.factory, + abi: factoryAbi, + functionName: 'ownerOf', + args: [created.wallet], + }), + f.push.readContract({ + address: f.manifest.addresses.factory, + abi: factoryAbi, + functionName: 'indexOf', + args: [created.wallet], + }), + f.push.getBalance({ address: created.wallet }), + ]); + expect(getAddress(ownerOf as Address)).toBe(f.ownerAddress); + expect(Number(indexOf)).toBe(created.index); + expect(balance).toBe(BigInt(0)); + const info = await f.owner.agentic.wallet(created.wallet).info(); + expect(info).toMatchObject({ + label: 'e2e-bare', + deployed: true, + rulesCount: 0, + owner: f.ownerAddress, + }); + f.evidence('create-bare', { + wallet: created.wallet, + index: created.index, + tx: created.tx.hash, + block: created.tx.blockNumber, + }); + }); + + it('2. wallet with a native rule returns the receipt-confirmed rule ID', async () => { + const created = await f.owner.agentic.create('e2e-rules', { + rules: [ + { + agent: f.agentAddress, + target: f.ownerAddress, + selector: 'value-only', + validUntil: inSeconds(3600), + maxValuePerCall: BigInt(1), + }, + ], + }); + expect(created.rulesIds).toHaveLength(1); + const { rules } = await f.owner.agentic.wallet(created.wallet).rules.list(); + expect(rules.map((r) => r.rulesId)).toEqual(created.rulesIds); + expect(rules[0].agent).toBe(getAddress(f.agentAddress)); + f.evidence('create-with-rule', { + wallet: created.wallet, + rulesIds: created.rulesIds, + tx: created.tx.hash, + atomic: created.tx.atomic, + }); + }); +}); diff --git a/packages/core/__e2e__/agw/funding-allowance.spec.ts b/packages/core/__e2e__/agw/funding-allowance.spec.ts new file mode 100644 index 00000000..064cd5bb --- /dev/null +++ b/packages/core/__e2e__/agw/funding-allowance.spec.ts @@ -0,0 +1,47 @@ +/** + * Scenario 2 — funding and bounded gateway allowance are ordinary sends, + * separate from create, and wallet PC is separate from signer gas. + */ +import { encodeFunctionData, erc20Abi, parseEther, type Address, type Hex } from 'viem'; +import { CHAIN } from '../../src/lib/constants/enums'; +import { getNativePRC20ForChain } from '../../src/lib/orchestrator/internals/helpers'; +import { AGW_E2E_ENABLED, evmClient, setupAgw, type AgwFixture } from './_fixture'; + +const d = AGW_E2E_ENABLED ? describe : describe.skip; + +d('agw funding', () => { + let f: AgwFixture; + let wallet: Address; + beforeAll(async () => { + f = await setupAgw(); + wallet = (await f.owner.agentic.create('e2e-funding', { rules: [] })).wallet; + }, 300_000); + afterAll(() => f?.teardown()); + + it('1. wallet PC is funded by an ordinary send and is separate from the signer balance', async () => { + const signerBefore = await f.push.getBalance({ address: f.ownerAddress }); + await f.fundPC(wallet, parseEther('0.01')); + expect(await f.push.getBalance({ address: wallet })).toBe(parseEther('0.01')); + expect(await f.push.getBalance({ address: f.ownerAddress })).toBeLessThan(signerBefore); + }); + + it('2. owner sets and removes a bounded gateway allowance through the owner door', async () => { + const token = getNativePRC20ForChain(CHAIN.ETHEREUM_SEPOLIA, f.manifest.network); + const ownerAgw = await evmClient(process.env['PUSH_PRIVATE_KEY'] as Hex, CHAIN.PUSH_TESTNET_DONUT, f.manifest.network, wallet); + const allowance = () => + f.push.readContract({ address: token, abi: erc20Abi, functionName: 'allowance', args: [wallet, f.manifest.addresses.gateway] }); + const approve = (amount: bigint) => + ownerAgw.universal.sendTransaction({ + to: token, + data: encodeFunctionData({ abi: erc20Abi, functionName: 'approve', args: [f.manifest.addresses.gateway, amount] }), + }); + const set = await approve(BigInt(1000)); + expect((await set.wait()).status).toBe(1); + expect(set.from).toBe(wallet); + expect(set.agentic?.door).toBe('owner'); + expect(await allowance()).toBe(BigInt(1000)); + await (await approve(BigInt(0))).wait(); + expect(await allowance()).toBe(BigInt(0)); + f.evidence('allowance-set-remove', { wallet, token, setTx: set.hash }); + }); +}); diff --git a/packages/core/__e2e__/agw/identity-gas.spec.ts b/packages/core/__e2e__/agw/identity-gas.spec.ts new file mode 100644 index 00000000..7d79af4e --- /dev/null +++ b/packages/core/__e2e__/agw/identity-gas.spec.ts @@ -0,0 +1,164 @@ +/** + * Scenario 9 — external-key agents act through the UEA for their actual + * origin chain; first-use vs subsequent gas. Solana-ORIGIN agents are covered + * here on a Push destination; Solana-DESTINATION rules are a separate, + * capability-gated feature (see multi-asset-svm.spec.ts). + */ +import { Keypair } from '@solana/web3.js'; +import bs58 from 'bs58'; +import { + createPublicClient, + createWalletClient, + fallback, + getAddress, + http, + parseEther, + type Address, + type Hex, +} from 'viem'; +import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts'; +import { sepolia } from 'viem/chains'; +import { PushChain } from '../../src'; +import { CHAIN } from '../../src/lib/constants/enums'; +import { CHAIN_INFO } from '../../src/lib/constants/chain'; +import { createProgressTracker } from '@e2e/shared/progress-tracker'; +import { + AGW_E2E_ENABLED, + evmClient, + inSeconds, + setupAgw, + type AgwFixture, +} from './_fixture'; + +const d = AGW_E2E_ENABLED ? describe : describe.skip; +const SINK = getAddress('0x000000000000000000000000000000000000dEaD'); + +async function ueaOf(address: string, chain: CHAIN): Promise
{ + const r = await PushChain.utils.account.deriveExecutorAccount( + PushChain.utils.account.toUniversal(address, { chain }), + { + skipNetworkCheck: true, + } + ); + return getAddress(r.address); +} + +d('agw identity', () => { + let f: AgwFixture; + beforeAll(async () => { + f = await setupAgw(); + }, 300_000); + afterAll(() => f?.teardown()); + + const walletFor = async (agent: Address) => { + const created = await f.owner.agentic.create('e2e-identity', { + rules: [ + { + agent, + target: SINK, + selector: 'value-only', + validUntil: inSeconds(3600), + maxValuePerCall: BigInt(1000), + maxValueTotal: BigInt(10_000), + }, + ], + }); + await f.fundPC(created.wallet, parseEther('0.001')); + return created.wallet; + }; + + it('1. an EVM key on Sepolia acts through its Sepolia UEA; origin and account status stay signer-scoped', async () => { + const key = process.env['EVM_PRIVATE_KEY'] as Hex; + if (!key) throw new Error('EVM_PRIVATE_KEY is required'); + const uea = await ueaOf( + privateKeyToAccount(key).address, + CHAIN.ETHEREUM_SEPOLIA + ); + const wallet = await walletFor(uea); + const agent = await evmClient( + key, + CHAIN.ETHEREUM_SEPOLIA, + f.manifest.network, + wallet + ); + expect(agent.universal.account).toBe(wallet); + expect(agent.universal.origin.chain).toBe(CHAIN.ETHEREUM_SEPOLIA); + expect((await agent.getAccountStatus()).uea.deployed).toBe(true); + const tx = await agent.universal.sendTransaction({ + to: SINK, + value: BigInt(1000), + }); + expect((await tx.wait()).status).toBe(1); + expect(tx.from).toBe(wallet); + expect(tx.origin.startsWith('eip155:11155111:')).toBe(true); + f.evidence('external-evm-agent', { wallet, uea, tx: tx.hash }); + }, 600_000); + + it('2. first use of an undeployed external UEA takes the one-time fee lock; the next action pays from the UEA', async () => { + const key = generatePrivateKey(); + const addr = privateKeyToAccount(key).address; + const transport = fallback( + CHAIN_INFO[CHAIN.ETHEREUM_SEPOLIA].defaultRPC.map((url) => http(url)) + ); + const master = createWalletClient({ + account: privateKeyToAccount(process.env['EVM_PRIVATE_KEY'] as Hex), + chain: sepolia, + transport, + }); + const origin = createPublicClient({ chain: sepolia, transport }); + const funded = await master.sendTransaction({ + to: addr, + value: parseEther(process.env['AGW_E2E_FIRST_USE_ETH'] ?? '0.003'), + account: master.account!, + chain: sepolia, + }); + await origin.waitForTransactionReceipt({ hash: funded }); + const uea = await ueaOf(addr, CHAIN.ETHEREUM_SEPOLIA); + const wallet = await walletFor(uea); + const first = createProgressTracker(); + const agent = await evmClient( + key, + CHAIN.ETHEREUM_SEPOLIA, + f.manifest.network, + wallet, + first.hook as (e: unknown) => void + ); + await ( + await agent.universal.sendTransaction({ to: SINK, value: BigInt(1) }) + ).wait(); + expect(first.hasEvent('SEND-TX-105-01')).toBe(true); + const second = createProgressTracker(); + await ( + await agent.universal.sendTransaction( + { to: SINK, value: BigInt(1) }, + { progressHook: second.hook } + ) + ).wait(); + expect(second.hasEvent('SEND-TX-105-01')).toBe(false); + f.evidence('first-use-uea', { wallet, uea }); + }, 900_000); + + it('3. a Solana-origin key acts through its Solana UEA on a Push destination', async () => { + const raw = process.env['SOLANA_PRIVATE_KEY']; + if (!raw) throw new Error('SOLANA_PRIVATE_KEY is required'); + const kp = Keypair.fromSecretKey(bs58.decode(raw)); + const uea = await ueaOf(kp.publicKey.toBase58(), CHAIN.SOLANA_DEVNET); + const wallet = await walletFor(uea); + const signer = await PushChain.utils.signer.toUniversalFromKeypair(kp, { + chain: CHAIN.SOLANA_DEVNET, + library: PushChain.CONSTANTS.LIBRARY.SOLANA_WEB3JS, + }); + const agent = await PushChain.initialize(signer, { + network: f.manifest.network, + agenticWallet: wallet, + }); + const tx = await agent.universal.sendTransaction({ + to: SINK, + value: BigInt(1), + }); + expect((await tx.wait()).status).toBe(1); + expect(tx.from).toBe(wallet); + expect(tx.origin.startsWith('solana:')).toBe(true); + f.evidence('solana-origin-agent', { wallet, uea, tx: tx.hash }); + }, 600_000); +}); diff --git a/packages/core/__e2e__/agw/labels.spec.ts b/packages/core/__e2e__/agw/labels.spec.ts new file mode 100644 index 00000000..8940c1ea --- /dev/null +++ b/packages/core/__e2e__/agw/labels.spec.ts @@ -0,0 +1,461 @@ +/** Public SDK labels against checked Donut v5; fresh wallets only. */ +import { + decodeEventLog, + createWalletClient, + http, + getAddress, + parseEther, + type Address, + type Hex, +} from 'viem'; +import { Keypair } from '@solana/web3.js'; +import bs58 from 'bs58'; +import { CHAIN_INFO, getPushViemChain } from '../../src/lib/constants/chain'; +import { readNativeCounters } from '@e2e/shared/agw-state'; +import { privateKeyToAccount } from 'viem/accounts'; +import { PushChain } from '../../src'; +import { CHAIN } from '../../src/lib/constants/enums'; +import { v5, MODE_SINGLE } from '../../src/lib/agentic/contracts/v5'; +import { decodeAgenticRevert } from '../../src/lib/agentic/revert'; +import { + AGW_E2E_ENABLED, + evmClient, + inSeconds, + setupAgw, + type AgwFixture, +} from './_fixture'; + +const d = AGW_E2E_ENABLED ? describe : describe.skip; +d('agw labels', () => { + let f: AgwFixture; + beforeAll(async () => { + f = await setupAgw(); + }, 300_000); + afterAll(() => f?.teardown()); + const count = (address: Address) => + f.push.readContract({ + address, + abi: v5.abis.wallet, + functionName: 'checkpointCount', + }); + + it('1. default and custom deployment labels are stored and listed', async () => { + const empty = await f.owner.agentic.create('', { rules: [] }); + const custom = await f.owner.agentic.create('e2e-v5-custom', { rules: [] }); + expect((await f.owner.agentic.wallet(empty.wallet).info()).label).toBe( + `AGW ${empty.index + 1}` + ); + expect((await f.owner.agentic.wallet(custom.wallet).info()).label).toBe( + 'e2e-v5-custom' + ); + const { wallets } = await f.owner.agentic.list(); + expect(wallets.find((w) => w.address === empty.wallet)?.label).toBe( + `AGW ${empty.index + 1}` + ); + expect(wallets.find((w) => w.address === custom.wallet)?.label).toBe( + 'e2e-v5-custom' + ); + const renamed = await f.owner.agentic + .wallet(custom.wallet) + .setLabel('isolated-rename'); + expect((await f.owner.agentic.wallet(custom.wallet).info()).label).toBe( + 'isolated-rename' + ); + expect((await f.owner.agentic.wallet(empty.wallet).info()).label).toBe( + `AGW ${empty.index + 1}` + ); + expect(await count(empty.wallet)).toBe(BigInt(0)); + expect(await count(custom.wallet)).toBe(BigInt(1)); + f.evidence('v5-label-default-custom', { + wallets: [empty.wallet, custom.wallet], + indices: [empty.index, custom.index], + hashes: [empty.tx.hash, custom.tx.hash, renamed.hash], + }); + }); + + it('2. owner rename and empty reset update info/list, emit LabelSet and tick the owner door', async () => { + const made = await f.owner.agentic.create('before', { rules: [] }); + const w = f.owner.agentic.wallet(made.wallet), + before = await count(made.wallet), + hook = jest.fn(); + const tx = await w.setLabel('after', { progressHook: hook }); + const receipt = await tx.wait(); + const labels = receipt.logs.flatMap((log) => { + if (log.address.toLowerCase() !== made.wallet.toLowerCase()) return []; + try { + const ev = decodeEventLog({ + abi: v5.abis.wallet, + data: log.data, + topics: log.topics, + }); + return ev.eventName === 'LabelSet' ? [ev.args.label] : []; + } catch { + return []; + } + }); + expect(labels).toEqual(['after']); + expect((await w.info()).label).toBe('after'); + expect( + (await f.owner.agentic.list()).wallets.find( + (x) => x.address === made.wallet + )?.label + ).toBe('after'); + expect(await count(made.wallet)).toBe(before + BigInt(1)); + expect(hook).toHaveBeenCalledWith( + expect.objectContaining({ id: 'AGENTIC-TX-199-01' }) + ); + const reset = await w.setLabel(''); + expect((await w.info()).label).toBe(`AGW ${made.index + 1}`); + expect(await count(made.wallet)).toBe(before + BigInt(2)); + f.evidence('v5-label-rename-reset', { + wallet: made.wallet, + hashes: [tx.hash, reset.hash], + checkpointsBefore: before, + checkpointsAfter: await count(made.wallet), + }); + }); + + it('3. UTF-8 byte boundaries are accepted or rejected without changing wallet state', async () => { + const made = await f.owner.agentic.create('🙂'.repeat(16), { rules: [] }); + const w = f.owner.agentic.wallet(made.wallet); + await w.setLabel('a'.repeat(64)); + const before = await count(made.wallet), + next = await f.owner.agentic.derive(); + for (const label of ['a'.repeat(65), '🙂'.repeat(17)]) { + await expect(w.setLabel(label)).rejects.toMatchObject({ + code: 'INVALID_RULE', + }); + await expect( + f.owner.agentic.create(label, { rules: [] }) + ).rejects.toMatchObject({ code: 'INVALID_RULE' }); + await expect( + f.push.simulateContract({ + address: made.wallet, + abi: v5.abis.wallet, + functionName: 'setLabel', + args: [label], + account: f.ownerAddress, + }) + ).rejects.toThrow('LabelTooLong'); + } + expect(await f.owner.agentic.derive()).toEqual(next); + expect((await w.info()).label).toBe('a'.repeat(64)); + expect(await count(made.wallet)).toBe(before); + f.evidence('v5-label-byte-boundary', { + wallet: made.wallet, + checkpoints: before, + unchangedNextSlot: next.index, + }); + }); + + it('4. an agent cannot rename through either the SDK or the contract', async () => { + const made = await f.owner.agentic.create('owner-only', { + rules: [ + { + agent: f.agentAddress, + target: f.ownerAddress, + selector: 'value-only', + validUntil: inSeconds(3600), + }, + ], + }); + const before = await count(made.wallet); + const agent = await f.agent(made.wallet); + await expect( + agent.agentic.wallet(made.wallet).setLabel('attack') + ).rejects.toMatchObject({ code: 'NOT_WALLET_OWNER' }); + await expect( + f.push.simulateContract({ + address: made.wallet, + abi: v5.abis.wallet, + functionName: 'setLabel', + args: ['attack'], + account: f.agentAddress, + }) + ).rejects.toThrow('CallerIsNotOwner'); + const agentDoorError = await f.push + .simulateContract({ + address: made.wallet, + abi: v5.abis.wallet, + functionName: 'executeAsAgent', + args: [ + made.rulesIds[0], + MODE_SINGLE, + v5.packSingle({ + target: made.wallet, + value: BigInt(0), + data: v5.encodeSetLabel('attack'), + }), + ], + account: f.agentAddress, + }) + .then( + () => undefined, + (error: unknown) => error + ); + // Normal grants cannot authorize wallet-self: the engine rejects the + // absent action policy before the wallet's additional dispatch guard. + expect(decodeAgenticRevert(agentDoorError)).toMatchObject({ + name: 'NoPoliciesSet', + }); + expect((await f.owner.agentic.wallet(made.wallet).info()).label).toBe( + 'owner-only' + ); + expect(await count(made.wallet)).toBe(before); + f.evidence('v5-label-agent-refused', { + wallet: made.wallet, + checkpoints: before, + }); + }); + + it('5. an external EVM owner creates and renames through its UEA', async () => { + const key = process.env['EVM_PRIVATE_KEY'] as Hex; + if (!key) throw new Error('EVM_PRIVATE_KEY is required'); + const origin = privateKeyToAccount(key).address; + const uea = getAddress( + ( + await PushChain.utils.account.deriveExecutorAccount( + PushChain.utils.account.toUniversal(origin, { + chain: CHAIN.ETHEREUM_SEPOLIA, + }), + { skipNetworkCheck: true } + ) + ).address + ); + await f.fundPC(uea, parseEther('3')); + const owner = await evmClient( + key, + CHAIN.ETHEREUM_SEPOLIA, + f.manifest.network + ); + const made = await owner.agentic.create('e2e-uea-before', { rules: [] }); + const w = owner.agentic.wallet(made.wallet); + expect((await w.owner()).owner).toBe(uea); + const before = await count(made.wallet); + const rename = await w.setLabel('e2e-uea-after'); + expect((await w.info()).label).toBe('e2e-uea-after'); + expect( + (await owner.agentic.list()).wallets.find( + (entry) => entry.address === made.wallet + )?.label + ).toBe('e2e-uea-after'); + const reset = await w.setLabel(''); + expect((await w.info()).label).toBe(`AGW ${made.index + 1}`); + expect(await count(made.wallet)).toBe(before + BigInt(2)); + f.evidence('v5-label-uea-owner', { + wallet: made.wallet, + owner: uea, + hashes: [made.tx.hash, rename.hash, reset.hash], + checkpointsBefore: before, + checkpointsAfter: await count(made.wallet), + }); + }); + it('6. a Solana-origin owner creates, renames and resets through its UEA', async () => { + const raw = process.env['SOLANA_PRIVATE_KEY']; + if (!raw) throw new Error('SOLANA_PRIVATE_KEY is required'); + let kp: Keypair; + try { + kp = Keypair.fromSecretKey(bs58.decode(raw)); + } catch { + kp = Keypair.fromSecretKey(Uint8Array.from(JSON.parse(raw))); + } + const uea = getAddress( + ( + await PushChain.utils.account.deriveExecutorAccount( + PushChain.utils.account.toUniversal(kp.publicKey.toBase58(), { + chain: CHAIN.SOLANA_DEVNET, + }), + { skipNetworkCheck: true } + ) + ).address + ); + await f.fundPC(uea, parseEther('3')); + const signer = await PushChain.utils.signer.toUniversalFromKeypair(kp, { + chain: CHAIN.SOLANA_DEVNET, + library: PushChain.CONSTANTS.LIBRARY.SOLANA_WEB3JS, + }); + const owner = await PushChain.initialize(signer, { + network: f.manifest.network, + }); + const made = await owner.agentic.create('', { rules: [] }); + const w = owner.agentic.wallet(made.wallet); + expect((await w.info()).label).toBe(`AGW ${made.index + 1}`); + expect((await w.owner()).owner).toBe(uea); + const before = await count(made.wallet); + const rename = await w.setLabel('Solana owner'); + expect((await w.info()).label).toBe('Solana owner'); + expect( + (await owner.agentic.list()).wallets.find( + (entry) => entry.address === made.wallet + )?.label + ).toBe('Solana owner'); + const reset = await w.setLabel(''); + expect((await w.info()).label).toBe(`AGW ${made.index + 1}`); + expect(await count(made.wallet)).toBe(before + BigInt(2)); + f.evidence('v5-label-solana-owner', { + wallet: made.wallet, + owner: uea, + hashes: [made.tx.hash, rename.hash, reset.hash], + checkpointsBefore: before, + checkpointsAfter: await count(made.wallet), + }); + }, 600_000); + + it('7. renaming an active wallet preserves rules, spend and remaining agent budget', async () => { + const made = await f.owner.agentic.create('active-before', { + rules: [ + { + agent: f.agentAddress, + target: f.ownerAddress, + selector: 'value-only', + validUntil: inSeconds(3600), + maxValuePerCall: BigInt(1), + maxValueTotal: BigInt(2), + maxCalls: 3, + }, + ], + }); + await f.fundPC(made.wallet, BigInt(10)); + const w = f.owner.agentic.wallet(made.wallet), + agent = await f.agent(made.wallet); + const first = await agent.universal.sendTransaction({ + to: f.ownerAddress, + value: BigInt(1), + }); + await first.wait(); + const ruleBefore = await w.rules.get(made.rulesIds[0]); + const spendBefore = await readNativeCounters( + f.push, + f.manifest.addresses, + made.wallet, + made.rulesIds[0] + ); + const checkpointsBefore = await count(made.wallet); + const nonceBefore = await f.push.readContract({ + address: made.wallet, + abi: v5.abis.wallet, + functionName: 'grantNonce', + }); + const rename = await w.setLabel('active-after'); + expect((await w.info()).label).toBe('active-after'); + expect(await w.rules.get(made.rulesIds[0])).toEqual(ruleBefore); + expect( + await readNativeCounters( + f.push, + f.manifest.addresses, + made.wallet, + made.rulesIds[0] + ) + ).toEqual(spendBefore); + expect( + await f.push.readContract({ + address: made.wallet, + abi: v5.abis.wallet, + functionName: 'grantNonce', + }) + ).toBe(nonceBefore); + expect(await count(made.wallet)).toBe(checkpointsBefore + BigInt(1)); + const second = await agent.universal.sendTransaction({ + to: f.ownerAddress, + value: BigInt(1), + }); + await second.wait(); + expect(second.agentic?.rulesId).toBe(made.rulesIds[0]); + const spendAfter = await readNativeCounters( + f.push, + f.manifest.addresses, + made.wallet, + made.rulesIds[0] + ); + expect(spendAfter).toMatchObject({ callsUsed: 2, valueSpent: BigInt(2) }); + const agentNonce = await f.push.getTransactionCount({ + address: f.agentAddress, + }); + await expect( + agent.universal.sendTransaction({ to: f.ownerAddress, value: BigInt(1) }) + ).rejects.toMatchObject({ + decodedError: { name: 'PolicyCheckReverted(TotalValueExceeded)' }, + }); + expect(await f.push.getTransactionCount({ address: f.agentAddress })).toBe( + agentNonce + ); + expect( + await readNativeCounters( + f.push, + f.manifest.addresses, + made.wallet, + made.rulesIds[0] + ) + ).toEqual(spendAfter); + expect(await count(made.wallet)).toBe(checkpointsBefore + BigInt(1)); + f.evidence('v5-label-active-rule', { + wallet: made.wallet, + rulesId: made.rulesIds[0], + hashes: [first.hash, rename.hash, second.hash], + spendBefore, + spendAfter, + grantNonce: nonceBefore, + }); + }); + + it('8. a failed owner batch rolls back the earlier rename and all checkpoints', async () => { + const made = await f.owner.agentic.create('batch-before', { rules: [] }); + const w = f.owner.agentic.wallet(made.wallet), + before = await count(made.wallet); + const key = process.env['PUSH_PRIVATE_KEY'] as Hex; + const owner = await evmClient( + key, + CHAIN.PUSH_TESTNET_DONUT, + f.manifest.network, + made.wallet + ); + const calls = [ + { + to: made.wallet, + value: BigInt(0), + data: v5.encodeSetLabel('temporary'), + }, + { + to: made.wallet, + value: BigInt(0), + data: v5.encodeSetLabel('a'.repeat(65)), + }, + ]; + await expect( + owner.universal.sendTransaction({ to: made.wallet, data: calls }) + ).rejects.toMatchObject({ decodedError: { name: 'LabelTooLong' } }); + expect((await w.info()).label).toBe('batch-before'); + // The SDK refuses this during simulation. A bounded raw transaction using + // the same SDK encoding additionally proves rollback in a mined receipt. + const client = createWalletClient({ + account: privateKeyToAccount(key), + chain: getPushViemChain(CHAIN.PUSH_TESTNET_DONUT), + transport: http(CHAIN_INFO[CHAIN.PUSH_TESTNET_DONUT].defaultRPC[0]), + }); + const hash = await client.sendTransaction({ + chain: client.chain, + to: made.wallet, + gas: BigInt(400_000), + data: v5.encodeExecute( + calls.map((call) => ({ + target: call.to, + value: call.value, + data: call.data, + })) + ), + }); + const receipt = await f.push.waitForTransactionReceipt({ hash }); + expect(receipt.status).toBe('reverted'); + expect(receipt.logs).toHaveLength(0); + expect((await w.info()).label).toBe('batch-before'); + expect(await count(made.wallet)).toBe(before); + f.evidence('v5-label-batch-rollback', { + wallet: made.wallet, + hash, + block: receipt.blockNumber, + gasUsed: receipt.gasUsed, + status: receipt.status, + checkpoints: before, + }); + }); +}); diff --git a/packages/core/__e2e__/agw/lifecycle.spec.ts b/packages/core/__e2e__/agw/lifecycle.spec.ts new file mode 100644 index 00000000..105a5ea2 --- /dev/null +++ b/packages/core/__e2e__/agw/lifecycle.spec.ts @@ -0,0 +1,127 @@ +import { readNativeCounters } from '@e2e/shared/agw-state'; +/** + * Scenarios 5 and 6 — add / update / revoke lifecycle and checkpoint counts. + * A replacement is five checkpoint ticks; allowance pulls are not ticks. + * The stale-spend race (intervening agent spend) is verified against the + * real contracts in the local harness; it cannot be timed reliably live. + */ +import { v5 } from '../../src/lib/agentic/contracts/v5'; +import { getAddress, parseEther, type Address, type Hex } from 'viem'; +import { AGENTIC_ERROR_CODE } from '../../src/lib/agentic/errors'; +import { + AGW_E2E_ENABLED, + inSeconds, + setupAgw, + type AgwFixture, +} from './_fixture'; + +const d = AGW_E2E_ENABLED ? describe : describe.skip; + +d('agw lifecycle', () => { + let f: AgwFixture; + let wallet: Address; + let original: Hex; + const sink = getAddress('0x000000000000000000000000000000000000dEaD'); + const rule = (maxValuePerCall: bigint) => ({ + agent: f.agentAddress, + target: sink, + selector: 'value-only' as const, + validUntil: inSeconds(3600), + maxValuePerCall, + maxValueTotal: maxValuePerCall * BigInt(10), + }); + const count = () => + f.push.readContract({ + address: wallet, + abi: v5.abis.wallet, + functionName: 'checkpointCount', + }) as Promise; + + beforeAll(async () => { + f = await setupAgw(); + wallet = (await f.owner.agentic.create('e2e-lifecycle', { rules: [] })) + .wallet; + await f.fundPC(wallet, parseEther('0.01')); + }, 300_000); + afterAll(() => f?.teardown()); + + it('1. rules.add grants with one RULES_GRANTED checkpoint', async () => { + const before = await count(); + const added = await f.owner.agentic + .wallet(wallet) + .rules.add([rule(BigInt(1000))]); + original = added.rulesIds[0]; + expect(await count()).toBe(before + BigInt(1)); + const { checkpoints } = await f.owner.agentic + .wallet(wallet) + .checkpoints({ sinceBlock: added.tx.blockNumber }); + expect(checkpoints.at(-1)).toMatchObject({ + kind: 'RULES_GRANTED', + ref: original, + }); + }); + + it('2. rules.update: old ID disabled, new ID usable with reset counters, five checkpoint ticks', async () => { + const agent = await f.agent(wallet); + await ( + await agent.universal.sendTransaction({ to: sink, value: BigInt(10) }) + ).wait(); + const spentBefore = await readNativeCounters( + f.push, + f.manifest.addresses, + wallet, + original + ); + expect(spentBefore).toMatchObject({ + valueSpent: BigInt(10), + callsUsed: 1, + }); + const before = await count(); + const res = await f.owner.agentic.wallet(wallet).rules.update({ + rules: [{ rulesId: original, rule: rule(BigInt(2000)) }], + }); + expect(await count()).toBe(before + BigInt(5)); + const replacement = res.rules[0].rulesId; + expect(res.rules[0].replaced).toBe(original); + expect( + await readNativeCounters( + f.push, + f.manifest.addresses, + wallet, + replacement + ) + ).toMatchObject({ valueSpent: BigInt(0), callsUsed: 0 }); + await expect( + f.owner.agentic.wallet(wallet).rules.get(original) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.RULE_NOT_FOUND }); + const tx = await agent.universal.sendTransaction({ + to: sink, + value: BigInt(1500), + }); + expect(tx.agentic?.rulesId).toBe(replacement); + f.evidence('rules-update', { + wallet, + original, + replacement, + tx: res.tx.hash, + checkpointDelta: 5, + }); + }); + + it('3. checkpoint history is contiguous and matches checkpointCount()', async () => { + const { checkpoints } = await f.owner.agentic.wallet(wallet).checkpoints(); + expect(checkpoints.map((c) => c.seq)).toEqual( + checkpoints.map((_, i) => i + 1) + ); + expect(BigInt(checkpoints.length)).toBe(await count()); + }); + + it('4. revoke({ all: true }) leaves no enabled rules', async () => { + await ( + await f.owner.agentic.wallet(wallet).rules.revoke({ all: true }) + ).wait(); + expect((await f.owner.agentic.wallet(wallet).rules.list()).rules).toEqual( + [] + ); + }); +}); diff --git a/packages/core/__e2e__/agw/management-extended.spec.ts b/packages/core/__e2e__/agw/management-extended.spec.ts new file mode 100644 index 00000000..6c5bb6b3 --- /dev/null +++ b/packages/core/__e2e__/agw/management-extended.spec.ts @@ -0,0 +1,283 @@ +import { PushChain } from '../../src'; +import { getAddress, type Address } from 'viem'; +import type { AgenticRuntime } from '../../src/lib/agentic/runtime'; +import { v5 } from '../../src/lib/agentic/contracts/v5'; +import { setupAgw, inSeconds, type AgwFixture } from './_fixture'; +import { readNativeCounters } from '../shared/agw-state'; + +const d = process.env['AGW_E2E'] === '1' ? describe : describe.skip; +const runtime = (client: PushChain) => + (client as unknown as { agenticRuntime: AgenticRuntime }).agenticRuntime; + +d('agw extended management', () => { + let f: AgwFixture; + beforeAll(async () => { + f = await setupAgw(); + }, 300_000); + afterAll(() => f?.teardown()); + const rule = (agent = f.agentAddress) => ({ + agent, + target: f.ownerAddress, + selector: 'value-only' as const, + validUntil: inSeconds(3600), + maxValuePerCall: BigInt(10), + maxValueTotal: BigInt(100), + maxCalls: 10, + }); + const count = (wallet: Address) => + f.push.readContract({ + address: wallet, + abi: v5.abis.wallet, + functionName: 'checkpointCount', + }); + it('1. prefunding a derived address survives deployment and info/list keep owner index and label', async () => { + const predicted = await f.owner.agentic.derive(); + expect(predicted.deployed).toBe(false); + await f.fundPC(predicted.address, BigInt(10)); + const made = await f.owner.agentic.create('e2e-prefunded-identity', { + rules: [], + }); + expect(made.wallet).toBe(predicted.address); + expect(made.index).toBe(predicted.index); + expect(await f.push.getBalance({ address: made.wallet })).toBe(BigInt(10)); + const w = f.owner.agentic.wallet(made.wallet); + expect(await w.info()).toMatchObject({ + owner: f.ownerAddress, + index: made.index, + label: 'e2e-prefunded-identity', + deployed: true, + rulesCount: 0, + }); + expect(await w.owner()).toEqual({ owner: f.ownerAddress }); + expect((await f.owner.agentic.list()).wallets).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + address: made.wallet, + index: made.index, + label: 'e2e-prefunded-identity', + }), + ]) + ); + expect(await f.owner.agentic.derive({ index: made.index })).toMatchObject({ + address: made.wallet, + deployed: true, + }); + f.evidence('extended-prefunding', { + wallet: made.wallet, + index: made.index, + txHash: made.tx.hash, + }); + }); + it('2. same-agent multiplicity is ambiguous before signing and selective revoke restores uncached lookup', async () => { + const made = await f.owner.agentic.create('e2e-ambiguous', { + rules: [rule(), rule()], + }); + await f.fundPC(made.wallet, BigInt(10)); + const agent = await f.agent(made.wallet), + nonce = await f.push.getTransactionCount({ address: f.agentAddress }); + await expect( + agent.universal.sendTransaction({ to: f.ownerAddress, value: BigInt(1) }) + ).rejects.toMatchObject({ + code: 'AMBIGUOUS_RULE', + details: { rulesIds: expect.arrayContaining(made.rulesIds) }, + }); + expect(await f.push.getTransactionCount({ address: f.agentAddress })).toBe( + nonce + ); + await ( + await f.owner.agentic.wallet(made.wallet).rules.revoke([made.rulesIds[0]]) + ).wait(); + const tx = await agent.universal.sendTransaction({ + to: f.ownerAddress, + value: BigInt(1), + }); + expect((await tx.wait()).status).toBe(1); + expect(tx.agentic?.rulesId).toBe(made.rulesIds[1]); + f.evidence('extended-uncached-lookup', { + wallet: made.wallet, + removed: made.rulesIds[0], + selected: made.rulesIds[1], + txHash: tx.hash, + }); + }); + it('3. multi-rule add and revoke are atomic batches with exact checkpoint counts', async () => { + const made = await f.owner.agentic.create('e2e-management-batches', { + rules: [], + }), + w = f.owner.agentic.wallet(made.wallet); + const added = await w.rules.add([ + rule(), + rule(getAddress('0x000000000000000000000000000000000000bEEF')), + ]); + expect(await count(made.wallet)).toBe(BigInt(4)); + expect(new Set(added.rulesIds).size).toBe(2); + expect((await w.rules.list()).rules.map((r) => r.rulesId)).toEqual( + expect.arrayContaining(added.rulesIds) + ); + await (await w.rules.revoke(added.rulesIds)).wait(); + expect(await count(made.wallet)).toBe(BigInt(8)); + expect((await w.rules.list()).rules).toEqual([]); + const cp = await w.checkpoints({ sinceBlock: added.tx.blockNumber }); + expect(cp.checkpoints).toHaveLength(8); + f.evidence('extended-management-batches', { + wallet: made.wallet, + rulesIds: added.rulesIds, + addHash: added.tx.hash, + checkpoints: 8, + }); + }); + it('4. invalid revoke targets preserve enabled rules and signer nonce', async () => { + const made = await f.owner.agentic.create('e2e-revoke-guards', { + rules: [rule()], + }), + w = f.owner.agentic.wallet(made.wallet), + nonce = await f.push.getTransactionCount({ address: f.ownerAddress }); + await expect(w.rules.revoke([])).rejects.toMatchObject({ + code: 'REVOKE_NEEDS_TARGET', + }); + await expect( + w.rules.revoke([made.rulesIds[0], made.rulesIds[0]]) + ).rejects.toMatchObject({ code: 'INVALID_RULE' }); + await expect( + w.rules.revoke([`0x${'12'.repeat(32)}`]) + ).rejects.toMatchObject({ code: 'RULE_NOT_FOUND' }); + expect(await f.push.getTransactionCount({ address: f.ownerAddress })).toBe( + nonce + ); + expect((await w.rules.list()).rules.map((r) => r.rulesId)).toEqual( + made.rulesIds + ); + }); + it('5. intervening agent spend refuses a stale replacement without changing grants or checkpoints', async () => { + const made = await f.owner.agentic.create('e2e-live-stale-update', { + rules: [rule()], + }); + await f.fundPC(made.wallet, BigInt(10)); + const agent = await f.agent(made.wallet), + rt = runtime(f.owner), + original = rt.execute; + let injected = false, + hash: string | undefined; + const before = await count(made.wallet), + grantNonce = await f.push.readContract({ + address: made.wallet, + abi: v5.abis.wallet, + functionName: 'grantNonce', + }); + rt.execute = async (params, opts) => { + if (!injected && params.to === made.wallet) { + injected = true; + const tx = await agent.universal.sendTransaction({ + to: f.ownerAddress, + value: BigInt(1), + }); + await tx.wait(); + hash = tx.hash; + } + return original(params, opts); + }; + try { + const error = await f.owner.agentic + .wallet(made.wallet) + .rules.update({ rules: [{ rulesId: made.rulesIds[0], rule: rule() }] }) + .then( + () => undefined, + (e: unknown) => e + ); + expect(error).toMatchObject({ + decodedError: { name: expect.stringContaining('SpentMismatch') }, + }); + expect(injected).toBe(true); + } finally { + rt.execute = original; + } + expect(await count(made.wallet)).toBe(before); + expect( + await f.push.readContract({ + address: made.wallet, + abi: v5.abis.wallet, + functionName: 'grantNonce', + }) + ).toBe(grantNonce); + expect( + (await f.owner.agentic.wallet(made.wallet).rules.list()).rules.map( + (r) => r.rulesId + ) + ).toEqual(made.rulesIds); + expect( + await readNativeCounters( + f.push, + f.manifest.addresses, + made.wallet, + made.rulesIds[0] + ) + ).toMatchObject({ valueSpent: BigInt(1), callsUsed: 1 }); + f.evidence('extended-stale-update', { + wallet: made.wallet, + rulesId: made.rulesIds[0], + spendHash: hash, + checkpoints: before, + grantNonce, + }); + }); + it('6. index race commits no grants to the competing wallet and retry takes the next slot', async () => { + const expectedNext = await f.owner.agentic.derive(); + const rt = runtime(f.owner), + original = rt.execute; + let competing: + | Awaited> + | undefined, + injected = false; + rt.execute = async (params, opts) => { + if (!injected && Array.isArray(params.data)) { + injected = true; + competing = await f.owner.agentic.create('e2e-race-winner', { + rules: [], + }); + } + return original(params, opts); + }; + let raceError: unknown; + try { + await f.owner.agentic.create('e2e-race-loser', { rules: [rule()] }); + } catch (error) { + raceError = error; + } + try { + const afterRace = await f.owner.agentic.derive(); + const competingRules = competing + ? (await f.owner.agentic.wallet(competing.wallet).rules.list()).rules + : undefined; + f.evidence('extended-index-race-error', { + code: (raceError as { code?: string } | undefined)?.code, + expectedWallet: expectedNext.address, + expectedIndex: expectedNext.index, + competingWallet: competing?.wallet, + competingIndex: competing?.index, + nextAfterRace: afterRace, + competingRuleIds: competingRules?.map((r) => r.rulesId), + }); + expect(raceError).toMatchObject({ + code: 'INDEX_RACE', + details: { committed: false }, + }); + } finally { + rt.execute = original; + } + if (!competing) throw new Error('Race injection did not run'); + expect( + (await f.owner.agentic.wallet(competing.wallet).rules.list()).rules + ).toEqual([]); + const retried = await f.owner.agentic.create('e2e-race-retry', { + rules: [rule()], + }); + expect(retried.index).toBe(competing.index + 1); + expect(retried.wallet).not.toBe(competing.wallet); + f.evidence('extended-index-race', { + competing: competing.wallet, + winnerHash: competing.tx.hash, + retried: retried.wallet, + retryHash: retried.tx.hash, + }); + }); +}); diff --git a/packages/core/__e2e__/agw/native-batch.spec.ts b/packages/core/__e2e__/agw/native-batch.spec.ts new file mode 100644 index 00000000..5a8e06ac --- /dev/null +++ b/packages/core/__e2e__/agw/native-batch.spec.ts @@ -0,0 +1,99 @@ +/** Opt-in live cases: require the existing verified-manifest gate and native + * EIP-7702 transport. These never accept a sequential fallback as success. */ +import { getAddress, parseEther, type Hex } from 'viem'; +import { AgenticRevertError } from '../../src'; +import { readNativeCounters } from '@e2e/shared/agw-state'; +import { + AGW_E2E_ENABLED, + inSeconds, + setupAgw, + type AgwFixture, +} from './_fixture'; + +const d = AGW_E2E_ENABLED ? describe : describe.skip; +const SINK = getAddress('0x000000000000000000000000000000000000dEaD'); +const calls = () => + Array.from({ length: 2 }, () => ({ + to: SINK, + value: BigInt(1000), + data: '0x' as Hex, + })); + +d('agw native batch', () => { + let f: AgwFixture; + beforeAll(async () => { + f = await setupAgw(); + }, 300_000); + afterAll(() => f?.teardown()); + + const create = async (maxCalls: number) => { + const created = await f.owner.agentic.create('e2e-native-batch', { + rules: [ + { + agent: f.agentAddress, + target: SINK, + selector: 'value-only', + validUntil: inSeconds(3600), + maxValuePerCall: BigInt(1000), + maxValueTotal: BigInt(5000), + maxCalls, + }, + ], + }); + await f.fundPC(created.wallet, parseEther('0.001')); + return { ...created, agent: await f.agent(created.wallet) }; + }; + + it('1. sender-preserving atomic native batch meters both actions', async () => { + const { wallet, rulesIds, agent } = await create(3); + const before = await f.push.getBalance({ address: wallet }); + const tx = await agent.universal.sendTransaction({ + to: SINK, + data: calls(), + }); + expect((await tx.wait()).status).toBe(1); + expect(tx.agentic?.nativeCalls).toEqual(calls()); + expect(tx.from).toBe(wallet); + expect(await f.push.getBalance({ address: wallet })).toBe( + before - BigInt(2000) + ); + expect( + await readNativeCounters( + f.push, + f.manifest.addresses, + wallet, + rulesIds[0] + ) + ).toMatchObject({ callsUsed: 2, valueSpent: BigInt(2000) }); + const raw = await f.push.getTransaction({ hash: tx.hash as Hex }); + expect(raw.type).toBe('eip7702'); + expect(getAddress(raw.from)).toBe(f.agentAddress); + expect(getAddress(raw.to as Hex)).toBe(f.agentAddress); + const replay = await f.owner.universal.trackTransaction(tx.hash); + expect(replay.agentic?.nativeCalls).toEqual(calls()); + expect(replay.from).toBe(wallet); + f.evidence('native-agent-batch', { + wallet, + rulesId: rulesIds[0], + tx: tx.hash, + }); + }); + + it('2. a later policy failure rolls back earlier native actions', async () => { + const { wallet, rulesIds, agent } = await create(1); + const before = await f.push.getBalance({ address: wallet }); + await expect( + agent.universal.sendTransaction({ to: SINK, data: calls() }) + ).rejects.toBeInstanceOf(AgenticRevertError); + expect(await f.push.getBalance({ address: wallet })).toBe(before); + expect( + await readNativeCounters( + f.push, + f.manifest.addresses, + wallet, + rulesIds[0] + ) + ).toMatchObject({ callsUsed: 0, valueSpent: BigInt(0) }); + f.evidence('native-agent-batch-rollback', { wallet, rulesId: rulesIds[0] }); + }); +}); diff --git a/packages/core/__e2e__/agw/native-exec.spec.ts b/packages/core/__e2e__/agw/native-exec.spec.ts new file mode 100644 index 00000000..7217c145 --- /dev/null +++ b/packages/core/__e2e__/agw/native-exec.spec.ts @@ -0,0 +1,101 @@ +/** + * Scenarios 3 and 4 — native owner and agent execution with independent + * state checks, and unauthorized / revoked / expired / over-cap failures with + * unchanged protected state. + */ +import { getAddress, parseEther, type Address, type Hex } from 'viem'; +import { privateKeyToAccount, generatePrivateKey } from 'viem/accounts'; +import { AgenticError, AgenticRevertError } from '../../src'; +import { CHAIN } from '../../src/lib/constants/enums'; +import { AGENTIC_ERROR_CODE } from '../../src/lib/agentic/errors'; +import { AGW_E2E_ENABLED, evmClient, inSeconds, setupAgw, type AgwFixture } from './_fixture'; + +const d = AGW_E2E_ENABLED ? describe : describe.skip; +const CAP = parseEther('0.001'); + +d('agw native', () => { + let f: AgwFixture; + let wallet: Address; + let rulesId: Hex; + const recipient = getAddress(privateKeyToAccount(generatePrivateKey()).address); + + beforeAll(async () => { + f = await setupAgw(); + const created = await f.owner.agentic.create('e2e-native', { + rules: [ + { + agent: f.agentAddress, + target: recipient, + selector: 'value-only', + validUntil: inSeconds(3600), + maxValuePerCall: CAP, + maxValueTotal: CAP * BigInt(3), + }, + ], + }); + wallet = created.wallet; + rulesId = created.rulesIds[0]; + await f.fundPC(wallet, parseEther('0.01')); + }, 300_000); + afterAll(() => f?.teardown()); + + it('1. agent door: value moves from the wallet under its rule; signer is origin, wallet is from', async () => { + const agent = await f.agent(wallet); + expect(agent.universal.account).toBe(wallet); + const before = await f.push.getBalance({ address: recipient }); + const tx = await agent.universal.sendTransaction({ to: recipient, value: CAP }); + const receipt = await tx.wait(); + expect(receipt.status).toBe(1); + expect(await f.push.getBalance({ address: recipient })).toBe(before + CAP); + expect(tx.from).toBe(wallet); + expect(receipt.from).toBe(wallet); + expect(tx.origin.toLowerCase()).toContain(f.agentAddress.toLowerCase()); + expect(tx.agentic).toMatchObject({ door: 'agent', rulesId }); + f.evidence('native-agent-send', { wallet, rulesId, tx: tx.hash, block: tx.blockNumber }); + }); + + it('2. owner door: value moves from the wallet without rules', async () => { + const owner = await evmClient(process.env['PUSH_PRIVATE_KEY'] as Hex, CHAIN.PUSH_TESTNET_DONUT, f.manifest.network, wallet); + const before = await f.push.getBalance({ address: recipient }); + const tx = await owner.universal.sendTransaction({ to: recipient, value: CAP * BigInt(2) }); + expect((await tx.wait()).status).toBe(1); + expect(await f.push.getBalance({ address: recipient })).toBe(before + CAP * BigInt(2)); + expect(tx.agentic?.door).toBe('owner'); + }); + + it('3. over-cap value reverts with the decoded policy gate and moves nothing', async () => { + const agent = await f.agent(wallet); + const before = await f.push.getBalance({ address: recipient }); + const err = await agent.universal.sendTransaction({ to: recipient, value: CAP + BigInt(1) }).catch((e) => e); + expect(err).toBeInstanceOf(AgenticRevertError); + expect(err.decodedError?.name).toMatch(/^PolicyCheckReverted/); + expect(await f.push.getBalance({ address: recipient })).toBe(before); + }); + + it('4. an unrelated signer cannot initialize against the wallet', async () => { + const stranger = generatePrivateKey(); + await expect(evmClient(stranger, CHAIN.PUSH_TESTNET_DONUT, f.manifest.network, wallet)).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.NOT_OWNER_OR_AGENT, + }); + }); + + it('5. after revocation the agent fails before signing with NO_RULES_FOR_CHAIN', async () => { + const agent = await f.agent(wallet); + await (await f.owner.agentic.wallet(wallet).rules.revoke([rulesId])).wait(); + const err = await agent.universal.sendTransaction({ to: recipient, value: BigInt(1) }).catch((e) => e); + expect(err).toBeInstanceOf(AgenticError); + expect(err.code).toBe(AGENTIC_ERROR_CODE.NO_RULES_FOR_CHAIN); + }); + + it('6. an expired rule still identifies the agent; the send is refused on-chain', async () => { + const created = await f.owner.agentic.create('e2e-expiry', { + rules: [{ agent: f.agentAddress, target: recipient, selector: 'value-only', validUntil: inSeconds(45), maxValuePerCall: CAP, maxValueTotal: CAP }], + }); + await f.fundPC(created.wallet, CAP * BigInt(2)); + await new Promise((r) => setTimeout(r, 60_000)); + const agent = await f.agent(created.wallet); + const err = await agent.universal.sendTransaction({ to: recipient, value: BigInt(1) }).catch((e) => e); + expect(err).toBeInstanceOf(AgenticRevertError); + expect(err.decodedError?.name).toBe('PolicyCheckReverted(RulesExpired)'); + }, 300_000); +}); diff --git a/packages/core/__e2e__/agw/native-policy-extended.spec.ts b/packages/core/__e2e__/agw/native-policy-extended.spec.ts new file mode 100644 index 00000000..72c31502 --- /dev/null +++ b/packages/core/__e2e__/agw/native-policy-extended.spec.ts @@ -0,0 +1,277 @@ +/** Native policy limits, confirmed zero defaults and lossless raw-offset reuse. */ +import { PushChain, AgenticRevertError, type NativeRule } from '../../src'; +import { encodeFunctionData, erc20Abi, type Address } from 'viem'; +import { getNativePRC20ForChain } from '../../src/lib/orchestrator/internals/helpers'; +import { readNativeCounters } from '../shared/agw-state'; +import { CHAIN } from '../../src/lib/constants/enums'; +import { setupAgw, inSeconds, type AgwFixture } from './_fixture'; + +const d = process.env['AGW_E2E'] === '1' ? describe : describe.skip; +const chain = PushChain.CONSTANTS.CHAIN.PUSH_TESTNET_DONUT; + +d('agw extended native policy', () => { + let f: AgwFixture, token: Address; + beforeAll(async () => { + f = await setupAgw(); + token = getNativePRC20ForChain(CHAIN.ETHEREUM_SEPOLIA, f.manifest.network); + }, 300_000); + afterAll(() => f?.teardown()); + const transfer = (to: Address, amount: bigint) => + encodeFunctionData({ + abi: erc20Abi, + functionName: 'transfer', + args: [to, amount], + }); + async function fixture( + balance = BigInt(50), + maxCalls = 2, + total = BigInt(15), + omitPc = false + ) { + const rule = { + agent: f.agentAddress, + target: token, + selector: 'transfer(address,uint256)' as const, + validUntil: inSeconds(3600), + ...(omitPc + ? {} + : { maxValuePerCall: BigInt(0), maxValueTotal: BigInt(0) }), + maxCalls, + pins: [{ arg: 0, expected: f.ownerAddress }], + amount: { arg: 1, maxPerCall: BigInt(10), maxTotal: total }, + }; + const made = await f.owner.agentic.create('e2e-native-meter', { + rules: [rule], + }); + if (balance) + await ( + await f.owner.universal.sendTransaction({ + to: token, + data: transfer(made.wallet, balance), + }) + ).wait(); + const agent = await f.agent(made.wallet); + const counters = () => + readNativeCounters( + f.push, + f.manifest.addresses, + made.wallet, + made.rulesIds[0] + ); + const tokenBalance = () => + f.push.readContract({ + address: token, + abi: erc20Abi, + functionName: 'balanceOf', + args: [made.wallet], + }); + const send = (amount: bigint, to = f.ownerAddress, value = BigInt(0)) => + agent.universal.sendTransaction({ + to: { address: token, chain }, + value, + data: transfer(to, amount), + }); + return { ...made, agent, counters, tokenBalance, send }; + } + async function refused( + s: Awaited>, + action: () => Promise, + gate?: string + ) { + const before = await s.counters(), + balance = await s.tokenBalance(); + const error = await action().then( + () => undefined, + (e: unknown) => e + ); + expect(error).toBeInstanceOf(AgenticRevertError); + if (gate) + expect((error as AgenticRevertError).decodedError?.name).toBe( + `PolicyCheckReverted(${gate})` + ); + expect(await s.counters()).toEqual(before); + expect(await s.tokenBalance()).toBe(balance); + f.evidence('extended-native-refusal', { + wallet: s.wallet, + rulesId: s.rulesIds[0], + gate: gate ?? 'callee/engine', + counters: before, + tokenBalance: balance, + }); + } + it('1. pinned recipient and metered amount decode losslessly and transfer through explicit Push chain', async () => { + const s = await fixture(); + const record = await f.owner.agentic + .wallet(s.wallet) + .rules.get(s.rulesIds[0]); + expect(record.rule).toMatchObject({ + pins: [ + { + offset: 4, + expected: `0x${f.ownerAddress + .slice(2) + .toLowerCase() + .padStart(64, '0')}`, + }, + ], + amount: { offset: 36, maxPerCall: BigInt(10), maxTotal: BigInt(15) }, + }); + const before = await f.push.readContract({ + address: token, + abi: erc20Abi, + functionName: 'balanceOf', + args: [f.ownerAddress], + }); + const tx = await s.send(BigInt(10)); + expect((await tx.wait()).status).toBe(1); + expect(await s.tokenBalance()).toBe(BigInt(40)); + expect(await s.counters()).toMatchObject({ + valueSpent: BigInt(0), + amountSpent: BigInt(10), + callsUsed: 1, + }); + expect( + await f.push.readContract({ + address: token, + abi: erc20Abi, + functionName: 'balanceOf', + args: [f.ownerAddress], + }) + ).toBe(before + BigInt(10)); + const replay = await f.owner.universal.trackTransaction(tx.hash); + expect(replay.from).toBe(s.wallet); + expect(replay.agentic?.rulesId).toBe(s.rulesIds[0]); + f.evidence('extended-native-meter', { + wallet: s.wallet, + rulesId: s.rulesIds[0], + txHash: tx.hash, + }); + }); + it('2. wrong recipient pin is refused with unchanged token balance and counters', async () => { + const s = await fixture(); + await refused(s, () => s.send(BigInt(1), f.agentAddress), 'ArgPinMismatch'); + }); + it('3. per-call amount cap refuses cap plus one', async () => { + const s = await fixture(); + await refused(s, () => s.send(BigInt(11)), 'NativeAmountExceedsCap'); + }); + it('4. cumulative amount accepts the exact total and refuses the next unit', async () => { + const s = await fixture(BigInt(50), 10); + await (await s.send(BigInt(10))).wait(); + await (await s.send(BigInt(5))).wait(); + expect((await s.counters()).amountSpent).toBe(BigInt(15)); + await refused(s, () => s.send(BigInt(1)), 'TotalNativeAmountExceeded'); + }); + it('5. call count accepts the exact count and refuses a zero-amount extra call', async () => { + const s = await fixture(); + await (await s.send(BigInt(1))).wait(); + await (await s.send(BigInt(1))).wait(); + expect((await s.counters()).callsUsed).toBe(2); + await refused(s, () => s.send(BigInt(0)), 'CallLimitReached'); + }); + it('6. explicit zero total forbids positive amount but permits a metered zero call', async () => { + const s = await fixture(BigInt(50), 10, BigInt(0)); + await refused(s, () => s.send(BigInt(1)), 'TotalNativeAmountExceeded'); + await (await s.send(BigInt(0))).wait(); + expect(await s.counters()).toMatchObject({ + amountSpent: BigInt(0), + callsUsed: 1, + }); + }); + it('7. failed token callee leaves all policy counters unchanged', async () => { + const s = await fixture(BigInt(5)); + await refused(s, () => s.send(BigInt(10))); + }); + it('8. an ungranted selector is refused without changing balances or allowance', async () => { + const s = await fixture(); + const before = await f.push.readContract({ + address: token, + abi: erc20Abi, + functionName: 'allowance', + args: [s.wallet, f.agentAddress], + }); + await refused(s, () => + s.agent.universal.sendTransaction({ + to: token, + data: encodeFunctionData({ + abi: erc20Abi, + functionName: 'approve', + args: [f.agentAddress, BigInt(1)], + }), + }) + ); + expect( + await f.push.readContract({ + address: token, + abi: erc20Abi, + functionName: 'allowance', + args: [s.wallet, f.agentAddress], + }) + ).toBe(before); + }); + it('9. omitted PC limits forbid value while still allowing a token transfer', async () => { + const s = await fixture(BigInt(5), 3, BigInt(15), true); + await f.fundPC(s.wallet, BigInt(10)); + const record = await f.owner.agentic + .wallet(s.wallet) + .rules.get(s.rulesIds[0]); + expect(record.rule).toMatchObject({ + maxValuePerCall: BigInt(0), + maxValueTotal: BigInt(0), + }); + await refused(s, () => s.send(BigInt(1), f.ownerAddress, BigInt(1)), 'ValueExceedsCap'); + const sent = await s.send(BigInt(1)); + expect((await sent.wait()).status).toBe(1); + expect(await s.counters()).toMatchObject({ + valueSpent: BigInt(0), + amountSpent: BigInt(1), + }); + f.evidence('zero-pc-defaults', { wallet: s.wallet, txHash: sent.hash }); + }); + it('10. decoded raw-offset rules can be granted again without fabricated ref metadata', async () => { + const s = await fixture(BigInt(0)); + const original = await f.owner.agentic + .wallet(s.wallet) + .rules.get(s.rulesIds[0]); + expect(original).not.toHaveProperty('ref'); + const made = await f.owner.agentic.create('raw-offset-reuse', { + rules: [original.rule as NativeRule], + }); + const reread = await f.owner.agentic + .wallet(made.wallet) + .rules.get(made.rulesIds[0]); + expect(reread.rule).toEqual(original.rule); + expect(reread).not.toHaveProperty('ref'); + f.evidence('raw-offset-reuse', { + wallet: made.wallet, + txHash: made.tx.hash, + }); + }); + it('11. removed ref and conflicting argument-offset inputs fail before signing', async () => { + const nonce = await f.push.getTransactionCount({ address: f.ownerAddress }); + const rule = { + agent: f.agentAddress, + target: token, + selector: 'transfer(address,uint256)', + validUntil: inSeconds(3600), + }; + await expect( + f.owner.agentic.create('invalid-ref', { + rules: [{ ...rule, ref: `0x${'11'.repeat(32)}` } as never], + }) + ).rejects.toMatchObject({ code: 'INVALID_RULE' }); + await expect( + f.owner.agentic.create('invalid-pin', { + rules: [ + { + ...rule, + pins: [{ arg: 0, offset: 4, expected: `0x${'00'.repeat(32)}` }], + } as never, + ], + }) + ).rejects.toMatchObject({ code: 'INVALID_RULE' }); + expect(await f.push.getTransactionCount({ address: f.ownerAddress })).toBe( + nonce + ); + }); +}); diff --git a/packages/core/__e2e__/agw/responses-hooks.spec.ts b/packages/core/__e2e__/agw/responses-hooks.spec.ts new file mode 100644 index 00000000..b026a005 --- /dev/null +++ b/packages/core/__e2e__/agw/responses-hooks.spec.ts @@ -0,0 +1,51 @@ +/** + * Scenario 10 — init-time and per-call hooks through wait without + * duplicates, and AGW `from` / signer `origin` on live and replayed + * responses. + */ +import { getAddress, parseEther, type Address } from 'viem'; +import type { ProgressEvent } from '../../src/lib/progress-hook/progress-hook.types'; +import { AGW_E2E_ENABLED, inSeconds, setupAgw, type AgwFixture } from './_fixture'; + +const d = AGW_E2E_ENABLED ? describe : describe.skip; +const SINK = getAddress('0x000000000000000000000000000000000000dEaD'); + +d('agw responses', () => { + let f: AgwFixture; + let wallet: Address; + beforeAll(async () => { + f = await setupAgw(); + const created = await f.owner.agentic.create('e2e-hooks', { + rules: [{ agent: f.agentAddress, target: SINK, selector: 'value-only', validUntil: inSeconds(3600), maxValuePerCall: BigInt(10), maxValueTotal: BigInt(100) }], + }); + wallet = created.wallet; + await f.fundPC(wallet, parseEther('0.001')); + }, 300_000); + afterAll(() => f?.teardown()); + + it('1. init and per-call hooks each see every event once, through wait', async () => { + const init: ProgressEvent[] = []; + const perCall: ProgressEvent[] = []; + const agent = await f.agent(wallet, (e) => init.push(e as ProgressEvent)); + const tx = await agent.universal.sendTransaction({ to: SINK, value: BigInt(1) }, { progressHook: (e) => perCall.push(e) }); + await tx.wait(); + const ids = (xs: ProgressEvent[]) => xs.map((e) => e.id); + expect(ids(perCall)).toEqual(ids(init)); + expect(new Set(ids(perCall).filter((i) => i.startsWith('AGENTIC-TX'))).size).toBe(ids(perCall).filter((i) => i.startsWith('AGENTIC-TX')).length); + expect(ids(perCall)).toEqual(expect.arrayContaining(['AGENTIC-TX-107', 'AGENTIC-TX-199-01', 'SEND-TX-199-01'])); + expect(ids(perCall)).not.toContain('AGENTIC-TX-103'); + }); + + it('2. live and replayed responses agree on wallet from and signer origin', async () => { + const agent = await f.agent(wallet); + const tx = await agent.universal.sendTransaction({ to: SINK, value: BigInt(1) }); + await tx.wait(); + const replay = await f.owner.universal.trackTransaction(tx.hash); + expect(replay.from).toBe(tx.from); + expect(replay.from).toBe(wallet); + expect(replay.origin).toBe(tx.origin); + expect(replay.to).toBe(SINK); + expect((await replay.wait()).from).toBe(wallet); + f.evidence('replay-identity', { wallet, tx: tx.hash }); + }); +}); diff --git a/packages/core/__e2e__/agw/svm-public.spec.ts b/packages/core/__e2e__/agw/svm-public.spec.ts new file mode 100644 index 00000000..79ff9089 --- /dev/null +++ b/packages/core/__e2e__/agw/svm-public.spec.ts @@ -0,0 +1,445 @@ +/** Public named-IDL lifecycle and destination delivery on Donut/Solana devnet. */ +import '@e2e/shared/setup'; +import { PushChain, type SolanaRule } from '../../src'; +import type { Idl } from '@coral-xyz/anchor'; +import { PublicKey, Keypair } from '@solana/web3.js'; +import bs58 from 'bs58'; +import { + createPublicClient, + http, + erc20Abi, + encodeFunctionData, + parseAbi, + parseEther, + zeroAddress, + type Address, + type Hex, +} from 'viem'; +import { privateKeyToAccount } from 'viem/accounts'; +import { CHAIN, PUSH_NETWORK } from '../../src/lib/constants/enums'; +import { CHAIN_INFO, getPushViemChain } from '../../src/lib/constants/chain'; +import counterIdl from '../../src/lib/orchestrator/svm-idl/__fixtures__/test_counter.idl.json'; +import { v5 } from '../../src/lib/agentic/contracts/v5'; +import { setupAgw, evmClient, inSeconds, type AgwFixture } from './_fixture'; +import { loadAgwManifest, verifyAgwManifest } from './_manifest'; +import { + inspectSvmWirePrograms, + svmWireConnection, + SVM_WIRE_CHAIN, + SVM_WIRE_PROGRAM, + SVM_WIRE_COUNTER, +} from '../shared/agw-svm-preflight'; + +const d = process.env['AGW_E2E'] === '1' ? describe : describe.skip; +const amount = BigInt(10_000), + pc = parseEther('41'); +d('agw public svm', () => { + let f: AgwFixture, + wallet: Address, + id: Hex, + token: Address, + agent: PushChain, + recipient: PublicKey, + cea: PublicKey, + idl: Idl; + const sol = svmWireConnection(); + const rule = (): SolanaRule => ({ + agent: f.agentAddress, + chainNamespace: SVM_WIRE_CHAIN, + validUntil: inSeconds(3600), + assets: [{ token: zeroAddress, maxPerCall: amount, maxTotal: amount }], + maxGasPerCall: parseEther('20'), + allowedInstructions: [ + { + program: SVM_WIRE_PROGRAM, + instruction: { idl, name: 'receive_sol' }, + accounts: [ + { + name: 'counter', + expected: { kind: 'address', address: SVM_WIRE_COUNTER.toBase58() }, + }, + { + name: 'recipient', + expected: { kind: 'address', address: recipient.toBase58() }, + }, + { name: 'cea_authority', expected: { kind: 'walletCEA' } }, + { + name: 'system_program', + expected: { + kind: 'address', + address: PublicKey.default.toBase58(), + }, + }, + ], + fields: [{ name: 'amount', max: amount }], + }, + ], + }); + const data = (value = amount, source = idl) => + PushChain.utils.helpers.encodeTxData({ + abi: source, + functionName: 'receive_sol', + args: [value], + }); + beforeAll(async () => { + await inspectSvmWirePrograms(sol); + const manifest = loadAgwManifest(); + if (manifest.network !== PUSH_NETWORK.TESTNET_DONUT) + throw new Error('Public SVM fixture requires Donut'); + if ( + parseEther(process.env['AGW_E2E_AGENT_PC'] ?? '0.5') > parseEther('0.5') + ) + throw new Error('Agent funding exceeds fixture budget'); + const key = process.env['SOLANA_PRIVATE_KEY']; + if (!key) throw new Error('Missing recipient identity'); + try { + recipient = Keypair.fromSecretKey(bs58.decode(key)).publicKey; + } catch { + recipient = Keypair.fromSecretKey( + Uint8Array.from(JSON.parse(key)) + ).publicKey; + } + const recipientInfo = await sol.getAccountInfo(recipient); + if ( + !recipientInfo || + recipientInfo.executable || + !recipientInfo.owner.equals(PublicKey.default) + ) + throw new Error('Owned recipient must be an existing System account'); + const push = createPublicClient({ + chain: getPushViemChain(CHAIN.PUSH_TESTNET_DONUT), + transport: http(CHAIN_INFO[CHAIN.PUSH_TESTNET_DONUT].defaultRPC[0]), + }); + await verifyAgwManifest(push, manifest); + const ownerKey = process.env['PUSH_PRIVATE_KEY'] as Hex; + if (!ownerKey) throw new Error('Missing owner'); + const ownerAddress = privateKeyToAccount(ownerKey).address; + token = await push.readContract({ + address: '0x00000000000000000000000000000000000000C0', + abi: parseAbi([ + 'function gasTokenPRC20ByChainNamespace(string) view returns (address)', + ]), + functionName: 'gasTokenPRC20ByChainNamespace', + args: [SVM_WIRE_CHAIN], + }); + if ( + (await push.getBalance({ address: ownerAddress })) < + pc + parseEther('2') || + (await push.readContract({ + address: token, + abi: erc20Abi, + functionName: 'balanceOf', + args: [ownerAddress], + })) < + amount * BigInt(2) + BigInt(1) + ) + throw new Error('Insufficient bounded fixture funds'); + idl = JSON.parse(JSON.stringify(counterIdl)) as Idl; + const receive = idl.instructions.find((i) => i.name === 'receive_sol')!; + const destination = receive.accounts.find((a) => a.name === 'recipient')!; + Object.assign(destination, { address: recipient.toBase58() }); + f = await setupAgw(); + const made = await f.owner.agentic.create('public-idl-svm', { + rules: [rule()], + }); + wallet = made.wallet; + id = made.rulesIds[0]; + const record = await f.owner.agentic.wallet(wallet).rules.get(id); + if (!('expectedCEA' in record.rule)) + throw new Error('Missing decoded destination account'); + cea = new PublicKey(Buffer.from(record.rule.expectedCEA.slice(2), 'hex')); + await f.fundPC(wallet, pc); + await ( + await f.owner.universal.sendTransaction({ + to: token, + data: encodeFunctionData({ + abi: erc20Abi, + functionName: 'transfer', + args: [wallet, amount * BigInt(2)], + }), + }) + ).wait(); + const owner = await evmClient( + ownerKey, + CHAIN.PUSH_TESTNET_DONUT, + manifest.network, + wallet + ); + await ( + await owner.universal.sendTransaction({ + to: token, + data: encodeFunctionData({ + abi: erc20Abi, + functionName: 'approve', + args: [manifest.addresses.gateway, amount * BigInt(2)], + }), + }) + ).wait(); + agent = await f.agent(wallet); + f.evidence('public-svm-setup', { + wallet, + id, + grantHash: made.tx.hash, + cea: cea.toBase58(), + recipient: recipient.toBase58(), + }); + }, 900_000); + afterAll(() => f?.teardown()); + it('1. named IDL grant reads exact constraints and replaces atomically', async () => { + const handle = f.owner.agentic.wallet(wallet), + record = await handle.rules.get(id); + expect(record).not.toHaveProperty('ref'); + expect(record.rule).toMatchObject({ + format: 'decoded', + dataPins: [{ offset: 8, len: 8, mode: 2 }], + }); + const count = (await handle.checkpoints()).checkpoints.length; + const updated = await handle.rules.update({ + rules: [{ rulesId: id, rule: rule() }], + }); + const previous = id; + id = updated.rules[0].rulesId; + await expect(handle.rules.get(previous)).rejects.toMatchObject({ + code: 'RULE_NOT_FOUND', + }); + expect((await handle.checkpoints()).checkpoints.length).toBe(count + 5); + f.evidence('public-svm-replacement', { + wallet, + id, + txHash: updated.tx.hash, + }); + }); + it('2. public send confirms actual CEA transfer and preserves replay identity', async () => { + const tx = await agent.universal.sendTransaction({ + to: { chain: SVM_WIRE_CHAIN, address: SVM_WIRE_PROGRAM }, + value: amount, + gasLimit: BigInt(0), + data: data(), + }); + f.evidence('public-svm-submitted', { wallet, id, hash: tx.hash }); + const receipt = await tx.wait({ outboundTimeoutMs: 600_000 }); + expect(receipt.externalStatus).toBe('success'); + expect(receipt.from).toBe(wallet); + const destination = await sol.getParsedTransaction( + receipt.externalTxHash!, + { commitment: 'confirmed', maxSupportedTransactionVersion: 0 } + ); + expect(destination?.meta?.err).toBeNull(); + expect( + destination?.meta?.innerInstructions?.some((g) => + g.instructions.some( + (ix) => + 'parsed' in ix && + ix.program === 'system' && + ix.parsed.type === 'transfer' && + ix.parsed.info.source === cea.toBase58() && + ix.parsed.info.destination === recipient.toBase58() && + BigInt(ix.parsed.info.lamports) === amount + ) + ) + ).toBe(true); + const replay = await f.owner.universal.trackTransaction(tx.hash); + expect(replay.from).toBe(wallet); + expect(replay.agentic?.destinationInstruction).toEqual( + tx.agentic?.destinationInstruction + ); + expect( + (await replay.wait({ outboundTimeoutMs: 600_000 })).externalTxHash + ).toBe(receipt.externalTxHash); + f.evidence('public-svm-delivered', { + wallet, + hash: tx.hash, + destinationHash: receipt.externalTxHash, + instruction: tx.agentic?.destinationInstruction, + }); + }, 900_000); + it('3. contract simulation maps account and data refusals without state changes', async () => { + const config = PushChain.utils.agentic.configId( + wallet, + id, + PushChain.utils.agentic.actionId( + f.manifest.addresses.gateway, + '0x77b86bec' + ) + ); + const state = async () => { + const [tokens, pcBalance, checkpoints, cfg] = await Promise.all([ + f.push.readContract({ + address: token, + abi: erc20Abi, + functionName: 'balanceOf', + args: [wallet], + }), + f.push.getBalance({ address: wallet }), + f.push.readContract({ + address: wallet, + abi: v5.abis.wallet, + functionName: 'checkpointCount', + }), + f.push.readContract({ + address: f.manifest.addresses.rulesPolicy, + abi: v5.abis.policy, + functionName: 'getSvmConfig', + args: [config, wallet], + }), + ]); + return { + tokens, + pcBalance, + checkpoints, + spent: cfg.assets.map((a) => a.spent), + }; + }; + const before = await state(); + const nonce = await f.push.getTransactionCount({ address: f.agentAddress }); + const wrong = JSON.parse(JSON.stringify(idl)) as Idl; + Object.assign( + wrong.instructions + .find((i) => i.name === 'receive_sol')! + .accounts.find((a) => a.name === 'recipient')!, + { address: PublicKey.default.toBase58() } + ); + await expect( + agent.universal.sendTransaction({ + to: { chain: SVM_WIRE_CHAIN, address: SVM_WIRE_PROGRAM }, + gasLimit: BigInt(0), + data: data(BigInt(1), wrong), + }) + ).rejects.toMatchObject({ + name: 'AgenticRevertError', + decodedError: { name: 'PolicyCheckReverted(SvmAccountPinMismatch)' }, + }); + await expect( + agent.universal.sendTransaction({ + to: { chain: SVM_WIRE_CHAIN, address: SVM_WIRE_PROGRAM }, + gasLimit: BigInt(0), + data: data(amount + BigInt(1)), + }) + ).rejects.toMatchObject({ + name: 'AgenticRevertError', + decodedError: { name: 'PolicyCheckReverted(SvmDataCeilingExceeded)' }, + }); + expect(await f.push.getTransactionCount({ address: f.agentAddress })).toBe( + nonce + ); + expect(await state()).toEqual(before); + f.evidence('public-svm-contract-refusals', { + wallet, + id, + agentNonce: nonce, + state: before, + }); + }); + it('4. public revoke removes the Solana rule and subsequent sends are refused', async () => { + const handle = f.owner.agentic.wallet(wallet); + await (await handle.rules.revoke([id])).wait(); + expect((await handle.rules.list()).rules).toHaveLength(0); + await expect( + agent.universal.sendTransaction({ + to: { chain: SVM_WIRE_CHAIN, address: SVM_WIRE_PROGRAM }, + data: data(), + }) + ).rejects.toMatchObject({ code: 'NO_RULES_FOR_CHAIN' }); + }); + it('5. owner funds-only transfer reaches the recipient and replays with the same amount', async () => { + const ownerKey = process.env['PUSH_PRIVATE_KEY'] as Hex; + const sender = await evmClient( + ownerKey, + CHAIN.PUSH_TESTNET_DONUT, + f.manifest.network, + wallet + ); + const before = await sol.getBalance(recipient); + const balance = await f.push.readContract({ + address: token, + abi: erc20Abi, + functionName: 'balanceOf', + args: [wallet], + }); + const tx = await sender.universal.sendTransaction({ + to: { chain: SVM_WIRE_CHAIN, address: recipient.toBase58() }, + value: amount, + gasLimit: BigInt(0), + }); + f.evidence('public-svm-owner-transfer-submitted', { + wallet, + hash: tx.hash, + }); + expect(tx.agentic?.door).toBe('owner'); + expect(tx.agentic?.rulesId).toBeUndefined(); + expect(tx.agentic?.destinationInstruction).toBeUndefined(); + expect(tx.agentic?.destinationTransfer).toMatchObject({ token, amount }); + const receipt = await tx.wait({ outboundTimeoutMs: 600_000 }); + expect(receipt.externalStatus).toBe('success'); + expect(receipt.from).toBe(wallet); + expect(await sol.getBalance(recipient)).toBe(before + Number(amount)); + expect( + await f.push.readContract({ + address: token, + abi: erc20Abi, + functionName: 'balanceOf', + args: [wallet], + }) + ).toBe(balance - amount); + const replay = await f.owner.universal.trackTransaction(tx.hash); + expect(replay.to).toBe(tx.to); + expect(replay.data).toBe('0x'); + expect(replay.value).toBe(amount); + expect(replay.agentic?.destinationTransfer).toEqual( + tx.agentic?.destinationTransfer + ); + expect( + (await replay.wait({ outboundTimeoutMs: 600_000 })).externalTxHash + ).toBe(receipt.externalTxHash); + f.evidence('public-svm-owner-transfer-delivered', { + wallet, + hash: tx.hash, + destinationHash: receipt.externalTxHash, + recipient: recipient.toBase58(), + amount, + }); + }, 900_000); + it('6. agents still require an instruction and owner allowance failures do not sign', async () => { + const agentNonce = await f.push.getTransactionCount({ + address: f.agentAddress, + }); + await expect( + agent.universal.sendTransaction({ + to: { chain: SVM_WIRE_CHAIN, address: recipient.toBase58() }, + value: amount, + }) + ).rejects.toMatchObject({ code: 'INVALID_RULE' }); + expect(await f.push.getTransactionCount({ address: f.agentAddress })).toBe( + agentNonce + ); + // Both funded sends have consumed the bounded allowance. Funding only the + // token lets this case isolate the separate allowance guard. + await ( + await f.owner.universal.sendTransaction({ + to: token, + data: encodeFunctionData({ + abi: erc20Abi, + functionName: 'transfer', + args: [wallet, BigInt(1)], + }), + }) + ).wait(); + const sender = await evmClient( + process.env['PUSH_PRIVATE_KEY'] as Hex, + CHAIN.PUSH_TESTNET_DONUT, + f.manifest.network, + wallet + ); + const nonce = await f.push.getTransactionCount({ address: f.ownerAddress }); + await expect( + sender.universal.sendTransaction({ + to: { chain: SVM_WIRE_CHAIN, address: recipient.toBase58() }, + value: BigInt(1), + gasLimit: BigInt(0), + }) + ).rejects.toMatchObject({ code: 'GATEWAY_ALLOWANCE_INSUFFICIENT' }); + expect(await f.push.getTransactionCount({ address: f.ownerAddress })).toBe( + nonce + ); + }); +}); diff --git a/packages/core/__e2e__/agw/svm-spl-transfer.spec.ts b/packages/core/__e2e__/agw/svm-spl-transfer.spec.ts new file mode 100644 index 00000000..e35a1110 --- /dev/null +++ b/packages/core/__e2e__/agw/svm-spl-transfer.spec.ts @@ -0,0 +1,224 @@ +/** Funds-only SPL delivery through the public AGW owner path on Donut/devnet. */ +import '@e2e/shared/setup'; +import { Keypair, PublicKey } from '@solana/web3.js'; +import bs58 from 'bs58'; +import { encodeFunctionData, erc20Abi, parseEther, type Hex } from 'viem'; +import { CHAIN, PUSH_NETWORK } from '../../src/lib/constants/enums'; +import { MOVEABLE_TOKEN_CONSTANTS } from '../../src/lib/constants/tokens'; +import { getPRC20Address } from '../../src/lib/universal/prc20-address'; +import { v5 } from '../../src/lib/agentic/contracts/v5'; +import { + AGW_E2E_ENABLED, + evmClient, + setupAgw, + type AgwFixture, +} from './_fixture'; +import { loadAgwManifest } from './_manifest'; +import { + inspectSvmWirePrograms, + svmWireConnection, +} from '@e2e/shared/agw-svm-preflight'; + +const d = AGW_E2E_ENABLED ? describe : describe.skip; +const TOKEN_PROGRAM = new PublicKey( + 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA' +); +const ATA_PROGRAM = new PublicKey( + 'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL' +); +const amount = BigInt(1000); // 0.001 USDT; fixture funding is bounded to this. + +d('agw svm spl transfer', () => { + let f: AgwFixture; + beforeAll(async () => { + if (loadAgwManifest().network !== PUSH_NETWORK.TESTNET_DONUT) + throw new Error('SPL fixture requires Donut'); + await inspectSvmWirePrograms(svmWireConnection()); + f = await setupAgw(); + }, 300_000); + afterAll(() => f?.teardown()); + + it('1. owner funds-only SPL delivery credits the recipient ATA and preserves burn, allowance and replay', async () => { + const sol = svmWireConnection(), + raw = process.env['SOLANA_PRIVATE_KEY']; + if (!raw) throw new Error('SOLANA_PRIVATE_KEY is required'); + let kp: Keypair; + try { + kp = Keypair.fromSecretKey(bs58.decode(raw)); + } catch { + kp = Keypair.fromSecretKey(Uint8Array.from(JSON.parse(raw))); + } + const recipient = kp.publicKey, + asset = MOVEABLE_TOKEN_CONSTANTS.SOLANA_DEVNET.USDT; + const mint = new PublicKey(asset.address); + const mintInfo = await sol.getAccountInfo(mint); + if (!mintInfo?.owner.equals(TOKEN_PROGRAM)) + throw new Error('Fixture mint is not a standard SPL mint'); + const ata = PublicKey.findProgramAddressSync( + [recipient.toBuffer(), TOKEN_PROGRAM.toBuffer(), mint.toBuffer()], + ATA_PROGRAM + )[0]; + const recipientBalance = async () => { + const info = await sol.getAccountInfo(ata); + if (!info) return BigInt(0); + if (!info.owner.equals(TOKEN_PROGRAM)) + throw new Error('Recipient ATA has unexpected owner'); + return BigInt((await sol.getTokenAccountBalance(ata)).value.amount); + }; + const token = getPRC20Address( + { chain: CHAIN.SOLANA_DEVNET, address: asset.address }, + { network: f.manifest.network } + ).address; + if ( + (await f.push.readContract({ + address: token, + abi: erc20Abi, + functionName: 'balanceOf', + args: [f.ownerAddress], + })) < amount + ) + throw new Error('Insufficient mapped SPL fixture funds'); + if ( + (await f.push.getBalance({ address: f.ownerAddress })) < parseEther('22') + ) + throw new Error('Insufficient bounded PC fixture funds'); + const made = await f.owner.agentic.create('v5-spl-owner-transfer', { + rules: [], + }); + await f.fundPC(made.wallet, parseEther('21')); + await ( + await f.owner.universal.sendTransaction({ + to: token, + data: encodeFunctionData({ + abi: erc20Abi, + functionName: 'transfer', + args: [made.wallet, amount], + }), + }) + ).wait(); + const owner = await evmClient( + process.env['PUSH_PRIVATE_KEY'] as Hex, + CHAIN.PUSH_TESTNET_DONUT, + f.manifest.network, + made.wallet + ); + await ( + await owner.universal.sendTransaction({ + to: token, + data: encodeFunctionData({ + abi: erc20Abi, + functionName: 'approve', + args: [f.manifest.addresses.gateway, amount], + }), + }) + ).wait(); + const beforeRecipient = await recipientBalance(); + const beforeCheckpoints = await f.push.readContract({ + address: made.wallet, + abi: v5.abis.wallet, + functionName: 'checkpointCount', + }); + const tx = await owner.universal.sendTransaction({ + to: { chain: CHAIN.SOLANA_DEVNET, address: recipient.toBase58() }, + funds: { token: asset, amount }, + gasLimit: BigInt(0), + }); + expect(tx.value).toBe(BigInt(0)); + expect(tx.agentic).toMatchObject({ + door: 'owner', + destinationTransfer: { + recipient: `0x${recipient.toBuffer().toString('hex')}`, + token, + amount, + }, + }); + expect(tx.agentic?.destinationInstruction).toBeUndefined(); + f.evidence('v5-spl-owner-submitted', { + wallet: made.wallet, + hash: tx.hash, + mint: mint.toBase58(), + recipient: recipient.toBase58(), + ata: ata.toBase58(), + amount, + }); + const receipt = await tx.wait({ outboundTimeoutMs: 600_000 }); + expect(receipt.externalStatus).toBe('success'); + expect(receipt.from).toBe(made.wallet); + expect(await recipientBalance()).toBe(beforeRecipient + amount); + expect( + await f.push.readContract({ + address: token, + abi: erc20Abi, + functionName: 'balanceOf', + args: [made.wallet], + }) + ).toBe(BigInt(0)); + expect( + await f.push.readContract({ + address: token, + abi: erc20Abi, + functionName: 'allowance', + args: [made.wallet, f.manifest.addresses.gateway], + }) + ).toBe(BigInt(0)); + expect( + await f.push.readContract({ + address: made.wallet, + abi: v5.abis.wallet, + functionName: 'checkpointCount', + }) + ).toBe(beforeCheckpoints + BigInt(1)); + let external = await sol.getParsedTransaction(receipt.externalTxHash!, { + commitment: 'confirmed', + maxSupportedTransactionVersion: 0, + }); + for (let retry = 0; !external && retry < 5; retry++) { + await new Promise((resolve) => setTimeout(resolve, 2000)); + external = await sol.getParsedTransaction(receipt.externalTxHash!, { + commitment: 'confirmed', + maxSupportedTransactionVersion: 0, + }); + } + expect(external?.meta?.err).toBeNull(); + const accountIndex = external?.transaction.message.accountKeys.findIndex( + (entry) => entry.pubkey.equals(ata) + ); + expect(accountIndex).toBeGreaterThanOrEqual(0); + const prior = external?.meta?.preTokenBalances?.find( + (balance) => + balance.accountIndex === accountIndex && + balance.mint === mint.toBase58() + ); + const credited = external?.meta?.postTokenBalances?.find( + (balance) => + balance.accountIndex === accountIndex && + balance.mint === mint.toBase58() + ); + expect(credited?.owner).toBe(recipient.toBase58()); + expect( + BigInt(credited?.uiTokenAmount.amount ?? '0') - + BigInt(prior?.uiTokenAmount.amount ?? '0') + ).toBe(amount); + const replay = await f.owner.universal.trackTransaction(tx.hash); + expect(replay.from).toBe(made.wallet); + expect(replay.to).toBe(tx.to); + expect(replay.value).toBe(BigInt(0)); + expect(replay.agentic?.destinationTransfer).toEqual( + tx.agentic?.destinationTransfer + ); + expect( + (await replay.wait({ outboundTimeoutMs: 600_000 })).externalTxHash + ).toBe(receipt.externalTxHash); + f.evidence('v5-spl-owner-delivered', { + wallet: made.wallet, + hash: tx.hash, + destinationHash: receipt.externalTxHash, + mint: mint.toBase58(), + recipient: recipient.toBase58(), + ata: ata.toBase58(), + beforeRecipient, + afterRecipient: await recipientBalance(), + amount, + }); + }, 900_000); +}); diff --git a/packages/core/__e2e__/agw/universal-evm.spec.ts b/packages/core/__e2e__/agw/universal-evm.spec.ts new file mode 100644 index 00000000..a617a178 --- /dev/null +++ b/packages/core/__e2e__/agw/universal-evm.spec.ts @@ -0,0 +1,244 @@ +/** + * Scenarios 7 and 8 — positive-amount EVM universal execution from the + * wallet, and destination failure classification. + * + * Rules are created through the public v5 UniversalRule SDK path. Destination + * receipt/replay checks remain opt-in funded live tests. + * + * creditRevert accounting is inert on the current executor (gap G07): a + * destination revert after URP passed still counts the spend. + */ +import { + createPublicClient, + encodeFunctionData, + erc20Abi, + fallback, + http, + parseAbi, + parseEventLogs, + parseEther, + type Address, + type Hex, +} from 'viem'; +import { sepolia } from 'viem/chains'; +import { CHAIN } from '../../src/lib/constants/enums'; +import { CHAIN_INFO } from '../../src/lib/constants/chain'; +import { MOVEABLE_TOKEN_CONSTANTS } from '../../src/lib/constants/tokens'; +import { getCEAAddress } from '../../src/lib/orchestrator/cea-utils'; +import { getNativePRC20ForChain } from '../../src/lib/orchestrator/internals/helpers'; +import { v5 } from '../../src/lib/agentic/contracts/v5'; +import { EVM_CHAIN_FIXTURES } from '@e2e/shared/chain-fixtures'; +import { COUNTER_ABI } from '@e2e/shared/outbound-helpers'; +import { verifyExternalTransaction } from '@e2e/shared/external-tx-verifier'; +import { + AGW_E2E_ENABLED, + evmClient, + inSeconds, + setupAgw, + type AgwFixture, +} from './_fixture'; + +const d = AGW_E2E_ENABLED ? describe : describe.skip; +const SEPOLIA = CHAIN.ETHEREUM_SEPOLIA; +const counter = EVM_CHAIN_FIXTURES.find((x) => x.chain === SEPOLIA)!.contracts + .counter as Address; +const INCREMENT = '0xd09de08a' as Hex; +const MISSING = '0xdeadbeef' as Hex; // not implemented by the counter → destination revert +const AMOUNT = BigInt(10) ** BigInt(12); // 0.000001 pETH +// Fresh CEA finalization currently needs ~1.3m gas on Sepolia; the core +// default of 500k was independently shown to revert. Keep a bounded explicit +// destination budget and preserve that default-budget evidence separately. +const DESTINATION_GAS = BigInt(2_000_000); +const MAX_PC = parseEther(process.env['AGW_E2E_MAX_PC_PER_CALL'] ?? '20'); + +d('agw universal evm', () => { + let f: AgwFixture; + let wallet: Address; + let token: Address; + let rulesId: Hex; + let cea: Address; + + beforeAll(async () => { + f = await setupAgw(); + const created = await f.owner.agentic.create('e2e-universal', { + rules: [ + { + agent: f.agentAddress, + chainNamespace: SEPOLIA, + assets: [ + { + token: MOVEABLE_TOKEN_CONSTANTS.ETHEREUM_SEPOLIA.ETH, + maxPerCall: AMOUNT * BigInt(2), + maxTotal: AMOUNT * BigInt(10), + }, + ], + validUntil: inSeconds(3600), + maxGasPerCall: MAX_PC, + allowedCalls: [ + { target: counter, selector: INCREMENT }, + { target: counter, selector: MISSING }, + ], + }, + ], + }); + wallet = created.wallet; + rulesId = created.rulesIds[0]; + token = getNativePRC20ForChain(SEPOLIA, f.manifest.network); + cea = (await getCEAAddress(wallet, SEPOLIA)).cea as Address; + // Separate funding: wallet PC for outbound fees and pETH to burn. + await f.fundPC(wallet, MAX_PC + parseEther('1')); + await ( + await f.owner.universal.sendTransaction({ + to: token, + data: encodeFunctionData({ + abi: erc20Abi, + functionName: 'transfer', + args: [wallet, AMOUNT * BigInt(3)], + }), + }) + ).wait(); + // Bounded allowance through the owner door. + const ownerAgw = await evmClient( + process.env['PUSH_PRIVATE_KEY'] as Hex, + CHAIN.PUSH_TESTNET_DONUT, + f.manifest.network, + wallet + ); + await ( + await ownerAgw.universal.sendTransaction({ + to: token, + data: encodeFunctionData({ + abi: erc20Abi, + functionName: 'approve', + args: [f.manifest.addresses.gateway, AMOUNT * BigInt(2)], + }), + }) + ).wait(); + }, 900_000); + afterAll(() => f?.teardown()); + + it('1. positive-amount outbound: allowance pull/burn, the wallet CEA executes on Sepolia, receipts and replay identity', async () => { + const sep = createPublicClient({ + chain: sepolia, + transport: fallback( + CHAIN_INFO[SEPOLIA].defaultRPC.map((url) => http(url)) + ), + }); + const countBefore = (await sep.readContract({ + address: counter, + abi: COUNTER_ABI, + functionName: 'count', + })) as bigint; + const balBefore = await f.push.readContract({ + address: token, + abi: erc20Abi, + functionName: 'balanceOf', + args: [wallet], + }); + const agent = await f.agent(wallet); + const ceaBefore = await sep.getBalance({ address: cea }); + // Explicit call array: the bridged ETH lands in the wallet's CEA and the + // allow-listed call runs with zero value. A single `data` follows ordinary + // Route 2 semantics and forwards the bridged value to the target. + const tx = await agent.universal.sendTransaction({ + to: { address: counter, chain: SEPOLIA }, + data: [{ to: counter, value: BigInt(0), data: INCREMENT }], + gasLimit: DESTINATION_GAS, + funds: { + amount: AMOUNT, + token: MOVEABLE_TOKEN_CONSTANTS.ETHEREUM_SEPOLIA.ETH, + }, + }); + expect(tx).toMatchObject({ from: wallet, route: 'UOA_TO_CEA' }); + expect(tx.agentic).toMatchObject({ + door: 'agent', + rulesId, + destinationAccount: cea, + }); + f.evidence('v5-evm-outbound-submitted', { + wallet, + cea, + pushTx: tx.hash, + destinationGasLimit: DESTINATION_GAS, + }); + const receipt = await tx.wait({ outboundTimeoutMs: 600_000 }); + expect(receipt.status).toBe(1); + expect(receipt.from).toBe(wallet); + expect(receipt.externalStatus).toBe('success'); + expect(receipt.externalTxHash).toBeTruthy(); + await verifyExternalTransaction(receipt.externalTxHash as string, SEPOLIA); + const destinationReceipt = await sep.getTransactionReceipt({ + hash: receipt.externalTxHash as Hex, + }); + // Attribute the call to this wallet's CEA, independently of a shared + // counter increase. The event is emitted by CEA for each executed step. + const executed = parseEventLogs({ + abi: parseAbi([ + 'event UniversalTxExecuted(bytes32 indexed subTxId, bytes32 indexed universalTxId, address indexed originCaller, address target, bytes data)', + ]), + logs: destinationReceipt.logs, + }); + expect( + executed.some( + (event) => + event.address.toLowerCase() === cea.toLowerCase() && + event.args.originCaller.toLowerCase() === wallet.toLowerCase() && + event.args.target.toLowerCase() === counter.toLowerCase() && + event.args.data === INCREMENT + ) + ).toBe(true); + expect( + await f.push.readContract({ + address: token, + abi: erc20Abi, + functionName: 'balanceOf', + args: [wallet], + }) + ).toBe(balBefore - AMOUNT); + expect( + await f.push.readContract({ + address: token, + abi: erc20Abi, + functionName: 'allowance', + args: [wallet, f.manifest.addresses.gateway], + }) + ).toBe(AMOUNT); + expect( + (await sep.readContract({ + address: counter, + abi: COUNTER_ABI, + functionName: 'count', + })) as bigint + ).toBeGreaterThan(countBefore); + // Independent destination check: the wallet's own CEA received the bridged amount. + expect(await sep.getBalance({ address: cea })).toBe(ceaBefore + AMOUNT); + const replay = await f.owner.universal.trackTransaction(tx.hash); + expect(replay.from).toBe(wallet); + expect(replay.agentic).toMatchObject({ door: 'agent', rulesId }); + f.evidence('universal-outbound', { + wallet, + cea, + rulesId, + pushTx: tx.hash, + externalTx: receipt.externalTxHash, + amount: AMOUNT, + }); + }, 900_000); + + it('2. destination revert is classified on the receipt; the Push leg succeeded', async () => { + const agent = await f.agent(wallet); + const tx = await agent.universal.sendTransaction({ + to: { address: counter, chain: SEPOLIA }, + data: MISSING, + gasLimit: DESTINATION_GAS, + }); + const receipt = await tx.wait({ outboundTimeoutMs: 600_000 }); + expect(receipt.status).toBe(1); + expect(receipt.externalStatus).toMatch(/fail|revert/i); + f.evidence('universal-destination-revert', { + wallet, + pushTx: tx.hash, + externalStatus: receipt.externalStatus, + }); + }, 900_000); +}); diff --git a/packages/core/__e2e__/agw/v5-multiasset.spec.ts b/packages/core/__e2e__/agw/v5-multiasset.spec.ts new file mode 100644 index 00000000..8c3a3cb4 --- /dev/null +++ b/packages/core/__e2e__/agw/v5-multiasset.spec.ts @@ -0,0 +1,344 @@ +/** Opt-in funded Donut acceptance. Nothing in this file runs in unit/local validation. */ +import type { UniversalRule } from '../../src'; +import { + createPublicClient, + encodeFunctionData, + erc20Abi, + fallback, + http, + parseAbi, + parseEventLogs, + parseEther, + type Address, + type Hex, +} from 'viem'; +import { sepolia } from 'viem/chains'; +import { CHAIN_INFO } from '../../src/lib/constants/chain'; +import { getPRC20Address } from '../../src/lib/universal/prc20-address'; +import { getCEAAddress } from '../../src/lib/orchestrator/cea-utils'; +import { configId } from '../../src/lib/agentic/codec/ids'; +import { CHAIN } from '../../src/lib/constants/enums'; +import { MOVEABLE_TOKEN_CONSTANTS } from '../../src/lib/constants/tokens'; +import { v5 } from '../../src/lib/agentic/contracts/v5'; +import { EVM_CHAIN_FIXTURES } from '@e2e/shared/chain-fixtures'; +import { verifyExternalTransaction } from '@e2e/shared/external-tx-verifier'; +import { + AGW_E2E_ENABLED, + evmClient, + inSeconds, + setupAgw, + type AgwFixture, +} from './_fixture'; + +const d = AGW_E2E_ENABLED ? describe : describe.skip; +const chain = CHAIN.ETHEREUM_SEPOLIA; +const counter = EVM_CHAIN_FIXTURES.find((x) => x.chain === chain)!.contracts + .counter as `0x${string}`; + +d('agw v5 multi-asset', () => { + let f: AgwFixture; + beforeAll(async () => { + f = await setupAgw(); + }); + afterAll(() => f?.teardown()); + it('1. public create reads and replaces an ordered two-token rule', async () => { + const rule: UniversalRule = { + agent: f.agentAddress, + chainNamespace: chain, + validUntil: inSeconds(3600), + maxGasPerCall: parseEther('20'), + assets: [ + { + token: MOVEABLE_TOKEN_CONSTANTS.ETHEREUM_SEPOLIA.ETH, + maxPerCall: BigInt(1000), + }, + { + token: MOVEABLE_TOKEN_CONSTANTS.ETHEREUM_SEPOLIA.USDC, + maxPerCall: BigInt(10), + maxTotal: BigInt(100), + }, + ], + allowedCalls: [{ target: counter, selector: 'increment()' as const }], + }; + const created = await f.owner.agentic.create('v5-two-token', { + rules: [rule], + }); + const w = f.owner.agentic.wallet(created.wallet); + const before = await w.rules.get(created.rulesIds[0]); + expect(before.rule).toMatchObject({ + assets: [ + { + maxPerCall: BigInt(1000), + maxTotal: BigInt(2) ** BigInt(256) - BigInt(1), + }, + { maxPerCall: BigInt(10), maxTotal: BigInt(100) }, + ], + }); + expect(before).not.toHaveProperty('spent'); + const count = await f.push.readContract({ + address: created.wallet, + abi: v5.abis.wallet, + functionName: 'checkpointCount', + }); + const replacement = await w.rules.update({ + rules: [{ rulesId: created.rulesIds[0], rule }], + }); + expect( + await f.push.readContract({ + address: created.wallet, + abi: v5.abis.wallet, + functionName: 'checkpointCount', + }) + ).toBe(count + BigInt(5)); + expect((await w.rules.list()).rules.map((x) => x.rulesId)).toEqual([ + replacement.rules[0].rulesId, + ]); + f.evidence('v5-two-token-replacement', { + wallet: created.wallet, + oldId: created.rulesIds[0], + newId: replacement.rules[0].rulesId, + txHash: replacement.tx.hash, + }); + }); + it('2. empty user assets routes a call-only outbound with zero token spend', async () => { + const created = await f.owner.agentic.create('v5-call-only', { + rules: [ + { + agent: f.agentAddress, + chainNamespace: chain, + assets: [], + validUntil: inSeconds(3600), + maxGasPerCall: parseEther('20'), + allowedCalls: [{ target: counter, selector: 'increment()' }], + }, + ], + }); + const record = await f.owner.agentic + .wallet(created.wallet) + .rules.get(created.rulesIds[0]); + expect(record.rule).toMatchObject({ + assets: [{ maxPerCall: BigInt(0), maxTotal: BigInt(0) }], + }); + await f.fundPC(created.wallet, parseEther('21')); + const agent = await f.agent(created.wallet); + const tx = await agent.universal.sendTransaction({ + to: { address: counter, chain }, + data: '0xd09de08a', + gasLimit: BigInt(2_000_000), + }); + const receipt = await tx.wait({ outboundTimeoutMs: 600_000 }); + expect(receipt.status).toBe(1); + expect(receipt.externalTxHash).toBeTruthy(); + await verifyExternalTransaction(receipt.externalTxHash as string, chain); + const [action] = await f.push.readContract({ + address: f.manifest.addresses.sessionEngine, + abi: v5.abis.engine, + functionName: 'getEnabledActions', + args: [created.wallet, created.rulesIds[0]], + }); + const { configId } = await import('../../src/lib/agentic/codec/ids'); + const cfg = await f.push.readContract({ + address: f.manifest.addresses.rulesPolicy, + abi: v5.abis.policy, + functionName: 'getConfig', + args: [ + configId(created.wallet, created.rulesIds[0], action), + created.wallet, + ], + }); + expect(cfg.assets.map((x) => x.spent)).toEqual([BigInt(0)]); + f.evidence('v5-call-only', { + wallet: created.wallet, + pushTx: tx.hash, + externalTx: receipt.externalTxHash, + }); + }, 900_000); + it('3. both assets execute independently after one token budget is exhausted', async () => { + const eth = MOVEABLE_TOKEN_CONSTANTS.ETHEREUM_SEPOLIA.ETH; + const usdc = MOVEABLE_TOKEN_CONSTANTS.ETHEREUM_SEPOLIA.USDC; + const amounts = [BigInt(10) ** BigInt(12), BigInt(10)]; + const tokens = [eth, usdc].map( + (token) => + getPRC20Address( + { chain, address: token.address }, + { network: f.manifest.network } + ).address + ); + // Keep an extra token unit and allowance available so total-limit failures + // reach URP instead of being masked by the SDK balance/allowance checks. + for (let i = 0; i < tokens.length; i++) { + const available = await f.push.readContract({ + address: tokens[i], + abi: erc20Abi, + functionName: 'balanceOf', + args: [f.ownerAddress], + }); + if (available < amounts[i] + BigInt(1)) + throw new Error('Insufficient master funds for two-asset fixture'); + } + const made = await f.owner.agentic.create('v5-independent-budgets', { + rules: [ + { + agent: f.agentAddress, + chainNamespace: chain, + validUntil: inSeconds(3600), + maxGasPerCall: parseEther('20'), + assets: [eth, usdc].map((token, i) => ({ + token, + maxPerCall: amounts[i], + maxTotal: amounts[i], + })), + allowedCalls: [{ target: counter, selector: 'increment()' }], + }, + ], + }); + await f.fundPC(made.wallet, parseEther('41')); + const owner = await evmClient( + process.env['PUSH_PRIVATE_KEY'] as Hex, + CHAIN.PUSH_TESTNET_DONUT, + f.manifest.network, + made.wallet + ); + for (let i = 0; i < tokens.length; i++) { + await ( + await f.owner.universal.sendTransaction({ + to: tokens[i], + data: encodeFunctionData({ + abi: erc20Abi, + functionName: 'transfer', + args: [made.wallet, amounts[i] + BigInt(1)], + }), + }) + ).wait(); + await ( + await owner.universal.sendTransaction({ + to: tokens[i], + data: encodeFunctionData({ + abi: erc20Abi, + functionName: 'approve', + args: [f.manifest.addresses.gateway, amounts[i] + BigInt(1)], + }), + }) + ).wait(); + } + const agent = await f.agent(made.wallet); + const [action] = await f.push.readContract({ + address: f.manifest.addresses.sessionEngine, + abi: v5.abis.engine, + functionName: 'getEnabledActions', + args: [made.wallet, made.rulesIds[0]], + }); + const key = configId(made.wallet, made.rulesIds[0], action); + const spent = async () => + ( + await f.push.readContract({ + address: f.manifest.addresses.rulesPolicy, + abi: v5.abis.policy, + functionName: 'getConfig', + args: [key, made.wallet], + }) + ).assets.map((asset) => asset.spent); + const sep = createPublicClient({ + chain: sepolia, + transport: fallback(CHAIN_INFO[chain].defaultRPC.map((url) => http(url))), + }); + const cea = (await getCEAAddress(made.wallet, chain)).cea as Address; + const params = (i: number, amount = amounts[i]) => ({ + to: { address: counter, chain }, + data: [{ to: counter, value: BigInt(0), data: '0xd09de08a' as Hex }], + funds: { token: [eth, usdc][i], amount }, + gasLimit: BigInt(2_000_000), + }); + const hashes: string[] = []; + expect(await spent()).toEqual([BigInt(0), BigInt(0)]); + for (let i = 0; i < tokens.length; i++) { + const beforeDestination = + i === 0 + ? await sep.getBalance({ address: cea }) + : await sep.readContract({ + address: usdc.address as Address, + abi: erc20Abi, + functionName: 'balanceOf', + args: [cea], + }); + const tx = await agent.universal.sendTransaction(params(i)); + f.evidence('v5-budget-outbound-submitted', { + wallet: made.wallet, + rulesId: made.rulesIds[0], + token: tokens[i], + amount: amounts[i], + pushTx: tx.hash, + }); + const receipt = await tx.wait({ outboundTimeoutMs: 600_000 }); + expect(receipt.externalStatus).toBe('success'); + await verifyExternalTransaction(receipt.externalTxHash!, chain); + const external = await sep.getTransactionReceipt({ + hash: receipt.externalTxHash as Hex, + }); + const executed = parseEventLogs({ + abi: parseAbi([ + 'event UniversalTxExecuted(bytes32 indexed subTxId, bytes32 indexed universalTxId, address indexed originCaller, address target, bytes data)', + ]), + logs: external.logs, + }); + expect( + executed.some( + (event) => + event.address.toLowerCase() === cea.toLowerCase() && + event.args.originCaller.toLowerCase() === + made.wallet.toLowerCase() && + event.args.target.toLowerCase() === counter.toLowerCase() + ) + ).toBe(true); + const afterDestination = + i === 0 + ? await sep.getBalance({ address: cea }) + : await sep.readContract({ + address: usdc.address as Address, + abi: erc20Abi, + functionName: 'balanceOf', + args: [cea], + }); + expect(afterDestination).toBe(beforeDestination + amounts[i]); + expect( + await f.push.readContract({ + address: tokens[i], + abi: erc20Abi, + functionName: 'balanceOf', + args: [made.wallet], + }) + ).toBe(BigInt(1)); + expect( + await f.push.readContract({ + address: tokens[i], + abi: erc20Abi, + functionName: 'allowance', + args: [made.wallet, f.manifest.addresses.gateway], + }) + ).toBe(BigInt(1)); + const expected = i === 0 ? [amounts[0], BigInt(0)] : amounts; + expect(await spent()).toEqual(expected); + const nonce = await f.push.getTransactionCount({ + address: f.agentAddress, + }); + await expect( + agent.universal.sendTransaction(params(i, BigInt(1))) + ).rejects.toMatchObject({ + decodedError: { name: 'PolicyCheckReverted(TotalSpendCapExceeded)' }, + }); + expect( + await f.push.getTransactionCount({ address: f.agentAddress }) + ).toBe(nonce); + expect(await spent()).toEqual(expected); + hashes.push(tx.hash, receipt.externalTxHash!); + } + f.evidence('v5-independent-token-budgets', { + wallet: made.wallet, + rulesId: made.rulesIds[0], + tokens, + amounts, + spent: await spent(), + hashes, + }); + }, 1_800_000); +}); diff --git a/packages/core/__e2e__/ci/agw-svm-preflight.ts b/packages/core/__e2e__/ci/agw-svm-preflight.ts new file mode 100644 index 00000000..588ef2c5 --- /dev/null +++ b/packages/core/__e2e__/ci/agw-svm-preflight.ts @@ -0,0 +1,30 @@ +/** No dotenv, signers or transactions: inspect both networks before funding a wire test. */ +import { mkdirSync, writeFileSync } from 'node:fs'; +import { dirname } from 'node:path'; +import { createPublicClient, fallback, http, parseAbi, type Address } from 'viem'; +import { CHAIN_INFO, getPushViemChain } from '../../src/lib/constants/chain'; +import { CHAIN } from '../../src/lib/constants/enums'; +import { loadAgwManifest, verifyAgwManifest } from '../agw/_manifest'; +import { inspectSvmWirePrograms, svmWireConnection, SVM_WIRE_CHAIN } from '../shared/agw-svm-preflight'; + +async function main() { + const manifest = loadAgwManifest(); + const push = createPublicClient({ chain: getPushViemChain(CHAIN.PUSH_TESTNET_DONUT), transport: fallback(CHAIN_INFO[CHAIN.PUSH_TESTNET_DONUT].defaultRPC.map((u) => http(u))) }); + await verifyAgwManifest(push, manifest); + const block = await push.getBlockNumber(); + const token = await push.readContract({ address: '0x00000000000000000000000000000000000000C0', + abi: parseAbi(['function gasTokenPRC20ByChainNamespace(string) view returns (address)']), + functionName: 'gasTokenPRC20ByChainNamespace', args: [SVM_WIRE_CHAIN], blockNumber: block }) as Address; + const source = await push.readContract({ address: token, abi: parseAbi(['function SOURCE_CHAIN_NAMESPACE() view returns (string)']), functionName: 'SOURCE_CHAIN_NAMESPACE', blockNumber: block }); + if (source !== SVM_WIRE_CHAIN) throw new Error('Gas PRC20 does not match Solana devnet'); + const quote = await push.readContract({ address: '0x00000000000000000000000000000000000000C0', + abi: parseAbi(['function getOutboundTxGasAndFees(address,uint256) view returns (address,uint256,uint256,uint256,string,uint256)']), + functionName: 'getOutboundTxGasAndFees', args: [token, BigInt(0)], blockNumber: block }); + const solana = await inspectSvmWirePrograms(svmWireConnection()); + const result = { push: { chainId: await push.getChainId(), block, sourceCommit: manifest.sourceCommit, token, quote }, solana, transactionsSent: 0 }; + const json = JSON.stringify(result, (_k, v) => typeof v === 'bigint' ? v.toString() : v, 2) + '\n'; + const output = process.argv[2]; + if (output) { mkdirSync(dirname(output), { recursive: true }); writeFileSync(output, json); } + process.stdout.write(json); +} +main().catch((error) => { console.error((error as Error).message); process.exitCode = 1; }); diff --git a/packages/core/__e2e__/ci/preflight.ts b/packages/core/__e2e__/ci/preflight.ts index 405ea41f..e7bc8c5e 100644 --- a/packages/core/__e2e__/ci/preflight.ts +++ b/packages/core/__e2e__/ci/preflight.ts @@ -64,6 +64,7 @@ import { deriveAtaPubkey, } from '../../src/lib/orchestrator/internals/svm-rent'; import { scenariosFor, aggregateNeeds, type Asset } from './suite'; +import { loadAgwManifest, verifyAgwManifest } from '../agw/_manifest'; // --------------------------------------------------------------------------- // tunables @@ -285,6 +286,10 @@ function renderTable(rows: Row[]): void { (async () => { const scenarios = scenariosFor(group); const raw = aggregateNeeds(scenarios); + if (group === 'agw-svm-replay') { + console.log('Recorded SVM replay is read-only: no keys, signing or funding needed.'); + return; + } /** Summed need for an asset, with headroom and reserve, as a decimal string. */ const target = (a: Asset): number => { @@ -326,6 +331,26 @@ function renderTable(rows: Row[]): void { chain: pushChainDef, transport: fallback(pushRpcs.map((u) => http(u))), }) as PublicClient; + + // -- AGW gate ------------------------------------------------------------ + // Every AGW group needs a verified compatible AGW deployment. + // Check it read-only BEFORE any balance work so nothing is ever funded for + // a run that cannot exercise a real deployment. + if (scenarios.some((s) => s.group.startsWith('agw'))) { + try { + await verifyAgwManifest(push, loadAgwManifest()); + console.log('AGW deployment manifest verified on-chain.'); + } catch (err) { + console.error(`\n${(err as Error).message}`); + console.error('No transactions were sent.'); + process.exit(1); + } + } + if (scenarios.some((s) => s.group === 'agw-svm-wire' || s.file === '__e2e__/agw/svm-public.spec.ts')) { + const { inspectSvmWirePrograms, svmWireConnection } = await import('../shared/agw-svm-preflight'); + await inspectSvmWirePrograms(svmWireConnection(solRpc)); + console.log('Solana wire fixture verified read-only before funding.'); + } const pushWallet = createWalletClient({ account: pushAcc, chain: pushChainDef, @@ -390,18 +415,19 @@ function renderTable(rows: Row[]): void { return BigInt(r?.value.amount ?? '0'); }); - const [dUsdtSep, dPeth, dUsdtEth, dPsol, dUsdtSol] = await Promise.all([ + const [dUsdtSep, dPeth, dUsdtEth, dPsol, dUsdtSol, dUsdcEth] = await Promise.all([ decimalsOf(usdtSepolia, sep), decimalsOf(s.pETH, push), decimalsOf(s.USDT_ETH, push), decimalsOf(s.pSOL, push), decimalsOf(s.USDT_SOL, push), + decimalsOf(s.USDC_ETH, push), ]); const dPc20 = pc20Push ? await decimalsOf(pc20Push, push) : 18; const [ sepEth, sepUsdt, - mPC, mPeth, mUsdtEth, mPsol, mUsdtSol, mPc20, + mPC, mPeth, mUsdtEth, mPsol, mUsdtSol, mUsdcEth, mPc20, uPC, uPeth, uUsdtEth, uPsol, uUsdtSol, uPc20, solBal, solUsdt, ceaSol, ceaUsdt, ] = await Promise.all([ @@ -413,6 +439,7 @@ function renderTable(rows: Row[]): void { erc20(s.USDT_ETH, pushAcc.address, push), erc20(s.pSOL, pushAcc.address, push), erc20(s.USDT_SOL, pushAcc.address, push), + erc20(s.USDC_ETH, pushAcc.address, push), pc20Push ? erc20(pc20Push, pushAcc.address, push) : Promise.resolve(BigInt(0)), retry(() => push.getBalance({ address: uea })), @@ -458,8 +485,9 @@ function renderTable(rows: Row[]): void { { scope: 'Push master (Donut)', asset: 'PC', need: units(target('masterPC'), 18) + deficit('ueaPC'), have: mPC, decimals: 18, tier: 'master' }, { scope: 'Push master (Donut)', asset: 'pETH', need: units(target('masterPETH'), dPeth) + deficit('ueaPETH'), have: mPeth, decimals: dPeth, tier: 'master' }, { scope: 'Push master (Donut)', asset: 'pUSDT.eth', need: deficit('ueaUsdtEth'), have: mUsdtEth, decimals: dUsdtEth, tier: 'master' }, - { scope: 'Push master (Donut)', asset: 'pSOL', need: deficit('ueaPSOL'), have: mPsol, decimals: dPsol, tier: 'master' }, - { scope: 'Push master (Donut)', asset: 'pUSDT.sol', need: deficit('ueaUsdtSol'), have: mUsdtSol, decimals: dUsdtSol, tier: 'master' }, + { scope: 'Push master (Donut)', asset: 'pSOL', need: units(target('masterPSOL'), dPsol) + deficit('ueaPSOL'), have: mPsol, decimals: dPsol, tier: 'master' }, + { scope: 'Push master (Donut)', asset: 'pUSDT.sol', need: units(target('masterUsdtSol'), dUsdtSol) + deficit('ueaUsdtSol'), have: mUsdtSol, decimals: dUsdtSol, tier: 'master' }, + { scope: 'Push master (Donut)', asset: 'pUSDC.eth', need: units(target('masterUsdcEth'), dUsdcEth), have: mUsdcEth, decimals: dUsdcEth, tier: 'master' }, { scope: 'Push master (Donut)', asset: 'PC20', need: deficit('ueaPC20'), have: mPc20, decimals: dPc20, tier: 'master' }, { scope: 'Solana master (Devnet)', asset: 'SOL', need: units(target('solanaSOL'), 9) + deficit('ceaSvmSOL'), have: solBal, decimals: 9, tier: 'master' }, { scope: 'Solana master (Devnet)', asset: 'USDT', need: units(target('solanaUsdt'), 6) + deficit('ceaSvmUsdt'), have: solUsdt, decimals: 6, tier: 'master' }, diff --git a/packages/core/__e2e__/ci/run.ts b/packages/core/__e2e__/ci/run.ts index 33d1ae10..5ff82702 100644 --- a/packages/core/__e2e__/ci/run.ts +++ b/packages/core/__e2e__/ci/run.ts @@ -6,8 +6,10 @@ * npx ts-node --transpile-only __e2e__/ci/run.ts [options] * * --group One of: all (default), smoke, evm-r1, evm-r2, evm-r3, - * svm-r1, svm-r2r3, pc20, push, cross-chain, known-fail - * (`all` excludes known-fail — ask for it by name) + * svm-r1, svm-r2r3, pc20, push, cross-chain, read, + * known-fail, agw, agw-svm-wire, agw-svm-replay + * (`all` excludes known-fail and AGW groups — ask by name; + * agw uses the checked Donut v5 manifest by default, see __e2e__/agw/_manifest.ts) * --list Print the selection and the jest argv, run nothing * --verify Check every `grep` against the real spec titles and exit * non-zero if any fragment matches 0 or >1 tests in its file @@ -55,7 +57,8 @@ function classify(prefix: string): 'describe' | 'it' | null { if (/\?[\s\S]*\b(it|test)\b[\s\S]*\)$/.test(p)) return 'it'; const m = p.match(/([A-Za-z_$][\w$]*)(?:\.(skip|only|failing|concurrent))?$/); if (!m) return null; - if (/^(describe|d|dWrapper|xdescribe|fdescribe)$/.test(m[1])) return 'describe'; + if (/^(describe|d|dWrapper|xdescribe|fdescribe)$/.test(m[1])) + return 'describe'; if (/^(it|test|xit|fit|itWrapper|itIf)$/.test(m[1])) return 'it'; return null; } @@ -83,7 +86,13 @@ function titlesOf(specPath: string): string[] { const depth = depthAt[at]; while (stack.length && stack[stack.length - 1].depth >= depth) stack.pop(); if (kind === 'describe') stack.push({ title: m[2], depth }); - else titles.push(stack.map((s) => s.title).concat(m[2]).join(' ')); + else + titles.push( + stack + .map((s) => s.title) + .concat(m[2]) + .join(' ') + ); } return titles; } @@ -158,13 +167,17 @@ if (has('verify')) { bad++; } else { for (const h of hits) seen.set(h, (seen.get(h) ?? []).concat(s.id)); - console.log(`✓ ${s.id.padEnd(32)} ${hits.length} test${hits.length > 1 ? 's' : ''}`); + console.log( + `✓ ${s.id.padEnd(32)} ${hits.length} test${hits.length > 1 ? 's' : ''}` + ); } } const dupes = [...seen.entries()].filter(([, ids]) => ids.length > 1); for (const [title, ids] of dupes) { - console.error(`✗ overlapping fragments — "${title}" claimed by ${ids.join(', ')}`); + console.error( + `✗ overlapping fragments — "${title}" claimed by ${ids.join(', ')}` + ); bad++; } @@ -193,7 +206,9 @@ if (has('verify')) { `\n${selected.length} scenarios, ${files.length} spec files, ${seen.size} distinct tests.` ); if (bad) { - console.error(`\n${bad} problem(s). The manifest has drifted from the specs.`); + console.error( + `\n${bad} problem(s). The manifest has drifted from the specs.` + ); process.exit(1); } console.log('Manifest is consistent with the specs.'); @@ -202,7 +217,8 @@ if (has('verify')) { if (has('list')) { const byGroup = new Map(); - for (const s of selected) byGroup.set(s.group, (byGroup.get(s.group) ?? []).concat(s)); + for (const s of selected) + byGroup.set(s.group, (byGroup.get(s.group) ?? []).concat(s)); for (const g of GROUPS) { const rows = byGroup.get(g); if (!rows) continue; @@ -214,8 +230,14 @@ if (has('list')) { console.log(` ${s.id.padEnd(32)} ${cost || '(free)'}`); } } - console.log(`\n${selected.length} scenarios across ${files.length} spec files.`); - console.log(`\nnpx ${jestArgs.map((a) => (/[\s|()]/.test(a) ? JSON.stringify(a) : a)).join(' ')}`); + console.log( + `\n${selected.length} scenarios across ${files.length} spec files.` + ); + console.log( + `\nnpx ${jestArgs + .map((a) => (/[\s|()]/.test(a) ? JSON.stringify(a) : a)) + .join(' ')}` + ); process.exit(0); } @@ -225,7 +247,9 @@ if (has('list')) { fs.mkdirSync(LOG_DIR, { recursive: true }); -console.log(`Running ${selected.length} scenarios (group: ${group}) across ${files.length} spec files.\n`); +console.log( + `Running ${selected.length} scenarios (group: ${group}) across ${files.length} spec files.\n` +); const result = spawnSync('npx', jestArgs, { cwd: CORE_ROOT, @@ -277,7 +301,9 @@ function writeSummary(): void { const skipped = all.length - passed - failed; // Skipped rows are the tests jest loaded but `-t` filtered out — noise here. - const shown = all.filter((a) => a.status !== 'pending' && a.status !== 'skipped'); + const shown = all.filter( + (a) => a.status !== 'pending' && a.status !== 'skipped' + ); const lines = [ `## E2E — group \`${group}\``, diff --git a/packages/core/__e2e__/ci/suite.ts b/packages/core/__e2e__/ci/suite.ts index 71ff5966..3bc27a74 100644 --- a/packages/core/__e2e__/ci/suite.ts +++ b/packages/core/__e2e__/ci/suite.ts @@ -34,6 +34,9 @@ export const GROUPS = [ 'cross-chain', 'read', 'known-fail', + 'agw', + 'agw-svm-wire', + 'agw-svm-replay', ] as const; export type Group = (typeof GROUPS)[number]; @@ -69,6 +72,9 @@ export type Asset = // Push master (PUSH_PRIVATE_KEY) on Push Donut — Push-native origin specs | 'masterPC' | 'masterPETH' + | 'masterPSOL' + | 'masterUsdcEth' + | 'masterUsdtSol' // The EVM master's UEA on Push Donut — Routes 2/3 on both VMs, and PC20 | 'ueaPC' | 'ueaPETH' @@ -149,9 +155,52 @@ const F = { readSvmIdl: '__e2e__/read/svm/account-idl.spec.ts', readMutability: '__e2e__/read/evm/any-mutability.spec.ts', readTrackLookup: '__e2e__/read/lifecycle/track-lookup.spec.ts', + agwCreate: '__e2e__/agw/create.spec.ts', + agwFunding: '__e2e__/agw/funding-allowance.spec.ts', + agwNative: '__e2e__/agw/native-exec.spec.ts', + agwLifecycle: '__e2e__/agw/lifecycle.spec.ts', + agwUniversal: '__e2e__/agw/universal-evm.spec.ts', + agwIdentity: '__e2e__/agw/identity-gas.spec.ts', + agwResponses: '__e2e__/agw/responses-hooks.spec.ts', + agwExtendedManagement: '__e2e__/agw/management-extended.spec.ts', + agwExtendedNative: '__e2e__/agw/native-policy-extended.spec.ts', } as const; export const SCENARIOS: Scenario[] = [ + { + id: 'agw-svm-replay-positive', group: 'agw-svm-replay', file: '__e2e__/agw-svm-wire/replay.spec.ts', + grep: 'agw svm recorded replay 1\\. positive replay', needs: {}, env: { AGW_SVM_WIRE_REPLAY_E2E: '1' }, + }, + { + id: 'agw-svm-replay-rejected', group: 'agw-svm-replay', file: '__e2e__/agw-svm-wire/replay.spec.ts', + grep: 'agw svm recorded replay 2\\. later terminal rejection', needs: {}, env: { AGW_SVM_WIRE_REPLAY_E2E: '1' }, + }, + { + id: 'agw-svm-replay-policy', group: 'agw-svm-replay', file: '__e2e__/agw-svm-wire/replay.spec.ts', + grep: 'agw svm recorded replay 3\\. pinned live policy', needs: {}, env: { AGW_SVM_WIRE_REPLAY_E2E: '1' }, + }, + { + id: 'agw-svm-wire-positive', group: 'agw-svm-wire', + file: '__e2e__/agw-svm-wire/outbound.spec.ts', + grep: 'agw svm wire 1\\. positive outbound', + needs: { masterPC: '45', masterPSOL: '0.00002' }, + env: { AGW_SVM_WIRE_E2E: '1' }, + note: 'Internal prepared-wire backend; public SVM capability remains gated.', + }, + { + id: 'agw-svm-wire-refusals', group: 'agw-svm-wire', + file: '__e2e__/agw-svm-wire/outbound.spec.ts', + grep: 'agw svm wire 2\\. substituted account', + needs: { masterPC: '45', masterPSOL: '0.00002' }, + env: { AGW_SVM_WIRE_E2E: '1' }, + }, + { + id: 'agw-svm-wire-failure', group: 'agw-svm-wire', + file: '__e2e__/agw-svm-wire/outbound.spec.ts', + grep: 'agw svm wire 3\\. destination program failure', + needs: { masterPC: '45', masterPSOL: '0.00002' }, + env: { AGW_SVM_WIRE_E2E: '1' }, + }, // --------------------------------------------------------------------------- // smoke — read-only. No transactions, no funds. Runs first so a broken build or // a dead RPC fails in ~3 min instead of 90. @@ -615,8 +664,11 @@ export const SCENARIOS: Scenario[] = [ note: 'prepareRead → simulateRead → sendTransaction → trackRead → value == Sepolia balance at pin.', }, { - id: 'read-canonical-registry', group: 'read', file: F.readRegistry, - grep: 'read state › canonical registry', needs: { masterPC: '0.2' }, + id: 'read-canonical-registry', + group: 'read', + file: F.readRegistry, + grep: 'read state › canonical registry', + needs: { masterPC: '0.2' }, note: 'Callback-free read plus a second pin: verifies per-request storage, stable-key latestResult and settlement.', }, { @@ -673,16 +725,25 @@ export const SCENARIOS: Scenario[] = [ note: 'Funds a fresh wallet with 0.5 PC, as the docs prompt will.', }, { - id: 'read-docs-evm-balance', group: 'read', file: F.readPlaygrounds, - grep: 'docs-examples › 13-read-state playgrounds universal_read_evm_balance', needs: { masterPC: '0.1' }, + id: 'read-docs-evm-balance', + group: 'read', + file: F.readPlaygrounds, + grep: 'docs-examples › 13-read-state playgrounds universal_read_evm_balance', + needs: { masterPC: '0.1' }, }, { - id: 'read-docs-batch', group: 'read', file: F.readPlaygrounds, - grep: 'docs-examples › 13-read-state playgrounds universal_read_batch', needs: { masterPC: '0.1' }, + id: 'read-docs-batch', + group: 'read', + file: F.readPlaygrounds, + grep: 'docs-examples › 13-read-state playgrounds universal_read_batch', + needs: { masterPC: '0.1' }, }, { - id: 'read-docs-resume', group: 'read', file: F.readPlaygrounds, - grep: 'docs-examples › 13-read-state playgrounds universal_read_resume', needs: { masterPC: '0.1' }, + id: 'read-docs-resume', + group: 'read', + file: F.readPlaygrounds, + grep: 'docs-examples › 13-read-state playgrounds universal_read_resume', + needs: { masterPC: '0.1' }, note: 'Read-only resume (own request ID, predefined request ID, tx hash); seeds a request if the balance example was not selected.', }, { @@ -702,37 +763,55 @@ export const SCENARIOS: Scenario[] = [ note: 'Same batch through the UEA — one atomic tx.', }, { - id: 'read-app-batch-recovery', group: 'read', file: F.readBatch, + id: 'read-app-batch-recovery', + group: 'read', + file: F.readBatch, grep: 'read state › custom app batch recovers the committed read', needs: { masterPC: '0.1' }, note: 'Force sequential wallet execution; recover the first read after the second request fails.', }, { - id: 'read-api-token', group: 'read', file: F.readApi, - grep: 'read state › public API coverage ERC20 shorthand', needs: { masterPC: '0.1' }, + id: 'read-api-token', + group: 'read', + file: F.readApi, + grep: 'read state › public API coverage ERC20 shorthand', + needs: { masterPC: '0.1' }, }, { - id: 'read-api-mixed-outcomes', group: 'read', file: F.readApi, - grep: 'read state › public API coverage mixed consensus outcomes', needs: { masterPC: '0.3' }, + id: 'read-api-mixed-outcomes', + group: 'read', + file: F.readApi, + grep: 'read state › public API coverage mixed consensus outcomes', + needs: { masterPC: '0.3' }, }, { - id: 'read-svm-token-auto', group: 'read', file: F.readSvmIdl, + id: 'read-svm-token-auto', + group: 'read', + file: F.readSvmIdl, grep: 'read state › Solana automatic token and IDL account reads detects the mint program', needs: { masterPC: '0.1' }, }, { - id: 'read-svm-idl', group: 'read', file: F.readSvmIdl, + id: 'read-svm-idl', + group: 'read', + file: F.readSvmIdl, grep: 'read state › Solana automatic token and IDL account reads decodes a real Anchor account', needs: { masterPC: '0.1' }, }, { - id: 'read-evm-any-mutability', group: 'read', file: F.readMutability, - grep: 'read state › EVM nonpayable and payable functions', needs: { masterPC: '0.1' }, + id: 'read-evm-any-mutability', + group: 'read', + file: F.readMutability, + grep: 'read state › EVM nonpayable and payable functions', + needs: { masterPC: '0.1' }, note: 'QuoterV2 (nonpayable) + Multicall3.aggregate (payable) simulated at the pinned block.', }, { - id: 'read-svm-raw', group: 'read', file: F.readSvmRaw, - grep: 'read state › SVM raw account', needs: { masterPC: '0.1' }, + id: 'read-svm-raw', + group: 'read', + file: F.readSvmRaw, + grep: 'read state › SVM raw account', + needs: { masterPC: '0.1' }, }, // --------------------------------------------------------------------------- @@ -753,15 +832,278 @@ export const SCENARIOS: Scenario[] = [ '(balance - reserve, the pre-fix behaviour) where the test expects the full ' + '~20.9 PC requirement. Real regression in the Route 2 dead-zone gas sizer.', }, + + // ------------------------------------------------------------------------- + // agw — agentic wallets. EXCLUDED from `all`: every spec's beforeAll fails + // its prerequisite gate until a verified compatible AGW deployment manifest + // (AGW_DEPLOYMENT_MANIFEST) exists. Preflight + // refuses to fund the group without it. Budgets are per run: the Push master + // (owner) pays setup gas, wallet PC and the bounded fresh-agent funding; + // the EVM master's UEA pays external-agent gas; pETH funds the outbound. + // ------------------------------------------------------------------------- + { + id: 'agw-create-bare', + group: 'agw', + file: F.agwCreate, + grep: 'agw create 1\\. bare wallet', + needs: { masterPC: '2' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-create-rules', + group: 'agw', + file: F.agwCreate, + grep: 'agw create 2\\. wallet with a native rule', + needs: { masterPC: '2' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-funding-pc', + group: 'agw', + file: F.agwFunding, + grep: 'agw funding 1\\. wallet PC', + needs: { masterPC: '1' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-funding-allowance', + group: 'agw', + file: F.agwFunding, + grep: 'agw funding 2\\. owner sets and removes', + needs: { masterPC: '1' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-native-batch', + group: 'agw', + file: '__e2e__/agw/native-batch.spec.ts', + grep: 'agw native batch 1\\. sender-preserving atomic', + needs: { masterPC: '2' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-native-batch-rollback', + group: 'agw', + file: '__e2e__/agw/native-batch.spec.ts', + grep: 'agw native batch 2\\. a later policy failure', + needs: { masterPC: '2' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-native-agent', + group: 'agw', + file: F.agwNative, + grep: 'agw native 1\\. agent door', + needs: { masterPC: '2' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-native-owner', + group: 'agw', + file: F.agwNative, + grep: 'agw native 2\\. owner door', + needs: { masterPC: '0.5' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-native-over-cap', + group: 'agw', + file: F.agwNative, + grep: 'agw native 3\\. over-cap', + needs: { masterPC: '0.5' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-native-stranger', + group: 'agw', + file: F.agwNative, + grep: 'agw native 4\\. an unrelated signer', + needs: { masterPC: '0.1' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-native-revoked', + group: 'agw', + file: F.agwNative, + grep: 'agw native 5\\. after revocation', + needs: { masterPC: '0.5' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-native-expired', + group: 'agw', + file: F.agwNative, + grep: 'agw native 6\\. an expired rule', + needs: { masterPC: '1' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-lifecycle-add', + group: 'agw', + file: F.agwLifecycle, + grep: 'agw lifecycle 1\\. rules\\.add', + needs: { masterPC: '2' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-lifecycle-update', + group: 'agw', + file: F.agwLifecycle, + grep: 'agw lifecycle 2\\. rules\\.update', + needs: { masterPC: '1' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-lifecycle-checkpoints', + group: 'agw', + file: F.agwLifecycle, + grep: 'agw lifecycle 3\\. checkpoint history', + needs: { masterPC: '0.1' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-lifecycle-revoke-all', + group: 'agw', + file: F.agwLifecycle, + grep: 'agw lifecycle 4\\. revoke', + needs: { masterPC: '0.5' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-universal-outbound', + group: 'agw', + file: F.agwUniversal, + grep: 'agw universal evm 1\\. positive-amount outbound', + needs: { masterPC: '25', masterPETH: '0.00001' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-v5-multi-asset', + group: 'agw', + file: '__e2e__/agw/v5-multiasset.spec.ts', + grep: 'agw v5 multi-asset 1\\. public create', + needs: { masterPC: '2' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-v5-call-only', + group: 'agw', + file: '__e2e__/agw/v5-multiasset.spec.ts', + grep: 'agw v5 multi-asset 2\\. empty user assets', + needs: { masterPC: '25' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-universal-dest-revert', + group: 'agw', + file: F.agwUniversal, + grep: 'agw universal evm 2\\. destination revert', + needs: { masterPC: '5' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-identity-evm', + group: 'agw', + file: F.agwIdentity, + grep: 'agw identity 1\\. an EVM key on Sepolia', + needs: { masterPC: '1', ueaPC: '1' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-identity-first-use', + group: 'agw', + file: F.agwIdentity, + grep: 'agw identity 2\\. first use', + needs: { masterPC: '1', sepoliaEth: '0.003' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-identity-solana', + group: 'agw', + file: F.agwIdentity, + grep: 'agw identity 3\\. a Solana-origin key', + needs: { masterPC: '1' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-responses-hooks', + group: 'agw', + file: F.agwResponses, + grep: 'agw responses 1\\. init and per-call hooks', + needs: { masterPC: '1' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-responses-replay', + group: 'agw', + file: F.agwResponses, + grep: 'agw responses 2\\. live and replayed', + needs: { masterPC: '0.5' }, + env: { AGW_E2E: '1' }, + }, + + ...Array.from({ length: 6 }, (_, i) => ({ + id: `agw-public-svm-${i + 1}`, group: 'agw' as const, + file: '__e2e__/agw/svm-public.spec.ts', grep: `agw public svm ${i + 1}\\.`, + needs: { masterPC: '45', masterPSOL: '0.000020001' }, env: { AGW_E2E: '1' }, + })), + + ...Array.from({ length: 8 }, (_, i) => ({ + id: `agw-labels-${i + 1}`, group: 'agw' as const, + file: '__e2e__/agw/labels.spec.ts', grep: `agw labels ${i + 1}\\.`, + needs: i === 4 ? { masterPC: '4', sepoliaEth: '0.003' } : i === 5 ? { masterPC: '4', solanaSOL: '0.003' } : { masterPC: '1' }, + env: { AGW_E2E: '1' }, + })), + + { + id: 'agw-v5-independent-token-budgets', group: 'agw', + file: '__e2e__/agw/v5-multiasset.spec.ts', grep: 'agw v5 multi-asset 3\\.', + needs: { masterPC: '45', masterPETH: '0.000001000000000001', masterUsdcEth: '0.000011' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-owner-spl-transfer', group: 'agw', + file: '__e2e__/agw/svm-spl-transfer.spec.ts', grep: 'agw svm spl transfer 1\\.', + needs: { masterPC: '23', masterUsdtSol: '0.001' }, + env: { AGW_E2E: '1' }, + }, + + // Extended AGW tests are opt-in and use bounded per-scenario testnet budgets. + ...[ + ['prefunding', '1\\. prefunding', '11'], + ['ambiguous-rules', '2\\. same-agent multiplicity', '11'], + ['batched-lifecycle', '3\\. multi-rule add', '0.5'], + ['invalid-revoke', '4\\. invalid revoke', '0.5'], + ['stale-update', '5\\. intervening agent spend', '11'], + ['index-race', '6\\. index race', '1'], + ].map(([slug, grep, pc]) => ({ + id: `agw-extended-${slug}`, + group: 'agw' as const, + file: F.agwExtendedManagement, + grep: `agw extended management ${grep}`, + needs: { masterPC: pc }, + env: { AGW_E2E: '1' }, + })), + ...Array.from({ length: 11 }, (_, i) => ({ + id: `agw-extended-native-policy-${i + 1}`, + group: 'agw' as const, + file: F.agwExtendedNative, + grep: `agw extended native policy ${i + 1}\\.`, + needs: { masterPC: '0.25', masterPETH: '0.000000000001' }, + env: { AGW_E2E: '1' }, + })), ]; /** * Scenarios for a group. `all` means "everything that should pass" — it deliberately - * excludes `known-fail`, which has to be asked for by name. + * excludes `known-fail` and every AGW group, which must be requested by name. */ export function scenariosFor(group: string | undefined): Scenario[] { if (!group || group === 'all') { - return SCENARIOS.filter((s) => s.group !== 'known-fail'); + // AGW stays opt-in: scenarios create/fund fresh wallets and consume testnet funds. + return SCENARIOS.filter( + (s) => s.group !== 'known-fail' && !s.group.startsWith('agw') + ); } if (!(GROUPS as readonly string[]).includes(group)) { throw new Error( @@ -777,7 +1119,10 @@ export function aggregateNeeds( ): Partial> { const total: Partial> = {}; for (const s of scenarios) { - for (const [asset, amount] of Object.entries(s.needs) as [Asset, string][]) { + for (const [asset, amount] of Object.entries(s.needs) as [ + Asset, + string + ][]) { total[asset] = (total[asset] ?? 0) + Number(amount); } } diff --git a/packages/core/__e2e__/shared/agw-state.ts b/packages/core/__e2e__/shared/agw-state.ts new file mode 100644 index 00000000..2c633e03 --- /dev/null +++ b/packages/core/__e2e__/shared/agw-state.ts @@ -0,0 +1,31 @@ +/** Independent contract-state assertions for AGW tests; never part of the public SDK. */ +import type { Address, Hex, PublicClient } from 'viem'; +import { v5 } from '../../src/lib/agentic/contracts/v5'; +import { configId } from '../../src/lib/agentic/codec/ids'; + +export async function readNativeCounters( + client: PublicClient, + addresses: { sessionEngine: Address; rulesPolicy: Address }, + wallet: Address, + rulesId: Hex +) { + const actions = await client.readContract({ + address: addresses.sessionEngine, + abi: v5.abis.engine, + functionName: 'getEnabledActions', + args: [wallet, rulesId], + }); + if (actions.length !== 1) + throw new Error('Native counter fixture expects one action'); + const cfg = await client.readContract({ + address: addresses.rulesPolicy, + abi: v5.abis.policy, + functionName: 'getNativeConfig', + args: [configId(wallet, rulesId, actions[0]), wallet], + }); + return { + valueSpent: cfg.valueSpent, + amountSpent: cfg.amountSpent, + callsUsed: Number(cfg.callsUsed), + }; +} diff --git a/packages/core/__e2e__/shared/agw-svm-policy-probe.ts b/packages/core/__e2e__/shared/agw-svm-policy-probe.ts new file mode 100644 index 00000000..8b5b0d6c --- /dev/null +++ b/packages/core/__e2e__/shared/agw-svm-policy-probe.ts @@ -0,0 +1,34 @@ +/** Bypass SDK validation to verify the deployed URP refuses the same mutations. eth_call only. */ +import { decodeFunctionData, encodeFunctionData, type Address, type Hex, type PublicClient } from 'viem'; +import { UNIVERSAL_GATEWAY_PC } from '../../src/lib/constants/abi'; +import { v5, type Call } from '../../src/lib/agentic/contracts/v5'; +import { parseAgwSvmPayload, encodeAgwSvmPayload } from '../../src/lib/agentic/execution/svm-payload'; +import { decodeAgenticRevert } from '../../src/lib/agentic/revert'; + +export async function probeSvmWirePolicies(push: PublicClient, input: { + from: Address; wallet: Address; rulesId: Hex; call: Call; blockNumber: bigint; +}) { + const decodedCall = decodeFunctionData({ abi: UNIVERSAL_GATEWAY_PC, data: input.call.data }); + if (decodedCall.functionName !== 'sendUniversalTxOutbound') throw new Error('Expected a gateway outbound request'); + const request = decodedCall.args[0]; + const parsed = parseAgwSvmPayload(request.payload); + const observations = []; + for (const kind of ['account-pin', 'instruction-data-pin'] as const) { + const accounts = parsed.accounts.map((account) => ({ ...account })); + const data = new Uint8Array(parsed.instructionData); + if (kind === 'account-pin') accounts[2].pubkey = accounts[1].pubkey; + else { + const view = new DataView(data.buffer, data.byteOffset, data.byteLength); + view.setBigUint64(8, view.getBigUint64(8, true) + BigInt(1), true); + } + const altered = { ...request, payload: encodeAgwSvmPayload(parsed.program, accounts, data) }; + const packet = v5.encodeExecuteAsAgent(input.rulesId, { ...input.call, + data: encodeFunctionData({ abi: UNIVERSAL_GATEWAY_PC, functionName: 'sendUniversalTxOutbound', args: [altered] }) }); + let decoded; + try { await push.call({ account: input.from, to: input.wallet, data: packet, blockNumber: input.blockNumber }); } + catch (error) { decoded = decodeAgenticRevert(error); } + if (!decoded?.name?.includes('Svm')) throw new Error(`Expected a decoded SVM policy refusal for ${kind}, got ${decoded?.name ?? 'no decoded refusal'}`); + observations.push({ kind, reverted: true, decoded }); + } + return { chainId: 42101, block: input.blockNumber.toString(), observations, transactionsSent: 0 }; +} diff --git a/packages/core/__e2e__/shared/agw-svm-preflight.ts b/packages/core/__e2e__/shared/agw-svm-preflight.ts new file mode 100644 index 00000000..1272c52b --- /dev/null +++ b/packages/core/__e2e__/shared/agw-svm-preflight.ts @@ -0,0 +1,73 @@ +/** Read-only checks for the internal AGW Solana wire acceptance suite. */ +import { createHash } from 'node:crypto'; +import { BorshAccountsCoder, type Idl } from '@coral-xyz/anchor'; +import { Connection, PublicKey } from '@solana/web3.js'; +import { CHAIN_INFO } from '../../src/lib/constants/chain'; +import { CHAIN } from '../../src/lib/constants/enums'; +import gatewayIdl from '../../src/lib/constants/abi/universalGatewayV0.json'; +import counterIdl from '../../src/lib/orchestrator/svm-idl/__fixtures__/test_counter.idl.json'; + +export const SVM_WIRE_CHAIN = CHAIN.SOLANA_DEVNET; +export const SVM_WIRE_PROGRAM = counterIdl.address; +export const SVM_WIRE_GATEWAY = CHAIN_INFO[SVM_WIRE_CHAIN].lockerContract!; +export const SVM_WIRE_COUNTER = PublicKey.findProgramAddressSync( + [Buffer.from('counter')], new PublicKey(SVM_WIRE_PROGRAM) +)[0]; +const LOADER = 'BPFLoaderUpgradeab1e11111111111111111111111'; +const COUNTER_DISC = Buffer.from(counterIdl.accounts.find((a) => a.name === 'Counter')!.discriminator); + +export function decodeWireCounter(data: Buffer) { + if (data.length < 48 || !data.subarray(0, 8).equals(COUNTER_DISC)) + throw new Error('Counter data does not match the selected IDL'); + return { value: data.readBigUInt64LE(8), authority: new PublicKey(data.subarray(16, 48)).toBase58() }; +} + +export function svmWireConnection(url = CHAIN_INFO[SVM_WIRE_CHAIN].defaultRPC[0]) { + return new Connection(url, { + commitment: 'confirmed', + disableRetryOnRateLimit: true, + fetch: (input, init) => fetch(input, { ...init, signal: AbortSignal.timeout(20_000) }), + }); +} + +export async function inspectSvmWirePrograms(connection: Connection) { + const genesis = await connection.getGenesisHash(); + if (`solana:${genesis.slice(0, 32)}` !== SVM_WIRE_CHAIN) + throw new Error('Solana RPC is not the selected devnet cluster'); + const gateway = new PublicKey(SVM_WIRE_GATEWAY), program = new PublicKey(SVM_WIRE_PROGRAM); + if (gatewayIdl.address !== gateway.toBase58()) throw new Error('Gateway registry and IDL disagree'); + const config = PublicKey.findProgramAddressSync([Buffer.from('config')], gateway)[0]; + const keys = [gateway, program, SVM_WIRE_COUNTER, config]; + const info = await connection.getMultipleAccountsInfoAndContext(keys); + const fingerprint = (data: Buffer) => createHash('sha256').update(data).digest('hex'); + const programDataKeys = info.value.slice(0, 2).map((account, i) => { + if (!account?.executable || account.owner.toBase58() !== LOADER || + account.data.length !== 36 || account.data.readUInt32LE(0) !== 2) + throw new Error(`Program ${keys[i].toBase58()} is not an executable upgradeable program`); + return new PublicKey(account.data.subarray(4, 36)); + }); + const counter = info.value[2], configuration = info.value[3]; + if (!counter || counter.executable || !counter.owner.equals(program)) throw new Error('Counter account is missing or has the wrong owner'); + const counterState = decodeWireCounter(counter.data); + if (!configuration || configuration.executable || !configuration.owner.equals(gateway)) throw new Error('Gateway configuration is missing or has the wrong owner'); + const decoded = new BorshAccountsCoder(gatewayIdl as unknown as Idl).decode('Config', configuration.data); + if (decoded.paused !== false) throw new Error('Gateway is paused'); + const implementations = await connection.getMultipleAccountsInfoAndContext(programDataKeys); + const programs = implementations.value.map((account, i) => { + if (!account || account.owner.toBase58() !== LOADER || account.data.readUInt32LE(0) !== 3 || account.data.length <= 45) + throw new Error('ProgramData account is missing or invalid'); + return { + address: keys[i].toBase58(), programData: programDataKeys[i].toBase58(), + lastUpgradeSlot: account.data.readBigUInt64LE(4).toString(), + dataLength: account.data.length, dataSha256: fingerprint(account.data), + }; + }); + return { + checkedAt: new Date().toISOString(), chain: SVM_WIRE_CHAIN, genesis, + slot: info.context.slot, programDataSlot: implementations.context.slot, programs, + gatewayConfig: { address: config.toBase58(), paused: decoded.paused, dataSha256: fingerprint(configuration.data) }, + counter: { address: SVM_WIRE_COUNTER.toBase58(), value: counterState.value.toString(), authority: counterState.authority, dataSha256: fingerprint(counter.data) }, + counterIdlSha256: fingerprint(Buffer.from(JSON.stringify(counterIdl))), + gatewayIdlSha256: fingerprint(Buffer.from(JSON.stringify(gatewayIdl))), + }; +} diff --git a/packages/core/jest.agw-local.config.ts b/packages/core/jest.agw-local.config.ts new file mode 100644 index 00000000..c2e22b0c --- /dev/null +++ b/packages/core/jest.agw-local.config.ts @@ -0,0 +1,23 @@ +/** + * Local AGW contract harness (review-only). Runs the SDK against the real + * pinned v5 contracts on anvil. Requires Foundry and AGW_LOCAL_DIR from + * scripts/agw-local/prepare.sh. Never part of the unit or E2E runs. + * + * AGW_LOCAL_DIR=$(packages/core/scripts/agw-local/prepare.sh | tail -1) \ + * node node_modules/jest/bin/jest.js --config packages/core/jest.agw-local.config.ts --runInBand + */ +export default { + displayName: 'core-agw-local', + preset: '../../jest.preset.js', + testEnvironment: 'node', + setupFilesAfterEnv: ['/__agw-local__/setup.ts'], + transform: { + '^.+\\.[tj]s$': [ + 'ts-jest', + { tsconfig: '/tsconfig.agw-local.json' }, + ], + }, + moduleFileExtensions: ['ts', 'js', 'html'], + testTimeout: 120000, + testMatch: ['/__agw-local__/**/*.spec.ts'], +}; diff --git a/packages/core/package.json b/packages/core/package.json index 45bf8bc3..7572d206 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -51,6 +51,11 @@ }, "scripts": { "build:proto": "scripts/protoc-generate.sh", + "docs:check:agw": "node scripts/check-agw-docs.js", + "agw:verify": "node scripts/agw-verify.js", + "agw:check:package": "node scripts/check-agw-package.js", + "agw:check:api": "node scripts/check-agw-api.js", + "agw:check:runtimes": "node scripts/check-agw-runtimes.js", "e2e:list": "ts-node --transpile-only __e2e__/ci/run.ts --list", "e2e:verify": "ts-node --transpile-only __e2e__/ci/run.ts --verify", "e2e:preflight": "ts-node --transpile-only __e2e__/ci/preflight.ts", @@ -67,6 +72,7 @@ "src/**/*.d.ts", "src/**/*.json", "README.md", + "AGW.md", "CHANGELOG.md" ], "devDependencies": { diff --git a/packages/core/scripts/agw-local/abis/engine.json b/packages/core/scripts/agw-local/abis/engine.json new file mode 100644 index 00000000..bdf678eb --- /dev/null +++ b/packages/core/scripts/agw-local/abis/engine.json @@ -0,0 +1,1957 @@ +[ + { + "type": "function", + "name": "areActionsEnabled", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "actions", + "type": "tuple[]", + "internalType": "struct ActionData[]", + "components": [ + { + "name": "actionTargetSelector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "actionTarget", + "type": "address", + "internalType": "address" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "areERC1271PoliciesEnabled", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "areUserOpPoliciesEnabled", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "disableActionId", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "actionId", + "type": "bytes32", + "internalType": "ActionId" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "disableActionPolicies", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "actionId", + "type": "bytes32", + "internalType": "ActionId" + }, + { + "name": "policies", + "type": "address[]", + "internalType": "address[]" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "disableERC1271Policies", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "policies", + "type": "address[]", + "internalType": "address[]" + }, + { + "name": "contexts", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNames", + "type": "string[]", + "internalType": "string[]" + } + ] + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "disableUserOpPolicies", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "policies", + "type": "address[]", + "internalType": "address[]" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "enableActionPolicies", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct ActionData[]", + "components": [ + { + "name": "actionTargetSelector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "actionTarget", + "type": "address", + "internalType": "address" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "enableERC1271Policies", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "erc1271Policies", + "type": "tuple", + "internalType": "struct ERC7739Data", + "components": [ + { + "name": "allowedERC7739Content", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNames", + "type": "string[]", + "internalType": "string[]" + } + ] + }, + { + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "enableSessions", + "inputs": [ + { + "name": "sessions", + "type": "tuple[]", + "internalType": "struct Session[]", + "components": [ + { + "name": "sessionValidator", + "type": "address", + "internalType": "contract ISessionValidator" + }, + { + "name": "sessionValidatorInitData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "erc7739Policies", + "type": "tuple", + "internalType": "struct ERC7739Data", + "components": [ + { + "name": "allowedERC7739Content", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNames", + "type": "string[]", + "internalType": "string[]" + } + ] + }, + { + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "actions", + "type": "tuple[]", + "internalType": "struct ActionData[]", + "components": [ + { + "name": "actionTargetSelector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "actionTarget", + "type": "address", + "internalType": "address" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "permitERC4337Paymaster", + "type": "bool", + "internalType": "bool" + } + ] + } + ], + "outputs": [ + { + "name": "permissionIds", + "type": "bytes32[]", + "internalType": "PermissionId[]" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "enableUserOpPolicies", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "getActionPolicies", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "actionId", + "type": "bytes32", + "internalType": "ActionId" + } + ], + "outputs": [ + { + "name": "", + "type": "address[]", + "internalType": "address[]" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getERC1271Policies", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ], + "outputs": [ + { + "name": "", + "type": "address[]", + "internalType": "address[]" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getEnabledActions", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes32[]", + "internalType": "bytes32[]" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getEnabledERC7739Content", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ], + "outputs": [ + { + "name": "enabledERC7739ContentHashes", + "type": "tuple[]", + "internalType": "struct ERC7739ContextHashes[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNameHashes", + "type": "bytes32[]", + "internalType": "bytes32[]" + } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getNonce", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getPermissionIDs", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "permissionIds", + "type": "bytes32[]", + "internalType": "PermissionId[]" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getPermissionId", + "inputs": [ + { + "name": "session", + "type": "tuple", + "internalType": "struct Session", + "components": [ + { + "name": "sessionValidator", + "type": "address", + "internalType": "contract ISessionValidator" + }, + { + "name": "sessionValidatorInitData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "erc7739Policies", + "type": "tuple", + "internalType": "struct ERC7739Data", + "components": [ + { + "name": "allowedERC7739Content", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNames", + "type": "string[]", + "internalType": "string[]" + } + ] + }, + { + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "actions", + "type": "tuple[]", + "internalType": "struct ActionData[]", + "components": [ + { + "name": "actionTargetSelector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "actionTarget", + "type": "address", + "internalType": "address" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "permitERC4337Paymaster", + "type": "bool", + "internalType": "bool" + } + ] + } + ], + "outputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "getSessionDigest", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "data", + "type": "tuple", + "internalType": "struct Session", + "components": [ + { + "name": "sessionValidator", + "type": "address", + "internalType": "contract ISessionValidator" + }, + { + "name": "sessionValidatorInitData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "erc7739Policies", + "type": "tuple", + "internalType": "struct ERC7739Data", + "components": [ + { + "name": "allowedERC7739Content", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNames", + "type": "string[]", + "internalType": "string[]" + } + ] + }, + { + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "actions", + "type": "tuple[]", + "internalType": "struct ActionData[]", + "components": [ + { + "name": "actionTargetSelector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "actionTarget", + "type": "address", + "internalType": "address" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "permitERC4337Paymaster", + "type": "bool", + "internalType": "bool" + } + ] + }, + { + "name": "mode", + "type": "uint8", + "internalType": "enum SmartSessionMode" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getSessionValidatorAndConfig", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ], + "outputs": [ + { + "name": "sessionValidator", + "type": "address", + "internalType": "address" + }, + { + "name": "sessionValidatorData", + "type": "bytes", + "internalType": "bytes" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getUserOpPolicies", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ], + "outputs": [ + { + "name": "", + "type": "address[]", + "internalType": "address[]" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isActionIdEnabled", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "actionId", + "type": "bytes32", + "internalType": "ActionId" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isActionPolicyEnabled", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "actionId", + "type": "bytes32", + "internalType": "ActionId" + }, + { + "name": "policy", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isERC1271PolicyEnabled", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "policy", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isERC7739ContentEnabled", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "content", + "type": "string", + "internalType": "string" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isISessionValidatorSet", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isInitialized", + "inputs": [ + { + "name": "smartAccount", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isModuleType", + "inputs": [ + { + "name": "typeID", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "isPermissionEnabled", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isUserOpPolicyEnabled", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "policy", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isValidSignatureWithSender", + "inputs": [ + { + "name": "sender", + "type": "address", + "internalType": "address" + }, + { + "name": "hash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "signature", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "result", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "onInstall", + "inputs": [ + { + "name": "data", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "onUninstall", + "inputs": [ + { + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "removeSession", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "revokeEnableSignature", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setPermit4337Paymaster", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "enabled", + "type": "bool", + "internalType": "bool" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "validateUserOp", + "inputs": [ + { + "name": "userOp", + "type": "tuple", + "internalType": "struct PackedUserOperation", + "components": [ + { + "name": "sender", + "type": "address", + "internalType": "address" + }, + { + "name": "nonce", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "initCode", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "callData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "accountGasLimits", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "preVerificationGas", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "gasFees", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "paymasterAndData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "signature", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "userOpHash", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [ + { + "name": "vd", + "type": "uint256", + "internalType": "ValidationData" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "ActionIdDisabled", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" + }, + { + "name": "actionId", + "type": "bytes32", + "indexed": false, + "internalType": "ActionId" + }, + { + "name": "smartAccount", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "NonceIterated", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" + }, + { + "name": "account", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "newValue", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "PermissionIdPermit4337Paymaster", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" + }, + { + "name": "smartAccount", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "enabled", + "type": "bool", + "indexed": false, + "internalType": "bool" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "PolicyDisabled", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" + }, + { + "name": "policyType", + "type": "uint8", + "indexed": false, + "internalType": "enum PolicyType" + }, + { + "name": "policy", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "smartAccount", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "PolicyEnabled", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" + }, + { + "name": "policyType", + "type": "uint8", + "indexed": false, + "internalType": "enum PolicyType" + }, + { + "name": "policy", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "smartAccount", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "SessionCreated", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" + }, + { + "name": "account", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "SessionRemoved", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" + }, + { + "name": "smartAccount", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "SessionValidatorDisabled", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" + }, + { + "name": "sessionValidator", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "smartAccount", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "SessionValidatorEnabled", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" + }, + { + "name": "sessionValidator", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "smartAccount", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "AssociatedArray_OutOfBounds", + "inputs": [ + { + "name": "index", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "ChainIdMismatch", + "inputs": [ + { + "name": "providedChainId", + "type": "uint64", + "internalType": "uint64" + } + ] + }, + { + "type": "error", + "name": "ChainIdMismatch", + "inputs": [ + { + "name": "providedChainId", + "type": "uint64", + "internalType": "uint64" + } + ] + }, + { + "type": "error", + "name": "ForbiddenValidationData", + "inputs": [] + }, + { + "type": "error", + "name": "HashIndexOutOfBounds", + "inputs": [ + { + "name": "index", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "HashMismatch", + "inputs": [ + { + "name": "providedHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "computedHash", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "HashMismatch", + "inputs": [ + { + "name": "providedHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "computedHash", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "InvalidActionId", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidCallTarget", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidData", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidEnableSignature", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "hash", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "InvalidISessionValidator", + "inputs": [ + { + "name": "sessionValidator", + "type": "address", + "internalType": "contract ISessionValidator" + } + ] + }, + { + "type": "error", + "name": "InvalidMode", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidPermissionId", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ] + }, + { + "type": "error", + "name": "InvalidSelfCall", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidSession", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ] + }, + { + "type": "error", + "name": "InvalidSessionKeySignature", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "sessionValidator", + "type": "address", + "internalType": "address" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "userOpHash", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "InvalidTarget", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidUserOpSender", + "inputs": [ + { + "name": "sender", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "NoExecutionsInBatch", + "inputs": [] + }, + { + "type": "error", + "name": "NoPoliciesSet", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ] + }, + { + "type": "error", + "name": "PartlyEnabledActions", + "inputs": [] + }, + { + "type": "error", + "name": "PartlyEnabledPolicies", + "inputs": [] + }, + { + "type": "error", + "name": "PaymasterValidationNotEnabled", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ] + }, + { + "type": "error", + "name": "PolicyViolation", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "policy", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "SignerNotFound", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "SignerNotFound", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "SmartSessionModuleAlreadyInstalled", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "UnsupportedCallType", + "inputs": [ + { + "name": "callType", + "type": "bytes1", + "internalType": "CallType" + } + ] + }, + { + "type": "error", + "name": "UnsupportedExecutionType", + "inputs": [] + }, + { + "type": "error", + "name": "UnsupportedPolicy", + "inputs": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "UnsupportedSmartSessionMode", + "inputs": [ + { + "name": "mode", + "type": "uint8", + "internalType": "enum SmartSessionMode" + } + ] + } +] diff --git a/packages/core/scripts/agw-local/abis/factory.json b/packages/core/scripts/agw-local/abis/factory.json new file mode 100644 index 00000000..30435540 --- /dev/null +++ b/packages/core/scripts/agw-local/abis/factory.json @@ -0,0 +1,1105 @@ +[ + { + "type": "constructor", + "inputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "DEFAULT_ADMIN_ROLE", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "OPERATOR_ROLE", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "PAUSER_ROLE", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "UPGRADE_INTERFACE_VERSION", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "acceptDefaultAdminTransfer", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "beginDefaultAdminTransfer", + "inputs": [ + { + "name": "newAdmin", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "cancelDefaultAdminTransfer", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "changeDefaultAdminDelay", + "inputs": [ + { + "name": "newDelay", + "type": "uint48", + "internalType": "uint48" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "defaultAdmin", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "defaultAdminDelay", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint48", + "internalType": "uint48" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "defaultAdminDelayIncreaseWait", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint48", + "internalType": "uint48" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "deployWallet", + "inputs": [ + { + "name": "label", + "type": "string", + "internalType": "string" + } + ], + "outputs": [ + { + "name": "wallet", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "deployWalletWithSig", + "inputs": [ + { + "name": "intent", + "type": "tuple", + "internalType": "struct OwnerIntent", + "components": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "wallet", + "type": "address", + "internalType": "address" + }, + { + "name": "executor", + "type": "address", + "internalType": "address" + }, + { + "name": "index", + "type": "uint96", + "internalType": "uint96" + }, + { + "name": "sessionHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "mode", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "execCalldataHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "nonceKey", + "type": "uint192", + "internalType": "uint192" + }, + { + "name": "nonceSeq", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "grantNonce", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "deadline", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "signerChainId", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "sig", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "label", + "type": "string", + "internalType": "string" + } + ], + "outputs": [ + { + "name": "wallet", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "domainSeparator", + "inputs": [ + { + "name": "signerChainId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getRoleAdmin", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "grantRole", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "hasRole", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "indexOf", + "inputs": [ + { + "name": "wallet", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "initialize", + "inputs": [ + { + "name": "admin", + "type": "address", + "internalType": "address" + }, + { + "name": "walletImplementation_", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "isWallet", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "owner", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "ownerOf", + "inputs": [ + { + "name": "wallet", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "pause", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "paused", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "pendingDefaultAdmin", + "inputs": [], + "outputs": [ + { + "name": "newAdmin", + "type": "address", + "internalType": "address" + }, + { + "name": "schedule", + "type": "uint48", + "internalType": "uint48" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "pendingDefaultAdminDelay", + "inputs": [], + "outputs": [ + { + "name": "newDelay", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "schedule", + "type": "uint48", + "internalType": "uint48" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "predictWallet", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "index", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "wallet", + "type": "address", + "internalType": "address" + }, + { + "name": "deployed", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "proxiableUUID", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "renounceRole", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "revokeRole", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "rollbackDefaultAdminDelay", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "supportsInterface", + "inputs": [ + { + "name": "interfaceId", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "unpause", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "upgradeToAndCall", + "inputs": [ + { + "name": "newImplementation", + "type": "address", + "internalType": "address" + }, + { + "name": "data", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "walletCount", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "walletImplementation", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "event", + "name": "DefaultAdminDelayChangeCanceled", + "inputs": [], + "anonymous": false + }, + { + "type": "event", + "name": "DefaultAdminDelayChangeScheduled", + "inputs": [ + { + "name": "newDelay", + "type": "uint48", + "indexed": false, + "internalType": "uint48" + }, + { + "name": "effectSchedule", + "type": "uint48", + "indexed": false, + "internalType": "uint48" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "DefaultAdminTransferCanceled", + "inputs": [], + "anonymous": false + }, + { + "type": "event", + "name": "DefaultAdminTransferScheduled", + "inputs": [ + { + "name": "newAdmin", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "acceptSchedule", + "type": "uint48", + "indexed": false, + "internalType": "uint48" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Initialized", + "inputs": [ + { + "name": "version", + "type": "uint64", + "indexed": false, + "internalType": "uint64" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Paused", + "inputs": [ + { + "name": "account", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RoleAdminChanged", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "previousAdminRole", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "newAdminRole", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RoleGranted", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RoleRevoked", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Unpaused", + "inputs": [ + { + "name": "account", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Upgraded", + "inputs": [ + { + "name": "implementation", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "WalletDeployed", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "index", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "wallet", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "label", + "type": "string", + "indexed": false, + "internalType": "string" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "AccessControlBadConfirmation", + "inputs": [] + }, + { + "type": "error", + "name": "AccessControlEnforcedDefaultAdminDelay", + "inputs": [ + { + "name": "schedule", + "type": "uint48", + "internalType": "uint48" + } + ] + }, + { + "type": "error", + "name": "AccessControlEnforcedDefaultAdminRules", + "inputs": [] + }, + { + "type": "error", + "name": "AccessControlInvalidDefaultAdmin", + "inputs": [ + { + "name": "defaultAdmin", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "AccessControlUnauthorizedAccount", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "neededRole", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "AddressEmptyCode", + "inputs": [ + { + "name": "target", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "CloneArgumentsTooLong", + "inputs": [] + }, + { + "type": "error", + "name": "Create2EmptyBytecode", + "inputs": [] + }, + { + "type": "error", + "name": "ERC1967InvalidImplementation", + "inputs": [ + { + "name": "implementation", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ERC1967NonPayable", + "inputs": [] + }, + { + "type": "error", + "name": "EnforcedPause", + "inputs": [] + }, + { + "type": "error", + "name": "ExecutorMismatch", + "inputs": [ + { + "name": "expected", + "type": "address", + "internalType": "address" + }, + { + "name": "actual", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ExpectedPause", + "inputs": [] + }, + { + "type": "error", + "name": "FailedCall", + "inputs": [] + }, + { + "type": "error", + "name": "FailedDeployment", + "inputs": [] + }, + { + "type": "error", + "name": "ImplementationNotSet", + "inputs": [] + }, + { + "type": "error", + "name": "IndexMismatch", + "inputs": [ + { + "name": "expected", + "type": "uint96", + "internalType": "uint96" + }, + { + "name": "provided", + "type": "uint96", + "internalType": "uint96" + } + ] + }, + { + "type": "error", + "name": "IndexOutOfRange", + "inputs": [ + { + "name": "index", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "next", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "InsufficientBalance", + "inputs": [ + { + "name": "balance", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "needed", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "IntentWalletMismatch", + "inputs": [ + { + "name": "expected", + "type": "address", + "internalType": "address" + }, + { + "name": "provided", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "InvalidInitialization", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidOwnerSignature", + "inputs": [] + }, + { + "type": "error", + "name": "NotAWallet", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "NotInitializing", + "inputs": [] + }, + { + "type": "error", + "name": "SafeCastOverflowedUintDowncast", + "inputs": [ + { + "name": "bits", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "SignatureExpired", + "inputs": [ + { + "name": "deadline", + "type": "uint48", + "internalType": "uint48" + } + ] + }, + { + "type": "error", + "name": "UUPSUnauthorizedCallContext", + "inputs": [] + }, + { + "type": "error", + "name": "UUPSUnsupportedProxiableUUID", + "inputs": [ + { + "name": "slot", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "ZeroAddress", + "inputs": [] + } +] diff --git a/packages/core/scripts/agw-local/abis/manifest.json b/packages/core/scripts/agw-local/abis/manifest.json new file mode 100644 index 00000000..7c13c7e0 --- /dev/null +++ b/packages/core/scripts/agw-local/abis/manifest.json @@ -0,0 +1,12 @@ +{ + "sourceRepository": "https://github.com/pushchain/push-agentic-wallets", + "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", + "deployedAbiEvidence": "Donut v5 source compiled in an isolated tree; deployment wiring checked at block 23991912; URP/engine/validator reused from v4", + "files": { + "wallet.json": "6a145964d6c43eaa6223dc8f3d59a540ac0c2f447f25c3a99007eea25de9c695", + "factory.json": "b65f66a1556d2a9ddf9aabe9f595c685c2aada436772892f5a40fb1eec846397", + "policy.json": "c7e3cd5c7f8e47be217c77ebebde4c090903cea7db63024838e434eb6f1fd77b", + "engine.json": "6e5d9cea4dbed01f06af913c1e093743b86b7432195f4a4bf90fb94b282c51b2", + "validator.json": "a4570ddc373241580de8742cbb3d9f2c837094c65bfd1cdd52243ca0c38196fd" + } +} diff --git a/packages/core/scripts/agw-local/abis/policy.json b/packages/core/scripts/agw-local/abis/policy.json new file mode 100644 index 00000000..88e39505 --- /dev/null +++ b/packages/core/scripts/agw-local/abis/policy.json @@ -0,0 +1,2157 @@ +[ + { + "type": "constructor", + "inputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "SEND_OUTBOUND_SELECTOR", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "SESSION_ENGINE", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "UNIVERSAL_EXECUTOR_MODULE", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "UNIVERSAL_GATEWAY_PC", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "assertSpent", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "expectedValueSpent", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "expectedAmountSpent", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "expectedCalls", + "type": "uint32", + "internalType": "uint32" + } + ], + "outputs": [], + "stateMutability": "view" + }, + { + "type": "function", + "name": "assertSpent", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "expectedSpent", + "type": "uint256[]", + "internalType": "uint256[]" + } + ], + "outputs": [], + "stateMutability": "view" + }, + { + "type": "function", + "name": "checkAction", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "target", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "data", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "creditRevert", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "outboundTxId", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "token", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "getConfig", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "tuple", + "internalType": "struct Config", + "components": [ + { + "name": "initialized", + "type": "bool", + "internalType": "bool" + }, + { + "name": "validUntil", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "expectedCEA", + "type": "address", + "internalType": "address" + }, + { + "name": "maxGasPerCall", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "assets", + "type": "tuple[]", + "internalType": "struct AssetCapState[]", + "components": [ + { + "name": "token", + "type": "address", + "internalType": "address" + }, + { + "name": "maxPerCall", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxTotal", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "spent", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "allowedCalls", + "type": "tuple[]", + "internalType": "struct AllowedCall[]", + "components": [ + { + "name": "target", + "type": "address", + "internalType": "address" + }, + { + "name": "selector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "beneficiaryOffset", + "type": "uint16", + "internalType": "uint16" + }, + { + "name": "hasBeneficiary", + "type": "bool", + "internalType": "bool" + }, + { + "name": "maxValue", + "type": "uint256", + "internalType": "uint256" + } + ] + } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getMode", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "tuple", + "internalType": "struct ModeSlot", + "components": [ + { + "name": "initialized", + "type": "bool", + "internalType": "bool" + }, + { + "name": "mode", + "type": "uint8", + "internalType": "enum RulesType" + }, + { + "name": "vm", + "type": "uint8", + "internalType": "enum VmFamily" + }, + { + "name": "chainHash", + "type": "bytes32", + "internalType": "bytes32" + } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getNativeConfig", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "tuple", + "internalType": "struct NativeConfig", + "components": [ + { + "name": "initialized", + "type": "bool", + "internalType": "bool" + }, + { + "name": "validUntil", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "target", + "type": "address", + "internalType": "address" + }, + { + "name": "selector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "maxValuePerCall", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxValueTotal", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "valueSpent", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amount", + "type": "tuple", + "internalType": "struct AmountRule", + "components": [ + { + "name": "enabled", + "type": "bool", + "internalType": "bool" + }, + { + "name": "offset", + "type": "uint16", + "internalType": "uint16" + }, + { + "name": "maxPerCall", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxTotal", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "amountSpent", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxCalls", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "callsUsed", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "pins", + "type": "tuple[]", + "internalType": "struct ArgPin[]", + "components": [ + { + "name": "offset", + "type": "uint16", + "internalType": "uint16" + }, + { + "name": "expected", + "type": "bytes32", + "internalType": "bytes32" + } + ] + } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getSvmConfig", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "tuple", + "internalType": "struct SvmConfig", + "components": [ + { + "name": "initialized", + "type": "bool", + "internalType": "bool" + }, + { + "name": "validUntil", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "expectedCEA", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "gatewayProgram", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "maxGasPerCall", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "assets", + "type": "tuple[]", + "internalType": "struct AssetCapState[]", + "components": [ + { + "name": "token", + "type": "address", + "internalType": "address" + }, + { + "name": "maxPerCall", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxTotal", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "spent", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "ceaAccounts", + "type": "bytes32[]", + "internalType": "bytes32[]" + }, + { + "name": "programs", + "type": "tuple[]", + "internalType": "struct AllowedProgram[]", + "components": [ + { + "name": "program", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "discriminator", + "type": "bytes8", + "internalType": "bytes8" + }, + { + "name": "discriminatorLen", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "dataless", + "type": "bool", + "internalType": "bool" + }, + { + "name": "maxAccounts", + "type": "uint8", + "internalType": "uint8" + } + ] + }, + { + "name": "pins", + "type": "tuple[]", + "internalType": "struct SvmAccountPin[]", + "components": [ + { + "name": "ruleIndex", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "accountIndex", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "expected", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "name": "dataPins", + "type": "tuple[]", + "internalType": "struct SvmDataPin[]", + "components": [ + { + "name": "ruleIndex", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "fromEnd", + "type": "bool", + "internalType": "bool" + }, + { + "name": "offset", + "type": "uint16", + "internalType": "uint16" + }, + { + "name": "offsetB", + "type": "uint16", + "internalType": "uint16" + }, + { + "name": "len", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "mode", + "type": "uint8", + "internalType": "enum SvmDataPinMode" + }, + { + "name": "expected", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "num", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "den", + "type": "uint64", + "internalType": "uint64" + } + ] + } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "initialize", + "inputs": [ + { + "name": "universalGatewayPC", + "type": "address", + "internalType": "address" + }, + { + "name": "universalExecutorModule", + "type": "address", + "internalType": "address" + }, + { + "name": "sessionEngine", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "initializeWithMultiplexer", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "configId", + "type": "bytes32", + "internalType": "ConfigId" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "isCredited", + "inputs": [ + { + "name": "outboundTxId", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "pushChainHash", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "supportsInterface", + "inputs": [ + { + "name": "iid", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "version", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "pure" + }, + { + "type": "event", + "name": "Initialized", + "inputs": [ + { + "name": "version", + "type": "uint64", + "indexed": false, + "internalType": "uint64" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "NativeCallMetered", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "indexed": true, + "internalType": "ConfigId" + }, + { + "name": "multiplexer", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "OutboundMetered", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "indexed": true, + "internalType": "ConfigId" + }, + { + "name": "multiplexer", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "token", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "PolicySet", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "indexed": false, + "internalType": "ConfigId" + }, + { + "name": "multiplexer", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "account", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RevertCredited", + "inputs": [ + { + "name": "outboundTxId", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "id", + "type": "bytes32", + "indexed": true, + "internalType": "ConfigId" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "token", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "amountApplied", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RulesConfigured", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "indexed": true, + "internalType": "ConfigId" + }, + { + "name": "multiplexer", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "mode", + "type": "uint8", + "indexed": false, + "internalType": "enum RulesType" + }, + { + "name": "vm", + "type": "uint8", + "indexed": false, + "internalType": "enum VmFamily" + }, + { + "name": "chainHash", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "AllowListOutOfRange", + "inputs": [ + { + "name": "length", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "AlreadyCredited", + "inputs": [ + { + "name": "outboundTxId", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "AlreadyInitialized", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" + } + ] + }, + { + "type": "error", + "name": "AmbiguousRule", + "inputs": [ + { + "name": "i", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "j", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "AmountExceedsCap", + "inputs": [ + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "cap", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "AmountExceedsU64", + "inputs": [ + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "ArgPinMismatch", + "inputs": [ + { + "name": "actual", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "index", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "expected", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "AssetListOutOfRange", + "inputs": [ + { + "name": "length", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "AssetNotAllowed", + "inputs": [ + { + "name": "token", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "AssetSpentMismatch", + "inputs": [ + { + "name": "token", + "type": "address", + "internalType": "address" + }, + { + "name": "expected", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "actual", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "BatchSizeOutOfRange", + "inputs": [ + { + "name": "count", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "BeneficiaryMismatch", + "inputs": [ + { + "name": "expected", + "type": "address", + "internalType": "address" + }, + { + "name": "actual", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "CallLimitReached", + "inputs": [ + { + "name": "callsUsed", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "maxCalls", + "type": "uint32", + "internalType": "uint32" + } + ] + }, + { + "type": "error", + "name": "CallNotAllowed", + "inputs": [ + { + "name": "target", + "type": "address", + "internalType": "address" + }, + { + "name": "selector", + "type": "bytes4", + "internalType": "bytes4" + } + ] + }, + { + "type": "error", + "name": "CalldataTooShort", + "inputs": [ + { + "name": "length", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "CalldataTooShortForAmount", + "inputs": [ + { + "name": "actualLength", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "needed", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "CalldataTooShortForPin", + "inputs": [ + { + "name": "actualLength", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "index", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "needed", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "CallerIsNotUEModule", + "inputs": [ + { + "name": "caller", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "CeaAccountAtUnpinnedIndex", + "inputs": [ + { + "name": "accountIndex", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "account", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "CeaAccountsMissExpectedCEA", + "inputs": [] + }, + { + "type": "error", + "name": "ChainMismatch", + "inputs": [ + { + "name": "declared", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "assetChain", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "DiscriminatorLenOutOfRange", + "inputs": [ + { + "name": "rule", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "len", + "type": "uint8", + "internalType": "uint8" + } + ] + }, + { + "type": "error", + "name": "DuplicateAsset", + "inputs": [ + { + "name": "token", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "DuplicateSvmPin", + "inputs": [ + { + "name": "first", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "second", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "EmptyChain", + "inputs": [] + }, + { + "type": "error", + "name": "ForbiddenInnerTarget", + "inputs": [ + { + "name": "target", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ForbiddenProgramInAllowList", + "inputs": [ + { + "name": "rule", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "program", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "ForbiddenTargetProgram", + "inputs": [ + { + "name": "program", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "InnerValueExceedsAllowance", + "inputs": [ + { + "name": "index", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxValue", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "InvalidAsset", + "inputs": [ + { + "name": "asset", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "InvalidCeaAccount", + "inputs": [ + { + "name": "index", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "InvalidConfigField", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidExpiry", + "inputs": [ + { + "name": "validUntil", + "type": "uint48", + "internalType": "uint48" + } + ] + }, + { + "type": "error", + "name": "InvalidInitialization", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidRevertRecipient", + "inputs": [ + { + "name": "expected", + "type": "address", + "internalType": "address" + }, + { + "name": "actual", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "InvalidSelector", + "inputs": [ + { + "name": "selector", + "type": "bytes4", + "internalType": "bytes4" + } + ] + }, + { + "type": "error", + "name": "InvalidSvmConfigField", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidTarget", + "inputs": [ + { + "name": "target", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "MalformedInnerCalldata", + "inputs": [] + }, + { + "type": "error", + "name": "MalformedOutboundRequest", + "inputs": [ + { + "name": "length", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "MalformedSvmPayload", + "inputs": [ + { + "name": "code", + "type": "uint8", + "internalType": "uint8" + } + ] + }, + { + "type": "error", + "name": "NativeAmountExceedsCap", + "inputs": [ + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "cap", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "NativeTargetIsGateway", + "inputs": [ + { + "name": "target", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "NativeTargetZero", + "inputs": [] + }, + { + "type": "error", + "name": "NotInitialized", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "NotInitializing", + "inputs": [] + }, + { + "type": "error", + "name": "PCValueExceedsCap", + "inputs": [ + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "cap", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "PayloadNotMulticall", + "inputs": [] + }, + { + "type": "error", + "name": "PolicyNotInitialized", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" + }, + { + "name": "multiplexer", + "type": "address", + "internalType": "address" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ProgramListOutOfRange", + "inputs": [ + { + "name": "length", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "ProgramNotAllowed", + "inputs": [ + { + "name": "program", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "discriminator", + "type": "bytes8", + "internalType": "bytes8" + } + ] + }, + { + "type": "error", + "name": "RecipientMustBeEmpty", + "inputs": [] + }, + { + "type": "error", + "name": "RecipientNotPubkey", + "inputs": [ + { + "name": "length", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "RecipientTargetMismatch", + "inputs": [ + { + "name": "recipient", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "target", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "RuleWithoutPin", + "inputs": [ + { + "name": "rule", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "RulesExpired", + "inputs": [ + { + "name": "validUntil", + "type": "uint48", + "internalType": "uint48" + } + ] + }, + { + "type": "error", + "name": "SelectorMismatch", + "inputs": [ + { + "name": "actual", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "expected", + "type": "bytes4", + "internalType": "bytes4" + } + ] + }, + { + "type": "error", + "name": "SpentLengthMismatch", + "inputs": [ + { + "name": "expected", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "actual", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "SpentMismatch", + "inputs": [ + { + "name": "expected", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "actual", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "SvmAccountCountBelowPin", + "inputs": [ + { + "name": "pin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "count", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "needed", + "type": "uint8", + "internalType": "uint8" + } + ] + }, + { + "type": "error", + "name": "SvmAccountCountMismatch", + "inputs": [ + { + "name": "count", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "expected", + "type": "uint8", + "internalType": "uint8" + } + ] + }, + { + "type": "error", + "name": "SvmAccountPinMismatch", + "inputs": [ + { + "name": "pin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "accountIndex", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "expected", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "actual", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "SvmAccountsOutOfRange", + "inputs": [ + { + "name": "count", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "SvmDataCeilingExceeded", + "inputs": [ + { + "name": "pin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "actual", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "ceiling", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "SvmDataFloorNotMet", + "inputs": [ + { + "name": "pin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "actual", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "floor", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "SvmDataPinInvalid", + "inputs": [ + { + "name": "pin", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "SvmDataPinMismatch", + "inputs": [ + { + "name": "pin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "expected", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "actual", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "SvmDataRatioNotMet", + "inputs": [ + { + "name": "pin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "a", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "b", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "num", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "den", + "type": "uint64", + "internalType": "uint64" + } + ] + }, + { + "type": "error", + "name": "SvmDataTooShortForPin", + "inputs": [ + { + "name": "pin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "ixLen", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "SvmInstructionNotExecute", + "inputs": [ + { + "name": "instructionId", + "type": "uint8", + "internalType": "uint8" + } + ] + }, + { + "type": "error", + "name": "SvmIxDataTooLong", + "inputs": [ + { + "name": "length", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "SvmMaxAccountsOutOfRange", + "inputs": [ + { + "name": "rule", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxAccounts", + "type": "uint8", + "internalType": "uint8" + } + ] + }, + { + "type": "error", + "name": "SvmPayloadEmpty", + "inputs": [] + }, + { + "type": "error", + "name": "SvmPinIndexOutOfRange", + "inputs": [ + { + "name": "pin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "accountIndex", + "type": "uint8", + "internalType": "uint8" + } + ] + }, + { + "type": "error", + "name": "SvmPinRuleOutOfRange", + "inputs": [ + { + "name": "pin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "rule", + "type": "uint8", + "internalType": "uint8" + } + ] + }, + { + "type": "error", + "name": "TargetMismatch", + "inputs": [ + { + "name": "actual", + "type": "address", + "internalType": "address" + }, + { + "name": "expected", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "TooManyCeaAccounts", + "inputs": [ + { + "name": "count", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "TooManyPins", + "inputs": [ + { + "name": "count", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "TooManySvmDataPins", + "inputs": [ + { + "name": "count", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "TooManySvmPins", + "inputs": [ + { + "name": "count", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "TotalNativeAmountExceeded", + "inputs": [ + { + "name": "newSpent", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "cap", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "TotalSpendCapExceeded", + "inputs": [ + { + "name": "wouldBeTotal", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "cap", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "TotalValueExceeded", + "inputs": [ + { + "name": "newSpent", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "cap", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "UncappedGasSwapRejected", + "inputs": [] + }, + { + "type": "error", + "name": "UnsupportedEnvelopeVersion", + "inputs": [ + { + "name": "version", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "UnsupportedNamespace", + "inputs": [ + { + "name": "chainHash", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "ValueExceedsCap", + "inputs": [ + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "cap", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "ValueOnlyCalldataNotEmpty", + "inputs": [ + { + "name": "length", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "ValueOnlyWithAmountRule", + "inputs": [] + }, + { + "type": "error", + "name": "ValueOnlyWithPins", + "inputs": [] + }, + { + "type": "error", + "name": "WrongModeForCall", + "inputs": [ + { + "name": "actual", + "type": "uint8", + "internalType": "enum RulesType" + } + ] + }, + { + "type": "error", + "name": "WrongVmForCall", + "inputs": [ + { + "name": "actual", + "type": "uint8", + "internalType": "enum VmFamily" + } + ] + }, + { + "type": "error", + "name": "ZeroAddress", + "inputs": [] + } +] diff --git a/packages/core/scripts/agw-local/abis/validator.json b/packages/core/scripts/agw-local/abis/validator.json new file mode 100644 index 00000000..86830881 --- /dev/null +++ b/packages/core/scripts/agw-local/abis/validator.json @@ -0,0 +1,141 @@ +[ + { + "type": "function", + "name": "isInitialized", + "inputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "isModuleType", + "inputs": [ + { + "name": "moduleTypeId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "onInstall", + "inputs": [ + { + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "onUninstall", + "inputs": [ + { + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "validateConfig", + "inputs": [ + { + "name": "data", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "validateSignatureWithData", + "inputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "sig", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "data", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "validSig", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "pure" + }, + { + "type": "error", + "name": "AlreadyInitialized", + "inputs": [ + { + "name": "smartAccount", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "MalformedConfig", + "inputs": [] + }, + { + "type": "error", + "name": "NotInitialized", + "inputs": [ + { + "name": "smartAccount", + "type": "address", + "internalType": "address" + } + ] + } +] diff --git a/packages/core/scripts/agw-local/abis/wallet.json b/packages/core/scripts/agw-local/abis/wallet.json new file mode 100644 index 00000000..5d5f6612 --- /dev/null +++ b/packages/core/scripts/agw-local/abis/wallet.json @@ -0,0 +1,1606 @@ +[ + { + "type": "constructor", + "inputs": [ + { + "name": "sessionEngine_", + "type": "address", + "internalType": "address" + }, + { + "name": "rulesPolicy_", + "type": "address", + "internalType": "address" + }, + { + "name": "sessionValidator_", + "type": "address", + "internalType": "address" + }, + { + "name": "universalGatewayPC_", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "receive", + "stateMutability": "payable" + }, + { + "type": "function", + "name": "RULES_POLICY", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "SESSION_ENGINE", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "SESSION_VALIDATOR", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "UNIVERSAL_GATEWAY_PC", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "accountId", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "agentOf", + "inputs": [ + { + "name": "rulesId", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "checkpointCount", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint64", + "internalType": "uint64" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "domainSeparator", + "inputs": [ + { + "name": "signerChainId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "execute", + "inputs": [ + { + "name": "mode", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "executionCalldata", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "executeAsAgent", + "inputs": [ + { + "name": "rulesId", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "mode", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "executionCalldata", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "executeWithSig", + "inputs": [ + { + "name": "mode", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "executionCalldata", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "intent", + "type": "tuple", + "internalType": "struct OwnerIntent", + "components": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "wallet", + "type": "address", + "internalType": "address" + }, + { + "name": "executor", + "type": "address", + "internalType": "address" + }, + { + "name": "index", + "type": "uint96", + "internalType": "uint96" + }, + { + "name": "sessionHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "mode", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "execCalldataHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "nonceKey", + "type": "uint192", + "internalType": "uint192" + }, + { + "name": "nonceSeq", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "grantNonce", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "deadline", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "signerChainId", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "sig", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "factory", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getNonce", + "inputs": [ + { + "name": "nonceKey", + "type": "uint192", + "internalType": "uint192" + } + ], + "outputs": [ + { + "name": "", + "type": "uint64", + "internalType": "uint64" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "grantNonce", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint64", + "internalType": "uint64" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "grantRules", + "inputs": [ + { + "name": "session", + "type": "tuple", + "internalType": "struct Session", + "components": [ + { + "name": "sessionValidator", + "type": "address", + "internalType": "contract ISessionValidator" + }, + { + "name": "sessionValidatorInitData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "erc7739Policies", + "type": "tuple", + "internalType": "struct ERC7739Data", + "components": [ + { + "name": "allowedERC7739Content", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNames", + "type": "string[]", + "internalType": "string[]" + } + ] + }, + { + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "actions", + "type": "tuple[]", + "internalType": "struct ActionData[]", + "components": [ + { + "name": "actionTargetSelector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "actionTarget", + "type": "address", + "internalType": "address" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "permitERC4337Paymaster", + "type": "bool", + "internalType": "bool" + } + ] + } + ], + "outputs": [ + { + "name": "rulesId", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "grantRulesWithSig", + "inputs": [ + { + "name": "session", + "type": "tuple", + "internalType": "struct Session", + "components": [ + { + "name": "sessionValidator", + "type": "address", + "internalType": "contract ISessionValidator" + }, + { + "name": "sessionValidatorInitData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "erc7739Policies", + "type": "tuple", + "internalType": "struct ERC7739Data", + "components": [ + { + "name": "allowedERC7739Content", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNames", + "type": "string[]", + "internalType": "string[]" + } + ] + }, + { + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "actions", + "type": "tuple[]", + "internalType": "struct ActionData[]", + "components": [ + { + "name": "actionTargetSelector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "actionTarget", + "type": "address", + "internalType": "address" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "permitERC4337Paymaster", + "type": "bool", + "internalType": "bool" + } + ] + }, + { + "name": "intent", + "type": "tuple", + "internalType": "struct OwnerIntent", + "components": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "wallet", + "type": "address", + "internalType": "address" + }, + { + "name": "executor", + "type": "address", + "internalType": "address" + }, + { + "name": "index", + "type": "uint96", + "internalType": "uint96" + }, + { + "name": "sessionHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "mode", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "execCalldataHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "nonceKey", + "type": "uint192", + "internalType": "uint192" + }, + { + "name": "nonceSeq", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "grantNonce", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "deadline", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "signerChainId", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "sig", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "rulesId", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "initializeAccount", + "inputs": [ + { + "name": "label_", + "type": "string", + "internalType": "string" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "installModule", + "inputs": [ + { + "name": "moduleTypeId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "module", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "isModuleInstalled", + "inputs": [ + { + "name": "moduleTypeId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "module", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isValidSignature", + "inputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "label", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "lastCheckpointBlock", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint64", + "internalType": "uint64" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "onERC1155BatchReceived", + "inputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "onERC1155Received", + "inputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "onERC721Received", + "inputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "owner", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "revokeAllRules", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "revokeRules", + "inputs": [ + { + "name": "rulesId", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setLabel", + "inputs": [ + { + "name": "label_", + "type": "string", + "internalType": "string" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "supportsExecutionMode", + "inputs": [ + { + "name": "mode", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "supportsInterface", + "inputs": [ + { + "name": "interfaceId", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "supportsModule", + "inputs": [ + { + "name": "moduleTypeId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "uninstallModule", + "inputs": [ + { + "name": "moduleTypeId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "module", + "type": "address", + "internalType": "address" + }, + { + "name": "deInitData", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "AccountInitialized", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "engine", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Checkpointed", + "inputs": [ + { + "name": "seq", + "type": "uint64", + "indexed": true, + "internalType": "uint64" + }, + { + "name": "kind", + "type": "uint8", + "indexed": false, + "internalType": "enum CheckpointKind" + }, + { + "name": "ref", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + }, + { + "name": "blockNumber", + "type": "uint64", + "indexed": false, + "internalType": "uint64" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "LabelSet", + "inputs": [ + { + "name": "label", + "type": "string", + "indexed": false, + "internalType": "string" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ModuleInstalled", + "inputs": [ + { + "name": "moduleTypeId", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "module", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ModuleUninstalled", + "inputs": [ + { + "name": "moduleTypeId", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "module", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "OwnerExecuted", + "inputs": [ + { + "name": "mode", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "executionCalldataHash", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "OwnerExecutedWithSig", + "inputs": [ + { + "name": "mode", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "executionCalldataHash", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + }, + { + "name": "nonceKey", + "type": "uint192", + "indexed": false, + "internalType": "uint192" + }, + { + "name": "nonceSeq", + "type": "uint64", + "indexed": false, + "internalType": "uint64" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RulesActionAuthorized", + "inputs": [ + { + "name": "rulesId", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "agent", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "callsHash", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RulesGranted", + "inputs": [ + { + "name": "rulesId", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "mode", + "type": "uint8", + "indexed": false, + "internalType": "enum RulesType" + }, + { + "name": "chainHash", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "chainNamespace", + "type": "string", + "indexed": false, + "internalType": "string" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RulesRevoked", + "inputs": [ + { + "name": "rulesId", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "UninstallCallbackFailed", + "inputs": [ + { + "name": "module", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "AlreadyInitialized", + "inputs": [] + }, + { + "type": "error", + "name": "CallerIsNotAgent", + "inputs": [ + { + "name": "rulesId", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "caller", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "CallerIsNotFactory", + "inputs": [] + }, + { + "type": "error", + "name": "CallerIsNotOwner", + "inputs": [] + }, + { + "type": "error", + "name": "DuplicateAction", + "inputs": [ + { + "name": "target", + "type": "address", + "internalType": "address" + }, + { + "name": "selector", + "type": "bytes4", + "internalType": "bytes4" + } + ] + }, + { + "type": "error", + "name": "EmptyChain", + "inputs": [] + }, + { + "type": "error", + "name": "EngineStillHoldsPermissions", + "inputs": [] + }, + { + "type": "error", + "name": "ExecutorMismatch", + "inputs": [ + { + "name": "expected", + "type": "address", + "internalType": "address" + }, + { + "name": "actual", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ForbiddenActionSelector", + "inputs": [ + { + "name": "selector", + "type": "bytes4", + "internalType": "bytes4" + } + ] + }, + { + "type": "error", + "name": "ForbiddenActionTarget", + "inputs": [ + { + "name": "target", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ForbiddenDispatchTarget", + "inputs": [ + { + "name": "target", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "InconsistentChain", + "inputs": [ + { + "name": "actionIndex", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "IntentExecMismatch", + "inputs": [ + { + "name": "actualCalldataHash", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "IntentGrantNonceMismatch", + "inputs": [ + { + "name": "expected", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "provided", + "type": "uint64", + "internalType": "uint64" + } + ] + }, + { + "type": "error", + "name": "IntentSessionMismatch", + "inputs": [ + { + "name": "actual", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "IntentWalletMismatch", + "inputs": [ + { + "name": "expected", + "type": "address", + "internalType": "address" + }, + { + "name": "provided", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "InvalidModuleAddress", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidNonce", + "inputs": [ + { + "name": "nonceKey", + "type": "uint192", + "internalType": "uint192" + }, + { + "name": "expected", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "provided", + "type": "uint64", + "internalType": "uint64" + } + ] + }, + { + "type": "error", + "name": "InvalidOwnerSignature", + "inputs": [] + }, + { + "type": "error", + "name": "LabelTooLong", + "inputs": [ + { + "name": "length", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "MalformedBatchCalldata", + "inputs": [] + }, + { + "type": "error", + "name": "MalformedSessionShape", + "inputs": [] + }, + { + "type": "error", + "name": "ModuleAlreadyInstalled", + "inputs": [ + { + "name": "module", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "OutsideTimeWindow", + "inputs": [ + { + "name": "validAfter", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "validUntil", + "type": "uint48", + "internalType": "uint48" + } + ] + }, + { + "type": "error", + "name": "OwnerLaneRequired", + "inputs": [ + { + "name": "nonceKey", + "type": "uint192", + "internalType": "uint192" + } + ] + }, + { + "type": "error", + "name": "OwnerSigExpired", + "inputs": [ + { + "name": "deadline", + "type": "uint48", + "internalType": "uint48" + } + ] + }, + { + "type": "error", + "name": "ReentrancyGuardReentrantCall", + "inputs": [] + }, + { + "type": "error", + "name": "RulesTypeMismatch", + "inputs": [ + { + "name": "derived", + "type": "uint8", + "internalType": "enum RulesType" + }, + { + "name": "actionIndex", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "target", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "TooManyActions", + "inputs": [ + { + "name": "count", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "UnknownPermission", + "inputs": [ + { + "name": "rulesId", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "UnsupportedExecutionMode", + "inputs": [] + }, + { + "type": "error", + "name": "UnsupportedModuleType", + "inputs": [ + { + "name": "moduleTypeId", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "ValidationFailed", + "inputs": [ + { + "name": "authorizer", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ValidatorNotInstalled", + "inputs": [ + { + "name": "validator", + "type": "address", + "internalType": "address" + } + ] + } +] diff --git a/packages/core/scripts/agw-local/contracts/HarnessFixtures.sol b/packages/core/scripts/agw-local/contracts/HarnessFixtures.sol new file mode 100644 index 00000000..9f509350 --- /dev/null +++ b/packages/core/scripts/agw-local/contracts/HarnessFixtures.sol @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +// REVIEW-ONLY FIXTURES for the SDK's local AGW harness. None of this is production +// code and none of it is a model of a deployed Push contract beyond the narrow +// behaviour named on each contract. Live gateway/core/TSS/destination behaviour is +// NOT exercised by anything that uses these fixtures. + +/// @notice Minimal PRC20 stand-in: transfers, allowances, burn and the +/// SOURCE_CHAIN_NAMESPACE view URP interrogates at universal grant. +contract HarnessPRC20 { + string public SOURCE_CHAIN_NAMESPACE; + string private _sourceOverride; + bool private _hasSourceOverride; + function setSourceChainNamespace(string calldata chain) external { SOURCE_CHAIN_NAMESPACE = chain; } + function setSourceTokenAddress(string calldata source) external { + _sourceOverride = source; _hasSourceOverride = true; + } + function SOURCE_TOKEN_ADDRESS() external view returns (string memory) { + if (_hasSourceOverride) return _sourceOverride; + bytes memory chars = "0123456789abcdef"; + bytes memory out = new bytes(42); out[0] = "0"; out[1] = "x"; + uint160 v = uint160(address(this)); + for (uint256 i; i < 40; ++i) out[41-i] = chars[(v >> (4*i)) & 15]; + return string(out); + } + uint8 public immutable decimals; + mapping(address => uint256) public balanceOf; + mapping(address => mapping(address => uint256)) public allowance; + uint256 public totalSupply; + + error LowBalance(); + error LowAllowance(); + + event Transfer(address indexed from, address indexed to, uint256 value); + event Approval(address indexed owner, address indexed spender, uint256 value); + + constructor(string memory sourceChainNamespace, uint8 decimals_) { + SOURCE_CHAIN_NAMESPACE = sourceChainNamespace; + decimals = decimals_; + } + + function mint(address to, uint256 amount) external { + balanceOf[to] += amount; + totalSupply += amount; + emit Transfer(address(0), to, amount); + } + + function approve(address spender, uint256 amount) external returns (bool) { + allowance[msg.sender][spender] = amount; + emit Approval(msg.sender, spender, amount); + return true; + } + + function transfer(address to, uint256 amount) external returns (bool) { + _move(msg.sender, to, amount); + return true; + } + + function transferFrom(address from, address to, uint256 amount) external returns (bool) { + uint256 a = allowance[from][msg.sender]; + if (a < amount) revert LowAllowance(); + allowance[from][msg.sender] = a - amount; + _move(from, to, amount); + return true; + } + + function burn(uint256 amount) external returns (bool) { + if (balanceOf[msg.sender] < amount) revert LowBalance(); + balanceOf[msg.sender] -= amount; + totalSupply -= amount; + emit Transfer(msg.sender, address(0), amount); + return true; + } + + function _move(address from, address to, uint256 amount) internal { + if (balanceOf[from] < amount) revert LowBalance(); + balanceOf[from] -= amount; + balanceOf[to] += amount; + emit Transfer(from, to, amount); + } +} + +/// @notice Fixed-quote stand-in for UniversalCore.getOutboundTxGasAndFees. +contract HarnessUniversalCore { + uint256 public gasFee = 1e15; + uint256 public protocolFee = 1e14; + mapping(string => address) public gasTokenPRC20ByChainNamespace; + function setGasToken(string calldata chain, address token) external { gasTokenPRC20ByChainNamespace[chain] = token; } + + function getOutboundTxGasAndFees(address prc20, uint256 gasLimit) + external + view + returns (address gasToken, uint256 gasFee_, uint256 protocolFee_, uint256 gasPrice, string memory chainNamespace, uint256 gasLimitUsed) + { + (bool ok, bytes memory ret) = prc20.staticcall(abi.encodeWithSignature("SOURCE_CHAIN_NAMESPACE()")); + chainNamespace = ok ? abi.decode(ret, (string)) : ""; + return (prc20, gasFee, protocolFee, 1 gwei, chainNamespace, gasLimit == 0 ? 200_000 : gasLimit); + } +} + +struct HarnessOutboundRequest { + bytes recipient; + address token; + uint256 amount; + uint256 gasLimit; + uint256 gasPrice; + uint256 maxPCForGas; + bytes payload; + address revertRecipient; +} + +/// @notice Stub of UniversalGatewayPC's outbound pull. Models ONLY: non-zero +/// token/revertRecipient, transferFrom(msg.sender) + burn of `amount`, +/// msg.value >= protocolFee, maxPCForGas <= msg.value - protocolFee with the +/// excess refunded, and a recorded request. No fee swap, routing, TSS or +/// destination execution. Mirrors gateway bcbf7df UniversalGatewayPC.sol:141-237,430-435. +contract HarnessGatewayPC { + HarnessUniversalCore public immutable universalCore; + uint256 public outboundCount; + bytes32 public lastRequestHash; + address public lastSender; + + error InvalidInput(); + error InsufficientFee(); + + event HarnessOutbound(address indexed sender, address indexed token, uint256 amount, uint256 value, bytes32 requestHash); + + constructor(HarnessUniversalCore core_) { + universalCore = core_; + } + + function sendUniversalTxOutbound(HarnessOutboundRequest calldata req) external payable { + if (req.token == address(0) || req.revertRecipient == address(0)) revert InvalidInput(); + if (req.amount == 0 && req.payload.length == 0) revert InvalidInput(); + uint256 protocolFee = universalCore.protocolFee(); + if (msg.value < protocolFee) revert InsufficientFee(); + uint256 pcForSwap = msg.value - protocolFee; + if (req.maxPCForGas != 0) { + if (req.maxPCForGas > pcForSwap) revert InsufficientFee(); + uint256 refund = pcForSwap - req.maxPCForGas; + if (refund > 0) { + (bool ok,) = msg.sender.call{ value: refund }(""); + require(ok, "refund"); + } + } + if (req.amount > 0) { + HarnessPRC20(req.token).transferFrom(msg.sender, address(this), req.amount); + HarnessPRC20(req.token).burn(req.amount); + } + outboundCount++; + lastSender = msg.sender; + lastRequestHash = keccak256(abi.encode(req)); + emit HarnessOutbound(msg.sender, req.token, req.amount, msg.value, lastRequestHash); + } + + receive() external payable { } +} + +/// @notice Native-rule target: records calls so authorization effects are observable. +contract HarnessTarget { + uint256 public counter; + address public lastBeneficiary; + uint256 public lastAmount; + uint256 public received; + + function increment() external { + counter++; + } + + function deposit(address beneficiary, uint256 amount) external payable { + lastBeneficiary = beneficiary; + lastAmount = amount; + received += msg.value; + counter++; + } + + receive() external payable { + received += msg.value; + } +} + +/// @notice Test-only ERC-7821-shaped executor for real Anvil EIP-7702 transactions. +/// Models self-call authorization and atomic CALL dispatch, not the deployed OZ artifact. +contract HarnessAtomicExecutor { + struct Execution { address target; uint256 value; bytes callData; } + function execute(bytes32 mode, bytes calldata data) external payable { + require(msg.sender == address(this), "self call only"); + require(mode == bytes32(uint256(1) << 248), "batch/default only"); + Execution[] memory calls = abi.decode(data, (Execution[])); + for (uint256 i; i < calls.length; ++i) { + (bool ok, bytes memory ret) = calls[i].target.call{value: calls[i].value}(calls[i].callData); + if (!ok) assembly { revert(add(ret, 32), mload(ret)) } + } + } + receive() external payable {} +} diff --git a/packages/core/scripts/agw-local/gen-abi.mjs b/packages/core/scripts/agw-local/gen-abi.mjs new file mode 100644 index 00000000..0430e31a --- /dev/null +++ b/packages/core/scripts/agw-local/gen-abi.mjs @@ -0,0 +1,72 @@ +#!/usr/bin/env node +// Regenerates packages/core/src/lib/agentic/contracts/abi/v5/*.ts from the +// pinned ABI snapshots in ./abis/. The JSON files are the source artifact set; +// this script only re-serialises them as +// `as const` TypeScript so viem can infer types. Run from the repo root: +// node packages/core/scripts/agw-local/gen-abi.mjs +import { createHash } from 'node:crypto'; +import { readFileSync, writeFileSync, mkdirSync } from 'node:fs'; +import { dirname, join, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const here = dirname(fileURLToPath(import.meta.url)); +const repo = resolve(here, '../../../..'); +const src = join(here, 'abis'); +const dst = join(repo, 'packages/core/src/lib/agentic/contracts/abi/v5'); +const PIN = '2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb'; + +const sourceNames = { + AGW: 'wallet', + AGWFactory: 'factory', + UniversalRulesPolicy: 'policy', + SmartSession: 'engine', + AgentValidator: 'validator', +}; +const files = { + AGW: ['AGW_ABI', 'agw.ts'], + AGWFactory: ['AGW_FACTORY_ABI', 'agw-factory.ts'], + UniversalRulesPolicy: [ + 'UNIVERSAL_RULES_POLICY_ABI', + 'universal-rules-policy.ts', + ], + SmartSession: ['SMART_SESSION_ABI', 'smart-session.ts'], + AgentValidator: ['AGENT_VALIDATOR_ABI', 'agent-validator.ts'], +}; +const manifest = JSON.parse(readFileSync(join(src, 'manifest.json'), 'utf8')); +if (manifest.sourceCommit !== PIN) { + throw new Error('ABI source commit does not match the supported generation'); +} + + +mkdirSync(dst, { recursive: true }); +const exports = []; +for (const [name, [constName, file]] of Object.entries(files)) { + const sourceFile = `${sourceNames[name]}.json`; + const raw = readFileSync(join(src, sourceFile)); + const sha = createHash('sha256').update(raw).digest('hex'); + if (sha !== manifest.files[sourceFile]) { + throw new Error(`ABI source hash mismatch: ${sourceFile}`); + } + const abi = JSON.parse(raw.toString()).filter( + (e) => e.type !== 'constructor' + ); + const body = + `// GENERATED by packages/core/scripts/agw-local/gen-abi.mjs — do not edit.\n` + + `// Source: packages/core/scripts/agw-local/abis/${sourceFile}\n` + + `// push-agentic-wallets@${PIN}\n` + + `// sha256(${name}.json) = ${sha}\n` + + `export const ${constName} = ${JSON.stringify(abi, null, 2)} as const;\n`; + writeFileSync(join(dst, file), body); + exports.push( + `export { ${constName} } from './${file.replace(/\.ts$/, '')}';` + ); +} +writeFileSync( + join(dst, 'index.ts'), + `// GENERATED by packages/core/scripts/agw-local/gen-abi.mjs — do not edit.\n` + + `// Review generation v5: Donut v5 deployment; source 2e61e13.\n` + + `export const V5_SOURCE_COMMIT = '${PIN}' as const;\n` + + exports.join('\n') + + '\n' +); +console.log(`wrote ${Object.keys(files).length} ABI modules to ${dst}`); diff --git a/packages/core/scripts/agw-local/prepare.sh b/packages/core/scripts/agw-local/prepare.sh new file mode 100755 index 00000000..9cd1923c --- /dev/null +++ b/packages/core/scripts/agw-local/prepare.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +# Prepare an ISOLATED build of the pinned AGW contracts for the SDK's local +# contract harness (review-only; never a deployment of record). +# +# AGW_REPO path to a push-agentic-wallets clone (default: ../../../../push-agentic-wallets +# relative to this script). Only `git archive` / `git ls-tree` are run against it, +# so the clone's working tree, branches and index are never touched. +# AGW_PIN commit to extract (default: the reviewed v5). +# OUT destination directory (default: $TMPDIR/push-agw-local-). +# +# The script extracts the pinned tree, fetches each git submodule at the exact +# commit recorded in that tree, copies the harness-only contracts from +# ./contracts into OUT/sdk-harness, and runs `forge build`. It never broadcasts. +set -euo pipefail + +HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +AGW_REPO="${AGW_REPO:-$HERE/../../../../../push-agentic-wallets}" +AGW_PIN="${AGW_PIN:-2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb}" +OUT="${OUT:-${TMPDIR:-/tmp}/push-agw-local-${AGW_PIN:0:7}}" + +command -v forge >/dev/null || { echo "forge not found (install Foundry)" >&2; exit 1; } +git -C "$AGW_REPO" cat-file -e "${AGW_PIN}^{commit}" 2>/dev/null || { + echo "AGW pin $AGW_PIN is not present in $AGW_REPO; fetch it first" >&2; exit 1; } + +mkdir -p "$OUT" +if [ ! -f "$OUT/.agw-pin" ] || [ "$(cat "$OUT/.agw-pin")" != "$AGW_PIN" ]; then + echo "extracting $AGW_PIN -> $OUT" + git -C "$AGW_REPO" archive "$AGW_PIN" | tar -x -C "$OUT" + # Submodules are gitlinks in the archive; fetch each at its recorded commit. + git -C "$AGW_REPO" ls-tree "$AGW_PIN" lib/ | awk '$2 == "commit" { print $3, $4 }' | + while read -r commit path; do + url="$(git -C "$AGW_REPO" show "$AGW_PIN:.gitmodules" | + git config -f /dev/stdin --get "submodule.$path.url")" + echo "submodule $path @ $commit ($url)" + rm -rf "${OUT:?}/$path" + git init -q "$OUT/$path" + git -C "$OUT/$path" fetch -q --depth 1 "$url" "$commit" + git -C "$OUT/$path" checkout -q FETCH_HEAD + test "$(git -C "$OUT/$path" rev-parse HEAD)" = "$commit" + done + echo "$AGW_PIN" > "$OUT/.agw-pin" +fi + +mkdir -p "$OUT/sdk-harness" +cp "$HERE"/contracts/*.sol "$OUT/sdk-harness/" + +(cd "$OUT" && forge build --offline src sdk-harness lib/smartsessions/contracts/SmartSession.sol lib/openzeppelin-contracts/contracts/proxy >/dev/null) +echo "$OUT" diff --git a/packages/core/scripts/agw-verify.js b/packages/core/scripts/agw-verify.js new file mode 100644 index 00000000..3ac74f72 --- /dev/null +++ b/packages/core/scripts/agw-verify.js @@ -0,0 +1,74 @@ +/** One unfunded verification entry point. No .env loading, live E2E or publishing. */ +const { spawnSync } = require('node:child_process'); +const fs = require('node:fs'); +const path = require('node:path'); +const root = path.resolve(__dirname, '../../..'); +const dir = path.join(root, '.agw-validation'); +fs.mkdirSync(dir, { recursive: true }); +function run(name, file, args, options = {}) { + process.stdout.write(`AGW validation: ${name}\n`); + const result = spawnSync(file, args, { + cwd: root, + encoding: 'utf8', + maxBuffer: 20 * 1024 * 1024, + ...options, + }); + const out = String(result.stdout || '') + String(result.stderr || ''); + fs.writeFileSync(path.join(dir, `${name}.log`), out); + if (result.error || result.status !== 0) { + throw new Error( + `AGW validation failed: ${name}; see .agw-validation/${name}.log` + ); + } + return out; +} +const node = process.execPath; +run('units', node, [ + 'node_modules/jest/bin/jest.js', + '--config', + 'packages/core/jest.config.ts', + '--runInBand', + '--testPathPattern=agentic|outbound-(confirmation-gate|svm-confirmation)|svm-idl|evm-client.batch-gas', +]); +for (const kind of ['lib', 'spec', 'agw-local']) + run(`types-${kind}`, node, [ + 'node_modules/typescript/bin/tsc', + '-p', + `packages/core/tsconfig.${kind}.json`, + '--noEmit', + ]); +run('docs', node, ['packages/core/scripts/check-agw-docs.js']); +const env = { + ...process.env, + OUT: process.env.AGW_LOCAL_DIR || path.join(dir, 'contracts'), +}; +run( + 'prepare-contracts', + 'bash', + ['packages/core/scripts/agw-local/prepare.sh'], + { env } +); +run( + 'local-contracts', + node, + [ + 'node_modules/jest/bin/jest.js', + '--config', + 'packages/core/jest.agw-local.config.ts', + '--runInBand', + ], + { env: { ...env, AGW_LOCAL_DIR: env.OUT } } +); +run( + 'build', + node, + ['node_modules/nx/bin/nx.js', 'run', 'core:build', '--skip-nx-cache'], + { env: { ...process.env, NX_DAEMON: 'false' } } +); +run('package', node, ['packages/core/scripts/check-agw-package.js']); +run('public-api', node, [ + 'packages/core/scripts/check-agw-api.js', + '--output', + path.join(dir, 'api-comparison.json'), +]); +process.stdout.write('AGW unfunded validation completed.\n'); diff --git a/packages/core/scripts/check-agw-api.js b/packages/core/scripts/check-agw-api.js new file mode 100644 index 00000000..41cde023 --- /dev/null +++ b/packages/core/scripts/check-agw-api.js @@ -0,0 +1,424 @@ +/** Public export/type comparison. Report changes; do not approve pending API choices. */ +const fs = require('node:fs'); +const path = require('node:path'); +const { execFileSync } = require('node:child_process'); +const ts = require('typescript'); +const assert = require('node:assert/strict'); +const root = path.resolve(__dirname, '../../..'); +const baseline = 'b1597b91a25dbf7f691f589b4e1e154add604315'; +const config = ts.readConfigFile( + path.join(root, 'packages/core/tsconfig.lib.json'), + ts.sys.readFile +); +const options = ts.parseJsonConfigFileContent( + config.config, + ts.sys, + path.join(root, 'packages/core') +).options; +const selected = [ + 'AgenticNamespace', + 'AgenticWallet', + 'AgenticError', + 'AgenticRevertError', + 'AGENTIC_ERROR_CODE', + 'NativeRule', + 'ArgPin', + 'AmountLimit', + 'AssetCap', + 'AllowedCall', + 'UniversalRule', + 'RulesRecord', + 'CreateOptions', + 'CreateResult', + 'AgenticTxMetadata', +]; +function snapshot(entry) { + const program = ts.createProgram([entry], { ...options, noEmit: true }); + const diagnostics = ts.getPreEmitDiagnostics(program); + if (diagnostics.length) + throw new Error( + ts.formatDiagnostics(diagnostics, { + getCanonicalFileName: (f) => f, + getCurrentDirectory: () => root, + getNewLine: () => '\n', + }) + ); + const checker = program.getTypeChecker(), + file = program.getSourceFile(entry); + const exports = checker.getExportsOfModule(checker.getSymbolAtLocation(file)); + const literals = new Map(), + ambiguous = new Set(); + for (const source of program + .getSourceFiles() + .filter((f) => f.fileName.includes('/packages/core/src/'))) { + for (let symbol of checker.getSymbolsInScope( + source, + ts.SymbolFlags.Value + )) { + const name = symbol.name; + if (symbol.flags & ts.SymbolFlags.Alias) + symbol = checker.getAliasedSymbol(symbol); + const type = checker.getTypeOfSymbolAtLocation(symbol, source); + if (type.flags & ts.TypeFlags.EnumLiteral) continue; + const literal = type.isStringLiteral() + ? JSON.stringify(type.value) + : type.isNumberLiteral() + ? String(type.value) + : undefined; + if (literal === undefined) continue; + if (literals.has(name) && literals.get(name) !== literal) + ambiguous.add(name); + else literals.set(name, literal); + } + } + const printer = ts.createPrinter({ removeComments: true }); + const modules = new Map( + program + .getSourceFiles() + .filter((f) => f.fileName.includes('/packages/core/src/')) + .map((f) => [ + 'sdk/src/' + + f.fileName + .split('/src/') + .pop() + .replace(/\.d\.ts$|\.tsx?$/, ''), + f, + ]) + ); + function reference(match, kind, module, name) { + const source = + modules.get(module) || + program.getSourceFile(module + '.d.ts') || + program.getSourceFile(module + '.ts'); + if (!source) return match; + const moduleSymbol = checker.getSymbolAtLocation(source); + let symbol = [ + ...(moduleSymbol ? checker.getExportsOfModule(moduleSymbol) : []), + ...checker.getSymbolsInScope( + source, + ts.SymbolFlags.Type | ts.SymbolFlags.Value | ts.SymbolFlags.Namespace + ), + ].find((s) => s.name === name); + if (!symbol) return match; + if (symbol.flags & ts.SymbolFlags.Alias) + symbol = checker.getAliasedSymbol(symbol); + const decl = symbol.declarations?.[0]; + if (!decl) return match; + if (!kind && symbol.flags & ts.SymbolFlags.TypeAlias) { + const type = checker.getDeclaredTypeOfSymbol(symbol); + if ( + type.flags & + (ts.TypeFlags.StringLike | + ts.TypeFlags.NumberLike | + ts.TypeFlags.BooleanLike | + ts.TypeFlags.BigIntLike | + ts.TypeFlags.TemplateLiteral | + ts.TypeFlags.Null | + ts.TypeFlags.Undefined) + ) + return normal( + checker.typeToString( + type, + file, + ts.TypeFormatFlags.NoTruncation | ts.TypeFormatFlags.InTypeAlias + ) + ); + } + if (kind === 'typeof ') { + const type = checker.getTypeOfSymbolAtLocation(symbol, decl); + const calls = type.getCallSignatures(); + if (calls.length === 1) + return normal( + checker.signatureToString( + calls[0], + file, + ts.TypeFormatFlags.NoTruncation | + ts.TypeFormatFlags.WriteArrowStyleSignature + ) + ); + } + const location = decl.getSourceFile().fileName; + if (!location.includes('/packages/core/src/')) return match; + return `${kind || ''}import("sdk/src/${location + .split('/src/') + .pop() + .replace(/\.d\.ts$|\.tsx?$/, '')}").${symbol.name}`; + } + function canonicalType(text) { + for (let pass = 0; pass < 4; pass++) + text = text.replace( + /(typeof )?import\("([^"]+)"\)\.([A-Za-z_][\w]*)/g, + reference + ); + text = text.replace( + /typeof import\("[^"]+"\)\.([A-Za-z_][\w]*)/g, + (match, name) => + ambiguous.has(name) ? match : literals.get(name) || match + ); + const parsed = ts.createSourceFile( + 'surface.ts', + `type Surface = ${text};`, + ts.ScriptTarget.Latest, + true + ); + const result = ts.transform(parsed, [ + (context) => { + const visit = (node) => { + node = ts.visitEachChild(node, visit, context); + if (ts.isUnionTypeNode(node) || ts.isIntersectionTypeNode(node)) { + const types = [...node.types].sort((a, b) => + printer + .printNode(ts.EmitHint.Unspecified, a, parsed) + .localeCompare( + printer.printNode(ts.EmitHint.Unspecified, b, parsed) + ) + ); + return ts.isUnionTypeNode(node) + ? ts.factory.createUnionTypeNode(types) + : ts.factory.createIntersectionTypeNode(types); + } + if ( + ts.isTypeLiteralNode(node) && + node.members.every( + (m) => ts.isPropertySignature(m) || ts.isMethodSignature(m) + ) + ) { + return ts.factory.createTypeLiteralNode( + [...node.members].sort((a, b) => + printer + .printNode(ts.EmitHint.Unspecified, a.name, parsed) + .localeCompare( + printer.printNode(ts.EmitHint.Unspecified, b.name, parsed) + ) + ) + ); + } + return node; + }; + return (source) => ts.visitNode(source, visit); + }, + ]); + try { + return printer.printNode( + ts.EmitHint.Unspecified, + result.transformed[0].statements[0].type, + parsed + ); + } finally { + result.dispose(); + } + } + const normal = (s) => + s.replace( + /import\("([^"]+)"\)/g, + (_, p) => + `import("${ + p.includes('/src/') ? 'sdk/src/' + p.split('/src/').pop() : p + }")` + ); + const text = (t, node) => + canonicalType( + normal( + checker.typeToString( + t, + node, + ts.TypeFormatFlags.NoTruncation | ts.TypeFormatFlags.InTypeAlias + ) + ) + ); + function properties(t) { + return Object.fromEntries( + checker + .getPropertiesOfType(t) + .filter((p) => { + const d = p.valueDeclaration || p.declarations?.[0]; + if ( + d && + /\/typescript\/lib\/lib\.[^/]+\.d\.ts$/.test( + d.getSourceFile().fileName + ) + ) + return false; + return ( + !d || + !( + ts.getCombinedModifierFlags(d) & + (ts.ModifierFlags.Private | ts.ModifierFlags.Protected) + ) + ); + }) + .map((p) => [ + p.name.replace(/(__@[^@]+)@\d+$/, '$1'), + { + optional: Boolean(p.flags & ts.SymbolFlags.Optional), + readonly: Boolean( + ts.getCheckFlags(p) & ts.CheckFlags.Readonly || + p.declarations?.some( + (d) => + ts.getCombinedModifierFlags(d) & ts.ModifierFlags.Readonly + ) + ), + type: text(checker.getTypeOfSymbolAtLocation(p, file), file), + }, + ]) + .sort(([a], [b]) => a.localeCompare(b)) + ); + } + const result = { + exports: exports.map((s) => s.name).sort(), + agw: {}, + publicSurface: {}, + }; + for (let s of exports) { + const name = s.name; + if (s.flags & ts.SymbolFlags.Alias) s = checker.getAliasedSymbol(s); + const t = + s.flags & + (ts.SymbolFlags.Interface | + ts.SymbolFlags.TypeAlias | + ts.SymbolFlags.Class) + ? checker.getDeclaredTypeOfSymbol(s) + : checker.getTypeOfSymbolAtLocation(s, file); + result.publicSurface[name] = { + type: text(t, file), + members: properties(t), + }; + } + for (const name of selected) { + let s = exports.find((s) => s.name === name); + if (!s) continue; + if (s.flags & ts.SymbolFlags.Alias) s = checker.getAliasedSymbol(s); + const t = + s.flags & + (ts.SymbolFlags.Interface | + ts.SymbolFlags.TypeAlias | + ts.SymbolFlags.Class) + ? checker.getDeclaredTypeOfSymbol(s) + : checker.getTypeOfSymbolAtLocation(s, file); + result.agw[name] = { type: text(t, file), members: properties(t) }; + } + let push = exports.find((s) => s.name === 'PushChain'); + if (push.flags & ts.SymbolFlags.Alias) push = checker.getAliasedSymbol(push); + const staticType = checker.getTypeOfSymbolAtLocation(push, file); + const instanceType = checker.getDeclaredTypeOfSymbol(push); + result.pushChainStatic = properties(staticType); + delete result.pushChainStatic.prototype; + result.pushChainInstance = properties(instanceType); + const universal = instanceType.getProperty('universal'); + result.transactionMethods = properties( + checker.getTypeOfSymbolAtLocation(universal, file) + ); + const utils = staticType.getProperty('utils'); + const utilsType = checker.getTypeOfSymbolAtLocation(utils, file); + result.utilityMethods = properties(utilsType); + delete result.utilityMethods.prototype; + const init = staticType.getProperty('initialize'); + result.initialize = text(checker.getTypeOfSymbolAtLocation(init, file), file); + const constants = staticType.getProperty('CONSTANTS'); + const cType = checker.getTypeOfSymbolAtLocation(constants, file), + agw = cType.getProperty('AGENTIC'); + const aType = checker.getTypeOfSymbolAtLocation(agw, file); + const donut = aType.getProperty('TESTNET_DONUT'); + result.agwConstants = properties( + checker.getNonNullableType(checker.getTypeOfSymbolAtLocation(donut, file)) + ); + result.constants = properties(cType); + return result; +} +const current = snapshot(path.join(root, 'packages/core/src/index.ts')); +const built = snapshot(path.join(root, 'dist/packages/core/src/index.d.ts')); +assert.deepEqual( + built, + current, + 'compiled public API differs from source public API' +); +try { + execFileSync('git', ['cat-file', '-e', `${baseline}^{commit}`], { + cwd: root, + stdio: 'ignore', + }); +} catch { + execFileSync( + 'git', + [ + 'fetch', + '--depth=1', + 'https://github.com/pushchain/push-chain-sdk.git', + baseline, + ], + { cwd: root, stdio: 'ignore' } + ); +} +const temp = fs.mkdtempSync(path.join(root, 'node_modules/.cache/agw-api-')); +try { + const archive = execFileSync( + 'git', + ['archive', baseline, 'packages/core/src'], + { cwd: root, maxBuffer: 30 * 1024 * 1024 } + ); + execFileSync('tar', ['-x', '-C', temp], { input: archive }); + const old = snapshot(path.join(temp, 'packages/core/src/index.ts')); + const changes = []; + for (const name of selected) + if (JSON.stringify(old.agw[name]) !== JSON.stringify(current.agw[name])) + changes.push(name); + const publicTypeChanges = Object.keys(current.publicSurface).filter( + (name) => + JSON.stringify(old.publicSurface[name]) !== + JSON.stringify(current.publicSurface[name]) + ); + const transactionMethodChanges = Object.keys( + current.transactionMethods + ).filter( + (name) => + JSON.stringify(old.transactionMethods[name]) !== + JSON.stringify(current.transactionMethods[name]) + ); + const instanceMethodChanges = Object.keys(current.pushChainInstance).filter( + (name) => + JSON.stringify(old.pushChainInstance[name]) !== + JSON.stringify(current.pushChainInstance[name]) + ); + const report = { + baseline, + head: execFileSync('git', ['rev-parse', 'HEAD'], { + cwd: root, + encoding: 'utf8', + }).trim(), + compiledMatchesSource: true, + initializeSignatureChanged: old.initialize !== current.initialize, + addedExports: current.exports.filter((s) => !old.exports.includes(s)), + removedExports: old.exports.filter((s) => !current.exports.includes(s)), + changedAgwTypes: changes, + publicTypeChanges, + transactionMethodChanges, + instanceMethodChanges, + agwConstantsChanged: + JSON.stringify(old.agwConstants) !== JSON.stringify(current.agwConstants), + before: old, + after: current, + scope: + 'All root exports and declared public members, PushChain static/instance members, universal transaction methods, utility groups, readonly/optional markers and constants. Behavior/default/deployment changes need the written session review.', + }; + const at = process.argv.indexOf('--output'); + if (at >= 0) + fs.writeFileSync( + path.resolve(process.argv[at + 1]), + JSON.stringify(report, null, 2) + '\n' + ); + process.stdout.write( + JSON.stringify({ + compiledMatchesSource: true, + addedExports: report.addedExports, + removedExports: report.removedExports, + changedAgwTypes: changes, + publicTypeChanges, + transactionMethodChanges, + instanceMethodChanges, + initializeSignatureChanged: report.initializeSignatureChanged, + agwConstantsChanged: report.agwConstantsChanged, + }) + '\n' + ); +} finally { + fs.rmSync(temp, { recursive: true, force: true }); +} diff --git a/packages/core/scripts/check-agw-docs.js b/packages/core/scripts/check-agw-docs.js new file mode 100644 index 00000000..ec10c4b1 --- /dev/null +++ b/packages/core/scripts/check-agw-docs.js @@ -0,0 +1,50 @@ +/** Typecheck public AGW guide blocks; never evaluate examples or load keys. */ +const fs = require('node:fs'); +const path = require('node:path'); +const ts = require('typescript'); + +const root = path.resolve(__dirname, '../../..'); +const guide = path.join(root, 'packages/core/AGW.md'); +const blocks = [ + ...fs.readFileSync(guide, 'utf8').matchAll(/```ts\n([\s\S]*?)```/g), +].map((m) => m[1]); +if (!blocks.length) throw new Error('No AGW TypeScript examples found'); +const cache = path.join(root, 'node_modules/.cache'); +fs.mkdirSync(cache, { recursive: true }); +const dir = fs.mkdtempSync(path.join(cache, 'agw-docs-')); +try { + const source = path.join(dir, 'examples.ts'); + fs.writeFileSync(source, blocks.join('\n\n')); + const configPath = path.join(root, 'packages/core/tsconfig.lib.json'); + const config = ts.readConfigFile(configPath, ts.sys.readFile); + if (config.error) + throw new Error( + ts.flattenDiagnosticMessageText(config.error.messageText, '\n') + ); + const parsed = ts.parseJsonConfigFileContent( + config.config, + ts.sys, + path.dirname(configPath) + ); + const program = ts.createProgram([source], { + ...parsed.options, + noEmit: true, + }); + const diagnostics = [...parsed.errors, ...ts.getPreEmitDiagnostics(program)]; + if (diagnostics.length) { + process.stderr.write( + ts.formatDiagnostics(diagnostics, { + getCanonicalFileName: (file) => file, + getCurrentDirectory: () => root, + getNewLine: () => '\n', + }) + ); + process.exitCode = 1; + } else { + process.stdout.write( + `AGW guide: ${blocks.length} TypeScript blocks typechecked against public exports; no examples executed.\n` + ); + } +} finally { + fs.rmSync(dir, { recursive: true, force: true }); +} diff --git a/packages/core/scripts/check-agw-package.js b/packages/core/scripts/check-agw-package.js new file mode 100644 index 00000000..83cc7805 --- /dev/null +++ b/packages/core/scripts/check-agw-package.js @@ -0,0 +1,74 @@ +/** Consume built JS/declarations, not tsconfig's source alias. No wallet operations. */ +const fs = require('node:fs'); +const path = require('node:path'); +const { pathToFileURL } = require('node:url'); +const { execFileSync } = require('node:child_process'); +const assert = require('node:assert/strict'); +const ts = require('typescript'); +const root = path.resolve(__dirname, '../../..'); +const built = path.join(root, 'dist/packages/core'); +async function main() { + const entry = path.join(built, 'src/index.js'); + const cjs = require(entry), + esm = await import(pathToFileURL(entry).href); + assert.equal(typeof cjs.PushChain.initialize, 'function'); + assert.equal(esm.PushChain, cjs.PushChain); + assert.equal( + cjs.PushChain.CONSTANTS.AGENTIC.TESTNET_DONUT.ENVELOPE_VERSION, + 1 + ); + assert.equal(typeof cjs.AgenticError, 'function'); + const [pack] = JSON.parse( + execFileSync('npm', ['pack', '--dry-run', '--json', '--ignore-scripts'], { + cwd: built, + encoding: 'utf8', + }) + ); + assert(pack.files.some((f) => f.path === 'AGW.md')); + assert(!pack.files.some((f) => /(^|\/)\.env($|\.)/.test(f.path))); + const guide = fs.readFileSync(path.join(built, 'AGW.md'), 'utf8'); + const source = [...guide.matchAll(/```ts\n([\s\S]*?)```/g)] + .map((m) => m[1]) + .join('\n\n'); + const tmp = fs.mkdtempSync( + path.join(root, 'node_modules/.cache/agw-consumer-') + ); + try { + const file = path.join(tmp, 'consumer.ts'); + fs.writeFileSync(file, source); + const config = ts.readConfigFile( + path.join(root, 'packages/core/tsconfig.lib.json'), + ts.sys.readFile + ); + const parsed = ts.parseJsonConfigFileContent( + config.config, + ts.sys, + path.join(root, 'packages/core') + ); + const options = { + ...parsed.options, + noEmit: true, + paths: { '@pushchain/core': [path.join(built, 'src/index.d.ts')] }, + }; + const diagnostics = ts.getPreEmitDiagnostics( + ts.createProgram([file], options) + ); + if (diagnostics.length) + throw new Error( + ts.formatDiagnostics(diagnostics, { + getCanonicalFileName: (f) => f, + getCurrentDirectory: () => root, + getNewLine: () => '\n', + }) + ); + } finally { + fs.rmSync(tmp, { recursive: true, force: true }); + } + process.stdout.write( + 'AGW package: CJS/ESM imports, compiled declaration examples and npm contents pass. No examples executed/published.\n' + ); +} +main().catch((error) => { + process.stderr.write(`${error.message}\n`); + process.exitCode = 1; +}); diff --git a/packages/core/scripts/check-agw-runtimes.js b/packages/core/scripts/check-agw-runtimes.js new file mode 100644 index 00000000..6161bc73 --- /dev/null +++ b/packages/core/scripts/check-agw-runtimes.js @@ -0,0 +1,93 @@ +/** Local runtime matrix only. Never dispatch GitHub CI, fund E2Es or publish. */ +const fs = require('node:fs'), + path = require('node:path'); +const { spawnSync } = require('node:child_process'); +const root = path.resolve(__dirname, '../../..'); +const argument = (name) => { + const at = process.argv.indexOf(name); + return at < 0 ? undefined : process.argv[at + 1]; +}; +const binaries = [ + { major: 20, node: argument('--node20') || process.execPath }, + { major: 24, node: argument('--node24') }, +]; +if (!binaries[1].node) + throw new Error( + 'Provide --node24 ; --node20 defaults to the current executable.' + ); +const output = path.resolve( + argument('--output') || path.join(root, '.agw-runtime-validation') +); +fs.mkdirSync(output, { recursive: true }); +const results = []; +function command(dir, node, args, env, name) { + const result = spawnSync(node, args, { + cwd: root, + env, + encoding: 'utf8', + maxBuffer: 30 * 1024 * 1024, + }); + fs.writeFileSync( + path.join(dir, name + '.log'), + String(result.stdout || '') + String(result.stderr || '') + ); + if (result.error || result.status !== 0) + throw new Error(`Node ${node} failed ${name}; see ${dir}/${name}.log`); + return result.stdout; +} +for (const runtime of binaries) { + const dir = path.join(output, 'node' + runtime.major); + fs.mkdirSync(dir, { recursive: true }); + const env = { + ...process.env, + PATH: path.dirname(runtime.node) + path.delimiter + process.env.PATH, + }; + const version = command( + dir, + runtime.node, + [ + '-p', + 'JSON.stringify({version:process.version,major:Number(process.versions.node.split(".")[0]),platform:process.platform,arch:process.arch})', + ], + env, + 'version' + ); + const actual = JSON.parse(version); + if (actual.major !== runtime.major) + throw new Error(`Expected Node ${runtime.major}, got ${actual.version}`); + process.stdout.write(`AGW runtime matrix: ${actual.version}\n`); + command( + dir, + runtime.node, + [ + 'node_modules/jest/bin/jest.js', + '--config', + 'packages/core/jest.config.ts', + '--runInBand', + ], + env, + 'full-unit' + ); + command( + dir, + runtime.node, + ['packages/core/scripts/agw-verify.js'], + env, + 'verification' + ); + for (const file of fs.readdirSync(path.join(root, '.agw-validation'))) { + const source = path.join(root, '.agw-validation', file); + if (fs.statSync(source).isFile()) + fs.copyFileSync(source, path.join(dir, file)); + } + results.push({ ...actual, passed: true }); +} +fs.writeFileSync( + path.join(output, 'results.json'), + JSON.stringify( + { results, hostedCi: false, published: false, fundedE2Es: false }, + null, + 2 + ) + '\n' +); +process.stdout.write('Both runtime matrix entries passed.\n'); diff --git a/packages/core/src/lib/agentic/__fixtures__/v5-vectors.json b/packages/core/src/lib/agentic/__fixtures__/v5-vectors.json new file mode 100644 index 00000000..3f037d15 --- /dev/null +++ b/packages/core/src/lib/agentic/__fixtures__/v5-vectors.json @@ -0,0 +1,181 @@ +{ + "provenance": { + "agwCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", + "generatedBy": "packages/core/__agw-local__/vectors.spec.ts", + "toolchain": "forge Version: 1.5.1-stable", + "chainId": 9000, + "note": "Addresses are deterministic for a fresh anvil + the harness deploy order." + }, + "rulesId": [ + { + "validator": "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512", + "agent": "0x70997970C51812dc3A010C7d01b50e0d17dc79C8", + "grantNonce": { + "$bigint": "0" + }, + "agentConfig": "0x00000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8", + "expected": "0xed16789aedd36446aa851df227d231dfdaab75ab95d022e251d179e27fdcee59" + }, + { + "validator": "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512", + "agent": "0x70997970C51812dc3A010C7d01b50e0d17dc79C8", + "grantNonce": { + "$bigint": "1" + }, + "agentConfig": "0x00000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8", + "expected": "0xb5cf1093fb5b4109923a54fc9a67eff369e01392403b645e8e0155a6cb4990fe" + }, + { + "validator": "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512", + "agent": "0x70997970C51812dc3A010C7d01b50e0d17dc79C8", + "grantNonce": { + "$bigint": "7" + }, + "agentConfig": "0x00000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8", + "expected": "0xc05ecd2b8ea27dcaff748d5027fcc6b7963b9bf5452ccc6e3016235a878a2da3" + }, + { + "validator": "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512", + "agent": "0x70997970C51812dc3A010C7d01b50e0d17dc79C8", + "grantNonce": { + "$bigint": "9223372036854775808" + }, + "agentConfig": "0x00000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8", + "expected": "0xc568da4c1ecd6f73d2609cba4bccba9108f9b3b43e13797e63aa25db68a6ea79" + }, + { + "validator": "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512", + "agent": "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC", + "grantNonce": { + "$bigint": "0" + }, + "agentConfig": "0x0000000000000000000000003c44cdddb6a900fa2b585dd299e03d12fa4293bc", + "expected": "0x0a7234266892a3ade6ba3f70c1a4c0b56aefb198e74a14a5d6d08c5f8587498e" + }, + { + "validator": "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512", + "agent": "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC", + "grantNonce": { + "$bigint": "1" + }, + "agentConfig": "0x0000000000000000000000003c44cdddb6a900fa2b585dd299e03d12fa4293bc", + "expected": "0x66c8518bd08fc86347cb20601b22df298d73794e99c6eb9250f52ce78c949674" + }, + { + "validator": "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512", + "agent": "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC", + "grantNonce": { + "$bigint": "7" + }, + "agentConfig": "0x0000000000000000000000003c44cdddb6a900fa2b585dd299e03d12fa4293bc", + "expected": "0x11be56b6d0b4b6ba03b6475bdbe4393f68e689d690a5428821664947c0e9df3a" + }, + { + "validator": "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512", + "agent": "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC", + "grantNonce": { + "$bigint": "9223372036854775808" + }, + "agentConfig": "0x0000000000000000000000003c44cdddb6a900fa2b585dd299e03d12fa4293bc", + "expected": "0x35257788092b8179db6e880a636bc3114dbe9b1b30445d3551218ccc682478df" + }, + { + "validator": "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512", + "agent": "0x00000000000000000000000000000000000000ff", + "grantNonce": { + "$bigint": "0" + }, + "agentConfig": "0x00000000000000000000000000000000000000000000000000000000000000ff", + "expected": "0x675a172b2a29803a43c4c478a43b68730a6d74aee6102750b59bc49d29b70b47" + }, + { + "validator": "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512", + "agent": "0x00000000000000000000000000000000000000ff", + "grantNonce": { + "$bigint": "1" + }, + "agentConfig": "0x00000000000000000000000000000000000000000000000000000000000000ff", + "expected": "0x1ba472d29a9d5f904acd8d6682ab6beb04026365da11ec4f7142231ac3eb592b" + }, + { + "validator": "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512", + "agent": "0x00000000000000000000000000000000000000ff", + "grantNonce": { + "$bigint": "7" + }, + "agentConfig": "0x00000000000000000000000000000000000000000000000000000000000000ff", + "expected": "0xb5e300538b76a563882467a58f2073ed1677234609d698d22bb441814355f12c" + }, + { + "validator": "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512", + "agent": "0x00000000000000000000000000000000000000ff", + "grantNonce": { + "$bigint": "9223372036854775808" + }, + "agentConfig": "0x00000000000000000000000000000000000000000000000000000000000000ff", + "expected": "0x7b190cef2be98a983c96b0c4653480549c1f7ce35232f400dff5c6ce7f551f11" + } + ], + "deriveWallet": [ + { + "factory": "0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6", + "walletImplementation": "0x0165878A594ca255338adfa4d48449f69242Eb8F", + "owner": "0x90F79bf6EB2c4f870365E785982E1f101E93b906", + "index": 0, + "expected": "0xE68bD7D2E9b2F21bA9e4e09cE2D20A3d681Ec6e1" + }, + { + "factory": "0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6", + "walletImplementation": "0x0165878A594ca255338adfa4d48449f69242Eb8F", + "owner": "0x1111111111111111111111111111111111111111", + "index": 0, + "expected": "0x3066c721A477afBF4c3732F39A0048684e4641cF" + } + ], + "native": { + "rule": { + "agent": "0x70997970C51812dc3A010C7d01b50e0d17dc79C8", + "target": "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318", + "selector": "deposit(address,uint256)", + "validUntil": 4102444800, + "pins": [ + { + "arg": 0, + "expected": "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC" + } + ], + "amount": { + "arg": 1, + "maxPerCall": { + "$bigint": "10" + }, + "maxTotal": { + "$bigint": "100" + } + }, + "maxValuePerCall": { + "$bigint": "5" + }, + "maxValueTotal": { + "$bigint": "50" + }, + "maxCalls": 3 + }, + "nativeChain": "eip155:9000", + "wallet": "0x3e8FE21F60352CE4e632537113451A6990b9b7e6", + "rulesId": "0xed16789aedd36446aa851df227d231dfdaab75ab95d022e251d179e27fdcee59", + "actionId": "0x95eb75f6723928adc7fd1b4edeec4a558cc76cef41e06b7a16448bf74364d791", + "configId": "0x939681af8de835b5dde52d6056defa47df21b9325892b5945f113a8112179e69", + "configInitialized": true, + "storedTarget": "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318", + "storedSelector": "0x47e7ef24", + "storedPins": [ + { + "offset": 4, + "expected": "0x0000000000000000000000003c44cdddb6a900fa2b585dd299e03d12fa4293bc" + } + ], + "storedAmountOffset": 36, + "encodedSession": "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000e7f1725e7734ce288f8367e1bb143e90bb3f051200000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002047e7ef24000000000000000000000000000000000000000000000000000000000000000000000000000000008a791620dd6260079bf849dc5567adc3f2fdc318000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000cf7ed3acca5a467e9e704c703e8d87f634fb0fc9000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000b6569703135353a3930303000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000f48657000000000000000000000000008a791620dd6260079bf849dc5567adc3f2fdc31847e7ef24000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000003200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000040000000000000000000000003c44cdddb6a900fa2b585dd299e03d12fa4293bc" + } +} diff --git a/packages/core/src/lib/agentic/__tests__/codec.spec.ts b/packages/core/src/lib/agentic/__tests__/codec.spec.ts new file mode 100644 index 00000000..6721ad68 --- /dev/null +++ b/packages/core/src/lib/agentic/__tests__/codec.spec.ts @@ -0,0 +1,444 @@ +import { decodeFunctionData, getAddress, type Address, type Hex } from 'viem'; +import vectorsJson from '../__fixtures__/v5-vectors.json'; +import { + actionId, + agentConfig, + configId, + deriveWallet, + rulesId, +} from '../codec/ids'; +import { + decodeNativeTerms, + encodeNativeTerms, + nativeRuleToTerms, + nativeTermsToRule, +} from '../codec/native'; +import { + buildSession, + decodeEnvelope, + decodeSession, + encodeEnvelope, + encodeSession, +} from '../codec/session'; +import { parseSelector, VALUE_ONLY_SELECTOR } from '../codec/selectors'; +import { argumentOffset, headSize } from '../codec/abi-layout'; +import { UINT256_MAX } from '../codec/defaults'; +import { v5 } from '../contracts/v5'; +import { AGW_ABI } from '../contracts/abi/v5'; +import { AGENTIC_ERROR_CODE } from '../errors'; +import type { NativeRule } from '../agentic.types'; + +/** Restore {$bigint} markers written by the vector generator. */ +function revive(v: T): T { + return JSON.parse(JSON.stringify(v), (_k, x) => + x && typeof x === 'object' && '$bigint' in x ? BigInt(x.$bigint) : x + ); +} +const vectors = revive(vectorsJson) as unknown as { + rulesId: { + validator: Address; + agent: Address; + grantNonce: bigint; + agentConfig: Hex; + expected: Hex; + }[]; + deriveWallet: { + factory: Address; + walletImplementation: Address; + owner: Address; + index: number; + expected: Address; + }[]; + native: { + rule: NativeRule; + nativeChain: string; + wallet: Address; + rulesId: Hex; + actionId: Hex; + configId: Hex; + configInitialized: boolean; + storedTarget: Address; + storedSelector: Hex; + storedPins: { offset: number; expected: Hex }[]; + storedAmountOffset: number; + encodedSession: Hex; + }; +}; + +const NOW = 1_700_000_000; +const target = getAddress('0x0000000000000000000000000000000000007a76'); +const agent = getAddress('0x00000000000000000000000000000000000000a9'); + +describe('IDs against contract-generated vectors (v5)', () => { + it.each(vectors.rulesId)( + 'rulesId(agent, nonce) = engine.getPermissionId — nonce $grantNonce', + (v) => { + expect(agentConfig(v.agent)).toBe(v.agentConfig); + expect( + rulesId({ + validator: v.validator, + agent: v.agent, + grantNonce: v.grantNonce, + }) + ).toBe(v.expected); + } + ); + + it.each(vectors.deriveWallet)( + 'deriveWallet mirrors factory.predictWallet for $owner', + (v) => { + expect(deriveWallet(v)).toBe(getAddress(v.expected)); + } + ); + + it('actionId/configId: the policy holds an initialized config under exactly this key', () => { + const n = vectors.native; + expect(n.configInitialized).toBe(true); + expect(actionId(getAddress(n.storedTarget), n.storedSelector)).toBe( + n.actionId + ); + expect(configId(n.wallet, n.rulesId, n.actionId)).toBe(n.configId); + }); + + it('rulesId rejects a grant nonce outside uint64', () => { + expect(() => + rulesId({ validator: agent, agent, grantNonce: BigInt(2) ** BigInt(64) }) + ).toThrow(/uint64/); + }); +}); + +describe('native rule codec', () => { + const v = vectors.native; + + it('encodes the session the contracts accepted and stored', () => { + const { terms } = nativeRuleToTerms(v.rule, { nowSeconds: NOW }); + const session = buildSession({ + validator: decodeSession(v.encodedSession).sessionValidator, + agent: v.rule.agent, + rulesPolicy: decodeSession(v.encodedSession).actions[0].actionPolicies[0] + .policy, + actions: [ + { + target: terms.target, + selector: terms.selector, + initData: encodeEnvelope(v.nativeChain, encodeNativeTerms(terms)), + }, + ], + }); + expect(encodeSession(session)).toBe(v.encodedSession); + expect(terms.pins).toEqual(v.storedPins); + expect(terms.amount.offset).toBe(v.storedAmountOffset); + expect(terms.selector).toBe(v.storedSelector); + }); + + it('round-trips terms through the envelope and back to a public rule', () => { + const { terms } = nativeRuleToTerms(v.rule, { nowSeconds: NOW }); + const env = decodeEnvelope( + encodeEnvelope(v.nativeChain, encodeNativeTerms(terms)) + ); + expect(env.chainNamespace).toBe(v.nativeChain); + const back = decodeNativeTerms(env.body); + expect(back).toEqual({ ...terms, validUntil: terms.validUntil }); + const rule = nativeTermsToRule(back, v.rule.agent); + // Stored terms carry offsets, not an ABI: decoded rules report the raw offset form. + expect(rule.pins).toEqual([ + { offset: 4, expected: terms.pins[0].expected.toLowerCase() }, + ]); + expect(rule.amount).toEqual({ + offset: 36, + maxPerCall: BigInt(10), + maxTotal: BigInt(100), + }); + expect(rule).not.toHaveProperty('ref'); + // …and the decoded rule re-encodes to identical terms with only its 4-byte selector. + expect(nativeRuleToTerms(rule, { nowSeconds: NOW }).terms).toEqual(terms); + }); + + it('decoding never invents argument indexes: a static array before a pin stays a raw offset', () => { + const input: NativeRule = { + agent, + target, + selector: 'deposit(uint256[2],address)', + validUntil: NOW + 10, + pins: [{ arg: 1, expected: agent }], + }; + const { terms } = nativeRuleToTerms(input, { nowSeconds: NOW }); + expect(terms.pins[0].offset).toBe(4 + 64); + const decoded = nativeTermsToRule(terms, agent); + expect(decoded.pins).toEqual([ + { offset: 68, expected: terms.pins[0].expected }, + ]); + expect(nativeRuleToTerms(decoded, { nowSeconds: NOW }).terms).toEqual( + terms + ); + }); + + it('a decoded address pin re-encodes in argument form once the signature is restored', () => { + const input: NativeRule = { + agent, + target, + selector: 'deposit(address,uint256)', + validUntil: NOW + 10, + pins: [{ arg: 0, expected: agent }], + }; + const { terms } = nativeRuleToTerms(input, { nowSeconds: NOW }); + const word = terms.pins[0].expected; + expect( + nativeRuleToTerms( + { ...input, pins: [{ arg: 0, expected: word }] }, + { nowSeconds: NOW } + ).terms + ).toEqual(terms); + expect(() => + nativeRuleToTerms( + { ...input, pins: [{ arg: 0, expected: `0x${'ff'.repeat(32)}` }] }, + { nowSeconds: NOW } + ) + ).toThrow(/does not encode/); + }); + + it('offset-form pins must be exact words at a valid offset', () => { + const base: NativeRule = { + agent, + target, + selector: '0xd09de08a', + validUntil: NOW + 10, + }; + expect(() => + nativeRuleToTerms( + { ...base, pins: [{ offset: 3, expected: `0x${'00'.repeat(32)}` }] }, + { nowSeconds: NOW } + ) + ).toThrow(/offset/); + expect(() => + nativeRuleToTerms( + { ...base, pins: [{ offset: 4, expected: '0x01' }] }, + { nowSeconds: NOW } + ) + ).toThrow(/32-byte/); + expect( + nativeRuleToTerms( + { ...base, pins: [{ offset: 36, expected: `0x${'00'.repeat(31)}01` }] }, + { nowSeconds: NOW } + ).terms.pins + ).toEqual([{ offset: 36, expected: `0x${'00'.repeat(31)}01` }]); + }); + + it('applies confirmed zero PC defaults and independent token/call defaults', () => { + const { terms } = nativeRuleToTerms( + { + agent, + target, + selector: 'f(uint256)', + validUntil: NOW + 10, + amount: { arg: 0, maxPerCall: BigInt(1) }, + }, + { nowSeconds: NOW } + ); + expect(terms.maxValuePerCall).toBe( + BigInt(0) + ); + expect(terms.maxValueTotal).toBe(BigInt(0)); + expect(terms.maxCalls).toBe(0); + expect(terms.amount.maxTotal).toBe(UINT256_MAX); + }); + + it('rejects ambiguous arg-plus-offset authoring for both pins and amount', () => { + const rule = { agent, target, selector: 'transfer(address,uint256)' as const, validUntil: NOW + 10 }; + expect(() => nativeRuleToTerms({ ...rule, pins: [{ arg: 0, offset: 4, expected: `0x${'00'.repeat(32)}` } as never] }, { nowSeconds: NOW })).toThrow('mutually exclusive'); + expect(() => nativeRuleToTerms({ ...rule, amount: { arg: 1, offset: 36, maxPerCall: BigInt(1) } as never }, { nowSeconds: NOW })).toThrow('mutually exclusive'); + }); + + it('keeps an explicit zero as zero', () => { + const { terms } = nativeRuleToTerms( + { + agent, + target, + selector: 'f(uint256)', + validUntil: NOW + 10, + amount: { arg: 0, maxPerCall: BigInt(1), maxTotal: BigInt(0) }, + }, + { nowSeconds: NOW } + ); + expect(terms.amount.maxTotal).toBe(BigInt(0)); + }); + + it('value-only rules encode the reserved selector and refuse pins/amount', () => { + const { terms } = nativeRuleToTerms( + { agent, target, selector: 'value-only', validUntil: NOW + 10 }, + { nowSeconds: NOW } + ); + expect(terms.selector).toBe(VALUE_ONLY_SELECTOR); + expect(() => + nativeRuleToTerms( + { + agent, + target, + selector: 'value-only', + validUntil: NOW + 10, + pins: [{ arg: 0, expected: agent }], + }, + { nowSeconds: NOW } + ) + ).toThrow(/value-only/); + }); + + it.each([ + ['past expiry', { validUntil: NOW }], + ['zero target', { target: '0x0000000000000000000000000000000000000000' }], + [ + 'too many pins', + { + selector: 'f(uint256)', + pins: Array.from({ length: 9 }, () => ({ + arg: 0, + expected: BigInt(1), + })), + }, + ], + [ + 'pin needs a signature', + { selector: '0x12345678', pins: [{ arg: 0, expected: BigInt(1) }] }, + ], + [ + 'pin on a dynamic argument', + { selector: 'f(bytes)', pins: [{ arg: 0, expected: '0x01' }] }, + ], + [ + 'pin index out of range', + { selector: 'f(uint256)', pins: [{ arg: 1, expected: BigInt(1) }] }, + ], + [ + 'pin value of the wrong type', + { selector: 'f(address)', pins: [{ arg: 0, expected: BigInt(1) }] }, + ], + [ + 'amount on a non-uint', + { selector: 'f(address)', amount: { arg: 0, maxPerCall: BigInt(1) } }, + ], + [ + 'amount also pinned', + { + selector: 'f(uint256)', + pins: [{ arg: 0, expected: BigInt(1) }], + amount: { arg: 0, maxPerCall: BigInt(1) }, + }, + ], + ['negative cap', { maxValuePerCall: BigInt(-1) }], + ['maxCalls beyond uint32', { maxCalls: 2 ** 32 }], + ])('rejects %s before signing', (_name, patch) => { + const rule = { + agent, + target, + selector: 'increment()', + validUntil: NOW + 10, + ...patch, + } as NativeRule; + expect(() => nativeRuleToTerms(rule, { nowSeconds: NOW })).toThrow( + expect.objectContaining({ code: AGENTIC_ERROR_CODE.INVALID_RULE }) + ); + }); + + it('approval policy is external while caller-supplied pins remain ABI-validated', () => { + const base = { agent, target, validUntil: NOW + 10 }; + expect(() => + nativeRuleToTerms( + { ...base, selector: 'approve(address,uint256)' }, + { nowSeconds: NOW } + ) + ).not.toThrow(); + expect(() => + nativeRuleToTerms( + { + ...base, + selector: 'approve(address,uint256)', + pins: [{ arg: 0, expected: agent }], + }, + { nowSeconds: NOW } + ) + ).not.toThrow(); + expect(() => + nativeRuleToTerms( + { + ...base, + selector: + 'permit(address,address,uint256,uint256,uint8,bytes32,bytes32)', + pins: [{ arg: 0, expected: agent }], + }, + { nowSeconds: NOW } + ) + ).not.toThrow(); + }); +}); + +describe('ABI layout offsets', () => { + it('accounts for dynamic heads and multi-word static tuples before the pinned argument', () => { + const dyn = parseSelector('f(bytes,address)'); + expect(argumentOffset(dyn.inputs, 1, 'pin')).toBe(4 + 32); + const tup = parseSelector('f((uint256,uint256),address)'); + expect(headSize(tup.inputs![0])).toBe(64); + expect(argumentOffset(tup.inputs, 1, 'pin')).toBe(4 + 64); + const arr = parseSelector('f(uint256[3],address)'); + expect(argumentOffset(arr.inputs, 1, 'pin')).toBe(4 + 96); + const dynTuple = parseSelector('f((uint256,bytes),address)'); + expect(argumentOffset(dynTuple.inputs, 1, 'pin')).toBe(4 + 32); + }); + + it('rejects pinning a tuple', () => { + const tup = parseSelector('f((uint256,uint256),address)'); + expect(() => argumentOffset(tup.inputs, 0, 'pin')).toThrow(/single-word/); + }); + + it('parses hex, signature and value-only selectors', () => { + expect(parseSelector('0x617BA037').selector).toBe('0x617ba037'); + expect( + parseSelector('supply(address,uint256,address,uint16)').selector + ).toBe('0x617ba037'); + expect(parseSelector('value-only').valueOnly).toBe(true); + expect(() => parseSelector('not a selector' as never)).toThrow(); + }); +}); + +describe('wallet call encoders decode back to the same calls', () => { + const call = { target, value: BigInt(7), data: '0xd09de08a' as Hex }; + + it('execute single uses packed ERC-7579 calldata', () => { + const data = v5.encodeExecute([call]); + const { functionName, args } = decodeFunctionData({ abi: AGW_ABI, data }); + expect(functionName).toBe('execute'); + expect(args[0]).toBe(`0x${'00'.repeat(32)}`); + expect((args[1] as Hex).length).toBe(2 + 2 * (20 + 32 + 4)); + expect(v5.decodeWalletCall(data)).toEqual({ + kind: 'execute', + mode: args[0], + calls: [call], + }); + }); + + it('execute batch uses abi.encode(Execution[])', () => { + const data = v5.encodeExecute([call, { ...call, value: BigInt(0) }]); + const decoded = v5.decodeWalletCall(data); + expect(decoded).toMatchObject({ + kind: 'execute', + mode: `0x01${'00'.repeat(31)}`, + }); + expect((decoded as { calls: unknown[] }).calls).toEqual([ + call, + { ...call, value: BigInt(0) }, + ]); + }); + + it('executeAsAgent carries the rule ID and one packed call', () => { + const id = `0x${'42'.repeat(32)}` as Hex; + expect(v5.decodeWalletCall(v5.encodeExecuteAsAgent(id, call))).toEqual({ + kind: 'executeAsAgent', + rulesId: id, + mode: `0x${'00'.repeat(32)}`, + calls: [call], + }); + }); + + it('unknown calldata is not mistaken for a wallet call', () => { + expect(v5.decodeWalletCall('0xdeadbeef')).toBeNull(); + }); +}); diff --git a/packages/core/src/lib/agentic/__tests__/fake-chain.ts b/packages/core/src/lib/agentic/__tests__/fake-chain.ts new file mode 100644 index 00000000..d56212bf --- /dev/null +++ b/packages/core/src/lib/agentic/__tests__/fake-chain.ts @@ -0,0 +1,415 @@ +/** + * In-memory stand-in for the AGW contract views used by unit tests. It models + * only what the SDK reads (factory registry/prediction, wallet wiring, + * engine enumeration, URP mode/native config, checkpoints and logs), so the + * SDK's own logic — selection, consistency, error mapping — is what is tested. + * Real-contract behaviour is covered by the local harness (__agw-local__). + */ +import { + encodeAbiParameters, + encodeEventTopics, + getAddress, + keccak256, + toBytes, + type AbiEvent, + type Address, + type Hex, + type Log, + type TransactionReceipt, +} from 'viem'; +import { PUSH_NETWORK } from '../../constants/enums'; +import { v5 } from '../contracts/v5'; +import type { ChainReader } from '../contracts/reader'; +import { actionId, configId, deriveWallet } from '../codec/ids'; +import { + registerAgenticGeneration, + resetAgenticGenerations, + type AgenticGeneration, +} from '../deployments'; +import type { NativeConfigRead } from '../contracts/v5'; + +export const ADDR = { + factory: getAddress('0x00000000000000000000000000000000000fac70'), + impl: getAddress('0x00000000000000000000000000000000000001a1'), + engine: getAddress('0x00000000000000000000000000000000000e0e0e'), + policy: getAddress('0x0000000000000000000000000000000000000b01'), + validator: getAddress('0x0000000000000000000000000000000000000a1d'), + gateway: getAddress('0x00000000000000000000000000000000000000c1'), + owner: getAddress('0x00000000000000000000000000000000000000a0'), + agent: getAddress('0x00000000000000000000000000000000000000a9'), + other: getAddress('0x00000000000000000000000000000000000000b9'), + target: getAddress('0x0000000000000000000000000000000000007a76'), +}; + +export const PUSH_NS = 'eip155:42101'; +export const SEPOLIA_NS = 'eip155:11155111'; + +export interface FakeRule { + rulesId: Hex; + agent: Address; + mode: number; // 1 native, 0 universal + chain: string; + actionIds: Hex[]; + native?: Partial; + universal?: { + assets: readonly { + token: Address; + maxPerCall?: bigint; + maxTotal?: bigint; + spent?: bigint; + }[]; + expectedCEA: Address; + maxGasPerCall: bigint; + }; +} + +export interface FakeWallet { + address: Address; + owner: Address; + index: bigint; + label: string; + rules: FakeRule[]; + checkpointCount: bigint; + grantNonce: bigint; + accountId?: string; +} + +export class FakeChain implements ChainReader { + policyVersion = '3.1.0'; + sourceTokens = new Map(); + block = BigInt(100); + wallets = new Map(); + walletCounts = new Map(); + balances = new Map(); + checkpointLogs: Log[] = []; + extraLogs: Log[] = []; + failOn = new Set(); + calls: { functionName: string; blockNumber?: bigint }[] = []; + /** Override the factory's prediction (to simulate derivation drift). */ + predictOverride?: (owner: Address, index: bigint) => Address; + receipts = new Map(); + + addWallet(owner: Address, label: string, rules: FakeRule[] = []): FakeWallet { + const index = this.walletCounts.get(owner.toLowerCase()) ?? BigInt(0); + const address = deriveWallet({ + factory: ADDR.factory, + walletImplementation: ADDR.impl, + owner, + index, + }); + const w: FakeWallet = { + address, + owner, + index, + label, + rules, + checkpointCount: BigInt(0), + grantNonce: BigInt(rules.length), + }; + this.wallets.set(address.toLowerCase(), w); + this.walletCounts.set(owner.toLowerCase(), index + BigInt(1)); + this.extraLogs.push( + log( + ADDR.factory, + v5.events.walletDeployed, + { owner, index, wallet: address }, + { label }, + BigInt(10) + ) + ); + return w; + } + + nativeRule( + agent: Address, + rulesId: Hex, + extra: Partial = {} + ): FakeRule { + return { + rulesId, + agent, + mode: 1, + chain: PUSH_NS, + actionIds: [actionId(ADDR.target, '0xd09de08a')], + native: extra, + }; + } + + async readContract( + args: Parameters[0] + ): Promise { + const fn = args.functionName; + this.calls.push({ functionName: fn, blockNumber: args.blockNumber }); + if (this.failOn.has(fn)) throw new Error(`rpc failure: ${fn}`); + const a = (args.args ?? []) as readonly unknown[]; + const at = args.address.toLowerCase(); + const wallet = this.wallets.get(at); + switch (fn) { + case 'version': + return this.policyVersion; + // factory + case 'walletImplementation': + return ADDR.impl; + case 'walletCount': + return this.walletCounts.get(String(a[0]).toLowerCase()) ?? BigInt(0); + case 'predictWallet': { + const [owner, index] = a as [Address, bigint]; + const count = this.walletCounts.get(owner.toLowerCase()) ?? BigInt(0); + if (index > count) throw new Error('IndexOutOfRange'); + const addr = this.predictOverride + ? this.predictOverride(owner, index) + : deriveWallet({ + factory: ADDR.factory, + walletImplementation: ADDR.impl, + owner, + index, + }); + return [addr, index < count] as const; + } + case 'isWallet': + return this.wallets.has(String(a[0]).toLowerCase()); + case 'indexOf': + return this.wallets.get(String(a[0]).toLowerCase())?.index ?? BigInt(0); + // wallet + case 'factory': + if (!wallet) throw new Error('no factory()'); + return ADDR.factory; + case 'label': + if (!wallet) throw new Error('not a wallet'); + return wallet.label || `AGW ${wallet.index + BigInt(1)}`; + case 'owner': + if (!wallet) throw new Error('not a wallet'); + return wallet.owner; + case 'SESSION_ENGINE': + return ADDR.engine; + case 'RULES_POLICY': + return ADDR.policy; + case 'SESSION_VALIDATOR': + return ADDR.validator; + case 'UNIVERSAL_GATEWAY_PC': + return ADDR.gateway; + case 'accountId': + return wallet?.accountId ?? 'push.agw.1.0.0'; + case 'grantNonce': + return wallet?.grantNonce ?? BigInt(0); + case 'checkpointCount': + return wallet?.checkpointCount ?? BigInt(0); + case 'agentOf': { + const r = wallet?.rules.find((x) => x.rulesId === a[0]); + return r?.agent ?? '0x0000000000000000000000000000000000000000'; + } + // engine + case 'getPermissionIDs': + return (this.wallets.get(String(a[0]).toLowerCase())?.rules ?? []).map( + (r) => r.rulesId + ); + case 'isPermissionEnabled': { + const w = this.wallets.get(String(a[1]).toLowerCase()); + return !!w?.rules.some((r) => r.rulesId === a[0]); + } + case 'getEnabledActions': { + const w = this.wallets.get(String(a[0]).toLowerCase()); + return w?.rules.find((r) => r.rulesId === a[1])?.actionIds ?? []; + } + // policy + case 'getMode': { + const found = this.findConfig(a[0] as Hex, a[1] as Address); + if (!found) + return { + initialized: false, + mode: 0, + vm: 0, + chainHash: `0x${'00'.repeat(32)}`, + }; + return { + initialized: true, + mode: found.rule.mode, + vm: 0, + chainHash: keccak256(toBytes(found.rule.chain)), + }; + } + case 'getNativeConfig': { + const found = this.findConfig(a[0] as Hex, a[1] as Address); + const n = found?.rule.native ?? {}; + return { + initialized: !!found, + validUntil: 2_000_000_000, + target: ADDR.target, + selector: '0xd09de08a', + maxValuePerCall: BigInt(0), + maxValueTotal: BigInt(0), + valueSpent: BigInt(0), + amount: { + enabled: false, + offset: 0, + maxPerCall: BigInt(0), + maxTotal: BigInt(0), + }, + amountSpent: BigInt(0), + maxCalls: 0, + callsUsed: 0, + pins: [], + ...n, + }; + } + case 'getConfig': { + const found = this.findConfig(a[0] as Hex, a[1] as Address); + const u = found?.rule.universal; + return { + initialized: !!found, + validUntil: 2_000_000_000, + expectedCEA: u?.expectedCEA ?? ADDR.other, + assets: (u?.assets ?? [{ token: ADDR.target }]).map((a) => ({ + maxPerCall: BigInt(1000), + maxTotal: BigInt(10000), + spent: BigInt(0), + ...a, + })), + maxGasPerCall: u?.maxGasPerCall ?? BigInt(0), + allowedCalls: [ + { + target: ADDR.target, + selector: '0xd09de08a', + beneficiaryOffset: 0, + hasBeneficiary: false, + maxValue: BigInt(0), + }, + ], + }; + } + case 'SOURCE_CHAIN_NAMESPACE': + return SEPOLIA_NS; + case 'SOURCE_TOKEN_ADDRESS': + return ( + this.sourceTokens.get(args.address.toLowerCase()) ?? args.address + ); + case 'gasTokenPRC20ByChainNamespace': + return getAddress('0x0000000000000000000000000000000000007070'); + case 'balanceOf': + case 'allowance': + return this.balances.get(`${fn}:${at}`) ?? BigInt(0); + default: + throw new Error(`FakeChain: unhandled ${fn}`); + } + } + + private findConfig(id: Hex, account: Address) { + const w = this.wallets.get(account.toLowerCase()); + if (!w) return undefined; + for (const rule of w.rules) { + for (const action of rule.actionIds) { + if (configId(w.address, rule.rulesId, action) === id) + return { rule, action }; + } + } + return undefined; + } + + async getBlockNumber(): Promise { + if (this.failOn.has('getBlockNumber')) + throw new Error('rpc failure: getBlockNumber'); + return this.block; + } + + async getCode(args: { address: Address }): Promise { + return this.wallets.has(args.address.toLowerCase()) ? '0x3d' : undefined; + } + + async getBalance(args: { address: Address }): Promise { + return this.balances.get(`pc:${args.address.toLowerCase()}`) ?? BigInt(0); + } + + async getLogs(args: Parameters[0]): Promise { + if (this.failOn.has('getLogs')) throw new Error('rpc failure: getLogs'); + return [...this.checkpointLogs, ...this.extraLogs].filter( + (l) => + l.address.toLowerCase() === args.address.toLowerCase() && + BigInt(l.blockNumber ?? BigInt(0)) >= args.fromBlock && + BigInt(l.blockNumber ?? BigInt(0)) <= args.toBlock + ); + } + + async getTransactionReceipt(args: { + hash: Hex; + }): Promise { + const r = this.receipts.get(args.hash); + if (!r) throw new Error(`no receipt ${args.hash}`); + return r; + } +} + +let logIndex = 0; +export function log( + address: Address, + event: AbiEvent, + indexed: Record, + data: Record, + blockNumber: bigint, + txHash: Hex = `0x${'ab'.repeat(32)}`, + transactionIndex = 0 +): Log { + const topics = encodeEventTopics({ + abi: [event], + eventName: event.name, + args: indexed, + } as never); + const nonIndexed = event.inputs.filter((i) => !('indexed' in i && i.indexed)); + return { + address, + topics: topics as [Hex, ...Hex[]], + data: encodeAbiParameters( + nonIndexed, + nonIndexed.map((i) => data[i.name as string]) as never + ), + blockNumber, + transactionHash: txHash, + transactionIndex, + logIndex: logIndex++, + blockHash: `0x${'cd'.repeat(32)}`, + removed: false, + } as Log; +} + +export function checkpointLog( + wallet: Address, + seq: number, + kind: number, + block: bigint, + txIndex = 0 +): Log { + return log( + wallet, + v5.events.checkpointed, + { seq: BigInt(seq) }, + { kind, ref: `0x${'11'.repeat(32)}`, blockNumber: block }, + block, + `0x${seq.toString(16).padStart(64, '0')}`, + txIndex + ); +} + +export function registerFakeGeneration( + network: PUSH_NETWORK = PUSH_NETWORK.TESTNET_DONUT +): AgenticGeneration { + resetAgenticGenerations(); + return registerAgenticGeneration({ + id: 'v5', + sourceCommit: '2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb', + network, + advertised: false, + addresses: { + factory: ADDR.factory, + walletImplementation: ADDR.impl, + sessionEngine: ADDR.engine, + rulesPolicy: ADDR.policy, + sessionValidator: ADDR.validator, + gateway: ADDR.gateway, + }, + startBlock: BigInt(1), + accountId: 'push.agw.1.0.0', + }); +} + +export function ruleId(n: number): Hex { + return `0x${n.toString(16).padStart(64, '0')}`; +} diff --git a/packages/core/src/lib/agentic/__tests__/labels.spec.ts b/packages/core/src/lib/agentic/__tests__/labels.spec.ts new file mode 100644 index 00000000..9688dc4b --- /dev/null +++ b/packages/core/src/lib/agentic/__tests__/labels.spec.ts @@ -0,0 +1,115 @@ +import { decodeFunctionData, encodeErrorResult } from 'viem'; +import { PUSH_NETWORK } from '../../constants/enums'; +import { PROGRESS_HOOK } from '../../progress-hook/progress-hook.types'; +import { v5 } from '../contracts/v5'; +import { currentGeneration, resetAgenticGenerations } from '../deployments'; +import { AGENTIC_ERROR_CODE } from '../errors'; +import { createWallet } from '../management/create'; +import { assertLabel } from '../management/label'; +import { setLabel } from '../management/rules-write'; +import { decodeAgwErrorData } from '../revert'; +import { AgenticWalletHandle } from '../wallet'; +import { ADDR, FakeChain, registerFakeGeneration } from './fake-chain'; +import { mockRuntime } from './mock-runtime'; + +beforeEach(() => { + registerFakeGeneration(); +}); +afterEach(resetAgenticGenerations); +const gen = () => currentGeneration(PUSH_NETWORK.TESTNET_DONUT); + +describe('v5 wallet labels', () => { + it('allows empty, 64 ASCII bytes and sixteen four-byte emoji without altering the label', () => { + for (const label of ['', 'a'.repeat(64), '🙂'.repeat(16), ' label ']) { + expect(() => assertLabel(label)).not.toThrow(); + } + }); + + it('refuses non-strings and overlong UTF-8 labels before a create reads or signs', async () => { + const chain = new FakeChain(); + const rt = mockRuntime(chain, { signer: ADDR.owner }); + for (const label of [null, 123, 'a'.repeat(65), '🙂'.repeat(17)]) { + await expect( + createWallet(rt, label as never, { rules: [] }) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.INVALID_RULE }); + } + expect(rt.executeMock).not.toHaveBeenCalled(); + expect(chain.calls).toEqual([]); + }); + + it('encodes a reset through the owner door and forwards the per-call progress hook', async () => { + const chain = new FakeChain(); + const w = chain.addWallet(ADDR.owner, 'custom'); + const rt = mockRuntime(chain, { signer: ADDR.owner }); + const hook = jest.fn(); + const tx = await new AgenticWalletHandle(rt, w.address).setLabel('', { + progressHook: hook, + }); + const sent = rt.executeMock.mock.calls[0][0]; + expect(sent).toMatchObject({ to: w.address, value: BigInt(0) }); + const outer = v5.decodeWalletCall(sent.data); + expect(outer?.kind).toBe('execute'); + if (outer?.kind !== 'execute') throw new Error('expected owner execute'); + expect(outer.calls).toHaveLength(1); + expect(outer.calls[0].target).toBe(w.address); + expect( + decodeFunctionData({ abi: v5.abis.wallet, data: outer.calls[0].data }) + ).toMatchObject({ functionName: 'setLabel', args: [''] }); + expect(hook).toHaveBeenCalledWith( + expect.objectContaining({ id: PROGRESS_HOOK.AGENTIC_TX_199_01 }) + ); + expect(tx.hash).toBeTruthy(); + }); + + it('refuses non-owner and read-only renames before signing', async () => { + const chain = new FakeChain(); + const w = chain.addWallet(ADDR.owner, 'x'); + const stranger = mockRuntime(chain, { signer: ADDR.agent }); + await expect( + setLabel(stranger, gen(), w.address, 'y') + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.NOT_WALLET_OWNER }); + const readOnly = mockRuntime(chain, { signer: ADDR.owner, readOnly: true }); + await expect( + setLabel(readOnly, gen(), w.address, 'y') + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.READ_ONLY }); + expect(stranger.executeMock).not.toHaveBeenCalled(); + expect(readOnly.executeMock).not.toHaveBeenCalled(); + }); + + it('uses the same owner door for an external owner identity', async () => { + const chain = new FakeChain(); + const w = chain.addWallet(ADDR.owner, 'x'); + const rt = mockRuntime(chain, { + signer: ADDR.owner, + signerIsPushNative: () => false, + }); + await setLabel(rt, gen(), w.address, 'UEA label'); + expect( + v5.decodeWalletCall(rt.executeMock.mock.calls[0][0].data)?.kind + ).toBe('execute'); + }); + + it('maps the new contract length error and emits a failed operation hook', async () => { + const chain = new FakeChain(); + const w = chain.addWallet(ADDR.owner, 'x'); + const data = encodeErrorResult({ + abi: v5.abis.wallet, + errorName: 'LabelTooLong', + args: [BigInt(65)], + }); + expect(decodeAgwErrorData(data)).toMatchObject({ + name: 'LabelTooLong', + decoded: '["65"]', + }); + const rt = mockRuntime(chain, { + signer: ADDR.owner, + execute: async () => { + throw new Error(`reverted ${data}`); + }, + }); + await expect(setLabel(rt, gen(), w.address, 'valid')).rejects.toMatchObject( + { decodedError: { name: 'LabelTooLong' } } + ); + expect(rt.events.at(-1)?.id).toBe(PROGRESS_HOOK.AGENTIC_TX_199_02); + }); +}); diff --git a/packages/core/src/lib/agentic/__tests__/management.spec.ts b/packages/core/src/lib/agentic/__tests__/management.spec.ts new file mode 100644 index 00000000..d9726b6a --- /dev/null +++ b/packages/core/src/lib/agentic/__tests__/management.spec.ts @@ -0,0 +1,685 @@ +import { + decodeFunctionData, + encodeErrorResult, + type Hex, + type Log, + type TransactionReceipt, +} from 'viem'; +import { PUSH_NETWORK } from '../../constants/enums'; +import { PushChainBatchExecutionError } from '../../orchestrator/internals/errors'; +import type { MultiCall } from '../../orchestrator/orchestrator.types'; +import { PROGRESS_HOOK } from '../../progress-hook/progress-hook.types'; +import { currentGeneration, resetAgenticGenerations } from '../deployments'; +import { + AGW_ABI, + AGW_FACTORY_ABI, + UNIVERSAL_RULES_POLICY_ABI, +} from '../contracts/abi/v5'; +import { v5 } from '../contracts/v5'; +import { deriveWallet, rulesId as computeRulesId } from '../codec/ids'; +import { AGENTIC_ERROR_CODE } from '../errors'; +import { createWallet } from '../management/create'; +import { addRules, revokeRules, updateRules } from '../management/rules-write'; +import type { NativeRule } from '../agentic.types'; +import { + ADDR, + FakeChain, + PUSH_NS, + log, + registerFakeGeneration, + ruleId, +} from './fake-chain'; +import { fakeResponse, mockRuntime } from './mock-runtime'; + +const NOW = 1_700_000_000; +const rule = (agent = ADDR.agent): NativeRule => ({ + agent, + target: ADDR.target, + selector: 'increment()', + validUntil: NOW + 100, +}); +const granted = (wallet: `0x${string}`, id: Hex, block = BigInt(101)) => + log( + wallet, + v5.events.rulesGranted, + { rulesId: id, chainHash: `0x${'00'.repeat(32)}` }, + { mode: 1, chainNamespace: PUSH_NS }, + block + ); +const revoked = (wallet: `0x${string}`, id: Hex) => + log(wallet, v5.events.rulesRevoked, { rulesId: id }, {}, BigInt(101)); + +function withLogs(logs: Log[], over = {}) { + const r = fakeResponse(over); + const base = r.wait; + r.wait = async () => ({ ...(await base()), logs }); + return r; +} + +beforeEach(() => registerFakeGeneration()); +afterEach(() => resetAgenticGenerations()); + +describe('agentic.create', () => { + const nextWallet = deriveWallet({ + factory: ADDR.factory, + walletImplementation: ADDR.impl, + owner: ADDR.owner, + index: 0, + }); + const ids = [ruleId(0), ruleId(1)].map((_, i) => + computeRulesId({ + validator: ADDR.validator, + agent: i === 0 ? ADDR.agent : ADDR.other, + grantNonce: BigInt(i), + }) + ); + + it('validates first, then sends deploy + grants in input order and returns receipt IDs', async () => { + const fake = new FakeChain(); + const rt = mockRuntime(fake, { + signer: ADDR.owner, + execute: (async () => + withLogs([ + log( + ADDR.factory, + v5.events.walletDeployed, + { owner: ADDR.owner, index: BigInt(0), wallet: nextWallet }, + { label: 'ops' }, + BigInt(101) + ), + granted(nextWallet, ids[0]), + granted(nextWallet, ids[1]), + ])) as never, + }); + const execute = jest.spyOn(rt, 'execute'); + const perCall = jest.fn(); + const res = await createWallet(rt, 'ops', { + rules: [rule(), rule(ADDR.other)], + progressHook: perCall, + }); + expect(res).toMatchObject({ wallet: nextWallet, index: 0, rulesIds: ids }); + const calls = (execute.mock.calls[0][0] as { data: MultiCall[] }).data; + expect(calls.map((c) => c.to)).toEqual([ + ADDR.factory, + nextWallet, + nextWallet, + ]); + expect( + decodeFunctionData({ abi: AGW_ABI, data: calls[1].data }).functionName + ).toBe('grantRules'); + expect(rt.events.map((e) => e.id)).toEqual([ + PROGRESS_HOOK.AGENTIC_TX_101, + PROGRESS_HOOK.AGENTIC_TX_102, + PROGRESS_HOOK.AGENTIC_TX_104, + PROGRESS_HOOK.AGENTIC_TX_199_01, + ]); + expect(rt.events.find((e) => e.id === 'AGENTIC-TX-103')).toBeUndefined(); + expect(perCall).toHaveBeenCalledTimes(4); + }); + + it('a bare wallet is one deployWallet call, no funding', async () => { + const fake = new FakeChain(); + const rt = mockRuntime(fake, { + signer: ADDR.owner, + execute: (async (p: { to: string; data: Hex; value: bigint }) => { + expect(p.to).toBe(ADDR.factory); + expect(p.value).toBe(BigInt(0)); + return withLogs([ + log( + ADDR.factory, + v5.events.walletDeployed, + { owner: ADDR.owner, index: BigInt(0), wallet: nextWallet }, + { label: '' }, + BigInt(101) + ), + ]); + }) as never, + }); + expect((await createWallet(rt, '', { rules: [] })).rulesIds).toEqual([]); + }); + + it('invalid input never reaches the signer', async () => { + const fake = new FakeChain(); + const rt = mockRuntime(fake, { signer: ADDR.owner }); + await expect( + createWallet(rt, 'x', { rules: [rule(ADDR.owner)] }) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.AGENT_IS_OWNER }); + await expect( + createWallet(rt, 'x', undefined as never) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.INVALID_RULE }); + await expect( + createWallet( + mockRuntime(fake, { signer: ADDR.owner, readOnly: true }), + 'x', + { rules: [] } + ) + ).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.READ_ONLY, + }); + expect(rt.executeMock).not.toHaveBeenCalled(); + }); + it('refuses a changed URP version before grant signing', async () => { + const fake = new FakeChain(); + fake.policyVersion = '3.2.0'; + const rt = mockRuntime(fake, { signer: ADDR.owner }); + await expect( + createWallet(rt, 'version', { rules: [rule()] }) + ).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.GENERATION_UNSUPPORTED, + }); + expect(rt.executeMock).not.toHaveBeenCalled(); + }); + + it('a different wallet in the receipt is an INDEX_RACE with full details', async () => { + const fake = new FakeChain(); + const elsewhere = deriveWallet({ + factory: ADDR.factory, + walletImplementation: ADDR.impl, + owner: ADDR.owner, + index: 1, + }); + const rt = mockRuntime(fake, { + signer: ADDR.owner, + execute: (async () => + withLogs([ + log( + ADDR.factory, + v5.events.walletDeployed, + { owner: ADDR.owner, index: BigInt(1), wallet: elsewhere }, + { label: '' }, + BigInt(101) + ), + ])) as never, + }); + await expect(createWallet(rt, '', { rules: [] })).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.INDEX_RACE, + }); + }); + + it('IDs that differ from the input order are a RECEIPT_MISMATCH, not a silent reorder', async () => { + const fake = new FakeChain(); + const rt = mockRuntime(fake, { + signer: ADDR.owner, + execute: (async () => + withLogs([ + log( + ADDR.factory, + v5.events.walletDeployed, + { owner: ADDR.owner, index: BigInt(0), wallet: nextWallet }, + { label: '' }, + BigInt(101) + ), + granted(nextWallet, ids[1]), + granted(nextWallet, ids[0]), + ])) as never, + }); + await expect( + createWallet(rt, '', { rules: [rule(), rule(ADDR.other)] }) + ).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.RECEIPT_MISMATCH, + }); + }); + + const receipt = (logs: Log[], status: 'success' | 'reverted' = 'success') => + ({ status, logs } as unknown as TransactionReceipt); + + it('a sequential failure after deployment is CREATE_PARTIAL; what committed comes from this call’s receipts', async () => { + const fake = new FakeChain(); + const h1 = `0x${'01'.repeat(32)}` as Hex; + const h2 = `0x${'02'.repeat(32)}` as Hex; + fake.receipts.set( + h1, + receipt([ + log( + ADDR.factory, + v5.events.walletDeployed, + { owner: ADDR.owner, index: BigInt(0), wallet: nextWallet }, + { label: 'ops' }, + BigInt(101) + ), + ]) + ); + fake.receipts.set(h2, receipt([granted(nextWallet, ids[0])])); + const rt = mockRuntime(fake, { + signer: ADDR.owner, + execute: (async () => { + throw new PushChainBatchExecutionError('grant 2 reverted', [h1, h2]); + }) as never, + }); + const err = await createWallet(rt, 'ops', { + rules: [rule(), rule(ADDR.other)], + }).catch((e) => e); + expect(err.code).toBe(AGENTIC_ERROR_CODE.CREATE_PARTIAL); + expect(err.details).toMatchObject({ + wallet: nextWallet, + walletDeployed: true, + grantedRulesIds: [ids[0]], + confirmedHashes: [h1, h2], + }); + expect(err.hint).toMatch(/rules\.add/); + expect(rt.events.at(-1)?.id).toBe(PROGRESS_HOOK.AGENTIC_TX_199_02); + }); + + it('a pending hash keeps an unconfirmed deployment unknown', async () => { + const fake = new FakeChain(); + const rt = mockRuntime(fake, { + signer: ADDR.owner, + execute: (async () => { + throw new PushChainBatchExecutionError( + 'timed out', + [], + `0x${'03'.repeat(32)}` + ); + }) as never, + }); + const err = await createWallet(rt, 'ops', { rules: [rule()] }).catch( + (e) => e + ); + expect(err.details).toMatchObject({ + walletDeployed: 'unknown', + pendingHash: `0x${'03'.repeat(32)}`, + }); + expect(err.hint).toMatch(/Do not retry/); + }); + + it('failed recovery reads report unknown state, never "not deployed"', async () => { + const fake = new FakeChain(); + const rt = mockRuntime(fake, { + signer: ADDR.owner, + execute: (async () => { + fake.addWallet(ADDR.owner, 'committed'); + throw new PushChainBatchExecutionError('grant failed', [ + `0x${'11'.repeat(32)}`, + ]); + }) as never, + }); + const err = await createWallet(rt, 'review', { rules: [rule()] }).catch( + (e) => e + ); + expect(err.code).toBe('CREATE_PARTIAL'); + expect(err.details.walletDeployed).toBe('unknown'); + expect(err.details.recoveryError).toBeTruthy(); + expect(err.hint).toMatch(/Do not retry/); + }); + + it('a receipt that cannot be read after submission keeps the hash and reports unknown state', async () => { + const fake = new FakeChain(); + const rt = mockRuntime(fake, { + signer: ADDR.owner, + execute: (async () => { + const r = fakeResponse({ hash: `0x${'44'.repeat(32)}` }); + r.wait = async () => { + throw new Error('rpc down'); + }; + return r; + }) as never, + }); + const err = await createWallet(rt, 'x', { rules: [] }).catch((e) => e); + expect(err.code).toBe(AGENTIC_ERROR_CODE.CREATE_PARTIAL); + expect(err.details).toMatchObject({ + walletDeployed: 'unknown', + submitted: { txHash: `0x${'44'.repeat(32)}` }, + }); + }); + + it('the deploy is index-bound: a raced slot reverts and is reported as INDEX_RACE with nothing committed', async () => { + const fake = new FakeChain(); + const raceData = encodeErrorResult({ + abi: AGW_FACTORY_ABI, + errorName: 'IndexMismatch', + args: [BigInt(1), BigInt(0)], + }); + const rt = mockRuntime(fake, { + signer: ADDR.owner, + execute: (async (p: { data: MultiCall[] }) => { + const deploy = decodeFunctionData({ + abi: AGW_FACTORY_ABI, + data: p.data[0].data, + }); + expect(deploy.functionName).toBe('deployWalletWithSig'); + expect( + (deploy.args[0] as { index: bigint; wallet: string }).index + ).toBe(BigInt(0)); + expect((deploy.args[0] as { wallet: string }).wallet).toBe(nextWallet); + throw new Error( + `Execution reverted with reason: custom error ${raceData.slice( + 0, + 10 + )}: ${raceData.slice(10)}.` + ); + }) as never, + }); + const err = await createWallet(rt, 'x', { rules: [rule()] }).catch( + (e) => e + ); + expect(err.code).toBe(AGENTIC_ERROR_CODE.INDEX_RACE); + expect(err.details).toMatchObject({ committed: false }); + }); + + it('a generic send error is still identified as a race when the fresh slot label proves another create won', async () => { + const fake = new FakeChain(); + const rt = mockRuntime(fake, { + signer: ADDR.owner, + execute: (async () => { + const winner = fake.addWallet(ADDR.owner, 'competing-create'); + winner.label = 'this-create'; // mutable view cannot erase the deploy evidence + throw new Error('opaque sender failure'); + }) as never, + }); + const err = await createWallet(rt, 'this-create', { + rules: [rule()], + }).catch((e) => e); + expect(err).toMatchObject({ + code: AGENTIC_ERROR_CODE.INDEX_RACE, + details: { + wallet: nextWallet, + index: 0, + committed: false, + competingLabel: 'competing-create', + }, + }); + }); + + it('a later rename alone does not establish a competing creation', async () => { + const fake = new FakeChain(); + const failure = new Error('opaque sender failure'); + const rt = mockRuntime(fake, { + signer: ADDR.owner, + execute: (async () => { + const w = fake.addWallet(ADDR.owner, 'this-create'); + w.label = 'renamed-after-deploy'; + throw failure; + }) as never, + }); + await expect(createWallet(rt, 'this-create', { rules: [rule()] })).rejects.toBe(failure); + }); + + it('a slot that is already deployed is refused before signing', async () => { + const fake = new FakeChain(); + fake.predictOverride = (owner, index) => + deriveWallet({ + factory: ADDR.factory, + walletImplementation: ADDR.impl, + owner, + index, + }); + const w = fake.addWallet(ADDR.owner, 'a'); + fake.walletCounts.set(ADDR.owner.toLowerCase(), BigInt(0)); // stale count pointing at a deployed slot + void w; + const rt = mockRuntime(fake, { signer: ADDR.owner }); + await expect(createWallet(rt, '', { rules: [] })).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.INDEX_RACE, + }); + expect(rt.executeMock).not.toHaveBeenCalled(); + }); +}); + +describe('rules.add / rules.revoke', () => { + const gen = () => currentGeneration(PUSH_NETWORK.TESTNET_DONUT); + + it('add: owner-only, same-agent grants allowed, IDs from the grant nonce', async () => { + const fake = new FakeChain(); + const w = fake.addWallet(ADDR.owner, 'w', [ + fake.nativeRule(ADDR.agent, ruleId(1)), + ]); + w.grantNonce = BigInt(4); + const expected = computeRulesId({ + validator: ADDR.validator, + agent: ADDR.agent, + grantNonce: BigInt(4), + }); + const stranger = mockRuntime(fake, { signer: ADDR.other }); + await expect( + addRules(stranger, gen(), w.address, [rule(ADDR.other)]) + ).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.NOT_WALLET_OWNER, + }); + const rt = mockRuntime(fake, { + signer: ADDR.owner, + execute: (async () => withLogs([granted(w.address, expected)])) as never, + }); + expect( + (await addRules(rt, gen(), w.address, [rule(ADDR.agent)])).rulesIds + ).toEqual([expected]); + }); + + it('add: several rules are one atomic owner execute batch (one signature on any signer)', async () => { + const fake = new FakeChain(); + const w = fake.addWallet(ADDR.owner, 'w'); + const ids = [ADDR.agent, ADDR.other].map((agent, i) => + computeRulesId({ + validator: ADDR.validator, + agent, + grantNonce: BigInt(i), + }) + ); + const rt = mockRuntime(fake, { + signer: ADDR.owner, + execute: (async () => + withLogs([ + granted(w.address, ids[0]), + granted(w.address, ids[1]), + ])) as never, + }); + const exec = jest.spyOn(rt, 'execute'); + expect( + (await addRules(rt, gen(), w.address, [rule(), rule(ADDR.other)])) + .rulesIds + ).toEqual(ids); + const sent = exec.mock.calls[0][0] as { to: string; data: Hex }; + expect(Array.isArray(sent.data)).toBe(false); + const outer = v5.decodeWalletCall(sent.data) as { + kind: string; + calls: { target: string; data: Hex }[]; + }; + expect(outer.kind).toBe('execute'); + expect( + outer.calls.map( + (c) => decodeFunctionData({ abi: AGW_ABI, data: c.data }).functionName + ) + ).toEqual(['grantRules', 'grantRules']); + }); + + it('revoke: bare and empty are refused; unknown IDs fail before signing; several IDs are one atomic owner execute', async () => { + const fake = new FakeChain(); + const w = fake.addWallet(ADDR.owner, 'w', [ + fake.nativeRule(ADDR.agent, ruleId(1)), + fake.nativeRule(ADDR.other, ruleId(2)), + ]); + const rt = mockRuntime(fake, { + signer: ADDR.owner, + execute: (async () => + withLogs([ + revoked(w.address, ruleId(1)), + revoked(w.address, ruleId(2)), + ])) as never, + }); + const exec = jest.spyOn(rt, 'execute'); + for (const bad of [undefined, [], {}, { all: false }]) { + await expect( + revokeRules(rt, gen(), w.address, bad as never) + ).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.REVOKE_NEEDS_TARGET, + }); + } + await expect( + revokeRules(rt, gen(), w.address, [ruleId(9)]) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.RULE_NOT_FOUND }); + expect(exec).not.toHaveBeenCalled(); + await revokeRules(rt, gen(), w.address, [ruleId(1), ruleId(2)]); + const sent = exec.mock.calls[0][0] as { to: string; data: Hex }; + expect(sent.to).toBe(w.address); + const decoded = v5.decodeWalletCall(sent.data) as { + kind: string; + calls: { target: string; data: Hex }[]; + }; + expect(decoded.kind).toBe('execute'); + expect( + decoded.calls.map( + (c) => decodeFunctionData({ abi: AGW_ABI, data: c.data }).functionName + ) + ).toEqual(['revokeRules', 'revokeRules']); + await revokeRules(rt, gen(), w.address, { all: true }); + expect( + decodeFunctionData({ + abi: AGW_ABI, + data: (exec.mock.calls[1][0] as { data: Hex }).data, + }).functionName + ).toBe('revokeAllRules'); + }); +}); + +describe('rules.update — one owner batch: assert → revoke → grant', () => { + const gen = () => currentGeneration(PUSH_NETWORK.TESTNET_DONUT); + + it('builds exactly one execute(batch) with the observed spend asserted per pair', async () => { + const fake = new FakeChain(); + const w = fake.addWallet(ADDR.owner, 'w', [ + fake.nativeRule(ADDR.agent, ruleId(1), { + valueSpent: BigInt(3), + amountSpent: BigInt(4), + callsUsed: 5, + }), + ]); + w.grantNonce = BigInt(2); + const newId = computeRulesId({ + validator: ADDR.validator, + agent: ADDR.agent, + grantNonce: BigInt(2), + }); + const rt = mockRuntime(fake, { + signer: ADDR.owner, + execute: (async () => + withLogs([ + revoked(w.address, ruleId(1)), + granted(w.address, newId), + ])) as never, + }); + const exec = jest.spyOn(rt, 'execute'); + const res = await updateRules(rt, gen(), w.address, { + rules: [{ rulesId: ruleId(1), rule: rule() }], + }); + expect(res.rules).toEqual([{ rulesId: newId, replaced: ruleId(1) }]); + expect(exec).toHaveBeenCalledTimes(1); + const sent = exec.mock.calls[0][0] as { to: string; data: Hex }; + expect(Array.isArray(sent.data)).toBe(false); // never a sequential multi-tx batch + const outer = v5.decodeWalletCall(sent.data) as { + kind: string; + mode: Hex; + calls: { target: string; data: Hex }[]; + }; + expect(outer.kind).toBe('execute'); + expect(outer.calls.map((c) => c.target)).toEqual([ + ADDR.policy, + w.address, + w.address, + ]); + const assertion = decodeFunctionData({ + abi: UNIVERSAL_RULES_POLICY_ABI, + data: outer.calls[0].data, + }); + expect(assertion.functionName).toBe('assertSpent'); + expect(assertion.args.slice(1)).toEqual([ + w.address, + BigInt(3), + BigInt(4), + 5, + ]); + expect( + outer.calls + .slice(1) + .map( + (c) => decodeFunctionData({ abi: AGW_ABI, data: c.data }).functionName + ) + ).toEqual(['revokeRules', 'grantRules']); + }); + + it('universal replacement asserts every asset in stored order before revoke/grant', async () => { + const fake = new FakeChain(); + const w = fake.addWallet(ADDR.owner, 'w', [ + { + ...fake.nativeRule(ADDR.agent, ruleId(1)), + mode: 0, + chain: 'eip155:11155111', + universal: { + expectedCEA: ADDR.other, + maxGasPerCall: BigInt(10), + assets: [ + { token: ADDR.target, spent: BigInt(4) }, + { token: ADDR.other, spent: BigInt(7) }, + ], + }, + }, + ]); + const next = computeRulesId({ + validator: ADDR.validator, + agent: ADDR.agent, + grantNonce: BigInt(1), + }); + const rt = mockRuntime(fake, { + signer: ADDR.owner, + execute: (async () => + withLogs([ + revoked(w.address, ruleId(1)), + granted(w.address, next), + ])) as never, + }); + const exec = jest.spyOn(rt, 'execute'); + await updateRules(rt, gen(), w.address, { + rules: [{ rulesId: ruleId(1), rule: rule() }], + }); + const data = (exec.mock.calls[0][0] as { data: Hex }).data; + const outer = v5.decodeWalletCall(data) as { calls: { data: Hex }[] }; + const assertion = decodeFunctionData({ + abi: UNIVERSAL_RULES_POLICY_ABI, + data: outer.calls[0].data, + }); + expect(assertion.args.slice(1)).toEqual([ + w.address, + [BigInt(4), BigInt(7)], + ]); + expect( + outer.calls + .slice(1) + .map( + (c) => decodeFunctionData({ abi: AGW_ABI, data: c.data }).functionName + ) + ).toEqual(['revokeRules', 'grantRules']); + }); + + it('replacement may name another live agent, but may not repeat an old ID', async () => { + const fake = new FakeChain(); + const w = fake.addWallet(ADDR.owner, 'w', [ + fake.nativeRule(ADDR.agent, ruleId(1)), + fake.nativeRule(ADDR.other, ruleId(2)), + ]); + const next = computeRulesId({ + validator: ADDR.validator, + agent: ADDR.other, + grantNonce: BigInt(2), + }); + const rt = mockRuntime(fake, { + signer: ADDR.owner, + execute: (async () => + withLogs([ + revoked(w.address, ruleId(1)), + granted(w.address, next), + ])) as never, + }); + expect( + ( + await updateRules(rt, gen(), w.address, { + rules: [{ rulesId: ruleId(1), rule: rule(ADDR.other) }], + }) + ).rules[0].rulesId + ).toBe(next); + await expect( + updateRules(rt, gen(), w.address, { + rules: [ + { rulesId: ruleId(1), rule: rule() }, + { rulesId: ruleId(1), rule: rule() }, + ], + }) + ).rejects.toThrow(/same old rule twice/); + }); +}); diff --git a/packages/core/src/lib/agentic/__tests__/mock-runtime.ts b/packages/core/src/lib/agentic/__tests__/mock-runtime.ts new file mode 100644 index 00000000..63dec705 --- /dev/null +++ b/packages/core/src/lib/agentic/__tests__/mock-runtime.ts @@ -0,0 +1,102 @@ +import type { Address, Hex } from 'viem'; +import { CHAIN, PUSH_NETWORK } from '../../constants/enums'; +import type { UniversalTxResponse } from '../../orchestrator/orchestrator.types'; +import type { ProgressEvent } from '../../progress-hook/progress-hook.types'; +import type { AgenticRuntime } from '../runtime'; +import { ADDR, FakeChain, PUSH_NS } from './fake-chain'; + +export interface MockRuntime extends AgenticRuntime { + executeMock: jest.Mock; + atomicMock: jest.Mock; + events: ProgressEvent[]; + perCallEvents: ProgressEvent[]; + fake: FakeChain; +} + +/** A response shaped like core's R1 response for a call to `to`. */ +export function fakeResponse(over: Partial = {}): UniversalTxResponse { + const resp = { + hash: `0x${'aa'.repeat(32)}`, + origin: `eip155:42101:${ADDR.agent}`, + blockNumber: BigInt(101), + blockHash: '0x', + transactionIndex: 0, + chainId: '42101', + from: ADDR.agent, + to: ADDR.target, + nonce: 1, + data: '0x', + value: BigInt(0), + gasLimit: BigInt(21000), + accessList: [], + wait: async () => ({ + hash: resp.hash, + blockNumber: BigInt(101), + blockHash: '0x', + transactionIndex: 0, + from: resp.from, + to: resp.to, + contractAddress: null, + gasPrice: BigInt(0), + gasUsed: BigInt(0), + cumulativeGasUsed: BigInt(0), + logs: [], + logsBloom: '0x', + status: 1 as const, + raw: { from: resp.from, to: resp.to }, + }), + progressHook: () => undefined, + type: '2', + typeVerbose: 'eip1559', + atomic: true, + signature: { r: '0x', s: '0x', v: 0 }, + ...over, + } as unknown as UniversalTxResponse; + return resp; +} + +export function mockRuntime( + fake: FakeChain, + over: Partial & { signer?: Address; readOnly?: boolean } = {} +): MockRuntime { + const events: ProgressEvent[] = []; + const perCallEvents: ProgressEvent[] = []; + const executeMock = jest.fn(async (params: { to: string; data?: Hex }) => + fakeResponse({ to: params.to, data: (params.data as string) ?? '0x' }) + ); + const atomicMock = jest.fn(async (params: { to: string }) => fakeResponse({ to: params.to })); + const signer = over.signer ?? ADDR.agent; + const rt: MockRuntime = { + network: PUSH_NETWORK.TESTNET_DONUT, + pushChainNamespace: PUSH_NS, + reader: fake, + isReadOnly: over.readOnly ?? false, + signerPushAccount: () => signer, + signerOrigin: () => ({ chain: CHAIN.PUSH_TESTNET_DONUT, address: signer }), + signerIsPushNative: () => true, + execute: executeMock as unknown as AgenticRuntime['execute'], + executeAtomicBatch: atomicMock as unknown as AgenticRuntime['executeAtomicBatch'], + emit: (event, perCall) => { + events.push(event); + if (perCall) { + perCallEvents.push(event); + perCall(event); + } + }, + signerAccountDeployed: async () => true, + signerBalance: async () => BigInt(10) ** BigInt(20), + getGasPrice: async () => BigInt(1), + quoteOutbound: async () => ({ protocolFee: BigInt(100), nativeValueForGas: BigInt(1000), gasLimitUsed: BigInt(200_000) }), + resolveCEA: async () => ({ cea: '0x000000000000000000000000000000000000CeA1' as Address, isDeployed: true }), + resolvePrc20: () => '0x0000000000000000000000000000000000007070' as Address, + nowSeconds: () => 1_700_000_000, + ...over, + executeMock, + atomicMock, + events, + perCallEvents, + fake, + }; + if (over.execute) rt.execute = over.execute; + return rt; +} diff --git a/packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts b/packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts new file mode 100644 index 00000000..ab65c14f --- /dev/null +++ b/packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts @@ -0,0 +1,119 @@ +import { encodeAbiParameters, type Hex } from 'viem'; +import { CHAIN, PUSH_NETWORK } from '../../constants/enums'; +import { PUSH_BATCH_EXECUTOR_ADDRESS } from '../../constants/chain'; +import { convertExecutorToOrigin } from '../../universal/account/account'; +import { adaptTrackedResponse } from '../response'; +import { v5, UEA_MULTICALL_PREFIX } from '../contracts/v5'; +import { resetAgenticGenerations } from '../deployments'; +import { ADDR, FakeChain, registerFakeGeneration, ruleId } from './fake-chain'; +import { fakeResponse, mockRuntime } from './mock-runtime'; + +jest.mock('../../universal/account/account', () => ({ + convertExecutorToOrigin: jest.fn(), +})); +afterEach(() => { + resetAgenticGenerations(); + jest.clearAllMocks(); +}); + +function fixture() { + registerFakeGeneration(); + const fake = new FakeChain(); + const wallet = fake.addWallet(ADDR.owner, 'batch'); + const actions = [ + { target: ADDR.target, value: BigInt(0), data: '0xd09de08a' as Hex }, + { target: ADDR.target, value: BigInt(2), data: '0xd09de08a' as Hex }, + ]; + const outer = actions.map((c) => ({ + target: wallet.address, + value: BigInt(0), + data: v5.encodeExecuteAsAgent(ruleId(1), c), + })); + const runtime = mockRuntime(fake); + return { fake, wallet, actions, outer, runtime }; +} + +it('recognizes a verified 7702 self-call and retains every native agent action', async () => { + const { fake, wallet, actions, outer, runtime } = fixture(); + const getCode = fake.getCode.bind(fake); + fake.getCode = async (p) => + p.address === ADDR.agent + ? (`0xef0100${PUSH_BATCH_EXECUTOR_ADDRESS[ + CHAIN.PUSH_TESTNET_DONUT + ]!.slice(2)}` as Hex) + : getCode(p); + const result = await adaptTrackedResponse( + runtime, + fakeResponse({ + from: ADDR.agent, + to: ADDR.agent, + data: v5.encodeExecute(outer), + }) + ); + expect(result).toMatchObject({ + from: wallet.address, + to: actions[0].target, + agentic: { + door: 'agent', + rulesId: ruleId(1), + rawTo: ADDR.agent, + nativeCalls: actions.map((c) => ({ + to: c.target, + value: c.value, + data: c.data, + })), + }, + }); +}); + +it('recognizes a verified UEA multicall carrying single agent-door entries', async () => { + const { wallet, actions, outer, runtime } = fixture(); + (convertExecutorToOrigin as jest.Mock).mockResolvedValue({ + exists: true, + account: { chain: CHAIN.ETHEREUM_SEPOLIA, address: ADDR.owner }, + }); + const data = (UEA_MULTICALL_PREFIX + + encodeAbiParameters( + [ + { + type: 'tuple[]', + components: [ + { name: 'to', type: 'address' }, + { name: 'value', type: 'uint256' }, + { name: 'data', type: 'bytes' }, + ], + }, + ], + [outer.map((c) => ({ to: c.target, value: c.value, data: c.data }))] + ).slice(2)) as Hex; + const result = await adaptTrackedResponse( + runtime, + fakeResponse({ + from: ADDR.agent, + to: wallet.address, + data, + raw: { + from: ADDR.other, + to: ADDR.agent, + nonce: 0, + data, + value: BigInt(0), + }, + }) + ); + expect(result.from).toBe(wallet.address); + expect(result.agentic?.nativeCalls).toEqual( + actions.map((c) => ({ to: c.target, value: c.value, data: c.data })) + ); +}); + +it('does not label an arbitrary forwarding contract as a trusted sender batch', async () => { + const { outer, runtime } = fixture(); + const response = fakeResponse({ + from: ADDR.agent, + to: ADDR.other, + data: v5.encodeExecute(outer), + }); + expect(await adaptTrackedResponse(runtime, response)).toBe(response); + expect(response.agentic).toBeUndefined(); +}); diff --git a/packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts b/packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts new file mode 100644 index 00000000..9064b48f --- /dev/null +++ b/packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts @@ -0,0 +1,300 @@ +import { encodeFunctionData, getAddress, type Hex } from 'viem'; +import { CHAIN, PUSH_NETWORK } from '../../constants/enums'; +import { ERC20_EVM } from '../../constants/abi'; +import { TransactionRoute } from '../../orchestrator/route-detector'; +import type { UniversalExecuteParams } from '../../orchestrator/orchestrator.types'; +import { transformToUniversalTxReceipt } from '../../orchestrator/internals/tx-transformer'; +import { transformToUniversalTxResponse } from '../../orchestrator/internals/response-builder'; +import { adaptTrackedResponse } from '../response'; +import { composeOutbound, type DestinationCall } from '../execution/outbound'; +import { agenticSend } from '../execution/send'; +import { v5 } from '../contracts/v5'; +import { currentGeneration, resetAgenticGenerations } from '../deployments'; +import type { AgenticExecutionContext } from '../context'; +import { ADDR, FakeChain, registerFakeGeneration, ruleId } from './fake-chain'; +import { mockRuntime, fakeResponse } from './mock-runtime'; + +jest.mock('../../universal/account/account', () => ({ + convertExecutorToOrigin: jest + .fn() + .mockResolvedValue({ account: null, exists: false }), +})); + +afterEach(() => resetAgenticGenerations()); + +const USDC = { + symbol: 'USDC', + decimals: 6, + address: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238' as Hex, + mechanism: 'approve' as const, +}; +const TRANSFER = encodeFunctionData({ + abi: ERC20_EVM, + functionName: 'transfer', + args: [ADDR.target, BigInt(10)], +}); +const TOKEN_CALL: DestinationCall = { + to: getAddress(USDC.address), + data: TRANSFER, + value: BigInt(0), +}; +const APP_CALL: DestinationCall = { + to: ADDR.target, + data: '0xd09de08a', + value: BigInt(0), +}; +const PRC20 = ADDR.other; +const PUSH_HASH = `0x${'ab'.repeat(32)}` as Hex; +const EXTERNAL_HASH = `0x${'ef'.repeat(32)}` as Hex; + +function fixture() { + registerFakeGeneration(); + const fake = new FakeChain(); + const wallet = fake.addWallet(ADDR.owner, 'outbound-review'); + const gen = currentGeneration(PUSH_NETWORK.TESTNET_DONUT); + const read = fake.readContract.bind(fake); + fake.readContract = async (args) => + args.functionName === 'SOURCE_CHAIN_NAMESPACE' + ? CHAIN.ETHEREUM_SEPOLIA + : read(args); + fake.balances.set(`pc:${wallet.address.toLowerCase()}`, BigInt(100000)); + fake.balances.set(`balanceOf:${PRC20.toLowerCase()}`, BigInt(1000)); + fake.balances.set(`allowance:${PRC20.toLowerCase()}`, BigInt(1000)); + const runtime = mockRuntime(fake, { + signer: ADDR.owner, + resolvePrc20: () => PRC20, + }); + runtime.executeMock.mockImplementation( + async (params: { to: string; data?: Hex }) => + fakeResponse({ + to: params.to, + data: params.data ?? '0x', + from: ADDR.owner, + origin: `eip155:42101:${ADDR.owner}`, + }) + ); + const context: AgenticExecutionContext = { + wallet: wallet.address, + generation: gen, + door: 'owner', + signerPushAccount: ADDR.owner, + signerOrigin: { chain: CHAIN.PUSH_TESTNET_DONUT, address: ADDR.owner }, + }; + return { fake, wallet, gen, runtime, context }; +} + +const cases: { + name: string; + params: UniversalExecuteParams; + calls: DestinationCall[]; +}[] = [ + { + name: 'explicit ERC20 transfer preserves its token target and calldata', + params: { + to: { address: USDC.address, chain: CHAIN.ETHEREUM_SEPOLIA }, + data: TRANSFER, + }, + calls: [TOKEN_CALL], + }, + { + name: 'funds-only transfer describes the actual generated token call', + params: { + to: { address: ADDR.target, chain: CHAIN.ETHEREUM_SEPOLIA }, + funds: { amount: BigInt(10), token: USDC }, + }, + calls: [TOKEN_CALL], + }, + { + name: 'funds plus app call keeps the generated transfer and app call in order', + params: { + to: { address: ADDR.target, chain: CHAIN.ETHEREUM_SEPOLIA }, + funds: { amount: BigInt(10), token: USDC }, + data: APP_CALL.data, + }, + calls: [TOKEN_CALL, APP_CALL], + }, + { + name: 'explicit call array retains all calls without guessing a primary action', + params: { + to: { address: ADDR.other, chain: CHAIN.ETHEREUM_SEPOLIA }, + data: [TOKEN_CALL, APP_CALL], + }, + calls: [TOKEN_CALL, APP_CALL], + }, + { + name: 'native transfer preserves the actual destination value', + params: { + to: { address: ADDR.target, chain: CHAIN.ETHEREUM_SEPOLIA }, + value: BigInt(7), + }, + calls: [{ to: ADDR.target, value: BigInt(7), data: '0x' }], + }, +]; + +describe('canonical outbound response on send and replay', () => { + it.each(cases)('$name', async ({ params, calls }) => { + const { wallet, runtime, context } = fixture(); + const live = await agenticSend(runtime, context, params); + const submitted = runtime.executeMock.mock.calls[0][0]; + const replay = await adaptTrackedResponse( + runtime, + fakeResponse({ + to: submitted.to, + data: submitted.data, + origin: live.origin, + from: ADDR.owner, + route: TransactionRoute.UOA_TO_PUSH, + }) + ); + const summary = calls[0]; + for (const response of [live, replay]) { + expect(response).toMatchObject({ + from: wallet.address, + origin: live.origin, + ...summary, + route: TransactionRoute.UOA_TO_CEA, + chain: CHAIN.ETHEREUM_SEPOLIA, + }); + expect(response.agentic?.destinationCalls).toEqual(calls); + expect(response.agentic).toMatchObject({ + rawTo: wallet.address, + rawData: submitted.data, + }); + expect(await response.wait()).toMatchObject({ + from: wallet.address, + to: summary.to, + }); + } + }); +}); + +describe.each(['owner', 'agent'] as const)( + 'outbound replay wait on the %s door', + (door) => { + it.each(['success', 'reverted'] as const)( + 'handles an early Push-only route with a %s Push receipt', + async (status) => { + const { wallet, gen, runtime } = fixture(); + const out = await composeOutbound( + runtime, + gen, + wallet.address, + { + to: { address: ADDR.target, chain: CHAIN.ETHEREUM_SEPOLIA }, + data: APP_CALL.data, + }, + { door } + ); + const input = + door === 'owner' + ? v5.encodeExecute([out.gatewayCall]) + : v5.encodeExecuteAsAgent(ruleId(1), out.gatewayCall); + const signer = door === 'owner' ? ADDR.owner : ADDR.agent; + const tx = { + hash: PUSH_HASH, + from: signer, + to: wallet.address, + input, + value: BigInt(0), + nonce: 1, + gas: BigInt(160000), + gasPrice: BigInt(1), + blockNumber: BigInt(100), + blockHash: `0x${'cd'.repeat(32)}`, + transactionIndex: 0, + type: 'eip1559', + accessList: [], + r: '0x1', + s: '0x2', + v: BigInt(0), + wait: jest.fn().mockResolvedValue({ + transactionHash: PUSH_HASH, + blockNumber: BigInt(100), + blockHash: `0x${'cd'.repeat(32)}`, + transactionIndex: 0, + from: signer, + to: wallet.address, + contractAddress: null, + gasUsed: BigInt(80000), + cumulativeGasUsed: BigInt(80000), + logs: [], + logsBloom: '0x', + status, + }), + }; + const waitForOutboundTx = jest.fn().mockResolvedValue({ + externalTxHash: EXTERNAL_HASH, + destinationChain: CHAIN.ETHEREUM_SEPOLIA, + recipient: ADDR.target, + amount: '0', + assetAddr: PRC20, + explorerUrl: 'https://example.test/tx', + }); + const initHook = jest.fn(); + const perCallHook = jest.fn(); + const response = await transformToUniversalTxResponse( + { + universalSigner: { + account: { chain: CHAIN.PUSH_TESTNET_DONUT, address: signer }, + }, + progressHook: initHook, + } as unknown as Parameters[0], + tx as unknown as Parameters[1], + [], + { + trackTransaction: jest.fn(), + waitForOutboundTx, + transformToUniversalTxReceipt, + printLog: jest.fn(), + outboundConstants: { + initialWaitMs: 0, + pollingIntervalMs: 1, + maxTimeoutMs: 100, + }, + inboundConstants: { + initialWaitMs: 0, + pollingIntervalMs: 1, + maxTimeoutMs: 100, + }, + } + ); + response.route = TransactionRoute.UOA_TO_PUSH; + response.chain = CHAIN.PUSH_TESTNET_DONUT; + await adaptTrackedResponse(runtime, response); + response.progressHook(perCallHook); + const receipt = await response.wait(); + expect(response).toMatchObject({ + from: wallet.address, + route: TransactionRoute.UOA_TO_CEA, + chain: CHAIN.ETHEREUM_SEPOLIA, + }); + expect(response.agentic).toMatchObject({ + door, + destinationCalls: [APP_CALL], + }); + expect(receipt.from).toBe(wallet.address); + if (status === 'success') { + expect(waitForOutboundTx).toHaveBeenCalledTimes(1); + expect(waitForOutboundTx.mock.calls[0][0]).toBe(PUSH_HASH); + expect(receipt).toMatchObject({ + status: 1, + externalStatus: 'success', + externalChain: CHAIN.ETHEREUM_SEPOLIA, + externalTxHash: EXTERNAL_HASH, + }); + } else { + expect(waitForOutboundTx).not.toHaveBeenCalled(); + expect(receipt.status).toBe(0); + expect(receipt.externalStatus).toBeUndefined(); + } + const terminal = + status === 'success' ? 'SEND-TX-299-01' : 'SEND-TX-299-02'; + for (const hook of [initHook, perCallHook]) { + expect( + hook.mock.calls.filter(([event]) => event.id === terminal) + ).toHaveLength(1); + } + } + ); + } +); diff --git a/packages/core/src/lib/agentic/__tests__/reads-context.spec.ts b/packages/core/src/lib/agentic/__tests__/reads-context.spec.ts new file mode 100644 index 00000000..15dc1217 --- /dev/null +++ b/packages/core/src/lib/agentic/__tests__/reads-context.spec.ts @@ -0,0 +1,548 @@ +import { getAddress } from 'viem'; +import { PUSH_NETWORK } from '../../constants/enums'; +import { resolveAgenticContext } from '../context'; +import { resetAgenticGenerations, currentGeneration } from '../deployments'; +import { AGENTIC_ERROR_CODE } from '../errors'; +import { readCheckpoints, validateSequence } from '../reads/checkpoints'; +import { getRule, listRules, selectRuleForSend } from '../reads/rules'; +import { Snapshot, scanLogs } from '../reads/snapshot'; +import { deriveForOwner, listForOwner, walletInfo } from '../reads/wallets'; +import { + ADDR, + FakeChain, + PUSH_NS, + SEPOLIA_NS, + checkpointLog, + log, + registerFakeGeneration, + ruleId, +} from './fake-chain'; +import { mockRuntime } from './mock-runtime'; +import { v5 } from '../contracts/v5'; +import { readOriginToken } from '../contracts/prc20-metadata'; + +describe('generation registry', () => { + afterEach(() => resetAgenticGenerations()); + + it('ships Donut v5 only; other networks are unsupported', () => { + resetAgenticGenerations(); + expect(currentGeneration(PUSH_NETWORK.TESTNET_DONUT)).toMatchObject({ + id: 'v5', + advertised: true, + }); + for (const n of Object.values(PUSH_NETWORK).filter( + (n) => n !== PUSH_NETWORK.TESTNET_DONUT + )) { + expect(() => currentGeneration(n)).toThrow( + expect.objectContaining({ + code: AGENTIC_ERROR_CODE.GENERATION_UNSUPPORTED, + }) + ); + } + }); + + it('initialize against any wallet fails before signing when no generation is registered', async () => { + resetAgenticGenerations(); + const fake = new FakeChain(); + await expect( + resolveAgenticContext( + mockRuntime(fake, { network: PUSH_NETWORK.MAINNET }), + ADDR.target + ) + ).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.GENERATION_UNSUPPORTED, + }); + }); +}); + +describe('Donut log-range limit', () => { + it('covers the full range in contiguous pages of at most 1,000 blocks', async () => { + const fake = new FakeChain(); + const getLogs = jest.spyOn(fake, 'getLogs'); + await scanLogs( + fake, + { address: ADDR.factory, event: v5.events.walletDeployed }, + BigInt(10), + BigInt(2010) + ); + expect(getLogs.mock.calls.map(([a]) => [a.fromBlock, a.toBlock])).toEqual([ + [BigInt(10), BigInt(1009)], + [BigInt(1010), BigInt(2009)], + [BigInt(2010), BigInt(2010)], + ]); + }); +}); + +describe('native PRC20 metadata', () => { + it('accepts a zero address word only for the registered gas token', async () => { + const fake = new FakeChain(), + gas = getAddress('0x0000000000000000000000000000000000007070'); + const original = fake.readContract.bind(fake); + jest.spyOn(fake, 'readContract').mockImplementation(async (args) => { + if (args.functionName === 'SOURCE_TOKEN_ADDRESS') { + const abi = args.abi as readonly { + outputs?: readonly { type: string }[]; + }[]; + if (abi[0].outputs?.[0].type === 'address') + return '0x0000000000000000000000000000000000000000'; + throw new Error('native precompile returns a static word'); + } + return original(args); + }); + const snap = await Snapshot.at(fake); + expect(await readOriginToken(snap, gas, SEPOLIA_NS)).toBe( + '0x0000000000000000000000000000000000000000' + ); + await expect( + readOriginToken(snap, ADDR.target, SEPOLIA_NS) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.RULE_READ_FAILED }); + }); +}); + +describe('initialize with agenticWallet — door resolution', () => { + let fake: FakeChain; + beforeEach(() => { + registerFakeGeneration(); + fake = new FakeChain(); + }); + afterEach(() => resetAgenticGenerations()); + + it('owner → owner door; universal account context keeps signer identity separate', async () => { + const w = fake.addWallet(ADDR.owner, 'w'); + const ctx = await resolveAgenticContext( + mockRuntime(fake, { signer: ADDR.owner }), + w.address + ); + expect(ctx).toMatchObject({ + wallet: w.address, + door: 'owner', + signerPushAccount: ADDR.owner, + }); + }); + + it('agent named in an enabled rule → agent door, even when that rule is expired', async () => { + const w = fake.addWallet(ADDR.owner, 'w', [ + fake.nativeRule(ADDR.agent, ruleId(1), { validUntil: 1 }), + ]); + const ctx = await resolveAgenticContext(mockRuntime(fake), w.address); + expect(ctx.door).toBe('agent'); + }); + + it('anyone else → NOT_OWNER_OR_AGENT', async () => { + const w = fake.addWallet(ADDR.owner, 'w', [ + fake.nativeRule(ADDR.agent, ruleId(1)), + ]); + await expect( + resolveAgenticContext( + mockRuntime(fake, { signer: ADDR.other }), + w.address + ) + ).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.NOT_OWNER_OR_AGENT, + }); + }); + + it('no code → WALLET_NOT_DEPLOYED; a contract that is not an AGW → NOT_AGENTIC_WALLET', async () => { + await expect( + resolveAgenticContext(mockRuntime(fake), ADDR.target) + ).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.WALLET_NOT_DEPLOYED, + }); + await expect( + resolveAgenticContext(mockRuntime(fake), 'not-an-address') + ).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.NOT_AGENTIC_WALLET, + }); + }); + + it('wiring that does not match the registered generation is refused', async () => { + const w = fake.addWallet(ADDR.owner, 'w'); + w.accountId = 'push.agentwallet.1.0.0'; + await expect( + resolveAgenticContext( + mockRuntime(fake, { signer: ADDR.owner }), + w.address + ) + ).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.GENERATION_UNSUPPORTED, + }); + }); +}); + +describe('per-send rule selection', () => { + let fake: FakeChain; + beforeEach(() => { + registerFakeGeneration(); + fake = new FakeChain(); + }); + afterEach(() => resetAgenticGenerations()); + const gen = () => currentGeneration(PUSH_NETWORK.TESTNET_DONUT); + + it('exactly one enabled (agent, chain) match is selected, at one block', async () => { + const w = fake.addWallet(ADDR.owner, 'w', [ + fake.nativeRule(ADDR.agent, ruleId(1)), + fake.nativeRule(ADDR.other, ruleId(2)), + { ...fake.nativeRule(ADDR.agent, ruleId(3)), mode: 0, chain: SEPOLIA_NS }, + ]); + const snap = await Snapshot.at(fake); + const r = await selectRuleForSend( + snap, + gen(), + w.address, + ADDR.agent, + PUSH_NS + ); + expect(r.rulesId).toBe(ruleId(1)); + const u = await selectRuleForSend( + snap, + gen(), + w.address, + ADDR.agent, + SEPOLIA_NS + ); + expect(u.rulesId).toBe(ruleId(3)); + expect(new Set(fake.calls.map((c) => c.blockNumber))).toEqual( + new Set([fake.block]) + ); + }); + + it('zero matches → NO_RULES_FOR_CHAIN', async () => { + const w = fake.addWallet(ADDR.owner, 'w', [ + fake.nativeRule(ADDR.other, ruleId(2)), + ]); + await expect( + selectRuleForSend( + await Snapshot.at(fake), + gen(), + w.address, + ADDR.agent, + PUSH_NS + ) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.NO_RULES_FOR_CHAIN }); + }); + + it('direct-grant duplicates → AMBIGUOUS_RULE listing every candidate, never an arbitrary pick', async () => { + const w = fake.addWallet(ADDR.owner, 'w', [ + fake.nativeRule(ADDR.agent, ruleId(1)), + fake.nativeRule(ADDR.agent, ruleId(2)), + ]); + await expect( + selectRuleForSend( + await Snapshot.at(fake), + gen(), + w.address, + ADDR.agent, + PUSH_NS + ) + ).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.AMBIGUOUS_RULE, + details: { rulesIds: [ruleId(1), ruleId(2)] }, + }); + }); + + it('a revoked rule is not a candidate; lookups are not cached between sends', async () => { + const w = fake.addWallet(ADDR.owner, 'w', [ + fake.nativeRule(ADDR.agent, ruleId(1)), + ]); + expect( + ( + await selectRuleForSend( + await Snapshot.at(fake), + gen(), + w.address, + ADDR.agent, + PUSH_NS + ) + ).rulesId + ).toBe(ruleId(1)); + w.rules = []; + await expect( + selectRuleForSend( + await Snapshot.at(fake), + gen(), + w.address, + ADDR.agent, + PUSH_NS + ) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.NO_RULES_FOR_CHAIN }); + }); + + it('an RPC failure is an error, never an empty rule set', async () => { + const w = fake.addWallet(ADDR.owner, 'w', [ + fake.nativeRule(ADDR.agent, ruleId(1)), + ]); + fake.failOn.add('getPermissionIDs'); + await expect( + selectRuleForSend( + await Snapshot.at(fake), + gen(), + w.address, + ADDR.agent, + PUSH_NS + ) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.RULE_READ_FAILED }); + }); +}); + +describe('rules.list / rules.get', () => { + let fake: FakeChain; + beforeEach(() => { + registerFakeGeneration(); + fake = new FakeChain(); + }); + afterEach(() => resetAgenticGenerations()); + const gen = () => currentGeneration(PUSH_NETWORK.TESTNET_DONUT); + + it('decodes active native records without exposing internal spend', async () => { + const w = fake.addWallet(ADDR.owner, 'w', [ + fake.nativeRule(ADDR.agent, ruleId(1), { + callsUsed: 3, + valueSpent: BigInt(5), + maxCalls: 9, + }), + ]); + const rules = await listRules( + await Snapshot.at(fake), + gen(), + w.address, + PUSH_NS + ); + expect(rules).toEqual([ + expect.objectContaining({ + rulesId: ruleId(1), + enabled: true, + chainNamespace: PUSH_NS, + agent: ADDR.agent, + rule: expect.objectContaining({ maxCalls: 9, selector: '0xd09de08a' }), + }), + ]); + }); + + it('public records contain no spent field', async () => { + const w = fake.addWallet(ADDR.owner, 'w', [ + fake.nativeRule(ADDR.agent, ruleId(1)), + ]); + const record = await getRule( + await Snapshot.at(fake), + gen(), + w.address, + ruleId(1), + PUSH_NS + ); + expect(record).not.toHaveProperty('spent'); + }); + + it('lists native and universal rules without truncating', async () => { + const w = fake.addWallet(ADDR.owner, 'w', [ + fake.nativeRule(ADDR.agent, ruleId(1)), + { ...fake.nativeRule(ADDR.other, ruleId(2)), mode: 0, chain: SEPOLIA_NS }, + ]); + const records = await listRules( + await Snapshot.at(fake), + gen(), + w.address, + PUSH_NS + ); + expect(records.map((r) => r.chainNamespace)).toEqual([PUSH_NS, SEPOLIA_NS]); + }); + it('an empty source-token address is native only for the chain registry gas token', async () => { + const token = getAddress('0x0000000000000000000000000000000000007070'); + fake.sourceTokens.set(token.toLowerCase(), ''); + const w = fake.addWallet(ADDR.owner, 'native-gas', [ + { + ...fake.nativeRule(ADDR.agent, ruleId(1)), + mode: 0, + chain: SEPOLIA_NS, + universal: { + expectedCEA: ADDR.other, + maxGasPerCall: BigInt(1), + assets: [{ token }], + }, + }, + ]); + const record = await getRule( + await Snapshot.at(fake), + gen(), + w.address, + ruleId(1), + PUSH_NS + ); + expect(record.rule).toMatchObject({ + assets: [{ token: '0x0000000000000000000000000000000000000000' }], + }); + fake.sourceTokens.set(ADDR.target.toLowerCase(), ''); + w.rules[0].universal!.assets = [{ token: ADDR.target }]; + await expect( + getRule(await Snapshot.at(fake), gen(), w.address, ruleId(1), PUSH_NS) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.RULE_READ_FAILED }); + }); + + it('unknown and revoked IDs both return RULE_NOT_FOUND without history reconstruction', async () => { + const w = fake.addWallet(ADDR.owner, 'w'); + const snap = await Snapshot.at(fake); + await expect( + getRule(snap, gen(), w.address, ruleId(9), PUSH_NS) + ).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.RULE_NOT_FOUND, + }); + fake.extraLogs.push( + log( + w.address, + v5.events.rulesRevoked, + { rulesId: ruleId(9) }, + {}, + BigInt(50) + ) + ); + await expect( + getRule(snap, gen(), w.address, ruleId(9), PUSH_NS) + ).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.RULE_NOT_FOUND, + }); + }); +}); + +describe('wallet reads', () => { + let fake: FakeChain; + beforeEach(() => { + registerFakeGeneration(); + fake = new FakeChain(); + }); + afterEach(() => resetAgenticGenerations()); + const gen = () => currentGeneration(PUSH_NETWORK.TESTNET_DONUT); + + it('derive defaults to the next unused index; beyond it is refused', async () => { + fake.addWallet(ADDR.owner, 'a'); + expect(await deriveForOwner(fake, gen(), ADDR.owner)).toMatchObject({ + index: 1, + deployed: false, + }); + expect(await deriveForOwner(fake, gen(), ADDR.owner, 0)).toMatchObject({ + index: 0, + deployed: true, + }); + await expect(deriveForOwner(fake, gen(), ADDR.owner, 2)).rejects.toThrow( + /beyond/ + ); + }); + + it('derivation drift between the factory and the SDK mirror is detected (obligation 13)', async () => { + fake.predictOverride = () => + getAddress('0x0000000000000000000000000000000000000bad'); + await expect(deriveForOwner(fake, gen(), ADDR.owner)).rejects.toMatchObject( + { + code: AGENTIC_ERROR_CODE.INCONSISTENT_READ, + } + ); + }); + + it('list returns deployed slots with labels and rule counts plus the next undeployed slot', async () => { + fake.addWallet(ADDR.owner, 'first', [ + fake.nativeRule(ADDR.agent, ruleId(1)), + ]); + fake.addWallet(ADDR.owner, ''); + const wallets = await listForOwner(fake, gen(), ADDR.owner); + expect( + wallets.map((w) => [w.index, w.label, w.deployed, w.rulesCount]) + ).toEqual([ + [0, 'first', true, 1], + [1, 'AGW 2', true, 0], + [2, '', false, 0], + ]); + }); + + it('an empty owner lists only slot 0, undeployed', async () => { + expect(await listForOwner(fake, gen(), ADDR.other)).toEqual([ + expect.objectContaining({ + index: 0, + deployed: false, + rulesCount: 0, + label: '', + }), + ]); + }); + + it('reads current labels without depending on deployment logs', async () => { + const w = fake.addWallet(ADDR.owner, 'original'); + w.label = 'renamed'; + fake.extraLogs = []; + expect(await walletInfo(fake, gen(), w.address)).toMatchObject({ label: 'renamed' }); + expect((await listForOwner(fake, gen(), ADDR.owner))[0].label).toBe('renamed'); + expect(fake.calls.filter((c) => c.functionName === 'label')).toHaveLength(2); + w.label = ''; + expect(await walletInfo(fake, gen(), w.address)).toMatchObject({ label: 'AGW 1' }); + }); + + it('info of the signer’s next slot describes it as undeployed; other undeployed addresses are refused', async () => { + const next = await deriveForOwner(fake, gen(), ADDR.owner); + expect( + await walletInfo(fake, gen(), next.address, ADDR.owner) + ).toMatchObject({ deployed: false, index: 0, owner: ADDR.owner }); + await expect( + walletInfo(fake, gen(), next.address, ADDR.other) + ).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.WALLET_NOT_DEPLOYED, + }); + }); +}); + +describe('checkpoints', () => { + let fake: FakeChain; + beforeEach(() => { + registerFakeGeneration(); + fake = new FakeChain(); + }); + afterEach(() => resetAgenticGenerations()); + const gen = () => currentGeneration(PUSH_NETWORK.TESTNET_DONUT); + + it('orders by block, tx and log index and counts five ticks for a replacement in one block', async () => { + const w = fake.addWallet(ADDR.owner, 'w'); + // A grant (seq 1), then a replacement batch (seq 2..6) in one tx; logs arrive reversed. + fake.checkpointLogs = [1, 2, 3, 4, 5, 6] + .map((seq) => + checkpointLog( + w.address, + seq, + [1, 0, 0, 2, 0, 1][seq - 1], + seq === 1 ? BigInt(20) : BigInt(60) + ) + ) + .reverse(); + w.checkpointCount = BigInt(6); + const { checkpoints } = await readCheckpoints(fake, gen(), w.address); + expect(checkpoints.map((c) => c.seq)).toEqual([1, 2, 3, 4, 5, 6]); + expect(checkpoints.slice(1).map((c) => c.kind)).toEqual([ + 'OWNER_ACTION', + 'OWNER_ACTION', + 'RULES_REVOKED', + 'OWNER_ACTION', + 'RULES_GRANTED', + ]); + const since = await readCheckpoints(fake, gen(), w.address, BigInt(60)); + expect(since.checkpoints).toHaveLength(5); + expect(since.checkpoints.every((c) => c.blockNumber === BigInt(60))).toBe( + true + ); + }); + + it('a count/event mismatch is reported (after one retry) rather than returned', async () => { + const w = fake.addWallet(ADDR.owner, 'w'); + fake.checkpointLogs = [checkpointLog(w.address, 1, 1, BigInt(20))]; + w.checkpointCount = BigInt(2); + await expect(readCheckpoints(fake, gen(), w.address)).rejects.toMatchObject( + { + code: AGENTIC_ERROR_CODE.INCONSISTENT_READ, + } + ); + }); + + it('validateSequence checks contiguity and the count', () => { + expect(validateSequence([1, 2, 3], BigInt(3), true)).toBeNull(); + expect(validateSequence([1, 3], BigInt(3), true)).toMatch(/gap/); + expect(validateSequence([2, 3], BigInt(3), false)).toBeNull(); + expect(validateSequence([2, 3], BigInt(4), false)).toMatch( + /does not match/ + ); + expect(validateSequence([], BigInt(0), true)).toBeNull(); + }); +}); diff --git a/packages/core/src/lib/agentic/__tests__/response-surface.spec.ts b/packages/core/src/lib/agentic/__tests__/response-surface.spec.ts new file mode 100644 index 00000000..3b508a49 --- /dev/null +++ b/packages/core/src/lib/agentic/__tests__/response-surface.spec.ts @@ -0,0 +1,254 @@ +import { + encodeErrorResult, + encodeFunctionData, + getAddress, + type Hex, +} from 'viem'; +import * as core from '../../index'; +import { CONSTANTS } from '../../constants'; +import { PUSH_NETWORK } from '../../constants/enums'; +import { UNIVERSAL_GATEWAY_PC } from '../../constants/abi'; +import { PushChainExecutionError } from '../../orchestrator/internals/errors'; +import { Utils } from '../../utils'; +import { AGW_ABI } from '../contracts/abi/v5'; +import { v5 } from '../contracts/v5'; +import { resetAgenticGenerations } from '../deployments'; +import { AgenticRevertError } from '../errors'; +import { adaptAgenticResponse, adaptTrackedResponse } from '../response'; +import { decodeAgenticRevert, decodeAgwErrorData } from '../revert'; +import { ADDR, FakeChain, registerFakeGeneration, ruleId } from './fake-chain'; +import { fakeResponse } from './mock-runtime'; + +afterEach(() => resetAgenticGenerations()); + +describe('response identity', () => { + it('live adaptation keeps origin/hash/raw and records the wrapped call', () => { + const resp = fakeResponse({ + to: ADDR.target, + data: '0xabcd', + from: ADDR.agent, + }); + const origin = resp.origin; + adaptAgenticResponse(resp, { + wallet: ADDR.owner, + door: 'agent', + rulesId: ruleId(1), + logical: { to: ADDR.other, data: '0x01', value: BigInt(2) }, + }); + expect(resp).toMatchObject({ + from: ADDR.owner, + to: ADDR.other, + data: '0x01', + value: BigInt(2), + origin, + }); + expect(resp.raw).toMatchObject({ + from: ADDR.agent, + to: ADDR.target, + data: '0xabcd', + }); + expect(resp.agentic).toMatchObject({ + rawTo: ADDR.target, + rawData: '0xabcd', + door: 'agent', + }); + }); + + it('replay: a tracked execute on a registered wallet is re-presented as the wallet’s call', async () => { + registerFakeGeneration(); + const fake = new FakeChain(); + const w = fake.addWallet(ADDR.owner, 'w'); + const data = v5.encodeExecuteAsAgent(ruleId(4), { + target: ADDR.target, + value: BigInt(0), + data: '0xd09de08a', + }); + const tracked = await adaptTrackedResponse( + { reader: fake, network: PUSH_NETWORK.TESTNET_DONUT }, + fakeResponse({ to: w.address, data, from: ADDR.agent }) + ); + expect(tracked).toMatchObject({ + from: w.address, + to: ADDR.target, + data: '0xd09de08a', + }); + expect(tracked.agentic).toMatchObject({ + door: 'agent', + rulesId: ruleId(4), + }); + }); + + it('replay: an outbound through the gateway restores the destination call and route', async () => { + registerFakeGeneration(); + const fake = new FakeChain(); + const w = fake.addWallet(ADDR.owner, 'w'); + const payload = ('0x2cc2842d' + + encodeFunctionData({ + abi: [ + { + type: 'function', + name: 'x', + inputs: [ + { + type: 'tuple[]', + components: [ + { name: 'to', type: 'address' }, + { name: 'value', type: 'uint256' }, + { name: 'data', type: 'bytes' }, + ], + }, + ], + outputs: [], + stateMutability: 'nonpayable', + }, + ], + args: [[{ to: ADDR.target, value: BigInt(0), data: '0xd09de08a' }]], + }).slice(10)) as Hex; + const gatewayCall = encodeFunctionData({ + abi: UNIVERSAL_GATEWAY_PC, + functionName: 'sendUniversalTxOutbound', + args: [ + { + recipient: '0x', + token: ADDR.other, + amount: BigInt(1), + gasLimit: BigInt(1), + gasPrice: BigInt(0), + maxPCForGas: BigInt(1), + payload, + revertRecipient: w.address, + }, + ], + }); + const data = v5.encodeExecuteAsAgent(ruleId(4), { + target: ADDR.gateway, + value: BigInt(5), + data: gatewayCall, + }); + const tracked = await adaptTrackedResponse( + { reader: fake, network: PUSH_NETWORK.TESTNET_DONUT }, + fakeResponse({ to: w.address, data }) + ); + expect(tracked).toMatchObject({ + from: w.address, + to: ADDR.target, + data: '0xd09de08a', + route: 'UOA_TO_CEA', + }); + // A Push-only route inferred from an incomplete Cosmos record is replaced. + const early = await adaptTrackedResponse( + { reader: fake, network: PUSH_NETWORK.TESTNET_DONUT }, + fakeResponse({ to: w.address, data, route: 'UOA_TO_PUSH' }) + ); + expect(early.route).toBe('UOA_TO_CEA'); + }); + + it('replay: anything not provably an AGW call is left untouched', async () => { + const fake = new FakeChain(); + const plain = fakeResponse({ to: ADDR.target, data: '0xd09de08a' }); + expect( + await adaptTrackedResponse( + { reader: fake, network: PUSH_NETWORK.TESTNET_DONUT }, + plain + ) + ).toBe(plain); + registerFakeGeneration(); + const spoof = fakeResponse({ + to: ADDR.target, + data: v5.encodeExecute([ + { target: ADDR.other, value: BigInt(0), data: '0x' }, + ]), + }); + const out = await adaptTrackedResponse( + { reader: fake, network: PUSH_NETWORK.TESTNET_DONUT }, + spoof + ); + expect(out.from).toBe(spoof.from); + expect(out.agentic).toBeUndefined(); + }); +}); + +describe('revert decoding', () => { + it('decodes AGW errors with arguments', () => { + const data = encodeErrorResult({ + abi: AGW_ABI, + errorName: 'CallerIsNotAgent', + args: [ruleId(1), ADDR.other], + }); + expect(decodeAgwErrorData(data)).toMatchObject({ + name: 'CallerIsNotAgent', + }); + }); + + it('names a truncated PolicyCheckReverted by its inner selector', () => { + expect( + decodeAgwErrorData(`0xf4270752${'8bb88ba1'.padEnd(64, '0')}`) + ).toMatchObject({ + name: 'PolicyCheckReverted(CallLimitReached)', + selector: '0xf4270752', + }); + }); + + it('finds revert data through error causes and viem-style messages', () => { + const inner = new Error('outer', { + cause: { + data: encodeErrorResult({ + abi: AGW_ABI, + errorName: 'UnsupportedExecutionMode', + }), + }, + }); + expect(decodeAgenticRevert(inner)?.name).toBe('UnsupportedExecutionMode'); + expect(decodeAgenticRevert(new Error('nothing here'))).toBeUndefined(); + }); + it('decodes viem simulation errors whose full revert lives in raw', () => { + const raw = `0xf4270752${'8bb88ba1'.padEnd(64, '0')}` as Hex; + expect( + decodeAgenticRevert({ + message: 'Unknown signature 0xf4270752', + cause: { raw }, + })?.name + ).toBe('PolicyCheckReverted(CallLimitReached)'); + }); +}); + +describe('public surface', () => { + it('exports the AGW errors, and the base execution error for instanceof checks', () => { + expect(core.AgenticError).toBeDefined(); + expect(new core.AgenticRevertError('x')).toBeInstanceOf( + core.PushChainExecutionError + ); + expect(core.PushChainExecutionError).toBe(PushChainExecutionError); + expect(core.AGENTIC_ERROR_CODE.NO_RULES_FOR_CHAIN).toBe( + 'NO_RULES_FOR_CHAIN' + ); + expect(new AgenticRevertError('x', { cause: 'c' }).cause).toBe('c'); + }); + + it('CONSTANTS.AGENTIC carries the checked Donut v5 proxies', () => { + expect(CONSTANTS.AGENTIC.TESTNET_DONUT).toMatchObject({ + FACTORY: '0x8137F96A50EBF41d904e3678c84c391a0D1BCcc5', + RULES_POLICY: '0x603E7f0aF6e1aAFf46DDfb28b1e99364f8BC59af', + ENVELOPE_VERSION: 1, + }); + expect(Object.isFrozen(CONSTANTS.AGENTIC)).toBe(true); + }); + + it('PushChain.utils.agentic is the pure helper set', () => { + expect(Object.keys(Utils.agentic).sort()).toEqual( + ['actionId', 'configId', 'decodeRules'].sort() + ); + // @ts-expect-error generation context helpers are not public + expect(Utils.agentic.rulesId).toBeUndefined(); + // @ts-expect-error the marketplace compiler is outside AGW + expect(Utils.agentic.compileCard).toBeUndefined(); + for (const name of [ + 'rulesId', + 'deriveWallet', + 'encodeRules', + 'compileCard', + ]) { + expect(Utils.agentic).not.toHaveProperty(name); + } + }); +}); diff --git a/packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts b/packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts new file mode 100644 index 00000000..fe301376 --- /dev/null +++ b/packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts @@ -0,0 +1,348 @@ +import { getAddress, type Address } from 'viem'; +import { CHAIN, PUSH_NETWORK } from '../../constants/enums'; +import { MOVEABLE_TOKEN_CONSTANTS } from '../../constants/tokens'; +import { getPRC20Address } from '../../universal/prc20-address'; +import { encodeUniversalTerms } from '../codec/universal-terms'; +import { buildSession, encodeEnvelope, encodeSession } from '../codec/session'; +import { prepareRules } from '../codec/rules'; +import { validateUniversalRuleShape } from '../codec/universal'; +import { V5_CAPABILITIES } from '../deployments'; +import { AGENTIC_ERROR_CODE } from '../errors'; +import { internalAgenticUtils } from '../utils'; +import type { NativeRule, UniversalRule } from '../agentic.types'; +import { ADDR, PUSH_NS, SEPOLIA_NS } from './fake-chain'; + +const NOW = 1_700_000_000; +const ctx = { + owner: ADDR.owner, + pushChainNamespace: PUSH_NS, + validator: ADDR.validator, + rulesPolicy: ADDR.policy, + capabilities: V5_CAPABILITIES, + nowSeconds: NOW, + forbiddenTargets: [ + ADDR.factory, + ADDR.engine, + ADDR.policy, + ADDR.validator, + ADDR.gateway, + ], +}; +const native = (over: Partial = {}): NativeRule => ({ + agent: ADDR.agent, + target: ADDR.target, + selector: 'increment()', + validUntil: NOW + 100, + ...over, +}); +const universal = (over: Partial = {}): UniversalRule => ({ + agent: ADDR.agent, + chainNamespace: SEPOLIA_NS, + assets: [ + { + token: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238', + maxPerCall: BigInt(100), + }, + ], + maxGasPerCall: BigInt(10) ** BigInt(18), + validUntil: NOW + 100, + allowedCalls: [ + { + target: ADDR.target, + selector: 'supply(address,uint256,address,uint16)', + beneficiary: 2, + }, + ], + ...over, +}); + +describe('prepareRules — spec 1.b checks before any signature', () => { + it('AGENT_IS_OWNER', () => { + expect(() => prepareRules([native({ agent: ADDR.owner })], ctx)).toThrow( + expect.objectContaining({ code: AGENTIC_ERROR_CODE.AGENT_IS_OWNER }) + ); + }); + + it('allows multiple rules for the same agent and chain', () => { + const prepared = prepareRules( + [native(), native({ target: ADDR.other })], + ctx + ); + expect(prepared).toHaveLength(2); + expect(prepared.map((p) => p.agent)).toEqual([ADDR.agent, ADDR.agent]); + expect(prepared.map((p) => p.nativeTerms?.target)).toEqual([ + ADDR.target, + ADDR.other, + ]); + }); + + it('native and universal rules coexist for the same agent', () => { + const u = universal(); + const prepared = prepareRules([native(), u], { + ...ctx, + gateway: ADDR.gateway, + universal: new Map([ + [ + u, + { + expectedCEA: ADDR.other, + assets: [ + { + token: ADDR.target, + maxPerCall: BigInt(100), + maxTotal: BigInt(1000), + }, + ], + }, + ], + ]), + }); + expect(prepared.map((p) => p.chainNamespace)).toEqual([ + PUSH_NS, + SEPOLIA_NS, + ]); + }); + + it('removed ref inputs fail explicitly instead of being silently dropped', () => { + expect(() => prepareRules([{ ...native(), ref: `0x${'99'.repeat(32)}` } as never], ctx)) + .toThrow(expect.objectContaining({ code: AGENTIC_ERROR_CODE.INVALID_RULE })); + }); + + it('refuses infrastructure targets the contracts would reject', () => { + for (const t of [ + ADDR.gateway, + ADDR.policy, + '0x0000000000000000000000000000000000000001' as Address, + ]) { + expect(() => prepareRules([native({ target: t })], ctx)).toThrow( + /infrastructure/ + ); + } + }); + + it('a universal rule naming the Push chain is rejected', () => { + expect(() => + prepareRules( + [universal({ chainNamespace: PUSH_NS as `eip155:${string}` })], + ctx + ) + ).toThrow(/omit chainNamespace/); + }); + + it('valid native rules produce one Session each, agent bound in the validator config', () => { + const [p] = prepareRules([native()], ctx); + expect(p.chainNamespace).toBe(PUSH_NS); + expect(p.session.sessionValidator).toBe(ADDR.validator); + expect(p.session.actions).toHaveLength(1); + expect(p.session.actions[0].actionPolicies[0].policy).toBe(ADDR.policy); + expect(p.session.permitERC4337Paymaster).toBe(false); + }); +}); + +describe('universal rules — validated, then capability-gated (A01, A05)', () => { + it('structural validation runs before the capability gate', () => { + expect(() => + validateUniversalRuleShape(universal({ allowedCalls: [] }), NOW) + ).toThrow(/1\.\.32/); + expect(() => + validateUniversalRuleShape(universal({ maxGasPerCall: BigInt(0) }), NOW) + ).toThrow(/maxGasPerCall/); + expect(() => + validateUniversalRuleShape( + universal({ chainNamespace: 'eip155:abc' as `eip155:${string}` }), + NOW + ) + ).toThrow(/CAIP-2/); + expect(() => + validateUniversalRuleShape( + universal({ + assets: Array.from({ length: 9 }, (_, i) => ({ + token: getAddress(`0x${(i + 1).toString(16).padStart(40, '0')}`), + maxPerCall: BigInt(1), + })), + }), + NOW + ) + ).toThrow(/at most 8/); + expect(() => + validateUniversalRuleShape( + universal({ + assets: [ + { token: ADDR.target, maxPerCall: BigInt(1) }, + { token: ADDR.target, maxPerCall: BigInt(2) }, + ], + }), + NOW + ) + ).toThrow(/duplicates/); + }); + + it('approval policy belongs to UI/marketplace; structurally valid approval calls are accepted', () => { + for (const selector of [ + 'approve(address,uint256)', + 'increaseAllowance(address,uint256)', + ] as const) { + expect(() => + validateUniversalRuleShape( + universal({ allowedCalls: [{ target: ADDR.target, selector }] }), + NOW + ) + ).not.toThrow(); + } + }); + + it('a beneficiary must be an address argument of a known signature', () => { + expect(() => + validateUniversalRuleShape( + universal({ + allowedCalls: [ + { + target: ADDR.target, + selector: 'supply(address,uint256,address,uint16)', + beneficiary: 1, + }, + ], + }), + NOW + ) + ).toThrow(/address argument/); + expect(() => + validateUniversalRuleShape( + universal({ + allowedCalls: [ + { target: ADDR.target, selector: '0x617ba037', beneficiary: 2 }, + ], + }), + NOW + ) + ).toThrow(/signature/); + }); + + it('requires resolved wallet/token context and named SVM IDL inputs', () => { + expect(() => prepareRules([universal()], ctx)).toThrow( + expect.objectContaining({ + code: AGENTIC_ERROR_CODE.INVALID_RULE, + }) + ); + expect(() => + prepareRules( + [ + universal({ + chainNamespace: 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1' as never, + }), + ], + ctx + ) + ).toThrow( + expect.objectContaining({ + code: AGENTIC_ERROR_CODE.INVALID_RULE, + }) + ); + }); +}); + +describe('internal generation codecs (pure)', () => { + const u = internalAgenticUtils; + + it('encodeRules → decodeRules round-trips a native rule', () => { + const rule = native({ + selector: 'deposit(address,uint256)', + pins: [{ arg: 0, expected: ADDR.other }], + maxCalls: 4, + }); + const [bytes] = u.encodeRules([rule], { + pushChainNamespace: PUSH_NS, + validator: ADDR.validator, + rulesPolicy: ADDR.policy, + nowSeconds: NOW, + }); + const back = u.decodeRules(bytes, { pushChainNamespace: PUSH_NS }); + expect(back).toMatchObject({ + agent: ADDR.agent, + target: ADDR.target, + maxCalls: 4, + validUntil: NOW + 100, + }); + expect((back as NativeRule).pins).toEqual([ + { + offset: 4, + expected: `0x${'0'.repeat(24)}${ADDR.other.slice(2).toLowerCase()}`, + }, + ]); + }); + + it('decodeRules rejects a foreign-chain envelope carrying native terms', () => { + const [bytes] = u.encodeRules([native()], { + pushChainNamespace: SEPOLIA_NS, + validator: ADDR.validator, + rulesPolicy: ADDR.policy, + nowSeconds: NOW, + }); + expect(() => u.decodeRules(bytes, { pushChainNamespace: PUSH_NS })).toThrow( + expect.objectContaining({ + code: AGENTIC_ERROR_CODE.RULE_READ_FAILED, + }) + ); + }); + + it('pure decoding resolves known v5 assets and preserves the exact beneficiary offset', () => { + const inputToken = MOVEABLE_TOKEN_CONSTANTS.ETHEREUM_SEPOLIA.USDC; + const prc20 = getPRC20Address(inputToken, { + network: PUSH_NETWORK.TESTNET_DONUT, + }).address; + const bytes = encodeSession( + buildSession({ + validator: ADDR.validator, + agent: ADDR.agent, + rulesPolicy: ADDR.policy, + actions: [ + { + target: ADDR.gateway, + selector: '0x77b86bec', + initData: encodeEnvelope( + CHAIN.ETHEREUM_SEPOLIA, + encodeUniversalTerms({ + validUntil: NOW + 100, + expectedCEA: ADDR.other, + assets: [ + { + token: prc20, + maxPerCall: BigInt(10), + maxTotal: BigInt(100), + }, + ], + maxGasPerCall: BigInt(20), + allowedCalls: [ + { + target: ADDR.target, + selector: '0x617ba037', + beneficiaryOffset: 68, + hasBeneficiary: true, + maxValue: BigInt(0), + }, + ], + }) + ), + }, + ], + }) + ); + expect(u.decodeRules(bytes)).toMatchObject({ + chainNamespace: CHAIN.ETHEREUM_SEPOLIA, + assets: [ + { + token: getAddress(inputToken.address), + maxPerCall: BigInt(10), + maxTotal: BigInt(100), + }, + ], + allowedCalls: [{ beneficiaryOffset: 68 }], + }); + }); + + it('actionId accepts signatures and hex alike', () => { + expect(u.actionId(ADDR.target, 'increment()')).toBe( + u.actionId(ADDR.target, '0xd09de08a') + ); + }); +}); diff --git a/packages/core/src/lib/agentic/__tests__/send.spec.ts b/packages/core/src/lib/agentic/__tests__/send.spec.ts new file mode 100644 index 00000000..5291fac1 --- /dev/null +++ b/packages/core/src/lib/agentic/__tests__/send.spec.ts @@ -0,0 +1,680 @@ +import { + decodeAbiParameters, + decodeFunctionData, + encodeFunctionData, + getAddress, + maxUint256, + type Address, + type Hex, +} from 'viem'; +import { CHAIN, PUSH_NETWORK } from '../../constants/enums'; +import { UNIVERSAL_GATEWAY_PC, ERC20_EVM } from '../../constants/abi'; +import { PushChainExecutionError } from '../../orchestrator/internals/errors'; +import { PROGRESS_HOOK } from '../../progress-hook/progress-hook.types'; +import type { AgenticExecutionContext } from '../context'; +import { currentGeneration, resetAgenticGenerations } from '../deployments'; +import { v5 } from '../contracts/v5'; +import { actionId } from '../codec/ids'; +import { AGENTIC_ERROR_CODE, AgenticRevertError } from '../errors'; +import { agenticSend } from '../execution/send'; +import { + ADDR, + FakeChain, + SEPOLIA_NS, + registerFakeGeneration, + ruleId, +} from './fake-chain'; +import { mockRuntime } from './mock-runtime'; + +const data = '0xd09de08a' as Hex; + +function setup( + door: 'owner' | 'agent', + rules = (f: FakeChain) => [f.nativeRule(ADDR.agent, ruleId(1))] +) { + registerFakeGeneration(); + const fake = new FakeChain(); + const w = fake.addWallet(ADDR.owner, 'w', rules(fake)); + const gen = currentGeneration(PUSH_NETWORK.TESTNET_DONUT); + const signer = door === 'owner' ? ADDR.owner : ADDR.agent; + const ctx: AgenticExecutionContext = { + wallet: w.address, + door, + signerPushAccount: signer, + signerOrigin: { chain: CHAIN.PUSH_TESTNET_DONUT, address: signer }, + generation: gen, + }; + return { fake, w, gen, ctx, rt: mockRuntime(fake, { signer }) }; +} + +afterEach(() => resetAgenticGenerations()); + +describe('guards fail before the signer is ever invoked', () => { + it.each([ + [ + 'from (Routes 3/4)', + { to: ADDR.target, data, from: { chain: CHAIN.ETHEREUM_SEPOLIA } }, + AGENTIC_ERROR_CODE.FROM_NOT_ALLOWED, + ], + [ + 'payGasWith', + { to: ADDR.target, data, payGasWith: {} }, + AGENTIC_ERROR_CODE.NOT_ALLOWED_IN_AGENTIC_MODE, + ], + [ + 'migration', + { + to: { address: ADDR.target, chain: CHAIN.ETHEREUM_SEPOLIA }, + migration: true, + }, + AGENTIC_ERROR_CODE.NOT_ALLOWED_IN_AGENTIC_MODE, + ], + [ + 'funds on a Push send', + { to: ADDR.target, funds: { amount: BigInt(1) } }, + AGENTIC_ERROR_CODE.NOT_ALLOWED_IN_AGENTIC_MODE, + ], + ])('%s', async (_name, params, code) => { + const { rt, ctx } = setup('agent'); + await expect(agenticSend(rt, ctx, params as never)).rejects.toMatchObject({ + code, + }); + expect(rt.executeMock).not.toHaveBeenCalled(); + }); + + it('read-only clients never sign', async () => { + const { fake, ctx } = setup('owner'); + const rt = mockRuntime(fake, { signer: ADDR.owner, readOnly: true }); + await expect( + agenticSend(rt, ctx, { to: ADDR.target, data }) + ).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.READ_ONLY, + }); + expect(rt.executeMock).not.toHaveBeenCalled(); + }); + + it.each([true, false])( + 'agent native arrays require an atomic sender-preserving transport (Push EOA=%s)', + async (native) => { + const { rt, ctx } = setup('agent'); + rt.signerIsPushNative = () => native; + const calls = [ + { to: ADDR.target, value: BigInt(0), data }, + { to: ADDR.target, value: BigInt(1), data }, + ]; + const tx = await agenticSend(rt, ctx, { to: ADDR.target, data: calls }); + expect(rt.executeMock).not.toHaveBeenCalled(); + expect(rt.atomicMock).toHaveBeenCalledTimes(1); + const batch = rt.atomicMock.mock.calls[0][0].data as { + to: Address; + value: bigint; + data: Hex; + }[]; + expect(batch.map((c) => c.to)).toEqual([ctx.wallet, ctx.wallet]); + expect(batch.map((c) => v5.decodeWalletCall(c.data))).toEqual( + calls.map((c) => ({ + kind: 'executeAsAgent', + rulesId: ruleId(1), + mode: `0x${'00'.repeat(32)}`, + calls: [{ target: c.to, value: c.value, data: c.data }], + })) + ); + expect(tx.agentic?.nativeCalls).toEqual(calls); + } + ); + + it('empty native arrays fail before any transport is called', async () => { + const { rt, ctx } = setup('agent'); + await expect( + agenticSend(rt, ctx, { to: ADDR.target, data: [] }) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.INVALID_RULE }); + expect(rt.executeMock).not.toHaveBeenCalled(); + expect(rt.atomicMock).not.toHaveBeenCalled(); + }); + + it('NO_RULES_FOR_CHAIN and AMBIGUOUS_RULE are pre-signature', async () => { + const none = setup('agent', () => []); + await expect( + agenticSend(none.rt, none.ctx, { to: ADDR.target, data }) + ).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.NO_RULES_FOR_CHAIN, + }); + const dup = setup('agent', (f) => [ + f.nativeRule(ADDR.agent, ruleId(1)), + f.nativeRule(ADDR.agent, ruleId(2)), + ]); + await expect( + agenticSend(dup.rt, dup.ctx, { to: ADDR.target, data }) + ).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.AMBIGUOUS_RULE, + }); + expect(none.rt.executeMock).not.toHaveBeenCalled(); + expect(dup.rt.executeMock).not.toHaveBeenCalled(); + }); + + it('an external agent whose deployed UEA cannot pay Push gas fails loudly; an undeployed UEA takes the first-use path', async () => { + const { fake, ctx } = setup('agent'); + const poor = mockRuntime(fake, { + signer: ADDR.agent, + signerIsPushNative: () => false, + signerAccountDeployed: async () => true, + signerBalance: async () => BigInt(5), + getGasPrice: async () => BigInt(1), + }); + await expect( + agenticSend(poor, ctx, { to: ADDR.target, data }) + ).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.AGENT_GAS_INSUFFICIENT, + }); + expect(poor.executeMock).not.toHaveBeenCalled(); + const firstUse = mockRuntime(fake, { + signer: ADDR.agent, + signerIsPushNative: () => false, + signerAccountDeployed: async () => false, + signerBalance: async () => BigInt(0), + }); + await agenticSend(firstUse, ctx, { to: ADDR.target, data }); + expect(firstUse.executeMock).toHaveBeenCalledTimes(1); + }); +}); + +describe('explicit Push destinations', () => { + it('a ChainTarget on the connected Push chain is a native send, same as a bare address', async () => { + const { rt, ctx } = setup('agent'); + const tx = await agenticSend(rt, ctx, { + to: { address: ADDR.target, chain: CHAIN.PUSH_TESTNET_DONUT }, + data, + }); + expect( + v5.decodeWalletCall(rt.executeMock.mock.calls[0][0].data) + ).toMatchObject({ kind: 'executeAsAgent', rulesId: ruleId(1) }); + expect(tx.route).not.toBe('UOA_TO_CEA'); + expect(tx.to).toBe(ADDR.target); + }); + + it('the owner door treats it the same way', async () => { + const { rt, ctx } = setup('owner'); + await agenticSend(rt, ctx, { + to: { address: ADDR.target, chain: CHAIN.PUSH_TESTNET }, + data, + }); + expect( + v5.decodeWalletCall(rt.executeMock.mock.calls[0][0].data) + ).toMatchObject({ kind: 'execute', calls: [{ target: ADDR.target }] }); + }); + + it('another Push network is refused, not routed outbound', async () => { + const { rt, ctx } = setup('owner'); + await expect( + agenticSend(rt, ctx, { + to: { address: ADDR.target, chain: CHAIN.PUSH_MAINNET }, + data, + }) + ).rejects.toThrow(/other than the connected network/); + expect(rt.executeMock).not.toHaveBeenCalled(); + }); +}); + +describe('native wrapping and logical identity', () => { + it('agent door: executeAsAgent(selected rule, exact call); response shows the wallet as from', async () => { + const { rt, ctx, w } = setup('agent'); + const perCall = jest.fn(); + const tx = await agenticSend( + rt, + ctx, + { to: ADDR.target, data, value: BigInt(3) }, + { progressHook: perCall } + ); + const sent = rt.executeMock.mock.calls[0][0]; + expect(sent.to).toBe(w.address); + expect(sent.value).toBe(BigInt(0)); + expect(v5.decodeWalletCall(sent.data)).toEqual({ + kind: 'executeAsAgent', + rulesId: ruleId(1), + mode: `0x${'00'.repeat(32)}`, + calls: [{ target: ADDR.target, value: BigInt(3), data }], + }); + expect(tx).toMatchObject({ + from: w.address, + to: ADDR.target, + data, + value: BigInt(3), + }); + expect(tx.origin).toContain(ADDR.agent); + expect(tx.agentic).toMatchObject({ + wallet: w.address, + door: 'agent', + rulesId: ruleId(1), + rawTo: w.address, + }); + const ids = rt.events.map((e) => e.id); + expect(ids).toEqual([ + PROGRESS_HOOK.AGENTIC_TX_107, + PROGRESS_HOOK.AGENTIC_TX_199_01, + ]); + expect(perCall).toHaveBeenCalledTimes(2); + expect(rt.executeMock.mock.calls[0][1]).toMatchObject({ + progressHook: perCall, + }); + }); + + it('owner door: arrays become one atomic execute(batch)', async () => { + const { rt, ctx } = setup('owner'); + await agenticSend(rt, ctx, { + to: ADDR.target, + data: [ + { to: ADDR.target, value: BigInt(0), data }, + { to: ADDR.other, value: BigInt(1), data: '0x' }, + ], + }); + const decoded = v5.decodeWalletCall(rt.executeMock.mock.calls[0][0].data); + expect(decoded).toMatchObject({ + kind: 'execute', + mode: `0x01${'00'.repeat(31)}`, + }); + expect((decoded as { calls: unknown[] }).calls).toHaveLength(2); + }); + + it('wallet waits report the wallet on the receipt too', async () => { + const { rt, ctx, w } = setup('agent'); + const tx = await agenticSend(rt, ctx, { to: ADDR.target, data }); + expect((await tx.wait()).from).toBe(w.address); + }); + + it('an on-chain policy revert becomes AgenticRevertError with the decoded gate and 199-02', async () => { + const { fake, ctx } = setup('agent'); + const rt = mockRuntime(fake, { + signer: ADDR.agent, + execute: async () => { + throw new PushChainExecutionError( + 'Execution reverted with reason: custom error 0xf4270752: 8bb88ba100000000000000000000000000000000000000000000000000000000.' + ); + }, + }); + const err = await agenticSend(rt, ctx, { to: ADDR.target, data }).catch( + (e) => e + ); + expect(err).toBeInstanceOf(AgenticRevertError); + expect(err).toBeInstanceOf(PushChainExecutionError); + expect(err.decodedError.name).toBe('PolicyCheckReverted(CallLimitReached)'); + const failed = rt.events.find( + (e) => e.id === PROGRESS_HOOK.AGENTIC_TX_199_02 + ); + expect(failed?.response).toMatchObject({ + decodedError: { name: 'PolicyCheckReverted(CallLimitReached)' }, + }); + }); +}); + +describe('EVM outbound composition from the wallet', () => { + const token = getAddress('0x0000000000000000000000000000000000007070'); + const universalSetup = () => { + const s = setup('agent', (f) => [ + { + ...f.nativeRule(ADDR.agent, ruleId(5)), + mode: 0, + chain: SEPOLIA_NS, + actionIds: [], + universal: { + assets: [{ token }], + expectedCEA: getAddress('0x000000000000000000000000000000000000cea1'), + maxGasPerCall: BigInt(5000), + }, + }, + ]); + // universal action id is (gateway, sendUniversalTxOutbound) + s.w.rules[0].actionIds = [actionId(ADDR.gateway, '0x77b86bec')]; + s.fake.balances.set( + `pc:${s.w.address.toLowerCase()}`, + BigInt(10) ** BigInt(18) + ); + s.fake.balances.set(`balanceOf:${token.toLowerCase()}`, BigInt(1000)); + s.fake.balances.set(`allowance:${token.toLowerCase()}`, BigInt(500)); + return s; + }; + const send = (amount?: bigint) => ({ + to: { address: ADDR.target, chain: CHAIN.ETHEREUM_SEPOLIA }, + data, + ...(amount + ? { + funds: { + amount, + token: { + symbol: 'USDC', + decimals: 6, + address: token, + mechanism: 'approve' as const, + }, + }, + } + : {}), + }); + + it('builds the policy-compatible request: empty recipient, wallet refund, nonzero gas cap, multicall payload, CEA of the wallet', async () => { + const s = universalSetup(); + const resolveCEA = jest.fn(async () => ({ + cea: getAddress('0x000000000000000000000000000000000000cea1'), + isDeployed: true, + })); + const rt = mockRuntime(s.fake, { + signer: ADDR.agent, + resolveCEA, + resolvePrc20: () => token, + }); + const tx = await agenticSend(rt, s.ctx, send(BigInt(100))); + expect(resolveCEA).toHaveBeenCalledWith( + s.w.address, + CHAIN.ETHEREUM_SEPOLIA + ); + const outer = v5.decodeWalletCall(rt.executeMock.mock.calls[0][0].data) as { + kind: string; + rulesId: Hex; + calls: { target: Address; value: bigint; data: Hex }[]; + }; + expect(outer.kind).toBe('executeAsAgent'); + expect(outer.rulesId).toBe(ruleId(5)); + expect(outer.calls[0].target).toBe(ADDR.gateway); + expect(outer.calls[0].value).toBe(BigInt(1100)); + const { args } = decodeFunctionData({ + abi: UNIVERSAL_GATEWAY_PC, + data: outer.calls[0].data, + }); + expect(args[0]).toMatchObject({ + recipient: '0x', + token, + amount: BigInt(100), + maxPCForGas: BigInt(1000), + revertRecipient: s.w.address, + }); + expect((args[0] as { payload: Hex }).payload.startsWith('0x2cc2842d')).toBe( + true + ); + expect(tx).toMatchObject({ + from: s.w.address, + to: token, + data: encodeFunctionData({ + abi: ERC20_EVM, + functionName: 'transfer', + args: [ADDR.target, BigInt(100)], + }), + route: 'UOA_TO_CEA', + chain: CHAIN.ETHEREUM_SEPOLIA, + }); + expect(tx.agentic?.destinationCalls).toHaveLength(2); + expect(tx.agentic?.destinationAccount).toBe( + getAddress('0x000000000000000000000000000000000000cea1') + ); + }); + + it('never injects an approval into the agent path; missing allowance fails before signing', async () => { + const s = universalSetup(); + s.fake.balances.set(`allowance:${token.toLowerCase()}`, BigInt(10)); + const rt = mockRuntime(s.fake, { + signer: ADDR.agent, + resolvePrc20: () => token, + }); + await expect( + agenticSend(rt, s.ctx, send(BigInt(100))) + ).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.GATEWAY_ALLOWANCE_INSUFFICIENT, + }); + expect(rt.executeMock).not.toHaveBeenCalled(); + }); + + it('wallet funding is checked locally; rule PC limits are enforced by the contract', async () => { + const s = universalSetup(); + s.fake.balances.set(`pc:${s.w.address.toLowerCase()}`, BigInt(10)); + const rt = mockRuntime(s.fake, { + signer: ADDR.agent, + resolvePrc20: () => token, + }); + await expect(agenticSend(rt, s.ctx, send())).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.WALLET_BALANCE_INSUFFICIENT, + }); + const s2 = universalSetup(); + const pricey = mockRuntime(s2.fake, { + signer: ADDR.agent, + resolvePrc20: () => token, + quoteOutbound: async () => ({ + protocolFee: BigInt(100), + nativeValueForGas: BigInt(10_000), + gasLimitUsed: BigInt(1), + }), + }); + const response = await agenticSend(pricey, s2.ctx, send()); + expect(pricey.executeMock).toHaveBeenCalledTimes(1); + expect(response.agentic?.rulesId).toBe(ruleId(5)); + }); + + it('a committed destination account that no longer matches derivation is drift, not a send', async () => { + const s = universalSetup(); + const rt = mockRuntime(s.fake, { + signer: ADDR.agent, + resolvePrc20: () => token, + resolveCEA: async () => ({ + cea: getAddress('0x000000000000000000000000000000000000dead'), + isDeployed: true, + }), + }); + await expect(agenticSend(rt, s.ctx, send())).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.INCONSISTENT_READ, + }); + }); + + it('a zero gas quote is refused (URP rejects an uncapped gas swap)', async () => { + const s = universalSetup(); + const rt = mockRuntime(s.fake, { + signer: ADDR.agent, + resolvePrc20: () => token, + quoteOutbound: async () => ({ + protocolFee: BigInt(1), + nativeValueForGas: BigInt(0), + gasLimitUsed: BigInt(1), + }), + }); + await expect(agenticSend(rt, s.ctx, send())).rejects.toThrow( + /uncapped gas swap/ + ); + }); + + it('SVM destinations reject EVM-width program addresses', async () => { + const s = universalSetup(); + const rt = mockRuntime(s.fake, { signer: ADDR.agent }); + await expect( + agenticSend( + rt, + { ...s.ctx, door: 'owner' }, + { to: { address: ADDR.target, chain: CHAIN.SOLANA_DEVNET }, data } + ) + ).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.INVALID_RULE, + }); + }); + + it('owner door never writes an allowance: it sends only the outbound and consumes the existing allowance', async () => { + const s = universalSetup(); + s.ctx.door = 'owner'; + s.ctx.signerPushAccount = ADDR.owner; + const rt = mockRuntime(s.fake, { + signer: ADDR.owner, + resolvePrc20: () => token, + }); + await agenticSend(rt, s.ctx, send(BigInt(100))); + const outer = v5.decodeWalletCall(rt.executeMock.mock.calls[0][0].data) as { + kind: string; + calls: { target: Address; data: Hex }[]; + }; + expect(outer.kind).toBe('execute'); + expect(outer.calls.map((c) => c.target)).toEqual([ADDR.gateway]); + }); + + it('owner door with too small an allowance fails before signing (no implicit approval)', async () => { + const s = universalSetup(); + s.ctx.door = 'owner'; + s.ctx.signerPushAccount = ADDR.owner; + s.fake.balances.set(`allowance:${token.toLowerCase()}`, BigInt(10)); + const rt = mockRuntime(s.fake, { + signer: ADDR.owner, + resolvePrc20: () => token, + }); + await expect( + agenticSend(rt, s.ctx, send(BigInt(100))) + ).rejects.toMatchObject({ + code: AGENTIC_ERROR_CODE.GATEWAY_ALLOWANCE_INSUFFICIENT, + }); + expect(rt.executeMock).not.toHaveBeenCalled(); + }); + + it('an existing unlimited allowance is consumed as-is', async () => { + const s = universalSetup(); + s.ctx.door = 'owner'; + s.ctx.signerPushAccount = ADDR.owner; + s.fake.balances.set(`allowance:${token.toLowerCase()}`, maxUint256); + const rt = mockRuntime(s.fake, { + signer: ADDR.owner, + resolvePrc20: () => token, + }); + await expect( + agenticSend(rt, s.ctx, send(BigInt(100))) + ).resolves.toBeDefined(); + }); + + it('a transfer-only ERC-20 outbound instructs a transfer to the requested recipient', async () => { + const s = universalSetup(); + s.ctx.door = 'owner'; + s.ctx.signerPushAccount = ADDR.owner; + const rt = mockRuntime(s.fake, { + signer: ADDR.owner, + resolvePrc20: () => token, + }); + const recipient = getAddress('0x00000000000000000000000000000000000ab0b0'); + const usdc = { + symbol: 'USDC', + decimals: 6, + address: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238', + mechanism: 'approve' as const, + }; + const tx = await agenticSend(rt, s.ctx, { + to: { address: recipient, chain: CHAIN.ETHEREUM_SEPOLIA }, + funds: { amount: BigInt(100), token: usdc }, + }); + const outer = v5.decodeWalletCall(rt.executeMock.mock.calls[0][0].data) as { + calls: { data: Hex }[]; + }; + const { args } = decodeFunctionData({ + abi: UNIVERSAL_GATEWAY_PC, + data: outer.calls[0].data, + }); + const payload = (args[0] as { payload: Hex }).payload; + const [calls] = decodeAbiParameters( + [ + { + type: 'tuple[]', + components: [ + { name: 'to', type: 'address' }, + { name: 'value', type: 'uint256' }, + { name: 'data', type: 'bytes' }, + ], + }, + ], + `0x${payload.slice(10)}` + ); + expect(calls).toHaveLength(1); + expect(getAddress(calls[0].to)).toBe(getAddress(usdc.address)); + expect( + decodeFunctionData({ abi: ERC20_EVM, data: calls[0].data }).args + ).toEqual([recipient, BigInt(100)]); + expect(tx.to).toBe(getAddress(usdc.address)); + expect(tx.data).toBe(calls[0].data); + expect(tx.agentic?.destinationCalls).toEqual( + calls.map((c) => ({ ...c, to: getAddress(c.to) })) + ); + }); + + it('a value-only outbound burns the native PRC20 for that value and forwards it to the recipient', async () => { + const s = universalSetup(); + s.ctx.door = 'owner'; + s.ctx.signerPushAccount = ADDR.owner; + const native = getAddress('0x0000000000000000000000000000000000000e7e'); + s.fake.balances.set(`balanceOf:${native.toLowerCase()}`, BigInt(1000)); + s.fake.balances.set(`allowance:${native.toLowerCase()}`, BigInt(1000)); + const rt = mockRuntime(s.fake, { + signer: ADDR.owner, + resolvePrc20: () => native, + }); + await agenticSend(rt, s.ctx, { + to: { address: ADDR.other, chain: CHAIN.ETHEREUM_SEPOLIA }, + value: BigInt(7), + }); + const outer = v5.decodeWalletCall(rt.executeMock.mock.calls[0][0].data) as { + calls: { data: Hex }[]; + }; + const req = decodeFunctionData({ + abi: UNIVERSAL_GATEWAY_PC, + data: outer.calls[0].data, + }).args[0] as { amount: bigint; payload: Hex }; + expect(req.amount).toBe(BigInt(7)); + expect(req.payload.toLowerCase()).toContain( + ADDR.other.slice(2).toLowerCase() + ); + }); + + it('an outbound with no destination call (parking in the CEA) is refused before signing', async () => { + const s = universalSetup(); + s.ctx.door = 'owner'; + s.ctx.signerPushAccount = ADDR.owner; + const cea = getAddress('0x000000000000000000000000000000000000cea1'); + const rt = mockRuntime(s.fake, { + signer: ADDR.owner, + resolvePrc20: () => token, + resolveCEA: async () => ({ cea, isDeployed: true }), + }); + await expect( + agenticSend(rt, s.ctx, { + to: { address: cea, chain: CHAIN.ETHEREUM_SEPOLIA }, + value: BigInt(1), + }) + ).rejects.toThrow(/no destination call/); + expect(rt.executeMock).not.toHaveBeenCalled(); + }); + + it('an agent value-only destination call is refused before signing (the policy admits only allow-listed calls)', async () => { + const s = universalSetup(); + const rt = mockRuntime(s.fake, { + signer: ADDR.agent, + resolvePrc20: () => token, + }); + await expect( + agenticSend(rt, s.ctx, { + to: { address: ADDR.other, chain: CHAIN.ETHEREUM_SEPOLIA }, + funds: { + amount: BigInt(1), + token: { + symbol: 'X', + decimals: 6, + address: token, + mechanism: 'native', + }, + }, + }) + ).rejects.toThrow(/no function selector/); + }); + + it('more than 10 destination calls are refused', async () => { + const s = universalSetup(); + const rt = mockRuntime(s.fake, { + signer: ADDR.agent, + resolvePrc20: () => token, + }); + await expect( + agenticSend(rt, s.ctx, { + to: { address: ADDR.target, chain: CHAIN.ETHEREUM_SEPOLIA }, + data: Array.from({ length: 11 }, () => ({ + to: ADDR.target, + value: BigInt(0), + data, + })), + }) + ).rejects.toThrow(/at most 10/); + }); +}); diff --git a/packages/core/src/lib/agentic/__tests__/svm-backend.spec.ts b/packages/core/src/lib/agentic/__tests__/svm-backend.spec.ts new file mode 100644 index 00000000..28e76662 --- /dev/null +++ b/packages/core/src/lib/agentic/__tests__/svm-backend.spec.ts @@ -0,0 +1,323 @@ +import { PublicKey } from '@solana/web3.js'; +import { bytesToHex, type Hex } from 'viem'; +import { CHAIN } from '../../constants/enums'; +import { createSvmMetadataProvider } from '../management/svm-metadata'; +import { resolveSvmContext } from '../management/svm-context'; +import { Snapshot } from '../reads/snapshot'; +import { + registerIdl, + clearRegistry, +} from '../../orchestrator/svm-idl/registry'; +import { prepareAgwSvmInstruction } from '../execution/svm-instruction'; +import { + deriveAgwSvmValueAccounts, + deriveAgwSvmAta, +} from '../codec/svm-accounts'; +import { ADDR, FakeChain } from './fake-chain'; +import type { SvmTermsWire } from '../codec/svm-terms'; +const key = (b: string) => `0x${b.repeat(32)}` as Hex; +const SPL = 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'; +const TOKEN2022 = 'TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb'; +const MINT = new PublicKey(Buffer.from(key('44').slice(2), 'hex')); +const PROGRAM = key('33'), + GATEWAY = key('22'); +const genesis = CHAIN.SOLANA_DEVNET.slice(7) + 'abcdefghijk'; +function rpc(owner = SPL, length = 82) { + const data = Buffer.alloc(length); + data[45] = 1; + if (length >= 166) data[165] = 1; + return { + getGenesisHash: jest.fn().mockResolvedValue(genesis), + getAccountInfo: jest.fn().mockResolvedValue({ + owner: new PublicKey(owner), + executable: false, + data, + lamports: 1, + rentEpoch: 0, + }), + }; +} +afterEach(clearRegistry); +describe('SVM metadata and resolved instruction backend', () => { + it.each(['dataless', 'non-anchor', 'wrong-account'])( + 'validates explicit wire accounts for %s instructions', + (kind) => { + const derived = deriveAgwSvmValueAccounts(ADDR.owner, GATEWAY, []); + const dataless = kind === 'dataless'; + const terms: SvmTermsWire = { + ...derived, + validUntil: 9999999999, + assets: [ + { token: ADDR.target, maxPerCall: BigInt(1), maxTotal: BigInt(2) }, + ], + maxGasPerCall: BigInt(10), + programs: [ + { + program: PROGRAM, + discriminator: '0x0100000000000000', + discriminatorLen: dataless ? 0 : 1, + dataless, + maxAccounts: 1, + }, + ], + pins: [ + { ruleIndex: 0, accountIndex: 0, expected: derived.expectedCEA }, + ], + dataPins: [], + }; + const build = () => + prepareAgwSvmInstruction( + { + wallet: ADDR.owner, + chain: CHAIN.SOLANA_DEVNET, + program: PROGRAM, + instructionData: dataless ? new Uint8Array() : new Uint8Array([1]), + accounts: [ + { + pubkey: + kind === 'wrong-account' ? key('66') : derived.expectedCEA, + isWritable: true, + }, + ], + }, + terms + ); + if (kind === 'wrong-account') + expect(build).toThrow('SvmAccountPinMismatch'); + else expect(build().recipient).toBe(PROGRAM); + } + ); + it.each([false, true])( + 'resolves output mint Token-2022 ownership, rejecting a wrong supplied program: %s', + async (wrong) => { + const fake = new FakeChain(); + fake.readContract = async ({ functionName }) => + functionName === 'gasTokenPRC20ByChainNamespace' + ? ADDR.other + : functionName === 'SOURCE_CHAIN_NAMESPACE' + ? CHAIN.SOLANA_DEVNET + : ''; + const mint = key('55'); + const metadata = { + gateway: async () => ({ + chainNamespace: CHAIN.SOLANA_DEVNET, + program: GATEWAY, + }), + mint: async () => ({ mint, tokenProgram: TOKEN2022 }), + }; + const promise = resolveSvmContext( + new Snapshot(fake, BigInt(1)), + ADDR.owner, + CHAIN.SOLANA_DEVNET, + [{ token: ADDR.other, maxPerCall: BigInt(1), maxTotal: BigInt(2) }], + metadata, + [{ mint, ...(wrong ? { tokenProgram: SPL } : {}) }] + ); + if (wrong) + await expect(promise).rejects.toThrow( + 'output mint/token-program mismatch' + ); + else { + const ctx = await promise; + expect(ctx.ceaAccounts).toEqual([ + ctx.expectedCEA, + deriveAgwSvmAta(ctx.expectedCEA, { mint, tokenProgram: TOKEN2022 }), + ]); + } + } + ); + it.each([ + [SPL, 82], + [TOKEN2022, 82], + [TOKEN2022, 166], + ])('reads initialized mint owner %s length %s', async (owner, length) => { + const r = rpc(owner, length); + const provider = createSvmMetadataProvider( + { + [CHAIN.SOLANA_DEVNET]: { + gatewayProgram: GATEWAY, + rpcUrls: ['http://fixture'], + }, + }, + () => r + ); + expect( + await provider.mint(CHAIN.SOLANA_DEVNET, bytesToHex(MINT.toBytes())) + ).toEqual({ mint: MINT.toBase58(), tokenProgram: owner }); + expect(await provider.gateway(CHAIN.SOLANA_DEVNET)).toEqual({ + chainNamespace: CHAIN.SOLANA_DEVNET, + program: GATEWAY, + }); + }); + it('rejects wrong cluster RPCs and falls back to the configured correct cluster', async () => { + const wrong = rpc(), + correct = rpc(); + wrong.getGenesisHash.mockResolvedValue('wrong-genesis'); + const provider = createSvmMetadataProvider( + { + [CHAIN.SOLANA_DEVNET]: { + gatewayProgram: GATEWAY, + rpcUrls: ['wrong', 'right'], + }, + }, + (url) => (url === 'wrong' ? wrong : correct) + ); + await provider.mint(CHAIN.SOLANA_DEVNET, bytesToHex(MINT.toBytes())); + expect(wrong.getAccountInfo).not.toHaveBeenCalled(); + expect(correct.getAccountInfo).toHaveBeenCalledTimes(1); + }); + it.each([ + 'missing', + 'executable', + 'token-account', + 'uninitialized', + 'wrong-owner', + ])('rejects %s as a mint', async (kind) => { + const r = rpc(), + info = await r.getAccountInfo(); + if (kind === 'missing') r.getAccountInfo.mockResolvedValue(null); + else { + if (kind === 'executable') info.executable = true; + if (kind === 'token-account') info.data = Buffer.alloc(165); + if (kind === 'uninitialized') info.data[45] = 0; + if (kind === 'wrong-owner') info.owner = PublicKey.default; + r.getAccountInfo.mockResolvedValue(info); + } + const p = createSvmMetadataProvider( + { + [CHAIN.SOLANA_DEVNET]: { + gatewayProgram: GATEWAY, + rpcUrls: ['fixture'], + }, + }, + () => r + ); + await expect( + p.mint(CHAIN.SOLANA_DEVNET, bytesToHex(MINT.toBytes())) + ).rejects.toMatchObject({ code: 'INVALID_RULE' }); + }); + it('requires a configured gateway/RPC, rather than choosing a devnet default', async () => { + await expect( + createSvmMetadataProvider({}).gateway(CHAIN.SOLANA_DEVNET) + ).rejects.toMatchObject({ code: 'INVALID_RULE' }); + }); + it('pins all PRC20 reads and rejects a source-chain mismatch', async () => { + const fake = new FakeChain(); + fake.readContract = jest.fn(async ({ functionName }) => + functionName === 'gasTokenPRC20ByChainNamespace' + ? ADDR.other + : CHAIN.ETHEREUM_SEPOLIA + ); + const snap = new Snapshot(fake, BigInt(123)); + const metadata = { + gateway: async () => ({ + chainNamespace: CHAIN.SOLANA_DEVNET, + program: GATEWAY, + }), + mint: jest.fn(), + }; + await expect( + resolveSvmContext( + snap, + ADDR.owner, + CHAIN.SOLANA_DEVNET, + [{ token: ADDR.target, maxPerCall: BigInt(1), maxTotal: BigInt(2) }], + metadata + ) + ).rejects.toMatchObject({ code: 'ASSET_CHAIN_MISMATCH' }); + expect( + (fake.readContract as jest.Mock).mock.calls.every( + ([arg]) => arg.blockNumber === BigInt(123) + ) + ).toBe(true); + }); + it('rejects registry and mint substitution', async () => { + const fake = new FakeChain(); + fake.readContract = async ({ functionName }) => + functionName === 'gasTokenPRC20ByChainNamespace' + ? ADDR.other + : functionName === 'SOURCE_CHAIN_NAMESPACE' + ? CHAIN.SOLANA_DEVNET + : MINT.toBase58(); + const snap = new Snapshot(fake, BigInt(1)), + caps = [ + { token: ADDR.target, maxPerCall: BigInt(1), maxTotal: BigInt(2) }, + ]; + await expect( + resolveSvmContext(snap, ADDR.owner, CHAIN.SOLANA_DEVNET, caps, { + gateway: async () => ({ + chainNamespace: CHAIN.SOLANA_TESTNET, + program: GATEWAY, + }), + mint: jest.fn(), + }) + ).rejects.toThrow('cluster mismatch'); + await expect( + resolveSvmContext(snap, ADDR.owner, CHAIN.SOLANA_DEVNET, caps, { + gateway: async () => ({ + chainNamespace: CHAIN.SOLANA_DEVNET, + program: GATEWAY, + }), + mint: async () => ({ mint: key('55'), tokenProgram: SPL }), + }) + ).rejects.toThrow('different mint'); + }); + it('derives the wallet authority for IDL accounts, not the signer/default gateway authority', () => { + const derived = deriveAgwSvmValueAccounts(ADDR.owner, GATEWAY, []); + const program = new PublicKey( + Buffer.from(PROGRAM.slice(2), 'hex') + ).toBase58(); + registerIdl({ + address: program, + metadata: { name: 'fixture', version: '1', spec: '0.1.0' }, + instructions: [ + { + name: 'go', + discriminator: [1, 2, 3, 4, 5, 6, 7, 8], + accounts: [{ name: 'cea_authority', writable: true }], + args: [], + }, + ], + }); + const t: SvmTermsWire = { + ...derived, + validUntil: 9999999999, + assets: [ + { token: ADDR.target, maxPerCall: BigInt(1), maxTotal: BigInt(2) }, + ], + maxGasPerCall: BigInt(10), + programs: [ + { + program: PROGRAM, + discriminator: '0x0102030405060708', + discriminatorLen: 8, + dataless: false, + maxAccounts: 1, + }, + ], + pins: [{ ruleIndex: 0, accountIndex: 0, expected: derived.expectedCEA }], + dataPins: [], + }; + const out = prepareAgwSvmInstruction( + { + wallet: ADDR.owner, + chain: CHAIN.SOLANA_DEVNET, + program, + instructionData: new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]), + }, + t + ); + expect(out.accounts[0].pubkey).toBe(derived.expectedCEA); + expect(() => + prepareAgwSvmInstruction( + { + wallet: ADDR.owner, + chain: CHAIN.SOLANA_DEVNET, + program, + instructionData: new Uint8Array([9, 2, 3, 4, 5, 6, 7, 8]), + }, + t + ) + ).toThrow(/discriminator/); + }); +}); diff --git a/packages/core/src/lib/agentic/__tests__/svm-idl.spec.ts b/packages/core/src/lib/agentic/__tests__/svm-idl.spec.ts new file mode 100644 index 00000000..e752336d --- /dev/null +++ b/packages/core/src/lib/agentic/__tests__/svm-idl.spec.ts @@ -0,0 +1,177 @@ +import type { Idl } from '@coral-xyz/anchor'; +import { PublicKey } from '@solana/web3.js'; +import { encodeAnchorIxData } from '../../orchestrator/svm-idl/ix-encoder'; +import type { SolanaRule } from '../agentic.types'; +import { compileSvmIdlRule, type SvmResolvedContext } from '../codec/svm-idl'; +import { SvmDataPinMode } from '../codec/svm-terms'; +import { + encodeAgwSvmPayload, + validateAgwSvmPayload, +} from '../execution/svm-payload'; +import { ADDR } from './fake-chain'; +import type { Hex } from 'viem'; +const key = (c: string) => `0x${c.repeat(64)}` as Hex; +const program = key('3'), + cea = key('4'), + mint = key('5'), + ata = key('6'); +const idl: Idl = { + address: new PublicKey(Buffer.from(program.slice(2), 'hex')).toBase58(), + metadata: { name: 'test', version: '1', spec: '0.1.0' }, + instructions: [ + { + name: 'deposit', + discriminator: [1, 2, 3, 4, 5, 6, 7, 8], + accounts: [ + { name: 'cea', writable: true }, + { name: 'token', writable: true }, + ], + args: [ + { name: 'flag', type: 'u8' }, + { name: 'amount', type: 'u64' }, + { name: 'minimum', type: 'u64' }, + ], + }, + ], +}; +const ctx: SvmResolvedContext = { + expectedCEA: cea, + gatewayProgram: key('2'), + ceaAccounts: [cea, ata], + assets: [ + { token: ADDR.target, maxPerCall: BigInt(10), maxTotal: BigInt(100) }, + ], + tokenAccounts: new Map([[mint, ata]]), +}; +const input = (): SolanaRule => ({ + agent: ADDR.agent, + chainNamespace: 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1', + validUntil: 100, + assets: [], + maxGasPerCall: BigInt(10), + allowedInstructions: [ + { + program, + instruction: { idl, name: 'deposit' }, + accounts: [ + { name: 'cea', expected: { kind: 'walletCEA' } }, + { name: 'token', expected: { kind: 'walletATA', token: mint } }, + ], + fields: [ + { name: 'flag', equals: BigInt(1) }, + { name: 'amount', max: BigInt(10) }, + { + numerator: 'amount', + denominator: 'minimum', + minRatio: { num: BigInt(2), den: BigInt(1) }, + }, + ], + }, + ], +}); +describe('named SVM IDL rule compilation', () => { + it('enforces named constraints against independently Borsh-encoded data', () => { + const terms = compileSvmIdlRule(input(), ctx, 0); + expect(terms.pins.map((p) => p.expected)).toEqual([cea, ata]); + expect(terms.dataPins.map((p) => [p.offset, p.len, p.mode])).toEqual([ + [8, 1, SvmDataPinMode.EQ], + [9, 8, SvmDataPinMode.LTE_LE], + [9, 8, SvmDataPinMode.RATIO_GTE_LE], + ]); + const payload = (amount: bigint, minimum: bigint) => + encodeAgwSvmPayload( + program, + [ + { pubkey: cea, isWritable: true }, + { pubkey: ata, isWritable: true }, + ], + encodeAnchorIxData(idl, 'deposit', [1, amount, minimum]) + ); + expect( + validateAgwSvmPayload(terms, program, payload(BigInt(10), BigInt(5))) + ).toBe(0); + expect(() => + validateAgwSvmPayload(terms, program, payload(BigInt(11), BigInt(5))) + ).toThrow('SvmDataCeilingExceeded'); + expect(() => + validateAgwSvmPayload(terms, program, payload(BigInt(9), BigInt(5))) + ).toThrow('SvmDataRatioNotMet'); + }); + it.each([ + [ + 'unknown account', + (r: SolanaRule) => { + r.allowedInstructions[0].accounts[0].name = 'wrong'; + }, + ], + [ + 'unlisted ATA', + (r: SolanaRule) => { + r.allowedInstructions[0].accounts[1].expected = { + kind: 'walletATA', + token: key('7'), + }; + }, + ], + [ + 'unknown field', + (r: SolanaRule) => { + r.allowedInstructions[0].fields = [{ name: 'wrong', max: BigInt(2) }]; + }, + ], + [ + 'overflow', + (r: SolanaRule) => { + r.allowedInstructions[0].fields = [{ name: 'flag', max: BigInt(256) }]; + }, + ], + [ + 'duplicate instruction', + (r: SolanaRule) => { + r.allowedInstructions.push(r.allowedInstructions[0]); + }, + ], + [ + 'mismatched program', + (r: SolanaRule) => { + r.allowedInstructions[0].program = key('8'); + }, + ], + [ + 'conflicting comparison', + (r: SolanaRule) => { + r.allowedInstructions[0].fields = [ + { name: 'flag', min: BigInt(0), max: BigInt(1) } as never, + ]; + }, + ], + ])('rejects %s', (_name, mutate) => { + const r = input(); + mutate(r); + expect(() => compileSvmIdlRule(r, ctx, 0)).toThrow(); + }); + it.each(['bytes', 'string', { vec: 'u8' }, { defined: { name: 'Unknown' } }])( + 'refuses unsupported layouts %j', + (type) => { + const r = input(); + r.allowedInstructions[0].instruction.idl = { + ...idl, + instructions: [ + { + ...idl.instructions[0], + args: [ + { name: 'prefix', type: type as never }, + ...idl.instructions[0].args, + ], + }, + ], + }; + expect(() => compileSvmIdlRule(r, ctx, 0)).toThrow('layout'); + } + ); + it('does not mutate the caller IDL', () => { + const before = JSON.stringify(idl); + compileSvmIdlRule(input(), ctx, 0); + expect(JSON.stringify(idl)).toBe(before); + }); +}); diff --git a/packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts b/packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts new file mode 100644 index 00000000..0d7317fc --- /dev/null +++ b/packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts @@ -0,0 +1,502 @@ +import { PublicKey } from '@solana/web3.js'; +import { bytesToHex, hexToBytes, numberToHex, type Hex } from 'viem'; +import { + decodeSvmTerms, + encodeSvmTerms, + validateSvmTerms, + SvmDataPinMode, + type SvmTermsWire, +} from '../codec/svm-terms'; +import { + deriveAgwSvmAta, + deriveAgwSvmCea, + deriveAgwSvmValueAccounts, + svmKey, + resolveAgwSvmRuleContext, +} from '../codec/svm-accounts'; +import { + encodeAgwSvmPayload, + parseAgwSvmPayload, + validateAgwSvmPayload, +} from '../execution/svm-payload'; +import { composeAgwSvmAction } from '../execution/svm-outbound'; +import { decodeFunctionData } from 'viem'; +import { UNIVERSAL_GATEWAY_PC } from '../../constants/abi'; +import { encodeSvmExecutePayload } from '../../orchestrator/payload-builders'; +import { ADDR } from './fake-chain'; + +const key = (byte: string) => `0x${byte.repeat(32)}` as Hex; +const CEA = key('11'), + GATEWAY = key('22'), + PROGRAM = key('33'), + ATA = key('44'); +const NOW = 1_700_000_000; +const base = (): SvmTermsWire => ({ + validUntil: NOW + 60, + expectedCEA: CEA, + gatewayProgram: GATEWAY, + assets: [{ token: ADDR.target, maxPerCall: BigInt(5), maxTotal: BigInt(10) }], + maxGasPerCall: BigInt(20), + ceaAccounts: [CEA, ATA], + programs: [ + { + program: PROGRAM, + discriminator: '0x0100000000000000', + discriminatorLen: 1, + dataless: false, + maxAccounts: 2, + }, + ], + pins: [ + { ruleIndex: 0, accountIndex: 0, expected: CEA }, + { ruleIndex: 0, accountIndex: 1, expected: ATA }, + ], + dataPins: [], +}); +const accounts = [ + { pubkey: CEA, isWritable: true }, + { pubkey: ATA, isWritable: true }, +]; + +describe('v5 internal SVM wire codec', () => { + it('round-trips ordered per-token caps and all four data-pin modes', () => { + const t = base(); + t.dataPins = [ + { + ruleIndex: 0, + fromEnd: false, + offset: 0, + offsetB: 0, + len: 1, + mode: 0, + expected: key('00'), + num: BigInt(0), + den: BigInt(0), + }, + { + ruleIndex: 0, + fromEnd: true, + offset: 8, + offsetB: 0, + len: 8, + mode: 1, + expected: numberToHex(5, { size: 32 }), + num: BigInt(0), + den: BigInt(0), + }, + { + ruleIndex: 0, + fromEnd: false, + offset: 1, + offsetB: 0, + len: 2, + mode: 2, + expected: numberToHex(65535, { size: 32 }), + num: BigInt(0), + den: BigInt(0), + }, + { + ruleIndex: 0, + fromEnd: true, + offset: 16, + offsetB: 8, + len: 8, + mode: 3, + expected: key('00'), + num: BigInt(9), + den: BigInt(10), + }, + ]; + t.assets = [ + ...t.assets, + { token: ADDR.other, maxPerCall: BigInt(0), maxTotal: BigInt(0) }, + ]; + expect(decodeSvmTerms(encodeSvmTerms(t, NOW))).toEqual(t); + }); + it.each([ + [ + 'expired', + (t: SvmTermsWire) => { + t.validUntil = NOW; + }, + ], + [ + 'zero CEA', + (t: SvmTermsWire) => { + t.expectedCEA = key('00'); + }, + ], + [ + 'empty assets', + (t: SvmTermsWire) => { + t.assets = []; + }, + ], + [ + 'duplicate tokens', + (t: SvmTermsWire) => { + t.assets = [t.assets[0], t.assets[0]]; + }, + ], + [ + 'system program', + (t: SvmTermsWire) => { + t.programs = [{ ...t.programs[0], program: key('00') }]; + }, + ], + [ + 'ambiguous prefixes', + (t: SvmTermsWire) => { + t.programs = [ + ...t.programs, + { + ...t.programs[0], + discriminator: '0x0102000000000000', + discriminatorLen: 2, + }, + ]; + }, + ], + [ + 'missing pin', + (t: SvmTermsWire) => { + t.pins = []; + }, + ], + [ + 'duplicate pin', + (t: SvmTermsWire) => { + t.pins = [t.pins[0], t.pins[0]]; + }, + ], + [ + 'CEA absent', + (t: SvmTermsWire) => { + t.ceaAccounts = [ATA]; + }, + ], + [ + 'fixed count outside bound', + (t: SvmTermsWire) => { + t.programs = [{ ...t.programs[0], maxAccounts: 65 }]; + }, + ], + ])('rejects %s before encoding', (_name, change) => { + const t = base(); + change(t); + expect(() => encodeSvmTerms(t, NOW)).toThrow( + expect.objectContaining({ code: 'INVALID_RULE' }) + ); + }); + it('refuses misleading integer/raw alignment and zero ratio denominators', () => { + const t = base(); + const p = { + ruleIndex: 0, + fromEnd: false, + offset: 1, + offsetB: 3, + len: 2, + mode: SvmDataPinMode.EQ, + expected: numberToHex(5, { size: 32 }), + num: BigInt(0), + den: BigInt(0), + }; + t.dataPins = [p]; + expect(() => validateSvmTerms(t, NOW)).toThrow(/left-aligned/); + t.dataPins = [ + { + ...p, + mode: SvmDataPinMode.GTE_LE, + expected: numberToHex(65536, { size: 32 }), + }, + ]; + expect(() => validateSvmTerms(t, NOW)).toThrow(/width/); + t.dataPins = [ + { + ...p, + mode: SvmDataPinMode.RATIO_GTE_LE, + num: BigInt(1), + den: BigInt(0), + }, + ]; + expect(() => validateSvmTerms(t, NOW)).toThrow(/ratio/); + }); +}); + +describe('wallet-scoped SVM value accounts', () => { + it('derives the exact PDA from wallet20 and the selected gateway', () => { + const result = deriveAgwSvmCea(ADDR.owner, GATEWAY); + const [expected, bump] = PublicKey.findProgramAddressSync( + [Buffer.from('push_identity'), Buffer.from(hexToBytes(ADDR.owner))], + new PublicKey(hexToBytes(GATEWAY)) + ); + expect(result).toEqual({ address: bytesToHex(expected.toBytes()), bump }); + expect(deriveAgwSvmCea(ADDR.agent, GATEWAY).address).not.toBe( + result.address + ); + expect(deriveAgwSvmCea(ADDR.owner, PROGRAM).address).not.toBe( + result.address + ); + expect(PublicKey.isOnCurve(hexToBytes(result.address))).toBe(false); + }); + it('resolved token caps cannot omit their corresponding protected ATAs', () => { + const cap = { + token: ADDR.target, + maxPerCall: BigInt(1), + maxTotal: BigInt(2), + }; + const result = resolveAgwSvmRuleContext( + ADDR.owner, + GATEWAY, + [ + { kind: 'native', cap }, + { kind: 'spl', cap: { ...cap, token: ADDR.other }, mint: PROGRAM }, + ], + [{ mint: ATA }] + ); + expect(result.ceaAccounts).toHaveLength(3); + expect(result.assets.map((a) => a.token)).toEqual([ + ADDR.target, + ADDR.other, + ]); + expect(() => deriveAgwSvmCea(ADDR.owner, key('00'))).toThrow( + /gateway program/ + ); + }); + it('includes input/output ATAs, deduplicates, and separates Token-2022 accounts', () => { + const t = { mint: PROGRAM }, + output = { mint: ATA }; + const derived = deriveAgwSvmValueAccounts( + ADDR.owner, + GATEWAY, + [t, t], + [output] + ); + expect(derived.ceaAccounts).toEqual([ + derived.expectedCEA, + deriveAgwSvmAta(derived.expectedCEA, t), + deriveAgwSvmAta(derived.expectedCEA, output), + ]); + const legacy = deriveAgwSvmAta(derived.expectedCEA, t), + token2022 = deriveAgwSvmAta(derived.expectedCEA, { + ...t, + tokenProgram: 'TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb', + }); + expect(token2022).not.toBe(legacy); + expect(svmKey(new PublicKey(hexToBytes(PROGRAM)).toBase58())).toBe(PROGRAM); + expect(() => + deriveAgwSvmAta(derived.expectedCEA, { mint: key('00') }) + ).toThrow(/native SOL/); + }); +}); + +describe('S12–S18 payload checks', () => { + it('matches the existing node encoder and parses every byte including writable flags', () => { + const payload = encodeAgwSvmPayload( + PROGRAM, + accounts, + new Uint8Array([1, 2, 3]) + ); + expect(payload).toBe( + encodeSvmExecutePayload({ + targetProgram: PROGRAM, + accounts, + ixData: new Uint8Array([1, 2, 3]), + instructionId: 2, + }) + ); + expect(parseAgwSvmPayload(payload)).toMatchObject({ + program: PROGRAM, + instructionData: new Uint8Array([1, 2, 3]), + accounts: [ + { pubkey: CEA, writableFlag: 1 }, + { pubkey: ATA, writableFlag: 1 }, + ], + }); + expect(validateAgwSvmPayload(base(), PROGRAM, payload)).toBe(0); + const raw = hexToBytes(payload); + raw[36] = 7; + expect(parseAgwSvmPayload(bytesToHex(raw)).accounts[0].writableFlag).toBe( + 7 + ); + expect(validateAgwSvmPayload(base(), PROGRAM, bytesToHex(raw))).toBe(0); // URP deliberately ignores flags. + }); + it.each([ + ['trailing data', (p: Hex) => `${p}00` as Hex, 'MalformedSvmPayload'], + ['truncated', (p: Hex) => p.slice(0, -2) as Hex, 'MalformedSvmPayload'], + [ + 'oversized count', + (p: Hex) => `0x00000041${p.slice(10)}` as Hex, + 'SvmAccountsOutOfRange', + ], + ])( + 'rejects %s with the corresponding contract error', + (_name, mutate, error) => { + const p = encodeAgwSvmPayload(PROGRAM, accounts, new Uint8Array([1])); + expect(() => parseAgwSvmPayload(mutate(p))).toThrow( + expect.objectContaining({ details: { contractError: error } }) + ); + } + ); + it('pins prevent key substitution and protected-account aliasing', () => { + const t = base(); + expect(() => + validateAgwSvmPayload( + t, + PROGRAM, + encodeAgwSvmPayload( + PROGRAM, + [{ ...accounts[0], pubkey: GATEWAY }, accounts[1]], + new Uint8Array([1]) + ) + ) + ).toThrow(/SvmAccountPinMismatch/); + t.programs = [{ ...t.programs[0], maxAccounts: 0 }]; + expect(() => + validateAgwSvmPayload( + t, + PROGRAM, + encodeAgwSvmPayload( + PROGRAM, + [...accounts, accounts[0]], + new Uint8Array([1]) + ) + ) + ).toThrow(/CeaAccountAtUnpinnedIndex/); + expect(() => + validateAgwSvmPayload( + t, + GATEWAY, + encodeAgwSvmPayload(PROGRAM, accounts, new Uint8Array([1])) + ) + ).toThrow(/RecipientTargetMismatch/); + }); + it('enforces little-endian floors/ceilings, from-end offsets, ratios and exact byte pins', () => { + const t = base(); + t.dataPins = [ + { + ruleIndex: 0, + fromEnd: true, + offset: 4, + offsetB: 2, + len: 2, + mode: 3, + expected: key('00'), + num: BigInt(9), + den: BigInt(10), + }, + ]; + const make = (out: number, input: number) => + encodeAgwSvmPayload( + PROGRAM, + accounts, + new Uint8Array([1, out & 255, out >> 8, input & 255, input >> 8]) + ); + expect(validateAgwSvmPayload(t, PROGRAM, make(90, 100))).toBe(0); + expect(() => validateAgwSvmPayload(t, PROGRAM, make(89, 100))).toThrow( + /SvmDataRatioNotMet/ + ); + t.dataPins = [ + { + ...t.dataPins[0], + fromEnd: false, + offset: 1, + mode: 1, + expected: numberToHex(90, { size: 32 }), + }, + ]; + expect(() => validateAgwSvmPayload(t, PROGRAM, make(89, 100))).toThrow( + /SvmDataFloorNotMet/ + ); + t.dataPins = [{ ...t.dataPins[0], mode: 2 }]; + expect(() => validateAgwSvmPayload(t, PROGRAM, make(91, 100))).toThrow( + /SvmDataCeilingExceeded/ + ); + t.dataPins = [ + { ...t.dataPins[0], mode: 0, expected: `0x5a00${'00'.repeat(30)}` }, + ]; + expect(validateAgwSvmPayload(t, PROGRAM, make(90, 100))).toBe(0); + expect(() => + validateAgwSvmPayload( + t, + PROGRAM, + encodeAgwSvmPayload(PROGRAM, accounts, new Uint8Array([1])) + ) + ).toThrow(/SvmDataTooShortForPin/); + }); +}); + +describe('internal SVM outbound action', () => { + const config = () => ({ + ...base(), + initialized: true, + maxGasPerCall: BigInt(100), + assets: [ + { + token: ADDR.target, + maxPerCall: BigInt(5), + maxTotal: BigInt(10), + spent: BigInt(2), + }, + ], + }); + const input = () => ({ + wallet: ADDR.owner, + gateway: ADDR.gateway, + token: ADDR.target, + amount: BigInt(3), + recipient: PROGRAM, + payload: encodeAgwSvmPayload(PROGRAM, accounts, new Uint8Array([1])), + gasLimit: BigInt(200000), + protocolFee: BigInt(2), + maxPCForGas: BigInt(3), + }); + it('uses the program recipient, wallet refund and quoted PC while preserving the exact payload', () => { + const i = input(), + result = composeAgwSvmAction(i, config(), NOW); + const request = decodeFunctionData({ + abi: UNIVERSAL_GATEWAY_PC, + data: result.data, + }).args![0]; + expect(result.target).toBe(ADDR.gateway); + expect(result.value).toBe(BigInt(5)); + expect(request).toMatchObject({ + recipient: PROGRAM, + revertRecipient: ADDR.owner, + amount: BigInt(3), + payload: i.payload, + gasPrice: BigInt(0), + }); + }); + it('rejects caps, zero gas and unknown assets before signing', () => { + expect(() => + composeAgwSvmAction({ ...input(), amount: BigInt(6) }, config(), NOW) + ).toThrow(/AmountExceedsCap/); + expect(() => + composeAgwSvmAction({ ...input(), token: ADDR.other }, config(), NOW) + ).toThrow(/AssetNotAllowed/); + expect(() => + composeAgwSvmAction({ ...input(), maxPCForGas: BigInt(0) }, config(), NOW) + ).toThrow(/UncappedGasSwapRejected/); + expect(() => + composeAgwSvmAction( + { ...input(), maxPCForGas: BigInt(100) }, + config(), + NOW + ) + ).toThrow(/PCValueExceedsCap/); + const c = config(); + c.assets[0].spent = BigInt(9); + expect(() => composeAgwSvmAction(input(), c, NOW)).toThrow( + /TotalSpendCapExceeded/ + ); + c.assets[0].maxPerCall = BigInt(2) ** BigInt(256) - BigInt(1); + expect(() => + composeAgwSvmAction( + { ...input(), amount: BigInt(2) ** BigInt(64) }, + c, + NOW + ) + ).toThrow(/AmountExceedsU64/); + }); +}); diff --git a/packages/core/src/lib/agentic/__tests__/svm-quote.spec.ts b/packages/core/src/lib/agentic/__tests__/svm-quote.spec.ts new file mode 100644 index 00000000..766135cd --- /dev/null +++ b/packages/core/src/lib/agentic/__tests__/svm-quote.spec.ts @@ -0,0 +1,251 @@ +import { + decodeFunctionResult, + encodeAbiParameters, + type Abi, + type Hex, +} from 'viem'; +import { preparePublicSvmRule } from '../management/svm-public'; +import { resolveSvmAssets } from '../management/svm-context'; +import { readSvmSourceToken } from '../contracts/prc20-metadata'; +import { PublicKey } from '@solana/web3.js'; +import { MOVEABLE_TOKEN_CONSTANTS } from '../../constants/tokens'; +import { getPRC20Address } from '../../universal/prc20-address'; +import { CHAIN } from '../../constants/enums'; +import { Snapshot } from '../reads/snapshot'; +import { quoteSvmRequest } from '../execution/svm-quote'; +import { ADDR, FakeChain } from './fake-chain'; +import { mockRuntime } from './mock-runtime'; +const mint = '0x' + '33'.repeat(32); +function fixture(chain = CHAIN.SOLANA_DEVNET) { + const fake = new FakeChain(); + fake.readContract = async ({ functionName }) => + functionName === 'gasTokenPRC20ByChainNamespace' + ? ADDR.other + : functionName === 'SOURCE_CHAIN_NAMESPACE' + ? chain + : mint; + const quoteOutbound = jest.fn().mockResolvedValue({ + protocolFee: BigInt(1), + nativeValueForGas: BigInt(10), + gasLimitUsed: BigInt(100), + }); + return { + snap: new Snapshot(fake, BigInt(1)), + rt: mockRuntime(fake, { quoteOutbound }), + quoteOutbound, + }; +} +describe('AGW Solana finalization quote context', () => { + it('uses the wallet identity and actual source mint for SPL rent budgeting', async () => { + const f = fixture(); + await quoteSvmRequest( + f.rt, + f.snap, + ADDR.owner, + ADDR.target, + CHAIN.SOLANA_DEVNET, + BigInt(0), + BigInt(5) + ); + expect(f.quoteOutbound).toHaveBeenCalledWith( + ADDR.target, + BigInt(0), + CHAIN.SOLANA_DEVNET, + { + wallet: ADDR.owner, + splMintBase58: new PublicKey( + Buffer.from(mint.slice(2), 'hex') + ).toBase58(), + burnAmount: BigInt(5), + } + ); + }); + it('native transfers carry no SPL mint or ATA requirement', async () => { + const f = fixture(); + const q = await quoteSvmRequest( + f.rt, + f.snap, + ADDR.owner, + ADDR.other, + CHAIN.SOLANA_DEVNET, + BigInt(0), + BigInt(5) + ); + expect(q.isNative).toBe(true); + expect(f.quoteOutbound.mock.calls[0][3].splMintBase58).toBeUndefined(); + }); + it('zero-burn instruction quotes do not add a transfer ATA requirement', async () => { + const f = fixture(); + await quoteSvmRequest( + f.rt, + f.snap, + ADDR.owner, + ADDR.target, + CHAIN.SOLANA_DEVNET, + BigInt(0), + BigInt(0) + ); + expect(f.quoteOutbound.mock.calls[0][3].splMintBase58).toBeUndefined(); + }); + it('an asset from another chain fails route validation without a quote', async () => { + const f = fixture(CHAIN.ETHEREUM_SEPOLIA); + await expect( + quoteSvmRequest( + f.rt, + f.snap, + ADDR.owner, + ADDR.target, + CHAIN.SOLANA_DEVNET, + BigInt(0), + BigInt(5) + ) + ).rejects.toMatchObject({ code: 'ASSET_CHAIN_MISMATCH' }); + expect(f.quoteOutbound).not.toHaveBeenCalled(); + }); + it('decodes the real precompile word when a Solidity string ABI cannot decode it', async () => { + const f = fixture(); + const read = f.snap.reader.readContract; + const outputTypes: string[] = []; + f.snap.reader.readContract = async (args) => { + if (args.functionName !== 'SOURCE_TOKEN_ADDRESS') return read(args); + const fn = (args.abi as Abi).find( + (entry) => entry.type === 'function' && entry.name === args.functionName + ); + if (fn?.type !== 'function') throw new Error('missing metadata ABI'); + outputTypes.push(fn.outputs[0].type); + return decodeFunctionResult({ + abi: args.abi as Abi, + functionName: args.functionName, + data: encodeAbiParameters([{ type: 'bytes32' }], [mint as Hex]), + }); + }; + await quoteSvmRequest( + f.rt, + f.snap, + ADDR.owner, + ADDR.target, + CHAIN.SOLANA_DEVNET, + BigInt(0), + BigInt(5) + ); + expect(outputTypes).toEqual(['string', 'bytes32']); + const expected = new PublicKey( + Buffer.from(mint.slice(2), 'hex') + ).toBase58(); + expect(f.quoteOutbound.mock.calls[0][3].splMintBase58).toBe(expected); + const metadata = { + gateway: jest.fn(), + mint: jest.fn().mockResolvedValue({ + mint: expected, + tokenProgram: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', + }), + }; + const assets = await resolveSvmAssets( + f.snap, + CHAIN.SOLANA_DEVNET, + [{ token: ADDR.target, maxPerCall: BigInt(5), maxTotal: BigInt(5) }], + metadata + ); + expect(assets[0]).toMatchObject({ kind: 'spl', mint: expected }); + expect(metadata.mint).toHaveBeenCalledWith(CHAIN.SOLANA_DEVNET, mint); + }); + + it('does not fabricate a mint when both metadata representations fail', async () => { + const f = fixture(); + f.snap.reader.readContract = async () => { + throw new Error('RPC unavailable'); + }; + await expect( + readSvmSourceToken(f.snap, ADDR.target, CHAIN.SOLANA_DEVNET) + ).rejects.toMatchObject({ + code: 'RULE_READ_FAILED', + cause: { message: 'RPC unavailable' }, + }); + expect(f.quoteOutbound).not.toHaveBeenCalled(); + }); + it('uses the current registered SPL mint when Donut metadata returns a zero word', async () => { + const f = fixture(); + const asset = MOVEABLE_TOKEN_CONSTANTS.SOLANA_DEVNET.USDT; + const token = getPRC20Address({ + chain: CHAIN.SOLANA_DEVNET, + address: asset.address, + }).address; + const read = f.snap.reader.readContract; + f.snap.reader.readContract = async (args) => { + if (args.functionName !== 'SOURCE_TOKEN_ADDRESS') return read(args); + return decodeFunctionResult({ + abi: args.abi as Abi, + functionName: args.functionName, + data: encodeAbiParameters( + [{ type: 'bytes32' }], + [`0x${'00'.repeat(32)}`] + ), + }); + }; + await quoteSvmRequest( + f.rt, + f.snap, + ADDR.owner, + token, + CHAIN.SOLANA_DEVNET, + BigInt(0), + BigInt(1000) + ); + expect(f.quoteOutbound.mock.calls[0][3].splMintBase58).toBe(asset.address); + await expect( + readSvmSourceToken(f.snap, ADDR.target, CHAIN.SOLANA_DEVNET) + ).rejects.toMatchObject({ code: 'INVALID_RULE' }); + }); + it('canonicalizes a decoded SPL mint before resolving its PRC20 mapping', async () => { + const f = fixture(); + const expected = new PublicKey( + Buffer.from(mint.slice(2), 'hex') + ).toBase58(); + const program = `0x${'44'.repeat(32)}` as Hex; + const rt = { + ...f.rt, + resolvePrc20: jest.fn().mockReturnValue(ADDR.target), + svmMetadata: { + gateway: async () => ({ + chainNamespace: CHAIN.SOLANA_DEVNET, + program: `0x${'22'.repeat(32)}`, + }), + mint: async () => ({ + mint: expected, + tokenProgram: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', + }), + }, + }; + await preparePublicSvmRule(rt, f.snap, ADDR.owner, { + agent: ADDR.agent, + chainNamespace: CHAIN.SOLANA_DEVNET, + assets: [{ token: mint, maxPerCall: BigInt(5), maxTotal: BigInt(5) }], + validUntil: f.rt.nowSeconds() + 3600, + maxGasPerCall: BigInt(10), + allowedInstructions: [ + { + program, + accounts: [{ name: 'authority', expected: { kind: 'walletCEA' } }], + instruction: { + name: 'ping', + idl: { + address: new PublicKey( + Buffer.from(program.slice(2), 'hex') + ).toBase58(), + metadata: { name: 'fixture', version: '1', spec: '0.1.0' }, + instructions: [ + { + name: 'ping', + discriminator: [1, 2, 3, 4, 5, 6, 7, 8], + accounts: [{ name: 'authority', signer: true }], + args: [], + }, + ], + }, + }, + }, + ], + }); + expect(rt.resolvePrc20).toHaveBeenCalledWith(expected, CHAIN.SOLANA_DEVNET); + }); +}); diff --git a/packages/core/src/lib/agentic/__tests__/svm-wire-fixture.spec.ts b/packages/core/src/lib/agentic/__tests__/svm-wire-fixture.spec.ts new file mode 100644 index 00000000..cb2a2d6b --- /dev/null +++ b/packages/core/src/lib/agentic/__tests__/svm-wire-fixture.spec.ts @@ -0,0 +1,59 @@ +import { Connection, PublicKey, type AccountInfo } from '@solana/web3.js'; +import { decodeWireCounter, inspectSvmWirePrograms, SVM_WIRE_COUNTER, SVM_WIRE_GATEWAY, SVM_WIRE_PROGRAM } from '../../../../__e2e__/shared/agw-svm-preflight'; + +const gateway = new PublicKey(SVM_WIRE_GATEWAY), program = new PublicKey(SVM_WIRE_PROGRAM); +const loader = new PublicKey('BPFLoaderUpgradeab1e11111111111111111111111'); +const config = PublicKey.findProgramAddressSync([Buffer.from('config')], gateway)[0]; +function fixture() { + const rows = new Map>(); + [gateway, program].forEach((key, i) => { + const programData = new PublicKey(Buffer.alloc(32, i + 1)); + const data = Buffer.alloc(36); data.writeUInt32LE(2); programData.toBuffer().copy(data, 4); + rows.set(key.toBase58(), { data, owner: loader, executable: true, lamports: 1, rentEpoch: 0 }); + const implementation = Buffer.alloc(49); implementation.writeUInt32LE(3); implementation.writeBigUInt64LE(BigInt(42), 4); + rows.set(programData.toBase58(), { data: implementation, owner: loader, executable: false, lamports: 1, rentEpoch: 0 }); + }); + const counter = Buffer.alloc(48); Buffer.from([255, 176, 4, 245, 188, 253, 124, 25]).copy(counter); counter.writeBigUInt64LE(BigInt(7), 8); + rows.set(SVM_WIRE_COUNTER.toBase58(), { data: counter, owner: program, executable: false, lamports: 1, rentEpoch: 0 }); + const data = Buffer.alloc(279); Buffer.from([155, 12, 170, 224, 30, 250, 204, 130]).copy(data); + rows.set(config.toBase58(), { data, owner: gateway, executable: false, lamports: 1, rentEpoch: 0 }); + const rpc = { + getGenesisHash: jest.fn().mockResolvedValue('EtWTRABZaYq6iMfeYKouRu166VU2xqa1wcaWoxPkrZBG'), + getMultipleAccountsInfoAndContext: jest.fn(async (keys: PublicKey[]) => ({ context: { slot: 99 }, value: keys.map((k) => rows.get(k.toBase58()) ?? null) })), + }; + return { rows, rpc, connection: rpc as unknown as Connection }; +} + +describe('unfunded AGW SVM wire fixture gate', () => { + it('records program fingerprints, slot and the actual IDL-decoded counter/config', async () => { + const { connection } = fixture(); + const result = await inspectSvmWirePrograms(connection); + expect(result.counter.value).toBe('7'); expect(result.gatewayConfig.paused).toBe(false); + expect(result.programs).toHaveLength(2); expect(result.programs[0].lastUpgradeSlot).toBe('42'); + expect(result.programs[0].dataSha256).toMatch(/^[0-9a-f]{64}$/); expect(result.slot).toBe(99); + }); + it('rejects an RPC for another cluster before reading account state', async () => { + const { rpc, connection } = fixture(); rpc.getGenesisHash.mockResolvedValue('other-cluster'); + await expect(inspectSvmWirePrograms(connection)).rejects.toThrow('selected devnet'); + expect(rpc.getMultipleAccountsInfoAndContext).not.toHaveBeenCalled(); + }); + it('rejects a non-executable program before reading ProgramData', async () => { + const { rows, rpc, connection } = fixture(); rows.get(gateway.toBase58())!.executable = false; + await expect(inspectSvmWirePrograms(connection)).rejects.toThrow('executable upgradeable'); + expect(rpc.getMultipleAccountsInfoAndContext).toHaveBeenCalledTimes(1); + }); + it('rejects a paused gateway using the actual Config decoder', async () => { + const { rows, connection } = fixture(); rows.get(config.toBase58())!.data[136] = 1; + await expect(inspectSvmWirePrograms(connection)).rejects.toThrow('paused'); + }); + it('rejects a substituted counter owner and an incompatible discriminator', async () => { + const { rows, connection } = fixture(); rows.get(SVM_WIRE_COUNTER.toBase58())!.owner = gateway; + await expect(inspectSvmWirePrograms(connection)).rejects.toThrow('wrong owner'); + expect(() => decodeWireCounter(Buffer.alloc(48))).toThrow('selected IDL'); + expect(() => decodeWireCounter(Buffer.alloc(8))).toThrow('selected IDL'); + }); + it('rejects missing ProgramData rather than treating program metadata as delivery proof', async () => { + const { rows, connection } = fixture(); rows.delete(new PublicKey(Buffer.alloc(32, 1)).toBase58()); + await expect(inspectSvmWirePrograms(connection)).rejects.toThrow('ProgramData'); + }); +}); diff --git a/packages/core/src/lib/agentic/agentic.ts b/packages/core/src/lib/agentic/agentic.ts new file mode 100644 index 00000000..e15344c0 --- /dev/null +++ b/packages/core/src/lib/agentic/agentic.ts @@ -0,0 +1,49 @@ +import { AgenticCapability, requireCapability } from './capabilities'; +import { currentGeneration } from './deployments'; +import { createWallet } from './management/create'; +import { emitAgentic } from './management/common'; +import { deriveForOwner, listForOwner } from './reads/wallets'; +import { AgenticWalletHandle } from './wallet'; +import { PROGRESS_HOOK } from '../progress-hook/progress-hook.types'; +import type { AgenticRuntime } from './runtime'; +import type { + AgenticAddress, + AgenticNamespace, + AgenticWallet, + CreateOptions, + CreateResult, + WalletSummary, +} from './agentic.types'; + +/** + * client.agentic — owner-side AGW management (spec section 1). Ownership is + * always the connected signer's Push identity (EOA, or the UEA for its origin + * chain), never the AGW an agentic client exposes as universal.account. + */ +export class AgenticNamespaceImpl implements AgenticNamespace { + constructor(private readonly runtime: AgenticRuntime) {} + + async derive(opts?: { index?: number }): Promise<{ address: AgenticAddress; index: number; deployed: boolean }> { + const gen = currentGeneration(this.runtime.network); + requireCapability(gen.capabilities, AgenticCapability.WALLET_READS); + const owner = this.runtime.signerPushAccount(); + const r = await deriveForOwner(this.runtime.reader, gen, owner, opts?.index); + emitAgentic(this.runtime, undefined, PROGRESS_HOOK.AGENTIC_TX_101, r.address, r.index, r.deployed); + return { address: r.address as AgenticAddress, index: r.index, deployed: r.deployed }; + } + + create(label: string, options: CreateOptions): Promise { + return createWallet(this.runtime, label, options); + } + + async list(): Promise<{ wallets: WalletSummary[] }> { + const gen = currentGeneration(this.runtime.network); + requireCapability(gen.capabilities, AgenticCapability.WALLET_READS); + const wallets = await listForOwner(this.runtime.reader, gen, this.runtime.signerPushAccount()); + return { wallets }; + } + + wallet(address: AgenticAddress): AgenticWallet { + return new AgenticWalletHandle(this.runtime, address); + } +} diff --git a/packages/core/src/lib/agentic/agentic.types.ts b/packages/core/src/lib/agentic/agentic.types.ts new file mode 100644 index 00000000..a0d1b6b2 --- /dev/null +++ b/packages/core/src/lib/agentic/agentic.types.ts @@ -0,0 +1,281 @@ +/** + * Public AGW types — AGW SDK page section 3 (Notion export 2026-10-03 13:23 IST). + * + * Named-IDL Solana inputs and native/EVM raw offsets follow the October 7 + * decisions. Contract-dependent label editing remains capability-gated. + */ +import type { Idl } from '@coral-xyz/anchor'; +import type { SvmTermsWire } from './codec/svm-terms'; +import type { MoveableToken } from '../constants/tokens'; +import type { UniversalTxResponse } from '../orchestrator/orchestrator.types'; +import type { ProgressEvent } from '../progress-hook/progress-hook.types'; + +export type AgenticAddress = `0x${string}`; +export type AgenticHex = `0x${string}`; +export type ForeignChainNamespace = `eip155:${string}` | `solana:${string}`; +export type AgenticProgressHook = (event: ProgressEvent) => void; + +/** '0x617ba037' or 'supply(address,uint256,address,uint16)'. */ +export type Selector = AgenticHex | `${string}(${string})`; + +export interface NativeRule { + /** Push address: an EOA, or the UEA of an external key. Never the owner. */ + agent: AgenticAddress; + /** Omitted = the connected Push chain. */ + chainNamespace?: never; + target: AgenticAddress; + selector: Selector | 'value-only'; + /** Unix seconds. */ + validUntil: number; + /** Default 0: no native PC value allowance. */ + maxValuePerCall?: bigint; + /** Default 0: no native PC value allowance. */ + maxValueTotal?: bigint; + /** Default 0 (unlimited calls until expiry). */ + maxCalls?: number; + pins?: ArgPin[]; + /** `maxTotal` default uint256 max (unlimited total). */ + amount?: AmountLimit; +} + +/** + * Where a pin or amount sits in the calldata. `arg` is the argument index in + * the selector signature (requires the signature form of `selector`). + * `offset` is the raw calldata byte offset, selector included — the form the + * contracts store; decoded rules (rules.get/list, decodeRules) always use it + * because stored terms carry no ABI. Advanced input form; ABI argument indexes are preferred for authoring. + */ +export type ArgPin = + | { + arg: number; + offset?: never; + expected: AgenticHex | AgenticAddress | bigint; + } + | { offset: number; arg?: never; expected: AgenticHex }; + +export type AmountLimit = ( + | { arg: number; offset?: never } + | { offset: number; arg?: never } +) & { + maxPerCall: bigint; + maxTotal?: bigint; +}; + +export interface AssetCap { + /** The destination chain's token (MOVEABLE constant) or native marker. */ + token: MoveableToken | AgenticAddress; + maxPerCall: bigint; + /** Omitted = uint256 maximum (unlimited). Explicit zero forbids movement. */ + maxTotal?: bigint; +} + +export interface AllowedCall { + target: AgenticAddress; + selector: Selector; + /** Argument index whose address must be the wallet's destination account. */ + beneficiary?: number; + /** Exact stored calldata offset for lossless decoded rules; mutually exclusive with beneficiary. Approved advanced input form. */ + beneficiaryOffset?: number; + /** Default 0. */ + maxValue?: bigint; +} + +export interface UniversalRule { + agent: AgenticAddress; + chainNamespace: `eip155:${string}`; + assets: AssetCap[]; + /** PC (wei) per outbound for the destination leg. */ + maxGasPerCall: bigint; + validUntil: number; + /** 1..32, all on chainNamespace. */ + allowedCalls: AllowedCall[]; +} + +/** An address may be base58 or a 32-byte hex Solana public key. */ +export type SvmAccountRef = + | { kind: 'walletCEA' } + | { kind: 'walletATA'; token: string } + | { kind: 'address'; address: string }; +export type SvmFieldConstraint = + | { name: string; equals: AgenticHex | bigint | boolean } + | { name: string; min: bigint } + | { name: string; max: bigint } + | { + numerator: string; + denominator: string; + minRatio: { num: bigint; den: bigint }; + }; +export interface SvmInstructionRule { + program: string; + instruction: { idl: Idl; name: string }; + /** Top-level account names from a supported Anchor IDL; optional/nested accounts are rejected. */ + accounts: { name: string; expected: SvmAccountRef }[]; + /** Fixed-width fields only; unsupported/variable layouts fail before signing. */ + fields?: SvmFieldConstraint[]; +} +export interface SolanaRule { + agent: AgenticAddress; + chainNamespace: `solana:${string}`; + validUntil: number; + assets: { + token: MoveableToken | string; + maxPerCall: bigint; + maxTotal?: bigint; + }[]; + maxGasPerCall: bigint; + /** Additional output mints whose wallet ATAs must be protected. */ + outputTokens?: string[]; + allowedInstructions: SvmInstructionRule[]; +} +/** Stored constraints contain no IDL; supply a named SolanaRule when replacing. */ +export interface DecodedSolanaRule extends Omit { + format: 'decoded'; + agent: AgenticAddress; + chainNamespace: `solana:${string}`; + assets: { token: string; maxPerCall: bigint; maxTotal: bigint }[]; +} +export type Rule = NativeRule | UniversalRule | SolanaRule; + +export interface RulesRecord { + rulesId: AgenticHex; + enabled: boolean; + chainNamespace: string; + agent: AgenticAddress; + validUntil: number; + rule: Rule | DecodedSolanaRule; +} + +export interface CreateOptions { + rules: Rule[]; + progressHook?: AgenticProgressHook; +} + +export interface CreateResult { + wallet: AgenticAddress; + index: number; + rulesIds: AgenticHex[]; + tx: UniversalTxResponse; +} + +export interface WalletSummary { + address: AgenticAddress; + index: number; + label: string; + deployed: boolean; + rulesCount: number; +} + +export interface WalletInfo { + address: AgenticAddress; + label: string; + index: number; + owner: AgenticAddress; + deployed: boolean; + rulesCount: number; +} + +export type CheckpointKind = 'OWNER_ACTION' | 'RULES_GRANTED' | 'RULES_REVOKED'; + +export interface Checkpoint { + seq: number; + kind: CheckpointKind; + ref: AgenticHex; + blockNumber: bigint; + txHash: AgenticHex; +} + +export interface AgenticWallet { + address: AgenticAddress; + info(): Promise; + owner(): Promise<{ owner: AgenticAddress }>; + /** Owner-only rename, at most 64 UTF-8 bytes. Empty resets the default label. */ + setLabel( + label: string, + opts?: { progressHook?: AgenticProgressHook } + ): Promise; + checkpoints(opts?: { + sinceBlock?: bigint; + }): Promise<{ checkpoints: Checkpoint[] }>; + rules: { + /** Enabled rules only; expired-but-enabled rules remain visible. No public spend counters. */ + list(): Promise<{ rules: RulesRecord[] }>; + /** Unknown and revoked IDs both return RULE_NOT_FOUND; v1 has no historical records. */ + get(rulesId: AgenticHex): Promise; + add( + rules: Rule[], + opts?: { progressHook?: AgenticProgressHook } + ): Promise<{ rulesIds: AgenticHex[]; tx: UniversalTxResponse }>; + update(params: { + rules: { rulesId: AgenticHex; rule: Rule }[]; + progressHook?: AgenticProgressHook; + }): Promise<{ + rules: { rulesId: AgenticHex; replaced: AgenticHex }[]; + tx: UniversalTxResponse; + }>; + revoke( + rulesIds: AgenticHex[], + opts?: { progressHook?: AgenticProgressHook } + ): Promise; + revoke(params: { + all: true; + progressHook?: AgenticProgressHook; + }): Promise; + }; +} + +export interface AgenticNamespace { + derive(opts?: { + index?: number; + }): Promise<{ address: AgenticAddress; index: number; deployed: boolean }>; + create(label: string, options: CreateOptions): Promise; + list(): Promise<{ wallets: WalletSummary[] }>; + wallet(address: AgenticAddress): AgenticWallet; +} + +/** Door the client uses in agenticWallet mode. */ +export type AgenticDoor = 'owner' | 'agent'; + +/** AGW metadata attached to responses produced by an agentic client. */ +export interface AgenticTxMetadata { + wallet: AgenticAddress; + door: AgenticDoor; + /** Rule selected for an agent-door send. */ + rulesId?: AgenticHex; + /** Destination CAIP-2 chain for the selected rule / outbound. */ + chainNamespace?: string; + /** The wallet's destination account (CEA) for an outbound. */ + destinationAccount?: AgenticAddress; + /** + * Ordered calls encoded for the destination CEA. Outbound response + * to/data/value summarize the first call, including an SDK-generated token + * transfer. Replay uses the same representation; it cannot recover which + * calls were supplied explicitly versus generated from funds. + */ + destinationCalls?: readonly { + to: AgenticAddress; + data: AgenticHex; + value: bigint; + }[]; + /** SVM instruction executed by the wallet's destination CEA. */ + destinationInstruction?: { + program: AgenticHex; + data: AgenticHex; + accounts: readonly { pubkey: AgenticHex; isWritable: boolean }[]; + }; + /** Funds-only Solana transfer. token is the burned PRC20 on Push. */ + destinationTransfer?: { + recipient: AgenticHex; + token: AgenticAddress; + amount: bigint; + }; + /** Ordered actions in a native agent batch; to/data/value summarize its first action. */ + nativeCalls?: readonly { + to: AgenticAddress; + data: AgenticHex; + value: bigint; + }[]; + /** Account the signer's transaction actually called (wallet or outer sender account). */ + rawTo: string; + /** Calldata the signer's transaction actually carried. */ + rawData: string; +} diff --git a/packages/core/src/lib/agentic/capabilities.ts b/packages/core/src/lib/agentic/capabilities.ts new file mode 100644 index 00000000..6e481d07 --- /dev/null +++ b/packages/core/src/lib/agentic/capabilities.ts @@ -0,0 +1,79 @@ +import { capabilityUnavailable } from './errors'; + +/** + * Internal capability flags for an AGW contract generation. A method whose + * capability is absent fails before any signature. Each unresolved target + * feature identifies the contract or product capability that must be verified + * before it can be advertised. + */ +export enum AgenticCapability { + /** Factory derive/list/deploy and wallet owner/info reads. */ + WALLET_READS = 'walletReads', + /** Active (enabled) rule enumeration and native-rule decoding. */ + ACTIVE_RULE_READS = 'activeRuleReads', + /** Owner door: execute(mode, executionCalldata). */ + OWNER_EXECUTE = 'ownerExecute', + /** Agent door: executeAsAgent(rulesId, mode, executionCalldata). */ + AGENT_EXECUTE = 'agentExecute', + /** Native (Push-chain) rule grants with NativeTerms encoding. */ + NATIVE_RULES = 'nativeRules', + /** Exact-equality native spend assertion used by rules.update. */ + ASSERT_SPENT_NATIVE = 'assertSpentNative', + /** checkpointCount + Checkpointed events. */ + CHECKPOINTS = 'checkpoints', + /** Agent-door EVM outbound composition against v5 per-token caps. */ + UNIVERSAL_EVM_OUTBOUND = 'universalEvmOutbound', + /** Target UniversalRule (assets[] / maxGasPerCall) encode/decode. A05/A07. */ + UNIVERSAL_EVM_RULES = 'universalEvmRules', + /** Per-token expected-spend assertion for universal replacement. A05. */ + ASSERT_SPENT_UNIVERSAL_MULTI = 'assertSpentUniversalMulti', + /** Named-IDL Solana authoring, exact decoded reads and instruction execution. */ + UNIVERSAL_SVM_RULES = 'universalSvmRules', + /** Editable wallet label (setLabel / LabelSet). A07. */ + SET_LABEL = 'setLabel', +} + +/** Why each target capability is unavailable when a generation lacks it. */ +export const CAPABILITY_DEPENDENCY: Record = { + [AgenticCapability.WALLET_READS]: + 'no verified AGW deployment for this network (A07)', + [AgenticCapability.ACTIVE_RULE_READS]: + 'no verified AGW deployment for this network (A07)', + [AgenticCapability.OWNER_EXECUTE]: + 'no verified AGW deployment for this network (A07)', + [AgenticCapability.AGENT_EXECUTE]: + 'no verified AGW deployment for this network (A07)', + [AgenticCapability.NATIVE_RULES]: + 'no verified AGW deployment for this network (A07)', + [AgenticCapability.ASSERT_SPENT_NATIVE]: + 'no verified AGW deployment for this network (A07)', + [AgenticCapability.CHECKPOINTS]: + 'no verified AGW deployment for this network (A07)', + [AgenticCapability.UNIVERSAL_EVM_OUTBOUND]: + 'the selected generation has no verified multi-asset outbound token resolution (A05/A07)', + [AgenticCapability.UNIVERSAL_EVM_RULES]: + 'EVM universal rules are unavailable for the selected SDK configuration', + [AgenticCapability.ASSERT_SPENT_UNIVERSAL_MULTI]: + 'universal expected-spend assertions are unavailable for this configuration', + [AgenticCapability.UNIVERSAL_SVM_RULES]: + 'SVM rules are unavailable for this generation', + [AgenticCapability.SET_LABEL]: + 'the selected generation has no editable label (A07; labels are deploy-time only)', +}; + +export function hasCapability( + capabilities: ReadonlySet, + capability: AgenticCapability +): boolean { + return capabilities.has(capability); +} + +/** Throws CAPABILITY_UNAVAILABLE (before signing) when the flag is absent. */ +export function requireCapability( + capabilities: ReadonlySet | undefined, + capability: AgenticCapability +): void { + if (!capabilities || !capabilities.has(capability)) { + throw capabilityUnavailable(capability, CAPABILITY_DEPENDENCY[capability]); + } +} diff --git a/packages/core/src/lib/agentic/chain.ts b/packages/core/src/lib/agentic/chain.ts new file mode 100644 index 00000000..cac1f6e2 --- /dev/null +++ b/packages/core/src/lib/agentic/chain.ts @@ -0,0 +1,13 @@ +import { CHAIN_INFO } from '../constants/chain'; +import { CHAIN, PUSH_NETWORK } from '../constants/enums'; + +/** 'eip155:' of the Push chain for a network — the native rule chain. */ +export function pushChainNamespaceFor(network: PUSH_NETWORK): string { + const chain = + network === PUSH_NETWORK.MAINNET + ? CHAIN.PUSH_MAINNET + : network === PUSH_NETWORK.TESTNET_DONUT || network === PUSH_NETWORK.TESTNET + ? CHAIN.PUSH_TESTNET_DONUT + : CHAIN.PUSH_LOCALNET; + return `eip155:${CHAIN_INFO[chain].chainId}`; +} diff --git a/packages/core/src/lib/agentic/codec/abi-layout.ts b/packages/core/src/lib/agentic/codec/abi-layout.ts new file mode 100644 index 00000000..2e1d4629 --- /dev/null +++ b/packages/core/src/lib/agentic/codec/abi-layout.ts @@ -0,0 +1,139 @@ +import { + decodeAbiParameters, + encodeAbiParameters, + isAddress, + isHex, + type AbiParameter, +} from 'viem'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; +import type { AgenticHex } from '../agentic.types'; + +/** + * ABI head layout for argument-position terms (native pins/amount, universal + * beneficiary). Contracts take ABSOLUTE byte offsets into calldata with the + * 4-byte selector included and read exactly one 32-byte word there, so only a + * single-word static elementary argument can be addressed. Preceding + * arguments may be dynamic (one head word: the offset pointer) or static + * tuples / fixed arrays (several head words); both are accounted for here. + */ + +const UINT16_MAX = 0xffff; + +function components(p: AbiParameter): readonly AbiParameter[] { + return (p as { components?: readonly AbiParameter[] }).components ?? []; +} + +/** Parse a trailing fixed/dynamic array suffix: 'uint256[3]' → base 'uint256', length 3. */ +function arraySuffix(type: string): { base: string; length: number | null } | null { + const m = /^(.*)\[(\d*)\]$/.exec(type); + if (!m) return null; + return { base: m[1], length: m[2] === '' ? null : Number(m[2]) }; +} + +export function isDynamic(p: AbiParameter): boolean { + const arr = arraySuffix(p.type); + if (arr) { + if (arr.length === null) return true; + return isDynamic({ ...p, type: arr.base } as AbiParameter); + } + if (p.type === 'bytes' || p.type === 'string') return true; + if (p.type === 'tuple') return components(p).some(isDynamic); + return false; +} + +/** Bytes this parameter occupies in the head of an encoding. */ +export function headSize(p: AbiParameter): number { + if (isDynamic(p)) return 32; + const arr = arraySuffix(p.type); + if (arr && arr.length !== null) { + return arr.length * headSize({ ...p, type: arr.base } as AbiParameter); + } + if (p.type === 'tuple') { + return components(p).reduce((sum, c) => sum + headSize(c), 0); + } + return 32; +} + +const ELEMENTARY = /^(address|bool|u?int(8|16|24|32|40|48|56|64|72|80|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256)?|bytes([1-9]|[12][0-9]|3[0-2]))$/; + +export function isSingleWordStatic(p: AbiParameter): boolean { + return ELEMENTARY.test(p.type); +} + +/** + * Absolute calldata byte offset (selector included) of argument `arg`. + * Rejects out-of-range indexes and any argument that is not one static word. + */ +export function argumentOffset( + inputs: readonly AbiParameter[] | undefined, + arg: number, + what: string +): number { + if (!inputs) { + throw invalid( + `${what} needs the function signature (e.g. 'supply(address,uint256,address,uint16)'), not a bare 4-byte selector` + ); + } + if (!Number.isInteger(arg) || arg < 0 || arg >= inputs.length) { + throw invalid(`${what} argument index ${arg} is out of range (0..${inputs.length - 1})`); + } + const target = inputs[arg]; + if (!isSingleWordStatic(target)) { + throw invalid( + `${what} argument ${arg} has type ${target.type}; only single-word static arguments can be pinned` + ); + } + let offset = 4; + for (let i = 0; i < arg; i++) offset += headSize(inputs[i]); + if (offset + 32 > UINT16_MAX) { + throw invalid(`${what} argument ${arg} lies beyond the uint16 offset range`); + } + return offset; +} + +/** Encode a pin's expected value as the exact 32-byte calldata word. */ +export function encodeArgWord( + param: AbiParameter, + expected: AgenticHex | bigint | string | boolean, + what: string +): AgenticHex { + try { + const isWord = typeof expected === 'string' && isHex(expected) && expected.length === 66; + if (param.type === 'address' && !isWord) { + if (typeof expected !== 'string' || !isAddress(expected, { strict: false })) { + throw new Error('expected an address'); + } + } else if (param.type.startsWith('bytes') && !isWord) { + if (typeof expected !== 'string' || !isHex(expected)) throw new Error('expected hex'); + } + // An already-encoded 32-byte word (as decoded rules return) is accepted + // when it is a canonical encoding of this argument type. + if (typeof expected === 'string' && isHex(expected) && expected.length === 66 && param.type !== 'bytes32') { + const [value] = decodeAbiParameters([param], expected as AgenticHex); + if (encodeAbiParameters([param], [value]).toLowerCase() !== expected.toLowerCase()) { + throw new Error('word is not a canonical encoding'); + } + return expected.toLowerCase() as AgenticHex; + } + return encodeAbiParameters([param], [expected]) as AgenticHex; + } catch (cause) { + throw invalid( + `${what} expected value does not encode as ${param.type}: ${ + cause instanceof Error ? cause.message : String(cause) + }`, + cause + ); + } +} + +/** Validate a raw calldata offset given directly (offset form). */ +export function rawOffset(offset: number, what: string): number { + if (!Number.isInteger(offset) || offset < 4 || offset + 32 > UINT16_MAX) { + throw invalid(`${what} offset ${offset} must be an integer in [4, ${UINT16_MAX - 32}] (selector included)`); + } + return offset; +} + +function invalid(message: string, cause?: unknown): AgenticError { + return new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, message, { cause }); +} diff --git a/packages/core/src/lib/agentic/codec/defaults.ts b/packages/core/src/lib/agentic/codec/defaults.ts new file mode 100644 index 00000000..cc652c46 --- /dev/null +++ b/packages/core/src/lib/agentic/codec/defaults.ts @@ -0,0 +1,59 @@ +/** + * THE single home for omitted-limit defaults. Native PC defaults are zero as + * confirmed on October 7. Nothing else in the SDK may invent + * a fallback for these fields; update this table for future changes. + * + * Explicit zero always stays zero. In the native policy a zero value/amount + * cap forbids positive value/amount, while maxCalls = 0 means unlimited. + */ +export const UINT256_MAX = BigInt(2) ** BigInt(256) - BigInt(1); + +export interface DefaultRow { + value: bigint; + meaning: string; + source: 'product' | 'v5'; +} + +export const AGENTIC_DEFAULTS = { + native: { + maxValuePerCall: { + value: BigInt(0), + meaning: 'no native value transfer', + source: 'product', + }, + maxValueTotal: { + value: BigInt(0), + meaning: 'no native value transfer', + source: 'product', + }, + amountMaxTotal: { + value: UINT256_MAX, + meaning: 'unlimited metered total', + source: 'product', + }, + maxCalls: { + value: BigInt(0), + meaning: 'unlimited calls until expiry', + source: 'product', + }, + }, + universal: { + assetMaxTotal: { + value: UINT256_MAX, + meaning: 'unlimited total; explicit zero forbids movement', + source: 'v5', + }, + allowedCallMaxValue: { + value: BigInt(0), + meaning: 'no native value attached to the destination call', + source: 'product', + }, + }, +} as const satisfies Record>; + +export function withDefault( + value: bigint | undefined, + row: DefaultRow +): bigint { + return value === undefined ? row.value : value; +} diff --git a/packages/core/src/lib/agentic/codec/ids.ts b/packages/core/src/lib/agentic/codec/ids.ts new file mode 100644 index 00000000..56c4f473 --- /dev/null +++ b/packages/core/src/lib/agentic/codec/ids.ts @@ -0,0 +1,112 @@ +import { + concat, + encodeAbiParameters, + encodePacked, + getAddress, + getContractAddress, + keccak256, + numberToHex, + type Address, + type Hex, +} from 'viem'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; + +/** + * Pure identity helpers mirroring the pinned AGW generation (v5): + * smartsessions IdLib.toActionId / toConfigId / toPermissionId and + * AGWFactory._predict (OZ Clones immutable-args CREATE2). + * Every input that changes the result is explicit — validator, factory and + * implementation are internal generation context. + */ + +/** keccak256(abi.encodePacked(address target, bytes4 selector)). */ +export function actionId(target: Address, selector: Hex): Hex { + return keccak256(encodePacked(['address', 'bytes4'], [target, selector])); +} + +/** keccak256(abi.encodePacked(wallet, keccak256(abi.encodePacked(rulesId, actionId)))). */ +export function configId(wallet: Address, rulesId: Hex, action: Hex): Hex { + const inner = keccak256( + encodePacked(['bytes32', 'bytes32'], [rulesId, action]) + ); + return keccak256(encodePacked(['address', 'bytes32'], [wallet, inner])); +} + +/** sessionValidatorInitData for the agent validator: abi.encode(address agent). */ +export function agentConfig(agent: Address): Hex { + return encodeAbiParameters([{ type: 'address' }], [agent]); +} + +/** + * The rules ID a grant produces: + * keccak256(abi.encode(validator, bytes abi.encode(agent), bytes32(grantNonce))). + * Chain is NOT part of the hash; records are keyed by wallet + rulesId. + */ +export function rulesId(ctx: { + validator: Address; + agent: Address; + grantNonce: bigint; +}): Hex { + if (ctx.grantNonce < BigInt(0) || ctx.grantNonce >= BigInt(2) ** BigInt(64)) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'grantNonce must fit uint64' + ); + } + return keccak256( + encodeAbiParameters( + [{ type: 'address' }, { type: 'bytes' }, { type: 'bytes32' }], + [ + ctx.validator, + agentConfig(ctx.agent), + numberToHex(ctx.grantNonce, { size: 32 }), + ] + ) + ); +} + +const UINT96_MAX = BigInt(2) ** BigInt(96) - BigInt(1); + +/** + * Counterfactual wallet address: CREATE2 by the factory proxy of an OZ clone + * of `walletImplementation` with immutable args (owner ‖ factory), salt + * keccak256(abi.encode(owner, uint96 index)). + */ +export function deriveWallet(ctx: { + factory: Address; + walletImplementation: Address; + owner: Address; + index: bigint | number; +}): Address { + const index = BigInt(ctx.index); + if (index < BigInt(0) || index > UINT96_MAX) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'wallet index must fit uint96' + ); + } + const salt = keccak256( + encodeAbiParameters( + [{ type: 'address' }, { type: 'uint96' }], + [ctx.owner, index] + ) + ); + const args = encodePacked(['address', 'address'], [ctx.owner, ctx.factory]); + const argsLength = (args.length - 2) / 2; + const initCode = concat([ + '0x61', + numberToHex(argsLength + 0x2d, { size: 2 }), + '0x3d81600a3d39f3363d3d373d3d3d363d73', + ctx.walletImplementation, + '0x5af43d82803e903d91602b57fd5bf3', + args, + ]); + return getAddress( + getContractAddress({ + opcode: 'CREATE2', + from: ctx.factory, + salt, + bytecodeHash: keccak256(initCode), + }) + ); +} diff --git a/packages/core/src/lib/agentic/codec/native.ts b/packages/core/src/lib/agentic/codec/native.ts new file mode 100644 index 00000000..b1197685 --- /dev/null +++ b/packages/core/src/lib/agentic/codec/native.ts @@ -0,0 +1,278 @@ +import { + decodeAbiParameters, + encodeAbiParameters, + getAddress, + isAddress, + isHex, + type AbiParameter, + type Address, + type Hex, +} from 'viem'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; +import type { AgenticHex, NativeRule } from '../agentic.types'; +import { argumentOffset, encodeArgWord, rawOffset } from './abi-layout'; +import { AGENTIC_DEFAULTS, UINT256_MAX, withDefault } from './defaults'; +import { + parseSelector, + VALUE_ONLY_SELECTOR, + type ParsedSelector, +} from './selectors'; + +/** URP native limits at v5 (Types.sol MAX_PINS, AGW MAX_NATIVE_ACTIONS). */ +export const MAX_PINS = 8; +const UINT32_MAX = 2 ** 32 - 1; +const UINT48_MAX = 2 ** 48 - 1; + +/** NativeTerms (Types.sol:354-363 at v5). */ +export interface NativeTermsWire { + validUntil: number; + target: Address; + selector: Hex; + maxValuePerCall: bigint; + maxValueTotal: bigint; + amount: { + enabled: boolean; + offset: number; + maxPerCall: bigint; + maxTotal: bigint; + }; + maxCalls: number; + pins: readonly { offset: number; expected: Hex }[]; +} + +export const NATIVE_TERMS_PARAM: AbiParameter = { + type: 'tuple', + components: [ + { name: 'validUntil', type: 'uint48' }, + { name: 'target', type: 'address' }, + { name: 'selector', type: 'bytes4' }, + { name: 'maxValuePerCall', type: 'uint256' }, + { name: 'maxValueTotal', type: 'uint256' }, + { + name: 'amount', + type: 'tuple', + components: [ + { name: 'enabled', type: 'bool' }, + { name: 'offset', type: 'uint16' }, + { name: 'maxPerCall', type: 'uint256' }, + { name: 'maxTotal', type: 'uint256' }, + ], + }, + { name: 'maxCalls', type: 'uint32' }, + { + name: 'pins', + type: 'tuple[]', + components: [ + { name: 'offset', type: 'uint16' }, + { name: 'expected', type: 'bytes32' }, + ], + }, + ], +}; + +function invalid( + message: string, + details?: Record +): AgenticError { + return new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, message, { + details, + }); +} + +function assertUint(value: bigint, bits: number, field: string): void { + if ( + typeof value !== 'bigint' || + value < BigInt(0) || + value >= BigInt(2) ** BigInt(bits) + ) { + throw invalid(`${field} must be a uint${bits} bigint`); + } +} + +export interface NativeEncodeContext { + /** Current unix time in seconds; grants with validUntil <= now are rejected. */ + nowSeconds: number; +} + +/** Normalize and validate a public NativeRule into wire terms. Pure. */ +export function nativeRuleToTerms( + rule: NativeRule, + ctx: NativeEncodeContext +): { terms: NativeTermsWire; parsed: ParsedSelector } { + if ( + !isAddress(rule.target, { strict: false }) || + /^0x0{40}$/i.test(rule.target) + ) { + throw invalid('native rule target must be a non-zero address'); + } + if ( + !Number.isInteger(rule.validUntil) || + rule.validUntil <= ctx.nowSeconds || + rule.validUntil > UINT48_MAX + ) { + throw invalid( + 'validUntil must be a future unix timestamp in seconds (uint48)', + { + validUntil: rule.validUntil, + } + ); + } + const parsed = parseSelector(rule.selector); + const pinsIn = rule.pins ?? []; + if (parsed.valueOnly && (pinsIn.length > 0 || rule.amount)) { + throw invalid('a value-only rule cannot carry pins or an amount rule'); + } + if (pinsIn.length > MAX_PINS) { + throw invalid(`at most ${MAX_PINS} pins are allowed`, { + pins: pinsIn.length, + }); + } + + const pins = pinsIn.map((p, i) => { + if (p.arg !== undefined && p.offset !== undefined) + throw invalid('pin arg and offset are mutually exclusive'); + if (p.offset !== undefined) { + if ( + typeof p.expected !== 'string' || + !isHex(p.expected) || + p.expected.length !== 66 + ) { + throw invalid( + `pins[${i}].expected must be the exact 32-byte calldata word in offset form` + ); + } + return { + offset: rawOffset(p.offset, `pins[${i}]`), + expected: p.expected.toLowerCase() as Hex, + }; + } + if (typeof p.arg !== 'number') throw invalid('pin requires arg or offset'); + const offset = argumentOffset(parsed.inputs, p.arg, `pins[${i}]`); + const param = (parsed.inputs as readonly AbiParameter[])[p.arg]; + return { offset, expected: encodeArgWord(param, p.expected, `pins[${i}]`) }; + }); + const offsets = new Set(pins.map((p) => p.offset)); + if (offsets.size !== pins.length) + throw invalid('two pins address the same argument'); + + let amount: NativeTermsWire['amount'] = { + enabled: false, + offset: 0, + maxPerCall: BigInt(0), + maxTotal: BigInt(0), + }; + if (rule.amount) { + let offset: number; + if (rule.amount.arg !== undefined && rule.amount.offset !== undefined) + throw invalid('amount arg and offset are mutually exclusive'); + if (rule.amount.offset !== undefined) { + offset = rawOffset(rule.amount.offset, 'amount'); + } else { + if (typeof rule.amount.arg !== 'number') + throw invalid('amount requires arg or offset'); + offset = argumentOffset(parsed.inputs, rule.amount.arg, 'amount'); + const param = (parsed.inputs as readonly AbiParameter[])[rule.amount.arg]; + if (!/^uint\d*$/.test(param.type)) { + throw invalid( + `amount argument must be an unsigned integer, got ${param.type}` + ); + } + } + if (offsets.has(offset)) throw invalid('amount argument is also pinned'); + assertUint(rule.amount.maxPerCall, 256, 'amount.maxPerCall'); + const maxTotal = withDefault( + rule.amount.maxTotal, + AGENTIC_DEFAULTS.native.amountMaxTotal + ); + assertUint(maxTotal, 256, 'amount.maxTotal'); + amount = { + enabled: true, + offset, + maxPerCall: rule.amount.maxPerCall, + maxTotal, + }; + } + + const maxValuePerCall = withDefault( + rule.maxValuePerCall, + AGENTIC_DEFAULTS.native.maxValuePerCall + ); + const maxValueTotal = withDefault( + rule.maxValueTotal, + AGENTIC_DEFAULTS.native.maxValueTotal + ); + assertUint(maxValuePerCall, 256, 'maxValuePerCall'); + assertUint(maxValueTotal, 256, 'maxValueTotal'); + const maxCalls = + rule.maxCalls === undefined + ? Number(AGENTIC_DEFAULTS.native.maxCalls.value) + : rule.maxCalls; + if (!Number.isInteger(maxCalls) || maxCalls < 0 || maxCalls > UINT32_MAX) { + throw invalid('maxCalls must be a uint32 integer'); + } + + return { + parsed, + terms: { + validUntil: rule.validUntil, + target: getAddress(rule.target), + selector: parsed.selector, + maxValuePerCall, + maxValueTotal, + amount, + maxCalls, + pins, + }, + }; +} + +export function encodeNativeTerms(terms: NativeTermsWire): Hex { + return encodeAbiParameters([NATIVE_TERMS_PARAM], [terms]); +} + +export function decodeNativeTerms(body: Hex): NativeTermsWire { + const [terms] = decodeAbiParameters([NATIVE_TERMS_PARAM], body); + return terms as unknown as NativeTermsWire; +} + +/** + * Wire terms back to the public NativeRule shape. Stored terms carry calldata + * offsets and exact words but no ABI, so pins and amount are returned in the + * raw `offset` form (never a guessed argument index) and `selector` is the + * 4-byte hex. The result re-encodes to the same terms. + */ +export function nativeTermsToRule( + terms: NativeTermsWire, + agent: Address +): NativeRule { + const rule: NativeRule = { + agent: getAddress(agent), + target: getAddress(terms.target), + selector: + terms.selector.toLowerCase() === VALUE_ONLY_SELECTOR + ? 'value-only' + : (terms.selector.toLowerCase() as AgenticHex), + validUntil: Number(terms.validUntil), + maxValuePerCall: terms.maxValuePerCall, + maxValueTotal: terms.maxValueTotal, + maxCalls: Number(terms.maxCalls), + }; + if (terms.pins.length > 0) { + rule.pins = terms.pins.map((p) => ({ + offset: Number(p.offset), + expected: p.expected.toLowerCase() as AgenticHex, + })); + } + if (terms.amount.enabled) { + rule.amount = { + offset: Number(terms.amount.offset), + maxPerCall: terms.amount.maxPerCall, + maxTotal: terms.amount.maxTotal, + }; + } + return rule; +} + +export function isUnlimited(value: bigint): boolean { + return value === UINT256_MAX; +} diff --git a/packages/core/src/lib/agentic/codec/rules.ts b/packages/core/src/lib/agentic/codec/rules.ts new file mode 100644 index 00000000..0d5364b8 --- /dev/null +++ b/packages/core/src/lib/agentic/codec/rules.ts @@ -0,0 +1,198 @@ +import { + getAddress, + isAddress, + keccak256, + toBytes, + type Address, + type Hex, +} from 'viem'; +import { AgenticCapability, requireCapability } from '../capabilities'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; +import type { + NativeRule, + Rule, + UniversalRule, + SolanaRule, +} from '../agentic.types'; +import { + encodeNativeTerms, + nativeRuleToTerms, + type NativeTermsWire, +} from './native'; +import { buildSession, encodeEnvelope, type SessionWire } from './session'; +import { encodeUniversalRule, type ResolvedUniversalRule } from './universal'; +import { encodeSvmTerms, type SvmTermsWire } from './svm-terms'; +import { SEND_OUTBOUND_SELECTOR } from '../contracts/v5'; +import type { UniversalTermsWire } from './universal-terms'; + +export function isSolanaRule(rule: Rule): rule is SolanaRule { + return ( + typeof (rule as SolanaRule).chainNamespace === 'string' && + (rule as SolanaRule).chainNamespace.startsWith('solana:') + ); +} + +export function isUniversalRule(rule: Rule): rule is UniversalRule { + return ( + (rule as UniversalRule).chainNamespace !== undefined && !isSolanaRule(rule) + ); +} + +/** CAIP-2 chain a rule governs: omitted = the connected Push chain. */ +export function ruleChain(rule: Rule, pushChainNamespace: string): string { + return ( + (rule as UniversalRule | SolanaRule).chainNamespace ?? pushChainNamespace + ); +} + +export function chainHash(chainNamespace: string): Hex { + return keccak256(toBytes(chainNamespace)); +} + +export interface RuleEncodeContext { + /** 'eip155:' of the connected network. */ + pushChainNamespace: string; + validator: Address; + rulesPolicy: Address; + capabilities: ReadonlySet; + nowSeconds: number; + gateway?: Address; + universal?: ReadonlyMap; + svm?: ReadonlyMap; + /** + * Addresses a native rule may never target (AGW _requireGrantableTarget / + * URP NativeTargetIsGateway): wallet, engine, policy, validator, factory, + * gateway. 0x0 and 0x1 are always refused. + */ + forbiddenTargets?: readonly Address[]; +} + +export interface PreparedRule { + rule: Rule; + agent: Address; + chainNamespace: string; + session: SessionWire; + /** Native terms when the rule is native (used for previews and assertions). */ + nativeTerms?: NativeTermsWire; + universalTerms?: UniversalTermsWire; + svmTerms?: SvmTermsWire; +} + +/** Validate before signing. V5 permits several grants for the same agent/chain. */ +export function prepareRules( + rules: readonly Rule[], + ctx: RuleEncodeContext & { + /** Wallet owner; when given, an agent equal to it is AGENT_IS_OWNER. */ + owner?: Address; + } +): PreparedRule[] { + if (!Array.isArray(rules)) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'rules must be an array' + ); + } + return rules.map((rule, i) => { + if (!rule || typeof rule !== 'object') { + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + `rules[${i}] is not an object` + ); + } + if ( + !isAddress(rule.agent, { strict: false }) || + /^0x0{40}$/i.test(rule.agent) + ) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + `rules[${i}].agent must be a non-zero Push address` + ); + } + const agent = getAddress(rule.agent); + if (ctx.owner && agent === getAddress(ctx.owner)) { + throw new AgenticError( + AGENTIC_ERROR_CODE.AGENT_IS_OWNER, + `rules[${i}].agent is the wallet owner; the owner uses the owner door` + ); + } + const chainNamespace = ruleChain(rule, ctx.pushChainNamespace); + if ( + isUniversalRule(rule) && + rule.chainNamespace === ctx.pushChainNamespace + ) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + `rules[${i}] names the connected Push chain; omit chainNamespace for a native rule` + ); + } + if ('ref' in rule) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'Rule ref is not supported; remove it from the input' + ); + } + + if (isSolanaRule(rule)) { + requireCapability( + ctx.capabilities, + AgenticCapability.UNIVERSAL_SVM_RULES + ); + const terms = ctx.svm?.get(rule); + if (!terms || !ctx.gateway) + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'SVM rules require resolved wallet context and named IDL inputs' + ); + return { + rule, + agent, + chainNamespace, + svmTerms: terms, + session: buildSession({ + validator: ctx.validator, + rulesPolicy: ctx.rulesPolicy, + agent, + actions: [ + { + target: ctx.gateway, + selector: SEND_OUTBOUND_SELECTOR, + initData: encodeEnvelope( + chainNamespace, + encodeSvmTerms(terms, ctx.nowSeconds) + ), + }, + ], + }), + }; + } + if (isUniversalRule(rule)) { + return encodeUniversalRule(rule, ctx); + } + requireCapability(ctx.capabilities, AgenticCapability.NATIVE_RULES); + const { terms } = nativeRuleToTerms(rule as NativeRule, ctx); + const forbidden = [ + '0x0000000000000000000000000000000000000000', + '0x0000000000000000000000000000000000000001', + ...(ctx.forbiddenTargets ?? []), + ].map((a) => a.toLowerCase()); + if (forbidden.includes(terms.target.toLowerCase())) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + `rules[${i}].target ${terms.target} is a wallet-infrastructure address the contracts refuse as a native target` + ); + } + const session = buildSession({ + validator: ctx.validator, + agent, + rulesPolicy: ctx.rulesPolicy, + actions: [ + { + target: terms.target, + selector: terms.selector, + initData: encodeEnvelope(chainNamespace, encodeNativeTerms(terms)), + }, + ], + }); + return { rule, agent, chainNamespace, session, nativeTerms: terms }; + }); +} diff --git a/packages/core/src/lib/agentic/codec/selectors.ts b/packages/core/src/lib/agentic/codec/selectors.ts new file mode 100644 index 00000000..317575f7 --- /dev/null +++ b/packages/core/src/lib/agentic/codec/selectors.ts @@ -0,0 +1,77 @@ +import { + parseAbiItem, + toFunctionSelector, + type AbiFunction, + type AbiParameter, +} from 'viem'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; +import type { AgenticHex, Selector } from '../agentic.types'; + +/** Selector URP uses for a value-only native rule (empty calldata). */ +export const VALUE_ONLY_SELECTOR = '0xffffffff' as const; + +export interface ParsedSelector { + /** 4-byte selector, lowercase. */ + selector: AgenticHex; + /** Canonical signature when the caller supplied one. */ + signature?: string; + /** ABI inputs, only available when the caller supplied a signature. */ + inputs?: readonly AbiParameter[]; + valueOnly: boolean; +} + +const HEX_SELECTOR = /^0x[0-9a-fA-F]{8}$/; + +/** + * Parse a public selector (`'0x617ba037'`, `'supply(address,uint256,address,uint16)'` + * or `'value-only'`). A signature is required wherever pins, amounts or + * beneficiaries need argument positions; a bare hex selector carries none. + */ +export function parseSelector(input: Selector | 'value-only'): ParsedSelector { + if (input === 'value-only') { + return { selector: VALUE_ONLY_SELECTOR, valueOnly: true }; + } + if (typeof input !== 'string') { + throw invalid(`selector must be a string, got ${typeof input}`); + } + if (HEX_SELECTOR.test(input)) { + const selector = input.toLowerCase() as AgenticHex; + if (selector === VALUE_ONLY_SELECTOR) { + return { selector, valueOnly: true }; + } + return { selector, valueOnly: false }; + } + let item: AbiFunction; + try { + const parsed = parseAbiItem(`function ${input}`); + if (parsed.type !== 'function') throw new Error('not a function'); + item = parsed; + } catch (cause) { + throw invalid( + `selector "${input}" is neither a 4-byte hex selector nor a function signature`, + cause + ); + } + const selector = toFunctionSelector(item).toLowerCase() as AgenticHex; + if (selector === VALUE_ONLY_SELECTOR) { + throw invalid(`selector "${input}" collides with the reserved value-only selector`); + } + return { + selector, + signature: `${item.name}(${item.inputs.map(canonicalType).join(',')})`, + inputs: item.inputs, + valueOnly: false, + }; +} + +function canonicalType(p: AbiParameter): string { + if (p.type.startsWith('tuple')) { + const components = (p as { components?: readonly AbiParameter[] }).components ?? []; + return `(${components.map(canonicalType).join(',')})${p.type.slice(5)}`; + } + return p.type; +} + +function invalid(message: string, cause?: unknown): AgenticError { + return new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, message, { cause }); +} diff --git a/packages/core/src/lib/agentic/codec/session.ts b/packages/core/src/lib/agentic/codec/session.ts new file mode 100644 index 00000000..fc98c1f6 --- /dev/null +++ b/packages/core/src/lib/agentic/codec/session.ts @@ -0,0 +1,116 @@ +import { + decodeAbiParameters, + encodeAbiParameters, + getAbiItem, + type AbiParameter, + type Address, + type Hex, +} from 'viem'; +import { AGW_ABI } from '../contracts/abi/v5'; +import { agentConfig } from './ids'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; + +/** + * The smartsessions `Session` a grant carries (DataTypes.sol:56-86, pinned + * v5). The wallet overwrites `salt` with its grant nonce, so the value + * sent is irrelevant; it is always zero here. + */ +export interface SessionWire { + sessionValidator: Address; + sessionValidatorInitData: Hex; + salt: Hex; + userOpPolicies: readonly { policy: Address; initData: Hex }[]; + erc7739Policies: { + allowedERC7739Content: readonly { + appDomainSeparator: Hex; + contentNames: readonly string[]; + }[]; + erc1271Policies: readonly { policy: Address; initData: Hex }[]; + }; + actions: readonly { + actionTargetSelector: Hex; + actionTarget: Address; + actionPolicies: readonly { policy: Address; initData: Hex }[]; + }[]; + permitERC4337Paymaster: boolean; +} + +export const SESSION_PARAM: AbiParameter = getAbiItem({ + abi: AGW_ABI, + name: 'grantRules', +}).inputs[0] as AbiParameter; + +const ZERO_SALT = `0x${'00'.repeat(32)}` as Hex; + +export const ENVELOPE_VERSION = 1; + +/** V5 URP envelope: abi.encode(uint16(1), string chainNamespace, bytes body). */ +export function encodeEnvelope(chainNamespace: string, body: Hex): Hex { + return encodeAbiParameters( + [{ type: 'uint16' }, { type: 'string' }, { type: 'bytes' }], + [ENVELOPE_VERSION, chainNamespace, body] + ); +} + +export function decodeEnvelope(initData: Hex): { + chainNamespace: string; + body: Hex; +} { + try { + const [version, chainNamespace, body] = decodeAbiParameters( + [{ type: 'uint16' }, { type: 'string' }, { type: 'bytes' }], + initData + ); + if (version !== ENVELOPE_VERSION) + throw new Error(`unsupported rules envelope version ${version}`); + return { chainNamespace, body }; + } catch (cause) { + throw new AgenticError( + AGENTIC_ERROR_CODE.RULE_READ_FAILED, + 'malformed URP envelope', + { + cause, + } + ); + } +} + +export function buildSession(ctx: { + validator: Address; + agent: Address; + rulesPolicy: Address; + actions: { target: Address; selector: Hex; initData: Hex }[]; +}): SessionWire { + return { + sessionValidator: ctx.validator, + sessionValidatorInitData: agentConfig(ctx.agent), + salt: ZERO_SALT, + userOpPolicies: [], + erc7739Policies: { allowedERC7739Content: [], erc1271Policies: [] }, + actions: ctx.actions.map((a) => ({ + actionTargetSelector: a.selector, + actionTarget: a.target, + actionPolicies: [{ policy: ctx.rulesPolicy, initData: a.initData }], + })), + permitERC4337Paymaster: false, + }; +} + +export function encodeSession(session: SessionWire): Hex { + return encodeAbiParameters([SESSION_PARAM], [session]); +} + +export function decodeSession(bytes: Hex): SessionWire { + try { + const [session] = decodeAbiParameters([SESSION_PARAM], bytes); + return session as unknown as SessionWire; + } catch (cause) { + throw new AgenticError( + AGENTIC_ERROR_CODE.RULE_READ_FAILED, + 'malformed Session encoding', + { + cause, + } + ); + } +} diff --git a/packages/core/src/lib/agentic/codec/svm-accounts.ts b/packages/core/src/lib/agentic/codec/svm-accounts.ts new file mode 100644 index 00000000..75452b96 --- /dev/null +++ b/packages/core/src/lib/agentic/codec/svm-accounts.ts @@ -0,0 +1,104 @@ +import { PublicKey } from '@solana/web3.js'; +import { + bytesToHex, + getAddress, + hexToBytes, + type Address, + type Hex, +} from 'viem'; +import { exactHex, SVM_LIMITS, svmInvalid } from './svm-terms'; +import type { AssetCapWire } from './universal-terms'; + +const SPL_TOKEN = new PublicKey('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'); +const TOKEN_2022 = new PublicKey('TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb'); +const ASSOCIATED_TOKEN = new PublicKey( + 'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL' +); + +export function svmKey(value: string): Hex { + try { + if (value.startsWith('0x')) { + exactHex(value, 32, 'pubkey'); + return bytesToHex(new PublicKey(hexToBytes(value)).toBytes()); + } + return bytesToHex(new PublicKey(value).toBytes()); + } catch { + throw svmInvalid('invalid Solana public key'); + } +} +function key(value: string) { + return new PublicKey(hexToBytes(svmKey(value))); +} + +/** Gateway is supplied by the selected cluster registry, never a global hard-coded program. */ +export function deriveAgwSvmCea( + wallet: Address, + gatewayProgram: string +): { address: Hex; bump: number } { + if (key(gatewayProgram).equals(PublicKey.default)) + throw svmInvalid('gateway program cannot be zero'); + const [pda, bump] = PublicKey.findProgramAddressSync( + [Buffer.from('push_identity'), Buffer.from(hexToBytes(getAddress(wallet)))], + key(gatewayProgram) + ); + return { address: bytesToHex(pda.toBytes()), bump }; +} +export interface SvmTokenAccountInput { + mint: string; + tokenProgram?: string; +} +export type ResolvedSvmAsset = + | { kind: 'native'; cap: AssetCapWire } + | { kind: 'spl'; cap: AssetCapWire; mint: string; tokenProgram?: string }; + +/** Every resolved SPL cap contributes an ATA; caller cannot omit a listed mint. */ +export function resolveAgwSvmRuleContext( + wallet: Address, + gatewayProgram: string, + assets: readonly ResolvedSvmAsset[], + outputs: readonly SvmTokenAccountInput[] = [] +) { + if (!assets.length || assets.length > SVM_LIMITS.assets) + throw svmInvalid('resolved assets must contain 1..8 entries'); + const tokens = assets.flatMap((a) => + a.kind === 'spl' ? [{ mint: a.mint, tokenProgram: a.tokenProgram }] : [] + ); + return { + ...deriveAgwSvmValueAccounts(wallet, gatewayProgram, tokens, outputs), + assets: assets.map((a) => a.cap), + }; +} +export function deriveAgwSvmAta( + owner: string, + token: SvmTokenAccountInput +): Hex { + const mint = key(token.mint), + program = token.tokenProgram ? key(token.tokenProgram) : SPL_TOKEN; + if (mint.equals(PublicKey.default)) + throw svmInvalid('native SOL uses the CEA, not an ATA'); + if (!program.equals(SPL_TOKEN) && !program.equals(TOKEN_2022)) + throw svmInvalid('unsupported token program'); + const [ata] = PublicKey.findProgramAddressSync( + [key(owner).toBuffer(), program.toBuffer(), mint.toBuffer()], + ASSOCIATED_TOKEN + ); + return bytesToHex(ata.toBytes()); +} +/** Includes every listed mint and swap-output mint. Native SOL is already covered by the CEA. */ +export function deriveAgwSvmValueAccounts( + wallet: Address, + gatewayProgram: string, + tokens: readonly SvmTokenAccountInput[], + outputs: readonly SvmTokenAccountInput[] = [] +): { expectedCEA: Hex; gatewayProgram: Hex; ceaAccounts: Hex[] } { + const expectedCEA = deriveAgwSvmCea(wallet, gatewayProgram).address; + const ceaAccounts = [ + ...new Set([ + expectedCEA, + ...[...tokens, ...outputs].map((t) => deriveAgwSvmAta(expectedCEA, t)), + ]), + ]; + if (ceaAccounts.length > SVM_LIMITS.ceaAccounts) + throw svmInvalid('derived CEA value-account set exceeds 16'); + return { expectedCEA, gatewayProgram: svmKey(gatewayProgram), ceaAccounts }; +} diff --git a/packages/core/src/lib/agentic/codec/svm-idl.ts b/packages/core/src/lib/agentic/codec/svm-idl.ts new file mode 100644 index 00000000..4e7f22f4 --- /dev/null +++ b/packages/core/src/lib/agentic/codec/svm-idl.ts @@ -0,0 +1,269 @@ +/** Compile named Anchor IDL constraints. Unsupported layouts are never guessed. */ +import type { Idl } from '@coral-xyz/anchor'; +import { bytesToHex, hexToBytes, type Hex } from 'viem'; +import type { SolanaRule, SvmAccountRef } from '../agentic.types'; +import { svmKey } from './svm-accounts'; +import { + SvmDataPinMode, + svmInvalid, + validateSvmTerms, + type SvmTermsWire, + type SvmDataPinWire, +} from './svm-terms'; + +export type SvmResolvedContext = Pick< + SvmTermsWire, + 'assets' | 'expectedCEA' | 'gatewayProgram' | 'ceaAccounts' +> & { + /** Verified mint -> wallet ATA mapping, including output mints. */ + tokenAccounts: ReadonlyMap; +}; +type Field = { offset: number; len: number; type: unknown }; +const widths: Record = { + bool: 1, + u8: 1, + i8: 1, + u16: 2, + i16: 2, + u32: 4, + i32: 4, + f32: 4, + u64: 8, + i64: 8, + f64: 8, + u128: 16, + i128: 16, + u256: 32, + i256: 32, + pubkey: 32, +}; +function width(type: unknown): number { + if (typeof type === 'string' && widths[type]) return widths[type]; + if (type && typeof type === 'object' && 'array' in type) { + const a = (type as { array: unknown }).array; + if ( + Array.isArray(a) && + a.length === 2 && + Number.isSafeInteger(a[1]) && + a[1] > 0 + ) { + const size = width(a[0]) * a[1]; + if (size <= 1024) return size; + } + } + throw svmInvalid( + 'IDL field layout is not supported: use fixed-width primitives or fixed arrays' + ); +} +export function svmIdlInstruction(idl: Idl, name: string) { + if (!idl || !Array.isArray(idl.instructions) || typeof name !== 'string') + throw svmInvalid('instruction requires an Anchor IDL and name'); + const found = idl.instructions.filter((i) => i.name === name); + if (found.length !== 1) + throw svmInvalid(`IDL instruction ${name} must exist exactly once`); + const ix = found[0]; + if ( + !Array.isArray(ix.discriminator) || + ix.discriminator.length !== 8 || + ix.discriminator.some((b) => !Number.isInteger(b) || b < 0 || b > 255) + ) + throw svmInvalid('Anchor IDL discriminator must contain eight bytes'); + return ix; +} +function accountNames(accounts: unknown[], prefix = ''): string[] { + return accounts.flatMap((entry) => { + if ( + !entry || + typeof entry !== 'object' || + !('name' in entry) || + typeof entry.name !== 'string' + ) + throw svmInvalid('invalid IDL account'); + const name = prefix + entry.name; + if ('accounts' in entry) + throw svmInvalid( + 'nested IDL accounts are not supported by the instruction resolver' + ); + if ('optional' in entry && entry.optional) + throw svmInvalid('optional IDL accounts are not supported for rules'); + return [name]; + }); +} +function resolveAccount(ref: SvmAccountRef, ctx: SvmResolvedContext): Hex { + if (!ref || typeof ref !== 'object') + throw svmInvalid('invalid named account reference'); + if (ref.kind === 'walletCEA') return ctx.expectedCEA; + if (ref.kind === 'address') return svmKey(ref.address); + if (ref.kind === 'walletATA') { + const ata = ctx.tokenAccounts.get(svmKey(ref.token)); + if (!ata) + throw svmInvalid( + 'walletATA mint must be listed in assets or outputTokens' + ); + return ata; + } + throw svmInvalid('unknown named account reference'); +} +function unsigned(f: Field): void { + if (typeof f.type !== 'string' || !/^u(8|16|32|64)$/.test(f.type)) + throw svmInvalid( + 'range/ratio constraints require unsigned integer fields of at most eight bytes' + ); +} +function bound(v: bigint, len: number): Hex { + if ( + typeof v !== 'bigint' || + v < BigInt(0) || + v >= BigInt(1) << BigInt(len * 8) + ) + throw svmInvalid('field constraint exceeds its unsigned width'); + return `0x${v.toString(16).padStart(64, '0')}`; +} +export function compileSvmIdlRule( + rule: SolanaRule, + ctx: SvmResolvedContext, + now: number +): SvmTermsWire { + if ( + !Array.isArray(rule.allowedInstructions) || + !rule.allowedInstructions.length || + rule.allowedInstructions.length > 32 + ) + throw svmInvalid('allowedInstructions must contain 1..32 entries'); + const terms: SvmTermsWire = { + validUntil: rule.validUntil, + maxGasPerCall: rule.maxGasPerCall, + assets: ctx.assets, + expectedCEA: ctx.expectedCEA, + gatewayProgram: ctx.gatewayProgram, + ceaAccounts: ctx.ceaAccounts, + programs: [], + pins: [], + dataPins: [], + }; + const programs = [], + pins = [], + dataPins: SvmDataPinWire[] = []; + for (const [ruleIndex, entry] of rule.allowedInstructions.entries()) { + const ix = svmIdlInstruction( + entry.instruction?.idl, + entry.instruction?.name + ); + const program = svmKey(entry.program); + if (svmKey(entry.instruction.idl.address) !== program) + throw svmInvalid('IDL address differs from rule program'); + if (!Array.isArray(ix.accounts) || !Array.isArray(entry.accounts)) + throw svmInvalid('instruction accounts are required'); + const names = accountNames(ix.accounts); + if (new Set(names).size !== names.length) + throw svmInvalid('duplicate IDL account names'); + programs.push({ + program, + discriminator: bytesToHex( + Uint8Array.from([ + ...ix.discriminator, + ...Array(8 - ix.discriminator.length).fill(0), + ]) + ), + discriminatorLen: ix.discriminator.length, + dataless: false, + maxAccounts: names.length, + }); + for (const a of entry.accounts) { + const accountIndex = names.indexOf(a.name); + if (accountIndex < 0) throw svmInvalid(`unknown IDL account ${a.name}`); + pins.push({ + ruleIndex, + accountIndex, + expected: resolveAccount(a.expected, ctx), + }); + } + const fields = new Map(); + let offset = ix.discriminator.length; + // Reject variable/nested-defined layouts rather than claiming a reliable offset. + for (const arg of ix.args) { + if (fields.has(arg.name)) throw svmInvalid('duplicate IDL field name'); + const len = width(arg.type); + fields.set(arg.name, { offset, len, type: arg.type }); + offset += len; + } + if (offset > 1024) + throw svmInvalid('IDL instruction data exceeds the policy limit'); + const field = (name: string) => { + const f = fields.get(name); + if (!f) throw svmInvalid(`unknown IDL field ${name}`); + return f; + }; + if (entry.fields !== undefined && !Array.isArray(entry.fields)) + throw svmInvalid('fields must be an array'); + for (const constraint of entry.fields ?? []) { + const keys = ['equals', 'min', 'max', 'minRatio'].filter( + (k) => k in constraint + ); + if (keys.length !== 1) + throw svmInvalid( + 'each field constraint must specify exactly one comparison' + ); + const f = field( + 'numerator' in constraint ? constraint.numerator : constraint.name + ); + const p: SvmDataPinWire = { + ruleIndex, + fromEnd: false, + offset: f.offset, + offsetB: 0, + len: f.len, + mode: SvmDataPinMode.EQ, + expected: `0x${'00'.repeat(32)}`, + num: BigInt(0), + den: BigInt(0), + }; + if ('minRatio' in constraint) { + unsigned(f); + const b = field(constraint.denominator); + unsigned(b); + if (f.len !== b.len) + throw svmInvalid('ratio fields must have the same width'); + Object.assign(p, { + mode: SvmDataPinMode.RATIO_GTE_LE, + offsetB: b.offset, + num: constraint.minRatio.num, + den: constraint.minRatio.den, + }); + } else if ('min' in constraint || 'max' in constraint) { + unsigned(f); + const min = 'min' in constraint; + p.mode = min ? SvmDataPinMode.GTE_LE : SvmDataPinMode.LTE_LE; + p.expected = bound(min ? constraint.min : constraint.max, f.len); + } else { + let bytes: Uint8Array; + if (typeof constraint.equals === 'bigint') { + unsigned(f); + bound(constraint.equals, f.len); + bytes = Uint8Array.from({ length: f.len }, (_, i) => + Number( + ((constraint.equals as bigint) >> BigInt(8 * i)) & BigInt(255) + ) + ); + } else if (typeof constraint.equals === 'boolean') { + if (f.type !== 'bool') + throw svmInvalid('boolean equality requires a bool field'); + bytes = Uint8Array.of(constraint.equals ? 1 : 0); + } else { + if (!/^0x(?:[a-fA-F0-9]{2})*$/.test(constraint.equals)) + throw svmInvalid('equality requires exact hex bytes'); + bytes = hexToBytes(constraint.equals); + } + if (bytes.length !== f.len || f.len > 32) + throw svmInvalid( + 'equality value must match field width (at most 32 bytes)' + ); + p.expected = `0x${bytesToHex(bytes).slice(2).padEnd(64, '0')}`; + } + dataPins.push(p); + } + } + Object.assign(terms, { programs, pins, dataPins }); + validateSvmTerms(terms, now); + return terms; +} diff --git a/packages/core/src/lib/agentic/codec/svm-terms.ts b/packages/core/src/lib/agentic/codec/svm-terms.ts new file mode 100644 index 00000000..dfae8ad7 --- /dev/null +++ b/packages/core/src/lib/agentic/codec/svm-terms.ts @@ -0,0 +1,303 @@ +/** Internal v5 SVM wire representation; not a proposed public Rule API. */ +import { + decodeAbiParameters, + encodeAbiParameters, + isAddress, + type Hex, +} from 'viem'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; +import { UINT256_MAX } from './defaults'; +import type { AssetCapWire } from './universal-terms'; + +export enum SvmDataPinMode { + EQ, + GTE_LE, + LTE_LE, + RATIO_GTE_LE, +} +export interface AllowedProgramWire { + program: Hex; + discriminator: Hex; + discriminatorLen: number; + dataless: boolean; + maxAccounts: number; +} +export interface SvmAccountPinWire { + ruleIndex: number; + accountIndex: number; + expected: Hex; +} +export interface SvmDataPinWire { + ruleIndex: number; + fromEnd: boolean; + offset: number; + offsetB: number; + len: number; + mode: SvmDataPinMode; + expected: Hex; + num: bigint; + den: bigint; +} +export interface SvmTermsWire { + validUntil: number; + expectedCEA: Hex; + gatewayProgram: Hex; + assets: readonly AssetCapWire[]; + maxGasPerCall: bigint; + ceaAccounts: readonly Hex[]; + programs: readonly AllowedProgramWire[]; + pins: readonly SvmAccountPinWire[]; + dataPins: readonly SvmDataPinWire[]; +} +export const SVM_LIMITS = { + assets: 8, + programs: 32, + pins: 16, + dataPins: 8, + ceaAccounts: 16, + accounts: 64, + ixData: 1024, +} as const; +export const UINT64_MAX = BigInt(2) ** BigInt(64) - BigInt(1); +export const FORBIDDEN_SVM_PROGRAMS: readonly Hex[] = [ + `0x${'00'.repeat(32)}`, + '0x06ddf6e1d765a193d9cbe146ceeb79ac1cb485ed5f5b37913a8cf5857eff00a9', + '0x06ddf6e1ee758fde18425dbce46ccddab61afc4d83b90d27febdf928d8a18bfc', + '0x06a1d8179137542a983437bdfe2a7ab2557f535c8a78722b68a49dc000000000', + '0x02a8f6914e88a1b0e210153ef763ae2b00c2b93d16c124d2c0537a1004800000', + '0x0277a6af97339b7ac88d1892c90446f50002309266f62e53c118244982000000', +]; +export const SVM_TERMS_PARAM = { + type: 'tuple', + components: [ + { name: 'validUntil', type: 'uint48' }, + { name: 'expectedCEA', type: 'bytes32' }, + { name: 'gatewayProgram', type: 'bytes32' }, + { + name: 'assets', + type: 'tuple[]', + components: [ + { name: 'token', type: 'address' }, + { name: 'maxPerCall', type: 'uint256' }, + { name: 'maxTotal', type: 'uint256' }, + ], + }, + { name: 'maxGasPerCall', type: 'uint256' }, + { name: 'ceaAccounts', type: 'bytes32[]' }, + { + name: 'programs', + type: 'tuple[]', + components: [ + { name: 'program', type: 'bytes32' }, + { name: 'discriminator', type: 'bytes8' }, + { name: 'discriminatorLen', type: 'uint8' }, + { name: 'dataless', type: 'bool' }, + { name: 'maxAccounts', type: 'uint8' }, + ], + }, + { + name: 'pins', + type: 'tuple[]', + components: [ + { name: 'ruleIndex', type: 'uint8' }, + { name: 'accountIndex', type: 'uint8' }, + { name: 'expected', type: 'bytes32' }, + ], + }, + { + name: 'dataPins', + type: 'tuple[]', + components: [ + { name: 'ruleIndex', type: 'uint8' }, + { name: 'fromEnd', type: 'bool' }, + { name: 'offset', type: 'uint16' }, + { name: 'offsetB', type: 'uint16' }, + { name: 'len', type: 'uint8' }, + { name: 'mode', type: 'uint8' }, + { name: 'expected', type: 'bytes32' }, + { name: 'num', type: 'uint64' }, + { name: 'den', type: 'uint64' }, + ], + }, + ], +} as const; + +export function svmInvalid(message: string): AgenticError { + return new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, message); +} +export function exactHex( + value: unknown, + bytes: number, + field: string +): asserts value is Hex { + if ( + typeof value !== 'string' || + !new RegExp(`^0x[0-9a-fA-F]{${bytes * 2}}$`).test(value) + ) + throw svmInvalid(`${field} must contain exactly ${bytes} bytes`); +} +function integer(value: number, max: number, field: string) { + if (!Number.isInteger(value) || value < 0 || value > max) + throw svmInvalid(`${field} is out of range`); +} +function uint(value: bigint, max: bigint, field: string) { + if (typeof value !== 'bigint' || value < BigInt(0) || value > max) + throw svmInvalid(`${field} is out of range`); +} +export function isForbiddenSvmProgram( + program: Hex, + terms: Pick +): boolean { + return [ + ...FORBIDDEN_SVM_PROGRAMS, + terms.gatewayProgram, + terms.expectedCEA, + ].some((x) => x.toLowerCase() === program.toLowerCase()); +} +function offsetValid(fromEnd: boolean, offset: number, len: number): boolean { + return fromEnd + ? offset >= len && offset <= SVM_LIMITS.ixData + : offset + len <= SVM_LIMITS.ixData; +} + +/** Grant-time structural rules. Chain/token/mint correctness requires resolved on-chain inputs. */ +export function validateSvmTerms(t: SvmTermsWire, nowSeconds: number): void { + integer(t.validUntil, 2 ** 48 - 1, 'validUntil'); + if (t.validUntil <= nowSeconds) + throw svmInvalid('validUntil must be in the future'); + exactHex(t.expectedCEA, 32, 'expectedCEA'); + exactHex(t.gatewayProgram, 32, 'gatewayProgram'); + if ( + BigInt(t.expectedCEA) === BigInt(0) || + BigInt(t.gatewayProgram) === BigInt(0) + ) + throw svmInvalid('CEA/gateway cannot be zero'); + uint(t.maxGasPerCall, UINT256_MAX, 'maxGasPerCall'); + if (!t.assets.length || t.assets.length > SVM_LIMITS.assets) + throw svmInvalid('assets must contain 1..8 entries'); + const tokens = new Set(); + for (const a of t.assets) { + if (!isAddress(a.token, { strict: false }) || BigInt(a.token) === BigInt(0)) + throw svmInvalid('asset token must be a non-zero PRC20'); + if (tokens.has(a.token.toLowerCase())) throw svmInvalid('duplicate asset'); + tokens.add(a.token.toLowerCase()); + uint(a.maxPerCall, UINT256_MAX, 'maxPerCall'); + uint(a.maxTotal, UINT256_MAX, 'maxTotal'); + } + if (!t.programs.length || t.programs.length > SVM_LIMITS.programs) + throw svmInvalid('programs must contain 1..32 entries'); + t.programs.forEach((r, i) => { + exactHex(r.program, 32, 'program'); + exactHex(r.discriminator, 8, 'discriminator'); + if (typeof r.dataless !== 'boolean') + throw svmInvalid('dataless must be boolean'); + integer(r.discriminatorLen, 8, 'discriminatorLen'); + integer(r.maxAccounts, SVM_LIMITS.accounts, 'maxAccounts'); + if (r.dataless !== (r.discriminatorLen === 0)) + throw svmInvalid('dataless and discriminator length disagree'); + if (isForbiddenSvmProgram(r.program, t)) + throw svmInvalid('forbidden program'); + for (const earlier of t.programs.slice(0, i)) { + if (earlier.program.toLowerCase() !== r.program.toLowerCase()) continue; + const overlap = + earlier.dataless || r.dataless + ? earlier.dataless && r.dataless + : earlier.discriminator + .slice( + 0, + 2 + 2 * Math.min(earlier.discriminatorLen, r.discriminatorLen) + ) + .toLowerCase() === + r.discriminator + .slice( + 0, + 2 + 2 * Math.min(earlier.discriminatorLen, r.discriminatorLen) + ) + .toLowerCase(); + if (overlap) + throw svmInvalid('ambiguous instruction discriminator prefixes'); + } + }); + if (t.pins.length > SVM_LIMITS.pins) + throw svmInvalid('too many account pins'); + const positions = new Set(), + covered = new Set(); + for (const p of t.pins) { + integer(p.ruleIndex, t.programs.length - 1, 'pin ruleIndex'); + integer(p.accountIndex, SVM_LIMITS.accounts - 1, 'accountIndex'); + exactHex(p.expected, 32, 'pin expected'); + const count = t.programs[p.ruleIndex].maxAccounts; + if (count && p.accountIndex >= count) + throw svmInvalid('pin outside fixed account count'); + const key = `${p.ruleIndex}:${p.accountIndex}`; + if (positions.has(key)) throw svmInvalid('duplicate account pin'); + positions.add(key); + covered.add(p.ruleIndex); + } + if (covered.size !== t.programs.length) + throw svmInvalid('every program rule needs an account pin'); + if (t.dataPins.length > SVM_LIMITS.dataPins) + throw svmInvalid('too many data pins'); + for (const p of t.dataPins) { + integer(p.ruleIndex, t.programs.length - 1, 'data pin ruleIndex'); + integer(p.mode, 3, 'data pin mode'); + integer(p.len, p.mode === SvmDataPinMode.EQ ? 32 : 8, 'data pin len'); + integer(p.offset, 65535, 'offset'); + integer(p.offsetB, 65535, 'offsetB'); + exactHex(p.expected, 32, 'data pin expected'); + uint(p.num, UINT64_MAX, 'num'); + uint(p.den, UINT64_MAX, 'den'); + if ( + typeof p.fromEnd !== 'boolean' || + !p.len || + t.programs[p.ruleIndex].dataless || + !offsetValid(p.fromEnd, p.offset, p.len) + ) + throw svmInvalid('invalid data pin shape'); + if ( + p.mode === SvmDataPinMode.EQ && + !/^0*$/.test(p.expected.slice(2 + p.len * 2)) + ) + throw svmInvalid('EQ expected must be left-aligned'); + if ( + (p.mode === SvmDataPinMode.GTE_LE || p.mode === SvmDataPinMode.LTE_LE) && + BigInt(p.expected) >= BigInt(1) << BigInt(p.len * 8) + ) + throw svmInvalid('integer expected exceeds field width'); + if ( + p.mode === SvmDataPinMode.RATIO_GTE_LE && + (!p.num || !p.den || !offsetValid(p.fromEnd, p.offsetB, p.len)) + ) + throw svmInvalid('invalid ratio pin'); + } + if (t.ceaAccounts.length > SVM_LIMITS.ceaAccounts) + throw svmInvalid('too many CEA accounts'); + const accounts = new Set(); + for (const key of t.ceaAccounts) { + exactHex(key, 32, 'CEA account'); + if ( + BigInt(key) === BigInt(0) || + accounts.has(key.toLowerCase()) || + t.programs.some((p) => p.program.toLowerCase() === key.toLowerCase()) + ) + throw svmInvalid('invalid CEA account list'); + accounts.add(key.toLowerCase()); + } + if (!accounts.has(t.expectedCEA.toLowerCase())) + throw svmInvalid('CEA account list must include expectedCEA'); +} +export function encodeSvmTerms(terms: SvmTermsWire, nowSeconds: number): Hex { + validateSvmTerms(terms, nowSeconds); + return encodeAbiParameters([SVM_TERMS_PARAM], [terms]); +} +export function decodeSvmTerms(body: Hex): SvmTermsWire { + try { + return decodeAbiParameters([SVM_TERMS_PARAM], body)[0]; + } catch (cause) { + throw new AgenticError( + AGENTIC_ERROR_CODE.RULE_READ_FAILED, + 'malformed SVM terms', + { cause } + ); + } +} diff --git a/packages/core/src/lib/agentic/codec/universal-terms.ts b/packages/core/src/lib/agentic/codec/universal-terms.ts new file mode 100644 index 00000000..4ac26304 --- /dev/null +++ b/packages/core/src/lib/agentic/codec/universal-terms.ts @@ -0,0 +1,60 @@ +import { + decodeAbiParameters, + encodeAbiParameters, + type Address, + type Hex, +} from 'viem'; + +export interface AssetCapWire { + token: Address; + maxPerCall: bigint; + maxTotal: bigint; +} +export interface AllowedCallWire { + target: Address; + selector: Hex; + beneficiaryOffset: number; + hasBeneficiary: boolean; + maxValue: bigint; +} +export interface UniversalTermsWire { + validUntil: number; + expectedCEA: Address; + assets: readonly AssetCapWire[]; + maxGasPerCall: bigint; + allowedCalls: readonly AllowedCallWire[]; +} +export const UNIVERSAL_TERMS_PARAM = { + type: 'tuple', + components: [ + { name: 'validUntil', type: 'uint48' }, + { name: 'expectedCEA', type: 'address' }, + { + name: 'assets', + type: 'tuple[]', + components: [ + { name: 'token', type: 'address' }, + { name: 'maxPerCall', type: 'uint256' }, + { name: 'maxTotal', type: 'uint256' }, + ], + }, + { name: 'maxGasPerCall', type: 'uint256' }, + { + name: 'allowedCalls', + type: 'tuple[]', + components: [ + { name: 'target', type: 'address' }, + { name: 'selector', type: 'bytes4' }, + { name: 'beneficiaryOffset', type: 'uint16' }, + { name: 'hasBeneficiary', type: 'bool' }, + { name: 'maxValue', type: 'uint256' }, + ], + }, + ], +} as const; +export function encodeUniversalTerms(terms: UniversalTermsWire): Hex { + return encodeAbiParameters([UNIVERSAL_TERMS_PARAM], [terms]); +} +export function decodeUniversalTerms(body: Hex): UniversalTermsWire { + return decodeAbiParameters([UNIVERSAL_TERMS_PARAM], body)[0]; +} diff --git a/packages/core/src/lib/agentic/codec/universal.ts b/packages/core/src/lib/agentic/codec/universal.ts new file mode 100644 index 00000000..d27b48ff --- /dev/null +++ b/packages/core/src/lib/agentic/codec/universal.ts @@ -0,0 +1,214 @@ +import { getAddress, isAddress, type Address } from 'viem'; +import { AgenticCapability, requireCapability } from '../capabilities'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; +import type { UniversalRule } from '../agentic.types'; +import type { RuleEncodeContext, PreparedRule } from './rules'; +import { argumentOffset, rawOffset } from './abi-layout'; +import { parseSelector } from './selectors'; +import { AGENTIC_DEFAULTS, UINT256_MAX, withDefault } from './defaults'; +import { buildSession, encodeEnvelope } from './session'; +import { SEND_OUTBOUND_SELECTOR } from '../contracts/v5'; +import { + encodeUniversalTerms, + type AssetCapWire, + type UniversalTermsWire, +} from './universal-terms'; + +export const MAX_ASSETS = 8; +export const MAX_ALLOWED_CALLS = 32; +export interface ResolvedUniversalRule { + expectedCEA: Address; + assets: readonly AssetCapWire[]; +} + +const CAIP2 = /^(eip155:[0-9]+|solana:[1-9A-HJ-NP-Za-km-z]{32,44})$/; +const UINT48_MAX = 2 ** 48 - 1; +function cap(value: unknown, what: string): asserts value is bigint { + if (typeof value !== 'bigint' || value < BigInt(0) || value > UINT256_MAX) + throw invalid(`${what} must be a uint256 bigint`); +} +export function validateUniversalRuleShape( + rule: UniversalRule, + nowSeconds: number +): void { + if ( + typeof rule.chainNamespace !== 'string' || + !CAIP2.test(rule.chainNamespace) + ) + throw invalid('chainNamespace must be a CAIP-2 eip155/solana chain'); + if ( + !Number.isSafeInteger(rule.validUntil) || + rule.validUntil <= nowSeconds || + rule.validUntil > UINT48_MAX + ) + throw invalid('validUntil must be a future uint48 unix timestamp'); + if (!Array.isArray(rule.assets) || rule.assets.length > MAX_ASSETS) + throw invalid(`assets must be an array of at most ${MAX_ASSETS} caps`); + cap(rule.maxGasPerCall, 'maxGasPerCall'); + if (rule.maxGasPerCall === BigInt(0)) + throw invalid('maxGasPerCall must be positive'); + if ( + !Array.isArray(rule.allowedCalls) || + rule.allowedCalls.length < 1 || + rule.allowedCalls.length > MAX_ALLOWED_CALLS + ) + throw invalid(`allowedCalls must contain 1..${MAX_ALLOWED_CALLS} entries`); + const seen = new Set(); + rule.allowedCalls.forEach((call, i) => { + if (!isAddress(call.target, { strict: false })) + throw invalid(`allowedCalls[${i}].target is not an EVM address`); + const parsed = parseSelector(call.selector); + if (parsed.valueOnly) + throw invalid(`allowedCalls[${i}] cannot be value-only`); + if (call.beneficiary !== undefined && call.beneficiaryOffset !== undefined) + throw invalid('beneficiary and beneficiaryOffset are mutually exclusive'); + if (call.beneficiary !== undefined) { + argumentOffset( + parsed.inputs, + call.beneficiary, + `allowedCalls[${i}].beneficiary` + ); + if (parsed.inputs?.[call.beneficiary]?.type !== 'address') + throw invalid( + `allowedCalls[${i}].beneficiary must be an address argument` + ); + } + if (call.beneficiaryOffset !== undefined) + rawOffset(call.beneficiaryOffset, `allowedCalls[${i}].beneficiary`); + cap( + call.maxValue ?? AGENTIC_DEFAULTS.universal.allowedCallMaxValue.value, + `allowedCalls[${i}].maxValue` + ); + const key = `${call.target.toLowerCase()}:${parsed.selector}`; + if (seen.has(key)) + throw invalid(`allowedCalls[${i}] duplicates an earlier target/selector`); + seen.add(key); + }); + const tokens = new Set(); + rule.assets.forEach((a, i) => { + const address = typeof a.token === 'string' ? a.token : a.token?.address; + if (typeof address !== 'string') + throw invalid(`assets[${i}].token is missing an address`); + const key = address.toLowerCase(); + if (tokens.has(key)) + throw invalid(`assets[${i}] duplicates an earlier token`); + tokens.add(key); + cap(a.maxPerCall, `assets[${i}].maxPerCall`); + cap( + withDefault(a.maxTotal, AGENTIC_DEFAULTS.universal.assetMaxTotal), + `assets[${i}].maxTotal` + ); + }); +} + +export function encodeUniversalRule( + rule: UniversalRule, + ctx: RuleEncodeContext +): PreparedRule { + if (rule.chainNamespace.startsWith('solana:')) + requireCapability(ctx.capabilities, AgenticCapability.UNIVERSAL_SVM_RULES); + validateUniversalRuleShape(rule, ctx.nowSeconds); + requireCapability( + ctx.capabilities, + rule.chainNamespace.startsWith('solana:') + ? AgenticCapability.UNIVERSAL_SVM_RULES + : AgenticCapability.UNIVERSAL_EVM_RULES + ); + const resolved = ctx.universal?.get(rule); + if (!resolved || !ctx.gateway) + throw invalid( + 'universal encoding requires resolved wallet CEA, PRC20 assets and gateway context' + ); + if ( + resolved.assets.length < 1 || + resolved.assets.length > MAX_ASSETS || + new Set(resolved.assets.map((a) => a.token.toLowerCase())).size !== + resolved.assets.length + ) + throw invalid('resolved assets must be 1..8 distinct PRC20s'); + if ( + !isAddress(resolved.expectedCEA) || + /^0x0{40}$/i.test(resolved.expectedCEA) + ) + throw invalid('expectedCEA must be a non-zero wallet destination account'); + const terms: UniversalTermsWire = { + validUntil: rule.validUntil, + expectedCEA: getAddress(resolved.expectedCEA), + assets: resolved.assets, + maxGasPerCall: rule.maxGasPerCall, + allowedCalls: rule.allowedCalls.map((call) => ({ + target: getAddress(call.target), + selector: parseSelector(call.selector).selector, + hasBeneficiary: + call.beneficiary !== undefined || call.beneficiaryOffset !== undefined, + beneficiaryOffset: + call.beneficiaryOffset ?? + (call.beneficiary === undefined + ? 0 + : argumentOffset( + parseSelector(call.selector).inputs, + call.beneficiary, + 'beneficiary' + )), + maxValue: withDefault( + call.maxValue, + AGENTIC_DEFAULTS.universal.allowedCallMaxValue + ), + })), + }; + const agent = getAddress(rule.agent); + return { + rule, + agent, + chainNamespace: rule.chainNamespace, + universalTerms: terms, + session: buildSession({ + validator: ctx.validator, + agent, + rulesPolicy: ctx.rulesPolicy, + actions: [ + { + target: ctx.gateway, + selector: SEND_OUTBOUND_SELECTOR, + initData: encodeEnvelope( + rule.chainNamespace, + encodeUniversalTerms(terms) + ), + }, + ], + }), + }; +} + +/** Source token addresses must be resolved from each PRC20 before calling this. */ +export function universalTermsToRule( + terms: UniversalTermsWire, + agent: Address, + chainNamespace: UniversalRule['chainNamespace'], + tokens: readonly Address[] +): UniversalRule { + if (tokens.length !== terms.assets.length) + throw invalid('origin-token list does not match stored asset order'); + return { + agent, + chainNamespace, + validUntil: Number(terms.validUntil), + maxGasPerCall: terms.maxGasPerCall, + assets: terms.assets.map((a, i) => ({ + token: tokens[i], + maxPerCall: a.maxPerCall, + maxTotal: a.maxTotal, + })), + allowedCalls: terms.allowedCalls.map((c) => ({ + target: c.target, + selector: c.selector, + maxValue: c.maxValue, + ...(c.hasBeneficiary + ? { beneficiaryOffset: Number(c.beneficiaryOffset) } + : {}), + })), + }; +} +function invalid(message: string): AgenticError { + return new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, message); +} diff --git a/packages/core/src/lib/agentic/constants.ts b/packages/core/src/lib/agentic/constants.ts new file mode 100644 index 00000000..f2f7d24b --- /dev/null +++ b/packages/core/src/lib/agentic/constants.ts @@ -0,0 +1,23 @@ +import { PUSH_NETWORK } from '../constants/enums'; +import { DONUT_V5_ADDRESSES } from './contracts/donut-v5'; + +/** Checked Donut v5 proxies. Unsupported networks are absent. */ +export interface AgenticNetworkConstants { + FACTORY: `0x${string}`; + RULES_POLICY: `0x${string}`; + MAX_PINS: number; + MAX_ALLOWED_CALLS: number; + ENVELOPE_VERSION: number; +} + +export const AGENTIC: Readonly< + Partial> +> = Object.freeze({ + [PUSH_NETWORK.TESTNET_DONUT]: Object.freeze({ + FACTORY: DONUT_V5_ADDRESSES.factory, + RULES_POLICY: DONUT_V5_ADDRESSES.rulesPolicy, + MAX_PINS: 8, + MAX_ALLOWED_CALLS: 32, + ENVELOPE_VERSION: 1, + }), +}); diff --git a/packages/core/src/lib/agentic/context.ts b/packages/core/src/lib/agentic/context.ts new file mode 100644 index 00000000..fc1f8203 --- /dev/null +++ b/packages/core/src/lib/agentic/context.ts @@ -0,0 +1,78 @@ +import { getAddress, type Address } from 'viem'; +import { CHAIN } from '../constants/enums'; +import { AgenticCapability, requireCapability } from './capabilities'; +import { resolveWalletGeneration, type AgenticGeneration } from './deployments'; +import { AGENTIC_ERROR_CODE, AgenticError } from './errors'; +import { readActiveRules } from './reads/rules'; +import { Snapshot } from './reads/snapshot'; +import type { AgenticRuntime } from './runtime'; +import type { AgenticDoor } from './agentic.types'; + +/** + * Identity of an agentic client. Three values stay separate: + * - signerOrigin: the key that signs (universal.origin) + * - signerPushAccount: its Push identity — EOA or UEA for its origin chain; + * pays Push gas and is the identity ownership checks use + * - wallet: the AGW, the execution account (universal.account) + */ +export interface AgenticExecutionContext { + wallet: Address; + door: AgenticDoor; + signerPushAccount: Address; + signerOrigin: { chain: CHAIN; address: string }; + generation: AgenticGeneration; +} + +/** + * Initialization-time resolution for `initialize(signer, { agenticWallet })`. + * Owner → owner door. Otherwise at least one ENABLED rule must name the + * signer's Push identity (expired-but-enabled still qualifies; expiry is an + * on-chain send check). Nothing here is cached for later sends. + */ +export async function resolveAgenticContext( + runtime: AgenticRuntime, + walletInput: string +): Promise { + let wallet: Address; + try { + wallet = getAddress(walletInput); + } catch (cause) { + throw new AgenticError(AGENTIC_ERROR_CODE.NOT_AGENTIC_WALLET, `"${walletInput}" is not an address`, { + cause, + }); + } + const generation = await resolveWalletGeneration(runtime.reader, runtime.network, wallet); + const signerPushAccount = runtime.signerPushAccount(); + const snap = await Snapshot.at(runtime.reader); + const owner = getAddress( + await snap.read
(wallet, generation.contracts.abis.wallet, 'owner') + ); + let door: AgenticDoor; + if (owner === signerPushAccount) { + requireCapability(generation.capabilities, AgenticCapability.OWNER_EXECUTE); + door = 'owner'; + } else { + requireCapability(generation.capabilities, AgenticCapability.AGENT_EXECUTE); + const active = await readActiveRules(snap, generation, wallet); + if (!active.some((r) => r.agent === signerPushAccount)) { + throw new AgenticError( + AGENTIC_ERROR_CODE.NOT_OWNER_OR_AGENT, + `${signerPushAccount} is neither the owner of ${wallet} nor the agent of an enabled rule`, + { + hint: runtime.signerIsPushNative() + ? 'Grant a rule to this Push address, or initialize with the owner signer.' + : 'An external key acts through its UEA for the chain it was initialized on; grant the rule to that UEA (PushChain.utils.account.deriveExecutorAccount).', + details: { wallet, signerPushAccount, owner }, + } + ); + } + door = 'agent'; + } + return { + wallet, + door, + signerPushAccount, + signerOrigin: runtime.signerOrigin(), + generation, + }; +} diff --git a/packages/core/src/lib/agentic/contracts/abi/v5/agent-validator.ts b/packages/core/src/lib/agentic/contracts/abi/v5/agent-validator.ts new file mode 100644 index 00000000..069206f6 --- /dev/null +++ b/packages/core/src/lib/agentic/contracts/abi/v5/agent-validator.ts @@ -0,0 +1,145 @@ +// GENERATED by packages/core/scripts/agw-local/gen-abi.mjs — do not edit. +// Source: packages/core/scripts/agw-local/abis/validator.json +// push-agentic-wallets@2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb +// sha256(AgentValidator.json) = a4570ddc373241580de8742cbb3d9f2c837094c65bfd1cdd52243ca0c38196fd +export const AGENT_VALIDATOR_ABI = [ + { + "type": "function", + "name": "isInitialized", + "inputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "isModuleType", + "inputs": [ + { + "name": "moduleTypeId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "onInstall", + "inputs": [ + { + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "onUninstall", + "inputs": [ + { + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "validateConfig", + "inputs": [ + { + "name": "data", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "validateSignatureWithData", + "inputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "sig", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "data", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "validSig", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "pure" + }, + { + "type": "error", + "name": "AlreadyInitialized", + "inputs": [ + { + "name": "smartAccount", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "MalformedConfig", + "inputs": [] + }, + { + "type": "error", + "name": "NotInitialized", + "inputs": [ + { + "name": "smartAccount", + "type": "address", + "internalType": "address" + } + ] + } +] as const; diff --git a/packages/core/src/lib/agentic/contracts/abi/v5/agw-factory.ts b/packages/core/src/lib/agentic/contracts/abi/v5/agw-factory.ts new file mode 100644 index 00000000..45519e58 --- /dev/null +++ b/packages/core/src/lib/agentic/contracts/abi/v5/agw-factory.ts @@ -0,0 +1,1104 @@ +// GENERATED by packages/core/scripts/agw-local/gen-abi.mjs — do not edit. +// Source: packages/core/scripts/agw-local/abis/factory.json +// push-agentic-wallets@2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb +// sha256(AGWFactory.json) = b65f66a1556d2a9ddf9aabe9f595c685c2aada436772892f5a40fb1eec846397 +export const AGW_FACTORY_ABI = [ + { + "type": "function", + "name": "DEFAULT_ADMIN_ROLE", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "OPERATOR_ROLE", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "PAUSER_ROLE", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "UPGRADE_INTERFACE_VERSION", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "acceptDefaultAdminTransfer", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "beginDefaultAdminTransfer", + "inputs": [ + { + "name": "newAdmin", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "cancelDefaultAdminTransfer", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "changeDefaultAdminDelay", + "inputs": [ + { + "name": "newDelay", + "type": "uint48", + "internalType": "uint48" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "defaultAdmin", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "defaultAdminDelay", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint48", + "internalType": "uint48" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "defaultAdminDelayIncreaseWait", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint48", + "internalType": "uint48" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "deployWallet", + "inputs": [ + { + "name": "label", + "type": "string", + "internalType": "string" + } + ], + "outputs": [ + { + "name": "wallet", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "deployWalletWithSig", + "inputs": [ + { + "name": "intent", + "type": "tuple", + "internalType": "struct OwnerIntent", + "components": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "wallet", + "type": "address", + "internalType": "address" + }, + { + "name": "executor", + "type": "address", + "internalType": "address" + }, + { + "name": "index", + "type": "uint96", + "internalType": "uint96" + }, + { + "name": "sessionHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "mode", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "execCalldataHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "nonceKey", + "type": "uint192", + "internalType": "uint192" + }, + { + "name": "nonceSeq", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "grantNonce", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "deadline", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "signerChainId", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "sig", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "label", + "type": "string", + "internalType": "string" + } + ], + "outputs": [ + { + "name": "wallet", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "domainSeparator", + "inputs": [ + { + "name": "signerChainId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getRoleAdmin", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "grantRole", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "hasRole", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "indexOf", + "inputs": [ + { + "name": "wallet", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "initialize", + "inputs": [ + { + "name": "admin", + "type": "address", + "internalType": "address" + }, + { + "name": "walletImplementation_", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "isWallet", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "owner", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "ownerOf", + "inputs": [ + { + "name": "wallet", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "pause", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "paused", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "pendingDefaultAdmin", + "inputs": [], + "outputs": [ + { + "name": "newAdmin", + "type": "address", + "internalType": "address" + }, + { + "name": "schedule", + "type": "uint48", + "internalType": "uint48" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "pendingDefaultAdminDelay", + "inputs": [], + "outputs": [ + { + "name": "newDelay", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "schedule", + "type": "uint48", + "internalType": "uint48" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "predictWallet", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "index", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "wallet", + "type": "address", + "internalType": "address" + }, + { + "name": "deployed", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "proxiableUUID", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "renounceRole", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "revokeRole", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "rollbackDefaultAdminDelay", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "supportsInterface", + "inputs": [ + { + "name": "interfaceId", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "unpause", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "upgradeToAndCall", + "inputs": [ + { + "name": "newImplementation", + "type": "address", + "internalType": "address" + }, + { + "name": "data", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "walletCount", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "walletImplementation", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "event", + "name": "DefaultAdminDelayChangeCanceled", + "inputs": [], + "anonymous": false + }, + { + "type": "event", + "name": "DefaultAdminDelayChangeScheduled", + "inputs": [ + { + "name": "newDelay", + "type": "uint48", + "indexed": false, + "internalType": "uint48" + }, + { + "name": "effectSchedule", + "type": "uint48", + "indexed": false, + "internalType": "uint48" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "DefaultAdminTransferCanceled", + "inputs": [], + "anonymous": false + }, + { + "type": "event", + "name": "DefaultAdminTransferScheduled", + "inputs": [ + { + "name": "newAdmin", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "acceptSchedule", + "type": "uint48", + "indexed": false, + "internalType": "uint48" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Initialized", + "inputs": [ + { + "name": "version", + "type": "uint64", + "indexed": false, + "internalType": "uint64" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Paused", + "inputs": [ + { + "name": "account", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RoleAdminChanged", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "previousAdminRole", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "newAdminRole", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RoleGranted", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RoleRevoked", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Unpaused", + "inputs": [ + { + "name": "account", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Upgraded", + "inputs": [ + { + "name": "implementation", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "WalletDeployed", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "index", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "wallet", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "label", + "type": "string", + "indexed": false, + "internalType": "string" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "AccessControlBadConfirmation", + "inputs": [] + }, + { + "type": "error", + "name": "AccessControlEnforcedDefaultAdminDelay", + "inputs": [ + { + "name": "schedule", + "type": "uint48", + "internalType": "uint48" + } + ] + }, + { + "type": "error", + "name": "AccessControlEnforcedDefaultAdminRules", + "inputs": [] + }, + { + "type": "error", + "name": "AccessControlInvalidDefaultAdmin", + "inputs": [ + { + "name": "defaultAdmin", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "AccessControlUnauthorizedAccount", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "neededRole", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "AddressEmptyCode", + "inputs": [ + { + "name": "target", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "CloneArgumentsTooLong", + "inputs": [] + }, + { + "type": "error", + "name": "Create2EmptyBytecode", + "inputs": [] + }, + { + "type": "error", + "name": "ERC1967InvalidImplementation", + "inputs": [ + { + "name": "implementation", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ERC1967NonPayable", + "inputs": [] + }, + { + "type": "error", + "name": "EnforcedPause", + "inputs": [] + }, + { + "type": "error", + "name": "ExecutorMismatch", + "inputs": [ + { + "name": "expected", + "type": "address", + "internalType": "address" + }, + { + "name": "actual", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ExpectedPause", + "inputs": [] + }, + { + "type": "error", + "name": "FailedCall", + "inputs": [] + }, + { + "type": "error", + "name": "FailedDeployment", + "inputs": [] + }, + { + "type": "error", + "name": "ImplementationNotSet", + "inputs": [] + }, + { + "type": "error", + "name": "IndexMismatch", + "inputs": [ + { + "name": "expected", + "type": "uint96", + "internalType": "uint96" + }, + { + "name": "provided", + "type": "uint96", + "internalType": "uint96" + } + ] + }, + { + "type": "error", + "name": "IndexOutOfRange", + "inputs": [ + { + "name": "index", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "next", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "InsufficientBalance", + "inputs": [ + { + "name": "balance", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "needed", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "IntentWalletMismatch", + "inputs": [ + { + "name": "expected", + "type": "address", + "internalType": "address" + }, + { + "name": "provided", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "InvalidInitialization", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidOwnerSignature", + "inputs": [] + }, + { + "type": "error", + "name": "NotAWallet", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "NotInitializing", + "inputs": [] + }, + { + "type": "error", + "name": "SafeCastOverflowedUintDowncast", + "inputs": [ + { + "name": "bits", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "SignatureExpired", + "inputs": [ + { + "name": "deadline", + "type": "uint48", + "internalType": "uint48" + } + ] + }, + { + "type": "error", + "name": "UUPSUnauthorizedCallContext", + "inputs": [] + }, + { + "type": "error", + "name": "UUPSUnsupportedProxiableUUID", + "inputs": [ + { + "name": "slot", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "ZeroAddress", + "inputs": [] + } +] as const; diff --git a/packages/core/src/lib/agentic/contracts/abi/v5/agw.ts b/packages/core/src/lib/agentic/contracts/abi/v5/agw.ts new file mode 100644 index 00000000..d3bed329 --- /dev/null +++ b/packages/core/src/lib/agentic/contracts/abi/v5/agw.ts @@ -0,0 +1,1584 @@ +// GENERATED by packages/core/scripts/agw-local/gen-abi.mjs — do not edit. +// Source: packages/core/scripts/agw-local/abis/wallet.json +// push-agentic-wallets@2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb +// sha256(AGW.json) = 6a145964d6c43eaa6223dc8f3d59a540ac0c2f447f25c3a99007eea25de9c695 +export const AGW_ABI = [ + { + "type": "receive", + "stateMutability": "payable" + }, + { + "type": "function", + "name": "RULES_POLICY", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "SESSION_ENGINE", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "SESSION_VALIDATOR", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "UNIVERSAL_GATEWAY_PC", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "accountId", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "agentOf", + "inputs": [ + { + "name": "rulesId", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "checkpointCount", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint64", + "internalType": "uint64" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "domainSeparator", + "inputs": [ + { + "name": "signerChainId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "execute", + "inputs": [ + { + "name": "mode", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "executionCalldata", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "executeAsAgent", + "inputs": [ + { + "name": "rulesId", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "mode", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "executionCalldata", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "executeWithSig", + "inputs": [ + { + "name": "mode", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "executionCalldata", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "intent", + "type": "tuple", + "internalType": "struct OwnerIntent", + "components": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "wallet", + "type": "address", + "internalType": "address" + }, + { + "name": "executor", + "type": "address", + "internalType": "address" + }, + { + "name": "index", + "type": "uint96", + "internalType": "uint96" + }, + { + "name": "sessionHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "mode", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "execCalldataHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "nonceKey", + "type": "uint192", + "internalType": "uint192" + }, + { + "name": "nonceSeq", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "grantNonce", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "deadline", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "signerChainId", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "sig", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "factory", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getNonce", + "inputs": [ + { + "name": "nonceKey", + "type": "uint192", + "internalType": "uint192" + } + ], + "outputs": [ + { + "name": "", + "type": "uint64", + "internalType": "uint64" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "grantNonce", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint64", + "internalType": "uint64" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "grantRules", + "inputs": [ + { + "name": "session", + "type": "tuple", + "internalType": "struct Session", + "components": [ + { + "name": "sessionValidator", + "type": "address", + "internalType": "contract ISessionValidator" + }, + { + "name": "sessionValidatorInitData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "erc7739Policies", + "type": "tuple", + "internalType": "struct ERC7739Data", + "components": [ + { + "name": "allowedERC7739Content", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNames", + "type": "string[]", + "internalType": "string[]" + } + ] + }, + { + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "actions", + "type": "tuple[]", + "internalType": "struct ActionData[]", + "components": [ + { + "name": "actionTargetSelector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "actionTarget", + "type": "address", + "internalType": "address" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "permitERC4337Paymaster", + "type": "bool", + "internalType": "bool" + } + ] + } + ], + "outputs": [ + { + "name": "rulesId", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "grantRulesWithSig", + "inputs": [ + { + "name": "session", + "type": "tuple", + "internalType": "struct Session", + "components": [ + { + "name": "sessionValidator", + "type": "address", + "internalType": "contract ISessionValidator" + }, + { + "name": "sessionValidatorInitData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "erc7739Policies", + "type": "tuple", + "internalType": "struct ERC7739Data", + "components": [ + { + "name": "allowedERC7739Content", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNames", + "type": "string[]", + "internalType": "string[]" + } + ] + }, + { + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "actions", + "type": "tuple[]", + "internalType": "struct ActionData[]", + "components": [ + { + "name": "actionTargetSelector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "actionTarget", + "type": "address", + "internalType": "address" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "permitERC4337Paymaster", + "type": "bool", + "internalType": "bool" + } + ] + }, + { + "name": "intent", + "type": "tuple", + "internalType": "struct OwnerIntent", + "components": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "wallet", + "type": "address", + "internalType": "address" + }, + { + "name": "executor", + "type": "address", + "internalType": "address" + }, + { + "name": "index", + "type": "uint96", + "internalType": "uint96" + }, + { + "name": "sessionHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "mode", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "execCalldataHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "nonceKey", + "type": "uint192", + "internalType": "uint192" + }, + { + "name": "nonceSeq", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "grantNonce", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "deadline", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "signerChainId", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "sig", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "rulesId", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "initializeAccount", + "inputs": [ + { + "name": "label_", + "type": "string", + "internalType": "string" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "installModule", + "inputs": [ + { + "name": "moduleTypeId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "module", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "isModuleInstalled", + "inputs": [ + { + "name": "moduleTypeId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "module", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isValidSignature", + "inputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "label", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "lastCheckpointBlock", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint64", + "internalType": "uint64" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "onERC1155BatchReceived", + "inputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "onERC1155Received", + "inputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "onERC721Received", + "inputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "owner", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "revokeAllRules", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "revokeRules", + "inputs": [ + { + "name": "rulesId", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setLabel", + "inputs": [ + { + "name": "label_", + "type": "string", + "internalType": "string" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "supportsExecutionMode", + "inputs": [ + { + "name": "mode", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "supportsInterface", + "inputs": [ + { + "name": "interfaceId", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "supportsModule", + "inputs": [ + { + "name": "moduleTypeId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "uninstallModule", + "inputs": [ + { + "name": "moduleTypeId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "module", + "type": "address", + "internalType": "address" + }, + { + "name": "deInitData", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "AccountInitialized", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "engine", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Checkpointed", + "inputs": [ + { + "name": "seq", + "type": "uint64", + "indexed": true, + "internalType": "uint64" + }, + { + "name": "kind", + "type": "uint8", + "indexed": false, + "internalType": "enum CheckpointKind" + }, + { + "name": "ref", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + }, + { + "name": "blockNumber", + "type": "uint64", + "indexed": false, + "internalType": "uint64" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "LabelSet", + "inputs": [ + { + "name": "label", + "type": "string", + "indexed": false, + "internalType": "string" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ModuleInstalled", + "inputs": [ + { + "name": "moduleTypeId", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "module", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ModuleUninstalled", + "inputs": [ + { + "name": "moduleTypeId", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "module", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "OwnerExecuted", + "inputs": [ + { + "name": "mode", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "executionCalldataHash", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "OwnerExecutedWithSig", + "inputs": [ + { + "name": "mode", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "executionCalldataHash", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + }, + { + "name": "nonceKey", + "type": "uint192", + "indexed": false, + "internalType": "uint192" + }, + { + "name": "nonceSeq", + "type": "uint64", + "indexed": false, + "internalType": "uint64" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RulesActionAuthorized", + "inputs": [ + { + "name": "rulesId", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "agent", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "callsHash", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RulesGranted", + "inputs": [ + { + "name": "rulesId", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "mode", + "type": "uint8", + "indexed": false, + "internalType": "enum RulesType" + }, + { + "name": "chainHash", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "chainNamespace", + "type": "string", + "indexed": false, + "internalType": "string" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RulesRevoked", + "inputs": [ + { + "name": "rulesId", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "UninstallCallbackFailed", + "inputs": [ + { + "name": "module", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "AlreadyInitialized", + "inputs": [] + }, + { + "type": "error", + "name": "CallerIsNotAgent", + "inputs": [ + { + "name": "rulesId", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "caller", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "CallerIsNotFactory", + "inputs": [] + }, + { + "type": "error", + "name": "CallerIsNotOwner", + "inputs": [] + }, + { + "type": "error", + "name": "DuplicateAction", + "inputs": [ + { + "name": "target", + "type": "address", + "internalType": "address" + }, + { + "name": "selector", + "type": "bytes4", + "internalType": "bytes4" + } + ] + }, + { + "type": "error", + "name": "EmptyChain", + "inputs": [] + }, + { + "type": "error", + "name": "EngineStillHoldsPermissions", + "inputs": [] + }, + { + "type": "error", + "name": "ExecutorMismatch", + "inputs": [ + { + "name": "expected", + "type": "address", + "internalType": "address" + }, + { + "name": "actual", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ForbiddenActionSelector", + "inputs": [ + { + "name": "selector", + "type": "bytes4", + "internalType": "bytes4" + } + ] + }, + { + "type": "error", + "name": "ForbiddenActionTarget", + "inputs": [ + { + "name": "target", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ForbiddenDispatchTarget", + "inputs": [ + { + "name": "target", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "InconsistentChain", + "inputs": [ + { + "name": "actionIndex", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "IntentExecMismatch", + "inputs": [ + { + "name": "actualCalldataHash", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "IntentGrantNonceMismatch", + "inputs": [ + { + "name": "expected", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "provided", + "type": "uint64", + "internalType": "uint64" + } + ] + }, + { + "type": "error", + "name": "IntentSessionMismatch", + "inputs": [ + { + "name": "actual", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "IntentWalletMismatch", + "inputs": [ + { + "name": "expected", + "type": "address", + "internalType": "address" + }, + { + "name": "provided", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "InvalidModuleAddress", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidNonce", + "inputs": [ + { + "name": "nonceKey", + "type": "uint192", + "internalType": "uint192" + }, + { + "name": "expected", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "provided", + "type": "uint64", + "internalType": "uint64" + } + ] + }, + { + "type": "error", + "name": "InvalidOwnerSignature", + "inputs": [] + }, + { + "type": "error", + "name": "LabelTooLong", + "inputs": [ + { + "name": "length", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "MalformedBatchCalldata", + "inputs": [] + }, + { + "type": "error", + "name": "MalformedSessionShape", + "inputs": [] + }, + { + "type": "error", + "name": "ModuleAlreadyInstalled", + "inputs": [ + { + "name": "module", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "OutsideTimeWindow", + "inputs": [ + { + "name": "validAfter", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "validUntil", + "type": "uint48", + "internalType": "uint48" + } + ] + }, + { + "type": "error", + "name": "OwnerLaneRequired", + "inputs": [ + { + "name": "nonceKey", + "type": "uint192", + "internalType": "uint192" + } + ] + }, + { + "type": "error", + "name": "OwnerSigExpired", + "inputs": [ + { + "name": "deadline", + "type": "uint48", + "internalType": "uint48" + } + ] + }, + { + "type": "error", + "name": "ReentrancyGuardReentrantCall", + "inputs": [] + }, + { + "type": "error", + "name": "RulesTypeMismatch", + "inputs": [ + { + "name": "derived", + "type": "uint8", + "internalType": "enum RulesType" + }, + { + "name": "actionIndex", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "target", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "TooManyActions", + "inputs": [ + { + "name": "count", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "UnknownPermission", + "inputs": [ + { + "name": "rulesId", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "UnsupportedExecutionMode", + "inputs": [] + }, + { + "type": "error", + "name": "UnsupportedModuleType", + "inputs": [ + { + "name": "moduleTypeId", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "ValidationFailed", + "inputs": [ + { + "name": "authorizer", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ValidatorNotInstalled", + "inputs": [ + { + "name": "validator", + "type": "address", + "internalType": "address" + } + ] + } +] as const; diff --git a/packages/core/src/lib/agentic/contracts/abi/v5/index.ts b/packages/core/src/lib/agentic/contracts/abi/v5/index.ts new file mode 100644 index 00000000..fa7ddd6a --- /dev/null +++ b/packages/core/src/lib/agentic/contracts/abi/v5/index.ts @@ -0,0 +1,8 @@ +// GENERATED by packages/core/scripts/agw-local/gen-abi.mjs — do not edit. +// Review generation v5: Donut v5 deployment; source 2e61e13. +export const V5_SOURCE_COMMIT = '2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb' as const; +export { AGW_ABI } from './agw'; +export { AGW_FACTORY_ABI } from './agw-factory'; +export { UNIVERSAL_RULES_POLICY_ABI } from './universal-rules-policy'; +export { SMART_SESSION_ABI } from './smart-session'; +export { AGENT_VALIDATOR_ABI } from './agent-validator'; diff --git a/packages/core/src/lib/agentic/contracts/abi/v5/smart-session.ts b/packages/core/src/lib/agentic/contracts/abi/v5/smart-session.ts new file mode 100644 index 00000000..20e207b1 --- /dev/null +++ b/packages/core/src/lib/agentic/contracts/abi/v5/smart-session.ts @@ -0,0 +1,1961 @@ +// GENERATED by packages/core/scripts/agw-local/gen-abi.mjs — do not edit. +// Source: packages/core/scripts/agw-local/abis/engine.json +// push-agentic-wallets@2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb +// sha256(SmartSession.json) = 6e5d9cea4dbed01f06af913c1e093743b86b7432195f4a4bf90fb94b282c51b2 +export const SMART_SESSION_ABI = [ + { + "type": "function", + "name": "areActionsEnabled", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "actions", + "type": "tuple[]", + "internalType": "struct ActionData[]", + "components": [ + { + "name": "actionTargetSelector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "actionTarget", + "type": "address", + "internalType": "address" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "areERC1271PoliciesEnabled", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "areUserOpPoliciesEnabled", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "disableActionId", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "actionId", + "type": "bytes32", + "internalType": "ActionId" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "disableActionPolicies", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "actionId", + "type": "bytes32", + "internalType": "ActionId" + }, + { + "name": "policies", + "type": "address[]", + "internalType": "address[]" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "disableERC1271Policies", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "policies", + "type": "address[]", + "internalType": "address[]" + }, + { + "name": "contexts", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNames", + "type": "string[]", + "internalType": "string[]" + } + ] + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "disableUserOpPolicies", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "policies", + "type": "address[]", + "internalType": "address[]" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "enableActionPolicies", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct ActionData[]", + "components": [ + { + "name": "actionTargetSelector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "actionTarget", + "type": "address", + "internalType": "address" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "enableERC1271Policies", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "erc1271Policies", + "type": "tuple", + "internalType": "struct ERC7739Data", + "components": [ + { + "name": "allowedERC7739Content", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNames", + "type": "string[]", + "internalType": "string[]" + } + ] + }, + { + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "enableSessions", + "inputs": [ + { + "name": "sessions", + "type": "tuple[]", + "internalType": "struct Session[]", + "components": [ + { + "name": "sessionValidator", + "type": "address", + "internalType": "contract ISessionValidator" + }, + { + "name": "sessionValidatorInitData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "erc7739Policies", + "type": "tuple", + "internalType": "struct ERC7739Data", + "components": [ + { + "name": "allowedERC7739Content", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNames", + "type": "string[]", + "internalType": "string[]" + } + ] + }, + { + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "actions", + "type": "tuple[]", + "internalType": "struct ActionData[]", + "components": [ + { + "name": "actionTargetSelector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "actionTarget", + "type": "address", + "internalType": "address" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "permitERC4337Paymaster", + "type": "bool", + "internalType": "bool" + } + ] + } + ], + "outputs": [ + { + "name": "permissionIds", + "type": "bytes32[]", + "internalType": "PermissionId[]" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "enableUserOpPolicies", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "getActionPolicies", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "actionId", + "type": "bytes32", + "internalType": "ActionId" + } + ], + "outputs": [ + { + "name": "", + "type": "address[]", + "internalType": "address[]" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getERC1271Policies", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ], + "outputs": [ + { + "name": "", + "type": "address[]", + "internalType": "address[]" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getEnabledActions", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes32[]", + "internalType": "bytes32[]" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getEnabledERC7739Content", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ], + "outputs": [ + { + "name": "enabledERC7739ContentHashes", + "type": "tuple[]", + "internalType": "struct ERC7739ContextHashes[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNameHashes", + "type": "bytes32[]", + "internalType": "bytes32[]" + } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getNonce", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getPermissionIDs", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "permissionIds", + "type": "bytes32[]", + "internalType": "PermissionId[]" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getPermissionId", + "inputs": [ + { + "name": "session", + "type": "tuple", + "internalType": "struct Session", + "components": [ + { + "name": "sessionValidator", + "type": "address", + "internalType": "contract ISessionValidator" + }, + { + "name": "sessionValidatorInitData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "erc7739Policies", + "type": "tuple", + "internalType": "struct ERC7739Data", + "components": [ + { + "name": "allowedERC7739Content", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNames", + "type": "string[]", + "internalType": "string[]" + } + ] + }, + { + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "actions", + "type": "tuple[]", + "internalType": "struct ActionData[]", + "components": [ + { + "name": "actionTargetSelector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "actionTarget", + "type": "address", + "internalType": "address" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "permitERC4337Paymaster", + "type": "bool", + "internalType": "bool" + } + ] + } + ], + "outputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "getSessionDigest", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "data", + "type": "tuple", + "internalType": "struct Session", + "components": [ + { + "name": "sessionValidator", + "type": "address", + "internalType": "contract ISessionValidator" + }, + { + "name": "sessionValidatorInitData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "erc7739Policies", + "type": "tuple", + "internalType": "struct ERC7739Data", + "components": [ + { + "name": "allowedERC7739Content", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNames", + "type": "string[]", + "internalType": "string[]" + } + ] + }, + { + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "actions", + "type": "tuple[]", + "internalType": "struct ActionData[]", + "components": [ + { + "name": "actionTargetSelector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "actionTarget", + "type": "address", + "internalType": "address" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "permitERC4337Paymaster", + "type": "bool", + "internalType": "bool" + } + ] + }, + { + "name": "mode", + "type": "uint8", + "internalType": "enum SmartSessionMode" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getSessionValidatorAndConfig", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ], + "outputs": [ + { + "name": "sessionValidator", + "type": "address", + "internalType": "address" + }, + { + "name": "sessionValidatorData", + "type": "bytes", + "internalType": "bytes" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getUserOpPolicies", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ], + "outputs": [ + { + "name": "", + "type": "address[]", + "internalType": "address[]" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isActionIdEnabled", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "actionId", + "type": "bytes32", + "internalType": "ActionId" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isActionPolicyEnabled", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "actionId", + "type": "bytes32", + "internalType": "ActionId" + }, + { + "name": "policy", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isERC1271PolicyEnabled", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "policy", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isERC7739ContentEnabled", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "content", + "type": "string", + "internalType": "string" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isISessionValidatorSet", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isInitialized", + "inputs": [ + { + "name": "smartAccount", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isModuleType", + "inputs": [ + { + "name": "typeID", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "isPermissionEnabled", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isUserOpPolicyEnabled", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "policy", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isValidSignatureWithSender", + "inputs": [ + { + "name": "sender", + "type": "address", + "internalType": "address" + }, + { + "name": "hash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "signature", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "result", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "onInstall", + "inputs": [ + { + "name": "data", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "onUninstall", + "inputs": [ + { + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "removeSession", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "revokeEnableSignature", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setPermit4337Paymaster", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "enabled", + "type": "bool", + "internalType": "bool" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "validateUserOp", + "inputs": [ + { + "name": "userOp", + "type": "tuple", + "internalType": "struct PackedUserOperation", + "components": [ + { + "name": "sender", + "type": "address", + "internalType": "address" + }, + { + "name": "nonce", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "initCode", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "callData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "accountGasLimits", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "preVerificationGas", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "gasFees", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "paymasterAndData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "signature", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "userOpHash", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [ + { + "name": "vd", + "type": "uint256", + "internalType": "ValidationData" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "ActionIdDisabled", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" + }, + { + "name": "actionId", + "type": "bytes32", + "indexed": false, + "internalType": "ActionId" + }, + { + "name": "smartAccount", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "NonceIterated", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" + }, + { + "name": "account", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "newValue", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "PermissionIdPermit4337Paymaster", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" + }, + { + "name": "smartAccount", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "enabled", + "type": "bool", + "indexed": false, + "internalType": "bool" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "PolicyDisabled", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" + }, + { + "name": "policyType", + "type": "uint8", + "indexed": false, + "internalType": "enum PolicyType" + }, + { + "name": "policy", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "smartAccount", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "PolicyEnabled", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" + }, + { + "name": "policyType", + "type": "uint8", + "indexed": false, + "internalType": "enum PolicyType" + }, + { + "name": "policy", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "smartAccount", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "SessionCreated", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" + }, + { + "name": "account", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "SessionRemoved", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" + }, + { + "name": "smartAccount", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "SessionValidatorDisabled", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" + }, + { + "name": "sessionValidator", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "smartAccount", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "SessionValidatorEnabled", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "indexed": false, + "internalType": "PermissionId" + }, + { + "name": "sessionValidator", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "smartAccount", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "AssociatedArray_OutOfBounds", + "inputs": [ + { + "name": "index", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "ChainIdMismatch", + "inputs": [ + { + "name": "providedChainId", + "type": "uint64", + "internalType": "uint64" + } + ] + }, + { + "type": "error", + "name": "ChainIdMismatch", + "inputs": [ + { + "name": "providedChainId", + "type": "uint64", + "internalType": "uint64" + } + ] + }, + { + "type": "error", + "name": "ForbiddenValidationData", + "inputs": [] + }, + { + "type": "error", + "name": "HashIndexOutOfBounds", + "inputs": [ + { + "name": "index", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "HashMismatch", + "inputs": [ + { + "name": "providedHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "computedHash", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "HashMismatch", + "inputs": [ + { + "name": "providedHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "computedHash", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "InvalidActionId", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidCallTarget", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidData", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidEnableSignature", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "hash", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "InvalidISessionValidator", + "inputs": [ + { + "name": "sessionValidator", + "type": "address", + "internalType": "contract ISessionValidator" + } + ] + }, + { + "type": "error", + "name": "InvalidMode", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidPermissionId", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ] + }, + { + "type": "error", + "name": "InvalidSelfCall", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidSession", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ] + }, + { + "type": "error", + "name": "InvalidSessionKeySignature", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "sessionValidator", + "type": "address", + "internalType": "address" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "userOpHash", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "InvalidTarget", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidUserOpSender", + "inputs": [ + { + "name": "sender", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "NoExecutionsInBatch", + "inputs": [] + }, + { + "type": "error", + "name": "NoPoliciesSet", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ] + }, + { + "type": "error", + "name": "PartlyEnabledActions", + "inputs": [] + }, + { + "type": "error", + "name": "PartlyEnabledPolicies", + "inputs": [] + }, + { + "type": "error", + "name": "PaymasterValidationNotEnabled", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + } + ] + }, + { + "type": "error", + "name": "PolicyViolation", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "policy", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "SignerNotFound", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "SignerNotFound", + "inputs": [ + { + "name": "permissionId", + "type": "bytes32", + "internalType": "PermissionId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "SmartSessionModuleAlreadyInstalled", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "UnsupportedCallType", + "inputs": [ + { + "name": "callType", + "type": "bytes1", + "internalType": "CallType" + } + ] + }, + { + "type": "error", + "name": "UnsupportedExecutionType", + "inputs": [] + }, + { + "type": "error", + "name": "UnsupportedPolicy", + "inputs": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "UnsupportedSmartSessionMode", + "inputs": [ + { + "name": "mode", + "type": "uint8", + "internalType": "enum SmartSessionMode" + } + ] + } +] as const; diff --git a/packages/core/src/lib/agentic/contracts/abi/v5/universal-rules-policy.ts b/packages/core/src/lib/agentic/contracts/abi/v5/universal-rules-policy.ts new file mode 100644 index 00000000..5b0e2f34 --- /dev/null +++ b/packages/core/src/lib/agentic/contracts/abi/v5/universal-rules-policy.ts @@ -0,0 +1,2156 @@ +// GENERATED by packages/core/scripts/agw-local/gen-abi.mjs — do not edit. +// Source: packages/core/scripts/agw-local/abis/policy.json +// push-agentic-wallets@2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb +// sha256(UniversalRulesPolicy.json) = c7e3cd5c7f8e47be217c77ebebde4c090903cea7db63024838e434eb6f1fd77b +export const UNIVERSAL_RULES_POLICY_ABI = [ + { + "type": "function", + "name": "SEND_OUTBOUND_SELECTOR", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "SESSION_ENGINE", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "UNIVERSAL_EXECUTOR_MODULE", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "UNIVERSAL_GATEWAY_PC", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "assertSpent", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "expectedValueSpent", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "expectedAmountSpent", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "expectedCalls", + "type": "uint32", + "internalType": "uint32" + } + ], + "outputs": [], + "stateMutability": "view" + }, + { + "type": "function", + "name": "assertSpent", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "expectedSpent", + "type": "uint256[]", + "internalType": "uint256[]" + } + ], + "outputs": [], + "stateMutability": "view" + }, + { + "type": "function", + "name": "checkAction", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "target", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "data", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "creditRevert", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "outboundTxId", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "token", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "getConfig", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "tuple", + "internalType": "struct Config", + "components": [ + { + "name": "initialized", + "type": "bool", + "internalType": "bool" + }, + { + "name": "validUntil", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "expectedCEA", + "type": "address", + "internalType": "address" + }, + { + "name": "maxGasPerCall", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "assets", + "type": "tuple[]", + "internalType": "struct AssetCapState[]", + "components": [ + { + "name": "token", + "type": "address", + "internalType": "address" + }, + { + "name": "maxPerCall", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxTotal", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "spent", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "allowedCalls", + "type": "tuple[]", + "internalType": "struct AllowedCall[]", + "components": [ + { + "name": "target", + "type": "address", + "internalType": "address" + }, + { + "name": "selector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "beneficiaryOffset", + "type": "uint16", + "internalType": "uint16" + }, + { + "name": "hasBeneficiary", + "type": "bool", + "internalType": "bool" + }, + { + "name": "maxValue", + "type": "uint256", + "internalType": "uint256" + } + ] + } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getMode", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "tuple", + "internalType": "struct ModeSlot", + "components": [ + { + "name": "initialized", + "type": "bool", + "internalType": "bool" + }, + { + "name": "mode", + "type": "uint8", + "internalType": "enum RulesType" + }, + { + "name": "vm", + "type": "uint8", + "internalType": "enum VmFamily" + }, + { + "name": "chainHash", + "type": "bytes32", + "internalType": "bytes32" + } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getNativeConfig", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "tuple", + "internalType": "struct NativeConfig", + "components": [ + { + "name": "initialized", + "type": "bool", + "internalType": "bool" + }, + { + "name": "validUntil", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "target", + "type": "address", + "internalType": "address" + }, + { + "name": "selector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "maxValuePerCall", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxValueTotal", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "valueSpent", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amount", + "type": "tuple", + "internalType": "struct AmountRule", + "components": [ + { + "name": "enabled", + "type": "bool", + "internalType": "bool" + }, + { + "name": "offset", + "type": "uint16", + "internalType": "uint16" + }, + { + "name": "maxPerCall", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxTotal", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "amountSpent", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxCalls", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "callsUsed", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "pins", + "type": "tuple[]", + "internalType": "struct ArgPin[]", + "components": [ + { + "name": "offset", + "type": "uint16", + "internalType": "uint16" + }, + { + "name": "expected", + "type": "bytes32", + "internalType": "bytes32" + } + ] + } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getSvmConfig", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "tuple", + "internalType": "struct SvmConfig", + "components": [ + { + "name": "initialized", + "type": "bool", + "internalType": "bool" + }, + { + "name": "validUntil", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "expectedCEA", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "gatewayProgram", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "maxGasPerCall", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "assets", + "type": "tuple[]", + "internalType": "struct AssetCapState[]", + "components": [ + { + "name": "token", + "type": "address", + "internalType": "address" + }, + { + "name": "maxPerCall", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxTotal", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "spent", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "ceaAccounts", + "type": "bytes32[]", + "internalType": "bytes32[]" + }, + { + "name": "programs", + "type": "tuple[]", + "internalType": "struct AllowedProgram[]", + "components": [ + { + "name": "program", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "discriminator", + "type": "bytes8", + "internalType": "bytes8" + }, + { + "name": "discriminatorLen", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "dataless", + "type": "bool", + "internalType": "bool" + }, + { + "name": "maxAccounts", + "type": "uint8", + "internalType": "uint8" + } + ] + }, + { + "name": "pins", + "type": "tuple[]", + "internalType": "struct SvmAccountPin[]", + "components": [ + { + "name": "ruleIndex", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "accountIndex", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "expected", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "name": "dataPins", + "type": "tuple[]", + "internalType": "struct SvmDataPin[]", + "components": [ + { + "name": "ruleIndex", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "fromEnd", + "type": "bool", + "internalType": "bool" + }, + { + "name": "offset", + "type": "uint16", + "internalType": "uint16" + }, + { + "name": "offsetB", + "type": "uint16", + "internalType": "uint16" + }, + { + "name": "len", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "mode", + "type": "uint8", + "internalType": "enum SvmDataPinMode" + }, + { + "name": "expected", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "num", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "den", + "type": "uint64", + "internalType": "uint64" + } + ] + } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "initialize", + "inputs": [ + { + "name": "universalGatewayPC", + "type": "address", + "internalType": "address" + }, + { + "name": "universalExecutorModule", + "type": "address", + "internalType": "address" + }, + { + "name": "sessionEngine", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "initializeWithMultiplexer", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "configId", + "type": "bytes32", + "internalType": "ConfigId" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "isCredited", + "inputs": [ + { + "name": "outboundTxId", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "pushChainHash", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "supportsInterface", + "inputs": [ + { + "name": "iid", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "version", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "pure" + }, + { + "type": "event", + "name": "Initialized", + "inputs": [ + { + "name": "version", + "type": "uint64", + "indexed": false, + "internalType": "uint64" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "NativeCallMetered", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "indexed": true, + "internalType": "ConfigId" + }, + { + "name": "multiplexer", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "OutboundMetered", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "indexed": true, + "internalType": "ConfigId" + }, + { + "name": "multiplexer", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "token", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "PolicySet", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "indexed": false, + "internalType": "ConfigId" + }, + { + "name": "multiplexer", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "account", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RevertCredited", + "inputs": [ + { + "name": "outboundTxId", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "id", + "type": "bytes32", + "indexed": true, + "internalType": "ConfigId" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "token", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "amountApplied", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RulesConfigured", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "indexed": true, + "internalType": "ConfigId" + }, + { + "name": "multiplexer", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "mode", + "type": "uint8", + "indexed": false, + "internalType": "enum RulesType" + }, + { + "name": "vm", + "type": "uint8", + "indexed": false, + "internalType": "enum VmFamily" + }, + { + "name": "chainHash", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "AllowListOutOfRange", + "inputs": [ + { + "name": "length", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "AlreadyCredited", + "inputs": [ + { + "name": "outboundTxId", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "AlreadyInitialized", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" + } + ] + }, + { + "type": "error", + "name": "AmbiguousRule", + "inputs": [ + { + "name": "i", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "j", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "AmountExceedsCap", + "inputs": [ + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "cap", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "AmountExceedsU64", + "inputs": [ + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "ArgPinMismatch", + "inputs": [ + { + "name": "actual", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "index", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "expected", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "AssetListOutOfRange", + "inputs": [ + { + "name": "length", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "AssetNotAllowed", + "inputs": [ + { + "name": "token", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "AssetSpentMismatch", + "inputs": [ + { + "name": "token", + "type": "address", + "internalType": "address" + }, + { + "name": "expected", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "actual", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "BatchSizeOutOfRange", + "inputs": [ + { + "name": "count", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "BeneficiaryMismatch", + "inputs": [ + { + "name": "expected", + "type": "address", + "internalType": "address" + }, + { + "name": "actual", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "CallLimitReached", + "inputs": [ + { + "name": "callsUsed", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "maxCalls", + "type": "uint32", + "internalType": "uint32" + } + ] + }, + { + "type": "error", + "name": "CallNotAllowed", + "inputs": [ + { + "name": "target", + "type": "address", + "internalType": "address" + }, + { + "name": "selector", + "type": "bytes4", + "internalType": "bytes4" + } + ] + }, + { + "type": "error", + "name": "CalldataTooShort", + "inputs": [ + { + "name": "length", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "CalldataTooShortForAmount", + "inputs": [ + { + "name": "actualLength", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "needed", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "CalldataTooShortForPin", + "inputs": [ + { + "name": "actualLength", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "index", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "needed", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "CallerIsNotUEModule", + "inputs": [ + { + "name": "caller", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "CeaAccountAtUnpinnedIndex", + "inputs": [ + { + "name": "accountIndex", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "account", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "CeaAccountsMissExpectedCEA", + "inputs": [] + }, + { + "type": "error", + "name": "ChainMismatch", + "inputs": [ + { + "name": "declared", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "assetChain", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "DiscriminatorLenOutOfRange", + "inputs": [ + { + "name": "rule", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "len", + "type": "uint8", + "internalType": "uint8" + } + ] + }, + { + "type": "error", + "name": "DuplicateAsset", + "inputs": [ + { + "name": "token", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "DuplicateSvmPin", + "inputs": [ + { + "name": "first", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "second", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "EmptyChain", + "inputs": [] + }, + { + "type": "error", + "name": "ForbiddenInnerTarget", + "inputs": [ + { + "name": "target", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ForbiddenProgramInAllowList", + "inputs": [ + { + "name": "rule", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "program", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "ForbiddenTargetProgram", + "inputs": [ + { + "name": "program", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "InnerValueExceedsAllowance", + "inputs": [ + { + "name": "index", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxValue", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "InvalidAsset", + "inputs": [ + { + "name": "asset", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "InvalidCeaAccount", + "inputs": [ + { + "name": "index", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "InvalidConfigField", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidExpiry", + "inputs": [ + { + "name": "validUntil", + "type": "uint48", + "internalType": "uint48" + } + ] + }, + { + "type": "error", + "name": "InvalidInitialization", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidRevertRecipient", + "inputs": [ + { + "name": "expected", + "type": "address", + "internalType": "address" + }, + { + "name": "actual", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "InvalidSelector", + "inputs": [ + { + "name": "selector", + "type": "bytes4", + "internalType": "bytes4" + } + ] + }, + { + "type": "error", + "name": "InvalidSvmConfigField", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidTarget", + "inputs": [ + { + "name": "target", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "MalformedInnerCalldata", + "inputs": [] + }, + { + "type": "error", + "name": "MalformedOutboundRequest", + "inputs": [ + { + "name": "length", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "MalformedSvmPayload", + "inputs": [ + { + "name": "code", + "type": "uint8", + "internalType": "uint8" + } + ] + }, + { + "type": "error", + "name": "NativeAmountExceedsCap", + "inputs": [ + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "cap", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "NativeTargetIsGateway", + "inputs": [ + { + "name": "target", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "NativeTargetZero", + "inputs": [] + }, + { + "type": "error", + "name": "NotInitialized", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "NotInitializing", + "inputs": [] + }, + { + "type": "error", + "name": "PCValueExceedsCap", + "inputs": [ + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "cap", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "PayloadNotMulticall", + "inputs": [] + }, + { + "type": "error", + "name": "PolicyNotInitialized", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "ConfigId" + }, + { + "name": "multiplexer", + "type": "address", + "internalType": "address" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ProgramListOutOfRange", + "inputs": [ + { + "name": "length", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "ProgramNotAllowed", + "inputs": [ + { + "name": "program", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "discriminator", + "type": "bytes8", + "internalType": "bytes8" + } + ] + }, + { + "type": "error", + "name": "RecipientMustBeEmpty", + "inputs": [] + }, + { + "type": "error", + "name": "RecipientNotPubkey", + "inputs": [ + { + "name": "length", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "RecipientTargetMismatch", + "inputs": [ + { + "name": "recipient", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "target", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "RuleWithoutPin", + "inputs": [ + { + "name": "rule", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "RulesExpired", + "inputs": [ + { + "name": "validUntil", + "type": "uint48", + "internalType": "uint48" + } + ] + }, + { + "type": "error", + "name": "SelectorMismatch", + "inputs": [ + { + "name": "actual", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "expected", + "type": "bytes4", + "internalType": "bytes4" + } + ] + }, + { + "type": "error", + "name": "SpentLengthMismatch", + "inputs": [ + { + "name": "expected", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "actual", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "SpentMismatch", + "inputs": [ + { + "name": "expected", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "actual", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "SvmAccountCountBelowPin", + "inputs": [ + { + "name": "pin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "count", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "needed", + "type": "uint8", + "internalType": "uint8" + } + ] + }, + { + "type": "error", + "name": "SvmAccountCountMismatch", + "inputs": [ + { + "name": "count", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "expected", + "type": "uint8", + "internalType": "uint8" + } + ] + }, + { + "type": "error", + "name": "SvmAccountPinMismatch", + "inputs": [ + { + "name": "pin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "accountIndex", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "expected", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "actual", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "SvmAccountsOutOfRange", + "inputs": [ + { + "name": "count", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "SvmDataCeilingExceeded", + "inputs": [ + { + "name": "pin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "actual", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "ceiling", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "SvmDataFloorNotMet", + "inputs": [ + { + "name": "pin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "actual", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "floor", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "SvmDataPinInvalid", + "inputs": [ + { + "name": "pin", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "SvmDataPinMismatch", + "inputs": [ + { + "name": "pin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "expected", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "actual", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "SvmDataRatioNotMet", + "inputs": [ + { + "name": "pin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "a", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "b", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "num", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "den", + "type": "uint64", + "internalType": "uint64" + } + ] + }, + { + "type": "error", + "name": "SvmDataTooShortForPin", + "inputs": [ + { + "name": "pin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "ixLen", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "SvmInstructionNotExecute", + "inputs": [ + { + "name": "instructionId", + "type": "uint8", + "internalType": "uint8" + } + ] + }, + { + "type": "error", + "name": "SvmIxDataTooLong", + "inputs": [ + { + "name": "length", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "SvmMaxAccountsOutOfRange", + "inputs": [ + { + "name": "rule", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxAccounts", + "type": "uint8", + "internalType": "uint8" + } + ] + }, + { + "type": "error", + "name": "SvmPayloadEmpty", + "inputs": [] + }, + { + "type": "error", + "name": "SvmPinIndexOutOfRange", + "inputs": [ + { + "name": "pin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "accountIndex", + "type": "uint8", + "internalType": "uint8" + } + ] + }, + { + "type": "error", + "name": "SvmPinRuleOutOfRange", + "inputs": [ + { + "name": "pin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "rule", + "type": "uint8", + "internalType": "uint8" + } + ] + }, + { + "type": "error", + "name": "TargetMismatch", + "inputs": [ + { + "name": "actual", + "type": "address", + "internalType": "address" + }, + { + "name": "expected", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "TooManyCeaAccounts", + "inputs": [ + { + "name": "count", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "TooManyPins", + "inputs": [ + { + "name": "count", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "TooManySvmDataPins", + "inputs": [ + { + "name": "count", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "TooManySvmPins", + "inputs": [ + { + "name": "count", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "TotalNativeAmountExceeded", + "inputs": [ + { + "name": "newSpent", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "cap", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "TotalSpendCapExceeded", + "inputs": [ + { + "name": "wouldBeTotal", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "cap", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "TotalValueExceeded", + "inputs": [ + { + "name": "newSpent", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "cap", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "UncappedGasSwapRejected", + "inputs": [] + }, + { + "type": "error", + "name": "UnsupportedEnvelopeVersion", + "inputs": [ + { + "name": "version", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "UnsupportedNamespace", + "inputs": [ + { + "name": "chainHash", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "ValueExceedsCap", + "inputs": [ + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "cap", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "ValueOnlyCalldataNotEmpty", + "inputs": [ + { + "name": "length", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "ValueOnlyWithAmountRule", + "inputs": [] + }, + { + "type": "error", + "name": "ValueOnlyWithPins", + "inputs": [] + }, + { + "type": "error", + "name": "WrongModeForCall", + "inputs": [ + { + "name": "actual", + "type": "uint8", + "internalType": "enum RulesType" + } + ] + }, + { + "type": "error", + "name": "WrongVmForCall", + "inputs": [ + { + "name": "actual", + "type": "uint8", + "internalType": "enum VmFamily" + } + ] + }, + { + "type": "error", + "name": "ZeroAddress", + "inputs": [] + } +] as const; diff --git a/packages/core/src/lib/agentic/contracts/donut-v5.ts b/packages/core/src/lib/agentic/contracts/donut-v5.ts new file mode 100644 index 00000000..c75425ea --- /dev/null +++ b/packages/core/src/lib/agentic/contracts/donut-v5.ts @@ -0,0 +1,13 @@ +import type { Address } from 'viem'; + +/** Source 2e61e13; code/proxy wiring checked at Donut block 23991912. */ +export const V5_SOURCE_COMMIT = '2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb'; +export const DONUT_V5_START_BLOCK = BigInt(23989983); +export const DONUT_V5_ADDRESSES = { + factory: '0x8137F96A50EBF41d904e3678c84c391a0D1BCcc5', + walletImplementation: '0x4D459Da499C14548aa16c46c57fD92880A88EBb4', + sessionEngine: '0x165A5E6782f39D30B38c7D97e1303e4CB2aD102a', + rulesPolicy: '0x603E7f0aF6e1aAFf46DDfb28b1e99364f8BC59af', + sessionValidator: '0x068EE2388475A98EE1f5a434C58bFF3444fffFe6', + gateway: '0x00000000000000000000000000000000000000C1', +} as const satisfies Record; diff --git a/packages/core/src/lib/agentic/contracts/prc20-metadata.ts b/packages/core/src/lib/agentic/contracts/prc20-metadata.ts new file mode 100644 index 00000000..332bb0b6 --- /dev/null +++ b/packages/core/src/lib/agentic/contracts/prc20-metadata.ts @@ -0,0 +1,128 @@ +import { + getAddress, + isAddress, + parseAbi, + zeroAddress, + type Address, + type Hex, +} from 'viem'; +import { UNIVERSAL_CORE_EVM } from '../../constants/abi/prc20.evm'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; +import type { Snapshot } from '../reads/snapshot'; +import { CHAIN, PUSH_NETWORK } from '../../constants/enums'; +import { MOVEABLE_TOKENS } from '../../constants/tokens'; +import { getPRC20Address } from '../../universal/prc20-address'; +import { svmKey } from '../codec/svm-accounts'; + +export const PRC20_SOURCE_ABI = parseAbi([ + 'function SOURCE_CHAIN_NAMESPACE() view returns (string)', + 'function SOURCE_TOKEN_ADDRESS() view returns (string)', +]); +const NATIVE_SOURCE_ABI = parseAbi([ + 'function SOURCE_TOKEN_ADDRESS() view returns (address)', +]); +const SVM_SOURCE_WORD_ABI = parseAbi([ + 'function SOURCE_TOKEN_ADDRESS() view returns (bytes32)', +]); + +/** Resolve the SVM source mint from metadata or the current chain-specific token registry. */ +export async function readSvmSourceToken( + snap: Snapshot, + token: Address, + chain: string, + network: PUSH_NETWORK = PUSH_NETWORK.TESTNET_DONUT +): Promise { + let source: string; + try { + source = await snap.read( + token, + PRC20_SOURCE_ABI, + 'SOURCE_TOKEN_ADDRESS' + ); + } catch (cause) { + try { + source = await snap.read( + token, + SVM_SOURCE_WORD_ABI, + 'SOURCE_TOKEN_ADDRESS' + ); + } catch { + throw cause; + } + } + const zeroKey = `0x${'00'.repeat(32)}` as Hex; + if ( + source === '' || + source.toLowerCase() === zeroAddress || + source.toLowerCase() === zeroKey + ) { + if (getAddress(token) === (await readGasPrc20(snap, chain))) return zeroKey; + // Current Donut SVM synthetic metadata exposes a zero word for SPL assets. + // Ordinary Route 2 already resolves these through the same token registry. + // Match both full origin chain and exact PRC20; never infer an unknown mint. + for (const asset of MOVEABLE_TOKENS[chain as CHAIN] ?? []) { + if (asset.mechanism === 'native') continue; + try { + const resolved = getPRC20Address( + { chain, address: asset.address }, + { network } + ); + if (getAddress(resolved.address) === getAddress(token)) + return svmKey(asset.address); + } catch { + // A token without a deployment in this network is not a candidate. + } + } + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + `source mint unavailable for PRC20 ${token} on ${chain}; no registered mapping matches` + ); + } + return svmKey(source); +} +export const CORE_ADDRESS = + '0x00000000000000000000000000000000000000C0' as Address; +export async function readGasPrc20( + snap: Snapshot, + chain: string +): Promise
{ + return getAddress( + await snap.read
( + CORE_ADDRESS, + UNIVERSAL_CORE_EVM, + 'gasTokenPRC20ByChainNamespace', + [chain] + ) + ); +} +/** Donut native precompile returns a zero word; ERC20 metadata is a dynamic string. */ +export async function readOriginToken( + snap: Snapshot, + token: Address, + chain: string +): Promise
{ + let source: string; + try { + source = await snap.read( + token, + PRC20_SOURCE_ABI, + 'SOURCE_TOKEN_ADDRESS' + ); + } catch (cause) { + if ((await readGasPrc20(snap, chain)) !== getAddress(token)) throw cause; + const native = await snap.read
( + token, + NATIVE_SOURCE_ABI, + 'SOURCE_TOKEN_ADDRESS' + ); + if (getAddress(native) === zeroAddress) return zeroAddress; + throw cause; + } + if (isAddress(source, { strict: false })) return getAddress(source); + if (source === '' && (await readGasPrc20(snap, chain)) === getAddress(token)) + return zeroAddress; + throw new AgenticError( + AGENTIC_ERROR_CODE.RULE_READ_FAILED, + `PRC20 ${token} has an invalid source token address` + ); +} diff --git a/packages/core/src/lib/agentic/contracts/reader.ts b/packages/core/src/lib/agentic/contracts/reader.ts new file mode 100644 index 00000000..7b978068 --- /dev/null +++ b/packages/core/src/lib/agentic/contracts/reader.ts @@ -0,0 +1,42 @@ +import type { Abi, AbiEvent, Address, Hex, Log, PublicClient, TransactionReceipt } from 'viem'; + +/** + * The narrow chain-read surface the AGW module needs. Tests mock it; the SDK + * adapts the Push client's viem PublicClient. Every snapshot read passes an + * explicit `blockNumber` so dependent reads observe one state. + */ +export interface ChainReader { + readContract(args: { + address: Address; + abi: Abi | readonly unknown[]; + functionName: string; + args?: readonly unknown[]; + blockNumber?: bigint; + }): Promise; + getBlockNumber(): Promise; + getCode(args: { address: Address; blockNumber?: bigint }): Promise; + getBalance(args: { address: Address; blockNumber?: bigint }): Promise; + getLogs(args: { + address: Address; + event: AbiEvent; + args?: Record; + fromBlock: bigint; + toBlock: bigint; + }): Promise; + getTransactionReceipt(args: { hash: Hex }): Promise; +} + +export function chainReaderFromPublicClient(client: PublicClient): ChainReader { + // viem's generics are narrower than this module's needs; the casts are + // confined to this adapter. + return { + readContract: (args) => + client.readContract(args as Parameters[0]), + getBlockNumber: () => client.getBlockNumber({ cacheTime: 0 }), + getCode: (args) => client.getCode(args), + getBalance: (args) => client.getBalance(args), + getLogs: (args) => + client.getLogs(args as Parameters[0]) as Promise, + getTransactionReceipt: (args) => client.getTransactionReceipt(args), + }; +} diff --git a/packages/core/src/lib/agentic/contracts/v5.ts b/packages/core/src/lib/agentic/contracts/v5.ts new file mode 100644 index 00000000..444dc5de --- /dev/null +++ b/packages/core/src/lib/agentic/contracts/v5.ts @@ -0,0 +1,422 @@ +import { + decodeAbiParameters, + decodeEventLog, + decodeFunctionData, + encodeAbiParameters, + encodeFunctionData, + encodePacked, + getAbiItem, + getAddress, + toEventSelector, + type AbiEvent, + type Address, + type Hex, + type Log, +} from 'viem'; +import { + AGW_ABI, + AGW_FACTORY_ABI, + SMART_SESSION_ABI, + UNIVERSAL_RULES_POLICY_ABI, +} from './abi/v5'; +import type { SessionWire } from '../codec/session'; +import type { CheckpointKind } from '../agentic.types'; +import type { NativeTermsWire } from '../codec/native'; +import type { UniversalTermsWire } from '../codec/universal-terms'; +import type { SvmTermsWire } from '../codec/svm-terms'; + +/** + * Contract adapter for the reviewed v5 ABI generation. All version- + * sensitive encoding, decoding and view names live here; callers never touch + * a raw ABI. A future generation gets its own adapter implementing the same + * interface. + */ + +export interface Call { + target: Address; + value: bigint; + data: Hex; +} + +export const MODE_SINGLE = `0x${'00'.repeat(32)}` as Hex; +export const MODE_BATCH = `0x01${'00'.repeat(31)}` as Hex; +export const SEND_OUTBOUND_SELECTOR = '0x77b86bec' as const; +export const UEA_MULTICALL_PREFIX = '0x2cc2842d' as const; + +const CHECKPOINT_KINDS: readonly CheckpointKind[] = [ + 'OWNER_ACTION', + 'RULES_GRANTED', + 'RULES_REVOKED', +]; + +export interface NativeConfigRead extends NativeTermsWire { + initialized: boolean; + valueSpent: bigint; + amountSpent: bigint; + callsUsed: number; +} + +export interface ModeRead { + initialized: boolean; + /** 0 = UNIVERSAL, 1 = NATIVE (RulesType). */ + mode: number; + /** 0 = EVM, 1 = SVM (VmFamily). */ + vm: number; + chainHash: Hex; +} + +export interface UniversalConfigRead + extends Omit { + initialized: boolean; + assets: readonly { + token: Address; + maxPerCall: bigint; + maxTotal: bigint; + spent: bigint; + }[]; +} + +export interface SvmConfigRead extends Omit { + initialized: boolean; + assets: readonly { + token: Address; + maxPerCall: bigint; + maxTotal: bigint; + spent: bigint; + }[]; +} + +export type DecodedWalletCall = + | { kind: 'execute'; mode: Hex; calls: Call[] } + | { kind: 'executeAsAgent'; rulesId: Hex; mode: Hex; calls: Call[] } + | { kind: 'grantRules'; session: SessionWire } + | { kind: 'revokeRules'; rulesId: Hex } + | { kind: 'revokeAllRules' }; + +const EXECUTION_TUPLE = [ + { + type: 'tuple[]', + components: [ + { name: 'target', type: 'address' }, + { name: 'value', type: 'uint256' }, + { name: 'callData', type: 'bytes' }, + ], + }, +] as const; + +export const v5 = { + id: 'v5', + abis: { + wallet: AGW_ABI, + factory: AGW_FACTORY_ABI, + engine: SMART_SESSION_ABI, + policy: UNIVERSAL_RULES_POLICY_ABI, + }, + events: { + walletDeployed: getAbiItem({ + abi: AGW_FACTORY_ABI, + name: 'WalletDeployed', + }) as AbiEvent, + checkpointed: getAbiItem({ + abi: AGW_ABI, + name: 'Checkpointed', + }) as AbiEvent, + rulesGranted: getAbiItem({ + abi: AGW_ABI, + name: 'RulesGranted', + }) as AbiEvent, + rulesRevoked: getAbiItem({ + abi: AGW_ABI, + name: 'RulesRevoked', + }) as AbiEvent, + }, + + // ---------------------------------------------------------------- encoders + encodeDeployWallet(label: string): Hex { + return encodeFunctionData({ + abi: AGW_FACTORY_ABI, + functionName: 'deployWallet', + args: [label], + }); + }, + /** + * Index-bound deployment for an owner calling the factory itself. + * deployWalletWithSig skips signature checks when msg.sender == intent.owner + * but still reverts IndexMismatch / IntentWalletMismatch unless the owner's + * next slot is exactly `index` and predicts to `wallet`. A concurrent + * creation therefore makes this call revert instead of deploying another + * slot while later calls in the batch target the predicted address. + */ + encodeDeployWalletAt( + owner: Address, + index: bigint, + wallet: Address, + label: string + ): Hex { + const zero32 = `0x${'00'.repeat(32)}` as Hex; + const zeroAddress = '0x0000000000000000000000000000000000000000' as Address; + return encodeFunctionData({ + abi: AGW_FACTORY_ABI, + functionName: 'deployWalletWithSig', + args: [ + { + owner, + wallet, + executor: zeroAddress, + index, + sessionHash: zero32, + mode: zero32, + execCalldataHash: zero32, + nonceKey: BigInt(0), + nonceSeq: BigInt(0), + grantNonce: BigInt(0), + deadline: 0, + signerChainId: BigInt(0), + }, + '0x', + label, + ], + }); + }, + encodeGrantRules(session: SessionWire): Hex { + return encodeFunctionData({ + abi: AGW_ABI, + functionName: 'grantRules', + args: [session as never], + }); + }, + encodeRevokeRules(rulesId: Hex): Hex { + return encodeFunctionData({ + abi: AGW_ABI, + functionName: 'revokeRules', + args: [rulesId], + }); + }, + encodeRevokeAllRules(): Hex { + return encodeFunctionData({ + abi: AGW_ABI, + functionName: 'revokeAllRules', + args: [], + }); + }, + encodeSetLabel(label: string): Hex { + return encodeFunctionData({ + abi: AGW_ABI, + functionName: 'setLabel', + args: [label], + }); + }, + /** ERC-7579 single execution calldata: abi.encodePacked(target, value, callData). */ + packSingle(call: Call): Hex { + return encodePacked( + ['address', 'uint256', 'bytes'], + [call.target, call.value, call.data] + ); + }, + encodeExecute(calls: Call[]): Hex { + if (calls.length === 0) throw new Error('execute needs at least one call'); + if (calls.length === 1) { + return encodeFunctionData({ + abi: AGW_ABI, + functionName: 'execute', + args: [MODE_SINGLE, v5.packSingle(calls[0])], + }); + } + const batch = encodeAbiParameters(EXECUTION_TUPLE, [ + calls.map((c) => ({ + target: c.target, + value: c.value, + callData: c.data, + })), + ]); + return encodeFunctionData({ + abi: AGW_ABI, + functionName: 'execute', + args: [MODE_BATCH, batch], + }); + }, + encodeExecuteAsAgent(rulesId: Hex, call: Call): Hex { + return encodeFunctionData({ + abi: AGW_ABI, + functionName: 'executeAsAgent', + args: [rulesId, MODE_SINGLE, v5.packSingle(call)], + }); + }, + encodeAssertSpentNative( + configId: Hex, + wallet: Address, + expected: { valueSpent: bigint; amountSpent: bigint; callsUsed: number } + ): Hex { + return encodeFunctionData({ + abi: UNIVERSAL_RULES_POLICY_ABI, + functionName: 'assertSpent', + args: [ + configId, + wallet, + expected.valueSpent, + expected.amountSpent, + expected.callsUsed, + ], + }); + }, + encodeAssertSpentUniversal( + configId: Hex, + wallet: Address, + expectedSpent: readonly bigint[] + ): Hex { + return encodeFunctionData({ + abi: UNIVERSAL_RULES_POLICY_ABI, + functionName: 'assertSpent', + args: [configId, wallet, expectedSpent], + }); + }, + + // ---------------------------------------------------------------- decoders + decodeWalletCall(data: Hex): DecodedWalletCall | null { + let decoded; + try { + decoded = decodeFunctionData({ abi: AGW_ABI, data }); + } catch { + return null; + } + switch (decoded.functionName) { + case 'execute': { + const [mode, ecd] = decoded.args as readonly [Hex, Hex]; + return { kind: 'execute', mode, calls: unpackExecution(mode, ecd) }; + } + case 'executeAsAgent': { + const [rulesId, mode, ecd] = decoded.args as readonly [Hex, Hex, Hex]; + return { + kind: 'executeAsAgent', + rulesId, + mode, + calls: unpackExecution(mode, ecd), + }; + } + case 'grantRules': + return { + kind: 'grantRules', + session: decoded.args[0] as unknown as SessionWire, + }; + case 'revokeRules': + return { kind: 'revokeRules', rulesId: decoded.args[0] as Hex }; + case 'revokeAllRules': + return { kind: 'revokeAllRules' }; + default: + return null; + } + }, + decodeCheckpointKind(kind: number): CheckpointKind { + const k = CHECKPOINT_KINDS[kind]; + if (!k) throw new Error(`unknown checkpoint kind ${kind}`); + return k; + }, + parseWalletDeployed(logs: readonly Log[], factory: Address) { + return decodeMatching(logs, factory, v5.events.walletDeployed).map( + (args) => ({ + owner: getAddress(args['owner'] as Address), + index: BigInt(args['index'] as bigint), + wallet: getAddress(args['wallet'] as Address), + label: args['label'] as string, + }) + ); + }, + parseRulesGranted(logs: readonly Log[], wallet: Address) { + return decodeMatching(logs, wallet, v5.events.rulesGranted).map((args) => ({ + rulesId: args['rulesId'] as Hex, + mode: Number(args['mode']), + chainNamespace: args['chainNamespace'] as string, + })); + }, + parseRulesRevoked(logs: readonly Log[], wallet: Address) { + return decodeMatching(logs, wallet, v5.events.rulesRevoked).map((args) => ({ + rulesId: args['rulesId'] as Hex, + })); + }, + parseCheckpointed(logs: readonly Log[], wallet: Address) { + return logs + .filter( + (l) => + sameAddress(l.address, wallet) && + l.topics[0]?.toLowerCase() === + toEventSelector(v5.events.checkpointed).toLowerCase() + ) + .flatMap((log) => { + try { + const ev = decodeEventLog({ + abi: [v5.events.checkpointed], + ...log, + strict: true, + }); + return [{ log, args: ev.args as unknown as Record }]; + } catch { + return []; + } + }) + .map(({ log, args }) => ({ + seq: Number(args['seq']), + kind: v5.decodeCheckpointKind(Number(args['kind'])), + ref: args['ref'] as Hex, + blockNumber: BigInt(log.blockNumber ?? BigInt(0)), + txHash: log.transactionHash as Hex, + logIndex: Number(log.logIndex ?? 0), + transactionIndex: Number(log.transactionIndex ?? 0), + })); + }, +}; + +function unpackExecution(mode: Hex, ecd: Hex): Call[] { + const callType = mode.slice(2, 4); + if (callType === '00') { + const bytes = ecd.slice(2); + return [ + { + target: getAddress(`0x${bytes.slice(0, 40)}`), + value: BigInt(`0x${bytes.slice(40, 104) || '0'}`), + data: `0x${bytes.slice(104)}` as Hex, + }, + ]; + } + if (callType === '01') { + const [execs] = decodeAbiParameters(EXECUTION_TUPLE, ecd); + return execs.map((e) => ({ + target: getAddress(e.target), + value: e.value, + data: e.callData as Hex, + })); + } + return []; +} + +function sameAddress(a: string | null | undefined, b: string): boolean { + return !!a && a.toLowerCase() === b.toLowerCase(); +} + +function decodeMatching( + logs: readonly Log[], + emitter: Address, + event: AbiEvent +): Record[] { + // viem's decodeEventLog skips the topic0 check when given a one-event ABI, + // so the event signature is matched explicitly here. + const topic0 = toEventSelector(event).toLowerCase(); + const out: Record[] = []; + for (const log of logs) { + if (!sameAddress(log.address, emitter)) continue; + if (log.topics[0]?.toLowerCase() !== topic0) continue; + try { + const ev = decodeEventLog({ + abi: [event], + data: log.data, + topics: log.topics, + strict: true, + }); + out.push(ev.args as unknown as Record); + } catch { + // not this event + } + } + return out; +} + +export type AgwContracts = typeof v5; diff --git a/packages/core/src/lib/agentic/deployments.ts b/packages/core/src/lib/agentic/deployments.ts new file mode 100644 index 00000000..421a0a02 --- /dev/null +++ b/packages/core/src/lib/agentic/deployments.ts @@ -0,0 +1,299 @@ +import { getAddress, type Address } from 'viem'; +import { PUSH_NETWORK } from '../constants/enums'; +import { AgenticCapability } from './capabilities'; +import { v5, type AgwContracts } from './contracts/v5'; +import type { ChainReader } from './contracts/reader'; +import { AGENTIC_ERROR_CODE, AgenticError } from './errors'; +import { + DONUT_V5_ADDRESSES, + DONUT_V5_START_BLOCK, + V5_SOURCE_COMMIT, +} from './contracts/donut-v5'; + +/** + * A verified AGW contract generation on one Push network. The registry is the + * ONLY source of AGW addresses in the SDK: no address is hard-coded anywhere + * else, and historical Donut deployments (generation 67929f2, grantMandate) + * are NOT registered because they do not implement this ABI. + */ +export interface AgenticGeneration { + /** Stable identifier, e.g. 'v5'. */ + id: string; + /** Contract source commit the ABI was generated from. */ + sourceCommit: string; + network: PUSH_NETWORK; + /** false = review fixture (local harness); never advertised as a release deployment. */ + advertised: boolean; + addresses: { + factory: Address; + walletImplementation: Address; + sessionEngine: Address; + rulesPolicy: Address; + sessionValidator: Address; + gateway: Address; + }; + /** First block to scan for factory/wallet events. */ + startBlock: bigint; + /** Expected wallet accountId(). */ + accountId: string; + capabilities: ReadonlySet; + contracts: AgwContracts; +} + +/** Capabilities the v5 ABI actually implements. Target-only features are absent. */ +export const V5_CAPABILITIES: ReadonlySet = new Set([ + AgenticCapability.WALLET_READS, + AgenticCapability.ACTIVE_RULE_READS, + AgenticCapability.OWNER_EXECUTE, + AgenticCapability.AGENT_EXECUTE, + AgenticCapability.NATIVE_RULES, + AgenticCapability.ASSERT_SPENT_NATIVE, + AgenticCapability.CHECKPOINTS, + AgenticCapability.UNIVERSAL_EVM_OUTBOUND, + AgenticCapability.UNIVERSAL_EVM_RULES, + AgenticCapability.UNIVERSAL_SVM_RULES, + AgenticCapability.ASSERT_SPENT_UNIVERSAL_MULTI, + AgenticCapability.SET_LABEL, +]); + +/** + * V5 only. Unsupported networks fail before signing; no legacy adapter fallback. + */ +const VERIFIED_DEPLOYMENTS: readonly AgenticGeneration[] = [ + { + id: 'v5', + sourceCommit: V5_SOURCE_COMMIT, + network: PUSH_NETWORK.TESTNET_DONUT, + advertised: true, + addresses: DONUT_V5_ADDRESSES, + startBlock: DONUT_V5_START_BLOCK, + accountId: 'push.agw.1.0.0', + capabilities: V5_CAPABILITIES, + contracts: v5, + }, +]; + +const registry: AgenticGeneration[] = [...VERIFIED_DEPLOYMENTS]; + +/** + * @internal Register a generation that is NOT a verified release deployment — + * the local contract harness and E2E manifest loader use this. Not exported + * from the package entry point. + */ +export function registerAgenticGeneration( + input: Omit & { + capabilities?: ReadonlySet; + } +): AgenticGeneration { + if (input.id !== v5.id || input.sourceCommit !== V5_SOURCE_COMMIT) { + throw new AgenticError( + AGENTIC_ERROR_CODE.GENERATION_UNSUPPORTED, + `no contract adapter for generation "${input.id}"` + ); + } + const gen: AgenticGeneration = { + ...input, + addresses: { + factory: getAddress(input.addresses.factory), + walletImplementation: getAddress(input.addresses.walletImplementation), + sessionEngine: getAddress(input.addresses.sessionEngine), + rulesPolicy: getAddress(input.addresses.rulesPolicy), + sessionValidator: getAddress(input.addresses.sessionValidator), + gateway: getAddress(input.addresses.gateway), + }, + capabilities: input.capabilities ?? V5_CAPABILITIES, + contracts: v5, + }; + const existing = registry.findIndex( + (g) => + g.network === gen.network && g.addresses.factory === gen.addresses.factory + ); + if (existing >= 0) registry.splice(existing, 1); + registry.push(gen); + verifiedWiring.clear(); + return gen; +} + +/** @internal Test/harness cleanup. Restores the checked Donut v5 registry. */ +export function resetAgenticGenerations(): void { + registry.splice(0, registry.length, ...VERIFIED_DEPLOYMENTS); + verifiedWiring.clear(); +} + +/** Grant compatibility check; the unrestricted owner door does not consult URP. */ +export async function verifyPolicyVersion( + reader: ChainReader, + gen: AgenticGeneration +): Promise { + const version = await reader.readContract({ + address: gen.addresses.rulesPolicy, + abi: gen.contracts.abis.policy, + functionName: 'version', + }); + if (version !== '3.1.0') + throw new AgenticError( + AGENTIC_ERROR_CODE.GENERATION_UNSUPPORTED, + `URP version ${String(version)} is not supported by the v5 adapter` + ); +} + +export function generationsFor( + network: PUSH_NETWORK +): readonly AgenticGeneration[] { + return registry.filter((g) => g.network === network); +} + +/** The generation new wallets are created on for this network. */ +export function currentGeneration(network: PUSH_NETWORK): AgenticGeneration { + const gens = generationsFor(network); + const gen = gens[gens.length - 1]; + if (!gen) { + throw new AgenticError( + AGENTIC_ERROR_CODE.GENERATION_UNSUPPORTED, + `no verified AGW deployment is registered for ${network}`, + { + hint: 'AGW v5 is configured on Donut only; this Push network has no registered v5 deployment.', + details: { network, assumption: 'A07' }, + } + ); + } + return gen; +} + +/** Generation infrastructure a native rule may not target (the wallet itself is added per call). */ +export function forbiddenTargets( + gen: AgenticGeneration, + wallet?: Address +): Address[] { + const a = gen.addresses; + return [ + a.factory, + a.sessionEngine, + a.rulesPolicy, + a.sessionValidator, + a.gateway, + ...(wallet ? [wallet] : []), + ]; +} + +const verifiedWiring = new Map>(); + +/** Confirms the factory still points at the registered implementation (cached per generation). */ +export function verifyFactoryWiring( + reader: ChainReader, + gen: AgenticGeneration +): Promise { + const key = `${gen.network}:${gen.addresses.factory}:${gen.addresses.walletImplementation}`; + let p = verifiedWiring.get(key); + if (!p) { + p = (async () => { + const impl = (await reader.readContract({ + address: gen.addresses.factory, + abi: gen.contracts.abis.factory, + functionName: 'walletImplementation', + })) as Address; + if (getAddress(impl) !== gen.addresses.walletImplementation) { + throw new AgenticError( + AGENTIC_ERROR_CODE.GENERATION_UNSUPPORTED, + `factory ${gen.addresses.factory} points at implementation ${impl}, not the registered ${gen.addresses.walletImplementation}` + ); + } + })(); + p.catch(() => verifiedWiring.delete(key)); + verifiedWiring.set(key, p); + } + return p; +} + +/** + * Resolve and verify the generation of a deployed wallet: + * code present → factory() is a registered factory → factory.isWallet(wallet) + * → immutable wiring and accountId match the registered generation. + */ +export async function resolveWalletGeneration( + reader: ChainReader, + network: PUSH_NETWORK, + wallet: Address +): Promise { + const gens = generationsFor(network); + if (gens.length === 0) currentGeneration(network); // throws GENERATION_UNSUPPORTED (A07) + + const code = await reader.getCode({ address: wallet }); + if (!code || code === '0x') { + throw new AgenticError( + AGENTIC_ERROR_CODE.WALLET_NOT_DEPLOYED, + `no contract is deployed at ${wallet}`, + { + hint: 'Deploy it with client.agentic.create, or check the address and network.', + } + ); + } + let factory: Address; + try { + factory = getAddress( + (await reader.readContract({ + address: wallet, + abi: v5.abis.wallet, + functionName: 'factory', + })) as Address + ); + } catch (cause) { + throw new AgenticError( + AGENTIC_ERROR_CODE.NOT_AGENTIC_WALLET, + `${wallet} does not expose an AGW factory()`, + { cause } + ); + } + const gen = gens.find((g) => g.addresses.factory === factory); + if (!gen) { + throw new AgenticError( + AGENTIC_ERROR_CODE.GENERATION_UNSUPPORTED, + `${wallet} was created by factory ${factory}, which is not a verified AGW generation on ${network}`, + { details: { factory, assumption: 'A07' } } + ); + } + const isWallet = (await reader.readContract({ + address: gen.addresses.factory, + abi: gen.contracts.abis.factory, + functionName: 'isWallet', + args: [wallet], + })) as boolean; + if (!isWallet) { + throw new AgenticError( + AGENTIC_ERROR_CODE.NOT_AGENTIC_WALLET, + `${wallet} is not a wallet of factory ${factory}` + ); + } + const [engine, policy, validator, gateway, accountId] = await Promise.all( + ( + [ + 'SESSION_ENGINE', + 'RULES_POLICY', + 'SESSION_VALIDATOR', + 'UNIVERSAL_GATEWAY_PC', + 'accountId', + ] as const + ).map((functionName) => + reader.readContract({ + address: wallet, + abi: gen.contracts.abis.wallet, + functionName, + }) + ) + ); + const mismatch = + getAddress(engine as Address) !== gen.addresses.sessionEngine || + getAddress(policy as Address) !== gen.addresses.rulesPolicy || + getAddress(validator as Address) !== gen.addresses.sessionValidator || + getAddress(gateway as Address) !== gen.addresses.gateway || + accountId !== gen.accountId; + if (mismatch) { + throw new AgenticError( + AGENTIC_ERROR_CODE.GENERATION_UNSUPPORTED, + `${wallet} wiring does not match registered generation ${gen.id}`, + { details: { engine, policy, validator, gateway, accountId } } + ); + } + await verifyFactoryWiring(reader, gen); + return gen; +} diff --git a/packages/core/src/lib/agentic/errors.ts b/packages/core/src/lib/agentic/errors.ts new file mode 100644 index 00000000..d66055dc --- /dev/null +++ b/packages/core/src/lib/agentic/errors.ts @@ -0,0 +1,124 @@ +import { + PushChainExecutionError, + type DecodedErrorPayload, +} from '../orchestrator/internals/errors'; + +/** + * Stable AGW error codes. The first groups are specified by the AGW SDK page + * (section 3.f); the remainder are SDK-owned codes that keep unsupported or + * unverified capabilities from being mistaken for success. + */ +export const AGENTIC_ERROR_CODE = { + // create / rule validation (spec 3.f) + AGENT_IS_OWNER: 'AGENT_IS_OWNER', + AMBIGUOUS_RULE: 'AMBIGUOUS_RULE', + TARGET_NOT_ON_RULE_CHAIN: 'TARGET_NOT_ON_RULE_CHAIN', + ASSET_CHAIN_MISMATCH: 'ASSET_CHAIN_MISMATCH', + // initialize with agenticWallet (spec 3.f) + NOT_OWNER_OR_AGENT: 'NOT_OWNER_OR_AGENT', + WALLET_NOT_DEPLOYED: 'WALLET_NOT_DEPLOYED', + NOT_AGENTIC_WALLET: 'NOT_AGENTIC_WALLET', + // rules.revoke (spec 3.f) + REVOKE_NEEDS_TARGET: 'REVOKE_NEEDS_TARGET', + // sendTransaction (spec 3.f) + NO_RULES_FOR_CHAIN: 'NO_RULES_FOR_CHAIN', + FROM_NOT_ALLOWED: 'FROM_NOT_ALLOWED', + NOT_ALLOWED_IN_AGENTIC_MODE: 'NOT_ALLOWED_IN_AGENTIC_MODE', + // SDK-owned + INVALID_RULE: 'INVALID_RULE', + CAPABILITY_UNAVAILABLE: 'CAPABILITY_UNAVAILABLE', + GENERATION_UNSUPPORTED: 'GENERATION_UNSUPPORTED', + READ_ONLY: 'READ_ONLY', + NOT_WALLET_OWNER: 'NOT_WALLET_OWNER', + RULE_NOT_FOUND: 'RULE_NOT_FOUND', + RULE_READ_FAILED: 'RULE_READ_FAILED', + INCONSISTENT_READ: 'INCONSISTENT_READ', + INDEX_RACE: 'INDEX_RACE', + CREATE_PARTIAL: 'CREATE_PARTIAL', + RECEIPT_MISMATCH: 'RECEIPT_MISMATCH', + RECEIPT_UNAVAILABLE: 'RECEIPT_UNAVAILABLE', + AGENT_GAS_INSUFFICIENT: 'AGENT_GAS_INSUFFICIENT', + WALLET_BALANCE_INSUFFICIENT: 'WALLET_BALANCE_INSUFFICIENT', + GATEWAY_ALLOWANCE_INSUFFICIENT: 'GATEWAY_ALLOWANCE_INSUFFICIENT', + RULE_LIMIT_EXCEEDED: 'RULE_LIMIT_EXCEEDED', +} as const; + +export type AgenticErrorCode = + (typeof AGENTIC_ERROR_CODE)[keyof typeof AGENTIC_ERROR_CODE]; + +/** + * Pre-signature AGW failure: invalid input, unsupported capability, failed + * eligibility or a read that cannot be trusted. Nothing was signed or sent + * unless `details` explicitly records committed hashes (CREATE_PARTIAL). + */ +export class AgenticError extends Error { + readonly code: AgenticErrorCode; + readonly hint?: string; + readonly details?: Readonly>; + override readonly cause?: unknown; + + constructor( + code: AgenticErrorCode, + message: string, + opts: { + hint?: string; + details?: Record; + cause?: unknown; + } = {} + ) { + super(message); + this.name = 'AgenticError'; + this.code = code; + this.hint = opts.hint; + this.details = opts.details; + this.cause = opts.cause; + } +} + +/** + * On-chain AGW, URP, factory or engine revert surfaced from an agentic send. + * Extends core's structured execution error so `instanceof + * PushChainExecutionError` keeps working, and keeps the underlying cause plus + * any batch recovery hashes. + */ +export class AgenticRevertError extends PushChainExecutionError { + readonly agenticCode?: string; + readonly transactionHashes?: `0x${string}`[]; + readonly pendingTransactionHash?: `0x${string}`; + + constructor( + message: string, + opts: { + decodedError?: DecodedErrorPayload; + gatewayTxHash?: string; + agenticCode?: string; + transactionHashes?: `0x${string}`[]; + pendingTransactionHash?: `0x${string}`; + cause?: unknown; + } = {} + ) { + super(message, { + decodedError: opts.decodedError, + gatewayTxHash: opts.gatewayTxHash, + cause: opts.cause, + }); + this.name = 'AgenticRevertError'; + this.agenticCode = opts.agenticCode; + this.transactionHashes = opts.transactionHashes + ? [...opts.transactionHashes] + : undefined; + this.pendingTransactionHash = opts.pendingTransactionHash; + } +} + +export function capabilityUnavailable( + capability: string, + dependency: string, + hint?: string +): AgenticError { + return new AgenticError( + AGENTIC_ERROR_CODE.CAPABILITY_UNAVAILABLE, + `AGW capability "${capability}" is not available: ${dependency}`, + { hint, details: { capability, dependency } } + ); +} diff --git a/packages/core/src/lib/agentic/execution/guards.ts b/packages/core/src/lib/agentic/execution/guards.ts new file mode 100644 index 00000000..2aa5f68e --- /dev/null +++ b/packages/core/src/lib/agentic/execution/guards.ts @@ -0,0 +1,46 @@ +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; + +/** Methods the spec forbids on an agentic client (spec 2.a). */ +export type ForbiddenAgenticMethod = + | 'prepareTransaction' + | 'executeTransactions' + | 'migrateCEA' + | 'rescueFunds' + | 'payGasWith'; + +export function notAllowedInAgenticMode(method: ForbiddenAgenticMethod | string): AgenticError { + return new AgenticError( + AGENTIC_ERROR_CODE.NOT_ALLOWED_IN_AGENTIC_MODE, + `${method} is not available on a client initialized with agenticWallet`, + { + hint: + method === 'prepareTransaction' || method === 'executeTransactions' + ? 'Use sendTransaction; cascades would run from the signer, not the wallet.' + : 'Use a client initialized without agenticWallet for signer-level operations.', + } + ); +} + +/** + * Reject inputs that would execute from somewhere other than the wallet, or + * that agentic mode does not support, before any signature or RPC call. + */ +export function guardAgenticSendParams(params: unknown): void { + if (!params || typeof params !== 'object') { + throw new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, 'sendTransaction needs a transaction object'); + } + const p = params as { + from?: unknown; + payGasWith?: unknown; + migration?: unknown; + }; + if (p.from !== undefined && p.from !== null) { + throw new AgenticError( + AGENTIC_ERROR_CODE.FROM_NOT_ALLOWED, + '`from` (Routes 3 and 4) is not allowed in agenticWallet mode', + { hint: 'A CEA-originated call makes msg.sender a CEA, so the wallet door check would fail.' } + ); + } + if (p.payGasWith !== undefined) throw notAllowedInAgenticMode('payGasWith'); + if (p.migration) throw notAllowedInAgenticMode('migrateCEA'); +} diff --git a/packages/core/src/lib/agentic/execution/outbound.ts b/packages/core/src/lib/agentic/execution/outbound.ts new file mode 100644 index 00000000..ab78059f --- /dev/null +++ b/packages/core/src/lib/agentic/execution/outbound.ts @@ -0,0 +1,263 @@ +import { + concat, + encodeAbiParameters, + encodeFunctionData, + getAddress, + type Address, + type Hex, +} from 'viem'; +import { CHAIN, VM } from '../../constants/enums'; +import { CHAIN_INFO } from '../../constants/chain'; +import type { MoveableToken } from '../../constants/tokens'; +import { ERC20_EVM, UNIVERSAL_GATEWAY_PC } from '../../constants/abi'; +import type { + UniversalExecuteParams, + UniversalOutboundTxRequest, +} from '../../orchestrator/orchestrator.types'; +import { isPC20Reference } from '../../orchestrator/orchestrator.types'; +import { resolveR2DestinationFundsToken } from '../../orchestrator/internals/route-handlers'; +import { AgenticCapability, requireCapability } from '../capabilities'; +import type { AgenticGeneration } from '../deployments'; +import type { Call } from '../contracts/v5'; +import { UEA_MULTICALL_PREFIX } from '../contracts/v5'; +import { + AGENTIC_ERROR_CODE, + AgenticError, + capabilityUnavailable, +} from '../errors'; +import type { AgenticRuntime } from '../runtime'; + +/** URP MAX_ACTIONS_PER_REQUEST at v5. */ +export const MAX_DESTINATION_CALLS = 10; + +const MULTICALL_TUPLE = [ + { + type: 'tuple[]', + components: [ + { name: 'to', type: 'address' }, + { name: 'value', type: 'uint256' }, + { name: 'data', type: 'bytes' }, + ], + }, +] as const; + +export interface DestinationCall { + to: Address; + value: bigint; + data: Hex; +} + +export interface ComposedOutbound { + chain: CHAIN; + destinationAccount: Address; + destinationAccountDeployed: boolean; + token: Address; + amount: bigint; + /** PC the wallet attaches: protocolFee + maxPCForGas. */ + value: bigint; + request: UniversalOutboundTxRequest; + /** The wallet's call into the gateway. */ + gatewayCall: Call; + destinationCalls: DestinationCall[]; +} + +/** + * The calls the wallet's destination account (CEA) executes, built exactly as + * core's Route 2 builds them for an ordinary account (buildR2CeaPayloadEvm): + * - explicit call arrays are used as given (the caller handles transfers); + * - with ERC-20 funds, a transfer(target, amount) is prepended to a single + * call, or is the whole payload for a transfer-only send; + * - native value (and native funds) goes to the target with the call, or as + * a value-only call; a value transfer to the CEA itself is skipped. + * Every encoded call names the requested target, so a response never reports + * a delivery the request does not instruct. + */ +export function destinationCalls( + params: UniversalExecuteParams, + ctx: { cea: Address; fundsToken?: MoveableToken } +): DestinationCall[] { + const target = getAddress((params.to as { address: string }).address); + if (Array.isArray(params.data)) { + return params.data.map((c) => ({ + to: getAddress(c.to), + value: c.value ?? BigInt(0), + data: c.data, + })); + } + const amount = params.funds?.amount ?? BigInt(0); + const token = ctx.fundsToken; + const erc20 = amount > BigInt(0) && token && token.mechanism !== 'native'; + const nativeFunds = + amount > BigInt(0) && token?.mechanism === 'native' ? amount : BigInt(0); + const value = params.value ?? BigInt(0); + const calls: DestinationCall[] = []; + if (erc20) { + calls.push({ + to: getAddress((token as MoveableToken).address), + value: BigInt(0), + data: encodeFunctionData({ + abi: ERC20_EVM, + functionName: 'transfer', + args: [target, amount], + }), + }); + } + const data = params.data && params.data !== '0x' ? params.data : undefined; + if (data) { + calls.push({ to: target, value: value + nativeFunds, data }); + } else { + const forward = value > BigInt(0) ? value : nativeFunds; + if (forward > BigInt(0) && target !== ctx.cea) { + calls.push({ to: target, value: forward, data: '0x' }); + } + } + return calls; +} + +/** + * Compose the AGW-originated EVM outbound (Route 2 shape, wallet context): + * - recipient = empty bytes, revertRecipient = the AGW, maxPCForGas > 0 + * - payload = UEA_MULTICALL ‖ abi.encode(Multicall[1..10]) executed by the AGW's CEA + * - value = protocolFee + maxPCForGas, paid from the AGW's PC + * The destination account is resolved from the AGW, never from the signer. + * The SDK never writes a gateway allowance on either door: the gateway pulls + * from an allowance the owner set separately with an ordinary send. + */ +export async function composeOutbound( + runtime: AgenticRuntime, + gen: AgenticGeneration, + wallet: Address, + params: UniversalExecuteParams, + opts: { ruleAssets?: readonly Address[]; door: 'owner' | 'agent' } +): Promise { + requireCapability(gen.capabilities, AgenticCapability.UNIVERSAL_EVM_OUTBOUND); + const target = params.to as { address: string; chain: CHAIN }; + const chain = target.chain; + const info = CHAIN_INFO[chain]; + if (!info) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + `unknown destination chain ${String(chain)}` + ); + } + if (info.vm !== VM.EVM) { + throw capabilityUnavailable( + AgenticCapability.UNIVERSAL_SVM_RULES, + 'This composer accepts EVM destinations; use the Solana instruction route' + ); + } + const funds = params.funds; + if (funds && isPC20Reference(funds.token)) { + throw capabilityUnavailable( + 'pc20Outbound', + 'PC20 tokens are not supported through an agentic wallet' + ); + } + // An omitted funds.token means the destination chain's native token, as in Route 2. + const fundsToken: MoveableToken | undefined = funds?.amount + ? funds.token + ? resolveR2DestinationFundsToken( + funds.token as MoveableToken, + chain, + runtime.network + ) + : { + symbol: 'native', + decimals: 18, + address: '0x0000000000000000000000000000000000000000', + mechanism: 'native', + } + : undefined; + + // Burn token and amount, as Route 2 sizes them for an ordinary account. + let token: Address; + let amount = BigInt(0); + if (funds) { + token = runtime.resolvePrc20( + funds.token as MoveableToken | undefined, + chain + ); + amount = funds.amount; + } else if ((params.value ?? BigInt(0)) > BigInt(0)) { + token = runtime.resolvePrc20(undefined, chain); + amount = params.value as bigint; + } else if (opts.ruleAssets?.length) { + token = getAddress(opts.ruleAssets[0]); + } else { + token = runtime.resolvePrc20(undefined, chain); + } + const resolved = await runtime.resolveCEA(wallet, chain); + const cea = getAddress(resolved.cea); + const calls = destinationCalls(params, { cea, fundsToken }); + if (calls.length === 0) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'this outbound carries no destination call; parking funds in the wallet’s destination account is not supported', + { + hint: 'Name a recipient other than the wallet’s own destination account, or add calldata.', + } + ); + } + if (calls.length > MAX_DESTINATION_CALLS) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + `at most ${MAX_DESTINATION_CALLS} destination calls per outbound` + ); + } + if (opts.door === 'agent') { + const bare = calls.findIndex((c) => (c.data.length - 2) / 2 < 4); + if (bare >= 0) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + `destination call ${bare} has no function selector; the rules policy only admits allow-listed calls`, + { + hint: 'A value-only destination transfer is not representable in an agent rule.', + } + ); + } + } + + const quote = await runtime.quoteOutbound( + token, + params.gasLimit ?? BigInt(0), + chain + ); + if (quote.nativeValueForGas <= BigInt(0)) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'outbound gas quote returned zero; URP rejects an uncapped gas swap' + ); + } + const maxPCForGas = quote.nativeValueForGas; + const value = quote.protocolFee + maxPCForGas; + const payload = concat([ + UEA_MULTICALL_PREFIX, + encodeAbiParameters(MULTICALL_TUPLE, [calls]), + ]); + const request: UniversalOutboundTxRequest = { + recipient: '0x', + token, + amount, + gasLimit: quote.gasLimitUsed, + gasPrice: BigInt(0), + maxPCForGas, + payload, + revertRecipient: wallet, + }; + const data = encodeFunctionData({ + abi: UNIVERSAL_GATEWAY_PC, + functionName: 'sendUniversalTxOutbound', + args: [request], + }); + return { + chain, + destinationAccount: cea, + destinationAccountDeployed: resolved.isDeployed, + token, + amount, + value, + request, + gatewayCall: { target: gen.addresses.gateway, value, data }, + destinationCalls: calls, + }; +} diff --git a/packages/core/src/lib/agentic/execution/send.ts b/packages/core/src/lib/agentic/execution/send.ts new file mode 100644 index 00000000..6f18a4ca --- /dev/null +++ b/packages/core/src/lib/agentic/execution/send.ts @@ -0,0 +1,401 @@ +import { sendPublicSvm } from './svm-public'; +import { getAddress, type Address, type Hex } from 'viem'; +import type { CHAIN } from '../../constants/enums'; +import { ERC20_EVM } from '../../constants/abi'; +import { PROGRESS_HOOK } from '../../progress-hook/progress-hook.types'; +import type { + ExecuteParams, + MultiCall, + TransactionExecutionOptions, + UniversalExecuteParams, + UniversalTxResponse, +} from '../../orchestrator/orchestrator.types'; +import { isChainTarget } from '../../orchestrator/route-detector'; +import { + getPushChainForNetwork, + isPushChain, +} from '../../orchestrator/internals/helpers'; +import { AgenticCapability, requireCapability } from '../capabilities'; +import type { AgenticExecutionContext } from '../context'; +import type { Call, UniversalConfigRead } from '../contracts/v5'; +import { SEND_OUTBOUND_SELECTOR } from '../contracts/v5'; +import { actionId, configId } from '../codec/ids'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; +import { + assertCanSign, + emitAgentic, + wrapSendError, +} from '../management/common'; +import { selectRuleForSend } from '../reads/rules'; +import { Snapshot } from '../reads/snapshot'; +import { adaptAgenticResponse, outboundResponseCall } from '../response'; +import type { AgenticRuntime } from '../runtime'; +import type { AgenticHex, AgenticProgressHook } from '../agentic.types'; +import { guardAgenticSendParams } from './guards'; +import { composeOutbound, type DestinationCall } from './outbound'; + +const MODE_UNIVERSAL = 0; +const VM_EVM = 0; +/** R1's own required-funds estimate when no gasLimit is given (execute-standard). */ +const DEFAULT_GAS_ESTIMATE = BigInt(1e7); + +/** Signer-level fields that legitimately carry over to the wrapped Push tx. */ +function signerFields(p: UniversalExecuteParams): Partial { + const out: Partial = {}; + if (p.gasLimit !== undefined && !isChainTarget(p.to)) + out.gasLimit = p.gasLimit; + if (p.maxFeePerGas !== undefined) out.maxFeePerGas = p.maxFeePerGas; + if (p.maxPriorityFeePerGas !== undefined) + out.maxPriorityFeePerGas = p.maxPriorityFeePerGas; + if (p.nonce !== undefined) out.nonce = p.nonce; + if (p.deadline !== undefined) out.deadline = p.deadline; + if (p.feeLockTxHash !== undefined) out.feeLockTxHash = p.feeLockTxHash; + return out; +} + +/** + * Spec 2.a gas rule: in agenticWallet mode an external signer's UEA must + * already hold the PC for its Push gas, except for the very first action + * while that UEA is undeployed (which takes the one-time origin fee lock). + * Mirrors R1's fee-lock condition so an underfunded UEA fails loudly here + * instead of silently locking origin funds on every action. + */ +async function enforceSignerGas( + runtime: AgenticRuntime, + gasLimit: bigint | undefined +): Promise { + if (runtime.signerIsPushNative()) return; + if (!(await runtime.signerAccountDeployed())) return; + const [gasPrice, balance] = await Promise.all([ + runtime.getGasPrice(), + runtime.signerBalance(), + ]); + const required = (gasLimit ?? DEFAULT_GAS_ESTIMATE) * gasPrice; + if (balance < required) { + throw new AgenticError( + AGENTIC_ERROR_CODE.AGENT_GAS_INSUFFICIENT, + `the signer's UEA ${runtime.signerPushAccount()} holds ${balance} PC wei but needs ~${required} for Push gas`, + { + hint: "The wallet's PC pays outbound fees, not the signer's gas. Top up the signer's UEA (PushChain.utils.account.deriveExecutorAccount) from a client without agenticWallet.", + details: { required, balance }, + } + ); + } +} + +/** + * A ChainTarget naming the connected Push chain is a native send, exactly like + * a bare address (core's route detector treats it the same way). A ChainTarget + * naming a different Push network is refused rather than routed outbound. + */ +function normalizePushDestination( + p: UniversalExecuteParams, + runtime: AgenticRuntime +): UniversalExecuteParams { + if (!isChainTarget(p.to)) return p; + const chain = p.to.chain; + if (chain === getPushChainForNetwork(runtime.network)) { + return { ...p, to: getAddress(p.to.address) }; + } + if (isPushChain(chain)) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + `destination ${chain} is a Push chain other than the connected network (${runtime.network})` + ); + } + return p; +} + +function toCalls(params: UniversalExecuteParams): Call[] { + if (Array.isArray(params.data)) { + return params.data.map((c) => ({ + target: getAddress(c.to), + value: c.value ?? BigInt(0), + data: c.data, + })); + } + return [ + { + target: getAddress(params.to as Address), + value: params.value ?? BigInt(0), + data: (params.data ?? '0x') as Hex, + }, + ]; +} + +/** + * sendTransaction in agenticWallet mode. Owner door → execute; agent door → + * executeAsAgent under the one enabled rule for (signer, destination), looked + * up on every send. Everything is validated before the signer is asked. + */ +export async function agenticSend( + runtime: AgenticRuntime, + actx: AgenticExecutionContext, + params: UniversalExecuteParams | ExecuteParams, + options?: TransactionExecutionOptions +): Promise { + assertCanSign(runtime, 'sendTransaction'); + guardAgenticSendParams(params); + const p = normalizePushDestination(params as UniversalExecuteParams, runtime); + const hook: AgenticProgressHook | undefined = + options?.progressHook ?? p.progressHook; + const gen = actx.generation; + const wallet = actx.wallet; + const outbound = isChainTarget(p.to); + const destination = outbound + ? (p.to as { chain: string }).chain + : runtime.pushChainNamespace; + + if (!outbound && p.funds) { + throw new AgenticError( + AGENTIC_ERROR_CODE.NOT_ALLOWED_IN_AGENTIC_MODE, + "`funds` on a Push-chain send would bridge from the signer; it does not move the wallet's tokens", + { + hint: "Transfer the wallet's PRC20 with a token transfer call in `data`.", + } + ); + } + + if (outbound && destination.startsWith('solana:')) { + await enforceSignerGas(runtime, undefined); + return sendPublicSvm(runtime, actx, p, options); + } + + let wrappedData: Hex; + let agentBatch: MultiCall[] | undefined; + let nativeCalls: Call[] | undefined; + let rulesId: AgenticHex | undefined; + let logical: { to: string; data: string; value: bigint }; + let meta: { route?: 'UOA_TO_CEA'; destinationAccount?: Address } = {}; + let outboundChain: CHAIN | undefined; + let destinationCalls: DestinationCall[] | undefined; + + if (actx.door === 'agent') { + requireCapability(gen.capabilities, AgenticCapability.AGENT_EXECUTE); + } else { + requireCapability(gen.capabilities, AgenticCapability.OWNER_EXECUTE); + } + + if (!outbound) { + const calls = toCalls(p); + if (calls.length === 0) + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'an empty call array cannot execute' + ); + if (actx.door === 'owner') { + wrappedData = gen.contracts.encodeExecute(calls); + } else { + const snap = await Snapshot.at(runtime.reader); + const rule = await selectRuleForSend( + snap, + gen, + wallet, + actx.signerPushAccount, + destination + ); + rulesId = rule.rulesId as AgenticHex; + wrappedData = gen.contracts.encodeExecuteAsAgent(rule.rulesId, calls[0]); + if (calls.length > 1) { + agentBatch = calls.map((call) => ({ + to: wallet, + value: BigInt(0), + data: gen.contracts.encodeExecuteAsAgent(rule.rulesId, call), + })); + nativeCalls = calls; + } + } + logical = + calls.length === 1 + ? { to: calls[0].target, data: calls[0].data, value: calls[0].value } + : agentBatch + ? { to: calls[0].target, data: calls[0].data, value: calls[0].value } + : { to: wallet, data: wrappedData, value: BigInt(0) }; + } else { + let ruleAssets: readonly Address[] | undefined; + let expectedCEA: Address | undefined; + const snap = await Snapshot.at(runtime.reader); + if (actx.door === 'agent') { + const rule = await selectRuleForSend( + snap, + gen, + wallet, + actx.signerPushAccount, + destination + ); + if (rule.mode !== MODE_UNIVERSAL || rule.vm !== VM_EVM) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + `rule ${rule.rulesId} is not an EVM universal rule` + ); + } + rulesId = rule.rulesId as AgenticHex; + const cfg = await snap.read( + gen.addresses.rulesPolicy, + gen.contracts.abis.policy, + 'getConfig', + [ + configId( + wallet, + rule.rulesId, + actionId(gen.addresses.gateway, SEND_OUTBOUND_SELECTOR) + ), + wallet, + ] + ); + ruleAssets = cfg.assets.map((a) => getAddress(a.token)); + expectedCEA = getAddress(cfg.expectedCEA); + } + const out = await composeOutbound(runtime, gen, wallet, p, { + ruleAssets, + door: actx.door, + }); + outboundChain = out.chain; + meta = { route: 'UOA_TO_CEA', destinationAccount: out.destinationAccount }; + const [walletPc, tokenBalance, allowance] = await Promise.all([ + runtime.reader.getBalance({ + address: wallet, + blockNumber: snap.blockNumber, + }), + out.amount > BigInt(0) + ? snap.read( + out.token, + ERC20_EVM as unknown as readonly unknown[], + 'balanceOf', + [wallet] + ) + : Promise.resolve(BigInt(0)), + snap.read( + out.token, + ERC20_EVM as unknown as readonly unknown[], + 'allowance', + [wallet, gen.addresses.gateway] + ), + ]); + if (walletPc < out.value) { + throw new AgenticError( + AGENTIC_ERROR_CODE.WALLET_BALANCE_INSUFFICIENT, + `wallet ${wallet} holds ${walletPc} PC wei; this outbound needs ${out.value} (protocol fee + gas cap)`, + { hint: "Fund the wallet's PC with an ordinary send to its address." } + ); + } + if (tokenBalance < out.amount) { + throw new AgenticError( + AGENTIC_ERROR_CODE.WALLET_BALANCE_INSUFFICIENT, + `wallet ${wallet} holds ${tokenBalance} of ${out.token}; this outbound burns ${out.amount}` + ); + } + // Both doors only consume an allowance the owner set separately; the SDK + // never writes one (a write from a stale read could restore revoked authority). + if (out.amount > allowance) { + throw new AgenticError( + AGENTIC_ERROR_CODE.GATEWAY_ALLOWANCE_INSUFFICIENT, + `the gateway may pull ${allowance} of ${out.token} from the wallet; this outbound needs ${out.amount}`, + { + hint: 'Set a bounded allowance first with an owner-door send: approve(gateway, cap) on the token (approve(gateway, 0) removes it).', + } + ); + } + if (actx.door === 'agent') { + if (expectedCEA && expectedCEA !== out.destinationAccount) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INCONSISTENT_READ, + `rule ${rulesId} committed destination account ${expectedCEA}, but the wallet's account on ${out.chain} now derives to ${out.destinationAccount}`, + { + hint: 'Destination-account derivation drift (obligation 13). The owner must regrant the rule.', + } + ); + } + wrappedData = gen.contracts.encodeExecuteAsAgent( + rulesId as Hex, + out.gatewayCall + ); + } else { + wrappedData = gen.contracts.encodeExecute([out.gatewayCall]); + } + destinationCalls = out.destinationCalls; + logical = outboundResponseCall(destinationCalls, { + to: out.gatewayCall.target, + data: out.gatewayCall.data, + value: out.gatewayCall.value, + }); + } + + await enforceSignerGas(runtime, signerFields(p).gasLimit); + emitAgentic( + runtime, + hook, + PROGRESS_HOOK.AGENTIC_TX_107, + rulesId, + outboundChain ?? destination, + actx.door + ); + + let resp: UniversalTxResponse; + try { + const sendOptions = hook ? { ...options, progressHook: hook } : options; + resp = agentBatch + ? await runtime.executeAtomicBatch( + { + ...signerFields(p), + to: wallet, + value: BigInt(0), + data: agentBatch, + }, + sendOptions + ) + : await runtime.execute( + { + ...signerFields(p), + to: wallet, + value: BigInt(0), + data: wrappedData, + }, + sendOptions + ); + } catch (err) { + const wrapped = wrapSendError(err) as { + code?: string; + message?: string; + decodedError?: unknown; + }; + emitAgentic( + runtime, + hook, + PROGRESS_HOOK.AGENTIC_TX_199_02, + 'sendTransaction', + wrapped?.code ?? 'UNKNOWN', + wrapped?.message ?? String(err), + wrapped?.decodedError + ); + throw wrapped; + } + adaptAgenticResponse(resp, { + wallet, + door: actx.door, + rulesId, + chainNamespace: outboundChain ?? destination, + destinationAccount: meta.destinationAccount as AgenticHex | undefined, + destinationCalls, + ...(nativeCalls + ? { + nativeCalls: nativeCalls.map((c) => ({ + to: c.target, + data: c.data, + value: c.value, + })), + } + : {}), + logical, + route: meta.route, + chain: outboundChain, + }); + emitAgentic( + runtime, + hook, + PROGRESS_HOOK.AGENTIC_TX_199_01, + 'sendTransaction', + resp.hash + ); + return resp; +} diff --git a/packages/core/src/lib/agentic/execution/svm-instruction.ts b/packages/core/src/lib/agentic/execution/svm-instruction.ts new file mode 100644 index 00000000..3d81bcd5 --- /dev/null +++ b/packages/core/src/lib/agentic/execution/svm-instruction.ts @@ -0,0 +1,67 @@ +import type { CHAIN } from '../../constants/enums'; +import { resolveSvmCallForCea } from '../../orchestrator/svm-idl/resolve'; +import type { SvmTermsWire } from '../codec/svm-terms'; +import { svmKey } from '../codec/svm-accounts'; +import { + encodeAgwSvmPayload, + validateAgwSvmPayload, + type SvmPayloadAccount, +} from './svm-payload'; +import type { Address } from 'viem'; + +/** Resolve IDL accounts with the wallet authority; granted permissions are checked by URP. */ +export function resolveAgwSvmInstruction( + input: { + wallet: Address; + chain: CHAIN; + program: string; + instructionData: Uint8Array; + accounts?: readonly SvmPayloadAccount[]; + }, + terms: SvmTermsWire +) { + const program = svmKey(input.program); + if (input.accounts) { + const payload = encodeAgwSvmPayload( + program, + input.accounts, + input.instructionData + ); + return { + recipient: program, + payload, + accounts: [...input.accounts], + instructionData: input.instructionData, + }; + } + const resolved = resolveSvmCallForCea( + { + programAddress: program, + data: input.instructionData, + senderUea: input.wallet, + targetChain: input.chain, + }, + terms.expectedCEA + ); + const payload = encodeAgwSvmPayload( + resolved.targetProgram, + resolved.accounts, + resolved.ixData + ); + return { + recipient: program, + payload, + accounts: resolved.accounts, + instructionData: resolved.ixData, + }; +} + +/** Diagnostic-only local policy preview. Sends use the resolver and contract enforcement. */ +export function prepareAgwSvmInstruction( + input: Parameters[0], + terms: SvmTermsWire +) { + const resolved = resolveAgwSvmInstruction(input, terms); + validateAgwSvmPayload(terms, resolved.recipient, resolved.payload); + return resolved; +} diff --git a/packages/core/src/lib/agentic/execution/svm-outbound.ts b/packages/core/src/lib/agentic/execution/svm-outbound.ts new file mode 100644 index 00000000..6f35c58f --- /dev/null +++ b/packages/core/src/lib/agentic/execution/svm-outbound.ts @@ -0,0 +1,102 @@ +/** Outbound encoding plus a diagnostic-only policy preview. */ +import { encodeFunctionData, getAddress, type Address, type Hex } from 'viem'; +import { UNIVERSAL_GATEWAY_PC } from '../../constants/abi'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; +import type { Call, SvmConfigRead } from '../contracts/v5'; +import { UINT256_MAX } from '../codec/defaults'; +import { UINT64_MAX } from '../codec/svm-terms'; +import { validateAgwSvmPayload } from './svm-payload'; + +export interface SvmOutboundInput { + wallet: Address; + gateway: Address; + token: Address; + amount: bigint; + recipient: Hex; + payload: Hex; + gasLimit: bigint; + protocolFee: bigint; + maxPCForGas: bigint; +} +/** Diagnostic-only local preview; production sends use buildAgwSvmAction. */ +export function composeAgwSvmAction( + input: SvmOutboundInput, + config: SvmConfigRead, + nowSeconds: number +): Call { + function fail(name: string): never { + throw new AgenticError(AGENTIC_ERROR_CODE.RULE_LIMIT_EXCEEDED, name, { + details: { contractError: name }, + }); + } + if (!config.initialized) fail('NotInitialized'); + if (nowSeconds > config.validUntil) fail('RulesExpired'); + for (const [name, value] of Object.entries({ + amount: input.amount, + gasLimit: input.gasLimit, + protocolFee: input.protocolFee, + maxPCForGas: input.maxPCForGas, + })) { + if (typeof value !== 'bigint' || value < BigInt(0) || value > UINT256_MAX) + fail(`${name}OutOfRange`); + } + const token = getAddress(input.token), + cap = config.assets.find((a) => getAddress(a.token) === token); + if (!cap) fail('AssetNotAllowed'); + if (input.amount > UINT64_MAX) fail('AmountExceedsU64'); + if (input.amount > cap.maxPerCall) fail('AmountExceedsCap'); + if (cap.spent + input.amount > cap.maxTotal) fail('TotalSpendCapExceeded'); + const value = input.protocolFee + input.maxPCForGas; + if (value > UINT256_MAX || value > config.maxGasPerCall) + fail('PCValueExceedsCap'); + if (!input.maxPCForGas) fail('UncappedGasSwapRejected'); + validateAgwSvmPayload(config, input.recipient, input.payload); + return buildAgwSvmAction(input); +} + +/** Encode an outbound without evaluating the granted policy; the wallet/URP enforces it. */ +export function buildAgwSvmAction(input: SvmOutboundInput): Call { + for (const [name, value] of Object.entries({ + amount: input.amount, + gasLimit: input.gasLimit, + protocolFee: input.protocolFee, + maxPCForGas: input.maxPCForGas, + })) { + if (typeof value !== 'bigint' || value < BigInt(0) || value > UINT256_MAX) + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + `${name} must fit uint256` + ); + } + if (input.amount > UINT64_MAX) + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'Solana amount must fit uint64' + ); + const value = input.protocolFee + input.maxPCForGas; + if (value > UINT256_MAX || input.maxPCForGas === BigInt(0)) + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'invalid outbound gas quote' + ); + const token = getAddress(input.token); + const request = { + recipient: input.recipient, + token, + amount: input.amount, + gasLimit: input.gasLimit, + gasPrice: BigInt(0), + maxPCForGas: input.maxPCForGas, + payload: input.payload, + revertRecipient: getAddress(input.wallet), + }; + return { + target: getAddress(input.gateway), + value, + data: encodeFunctionData({ + abi: UNIVERSAL_GATEWAY_PC, + functionName: 'sendUniversalTxOutbound', + args: [request], + }), + }; +} diff --git a/packages/core/src/lib/agentic/execution/svm-payload.ts b/packages/core/src/lib/agentic/execution/svm-payload.ts new file mode 100644 index 00000000..da76d7ee --- /dev/null +++ b/packages/core/src/lib/agentic/execution/svm-payload.ts @@ -0,0 +1,146 @@ +/** Parser/validator for the deployed S12–S18 instruction grammar. */ +import { bytesToHex, hexToBytes, type Hex } from 'viem'; +import { encodeSvmExecutePayload } from '../../orchestrator/payload-builders'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; +import { + exactHex, + isForbiddenSvmProgram, + SVM_LIMITS, + SvmDataPinMode, + type SvmTermsWire, +} from '../codec/svm-terms'; + +export interface SvmPayloadAccount { + pubkey: Hex; + isWritable: boolean; +} +export interface ParsedSvmPayload { + program: Hex; + accounts: (SvmPayloadAccount & { writableFlag: number })[]; + instructionData: Uint8Array; +} +function fail(name: string): never { + throw new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, name, { + details: { contractError: name }, + }); +} +export function parseAgwSvmPayload(payload: Hex): ParsedSvmPayload { + if (!/^0x(?:[0-9a-fA-F]{2})*$/.test(payload)) fail('MalformedSvmPayload'); + const bytes = hexToBytes(payload); + if (!bytes.length) fail('SvmPayloadEmpty'); + if (bytes.length < 41) fail('MalformedSvmPayload'); + const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength), + count = view.getUint32(0, false); + if (count > SVM_LIMITS.accounts) fail('SvmAccountsOutOfRange'); + const lenOffset = 4 + count * 33; + if (bytes.length < lenOffset + 4) fail('MalformedSvmPayload'); + const length = view.getUint32(lenOffset, false); + if (length > SVM_LIMITS.ixData) fail('SvmIxDataTooLong'); + const dataOffset = lenOffset + 4; + if (bytes.length !== dataOffset + length + 33) fail('MalformedSvmPayload'); + if (bytes[dataOffset + length] !== 2) fail('SvmInstructionNotExecute'); + const accounts = Array.from({ length: count }, (_, i) => { + const offset = 4 + i * 33, + writableFlag = bytes[offset + 32]; + // URP does not judge this flag. Preserve the raw value for diagnostics. + return { + pubkey: bytesToHex(bytes.slice(offset, offset + 32)), + isWritable: writableFlag === 1, + writableFlag, + }; + }); + return { + program: bytesToHex(bytes.slice(dataOffset + length + 1)), + accounts, + instructionData: bytes.slice(dataOffset, dataOffset + length), + }; +} +export function encodeAgwSvmPayload( + program: Hex, + accounts: readonly SvmPayloadAccount[], + instructionData: Uint8Array +): Hex { + exactHex(program, 32, 'target program'); + if (accounts.length > SVM_LIMITS.accounts) fail('SvmAccountsOutOfRange'); + if (instructionData.length > SVM_LIMITS.ixData) fail('SvmIxDataTooLong'); + accounts.forEach((a) => { + exactHex(a.pubkey, 32, 'account'); + if (typeof a.isWritable !== 'boolean') fail('MalformedSvmPayload'); + }); + return encodeSvmExecutePayload({ + targetProgram: program, + accounts: [...accounts], + ixData: instructionData, + instructionId: 2, + }); +} +function uintLE(data: Uint8Array): bigint { + return data.reduceRight((v, b) => (v << BigInt(8)) + BigInt(b), BigInt(0)); +} +/** Terms must have passed grant-shape validation. On-chain URP remains the enforcement authority. */ +export function validateAgwSvmPayload( + terms: SvmTermsWire, + recipient: Hex, + payload: Hex +): number { + exactHex(recipient, 32, 'recipient'); + if (BigInt(recipient) === BigInt(0)) fail('RecipientNotPubkey'); + const v = parseAgwSvmPayload(payload), + data = v.instructionData; + if (v.program.toLowerCase() !== recipient.toLowerCase()) + fail('RecipientTargetMismatch'); + if (isForbiddenSvmProgram(v.program, terms)) fail('ForbiddenTargetProgram'); + const rule = terms.programs.findIndex( + (p) => + p.program.toLowerCase() === v.program.toLowerCase() && + (p.dataless + ? data.length === 0 + : data.length >= p.discriminatorLen && + bytesToHex(data.slice(0, p.discriminatorLen)).toLowerCase() === + p.discriminator.slice(0, 2 + p.discriminatorLen * 2).toLowerCase()) + ); + if (rule < 0) fail('ProgramNotAllowed'); + const fixed = terms.programs[rule].maxAccounts; + if (fixed && fixed !== v.accounts.length) fail('SvmAccountCountMismatch'); + const pins = terms.pins.filter((p) => p.ruleIndex === rule); + for (const p of pins) { + if (p.accountIndex >= v.accounts.length) fail('SvmAccountCountBelowPin'); + if ( + v.accounts[p.accountIndex].pubkey.toLowerCase() !== + p.expected.toLowerCase() + ) + fail('SvmAccountPinMismatch'); + } + function field(fromEnd: boolean, offset: number, len: number): Uint8Array { + const start = fromEnd ? data.length - offset : offset; + if (start < 0 || start + len > data.length) fail('SvmDataTooShortForPin'); + return data.slice(start, start + len); + } + for (const p of terms.dataPins.filter((p) => p.ruleIndex === rule)) { + const a = field(p.fromEnd, p.offset, p.len); + if (p.mode === SvmDataPinMode.EQ) { + if ( + bytesToHex(a).toLowerCase() !== + p.expected.slice(0, 2 + p.len * 2).toLowerCase() + ) + fail('SvmDataPinMismatch'); + } else if (p.mode === SvmDataPinMode.GTE_LE) { + if (uintLE(a) < BigInt(p.expected)) fail('SvmDataFloorNotMet'); + } else if (p.mode === SvmDataPinMode.LTE_LE) { + if (uintLE(a) > BigInt(p.expected)) fail('SvmDataCeilingExceeded'); + } else if ( + uintLE(a) * p.den < + uintLE(field(p.fromEnd, p.offsetB, p.len)) * p.num + ) + fail('SvmDataRatioNotMet'); + } + const protectedKeys = new Set(terms.ceaAccounts.map((k) => k.toLowerCase())); + v.accounts.forEach((a, i) => { + if ( + protectedKeys.has(a.pubkey.toLowerCase()) && + !pins.some((p) => p.accountIndex === i) + ) + fail('CeaAccountAtUnpinnedIndex'); + }); + return rule; +} diff --git a/packages/core/src/lib/agentic/execution/svm-public.ts b/packages/core/src/lib/agentic/execution/svm-public.ts new file mode 100644 index 00000000..00c9b347 --- /dev/null +++ b/packages/core/src/lib/agentic/execution/svm-public.ts @@ -0,0 +1,278 @@ +import { PROGRESS_HOOK } from '../../progress-hook/progress-hook.types'; +import { emitAgentic } from '../management/common'; +import { bytesToHex, hexToBytes, erc20Abi, getAddress, type Hex } from 'viem'; +import type { CHAIN } from '../../constants/enums'; +import { + isPC20Reference, + type UniversalExecuteParams, + type TransactionExecutionOptions, +} from '../../orchestrator/orchestrator.types'; +import { resolveSvmCallForCea } from '../../orchestrator/svm-idl/resolve'; +import type { AgenticRuntime } from '../runtime'; +import type { AgenticExecutionContext } from '../context'; +import { AgenticCapability, requireCapability } from '../capabilities'; +import { selectRuleForSend } from '../reads/rules'; +import { readSvmConfig } from '../reads/svm'; +import { Snapshot } from '../reads/snapshot'; +import { svmMetadata } from '../management/svm-public'; +import { wrapSendError } from '../management/common'; +import type { MoveableToken } from '../../constants/tokens'; +import { svmKey, deriveAgwSvmCea } from '../codec/svm-accounts'; +import { svmInvalid, UINT64_MAX } from '../codec/svm-terms'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; +import { prepareSvmAgentExecution } from './svm-send'; +import { encodeAgwSvmPayload } from './svm-payload'; +import { quoteSvmRequest } from './svm-quote'; +import { buildAgwSvmAction } from './svm-outbound'; +import type { AgenticTxMetadata } from '../agentic.types'; +import { adaptAgenticResponse } from '../response'; + +/** Public single-instruction route; the contract enforces the supplied rule. */ +export async function sendPublicSvm( + runtime: AgenticRuntime, + actx: AgenticExecutionContext, + p: UniversalExecuteParams, + options?: TransactionExecutionOptions +) { + const gen = actx.generation, + wallet = actx.wallet; + requireCapability(gen.capabilities, AgenticCapability.UNIVERSAL_SVM_RULES); + requireCapability( + gen.capabilities, + actx.door === 'agent' + ? AgenticCapability.AGENT_EXECUTE + : AgenticCapability.OWNER_EXECUTE + ); + const to = p.to as { address: string; chain: CHAIN }; + const target = svmKey(to.address); + if (Array.isArray(p.data)) + throw svmInvalid('Solana AGW sends do not support instruction arrays'); + const hasInstruction = p.data !== undefined && p.data !== '0x'; + if ( + hasInstruction && + (typeof p.data !== 'string' || !/^0x(?:[0-9a-fA-F]{2})+$/.test(p.data)) + ) + throw svmInvalid('invalid Solana instruction bytes'); + if (!hasInstruction && actx.door === 'agent') + throw svmInvalid('Solana agent sends require an encoded instruction'); + if (p.funds && isPC20Reference(p.funds.token)) + throw svmInvalid('PC20 SVM outbound is not supported'); + if (p.funds && (p.value ?? BigInt(0)) !== BigInt(0)) + throw svmInvalid('use either funds or value for the bridged amount'); + const amount = p.funds?.amount ?? p.value ?? BigInt(0); + if (typeof amount !== 'bigint' || amount < BigInt(0) || amount > UINT64_MAX) + throw svmInvalid('Solana outbound amount must fit uint64'); + if (!hasInstruction && amount === BigInt(0)) + throw svmInvalid('a funds-only send requires a positive amount'); + const metadata = svmMetadata(runtime), + snap = await Snapshot.at(runtime.reader); + let rulesId: Hex | undefined, + data: Hex, + instruction: + | { + recipient: Hex; + instructionData: Uint8Array; + accounts: readonly { pubkey: Hex; isWritable: boolean }[]; + } + | undefined, + cea: Hex; + let destinationTransfer: AgenticTxMetadata['destinationTransfer']; + let transferValue = BigInt(0); + const gasLimit = p.gasLimit ?? BigInt(1_000_000); + if (actx.door === 'agent') { + const active = await selectRuleForSend( + snap, + gen, + wallet, + actx.signerPushAccount, + to.chain + ); + const stored = await readSvmConfig( + snap, + gen, + wallet, + active, + runtime.pushChainNamespace + ); + const token = + p.funds || amount > BigInt(0) + ? runtime.resolvePrc20( + p.funds?.token as MoveableToken | undefined, + to.chain + ) + : getAddress(stored.config.assets[0].token); + const prepared = await prepareSvmAgentExecution( + runtime, + gen, + { + wallet, + rulesId: active.rulesId, + token, + amount, + gasLimit, + program: target, + instructionData: hexToBytes(p.data as Hex), + }, + metadata + ); + data = prepared.data; + instruction = prepared.instruction; + cea = stored.config.expectedCEA; + rulesId = active.rulesId; + } else { + const gateway = await metadata.gateway(to.chain as `solana:${string}`); + cea = deriveAgwSvmCea(wallet, gateway.program).address; + const resolved = hasInstruction + ? resolveSvmCallForCea( + { + programAddress: target, + data: hexToBytes(p.data as Hex), + senderUea: wallet, + targetChain: to.chain, + }, + cea + ) + : undefined; + if (resolved) + instruction = { + recipient: resolved.targetProgram, + instructionData: resolved.ixData, + accounts: resolved.accounts, + }; + const token = runtime.resolvePrc20( + p.funds?.token as MoveableToken | undefined, + to.chain + ); + const quote = await quoteSvmRequest( + runtime, + snap, + wallet, + token, + to.chain, + gasLimit, + amount + ); + if (!hasInstruction) { + destinationTransfer = { recipient: target, token, amount }; + transferValue = quote.isNative ? amount : BigInt(0); + } + const [pc, balance, allowance] = await Promise.all([ + runtime.reader.getBalance({ + address: wallet, + blockNumber: snap.blockNumber, + }), + snap.read(token, erc20Abi, 'balanceOf', [wallet]), + snap.read(token, erc20Abi, 'allowance', [ + wallet, + gen.addresses.gateway, + ]), + ]); + const value = quote.protocolFee + quote.nativeValueForGas; + if (pc < value || balance < amount) + throw new AgenticError( + AGENTIC_ERROR_CODE.WALLET_BALANCE_INSUFFICIENT, + 'wallet cannot cover Solana outbound' + ); + if (allowance < amount) + throw new AgenticError( + AGENTIC_ERROR_CODE.GATEWAY_ALLOWANCE_INSUFFICIENT, + 'set the wallet gateway allowance separately' + ); + const call = buildAgwSvmAction({ + wallet, + gateway: gen.addresses.gateway, + token, + amount, + recipient: target, + payload: resolved + ? encodeAgwSvmPayload( + resolved.targetProgram, + resolved.accounts, + resolved.ixData + ) + : '0x', + gasLimit: quote.gasLimitUsed, + protocolFee: quote.protocolFee, + maxPCForGas: quote.nativeValueForGas, + }); + data = gen.contracts.encodeExecute([call]); + } + const hook = options?.progressHook ?? p.progressHook; + emitAgentic( + runtime, + hook, + PROGRESS_HOOK.AGENTIC_TX_107, + rulesId, + to.chain, + actx.door + ); + let response; + try { + response = await runtime.execute( + { + to: wallet, + value: BigInt(0), + data, + ...(p.nonce === undefined ? {} : { nonce: p.nonce }), + ...(p.maxFeePerGas === undefined + ? {} + : { maxFeePerGas: p.maxFeePerGas }), + ...(p.maxPriorityFeePerGas === undefined + ? {} + : { maxPriorityFeePerGas: p.maxPriorityFeePerGas }), + ...(p.deadline === undefined ? {} : { deadline: p.deadline }), + ...(p.feeLockTxHash === undefined + ? {} + : { feeLockTxHash: p.feeLockTxHash }), + }, + { ...options, progressHook: options?.progressHook ?? p.progressHook } + ); + } catch (error) { + const wrapped = wrapSendError(error) as AgenticError & { + decodedError?: unknown; + }; + emitAgentic( + runtime, + hook, + PROGRESS_HOOK.AGENTIC_TX_199_02, + 'sendTransaction', + wrapped.code ?? 'UNKNOWN', + wrapped.message, + wrapped.decodedError + ); + throw wrapped; + } + const result = adaptAgenticResponse(response, { + wallet, + door: actx.door, + rulesId, + chainNamespace: to.chain, + chain: to.chain, + route: 'UOA_TO_CEA', + ...(instruction + ? { + destinationAccount: cea, + destinationInstruction: { + program: instruction.recipient, + data: bytesToHex(instruction.instructionData), + accounts: instruction.accounts, + }, + } + : { destinationTransfer }), + logical: instruction + ? { + to: instruction.recipient, + data: bytesToHex(instruction.instructionData), + value: BigInt(0), + } + : { to: target, data: '0x', value: transferValue }, + }); + emitAgentic( + runtime, + hook, + PROGRESS_HOOK.AGENTIC_TX_199_01, + 'sendTransaction', + response.hash + ); + return result; +} diff --git a/packages/core/src/lib/agentic/execution/svm-quote.ts b/packages/core/src/lib/agentic/execution/svm-quote.ts new file mode 100644 index 00000000..f78fa563 --- /dev/null +++ b/packages/core/src/lib/agentic/execution/svm-quote.ts @@ -0,0 +1,51 @@ +import { PublicKey } from '@solana/web3.js'; +import { getAddress, hexToBytes, type Address } from 'viem'; +import type { CHAIN } from '../../constants/enums'; +import { + PRC20_SOURCE_ABI, + readGasPrc20, + readSvmSourceToken, +} from '../contracts/prc20-metadata'; +import type { AgenticRuntime } from '../runtime'; +import type { Snapshot } from '../reads/snapshot'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; + +/** Route/fee validation, independent of the selected rule's permissions. */ +export async function quoteSvmRequest( + runtime: AgenticRuntime, + snap: Snapshot, + wallet: Address, + token: Address, + chain: CHAIN, + gasLimit: bigint, + amount: bigint +) { + if ( + (await snap.read( + token, + PRC20_SOURCE_ABI, + 'SOURCE_CHAIN_NAMESPACE' + )) !== chain + ) { + throw new AgenticError( + AGENTIC_ERROR_CODE.ASSET_CHAIN_MISMATCH, + 'outbound asset belongs to another chain' + ); + } + const isNative = + getAddress(token) === getAddress(await readGasPrc20(snap, chain)); + const splMintBase58 = + !isNative && amount > BigInt(0) + ? new PublicKey( + hexToBytes( + await readSvmSourceToken(snap, token, chain, runtime.network) + ) + ).toBase58() + : undefined; + const quote = await runtime.quoteOutbound(token, gasLimit, chain, { + wallet, + splMintBase58, + burnAmount: amount, + }); + return { ...quote, isNative }; +} diff --git a/packages/core/src/lib/agentic/execution/svm-send.ts b/packages/core/src/lib/agentic/execution/svm-send.ts new file mode 100644 index 00000000..b28d80d7 --- /dev/null +++ b/packages/core/src/lib/agentic/execution/svm-send.ts @@ -0,0 +1,178 @@ +import { quoteSvmRequest } from './svm-quote'; +/** Prepared-wire agent execution used by the public Solana route. */ +import { getAddress, erc20Abi, type Address, type Hex } from 'viem'; +import { CHAIN } from '../../constants/enums'; +import type { AgenticGeneration } from '../deployments'; +import type { AgenticRuntime } from '../runtime'; +import { assertCanSign, wrapSendError } from '../management/common'; +import { Snapshot } from '../reads/snapshot'; +import { readSvmRule } from '../reads/svm'; +import { + resolveSvmContext, + type SvmMetadataProvider, +} from '../management/svm-context'; +import { buildAgwSvmAction } from './svm-outbound'; +import { resolveAgwSvmInstruction } from './svm-instruction'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; +import { verifySvmWallet } from '../management/svm'; +import type { SvmPayloadAccount } from './svm-payload'; + +export interface PreparedSvmRequest { + wallet: Address; + rulesId: Hex; + token: Address; + amount: bigint; + gasLimit: bigint; + program: string; + instructionData: Uint8Array; + /** Already-resolved wire accounts for non-Anchor/dataless programs. */ + accounts?: readonly SvmPayloadAccount[]; +} + +export async function prepareSvmAgentExecution( + runtime: AgenticRuntime, + gen: AgenticGeneration, + input: PreparedSvmRequest, + metadata: SvmMetadataProvider +) { + assertCanSign(runtime, 'internal SVM send'); + await verifySvmWallet(runtime, gen, input.wallet); + const snap = await Snapshot.at(runtime.reader); + const stored = await readSvmRule( + snap, + gen, + input.wallet, + input.rulesId, + runtime.pushChainNamespace + ); + if (getAddress(stored.agent) !== getAddress(runtime.signerPushAccount())) + throw new AgenticError( + AGENTIC_ERROR_CODE.NOT_OWNER_OR_AGENT, + 'signer is not this SVM rule agent' + ); + const chain = stored.chainNamespace as CHAIN; + const resolved = await resolveSvmContext( + snap, + input.wallet, + stored.chainNamespace, + stored.config.assets, + metadata + ); + if ( + resolved.expectedCEA.toLowerCase() !== + stored.config.expectedCEA.toLowerCase() || + resolved.gatewayProgram.toLowerCase() !== + stored.config.gatewayProgram.toLowerCase() || + resolved.ceaAccounts.some( + (a) => + !stored.config.ceaAccounts.some( + (b) => a.toLowerCase() === b.toLowerCase() + ) + ) + ) + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'stored SVM context does not cover the wallet and every asset' + ); + const instruction = resolveAgwSvmInstruction( + { + wallet: input.wallet, + chain, + program: input.program, + instructionData: input.instructionData, + accounts: input.accounts, + }, + stored.config + ); + const quote = await quoteSvmRequest( + runtime, + snap, + input.wallet, + getAddress(input.token), + chain, + input.gasLimit, + input.amount + ); + const call = buildAgwSvmAction({ + ...input, + gateway: gen.addresses.gateway, + recipient: instruction.recipient, + payload: instruction.payload, + gasLimit: quote.gasLimitUsed, + protocolFee: quote.protocolFee, + maxPCForGas: quote.nativeValueForGas, + }); + const walletPc = await runtime.reader.getBalance({ + address: input.wallet, + blockNumber: snap.blockNumber, + }); + if (walletPc < call.value) + throw new AgenticError( + AGENTIC_ERROR_CODE.WALLET_BALANCE_INSUFFICIENT, + 'wallet PC is below the SVM outbound quote' + ); + if (input.amount > BigInt(0)) { + const balance = await snap.read( + input.token, + erc20Abi, + 'balanceOf', + [input.wallet] + ); + if (balance < input.amount) + throw new AgenticError( + AGENTIC_ERROR_CODE.WALLET_BALANCE_INSUFFICIENT, + 'wallet token balance is below the SVM amount' + ); + const allowance = await snap.read( + input.token, + erc20Abi, + 'allowance', + [input.wallet, gen.addresses.gateway] + ); + if (allowance < input.amount) + throw new AgenticError( + AGENTIC_ERROR_CODE.GATEWAY_ALLOWANCE_INSUFFICIENT, + 'owner must establish the SVM gateway allowance separately' + ); + } + const signerPc = await runtime.signerBalance(); + const gasReserve = (await runtime.getGasPrice()) * BigInt(10_000_000); + if ((await runtime.signerAccountDeployed()) && signerPc < gasReserve) + throw new AgenticError( + AGENTIC_ERROR_CODE.AGENT_GAS_INSUFFICIENT, + 'deployed SVM agent identity has no Push gas balance' + ); + return { + stored, + call, + instruction, + quote, + data: gen.contracts.encodeExecuteAsAgent(input.rulesId, call), + }; +} + +export async function sendSvmAgentWire( + runtime: AgenticRuntime, + gen: AgenticGeneration, + input: PreparedSvmRequest, + metadata: SvmMetadataProvider +) { + const prepared = await prepareSvmAgentExecution( + runtime, + gen, + input, + metadata + ); + try { + const tx = await runtime.execute({ + to: input.wallet, + value: BigInt(0), + data: prepared.data, + }); + // Return the ordinary signer response and explicit wire context internally. + // The public wrapper applies the response presentation. + return { tx, context: prepared.stored, instruction: prepared.instruction }; + } catch (error) { + throw wrapSendError(error); + } +} diff --git a/packages/core/src/lib/agentic/index.ts b/packages/core/src/lib/agentic/index.ts new file mode 100644 index 00000000..0bfceff3 --- /dev/null +++ b/packages/core/src/lib/agentic/index.ts @@ -0,0 +1,33 @@ +export type { + AgenticAddress, + AgenticHex, + AgenticDoor, + AgenticNamespace, + AgenticProgressHook, + AgenticTxMetadata, + AgenticWallet, + AllowedCall, + AssetCap, + Checkpoint, + CheckpointKind, + CreateOptions, + CreateResult, + ForeignChainNamespace, + NativeRule, + SolanaRule, + DecodedSolanaRule, + SvmInstructionRule, + SvmAccountRef, + SvmFieldConstraint, + Rule, + RulesRecord, + Selector, + UniversalRule, + WalletInfo, + WalletSummary, +} from './agentic.types'; +export { AGENTIC_ERROR_CODE, AgenticError, AgenticRevertError } from './errors'; +export type { AgenticErrorCode } from './errors'; +export { AGENTIC } from './constants'; +export type { AgenticNetworkConstants } from './constants'; +export { agenticUtils } from './utils'; diff --git a/packages/core/src/lib/agentic/management/common.ts b/packages/core/src/lib/agentic/management/common.ts new file mode 100644 index 00000000..5a67bd01 --- /dev/null +++ b/packages/core/src/lib/agentic/management/common.ts @@ -0,0 +1,145 @@ +import { getAddress, type Address, type Hex, type Log } from 'viem'; +import type { MultiCall, UniversalTxResponse } from '../../orchestrator/orchestrator.types'; +import { + PushChainBatchExecutionError, + PushChainExecutionError, + type DecodedErrorPayload, +} from '../../orchestrator/internals/errors'; +import PROGRESS_HOOKS from '../../progress-hook/progress-hook'; +import { PROGRESS_HOOK } from '../../progress-hook/progress-hook.types'; +import type { AgenticGeneration } from '../deployments'; +import { AGENTIC_ERROR_CODE, AgenticError, AgenticRevertError } from '../errors'; +import type { AgenticRuntime } from '../runtime'; +import type { AgenticProgressHook } from '../agentic.types'; +import { Snapshot } from '../reads/snapshot'; +import { decodeAgenticRevert } from '../revert'; + +export function emitAgentic( + runtime: AgenticRuntime, + perCall: AgenticProgressHook | undefined, + id: PROGRESS_HOOK, + ...args: unknown[] +): void { + runtime.emit(PROGRESS_HOOKS[id](...args), perCall); +} + +export function assertCanSign(runtime: AgenticRuntime, operation: string): void { + if (runtime.isReadOnly) { + throw new AgenticError( + AGENTIC_ERROR_CODE.READ_ONLY, + `${operation} needs a signer; this client was initialized read-only` + ); + } +} + +/** Owner-only management writes: the connected signer's Push identity must be the stored owner. */ +export async function assertOwner( + runtime: AgenticRuntime, + gen: AgenticGeneration, + wallet: Address, + snap: Snapshot +): Promise
{ + const owner = getAddress(await snap.read
(wallet, gen.contracts.abis.wallet, 'owner')); + const signer = runtime.signerPushAccount(); + if (owner !== signer) { + throw new AgenticError( + AGENTIC_ERROR_CODE.NOT_WALLET_OWNER, + `${signer} is not the owner of ${wallet} (owner is ${owner})`, + { hint: 'Rule and label writes are owner-only. Initialize with the owner signer.' } + ); + } + return owner; +} + +/** + * Send owner calls through the signer's ordinary transaction path: one call + * as a plain transaction, several as the signer's batch (UEA multicall, + * EIP-7702 atomic batch, or the documented sequential fallback for a Push EOA + * without 7702 — reported through `atomic` / `transactionHashes`). + */ +export async function sendOwnerCalls( + runtime: AgenticRuntime, + calls: MultiCall[], + progressHook: AgenticProgressHook | undefined +): Promise { + if (calls.length === 0) throw new Error('sendOwnerCalls needs at least one call'); + const options = progressHook ? { progressHook } : undefined; + if (calls.length === 1) { + return runtime.execute({ to: calls[0].to, value: calls[0].value, data: calls[0].data }, options); + } + return runtime.execute({ to: calls[0].to, value: BigInt(0), data: calls }, options); +} + +/** + * Wait for every Push transaction the operation produced and return their + * logs in submission order. A reverted transaction raises AgenticRevertError + * carrying all hashes. + */ +export async function confirmedLogs( + runtime: AgenticRuntime, + tx: UniversalTxResponse +): Promise<{ logs: Log[]; hashes: Hex[] }> { + const hashes = (tx.transactionHashes ?? [tx.hash as Hex]) as Hex[]; + const unavailable = (cause: unknown) => + new AgenticError( + AGENTIC_ERROR_CODE.RECEIPT_UNAVAILABLE, + `submitted ${tx.hash} but could not read its receipt: ${cause instanceof Error ? cause.message : String(cause)}`, + { + hint: 'The transaction may still land. Check these hashes before retrying.', + details: { txHash: tx.hash, transactionHashes: hashes }, + cause, + } + ); + let receipt; + try { + receipt = await tx.wait(); + } catch (cause) { + throw unavailable(cause); + } + if (hashes.length === 1) { + if (receipt.status !== 1) { + throw new AgenticRevertError(`Push transaction ${tx.hash} reverted`, { + transactionHashes: hashes, + }); + } + return { logs: receipt.logs as Log[], hashes }; + } + const logs: Log[] = []; + for (const hash of hashes) { + let r; + try { + r = await runtime.reader.getTransactionReceipt({ hash }); + } catch (cause) { + throw unavailable(cause); + } + if (r.status !== 'success') { + throw new AgenticRevertError(`Push transaction ${hash} reverted`, { transactionHashes: hashes }); + } + logs.push(...(r.logs as Log[])); + } + return { logs, hashes }; +} + +/** Normalize a send failure: keep batch hashes and decoded revert data. */ +export function wrapSendError(err: unknown): unknown { + if (err instanceof AgenticError || err instanceof AgenticRevertError) return err; + const decoded = decodeAgenticRevert(err); + if (err instanceof PushChainBatchExecutionError) { + return new AgenticRevertError(err.message, { + decodedError: decoded ?? err.decodedError, + transactionHashes: err.transactionHashes, + pendingTransactionHash: err.pendingTransactionHash, + cause: err, + }); + } + if (decoded || err instanceof PushChainExecutionError) { + const e = err as { message?: string; gatewayTxHash?: string; decodedError?: DecodedErrorPayload }; + return new AgenticRevertError(e?.message ?? decoded?.name ?? 'AGW revert', { + decodedError: decoded ?? e?.decodedError, + gatewayTxHash: e?.gatewayTxHash, + agenticCode: decoded?.name, + cause: err, + }); + } + return err; +} diff --git a/packages/core/src/lib/agentic/management/create.ts b/packages/core/src/lib/agentic/management/create.ts new file mode 100644 index 00000000..3ed82950 --- /dev/null +++ b/packages/core/src/lib/agentic/management/create.ts @@ -0,0 +1,403 @@ +import { getAddress, type Address, type Hex, type Log } from 'viem'; +import { PROGRESS_HOOK } from '../../progress-hook/progress-hook.types'; +import type { MultiCall } from '../../orchestrator/orchestrator.types'; +import { PushChainBatchExecutionError } from '../../orchestrator/internals/errors'; +import { AgenticCapability, requireCapability } from '../capabilities'; +import { currentGeneration, verifyFactoryWiring } from '../deployments'; +import { deriveWallet, rulesId as computeRulesId } from '../codec/ids'; +import { prepareWalletRules } from './prepare'; +import { assertLabel } from './label'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; +import type { AgenticRuntime } from '../runtime'; +import type { CreateOptions, CreateResult } from '../agentic.types'; +import { Snapshot, scanLogs } from '../reads/snapshot'; +import { walletCount, walletInfo } from '../reads/wallets'; +import { + assertCanSign, + confirmedLogs, + emitAgentic, + sendOwnerCalls, + wrapSendError, +} from './common'; + +/** + * client.agentic.create(label, { rules }): deploy + grants only. Funding and + * approvals are separate ordinary sends. Every input is validated and every + * prediction re-read immediately before signing; IDs are returned from + * receipts in input order. + * + * Strategy follows the signer: an external owner's UEA batches atomically, a + * Push EOA uses an EIP-7702 batch when available and otherwise the documented + * sequential fallback. A sequential failure raises CREATE_PARTIAL with the + * deployed wallet, confirmed/pending hashes and granted IDs so the caller can + * finish with `wallet(w).rules.add(remaining)` — the SDK never deploys another + * wallet on its own. + */ +export async function createWallet( + runtime: AgenticRuntime, + label: string, + options: CreateOptions +): Promise { + const hook = options?.progressHook; + assertLabel(label); + if (!options || !Array.isArray(options.rules)) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'options.rules is required (use [] for a bare wallet)' + ); + } + assertCanSign(runtime, 'agentic.create'); + const gen = currentGeneration(runtime.network); + requireCapability(gen.capabilities, AgenticCapability.WALLET_READS); + await verifyFactoryWiring(runtime.reader, gen); + + const owner = runtime.signerPushAccount(); + const snap = await Snapshot.at(runtime.reader); + const index = await walletCount(snap, gen, owner); + const [predicted, deployed] = await snap.read( + gen.addresses.factory, + gen.contracts.abis.factory, + 'predictWallet', + [owner, index] + ); + const wallet = getAddress(predicted); + const mirror = deriveWallet({ + factory: gen.addresses.factory, + walletImplementation: gen.addresses.walletImplementation, + owner, + index, + }); + if (wallet !== mirror || deployed || (await snap.code(wallet))) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INDEX_RACE, + `next wallet slot ${index} for ${owner} is not a fresh counterfactual address`, + { details: { wallet, mirror, deployed } } + ); + } + const prepared = await prepareWalletRules( + runtime, + gen, + owner, + wallet, + options.rules, + snap + ); + const selfTarget = prepared.findIndex( + (p) => p.nativeTerms?.target === wallet + ); + if (selfTarget >= 0) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + `rules[${selfTarget}].target is the wallet being created; the contracts refuse it as a native target` + ); + } + emitAgentic( + runtime, + hook, + PROGRESS_HOOK.AGENTIC_TX_101, + wallet, + Number(index), + false + ); + + // A fresh wallet's grant nonce starts at 0 and increments per grant. + const predictedIds = prepared.map((p, i) => + computeRulesId({ + validator: gen.addresses.sessionValidator, + agent: p.agent, + grantNonce: BigInt(i), + }) + ); + const calls: MultiCall[] = [ + // Index-bound: reverts (nothing committed) if another creation took this slot. + { + to: gen.addresses.factory, + value: BigInt(0), + data: gen.contracts.encodeDeployWalletAt(owner, index, wallet, label), + }, + ...prepared.map((p) => ({ + to: wallet, + value: BigInt(0), + data: gen.contracts.encodeGrantRules(p.session), + })), + ]; + const strategy = + calls.length === 1 + ? 'single' + : runtime.signerIsPushNative() + ? 'push-eoa-batch' + : 'uea-multicall'; + emitAgentic(runtime, hook, PROGRESS_HOOK.AGENTIC_TX_102, wallet, strategy); + + let tx; + try { + tx = await sendOwnerCalls(runtime, calls, hook); + } catch (err) { + const wrapped = await createFailure( + runtime, + gen, + wallet, + Number(index), + owner, + label, + err + ); + emitFailure(runtime, hook, wrapped); + throw wrapped; + } + + let logs; + try { + ({ logs } = await confirmedLogs(runtime, tx)); + } catch (err) { + const wrapped = await createFailure( + runtime, + gen, + wallet, + Number(index), + owner, + label, + err + ); + emitFailure(runtime, hook, wrapped); + throw wrapped; + } + const deployedEv = gen.contracts.parseWalletDeployed( + logs, + gen.addresses.factory + ); + const granted = gen.contracts + .parseRulesGranted(logs, wallet) + .map((g) => g.rulesId); + if ( + deployedEv.length !== 1 || + deployedEv[0].wallet !== wallet || + deployedEv[0].index !== index + ) { + const err = new AgenticError( + AGENTIC_ERROR_CODE.INDEX_RACE, + `deployWallet produced ${ + deployedEv.map((d) => `${d.wallet}#${d.index}`).join(', ') || + 'no wallet' + }, expected ${wallet}#${index}; grants targeted ${wallet}`, + { + hint: 'Another deployment by this owner raced this call. Inspect both wallets with client.agentic.list() before retrying.', + details: { + expected: wallet, + deployed: deployedEv, + grantedRulesIds: granted, + txHash: tx.hash, + }, + } + ); + emitFailure(runtime, hook, err); + throw err; + } + if (!sameIds(granted, predictedIds)) { + const err = new AgenticError( + AGENTIC_ERROR_CODE.RECEIPT_MISMATCH, + 'RulesGranted events do not match the requested rules in order', + { details: { granted, predicted: predictedIds, txHash: tx.hash } } + ); + emitFailure(runtime, hook, err); + throw err; + } + if (granted.length > 0) + emitAgentic(runtime, hook, PROGRESS_HOOK.AGENTIC_TX_104, granted); + emitAgentic( + runtime, + hook, + PROGRESS_HOOK.AGENTIC_TX_199_01, + 'create', + tx.hash + ); + return { + wallet, + index: Number(index), + rulesIds: granted as `0x${string}`[], + tx, + }; +} + +function sameIds(a: readonly Hex[], b: readonly Hex[]): boolean { + return ( + a.length === b.length && + a.every((x, i) => x.toLowerCase() === b[i].toLowerCase()) + ); +} + +const RACE_ERRORS = new Set(['IndexMismatch', 'IntentWalletMismatch']); + +/** + * Turn a create failure into an exact report. What committed is derived from + * THIS operation's own receipts, never from a later state read; when those + * receipts cannot be fetched the outcome is reported as unknown so callers do + * not retry a creation that may have landed. + */ +async function createFailure( + runtime: AgenticRuntime, + gen: ReturnType, + wallet: Address, + index: number, + owner: Address, + label: string, + err: unknown +): Promise { + const wrapped = wrapSendError(err); + const batch = err instanceof PushChainBatchExecutionError ? err : undefined; + const confirmed = (batch?.transactionHashes ?? []) as Hex[]; + const pending = batch?.pendingTransactionHash; + const receiptUnavailable = + wrapped instanceof AgenticError && + wrapped.code === AGENTIC_ERROR_CODE.RECEIPT_UNAVAILABLE; + + // The index-bound deploy reverted: another creation took the slot first and + // nothing from this call committed. + const decodedName = (wrapped as { decodedError?: { name?: string } }) + .decodedError?.name; + if ( + confirmed.length === 0 && + !pending && + decodedName && + RACE_ERRORS.has(decodedName) + ) { + return new AgenticError( + AGENTIC_ERROR_CODE.INDEX_RACE, + `wallet slot ${index} (${wallet}) was taken by a concurrent creation; nothing was committed`, + { + hint: 'Retry agentic.create; it re-reads the next slot.', + details: { wallet, index, committed: false }, + cause: wrapped, + } + ); + } + if (confirmed.length === 0 && !pending && !receiptUnavailable) { + // Some send paths flatten the factory revert to a generic execution + // error, losing the IndexMismatch selector. If the owner's next index has + // moved and immutable deployment metadata proves another label owns the + // predicted slot, this call could not have deployed or granted. + try { + const snap = await Snapshot.at(runtime.reader); + const next = await walletCount(snap, gen, owner); + if (next > BigInt(index)) { + const competing = await walletInfo(runtime.reader, gen, wallet); + // label() is mutable in v5: only the immutable deploy event proves + // which creation occupied this slot. A later rename proves nothing. + const logs = await scanLogs( + runtime.reader, + { + address: gen.addresses.factory, + event: gen.contracts.events.walletDeployed, + args: { wallet }, + }, + gen.startBlock, + snap.blockNumber + ); + const deployed = gen.contracts + .parseWalletDeployed(logs, gen.addresses.factory) + .find((entry) => entry.wallet === wallet); + const competingLabel = deployed?.label; + if ( + competing.deployed && + competing.index === index && + getAddress(competing.owner) === owner && + competingLabel !== undefined && + competingLabel !== label + ) { + return new AgenticError( + AGENTIC_ERROR_CODE.INDEX_RACE, + 'wallet slot ' + index + ' was consumed by a concurrent deployment', + { + hint: + 'Slot ' + + index + + ' belongs to "' + + competingLabel + + '". No wallet or rules from this create call were committed; retry agentic.create to use the next slot.', + details: { + wallet, + index, + committed: false, + competingLabel, + }, + cause: wrapped, + } + ); + } + } + } catch { + // If the owner counter/event cannot be reconciled, preserve the original + // error; never infer that a retry is safe from an incomplete read. + } + // Nothing was confirmed (pre-broadcast failure or a reverted atomic batch). + return wrapped; + } + + let walletDeployed: boolean | 'unknown' = 'unknown'; + let grantedRulesIds: Hex[] | undefined; + let recoveryError: string | undefined; + if (!receiptUnavailable) { + try { + const logs: Log[] = []; + for (const hash of confirmed) { + const r = await runtime.reader.getTransactionReceipt({ hash }); + if (r.status === 'success') logs.push(...(r.logs as Log[])); + } + const deployed = gen.contracts + .parseWalletDeployed(logs, gen.addresses.factory) + .some((d) => d.wallet === wallet); + grantedRulesIds = gen.contracts + .parseRulesGranted(logs, wallet) + .map((g) => g.rulesId); + // A pending hash may itself be the deployment; only a confirmed deploy is certain. + walletDeployed = deployed ? true : pending ? 'unknown' : false; + } catch (e) { + recoveryError = e instanceof Error ? e.message : String(e); + } + } + const hint = + walletDeployed === true + ? `Wallet ${wallet} is deployed. Do not call create again; once any pending hash settles, finish with client.agentic.wallet('${wallet}').rules.add().` + : walletDeployed === false + ? 'No wallet was deployed by this call; it is safe to retry.' + : 'The outcome is unknown. Do not retry create until the listed hashes are reconciled (client.agentic.list() shows deployed wallets).'; + return new AgenticError( + AGENTIC_ERROR_CODE.CREATE_PARTIAL, + `agentic.create did not complete: ${ + (wrapped as Error)?.message ?? String(err) + }`, + { + hint, + details: { + wallet, + index, + walletDeployed, + grantedRulesIds, + confirmedHashes: confirmed, + pendingHash: pending, + ...(receiptUnavailable + ? { submitted: (wrapped as AgenticError).details } + : {}), + ...(recoveryError ? { recoveryError } : {}), + }, + cause: wrapped, + } + ); +} + +function emitFailure( + runtime: AgenticRuntime, + hook: CreateOptions['progressHook'], + err: unknown +): void { + const e = err as { code?: string; message?: string; decodedError?: unknown }; + emitAgentic( + runtime, + hook, + PROGRESS_HOOK.AGENTIC_TX_199_02, + 'create', + e?.code ?? 'UNKNOWN', + e?.message ?? String(err), + e?.decodedError + ); +} diff --git a/packages/core/src/lib/agentic/management/label.ts b/packages/core/src/lib/agentic/management/label.ts new file mode 100644 index 00000000..a63e2b30 --- /dev/null +++ b/packages/core/src/lib/agentic/management/label.ts @@ -0,0 +1,21 @@ +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; + +/** AGW MAX_LABEL_BYTES. Empty resets the default; lengths count UTF-8 bytes. */ +export const MAX_LABEL_BYTES = 64; + +export function assertLabel(label: string): void { + if (typeof label !== 'string') { + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'label must be a string' + ); + } + const length = new TextEncoder().encode(label).length; + if (length > MAX_LABEL_BYTES) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + `label must be at most ${MAX_LABEL_BYTES} UTF-8 bytes (received ${length})`, + { details: { length, maxLength: MAX_LABEL_BYTES } } + ); + } +} diff --git a/packages/core/src/lib/agentic/management/prepare.ts b/packages/core/src/lib/agentic/management/prepare.ts new file mode 100644 index 00000000..d2019629 --- /dev/null +++ b/packages/core/src/lib/agentic/management/prepare.ts @@ -0,0 +1,144 @@ +import { preparePublicSvmRule } from './svm-public'; +import type { SvmTermsWire } from '../codec/svm-terms'; +import { getAddress, zeroAddress, type Address } from 'viem'; +import { CHAIN, VM } from '../../constants/enums'; +import { CHAIN_INFO } from '../../constants/chain'; +import { AGENTIC_DEFAULTS, withDefault } from '../codec/defaults'; +import { isUniversalRule, isSolanaRule, prepareRules } from '../codec/rules'; +import { + validateUniversalRuleShape, + type ResolvedUniversalRule, +} from '../codec/universal'; +import { + forbiddenTargets, + verifyPolicyVersion, + type AgenticGeneration, +} from '../deployments'; +import { AgenticCapability, requireCapability } from '../capabilities'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; +import type { Rule, UniversalRule, SolanaRule } from '../agentic.types'; +import type { AgenticRuntime } from '../runtime'; +import { Snapshot } from '../reads/snapshot'; + +import { + PRC20_SOURCE_ABI, + readGasPrc20, + readOriginToken, +} from '../contracts/prc20-metadata'; + +/** Resolve wallet-dependent wire inputs without signing or mutating authority. */ +export async function prepareWalletRules( + runtime: AgenticRuntime, + gen: AgenticGeneration, + owner: Address, + wallet: Address, + rules: readonly Rule[], + snap: Snapshot +) { + if (rules.length) await verifyPolicyVersion(runtime.reader, gen); + const svm = new Map(); + const universal = new Map(); + for (const rule of rules) { + if (rule && isSolanaRule(rule)) { + requireCapability( + gen.capabilities, + AgenticCapability.UNIVERSAL_SVM_RULES + ); + svm.set(rule, await preparePublicSvmRule(runtime, snap, wallet, rule)); + continue; + } + if (!isUniversalRule(rule)) continue; + if (rule.chainNamespace.startsWith('solana:')) + requireCapability( + gen.capabilities, + AgenticCapability.UNIVERSAL_SVM_RULES + ); + validateUniversalRuleShape(rule, runtime.nowSeconds()); + requireCapability( + gen.capabilities, + rule.chainNamespace.startsWith('solana:') + ? AgenticCapability.UNIVERSAL_SVM_RULES + : AgenticCapability.UNIVERSAL_EVM_RULES + ); + const chain = rule.chainNamespace as CHAIN; + if (CHAIN_INFO[chain]?.vm !== VM.EVM) + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + `unsupported EVM rule chain ${chain}` + ); + const { cea } = await runtime.resolveCEA(wallet, chain); + const assets = rule.assets.length + ? rule.assets.map((a) => ({ + token: + typeof a.token === 'string' && getAddress(a.token) === zeroAddress + ? undefined + : a.token, + maxPerCall: a.maxPerCall, + maxTotal: withDefault( + a.maxTotal, + AGENTIC_DEFAULTS.universal.assetMaxTotal + ), + })) + : [{ token: undefined, maxPerCall: BigInt(0), maxTotal: BigInt(0) }]; + const resolved = []; + for (const asset of assets) { + const token = + asset.token === undefined + ? await readGasPrc20(snap, chain) + : runtime.resolvePrc20(asset.token, chain); + if (token === zeroAddress) + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + `no gas PRC20 registered for ${chain}` + ); + const namespace = await snap.read( + token, + PRC20_SOURCE_ABI, + 'SOURCE_CHAIN_NAMESPACE' + ); + if (namespace !== chain) + throw new AgenticError( + AGENTIC_ERROR_CODE.ASSET_CHAIN_MISMATCH, + `PRC20 ${token} belongs to ${namespace}, not ${chain}` + ); + if (asset.token !== undefined) { + const expected = + typeof asset.token === 'string' + ? getAddress(asset.token) + : getAddress(asset.token.address); + if (expected === zeroAddress) { + if ((await readGasPrc20(snap, chain)) !== getAddress(token)) + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'resolved token is not the registered native gas token' + ); + } else { + const source = await readOriginToken(snap, token, chain); + if (source !== expected) + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + `PRC20 ${token} represents ${source}, not requested token ${expected}` + ); + } + } + resolved.push({ + token: getAddress(token), + maxPerCall: asset.maxPerCall, + maxTotal: asset.maxTotal, + }); + } + universal.set(rule, { expectedCEA: getAddress(cea), assets: resolved }); + } + return prepareRules(rules, { + owner, + pushChainNamespace: runtime.pushChainNamespace, + validator: gen.addresses.sessionValidator, + rulesPolicy: gen.addresses.rulesPolicy, + gateway: gen.addresses.gateway, + capabilities: gen.capabilities, + nowSeconds: runtime.nowSeconds(), + forbiddenTargets: forbiddenTargets(gen, wallet), + universal, + svm, + }); +} diff --git a/packages/core/src/lib/agentic/management/rules-write.ts b/packages/core/src/lib/agentic/management/rules-write.ts new file mode 100644 index 00000000..96d5fcb7 --- /dev/null +++ b/packages/core/src/lib/agentic/management/rules-write.ts @@ -0,0 +1,451 @@ +import type { Address, Hex } from 'viem'; +import { PROGRESS_HOOK } from '../../progress-hook/progress-hook.types'; +import type { + MultiCall, + UniversalTxResponse, +} from '../../orchestrator/orchestrator.types'; +import { AgenticCapability, requireCapability } from '../capabilities'; +import { type AgenticGeneration } from '../deployments'; +import { rulesId as computeRulesId } from '../codec/ids'; +import { prepareWalletRules } from './prepare'; +import { assertLabel } from './label'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; +import type { AgenticRuntime } from '../runtime'; +import type { AgenticHex, AgenticProgressHook, Rule } from '../agentic.types'; +import { + readActiveRules, + readNativeSpend, + readUniversalSpend, +} from '../reads/rules'; +import { Snapshot } from '../reads/snapshot'; +import { + assertCanSign, + assertOwner, + confirmedLogs, + emitAgentic, + sendOwnerCalls, + wrapSendError, +} from './common'; + +const MODE_NATIVE = 1; + +async function finish( + runtime: AgenticRuntime, + hook: AgenticProgressHook | undefined, + operation: string, + run: () => Promise +): Promise { + try { + const result = await run(); + emitAgentic( + runtime, + hook, + PROGRESS_HOOK.AGENTIC_TX_199_01, + operation, + result.tx.hash + ); + return result; + } catch (err) { + const wrapped = wrapSendError(err) as { + code?: string; + message?: string; + decodedError?: unknown; + }; + emitAgentic( + runtime, + hook, + PROGRESS_HOOK.AGENTIC_TX_199_02, + operation, + wrapped?.code ?? 'UNKNOWN', + wrapped?.message ?? String(err), + wrapped?.decodedError + ); + throw wrapped; + } +} + +/** w.rules.add(rules): owner grants on an existing wallet, IDs in input order. */ +export async function addRules( + runtime: AgenticRuntime, + gen: AgenticGeneration, + wallet: Address, + rules: readonly Rule[], + hook?: AgenticProgressHook +): Promise<{ rulesIds: AgenticHex[]; tx: UniversalTxResponse }> { + assertCanSign(runtime, 'rules.add'); + if (!Array.isArray(rules) || rules.length === 0) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'rules.add needs at least one rule' + ); + } + const snap = await Snapshot.at(runtime.reader); + const owner = await assertOwner(runtime, gen, wallet, snap); + const prepared = await prepareWalletRules( + runtime, + gen, + owner, + wallet, + rules, + snap + ); + const nonce = BigInt( + await snap.read(wallet, gen.contracts.abis.wallet, 'grantNonce') + ); + const predicted = prepared.map((p, i) => + computeRulesId({ + validator: gen.addresses.sessionValidator, + agent: p.agent, + grantNonce: nonce + BigInt(i), + }) + ); + // One rule: a direct owner grant (one RULES_GRANTED tick). Several: one + // owner `execute` batch of self-calls, so the grants are atomic and need a + // single signature on every signer type (each grant then also ticks one + // OWNER_ACTION before its RULES_GRANTED). + const grants = prepared.map((p) => gen.contracts.encodeGrantRules(p.session)); + const calls: MultiCall[] = + grants.length === 1 + ? [{ to: wallet, value: BigInt(0), data: grants[0] }] + : [ + { + to: wallet, + value: BigInt(0), + data: gen.contracts.encodeExecute( + grants.map((data) => ({ target: wallet, value: BigInt(0), data })) + ), + }, + ]; + return finish(runtime, hook, 'rules.add', async () => { + const tx = await sendOwnerCalls(runtime, calls, hook); + const { logs } = await confirmedLogs(runtime, tx); + const granted = gen.contracts + .parseRulesGranted(logs, wallet) + .map((g) => g.rulesId as AgenticHex); + if (!sameIds(granted, predicted)) { + throw new AgenticError( + AGENTIC_ERROR_CODE.RECEIPT_MISMATCH, + 'RulesGranted events do not match the requested rules in order (a concurrent grant may have raced)', + { details: { granted, predicted, txHash: tx.hash } } + ); + } + emitAgentic(runtime, hook, PROGRESS_HOOK.AGENTIC_TX_104, granted); + return { rulesIds: granted, tx }; + }); +} + +/** Bare revoke (no IDs, empty list, or anything but { all: true }) is refused. */ +export function assertRevokeTarget(target: unknown): { + all: boolean; + ids?: AgenticHex[]; +} { + const all = + !!target && + !Array.isArray(target) && + (target as { all?: unknown }).all === true; + const ids = Array.isArray(target) ? (target as AgenticHex[]) : undefined; + if (!all && (!ids || ids.length === 0)) { + throw new AgenticError( + AGENTIC_ERROR_CODE.REVOKE_NEEDS_TARGET, + 'rules.revoke needs explicit rule IDs or { all: true }', + { + hint: 'A bare revoke that wipes every rule is too easy to make by mistake.', + } + ); + } + return { all, ids }; +} + +/** w.rules.revoke(ids) / w.rules.revoke({ all: true }). Bare revoke is refused. */ +export async function revokeRules( + runtime: AgenticRuntime, + gen: AgenticGeneration, + wallet: Address, + target: + | AgenticHex[] + | { all: true; progressHook?: AgenticProgressHook } + | undefined, + hook?: AgenticProgressHook +): Promise { + const { all, ids } = assertRevokeTarget(target); + if (all) + hook = + (target as { progressHook?: AgenticProgressHook }).progressHook ?? hook; + assertCanSign(runtime, 'rules.revoke'); + const snap = await Snapshot.at(runtime.reader); + await assertOwner(runtime, gen, wallet, snap); + + let calls: MultiCall[]; + if (all) { + calls = [ + { + to: wallet, + value: BigInt(0), + data: gen.contracts.encodeRevokeAllRules(), + }, + ]; + } else { + const unique = new Set((ids as Hex[]).map((i) => i.toLowerCase())); + if (unique.size !== (ids as Hex[]).length) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'rules.revoke got the same rule ID twice' + ); + } + for (const id of ids as Hex[]) { + const enabled = await snap.read( + gen.addresses.sessionEngine, + gen.contracts.abis.engine, + 'isPermissionEnabled', + [id, wallet] + ); + if (!enabled) { + throw new AgenticError( + AGENTIC_ERROR_CODE.RULE_NOT_FOUND, + `rule ${id} is not enabled on ${wallet}` + ); + } + } + // Several IDs go through one owner `execute` batch so revocation is atomic + // regardless of signer batching support. + calls = + (ids as Hex[]).length === 1 + ? [ + { + to: wallet, + value: BigInt(0), + data: gen.contracts.encodeRevokeRules((ids as Hex[])[0]), + }, + ] + : [ + { + to: wallet, + value: BigInt(0), + data: gen.contracts.encodeExecute( + (ids as Hex[]).map((id) => ({ + target: wallet, + value: BigInt(0), + data: gen.contracts.encodeRevokeRules(id), + })) + ), + }, + ]; + } + const result = await finish(runtime, hook, 'rules.revoke', async () => { + const tx = await sendOwnerCalls(runtime, calls, hook); + const { logs } = await confirmedLogs(runtime, tx); + const revoked = gen.contracts + .parseRulesRevoked(logs, wallet) + .map((r) => r.rulesId); + emitAgentic( + runtime, + hook, + PROGRESS_HOOK.AGENTIC_TX_105, + all ? { all: true } : { rulesIds: revoked } + ); + return { tx }; + }); + return result.tx; +} + +/** + * w.rules.update({ rules: [{ rulesId, rule }] }): for every pair, inside ONE + * owner `execute` batch: assertSpent(expected) → revokeRules(old) → + * grantRules(new). Never falls back to sequential sends. An agent spending + * between the read and inclusion makes the whole batch revert; retry needs a + * fresh read and a new owner signature. New counters start at zero. + */ +export async function updateRules( + runtime: AgenticRuntime, + gen: AgenticGeneration, + wallet: Address, + params: { + rules: { rulesId: AgenticHex; rule: Rule }[]; + progressHook?: AgenticProgressHook; + } +): Promise<{ + rules: { rulesId: AgenticHex; replaced: AgenticHex }[]; + tx: UniversalTxResponse; +}> { + const hook = params?.progressHook; + assertCanSign(runtime, 'rules.update'); + if (!params || !Array.isArray(params.rules) || params.rules.length === 0) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'rules.update needs at least one { rulesId, rule } pair' + ); + } + requireCapability(gen.capabilities, AgenticCapability.OWNER_EXECUTE); + const oldIds = params.rules.map((p) => p.rulesId.toLowerCase()); + if (new Set(oldIds).size !== oldIds.length) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'rules.update names the same old rule twice' + ); + } + + const snap = await Snapshot.at(runtime.reader); + const owner = await assertOwner(runtime, gen, wallet, snap); + const active = await readActiveRules(snap, gen, wallet); + const byId = new Map(active.map((r) => [r.rulesId.toLowerCase(), r])); + + const assertions: { configId: Hex; data: Hex }[][] = []; + for (const pair of params.rules) { + const old = byId.get(pair.rulesId.toLowerCase()); + if (!old) + throw new AgenticError( + AGENTIC_ERROR_CODE.RULE_NOT_FOUND, + `rule ${pair.rulesId} is not enabled on ${wallet}` + ); + if (old.mode === MODE_NATIVE) { + requireCapability( + gen.capabilities, + AgenticCapability.ASSERT_SPENT_NATIVE + ); + const guards = []; + for (const action of old.actionIds) { + const spend = await readNativeSpend(snap, gen, wallet, old, action); + guards.push({ + configId: spend.configId, + data: gen.contracts.encodeAssertSpentNative( + spend.configId, + wallet, + spend + ), + }); + } + assertions.push(guards); + } else { + requireCapability( + gen.capabilities, + AgenticCapability.ASSERT_SPENT_UNIVERSAL_MULTI + ); + const spend = await readUniversalSpend(snap, gen, wallet, old); + assertions.push([ + { + configId: spend.configId, + data: gen.contracts.encodeAssertSpentUniversal( + spend.configId, + wallet, + spend.expectedSpent + ), + }, + ]); + } + } + const prepared = await prepareWalletRules( + runtime, + gen, + owner, + wallet, + params.rules.map((p) => p.rule), + snap + ); + const nonce = BigInt( + await snap.read(wallet, gen.contracts.abis.wallet, 'grantNonce') + ); + const predicted = prepared.map((p, i) => + computeRulesId({ + validator: gen.addresses.sessionValidator, + agent: p.agent, + grantNonce: nonce + BigInt(i), + }) + ); + + const batch = params.rules.flatMap((pair, i) => [ + ...assertions[i].map((a) => ({ + target: gen.addresses.rulesPolicy, + value: BigInt(0), + data: a.data, + })), + { + target: wallet, + value: BigInt(0), + data: gen.contracts.encodeRevokeRules(pair.rulesId), + }, + { + target: wallet, + value: BigInt(0), + data: gen.contracts.encodeGrantRules(prepared[i].session), + }, + ]); + const call: MultiCall = { + to: wallet, + value: BigInt(0), + data: gen.contracts.encodeExecute(batch), + }; + + return finish(runtime, hook, 'rules.update', async () => { + const tx = await sendOwnerCalls(runtime, [call], hook); + const { logs } = await confirmedLogs(runtime, tx); + const granted = gen.contracts + .parseRulesGranted(logs, wallet) + .map((g) => g.rulesId as AgenticHex); + const revoked = gen.contracts + .parseRulesRevoked(logs, wallet) + .map((r) => r.rulesId.toLowerCase()); + if ( + !sameIds(granted, predicted) || + !sameIds(revoked as Hex[], oldIds as Hex[]) + ) { + throw new AgenticError( + AGENTIC_ERROR_CODE.RECEIPT_MISMATCH, + 'rules.update receipt does not show the expected revoke/grant pairs', + { details: { granted, predicted, revoked, txHash: tx.hash } } + ); + } + emitAgentic(runtime, hook, PROGRESS_HOOK.AGENTIC_TX_105, { + rulesIds: params.rules.map((p) => p.rulesId), + }); + emitAgentic(runtime, hook, PROGRESS_HOOK.AGENTIC_TX_104, granted); + return { + tx, + rules: granted.map((id, i) => ({ + rulesId: id, + replaced: params.rules[i].rulesId, + })), + }; + }); +} + +function sameIds(a: readonly Hex[], b: readonly Hex[]): boolean { + return ( + a.length === b.length && + a.every((x, i) => x.toLowerCase() === b[i].toLowerCase()) + ); +} + +/** Owner rename through the owner door; empty resets the default label. */ +export async function setLabel( + runtime: AgenticRuntime, + gen: AgenticGeneration, + wallet: Address, + label: string, + hook?: AgenticProgressHook +): Promise { + assertLabel(label); + assertCanSign(runtime, 'setLabel'); + requireCapability(gen.capabilities, AgenticCapability.SET_LABEL); + return finish(runtime, hook, 'setLabel', async () => { + await assertOwner(runtime, gen, wallet, await Snapshot.at(runtime.reader)); + const tx = await sendOwnerCalls( + runtime, + [ + { + to: wallet, + value: BigInt(0), + data: gen.contracts.encodeExecute([ + { + target: wallet, + value: BigInt(0), + data: gen.contracts.encodeSetLabel(label), + }, + ]), + }, + ], + hook + ); + await confirmedLogs(runtime, tx); + return { tx }; + }).then(({ tx }) => tx); +} diff --git a/packages/core/src/lib/agentic/management/svm-context.ts b/packages/core/src/lib/agentic/management/svm-context.ts new file mode 100644 index 00000000..2187712c --- /dev/null +++ b/packages/core/src/lib/agentic/management/svm-context.ts @@ -0,0 +1,115 @@ +/** Internal resolved context; no public Rule schema or cluster assumptions. */ +import { getAddress, type Address, type Hex } from 'viem'; +import { PUSH_NETWORK } from '../../constants/enums'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; +import { + PRC20_SOURCE_ABI, + readGasPrc20, + readSvmSourceToken, +} from '../contracts/prc20-metadata'; +import { + svmKey, + resolveAgwSvmRuleContext, + type SvmTokenAccountInput, + type ResolvedSvmAsset, +} from '../codec/svm-accounts'; +import type { AssetCapWire } from '../codec/universal-terms'; +import type { Snapshot } from '../reads/snapshot'; + +export interface SvmMetadataProvider { + /** Must identify the requested full CAIP-2 cluster; no global gateway default. */ + gateway( + chainNamespace: `solana:${string}` + ): Promise<{ chainNamespace: string; program: string }>; + /** RPC-backed mint owner (legacy SPL or Token-2022), not an assumed default. */ + mint( + chainNamespace: `solana:${string}`, + address: Hex + ): Promise<{ mint: string; tokenProgram: string }>; +} + +const ZERO_KEY = `0x${'00'.repeat(32)}` as Hex; + +export async function resolveSvmAssets( + snap: Snapshot, + chain: `solana:${string}`, + caps: readonly AssetCapWire[], + metadata: SvmMetadataProvider, + network: PUSH_NETWORK = PUSH_NETWORK.TESTNET_DONUT +): Promise { + const gas = await readGasPrc20(snap, chain); + const out: ResolvedSvmAsset[] = []; + for (const cap of caps) { + const token = getAddress(cap.token); + const namespace = await snap.read( + token, + PRC20_SOURCE_ABI, + 'SOURCE_CHAIN_NAMESPACE' + ); + if (namespace !== chain) + throw new AgenticError( + AGENTIC_ERROR_CODE.ASSET_CHAIN_MISMATCH, + `PRC20 ${token} belongs to ${namespace}, not ${chain}` + ); + const source = await readSvmSourceToken(snap, token, chain, network); + const native = source === ZERO_KEY; + if (native) { + if (token !== gas) + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'native marker is not the registered gas PRC20' + ); + out.push({ kind: 'native', cap: { ...cap, token } }); + } else { + const key = svmKey(source); + const mint = await metadata.mint(chain, key); + if (svmKey(mint.mint) !== key) + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'mint resolver returned a different mint' + ); + out.push({ kind: 'spl', cap: { ...cap, token }, ...mint }); + } + } + return out; +} + +export async function resolveSvmContext( + snap: Snapshot, + wallet: Address, + chain: `solana:${string}`, + caps: readonly AssetCapWire[], + metadata: SvmMetadataProvider, + outputs: readonly SvmTokenAccountInput[] = [], + network: PUSH_NETWORK = PUSH_NETWORK.TESTNET_DONUT +) { + const gateway = await metadata.gateway(chain); + if (gateway.chainNamespace !== chain) + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'gateway registry cluster mismatch' + ); + const assets = await resolveSvmAssets(snap, chain, caps, metadata, network); + const resolvedOutputs = []; + for (const output of outputs) { + const key = svmKey(output.mint); + const resolved = await metadata.mint(chain, key); + if ( + svmKey(resolved.mint) !== key || + (output.tokenProgram && + svmKey(output.tokenProgram) !== svmKey(resolved.tokenProgram)) + ) + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'output mint/token-program mismatch' + ); + resolvedOutputs.push(resolved); + } + // Derivation validates token programs and covers every mint/output. + return resolveAgwSvmRuleContext( + wallet, + gateway.program, + assets, + resolvedOutputs + ); +} diff --git a/packages/core/src/lib/agentic/management/svm-metadata.ts b/packages/core/src/lib/agentic/management/svm-metadata.ts new file mode 100644 index 00000000..82aa0bef --- /dev/null +++ b/packages/core/src/lib/agentic/management/svm-metadata.ts @@ -0,0 +1,75 @@ +import { Connection, PublicKey } from '@solana/web3.js'; +import { svmKey } from '../codec/svm-accounts'; +import { svmInvalid } from '../codec/svm-terms'; +import type { SvmMetadataProvider } from './svm-context'; +import { AgenticError, AGENTIC_ERROR_CODE } from '../errors'; + +export interface SvmClusterConfig { + gatewayProgram: string; + rpcUrls: readonly string[]; +} +type MintRpc = Pick; +const SPL = 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'; +const TOKEN_2022 = 'TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb'; + +/** Explicit cluster configuration; HTTP reads only, no signing/subscriptions. */ +export function createSvmMetadataProvider( + clusters: Readonly>>, + connect: (url: string) => MintRpc = (url) => new Connection(url, 'confirmed') +): SvmMetadataProvider { + function config(chain: `solana:${string}`) { + const c = clusters[chain]; + if (!c || !c.rpcUrls.length) + throw svmInvalid(`no SVM registry/RPC configuration for ${chain}`); + svmKey(c.gatewayProgram); + return c; + } + async function read( + chain: `solana:${string}`, + fn: (rpc: MintRpc) => Promise + ): Promise { + const c = config(chain); + let last: unknown; + for (const url of c.rpcUrls) { + try { + const rpc = connect(url); + // CAIP-2 Solana references are the first 32 characters of genesisHash. + if (`solana:${(await rpc.getGenesisHash()).slice(0, 32)}` !== chain) + throw svmInvalid('SVM RPC genesis/cluster mismatch'); + return await fn(rpc); + } catch (error) { + last = error; + } + } + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + `SVM metadata lookup failed for ${chain}`, + { cause: last } + ); + } + return { + gateway: async (chain) => + read(chain, async () => ({ + chainNamespace: chain, + program: config(chain).gatewayProgram, + })), + mint: async (chain, address) => + read(chain, async (rpc) => { + const mint = new PublicKey( + Buffer.from(svmKey(address).slice(2), 'hex') + ); + const info = await rpc.getAccountInfo(mint, 'confirmed'); + if (!info || info.executable) + throw svmInvalid('mint account missing or executable'); + const owner = info.owner.toBase58(), + data = info.data; + const legacy = owner === SPL && data.length === 82; + const extended = + owner === TOKEN_2022 && + (data.length === 82 || (data.length >= 166 && data[165] === 1)); + if ((!legacy && !extended) || data[45] !== 1) + throw svmInvalid('account is not an initialized supported SPL mint'); + return { mint: mint.toBase58(), tokenProgram: owner }; + }), + }; +} diff --git a/packages/core/src/lib/agentic/management/svm-public.ts b/packages/core/src/lib/agentic/management/svm-public.ts new file mode 100644 index 00000000..f74d996b --- /dev/null +++ b/packages/core/src/lib/agentic/management/svm-public.ts @@ -0,0 +1,121 @@ +import { PublicKey } from '@solana/web3.js'; +import { getAddress, hexToBytes, zeroAddress } from 'viem'; +import type { Address, Hex } from 'viem'; +import { CHAIN, VM } from '../../constants/enums'; +import { CHAIN_INFO } from '../../constants/chain'; +import type { SolanaRule } from '../agentic.types'; +import type { AgenticRuntime } from '../runtime'; +import type { Snapshot } from '../reads/snapshot'; +import { readGasPrc20 } from '../contracts/prc20-metadata'; +import { resolveSvmContext } from './svm-context'; +import { createSvmMetadataProvider } from './svm-metadata'; +import { deriveAgwSvmAta, svmKey } from '../codec/svm-accounts'; +import { compileSvmIdlRule } from '../codec/svm-idl'; +import { svmInvalid } from '../codec/svm-terms'; +import { UINT256_MAX } from '../codec/defaults'; + +export function svmMetadata(runtime: AgenticRuntime) { + return ( + runtime.svmMetadata ?? + createSvmMetadataProvider({ + [CHAIN.SOLANA_DEVNET]: { + gatewayProgram: CHAIN_INFO[CHAIN.SOLANA_DEVNET].lockerContract ?? '', + rpcUrls: CHAIN_INFO[CHAIN.SOLANA_DEVNET].defaultRPC, + }, + }) + ); +} +export async function preparePublicSvmRule( + runtime: AgenticRuntime, + snap: Snapshot, + wallet: Address, + rule: SolanaRule +) { + const chain = rule.chainNamespace as CHAIN; + if (CHAIN_INFO[chain]?.vm !== VM.SVM) + throw svmInvalid('unknown Solana chain'); + if (!Array.isArray(rule.assets) || rule.assets.length > 8) + throw svmInvalid('assets must contain at most eight entries'); + if (rule.outputTokens !== undefined && !Array.isArray(rule.outputTokens)) + throw svmInvalid('outputTokens must be an array of mint addresses'); + const metadata = svmMetadata(runtime); + const requested = rule.assets.length + ? rule.assets + : [{ token: zeroAddress, maxPerCall: BigInt(0), maxTotal: BigInt(0) }]; + const caps: { token: Address; maxPerCall: bigint; maxTotal: bigint }[] = []; + const tokenAccounts = new Map(), + mints = new Set(); + const sources: { key?: Hex; token: Address }[] = []; + for (const asset of requested) { + const source = + typeof asset.token === 'string' ? asset.token : asset.token?.address; + if (typeof source !== 'string') + throw svmInvalid('asset token requires an address'); + if ( + typeof asset.token !== 'string' && + 'chain' in asset.token && + asset.token.chain !== chain + ) + throw svmInvalid('asset token belongs to another chain'); + const native = + source === zeroAddress || + /^0x0{64}$/.test(source) || + source === '11111111111111111111111111111111'; + const key = native ? undefined : svmKey(source); + const sourceToken = + typeof asset.token === 'string' && key + ? new PublicKey(hexToBytes(key)).toBase58() + : asset.token; + const token = native + ? await readGasPrc20(snap, chain) + : runtime.resolvePrc20(sourceToken, chain); + if (caps.some((c) => c.token === getAddress(token))) + throw svmInvalid('duplicate SVM asset'); + caps.push({ + token: getAddress(token), + maxPerCall: asset.maxPerCall, + maxTotal: asset.maxTotal ?? UINT256_MAX, + }); + sources.push({ key, token }); + if (key) mints.add(key); + } + const outputs = (rule.outputTokens ?? []).map((mint) => ({ mint })); + outputs.forEach((o) => mints.add(svmKey(o.mint))); + const ctx = await resolveSvmContext( + snap, + wallet, + rule.chainNamespace, + caps, + metadata, + outputs, + runtime.network + ); + // Validate the PRC20 actually represents the requested source mint, not merely its chain. + const { resolveSvmAssets } = await import('./svm-context'); + const resolved = await resolveSvmAssets( + snap, + rule.chainNamespace, + caps, + metadata, + runtime.network + ); + resolved.forEach((a, i) => { + if ( + sources[i].key + ? a.kind !== 'spl' || svmKey(a.mint) !== sources[i].key + : a.kind !== 'native' + ) + throw svmInvalid('PRC20 source does not match requested asset'); + }); + for (const mint of mints) { + const token = await metadata.mint(rule.chainNamespace, mint); + if (svmKey(token.mint) !== mint) + throw svmInvalid('mint resolver returned another mint'); + tokenAccounts.set(mint, deriveAgwSvmAta(ctx.expectedCEA, token)); + } + return compileSvmIdlRule( + rule, + { ...ctx, tokenAccounts }, + runtime.nowSeconds() + ); +} diff --git a/packages/core/src/lib/agentic/management/svm.ts b/packages/core/src/lib/agentic/management/svm.ts new file mode 100644 index 00000000..685b661a --- /dev/null +++ b/packages/core/src/lib/agentic/management/svm.ts @@ -0,0 +1,254 @@ +/** Internal explicit-wire operations. Not exported by the SDK entry point. */ +import { getAddress, type Address, type Hex } from 'viem'; +import type { AgenticRuntime } from '../runtime'; +import { + resolveWalletGeneration, + verifyPolicyVersion, + type AgenticGeneration, +} from '../deployments'; +import { Snapshot } from '../reads/snapshot'; +import { readSvmRule } from '../reads/svm'; +import { + assertCanSign, + assertOwner, + confirmedLogs, + wrapSendError, +} from './common'; +import { encodeSvmTerms, type SvmTermsWire } from '../codec/svm-terms'; +import { buildSession, encodeEnvelope } from '../codec/session'; +import { rulesId as predictRulesId } from '../codec/ids'; +import { SEND_OUTBOUND_SELECTOR } from '../contracts/v5'; +import { deriveAgwSvmCea } from '../codec/svm-accounts'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; +import { PRC20_SOURCE_ABI } from '../contracts/prc20-metadata'; + +async function verifyAssets(snap: Snapshot, input: SvmWireGrant) { + if (!/^solana:[1-9A-HJ-NP-Za-km-z]{32}$/.test(input.chainNamespace)) + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'SVM chain must be a full Solana CAIP-2 namespace' + ); + for (const cap of input.terms.assets) { + if ( + (await snap.read( + cap.token, + PRC20_SOURCE_ABI, + 'SOURCE_CHAIN_NAMESPACE' + )) !== input.chainNamespace + ) + throw new AgenticError( + AGENTIC_ERROR_CODE.ASSET_CHAIN_MISMATCH, + 'SVM asset source-chain mismatch' + ); + } +} + +export interface SvmWireGrant { + agent: Address; + chainNamespace: `solana:${string}`; + terms: SvmTermsWire; +} + +export async function verifySvmWallet( + runtime: AgenticRuntime, + gen: AgenticGeneration, + wallet: Address +) { + const actual = await resolveWalletGeneration( + runtime.reader, + runtime.network, + wallet + ); + if (actual.addresses.factory !== gen.addresses.factory) + throw new AgenticError( + AGENTIC_ERROR_CODE.GENERATION_UNSUPPORTED, + 'SVM wallet generation mismatch' + ); + await verifyPolicyVersion(runtime.reader, gen); +} + +function session( + gen: AgenticGeneration, + wallet: Address, + owner: Address, + input: SvmWireGrant, + now: number +) { + const agent = getAddress(input.agent); + if (agent === owner) + throw new AgenticError( + AGENTIC_ERROR_CODE.AGENT_IS_OWNER, + 'agent must differ from owner' + ); + const cea = deriveAgwSvmCea(wallet, input.terms.gatewayProgram).address; + if (cea.toLowerCase() !== input.terms.expectedCEA.toLowerCase()) + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'SVM expectedCEA does not belong to this wallet/gateway' + ); + return buildSession({ + validator: gen.addresses.sessionValidator, + rulesPolicy: gen.addresses.rulesPolicy, + agent, + actions: [ + { + target: gen.addresses.gateway, + selector: SEND_OUTBOUND_SELECTOR, + initData: encodeEnvelope( + input.chainNamespace, + encodeSvmTerms(input.terms, now) + ), + }, + ], + }); +} + +export async function grantSvmWire( + runtime: AgenticRuntime, + gen: AgenticGeneration, + wallet: Address, + input: SvmWireGrant +) { + assertCanSign(runtime, 'internal SVM grant'); + await verifySvmWallet(runtime, gen, wallet); + const snap = await Snapshot.at(runtime.reader); + const owner = await assertOwner(runtime, gen, wallet, snap); + await verifyAssets(snap, input); + const s = session(gen, wallet, owner, input, runtime.nowSeconds()); + const nonce = await snap.read( + wallet, + gen.contracts.abis.wallet, + 'grantNonce' + ); + const expected = predictRulesId({ + validator: gen.addresses.sessionValidator, + agent: getAddress(input.agent), + grantNonce: nonce, + }); + let tx; + try { + tx = await runtime.execute({ + to: wallet, + value: BigInt(0), + data: gen.contracts.encodeGrantRules(s), + }); + } catch (error) { + throw wrapSendError(error); + } + const { logs } = await confirmedLogs(runtime, tx); + const granted = gen.contracts.parseRulesGranted(logs, wallet); + if ( + granted.length !== 1 || + granted[0].mode !== 0 || + granted[0].chainNamespace !== input.chainNamespace + ) + throw new AgenticError( + AGENTIC_ERROR_CODE.RECEIPT_MISMATCH, + 'SVM grant receipt did not match this operation', + { details: { txHash: tx.hash, expected } } + ); + // Another owner grant can advance grantNonce between read and inclusion. + // The sole matching event from this receipt is the authoritative ID. + return { rulesId: granted[0].rulesId, tx }; +} + +/** Snapshot -> all-asset assertion -> revoke -> grant. No sequential fallback. */ +export async function prepareSvmReplacement( + runtime: AgenticRuntime, + gen: AgenticGeneration, + wallet: Address, + oldId: Hex, + input: SvmWireGrant +) { + assertCanSign(runtime, 'internal SVM replacement'); + await verifySvmWallet(runtime, gen, wallet); + const snap = await Snapshot.at(runtime.reader); + const owner = await assertOwner(runtime, gen, wallet, snap); + await verifyAssets(snap, input); + const old = await readSvmRule( + snap, + gen, + wallet, + oldId, + runtime.pushChainNamespace + ); + const s = session(gen, wallet, owner, input, runtime.nowSeconds()); + const nonce = await snap.read( + wallet, + gen.contracts.abis.wallet, + 'grantNonce' + ); + const rulesId = predictRulesId({ + validator: gen.addresses.sessionValidator, + agent: getAddress(input.agent), + grantNonce: nonce, + }); + const calls = [ + { + target: gen.addresses.rulesPolicy, + value: BigInt(0), + data: gen.contracts.encodeAssertSpentUniversal( + old.configId, + wallet, + old.config.assets.map((a) => a.spent) + ), + }, + { + target: wallet, + value: BigInt(0), + data: gen.contracts.encodeRevokeRules(oldId), + }, + { + target: wallet, + value: BigInt(0), + data: gen.contracts.encodeGrantRules(s), + }, + ]; + return { + rulesId, + oldId, + snapshotBlock: snap.blockNumber, + data: gen.contracts.encodeExecute(calls), + }; +} + +export async function replaceSvmWire( + runtime: AgenticRuntime, + gen: AgenticGeneration, + wallet: Address, + oldId: Hex, + input: SvmWireGrant +) { + const prepared = await prepareSvmReplacement( + runtime, + gen, + wallet, + oldId, + input + ); + let tx; + try { + tx = await runtime.execute({ + to: wallet, + value: BigInt(0), + data: prepared.data, + }); + } catch (error) { + throw wrapSendError(error); + } + const { logs } = await confirmedLogs(runtime, tx); + const grants = gen.contracts.parseRulesGranted(logs, wallet); + const revokes = gen.contracts.parseRulesRevoked(logs, wallet); + if ( + grants.length !== 1 || + grants[0].mode !== 0 || + grants[0].chainNamespace !== input.chainNamespace || + !revokes.some((r) => r.rulesId.toLowerCase() === oldId.toLowerCase()) + ) + throw new AgenticError( + AGENTIC_ERROR_CODE.RECEIPT_MISMATCH, + 'SVM replacement receipt mismatch', + { details: { txHash: tx.hash } } + ); + return { rulesId: grants[0].rulesId, replaced: oldId, tx }; +} diff --git a/packages/core/src/lib/agentic/reads/checkpoints.ts b/packages/core/src/lib/agentic/reads/checkpoints.ts new file mode 100644 index 00000000..71381920 --- /dev/null +++ b/packages/core/src/lib/agentic/reads/checkpoints.ts @@ -0,0 +1,85 @@ +import type { Address } from 'viem'; +import { AgenticCapability, requireCapability } from '../capabilities'; +import type { AgenticGeneration } from '../deployments'; +import type { ChainReader } from '../contracts/reader'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; +import type { Checkpoint } from '../agentic.types'; +import { Snapshot, scanLogs } from './snapshot'; + +const MAX_ATTEMPTS = 2; + +/** + * w.checkpoints(): Checkpointed events in (block, tx, log) order, checked + * against the wallet's checkpointCount() at the same snapshot block. + * `sinceBlock` is inclusive. Evaluators should compare counts — one block can + * hold several ticks, and allowance pulls change balances without any tick. + */ +export async function readCheckpoints( + reader: ChainReader, + gen: AgenticGeneration, + wallet: Address, + sinceBlock?: bigint +): Promise<{ checkpoints: Checkpoint[]; count: bigint; blockNumber: bigint }> { + requireCapability(gen.capabilities, AgenticCapability.CHECKPOINTS); + let lastError: AgenticError | undefined; + for (let attempt = 0; attempt < MAX_ATTEMPTS; attempt++) { + const snap = await Snapshot.at(reader); + const count = BigInt( + await snap.read(wallet, gen.contracts.abis.wallet, 'checkpointCount') + ); + const from = sinceBlock !== undefined && sinceBlock > gen.startBlock ? sinceBlock : gen.startBlock; + const logs = await scanLogs( + reader, + { address: wallet, event: gen.contracts.events.checkpointed }, + from, + snap.blockNumber + ); + const decoded = gen.contracts + .parseCheckpointed(logs, wallet) + .sort((a, b) => + a.blockNumber !== b.blockNumber + ? a.blockNumber < b.blockNumber + ? -1 + : 1 + : a.transactionIndex !== b.transactionIndex + ? a.transactionIndex - b.transactionIndex + : a.logIndex - b.logIndex + ); + const problem = validateSequence(decoded.map((c) => c.seq), count, sinceBlock === undefined || from === gen.startBlock); + if (!problem) { + return { + count, + blockNumber: snap.blockNumber, + checkpoints: decoded.map(({ seq, kind, ref, blockNumber, txHash }) => ({ + seq, + kind, + ref, + blockNumber, + txHash, + })), + }; + } + lastError = new AgenticError(AGENTIC_ERROR_CODE.INCONSISTENT_READ, problem, { + details: { wallet, count, blockNumber: snap.blockNumber }, + }); + } + throw lastError as AgenticError; +} + +/** Sequence must be contiguous, end at `count`, and start at 1 for a full scan. */ +export function validateSequence(seqs: number[], count: bigint, fullRange: boolean): string | null { + for (let i = 1; i < seqs.length; i++) { + if (seqs[i] !== seqs[i - 1] + 1) return `checkpoint sequence gap between ${seqs[i - 1]} and ${seqs[i]}`; + } + if (fullRange) { + if (BigInt(seqs.length) !== count) { + return `found ${seqs.length} Checkpointed events but checkpointCount() is ${count}`; + } + if (seqs.length > 0 && seqs[0] !== 1) return `first checkpoint seq is ${seqs[0]}, expected 1`; + return null; + } + if (seqs.length > 0 && BigInt(seqs[seqs.length - 1]) !== count) { + return `last checkpoint seq ${seqs[seqs.length - 1]} does not match checkpointCount() ${count}`; + } + return null; +} diff --git a/packages/core/src/lib/agentic/reads/rules.ts b/packages/core/src/lib/agentic/reads/rules.ts new file mode 100644 index 00000000..0c4dcc85 --- /dev/null +++ b/packages/core/src/lib/agentic/reads/rules.ts @@ -0,0 +1,398 @@ +import { readSvmConfig } from './svm'; +import { readGasPrc20, readSvmSourceToken } from '../contracts/prc20-metadata'; +import { getAddress, zeroAddress, type Address, type Hex } from 'viem'; +import { CHAIN } from '../../constants/enums'; +import { AgenticCapability, requireCapability } from '../capabilities'; +import type { AgenticGeneration } from '../deployments'; +import type { + NativeConfigRead, + ModeRead, + UniversalConfigRead, +} from '../contracts/v5'; +import { configId } from '../codec/ids'; +import { nativeTermsToRule } from '../codec/native'; +import { universalTermsToRule } from '../codec/universal'; +import { readOriginToken } from '../contracts/prc20-metadata'; +import { chainHash } from '../codec/rules'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; +import type { AgenticHex, RulesRecord } from '../agentic.types'; +import { Snapshot } from './snapshot'; + +const MODE_UNIVERSAL = 0; +const MODE_NATIVE = 1; + +export interface ActiveRule { + rulesId: Hex; + /** agentOf(rulesId); zero means the engine no longer resolves it. */ + agent: Address; + actionIds: readonly Hex[]; + mode: number; + vm: number; + chainHash: Hex; +} + +/** Enabled rule IDs with their agent and governed chain, all at one block. */ +export async function readActiveRules( + snap: Snapshot, + gen: AgenticGeneration, + wallet: Address +): Promise { + const ids = await snap.read( + gen.addresses.sessionEngine, + gen.contracts.abis.engine, + 'getPermissionIDs', + [wallet] + ); + return Promise.all(ids.map((id) => readActiveRule(snap, gen, wallet, id))); +} + +async function readActiveRule( + snap: Snapshot, + gen: AgenticGeneration, + wallet: Address, + rulesId: Hex +): Promise { + const [agent, actionIds] = await Promise.all([ + snap.read
(wallet, gen.contracts.abis.wallet, 'agentOf', [rulesId]), + snap.read( + gen.addresses.sessionEngine, + gen.contracts.abis.engine, + 'getEnabledActions', + [wallet, rulesId] + ), + ]); + if (actionIds.length === 0) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INCONSISTENT_READ, + `enabled rule ${rulesId} has no enabled actions` + ); + } + const modes = await Promise.all( + actionIds.map((a) => + snap.read( + gen.addresses.rulesPolicy, + gen.contracts.abis.policy, + 'getMode', + [configId(wallet, rulesId, a), wallet] + ) + ) + ); + const first = modes[0]; + if ( + !modes.every( + (m) => + m.initialized && + m.chainHash === first.chainHash && + m.mode === first.mode + ) + ) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INCONSISTENT_READ, + `rule ${rulesId} has uninitialized or mixed-chain policy configs` + ); + } + return { + rulesId, + agent: getAddress(agent), + actionIds, + mode: Number(first.mode), + vm: Number(first.vm), + chainHash: first.chainHash, + }; +} + +/** Map a stored chain hash back to its CAIP-2 string from known chains. */ +export function chainFromHash( + hash: Hex, + pushChainNamespace: string +): string | undefined { + const known = [pushChainNamespace, ...Object.values(CHAIN)]; + return known.find((c) => chainHash(c) === hash); +} + +/** + * Agent-door rule selection for one send (spec 2.a): enabled rules whose agent + * is the signer and whose chain is the destination, read uncached at one + * block. Expiry, caps and policy remain on-chain checks. + */ +export async function selectRuleForSend( + snap: Snapshot, + gen: AgenticGeneration, + wallet: Address, + agent: Address, + destinationChain: string +): Promise { + const active = await readActiveRules(snap, gen, wallet); + const want = chainHash(destinationChain); + const matches = active.filter( + (r) => r.agent === getAddress(agent) && r.chainHash === want + ); + if (matches.length === 0) { + throw new AgenticError( + AGENTIC_ERROR_CODE.NO_RULES_FOR_CHAIN, + `no enabled rule on ${wallet} names ${agent} for ${destinationChain}`, + { + details: { + wallet, + agent, + destinationChain, + blockNumber: snap.blockNumber, + }, + } + ); + } + if (matches.length > 1) { + throw new AgenticError( + AGENTIC_ERROR_CODE.AMBIGUOUS_RULE, + `${matches.length} enabled rules on ${wallet} name ${agent} for ${destinationChain}`, + { + hint: 'Multiple enabled rules match this agent and chain. Inspect details.rulesIds and ask the owner to resolve the overlap; no transaction was submitted.', + details: { rulesIds: matches.map((m) => m.rulesId) }, + } + ); + } + return matches[0]; +} + +/** Decode one active rule into the public record. */ +export async function decodeActiveRule( + snap: Snapshot, + gen: AgenticGeneration, + wallet: Address, + rule: ActiveRule, + pushChainNamespace: string +): Promise { + if (rule.mode === MODE_UNIVERSAL) { + if (rule.vm === 1) { + requireCapability( + gen.capabilities, + AgenticCapability.UNIVERSAL_SVM_RULES + ); + const stored = await readSvmConfig( + snap, + gen, + wallet, + rule, + pushChainNamespace + ); + const cfg = stored.config; + const gas = await readGasPrc20(snap, stored.chainNamespace); + const assets = await Promise.all( + cfg.assets.map(async (a) => ({ + token: + getAddress(a.token) === gas + ? zeroAddress + : await readSvmSourceToken( + snap, + a.token, + stored.chainNamespace, + gen.network + ), + maxPerCall: a.maxPerCall, + maxTotal: a.maxTotal, + })) + ); + return { + rulesId: rule.rulesId, + enabled: true, + agent: rule.agent, + chainNamespace: stored.chainNamespace, + validUntil: Number(cfg.validUntil), + rule: { + format: 'decoded', + agent: rule.agent, + chainNamespace: stored.chainNamespace, + validUntil: Number(cfg.validUntil), + expectedCEA: cfg.expectedCEA, + gatewayProgram: cfg.gatewayProgram, + maxGasPerCall: cfg.maxGasPerCall, + assets, + ceaAccounts: cfg.ceaAccounts, + programs: cfg.programs, + pins: cfg.pins, + dataPins: cfg.dataPins, + }, + }; + } + if (rule.vm !== 0) + throw new AgenticError( + AGENTIC_ERROR_CODE.RULE_READ_FAILED, + 'unknown universal VM' + ); + requireCapability(gen.capabilities, AgenticCapability.UNIVERSAL_EVM_RULES); + const chain = chainFromHash(rule.chainHash, pushChainNamespace); + if (!chain || !chain.startsWith('eip155:')) + throw new AgenticError( + AGENTIC_ERROR_CODE.RULE_READ_FAILED, + 'unknown EVM rule chain' + ); + const cfg = await snap.read( + gen.addresses.rulesPolicy, + gen.contracts.abis.policy, + 'getConfig', + [configId(wallet, rule.rulesId, rule.actionIds[0]), wallet] + ); + if (!cfg.initialized) + throw new AgenticError( + AGENTIC_ERROR_CODE.INCONSISTENT_READ, + 'uninitialized universal rule' + ); + if ( + !cfg.assets.length || + cfg.assets.length > 8 || + !cfg.allowedCalls.length || + cfg.allowedCalls.length > 32 || + cfg.expectedCEA === zeroAddress + ) + throw new AgenticError( + AGENTIC_ERROR_CODE.INCONSISTENT_READ, + 'invalid stored universal rule shape' + ); + const tokens = await Promise.all( + cfg.assets.map((a) => readOriginToken(snap, a.token, chain)) + ); + return { + rulesId: rule.rulesId, + enabled: true, + chainNamespace: chain, + agent: rule.agent, + validUntil: Number(cfg.validUntil), + rule: universalTermsToRule( + cfg, + rule.agent, + chain as `eip155:${string}`, + tokens + ), + }; + } + if (rule.mode !== MODE_NATIVE) { + throw new AgenticError( + AGENTIC_ERROR_CODE.RULE_READ_FAILED, + `rule ${rule.rulesId} has unknown mode ${rule.mode}` + ); + } + if (rule.actionIds.length !== 1) { + throw new AgenticError( + AGENTIC_ERROR_CODE.RULE_READ_FAILED, + `rule ${rule.rulesId} has ${rule.actionIds.length} native actions; the public NativeRule is single-action (A02)` + ); + } + const cfg = await snap.read( + gen.addresses.rulesPolicy, + gen.contracts.abis.policy, + 'getNativeConfig', + [configId(wallet, rule.rulesId, rule.actionIds[0]), wallet] + ); + if (!cfg.initialized) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INCONSISTENT_READ, + `native config for ${rule.rulesId} is not initialized` + ); + } + if (rule.agent === getAddress(`0x${'00'.repeat(20)}`)) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INCONSISTENT_READ, + `enabled rule ${rule.rulesId} does not resolve to an agent` + ); + } + return { + rulesId: rule.rulesId as AgenticHex, + enabled: true, + chainNamespace: pushChainNamespace, + agent: rule.agent, + validUntil: Number(cfg.validUntil), + rule: nativeTermsToRule(cfg, rule.agent), + }; +} + +/** Native spend counters for the update assertion. */ +export async function readNativeSpend( + snap: Snapshot, + gen: AgenticGeneration, + wallet: Address, + rule: ActiveRule, + action: Hex = rule.actionIds[0] +): Promise<{ + configId: Hex; + valueSpent: bigint; + amountSpent: bigint; + callsUsed: number; +}> { + const id = configId(wallet, rule.rulesId, action); + const cfg = await snap.read( + gen.addresses.rulesPolicy, + gen.contracts.abis.policy, + 'getNativeConfig', + [id, wallet] + ); + return { + configId: id, + valueSpent: cfg.valueSpent, + amountSpent: cfg.amountSpent, + callsUsed: Number(cfg.callsUsed), + }; +} + +export async function readUniversalSpend( + snap: Snapshot, + gen: AgenticGeneration, + wallet: Address, + rule: ActiveRule +): Promise<{ configId: Hex; expectedSpent: bigint[] }> { + const id = configId(wallet, rule.rulesId, rule.actionIds[0]); + const fn = rule.vm === 1 ? 'getSvmConfig' : 'getConfig'; + const cfg = await snap.read<{ + initialized: boolean; + assets: readonly { spent: bigint }[]; + }>(gen.addresses.rulesPolicy, gen.contracts.abis.policy, fn, [id, wallet]); + if (!cfg.initialized) + throw new AgenticError( + AGENTIC_ERROR_CODE.INCONSISTENT_READ, + 'uninitialized universal spend config' + ); + return { configId: id, expectedSpent: cfg.assets.map((a) => a.spent) }; +} + +export async function listRules( + snap: Snapshot, + gen: AgenticGeneration, + wallet: Address, + pushChainNamespace: string +): Promise { + requireCapability(gen.capabilities, AgenticCapability.ACTIVE_RULE_READS); + const active = await readActiveRules(snap, gen, wallet); + const records: RulesRecord[] = []; + for (const r of active) + records.push( + await decodeActiveRule(snap, gen, wallet, r, pushChainNamespace) + ); + return records; +} + +/** + * rules.get returns enabled records only. Unknown/revoked IDs are deliberately + * indistinguishable without historical reconstruction, which is outside v1. + */ +export async function getRule( + snap: Snapshot, + gen: AgenticGeneration, + wallet: Address, + rulesId: Hex, + pushChainNamespace: string +): Promise { + requireCapability(gen.capabilities, AgenticCapability.ACTIVE_RULE_READS); + const enabled = await snap.read( + gen.addresses.sessionEngine, + gen.contracts.abis.engine, + 'isPermissionEnabled', + [rulesId, wallet] + ); + if (enabled) { + const active = await readActiveRule(snap, gen, wallet, rulesId); + return decodeActiveRule(snap, gen, wallet, active, pushChainNamespace); + } + throw new AgenticError( + AGENTIC_ERROR_CODE.RULE_NOT_FOUND, + `rule ${rulesId} is not enabled on ${wallet} (unknown or revoked; v1 has no rule history)` + ); +} diff --git a/packages/core/src/lib/agentic/reads/snapshot.ts b/packages/core/src/lib/agentic/reads/snapshot.ts new file mode 100644 index 00000000..a4fa6285 --- /dev/null +++ b/packages/core/src/lib/agentic/reads/snapshot.ts @@ -0,0 +1,112 @@ +import type { AbiEvent, Address, Log } from 'viem'; +import type { ChainReader } from '../contracts/reader'; +import { + AGENTIC_ERROR_CODE, + AgenticError, + type AgenticErrorCode, +} from '../errors'; + +/** + * All reads of one logical operation are pinned to a single block so dependent + * reads (enumerate IDs → per-ID config) observe one state. An RPC failure is + * surfaced as an error; it is never treated as "empty". + */ +export class Snapshot { + constructor( + readonly reader: ChainReader, + readonly blockNumber: bigint, + private readonly failCode: AgenticErrorCode = AGENTIC_ERROR_CODE.RULE_READ_FAILED + ) {} + + static async at( + reader: ChainReader, + failCode: AgenticErrorCode = AGENTIC_ERROR_CODE.RULE_READ_FAILED + ): Promise { + let block: bigint; + try { + block = await reader.getBlockNumber(); + } catch (cause) { + throw new AgenticError( + failCode, + 'could not read the current Push block number', + { cause } + ); + } + return new Snapshot(reader, block, failCode); + } + + async read( + address: Address, + abi: readonly unknown[], + functionName: string, + args: readonly unknown[] = [] + ): Promise { + try { + return (await this.reader.readContract({ + address, + abi, + functionName, + args, + blockNumber: this.blockNumber, + })) as T; + } catch (cause) { + throw new AgenticError( + this.failCode, + `${functionName} read on ${address} failed at block ${this.blockNumber}`, + { + cause, + details: { address, functionName, blockNumber: this.blockNumber }, + } + ); + } + } + + async code(address: Address): Promise { + try { + const code = await this.reader.getCode({ + address, + blockNumber: this.blockNumber, + }); + return !!code && code !== '0x'; + } catch (cause) { + throw new AgenticError(this.failCode, `getCode(${address}) failed`, { + cause, + }); + } + } +} + +/** Max block span per eth_getLogs request. */ +// Donut's public RPC limits eth_getLogs ranges to a distance of 1,000 blocks. +export const LOG_PAGE_BLOCKS = BigInt(1_000); + +/** + * Paginated log scan [fromBlock, toBlock] inclusive. A failed page fails the + * whole scan; partial results are never returned. + */ +export async function scanLogs( + reader: ChainReader, + args: { address: Address; event: AbiEvent; args?: Record }, + fromBlock: bigint, + toBlock: bigint, + page: bigint = LOG_PAGE_BLOCKS +): Promise { + const out: Log[] = []; + if (fromBlock > toBlock) return out; + for (let start = fromBlock; start <= toBlock; start += page) { + const end = + start + page - BigInt(1) > toBlock ? toBlock : start + page - BigInt(1); + try { + out.push( + ...(await reader.getLogs({ ...args, fromBlock: start, toBlock: end })) + ); + } catch (cause) { + throw new AgenticError( + AGENTIC_ERROR_CODE.RULE_READ_FAILED, + `log scan for ${args.event.name} failed for blocks ${start}-${end}`, + { cause } + ); + } + } + return out; +} diff --git a/packages/core/src/lib/agentic/reads/svm.ts b/packages/core/src/lib/agentic/reads/svm.ts new file mode 100644 index 00000000..56767cff --- /dev/null +++ b/packages/core/src/lib/agentic/reads/svm.ts @@ -0,0 +1,98 @@ +/** Internal lossless SVM state shared by public reads and execution. */ +import type { Address, Hex } from 'viem'; +import type { AgenticGeneration } from '../deployments'; +import type { SvmConfigRead } from '../contracts/v5'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; +import { actionId, configId } from '../codec/ids'; +import { SEND_OUTBOUND_SELECTOR } from '../contracts/v5'; +import { validateSvmTerms } from '../codec/svm-terms'; +import { chainFromHash, readActiveRules, type ActiveRule } from './rules'; +import type { Snapshot } from './snapshot'; + +export interface SvmRuleSnapshot { + wallet: Address; + rulesId: Hex; + agent: Address; + chainNamespace: `solana:${string}`; + configId: Hex; + config: SvmConfigRead; + blockNumber: bigint; +} + +export async function readSvmRule( + snap: Snapshot, + gen: AgenticGeneration, + wallet: Address, + rulesId: Hex, + pushChainNamespace: string +): Promise { + const active = (await readActiveRules(snap, gen, wallet)).find( + (r) => r.rulesId.toLowerCase() === rulesId.toLowerCase() + ); + if (!active) + throw new AgenticError( + AGENTIC_ERROR_CODE.RULE_NOT_FOUND, + `no enabled SVM rule ${rulesId} on ${wallet}` + ); + return readSvmConfig(snap, gen, wallet, active, pushChainNamespace); +} + +export async function readSvmConfig( + snap: Snapshot, + gen: AgenticGeneration, + wallet: Address, + active: ActiveRule, + pushChainNamespace: string +): Promise { + const chain = chainFromHash(active.chainHash, pushChainNamespace); + const expectedAction = actionId( + gen.addresses.gateway, + SEND_OUTBOUND_SELECTOR + ); + if ( + active.mode !== 0 || + active.vm !== 1 || + !chain?.startsWith('solana:') || + active.actionIds.length !== 1 || + active.actionIds[0].toLowerCase() !== expectedAction.toLowerCase() + ) + throw new AgenticError( + AGENTIC_ERROR_CODE.INCONSISTENT_READ, + 'rule is not a single gateway SVM action' + ); + const id = configId(wallet, active.rulesId, active.actionIds[0]); + const cfg = await snap.read( + gen.addresses.rulesPolicy, + gen.contracts.abis.policy, + 'getSvmConfig', + [id, wallet] + ); + try { + if (!cfg.initialized) throw new Error('uninitialized SVM config'); + // Stored expired rules remain readable. Grant-time validation still checks expiry. + validateSvmTerms(cfg, -1); + for (const cap of cfg.assets) { + if ( + typeof cap.spent !== 'bigint' || + cap.spent < BigInt(0) || + cap.spent > cap.maxTotal + ) + throw new Error('invalid stored asset counter'); + } + } catch (cause) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INCONSISTENT_READ, + 'malformed stored SVM config', + { cause } + ); + } + return { + wallet, + rulesId: active.rulesId, + agent: active.agent, + chainNamespace: chain as `solana:${string}`, + configId: id, + config: cfg, + blockNumber: snap.blockNumber, + }; +} diff --git a/packages/core/src/lib/agentic/reads/wallets.ts b/packages/core/src/lib/agentic/reads/wallets.ts new file mode 100644 index 00000000..fd0c33f1 --- /dev/null +++ b/packages/core/src/lib/agentic/reads/wallets.ts @@ -0,0 +1,198 @@ +import { getAddress, type Address } from 'viem'; +import type { AgenticGeneration } from '../deployments'; +import type { ChainReader } from '../contracts/reader'; +import { deriveWallet } from '../codec/ids'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; +import type { WalletInfo, WalletSummary } from '../agentic.types'; +import { Snapshot } from './snapshot'; + +/** Factory-predicted address for (owner, index), cross-checked against the pure mirror. */ +async function predict( + snap: Snapshot, + gen: AgenticGeneration, + owner: Address, + index: bigint +): Promise<{ address: Address; deployed: boolean }> { + const [address, deployed] = await snap.read( + gen.addresses.factory, + gen.contracts.abis.factory, + 'predictWallet', + [owner, index] + ); + const mirror = deriveWallet({ + factory: gen.addresses.factory, + walletImplementation: gen.addresses.walletImplementation, + owner, + index, + }); + if (getAddress(address) !== mirror) { + // Derivation drift between the SDK mirror and the factory (obligation 13). + throw new AgenticError( + AGENTIC_ERROR_CODE.INCONSISTENT_READ, + `factory predicted ${address} for (${owner}, ${index}) but the SDK derives ${mirror}`, + { details: { generation: gen.id } } + ); + } + return { address: getAddress(address), deployed }; +} + +export async function walletCount( + snap: Snapshot, + gen: AgenticGeneration, + owner: Address +): Promise { + return BigInt( + await snap.read( + gen.addresses.factory, + gen.contracts.abis.factory, + 'walletCount', + [owner] + ) + ); +} + +/** client.agentic.derive: default index is the owner's next unused slot. */ +export async function deriveForOwner( + reader: ChainReader, + gen: AgenticGeneration, + owner: Address, + index?: number +): Promise<{ address: Address; index: number; deployed: boolean }> { + const snap = await Snapshot.at(reader); + const next = await walletCount(snap, gen, owner); + let target = next; + if (index !== undefined) { + if (!Number.isInteger(index) || index < 0) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'index must be a non-negative integer' + ); + } + target = BigInt(index); + if (target > next) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + `index ${index} is beyond the owner's next unused index ${next}; the factory only predicts up to the next slot` + ); + } + } + const p = await predict(snap, gen, owner, target); + return { address: p.address, index: Number(target), deployed: p.deployed }; +} + +export async function rulesCount( + snap: Snapshot, + gen: AgenticGeneration, + wallet: Address +): Promise { + const ids = await snap.read( + gen.addresses.sessionEngine, + gen.contracts.abis.engine, + 'getPermissionIDs', + [wallet] + ); + return ids.length; +} + +/** + * client.agentic.list: every deployed slot plus the next undeployed slot + * (deployed=false, rulesCount=0), as in the spec example. + */ +export async function listForOwner( + reader: ChainReader, + gen: AgenticGeneration, + owner: Address +): Promise { + const snap = await Snapshot.at(reader); + const count = await walletCount(snap, gen, owner); + const out: WalletSummary[] = []; + for (let i = BigInt(0); i <= count; i++) { + const p = await predict(snap, gen, owner, i); + const deployed = i < count; + if (deployed !== p.deployed) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INCONSISTENT_READ, + `factory reports slot ${i} deployed=${p.deployed} but walletCount is ${count}` + ); + } + const label = deployed + ? await snap.read(p.address, gen.contracts.abis.wallet, 'label') + : ''; + out.push({ + address: p.address, + index: Number(i), + label, + deployed, + rulesCount: deployed ? await rulesCount(snap, gen, p.address) : 0, + }); + } + return out; +} + +/** w.owner(): the owner as the wallet stores it. */ +export async function walletOwner( + reader: ChainReader, + gen: AgenticGeneration, + wallet: Address +): Promise
{ + const snap = await Snapshot.at(reader); + return getAddress( + await snap.read
(wallet, gen.contracts.abis.wallet, 'owner') + ); +} + +/** + * w.info(). A deployed wallet is read from chain. An undeployed address is + * only describable when it is `signerIdentity`'s next predicted slot. + */ +export async function walletInfo( + reader: ChainReader, + gen: AgenticGeneration, + wallet: Address, + signerIdentity?: Address +): Promise { + const snap = await Snapshot.at(reader); + const deployed = await snap.code(wallet); + if (!deployed) { + if (signerIdentity) { + const next = await walletCount(snap, gen, signerIdentity); + const p = await predict(snap, gen, signerIdentity, next); + if (p.address === getAddress(wallet)) { + return { + address: p.address, + label: '', + index: Number(next), + owner: getAddress(signerIdentity), + deployed: false, + rulesCount: 0, + }; + } + } + throw new AgenticError( + AGENTIC_ERROR_CODE.WALLET_NOT_DEPLOYED, + `${wallet} is not deployed and is not the connected owner's next wallet slot` + ); + } + const [owner, index] = await Promise.all([ + snap.read
(wallet, gen.contracts.abis.wallet, 'owner'), + snap.read( + gen.addresses.factory, + gen.contracts.abis.factory, + 'indexOf', + [wallet] + ), + ]); + const label = await snap.read( + wallet, + gen.contracts.abis.wallet, + 'label' + ); + return { + address: getAddress(wallet), + label, + index: Number(index), + owner: getAddress(owner), + deployed: true, + rulesCount: await rulesCount(snap, gen, wallet), + }; +} diff --git a/packages/core/src/lib/agentic/response.ts b/packages/core/src/lib/agentic/response.ts new file mode 100644 index 00000000..111fdf28 --- /dev/null +++ b/packages/core/src/lib/agentic/response.ts @@ -0,0 +1,432 @@ +import { Snapshot } from './reads/snapshot'; +import { readGasPrc20 } from './contracts/prc20-metadata'; +import { parseAgwSvmPayload } from './execution/svm-payload'; +import { deriveAgwSvmCea } from './codec/svm-accounts'; +import { CHAIN_INFO } from '../constants/chain'; +import { bytesToHex } from 'viem'; +import { + decodeAbiParameters, + decodeFunctionData, + getAddress, + type Address, + type Hex, +} from 'viem'; +import { CHAIN } from '../constants/enums'; +import { getBatchExecutorAddress } from '../constants/chain'; +import { getPushChainForNetwork } from '../orchestrator/internals/helpers'; +import { convertExecutorToOrigin } from '../universal/account/account'; +import { pushChainNamespaceFor } from './chain'; +import { UNIVERSAL_GATEWAY_PC } from '../constants/abi'; +import type { + TransactionRouteType, + UniversalTxResponse, +} from '../orchestrator/orchestrator.types'; +import { + v5, + SEND_OUTBOUND_SELECTOR, + UEA_MULTICALL_PREFIX, + type Call, +} from './contracts/v5'; +import { generationsFor, resolveWalletGeneration } from './deployments'; +import type { AgenticRuntime } from './runtime'; +import type { + AgenticAddress, + AgenticHex, + AgenticTxMetadata, +} from './agentic.types'; + +export interface LogicalCall { + to: string; + data: string; + value: bigint; +} + +/** + * Present an AGW send as the wallet's own transaction: `from` is the AGW and + * `to`/`data`/`value` are the logical call. The signer's `origin`, hashes, + * nonce, gas and the on-chain `raw` fields are kept untouched; the wrapped + * call the signer actually sent is recorded in `agentic.rawTo/rawData`. + * Mutates in place so `wait()` (which reads these fields) reports the same + * identity on the receipt. + */ +export function adaptAgenticResponse( + resp: UniversalTxResponse, + meta: Omit & { + logical: LogicalCall; + route?: TransactionRouteType; + chain?: CHAIN; + } +): UniversalTxResponse { + const rawTo = resp.to; + const rawData = resp.data; + if (!resp.raw) { + resp.raw = { + from: resp.from, + to: resp.to, + nonce: resp.nonce, + data: resp.data, + value: resp.value, + }; + } + resp.from = getAddress(meta.wallet); + resp.to = meta.logical.to; + resp.data = meta.logical.data; + resp.value = meta.logical.value; + if (meta.route) resp.route = meta.route; + if (meta.chain) { + resp.chain = meta.chain; + resp.chainNamespace = meta.chain; + } + resp.agentic = { + wallet: getAddress(meta.wallet) as AgenticAddress, + door: meta.door, + ...(meta.rulesId ? { rulesId: meta.rulesId } : {}), + ...(meta.chainNamespace ? { chainNamespace: meta.chainNamespace } : {}), + ...(meta.destinationAccount + ? { destinationAccount: meta.destinationAccount } + : {}), + ...(meta.destinationCalls + ? { destinationCalls: meta.destinationCalls.map((call) => ({ ...call })) } + : {}), + ...(meta.destinationInstruction + ? { destinationInstruction: meta.destinationInstruction } + : {}), + ...(meta.destinationTransfer + ? { destinationTransfer: { ...meta.destinationTransfer } } + : {}), + ...(meta.nativeCalls + ? { nativeCalls: meta.nativeCalls.map((call) => ({ ...call })) } + : {}), + rawTo, + rawData, + }; + return resp; +} + +/** + * trackTransaction replay: if the tracked Push tx called execute/executeAsAgent + * on a wallet of a registered, verified generation, restore the same logical + * identity a live send reports. Anything unrecognised is returned unchanged. + */ +export async function adaptTrackedResponse( + runtime: Pick, + resp: UniversalTxResponse +): Promise { + if (resp.agentic || generationsFor(runtime.network).length === 0) return resp; + const batch = await adaptNativeAgentBatch(runtime, resp); + if (batch) return batch; + const decoded = v5.decodeWalletCall(resp.data as Hex); + if ( + !decoded || + (decoded.kind !== 'execute' && decoded.kind !== 'executeAsAgent') + ) + return resp; + let wallet: Address; + try { + wallet = getAddress(resp.to); + } catch { + return resp; + } + let gen; + try { + gen = await resolveWalletGeneration( + runtime.reader, + runtime.network, + wallet + ); + } catch { + return resp; + } + const door = decoded.kind === 'execute' ? 'owner' : 'agent'; + const rulesId = + decoded.kind === 'executeAsAgent' + ? (decoded.rulesId as AgenticHex) + : undefined; + const calls = decoded.calls; + const outbound = calls.find( + (c) => + getAddress(c.target) === gen.addresses.gateway && + c.data.toLowerCase().startsWith(SEND_OUTBOUND_SELECTOR) + ); + if (outbound) { + const out = decodeOutbound(outbound.data); + const chain = await tokenChain(runtime, out.token); + if (chain?.startsWith('solana:')) { + if ( + door === 'owner' && + out.payload === '0x' && + out.amount > BigInt(0) && + /^0x[0-9a-fA-F]{64}$/.test(out.recipient) + ) { + try { + const gas = await readGasPrc20( + new Snapshot(runtime.reader, resp.blockNumber), + chain + ); + return adaptAgenticResponse(resp, { + wallet, + door, + chainNamespace: chain, + chain: chain as CHAIN, + route: 'UOA_TO_CEA', + destinationTransfer: { + recipient: out.recipient, + token: out.token, + amount: out.amount, + }, + logical: { + to: out.recipient, + data: '0x', + value: getAddress(gas) === out.token ? out.amount : BigInt(0), + }, + }); + } catch { + // Preserve the actual gateway summary when historical token metadata + // cannot be read; destination polling below still uses the known chain. + } + } + try { + const instruction = parseAgwSvmPayload(out.payload); + const destinationInstruction = { + program: instruction.program, + accounts: instruction.accounts.map(({ pubkey, isWritable }) => ({ + pubkey, + isWritable, + })), + data: bytesToHex(instruction.instructionData), + }; + return adaptAgenticResponse(resp, { + wallet, + door, + rulesId, + chainNamespace: chain, + chain: chain as CHAIN, + route: 'UOA_TO_CEA', + destinationInstruction, + destinationAccount: deriveAgwSvmCea( + wallet, + CHAIN_INFO[chain as CHAIN].lockerContract ?? '' + ).address, + logical: { + to: instruction.program, + data: destinationInstruction.data, + value: BigInt(0), + }, + }); + } catch { + // Historical owner calls may use another payload format. Preserve the + // actual gateway call below instead of inventing instruction metadata. + } + } + // The decoded wallet call is authoritative: core may have inferred a + // Push-only route from an incomplete Cosmos record, which would stop + // wait() from polling the destination leg. + return adaptAgenticResponse(resp, { + wallet, + door, + rulesId, + chainNamespace: chain, + logical: outboundResponseCall(out.calls, { + to: outbound.target, + data: outbound.data, + value: outbound.value, + }), + ...(out.calls.length > 0 ? { destinationCalls: out.calls } : {}), + route: 'UOA_TO_CEA', + chain: (chain as CHAIN | undefined) ?? resp.chain, + }); + } + const single = calls.length === 1 ? calls[0] : undefined; + return adaptAgenticResponse(resp, { + wallet, + door, + rulesId, + chainNamespace: undefined, + logical: single + ? { to: single.target, data: single.data, value: single.value } + : { to: wallet, data: resp.data, value: BigInt(0) }, + }); +} + +/** Decode only supported sender-account batches, never an arbitrary forwarding helper. */ +async function adaptNativeAgentBatch( + runtime: Pick, + resp: UniversalTxResponse +): Promise { + let outer: Call[]; + const isUea = resp.data.toLowerCase().startsWith(UEA_MULTICALL_PREFIX); + try { + if (isUea) { + const [entries] = decodeAbiParameters( + [ + { + type: 'tuple[]', + components: [ + { name: 'to', type: 'address' }, + { name: 'value', type: 'uint256' }, + { name: 'data', type: 'bytes' }, + ], + }, + ], + `0x${resp.data.slice(10)}` + ); + outer = entries.map((c) => ({ + target: getAddress(c.to), + value: c.value, + data: c.data, + })); + } else { + const batch = v5.decodeWalletCall(resp.data as Hex); + if (batch?.kind !== 'execute' || batch.mode !== `0x01${'00'.repeat(31)}`) + return; + outer = batch.calls; + } + if ( + outer.length < 2 || + outer.some((c) => c.value !== BigInt(0) || c.target !== outer[0].target) + ) + return; + const inner = outer.map((c) => v5.decodeWalletCall(c.data)); + const first = inner[0]; + if (first?.kind !== 'executeAsAgent' || first.calls.length !== 1) return; + const nativeCalls: { to: Address; value: bigint; data: Hex }[] = []; + for (const c of inner) { + if ( + c?.kind !== 'executeAsAgent' || + c.calls.length !== 1 || + c.rulesId !== first.rulesId || + c.mode !== `0x${'00'.repeat(32)}` + ) + return; + const call = c.calls[0]; + nativeCalls.push({ to: call.target, value: call.value, data: call.data }); + } + const senderAccount = getAddress(resp.from); + if (isUea) { + if (getAddress(resp.raw?.to ?? resp.to) !== senderAccount) return; + const origin = await convertExecutorToOrigin(senderAccount, { + _internal: true, + }); + if (!origin.exists) return; + } else { + if (getAddress(resp.to) !== senderAccount) return; + const executor = getBatchExecutorAddress( + getPushChainForNetwork(runtime.network) + ); + if (!executor) return; + const code = await runtime.reader.getCode({ + address: senderAccount, + blockNumber: resp.blockNumber, + }); + if (code?.toLowerCase() !== `0xef0100${executor.slice(2).toLowerCase()}`) + return; + } + const wallet = outer[0].target; + const gen = await resolveWalletGeneration( + runtime.reader, + runtime.network, + wallet + ); + // This recognizer is only for native arrays; keep mixed/outbound batches raw. + if (nativeCalls.some((c) => c.to === gen.addresses.gateway)) return; + return adaptAgenticResponse(resp, { + wallet, + door: 'agent', + rulesId: first.rulesId as AgenticHex, + chainNamespace: pushChainNamespaceFor(runtime.network), + nativeCalls, + logical: { ...nativeCalls[0] }, + }); + } catch { + // Unsupported payload or unverified sender/wallet: preserve the original response. + return; + } +} + +/** + * Canonical outbound summary for both send and replay: the first actual + * destination call. The complete ordered calls live in agentic.destinationCalls. + * Identical calldata can come from explicit calls or generated transfers, so + * never infer the original input shape from a selector. For an unrecognized + * historical payload, retain the actual gateway call instead of inventing one. + */ +export function outboundResponseCall( + calls: readonly { to: Address; value: bigint; data: Hex }[], + fallback: LogicalCall +): LogicalCall { + const first = calls[0]; + return first + ? { to: first.to, data: first.data, value: first.value } + : fallback; +} + +function decodeOutbound(data: Hex): { + payload: Hex; + recipient: Hex; + amount: bigint; + token: Address; + calls: { to: Address; value: bigint; data: Hex }[]; +} { + const { args } = decodeFunctionData({ abi: UNIVERSAL_GATEWAY_PC, data }); + const req = args?.[0] as { + token: Address; + payload: Hex; + recipient: Hex; + amount: bigint; + }; + let calls: { to: Address; value: bigint; data: Hex }[] = []; + if (req.payload.toLowerCase().startsWith(UEA_MULTICALL_PREFIX)) { + try { + const [decodedCalls] = decodeAbiParameters( + [ + { + type: 'tuple[]', + components: [ + { name: 'to', type: 'address' }, + { name: 'value', type: 'uint256' }, + { name: 'data', type: 'bytes' }, + ], + }, + ], + `0x${req.payload.slice(10)}` + ); + calls = decodedCalls.map((c) => ({ + to: getAddress(c.to), + value: c.value, + data: c.data, + })); + } catch { + calls = []; + } + } + return { + token: getAddress(req.token), + payload: req.payload, + recipient: req.recipient, + amount: req.amount, + calls, + }; +} + +async function tokenChain( + runtime: Pick, + token: Address +): Promise { + try { + return (await runtime.reader.readContract({ + address: token, + abi: [ + { + type: 'function', + name: 'SOURCE_CHAIN_NAMESPACE', + inputs: [], + outputs: [{ type: 'string' }], + stateMutability: 'view', + }, + ], + functionName: 'SOURCE_CHAIN_NAMESPACE', + })) as string; + } catch { + return undefined; + } +} diff --git a/packages/core/src/lib/agentic/revert.ts b/packages/core/src/lib/agentic/revert.ts new file mode 100644 index 00000000..a6a07daa --- /dev/null +++ b/packages/core/src/lib/agentic/revert.ts @@ -0,0 +1,131 @@ +import { + decodeErrorResult, + toFunctionSelector, + type Abi, + type Hex, +} from 'viem'; +import { formatAbiItem } from 'viem/utils'; +import type { DecodedErrorPayload } from '../orchestrator/internals/errors'; +import { + AGW_ABI, + AGW_FACTORY_ABI, + SMART_SESSION_ABI, + UNIVERSAL_RULES_POLICY_ABI, +} from './contracts/abi/v5'; + +/** URP reverts reached through the engine are truncated to this wrapper. */ +export const POLICY_CHECK_REVERTED_SELECTOR = '0xf4270752'; + +const ERROR_ABIS: readonly Abi[] = [ + AGW_ABI as unknown as Abi, + UNIVERSAL_RULES_POLICY_ABI as unknown as Abi, + AGW_FACTORY_ABI as unknown as Abi, + SMART_SESSION_ABI as unknown as Abi, +]; + +/** selector → error name across the AGW/URP/factory/engine ABIs. */ +const ERROR_NAMES: ReadonlyMap = new Map( + ERROR_ABIS.flatMap((abi) => + abi + .filter((item) => item.type === 'error') + .map((item) => { + const err = item as { + type: 'error'; + name: string; + inputs: readonly { type: string }[]; + }; + return [ + toFunctionSelector(formatAbiItem(err as never)).toLowerCase(), + err.name, + ] as const; + }) + ) +); + +const HEX_DATA = /0x[0-9a-fA-F]{8,}/g; +const CUSTOM_ERROR_TEXT = /custom error (0x[0-9a-fA-F]{8}):?\s*([0-9a-fA-F]*)/g; + +/** Pull candidate revert data out of an error (viem chains, nested causes, messages). */ +function revertDataCandidates(err: unknown, depth = 0): Hex[] { + if (!err || depth > 6) return []; + const out: Hex[] = []; + const e = err as { + data?: unknown; + raw?: unknown; + cause?: unknown; + message?: unknown; + details?: unknown; + }; + if (typeof e.raw === 'string' && /^0x[0-9a-fA-F]{8,}$/.test(e.raw)) + out.push(e.raw as Hex); + if (typeof e.data === 'string' && /^0x[0-9a-fA-F]{8,}$/.test(e.data)) + out.push(e.data as Hex); + if ( + e.data && + typeof e.data === 'object' && + typeof (e.data as { data?: unknown }).data === 'string' + ) { + out.push((e.data as { data: Hex }).data); + } + for (const text of [e.message, e.details]) { + if (typeof text !== 'string') continue; + // viem renders unknown custom errors as "custom error 0x: ". + for (const m of text.matchAll(CUSTOM_ERROR_TEXT)) + out.push(`${m[1]}${m[2] ?? ''}` as Hex); + out.push(...((text.match(HEX_DATA) ?? []) as Hex[])); + } + out.push(...revertDataCandidates(e.cause, depth + 1)); + return out; +} + +/** Decode raw revert data against the AGW/URP/factory/engine error ABIs. */ +export function decodeAgwErrorData(data: Hex): DecodedErrorPayload | undefined { + const selector = data.slice(0, 10).toLowerCase(); + if (selector === POLICY_CHECK_REVERTED_SELECTOR && data.length >= 10 + 64) { + // bytes32 = 4-byte policy error selector ‖ 28 bytes of its first argument. + // The arguments are truncated, so the inner error is named by selector only. + const word = `0x${data.slice(10, 74)}` as Hex; + const innerName = ERROR_NAMES.get(word.slice(0, 10).toLowerCase()); + return { + name: innerName + ? `PolicyCheckReverted(${innerName})` + : 'PolicyCheckReverted', + selector, + decoded: word, + hint: 'URP rejected the action (truncated through the session engine). The inner selector names the gate; arguments are truncated to 28 bytes.', + }; + } + for (const abi of ERROR_ABIS) { + try { + const r = decodeErrorResult({ abi, data }); + return { + name: r.errorName, + selector, + decoded: r.args && r.args.length ? stringifyArgs(r.args) : undefined, + }; + } catch { + // try the next ABI + } + } + // Arguments lost (e.g. a node rendered them as text): name the error by its selector. + const name = ERROR_NAMES.get(selector); + return name + ? { name, selector, hint: 'Error arguments were not available.' } + : undefined; +} + +export function decodeAgenticRevert( + err: unknown +): DecodedErrorPayload | undefined { + for (const data of revertDataCandidates(err)) { + const decoded = decodeAgwErrorData(data); + if (decoded) return decoded; + } + return undefined; +} + +function stringifyArgs(args: readonly unknown[]): string { + return JSON.stringify(args, (_k, v) => + typeof v === 'bigint' ? v.toString() : v + ); +} diff --git a/packages/core/src/lib/agentic/runtime.ts b/packages/core/src/lib/agentic/runtime.ts new file mode 100644 index 00000000..0068f20e --- /dev/null +++ b/packages/core/src/lib/agentic/runtime.ts @@ -0,0 +1,176 @@ +import { getAddress, type Address } from 'viem'; +import { CHAIN, PUSH_NETWORK } from '../constants/enums'; +import type { MoveableToken } from '../constants/tokens'; +import { AtomicBatchUnavailableError } from '../orchestrator/internals/errors'; +import { capabilityUnavailable } from './errors'; +import type { Orchestrator } from '../orchestrator/orchestrator'; +import type { + ExecuteParams, + TransactionExecutionOptions, + UniversalExecuteParams, + UniversalTxResponse, +} from '../orchestrator/orchestrator.types'; +import type { ProgressEvent } from '../progress-hook/progress-hook.types'; +import { getCEAAddress } from '../orchestrator/cea-utils'; +import type { OrchestratorContext } from '../orchestrator/internals/context'; +import { computeUEAOffchain } from '../orchestrator/internals/uea-manager'; +import { ensureSvmFinalizeGasBudgetQuote } from '../orchestrator/internals/svm-rent'; +import { queryOutboundGasFee } from '../orchestrator/internals/gas-calculator'; +import { + getNativePRC20ForChain, + isPushChain, +} from '../orchestrator/internals/helpers'; +import { pushChainNamespaceFor } from './chain'; +import { getPRC20Address } from '../universal/prc20-address'; +import { + chainReaderFromPublicClient, + type ChainReader, +} from './contracts/reader'; +import type { SvmMetadataProvider } from './management/svm-context'; +import { createSvmMetadataProvider } from './management/svm-metadata'; +import { CHAIN_INFO } from '../constants/chain'; +import type { AgenticProgressHook } from './agentic.types'; + +/** + * Everything the AGW module needs from the surrounding client. Tests supply a + * mock; PushChain builds the real one from its orchestrator. Keeping this + * explicit is what separates the signer's identity (gas, account status, + * ownership derivation) from the AGW execution account. + */ +export interface AgenticRuntime { + readonly network: PUSH_NETWORK; + /** 'eip155:' of the connected Push chain — the native rule chain. */ + readonly pushChainNamespace: string; + readonly reader: ChainReader; + readonly isReadOnly: boolean; + readonly svmMetadata?: SvmMetadataProvider; + /** Connected signer's Push identity: its EOA, or its UEA for its actual origin chain. */ + signerPushAccount(): Address; + /** Connected signer's origin account (universal.origin). */ + signerOrigin(): { chain: CHAIN; address: string }; + signerIsPushNative(): boolean; + /** The signer's ordinary transaction path (orchestrator.execute). */ + execute( + params: ExecuteParams | UniversalExecuteParams, + options?: TransactionExecutionOptions + ): Promise; + /** Sender-preserving UEA/7702 transport; native sequential fallback is forbidden. */ + executeAtomicBatch( + params: ExecuteParams, + options?: TransactionExecutionOptions + ): Promise; + /** Emit to the init-time hook and, if different, the per-call hook. */ + emit(event: ProgressEvent, perCallHook?: AgenticProgressHook): void; + /** Whether the signer's own UEA is deployed (always true for a Push EOA). */ + signerAccountDeployed(): Promise; + signerBalance(): Promise; + getGasPrice(): Promise; + quoteOutbound( + prc20: Address, + gasLimit: bigint, + chain: CHAIN, + svm?: { wallet: Address; splMintBase58?: string; burnAmount: bigint } + ): Promise<{ + protocolFee: bigint; + nativeValueForGas: bigint; + gasLimitUsed: bigint; + }>; + resolveCEA( + account: Address, + chain: CHAIN + ): Promise<{ cea: Address; isDeployed: boolean }>; + resolvePrc20( + token: MoveableToken | string | undefined, + chain: CHAIN + ): Address; + nowSeconds(): number; +} + +/** Build the runtime over an orchestrator (the orchestrator IS the internal ctx). */ +export function createAgenticRuntime( + orchestrator: Orchestrator, + isReadOnly: boolean +): AgenticRuntime { + const ctx = orchestrator as unknown as OrchestratorContext; + const network = orchestrator.getNetwork(); + return { + network, + pushChainNamespace: pushChainNamespaceFor(network), + get reader() { + return chainReaderFromPublicClient(ctx.pushClient.publicClient); + }, + isReadOnly, + svmMetadata: createSvmMetadataProvider({ + [CHAIN.SOLANA_DEVNET]: { + gatewayProgram: CHAIN_INFO[CHAIN.SOLANA_DEVNET].lockerContract ?? '', + rpcUrls: + orchestrator.getRpcUrls()[CHAIN.SOLANA_DEVNET] ?? + CHAIN_INFO[CHAIN.SOLANA_DEVNET].defaultRPC, + }, + }), + signerPushAccount: () => getAddress(computeUEAOffchain(ctx)), + signerOrigin: () => orchestrator.getUOA(), + signerIsPushNative: () => isPushChain(ctx.universalSigner.account.chain), + execute: (params, options) => orchestrator.execute(params, options), + executeAtomicBatch: async (params, options) => { + try { + return await orchestrator.executeAtomicBatch(params, options); + } catch (error) { + if (error instanceof AtomicBatchUnavailableError) { + throw capabilityUnavailable('atomicNativeAgentBatch', error.message); + } + throw error; + } + }, + emit: (event, perCallHook) => { + const base = orchestrator.getProgressHook(); + base?.(event); + if (perCallHook && perCallHook !== base) perCallHook(event); + }, + signerAccountDeployed: async () => { + if (isPushChain(ctx.universalSigner.account.chain)) return true; + const status = await orchestrator.getAccountStatus(); + return status.uea.deployed; + }, + signerBalance: () => ctx.pushClient.getBalance(computeUEAOffchain(ctx)), + getGasPrice: () => ctx.pushClient.getGasPrice(), + quoteOutbound: async (prc20, gasLimit, chain, svm) => { + let q = await queryOutboundGasFee(ctx, prc20, gasLimit, chain); + if (svm) { + q = await ensureSvmFinalizeGasBudgetQuote({ + ctx, + ueaAddress: svm.wallet, + targetChain: chain, + prc20Token: prc20, + quote: q, + splMintBase58: svm.splMintBase58, + burnAmount: svm.burnAmount, + pathTag: 'AGW_SVM', + }); + } + return { + protocolFee: q.protocolFee, + nativeValueForGas: q.nativeValueForGas, + gasLimitUsed: q.gasLimitUsed, + }; + }, + resolveCEA: async (account, chain) => { + const r = await getCEAAddress( + account, + chain, + orchestrator.getRpcUrls()[chain]?.[0] + ); + return { cea: getAddress(r.cea), isDeployed: r.isDeployed }; + }, + resolvePrc20: (token, chain) => + getAddress( + token + ? getPRC20Address( + typeof token === 'string' ? { chain, address: token } : token, + { network } + ).address + : getNativePRC20ForChain(chain, network) + ), + nowSeconds: () => Math.floor(Date.now() / 1000), + }; +} diff --git a/packages/core/src/lib/agentic/utils.ts b/packages/core/src/lib/agentic/utils.ts new file mode 100644 index 00000000..2c863bd2 --- /dev/null +++ b/packages/core/src/lib/agentic/utils.ts @@ -0,0 +1,249 @@ +import { decodeSvmTerms, validateSvmTerms } from './codec/svm-terms'; +import { svmKey } from './codec/svm-accounts'; +import { getAddress, isHex, zeroAddress, type Address, type Hex } from 'viem'; +import { CHAIN, PUSH_NETWORK } from '../constants/enums'; +import { MOVEABLE_TOKENS } from '../constants/tokens'; +import { getPRC20Address } from '../universal/prc20-address'; +import { AgenticCapability } from './capabilities'; +import { V5_CAPABILITIES } from './deployments'; +import { + actionId as actionIdRaw, + configId as configIdRaw, + deriveWallet as deriveWalletRaw, + rulesId as rulesIdRaw, +} from './codec/ids'; +import { decodeNativeTerms, nativeTermsToRule } from './codec/native'; +import { prepareRules } from './codec/rules'; +import { parseSelector } from './codec/selectors'; +import { decodeEnvelope, decodeSession, encodeSession } from './codec/session'; +import { + AGENTIC_ERROR_CODE, + AgenticError, + capabilityUnavailable, +} from './errors'; +import { pushChainNamespaceFor } from './chain'; +import { decodeUniversalTerms } from './codec/universal-terms'; +import { universalTermsToRule } from './codec/universal'; +import type { + AgenticHex, + Rule, + Selector, + DecodedSolanaRule, +} from './agentic.types'; +import type { UniversalRule } from './agentic.types'; +import type { ResolvedUniversalRule } from './codec/universal'; + +/** + * Internal generation context. Harsh H4.1 (October 4): deployment inputs + * are implementation details, not public helper parameters. + */ +export interface RulesEncodeContext { + /** Connected Push network, or an explicit 'eip155:' native chain. */ + network?: PUSH_NETWORK; + pushChainNamespace?: string; + validator: Address; + rulesPolicy: Address; + gateway?: Address; + universal?: ReadonlyMap; + /** Wallet owner, for the AGENT_IS_OWNER check. */ + owner?: Address; + /** Defaults to the current time. */ + nowSeconds?: number; +} + +function nativeNamespace(ctx: { + network?: PUSH_NETWORK; + pushChainNamespace?: string; +}): string { + if (ctx.pushChainNamespace) return ctx.pushChainNamespace; + return pushChainNamespaceFor(ctx.network ?? PUSH_NETWORK.TESTNET_DONUT); +} + +/** Internal codecs and identities — not exported from the package entry point. */ +export const internalAgenticUtils = { + /** The ID a grant with this grantNonce produces. Chain is not part of the hash. */ + rulesId( + agent: Address, + grantNonce: bigint | number, + ctx: { validator: Address } + ): AgenticHex { + return rulesIdRaw({ + validator: getAddress(ctx.validator), + agent: getAddress(agent), + grantNonce: BigInt(grantNonce), + }) as AgenticHex; + }, + + /** Hash of one allowed call: keccak256(target ‖ selector). */ + actionId(target: Address, selector: Selector | 'value-only'): AgenticHex { + return actionIdRaw( + getAddress(target), + parseSelector(selector).selector + ) as AgenticHex; + }, + + /** Key of one allowed call's stored config under one rule on one wallet. */ + configId(wallet: Address, rulesId: Hex, actionId: Hex): AgenticHex { + return configIdRaw(getAddress(wallet), rulesId, actionId) as AgenticHex; + }, + + /** Any-owner wallet address. */ + deriveWallet( + owner: Address, + index: bigint | number, + ctx: { factory: Address; walletImplementation: Address } + ): Address { + return deriveWalletRaw({ + factory: getAddress(ctx.factory), + walletImplementation: getAddress(ctx.walletImplementation), + owner: getAddress(owner), + index, + }); + }, + + /** + * Encode rules into the grant `Session` bytes, one per rule, in order. + * EVM universal rules require wallet/token resolution in the internal context. + */ + encodeRules(rules: readonly Rule[], ctx: RulesEncodeContext): AgenticHex[] { + return prepareRules(rules, { + owner: ctx.owner ? getAddress(ctx.owner) : undefined, + pushChainNamespace: nativeNamespace(ctx), + validator: getAddress(ctx.validator), + rulesPolicy: getAddress(ctx.rulesPolicy), + gateway: ctx.gateway, + universal: ctx.universal, + capabilities: V5_CAPABILITIES, + nowSeconds: ctx.nowSeconds ?? Math.floor(Date.now() / 1000), + }).map((p) => encodeSession(p.session) as AgenticHex); + }, + + /** Inverse of encodeRules for one Session encoding. */ + decodeRules( + bytes: Hex, + ctx: { network?: PUSH_NETWORK; pushChainNamespace?: string } = {} + ): Rule | DecodedSolanaRule { + if (!isHex(bytes)) + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'decodeRules expects hex bytes' + ); + const session = decodeSession(bytes); + if ( + session.actions.length !== 1 || + session.actions[0].actionPolicies.length !== 1 + ) { + throw new AgenticError( + AGENTIC_ERROR_CODE.RULE_READ_FAILED, + 'only single-action rules (one URP policy) are representable as a public Rule' + ); + } + const agent = getAddress( + `0x${session.sessionValidatorInitData.slice(26, 66)}` + ); + const { chainNamespace, body } = decodeEnvelope( + session.actions[0].actionPolicies[0].initData + ); + if (chainNamespace !== nativeNamespace(ctx)) { + if (chainNamespace.startsWith('solana:')) { + const terms = decodeSvmTerms(body); + validateSvmTerms(terms, -1); + const assets = terms.assets.map((a) => { + const chain = chainNamespace as CHAIN; + const token = (MOVEABLE_TOKENS[chain] ?? []).find((candidate) => { + try { + return ( + getAddress( + getPRC20Address( + { chain, address: candidate.address }, + { network: ctx.network ?? PUSH_NETWORK.TESTNET_DONUT } + ).address + ) === getAddress(a.token) + ); + } catch { + return false; + } + }); + if (!token) + throw new AgenticError( + AGENTIC_ERROR_CODE.RULE_READ_FAILED, + 'SVM source token is absent from the static registry; use wallet.rules.get()' + ); + return { + token: + token.mechanism === 'native' + ? zeroAddress + : svmKey(token.address), + maxPerCall: a.maxPerCall, + maxTotal: a.maxTotal, + }; + }); + return { + ...terms, + format: 'decoded', + agent, + chainNamespace: chainNamespace as `solana:${string}`, + assets, + }; + } + if (!chainNamespace.startsWith('eip155:')) + throw capabilityUnavailable( + AgenticCapability.UNIVERSAL_SVM_RULES, + 'unsupported universal chain namespace' + ); + let terms; + try { + terms = decodeUniversalTerms(body); + } catch (cause) { + throw new AgenticError( + AGENTIC_ERROR_CODE.RULE_READ_FAILED, + 'malformed universal terms', + { cause } + ); + } + const chain = chainNamespace as CHAIN; + const network = ctx.network ?? PUSH_NETWORK.TESTNET_DONUT; + const tokens = terms.assets.map((asset) => { + const token = (MOVEABLE_TOKENS[chain] ?? []).find((candidate) => { + try { + return ( + getAddress( + getPRC20Address( + { chain, address: candidate.address }, + { network } + ).address + ) === getAddress(asset.token) + ); + } catch { + return false; + } + }); + if (!token) + throw new AgenticError( + AGENTIC_ERROR_CODE.RULE_READ_FAILED, + `PRC20 ${asset.token} is not in the static ${chain} token registry`, + { + hint: 'Use wallet.rules.get() for on-chain source-token resolution.', + } + ); + return token.mechanism === 'native' + ? zeroAddress + : getAddress(token.address); + }); + return universalTermsToRule( + terms, + agent, + chainNamespace as `eip155:${string}`, + tokens + ); + } + return nativeTermsToRule(decodeNativeTerms(body), agent); + }, +}; + +/** Public helpers requiring no contract deployment context. */ +export const agenticUtils = { + actionId: internalAgenticUtils.actionId, + configId: internalAgenticUtils.configId, + decodeRules: internalAgenticUtils.decodeRules, +}; diff --git a/packages/core/src/lib/agentic/wallet.ts b/packages/core/src/lib/agentic/wallet.ts new file mode 100644 index 00000000..ddecd3a6 --- /dev/null +++ b/packages/core/src/lib/agentic/wallet.ts @@ -0,0 +1,196 @@ +import { getAddress, type Address } from 'viem'; +import { AgenticCapability, requireCapability } from './capabilities'; +import { resolveWalletGeneration, type AgenticGeneration } from './deployments'; +import { AGENTIC_ERROR_CODE, AgenticError } from './errors'; +import { + addRules, + assertRevokeTarget, + revokeRules, + setLabel, + updateRules, +} from './management/rules-write'; +import { readCheckpoints } from './reads/checkpoints'; +import { getRule, listRules } from './reads/rules'; +import { Snapshot } from './reads/snapshot'; +import { walletInfo, walletOwner } from './reads/wallets'; +import type { AgenticRuntime } from './runtime'; +import type { + AgenticAddress, + AgenticHex, + AgenticProgressHook, + AgenticWallet, + Checkpoint, + RulesRecord, + WalletInfo, +} from './agentic.types'; +import type { UniversalTxResponse } from '../orchestrator/orchestrator.types'; +import { currentGeneration } from './deployments'; +import { assertLabel } from './management/label'; + +/** + * Management handle for one wallet (spec 1.d). Reads work for any wallet; + * writes require the connected signer to be the owner. It never sends AS the + * wallet — that is PushChain.initialize(signer, { agenticWallet }). + */ +export class AgenticWalletHandle implements AgenticWallet { + readonly address: AgenticAddress; + readonly rules: AgenticWallet['rules']; + private generation?: Promise; + + constructor(private readonly runtime: AgenticRuntime, address: string) { + try { + this.address = getAddress(address) as AgenticAddress; + } catch (cause) { + throw new AgenticError( + AGENTIC_ERROR_CODE.NOT_AGENTIC_WALLET, + `"${address}" is not an address`, + { cause } + ); + } + this.rules = { + list: () => this.listRules(), + get: (rulesId) => this.getRule(rulesId), + add: async (rules, opts) => + addRules( + this.runtime, + await this.gen(), + this.address, + rules, + opts?.progressHook + ), + update: async (params) => + updateRules(this.runtime, await this.gen(), this.address, params), + revoke: (async ( + target: + | AgenticHex[] + | { all: true; progressHook?: AgenticProgressHook }, + opts?: { progressHook?: AgenticProgressHook } + ) => { + // Validate the target shape before any RPC so a bare revoke costs nothing. + assertRevokeTarget(target); + return revokeRules( + this.runtime, + await this.gen(), + this.address, + target, + opts?.progressHook + ); + }) as AgenticWallet['rules']['revoke'], + }; + } + + /** Deployed wallets resolve their own generation; undeployed ones use the network's current one. */ + private gen(): Promise { + if (!this.generation) { + this.generation = resolveWalletGeneration( + this.runtime.reader, + this.runtime.network, + this.address + ); + this.generation.catch(() => { + this.generation = undefined; + }); + } + return this.generation; + } + + async info(): Promise { + let gen: AgenticGeneration; + try { + gen = await this.gen(); + } catch (err) { + if ( + err instanceof AgenticError && + err.code === AGENTIC_ERROR_CODE.WALLET_NOT_DEPLOYED + ) { + gen = currentGeneration(this.runtime.network); + } else { + throw err; + } + } + requireCapability(gen.capabilities, AgenticCapability.WALLET_READS); + return walletInfo( + this.runtime.reader, + gen, + this.address, + this.signerIdentity() + ); + } + + async owner(): Promise<{ owner: AgenticAddress }> { + const gen = await this.gen(); + return { + owner: (await walletOwner( + this.runtime.reader, + gen, + this.address + )) as AgenticAddress, + }; + } + + async setLabel( + label: string, + opts?: { progressHook?: AgenticProgressHook } + ): Promise { + assertLabel(label); + return setLabel( + this.runtime, + await this.gen(), + this.address, + label, + opts?.progressHook + ); + } + + async checkpoints(opts?: { + sinceBlock?: bigint; + }): Promise<{ checkpoints: Checkpoint[] }> { + const gen = await this.gen(); + const { checkpoints } = await readCheckpoints( + this.runtime.reader, + gen, + this.address, + opts?.sinceBlock + ); + return { checkpoints }; + } + + private async listRules(): Promise<{ rules: RulesRecord[] }> { + const gen = await this.gen(); + const snap = await Snapshot.at(this.runtime.reader); + return { + rules: await listRules( + snap, + gen, + this.address, + this.runtime.pushChainNamespace + ), + }; + } + + private async getRule(rulesId: AgenticHex): Promise { + if (typeof rulesId !== 'string' || !/^0x[0-9a-fA-F]{64}$/.test(rulesId)) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'rulesId must be a 32-byte hex string' + ); + } + const gen = await this.gen(); + const snap = await Snapshot.at(this.runtime.reader); + return getRule( + snap, + gen, + this.address, + rulesId, + this.runtime.pushChainNamespace + ); + } + + private signerIdentity(): Address | undefined { + try { + return this.runtime.signerPushAccount(); + } catch { + return undefined; + } + } +} diff --git a/packages/core/src/lib/constants/enums.ts b/packages/core/src/lib/constants/enums.ts index da52330a..31ef1c3e 100644 --- a/packages/core/src/lib/constants/enums.ts +++ b/packages/core/src/lib/constants/enums.ts @@ -34,12 +34,15 @@ export enum CHAIN { } /** - * Read-only destination exposed with the OG `CHAIN.WEB2` spelling without - * widening the blockchain enum type accepted by transaction APIs. + * Read-only Web2 source kept on `CHAIN` for compatibility without widening the + * blockchain enum type accepted by transaction APIs. + * + * @deprecated Use `PushChain.CONSTANTS.READ.CHAIN.WEB2`. Same value (`'web2'`); + * the legacy literal `'web2:https'` is still accepted as read input. */ // eslint-disable-next-line @typescript-eslint/no-namespace -- declaration merging keeps Web2 out of the transaction enum union export namespace CHAIN { - export const WEB2 = 'web2:https' as const; + export const WEB2 = 'web2' as const; } // Namespace properties are normally enumerable after TypeScript emits them. // Keep blockchain enumeration (`Object.values(CHAIN)`) blockchain-only. diff --git a/packages/core/src/lib/constants/index.ts b/packages/core/src/lib/constants/index.ts index dcc1523c..a9ee4211 100644 --- a/packages/core/src/lib/constants/index.ts +++ b/packages/core/src/lib/constants/index.ts @@ -15,13 +15,27 @@ import { READ_NAMESPACE, WEB2_DEFAULT_TIMEOUT_MS, WEB2_MAX_EXTRACT_ENTRIES, + WEB2_READ_CHAIN, } from './read-state'; import { UNIVERSAL_READ_STATUS, READ_STATUS, READ_ERROR_CODE, READ_OUTCOME } from '../read-state/read-state.types'; +import { AGENTIC } from '../agentic/constants'; + +/** + * `PushChain.CONSTANTS.READ.CHAIN` — every read source: all of `CHAIN` (same + * string values) plus the enumerable Web2 source. A superset of CHAIN, so + * `read({ chain: CHAIN.X })` keeps compiling. + */ +export const READ_CHAIN = Object.freeze({ + ...CHAIN, + WEB2: WEB2_READ_CHAIN, +}) as Readonly<{ [K in keyof typeof CHAIN]: (typeof CHAIN)[K] }> & { readonly WEB2: typeof WEB2_READ_CHAIN }; /** `PushChain.CONSTANTS.READ` — cross-chain read state. Values verified against the deployed UniversalCallback. */ export const READ_CONSTANTS = { - /** Read-only Web2 destination. Equivalent to `CHAIN.WEB2`. */ - WEB2: CHAIN.WEB2, + /** Every read source, enumerable (spec page 5 §4). */ + CHAIN: READ_CHAIN, + /** @deprecated Use `READ.CHAIN.WEB2`. Same value (`'web2'`). */ + WEB2: WEB2_READ_CHAIN, NAMESPACE: READ_NAMESPACE, MAX_CALLBACK_GAS_LIMIT, MIN_CONFIRMATIONS_FLOOR, @@ -57,6 +71,8 @@ export const CONSTANTS = { MOVEABLE: { TOKEN: MOVEABLE_TOKEN_CONSTANTS }, PAYABLE: { TOKEN: PAYABLE_TOKEN_CONSTANTS }, READ: READ_CONSTANTS, + /** Checked v5 agentic wallet deployments by Push network (Donut only). */ + AGENTIC, }; export type { TypedDataDomain, TypedData }; diff --git a/packages/core/src/lib/constants/read-state.ts b/packages/core/src/lib/constants/read-state.ts index 03ac47b8..5e596644 100644 --- a/packages/core/src/lib/constants/read-state.ts +++ b/packages/core/src/lib/constants/read-state.ts @@ -42,6 +42,19 @@ export const WEB2_MAX_TIMEOUT_MS = 15_000; * Web2 is not a blockchain and is not a `CHAIN` enum member. Reads target it via * an explicit destination; the node routes on namespace `web2`, id `https`. */ +/** Public Web2 read source (`READ.CHAIN.WEB2`). */ +export const WEB2_READ_CHAIN = 'web2' as const; +/** + * Legacy public spelling, and the unchanged CAIP-2 wire identity validators + * route on. Still accepted as read input. + */ +export const LEGACY_WEB2_READ_CHAIN = 'web2:https' as const; + +/** True for either public Web2 spelling. */ +export function isWeb2ReadChain(chain: unknown): chain is typeof WEB2_READ_CHAIN | typeof LEGACY_WEB2_READ_CHAIN { + return chain === WEB2_READ_CHAIN || chain === LEGACY_WEB2_READ_CHAIN; +} + export const WEB2_DESTINATION = { chainNamespace: 'web2', chainId: 'https', diff --git a/packages/core/src/lib/index.ts b/packages/core/src/lib/index.ts index e0906cfa..940cf4c4 100644 --- a/packages/core/src/lib/index.ts +++ b/packages/core/src/lib/index.ts @@ -175,4 +175,49 @@ export { export { UNIVERSAL_CALLBACK_EVM } from './constants/abi/universalCallback.evm'; export { UNIVERSAL_READ_REGISTRY_EVM } from './constants/abi/universalReadRegistry.evm'; +// Structured execution errors (base class of AgenticRevertError) +export { + PushChainExecutionError, + PushChainBatchExecutionError, +} from './orchestrator/internals/errors'; +export type { DecodedErrorPayload } from './orchestrator/internals/errors'; + +// Agentic wallet (AGW) +export type { PushChainInitializeOptions } from './push-chain/push-chain'; +export { + AGENTIC_ERROR_CODE, + AgenticError, + AgenticRevertError, +} from './agentic'; +export type { + AgenticAddress, + AgenticDoor, + AgenticErrorCode, + AgenticHex, + AgenticNamespace, + AgenticNetworkConstants, + AgenticProgressHook, + AgenticTxMetadata, + AgenticWallet, + AllowedCall, + AssetCap, + Checkpoint, + CheckpointKind, + CreateOptions, + CreateResult, + ForeignChainNamespace, + NativeRule, + SolanaRule, + DecodedSolanaRule, + SvmInstructionRule, + SvmAccountRef, + SvmFieldConstraint, + Rule, + RulesRecord, + Selector, + UniversalRule, + WalletInfo, + WalletSummary, +} from './agentic'; + export { PushChain }; diff --git a/packages/core/src/lib/orchestrator/__tests__/outbound-svm-confirmation.spec.ts b/packages/core/src/lib/orchestrator/__tests__/outbound-svm-confirmation.spec.ts new file mode 100644 index 00000000..11f50cc0 --- /dev/null +++ b/packages/core/src/lib/orchestrator/__tests__/outbound-svm-confirmation.spec.ts @@ -0,0 +1,127 @@ +import { Connection } from '@solana/web3.js'; +import bs58 from 'bs58'; +import { CHAIN } from '../../constants/enums'; +import { + waitForOutboundTx, + OutboundFailedError, + OutboundTimeoutError, +} from '../internals/outbound-sync'; +import { OutboundStatus } from '../../generated/uexecutor/v2/types'; +import type { OrchestratorContext } from '../internals/context'; +jest.mock('@solana/web3.js', () => ({ + ...jest.requireActual('@solana/web3.js'), + Connection: jest.fn(), +})); +const bytes = Buffer.alloc(64, 12), + signature = bs58.encode(bytes), + hex = '0x' + bytes.toString('hex'); +const statuses = jest.fn(), + genesis = jest.fn(); +beforeEach(() => { + statuses.mockReset(); + genesis + .mockReset() + .mockResolvedValue(CHAIN.SOLANA_DEVNET.slice(7) + 'abcdefghijk'); + (Connection as unknown as jest.Mock).mockImplementation(() => ({ + getGenesisHash: genesis, + getSignatureStatuses: statuses, + })); +}); +function context(hash: string): OrchestratorContext { + return { + printTraces: false, + pushNetwork: 'TESTNET_DONUT', + rpcUrls: { [CHAIN.SOLANA_DEVNET]: ['http://fixture'] }, + pushClient: { + getCosmosTx: jest.fn().mockResolvedValue({ events: [] }), + getUniversalTxByIdV2: jest + .fn() + .mockResolvedValue({ + universalTx: { + universalStatus: 6, + pcTx: [], + outboundTx: [ + { + destinationChain: CHAIN.SOLANA_DEVNET, + outboundStatus: OutboundStatus.PENDING, + recipient: 'fixture', + amount: '0', + externalAssetAddr: '', + observedTx: { txHash: hash }, + }, + ], + }, + }), + }, + } as unknown as OrchestratorContext; +} +const opts = { initialWaitMs: 0, pollingIntervalMs: 1, timeout: 100 }; +it.each([signature, hex])( + 'confirms pending Cosmos signature %s through Solana RPC', + async (hash) => { + statuses.mockResolvedValue({ + value: [{ confirmationStatus: 'confirmed', err: null }], + }); + const out = await waitForOutboundTx(context(hash), '0xpush', opts); + expect(out.externalTxHash).toBe(hash); + expect(statuses).toHaveBeenCalledWith([signature], { + searchTransactionHistory: true, + }); + } +); +it('waits through processed status before finalization', async () => { + statuses + .mockResolvedValueOnce({ + value: [{ confirmationStatus: 'processed', err: null }], + }) + .mockResolvedValue({ + value: [{ confirmationStatus: 'finalized', err: null }], + }); + await waitForOutboundTx(context(signature), '0xpush', opts); + expect(statuses).toHaveBeenCalledTimes(2); +}); +it('reports a confirmed signature error as failure, preserving the hash', async () => { + statuses.mockResolvedValue({ + value: [ + { + confirmationStatus: 'confirmed', + err: { InstructionError: [0, 'Custom'] }, + }, + ], + }); + await expect( + waitForOutboundTx(context(hex), '0xpush', opts) + ).rejects.toMatchObject({ code: 'OUTBOUND_FAILED', externalTxHash: hex }); +}); +it.each([ + 'wrong-cluster', + 'missing', + 'processed-error', + 'rpc-error', + 'malformed-hash', +])('keeps %s pending until timeout', async (kind) => { + statuses.mockResolvedValue({ value: [null] }); + if (kind === 'wrong-cluster') genesis.mockResolvedValue('wrong'); + if (kind === 'processed-error') + statuses.mockResolvedValue({ + value: [{ confirmationStatus: 'processed', err: { failure: true } }], + }); + if (kind === 'rpc-error') + statuses.mockRejectedValue(new Error('RPC unavailable')); + const hash = kind === 'malformed-hash' ? '0x1234' : signature; + await expect( + waitForOutboundTx(context(hash), '0xpush', { ...opts, timeout: 20 }) + ).rejects.toBeInstanceOf(OutboundTimeoutError); + if (kind === 'wrong-cluster' || kind === 'malformed-hash') + expect(statuses).not.toHaveBeenCalled(); +}); +it('keeps an authoritative Cosmos revert ahead of the RPC tiebreaker', async () => { + const ctx = context(signature); + (ctx.pushClient.getUniversalTxByIdV2 as jest.Mock).mockResolvedValue({ + universalTx: { universalStatus: 8, pcTx: [], outboundTx: [] }, + }); + await expect(waitForOutboundTx(ctx, '0xpush', opts)).rejects.toBeInstanceOf( + OutboundFailedError + ); + expect(statuses).not.toHaveBeenCalled(); +}); diff --git a/packages/core/src/lib/orchestrator/__tests__/push-chain-native-multicall.spec.ts b/packages/core/src/lib/orchestrator/__tests__/push-chain-native-multicall.spec.ts index 626912dc..c90d3082 100644 --- a/packages/core/src/lib/orchestrator/__tests__/push-chain-native-multicall.spec.ts +++ b/packages/core/src/lib/orchestrator/__tests__/push-chain-native-multicall.spec.ts @@ -1,5 +1,6 @@ import { CHAIN, PUSH_NETWORK } from '../../constants/enums'; import { construct, toUniversal } from '../../universal/signer/signer'; +import { AtomicBatchUnavailableError } from '../internals/errors'; import { EIP7702NotSupportedError } from '../../vm-client/evm-client'; import type { OrchestratorContext } from '../internals/context'; import { sendPushTx } from '../internals/push-chain-tx'; @@ -51,6 +52,7 @@ function makeContext(signer: OrchestratorContext['universalSigner']) { getTransactionCount: jest.fn().mockResolvedValue(41), waitForTransactionReceipt, call: jest.fn(), + getCode: jest.fn().mockResolvedValue('0x6000'), }, }; @@ -260,3 +262,45 @@ describe('sendPushTx native multicall routing', () => { expect(transformFn).not.toHaveBeenCalled(); }); }); + + +describe('atomic-only native batches (AGW sender-preserving arrays)', () => { + async function context(supportsAuthorization = true) { + const signer = await toUniversal(construct( + { chain: CHAIN.PUSH_TESTNET_DONUT, address: '0x3333333333333333333333333333333333333333' }, + { signMessage: async (data) => data, signAndSendTransaction: async (data) => data, + ...(supportsAuthorization ? { signAuthorization: jest.fn() } : {}) } + )); + return makeContext(signer); + } + + it('rejects missing signer capability without sending any sequential call', async () => { + const { ctx, pushClient } = await context(false); + await expect(sendPushTx(ctx, execute, [], transformFn, true)).rejects.toBeInstanceOf(AtomicBatchUnavailableError); + expect(pushClient.sendTransaction).not.toHaveBeenCalled(); + expect(pushClient.sendBatch7702).not.toHaveBeenCalled(); + }); + + it('refuses a missing executor before authorization or broadcast', async () => { + const { ctx, pushClient } = await context(); + pushClient.publicClient.getCode.mockResolvedValue('0x'); + await expect(sendPushTx(ctx, execute, [], transformFn, true)).rejects.toBeInstanceOf(AtomicBatchUnavailableError); + expect(pushClient.sendTransaction).not.toHaveBeenCalled(); + expect(pushClient.sendBatch7702).not.toHaveBeenCalled(); + }); + + it('does not fall back when authorization is exposed but unsupported at runtime', async () => { + const { ctx, pushClient } = await context(); + pushClient.sendBatch7702.mockRejectedValueOnce(new EIP7702NotSupportedError()); + await expect(sendPushTx(ctx, execute, [], transformFn, true)).rejects.toBeInstanceOf(AtomicBatchUnavailableError); + expect(pushClient.sendTransaction).not.toHaveBeenCalled(); + expect(pushClient.sendBatch7702).toHaveBeenCalledTimes(1); + }); + + it('uses the atomic transport when signer and executor are available', async () => { + const { ctx, pushClient } = await context(); + await sendPushTx(ctx, execute, [], transformFn, true); + expect(pushClient.sendBatch7702).toHaveBeenCalledTimes(1); + expect(pushClient.sendTransaction).not.toHaveBeenCalled(); + }); +}); diff --git a/packages/core/src/lib/orchestrator/internals/errors.ts b/packages/core/src/lib/orchestrator/internals/errors.ts index 58f3ec78..871ddda3 100644 --- a/packages/core/src/lib/orchestrator/internals/errors.ts +++ b/packages/core/src/lib/orchestrator/internals/errors.ts @@ -43,14 +43,25 @@ export class PushChainExecutionError extends Error { readonly code = 'PUSH_CHAIN_EXECUTION_FAILED' as const; readonly gatewayTxHash?: string; readonly decodedError?: DecodedErrorPayload; + /** Underlying transport/RPC error, kept so raw revert data is not lost. */ + override readonly cause?: unknown; constructor( message: string, - opts: { gatewayTxHash?: string; decodedError?: DecodedErrorPayload } = {} + opts: { gatewayTxHash?: string; decodedError?: DecodedErrorPayload; cause?: unknown } = {} ) { super(normalizePublicErrorMessage(message)); this.name = 'PushChainExecutionError'; this.gatewayTxHash = opts.gatewayTxHash; this.decodedError = opts.decodedError; + if (opts.cause !== undefined) this.cause = opts.cause; + } +} + +/** @internal A caller required an atomic native batch; sequential fallback is forbidden. */ +export class AtomicBatchUnavailableError extends PushChainExecutionError { + constructor(message: string, cause?: unknown) { + super(message, { cause }); + this.name = 'AtomicBatchUnavailableError'; } } diff --git a/packages/core/src/lib/orchestrator/internals/execute-standard.ts b/packages/core/src/lib/orchestrator/internals/execute-standard.ts index a0d0a026..9195afcf 100644 --- a/packages/core/src/lib/orchestrator/internals/execute-standard.ts +++ b/packages/core/src/lib/orchestrator/internals/execute-standard.ts @@ -136,7 +136,8 @@ export async function executeStandardPayload( ctx: OrchestratorContext, execute: ExecuteParams, eventBuffer: ProgressEvent[], - getResponseCallbacks: () => ResponseBuilderCallbacks + getResponseCallbacks: () => ResponseBuilderCallbacks, + policy?: { requireAtomicBatch: boolean } ): Promise { const transformFn = (tx: TxResponse, buf: ProgressEvent[] = []) => transformToUniversalTxResponse(ctx, tx, buf, getResponseCallbacks()); @@ -169,7 +170,7 @@ export async function executeStandardPayload( fireProgressHook(ctx, PROGRESS_HOOK.SEND_TX_107); let tx: UniversalTxResponse; try { - tx = await sendPushTx(ctx, execute, eventBuffer, transformFn); + tx = await sendPushTx(ctx, execute, eventBuffer, transformFn, policy?.requireAtomicBatch); } catch (err) { // Push Chain broadcast failed. Wallet rejection surfaces as 104-04; // everything else (RPC fail, on-chain revert) as 199-02. @@ -184,7 +185,7 @@ export async function executeStandardPayload( // outer orchestrator catch doesn't emit a second 199-02 on top. ctx._routeTerminalEmitted = true; if (!isUserDecline && !(err instanceof PushChainExecutionError)) { - throw new PushChainExecutionError(errMsg); + throw new PushChainExecutionError(errMsg, { cause: err }); } throw err; } diff --git a/packages/core/src/lib/orchestrator/internals/outbound-sync.ts b/packages/core/src/lib/orchestrator/internals/outbound-sync.ts index 56089d9b..f9cb9831 100644 --- a/packages/core/src/lib/orchestrator/internals/outbound-sync.ts +++ b/packages/core/src/lib/orchestrator/internals/outbound-sync.ts @@ -7,6 +7,8 @@ import { resolvePC20WrapperForReceipt } from './pc20/tracking'; import { createPublicClient, fallback, http } from 'viem'; +import { Connection } from '@solana/web3.js'; +import bs58 from 'bs58'; import { CHAIN_INFO, VM_NAMESPACE } from '../../constants/chain'; import { CHAIN, VM } from '../../constants/enums'; import { UniversalTxStatus } from '../../generated/uexecutor/v1/types'; @@ -113,15 +115,15 @@ export class OutboundFailedError extends Error { * (preserves the silent-success bug fix); if no receipt yet or RPC failure, * we keep polling. * - * EVM-only — SVM tiebreaker would need a separate signature lookup path. + * EVM receipts and confirmed/finalized Solana signatures are supported. */ -async function verifyExternalEvmReceipt( +async function verifyExternalReceipt( ctx: OrchestratorContext, destinationChain: CHAIN, externalTxHash: string ): Promise<'success' | 'reverted' | 'pending' | 'unsupported'> { const chainInfo = CHAIN_INFO[destinationChain]; - if (!chainInfo || chainInfo.vm !== VM.EVM) { + if (!chainInfo || (chainInfo.vm !== VM.EVM && chainInfo.vm !== VM.SVM)) { return 'unsupported'; } // Guard against unit-test contexts that don't pass a real rpcUrls map — @@ -133,6 +135,52 @@ async function verifyExternalEvmReceipt( : chainInfo.defaultRPC; if (!rpcUrls?.length) return 'unsupported'; + if (chainInfo.vm === VM.SVM) { + let signature: string; + try { + const bytes = externalTxHash.startsWith('0x') + ? /^0x[0-9a-fA-F]{128}$/.test(externalTxHash) + ? Buffer.from(externalTxHash.slice(2), 'hex') + : new Uint8Array() + : bs58.decode(externalTxHash); + if (bytes.length !== 64) return 'pending'; + signature = bs58.encode(bytes); + } catch { + return 'pending'; + } + for (const url of rpcUrls) { + try { + const connection = new Connection(url, 'confirmed'); + if ( + `solana:${(await connection.getGenesisHash()).slice(0, 32)}` !== + destinationChain + ) + continue; + const result = await connection.getSignatureStatuses([signature], { + searchTransactionHistory: true, + }); + const status = result.value[0]; + // A processed vote can still disappear. Never report success/failure + // before the signature is confirmed or finalized on the right cluster. + if ( + !status || + (status.confirmationStatus !== 'confirmed' && + status.confirmationStatus !== 'finalized') + ) + return 'pending'; + return status.err ? 'reverted' : 'success'; + } catch (error) { + printLog( + ctx, + `[verifyExternalReceipt] SVM RPC unavailable: ${ + error instanceof Error ? error.name : 'unknown' + }` + ); + } + } + return 'pending'; + } + try { const client = createPublicClient({ transport: fallback(rpcUrls.map((url) => http(url))), @@ -153,7 +201,7 @@ async function verifyExternalEvmReceipt( } printLog( ctx, - `[verifyExternalEvmReceipt] RPC error for ${destinationChain} tx ${externalTxHash}: ${msg}` + `[verifyExternalReceipt] RPC error for ${destinationChain} tx ${externalTxHash}: ${msg}` ); return 'pending'; } @@ -397,7 +445,7 @@ export async function waitForOutboundTx( ob.outboundStatus === OutboundStatus.OBSERVED; if (!isCosmosObserved) { // Tiebreaker: ask the destination-chain RPC directly. - const verdict = await verifyExternalEvmReceipt( + const verdict = await verifyExternalReceipt( ctx, chain, ob.observedTx.txHash @@ -468,11 +516,10 @@ export async function waitForOutboundTx( // created, and a repeat export deploys no wrapper so nothing is // ever observed to backfill it. Resolve from UniversalCore instead, // keyed by the Push-native source token. - const pc20Wrapper = await resolvePC20WrapperForReceipt( - ctx, - ob, - { network: ctx.pushNetwork, rpcUrls: ctx.rpcUrls } - ); + const pc20Wrapper = await resolvePC20WrapperForReceipt(ctx, ob, { + network: ctx.pushNetwork, + rpcUrls: ctx.rpcUrls, + }); const details: OutboundTxDetails = { externalTxHash: ob.observedTx.txHash, destinationChain: chain, @@ -738,7 +785,7 @@ export async function waitForAllOutboundTxsV2( const isCosmosObserved = ob.outboundStatus === OutboundStatus.OBSERVED; if (!isCosmosObserved) { - const verdict = await verifyExternalEvmReceipt( + const verdict = await verifyExternalReceipt( ctx, chain, externalTxHash diff --git a/packages/core/src/lib/orchestrator/internals/push-chain-tx.ts b/packages/core/src/lib/orchestrator/internals/push-chain-tx.ts index 551ae237..14005428 100644 --- a/packages/core/src/lib/orchestrator/internals/push-chain-tx.ts +++ b/packages/core/src/lib/orchestrator/internals/push-chain-tx.ts @@ -30,7 +30,7 @@ import type { import type { OrchestratorContext } from './context'; import { fireProgressHook, printLog } from './context'; import { decodeRevert, formatDecodedRevertForUser } from './error-decoder'; -import { PushChainExecutionError, PushChainBatchExecutionError } from './errors'; +import { PushChainExecutionError, PushChainBatchExecutionError, AtomicBatchUnavailableError } from './errors'; import { normalizePublicErrorMessage } from '../../formatters'; // ============================================================================ @@ -115,7 +115,8 @@ export async function sendPushTx( ctx: OrchestratorContext, execute: ExecuteParams, eventBuffer: ProgressEvent[], - transformFn: TransformToResponseFn + transformFn: TransformToResponseFn, + requireAtomicBatch = false ): Promise { if (Array.isArray(execute.data)) { const calls = execute.data as MultiCall[]; @@ -138,6 +139,15 @@ export async function sendPushTx( const executor = getBatchExecutorAddress( ctx.universalSigner.account.chain ); + if (requireAtomicBatch) { + if (!executor || !ctx.universalSigner.signAuthorization) { + throw new AtomicBatchUnavailableError('This operation requires a sender-preserving atomic batch; the signer/network does not support EIP-7702.'); + } + const code = await ctx.pushClient.publicClient.getCode({ address: executor }); + if (!code || code === '0x') { + throw new AtomicBatchUnavailableError(`Atomic batch executor ${executor} is not deployed on the connected network.`); + } + } if (executor && ctx.universalSigner.signAuthorization) { try { printLog( @@ -161,6 +171,9 @@ export async function sendPushTx( // to sequential execution cannot double-execute. Any other error // (e.g. a real revert) must surface. if (!(err instanceof EIP7702NotSupportedError)) throw err; + if (requireAtomicBatch) { + throw new AtomicBatchUnavailableError('The signer could not authorize EIP-7702; no sequential transactions were sent.', err); + } printLog( ctx, `sendPushTx — wallet cannot sign EIP-7702 authorization; falling back to sequential execution` diff --git a/packages/core/src/lib/orchestrator/orchestrator.ts b/packages/core/src/lib/orchestrator/orchestrator.ts index 0943e429..f6084c31 100644 --- a/packages/core/src/lib/orchestrator/orchestrator.ts +++ b/packages/core/src/lib/orchestrator/orchestrator.ts @@ -247,6 +247,25 @@ export class Orchestrator { async execute( params: ExecuteParams | UniversalExecuteParams, options?: TransactionExecutionOptions + ): Promise { + return this.executeWithPolicy(params, options, false); + } + + /** @internal Sender-preserving batch. Never uses the native sequential fallback. */ + async executeAtomicBatch( + params: ExecuteParams, + options?: TransactionExecutionOptions + ): Promise { + if (typeof params.to !== 'string' || !Array.isArray(params.data) || params.data.length < 2 || params.funds) { + throw new Error('executeAtomicBatch requires multiple Push calls and no signer funds'); + } + return this.executeWithPolicy(params, options, true); + } + + private async executeWithPolicy( + params: ExecuteParams | UniversalExecuteParams, + options: TransactionExecutionOptions | undefined, + requireAtomicBatch: boolean ): Promise { const inlineProgressHook = params.progressHook; if (options || inlineProgressHook) { @@ -449,7 +468,9 @@ export class Orchestrator { ); } return attachPerCallHookForWait( - await _executeStandardPayload(this.ctx, execute, eventBuffer, rcb) + await (requireAtomicBatch + ? _executeStandardPayload(this.ctx, execute, eventBuffer, rcb, { requireAtomicBatch: true }) + : _executeStandardPayload(this.ctx, execute, eventBuffer, rcb)) ); } catch (err) { const errMessage = normalizePublicErrorMessage(err); diff --git a/packages/core/src/lib/orchestrator/orchestrator.types.ts b/packages/core/src/lib/orchestrator/orchestrator.types.ts index 86b190ec..3a5b9f53 100644 --- a/packages/core/src/lib/orchestrator/orchestrator.types.ts +++ b/packages/core/src/lib/orchestrator/orchestrator.types.ts @@ -471,6 +471,15 @@ export interface UniversalTxResponse { /** Transaction route (UOA_TO_PUSH, UOA_TO_CEA, CEA_TO_PUSH, CEA_TO_CEA) */ route?: TransactionRouteType; + /** + * Agentic wallet (AGW) context, present when the transaction executed + * through an AGW. `from` is then the wallet and `origin` stays the signer; + * `agentic.rawTo` / `rawData` hold the wrapped call the signer sent. + * Outbound to/data/value summarize the first encoded destination call; + * `agentic.destinationCalls` retains the complete ordered call list. + */ + agentic?: import('../agentic/agentic.types').AgenticTxMetadata; + // 12. Internal flags /** * @internal True when this response was produced by `trackTransaction` and diff --git a/packages/core/src/lib/orchestrator/route-detector.ts b/packages/core/src/lib/orchestrator/route-detector.ts index 21d543a8..2ed0b15c 100644 --- a/packages/core/src/lib/orchestrator/route-detector.ts +++ b/packages/core/src/lib/orchestrator/route-detector.ts @@ -9,6 +9,7 @@ */ import { CHAIN } from '../constants/enums'; +import { isWeb2ReadChain } from '../constants/read-state'; import { MOVEABLE_TOKENS, type MoveableToken } from '../constants/tokens'; import type { UniversalExecuteParams, @@ -238,8 +239,8 @@ export function validateRouteParams( context?: { clientChain?: CHAIN } ): void { const toChain = isChainTarget(params.to) ? String(params.to.chain) : undefined; - if (String(params.from?.chain ?? '') === CHAIN.WEB2 || toChain === CHAIN.WEB2) { - throw new RouteValidationError('CHAIN.WEB2 is a read-only destination and cannot be used with transaction APIs'); + if (isWeb2ReadChain(String(params.from?.chain ?? '')) || isWeb2ReadChain(toChain)) { + throw new RouteValidationError('READ.CHAIN.WEB2 is a read-only destination and cannot be used with transaction APIs'); } const route = detectRoute(params); diff --git a/packages/core/src/lib/orchestrator/svm-idl/resolve.ts b/packages/core/src/lib/orchestrator/svm-idl/resolve.ts index 444b7760..dbcc2792 100644 --- a/packages/core/src/lib/orchestrator/svm-idl/resolve.ts +++ b/packages/core/src/lib/orchestrator/svm-idl/resolve.ts @@ -43,6 +43,16 @@ const CEA_AUTHORITY_NAMES = new Set([ ]); export function resolveSvmCall(input: ResolveInput): ResolvedSvmCall { + return resolveCall(input); +} + +/** Internal AGW seam: use its registry-derived authority, not the signer's CEA. */ +export function resolveSvmCallForCea(input: ResolveInput, ceaAuthority: `0x${string}`): ResolvedSvmCall { + if (!/^0x[0-9a-fA-F]{64}$/.test(ceaAuthority)) throw new Error('SVM CEA authority must be 32 bytes'); + return resolveCall(input, ceaAuthority); +} + +function resolveCall(input: ResolveInput, authority?: `0x${string}`): ResolvedSvmCall { const idl = getIdl(input.programAddress); if (!idl) { throw new Error( @@ -74,11 +84,7 @@ export function resolveSvmCall(input: ResolveInput): ResolvedSvmCall { const programPk = new PublicKey( Buffer.from(input.programAddress.slice(2), 'hex') ); - const { address: ceaPdaHex } = deriveSvmCeaPda( - input.senderUea, - input.targetChain, - true - ); + const ceaPdaHex = authority ?? deriveSvmCeaPda(input.senderUea, input.targetChain, true).address; const accounts: SvmGatewayAccountMeta[] = []; for (const item of ix.accounts) { diff --git a/packages/core/src/lib/progress-hook/__tests__/response-invariant.spec.ts b/packages/core/src/lib/progress-hook/__tests__/response-invariant.spec.ts index b4d683ed..98feda7d 100644 --- a/packages/core/src/lib/progress-hook/__tests__/response-invariant.spec.ts +++ b/packages/core/src/lib/progress-hook/__tests__/response-invariant.spec.ts @@ -170,6 +170,15 @@ const STUB_ARGS: Record = { [PROGRESS_HOOK.UEA_MIG_9901]: ['v2.0.0'], [PROGRESS_HOOK.UEA_MIG_9902]: [], [PROGRESS_HOOK.UEA_MIG_9903]: [], + // Agentic wallet + [PROGRESS_HOOK.AGENTIC_TX_101]: ['0xwallet', 0, false], + [PROGRESS_HOOK.AGENTIC_TX_102]: ['0xwallet', 'atomic'], + [PROGRESS_HOOK.AGENTIC_TX_104]: [['0xrule']], + [PROGRESS_HOOK.AGENTIC_TX_105]: [{ rulesIds: ['0xrule'] }], + [PROGRESS_HOOK.AGENTIC_TX_106]: ['label'], + [PROGRESS_HOOK.AGENTIC_TX_107]: ['0xrule', 'eip155:42101', 'agent'], + [PROGRESS_HOOK.AGENTIC_TX_199_01]: ['create', '0xhash'], + [PROGRESS_HOOK.AGENTIC_TX_199_02]: ['create', 'NO_RULES_FOR_CHAIN', 'no rule', { name: 'X' }], // Read state (READ-TX 101–199, 001/999) — positional args as in progress-hook.ts [PROGRESS_HOOK.READ_TX_101]: ['eip155:11155111', 'eip155', 0], [PROGRESS_HOOK.READ_TX_102_01]: ['eip155:11155111'], diff --git a/packages/core/src/lib/progress-hook/progress-hook.ts b/packages/core/src/lib/progress-hook/progress-hook.ts index ccc977fc..821950fb 100644 --- a/packages/core/src/lib/progress-hook/progress-hook.ts +++ b/packages/core/src/lib/progress-hook/progress-hook.ts @@ -8,6 +8,7 @@ import { formatPc, normalizePcInsufficientFundsError } from '../formatters'; import { Utils } from '../utils'; import { PROGRESS_HOOK, + PROGRESS_HOOK_AGENTIC, PROGRESS_HOOK_MIG, PROGRESS_HOOK_READ, PROGRESS_HOOK_MULTICHAIN, @@ -1593,6 +1594,79 @@ const RAW_HOOKS_READ: { }), }; +// ============================================================================= +// Agentic wallet (AGW) — AGENTIC-TX (spec 3.f, PROPOSED). No AGENTIC-TX-103. +// ============================================================================= + +type AgenticDecodedError = { name?: string; hint?: string; selector?: string; decoded?: string }; + +const RAW_HOOKS_AGENTIC: { + [K in PROGRESS_HOOK_AGENTIC]: ProgressEventFunctionWithoutTimestamp; +} = { + [PROGRESS_HOOK.AGENTIC_TX_101]: (address: string, index: number, deployed: boolean) => ({ + id: PROGRESS_HOOK.AGENTIC_TX_101, + title: 'Agentic Wallet Derived', + message: `Wallet ${address} at index ${index} (${deployed ? 'deployed' : 'not deployed'}).`, + response: { address, index, deployed }, + level: 'INFO', + }), + [PROGRESS_HOOK.AGENTIC_TX_102]: (address: string, strategy: string) => ({ + id: PROGRESS_HOOK.AGENTIC_TX_102, + title: 'Deploy Step Added', + message: `Deploying agentic wallet ${address} (${strategy}).`, + response: { address, strategy }, + level: 'INFO', + }), + [PROGRESS_HOOK.AGENTIC_TX_104]: (rulesIds: string[]) => ({ + id: PROGRESS_HOOK.AGENTIC_TX_104, + title: 'Rules Granted', + message: `Granted ${rulesIds.length} rule${rulesIds.length === 1 ? '' : 's'}.`, + response: { rulesIds }, + level: 'INFO', + }), + [PROGRESS_HOOK.AGENTIC_TX_105]: (target: { rulesIds: string[] } | { all: true }) => ({ + id: PROGRESS_HOOK.AGENTIC_TX_105, + title: 'Rules Revoked', + message: + 'all' in target + ? 'Revoked every rule on the wallet.' + : `Revoked ${target.rulesIds.length} rule${target.rulesIds.length === 1 ? '' : 's'}.`, + response: target, + level: 'INFO', + }), + [PROGRESS_HOOK.AGENTIC_TX_106]: (label: string) => ({ + id: PROGRESS_HOOK.AGENTIC_TX_106, + title: 'Label Set', + message: `Wallet label set to "${label}".`, + response: { label }, + level: 'INFO', + }), + [PROGRESS_HOOK.AGENTIC_TX_107]: (rulesId: string | undefined, chainNamespace: string, door: 'owner' | 'agent') => ({ + id: PROGRESS_HOOK.AGENTIC_TX_107, + title: 'Rule Resolved', + message: + door === 'owner' + ? `Owner door on ${chainNamespace}; no rule applies.` + : `Agent door on ${chainNamespace} under rule ${rulesId}.`, + response: { rulesId: rulesId ?? null, chainNamespace, door }, + level: 'INFO', + }), + [PROGRESS_HOOK.AGENTIC_TX_199_01]: (operation: string, txHash?: string) => ({ + id: PROGRESS_HOOK.AGENTIC_TX_199_01, + title: 'Agentic Operation Done', + message: `${operation} completed.`, + response: { operation, txHash: txHash ?? null }, + level: 'SUCCESS', + }), + [PROGRESS_HOOK.AGENTIC_TX_199_02]: (operation: string, code: string, message: string, decodedError?: AgenticDecodedError) => ({ + id: PROGRESS_HOOK.AGENTIC_TX_199_02, + title: 'Agentic Operation Failed', + message: `${operation} failed: ${message}`, + response: { operation, code, decodedError: decodedError ?? null }, + level: 'ERROR', + }), +}; + // Combine all routes into the master record const RAW_HOOKS: { [K in PROGRESS_HOOK]: ProgressEventFunctionWithoutTimestamp; @@ -1603,6 +1677,7 @@ const RAW_HOOKS: { ...RAW_HOOKS_MULTICHAIN, ...RAW_HOOKS_MIG, ...RAW_HOOKS_READ, + ...RAW_HOOKS_AGENTIC, }; // Build final hooks with timestamp injection diff --git a/packages/core/src/lib/progress-hook/progress-hook.types.ts b/packages/core/src/lib/progress-hook/progress-hook.types.ts index 94954b7e..4935d1cd 100644 --- a/packages/core/src/lib/progress-hook/progress-hook.types.ts +++ b/packages/core/src/lib/progress-hook/progress-hook.types.ts @@ -176,6 +176,17 @@ export enum PROGRESS_HOOK { UEA_MIG_9901 = 'UEA-MIG-9901', UEA_MIG_9902 = 'UEA-MIG-9902', UEA_MIG_9903 = 'UEA-MIG-9903', + + // Agentic wallet (AGW) — AGENTIC-TX (PROPOSED in the AGW SDK spec 3.f). + // AGENTIC-TX-103 was removed by the spec (create no longer funds). + AGENTIC_TX_101 = 'AGENTIC-TX-101', + AGENTIC_TX_102 = 'AGENTIC-TX-102', + AGENTIC_TX_104 = 'AGENTIC-TX-104', + AGENTIC_TX_105 = 'AGENTIC-TX-105', + AGENTIC_TX_106 = 'AGENTIC-TX-106', + AGENTIC_TX_107 = 'AGENTIC-TX-107', + AGENTIC_TX_199_01 = 'AGENTIC-TX-199-01', + AGENTIC_TX_199_02 = 'AGENTIC-TX-199-02', } // Route-scoped TYPE aliases — compile-time narrowing for new emission code. @@ -319,3 +330,13 @@ export type PROGRESS_HOOK_READ = | PROGRESS_HOOK.READ_TX_999_01 | PROGRESS_HOOK.READ_TX_999_02 | PROGRESS_HOOK.READ_TX_999_03; + +export type PROGRESS_HOOK_AGENTIC = + | PROGRESS_HOOK.AGENTIC_TX_101 + | PROGRESS_HOOK.AGENTIC_TX_102 + | PROGRESS_HOOK.AGENTIC_TX_104 + | PROGRESS_HOOK.AGENTIC_TX_105 + | PROGRESS_HOOK.AGENTIC_TX_106 + | PROGRESS_HOOK.AGENTIC_TX_107 + | PROGRESS_HOOK.AGENTIC_TX_199_01 + | PROGRESS_HOOK.AGENTIC_TX_199_02; diff --git a/packages/core/src/lib/push-chain/push-chain.ts b/packages/core/src/lib/push-chain/push-chain.ts index 9dc13208..5939f461 100644 --- a/packages/core/src/lib/push-chain/push-chain.ts +++ b/packages/core/src/lib/push-chain/push-chain.ts @@ -47,7 +47,32 @@ import { type ReadTrackOptions, type ReadExecuteOptions, } from '../read-state/read-params'; -import { assertRequestEntrypoint, executeReads as executePreparedReads } from '../read-state/read-executor'; +import { assertRequestEntrypoint, executeReads as executePreparedReads, type ReadExecutorDeps } from '../read-state/read-executor'; +import { AgenticNamespaceImpl } from '../agentic/agentic'; +import { resolveAgenticContext, type AgenticExecutionContext } from '../agentic/context'; +import { agenticSend } from '../agentic/execution/send'; +import { notAllowedInAgenticMode } from '../agentic/execution/guards'; +import { adaptTrackedResponse } from '../agentic/response'; +import { createAgenticRuntime, type AgenticRuntime } from '../agentic/runtime'; +import type { AgenticNamespace } from '../agentic/agentic.types'; + +/** Options accepted by `PushChain.initialize` / `reinitialize`. */ +export interface PushChainInitializeOptions { + network: PUSH_NETWORK; + rpcUrls?: Partial>; + blockExplorers?: Partial>; + printTraces?: boolean; + progressHook?: (progress: ProgressEvent) => void; + /** + * Act as this agentic wallet (AGW). The signer decides the door: the owner + * sends through `execute`, an agent named in an enabled rule through + * `executeAsAgent`; anyone else fails with NOT_OWNER_OR_AGENT. + * `universal.account` becomes the wallet; `universal.origin`, + * `getAccountStatus()` and gas stay the signer's. Not inherited by + * `reinitialize` — pass it again to keep acting as the wallet. + */ + agenticWallet?: `0x${string}`; +} /** * @class PushChain @@ -258,6 +283,16 @@ export class PushChain { ) => Promise; }; + /** + * Agentic wallet management (AGW): derive, create, list and per-wallet + * handles. Ownership is the connected signer's Push identity. + */ + agentic: AgenticNamespace; + + /** @internal AGW execution context when initialized with `agenticWallet`. */ + private agenticContext?: AgenticExecutionContext; + private readonly agenticRuntime: AgenticRuntime; + /** * Account status including UEA deployment state and version info. * Initially unloaded — call getAccountStatus() to populate. @@ -293,12 +328,36 @@ export class PushChain { // Default — overwritten in createInstance() with the background fetch this.accountStatusReady = Promise.resolve(); + this.agenticRuntime = createAgenticRuntime(orchestrator, isReadMode); + this.agentic = new AgenticNamespaceImpl(this.agenticRuntime); + + // eslint-disable-next-line @typescript-eslint/no-this-alias -- getters below need the instance + const self = this; + // In agenticWallet mode, request transactions execute through the wallet + // and the wallet pays the request value, so its balance gates the read. + const readDeps = (): ReadExecutorDeps => { + const actx = self.agenticContext; + if (!actx) return orchestrator; + return { + execute: (params, options) => agenticSend(self.agenticRuntime, actx, params, options), + trackRead: orchestrator.trackRead.bind(orchestrator) as Orchestrator['trackRead'], + revalidateRead: orchestrator.revalidateRead.bind(orchestrator), + getProgressHook: orchestrator.getProgressHook.bind(orchestrator), + getReadBalance: () => self.agenticRuntime.reader.getBalance({ address: actx.wallet }), + }; + }; + // Unspent read budget returns to whoever paid it: the wallet in agentic mode. + const withReadRefund = (options: T): T => + self.agenticContext && options.refundTo === undefined + ? { ...options, refundTo: self.agenticContext.wallet } + : options; + this.universal = { get origin() { return orchestrator.getUOA(); }, get account() { - return orchestrator.computeUEAOffchain(); + return self.agenticContext?.wallet ?? orchestrator.computeUEAOffchain(); }, sendTransaction: (...args) => { if (this.isReadMode) { @@ -306,12 +365,16 @@ export class PushChain { 'Read only mode cannot call sendTransaction function' ); } + if (this.agenticContext) { + return agenticSend(this.agenticRuntime, this.agenticContext, ...args); + } return orchestrator.execute.bind(orchestrator)(...args); }, prepareTransaction: ( params: UniversalExecuteParams, options?: TransactionExecutionOptions ) => { + if (this.agenticContext) throw notAllowedInAgenticMode('prepareTransaction'); return orchestrator.prepareTransaction.bind(orchestrator)( params, options @@ -326,40 +389,44 @@ export class PushChain { 'Read only mode cannot call executeTransactions function' ); } + if (this.agenticContext) throw notAllowedInAgenticMode('executeTransactions'); return orchestrator.createCascadedBuilder(txs, options).send(); }, - trackTransaction: (txHash: string, options?: import('../orchestrator/orchestrator.types').TrackTransactionOptions) => { - return orchestrator.trackTransaction.bind(orchestrator)(txHash, options); + trackTransaction: async (txHash: string, options?: import('../orchestrator/orchestrator.types').TrackTransactionOptions) => { + const tracked = await orchestrator.trackTransaction.bind(orchestrator)(txHash, options); + return adaptTrackedResponse(this.agenticRuntime, tracked); }, migrateCEA: (chain: CHAIN) => { if (this.isReadMode) { throw new Error('Read only mode cannot call migrateCEA function'); } + if (this.agenticContext) throw notAllowedInAgenticMode('migrateCEA'); return orchestrator.migrateCEA.bind(orchestrator)(chain); }, rescueFunds: (params: RescueFundsParams) => { if (this.isReadMode) { throw new Error('Read only mode cannot call rescueFunds function'); } + if (this.agenticContext) throw notAllowedInAgenticMode('rescueFunds'); return orchestrator.rescueFunds.bind(orchestrator)(params); }, // Only read()/executeReads() send transactions; prepare/simulate/track remain read-only. read: async (subject: string, options: O) => { - const params = await resolveReadSpecParams(subject, options, orchestrator.getNetwork(), orchestrator.getRpcUrls()); + const params = await resolveReadSpecParams(subject, withReadRefund(options), orchestrator.getNetwork(), orchestrator.getRpcUrls()); assertRequestEntrypoint(params.callback, 'read'); if (this.isReadMode) throw new Error('Read only mode cannot call read function'); const prepared = await orchestrator.prepareRead(params, options.progressHook); - const { reads: [response] } = await executePreparedReads(orchestrator, [prepared] as const, options); + const { reads: [response] } = await executePreparedReads(readDeps(), [prepared] as const, options); return response as UniversalReadResponse>; }, prepareRead: async (subject: string, options: O & ValidateReadCall) => { - const params = await resolveReadSpecParams(subject, options, orchestrator.getNetwork(), orchestrator.getRpcUrls()); + const params = await resolveReadSpecParams(subject, withReadRefund(options), orchestrator.getNetwork(), orchestrator.getRpcUrls()); return orchestrator.prepareRead(params) as Promise>>; }, executeReads: (async (reads: readonly PreparedRead[], options?: ReadExecuteOptions) => { reads.forEach((r) => assertRequestEntrypoint(r.callback)); if (this.isReadMode) throw new Error('Read only mode cannot call executeReads function'); - return executePreparedReads(orchestrator, reads, options); + return executePreparedReads(readDeps(), reads, options); }) as PushChain['universal']['executeReads'], trackRead: ((ref: { txHash: Hex } | { requestId: Hex | bigint }, options?: ReadTrackOptions & { progressHook?: (e: ProgressEvent) => void }) => { const opts = { ...toLifecycleOptions(options), progressHook: options?.progressHook }; @@ -702,13 +769,7 @@ export class PushChain { */ private static async createInstance( universalSigner: UniversalSigner | UniversalAccount, - options?: { - network: PUSH_NETWORK; - rpcUrls?: Partial>; - blockExplorers?: Partial>; - printTraces?: boolean; - progressHook?: (progress: ProgressEvent) => void; - } + options?: PushChainInitializeOptions ): Promise { const isReadOnly = PushChain.isUniversalAccount(universalSigner); @@ -773,6 +834,16 @@ export class PushChain { // Let execute() await the background fetch instead of re-fetching orchestrator.accountStatusReadyPromise = instance.accountStatusReady; + // Agentic mode: validate the wallet, its generation and the signer's door + // before returning a client. A read-only client may hold the context (so + // universal.account shows the wallet) but every signing path stays closed. + if (options?.agenticWallet !== undefined) { + instance.agenticContext = await resolveAgenticContext( + instance.agenticRuntime, + options.agenticWallet + ); + } + return instance; } @@ -790,13 +861,7 @@ export class PushChain { */ static initialize = async ( universalSigner: UniversalSigner | UniversalAccount, - options?: { - network: PUSH_NETWORK; - rpcUrls?: Partial>; - blockExplorers?: Partial>; - printTraces?: boolean; - progressHook?: (progress: ProgressEvent) => void; - } + options?: PushChainInitializeOptions ): Promise => { return PushChain.createInstance(universalSigner, options); }; @@ -815,27 +880,20 @@ export class PushChain { */ reinitialize = async ( universalSigner: UniversalSigner | UniversalAccount, - options?: { - network: PUSH_NETWORK; - rpcUrls?: Partial>; - blockExplorers?: Partial>; - printTraces?: boolean; - progressHook?: (progress: ProgressEvent) => void; - } + options?: PushChainInitializeOptions ): Promise => { - const mergedOptions = { + // agenticWallet is NOT inherited: an omitted value yields an ordinary + // client, and a supplied one reruns every wallet/role check. + const mergedOptions: PushChainInitializeOptions = { network: options?.network ?? this.orchestrator.getNetwork(), rpcUrls: options?.rpcUrls ?? this.orchestrator.getRpcUrls(), blockExplorers: options?.blockExplorers ?? this.blockExplorers, printTraces: options?.printTraces ?? this.orchestrator.getPrintTraces(), progressHook: options?.progressHook ?? this.orchestrator.getProgressHook(), - } as { - network: PUSH_NETWORK; - rpcUrls?: Partial>; - blockExplorers?: Partial>; - printTraces?: boolean; - progressHook?: (progress: ProgressEvent) => void; + ...(options?.agenticWallet !== undefined + ? { agenticWallet: options.agenticWallet } + : {}), }; return PushChain.createInstance(universalSigner, mergedOptions); }; diff --git a/packages/core/src/lib/read-state/__tests__/public-surface.spec.ts b/packages/core/src/lib/read-state/__tests__/public-surface.spec.ts index d55a2c22..1beef01e 100644 --- a/packages/core/src/lib/read-state/__tests__/public-surface.spec.ts +++ b/packages/core/src/lib/read-state/__tests__/public-surface.spec.ts @@ -17,9 +17,10 @@ describe('read-state public surface', () => { ]) { expect(typeof (core as Record)[fn]).toBe('function'); } - expect(core.CHAIN.WEB2).toBe('web2:https'); - expect(PushChain.CONSTANTS.CHAIN.WEB2).toBe('web2:https'); - expect(Object.values(PushChain.CONSTANTS.CHAIN)).not.toContain('web2:https'); + // CHAIN.WEB2 is the deprecated alias of READ.CHAIN.WEB2 (AGW SDK page §4). + expect(core.CHAIN.WEB2).toBe('web2'); + expect(PushChain.CONSTANTS.CHAIN.WEB2).toBe(PushChain.CONSTANTS.READ.CHAIN.WEB2); + expect(Object.values(PushChain.CONSTANTS.CHAIN)).not.toContain('web2'); expect(core.UNIVERSAL_READ_STATUS.FULFILLED).toBe(3); expect(core.READ_STATUS.ERROR).toBe(2); expect(core.READ_ERROR_CODE.INVALID_QUERY).toBe(1); @@ -30,7 +31,8 @@ describe('read-state public surface', () => { it('PushChain.CONSTANTS.READ pins the contract-derived values', () => { const R = PushChain.CONSTANTS.READ; - expect(R.WEB2).toBe('web2:https'); + expect(R.WEB2).toBe('web2'); + expect(R.CHAIN.WEB2).toBe('web2'); expect(R.MAX_CALLBACK_GAS_LIMIT).toBe(1_000_000n); expect(R.MIN_CONFIRMATIONS_FLOOR).toBe(1); expect(R.DEFAULT_EXPIRY_BLOCKS).toBe(300n); diff --git a/packages/core/src/lib/read-state/__tests__/web2-compat.spec.ts b/packages/core/src/lib/read-state/__tests__/web2-compat.spec.ts new file mode 100644 index 00000000..e964bb7e --- /dev/null +++ b/packages/core/src/lib/read-state/__tests__/web2-compat.spec.ts @@ -0,0 +1,69 @@ +/** + * READ.CHAIN / Web2 compatibility (AGW SDK page §4, confirmed 2026-09-28): + * new enumerable READ.CHAIN.WEB2 = 'web2'; CHAIN.WEB2 and READ.WEB2 stay as + * deprecated aliases; the legacy 'web2:https' literal is still accepted; the + * wire identity the node routes on stays web2:https. + */ +import { PushChain } from '../../index'; +import { CHAIN } from '../../constants/enums'; +import { validateRouteParams } from '../../orchestrator/route-detector'; +import { resolveDestination } from '../destination'; +import { toBuildReadSpecParams, toReadDestination, toReadQuery } from '../read-params'; +import type { ReadChain } from '../read-state.types'; + +const R = PushChain.CONSTANTS.READ; +const web2 = { web2: { extract: [{ path: '$.a', valueType: 'string' as const }] } }; + +describe('READ.CHAIN', () => { + it('is an enumerable superset of CHAIN with WEB2 = "web2"', () => { + const values = Object.values(R.CHAIN); + for (const c of Object.values(CHAIN)) expect(values).toContain(c); + expect(values).toContain('web2'); + expect(Object.keys(R.CHAIN)).toContain('WEB2'); + expect(R.CHAIN.ETHEREUM_SEPOLIA).toBe(CHAIN.ETHEREUM_SEPOLIA); + }); + + it('CHAIN itself still enumerates only blockchains', () => { + expect(Object.keys(CHAIN)).not.toContain('WEB2'); + expect(CHAIN.WEB2).toBe(R.CHAIN.WEB2); + expect(R.WEB2).toBe(R.CHAIN.WEB2); + }); +}); + +describe.each([ + ['READ.CHAIN.WEB2', R.CHAIN.WEB2], + ['deprecated CHAIN.WEB2', CHAIN.WEB2], + ['legacy literal', 'web2:https'], +] as const)('%s', (_name, chain) => { + it('normalizes to the unchanged wire identity', () => { + const dest = resolveDestination(toReadDestination(chain as ReadChain)); + expect(dest).toMatchObject({ chainNamespace: 'web2', chainId: 'https', caip2: 'web2:https', namespace: 'web2' }); + expect(resolveDestination({ chain: chain as ReadChain })).toMatchObject({ caip2: 'web2:https' }); + }); + + it('builds an http query and spec params', () => { + expect(toReadQuery('https://x.test/a', { chain: chain as ReadChain, ...web2 })).toMatchObject({ type: 'http', url: 'https://x.test/a' }); + expect(toBuildReadSpecParams('https://x.test/a', { chain: chain as ReadChain, ...web2 }).destination).toEqual({ + chainNamespace: 'web2', + chainId: 'https', + }); + }); + + it('is rejected by transaction routing', () => { + expect(() => validateRouteParams({ to: { address: '0x0000000000000000000000000000000000000001', chain: chain as never } })).toThrow( + /read-only destination/ + ); + }); +}); + +describe('type-level separation', () => { + it('compiles', () => { + const a: ReadChain = 'web2'; + const b: ReadChain = 'web2:https'; + const c: ReadChain = CHAIN.ETHEREUM_SEPOLIA; + const d: ReadChain = R.CHAIN.WEB2; + // @ts-expect-error — a transaction ChainTarget never accepts the Web2 read source + const t: import('../../orchestrator/orchestrator.types').ChainTarget = { address: '0x', chain: R.CHAIN.WEB2 }; + expect([a, b, c, d, t].length).toBe(5); + }); +}); diff --git a/packages/core/src/lib/read-state/destination.ts b/packages/core/src/lib/read-state/destination.ts index 51b3b7a2..d7b9c268 100644 --- a/packages/core/src/lib/read-state/destination.ts +++ b/packages/core/src/lib/read-state/destination.ts @@ -1,4 +1,4 @@ -import { READ_NAMESPACE, type ReadNamespace } from '../constants/read-state'; +import { READ_NAMESPACE, WEB2_DESTINATION, WEB2_READ_CHAIN, type ReadNamespace } from '../constants/read-state'; import { UnsupportedReadDestinationError } from './errors'; import type { ReadDestination, ResolvedDestination } from './read-state.types'; @@ -17,7 +17,11 @@ const KNOWN: ReadonlySet = new Set(Object.values(READ_NAMESPACE)); export function resolveDestination(dest: ReadDestination): ResolvedDestination { let chainNamespace: string; let chainId: string; - if ('chain' in dest) { + if ('chain' in dest && dest.chain === WEB2_READ_CHAIN) { + // The public 'web2' spelling has no ':'; its wire identity is web2:https. + chainNamespace = WEB2_DESTINATION.chainNamespace; + chainId = WEB2_DESTINATION.chainId; + } else if ('chain' in dest) { const idx = dest.chain.indexOf(':'); if (idx <= 0) { throw new UnsupportedReadDestinationError(`chain is not CAIP-2: ${dest.chain}`); diff --git a/packages/core/src/lib/read-state/read-params.ts b/packages/core/src/lib/read-state/read-params.ts index ca8e5b65..65b18ab3 100644 --- a/packages/core/src/lib/read-state/read-params.ts +++ b/packages/core/src/lib/read-state/read-params.ts @@ -19,11 +19,11 @@ import { detectTokenProgram, resolveAccountName, validateIdl } from './svm-accou import { deriveIdlPda, isProgramSubject } from './svm-pda'; import { CHAIN, PUSH_NETWORK } from '../constants/enums'; import { computeReadQueryKey, resolveReadCallback } from './registry'; -import { READ_NAMESPACE, WEB2_DESTINATION } from '../constants/read-state'; +import { isWeb2ReadChain, READ_NAMESPACE, WEB2_DESTINATION } from '../constants/read-state'; import { resolveDestination } from './destination'; import { deriveAssociatedTokenAddress } from './envelopes/svm'; import { InvalidReadQueryError } from './errors'; -import type { BuildReadSpecParams, ReadChain, ReadDestination, ReadLifecycleOptions, ReadQuery, ReadResultShape, Web2Extract } from './read-state.types'; +import type { BuildReadSpecParams, ReadChain, ReadDestination, ReadLifecycleOptions, ReadQuery, ReadResultShape, Web2Extract, Web2ReadChain } from './read-state.types'; import type { ReadCallback } from './read-state.types'; import type { ProgressEvent } from '../progress-hook/progress-hook.types'; @@ -106,7 +106,7 @@ export type ReadQueryOptions = | ({ chain: SvmChain } & Query<'idl' | 'functionName' | 'args', { idl: Idl; functionName?: string; args?: readonly unknown[] }>) | ({ chain: EvmChain } & Query<'abi' | 'functionName' | 'args', { abi: Abi; functionName: string; args?: readonly unknown[] }>) | ({ chain: EvmChain } & Query<'storageSlot', { storageSlot: Hex | bigint }>) - | ({ chain: typeof CHAIN.WEB2 } & Query<'web2', { web2: ReadWeb2Options }>); + | ({ chain: Web2ReadChain } & Query<'web2', { web2: ReadWeb2Options }>); export type ReadCallbackOptions = { callback?: @@ -122,7 +122,7 @@ type FinalizedDestinationOptions = { blockNumber?: never; minConfirmations?: nev /** EVM reads expose pinning; SVM and Web2 choose their finalized/heightless references internally. */ export type ReadPrepareOptions = SharedPrepareOptions & ( | (Extract & EvmPinningOptions) - | (Extract & FinalizedDestinationOptions) + | (Extract & FinalizedDestinationOptions) ); export type ReadExecuteOptions = Pick; type WithExecutionOptions = T extends unknown @@ -196,7 +196,8 @@ function queryKind(o: ReadOptionsInput): (typeof QUERY_KEYS)[number] | 'native' } export function toReadDestination(chain: ReadChain): ReadDestination { - return chain === CHAIN.WEB2 ? WEB2_DESTINATION : { chain }; + // Both public spellings normalize to the unchanged wire identity web2:https. + return isWeb2ReadChain(chain) ? WEB2_DESTINATION : { chain }; } /** Build the internal query from the public grammar. Pure. */ @@ -209,7 +210,7 @@ export function toReadQuery(subject: string, o: ReadOptionsInput, resolvedTokenP if (!/^https:\/\//i.test(subject)) throw new InvalidReadQueryError('web2 subject must be an https:// URL'); return { type: 'http', url: subject, ...o.web2 }; } - if (kind === 'web2') throw new InvalidReadQueryError('`web2` is only valid with chain CHAIN.WEB2'); + if (kind === 'web2') throw new InvalidReadQueryError('`web2` is only valid with chain READ.CHAIN.WEB2'); if (dest.namespace === READ_NAMESPACE.EVM) { if (!isAddress(subject)) throw new InvalidReadQueryError(`EVM subject must be an address, got ${subject}`); diff --git a/packages/core/src/lib/read-state/read-state.types.ts b/packages/core/src/lib/read-state/read-state.types.ts index 6639c275..4f738085 100644 --- a/packages/core/src/lib/read-state/read-state.types.ts +++ b/packages/core/src/lib/read-state/read-state.types.ts @@ -11,7 +11,9 @@ import type { ReadNamespace } from '../constants/read-state'; * Where a read goes. `CHAIN` enum values are CAIP-2 and split cleanly; the * explicit form is the low-level escape hatch; the public API uses `CHAIN.WEB2`. */ -export type ReadChain = CHAIN | typeof CHAIN.WEB2; +/** Web2 read source: `READ.CHAIN.WEB2` (`'web2'`) or the legacy `'web2:https'` literal. */ +export type Web2ReadChain = 'web2' | 'web2:https'; +export type ReadChain = CHAIN | Web2ReadChain; export type ReadDestination = { chain: ReadChain } | { chainNamespace: string; chainId: string }; export type ResolvedDestination = { diff --git a/packages/core/src/lib/read-state/read-tracker.ts b/packages/core/src/lib/read-state/read-tracker.ts index 991c698d..79f891c0 100644 --- a/packages/core/src/lib/read-state/read-tracker.ts +++ b/packages/core/src/lib/read-state/read-tracker.ts @@ -26,6 +26,8 @@ import { READ_TRACK_MAX_TIMEOUT_MS, READ_TRACK_MIN_POLL_INTERVAL_MS, READ_TRACK_POLL_INTERVAL_MS, + WEB2_READ_CHAIN, + isWeb2ReadChain, } from '../constants/read-state'; import type { UniversalRead } from '../generated/ucallback/v1'; import { PROGRESS_HOOK } from '../progress-hook/progress-hook.types'; @@ -343,8 +345,8 @@ export function inferResultShape(namespace: string, query: Hex): ReadResultShape } } -function chainFromCaip2(caip2: string): CHAIN | typeof CHAIN.WEB2 | undefined { - if (caip2 === CHAIN.WEB2) return CHAIN.WEB2; +function chainFromCaip2(caip2: string): CHAIN | typeof WEB2_READ_CHAIN | undefined { + if (isWeb2ReadChain(caip2)) return WEB2_READ_CHAIN; return (Object.values(CHAIN) as string[]).includes(caip2) ? (caip2 as CHAIN) : undefined; } diff --git a/packages/core/src/lib/read-state/spec-builder.ts b/packages/core/src/lib/read-state/spec-builder.ts index 52641100..99b04efd 100644 --- a/packages/core/src/lib/read-state/spec-builder.ts +++ b/packages/core/src/lib/read-state/spec-builder.ts @@ -13,7 +13,7 @@ import { import { UNIVERSAL_CALLBACK_EVM } from '../constants/abi/universalCallback.evm'; import { UEA_FACTORY_ABI } from '../constants/abi/uea-factory'; import { UEA_FACTORY } from '../constants/chain'; -import { DEFAULT_EXPIRY_BLOCKS, MIN_CONFIRMATIONS_FLOOR, READ_NAMESPACE, READ_PREFLIGHT_STALE_MS } from '../constants/read-state'; +import { DEFAULT_EXPIRY_BLOCKS, MIN_CONFIRMATIONS_FLOOR, READ_NAMESPACE, READ_PREFLIGHT_STALE_MS, WEB2_READ_CHAIN } from '../constants/read-state'; import { sizeCallbackBudget } from './budget'; import { computeReadQueryKey } from './registry'; import { resolveDestination } from './destination'; @@ -137,7 +137,7 @@ export function buildReadSpecFromPreflight( return { callback: params.callback, queryKey: computeReadQueryKey(params.destination, params.query), - chain: dest.caip2 as ReadChain, + chain: (isWeb2 ? WEB2_READ_CHAIN : dest.caip2) as ReadChain, spec, specTuple: toTuple(spec), encodedSpec: encodeSpec(spec), diff --git a/packages/core/src/lib/universal/prc20-address.ts b/packages/core/src/lib/universal/prc20-address.ts new file mode 100644 index 00000000..693aa28e --- /dev/null +++ b/packages/core/src/lib/universal/prc20-address.ts @@ -0,0 +1,168 @@ +import { CHAIN, PUSH_NETWORK } from '../constants/enums'; +import { MOVEABLE_TOKENS, type MoveableToken } from '../constants/tokens'; +import { SYNTHETIC_PUSH_ERC20 } from '../constants/chain'; + +/** Shared pure origin-to-PRC20 mapping; no signer or network reads. */ +export function getPRC20Address( + token: MoveableToken | { chain: string; address: string }, + options?: { network?: PUSH_NETWORK } +): { + address: `0x${string}`; + chain: CHAIN; + symbol: string; + decimals: number; + network: PUSH_NETWORK; +} { + const network = options?.network ?? PUSH_NETWORK.TESTNET_DONUT; + + const assertDeployed = ( + addr: string | undefined, + ctx: string + ): `0x${string}` => { + if (!addr || addr === '0xTBD') { + throw new Error( + `PRC20 address not available for ${ctx} on network ${network}` + ); + } + return addr as `0x${string}`; + }; + + // PushChainMoveableToken (pETH, pSOL, pUSDT(BNB), …) carries its PRC-20 address + // and origin `sourceChain` directly — no registry lookup needed. + const pcToken = token as Partial<{ + prc20Address: `0x${string}`; + sourceChain: CHAIN; + symbol: string; + decimals: number; + }>; + if (pcToken.prc20Address) { + return { + address: assertDeployed( + pcToken.prc20Address, + `${pcToken.symbol ?? 'token'} (${pcToken.sourceChain ?? 'unknown'})` + ), + chain: pcToken.sourceChain as CHAIN, + symbol: pcToken.symbol as string, + decimals: pcToken.decimals as number, + network, + }; + } + + // Infer origin chain, symbol, decimals by matching against MOVEABLE_TOKENS + let originChain: CHAIN | undefined; + let tokenSymbol: string | undefined; + let tokenDecimals: number | undefined; + + if ('symbol' in token) { + // MoveableToken path: infer chain by symbol + address + for (const [key, list] of Object.entries(MOVEABLE_TOKENS)) { + const k = key as CHAIN; + const match = (list ?? []).find( + (t) => t.symbol === token.symbol && t.address === token.address + ); + if (match) { + originChain = k; + tokenSymbol = match.symbol; + tokenDecimals = match.decimals; + break; + } + } + } else { + // { chain, address } path: trust the provided chain and resolve symbol via registry + originChain = token.chain as CHAIN; + const list = MOVEABLE_TOKENS[originChain] ?? []; + const match = list.find((t) => t.address === token.address); + if (match) { + tokenSymbol = match.symbol; + tokenDecimals = match.decimals; + } + } + + if (!originChain || !tokenSymbol || tokenDecimals === undefined) { + throw new Error('Unable to infer origin chain or token symbol for token'); + } + + const map = SYNTHETIC_PUSH_ERC20[network]; + if (!map) { + throw new Error(`No PRC20 address map configured for network: ${network}`); + } + + // Map token → synthetic key by origin chain family + const isEthFamily = + originChain === CHAIN.ETHEREUM_MAINNET || + originChain === CHAIN.ETHEREUM_SEPOLIA; + const isArbFamily = originChain === CHAIN.ARBITRUM_SEPOLIA; + const isBaseFamily = originChain === CHAIN.BASE_SEPOLIA; + const isBnbFamily = originChain === CHAIN.BNB_TESTNET; + const isSolFamily = originChain === CHAIN.SOLANA_DEVNET; + + let key: + | 'pETH' + | 'pETH_ARB' + | 'pETH_BASE' + | 'pBNB' + | 'pSOL' + | 'USDT_ETH' + | 'USDT_ARB' + | 'USDT_SOL' + | 'USDT_BSC' + | 'USDT_BASE' + | 'USDC_ETH' + | 'USDC_ARB' + | 'USDC_SOL' + | 'USDC_BSC' + | 'USDC_BASE'; + + switch (tokenSymbol) { + case 'ETH': { + if (isEthFamily) key = 'pETH'; + else if (isArbFamily) key = 'pETH_ARB'; + else if (isBaseFamily) key = 'pETH_BASE'; + else + throw new Error('Unsupported ETH origin chain for synthetic mapping'); + break; + } + case 'SOL': { + if (!isSolFamily) + throw new Error('SOL token provided but origin is not Solana'); + key = 'pSOL'; + break; + } + case 'BNB': { + if (!isBnbFamily) + throw new Error('BNB token provided but origin is not BNB Testnet'); + key = 'pBNB'; + break; + } + case 'USDT': { + if (isEthFamily) key = 'USDT_ETH'; + else if (isArbFamily) key = 'USDT_ARB'; + else if (isBaseFamily) key = 'USDT_BASE'; + else if (isBnbFamily) key = 'USDT_BSC'; + else if (isSolFamily) key = 'USDT_SOL'; + else + throw new Error('Unsupported USDT origin chain for synthetic mapping'); + break; + } + case 'USDC': { + if (isEthFamily) key = 'USDC_ETH'; + else if (isArbFamily) key = 'USDC_ARB'; + else if (isBaseFamily) key = 'USDC_BASE'; + else if (isBnbFamily) key = 'USDC_BSC'; + else if (isSolFamily) key = 'USDC_SOL'; + else + throw new Error('Unsupported USDC origin chain for synthetic mapping'); + break; + } + default: + throw new Error(`Unsupported token symbol: ${tokenSymbol}`); + } + + return { + address: assertDeployed(map[key], `${tokenSymbol} on ${originChain}`), + chain: originChain, + symbol: tokenSymbol, + decimals: tokenDecimals, + network, + }; +} diff --git a/packages/core/src/lib/utils.ts b/packages/core/src/lib/utils.ts index 7670f2c3..3fa4d979 100644 --- a/packages/core/src/lib/utils.ts +++ b/packages/core/src/lib/utils.ts @@ -18,7 +18,7 @@ import { PAYABLE_TOKENS, type MoveableToken, } from './constants/tokens'; -import { SYNTHETIC_PUSH_ERC20 } from './constants/chain'; +import { getPRC20Address } from './universal/prc20-address'; import { UniversalAccount } from './universal/universal.types'; import type { PushChain } from './push-chain/push-chain'; import { encodeFunctionData, formatUnits, getAddress } from 'viem'; @@ -31,6 +31,7 @@ import { import { PC20WrapperNotRegisteredError } from './orchestrator/internals/pc20/errors'; import { getPushChainForNetwork } from './orchestrator/internals/helpers'; import { Buffer } from 'buffer'; +import { agenticUtils } from './agentic/utils'; import type { Idl } from '@coral-xyz/anchor'; import { encodeAnchorIxData, @@ -309,7 +310,8 @@ export class Utils { } // SVM path: explicit idl, or legacy abi-as-IDL for backward compat. - const svmIdl: Idl | undefined = idl ?? (isAnchorIdl(abi) ? abi : undefined); + const svmIdl: Idl | undefined = + idl ?? (isAnchorIdl(abi) ? abi : undefined); if (svmIdl) { registerSvmIdl(svmIdl); const bytes = encodeAnchorIxData(svmIdl, functionName, args); @@ -771,179 +773,7 @@ export class Utils { * }); * ``` */ - getPRC20Address( - token: MoveableToken | { chain: string; address: string }, - options?: { network?: PUSH_NETWORK } - ): { - address: `0x${string}`; - chain: CHAIN; - symbol: string; - decimals: number; - network: PUSH_NETWORK; - } { - const network = options?.network ?? PUSH_NETWORK.TESTNET_DONUT; - - const assertDeployed = ( - addr: string | undefined, - ctx: string - ): `0x${string}` => { - if (!addr || addr === '0xTBD') { - throw new Error( - `PRC20 address not available for ${ctx} on network ${network}` - ); - } - return addr as `0x${string}`; - }; - - // PushChainMoveableToken (pETH, pSOL, pUSDT(BNB), …) carries its PRC-20 address - // and origin `sourceChain` directly — no registry lookup needed. - const pcToken = token as Partial<{ - prc20Address: `0x${string}`; - sourceChain: CHAIN; - symbol: string; - decimals: number; - }>; - if (pcToken.prc20Address) { - return { - address: assertDeployed( - pcToken.prc20Address, - `${pcToken.symbol ?? 'token'} (${pcToken.sourceChain ?? 'unknown'})` - ), - chain: pcToken.sourceChain as CHAIN, - symbol: pcToken.symbol as string, - decimals: pcToken.decimals as number, - network, - }; - } - - // Infer origin chain, symbol, decimals by matching against MOVEABLE_TOKENS - let originChain: CHAIN | undefined; - let tokenSymbol: string | undefined; - let tokenDecimals: number | undefined; - - if ('symbol' in token) { - // MoveableToken path: infer chain by symbol + address - for (const [key, list] of Object.entries(MOVEABLE_TOKENS)) { - const k = key as CHAIN; - const match = (list ?? []).find( - (t) => t.symbol === token.symbol && t.address === token.address - ); - if (match) { - originChain = k; - tokenSymbol = match.symbol; - tokenDecimals = match.decimals; - break; - } - } - } else { - // { chain, address } path: trust the provided chain and resolve symbol via registry - originChain = token.chain as CHAIN; - const list = MOVEABLE_TOKENS[originChain] ?? []; - const match = list.find((t) => t.address === token.address); - if (match) { - tokenSymbol = match.symbol; - tokenDecimals = match.decimals; - } - } - - if (!originChain || !tokenSymbol || tokenDecimals === undefined) { - throw new Error( - 'Unable to infer origin chain or token symbol for token' - ); - } - - const map = SYNTHETIC_PUSH_ERC20[network]; - if (!map) { - throw new Error( - `No PRC20 address map configured for network: ${network}` - ); - } - - // Map token → synthetic key by origin chain family - const isEthFamily = - originChain === CHAIN.ETHEREUM_MAINNET || - originChain === CHAIN.ETHEREUM_SEPOLIA; - const isArbFamily = originChain === CHAIN.ARBITRUM_SEPOLIA; - const isBaseFamily = originChain === CHAIN.BASE_SEPOLIA; - const isBnbFamily = originChain === CHAIN.BNB_TESTNET; - const isSolFamily = originChain === CHAIN.SOLANA_DEVNET; - - let key: - | 'pETH' - | 'pETH_ARB' - | 'pETH_BASE' - | 'pBNB' - | 'pSOL' - | 'USDT_ETH' - | 'USDT_ARB' - | 'USDT_SOL' - | 'USDT_BSC' - | 'USDT_BASE' - | 'USDC_ETH' - | 'USDC_ARB' - | 'USDC_SOL' - | 'USDC_BSC' - | 'USDC_BASE'; - - switch (tokenSymbol) { - case 'ETH': { - if (isEthFamily) key = 'pETH'; - else if (isArbFamily) key = 'pETH_ARB'; - else if (isBaseFamily) key = 'pETH_BASE'; - else - throw new Error( - 'Unsupported ETH origin chain for synthetic mapping' - ); - break; - } - case 'SOL': { - if (!isSolFamily) - throw new Error('SOL token provided but origin is not Solana'); - key = 'pSOL'; - break; - } - case 'BNB': { - if (!isBnbFamily) - throw new Error('BNB token provided but origin is not BNB Testnet'); - key = 'pBNB'; - break; - } - case 'USDT': { - if (isEthFamily) key = 'USDT_ETH'; - else if (isArbFamily) key = 'USDT_ARB'; - else if (isBaseFamily) key = 'USDT_BASE'; - else if (isBnbFamily) key = 'USDT_BSC'; - else if (isSolFamily) key = 'USDT_SOL'; - else - throw new Error( - 'Unsupported USDT origin chain for synthetic mapping' - ); - break; - } - case 'USDC': { - if (isEthFamily) key = 'USDC_ETH'; - else if (isArbFamily) key = 'USDC_ARB'; - else if (isBaseFamily) key = 'USDC_BASE'; - else if (isBnbFamily) key = 'USDC_BSC'; - else if (isSolFamily) key = 'USDC_SOL'; - else - throw new Error( - 'Unsupported USDC origin chain for synthetic mapping' - ); - break; - } - default: - throw new Error(`Unsupported token symbol: ${tokenSymbol}`); - } - - return { - address: assertDeployed(map[key], `${tokenSymbol} on ${originChain}`), - chain: originChain, - symbol: tokenSymbol, - decimals: tokenDecimals, - network, - }; - }, + getPRC20Address, /** * Resolve a PC20 token against UniversalCore's on-chain registry, and list @@ -1042,6 +872,13 @@ export class Utils { }, }; + /** + * Agentic wallet (AGW) pure helpers: rulesId, actionId, configId, + * deriveWallet, encodeRules, decodeRules, compileCard. Generation context is + * explicit (provisional signatures, A04); no RPC is performed. + */ + static agentic = agenticUtils; + /** * Internal: resolves a CHAIN enum from either a CHAIN value or a PushChain client instance. */ diff --git a/packages/core/src/lib/vm-client/evm-client.batch-gas.spec.ts b/packages/core/src/lib/vm-client/evm-client.batch-gas.spec.ts new file mode 100644 index 00000000..d117592e --- /dev/null +++ b/packages/core/src/lib/vm-client/evm-client.batch-gas.spec.ts @@ -0,0 +1,75 @@ +import { bytesToHex, parseTransaction } from 'viem'; +import { EvmClient } from './evm-client'; +import { CHAIN } from '../constants/enums'; +import type { UniversalSigner } from '../universal/universal.types'; +const account = '0x3333333333333333333333333333333333333333', + executor = '0x4444444444444444444444444444444444444444'; +function fixture() { + const client = new EvmClient({ rpcUrls: ['http://localhost:8545'] }); + const estimateGas = jest.fn(), + send = jest + .fn, [Uint8Array]>() + .mockResolvedValue(new Uint8Array(32)); + client.publicClient = { + estimateGas, + getCode: jest.fn().mockResolvedValue('0xef0100' + executor.slice(2)), + estimateFeesPerGas: jest.fn().mockResolvedValue({ + maxFeePerGas: BigInt(10), + maxPriorityFeePerGas: BigInt(1), + }), + getChainId: jest.fn().mockResolvedValue(42101), + getTransactionCount: jest.fn().mockResolvedValue(5), + } as never; + const signer: UniversalSigner = { + account: { chain: CHAIN.PUSH_TESTNET_DONUT, address: account }, + signMessage: async (x) => x, + signAuthorization: jest.fn().mockResolvedValue({ + address: executor, + chainId: 42101, + nonce: 6, + yParity: 0, + r: '0x' + '11'.repeat(32), + s: '0x' + '22'.repeat(32), + }), + signAndSendTransaction: send, + }; + const run = () => + client.sendBatch7702({ + executor, + signer, + calls: [ + { to: executor, value: BigInt(0), data: '0x12345678' }, + { to: executor, value: BigInt(0), data: '0x12345678' }, + ], + }); + return { client, estimateGas, send, run }; +} +describe('7702 estimation without guessed per-call ceilings', () => { + it('uses a real estimate for an already delegated account when authorization RPC support is absent', async () => { + const f = fixture(); + f.estimateGas + .mockRejectedValueOnce(new Error('unsupported auth list')) + .mockResolvedValueOnce(BigInt(1_400_000)); + await f.run(); + const tx = parseTransaction(bytesToHex(f.send.mock.calls[0][0])); + expect(tx.gas).toBe(BigInt(1_705_000)); + expect(f.estimateGas.mock.calls[1][0]).not.toHaveProperty('stateOverride'); + }); + it('uses a delegation override for a fresh account only when authorization estimation fails', async () => { + const f = fixture(); + (f.client.publicClient.getCode as jest.Mock).mockResolvedValue('0x'); + f.estimateGas + .mockRejectedValueOnce(new Error('unsupported')) + .mockResolvedValueOnce(BigInt(2_000_000)); + await f.run(); + expect(f.estimateGas.mock.calls[1][0].stateOverride[0].code).toBe( + '0xef0100' + executor.slice(2) + ); + }); + it('does not broadcast a guessed gas budget when all supported estimates fail', async () => { + const f = fixture(); + f.estimateGas.mockRejectedValue(new Error('execution rejected')); + await expect(f.run()).rejects.toThrow('execution rejected'); + expect(f.send).not.toHaveBeenCalled(); + }); +}); diff --git a/packages/core/src/lib/vm-client/evm-client.dynamic-gas.spec.ts b/packages/core/src/lib/vm-client/evm-client.dynamic-gas.spec.ts index 97ef53af..bfdf2191 100644 --- a/packages/core/src/lib/vm-client/evm-client.dynamic-gas.spec.ts +++ b/packages/core/src/lib/vm-client/evm-client.dynamic-gas.spec.ts @@ -25,7 +25,7 @@ describe('EvmClient dynamic gas estimation', () => { .fn() .mockImplementation(async (unsignedTx: Uint8Array) => { const parsed = parseTransaction(bytesToHex(unsignedTx)); - expect(parsed.gas).toBe(estimatedGas); + expect(parsed.gas).toBe(BigInt(969_600)); expect(parsed.nonce).toBe(9); return Uint8Array.from(Buffer.from(TX_HASH.slice(2), 'hex')); }); @@ -57,9 +57,9 @@ describe('EvmClient dynamic gas estimation', () => { const estimatedGas = BigInt(21_062); const client = new EvmClient({ rpcUrls: ['http://localhost:8545'] }); client.publicClient = { - getCode: jest.fn().mockResolvedValue( - '0xef01000106bf2f9b02f32203a83a3bdad79fe8818f3796' - ), + getCode: jest + .fn() + .mockResolvedValue('0xef01000106bf2f9b02f32203a83a3bdad79fe8818f3796'), estimateGas: jest.fn().mockResolvedValue(estimatedGas), estimateFeesPerGas: jest.fn().mockResolvedValue({ maxFeePerGas: BigInt(10), @@ -73,7 +73,7 @@ describe('EvmClient dynamic gas estimation', () => { .fn() .mockImplementation(async (unsignedTx: Uint8Array) => { const parsed = parseTransaction(bytesToHex(unsignedTx)); - expect(parsed.gas).toBe(estimatedGas); + expect(parsed.gas).toBe(BigInt(25_275)); return Uint8Array.from(Buffer.from(TX_HASH.slice(2), 'hex')); }); const signer: UniversalSigner = { @@ -137,4 +137,45 @@ describe('EvmClient dynamic gas estimation', () => { expect(client.publicClient.estimateGas).not.toHaveBeenCalled(); }); + + it.each([ + { explicitGas: undefined, expectedGas: BigInt(579_802) }, + { explicitGas: BigInt(500_000), expectedGas: BigInt(500_000) }, + ])( + 'adds headroom for the observed AGW outbound estimate unless gas is explicit ($explicitGas)', + async ({ explicitGas, expectedGas }) => { + // At the same Donut block, this estimate reverted while 500,000 gas passed. + const client = new EvmClient({ rpcUrls: ['http://localhost:8545'] }); + client.publicClient = { + estimateGas: jest.fn().mockResolvedValue(BigInt(483_168)), + estimateFeesPerGas: jest.fn().mockResolvedValue({ + maxFeePerGas: BigInt(10), + maxPriorityFeePerGas: BigInt(1), + }), + getChainId: jest.fn().mockResolvedValue(42101), + } as unknown as typeof client.publicClient; + const signer: UniversalSigner = { + account: { chain: CHAIN.PUSH_TESTNET_DONUT, address: ACCOUNT }, + signMessage: async (data) => data, + signAndSendTransaction: jest.fn(async (unsignedTx: Uint8Array) => { + expect(parseTransaction(bytesToHex(unsignedTx)).gas).toBe( + expectedGas + ); + return Uint8Array.from(Buffer.from(TX_HASH.slice(2), 'hex')); + }), + }; + + await client.sendTransaction({ + to: TARGET, + data: '0x12345678', + signer, + nonce: 12, + gas: explicitGas, + }); + + expect(client.publicClient.estimateGas).toHaveBeenCalledTimes( + explicitGas ? 0 : 1 + ); + } + ); }); diff --git a/packages/core/src/lib/vm-client/evm-client.ts b/packages/core/src/lib/vm-client/evm-client.ts index 772fcbaa..88e365ea 100644 --- a/packages/core/src/lib/vm-client/evm-client.ts +++ b/packages/core/src/lib/vm-client/evm-client.ts @@ -275,13 +275,19 @@ export class EvmClient { const resolveGas = async (): Promise => { if (explicitGas) return explicitGas; - const estimate = () => - this.publicClient.estimateGas({ + const estimate = async () => { + const estimatedGas = await this.publicClient.estimateGas({ account: signer.account.address as `0x${string}`, to, data, value, }); + // Leave headroom for nested calls and state changes before inclusion, + // as on the EIP-7702 batch path. Donut can return an estimate that + // reverts inside an AGW -> gateway -> token call even at the same state. + // This is the Push execution limit, separate from destination gas. + return (estimatedGas * BigInt(120) + BigInt(99)) / BigInt(100); + }; if (data !== '0x') return estimate(); @@ -422,29 +428,35 @@ export class EvmClient { throw new EIP7702NotSupportedError(err); } - // Estimate gas against the delegated account: override the EOA's code with - // the 7702 delegation designator (0xef0100 || executor) so estimation runs - // the executor. Fall back to a safe ceiling if the node rejects overrides. + // Prefer authorization-aware estimation of the actual type-4 transaction. + // Some RPCs reject that format or state overrides. An ordinary estimate is + // valid only if the account is already delegated to this exact executor. + // Never guess a per-call ceiling: contract deployment/grants vary in cost. + const delegation = ('0xef0100' + executor.slice(2)) as Hex; let gas: bigint; try { gas = await this.publicClient.estimateGas({ account, to: account, data, - stateOverride: [ - { - address: account, - code: ('0xef0100' + executor.slice(2)) as Hex, - }, - ], + authorizationList: [authorization as never], }); - gas = (gas * BigInt(120)) / BigInt(100); // headroom for delegation + auth } catch { - // Estimation unavailable (e.g. node rejects state overrides). Scale the - // ceiling with the batch size so large batches don't OOG — the legacy - // per-call loop budgeted ~500k gas per call; mirror that plus overhead. - gas = BigInt(500_000) * BigInt(calls.length) + BigInt(100_000); + const code = await this.publicClient.getCode({ address: account }); + if (code?.toLowerCase() === delegation.toLowerCase()) { + gas = await this.publicClient.estimateGas({ account, to: account, data }); + } else { + gas = await this.publicClient.estimateGas({ + account, + to: account, + data, + stateOverride: [{ address: account, code: delegation }], + }); + } } + // The fallback estimates omit authorization processing (25k intrinsic). + // Include it conservatively on every path, plus 20% execution headroom. + gas = (gas * BigInt(120) + BigInt(99)) / BigInt(100) + BigInt(25_000); const unsignedTx = serializeTransaction({ chainId, diff --git a/packages/core/tsconfig.agw-local.json b/packages/core/tsconfig.agw-local.json new file mode 100644 index 00000000..e547653d --- /dev/null +++ b/packages/core/tsconfig.agw-local.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "module": "commonjs", + "types": ["jest", "node"] + }, + "include": ["__agw-local__/**/*.ts", "src/**/*.d.ts"] +} From 6bd8ad5072f512c4e6b993d293200185a5a72c24 Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Mon, 12 Oct 2026 23:09:58 +0530 Subject: [PATCH 33/68] feat(core): align AGW rules and presets with October SDK feedback --- .gitignore | 1 + packages/core/AGW.md | 356 +++------- .../__agw-local__/agw-local-advanced.spec.ts | 133 ++-- .../__agw-local__/agw-local-batch.spec.ts | 29 +- .../__agw-local__/agw-local-races.spec.ts | 18 +- packages/core/__agw-local__/agw-local.spec.ts | 95 ++- packages/core/__agw-local__/labels.spec.ts | 4 +- .../__agw-local__/native-multi-action.spec.ts | 267 +++++++ .../core/__agw-local__/svm-backend.spec.ts | 8 +- .../core/__agw-local__/svm-public.spec.ts | 84 +-- .../core/__agw-local__/v5-multiasset.spec.ts | 77 +- packages/core/__agw-local__/vectors.spec.ts | 10 +- packages/core/__e2e__/agw/create.spec.ts | 16 +- .../core/__e2e__/agw/identity-gas.spec.ts | 26 +- packages/core/__e2e__/agw/labels.spec.ts | 54 +- packages/core/__e2e__/agw/lifecycle.spec.ts | 22 +- .../__e2e__/agw/management-extended.spec.ts | 91 +-- .../core/__e2e__/agw/native-batch.spec.ts | 26 +- packages/core/__e2e__/agw/native-exec.spec.ts | 98 ++- .../__e2e__/agw/native-multi-action.spec.ts | 663 ++++++++++++++++++ .../agw/native-policy-extended.spec.ts | 82 ++- .../core/__e2e__/agw/responses-hooks.spec.ts | 49 +- packages/core/__e2e__/agw/svm-public.spec.ts | 55 +- .../core/__e2e__/agw/universal-evm.spec.ts | 2 +- .../core/__e2e__/agw/v5-multiasset.spec.ts | 14 +- packages/core/__e2e__/ci/suite.ts | 84 ++- packages/core/__e2e__/shared/agw-state.ts | 31 + packages/core/scripts/check-agw-api.js | 10 +- packages/core/scripts/check-agw-package.js | 5 +- .../src/lib/agentic/__tests__/fake-chain.ts | 11 +- .../src/lib/agentic/__tests__/labels.spec.ts | 21 +- .../lib/agentic/__tests__/management.spec.ts | 19 +- .../__tests__/native-multi-action.spec.ts | 366 ++++++++++ .../src/lib/agentic/__tests__/presets.spec.ts | 251 +++++++ .../lib/agentic/__tests__/public-rule.spec.ts | 207 ++++++ .../agentic/__tests__/reads-context.spec.ts | 80 ++- .../__tests__/response-surface.spec.ts | 32 +- .../agentic/__tests__/rules-policy.spec.ts | 17 +- .../src/lib/agentic/__tests__/send.spec.ts | 32 + packages/core/src/lib/agentic/agentic.ts | 40 +- .../core/src/lib/agentic/agentic.types.ts | 146 +++- packages/core/src/lib/agentic/capabilities.ts | 2 +- .../core/src/lib/agentic/codec/defaults.ts | 6 +- packages/core/src/lib/agentic/codec/native.ts | 170 ++++- packages/core/src/lib/agentic/codec/rules.ts | 61 +- .../core/src/lib/agentic/codec/svm-idl.ts | 2 +- packages/core/src/lib/agentic/constants.ts | 30 +- packages/core/src/lib/agentic/deployments.ts | 14 +- packages/core/src/lib/agentic/errors.ts | 7 +- .../src/lib/agentic/execution/outbound.ts | 6 +- .../src/lib/agentic/execution/svm-outbound.ts | 2 +- packages/core/src/lib/agentic/index.ts | 26 +- .../core/src/lib/agentic/management/create.ts | 12 +- .../src/lib/agentic/management/duplicates.ts | 28 + .../src/lib/agentic/management/prepare.ts | 10 +- .../src/lib/agentic/management/rules-write.ts | 35 +- .../src/lib/agentic/management/svm-public.ts | 33 +- .../core/src/lib/agentic/management/svm.ts | 2 +- .../core/src/lib/agentic/presets/catalog.ts | 23 + .../core/src/lib/agentic/presets/index.ts | 240 +++++++ .../core/src/lib/agentic/presets/types.ts | 40 ++ packages/core/src/lib/agentic/public-rule.ts | 420 +++++++++++ .../core/src/lib/agentic/reads/checkpoints.ts | 102 ++- packages/core/src/lib/agentic/reads/rules.ts | 132 +++- packages/core/src/lib/agentic/utils.ts | 42 +- packages/core/src/lib/agentic/wallet.ts | 35 +- packages/core/src/lib/index.ts | 39 +- packages/core/src/lib/utils.ts | 10 +- 68 files changed, 4183 insertions(+), 978 deletions(-) create mode 100644 packages/core/__agw-local__/native-multi-action.spec.ts create mode 100644 packages/core/__e2e__/agw/native-multi-action.spec.ts create mode 100644 packages/core/src/lib/agentic/__tests__/native-multi-action.spec.ts create mode 100644 packages/core/src/lib/agentic/__tests__/presets.spec.ts create mode 100644 packages/core/src/lib/agentic/__tests__/public-rule.spec.ts create mode 100644 packages/core/src/lib/agentic/management/duplicates.ts create mode 100644 packages/core/src/lib/agentic/presets/catalog.ts create mode 100644 packages/core/src/lib/agentic/presets/index.ts create mode 100644 packages/core/src/lib/agentic/presets/types.ts create mode 100644 packages/core/src/lib/agentic/public-rule.ts diff --git a/.gitignore b/.gitignore index a3622c68..5cd47d8e 100644 --- a/.gitignore +++ b/.gitignore @@ -62,3 +62,4 @@ e2e-logs/ .agw-validation/ .ci-contracts/ .agw-runtime-validation/ +/plan/agw/research/native-multi-action-e2e-2026-10-12/logs diff --git a/packages/core/AGW.md b/packages/core/AGW.md index 8945327b..b2d91998 100644 --- a/packages/core/AGW.md +++ b/packages/core/AGW.md @@ -1,30 +1,16 @@ # Agentic wallets on Push Chain -This guide describes AGW v5 in this SDK branch. Donut is the configured deployment. Native Push, EVM destination rules and named-IDL Solana devnet rules are supported. Solana-origin signers can already act through their Push UEA. - -An AGW holds assets. Its owner grants or revokes rules and can execute unrestricted owner calls. An agent executes through its own Push identity, and each agent call must pass the granted policy. A Push-native key's identity is its EOA; an external key's identity is its Push UEA for that origin chain. - -```mermaid -flowchart LR - Owner[Owner EOA or UEA] -->|create, grant, update, revoke| Wallet[AGW] - Owner -->|owner execution| Wallet - Agent[Agent EOA or UEA] -->|agent execution| Wallet - Wallet -->|agent calls checked| Policy[Engine and rules policy] - Policy --> Native[Push target] - Policy --> Gateway[Gateway and destination account] -``` +This branch implements the SDK-only October 12 feedback against the deployed Donut v5 contracts. Contract-dependent changes remain explicit below. -## Connect a Push-native signer +## Connect -Pass a key from your application's key management. The functions below do not load `.env` files or run automatically. They use `viem` and the SDK's public exports. From the SDK checkout, check all TypeScript blocks together with `node packages/core/scripts/check-agw-docs.js` (or `yarn docs:check:agw` from packages/core). +Use an application-managed key; examples do not load secrets or execute automatically. ```ts import { PushChain, AgenticError, - type NativeRule, - type UniversalRule, - type SolanaRule, + type Rule, } from '@pushchain/core'; import { createWalletClient, @@ -60,307 +46,149 @@ async function connectPush(key: Hex, wallet?: Address): Promise { } ``` -`connectPush(ownerKey)` creates an ordinary owner client for management and funding. `connectPush(key, wallet)` sends from that AGW. The SDK determines the owner or agent door from the connected signer; the caller does not select a door. - -## Create a wallet and grant a native rule +## Create and manage rules -This example permits ten value transfers to one recipient before expiry, with explicit per-call and total limits. Explicit limits avoid relying on native omission defaults that are still being finalized. +Every chain uses `Rule.allowedCalls`. Omit `chainNamespace` for Push. The agent is always its Push address: a native EOA or an external signer's UEA. The owner cannot be its own agent. ```ts -async function createNativeWallet( - owner: PushChain, - agent: Address, - recipient: Address, -) { - const rule: NativeRule = { +async function createNative(owner: PushChain, agent: Address, token: Address, recipient: Address) { + const rule: Rule = { agent, - target: recipient, - selector: 'value-only', validUntil: Math.floor(Date.now() / 1000) + 3600, - maxValuePerCall: parseEther('0.001'), - maxValueTotal: parseEther('0.01'), - maxCalls: 10, + allowedCalls: [{ + target: token, + selector: 'transfer(address,uint256)', + pins: [{ arg: 0, expected: recipient }, { arg: 1, max: 10n }], + }], }; - const prediction = await owner.agentic.derive(); - const created = await owner.agentic.create('native-transfers', { - rules: [rule], - }); - return { prediction, created, rule }; + return owner.agentic.create('operations', { rules: [rule] }); } -``` -Create confirms deployment/grant receipts and returns `wallet`, `index`, `rulesIds` and transaction metadata. It does not fund the wallet or agent. A concurrent owner creation can invalidate a predicted index; the index-bound deployment refuses that race instead of granting on another wallet. - -## Fund separately, then send as the agent - -The wallet pays the transfer value. The agent pays Push transaction gas from its own EOA/UEA. Cross-chain sends also need PC in the wallet for the outbound budget. These are separate balances. - -```ts -async function fundAndSendNative( - owner: PushChain, - wallet: Address, - agentKey: Hex, - recipient: Address, -) { - await (await owner.universal.sendTransaction({ - to: wallet, - value: parseEther('0.02'), - })).wait(); - // Fund the agent's Push identity separately if it needs transaction gas. - const agent = await connectPush(agentKey, wallet); - const response = await agent.universal.sendTransaction({ - to: recipient, - value: parseEther('0.001'), +async function manage(owner: PushChain, address: Address, id: Hex) { + const wallet = owner.agentic.wallet(address); + const record = await wallet.rules.get(id); + // Reads preserve the constraints needed by update. + const changed = await wallet.rules.update({ + rules: [{ rulesId: id, rule: { ...record.rule, validUntil: record.validUntil + 3600 } }], }); - return response.wait(); + await wallet.setLabel('renamed'); // direct cosmetic write; no checkpoint + await wallet.rules.delete([changed.rules[0].rulesId]); + // Delete all requires an explicit target: + // await wallet.rules.delete({ all: true }); + return wallet.info(); } ``` -For an external signer, grant to its derived Push UEA rather than its origin-chain address. Use `PushChain.utils.account.deriveExecutorAccount` with the signer’s actual origin chain. First-use external UEA gas handling uses that origin; changing the origin chain changes the UEA identity. +`derive({ index? })` returns the predicted address, index and deployment state. `list()` enumerates the connected owner's wallets. A wallet handle provides `info`, `owner`, `checkpoints`, `setLabel`, and `rules.list/get/add/update/delete`. Deleted rules are not returned in v1. Rule IDs may change during update. -Native agent arrays use an atomic UEA/EIP-7702 transport that preserves the agent sender. Each action is checked individually. An unavailable atomic transport fails explicitly; the SDK does not submit the agent batch sequentially. +`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. -## Read, replace and revoke rules +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. -A management handle is `owner.agentic.wallet(wallet)`. It reads and writes rules but does not switch the owner's transaction execution identity to the wallet. - -```ts -async function inspectWallet(owner: PushChain, wallet: Address) { - const handle = owner.agentic.wallet(wallet); - const [info, ownerRecord, rules] = await Promise.all([ - handle.info(), handle.owner(), handle.rules.list(), - ]); - return { info, owner: ownerRecord.owner, rules: rules.rules }; -} - -async function replaceNativeRule( - owner: PushChain, - wallet: Address, - rulesId: Hex, - replacement: NativeRule, -) { - return owner.agentic.wallet(wallet).rules.update({ - rules: [{ rulesId, rule: replacement }], - }); -} - -async function revokeRule(owner: PushChain, wallet: Address, rulesId: Hex) { - return (await owner.agentic.wallet(wallet).rules.revoke([rulesId])).wait(); -} -``` +## Pins and zero defaults -Replacement asserts the old spend, revokes and grants in one owner transaction. Intervening agent spending makes the whole replacement revert. The new rule gets a new ID and fresh counters. A single replacement records five checkpoints. Failed transactions unwind their checkpoints; agent calls do not tick the owner checkpoint count. +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. -`rules.list()` returns enabled rules, including enabled rules whose expiry has passed. Expiry is enforced on execution. Revoked-history reconstruction is outside v1. Rule IDs are wallet-scoped; do not treat an ID alone as a globally unique permission. +`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. -## Wallet labels +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. -Donut uses the v5 factory `0x8137F96A50EBF41d904e3678c84c391a0D1BCcc5`. Wallet labels are stored on-chain; `info()` and `list()` read the current value. An empty deployment label defaults to `AGW `. +## EVM destinations ```ts -async function renameWallet(owner: PushChain, wallet: Address) { - const handle = owner.agentic.wallet(wallet); - const renamed = await handle.setLabel('Trading'); - const info = await handle.info(); - const reset = await handle.setLabel(''); - return { renamed, info, reset }; -} -``` - -Create and rename labels accept at most **64 UTF-8 bytes**, including spaces; 16 four-byte emoji fit. Empty rename resets the default. The SDK renames through the owner door for EOA and UEA owners, emits progress through the supplied hook and records one owner-action checkpoint. The contract's direct `setLabel` call itself records no checkpoint. Agent and read-only clients cannot rename. - -New wallets use v5 only. Existing v4 wallets do not acquire label functions and are unsupported by this SDK adapter. Wallet predictions and EIP-712 intent domains use the new factory; do not reuse old predicted addresses or signatures. On relayed signed deployment, the contract does not include the cosmetic label in `OwnerIntent`; the owner can correct it afterward. - -## Grant an EVM destination rule - -The destination token identifies an asset on that destination chain. The SDK resolves the mapped PRC20 held by the AGW. Limits use the token's smallest units; `maxGasPerCall` uses PC wei. A rule may list several assets, but each outbound request moves one listed token. - -The example below bridges at most 0.000001 ETH per call and permits a counter's `increment()` call. The explicit zero-value call leaves the bridged ETH in the wallet's CEA. Use a target that actually implements that selector. - -```ts -async function createSepoliaWallet( - owner: PushChain, - agent: Address, - counter: Address, -) { - const rule: UniversalRule = { +function evmRule(agent: Address, target: Address): Rule { + return { agent, chainNamespace: SEPOLIA, - assets: [{ - token: ETH, - maxPerCall: BigInt(10) ** BigInt(12), - maxTotal: BigInt(10) ** BigInt(13), - }], - maxGasPerCall: parseEther('20'), validUntil: Math.floor(Date.now() / 1000) + 3600, - allowedCalls: [{ target: counter, selector: 'increment()', maxValue: BigInt(0) }], + assets: [{ token: ETH, maxPerCall: 1_000n, maxTotal: 10_000n }], + maxGasPerCall: parseEther('20'), + allowedCalls: [{ + target, + selector: 'deposit(address,uint256)', + pins: [{ arg: 0, expected: PushChain.CONSTANTS.AGENTIC.WALLET }], + }], }; - return owner.agentic.create('sepolia-counter', { rules: [rule] }); } ``` -An omitted universal asset total uses uint256 maximum; explicit zero forbids movement. `assets: []` is a call-only rule, represented internally by a zero-cap destination gas token. The SDK derives `expectedCEA` from the wallet, not the agent. - -## Fund the PRC20 and set a bounded allowance - -The gateway pulls the selected PRC20 from the AGW. Set the allowance through the owner door as a separate, explicit action. Neither owner nor agent outbound sends change allowances automatically. - -```ts -async function prepareSepoliaWallet( - owner: PushChain, - ownerKey: Hex, - wallet: Address, - amount: bigint, -) { - const prc20 = PushChain.utils.tokens.getPRC20Address(ETH, { network: NETWORK }); - // The ordinary owner account must already hold the mapped PRC20. - await (await owner.universal.sendTransaction({ - to: wallet, value: parseEther('21'), - })).wait(); - await (await owner.universal.sendTransaction({ - to: prc20.address, - data: encodeFunctionData({ - abi: erc20Abi, functionName: 'transfer', args: [wallet, amount], - }), - })).wait(); - const ownerDoor = await connectPush(ownerKey, wallet); - const gateway = '0x00000000000000000000000000000000000000C1' as Address; - await (await ownerDoor.universal.sendTransaction({ - to: prc20.address, - data: encodeFunctionData({ - abi: erc20Abi, functionName: 'approve', args: [gateway, amount], - }), - })).wait(); -} +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. -async function sendToSepolia(agent: PushChain, counter: Address, amount: bigint) { - return agent.universal.sendTransaction({ - to: { address: counter, chain: SEPOLIA }, - data: [{ to: counter, value: BigInt(0), data: '0xd09de08a' }], - funds: { amount, token: ETH }, - gasLimit: BigInt(2_000_000), // includes fresh CEA finalization in this example - }); -} -``` +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. -The current core default of 500,000 destination gas was insufficient for fresh Sepolia CEA finalization in our live test (~1.3 million estimated). The example supplies a bounded two-million-gas limit; choose a budget appropriate for your destination calls. The 20/21-PC values are example budgets, not fee estimates. Fees and gas are quoted for the current request. Approval safety is the application's responsibility; the SDK validates structure and contract limits rather than deciding whether a grant is appropriate. +## Solana destinations -## Wait, replay and recover - -`from` is the AGW and `origin` is the signer. For EVM outbounds, `to/data/value` describe the first destination call; `agentic.destinationCalls` preserves all destination calls. `agentic.rawTo/rawData` retain the wrapped Push call. +Rules use fixed-width signatures and numeric positions, without an IDL: ```ts -async function waitForDelivery(response: WalletTransaction) { - const receipt = await response.wait({ outboundTimeoutMs: 600_000 }); +function solanaRule(agent: Address, program: string): Rule { return { - pushSucceeded: receipt.status === 1, - destinationStatus: receipt.externalStatus, - externalTxHash: receipt.externalTxHash, + agent, + chainNamespace: PushChain.CONSTANTS.CHAIN.SOLANA_DEVNET, + validUntil: Math.floor(Date.now() / 1000) + 3600, + maxGasPerCall: parseEther('20'), + allowedCalls: [{ + target: program, + selector: 'receive_sol(u64)', + pins: [ + { account: 2, expected: PushChain.CONSTANTS.AGENTIC.WALLET }, + { arg: 0, max: 1_000n }, + ], + }], }; } +``` -async function replay(owner: PushChain, hash: string) { - const response = await owner.universal.trackTransaction(hash); - return response.wait({ outboundTimeoutMs: 600_000 }); -} +Use the program's actual account positions. `{ account, expected: WALLET, token: mint }` pins the wallet's ATA, using the verified mint/token-program context. Fixed integer, bool, pubkey and fixed-array layouts are supported; dynamic or undefined layouts fail before signing. Raw eight-byte discriminators support account pins; argument pins also need argument types. A nonzero per-call EVM `maxValue` has no Solana encoding. -function recoveryDetails(error: unknown) { - if (!(error instanceof AgenticError)) throw error; - return { code: error.code, hint: error.hint, details: error.details }; -} -``` +Solana reads return `format: 'decoded'` with exact stored discriminators, offsets and constraints. This raw form is accepted by `rules.update`, preserving restrictions without inventing an IDL. Reusing it for another wallet/gateway is rejected. Send-data encoding still uses the existing `utils.helpers.encodeTxData` IDL helper; rule authoring and transaction encoding are separate operations. -A successful Push receipt does not mean destination success. Check `externalStatus`. A timeout can mean the relay is still processing; track the same hash rather than assuming the transaction failed. Reverted Push roots do not start destination polling. Wrapped outbounds are recognized from their calldata even if the indexer initially reports only the Push leg. +## Spend, checkpoints and execution -| Result | Application action | -| --- | --- | -| `INDEX_RACE` | This create committed nothing; derive/retry the next slot. | -| `CREATE_PARTIAL` | Inspect `details.walletDeployed`, `grantedRulesIds`, `confirmedHashes` and `pendingHash`. Reconcile unknown/pending outcomes. If deployed, finish missing grants with `rules.add`; do not create a replacement wallet blindly. | -| `NO_RULES_FOR_CHAIN` | Grant a suitable enabled rule before the agent sends. | -| `AMBIGUOUS_RULE` | Multiple enabled rules match the agent and chain. No transaction is submitted. Inspect `details.rulesIds` and have the owner resolve the overlap; the SDK does not pick or revoke a rule arbitrarily. | -| `GATEWAY_ALLOWANCE_INSUFFICIENT` | The owner must explicitly establish a sufficient allowance. | -| `CAPABILITY_UNAVAILABLE` / `GENERATION_UNSUPPORTED` | Inspect the capability/deployment details; no compatible operation was submitted. | +`rules.get/list` return `spent`. Universal spend contains one entry per asset in stored order. A single native call has scalar value/amount/call counters. Several native calls return `spent.actions`, with each entry identified by target and selector; unrelated token amounts are not summed. -Ordinary returned funds do not lower policy spend. `creditRevert` still needs platform executor support. Revoking rules stops agent authorization but does not remove ERC20 allowances; the owner manages those separately. +Native historical terms with lifetime limits or differing per-action expiries that the new public shape cannot preserve return an explicit capability error rather than silently dropping restrictions. -## Solana rules using named IDL inputs +Connect with `PushChain.initialize(signer, { agenticWallet: address })` to send from the wallet. Signer identity determines the owner or agent door. Native agent arrays are atomic and every call passes policy checks. `from` cannot be overridden. Responses identify the wallet as `from` and signer as `origin`, including wait/replay results. -Use `SolanaRule` with an Anchor IDL, instruction name, named account restrictions and field constraints. Addresses accept base58 or 32-byte hex. `walletCEA` and `walletATA` references are derived from the AGW and configured cluster; declare output mints in `outputTokens` when their wallet ATAs also need protection. +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. -```ts -import type { Idl } from '@coral-xyz/anchor'; +## Deployment-dependent behavior -async function createSolanaWallet( - owner: PushChain, agent: Address, program: string, - idl: Idl, recipient: string, counter: string, -) { - const rule: SolanaRule = { - agent, - chainNamespace: PushChain.CONSTANTS.CHAIN.SOLANA_DEVNET, - validUntil: Math.floor(Date.now() / 1000) + 3600, - assets: [{ token: '0x0000000000000000000000000000000000000000', maxPerCall: BigInt(10_000), maxTotal: BigInt(20_000) }], - maxGasPerCall: parseEther('20'), - allowedInstructions: [{ - program, - instruction: { idl, name: 'receive_sol' }, - accounts: [ - { name: 'counter', expected: { kind: 'address', address: counter } }, - { name: 'recipient', expected: { kind: 'address', address: recipient } }, - { name: 'cea_authority', expected: { kind: 'walletCEA' } }, - { name: 'system_program', expected: { kind: 'address', address: '11111111111111111111111111111111' } }, - ], - fields: [{ name: 'amount', max: BigInt(10_000) }], - }], - }; - return owner.agentic.create('solana-wallet', { rules: [rule] }); -} +The October 12 contract feedback is not deployed. Until it is verified: -async function sendSolanaInstruction(agent: PushChain, program: string, idl: Idl) { - const data = PushChain.utils.helpers.encodeTxData({ - abi: idl, functionName: 'receive_sol', args: [BigInt(10_000)], - }); - return agent.universal.sendTransaction({ - to: { address: program, chain: PushChain.CONSTANTS.CHAIN.SOLANA_DEVNET }, - data, value: BigInt(10_000), - }); -} -``` +- 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. +- 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. +- General EVM destination pins and the new atomic factory `createWallet` are unavailable. -These examples assume the supplied IDL describes `receive_sol` with those accounts and a `u64` amount. The send resolver needs matching account addresses/PDA definitions in its IDL. Fund the wallet and set a separate bounded gateway allowance before sending. Native SOL amounts are lamports; the wallet burns its corresponding PRC20. `assets: []` creates a zero-amount gas-token routing cap. +`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`. -Supported rule layouts have an eight-byte discriminator, top-level non-optional accounts, and fixed-width primitive/fixed-array arguments. Field comparisons support exact bytes (at most 32 bytes), unsigned integer min/max (up to `u64`), and same-width unsigned ratio floors. Variable-length or nested/defined argument layouts and optional/nested accounts are rejected before signing. An IDL describes encoding; it does not prove what the program does with those accounts. +## Preset discovery and templates (section 7) -Agent SVM sends require one instruction encoded with `encodeTxData` (which registers the IDL), or data matching an already registered IDL. Instruction arrays remain unsupported. Owners can also send funds without any IDL or instruction: +`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. ```ts -async function transferSolanaFunds(ownerWallet: PushChain, recipient: string) { - return ownerWallet.universal.sendTransaction({ - to: { address: recipient, chain: PushChain.CONSTANTS.CHAIN.SOLANA_DEVNET }, - value: BigInt(10_000), // native SOL, in lamports - }); -} - -async function transferSolanaUsdt(ownerWallet: PushChain, recipient: string) { - return ownerWallet.universal.sendTransaction({ - to: { address: recipient, chain: PushChain.CONSTANTS.CHAIN.SOLANA_DEVNET }, - funds: { - token: PushChain.CONSTANTS.MOVEABLE.TOKEN.SOLANA_DEVNET.USDT, - amount: BigInt(1), // 0.000001 USDT at six decimals - }, - }); +const { presets } = PushChain.utils.agentic.presets.list({ type: 'CATEGORY' }); +const availablePresets = presets.filter(preset => preset.chains.length > 0); +const { rules: reviewTemplates } = PushChain.utils.agentic.presets.get( + PushChain.CONSTANTS.AGENTIC.PRESETS.CATEGORY.DEXES, +); +// Currently [], since there is no approved catalog. Never treat an empty result as an active preset. + +function filledPreset(agent: Address) { + return PushChain.utils.agentic.presets.get( + PushChain.CONSTANTS.AGENTIC.PRESETS.CATEGORY.DEXES, + { agent, validUntil: Math.floor(Date.now() / 1000) + 3600 }, + ).rules; } ``` -`ownerWallet` is initialized with the owner signer and `agenticWallet`. As with instruction sends, fund the wallet with PC/PRC20 and establish a separate bounded gateway allowance. Transfers use an empty payload and the requested recipient; the SDK applies core’s Solana finalization/rent budget using the wallet identity. Send either `value` for SOL or `funds` for a token, not both. A zero-amount funds-only send is rejected. - -Funds-only responses expose `agentic.destinationTransfer` with the recipient, burned Push PRC20 token, and amount. They have no `destinationInstruction`; replay uses the same representation. Native SOL transfers show their amount in `value`, while SPL transfers carry the amount in transfer metadata and show zero native value. - -Structural/context/funding failures are SDK `AgenticError`s. Granted permissions, expiry and spend limits are enforced by the contract. Refusals obtained during contract simulation or execution are mapped to `AgenticRevertError` with `decodedError`; simulation failure does not broadcast a transaction. Reads return `DecodedSolanaRule` with `format: 'decoded'` and exact stored program/account/data constraints. They cannot reconstruct an IDL; use a named `SolanaRule` input to add or replace it. Native/EVM decoded rules remain reusable in raw-offset form. +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. -Responses expose `agentic.destinationInstruction` and the wallet’s destination CEA. Check `externalStatus` and replay the same transaction hash after a timeout. +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. -## Current API boundaries +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. -Rule `ref` is removed from public inputs and records; supplying it is rejected. Checkpoint `ref` is a separate existing event field and is preserved. Editable labels are implemented against the checked v5 deployment. Contract permission enforcement is already present: unauthorized actions under the supplied rule are rejected, and the SDK maps the errors. Revoked history, public spend records, public generation context and `compileCard` are outside standalone v1. Omitted native PC value limits are zero. Native argument-index and raw-offset inputs are both supported; decoded native/EVM rules preserve exact offsets. +## Validation -Use `PushChain.CONSTANTS.READ.CHAIN.WEB2` for Web2 reads. Its value is `web2`; the old literal `web2:https` is still accepted and normalizes to the same wire identity. Literal comparisons against the older spelling need updating. Web2 is a read source, not a transaction destination. +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. diff --git a/packages/core/__agw-local__/agw-local-advanced.spec.ts b/packages/core/__agw-local__/agw-local-advanced.spec.ts index 83817f1b..9e801d6d 100644 --- a/packages/core/__agw-local__/agw-local-advanced.spec.ts +++ b/packages/core/__agw-local__/agw-local-advanced.spec.ts @@ -24,7 +24,6 @@ import type { AgenticExecutionContext } from '../src/lib/agentic/context'; import { buildSession, encodeEnvelope } from '../src/lib/agentic/codec/session'; import { encodeUniversalTerms } from '../src/lib/agentic/codec/universal-terms'; import { startHarness, type Harness } from './harness'; - const TARGET_ABI = parseAbi([ 'function increment()', 'function deposit(address beneficiary, uint256 amount) payable', @@ -46,13 +45,11 @@ const GATEWAY_ABI = parseAbi([ const CORE_ABI = parseAbi([ 'function getOutboundTxGasAndFees(address,uint256) view returns (address,uint256,uint256,uint256,string,uint256)', ]); - type Internals = { agenticRuntime: AgenticRuntime; agenticContext?: AgenticExecutionContext; }; const internals = (c: PushChain) => c as unknown as Internals; - async function chainNow(h: Harness): Promise { return Number((await h.publicClient.getBlock()).timestamp); } @@ -73,12 +70,10 @@ const fund = (h: Harness, to: Address, value: bigint) => account: h.wallets[4].account!, chain: h.wallets[4].chain, }); - describe('AGW advanced paths against real v5 contracts', () => { let h: Harness; let owner: PushChain; let agentAddr: Address; - beforeAll(async () => { h = await startHarness(18547); owner = await h.client(0); @@ -87,26 +82,29 @@ describe('AGW advanced paths against real v5 contracts', () => { afterAll(async () => { await h?.stop(); }); - describe('native pins, amount and value caps', () => { let wallet: Address; let agent: PushChain; const beneficiary = getAddress( '0x00000000000000000000000000000000000b0b0b' ); - beforeAll(async () => { const created = await owner.agentic.create('pins', { rules: [ { agent: agentAddr, - target: h.addresses.target, - selector: 'deposit(address,uint256)', validUntil: (await chainNow(h)) + 3600, - pins: [{ arg: 0, expected: beneficiary }], - amount: { arg: 1, maxPerCall: BigInt(10), maxTotal: BigInt(15) }, - maxValuePerCall: BigInt(1000), - maxValueTotal: BigInt(1000), + allowedCalls: [ + { + target: h.addresses.target, + selector: 'deposit(address,uint256)', + maxValue: BigInt(1000), + pins: [ + { arg: 0, expected: beneficiary }, + { arg: 1, max: BigInt(10) }, + ], + }, + ], }, ], }); @@ -116,7 +114,6 @@ describe('AGW advanced paths against real v5 contracts', () => { }); agent = await h.client(1, { agenticWallet: wallet }); }); - const deposit = (to: Address, amount: bigint, value = BigInt(0)) => agent.universal.sendTransaction({ to: h.addresses.target, @@ -127,7 +124,6 @@ describe('AGW advanced paths against real v5 contracts', () => { args: [to, amount], }), }); - it('a pinned beneficiary and an in-cap amount pass', async () => { await (await deposit(beneficiary, BigInt(5), BigInt(10))).wait(); expect( @@ -138,7 +134,6 @@ describe('AGW advanced paths against real v5 contracts', () => { }) ).toBe(beneficiary); }); - it('a wrong beneficiary is rejected by URP with a decoded error and no state change', async () => { const err = await deposit(agentAddr, BigInt(5)).catch((e) => e); expect(err).toBeInstanceOf(AgenticRevertError); @@ -146,7 +141,11 @@ describe('AGW advanced paths against real v5 contracts', () => { 'PolicyCheckReverted(ArgPinMismatch)' ); const rec = await owner.agentic.wallet(wallet).rules.list(); - expect(rec.rules[0]).not.toHaveProperty('spent'); + expect(rec.rules[0].spent).toMatchObject({ + kind: 'native', + amountSpent: BigInt(5), + callsUsed: 1, + }); expect( await readNativeCounters( h.publicClient, @@ -156,43 +155,46 @@ describe('AGW advanced paths against real v5 contracts', () => { ) ).toMatchObject({ amountSpent: BigInt(5), callsUsed: 1 }); }); - - it('per-call and lifetime amount caps are enforced on-chain', async () => { + it('per-call amounts are enforced and repeated valid calls remain usable', async () => { await expect(deposit(beneficiary, BigInt(11))).rejects.toBeInstanceOf( AgenticRevertError ); await (await deposit(beneficiary, BigInt(10))).wait(); - await expect(deposit(beneficiary, BigInt(1))).rejects.toBeInstanceOf( - AgenticRevertError - ); + await (await deposit(beneficiary, BigInt(1))).wait(); }); - it('the decoded native terms carry the pins and caps as stored', async () => { const { rules } = await owner.agentic.wallet(wallet).rules.list(); expect(rules[0].rule).toMatchObject({ - pins: [ + allowedCalls: [ { - offset: 4, - expected: `0x${'0'.repeat(24)}${beneficiary - .slice(2) - .toLowerCase()}`, + pins: [ + { + arg: 0, + expected: `0x${'0'.repeat(24)}${beneficiary + .slice(2) + .toLowerCase()}`, + }, + { arg: 1, max: BigInt(10) }, + ], + maxValue: BigInt(1000), }, ], - amount: { offset: 36, maxPerCall: BigInt(10), maxTotal: BigInt(15) }, - maxValuePerCall: BigInt(1000), }); }); }); - describe('stale-spend replacement race', () => { it('an agent spend between the read and inclusion reverts the whole replacement atomically', async () => { const created = await owner.agentic.create('race', { rules: [ { agent: agentAddr, - target: h.addresses.target, - selector: 'increment()', validUntil: (await chainNow(h)) + 3600, + allowedCalls: [ + { + target: h.addresses.target, + selector: 'increment()', + }, + ], }, ], }); @@ -228,9 +230,9 @@ describe('AGW advanced paths against real v5 contracts', () => { rulesId: oldId, rule: { agent: agentAddr, + validUntil: (await chainNow(h)) + 3600, target: h.addresses.target, selector: 'increment()', - validUntil: (await chainNow(h)) + 3600, }, }, ], @@ -248,16 +250,19 @@ describe('AGW advanced paths against real v5 contracts', () => { ).toBe(cpBefore); }); }); - describe('expiry', () => { it('an expired-but-enabled rule still identifies the agent; the send fails on-chain', async () => { const created = await owner.agentic.create('expiring', { rules: [ { agent: agentAddr, - target: h.addresses.target, - selector: 'increment()', validUntil: (await chainNow(h)) + 600, + allowedCalls: [ + { + target: h.addresses.target, + selector: 'increment()', + }, + ], }, ], }); @@ -276,7 +281,6 @@ describe('AGW advanced paths against real v5 contracts', () => { expect(err.decodedError?.name).toBe('PolicyCheckReverted(RulesExpired)'); }); }); - describe('sequential create partial failure and recovery', () => { it('reports CREATE_PARTIAL with the deployed wallet and granted IDs; rules.add finishes it', async () => { // Chain time runs ahead of the local clock: the SDK accepts validUntil, the policy does not. @@ -287,15 +291,23 @@ describe('AGW advanced paths against real v5 contracts', () => { rules: [ { agent: agentAddr, - target: h.addresses.target, - selector: 'increment()', validUntil: (await chainNow(h)) + 3600, + allowedCalls: [ + { + target: h.addresses.target, + selector: 'increment()', + }, + ], }, { agent: h.wallets[3].account!.address, - target: h.addresses.target, - selector: 'increment()', validUntil: skewedValidUntil, + allowedCalls: [ + { + target: h.addresses.target, + selector: 'increment()', + }, + ], }, ], }) @@ -309,16 +321,19 @@ describe('AGW advanced paths against real v5 contracts', () => { const added = await owner.agentic.wallet(wallet).rules.add([ { agent: h.wallets[3].account!.address, - target: h.addresses.target, - selector: 'increment()', validUntil: (await chainNow(h)) + 3600, + allowedCalls: [ + { + target: h.addresses.target, + selector: 'increment()', + }, + ], }, ]); expect(added.rulesIds).toHaveLength(1); const { rules } = await owner.agentic.wallet(wallet).rules.list(); expect(rules).toHaveLength(2); }); - it('rules.add with several rules is one atomic owner batch: OWNER_ACTION + RULES_GRANTED per rule', async () => { const created = await owner.agentic.create('multi-add', { rules: [] }); const before = await h.publicClient.readContract({ @@ -329,15 +344,23 @@ describe('AGW advanced paths against real v5 contracts', () => { const added = await owner.agentic.wallet(created.wallet).rules.add([ { agent: agentAddr, - target: h.addresses.target, - selector: 'increment()', validUntil: (await chainNow(h)) + 3600, + allowedCalls: [ + { + target: h.addresses.target, + selector: 'increment()', + }, + ], }, { agent: h.wallets[3].account!.address, - target: h.addresses.target, - selector: 'increment()', validUntil: (await chainNow(h)) + 3600, + allowedCalls: [ + { + target: h.addresses.target, + selector: 'increment()', + }, + ], }, ]); expect(added.rulesIds).toHaveLength(2); @@ -355,7 +378,6 @@ describe('AGW advanced paths against real v5 contracts', () => { expect(before).toBe(BigInt(0)); }); }); - describe('agent EVM outbound (v5 multi-asset terms, stub gateway)', () => { const SEPOLIA = CHAIN.ETHEREUM_SEPOLIA; const CEA = getAddress('0x000000000000000000000000000000000000cea1'); @@ -366,7 +388,6 @@ describe('AGW advanced paths against real v5 contracts', () => { let runtime: AgenticRuntime; let ctx: AgenticExecutionContext; let ownerAgw: PushChain; - beforeAll(async () => { token = await h.deploy(0, 'HarnessPRC20', 'HarnessFixtures.sol', [ SEPOLIA, @@ -374,7 +395,7 @@ describe('AGW advanced paths against real v5 contracts', () => { ]); const created = await owner.agentic.create('outbound', { rules: [] }); wallet = created.wallet; - await h.write(0, token, TOKEN_ABI, 'mint', [wallet, BigInt(1_000_000)]); + await h.write(0, token, TOKEN_ABI, 'mint', [wallet, BigInt(1000000)]); await h.publicClient.waitForTransactionReceipt({ hash: await fund(h, wallet, BigInt(10) ** BigInt(17)), }); @@ -421,7 +442,6 @@ describe('AGW advanced paths against real v5 contracts', () => { functionName: 'getPermissionIDs', args: [wallet], })) as Hex[]; - const agent = await h.client(1, { agenticWallet: wallet }); ctx = internals(agent).agenticContext!; const base = internals(agent).agenticRuntime; @@ -443,7 +463,6 @@ describe('AGW advanced paths against real v5 contracts', () => { }; ownerAgw = await h.client(0, { agenticWallet: wallet }); }); - // Explicit call array: the funds land in the wallet's CEA and the listed // call runs as given (a single `data` would also prepend transfer(target)). const send = (amount: bigint) => @@ -460,13 +479,11 @@ describe('AGW advanced paths against real v5 contracts', () => { }, }, }); - it('fails before signing when the owner has not set a gateway allowance', async () => { await expect(send(BigInt(100))).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.GATEWAY_ALLOWANCE_INSUFFICIENT, }); }); - it('owner sets a bounded allowance with an ordinary owner-door send; the agent outbound passes URP, pulls and burns', async () => { await ( await ownerAgw.universal.sendTransaction({ @@ -546,7 +563,7 @@ describe('AGW advanced paths against real v5 contracts', () => { recipient: '0x', token, amount: BigInt(100), - gasLimit: BigInt(200_000), + gasLimit: BigInt(2000000), gasPrice: BigInt(0), maxPCForGas: BigInt(10) ** BigInt(15), payload, @@ -572,7 +589,6 @@ describe('AGW advanced paths against real v5 contracts', () => { }); expect(keccak256(toBytes(SEPOLIA))).toBeTruthy(); }); - it('owner can remove the allowance; the agent is stopped before signing again', async () => { await ( await ownerAgw.universal.sendTransaction({ @@ -588,7 +604,6 @@ describe('AGW advanced paths against real v5 contracts', () => { code: AGENTIC_ERROR_CODE.GATEWAY_ALLOWANCE_INSUFFICIENT, }); }); - it('a call outside the allow-list is rejected by URP on-chain', async () => { await ( await ownerAgw.universal.sendTransaction({ diff --git a/packages/core/__agw-local__/agw-local-batch.spec.ts b/packages/core/__agw-local__/agw-local-batch.spec.ts index ae5071df..fdb5713c 100644 --- a/packages/core/__agw-local__/agw-local-batch.spec.ts +++ b/packages/core/__agw-local__/agw-local-batch.spec.ts @@ -12,7 +12,6 @@ import { PUSH_BATCH_EXECUTOR_ADDRESS } from '../src/lib/constants/chain'; import { startHarness, type Harness } from './harness'; import { EvmClient } from '../src/lib/vm-client/evm-client'; import { readNativeCounters } from '../__e2e__/shared/agw-state'; - const ABI = parseAbi([ 'function increment()', 'function counter() view returns(uint256)', @@ -20,7 +19,6 @@ const ABI = parseAbi([ let h: Harness; let owner: PushChain; let previous: Address | undefined; - beforeAll(async () => { h = await startHarness(18552); previous = PUSH_BATCH_EXECUTOR_ADDRESS[CHAIN.PUSH_LOCALNET]; @@ -37,16 +35,18 @@ afterAll(async () => { else delete PUSH_BATCH_EXECUTOR_ADDRESS[CHAIN.PUSH_LOCALNET]; await h?.stop(); }); - -async function walletFor(maxCalls: number) { +async function walletFor(_maxCalls: number) { const result = await owner.agentic.create('native-batch', { rules: [ { agent: h.wallets[1].account!.address, - target: h.addresses.target, - selector: 'increment()', validUntil: Number((await h.publicClient.getBlock()).timestamp) + 3600, - maxCalls, + allowedCalls: [ + { + target: h.addresses.target, + selector: 'increment()', + }, + ], }, ], }); @@ -65,7 +65,6 @@ const counter = () => abi: ABI, functionName: 'counter', }); - it('atomic native agent array preserves the agent sender and meters both actions', async () => { const { wallet, rulesIds, agent } = await walletFor(3); const before = await counter(); @@ -91,7 +90,6 @@ it('atomic native agent array preserves the agent sender and meters both actions expect(getAddress(raw.from)).toBe(h.wallets[1].account!.address); expect(getAddress(raw.to as Address)).toBe(h.wallets[1].account!.address); }); - it('failure of a later native action rolls back the earlier call and its counters', async () => { const { wallet, rulesIds, agent } = await walletFor(1); const before = await counter(); @@ -107,7 +105,7 @@ it('failure of a later native action rolls back the earlier call and its counter .mockImplementation(async function (this: EvmClient, params) { const estimate = jest .spyOn(this.publicClient, 'estimateGas') - .mockResolvedValue(BigInt(2_000_000)); + .mockResolvedValue(BigInt(2000000)); try { return await original.call(this, params); } finally { @@ -116,7 +114,10 @@ it('failure of a later native action rolls back the earlier call and its counter }); try { await expect( - agent.universal.sendTransaction({ to: h.addresses.target, data: calls() }) + agent.universal.sendTransaction({ + to: h.addresses.target, + data: [calls()[0], { ...calls()[1], data: '0xffffffff' }], + }) ).rejects.toBeInstanceOf(AgenticRevertError); } finally { send.mockRestore(); @@ -137,14 +138,16 @@ it('failure of a later native action rolls back the earlier call and its counter ) ).toMatchObject({ callsUsed: 0 }); }); - it('normal estimation refuses an invalid native batch before broadcasting', async () => { const { agent } = await walletFor(1); const nonce = await h.publicClient.getTransactionCount({ address: h.wallets[1].account!.address, }); await expect( - agent.universal.sendTransaction({ to: h.addresses.target, data: calls() }) + agent.universal.sendTransaction({ + to: h.addresses.target, + data: [calls()[0], { ...calls()[1], data: '0xffffffff' }], + }) ).rejects.toBeInstanceOf(AgenticRevertError); expect( await h.publicClient.getTransactionCount({ diff --git a/packages/core/__agw-local__/agw-local-races.spec.ts b/packages/core/__agw-local__/agw-local-races.spec.ts index dd106d64..efe87bae 100644 --- a/packages/core/__agw-local__/agw-local-races.spec.ts +++ b/packages/core/__agw-local__/agw-local-races.spec.ts @@ -12,15 +12,17 @@ import type { AgenticRuntime } from '../src/lib/agentic/runtime'; import { v5 } from '../src/lib/agentic/contracts/v5'; import { AGENTIC_ERROR_CODE } from '../src/lib/agentic/errors'; import { startHarness, type Harness } from './harness'; - const TOKEN = parseAbi([ 'function mint(address,uint256)', 'function approve(address,uint256) returns (bool)', 'function allowance(address,address) view returns (uint256)', ]); const internalsOf = (c: PushChain) => - (c as unknown as { agenticRuntime: AgenticRuntime }).agenticRuntime; - + ( + c as unknown as { + agenticRuntime: AgenticRuntime; + } + ).agenticRuntime; describe('AGW race regressions (real v5 contracts)', () => { let h: Harness; let owner: PushChain; @@ -31,7 +33,6 @@ describe('AGW race regressions (real v5 contracts)', () => { afterAll(async () => { await h?.stop(); }); - it('R1 a concurrent creation makes create() fail with nothing granted on either wallet', async () => { const expected = await owner.agentic.derive(); const rt = internalsOf(owner); @@ -52,10 +53,14 @@ describe('AGW race regressions (real v5 contracts)', () => { rules: [ { agent: h.wallets[1].account!.address, - target: h.addresses.target, - selector: 'increment()', validUntil: Number((await h.publicClient.getBlock()).timestamp) + 3600, + allowedCalls: [ + { + target: h.addresses.target, + selector: 'increment()', + }, + ], }, ], }) @@ -82,7 +87,6 @@ describe('AGW race regressions (real v5 contracts)', () => { const retried = await owner.agentic.create('intended', { rules: [] }); expect(retried.index).toBe(next.index); }); - it('R4 an allowance revoked after the SDK read it stays revoked; the outbound fails on-chain', async () => { const { wallet } = await owner.agentic.create('allowance-race', { rules: [], diff --git a/packages/core/__agw-local__/agw-local.spec.ts b/packages/core/__agw-local__/agw-local.spec.ts index 93f0a3db..d3ae46d2 100644 --- a/packages/core/__agw-local__/agw-local.spec.ts +++ b/packages/core/__agw-local__/agw-local.spec.ts @@ -20,7 +20,6 @@ import { } from '../src'; import { AGENTIC_ERROR_CODE } from '../src/lib/agentic/errors'; import { startHarness, type Harness } from './harness'; - const TARGET_ABI = parseAbi([ 'function increment()', 'function counter() view returns (uint256)', @@ -32,15 +31,12 @@ const WALLET_ABI = parseAbi([ 'function agentOf(bytes32) view returns (address)', 'function owner() view returns (address)', ]); - const inAnHour = () => Math.floor(Date.now() / 1000) + 3600; - describe('AGW SDK against real v5 contracts (local anvil)', () => { let h: Harness; let owner: PushChain; let ownerAddr: Address; let agentAddr: Address; - beforeAll(async () => { h = await startHarness(); owner = await h.client(0); @@ -50,7 +46,6 @@ describe('AGW SDK against real v5 contracts (local anvil)', () => { afterAll(async () => { await h?.stop(); }); - const counter = () => h.publicClient.readContract({ address: h.addresses.target, @@ -63,7 +58,6 @@ describe('AGW SDK against real v5 contracts (local anvil)', () => { abi: WALLET_ABI, functionName: 'checkpointCount', }); - it('derive() predicts slot 0 from the signer identity and matches the factory', async () => { const d = await owner.agentic.derive(); expect(d.index).toBe(0); @@ -76,7 +70,6 @@ describe('AGW SDK against real v5 contracts (local anvil)', () => { })) as readonly [Address, boolean]; expect(d.address).toBe(getAddress(predicted)); }); - let bare: Address; it('create(label, { rules: [] }) deploys a bare wallet without funding it', async () => { const created = await owner.agentic.create('scratch', { rules: [] }); @@ -93,7 +86,6 @@ describe('AGW SDK against real v5 contracts (local anvil)', () => { rulesCount: 0, }); }); - let wallet: Address; let rule1: Hex; it('create with a native rule returns the receipt-confirmed ID; grant order and IDs match the contract', async () => { @@ -101,10 +93,13 @@ describe('AGW SDK against real v5 contracts (local anvil)', () => { rules: [ { agent: agentAddr, - target: h.addresses.target, - selector: 'increment()', validUntil: inAnHour(), - maxCalls: 2, + allowedCalls: [ + { + target: h.addresses.target, + selector: 'increment()', + }, + ], }, ], }); @@ -122,7 +117,6 @@ describe('AGW SDK against real v5 contracts (local anvil)', () => { // Sequential fallback on a 7702-less localnet is reported honestly. expect(typeof created.tx.atomic).toBe('boolean'); }); - it('list() returns both deployed wallets plus the next undeployed slot', async () => { const { wallets } = await owner.agentic.list(); expect( @@ -133,16 +127,13 @@ describe('AGW SDK against real v5 contracts (local anvil)', () => { [2, '', false, 0], ]); }); - - it('rules.get / rules.list decode active terms without exposing internal spend', async () => { + it('rules.get / rules.list decode active terms including spend', async () => { const rec = await owner.agentic.wallet(wallet).rules.get(rule1); expect(rec.agent).toBe(agentAddr); expect(rec.rule).toMatchObject({ - target: h.addresses.target, - maxCalls: 2, - maxValuePerCall: BigInt(0), + allowedCalls: [{ target: h.addresses.target, maxValue: BigInt(0) }], }); - expect(rec).not.toHaveProperty('spent'); + expect(rec).toHaveProperty('spent'); expect( await readNativeCounters( h.publicClient, @@ -154,7 +145,6 @@ describe('AGW SDK against real v5 contracts (local anvil)', () => { const { rules } = await owner.agentic.wallet(wallet).rules.list(); expect(rules.map((r) => r.rulesId)).toEqual([rule1]); }); - let agent: PushChain; it('agent client: universal.account is the wallet, origin stays the signer, sends go through executeAsAgent', async () => { agent = await h.client(1, { agenticWallet: wallet }); @@ -176,8 +166,7 @@ describe('AGW SDK against real v5 contracts (local anvil)', () => { expect(tx.agentic).toMatchObject({ wallet, door: 'agent', rulesId: rule1 }); expect(tx.agentic?.rawTo?.toLowerCase()).toBe(wallet.toLowerCase()); }); - - it('agent sends do not tick checkpoints; the policy enforces maxCalls on-chain', async () => { + it('agent sends do not tick checkpoints; counters increase without the retired maxCalls limit', async () => { const cpBefore = await checkpointCount(wallet); await ( await agent.universal.sendTransaction({ @@ -190,7 +179,7 @@ describe('AGW SDK against real v5 contracts (local anvil)', () => { ).wait(); expect(await checkpointCount(wallet)).toBe(cpBefore); const rec = await owner.agentic.wallet(wallet).rules.get(rule1); - expect(rec).not.toHaveProperty('spent'); + expect(rec).toHaveProperty('spent'); expect( await readNativeCounters( h.publicClient, @@ -199,27 +188,24 @@ describe('AGW SDK against real v5 contracts (local anvil)', () => { rule1 ) ).toMatchObject({ callsUsed: 2 }); - const err = await agent.universal - .sendTransaction({ + await ( + await agent.universal.sendTransaction({ to: h.addresses.target, data: encodeFunctionData({ abi: TARGET_ABI, functionName: 'increment', }), }) - .catch((e) => e); - expect(err).toBeInstanceOf(AgenticRevertError); - expect(err.decodedError?.name).toBe( - 'PolicyCheckReverted(CallLimitReached)' - ); + ).wait(); + expect( + (await owner.agentic.wallet(wallet).rules.get(rule1)).spent + ).toMatchObject({ kind: 'native', callsUsed: 3 }); }); - it('a stranger cannot initialize against the wallet', async () => { await expect(h.client(2, { agenticWallet: wallet })).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.NOT_OWNER_OR_AGENT, }); }); - it('owner client goes through execute and ticks one OWNER_ACTION checkpoint per call', async () => { const ownerAgw = await h.client(0, { agenticWallet: wallet }); const before = await checkpointCount(wallet); @@ -245,7 +231,6 @@ describe('AGW SDK against real v5 contracts (local anvil)', () => { 'OWNER_ACTION', ]); }); - it('native agent arrays require an available atomic executor instead of sequential fallback', async () => { const data = encodeFunctionData({ abi: TARGET_ABI, @@ -263,7 +248,6 @@ describe('AGW SDK against real v5 contracts (local anvil)', () => { code: AGENTIC_ERROR_CODE.CAPABILITY_UNAVAILABLE, }); }); - let rule2: Hex; it('rules.update replaces atomically: five checkpoints, old disabled, new usable with reset counters', async () => { const before = await checkpointCount(wallet); @@ -273,10 +257,13 @@ describe('AGW SDK against real v5 contracts (local anvil)', () => { rulesId: rule1, rule: { agent: agentAddr, - target: h.addresses.target, - selector: 'increment()', validUntil: inAnHour(), - maxCalls: 1, + allowedCalls: [ + { + target: h.addresses.target, + selector: 'increment()', + }, + ], }, }, ], @@ -295,7 +282,7 @@ describe('AGW SDK against real v5 contracts (local anvil)', () => { 'RULES_GRANTED', ]); const rec = await owner.agentic.wallet(wallet).rules.get(rule2); - expect(rec).not.toHaveProperty('spent'); + expect(rec).toHaveProperty('spent'); expect( await readNativeCounters( h.publicClient, @@ -315,7 +302,6 @@ describe('AGW SDK against real v5 contracts (local anvil)', () => { }); expect(tx.agentic?.rulesId).toBe(rule2); }); - it('full checkpoint history is contiguous and matches checkpointCount()', async () => { const { checkpoints } = await owner.agentic.wallet(wallet).checkpoints(); expect(checkpoints.map((c) => c.seq)).toEqual( @@ -324,18 +310,17 @@ describe('AGW SDK against real v5 contracts (local anvil)', () => { expect(BigInt(checkpoints.length)).toBe(await checkpointCount(wallet)); expect(checkpoints[0].kind).toBe('RULES_GRANTED'); }); - it('bare revoke is refused; revoke({ all: true }) disables every rule', async () => { await expect( - owner.agentic.wallet(wallet).rules.revoke(undefined as unknown as Hex[]) - ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.REVOKE_NEEDS_TARGET }); + owner.agentic.wallet(wallet).rules.delete(undefined as unknown as Hex[]) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.DELETE_NEEDS_TARGET }); await expect( - owner.agentic.wallet(wallet).rules.revoke([]) + owner.agentic.wallet(wallet).rules.delete([]) ).rejects.toMatchObject({ - code: AGENTIC_ERROR_CODE.REVOKE_NEEDS_TARGET, + code: AGENTIC_ERROR_CODE.DELETE_NEEDS_TARGET, }); await ( - await owner.agentic.wallet(wallet).rules.revoke({ all: true }) + await owner.agentic.wallet(wallet).rules.delete({ all: true }) ).wait(); const { rules } = await owner.agentic.wallet(wallet).rules.list(); expect(rules).toEqual([]); @@ -349,21 +334,23 @@ describe('AGW SDK against real v5 contracts (local anvil)', () => { }) ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.NO_RULES_FOR_CHAIN }); }); - it('a non-owner cannot write rules (fails before signing)', async () => { const stranger = await h.client(2); await expect( stranger.agentic.wallet(wallet).rules.add([ { agent: agentAddr, - target: h.addresses.target, - selector: 'increment()', validUntil: inAnHour(), + allowedCalls: [ + { + target: h.addresses.target, + selector: 'increment()', + }, + ], }, ]) ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.NOT_WALLET_OWNER }); }); - it('a read-only client can read but never sign, even with the owner address', async () => { const ro = await h.readOnlyClient(0, { agenticWallet: wallet }); expect(ro.universal.account).toBe(wallet); @@ -372,9 +359,13 @@ describe('AGW SDK against real v5 contracts (local anvil)', () => { ro.agentic.wallet(wallet).rules.add([ { agent: agentAddr, - target: h.addresses.target, - selector: 'increment()', validUntil: inAnHour(), + allowedCalls: [ + { + target: h.addresses.target, + selector: 'increment()', + }, + ], }, ]) ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.READ_ONLY }); @@ -382,7 +373,6 @@ describe('AGW SDK against real v5 contracts (local anvil)', () => { ro.universal.sendTransaction({ to: h.addresses.target, data: '0x' }) ).toThrow(/Read only/); }); - it('reinitialize without agenticWallet returns an ordinary client', async () => { const ownerAgw = await h.client(0, { agenticWallet: wallet }); const plain = await ownerAgw.reinitialize( @@ -395,7 +385,6 @@ describe('AGW SDK against real v5 contracts (local anvil)', () => { ); expect(plain.universal.account.toLowerCase()).toBe(ownerAddr.toLowerCase()); }); - it('signer-level and cascade entry points are closed in agentic mode', async () => { const ownerAgw = await h.client(0, { agenticWallet: wallet }); const code = AGENTIC_ERROR_CODE.NOT_ALLOWED_IN_AGENTIC_MODE; @@ -431,14 +420,12 @@ describe('AGW SDK against real v5 contracts (local anvil)', () => { }) ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.FROM_NOT_ALLOWED }); }); - it('getAccountStatus stays signer-scoped in agentic mode', async () => { const ownerAgw = await h.client(0, { agenticWallet: wallet }); const status = await ownerAgw.getAccountStatus(); expect(status.mode).toBe('signer'); expect(ownerAgw.universal.account).toBe(wallet); }); - it('errors from the agentic surface are typed', () => { expect( new AgenticError(AGENTIC_ERROR_CODE.AMBIGUOUS_RULE, 'x') diff --git a/packages/core/__agw-local__/labels.spec.ts b/packages/core/__agw-local__/labels.spec.ts index 86786d7e..1f377f13 100644 --- a/packages/core/__agw-local__/labels.spec.ts +++ b/packages/core/__agw-local__/labels.spec.ts @@ -66,13 +66,13 @@ describe('v5 label SDK against real contracts', () => { (x) => x.address === made.wallet )?.label ).toBe('after'); - expect(await count(made.wallet)).toBe(before + BigInt(1)); + expect(await count(made.wallet)).toBe(before); expect(hook).toHaveBeenCalledWith( expect.objectContaining({ id: 'AGENTIC-TX-199-01' }) ); await w.setLabel(''); expect((await w.info()).label).toBe(`AGW ${made.index + 1}`); - expect(await count(made.wallet)).toBe(before + BigInt(2)); + expect(await count(made.wallet)).toBe(before); }); it('direct contract rename changes no checkpoint; subsequent SDK reads show it', async () => { diff --git a/packages/core/__agw-local__/native-multi-action.spec.ts b/packages/core/__agw-local__/native-multi-action.spec.ts new file mode 100644 index 00000000..ecd23af5 --- /dev/null +++ b/packages/core/__agw-local__/native-multi-action.spec.ts @@ -0,0 +1,267 @@ +/** + * Multi-action native rules against the real pinned v5 contracts: one rule ID + * allows several Push functions, each metered by its own stored terms. + * Unified section-6 public shape; the contract support + * (AGW MAX_NATIVE_ACTIONS = 8) is what these tests exercise. + */ +import { + encodeFunctionData, + getAddress, + parseAbi, + type Address, + type Hex, +} from 'viem'; +import { AgenticRevertError, CHAIN, type Rule, type PushChain } from '../src'; +import { PUSH_BATCH_EXECUTOR_ADDRESS } from '../src/lib/constants/chain'; +import { startHarness, type Harness } from './harness'; +const ABI = parseAbi([ + 'function increment()', + 'function counter() view returns (uint256)', + 'function deposit(address beneficiary, uint256 amount) payable', + 'function lastBeneficiary() view returns (address)', + 'function received() view returns (uint256)', +]); +const WALLET = parseAbi(['function checkpointCount() view returns (uint64)']); +const beneficiary = getAddress('0x00000000000000000000000000000000000b0b0b'); +let h: Harness; +let owner: PushChain; +let previousExecutor: Address | undefined; +beforeAll(async () => { + h = await startHarness(18553); + previousExecutor = PUSH_BATCH_EXECUTOR_ADDRESS[CHAIN.PUSH_LOCALNET]; + PUSH_BATCH_EXECUTOR_ADDRESS[CHAIN.PUSH_LOCALNET] = await h.deploy( + 0, + 'HarnessAtomicExecutor', + 'HarnessFixtures.sol' + ); + owner = await h.client(0); +}); +afterAll(async () => { + if (previousExecutor) + PUSH_BATCH_EXECUTOR_ADDRESS[CHAIN.PUSH_LOCALNET] = previousExecutor; + else delete PUSH_BATCH_EXECUTOR_ADDRESS[CHAIN.PUSH_LOCALNET]; + await h?.stop(); +}); +const now = async () => Number((await h.publicClient.getBlock()).timestamp); +const counter = () => + h.publicClient.readContract({ + address: h.addresses.target, + abi: ABI, + functionName: 'counter', + }); +const increment = () => + encodeFunctionData({ abi: ABI, functionName: 'increment' }); +const deposit = (to: Address, amount: bigint) => + encodeFunctionData({ abi: ABI, functionName: 'deposit', args: [to, amount] }); +async function rule(): Promise { + return { + agent: h.wallets[1].account!.address, + validUntil: (await now()) + 3600, + allowedCalls: [ + { + target: h.addresses.target, + selector: 'increment()', + }, + { + target: h.addresses.target, + selector: 'deposit(address,uint256)', + pins: [ + { arg: 0, expected: beneficiary }, + { arg: 1, max: BigInt(10) }, + ], + }, + ], + }; +} +describe('multi-action native rules (real v5 contracts)', () => { + let wallet: Address; + let rulesId: Hex; + let agent: PushChain; + beforeAll(async () => { + const created = await owner.agentic.create('multi-action', { + rules: [await rule()], + }); + wallet = created.wallet; + rulesId = created.rulesIds[0]; + agent = await h.client(1, { agenticWallet: wallet }); + }); + it('grants both functions under ONE rule ID and reads them back in order', async () => { + const { rules } = await owner.agentic.wallet(wallet).rules.list(); + expect(rules.map((r) => r.rulesId)).toEqual([rulesId]); + const decoded = rules[0].rule as Rule; + expect(decoded.allowedCalls.map((a) => a.selector)).toEqual([ + '0xd09de08a', + '0x47e7ef24', + ]); + expect(rules[0].spent).toMatchObject({ + kind: 'native', + actions: [ + expect.objectContaining({ callsUsed: 0 }), + expect.objectContaining({ callsUsed: 0 }), + ], + }); + expect(decoded.allowedCalls[1]).toMatchObject({ + pins: [ + { + arg: 0, + expected: `0x${'0'.repeat(24)}${beneficiary.slice(2).toLowerCase()}`, + }, + { arg: 1, max: BigInt(10) }, + ], + }); + }); + it('the agent can call each allowed function; each is checked against its own terms', async () => { + const before = await counter(); + const t1 = await agent.universal.sendTransaction({ + to: h.addresses.target, + data: increment(), + }); + expect((await t1.wait()).status).toBe(1); + expect(t1.agentic?.rulesId).toBe(rulesId); + const t2 = await agent.universal.sendTransaction({ + to: h.addresses.target, + data: deposit(beneficiary, BigInt(5)), + }); + expect((await t2.wait()).status).toBe(1); + expect(t2.agentic?.rulesId).toBe(rulesId); + expect(await counter()).toBe(before + BigInt(2)); + expect( + await h.publicClient.readContract({ + address: h.addresses.target, + abi: ABI, + functionName: 'lastBeneficiary', + }) + ).toBe(beneficiary); + }); + it('per-action limits still apply: a wrong pin and an over-cap amount are rejected on-chain', async () => { + const wrongPin = await agent.universal + .sendTransaction({ + to: h.addresses.target, + data: deposit(h.wallets[3].account!.address, BigInt(5)), + }) + .catch((e) => e); + expect(wrongPin).toBeInstanceOf(AgenticRevertError); + expect(wrongPin.decodedError?.name).toBe( + 'PolicyCheckReverted(ArgPinMismatch)' + ); + const overCap = await agent.universal + .sendTransaction({ + to: h.addresses.target, + data: deposit(beneficiary, BigInt(11)), + }) + .catch((e) => e); + expect(overCap).toBeInstanceOf(AgenticRevertError); + }); + it('a function outside the rule’s actions is rejected on-chain', async () => { + const err = await agent.universal + .sendTransaction({ + to: h.addresses.target, + data: encodeFunctionData({ abi: ABI, functionName: 'received' }), + }) + .catch((e) => e); + expect(err).toBeInstanceOf(AgenticRevertError); + }); + it('per-action spend is independent across repeated calls', async () => { + await ( + await agent.universal.sendTransaction({ + to: h.addresses.target, + data: increment(), + }) + ).wait(); + await ( + await agent.universal.sendTransaction({ + to: h.addresses.target, + data: increment(), + }) + ).wait(); + await ( + await agent.universal.sendTransaction({ + to: h.addresses.target, + data: deposit(beneficiary, BigInt(5)), + }) + ).wait(); + expect( + (await owner.agentic.wallet(wallet).rules.get(rulesId)).spent + ).toMatchObject({ + kind: 'native', + actions: [ + { callsUsed: 3, amountSpent: BigInt(0) }, + { callsUsed: 2, amountSpent: BigInt(10) }, + ], + }); + }); + it('one atomic agent batch can mix functions of the same rule', async () => { + const created = await owner.agentic.create('multi-action-batch', { + rules: [await rule()], + }); + const batchAgent = await h.client(1, { agenticWallet: created.wallet }); + const before = await counter(); + const tx = await batchAgent.universal.sendTransaction({ + to: h.addresses.target, + data: [ + { to: h.addresses.target, value: BigInt(0), data: increment() }, + { + to: h.addresses.target, + value: BigInt(0), + data: deposit(beneficiary, BigInt(7)), + }, + ], + }); + expect((await tx.wait()).status).toBe(1); + expect(tx.agentic?.rulesId).toBe(created.rulesIds[0]); + expect(await counter()).toBe(before + BigInt(2)); + // All-or-nothing: an over-cap item reverts the whole batch, including the increment. + const mid = await counter(); + const bad = await batchAgent.universal + .sendTransaction({ + to: h.addresses.target, + data: [ + { to: h.addresses.target, value: BigInt(0), data: increment() }, + { + to: h.addresses.target, + value: BigInt(0), + data: deposit(beneficiary, BigInt(11)), + }, + ], + }) + .catch((e) => e); + expect(bad).toBeInstanceOf(AgenticRevertError); + expect(await counter()).toBe(mid); + }); + it('rules.update replaces a multi-action rule atomically, asserting every action’s spend', async () => { + const before = (await h.publicClient.readContract({ + address: wallet, + abi: WALLET, + functionName: 'checkpointCount', + })) as bigint; + const replacement: Rule = { + ...(await rule()), + allowedCalls: [(await rule()).allowedCalls[0]], + }; + const res = await owner.agentic + .wallet(wallet) + .rules.update({ rules: [{ rulesId, rule: replacement }] }); + // 2 assertions + revoke + grant = 4 OWNER_ACTION, then RULES_REVOKED and RULES_GRANTED. + expect( + (await h.publicClient.readContract({ + address: wallet, + abi: WALLET, + functionName: 'checkpointCount', + })) as bigint + ).toBe(before + BigInt(6)); + const { rules } = await owner.agentic.wallet(wallet).rules.list(); + expect(rules.map((r) => r.rulesId)).toEqual([res.rules[0].rulesId]); + expect((rules[0].rule as Rule).allowedCalls).toHaveLength(1); + // The new rule starts with fresh counters: increment() works again. + expect( + ( + await ( + await agent.universal.sendTransaction({ + to: h.addresses.target, + data: increment(), + }) + ).wait() + ).status + ).toBe(1); + }); +}); diff --git a/packages/core/__agw-local__/svm-backend.spec.ts b/packages/core/__agw-local__/svm-backend.spec.ts index 98e22be9..57046e94 100644 --- a/packages/core/__agw-local__/svm-backend.spec.ts +++ b/packages/core/__agw-local__/svm-backend.spec.ts @@ -212,7 +212,9 @@ describe('internal prepared SVM backend on v5', () => { expect(stored.chainNamespace).toBe(CHAIN.SOLANA_DEVNET); await expect( owner.agentic.wallet(s.wallet).rules.get(s.id) - ).resolves.toMatchObject({ rule: { format: 'decoded', pins: s.input.terms.pins } }); + ).resolves.toMatchObject({ + rule: { format: 'decoded', pins: s.input.terms.pins }, + }); }); it('runs context, IDL, quote, allowance, wrapping and real token pull/burn as the agent', async () => { const s = await setup(); @@ -360,7 +362,7 @@ describe('internal prepared SVM backend on v5', () => { }); it('generic owner revocation disables a SVM rule without public decoding', async () => { const s = await setup(); - await (await owner.agentic.wallet(s.wallet).rules.revoke([s.id])).wait(); + await (await owner.agentic.wallet(s.wallet).rules.delete([s.id])).wait(); await expect(cfg(s.wallet, s.id)).rejects.toMatchObject({ code: 'RULE_NOT_FOUND', }); @@ -407,7 +409,7 @@ describe('internal prepared SVM backend on v5', () => { runtime.execute = async (params, options) => { if (kind === 'revocation') await ( - await owner.agentic.wallet(s.wallet).rules.revoke([s.id]) + await owner.agentic.wallet(s.wallet).rules.delete([s.id]) ).wait(); else await h.write(0, s.wallet, v5.abis.wallet, 'execute', [ diff --git a/packages/core/__agw-local__/svm-public.spec.ts b/packages/core/__agw-local__/svm-public.spec.ts index 1e8c423d..d28448e2 100644 --- a/packages/core/__agw-local__/svm-public.spec.ts +++ b/packages/core/__agw-local__/svm-public.spec.ts @@ -1,14 +1,17 @@ -/** Public named-IDL API against actual AGW/URP; destination/gateway are fixtures. */ +/** Public numeric-pin API against actual AGW/URP; destination/gateway are fixtures. */ import { PublicKey } from '@solana/web3.js'; import type { Idl } from '@coral-xyz/anchor'; import { + hexToBytes, + sha256, + toHex, encodeFunctionData, parseAbi, zeroAddress, type Address, type Hex, } from 'viem'; -import { CHAIN, PushChain, AgenticRevertError, type SolanaRule } from '../src'; +import { CHAIN, PushChain, AgenticRevertError, type Rule } from '../src'; import type { AgenticRuntime } from '../src/lib/agentic/runtime'; import { v5 } from '../src/lib/agentic/contracts/v5'; import { clearRegistry } from '../src/lib/orchestrator/svm-idl/registry'; @@ -21,7 +24,9 @@ const idl: Idl = { instructions: [ { name: 'deposit', - discriminator: [1, 2, 3, 4, 5, 6, 7, 8], + discriminator: Array.from( + hexToBytes(sha256(toHex('global:deposit'))).slice(0, 8) + ), accounts: [{ name: 'cea_authority', writable: true }], args: [{ name: 'amount', type: 'u64' }], }, @@ -35,7 +40,7 @@ const TOKEN = parseAbi([ const CORE = parseAbi(['function setGasToken(string,address)']); const rt = (c: PushChain) => (c as unknown as { agenticRuntime: AgenticRuntime }).agenticRuntime; -describe('public Solana IDL rules on actual v5', () => { +describe('public Solana rules on actual v5', () => { let h: Harness, owner: PushChain, token: Address; beforeAll(async () => { h = await startHarness(18561); @@ -74,7 +79,7 @@ describe('public Solana IDL rules on actual v5', () => { }), }); } - const rule = (): SolanaRule => ({ + const rule = (): Rule => ({ agent: h.wallets[1].account!.address, chainNamespace: CHAIN.SOLANA_DEVNET, validUntil: Math.floor(Date.now() / 1000) + 3600, @@ -82,12 +87,14 @@ describe('public Solana IDL rules on actual v5', () => { assets: [ { token: zeroAddress, maxPerCall: BigInt(5), maxTotal: BigInt(10) }, ], - allowedInstructions: [ + allowedCalls: [ { - program, - instruction: { idl, name: 'deposit' }, - accounts: [{ name: 'cea_authority', expected: { kind: 'walletCEA' } }], - fields: [{ name: 'amount', max: BigInt(5) }], + target: program, + selector: 'deposit(u64)', + pins: [ + { account: 0, expected: PushChain.CONSTANTS.AGENTIC.WALLET }, + { arg: 0, max: BigInt(5) }, + ], }, ], }); @@ -102,10 +109,20 @@ describe('public Solana IDL rules on actual v5', () => { }); expect((await wallet.rules.list()).rules).toHaveLength(1); const update = await wallet.rules.update({ - rules: [{ rulesId: made.rulesIds[0], rule: rule() }], + rules: [ + { + rulesId: made.rulesIds[0], + rule: { ...record.rule, validUntil: record.validUntil + 60 }, + }, + ], }); expect(update.rules[0].rulesId).not.toBe(made.rulesIds[0]); - await (await wallet.rules.revoke([update.rules[0].rulesId])).wait(); + const reread = await wallet.rules.get(update.rules[0].rulesId); + expect(reread.rule).toEqual({ + ...record.rule, + validUntil: record.validUntil + 60, + }); + await (await wallet.rules.delete([update.rules[0].rulesId])).wait(); expect((await wallet.rules.list()).rules).toHaveLength(0); }); it('agent public send uses wallet context, mapped errors and replay metadata', async () => { @@ -353,27 +370,16 @@ describe('public Solana IDL rules on actual v5', () => { }, }); const input = rule(); - input.assets = [{ token: mint, maxPerCall: BigInt(5) }]; - input.outputTokens = [output]; - input.allowedInstructions[0].instruction = { - idl: { - ...idl, - instructions: [ - { - ...idl.instructions[0], - accounts: [ - { name: 'cea_authority' }, - { name: 'inputAta', writable: true }, - { name: 'outputAta', writable: true }, - ], - }, - ], - }, - name: 'deposit', - }; - input.allowedInstructions[0].accounts.push( - { name: 'inputAta', expected: { kind: 'walletATA', token: mint } }, - { name: 'outputAta', expected: { kind: 'walletATA', token: output } } + input.assets = [ + { token: mint, maxPerCall: BigInt(5), maxTotal: BigInt(5) }, + ]; + input.allowedCalls[0].pins!.push( + { account: 1, expected: PushChain.CONSTANTS.AGENTIC.WALLET, token: mint }, + { + account: 2, + expected: PushChain.CONSTANTS.AGENTIC.WALLET, + token: output, + } ); const made = await source.agentic.create('public-spl', { rules: [input] }); const read = await source.agentic @@ -385,9 +391,7 @@ describe('public Solana IDL rules on actual v5', () => { expect(read.rule.pins.map((p) => p.expected)).toEqual( read.rule.ceaAccounts ); - expect(read.rule.assets[0].maxTotal).toBe( - BigInt(2) ** BigInt(256) - BigInt(1) - ); + expect(read.rule.assets[0].maxTotal).toBe(BigInt(5)); await h.publicClient.waitForTransactionReceipt({ hash: await h.wallets[4].sendTransaction({ to: made.wallet, @@ -443,15 +447,17 @@ describe('public Solana IDL rules on actual v5', () => { .status ).toBe('success'); }); - it('invalid named input and removed ref never submit a transaction', async () => { + it('invalid account position and removed ref never submit a transaction', async () => { const before = await h.publicClient.getTransactionCount({ address: h.wallets[0].account!.address, }); const r = rule(); - r.allowedInstructions[0].accounts[0].name = 'typo'; + r.allowedCalls[0].pins = [ + { account: 64, expected: PushChain.CONSTANTS.AGENTIC.WALLET }, + ]; await expect( owner.agentic.create('invalid', { rules: [r] }) - ).rejects.toThrow('unknown IDL account'); + ).rejects.toThrow('account position'); await expect( owner.agentic.create('removed-ref', { rules: [{ ...rule(), ref: `0x${'11'.repeat(32)}` } as never], diff --git a/packages/core/__agw-local__/v5-multiasset.spec.ts b/packages/core/__agw-local__/v5-multiasset.spec.ts index 0d5f04fe..2fe6edf4 100644 --- a/packages/core/__agw-local__/v5-multiasset.spec.ts +++ b/packages/core/__agw-local__/v5-multiasset.spec.ts @@ -1,3 +1,5 @@ +import { buildPresetApi } from '../src/lib/agentic/presets'; +import { publicRules } from '../src/lib/agentic/public-rule'; /** Actual v5 AGW/URP/engine. Token/core/gateway and destination lookup are local fixtures; no bridge/TSS proof. */ import { encodeFunctionData, @@ -6,12 +8,13 @@ import { type Address, type Hex, } from 'viem'; -import { CHAIN, type PushChain, type UniversalRule } from '../src'; +import { CHAIN, type PushChain, type Rule } from '../src'; import type { AgenticRuntime } from '../src/lib/agentic/runtime'; import { updateRules } from '../src/lib/agentic/management/rules-write'; import { createWallet } from '../src/lib/agentic/management/create'; import { configId } from '../src/lib/agentic/codec/ids'; -import { UINT256_MAX } from '../src/lib/agentic/codec/defaults'; +import { prepareWalletRules } from '../src/lib/agentic/management/prepare'; +import { Snapshot } from '../src/lib/agentic/reads/snapshot'; import { buildSession } from '../src/lib/agentic/codec/session'; import { encodeNativeTerms, @@ -69,11 +72,11 @@ describe('v5 multi-asset SDK management and execution', () => { }; } function rule( - assets: UniversalRule['assets'] = [ + assets: Rule['assets'] = [ { token: a, maxPerCall: BigInt(5), maxTotal: BigInt(7) }, { token: b, maxPerCall: BigInt(9), maxTotal: BigInt(30) }, ] - ): UniversalRule { + ): Rule { return { agent: h.wallets[1].account!.address, chainNamespace: CHAIN_NS, @@ -149,6 +152,42 @@ describe('v5 multi-asset SDK management and execution', () => { args: [configId(wallet, id, action), wallet], }); } + it('a fixture preset produces rules accepted by public create and enforced by real contracts', async () => { + const presets = buildPresetApi([ + { + constant: 'DEXES', + name: 'Local fixture only', + chains: [ + { + chainNamespace: CHAIN_NS, + allowedCalls: [ + { target: DEST, selector: 'increment()', app: 'Harness' }, + ], + maxGasPerCall: BigInt(10) ** BigInt(16), + }, + ], + }, + ]); + const { rules } = presets.get('DEXES', { + agent: h.wallets[1].account!.address, + validUntil: Math.floor(Date.now() / 1000) + 3600, + assets: [ + { + chainNamespace: CHAIN_NS, + token: a, + maxPerCall: BigInt(5), + maxTotal: BigInt(7), + }, + ], + }); + const { wallet, id, send } = await setup(rules[0]); + await waitPush(send(a, BigInt(5))); + expect((await stored(wallet, id)).assets[0].spent).toBe(BigInt(5)); + await expect(send(a, BigInt(3))).rejects.toMatchObject({ + decodedError: { name: 'PolicyCheckReverted(TotalSpendCapExceeded)' }, + }); + }); + it('public create encodes two ordered assets; public get reconstructs source-token caps', async () => { const { wallet, id } = await setup(); expect((await stored(wallet, id)).assets.map((x) => x.token)).toEqual([ @@ -215,7 +254,7 @@ describe('v5 multi-asset SDK management and execution', () => { BigInt(9), ]); }); - it('omitted total encodes maxUint256; explicit zero prohibits movement', async () => { + it('omitted and explicit zero totals both prohibit movement', async () => { const { wallet, id, send } = await setup( rule([ { token: a, maxPerCall: BigInt(5) }, @@ -223,9 +262,12 @@ describe('v5 multi-asset SDK management and execution', () => { ]) ); expect((await stored(wallet, id)).assets.map((x) => x.maxTotal)).toEqual([ - UINT256_MAX, + BigInt(0), BigInt(0), ]); + await expect(send(a, BigInt(1))).rejects.toMatchObject({ + decodedError: { name: 'PolicyCheckReverted(TotalSpendCapExceeded)' }, + }); await expect(send(b, BigInt(1))).rejects.toMatchObject({ decodedError: { name: 'PolicyCheckReverted(TotalSpendCapExceeded)' }, }); @@ -285,7 +327,7 @@ describe('v5 multi-asset SDK management and execution', () => { }; await expect( updateRules(racing, h.generation, wallet, { - rules: [{ rulesId: id, rule: rule() }], + rules: [{ rulesId: id, rule: publicRules([rule()])[0] }], }) ).rejects.toMatchObject({ decodedError: { name: 'AssetSpentMismatch' } }); expect( @@ -304,11 +346,26 @@ describe('v5 multi-asset SDK management and execution', () => { }) ).toBe(count); }); - it('duplicate grants are allowed, but an ambiguous send fails before any signature', async () => { + it('out-of-band duplicate contract grants still make sends ambiguous', async () => { const created = await owner.agentic.create('multiple', { - rules: [rule(), rule()], + rules: [rule()], }); - expect(new Set(created.rulesIds).size).toBe(2); + const rt = internal(owner); + const [prepared] = await prepareWalletRules( + rt, + h.generation, + h.wallets[0].account!.address, + created.wallet, + publicRules([rule()]), + await Snapshot.at(rt.reader) + ); + await h.write( + 0, + created.wallet, + h.generation.contracts.abis.wallet as never, + 'grantRules', + [prepared.session] + ); const agent = await h.client(1, { agenticWallet: created.wallet }); await expect( agent.universal.sendTransaction({ diff --git a/packages/core/__agw-local__/vectors.spec.ts b/packages/core/__agw-local__/vectors.spec.ts index ed603c0d..dcc5d291 100644 --- a/packages/core/__agw-local__/vectors.spec.ts +++ b/packages/core/__agw-local__/vectors.spec.ts @@ -1,3 +1,4 @@ +import type { AgenticRuntime } from '../src/lib/agentic/runtime'; /** * Contract-generated vectors for the pure AGW codecs. Every `expected` value * below is computed BY THE PINNED CONTRACTS (pure engine/factory views, or @@ -127,7 +128,14 @@ describe('contract-generated AGW vectors (v5)', () => { maxValueTotal: BigInt(50), maxCalls: 3, }; - const created = await owner.agentic.create('vectors', { rules: [rule] }); + const { createWallet } = await import( + '../src/lib/agentic/management/create' + ); + const created = await createWallet( + (owner as unknown as { agenticRuntime: AgenticRuntime }).agenticRuntime, + 'vectors', + { rules: [rule] } + ); const wallet = created.wallet; const rid = created.rulesIds[0]; const [actionId] = (await pc.readContract({ diff --git a/packages/core/__e2e__/agw/create.spec.ts b/packages/core/__e2e__/agw/create.spec.ts index 177f7201..bd05db7c 100644 --- a/packages/core/__e2e__/agw/create.spec.ts +++ b/packages/core/__e2e__/agw/create.spec.ts @@ -11,16 +11,13 @@ import { setupAgw, type AgwFixture, } from './_fixture'; - const d = AGW_E2E_ENABLED ? describe : describe.skip; - d('agw create', () => { let f: AgwFixture; beforeAll(async () => { f = await setupAgw(); - }, 300_000); + }, 300000); afterAll(() => f?.teardown()); - it('1. bare wallet: factory records the owner and index, no rules, no implicit funding', async () => { const before = await f.owner.agentic.derive(); const created = await f.owner.agentic.create('e2e-bare', { rules: [] }); @@ -60,16 +57,19 @@ d('agw create', () => { block: created.tx.blockNumber, }); }); - it('2. wallet with a native rule returns the receipt-confirmed rule ID', async () => { const created = await f.owner.agentic.create('e2e-rules', { rules: [ { agent: f.agentAddress, - target: f.ownerAddress, - selector: 'value-only', validUntil: inSeconds(3600), - maxValuePerCall: BigInt(1), + allowedCalls: [ + { + target: f.ownerAddress, + selector: 'value-only', + maxValue: BigInt(1), + }, + ], }, ], }); diff --git a/packages/core/__e2e__/agw/identity-gas.spec.ts b/packages/core/__e2e__/agw/identity-gas.spec.ts index 7d79af4e..b90c5bee 100644 --- a/packages/core/__e2e__/agw/identity-gas.spec.ts +++ b/packages/core/__e2e__/agw/identity-gas.spec.ts @@ -29,10 +29,8 @@ import { setupAgw, type AgwFixture, } from './_fixture'; - const d = AGW_E2E_ENABLED ? describe : describe.skip; const SINK = getAddress('0x000000000000000000000000000000000000dEaD'); - async function ueaOf(address: string, chain: CHAIN): Promise
{ const r = await PushChain.utils.account.deriveExecutorAccount( PushChain.utils.account.toUniversal(address, { chain }), @@ -42,31 +40,31 @@ async function ueaOf(address: string, chain: CHAIN): Promise
{ ); return getAddress(r.address); } - d('agw identity', () => { let f: AgwFixture; beforeAll(async () => { f = await setupAgw(); - }, 300_000); + }, 300000); afterAll(() => f?.teardown()); - const walletFor = async (agent: Address) => { const created = await f.owner.agentic.create('e2e-identity', { rules: [ { agent, - target: SINK, - selector: 'value-only', validUntil: inSeconds(3600), - maxValuePerCall: BigInt(1000), - maxValueTotal: BigInt(10_000), + allowedCalls: [ + { + target: SINK, + selector: 'value-only', + maxValue: BigInt(1000), + }, + ], }, ], }); await f.fundPC(created.wallet, parseEther('0.001')); return created.wallet; }; - it('1. an EVM key on Sepolia acts through its Sepolia UEA; origin and account status stay signer-scoped', async () => { const key = process.env['EVM_PRIVATE_KEY'] as Hex; if (!key) throw new Error('EVM_PRIVATE_KEY is required'); @@ -92,8 +90,7 @@ d('agw identity', () => { expect(tx.from).toBe(wallet); expect(tx.origin.startsWith('eip155:11155111:')).toBe(true); f.evidence('external-evm-agent', { wallet, uea, tx: tx.hash }); - }, 600_000); - + }, 600000); it('2. first use of an undeployed external UEA takes the one-time fee lock; the next action pays from the UEA', async () => { const key = generatePrivateKey(); const addr = privateKeyToAccount(key).address; @@ -136,8 +133,7 @@ d('agw identity', () => { ).wait(); expect(second.hasEvent('SEND-TX-105-01')).toBe(false); f.evidence('first-use-uea', { wallet, uea }); - }, 900_000); - + }, 900000); it('3. a Solana-origin key acts through its Solana UEA on a Push destination', async () => { const raw = process.env['SOLANA_PRIVATE_KEY']; if (!raw) throw new Error('SOLANA_PRIVATE_KEY is required'); @@ -160,5 +156,5 @@ d('agw identity', () => { expect(tx.from).toBe(wallet); expect(tx.origin.startsWith('solana:')).toBe(true); f.evidence('solana-origin-agent', { wallet, uea, tx: tx.hash }); - }, 600_000); + }, 600000); }); diff --git a/packages/core/__e2e__/agw/labels.spec.ts b/packages/core/__e2e__/agw/labels.spec.ts index 8940c1ea..a5ca52d4 100644 --- a/packages/core/__e2e__/agw/labels.spec.ts +++ b/packages/core/__e2e__/agw/labels.spec.ts @@ -24,13 +24,12 @@ import { setupAgw, type AgwFixture, } from './_fixture'; - const d = AGW_E2E_ENABLED ? describe : describe.skip; d('agw labels', () => { let f: AgwFixture; beforeAll(async () => { f = await setupAgw(); - }, 300_000); + }, 300000); afterAll(() => f?.teardown()); const count = (address: Address) => f.push.readContract({ @@ -38,7 +37,6 @@ d('agw labels', () => { abi: v5.abis.wallet, functionName: 'checkpointCount', }); - it('1. default and custom deployment labels are stored and listed', async () => { const empty = await f.owner.agentic.create('', { rules: [] }); const custom = await f.owner.agentic.create('e2e-v5-custom', { rules: [] }); @@ -65,14 +63,13 @@ d('agw labels', () => { `AGW ${empty.index + 1}` ); expect(await count(empty.wallet)).toBe(BigInt(0)); - expect(await count(custom.wallet)).toBe(BigInt(1)); + expect(await count(custom.wallet)).toBe(BigInt(0)); f.evidence('v5-label-default-custom', { wallets: [empty.wallet, custom.wallet], indices: [empty.index, custom.index], hashes: [empty.tx.hash, custom.tx.hash, renamed.hash], }); }); - it('2. owner rename and empty reset update info/list, emit LabelSet and tick the owner door', async () => { const made = await f.owner.agentic.create('before', { rules: [] }); const w = f.owner.agentic.wallet(made.wallet), @@ -100,13 +97,13 @@ d('agw labels', () => { (x) => x.address === made.wallet )?.label ).toBe('after'); - expect(await count(made.wallet)).toBe(before + BigInt(1)); + expect(await count(made.wallet)).toBe(before); expect(hook).toHaveBeenCalledWith( expect.objectContaining({ id: 'AGENTIC-TX-199-01' }) ); const reset = await w.setLabel(''); expect((await w.info()).label).toBe(`AGW ${made.index + 1}`); - expect(await count(made.wallet)).toBe(before + BigInt(2)); + expect(await count(made.wallet)).toBe(before); f.evidence('v5-label-rename-reset', { wallet: made.wallet, hashes: [tx.hash, reset.hash], @@ -114,7 +111,6 @@ d('agw labels', () => { checkpointsAfter: await count(made.wallet), }); }); - it('3. UTF-8 byte boundaries are accepted or rejected without changing wallet state', async () => { const made = await f.owner.agentic.create('🙂'.repeat(16), { rules: [] }); const w = f.owner.agentic.wallet(made.wallet); @@ -147,15 +143,18 @@ d('agw labels', () => { unchangedNextSlot: next.index, }); }); - it('4. an agent cannot rename through either the SDK or the contract', async () => { const made = await f.owner.agentic.create('owner-only', { rules: [ { agent: f.agentAddress, - target: f.ownerAddress, - selector: 'value-only', validUntil: inSeconds(3600), + allowedCalls: [ + { + target: f.ownerAddress, + selector: 'value-only', + }, + ], }, ], }); @@ -207,7 +206,6 @@ d('agw labels', () => { checkpoints: before, }); }); - it('5. an external EVM owner creates and renames through its UEA', async () => { const key = process.env['EVM_PRIVATE_KEY'] as Hex; if (!key) throw new Error('EVM_PRIVATE_KEY is required'); @@ -241,7 +239,7 @@ d('agw labels', () => { ).toBe('e2e-uea-after'); const reset = await w.setLabel(''); expect((await w.info()).label).toBe(`AGW ${made.index + 1}`); - expect(await count(made.wallet)).toBe(before + BigInt(2)); + expect(await count(made.wallet)).toBe(before); f.evidence('v5-label-uea-owner', { wallet: made.wallet, owner: uea, @@ -291,7 +289,7 @@ d('agw labels', () => { ).toBe('Solana owner'); const reset = await w.setLabel(''); expect((await w.info()).label).toBe(`AGW ${made.index + 1}`); - expect(await count(made.wallet)).toBe(before + BigInt(2)); + expect(await count(made.wallet)).toBe(before); f.evidence('v5-label-solana-owner', { wallet: made.wallet, owner: uea, @@ -299,19 +297,20 @@ d('agw labels', () => { checkpointsBefore: before, checkpointsAfter: await count(made.wallet), }); - }, 600_000); - - it('7. renaming an active wallet preserves rules, spend and remaining agent budget', async () => { + }, 600000); + it('7. renaming an active wallet preserves rules, spend and per-call agent cap', async () => { const made = await f.owner.agentic.create('active-before', { rules: [ { agent: f.agentAddress, - target: f.ownerAddress, - selector: 'value-only', validUntil: inSeconds(3600), - maxValuePerCall: BigInt(1), - maxValueTotal: BigInt(2), - maxCalls: 3, + allowedCalls: [ + { + target: f.ownerAddress, + selector: 'value-only', + maxValue: BigInt(1), + }, + ], }, ], }); @@ -354,7 +353,7 @@ d('agw labels', () => { functionName: 'grantNonce', }) ).toBe(nonceBefore); - expect(await count(made.wallet)).toBe(checkpointsBefore + BigInt(1)); + expect(await count(made.wallet)).toBe(checkpointsBefore); const second = await agent.universal.sendTransaction({ to: f.ownerAddress, value: BigInt(1), @@ -372,9 +371,9 @@ d('agw labels', () => { address: f.agentAddress, }); await expect( - agent.universal.sendTransaction({ to: f.ownerAddress, value: BigInt(1) }) + agent.universal.sendTransaction({ to: f.ownerAddress, value: BigInt(2) }) ).rejects.toMatchObject({ - decodedError: { name: 'PolicyCheckReverted(TotalValueExceeded)' }, + decodedError: { name: 'PolicyCheckReverted(ValueExceedsCap)' }, }); expect(await f.push.getTransactionCount({ address: f.agentAddress })).toBe( agentNonce @@ -387,7 +386,7 @@ d('agw labels', () => { made.rulesIds[0] ) ).toEqual(spendAfter); - expect(await count(made.wallet)).toBe(checkpointsBefore + BigInt(1)); + expect(await count(made.wallet)).toBe(checkpointsBefore); f.evidence('v5-label-active-rule', { wallet: made.wallet, rulesId: made.rulesIds[0], @@ -397,7 +396,6 @@ d('agw labels', () => { grantNonce: nonceBefore, }); }); - it('8. a failed owner batch rolls back the earlier rename and all checkpoints', async () => { const made = await f.owner.agentic.create('batch-before', { rules: [] }); const w = f.owner.agentic.wallet(made.wallet), @@ -435,7 +433,7 @@ d('agw labels', () => { const hash = await client.sendTransaction({ chain: client.chain, to: made.wallet, - gas: BigInt(400_000), + gas: BigInt(400000), data: v5.encodeExecute( calls.map((call) => ({ target: call.to, diff --git a/packages/core/__e2e__/agw/lifecycle.spec.ts b/packages/core/__e2e__/agw/lifecycle.spec.ts index 105a5ea2..77b3cc1b 100644 --- a/packages/core/__e2e__/agw/lifecycle.spec.ts +++ b/packages/core/__e2e__/agw/lifecycle.spec.ts @@ -14,9 +14,7 @@ import { setupAgw, type AgwFixture, } from './_fixture'; - const d = AGW_E2E_ENABLED ? describe : describe.skip; - d('agw lifecycle', () => { let f: AgwFixture; let wallet: Address; @@ -24,11 +22,14 @@ d('agw lifecycle', () => { const sink = getAddress('0x000000000000000000000000000000000000dEaD'); const rule = (maxValuePerCall: bigint) => ({ agent: f.agentAddress, - target: sink, - selector: 'value-only' as const, validUntil: inSeconds(3600), - maxValuePerCall, - maxValueTotal: maxValuePerCall * BigInt(10), + allowedCalls: [ + { + target: sink, + selector: 'value-only' as const, + maxValue: maxValuePerCall, + }, + ], }); const count = () => f.push.readContract({ @@ -36,15 +37,13 @@ d('agw lifecycle', () => { abi: v5.abis.wallet, functionName: 'checkpointCount', }) as Promise; - beforeAll(async () => { f = await setupAgw(); wallet = (await f.owner.agentic.create('e2e-lifecycle', { rules: [] })) .wallet; await f.fundPC(wallet, parseEther('0.01')); - }, 300_000); + }, 300000); afterAll(() => f?.teardown()); - it('1. rules.add grants with one RULES_GRANTED checkpoint', async () => { const before = await count(); const added = await f.owner.agentic @@ -60,7 +59,6 @@ d('agw lifecycle', () => { ref: original, }); }); - it('2. rules.update: old ID disabled, new ID usable with reset counters, five checkpoint ticks', async () => { const agent = await f.agent(wallet); await ( @@ -107,7 +105,6 @@ d('agw lifecycle', () => { checkpointDelta: 5, }); }); - it('3. checkpoint history is contiguous and matches checkpointCount()', async () => { const { checkpoints } = await f.owner.agentic.wallet(wallet).checkpoints(); expect(checkpoints.map((c) => c.seq)).toEqual( @@ -115,10 +112,9 @@ d('agw lifecycle', () => { ); expect(BigInt(checkpoints.length)).toBe(await count()); }); - it('4. revoke({ all: true }) leaves no enabled rules', async () => { await ( - await f.owner.agentic.wallet(wallet).rules.revoke({ all: true }) + await f.owner.agentic.wallet(wallet).rules.delete({ all: true }) ).wait(); expect((await f.owner.agentic.wallet(wallet).rules.list()).rules).toEqual( [] diff --git a/packages/core/__e2e__/agw/management-extended.spec.ts b/packages/core/__e2e__/agw/management-extended.spec.ts index 6c5bb6b3..0a0b1210 100644 --- a/packages/core/__e2e__/agw/management-extended.spec.ts +++ b/packages/core/__e2e__/agw/management-extended.spec.ts @@ -4,25 +4,29 @@ import type { AgenticRuntime } from '../../src/lib/agentic/runtime'; import { v5 } from '../../src/lib/agentic/contracts/v5'; import { setupAgw, inSeconds, type AgwFixture } from './_fixture'; import { readNativeCounters } from '../shared/agw-state'; - const d = process.env['AGW_E2E'] === '1' ? describe : describe.skip; const runtime = (client: PushChain) => - (client as unknown as { agenticRuntime: AgenticRuntime }).agenticRuntime; - + ( + client as unknown as { + agenticRuntime: AgenticRuntime; + } + ).agenticRuntime; d('agw extended management', () => { let f: AgwFixture; beforeAll(async () => { f = await setupAgw(); - }, 300_000); + }, 300000); afterAll(() => f?.teardown()); const rule = (agent = f.agentAddress) => ({ agent, - target: f.ownerAddress, - selector: 'value-only' as const, validUntil: inSeconds(3600), - maxValuePerCall: BigInt(10), - maxValueTotal: BigInt(100), - maxCalls: 10, + allowedCalls: [ + { + target: f.ownerAddress, + selector: 'value-only' as const, + maxValue: BigInt(10), + }, + ], }); const count = (wallet: Address) => f.push.readContract({ @@ -68,36 +72,37 @@ d('agw extended management', () => { txHash: made.tx.hash, }); }); - it('2. same-agent multiplicity is ambiguous before signing and selective revoke restores uncached lookup', async () => { - const made = await f.owner.agentic.create('e2e-ambiguous', { - rules: [rule(), rule()], - }); - await f.fundPC(made.wallet, BigInt(10)); - const agent = await f.agent(made.wallet), - nonce = await f.push.getTransactionCount({ address: f.agentAddress }); + it('2. create and add reject duplicate agent/chain rules before signing', async () => { + const nonce = await f.push.getTransactionCount({ address: f.ownerAddress }); await expect( - agent.universal.sendTransaction({ to: f.ownerAddress, value: BigInt(1) }) - ).rejects.toMatchObject({ - code: 'AMBIGUOUS_RULE', - details: { rulesIds: expect.arrayContaining(made.rulesIds) }, - }); - expect(await f.push.getTransactionCount({ address: f.agentAddress })).toBe( + f.owner.agentic.create('duplicate', { rules: [rule(), rule()] }) + ).rejects.toMatchObject({ code: 'DUPLICATE_RULE' }); + expect(await f.push.getTransactionCount({ address: f.ownerAddress })).toBe( nonce ); - await ( - await f.owner.agentic.wallet(made.wallet).rules.revoke([made.rulesIds[0]]) - ).wait(); - const tx = await agent.universal.sendTransaction({ - to: f.ownerAddress, - value: BigInt(1), + const made = await f.owner.agentic.create('single', { rules: [rule()] }); + const w = f.owner.agentic.wallet(made.wallet), + before = await count(made.wallet); + const afterCreate = await f.push.getTransactionCount({ + address: f.ownerAddress, + }); + await expect(w.rules.add([rule()])).rejects.toMatchObject({ + code: 'DUPLICATE_RULE', }); - expect((await tx.wait()).status).toBe(1); - expect(tx.agentic?.rulesId).toBe(made.rulesIds[1]); - f.evidence('extended-uncached-lookup', { + expect(await f.push.getTransactionCount({ address: f.ownerAddress })).toBe( + afterCreate + ); + expect(await count(made.wallet)).toBe(before); + expect((await w.rules.list()).rules.map((r) => r.rulesId)).toEqual( + made.rulesIds + ); + await (await w.rules.delete(made.rulesIds)).wait(); + const added = await w.rules.add([rule()]); + expect(added.rulesIds[0]).not.toBe(made.rulesIds[0]); + f.evidence('duplicate-rule-guards', { wallet: made.wallet, - removed: made.rulesIds[0], - selected: made.rulesIds[1], - txHash: tx.hash, + deleted: made.rulesIds, + added: added.rulesIds, }); }); it('3. multi-rule add and revoke are atomic batches with exact checkpoint counts', async () => { @@ -114,7 +119,7 @@ d('agw extended management', () => { expect((await w.rules.list()).rules.map((r) => r.rulesId)).toEqual( expect.arrayContaining(added.rulesIds) ); - await (await w.rules.revoke(added.rulesIds)).wait(); + await (await w.rules.delete(added.rulesIds)).wait(); expect(await count(made.wallet)).toBe(BigInt(8)); expect((await w.rules.list()).rules).toEqual([]); const cp = await w.checkpoints({ sinceBlock: added.tx.blockNumber }); @@ -132,14 +137,14 @@ d('agw extended management', () => { }), w = f.owner.agentic.wallet(made.wallet), nonce = await f.push.getTransactionCount({ address: f.ownerAddress }); - await expect(w.rules.revoke([])).rejects.toMatchObject({ - code: 'REVOKE_NEEDS_TARGET', + await expect(w.rules.delete([])).rejects.toMatchObject({ + code: 'DELETE_NEEDS_TARGET', }); await expect( - w.rules.revoke([made.rulesIds[0], made.rulesIds[0]]) + w.rules.delete([made.rulesIds[0], made.rulesIds[0]]) ).rejects.toMatchObject({ code: 'INVALID_RULE' }); await expect( - w.rules.revoke([`0x${'12'.repeat(32)}`]) + w.rules.delete([`0x${'12'.repeat(32)}`]) ).rejects.toMatchObject({ code: 'RULE_NOT_FOUND' }); expect(await f.push.getTransactionCount({ address: f.ownerAddress })).toBe( nonce @@ -249,7 +254,13 @@ d('agw extended management', () => { ? (await f.owner.agentic.wallet(competing.wallet).rules.list()).rules : undefined; f.evidence('extended-index-race-error', { - code: (raceError as { code?: string } | undefined)?.code, + code: ( + raceError as + | { + code?: string; + } + | undefined + )?.code, expectedWallet: expectedNext.address, expectedIndex: expectedNext.index, competingWallet: competing?.wallet, diff --git a/packages/core/__e2e__/agw/native-batch.spec.ts b/packages/core/__e2e__/agw/native-batch.spec.ts index 5a8e06ac..04c9515c 100644 --- a/packages/core/__e2e__/agw/native-batch.spec.ts +++ b/packages/core/__e2e__/agw/native-batch.spec.ts @@ -9,7 +9,6 @@ import { setupAgw, type AgwFixture, } from './_fixture'; - const d = AGW_E2E_ENABLED ? describe : describe.skip; const SINK = getAddress('0x000000000000000000000000000000000000dEaD'); const calls = () => @@ -18,32 +17,31 @@ const calls = () => value: BigInt(1000), data: '0x' as Hex, })); - d('agw native batch', () => { let f: AgwFixture; beforeAll(async () => { f = await setupAgw(); - }, 300_000); + }, 300000); afterAll(() => f?.teardown()); - - const create = async (maxCalls: number) => { + const create = async (_maxCalls: number) => { const created = await f.owner.agentic.create('e2e-native-batch', { rules: [ { agent: f.agentAddress, - target: SINK, - selector: 'value-only', validUntil: inSeconds(3600), - maxValuePerCall: BigInt(1000), - maxValueTotal: BigInt(5000), - maxCalls, + allowedCalls: [ + { + target: SINK, + selector: 'value-only', + maxValue: BigInt(1000), + }, + ], }, ], }); await f.fundPC(created.wallet, parseEther('0.001')); return { ...created, agent: await f.agent(created.wallet) }; }; - it('1. sender-preserving atomic native batch meters both actions', async () => { const { wallet, rulesIds, agent } = await create(3); const before = await f.push.getBalance({ address: wallet }); @@ -78,12 +76,14 @@ d('agw native batch', () => { tx: tx.hash, }); }); - it('2. a later policy failure rolls back earlier native actions', async () => { const { wallet, rulesIds, agent } = await create(1); const before = await f.push.getBalance({ address: wallet }); await expect( - agent.universal.sendTransaction({ to: SINK, data: calls() }) + agent.universal.sendTransaction({ + to: SINK, + data: [calls()[0], { ...calls()[1], value: BigInt(1001) }], + }) ).rejects.toBeInstanceOf(AgenticRevertError); expect(await f.push.getBalance({ address: wallet })).toBe(before); expect( diff --git a/packages/core/__e2e__/agw/native-exec.spec.ts b/packages/core/__e2e__/agw/native-exec.spec.ts index 7217c145..ee3ca4b2 100644 --- a/packages/core/__e2e__/agw/native-exec.spec.ts +++ b/packages/core/__e2e__/agw/native-exec.spec.ts @@ -8,42 +8,52 @@ import { privateKeyToAccount, generatePrivateKey } from 'viem/accounts'; import { AgenticError, AgenticRevertError } from '../../src'; import { CHAIN } from '../../src/lib/constants/enums'; import { AGENTIC_ERROR_CODE } from '../../src/lib/agentic/errors'; -import { AGW_E2E_ENABLED, evmClient, inSeconds, setupAgw, type AgwFixture } from './_fixture'; - +import { + AGW_E2E_ENABLED, + evmClient, + inSeconds, + setupAgw, + type AgwFixture, +} from './_fixture'; const d = AGW_E2E_ENABLED ? describe : describe.skip; const CAP = parseEther('0.001'); - d('agw native', () => { let f: AgwFixture; let wallet: Address; let rulesId: Hex; - const recipient = getAddress(privateKeyToAccount(generatePrivateKey()).address); - + const recipient = getAddress( + privateKeyToAccount(generatePrivateKey()).address + ); beforeAll(async () => { f = await setupAgw(); const created = await f.owner.agentic.create('e2e-native', { rules: [ { agent: f.agentAddress, - target: recipient, - selector: 'value-only', validUntil: inSeconds(3600), - maxValuePerCall: CAP, - maxValueTotal: CAP * BigInt(3), + allowedCalls: [ + { + target: recipient, + selector: 'value-only', + maxValue: CAP, + }, + ], }, ], }); wallet = created.wallet; rulesId = created.rulesIds[0]; await f.fundPC(wallet, parseEther('0.01')); - }, 300_000); + }, 300000); afterAll(() => f?.teardown()); - it('1. agent door: value moves from the wallet under its rule; signer is origin, wallet is from', async () => { const agent = await f.agent(wallet); expect(agent.universal.account).toBe(wallet); const before = await f.push.getBalance({ address: recipient }); - const tx = await agent.universal.sendTransaction({ to: recipient, value: CAP }); + const tx = await agent.universal.sendTransaction({ + to: recipient, + value: CAP, + }); const receipt = await tx.wait(); expect(receipt.status).toBe(1); expect(await f.push.getBalance({ address: recipient })).toBe(before + CAP); @@ -51,51 +61,81 @@ d('agw native', () => { expect(receipt.from).toBe(wallet); expect(tx.origin.toLowerCase()).toContain(f.agentAddress.toLowerCase()); expect(tx.agentic).toMatchObject({ door: 'agent', rulesId }); - f.evidence('native-agent-send', { wallet, rulesId, tx: tx.hash, block: tx.blockNumber }); + f.evidence('native-agent-send', { + wallet, + rulesId, + tx: tx.hash, + block: tx.blockNumber, + }); }); - it('2. owner door: value moves from the wallet without rules', async () => { - const owner = await evmClient(process.env['PUSH_PRIVATE_KEY'] as Hex, CHAIN.PUSH_TESTNET_DONUT, f.manifest.network, wallet); + const owner = await evmClient( + process.env['PUSH_PRIVATE_KEY'] as Hex, + CHAIN.PUSH_TESTNET_DONUT, + f.manifest.network, + wallet + ); const before = await f.push.getBalance({ address: recipient }); - const tx = await owner.universal.sendTransaction({ to: recipient, value: CAP * BigInt(2) }); + const tx = await owner.universal.sendTransaction({ + to: recipient, + value: CAP * BigInt(2), + }); expect((await tx.wait()).status).toBe(1); - expect(await f.push.getBalance({ address: recipient })).toBe(before + CAP * BigInt(2)); + expect(await f.push.getBalance({ address: recipient })).toBe( + before + CAP * BigInt(2) + ); expect(tx.agentic?.door).toBe('owner'); }); - it('3. over-cap value reverts with the decoded policy gate and moves nothing', async () => { const agent = await f.agent(wallet); const before = await f.push.getBalance({ address: recipient }); - const err = await agent.universal.sendTransaction({ to: recipient, value: CAP + BigInt(1) }).catch((e) => e); + const err = await agent.universal + .sendTransaction({ to: recipient, value: CAP + BigInt(1) }) + .catch((e) => e); expect(err).toBeInstanceOf(AgenticRevertError); expect(err.decodedError?.name).toMatch(/^PolicyCheckReverted/); expect(await f.push.getBalance({ address: recipient })).toBe(before); }); - it('4. an unrelated signer cannot initialize against the wallet', async () => { const stranger = generatePrivateKey(); - await expect(evmClient(stranger, CHAIN.PUSH_TESTNET_DONUT, f.manifest.network, wallet)).rejects.toMatchObject({ + await expect( + evmClient(stranger, CHAIN.PUSH_TESTNET_DONUT, f.manifest.network, wallet) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.NOT_OWNER_OR_AGENT, }); }); - it('5. after revocation the agent fails before signing with NO_RULES_FOR_CHAIN', async () => { const agent = await f.agent(wallet); - await (await f.owner.agentic.wallet(wallet).rules.revoke([rulesId])).wait(); - const err = await agent.universal.sendTransaction({ to: recipient, value: BigInt(1) }).catch((e) => e); + await (await f.owner.agentic.wallet(wallet).rules.delete([rulesId])).wait(); + const err = await agent.universal + .sendTransaction({ to: recipient, value: BigInt(1) }) + .catch((e) => e); expect(err).toBeInstanceOf(AgenticError); expect(err.code).toBe(AGENTIC_ERROR_CODE.NO_RULES_FOR_CHAIN); }); - it('6. an expired rule still identifies the agent; the send is refused on-chain', async () => { const created = await f.owner.agentic.create('e2e-expiry', { - rules: [{ agent: f.agentAddress, target: recipient, selector: 'value-only', validUntil: inSeconds(45), maxValuePerCall: CAP, maxValueTotal: CAP }], + rules: [ + { + agent: f.agentAddress, + validUntil: inSeconds(45), + allowedCalls: [ + { + target: recipient, + selector: 'value-only', + maxValue: CAP, + }, + ], + }, + ], }); await f.fundPC(created.wallet, CAP * BigInt(2)); - await new Promise((r) => setTimeout(r, 60_000)); + await new Promise((r) => setTimeout(r, 60000)); const agent = await f.agent(created.wallet); - const err = await agent.universal.sendTransaction({ to: recipient, value: BigInt(1) }).catch((e) => e); + const err = await agent.universal + .sendTransaction({ to: recipient, value: BigInt(1) }) + .catch((e) => e); expect(err).toBeInstanceOf(AgenticRevertError); expect(err.decodedError?.name).toBe('PolicyCheckReverted(RulesExpired)'); - }, 300_000); + }, 300000); }); diff --git a/packages/core/__e2e__/agw/native-multi-action.spec.ts b/packages/core/__e2e__/agw/native-multi-action.spec.ts new file mode 100644 index 00000000..d5624ebe --- /dev/null +++ b/packages/core/__e2e__/agw/native-multi-action.spec.ts @@ -0,0 +1,663 @@ +/** Public multi-action native rules on checked Donut v5; no contract deployments. */ +import { + createWalletClient, + encodeFunctionData, + erc20Abi, + getAddress, + http, + parseEther, + type Address, + type Hex, +} from 'viem'; +import { privateKeyToAccount } from 'viem/accounts'; +import { AgenticRevertError, type Rule } from '../../src'; +import { CHAIN } from '../../src/lib/constants/enums'; +import { + CHAIN_INFO, + getPushViemChain, + PUSH_BATCH_EXECUTOR_ADDRESS, +} from '../../src/lib/constants/chain'; +import { getNativePRC20ForChain } from '../../src/lib/orchestrator/internals/helpers'; +import type { AgenticRuntime } from '../../src/lib/agentic/runtime'; +import { v5 } from '../../src/lib/agentic/contracts/v5'; +import { actionId } from '../../src/lib/agentic/codec/ids'; +import { readNativeActionConfigs } from '@e2e/shared/agw-state'; +import { + AGW_E2E_ENABLED, + inSeconds, + setupAgw, + type AgwFixture, +} from './_fixture'; +const d = AGW_E2E_ENABLED ? describe : describe.skip; +const ZERO = BigInt(0), + ONE = BigInt(1); +d('agw native multi-action', () => { + let f: AgwFixture, token: Address; + beforeAll(async () => { + if ( + parseEther(process.env['AGW_E2E_AGENT_PC'] ?? '0.5') > parseEther('0.5') + ) + throw new Error('Fixture agent budget is at most 0.5 PC'); + f = await setupAgw(); + token = getNativePRC20ForChain(CHAIN.ETHEREUM_SEPOLIA, f.manifest.network); + const balance = await f.push.readContract({ + address: token, + abi: erc20Abi, + functionName: 'balanceOf', + args: [f.ownerAddress], + }); + if (balance < BigInt(400)) + throw new Error( + 'Need 400 raw pETH units for bounded native multi-action fixtures' + ); + }, 300000); + afterAll(() => f?.teardown()); + const transfer = (amount: bigint, recipient = f.ownerAddress) => + encodeFunctionData({ + abi: erc20Abi, + functionName: 'transfer', + args: [recipient, amount], + }); + const rule = (): Rule => ({ + agent: f.agentAddress, + validUntil: inSeconds(3600), + allowedCalls: [ + { + target: f.ownerAddress, + selector: 'value-only', + maxValue: ONE, + }, + { + target: token, + selector: 'transfer(address,uint256)', + pins: [ + { arg: 0, expected: f.ownerAddress }, + { arg: 1, max: BigInt(3) }, + ], + }, + ], + }); + async function fixture(input = rule()) { + const made = await f.owner.agentic.create('e2e-native-multi', { + rules: [input], + }); + expect(made.rulesIds).toHaveLength(1); + await f.fundPC(made.wallet, BigInt(10)); + await ( + await f.owner.universal.sendTransaction({ + to: token, + data: transfer(BigInt(20), made.wallet), + }) + ).wait(); + const agent = await f.agent(made.wallet); + return { + ...made, + id: made.rulesIds[0] as Hex, + handle: f.owner.agentic.wallet(made.wallet), + agent, + }; + } + type Fixture = Awaited>; + const sendPC = (s: Fixture, value = ONE) => + s.agent.universal.sendTransaction({ to: f.ownerAddress, value }); + const sendToken = (s: Fixture, amount = ONE, recipient = f.ownerAddress) => + s.agent.universal.sendTransaction({ + to: token, + data: transfer(amount, recipient), + }); + const calls = (amount = BigInt(2)) => [ + { to: f.ownerAddress, value: ONE, data: '0x' as Hex }, + { to: token, value: ZERO, data: transfer(amount) }, + ]; + async function state(s: Fixture) { + const blockNumber = await f.push.getBlockNumber({ cacheTime: 0 }); + const [ + configs, + walletPC, + recipientPC, + walletToken, + recipientToken, + checkpointCount, + grantNonce, + ] = await Promise.all([ + readNativeActionConfigs( + f.push, + f.manifest.addresses, + s.wallet, + s.id, + blockNumber + ), + f.push.getBalance({ address: s.wallet, blockNumber }), + f.push.getBalance({ address: f.ownerAddress, blockNumber }), + f.push.readContract({ + address: token, + abi: erc20Abi, + functionName: 'balanceOf', + args: [s.wallet], + blockNumber, + }), + f.push.readContract({ + address: token, + abi: erc20Abi, + functionName: 'balanceOf', + args: [f.ownerAddress], + blockNumber, + }), + f.push.readContract({ + address: s.wallet, + abi: v5.abis.wallet, + functionName: 'checkpointCount', + blockNumber, + }), + f.push.readContract({ + address: s.wallet, + abi: v5.abis.wallet, + functionName: 'grantNonce', + blockNumber, + }), + ]); + return { + configs, + walletPC, + recipientPC, + walletToken, + recipientToken, + checkpointCount, + grantNonce, + }; + } + function config( + snapshot: Awaited>, + target: Address, + selector: Hex + ) { + const entry = snapshot.configs.find( + (entry) => entry.actionId === actionId(target, selector) + ); + if (!entry) throw new Error('Missing independent per-action config'); + return entry.config; + } + async function refused( + s: Fixture, + send: () => Promise, + gate: string + ) { + const before = await state(s), + nonce = await f.push.getTransactionCount({ address: f.agentAddress }); + const error = await send().then( + () => undefined, + (e: unknown) => e + ); + expect(error).toBeInstanceOf(AgenticRevertError); + expect((error as AgenticRevertError).decodedError?.name).toBe(gate); + expect(await state(s)).toEqual(before); + expect(await f.push.getTransactionCount({ address: f.agentAddress })).toBe( + nonce + ); + f.evidence('native-multi-refused', { + wallet: s.wallet, + id: s.id, + gate, + state: before, + agentNonce: nonce, + }); + } + it('1. one rule grants and reads both allowedCalls; decoded terms can be granted losslessly', async () => { + const s = await fixture(); + const { rules } = await s.handle.rules.list(); + expect(rules.map((r) => r.rulesId)).toEqual([s.id]); + const decoded = (await s.handle.rules.get(s.id)).rule as Rule; + expect(decoded.allowedCalls.map((a) => [a.target, a.selector])).toEqual([ + [f.ownerAddress, 'value-only'], + [token, '0xa9059cbb'], + ]); + expect(decoded.allowedCalls[1]).toMatchObject({ + pins: [{ arg: 0 }, { arg: 1, max: BigInt(3) }], + }); + const copy = await f.owner.agentic.create('e2e-native-multi-copy', { + rules: [decoded], + }); + expect( + (await f.owner.agentic.wallet(copy.wallet).rules.get(copy.rulesIds[0])) + .rule + ).toEqual(decoded); + const before = await state(s); + const pc = await sendPC(s); + await pc.wait(); + const afterPC = await state(s); + expect(afterPC.walletPC).toBe(before.walletPC - ONE); + expect(afterPC.recipientPC).toBe(before.recipientPC + ONE); + expect(config(afterPC, token, '0xa9059cbb')).toEqual( + config(before, token, '0xa9059cbb') + ); + const moved = await sendToken(s, BigInt(2)); + await moved.wait(); + const after = await state(s); + expect(after.walletToken).toBe(before.walletToken - BigInt(2)); + expect(after.recipientToken).toBe(before.recipientToken + BigInt(2)); + expect(config(after, f.ownerAddress, '0xffffffff')).toMatchObject({ + valueSpent: ONE, + callsUsed: 1, + }); + expect(config(after, token, '0xa9059cbb')).toMatchObject({ + amountSpent: BigInt(2), + callsUsed: 1, + }); + expect(after.checkpointCount).toBe(before.checkpointCount); + expect(pc.agentic?.rulesId).toBe(s.id); + expect(moved.agentic?.rulesId).toBe(s.id); + const replay = await f.owner.universal.trackTransaction(moved.hash); + expect(replay.from).toBe(s.wallet); + expect(replay.origin).toBe(moved.origin); + expect(replay.agentic?.rulesId).toBe(s.id); + f.evidence('native-multi-grant-read-send', { + wallet: s.wallet, + id: s.id, + copy: copy.wallet, + hashes: [s.tx.hash, copy.tx.hash, pc.hash, moved.hash], + state: after, + }); + }); + it('2. wrong pin, excess amount and an ungranted selector fail without changing either action', async () => { + const s = await fixture(); + await refused( + s, + () => sendToken(s, ONE, f.agentAddress), + 'PolicyCheckReverted(ArgPinMismatch)' + ); + await refused( + s, + () => sendToken(s, BigInt(4)), + 'PolicyCheckReverted(NativeAmountExceedsCap)' + ); + await refused( + s, + () => + s.agent.universal.sendTransaction({ + to: token, + data: encodeFunctionData({ + abi: erc20Abi, + functionName: 'approve', + args: [f.agentAddress, ONE], + }), + }), + 'NoPoliciesSet' + ); + expect( + await f.push.readContract({ + address: token, + abi: erc20Abi, + functionName: 'allowance', + args: [s.wallet, f.agentAddress], + }) + ).toBe(ZERO); + }); + it('3. per-call limits allow repeated calls with independent spend entries', async () => { + const s = await fixture(); + await (await sendPC(s)).wait(); + await (await sendPC(s)).wait(); + await (await sendPC(s, ZERO)).wait(); + await (await sendToken(s, BigInt(3))).wait(); + await (await sendToken(s, BigInt(2))).wait(); + await (await sendToken(s)).wait(); + const final = await state(s); + expect(config(final, f.ownerAddress, '0xffffffff')).toMatchObject({ + valueSpent: BigInt(2), + callsUsed: 3, + }); + expect(config(final, token, '0xa9059cbb')).toMatchObject({ + amountSpent: BigInt(6), + callsUsed: 3, + }); + f.evidence('native-multi-independent-counters', { + wallet: s.wallet, + id: s.id, + state: final, + }); + }); + it('4. a mixed-function atomic agent batch preserves sender, per-action spend and replay', async () => { + const s = await fixture(), + before = await state(s); + const tx = await s.agent.universal.sendTransaction({ + to: f.ownerAddress, + data: calls(), + }); + expect((await tx.wait()).status).toBe(1); + const raw = await f.push.getTransaction({ hash: tx.hash as Hex }); + expect(raw.type).toBe('eip7702'); + expect(getAddress(raw.from)).toBe(f.agentAddress); + expect(getAddress(raw.to as Address)).toBe(f.agentAddress); + const after = await state(s); + expect(after.walletPC).toBe(before.walletPC - ONE); + expect(after.walletToken).toBe(before.walletToken - BigInt(2)); + expect(config(after, f.ownerAddress, '0xffffffff')).toMatchObject({ + callsUsed: 1, + valueSpent: ONE, + }); + expect(config(after, token, '0xa9059cbb')).toMatchObject({ + callsUsed: 1, + amountSpent: BigInt(2), + }); + expect(after.checkpointCount).toBe(before.checkpointCount); + const replay = await f.owner.universal.trackTransaction(tx.hash); + expect(replay.from).toBe(s.wallet); + expect(replay.agentic?.nativeCalls).toEqual(calls()); + expect(replay.agentic?.rulesId).toBe(s.id); + f.evidence('native-multi-mixed-batch', { + wallet: s.wallet, + id: s.id, + hash: tx.hash, + state: after, + }); + }); + it('5. a failing second batch action rolls back PC, tokens and all action counters in a mined transaction', async () => { + const s = await fixture(); + // Establish delegation through the real public SDK transport, then reuse + // its configured executor for a bounded deliberately reverted transaction. + await ( + await s.agent.universal.sendTransaction({ + to: f.ownerAddress, + data: calls(ONE), + }) + ).wait(); + await refused( + s, + () => + s.agent.universal.sendTransaction({ + to: f.ownerAddress, + data: calls(BigInt(4)), + }), + 'PolicyCheckReverted(NativeAmountExceedsCap)' + ); + const executor = PUSH_BATCH_EXECUTOR_ADDRESS[CHAIN.PUSH_TESTNET_DONUT]; + if (!executor) throw new Error('Missing verified native batch executor'); + expect( + (await f.push.getCode({ address: f.agentAddress }))?.toLowerCase() + ).toBe(`0xef0100${executor.slice(2)}`.toLowerCase()); + const before = await state(s), + nonce = await f.push.getTransactionCount({ address: f.agentAddress }); + const raw = createWalletClient({ + account: privateKeyToAccount(f.agentKey), + chain: getPushViemChain(CHAIN.PUSH_TESTNET_DONUT), + transport: http(CHAIN_INFO[CHAIN.PUSH_TESTNET_DONUT].defaultRPC[0]), + }); + const data = v5.encodeExecute( + calls(BigInt(4)).map((c) => ({ + target: s.wallet, + value: ZERO, + data: v5.encodeExecuteAsAgent(s.id, { + target: c.to, + value: c.value, + data: c.data, + }), + })) + ); + const hash = await raw.sendTransaction({ + chain: raw.chain, + to: f.agentAddress, + data, + gas: BigInt(600000), + }); + const receipt = await f.push.waitForTransactionReceipt({ hash }); + expect(receipt.status).toBe('reverted'); + expect(receipt.logs).toHaveLength(0); + expect(await state(s)).toEqual(before); + expect(await f.push.getTransactionCount({ address: f.agentAddress })).toBe( + nonce + 1 + ); + f.evidence('native-multi-mined-rollback', { + wallet: s.wallet, + id: s.id, + hash, + block: receipt.blockNumber, + gasUsed: receipt.gasUsed, + state: before, + }); + }); + it('6. replacement guards every old action and records six checkpoints for a two-action rule', async () => { + const s = await fixture(); + await (await sendPC(s)).wait(); + await (await sendToken(s, BigInt(2))).wait(); + const before = await state(s), + input = rule(); + const replacement = await s.handle.rules.update({ + rules: [{ rulesId: s.id, rule: input }], + }); + const next = replacement.rules[0].rulesId as Hex; + expect(next).not.toBe(s.id); + await expect(s.handle.rules.get(s.id)).rejects.toMatchObject({ + code: 'RULE_NOT_FOUND', + }); + expect((await s.handle.rules.list()).rules.map((r) => r.rulesId)).toEqual([ + next, + ]); + expect( + await f.push.readContract({ + address: s.wallet, + abi: v5.abis.wallet, + functionName: 'checkpointCount', + }) + ).toBe(before.checkpointCount + BigInt(6)); + for (const { config: cfg } of await readNativeActionConfigs( + f.push, + f.manifest.addresses, + s.wallet, + next + )) { + expect(cfg).toMatchObject({ + valueSpent: ZERO, + amountSpent: ZERO, + callsUsed: 0, + }); + } + const reused = await sendToken(s); + await reused.wait(); + expect(reused.agentic?.rulesId).toBe(next); + const trimmed = await s.handle.rules.update({ + rules: [ + { + rulesId: next, + rule: { ...rule(), allowedCalls: [rule().allowedCalls[0]] }, + }, + ], + }); + expect( + (await s.handle.rules.get(trimmed.rules[0].rulesId)).rule + ).toMatchObject({ + allowedCalls: [{ target: f.ownerAddress, selector: 'value-only' }], + }); + const nonce = await f.push.getTransactionCount({ address: f.agentAddress }); + await expect(sendToken(s)).rejects.toMatchObject({ + decodedError: { name: 'NoPoliciesSet' }, + }); + expect(await f.push.getTransactionCount({ address: f.agentAddress })).toBe( + nonce + ); + f.evidence('native-multi-replacement', { + wallet: s.wallet, + oldId: s.id, + newId: next, + trimmedId: trimmed.rules[0].rulesId, + hashes: [replacement.tx.hash, reused.hash, trimmed.tx.hash], + }); + }); + it('7. spending the second action mid-update rejects the stale batch and a fresh retry succeeds', async () => { + const s = await fixture(), + before = await state(s); + const runtime = ( + f.owner as unknown as { + agenticRuntime: AgenticRuntime; + } + ).agenticRuntime; + const original = runtime.execute; + let injected = false, + spendHash: string | undefined; + runtime.execute = async (params, options) => { + if (!injected && params.to === s.wallet) { + injected = true; + const tx = await sendToken(s); + await tx.wait(); + spendHash = tx.hash; + } + return original(params, options); + }; + try { + await expect( + s.handle.rules.update({ rules: [{ rulesId: s.id, rule: rule() }] }) + ).rejects.toMatchObject({ + decodedError: { name: 'SpentMismatch' }, + }); + expect(injected).toBe(true); + } finally { + runtime.execute = original; + } + const after = await state(s); + expect(after.checkpointCount).toBe(before.checkpointCount); + expect(after.grantNonce).toBe(before.grantNonce); + expect(config(after, f.ownerAddress, '0xffffffff')).toEqual( + config(before, f.ownerAddress, '0xffffffff') + ); + expect(config(after, token, '0xa9059cbb')).toMatchObject({ + amountSpent: ONE, + callsUsed: 1, + }); + expect(after.walletToken).toBe(before.walletToken - ONE); + expect((await s.handle.rules.list()).rules.map((r) => r.rulesId)).toEqual([ + s.id, + ]); + const retry = await s.handle.rules.update({ + rules: [{ rulesId: s.id, rule: rule() }], + }); + expect( + await f.push.readContract({ + address: s.wallet, + abi: v5.abis.wallet, + functionName: 'checkpointCount', + }) + ).toBe(before.checkpointCount + BigInt(6)); + f.evidence('native-multi-second-action-race', { + wallet: s.wallet, + oldId: s.id, + newId: retry.rules[0].rulesId, + spendHash, + retryHash: retry.tx.hash, + stateAfterRace: after, + }); + }); + it('8. eight unique native allowedCalls are accepted; duplicate, mixed and ninth-action inputs never sign', async () => { + const allowedCalls = Array.from({ length: 8 }, (_, i) => ({ + target: getAddress(`0x${(0x1000 + i).toString(16).padStart(40, '0')}`), + selector: 'value-only' as const, + })); + const input = { + agent: f.agentAddress, + validUntil: inSeconds(3600), + allowedCalls, + }; + const made = await f.owner.agentic.create('e2e-native-eight', { + rules: [input], + }); + expect( + ( + (await f.owner.agentic.wallet(made.wallet).rules.get(made.rulesIds[0])) + .rule as Rule + ).allowedCalls + ).toHaveLength(8); + const invalid = [ + { ...input, allowedCalls: [] }, + { + ...input, + allowedCalls: [ + ...allowedCalls, + { + target: f.ownerAddress, + selector: 'value-only', + }, + ], + }, + { ...input, allowedCalls: [allowedCalls[0], allowedCalls[0]] }, + { ...input, target: f.ownerAddress }, + ]; + const next = await f.owner.agentic.derive(), + nonce = await f.push.getTransactionCount({ address: f.ownerAddress }); + for (const rule of invalid) + await expect( + f.owner.agentic.create('invalid-native-allowedCalls', { + rules: [rule as Rule], + }) + ).rejects.toMatchObject({ + code: expect.stringMatching(/INVALID_RULE|CAPABILITY_UNAVAILABLE/), + }); + expect(await f.owner.agentic.derive()).toEqual(next); + expect(await f.push.getTransactionCount({ address: f.ownerAddress })).toBe( + nonce + ); + f.evidence('native-multi-eight-boundary', { + wallet: made.wallet, + id: made.rulesIds[0], + hash: made.tx.hash, + unchangedNextSlot: next.index, + }); + }); + it('9. one expiry applies to all calls and expired calls move nothing', async () => { + const input = rule(), + expiry = inSeconds(60); + input.validUntil = expiry; + const s = await fixture(input); + expect((await s.handle.rules.get(s.id)).validUntil).toBe(expiry); + const deadline = Date.now() + 120_000; + while (Number((await f.push.getBlock()).timestamp) <= expiry) { + if (Date.now() > deadline) throw Error('Donut expiry wait timed out'); + await new Promise((r) => setTimeout(r, 2000)); + } + await refused(s, () => sendPC(s), 'PolicyCheckReverted(RulesExpired)'); + await refused(s, () => sendToken(s), 'PolicyCheckReverted(RulesExpired)'); + f.evidence('native-multi-shared-expiry', { + wallet: s.wallet, + id: s.id, + expiry, + }); + }, 300_000); + + it('10. malformed action objects and invalid rule expiry return structured errors before signing', async () => { + const base = rule(), + next = await f.owner.agentic.derive(), + nonce = await f.push.getTransactionCount({ address: f.ownerAddress }); + const invalid = [ + { ...base, allowedCalls: [null] }, + { ...base, allowedCalls: [42] }, + { + ...base, + validUntil: undefined, + allowedCalls: [ + { + ...base.allowedCalls[0], + }, + ], + }, + { + ...base, + validUntil: 1, + allowedCalls: [ + { + ...base.allowedCalls[0], + }, + ], + }, + ]; + for (const input of invalid) + await expect( + f.owner.agentic.create('invalid-multi-action', { + rules: [input as unknown as Rule], + }) + ).rejects.toMatchObject({ name: 'AgenticError', code: 'INVALID_RULE' }); + expect(await f.owner.agentic.derive()).toEqual(next); + expect(await f.push.getTransactionCount({ address: f.ownerAddress })).toBe( + nonce + ); + f.evidence('native-multi-invalid-input', { + unchangedNextSlot: next.index, + ownerNonce: nonce, + }); + }); +}); diff --git a/packages/core/__e2e__/agw/native-policy-extended.spec.ts b/packages/core/__e2e__/agw/native-policy-extended.spec.ts index 72c31502..c98c7435 100644 --- a/packages/core/__e2e__/agw/native-policy-extended.spec.ts +++ b/packages/core/__e2e__/agw/native-policy-extended.spec.ts @@ -1,20 +1,18 @@ /** Native policy limits, confirmed zero defaults and lossless raw-offset reuse. */ -import { PushChain, AgenticRevertError, type NativeRule } from '../../src'; +import { PushChain, AgenticRevertError, type RuleInput } from '../../src'; import { encodeFunctionData, erc20Abi, type Address } from 'viem'; import { getNativePRC20ForChain } from '../../src/lib/orchestrator/internals/helpers'; import { readNativeCounters } from '../shared/agw-state'; import { CHAIN } from '../../src/lib/constants/enums'; import { setupAgw, inSeconds, type AgwFixture } from './_fixture'; - const d = process.env['AGW_E2E'] === '1' ? describe : describe.skip; const chain = PushChain.CONSTANTS.CHAIN.PUSH_TESTNET_DONUT; - d('agw extended native policy', () => { let f: AgwFixture, token: Address; beforeAll(async () => { f = await setupAgw(); token = getNativePRC20ForChain(CHAIN.ETHEREUM_SEPOLIA, f.manifest.network); - }, 300_000); + }, 300000); afterAll(() => f?.teardown()); const transfer = (to: Address, amount: bigint) => encodeFunctionData({ @@ -30,15 +28,18 @@ d('agw extended native policy', () => { ) { const rule = { agent: f.agentAddress, - target: token, - selector: 'transfer(address,uint256)' as const, validUntil: inSeconds(3600), - ...(omitPc - ? {} - : { maxValuePerCall: BigInt(0), maxValueTotal: BigInt(0) }), - maxCalls, - pins: [{ arg: 0, expected: f.ownerAddress }], - amount: { arg: 1, maxPerCall: BigInt(10), maxTotal: total }, + allowedCalls: [ + { + target: token, + selector: 'transfer(address,uint256)' as const, + ...(omitPc ? {} : { maxValue: BigInt(0) }), + pins: [ + { arg: 0, expected: f.ownerAddress }, + { arg: 1, max: total === BigInt(0) ? BigInt(0) : BigInt(10) }, + ], + }, + ], }; const made = await f.owner.agentic.create('e2e-native-meter', { rules: [rule], @@ -105,16 +106,20 @@ d('agw extended native policy', () => { .wallet(s.wallet) .rules.get(s.rulesIds[0]); expect(record.rule).toMatchObject({ - pins: [ + allowedCalls: [ { - offset: 4, - expected: `0x${f.ownerAddress - .slice(2) - .toLowerCase() - .padStart(64, '0')}`, + pins: [ + { + arg: 0, + expected: `0x${f.ownerAddress + .slice(2) + .toLowerCase() + .padStart(64, '0')}`, + }, + { arg: 1, max: BigInt(10) }, + ], }, ], - amount: { offset: 36, maxPerCall: BigInt(10), maxTotal: BigInt(15) }, }); const before = await f.push.readContract({ address: token, @@ -155,23 +160,25 @@ d('agw extended native policy', () => { const s = await fixture(); await refused(s, () => s.send(BigInt(11)), 'NativeAmountExceedsCap'); }); - it('4. cumulative amount accepts the exact total and refuses the next unit', async () => { + it('4. repeated per-call amounts accumulate spend without a removed lifetime cap', async () => { const s = await fixture(BigInt(50), 10); await (await s.send(BigInt(10))).wait(); await (await s.send(BigInt(5))).wait(); expect((await s.counters()).amountSpent).toBe(BigInt(15)); - await refused(s, () => s.send(BigInt(1)), 'TotalNativeAmountExceeded'); + await (await s.send(BigInt(1))).wait(); + expect((await s.counters()).amountSpent).toBe(BigInt(16)); }); - it('5. call count accepts the exact count and refuses a zero-amount extra call', async () => { + it('5. repeated calls have no removed maxCalls limit', async () => { const s = await fixture(); await (await s.send(BigInt(1))).wait(); await (await s.send(BigInt(1))).wait(); expect((await s.counters()).callsUsed).toBe(2); - await refused(s, () => s.send(BigInt(0)), 'CallLimitReached'); + await (await s.send(BigInt(0))).wait(); + expect((await s.counters()).callsUsed).toBe(3); }); - it('6. explicit zero total forbids positive amount but permits a metered zero call', async () => { + it('6. explicit zero MAX pin forbids positive amount but permits a metered zero call', async () => { const s = await fixture(BigInt(50), 10, BigInt(0)); - await refused(s, () => s.send(BigInt(1)), 'TotalNativeAmountExceeded'); + await refused(s, () => s.send(BigInt(1)), 'NativeAmountExceedsCap'); await (await s.send(BigInt(0))).wait(); expect(await s.counters()).toMatchObject({ amountSpent: BigInt(0), @@ -216,10 +223,13 @@ d('agw extended native policy', () => { .wallet(s.wallet) .rules.get(s.rulesIds[0]); expect(record.rule).toMatchObject({ - maxValuePerCall: BigInt(0), - maxValueTotal: BigInt(0), + allowedCalls: [{ maxValue: BigInt(0) }], }); - await refused(s, () => s.send(BigInt(1), f.ownerAddress, BigInt(1)), 'ValueExceedsCap'); + await refused( + s, + () => s.send(BigInt(1), f.ownerAddress, BigInt(1)), + 'ValueExceedsCap' + ); const sent = await s.send(BigInt(1)); expect((await sent.wait()).status).toBe(1); expect(await s.counters()).toMatchObject({ @@ -228,21 +238,21 @@ d('agw extended native policy', () => { }); f.evidence('zero-pc-defaults', { wallet: s.wallet, txHash: sent.hash }); }); - it('10. decoded raw-offset rules can be granted again without fabricated ref metadata', async () => { + it('10. decoded arg-index rules can be granted again without fabricated ref metadata', async () => { const s = await fixture(BigInt(0)); const original = await f.owner.agentic .wallet(s.wallet) .rules.get(s.rulesIds[0]); expect(original).not.toHaveProperty('ref'); - const made = await f.owner.agentic.create('raw-offset-reuse', { - rules: [original.rule as NativeRule], + const made = await f.owner.agentic.create('arg-index-reuse', { + rules: [original.rule as RuleInput], }); const reread = await f.owner.agentic .wallet(made.wallet) .rules.get(made.rulesIds[0]); expect(reread.rule).toEqual(original.rule); expect(reread).not.toHaveProperty('ref'); - f.evidence('raw-offset-reuse', { + f.evidence('arg-index-reuse', { wallet: made.wallet, txHash: made.tx.hash, }); @@ -251,9 +261,13 @@ d('agw extended native policy', () => { const nonce = await f.push.getTransactionCount({ address: f.ownerAddress }); const rule = { agent: f.agentAddress, - target: token, - selector: 'transfer(address,uint256)', validUntil: inSeconds(3600), + allowedCalls: [ + { + target: token, + selector: 'transfer(address,uint256)', + }, + ], }; await expect( f.owner.agentic.create('invalid-ref', { diff --git a/packages/core/__e2e__/agw/responses-hooks.spec.ts b/packages/core/__e2e__/agw/responses-hooks.spec.ts index b026a005..683e70af 100644 --- a/packages/core/__e2e__/agw/responses-hooks.spec.ts +++ b/packages/core/__e2e__/agw/responses-hooks.spec.ts @@ -5,40 +5,67 @@ */ import { getAddress, parseEther, type Address } from 'viem'; import type { ProgressEvent } from '../../src/lib/progress-hook/progress-hook.types'; -import { AGW_E2E_ENABLED, inSeconds, setupAgw, type AgwFixture } from './_fixture'; - +import { + AGW_E2E_ENABLED, + inSeconds, + setupAgw, + type AgwFixture, +} from './_fixture'; const d = AGW_E2E_ENABLED ? describe : describe.skip; const SINK = getAddress('0x000000000000000000000000000000000000dEaD'); - d('agw responses', () => { let f: AgwFixture; let wallet: Address; beforeAll(async () => { f = await setupAgw(); const created = await f.owner.agentic.create('e2e-hooks', { - rules: [{ agent: f.agentAddress, target: SINK, selector: 'value-only', validUntil: inSeconds(3600), maxValuePerCall: BigInt(10), maxValueTotal: BigInt(100) }], + rules: [ + { + agent: f.agentAddress, + validUntil: inSeconds(3600), + allowedCalls: [ + { + target: SINK, + selector: 'value-only', + maxValue: BigInt(10), + }, + ], + }, + ], }); wallet = created.wallet; await f.fundPC(wallet, parseEther('0.001')); - }, 300_000); + }, 300000); afterAll(() => f?.teardown()); - it('1. init and per-call hooks each see every event once, through wait', async () => { const init: ProgressEvent[] = []; const perCall: ProgressEvent[] = []; const agent = await f.agent(wallet, (e) => init.push(e as ProgressEvent)); - const tx = await agent.universal.sendTransaction({ to: SINK, value: BigInt(1) }, { progressHook: (e) => perCall.push(e) }); + const tx = await agent.universal.sendTransaction( + { to: SINK, value: BigInt(1) }, + { progressHook: (e) => perCall.push(e) } + ); await tx.wait(); const ids = (xs: ProgressEvent[]) => xs.map((e) => e.id); expect(ids(perCall)).toEqual(ids(init)); - expect(new Set(ids(perCall).filter((i) => i.startsWith('AGENTIC-TX'))).size).toBe(ids(perCall).filter((i) => i.startsWith('AGENTIC-TX')).length); - expect(ids(perCall)).toEqual(expect.arrayContaining(['AGENTIC-TX-107', 'AGENTIC-TX-199-01', 'SEND-TX-199-01'])); + expect( + new Set(ids(perCall).filter((i) => i.startsWith('AGENTIC-TX'))).size + ).toBe(ids(perCall).filter((i) => i.startsWith('AGENTIC-TX')).length); + expect(ids(perCall)).toEqual( + expect.arrayContaining([ + 'AGENTIC-TX-107', + 'AGENTIC-TX-199-01', + 'SEND-TX-199-01', + ]) + ); expect(ids(perCall)).not.toContain('AGENTIC-TX-103'); }); - it('2. live and replayed responses agree on wallet from and signer origin', async () => { const agent = await f.agent(wallet); - const tx = await agent.universal.sendTransaction({ to: SINK, value: BigInt(1) }); + const tx = await agent.universal.sendTransaction({ + to: SINK, + value: BigInt(1), + }); await tx.wait(); const replay = await f.owner.universal.trackTransaction(tx.hash); expect(replay.from).toBe(tx.from); diff --git a/packages/core/__e2e__/agw/svm-public.spec.ts b/packages/core/__e2e__/agw/svm-public.spec.ts index 79ff9089..a135ea64 100644 --- a/packages/core/__e2e__/agw/svm-public.spec.ts +++ b/packages/core/__e2e__/agw/svm-public.spec.ts @@ -1,6 +1,7 @@ -/** Public named-IDL lifecycle and destination delivery on Donut/Solana devnet. */ +import { actionId, configId } from '../../src/lib/agentic/codec/ids'; +/** Public numeric-pin lifecycle and destination delivery on Donut/Solana devnet. */ import '@e2e/shared/setup'; -import { PushChain, type SolanaRule } from '../../src'; +import { PushChain, type Rule } from '../../src'; import type { Idl } from '@coral-xyz/anchor'; import { PublicKey, Keypair } from '@solana/web3.js'; import bs58 from 'bs58'; @@ -43,35 +44,23 @@ d('agw public svm', () => { cea: PublicKey, idl: Idl; const sol = svmWireConnection(); - const rule = (): SolanaRule => ({ + const rule = (): Rule => ({ agent: f.agentAddress, chainNamespace: SVM_WIRE_CHAIN, validUntil: inSeconds(3600), assets: [{ token: zeroAddress, maxPerCall: amount, maxTotal: amount }], maxGasPerCall: parseEther('20'), - allowedInstructions: [ + allowedCalls: [ { - program: SVM_WIRE_PROGRAM, - instruction: { idl, name: 'receive_sol' }, - accounts: [ - { - name: 'counter', - expected: { kind: 'address', address: SVM_WIRE_COUNTER.toBase58() }, - }, - { - name: 'recipient', - expected: { kind: 'address', address: recipient.toBase58() }, - }, - { name: 'cea_authority', expected: { kind: 'walletCEA' } }, - { - name: 'system_program', - expected: { - kind: 'address', - address: PublicKey.default.toBase58(), - }, - }, + target: SVM_WIRE_PROGRAM, + selector: 'receive_sol(u64)', + pins: [ + { account: 0, expected: SVM_WIRE_COUNTER.toBase58() }, + { account: 1, expected: recipient.toBase58() }, + { account: 2, expected: PushChain.CONSTANTS.AGENTIC.WALLET }, + { account: 3, expected: PublicKey.default.toBase58() }, + { arg: 0, max: amount }, ], - fields: [{ name: 'amount', max: amount }], }, ], }); @@ -185,7 +174,7 @@ d('agw public svm', () => { }); }, 900_000); afterAll(() => f?.teardown()); - it('1. named IDL grant reads exact constraints and replaces atomically', async () => { + it('1. numeric-pin grant reads exact raw constraints and replaces atomically', async () => { const handle = f.owner.agentic.wallet(wallet), record = await handle.rules.get(id); expect(record).not.toHaveProperty('ref'); @@ -195,7 +184,12 @@ d('agw public svm', () => { }); const count = (await handle.checkpoints()).checkpoints.length; const updated = await handle.rules.update({ - rules: [{ rulesId: id, rule: rule() }], + rules: [ + { + rulesId: id, + rule: { ...record.rule, validUntil: record.validUntil + 60 }, + }, + ], }); const previous = id; id = updated.rules[0].rulesId; @@ -254,13 +248,10 @@ d('agw public svm', () => { }); }, 900_000); it('3. contract simulation maps account and data refusals without state changes', async () => { - const config = PushChain.utils.agentic.configId( + const config = configId( wallet, id, - PushChain.utils.agentic.actionId( - f.manifest.addresses.gateway, - '0x77b86bec' - ) + actionId(f.manifest.addresses.gateway, '0x77b86bec') ); const state = async () => { const [tokens, pcBalance, checkpoints, cfg] = await Promise.all([ @@ -332,7 +323,7 @@ d('agw public svm', () => { }); it('4. public revoke removes the Solana rule and subsequent sends are refused', async () => { const handle = f.owner.agentic.wallet(wallet); - await (await handle.rules.revoke([id])).wait(); + await (await handle.rules.delete([id])).wait(); expect((await handle.rules.list()).rules).toHaveLength(0); await expect( agent.universal.sendTransaction({ diff --git a/packages/core/__e2e__/agw/universal-evm.spec.ts b/packages/core/__e2e__/agw/universal-evm.spec.ts index a617a178..f69d6c18 100644 --- a/packages/core/__e2e__/agw/universal-evm.spec.ts +++ b/packages/core/__e2e__/agw/universal-evm.spec.ts @@ -143,7 +143,7 @@ d('agw universal evm', () => { const tx = await agent.universal.sendTransaction({ to: { address: counter, chain: SEPOLIA }, data: [{ to: counter, value: BigInt(0), data: INCREMENT }], - gasLimit: DESTINATION_GAS, + // Omit gasLimit: the SDK must budget for this fresh CEA. funds: { amount: AMOUNT, token: MOVEABLE_TOKEN_CONSTANTS.ETHEREUM_SEPOLIA.ETH, diff --git a/packages/core/__e2e__/agw/v5-multiasset.spec.ts b/packages/core/__e2e__/agw/v5-multiasset.spec.ts index 8c3a3cb4..25bb4828 100644 --- a/packages/core/__e2e__/agw/v5-multiasset.spec.ts +++ b/packages/core/__e2e__/agw/v5-multiasset.spec.ts @@ -1,5 +1,5 @@ /** Opt-in funded Donut acceptance. Nothing in this file runs in unit/local validation. */ -import type { UniversalRule } from '../../src'; +import type { Rule } from '../../src'; import { createPublicClient, encodeFunctionData, @@ -42,7 +42,7 @@ d('agw v5 multi-asset', () => { }); afterAll(() => f?.teardown()); it('1. public create reads and replaces an ordered two-token rule', async () => { - const rule: UniversalRule = { + const rule: Rule = { agent: f.agentAddress, chainNamespace: chain, validUntil: inSeconds(3600), @@ -69,12 +69,18 @@ d('agw v5 multi-asset', () => { assets: [ { maxPerCall: BigInt(1000), - maxTotal: BigInt(2) ** BigInt(256) - BigInt(1), + maxTotal: BigInt(0), }, { maxPerCall: BigInt(10), maxTotal: BigInt(100) }, ], }); - expect(before).not.toHaveProperty('spent'); + expect(before.spent).toMatchObject({ + kind: 'universal', + assets: [ + expect.objectContaining({ spent: BigInt(0) }), + expect.objectContaining({ spent: BigInt(0) }), + ], + }); const count = await f.push.readContract({ address: created.wallet, abi: v5.abis.wallet, diff --git a/packages/core/__e2e__/ci/suite.ts b/packages/core/__e2e__/ci/suite.ts index 3bc27a74..9e08598e 100644 --- a/packages/core/__e2e__/ci/suite.ts +++ b/packages/core/__e2e__/ci/suite.ts @@ -168,19 +168,32 @@ const F = { export const SCENARIOS: Scenario[] = [ { - id: 'agw-svm-replay-positive', group: 'agw-svm-replay', file: '__e2e__/agw-svm-wire/replay.spec.ts', - grep: 'agw svm recorded replay 1\\. positive replay', needs: {}, env: { AGW_SVM_WIRE_REPLAY_E2E: '1' }, + id: 'agw-svm-replay-positive', + group: 'agw-svm-replay', + file: '__e2e__/agw-svm-wire/replay.spec.ts', + grep: 'agw svm recorded replay 1\\. positive replay', + needs: {}, + env: { AGW_SVM_WIRE_REPLAY_E2E: '1' }, }, { - id: 'agw-svm-replay-rejected', group: 'agw-svm-replay', file: '__e2e__/agw-svm-wire/replay.spec.ts', - grep: 'agw svm recorded replay 2\\. later terminal rejection', needs: {}, env: { AGW_SVM_WIRE_REPLAY_E2E: '1' }, + id: 'agw-svm-replay-rejected', + group: 'agw-svm-replay', + file: '__e2e__/agw-svm-wire/replay.spec.ts', + grep: 'agw svm recorded replay 2\\. later terminal rejection', + needs: {}, + env: { AGW_SVM_WIRE_REPLAY_E2E: '1' }, }, { - id: 'agw-svm-replay-policy', group: 'agw-svm-replay', file: '__e2e__/agw-svm-wire/replay.spec.ts', - grep: 'agw svm recorded replay 3\\. pinned live policy', needs: {}, env: { AGW_SVM_WIRE_REPLAY_E2E: '1' }, + id: 'agw-svm-replay-policy', + group: 'agw-svm-replay', + file: '__e2e__/agw-svm-wire/replay.spec.ts', + grep: 'agw svm recorded replay 3\\. pinned live policy', + needs: {}, + env: { AGW_SVM_WIRE_REPLAY_E2E: '1' }, }, { - id: 'agw-svm-wire-positive', group: 'agw-svm-wire', + id: 'agw-svm-wire-positive', + group: 'agw-svm-wire', file: '__e2e__/agw-svm-wire/outbound.spec.ts', grep: 'agw svm wire 1\\. positive outbound', needs: { masterPC: '45', masterPSOL: '0.00002' }, @@ -188,14 +201,16 @@ export const SCENARIOS: Scenario[] = [ note: 'Internal prepared-wire backend; public SVM capability remains gated.', }, { - id: 'agw-svm-wire-refusals', group: 'agw-svm-wire', + id: 'agw-svm-wire-refusals', + group: 'agw-svm-wire', file: '__e2e__/agw-svm-wire/outbound.spec.ts', grep: 'agw svm wire 2\\. substituted account', needs: { masterPC: '45', masterPSOL: '0.00002' }, env: { AGW_SVM_WIRE_E2E: '1' }, }, { - id: 'agw-svm-wire-failure', group: 'agw-svm-wire', + id: 'agw-svm-wire-failure', + group: 'agw-svm-wire', file: '__e2e__/agw-svm-wire/outbound.spec.ts', grep: 'agw svm wire 3\\. destination program failure', needs: { masterPC: '45', masterPSOL: '0.00002' }, @@ -1043,35 +1058,62 @@ export const SCENARIOS: Scenario[] = [ }, ...Array.from({ length: 6 }, (_, i) => ({ - id: `agw-public-svm-${i + 1}`, group: 'agw' as const, - file: '__e2e__/agw/svm-public.spec.ts', grep: `agw public svm ${i + 1}\\.`, - needs: { masterPC: '45', masterPSOL: '0.000020001' }, env: { AGW_E2E: '1' }, + id: `agw-public-svm-${i + 1}`, + group: 'agw' as const, + file: '__e2e__/agw/svm-public.spec.ts', + grep: `agw public svm ${i + 1}\\.`, + needs: { masterPC: '45', masterPSOL: '0.000020001' }, + env: { AGW_E2E: '1' }, })), ...Array.from({ length: 8 }, (_, i) => ({ - id: `agw-labels-${i + 1}`, group: 'agw' as const, - file: '__e2e__/agw/labels.spec.ts', grep: `agw labels ${i + 1}\\.`, - needs: i === 4 ? { masterPC: '4', sepoliaEth: '0.003' } : i === 5 ? { masterPC: '4', solanaSOL: '0.003' } : { masterPC: '1' }, + id: `agw-labels-${i + 1}`, + group: 'agw' as const, + file: '__e2e__/agw/labels.spec.ts', + grep: `agw labels ${i + 1}\\.`, + needs: + i === 4 + ? { masterPC: '4', sepoliaEth: '0.003' } + : i === 5 + ? { masterPC: '4', solanaSOL: '0.003' } + : { masterPC: '1' }, env: { AGW_E2E: '1' }, })), { - id: 'agw-v5-independent-token-budgets', group: 'agw', - file: '__e2e__/agw/v5-multiasset.spec.ts', grep: 'agw v5 multi-asset 3\\.', - needs: { masterPC: '45', masterPETH: '0.000001000000000001', masterUsdcEth: '0.000011' }, + id: 'agw-v5-independent-token-budgets', + group: 'agw', + file: '__e2e__/agw/v5-multiasset.spec.ts', + grep: 'agw v5 multi-asset 3\\.', + needs: { + masterPC: '45', + masterPETH: '0.000001000000000001', + masterUsdcEth: '0.000011', + }, env: { AGW_E2E: '1' }, }, { - id: 'agw-owner-spl-transfer', group: 'agw', - file: '__e2e__/agw/svm-spl-transfer.spec.ts', grep: 'agw svm spl transfer 1\\.', + id: 'agw-owner-spl-transfer', + group: 'agw', + file: '__e2e__/agw/svm-spl-transfer.spec.ts', + grep: 'agw svm spl transfer 1\\.', needs: { masterPC: '23', masterUsdtSol: '0.001' }, env: { AGW_E2E: '1' }, }, + ...Array.from({ length: 10 }, (_, i) => ({ + id: `agw-native-multi-action-${i + 1}`, + group: 'agw' as const, + file: '__e2e__/agw/native-multi-action.spec.ts', + grep: `agw native multi-action ${i + 1}\\.`, + needs: { masterPC: '1', masterPETH: '0.00000000000000004' }, + env: { AGW_E2E: '1' }, + })), + // Extended AGW tests are opt-in and use bounded per-scenario testnet budgets. ...[ ['prefunding', '1\\. prefunding', '11'], - ['ambiguous-rules', '2\\. same-agent multiplicity', '11'], + ['duplicate-rules', '2\\. create and add reject duplicate', '11'], ['batched-lifecycle', '3\\. multi-rule add', '0.5'], ['invalid-revoke', '4\\. invalid revoke', '0.5'], ['stale-update', '5\\. intervening agent spend', '11'], diff --git a/packages/core/__e2e__/shared/agw-state.ts b/packages/core/__e2e__/shared/agw-state.ts index 2c633e03..09d83443 100644 --- a/packages/core/__e2e__/shared/agw-state.ts +++ b/packages/core/__e2e__/shared/agw-state.ts @@ -29,3 +29,34 @@ export async function readNativeCounters( callsUsed: Number(cfg.callsUsed), }; } + +/** All native action terms/counters in engine order, pinned to one block. */ +export async function readNativeActionConfigs( + client: PublicClient, + addresses: { sessionEngine: Address; rulesPolicy: Address }, + wallet: Address, + rulesId: Hex, + blockNumber?: bigint +) { + const block = blockNumber ?? (await client.getBlockNumber({ cacheTime: 0 })); + const actions = await client.readContract({ + address: addresses.sessionEngine, + abi: v5.abis.engine, + functionName: 'getEnabledActions', + args: [wallet, rulesId], + blockNumber: block, + }); + if (!actions.length) throw new Error('Native fixture has no enabled action'); + return Promise.all( + actions.map(async (action) => ({ + actionId: action, + config: await client.readContract({ + address: addresses.rulesPolicy, + abi: v5.abis.policy, + functionName: 'getNativeConfig', + args: [configId(wallet, rulesId, action), wallet], + blockNumber: block, + }), + })) + ); +} diff --git a/packages/core/scripts/check-agw-api.js b/packages/core/scripts/check-agw-api.js index 41cde023..4aa6c929 100644 --- a/packages/core/scripts/check-agw-api.js +++ b/packages/core/scripts/check-agw-api.js @@ -21,6 +21,10 @@ const selected = [ 'AgenticError', 'AgenticRevertError', 'AGENTIC_ERROR_CODE', + 'Rule', + 'RuleInput', + 'Pin', + 'Spent', 'NativeRule', 'ArgPin', 'AmountLimit', @@ -320,7 +324,11 @@ function snapshot(entry) { const aType = checker.getTypeOfSymbolAtLocation(agw, file); const donut = aType.getProperty('TESTNET_DONUT'); result.agwConstants = properties( - checker.getNonNullableType(checker.getTypeOfSymbolAtLocation(donut, file)) + donut + ? checker.getNonNullableType( + checker.getTypeOfSymbolAtLocation(donut, file) + ) + : aType ); result.constants = properties(cType); return result; diff --git a/packages/core/scripts/check-agw-package.js b/packages/core/scripts/check-agw-package.js index 83cc7805..85e87be4 100644 --- a/packages/core/scripts/check-agw-package.js +++ b/packages/core/scripts/check-agw-package.js @@ -13,10 +13,7 @@ async function main() { esm = await import(pathToFileURL(entry).href); assert.equal(typeof cjs.PushChain.initialize, 'function'); assert.equal(esm.PushChain, cjs.PushChain); - assert.equal( - cjs.PushChain.CONSTANTS.AGENTIC.TESTNET_DONUT.ENVELOPE_VERSION, - 1 - ); + assert.equal(cjs.PushChain.CONSTANTS.AGENTIC.WALLET, 'agentic:wallet'); assert.equal(typeof cjs.AgenticError, 'function'); const [pack] = JSON.parse( execFileSync('npm', ['pack', '--dry-run', '--json', '--ignore-scripts'], { diff --git a/packages/core/src/lib/agentic/__tests__/fake-chain.ts b/packages/core/src/lib/agentic/__tests__/fake-chain.ts index d56212bf..1b38300e 100644 --- a/packages/core/src/lib/agentic/__tests__/fake-chain.ts +++ b/packages/core/src/lib/agentic/__tests__/fake-chain.ts @@ -51,6 +51,8 @@ export interface FakeRule { chain: string; actionIds: Hex[]; native?: Partial; + /** Per-action native config overrides, keyed by lowercase action ID. */ + nativeByAction?: Record>; universal?: { assets: readonly { token: Address; @@ -230,14 +232,19 @@ export class FakeChain implements ChainReader { } case 'getNativeConfig': { const found = this.findConfig(a[0] as Hex, a[1] as Address); - const n = found?.rule.native ?? {}; + const n = { + ...(found?.rule.native ?? {}), + ...(found + ? found.rule.nativeByAction?.[found.action.toLowerCase()] ?? {} + : {}), + }; return { initialized: !!found, validUntil: 2_000_000_000, target: ADDR.target, selector: '0xd09de08a', maxValuePerCall: BigInt(0), - maxValueTotal: BigInt(0), + maxValueTotal: (BigInt(1) << BigInt(256)) - BigInt(1), valueSpent: BigInt(0), amount: { enabled: false, diff --git a/packages/core/src/lib/agentic/__tests__/labels.spec.ts b/packages/core/src/lib/agentic/__tests__/labels.spec.ts index 9688dc4b..84527c65 100644 --- a/packages/core/src/lib/agentic/__tests__/labels.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/labels.spec.ts @@ -37,7 +37,7 @@ describe('v5 wallet labels', () => { expect(chain.calls).toEqual([]); }); - it('encodes a reset through the owner door and forwards the per-call progress hook', async () => { + it('encodes a direct reset and forwards the per-call progress hook', async () => { const chain = new FakeChain(); const w = chain.addWallet(ADDR.owner, 'custom'); const rt = mockRuntime(chain, { signer: ADDR.owner }); @@ -47,14 +47,12 @@ describe('v5 wallet labels', () => { }); const sent = rt.executeMock.mock.calls[0][0]; expect(sent).toMatchObject({ to: w.address, value: BigInt(0) }); - const outer = v5.decodeWalletCall(sent.data); - expect(outer?.kind).toBe('execute'); - if (outer?.kind !== 'execute') throw new Error('expected owner execute'); - expect(outer.calls).toHaveLength(1); - expect(outer.calls[0].target).toBe(w.address); expect( - decodeFunctionData({ abi: v5.abis.wallet, data: outer.calls[0].data }) + decodeFunctionData({ abi: v5.abis.wallet, data: sent.data }) ).toMatchObject({ functionName: 'setLabel', args: [''] }); + expect(hook).toHaveBeenCalledWith( + expect.objectContaining({ id: PROGRESS_HOOK.AGENTIC_TX_106 }) + ); expect(hook).toHaveBeenCalledWith( expect.objectContaining({ id: PROGRESS_HOOK.AGENTIC_TX_199_01 }) ); @@ -76,7 +74,7 @@ describe('v5 wallet labels', () => { expect(readOnly.executeMock).not.toHaveBeenCalled(); }); - it('uses the same owner door for an external owner identity', async () => { + it('uses a direct label call for an external owner identity', async () => { const chain = new FakeChain(); const w = chain.addWallet(ADDR.owner, 'x'); const rt = mockRuntime(chain, { @@ -85,8 +83,11 @@ describe('v5 wallet labels', () => { }); await setLabel(rt, gen(), w.address, 'UEA label'); expect( - v5.decodeWalletCall(rt.executeMock.mock.calls[0][0].data)?.kind - ).toBe('execute'); + decodeFunctionData({ + abi: v5.abis.wallet, + data: rt.executeMock.mock.calls[0][0].data, + }).functionName + ).toBe('setLabel'); }); it('maps the new contract length error and emits a failed operation hook', async () => { diff --git a/packages/core/src/lib/agentic/__tests__/management.spec.ts b/packages/core/src/lib/agentic/__tests__/management.spec.ts index d9726b6a..f7d305e1 100644 --- a/packages/core/src/lib/agentic/__tests__/management.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/management.spec.ts @@ -165,7 +165,7 @@ describe('agentic.create', () => { await expect( createWallet(rt, 'version', { rules: [rule()] }) ).rejects.toMatchObject({ - code: AGENTIC_ERROR_CODE.GENERATION_UNSUPPORTED, + code: AGENTIC_ERROR_CODE.CAPABILITY_UNAVAILABLE, }); expect(rt.executeMock).not.toHaveBeenCalled(); }); @@ -391,7 +391,9 @@ describe('agentic.create', () => { throw failure; }) as never, }); - await expect(createWallet(rt, 'this-create', { rules: [rule()] })).rejects.toBe(failure); + await expect( + createWallet(rt, 'this-create', { rules: [rule()] }) + ).rejects.toBe(failure); }); it('a slot that is already deployed is refused before signing', async () => { @@ -414,10 +416,10 @@ describe('agentic.create', () => { }); }); -describe('rules.add / rules.revoke', () => { +describe('rules.add / rules.delete', () => { const gen = () => currentGeneration(PUSH_NETWORK.TESTNET_DONUT); - it('add: owner-only, same-agent grants allowed, IDs from the grant nonce', async () => { + it('add: owner-only, duplicate agent/chain refused before signing', async () => { const fake = new FakeChain(); const w = fake.addWallet(ADDR.owner, 'w', [ fake.nativeRule(ADDR.agent, ruleId(1)), @@ -438,9 +440,10 @@ describe('rules.add / rules.revoke', () => { signer: ADDR.owner, execute: (async () => withLogs([granted(w.address, expected)])) as never, }); - expect( - (await addRules(rt, gen(), w.address, [rule(ADDR.agent)])).rulesIds - ).toEqual([expected]); + await expect( + addRules(rt, gen(), w.address, [rule(ADDR.agent)]) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.DUPLICATE_RULE }); + expect(rt.executeMock).not.toHaveBeenCalled(); }); it('add: several rules are one atomic owner execute batch (one signature on any signer)', async () => { @@ -499,7 +502,7 @@ describe('rules.add / rules.revoke', () => { await expect( revokeRules(rt, gen(), w.address, bad as never) ).rejects.toMatchObject({ - code: AGENTIC_ERROR_CODE.REVOKE_NEEDS_TARGET, + code: AGENTIC_ERROR_CODE.DELETE_NEEDS_TARGET, }); } await expect( diff --git a/packages/core/src/lib/agentic/__tests__/native-multi-action.spec.ts b/packages/core/src/lib/agentic/__tests__/native-multi-action.spec.ts new file mode 100644 index 00000000..b317a1a2 --- /dev/null +++ b/packages/core/src/lib/agentic/__tests__/native-multi-action.spec.ts @@ -0,0 +1,366 @@ +/** + * Multi-action native rules: one rule ID allowing 1..8 Push functions, each + * with its own limits (AGW _grantRules: MAX_NATIVE_ACTIONS, DuplicateAction, + * InconsistentChain). PENDING product sign-off — plan/agw/pending-items.md. + */ +import { getAddress, type Hex } from 'viem'; +import { PUSH_NETWORK } from '../../constants/enums'; +import { actionId } from '../codec/ids'; +import { + MAX_NATIVE_ACTIONS, + nativeActionTermsToRule, + nativeRuleToActionTerms, + nativeRuleToTerms, +} from '../codec/native'; +import { prepareRules } from '../codec/rules'; +import { decodeEnvelope, decodeSession } from '../codec/session'; +import { + currentGeneration, + resetAgenticGenerations, + V5_CAPABILITIES, +} from '../deployments'; +import { AGENTIC_ERROR_CODE } from '../errors'; +import { decodeActiveRule, readActiveRules } from '../reads/rules'; +import { Snapshot } from '../reads/snapshot'; +import { agenticUtils, internalAgenticUtils } from '../utils'; +import type { NativeMultiRule, NativeRule } from '../agentic.types'; +import { + ADDR, + FakeChain, + PUSH_NS, + registerFakeGeneration, + ruleId, +} from './fake-chain'; + +const NOW = 1_700_000_000; +const other = getAddress('0x0000000000000000000000000000000000007b7b'); + +const multi = (over: Partial = {}): NativeMultiRule => ({ + agent: ADDR.agent, + validUntil: NOW + 100, + actions: [ + { target: ADDR.target, selector: 'increment()', maxCalls: 5 }, + { + target: other, + selector: 'deposit(address,uint256)', + pins: [{ arg: 0, expected: ADDR.other }], + amount: { arg: 1, maxPerCall: BigInt(10) }, + maxValuePerCall: BigInt(3), + maxValueTotal: BigInt(9), + }, + ], + ...over, +}); + +const ctx = { + owner: ADDR.owner, + pushChainNamespace: PUSH_NS, + validator: ADDR.validator, + rulesPolicy: ADDR.policy, + gateway: ADDR.gateway, + capabilities: V5_CAPABILITIES, + nowSeconds: NOW, + forbiddenTargets: [ + ADDR.factory, + ADDR.engine, + ADDR.policy, + ADDR.validator, + ADDR.gateway, + ], +}; + +describe('native rule codec — multiple actions', () => { + it('encodes each action with its own limits, in input order, sharing the rule expiry', () => { + const out = nativeRuleToActionTerms(multi(), { nowSeconds: NOW }); + expect(out.map((o) => o.terms.target)).toEqual([ADDR.target, other]); + expect(out[0].terms).toMatchObject({ + maxCalls: 5, + validUntil: NOW + 100, + maxValuePerCall: BigInt(0), + }); + expect(out[1].terms).toMatchObject({ + maxValuePerCall: BigInt(3), + maxValueTotal: BigInt(9), + validUntil: NOW + 100, + }); + expect(out[1].terms.pins).toHaveLength(1); + expect(out[1].terms.amount).toMatchObject({ + enabled: true, + offset: 36, + maxPerCall: BigInt(10), + }); + }); + + it('the single-action shorthand is unchanged and equals a one-entry actions list', () => { + const single: NativeRule = { + agent: ADDR.agent, + target: ADDR.target, + selector: 'increment()', + validUntil: NOW + 100, + maxCalls: 2, + }; + const asList: NativeRule = { + agent: ADDR.agent, + validUntil: NOW + 100, + actions: [{ target: ADDR.target, selector: 'increment()', maxCalls: 2 }], + }; + expect( + nativeRuleToActionTerms(asList, { nowSeconds: NOW })[0].terms + ).toEqual(nativeRuleToTerms(single, { nowSeconds: NOW }).terms); + }); + + it('round-trips: stored terms decode to the actions form and re-encode identically', () => { + const terms = nativeRuleToActionTerms(multi(), { nowSeconds: NOW }).map( + (o) => o.terms + ); + const decoded = nativeActionTermsToRule(terms, ADDR.agent); + expect(decoded.actions).toHaveLength(2); + expect(decoded.validUntil).toBe(NOW + 100); + expect(decoded.actions?.[0]).not.toHaveProperty('validUntil'); + expect( + nativeRuleToActionTerms(decoded, { nowSeconds: NOW }).map((o) => o.terms) + ).toEqual(terms); + }); + + it('a single stored action decodes to the shorthand form', () => { + const terms = nativeRuleToActionTerms( + multi({ actions: [multi().actions[0]] }), + { nowSeconds: NOW } + ).map((o) => o.terms); + const decoded = nativeActionTermsToRule(terms, ADDR.agent); + expect(decoded.actions).toBeUndefined(); + expect(decoded).toMatchObject({ target: ADDR.target, maxCalls: 5 }); + }); + + it('per-action expiries are kept: the rule shows the earliest, later actions carry their own', () => { + const rule = multi({ + actions: [ + { ...multi().actions[0], validUntil: NOW + 500 }, + multi().actions[1], + ], + }); + const terms = nativeRuleToActionTerms(rule, { nowSeconds: NOW }).map( + (o) => o.terms + ); + expect(terms.map((t) => t.validUntil)).toEqual([NOW + 500, NOW + 100]); + const decoded = nativeActionTermsToRule(terms, ADDR.agent); + expect(decoded.validUntil).toBe(NOW + 100); + expect(decoded.actions?.[0].validUntil).toBe(NOW + 500); + expect( + nativeRuleToActionTerms(decoded, { nowSeconds: NOW }).map((o) => o.terms) + ).toEqual(terms); + }); + + it.each([ + [ + 'a null action', + { actions: [null] } as never, + /actions\[0\] must be an action object/, + ], + [ + 'a non-object action', + { actions: [42] } as never, + /actions\[0\] must be an action object/, + ], + [ + 'missing rule expiry despite overrides', + { + validUntil: undefined, + actions: [{ ...multi().actions[0], validUntil: NOW + 100 }], + } as never, + /rule validUntil/, + ], + [ + 'expired rule expiry despite overrides', + { + validUntil: NOW - 1, + actions: [{ ...multi().actions[0], validUntil: NOW + 100 }], + }, + /rule validUntil/, + ], + ['an empty actions list', { actions: [] }, /1\.\.8/], + [ + 'more than the contract limit', + { + actions: Array.from({ length: MAX_NATIVE_ACTIONS + 1 }, (_, i) => ({ + target: getAddress(`0x${(i + 16).toString(16).padStart(40, '0')}`), + selector: 'increment()' as const, + })), + }, + /1\.\.8/, + ], + [ + 'a repeated target and selector', + { + actions: [ + { target: ADDR.target, selector: 'increment()' as const }, + { target: ADDR.target, selector: '0xd09de08a' as const }, + ], + }, + /repeats the target and selector of actions\[0\]/, + ], + [ + 'top-level action fields mixed with actions', + { target: ADDR.target } as never, + /cannot be combined with top-level target/, + ], + [ + 'an invalid action, reported with its index', + { + actions: [ + multi().actions[0], + { + target: other, + selector: 'f(bytes)' as const, + pins: [{ arg: 0, expected: '0x01' as Hex }], + }, + ], + }, + /^actions\[1\]: /, + ], + ])('rejects %s before signing', (_name, patch, message) => { + expect(() => + nativeRuleToActionTerms(multi(patch as Partial), { + nowSeconds: NOW, + }) + ).toThrow( + expect.objectContaining({ + code: AGENTIC_ERROR_CODE.INVALID_RULE, + message: expect.stringMatching(message), + }) + ); + }); + + it('the same function on different targets is allowed (distinct action IDs)', () => { + expect(() => + nativeRuleToActionTerms( + multi({ + actions: [ + { target: ADDR.target, selector: 'increment()' }, + { target: other, selector: 'increment()' }, + ], + }), + { nowSeconds: NOW } + ) + ).not.toThrow(); + }); +}); + +describe('prepareRules — one session, one rule ID, several actions', () => { + it('builds one session action per native action, each with its own URP envelope on the Push chain', () => { + const [p] = prepareRules([multi()], ctx); + expect(p.session.actions.map((a) => a.actionTarget)).toEqual([ + ADDR.target, + other, + ]); + expect( + p.session.actions.every( + (a) => + a.actionPolicies.length === 1 && + a.actionPolicies[0].policy === ADDR.policy + ) + ).toBe(true); + expect( + p.session.actions.map( + (a) => decodeEnvelope(a.actionPolicies[0].initData).chainNamespace + ) + ).toEqual([PUSH_NS, PUSH_NS]); + expect(p.nativeTerms).toHaveLength(2); + }); + + it('refuses an infrastructure target in any action, naming it', () => { + expect(() => + prepareRules( + [ + multi({ + actions: [ + multi().actions[0], + { target: ADDR.gateway, selector: 'increment()' }, + ], + }), + ], + ctx + ) + ).toThrow(/rules\[0\]\.actions\[1\]\.target/); + }); + + it('one multi-action rule is one rule per agent on Push, so it never collides with itself', () => { + expect(prepareRules([multi()], ctx)).toHaveLength(1); + }); +}); + +describe('utils.agentic.decodeRules — several actions', () => { + it('decodes a multi-action session into the actions form', () => { + const [bytes] = internalAgenticUtils.encodeRules([multi()], { + pushChainNamespace: PUSH_NS, + validator: ADDR.validator, + rulesPolicy: ADDR.policy, + nowSeconds: NOW, + }); + expect(decodeSession(bytes).actions).toHaveLength(2); + const back = agenticUtils.decodeRules(bytes, { + pushChainNamespace: PUSH_NS, + }) as NativeMultiRule; + expect(back.actions.map((a) => a.target)).toEqual([ADDR.target, other]); + expect(back.actions[1]).toMatchObject({ + maxValuePerCall: BigInt(3), + amount: { offset: 36, maxPerCall: BigInt(10) }, + }); + }); +}); + +describe('rules.get / rules.list — reading several stored actions', () => { + afterEach(() => resetAgenticGenerations()); + + it('decodes every action in engine order at one block', async () => { + registerFakeGeneration(); + const fake = new FakeChain(); + const a0 = actionId(ADDR.target, '0xd09de08a'); + const a1 = actionId(other, '0x47e7ef24'); + const w = fake.addWallet(ADDR.owner, 'w', [ + { + ...fake.nativeRule(ADDR.agent, ruleId(1)), + actionIds: [a0, a1], + nativeByAction: { + [a0.toLowerCase()]: { + target: ADDR.target, + selector: '0xd09de08a', + maxCalls: 0, + callsUsed: 5, + }, + [a1.toLowerCase()]: { + target: other, + selector: '0x47e7ef24', + maxValuePerCall: BigInt(3), + }, + }, + }, + ]); + const gen = currentGeneration(PUSH_NETWORK.TESTNET_DONUT); + const snap = await Snapshot.at(fake); + const [active] = await readActiveRules(snap, gen, w.address); + const record = await decodeActiveRule( + snap, + gen, + w.address, + active, + PUSH_NS + ); + const rule = record.rule as import('../agentic.types').Rule; + expect(rule.allowedCalls.map((a) => [a.target, a.selector])).toEqual([ + [ADDR.target, '0xd09de08a'], + [other, '0x47e7ef24'], + ]); + expect(record.spent).toMatchObject({ + kind: 'native', + actions: [ + expect.objectContaining({ callsUsed: 5 }), + expect.objectContaining({ callsUsed: 0 }), + ], + }); + expect(rule.allowedCalls[1].maxValue).toBe(BigInt(3)); + expect(new Set(fake.calls.map((c) => c.blockNumber))).toEqual( + new Set([fake.block]) + ); + }); +}); diff --git a/packages/core/src/lib/agentic/__tests__/presets.spec.ts b/packages/core/src/lib/agentic/__tests__/presets.spec.ts new file mode 100644 index 00000000..0b24bd42 --- /dev/null +++ b/packages/core/src/lib/agentic/__tests__/presets.spec.ts @@ -0,0 +1,251 @@ +import { getAddress, zeroAddress } from 'viem'; +import { AGENTIC } from '../constants'; +import { agenticPresets, buildPresetApi } from '../presets'; +import type { PresetDefinition } from '../presets/catalog'; +import type { Rule } from '../agentic.types'; +import { normalizePublicRule, publicRules } from '../public-rule'; +import { FakeChain, ADDR } from './fake-chain'; +import { mockRuntime } from './mock-runtime'; +const chain = 'eip155:11155111' as const, + other = 'eip155:84532' as const; +const target = getAddress('0x0000000000000000000000000000000000001234'); +const token = getAddress('0x000000000000000000000000000000000000abcd'); +const agent = getAddress('0x000000000000000000000000000000000000a999'); +const until = () => Math.floor(Date.now() / 1000) + 3600; +function catalog(): PresetDefinition[] { + return [ + { + constant: 'DEXES', + name: 'Test-only DEX', + chains: [ + { + chainNamespace: chain, + allowedCalls: [ + { + target, + selector: 'deposit(address,uint256)', + pins: [{ arg: 0, expected: AGENTIC.WALLET }], + app: 'Fixture', + label: 'Deposit', + }, + ], + approvals: [{ spender: target, app: 'Fixture' }], + }, + { + chainNamespace: other, + allowedCalls: [ + { + target, + selector: 'withdraw(address)', + pins: [{ arg: 0, expected: AGENTIC.WALLET }], + }, + ], + }, + ], + }, + ]; +} +it('exposes enumerable frozen categories with no invented production addresses', () => { + expect(Object.values(AGENTIC.PRESETS.CATEGORY)).toEqual([ + 'DEXES', + 'LENDING', + 'PREDICTION', + ]); + expect(Object.isFrozen(AGENTIC.PRESETS.CATEGORY)).toBe(true); + expect( + agenticPresets.list().presets.map((p) => [p.constant, p.chains]) + ).toEqual([ + ['DEXES', []], + ['LENDING', []], + ['PREDICTION', []], + ]); + expect(agenticPresets.get('DEXES')).toEqual({ rules: [] }); + expect(() => agenticPresets.get('DEXES', { chainNamespace: chain })).toThrow( + /no approved entry/ + ); + expect(() => + agenticPresets.get('DEXES', { assets: [{ chainNamespace: chain, token }] }) + ).toThrow(/no approved app entries/); +}); +it('groups all apps on a chain into one editable template and omits unspecified fields', () => { + const data = catalog(); + data[0].chains[0].allowedCalls = [ + ...data[0].chains[0].allowedCalls, + { + target: ADDR.other, + selector: 'lend(address)', + pins: [{ arg: 0, expected: AGENTIC.WALLET }], + }, + ]; + const api = buildPresetApi(data), + res = api.get('DEXES'); + expect(res.rules.map((r) => r.chainNamespace)).toEqual([chain, other]); + expect(res.rules[0].allowedCalls).toHaveLength(2); + for (const rule of res.rules) { + expect(rule).not.toHaveProperty('agent'); + expect(rule).not.toHaveProperty('assets'); + expect(rule).not.toHaveProperty('validUntil'); + } + expect(api.list({ type: 'CATEGORY' }).presets[0].chains).toEqual([ + chain, + other, + ]); +}); +it('returns ready Rule types with identity and expiry; routes assets and defaults missing caps to zero', () => { + const api = buildPresetApi(catalog()); + const { rules } = api.get('DEXES', { + agent, + validUntil: until(), + assets: [ + { chainNamespace: chain, token }, + { + chainNamespace: other, + token: zeroAddress, + maxPerCall: BigInt(2), + maxTotal: BigInt(3), + }, + ], + }); + const typed: Rule[] = rules; + expect(typed[0].assets).toEqual([ + { token, maxPerCall: BigInt(0), maxTotal: BigInt(0) }, + ]); + expect(typed[1].assets).toEqual([ + { token: zeroAddress, maxPerCall: BigInt(2), maxTotal: BigInt(3) }, + ]); + expect(typed.every((r) => r.agent === agent && r.validUntil > 0)).toBe(true); +}); +it('does not type an incomplete template as a ready rule', () => { + const { rules } = buildPresetApi(catalog()).get('DEXES'); + // @ts-expect-error callers must fill agent and expiry before create + const ready: Rule[] = rules; + expect(ready[0].agent).toBeUndefined(); +}); +it('adds only spender-pinned and amount-bounded ERC20 approvals; native assets have none', () => { + const { rules } = buildPresetApi(catalog()).get('DEXES', { + chainNamespace: chain, + assets: [ + { token, maxPerCall: BigInt(5), maxTotal: BigInt(10) }, + { token: zeroAddress, maxPerCall: BigInt(1) }, + ], + }); + expect(rules).toHaveLength(1); + expect(rules[0].allowedCalls).toHaveLength(2); + expect(rules[0].allowedCalls[1]).toMatchObject({ + target: token, + selector: 'approve(address,uint256)', + pins: [ + { arg: 0, expected: target }, + { arg: 1, max: BigInt(5) }, + ], + }); + expect(rules[0].assets![0]).not.toHaveProperty('chainNamespace'); +}); +it('does not mutate caller assets, returned records, or the bundled catalog', () => { + const data = catalog(); + const api = buildPresetApi(data); + const asset = { + token: { + address: token, + symbol: 'TEST', + decimals: 6, + mechanism: 'approve' as const, + }, + }; + const first = api.get('DEXES', { chainNamespace: chain, assets: [asset] }); + first.rules[0].allowedCalls[0].pins![0] = { arg: 0, expected: zeroAddress }; + (first.rules[0].assets![0].token as { address: string }).address = + zeroAddress; + api.list().presets[0].chains.length = 0; + data[0].chains[0].allowedCalls[0].target = zeroAddress; + expect(asset.token.address).toBe(token); + expect(api.get('DEXES').rules[0].allowedCalls[0]).toMatchObject({ + target, + pins: [{ arg: 0, expected: AGENTIC.WALLET }], + }); + expect(api.list().presets[0].chains).toHaveLength(2); +}); +it.each([ + { assets: [{ token }] }, + { chainNamespace: chain, assets: [{ chainNamespace: other, token }] }, + { + chainNamespace: chain, + assets: [{ token }, { token: token.toUpperCase().replace('0X', '0x') }], + }, + { chainNamespace: chain, assets: [{ token, maxPerCall: BigInt(-1) }] }, + { + chainNamespace: chain, + assets: [{ token, maxTotal: BigInt(1) << BigInt(256) }], + }, + { agent: zeroAddress }, + { validUntil: 1 }, + { validUntil: 1.5 }, + { assets: [null] }, +])( + 'rejects malformed or mismatched options before returning templates (case %#)', + (options) => { + expect(() => + buildPresetApi(catalog()).get('DEXES', options as never) + ).toThrow(); + } +); +it('rejects unknown presets, unsupported list types and unsupported chain filters', () => { + const api = buildPresetApi(catalog()); + expect(() => api.get('UNKNOWN' as never)).toThrow(/unknown preset/); + expect(() => api.list({ type: 'APP' } as never)).toThrow(/only CATEGORY/); + expect(() => api.get('DEXES', { chainNamespace: 'eip155:1' })).toThrow( + /no approved entry/ + ); +}); +it('refuses conflicting spenders rather than emitting unrestricted or ambiguous approvals', () => { + const data = catalog(); + data[0].chains[0].approvals = [ + { spender: target, app: 'One' }, + { spender: ADDR.other, app: 'Two' }, + ]; + expect(() => + buildPresetApi(data).get('DEXES', { + chainNamespace: chain, + assets: [{ token }], + }) + ).toThrow(/multiple spenders/); +}); +it('enforces the 32-call ceiling including generated approvals', () => { + const data = catalog(); + data[0].chains[0].allowedCalls = Array.from({ length: 32 }, (_, i) => ({ + target, + selector: `fn${i}()`, + })); + const api = buildPresetApi(data); + expect( + api.get('DEXES', { chainNamespace: chain }).rules[0].allowedCalls + ).toHaveLength(32); + expect(() => + api.get('DEXES', { chainNamespace: chain, assets: [{ token }] }) + ).toThrow(/1..32/); +}); +it('requires full signatures and rejects duplicate function entries', () => { + const data = catalog(); + data[0].chains[0].allowedCalls = [{ target, selector: 'deposit' as never }]; + expect(() => buildPresetApi(data).get('DEXES')).toThrow(/full signatures/); + data[0].chains[0].allowedCalls = [ + { target, selector: 'deposit()' }, + { target, selector: 'deposit()' }, + ]; + expect(() => buildPresetApi(data).get('DEXES')).toThrow(/duplicate target/); +}); +it('cannot bypass current deployment limitations through a preset approval', async () => { + const { rules } = buildPresetApi(catalog()).get('DEXES', { + chainNamespace: chain, + agent, + validUntil: until(), + assets: [{ token, maxPerCall: BigInt(5) }], + }); + await expect( + normalizePublicRule( + publicRules(rules)[0], + ADDR.other, + mockRuntime(new FakeChain()) + ) + ).rejects.toMatchObject({ code: 'CAPABILITY_UNAVAILABLE' }); +}); diff --git a/packages/core/src/lib/agentic/__tests__/public-rule.spec.ts b/packages/core/src/lib/agentic/__tests__/public-rule.spec.ts new file mode 100644 index 00000000..10c4b587 --- /dev/null +++ b/packages/core/src/lib/agentic/__tests__/public-rule.spec.ts @@ -0,0 +1,207 @@ +import { getAddress } from 'viem'; +import { PublicKey } from '@solana/web3.js'; +import { normalizePublicRule, publicRules, WALLET } from '../public-rule'; +import { prepareWalletRules } from '../management/prepare'; +import { currentGeneration, resetAgenticGenerations } from '../deployments'; +import { PUSH_NETWORK } from '../../constants/enums'; +import { Snapshot } from '../reads/snapshot'; +import { UINT256_MAX } from '../codec/defaults'; +import type { + Rule, + NativeMultiRule, + UniversalRule, + SolanaRule, +} from '../agentic.types'; +import { ADDR, FakeChain, registerFakeGeneration } from './fake-chain'; +import { mockRuntime } from './mock-runtime'; +import { compileSvmIdlRule } from '../codec/svm-idl'; +const now = 1_700_000_000; +const wallet = getAddress('0x000000000000000000000000000000000000aaaa'); +const base = (): Rule => ({ + agent: ADDR.agent, + validUntil: now + 100, + allowedCalls: [ + { + target: ADDR.target, + selector: 'transfer(address,uint256)', + pins: [ + { arg: 0, expected: WALLET }, + { arg: 1, max: BigInt(5) }, + ], + }, + ], +}); +const fake = () => new FakeChain(); +async function normalize(rule: Rule) { + return normalizePublicRule( + publicRules([rule])[0], + wallet, + mockRuntime(fake()) + ); +} +beforeEach(registerFakeGeneration); +afterEach(resetAgenticGenerations); +it('normalizes unified native calls into exact EQ/MAX words with zero PC default', async () => { + const out = (await normalize(base())) as NativeMultiRule; + expect(out.actions).toEqual([ + expect.objectContaining({ + maxValuePerCall: BigInt(0), + maxValueTotal: UINT256_MAX, + maxCalls: 0, + pins: [{ offset: 4, expected: `0x${wallet.slice(2).padStart(64, '0')}` }], + amount: { offset: 36, maxPerCall: BigInt(5), maxTotal: UINT256_MAX }, + }), + ]); + const rt = mockRuntime(fake()); + const [p] = await prepareWalletRules( + rt, + currentGeneration(PUSH_NETWORK.TESTNET_DONUT), + ADDR.owner, + wallet, + publicRules([base()]), + await Snapshot.at(rt.reader) + ); + expect(p.nativeTerms?.[0].amount.maxPerCall).toBe(BigInt(5)); +}); +it.each(['actions', 'target', 'amount', 'maxCalls', 'maxValueTotal', 'ref'])( + 'rejects retired top-level %s before signing', + async (field) => { + await expect(normalize({ ...base(), [field]: null })).rejects.toMatchObject( + { code: 'INVALID_RULE' } + ); + } +); +it('rejects two native MAX pins on the deployed policy', async () => { + const r = base(); + r.allowedCalls[0].pins = [ + { arg: 0, max: BigInt(1) }, + { arg: 1, max: BigInt(2) }, + ]; + await expect(normalize(r)).rejects.toMatchObject({ + code: 'CAPABILITY_UNAVAILABLE', + }); +}); +it('compiles the existing EVM WALLET beneficiary and defaults asset total to zero', async () => { + const r = base(); + r.chainNamespace = 'eip155:11155111'; + r.assets = [{ token: ADDR.other, maxPerCall: BigInt(1) }]; + r.allowedCalls[0].pins = [{ arg: 0, expected: WALLET }]; + const out = (await normalize(r)) as UniversalRule; + expect(out.allowedCalls[0]).toMatchObject({ + beneficiaryOffset: 4, + maxValue: BigInt(0), + }); + expect(out.assets[0].maxTotal).toBe(BigInt(0)); +}); +it('rejects unavailable destination MAX pins before contract deployment', async () => { + await expect( + normalize({ ...base(), chainNamespace: 'eip155:11155111' }) + ).rejects.toMatchObject({ code: 'CAPABILITY_UNAVAILABLE' }); +}); +it('refuses layouts whose top-level argument indexes cannot be reconstructed', async () => { + const r = base(); + r.allowedCalls[0] = { + target: ADDR.target, + selector: 'f(uint256[2],uint256)', + pins: [{ arg: 1, max: BigInt(1) }], + }; + await expect(normalize(r)).rejects.toMatchObject({ + code: 'CAPABILITY_UNAVAILABLE', + }); +}); +it('compiles numeric Solana arg/account pins without a caller IDL', async () => { + const program = new PublicKey(Buffer.alloc(32, 3)).toBase58(); + const gateway = new PublicKey(Buffer.alloc(32, 4)).toBase58(); + const rt = mockRuntime(fake(), { + svmMetadata: { + gateway: async (chain) => ({ chainNamespace: chain, program: gateway }), + mint: async () => { + throw Error('unused'); + }, + }, + }); + const rule: Rule = { + agent: ADDR.agent, + chainNamespace: 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1', + validUntil: now + 100, + allowedCalls: [ + { + target: program, + selector: 'receive_sol(u64)', + pins: [ + { account: 0, expected: WALLET }, + { arg: 0, max: BigInt(5) }, + ], + }, + ], + }; + const out = (await normalizePublicRule( + publicRules([rule])[0], + wallet, + rt + )) as SolanaRule; + const cea = `0x${'01'.repeat(32)}` as const; + const terms = compileSvmIdlRule( + out, + { + expectedCEA: cea, + gatewayProgram: `0x${'04'.repeat(32)}`, + assets: [ + { token: ADDR.other, maxPerCall: BigInt(1), maxTotal: BigInt(1) }, + ], + ceaAccounts: [cea], + tokenAccounts: new Map(), + }, + now + ); + expect(terms.programs[0].maxAccounts).toBe(0); + expect(terms.pins).toEqual([ + { ruleIndex: 0, accountIndex: 0, expected: cea }, + ]); + expect(terms.dataPins[0]).toMatchObject({ offset: 8, len: 8, mode: 2 }); +}); + +it('public create rejects missing options asynchronously, and update rejects malformed pairs before reads', async () => { + const { AgenticNamespaceImpl } = await import('../agentic'); + const { AgenticWalletHandle } = await import('../wallet'); + const rt = mockRuntime(fake(), { signer: ADDR.owner }); + const ns = new AgenticNamespaceImpl(rt); + await expect(ns.create('invalid', undefined as never)).rejects.toMatchObject({ + code: 'INVALID_RULE', + }); + const handle = new AgenticWalletHandle(rt, wallet); + for (const params of [ + undefined, + {}, + { rules: [] }, + { rules: [null] }, + { rules: [{ rulesId: '0x', rule: base() }] }, + ]) { + await expect(handle.rules.update(params as never)).rejects.toMatchObject({ + code: 'INVALID_RULE', + }); + } + expect(rt.fake.calls).toEqual([]); + expect(rt.executeMock).not.toHaveBeenCalled(); +}); + +it('does not silently discard a token qualifier on an argument pin', async () => { + const r = base(); + r.allowedCalls[0].pins = [ + { arg: 0, expected: WALLET, token: ADDR.other } as never, + ]; + await expect(normalize(r)).rejects.toMatchObject({ code: 'INVALID_RULE' }); +}); + +it('reads native wallet equality as WALLET and re-encodes its exact word', async () => { + const { getRule } = await import('../reads/rules'); + const { ruleId } = await import('./fake-chain'); + const chain=fake();const w=chain.addWallet(ADDR.owner,'wallet-pin'); + const word=`0x${w.address.slice(2).toLowerCase().padStart(64,'0')}` as const; + w.rules.push(chain.nativeRule(ADDR.agent,ruleId(1),{pins:[{offset:4,expected:word}]})); + const rt=mockRuntime(chain); + const rec=await getRule(await Snapshot.at(chain),currentGeneration(PUSH_NETWORK.TESTNET_DONUT),w.address,ruleId(1),rt.pushChainNamespace); + expect(rec.rule).toMatchObject({allowedCalls:[{pins:[{arg:0,expected:WALLET}]}]}); + const normalized=await normalizePublicRule(publicRules([rec.rule])[0],w.address,rt) as NativeMultiRule; + expect(normalized.actions[0].pins).toEqual([{offset:4,expected:word}]); +}); diff --git a/packages/core/src/lib/agentic/__tests__/reads-context.spec.ts b/packages/core/src/lib/agentic/__tests__/reads-context.spec.ts index 15dc1217..72cf7515 100644 --- a/packages/core/src/lib/agentic/__tests__/reads-context.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/reads-context.spec.ts @@ -35,7 +35,7 @@ describe('generation registry', () => { )) { expect(() => currentGeneration(n)).toThrow( expect.objectContaining({ - code: AGENTIC_ERROR_CODE.GENERATION_UNSUPPORTED, + code: AGENTIC_ERROR_CODE.CAPABILITY_UNAVAILABLE, }) ); } @@ -50,7 +50,7 @@ describe('generation registry', () => { ADDR.target ) ).rejects.toMatchObject({ - code: AGENTIC_ERROR_CODE.GENERATION_UNSUPPORTED, + code: AGENTIC_ERROR_CODE.CAPABILITY_UNAVAILABLE, }); }); }); @@ -164,7 +164,7 @@ describe('initialize with agenticWallet — door resolution', () => { w.address ) ).rejects.toMatchObject({ - code: AGENTIC_ERROR_CODE.GENERATION_UNSUPPORTED, + code: AGENTIC_ERROR_CODE.CAPABILITY_UNAVAILABLE, }); }); }); @@ -293,12 +293,12 @@ describe('rules.list / rules.get', () => { afterEach(() => resetAgenticGenerations()); const gen = () => currentGeneration(PUSH_NETWORK.TESTNET_DONUT); - it('decodes active native records without exposing internal spend', async () => { + it('decodes active native records with spend', async () => { const w = fake.addWallet(ADDR.owner, 'w', [ fake.nativeRule(ADDR.agent, ruleId(1), { callsUsed: 3, valueSpent: BigInt(5), - maxCalls: 9, + maxCalls: 0, }), ]); const rules = await listRules( @@ -313,12 +313,15 @@ describe('rules.list / rules.get', () => { enabled: true, chainNamespace: PUSH_NS, agent: ADDR.agent, - rule: expect.objectContaining({ maxCalls: 9, selector: '0xd09de08a' }), + rule: expect.objectContaining({ + allowedCalls: [expect.objectContaining({ selector: '0xd09de08a' })], + }), + spent: expect.objectContaining({ valueSpent: BigInt(5) }), }), ]); }); - it('public records contain no spent field', async () => { + it('public records contain native spend', async () => { const w = fake.addWallet(ADDR.owner, 'w', [ fake.nativeRule(ADDR.agent, ruleId(1)), ]); @@ -329,7 +332,12 @@ describe('rules.list / rules.get', () => { ruleId(1), PUSH_NS ); - expect(record).not.toHaveProperty('spent'); + expect(record.spent).toMatchObject({ + kind: 'native', + valueSpent: BigInt(0), + amountSpent: BigInt(0), + callsUsed: 0, + }); }); it('lists native and universal rules without truncating', async () => { @@ -466,11 +474,19 @@ describe('wallet reads', () => { const w = fake.addWallet(ADDR.owner, 'original'); w.label = 'renamed'; fake.extraLogs = []; - expect(await walletInfo(fake, gen(), w.address)).toMatchObject({ label: 'renamed' }); - expect((await listForOwner(fake, gen(), ADDR.owner))[0].label).toBe('renamed'); - expect(fake.calls.filter((c) => c.functionName === 'label')).toHaveLength(2); + expect(await walletInfo(fake, gen(), w.address)).toMatchObject({ + label: 'renamed', + }); + expect((await listForOwner(fake, gen(), ADDR.owner))[0].label).toBe( + 'renamed' + ); + expect(fake.calls.filter((c) => c.functionName === 'label')).toHaveLength( + 2 + ); w.label = ''; - expect(await walletInfo(fake, gen(), w.address)).toMatchObject({ label: 'AGW 1' }); + expect(await walletInfo(fake, gen(), w.address)).toMatchObject({ + label: 'AGW 1', + }); }); it('info of the signer’s next slot describes it as undeployed; other undeployed addresses are refused', async () => { @@ -536,6 +552,46 @@ describe('checkpoints', () => { ); }); + it('uses retained logs only when a complete sequence proves no checkpoint was pruned', async () => { + const w = fake.addWallet(ADDR.owner, 'fresh'); + w.checkpointCount = BigInt(2); + fake.checkpointLogs = [ + checkpointLog(w.address, 1, 1, BigInt(60)), + checkpointLog(w.address, 2, 2, BigInt(70)), + ]; + const original = fake.getLogs.bind(fake); + jest.spyOn(fake, 'getLogs').mockImplementation(async (args) => { + if (args.fromBlock < BigInt(50)) + throw new Error('height 10 is not available, lowest height is 50'); + return original(args); + }); + const result = await readCheckpoints(fake, gen(), w.address); + expect(result.checkpoints.map((c) => c.seq)).toEqual([1, 2]); + fake.checkpointLogs = [checkpointLog(w.address, 2, 2, BigInt(70))]; + await expect(readCheckpoints(fake, gen(), w.address)).rejects.toMatchObject( + { code: AGENTIC_ERROR_CODE.INCONSISTENT_READ } + ); + }); + + it('does not skip arbitrary RPC errors or a pruned explicit sinceBlock range', async () => { + const w = fake.addWallet(ADDR.owner, 'history'); + w.checkpointCount = BigInt(1); + const logs = jest + .spyOn(fake, 'getLogs') + .mockRejectedValue(new Error('temporary RPC failure')); + await expect(readCheckpoints(fake, gen(), w.address)).rejects.toMatchObject( + { code: AGENTIC_ERROR_CODE.RULE_READ_FAILED } + ); + expect(logs).toHaveBeenCalledTimes(1); + logs.mockRejectedValue( + new Error('height 10 is not available, lowest height is 50') + ); + await expect( + readCheckpoints(fake, gen(), w.address, BigInt(20)) + ).rejects.toMatchObject({ code: AGENTIC_ERROR_CODE.RULE_READ_FAILED }); + expect(logs).toHaveBeenCalledTimes(2); + }); + it('validateSequence checks contiguity and the count', () => { expect(validateSequence([1, 2, 3], BigInt(3), true)).toBeNull(); expect(validateSequence([1, 3], BigInt(3), true)).toMatch(/gap/); diff --git a/packages/core/src/lib/agentic/__tests__/response-surface.spec.ts b/packages/core/src/lib/agentic/__tests__/response-surface.spec.ts index 3b508a49..e4550ae4 100644 --- a/packages/core/src/lib/agentic/__tests__/response-surface.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/response-surface.spec.ts @@ -225,30 +225,14 @@ describe('public surface', () => { expect(new AgenticRevertError('x', { cause: 'c' }).cause).toBe('c'); }); - it('CONSTANTS.AGENTIC carries the checked Donut v5 proxies', () => { - expect(CONSTANTS.AGENTIC.TESTNET_DONUT).toMatchObject({ - FACTORY: '0x8137F96A50EBF41d904e3678c84c391a0D1BCcc5', - RULES_POLICY: '0x603E7f0aF6e1aAFf46DDfb28b1e99364f8BC59af', - ENVELOPE_VERSION: 1, - }); + it('exposes the wallet marker and preset API, keeping deployment wiring and codecs internal', () => { + expect(CONSTANTS.AGENTIC.WALLET).toBe('agentic:wallet'); + expect(Object.keys(CONSTANTS.AGENTIC).sort()).toEqual([ + 'PRESETS', + 'WALLET', + ]); expect(Object.isFrozen(CONSTANTS.AGENTIC)).toBe(true); - }); - - it('PushChain.utils.agentic is the pure helper set', () => { - expect(Object.keys(Utils.agentic).sort()).toEqual( - ['actionId', 'configId', 'decodeRules'].sort() - ); - // @ts-expect-error generation context helpers are not public - expect(Utils.agentic.rulesId).toBeUndefined(); - // @ts-expect-error the marketplace compiler is outside AGW - expect(Utils.agentic.compileCard).toBeUndefined(); - for (const name of [ - 'rulesId', - 'deriveWallet', - 'encodeRules', - 'compileCard', - ]) { - expect(Utils.agentic).not.toHaveProperty(name); - } + expect(Object.keys(Utils.agentic)).toEqual(['presets']); + expect(Object.keys(Utils.agentic.presets).sort()).toEqual(['get', 'list']); }); }); diff --git a/packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts b/packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts index fe301376..8127cfc8 100644 --- a/packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts @@ -9,7 +9,11 @@ import { validateUniversalRuleShape } from '../codec/universal'; import { V5_CAPABILITIES } from '../deployments'; import { AGENTIC_ERROR_CODE } from '../errors'; import { internalAgenticUtils } from '../utils'; -import type { NativeRule, UniversalRule } from '../agentic.types'; +import type { + NativeRule, + NativeSingleRule, + UniversalRule, +} from '../agentic.types'; import { ADDR, PUSH_NS, SEPOLIA_NS } from './fake-chain'; const NOW = 1_700_000_000; @@ -28,7 +32,7 @@ const ctx = { ADDR.gateway, ], }; -const native = (over: Partial = {}): NativeRule => ({ +const native = (over: Partial = {}): NativeSingleRule => ({ agent: ADDR.agent, target: ADDR.target, selector: 'increment()', @@ -70,7 +74,7 @@ describe('prepareRules — spec 1.b checks before any signature', () => { ); expect(prepared).toHaveLength(2); expect(prepared.map((p) => p.agent)).toEqual([ADDR.agent, ADDR.agent]); - expect(prepared.map((p) => p.nativeTerms?.target)).toEqual([ + expect(prepared.map((p) => p.nativeTerms?.[0].target)).toEqual([ ADDR.target, ADDR.other, ]); @@ -104,8 +108,11 @@ describe('prepareRules — spec 1.b checks before any signature', () => { }); it('removed ref inputs fail explicitly instead of being silently dropped', () => { - expect(() => prepareRules([{ ...native(), ref: `0x${'99'.repeat(32)}` } as never], ctx)) - .toThrow(expect.objectContaining({ code: AGENTIC_ERROR_CODE.INVALID_RULE })); + expect(() => + prepareRules([{ ...native(), ref: `0x${'99'.repeat(32)}` } as never], ctx) + ).toThrow( + expect.objectContaining({ code: AGENTIC_ERROR_CODE.INVALID_RULE }) + ); }); it('refuses infrastructure targets the contracts would reject', () => { diff --git a/packages/core/src/lib/agentic/__tests__/send.spec.ts b/packages/core/src/lib/agentic/__tests__/send.spec.ts index 5291fac1..a9b567cf 100644 --- a/packages/core/src/lib/agentic/__tests__/send.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/send.spec.ts @@ -350,6 +350,38 @@ describe('EVM outbound composition from the wallet', () => { : {}), }); + it.each([ + [false, undefined, BigInt(2_000_000)], + [true, undefined, BigInt(0)], + [false, BigInt(123456), BigInt(123456)], + [true, BigInt(123456), BigInt(123456)], + [false, BigInt(0), BigInt(0)], + ])( + 'destination gas: deployed=%s explicit=%s quotes %s', + async (isDeployed, gasLimit, expected) => { + const s = universalSetup(); + const quoteOutbound = jest.fn(async (_token: Address, _gas: bigint) => ({ + protocolFee: BigInt(100), + nativeValueForGas: BigInt(1000), + gasLimitUsed: BigInt(200_000), + })); + const rt = mockRuntime(s.fake, { + signer: ADDR.agent, + resolvePrc20: () => token, + resolveCEA: async () => ({ + cea: getAddress('0x000000000000000000000000000000000000cea1'), + isDeployed, + }), + quoteOutbound, + }); + await agenticSend(rt, s.ctx, { + ...send(BigInt(100)), + ...(gasLimit === undefined ? {} : { gasLimit }), + }); + expect(quoteOutbound.mock.calls[0][1]).toBe(expected); + } + ); + it('builds the policy-compatible request: empty recipient, wallet refund, nonzero gas cap, multicall payload, CEA of the wallet', async () => { const s = universalSetup(); const resolveCEA = jest.fn(async () => ({ diff --git a/packages/core/src/lib/agentic/agentic.ts b/packages/core/src/lib/agentic/agentic.ts index e15344c0..e0269924 100644 --- a/packages/core/src/lib/agentic/agentic.ts +++ b/packages/core/src/lib/agentic/agentic.ts @@ -1,3 +1,4 @@ +import { publicRules } from './public-rule'; import { AgenticCapability, requireCapability } from './capabilities'; import { currentGeneration } from './deployments'; import { createWallet } from './management/create'; @@ -23,23 +24,48 @@ import type { export class AgenticNamespaceImpl implements AgenticNamespace { constructor(private readonly runtime: AgenticRuntime) {} - async derive(opts?: { index?: number }): Promise<{ address: AgenticAddress; index: number; deployed: boolean }> { + async derive(opts?: { + index?: number; + }): Promise<{ address: AgenticAddress; index: number; deployed: boolean }> { const gen = currentGeneration(this.runtime.network); requireCapability(gen.capabilities, AgenticCapability.WALLET_READS); const owner = this.runtime.signerPushAccount(); - const r = await deriveForOwner(this.runtime.reader, gen, owner, opts?.index); - emitAgentic(this.runtime, undefined, PROGRESS_HOOK.AGENTIC_TX_101, r.address, r.index, r.deployed); - return { address: r.address as AgenticAddress, index: r.index, deployed: r.deployed }; + const r = await deriveForOwner( + this.runtime.reader, + gen, + owner, + opts?.index + ); + emitAgentic( + this.runtime, + undefined, + PROGRESS_HOOK.AGENTIC_TX_101, + r.address, + r.index, + r.deployed + ); + return { + address: r.address as AgenticAddress, + index: r.index, + deployed: r.deployed, + }; } - create(label: string, options: CreateOptions): Promise { - return createWallet(this.runtime, label, options); + async create(label: string, options: CreateOptions): Promise { + return createWallet(this.runtime, label, { + ...options, + rules: publicRules(options?.rules), + }); } async list(): Promise<{ wallets: WalletSummary[] }> { const gen = currentGeneration(this.runtime.network); requireCapability(gen.capabilities, AgenticCapability.WALLET_READS); - const wallets = await listForOwner(this.runtime.reader, gen, this.runtime.signerPushAccount()); + const wallets = await listForOwner( + this.runtime.reader, + gen, + this.runtime.signerPushAccount() + ); return { wallets }; } diff --git a/packages/core/src/lib/agentic/agentic.types.ts b/packages/core/src/lib/agentic/agentic.types.ts index a0d1b6b2..6dcc6e9a 100644 --- a/packages/core/src/lib/agentic/agentic.types.ts +++ b/packages/core/src/lib/agentic/agentic.types.ts @@ -1,8 +1,5 @@ -/** - * Public AGW types — AGW SDK page section 3 (Notion export 2026-10-03 13:23 IST). - * - * Named-IDL Solana inputs and native/EVM raw offsets follow the October 7 - * decisions. Contract-dependent label editing remains capability-gated. +/** Public section-6 rules and internal adapters for the deployed v5 wire format. + * Source snapshot: October 12, 2026. Internal normalized types are not package exports. */ import type { Idl } from '@coral-xyz/anchor'; import type { SvmTermsWire } from './codec/svm-terms'; @@ -18,15 +15,10 @@ export type AgenticProgressHook = (event: ProgressEvent) => void; /** '0x617ba037' or 'supply(address,uint256,address,uint16)'. */ export type Selector = AgenticHex | `${string}(${string})`; -export interface NativeRule { - /** Push address: an EOA, or the UEA of an external key. Never the owner. */ - agent: AgenticAddress; - /** Omitted = the connected Push chain. */ - chainNamespace?: never; +/** One Push function a native rule allows, with its own limits and counters. */ +export interface NativeAction { target: AgenticAddress; selector: Selector | 'value-only'; - /** Unix seconds. */ - validUntil: number; /** Default 0: no native PC value allowance. */ maxValuePerCall?: bigint; /** Default 0: no native PC value allowance. */ @@ -36,8 +28,48 @@ export interface NativeRule { pins?: ArgPin[]; /** `maxTotal` default uint256 max (unlimited total). */ amount?: AmountLimit; + /** + * Overrides the rule's `validUntil` for this action. Decoded rules set it + * only when stored actions expire at different times. + */ + validUntil?: number; +} + +interface NativeRuleCommon { + /** Push address: an EOA, or the UEA of an external key. Never the owner. */ + agent: AgenticAddress; + /** Omitted = the connected Push chain. */ + chainNamespace?: never; + /** Unix seconds. */ + validUntil: number; +} + +/** A native rule allowing one function (shorthand for a one-entry `actions`). */ +export interface NativeSingleRule + extends NativeRuleCommon, + Omit { + actions?: never; +} + +/** + * A native rule allowing 1..8 functions under ONE rule ID. Each action keeps + * its own limits and counters on-chain; (target, selector) pairs must be + * unique. One rule per agent on Push keeps send-time selection unambiguous. + * Internal normalized representation; public callers use Rule.allowedCalls. + */ +export interface NativeMultiRule extends NativeRuleCommon { + actions: NativeAction[]; + target?: never; + selector?: never; + maxValuePerCall?: never; + maxValueTotal?: never; + maxCalls?: never; + pins?: never; + amount?: never; } +export type NativeRule = NativeSingleRule | NativeMultiRule; + /** * Where a pin or amount sits in the calldata. `arg` is the argument index in * the selector signature (requires the signature form of `selector`). @@ -65,7 +97,7 @@ export interface AssetCap { /** The destination chain's token (MOVEABLE constant) or native marker. */ token: MoveableToken | AgenticAddress; maxPerCall: bigint; - /** Omitted = uint256 maximum (unlimited). Explicit zero forbids movement. */ + /** Omitted = zero. Explicit zero forbids movement. */ maxTotal?: bigint; } @@ -106,6 +138,8 @@ export type SvmFieldConstraint = minRatio: { num: bigint; den: bigint }; }; export interface SvmInstructionRule { + /** Internal wire override: 0 means no exact account-count constraint. */ + maxAccounts?: number; program: string; instruction: { idl: Idl; name: string }; /** Top-level account names from a supported Anchor IDL; optional/nested accounts are rejected. */ @@ -127,26 +161,92 @@ export interface SolanaRule { outputTokens?: string[]; allowedInstructions: SvmInstructionRule[]; } -/** Stored constraints contain no IDL; supply a named SolanaRule when replacing. */ +/** Lossless stored Solana layout, accepted by update without an invented IDL. */ export interface DecodedSolanaRule extends Omit { format: 'decoded'; agent: AgenticAddress; chainNamespace: `solana:${string}`; assets: { token: string; maxPerCall: bigint; maxTotal: bigint }[]; } -export type Rule = NativeRule | UniversalRule | SolanaRule; +export type InternalRule = NativeRule | UniversalRule | SolanaRule; -export interface RulesRecord { +export interface InternalRulesRecord { rulesId: AgenticHex; enabled: boolean; chainNamespace: string; agent: AgenticAddress; validUntil: number; - rule: Rule | DecodedSolanaRule; + rule: InternalRule | DecodedSolanaRule; +} + +/** Current SDK section 6 public rule shape; contract wire types above are internal. */ +export type WalletMarker = 'agentic:wallet'; +export type Pin = + | { + arg: number; + expected: AgenticHex | AgenticAddress | bigint | WalletMarker; + max?: never; + account?: never; + } + | { arg: number; max: bigint; expected?: never; account?: never } + | { + account: number; + expected: string | WalletMarker; + token?: MoveableToken | string; + arg?: never; + max?: never; + }; +export interface RuleCall { + target: string; + selector: Selector | 'value-only'; + pins?: Pin[]; + maxValue?: bigint; + app?: string; + label?: string; +} +export interface RuleAsset { + token: MoveableToken | string; + maxPerCall: bigint; + maxTotal?: bigint; +} +export interface Rule { + agent: AgenticAddress; + chainNamespace?: ForeignChainNamespace; + validUntil: number; + assets?: RuleAsset[]; + maxGasPerCall?: bigint; + allowedCalls: RuleCall[]; +} +export type RuleInput = Rule | DecodedSolanaRule; +export type Spent = + | { + kind: 'native'; + valueSpent: bigint; + amountSpent: bigint; + callsUsed: number; + } + | { + kind: 'native'; + actions: { + target: AgenticAddress; + selector: Selector | 'value-only'; + valueSpent: bigint; + amountSpent: bigint; + callsUsed: number; + }[]; + } + | { kind: 'universal'; assets: { token: string; spent: bigint }[] }; +export interface RulesRecord extends Omit { + rule: RuleInput; + spent: Spent; +} +export interface InternalCreateOptions { + rules: InternalRule[]; + progressHook?: AgenticProgressHook; } export interface CreateOptions { - rules: Rule[]; + rules: RuleInput[]; progressHook?: AgenticProgressHook; } @@ -197,26 +297,26 @@ export interface AgenticWallet { sinceBlock?: bigint; }): Promise<{ checkpoints: Checkpoint[] }>; rules: { - /** Enabled rules only; expired-but-enabled rules remain visible. No public spend counters. */ + /** Enabled rules only; expired-but-enabled rules remain visible. Includes policy spend counters. */ list(): Promise<{ rules: RulesRecord[] }>; /** Unknown and revoked IDs both return RULE_NOT_FOUND; v1 has no historical records. */ get(rulesId: AgenticHex): Promise; add( - rules: Rule[], + rules: RuleInput[], opts?: { progressHook?: AgenticProgressHook } ): Promise<{ rulesIds: AgenticHex[]; tx: UniversalTxResponse }>; update(params: { - rules: { rulesId: AgenticHex; rule: Rule }[]; + rules: { rulesId: AgenticHex; rule: RuleInput }[]; progressHook?: AgenticProgressHook; }): Promise<{ rules: { rulesId: AgenticHex; replaced: AgenticHex }[]; tx: UniversalTxResponse; }>; - revoke( + delete( rulesIds: AgenticHex[], opts?: { progressHook?: AgenticProgressHook } ): Promise; - revoke(params: { + delete(params: { all: true; progressHook?: AgenticProgressHook; }): Promise; diff --git a/packages/core/src/lib/agentic/capabilities.ts b/packages/core/src/lib/agentic/capabilities.ts index 6e481d07..0f6cecf0 100644 --- a/packages/core/src/lib/agentic/capabilities.ts +++ b/packages/core/src/lib/agentic/capabilities.ts @@ -27,7 +27,7 @@ export enum AgenticCapability { UNIVERSAL_EVM_RULES = 'universalEvmRules', /** Per-token expected-spend assertion for universal replacement. A05. */ ASSERT_SPENT_UNIVERSAL_MULTI = 'assertSpentUniversalMulti', - /** Named-IDL Solana authoring, exact decoded reads and instruction execution. */ + /** Numeric-pin Solana authoring, exact decoded reads and instruction execution. */ UNIVERSAL_SVM_RULES = 'universalSvmRules', /** Editable wallet label (setLabel / LabelSet). A07. */ SET_LABEL = 'setLabel', diff --git a/packages/core/src/lib/agentic/codec/defaults.ts b/packages/core/src/lib/agentic/codec/defaults.ts index cc652c46..a5fc885b 100644 --- a/packages/core/src/lib/agentic/codec/defaults.ts +++ b/packages/core/src/lib/agentic/codec/defaults.ts @@ -39,9 +39,9 @@ export const AGENTIC_DEFAULTS = { }, universal: { assetMaxTotal: { - value: UINT256_MAX, - meaning: 'unlimited total; explicit zero forbids movement', - source: 'v5', + value: BigInt(0), + meaning: 'omitted or zero forbids token movement', + source: 'product', }, allowedCallMaxValue: { value: BigInt(0), diff --git a/packages/core/src/lib/agentic/codec/native.ts b/packages/core/src/lib/agentic/codec/native.ts index b1197685..57013161 100644 --- a/packages/core/src/lib/agentic/codec/native.ts +++ b/packages/core/src/lib/agentic/codec/native.ts @@ -9,7 +9,12 @@ import { type Hex, } from 'viem'; import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; -import type { AgenticHex, NativeRule } from '../agentic.types'; +import type { + AgenticHex, + NativeAction, + NativeRule, + NativeSingleRule, +} from '../agentic.types'; import { argumentOffset, encodeArgWord, rawOffset } from './abi-layout'; import { AGENTIC_DEFAULTS, UINT256_MAX, withDefault } from './defaults'; import { @@ -20,6 +25,7 @@ import { /** URP native limits at v5 (Types.sol MAX_PINS, AGW MAX_NATIVE_ACTIONS). */ export const MAX_PINS = 8; +export const MAX_NATIVE_ACTIONS = 8; const UINT32_MAX = 2 ** 32 - 1; const UINT48_MAX = 2 ** 48 - 1; @@ -94,10 +100,135 @@ export interface NativeEncodeContext { nowSeconds: number; } -/** Normalize and validate a public NativeRule into wire terms. Pure. */ +const SINGLE_ACTION_FIELDS = [ + 'target', + 'selector', + 'maxValuePerCall', + 'maxValueTotal', + 'maxCalls', + 'pins', + 'amount', +] as const; + +/** + * The actions a native rule allows: the single-action shorthand, or the + * explicit `actions` list (1..8). Each carries its effective `validUntil`. + */ +export function nativeActionsOf( + rule: NativeRule +): (NativeAction & { validUntil: number })[] { + if ( + !Number.isInteger(rule.validUntil) || + rule.validUntil < 1 || + rule.validUntil > UINT48_MAX + ) { + throw invalid( + 'rule validUntil must be a positive unix timestamp in seconds (uint48)' + ); + } + if (rule.actions !== undefined) { + if ( + !Array.isArray(rule.actions) || + rule.actions.length < 1 || + rule.actions.length > MAX_NATIVE_ACTIONS + ) { + throw invalid( + `actions must contain 1..${MAX_NATIVE_ACTIONS} entries (the AGW native action limit)` + ); + } + const mixed = SINGLE_ACTION_FIELDS.filter( + (f) => (rule as unknown as Record)[f] !== undefined + ); + if (mixed.length > 0) { + throw invalid( + `actions cannot be combined with top-level ${mixed.join( + ', ' + )}; put them inside each action` + ); + } + return rule.actions.map((a, i) => { + if (!a || typeof a !== 'object' || Array.isArray(a)) { + throw invalid(`actions[${i}] must be an action object`, { action: i }); + } + return { ...a, validUntil: a.validUntil ?? rule.validUntil }; + }); + } + const single = rule as NativeSingleRule; + return [ + { + target: single.target, + selector: single.selector, + maxValuePerCall: single.maxValuePerCall, + maxValueTotal: single.maxValueTotal, + maxCalls: single.maxCalls, + pins: single.pins, + amount: single.amount, + validUntil: single.validUntil, + }, + ]; +} + +/** + * Normalize and validate every action of a native rule into wire terms, in + * input order. (target, selector) pairs must be unique — the wallet refuses + * duplicates (DuplicateAction) because they share one action ID. Pure. + */ +export function nativeRuleToActionTerms( + rule: NativeRule, + ctx: NativeEncodeContext +): { terms: NativeTermsWire; parsed: ParsedSelector }[] { + if (rule.validUntil <= ctx.nowSeconds) { + throw invalid( + 'rule validUntil must be a future unix timestamp in seconds (uint48)' + ); + } + const actions = nativeActionsOf(rule); + const multi = rule.actions !== undefined; + const out = actions.map((action, i) => { + try { + return nativeActionToTerms(action, ctx); + } catch (err) { + if (multi && err instanceof AgenticError) { + throw new AgenticError(err.code, `actions[${i}]: ${err.message}`, { + hint: err.hint, + details: { ...(err.details ?? {}), action: i }, + cause: err, + }); + } + throw err; + } + }); + const seen = new Map(); + out.forEach(({ terms }, i) => { + const key = `${terms.target.toLowerCase()}:${terms.selector}`; + const first = seen.get(key); + if (first !== undefined) { + throw invalid( + `actions[${i}] repeats the target and selector of actions[${first}]`, + { action: i } + ); + } + seen.set(key, i); + }); + return out; +} + +/** Single-action convenience; multi-action rules use nativeRuleToActionTerms. */ export function nativeRuleToTerms( rule: NativeRule, ctx: NativeEncodeContext +): { terms: NativeTermsWire; parsed: ParsedSelector } { + const all = nativeRuleToActionTerms(rule, ctx); + if (all.length !== 1) { + throw invalid('nativeRuleToTerms takes a single-action rule'); + } + return all[0]; +} + +/** Normalize and validate one native action into wire terms. Pure. */ +export function nativeActionToTerms( + rule: NativeAction & { validUntil: number }, + ctx: NativeEncodeContext ): { terms: NativeTermsWire; parsed: ParsedSelector } { if ( !isAddress(rule.target, { strict: false }) || @@ -244,8 +375,8 @@ export function decodeNativeTerms(body: Hex): NativeTermsWire { export function nativeTermsToRule( terms: NativeTermsWire, agent: Address -): NativeRule { - const rule: NativeRule = { +): NativeSingleRule { + const rule: NativeSingleRule = { agent: getAddress(agent), target: getAddress(terms.target), selector: @@ -273,6 +404,37 @@ export function nativeTermsToRule( return rule; } +/** + * Stored action terms back to a public NativeRule: the single-action + * shorthand for one action, otherwise `actions` in stored order. The rule's + * `validUntil` is the earliest action expiry; an action expiring later keeps + * its own `validUntil`, so the result re-encodes to identical terms. + */ +export function nativeActionTermsToRule( + termsList: readonly NativeTermsWire[], + agent: Address +): NativeRule { + if (termsList.length === 0) { + throw new AgenticError( + AGENTIC_ERROR_CODE.RULE_READ_FAILED, + 'a native rule needs at least one action' + ); + } + if (termsList.length === 1) return nativeTermsToRule(termsList[0], agent); + const decoded = termsList.map((t) => nativeTermsToRule(t, agent)); + const validUntil = Math.min(...decoded.map((d) => d.validUntil)); + return { + agent: getAddress(agent), + validUntil, + actions: decoded.map( + ({ agent: _agent, validUntil: actionValidUntil, ...action }) => + actionValidUntil === validUntil + ? action + : { ...action, validUntil: actionValidUntil } + ), + }; +} + export function isUnlimited(value: bigint): boolean { return value === UINT256_MAX; } diff --git a/packages/core/src/lib/agentic/codec/rules.ts b/packages/core/src/lib/agentic/codec/rules.ts index 0d5364b8..3b9988b0 100644 --- a/packages/core/src/lib/agentic/codec/rules.ts +++ b/packages/core/src/lib/agentic/codec/rules.ts @@ -10,13 +10,13 @@ import { AgenticCapability, requireCapability } from '../capabilities'; import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; import type { NativeRule, - Rule, + InternalRule, UniversalRule, SolanaRule, } from '../agentic.types'; import { encodeNativeTerms, - nativeRuleToTerms, + nativeRuleToActionTerms, type NativeTermsWire, } from './native'; import { buildSession, encodeEnvelope, type SessionWire } from './session'; @@ -25,21 +25,24 @@ import { encodeSvmTerms, type SvmTermsWire } from './svm-terms'; import { SEND_OUTBOUND_SELECTOR } from '../contracts/v5'; import type { UniversalTermsWire } from './universal-terms'; -export function isSolanaRule(rule: Rule): rule is SolanaRule { +export function isSolanaRule(rule: InternalRule): rule is SolanaRule { return ( typeof (rule as SolanaRule).chainNamespace === 'string' && (rule as SolanaRule).chainNamespace.startsWith('solana:') ); } -export function isUniversalRule(rule: Rule): rule is UniversalRule { +export function isUniversalRule(rule: InternalRule): rule is UniversalRule { return ( (rule as UniversalRule).chainNamespace !== undefined && !isSolanaRule(rule) ); } /** CAIP-2 chain a rule governs: omitted = the connected Push chain. */ -export function ruleChain(rule: Rule, pushChainNamespace: string): string { +export function ruleChain( + rule: InternalRule, + pushChainNamespace: string +): string { return ( (rule as UniversalRule | SolanaRule).chainNamespace ?? pushChainNamespace ); @@ -68,19 +71,19 @@ export interface RuleEncodeContext { } export interface PreparedRule { - rule: Rule; + rule: InternalRule; agent: Address; chainNamespace: string; session: SessionWire; - /** Native terms when the rule is native (used for previews and assertions). */ - nativeTerms?: NativeTermsWire; + /** Native terms, one per action in input order, when the rule is native. */ + nativeTerms?: NativeTermsWire[]; universalTerms?: UniversalTermsWire; svmTerms?: SvmTermsWire; } /** Validate before signing. V5 permits several grants for the same agent/chain. */ export function prepareRules( - rules: readonly Rule[], + rules: readonly InternalRule[], ctx: RuleEncodeContext & { /** Wallet owner; when given, an agent equal to it is AGENT_IS_OWNER. */ owner?: Address; @@ -128,7 +131,7 @@ export function prepareRules( if ('ref' in rule) { throw new AgenticError( AGENTIC_ERROR_CODE.INVALID_RULE, - 'Rule ref is not supported; remove it from the input' + 'InternalRule ref is not supported; remove it from the input' ); } @@ -141,7 +144,7 @@ export function prepareRules( if (!terms || !ctx.gateway) throw new AgenticError( AGENTIC_ERROR_CODE.INVALID_RULE, - 'SVM rules require resolved wallet context and named IDL inputs' + 'SVM rules require resolved wallet context and validated instruction layouts' ); return { rule, @@ -169,30 +172,36 @@ export function prepareRules( return encodeUniversalRule(rule, ctx); } requireCapability(ctx.capabilities, AgenticCapability.NATIVE_RULES); - const { terms } = nativeRuleToTerms(rule as NativeRule, ctx); + const actions = nativeRuleToActionTerms(rule as NativeRule, ctx).map( + (a) => a.terms + ); const forbidden = [ '0x0000000000000000000000000000000000000000', '0x0000000000000000000000000000000000000001', ...(ctx.forbiddenTargets ?? []), ].map((a) => a.toLowerCase()); - if (forbidden.includes(terms.target.toLowerCase())) { - throw new AgenticError( - AGENTIC_ERROR_CODE.INVALID_RULE, - `rules[${i}].target ${terms.target} is a wallet-infrastructure address the contracts refuse as a native target` - ); - } + actions.forEach((terms, j) => { + if (forbidden.includes(terms.target.toLowerCase())) { + const where = + actions.length > 1 ? `rules[${i}].actions[${j}]` : `rules[${i}]`; + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + `${where}.target ${terms.target} is a wallet-infrastructure address the contracts refuse as a native target` + ); + } + }); + // One rule, one rule ID: every action is a separate (target, selector) + // entry of the same session, each with its own stored terms. const session = buildSession({ validator: ctx.validator, agent, rulesPolicy: ctx.rulesPolicy, - actions: [ - { - target: terms.target, - selector: terms.selector, - initData: encodeEnvelope(chainNamespace, encodeNativeTerms(terms)), - }, - ], + actions: actions.map((terms) => ({ + target: terms.target, + selector: terms.selector, + initData: encodeEnvelope(chainNamespace, encodeNativeTerms(terms)), + })), }); - return { rule, agent, chainNamespace, session, nativeTerms: terms }; + return { rule, agent, chainNamespace, session, nativeTerms: actions }; }); } diff --git a/packages/core/src/lib/agentic/codec/svm-idl.ts b/packages/core/src/lib/agentic/codec/svm-idl.ts index 4e7f22f4..9ed41f35 100644 --- a/packages/core/src/lib/agentic/codec/svm-idl.ts +++ b/packages/core/src/lib/agentic/codec/svm-idl.ts @@ -167,7 +167,7 @@ export function compileSvmIdlRule( ), discriminatorLen: ix.discriminator.length, dataless: false, - maxAccounts: names.length, + maxAccounts: entry.maxAccounts ?? names.length, }); for (const a of entry.accounts) { const accountIndex = names.indexOf(a.name); diff --git a/packages/core/src/lib/agentic/constants.ts b/packages/core/src/lib/agentic/constants.ts index f2f7d24b..1b3640a2 100644 --- a/packages/core/src/lib/agentic/constants.ts +++ b/packages/core/src/lib/agentic/constants.ts @@ -1,23 +1,11 @@ -import { PUSH_NETWORK } from '../constants/enums'; -import { DONUT_V5_ADDRESSES } from './contracts/donut-v5'; - -/** Checked Donut v5 proxies. Unsupported networks are absent. */ -export interface AgenticNetworkConstants { - FACTORY: `0x${string}`; - RULES_POLICY: `0x${string}`; - MAX_PINS: number; - MAX_ALLOWED_CALLS: number; - ENVELOPE_VERSION: number; -} - -export const AGENTIC: Readonly< - Partial> -> = Object.freeze({ - [PUSH_NETWORK.TESTNET_DONUT]: Object.freeze({ - FACTORY: DONUT_V5_ADDRESSES.factory, - RULES_POLICY: DONUT_V5_ADDRESSES.rulesPolicy, - MAX_PINS: 8, - MAX_ALLOWED_CALLS: 32, - ENVELOPE_VERSION: 1, +/** Public section-7 discovery constants; deployment wiring stays internal. */ +export const AGENTIC = Object.freeze({ + WALLET: 'agentic:wallet' as const, + PRESETS: Object.freeze({ + CATEGORY: Object.freeze({ + DEXES: 'DEXES' as const, + LENDING: 'LENDING' as const, + PREDICTION: 'PREDICTION' as const, + }), }), }); diff --git a/packages/core/src/lib/agentic/deployments.ts b/packages/core/src/lib/agentic/deployments.ts index 421a0a02..e9a9f84e 100644 --- a/packages/core/src/lib/agentic/deployments.ts +++ b/packages/core/src/lib/agentic/deployments.ts @@ -87,7 +87,7 @@ export function registerAgenticGeneration( ): AgenticGeneration { if (input.id !== v5.id || input.sourceCommit !== V5_SOURCE_COMMIT) { throw new AgenticError( - AGENTIC_ERROR_CODE.GENERATION_UNSUPPORTED, + AGENTIC_ERROR_CODE.CAPABILITY_UNAVAILABLE, `no contract adapter for generation "${input.id}"` ); } @@ -132,7 +132,7 @@ export async function verifyPolicyVersion( }); if (version !== '3.1.0') throw new AgenticError( - AGENTIC_ERROR_CODE.GENERATION_UNSUPPORTED, + AGENTIC_ERROR_CODE.CAPABILITY_UNAVAILABLE, `URP version ${String(version)} is not supported by the v5 adapter` ); } @@ -149,7 +149,7 @@ export function currentGeneration(network: PUSH_NETWORK): AgenticGeneration { const gen = gens[gens.length - 1]; if (!gen) { throw new AgenticError( - AGENTIC_ERROR_CODE.GENERATION_UNSUPPORTED, + AGENTIC_ERROR_CODE.CAPABILITY_UNAVAILABLE, `no verified AGW deployment is registered for ${network}`, { hint: 'AGW v5 is configured on Donut only; this Push network has no registered v5 deployment.', @@ -194,7 +194,7 @@ export function verifyFactoryWiring( })) as Address; if (getAddress(impl) !== gen.addresses.walletImplementation) { throw new AgenticError( - AGENTIC_ERROR_CODE.GENERATION_UNSUPPORTED, + AGENTIC_ERROR_CODE.CAPABILITY_UNAVAILABLE, `factory ${gen.addresses.factory} points at implementation ${impl}, not the registered ${gen.addresses.walletImplementation}` ); } @@ -216,7 +216,7 @@ export async function resolveWalletGeneration( wallet: Address ): Promise { const gens = generationsFor(network); - if (gens.length === 0) currentGeneration(network); // throws GENERATION_UNSUPPORTED (A07) + if (gens.length === 0) currentGeneration(network); // throws CAPABILITY_UNAVAILABLE (A07) const code = await reader.getCode({ address: wallet }); if (!code || code === '0x') { @@ -247,7 +247,7 @@ export async function resolveWalletGeneration( const gen = gens.find((g) => g.addresses.factory === factory); if (!gen) { throw new AgenticError( - AGENTIC_ERROR_CODE.GENERATION_UNSUPPORTED, + AGENTIC_ERROR_CODE.CAPABILITY_UNAVAILABLE, `${wallet} was created by factory ${factory}, which is not a verified AGW generation on ${network}`, { details: { factory, assumption: 'A07' } } ); @@ -289,7 +289,7 @@ export async function resolveWalletGeneration( accountId !== gen.accountId; if (mismatch) { throw new AgenticError( - AGENTIC_ERROR_CODE.GENERATION_UNSUPPORTED, + AGENTIC_ERROR_CODE.CAPABILITY_UNAVAILABLE, `${wallet} wiring does not match registered generation ${gen.id}`, { details: { engine, policy, validator, gateway, accountId } } ); diff --git a/packages/core/src/lib/agentic/errors.ts b/packages/core/src/lib/agentic/errors.ts index d66055dc..b7583887 100644 --- a/packages/core/src/lib/agentic/errors.ts +++ b/packages/core/src/lib/agentic/errors.ts @@ -10,6 +10,7 @@ import { */ export const AGENTIC_ERROR_CODE = { // create / rule validation (spec 3.f) + DUPLICATE_RULE: 'DUPLICATE_RULE', AGENT_IS_OWNER: 'AGENT_IS_OWNER', AMBIGUOUS_RULE: 'AMBIGUOUS_RULE', TARGET_NOT_ON_RULE_CHAIN: 'TARGET_NOT_ON_RULE_CHAIN', @@ -18,8 +19,8 @@ export const AGENTIC_ERROR_CODE = { NOT_OWNER_OR_AGENT: 'NOT_OWNER_OR_AGENT', WALLET_NOT_DEPLOYED: 'WALLET_NOT_DEPLOYED', NOT_AGENTIC_WALLET: 'NOT_AGENTIC_WALLET', - // rules.revoke (spec 3.f) - REVOKE_NEEDS_TARGET: 'REVOKE_NEEDS_TARGET', + // rules.delete (spec 3.f) + DELETE_NEEDS_TARGET: 'DELETE_NEEDS_TARGET', // sendTransaction (spec 3.f) NO_RULES_FOR_CHAIN: 'NO_RULES_FOR_CHAIN', FROM_NOT_ALLOWED: 'FROM_NOT_ALLOWED', @@ -27,7 +28,6 @@ export const AGENTIC_ERROR_CODE = { // SDK-owned INVALID_RULE: 'INVALID_RULE', CAPABILITY_UNAVAILABLE: 'CAPABILITY_UNAVAILABLE', - GENERATION_UNSUPPORTED: 'GENERATION_UNSUPPORTED', READ_ONLY: 'READ_ONLY', NOT_WALLET_OWNER: 'NOT_WALLET_OWNER', RULE_NOT_FOUND: 'RULE_NOT_FOUND', @@ -40,7 +40,6 @@ export const AGENTIC_ERROR_CODE = { AGENT_GAS_INSUFFICIENT: 'AGENT_GAS_INSUFFICIENT', WALLET_BALANCE_INSUFFICIENT: 'WALLET_BALANCE_INSUFFICIENT', GATEWAY_ALLOWANCE_INSUFFICIENT: 'GATEWAY_ALLOWANCE_INSUFFICIENT', - RULE_LIMIT_EXCEEDED: 'RULE_LIMIT_EXCEEDED', } as const; export type AgenticErrorCode = diff --git a/packages/core/src/lib/agentic/execution/outbound.ts b/packages/core/src/lib/agentic/execution/outbound.ts index ab78059f..999690ef 100644 --- a/packages/core/src/lib/agentic/execution/outbound.ts +++ b/packages/core/src/lib/agentic/execution/outbound.ts @@ -27,6 +27,9 @@ import { } from '../errors'; import type { AgenticRuntime } from '../runtime'; +/** Includes first-use CEA deployment; explicit caller gas always takes precedence. */ +const FIRST_USE_EVM_GAS_LIMIT = BigInt(2_000_000); + /** URP MAX_ACTIONS_PER_REQUEST at v5. */ export const MAX_DESTINATION_CALLS = 10; @@ -219,7 +222,8 @@ export async function composeOutbound( const quote = await runtime.quoteOutbound( token, - params.gasLimit ?? BigInt(0), + params.gasLimit ?? + (resolved.isDeployed ? BigInt(0) : FIRST_USE_EVM_GAS_LIMIT), chain ); if (quote.nativeValueForGas <= BigInt(0)) { diff --git a/packages/core/src/lib/agentic/execution/svm-outbound.ts b/packages/core/src/lib/agentic/execution/svm-outbound.ts index 6f35c58f..390f3320 100644 --- a/packages/core/src/lib/agentic/execution/svm-outbound.ts +++ b/packages/core/src/lib/agentic/execution/svm-outbound.ts @@ -25,7 +25,7 @@ export function composeAgwSvmAction( nowSeconds: number ): Call { function fail(name: string): never { - throw new AgenticError(AGENTIC_ERROR_CODE.RULE_LIMIT_EXCEEDED, name, { + throw new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, name, { details: { contractError: name }, }); } diff --git a/packages/core/src/lib/agentic/index.ts b/packages/core/src/lib/agentic/index.ts index 0bfceff3..667d5155 100644 --- a/packages/core/src/lib/agentic/index.ts +++ b/packages/core/src/lib/agentic/index.ts @@ -6,28 +6,34 @@ export type { AgenticProgressHook, AgenticTxMetadata, AgenticWallet, - AllowedCall, - AssetCap, + RuleCall as AllowedCall, + RuleAsset as AssetCap, Checkpoint, CheckpointKind, CreateOptions, CreateResult, ForeignChainNamespace, - NativeRule, - SolanaRule, DecodedSolanaRule, - SvmInstructionRule, - SvmAccountRef, - SvmFieldConstraint, Rule, + RuleInput, + Pin, + Spent, + WalletMarker, RulesRecord, Selector, - UniversalRule, WalletInfo, WalletSummary, } from './agentic.types'; export { AGENTIC_ERROR_CODE, AgenticError, AgenticRevertError } from './errors'; export type { AgenticErrorCode } from './errors'; export { AGENTIC } from './constants'; -export type { AgenticNetworkConstants } from './constants'; -export { agenticUtils } from './utils'; + +export type { + Preset, + PresetCategory, + PresetAsset, + PresetOptions, + ReadyPresetOptions, + PresetRuleTemplate, + AgenticPresets, +} from './presets/types'; diff --git a/packages/core/src/lib/agentic/management/create.ts b/packages/core/src/lib/agentic/management/create.ts index 3ed82950..a021a99a 100644 --- a/packages/core/src/lib/agentic/management/create.ts +++ b/packages/core/src/lib/agentic/management/create.ts @@ -1,3 +1,4 @@ +import { assertNoDuplicateRules } from './duplicates'; import { getAddress, type Address, type Hex, type Log } from 'viem'; import { PROGRESS_HOOK } from '../../progress-hook/progress-hook.types'; import type { MultiCall } from '../../orchestrator/orchestrator.types'; @@ -9,7 +10,7 @@ import { prepareWalletRules } from './prepare'; import { assertLabel } from './label'; import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; import type { AgenticRuntime } from '../runtime'; -import type { CreateOptions, CreateResult } from '../agentic.types'; +import type { InternalCreateOptions, CreateResult } from '../agentic.types'; import { Snapshot, scanLogs } from '../reads/snapshot'; import { walletCount, walletInfo } from '../reads/wallets'; import { @@ -36,7 +37,7 @@ import { export async function createWallet( runtime: AgenticRuntime, label: string, - options: CreateOptions + options: InternalCreateOptions ): Promise { const hook = options?.progressHook; assertLabel(label); @@ -82,8 +83,9 @@ export async function createWallet( options.rules, snap ); - const selfTarget = prepared.findIndex( - (p) => p.nativeTerms?.target === wallet + assertNoDuplicateRules(prepared); + const selfTarget = prepared.findIndex((p) => + p.nativeTerms?.some((t) => t.target === wallet) ); if (selfTarget >= 0) { throw new AgenticError( @@ -387,7 +389,7 @@ async function createFailure( function emitFailure( runtime: AgenticRuntime, - hook: CreateOptions['progressHook'], + hook: InternalCreateOptions['progressHook'], err: unknown ): void { const e = err as { code?: string; message?: string; decodedError?: unknown }; diff --git a/packages/core/src/lib/agentic/management/duplicates.ts b/packages/core/src/lib/agentic/management/duplicates.ts new file mode 100644 index 00000000..68e1e02e --- /dev/null +++ b/packages/core/src/lib/agentic/management/duplicates.ts @@ -0,0 +1,28 @@ +import { getAddress } from 'viem'; +import type { PreparedRule } from '../codec/rules'; +import { chainHash } from '../codec/rules'; +import type { ActiveRule } from '../reads/rules'; +import { AgenticError, AGENTIC_ERROR_CODE } from '../errors'; + +/** SDK creation policy; existing contract overlaps still use AMBIGUOUS_RULE at send. */ +export function assertNoDuplicateRules( + prepared: readonly PreparedRule[], + existing: readonly ActiveRule[] = [] +): void { + const keys = new Set( + existing.map((r) => `${getAddress(r.agent)}:${r.chainHash}`) + ); + for (const rule of prepared) { + const key = `${getAddress(rule.agent)}:${chainHash(rule.chainNamespace)}`; + if (keys.has(key)) + throw new AgenticError( + AGENTIC_ERROR_CODE.DUPLICATE_RULE, + `an enabled rule already names ${rule.agent} for ${rule.chainNamespace}`, + { + hint: 'Put multiple allowed calls in one rule or update the existing rule.', + details: { agent: rule.agent, chainNamespace: rule.chainNamespace }, + } + ); + keys.add(key); + } +} diff --git a/packages/core/src/lib/agentic/management/prepare.ts b/packages/core/src/lib/agentic/management/prepare.ts index d2019629..195841b0 100644 --- a/packages/core/src/lib/agentic/management/prepare.ts +++ b/packages/core/src/lib/agentic/management/prepare.ts @@ -1,3 +1,4 @@ +import { isPublicRule, normalizePublicRule } from '../public-rule'; import { preparePublicSvmRule } from './svm-public'; import type { SvmTermsWire } from '../codec/svm-terms'; import { getAddress, zeroAddress, type Address } from 'viem'; @@ -16,7 +17,7 @@ import { } from '../deployments'; import { AgenticCapability, requireCapability } from '../capabilities'; import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; -import type { Rule, UniversalRule, SolanaRule } from '../agentic.types'; +import type { InternalRule, UniversalRule, SolanaRule } from '../agentic.types'; import type { AgenticRuntime } from '../runtime'; import { Snapshot } from '../reads/snapshot'; @@ -32,9 +33,14 @@ export async function prepareWalletRules( gen: AgenticGeneration, owner: Address, wallet: Address, - rules: readonly Rule[], + inputs: readonly InternalRule[], snap: Snapshot ) { + const rules = await Promise.all( + inputs.map((rule) => + isPublicRule(rule) ? normalizePublicRule(rule, wallet, runtime) : rule + ) + ); if (rules.length) await verifyPolicyVersion(runtime.reader, gen); const svm = new Map(); const universal = new Map(); diff --git a/packages/core/src/lib/agentic/management/rules-write.ts b/packages/core/src/lib/agentic/management/rules-write.ts index 96d5fcb7..07c8f0ae 100644 --- a/packages/core/src/lib/agentic/management/rules-write.ts +++ b/packages/core/src/lib/agentic/management/rules-write.ts @@ -1,3 +1,4 @@ +import { assertNoDuplicateRules } from './duplicates'; import type { Address, Hex } from 'viem'; import { PROGRESS_HOOK } from '../../progress-hook/progress-hook.types'; import type { @@ -11,7 +12,11 @@ import { prepareWalletRules } from './prepare'; import { assertLabel } from './label'; import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; import type { AgenticRuntime } from '../runtime'; -import type { AgenticHex, AgenticProgressHook, Rule } from '../agentic.types'; +import type { + AgenticHex, + AgenticProgressHook, + InternalRule, +} from '../agentic.types'; import { readActiveRules, readNativeSpend, @@ -69,7 +74,7 @@ export async function addRules( runtime: AgenticRuntime, gen: AgenticGeneration, wallet: Address, - rules: readonly Rule[], + rules: readonly InternalRule[], hook?: AgenticProgressHook ): Promise<{ rulesIds: AgenticHex[]; tx: UniversalTxResponse }> { assertCanSign(runtime, 'rules.add'); @@ -89,6 +94,7 @@ export async function addRules( rules, snap ); + assertNoDuplicateRules(prepared, await readActiveRules(snap, gen, wallet)); const nonce = BigInt( await snap.read(wallet, gen.contracts.abis.wallet, 'grantNonce') ); @@ -146,8 +152,8 @@ export function assertRevokeTarget(target: unknown): { const ids = Array.isArray(target) ? (target as AgenticHex[]) : undefined; if (!all && (!ids || ids.length === 0)) { throw new AgenticError( - AGENTIC_ERROR_CODE.REVOKE_NEEDS_TARGET, - 'rules.revoke needs explicit rule IDs or { all: true }', + AGENTIC_ERROR_CODE.DELETE_NEEDS_TARGET, + 'rules.delete needs explicit rule IDs or { all: true }', { hint: 'A bare revoke that wipes every rule is too easy to make by mistake.', } @@ -156,7 +162,7 @@ export function assertRevokeTarget(target: unknown): { return { all, ids }; } -/** w.rules.revoke(ids) / w.rules.revoke({ all: true }). Bare revoke is refused. */ +/** w.rules.delete(ids) / w.rules.delete({ all: true }). Bare revoke is refused. */ export async function revokeRules( runtime: AgenticRuntime, gen: AgenticGeneration, @@ -171,7 +177,7 @@ export async function revokeRules( if (all) hook = (target as { progressHook?: AgenticProgressHook }).progressHook ?? hook; - assertCanSign(runtime, 'rules.revoke'); + assertCanSign(runtime, 'rules.delete'); const snap = await Snapshot.at(runtime.reader); await assertOwner(runtime, gen, wallet, snap); @@ -189,7 +195,7 @@ export async function revokeRules( if (unique.size !== (ids as Hex[]).length) { throw new AgenticError( AGENTIC_ERROR_CODE.INVALID_RULE, - 'rules.revoke got the same rule ID twice' + 'rules.delete got the same rule ID twice' ); } for (const id of ids as Hex[]) { @@ -231,7 +237,7 @@ export async function revokeRules( }, ]; } - const result = await finish(runtime, hook, 'rules.revoke', async () => { + const result = await finish(runtime, hook, 'rules.delete', async () => { const tx = await sendOwnerCalls(runtime, calls, hook); const { logs } = await confirmedLogs(runtime, tx); const revoked = gen.contracts @@ -260,7 +266,7 @@ export async function updateRules( gen: AgenticGeneration, wallet: Address, params: { - rules: { rulesId: AgenticHex; rule: Rule }[]; + rules: { rulesId: AgenticHex; rule: InternalRule }[]; progressHook?: AgenticProgressHook; } ): Promise<{ @@ -415,7 +421,7 @@ function sameIds(a: readonly Hex[], b: readonly Hex[]): boolean { ); } -/** Owner rename through the owner door; empty resets the default label. */ +/** Direct owner rename; empty resets the default label without a checkpoint. */ export async function setLabel( runtime: AgenticRuntime, gen: AgenticGeneration, @@ -434,18 +440,13 @@ export async function setLabel( { to: wallet, value: BigInt(0), - data: gen.contracts.encodeExecute([ - { - target: wallet, - value: BigInt(0), - data: gen.contracts.encodeSetLabel(label), - }, - ]), + data: gen.contracts.encodeSetLabel(label), }, ], hook ); await confirmedLogs(runtime, tx); + emitAgentic(runtime, hook, PROGRESS_HOOK.AGENTIC_TX_106, label); return { tx }; }).then(({ tx }) => tx); } diff --git a/packages/core/src/lib/agentic/management/svm-public.ts b/packages/core/src/lib/agentic/management/svm-public.ts index f74d996b..3fcc1409 100644 --- a/packages/core/src/lib/agentic/management/svm-public.ts +++ b/packages/core/src/lib/agentic/management/svm-public.ts @@ -3,7 +3,7 @@ import { getAddress, hexToBytes, zeroAddress } from 'viem'; import type { Address, Hex } from 'viem'; import { CHAIN, VM } from '../../constants/enums'; import { CHAIN_INFO } from '../../constants/chain'; -import type { SolanaRule } from '../agentic.types'; +import type { SolanaRule, DecodedSolanaRule } from '../agentic.types'; import type { AgenticRuntime } from '../runtime'; import type { Snapshot } from '../reads/snapshot'; import { readGasPrc20 } from '../contracts/prc20-metadata'; @@ -12,7 +12,7 @@ import { createSvmMetadataProvider } from './svm-metadata'; import { deriveAgwSvmAta, svmKey } from '../codec/svm-accounts'; import { compileSvmIdlRule } from '../codec/svm-idl'; import { svmInvalid } from '../codec/svm-terms'; -import { UINT256_MAX } from '../codec/defaults'; +import { validateSvmTerms } from '../codec/svm-terms'; export function svmMetadata(runtime: AgenticRuntime) { return ( @@ -29,14 +29,16 @@ export async function preparePublicSvmRule( runtime: AgenticRuntime, snap: Snapshot, wallet: Address, - rule: SolanaRule + rule: SolanaRule | DecodedSolanaRule ) { const chain = rule.chainNamespace as CHAIN; if (CHAIN_INFO[chain]?.vm !== VM.SVM) throw svmInvalid('unknown Solana chain'); if (!Array.isArray(rule.assets) || rule.assets.length > 8) throw svmInvalid('assets must contain at most eight entries'); - if (rule.outputTokens !== undefined && !Array.isArray(rule.outputTokens)) + const raw = 'format' in rule && rule.format === 'decoded'; + const outputTokens = 'outputTokens' in rule ? rule.outputTokens : undefined; + if (outputTokens !== undefined && !Array.isArray(outputTokens)) throw svmInvalid('outputTokens must be an array of mint addresses'); const metadata = svmMetadata(runtime); const requested = rule.assets.length @@ -74,12 +76,12 @@ export async function preparePublicSvmRule( caps.push({ token: getAddress(token), maxPerCall: asset.maxPerCall, - maxTotal: asset.maxTotal ?? UINT256_MAX, + maxTotal: asset.maxTotal ?? BigInt(0), }); sources.push({ key, token }); if (key) mints.add(key); } - const outputs = (rule.outputTokens ?? []).map((mint) => ({ mint })); + const outputs = (outputTokens ?? []).map((mint) => ({ mint })); outputs.forEach((o) => mints.add(svmKey(o.mint))); const ctx = await resolveSvmContext( snap, @@ -113,8 +115,25 @@ export async function preparePublicSvmRule( throw svmInvalid('mint resolver returned another mint'); tokenAccounts.set(mint, deriveAgwSvmAta(ctx.expectedCEA, token)); } + if (raw) { + const stored = rule as DecodedSolanaRule; + if ( + svmKey(stored.expectedCEA) !== ctx.expectedCEA || + svmKey(stored.gatewayProgram) !== ctx.gatewayProgram + ) + throw svmInvalid('decoded rule belongs to another wallet or gateway'); + if ( + ctx.ceaAccounts.some( + (a) => !stored.ceaAccounts.some((s) => svmKey(s) === a) + ) + ) + throw svmInvalid('decoded rule omits a required wallet value account'); + const terms = { ...stored, assets: caps }; + validateSvmTerms(terms, runtime.nowSeconds()); + return terms; + } return compileSvmIdlRule( - rule, + rule as SolanaRule, { ...ctx, tokenAccounts }, runtime.nowSeconds() ); diff --git a/packages/core/src/lib/agentic/management/svm.ts b/packages/core/src/lib/agentic/management/svm.ts index 685b661a..14aa58ab 100644 --- a/packages/core/src/lib/agentic/management/svm.ts +++ b/packages/core/src/lib/agentic/management/svm.ts @@ -61,7 +61,7 @@ export async function verifySvmWallet( ); if (actual.addresses.factory !== gen.addresses.factory) throw new AgenticError( - AGENTIC_ERROR_CODE.GENERATION_UNSUPPORTED, + AGENTIC_ERROR_CODE.CAPABILITY_UNAVAILABLE, 'SVM wallet generation mismatch' ); await verifyPolicyVersion(runtime.reader, gen); diff --git a/packages/core/src/lib/agentic/presets/catalog.ts b/packages/core/src/lib/agentic/presets/catalog.ts new file mode 100644 index 00000000..5edbbec6 --- /dev/null +++ b/packages/core/src/lib/agentic/presets/catalog.ts @@ -0,0 +1,23 @@ +import type { Address } from 'viem'; +import type { RuleCall, ForeignChainNamespace } from '../agentic.types'; +import type { PresetCategory } from './types'; + +/** Internal catalog: reviewed addresses and explicit calls only; never fetched at runtime. */ +export interface PresetChainDefinition { + chainNamespace: ForeignChainNamespace; + allowedCalls: readonly RuleCall[]; + /** Exact spenders that need an approval for each non-native supplied asset. */ + approvals?: readonly { spender: Address; app: string }[]; + maxGasPerCall?: bigint; +} +export interface PresetDefinition { + constant: PresetCategory; + name: string; + chains: readonly PresetChainDefinition[]; +} +/** No approved app/address catalog yet. Empty categories must be hidden by UIs. */ +export const PRESET_CATALOG: readonly PresetDefinition[] = [ + { constant: 'DEXES', name: 'Popular DEXes', chains: [] }, + { constant: 'LENDING', name: 'Lending', chains: [] }, + { constant: 'PREDICTION', name: 'Prediction markets', chains: [] }, +]; diff --git a/packages/core/src/lib/agentic/presets/index.ts b/packages/core/src/lib/agentic/presets/index.ts new file mode 100644 index 00000000..60f5a842 --- /dev/null +++ b/packages/core/src/lib/agentic/presets/index.ts @@ -0,0 +1,240 @@ +import { getAddress, isAddress, zeroAddress } from 'viem'; +import { + AgenticError, + AGENTIC_ERROR_CODE, + capabilityUnavailable, +} from '../errors'; +import type { RuleAsset, RuleCall } from '../agentic.types'; +import type { + AgenticPresets, + PresetOptions, + PresetRuleTemplate, +} from './types'; +import { parseSelector } from '../codec/selectors'; +import { PRESET_CATALOG, type PresetDefinition } from './catalog'; + +const MAX_UINT256 = (BigInt(1) << BigInt(256)) - BigInt(1); +const invalid = (message: string) => + new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, message); +function cap(value: unknown, name: string): bigint { + if (value === undefined) return BigInt(0); + if (typeof value !== 'bigint' || value < BigInt(0) || value > MAX_UINT256) + throw invalid(`${name} must be a uint256 bigint`); + return value; +} +function copyCall(call: RuleCall): RuleCall { + return { + ...call, + ...(call.pins + ? { + pins: call.pins.map((p) => ({ + ...p, + ...('token' in p && p.token && typeof p.token === 'object' + ? { token: { ...p.token } } + : {}), + })), + } + : {}), + }; +} +function tokenAddress(token: RuleAsset['token']): string { + const address = typeof token === 'string' ? token : token?.address; + if (typeof address !== 'string' || !address.trim()) + throw invalid('preset asset requires a token address'); + return address; +} +/** Not a public registration API. Tests inject fixtures; production uses the bundled catalog. */ +export function buildPresetApi( + catalog: readonly PresetDefinition[] +): AgenticPresets { + // Detach from the input so neither a returned template nor an input mutation changes the catalog. + const entries = catalog.map((p) => ({ + ...p, + chains: p.chains.map((c) => ({ + ...c, + allowedCalls: c.allowedCalls.map(copyCall), + approvals: c.approvals?.map((a) => ({ ...a })), + })), + })); + if ( + new Set(entries.map((e) => e.constant)).size !== entries.length || + entries.some( + (e) => + new Set(e.chains.map((c) => c.chainNamespace)).size !== e.chains.length + ) + ) + throw invalid('duplicate preset or chain in catalog'); + const api = { + list(options?: { type?: 'CATEGORY' }) { + if (options?.type !== undefined && options.type !== 'CATEGORY') + throw invalid('only CATEGORY presets are supported'); + return { + presets: entries.map((p) => ({ + type: 'CATEGORY' as const, + constant: p.constant, + name: p.name, + chains: p.chains.map((c) => c.chainNamespace), + })), + }; + }, + get(preset: string, options: PresetOptions = {}) { + const entry = entries.find((p) => p.constant === preset); + if (!entry) throw invalid(`unknown preset ${String(preset)}`); + if (!options || typeof options !== 'object' || Array.isArray(options)) + throw invalid('preset options must be an object'); + if ( + options.agent !== undefined && + (!isAddress(options.agent, { strict: false }) || + getAddress(options.agent) === zeroAddress) + ) + throw invalid('preset agent must be a nonzero Push address'); + if ( + options.validUntil !== undefined && + (!Number.isSafeInteger(options.validUntil) || + options.validUntil <= Math.floor(Date.now() / 1000) || + options.validUntil >= 2 ** 48) + ) + throw invalid('preset validUntil must be a future uint48 timestamp'); + if (options.assets !== undefined && !Array.isArray(options.assets)) + throw invalid('preset assets must be an array'); + const chains = + options.chainNamespace === undefined + ? entry.chains + : entry.chains.filter( + (c) => c.chainNamespace === options.chainNamespace + ); + if (options.chainNamespace !== undefined && !chains.length) + throw capabilityUnavailable( + 'presetChain', + `preset ${preset} has no approved entry for ${options.chainNamespace}` + ); + if (!chains.length && options.assets?.length) + throw capabilityUnavailable( + 'presetCatalog', + `preset ${preset} has no approved app entries` + ); + const assets = new Map(); + for (const asset of options.assets ?? []) { + if (!asset || typeof asset !== 'object') + throw invalid('preset asset must be an object'); + const chain = asset.chainNamespace ?? options.chainNamespace; + if (!chain) + throw invalid( + 'each asset needs chainNamespace when no chain filter is supplied' + ); + if (!chains.some((c) => c.chainNamespace === chain)) + throw invalid(`asset chain ${chain} is outside the selected preset`); + const address = tokenAddress(asset.token); + if ( + chain.startsWith('eip155:') && + !isAddress(address, { strict: false }) + ) + throw invalid('EVM preset asset requires an EVM address'); + const group = assets.get(chain) ?? []; + const key = chain.startsWith('eip155:') + ? address.toLowerCase() + : address; + if ( + group.some( + (a) => + (chain.startsWith('eip155:') + ? tokenAddress(a.token).toLowerCase() + : tokenAddress(a.token)) === key + ) + ) + throw invalid('duplicate preset asset on the same chain'); + group.push({ + token: + typeof asset.token === 'string' ? asset.token : { ...asset.token }, + maxPerCall: cap(asset.maxPerCall, 'maxPerCall'), + maxTotal: cap(asset.maxTotal, 'maxTotal'), + }); + assets.set(chain, group); + } + const rules: PresetRuleTemplate[] = chains.map((chain) => { + const calls = chain.allowedCalls.map(copyCall); + const approvals = new Map(); + for (const asset of assets.get(chain.chainNamespace) ?? []) { + const token = tokenAddress(asset.token); + if ( + token === zeroAddress || + (typeof asset.token !== 'string' && + asset.token.mechanism === 'native') + ) + continue; + for (const approval of chain.approvals ?? []) { + if (!chain.chainNamespace.startsWith('eip155:')) + throw capabilityUnavailable( + 'presetApproval', + 'Solana approvals require a separately reviewed instruction template' + ); + const spender = getAddress(approval.spender); + const target = getAddress(token); + const previous = approvals.get(target); + if (previous && previous !== spender) + throw capabilityUnavailable( + 'presetApproval', + 'multiple spenders for one token need a reviewed policy representation; no unrestricted approval is generated' + ); + if (previous) continue; + approvals.set(target, spender); + calls.push({ + target, + selector: 'approve(address,uint256)', + pins: [ + { arg: 0, expected: spender }, + { arg: 1, max: asset.maxPerCall }, + ], + app: approval.app, + label: 'Approve token spending', + }); + } + } + if (!calls.length || calls.length > 32) + throw capabilityUnavailable( + 'presetCalls', + 'preset must contain 1..32 allowed calls including approvals' + ); + const pairs = new Set(); + for (const call of calls) { + if (!/^[A-Za-z_$][\w$]*\(.*\)$/.test(call.selector)) + throw invalid('preset selectors must be full signatures'); + const selector = chain.chainNamespace.startsWith('eip155:') + ? parseSelector(call.selector).selector + : call.selector; + const pair = `${ + chain.chainNamespace.startsWith('eip155:') + ? call.target.toLowerCase() + : call.target + }:${selector}`; + if (pairs.has(pair)) + throw capabilityUnavailable( + 'presetCalls', + 'duplicate target/function entries need a reviewed policy representation' + ); + pairs.add(pair); + } + return { + chainNamespace: chain.chainNamespace, + allowedCalls: calls, + ...(options.agent !== undefined + ? { agent: getAddress(options.agent) } + : {}), + ...(options.validUntil !== undefined + ? { validUntil: options.validUntil } + : {}), + ...(options.assets !== undefined + ? { assets: assets.get(chain.chainNamespace) ?? [] } + : {}), + ...(chain.maxGasPerCall !== undefined + ? { maxGasPerCall: cap(chain.maxGasPerCall, 'maxGasPerCall') } + : {}), + }; + }); + return { rules }; + }, + }; + // The overload narrows templates only when both required fields were supplied and validated. + return Object.freeze(api) as AgenticPresets; +} +export const agenticPresets = buildPresetApi(PRESET_CATALOG); diff --git a/packages/core/src/lib/agentic/presets/types.ts b/packages/core/src/lib/agentic/presets/types.ts new file mode 100644 index 00000000..5e3a6bc7 --- /dev/null +++ b/packages/core/src/lib/agentic/presets/types.ts @@ -0,0 +1,40 @@ +import type { Address } from 'viem'; +import type { Rule, RuleAsset, ForeignChainNamespace } from '../agentic.types'; + +export type PresetCategory = 'DEXES' | 'LENDING' | 'PREDICTION'; +export interface Preset { + type: 'CATEGORY'; + constant: PresetCategory; + name: string; + chains: ForeignChainNamespace[]; +} +/** An editable review-screen template; both identity and expiry are required by create. */ +export type PresetRuleTemplate = Omit & { + agent?: Address; + validUntil?: number; +}; +export interface PresetAsset { + chainNamespace?: ForeignChainNamespace; + token: RuleAsset['token']; + /** Omitted caps are zero, by the user's October 12 decision. */ + maxPerCall?: bigint; + maxTotal?: bigint; +} +export interface PresetOptions { + chainNamespace?: ForeignChainNamespace; + agent?: Address; + validUntil?: number; + assets?: PresetAsset[]; +} +export interface ReadyPresetOptions extends PresetOptions { + agent: Address; + validUntil: number; +} +export interface AgenticPresets { + list(options?: { type?: 'CATEGORY' }): { presets: Preset[] }; + get(preset: PresetCategory, options: ReadyPresetOptions): { rules: Rule[] }; + get( + preset: PresetCategory, + options?: PresetOptions + ): { rules: PresetRuleTemplate[] }; +} diff --git a/packages/core/src/lib/agentic/public-rule.ts b/packages/core/src/lib/agentic/public-rule.ts new file mode 100644 index 00000000..bf293415 --- /dev/null +++ b/packages/core/src/lib/agentic/public-rule.ts @@ -0,0 +1,420 @@ +/** Public section-6 rule normalization into the deployed v5 wire model. */ +import type { Idl } from '@coral-xyz/anchor'; +import { PublicKey } from '@solana/web3.js'; +import { + getAddress, + hexToBytes, + isAddress, + isHex, + numberToHex, + sha256, + toHex, + type Address, + type Hex, +} from 'viem'; +import type { + Rule, + RuleInput, + InternalRule, + NativeAction, + SolanaRule, + UniversalRule, + Pin, +} from './agentic.types'; +import { + AGENTIC_ERROR_CODE, + AgenticError, + capabilityUnavailable, +} from './errors'; +import { parseSelector } from './codec/selectors'; +import { argumentOffset, encodeArgWord, headSize } from './codec/abi-layout'; +import { UINT256_MAX } from './codec/defaults'; +import { deriveAgwSvmCea, svmKey } from './codec/svm-accounts'; +import type { AgenticRuntime } from './runtime'; +import { CHAIN } from '../constants/enums'; + +export const WALLET = 'agentic:wallet' as const; +const PUBLIC_INPUT = Symbol('AGW public rule'); +/** Mark authored inputs for normalization after the wallet address is fixed. */ +export function publicRules(rules: readonly RuleInput[]): InternalRule[] { + if (!Array.isArray(rules)) throw invalid('rules must be an array'); + return rules.map((rule) => { + if (!rule || typeof rule !== 'object') + throw invalid('rule must be an object'); + return { ...rule, [PUBLIC_INPUT]: true } as unknown as InternalRule; + }); +} +export function isPublicRule(rule: InternalRule): boolean { + return !!rule && !!(rule as unknown as Record)[PUBLIC_INPUT]; +} +function invalid(message: string) { + return new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, message); +} +function rejectFields(obj: object, fields: string[], where: string) { + for (const field of fields) + if (field in obj) + throw invalid( + `${where}.${field} is not supported by the current rule shape` + ); +} +function uint(value: unknown, name: string): bigint { + if (typeof value !== 'bigint' || value < BigInt(0) || value > UINT256_MAX) + throw invalid(`${name} must be a uint256 bigint`); + return value; +} +export function evmPinOffset( + selector: Rule['allowedCalls'][number]['selector'], + arg: number +): number { + if (!Number.isInteger(arg) || arg < 0 || 4 + 32 * arg + 32 > 65535) + throw invalid('pin arg is outside the supported calldata range'); + const parsed = parseSelector(selector); + if (parsed.valueOnly) + throw invalid('value-only calls cannot have argument pins'); + if (!parsed.inputs) return 4 + 32 * arg; + if (parsed.inputs.slice(0, arg).some((p) => headSize(p) !== 32)) + throw capabilityUnavailable( + 'argumentLayout', + 'pins after multi-word tuple/array arguments need an explicit lossless index convention' + ); + return argumentOffset(parsed.inputs, arg, 'pin'); +} +function expectedWord( + selector: Rule['allowedCalls'][number]['selector'], + arg: number, + value: unknown +): Hex { + const parsed = parseSelector(selector); + if (parsed.inputs) + return encodeArgWord(parsed.inputs[arg], value as Hex | bigint, 'pin'); + if (typeof value === 'bigint') + return numberToHex(uint(value, 'pin.expected'), { size: 32 }); + if (typeof value === 'string' && isAddress(value, { strict: false })) + return `0x${value.slice(2).padStart(64, '0')}`.toLowerCase() as Hex; + if (typeof value === 'string' && isHex(value) && value.length === 66) + return value.toLowerCase() as Hex; + throw invalid( + 'a raw EVM selector needs an address, uint256 or exact 32-byte expected word' + ); +} +export async function normalizePublicRule( + input: InternalRule, + wallet: Address, + runtime: AgenticRuntime +): Promise { + const rule = input as unknown as RuleInput; + if ('format' in rule && rule.format === 'decoded') return input; + const r = rule as Rule; + rejectFields( + r, + [ + 'target', + 'selector', + 'actions', + 'pins', + 'amount', + 'maxCalls', + 'maxValuePerCall', + 'maxValueTotal', + 'ref', + 'allowedInstructions', + 'outputTokens', + ], + 'rule' + ); + if ( + !Number.isSafeInteger(r.validUntil) || + r.validUntil <= runtime.nowSeconds() || + r.validUntil >= 2 ** 48 + ) + throw invalid('validUntil must be a future uint48 timestamp'); + if ( + !Array.isArray(r.allowedCalls) || + r.allowedCalls.length < 1 || + r.allowedCalls.length > 32 + ) + throw invalid('allowedCalls must contain 1..32 calls'); + for (const c of r.allowedCalls) { + if (!c || typeof c !== 'object') + throw invalid('allowedCall must be an object'); + rejectFields( + c, + [ + 'beneficiary', + 'beneficiaryOffset', + 'amount', + 'maxCalls', + 'maxValuePerCall', + 'maxValueTotal', + 'validUntil', + ], + 'allowedCall' + ); + uint(c.maxValue ?? BigInt(0), 'allowedCall.maxValue'); + if (c.pins !== undefined && !Array.isArray(c.pins)) + throw invalid('pins must be an array'); + for (const pin of c.pins ?? []) { + if (!pin || typeof pin !== 'object') + throw invalid('pin must be an object'); + rejectFields(pin, ['offset', 'min'], 'pin'); + if ('token' in pin && (!('account' in pin) || pin.expected !== WALLET)) + throw invalid('token is only valid on a WALLET account pin'); + if ('arg' in pin === 'account' in pin) + throw invalid('pin must identify exactly one arg or account'); + if ('expected' in pin === 'max' in pin) + throw invalid('pin must specify exactly one expected or max'); + } + } + if (r.chainNamespace?.startsWith('solana:')) { + const { svmMetadata } = await import('./management/svm-public'); + const gateway = await svmMetadata(runtime).gateway( + r.chainNamespace as `solana:${string}` + ); + if (gateway.chainNamespace !== r.chainNamespace) + throw invalid('gateway registry cluster mismatch'); + return svmRule(r, deriveAgwSvmCea(wallet, gateway.program).address); + } + const native = r.chainNamespace === undefined; + if (r.chainNamespace === runtime.pushChainNamespace) + throw invalid('omit chainNamespace for Push rules'); + if (native && r.allowedCalls.length > 8) + throw capabilityUnavailable( + 'nativeActions', + 'the deployed v5 wallet permits at most eight native actions' + ); + if (native && (r.assets !== undefined || r.maxGasPerCall !== undefined)) + throw invalid('native rules do not carry assets or maxGasPerCall'); + const own = native + ? wallet + : (await runtime.resolveCEA(wallet, r.chainNamespace as CHAIN)).cea; + const nativeActions: NativeAction[] = []; + const calls: UniversalRule['allowedCalls'] = []; + for (const call of r.allowedCalls) { + const pins = call.pins ?? []; + let amount: NativeAction['amount']; + const eq: NonNullable = []; + let beneficiaryOffset: number | undefined; + const occupied = new Set(); + for (const pin of pins) { + if ('account' in pin) throw invalid('account pins only apply to Solana'); + const offset = evmPinOffset(call.selector, pin.arg); + if (occupied.has(offset)) throw invalid('duplicate pin argument'); + occupied.add(offset); + if (!native) { + if ( + !('expected' in pin) || + pin.expected !== WALLET || + beneficiaryOffset !== undefined + ) + throw capabilityUnavailable( + 'evmDestinationPins', + 'general or multiple EVM destination pins require contract change 6.3; v5 supports one WALLET pin per call' + ); + beneficiaryOffset = offset; + } else if ('max' in pin) { + if (amount) + throw capabilityUnavailable( + 'nativeMaxPins', + 'v5 supports one max pin per native call' + ); + amount = { + offset, + maxPerCall: uint(pin.max, 'pin.max'), + maxTotal: UINT256_MAX, + }; + } else { + eq.push({ + offset, + expected: expectedWord( + call.selector, + pin.arg, + pin.expected === WALLET ? own : pin.expected + ), + }); + } + } + if (native) + nativeActions.push({ + target: getAddress(call.target), + selector: call.selector, + pins: eq, + amount, + maxValuePerCall: call.maxValue ?? BigInt(0), + maxValueTotal: UINT256_MAX, + maxCalls: 0, + }); + else + calls.push({ + target: getAddress(call.target), + selector: + call.selector as UniversalRule['allowedCalls'][number]['selector'], + beneficiaryOffset, + maxValue: call.maxValue ?? BigInt(0), + }); + } + if (native) + return { agent: r.agent, validUntil: r.validUntil, actions: nativeActions }; + return { + agent: r.agent, + validUntil: r.validUntil, + chainNamespace: r.chainNamespace as `eip155:${string}`, + assets: (r.assets ?? []).map((a) => ({ + ...a, + token: a.token as Address, + maxTotal: a.maxTotal ?? BigInt(0), + })), + maxGasPerCall: r.maxGasPerCall ?? BigInt(0), + allowedCalls: calls, + }; +} + +function svmType( + text: string +): Idl['instructions'][number]['args'][number]['type'] { + const array = text.match(/^(.+)\[(\d+)\]$/); + if (array) { + const count = Number(array[2]); + if (!Number.isSafeInteger(count) || count < 1 || count > 128) + throw invalid('unsupported SVM fixed array size'); + return { array: [svmType(array[1]), count] }; + } + if ( + [ + 'u8', + 'u16', + 'u32', + 'u64', + 'i8', + 'i16', + 'i32', + 'i64', + 'bool', + 'pubkey', + ].includes(text) + ) + return text as 'u64'; + if (text === 'publicKey') return 'pubkey'; + throw capabilityUnavailable( + 'svmArgumentLayout', + `unsupported fixed-size Solana type ${text}` + ); +} +function svmRule(rule: Rule, cea: Hex): SolanaRule { + return { + agent: rule.agent, + validUntil: rule.validUntil, + chainNamespace: rule.chainNamespace as `solana:${string}`, + outputTokens: [ + ...new Set( + rule.allowedCalls.flatMap((c) => + (c.pins ?? []).flatMap((p) => + 'account' in p && 'token' in p && p.expected === WALLET && p.token + ? [typeof p.token === 'string' ? p.token : p.token.address] + : [] + ) + ) + ), + ], + assets: (rule.assets ?? []).map((asset) => ({ + ...asset, + maxTotal: asset.maxTotal ?? BigInt(0), + })), + maxGasPerCall: rule.maxGasPerCall ?? BigInt(0), + allowedInstructions: rule.allowedCalls.map((call) => { + if ((call.maxValue ?? BigInt(0)) !== BigInt(0)) + throw capabilityUnavailable( + 'svmCallValue', + 'native Solana instruction value is governed by its transfer/pin, not an EVM call value' + ); + const full = String(call.selector).match( + /^([A-Za-z_][A-Za-z0-9_]*)\((.*)\)$/ + ); + const raw = /^0x[0-9a-fA-F]{16}$/.test(call.selector); + if (!full && !raw) + throw invalid( + 'Solana selector needs a fixed-width signature or eight-byte discriminator' + ); + const types = + full && full[2] ? full[2].split(',').map((s) => svmType(s.trim())) : []; + const name = full?.[1] ?? 'raw'; + const discriminator = raw + ? hexToBytes(call.selector as Hex) + : hexToBytes( + sha256( + toHex( + `global:${name + .replace(/([a-z0-9])([A-Z])/g, '$1_$2') + .toLowerCase()}` + ) + ) + ).slice(0, 8); + const pins = call.pins ?? []; + const accounts = pins.filter( + (p): p is Extract => 'account' in p + ); + if ( + accounts.some( + (p) => + !Number.isInteger(p.account) || p.account < 0 || p.account >= 64 + ) + ) + throw invalid('Solana account position must be 0..63'); + const accountCount = Math.max(0, ...accounts.map((p) => p.account + 1)); + const idl: Idl = { + address: new PublicKey(hexToBytes(svmKey(call.target))).toBase58(), + metadata: { name: 'rule_layout', version: '1', spec: '0.1.0' }, + instructions: [ + { + name, + discriminator: Array.from(discriminator), + accounts: Array.from({ length: accountCount }, (_, i) => ({ + name: `account${i}`, + })), + args: types.map((type, i) => ({ name: `arg${i}`, type })), + }, + ], + }; + return { + maxAccounts: 0, + program: call.target, + instruction: { idl, name }, + accounts: accounts.map((p) => ({ + name: `account${p.account}`, + expected: + p.expected === WALLET + ? p.token + ? { + kind: 'walletATA' as const, + token: + typeof p.token === 'string' ? p.token : p.token.address, + } + : { kind: 'walletCEA' as const } + : { kind: 'address' as const, address: p.expected }, + })), + fields: pins + .filter((p) => 'arg' in p) + .map((p) => { + const arg = (p as { arg: number }).arg; + if (!Number.isInteger(arg) || arg < 0 || arg >= types.length) + throw capabilityUnavailable( + 'svmArgumentLayout', + 'argument pins need a signature with the indexed argument type; use decoded raw constraints for stored rules' + ); + if ('max' in p) + return { name: `arg${arg}`, max: uint(p.max, 'pin.max') }; + const rawExpected = (p as { expected: string | bigint }).expected; + const eq = rawExpected === WALLET ? cea : rawExpected; + return { + name: `arg${arg}`, + equals: + typeof eq === 'bigint' + ? eq + : /^0x/.test(eq) + ? (eq as Hex) + : svmKey(eq), + }; + }), + }; + }), + }; +} diff --git a/packages/core/src/lib/agentic/reads/checkpoints.ts b/packages/core/src/lib/agentic/reads/checkpoints.ts index 71381920..93a3979c 100644 --- a/packages/core/src/lib/agentic/reads/checkpoints.ts +++ b/packages/core/src/lib/agentic/reads/checkpoints.ts @@ -1,4 +1,4 @@ -import type { Address } from 'viem'; +import type { Address, Log } from 'viem'; import { AgenticCapability, requireCapability } from '../capabilities'; import type { AgenticGeneration } from '../deployments'; import type { ChainReader } from '../contracts/reader'; @@ -25,15 +25,37 @@ export async function readCheckpoints( for (let attempt = 0; attempt < MAX_ATTEMPTS; attempt++) { const snap = await Snapshot.at(reader); const count = BigInt( - await snap.read(wallet, gen.contracts.abis.wallet, 'checkpointCount') - ); - const from = sinceBlock !== undefined && sinceBlock > gen.startBlock ? sinceBlock : gen.startBlock; - const logs = await scanLogs( - reader, - { address: wallet, event: gen.contracts.events.checkpointed }, - from, - snap.blockNumber + await snap.read( + wallet, + gen.contracts.abis.wallet, + 'checkpointCount' + ) ); + const from = + sinceBlock !== undefined && sinceBlock > gen.startBlock + ? sinceBlock + : gen.startBlock; + const filter = { + address: wallet, + event: gen.contracts.events.checkpointed, + }; + let logs: Log[]; + try { + logs = await scanLogs(reader, filter, from, snap.blockNumber); + } catch (cause) { + const retained = lowestRetainedHeight(cause); + // A fresh wallet may have its entire history after the RPC retention + // floor. Never treat truncation as success: the FULL sequence/count + // validation below must still prove every checkpoint is present. + if ( + sinceBlock !== undefined || + retained === undefined || + retained <= from || + retained > snap.blockNumber + ) + throw cause; + logs = await scanLogs(reader, filter, retained, snap.blockNumber); + } const decoded = gen.contracts .parseCheckpointed(logs, wallet) .sort((a, b) => @@ -42,10 +64,14 @@ export async function readCheckpoints( ? -1 : 1 : a.transactionIndex !== b.transactionIndex - ? a.transactionIndex - b.transactionIndex - : a.logIndex - b.logIndex + ? a.transactionIndex - b.transactionIndex + : a.logIndex - b.logIndex ); - const problem = validateSequence(decoded.map((c) => c.seq), count, sinceBlock === undefined || from === gen.startBlock); + const problem = validateSequence( + decoded.map((c) => c.seq), + count, + sinceBlock === undefined || from === gen.startBlock + ); if (!problem) { return { count, @@ -59,27 +85,65 @@ export async function readCheckpoints( })), }; } - lastError = new AgenticError(AGENTIC_ERROR_CODE.INCONSISTENT_READ, problem, { - details: { wallet, count, blockNumber: snap.blockNumber }, - }); + lastError = new AgenticError( + AGENTIC_ERROR_CODE.INCONSISTENT_READ, + problem, + { + details: { wallet, count, blockNumber: snap.blockNumber }, + } + ); } throw lastError as AgenticError; } /** Sequence must be contiguous, end at `count`, and start at 1 for a full scan. */ -export function validateSequence(seqs: number[], count: bigint, fullRange: boolean): string | null { +export function validateSequence( + seqs: number[], + count: bigint, + fullRange: boolean +): string | null { for (let i = 1; i < seqs.length; i++) { - if (seqs[i] !== seqs[i - 1] + 1) return `checkpoint sequence gap between ${seqs[i - 1]} and ${seqs[i]}`; + if (seqs[i] !== seqs[i - 1] + 1) + return `checkpoint sequence gap between ${seqs[i - 1]} and ${seqs[i]}`; } if (fullRange) { if (BigInt(seqs.length) !== count) { return `found ${seqs.length} Checkpointed events but checkpointCount() is ${count}`; } - if (seqs.length > 0 && seqs[0] !== 1) return `first checkpoint seq is ${seqs[0]}, expected 1`; + if (seqs.length > 0 && seqs[0] !== 1) + return `first checkpoint seq is ${seqs[0]}, expected 1`; return null; } if (seqs.length > 0 && BigInt(seqs[seqs.length - 1]) !== count) { - return `last checkpoint seq ${seqs[seqs.length - 1]} does not match checkpointCount() ${count}`; + return `last checkpoint seq ${ + seqs[seqs.length - 1] + } does not match checkpointCount() ${count}`; } return null; } + +/** Recognize Donut/CometBFT's explicit pruning error, not arbitrary RPC failures. */ +function lowestRetainedHeight(error: unknown): bigint | undefined { + const visited = new Set(); + for ( + let depth = 0; + depth < 8 && error && typeof error === 'object' && !visited.has(error); + depth++ + ) { + visited.add(error); + const value = error as { + message?: unknown; + details?: unknown; + cause?: unknown; + }; + for (const text of [value.message, value.details]) { + if (typeof text !== 'string') continue; + const match = /height \d+ is not available, lowest height is (\d+)/.exec( + text + ); + if (match) return BigInt(match[1]); + } + error = value.cause; + } + return undefined; +} diff --git a/packages/core/src/lib/agentic/reads/rules.ts b/packages/core/src/lib/agentic/reads/rules.ts index 0c4dcc85..44298144 100644 --- a/packages/core/src/lib/agentic/reads/rules.ts +++ b/packages/core/src/lib/agentic/reads/rules.ts @@ -10,8 +10,10 @@ import type { UniversalConfigRead, } from '../contracts/v5'; import { configId } from '../codec/ids'; -import { nativeTermsToRule } from '../codec/native'; -import { universalTermsToRule } from '../codec/universal'; +import { nativeActionTermsToRule } from '../codec/native'; +import { UINT256_MAX } from '../codec/defaults'; +import { WALLET } from '../public-rule'; +import { capabilityUnavailable } from '../errors'; import { readOriginToken } from '../contracts/prc20-metadata'; import { chainHash } from '../codec/rules'; import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; @@ -198,6 +200,13 @@ export async function decodeActiveRule( agent: rule.agent, chainNamespace: stored.chainNamespace, validUntil: Number(cfg.validUntil), + spent: { + kind: 'universal', + assets: assets.map((a, i) => ({ + token: a.token, + spent: cfg.assets[i].spent, + })), + }, rule: { format: 'decoded', agent: rule.agent, @@ -257,12 +266,32 @@ export async function decodeActiveRule( chainNamespace: chain, agent: rule.agent, validUntil: Number(cfg.validUntil), - rule: universalTermsToRule( - cfg, - rule.agent, - chain as `eip155:${string}`, - tokens - ), + spent: { + kind: 'universal', + assets: tokens.map((token, i) => ({ + token, + spent: cfg.assets[i].spent, + })), + }, + rule: { + agent: rule.agent, + chainNamespace: chain as `eip155:${string}`, + validUntil: Number(cfg.validUntil), + maxGasPerCall: cfg.maxGasPerCall, + assets: cfg.assets.map((a, i) => ({ + token: tokens[i], + maxPerCall: a.maxPerCall, + maxTotal: a.maxTotal, + })), + allowedCalls: cfg.allowedCalls.map((c) => ({ + target: c.target, + selector: c.selector, + maxValue: c.maxValue, + pins: c.hasBeneficiary + ? [{ arg: storedArg(c.beneficiaryOffset), expected: WALLET }] + : [], + })), + }, }; } if (rule.mode !== MODE_NATIVE) { @@ -271,24 +300,64 @@ export async function decodeActiveRule( `rule ${rule.rulesId} has unknown mode ${rule.mode}` ); } - if (rule.actionIds.length !== 1) { - throw new AgenticError( - AGENTIC_ERROR_CODE.RULE_READ_FAILED, - `rule ${rule.rulesId} has ${rule.actionIds.length} native actions; the public NativeRule is single-action (A02)` - ); - } - const cfg = await snap.read( - gen.addresses.rulesPolicy, - gen.contracts.abis.policy, - 'getNativeConfig', - [configId(wallet, rule.rulesId, rule.actionIds[0]), wallet] + // One stored config per action, read at the same block, in engine order. + const configs = await Promise.all( + rule.actionIds.map((action) => + snap.read( + gen.addresses.rulesPolicy, + gen.contracts.abis.policy, + 'getNativeConfig', + [configId(wallet, rule.rulesId, action), wallet] + ) + ) ); - if (!cfg.initialized) { + if (configs.some((c) => !c.initialized)) { throw new AgenticError( AGENTIC_ERROR_CODE.INCONSISTENT_READ, `native config for ${rule.rulesId} is not initialized` ); } + const decoded = nativeActionTermsToRule(configs, rule.agent); + if ( + configs.some( + (c) => + c.maxValueTotal !== UINT256_MAX || + Number(c.maxCalls) !== 0 || + (c.amount.enabled && c.amount.maxTotal !== UINT256_MAX) || + Number(c.validUntil) !== decoded.validUntil + ) + ) { + throw capabilityUnavailable( + 'nativeRuleRead', + 'stored lifetime limits or differing action expiries cannot be represented by section-6 rules without losing constraints' + ); + } + const allowedCalls = configs.map((c) => ({ + target: getAddress(c.target), + selector: + c.selector === '0xffffffff' ? ('value-only' as const) : c.selector, + maxValue: c.maxValuePerCall, + pins: [ + ...c.pins.map((p) => ({ + arg: storedArg(p.offset), + expected: + p.expected.toLowerCase() === + `0x${wallet.slice(2).toLowerCase().padStart(64, '0')}` + ? WALLET + : p.expected, + })), + ...(c.amount.enabled + ? [{ arg: storedArg(c.amount.offset), max: c.amount.maxPerCall }] + : []), + ], + })); + const counters = configs.map((c, i) => ({ + target: allowedCalls[i].target, + selector: allowedCalls[i].selector, + valueSpent: c.valueSpent, + amountSpent: c.amountSpent, + callsUsed: Number(c.callsUsed), + })); if (rule.agent === getAddress(`0x${'00'.repeat(20)}`)) { throw new AgenticError( AGENTIC_ERROR_CODE.INCONSISTENT_READ, @@ -300,8 +369,17 @@ export async function decodeActiveRule( enabled: true, chainNamespace: pushChainNamespace, agent: rule.agent, - validUntil: Number(cfg.validUntil), - rule: nativeTermsToRule(cfg, rule.agent), + validUntil: decoded.validUntil, + rule: { agent: rule.agent, validUntil: decoded.validUntil, allowedCalls }, + spent: + counters.length === 1 + ? { + kind: 'native', + valueSpent: counters[0].valueSpent, + amountSpent: counters[0].amountSpent, + callsUsed: counters[0].callsUsed, + } + : { kind: 'native', actions: counters }, }; } @@ -396,3 +474,13 @@ export async function getRule( `rule ${rulesId} is not enabled on ${wallet} (unknown or revoked; v1 has no rule history)` ); } + +/** With a raw selector, arg denotes its ABI head-word position. */ +function storedArg(offset: number): number { + if (offset < 4 || (offset - 4) % 32 !== 0) + throw capabilityUnavailable( + 'argumentLayout', + 'stored pin is not aligned to an ABI argument word' + ); + return (offset - 4) / 32; +} diff --git a/packages/core/src/lib/agentic/utils.ts b/packages/core/src/lib/agentic/utils.ts index 2c863bd2..e2dbcfd9 100644 --- a/packages/core/src/lib/agentic/utils.ts +++ b/packages/core/src/lib/agentic/utils.ts @@ -12,7 +12,7 @@ import { deriveWallet as deriveWalletRaw, rulesId as rulesIdRaw, } from './codec/ids'; -import { decodeNativeTerms, nativeTermsToRule } from './codec/native'; +import { decodeNativeTerms, nativeActionTermsToRule } from './codec/native'; import { prepareRules } from './codec/rules'; import { parseSelector } from './codec/selectors'; import { decodeEnvelope, decodeSession, encodeSession } from './codec/session'; @@ -26,7 +26,7 @@ import { decodeUniversalTerms } from './codec/universal-terms'; import { universalTermsToRule } from './codec/universal'; import type { AgenticHex, - Rule, + InternalRule, Selector, DecodedSolanaRule, } from './agentic.types'; @@ -105,7 +105,10 @@ export const internalAgenticUtils = { * Encode rules into the grant `Session` bytes, one per rule, in order. * EVM universal rules require wallet/token resolution in the internal context. */ - encodeRules(rules: readonly Rule[], ctx: RulesEncodeContext): AgenticHex[] { + encodeRules( + rules: readonly InternalRule[], + ctx: RulesEncodeContext + ): AgenticHex[] { return prepareRules(rules, { owner: ctx.owner ? getAddress(ctx.owner) : undefined, pushChainNamespace: nativeNamespace(ctx), @@ -122,7 +125,7 @@ export const internalAgenticUtils = { decodeRules( bytes: Hex, ctx: { network?: PUSH_NETWORK; pushChainNamespace?: string } = {} - ): Rule | DecodedSolanaRule { + ): InternalRule | DecodedSolanaRule { if (!isHex(bytes)) throw new AgenticError( AGENTIC_ERROR_CODE.INVALID_RULE, @@ -130,12 +133,12 @@ export const internalAgenticUtils = { ); const session = decodeSession(bytes); if ( - session.actions.length !== 1 || - session.actions[0].actionPolicies.length !== 1 + session.actions.length === 0 || + session.actions.some((a) => a.actionPolicies.length !== 1) ) { throw new AgenticError( AGENTIC_ERROR_CODE.RULE_READ_FAILED, - 'only single-action rules (one URP policy) are representable as a public Rule' + 'every action needs exactly one URP policy to be representable as a public InternalRule' ); } const agent = getAddress( @@ -144,6 +147,15 @@ export const internalAgenticUtils = { const { chainNamespace, body } = decodeEnvelope( session.actions[0].actionPolicies[0].initData ); + if ( + chainNamespace !== nativeNamespace(ctx) && + session.actions.length !== 1 + ) { + throw new AgenticError( + AGENTIC_ERROR_CODE.RULE_READ_FAILED, + 'only native rules carry more than one action' + ); + } if (chainNamespace !== nativeNamespace(ctx)) { if (chainNamespace.startsWith('solana:')) { const terms = decodeSvmTerms(body); @@ -237,7 +249,21 @@ export const internalAgenticUtils = { tokens ); } - return nativeTermsToRule(decodeNativeTerms(body), agent); + // Native: one stored terms body per action, all on the native chain. + const terms = session.actions.map((a, i) => { + const env = + i === 0 + ? { chainNamespace, body } + : decodeEnvelope(a.actionPolicies[0].initData); + if (env.chainNamespace !== chainNamespace) { + throw new AgenticError( + AGENTIC_ERROR_CODE.RULE_READ_FAILED, + `action ${i} names chain ${env.chainNamespace}, not ${chainNamespace}` + ); + } + return decodeNativeTerms(env.body); + }); + return nativeActionTermsToRule(terms, agent); }, }; diff --git a/packages/core/src/lib/agentic/wallet.ts b/packages/core/src/lib/agentic/wallet.ts index ddecd3a6..c891d4e5 100644 --- a/packages/core/src/lib/agentic/wallet.ts +++ b/packages/core/src/lib/agentic/wallet.ts @@ -1,3 +1,4 @@ +import { publicRules } from './public-rule'; import { getAddress, type Address } from 'viem'; import { AgenticCapability, requireCapability } from './capabilities'; import { resolveWalletGeneration, type AgenticGeneration } from './deployments'; @@ -55,12 +56,36 @@ export class AgenticWalletHandle implements AgenticWallet { this.runtime, await this.gen(), this.address, - rules, + publicRules(rules), opts?.progressHook ), - update: async (params) => - updateRules(this.runtime, await this.gen(), this.address, params), - revoke: (async ( + update: async (params) => { + if ( + !params || + !Array.isArray(params.rules) || + params.rules.length === 0 || + params.rules.some( + (p) => + !p || + typeof p.rulesId !== 'string' || + !/^0x[0-9a-fA-F]{64}$/.test(p.rulesId) + ) + ) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'rules.update needs { rulesId, rule } pairs with 32-byte rule IDs' + ); + } + const rules = params.rules.map((p) => ({ + ...p, + rule: publicRules([p.rule])[0], + })); + return updateRules(this.runtime, await this.gen(), this.address, { + ...params, + rules, + }); + }, + delete: (async ( target: | AgenticHex[] | { all: true; progressHook?: AgenticProgressHook }, @@ -75,7 +100,7 @@ export class AgenticWalletHandle implements AgenticWallet { target, opts?.progressHook ); - }) as AgenticWallet['rules']['revoke'], + }) as AgenticWallet['rules']['delete'], }; } diff --git a/packages/core/src/lib/index.ts b/packages/core/src/lib/index.ts index 940cf4c4..1767a522 100644 --- a/packages/core/src/lib/index.ts +++ b/packages/core/src/lib/index.ts @@ -71,7 +71,11 @@ export type { export { parseUEAVersion } from './orchestrator/orchestrator.types'; // Route detection utilities -export { TransactionRoute, detectRoute, isChainTarget } from './orchestrator/route-detector'; +export { + TransactionRoute, + detectRoute, + isChainTarget, +} from './orchestrator/route-detector'; // Outbound gas cap helpers export { @@ -137,7 +141,17 @@ export type { ReadResponseTuple, BatchReadResponse, } from './read-state/read-state.types'; -export type { ReadOptions, ReadPrepareOptions, ReadQueryOptions, ReadCallbackOptions, ReadValue, ValidateReadCall, ReadWeb2Options, ReadTrackOptions, ReadExecuteOptions } from './read-state/read-params'; +export type { + ReadOptions, + ReadPrepareOptions, + ReadQueryOptions, + ReadCallbackOptions, + ReadValue, + ValidateReadCall, + ReadWeb2Options, + ReadTrackOptions, + ReadExecuteOptions, +} from './read-state/read-params'; export { UNIVERSAL_READ_STATUS, READ_STATUS, @@ -195,7 +209,6 @@ export type { AgenticErrorCode, AgenticHex, AgenticNamespace, - AgenticNetworkConstants, AgenticProgressHook, AgenticTxMetadata, AgenticWallet, @@ -206,18 +219,26 @@ export type { CreateOptions, CreateResult, ForeignChainNamespace, - NativeRule, - SolanaRule, DecodedSolanaRule, - SvmInstructionRule, - SvmAccountRef, - SvmFieldConstraint, Rule, + RuleInput, + Pin, + Spent, + WalletMarker, RulesRecord, Selector, - UniversalRule, WalletInfo, WalletSummary, } from './agentic'; export { PushChain }; + +export type { + Preset, + PresetCategory, + PresetAsset, + PresetOptions, + ReadyPresetOptions, + PresetRuleTemplate, + AgenticPresets, +} from './agentic'; diff --git a/packages/core/src/lib/utils.ts b/packages/core/src/lib/utils.ts index 3fa4d979..ca82e7ba 100644 --- a/packages/core/src/lib/utils.ts +++ b/packages/core/src/lib/utils.ts @@ -1,3 +1,4 @@ +import { agenticPresets } from './agentic/presets'; import { convertOriginToExecutor, fromChainAgnostic, @@ -31,7 +32,6 @@ import { import { PC20WrapperNotRegisteredError } from './orchestrator/internals/pc20/errors'; import { getPushChainForNetwork } from './orchestrator/internals/helpers'; import { Buffer } from 'buffer'; -import { agenticUtils } from './agentic/utils'; import type { Idl } from '@coral-xyz/anchor'; import { encodeAnchorIxData, @@ -872,12 +872,8 @@ export class Utils { }, }; - /** - * Agentic wallet (AGW) pure helpers: rulesId, actionId, configId, - * deriveWallet, encodeRules, decodeRules, compileCard. Generation context is - * explicit (provisional signatures, A04); no RPC is performed. - */ - static agentic = agenticUtils; + /** Pure preset discovery/templates; internal encoders and identifiers stay private. */ + static readonly agentic = Object.freeze({ presets: agenticPresets }); /** * Internal: resolves a CHAIN enum from either a CHAIN value or a PushChain client instance. From 31db25bb8f88699ae6daed556704135188b7558a Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Mon, 12 Oct 2026 23:10:23 +0530 Subject: [PATCH 34/68] docs(agw): record October spec feedback and preset validation --- plan/agw/README.md | 5 + plan/agw/SOURCES.md | 4 +- plan/agw/gaps.md | 12 + plan/agw/implementation-status.md | 21 +- plan/agw/latest-refresh.json | 148 +- plan/agw/notion/1-agw-contract-changes.md | 142 +- plan/agw/notion/5-sdk-agw.md | 639 +- plan/agw/pending-items.md | 20 + plan/agw/questions-harsh.md | 26 +- plan/agw/questions-zaryab.md | 22 +- .../README.md | 43 + .../api-comparison.json | 11644 ++++++++++++++++ .../credential-scan.json | 4 + .../live-evidence.jsonl | 16 + .../validation.json | 26 + .../contracts-export.zip | Bin 0 -> 14990 bytes .../contracts-latest.md | 502 + .../contracts-previous.md | 362 + .../contracts.diff | 147 + .../download-manifest.json | 18 + .../previous-latest-refresh.json | 135 + .../previous-questions-harsh.md | 25 + .../previous-questions-zaryab.md | 12 + .../sdk-export.zip | Bin 0 -> 28811 bytes .../sdk-latest.md | 1352 ++ .../sdk-previous.md | 731 + .../section6-feedback-2026-10-12/sdk.diff | 695 + .../section7-presets-2026-10-12/api.json | 11558 +++++++++++++++ .../section7-presets-2026-10-12/commands.md | 12 + .../section7-presets-2026-10-12/docs.log | 1 + .../section7-presets-2026-10-12/full-unit.log | 176 + .../local-contract.log | 19 + .../section7-presets-2026-10-12/package.log | 1 + .../preset-unit.log | 8 + .../timing-test-rerun.log | 17 + plan/agw/section6-action-items.md | 53 + plan/agw/section7-presets.md | 30 + plan/agw/source-manifest.json | 36 +- 38 files changed, 28479 insertions(+), 183 deletions(-) create mode 100644 plan/agw/pending-items.md create mode 100644 plan/agw/research/native-multi-action-e2e-2026-10-12/README.md create mode 100644 plan/agw/research/native-multi-action-e2e-2026-10-12/api-comparison.json create mode 100644 plan/agw/research/native-multi-action-e2e-2026-10-12/credential-scan.json create mode 100644 plan/agw/research/native-multi-action-e2e-2026-10-12/live-evidence.jsonl create mode 100644 plan/agw/research/native-multi-action-e2e-2026-10-12/validation.json create mode 100644 plan/agw/research/section6-feedback-2026-10-12/contracts-export.zip create mode 100644 plan/agw/research/section6-feedback-2026-10-12/contracts-latest.md create mode 100644 plan/agw/research/section6-feedback-2026-10-12/contracts-previous.md create mode 100644 plan/agw/research/section6-feedback-2026-10-12/contracts.diff create mode 100644 plan/agw/research/section6-feedback-2026-10-12/download-manifest.json create mode 100644 plan/agw/research/section6-feedback-2026-10-12/previous-latest-refresh.json create mode 100644 plan/agw/research/section6-feedback-2026-10-12/previous-questions-harsh.md create mode 100644 plan/agw/research/section6-feedback-2026-10-12/previous-questions-zaryab.md create mode 100644 plan/agw/research/section6-feedback-2026-10-12/sdk-export.zip create mode 100644 plan/agw/research/section6-feedback-2026-10-12/sdk-latest.md create mode 100644 plan/agw/research/section6-feedback-2026-10-12/sdk-previous.md create mode 100644 plan/agw/research/section6-feedback-2026-10-12/sdk.diff create mode 100644 plan/agw/research/section7-presets-2026-10-12/api.json create mode 100644 plan/agw/research/section7-presets-2026-10-12/commands.md create mode 100644 plan/agw/research/section7-presets-2026-10-12/docs.log create mode 100644 plan/agw/research/section7-presets-2026-10-12/full-unit.log create mode 100644 plan/agw/research/section7-presets-2026-10-12/local-contract.log create mode 100644 plan/agw/research/section7-presets-2026-10-12/package.log create mode 100644 plan/agw/research/section7-presets-2026-10-12/preset-unit.log create mode 100644 plan/agw/research/section7-presets-2026-10-12/timing-test-rerun.log create mode 100644 plan/agw/section6-action-items.md create mode 100644 plan/agw/section7-presets.md diff --git a/plan/agw/README.md b/plan/agw/README.md index b03aa8d3..5b696983 100644 --- a/plan/agw/README.md +++ b/plan/agw/README.md @@ -1,5 +1,7 @@ # AGW SDK planning +**Current — October 12:** [downloaded sections 6/7, changes and deployment dependencies](section6-action-items.md). SDK-only migration and the [preset framework](section7-presets.md) are implemented locally; [open items](pending-items.md) supersede older decision summaries below. Notion pages 1/5 were refreshed; other ten snapshots retain October 7 timestamps. The new contract feedback is not deployed. + This package contains planning, source snapshots and review evidence for `feat/agw-sdk-v4`. Current runtime uses Donut v5 source `2e61e13`; legacy runtime adapters have been removed. **October 7:** product decisions are settled. Public named-IDL Solana lifecycle/sends/reads/replay are implemented, rule `ref` is removed, zero native PC defaults are confirmed, and native/EVM raw-offset authoring is approved. Seven additional E2Es passed on Donut/devnet, bringing the opt-in AGW group to 46 scenarios at that checkpoint; the subsequent fixes extend it to 48 scenarios with selected-run live coverage. The final local/unit/build results are in [implementation status](implementation-status.md). @@ -25,6 +27,7 @@ Latest source check: [full October 7 Notion/contract refresh](research/source-re | [Implementation review handoff](implementation-review-handoff.md) | Revisions, changed modules, commands and counts, real-vs-mock evidence, review hotspots | | [Interactive tutorial](agw-tutorial.html) | Account, rule, funding and execution diagrams; open in a browser | | [Integrator obligations](contract-integrator-obligations.md) | Contract-delegated SDK/product requirements | +| [Pending items](pending-items.md) | Open items with owners, including the multi-action native rule decision | | [External blockers](external-blockers.md) | Remaining defaults/type clarification and contract/deployment dependencies | | [Questions for Harsh](questions-harsh.md) | Product decisions and recommendations | | [Questions for Zaryab](questions-zaryab.md) | Ref/label v1 scope and joint Solana review; fixture request closed | @@ -43,3 +46,5 @@ Older planning revisions, duplicated exports, superseded validation runs and the Before sharing questions, refresh remote refs and Notion again, record exact revisions and remove questions answered by newer evidence. No team messages or contract deployments have been sent by this work. Authorized, bounded testnet transactions are recorded in the live acceptance evidence. Latest coverage: [five added v5 E2Es and metadata fix](research/extended-v5-e2e-2026-10-07/README.md). All five new scenarios have live passing evidence. The AGW group registers 58 cases; default `all` is unchanged. Fresh Sepolia CEA delivery currently uses an explicit destination-gas budget in tests/examples; the upstream default remains a follow-up. + +**October 12 native multi-action acceptance:** 10/10 new live cases passed; 68 AGW cases are registered. Full units: 2,034 passed; actual-contract harness: 97 passed. Input validation and checkpoint documentation fixes are local on `feat/agw-sdk-v4`, following the user’s v5 merge. [Evidence](research/native-multi-action-e2e-2026-10-12/README.md) · [Remaining items](pending-items.md). No commit or push was made for this work. diff --git a/plan/agw/SOURCES.md b/plan/agw/SOURCES.md index aa9eb455..55c88bc7 100644 --- a/plan/agw/SOURCES.md +++ b/plan/agw/SOURCES.md @@ -1,6 +1,8 @@ # AGW source links and refresh procedure -**Latest refresh — October 7, 2026:** all 12 Notion pages downloaded/imported (1 changed, 11 unchanged), current discussions inspected where exposed, and all three contract repositories fetched. AGW/gateway code is unchanged; core marketplace head `9479aef` adds docs only over `cb69e0b`. Donut code/wiring and Solana program fingerprints match prior probes. [Refresh report, evidence and SDK alignment findings](research/source-refresh-2026-10-07/README.md). +**Latest focused refresh — October 12, 2026:** pages 1 and 5 re-exported with section 6 feedback and SDK section 7 presets. [Change list and deployment boundary](section6-action-items.md). Other ten pages retain their October 7 snapshots; this was not a contract deployment verification. + +**Latest full refresh — October 7, 2026:** all 12 Notion pages downloaded/imported (1 changed, 11 unchanged), current discussions inspected where exposed, and all three contract repositories fetched. AGW/gateway code is unchanged; core marketplace head `9479aef` adds docs only over `cb69e0b`. Donut code/wiring and Solana program fingerprints match prior probes. [Refresh report, evidence and SDK alignment findings](research/source-refresh-2026-10-07/README.md). The dated entries below preserve earlier observations and decisions; use the October 7 report and current decision documents for present status. diff --git a/plan/agw/gaps.md b/plan/agw/gaps.md index 0b64428d..e94117b9 100644 --- a/plan/agw/gaps.md +++ b/plan/agw/gaps.md @@ -1,5 +1,17 @@ # AGW contract and SDK gap register +**Current override — October 12:** new sections 6/7 supersede the October 7 decisions below. [Feedback work list](section6-action-items.md); [only remaining items](pending-items.md). Unified allowedCalls, zero caps, spend reads, numeric Solana authoring/raw decoded updates, duplicate creation checks and direct label calls are implemented locally. Live acceptance of this changed API is in progress. + +| ID | Status | Current dependency | +| --- | --- | --- | +| G31 | Contract deployment pending | Exact per-outbound approval on both doors (§6.1); retain allowance guard until deployed | +| G32 | Contract deployment pending | Atomic createWallet and initial grants (§6.2); retain receipt-based partial recovery/index protection | +| G33 | Contract deployment pending | General EVM destination EQ/MAX pins (§6.3); one WALLET pin remains supported | +| G34 | Spec/policy mismatch | Public ceiling 32 calls versus deployed native ceiling 8 | +| G35 | Product/data open | Preset app catalog, missing caps and compound argument indexing (§7) | + +Native multi-action spend entries and Solana decoded raw form were approved by the user on October 12. Default first-use EVM gas is now an SDK change, not a core/gateway blocker. G07 revert credit remains downstream. The following dated register is historical where it conflicts with this override. + **October 7 alignment:** all product choices are settled. Named-IDL Solana integration and removal of rule `ref` are implemented; raw-offset inputs remain supported. Editable labels are delivered and implemented against v5. Contract validation already exists; retain the SDK ambiguity guard. [Current delivery items](questions-zaryab.md). Updated October 7, 2026 following the clarified contract-enforcement decision, the [v4 deployment/owner-guide review](research/deployment-review-2026-10-06/README.md), [Harsh’s replies](product-decisions-2026-10-04.md), v4 implementation on feat/agw-sdk-v4, and [live Notion comments](research/notion-comments-2026-10-05.md). This register distinguishes unresolved dependencies, implemented SDK work, deferred scope and historical corrections. G01–G30 are tracking IDs, not a count of open defects. diff --git a/plan/agw/implementation-status.md b/plan/agw/implementation-status.md index 2a3b9519..2307225d 100644 --- a/plan/agw/implementation-status.md +++ b/plan/agw/implementation-status.md @@ -1,5 +1,18 @@ # AGW SDK implementation status +**Current — October 12 sections 6/7:** SDK-only feedback and the preset framework are implemented locally. [Section 6 work list](section6-action-items.md) · [Preset scope/decisions](section7-presets.md) · [Open items](pending-items.md). + +- Full unit run: **2,075 passed, 0 failed, 12 skipped**. An earlier 100ms timing-test failure passed both on retry and in this final full run. +- Section-6 real-contract coverage: all 97 cases pass across the suite and focused correction run. Presets add one fixture integration; its complete 11-case multi-asset suite passes. +- Live section-6 coverage: **65/68 passed initially, then all 3 corrected cases passed**. All 68 cases have passing coverage; this is not one clean full invocation. No app-preset live claim is made with an empty approved catalog. +- Build, library/spec/local typechecks, guide examples, compiled package imports/declarations and source-versus-built API comparison pass. New preset code has no lint errors. +- Preset categories are enumerable; production chains remain empty pending catalog approval. Missing preset caps default to zero per the user. Templates omit identity/expiry until supplied. No encoder/ID utilities were re-exposed. +- SDK changes are grouped in commit `6bd8ad50`; planning is tracked separately on v4 and excluded from the v5 sync. New contract feedback remains undeployed; automatic approvals, atomic factory create and general EVM pins remain gated. + +The dated entries below describe earlier checkpoints and are superseded where they conflict with the current summary. + +**October 12:** ten native multi-action live E2Es passed in one Donut invocation; malformed-action/required-expiry guards and the N + 4 checkpoint description are fixed. [Acceptance and evidence](research/native-multi-action-e2e-2026-10-12/README.md). Work remains local on `feat/agw-sdk-v4`; public multi-action shape still awaits product sign-off. + **Latest v5 integration:** the new factory, source/artifacts, stored label reads and owner-only rename/reset are integrated. [V5 validation](research/v5-implementation-2026-10-07/README.md) distinguishes current tests from earlier v4 evidence. **Fresh alignment review:** [October 7 source refresh](research/source-refresh-2026-10-07/README.md) confirms stable deployed code and identified SDK follow-ups G27 (policy-preflight/error parity) and G28 (Solana owner funds-only support). Both are now fixed; [follow-up validation](research/sdk-alignment-fixes-2026-10-07/README.md) records contract-derived errors and actual SOL transfer/replay. @@ -10,12 +23,12 @@ | Level | Current evidence | | --- | --- | -| Unit | 2,014 passed, 0 failed; 12 skipped | -| Actual contracts | 90 passed, 0 failed across 12 Anvil suites | +| Unit | 2,034 passed, 0 failed; 12 skipped (includes 20 multi-action native tests) | +| Actual contracts | 97 passed, 0 failed across 13 Anvil suites (includes 7 multi-action native tests) | | New funded tests | Expanded v5 labels, native/lifecycle, EVM, SOL and SPL cases pass across selected runs; [new report](research/extended-v5-e2e-2026-10-07/README.md) records individual runs and the gas-default issue | | Build/typechecks | Build and lib/spec/local/AGW-E2E checks pass | | Consumer checks | Package imports, compiled declarations, API comparison and guide examples pass | -| E2E selection | AGW: 58 scenarios/14 files/58 tests; default all remains 76/40/81 | +| E2E selection | AGW: 68 scenarios/15 files/68 tests; default all remains 76/40/81 | These are selected live runs. Latest expansion verified 20 distinct labels/EVM/multi-asset/SOL/SPL scenarios across selected runs; earlier v5 native/lifecycle evidence adds ten distinct cases. This is not a full 58-case invocation. Older v4 evidence includes 39 prior cases plus seven additions. See the linked report for the initial 7702 gas failure and verified fix, public API changes, IDL-layout limits and test evidence. @@ -43,6 +56,8 @@ These are selected live runs. Latest expansion verified 20 distinct labels/EVM/m ## Remaining dependencies +Open items, owners and the multi-action native rule decision: [pending items](pending-items.md). + Product choices are settled. Rule ref is removed; zero native PC defaults and the current token model are retained; dual native/EVM raw/index inputs are approved; named IDL Solana authoring is implemented. Contract validation is authoritative; AMBIGUOUS_RULE remains the SDK response to multiple candidates. No selection interface change is required. Freshly fetched contracts already validate explicit rulesIds and reject unauthorized actions. V5 supplies stored labels and setLabel, now enabled by the SDK. [Contract delivery items](questions-zaryab.md). `creditRevert` remains a separate Push-core executor dependency; ordinary returned funds do not lower policy spend. diff --git a/plan/agw/latest-refresh.json b/plan/agw/latest-refresh.json index b0d1334c..2d177337 100644 --- a/plan/agw/latest-refresh.json +++ b/plan/agw/latest-refresh.json @@ -1,135 +1,31 @@ { - "run_id": "20261007T102718466408Z", - "pulled_at": "2026-10-07T10:27:18.466408+00:00", - "complete": true, - "missing_page_ids": [], - "unknown_export_entries": [], + "run_id": "20261012T145327Z", + "pulled_at": "2026-10-12T14:53:27.075673+00:00", + "scope": "pages 1 and 5 requested by user", + "complete": false, + "requested_pages_complete": true, + "notes": "Focused refresh of two pages, not a new twelve-page export. Other ten pages retain their individual source-manifest timestamps. Discussions inspected separately; native exports omit comments.", + "previous_full_refresh": "research/section6-feedback-2026-10-12/previous-latest-refresh.json", "archives": [ - "notion/exports/20261007T102718466408Z/export-1.zip", - "notion/exports/20261007T102718466408Z/export-2.zip", - "notion/exports/20261007T102718466408Z/export-3.zip", - "notion/exports/20261007T102718466408Z/export-4.zip" + "research/section6-feedback-2026-10-12/sdk-export.zip", + "research/section6-feedback-2026-10-12/contracts-export.zip" ], "pages": [ { - "page_id": "3e9188aea7f481c8b38ccba332b0afa2", - "title": "AGW design overview", - "local_file": "notion/overview.md", - "changed": false, - "previous_sha256": "f2d7954e018324a937282ca190f397cc12a27973a07c891f3edfd6e89383c53e", - "sha256": "f2d7954e018324a937282ca190f397cc12a27973a07c891f3edfd6e89383c53e", - "raw_export_sha256": "99b727bd58cf588b2c766dc1b93eff402c47e918718b69c2a456b119ad43435b" + "page": "sdk", + "export_entry": "Private & Shared/5 SDK AGW 3e9188aea7f481cf8e8de324956549b9.md", + "sha256": "7f8e6e892686fc298bd0a40d66d7e21cb457711e18a272e563322403bc0380ec", + "exported_at": "2026-10-12T14:53:27.075673+00:00", + "local_file": "plan/agw/notion/5-sdk-agw.md", + "native_export_includes_comments": false }, { - "page_id": "3e9188aea7f4813aa31fc95ceb4e684d", - "title": "1 AGW Contract Changes", - "local_file": "notion/1-agw-contract-changes.md", - "changed": false, - "previous_sha256": "f1301d8ff1cf370968b90a3d53037ece8fa4c6783c45a402f9be6998928e3631", - "sha256": "f1301d8ff1cf370968b90a3d53037ece8fa4c6783c45a402f9be6998928e3631", - "raw_export_sha256": "f1301d8ff1cf370968b90a3d53037ece8fa4c6783c45a402f9be6998928e3631" - }, - { - "page_id": "3e9188aea7f48118b90ac9b267496295", - "title": "2 Universal Marketplace", - "local_file": "notion/2-universal-marketplace.md", - "changed": false, - "previous_sha256": "5ddfd9e8980faae9eec85e3959cc99edbb3b115565af289c5603a91df0b78d18", - "sha256": "5ddfd9e8980faae9eec85e3959cc99edbb3b115565af289c5603a91df0b78d18", - "raw_export_sha256": "5ddfd9e8980faae9eec85e3959cc99edbb3b115565af289c5603a91df0b78d18" - }, - { - "page_id": "3e9188aea7f48188a838c3a740d8c858", - "title": "3 ERC-8183 job kernel and hook", - "local_file": "notion/3-8183-job-kernel-and-hook.md", - "changed": false, - "previous_sha256": "3c805db465f2d39db8d34179ac1dd864db1abf7b1b3e93f38074fbf393093f90", - "sha256": "3c805db465f2d39db8d34179ac1dd864db1abf7b1b3e93f38074fbf393093f90", - "raw_export_sha256": "3c805db465f2d39db8d34179ac1dd864db1abf7b1b3e93f38074fbf393093f90" - }, - { - "page_id": "3e9188aea7f4817bb03ef4c78c883f8b", - "title": "4 Universal Evaluation", - "local_file": "notion/4-universal-evaluation.md", - "changed": false, - "previous_sha256": "a2f1c93a75b8631c9628c06f1be135fa0198f00f096a765ce808dd5e544b2d6f", - "sha256": "a2f1c93a75b8631c9628c06f1be135fa0198f00f096a765ce808dd5e544b2d6f", - "raw_export_sha256": "a2f1c93a75b8631c9628c06f1be135fa0198f00f096a765ce808dd5e544b2d6f" - }, - { - "page_id": "3e9188aea7f481cf8e8de324956549b9", - "title": "5 SDK AGW", - "local_file": "notion/5-sdk-agw.md", - "changed": true, - "previous_sha256": "e407ee77cdf874db7ef4697f84e9945ff3a12a2f2e07e8a7f90bd24e93ea32f1", - "sha256": "d3bc55b08a37d762c49173149fd8d554a8551682c0956de3e91394a54bfed9a6", - "raw_export_sha256": "8d024eb2bd2955fc772d2194f50a02d601a2d5bf903b0c9cc74882ee11348130" - }, - { - "page_id": "3ea188aea7f481e2961ed97129f3a4e6", - "title": "6 SDK Universal Marketplace", - "local_file": "notion/6-sdk-universal-marketplace.md", - "changed": false, - "previous_sha256": "e7298952f2ba9adb218b4ef0459b8fa696a2072167dc5f655060b69788cf528c", - "sha256": "e7298952f2ba9adb218b4ef0459b8fa696a2072167dc5f655060b69788cf528c", - "raw_export_sha256": "e7298952f2ba9adb218b4ef0459b8fa696a2072167dc5f655060b69788cf528c" - }, - { - "page_id": "3ea188aea7f481e0a137f5a896723376", - "title": "7 SDK ERC-8183 Job", - "local_file": "notion/7-sdk-8183-job.md", - "changed": false, - "previous_sha256": "dbf1ff539f5df944e5f5f55710f5f6d3359469a141038cec2604e7c33392752c", - "sha256": "dbf1ff539f5df944e5f5f55710f5f6d3359469a141038cec2604e7c33392752c", - "raw_export_sha256": "dbf1ff539f5df944e5f5f55710f5f6d3359469a141038cec2604e7c33392752c" - }, - { - "page_id": "3ea188aea7f48197a3b3cfdedfa74fee", - "title": "8 SDK Universal Evaluation", - "local_file": "notion/8-sdk-universal-evaluation.md", - "changed": false, - "previous_sha256": "eb2e584bd76aeea06c0dd03b3c8802b2340acf955e1ea75bf7768ebf9d2ab34e", - "sha256": "eb2e584bd76aeea06c0dd03b3c8802b2340acf955e1ea75bf7768ebf9d2ab34e", - "raw_export_sha256": "eb2e584bd76aeea06c0dd03b3c8802b2340acf955e1ea75bf7768ebf9d2ab34e" - }, - { - "page_id": "d2d188aea7f4825cbcea81ef86eca607", - "title": "Legacy PUSH AGW SDK Doc v1", - "local_file": "notion/legacy-agw-sdk-v1.md", - "changed": false, - "previous_sha256": "9e6569ef9b76d59cb411d65305d67333c6766abc2e9c80a35ae6f56f12f70916", - "sha256": "9e6569ef9b76d59cb411d65305d67333c6766abc2e9c80a35ae6f56f12f70916", - "raw_export_sha256": "9e6569ef9b76d59cb411d65305d67333c6766abc2e9c80a35ae6f56f12f70916" - }, - { - "page_id": "3d1188aea7f480ddbb4af6d0efb211e6", - "title": "AGW Address Book PC Donut", - "local_file": "notion/agw-address-book-donut-2026-09-04.md", - "changed": false, - "previous_sha256": "5c5017d6b4a58af0fa8854ef550b054c1f33d57a812ea51a16f31f7c33e79742", - "sha256": "5c5017d6b4a58af0fa8854ef550b054c1f33d57a812ea51a16f31f7c33e79742", - "raw_export_sha256": "5c5017d6b4a58af0fa8854ef550b054c1f33d57a812ea51a16f31f7c33e79742" - }, - { - "page_id": "3d1188aea7f4801f9cb3fbd9318ec536", - "title": "Agentic wallet flow updated", - "local_file": "notion/agentic-wallet-flow-2026-09-07.md", - "changed": false, - "previous_sha256": "d4a922fd1d33da5a7042f26053e8df0e496c3ccd4cb0044b0892948ac509c3a0", - "sha256": "d4a922fd1d33da5a7042f26053e8df0e496c3ccd4cb0044b0892948ac509c3a0", - "raw_export_sha256": "d4a922fd1d33da5a7042f26053e8df0e496c3ccd4cb0044b0892948ac509c3a0" + "page": "contracts", + "export_entry": "Private & Shared/1 AGW Contract Changes (nomenclature standard + ch 3e9188aea7f4813aa31fc95ceb4e684d.md", + "sha256": "7d1690747f52a32a2e3c9eac64422db8dbc673729f370156da2c83c06634bac4", + "exported_at": "2026-10-12T14:53:27.077622+00:00", + "local_file": "plan/agw/notion/1-agw-contract-changes.md", + "native_export_includes_comments": false } - ], - "review_status": "Review required", - "contract_deployment_followup": { - "checked_on": "2026-10-07", - "documentation_commit": "bd230d20dbf778d9994b1f1082f79b1a8829a10f", - "deployed_source_commit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", - "generation": "v5", - "chain_id": 42101, - "readonly_block": 23991912, - "evidence": "research/deployment-review-2026-10-07-v5/README.md", - "sdk_validation": "research/v5-implementation-2026-10-07/README.md", - "notion_reexported_for_this_followup": false - } + ] } diff --git a/plan/agw/notion/1-agw-contract-changes.md b/plan/agw/notion/1-agw-contract-changes.md index 029e3e82..0db4e6a6 100644 --- a/plan/agw/notion/1-agw-contract-changes.md +++ b/plan/agw/notion/1-agw-contract-changes.md @@ -359,4 +359,144 @@ uint8 constant MAX_ASSETS = 8; 3. `creditRevert`: wire the executor module, or replace the credit path. 4. Anything in the rename map or the diff that should stay as is. -The SDK surface lives on page 5 (SDK: AGW). \ No newline at end of file +The SDK surface lives on page 5 (SDK: AGW). + +# 6. Changes proposed on 12 Oct 2026 + +These come from the review of the first SDK implementation, [push-chain-sdk PR #291](https://github.com/pushchain/push-chain-sdk/pull/291), which runs against the v5 contracts on Donut. Sections 0 to 5 above are left exactly as they were. Where an entry here differs from them, the entry here is the current one. The SDK side of each change is on [5. SDK: AGW](https://app.notion.com/p/5-SDK-AGW-3e9188aea7f481cf8e8de324956549b9?pvs=21) (page 5), section 6. + +Struct and field names below are shown by meaning. Where the v5 source names a field differently, the source name wins. + +| # | Change | Contract | Replaces above | SDK side (page 5) | +| --- | --- | --- | --- | --- | +| 6.1 | The wallet approves the gateway itself, for the exact amount, inside each outbound | AGW | new | 6.g | +| 6.2 | One factory call deploys the wallet and grants its rules | AGWFactory, AGW | new (page 5 called this "item 11") | 6.b | +| 6.3 | Pins on EVM destination calls | UniversalRulesPolicy | new | 6.a | +| 6.4 | `ref` removed from `grantRules` | AGW | section 4 item 3, and the `ref` lines in 4b and 4c | 6.b, 6.c, 6.d | +| 6.5 | A cap of 0 means nothing moves | UniversalRulesPolicy | "0 = no total cap" in 4c | 6.b | + +### 6.1 The wallet approves the gateway itself, for the exact amount, inside each outbound + +**What happens today.** When the wallet sends a token to another chain, `UniversalGatewayPC` takes the token out of the wallet. That needs an ERC20 approval from the wallet to the gateway. Nothing in the wallet sets it, so the owner has to send `approve(gateway, amount)` through the owner door before the agent's first cross-chain send. If the owner skips it, the agent's send fails. + +**Why that is wrong.** + +- Granting a rule with an asset cap already says how much the agent may move. A second, separate permission is a step no user expects. +- The approval goes through the owner door, so it records an `OWNER_ACTION` checkpoint. An owner who raises the allowance during a job is treated as having changed something mid-job. +- `revokeRules` and `revokeAllRules` do not clear the allowance. It stays on the wallet. +- When the allowance runs out, the agent stops until the owner returns. + +**Change.** The wallet sets the approval itself, for the exact amount of the outbound, in the same transaction, on both doors. + +```diff +// AGW, owner door and agent door +~ execute / executeWithSig / executeAsAgent +~ when a call's target is UNIVERSAL_GATEWAY_PC and its selector is sendUniversalTxOutbound(req): ++ before the call: approve req.token to UNIVERSAL_GATEWAY_PC for req.amount ++ after the call: allowance is 0 again (the gateway took exactly req.amount; reset it if anything is left) +~ agent door order: the rules policy checks req against the rules first, then the approval, then the gateway call += a native-coin outbound (no token pulled) is untouched +``` + +No standing allowance exists at any point outside the call. There is nothing to top up, nothing left after a revoke, and no checkpoint, because the owner did nothing. + +To confirm while implementing: whether the gateway takes anything from the wallet beyond `req.amount` (a fee in the token). If it does, the approval must cover that amount as well. + +### 6.2 One factory call deploys the wallet and grants its rules + +**What happens today.** An external owner sends deploy and grants as one UEA multicall. A Push EOA owner cannot (core rejects a multicall from a Push-native sender), so the SDK sends the deploy and then each grant as its own transaction. If a later grant fails, the wallet exists with only some of its rules. + +**Change.** A factory entry that does both in one transaction, for any owner. Either the wallet exists with every rule passed, or the transaction reverts as a whole. + +```diff +// AGWFactory ++ createWallet(string label, Session[] rules) returns (address wallet, bytes32[] rulesIds) ++ caller is the owner ++ deploys the wallet, then grants every rule, in order; reverts as a whole if any grant fails ++ rules may be empty, in which case it behaves as deployWallet ++ rulesIds are the same ids grantRules would have returned, in the order passed += deployWallet(string label) // unchanged += deployWalletWithSig(...) // unchanged + +// AGW ++ the wallet accepts its first rules from the factory, and only during its own deployment +~ each rule granted this way emits RulesGranted and records a RULES_GRANTED checkpoint, exactly as grantRules does +``` + +To decide: whether a signed variant (`createWalletWithSig`, same digest rules as `deployWalletWithSig` with the rules hashed in) lands in the same change. The marketplace's `startJob` deploys a wallet with rules for the user, so it would use that variant. + +### 6.3 Pins on EVM destination calls + +**What happens today.** All rule checks run on Push, in the rules policy, before the wallet is allowed to call the gateway. For an outbound to an EVM chain the policy unpacks the payload and checks each destination call's target, selector, beneficiary and value. It has no field for a general pin. A rule cannot say "argument 0 of `supply` must be USDC", so an agent allowed to call `supply` can pass any asset the wallet's CEA holds. The Push rulebook has argument pins, and the Solana rulebook has account and data pins. The EVM destination rulebook is the only one without them. + +**Change.** The EVM allowed call gains a list of pins, read from the destination call's calldata the same way the beneficiary already is. A pin either requires an argument to equal a value or to not exceed a value. + +```diff +// libraries/Types.sol + struct ArgPin { += offset; // byte position of the argument in the call's calldata ++ uint8 op; // 0 = EQ: the 32 bytes at offset must equal value ++ // 1 = MAX: the 32 bytes at offset, read as uint256, must not exceed value += bytes32 value; + } + +// universal EVM terms + struct AllowedCall { += target; selector; beneficiary offset and flag; maxValue; ++ ArgPin[] pins; // 0..MAX_PINS (8) + } + +// UniversalRulesPolicy, EVM rulebook +~ checkAction: for each destination call in the payload, after the target, selector, beneficiary and value checks, ++ check every pin of the matching allowed call against that call's calldata ++ reverts reuse the Push rulebook's pin error (ArgPinMismatch) for EQ, and add one for MAX + +// UniversalRulesPolicy, Push rulebook ++ the same op on its pins, so a MAX pin is an ordinary pin there too += the metered argument and the call counter stay in the contract; the SDK no longer exposes them +``` + +The SDK now has one rule shape for every chain, with pins inside each allowed call (page 5, 6.a). Until this lands, the SDK rejects a pin on an EVM destination call before signing, and compiles a `max` pin on a Push call to the existing metered argument (one per call). + +The SDK also folds `beneficiary` into pins: it is written as a pin whose expected value is the wallet itself (page 5, 6.a). Until this change lands, the SDK compiles that pin to the existing beneficiary check, one per call. Once pins exist on EVM destination calls, the same check is an ordinary EQ pin against the wallet's CEA, and the dedicated beneficiary offset and flag on `AllowedCall` can be retired. To decide: retire them in this change, or keep them. + +### 6.4 `ref` removed from `grantRules` + +Section 4 item 3 added a `bytes32 ref` to `grantRules` so a job could bind to a rules id. It is not needed: `rulesId` is generated at grant, and that id is what a job, a card or an indexer latches on to. The v5 contracts on Donut already grant without it. + +```diff +// AGW +- grantRules(Session session, bytes32 ref) returns (bytes32 rulesId) ++ grantRules(Session session) returns (bytes32 rulesId) +- grantRulesWithSig(Session session, bytes32 ref, uint48 deadline, bytes ownerSig) returns (bytes32 rulesId) ++ grantRulesWithSig(Session session, uint48 deadline, bytes ownerSig) returns (bytes32 rulesId) +- RulesGranted(bytes32 indexed rulesId, uint8 mode, bytes32 indexed chainHash, string chainNamespace, bytes32 ref) ++ RulesGranted(bytes32 indexed rulesId, uint8 mode, bytes32 indexed chainHash, string chainNamespace) += Checkpointed(uint64 indexed seq, uint8 kind, bytes32 ref, uint64 blockNumber) // keeps its ref: the checkpoint's own reference +``` + +The `ref?: Hex` field on the SDK struct in 4c goes with it. + +### 6.5 A cap of 0 means nothing moves + +4c says `maxTotal: 0` means no total cap. That is reversed. A wallet whose purpose is to limit an agent must not hand out an unlimited budget because a field was left empty. + +```diff +// universal terms (EVM and SVM) + struct AssetCap { += address token; += uint256 maxPerCall; +- uint256 maxTotal; // 0 = no running cap ++ uint256 maxTotal; // 0 = the agent cannot move this token + } +// same reading for the native coin caps on a Push call: 0 = no native coin may be sent +``` + +The v5 contracts on Donut already treat an explicit zero as "cannot move". The gap was in the SDK, which sent the largest possible number when `maxTotal` was left out. It now sends 0 (page 5, 6.b). + +### 6.6 Checked, no contract change needed + +- **`setLabel` is not a checkpoint.** Item 10 in section 4 already says so and the v5 contract behaves that way. The first SDK implementation routed the rename through the owner door, which does record a checkpoint. The fix is in the SDK: it calls `setLabel` on the wallet directly (page 5, 6.f). +- **First-use destination gas.** The 500,000 default that fails when a CEA is deployed on first use is an SDK default. No contract change (page 5, 6.g). +- **`spent` on rule records.** The counters are already readable from the policy. The SDK puts them back on the record (page 5, 6.c and 6.d). +- **Deleting a rule.** The SDK renames `rules.revoke` to `rules.delete` (page 5, 6.m). `revokeRules` and `revokeAllRules` already remove the rule from the session engine for good, so the contract does what the new name says. The contract names stay as they are. \ No newline at end of file diff --git a/plan/agw/notion/5-sdk-agw.md b/plan/agw/notion/5-sdk-agw.md index 06c7346f..c87d0fec 100644 --- a/plan/agw/notion/5-sdk-agw.md +++ b/plan/agw/notion/5-sdk-agw.md @@ -30,7 +30,7 @@ New - `rules.update`, - `rules.revoke` - `PushChain.CONSTANTS.AGENTIC` -- `PushChain.utils.agentic` +- `~~PushChain.utils.agentic~~` (dropped 12 Oct 2026, see 6.h) Updated @@ -144,7 +144,7 @@ Before asking for a signature the SDK checks that no rule's agent is the owner ( Under the hood this is `deployWallet` (or reuse of a derived address) and one `grantRules` per rule. For an external owner they go as one UEA multicall under one signature. Funding is not part of `create`: the wallet is a normal Push account, so send tokens and PC to its address the way you would to any account (1.a shows the address before deployment). -For a Push EOA owner the same thing needs a batching entry on the factory, because core rejects multicall from a Push-native sender: [1. AGW Contract Changes (nomenclature standard + change set)](1-agw-contract-changes.md) item 11, **PROPOSED** (`createWallet(label, rules[])` on the factory). Until it lands the SDK sends deploy and grant as separate transactions and says so through progress events (AGENTIC-TX-102 and 104); `tx` is then the last of them. +For a Push EOA owner the same thing needs a batching entry on the factory, because core rejects multicall from a Push-native sender: [1. AGW Contract Changes (nomenclature standard + change set)](https://app.notion.com/p/1-AGW-Contract-Changes-nomenclature-standard-change-set-3e9188aea7f4813aa31fc95ceb4e684d?pvs=21) item 11, **PROPOSED** (`createWallet(label, rules[])` on the factory). Until it lands the SDK sends deploy and grant as separate transactions and says so through progress events (AGENTIC-TX-102 and 104); `tx` is then the last of them. A `progressHook` passed to `PushChain.initialize` receives the same events alongside the per-call one, as in core. @@ -248,7 +248,7 @@ Page rule: identities going in and out of the agentic namespace are Push address ### 1.g Set the wallet label - `w.setLabel` -**PROPOSED**, contract change, see [1. AGW Contract Changes (nomenclature standard + change set)](1-agw-contract-changes.md) item 10. Changes the label shown in `list()` and `info()`; owner only. +**PROPOSED**, contract change, see [1. AGW Contract Changes (nomenclature standard + change set)](https://app.notion.com/p/1-AGW-Contract-Changes-nomenclature-standard-change-set-3e9188aea7f4813aa31fc95ceb4e684d?pvs=21) item 10. Changes the label shown in `list()` and `info()`; owner only. ```tsx // Function @@ -480,7 +480,7 @@ const ownerClient = await PushChain.initialize(ownerSigner, { // owner door: t Which door the client uses depends on who the signer is. If the signer is the wallet's owner, sends go through the owner door: no rules, and every send is recorded as a checkpoint. If the signer is an address named as agent in one of the wallet's rules, sends go through the agent door and the rules apply. If it is neither, `initialize` throws `NOT_OWNER_OR_AGENT`. If the address has no wallet deployed yet it throws `WALLET_NOT_DEPLOYED`, and if the address is not an agentic wallet it throws `NOT_AGENTIC_WALLET`. This is also how an owner acts as the wallet with the full client: `PushChain.initialize(ownerSigner, { agenticWallet })`. There is one way to send as a wallet and the signer decides the door. -On the agent door the SDK sends; URP on-chain is the only rule checker. Before sending, the SDK only looks up the `rulesId` for the destination chain: the rule that is enabled, whose `agent` equals the signer, and whose `chainNamespace` equals the destination. The lookup is one read on every send, not cached at initialize. If none is found it throws `NO_RULES_FOR_CHAIN` before any signature, so it costs nothing; otherwise it calls `executeAsAgent(rulesId, ...)` on the wallet. That is the agent door from D3 on [1. AGW Contract Changes (nomenclature standard + change set)](1-agw-contract-changes.md): there is no session validator, and the wallet only checks that `msg.sender` is the rule's agent. There is one rule per (agent, chain), so a signer and a destination match at most one rule. If the action breaks a rule, it reverts on-chain and the agent pays that gas. `sendTransaction` then throws `AgenticRevertError`, which extends core's `PushChainExecutionError` and carries URP's custom error in `decodedError`, so the agent sees which gate failed (3.f). +On the agent door the SDK sends; URP on-chain is the only rule checker. Before sending, the SDK only looks up the `rulesId` for the destination chain: the rule that is enabled, whose `agent` equals the signer, and whose `chainNamespace` equals the destination. The lookup is one read on every send, not cached at initialize. If none is found it throws `NO_RULES_FOR_CHAIN` before any signature, so it costs nothing; otherwise it calls `executeAsAgent(rulesId, ...)` on the wallet. That is the agent door from D3 on [1. AGW Contract Changes (nomenclature standard + change set)](https://app.notion.com/p/1-AGW-Contract-Changes-nomenclature-standard-change-set-3e9188aea7f4813aa31fc95ceb4e684d?pvs=21): there is no session validator, and the wallet only checks that `msg.sender` is the rule's agent. There is one rule per (agent, chain), so a signer and a destination match at most one rule. If the action breaks a rule, it reverts on-chain and the agent pays that gas. `sendTransaction` then throws `AgenticRevertError`, which extends core's `PushChainExecutionError` and carries URP's custom error in `decodedError`, so the agent sees which gate failed (3.f). From an external key, the call arrives through the agent's UEA. If the agent's UEA is not yet deployed, the first action takes the origin-chain fee lock once (minimum $1), which deploys the UEA and funds it with PC. Every later action requires PC in the UEA and is a direct Push transaction paid from that balance, with no origin transaction and no cross-chain wait. @@ -646,7 +646,9 @@ interface WalletInfo { address: Address; label: string; index: number; owner: Ad interface Checkpoint { seq: number; kind: 'OWNER_ACTION' | 'RULES_GRANTED' | 'RULES_REVOKED'; ref: Hex; blockNumber: bigint; txHash: Hex } ``` -### 3.d Constants, PushChain.CONSTANTS.AGENTIC (new) +### ~~3.d Constants, PushChain.CONSTANTS.AGENTIC (new)~~ + +Dropped on 12 Oct 2026, except `WALLET`. See 6.h. ```tsx PushChain.CONSTANTS.AGENTIC[PUSH_NETWORK.TESTNET_DONUT] = { @@ -655,9 +657,11 @@ PushChain.CONSTANTS.AGENTIC[PUSH_NETWORK.TESTNET_DONUT] = { }; ``` -### 3.e Helpers, PushChain.utils.agentic (new) +### ~~3.e Helpers, PushChain.utils.agentic (new)~~ + +Dropped on 12 Oct 2026. See 6.h. -Pure functions with the same output as the on-chain views. +~~Pure functions with the same output as the on-chain views.~~ ```tsx PushChain.utils.agentic = { @@ -702,7 +706,7 @@ class AgenticRevertError extends PushChainExecutionError {} **PROPOSED:** the AGENTIC-TX event list. Every write (`create`, `setLabel`, `rules.add`, `rules.update`, `rules.revoke`) takes a per-call `progressHook`; a `progressHook` passed to `PushChain.initialize` runs alongside it, as in core. -`NO_RULES_FOR_CHAIN` is thrown before any signature and costs nothing. The rules lookup is one read on every send, not cached at initialize. A URP revert is thrown from `sendTransaction` as `AgenticRevertError` and also lands as `decodedError` on AGENTIC-TX-199-02. A destination-chain revert after URP passed still counts the spend, because the spend is counted when the outbound leaves Push; whether it is credited back depends on [1. AGW Contract Changes (nomenclature standard + change set)](1-agw-contract-changes.md) item 6 (`creditRevert`). +`NO_RULES_FOR_CHAIN` is thrown before any signature and costs nothing. The rules lookup is one read on every send, not cached at initialize. A URP revert is thrown from `sendTransaction` as `AgenticRevertError` and also lands as `decodedError` on AGENTIC-TX-199-02. A destination-chain revert after URP passed still counts the spend, because the spend is counted when the outbound leaves Push; whether it is credited back depends on [1. AGW Contract Changes (nomenclature standard + change set)](https://app.notion.com/p/1-AGW-Contract-Changes-nomenclature-standard-change-set-3e9188aea7f4813aa31fc95ceb4e684d?pvs=21) item 6 (`creditRevert`). # 4. Outside change: [PushChain.CONSTANTS.READ](http://PushChain.CONSTANTS.READ).CHAIN (confirmed 2026-09-28) @@ -728,4 +732,621 @@ read({ chain: PushChain.CONSTANTS.CHAIN.ETHEREUM_SEPOLIA, ... }) // still comp # 5. Open for review 1. `rules.update` resets spend counters because it is revoke plus grant. Accepted for v1 and stated in 1.l; an in-place update is a contract change with no demand yet. -2. `setLabel` assumes [1. AGW Contract Changes (nomenclature standard + change set)](1-agw-contract-changes.md) item 10 lands. Pointer for the team. \ No newline at end of file +2. `setLabel` assumes [1. AGW Contract Changes (nomenclature standard + change set)](https://app.notion.com/p/1-AGW-Contract-Changes-nomenclature-standard-change-set-3e9188aea7f4813aa31fc95ceb4e684d?pvs=21) item 10 lands. Pointer for the team. + +# 6. Changes proposed on 12 Oct 2026 + +These come from the review of the first SDK implementation, [push-chain-sdk PR #291](https://github.com/pushchain/push-chain-sdk/pull/291). Sections 1 to 5 above are left exactly as they were. Where an entry here differs from them, the entry here is the current one. Every function whose call or result changes is written out again in full, so the change can be read without scrolling up. + +Contract changes are written on [1. AGW Contract Changes (nomenclature standard + change set)](https://app.notion.com/p/1-AGW-Contract-Changes-nomenclature-standard-change-set-3e9188aea7f4813aa31fc95ceb4e684d?pvs=21) (page 1), section 6, and are referenced from here by item number. + +| # | Change | Replaces above | Contract change (page 1) | +| --- | --- | --- | --- | +| 6.a | One rule shape for every chain, pins inside `allowedCalls`, `beneficiary` folded into pins | 3.b `NativeRule`, `UniversalRule` | 6.3 | +| 6.b | `create` is one transaction for every owner; `ref` removed; omitted caps are 0 | 1.b | 6.2, 6.4, 6.5 | +| 6.c, 6.d | `rules.list` and `rules.get`: `spent` per asset, no `ref`, arguments read back as `arg` | 1.i, 1.j | none | +| 6.e | `rules.add` and `rules.update`: call unchanged, new rule shape | 1.k, 1.l | none | +| 6.f | `setLabel` is never a checkpoint | 1.g | none | +| 6.g | Sending as the wallet: no gateway approval step, first-use gas default | 2.a | 6.1 | +| 6.h | Types, as they end up | 3.b, `RulesRecord`, `Spent`, 3.d, 3.e | none | +| 6.i | Solana: same rule shape, pins on arguments and on accounts, no IDL in a rule | new | none | +| 6.l | Response fields and error codes added by the first implementation: accepted, with four codes removed | 3.f | none | +| 6.m | `rules.revoke` is renamed `rules.delete` | 1.m | none | + +### 6.a One rule shape for every chain + +There is one rule shape. A rule for calls on Push is the same object as a cross-chain rule with `chainNamespace` left out. What the agent may call is always a list of `allowedCalls`, and restrictions on a function's arguments sit inside each allowed call as `pins`. + +A pin restricts one argument of the allowed function. It is either `expected` (the argument must equal this constant) or `max` (the argument must not exceed this number). To require that an argument is the wallet itself, the expected value is `PushChain.CONSTANTS.AGENTIC.WALLET`. A minimum on an argument (for example a minimum amount out on a swap) is not part of v1 and is deferred to the next version. + +```tsx +// a rule on Push: chainNamespace left out +{ + agent: '0xAgentOnPush', + validUntil: now + 30 * 86400, + allowedCalls: [ + { target: vault, selector: 'deposit(address,uint256)', + pins: [ + { arg: 0, expected: beneficiary }, // argument 0 must be this address + { arg: 1, max: parseUnits('10', 18) }, // argument 1 must not exceed this, per call + ] }, + ], +} + +// a rule on Ethereum Sepolia: same shape, plus the tokens the agent may move +{ + agent: '0xAgentOnPush', + chainNamespace: CHAIN.ETHEREUM_SEPOLIA, + assets: [ + { token: MOVEABLE.TOKEN.ETHEREUM_SEPOLIA.USDC, maxPerCall: parseUnits('100', 6), maxTotal: parseUnits('1000', 6) }, + ], + maxGasPerCall: parseUnits('1', 18), + validUntil: now + 30 * 86400, + allowedCalls: [ + { target: aavePool, selector: 'supply(address,uint256,address,uint16)', + pins: [ + { arg: 0, expected: usdcSepolia }, // asset must be USDC + { arg: 2, expected: PushChain.CONSTANTS.AGENTIC.WALLET }, // onBehalfOf must be this wallet + ] }, + { target: usdcSepolia, selector: 'approve(address,uint256)' }, + ], +} +``` + +What is gone from the shape: the separate `NativeRule` type with `target`, `selector`, `pins` and `amount` at the top of the rule, and the fields `amount.maxTotal`, `maxValueTotal` and `maxCalls`. A `max` pin limits each call only. The SDK has no per-argument lifetime total and no call counter. On a cross-chain rule the lifetime limit on a token is the asset's `maxTotal`. On a Push call the lifetime limit is what the owner funds the wallet with, plus `validUntil`. + +`beneficiary` is now a pin. On page sections above, `beneficiary: 2` meant that argument 2 must be the wallet's own account. That is a pin whose expected value is the wallet, so it is written as `{ arg: 2, expected: PushChain.CONSTANTS.AGENTIC.WALLET }` and the separate field is removed. `WALLET` stands for the wallet's own account on the rule's chain: the AGW address for a call on Push, and the wallet's CEA for a call on another chain. The SDK fills in the real address when the rule is granted, so nobody has to look up a CEA. It is a marker and not an address (its value is the string `'agentic:wallet'`), because an agent card lists its rules before any wallet exists. On read, a pin whose stored value is the wallet's own account comes back as `WALLET`. + +Where each part is checked. Every check runs on Push, in the rules policy, before the wallet is allowed to make the call or hand it to the gateway. + +| On an allowed call | Call on Push | Call on an EVM destination | +| --- | --- | --- | +| `target`, `selector`, `maxValue` | Checked | Checked | +| A pin with `expected: WALLET` | Checked | Checked. One per call until page 1, 6.3 lands | +| Any other pin | Checked. Up to 8 `expected` pins and one `max` pin per call | Needs page 1, 6.3. Until it lands the SDK rejects it before signing | + +### 6.b Create an agentic wallet - `client.agentic.create` (changed) + +Deploys the wallet and grants the rules in one transaction, for every kind of owner. Either the wallet exists with every rule that was passed, or nothing happened. + +```tsx +// Function +const created = await client.agentic.create(label, { options }) + +// Usage and Params +const created = await client.agentic.create('aave-optimiser', { // wallet with one cross-chain rule + rules: [{ // one entry per chain per agent + agent: '0xAgentOnPush', // a Push address: the agent's EOA, or its UEA if the key lives on another chain. Never the owner + chainNamespace: CHAIN.ETHEREUM_SEPOLIA, // left out = a rule for calls on Push + assets: [ + { token: MOVEABLE.TOKEN.ETHEREUM_SEPOLIA.USDC, maxPerCall: parseUnits('100', 6), maxTotal: parseUnits('1000', 6) }, + { token: MOVEABLE.TOKEN.ETHEREUM_SEPOLIA.WETH, maxPerCall: parseUnits('0.5', 18), maxTotal: parseUnits('2', 18) }, + ], + maxGasPerCall: parseUnits('1', 18), // PC (wei) per outbound for the destination leg + validUntil: now + 30 * 86400, + allowedCalls: [ + { target: aavePool, selector: 'supply(address,uint256,address,uint16)', + pins: [{ arg: 2, expected: PushChain.CONSTANTS.AGENTIC.WALLET }] }, // onBehalfOf must be this wallet (its CEA on Sepolia) + { target: usdcSepolia, selector: 'approve(address,uint256)' }, + ], + }], + progressHook: (p) => console.log(p.id, p.message), // AGENTIC-TX-1xx +}); +const bare = await client.agentic.create('scratch', { rules: [] }); // wallet first, rules later with rules.add +// label string, required shown in list() and info(); the contract stores it +// options.rules Rule[], required one per chain per agent, may be empty; shape in 6.a +// options.progressHook function, optional progress events, AGENTIC-TX-1xx; default none +// rules[].agent Address, required the Push address allowed to act under this rule; never the owner +// rules[].chainNamespace string, optional the chain the rule governs; left out = Push +// rules[].assets AssetCap[], cross-chain rules tokens the agent may move; each cap is { token, maxPerCall, maxTotal } +// rules[].assets[].maxTotal bigint, optional lifetime cap for that token; left out = 0, and 0 means the agent cannot move it +// rules[].maxGasPerCall bigint, cross-chain rules PC (wei) the wallet may spend per outbound for the destination leg +// rules[].allowedCalls AllowedCall[], required what the agent may call; each is { target, selector, pins?, maxValue? } +// rules[].allowedCalls[].maxValue bigint, optional native coin per call; left out = 0 +// rules[].allowedCalls[].pins Pin[], optional { arg, expected } or { arg, max }; expected may be PushChain.CONSTANTS.AGENTIC.WALLET; see 6.a + +// Returns +// { wallet, index, rulesIds, tx } +{ + wallet: '0x2Fd904d6f2C0b34d58426C8Ae9c5267E845CE98f', + index: 0, + rulesIds: ['0x9c1e...'], // in the order of the rules you passed; empty for rules: [] + tx: { // UniversalTxResponse, always a single transaction + hash: '0xb527...', + origin: 'eip155:11155111:0x31dC...', // the owner's key, CAIP-10 + from: '0xFd6C2fE69bE13d8bE379CCB6c9306e74193EC1A9', // the owner's Push account + blockNumber: 1290n, + wait // await tx.wait() for the receipt; status lives on the receipt + } +} +``` + +What changed from 1.b: + +- **One transaction for every owner.** 1.b said a Push EOA owner gets separate deploy and grant transactions until a factory entry lands. That fallback is removed. The factory entry is page 1, 6.2. There is no partial result to reconcile. +- **`ref` is removed** from every rule. The `rulesId` the grant returns is what a job, a card or an indexer latches on to. Page 1, 6.4. +- **A cap that is left out is 0, never unlimited.** That covers `assets[].maxTotal` and `allowedCalls[].maxValue`. A forgotten cap means the agent cannot move that asset, which shows up on the first send. Page 1, 6.5. Note that the WETH line in 1.b had no `maxTotal`; under this rule it would move nothing, so the example here sets one. +- **Rules use the single shape from 6.a.** +- **The beneficiary field is a pin.** `beneficiary: 2` is written as a pin on argument 2 whose expected value is `PushChain.CONSTANTS.AGENTIC.WALLET` (6.a). + +### 6.c List rules - `w.rules.list` (changed) + +Returns every enabled rule on the wallet as a decoded record, including what each rule has spent so far. + +```tsx +// Function +const res = await w.rules.list() + +// Usage and Params +const { rules } = await w.rules.list(); // the wallet's rules +// no params + +// Returns +// { rules: RulesRecord[] } +{ + rules: [ + { + rulesId: '0x9c1e...', + enabled: true, + chainNamespace: 'eip155:11155111', + agent: '0xAgentOnPush', + validUntil: 1767225600, + rule: { /* the rule in the 6.a shape, accepted as is by rules.update */ }, + spent: { // one entry per asset, same order as rule.assets + kind: 'universal', + assets: [ + { token: '0x1c7D...7238', spent: 25000000n }, // USDC + { token: '0xfFf9...6B14', spent: 0n }, // WETH + ] + } + } + ] +} +``` + +### 6.d Get one rule - `w.rules.get` (changed) + +Returns one rule by id, decoded, with what it has spent. + +```tsx +// Function +const record = await w.rules.get(rulesId) + +// Usage and Params +const record = await w.rules.get('0x9c1e...'); // one rule by id +// rulesId Hex, required the id returned by create or rules.add + +// Returns +// RulesRecord +{ + rulesId: '0x51c0...', + enabled: true, + chainNamespace: 'eip155:42101', // a rule on Push + agent: '0xAgentOnPush', + validUntil: 1767225600, + rule: { + agent: '0xAgentOnPush', + validUntil: 1767225600, + allowedCalls: [ + { target: '0xVault', selector: 'deposit(address,uint256)', + pins: [ + { arg: 0, expected: '0x00000000000000000000000000000000000000000000000000000000000b0b0b' }, + { arg: 1, max: 10000000000000000000n }, + ] }, + ], + }, + spent: { kind: 'native', valueSpent: 0n, amountSpent: 5000000000000000000n, callsUsed: 1 } +} +``` + +What changed from 1.i and 1.j: + +- **`spent` is on every record**, as 1.i and 1.j already said. The first implementation dropped it; it goes back. For a cross-chain rule it is now a list with one entry per asset, because each asset has its own budget. 1.i showed a single `amountSpent`, which predates per-asset budgets. +- **`ref` is removed** from the record, following 6.b. +- **Arguments read back as `arg`, never as a byte offset.** The contract stores a pin and a beneficiary as a byte position in the calldata (argument 0 is byte 4, argument 1 is byte 36). The SDK converts that back, so a developer who wrote `arg: 0` reads `arg: 0`. A pin on the wallet itself reads back as `WALLET`. +- **The record is accepted by `rules.update` without edits.** The test is: read a rule, change `validUntil`, pass it back. An `expected` value reads back as 32-byte hex, because the contract keeps the function selector and not the argument types; it is accepted as input in that form. + +### 6.e Add and update rules - `w.rules.add`, `w.rules.update` (call unchanged) + +The calls and results in 1.k and 1.l stay as they are. Two things change through the rule itself: rules are in the 6.a shape, and they carry no `ref`. + +### 6.f Set the wallet label - `w.setLabel` (changed) + +Changes the label shown in `list()` and `info()`. Owner only. + +```tsx +// Function +const tx = await w.setLabel(label, { options? }) + +// Usage and Params +const tx = await w.setLabel('aave-optimiser-v2'); // rename the wallet +const reset = await w.setLabel(''); // back to the default label +const tracked = await w.setLabel('aave-optimiser-v2', { progressHook: (p) => console.log(p.id) }); // with progress events +// label string, required the new label, at most 64 bytes of UTF-8; an empty string resets it to the default "AGW " +// options.progressHook function, optional progress events, AGENTIC-TX-106; default none + +// Returns +// { hash, origin, from, to, blockNumber, wait() } +{ + hash: '0x3b8d...', + origin: 'eip155:11155111:0x31dC...', // the owner's key, CAIP-10 + from: '0xFd6C2fE69bE13d8bE379CCB6c9306e74193EC1A9', // the owner's Push account + to: '0x2Fd904d6f2C0b34d58426C8Ae9c5267E845CE98f', // the wallet + blockNumber: 1488n, + wait // await tx.wait() for the receipt; status lives on the receipt +} +``` + +What changed from 1.g: the function is live in the contract, so it is no longer proposed. The rule that a rename is not a checkpoint now binds the SDK too. The first implementation sent the rename through the owner door, and every owner door call records an `OWNER_ACTION` checkpoint. With the checkpoint rule for 8183 jobs, a user who renamed a wallet during a job would hand the fee to the agent over a label. The SDK must call the wallet's `setLabel` directly, for a Push EOA owner and for a UEA owner, so that the checkpoint count is the same before and after a rename. + +### 6.g Send as the wallet - `sendTransaction` with `agenticWallet` (changed) + +The call is the one in 2.a. Two things around it change. + +```tsx +// Function +const tx = await client.universal.sendTransaction({ options }) + +// Usage and Params +const agentClient = await PushChain.initialize(agentSigner, { // agent door: the signer is named as agent in a rule + network: PushChain.CONSTANTS.PUSH_NETWORK.TESTNET, + agenticWallet: '0xWallet', +}); +const tx = await agentClient.universal.sendTransaction({ // rule picked by the destination chain + to: { address: aavePool, chain: CHAIN.ETHEREUM_SEPOLIA }, + data: [ + { to: usdcSepolia, value: 0n, data: approveData }, + { to: aavePool, value: 0n, data: supplyData }, + ], + funds: { amount: parseUnits('100', 6), token: MOVEABLE.TOKEN.ETHEREUM_SEPOLIA.USDC }, +}); +// to { address, chain }, required the destination call and its chain +// data Hex or call array, optional the destination call data +// funds { amount, token }, optional the token the wallet moves with this send +// gasLimit bigint, optional destination gas; left out = the SDK default, which covers first use on a chain (see below) + +// Returns +// { hash, origin, from, blockNumber, wait() } +{ + hash: '0x6f2a...', + origin: 'eip155:11155111:0x7Be1...', // the agent's key, CAIP-10 + from: '0xWallet', // the AGW, not the signer + blockNumber: 1530n, + wait +} +``` + +What changed from 2.a: + +- **No gateway approval step.** When the wallet sends a token to another chain, the gateway on Push takes the token out of the wallet, which needs an ERC20 approval from the wallet. The first implementation left that to the owner as a separate transaction through the owner door before the agent's first send. That step is removed: the wallet approves the exact amount inside its own outbound call (page 1, 6.1). Funding a wallet is two plain transfers to its address, PC and the token. The SDK has no allowance check and no allowance error. +- **The default destination gas covers first use on a chain.** The first time a wallet sends to a chain, its account there (the CEA) is deployed as part of the call, which took about 1.3 million gas on Sepolia against a core default of 500,000. When the CEA is not deployed yet and the caller gave no `gasLimit`, the SDK uses a first-use default large enough for the deployment. When the CEA exists, the normal default applies. A `gasLimit` from the caller always wins, and `maxGasPerCall` on the rule still bounds what the agent can spend. + +### 6.h Types, as they end up + +These replace `NativeRule`, `UniversalRule`, `AllowedCall`, `RulesRecord` and `Spent` in 3.b. Everything else in section 3 stands. + +```tsx +interface Rule { + agent: Address; // Push address: EOA, or the UEA of an external key + chainNamespace?: ChainNamespace; // left out = the connected Push chain + validUntil: number; + assets?: AssetCap[]; // cross-chain rules: tokens the agent may move on chainNamespace + maxGasPerCall?: bigint; // cross-chain rules: PC (wei) per outbound for the destination leg + allowedCalls: AllowedCall[]; // 1..32 +} + +interface AssetCap { + token: MoveableToken | Address; // the other chain's token address, or the native marker + maxPerCall: bigint; + maxTotal?: bigint; // left out = 0; 0 means the agent cannot move this token +} + +interface AllowedCall { + target: Address | string; // a contract; on Solana, the program address + selector: Selector | 'value-only'; // on Solana, the instruction name with its argument types + pins?: Pin[]; + maxValue?: bigint; // native coin per call; left out = 0 +} + +type Pin = + | { arg: number; expected: Hex | Address | bigint | WalletMarker } // the argument must equal this constant, or be the wallet itself + | { arg: number; max: bigint } // the argument must not exceed this + | { account: number; expected: string | WalletMarker; token?: MoveableToken | string }; // Solana only: the account at this position must be this address, or the wallet itself; with token, the wallet's token account for that token + +type WalletMarker = typeof PushChain.CONSTANTS.AGENTIC.WALLET; // 'agentic:wallet': the wallet's own account on the rule's chain + +interface RulesRecord { + rulesId: Hex; + enabled: boolean; + chainNamespace: string; + agent: Address; + validUntil: number; + rule: Rule; // accepted as is by rules.update + spent: Spent; +} + +type Spent = + | { kind: 'native'; valueSpent: bigint; amountSpent: bigint; callsUsed: number } + | { kind: 'universal'; assets: { token: Address; spent: bigint }[] }; // one entry per asset, same order as rule.assets +``` + +`Checkpoint` in 3.c keeps its `ref` field. That one is the checkpoint's own reference (a rules id or a call hash) and has nothing to do with the rule `ref` removed in 6.b. + +`PushChain.CONSTANTS.AGENTIC` has one member, `WALLET` (6.a). The rest of 3.d (`FACTORY`, `RULES_POLICY`, `MAX_PINS`, `MAX_ALLOWED_CALLS`, `ENVELOPE_VERSION`) is dropped. Contract addresses and limits stay inside the SDK and are not exposed. The first implementation exposes all five on `PushChain.CONSTANTS.AGENTIC`; they are removed. + +`PushChain.utils.agentic` (3.e) is dropped. The ids and the encoders stay inside the SDK, `client.agentic.derive` covers deriving a wallet address, and `compileCard` is left to the marketplace page (page 6). The first implementation exposes `actionId`, `configId` and `decodeRules` on `PushChain.utils.agentic`; they are removed. + +### 6.i Solana, decided for v1 + +A Solana rule uses the same `allowedCalls` and `pins` shape as every other chain (6.a). The separate `allowedInstructions` shape of the first implementation, with an IDL and named accounts and fields, is replaced. + +```tsx +// a rule on Solana devnet +{ + agent: '0xAgentOnPush', + chainNamespace: CHAIN.SOLANA_DEVNET, + assets: [ + { token: '0x0000000000000000000000000000000000000000', maxPerCall: 10_000n, maxTotal: 20_000n }, // native SOL, in lamports + ], + maxGasPerCall: parseUnits('1', 18), + validUntil: now + 30 * 86400, + allowedCalls: [ + { target: program, // the program address + selector: 'receive_sol(u64)', // instruction name and argument types + pins: [ + { arg: 0, max: 10_000n }, // the amount + { account: 1, expected: recipient }, // account 1 must be this address + { account: 2, expected: PushChain.CONSTANTS.AGENTIC.WALLET }, // account 2 must be this wallet (its CEA on Solana) + ] }, + ], +} +``` + +The selector is the instruction's name with its argument types, the same idea as an EVM function signature. It is enough to identify the instruction and to locate each argument, so a rule carries no IDL. A program that does not follow the Anchor naming is written with a raw hex selector, as on EVM. + +A Solana instruction carries two separate lists: its arguments (the values in the instruction data) and its accounts (the addresses it touches, passed beside the data). A pin says which list it means: `arg` is a position in the arguments and `account` is a position in the accounts list, both counted from 0. EVM rules only use `arg`, because an EVM call carries its addresses as arguments. + +Tokens on Solana are not held at the wallet's own address. For each token it holds, the wallet has a separate token account, whose address is derived from the wallet and the token. To require that an account is the wallet's token account for a given token, the pin names the token as well: + +```tsx +{ account: 1, expected: PushChain.CONSTANTS.AGENTIC.WALLET, token: MOVEABLE.TOKEN.SOLANA_DEVNET.USDT } // account 1 must be this wallet's USDT token account +``` + +Without `token`, `WALLET` on an account means the wallet's CEA itself, which is where native SOL sits. + +The IDL is still used where it is used today: when the call data for a send is built with `PushChain.utils.helpers.encodeTxData`, where it is passed in place of an ABI. + +Accepted for v1: + +- **A Solana rule reads back in the form it was written.** Positions go in and positions come out, so the read, change, pass back test of 6.d holds for Solana too. +- **An agent sends one Solana instruction per transaction.** Arrays of instructions are not supported on the agent door. +- **Only instructions with fixed-size arguments can be put under a rule.** Numbers up to u64, public keys, booleans and fixed-length arrays work, with top-level, non-optional accounts. Lists, strings, optional values and nested structs are rejected before signing. A deposit of an amount works; a routed swap that takes a list of hops does not. + +### 6.j Contract changes these depend on + +All on [1. AGW Contract Changes (nomenclature standard + change set)](https://app.notion.com/p/1-AGW-Contract-Changes-nomenclature-standard-change-set-3e9188aea7f4813aa31fc95ceb4e684d?pvs=21), section 6. + +| Page 1 item | Contract change | Needed by | +| --- | --- | --- | +| 6.1 | The wallet approves the gateway for the exact amount inside each outbound | 6.g | +| 6.2 | One factory call that deploys the wallet and grants its rules | 6.b | +| 6.3 | Pins on EVM destination calls in the rules policy | 6.a | +| 6.4 | `ref` removed from `grantRules` | 6.b, 6.c, 6.d | +| 6.5 | A cap of 0 means nothing moves | 6.b | + +### 6.k Still open + +1. Whether the rules policy can enforce the wallet token account pin of 6.i in every case. To confirm with the contracts owner. + +### 6.l Response fields and error codes added by the first implementation + +The first implementation adds response fields and error codes that are not in 3.f. They are accepted as listed here. Four codes are removed, each for the reason given below. + +**The `agentic` object on a response.** Every send made as the wallet carries an `agentic` object on its response, so the caller can see which wallet, which door and which rule the send used. Only the fields that apply to that send are present. + +```tsx +// tx.agentic, on the UniversalTxResponse of a send made as the wallet +{ + wallet: '0xWallet', // the AGW + door: 'agent', // 'owner' or 'agent' + rulesId: '0x9c1e...', // the rule used; agent door only + chainNamespace: 'eip155:11155111', // destination chain of a cross-chain send + destinationAccount: '0xCEA...', // the wallet's CEA on that chain + destinationCalls: [{ to, data, value }], // the ordered calls run on an EVM destination + destinationInstruction: { program, data, accounts }, // the instruction run on Solana + destinationTransfer: { recipient, token, amount }, // a plain transfer of SOL or a token on Solana + nativeCalls: [{ to, data, value }], // the ordered calls of a batch on Push + rawTo: '0xWallet', // what the signer's transaction actually called + rawData: '0x...' // the calldata it actually carried +} +``` + +**Error codes that stay.** All are thrown before anything is signed, unless the row says otherwise. + +| Code | Thrown when | +| --- | --- | +| `INDEX_RACE` | Another `create` took the wallet slot first. Nothing was committed; call `create` again | +| `NOT_WALLET_OWNER` | The signer tries to change a wallet it does not own | +| `READ_ONLY` | A client with no signer tries to write | +| `RULE_NOT_FOUND` | The rule id is not an enabled rule on the wallet | +| `INVALID_RULE` | A rule or a label is malformed, for example a label over 64 bytes | +| `AMBIGUOUS_RULE` | More than one enabled rule matches the agent and the destination chain. The SDK does not pick one | +| `RULE_READ_FAILED` | The rules could not be read from the chain, so the SDK does not send | +| `INCONSISTENT_READ` | Two reads from the chain disagree with each other, so the SDK does not act on them | +| `AGENT_GAS_INSUFFICIENT` | The agent's own Push account has no PC for gas. The wallet's PC pays for the outbound, not for the agent's gas | +| `WALLET_BALANCE_INSUFFICIENT` | The wallet does not hold enough PC or enough of the token for the send | +| `CAPABILITY_UNAVAILABLE` | The network cannot do what was asked, for example a batch as the agent where no atomic batch is available | +| `RECEIPT_UNAVAILABLE` | After sending: the transaction was submitted but its receipt could not be read. It may still land | +| `RECEIPT_MISMATCH` | After sending: the receipt does not match what was sent, for example rule ids in a different order | + +**Error codes that are removed.** + +| Code | Why it goes | +| --- | --- | +| `CREATE_PARTIAL` | `create` is one transaction (6.b), so it cannot end half done | +| `GATEWAY_ALLOWANCE_INSUFFICIENT` | The wallet approves the gateway itself (6.g, page 1 item 6.1) | +| `GENERATION_UNSUPPORTED` | There are no earlier wallet versions to support | +| `RULE_LIMIT_EXCEEDED` | Only raised by a local preview of a Solana send. The on-chain rules policy is the only rule checker (2.a), so this is not a public code | + +**`DUPLICATE_RULE` is restored.** 3.f lists `DUPLICATE_RULE`: two rules for the same agent and chain are rejected before signing. The first implementation does not have it and only notices the overlap later, when the agent sends (`AMBIGUOUS_RULE`). The check goes back into `create` and `rules.add`. `AMBIGUOUS_RULE` stays for a wallet that already has overlapping rules. + +**Fields on the error classes.** `AgenticError` also carries `details` and `cause`, and both stay. `AgenticRevertError` carries `transactionHashes` and `pendingTransactionHash`, and a returned `tx` carries an `atomic` flag. These three report a write that was split across several transactions. They are removed once every write is a single transaction (6.b). + +The progress events of the first implementation are the ones in 3.f, with nothing added. + +### 6.m Delete rules - `w.rules.delete` (renamed from `w.rules.revoke`) + +Removes some rules by id, or all of them in one atomic call. This is 1.m under a new name. The call shape and the result are unchanged. + +```tsx +// Function +const tx = await w.rules.delete(rulesIds, { options? }) +const tx = await w.rules.delete({ all, progressHook? }) + +// Usage and Params +const some = await w.rules.delete(['0x9c1e...', '0x7d3a...']); // delete these rules +const all = await w.rules.delete({ all: true }); // delete every rule on the wallet +const tracked = await w.rules.delete(['0x9c1e...'], { progressHook: (p) => console.log(p.id) }); // with progress events +// rulesIds Hex[], required unless all is set the rules to delete +// options.progressHook function, optional progress events, AGENTIC-TX-105; default none +// all true, required unless rulesIds given delete every rule on the wallet in one atomic call +// progressHook function, optional same events, in the { all: true } form; default none + +// Returns +// { hash, origin, from, to, blockNumber, wait() } +{ + hash: '0x8e01...', + origin: 'eip155:11155111:0x31dC...', // the owner's key, CAIP-10 + from: '0xFd6C2fE69bE13d8bE379CCB6c9306e74193EC1A9', // the owner's Push account + to: '0x2Fd904d6f2C0b34d58426C8Ae9c5267E845CE98f', // the wallet + blockNumber: 1512n, + wait // await tx.wait() for the receipt; status lives on the receipt +} +``` + +What changed from 1.m: + +- **The method is delete, not revoke.** The handle now reads `rules.add`, `rules.update`, `rules.delete`. Delete is also what happens on-chain: the wallet removes the rule from the session engine for good. A deleted rule cannot be switched back on, and granting the same rule again produces a new `rulesId`. +- **The bare-call error is renamed.** A bare `delete()` still throws. The code is `DELETE_NEEDS_TARGET` (was `REVOKE_NEEDS_TARGET`). +- **Contract names do not change.** The wallet functions stay `revokeRules` and `revokeAllRules`, the event stays `RulesRevoked`, and the checkpoint kind stays `RULES_REVOKED`. `w.checkpoints()` returns that kind as the contract records it. + +# 7. Changes proposed on 12 Oct 2026: Presets + +A preset is a ready-made set of rules for a common use case, such as trading on popular DEXes. The wallet UI and developers both read presets from the SDK, so there is one source for them. A preset only produces rules. The rules are then passed to `client.agentic.create` in the normal way, and can be edited before that. App ABIs are not part of presets and stay in the wallet UI, because the UI can update them without an SDK release. + +List of changes: + +- New constants: `PushChain.CONSTANTS.AGENTIC.PRESETS.CATEGORY` with `DEXES`, `LENDING` and `PREDICTION`. An app level (`PushChain.CONSTANTS.AGENTIC.PRESETS.APP`) can be added later without changing the functions. +- New function: `PushChain.utils.agentic.presets.list`, which lists every preset the SDK ships. +- New function: `PushChain.utils.agentic.presets.get`, which returns the rules for one preset. +- This brings back `PushChain.CONSTANTS.AGENTIC` members beyond `WALLET` and the `PushChain.utils.agentic` namespace, for presets only. Both were dropped earlier on this page (6.h). + +### 7.a Preset constants - `PushChain.CONSTANTS.AGENTIC.PRESETS` + +```tsx +PushChain.CONSTANTS.AGENTIC.PRESETS.CATEGORY.DEXES +PushChain.CONSTANTS.AGENTIC.PRESETS.CATEGORY.LENDING +PushChain.CONSTANTS.AGENTIC.PRESETS.CATEGORY.PREDICTION +// later: PushChain.CONSTANTS.AGENTIC.PRESETS.APP. +``` + +The constants object must be enumerable so that tools which iterate constants can list it. + +### 7.b List available presets - `PushChain.utils.agentic.presets.list` + +Returns every preset the SDK ships, so a UI can show them as cards and a developer can discover them. + +```tsx +// Function +const res = PushChain.utils.agentic.presets.list({ options? }) + +// Usage and Params +const { presets } = PushChain.utils.agentic.presets.list(); // every preset the SDK ships +// options.type string, optional 'CATEGORY' today, 'APP' later; omit to list everything + +// Returns +// { presets: Preset[] } +{ + presets: [ + { + type: 'CATEGORY', // later 'APP' + constant: PushChain.CONSTANTS.AGENTIC.PRESETS.CATEGORY.DEXES, + name: 'Popular DEXes', + chains: ['eip155:11155111', 'eip155:84532'] // chains this preset has rules for (Ethereum Sepolia, Base Sepolia) + } + ] +} +``` + +A preset with an empty `chains` list has nothing behind it yet (`PREDICTION` today, since its main apps are on a chain Push does not support yet), and the wallet UI should hide it. + +### 7.c Get the rules of a preset - `PushChain.utils.agentic.presets.get` + +Returns one rule per chain for the chosen preset. Each rule already contains the allowed contracts, the allowed calls with their full signatures, and the pins that keep funds going back to the wallet. The agent, assets and expiry are optional: pass them to get rules that are ready for `create`, or leave them out to pre-fill a review screen and add them later. + +```tsx +// Function +const res = PushChain.utils.agentic.presets.get(preset, { options? }) + +// Usage and Params +const { rules } = PushChain.utils.agentic.presets.get( + PushChain.CONSTANTS.AGENTIC.PRESETS.CATEGORY.DEXES, // a category constant now, an app constant later + { + chainNamespace: PushChain.CONSTANTS.CHAIN.ETHEREUM_SEPOLIA, // optional, omit to get every chain of the preset + agent: '0xAgentOnPush', // optional, the agent's Push address, applied to every rule + assets: [{ chainNamespace, token, maxPerCall, maxTotal }], // optional, each asset is placed on the rule of its chain + validUntil: now + 30 * 86400, // optional, applied to every rule; omit to set it later + } +); + +await client.agentic.create('My DEX agent', { rules }); + +// Returns +// { rules: Rule[] }, one rule per chain, in the same shape client.agentic.create takes +{ + rules: [ + { + agent: '0xAgentOnPush', + chainNamespace: 'eip155:11155111', + assets: [{ token: '0x1c7D...7238', maxPerCall: 100000000n, maxTotal: 1000000000n }], // from options.assets, without its chainNamespace + validUntil: 1767225600, + allowedCalls: [ + { + target: '0x...', + selector: 'exactInputSingle((address,address,uint24,address,uint256,uint256,uint160))', + pins: [{ arg: 3, expected: PushChain.CONSTANTS.AGENTIC.WALLET }], + app: 'Uniswap V3', // display only, ignored by create + label: 'Swap exact input' // display only, ignored by create + } + // plus one approve(address,uint256) per asset, spender pinned to the app's contract (see Behaviour) + ] + } + ] +} +``` + +**Behaviour** + +| Case | What happens | +| --- | --- | +| `chainNamespace` omitted | One rule is returned for every chain the preset covers. | +| `agent`, `assets` or `validUntil` omitted | The rule is returned without that field. The caller adds it before `create`, and `create` rejects a rule with no agent as it already does. | +| `assets` passed | Each asset is placed on the rule of its chain. If `chainNamespace` is set in the options, the `chainNamespace` on each asset can be left out. For each asset, an approve call is added to that rule, with the spender pinned to the app's contract on that chain, because a swap or deposit fails without it. | +| Asset passed without a cap | Proposed: `get` throws. An omitted cap means 0 in the rules policy, so the rule would allow nothing, and a preset should never silently produce a rule that cannot act. | +| Selectors | Always the full signature, never the bare name, because apps overload function names (for example two different execute functions on the same router). | +| Grouping | One rule per chain per category, not one rule per app. Each category stays at two or three apps per chain so the rule stays inside the 32 allowed calls limit of a universal rule. | +| Display fields | `app` and `label` on each allowed call are for showing names in a UI. `create` ignores them. | + +### 7.d Notes for the wallet UI + +- Call `get` with only the preset to pre-fill the review screen, then let the user add the agent, tokens, limits and expiry. +- A blank limit shown as infinity in the UI must be sent as an explicit maximum value. Leaving the cap out means 0, not unlimited. +- The preset data (contract addresses, calls and pins) ships inside the SDK. An app upgrade becomes a new app entry, and the old one keeps working because the older contract still exists. + +### 7.e Open questions + +- Can a pin's arg index reach a field inside a struct argument? The Uniswap `exactInputSingle` example depends on it, because the recipient sits inside a struct. (Rules policy contract owner) +- Routers that hide the recipient inside encoded bytes, such as Uniswap Universal Router `execute`, cannot be pinned, so they should not be preset targets. Confirm the list of apps and functions per chain with this in mind. (SDK owner with the rules policy contract owner) +- Is the agent one Push address for every chain, including Solana rules? If not, `agent` becomes a per-chain map. (SDK owner) +- Should `get` throw when an asset has no cap, as proposed above? (Page owner) +- First preset list for testnet: which apps on which chains for `DEXES` and `LENDING`. (SDK owner with the rules policy contract owner) \ No newline at end of file diff --git a/plan/agw/pending-items.md b/plan/agw/pending-items.md new file mode 100644 index 00000000..4d9831d1 --- /dev/null +++ b/plan/agw/pending-items.md @@ -0,0 +1,20 @@ +# AGW SDK pending items + +October 12, 2026. The newly downloaded SDK sections 6/7 supersede the earlier `actions[]` proposal and multiple-rule creation decision. See [the item-by-item feedback list](section6-action-items.md). + +| Item | Owner / dependency | Completion condition | +| --- | --- | --- | +| Exact outbound allowance inside both wallet doors | Contract team, §6.1 | Verified source/ABI/deployment; SDK can then remove manual-allowance preflight | +| Atomic factory create and initial grants | Contract team, §6.2 | Verified entry points, owner/signed variants and index-race behavior; remove partial recovery only then | +| General EVM destination EQ/MAX pins | Contract team, §6.3 | Deployed policy encoding; currently only one WALLET beneficiary pin is supported | +| Native 1..32 calls in spec versus deployed maximum 8 | Product/contracts | Align spec or deploy increased ceiling; SDK enforces 8 now | +| Presets (§7) | Product/app catalog | Approved apps/addresses/chains, struct-field pins and multi-spender approval representation; framework is implemented, missing caps default to zero, incomplete results are typed templates | +| ABI compound argument reconstruction | Product/spec metadata | Define struct fields and how layouts survive reads; unsupported layouts fail explicitly | +| Native historical lifetime limits | Spec/migration | Define a lossless public representation if these old grants must be editable; never drop their restrictions silently | +| Revert credit | Push-core executor | Executor invokes creditRevert; verify restored spend independently | +| Delivery/terminal latency | Platform | Resolve delayed terminal status and bounded polling expectations | +| Single clean live run / new-contract acceptance | SDK, then new deployment | Current 68 cases pass across the full run plus targeted rerun; a single clean full invocation and new-contract acceptance remain distinct | + +User decisions recorded October 12: multi-action native `spent` uses per-action entries. Decoded Solana rules may use an explicit raw form for lossless get→update; authored rules use arg/account positions. These no longer require clarification. + +The first-use EVM gas default is being fixed in the SDK and is no longer an external core/gateway question. `setLabel` already exists on v5; direct invocation requires no contract change. diff --git a/plan/agw/questions-harsh.md b/plan/agw/questions-harsh.md index 612b716a..c7705a93 100644 --- a/plan/agw/questions-harsh.md +++ b/plan/agw/questions-harsh.md @@ -1,25 +1,15 @@ -# AGW SDK — product decisions confirmed +# AGW SDK — remaining preset catalog decisions -Updated October 7, 2026 from Shoaib’s relayed team answers and SDK-owned decision approval. There are no remaining product questions in this document. +Updated October 12, 2026 after the user authorized the section-7 framework. Local draft; nothing sent. - -## 1–2. Defaults and token model +## Catalog to provide later -Omitted native `maxValuePerCall` and `maxValueTotal` are `0`: no native PC value allowance. Retain the current `assets[]` model and independent per-token budgets. The SDK matches these decisions. +Which verified apps, functions, deployed addresses and chains should ship for `DEXES` and `LENDING`? The framework is implemented, but all categories currently have empty `chains` lists. UI callers should hide them. - -## 3. Solana rules +The contract/SDK review of those entries must settle tuple-field positions and how multiple apps can safely receive approvals for the same token. The framework rejects ambiguous approval combinations instead of generating unrestricted approvals. General EVM pins also need the pending policy deployment. -Use named inputs from an IDL. The SDK now exposes `SolanaRule`, compiles supported Anchor layouts, derives wallet accounts, and returns exact decoded constraints. Unsupported layouts fail explicitly. See the [consumer guide](../../packages/core/AGW.md#solana-rules-using-named-idl-inputs). +## Decisions already made — no repeated question - -## 4. Native/EVM argument restrictions +The user chose zero defaults for either omitted preset asset cap and deferred the catalog. Omitting agent or expiry returns a typed `PresetRuleTemplate`; providing both yields `Rule[]`. Per-action native spend and raw decoded Solana get→update were already approved. The new preset namespace contains only `list/get`; encoding and ID helpers remain internal. -Keep both ABI argument-index and raw-offset inputs, with exact offsets on reads. Shoaib approved this SDK-owned choice. Inputs that specify both forms are rejected; normal examples should prefer argument indexes. - - -## 5. Contract validation and SDK errors — clarified - -The intended behavior is that the existing contract rejects unauthorized functions/actions under the supplied rule, and the SDK maps those errors. This does not request automatic rule selection or a new contract interface. The SDK retains `AMBIGUOUS_RULE` when multiple enabled rules match the agent and chain, without submitting a transaction. No caller-facing rule selector is being added. - -Rule `ref` is removed from scope; editable labels are delivered and implemented against v5. [Zaryab delivery items](questions-zaryab.md). +[Implementation and acceptance](section7-presets.md). diff --git a/plan/agw/questions-zaryab.md b/plan/agw/questions-zaryab.md index dc44347a..cf31cb1c 100644 --- a/plan/agw/questions-zaryab.md +++ b/plan/agw/questions-zaryab.md @@ -1,12 +1,18 @@ -# AGW SDK — contract delivery status +# AGW SDK — contract delivery and confirmation -Updated October 7, 2026 after the v5 deployment. **No remaining standalone AGW contract question needs an answer from Zaryab.** +October 12, 2026. Local draft; nothing has been sent. Source: [contract feedback §6](https://app.notion.com/p/pushprotocol/1-AGW-Contract-Changes-nomenclature-standard-change-set-3e9188aea7f4813aa31fc95ceb4e684d). The user confirms these changes are not deployed. Existing v5 labels and ref removal are already delivered. - - -The label interface and compatible deployment are delivered in `deploy-agw@bd230d2` (deployed source `2e61e13`). The SDK now uses the new factory, reads stored labels and implements owner-only `setLabel` with empty reset and the 64-byte limit. [Deployment verification](research/deployment-review-2026-10-07-v5/README.md) · [SDK migration and acceptance](research/v5-implementation-2026-10-07/README.md). +## Delivery already requested by Harsh - -Named-IDL Solana authoring, removal of rule `ref`, zero native PC defaults and the existing token model remain settled. Native/EVM inputs accept argument indexes or raw offsets. The SDK retains AMBIGUOUS_RULE; the contract validates the supplied rule. No automatic-selection interface change is requested. +- **§6.1:** exact gateway approval inside each outbound, on both doors, cleared afterward. SDK allowance checks stay until the implementation/deployment is verified. +- **§6.2:** atomic factory create plus grants. Supply the final ABI and owner/signed entry points, preserving the intended wallet/index binding. Partial-create recovery stays until every supported owner uses the atomic path. +- **§6.3:** general EQ/MAX pins on EVM destination calls. SDK supports the current single WALLET pin and rejects other destination pins until the new policy is available. -Push-core spend credit and bridge retry timing remain separate downstream follow-ups. They do not block the label integration. +These are delivery dependencies, not requests to reconsider the agreed design. Deployment addresses do not need to be supplied again here; the SDK will verify the updated address book and implementation when notified. + +## Confirmations still needed + +1. **Native call ceiling:** SDK §6.h says 1..32 allowed calls; deployed AGW permits eight native actions. Should this deployment increase the native ceiling, or should the spec explicitly retain eight? +2. **Solana wallet-token-account pins:** SDK §6.k asks whether the policy enforces these in every supported case. The SDK derives the wallet CEA and token-program-specific ATA and has local/live SPL evidence; please confirm the intended policy boundary beyond those tested cases. + +Push-core revert credit and platform terminal-status latency remain downstream items, separate from this contract change set. [Full implementation/deployment boundary](section6-action-items.md). diff --git a/plan/agw/research/native-multi-action-e2e-2026-10-12/README.md b/plan/agw/research/native-multi-action-e2e-2026-10-12/README.md new file mode 100644 index 00000000..612163af --- /dev/null +++ b/plan/agw/research/native-multi-action-e2e-2026-10-12/README.md @@ -0,0 +1,43 @@ +# Native multi-action SDK acceptance — October 12, 2026 + +Working branch: `feat/agw-sdk-v4`, after the user's v5 merge (`7115c594`). Contract fixture: deployed Donut v5 source `2e61e13`. All work in this pass remains local; no commit, push, PR update or merge was performed by the agent. + +## Changes + +Ten opt-in scenarios are added in `packages/core/__e2e__/agw/native-multi-action.spec.ts`. The AGW group now contains **68 scenarios / 15 files / 68 tests**. Default `all` remains **76 / 40 / 81**. + +1. Grant/read two native actions under one ID, recreate decoded terms, execute both, and verify replay identity. +2. Reject wrong recipient pins, excess amounts and an ungranted selector with unchanged balances, both action configs and signer nonce. +3. Exhaust PC/call capacity in one action while the token action remains usable; verify independent counters and amount totals. +4. Execute a mixed PC/token atomic batch through native EIP-7702, checking sender identity, both spends and replayed call metadata. +5. Reject a failing second item through SDK simulation, then submit the same encoded mixed batch as a bounded raw transaction through the already delegated agent. Its mined revert must have no logs and restore both balances and action counters. +6. Replace a two-action rule, verify six checkpoint ticks and fresh counters, then remove an action and prove it is no longer authorized. +7. Inject a real token spend in the second action between replacement reads and execution; require `SpentMismatch`, unchanged grant nonce/checkpoints and original rule, then a successful fresh retry. +8. Accept eight actions; reject empty, duplicate, mixed-shape and ninth-action inputs before signing. +9. Expire the first action while the later-expiring second action remains usable under the same ID. +10. Return structured `INVALID_RULE` for malformed action entries and missing/expired rule expiry, with no new wallet or owner nonce change. + +The shared state helper reads every action's policy config at one pinned block. Tests compare actual balances, individual counters, grant nonces, checkpoint counts and receipts instead of relying on SDK return values alone. Each test creates its own wallets and can be selected independently. + +## Review fixes exercised by the tests + +- `nativeActionsOf` checks that every action is an object before reading it, so `actions: [null]` produces `AgenticError(INVALID_RULE)` rather than a JavaScript `TypeError`. +- Required rule-level expiry is validated even when every action overrides it. Four added unit regressions cover null/non-object entries and missing/expired rule expiry. +- The guide now states that replacement of N old native actions adds **N + 4** checkpoints. Universal replacement still adds five. +- The public multi-action type remains pending product sign-off. Test completion does not constitute that approval. + +## Validation + +- Full units: **2,034 passed, 12 skipped, 0 failed**. Focused AGW units: **255 passed**. +- Actual pinned v5 contract harness: **97 passed**, 13 suites, including the seven prior multi-action cases. +- Spec/local typechecks, build, 11 consumer guide blocks, CJS/ESM package/declaration checks and API comparison passed. +- Registration and full-group funding preflight `--dry-run` passed. The live run selects only this new ten-case file. +- Final E2E/state-helper lint has no errors or warnings. The native codec retains its previously reported unused destructured `_agent` warning. + +Live Donut: **10/10 passed in one invocation** (585 seconds). [Exact live log](logs/live-donut.log), [transaction and state evidence](live-evidence.jsonl), [validation summary](validation.json). No scenario was skipped or rerun to obtain this result. The final test file additionally bounds the expiry wait to two minutes; the successful run did not require that timeout. + +## Scope and funding + +The existing verified v5 manifest gates setup. No test contract is deployed. Fixtures use one fresh agent funded with at most **0.5 PC**, fresh AGWs funded with **10 PC wei** and **20 raw pETH units** each, and existing Donut token/executor contracts. The intentionally failing raw batch has a **600,000-gas** ceiling and spends the fresh agent's gas only. Its outer encoding is the same ERC-7821 execute shape used by the SDK. + +The second-action race injects a real public SDK send immediately before owner submission; the stale owner operation is refused during simulation. The expiry wait is bounded to two minutes. No external-chain delivery or contract deployment is needed for these native cases. Existing EVM/SVM and other live groups were not rerun in this pass; this is not a single 68-case run. diff --git a/plan/agw/research/native-multi-action-e2e-2026-10-12/api-comparison.json b/plan/agw/research/native-multi-action-e2e-2026-10-12/api-comparison.json new file mode 100644 index 00000000..98c958a4 --- /dev/null +++ b/plan/agw/research/native-multi-action-e2e-2026-10-12/api-comparison.json @@ -0,0 +1,11644 @@ +{ + "baseline": "b1597b91a25dbf7f691f589b4e1e154add604315", + "head": "7115c59474af6304905ad3e4466732b0530dc791", + "compiledMatchesSource": true, + "initializeSignatureChanged": false, + "addedExports": [ + "DecodedSolanaRule", + "NativeAction", + "NativeMultiRule", + "NativeSingleRule", + "SolanaRule", + "SvmAccountRef", + "SvmFieldConstraint", + "SvmInstructionRule" + ], + "removedExports": [], + "changedAgwTypes": [ + "AgenticError", + "AGENTIC_ERROR_CODE", + "NativeRule", + "AllowedCall", + "UniversalRule", + "RulesRecord", + "AgenticTxMetadata" + ], + "publicTypeChanges": [ + "AGENTIC_ERROR_CODE", + "AgenticError", + "AgenticErrorCode", + "AgenticNetworkConstants", + "AgenticTxMetadata", + "AllowedCall", + "NativeAction", + "NativeMultiRule", + "NativeRule", + "NativeSingleRule", + "SolanaRule", + "DecodedSolanaRule", + "SvmInstructionRule", + "SvmAccountRef", + "SvmFieldConstraint", + "Rule", + "RulesRecord", + "UniversalRule" + ], + "transactionMethodChanges": [], + "instanceMethodChanges": [], + "agwConstantsChanged": true, + "before": { + "exports": [ + "AGENTIC_ERROR_CODE", + "AccountRole", + "AccountStatus", + "AccountType", + "AgenticAddress", + "AgenticDoor", + "AgenticError", + "AgenticErrorCode", + "AgenticHex", + "AgenticNamespace", + "AgenticNetworkConstants", + "AgenticProgressHook", + "AgenticRevertError", + "AgenticTxMetadata", + "AgenticWallet", + "AllowedCall", + "AssetCap", + "BatchReadResponse", + "BuildReadSpecParams", + "CHAIN", + "CONTRACT_REQUEST_STATUS", + "CascadeCompletionResult", + "CascadeHopInfo", + "CascadeProgressEvent", + "CascadeTrackOptions", + "CascadedTxResponse", + "ChainSource", + "ChainTarget", + "Checkpoint", + "CheckpointKind", + "ConversionQuote", + "CreateOptions", + "CreateResult", + "DEFAULT_MAX_PC_FOR_GAS_BUFFER_BPS", + "DecodedErrorPayload", + "DecodedReadResult", + "DerivedExecutorAccount", + "EncodedReadQuery", + "EvmReadQuery", + "ForeignChainNamespace", + "FulfilOutcome", + "FundsToken", + "InsufficientPC20BalanceError", + "InvalidPC20AddressError", + "InvalidPC20MetadataError", + "InvalidReadQueryError", + "InvalidReadSpecError", + "MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT", + "MaxPCForGasCapFromNativeValueInput", + "MaxPCForGasCapInput", + "MaxPCForGasCapQuote", + "MultiChainTxResponse", + "NativeRule", + "OutboundTxDetails", + "PC20AddressResult", + "PC20AmbiguousAddressError", + "PC20Error", + "PC20ExpectedButPRC20Error", + "PC20ExportRevertedError", + "PC20FactoryMismatchError", + "PC20RegistryEntry", + "PC20RegistryMismatchError", + "PC20TokenChainMismatchError", + "PC20TokenReference", + "PC20UnknownChainNamespaceError", + "PC20UnsafeEmptyPayloadError", + "PC20WrapperNotRegisteredError", + "PC20WrapperPredictionUnavailableError", + "ParsedReadRequest", + "PreparedRead", + "PreparedUniversalTx", + "PushChain", + "PushChainBatchExecutionError", + "PushChainExecutionError", + "PushChainInitializeOptions", + "READ_ERROR_CODE", + "READ_OUTCOME", + "READ_STATUS", + "ReadCallback", + "ReadCallbackOptions", + "ReadChain", + "ReadDecodeError", + "ReadDestination", + "ReadExecuteOptions", + "ReadFees", + "ReadHeightUnavailableError", + "ReadLifecycleOptions", + "ReadNotFoundError", + "ReadOptions", + "ReadPreflight", + "ReadPrepareOptions", + "ReadQuery", + "ReadQueryOptions", + "ReadRef", + "ReadRegistryUnavailableError", + "ReadResponseTuple", + "ReadResultShape", + "ReadSpec", + "ReadSpecTuple", + "ReadSpecViolation", + "ReadStateError", + "ReadTimeoutError", + "ReadTrackOptions", + "ReadValue", + "ReadWeb2Options", + "ReceiptLike", + "RescueFundsParams", + "ResolvedAccount", + "ResolvedControllerAccounts", + "ResolvedDestination", + "Rule", + "RulesRecord", + "Selector", + "SignAuthorizationParams", + "SignedAuthorization", + "SimulateReadResult", + "SvmExecutePayloadFields", + "SvmGatewayAccountMeta", + "SvmReadQuery", + "TERMINAL_READ_STATUSES", + "TransactionRoute", + "TransactionRouteType", + "UEAStatus", + "UNIVERSAL_CALLBACK_EVM", + "UNIVERSAL_READ_REGISTRY_EVM", + "UNIVERSAL_READ_STATUS", + "UniversalAccount", + "UniversalExecuteParams", + "UniversalOutboundTxRequest", + "UniversalReadResponse", + "UniversalRule", + "UniversalSigner", + "UniversalSignerSkeleton", + "UniversalTo", + "UnsupportedPC20DestinationError", + "UnsupportedReadDestinationError", + "ValidateReadCall", + "WaitForOutboundOptions", + "WalletInfo", + "WalletSummary", + "Web2Extract", + "Web2ReadQuery", + "Web2ValueType", + "buildErc20WithdrawalMulticall", + "buildMigrationPayload", + "buildReadSpecFromPreflight", + "chainSupportsCEA", + "chainSupportsOutbound", + "decodeReadResult", + "detectRoute", + "encodeReadQuery", + "encodeSvmExecutePayload", + "getAllCEAAddresses", + "getCEAAddress", + "getCEAFactoryAddress", + "getPushAccountForCEA", + "inferResultShape", + "isCEA", + "isChainTarget", + "isPC20Reference", + "isSvmChain", + "isValidSolanaHexAddress", + "parseFulfilOutcome", + "parseReadRequestsFromReceipt", + "parseUEAVersion", + "quoteMaxPCForGasCap", + "quoteMaxPCForGasCapFromNativeValue", + "resolveDestination", + "sizeCallbackBudget", + "toCallData", + "toReadQuery", + "toRequestIdHex", + "validateReadSpec" + ], + "agw": { + "AgenticNamespace": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace", + "members": { + "create": { + "optional": false, + "readonly": false, + "type": "(label: string, options: import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions) => Promise" + }, + "derive": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n index?: number;\n}) => Promise<{\n address: `0x${string}`;\n deployed: boolean;\n index: number;\n}>" + }, + "list": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n wallets: import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary[];\n}>" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "(address: `0x${string}`) => import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet" + } + } + }, + "AgenticWallet": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "checkpoints": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n sinceBlock?: bigint;\n}) => Promise<{\n checkpoints: import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint[];\n}>" + }, + "info": { + "optional": false, + "readonly": false, + "type": "() => Promise" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n owner: `0x${string}`;\n}>" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "{\n add(rules: import(\"sdk/src/lib/agentic/agentic.types\").Rule[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise<{\n rulesIds: `0x${string}`[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n get(rulesId: `0x${string}`): Promise;\n list(): Promise<{\n rules: import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord[];\n }>;\n revoke(rulesIds: `0x${string}`[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n revoke(params: {\n all: true;\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n update(params: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n rules: {\n rule: import(\"sdk/src/lib/agentic/agentic.types\").Rule;\n rulesId: `0x${string}`;\n }[];\n }): Promise<{\n rules: {\n replaced: `0x${string}`;\n rulesId: `0x${string}`;\n }[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n}" + }, + "setLabel": { + "optional": false, + "readonly": false, + "type": "(label: string, opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n}) => Promise" + } + } + }, + "AgenticError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"CREATE_PARTIAL\" | \"DUPLICATE_RULE\" | \"FROM_NOT_ALLOWED\" | \"GATEWAY_ALLOWANCE_INSUFFICIENT\" | \"GENERATION_UNSUPPORTED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"REVOKE_NEEDS_TARGET\" | \"RULE_LIMIT_EXCEEDED\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"" + }, + "details": { + "optional": true, + "readonly": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "AgenticRevertError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticRevertError", + "members": { + "agenticCode": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + } + } + }, + "AGENTIC_ERROR_CODE": { + "type": "{\n readonly AGENT_GAS_INSUFFICIENT: \"AGENT_GAS_INSUFFICIENT\";\n readonly AGENT_IS_OWNER: \"AGENT_IS_OWNER\";\n readonly ASSET_CHAIN_MISMATCH: \"ASSET_CHAIN_MISMATCH\";\n readonly CAPABILITY_UNAVAILABLE: \"CAPABILITY_UNAVAILABLE\";\n readonly CREATE_PARTIAL: \"CREATE_PARTIAL\";\n readonly DUPLICATE_RULE: \"DUPLICATE_RULE\";\n readonly FROM_NOT_ALLOWED: \"FROM_NOT_ALLOWED\";\n readonly GATEWAY_ALLOWANCE_INSUFFICIENT: \"GATEWAY_ALLOWANCE_INSUFFICIENT\";\n readonly GENERATION_UNSUPPORTED: \"GENERATION_UNSUPPORTED\";\n readonly INCONSISTENT_READ: \"INCONSISTENT_READ\";\n readonly INDEX_RACE: \"INDEX_RACE\";\n readonly INVALID_RULE: \"INVALID_RULE\";\n readonly NO_RULES_FOR_CHAIN: \"NO_RULES_FOR_CHAIN\";\n readonly NOT_AGENTIC_WALLET: \"NOT_AGENTIC_WALLET\";\n readonly NOT_ALLOWED_IN_AGENTIC_MODE: \"NOT_ALLOWED_IN_AGENTIC_MODE\";\n readonly NOT_OWNER_OR_AGENT: \"NOT_OWNER_OR_AGENT\";\n readonly NOT_WALLET_OWNER: \"NOT_WALLET_OWNER\";\n readonly READ_ONLY: \"READ_ONLY\";\n readonly RECEIPT_MISMATCH: \"RECEIPT_MISMATCH\";\n readonly RECEIPT_UNAVAILABLE: \"RECEIPT_UNAVAILABLE\";\n readonly REVOKE_NEEDS_TARGET: \"REVOKE_NEEDS_TARGET\";\n readonly RULE_LIMIT_EXCEEDED: \"RULE_LIMIT_EXCEEDED\";\n readonly RULE_NOT_FOUND: \"RULE_NOT_FOUND\";\n readonly RULE_READ_FAILED: \"RULE_READ_FAILED\";\n readonly TARGET_NOT_ON_RULE_CHAIN: \"TARGET_NOT_ON_RULE_CHAIN\";\n readonly WALLET_BALANCE_INSUFFICIENT: \"WALLET_BALANCE_INSUFFICIENT\";\n readonly WALLET_NOT_DEPLOYED: \"WALLET_NOT_DEPLOYED\";\n}", + "members": { + "AGENT_GAS_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\"" + }, + "AGENT_IS_OWNER": { + "optional": false, + "readonly": true, + "type": "\"AGENT_IS_OWNER\"" + }, + "ASSET_CHAIN_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"ASSET_CHAIN_MISMATCH\"" + }, + "CAPABILITY_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"CAPABILITY_UNAVAILABLE\"" + }, + "CREATE_PARTIAL": { + "optional": false, + "readonly": true, + "type": "\"CREATE_PARTIAL\"" + }, + "DUPLICATE_RULE": { + "optional": false, + "readonly": true, + "type": "\"DUPLICATE_RULE\"" + }, + "FROM_NOT_ALLOWED": { + "optional": false, + "readonly": true, + "type": "\"FROM_NOT_ALLOWED\"" + }, + "GATEWAY_ALLOWANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"GATEWAY_ALLOWANCE_INSUFFICIENT\"" + }, + "GENERATION_UNSUPPORTED": { + "optional": false, + "readonly": true, + "type": "\"GENERATION_UNSUPPORTED\"" + }, + "INCONSISTENT_READ": { + "optional": false, + "readonly": true, + "type": "\"INCONSISTENT_READ\"" + }, + "INDEX_RACE": { + "optional": false, + "readonly": true, + "type": "\"INDEX_RACE\"" + }, + "INVALID_RULE": { + "optional": false, + "readonly": true, + "type": "\"INVALID_RULE\"" + }, + "NO_RULES_FOR_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"NO_RULES_FOR_CHAIN\"" + }, + "NOT_AGENTIC_WALLET": { + "optional": false, + "readonly": true, + "type": "\"NOT_AGENTIC_WALLET\"" + }, + "NOT_ALLOWED_IN_AGENTIC_MODE": { + "optional": false, + "readonly": true, + "type": "\"NOT_ALLOWED_IN_AGENTIC_MODE\"" + }, + "NOT_OWNER_OR_AGENT": { + "optional": false, + "readonly": true, + "type": "\"NOT_OWNER_OR_AGENT\"" + }, + "NOT_WALLET_OWNER": { + "optional": false, + "readonly": true, + "type": "\"NOT_WALLET_OWNER\"" + }, + "READ_ONLY": { + "optional": false, + "readonly": true, + "type": "\"READ_ONLY\"" + }, + "RECEIPT_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_MISMATCH\"" + }, + "RECEIPT_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_UNAVAILABLE\"" + }, + "REVOKE_NEEDS_TARGET": { + "optional": false, + "readonly": true, + "type": "\"REVOKE_NEEDS_TARGET\"" + }, + "RULE_LIMIT_EXCEEDED": { + "optional": false, + "readonly": true, + "type": "\"RULE_LIMIT_EXCEEDED\"" + }, + "RULE_NOT_FOUND": { + "optional": false, + "readonly": true, + "type": "\"RULE_NOT_FOUND\"" + }, + "RULE_READ_FAILED": { + "optional": false, + "readonly": true, + "type": "\"RULE_READ_FAILED\"" + }, + "TARGET_NOT_ON_RULE_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"TARGET_NOT_ON_RULE_CHAIN\"" + }, + "WALLET_BALANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"WALLET_BALANCE_INSUFFICIENT\"" + }, + "WALLET_NOT_DEPLOYED": { + "optional": false, + "readonly": true, + "type": "\"WALLET_NOT_DEPLOYED\"" + } + } + }, + "NativeRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "amount": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AmountLimit | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "maxCalls": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValuePerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxValueTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "pins": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ArgPin[] | undefined" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "AssetCap": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap", + "members": { + "maxPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/constants/tokens\").MoveableToken" + } + } + }, + "AllowedCall": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall", + "members": { + "beneficiary": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValue": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "`${string}(${string})` | `0x${string}`" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "UniversalRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall[]" + }, + "assets": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap[]" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "`eip155:${string}` | `solana:${string}`" + }, + "maxGasPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "RulesRecord": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "enabled": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "ref": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "rule": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule | import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule" + }, + "rulesId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "CreateOptions": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions", + "members": { + "progressHook": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook | undefined" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Rule[]" + } + } + }, + "CreateResult": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateResult", + "members": { + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "rulesIds": { + "optional": false, + "readonly": false, + "type": "`0x${string}`[]" + }, + "tx": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticTxMetadata": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticTxMetadata", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destinationAccount": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "destinationCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "door": { + "optional": false, + "readonly": false, + "type": "\"agent\" | \"owner\"" + }, + "nativeCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "rawData": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rawTo": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesId": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + } + }, + "publicSurface": { + "CHAIN": { + "type": "typeof import(\"sdk/src/lib/constants/enums\").CHAIN", + "members": { + "ARBITRUM_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA" + }, + "BASE_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA" + }, + "BNB_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET" + }, + "ETHEREUM_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET" + }, + "ETHEREUM_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA" + }, + "PUSH_LOCALNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET" + }, + "PUSH_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET" + }, + "PUSH_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET" + }, + "PUSH_TESTNET_DONUT": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET" + }, + "SOLANA_DEVNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET" + }, + "SOLANA_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET" + }, + "SOLANA_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET" + }, + "WEB2": { + "optional": false, + "readonly": false, + "type": "\"web2\"" + } + } + }, + "ConversionQuote": { + "type": "import(\"sdk/src/lib/constants/tokens\").ConversionQuote", + "members": { + "amountIn": { + "optional": false, + "readonly": false, + "type": "string" + }, + "amountOut": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rate": { + "optional": false, + "readonly": false, + "type": "number" + }, + "route": { + "optional": true, + "readonly": false, + "type": "string[] | undefined" + }, + "timestamp": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "UniversalSigner": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalSigner", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "signAndSendTransaction": { + "optional": false, + "readonly": false, + "type": "(unsignedTx: Uint8Array) => Promise" + }, + "signAuthorization": { + "optional": true, + "readonly": false, + "type": "((params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise) | undefined" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": true, + "readonly": false, + "type": "(({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise) | undefined" + } + } + }, + "UniversalAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "UniversalSignerSkeleton": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "signAndSendTransaction": { + "optional": false, + "readonly": false, + "type": "(unsignedTx: Uint8Array) => Promise" + }, + "signAuthorization": { + "optional": true, + "readonly": false, + "type": "((params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise) | undefined" + }, + "signerId": { + "optional": false, + "readonly": false, + "type": "string" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": true, + "readonly": false, + "type": "(({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise) | undefined" + } + } + }, + "SignAuthorizationParams": { + "type": "{\n chainId?: number;\n contractAddress: `0x${string}`;\n executor?: \"self\";\n nonce?: number;\n}", + "members": { + "chainId": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "contractAddress": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "executor": { + "optional": true, + "readonly": false, + "type": "\"self\" | undefined" + }, + "nonce": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "SignedAuthorization": { + "type": "{\n address: `0x${string}`;\n chainId: number;\n nonce: number;\n r: `0x${string}`;\n s: `0x${string}`;\n v?: bigint;\n yParity: number;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainId": { + "optional": false, + "readonly": false, + "type": "number" + }, + "nonce": { + "optional": false, + "readonly": false, + "type": "number" + }, + "r": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "s": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "v": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "yParity": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "DerivedExecutorAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").DerivedExecutorAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean | null" + } + } + }, + "ResolvedAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainName": { + "optional": false, + "readonly": false, + "type": "string" + }, + "exists": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "role": { + "optional": true, + "readonly": false, + "type": "\"controller\" | undefined" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"cea\" | \"uea\" | \"uoa\"" + } + } + }, + "ResolvedControllerAccounts": { + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedControllerAccounts", + "members": { + "accounts": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedAccount[]" + } + } + }, + "AccountType": { + "type": "\"cea\" | \"uea\" | \"uoa\"", + "members": {} + }, + "AccountRole": { + "type": "\"controller\"", + "members": {} + }, + "PC20TokenReference": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "FundsToken": { + "type": "import(\"sdk/src/lib/constants/tokens\").MoveableToken | import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20TokenReference", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "PC20RegistryEntry": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "chainName": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "PC20AddressResult": { + "type": "{\n address: `0x${string}`;\n decimals: number;\n name: string;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n registry: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20RegistryEntry[];\n symbol: string;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "decimals": { + "optional": false, + "readonly": false, + "type": "number" + }, + "name": { + "optional": false, + "readonly": false, + "type": "string" + }, + "network": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "registry": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20RegistryEntry[]" + }, + "symbol": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "isPC20Reference": { + "type": "(token: import(\"sdk/src/lib/orchestrator/orchestrator.types\").FundsToken | undefined) => token is import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20TokenReference", + "members": {} + }, + "PC20Error": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20Error", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidPC20AddressError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InvalidPC20AddressError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20TokenChainMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20TokenChainMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20WrapperNotRegisteredError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20WrapperNotRegisteredError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20RegistryMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20RegistryMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20FactoryMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20FactoryMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidPC20MetadataError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InvalidPC20MetadataError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20ExpectedButPRC20Error": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20ExpectedButPRC20Error", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20AmbiguousAddressError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20AmbiguousAddressError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "candidates": { + "optional": false, + "readonly": true, + "type": "{\n chain: string;\n pushAddress: string;\n}[]" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "UnsupportedPC20DestinationError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").UnsupportedPC20DestinationError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InsufficientPC20BalanceError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InsufficientPC20BalanceError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20UnknownChainNamespaceError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20UnknownChainNamespaceError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20WrapperPredictionUnavailableError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20WrapperPredictionUnavailableError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20ExportRevertedError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20ExportRevertedError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "lockedAmount": { + "optional": true, + "readonly": true, + "type": "bigint | undefined" + }, + "outboundTxId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "revertRecipient": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20UnsafeEmptyPayloadError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20UnsafeEmptyPayloadError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ChainTarget": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "ChainSource": { + "type": "{\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "UniversalTo": { + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget", + "members": {} + }, + "TransactionRouteType": { + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"", + "members": {} + }, + "UniversalExecuteParams": { + "type": "{\n from?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainSource;\n migration?: boolean;\n to: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTo;\n} & Omit", + "members": { + "_minimumDepositUsd": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "_requiredFundsOverride": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "_skipFeeLocking": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "_ueaStatus": { + "optional": true, + "readonly": false, + "type": "{\n balance: bigint;\n isDeployed: boolean;\n nonce: bigint;\n} | undefined" + }, + "data": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiCall[] | undefined" + }, + "deadline": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "feeLockTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "from": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainSource | undefined" + }, + "funds": { + "optional": true, + "readonly": false, + "type": "{\n amount: bigint;\n token?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").FundsToken;\n} | undefined" + }, + "gasLimit": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFeePerGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxPCForGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxPriorityFeePerGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "migration": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "nonce": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "options": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions | undefined" + }, + "payGasWith": { + "optional": true, + "readonly": false, + "type": "{\n minAmountOut?: bigint | string;\n slippageBps?: number;\n token?: import(\"sdk/src/lib/constants/tokens\").PayableToken;\n} | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "to": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget" + }, + "value": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "UniversalOutboundTxRequest": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalOutboundTxRequest", + "members": { + "amount": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gasPrice": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxPCForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "payload": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "recipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "revertRecipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "PreparedUniversalTx": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx", + "members": { + "_hop": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").HopDescriptor" + }, + "deadline": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "estimatedGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gatewayRequest": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalOutboundTxRequest | import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxRequest" + }, + "nonce": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "payload": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + } + } + }, + "CascadedTxResponse": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadedTxResponse", + "members": { + "finalTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hopCount": { + "optional": false, + "readonly": false, + "type": "number" + }, + "hops": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo[]" + }, + "initialTxHash": { + "optional": false, + "readonly": false, + "type": "string" + }, + "initialTxResponse": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions) => Promise" + }, + "waitForAll": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions) => Promise" + } + } + }, + "CascadeHopInfo": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo", + "members": { + "executionChain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "expectedSubTxId": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hopIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "outboundDetails": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").OutboundTxDetails | undefined" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + }, + "status": { + "optional": false, + "readonly": false, + "type": "\"confirmed\" | \"failed\" | \"pending\" | \"submitted\"" + }, + "txHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "CascadeTrackOptions": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions", + "members": { + "eventHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeProgressEvent) => void) | undefined" + }, + "timeout": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "CascadeProgressEvent": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeProgressEvent", + "members": { + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "elapsed": { + "optional": false, + "readonly": false, + "type": "number" + }, + "hopIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + }, + "status": { + "optional": false, + "readonly": false, + "type": "\"confirmed\" | \"failed\" | \"found\" | \"polling\" | \"timeout\" | \"waiting\"" + }, + "txHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "CascadeCompletionResult": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeCompletionResult", + "members": { + "failedAt": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "finalTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "finalTxResponse": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadedTxResponse | undefined" + }, + "hops": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo[]" + }, + "success": { + "optional": false, + "readonly": false, + "type": "boolean" + } + } + }, + "MultiChainTxResponse": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiChainTxResponse", + "members": { + "chains": { + "optional": false, + "readonly": false, + "type": "{\n blockNumber: bigint;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n hash: string;\n status: \"confirmed\" | \"failed\" | \"pending\";\n}[]" + }, + "transactions": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse[]" + } + } + }, + "OutboundTxDetails": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").OutboundTxDetails", + "members": { + "amount": { + "optional": false, + "readonly": false, + "type": "string" + }, + "assetAddr": { + "optional": false, + "readonly": false, + "type": "string" + }, + "destinationChain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "explorerUrl": { + "optional": false, + "readonly": false, + "type": "string" + }, + "externalTxHash": { + "optional": false, + "readonly": false, + "type": "string" + }, + "recipient": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "WaitForOutboundOptions": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").WaitForOutboundOptions", + "members": { + "_expectedDestinationChain": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "_outboundIndex": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "_resolvedSubTxId": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "initialWaitMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: {\n elapsed: number;\n status: \"failed\" | \"found\" | \"polling\" | \"timeout\" | \"waiting\";\n}) => void) | undefined" + }, + "timeout": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "SvmGatewayAccountMeta": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmGatewayAccountMeta", + "members": { + "isWritable": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "pubkey": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "SvmExecutePayloadFields": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmExecutePayloadFields", + "members": { + "accounts": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmGatewayAccountMeta[]" + }, + "instructionId": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "ixData": { + "optional": false, + "readonly": false, + "type": "Uint8Array" + }, + "targetProgram": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AccountStatus": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus", + "members": { + "mode": { + "optional": false, + "readonly": false, + "type": "\"read-only\" | \"signer\"" + }, + "uea": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UEAStatus" + } + } + }, + "UEAStatus": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UEAStatus", + "members": { + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "loaded": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "minRequiredVersion": { + "optional": false, + "readonly": false, + "type": "string" + }, + "requiresUpgrade": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "version": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "RescueFundsParams": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").RescueFundsParams", + "members": { + "prc20": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "universalTxId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "parseUEAVersion": { + "type": "(version: string) => number", + "members": {} + }, + "TransactionRoute": { + "type": "typeof import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute", + "members": { + "CEA_TO_CEA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.CEA_TO_CEA" + }, + "CEA_TO_PUSH": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.CEA_TO_PUSH" + }, + "UOA_TO_CEA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.UOA_TO_CEA" + }, + "UOA_TO_PUSH": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.UOA_TO_PUSH" + } + } + }, + "detectRoute": { + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams) => import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute", + "members": {} + }, + "isChainTarget": { + "type": "(to: unknown) => to is import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget", + "members": {} + }, + "DEFAULT_MAX_PC_FOR_GAS_BUFFER_BPS": { + "type": "1000", + "members": {} + }, + "MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT": { + "type": "10000", + "members": {} + }, + "quoteMaxPCForGasCap": { + "type": "(input: import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapInput) => import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": {} + }, + "quoteMaxPCForGasCapFromNativeValue": { + "type": "(input: import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapFromNativeValueInput) => import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": {} + }, + "MaxPCForGasCapInput": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapInput", + "members": { + "bufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "gasLegNativePc": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "MaxPCForGasCapFromNativeValueInput": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapFromNativeValueInput", + "members": { + "bufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "nativeValueForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "MaxPCForGasCapQuote": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": { + "bufferBps": { + "optional": false, + "readonly": false, + "type": "number" + }, + "gasLegNativePc": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxPCForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "nativeValueForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "getCEAAddress": { + "type": "(ueaAddress: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise", + "members": {} + }, + "getPushAccountForCEA": { + "type": "(ceaAddress: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise<`0x${string}`>", + "members": {} + }, + "isCEA": { + "type": "(address: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise", + "members": {} + }, + "chainSupportsCEA": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "chainSupportsOutbound": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "getCEAFactoryAddress": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => `0x${string}` | undefined", + "members": {} + }, + "getAllCEAAddresses": { + "type": "(ueaAddress: `0x${string}`, rpcUrls?: Partial>) => Promise", + "members": {} + }, + "encodeSvmExecutePayload": { + "type": "(fields: import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmExecutePayloadFields) => `0x${string}`", + "members": {} + }, + "isSvmChain": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "isValidSolanaHexAddress": { + "type": "(address: string) => boolean", + "members": {} + }, + "buildMigrationPayload": { + "type": "() => `0x${string}`", + "members": {} + }, + "buildErc20WithdrawalMulticall": { + "type": "(tokenAddress: `0x${string}`, recipientAddress: `0x${string}`, amount: bigint) => import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiCall[]", + "members": {} + }, + "ReadChain": { + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain", + "members": {} + }, + "ReadDestination": { + "type": "{\n chain: import(\"sdk/src/lib/read-state/read-state.types\").ReadChain;\n} | {\n chainId: string;\n chainNamespace: string;\n}", + "members": {} + }, + "ResolvedDestination": { + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}", + "members": { + "caip2": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainId": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "namespace": { + "optional": false, + "readonly": false, + "type": "\"eip155\" | \"solana\" | \"web2\"" + } + } + }, + "ReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").SvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery", + "members": { + "type": { + "optional": false, + "readonly": false, + "type": "\"accountBalance\" | \"contractCall\" | \"http\" | \"lamportBalance\" | \"rawAccountData\" | \"splTokenAccount\" | \"storageSlot\"" + } + } + }, + "EvmReadQuery": { + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n target: `0x${string}`;\n type: \"contractCall\";\n} | {\n callData: `0x${string}`;\n target: `0x${string}`;\n type: \"contractCall\";\n} | {\n slot: `0x${string}` | bigint;\n target: `0x${string}`;\n type: \"storageSlot\";\n} | {\n target: `0x${string}`;\n type: \"accountBalance\";\n}", + "members": { + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"accountBalance\" | \"contractCall\" | \"storageSlot\"" + } + } + }, + "SvmReadQuery": { + "type": "{\n account: string | Uint8Array;\n accountName?: string;\n idl?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n type: \"rawAccountData\";\n} | {\n account: string | Uint8Array;\n type: \"lamportBalance\";\n} | {\n account: string | Uint8Array;\n type: \"splTokenAccount\";\n}", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "string | Uint8Array" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"lamportBalance\" | \"rawAccountData\" | \"splTokenAccount\"" + } + } + }, + "Web2ReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery", + "members": { + "body": { + "optional": true, + "readonly": false, + "type": "string | Uint8Array | undefined" + }, + "extract": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[]" + }, + "headers": { + "optional": true, + "readonly": false, + "type": "Record | undefined" + }, + "method": { + "optional": true, + "readonly": false, + "type": "\"GET\" | \"POST\" | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"http\"" + }, + "url": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "Web2Extract": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract", + "members": { + "decimals": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "path": { + "optional": false, + "readonly": false, + "type": "string" + }, + "valueType": { + "optional": false, + "readonly": false, + "type": "\"bool\" | \"bytes\" | \"int256\" | \"string\" | \"uint256\"" + } + } + }, + "Web2ValueType": { + "type": "\"bool\" | \"bytes\" | \"int256\" | \"string\" | \"uint256\"", + "members": {} + }, + "EncodedReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery", + "members": { + "blockRef": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "encoded": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "namespace": { + "optional": false, + "readonly": false, + "type": "\"eip155\" | \"solana\" | \"web2\"" + }, + "ownerBytes": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "queryType": { + "optional": false, + "readonly": false, + "type": "number" + }, + "resultShape": { + "optional": false, + "readonly": false, + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}" + }, + "warnings": { + "optional": false, + "readonly": false, + "type": "string[]" + } + } + }, + "ReadResultShape": { + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"bytes32\" | \"evmCall\" | \"raw\" | \"svmAccount\" | \"uint256\" | \"web2\"" + } + } + }, + "DecodedReadResult": { + "type": "{\n accountName: string;\n kind: \"svmAccount\";\n value: unknown;\n} | {\n kind: \"bytes32\";\n value: `0x${string}`;\n} | {\n kind: \"evmCall\";\n value: unknown;\n} | {\n kind: \"raw\";\n value: `0x${string}`;\n} | {\n kind: \"uint256\";\n value: bigint;\n} | {\n kind: \"web2\";\n values: readonly unknown[];\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"bytes32\" | \"evmCall\" | \"raw\" | \"svmAccount\" | \"uint256\" | \"web2\"" + } + } + }, + "ReadPreflight": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight", + "members": { + "destination": { + "optional": false, + "readonly": false, + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}" + }, + "fetchedAt": { + "optional": false, + "readonly": false, + "type": "number" + }, + "observedChainHeight": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pushBlockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pushGasPrice": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "universalCallback": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "universalCore": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ReadSpec": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "{\n chainId: string;\n chainNamespace: string;\n owner: `0x${string}`;\n}" + }, + "blockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "expiryPushChainHeight": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "minConfirmations": { + "optional": false, + "readonly": false, + "type": "number" + }, + "query": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "revertRecipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ReadSpecTuple": { + "type": "readonly [\n readonly [\n string,\n string,\n `0x${string}`\n ],\n `0x${string}`,\n number,\n bigint,\n bigint,\n bigint,\n `0x${string}`\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "readonly [\n string,\n string,\n `0x${string}`\n]" + }, + "1": { + "optional": false, + "readonly": true, + "type": "`0x${string}`" + }, + "2": { + "optional": false, + "readonly": true, + "type": "number" + }, + "3": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "4": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "5": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "6": { + "optional": false, + "readonly": true, + "type": "`0x${string}`" + }, + "length": { + "optional": false, + "readonly": true, + "type": "7" + } + } + }, + "BuildReadSpecParams": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").BuildReadSpecParams", + "members": { + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "budgetBuffer": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback | undefined" + }, + "callbackBudget": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "destination": { + "optional": false, + "readonly": false, + "type": "{\n chain: import(\"sdk/src/lib/read-state/read-state.types\").ReadChain;\n} | {\n chainId: string;\n chainNamespace: string;\n}" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "expiryPushChainHeight": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFeeBufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "owner": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "query": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").SvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "PreparedRead": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead", + "members": { + "__@preparedReadValue": { + "optional": true, + "readonly": true, + "type": "T | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback | undefined" + }, + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "encodedQuery": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery" + }, + "encodedSpec": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "fees": { + "optional": false, + "readonly": false, + "type": "{\n callbackBudget: bigint;\n protocolFee: bigint;\n total: bigint;\n}" + }, + "preflight": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "queryKey": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "resultShape": { + "optional": false, + "readonly": false, + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}" + }, + "spec": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec" + }, + "specTuple": { + "optional": false, + "readonly": false, + "type": "readonly [\n readonly [\n string,\n string,\n `0x${string}`\n ],\n `0x${string}`,\n number,\n bigint,\n bigint,\n bigint,\n `0x${string}`\n]" + }, + "value": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "warnings": { + "optional": false, + "readonly": false, + "type": "string[]" + } + } + }, + "ReadCallback": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "((spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpecTuple, callbackGasLimit: bigint) => readonly unknown[]) | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "gasLimit": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "target": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "SimulateReadResult": { + "type": "{\n args?: readonly unknown[];\n error: string;\n errorName?: string;\n ok: false;\n} | {\n ok: true;\n}", + "members": { + "ok": { + "optional": false, + "readonly": false, + "type": "boolean" + } + } + }, + "ParsedReadRequest": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ParsedReadRequest", + "members": { + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackTarget": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "logIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "originalFunder": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "requestId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "requestIdUint": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "spec": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec" + }, + "totalPaid": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "FulfilOutcome": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").FulfilOutcome", + "members": { + "burned": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "delivered": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "expired": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "failReason": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "gasReported": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refunded": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refundFailed": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "ReceiptLike": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike", + "members": { + "logs": { + "optional": false, + "readonly": false, + "type": "readonly {\n address: string;\n data: string;\n logIndex?: number | string;\n topics: readonly string[];\n}[]" + } + } + }, + "ReadRef": { + "type": "{\n requestId: `0x${string}` | bigint;\n} | {\n txHash: `0x${string}`;\n}", + "members": {} + }, + "ReadLifecycleOptions": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadLifecycleOptions", + "members": { + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "resultShape": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadFees": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadFees", + "members": { + "burned": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "paid": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "refunded": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refundFailed": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + } + } + }, + "UniversalReadResponse": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse", + "members": { + "callbackDelivered": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "callbackFailReason": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "decoded": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").DecodedReadResult | undefined" + }, + "decodeError": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destination": { + "optional": false, + "readonly": false, + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}" + }, + "errorMsg": { + "optional": false, + "readonly": false, + "type": "string" + }, + "explorerUrl": { + "optional": false, + "readonly": false, + "type": "string" + }, + "fees": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadFees" + }, + "isTerminal": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "outcome": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME" + }, + "pcTx": { + "optional": false, + "readonly": false, + "type": "readonly {\n blockHeight: number;\n errorMsg: string;\n status: string;\n txHash: `0x${string}`;\n}[]" + }, + "raw": { + "optional": false, + "readonly": false, + "type": "{\n errorCode: import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n resultData: `0x${string}`;\n status: import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n} | null" + }, + "refresh": { + "optional": false, + "readonly": false, + "type": "() => Promise>" + }, + "request": { + "optional": false, + "readonly": false, + "type": "{\n callbackGasLimit: bigint;\n callbackTarget: `0x${string}`;\n createdAtHeight: bigint;\n logIndex: number;\n originalFunder: `0x${string}`;\n refundTo: `0x${string}`;\n spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec;\n}" + }, + "requestId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "requestIdUint": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "status": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "value": { + "optional": true, + "readonly": false, + "type": "T | undefined" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/read-state/read-state.types\").ReadLifecycleOptions) => Promise>" + } + } + }, + "ReadResponseTuple": { + "type": "{\n -readonly [K in keyof R]: import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse ? T : unknown>;\n}", + "members": {} + }, + "BatchReadResponse": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").BatchReadResponse", + "members": { + "atomic": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "count": { + "optional": false, + "readonly": false, + "type": "number" + }, + "reads": { + "optional": false, + "readonly": false, + "type": "{\n -readonly [K in keyof R]: import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse ? T : unknown>;\n}" + }, + "transactionHashes": { + "optional": true, + "readonly": false, + "type": "readonly `0x${string}`[] | undefined" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: Omit) => Promise>" + } + } + }, + "ReadOptions": { + "type": "((import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">)) & {\n callback?: (Pick & Required>) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n };\n}", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "advanced": { + "optional": true, + "readonly": false, + "type": "{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n} | undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "({\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} & {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n}) | ({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick & Pick & Required>) | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadPrepareOptions": { + "type": "((((({\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\">) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n}) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">)) & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n}) | ((({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n}) | ({\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\">)) & {\n blockNumber?: never;\n minConfirmations?: never;\n})) & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n}) & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "advanced": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadQueryOptions": { + "type": "({\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\">) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n}) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n}) | ({\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\">)", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadCallbackOptions": { + "type": "{\n callback?: ({\n gasLimit?: bigint;\n target: `0x${string}`;\n } & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n };\n}", + "members": { + "callback": { + "optional": true, + "readonly": false, + "type": "({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} | undefined" + } + } + }, + "ReadValue": { + "type": "O extends {\n abi: infer A extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: infer F extends string;\n} ? number extends A[\"length\"] ? unknown : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, O extends {\n args: infer Args extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n} ? Args : readonly [\n] extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> ? import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> & readonly [\n] : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>> extends infer Selected ? Selected extends {\n outputs: readonly unknown[];\n type: \"function\";\n} & import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiFunction ? {\n [key in keyof {\n [key in keyof import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"]]: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterToPrimitiveType, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"][key], import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterKind>;\n }]: {\n [key in keyof import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"]]: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterToPrimitiveType, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"][key], import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterKind>;\n }[key];\n} extends infer types ? types extends readonly [\n] ? void : types extends readonly [\n infer type\n] ? type : types : never : never : never : O extends {\n web2: {\n extract: infer E extends readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n };\n} ? {\n readonly [K in keyof E]: {\n bool: boolean;\n bytes: `0x${string}`;\n int256: bigint;\n string: string;\n uint256: bigint;\n }[E[K][\"valueType\"]];\n} : O extends {\n storageSlot: unknown;\n} ? `0x${string}` : O extends {\n idl: infer I extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} ? string extends Extract, string> ? unknown : (O extends {\n functionName: infer N extends string;\n} ? N : undefined) extends string ? import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/index\").IdlAccounts[{\n [K in Extract, string>]: Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : K> extends Lowercase<(O extends {\n functionName: infer N extends string;\n } ? N : undefined) & string extends `${infer H}_${infer T}` ? `${H}${Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : (O extends {\n functionName: infer N extends string;\n } ? N : undefined) & string> ? K : never;\n}[Extract, string>]] : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/index\").IdlAccounts[Extract, string>] : bigint", + "members": {} + }, + "ValidateReadCall": { + "type": "O extends {\n abi: infer A extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: infer F extends string;\n} ? (readonly [\n] extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> ? {\n args?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n} : {\n args: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n}) & {\n functionName: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionName;\n} : O extends {\n functionName: infer N extends string;\n idl: infer I extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} ? string extends Extract, string> ? unknown : [\n {\n [K in Extract, string>]: Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : K> extends Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : N> ? K : never;\n }[Extract, string>]\n] extends [\n never\n] ? {\n functionName: Extract, string>;\n} : unknown : unknown", + "members": {} + }, + "ReadWeb2Options": { + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options", + "members": { + "body": { + "optional": true, + "readonly": false, + "type": "string | Uint8Array | undefined" + }, + "extract": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[]" + }, + "headers": { + "optional": true, + "readonly": false, + "type": "Record | undefined" + }, + "method": { + "optional": true, + "readonly": false, + "type": "\"GET\" | \"POST\" | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadTrackOptions": { + "type": "{\n advanced?: Omit, \"enforceGasCheck\">;\n resultShape?: import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape;\n}", + "members": { + "advanced": { + "optional": true, + "readonly": false, + "type": "Omit<{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n}, \"enforceGasCheck\"> | undefined" + }, + "resultShape": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape | undefined" + } + } + }, + "ReadExecuteOptions": { + "type": "{\n advanced?: {\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n } | undefined;\n progressHook?: ((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined;\n waitForCompletion?: boolean | undefined;\n}", + "members": { + "advanced": { + "optional": true, + "readonly": false, + "type": "{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n} | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + } + } + }, + "UNIVERSAL_READ_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS", + "members": { + "ABORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.ABORTED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.EXPIRED" + }, + "FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.FAILED" + }, + "FULFILLED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.FULFILLED" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.PENDING" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.UNSPECIFIED" + }, + "VOTING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.VOTING" + } + } + }, + "READ_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS", + "members": { + "ERROR": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.ERROR" + }, + "SUCCESS": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.SUCCESS" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.UNSPECIFIED" + } + } + }, + "READ_ERROR_CODE": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE", + "members": { + "INVALID_QUERY": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.INVALID_QUERY" + }, + "INVALID_RESULT": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.INVALID_RESULT" + }, + "NOT_FOUND": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.NOT_FOUND" + }, + "REJECTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.REJECTED" + }, + "REVERTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.REVERTED" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.UNSPECIFIED" + }, + "UNSUPPORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.UNSUPPORTED" + } + } + }, + "READ_OUTCOME": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME", + "members": { + "ABORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.ABORTED" + }, + "CALLBACK_FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.CALLBACK_FAILED" + }, + "DECODE_FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.DECODE_FAILED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.EXPIRED" + }, + "FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.FAILED" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.PENDING" + }, + "SOURCE_ERROR": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.SOURCE_ERROR" + }, + "SUCCESS": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.SUCCESS" + }, + "UNKNOWN": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.UNKNOWN" + } + } + }, + "CONTRACT_REQUEST_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS", + "members": { + "EXECUTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.EXECUTED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.EXPIRED" + }, + "NONE": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.NONE" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.PENDING" + }, + "SETTLED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.SETTLED" + } + } + }, + "TERMINAL_READ_STATUSES": { + "type": "ReadonlySet", + "members": {} + }, + "ReadStateError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadStateError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidReadQueryError": { + "type": "import(\"sdk/src/lib/read-state/errors\").InvalidReadQueryError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidReadSpecError": { + "type": "import(\"sdk/src/lib/read-state/errors\").InvalidReadSpecError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "violations": { + "optional": false, + "readonly": true, + "type": "readonly import(\"sdk/src/lib/read-state/errors\").ReadSpecViolation[]" + } + } + }, + "ReadHeightUnavailableError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadHeightUnavailableError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "UnsupportedReadDestinationError": { + "type": "import(\"sdk/src/lib/read-state/errors\").UnsupportedReadDestinationError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadDecodeError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadDecodeError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadTimeoutError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadTimeoutError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "lastStatus": { + "optional": false, + "readonly": true, + "type": "number" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadNotFoundError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadNotFoundError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadRegistryUnavailableError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadRegistryUnavailableError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadSpecViolation": { + "type": "\"CALLBACK_GAS_LIMIT_EXCEEDED\" | \"DOMAIN_BLOCKED\" | \"EMPTY_QUERY\" | \"EXCESSIVE_FEE\" | \"INSUFFICIENT_CALLBACK_BUDGET\" | \"INSUFFICIENT_FEE\" | \"INVALID_ACCOUNT_ID\" | \"INVALID_BLOCK_NUMBER\" | \"INVALID_EXPIRY_HEIGHT\" | \"INVALID_MIN_CONFIRMATIONS\" | \"SVM_OWNER_NOT_32_BYTES\" | \"ZERO_CALLBACK_BUDGET\" | \"ZERO_CALLBACK_GAS_LIMIT\" | \"ZERO_REVERT_RECIPIENT\"", + "members": {} + }, + "resolveDestination": { + "type": "(dest: import(\"sdk/src/lib/read-state/read-state.types\").ReadDestination) => import(\"sdk/src/lib/read-state/read-state.types\").ResolvedDestination", + "members": {} + }, + "encodeReadQuery": { + "type": "(destination: import(\"sdk/src/lib/read-state/read-state.types\").ReadDestination, query: import(\"sdk/src/lib/read-state/read-state.types\").ReadQuery, options?: {\n blockNumber?: bigint;\n minSlot?: bigint;\n}) => import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery", + "members": {} + }, + "decodeReadResult": { + "type": "(resultData: `0x${string}`, shape: import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape) => import(\"sdk/src/lib/read-state/read-state.types\").DecodedReadResult", + "members": {} + }, + "parseReadRequestsFromReceipt": { + "type": "(receipt: import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike, universalCallback: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").ParsedReadRequest[]", + "members": {} + }, + "parseFulfilOutcome": { + "type": "(receipt: import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike, universalCallback: `0x${string}`, requestId: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").FulfilOutcome", + "members": {} + }, + "buildReadSpecFromPreflight": { + "type": "(preflight: import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight, params: import(\"sdk/src/lib/read-state/read-state.types\").BuildReadSpecParams, defaults?: {\n refundTo?: `0x${string}`;\n}) => import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead", + "members": {} + }, + "validateReadSpec": { + "type": "(input: import(\"sdk/src/lib/read-state/validate\").ValidateReadSpecInput) => {\n ok: false;\n violations: import(\"sdk/src/lib/read-state/errors\").ReadSpecViolation[];\n} | {\n ok: true;\n}", + "members": {} + }, + "toCallData": { + "type": "(prepared: import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead, target: {\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: (spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpecTuple, callbackGasLimit: bigint) => readonly unknown[];\n functionName: string;\n}) => {\n data: `0x${string}`;\n value: bigint;\n}", + "members": {} + }, + "sizeCallbackBudget": { + "type": "(callbackGasLimit: bigint, pushGasPrice: bigint, buffer?: number) => bigint", + "members": {} + }, + "inferResultShape": { + "type": "(namespace: string, query: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape", + "members": {} + }, + "toRequestIdHex": { + "type": "(id: `0x${string}` | bigint) => `0x${string}`", + "members": {} + }, + "toReadQuery": { + "type": "(subject: string, o: ReadOptionsInput, resolvedTokenProgram?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@solana/web3.js/lib/index\").PublicKey) => import(\"sdk/src/lib/read-state/read-state.types\").ReadQuery", + "members": {} + }, + "UNIVERSAL_CALLBACK_EVM": { + "type": "readonly [\n {\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"requestExternalReadSelf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"estimateFee\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"statusOf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"enum RequestStatus\";\n readonly name: \"\";\n readonly type: \"uint8\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"isFulfilled\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getPendingRead\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly internalType: \"struct PendingRead\";\n readonly name: \"\";\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"totalEscrowed\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"blockedDomains\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly indexed: false;\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"readSpec\";\n readonly type: \"tuple\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"totalPaid\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"protocolFee\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ReadRequested\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"ReadFulfilled\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"reason\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"CallbackFailed\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"gasReported\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"burned\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"CallbackGasReported\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundSent\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundFailed\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RequestExpired\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"vaultPC\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ProtocolFeeDistributed\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidAccountId\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"EmptyQuery\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidMinConfirmations\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"DomainBlocked\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidBlockNumber\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidExpiryHeight\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroRevertRecipient\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroCallbackGasLimit\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint64\";\n readonly name: \"provided\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"max\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"CallbackGasLimitExceeded\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"required\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"InsufficientFee\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ExcessiveFee\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"actual\";\n readonly type: \"uint8\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"expected\";\n readonly type: \"uint8\";\n }\n ];\n readonly name: \"InvalidRequestStatus\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ContractIsPaused\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"CallerIsNotUCallbackModule\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n }\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"requestExternalReadSelf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n}" + }, + "1": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"estimateFee\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "2": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"statusOf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"enum RequestStatus\";\n readonly name: \"\";\n readonly type: \"uint8\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "3": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"isFulfilled\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "4": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getPendingRead\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly internalType: \"struct PendingRead\";\n readonly name: \"\";\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "5": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"totalEscrowed\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "6": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"blockedDomains\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "7": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly indexed: false;\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"readSpec\";\n readonly type: \"tuple\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"totalPaid\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"protocolFee\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ReadRequested\";\n readonly type: \"event\";\n}" + }, + "8": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"ReadFulfilled\";\n readonly type: \"event\";\n}" + }, + "9": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"reason\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"CallbackFailed\";\n readonly type: \"event\";\n}" + }, + "10": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"gasReported\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"burned\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"CallbackGasReported\";\n readonly type: \"event\";\n}" + }, + "11": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundSent\";\n readonly type: \"event\";\n}" + }, + "12": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundFailed\";\n readonly type: \"event\";\n}" + }, + "13": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RequestExpired\";\n readonly type: \"event\";\n}" + }, + "14": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"vaultPC\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ProtocolFeeDistributed\";\n readonly type: \"event\";\n}" + }, + "15": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidAccountId\";\n readonly type: \"error\";\n}" + }, + "16": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"EmptyQuery\";\n readonly type: \"error\";\n}" + }, + "17": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidMinConfirmations\";\n readonly type: \"error\";\n}" + }, + "18": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"DomainBlocked\";\n readonly type: \"error\";\n}" + }, + "19": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidBlockNumber\";\n readonly type: \"error\";\n}" + }, + "20": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidExpiryHeight\";\n readonly type: \"error\";\n}" + }, + "21": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroRevertRecipient\";\n readonly type: \"error\";\n}" + }, + "22": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroCallbackGasLimit\";\n readonly type: \"error\";\n}" + }, + "23": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint64\";\n readonly name: \"provided\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"max\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"CallbackGasLimitExceeded\";\n readonly type: \"error\";\n}" + }, + "24": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"required\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"InsufficientFee\";\n readonly type: \"error\";\n}" + }, + "25": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ExcessiveFee\";\n readonly type: \"error\";\n}" + }, + "26": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"actual\";\n readonly type: \"uint8\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"expected\";\n readonly type: \"uint8\";\n }\n ];\n readonly name: \"InvalidRequestStatus\";\n readonly type: \"error\";\n}" + }, + "27": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ContractIsPaused\";\n readonly type: \"error\";\n}" + }, + "28": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"CallerIsNotUCallbackModule\";\n readonly type: \"error\";\n}" + }, + "29": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n}" + }, + "length": { + "optional": false, + "readonly": true, + "type": "30" + } + } + }, + "UNIVERSAL_READ_REGISTRY_EVM": { + "type": "readonly [\n {\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n },\n {\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"read\";\n readonly outputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"universalCallback_\";\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"constructor\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"initialize\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getLocalContext\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"hasResult\";\n readonly outputs: readonly [\n {\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"onUniversalData\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"queryKeyOf\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes32\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"readerOf\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"requestOrderOf\";\n readonly outputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"universalCallback\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"resultByRequestId\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"latestResult\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"version\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"Initialized\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadRequested\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadStored\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidInitialization\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"NotInitializing\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroAddressInit\";\n readonly type: \"error\";\n }\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n },\n {\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"read\";\n readonly outputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n}" + }, + "1": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"universalCallback_\";\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"constructor\";\n}" + }, + "2": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"initialize\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n}" + }, + "3": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getLocalContext\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "4": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"hasResult\";\n readonly outputs: readonly [\n {\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "5": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"onUniversalData\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n}" + }, + "6": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"queryKeyOf\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes32\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "7": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"readerOf\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "8": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"requestOrderOf\";\n readonly outputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "9": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"universalCallback\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "10": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"resultByRequestId\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "11": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"latestResult\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "12": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"version\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"Initialized\";\n readonly type: \"event\";\n}" + }, + "13": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadRequested\";\n readonly type: \"event\";\n}" + }, + "14": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadStored\";\n readonly type: \"event\";\n}" + }, + "15": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidInitialization\";\n readonly type: \"error\";\n}" + }, + "16": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"NotInitializing\";\n readonly type: \"error\";\n}" + }, + "17": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n}" + }, + "18": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroAddressInit\";\n readonly type: \"error\";\n}" + }, + "length": { + "optional": false, + "readonly": true, + "type": "19" + } + } + }, + "PushChainExecutionError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").PushChainExecutionError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PushChainBatchExecutionError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").PushChainBatchExecutionError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": false, + "readonly": true, + "type": "`0x${string}`[]" + } + } + }, + "DecodedErrorPayload": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload", + "members": { + "decoded": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "name": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "selector": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "PushChainInitializeOptions": { + "type": "import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions", + "members": { + "agenticWallet": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "blockExplorers": { + "optional": true, + "readonly": false, + "type": "Partial> | undefined" + }, + "network": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "printTraces": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "rpcUrls": { + "optional": true, + "readonly": false, + "type": "Partial> | undefined" + } + } + }, + "AGENTIC_ERROR_CODE": { + "type": "{\n readonly AGENT_GAS_INSUFFICIENT: \"AGENT_GAS_INSUFFICIENT\";\n readonly AGENT_IS_OWNER: \"AGENT_IS_OWNER\";\n readonly ASSET_CHAIN_MISMATCH: \"ASSET_CHAIN_MISMATCH\";\n readonly CAPABILITY_UNAVAILABLE: \"CAPABILITY_UNAVAILABLE\";\n readonly CREATE_PARTIAL: \"CREATE_PARTIAL\";\n readonly DUPLICATE_RULE: \"DUPLICATE_RULE\";\n readonly FROM_NOT_ALLOWED: \"FROM_NOT_ALLOWED\";\n readonly GATEWAY_ALLOWANCE_INSUFFICIENT: \"GATEWAY_ALLOWANCE_INSUFFICIENT\";\n readonly GENERATION_UNSUPPORTED: \"GENERATION_UNSUPPORTED\";\n readonly INCONSISTENT_READ: \"INCONSISTENT_READ\";\n readonly INDEX_RACE: \"INDEX_RACE\";\n readonly INVALID_RULE: \"INVALID_RULE\";\n readonly NO_RULES_FOR_CHAIN: \"NO_RULES_FOR_CHAIN\";\n readonly NOT_AGENTIC_WALLET: \"NOT_AGENTIC_WALLET\";\n readonly NOT_ALLOWED_IN_AGENTIC_MODE: \"NOT_ALLOWED_IN_AGENTIC_MODE\";\n readonly NOT_OWNER_OR_AGENT: \"NOT_OWNER_OR_AGENT\";\n readonly NOT_WALLET_OWNER: \"NOT_WALLET_OWNER\";\n readonly READ_ONLY: \"READ_ONLY\";\n readonly RECEIPT_MISMATCH: \"RECEIPT_MISMATCH\";\n readonly RECEIPT_UNAVAILABLE: \"RECEIPT_UNAVAILABLE\";\n readonly REVOKE_NEEDS_TARGET: \"REVOKE_NEEDS_TARGET\";\n readonly RULE_LIMIT_EXCEEDED: \"RULE_LIMIT_EXCEEDED\";\n readonly RULE_NOT_FOUND: \"RULE_NOT_FOUND\";\n readonly RULE_READ_FAILED: \"RULE_READ_FAILED\";\n readonly TARGET_NOT_ON_RULE_CHAIN: \"TARGET_NOT_ON_RULE_CHAIN\";\n readonly WALLET_BALANCE_INSUFFICIENT: \"WALLET_BALANCE_INSUFFICIENT\";\n readonly WALLET_NOT_DEPLOYED: \"WALLET_NOT_DEPLOYED\";\n}", + "members": { + "AGENT_GAS_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\"" + }, + "AGENT_IS_OWNER": { + "optional": false, + "readonly": true, + "type": "\"AGENT_IS_OWNER\"" + }, + "ASSET_CHAIN_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"ASSET_CHAIN_MISMATCH\"" + }, + "CAPABILITY_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"CAPABILITY_UNAVAILABLE\"" + }, + "CREATE_PARTIAL": { + "optional": false, + "readonly": true, + "type": "\"CREATE_PARTIAL\"" + }, + "DUPLICATE_RULE": { + "optional": false, + "readonly": true, + "type": "\"DUPLICATE_RULE\"" + }, + "FROM_NOT_ALLOWED": { + "optional": false, + "readonly": true, + "type": "\"FROM_NOT_ALLOWED\"" + }, + "GATEWAY_ALLOWANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"GATEWAY_ALLOWANCE_INSUFFICIENT\"" + }, + "GENERATION_UNSUPPORTED": { + "optional": false, + "readonly": true, + "type": "\"GENERATION_UNSUPPORTED\"" + }, + "INCONSISTENT_READ": { + "optional": false, + "readonly": true, + "type": "\"INCONSISTENT_READ\"" + }, + "INDEX_RACE": { + "optional": false, + "readonly": true, + "type": "\"INDEX_RACE\"" + }, + "INVALID_RULE": { + "optional": false, + "readonly": true, + "type": "\"INVALID_RULE\"" + }, + "NO_RULES_FOR_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"NO_RULES_FOR_CHAIN\"" + }, + "NOT_AGENTIC_WALLET": { + "optional": false, + "readonly": true, + "type": "\"NOT_AGENTIC_WALLET\"" + }, + "NOT_ALLOWED_IN_AGENTIC_MODE": { + "optional": false, + "readonly": true, + "type": "\"NOT_ALLOWED_IN_AGENTIC_MODE\"" + }, + "NOT_OWNER_OR_AGENT": { + "optional": false, + "readonly": true, + "type": "\"NOT_OWNER_OR_AGENT\"" + }, + "NOT_WALLET_OWNER": { + "optional": false, + "readonly": true, + "type": "\"NOT_WALLET_OWNER\"" + }, + "READ_ONLY": { + "optional": false, + "readonly": true, + "type": "\"READ_ONLY\"" + }, + "RECEIPT_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_MISMATCH\"" + }, + "RECEIPT_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_UNAVAILABLE\"" + }, + "REVOKE_NEEDS_TARGET": { + "optional": false, + "readonly": true, + "type": "\"REVOKE_NEEDS_TARGET\"" + }, + "RULE_LIMIT_EXCEEDED": { + "optional": false, + "readonly": true, + "type": "\"RULE_LIMIT_EXCEEDED\"" + }, + "RULE_NOT_FOUND": { + "optional": false, + "readonly": true, + "type": "\"RULE_NOT_FOUND\"" + }, + "RULE_READ_FAILED": { + "optional": false, + "readonly": true, + "type": "\"RULE_READ_FAILED\"" + }, + "TARGET_NOT_ON_RULE_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"TARGET_NOT_ON_RULE_CHAIN\"" + }, + "WALLET_BALANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"WALLET_BALANCE_INSUFFICIENT\"" + }, + "WALLET_NOT_DEPLOYED": { + "optional": false, + "readonly": true, + "type": "\"WALLET_NOT_DEPLOYED\"" + } + } + }, + "AgenticError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"CREATE_PARTIAL\" | \"DUPLICATE_RULE\" | \"FROM_NOT_ALLOWED\" | \"GATEWAY_ALLOWANCE_INSUFFICIENT\" | \"GENERATION_UNSUPPORTED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"REVOKE_NEEDS_TARGET\" | \"RULE_LIMIT_EXCEEDED\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"" + }, + "details": { + "optional": true, + "readonly": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "AgenticRevertError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticRevertError", + "members": { + "agenticCode": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + } + } + }, + "AgenticAddress": { + "type": "`0x${string}`", + "members": {} + }, + "AgenticDoor": { + "type": "\"agent\" | \"owner\"", + "members": {} + }, + "AgenticErrorCode": { + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"CREATE_PARTIAL\" | \"DUPLICATE_RULE\" | \"FROM_NOT_ALLOWED\" | \"GATEWAY_ALLOWANCE_INSUFFICIENT\" | \"GENERATION_UNSUPPORTED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"REVOKE_NEEDS_TARGET\" | \"RULE_LIMIT_EXCEEDED\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"", + "members": {} + }, + "AgenticHex": { + "type": "`0x${string}`", + "members": {} + }, + "AgenticNamespace": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace", + "members": { + "create": { + "optional": false, + "readonly": false, + "type": "(label: string, options: import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions) => Promise" + }, + "derive": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n index?: number;\n}) => Promise<{\n address: `0x${string}`;\n deployed: boolean;\n index: number;\n}>" + }, + "list": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n wallets: import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary[];\n}>" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "(address: `0x${string}`) => import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet" + } + } + }, + "AgenticNetworkConstants": { + "type": "import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants", + "members": { + "ENVELOPE_VERSION": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "FACTORY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "MAX_ALLOWED_CALLS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "MAX_PINS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "RULES_POLICY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticProgressHook": { + "type": "(event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void", + "members": {} + }, + "AgenticTxMetadata": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticTxMetadata", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destinationAccount": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "destinationCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "door": { + "optional": false, + "readonly": false, + "type": "\"agent\" | \"owner\"" + }, + "nativeCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "rawData": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rawTo": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesId": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticWallet": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "checkpoints": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n sinceBlock?: bigint;\n}) => Promise<{\n checkpoints: import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint[];\n}>" + }, + "info": { + "optional": false, + "readonly": false, + "type": "() => Promise" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n owner: `0x${string}`;\n}>" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "{\n add(rules: import(\"sdk/src/lib/agentic/agentic.types\").Rule[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise<{\n rulesIds: `0x${string}`[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n get(rulesId: `0x${string}`): Promise;\n list(): Promise<{\n rules: import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord[];\n }>;\n revoke(rulesIds: `0x${string}`[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n revoke(params: {\n all: true;\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n update(params: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n rules: {\n rule: import(\"sdk/src/lib/agentic/agentic.types\").Rule;\n rulesId: `0x${string}`;\n }[];\n }): Promise<{\n rules: {\n replaced: `0x${string}`;\n rulesId: `0x${string}`;\n }[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n}" + }, + "setLabel": { + "optional": false, + "readonly": false, + "type": "(label: string, opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n}) => Promise" + } + } + }, + "AllowedCall": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall", + "members": { + "beneficiary": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValue": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "`${string}(${string})` | `0x${string}`" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AssetCap": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap", + "members": { + "maxPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/constants/tokens\").MoveableToken" + } + } + }, + "Checkpoint": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint", + "members": { + "blockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "kind": { + "optional": false, + "readonly": false, + "type": "\"OWNER_ACTION\" | \"RULES_GRANTED\" | \"RULES_REVOKED\"" + }, + "ref": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "seq": { + "optional": false, + "readonly": false, + "type": "number" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "CheckpointKind": { + "type": "\"OWNER_ACTION\" | \"RULES_GRANTED\" | \"RULES_REVOKED\"", + "members": {} + }, + "CreateOptions": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions", + "members": { + "progressHook": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook | undefined" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Rule[]" + } + } + }, + "CreateResult": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateResult", + "members": { + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "rulesIds": { + "optional": false, + "readonly": false, + "type": "`0x${string}`[]" + }, + "tx": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ForeignChainNamespace": { + "type": "`eip155:${string}` | `solana:${string}`", + "members": {} + }, + "NativeRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "amount": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AmountLimit | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "maxCalls": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValuePerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxValueTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "pins": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ArgPin[] | undefined" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Rule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule | import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "RulesRecord": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "enabled": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "ref": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "rule": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule | import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule" + }, + "rulesId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Selector": { + "type": "`${string}(${string})` | `0x${string}`", + "members": {} + }, + "UniversalRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall[]" + }, + "assets": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap[]" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "`eip155:${string}` | `solana:${string}`" + }, + "maxGasPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "WalletInfo": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").WalletInfo", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "label": { + "optional": false, + "readonly": false, + "type": "string" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "rulesCount": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "WalletSummary": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "label": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesCount": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "PushChain": { + "type": "import(\"sdk/src/lib/push-chain/push-chain\").PushChain", + "members": { + "accountStatus": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus" + }, + "accountStatusReady": { + "optional": false, + "readonly": false, + "type": "Promise" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace" + }, + "explorer": { + "optional": false, + "readonly": false, + "type": "{\n getTransactionUrl: (txHash: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n listAllUrls: () => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n listUrls: (options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n}" + }, + "funds": { + "optional": false, + "readonly": false, + "type": "{\n getConversionQuote: (amountIn: bigint, options: {\n from: import(\"sdk/src/lib/constants/tokens\").PayableToken | undefined;\n to: import(\"sdk/src/lib/constants/tokens\").MoveableToken | undefined;\n }) => Promise;\n}" + }, + "getAccountStatus": { + "optional": false, + "readonly": false, + "type": "(options?: {\n forceRefresh?: boolean;\n}) => Promise" + }, + "isReadMode": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "moveable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").MoveableTokenAccessor;\n}" + }, + "payable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").PayableTokenAccessor;\n}" + }, + "reinitialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "universal": { + "optional": false, + "readonly": false, + "type": "{\n readonly account: `0x${string}`;\n executeReads: (reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>;\n executeTransactions: (txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise;\n migrateCEA: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"migrateCEA\"];\n readonly origin: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n prepareRead: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n prepareTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"prepareTransaction\"];\n read: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n rescueFunds: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"rescueFunds\"];\n sendTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"execute\"];\n signMessage: (data: Uint8Array) => Promise;\n signTypedData: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n trackRead: {\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n };\n trackTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"trackTransaction\"];\n}" + }, + "upgradeAccount": { + "optional": false, + "readonly": false, + "type": "(options?: {\n progressHook?: (progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n}) => Promise" + } + } + } + }, + "pushChainStatic": { + "CONSTANTS": { + "optional": false, + "readonly": false, + "type": "{\n AGENTIC: Readonly>>;\n CHAIN: typeof import(\"sdk/src/lib/constants/enums\").CHAIN;\n LIBRARY: typeof import(\"sdk/src/lib/constants/enums\").LIBRARY;\n MOVEABLE: {\n TOKEN: import(\"sdk/src/lib/constants/tokens\").MoveableTokenConstantsMap;\n };\n PAYABLE: {\n TOKEN: import(\"sdk/src/lib/constants/tokens\").PayableTokenConstantsMap;\n };\n PUSH_NETWORK: typeof import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n READ: {\n readonly CALLBACK_BUDGET_BUFFER: 3;\n readonly CHAIN: {\n readonly WEB2: \"web2\";\n } & Readonly<{\n readonly ARBITRUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA;\n readonly BASE_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA;\n readonly BNB_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET;\n readonly ETHEREUM_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET;\n readonly ETHEREUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA;\n readonly PUSH_LOCALNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET;\n readonly PUSH_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET;\n readonly PUSH_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly PUSH_TESTNET_DONUT: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly SOLANA_DEVNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET;\n readonly SOLANA_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET;\n readonly SOLANA_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n readonly WEB2: \"web2\";\n }>;\n readonly DEFAULT_EXPIRY_BLOCKS: 300n;\n readonly ERROR_CODE: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n readonly MAX_CALLBACK_GAS_LIMIT: 1000000n;\n readonly MIN_CONFIRMATIONS_FLOOR: 1;\n readonly NAMESPACE: {\n readonly EVM: \"eip155\";\n readonly SVM: \"solana\";\n readonly WEB2: \"web2\";\n };\n readonly OUTCOME: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME;\n readonly REGISTRY_CALLBACK_GAS: 500000n;\n readonly RESULT_STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n readonly STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS;\n readonly UNIVERSAL_CALLBACK_ADDRESSES: Record;\n readonly UNIVERSAL_CORE_ADDRESSES: Record;\n readonly UNIVERSAL_READ_REGISTRY_ADDRESS: {\n readonly TESTNET_DONUT: \"0x00000000000000000000000000000000000000b2\";\n };\n readonly WEB2: \"web2\";\n readonly WEB2_DEFAULT_TIMEOUT_MS: 5000;\n readonly WEB2_MAX_EXTRACT_ENTRIES: 16;\n };\n}" + }, + "initialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "utils": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/utils\").Utils" + } + }, + "pushChainInstance": { + "accountStatus": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus" + }, + "accountStatusReady": { + "optional": false, + "readonly": false, + "type": "Promise" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace" + }, + "explorer": { + "optional": false, + "readonly": false, + "type": "{\n getTransactionUrl: (txHash: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n listAllUrls: () => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n listUrls: (options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n}" + }, + "funds": { + "optional": false, + "readonly": false, + "type": "{\n getConversionQuote: (amountIn: bigint, options: {\n from: import(\"sdk/src/lib/constants/tokens\").PayableToken | undefined;\n to: import(\"sdk/src/lib/constants/tokens\").MoveableToken | undefined;\n }) => Promise;\n}" + }, + "getAccountStatus": { + "optional": false, + "readonly": false, + "type": "(options?: {\n forceRefresh?: boolean;\n}) => Promise" + }, + "isReadMode": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "moveable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").MoveableTokenAccessor;\n}" + }, + "payable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").PayableTokenAccessor;\n}" + }, + "reinitialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "universal": { + "optional": false, + "readonly": false, + "type": "{\n readonly account: `0x${string}`;\n executeReads: (reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>;\n executeTransactions: (txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise;\n migrateCEA: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"migrateCEA\"];\n readonly origin: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n prepareRead: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n prepareTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"prepareTransaction\"];\n read: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n rescueFunds: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"rescueFunds\"];\n sendTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"execute\"];\n signMessage: (data: Uint8Array) => Promise;\n signTypedData: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n trackRead: {\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n };\n trackTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"trackTransaction\"];\n}" + }, + "upgradeAccount": { + "optional": false, + "readonly": false, + "type": "(options?: {\n progressHook?: (progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n}) => Promise" + } + }, + "transactionMethods": { + "account": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "executeReads": { + "optional": false, + "readonly": false, + "type": "(reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>" + }, + "executeTransactions": { + "optional": false, + "readonly": false, + "type": "(txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise" + }, + "migrateCEA": { + "optional": false, + "readonly": false, + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => Promise" + }, + "origin": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "prepareRead": { + "optional": false, + "readonly": false, + "type": "(subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>" + }, + "prepareTransaction": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions) => Promise" + }, + "read": { + "optional": false, + "readonly": false, + "type": "(subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>" + }, + "rescueFunds": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").RescueFundsParams) => Promise" + }, + "sendTransaction": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").ExecuteParams | import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions) => Promise" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": false, + "readonly": false, + "type": "({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise" + }, + "trackRead": { + "optional": false, + "readonly": false, + "type": "{\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n}" + }, + "trackTransaction": { + "optional": false, + "readonly": false, + "type": "(txHash: string, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TrackTransactionOptions) => Promise" + } + }, + "utilityMethods": { + "account": { + "optional": false, + "readonly": false, + "type": "{\n convertExecutorToOriginAccount: (ueaAddress: `0x${string}`, options?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n }) => Promise;\n convertOriginToExecutor: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n onlyCompute?: boolean;\n }) => Promise;\n deriveExecutorAccount: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n skipNetworkCheck?: boolean;\n }) => Promise;\n fromChainAgnostic: (caip: string) => import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n resolveControllerAccount: (address: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n skipNetworkCheck?: boolean;\n }) => Promise;\n toChainAgnostic: (address: string, options: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n toUniversal: (address: string, options: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n}" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "{\n actionId: (target: `0x${string}`, selector: \"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector) => `0x${string}`;\n configId: (wallet: `0x${string}`, rulesId: `0x${string}`, actionId: `0x${string}`) => `0x${string}`;\n decodeRules: (bytes: `0x${string}`, ctx?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n pushChainNamespace?: string;\n }) => import(\"sdk/src/lib/agentic/agentic.types\").Rule;\n}" + }, + "chains": { + "optional": false, + "readonly": false, + "type": "{\n getChainName: (chainNamespace: string) => string | undefined;\n getChainNamespace: (chainName: string) => string | undefined;\n getSupportedChains: (network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK) => {\n chains: import(\"sdk/src/lib/constants/enums\").CHAIN[];\n };\n getSupportedChainsByName: (network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK) => {\n chains: string[];\n };\n}" + }, + "conversion": { + "optional": false, + "readonly": false, + "type": "{\n slippageToMinAmount(amount: string, options: {\n slippageBps: number;\n }): string;\n}" + }, + "helpers": { + "optional": false, + "readonly": false, + "type": "{\n encodeTxData({ abi, idl, functionName, args, }: {\n abi?: any;\n args?: any[];\n functionName: string;\n idl?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n }): `0x${string}`;\n formatUnits(value: bigint | string, decimalsOrOptions: {\n decimals: number;\n precision?: number;\n } | number): string;\n getChainName: (chainName: string) => string | undefined;\n parseUnits(value: string, exponent: {\n decimals: number;\n } | number): bigint;\n}" + }, + "signer": { + "optional": false, + "readonly": false, + "type": "{\n construct: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options: {\n signAndSendTransaction: (unsignedTx: Uint8Array) => Promise;\n signAuthorization?: (params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise;\n signMessage: (data: Uint8Array) => Promise;\n signTypedData?: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n }) => import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton;\n toUniversal: (signer: import(\"sdk/src/lib/universal/universal.types\").EthersV5SignerType | import(\"sdk/src/lib/universal/universal.types\").EthersV6SignerType | import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton | import(\"sdk/src/lib/universal/universal.types\").ViemSignerType) => Promise;\n toUniversalFromKeypair: (clientOrAccount: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@solana/web3.js/lib/index\").Keypair | import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").WalletClient | import(\"sdk/src/lib/universal/universal.types\").EthersV6SignerType, { chain, library }: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n library: import(\"sdk/src/lib/constants/enums\").LIBRARY;\n }) => Promise;\n}" + }, + "svm": { + "optional": false, + "readonly": false, + "type": "{\n getRegisteredIdls: () => Array<{\n address: `0x${string}`;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n }>;\n registerIdl: (idl: unknown) => void;\n}" + }, + "tokens": { + "optional": false, + "readonly": false, + "type": "{\n getMoveableTokens(chainOrClient?: import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/push-chain/push-chain\").PushChain): {\n tokens: Array<{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n decimals: number;\n mechanism: \"approve\" | \"native\" | \"permit2\";\n prc20Address?: `0x${string}`;\n sourceChain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n symbol: string;\n }>;\n };\n getPayableTokens(chainOrClient?: import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/push-chain/push-chain\").PushChain): {\n tokens: Array<{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n decimals: number;\n mechanism: \"approve\" | \"native\" | \"permit2\";\n symbol: string;\n }>;\n };\n getPC20Address(address: string, options: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n rpcUrls?: Partial>;\n strict?: boolean;\n }): Promise;\n getPRC20Address(token: {\n address: string;\n chain: string;\n } | import(\"sdk/src/lib/constants/tokens\").MoveableToken, options?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n }): {\n address: `0x${string}`;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n decimals: number;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n symbol: string;\n };\n}" + } + }, + "initialize": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise", + "agwConstants": { + "ENVELOPE_VERSION": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "FACTORY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "MAX_ALLOWED_CALLS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "MAX_PINS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "RULES_POLICY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + }, + "constants": { + "AGENTIC": { + "optional": false, + "readonly": false, + "type": "{\n readonly LOCALNET?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n readonly MAINNET?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n readonly TESTNET?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n readonly TESTNET_DONUT?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n}" + }, + "CHAIN": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "LIBRARY": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").LIBRARY" + }, + "MOVEABLE": { + "optional": false, + "readonly": false, + "type": "{\n TOKEN: import(\"sdk/src/lib/constants/tokens\").MoveableTokenConstantsMap;\n}" + }, + "PAYABLE": { + "optional": false, + "readonly": false, + "type": "{\n TOKEN: import(\"sdk/src/lib/constants/tokens\").PayableTokenConstantsMap;\n}" + }, + "PUSH_NETWORK": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "READ": { + "optional": false, + "readonly": false, + "type": "{\n readonly CALLBACK_BUDGET_BUFFER: 3;\n readonly CHAIN: {\n readonly WEB2: \"web2\";\n } & Readonly<{\n readonly ARBITRUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA;\n readonly BASE_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA;\n readonly BNB_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET;\n readonly ETHEREUM_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET;\n readonly ETHEREUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA;\n readonly PUSH_LOCALNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET;\n readonly PUSH_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET;\n readonly PUSH_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly PUSH_TESTNET_DONUT: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly SOLANA_DEVNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET;\n readonly SOLANA_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET;\n readonly SOLANA_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n readonly WEB2: \"web2\";\n }>;\n readonly DEFAULT_EXPIRY_BLOCKS: 300n;\n readonly ERROR_CODE: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n readonly MAX_CALLBACK_GAS_LIMIT: 1000000n;\n readonly MIN_CONFIRMATIONS_FLOOR: 1;\n readonly NAMESPACE: {\n readonly EVM: \"eip155\";\n readonly SVM: \"solana\";\n readonly WEB2: \"web2\";\n };\n readonly OUTCOME: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME;\n readonly REGISTRY_CALLBACK_GAS: 500000n;\n readonly RESULT_STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n readonly STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS;\n readonly UNIVERSAL_CALLBACK_ADDRESSES: Record;\n readonly UNIVERSAL_CORE_ADDRESSES: Record;\n readonly UNIVERSAL_READ_REGISTRY_ADDRESS: {\n readonly TESTNET_DONUT: \"0x00000000000000000000000000000000000000b2\";\n };\n readonly WEB2: \"web2\";\n readonly WEB2_DEFAULT_TIMEOUT_MS: 5000;\n readonly WEB2_MAX_EXTRACT_ENTRIES: 16;\n}" + } + } + }, + "after": { + "exports": [ + "AGENTIC_ERROR_CODE", + "AccountRole", + "AccountStatus", + "AccountType", + "AgenticAddress", + "AgenticDoor", + "AgenticError", + "AgenticErrorCode", + "AgenticHex", + "AgenticNamespace", + "AgenticNetworkConstants", + "AgenticProgressHook", + "AgenticRevertError", + "AgenticTxMetadata", + "AgenticWallet", + "AllowedCall", + "AssetCap", + "BatchReadResponse", + "BuildReadSpecParams", + "CHAIN", + "CONTRACT_REQUEST_STATUS", + "CascadeCompletionResult", + "CascadeHopInfo", + "CascadeProgressEvent", + "CascadeTrackOptions", + "CascadedTxResponse", + "ChainSource", + "ChainTarget", + "Checkpoint", + "CheckpointKind", + "ConversionQuote", + "CreateOptions", + "CreateResult", + "DEFAULT_MAX_PC_FOR_GAS_BUFFER_BPS", + "DecodedErrorPayload", + "DecodedReadResult", + "DecodedSolanaRule", + "DerivedExecutorAccount", + "EncodedReadQuery", + "EvmReadQuery", + "ForeignChainNamespace", + "FulfilOutcome", + "FundsToken", + "InsufficientPC20BalanceError", + "InvalidPC20AddressError", + "InvalidPC20MetadataError", + "InvalidReadQueryError", + "InvalidReadSpecError", + "MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT", + "MaxPCForGasCapFromNativeValueInput", + "MaxPCForGasCapInput", + "MaxPCForGasCapQuote", + "MultiChainTxResponse", + "NativeAction", + "NativeMultiRule", + "NativeRule", + "NativeSingleRule", + "OutboundTxDetails", + "PC20AddressResult", + "PC20AmbiguousAddressError", + "PC20Error", + "PC20ExpectedButPRC20Error", + "PC20ExportRevertedError", + "PC20FactoryMismatchError", + "PC20RegistryEntry", + "PC20RegistryMismatchError", + "PC20TokenChainMismatchError", + "PC20TokenReference", + "PC20UnknownChainNamespaceError", + "PC20UnsafeEmptyPayloadError", + "PC20WrapperNotRegisteredError", + "PC20WrapperPredictionUnavailableError", + "ParsedReadRequest", + "PreparedRead", + "PreparedUniversalTx", + "PushChain", + "PushChainBatchExecutionError", + "PushChainExecutionError", + "PushChainInitializeOptions", + "READ_ERROR_CODE", + "READ_OUTCOME", + "READ_STATUS", + "ReadCallback", + "ReadCallbackOptions", + "ReadChain", + "ReadDecodeError", + "ReadDestination", + "ReadExecuteOptions", + "ReadFees", + "ReadHeightUnavailableError", + "ReadLifecycleOptions", + "ReadNotFoundError", + "ReadOptions", + "ReadPreflight", + "ReadPrepareOptions", + "ReadQuery", + "ReadQueryOptions", + "ReadRef", + "ReadRegistryUnavailableError", + "ReadResponseTuple", + "ReadResultShape", + "ReadSpec", + "ReadSpecTuple", + "ReadSpecViolation", + "ReadStateError", + "ReadTimeoutError", + "ReadTrackOptions", + "ReadValue", + "ReadWeb2Options", + "ReceiptLike", + "RescueFundsParams", + "ResolvedAccount", + "ResolvedControllerAccounts", + "ResolvedDestination", + "Rule", + "RulesRecord", + "Selector", + "SignAuthorizationParams", + "SignedAuthorization", + "SimulateReadResult", + "SolanaRule", + "SvmAccountRef", + "SvmExecutePayloadFields", + "SvmFieldConstraint", + "SvmGatewayAccountMeta", + "SvmInstructionRule", + "SvmReadQuery", + "TERMINAL_READ_STATUSES", + "TransactionRoute", + "TransactionRouteType", + "UEAStatus", + "UNIVERSAL_CALLBACK_EVM", + "UNIVERSAL_READ_REGISTRY_EVM", + "UNIVERSAL_READ_STATUS", + "UniversalAccount", + "UniversalExecuteParams", + "UniversalOutboundTxRequest", + "UniversalReadResponse", + "UniversalRule", + "UniversalSigner", + "UniversalSignerSkeleton", + "UniversalTo", + "UnsupportedPC20DestinationError", + "UnsupportedReadDestinationError", + "ValidateReadCall", + "WaitForOutboundOptions", + "WalletInfo", + "WalletSummary", + "Web2Extract", + "Web2ReadQuery", + "Web2ValueType", + "buildErc20WithdrawalMulticall", + "buildMigrationPayload", + "buildReadSpecFromPreflight", + "chainSupportsCEA", + "chainSupportsOutbound", + "decodeReadResult", + "detectRoute", + "encodeReadQuery", + "encodeSvmExecutePayload", + "getAllCEAAddresses", + "getCEAAddress", + "getCEAFactoryAddress", + "getPushAccountForCEA", + "inferResultShape", + "isCEA", + "isChainTarget", + "isPC20Reference", + "isSvmChain", + "isValidSolanaHexAddress", + "parseFulfilOutcome", + "parseReadRequestsFromReceipt", + "parseUEAVersion", + "quoteMaxPCForGasCap", + "quoteMaxPCForGasCapFromNativeValue", + "resolveDestination", + "sizeCallbackBudget", + "toCallData", + "toReadQuery", + "toRequestIdHex", + "validateReadSpec" + ], + "agw": { + "AgenticNamespace": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace", + "members": { + "create": { + "optional": false, + "readonly": false, + "type": "(label: string, options: import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions) => Promise" + }, + "derive": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n index?: number;\n}) => Promise<{\n address: `0x${string}`;\n deployed: boolean;\n index: number;\n}>" + }, + "list": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n wallets: import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary[];\n}>" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "(address: `0x${string}`) => import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet" + } + } + }, + "AgenticWallet": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "checkpoints": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n sinceBlock?: bigint;\n}) => Promise<{\n checkpoints: import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint[];\n}>" + }, + "info": { + "optional": false, + "readonly": false, + "type": "() => Promise" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n owner: `0x${string}`;\n}>" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "{\n add(rules: import(\"sdk/src/lib/agentic/agentic.types\").Rule[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise<{\n rulesIds: `0x${string}`[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n get(rulesId: `0x${string}`): Promise;\n list(): Promise<{\n rules: import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord[];\n }>;\n revoke(rulesIds: `0x${string}`[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n revoke(params: {\n all: true;\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n update(params: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n rules: {\n rule: import(\"sdk/src/lib/agentic/agentic.types\").Rule;\n rulesId: `0x${string}`;\n }[];\n }): Promise<{\n rules: {\n replaced: `0x${string}`;\n rulesId: `0x${string}`;\n }[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n}" + }, + "setLabel": { + "optional": false, + "readonly": false, + "type": "(label: string, opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n}) => Promise" + } + } + }, + "AgenticError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"AMBIGUOUS_RULE\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"CREATE_PARTIAL\" | \"FROM_NOT_ALLOWED\" | \"GATEWAY_ALLOWANCE_INSUFFICIENT\" | \"GENERATION_UNSUPPORTED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"REVOKE_NEEDS_TARGET\" | \"RULE_LIMIT_EXCEEDED\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"" + }, + "details": { + "optional": true, + "readonly": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "AgenticRevertError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticRevertError", + "members": { + "agenticCode": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + } + } + }, + "AGENTIC_ERROR_CODE": { + "type": "{\n readonly AGENT_GAS_INSUFFICIENT: \"AGENT_GAS_INSUFFICIENT\";\n readonly AGENT_IS_OWNER: \"AGENT_IS_OWNER\";\n readonly AMBIGUOUS_RULE: \"AMBIGUOUS_RULE\";\n readonly ASSET_CHAIN_MISMATCH: \"ASSET_CHAIN_MISMATCH\";\n readonly CAPABILITY_UNAVAILABLE: \"CAPABILITY_UNAVAILABLE\";\n readonly CREATE_PARTIAL: \"CREATE_PARTIAL\";\n readonly FROM_NOT_ALLOWED: \"FROM_NOT_ALLOWED\";\n readonly GATEWAY_ALLOWANCE_INSUFFICIENT: \"GATEWAY_ALLOWANCE_INSUFFICIENT\";\n readonly GENERATION_UNSUPPORTED: \"GENERATION_UNSUPPORTED\";\n readonly INCONSISTENT_READ: \"INCONSISTENT_READ\";\n readonly INDEX_RACE: \"INDEX_RACE\";\n readonly INVALID_RULE: \"INVALID_RULE\";\n readonly NO_RULES_FOR_CHAIN: \"NO_RULES_FOR_CHAIN\";\n readonly NOT_AGENTIC_WALLET: \"NOT_AGENTIC_WALLET\";\n readonly NOT_ALLOWED_IN_AGENTIC_MODE: \"NOT_ALLOWED_IN_AGENTIC_MODE\";\n readonly NOT_OWNER_OR_AGENT: \"NOT_OWNER_OR_AGENT\";\n readonly NOT_WALLET_OWNER: \"NOT_WALLET_OWNER\";\n readonly READ_ONLY: \"READ_ONLY\";\n readonly RECEIPT_MISMATCH: \"RECEIPT_MISMATCH\";\n readonly RECEIPT_UNAVAILABLE: \"RECEIPT_UNAVAILABLE\";\n readonly REVOKE_NEEDS_TARGET: \"REVOKE_NEEDS_TARGET\";\n readonly RULE_LIMIT_EXCEEDED: \"RULE_LIMIT_EXCEEDED\";\n readonly RULE_NOT_FOUND: \"RULE_NOT_FOUND\";\n readonly RULE_READ_FAILED: \"RULE_READ_FAILED\";\n readonly TARGET_NOT_ON_RULE_CHAIN: \"TARGET_NOT_ON_RULE_CHAIN\";\n readonly WALLET_BALANCE_INSUFFICIENT: \"WALLET_BALANCE_INSUFFICIENT\";\n readonly WALLET_NOT_DEPLOYED: \"WALLET_NOT_DEPLOYED\";\n}", + "members": { + "AGENT_GAS_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\"" + }, + "AGENT_IS_OWNER": { + "optional": false, + "readonly": true, + "type": "\"AGENT_IS_OWNER\"" + }, + "AMBIGUOUS_RULE": { + "optional": false, + "readonly": true, + "type": "\"AMBIGUOUS_RULE\"" + }, + "ASSET_CHAIN_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"ASSET_CHAIN_MISMATCH\"" + }, + "CAPABILITY_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"CAPABILITY_UNAVAILABLE\"" + }, + "CREATE_PARTIAL": { + "optional": false, + "readonly": true, + "type": "\"CREATE_PARTIAL\"" + }, + "FROM_NOT_ALLOWED": { + "optional": false, + "readonly": true, + "type": "\"FROM_NOT_ALLOWED\"" + }, + "GATEWAY_ALLOWANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"GATEWAY_ALLOWANCE_INSUFFICIENT\"" + }, + "GENERATION_UNSUPPORTED": { + "optional": false, + "readonly": true, + "type": "\"GENERATION_UNSUPPORTED\"" + }, + "INCONSISTENT_READ": { + "optional": false, + "readonly": true, + "type": "\"INCONSISTENT_READ\"" + }, + "INDEX_RACE": { + "optional": false, + "readonly": true, + "type": "\"INDEX_RACE\"" + }, + "INVALID_RULE": { + "optional": false, + "readonly": true, + "type": "\"INVALID_RULE\"" + }, + "NO_RULES_FOR_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"NO_RULES_FOR_CHAIN\"" + }, + "NOT_AGENTIC_WALLET": { + "optional": false, + "readonly": true, + "type": "\"NOT_AGENTIC_WALLET\"" + }, + "NOT_ALLOWED_IN_AGENTIC_MODE": { + "optional": false, + "readonly": true, + "type": "\"NOT_ALLOWED_IN_AGENTIC_MODE\"" + }, + "NOT_OWNER_OR_AGENT": { + "optional": false, + "readonly": true, + "type": "\"NOT_OWNER_OR_AGENT\"" + }, + "NOT_WALLET_OWNER": { + "optional": false, + "readonly": true, + "type": "\"NOT_WALLET_OWNER\"" + }, + "READ_ONLY": { + "optional": false, + "readonly": true, + "type": "\"READ_ONLY\"" + }, + "RECEIPT_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_MISMATCH\"" + }, + "RECEIPT_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_UNAVAILABLE\"" + }, + "REVOKE_NEEDS_TARGET": { + "optional": false, + "readonly": true, + "type": "\"REVOKE_NEEDS_TARGET\"" + }, + "RULE_LIMIT_EXCEEDED": { + "optional": false, + "readonly": true, + "type": "\"RULE_LIMIT_EXCEEDED\"" + }, + "RULE_NOT_FOUND": { + "optional": false, + "readonly": true, + "type": "\"RULE_NOT_FOUND\"" + }, + "RULE_READ_FAILED": { + "optional": false, + "readonly": true, + "type": "\"RULE_READ_FAILED\"" + }, + "TARGET_NOT_ON_RULE_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"TARGET_NOT_ON_RULE_CHAIN\"" + }, + "WALLET_BALANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"WALLET_BALANCE_INSUFFICIENT\"" + }, + "WALLET_NOT_DEPLOYED": { + "optional": false, + "readonly": true, + "type": "\"WALLET_NOT_DEPLOYED\"" + } + } + }, + "NativeRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeMultiRule | import(\"sdk/src/lib/agentic/agentic.types\").NativeSingleRule", + "members": { + "actions": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeAction[] | undefined" + }, + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "amount": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AmountLimit | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "maxCalls": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValuePerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxValueTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "pins": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ArgPin[] | undefined" + }, + "selector": { + "optional": true, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector | undefined" + }, + "target": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "AssetCap": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap", + "members": { + "maxPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/constants/tokens\").MoveableToken" + } + } + }, + "AllowedCall": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall", + "members": { + "beneficiary": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "beneficiaryOffset": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValue": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "`${string}(${string})` | `0x${string}`" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "UniversalRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall[]" + }, + "assets": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap[]" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "`eip155:${string}`" + }, + "maxGasPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "RulesRecord": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "enabled": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "rule": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").DecodedSolanaRule | import(\"sdk/src/lib/agentic/agentic.types\").Rule" + }, + "rulesId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "CreateOptions": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions", + "members": { + "progressHook": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook | undefined" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Rule[]" + } + } + }, + "CreateResult": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateResult", + "members": { + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "rulesIds": { + "optional": false, + "readonly": false, + "type": "`0x${string}`[]" + }, + "tx": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticTxMetadata": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticTxMetadata", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destinationAccount": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "destinationCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "destinationInstruction": { + "optional": true, + "readonly": false, + "type": "{\n accounts: readonly {\n isWritable: boolean;\n pubkey: `0x${string}`;\n }[];\n data: `0x${string}`;\n program: `0x${string}`;\n} | undefined" + }, + "destinationTransfer": { + "optional": true, + "readonly": false, + "type": "{\n amount: bigint;\n recipient: `0x${string}`;\n token: `0x${string}`;\n} | undefined" + }, + "door": { + "optional": false, + "readonly": false, + "type": "\"agent\" | \"owner\"" + }, + "nativeCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "rawData": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rawTo": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesId": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + } + }, + "publicSurface": { + "CHAIN": { + "type": "typeof import(\"sdk/src/lib/constants/enums\").CHAIN", + "members": { + "ARBITRUM_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA" + }, + "BASE_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA" + }, + "BNB_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET" + }, + "ETHEREUM_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET" + }, + "ETHEREUM_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA" + }, + "PUSH_LOCALNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET" + }, + "PUSH_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET" + }, + "PUSH_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET" + }, + "PUSH_TESTNET_DONUT": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET" + }, + "SOLANA_DEVNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET" + }, + "SOLANA_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET" + }, + "SOLANA_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET" + }, + "WEB2": { + "optional": false, + "readonly": false, + "type": "\"web2\"" + } + } + }, + "ConversionQuote": { + "type": "import(\"sdk/src/lib/constants/tokens\").ConversionQuote", + "members": { + "amountIn": { + "optional": false, + "readonly": false, + "type": "string" + }, + "amountOut": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rate": { + "optional": false, + "readonly": false, + "type": "number" + }, + "route": { + "optional": true, + "readonly": false, + "type": "string[] | undefined" + }, + "timestamp": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "UniversalSigner": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalSigner", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "signAndSendTransaction": { + "optional": false, + "readonly": false, + "type": "(unsignedTx: Uint8Array) => Promise" + }, + "signAuthorization": { + "optional": true, + "readonly": false, + "type": "((params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise) | undefined" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": true, + "readonly": false, + "type": "(({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise) | undefined" + } + } + }, + "UniversalAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "UniversalSignerSkeleton": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "signAndSendTransaction": { + "optional": false, + "readonly": false, + "type": "(unsignedTx: Uint8Array) => Promise" + }, + "signAuthorization": { + "optional": true, + "readonly": false, + "type": "((params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise) | undefined" + }, + "signerId": { + "optional": false, + "readonly": false, + "type": "string" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": true, + "readonly": false, + "type": "(({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise) | undefined" + } + } + }, + "SignAuthorizationParams": { + "type": "{\n chainId?: number;\n contractAddress: `0x${string}`;\n executor?: \"self\";\n nonce?: number;\n}", + "members": { + "chainId": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "contractAddress": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "executor": { + "optional": true, + "readonly": false, + "type": "\"self\" | undefined" + }, + "nonce": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "SignedAuthorization": { + "type": "{\n address: `0x${string}`;\n chainId: number;\n nonce: number;\n r: `0x${string}`;\n s: `0x${string}`;\n v?: bigint;\n yParity: number;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainId": { + "optional": false, + "readonly": false, + "type": "number" + }, + "nonce": { + "optional": false, + "readonly": false, + "type": "number" + }, + "r": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "s": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "v": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "yParity": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "DerivedExecutorAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").DerivedExecutorAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean | null" + } + } + }, + "ResolvedAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainName": { + "optional": false, + "readonly": false, + "type": "string" + }, + "exists": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "role": { + "optional": true, + "readonly": false, + "type": "\"controller\" | undefined" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"cea\" | \"uea\" | \"uoa\"" + } + } + }, + "ResolvedControllerAccounts": { + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedControllerAccounts", + "members": { + "accounts": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedAccount[]" + } + } + }, + "AccountType": { + "type": "\"cea\" | \"uea\" | \"uoa\"", + "members": {} + }, + "AccountRole": { + "type": "\"controller\"", + "members": {} + }, + "PC20TokenReference": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "FundsToken": { + "type": "import(\"sdk/src/lib/constants/tokens\").MoveableToken | import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20TokenReference", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "PC20RegistryEntry": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "chainName": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "PC20AddressResult": { + "type": "{\n address: `0x${string}`;\n decimals: number;\n name: string;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n registry: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20RegistryEntry[];\n symbol: string;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "decimals": { + "optional": false, + "readonly": false, + "type": "number" + }, + "name": { + "optional": false, + "readonly": false, + "type": "string" + }, + "network": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "registry": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20RegistryEntry[]" + }, + "symbol": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "isPC20Reference": { + "type": "(token: import(\"sdk/src/lib/orchestrator/orchestrator.types\").FundsToken | undefined) => token is import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20TokenReference", + "members": {} + }, + "PC20Error": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20Error", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidPC20AddressError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InvalidPC20AddressError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20TokenChainMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20TokenChainMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20WrapperNotRegisteredError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20WrapperNotRegisteredError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20RegistryMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20RegistryMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20FactoryMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20FactoryMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidPC20MetadataError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InvalidPC20MetadataError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20ExpectedButPRC20Error": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20ExpectedButPRC20Error", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20AmbiguousAddressError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20AmbiguousAddressError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "candidates": { + "optional": false, + "readonly": true, + "type": "{\n chain: string;\n pushAddress: string;\n}[]" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "UnsupportedPC20DestinationError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").UnsupportedPC20DestinationError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InsufficientPC20BalanceError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InsufficientPC20BalanceError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20UnknownChainNamespaceError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20UnknownChainNamespaceError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20WrapperPredictionUnavailableError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20WrapperPredictionUnavailableError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20ExportRevertedError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20ExportRevertedError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "lockedAmount": { + "optional": true, + "readonly": true, + "type": "bigint | undefined" + }, + "outboundTxId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "revertRecipient": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20UnsafeEmptyPayloadError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20UnsafeEmptyPayloadError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ChainTarget": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "ChainSource": { + "type": "{\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "UniversalTo": { + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget", + "members": {} + }, + "TransactionRouteType": { + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"", + "members": {} + }, + "UniversalExecuteParams": { + "type": "{\n from?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainSource;\n migration?: boolean;\n to: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTo;\n} & Omit", + "members": { + "_minimumDepositUsd": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "_requiredFundsOverride": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "_skipFeeLocking": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "_ueaStatus": { + "optional": true, + "readonly": false, + "type": "{\n balance: bigint;\n isDeployed: boolean;\n nonce: bigint;\n} | undefined" + }, + "data": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiCall[] | undefined" + }, + "deadline": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "feeLockTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "from": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainSource | undefined" + }, + "funds": { + "optional": true, + "readonly": false, + "type": "{\n amount: bigint;\n token?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").FundsToken;\n} | undefined" + }, + "gasLimit": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFeePerGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxPCForGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxPriorityFeePerGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "migration": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "nonce": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "options": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions | undefined" + }, + "payGasWith": { + "optional": true, + "readonly": false, + "type": "{\n minAmountOut?: bigint | string;\n slippageBps?: number;\n token?: import(\"sdk/src/lib/constants/tokens\").PayableToken;\n} | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "to": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget" + }, + "value": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "UniversalOutboundTxRequest": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalOutboundTxRequest", + "members": { + "amount": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gasPrice": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxPCForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "payload": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "recipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "revertRecipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "PreparedUniversalTx": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx", + "members": { + "_hop": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").HopDescriptor" + }, + "deadline": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "estimatedGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gatewayRequest": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalOutboundTxRequest | import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxRequest" + }, + "nonce": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "payload": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + } + } + }, + "CascadedTxResponse": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadedTxResponse", + "members": { + "finalTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hopCount": { + "optional": false, + "readonly": false, + "type": "number" + }, + "hops": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo[]" + }, + "initialTxHash": { + "optional": false, + "readonly": false, + "type": "string" + }, + "initialTxResponse": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions) => Promise" + }, + "waitForAll": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions) => Promise" + } + } + }, + "CascadeHopInfo": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo", + "members": { + "executionChain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "expectedSubTxId": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hopIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "outboundDetails": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").OutboundTxDetails | undefined" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + }, + "status": { + "optional": false, + "readonly": false, + "type": "\"confirmed\" | \"failed\" | \"pending\" | \"submitted\"" + }, + "txHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "CascadeTrackOptions": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions", + "members": { + "eventHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeProgressEvent) => void) | undefined" + }, + "timeout": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "CascadeProgressEvent": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeProgressEvent", + "members": { + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "elapsed": { + "optional": false, + "readonly": false, + "type": "number" + }, + "hopIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + }, + "status": { + "optional": false, + "readonly": false, + "type": "\"confirmed\" | \"failed\" | \"found\" | \"polling\" | \"timeout\" | \"waiting\"" + }, + "txHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "CascadeCompletionResult": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeCompletionResult", + "members": { + "failedAt": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "finalTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "finalTxResponse": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadedTxResponse | undefined" + }, + "hops": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo[]" + }, + "success": { + "optional": false, + "readonly": false, + "type": "boolean" + } + } + }, + "MultiChainTxResponse": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiChainTxResponse", + "members": { + "chains": { + "optional": false, + "readonly": false, + "type": "{\n blockNumber: bigint;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n hash: string;\n status: \"confirmed\" | \"failed\" | \"pending\";\n}[]" + }, + "transactions": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse[]" + } + } + }, + "OutboundTxDetails": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").OutboundTxDetails", + "members": { + "amount": { + "optional": false, + "readonly": false, + "type": "string" + }, + "assetAddr": { + "optional": false, + "readonly": false, + "type": "string" + }, + "destinationChain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "explorerUrl": { + "optional": false, + "readonly": false, + "type": "string" + }, + "externalTxHash": { + "optional": false, + "readonly": false, + "type": "string" + }, + "recipient": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "WaitForOutboundOptions": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").WaitForOutboundOptions", + "members": { + "_expectedDestinationChain": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "_outboundIndex": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "_resolvedSubTxId": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "initialWaitMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: {\n elapsed: number;\n status: \"failed\" | \"found\" | \"polling\" | \"timeout\" | \"waiting\";\n}) => void) | undefined" + }, + "timeout": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "SvmGatewayAccountMeta": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmGatewayAccountMeta", + "members": { + "isWritable": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "pubkey": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "SvmExecutePayloadFields": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmExecutePayloadFields", + "members": { + "accounts": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmGatewayAccountMeta[]" + }, + "instructionId": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "ixData": { + "optional": false, + "readonly": false, + "type": "Uint8Array" + }, + "targetProgram": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AccountStatus": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus", + "members": { + "mode": { + "optional": false, + "readonly": false, + "type": "\"read-only\" | \"signer\"" + }, + "uea": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UEAStatus" + } + } + }, + "UEAStatus": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UEAStatus", + "members": { + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "loaded": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "minRequiredVersion": { + "optional": false, + "readonly": false, + "type": "string" + }, + "requiresUpgrade": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "version": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "RescueFundsParams": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").RescueFundsParams", + "members": { + "prc20": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "universalTxId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "parseUEAVersion": { + "type": "(version: string) => number", + "members": {} + }, + "TransactionRoute": { + "type": "typeof import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute", + "members": { + "CEA_TO_CEA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.CEA_TO_CEA" + }, + "CEA_TO_PUSH": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.CEA_TO_PUSH" + }, + "UOA_TO_CEA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.UOA_TO_CEA" + }, + "UOA_TO_PUSH": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.UOA_TO_PUSH" + } + } + }, + "detectRoute": { + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams) => import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute", + "members": {} + }, + "isChainTarget": { + "type": "(to: unknown) => to is import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget", + "members": {} + }, + "DEFAULT_MAX_PC_FOR_GAS_BUFFER_BPS": { + "type": "1000", + "members": {} + }, + "MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT": { + "type": "10000", + "members": {} + }, + "quoteMaxPCForGasCap": { + "type": "(input: import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapInput) => import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": {} + }, + "quoteMaxPCForGasCapFromNativeValue": { + "type": "(input: import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapFromNativeValueInput) => import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": {} + }, + "MaxPCForGasCapInput": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapInput", + "members": { + "bufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "gasLegNativePc": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "MaxPCForGasCapFromNativeValueInput": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapFromNativeValueInput", + "members": { + "bufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "nativeValueForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "MaxPCForGasCapQuote": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": { + "bufferBps": { + "optional": false, + "readonly": false, + "type": "number" + }, + "gasLegNativePc": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxPCForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "nativeValueForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "getCEAAddress": { + "type": "(ueaAddress: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise", + "members": {} + }, + "getPushAccountForCEA": { + "type": "(ceaAddress: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise<`0x${string}`>", + "members": {} + }, + "isCEA": { + "type": "(address: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise", + "members": {} + }, + "chainSupportsCEA": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "chainSupportsOutbound": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "getCEAFactoryAddress": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => `0x${string}` | undefined", + "members": {} + }, + "getAllCEAAddresses": { + "type": "(ueaAddress: `0x${string}`, rpcUrls?: Partial>) => Promise", + "members": {} + }, + "encodeSvmExecutePayload": { + "type": "(fields: import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmExecutePayloadFields) => `0x${string}`", + "members": {} + }, + "isSvmChain": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "isValidSolanaHexAddress": { + "type": "(address: string) => boolean", + "members": {} + }, + "buildMigrationPayload": { + "type": "() => `0x${string}`", + "members": {} + }, + "buildErc20WithdrawalMulticall": { + "type": "(tokenAddress: `0x${string}`, recipientAddress: `0x${string}`, amount: bigint) => import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiCall[]", + "members": {} + }, + "ReadChain": { + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain", + "members": {} + }, + "ReadDestination": { + "type": "{\n chain: import(\"sdk/src/lib/read-state/read-state.types\").ReadChain;\n} | {\n chainId: string;\n chainNamespace: string;\n}", + "members": {} + }, + "ResolvedDestination": { + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}", + "members": { + "caip2": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainId": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "namespace": { + "optional": false, + "readonly": false, + "type": "\"eip155\" | \"solana\" | \"web2\"" + } + } + }, + "ReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").SvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery", + "members": { + "type": { + "optional": false, + "readonly": false, + "type": "\"accountBalance\" | \"contractCall\" | \"http\" | \"lamportBalance\" | \"rawAccountData\" | \"splTokenAccount\" | \"storageSlot\"" + } + } + }, + "EvmReadQuery": { + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n target: `0x${string}`;\n type: \"contractCall\";\n} | {\n callData: `0x${string}`;\n target: `0x${string}`;\n type: \"contractCall\";\n} | {\n slot: `0x${string}` | bigint;\n target: `0x${string}`;\n type: \"storageSlot\";\n} | {\n target: `0x${string}`;\n type: \"accountBalance\";\n}", + "members": { + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"accountBalance\" | \"contractCall\" | \"storageSlot\"" + } + } + }, + "SvmReadQuery": { + "type": "{\n account: string | Uint8Array;\n accountName?: string;\n idl?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n type: \"rawAccountData\";\n} | {\n account: string | Uint8Array;\n type: \"lamportBalance\";\n} | {\n account: string | Uint8Array;\n type: \"splTokenAccount\";\n}", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "string | Uint8Array" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"lamportBalance\" | \"rawAccountData\" | \"splTokenAccount\"" + } + } + }, + "Web2ReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery", + "members": { + "body": { + "optional": true, + "readonly": false, + "type": "string | Uint8Array | undefined" + }, + "extract": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[]" + }, + "headers": { + "optional": true, + "readonly": false, + "type": "Record | undefined" + }, + "method": { + "optional": true, + "readonly": false, + "type": "\"GET\" | \"POST\" | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"http\"" + }, + "url": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "Web2Extract": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract", + "members": { + "decimals": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "path": { + "optional": false, + "readonly": false, + "type": "string" + }, + "valueType": { + "optional": false, + "readonly": false, + "type": "\"bool\" | \"bytes\" | \"int256\" | \"string\" | \"uint256\"" + } + } + }, + "Web2ValueType": { + "type": "\"bool\" | \"bytes\" | \"int256\" | \"string\" | \"uint256\"", + "members": {} + }, + "EncodedReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery", + "members": { + "blockRef": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "encoded": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "namespace": { + "optional": false, + "readonly": false, + "type": "\"eip155\" | \"solana\" | \"web2\"" + }, + "ownerBytes": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "queryType": { + "optional": false, + "readonly": false, + "type": "number" + }, + "resultShape": { + "optional": false, + "readonly": false, + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}" + }, + "warnings": { + "optional": false, + "readonly": false, + "type": "string[]" + } + } + }, + "ReadResultShape": { + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"bytes32\" | \"evmCall\" | \"raw\" | \"svmAccount\" | \"uint256\" | \"web2\"" + } + } + }, + "DecodedReadResult": { + "type": "{\n accountName: string;\n kind: \"svmAccount\";\n value: unknown;\n} | {\n kind: \"bytes32\";\n value: `0x${string}`;\n} | {\n kind: \"evmCall\";\n value: unknown;\n} | {\n kind: \"raw\";\n value: `0x${string}`;\n} | {\n kind: \"uint256\";\n value: bigint;\n} | {\n kind: \"web2\";\n values: readonly unknown[];\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"bytes32\" | \"evmCall\" | \"raw\" | \"svmAccount\" | \"uint256\" | \"web2\"" + } + } + }, + "ReadPreflight": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight", + "members": { + "destination": { + "optional": false, + "readonly": false, + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}" + }, + "fetchedAt": { + "optional": false, + "readonly": false, + "type": "number" + }, + "observedChainHeight": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pushBlockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pushGasPrice": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "universalCallback": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "universalCore": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ReadSpec": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "{\n chainId: string;\n chainNamespace: string;\n owner: `0x${string}`;\n}" + }, + "blockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "expiryPushChainHeight": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "minConfirmations": { + "optional": false, + "readonly": false, + "type": "number" + }, + "query": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "revertRecipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ReadSpecTuple": { + "type": "readonly [\n readonly [\n string,\n string,\n `0x${string}`\n ],\n `0x${string}`,\n number,\n bigint,\n bigint,\n bigint,\n `0x${string}`\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "readonly [\n string,\n string,\n `0x${string}`\n]" + }, + "1": { + "optional": false, + "readonly": true, + "type": "`0x${string}`" + }, + "2": { + "optional": false, + "readonly": true, + "type": "number" + }, + "3": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "4": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "5": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "6": { + "optional": false, + "readonly": true, + "type": "`0x${string}`" + }, + "length": { + "optional": false, + "readonly": true, + "type": "7" + } + } + }, + "BuildReadSpecParams": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").BuildReadSpecParams", + "members": { + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "budgetBuffer": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback | undefined" + }, + "callbackBudget": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "destination": { + "optional": false, + "readonly": false, + "type": "{\n chain: import(\"sdk/src/lib/read-state/read-state.types\").ReadChain;\n} | {\n chainId: string;\n chainNamespace: string;\n}" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "expiryPushChainHeight": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFeeBufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "owner": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "query": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").SvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "PreparedRead": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead", + "members": { + "__@preparedReadValue": { + "optional": true, + "readonly": true, + "type": "T | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback | undefined" + }, + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "encodedQuery": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery" + }, + "encodedSpec": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "fees": { + "optional": false, + "readonly": false, + "type": "{\n callbackBudget: bigint;\n protocolFee: bigint;\n total: bigint;\n}" + }, + "preflight": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "queryKey": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "resultShape": { + "optional": false, + "readonly": false, + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}" + }, + "spec": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec" + }, + "specTuple": { + "optional": false, + "readonly": false, + "type": "readonly [\n readonly [\n string,\n string,\n `0x${string}`\n ],\n `0x${string}`,\n number,\n bigint,\n bigint,\n bigint,\n `0x${string}`\n]" + }, + "value": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "warnings": { + "optional": false, + "readonly": false, + "type": "string[]" + } + } + }, + "ReadCallback": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "((spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpecTuple, callbackGasLimit: bigint) => readonly unknown[]) | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "gasLimit": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "target": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "SimulateReadResult": { + "type": "{\n args?: readonly unknown[];\n error: string;\n errorName?: string;\n ok: false;\n} | {\n ok: true;\n}", + "members": { + "ok": { + "optional": false, + "readonly": false, + "type": "boolean" + } + } + }, + "ParsedReadRequest": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ParsedReadRequest", + "members": { + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackTarget": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "logIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "originalFunder": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "requestId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "requestIdUint": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "spec": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec" + }, + "totalPaid": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "FulfilOutcome": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").FulfilOutcome", + "members": { + "burned": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "delivered": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "expired": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "failReason": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "gasReported": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refunded": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refundFailed": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "ReceiptLike": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike", + "members": { + "logs": { + "optional": false, + "readonly": false, + "type": "readonly {\n address: string;\n data: string;\n logIndex?: number | string;\n topics: readonly string[];\n}[]" + } + } + }, + "ReadRef": { + "type": "{\n requestId: `0x${string}` | bigint;\n} | {\n txHash: `0x${string}`;\n}", + "members": {} + }, + "ReadLifecycleOptions": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadLifecycleOptions", + "members": { + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "resultShape": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadFees": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadFees", + "members": { + "burned": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "paid": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "refunded": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refundFailed": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + } + } + }, + "UniversalReadResponse": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse", + "members": { + "callbackDelivered": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "callbackFailReason": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "decoded": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").DecodedReadResult | undefined" + }, + "decodeError": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destination": { + "optional": false, + "readonly": false, + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}" + }, + "errorMsg": { + "optional": false, + "readonly": false, + "type": "string" + }, + "explorerUrl": { + "optional": false, + "readonly": false, + "type": "string" + }, + "fees": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadFees" + }, + "isTerminal": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "outcome": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME" + }, + "pcTx": { + "optional": false, + "readonly": false, + "type": "readonly {\n blockHeight: number;\n errorMsg: string;\n status: string;\n txHash: `0x${string}`;\n}[]" + }, + "raw": { + "optional": false, + "readonly": false, + "type": "{\n errorCode: import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n resultData: `0x${string}`;\n status: import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n} | null" + }, + "refresh": { + "optional": false, + "readonly": false, + "type": "() => Promise>" + }, + "request": { + "optional": false, + "readonly": false, + "type": "{\n callbackGasLimit: bigint;\n callbackTarget: `0x${string}`;\n createdAtHeight: bigint;\n logIndex: number;\n originalFunder: `0x${string}`;\n refundTo: `0x${string}`;\n spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec;\n}" + }, + "requestId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "requestIdUint": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "status": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "value": { + "optional": true, + "readonly": false, + "type": "T | undefined" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/read-state/read-state.types\").ReadLifecycleOptions) => Promise>" + } + } + }, + "ReadResponseTuple": { + "type": "{\n -readonly [K in keyof R]: import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse ? T : unknown>;\n}", + "members": {} + }, + "BatchReadResponse": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").BatchReadResponse", + "members": { + "atomic": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "count": { + "optional": false, + "readonly": false, + "type": "number" + }, + "reads": { + "optional": false, + "readonly": false, + "type": "{\n -readonly [K in keyof R]: import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse ? T : unknown>;\n}" + }, + "transactionHashes": { + "optional": true, + "readonly": false, + "type": "readonly `0x${string}`[] | undefined" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: Omit) => Promise>" + } + } + }, + "ReadOptions": { + "type": "((import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">)) & {\n callback?: (Pick & Required>) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n };\n}", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "advanced": { + "optional": true, + "readonly": false, + "type": "{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n} | undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "({\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} & {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n}) | ({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick & Pick & Required>) | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadPrepareOptions": { + "type": "((((({\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\">) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n}) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">)) & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n}) | ((({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n}) | ({\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\">)) & {\n blockNumber?: never;\n minConfirmations?: never;\n})) & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n}) & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "advanced": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadQueryOptions": { + "type": "({\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\">) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n}) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n}) | ({\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\">)", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadCallbackOptions": { + "type": "{\n callback?: ({\n gasLimit?: bigint;\n target: `0x${string}`;\n } & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n };\n}", + "members": { + "callback": { + "optional": true, + "readonly": false, + "type": "({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} | undefined" + } + } + }, + "ReadValue": { + "type": "O extends {\n abi: infer A extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: infer F extends string;\n} ? number extends A[\"length\"] ? unknown : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, O extends {\n args: infer Args extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n} ? Args : readonly [\n] extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> ? import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> & readonly [\n] : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>> extends infer Selected ? Selected extends {\n outputs: readonly unknown[];\n type: \"function\";\n} & import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiFunction ? {\n [key in keyof {\n [key in keyof import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"]]: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterToPrimitiveType, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"][key], import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterKind>;\n }]: {\n [key in keyof import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"]]: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterToPrimitiveType, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"][key], import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterKind>;\n }[key];\n} extends infer types ? types extends readonly [\n] ? void : types extends readonly [\n infer type\n] ? type : types : never : never : never : O extends {\n web2: {\n extract: infer E extends readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n };\n} ? {\n readonly [K in keyof E]: {\n bool: boolean;\n bytes: `0x${string}`;\n int256: bigint;\n string: string;\n uint256: bigint;\n }[E[K][\"valueType\"]];\n} : O extends {\n storageSlot: unknown;\n} ? `0x${string}` : O extends {\n idl: infer I extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} ? string extends Extract, string> ? unknown : (O extends {\n functionName: infer N extends string;\n} ? N : undefined) extends string ? import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/index\").IdlAccounts[{\n [K in Extract, string>]: Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : K> extends Lowercase<(O extends {\n functionName: infer N extends string;\n } ? N : undefined) & string extends `${infer H}_${infer T}` ? `${H}${Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : (O extends {\n functionName: infer N extends string;\n } ? N : undefined) & string> ? K : never;\n}[Extract, string>]] : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/index\").IdlAccounts[Extract, string>] : bigint", + "members": {} + }, + "ValidateReadCall": { + "type": "O extends {\n abi: infer A extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: infer F extends string;\n} ? (readonly [\n] extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> ? {\n args?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n} : {\n args: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n}) & {\n functionName: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionName;\n} : O extends {\n functionName: infer N extends string;\n idl: infer I extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} ? string extends Extract, string> ? unknown : [\n {\n [K in Extract, string>]: Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : K> extends Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : N> ? K : never;\n }[Extract, string>]\n] extends [\n never\n] ? {\n functionName: Extract, string>;\n} : unknown : unknown", + "members": {} + }, + "ReadWeb2Options": { + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options", + "members": { + "body": { + "optional": true, + "readonly": false, + "type": "string | Uint8Array | undefined" + }, + "extract": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[]" + }, + "headers": { + "optional": true, + "readonly": false, + "type": "Record | undefined" + }, + "method": { + "optional": true, + "readonly": false, + "type": "\"GET\" | \"POST\" | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadTrackOptions": { + "type": "{\n advanced?: Omit, \"enforceGasCheck\">;\n resultShape?: import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape;\n}", + "members": { + "advanced": { + "optional": true, + "readonly": false, + "type": "Omit<{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n}, \"enforceGasCheck\"> | undefined" + }, + "resultShape": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape | undefined" + } + } + }, + "ReadExecuteOptions": { + "type": "{\n advanced?: {\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n } | undefined;\n progressHook?: ((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined;\n waitForCompletion?: boolean | undefined;\n}", + "members": { + "advanced": { + "optional": true, + "readonly": false, + "type": "{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n} | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + } + } + }, + "UNIVERSAL_READ_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS", + "members": { + "ABORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.ABORTED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.EXPIRED" + }, + "FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.FAILED" + }, + "FULFILLED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.FULFILLED" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.PENDING" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.UNSPECIFIED" + }, + "VOTING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.VOTING" + } + } + }, + "READ_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS", + "members": { + "ERROR": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.ERROR" + }, + "SUCCESS": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.SUCCESS" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.UNSPECIFIED" + } + } + }, + "READ_ERROR_CODE": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE", + "members": { + "INVALID_QUERY": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.INVALID_QUERY" + }, + "INVALID_RESULT": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.INVALID_RESULT" + }, + "NOT_FOUND": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.NOT_FOUND" + }, + "REJECTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.REJECTED" + }, + "REVERTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.REVERTED" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.UNSPECIFIED" + }, + "UNSUPPORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.UNSUPPORTED" + } + } + }, + "READ_OUTCOME": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME", + "members": { + "ABORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.ABORTED" + }, + "CALLBACK_FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.CALLBACK_FAILED" + }, + "DECODE_FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.DECODE_FAILED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.EXPIRED" + }, + "FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.FAILED" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.PENDING" + }, + "SOURCE_ERROR": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.SOURCE_ERROR" + }, + "SUCCESS": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.SUCCESS" + }, + "UNKNOWN": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.UNKNOWN" + } + } + }, + "CONTRACT_REQUEST_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS", + "members": { + "EXECUTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.EXECUTED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.EXPIRED" + }, + "NONE": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.NONE" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.PENDING" + }, + "SETTLED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.SETTLED" + } + } + }, + "TERMINAL_READ_STATUSES": { + "type": "ReadonlySet", + "members": {} + }, + "ReadStateError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadStateError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidReadQueryError": { + "type": "import(\"sdk/src/lib/read-state/errors\").InvalidReadQueryError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidReadSpecError": { + "type": "import(\"sdk/src/lib/read-state/errors\").InvalidReadSpecError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "violations": { + "optional": false, + "readonly": true, + "type": "readonly import(\"sdk/src/lib/read-state/errors\").ReadSpecViolation[]" + } + } + }, + "ReadHeightUnavailableError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadHeightUnavailableError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "UnsupportedReadDestinationError": { + "type": "import(\"sdk/src/lib/read-state/errors\").UnsupportedReadDestinationError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadDecodeError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadDecodeError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadTimeoutError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadTimeoutError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "lastStatus": { + "optional": false, + "readonly": true, + "type": "number" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadNotFoundError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadNotFoundError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadRegistryUnavailableError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadRegistryUnavailableError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadSpecViolation": { + "type": "\"CALLBACK_GAS_LIMIT_EXCEEDED\" | \"DOMAIN_BLOCKED\" | \"EMPTY_QUERY\" | \"EXCESSIVE_FEE\" | \"INSUFFICIENT_CALLBACK_BUDGET\" | \"INSUFFICIENT_FEE\" | \"INVALID_ACCOUNT_ID\" | \"INVALID_BLOCK_NUMBER\" | \"INVALID_EXPIRY_HEIGHT\" | \"INVALID_MIN_CONFIRMATIONS\" | \"SVM_OWNER_NOT_32_BYTES\" | \"ZERO_CALLBACK_BUDGET\" | \"ZERO_CALLBACK_GAS_LIMIT\" | \"ZERO_REVERT_RECIPIENT\"", + "members": {} + }, + "resolveDestination": { + "type": "(dest: import(\"sdk/src/lib/read-state/read-state.types\").ReadDestination) => import(\"sdk/src/lib/read-state/read-state.types\").ResolvedDestination", + "members": {} + }, + "encodeReadQuery": { + "type": "(destination: import(\"sdk/src/lib/read-state/read-state.types\").ReadDestination, query: import(\"sdk/src/lib/read-state/read-state.types\").ReadQuery, options?: {\n blockNumber?: bigint;\n minSlot?: bigint;\n}) => import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery", + "members": {} + }, + "decodeReadResult": { + "type": "(resultData: `0x${string}`, shape: import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape) => import(\"sdk/src/lib/read-state/read-state.types\").DecodedReadResult", + "members": {} + }, + "parseReadRequestsFromReceipt": { + "type": "(receipt: import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike, universalCallback: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").ParsedReadRequest[]", + "members": {} + }, + "parseFulfilOutcome": { + "type": "(receipt: import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike, universalCallback: `0x${string}`, requestId: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").FulfilOutcome", + "members": {} + }, + "buildReadSpecFromPreflight": { + "type": "(preflight: import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight, params: import(\"sdk/src/lib/read-state/read-state.types\").BuildReadSpecParams, defaults?: {\n refundTo?: `0x${string}`;\n}) => import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead", + "members": {} + }, + "validateReadSpec": { + "type": "(input: import(\"sdk/src/lib/read-state/validate\").ValidateReadSpecInput) => {\n ok: false;\n violations: import(\"sdk/src/lib/read-state/errors\").ReadSpecViolation[];\n} | {\n ok: true;\n}", + "members": {} + }, + "toCallData": { + "type": "(prepared: import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead, target: {\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: (spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpecTuple, callbackGasLimit: bigint) => readonly unknown[];\n functionName: string;\n}) => {\n data: `0x${string}`;\n value: bigint;\n}", + "members": {} + }, + "sizeCallbackBudget": { + "type": "(callbackGasLimit: bigint, pushGasPrice: bigint, buffer?: number) => bigint", + "members": {} + }, + "inferResultShape": { + "type": "(namespace: string, query: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape", + "members": {} + }, + "toRequestIdHex": { + "type": "(id: `0x${string}` | bigint) => `0x${string}`", + "members": {} + }, + "toReadQuery": { + "type": "(subject: string, o: ReadOptionsInput, resolvedTokenProgram?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@solana/web3.js/lib/index\").PublicKey) => import(\"sdk/src/lib/read-state/read-state.types\").ReadQuery", + "members": {} + }, + "UNIVERSAL_CALLBACK_EVM": { + "type": "readonly [\n {\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"requestExternalReadSelf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"estimateFee\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"statusOf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"enum RequestStatus\";\n readonly name: \"\";\n readonly type: \"uint8\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"isFulfilled\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getPendingRead\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly internalType: \"struct PendingRead\";\n readonly name: \"\";\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"totalEscrowed\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"blockedDomains\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly indexed: false;\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"readSpec\";\n readonly type: \"tuple\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"totalPaid\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"protocolFee\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ReadRequested\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"ReadFulfilled\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"reason\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"CallbackFailed\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"gasReported\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"burned\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"CallbackGasReported\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundSent\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundFailed\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RequestExpired\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"vaultPC\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ProtocolFeeDistributed\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidAccountId\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"EmptyQuery\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidMinConfirmations\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"DomainBlocked\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidBlockNumber\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidExpiryHeight\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroRevertRecipient\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroCallbackGasLimit\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint64\";\n readonly name: \"provided\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"max\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"CallbackGasLimitExceeded\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"required\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"InsufficientFee\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ExcessiveFee\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"actual\";\n readonly type: \"uint8\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"expected\";\n readonly type: \"uint8\";\n }\n ];\n readonly name: \"InvalidRequestStatus\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ContractIsPaused\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"CallerIsNotUCallbackModule\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n }\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"requestExternalReadSelf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n}" + }, + "1": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"estimateFee\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "2": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"statusOf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"enum RequestStatus\";\n readonly name: \"\";\n readonly type: \"uint8\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "3": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"isFulfilled\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "4": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getPendingRead\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly internalType: \"struct PendingRead\";\n readonly name: \"\";\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "5": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"totalEscrowed\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "6": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"blockedDomains\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "7": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly indexed: false;\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"readSpec\";\n readonly type: \"tuple\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"totalPaid\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"protocolFee\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ReadRequested\";\n readonly type: \"event\";\n}" + }, + "8": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"ReadFulfilled\";\n readonly type: \"event\";\n}" + }, + "9": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"reason\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"CallbackFailed\";\n readonly type: \"event\";\n}" + }, + "10": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"gasReported\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"burned\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"CallbackGasReported\";\n readonly type: \"event\";\n}" + }, + "11": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundSent\";\n readonly type: \"event\";\n}" + }, + "12": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundFailed\";\n readonly type: \"event\";\n}" + }, + "13": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RequestExpired\";\n readonly type: \"event\";\n}" + }, + "14": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"vaultPC\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ProtocolFeeDistributed\";\n readonly type: \"event\";\n}" + }, + "15": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidAccountId\";\n readonly type: \"error\";\n}" + }, + "16": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"EmptyQuery\";\n readonly type: \"error\";\n}" + }, + "17": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidMinConfirmations\";\n readonly type: \"error\";\n}" + }, + "18": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"DomainBlocked\";\n readonly type: \"error\";\n}" + }, + "19": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidBlockNumber\";\n readonly type: \"error\";\n}" + }, + "20": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidExpiryHeight\";\n readonly type: \"error\";\n}" + }, + "21": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroRevertRecipient\";\n readonly type: \"error\";\n}" + }, + "22": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroCallbackGasLimit\";\n readonly type: \"error\";\n}" + }, + "23": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint64\";\n readonly name: \"provided\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"max\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"CallbackGasLimitExceeded\";\n readonly type: \"error\";\n}" + }, + "24": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"required\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"InsufficientFee\";\n readonly type: \"error\";\n}" + }, + "25": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ExcessiveFee\";\n readonly type: \"error\";\n}" + }, + "26": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"actual\";\n readonly type: \"uint8\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"expected\";\n readonly type: \"uint8\";\n }\n ];\n readonly name: \"InvalidRequestStatus\";\n readonly type: \"error\";\n}" + }, + "27": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ContractIsPaused\";\n readonly type: \"error\";\n}" + }, + "28": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"CallerIsNotUCallbackModule\";\n readonly type: \"error\";\n}" + }, + "29": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n}" + }, + "length": { + "optional": false, + "readonly": true, + "type": "30" + } + } + }, + "UNIVERSAL_READ_REGISTRY_EVM": { + "type": "readonly [\n {\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n },\n {\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"read\";\n readonly outputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"universalCallback_\";\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"constructor\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"initialize\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getLocalContext\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"hasResult\";\n readonly outputs: readonly [\n {\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"onUniversalData\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"queryKeyOf\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes32\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"readerOf\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"requestOrderOf\";\n readonly outputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"universalCallback\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"resultByRequestId\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"latestResult\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"version\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"Initialized\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadRequested\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadStored\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidInitialization\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"NotInitializing\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroAddressInit\";\n readonly type: \"error\";\n }\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n },\n {\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"read\";\n readonly outputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n}" + }, + "1": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"universalCallback_\";\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"constructor\";\n}" + }, + "2": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"initialize\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n}" + }, + "3": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getLocalContext\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "4": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"hasResult\";\n readonly outputs: readonly [\n {\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "5": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"onUniversalData\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n}" + }, + "6": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"queryKeyOf\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes32\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "7": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"readerOf\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "8": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"requestOrderOf\";\n readonly outputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "9": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"universalCallback\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "10": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"resultByRequestId\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "11": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"latestResult\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "12": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"version\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"Initialized\";\n readonly type: \"event\";\n}" + }, + "13": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadRequested\";\n readonly type: \"event\";\n}" + }, + "14": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadStored\";\n readonly type: \"event\";\n}" + }, + "15": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidInitialization\";\n readonly type: \"error\";\n}" + }, + "16": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"NotInitializing\";\n readonly type: \"error\";\n}" + }, + "17": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n}" + }, + "18": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroAddressInit\";\n readonly type: \"error\";\n}" + }, + "length": { + "optional": false, + "readonly": true, + "type": "19" + } + } + }, + "PushChainExecutionError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").PushChainExecutionError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PushChainBatchExecutionError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").PushChainBatchExecutionError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": false, + "readonly": true, + "type": "`0x${string}`[]" + } + } + }, + "DecodedErrorPayload": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload", + "members": { + "decoded": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "name": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "selector": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "PushChainInitializeOptions": { + "type": "import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions", + "members": { + "agenticWallet": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "blockExplorers": { + "optional": true, + "readonly": false, + "type": "Partial> | undefined" + }, + "network": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "printTraces": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "rpcUrls": { + "optional": true, + "readonly": false, + "type": "Partial> | undefined" + } + } + }, + "AGENTIC_ERROR_CODE": { + "type": "{\n readonly AGENT_GAS_INSUFFICIENT: \"AGENT_GAS_INSUFFICIENT\";\n readonly AGENT_IS_OWNER: \"AGENT_IS_OWNER\";\n readonly AMBIGUOUS_RULE: \"AMBIGUOUS_RULE\";\n readonly ASSET_CHAIN_MISMATCH: \"ASSET_CHAIN_MISMATCH\";\n readonly CAPABILITY_UNAVAILABLE: \"CAPABILITY_UNAVAILABLE\";\n readonly CREATE_PARTIAL: \"CREATE_PARTIAL\";\n readonly FROM_NOT_ALLOWED: \"FROM_NOT_ALLOWED\";\n readonly GATEWAY_ALLOWANCE_INSUFFICIENT: \"GATEWAY_ALLOWANCE_INSUFFICIENT\";\n readonly GENERATION_UNSUPPORTED: \"GENERATION_UNSUPPORTED\";\n readonly INCONSISTENT_READ: \"INCONSISTENT_READ\";\n readonly INDEX_RACE: \"INDEX_RACE\";\n readonly INVALID_RULE: \"INVALID_RULE\";\n readonly NO_RULES_FOR_CHAIN: \"NO_RULES_FOR_CHAIN\";\n readonly NOT_AGENTIC_WALLET: \"NOT_AGENTIC_WALLET\";\n readonly NOT_ALLOWED_IN_AGENTIC_MODE: \"NOT_ALLOWED_IN_AGENTIC_MODE\";\n readonly NOT_OWNER_OR_AGENT: \"NOT_OWNER_OR_AGENT\";\n readonly NOT_WALLET_OWNER: \"NOT_WALLET_OWNER\";\n readonly READ_ONLY: \"READ_ONLY\";\n readonly RECEIPT_MISMATCH: \"RECEIPT_MISMATCH\";\n readonly RECEIPT_UNAVAILABLE: \"RECEIPT_UNAVAILABLE\";\n readonly REVOKE_NEEDS_TARGET: \"REVOKE_NEEDS_TARGET\";\n readonly RULE_LIMIT_EXCEEDED: \"RULE_LIMIT_EXCEEDED\";\n readonly RULE_NOT_FOUND: \"RULE_NOT_FOUND\";\n readonly RULE_READ_FAILED: \"RULE_READ_FAILED\";\n readonly TARGET_NOT_ON_RULE_CHAIN: \"TARGET_NOT_ON_RULE_CHAIN\";\n readonly WALLET_BALANCE_INSUFFICIENT: \"WALLET_BALANCE_INSUFFICIENT\";\n readonly WALLET_NOT_DEPLOYED: \"WALLET_NOT_DEPLOYED\";\n}", + "members": { + "AGENT_GAS_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\"" + }, + "AGENT_IS_OWNER": { + "optional": false, + "readonly": true, + "type": "\"AGENT_IS_OWNER\"" + }, + "AMBIGUOUS_RULE": { + "optional": false, + "readonly": true, + "type": "\"AMBIGUOUS_RULE\"" + }, + "ASSET_CHAIN_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"ASSET_CHAIN_MISMATCH\"" + }, + "CAPABILITY_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"CAPABILITY_UNAVAILABLE\"" + }, + "CREATE_PARTIAL": { + "optional": false, + "readonly": true, + "type": "\"CREATE_PARTIAL\"" + }, + "FROM_NOT_ALLOWED": { + "optional": false, + "readonly": true, + "type": "\"FROM_NOT_ALLOWED\"" + }, + "GATEWAY_ALLOWANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"GATEWAY_ALLOWANCE_INSUFFICIENT\"" + }, + "GENERATION_UNSUPPORTED": { + "optional": false, + "readonly": true, + "type": "\"GENERATION_UNSUPPORTED\"" + }, + "INCONSISTENT_READ": { + "optional": false, + "readonly": true, + "type": "\"INCONSISTENT_READ\"" + }, + "INDEX_RACE": { + "optional": false, + "readonly": true, + "type": "\"INDEX_RACE\"" + }, + "INVALID_RULE": { + "optional": false, + "readonly": true, + "type": "\"INVALID_RULE\"" + }, + "NO_RULES_FOR_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"NO_RULES_FOR_CHAIN\"" + }, + "NOT_AGENTIC_WALLET": { + "optional": false, + "readonly": true, + "type": "\"NOT_AGENTIC_WALLET\"" + }, + "NOT_ALLOWED_IN_AGENTIC_MODE": { + "optional": false, + "readonly": true, + "type": "\"NOT_ALLOWED_IN_AGENTIC_MODE\"" + }, + "NOT_OWNER_OR_AGENT": { + "optional": false, + "readonly": true, + "type": "\"NOT_OWNER_OR_AGENT\"" + }, + "NOT_WALLET_OWNER": { + "optional": false, + "readonly": true, + "type": "\"NOT_WALLET_OWNER\"" + }, + "READ_ONLY": { + "optional": false, + "readonly": true, + "type": "\"READ_ONLY\"" + }, + "RECEIPT_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_MISMATCH\"" + }, + "RECEIPT_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_UNAVAILABLE\"" + }, + "REVOKE_NEEDS_TARGET": { + "optional": false, + "readonly": true, + "type": "\"REVOKE_NEEDS_TARGET\"" + }, + "RULE_LIMIT_EXCEEDED": { + "optional": false, + "readonly": true, + "type": "\"RULE_LIMIT_EXCEEDED\"" + }, + "RULE_NOT_FOUND": { + "optional": false, + "readonly": true, + "type": "\"RULE_NOT_FOUND\"" + }, + "RULE_READ_FAILED": { + "optional": false, + "readonly": true, + "type": "\"RULE_READ_FAILED\"" + }, + "TARGET_NOT_ON_RULE_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"TARGET_NOT_ON_RULE_CHAIN\"" + }, + "WALLET_BALANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"WALLET_BALANCE_INSUFFICIENT\"" + }, + "WALLET_NOT_DEPLOYED": { + "optional": false, + "readonly": true, + "type": "\"WALLET_NOT_DEPLOYED\"" + } + } + }, + "AgenticError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"AMBIGUOUS_RULE\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"CREATE_PARTIAL\" | \"FROM_NOT_ALLOWED\" | \"GATEWAY_ALLOWANCE_INSUFFICIENT\" | \"GENERATION_UNSUPPORTED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"REVOKE_NEEDS_TARGET\" | \"RULE_LIMIT_EXCEEDED\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"" + }, + "details": { + "optional": true, + "readonly": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "AgenticRevertError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticRevertError", + "members": { + "agenticCode": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + } + } + }, + "AgenticAddress": { + "type": "`0x${string}`", + "members": {} + }, + "AgenticDoor": { + "type": "\"agent\" | \"owner\"", + "members": {} + }, + "AgenticErrorCode": { + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"AMBIGUOUS_RULE\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"CREATE_PARTIAL\" | \"FROM_NOT_ALLOWED\" | \"GATEWAY_ALLOWANCE_INSUFFICIENT\" | \"GENERATION_UNSUPPORTED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"REVOKE_NEEDS_TARGET\" | \"RULE_LIMIT_EXCEEDED\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"", + "members": {} + }, + "AgenticHex": { + "type": "`0x${string}`", + "members": {} + }, + "AgenticNamespace": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace", + "members": { + "create": { + "optional": false, + "readonly": false, + "type": "(label: string, options: import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions) => Promise" + }, + "derive": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n index?: number;\n}) => Promise<{\n address: `0x${string}`;\n deployed: boolean;\n index: number;\n}>" + }, + "list": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n wallets: import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary[];\n}>" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "(address: `0x${string}`) => import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet" + } + } + }, + "AgenticNetworkConstants": { + "type": "import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants", + "members": { + "ENVELOPE_VERSION": { + "optional": false, + "readonly": false, + "type": "number" + }, + "FACTORY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "MAX_ALLOWED_CALLS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "MAX_PINS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "RULES_POLICY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticProgressHook": { + "type": "(event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void", + "members": {} + }, + "AgenticTxMetadata": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticTxMetadata", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destinationAccount": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "destinationCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "destinationInstruction": { + "optional": true, + "readonly": false, + "type": "{\n accounts: readonly {\n isWritable: boolean;\n pubkey: `0x${string}`;\n }[];\n data: `0x${string}`;\n program: `0x${string}`;\n} | undefined" + }, + "destinationTransfer": { + "optional": true, + "readonly": false, + "type": "{\n amount: bigint;\n recipient: `0x${string}`;\n token: `0x${string}`;\n} | undefined" + }, + "door": { + "optional": false, + "readonly": false, + "type": "\"agent\" | \"owner\"" + }, + "nativeCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "rawData": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rawTo": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesId": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticWallet": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "checkpoints": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n sinceBlock?: bigint;\n}) => Promise<{\n checkpoints: import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint[];\n}>" + }, + "info": { + "optional": false, + "readonly": false, + "type": "() => Promise" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n owner: `0x${string}`;\n}>" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "{\n add(rules: import(\"sdk/src/lib/agentic/agentic.types\").Rule[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise<{\n rulesIds: `0x${string}`[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n get(rulesId: `0x${string}`): Promise;\n list(): Promise<{\n rules: import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord[];\n }>;\n revoke(rulesIds: `0x${string}`[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n revoke(params: {\n all: true;\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n update(params: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n rules: {\n rule: import(\"sdk/src/lib/agentic/agentic.types\").Rule;\n rulesId: `0x${string}`;\n }[];\n }): Promise<{\n rules: {\n replaced: `0x${string}`;\n rulesId: `0x${string}`;\n }[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n}" + }, + "setLabel": { + "optional": false, + "readonly": false, + "type": "(label: string, opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n}) => Promise" + } + } + }, + "AllowedCall": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall", + "members": { + "beneficiary": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "beneficiaryOffset": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValue": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "`${string}(${string})` | `0x${string}`" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AssetCap": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap", + "members": { + "maxPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/constants/tokens\").MoveableToken" + } + } + }, + "Checkpoint": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint", + "members": { + "blockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "kind": { + "optional": false, + "readonly": false, + "type": "\"OWNER_ACTION\" | \"RULES_GRANTED\" | \"RULES_REVOKED\"" + }, + "ref": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "seq": { + "optional": false, + "readonly": false, + "type": "number" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "CheckpointKind": { + "type": "\"OWNER_ACTION\" | \"RULES_GRANTED\" | \"RULES_REVOKED\"", + "members": {} + }, + "CreateOptions": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions", + "members": { + "progressHook": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook | undefined" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Rule[]" + } + } + }, + "CreateResult": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateResult", + "members": { + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "rulesIds": { + "optional": false, + "readonly": false, + "type": "`0x${string}`[]" + }, + "tx": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ForeignChainNamespace": { + "type": "`eip155:${string}` | `solana:${string}`", + "members": {} + }, + "NativeAction": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeAction", + "members": { + "amount": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AmountLimit | undefined" + }, + "maxCalls": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValuePerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxValueTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "pins": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ArgPin[] | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "NativeMultiRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeMultiRule", + "members": { + "actions": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeAction[]" + }, + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "amount": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "maxCalls": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "maxValuePerCall": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "maxValueTotal": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "pins": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "selector": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "target": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "NativeRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeMultiRule | import(\"sdk/src/lib/agentic/agentic.types\").NativeSingleRule", + "members": { + "actions": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeAction[] | undefined" + }, + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "amount": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AmountLimit | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "maxCalls": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValuePerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxValueTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "pins": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ArgPin[] | undefined" + }, + "selector": { + "optional": true, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector | undefined" + }, + "target": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "NativeSingleRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeSingleRule", + "members": { + "actions": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "amount": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AmountLimit | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "maxCalls": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValuePerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxValueTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "pins": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ArgPin[] | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "SolanaRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").SolanaRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "allowedInstructions": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").SvmInstructionRule[]" + }, + "assets": { + "optional": false, + "readonly": false, + "type": "{\n maxPerCall: bigint;\n maxTotal?: bigint;\n token: import(\"sdk/src/lib/constants/tokens\").MoveableToken | string;\n}[]" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "`solana:${string}`" + }, + "maxGasPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "outputTokens": { + "optional": true, + "readonly": false, + "type": "string[] | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "DecodedSolanaRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").DecodedSolanaRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "assets": { + "optional": false, + "readonly": false, + "type": "{\n maxPerCall: bigint;\n maxTotal: bigint;\n token: string;\n}[]" + }, + "ceaAccounts": { + "optional": false, + "readonly": false, + "type": "readonly `0x${string}`[]" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "`solana:${string}`" + }, + "dataPins": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/agentic/codec/svm-terms\").SvmDataPinWire[]" + }, + "expectedCEA": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "format": { + "optional": false, + "readonly": false, + "type": "\"decoded\"" + }, + "gatewayProgram": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "maxGasPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pins": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/agentic/codec/svm-terms\").SvmAccountPinWire[]" + }, + "programs": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/agentic/codec/svm-terms\").AllowedProgramWire[]" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "SvmInstructionRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").SvmInstructionRule", + "members": { + "accounts": { + "optional": false, + "readonly": false, + "type": "{\n expected: import(\"sdk/src/lib/agentic/agentic.types\").SvmAccountRef;\n name: string;\n}[]" + }, + "fields": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").SvmFieldConstraint[] | undefined" + }, + "instruction": { + "optional": false, + "readonly": false, + "type": "{\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n name: string;\n}" + }, + "program": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "SvmAccountRef": { + "type": "{\n address: string;\n kind: \"address\";\n} | {\n kind: \"walletATA\";\n token: string;\n} | {\n kind: \"walletCEA\";\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"address\" | \"walletATA\" | \"walletCEA\"" + } + } + }, + "SvmFieldConstraint": { + "type": "{\n denominator: string;\n minRatio: {\n den: bigint;\n num: bigint;\n };\n numerator: string;\n} | {\n equals: `0x${string}` | bigint | boolean;\n name: string;\n} | {\n max: bigint;\n name: string;\n} | {\n min: bigint;\n name: string;\n}", + "members": {} + }, + "Rule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule | import(\"sdk/src/lib/agentic/agentic.types\").SolanaRule | import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "`eip155:${string}` | `solana:${string}` | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "RulesRecord": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "enabled": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "rule": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").DecodedSolanaRule | import(\"sdk/src/lib/agentic/agentic.types\").Rule" + }, + "rulesId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Selector": { + "type": "`${string}(${string})` | `0x${string}`", + "members": {} + }, + "UniversalRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall[]" + }, + "assets": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap[]" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "`eip155:${string}`" + }, + "maxGasPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "WalletInfo": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").WalletInfo", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "label": { + "optional": false, + "readonly": false, + "type": "string" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "rulesCount": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "WalletSummary": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "label": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesCount": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "PushChain": { + "type": "import(\"sdk/src/lib/push-chain/push-chain\").PushChain", + "members": { + "accountStatus": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus" + }, + "accountStatusReady": { + "optional": false, + "readonly": false, + "type": "Promise" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace" + }, + "explorer": { + "optional": false, + "readonly": false, + "type": "{\n getTransactionUrl: (txHash: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n listAllUrls: () => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n listUrls: (options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n}" + }, + "funds": { + "optional": false, + "readonly": false, + "type": "{\n getConversionQuote: (amountIn: bigint, options: {\n from: import(\"sdk/src/lib/constants/tokens\").PayableToken | undefined;\n to: import(\"sdk/src/lib/constants/tokens\").MoveableToken | undefined;\n }) => Promise;\n}" + }, + "getAccountStatus": { + "optional": false, + "readonly": false, + "type": "(options?: {\n forceRefresh?: boolean;\n}) => Promise" + }, + "isReadMode": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "moveable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").MoveableTokenAccessor;\n}" + }, + "payable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").PayableTokenAccessor;\n}" + }, + "reinitialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "universal": { + "optional": false, + "readonly": false, + "type": "{\n readonly account: `0x${string}`;\n executeReads: (reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>;\n executeTransactions: (txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise;\n migrateCEA: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"migrateCEA\"];\n readonly origin: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n prepareRead: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n prepareTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"prepareTransaction\"];\n read: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n rescueFunds: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"rescueFunds\"];\n sendTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"execute\"];\n signMessage: (data: Uint8Array) => Promise;\n signTypedData: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n trackRead: {\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n };\n trackTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"trackTransaction\"];\n}" + }, + "upgradeAccount": { + "optional": false, + "readonly": false, + "type": "(options?: {\n progressHook?: (progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n}) => Promise" + } + } + } + }, + "pushChainStatic": { + "CONSTANTS": { + "optional": false, + "readonly": false, + "type": "{\n AGENTIC: Readonly>>;\n CHAIN: typeof import(\"sdk/src/lib/constants/enums\").CHAIN;\n LIBRARY: typeof import(\"sdk/src/lib/constants/enums\").LIBRARY;\n MOVEABLE: {\n TOKEN: import(\"sdk/src/lib/constants/tokens\").MoveableTokenConstantsMap;\n };\n PAYABLE: {\n TOKEN: import(\"sdk/src/lib/constants/tokens\").PayableTokenConstantsMap;\n };\n PUSH_NETWORK: typeof import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n READ: {\n readonly CALLBACK_BUDGET_BUFFER: 3;\n readonly CHAIN: {\n readonly WEB2: \"web2\";\n } & Readonly<{\n readonly ARBITRUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA;\n readonly BASE_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA;\n readonly BNB_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET;\n readonly ETHEREUM_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET;\n readonly ETHEREUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA;\n readonly PUSH_LOCALNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET;\n readonly PUSH_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET;\n readonly PUSH_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly PUSH_TESTNET_DONUT: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly SOLANA_DEVNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET;\n readonly SOLANA_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET;\n readonly SOLANA_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n readonly WEB2: \"web2\";\n }>;\n readonly DEFAULT_EXPIRY_BLOCKS: 300n;\n readonly ERROR_CODE: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n readonly MAX_CALLBACK_GAS_LIMIT: 1000000n;\n readonly MIN_CONFIRMATIONS_FLOOR: 1;\n readonly NAMESPACE: {\n readonly EVM: \"eip155\";\n readonly SVM: \"solana\";\n readonly WEB2: \"web2\";\n };\n readonly OUTCOME: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME;\n readonly REGISTRY_CALLBACK_GAS: 500000n;\n readonly RESULT_STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n readonly STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS;\n readonly UNIVERSAL_CALLBACK_ADDRESSES: Record;\n readonly UNIVERSAL_CORE_ADDRESSES: Record;\n readonly UNIVERSAL_READ_REGISTRY_ADDRESS: {\n readonly TESTNET_DONUT: \"0x00000000000000000000000000000000000000b2\";\n };\n readonly WEB2: \"web2\";\n readonly WEB2_DEFAULT_TIMEOUT_MS: 5000;\n readonly WEB2_MAX_EXTRACT_ENTRIES: 16;\n };\n}" + }, + "initialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "utils": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/utils\").Utils" + } + }, + "pushChainInstance": { + "accountStatus": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus" + }, + "accountStatusReady": { + "optional": false, + "readonly": false, + "type": "Promise" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace" + }, + "explorer": { + "optional": false, + "readonly": false, + "type": "{\n getTransactionUrl: (txHash: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n listAllUrls: () => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n listUrls: (options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n}" + }, + "funds": { + "optional": false, + "readonly": false, + "type": "{\n getConversionQuote: (amountIn: bigint, options: {\n from: import(\"sdk/src/lib/constants/tokens\").PayableToken | undefined;\n to: import(\"sdk/src/lib/constants/tokens\").MoveableToken | undefined;\n }) => Promise;\n}" + }, + "getAccountStatus": { + "optional": false, + "readonly": false, + "type": "(options?: {\n forceRefresh?: boolean;\n}) => Promise" + }, + "isReadMode": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "moveable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").MoveableTokenAccessor;\n}" + }, + "payable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").PayableTokenAccessor;\n}" + }, + "reinitialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "universal": { + "optional": false, + "readonly": false, + "type": "{\n readonly account: `0x${string}`;\n executeReads: (reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>;\n executeTransactions: (txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise;\n migrateCEA: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"migrateCEA\"];\n readonly origin: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n prepareRead: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n prepareTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"prepareTransaction\"];\n read: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n rescueFunds: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"rescueFunds\"];\n sendTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"execute\"];\n signMessage: (data: Uint8Array) => Promise;\n signTypedData: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n trackRead: {\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n };\n trackTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"trackTransaction\"];\n}" + }, + "upgradeAccount": { + "optional": false, + "readonly": false, + "type": "(options?: {\n progressHook?: (progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n}) => Promise" + } + }, + "transactionMethods": { + "account": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "executeReads": { + "optional": false, + "readonly": false, + "type": "(reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>" + }, + "executeTransactions": { + "optional": false, + "readonly": false, + "type": "(txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise" + }, + "migrateCEA": { + "optional": false, + "readonly": false, + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => Promise" + }, + "origin": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "prepareRead": { + "optional": false, + "readonly": false, + "type": "(subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>" + }, + "prepareTransaction": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions) => Promise" + }, + "read": { + "optional": false, + "readonly": false, + "type": "(subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>" + }, + "rescueFunds": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").RescueFundsParams) => Promise" + }, + "sendTransaction": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").ExecuteParams | import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions) => Promise" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": false, + "readonly": false, + "type": "({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise" + }, + "trackRead": { + "optional": false, + "readonly": false, + "type": "{\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n}" + }, + "trackTransaction": { + "optional": false, + "readonly": false, + "type": "(txHash: string, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TrackTransactionOptions) => Promise" + } + }, + "utilityMethods": { + "account": { + "optional": false, + "readonly": false, + "type": "{\n convertExecutorToOriginAccount: (ueaAddress: `0x${string}`, options?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n }) => Promise;\n convertOriginToExecutor: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n onlyCompute?: boolean;\n }) => Promise;\n deriveExecutorAccount: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n skipNetworkCheck?: boolean;\n }) => Promise;\n fromChainAgnostic: (caip: string) => import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n resolveControllerAccount: (address: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n skipNetworkCheck?: boolean;\n }) => Promise;\n toChainAgnostic: (address: string, options: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n toUniversal: (address: string, options: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n}" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "{\n actionId: (target: `0x${string}`, selector: \"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector) => `0x${string}`;\n configId: (wallet: `0x${string}`, rulesId: `0x${string}`, actionId: `0x${string}`) => `0x${string}`;\n decodeRules: (bytes: `0x${string}`, ctx?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n pushChainNamespace?: string;\n }) => import(\"sdk/src/lib/agentic/agentic.types\").DecodedSolanaRule | import(\"sdk/src/lib/agentic/agentic.types\").Rule;\n}" + }, + "chains": { + "optional": false, + "readonly": false, + "type": "{\n getChainName: (chainNamespace: string) => string | undefined;\n getChainNamespace: (chainName: string) => string | undefined;\n getSupportedChains: (network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK) => {\n chains: import(\"sdk/src/lib/constants/enums\").CHAIN[];\n };\n getSupportedChainsByName: (network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK) => {\n chains: string[];\n };\n}" + }, + "conversion": { + "optional": false, + "readonly": false, + "type": "{\n slippageToMinAmount(amount: string, options: {\n slippageBps: number;\n }): string;\n}" + }, + "helpers": { + "optional": false, + "readonly": false, + "type": "{\n encodeTxData({ abi, idl, functionName, args, }: {\n abi?: any;\n args?: any[];\n functionName: string;\n idl?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n }): `0x${string}`;\n formatUnits(value: bigint | string, decimalsOrOptions: {\n decimals: number;\n precision?: number;\n } | number): string;\n getChainName: (chainName: string) => string | undefined;\n parseUnits(value: string, exponent: {\n decimals: number;\n } | number): bigint;\n}" + }, + "signer": { + "optional": false, + "readonly": false, + "type": "{\n construct: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options: {\n signAndSendTransaction: (unsignedTx: Uint8Array) => Promise;\n signAuthorization?: (params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise;\n signMessage: (data: Uint8Array) => Promise;\n signTypedData?: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n }) => import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton;\n toUniversal: (signer: import(\"sdk/src/lib/universal/universal.types\").EthersV5SignerType | import(\"sdk/src/lib/universal/universal.types\").EthersV6SignerType | import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton | import(\"sdk/src/lib/universal/universal.types\").ViemSignerType) => Promise;\n toUniversalFromKeypair: (clientOrAccount: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@solana/web3.js/lib/index\").Keypair | import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").WalletClient | import(\"sdk/src/lib/universal/universal.types\").EthersV6SignerType, { chain, library }: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n library: import(\"sdk/src/lib/constants/enums\").LIBRARY;\n }) => Promise;\n}" + }, + "svm": { + "optional": false, + "readonly": false, + "type": "{\n getRegisteredIdls: () => Array<{\n address: `0x${string}`;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n }>;\n registerIdl: (idl: unknown) => void;\n}" + }, + "tokens": { + "optional": false, + "readonly": false, + "type": "{\n getMoveableTokens(chainOrClient?: import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/push-chain/push-chain\").PushChain): {\n tokens: Array<{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n decimals: number;\n mechanism: \"approve\" | \"native\" | \"permit2\";\n prc20Address?: `0x${string}`;\n sourceChain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n symbol: string;\n }>;\n };\n getPayableTokens(chainOrClient?: import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/push-chain/push-chain\").PushChain): {\n tokens: Array<{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n decimals: number;\n mechanism: \"approve\" | \"native\" | \"permit2\";\n symbol: string;\n }>;\n };\n getPC20Address(address: string, options: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n rpcUrls?: Partial>;\n strict?: boolean;\n }): Promise;\n getPRC20Address: (token: {\n address: string;\n chain: string;\n } | import(\"sdk/src/lib/constants/tokens\").MoveableToken, options?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n }) => {\n address: `0x${string}`;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n decimals: number;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n symbol: string;\n };\n}" + } + }, + "initialize": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise", + "agwConstants": { + "ENVELOPE_VERSION": { + "optional": false, + "readonly": false, + "type": "number" + }, + "FACTORY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "MAX_ALLOWED_CALLS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "MAX_PINS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "RULES_POLICY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + }, + "constants": { + "AGENTIC": { + "optional": false, + "readonly": false, + "type": "{\n readonly LOCALNET?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n readonly MAINNET?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n readonly TESTNET?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n readonly TESTNET_DONUT?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n}" + }, + "CHAIN": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "LIBRARY": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").LIBRARY" + }, + "MOVEABLE": { + "optional": false, + "readonly": false, + "type": "{\n TOKEN: import(\"sdk/src/lib/constants/tokens\").MoveableTokenConstantsMap;\n}" + }, + "PAYABLE": { + "optional": false, + "readonly": false, + "type": "{\n TOKEN: import(\"sdk/src/lib/constants/tokens\").PayableTokenConstantsMap;\n}" + }, + "PUSH_NETWORK": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "READ": { + "optional": false, + "readonly": false, + "type": "{\n readonly CALLBACK_BUDGET_BUFFER: 3;\n readonly CHAIN: {\n readonly WEB2: \"web2\";\n } & Readonly<{\n readonly ARBITRUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA;\n readonly BASE_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA;\n readonly BNB_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET;\n readonly ETHEREUM_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET;\n readonly ETHEREUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA;\n readonly PUSH_LOCALNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET;\n readonly PUSH_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET;\n readonly PUSH_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly PUSH_TESTNET_DONUT: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly SOLANA_DEVNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET;\n readonly SOLANA_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET;\n readonly SOLANA_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n readonly WEB2: \"web2\";\n }>;\n readonly DEFAULT_EXPIRY_BLOCKS: 300n;\n readonly ERROR_CODE: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n readonly MAX_CALLBACK_GAS_LIMIT: 1000000n;\n readonly MIN_CONFIRMATIONS_FLOOR: 1;\n readonly NAMESPACE: {\n readonly EVM: \"eip155\";\n readonly SVM: \"solana\";\n readonly WEB2: \"web2\";\n };\n readonly OUTCOME: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME;\n readonly REGISTRY_CALLBACK_GAS: 500000n;\n readonly RESULT_STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n readonly STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS;\n readonly UNIVERSAL_CALLBACK_ADDRESSES: Record;\n readonly UNIVERSAL_CORE_ADDRESSES: Record;\n readonly UNIVERSAL_READ_REGISTRY_ADDRESS: {\n readonly TESTNET_DONUT: \"0x00000000000000000000000000000000000000b2\";\n };\n readonly WEB2: \"web2\";\n readonly WEB2_DEFAULT_TIMEOUT_MS: 5000;\n readonly WEB2_MAX_EXTRACT_ENTRIES: 16;\n}" + } + } + }, + "scope": "All root exports and declared public members, PushChain static/instance members, universal transaction methods, utility groups, readonly/optional markers and constants. Behavior/default/deployment changes need the written session review." +} diff --git a/plan/agw/research/native-multi-action-e2e-2026-10-12/credential-scan.json b/plan/agw/research/native-multi-action-e2e-2026-10-12/credential-scan.json new file mode 100644 index 00000000..4c200d6d --- /dev/null +++ b/plan/agw/research/native-multi-action-e2e-2026-10-12/credential-scan.json @@ -0,0 +1,4 @@ +{ + "scanned": 37, + "credentialMatches": [] +} diff --git a/plan/agw/research/native-multi-action-e2e-2026-10-12/live-evidence.jsonl b/plan/agw/research/native-multi-action-e2e-2026-10-12/live-evidence.jsonl new file mode 100644 index 00000000..18bd02fe --- /dev/null +++ b/plan/agw/research/native-multi-action-e2e-2026-10-12/live-evidence.jsonl @@ -0,0 +1,16 @@ +{"name": "native-multi-grant-read-send", "at": "2026-10-12T11:44:22.795Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0x76c1ea6815fF50407325b3752627F20BAe82b8cD", "id": "0xc56220c74ac19d10e6e06d9fc4a86686487e26f457b56cc804d638afa9ef6075", "copy": "0xeF8180C9EEB82f25Ad3B96CD50E849AF414f1b6A", "hashes": ["0x23d526366ead37fb3b2f0d9929a2665aececa7bf81e30c7ab00274b86808efee", "0x9ec060ab43138d918b12bd5fbb70fb8fa87c2bba0ef2df22b69e92eaf819e56c", "0x83587566f82943d1c7e2c17d9bdf2fa8d98ecb14c0a237072d9ea1d2e3d45120", "0xb1ed6b77c5f82f0e5dd719dfe79bb2143abdb15b47a578a317f90192a606c902"], "state": {"configs": [{"actionId": "0x4fe8d98db364b0d0802786da5e61c881c40402aa4663465b7a61732dde03167c", "config": {"initialized": true, "validUntil": 1791808978, "target": "0x0A16CBa65FfCAa4C2282b27b027Ab4A2fE46E0Bf", "selector": "0xffffffff", "maxValuePerCall": "1", "maxValueTotal": "2", "valueSpent": "1", "amount": {"enabled": false, "offset": 0, "maxPerCall": "0", "maxTotal": "0"}, "amountSpent": "0", "maxCalls": 2, "callsUsed": 1, "pins": []}}, {"actionId": "0x0e8617603fbb66bc7458db5803c01fa022ef9f48b47628d52af31c980f10421d", "config": {"initialized": true, "validUntil": 1791808978, "target": "0x2971824Db68229D087931155C2b8bB820B275809", "selector": "0xa9059cbb", "maxValuePerCall": "0", "maxValueTotal": "0", "valueSpent": "0", "amount": {"enabled": true, "offset": 36, "maxPerCall": "3", "maxTotal": "5"}, "amountSpent": "2", "maxCalls": 4, "callsUsed": 1, "pins": [{"offset": 4, "expected": "0x0000000000000000000000000a16cba65ffcaa4c2282b27b027ab4a2fe46e0bf"}]}}], "walletPC": "9", "recipientPC": "969572353733022131997650", "walletToken": "18", "recipientToken": "434311519549551168609", "checkpointCount": "1", "grantNonce": "1"}} +{"name": "native-multi-refused", "at": "2026-10-12T11:45:01.116Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0xFC43b68d04A07cD67E175849E677279de8f86531", "id": "0xc56220c74ac19d10e6e06d9fc4a86686487e26f457b56cc804d638afa9ef6075", "gate": "PolicyCheckReverted(ArgPinMismatch)", "state": {"configs": [{"actionId": "0x4fe8d98db364b0d0802786da5e61c881c40402aa4663465b7a61732dde03167c", "config": {"initialized": true, "validUntil": 1791809062, "target": "0x0A16CBa65FfCAa4C2282b27b027Ab4A2fE46E0Bf", "selector": "0xffffffff", "maxValuePerCall": "1", "maxValueTotal": "2", "valueSpent": "0", "amount": {"enabled": false, "offset": 0, "maxPerCall": "0", "maxTotal": "0"}, "amountSpent": "0", "maxCalls": 2, "callsUsed": 0, "pins": []}}, {"actionId": "0x0e8617603fbb66bc7458db5803c01fa022ef9f48b47628d52af31c980f10421d", "config": {"initialized": true, "validUntil": 1791809062, "target": "0x2971824Db68229D087931155C2b8bB820B275809", "selector": "0xa9059cbb", "maxValuePerCall": "0", "maxValueTotal": "0", "valueSpent": "0", "amount": {"enabled": true, "offset": 36, "maxPerCall": "3", "maxTotal": "5"}, "amountSpent": "0", "maxCalls": 4, "callsUsed": 0, "pins": [{"offset": 4, "expected": "0x0000000000000000000000000a16cba65ffcaa4c2282b27b027ab4a2fe46e0bf"}]}}], "walletPC": "10", "recipientPC": "969572352390339131997640", "walletToken": "20", "recipientToken": "434311519549551168589", "checkpointCount": "1", "grantNonce": "1"}, "agentNonce": 2} +{"name": "native-multi-refused", "at": "2026-10-12T11:45:05.025Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0xFC43b68d04A07cD67E175849E677279de8f86531", "id": "0xc56220c74ac19d10e6e06d9fc4a86686487e26f457b56cc804d638afa9ef6075", "gate": "PolicyCheckReverted(NativeAmountExceedsCap)", "state": {"configs": [{"actionId": "0x4fe8d98db364b0d0802786da5e61c881c40402aa4663465b7a61732dde03167c", "config": {"initialized": true, "validUntil": 1791809062, "target": "0x0A16CBa65FfCAa4C2282b27b027Ab4A2fE46E0Bf", "selector": "0xffffffff", "maxValuePerCall": "1", "maxValueTotal": "2", "valueSpent": "0", "amount": {"enabled": false, "offset": 0, "maxPerCall": "0", "maxTotal": "0"}, "amountSpent": "0", "maxCalls": 2, "callsUsed": 0, "pins": []}}, {"actionId": "0x0e8617603fbb66bc7458db5803c01fa022ef9f48b47628d52af31c980f10421d", "config": {"initialized": true, "validUntil": 1791809062, "target": "0x2971824Db68229D087931155C2b8bB820B275809", "selector": "0xa9059cbb", "maxValuePerCall": "0", "maxValueTotal": "0", "valueSpent": "0", "amount": {"enabled": true, "offset": 36, "maxPerCall": "3", "maxTotal": "5"}, "amountSpent": "0", "maxCalls": 4, "callsUsed": 0, "pins": [{"offset": 4, "expected": "0x0000000000000000000000000a16cba65ffcaa4c2282b27b027ab4a2fe46e0bf"}]}}], "walletPC": "10", "recipientPC": "969572352390339131997640", "walletToken": "20", "recipientToken": "434311519549551168589", "checkpointCount": "1", "grantNonce": "1"}, "agentNonce": 2} +{"name": "native-multi-refused", "at": "2026-10-12T11:45:08.918Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0xFC43b68d04A07cD67E175849E677279de8f86531", "id": "0xc56220c74ac19d10e6e06d9fc4a86686487e26f457b56cc804d638afa9ef6075", "gate": "NoPoliciesSet", "state": {"configs": [{"actionId": "0x4fe8d98db364b0d0802786da5e61c881c40402aa4663465b7a61732dde03167c", "config": {"initialized": true, "validUntil": 1791809062, "target": "0x0A16CBa65FfCAa4C2282b27b027Ab4A2fE46E0Bf", "selector": "0xffffffff", "maxValuePerCall": "1", "maxValueTotal": "2", "valueSpent": "0", "amount": {"enabled": false, "offset": 0, "maxPerCall": "0", "maxTotal": "0"}, "amountSpent": "0", "maxCalls": 2, "callsUsed": 0, "pins": []}}, {"actionId": "0x0e8617603fbb66bc7458db5803c01fa022ef9f48b47628d52af31c980f10421d", "config": {"initialized": true, "validUntil": 1791809062, "target": "0x2971824Db68229D087931155C2b8bB820B275809", "selector": "0xa9059cbb", "maxValuePerCall": "0", "maxValueTotal": "0", "valueSpent": "0", "amount": {"enabled": true, "offset": 36, "maxPerCall": "3", "maxTotal": "5"}, "amountSpent": "0", "maxCalls": 4, "callsUsed": 0, "pins": [{"offset": 4, "expected": "0x0000000000000000000000000a16cba65ffcaa4c2282b27b027ab4a2fe46e0bf"}]}}], "walletPC": "10", "recipientPC": "969572352390339131997640", "walletToken": "20", "recipientToken": "434311519549551168589", "checkpointCount": "1", "grantNonce": "1"}, "agentNonce": 2} +{"name": "native-multi-refused", "at": "2026-10-12T11:45:58.131Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0x3590679Ad8a77610Eb3D70B8b972E1e2a500817b", "id": "0xc56220c74ac19d10e6e06d9fc4a86686487e26f457b56cc804d638afa9ef6075", "gate": "PolicyCheckReverted(CallLimitReached)", "state": {"configs": [{"actionId": "0x4fe8d98db364b0d0802786da5e61c881c40402aa4663465b7a61732dde03167c", "config": {"initialized": true, "validUntil": 1791809109, "target": "0x0A16CBa65FfCAa4C2282b27b027Ab4A2fE46E0Bf", "selector": "0xffffffff", "maxValuePerCall": "1", "maxValueTotal": "2", "valueSpent": "2", "amount": {"enabled": false, "offset": 0, "maxPerCall": "0", "maxTotal": "0"}, "amountSpent": "0", "maxCalls": 2, "callsUsed": 2, "pins": []}}, {"actionId": "0x0e8617603fbb66bc7458db5803c01fa022ef9f48b47628d52af31c980f10421d", "config": {"initialized": true, "validUntil": 1791809109, "target": "0x2971824Db68229D087931155C2b8bB820B275809", "selector": "0xa9059cbb", "maxValuePerCall": "0", "maxValueTotal": "0", "valueSpent": "0", "amount": {"enabled": true, "offset": 36, "maxPerCall": "3", "maxTotal": "5"}, "amountSpent": "0", "maxCalls": 4, "callsUsed": 0, "pins": [{"offset": 4, "expected": "0x0000000000000000000000000a16cba65ffcaa4c2282b27b027ab4a2fe46e0bf"}]}}], "walletPC": "8", "recipientPC": "969572351047696631997632", "walletToken": "20", "recipientToken": "434311519549551168569", "checkpointCount": "1", "grantNonce": "1"}, "agentNonce": 4} +{"name": "native-multi-refused", "at": "2026-10-12T11:46:17.796Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0x3590679Ad8a77610Eb3D70B8b972E1e2a500817b", "id": "0xc56220c74ac19d10e6e06d9fc4a86686487e26f457b56cc804d638afa9ef6075", "gate": "PolicyCheckReverted(TotalNativeAmountExceeded)", "state": {"configs": [{"actionId": "0x4fe8d98db364b0d0802786da5e61c881c40402aa4663465b7a61732dde03167c", "config": {"initialized": true, "validUntil": 1791809109, "target": "0x0A16CBa65FfCAa4C2282b27b027Ab4A2fE46E0Bf", "selector": "0xffffffff", "maxValuePerCall": "1", "maxValueTotal": "2", "valueSpent": "2", "amount": {"enabled": false, "offset": 0, "maxPerCall": "0", "maxTotal": "0"}, "amountSpent": "0", "maxCalls": 2, "callsUsed": 2, "pins": []}}, {"actionId": "0x0e8617603fbb66bc7458db5803c01fa022ef9f48b47628d52af31c980f10421d", "config": {"initialized": true, "validUntil": 1791809109, "target": "0x2971824Db68229D087931155C2b8bB820B275809", "selector": "0xa9059cbb", "maxValuePerCall": "0", "maxValueTotal": "0", "valueSpent": "0", "amount": {"enabled": true, "offset": 36, "maxPerCall": "3", "maxTotal": "5"}, "amountSpent": "5", "maxCalls": 4, "callsUsed": 2, "pins": [{"offset": 4, "expected": "0x0000000000000000000000000a16cba65ffcaa4c2282b27b027ab4a2fe46e0bf"}]}}], "walletPC": "8", "recipientPC": "969572351047696631997632", "walletToken": "15", "recipientToken": "434311519549551168574", "checkpointCount": "1", "grantNonce": "1"}, "agentNonce": 6} +{"name": "native-multi-independent-counters", "at": "2026-10-12T11:46:18.693Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0x3590679Ad8a77610Eb3D70B8b972E1e2a500817b", "id": "0xc56220c74ac19d10e6e06d9fc4a86686487e26f457b56cc804d638afa9ef6075", "state": {"configs": [{"actionId": "0x4fe8d98db364b0d0802786da5e61c881c40402aa4663465b7a61732dde03167c", "config": {"initialized": true, "validUntil": 1791809109, "target": "0x0A16CBa65FfCAa4C2282b27b027Ab4A2fE46E0Bf", "selector": "0xffffffff", "maxValuePerCall": "1", "maxValueTotal": "2", "valueSpent": "2", "amount": {"enabled": false, "offset": 0, "maxPerCall": "0", "maxTotal": "0"}, "amountSpent": "0", "maxCalls": 2, "callsUsed": 2, "pins": []}}, {"actionId": "0x0e8617603fbb66bc7458db5803c01fa022ef9f48b47628d52af31c980f10421d", "config": {"initialized": true, "validUntil": 1791809109, "target": "0x2971824Db68229D087931155C2b8bB820B275809", "selector": "0xa9059cbb", "maxValuePerCall": "0", "maxValueTotal": "0", "valueSpent": "0", "amount": {"enabled": true, "offset": 36, "maxPerCall": "3", "maxTotal": "5"}, "amountSpent": "5", "maxCalls": 4, "callsUsed": 2, "pins": [{"offset": 4, "expected": "0x0000000000000000000000000a16cba65ffcaa4c2282b27b027ab4a2fe46e0bf"}]}}], "walletPC": "8", "recipientPC": "969572351047696631997632", "walletToken": "15", "recipientToken": "434311519549551168574", "checkpointCount": "1", "grantNonce": "1"}} +{"name": "native-multi-mixed-batch", "at": "2026-10-12T11:47:11.010Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0xbef2F2fBfd7E8316B5BC62EabE763dE94F33960d", "id": "0xc56220c74ac19d10e6e06d9fc4a86686487e26f457b56cc804d638afa9ef6075", "hash": "0x8244c8dced419a9baad66ab7888be8b63829bb299eee1c76c29b3a3b1572e877", "state": {"configs": [{"actionId": "0x4fe8d98db364b0d0802786da5e61c881c40402aa4663465b7a61732dde03167c", "config": {"initialized": true, "validUntil": 1791809178, "target": "0x0A16CBa65FfCAa4C2282b27b027Ab4A2fE46E0Bf", "selector": "0xffffffff", "maxValuePerCall": "1", "maxValueTotal": "2", "valueSpent": "1", "amount": {"enabled": false, "offset": 0, "maxPerCall": "0", "maxTotal": "0"}, "amountSpent": "0", "maxCalls": 2, "callsUsed": 1, "pins": []}}, {"actionId": "0x0e8617603fbb66bc7458db5803c01fa022ef9f48b47628d52af31c980f10421d", "config": {"initialized": true, "validUntil": 1791809178, "target": "0x2971824Db68229D087931155C2b8bB820B275809", "selector": "0xa9059cbb", "maxValuePerCall": "0", "maxValueTotal": "0", "valueSpent": "0", "amount": {"enabled": true, "offset": 36, "maxPerCall": "3", "maxTotal": "5"}, "amountSpent": "2", "maxCalls": 4, "callsUsed": 1, "pins": [{"offset": 4, "expected": "0x0000000000000000000000000a16cba65ffcaa4c2282b27b027ab4a2fe46e0bf"}]}}], "walletPC": "9", "recipientPC": "969572349705013631997623", "walletToken": "18", "recipientToken": "434311519549551168556", "checkpointCount": "1", "grantNonce": "1"}} +{"name": "native-multi-refused", "at": "2026-10-12T11:47:56.726Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0xDEB9A125CB641D26A695CA1D4443939C71f8635c", "id": "0xc56220c74ac19d10e6e06d9fc4a86686487e26f457b56cc804d638afa9ef6075", "gate": "PolicyCheckReverted(NativeAmountExceedsCap)", "state": {"configs": [{"actionId": "0x4fe8d98db364b0d0802786da5e61c881c40402aa4663465b7a61732dde03167c", "config": {"initialized": true, "validUntil": 1791809231, "target": "0x0A16CBa65FfCAa4C2282b27b027Ab4A2fE46E0Bf", "selector": "0xffffffff", "maxValuePerCall": "1", "maxValueTotal": "2", "valueSpent": "1", "amount": {"enabled": false, "offset": 0, "maxPerCall": "0", "maxTotal": "0"}, "amountSpent": "0", "maxCalls": 2, "callsUsed": 1, "pins": []}}, {"actionId": "0x0e8617603fbb66bc7458db5803c01fa022ef9f48b47628d52af31c980f10421d", "config": {"initialized": true, "validUntil": 1791809231, "target": "0x2971824Db68229D087931155C2b8bB820B275809", "selector": "0xa9059cbb", "maxValuePerCall": "0", "maxValueTotal": "0", "valueSpent": "0", "amount": {"enabled": true, "offset": 36, "maxPerCall": "3", "maxTotal": "5"}, "amountSpent": "1", "maxCalls": 4, "callsUsed": 1, "pins": [{"offset": 4, "expected": "0x0000000000000000000000000a16cba65ffcaa4c2282b27b027ab4a2fe46e0bf"}]}}], "walletPC": "9", "recipientPC": "969572348362330631997614", "walletToken": "19", "recipientToken": "434311519549551168537", "checkpointCount": "1", "grantNonce": "1"}, "agentNonce": 10} +{"name": "native-multi-mined-rollback", "at": "2026-10-12T11:48:02.313Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0xDEB9A125CB641D26A695CA1D4443939C71f8635c", "id": "0xc56220c74ac19d10e6e06d9fc4a86686487e26f457b56cc804d638afa9ef6075", "hash": "0xe592e422c9f958f80e1a5b2b6575c5f49b27e41033a5d5b3aafac4510245799a", "block": "24167667", "gasUsed": "300000", "state": {"configs": [{"actionId": "0x4fe8d98db364b0d0802786da5e61c881c40402aa4663465b7a61732dde03167c", "config": {"initialized": true, "validUntil": 1791809231, "target": "0x0A16CBa65FfCAa4C2282b27b027Ab4A2fE46E0Bf", "selector": "0xffffffff", "maxValuePerCall": "1", "maxValueTotal": "2", "valueSpent": "1", "amount": {"enabled": false, "offset": 0, "maxPerCall": "0", "maxTotal": "0"}, "amountSpent": "0", "maxCalls": 2, "callsUsed": 1, "pins": []}}, {"actionId": "0x0e8617603fbb66bc7458db5803c01fa022ef9f48b47628d52af31c980f10421d", "config": {"initialized": true, "validUntil": 1791809231, "target": "0x2971824Db68229D087931155C2b8bB820B275809", "selector": "0xa9059cbb", "maxValuePerCall": "0", "maxValueTotal": "0", "valueSpent": "0", "amount": {"enabled": true, "offset": 36, "maxPerCall": "3", "maxTotal": "5"}, "amountSpent": "1", "maxCalls": 4, "callsUsed": 1, "pins": [{"offset": 4, "expected": "0x0000000000000000000000000a16cba65ffcaa4c2282b27b027ab4a2fe46e0bf"}]}}], "walletPC": "9", "recipientPC": "969572348362330631997614", "walletToken": "19", "recipientToken": "434311519549551168537", "checkpointCount": "1", "grantNonce": "1"}} +{"name": "native-multi-replacement", "at": "2026-10-12T11:49:13.204Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0xBbCF2b4fB9b49237129175293Ec96Cc3008437a1", "oldId": "0xc56220c74ac19d10e6e06d9fc4a86686487e26f457b56cc804d638afa9ef6075", "newId": "0x8744081a45faa6a01722dff73da0d93bc796614f2cd3c3f795d7ffea10beb33d", "trimmedId": "0x8cbdc3d9165f9a9bd37f0b81ff4ef7f04ab523e808717c14cda312b151e1b80a", "hashes": ["0x7c1443310972b9e3501351ac63c343045ac77c601c65104a53d10a1542ca2381", "0xac7a139322ba8b7e981ffcab11551667463311014be4a3541067309cdb2209cd", "0x908065e4a835ade2f4195cc37092e5f94d7ee0bdb8523a3f70d2575e049dfebe"]} +{"name": "native-multi-second-action-race", "at": "2026-10-12T11:50:08.320Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0x1E5616320596A9b0F0326eAeA2E061dccB34c7B4", "oldId": "0xc56220c74ac19d10e6e06d9fc4a86686487e26f457b56cc804d638afa9ef6075", "newId": "0x8744081a45faa6a01722dff73da0d93bc796614f2cd3c3f795d7ffea10beb33d", "spendHash": "0x6e0bfd3b2b481cf39dfc8ef8bc3b9d82250accfdfff6f0d2297b95a628a39247", "retryHash": "0x8f399fb1485bde5ce938ba8ff12858ecee9e1610c033930939fd079a1f94ccec", "stateAfterRace": {"configs": [{"actionId": "0x4fe8d98db364b0d0802786da5e61c881c40402aa4663465b7a61732dde03167c", "config": {"initialized": true, "validUntil": 1791809353, "target": "0x0A16CBa65FfCAa4C2282b27b027Ab4A2fE46E0Bf", "selector": "0xffffffff", "maxValuePerCall": "1", "maxValueTotal": "2", "valueSpent": "0", "amount": {"enabled": false, "offset": 0, "maxPerCall": "0", "maxTotal": "0"}, "amountSpent": "0", "maxCalls": 2, "callsUsed": 0, "pins": []}}, {"actionId": "0x0e8617603fbb66bc7458db5803c01fa022ef9f48b47628d52af31c980f10421d", "config": {"initialized": true, "validUntil": 1791809353, "target": "0x2971824Db68229D087931155C2b8bB820B275809", "selector": "0xa9059cbb", "maxValuePerCall": "0", "maxValueTotal": "0", "valueSpent": "0", "amount": {"enabled": true, "offset": 36, "maxPerCall": "3", "maxTotal": "5"}, "amountSpent": "1", "maxCalls": 4, "callsUsed": 1, "pins": [{"offset": 4, "expected": "0x0000000000000000000000000a16cba65ffcaa4c2282b27b027ab4a2fe46e0bf"}]}}], "walletPC": "10", "recipientPC": "969572343854891006997595", "walletToken": "19", "recipientToken": "434311519549551168501", "checkpointCount": "1", "grantNonce": "1"}} +{"name": "native-multi-eight-boundary", "at": "2026-10-12T11:50:31.951Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0x2AaEd40d93A6B00f6Cf6523F07199AFA5caF4061", "id": "0xc56220c74ac19d10e6e06d9fc4a86686487e26f457b56cc804d638afa9ef6075", "hash": "0x18b052a9dcff2091a7ba315afd9264ea6f80d93a147c05c2d30ffc47986dab5e", "unchangedNextSlot": 40} +{"name": "native-multi-refused", "at": "2026-10-12T11:52:12.019Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0xA79688f8fb433E60DEF8492372528Ae06E68B158", "id": "0xc56220c74ac19d10e6e06d9fc4a86686487e26f457b56cc804d638afa9ef6075", "gate": "PolicyCheckReverted(RulesExpired)", "state": {"configs": [{"actionId": "0x4fe8d98db364b0d0802786da5e61c881c40402aa4663465b7a61732dde03167c", "config": {"initialized": true, "validUntil": 1791805921, "target": "0x0A16CBa65FfCAa4C2282b27b027Ab4A2fE46E0Bf", "selector": "0xffffffff", "maxValuePerCall": "1", "maxValueTotal": "2", "valueSpent": "1", "amount": {"enabled": false, "offset": 0, "maxPerCall": "0", "maxTotal": "0"}, "amountSpent": "0", "maxCalls": 2, "callsUsed": 1, "pins": []}}, {"actionId": "0x0e8617603fbb66bc7458db5803c01fa022ef9f48b47628d52af31c980f10421d", "config": {"initialized": true, "validUntil": 1791809521, "target": "0x2971824Db68229D087931155C2b8bB820B275809", "selector": "0xa9059cbb", "maxValuePerCall": "0", "maxValueTotal": "0", "valueSpent": "0", "amount": {"enabled": true, "offset": 36, "maxPerCall": "3", "maxTotal": "5"}, "amountSpent": "0", "maxCalls": 4, "callsUsed": 0, "pins": [{"offset": 4, "expected": "0x0000000000000000000000000a16cba65ffcaa4c2282b27b027ab4a2fe46e0bf"}]}}], "walletPC": "9", "recipientPC": "969572338780101506997586", "walletToken": "20", "recipientToken": "434311519549551168481", "checkpointCount": "1", "grantNonce": "1"}, "agentNonce": 16} +{"name": "native-multi-action-expiry", "at": "2026-10-12T11:52:19.053Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "wallet": "0xA79688f8fb433E60DEF8492372528Ae06E68B158", "id": "0xc56220c74ac19d10e6e06d9fc4a86686487e26f457b56cc804d638afa9ef6075", "expiry": 1791805921, "laterExpiry": 1791809521, "hash": "0xc96da84063a0e25c4960bf9e8044c4d9c2c6c8c67e7832551ca70fd7c02ae5ee", "state": {"configs": [{"actionId": "0x4fe8d98db364b0d0802786da5e61c881c40402aa4663465b7a61732dde03167c", "config": {"initialized": true, "validUntil": 1791805921, "target": "0x0A16CBa65FfCAa4C2282b27b027Ab4A2fE46E0Bf", "selector": "0xffffffff", "maxValuePerCall": "1", "maxValueTotal": "2", "valueSpent": "1", "amount": {"enabled": false, "offset": 0, "maxPerCall": "0", "maxTotal": "0"}, "amountSpent": "0", "maxCalls": 2, "callsUsed": 1, "pins": []}}, {"actionId": "0x0e8617603fbb66bc7458db5803c01fa022ef9f48b47628d52af31c980f10421d", "config": {"initialized": true, "validUntil": 1791809521, "target": "0x2971824Db68229D087931155C2b8bB820B275809", "selector": "0xa9059cbb", "maxValuePerCall": "0", "maxValueTotal": "0", "valueSpent": "0", "amount": {"enabled": true, "offset": 36, "maxPerCall": "3", "maxTotal": "5"}, "amountSpent": "1", "maxCalls": 4, "callsUsed": 1, "pins": [{"offset": 4, "expected": "0x0000000000000000000000000a16cba65ffcaa4c2282b27b027ab4a2fe46e0bf"}]}}], "walletPC": "9", "recipientPC": "969572338780101506997586", "walletToken": "19", "recipientToken": "434311519549551168482", "checkpointCount": "1", "grantNonce": "1"}} +{"name": "native-multi-invalid-input", "at": "2026-10-12T11:52:27.491Z", "network": "TESTNET_DONUT", "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", "unchangedNextSlot": 41, "ownerNonce": 712} diff --git a/plan/agw/research/native-multi-action-e2e-2026-10-12/validation.json b/plan/agw/research/native-multi-action-e2e-2026-10-12/validation.json new file mode 100644 index 00000000..584c7b9c --- /dev/null +++ b/plan/agw/research/native-multi-action-e2e-2026-10-12/validation.json @@ -0,0 +1,26 @@ +{ + "date": "2026-10-12", + "branch": "feat/agw-sdk-v4", + "base_head": "7115c59474af6304905ad3e4466732b0530dc791", + "source": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", + "unit": { + "passed": 2034, + "skipped": 12, + "failed": 0 + }, + "actual_contracts": { + "passed": 97, + "failed": 0 + }, + "live": { + "passed": 10, + "failed": 0, + "single_invocation": true + }, + "agw_scenarios": 68, + "default_scenarios": 76, + "committed": false, + "pushed": false, + "evidence_rows": 16, + "test_sha256": "7e04e470bf8642eab41fabe943f387ae0d592f1139328c713289bdac39eb420f" +} diff --git a/plan/agw/research/section6-feedback-2026-10-12/contracts-export.zip b/plan/agw/research/section6-feedback-2026-10-12/contracts-export.zip new file mode 100644 index 0000000000000000000000000000000000000000..e2769d05e535f58dc6d241b86a8dc637b24f1215 GIT binary patch literal 14990 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 literal 0 HcmV?d00001 diff --git a/plan/agw/research/section6-feedback-2026-10-12/contracts-latest.md b/plan/agw/research/section6-feedback-2026-10-12/contracts-latest.md new file mode 100644 index 00000000..0db4e6a6 --- /dev/null +++ b/plan/agw/research/section6-feedback-2026-10-12/contracts-latest.md @@ -0,0 +1,502 @@ +# 1. AGW Contract Changes (nomenclature standard + change set) + + + +# 0. Before the naming: AGW will break when the gateway is upgraded + +**What happened.** The gateway team changed the outbound request struct on GitHub main. Two fields are gone (`gasPrice`, `maxPCForGas`). AGW copied the old struct into its own repo and URP checks one of the removed fields (gate 9: `maxPCForGas` must be non-zero). + +**Why it still works today.** Donut is still running the old gateway (implementation `0x1e41...a659` has the old eight fields). + +**What breaks.** The day the new gateway is deployed on Donut, every cross-chain rule set stops working: URP rejects every request. + +**Fix, two rules.** + +1. AGW never copies a gateway or core struct. It imports them from the gateway and core packages, so a change upstream fails the build instead of failing on-chain. +2. The URP upgrade and the gateway upgrade go out together, not separately. + +Same rule for the selector: derive `sendUniversalTxOutbound.selector` from the interface, do not hardcode `0x77b86bec`. + +# 1. How core and gateway name things (the standard AGW follows) + +These conventions already exist in `push-chain-core-contracts` and `push-chain-gateway-contracts`. AGW adopts them as is. Where the two repos disagree, the AGW column says which one wins. + +| Area | Convention | Example | AGW | +| --- | --- | --- | --- | +| Contract names | Chain-agnostic components spell out Universal. Push-side variants add PC. Accounts are 3-letter acronyms. | `UniversalCore`, `UniversalGatewayPC`, `UEA`, `CEAFactory` | `AGW`, `AGWFactory`, `UniversalRulesPolicy` | +| Errors | One `libraries/Errors.sol` per repo, one error library per contract, PascalCase, arguments only when the caller needs them. Caller checks are `CallerIsNotX`. | `UEAErrors.InvalidCall()`, `CommonErrors.ZeroAddress()`, `CallerIsNotUEModule()` | `AGWErrors`, `AGWFactoryErrors`, `UniversalRulesPolicyErrors` | +| Types and constants | One `libraries/Types.sol`, plain file-level structs, `UPPER_SNAKE` constants, selectors derived not hardcoded. | `struct Multicall`, `MULTICALL_SELECTOR = bytes4(keccak256("UEA_MULTICALL"))` | `libraries/Types.sol`; gateway and core structs imported, never copied | +| Request shape | One `XRequest` struct as the single argument; the contract infers the kind. Users never state a type. | `sendUniversalTxOutbound(UniversalOutboundTxRequest req)` infers `TX_TYPE` | `grantRules(Session)` infers `NATIVE` vs `UNIVERSAL` from `chainNamespace` | +| Interface sections | Tag plus number banners, events first, NatSpec on everything. | `UGPC_1: EVENTS`, `UGPC_2: OUTBOUND TX`, `UGPC_3: VIEW FUNCTIONS` | `AGW_1: EVENTS` ... `AGW_5: VIEWS`, `URP_1` ... `URP_3` | +| Functions | `setX`, `getX`, `isX`. Set-once wiring is read through `UPPER_CASE()` getters. | `isSupportedToken()`, `UNIVERSAL_CORE()` | `SESSION_ENGINE()`, `RULES_POLICY()`, `UNIVERSAL_GATEWAY_PC()` | +| Storage | Internal state is underscore-prefixed. | `_walletCount` | `_` everywhere; drop URP's `$` prefix | +| Roles | `UPPER_SNAKE_ROLE`. | `DEFAULT_ADMIN_ROLE`, `PAUSER_ROLE`, `TSS_ROLE` | same; `PAUSER` and `OPERATOR` split kept, documented | +| Chain identity | Full CAIP-2 string, field named `chainNamespace`. | `"eip155:1"` | envelope field renamed `chain` to `chainNamespace` | +| Events | No consistent rule upstream. | `SetChainMeta` (imperative), `VaultPCUpdated` (past) | past tense: `RulesGranted`, `WalletDeployed` | +| Layout | `src/` with `interfaces/` and `libraries/`; numbered docs and tests; addresses per network; `CLAUDE.md` in every package. | `docs/1_PUSH_CHAIN.md`, `test/gateway/1_adminActions.t.sol`, `docs/addresses/sepolia.md` | same, see rename map | + +#### Where each convention was seen (open only if you want the receipts) + +Core repo, folder layout: + +``` +src/ + Interfaces/ IUniversalCore.sol, IUEA.sol, ICEA.sol + libraries/ Errors.sol, Types.sol, Utils.sol + uea/ UEAFactory.sol, UEA_EVM.sol, UEA_SVM.sol + cea/ CEAFactory.sol, CEA.sol + UniversalCore.sol, PRC20.sol, WPC.sol +``` + +Gateway repo, folder layout: + +``` +contracts/evm-gateway/ + src/ UniversalGateway.sol, UniversalGatewayPC.sol, Vault.sol, VaultPC.sol + src/interfaces/ IUniversalGatewayPC.sol, IVault.sol + src/libraries/ Errors.sol, Types.sol, TypesUG.sol, TypesUGPC.sol + docs/ 1_PUSH_CHAIN.md, 2_UniversalGateway.md, 3_UniversalGatewayPC.md + docs/addresses/ sepolia.md, bsc-testnet.md + test/gateway/ 1_adminActions.t.sol ... 14_gatewayPC.t.sol + script/ 1_DeployGatewayWithProxy.sol, 3_UpgradeGatewayNewImpl.sol + CLAUDE.md +``` + +Errors (core, `libraries/Errors.sol`): + +```solidity +library CommonErrors { error ZeroAddress(); error Unauthorized(); error InvalidInput(); } +library UniversalCoreErrors { error CallerIsNotUEModule(); error GasLimitBelowBase(uint256 provided, uint256 minimum); } +library UEAErrors { error InvalidCall(); error ExecutionFailed(); } +``` + +Types (core, `libraries/Types.sol`): + +```solidity +struct UniversalAccountId { string chainNamespace; string chainId; bytes owner; } +struct Multicall { address to; uint256 value; bytes data; } +bytes4 constant MULTICALL_SELECTOR = bytes4(keccak256("UEA_MULTICALL")); +``` + +Request shape (gateway, `TypesUGPC.sol` and `IUniversalGatewayPC.sol`): + +```solidity +struct UniversalOutboundTxRequest { bytes recipient; address token; uint256 amount; uint256 gasLimit; bytes payload; address revertRecipient; } +function sendUniversalTxOutbound(UniversalOutboundTxRequest calldata req) external payable; // TX_TYPE inferred inside +``` + +Interface sections and wiring getters (gateway, `IUniversalGatewayPC.sol`): + +```solidity +// UGPC_1: EVENTS +// UGPC_2: OUTBOUND TX +// UGPC_3: VIEW FUNCTIONS +function UNIVERSAL_CORE() external view returns (address); +``` + +Events (both repos, no single rule): + +```solidity +event SetChainMeta(...); // core, imperative +event PauserRoleGranted(...); // core, past tense +event UniversalTxOutbound(...); // gateway, noun +event VaultPCUpdated(...); // gateway, past tense +``` + +Chain identity, the same field name with two meanings: + +```solidity +gasPriceByChainNamespace("eip155:1") // UniversalCore: full CAIP-2 string +UniversalAccountId({ chainNamespace: "eip155", chainId: "1" }) // Read State: split +``` + +# 2. Decisions + +| # | Decision | Outcome | +| --- | --- | --- | +| D1 | Wallet contract name | **AGW.sol** (account acronym like UEA, CEA). Full form "Agentic Wallet" in the NatSpec title only. Factory stays `AGWFactory.sol`. | +| D2 | Policy contract name | **UniversalRulesPolicy.sol**. `URP` stays as the short form in comments, events and the SDK constant, the way `UGPC` stands for `UniversalGatewayPC`. | +| D3 | Validator contract name | PROPOSED 2026-09-29: **no validator.** The agent is a Push address: a native key is its own EOA, any external key (EVM, Solana, anything) is its UEA, deterministic from (chain, owner). Cross-VM signature verification already happens inside the UEA, so the agent door checks `msg.sender == rules.agent` and hands the calls to URP. `PushSessionValidator.sol` is removed rather than renamed. Pending one check against the v3 branch: how deep SmartSession's signature path is wired into the engine calls URP relies on, and whether the policy engine can be driven from a sender check without forking it. | +| D4 | Vocabulary for the granted object | **rules, one word everywhere.** On-chain: `grantRules`, `revokeRules`, `revokeAllRules`, `rulesId`, `RulesGranted`, `RulesRevoked`, `RulesActionAuthorized`. Layer: Universal Rules. SDK: `client.agentic.rules`. `permissionId` remains the SmartSession-internal name and is exposed as `rulesId`. `mandate` is retired from code, docs and copy. +**Rename boundary (2026-09-29).** Three vocabularies live in the fork; only ours is renamed. ERC-7579 names stay (`execute(mode, executionCalldata)`, `ModeCode`, module types, `installModule`). SmartSession names stay inside the engine and on the interfaces URP implements (`Session`, `permissionId`, `PolicyData`, `ActionData`, `ConfigId`, `enableSessions`, `isPermissionEnabled`, `IPolicy.checkAction`, `initializeWithMultiplexer`): audit history and upstream diffs attach to those names. Push's own words (`mandate`, `PushAgentWallet`, our events, envelope, docs, SDK) become rules. The seam is the AGW ABI: `rulesId` is computed by the engine's `getPermissionId(Session)` and the NatSpec states `rulesId == permissionId`. If the engine is vendored with edits, it lives in `src/vendor/smartsession/` with a note naming the upstream commit and every local change. If D3 ends with the engine dropped, SmartSession vocabulary leaves with it. | +| D5 | Door functions | Keep `execute` (owner door). Agent door becomes `executeAsAgent(bytes32 rulesId, bytes32 mode, bytes executionCalldata)`, gated on `msg.sender == rules.agent`, replacing `executeWithSession` and its signature blob (follows D3). "Owner door" and "agent door" stay as NatSpec language. | +| D6 | Chain field in the envelope | Rename `chain` to `chainNamespace`, full CAIP-2 string, matching `UniversalCore` and gateway events. Read State keeps its split fields; the SDK converts. | +| D7 | Mode names | `NATIVE` and `UNIVERSAL` stay. The SVM rulebook is selected by the `solana` namespace inside `UNIVERSAL`; no new mode name. | + +# 3. Rename map (current to proposed) + +| Area | Today | Proposed | +| --- | --- | --- | +| Inherited names (7579, SmartSession) | `execute(mode, executionCalldata)`, `Session`, `permissionId`, `PolicyData`, `ActionData`, `ConfigId`, `checkAction`, `initializeWithMultiplexer` | unchanged (see D4 rename boundary) | +| Wallet | `PushAgentWallet.sol` | `AGW.sol` | +| Factory | `AGWFactory.sol` | `AGWFactory.sol` (unchanged) | +| Policy | `policies/URP.sol` | `UniversalRulesPolicy.sol` | +| Validator | `validators/PushSessionValidator.sol` | removed (D3): agent identity is a Push address, verification lives in the UEA | +| Interfaces | `IPushAgentWallet`, `IURP`, `IPushSessionValidator`, local `IUniversalGatewayPC`, `IPRC20Source` | `IAGW`, `IUniversalRulesPolicy`; gateway and core interfaces imported (`IUEAFactory` for `computeUEA` in tests and tooling) | +| Errors | `libraries/PushWalletErrors.sol` plus errors declared in `IURP` and `IAGWFactory` | `libraries/Errors.sol` with `AGWErrors`, `AGWFactoryErrors`, `UniversalRulesPolicyErrors`; reuse `CommonErrors` names (`ZeroAddress`, `Unauthorized`, `AlreadyInitialized`); `AGWErrors.CallerIsNotAgent()` | +| Types | `libraries/PushWalletTypes.sol` re-declares `UniversalOutboundTxRequest`, `Multicall` | `libraries/Types.sol` with AGW-owned structs only (`RulesEnvelope`, `NativeTerms`, `UniversalTerms`, `AllowedCall`, `ArgPin`, `AmountRule`); gateway and core types imported | +| Grant / revoke | `grantMandate`, `stopMandate`, `stopAll` | `grantRules`, `revokeRules`, `revokeAllRules` | +| Events | `MandateGranted`, `MandateRevoked`, `MandateActionAuthorized`, `URPPolicySet` | `RulesGranted`, `RulesRevoked`, `RulesActionAuthorized`, `RulesConfigured` | +| Ids | `permissionId` in wallet ABI | `rulesId` in wallet ABI (engine keeps `permissionId` internally) | +| Wiring getters | `sessionEngine()`, `urp()`, `sessionValidator()`, `universalGateway()` | `SESSION_ENGINE()`, `RULES_POLICY()`, `UNIVERSAL_GATEWAY_PC()` (no validator getter, D3) | +| Storage prefix | `_` in wallet and factory, `$` in URP | `_` everywhere | +| Envelope | `abi.encode(string chain, bytes body)` | `abi.encode(uint16 version, string chainNamespace, bytes body)` | +| Interface banners | none | `AGW_1: EVENTS`, `AGW_2: OWNER DOOR`, `AGW_3: AGENT DOOR`, `AGW_4: RULES LIFECYCLE`, `AGW_5: VIEWS`; `URP_1: EVENTS`, `URP_2: POLICY`, `URP_3: VIEWS`; `AGWF_1: EVENTS`, `AGWF_2: DEPLOY`, `AGWF_3: VIEWS` | +| Selector constant | `SEND_OUTBOUND_SELECTOR = 0x77b86bec` | derived from `IUniversalGatewayPC` | +| Roles | `PAUSER_ROLE` pauses, `OPERATOR_ROLE` unpauses | keep the split, document it as a deliberate deviation from gateway | +| Event tense | past tense | past tense, written down as the rule | +| Docs | `docs/v3-architecture.md`, `agentic_wallet_flow.md`, `push_native_agentic_wallet_flow.md` | `docs/1_AGW.md`, `2_UniversalRulesPolicy.md`, `3_Universal_Flow.md`, `4_Native_Flow.md` | +| Addresses | `deployments/address-book-v3/ADDRESSES.md` | `docs/addresses/donut.md` | +| Tests | `test/unit/*.t.sol`, `test/integration/*.t.sol` | numbered by area: `1_factory`, `2_ownerDoor`, `3_rulesLifecycle`, `4_agentDoor`, `5_universalRulebook`, `6_nativeRulebook`, `7_externalAgentViaUEA`, `8_e2e` | + +# 4. Structural changes that ride along with the rename + +Agreed on 2026-09-28. Listed here so the rename and the additions land in one change set and one audit, before the permanent deployment. + +1. **Signature-authorized variants**: `deployWalletWithSig`, `grantRulesWithSig`, `executeWithSig`. One EIP-712 domain per contract. Digest includes chainid, contract, nonce (the wallet's grant nonce for grants; a per-owner nonce on the factory), deadline. Verify ECDSA, and ERC-1271 when the owner has code (a UEA). +2. **Checkpoints**: the wallet records owner-side changes an evaluator needs: principal moved out (owner-door value or token transfer out, and every outbound), rules granted, revoked or replaced, key changed. Per-wallet monotonic counter plus `Checkpointed(kind, ref, blockNumber)`, so an evaluator can ask "any checkpoint after block N" with one read. +3. **`bytes32 ref` on `grantRules`**, emitted in `RulesGranted`, so a job binds to a rules id and an indexer goes rules to job without the hook. +4. **Stop-only role: dropped for v1** (2026-10-01). A binder address that could call `revokeRules` and nothing else was considered so a job hook could end rules at job end. Not needed: rules expire by `validUntil`, which the fund hook requires to be at or after the job's `expiredAt`, caps bound the gap, and the hook keeps its own one-live-job slot. Additive to bring back later. +5. **Envelope version word**: `abi.encode(uint16 version, string chainNamespace, bytes body)`. +6. **`creditRevert` reachability**: wire the real executor module or replace the credit path. Today spend never decreases on Donut. +7. **SVM rulebook** in the policy, keyed by the `solana` namespace: 32-byte `expectedCEA` and targets, program plus instruction discriminator allow-list, beneficiary check over the accounts array, SVM payload gate. +8. **Import gateway and core types**, derive the outbound selector, sequence the URP upgrade with the gateway's struct change. +9. **Agent identity is a Push address** (2026-09-29). The rules name an address: an EOA, or the UEA of an external key. The agent door checks the sender instead of verifying a session signature; the validator contract goes. One identity for rules, card and 8183 provider, so the fund hook matches by equality. Sizing against the v3 branch pending (D3). +10. **Editable label** (2026-10-01). `setLabel(string label)` on AGW, owner only, emits `LabelSet(string label)`. Today the label is only passed at `deployWallet` and emitted in `WalletDeployed`. Not a checkpoint kind: cosmetic metadata, evaluators ignore it. SDK: `w.setLabel(label)` on page 5. + +# 4b. Contract surface, as a diff + +Read `+` as added, `-` as removed, `~` as changed in place, `=` as unchanged. Names are the post-rename names. Storage slots never move; renames are labels only. + +**AGWFactory** + +```diff += deployWallet(string label) returns (address wallet) // caller is the owner ++ deployWalletWithSig(address owner, uint96 index, string label, ++ uint48 deadline, bytes ownerSig) returns (address) // EIP-712; index must equal walletCount(owner) ++ // ownerSig: ECDSA, or ERC-1271 when owner has code (UEA) ++ DOMAIN_SEPARATOR() view returns (bytes32) += predictWallet(address owner, uint256 index) view returns (address, bool deployed) += walletCount / ownerOf / isWallet / indexOf / walletImplementation += pause() PAUSER_ROLE, unpause() OPERATOR_ROLE += event WalletDeployed(owner, index, wallet, label) +``` + +**AGW** (was PushAgentWallet) + +```diff +// owner door += execute(bytes32 mode, bytes executionCalldata) payable // owner only, no policy +~ execute now emits Checkpointed(seq, OWNER_ACTION, keccak(calldata), block) ++ executeWithSig(bytes32 mode, bytes executionCalldata, ++ uint64 ownerNonce, uint48 deadline, bytes ownerSig) // owner door by signature, same effects as execute ++ ownerNonce() view returns (uint64) ++ setLabel(string label) // owner only; emits LabelSet; not a checkpoint + +// rules lifecycle +- grantMandate(Session) returns (bytes32 permissionId) ++ grantRules(Session session, bytes32 ref) returns (bytes32 rulesId) // ref: job or card reference, emitted, not interpreted ++ grantRulesWithSig(Session session, bytes32 ref, uint48 deadline, bytes ownerSig) returns (bytes32 rulesId) ++ // digest includes grantNonce, so a signed grant cannot replay +- stopMandate(bytes32 permissionId) ++ revokeRules(bytes32 rulesId) // owner or self +- stopAll() ++ revokeAllRules() // owner or self + +// agent door (D3, D5) +- executeWithSession(address validator, bytes32 mode, bytes executionCalldata, +- bytes signature, uint192 nonceKey, uint64 nonceSeq, uint48 requestExpiry) ++ executeAsAgent(bytes32 rulesId, bytes32 mode, bytes executionCalldata) ++ requires msg.sender == agentOf(rulesId); replay and expiry come from the sender's own tx (EOA nonce, or the UEA's) ++ URP checks every call exactly as before; no signature blob, no validator address ++ agentOf(bytes32 rulesId) view returns (address) + +// checkpoints ++ checkpointCount() view returns (uint64) ++ lastCheckpointBlock() view returns (uint64) ++ event Checkpointed(uint64 indexed seq, uint8 kind, bytes32 ref, uint64 blockNumber) ++ kind: 0 OWNER_ACTION (any owner-door execute), 1 RULES_GRANTED, 2 RULES_REVOKED ++ emitted from execute, executeWithSig, grantRules*, revokeRules, revokeAllRules + +// views (wiring, renamed to UPPER_CASE) +- sessionEngine() urp() sessionValidator() universalGateway() ++ SESSION_ENGINE() RULES_POLICY() UNIVERSAL_GATEWAY_PC() += owner() factory() grantNonce() getNonce(uint192) accountId() ++ DOMAIN_SEPARATOR() view returns (bytes32) + +// events +- MandateGranted(permissionId, mandateType, chainHash, chain) ++ RulesGranted(bytes32 indexed rulesId, uint8 mode, bytes32 indexed chainHash, string chainNamespace, bytes32 ref) +- MandateRevoked(permissionId) ++ RulesRevoked(bytes32 indexed rulesId, address by) +- MandateActionAuthorized(permissionId, nonceKey, nonceSeq, opHash) ++ RulesActionAuthorized(bytes32 indexed rulesId, address indexed agent, bytes32 callsHash) ++ event LabelSet(string label) +``` + +**UniversalRulesPolicy** (was URP) + +```diff +~ initializeWithMultiplexer(address account, ConfigId id, bytes initData) +~ initData = abi.encode(uint16 version, string chainNamespace, bytes body) // was (string chain, bytes body) +~ rulebook chosen by namespace: this chain => native; eip155:* => universal EVM; solana:* => universal SVM ++ SVM rulebook ++ struct SvmTerms { uint48 validUntil; bytes32 expectedCEA; address asset; uint256 maxAmountPerCall; ++ uint256 maxAmountTotal; uint256 maxPCPerCall; SvmAllowedCall[] allowedCalls; } ++ struct SvmAllowedCall { bytes32 program; bytes8 discriminator; uint8 beneficiaryAccountIndex; bool hasBeneficiary; uint64 maxLamports; } ++ gates mirror the EVM list; beneficiary checked in the accounts array, payload gate for the SVM outbound format +~ checkAction: UniversalOutboundTxRequest imported from the gateway package +~ gate 4c MIN_OUTBOUND_BODY_LEN recomputed from the imported struct +~ gate 9 (maxPCForGas != 0) removed when the six-field gateway struct lands; deploy in the same window +~ creditRevert(id, account, outboundTxId, amount): caller is the real executor module, set at initialize += or removed if the credit path is replaced (decision pending) += assertSpent (both overloads), getConfig, getNativeConfig, getMode, pushChainHash, isCredited ++ getSvmConfig(ConfigId, address) view +- event URPPolicySet(...) ++ event RulesConfigured(bytes32 indexed configId, address indexed multiplexer, address indexed account, uint8 mode, bytes32 chainHash) += OutboundMetered, NativeCallMetered, RevertCredited +~ storage variables renamed $configs, $credited, $mode, $native to _configs, _credited, _mode, _native (labels only, slots unchanged) ++ _svm mapping appended after _native; __gap shrinks by one +~ version() returns "2.0.0" +``` + +**PushSessionValidator** + +```diff +- validateConfig(bytes keyConfig) +- validateSignatureWithData(bytes32 hash, bytes sig, bytes keyConfig) +- contract removed (D3). Session.sessionValidator and keyConfig are replaced by a single address in the rules: the agent. +``` + +**Not in this change set** (belongs to 8183, listed so nobody looks for it here): the fund hook's key-match and expiry checks, the marketplace, the evaluator. + +# 4c. What the SDK rule shape changes in the contracts (PROPOSED 2026-10-02) + +Page 5 (SDK: AGW) settled the shape of a cross-chain rule in `client.agentic.create`. Three of those SDK changes touch the contracts. Nothing else on page 5 does. Names are the post-rename names from section 3; struct changes are to the universal terms URP decodes from the rules envelope. + +**1. One rule can move several tokens: `assets: AssetCap[]` replaces `asset`, `maxAmountPerCall`, `maxAmountTotal`.** + +The SDK takes each asset as the token's address on the rule's chain (`MOVEABLE.TOKEN..` or the native marker) and resolves it to the PRC20 on Push before encoding, so the contract keeps storing PRC20 addresses. The spend counter becomes per asset. + +```diff +// universal EVM terms (and SvmTerms, same change) +- address asset; uint256 maxAmountPerCall; uint256 maxAmountTotal; ++ AssetCap[] assets; // 0..MAX_ASSETS; empty = call contracts, move nothing ++ struct AssetCap { address token; uint256 maxPerCall; uint256 maxTotal; } // token: PRC20 on Push; maxTotal 0 = no total cap ++ uint8 constant MAX_ASSETS = 8; + +// metering +~ amount gate: the token being moved must be one of assets[]; per-call and running total checked against that entry +~ _spent[configId] becomes per token: mapping(address token => uint256 spent) +~ assertSpent(configId, account) returns the per-token totals; the existing single-amount overload goes +~ OutboundMetered carries the token +``` + +**2. `maxGasPerCall` replaces `maxPCPerCall`.** + +Rename only. Same meaning: the PC (wei) the wallet may pass as `msg.value` on one outbound for the destination leg. The gate that checks it does not change. + +```diff +- uint256 maxPCPerCall; ++ uint256 maxGasPerCall; +``` + +**3. The struct, as it ends up.** + +SDK side, what `create` takes per rule (page 5, 3.b). `agent` and `ref` go to `grantRules`, the rest is encoded into the rules envelope. + +```tsx +interface UniversalRule { + agent: Address; // Push address: EOA, or the UEA of an external key + ref?: Hex; // emitted in RulesGranted, not interpreted + chainNamespace: ForeignChainNamespace; + assets: AssetCap[]; // tokens the agent may move on chainNamespace; 0..8 + maxGasPerCall: bigint; // PC (wei) per outbound for the destination leg + validUntil: number; + allowedCalls: AllowedCall[]; +} + +interface AssetCap { + token: MoveableToken | Address; // the other chain's token address (MOVEABLE.TOKEN..) or the native marker + maxPerCall: bigint; + maxTotal?: bigint; +} +``` + +Contract side, what URP decodes from the envelope body for an `eip155` namespace (`SvmTerms` takes the same `assets` and `maxGasPerCall` fields). + +```solidity +struct AssetCap { + address token; // PRC20 on Push, resolved by the SDK from the other chain's address + uint256 maxPerCall; + uint256 maxTotal; // 0 = no running cap +} + +struct UniversalTerms { + uint48 validUntil; + bytes32 expectedCEA; + AssetCap[] assets; // 0..MAX_ASSETS; empty = call contracts, move nothing + uint256 maxGasPerCall; // PC (wei) per outbound + AllowedCall[] allowedCalls; // unchanged +} + +uint8 constant MAX_ASSETS = 8; +``` + +# 5. Open for review on this page + +1. D3: removing the validator. Needs the v3 branch check on how SmartSession's engine is entered (signature path vs a sender-gated call into the same policy checks). If the engine cannot be entered without a signature, the fallback is a validator that accepts a trivial signature from the sender, which keeps the identity model and loses nothing but elegance. +2. Checkpoint kinds, since they are the evaluator's contract with the wallet. +3. `creditRevert`: wire the executor module, or replace the credit path. +4. Anything in the rename map or the diff that should stay as is. + +The SDK surface lives on page 5 (SDK: AGW). + +# 6. Changes proposed on 12 Oct 2026 + +These come from the review of the first SDK implementation, [push-chain-sdk PR #291](https://github.com/pushchain/push-chain-sdk/pull/291), which runs against the v5 contracts on Donut. Sections 0 to 5 above are left exactly as they were. Where an entry here differs from them, the entry here is the current one. The SDK side of each change is on [5. SDK: AGW](https://app.notion.com/p/5-SDK-AGW-3e9188aea7f481cf8e8de324956549b9?pvs=21) (page 5), section 6. + +Struct and field names below are shown by meaning. Where the v5 source names a field differently, the source name wins. + +| # | Change | Contract | Replaces above | SDK side (page 5) | +| --- | --- | --- | --- | --- | +| 6.1 | The wallet approves the gateway itself, for the exact amount, inside each outbound | AGW | new | 6.g | +| 6.2 | One factory call deploys the wallet and grants its rules | AGWFactory, AGW | new (page 5 called this "item 11") | 6.b | +| 6.3 | Pins on EVM destination calls | UniversalRulesPolicy | new | 6.a | +| 6.4 | `ref` removed from `grantRules` | AGW | section 4 item 3, and the `ref` lines in 4b and 4c | 6.b, 6.c, 6.d | +| 6.5 | A cap of 0 means nothing moves | UniversalRulesPolicy | "0 = no total cap" in 4c | 6.b | + +### 6.1 The wallet approves the gateway itself, for the exact amount, inside each outbound + +**What happens today.** When the wallet sends a token to another chain, `UniversalGatewayPC` takes the token out of the wallet. That needs an ERC20 approval from the wallet to the gateway. Nothing in the wallet sets it, so the owner has to send `approve(gateway, amount)` through the owner door before the agent's first cross-chain send. If the owner skips it, the agent's send fails. + +**Why that is wrong.** + +- Granting a rule with an asset cap already says how much the agent may move. A second, separate permission is a step no user expects. +- The approval goes through the owner door, so it records an `OWNER_ACTION` checkpoint. An owner who raises the allowance during a job is treated as having changed something mid-job. +- `revokeRules` and `revokeAllRules` do not clear the allowance. It stays on the wallet. +- When the allowance runs out, the agent stops until the owner returns. + +**Change.** The wallet sets the approval itself, for the exact amount of the outbound, in the same transaction, on both doors. + +```diff +// AGW, owner door and agent door +~ execute / executeWithSig / executeAsAgent +~ when a call's target is UNIVERSAL_GATEWAY_PC and its selector is sendUniversalTxOutbound(req): ++ before the call: approve req.token to UNIVERSAL_GATEWAY_PC for req.amount ++ after the call: allowance is 0 again (the gateway took exactly req.amount; reset it if anything is left) +~ agent door order: the rules policy checks req against the rules first, then the approval, then the gateway call += a native-coin outbound (no token pulled) is untouched +``` + +No standing allowance exists at any point outside the call. There is nothing to top up, nothing left after a revoke, and no checkpoint, because the owner did nothing. + +To confirm while implementing: whether the gateway takes anything from the wallet beyond `req.amount` (a fee in the token). If it does, the approval must cover that amount as well. + +### 6.2 One factory call deploys the wallet and grants its rules + +**What happens today.** An external owner sends deploy and grants as one UEA multicall. A Push EOA owner cannot (core rejects a multicall from a Push-native sender), so the SDK sends the deploy and then each grant as its own transaction. If a later grant fails, the wallet exists with only some of its rules. + +**Change.** A factory entry that does both in one transaction, for any owner. Either the wallet exists with every rule passed, or the transaction reverts as a whole. + +```diff +// AGWFactory ++ createWallet(string label, Session[] rules) returns (address wallet, bytes32[] rulesIds) ++ caller is the owner ++ deploys the wallet, then grants every rule, in order; reverts as a whole if any grant fails ++ rules may be empty, in which case it behaves as deployWallet ++ rulesIds are the same ids grantRules would have returned, in the order passed += deployWallet(string label) // unchanged += deployWalletWithSig(...) // unchanged + +// AGW ++ the wallet accepts its first rules from the factory, and only during its own deployment +~ each rule granted this way emits RulesGranted and records a RULES_GRANTED checkpoint, exactly as grantRules does +``` + +To decide: whether a signed variant (`createWalletWithSig`, same digest rules as `deployWalletWithSig` with the rules hashed in) lands in the same change. The marketplace's `startJob` deploys a wallet with rules for the user, so it would use that variant. + +### 6.3 Pins on EVM destination calls + +**What happens today.** All rule checks run on Push, in the rules policy, before the wallet is allowed to call the gateway. For an outbound to an EVM chain the policy unpacks the payload and checks each destination call's target, selector, beneficiary and value. It has no field for a general pin. A rule cannot say "argument 0 of `supply` must be USDC", so an agent allowed to call `supply` can pass any asset the wallet's CEA holds. The Push rulebook has argument pins, and the Solana rulebook has account and data pins. The EVM destination rulebook is the only one without them. + +**Change.** The EVM allowed call gains a list of pins, read from the destination call's calldata the same way the beneficiary already is. A pin either requires an argument to equal a value or to not exceed a value. + +```diff +// libraries/Types.sol + struct ArgPin { += offset; // byte position of the argument in the call's calldata ++ uint8 op; // 0 = EQ: the 32 bytes at offset must equal value ++ // 1 = MAX: the 32 bytes at offset, read as uint256, must not exceed value += bytes32 value; + } + +// universal EVM terms + struct AllowedCall { += target; selector; beneficiary offset and flag; maxValue; ++ ArgPin[] pins; // 0..MAX_PINS (8) + } + +// UniversalRulesPolicy, EVM rulebook +~ checkAction: for each destination call in the payload, after the target, selector, beneficiary and value checks, ++ check every pin of the matching allowed call against that call's calldata ++ reverts reuse the Push rulebook's pin error (ArgPinMismatch) for EQ, and add one for MAX + +// UniversalRulesPolicy, Push rulebook ++ the same op on its pins, so a MAX pin is an ordinary pin there too += the metered argument and the call counter stay in the contract; the SDK no longer exposes them +``` + +The SDK now has one rule shape for every chain, with pins inside each allowed call (page 5, 6.a). Until this lands, the SDK rejects a pin on an EVM destination call before signing, and compiles a `max` pin on a Push call to the existing metered argument (one per call). + +The SDK also folds `beneficiary` into pins: it is written as a pin whose expected value is the wallet itself (page 5, 6.a). Until this change lands, the SDK compiles that pin to the existing beneficiary check, one per call. Once pins exist on EVM destination calls, the same check is an ordinary EQ pin against the wallet's CEA, and the dedicated beneficiary offset and flag on `AllowedCall` can be retired. To decide: retire them in this change, or keep them. + +### 6.4 `ref` removed from `grantRules` + +Section 4 item 3 added a `bytes32 ref` to `grantRules` so a job could bind to a rules id. It is not needed: `rulesId` is generated at grant, and that id is what a job, a card or an indexer latches on to. The v5 contracts on Donut already grant without it. + +```diff +// AGW +- grantRules(Session session, bytes32 ref) returns (bytes32 rulesId) ++ grantRules(Session session) returns (bytes32 rulesId) +- grantRulesWithSig(Session session, bytes32 ref, uint48 deadline, bytes ownerSig) returns (bytes32 rulesId) ++ grantRulesWithSig(Session session, uint48 deadline, bytes ownerSig) returns (bytes32 rulesId) +- RulesGranted(bytes32 indexed rulesId, uint8 mode, bytes32 indexed chainHash, string chainNamespace, bytes32 ref) ++ RulesGranted(bytes32 indexed rulesId, uint8 mode, bytes32 indexed chainHash, string chainNamespace) += Checkpointed(uint64 indexed seq, uint8 kind, bytes32 ref, uint64 blockNumber) // keeps its ref: the checkpoint's own reference +``` + +The `ref?: Hex` field on the SDK struct in 4c goes with it. + +### 6.5 A cap of 0 means nothing moves + +4c says `maxTotal: 0` means no total cap. That is reversed. A wallet whose purpose is to limit an agent must not hand out an unlimited budget because a field was left empty. + +```diff +// universal terms (EVM and SVM) + struct AssetCap { += address token; += uint256 maxPerCall; +- uint256 maxTotal; // 0 = no running cap ++ uint256 maxTotal; // 0 = the agent cannot move this token + } +// same reading for the native coin caps on a Push call: 0 = no native coin may be sent +``` + +The v5 contracts on Donut already treat an explicit zero as "cannot move". The gap was in the SDK, which sent the largest possible number when `maxTotal` was left out. It now sends 0 (page 5, 6.b). + +### 6.6 Checked, no contract change needed + +- **`setLabel` is not a checkpoint.** Item 10 in section 4 already says so and the v5 contract behaves that way. The first SDK implementation routed the rename through the owner door, which does record a checkpoint. The fix is in the SDK: it calls `setLabel` on the wallet directly (page 5, 6.f). +- **First-use destination gas.** The 500,000 default that fails when a CEA is deployed on first use is an SDK default. No contract change (page 5, 6.g). +- **`spent` on rule records.** The counters are already readable from the policy. The SDK puts them back on the record (page 5, 6.c and 6.d). +- **Deleting a rule.** The SDK renames `rules.revoke` to `rules.delete` (page 5, 6.m). `revokeRules` and `revokeAllRules` already remove the rule from the session engine for good, so the contract does what the new name says. The contract names stay as they are. \ No newline at end of file diff --git a/plan/agw/research/section6-feedback-2026-10-12/contracts-previous.md b/plan/agw/research/section6-feedback-2026-10-12/contracts-previous.md new file mode 100644 index 00000000..029e3e82 --- /dev/null +++ b/plan/agw/research/section6-feedback-2026-10-12/contracts-previous.md @@ -0,0 +1,362 @@ +# 1. AGW Contract Changes (nomenclature standard + change set) + + + +# 0. Before the naming: AGW will break when the gateway is upgraded + +**What happened.** The gateway team changed the outbound request struct on GitHub main. Two fields are gone (`gasPrice`, `maxPCForGas`). AGW copied the old struct into its own repo and URP checks one of the removed fields (gate 9: `maxPCForGas` must be non-zero). + +**Why it still works today.** Donut is still running the old gateway (implementation `0x1e41...a659` has the old eight fields). + +**What breaks.** The day the new gateway is deployed on Donut, every cross-chain rule set stops working: URP rejects every request. + +**Fix, two rules.** + +1. AGW never copies a gateway or core struct. It imports them from the gateway and core packages, so a change upstream fails the build instead of failing on-chain. +2. The URP upgrade and the gateway upgrade go out together, not separately. + +Same rule for the selector: derive `sendUniversalTxOutbound.selector` from the interface, do not hardcode `0x77b86bec`. + +# 1. How core and gateway name things (the standard AGW follows) + +These conventions already exist in `push-chain-core-contracts` and `push-chain-gateway-contracts`. AGW adopts them as is. Where the two repos disagree, the AGW column says which one wins. + +| Area | Convention | Example | AGW | +| --- | --- | --- | --- | +| Contract names | Chain-agnostic components spell out Universal. Push-side variants add PC. Accounts are 3-letter acronyms. | `UniversalCore`, `UniversalGatewayPC`, `UEA`, `CEAFactory` | `AGW`, `AGWFactory`, `UniversalRulesPolicy` | +| Errors | One `libraries/Errors.sol` per repo, one error library per contract, PascalCase, arguments only when the caller needs them. Caller checks are `CallerIsNotX`. | `UEAErrors.InvalidCall()`, `CommonErrors.ZeroAddress()`, `CallerIsNotUEModule()` | `AGWErrors`, `AGWFactoryErrors`, `UniversalRulesPolicyErrors` | +| Types and constants | One `libraries/Types.sol`, plain file-level structs, `UPPER_SNAKE` constants, selectors derived not hardcoded. | `struct Multicall`, `MULTICALL_SELECTOR = bytes4(keccak256("UEA_MULTICALL"))` | `libraries/Types.sol`; gateway and core structs imported, never copied | +| Request shape | One `XRequest` struct as the single argument; the contract infers the kind. Users never state a type. | `sendUniversalTxOutbound(UniversalOutboundTxRequest req)` infers `TX_TYPE` | `grantRules(Session)` infers `NATIVE` vs `UNIVERSAL` from `chainNamespace` | +| Interface sections | Tag plus number banners, events first, NatSpec on everything. | `UGPC_1: EVENTS`, `UGPC_2: OUTBOUND TX`, `UGPC_3: VIEW FUNCTIONS` | `AGW_1: EVENTS` ... `AGW_5: VIEWS`, `URP_1` ... `URP_3` | +| Functions | `setX`, `getX`, `isX`. Set-once wiring is read through `UPPER_CASE()` getters. | `isSupportedToken()`, `UNIVERSAL_CORE()` | `SESSION_ENGINE()`, `RULES_POLICY()`, `UNIVERSAL_GATEWAY_PC()` | +| Storage | Internal state is underscore-prefixed. | `_walletCount` | `_` everywhere; drop URP's `$` prefix | +| Roles | `UPPER_SNAKE_ROLE`. | `DEFAULT_ADMIN_ROLE`, `PAUSER_ROLE`, `TSS_ROLE` | same; `PAUSER` and `OPERATOR` split kept, documented | +| Chain identity | Full CAIP-2 string, field named `chainNamespace`. | `"eip155:1"` | envelope field renamed `chain` to `chainNamespace` | +| Events | No consistent rule upstream. | `SetChainMeta` (imperative), `VaultPCUpdated` (past) | past tense: `RulesGranted`, `WalletDeployed` | +| Layout | `src/` with `interfaces/` and `libraries/`; numbered docs and tests; addresses per network; `CLAUDE.md` in every package. | `docs/1_PUSH_CHAIN.md`, `test/gateway/1_adminActions.t.sol`, `docs/addresses/sepolia.md` | same, see rename map | + +#### Where each convention was seen (open only if you want the receipts) + +Core repo, folder layout: + +``` +src/ + Interfaces/ IUniversalCore.sol, IUEA.sol, ICEA.sol + libraries/ Errors.sol, Types.sol, Utils.sol + uea/ UEAFactory.sol, UEA_EVM.sol, UEA_SVM.sol + cea/ CEAFactory.sol, CEA.sol + UniversalCore.sol, PRC20.sol, WPC.sol +``` + +Gateway repo, folder layout: + +``` +contracts/evm-gateway/ + src/ UniversalGateway.sol, UniversalGatewayPC.sol, Vault.sol, VaultPC.sol + src/interfaces/ IUniversalGatewayPC.sol, IVault.sol + src/libraries/ Errors.sol, Types.sol, TypesUG.sol, TypesUGPC.sol + docs/ 1_PUSH_CHAIN.md, 2_UniversalGateway.md, 3_UniversalGatewayPC.md + docs/addresses/ sepolia.md, bsc-testnet.md + test/gateway/ 1_adminActions.t.sol ... 14_gatewayPC.t.sol + script/ 1_DeployGatewayWithProxy.sol, 3_UpgradeGatewayNewImpl.sol + CLAUDE.md +``` + +Errors (core, `libraries/Errors.sol`): + +```solidity +library CommonErrors { error ZeroAddress(); error Unauthorized(); error InvalidInput(); } +library UniversalCoreErrors { error CallerIsNotUEModule(); error GasLimitBelowBase(uint256 provided, uint256 minimum); } +library UEAErrors { error InvalidCall(); error ExecutionFailed(); } +``` + +Types (core, `libraries/Types.sol`): + +```solidity +struct UniversalAccountId { string chainNamespace; string chainId; bytes owner; } +struct Multicall { address to; uint256 value; bytes data; } +bytes4 constant MULTICALL_SELECTOR = bytes4(keccak256("UEA_MULTICALL")); +``` + +Request shape (gateway, `TypesUGPC.sol` and `IUniversalGatewayPC.sol`): + +```solidity +struct UniversalOutboundTxRequest { bytes recipient; address token; uint256 amount; uint256 gasLimit; bytes payload; address revertRecipient; } +function sendUniversalTxOutbound(UniversalOutboundTxRequest calldata req) external payable; // TX_TYPE inferred inside +``` + +Interface sections and wiring getters (gateway, `IUniversalGatewayPC.sol`): + +```solidity +// UGPC_1: EVENTS +// UGPC_2: OUTBOUND TX +// UGPC_3: VIEW FUNCTIONS +function UNIVERSAL_CORE() external view returns (address); +``` + +Events (both repos, no single rule): + +```solidity +event SetChainMeta(...); // core, imperative +event PauserRoleGranted(...); // core, past tense +event UniversalTxOutbound(...); // gateway, noun +event VaultPCUpdated(...); // gateway, past tense +``` + +Chain identity, the same field name with two meanings: + +```solidity +gasPriceByChainNamespace("eip155:1") // UniversalCore: full CAIP-2 string +UniversalAccountId({ chainNamespace: "eip155", chainId: "1" }) // Read State: split +``` + +# 2. Decisions + +| # | Decision | Outcome | +| --- | --- | --- | +| D1 | Wallet contract name | **AGW.sol** (account acronym like UEA, CEA). Full form "Agentic Wallet" in the NatSpec title only. Factory stays `AGWFactory.sol`. | +| D2 | Policy contract name | **UniversalRulesPolicy.sol**. `URP` stays as the short form in comments, events and the SDK constant, the way `UGPC` stands for `UniversalGatewayPC`. | +| D3 | Validator contract name | PROPOSED 2026-09-29: **no validator.** The agent is a Push address: a native key is its own EOA, any external key (EVM, Solana, anything) is its UEA, deterministic from (chain, owner). Cross-VM signature verification already happens inside the UEA, so the agent door checks `msg.sender == rules.agent` and hands the calls to URP. `PushSessionValidator.sol` is removed rather than renamed. Pending one check against the v3 branch: how deep SmartSession's signature path is wired into the engine calls URP relies on, and whether the policy engine can be driven from a sender check without forking it. | +| D4 | Vocabulary for the granted object | **rules, one word everywhere.** On-chain: `grantRules`, `revokeRules`, `revokeAllRules`, `rulesId`, `RulesGranted`, `RulesRevoked`, `RulesActionAuthorized`. Layer: Universal Rules. SDK: `client.agentic.rules`. `permissionId` remains the SmartSession-internal name and is exposed as `rulesId`. `mandate` is retired from code, docs and copy. +**Rename boundary (2026-09-29).** Three vocabularies live in the fork; only ours is renamed. ERC-7579 names stay (`execute(mode, executionCalldata)`, `ModeCode`, module types, `installModule`). SmartSession names stay inside the engine and on the interfaces URP implements (`Session`, `permissionId`, `PolicyData`, `ActionData`, `ConfigId`, `enableSessions`, `isPermissionEnabled`, `IPolicy.checkAction`, `initializeWithMultiplexer`): audit history and upstream diffs attach to those names. Push's own words (`mandate`, `PushAgentWallet`, our events, envelope, docs, SDK) become rules. The seam is the AGW ABI: `rulesId` is computed by the engine's `getPermissionId(Session)` and the NatSpec states `rulesId == permissionId`. If the engine is vendored with edits, it lives in `src/vendor/smartsession/` with a note naming the upstream commit and every local change. If D3 ends with the engine dropped, SmartSession vocabulary leaves with it. | +| D5 | Door functions | Keep `execute` (owner door). Agent door becomes `executeAsAgent(bytes32 rulesId, bytes32 mode, bytes executionCalldata)`, gated on `msg.sender == rules.agent`, replacing `executeWithSession` and its signature blob (follows D3). "Owner door" and "agent door" stay as NatSpec language. | +| D6 | Chain field in the envelope | Rename `chain` to `chainNamespace`, full CAIP-2 string, matching `UniversalCore` and gateway events. Read State keeps its split fields; the SDK converts. | +| D7 | Mode names | `NATIVE` and `UNIVERSAL` stay. The SVM rulebook is selected by the `solana` namespace inside `UNIVERSAL`; no new mode name. | + +# 3. Rename map (current to proposed) + +| Area | Today | Proposed | +| --- | --- | --- | +| Inherited names (7579, SmartSession) | `execute(mode, executionCalldata)`, `Session`, `permissionId`, `PolicyData`, `ActionData`, `ConfigId`, `checkAction`, `initializeWithMultiplexer` | unchanged (see D4 rename boundary) | +| Wallet | `PushAgentWallet.sol` | `AGW.sol` | +| Factory | `AGWFactory.sol` | `AGWFactory.sol` (unchanged) | +| Policy | `policies/URP.sol` | `UniversalRulesPolicy.sol` | +| Validator | `validators/PushSessionValidator.sol` | removed (D3): agent identity is a Push address, verification lives in the UEA | +| Interfaces | `IPushAgentWallet`, `IURP`, `IPushSessionValidator`, local `IUniversalGatewayPC`, `IPRC20Source` | `IAGW`, `IUniversalRulesPolicy`; gateway and core interfaces imported (`IUEAFactory` for `computeUEA` in tests and tooling) | +| Errors | `libraries/PushWalletErrors.sol` plus errors declared in `IURP` and `IAGWFactory` | `libraries/Errors.sol` with `AGWErrors`, `AGWFactoryErrors`, `UniversalRulesPolicyErrors`; reuse `CommonErrors` names (`ZeroAddress`, `Unauthorized`, `AlreadyInitialized`); `AGWErrors.CallerIsNotAgent()` | +| Types | `libraries/PushWalletTypes.sol` re-declares `UniversalOutboundTxRequest`, `Multicall` | `libraries/Types.sol` with AGW-owned structs only (`RulesEnvelope`, `NativeTerms`, `UniversalTerms`, `AllowedCall`, `ArgPin`, `AmountRule`); gateway and core types imported | +| Grant / revoke | `grantMandate`, `stopMandate`, `stopAll` | `grantRules`, `revokeRules`, `revokeAllRules` | +| Events | `MandateGranted`, `MandateRevoked`, `MandateActionAuthorized`, `URPPolicySet` | `RulesGranted`, `RulesRevoked`, `RulesActionAuthorized`, `RulesConfigured` | +| Ids | `permissionId` in wallet ABI | `rulesId` in wallet ABI (engine keeps `permissionId` internally) | +| Wiring getters | `sessionEngine()`, `urp()`, `sessionValidator()`, `universalGateway()` | `SESSION_ENGINE()`, `RULES_POLICY()`, `UNIVERSAL_GATEWAY_PC()` (no validator getter, D3) | +| Storage prefix | `_` in wallet and factory, `$` in URP | `_` everywhere | +| Envelope | `abi.encode(string chain, bytes body)` | `abi.encode(uint16 version, string chainNamespace, bytes body)` | +| Interface banners | none | `AGW_1: EVENTS`, `AGW_2: OWNER DOOR`, `AGW_3: AGENT DOOR`, `AGW_4: RULES LIFECYCLE`, `AGW_5: VIEWS`; `URP_1: EVENTS`, `URP_2: POLICY`, `URP_3: VIEWS`; `AGWF_1: EVENTS`, `AGWF_2: DEPLOY`, `AGWF_3: VIEWS` | +| Selector constant | `SEND_OUTBOUND_SELECTOR = 0x77b86bec` | derived from `IUniversalGatewayPC` | +| Roles | `PAUSER_ROLE` pauses, `OPERATOR_ROLE` unpauses | keep the split, document it as a deliberate deviation from gateway | +| Event tense | past tense | past tense, written down as the rule | +| Docs | `docs/v3-architecture.md`, `agentic_wallet_flow.md`, `push_native_agentic_wallet_flow.md` | `docs/1_AGW.md`, `2_UniversalRulesPolicy.md`, `3_Universal_Flow.md`, `4_Native_Flow.md` | +| Addresses | `deployments/address-book-v3/ADDRESSES.md` | `docs/addresses/donut.md` | +| Tests | `test/unit/*.t.sol`, `test/integration/*.t.sol` | numbered by area: `1_factory`, `2_ownerDoor`, `3_rulesLifecycle`, `4_agentDoor`, `5_universalRulebook`, `6_nativeRulebook`, `7_externalAgentViaUEA`, `8_e2e` | + +# 4. Structural changes that ride along with the rename + +Agreed on 2026-09-28. Listed here so the rename and the additions land in one change set and one audit, before the permanent deployment. + +1. **Signature-authorized variants**: `deployWalletWithSig`, `grantRulesWithSig`, `executeWithSig`. One EIP-712 domain per contract. Digest includes chainid, contract, nonce (the wallet's grant nonce for grants; a per-owner nonce on the factory), deadline. Verify ECDSA, and ERC-1271 when the owner has code (a UEA). +2. **Checkpoints**: the wallet records owner-side changes an evaluator needs: principal moved out (owner-door value or token transfer out, and every outbound), rules granted, revoked or replaced, key changed. Per-wallet monotonic counter plus `Checkpointed(kind, ref, blockNumber)`, so an evaluator can ask "any checkpoint after block N" with one read. +3. **`bytes32 ref` on `grantRules`**, emitted in `RulesGranted`, so a job binds to a rules id and an indexer goes rules to job without the hook. +4. **Stop-only role: dropped for v1** (2026-10-01). A binder address that could call `revokeRules` and nothing else was considered so a job hook could end rules at job end. Not needed: rules expire by `validUntil`, which the fund hook requires to be at or after the job's `expiredAt`, caps bound the gap, and the hook keeps its own one-live-job slot. Additive to bring back later. +5. **Envelope version word**: `abi.encode(uint16 version, string chainNamespace, bytes body)`. +6. **`creditRevert` reachability**: wire the real executor module or replace the credit path. Today spend never decreases on Donut. +7. **SVM rulebook** in the policy, keyed by the `solana` namespace: 32-byte `expectedCEA` and targets, program plus instruction discriminator allow-list, beneficiary check over the accounts array, SVM payload gate. +8. **Import gateway and core types**, derive the outbound selector, sequence the URP upgrade with the gateway's struct change. +9. **Agent identity is a Push address** (2026-09-29). The rules name an address: an EOA, or the UEA of an external key. The agent door checks the sender instead of verifying a session signature; the validator contract goes. One identity for rules, card and 8183 provider, so the fund hook matches by equality. Sizing against the v3 branch pending (D3). +10. **Editable label** (2026-10-01). `setLabel(string label)` on AGW, owner only, emits `LabelSet(string label)`. Today the label is only passed at `deployWallet` and emitted in `WalletDeployed`. Not a checkpoint kind: cosmetic metadata, evaluators ignore it. SDK: `w.setLabel(label)` on page 5. + +# 4b. Contract surface, as a diff + +Read `+` as added, `-` as removed, `~` as changed in place, `=` as unchanged. Names are the post-rename names. Storage slots never move; renames are labels only. + +**AGWFactory** + +```diff += deployWallet(string label) returns (address wallet) // caller is the owner ++ deployWalletWithSig(address owner, uint96 index, string label, ++ uint48 deadline, bytes ownerSig) returns (address) // EIP-712; index must equal walletCount(owner) ++ // ownerSig: ECDSA, or ERC-1271 when owner has code (UEA) ++ DOMAIN_SEPARATOR() view returns (bytes32) += predictWallet(address owner, uint256 index) view returns (address, bool deployed) += walletCount / ownerOf / isWallet / indexOf / walletImplementation += pause() PAUSER_ROLE, unpause() OPERATOR_ROLE += event WalletDeployed(owner, index, wallet, label) +``` + +**AGW** (was PushAgentWallet) + +```diff +// owner door += execute(bytes32 mode, bytes executionCalldata) payable // owner only, no policy +~ execute now emits Checkpointed(seq, OWNER_ACTION, keccak(calldata), block) ++ executeWithSig(bytes32 mode, bytes executionCalldata, ++ uint64 ownerNonce, uint48 deadline, bytes ownerSig) // owner door by signature, same effects as execute ++ ownerNonce() view returns (uint64) ++ setLabel(string label) // owner only; emits LabelSet; not a checkpoint + +// rules lifecycle +- grantMandate(Session) returns (bytes32 permissionId) ++ grantRules(Session session, bytes32 ref) returns (bytes32 rulesId) // ref: job or card reference, emitted, not interpreted ++ grantRulesWithSig(Session session, bytes32 ref, uint48 deadline, bytes ownerSig) returns (bytes32 rulesId) ++ // digest includes grantNonce, so a signed grant cannot replay +- stopMandate(bytes32 permissionId) ++ revokeRules(bytes32 rulesId) // owner or self +- stopAll() ++ revokeAllRules() // owner or self + +// agent door (D3, D5) +- executeWithSession(address validator, bytes32 mode, bytes executionCalldata, +- bytes signature, uint192 nonceKey, uint64 nonceSeq, uint48 requestExpiry) ++ executeAsAgent(bytes32 rulesId, bytes32 mode, bytes executionCalldata) ++ requires msg.sender == agentOf(rulesId); replay and expiry come from the sender's own tx (EOA nonce, or the UEA's) ++ URP checks every call exactly as before; no signature blob, no validator address ++ agentOf(bytes32 rulesId) view returns (address) + +// checkpoints ++ checkpointCount() view returns (uint64) ++ lastCheckpointBlock() view returns (uint64) ++ event Checkpointed(uint64 indexed seq, uint8 kind, bytes32 ref, uint64 blockNumber) ++ kind: 0 OWNER_ACTION (any owner-door execute), 1 RULES_GRANTED, 2 RULES_REVOKED ++ emitted from execute, executeWithSig, grantRules*, revokeRules, revokeAllRules + +// views (wiring, renamed to UPPER_CASE) +- sessionEngine() urp() sessionValidator() universalGateway() ++ SESSION_ENGINE() RULES_POLICY() UNIVERSAL_GATEWAY_PC() += owner() factory() grantNonce() getNonce(uint192) accountId() ++ DOMAIN_SEPARATOR() view returns (bytes32) + +// events +- MandateGranted(permissionId, mandateType, chainHash, chain) ++ RulesGranted(bytes32 indexed rulesId, uint8 mode, bytes32 indexed chainHash, string chainNamespace, bytes32 ref) +- MandateRevoked(permissionId) ++ RulesRevoked(bytes32 indexed rulesId, address by) +- MandateActionAuthorized(permissionId, nonceKey, nonceSeq, opHash) ++ RulesActionAuthorized(bytes32 indexed rulesId, address indexed agent, bytes32 callsHash) ++ event LabelSet(string label) +``` + +**UniversalRulesPolicy** (was URP) + +```diff +~ initializeWithMultiplexer(address account, ConfigId id, bytes initData) +~ initData = abi.encode(uint16 version, string chainNamespace, bytes body) // was (string chain, bytes body) +~ rulebook chosen by namespace: this chain => native; eip155:* => universal EVM; solana:* => universal SVM ++ SVM rulebook ++ struct SvmTerms { uint48 validUntil; bytes32 expectedCEA; address asset; uint256 maxAmountPerCall; ++ uint256 maxAmountTotal; uint256 maxPCPerCall; SvmAllowedCall[] allowedCalls; } ++ struct SvmAllowedCall { bytes32 program; bytes8 discriminator; uint8 beneficiaryAccountIndex; bool hasBeneficiary; uint64 maxLamports; } ++ gates mirror the EVM list; beneficiary checked in the accounts array, payload gate for the SVM outbound format +~ checkAction: UniversalOutboundTxRequest imported from the gateway package +~ gate 4c MIN_OUTBOUND_BODY_LEN recomputed from the imported struct +~ gate 9 (maxPCForGas != 0) removed when the six-field gateway struct lands; deploy in the same window +~ creditRevert(id, account, outboundTxId, amount): caller is the real executor module, set at initialize += or removed if the credit path is replaced (decision pending) += assertSpent (both overloads), getConfig, getNativeConfig, getMode, pushChainHash, isCredited ++ getSvmConfig(ConfigId, address) view +- event URPPolicySet(...) ++ event RulesConfigured(bytes32 indexed configId, address indexed multiplexer, address indexed account, uint8 mode, bytes32 chainHash) += OutboundMetered, NativeCallMetered, RevertCredited +~ storage variables renamed $configs, $credited, $mode, $native to _configs, _credited, _mode, _native (labels only, slots unchanged) ++ _svm mapping appended after _native; __gap shrinks by one +~ version() returns "2.0.0" +``` + +**PushSessionValidator** + +```diff +- validateConfig(bytes keyConfig) +- validateSignatureWithData(bytes32 hash, bytes sig, bytes keyConfig) +- contract removed (D3). Session.sessionValidator and keyConfig are replaced by a single address in the rules: the agent. +``` + +**Not in this change set** (belongs to 8183, listed so nobody looks for it here): the fund hook's key-match and expiry checks, the marketplace, the evaluator. + +# 4c. What the SDK rule shape changes in the contracts (PROPOSED 2026-10-02) + +Page 5 (SDK: AGW) settled the shape of a cross-chain rule in `client.agentic.create`. Three of those SDK changes touch the contracts. Nothing else on page 5 does. Names are the post-rename names from section 3; struct changes are to the universal terms URP decodes from the rules envelope. + +**1. One rule can move several tokens: `assets: AssetCap[]` replaces `asset`, `maxAmountPerCall`, `maxAmountTotal`.** + +The SDK takes each asset as the token's address on the rule's chain (`MOVEABLE.TOKEN..` or the native marker) and resolves it to the PRC20 on Push before encoding, so the contract keeps storing PRC20 addresses. The spend counter becomes per asset. + +```diff +// universal EVM terms (and SvmTerms, same change) +- address asset; uint256 maxAmountPerCall; uint256 maxAmountTotal; ++ AssetCap[] assets; // 0..MAX_ASSETS; empty = call contracts, move nothing ++ struct AssetCap { address token; uint256 maxPerCall; uint256 maxTotal; } // token: PRC20 on Push; maxTotal 0 = no total cap ++ uint8 constant MAX_ASSETS = 8; + +// metering +~ amount gate: the token being moved must be one of assets[]; per-call and running total checked against that entry +~ _spent[configId] becomes per token: mapping(address token => uint256 spent) +~ assertSpent(configId, account) returns the per-token totals; the existing single-amount overload goes +~ OutboundMetered carries the token +``` + +**2. `maxGasPerCall` replaces `maxPCPerCall`.** + +Rename only. Same meaning: the PC (wei) the wallet may pass as `msg.value` on one outbound for the destination leg. The gate that checks it does not change. + +```diff +- uint256 maxPCPerCall; ++ uint256 maxGasPerCall; +``` + +**3. The struct, as it ends up.** + +SDK side, what `create` takes per rule (page 5, 3.b). `agent` and `ref` go to `grantRules`, the rest is encoded into the rules envelope. + +```tsx +interface UniversalRule { + agent: Address; // Push address: EOA, or the UEA of an external key + ref?: Hex; // emitted in RulesGranted, not interpreted + chainNamespace: ForeignChainNamespace; + assets: AssetCap[]; // tokens the agent may move on chainNamespace; 0..8 + maxGasPerCall: bigint; // PC (wei) per outbound for the destination leg + validUntil: number; + allowedCalls: AllowedCall[]; +} + +interface AssetCap { + token: MoveableToken | Address; // the other chain's token address (MOVEABLE.TOKEN..) or the native marker + maxPerCall: bigint; + maxTotal?: bigint; +} +``` + +Contract side, what URP decodes from the envelope body for an `eip155` namespace (`SvmTerms` takes the same `assets` and `maxGasPerCall` fields). + +```solidity +struct AssetCap { + address token; // PRC20 on Push, resolved by the SDK from the other chain's address + uint256 maxPerCall; + uint256 maxTotal; // 0 = no running cap +} + +struct UniversalTerms { + uint48 validUntil; + bytes32 expectedCEA; + AssetCap[] assets; // 0..MAX_ASSETS; empty = call contracts, move nothing + uint256 maxGasPerCall; // PC (wei) per outbound + AllowedCall[] allowedCalls; // unchanged +} + +uint8 constant MAX_ASSETS = 8; +``` + +# 5. Open for review on this page + +1. D3: removing the validator. Needs the v3 branch check on how SmartSession's engine is entered (signature path vs a sender-gated call into the same policy checks). If the engine cannot be entered without a signature, the fallback is a validator that accepts a trivial signature from the sender, which keeps the identity model and loses nothing but elegance. +2. Checkpoint kinds, since they are the evaluator's contract with the wallet. +3. `creditRevert`: wire the executor module, or replace the credit path. +4. Anything in the rename map or the diff that should stay as is. + +The SDK surface lives on page 5 (SDK: AGW). \ No newline at end of file diff --git a/plan/agw/research/section6-feedback-2026-10-12/contracts.diff b/plan/agw/research/section6-feedback-2026-10-12/contracts.diff new file mode 100644 index 00000000..1a763256 --- /dev/null +++ b/plan/agw/research/section6-feedback-2026-10-12/contracts.diff @@ -0,0 +1,147 @@ +--- previous/1-agw-contract-changes.md ++++ latest/1-agw-contract-changes.md +@@ -359,4 +359,144 @@ + 3. `creditRevert`: wire the executor module, or replace the credit path. + 4. Anything in the rename map or the diff that should stay as is. + +-The SDK surface lives on page 5 (SDK: AGW).+The SDK surface lives on page 5 (SDK: AGW). ++ ++# 6. Changes proposed on 12 Oct 2026 ++ ++These come from the review of the first SDK implementation, [push-chain-sdk PR #291](https://github.com/pushchain/push-chain-sdk/pull/291), which runs against the v5 contracts on Donut. Sections 0 to 5 above are left exactly as they were. Where an entry here differs from them, the entry here is the current one. The SDK side of each change is on [5. SDK: AGW](https://app.notion.com/p/5-SDK-AGW-3e9188aea7f481cf8e8de324956549b9?pvs=21) (page 5), section 6. ++ ++Struct and field names below are shown by meaning. Where the v5 source names a field differently, the source name wins. ++ ++| # | Change | Contract | Replaces above | SDK side (page 5) | ++| --- | --- | --- | --- | --- | ++| 6.1 | The wallet approves the gateway itself, for the exact amount, inside each outbound | AGW | new | 6.g | ++| 6.2 | One factory call deploys the wallet and grants its rules | AGWFactory, AGW | new (page 5 called this "item 11") | 6.b | ++| 6.3 | Pins on EVM destination calls | UniversalRulesPolicy | new | 6.a | ++| 6.4 | `ref` removed from `grantRules` | AGW | section 4 item 3, and the `ref` lines in 4b and 4c | 6.b, 6.c, 6.d | ++| 6.5 | A cap of 0 means nothing moves | UniversalRulesPolicy | "0 = no total cap" in 4c | 6.b | ++ ++### 6.1 The wallet approves the gateway itself, for the exact amount, inside each outbound ++ ++**What happens today.** When the wallet sends a token to another chain, `UniversalGatewayPC` takes the token out of the wallet. That needs an ERC20 approval from the wallet to the gateway. Nothing in the wallet sets it, so the owner has to send `approve(gateway, amount)` through the owner door before the agent's first cross-chain send. If the owner skips it, the agent's send fails. ++ ++**Why that is wrong.** ++ ++- Granting a rule with an asset cap already says how much the agent may move. A second, separate permission is a step no user expects. ++- The approval goes through the owner door, so it records an `OWNER_ACTION` checkpoint. An owner who raises the allowance during a job is treated as having changed something mid-job. ++- `revokeRules` and `revokeAllRules` do not clear the allowance. It stays on the wallet. ++- When the allowance runs out, the agent stops until the owner returns. ++ ++**Change.** The wallet sets the approval itself, for the exact amount of the outbound, in the same transaction, on both doors. ++ ++```diff ++// AGW, owner door and agent door ++~ execute / executeWithSig / executeAsAgent ++~ when a call's target is UNIVERSAL_GATEWAY_PC and its selector is sendUniversalTxOutbound(req): +++ before the call: approve req.token to UNIVERSAL_GATEWAY_PC for req.amount +++ after the call: allowance is 0 again (the gateway took exactly req.amount; reset it if anything is left) ++~ agent door order: the rules policy checks req against the rules first, then the approval, then the gateway call ++= a native-coin outbound (no token pulled) is untouched ++``` ++ ++No standing allowance exists at any point outside the call. There is nothing to top up, nothing left after a revoke, and no checkpoint, because the owner did nothing. ++ ++To confirm while implementing: whether the gateway takes anything from the wallet beyond `req.amount` (a fee in the token). If it does, the approval must cover that amount as well. ++ ++### 6.2 One factory call deploys the wallet and grants its rules ++ ++**What happens today.** An external owner sends deploy and grants as one UEA multicall. A Push EOA owner cannot (core rejects a multicall from a Push-native sender), so the SDK sends the deploy and then each grant as its own transaction. If a later grant fails, the wallet exists with only some of its rules. ++ ++**Change.** A factory entry that does both in one transaction, for any owner. Either the wallet exists with every rule passed, or the transaction reverts as a whole. ++ ++```diff ++// AGWFactory +++ createWallet(string label, Session[] rules) returns (address wallet, bytes32[] rulesIds) +++ caller is the owner +++ deploys the wallet, then grants every rule, in order; reverts as a whole if any grant fails +++ rules may be empty, in which case it behaves as deployWallet +++ rulesIds are the same ids grantRules would have returned, in the order passed ++= deployWallet(string label) // unchanged ++= deployWalletWithSig(...) // unchanged ++ ++// AGW +++ the wallet accepts its first rules from the factory, and only during its own deployment ++~ each rule granted this way emits RulesGranted and records a RULES_GRANTED checkpoint, exactly as grantRules does ++``` ++ ++To decide: whether a signed variant (`createWalletWithSig`, same digest rules as `deployWalletWithSig` with the rules hashed in) lands in the same change. The marketplace's `startJob` deploys a wallet with rules for the user, so it would use that variant. ++ ++### 6.3 Pins on EVM destination calls ++ ++**What happens today.** All rule checks run on Push, in the rules policy, before the wallet is allowed to call the gateway. For an outbound to an EVM chain the policy unpacks the payload and checks each destination call's target, selector, beneficiary and value. It has no field for a general pin. A rule cannot say "argument 0 of `supply` must be USDC", so an agent allowed to call `supply` can pass any asset the wallet's CEA holds. The Push rulebook has argument pins, and the Solana rulebook has account and data pins. The EVM destination rulebook is the only one without them. ++ ++**Change.** The EVM allowed call gains a list of pins, read from the destination call's calldata the same way the beneficiary already is. A pin either requires an argument to equal a value or to not exceed a value. ++ ++```diff ++// libraries/Types.sol ++ struct ArgPin { ++= offset; // byte position of the argument in the call's calldata +++ uint8 op; // 0 = EQ: the 32 bytes at offset must equal value +++ // 1 = MAX: the 32 bytes at offset, read as uint256, must not exceed value ++= bytes32 value; ++ } ++ ++// universal EVM terms ++ struct AllowedCall { ++= target; selector; beneficiary offset and flag; maxValue; +++ ArgPin[] pins; // 0..MAX_PINS (8) ++ } ++ ++// UniversalRulesPolicy, EVM rulebook ++~ checkAction: for each destination call in the payload, after the target, selector, beneficiary and value checks, +++ check every pin of the matching allowed call against that call's calldata +++ reverts reuse the Push rulebook's pin error (ArgPinMismatch) for EQ, and add one for MAX ++ ++// UniversalRulesPolicy, Push rulebook +++ the same op on its pins, so a MAX pin is an ordinary pin there too ++= the metered argument and the call counter stay in the contract; the SDK no longer exposes them ++``` ++ ++The SDK now has one rule shape for every chain, with pins inside each allowed call (page 5, 6.a). Until this lands, the SDK rejects a pin on an EVM destination call before signing, and compiles a `max` pin on a Push call to the existing metered argument (one per call). ++ ++The SDK also folds `beneficiary` into pins: it is written as a pin whose expected value is the wallet itself (page 5, 6.a). Until this change lands, the SDK compiles that pin to the existing beneficiary check, one per call. Once pins exist on EVM destination calls, the same check is an ordinary EQ pin against the wallet's CEA, and the dedicated beneficiary offset and flag on `AllowedCall` can be retired. To decide: retire them in this change, or keep them. ++ ++### 6.4 `ref` removed from `grantRules` ++ ++Section 4 item 3 added a `bytes32 ref` to `grantRules` so a job could bind to a rules id. It is not needed: `rulesId` is generated at grant, and that id is what a job, a card or an indexer latches on to. The v5 contracts on Donut already grant without it. ++ ++```diff ++// AGW ++- grantRules(Session session, bytes32 ref) returns (bytes32 rulesId) +++ grantRules(Session session) returns (bytes32 rulesId) ++- grantRulesWithSig(Session session, bytes32 ref, uint48 deadline, bytes ownerSig) returns (bytes32 rulesId) +++ grantRulesWithSig(Session session, uint48 deadline, bytes ownerSig) returns (bytes32 rulesId) ++- RulesGranted(bytes32 indexed rulesId, uint8 mode, bytes32 indexed chainHash, string chainNamespace, bytes32 ref) +++ RulesGranted(bytes32 indexed rulesId, uint8 mode, bytes32 indexed chainHash, string chainNamespace) ++= Checkpointed(uint64 indexed seq, uint8 kind, bytes32 ref, uint64 blockNumber) // keeps its ref: the checkpoint's own reference ++``` ++ ++The `ref?: Hex` field on the SDK struct in 4c goes with it. ++ ++### 6.5 A cap of 0 means nothing moves ++ ++4c says `maxTotal: 0` means no total cap. That is reversed. A wallet whose purpose is to limit an agent must not hand out an unlimited budget because a field was left empty. ++ ++```diff ++// universal terms (EVM and SVM) ++ struct AssetCap { ++= address token; ++= uint256 maxPerCall; ++- uint256 maxTotal; // 0 = no running cap +++ uint256 maxTotal; // 0 = the agent cannot move this token ++ } ++// same reading for the native coin caps on a Push call: 0 = no native coin may be sent ++``` ++ ++The v5 contracts on Donut already treat an explicit zero as "cannot move". The gap was in the SDK, which sent the largest possible number when `maxTotal` was left out. It now sends 0 (page 5, 6.b). ++ ++### 6.6 Checked, no contract change needed ++ ++- **`setLabel` is not a checkpoint.** Item 10 in section 4 already says so and the v5 contract behaves that way. The first SDK implementation routed the rename through the owner door, which does record a checkpoint. The fix is in the SDK: it calls `setLabel` on the wallet directly (page 5, 6.f). ++- **First-use destination gas.** The 500,000 default that fails when a CEA is deployed on first use is an SDK default. No contract change (page 5, 6.g). ++- **`spent` on rule records.** The counters are already readable from the policy. The SDK puts them back on the record (page 5, 6.c and 6.d). ++- **Deleting a rule.** The SDK renames `rules.revoke` to `rules.delete` (page 5, 6.m). `revokeRules` and `revokeAllRules` already remove the rule from the session engine for good, so the contract does what the new name says. The contract names stay as they are. \ No newline at end of file diff --git a/plan/agw/research/section6-feedback-2026-10-12/download-manifest.json b/plan/agw/research/section6-feedback-2026-10-12/download-manifest.json new file mode 100644 index 00000000..8df178fa --- /dev/null +++ b/plan/agw/research/section6-feedback-2026-10-12/download-manifest.json @@ -0,0 +1,18 @@ +[ + { + "page": "sdk", + "export_entry": "Private & Shared/5 SDK AGW 3e9188aea7f481cf8e8de324956549b9.md", + "sha256": "7f8e6e892686fc298bd0a40d66d7e21cb457711e18a272e563322403bc0380ec", + "exported_at": "2026-10-12T14:53:27.075673+00:00", + "local_file": "plan/agw/notion/5-sdk-agw.md", + "native_export_includes_comments": false + }, + { + "page": "contracts", + "export_entry": "Private & Shared/1 AGW Contract Changes (nomenclature standard + ch 3e9188aea7f4813aa31fc95ceb4e684d.md", + "sha256": "7d1690747f52a32a2e3c9eac64422db8dbc673729f370156da2c83c06634bac4", + "exported_at": "2026-10-12T14:53:27.077622+00:00", + "local_file": "plan/agw/notion/1-agw-contract-changes.md", + "native_export_includes_comments": false + } +] diff --git a/plan/agw/research/section6-feedback-2026-10-12/previous-latest-refresh.json b/plan/agw/research/section6-feedback-2026-10-12/previous-latest-refresh.json new file mode 100644 index 00000000..b0d1334c --- /dev/null +++ b/plan/agw/research/section6-feedback-2026-10-12/previous-latest-refresh.json @@ -0,0 +1,135 @@ +{ + "run_id": "20261007T102718466408Z", + "pulled_at": "2026-10-07T10:27:18.466408+00:00", + "complete": true, + "missing_page_ids": [], + "unknown_export_entries": [], + "archives": [ + "notion/exports/20261007T102718466408Z/export-1.zip", + "notion/exports/20261007T102718466408Z/export-2.zip", + "notion/exports/20261007T102718466408Z/export-3.zip", + "notion/exports/20261007T102718466408Z/export-4.zip" + ], + "pages": [ + { + "page_id": "3e9188aea7f481c8b38ccba332b0afa2", + "title": "AGW design overview", + "local_file": "notion/overview.md", + "changed": false, + "previous_sha256": "f2d7954e018324a937282ca190f397cc12a27973a07c891f3edfd6e89383c53e", + "sha256": "f2d7954e018324a937282ca190f397cc12a27973a07c891f3edfd6e89383c53e", + "raw_export_sha256": "99b727bd58cf588b2c766dc1b93eff402c47e918718b69c2a456b119ad43435b" + }, + { + "page_id": "3e9188aea7f4813aa31fc95ceb4e684d", + "title": "1 AGW Contract Changes", + "local_file": "notion/1-agw-contract-changes.md", + "changed": false, + "previous_sha256": "f1301d8ff1cf370968b90a3d53037ece8fa4c6783c45a402f9be6998928e3631", + "sha256": "f1301d8ff1cf370968b90a3d53037ece8fa4c6783c45a402f9be6998928e3631", + "raw_export_sha256": "f1301d8ff1cf370968b90a3d53037ece8fa4c6783c45a402f9be6998928e3631" + }, + { + "page_id": "3e9188aea7f48118b90ac9b267496295", + "title": "2 Universal Marketplace", + "local_file": "notion/2-universal-marketplace.md", + "changed": false, + "previous_sha256": "5ddfd9e8980faae9eec85e3959cc99edbb3b115565af289c5603a91df0b78d18", + "sha256": "5ddfd9e8980faae9eec85e3959cc99edbb3b115565af289c5603a91df0b78d18", + "raw_export_sha256": "5ddfd9e8980faae9eec85e3959cc99edbb3b115565af289c5603a91df0b78d18" + }, + { + "page_id": "3e9188aea7f48188a838c3a740d8c858", + "title": "3 ERC-8183 job kernel and hook", + "local_file": "notion/3-8183-job-kernel-and-hook.md", + "changed": false, + "previous_sha256": "3c805db465f2d39db8d34179ac1dd864db1abf7b1b3e93f38074fbf393093f90", + "sha256": "3c805db465f2d39db8d34179ac1dd864db1abf7b1b3e93f38074fbf393093f90", + "raw_export_sha256": "3c805db465f2d39db8d34179ac1dd864db1abf7b1b3e93f38074fbf393093f90" + }, + { + "page_id": "3e9188aea7f4817bb03ef4c78c883f8b", + "title": "4 Universal Evaluation", + "local_file": "notion/4-universal-evaluation.md", + "changed": false, + "previous_sha256": "a2f1c93a75b8631c9628c06f1be135fa0198f00f096a765ce808dd5e544b2d6f", + "sha256": "a2f1c93a75b8631c9628c06f1be135fa0198f00f096a765ce808dd5e544b2d6f", + "raw_export_sha256": "a2f1c93a75b8631c9628c06f1be135fa0198f00f096a765ce808dd5e544b2d6f" + }, + { + "page_id": "3e9188aea7f481cf8e8de324956549b9", + "title": "5 SDK AGW", + "local_file": "notion/5-sdk-agw.md", + "changed": true, + "previous_sha256": "e407ee77cdf874db7ef4697f84e9945ff3a12a2f2e07e8a7f90bd24e93ea32f1", + "sha256": "d3bc55b08a37d762c49173149fd8d554a8551682c0956de3e91394a54bfed9a6", + "raw_export_sha256": "8d024eb2bd2955fc772d2194f50a02d601a2d5bf903b0c9cc74882ee11348130" + }, + { + "page_id": "3ea188aea7f481e2961ed97129f3a4e6", + "title": "6 SDK Universal Marketplace", + "local_file": "notion/6-sdk-universal-marketplace.md", + "changed": false, + "previous_sha256": "e7298952f2ba9adb218b4ef0459b8fa696a2072167dc5f655060b69788cf528c", + "sha256": "e7298952f2ba9adb218b4ef0459b8fa696a2072167dc5f655060b69788cf528c", + "raw_export_sha256": "e7298952f2ba9adb218b4ef0459b8fa696a2072167dc5f655060b69788cf528c" + }, + { + "page_id": "3ea188aea7f481e0a137f5a896723376", + "title": "7 SDK ERC-8183 Job", + "local_file": "notion/7-sdk-8183-job.md", + "changed": false, + "previous_sha256": "dbf1ff539f5df944e5f5f55710f5f6d3359469a141038cec2604e7c33392752c", + "sha256": "dbf1ff539f5df944e5f5f55710f5f6d3359469a141038cec2604e7c33392752c", + "raw_export_sha256": "dbf1ff539f5df944e5f5f55710f5f6d3359469a141038cec2604e7c33392752c" + }, + { + "page_id": "3ea188aea7f48197a3b3cfdedfa74fee", + "title": "8 SDK Universal Evaluation", + "local_file": "notion/8-sdk-universal-evaluation.md", + "changed": false, + "previous_sha256": "eb2e584bd76aeea06c0dd03b3c8802b2340acf955e1ea75bf7768ebf9d2ab34e", + "sha256": "eb2e584bd76aeea06c0dd03b3c8802b2340acf955e1ea75bf7768ebf9d2ab34e", + "raw_export_sha256": "eb2e584bd76aeea06c0dd03b3c8802b2340acf955e1ea75bf7768ebf9d2ab34e" + }, + { + "page_id": "d2d188aea7f4825cbcea81ef86eca607", + "title": "Legacy PUSH AGW SDK Doc v1", + "local_file": "notion/legacy-agw-sdk-v1.md", + "changed": false, + "previous_sha256": "9e6569ef9b76d59cb411d65305d67333c6766abc2e9c80a35ae6f56f12f70916", + "sha256": "9e6569ef9b76d59cb411d65305d67333c6766abc2e9c80a35ae6f56f12f70916", + "raw_export_sha256": "9e6569ef9b76d59cb411d65305d67333c6766abc2e9c80a35ae6f56f12f70916" + }, + { + "page_id": "3d1188aea7f480ddbb4af6d0efb211e6", + "title": "AGW Address Book PC Donut", + "local_file": "notion/agw-address-book-donut-2026-09-04.md", + "changed": false, + "previous_sha256": "5c5017d6b4a58af0fa8854ef550b054c1f33d57a812ea51a16f31f7c33e79742", + "sha256": "5c5017d6b4a58af0fa8854ef550b054c1f33d57a812ea51a16f31f7c33e79742", + "raw_export_sha256": "5c5017d6b4a58af0fa8854ef550b054c1f33d57a812ea51a16f31f7c33e79742" + }, + { + "page_id": "3d1188aea7f4801f9cb3fbd9318ec536", + "title": "Agentic wallet flow updated", + "local_file": "notion/agentic-wallet-flow-2026-09-07.md", + "changed": false, + "previous_sha256": "d4a922fd1d33da5a7042f26053e8df0e496c3ccd4cb0044b0892948ac509c3a0", + "sha256": "d4a922fd1d33da5a7042f26053e8df0e496c3ccd4cb0044b0892948ac509c3a0", + "raw_export_sha256": "d4a922fd1d33da5a7042f26053e8df0e496c3ccd4cb0044b0892948ac509c3a0" + } + ], + "review_status": "Review required", + "contract_deployment_followup": { + "checked_on": "2026-10-07", + "documentation_commit": "bd230d20dbf778d9994b1f1082f79b1a8829a10f", + "deployed_source_commit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", + "generation": "v5", + "chain_id": 42101, + "readonly_block": 23991912, + "evidence": "research/deployment-review-2026-10-07-v5/README.md", + "sdk_validation": "research/v5-implementation-2026-10-07/README.md", + "notion_reexported_for_this_followup": false + } +} diff --git a/plan/agw/research/section6-feedback-2026-10-12/previous-questions-harsh.md b/plan/agw/research/section6-feedback-2026-10-12/previous-questions-harsh.md new file mode 100644 index 00000000..612b716a --- /dev/null +++ b/plan/agw/research/section6-feedback-2026-10-12/previous-questions-harsh.md @@ -0,0 +1,25 @@ +# AGW SDK — product decisions confirmed + +Updated October 7, 2026 from Shoaib’s relayed team answers and SDK-owned decision approval. There are no remaining product questions in this document. + + +## 1–2. Defaults and token model + +Omitted native `maxValuePerCall` and `maxValueTotal` are `0`: no native PC value allowance. Retain the current `assets[]` model and independent per-token budgets. The SDK matches these decisions. + + +## 3. Solana rules + +Use named inputs from an IDL. The SDK now exposes `SolanaRule`, compiles supported Anchor layouts, derives wallet accounts, and returns exact decoded constraints. Unsupported layouts fail explicitly. See the [consumer guide](../../packages/core/AGW.md#solana-rules-using-named-idl-inputs). + + +## 4. Native/EVM argument restrictions + +Keep both ABI argument-index and raw-offset inputs, with exact offsets on reads. Shoaib approved this SDK-owned choice. Inputs that specify both forms are rejected; normal examples should prefer argument indexes. + + +## 5. Contract validation and SDK errors — clarified + +The intended behavior is that the existing contract rejects unauthorized functions/actions under the supplied rule, and the SDK maps those errors. This does not request automatic rule selection or a new contract interface. The SDK retains `AMBIGUOUS_RULE` when multiple enabled rules match the agent and chain, without submitting a transaction. No caller-facing rule selector is being added. + +Rule `ref` is removed from scope; editable labels are delivered and implemented against v5. [Zaryab delivery items](questions-zaryab.md). diff --git a/plan/agw/research/section6-feedback-2026-10-12/previous-questions-zaryab.md b/plan/agw/research/section6-feedback-2026-10-12/previous-questions-zaryab.md new file mode 100644 index 00000000..dc44347a --- /dev/null +++ b/plan/agw/research/section6-feedback-2026-10-12/previous-questions-zaryab.md @@ -0,0 +1,12 @@ +# AGW SDK — contract delivery status + +Updated October 7, 2026 after the v5 deployment. **No remaining standalone AGW contract question needs an answer from Zaryab.** + + + +The label interface and compatible deployment are delivered in `deploy-agw@bd230d2` (deployed source `2e61e13`). The SDK now uses the new factory, reads stored labels and implements owner-only `setLabel` with empty reset and the 64-byte limit. [Deployment verification](research/deployment-review-2026-10-07-v5/README.md) · [SDK migration and acceptance](research/v5-implementation-2026-10-07/README.md). + + +Named-IDL Solana authoring, removal of rule `ref`, zero native PC defaults and the existing token model remain settled. Native/EVM inputs accept argument indexes or raw offsets. The SDK retains AMBIGUOUS_RULE; the contract validates the supplied rule. No automatic-selection interface change is requested. + +Push-core spend credit and bridge retry timing remain separate downstream follow-ups. They do not block the label integration. diff --git a/plan/agw/research/section6-feedback-2026-10-12/sdk-export.zip b/plan/agw/research/section6-feedback-2026-10-12/sdk-export.zip new file mode 100644 index 0000000000000000000000000000000000000000..bab91a194a0e86595f9fdb5a54576afb0b3114cb GIT binary patch literal 28811 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�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 +🧩 + +**Where we are going.** `client.agentic` in `@pushchain/core`: create a wallet with rules in one call, act as an agent through it with the same `sendTransaction` everyone already uses, and later list cards, start jobs and build criteria from the same client. Examples first, types second, nothing that breaks the existing SDK. + +**What this page is.** The SDK surface for the AGW alone: `client.agentic` on the owner side, `PushChain.initialize(agentSigner, { agenticWallet })` on the agent side. One heading per function so the table of contents lists everything that is coming in. Marketplace, job and evaluation SDKs are pages 6, 7, 8. + +**Namespaces.** Four top-level, one per piece: `client.agentic`, `client.market`, `client.job`, `client.evaluation`. Nothing is nested under `agentic`. + + + +# List of changes + +New + +- `client.agentic.derive` +- `client.agentic.create` +- `client.agentic.list` +- `client.agentic.wallet`, + - a management handle with + - `info`, + - `owner`, + - `setLabel` (PROPOSED), + - `checkpoints`, + - `rules.list`, + - `rules.get`, + - `rules.add`, + - `rules.update`, + - `rules.revoke` +- `PushChain.CONSTANTS.AGENTIC` +- `~~PushChain.utils.agentic~~` (dropped 12 Oct 2026, see 6.h) + +Updated + +- `PushChain.initialize`, new option `agenticWallet` +- `PushChain.CONSTANTS.READ.CHAIN`, outside change confirmed 2026-09-28 + +Initialize is unchanged on the owner side: + +```tsx +const client = await PushChain.initialize(universalSigner, { network: PushChain.CONSTANTS.PUSH_NETWORK.TESTNET }); +``` + +| Signer | Door | Rules checked | +| --- | --- | --- | +| The wallet's owner | Owner door (`execute`) | No. Every send is recorded as a checkpoint | +| An address named as `agent` in one of the wallet's rules | Agent door (`executeAsAgent`) | Yes, by URP (UniversalRulesPolicy, the on-chain rule checker) | +| Anyone else | None | Never reached: `initialize` throws `NOT_OWNER_OR_AGENT` | + +An agentic wallet involves three parties, and it helps to have them straight before reading the functions. + +The **owner** is whoever created the wallet. When the owner sends through the wallet, no rules are checked; this is called the owner door, and the contract records every such action as a checkpoint so that an evaluator can later tell whether the owner touched anything mid-job. + +The **agent** is the address the owner allows to act on its behalf. It is always a Push address. If the agent's key is a Push EOA, that EOA is the agent. If the key lives on another chain (an EVM key on Ethereum, a Solana key, anything else), the agent is that key's UEA on Push, which exists deterministically for every external key. The SDK never asks for a curve, a chain or a key type. When the agent sends through the wallet, the rules are checked; this is the agent door. + +The **rules** say what an agent may do. Each rule names its agent and its destination chain, and there is one rule per chain per agent, so a wallet can have one agent for Ethereum and a different one for Solana. The `chainNamespace` on a rule decides which rulebook applies: leave it out and the rule governs calls on Push itself; set it to an `eip155` or `solana` chain and the rule governs cross-chain calls to that chain. + +Two ways to touch a wallet from the SDK. `PushChain.initialize(signer, { agenticWallet })` returns a client that acts as the wallet, and whether it goes through the owner door or the agent door depends on who the signer is. `client.agentic.wallet(address)` returns a handle for managing the wallet (rules, label, checkpoints) and never sends as it. + +# 1. Owner side, by example + +The owner side is everything the person who owns the wallet does: create it, fund it, write and revoke the rules, look at what happened. The agent side (section 2) is what the agent does: act through the wallet within those rules. + +### 1.a Derive an agentic wallet address - `client.agentic.derive` + +Gives you the address a wallet will have before it is deployed. The address depends only on the owner and an index. + +```tsx +// Function +const first = await client.agentic.derive({ options? }) + +// Usage and Params +const next = await client.agentic.derive(); // the owner's next wallet +const first = await client.agentic.derive({ index: 0 }); // a specific slot +// options.index number, optional which wallet slot to derive; default is the owner's next unused index + +// Returns +// { address, index, deployed } +{ + address: '0x2Fd904d6f2C0b34d58426C8Ae9c5267E845CE98f', + index: 0, + deployed: false +} +``` + +Because the address depends only on the owner and an index, it is the same whether you deploy first or later. That lets you send funds to it first (from any chain) and deploy afterwards, or show the address in a UI before anything is on-chain. Same idea as `deriveExecutorAccount` for a UEA. + +### 1.b Create an agentic wallet - `client.agentic.create` + +Deploys the wallet and grants the rules. The label is the only wallet-level input; the agent and an optional `ref` are named on each rule, because that is where the contract binds them. + +```tsx +// Function +const created = await client.agentic.create(label, { options }) + +// Usage and Params +const created = await client.agentic.create('aave-optimiser', { // wallet with one cross-chain rule + rules: [{ // one entry per chain per agent + agent: '0xAgentOnPush', // a Push address: the agent's EOA, or its UEA if the key lives on another chain. Never the owner + chainNamespace: CHAIN.ETHEREUM_SEPOLIA, // foreign chain => universal rulebook + assets: [ + { token: MOVEABLE.TOKEN.ETHEREUM_SEPOLIA.USDC, maxPerCall: parseUnits('100', 6), maxTotal: parseUnits('1000', 6) }, + { token: MOVEABLE.TOKEN.ETHEREUM_SEPOLIA.WETH, maxPerCall: parseUnits('0.5', 18) }, + ], + maxGasPerCall: parseUnits('1', 18), // PC (wei) per outbound for the destination leg + validUntil: now + 30 * 86400, + allowedCalls: [ + { target: aavePool, selector: 'supply(address,uint256,address,uint16)', beneficiary: 2 }, // arg index, not offset: onBehalfOf must be the AGW's CEA + { target: usdcSepolia, selector: 'approve(address,uint256)' }, + ], + }], + progressHook: (p) => console.log(p.id, p.message), // AGENTIC-TX-1xx +}); +const bare = await client.agentic.create('scratch', { rules: [] }); // wallet first, rules later with rules.add +// label string, required shown in list() and info(); the contract stores it +// options.rules Rule[], required one per chain per agent, may be empty; each rule carries its own agent and optional ref +// options.progressHook function, optional progress events, AGENTIC-TX-1xx; default none +// rules[].agent Address, required the Push address allowed to act under this rule; never the owner +// rules[].ref Hex, optional emitted in RulesGranted, not interpreted; default zero +// rules[].assets AssetCap[], required on a universal rule tokens the agent may move, as the other chain's address (MOVEABLE constants); the SDK resolves each to its PRC20 on Push; each cap is { token, maxPerCall, maxTotal? } +// rules[].maxGasPerCall bigint, required on a universal rule PC (wei) the wallet may spend per outbound for the destination leg + +// Returns +// { wallet, index, rulesIds, tx } +{ + wallet: '0x2Fd904d6f2C0b34d58426C8Ae9c5267E845CE98f', + index: 0, + rulesIds: ['0x9c1e...'], // in the order of the rules you passed; empty for rules: [] + tx: { // UniversalTxResponse + hash: '0xb527...', + origin: 'eip155:11155111:0x31dC...', // the owner's key, CAIP-10 + from: '0xFd6C2fE69bE13d8bE379CCB6c9306e74193EC1A9', // the owner's Push account + blockNumber: 1290n, + wait // await tx.wait() for the receipt; status lives on the receipt + } +} +``` + +One rule per chain per agent. A wallet may have different agents on different chains. If an agent needs to act on two chains, `rules` has two entries with the same `agent`; two agents on one chain are two entries with the same `chainNamespace`. Nobody states a rule type; the SDK reads it from `chainNamespace`. `rules: []` is allowed: create the wallet first and grant rules later with `rules.add` (1.k). + +Before asking for a signature the SDK checks that no rule's agent is the owner (`AGENT_IS_OWNER`), that no two rules share both agent and chain (`DUPLICATE_RULE`), that every `allowedCalls[].target` is on the rule's chain (`TARGET_NOT_ON_RULE_CHAIN`), and that every `assets[].token` resolves to a PRC20 whose `SOURCE_CHAIN_NAMESPACE` matches the rule's chain (`ASSET_CHAIN_MISMATCH`). + +Under the hood this is `deployWallet` (or reuse of a derived address) and one `grantRules` per rule. For an external owner they go as one UEA multicall under one signature. Funding is not part of `create`: the wallet is a normal Push account, so send tokens and PC to its address the way you would to any account (1.a shows the address before deployment). + +For a Push EOA owner the same thing needs a batching entry on the factory, because core rejects multicall from a Push-native sender: [1. AGW Contract Changes (nomenclature standard + change set)](https://app.notion.com/p/1-AGW-Contract-Changes-nomenclature-standard-change-set-3e9188aea7f4813aa31fc95ceb4e684d?pvs=21) item 11, **PROPOSED** (`createWallet(label, rules[])` on the factory). Until it lands the SDK sends deploy and grant as separate transactions and says so through progress events (AGENTIC-TX-102 and 104); `tx` is then the last of them. + +A `progressHook` passed to `PushChain.initialize` receives the same events alongside the per-call one, as in core. + +Warning for an agent whose key lives on another chain: the same EVM key initialized against two chains yields two UEAs, because a UEA is derived from namespace, chainId and owner. Grant the rule to the UEA of the chain the agent will run against. `PushChain.utils.account.deriveExecutorAccount(PushChain.utils.account.toUniversal(address, { chain }))` gives it. + +### 1.c List an owner's wallets - `client.agentic.list` + +Lists the wallets owned by the connected signer. It takes no arguments and only reads the connected account. + +```tsx +// Function +const res = await client.agentic.list() + +// Usage and Params +const { wallets } = await client.agentic.list(); // the connected signer's wallets +// no params + +// Returns +// { wallets: Array<{ address, index, label, deployed, rulesCount }> } +{ + wallets: [ + { address: '0x2Fd9...', index: 0, label: 'aave-optimiser', deployed: true, rulesCount: 1 }, + { address: '0x81aB...', index: 1, label: '', deployed: false, rulesCount: 0 }, + ] +} +``` + +Client methods act on the connected account; reads about any other account live in `PushChain.utils`. If a read-only view is needed later (a marketplace or explorer page showing the wallets of an address with no signer), it becomes `PushChain.utils.agentic.wallets(owner: Address)` taking a Push address; an external owner passes its UEA. Not in v1. + +### 1.d Get a wallet handle - `client.agentic.wallet` + +Returns a handle for one wallet: the reads that are specific to an agentic wallet, plus the rule writes only an owner can do. It is not a client and never sends as the wallet. + +```tsx +// Function +const w = client.agentic.wallet(address) + +// Usage and Params +const w = client.agentic.wallet('0xWallet'); // handle for one wallet; nothing is sent +// address Address, required the AGW to manage, a Push address + +// Returns +// { address, info(), owner(), setLabel(), checkpoints(), rules.* } +{ + address: '0xWallet', + info, owner, setLabel, checkpoints, // 1.e to 1.h + rules: { list, get, add, update, revoke } // 1.i to 1.m +} +``` + +There is one way to send as the wallet: `PushChain.initialize(signer, { agenticWallet })` (section 2). The handle only manages. To send as the wallet, move funds, reach the wallet's CEA on another chain, or read balances, initialize with `agenticWallet` and use the normal account tooling: `sendTransaction`, `universal.read`, or viem and ethers against `client.universal.account`. That gives the owner the full `sendTransaction` with every route the SDK already has, the same receipts, and the wallet's CEA reachable exactly as it is for any other account. + +Balance reads are deliberately not on the handle: they are not agentic, and every account is read the same way. There is no `w.execute` for the same reason. The handle stays what its name says: management. + +### 1.e Read wallet info - `w.info` + +Returns the wallet's summary in one read: the fields `list()` shows for each wallet, plus the owner. It is how you read the label from the handle. + +```tsx +// Function +const info = await w.info() + +// Usage and Params +const { label, deployed } = await w.info(); // one wallet's summary +// no params + +// Returns +// { address, label, index, owner, deployed, rulesCount } +{ + address: '0x2Fd904d6f2C0b34d58426C8Ae9c5267E845CE98f', + label: 'aave-optimiser', + index: 0, + owner: '0xFd6C2fE69bE13d8bE379CCB6c9306e74193EC1A9', + deployed: true, + rulesCount: 1 +} +``` + +### 1.f Read the owner - `w.owner` + +Returns the owner's Push address, as the contract stores it. + +```tsx +// Function +const res = await w.owner() + +// Usage and Params +const { owner } = await w.owner(); // the Push address stored as owner +// no params + +// Returns +// { owner } +{ + owner: '0xFd6C2fE69bE13d8bE379CCB6c9306e74193EC1A9' +} +``` + +If the owner is a UEA and you need the controlling origin behind it (the chain and the external key), use `resolveControllerAccount` on the returned address. + +Page rule: identities going in and out of the agentic namespace are Push addresses (owner, agent, wallet). + +### 1.g Set the wallet label - `w.setLabel` + +**PROPOSED**, contract change, see [1. AGW Contract Changes (nomenclature standard + change set)](https://app.notion.com/p/1-AGW-Contract-Changes-nomenclature-standard-change-set-3e9188aea7f4813aa31fc95ceb4e684d?pvs=21) item 10. Changes the label shown in `list()` and `info()`; owner only. + +```tsx +// Function +const tx = await w.setLabel(label, { options? }) + +// Usage and Params +const tx = await w.setLabel('aave-optimiser-v2'); // rename the wallet +const tracked = await w.setLabel('aave-optimiser-v2', { progressHook: (p) => console.log(p.id) }); // with progress events +// label string, required the new label; stored by the contract and emitted in LabelSet +// options.progressHook function, optional progress events, AGENTIC-TX-106; default none + +// Returns +// { hash, origin, from, to, blockNumber, wait() } +{ + hash: '0x3b8d...', + origin: 'eip155:11155111:0x31dC...', // the owner's key, CAIP-10 + from: '0xFd6C2fE69bE13d8bE379CCB6c9306e74193EC1A9', // the owner's Push account + to: '0x2Fd904d6f2C0b34d58426C8Ae9c5267E845CE98f', // the wallet + blockNumber: 1488n, + wait // await tx.wait() for the receipt; status lives on the receipt +} +``` + +Emits `LabelSet(string label)`. It is not a checkpoint: the label is cosmetic metadata and evaluators ignore it. Today the label can only be set once, at `deployWallet`, and is emitted in `WalletDeployed`. + +### 1.h Read checkpoints - `w.checkpoints` + +Every owner-side change the wallet has recorded: owner-door sends, rules granted, rules revoked. An evaluator reads these to know whether the owner changed anything after a job started (page 4). + +```tsx +// Function +const res = await w.checkpoints({ options? }) + +// Usage and Params +const all = await w.checkpoints(); // every checkpoint +const recent = await w.checkpoints({ sinceBlock: 1234n }); // from a block onward +// options.sinceBlock bigint, optional only checkpoints at or after this block; default all + +// Returns +// { checkpoints: Array<{ seq, kind, ref, blockNumber, txHash }> } +{ + checkpoints: [ + { seq: 3, kind: 'RULES_GRANTED', ref: '0x9c1e...', blockNumber: 1290n, txHash: '0x...' }, + { seq: 4, kind: 'OWNER_ACTION', ref: '0x5a7b...', blockNumber: 1402n, txHash: '0x...' }, + ] +} +``` + +### 1.i List rules - `w.rules.list` + +Returns every rule on the wallet as a decoded record, including what each rule has spent so far. + +```tsx +// Function +const res = await w.rules.list() + +// Usage and Params +const { rules } = await w.rules.list(); // the wallet's rules +// no params + +// Returns +// { rules: RulesRecord[] } +{ + rules: [ + { + rulesId: '0x9c1e...', + enabled: true, + chainNamespace: 'eip155:11155111', + agent: '0xAgentOnPush', + validUntil: 1767225600, + ref: '0x4a2f...', + rule: { /* decoded UniversalRule, as passed to create */ }, + spent: { kind: 'universal', amountSpent: 25000000n } // shape PROPOSED, see 3.b + } + ] +} +``` + +### 1.j Get one rule - `w.rules.get` + +Returns one rule by id, decoded, with what it has spent. + +```tsx +// Function +const record = await w.rules.get(rulesId) + +// Usage and Params +const record = await w.rules.get('0x9c1e...'); // one rule by id +// rulesId Hex, required the id returned by create or rules.add + +// Returns +// RulesRecord +{ + rulesId: '0x9c1e...', + enabled: true, + chainNamespace: 'eip155:11155111', + agent: '0xAgentOnPush', + validUntil: 1767225600, + ref: '0x4a2f...', + rule: { /* decoded UniversalRule */ }, + spent: { kind: 'universal', amountSpent: 25000000n } // shape PROPOSED, see 3.b +} +``` + +`spent` is a field on the record, so `get` and `list` both carry it. There is no separate spent call. + +### 1.k Add rules - `w.rules.add` + +Grants new rules on an existing wallet under one signature. The rules array comes first; `agent` and `ref` live on each rule. + +```tsx +// Function +const res = await w.rules.add(rules, { options? }) + +// Usage and Params +const one = await w.rules.add([nativeRule]); // one rule +const many = await w.rules.add([ruleOnSepolia, ruleOnPush]); // several rules, one signature +const tracked = await w.rules.add([nativeRule], { progressHook: (p) => console.log(p.id, p.message) }); // with progress events +// rules Rule[], required one per chain per agent; each rule carries its own agent and optional ref +// options.progressHook function, optional progress events, AGENTIC-TX-104; default none + +// Returns +// { rulesIds, tx } +{ + rulesIds: ['0x7d3a...'], // in the order of the rules you passed + tx: { // UniversalTxResponse + hash: '0x4c19...', + origin: 'eip155:11155111:0x31dC...', + from: '0xFd6C2fE69bE13d8bE379CCB6c9306e74193EC1A9', + blockNumber: 1501n, + wait + } +} +``` + +Records a `RULES_GRANTED` checkpoint. + +### 1.l Update rules - `w.rules.update` + +Replaces rules in a batch: each pair names one old rule and the one new rule that takes its place. + +```tsx +// Function +const res = await w.rules.update({ rules, progressHook? }) + +// Usage and Params +const one = await w.rules.update({ rules: [{ rulesId: '0x9c1e...', rule: newRule }] }); // replace one rule +const many = await w.rules.update({ rules: [{ rulesId: idA, rule: ruleA }, { rulesId: idB, rule: ruleB }] }); // replace several, one signature +const tracked = await w.rules.update({ rules: [{ rulesId: idA, rule: ruleA }], progressHook: (p) => console.log(p.id) }); // with progress events +// rules Array<{ rulesId, rule }>, required one old rule to one new rule per pair +// rules[].rulesId Hex, required the rule being replaced +// rules[].rule Rule, required the replacement; one rule per agent per chain still applies +// progressHook function, optional progress events, AGENTIC-TX-105 and 104; default none + +// Returns +// { rules: Array<{ rulesId, replaced }>, tx } +{ + rules: [ + { rulesId: '0x51c0...', replaced: '0x9c1e...' }, // new id, old id + ], + tx: { // UniversalTxResponse + hash: '0x7a02...', + origin: 'eip155:11155111:0x31dC...', + from: '0xFd6C2fE69bE13d8bE379CCB6c9306e74193EC1A9', + blockNumber: 1507n, + wait + } +} +``` + +Rules are immutable on-chain, so an update is a revoke plus a grant: for each pair the SDK asserts the old rule's spend, revokes it and grants the new one, all pairs in one multicall. The result is a new `rulesId` per pair, and the spend counters reset on the new rule: what the old rule had spent does not carry over. This is accepted for v1 (open item 1); an in-place update would be a contract change and there is no demand for it yet. + +### 1.m Revoke rules - `w.rules.revoke` + +Revokes some rules by id, or all of them in one atomic call. + +```tsx +// Function +const tx = await w.rules.revoke(rulesIds, { options? }) +const tx = await w.rules.revoke({ all, progressHook? }) + +// Usage and Params +const some = await w.rules.revoke(['0x9c1e...', '0x7d3a...']); // revoke these rules +const all = await w.rules.revoke({ all: true }); // revoke every rule, on-chain revokeAllRules +const tracked = await w.rules.revoke(['0x9c1e...'], { progressHook: (p) => console.log(p.id) }); // with progress events +// rulesIds Hex[], required unless all is set the rules to revoke +// options.progressHook function, optional progress events, AGENTIC-TX-105; default none +// all true, required unless rulesIds given revoke every rule on the wallet in one atomic call +// progressHook function, optional same events, in the { all: true } form; default none + +// Returns +// { hash, origin, from, to, blockNumber, wait() } +{ + hash: '0x8e01...', + origin: 'eip155:11155111:0x31dC...', // the owner's key, CAIP-10 + from: '0xFd6C2fE69bE13d8bE379CCB6c9306e74193EC1A9', // the owner's Push account + to: '0x2Fd904d6f2C0b34d58426C8Ae9c5267E845CE98f', // the wallet + blockNumber: 1512n, + wait // await tx.wait() for the receipt; status lives on the receipt +} +``` + +A bare `revoke()` is not allowed and throws `REVOKE_NEEDS_TARGET`: a call with no argument that wipes every rule is too easy to make by mistake. Records `RULES_REVOKED` checkpoints. + +# 2. Agent side, by example + +There is no new method on the agent side. The agent uses its own signer and tells `initialize` which wallet to act through. It does not name a rule: which rule applies is decided per transaction, from the destination chain. + +### 2.a Act as the wallet - `PushChain.initialize` with `agenticWallet` (updated) + +Returns a client whose account is the wallet. Whether its sends go through the owner door or the agent door depends on who the signer is. + +```tsx +// Function +const client = await PushChain.initialize(signer, { options }) + +// Usage and Params +const agentClient = await PushChain.initialize(agentSigner, { // agent door: the signer is named as agent in a rule + network: PushChain.CONSTANTS.PUSH_NETWORK.TESTNET, + agenticWallet: '0xWallet', +}); +const ownerClient = await PushChain.initialize(ownerSigner, { // owner door: the signer owns the wallet + network: PushChain.CONSTANTS.PUSH_NETWORK.TESTNET, + agenticWallet: '0xWallet', +}); +``` + +`agentSigner` is any signer `initialize` accepts today. If the key lives on another chain, the SDK derives its UEA and everything goes through that, as it does for every external user. + +Which door the client uses depends on who the signer is. If the signer is the wallet's owner, sends go through the owner door: no rules, and every send is recorded as a checkpoint. If the signer is an address named as agent in one of the wallet's rules, sends go through the agent door and the rules apply. If it is neither, `initialize` throws `NOT_OWNER_OR_AGENT`. If the address has no wallet deployed yet it throws `WALLET_NOT_DEPLOYED`, and if the address is not an agentic wallet it throws `NOT_AGENTIC_WALLET`. This is also how an owner acts as the wallet with the full client: `PushChain.initialize(ownerSigner, { agenticWallet })`. There is one way to send as a wallet and the signer decides the door. + +On the agent door the SDK sends; URP on-chain is the only rule checker. Before sending, the SDK only looks up the `rulesId` for the destination chain: the rule that is enabled, whose `agent` equals the signer, and whose `chainNamespace` equals the destination. The lookup is one read on every send, not cached at initialize. If none is found it throws `NO_RULES_FOR_CHAIN` before any signature, so it costs nothing; otherwise it calls `executeAsAgent(rulesId, ...)` on the wallet. That is the agent door from D3 on [1. AGW Contract Changes (nomenclature standard + change set)](https://app.notion.com/p/1-AGW-Contract-Changes-nomenclature-standard-change-set-3e9188aea7f4813aa31fc95ceb4e684d?pvs=21): there is no session validator, and the wallet only checks that `msg.sender` is the rule's agent. There is one rule per (agent, chain), so a signer and a destination match at most one rule. If the action breaks a rule, it reverts on-chain and the agent pays that gas. `sendTransaction` then throws `AgenticRevertError`, which extends core's `PushChainExecutionError` and carries URP's custom error in `decodedError`, so the agent sees which gate failed (3.f). + +From an external key, the call arrives through the agent's UEA. If the agent's UEA is not yet deployed, the first action takes the origin-chain fee lock once (minimum $1), which deploys the UEA and funds it with PC. Every later action requires PC in the UEA and is a direct Push transaction paid from that balance, with no origin transaction and no cross-chain wait. + +Two things for whoever runs the agent. The agent's UEA is a second balance to keep funded: the AGW's PC covers the wallet's outbound fees, not the agent's gas. And in `agenticWallet` mode the SDK turns `enforceGasCheck` on for every action except that one first action while the agent's UEA is not yet deployed, so an empty UEA fails loudly instead of silently falling back to a $1 origin lock and a confirmation wait on every action. + +Routing. In `agenticWallet` mode every send is wrapped as `executeAsAgent` (agent door) or `execute` (owner door), and for cross-chain legs the AGW itself calls the gateway. So the AGW's CEA executes on the destination and the AGW's PC pays as `msg.value`. The SDK never uses the signer's own Route 2, which would run through the agent's CEA instead of the wallet's. Any `from` (Routes 3 and 4) is rejected in `agenticWallet` mode with `FROM_NOT_ALLOWED`: it makes `msg.sender` a CEA, and the agent door check fails. + +What changes on the client in this mode: + +- `universal.account` is the wallet address string, so receipts show the AGW as `from`. `universal.origin` stays the signer's origin account. +- `getAccountStatus()` reports the signer's own UEA, not the wallet. +- The signer is whatever was passed to `initialize`. To top up the agent's UEA, find it with `PushChain.utils.account.deriveExecutorAccount(signer.account)` and send PC to it from a client initialized without `agenticWallet`. +- A Solana-keyed agent can act on Push and `eip155` destinations now, and on `solana:` destinations once the SVM rulebook ships. +- Agents read their own rules through `client.agentic.wallet(addr).rules.list()`. +- `tx.data` arrays and `tx.funds` (moving the AGW's PRC20) work as they do for any account. +- `payGasWith`, `migrateCEA`, `rescueFunds`, `prepareTransaction` and `executeTransactions` throw `NOT_ALLOWED_IN_AGENTIC_MODE`. + +```tsx +const tx = await agentClient.universal.sendTransaction({ // agent door, rule picked by the destination chain + to: { address: aavePool, chain: CHAIN.ETHEREUM_SEPOLIA }, + data: supplyData, +}); + +// tx: UniversalTxResponse +{ + hash: '0x6f2a...', + origin: 'eip155:11155111:0x7Be1...', // the agent's key, CAIP-10 + from: '0xWallet', // the AGW, not the signer + blockNumber: 1530n, + wait +} + +const receipt = await tx.wait(); +// receipt: UniversalTxReceipt +{ + status: 1, + hash: '0x6f2a...', + from: '0xWallet', + blockNumber: 1530n, + externalTxHash: '0x91c4...' // the leg executed by the AGW's CEA on Sepolia +} +``` + +The same EVM key initialized against two chains yields two UEAs (derived from namespace, chainId and owner), so the rule must name the UEA of the chain this client initializes against (see 1.b). + +# 3. Types + +### 3.a Client, options and namespace + +```tsx +type Address = `0x${string}`; +type Hex = `0x${string}`; +type ForeignChainNamespace = `eip155:${string}` | `solana:${string}`; +type ProgressHook = (p: ProgressEvent) => void; // ProgressEvent is core's shape: { id, title, message, level, response, timestamp } + +interface PushChainClient { + universal: UniversalNamespace; // in agenticWallet mode: account is the wallet + agentic: AgenticNamespace; // this page + market: MarketNamespace; // page 6 + job: JobNamespace; // page 7 + evaluation: EvaluationNamespace; // page 8 +} + +interface InitializeOptions { + network?: PUSH_NETWORK; + rpcUrls?: Partial>; + agenticWallet?: Address; // NEW: act as the wallet; door chosen by the signer's Push address + // enforceGasCheck is on when agenticWallet is set, except for the first action while the agent's UEA is not yet deployed (2.a) +} + +interface AgenticNamespace { + derive(opts?: { index?: number }): Promise<{ address: Address; index: number; deployed: boolean }>; + create(label: string, options: CreateOptions): Promise; + list(): Promise<{ wallets: WalletSummary[] }>; // connected signer only + wallet(address: Address): AgenticWallet; +} + +interface CreateOptions { + rules: Rule[]; // one entry per chain per agent, may be empty; each rule names its agent and optional ref + progressHook?: ProgressHook; // AGENTIC-TX-1xx +} + +// No AgentKey type, no curve, no chain. The agent is a Push address. A native key is its own EOA; any external key +// (EVM, Solana, anything) is its UEA, deterministic from (chain, owner), deployed lazily on first use. The AGW's agent +// door checks msg.sender == rules.agent; cross-VM signature verification already happened inside the UEA (page 1, D3). + +interface CreateResult { wallet: Address; index: number; rulesIds: Hex[]; tx: UniversalTxResponse } +interface WalletSummary { address: Address; index: number; label: string; deployed: boolean; rulesCount: number } +``` + +### 3.b Rules + +```tsx +type Rule = NativeRule | UniversalRule; // chainNamespace decides the rulebook: omitted = native, foreign = universal + +interface NativeRule { + agent: Address; // Push address: EOA, or the UEA of an external key (PushChain.utils.account.deriveExecutorAccount) + ref?: Hex; // emitted in RulesGranted, not interpreted + chainNamespace?: never; // omitted = the connected Push chain + target: Address; + selector: Selector | 'value-only'; + validUntil: number; + maxValuePerCall?: bigint; maxValueTotal?: bigint; maxCalls?: number; + pins?: { arg: number; expected: Hex | Address | bigint }[]; + amount?: { arg: number; maxPerCall: bigint; maxTotal?: bigint }; +} + +interface UniversalRule { + agent: Address; // same as NativeRule.agent + ref?: Hex; // same as NativeRule.ref + chainNamespace: ForeignChainNamespace; // "eip155:..." now; "solana:..." once the SVM rulebook ships + assets: AssetCap[]; // tokens the agent may move on chainNamespace; SDK resolves each to its PRC20 and asserts SOURCE_CHAIN_NAMESPACE + maxGasPerCall: bigint; // PC (wei) per outbound for the destination leg + validUntil: number; + allowedCalls: AllowedCall[]; // 1..32, all on chainNamespace +} + +interface AssetCap { + token: MoveableToken | Address; // the other chain's token address (MOVEABLE.TOKEN..) or the native marker; the contract stores the PRC20 + maxPerCall: bigint; + maxTotal?: bigint; +} + +type Selector = Hex | `${string}(${string})`; // '0x617ba037' or 'supply(address,uint256,address,uint16)' + +interface AllowedCall { target: Address; selector: Selector; beneficiary?: number; maxValue?: bigint } // beneficiary = arg index + +interface RulesRecord { + rulesId: Hex; + enabled: boolean; + chainNamespace: string; + agent: Address; // the Push address granted + validUntil: number; + ref: Hex; + rule: Rule; // decoded terms; NativeRule or UniversalRule + spent: Spent; // carried by rules.get and rules.list; no separate call +} + +type Spent = { kind: 'universal'; amountSpent: bigint } | { kind: 'native'; valueSpent: bigint; amountSpent: bigint; callsUsed: number }; // PROPOSED: one self-describing object, readable without knowing the rulebook +``` + +### 3.c Wallet handle and checkpoints + +```tsx +interface AgenticWallet { + address: Address; + info(): Promise; + owner(): Promise<{ owner: Address }>; // Push address as stored + setLabel(label: string, opts?: { progressHook?: ProgressHook }): Promise; // PROPOSED, page 1 item 10 + checkpoints(opts?: { sinceBlock?: bigint }): Promise<{ checkpoints: Checkpoint[] }>; + rules: { + list(): Promise<{ rules: RulesRecord[] }>; + get(rulesId: Hex): Promise; + add(rules: Rule[], opts?: { progressHook?: ProgressHook }): Promise<{ rulesIds: Hex[]; tx: UniversalTxResponse }>; + update(params: { rules: { rulesId: Hex; rule: Rule }[]; progressHook?: ProgressHook }): Promise<{ rules: { rulesId: Hex; replaced: Hex }[]; tx: UniversalTxResponse }>; // revoke plus grant; spend counters reset + revoke(rulesIds: Hex[], opts?: { progressHook?: ProgressHook }): Promise; + revoke(params: { all: true; progressHook?: ProgressHook }): Promise; + }; +} + +interface WalletInfo { address: Address; label: string; index: number; owner: Address; deployed: boolean; rulesCount: number } + +interface Checkpoint { seq: number; kind: 'OWNER_ACTION' | 'RULES_GRANTED' | 'RULES_REVOKED'; ref: Hex; blockNumber: bigint; txHash: Hex } +``` + +### ~~3.d Constants, PushChain.CONSTANTS.AGENTIC (new)~~ + +Dropped on 12 Oct 2026, except `WALLET`. See 6.h. + +```tsx +PushChain.CONSTANTS.AGENTIC[PUSH_NETWORK.TESTNET_DONUT] = { + FACTORY, RULES_POLICY, // RULES_POLICY is URP; no validator address (page 1, D3) + MAX_PINS: 8, MAX_ALLOWED_CALLS: 32, ENVELOPE_VERSION: 1, +}; +``` + +### ~~3.e Helpers, PushChain.utils.agentic (new)~~ + +Dropped on 12 Oct 2026. See 6.h. + +~~Pure functions with the same output as the on-chain views.~~ + +```tsx +PushChain.utils.agentic = { + rulesId(agent, chainNamespace, grantNonce), // the id a grant produces, same as the contract assigns + actionId(target, selector), // id of one allowed call: hash of its target and selector + configId(wallet, rulesId, actionId), // key of one allowed call's stored config, under one rule on one wallet + encodeRules(rules, ctx), // ctx = wallet and chain context needed to resolve beneficiary offsets + decodeRules(bytes), + deriveWallet(owner, index), // any-owner variant of client.agentic.derive + compileCard(card, userInput, ctx), // used by page 6; lives here because it produces Rule[] +}; +``` + +### 3.f Errors and progress + +```tsx +class AgenticError extends Error { code: string; hint?: string } +class AgenticRevertError extends PushChainExecutionError {} +// decoded custom error from the AGW, URP or the factory; uses core's fields: +// code string +// decodedError { name, hint, selector, decoded } + +// codes +// create: AGENT_IS_OWNER, DUPLICATE_RULE, TARGET_NOT_ON_RULE_CHAIN, ASSET_CHAIN_MISMATCH +// initialize (agenticWallet): NOT_OWNER_OR_AGENT, WALLET_NOT_DEPLOYED, NOT_AGENTIC_WALLET +// rules.revoke: REVOKE_NEEDS_TARGET (bare revoke) +// sendTransaction: NO_RULES_FOR_CHAIN, FROM_NOT_ALLOWED (any from, Routes 3 and 4) +// agentic mode: NOT_ALLOWED_IN_AGENTIC_MODE (prepareTransaction, executeTransactions, payGasWith, migrateCEA, rescueFunds) + +// progress events, AGENTIC-TX (PROPOSED) +// AGENTIC-TX-101 wallet derived { address, index, deployed } +// AGENTIC-TX-102 deploy step added +// AGENTIC-TX-104 rules granted { rulesIds } +// AGENTIC-TX-105 rules revoked { rulesIds | all } +// AGENTIC-TX-106 label set +// AGENTIC-TX-107 rule resolved for a send { rulesId, chainNamespace, door } +// AGENTIC-TX-199-01 done +// AGENTIC-TX-199-02 failed { code, decodedError } +// The Push leg of any agentic send also emits core's SEND-TX-1xx events. +// A cross-chain leg sent by the AGW emits 209-xx and 299-xx, never 201 to 204 (the signer's own Route 2 is never used). +``` + +**PROPOSED:** the AGENTIC-TX event list. Every write (`create`, `setLabel`, `rules.add`, `rules.update`, `rules.revoke`) takes a per-call `progressHook`; a `progressHook` passed to `PushChain.initialize` runs alongside it, as in core. + +`NO_RULES_FOR_CHAIN` is thrown before any signature and costs nothing. The rules lookup is one read on every send, not cached at initialize. A URP revert is thrown from `sendTransaction` as `AgenticRevertError` and also lands as `decodedError` on AGENTIC-TX-199-02. A destination-chain revert after URP passed still counts the spend, because the spend is counted when the outbound leaves Push; whether it is credited back depends on [1. AGW Contract Changes (nomenclature standard + change set)](https://app.notion.com/p/1-AGW-Contract-Changes-nomenclature-standard-change-set-3e9188aea7f4813aa31fc95ceb4e684d?pvs=21) item 6 (`creditRevert`). + +# 4. Outside change: [PushChain.CONSTANTS.READ](http://PushChain.CONSTANTS.READ).CHAIN (confirmed 2026-09-28) + +Problem: `read()` takes `chain: PushChain.CONSTANTS.CHAIN.X`, but `CHAIN` is the set of blockchains the SDK signs for and routes to. Web2 is not one, so `CHAIN.WEB2` exists as a hidden (non-enumerable) member: it works if you know it is there and never appears in any listing. Reads have a wider domain than transactions: anything validators can observe. + +Change: a read-specific constant that is a superset of `CHAIN`. The field name stays `chain`, so nothing breaks, and `CHAIN` values remain valid because the strings are identical. + +```tsx +PushChain.CONSTANTS.READ.CHAIN = { + ...PushChain.CONSTANTS.CHAIN, // every real chain, same string values + WEB2: 'web2', // non-chain source, first-class here, enumerable +}; +type ReadChain = CHAIN | 'web2'; // ReadParams.chain: ReadChain + +read({ chain: PushChain.CONSTANTS.READ.CHAIN.WEB2, ... }) +read({ chain: PushChain.CONSTANTS.CHAIN.ETHEREUM_SEPOLIA, ... }) // still compiles +``` + +- `CHAIN.WEB2` becomes a deprecated alias of `READ.CHAIN.WEB2` for one release (the docs listed it on 2026-09-22), then goes. +- Anything that iterates `CHAIN` stops seeing a fake chain; anything that iterates `READ.CHAIN` sees every read source. +- The evaluator's `Read.chain` (page 8) takes the same values, so `READ.CHAIN` is the one constant the read SDK and the criteria compiler share. + +# 5. Open for review + +1. `rules.update` resets spend counters because it is revoke plus grant. Accepted for v1 and stated in 1.l; an in-place update is a contract change with no demand yet. +2. `setLabel` assumes [1. AGW Contract Changes (nomenclature standard + change set)](https://app.notion.com/p/1-AGW-Contract-Changes-nomenclature-standard-change-set-3e9188aea7f4813aa31fc95ceb4e684d?pvs=21) item 10 lands. Pointer for the team. + +# 6. Changes proposed on 12 Oct 2026 + +These come from the review of the first SDK implementation, [push-chain-sdk PR #291](https://github.com/pushchain/push-chain-sdk/pull/291). Sections 1 to 5 above are left exactly as they were. Where an entry here differs from them, the entry here is the current one. Every function whose call or result changes is written out again in full, so the change can be read without scrolling up. + +Contract changes are written on [1. AGW Contract Changes (nomenclature standard + change set)](https://app.notion.com/p/1-AGW-Contract-Changes-nomenclature-standard-change-set-3e9188aea7f4813aa31fc95ceb4e684d?pvs=21) (page 1), section 6, and are referenced from here by item number. + +| # | Change | Replaces above | Contract change (page 1) | +| --- | --- | --- | --- | +| 6.a | One rule shape for every chain, pins inside `allowedCalls`, `beneficiary` folded into pins | 3.b `NativeRule`, `UniversalRule` | 6.3 | +| 6.b | `create` is one transaction for every owner; `ref` removed; omitted caps are 0 | 1.b | 6.2, 6.4, 6.5 | +| 6.c, 6.d | `rules.list` and `rules.get`: `spent` per asset, no `ref`, arguments read back as `arg` | 1.i, 1.j | none | +| 6.e | `rules.add` and `rules.update`: call unchanged, new rule shape | 1.k, 1.l | none | +| 6.f | `setLabel` is never a checkpoint | 1.g | none | +| 6.g | Sending as the wallet: no gateway approval step, first-use gas default | 2.a | 6.1 | +| 6.h | Types, as they end up | 3.b, `RulesRecord`, `Spent`, 3.d, 3.e | none | +| 6.i | Solana: same rule shape, pins on arguments and on accounts, no IDL in a rule | new | none | +| 6.l | Response fields and error codes added by the first implementation: accepted, with four codes removed | 3.f | none | +| 6.m | `rules.revoke` is renamed `rules.delete` | 1.m | none | + +### 6.a One rule shape for every chain + +There is one rule shape. A rule for calls on Push is the same object as a cross-chain rule with `chainNamespace` left out. What the agent may call is always a list of `allowedCalls`, and restrictions on a function's arguments sit inside each allowed call as `pins`. + +A pin restricts one argument of the allowed function. It is either `expected` (the argument must equal this constant) or `max` (the argument must not exceed this number). To require that an argument is the wallet itself, the expected value is `PushChain.CONSTANTS.AGENTIC.WALLET`. A minimum on an argument (for example a minimum amount out on a swap) is not part of v1 and is deferred to the next version. + +```tsx +// a rule on Push: chainNamespace left out +{ + agent: '0xAgentOnPush', + validUntil: now + 30 * 86400, + allowedCalls: [ + { target: vault, selector: 'deposit(address,uint256)', + pins: [ + { arg: 0, expected: beneficiary }, // argument 0 must be this address + { arg: 1, max: parseUnits('10', 18) }, // argument 1 must not exceed this, per call + ] }, + ], +} + +// a rule on Ethereum Sepolia: same shape, plus the tokens the agent may move +{ + agent: '0xAgentOnPush', + chainNamespace: CHAIN.ETHEREUM_SEPOLIA, + assets: [ + { token: MOVEABLE.TOKEN.ETHEREUM_SEPOLIA.USDC, maxPerCall: parseUnits('100', 6), maxTotal: parseUnits('1000', 6) }, + ], + maxGasPerCall: parseUnits('1', 18), + validUntil: now + 30 * 86400, + allowedCalls: [ + { target: aavePool, selector: 'supply(address,uint256,address,uint16)', + pins: [ + { arg: 0, expected: usdcSepolia }, // asset must be USDC + { arg: 2, expected: PushChain.CONSTANTS.AGENTIC.WALLET }, // onBehalfOf must be this wallet + ] }, + { target: usdcSepolia, selector: 'approve(address,uint256)' }, + ], +} +``` + +What is gone from the shape: the separate `NativeRule` type with `target`, `selector`, `pins` and `amount` at the top of the rule, and the fields `amount.maxTotal`, `maxValueTotal` and `maxCalls`. A `max` pin limits each call only. The SDK has no per-argument lifetime total and no call counter. On a cross-chain rule the lifetime limit on a token is the asset's `maxTotal`. On a Push call the lifetime limit is what the owner funds the wallet with, plus `validUntil`. + +`beneficiary` is now a pin. On page sections above, `beneficiary: 2` meant that argument 2 must be the wallet's own account. That is a pin whose expected value is the wallet, so it is written as `{ arg: 2, expected: PushChain.CONSTANTS.AGENTIC.WALLET }` and the separate field is removed. `WALLET` stands for the wallet's own account on the rule's chain: the AGW address for a call on Push, and the wallet's CEA for a call on another chain. The SDK fills in the real address when the rule is granted, so nobody has to look up a CEA. It is a marker and not an address (its value is the string `'agentic:wallet'`), because an agent card lists its rules before any wallet exists. On read, a pin whose stored value is the wallet's own account comes back as `WALLET`. + +Where each part is checked. Every check runs on Push, in the rules policy, before the wallet is allowed to make the call or hand it to the gateway. + +| On an allowed call | Call on Push | Call on an EVM destination | +| --- | --- | --- | +| `target`, `selector`, `maxValue` | Checked | Checked | +| A pin with `expected: WALLET` | Checked | Checked. One per call until page 1, 6.3 lands | +| Any other pin | Checked. Up to 8 `expected` pins and one `max` pin per call | Needs page 1, 6.3. Until it lands the SDK rejects it before signing | + +### 6.b Create an agentic wallet - `client.agentic.create` (changed) + +Deploys the wallet and grants the rules in one transaction, for every kind of owner. Either the wallet exists with every rule that was passed, or nothing happened. + +```tsx +// Function +const created = await client.agentic.create(label, { options }) + +// Usage and Params +const created = await client.agentic.create('aave-optimiser', { // wallet with one cross-chain rule + rules: [{ // one entry per chain per agent + agent: '0xAgentOnPush', // a Push address: the agent's EOA, or its UEA if the key lives on another chain. Never the owner + chainNamespace: CHAIN.ETHEREUM_SEPOLIA, // left out = a rule for calls on Push + assets: [ + { token: MOVEABLE.TOKEN.ETHEREUM_SEPOLIA.USDC, maxPerCall: parseUnits('100', 6), maxTotal: parseUnits('1000', 6) }, + { token: MOVEABLE.TOKEN.ETHEREUM_SEPOLIA.WETH, maxPerCall: parseUnits('0.5', 18), maxTotal: parseUnits('2', 18) }, + ], + maxGasPerCall: parseUnits('1', 18), // PC (wei) per outbound for the destination leg + validUntil: now + 30 * 86400, + allowedCalls: [ + { target: aavePool, selector: 'supply(address,uint256,address,uint16)', + pins: [{ arg: 2, expected: PushChain.CONSTANTS.AGENTIC.WALLET }] }, // onBehalfOf must be this wallet (its CEA on Sepolia) + { target: usdcSepolia, selector: 'approve(address,uint256)' }, + ], + }], + progressHook: (p) => console.log(p.id, p.message), // AGENTIC-TX-1xx +}); +const bare = await client.agentic.create('scratch', { rules: [] }); // wallet first, rules later with rules.add +// label string, required shown in list() and info(); the contract stores it +// options.rules Rule[], required one per chain per agent, may be empty; shape in 6.a +// options.progressHook function, optional progress events, AGENTIC-TX-1xx; default none +// rules[].agent Address, required the Push address allowed to act under this rule; never the owner +// rules[].chainNamespace string, optional the chain the rule governs; left out = Push +// rules[].assets AssetCap[], cross-chain rules tokens the agent may move; each cap is { token, maxPerCall, maxTotal } +// rules[].assets[].maxTotal bigint, optional lifetime cap for that token; left out = 0, and 0 means the agent cannot move it +// rules[].maxGasPerCall bigint, cross-chain rules PC (wei) the wallet may spend per outbound for the destination leg +// rules[].allowedCalls AllowedCall[], required what the agent may call; each is { target, selector, pins?, maxValue? } +// rules[].allowedCalls[].maxValue bigint, optional native coin per call; left out = 0 +// rules[].allowedCalls[].pins Pin[], optional { arg, expected } or { arg, max }; expected may be PushChain.CONSTANTS.AGENTIC.WALLET; see 6.a + +// Returns +// { wallet, index, rulesIds, tx } +{ + wallet: '0x2Fd904d6f2C0b34d58426C8Ae9c5267E845CE98f', + index: 0, + rulesIds: ['0x9c1e...'], // in the order of the rules you passed; empty for rules: [] + tx: { // UniversalTxResponse, always a single transaction + hash: '0xb527...', + origin: 'eip155:11155111:0x31dC...', // the owner's key, CAIP-10 + from: '0xFd6C2fE69bE13d8bE379CCB6c9306e74193EC1A9', // the owner's Push account + blockNumber: 1290n, + wait // await tx.wait() for the receipt; status lives on the receipt + } +} +``` + +What changed from 1.b: + +- **One transaction for every owner.** 1.b said a Push EOA owner gets separate deploy and grant transactions until a factory entry lands. That fallback is removed. The factory entry is page 1, 6.2. There is no partial result to reconcile. +- **`ref` is removed** from every rule. The `rulesId` the grant returns is what a job, a card or an indexer latches on to. Page 1, 6.4. +- **A cap that is left out is 0, never unlimited.** That covers `assets[].maxTotal` and `allowedCalls[].maxValue`. A forgotten cap means the agent cannot move that asset, which shows up on the first send. Page 1, 6.5. Note that the WETH line in 1.b had no `maxTotal`; under this rule it would move nothing, so the example here sets one. +- **Rules use the single shape from 6.a.** +- **The beneficiary field is a pin.** `beneficiary: 2` is written as a pin on argument 2 whose expected value is `PushChain.CONSTANTS.AGENTIC.WALLET` (6.a). + +### 6.c List rules - `w.rules.list` (changed) + +Returns every enabled rule on the wallet as a decoded record, including what each rule has spent so far. + +```tsx +// Function +const res = await w.rules.list() + +// Usage and Params +const { rules } = await w.rules.list(); // the wallet's rules +// no params + +// Returns +// { rules: RulesRecord[] } +{ + rules: [ + { + rulesId: '0x9c1e...', + enabled: true, + chainNamespace: 'eip155:11155111', + agent: '0xAgentOnPush', + validUntil: 1767225600, + rule: { /* the rule in the 6.a shape, accepted as is by rules.update */ }, + spent: { // one entry per asset, same order as rule.assets + kind: 'universal', + assets: [ + { token: '0x1c7D...7238', spent: 25000000n }, // USDC + { token: '0xfFf9...6B14', spent: 0n }, // WETH + ] + } + } + ] +} +``` + +### 6.d Get one rule - `w.rules.get` (changed) + +Returns one rule by id, decoded, with what it has spent. + +```tsx +// Function +const record = await w.rules.get(rulesId) + +// Usage and Params +const record = await w.rules.get('0x9c1e...'); // one rule by id +// rulesId Hex, required the id returned by create or rules.add + +// Returns +// RulesRecord +{ + rulesId: '0x51c0...', + enabled: true, + chainNamespace: 'eip155:42101', // a rule on Push + agent: '0xAgentOnPush', + validUntil: 1767225600, + rule: { + agent: '0xAgentOnPush', + validUntil: 1767225600, + allowedCalls: [ + { target: '0xVault', selector: 'deposit(address,uint256)', + pins: [ + { arg: 0, expected: '0x00000000000000000000000000000000000000000000000000000000000b0b0b' }, + { arg: 1, max: 10000000000000000000n }, + ] }, + ], + }, + spent: { kind: 'native', valueSpent: 0n, amountSpent: 5000000000000000000n, callsUsed: 1 } +} +``` + +What changed from 1.i and 1.j: + +- **`spent` is on every record**, as 1.i and 1.j already said. The first implementation dropped it; it goes back. For a cross-chain rule it is now a list with one entry per asset, because each asset has its own budget. 1.i showed a single `amountSpent`, which predates per-asset budgets. +- **`ref` is removed** from the record, following 6.b. +- **Arguments read back as `arg`, never as a byte offset.** The contract stores a pin and a beneficiary as a byte position in the calldata (argument 0 is byte 4, argument 1 is byte 36). The SDK converts that back, so a developer who wrote `arg: 0` reads `arg: 0`. A pin on the wallet itself reads back as `WALLET`. +- **The record is accepted by `rules.update` without edits.** The test is: read a rule, change `validUntil`, pass it back. An `expected` value reads back as 32-byte hex, because the contract keeps the function selector and not the argument types; it is accepted as input in that form. + +### 6.e Add and update rules - `w.rules.add`, `w.rules.update` (call unchanged) + +The calls and results in 1.k and 1.l stay as they are. Two things change through the rule itself: rules are in the 6.a shape, and they carry no `ref`. + +### 6.f Set the wallet label - `w.setLabel` (changed) + +Changes the label shown in `list()` and `info()`. Owner only. + +```tsx +// Function +const tx = await w.setLabel(label, { options? }) + +// Usage and Params +const tx = await w.setLabel('aave-optimiser-v2'); // rename the wallet +const reset = await w.setLabel(''); // back to the default label +const tracked = await w.setLabel('aave-optimiser-v2', { progressHook: (p) => console.log(p.id) }); // with progress events +// label string, required the new label, at most 64 bytes of UTF-8; an empty string resets it to the default "AGW " +// options.progressHook function, optional progress events, AGENTIC-TX-106; default none + +// Returns +// { hash, origin, from, to, blockNumber, wait() } +{ + hash: '0x3b8d...', + origin: 'eip155:11155111:0x31dC...', // the owner's key, CAIP-10 + from: '0xFd6C2fE69bE13d8bE379CCB6c9306e74193EC1A9', // the owner's Push account + to: '0x2Fd904d6f2C0b34d58426C8Ae9c5267E845CE98f', // the wallet + blockNumber: 1488n, + wait // await tx.wait() for the receipt; status lives on the receipt +} +``` + +What changed from 1.g: the function is live in the contract, so it is no longer proposed. The rule that a rename is not a checkpoint now binds the SDK too. The first implementation sent the rename through the owner door, and every owner door call records an `OWNER_ACTION` checkpoint. With the checkpoint rule for 8183 jobs, a user who renamed a wallet during a job would hand the fee to the agent over a label. The SDK must call the wallet's `setLabel` directly, for a Push EOA owner and for a UEA owner, so that the checkpoint count is the same before and after a rename. + +### 6.g Send as the wallet - `sendTransaction` with `agenticWallet` (changed) + +The call is the one in 2.a. Two things around it change. + +```tsx +// Function +const tx = await client.universal.sendTransaction({ options }) + +// Usage and Params +const agentClient = await PushChain.initialize(agentSigner, { // agent door: the signer is named as agent in a rule + network: PushChain.CONSTANTS.PUSH_NETWORK.TESTNET, + agenticWallet: '0xWallet', +}); +const tx = await agentClient.universal.sendTransaction({ // rule picked by the destination chain + to: { address: aavePool, chain: CHAIN.ETHEREUM_SEPOLIA }, + data: [ + { to: usdcSepolia, value: 0n, data: approveData }, + { to: aavePool, value: 0n, data: supplyData }, + ], + funds: { amount: parseUnits('100', 6), token: MOVEABLE.TOKEN.ETHEREUM_SEPOLIA.USDC }, +}); +// to { address, chain }, required the destination call and its chain +// data Hex or call array, optional the destination call data +// funds { amount, token }, optional the token the wallet moves with this send +// gasLimit bigint, optional destination gas; left out = the SDK default, which covers first use on a chain (see below) + +// Returns +// { hash, origin, from, blockNumber, wait() } +{ + hash: '0x6f2a...', + origin: 'eip155:11155111:0x7Be1...', // the agent's key, CAIP-10 + from: '0xWallet', // the AGW, not the signer + blockNumber: 1530n, + wait +} +``` + +What changed from 2.a: + +- **No gateway approval step.** When the wallet sends a token to another chain, the gateway on Push takes the token out of the wallet, which needs an ERC20 approval from the wallet. The first implementation left that to the owner as a separate transaction through the owner door before the agent's first send. That step is removed: the wallet approves the exact amount inside its own outbound call (page 1, 6.1). Funding a wallet is two plain transfers to its address, PC and the token. The SDK has no allowance check and no allowance error. +- **The default destination gas covers first use on a chain.** The first time a wallet sends to a chain, its account there (the CEA) is deployed as part of the call, which took about 1.3 million gas on Sepolia against a core default of 500,000. When the CEA is not deployed yet and the caller gave no `gasLimit`, the SDK uses a first-use default large enough for the deployment. When the CEA exists, the normal default applies. A `gasLimit` from the caller always wins, and `maxGasPerCall` on the rule still bounds what the agent can spend. + +### 6.h Types, as they end up + +These replace `NativeRule`, `UniversalRule`, `AllowedCall`, `RulesRecord` and `Spent` in 3.b. Everything else in section 3 stands. + +```tsx +interface Rule { + agent: Address; // Push address: EOA, or the UEA of an external key + chainNamespace?: ChainNamespace; // left out = the connected Push chain + validUntil: number; + assets?: AssetCap[]; // cross-chain rules: tokens the agent may move on chainNamespace + maxGasPerCall?: bigint; // cross-chain rules: PC (wei) per outbound for the destination leg + allowedCalls: AllowedCall[]; // 1..32 +} + +interface AssetCap { + token: MoveableToken | Address; // the other chain's token address, or the native marker + maxPerCall: bigint; + maxTotal?: bigint; // left out = 0; 0 means the agent cannot move this token +} + +interface AllowedCall { + target: Address | string; // a contract; on Solana, the program address + selector: Selector | 'value-only'; // on Solana, the instruction name with its argument types + pins?: Pin[]; + maxValue?: bigint; // native coin per call; left out = 0 +} + +type Pin = + | { arg: number; expected: Hex | Address | bigint | WalletMarker } // the argument must equal this constant, or be the wallet itself + | { arg: number; max: bigint } // the argument must not exceed this + | { account: number; expected: string | WalletMarker; token?: MoveableToken | string }; // Solana only: the account at this position must be this address, or the wallet itself; with token, the wallet's token account for that token + +type WalletMarker = typeof PushChain.CONSTANTS.AGENTIC.WALLET; // 'agentic:wallet': the wallet's own account on the rule's chain + +interface RulesRecord { + rulesId: Hex; + enabled: boolean; + chainNamespace: string; + agent: Address; + validUntil: number; + rule: Rule; // accepted as is by rules.update + spent: Spent; +} + +type Spent = + | { kind: 'native'; valueSpent: bigint; amountSpent: bigint; callsUsed: number } + | { kind: 'universal'; assets: { token: Address; spent: bigint }[] }; // one entry per asset, same order as rule.assets +``` + +`Checkpoint` in 3.c keeps its `ref` field. That one is the checkpoint's own reference (a rules id or a call hash) and has nothing to do with the rule `ref` removed in 6.b. + +`PushChain.CONSTANTS.AGENTIC` has one member, `WALLET` (6.a). The rest of 3.d (`FACTORY`, `RULES_POLICY`, `MAX_PINS`, `MAX_ALLOWED_CALLS`, `ENVELOPE_VERSION`) is dropped. Contract addresses and limits stay inside the SDK and are not exposed. The first implementation exposes all five on `PushChain.CONSTANTS.AGENTIC`; they are removed. + +`PushChain.utils.agentic` (3.e) is dropped. The ids and the encoders stay inside the SDK, `client.agentic.derive` covers deriving a wallet address, and `compileCard` is left to the marketplace page (page 6). The first implementation exposes `actionId`, `configId` and `decodeRules` on `PushChain.utils.agentic`; they are removed. + +### 6.i Solana, decided for v1 + +A Solana rule uses the same `allowedCalls` and `pins` shape as every other chain (6.a). The separate `allowedInstructions` shape of the first implementation, with an IDL and named accounts and fields, is replaced. + +```tsx +// a rule on Solana devnet +{ + agent: '0xAgentOnPush', + chainNamespace: CHAIN.SOLANA_DEVNET, + assets: [ + { token: '0x0000000000000000000000000000000000000000', maxPerCall: 10_000n, maxTotal: 20_000n }, // native SOL, in lamports + ], + maxGasPerCall: parseUnits('1', 18), + validUntil: now + 30 * 86400, + allowedCalls: [ + { target: program, // the program address + selector: 'receive_sol(u64)', // instruction name and argument types + pins: [ + { arg: 0, max: 10_000n }, // the amount + { account: 1, expected: recipient }, // account 1 must be this address + { account: 2, expected: PushChain.CONSTANTS.AGENTIC.WALLET }, // account 2 must be this wallet (its CEA on Solana) + ] }, + ], +} +``` + +The selector is the instruction's name with its argument types, the same idea as an EVM function signature. It is enough to identify the instruction and to locate each argument, so a rule carries no IDL. A program that does not follow the Anchor naming is written with a raw hex selector, as on EVM. + +A Solana instruction carries two separate lists: its arguments (the values in the instruction data) and its accounts (the addresses it touches, passed beside the data). A pin says which list it means: `arg` is a position in the arguments and `account` is a position in the accounts list, both counted from 0. EVM rules only use `arg`, because an EVM call carries its addresses as arguments. + +Tokens on Solana are not held at the wallet's own address. For each token it holds, the wallet has a separate token account, whose address is derived from the wallet and the token. To require that an account is the wallet's token account for a given token, the pin names the token as well: + +```tsx +{ account: 1, expected: PushChain.CONSTANTS.AGENTIC.WALLET, token: MOVEABLE.TOKEN.SOLANA_DEVNET.USDT } // account 1 must be this wallet's USDT token account +``` + +Without `token`, `WALLET` on an account means the wallet's CEA itself, which is where native SOL sits. + +The IDL is still used where it is used today: when the call data for a send is built with `PushChain.utils.helpers.encodeTxData`, where it is passed in place of an ABI. + +Accepted for v1: + +- **A Solana rule reads back in the form it was written.** Positions go in and positions come out, so the read, change, pass back test of 6.d holds for Solana too. +- **An agent sends one Solana instruction per transaction.** Arrays of instructions are not supported on the agent door. +- **Only instructions with fixed-size arguments can be put under a rule.** Numbers up to u64, public keys, booleans and fixed-length arrays work, with top-level, non-optional accounts. Lists, strings, optional values and nested structs are rejected before signing. A deposit of an amount works; a routed swap that takes a list of hops does not. + +### 6.j Contract changes these depend on + +All on [1. AGW Contract Changes (nomenclature standard + change set)](https://app.notion.com/p/1-AGW-Contract-Changes-nomenclature-standard-change-set-3e9188aea7f4813aa31fc95ceb4e684d?pvs=21), section 6. + +| Page 1 item | Contract change | Needed by | +| --- | --- | --- | +| 6.1 | The wallet approves the gateway for the exact amount inside each outbound | 6.g | +| 6.2 | One factory call that deploys the wallet and grants its rules | 6.b | +| 6.3 | Pins on EVM destination calls in the rules policy | 6.a | +| 6.4 | `ref` removed from `grantRules` | 6.b, 6.c, 6.d | +| 6.5 | A cap of 0 means nothing moves | 6.b | + +### 6.k Still open + +1. Whether the rules policy can enforce the wallet token account pin of 6.i in every case. To confirm with the contracts owner. + +### 6.l Response fields and error codes added by the first implementation + +The first implementation adds response fields and error codes that are not in 3.f. They are accepted as listed here. Four codes are removed, each for the reason given below. + +**The `agentic` object on a response.** Every send made as the wallet carries an `agentic` object on its response, so the caller can see which wallet, which door and which rule the send used. Only the fields that apply to that send are present. + +```tsx +// tx.agentic, on the UniversalTxResponse of a send made as the wallet +{ + wallet: '0xWallet', // the AGW + door: 'agent', // 'owner' or 'agent' + rulesId: '0x9c1e...', // the rule used; agent door only + chainNamespace: 'eip155:11155111', // destination chain of a cross-chain send + destinationAccount: '0xCEA...', // the wallet's CEA on that chain + destinationCalls: [{ to, data, value }], // the ordered calls run on an EVM destination + destinationInstruction: { program, data, accounts }, // the instruction run on Solana + destinationTransfer: { recipient, token, amount }, // a plain transfer of SOL or a token on Solana + nativeCalls: [{ to, data, value }], // the ordered calls of a batch on Push + rawTo: '0xWallet', // what the signer's transaction actually called + rawData: '0x...' // the calldata it actually carried +} +``` + +**Error codes that stay.** All are thrown before anything is signed, unless the row says otherwise. + +| Code | Thrown when | +| --- | --- | +| `INDEX_RACE` | Another `create` took the wallet slot first. Nothing was committed; call `create` again | +| `NOT_WALLET_OWNER` | The signer tries to change a wallet it does not own | +| `READ_ONLY` | A client with no signer tries to write | +| `RULE_NOT_FOUND` | The rule id is not an enabled rule on the wallet | +| `INVALID_RULE` | A rule or a label is malformed, for example a label over 64 bytes | +| `AMBIGUOUS_RULE` | More than one enabled rule matches the agent and the destination chain. The SDK does not pick one | +| `RULE_READ_FAILED` | The rules could not be read from the chain, so the SDK does not send | +| `INCONSISTENT_READ` | Two reads from the chain disagree with each other, so the SDK does not act on them | +| `AGENT_GAS_INSUFFICIENT` | The agent's own Push account has no PC for gas. The wallet's PC pays for the outbound, not for the agent's gas | +| `WALLET_BALANCE_INSUFFICIENT` | The wallet does not hold enough PC or enough of the token for the send | +| `CAPABILITY_UNAVAILABLE` | The network cannot do what was asked, for example a batch as the agent where no atomic batch is available | +| `RECEIPT_UNAVAILABLE` | After sending: the transaction was submitted but its receipt could not be read. It may still land | +| `RECEIPT_MISMATCH` | After sending: the receipt does not match what was sent, for example rule ids in a different order | + +**Error codes that are removed.** + +| Code | Why it goes | +| --- | --- | +| `CREATE_PARTIAL` | `create` is one transaction (6.b), so it cannot end half done | +| `GATEWAY_ALLOWANCE_INSUFFICIENT` | The wallet approves the gateway itself (6.g, page 1 item 6.1) | +| `GENERATION_UNSUPPORTED` | There are no earlier wallet versions to support | +| `RULE_LIMIT_EXCEEDED` | Only raised by a local preview of a Solana send. The on-chain rules policy is the only rule checker (2.a), so this is not a public code | + +**`DUPLICATE_RULE` is restored.** 3.f lists `DUPLICATE_RULE`: two rules for the same agent and chain are rejected before signing. The first implementation does not have it and only notices the overlap later, when the agent sends (`AMBIGUOUS_RULE`). The check goes back into `create` and `rules.add`. `AMBIGUOUS_RULE` stays for a wallet that already has overlapping rules. + +**Fields on the error classes.** `AgenticError` also carries `details` and `cause`, and both stay. `AgenticRevertError` carries `transactionHashes` and `pendingTransactionHash`, and a returned `tx` carries an `atomic` flag. These three report a write that was split across several transactions. They are removed once every write is a single transaction (6.b). + +The progress events of the first implementation are the ones in 3.f, with nothing added. + +### 6.m Delete rules - `w.rules.delete` (renamed from `w.rules.revoke`) + +Removes some rules by id, or all of them in one atomic call. This is 1.m under a new name. The call shape and the result are unchanged. + +```tsx +// Function +const tx = await w.rules.delete(rulesIds, { options? }) +const tx = await w.rules.delete({ all, progressHook? }) + +// Usage and Params +const some = await w.rules.delete(['0x9c1e...', '0x7d3a...']); // delete these rules +const all = await w.rules.delete({ all: true }); // delete every rule on the wallet +const tracked = await w.rules.delete(['0x9c1e...'], { progressHook: (p) => console.log(p.id) }); // with progress events +// rulesIds Hex[], required unless all is set the rules to delete +// options.progressHook function, optional progress events, AGENTIC-TX-105; default none +// all true, required unless rulesIds given delete every rule on the wallet in one atomic call +// progressHook function, optional same events, in the { all: true } form; default none + +// Returns +// { hash, origin, from, to, blockNumber, wait() } +{ + hash: '0x8e01...', + origin: 'eip155:11155111:0x31dC...', // the owner's key, CAIP-10 + from: '0xFd6C2fE69bE13d8bE379CCB6c9306e74193EC1A9', // the owner's Push account + to: '0x2Fd904d6f2C0b34d58426C8Ae9c5267E845CE98f', // the wallet + blockNumber: 1512n, + wait // await tx.wait() for the receipt; status lives on the receipt +} +``` + +What changed from 1.m: + +- **The method is delete, not revoke.** The handle now reads `rules.add`, `rules.update`, `rules.delete`. Delete is also what happens on-chain: the wallet removes the rule from the session engine for good. A deleted rule cannot be switched back on, and granting the same rule again produces a new `rulesId`. +- **The bare-call error is renamed.** A bare `delete()` still throws. The code is `DELETE_NEEDS_TARGET` (was `REVOKE_NEEDS_TARGET`). +- **Contract names do not change.** The wallet functions stay `revokeRules` and `revokeAllRules`, the event stays `RulesRevoked`, and the checkpoint kind stays `RULES_REVOKED`. `w.checkpoints()` returns that kind as the contract records it. + +# 7. Changes proposed on 12 Oct 2026: Presets + +A preset is a ready-made set of rules for a common use case, such as trading on popular DEXes. The wallet UI and developers both read presets from the SDK, so there is one source for them. A preset only produces rules. The rules are then passed to `client.agentic.create` in the normal way, and can be edited before that. App ABIs are not part of presets and stay in the wallet UI, because the UI can update them without an SDK release. + +List of changes: + +- New constants: `PushChain.CONSTANTS.AGENTIC.PRESETS.CATEGORY` with `DEXES`, `LENDING` and `PREDICTION`. An app level (`PushChain.CONSTANTS.AGENTIC.PRESETS.APP`) can be added later without changing the functions. +- New function: `PushChain.utils.agentic.presets.list`, which lists every preset the SDK ships. +- New function: `PushChain.utils.agentic.presets.get`, which returns the rules for one preset. +- This brings back `PushChain.CONSTANTS.AGENTIC` members beyond `WALLET` and the `PushChain.utils.agentic` namespace, for presets only. Both were dropped earlier on this page (6.h). + +### 7.a Preset constants - `PushChain.CONSTANTS.AGENTIC.PRESETS` + +```tsx +PushChain.CONSTANTS.AGENTIC.PRESETS.CATEGORY.DEXES +PushChain.CONSTANTS.AGENTIC.PRESETS.CATEGORY.LENDING +PushChain.CONSTANTS.AGENTIC.PRESETS.CATEGORY.PREDICTION +// later: PushChain.CONSTANTS.AGENTIC.PRESETS.APP. +``` + +The constants object must be enumerable so that tools which iterate constants can list it. + +### 7.b List available presets - `PushChain.utils.agentic.presets.list` + +Returns every preset the SDK ships, so a UI can show them as cards and a developer can discover them. + +```tsx +// Function +const res = PushChain.utils.agentic.presets.list({ options? }) + +// Usage and Params +const { presets } = PushChain.utils.agentic.presets.list(); // every preset the SDK ships +// options.type string, optional 'CATEGORY' today, 'APP' later; omit to list everything + +// Returns +// { presets: Preset[] } +{ + presets: [ + { + type: 'CATEGORY', // later 'APP' + constant: PushChain.CONSTANTS.AGENTIC.PRESETS.CATEGORY.DEXES, + name: 'Popular DEXes', + chains: ['eip155:11155111', 'eip155:84532'] // chains this preset has rules for (Ethereum Sepolia, Base Sepolia) + } + ] +} +``` + +A preset with an empty `chains` list has nothing behind it yet (`PREDICTION` today, since its main apps are on a chain Push does not support yet), and the wallet UI should hide it. + +### 7.c Get the rules of a preset - `PushChain.utils.agentic.presets.get` + +Returns one rule per chain for the chosen preset. Each rule already contains the allowed contracts, the allowed calls with their full signatures, and the pins that keep funds going back to the wallet. The agent, assets and expiry are optional: pass them to get rules that are ready for `create`, or leave them out to pre-fill a review screen and add them later. + +```tsx +// Function +const res = PushChain.utils.agentic.presets.get(preset, { options? }) + +// Usage and Params +const { rules } = PushChain.utils.agentic.presets.get( + PushChain.CONSTANTS.AGENTIC.PRESETS.CATEGORY.DEXES, // a category constant now, an app constant later + { + chainNamespace: PushChain.CONSTANTS.CHAIN.ETHEREUM_SEPOLIA, // optional, omit to get every chain of the preset + agent: '0xAgentOnPush', // optional, the agent's Push address, applied to every rule + assets: [{ chainNamespace, token, maxPerCall, maxTotal }], // optional, each asset is placed on the rule of its chain + validUntil: now + 30 * 86400, // optional, applied to every rule; omit to set it later + } +); + +await client.agentic.create('My DEX agent', { rules }); + +// Returns +// { rules: Rule[] }, one rule per chain, in the same shape client.agentic.create takes +{ + rules: [ + { + agent: '0xAgentOnPush', + chainNamespace: 'eip155:11155111', + assets: [{ token: '0x1c7D...7238', maxPerCall: 100000000n, maxTotal: 1000000000n }], // from options.assets, without its chainNamespace + validUntil: 1767225600, + allowedCalls: [ + { + target: '0x...', + selector: 'exactInputSingle((address,address,uint24,address,uint256,uint256,uint160))', + pins: [{ arg: 3, expected: PushChain.CONSTANTS.AGENTIC.WALLET }], + app: 'Uniswap V3', // display only, ignored by create + label: 'Swap exact input' // display only, ignored by create + } + // plus one approve(address,uint256) per asset, spender pinned to the app's contract (see Behaviour) + ] + } + ] +} +``` + +**Behaviour** + +| Case | What happens | +| --- | --- | +| `chainNamespace` omitted | One rule is returned for every chain the preset covers. | +| `agent`, `assets` or `validUntil` omitted | The rule is returned without that field. The caller adds it before `create`, and `create` rejects a rule with no agent as it already does. | +| `assets` passed | Each asset is placed on the rule of its chain. If `chainNamespace` is set in the options, the `chainNamespace` on each asset can be left out. For each asset, an approve call is added to that rule, with the spender pinned to the app's contract on that chain, because a swap or deposit fails without it. | +| Asset passed without a cap | Proposed: `get` throws. An omitted cap means 0 in the rules policy, so the rule would allow nothing, and a preset should never silently produce a rule that cannot act. | +| Selectors | Always the full signature, never the bare name, because apps overload function names (for example two different execute functions on the same router). | +| Grouping | One rule per chain per category, not one rule per app. Each category stays at two or three apps per chain so the rule stays inside the 32 allowed calls limit of a universal rule. | +| Display fields | `app` and `label` on each allowed call are for showing names in a UI. `create` ignores them. | + +### 7.d Notes for the wallet UI + +- Call `get` with only the preset to pre-fill the review screen, then let the user add the agent, tokens, limits and expiry. +- A blank limit shown as infinity in the UI must be sent as an explicit maximum value. Leaving the cap out means 0, not unlimited. +- The preset data (contract addresses, calls and pins) ships inside the SDK. An app upgrade becomes a new app entry, and the old one keeps working because the older contract still exists. + +### 7.e Open questions + +- Can a pin's arg index reach a field inside a struct argument? The Uniswap `exactInputSingle` example depends on it, because the recipient sits inside a struct. (Rules policy contract owner) +- Routers that hide the recipient inside encoded bytes, such as Uniswap Universal Router `execute`, cannot be pinned, so they should not be preset targets. Confirm the list of apps and functions per chain with this in mind. (SDK owner with the rules policy contract owner) +- Is the agent one Push address for every chain, including Solana rules? If not, `agent` becomes a per-chain map. (SDK owner) +- Should `get` throw when an asset has no cap, as proposed above? (Page owner) +- First preset list for testnet: which apps on which chains for `DEXES` and `LENDING`. (SDK owner with the rules policy contract owner) \ No newline at end of file diff --git a/plan/agw/research/section6-feedback-2026-10-12/sdk-previous.md b/plan/agw/research/section6-feedback-2026-10-12/sdk-previous.md new file mode 100644 index 00000000..06c7346f --- /dev/null +++ b/plan/agw/research/section6-feedback-2026-10-12/sdk-previous.md @@ -0,0 +1,731 @@ +# 5. SDK: AGW + + + +# List of changes + +New + +- `client.agentic.derive` +- `client.agentic.create` +- `client.agentic.list` +- `client.agentic.wallet`, + - a management handle with + - `info`, + - `owner`, + - `setLabel` (PROPOSED), + - `checkpoints`, + - `rules.list`, + - `rules.get`, + - `rules.add`, + - `rules.update`, + - `rules.revoke` +- `PushChain.CONSTANTS.AGENTIC` +- `PushChain.utils.agentic` + +Updated + +- `PushChain.initialize`, new option `agenticWallet` +- `PushChain.CONSTANTS.READ.CHAIN`, outside change confirmed 2026-09-28 + +Initialize is unchanged on the owner side: + +```tsx +const client = await PushChain.initialize(universalSigner, { network: PushChain.CONSTANTS.PUSH_NETWORK.TESTNET }); +``` + +| Signer | Door | Rules checked | +| --- | --- | --- | +| The wallet's owner | Owner door (`execute`) | No. Every send is recorded as a checkpoint | +| An address named as `agent` in one of the wallet's rules | Agent door (`executeAsAgent`) | Yes, by URP (UniversalRulesPolicy, the on-chain rule checker) | +| Anyone else | None | Never reached: `initialize` throws `NOT_OWNER_OR_AGENT` | + +An agentic wallet involves three parties, and it helps to have them straight before reading the functions. + +The **owner** is whoever created the wallet. When the owner sends through the wallet, no rules are checked; this is called the owner door, and the contract records every such action as a checkpoint so that an evaluator can later tell whether the owner touched anything mid-job. + +The **agent** is the address the owner allows to act on its behalf. It is always a Push address. If the agent's key is a Push EOA, that EOA is the agent. If the key lives on another chain (an EVM key on Ethereum, a Solana key, anything else), the agent is that key's UEA on Push, which exists deterministically for every external key. The SDK never asks for a curve, a chain or a key type. When the agent sends through the wallet, the rules are checked; this is the agent door. + +The **rules** say what an agent may do. Each rule names its agent and its destination chain, and there is one rule per chain per agent, so a wallet can have one agent for Ethereum and a different one for Solana. The `chainNamespace` on a rule decides which rulebook applies: leave it out and the rule governs calls on Push itself; set it to an `eip155` or `solana` chain and the rule governs cross-chain calls to that chain. + +Two ways to touch a wallet from the SDK. `PushChain.initialize(signer, { agenticWallet })` returns a client that acts as the wallet, and whether it goes through the owner door or the agent door depends on who the signer is. `client.agentic.wallet(address)` returns a handle for managing the wallet (rules, label, checkpoints) and never sends as it. + +# 1. Owner side, by example + +The owner side is everything the person who owns the wallet does: create it, fund it, write and revoke the rules, look at what happened. The agent side (section 2) is what the agent does: act through the wallet within those rules. + +### 1.a Derive an agentic wallet address - `client.agentic.derive` + +Gives you the address a wallet will have before it is deployed. The address depends only on the owner and an index. + +```tsx +// Function +const first = await client.agentic.derive({ options? }) + +// Usage and Params +const next = await client.agentic.derive(); // the owner's next wallet +const first = await client.agentic.derive({ index: 0 }); // a specific slot +// options.index number, optional which wallet slot to derive; default is the owner's next unused index + +// Returns +// { address, index, deployed } +{ + address: '0x2Fd904d6f2C0b34d58426C8Ae9c5267E845CE98f', + index: 0, + deployed: false +} +``` + +Because the address depends only on the owner and an index, it is the same whether you deploy first or later. That lets you send funds to it first (from any chain) and deploy afterwards, or show the address in a UI before anything is on-chain. Same idea as `deriveExecutorAccount` for a UEA. + +### 1.b Create an agentic wallet - `client.agentic.create` + +Deploys the wallet and grants the rules. The label is the only wallet-level input; the agent and an optional `ref` are named on each rule, because that is where the contract binds them. + +```tsx +// Function +const created = await client.agentic.create(label, { options }) + +// Usage and Params +const created = await client.agentic.create('aave-optimiser', { // wallet with one cross-chain rule + rules: [{ // one entry per chain per agent + agent: '0xAgentOnPush', // a Push address: the agent's EOA, or its UEA if the key lives on another chain. Never the owner + chainNamespace: CHAIN.ETHEREUM_SEPOLIA, // foreign chain => universal rulebook + assets: [ + { token: MOVEABLE.TOKEN.ETHEREUM_SEPOLIA.USDC, maxPerCall: parseUnits('100', 6), maxTotal: parseUnits('1000', 6) }, + { token: MOVEABLE.TOKEN.ETHEREUM_SEPOLIA.WETH, maxPerCall: parseUnits('0.5', 18) }, + ], + maxGasPerCall: parseUnits('1', 18), // PC (wei) per outbound for the destination leg + validUntil: now + 30 * 86400, + allowedCalls: [ + { target: aavePool, selector: 'supply(address,uint256,address,uint16)', beneficiary: 2 }, // arg index, not offset: onBehalfOf must be the AGW's CEA + { target: usdcSepolia, selector: 'approve(address,uint256)' }, + ], + }], + progressHook: (p) => console.log(p.id, p.message), // AGENTIC-TX-1xx +}); +const bare = await client.agentic.create('scratch', { rules: [] }); // wallet first, rules later with rules.add +// label string, required shown in list() and info(); the contract stores it +// options.rules Rule[], required one per chain per agent, may be empty; each rule carries its own agent and optional ref +// options.progressHook function, optional progress events, AGENTIC-TX-1xx; default none +// rules[].agent Address, required the Push address allowed to act under this rule; never the owner +// rules[].ref Hex, optional emitted in RulesGranted, not interpreted; default zero +// rules[].assets AssetCap[], required on a universal rule tokens the agent may move, as the other chain's address (MOVEABLE constants); the SDK resolves each to its PRC20 on Push; each cap is { token, maxPerCall, maxTotal? } +// rules[].maxGasPerCall bigint, required on a universal rule PC (wei) the wallet may spend per outbound for the destination leg + +// Returns +// { wallet, index, rulesIds, tx } +{ + wallet: '0x2Fd904d6f2C0b34d58426C8Ae9c5267E845CE98f', + index: 0, + rulesIds: ['0x9c1e...'], // in the order of the rules you passed; empty for rules: [] + tx: { // UniversalTxResponse + hash: '0xb527...', + origin: 'eip155:11155111:0x31dC...', // the owner's key, CAIP-10 + from: '0xFd6C2fE69bE13d8bE379CCB6c9306e74193EC1A9', // the owner's Push account + blockNumber: 1290n, + wait // await tx.wait() for the receipt; status lives on the receipt + } +} +``` + +One rule per chain per agent. A wallet may have different agents on different chains. If an agent needs to act on two chains, `rules` has two entries with the same `agent`; two agents on one chain are two entries with the same `chainNamespace`. Nobody states a rule type; the SDK reads it from `chainNamespace`. `rules: []` is allowed: create the wallet first and grant rules later with `rules.add` (1.k). + +Before asking for a signature the SDK checks that no rule's agent is the owner (`AGENT_IS_OWNER`), that no two rules share both agent and chain (`DUPLICATE_RULE`), that every `allowedCalls[].target` is on the rule's chain (`TARGET_NOT_ON_RULE_CHAIN`), and that every `assets[].token` resolves to a PRC20 whose `SOURCE_CHAIN_NAMESPACE` matches the rule's chain (`ASSET_CHAIN_MISMATCH`). + +Under the hood this is `deployWallet` (or reuse of a derived address) and one `grantRules` per rule. For an external owner they go as one UEA multicall under one signature. Funding is not part of `create`: the wallet is a normal Push account, so send tokens and PC to its address the way you would to any account (1.a shows the address before deployment). + +For a Push EOA owner the same thing needs a batching entry on the factory, because core rejects multicall from a Push-native sender: [1. AGW Contract Changes (nomenclature standard + change set)](1-agw-contract-changes.md) item 11, **PROPOSED** (`createWallet(label, rules[])` on the factory). Until it lands the SDK sends deploy and grant as separate transactions and says so through progress events (AGENTIC-TX-102 and 104); `tx` is then the last of them. + +A `progressHook` passed to `PushChain.initialize` receives the same events alongside the per-call one, as in core. + +Warning for an agent whose key lives on another chain: the same EVM key initialized against two chains yields two UEAs, because a UEA is derived from namespace, chainId and owner. Grant the rule to the UEA of the chain the agent will run against. `PushChain.utils.account.deriveExecutorAccount(PushChain.utils.account.toUniversal(address, { chain }))` gives it. + +### 1.c List an owner's wallets - `client.agentic.list` + +Lists the wallets owned by the connected signer. It takes no arguments and only reads the connected account. + +```tsx +// Function +const res = await client.agentic.list() + +// Usage and Params +const { wallets } = await client.agentic.list(); // the connected signer's wallets +// no params + +// Returns +// { wallets: Array<{ address, index, label, deployed, rulesCount }> } +{ + wallets: [ + { address: '0x2Fd9...', index: 0, label: 'aave-optimiser', deployed: true, rulesCount: 1 }, + { address: '0x81aB...', index: 1, label: '', deployed: false, rulesCount: 0 }, + ] +} +``` + +Client methods act on the connected account; reads about any other account live in `PushChain.utils`. If a read-only view is needed later (a marketplace or explorer page showing the wallets of an address with no signer), it becomes `PushChain.utils.agentic.wallets(owner: Address)` taking a Push address; an external owner passes its UEA. Not in v1. + +### 1.d Get a wallet handle - `client.agentic.wallet` + +Returns a handle for one wallet: the reads that are specific to an agentic wallet, plus the rule writes only an owner can do. It is not a client and never sends as the wallet. + +```tsx +// Function +const w = client.agentic.wallet(address) + +// Usage and Params +const w = client.agentic.wallet('0xWallet'); // handle for one wallet; nothing is sent +// address Address, required the AGW to manage, a Push address + +// Returns +// { address, info(), owner(), setLabel(), checkpoints(), rules.* } +{ + address: '0xWallet', + info, owner, setLabel, checkpoints, // 1.e to 1.h + rules: { list, get, add, update, revoke } // 1.i to 1.m +} +``` + +There is one way to send as the wallet: `PushChain.initialize(signer, { agenticWallet })` (section 2). The handle only manages. To send as the wallet, move funds, reach the wallet's CEA on another chain, or read balances, initialize with `agenticWallet` and use the normal account tooling: `sendTransaction`, `universal.read`, or viem and ethers against `client.universal.account`. That gives the owner the full `sendTransaction` with every route the SDK already has, the same receipts, and the wallet's CEA reachable exactly as it is for any other account. + +Balance reads are deliberately not on the handle: they are not agentic, and every account is read the same way. There is no `w.execute` for the same reason. The handle stays what its name says: management. + +### 1.e Read wallet info - `w.info` + +Returns the wallet's summary in one read: the fields `list()` shows for each wallet, plus the owner. It is how you read the label from the handle. + +```tsx +// Function +const info = await w.info() + +// Usage and Params +const { label, deployed } = await w.info(); // one wallet's summary +// no params + +// Returns +// { address, label, index, owner, deployed, rulesCount } +{ + address: '0x2Fd904d6f2C0b34d58426C8Ae9c5267E845CE98f', + label: 'aave-optimiser', + index: 0, + owner: '0xFd6C2fE69bE13d8bE379CCB6c9306e74193EC1A9', + deployed: true, + rulesCount: 1 +} +``` + +### 1.f Read the owner - `w.owner` + +Returns the owner's Push address, as the contract stores it. + +```tsx +// Function +const res = await w.owner() + +// Usage and Params +const { owner } = await w.owner(); // the Push address stored as owner +// no params + +// Returns +// { owner } +{ + owner: '0xFd6C2fE69bE13d8bE379CCB6c9306e74193EC1A9' +} +``` + +If the owner is a UEA and you need the controlling origin behind it (the chain and the external key), use `resolveControllerAccount` on the returned address. + +Page rule: identities going in and out of the agentic namespace are Push addresses (owner, agent, wallet). + +### 1.g Set the wallet label - `w.setLabel` + +**PROPOSED**, contract change, see [1. AGW Contract Changes (nomenclature standard + change set)](1-agw-contract-changes.md) item 10. Changes the label shown in `list()` and `info()`; owner only. + +```tsx +// Function +const tx = await w.setLabel(label, { options? }) + +// Usage and Params +const tx = await w.setLabel('aave-optimiser-v2'); // rename the wallet +const tracked = await w.setLabel('aave-optimiser-v2', { progressHook: (p) => console.log(p.id) }); // with progress events +// label string, required the new label; stored by the contract and emitted in LabelSet +// options.progressHook function, optional progress events, AGENTIC-TX-106; default none + +// Returns +// { hash, origin, from, to, blockNumber, wait() } +{ + hash: '0x3b8d...', + origin: 'eip155:11155111:0x31dC...', // the owner's key, CAIP-10 + from: '0xFd6C2fE69bE13d8bE379CCB6c9306e74193EC1A9', // the owner's Push account + to: '0x2Fd904d6f2C0b34d58426C8Ae9c5267E845CE98f', // the wallet + blockNumber: 1488n, + wait // await tx.wait() for the receipt; status lives on the receipt +} +``` + +Emits `LabelSet(string label)`. It is not a checkpoint: the label is cosmetic metadata and evaluators ignore it. Today the label can only be set once, at `deployWallet`, and is emitted in `WalletDeployed`. + +### 1.h Read checkpoints - `w.checkpoints` + +Every owner-side change the wallet has recorded: owner-door sends, rules granted, rules revoked. An evaluator reads these to know whether the owner changed anything after a job started (page 4). + +```tsx +// Function +const res = await w.checkpoints({ options? }) + +// Usage and Params +const all = await w.checkpoints(); // every checkpoint +const recent = await w.checkpoints({ sinceBlock: 1234n }); // from a block onward +// options.sinceBlock bigint, optional only checkpoints at or after this block; default all + +// Returns +// { checkpoints: Array<{ seq, kind, ref, blockNumber, txHash }> } +{ + checkpoints: [ + { seq: 3, kind: 'RULES_GRANTED', ref: '0x9c1e...', blockNumber: 1290n, txHash: '0x...' }, + { seq: 4, kind: 'OWNER_ACTION', ref: '0x5a7b...', blockNumber: 1402n, txHash: '0x...' }, + ] +} +``` + +### 1.i List rules - `w.rules.list` + +Returns every rule on the wallet as a decoded record, including what each rule has spent so far. + +```tsx +// Function +const res = await w.rules.list() + +// Usage and Params +const { rules } = await w.rules.list(); // the wallet's rules +// no params + +// Returns +// { rules: RulesRecord[] } +{ + rules: [ + { + rulesId: '0x9c1e...', + enabled: true, + chainNamespace: 'eip155:11155111', + agent: '0xAgentOnPush', + validUntil: 1767225600, + ref: '0x4a2f...', + rule: { /* decoded UniversalRule, as passed to create */ }, + spent: { kind: 'universal', amountSpent: 25000000n } // shape PROPOSED, see 3.b + } + ] +} +``` + +### 1.j Get one rule - `w.rules.get` + +Returns one rule by id, decoded, with what it has spent. + +```tsx +// Function +const record = await w.rules.get(rulesId) + +// Usage and Params +const record = await w.rules.get('0x9c1e...'); // one rule by id +// rulesId Hex, required the id returned by create or rules.add + +// Returns +// RulesRecord +{ + rulesId: '0x9c1e...', + enabled: true, + chainNamespace: 'eip155:11155111', + agent: '0xAgentOnPush', + validUntil: 1767225600, + ref: '0x4a2f...', + rule: { /* decoded UniversalRule */ }, + spent: { kind: 'universal', amountSpent: 25000000n } // shape PROPOSED, see 3.b +} +``` + +`spent` is a field on the record, so `get` and `list` both carry it. There is no separate spent call. + +### 1.k Add rules - `w.rules.add` + +Grants new rules on an existing wallet under one signature. The rules array comes first; `agent` and `ref` live on each rule. + +```tsx +// Function +const res = await w.rules.add(rules, { options? }) + +// Usage and Params +const one = await w.rules.add([nativeRule]); // one rule +const many = await w.rules.add([ruleOnSepolia, ruleOnPush]); // several rules, one signature +const tracked = await w.rules.add([nativeRule], { progressHook: (p) => console.log(p.id, p.message) }); // with progress events +// rules Rule[], required one per chain per agent; each rule carries its own agent and optional ref +// options.progressHook function, optional progress events, AGENTIC-TX-104; default none + +// Returns +// { rulesIds, tx } +{ + rulesIds: ['0x7d3a...'], // in the order of the rules you passed + tx: { // UniversalTxResponse + hash: '0x4c19...', + origin: 'eip155:11155111:0x31dC...', + from: '0xFd6C2fE69bE13d8bE379CCB6c9306e74193EC1A9', + blockNumber: 1501n, + wait + } +} +``` + +Records a `RULES_GRANTED` checkpoint. + +### 1.l Update rules - `w.rules.update` + +Replaces rules in a batch: each pair names one old rule and the one new rule that takes its place. + +```tsx +// Function +const res = await w.rules.update({ rules, progressHook? }) + +// Usage and Params +const one = await w.rules.update({ rules: [{ rulesId: '0x9c1e...', rule: newRule }] }); // replace one rule +const many = await w.rules.update({ rules: [{ rulesId: idA, rule: ruleA }, { rulesId: idB, rule: ruleB }] }); // replace several, one signature +const tracked = await w.rules.update({ rules: [{ rulesId: idA, rule: ruleA }], progressHook: (p) => console.log(p.id) }); // with progress events +// rules Array<{ rulesId, rule }>, required one old rule to one new rule per pair +// rules[].rulesId Hex, required the rule being replaced +// rules[].rule Rule, required the replacement; one rule per agent per chain still applies +// progressHook function, optional progress events, AGENTIC-TX-105 and 104; default none + +// Returns +// { rules: Array<{ rulesId, replaced }>, tx } +{ + rules: [ + { rulesId: '0x51c0...', replaced: '0x9c1e...' }, // new id, old id + ], + tx: { // UniversalTxResponse + hash: '0x7a02...', + origin: 'eip155:11155111:0x31dC...', + from: '0xFd6C2fE69bE13d8bE379CCB6c9306e74193EC1A9', + blockNumber: 1507n, + wait + } +} +``` + +Rules are immutable on-chain, so an update is a revoke plus a grant: for each pair the SDK asserts the old rule's spend, revokes it and grants the new one, all pairs in one multicall. The result is a new `rulesId` per pair, and the spend counters reset on the new rule: what the old rule had spent does not carry over. This is accepted for v1 (open item 1); an in-place update would be a contract change and there is no demand for it yet. + +### 1.m Revoke rules - `w.rules.revoke` + +Revokes some rules by id, or all of them in one atomic call. + +```tsx +// Function +const tx = await w.rules.revoke(rulesIds, { options? }) +const tx = await w.rules.revoke({ all, progressHook? }) + +// Usage and Params +const some = await w.rules.revoke(['0x9c1e...', '0x7d3a...']); // revoke these rules +const all = await w.rules.revoke({ all: true }); // revoke every rule, on-chain revokeAllRules +const tracked = await w.rules.revoke(['0x9c1e...'], { progressHook: (p) => console.log(p.id) }); // with progress events +// rulesIds Hex[], required unless all is set the rules to revoke +// options.progressHook function, optional progress events, AGENTIC-TX-105; default none +// all true, required unless rulesIds given revoke every rule on the wallet in one atomic call +// progressHook function, optional same events, in the { all: true } form; default none + +// Returns +// { hash, origin, from, to, blockNumber, wait() } +{ + hash: '0x8e01...', + origin: 'eip155:11155111:0x31dC...', // the owner's key, CAIP-10 + from: '0xFd6C2fE69bE13d8bE379CCB6c9306e74193EC1A9', // the owner's Push account + to: '0x2Fd904d6f2C0b34d58426C8Ae9c5267E845CE98f', // the wallet + blockNumber: 1512n, + wait // await tx.wait() for the receipt; status lives on the receipt +} +``` + +A bare `revoke()` is not allowed and throws `REVOKE_NEEDS_TARGET`: a call with no argument that wipes every rule is too easy to make by mistake. Records `RULES_REVOKED` checkpoints. + +# 2. Agent side, by example + +There is no new method on the agent side. The agent uses its own signer and tells `initialize` which wallet to act through. It does not name a rule: which rule applies is decided per transaction, from the destination chain. + +### 2.a Act as the wallet - `PushChain.initialize` with `agenticWallet` (updated) + +Returns a client whose account is the wallet. Whether its sends go through the owner door or the agent door depends on who the signer is. + +```tsx +// Function +const client = await PushChain.initialize(signer, { options }) + +// Usage and Params +const agentClient = await PushChain.initialize(agentSigner, { // agent door: the signer is named as agent in a rule + network: PushChain.CONSTANTS.PUSH_NETWORK.TESTNET, + agenticWallet: '0xWallet', +}); +const ownerClient = await PushChain.initialize(ownerSigner, { // owner door: the signer owns the wallet + network: PushChain.CONSTANTS.PUSH_NETWORK.TESTNET, + agenticWallet: '0xWallet', +}); +``` + +`agentSigner` is any signer `initialize` accepts today. If the key lives on another chain, the SDK derives its UEA and everything goes through that, as it does for every external user. + +Which door the client uses depends on who the signer is. If the signer is the wallet's owner, sends go through the owner door: no rules, and every send is recorded as a checkpoint. If the signer is an address named as agent in one of the wallet's rules, sends go through the agent door and the rules apply. If it is neither, `initialize` throws `NOT_OWNER_OR_AGENT`. If the address has no wallet deployed yet it throws `WALLET_NOT_DEPLOYED`, and if the address is not an agentic wallet it throws `NOT_AGENTIC_WALLET`. This is also how an owner acts as the wallet with the full client: `PushChain.initialize(ownerSigner, { agenticWallet })`. There is one way to send as a wallet and the signer decides the door. + +On the agent door the SDK sends; URP on-chain is the only rule checker. Before sending, the SDK only looks up the `rulesId` for the destination chain: the rule that is enabled, whose `agent` equals the signer, and whose `chainNamespace` equals the destination. The lookup is one read on every send, not cached at initialize. If none is found it throws `NO_RULES_FOR_CHAIN` before any signature, so it costs nothing; otherwise it calls `executeAsAgent(rulesId, ...)` on the wallet. That is the agent door from D3 on [1. AGW Contract Changes (nomenclature standard + change set)](1-agw-contract-changes.md): there is no session validator, and the wallet only checks that `msg.sender` is the rule's agent. There is one rule per (agent, chain), so a signer and a destination match at most one rule. If the action breaks a rule, it reverts on-chain and the agent pays that gas. `sendTransaction` then throws `AgenticRevertError`, which extends core's `PushChainExecutionError` and carries URP's custom error in `decodedError`, so the agent sees which gate failed (3.f). + +From an external key, the call arrives through the agent's UEA. If the agent's UEA is not yet deployed, the first action takes the origin-chain fee lock once (minimum $1), which deploys the UEA and funds it with PC. Every later action requires PC in the UEA and is a direct Push transaction paid from that balance, with no origin transaction and no cross-chain wait. + +Two things for whoever runs the agent. The agent's UEA is a second balance to keep funded: the AGW's PC covers the wallet's outbound fees, not the agent's gas. And in `agenticWallet` mode the SDK turns `enforceGasCheck` on for every action except that one first action while the agent's UEA is not yet deployed, so an empty UEA fails loudly instead of silently falling back to a $1 origin lock and a confirmation wait on every action. + +Routing. In `agenticWallet` mode every send is wrapped as `executeAsAgent` (agent door) or `execute` (owner door), and for cross-chain legs the AGW itself calls the gateway. So the AGW's CEA executes on the destination and the AGW's PC pays as `msg.value`. The SDK never uses the signer's own Route 2, which would run through the agent's CEA instead of the wallet's. Any `from` (Routes 3 and 4) is rejected in `agenticWallet` mode with `FROM_NOT_ALLOWED`: it makes `msg.sender` a CEA, and the agent door check fails. + +What changes on the client in this mode: + +- `universal.account` is the wallet address string, so receipts show the AGW as `from`. `universal.origin` stays the signer's origin account. +- `getAccountStatus()` reports the signer's own UEA, not the wallet. +- The signer is whatever was passed to `initialize`. To top up the agent's UEA, find it with `PushChain.utils.account.deriveExecutorAccount(signer.account)` and send PC to it from a client initialized without `agenticWallet`. +- A Solana-keyed agent can act on Push and `eip155` destinations now, and on `solana:` destinations once the SVM rulebook ships. +- Agents read their own rules through `client.agentic.wallet(addr).rules.list()`. +- `tx.data` arrays and `tx.funds` (moving the AGW's PRC20) work as they do for any account. +- `payGasWith`, `migrateCEA`, `rescueFunds`, `prepareTransaction` and `executeTransactions` throw `NOT_ALLOWED_IN_AGENTIC_MODE`. + +```tsx +const tx = await agentClient.universal.sendTransaction({ // agent door, rule picked by the destination chain + to: { address: aavePool, chain: CHAIN.ETHEREUM_SEPOLIA }, + data: supplyData, +}); + +// tx: UniversalTxResponse +{ + hash: '0x6f2a...', + origin: 'eip155:11155111:0x7Be1...', // the agent's key, CAIP-10 + from: '0xWallet', // the AGW, not the signer + blockNumber: 1530n, + wait +} + +const receipt = await tx.wait(); +// receipt: UniversalTxReceipt +{ + status: 1, + hash: '0x6f2a...', + from: '0xWallet', + blockNumber: 1530n, + externalTxHash: '0x91c4...' // the leg executed by the AGW's CEA on Sepolia +} +``` + +The same EVM key initialized against two chains yields two UEAs (derived from namespace, chainId and owner), so the rule must name the UEA of the chain this client initializes against (see 1.b). + +# 3. Types + +### 3.a Client, options and namespace + +```tsx +type Address = `0x${string}`; +type Hex = `0x${string}`; +type ForeignChainNamespace = `eip155:${string}` | `solana:${string}`; +type ProgressHook = (p: ProgressEvent) => void; // ProgressEvent is core's shape: { id, title, message, level, response, timestamp } + +interface PushChainClient { + universal: UniversalNamespace; // in agenticWallet mode: account is the wallet + agentic: AgenticNamespace; // this page + market: MarketNamespace; // page 6 + job: JobNamespace; // page 7 + evaluation: EvaluationNamespace; // page 8 +} + +interface InitializeOptions { + network?: PUSH_NETWORK; + rpcUrls?: Partial>; + agenticWallet?: Address; // NEW: act as the wallet; door chosen by the signer's Push address + // enforceGasCheck is on when agenticWallet is set, except for the first action while the agent's UEA is not yet deployed (2.a) +} + +interface AgenticNamespace { + derive(opts?: { index?: number }): Promise<{ address: Address; index: number; deployed: boolean }>; + create(label: string, options: CreateOptions): Promise; + list(): Promise<{ wallets: WalletSummary[] }>; // connected signer only + wallet(address: Address): AgenticWallet; +} + +interface CreateOptions { + rules: Rule[]; // one entry per chain per agent, may be empty; each rule names its agent and optional ref + progressHook?: ProgressHook; // AGENTIC-TX-1xx +} + +// No AgentKey type, no curve, no chain. The agent is a Push address. A native key is its own EOA; any external key +// (EVM, Solana, anything) is its UEA, deterministic from (chain, owner), deployed lazily on first use. The AGW's agent +// door checks msg.sender == rules.agent; cross-VM signature verification already happened inside the UEA (page 1, D3). + +interface CreateResult { wallet: Address; index: number; rulesIds: Hex[]; tx: UniversalTxResponse } +interface WalletSummary { address: Address; index: number; label: string; deployed: boolean; rulesCount: number } +``` + +### 3.b Rules + +```tsx +type Rule = NativeRule | UniversalRule; // chainNamespace decides the rulebook: omitted = native, foreign = universal + +interface NativeRule { + agent: Address; // Push address: EOA, or the UEA of an external key (PushChain.utils.account.deriveExecutorAccount) + ref?: Hex; // emitted in RulesGranted, not interpreted + chainNamespace?: never; // omitted = the connected Push chain + target: Address; + selector: Selector | 'value-only'; + validUntil: number; + maxValuePerCall?: bigint; maxValueTotal?: bigint; maxCalls?: number; + pins?: { arg: number; expected: Hex | Address | bigint }[]; + amount?: { arg: number; maxPerCall: bigint; maxTotal?: bigint }; +} + +interface UniversalRule { + agent: Address; // same as NativeRule.agent + ref?: Hex; // same as NativeRule.ref + chainNamespace: ForeignChainNamespace; // "eip155:..." now; "solana:..." once the SVM rulebook ships + assets: AssetCap[]; // tokens the agent may move on chainNamespace; SDK resolves each to its PRC20 and asserts SOURCE_CHAIN_NAMESPACE + maxGasPerCall: bigint; // PC (wei) per outbound for the destination leg + validUntil: number; + allowedCalls: AllowedCall[]; // 1..32, all on chainNamespace +} + +interface AssetCap { + token: MoveableToken | Address; // the other chain's token address (MOVEABLE.TOKEN..) or the native marker; the contract stores the PRC20 + maxPerCall: bigint; + maxTotal?: bigint; +} + +type Selector = Hex | `${string}(${string})`; // '0x617ba037' or 'supply(address,uint256,address,uint16)' + +interface AllowedCall { target: Address; selector: Selector; beneficiary?: number; maxValue?: bigint } // beneficiary = arg index + +interface RulesRecord { + rulesId: Hex; + enabled: boolean; + chainNamespace: string; + agent: Address; // the Push address granted + validUntil: number; + ref: Hex; + rule: Rule; // decoded terms; NativeRule or UniversalRule + spent: Spent; // carried by rules.get and rules.list; no separate call +} + +type Spent = { kind: 'universal'; amountSpent: bigint } | { kind: 'native'; valueSpent: bigint; amountSpent: bigint; callsUsed: number }; // PROPOSED: one self-describing object, readable without knowing the rulebook +``` + +### 3.c Wallet handle and checkpoints + +```tsx +interface AgenticWallet { + address: Address; + info(): Promise; + owner(): Promise<{ owner: Address }>; // Push address as stored + setLabel(label: string, opts?: { progressHook?: ProgressHook }): Promise; // PROPOSED, page 1 item 10 + checkpoints(opts?: { sinceBlock?: bigint }): Promise<{ checkpoints: Checkpoint[] }>; + rules: { + list(): Promise<{ rules: RulesRecord[] }>; + get(rulesId: Hex): Promise; + add(rules: Rule[], opts?: { progressHook?: ProgressHook }): Promise<{ rulesIds: Hex[]; tx: UniversalTxResponse }>; + update(params: { rules: { rulesId: Hex; rule: Rule }[]; progressHook?: ProgressHook }): Promise<{ rules: { rulesId: Hex; replaced: Hex }[]; tx: UniversalTxResponse }>; // revoke plus grant; spend counters reset + revoke(rulesIds: Hex[], opts?: { progressHook?: ProgressHook }): Promise; + revoke(params: { all: true; progressHook?: ProgressHook }): Promise; + }; +} + +interface WalletInfo { address: Address; label: string; index: number; owner: Address; deployed: boolean; rulesCount: number } + +interface Checkpoint { seq: number; kind: 'OWNER_ACTION' | 'RULES_GRANTED' | 'RULES_REVOKED'; ref: Hex; blockNumber: bigint; txHash: Hex } +``` + +### 3.d Constants, PushChain.CONSTANTS.AGENTIC (new) + +```tsx +PushChain.CONSTANTS.AGENTIC[PUSH_NETWORK.TESTNET_DONUT] = { + FACTORY, RULES_POLICY, // RULES_POLICY is URP; no validator address (page 1, D3) + MAX_PINS: 8, MAX_ALLOWED_CALLS: 32, ENVELOPE_VERSION: 1, +}; +``` + +### 3.e Helpers, PushChain.utils.agentic (new) + +Pure functions with the same output as the on-chain views. + +```tsx +PushChain.utils.agentic = { + rulesId(agent, chainNamespace, grantNonce), // the id a grant produces, same as the contract assigns + actionId(target, selector), // id of one allowed call: hash of its target and selector + configId(wallet, rulesId, actionId), // key of one allowed call's stored config, under one rule on one wallet + encodeRules(rules, ctx), // ctx = wallet and chain context needed to resolve beneficiary offsets + decodeRules(bytes), + deriveWallet(owner, index), // any-owner variant of client.agentic.derive + compileCard(card, userInput, ctx), // used by page 6; lives here because it produces Rule[] +}; +``` + +### 3.f Errors and progress + +```tsx +class AgenticError extends Error { code: string; hint?: string } +class AgenticRevertError extends PushChainExecutionError {} +// decoded custom error from the AGW, URP or the factory; uses core's fields: +// code string +// decodedError { name, hint, selector, decoded } + +// codes +// create: AGENT_IS_OWNER, DUPLICATE_RULE, TARGET_NOT_ON_RULE_CHAIN, ASSET_CHAIN_MISMATCH +// initialize (agenticWallet): NOT_OWNER_OR_AGENT, WALLET_NOT_DEPLOYED, NOT_AGENTIC_WALLET +// rules.revoke: REVOKE_NEEDS_TARGET (bare revoke) +// sendTransaction: NO_RULES_FOR_CHAIN, FROM_NOT_ALLOWED (any from, Routes 3 and 4) +// agentic mode: NOT_ALLOWED_IN_AGENTIC_MODE (prepareTransaction, executeTransactions, payGasWith, migrateCEA, rescueFunds) + +// progress events, AGENTIC-TX (PROPOSED) +// AGENTIC-TX-101 wallet derived { address, index, deployed } +// AGENTIC-TX-102 deploy step added +// AGENTIC-TX-104 rules granted { rulesIds } +// AGENTIC-TX-105 rules revoked { rulesIds | all } +// AGENTIC-TX-106 label set +// AGENTIC-TX-107 rule resolved for a send { rulesId, chainNamespace, door } +// AGENTIC-TX-199-01 done +// AGENTIC-TX-199-02 failed { code, decodedError } +// The Push leg of any agentic send also emits core's SEND-TX-1xx events. +// A cross-chain leg sent by the AGW emits 209-xx and 299-xx, never 201 to 204 (the signer's own Route 2 is never used). +``` + +**PROPOSED:** the AGENTIC-TX event list. Every write (`create`, `setLabel`, `rules.add`, `rules.update`, `rules.revoke`) takes a per-call `progressHook`; a `progressHook` passed to `PushChain.initialize` runs alongside it, as in core. + +`NO_RULES_FOR_CHAIN` is thrown before any signature and costs nothing. The rules lookup is one read on every send, not cached at initialize. A URP revert is thrown from `sendTransaction` as `AgenticRevertError` and also lands as `decodedError` on AGENTIC-TX-199-02. A destination-chain revert after URP passed still counts the spend, because the spend is counted when the outbound leaves Push; whether it is credited back depends on [1. AGW Contract Changes (nomenclature standard + change set)](1-agw-contract-changes.md) item 6 (`creditRevert`). + +# 4. Outside change: [PushChain.CONSTANTS.READ](http://PushChain.CONSTANTS.READ).CHAIN (confirmed 2026-09-28) + +Problem: `read()` takes `chain: PushChain.CONSTANTS.CHAIN.X`, but `CHAIN` is the set of blockchains the SDK signs for and routes to. Web2 is not one, so `CHAIN.WEB2` exists as a hidden (non-enumerable) member: it works if you know it is there and never appears in any listing. Reads have a wider domain than transactions: anything validators can observe. + +Change: a read-specific constant that is a superset of `CHAIN`. The field name stays `chain`, so nothing breaks, and `CHAIN` values remain valid because the strings are identical. + +```tsx +PushChain.CONSTANTS.READ.CHAIN = { + ...PushChain.CONSTANTS.CHAIN, // every real chain, same string values + WEB2: 'web2', // non-chain source, first-class here, enumerable +}; +type ReadChain = CHAIN | 'web2'; // ReadParams.chain: ReadChain + +read({ chain: PushChain.CONSTANTS.READ.CHAIN.WEB2, ... }) +read({ chain: PushChain.CONSTANTS.CHAIN.ETHEREUM_SEPOLIA, ... }) // still compiles +``` + +- `CHAIN.WEB2` becomes a deprecated alias of `READ.CHAIN.WEB2` for one release (the docs listed it on 2026-09-22), then goes. +- Anything that iterates `CHAIN` stops seeing a fake chain; anything that iterates `READ.CHAIN` sees every read source. +- The evaluator's `Read.chain` (page 8) takes the same values, so `READ.CHAIN` is the one constant the read SDK and the criteria compiler share. + +# 5. Open for review + +1. `rules.update` resets spend counters because it is revoke plus grant. Accepted for v1 and stated in 1.l; an in-place update is a contract change with no demand yet. +2. `setLabel` assumes [1. AGW Contract Changes (nomenclature standard + change set)](1-agw-contract-changes.md) item 10 lands. Pointer for the team. \ No newline at end of file diff --git a/plan/agw/research/section6-feedback-2026-10-12/sdk.diff b/plan/agw/research/section6-feedback-2026-10-12/sdk.diff new file mode 100644 index 00000000..2fc36e41 --- /dev/null +++ b/plan/agw/research/section6-feedback-2026-10-12/sdk.diff @@ -0,0 +1,695 @@ +--- previous/5-sdk-agw.md ++++ latest/5-sdk-agw.md +@@ -30,7 +30,7 @@ + - `rules.update`, + - `rules.revoke` + - `PushChain.CONSTANTS.AGENTIC` +-- `PushChain.utils.agentic` ++- `~~PushChain.utils.agentic~~` (dropped 12 Oct 2026, see 6.h) + + Updated + +@@ -144,7 +144,7 @@ + + Under the hood this is `deployWallet` (or reuse of a derived address) and one `grantRules` per rule. For an external owner they go as one UEA multicall under one signature. Funding is not part of `create`: the wallet is a normal Push account, so send tokens and PC to its address the way you would to any account (1.a shows the address before deployment). + +-For a Push EOA owner the same thing needs a batching entry on the factory, because core rejects multicall from a Push-native sender: [1. AGW Contract Changes (nomenclature standard + change set)](1-agw-contract-changes.md) item 11, **PROPOSED** (`createWallet(label, rules[])` on the factory). Until it lands the SDK sends deploy and grant as separate transactions and says so through progress events (AGENTIC-TX-102 and 104); `tx` is then the last of them. ++For a Push EOA owner the same thing needs a batching entry on the factory, because core rejects multicall from a Push-native sender: [1. AGW Contract Changes (nomenclature standard + change set)](https://app.notion.com/p/1-AGW-Contract-Changes-nomenclature-standard-change-set-3e9188aea7f4813aa31fc95ceb4e684d?pvs=21) item 11, **PROPOSED** (`createWallet(label, rules[])` on the factory). Until it lands the SDK sends deploy and grant as separate transactions and says so through progress events (AGENTIC-TX-102 and 104); `tx` is then the last of them. + + A `progressHook` passed to `PushChain.initialize` receives the same events alongside the per-call one, as in core. + +@@ -248,7 +248,7 @@ + + ### 1.g Set the wallet label - `w.setLabel` + +-**PROPOSED**, contract change, see [1. AGW Contract Changes (nomenclature standard + change set)](1-agw-contract-changes.md) item 10. Changes the label shown in `list()` and `info()`; owner only. ++**PROPOSED**, contract change, see [1. AGW Contract Changes (nomenclature standard + change set)](https://app.notion.com/p/1-AGW-Contract-Changes-nomenclature-standard-change-set-3e9188aea7f4813aa31fc95ceb4e684d?pvs=21) item 10. Changes the label shown in `list()` and `info()`; owner only. + + ```tsx + // Function +@@ -480,7 +480,7 @@ + + Which door the client uses depends on who the signer is. If the signer is the wallet's owner, sends go through the owner door: no rules, and every send is recorded as a checkpoint. If the signer is an address named as agent in one of the wallet's rules, sends go through the agent door and the rules apply. If it is neither, `initialize` throws `NOT_OWNER_OR_AGENT`. If the address has no wallet deployed yet it throws `WALLET_NOT_DEPLOYED`, and if the address is not an agentic wallet it throws `NOT_AGENTIC_WALLET`. This is also how an owner acts as the wallet with the full client: `PushChain.initialize(ownerSigner, { agenticWallet })`. There is one way to send as a wallet and the signer decides the door. + +-On the agent door the SDK sends; URP on-chain is the only rule checker. Before sending, the SDK only looks up the `rulesId` for the destination chain: the rule that is enabled, whose `agent` equals the signer, and whose `chainNamespace` equals the destination. The lookup is one read on every send, not cached at initialize. If none is found it throws `NO_RULES_FOR_CHAIN` before any signature, so it costs nothing; otherwise it calls `executeAsAgent(rulesId, ...)` on the wallet. That is the agent door from D3 on [1. AGW Contract Changes (nomenclature standard + change set)](1-agw-contract-changes.md): there is no session validator, and the wallet only checks that `msg.sender` is the rule's agent. There is one rule per (agent, chain), so a signer and a destination match at most one rule. If the action breaks a rule, it reverts on-chain and the agent pays that gas. `sendTransaction` then throws `AgenticRevertError`, which extends core's `PushChainExecutionError` and carries URP's custom error in `decodedError`, so the agent sees which gate failed (3.f). ++On the agent door the SDK sends; URP on-chain is the only rule checker. Before sending, the SDK only looks up the `rulesId` for the destination chain: the rule that is enabled, whose `agent` equals the signer, and whose `chainNamespace` equals the destination. The lookup is one read on every send, not cached at initialize. If none is found it throws `NO_RULES_FOR_CHAIN` before any signature, so it costs nothing; otherwise it calls `executeAsAgent(rulesId, ...)` on the wallet. That is the agent door from D3 on [1. AGW Contract Changes (nomenclature standard + change set)](https://app.notion.com/p/1-AGW-Contract-Changes-nomenclature-standard-change-set-3e9188aea7f4813aa31fc95ceb4e684d?pvs=21): there is no session validator, and the wallet only checks that `msg.sender` is the rule's agent. There is one rule per (agent, chain), so a signer and a destination match at most one rule. If the action breaks a rule, it reverts on-chain and the agent pays that gas. `sendTransaction` then throws `AgenticRevertError`, which extends core's `PushChainExecutionError` and carries URP's custom error in `decodedError`, so the agent sees which gate failed (3.f). + + From an external key, the call arrives through the agent's UEA. If the agent's UEA is not yet deployed, the first action takes the origin-chain fee lock once (minimum $1), which deploys the UEA and funds it with PC. Every later action requires PC in the UEA and is a direct Push transaction paid from that balance, with no origin transaction and no cross-chain wait. + +@@ -646,7 +646,9 @@ + interface Checkpoint { seq: number; kind: 'OWNER_ACTION' | 'RULES_GRANTED' | 'RULES_REVOKED'; ref: Hex; blockNumber: bigint; txHash: Hex } + ``` + +-### 3.d Constants, PushChain.CONSTANTS.AGENTIC (new) ++### ~~3.d Constants, PushChain.CONSTANTS.AGENTIC (new)~~ ++ ++Dropped on 12 Oct 2026, except `WALLET`. See 6.h. + + ```tsx + PushChain.CONSTANTS.AGENTIC[PUSH_NETWORK.TESTNET_DONUT] = { +@@ -655,9 +657,11 @@ + }; + ``` + +-### 3.e Helpers, PushChain.utils.agentic (new) +- +-Pure functions with the same output as the on-chain views. ++### ~~3.e Helpers, PushChain.utils.agentic (new)~~ ++ ++Dropped on 12 Oct 2026. See 6.h. ++ ++~~Pure functions with the same output as the on-chain views.~~ + + ```tsx + PushChain.utils.agentic = { +@@ -702,7 +706,7 @@ + + **PROPOSED:** the AGENTIC-TX event list. Every write (`create`, `setLabel`, `rules.add`, `rules.update`, `rules.revoke`) takes a per-call `progressHook`; a `progressHook` passed to `PushChain.initialize` runs alongside it, as in core. + +-`NO_RULES_FOR_CHAIN` is thrown before any signature and costs nothing. The rules lookup is one read on every send, not cached at initialize. A URP revert is thrown from `sendTransaction` as `AgenticRevertError` and also lands as `decodedError` on AGENTIC-TX-199-02. A destination-chain revert after URP passed still counts the spend, because the spend is counted when the outbound leaves Push; whether it is credited back depends on [1. AGW Contract Changes (nomenclature standard + change set)](1-agw-contract-changes.md) item 6 (`creditRevert`). ++`NO_RULES_FOR_CHAIN` is thrown before any signature and costs nothing. The rules lookup is one read on every send, not cached at initialize. A URP revert is thrown from `sendTransaction` as `AgenticRevertError` and also lands as `decodedError` on AGENTIC-TX-199-02. A destination-chain revert after URP passed still counts the spend, because the spend is counted when the outbound leaves Push; whether it is credited back depends on [1. AGW Contract Changes (nomenclature standard + change set)](https://app.notion.com/p/1-AGW-Contract-Changes-nomenclature-standard-change-set-3e9188aea7f4813aa31fc95ceb4e684d?pvs=21) item 6 (`creditRevert`). + + # 4. Outside change: [PushChain.CONSTANTS.READ](http://PushChain.CONSTANTS.READ).CHAIN (confirmed 2026-09-28) + +@@ -728,4 +732,621 @@ + # 5. Open for review + + 1. `rules.update` resets spend counters because it is revoke plus grant. Accepted for v1 and stated in 1.l; an in-place update is a contract change with no demand yet. +-2. `setLabel` assumes [1. AGW Contract Changes (nomenclature standard + change set)](1-agw-contract-changes.md) item 10 lands. Pointer for the team.+2. `setLabel` assumes [1. AGW Contract Changes (nomenclature standard + change set)](https://app.notion.com/p/1-AGW-Contract-Changes-nomenclature-standard-change-set-3e9188aea7f4813aa31fc95ceb4e684d?pvs=21) item 10 lands. Pointer for the team. ++ ++# 6. Changes proposed on 12 Oct 2026 ++ ++These come from the review of the first SDK implementation, [push-chain-sdk PR #291](https://github.com/pushchain/push-chain-sdk/pull/291). Sections 1 to 5 above are left exactly as they were. Where an entry here differs from them, the entry here is the current one. Every function whose call or result changes is written out again in full, so the change can be read without scrolling up. ++ ++Contract changes are written on [1. AGW Contract Changes (nomenclature standard + change set)](https://app.notion.com/p/1-AGW-Contract-Changes-nomenclature-standard-change-set-3e9188aea7f4813aa31fc95ceb4e684d?pvs=21) (page 1), section 6, and are referenced from here by item number. ++ ++| # | Change | Replaces above | Contract change (page 1) | ++| --- | --- | --- | --- | ++| 6.a | One rule shape for every chain, pins inside `allowedCalls`, `beneficiary` folded into pins | 3.b `NativeRule`, `UniversalRule` | 6.3 | ++| 6.b | `create` is one transaction for every owner; `ref` removed; omitted caps are 0 | 1.b | 6.2, 6.4, 6.5 | ++| 6.c, 6.d | `rules.list` and `rules.get`: `spent` per asset, no `ref`, arguments read back as `arg` | 1.i, 1.j | none | ++| 6.e | `rules.add` and `rules.update`: call unchanged, new rule shape | 1.k, 1.l | none | ++| 6.f | `setLabel` is never a checkpoint | 1.g | none | ++| 6.g | Sending as the wallet: no gateway approval step, first-use gas default | 2.a | 6.1 | ++| 6.h | Types, as they end up | 3.b, `RulesRecord`, `Spent`, 3.d, 3.e | none | ++| 6.i | Solana: same rule shape, pins on arguments and on accounts, no IDL in a rule | new | none | ++| 6.l | Response fields and error codes added by the first implementation: accepted, with four codes removed | 3.f | none | ++| 6.m | `rules.revoke` is renamed `rules.delete` | 1.m | none | ++ ++### 6.a One rule shape for every chain ++ ++There is one rule shape. A rule for calls on Push is the same object as a cross-chain rule with `chainNamespace` left out. What the agent may call is always a list of `allowedCalls`, and restrictions on a function's arguments sit inside each allowed call as `pins`. ++ ++A pin restricts one argument of the allowed function. It is either `expected` (the argument must equal this constant) or `max` (the argument must not exceed this number). To require that an argument is the wallet itself, the expected value is `PushChain.CONSTANTS.AGENTIC.WALLET`. A minimum on an argument (for example a minimum amount out on a swap) is not part of v1 and is deferred to the next version. ++ ++```tsx ++// a rule on Push: chainNamespace left out ++{ ++ agent: '0xAgentOnPush', ++ validUntil: now + 30 * 86400, ++ allowedCalls: [ ++ { target: vault, selector: 'deposit(address,uint256)', ++ pins: [ ++ { arg: 0, expected: beneficiary }, // argument 0 must be this address ++ { arg: 1, max: parseUnits('10', 18) }, // argument 1 must not exceed this, per call ++ ] }, ++ ], ++} ++ ++// a rule on Ethereum Sepolia: same shape, plus the tokens the agent may move ++{ ++ agent: '0xAgentOnPush', ++ chainNamespace: CHAIN.ETHEREUM_SEPOLIA, ++ assets: [ ++ { token: MOVEABLE.TOKEN.ETHEREUM_SEPOLIA.USDC, maxPerCall: parseUnits('100', 6), maxTotal: parseUnits('1000', 6) }, ++ ], ++ maxGasPerCall: parseUnits('1', 18), ++ validUntil: now + 30 * 86400, ++ allowedCalls: [ ++ { target: aavePool, selector: 'supply(address,uint256,address,uint16)', ++ pins: [ ++ { arg: 0, expected: usdcSepolia }, // asset must be USDC ++ { arg: 2, expected: PushChain.CONSTANTS.AGENTIC.WALLET }, // onBehalfOf must be this wallet ++ ] }, ++ { target: usdcSepolia, selector: 'approve(address,uint256)' }, ++ ], ++} ++``` ++ ++What is gone from the shape: the separate `NativeRule` type with `target`, `selector`, `pins` and `amount` at the top of the rule, and the fields `amount.maxTotal`, `maxValueTotal` and `maxCalls`. A `max` pin limits each call only. The SDK has no per-argument lifetime total and no call counter. On a cross-chain rule the lifetime limit on a token is the asset's `maxTotal`. On a Push call the lifetime limit is what the owner funds the wallet with, plus `validUntil`. ++ ++`beneficiary` is now a pin. On page sections above, `beneficiary: 2` meant that argument 2 must be the wallet's own account. That is a pin whose expected value is the wallet, so it is written as `{ arg: 2, expected: PushChain.CONSTANTS.AGENTIC.WALLET }` and the separate field is removed. `WALLET` stands for the wallet's own account on the rule's chain: the AGW address for a call on Push, and the wallet's CEA for a call on another chain. The SDK fills in the real address when the rule is granted, so nobody has to look up a CEA. It is a marker and not an address (its value is the string `'agentic:wallet'`), because an agent card lists its rules before any wallet exists. On read, a pin whose stored value is the wallet's own account comes back as `WALLET`. ++ ++Where each part is checked. Every check runs on Push, in the rules policy, before the wallet is allowed to make the call or hand it to the gateway. ++ ++| On an allowed call | Call on Push | Call on an EVM destination | ++| --- | --- | --- | ++| `target`, `selector`, `maxValue` | Checked | Checked | ++| A pin with `expected: WALLET` | Checked | Checked. One per call until page 1, 6.3 lands | ++| Any other pin | Checked. Up to 8 `expected` pins and one `max` pin per call | Needs page 1, 6.3. Until it lands the SDK rejects it before signing | ++ ++### 6.b Create an agentic wallet - `client.agentic.create` (changed) ++ ++Deploys the wallet and grants the rules in one transaction, for every kind of owner. Either the wallet exists with every rule that was passed, or nothing happened. ++ ++```tsx ++// Function ++const created = await client.agentic.create(label, { options }) ++ ++// Usage and Params ++const created = await client.agentic.create('aave-optimiser', { // wallet with one cross-chain rule ++ rules: [{ // one entry per chain per agent ++ agent: '0xAgentOnPush', // a Push address: the agent's EOA, or its UEA if the key lives on another chain. Never the owner ++ chainNamespace: CHAIN.ETHEREUM_SEPOLIA, // left out = a rule for calls on Push ++ assets: [ ++ { token: MOVEABLE.TOKEN.ETHEREUM_SEPOLIA.USDC, maxPerCall: parseUnits('100', 6), maxTotal: parseUnits('1000', 6) }, ++ { token: MOVEABLE.TOKEN.ETHEREUM_SEPOLIA.WETH, maxPerCall: parseUnits('0.5', 18), maxTotal: parseUnits('2', 18) }, ++ ], ++ maxGasPerCall: parseUnits('1', 18), // PC (wei) per outbound for the destination leg ++ validUntil: now + 30 * 86400, ++ allowedCalls: [ ++ { target: aavePool, selector: 'supply(address,uint256,address,uint16)', ++ pins: [{ arg: 2, expected: PushChain.CONSTANTS.AGENTIC.WALLET }] }, // onBehalfOf must be this wallet (its CEA on Sepolia) ++ { target: usdcSepolia, selector: 'approve(address,uint256)' }, ++ ], ++ }], ++ progressHook: (p) => console.log(p.id, p.message), // AGENTIC-TX-1xx ++}); ++const bare = await client.agentic.create('scratch', { rules: [] }); // wallet first, rules later with rules.add ++// label string, required shown in list() and info(); the contract stores it ++// options.rules Rule[], required one per chain per agent, may be empty; shape in 6.a ++// options.progressHook function, optional progress events, AGENTIC-TX-1xx; default none ++// rules[].agent Address, required the Push address allowed to act under this rule; never the owner ++// rules[].chainNamespace string, optional the chain the rule governs; left out = Push ++// rules[].assets AssetCap[], cross-chain rules tokens the agent may move; each cap is { token, maxPerCall, maxTotal } ++// rules[].assets[].maxTotal bigint, optional lifetime cap for that token; left out = 0, and 0 means the agent cannot move it ++// rules[].maxGasPerCall bigint, cross-chain rules PC (wei) the wallet may spend per outbound for the destination leg ++// rules[].allowedCalls AllowedCall[], required what the agent may call; each is { target, selector, pins?, maxValue? } ++// rules[].allowedCalls[].maxValue bigint, optional native coin per call; left out = 0 ++// rules[].allowedCalls[].pins Pin[], optional { arg, expected } or { arg, max }; expected may be PushChain.CONSTANTS.AGENTIC.WALLET; see 6.a ++ ++// Returns ++// { wallet, index, rulesIds, tx } ++{ ++ wallet: '0x2Fd904d6f2C0b34d58426C8Ae9c5267E845CE98f', ++ index: 0, ++ rulesIds: ['0x9c1e...'], // in the order of the rules you passed; empty for rules: [] ++ tx: { // UniversalTxResponse, always a single transaction ++ hash: '0xb527...', ++ origin: 'eip155:11155111:0x31dC...', // the owner's key, CAIP-10 ++ from: '0xFd6C2fE69bE13d8bE379CCB6c9306e74193EC1A9', // the owner's Push account ++ blockNumber: 1290n, ++ wait // await tx.wait() for the receipt; status lives on the receipt ++ } ++} ++``` ++ ++What changed from 1.b: ++ ++- **One transaction for every owner.** 1.b said a Push EOA owner gets separate deploy and grant transactions until a factory entry lands. That fallback is removed. The factory entry is page 1, 6.2. There is no partial result to reconcile. ++- **`ref` is removed** from every rule. The `rulesId` the grant returns is what a job, a card or an indexer latches on to. Page 1, 6.4. ++- **A cap that is left out is 0, never unlimited.** That covers `assets[].maxTotal` and `allowedCalls[].maxValue`. A forgotten cap means the agent cannot move that asset, which shows up on the first send. Page 1, 6.5. Note that the WETH line in 1.b had no `maxTotal`; under this rule it would move nothing, so the example here sets one. ++- **Rules use the single shape from 6.a.** ++- **The beneficiary field is a pin.** `beneficiary: 2` is written as a pin on argument 2 whose expected value is `PushChain.CONSTANTS.AGENTIC.WALLET` (6.a). ++ ++### 6.c List rules - `w.rules.list` (changed) ++ ++Returns every enabled rule on the wallet as a decoded record, including what each rule has spent so far. ++ ++```tsx ++// Function ++const res = await w.rules.list() ++ ++// Usage and Params ++const { rules } = await w.rules.list(); // the wallet's rules ++// no params ++ ++// Returns ++// { rules: RulesRecord[] } ++{ ++ rules: [ ++ { ++ rulesId: '0x9c1e...', ++ enabled: true, ++ chainNamespace: 'eip155:11155111', ++ agent: '0xAgentOnPush', ++ validUntil: 1767225600, ++ rule: { /* the rule in the 6.a shape, accepted as is by rules.update */ }, ++ spent: { // one entry per asset, same order as rule.assets ++ kind: 'universal', ++ assets: [ ++ { token: '0x1c7D...7238', spent: 25000000n }, // USDC ++ { token: '0xfFf9...6B14', spent: 0n }, // WETH ++ ] ++ } ++ } ++ ] ++} ++``` ++ ++### 6.d Get one rule - `w.rules.get` (changed) ++ ++Returns one rule by id, decoded, with what it has spent. ++ ++```tsx ++// Function ++const record = await w.rules.get(rulesId) ++ ++// Usage and Params ++const record = await w.rules.get('0x9c1e...'); // one rule by id ++// rulesId Hex, required the id returned by create or rules.add ++ ++// Returns ++// RulesRecord ++{ ++ rulesId: '0x51c0...', ++ enabled: true, ++ chainNamespace: 'eip155:42101', // a rule on Push ++ agent: '0xAgentOnPush', ++ validUntil: 1767225600, ++ rule: { ++ agent: '0xAgentOnPush', ++ validUntil: 1767225600, ++ allowedCalls: [ ++ { target: '0xVault', selector: 'deposit(address,uint256)', ++ pins: [ ++ { arg: 0, expected: '0x00000000000000000000000000000000000000000000000000000000000b0b0b' }, ++ { arg: 1, max: 10000000000000000000n }, ++ ] }, ++ ], ++ }, ++ spent: { kind: 'native', valueSpent: 0n, amountSpent: 5000000000000000000n, callsUsed: 1 } ++} ++``` ++ ++What changed from 1.i and 1.j: ++ ++- **`spent` is on every record**, as 1.i and 1.j already said. The first implementation dropped it; it goes back. For a cross-chain rule it is now a list with one entry per asset, because each asset has its own budget. 1.i showed a single `amountSpent`, which predates per-asset budgets. ++- **`ref` is removed** from the record, following 6.b. ++- **Arguments read back as `arg`, never as a byte offset.** The contract stores a pin and a beneficiary as a byte position in the calldata (argument 0 is byte 4, argument 1 is byte 36). The SDK converts that back, so a developer who wrote `arg: 0` reads `arg: 0`. A pin on the wallet itself reads back as `WALLET`. ++- **The record is accepted by `rules.update` without edits.** The test is: read a rule, change `validUntil`, pass it back. An `expected` value reads back as 32-byte hex, because the contract keeps the function selector and not the argument types; it is accepted as input in that form. ++ ++### 6.e Add and update rules - `w.rules.add`, `w.rules.update` (call unchanged) ++ ++The calls and results in 1.k and 1.l stay as they are. Two things change through the rule itself: rules are in the 6.a shape, and they carry no `ref`. ++ ++### 6.f Set the wallet label - `w.setLabel` (changed) ++ ++Changes the label shown in `list()` and `info()`. Owner only. ++ ++```tsx ++// Function ++const tx = await w.setLabel(label, { options? }) ++ ++// Usage and Params ++const tx = await w.setLabel('aave-optimiser-v2'); // rename the wallet ++const reset = await w.setLabel(''); // back to the default label ++const tracked = await w.setLabel('aave-optimiser-v2', { progressHook: (p) => console.log(p.id) }); // with progress events ++// label string, required the new label, at most 64 bytes of UTF-8; an empty string resets it to the default "AGW " ++// options.progressHook function, optional progress events, AGENTIC-TX-106; default none ++ ++// Returns ++// { hash, origin, from, to, blockNumber, wait() } ++{ ++ hash: '0x3b8d...', ++ origin: 'eip155:11155111:0x31dC...', // the owner's key, CAIP-10 ++ from: '0xFd6C2fE69bE13d8bE379CCB6c9306e74193EC1A9', // the owner's Push account ++ to: '0x2Fd904d6f2C0b34d58426C8Ae9c5267E845CE98f', // the wallet ++ blockNumber: 1488n, ++ wait // await tx.wait() for the receipt; status lives on the receipt ++} ++``` ++ ++What changed from 1.g: the function is live in the contract, so it is no longer proposed. The rule that a rename is not a checkpoint now binds the SDK too. The first implementation sent the rename through the owner door, and every owner door call records an `OWNER_ACTION` checkpoint. With the checkpoint rule for 8183 jobs, a user who renamed a wallet during a job would hand the fee to the agent over a label. The SDK must call the wallet's `setLabel` directly, for a Push EOA owner and for a UEA owner, so that the checkpoint count is the same before and after a rename. ++ ++### 6.g Send as the wallet - `sendTransaction` with `agenticWallet` (changed) ++ ++The call is the one in 2.a. Two things around it change. ++ ++```tsx ++// Function ++const tx = await client.universal.sendTransaction({ options }) ++ ++// Usage and Params ++const agentClient = await PushChain.initialize(agentSigner, { // agent door: the signer is named as agent in a rule ++ network: PushChain.CONSTANTS.PUSH_NETWORK.TESTNET, ++ agenticWallet: '0xWallet', ++}); ++const tx = await agentClient.universal.sendTransaction({ // rule picked by the destination chain ++ to: { address: aavePool, chain: CHAIN.ETHEREUM_SEPOLIA }, ++ data: [ ++ { to: usdcSepolia, value: 0n, data: approveData }, ++ { to: aavePool, value: 0n, data: supplyData }, ++ ], ++ funds: { amount: parseUnits('100', 6), token: MOVEABLE.TOKEN.ETHEREUM_SEPOLIA.USDC }, ++}); ++// to { address, chain }, required the destination call and its chain ++// data Hex or call array, optional the destination call data ++// funds { amount, token }, optional the token the wallet moves with this send ++// gasLimit bigint, optional destination gas; left out = the SDK default, which covers first use on a chain (see below) ++ ++// Returns ++// { hash, origin, from, blockNumber, wait() } ++{ ++ hash: '0x6f2a...', ++ origin: 'eip155:11155111:0x7Be1...', // the agent's key, CAIP-10 ++ from: '0xWallet', // the AGW, not the signer ++ blockNumber: 1530n, ++ wait ++} ++``` ++ ++What changed from 2.a: ++ ++- **No gateway approval step.** When the wallet sends a token to another chain, the gateway on Push takes the token out of the wallet, which needs an ERC20 approval from the wallet. The first implementation left that to the owner as a separate transaction through the owner door before the agent's first send. That step is removed: the wallet approves the exact amount inside its own outbound call (page 1, 6.1). Funding a wallet is two plain transfers to its address, PC and the token. The SDK has no allowance check and no allowance error. ++- **The default destination gas covers first use on a chain.** The first time a wallet sends to a chain, its account there (the CEA) is deployed as part of the call, which took about 1.3 million gas on Sepolia against a core default of 500,000. When the CEA is not deployed yet and the caller gave no `gasLimit`, the SDK uses a first-use default large enough for the deployment. When the CEA exists, the normal default applies. A `gasLimit` from the caller always wins, and `maxGasPerCall` on the rule still bounds what the agent can spend. ++ ++### 6.h Types, as they end up ++ ++These replace `NativeRule`, `UniversalRule`, `AllowedCall`, `RulesRecord` and `Spent` in 3.b. Everything else in section 3 stands. ++ ++```tsx ++interface Rule { ++ agent: Address; // Push address: EOA, or the UEA of an external key ++ chainNamespace?: ChainNamespace; // left out = the connected Push chain ++ validUntil: number; ++ assets?: AssetCap[]; // cross-chain rules: tokens the agent may move on chainNamespace ++ maxGasPerCall?: bigint; // cross-chain rules: PC (wei) per outbound for the destination leg ++ allowedCalls: AllowedCall[]; // 1..32 ++} ++ ++interface AssetCap { ++ token: MoveableToken | Address; // the other chain's token address, or the native marker ++ maxPerCall: bigint; ++ maxTotal?: bigint; // left out = 0; 0 means the agent cannot move this token ++} ++ ++interface AllowedCall { ++ target: Address | string; // a contract; on Solana, the program address ++ selector: Selector | 'value-only'; // on Solana, the instruction name with its argument types ++ pins?: Pin[]; ++ maxValue?: bigint; // native coin per call; left out = 0 ++} ++ ++type Pin = ++ | { arg: number; expected: Hex | Address | bigint | WalletMarker } // the argument must equal this constant, or be the wallet itself ++ | { arg: number; max: bigint } // the argument must not exceed this ++ | { account: number; expected: string | WalletMarker; token?: MoveableToken | string }; // Solana only: the account at this position must be this address, or the wallet itself; with token, the wallet's token account for that token ++ ++type WalletMarker = typeof PushChain.CONSTANTS.AGENTIC.WALLET; // 'agentic:wallet': the wallet's own account on the rule's chain ++ ++interface RulesRecord { ++ rulesId: Hex; ++ enabled: boolean; ++ chainNamespace: string; ++ agent: Address; ++ validUntil: number; ++ rule: Rule; // accepted as is by rules.update ++ spent: Spent; ++} ++ ++type Spent = ++ | { kind: 'native'; valueSpent: bigint; amountSpent: bigint; callsUsed: number } ++ | { kind: 'universal'; assets: { token: Address; spent: bigint }[] }; // one entry per asset, same order as rule.assets ++``` ++ ++`Checkpoint` in 3.c keeps its `ref` field. That one is the checkpoint's own reference (a rules id or a call hash) and has nothing to do with the rule `ref` removed in 6.b. ++ ++`PushChain.CONSTANTS.AGENTIC` has one member, `WALLET` (6.a). The rest of 3.d (`FACTORY`, `RULES_POLICY`, `MAX_PINS`, `MAX_ALLOWED_CALLS`, `ENVELOPE_VERSION`) is dropped. Contract addresses and limits stay inside the SDK and are not exposed. The first implementation exposes all five on `PushChain.CONSTANTS.AGENTIC`; they are removed. ++ ++`PushChain.utils.agentic` (3.e) is dropped. The ids and the encoders stay inside the SDK, `client.agentic.derive` covers deriving a wallet address, and `compileCard` is left to the marketplace page (page 6). The first implementation exposes `actionId`, `configId` and `decodeRules` on `PushChain.utils.agentic`; they are removed. ++ ++### 6.i Solana, decided for v1 ++ ++A Solana rule uses the same `allowedCalls` and `pins` shape as every other chain (6.a). The separate `allowedInstructions` shape of the first implementation, with an IDL and named accounts and fields, is replaced. ++ ++```tsx ++// a rule on Solana devnet ++{ ++ agent: '0xAgentOnPush', ++ chainNamespace: CHAIN.SOLANA_DEVNET, ++ assets: [ ++ { token: '0x0000000000000000000000000000000000000000', maxPerCall: 10_000n, maxTotal: 20_000n }, // native SOL, in lamports ++ ], ++ maxGasPerCall: parseUnits('1', 18), ++ validUntil: now + 30 * 86400, ++ allowedCalls: [ ++ { target: program, // the program address ++ selector: 'receive_sol(u64)', // instruction name and argument types ++ pins: [ ++ { arg: 0, max: 10_000n }, // the amount ++ { account: 1, expected: recipient }, // account 1 must be this address ++ { account: 2, expected: PushChain.CONSTANTS.AGENTIC.WALLET }, // account 2 must be this wallet (its CEA on Solana) ++ ] }, ++ ], ++} ++``` ++ ++The selector is the instruction's name with its argument types, the same idea as an EVM function signature. It is enough to identify the instruction and to locate each argument, so a rule carries no IDL. A program that does not follow the Anchor naming is written with a raw hex selector, as on EVM. ++ ++A Solana instruction carries two separate lists: its arguments (the values in the instruction data) and its accounts (the addresses it touches, passed beside the data). A pin says which list it means: `arg` is a position in the arguments and `account` is a position in the accounts list, both counted from 0. EVM rules only use `arg`, because an EVM call carries its addresses as arguments. ++ ++Tokens on Solana are not held at the wallet's own address. For each token it holds, the wallet has a separate token account, whose address is derived from the wallet and the token. To require that an account is the wallet's token account for a given token, the pin names the token as well: ++ ++```tsx ++{ account: 1, expected: PushChain.CONSTANTS.AGENTIC.WALLET, token: MOVEABLE.TOKEN.SOLANA_DEVNET.USDT } // account 1 must be this wallet's USDT token account ++``` ++ ++Without `token`, `WALLET` on an account means the wallet's CEA itself, which is where native SOL sits. ++ ++The IDL is still used where it is used today: when the call data for a send is built with `PushChain.utils.helpers.encodeTxData`, where it is passed in place of an ABI. ++ ++Accepted for v1: ++ ++- **A Solana rule reads back in the form it was written.** Positions go in and positions come out, so the read, change, pass back test of 6.d holds for Solana too. ++- **An agent sends one Solana instruction per transaction.** Arrays of instructions are not supported on the agent door. ++- **Only instructions with fixed-size arguments can be put under a rule.** Numbers up to u64, public keys, booleans and fixed-length arrays work, with top-level, non-optional accounts. Lists, strings, optional values and nested structs are rejected before signing. A deposit of an amount works; a routed swap that takes a list of hops does not. ++ ++### 6.j Contract changes these depend on ++ ++All on [1. AGW Contract Changes (nomenclature standard + change set)](https://app.notion.com/p/1-AGW-Contract-Changes-nomenclature-standard-change-set-3e9188aea7f4813aa31fc95ceb4e684d?pvs=21), section 6. ++ ++| Page 1 item | Contract change | Needed by | ++| --- | --- | --- | ++| 6.1 | The wallet approves the gateway for the exact amount inside each outbound | 6.g | ++| 6.2 | One factory call that deploys the wallet and grants its rules | 6.b | ++| 6.3 | Pins on EVM destination calls in the rules policy | 6.a | ++| 6.4 | `ref` removed from `grantRules` | 6.b, 6.c, 6.d | ++| 6.5 | A cap of 0 means nothing moves | 6.b | ++ ++### 6.k Still open ++ ++1. Whether the rules policy can enforce the wallet token account pin of 6.i in every case. To confirm with the contracts owner. ++ ++### 6.l Response fields and error codes added by the first implementation ++ ++The first implementation adds response fields and error codes that are not in 3.f. They are accepted as listed here. Four codes are removed, each for the reason given below. ++ ++**The `agentic` object on a response.** Every send made as the wallet carries an `agentic` object on its response, so the caller can see which wallet, which door and which rule the send used. Only the fields that apply to that send are present. ++ ++```tsx ++// tx.agentic, on the UniversalTxResponse of a send made as the wallet ++{ ++ wallet: '0xWallet', // the AGW ++ door: 'agent', // 'owner' or 'agent' ++ rulesId: '0x9c1e...', // the rule used; agent door only ++ chainNamespace: 'eip155:11155111', // destination chain of a cross-chain send ++ destinationAccount: '0xCEA...', // the wallet's CEA on that chain ++ destinationCalls: [{ to, data, value }], // the ordered calls run on an EVM destination ++ destinationInstruction: { program, data, accounts }, // the instruction run on Solana ++ destinationTransfer: { recipient, token, amount }, // a plain transfer of SOL or a token on Solana ++ nativeCalls: [{ to, data, value }], // the ordered calls of a batch on Push ++ rawTo: '0xWallet', // what the signer's transaction actually called ++ rawData: '0x...' // the calldata it actually carried ++} ++``` ++ ++**Error codes that stay.** All are thrown before anything is signed, unless the row says otherwise. ++ ++| Code | Thrown when | ++| --- | --- | ++| `INDEX_RACE` | Another `create` took the wallet slot first. Nothing was committed; call `create` again | ++| `NOT_WALLET_OWNER` | The signer tries to change a wallet it does not own | ++| `READ_ONLY` | A client with no signer tries to write | ++| `RULE_NOT_FOUND` | The rule id is not an enabled rule on the wallet | ++| `INVALID_RULE` | A rule or a label is malformed, for example a label over 64 bytes | ++| `AMBIGUOUS_RULE` | More than one enabled rule matches the agent and the destination chain. The SDK does not pick one | ++| `RULE_READ_FAILED` | The rules could not be read from the chain, so the SDK does not send | ++| `INCONSISTENT_READ` | Two reads from the chain disagree with each other, so the SDK does not act on them | ++| `AGENT_GAS_INSUFFICIENT` | The agent's own Push account has no PC for gas. The wallet's PC pays for the outbound, not for the agent's gas | ++| `WALLET_BALANCE_INSUFFICIENT` | The wallet does not hold enough PC or enough of the token for the send | ++| `CAPABILITY_UNAVAILABLE` | The network cannot do what was asked, for example a batch as the agent where no atomic batch is available | ++| `RECEIPT_UNAVAILABLE` | After sending: the transaction was submitted but its receipt could not be read. It may still land | ++| `RECEIPT_MISMATCH` | After sending: the receipt does not match what was sent, for example rule ids in a different order | ++ ++**Error codes that are removed.** ++ ++| Code | Why it goes | ++| --- | --- | ++| `CREATE_PARTIAL` | `create` is one transaction (6.b), so it cannot end half done | ++| `GATEWAY_ALLOWANCE_INSUFFICIENT` | The wallet approves the gateway itself (6.g, page 1 item 6.1) | ++| `GENERATION_UNSUPPORTED` | There are no earlier wallet versions to support | ++| `RULE_LIMIT_EXCEEDED` | Only raised by a local preview of a Solana send. The on-chain rules policy is the only rule checker (2.a), so this is not a public code | ++ ++**`DUPLICATE_RULE` is restored.** 3.f lists `DUPLICATE_RULE`: two rules for the same agent and chain are rejected before signing. The first implementation does not have it and only notices the overlap later, when the agent sends (`AMBIGUOUS_RULE`). The check goes back into `create` and `rules.add`. `AMBIGUOUS_RULE` stays for a wallet that already has overlapping rules. ++ ++**Fields on the error classes.** `AgenticError` also carries `details` and `cause`, and both stay. `AgenticRevertError` carries `transactionHashes` and `pendingTransactionHash`, and a returned `tx` carries an `atomic` flag. These three report a write that was split across several transactions. They are removed once every write is a single transaction (6.b). ++ ++The progress events of the first implementation are the ones in 3.f, with nothing added. ++ ++### 6.m Delete rules - `w.rules.delete` (renamed from `w.rules.revoke`) ++ ++Removes some rules by id, or all of them in one atomic call. This is 1.m under a new name. The call shape and the result are unchanged. ++ ++```tsx ++// Function ++const tx = await w.rules.delete(rulesIds, { options? }) ++const tx = await w.rules.delete({ all, progressHook? }) ++ ++// Usage and Params ++const some = await w.rules.delete(['0x9c1e...', '0x7d3a...']); // delete these rules ++const all = await w.rules.delete({ all: true }); // delete every rule on the wallet ++const tracked = await w.rules.delete(['0x9c1e...'], { progressHook: (p) => console.log(p.id) }); // with progress events ++// rulesIds Hex[], required unless all is set the rules to delete ++// options.progressHook function, optional progress events, AGENTIC-TX-105; default none ++// all true, required unless rulesIds given delete every rule on the wallet in one atomic call ++// progressHook function, optional same events, in the { all: true } form; default none ++ ++// Returns ++// { hash, origin, from, to, blockNumber, wait() } ++{ ++ hash: '0x8e01...', ++ origin: 'eip155:11155111:0x31dC...', // the owner's key, CAIP-10 ++ from: '0xFd6C2fE69bE13d8bE379CCB6c9306e74193EC1A9', // the owner's Push account ++ to: '0x2Fd904d6f2C0b34d58426C8Ae9c5267E845CE98f', // the wallet ++ blockNumber: 1512n, ++ wait // await tx.wait() for the receipt; status lives on the receipt ++} ++``` ++ ++What changed from 1.m: ++ ++- **The method is delete, not revoke.** The handle now reads `rules.add`, `rules.update`, `rules.delete`. Delete is also what happens on-chain: the wallet removes the rule from the session engine for good. A deleted rule cannot be switched back on, and granting the same rule again produces a new `rulesId`. ++- **The bare-call error is renamed.** A bare `delete()` still throws. The code is `DELETE_NEEDS_TARGET` (was `REVOKE_NEEDS_TARGET`). ++- **Contract names do not change.** The wallet functions stay `revokeRules` and `revokeAllRules`, the event stays `RulesRevoked`, and the checkpoint kind stays `RULES_REVOKED`. `w.checkpoints()` returns that kind as the contract records it. ++ ++# 7. Changes proposed on 12 Oct 2026: Presets ++ ++A preset is a ready-made set of rules for a common use case, such as trading on popular DEXes. The wallet UI and developers both read presets from the SDK, so there is one source for them. A preset only produces rules. The rules are then passed to `client.agentic.create` in the normal way, and can be edited before that. App ABIs are not part of presets and stay in the wallet UI, because the UI can update them without an SDK release. ++ ++List of changes: ++ ++- New constants: `PushChain.CONSTANTS.AGENTIC.PRESETS.CATEGORY` with `DEXES`, `LENDING` and `PREDICTION`. An app level (`PushChain.CONSTANTS.AGENTIC.PRESETS.APP`) can be added later without changing the functions. ++- New function: `PushChain.utils.agentic.presets.list`, which lists every preset the SDK ships. ++- New function: `PushChain.utils.agentic.presets.get`, which returns the rules for one preset. ++- This brings back `PushChain.CONSTANTS.AGENTIC` members beyond `WALLET` and the `PushChain.utils.agentic` namespace, for presets only. Both were dropped earlier on this page (6.h). ++ ++### 7.a Preset constants - `PushChain.CONSTANTS.AGENTIC.PRESETS` ++ ++```tsx ++PushChain.CONSTANTS.AGENTIC.PRESETS.CATEGORY.DEXES ++PushChain.CONSTANTS.AGENTIC.PRESETS.CATEGORY.LENDING ++PushChain.CONSTANTS.AGENTIC.PRESETS.CATEGORY.PREDICTION ++// later: PushChain.CONSTANTS.AGENTIC.PRESETS.APP. ++``` ++ ++The constants object must be enumerable so that tools which iterate constants can list it. ++ ++### 7.b List available presets - `PushChain.utils.agentic.presets.list` ++ ++Returns every preset the SDK ships, so a UI can show them as cards and a developer can discover them. ++ ++```tsx ++// Function ++const res = PushChain.utils.agentic.presets.list({ options? }) ++ ++// Usage and Params ++const { presets } = PushChain.utils.agentic.presets.list(); // every preset the SDK ships ++// options.type string, optional 'CATEGORY' today, 'APP' later; omit to list everything ++ ++// Returns ++// { presets: Preset[] } ++{ ++ presets: [ ++ { ++ type: 'CATEGORY', // later 'APP' ++ constant: PushChain.CONSTANTS.AGENTIC.PRESETS.CATEGORY.DEXES, ++ name: 'Popular DEXes', ++ chains: ['eip155:11155111', 'eip155:84532'] // chains this preset has rules for (Ethereum Sepolia, Base Sepolia) ++ } ++ ] ++} ++``` ++ ++A preset with an empty `chains` list has nothing behind it yet (`PREDICTION` today, since its main apps are on a chain Push does not support yet), and the wallet UI should hide it. ++ ++### 7.c Get the rules of a preset - `PushChain.utils.agentic.presets.get` ++ ++Returns one rule per chain for the chosen preset. Each rule already contains the allowed contracts, the allowed calls with their full signatures, and the pins that keep funds going back to the wallet. The agent, assets and expiry are optional: pass them to get rules that are ready for `create`, or leave them out to pre-fill a review screen and add them later. ++ ++```tsx ++// Function ++const res = PushChain.utils.agentic.presets.get(preset, { options? }) ++ ++// Usage and Params ++const { rules } = PushChain.utils.agentic.presets.get( ++ PushChain.CONSTANTS.AGENTIC.PRESETS.CATEGORY.DEXES, // a category constant now, an app constant later ++ { ++ chainNamespace: PushChain.CONSTANTS.CHAIN.ETHEREUM_SEPOLIA, // optional, omit to get every chain of the preset ++ agent: '0xAgentOnPush', // optional, the agent's Push address, applied to every rule ++ assets: [{ chainNamespace, token, maxPerCall, maxTotal }], // optional, each asset is placed on the rule of its chain ++ validUntil: now + 30 * 86400, // optional, applied to every rule; omit to set it later ++ } ++); ++ ++await client.agentic.create('My DEX agent', { rules }); ++ ++// Returns ++// { rules: Rule[] }, one rule per chain, in the same shape client.agentic.create takes ++{ ++ rules: [ ++ { ++ agent: '0xAgentOnPush', ++ chainNamespace: 'eip155:11155111', ++ assets: [{ token: '0x1c7D...7238', maxPerCall: 100000000n, maxTotal: 1000000000n }], // from options.assets, without its chainNamespace ++ validUntil: 1767225600, ++ allowedCalls: [ ++ { ++ target: '0x...', ++ selector: 'exactInputSingle((address,address,uint24,address,uint256,uint256,uint160))', ++ pins: [{ arg: 3, expected: PushChain.CONSTANTS.AGENTIC.WALLET }], ++ app: 'Uniswap V3', // display only, ignored by create ++ label: 'Swap exact input' // display only, ignored by create ++ } ++ // plus one approve(address,uint256) per asset, spender pinned to the app's contract (see Behaviour) ++ ] ++ } ++ ] ++} ++``` ++ ++**Behaviour** ++ ++| Case | What happens | ++| --- | --- | ++| `chainNamespace` omitted | One rule is returned for every chain the preset covers. | ++| `agent`, `assets` or `validUntil` omitted | The rule is returned without that field. The caller adds it before `create`, and `create` rejects a rule with no agent as it already does. | ++| `assets` passed | Each asset is placed on the rule of its chain. If `chainNamespace` is set in the options, the `chainNamespace` on each asset can be left out. For each asset, an approve call is added to that rule, with the spender pinned to the app's contract on that chain, because a swap or deposit fails without it. | ++| Asset passed without a cap | Proposed: `get` throws. An omitted cap means 0 in the rules policy, so the rule would allow nothing, and a preset should never silently produce a rule that cannot act. | ++| Selectors | Always the full signature, never the bare name, because apps overload function names (for example two different execute functions on the same router). | ++| Grouping | One rule per chain per category, not one rule per app. Each category stays at two or three apps per chain so the rule stays inside the 32 allowed calls limit of a universal rule. | ++| Display fields | `app` and `label` on each allowed call are for showing names in a UI. `create` ignores them. | ++ ++### 7.d Notes for the wallet UI ++ ++- Call `get` with only the preset to pre-fill the review screen, then let the user add the agent, tokens, limits and expiry. ++- A blank limit shown as infinity in the UI must be sent as an explicit maximum value. Leaving the cap out means 0, not unlimited. ++- The preset data (contract addresses, calls and pins) ships inside the SDK. An app upgrade becomes a new app entry, and the old one keeps working because the older contract still exists. ++ ++### 7.e Open questions ++ ++- Can a pin's arg index reach a field inside a struct argument? The Uniswap `exactInputSingle` example depends on it, because the recipient sits inside a struct. (Rules policy contract owner) ++- Routers that hide the recipient inside encoded bytes, such as Uniswap Universal Router `execute`, cannot be pinned, so they should not be preset targets. Confirm the list of apps and functions per chain with this in mind. (SDK owner with the rules policy contract owner) ++- Is the agent one Push address for every chain, including Solana rules? If not, `agent` becomes a per-chain map. (SDK owner) ++- Should `get` throw when an asset has no cap, as proposed above? (Page owner) ++- First preset list for testnet: which apps on which chains for `DEXES` and `LENDING`. (SDK owner with the rules policy contract owner) \ No newline at end of file diff --git a/plan/agw/research/section7-presets-2026-10-12/api.json b/plan/agw/research/section7-presets-2026-10-12/api.json new file mode 100644 index 00000000..c9f8ff6b --- /dev/null +++ b/plan/agw/research/section7-presets-2026-10-12/api.json @@ -0,0 +1,11558 @@ +{ + "baseline": "b1597b91a25dbf7f691f589b4e1e154add604315", + "head": "7115c59474af6304905ad3e4466732b0530dc791", + "compiledMatchesSource": true, + "initializeSignatureChanged": false, + "addedExports": [ + "AgenticPresets", + "DecodedSolanaRule", + "Pin", + "Preset", + "PresetAsset", + "PresetCategory", + "PresetOptions", + "PresetRuleTemplate", + "ReadyPresetOptions", + "RuleInput", + "Spent", + "WalletMarker" + ], + "removedExports": [ + "AgenticNetworkConstants", + "NativeRule", + "UniversalRule" + ], + "changedAgwTypes": [ + "AgenticWallet", + "AgenticError", + "AGENTIC_ERROR_CODE", + "Rule", + "RuleInput", + "Pin", + "Spent", + "NativeRule", + "AssetCap", + "AllowedCall", + "UniversalRule", + "RulesRecord", + "CreateOptions", + "AgenticTxMetadata" + ], + "publicTypeChanges": [ + "AGENTIC_ERROR_CODE", + "AgenticError", + "AgenticErrorCode", + "AgenticTxMetadata", + "AgenticWallet", + "AllowedCall", + "AssetCap", + "CreateOptions", + "DecodedSolanaRule", + "Rule", + "RuleInput", + "Pin", + "Spent", + "WalletMarker", + "RulesRecord", + "Preset", + "PresetCategory", + "PresetAsset", + "PresetOptions", + "ReadyPresetOptions", + "PresetRuleTemplate", + "AgenticPresets" + ], + "transactionMethodChanges": [], + "instanceMethodChanges": [], + "agwConstantsChanged": true, + "before": { + "exports": [ + "AGENTIC_ERROR_CODE", + "AccountRole", + "AccountStatus", + "AccountType", + "AgenticAddress", + "AgenticDoor", + "AgenticError", + "AgenticErrorCode", + "AgenticHex", + "AgenticNamespace", + "AgenticNetworkConstants", + "AgenticProgressHook", + "AgenticRevertError", + "AgenticTxMetadata", + "AgenticWallet", + "AllowedCall", + "AssetCap", + "BatchReadResponse", + "BuildReadSpecParams", + "CHAIN", + "CONTRACT_REQUEST_STATUS", + "CascadeCompletionResult", + "CascadeHopInfo", + "CascadeProgressEvent", + "CascadeTrackOptions", + "CascadedTxResponse", + "ChainSource", + "ChainTarget", + "Checkpoint", + "CheckpointKind", + "ConversionQuote", + "CreateOptions", + "CreateResult", + "DEFAULT_MAX_PC_FOR_GAS_BUFFER_BPS", + "DecodedErrorPayload", + "DecodedReadResult", + "DerivedExecutorAccount", + "EncodedReadQuery", + "EvmReadQuery", + "ForeignChainNamespace", + "FulfilOutcome", + "FundsToken", + "InsufficientPC20BalanceError", + "InvalidPC20AddressError", + "InvalidPC20MetadataError", + "InvalidReadQueryError", + "InvalidReadSpecError", + "MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT", + "MaxPCForGasCapFromNativeValueInput", + "MaxPCForGasCapInput", + "MaxPCForGasCapQuote", + "MultiChainTxResponse", + "NativeRule", + "OutboundTxDetails", + "PC20AddressResult", + "PC20AmbiguousAddressError", + "PC20Error", + "PC20ExpectedButPRC20Error", + "PC20ExportRevertedError", + "PC20FactoryMismatchError", + "PC20RegistryEntry", + "PC20RegistryMismatchError", + "PC20TokenChainMismatchError", + "PC20TokenReference", + "PC20UnknownChainNamespaceError", + "PC20UnsafeEmptyPayloadError", + "PC20WrapperNotRegisteredError", + "PC20WrapperPredictionUnavailableError", + "ParsedReadRequest", + "PreparedRead", + "PreparedUniversalTx", + "PushChain", + "PushChainBatchExecutionError", + "PushChainExecutionError", + "PushChainInitializeOptions", + "READ_ERROR_CODE", + "READ_OUTCOME", + "READ_STATUS", + "ReadCallback", + "ReadCallbackOptions", + "ReadChain", + "ReadDecodeError", + "ReadDestination", + "ReadExecuteOptions", + "ReadFees", + "ReadHeightUnavailableError", + "ReadLifecycleOptions", + "ReadNotFoundError", + "ReadOptions", + "ReadPreflight", + "ReadPrepareOptions", + "ReadQuery", + "ReadQueryOptions", + "ReadRef", + "ReadRegistryUnavailableError", + "ReadResponseTuple", + "ReadResultShape", + "ReadSpec", + "ReadSpecTuple", + "ReadSpecViolation", + "ReadStateError", + "ReadTimeoutError", + "ReadTrackOptions", + "ReadValue", + "ReadWeb2Options", + "ReceiptLike", + "RescueFundsParams", + "ResolvedAccount", + "ResolvedControllerAccounts", + "ResolvedDestination", + "Rule", + "RulesRecord", + "Selector", + "SignAuthorizationParams", + "SignedAuthorization", + "SimulateReadResult", + "SvmExecutePayloadFields", + "SvmGatewayAccountMeta", + "SvmReadQuery", + "TERMINAL_READ_STATUSES", + "TransactionRoute", + "TransactionRouteType", + "UEAStatus", + "UNIVERSAL_CALLBACK_EVM", + "UNIVERSAL_READ_REGISTRY_EVM", + "UNIVERSAL_READ_STATUS", + "UniversalAccount", + "UniversalExecuteParams", + "UniversalOutboundTxRequest", + "UniversalReadResponse", + "UniversalRule", + "UniversalSigner", + "UniversalSignerSkeleton", + "UniversalTo", + "UnsupportedPC20DestinationError", + "UnsupportedReadDestinationError", + "ValidateReadCall", + "WaitForOutboundOptions", + "WalletInfo", + "WalletSummary", + "Web2Extract", + "Web2ReadQuery", + "Web2ValueType", + "buildErc20WithdrawalMulticall", + "buildMigrationPayload", + "buildReadSpecFromPreflight", + "chainSupportsCEA", + "chainSupportsOutbound", + "decodeReadResult", + "detectRoute", + "encodeReadQuery", + "encodeSvmExecutePayload", + "getAllCEAAddresses", + "getCEAAddress", + "getCEAFactoryAddress", + "getPushAccountForCEA", + "inferResultShape", + "isCEA", + "isChainTarget", + "isPC20Reference", + "isSvmChain", + "isValidSolanaHexAddress", + "parseFulfilOutcome", + "parseReadRequestsFromReceipt", + "parseUEAVersion", + "quoteMaxPCForGasCap", + "quoteMaxPCForGasCapFromNativeValue", + "resolveDestination", + "sizeCallbackBudget", + "toCallData", + "toReadQuery", + "toRequestIdHex", + "validateReadSpec" + ], + "agw": { + "AgenticNamespace": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace", + "members": { + "create": { + "optional": false, + "readonly": false, + "type": "(label: string, options: import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions) => Promise" + }, + "derive": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n index?: number;\n}) => Promise<{\n address: `0x${string}`;\n deployed: boolean;\n index: number;\n}>" + }, + "list": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n wallets: import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary[];\n}>" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "(address: `0x${string}`) => import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet" + } + } + }, + "AgenticWallet": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "checkpoints": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n sinceBlock?: bigint;\n}) => Promise<{\n checkpoints: import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint[];\n}>" + }, + "info": { + "optional": false, + "readonly": false, + "type": "() => Promise" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n owner: `0x${string}`;\n}>" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "{\n add(rules: import(\"sdk/src/lib/agentic/agentic.types\").Rule[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise<{\n rulesIds: `0x${string}`[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n get(rulesId: `0x${string}`): Promise;\n list(): Promise<{\n rules: import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord[];\n }>;\n revoke(rulesIds: `0x${string}`[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n revoke(params: {\n all: true;\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n update(params: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n rules: {\n rule: import(\"sdk/src/lib/agentic/agentic.types\").Rule;\n rulesId: `0x${string}`;\n }[];\n }): Promise<{\n rules: {\n replaced: `0x${string}`;\n rulesId: `0x${string}`;\n }[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n}" + }, + "setLabel": { + "optional": false, + "readonly": false, + "type": "(label: string, opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n}) => Promise" + } + } + }, + "AgenticError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"CREATE_PARTIAL\" | \"DUPLICATE_RULE\" | \"FROM_NOT_ALLOWED\" | \"GATEWAY_ALLOWANCE_INSUFFICIENT\" | \"GENERATION_UNSUPPORTED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"REVOKE_NEEDS_TARGET\" | \"RULE_LIMIT_EXCEEDED\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"" + }, + "details": { + "optional": true, + "readonly": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "AgenticRevertError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticRevertError", + "members": { + "agenticCode": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + } + } + }, + "AGENTIC_ERROR_CODE": { + "type": "{\n readonly AGENT_GAS_INSUFFICIENT: \"AGENT_GAS_INSUFFICIENT\";\n readonly AGENT_IS_OWNER: \"AGENT_IS_OWNER\";\n readonly ASSET_CHAIN_MISMATCH: \"ASSET_CHAIN_MISMATCH\";\n readonly CAPABILITY_UNAVAILABLE: \"CAPABILITY_UNAVAILABLE\";\n readonly CREATE_PARTIAL: \"CREATE_PARTIAL\";\n readonly DUPLICATE_RULE: \"DUPLICATE_RULE\";\n readonly FROM_NOT_ALLOWED: \"FROM_NOT_ALLOWED\";\n readonly GATEWAY_ALLOWANCE_INSUFFICIENT: \"GATEWAY_ALLOWANCE_INSUFFICIENT\";\n readonly GENERATION_UNSUPPORTED: \"GENERATION_UNSUPPORTED\";\n readonly INCONSISTENT_READ: \"INCONSISTENT_READ\";\n readonly INDEX_RACE: \"INDEX_RACE\";\n readonly INVALID_RULE: \"INVALID_RULE\";\n readonly NO_RULES_FOR_CHAIN: \"NO_RULES_FOR_CHAIN\";\n readonly NOT_AGENTIC_WALLET: \"NOT_AGENTIC_WALLET\";\n readonly NOT_ALLOWED_IN_AGENTIC_MODE: \"NOT_ALLOWED_IN_AGENTIC_MODE\";\n readonly NOT_OWNER_OR_AGENT: \"NOT_OWNER_OR_AGENT\";\n readonly NOT_WALLET_OWNER: \"NOT_WALLET_OWNER\";\n readonly READ_ONLY: \"READ_ONLY\";\n readonly RECEIPT_MISMATCH: \"RECEIPT_MISMATCH\";\n readonly RECEIPT_UNAVAILABLE: \"RECEIPT_UNAVAILABLE\";\n readonly REVOKE_NEEDS_TARGET: \"REVOKE_NEEDS_TARGET\";\n readonly RULE_LIMIT_EXCEEDED: \"RULE_LIMIT_EXCEEDED\";\n readonly RULE_NOT_FOUND: \"RULE_NOT_FOUND\";\n readonly RULE_READ_FAILED: \"RULE_READ_FAILED\";\n readonly TARGET_NOT_ON_RULE_CHAIN: \"TARGET_NOT_ON_RULE_CHAIN\";\n readonly WALLET_BALANCE_INSUFFICIENT: \"WALLET_BALANCE_INSUFFICIENT\";\n readonly WALLET_NOT_DEPLOYED: \"WALLET_NOT_DEPLOYED\";\n}", + "members": { + "AGENT_GAS_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\"" + }, + "AGENT_IS_OWNER": { + "optional": false, + "readonly": true, + "type": "\"AGENT_IS_OWNER\"" + }, + "ASSET_CHAIN_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"ASSET_CHAIN_MISMATCH\"" + }, + "CAPABILITY_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"CAPABILITY_UNAVAILABLE\"" + }, + "CREATE_PARTIAL": { + "optional": false, + "readonly": true, + "type": "\"CREATE_PARTIAL\"" + }, + "DUPLICATE_RULE": { + "optional": false, + "readonly": true, + "type": "\"DUPLICATE_RULE\"" + }, + "FROM_NOT_ALLOWED": { + "optional": false, + "readonly": true, + "type": "\"FROM_NOT_ALLOWED\"" + }, + "GATEWAY_ALLOWANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"GATEWAY_ALLOWANCE_INSUFFICIENT\"" + }, + "GENERATION_UNSUPPORTED": { + "optional": false, + "readonly": true, + "type": "\"GENERATION_UNSUPPORTED\"" + }, + "INCONSISTENT_READ": { + "optional": false, + "readonly": true, + "type": "\"INCONSISTENT_READ\"" + }, + "INDEX_RACE": { + "optional": false, + "readonly": true, + "type": "\"INDEX_RACE\"" + }, + "INVALID_RULE": { + "optional": false, + "readonly": true, + "type": "\"INVALID_RULE\"" + }, + "NO_RULES_FOR_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"NO_RULES_FOR_CHAIN\"" + }, + "NOT_AGENTIC_WALLET": { + "optional": false, + "readonly": true, + "type": "\"NOT_AGENTIC_WALLET\"" + }, + "NOT_ALLOWED_IN_AGENTIC_MODE": { + "optional": false, + "readonly": true, + "type": "\"NOT_ALLOWED_IN_AGENTIC_MODE\"" + }, + "NOT_OWNER_OR_AGENT": { + "optional": false, + "readonly": true, + "type": "\"NOT_OWNER_OR_AGENT\"" + }, + "NOT_WALLET_OWNER": { + "optional": false, + "readonly": true, + "type": "\"NOT_WALLET_OWNER\"" + }, + "READ_ONLY": { + "optional": false, + "readonly": true, + "type": "\"READ_ONLY\"" + }, + "RECEIPT_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_MISMATCH\"" + }, + "RECEIPT_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_UNAVAILABLE\"" + }, + "REVOKE_NEEDS_TARGET": { + "optional": false, + "readonly": true, + "type": "\"REVOKE_NEEDS_TARGET\"" + }, + "RULE_LIMIT_EXCEEDED": { + "optional": false, + "readonly": true, + "type": "\"RULE_LIMIT_EXCEEDED\"" + }, + "RULE_NOT_FOUND": { + "optional": false, + "readonly": true, + "type": "\"RULE_NOT_FOUND\"" + }, + "RULE_READ_FAILED": { + "optional": false, + "readonly": true, + "type": "\"RULE_READ_FAILED\"" + }, + "TARGET_NOT_ON_RULE_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"TARGET_NOT_ON_RULE_CHAIN\"" + }, + "WALLET_BALANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"WALLET_BALANCE_INSUFFICIENT\"" + }, + "WALLET_NOT_DEPLOYED": { + "optional": false, + "readonly": true, + "type": "\"WALLET_NOT_DEPLOYED\"" + } + } + }, + "Rule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule | import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "NativeRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "amount": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AmountLimit | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "maxCalls": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValuePerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxValueTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "pins": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ArgPin[] | undefined" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "AssetCap": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap", + "members": { + "maxPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/constants/tokens\").MoveableToken" + } + } + }, + "AllowedCall": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall", + "members": { + "beneficiary": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValue": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "`${string}(${string})` | `0x${string}`" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "UniversalRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall[]" + }, + "assets": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap[]" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "`eip155:${string}` | `solana:${string}`" + }, + "maxGasPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "RulesRecord": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "enabled": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "ref": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "rule": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule | import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule" + }, + "rulesId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "CreateOptions": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions", + "members": { + "progressHook": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook | undefined" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Rule[]" + } + } + }, + "CreateResult": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateResult", + "members": { + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "rulesIds": { + "optional": false, + "readonly": false, + "type": "`0x${string}`[]" + }, + "tx": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticTxMetadata": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticTxMetadata", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destinationAccount": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "destinationCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "door": { + "optional": false, + "readonly": false, + "type": "\"agent\" | \"owner\"" + }, + "nativeCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "rawData": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rawTo": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesId": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + } + }, + "publicSurface": { + "CHAIN": { + "type": "typeof import(\"sdk/src/lib/constants/enums\").CHAIN", + "members": { + "ARBITRUM_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA" + }, + "BASE_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA" + }, + "BNB_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET" + }, + "ETHEREUM_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET" + }, + "ETHEREUM_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA" + }, + "PUSH_LOCALNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET" + }, + "PUSH_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET" + }, + "PUSH_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET" + }, + "PUSH_TESTNET_DONUT": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET" + }, + "SOLANA_DEVNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET" + }, + "SOLANA_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET" + }, + "SOLANA_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET" + }, + "WEB2": { + "optional": false, + "readonly": false, + "type": "\"web2\"" + } + } + }, + "ConversionQuote": { + "type": "import(\"sdk/src/lib/constants/tokens\").ConversionQuote", + "members": { + "amountIn": { + "optional": false, + "readonly": false, + "type": "string" + }, + "amountOut": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rate": { + "optional": false, + "readonly": false, + "type": "number" + }, + "route": { + "optional": true, + "readonly": false, + "type": "string[] | undefined" + }, + "timestamp": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "UniversalSigner": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalSigner", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "signAndSendTransaction": { + "optional": false, + "readonly": false, + "type": "(unsignedTx: Uint8Array) => Promise" + }, + "signAuthorization": { + "optional": true, + "readonly": false, + "type": "((params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise) | undefined" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": true, + "readonly": false, + "type": "(({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise) | undefined" + } + } + }, + "UniversalAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "UniversalSignerSkeleton": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "signAndSendTransaction": { + "optional": false, + "readonly": false, + "type": "(unsignedTx: Uint8Array) => Promise" + }, + "signAuthorization": { + "optional": true, + "readonly": false, + "type": "((params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise) | undefined" + }, + "signerId": { + "optional": false, + "readonly": false, + "type": "string" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": true, + "readonly": false, + "type": "(({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise) | undefined" + } + } + }, + "SignAuthorizationParams": { + "type": "{\n chainId?: number;\n contractAddress: `0x${string}`;\n executor?: \"self\";\n nonce?: number;\n}", + "members": { + "chainId": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "contractAddress": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "executor": { + "optional": true, + "readonly": false, + "type": "\"self\" | undefined" + }, + "nonce": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "SignedAuthorization": { + "type": "{\n address: `0x${string}`;\n chainId: number;\n nonce: number;\n r: `0x${string}`;\n s: `0x${string}`;\n v?: bigint;\n yParity: number;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainId": { + "optional": false, + "readonly": false, + "type": "number" + }, + "nonce": { + "optional": false, + "readonly": false, + "type": "number" + }, + "r": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "s": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "v": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "yParity": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "DerivedExecutorAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").DerivedExecutorAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean | null" + } + } + }, + "ResolvedAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainName": { + "optional": false, + "readonly": false, + "type": "string" + }, + "exists": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "role": { + "optional": true, + "readonly": false, + "type": "\"controller\" | undefined" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"cea\" | \"uea\" | \"uoa\"" + } + } + }, + "ResolvedControllerAccounts": { + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedControllerAccounts", + "members": { + "accounts": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedAccount[]" + } + } + }, + "AccountType": { + "type": "\"cea\" | \"uea\" | \"uoa\"", + "members": {} + }, + "AccountRole": { + "type": "\"controller\"", + "members": {} + }, + "PC20TokenReference": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "FundsToken": { + "type": "import(\"sdk/src/lib/constants/tokens\").MoveableToken | import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20TokenReference", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "PC20RegistryEntry": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "chainName": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "PC20AddressResult": { + "type": "{\n address: `0x${string}`;\n decimals: number;\n name: string;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n registry: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20RegistryEntry[];\n symbol: string;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "decimals": { + "optional": false, + "readonly": false, + "type": "number" + }, + "name": { + "optional": false, + "readonly": false, + "type": "string" + }, + "network": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "registry": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20RegistryEntry[]" + }, + "symbol": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "isPC20Reference": { + "type": "(token: import(\"sdk/src/lib/orchestrator/orchestrator.types\").FundsToken | undefined) => token is import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20TokenReference", + "members": {} + }, + "PC20Error": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20Error", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidPC20AddressError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InvalidPC20AddressError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20TokenChainMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20TokenChainMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20WrapperNotRegisteredError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20WrapperNotRegisteredError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20RegistryMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20RegistryMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20FactoryMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20FactoryMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidPC20MetadataError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InvalidPC20MetadataError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20ExpectedButPRC20Error": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20ExpectedButPRC20Error", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20AmbiguousAddressError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20AmbiguousAddressError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "candidates": { + "optional": false, + "readonly": true, + "type": "{\n chain: string;\n pushAddress: string;\n}[]" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "UnsupportedPC20DestinationError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").UnsupportedPC20DestinationError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InsufficientPC20BalanceError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InsufficientPC20BalanceError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20UnknownChainNamespaceError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20UnknownChainNamespaceError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20WrapperPredictionUnavailableError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20WrapperPredictionUnavailableError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20ExportRevertedError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20ExportRevertedError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "lockedAmount": { + "optional": true, + "readonly": true, + "type": "bigint | undefined" + }, + "outboundTxId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "revertRecipient": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20UnsafeEmptyPayloadError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20UnsafeEmptyPayloadError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ChainTarget": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "ChainSource": { + "type": "{\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "UniversalTo": { + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget", + "members": {} + }, + "TransactionRouteType": { + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"", + "members": {} + }, + "UniversalExecuteParams": { + "type": "{\n from?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainSource;\n migration?: boolean;\n to: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTo;\n} & Omit", + "members": { + "_minimumDepositUsd": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "_requiredFundsOverride": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "_skipFeeLocking": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "_ueaStatus": { + "optional": true, + "readonly": false, + "type": "{\n balance: bigint;\n isDeployed: boolean;\n nonce: bigint;\n} | undefined" + }, + "data": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiCall[] | undefined" + }, + "deadline": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "feeLockTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "from": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainSource | undefined" + }, + "funds": { + "optional": true, + "readonly": false, + "type": "{\n amount: bigint;\n token?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").FundsToken;\n} | undefined" + }, + "gasLimit": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFeePerGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxPCForGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxPriorityFeePerGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "migration": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "nonce": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "options": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions | undefined" + }, + "payGasWith": { + "optional": true, + "readonly": false, + "type": "{\n minAmountOut?: bigint | string;\n slippageBps?: number;\n token?: import(\"sdk/src/lib/constants/tokens\").PayableToken;\n} | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "to": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget" + }, + "value": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "UniversalOutboundTxRequest": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalOutboundTxRequest", + "members": { + "amount": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gasPrice": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxPCForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "payload": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "recipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "revertRecipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "PreparedUniversalTx": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx", + "members": { + "_hop": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").HopDescriptor" + }, + "deadline": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "estimatedGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gatewayRequest": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalOutboundTxRequest | import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxRequest" + }, + "nonce": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "payload": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + } + } + }, + "CascadedTxResponse": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadedTxResponse", + "members": { + "finalTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hopCount": { + "optional": false, + "readonly": false, + "type": "number" + }, + "hops": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo[]" + }, + "initialTxHash": { + "optional": false, + "readonly": false, + "type": "string" + }, + "initialTxResponse": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions) => Promise" + }, + "waitForAll": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions) => Promise" + } + } + }, + "CascadeHopInfo": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo", + "members": { + "executionChain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "expectedSubTxId": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hopIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "outboundDetails": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").OutboundTxDetails | undefined" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + }, + "status": { + "optional": false, + "readonly": false, + "type": "\"confirmed\" | \"failed\" | \"pending\" | \"submitted\"" + }, + "txHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "CascadeTrackOptions": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions", + "members": { + "eventHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeProgressEvent) => void) | undefined" + }, + "timeout": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "CascadeProgressEvent": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeProgressEvent", + "members": { + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "elapsed": { + "optional": false, + "readonly": false, + "type": "number" + }, + "hopIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + }, + "status": { + "optional": false, + "readonly": false, + "type": "\"confirmed\" | \"failed\" | \"found\" | \"polling\" | \"timeout\" | \"waiting\"" + }, + "txHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "CascadeCompletionResult": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeCompletionResult", + "members": { + "failedAt": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "finalTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "finalTxResponse": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadedTxResponse | undefined" + }, + "hops": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo[]" + }, + "success": { + "optional": false, + "readonly": false, + "type": "boolean" + } + } + }, + "MultiChainTxResponse": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiChainTxResponse", + "members": { + "chains": { + "optional": false, + "readonly": false, + "type": "{\n blockNumber: bigint;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n hash: string;\n status: \"confirmed\" | \"failed\" | \"pending\";\n}[]" + }, + "transactions": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse[]" + } + } + }, + "OutboundTxDetails": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").OutboundTxDetails", + "members": { + "amount": { + "optional": false, + "readonly": false, + "type": "string" + }, + "assetAddr": { + "optional": false, + "readonly": false, + "type": "string" + }, + "destinationChain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "explorerUrl": { + "optional": false, + "readonly": false, + "type": "string" + }, + "externalTxHash": { + "optional": false, + "readonly": false, + "type": "string" + }, + "recipient": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "WaitForOutboundOptions": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").WaitForOutboundOptions", + "members": { + "_expectedDestinationChain": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "_outboundIndex": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "_resolvedSubTxId": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "initialWaitMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: {\n elapsed: number;\n status: \"failed\" | \"found\" | \"polling\" | \"timeout\" | \"waiting\";\n}) => void) | undefined" + }, + "timeout": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "SvmGatewayAccountMeta": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmGatewayAccountMeta", + "members": { + "isWritable": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "pubkey": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "SvmExecutePayloadFields": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmExecutePayloadFields", + "members": { + "accounts": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmGatewayAccountMeta[]" + }, + "instructionId": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "ixData": { + "optional": false, + "readonly": false, + "type": "Uint8Array" + }, + "targetProgram": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AccountStatus": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus", + "members": { + "mode": { + "optional": false, + "readonly": false, + "type": "\"read-only\" | \"signer\"" + }, + "uea": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UEAStatus" + } + } + }, + "UEAStatus": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UEAStatus", + "members": { + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "loaded": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "minRequiredVersion": { + "optional": false, + "readonly": false, + "type": "string" + }, + "requiresUpgrade": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "version": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "RescueFundsParams": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").RescueFundsParams", + "members": { + "prc20": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "universalTxId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "parseUEAVersion": { + "type": "(version: string) => number", + "members": {} + }, + "TransactionRoute": { + "type": "typeof import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute", + "members": { + "CEA_TO_CEA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.CEA_TO_CEA" + }, + "CEA_TO_PUSH": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.CEA_TO_PUSH" + }, + "UOA_TO_CEA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.UOA_TO_CEA" + }, + "UOA_TO_PUSH": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.UOA_TO_PUSH" + } + } + }, + "detectRoute": { + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams) => import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute", + "members": {} + }, + "isChainTarget": { + "type": "(to: unknown) => to is import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget", + "members": {} + }, + "DEFAULT_MAX_PC_FOR_GAS_BUFFER_BPS": { + "type": "1000", + "members": {} + }, + "MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT": { + "type": "10000", + "members": {} + }, + "quoteMaxPCForGasCap": { + "type": "(input: import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapInput) => import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": {} + }, + "quoteMaxPCForGasCapFromNativeValue": { + "type": "(input: import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapFromNativeValueInput) => import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": {} + }, + "MaxPCForGasCapInput": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapInput", + "members": { + "bufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "gasLegNativePc": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "MaxPCForGasCapFromNativeValueInput": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapFromNativeValueInput", + "members": { + "bufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "nativeValueForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "MaxPCForGasCapQuote": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": { + "bufferBps": { + "optional": false, + "readonly": false, + "type": "number" + }, + "gasLegNativePc": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxPCForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "nativeValueForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "getCEAAddress": { + "type": "(ueaAddress: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise", + "members": {} + }, + "getPushAccountForCEA": { + "type": "(ceaAddress: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise<`0x${string}`>", + "members": {} + }, + "isCEA": { + "type": "(address: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise", + "members": {} + }, + "chainSupportsCEA": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "chainSupportsOutbound": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "getCEAFactoryAddress": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => `0x${string}` | undefined", + "members": {} + }, + "getAllCEAAddresses": { + "type": "(ueaAddress: `0x${string}`, rpcUrls?: Partial>) => Promise", + "members": {} + }, + "encodeSvmExecutePayload": { + "type": "(fields: import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmExecutePayloadFields) => `0x${string}`", + "members": {} + }, + "isSvmChain": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "isValidSolanaHexAddress": { + "type": "(address: string) => boolean", + "members": {} + }, + "buildMigrationPayload": { + "type": "() => `0x${string}`", + "members": {} + }, + "buildErc20WithdrawalMulticall": { + "type": "(tokenAddress: `0x${string}`, recipientAddress: `0x${string}`, amount: bigint) => import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiCall[]", + "members": {} + }, + "ReadChain": { + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain", + "members": {} + }, + "ReadDestination": { + "type": "{\n chain: import(\"sdk/src/lib/read-state/read-state.types\").ReadChain;\n} | {\n chainId: string;\n chainNamespace: string;\n}", + "members": {} + }, + "ResolvedDestination": { + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}", + "members": { + "caip2": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainId": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "namespace": { + "optional": false, + "readonly": false, + "type": "\"eip155\" | \"solana\" | \"web2\"" + } + } + }, + "ReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").SvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery", + "members": { + "type": { + "optional": false, + "readonly": false, + "type": "\"accountBalance\" | \"contractCall\" | \"http\" | \"lamportBalance\" | \"rawAccountData\" | \"splTokenAccount\" | \"storageSlot\"" + } + } + }, + "EvmReadQuery": { + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n target: `0x${string}`;\n type: \"contractCall\";\n} | {\n callData: `0x${string}`;\n target: `0x${string}`;\n type: \"contractCall\";\n} | {\n slot: `0x${string}` | bigint;\n target: `0x${string}`;\n type: \"storageSlot\";\n} | {\n target: `0x${string}`;\n type: \"accountBalance\";\n}", + "members": { + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"accountBalance\" | \"contractCall\" | \"storageSlot\"" + } + } + }, + "SvmReadQuery": { + "type": "{\n account: string | Uint8Array;\n accountName?: string;\n idl?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n type: \"rawAccountData\";\n} | {\n account: string | Uint8Array;\n type: \"lamportBalance\";\n} | {\n account: string | Uint8Array;\n type: \"splTokenAccount\";\n}", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "string | Uint8Array" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"lamportBalance\" | \"rawAccountData\" | \"splTokenAccount\"" + } + } + }, + "Web2ReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery", + "members": { + "body": { + "optional": true, + "readonly": false, + "type": "string | Uint8Array | undefined" + }, + "extract": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[]" + }, + "headers": { + "optional": true, + "readonly": false, + "type": "Record | undefined" + }, + "method": { + "optional": true, + "readonly": false, + "type": "\"GET\" | \"POST\" | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"http\"" + }, + "url": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "Web2Extract": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract", + "members": { + "decimals": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "path": { + "optional": false, + "readonly": false, + "type": "string" + }, + "valueType": { + "optional": false, + "readonly": false, + "type": "\"bool\" | \"bytes\" | \"int256\" | \"string\" | \"uint256\"" + } + } + }, + "Web2ValueType": { + "type": "\"bool\" | \"bytes\" | \"int256\" | \"string\" | \"uint256\"", + "members": {} + }, + "EncodedReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery", + "members": { + "blockRef": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "encoded": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "namespace": { + "optional": false, + "readonly": false, + "type": "\"eip155\" | \"solana\" | \"web2\"" + }, + "ownerBytes": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "queryType": { + "optional": false, + "readonly": false, + "type": "number" + }, + "resultShape": { + "optional": false, + "readonly": false, + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}" + }, + "warnings": { + "optional": false, + "readonly": false, + "type": "string[]" + } + } + }, + "ReadResultShape": { + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"bytes32\" | \"evmCall\" | \"raw\" | \"svmAccount\" | \"uint256\" | \"web2\"" + } + } + }, + "DecodedReadResult": { + "type": "{\n accountName: string;\n kind: \"svmAccount\";\n value: unknown;\n} | {\n kind: \"bytes32\";\n value: `0x${string}`;\n} | {\n kind: \"evmCall\";\n value: unknown;\n} | {\n kind: \"raw\";\n value: `0x${string}`;\n} | {\n kind: \"uint256\";\n value: bigint;\n} | {\n kind: \"web2\";\n values: readonly unknown[];\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"bytes32\" | \"evmCall\" | \"raw\" | \"svmAccount\" | \"uint256\" | \"web2\"" + } + } + }, + "ReadPreflight": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight", + "members": { + "destination": { + "optional": false, + "readonly": false, + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}" + }, + "fetchedAt": { + "optional": false, + "readonly": false, + "type": "number" + }, + "observedChainHeight": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pushBlockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pushGasPrice": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "universalCallback": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "universalCore": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ReadSpec": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "{\n chainId: string;\n chainNamespace: string;\n owner: `0x${string}`;\n}" + }, + "blockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "expiryPushChainHeight": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "minConfirmations": { + "optional": false, + "readonly": false, + "type": "number" + }, + "query": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "revertRecipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ReadSpecTuple": { + "type": "readonly [\n readonly [\n string,\n string,\n `0x${string}`\n ],\n `0x${string}`,\n number,\n bigint,\n bigint,\n bigint,\n `0x${string}`\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "readonly [\n string,\n string,\n `0x${string}`\n]" + }, + "1": { + "optional": false, + "readonly": true, + "type": "`0x${string}`" + }, + "2": { + "optional": false, + "readonly": true, + "type": "number" + }, + "3": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "4": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "5": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "6": { + "optional": false, + "readonly": true, + "type": "`0x${string}`" + }, + "length": { + "optional": false, + "readonly": true, + "type": "7" + } + } + }, + "BuildReadSpecParams": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").BuildReadSpecParams", + "members": { + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "budgetBuffer": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback | undefined" + }, + "callbackBudget": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "destination": { + "optional": false, + "readonly": false, + "type": "{\n chain: import(\"sdk/src/lib/read-state/read-state.types\").ReadChain;\n} | {\n chainId: string;\n chainNamespace: string;\n}" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "expiryPushChainHeight": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFeeBufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "owner": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "query": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").SvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "PreparedRead": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead", + "members": { + "__@preparedReadValue": { + "optional": true, + "readonly": true, + "type": "T | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback | undefined" + }, + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "encodedQuery": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery" + }, + "encodedSpec": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "fees": { + "optional": false, + "readonly": false, + "type": "{\n callbackBudget: bigint;\n protocolFee: bigint;\n total: bigint;\n}" + }, + "preflight": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "queryKey": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "resultShape": { + "optional": false, + "readonly": false, + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}" + }, + "spec": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec" + }, + "specTuple": { + "optional": false, + "readonly": false, + "type": "readonly [\n readonly [\n string,\n string,\n `0x${string}`\n ],\n `0x${string}`,\n number,\n bigint,\n bigint,\n bigint,\n `0x${string}`\n]" + }, + "value": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "warnings": { + "optional": false, + "readonly": false, + "type": "string[]" + } + } + }, + "ReadCallback": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "((spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpecTuple, callbackGasLimit: bigint) => readonly unknown[]) | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "gasLimit": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "target": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "SimulateReadResult": { + "type": "{\n args?: readonly unknown[];\n error: string;\n errorName?: string;\n ok: false;\n} | {\n ok: true;\n}", + "members": { + "ok": { + "optional": false, + "readonly": false, + "type": "boolean" + } + } + }, + "ParsedReadRequest": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ParsedReadRequest", + "members": { + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackTarget": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "logIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "originalFunder": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "requestId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "requestIdUint": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "spec": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec" + }, + "totalPaid": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "FulfilOutcome": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").FulfilOutcome", + "members": { + "burned": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "delivered": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "expired": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "failReason": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "gasReported": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refunded": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refundFailed": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "ReceiptLike": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike", + "members": { + "logs": { + "optional": false, + "readonly": false, + "type": "readonly {\n address: string;\n data: string;\n logIndex?: number | string;\n topics: readonly string[];\n}[]" + } + } + }, + "ReadRef": { + "type": "{\n requestId: `0x${string}` | bigint;\n} | {\n txHash: `0x${string}`;\n}", + "members": {} + }, + "ReadLifecycleOptions": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadLifecycleOptions", + "members": { + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "resultShape": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadFees": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadFees", + "members": { + "burned": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "paid": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "refunded": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refundFailed": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + } + } + }, + "UniversalReadResponse": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse", + "members": { + "callbackDelivered": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "callbackFailReason": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "decoded": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").DecodedReadResult | undefined" + }, + "decodeError": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destination": { + "optional": false, + "readonly": false, + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}" + }, + "errorMsg": { + "optional": false, + "readonly": false, + "type": "string" + }, + "explorerUrl": { + "optional": false, + "readonly": false, + "type": "string" + }, + "fees": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadFees" + }, + "isTerminal": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "outcome": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME" + }, + "pcTx": { + "optional": false, + "readonly": false, + "type": "readonly {\n blockHeight: number;\n errorMsg: string;\n status: string;\n txHash: `0x${string}`;\n}[]" + }, + "raw": { + "optional": false, + "readonly": false, + "type": "{\n errorCode: import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n resultData: `0x${string}`;\n status: import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n} | null" + }, + "refresh": { + "optional": false, + "readonly": false, + "type": "() => Promise>" + }, + "request": { + "optional": false, + "readonly": false, + "type": "{\n callbackGasLimit: bigint;\n callbackTarget: `0x${string}`;\n createdAtHeight: bigint;\n logIndex: number;\n originalFunder: `0x${string}`;\n refundTo: `0x${string}`;\n spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec;\n}" + }, + "requestId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "requestIdUint": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "status": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "value": { + "optional": true, + "readonly": false, + "type": "T | undefined" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/read-state/read-state.types\").ReadLifecycleOptions) => Promise>" + } + } + }, + "ReadResponseTuple": { + "type": "{\n -readonly [K in keyof R]: import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse ? T : unknown>;\n}", + "members": {} + }, + "BatchReadResponse": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").BatchReadResponse", + "members": { + "atomic": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "count": { + "optional": false, + "readonly": false, + "type": "number" + }, + "reads": { + "optional": false, + "readonly": false, + "type": "{\n -readonly [K in keyof R]: import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse ? T : unknown>;\n}" + }, + "transactionHashes": { + "optional": true, + "readonly": false, + "type": "readonly `0x${string}`[] | undefined" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: Omit) => Promise>" + } + } + }, + "ReadOptions": { + "type": "((import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">)) & {\n callback?: (Pick & Required>) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n };\n}", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "advanced": { + "optional": true, + "readonly": false, + "type": "{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n} | undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "({\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} & {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n}) | ({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick & Pick & Required>) | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadPrepareOptions": { + "type": "((((({\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\">) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n}) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">)) & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n}) | ((({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n}) | ({\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\">)) & {\n blockNumber?: never;\n minConfirmations?: never;\n})) & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n}) & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "advanced": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadQueryOptions": { + "type": "({\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\">) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n}) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n}) | ({\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\">)", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadCallbackOptions": { + "type": "{\n callback?: ({\n gasLimit?: bigint;\n target: `0x${string}`;\n } & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n };\n}", + "members": { + "callback": { + "optional": true, + "readonly": false, + "type": "({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} | undefined" + } + } + }, + "ReadValue": { + "type": "O extends {\n abi: infer A extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: infer F extends string;\n} ? number extends A[\"length\"] ? unknown : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, O extends {\n args: infer Args extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n} ? Args : readonly [\n] extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> ? import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> & readonly [\n] : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>> extends infer Selected ? Selected extends {\n outputs: readonly unknown[];\n type: \"function\";\n} & import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiFunction ? {\n [key in keyof {\n [key in keyof import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"]]: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterToPrimitiveType, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"][key], import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterKind>;\n }]: {\n [key in keyof import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"]]: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterToPrimitiveType, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"][key], import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterKind>;\n }[key];\n} extends infer types ? types extends readonly [\n] ? void : types extends readonly [\n infer type\n] ? type : types : never : never : never : O extends {\n web2: {\n extract: infer E extends readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n };\n} ? {\n readonly [K in keyof E]: {\n bool: boolean;\n bytes: `0x${string}`;\n int256: bigint;\n string: string;\n uint256: bigint;\n }[E[K][\"valueType\"]];\n} : O extends {\n storageSlot: unknown;\n} ? `0x${string}` : O extends {\n idl: infer I extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} ? string extends Extract, string> ? unknown : (O extends {\n functionName: infer N extends string;\n} ? N : undefined) extends string ? import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/index\").IdlAccounts[{\n [K in Extract, string>]: Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : K> extends Lowercase<(O extends {\n functionName: infer N extends string;\n } ? N : undefined) & string extends `${infer H}_${infer T}` ? `${H}${Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : (O extends {\n functionName: infer N extends string;\n } ? N : undefined) & string> ? K : never;\n}[Extract, string>]] : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/index\").IdlAccounts[Extract, string>] : bigint", + "members": {} + }, + "ValidateReadCall": { + "type": "O extends {\n abi: infer A extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: infer F extends string;\n} ? (readonly [\n] extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> ? {\n args?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n} : {\n args: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n}) & {\n functionName: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionName;\n} : O extends {\n functionName: infer N extends string;\n idl: infer I extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} ? string extends Extract, string> ? unknown : [\n {\n [K in Extract, string>]: Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : K> extends Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : N> ? K : never;\n }[Extract, string>]\n] extends [\n never\n] ? {\n functionName: Extract, string>;\n} : unknown : unknown", + "members": {} + }, + "ReadWeb2Options": { + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options", + "members": { + "body": { + "optional": true, + "readonly": false, + "type": "string | Uint8Array | undefined" + }, + "extract": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[]" + }, + "headers": { + "optional": true, + "readonly": false, + "type": "Record | undefined" + }, + "method": { + "optional": true, + "readonly": false, + "type": "\"GET\" | \"POST\" | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadTrackOptions": { + "type": "{\n advanced?: Omit, \"enforceGasCheck\">;\n resultShape?: import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape;\n}", + "members": { + "advanced": { + "optional": true, + "readonly": false, + "type": "Omit<{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n}, \"enforceGasCheck\"> | undefined" + }, + "resultShape": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape | undefined" + } + } + }, + "ReadExecuteOptions": { + "type": "{\n advanced?: {\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n } | undefined;\n progressHook?: ((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined;\n waitForCompletion?: boolean | undefined;\n}", + "members": { + "advanced": { + "optional": true, + "readonly": false, + "type": "{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n} | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + } + } + }, + "UNIVERSAL_READ_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS", + "members": { + "ABORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.ABORTED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.EXPIRED" + }, + "FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.FAILED" + }, + "FULFILLED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.FULFILLED" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.PENDING" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.UNSPECIFIED" + }, + "VOTING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.VOTING" + } + } + }, + "READ_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS", + "members": { + "ERROR": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.ERROR" + }, + "SUCCESS": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.SUCCESS" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.UNSPECIFIED" + } + } + }, + "READ_ERROR_CODE": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE", + "members": { + "INVALID_QUERY": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.INVALID_QUERY" + }, + "INVALID_RESULT": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.INVALID_RESULT" + }, + "NOT_FOUND": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.NOT_FOUND" + }, + "REJECTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.REJECTED" + }, + "REVERTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.REVERTED" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.UNSPECIFIED" + }, + "UNSUPPORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.UNSUPPORTED" + } + } + }, + "READ_OUTCOME": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME", + "members": { + "ABORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.ABORTED" + }, + "CALLBACK_FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.CALLBACK_FAILED" + }, + "DECODE_FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.DECODE_FAILED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.EXPIRED" + }, + "FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.FAILED" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.PENDING" + }, + "SOURCE_ERROR": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.SOURCE_ERROR" + }, + "SUCCESS": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.SUCCESS" + }, + "UNKNOWN": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.UNKNOWN" + } + } + }, + "CONTRACT_REQUEST_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS", + "members": { + "EXECUTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.EXECUTED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.EXPIRED" + }, + "NONE": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.NONE" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.PENDING" + }, + "SETTLED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.SETTLED" + } + } + }, + "TERMINAL_READ_STATUSES": { + "type": "ReadonlySet", + "members": {} + }, + "ReadStateError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadStateError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidReadQueryError": { + "type": "import(\"sdk/src/lib/read-state/errors\").InvalidReadQueryError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidReadSpecError": { + "type": "import(\"sdk/src/lib/read-state/errors\").InvalidReadSpecError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "violations": { + "optional": false, + "readonly": true, + "type": "readonly import(\"sdk/src/lib/read-state/errors\").ReadSpecViolation[]" + } + } + }, + "ReadHeightUnavailableError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadHeightUnavailableError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "UnsupportedReadDestinationError": { + "type": "import(\"sdk/src/lib/read-state/errors\").UnsupportedReadDestinationError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadDecodeError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadDecodeError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadTimeoutError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadTimeoutError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "lastStatus": { + "optional": false, + "readonly": true, + "type": "number" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadNotFoundError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadNotFoundError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadRegistryUnavailableError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadRegistryUnavailableError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadSpecViolation": { + "type": "\"CALLBACK_GAS_LIMIT_EXCEEDED\" | \"DOMAIN_BLOCKED\" | \"EMPTY_QUERY\" | \"EXCESSIVE_FEE\" | \"INSUFFICIENT_CALLBACK_BUDGET\" | \"INSUFFICIENT_FEE\" | \"INVALID_ACCOUNT_ID\" | \"INVALID_BLOCK_NUMBER\" | \"INVALID_EXPIRY_HEIGHT\" | \"INVALID_MIN_CONFIRMATIONS\" | \"SVM_OWNER_NOT_32_BYTES\" | \"ZERO_CALLBACK_BUDGET\" | \"ZERO_CALLBACK_GAS_LIMIT\" | \"ZERO_REVERT_RECIPIENT\"", + "members": {} + }, + "resolveDestination": { + "type": "(dest: import(\"sdk/src/lib/read-state/read-state.types\").ReadDestination) => import(\"sdk/src/lib/read-state/read-state.types\").ResolvedDestination", + "members": {} + }, + "encodeReadQuery": { + "type": "(destination: import(\"sdk/src/lib/read-state/read-state.types\").ReadDestination, query: import(\"sdk/src/lib/read-state/read-state.types\").ReadQuery, options?: {\n blockNumber?: bigint;\n minSlot?: bigint;\n}) => import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery", + "members": {} + }, + "decodeReadResult": { + "type": "(resultData: `0x${string}`, shape: import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape) => import(\"sdk/src/lib/read-state/read-state.types\").DecodedReadResult", + "members": {} + }, + "parseReadRequestsFromReceipt": { + "type": "(receipt: import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike, universalCallback: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").ParsedReadRequest[]", + "members": {} + }, + "parseFulfilOutcome": { + "type": "(receipt: import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike, universalCallback: `0x${string}`, requestId: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").FulfilOutcome", + "members": {} + }, + "buildReadSpecFromPreflight": { + "type": "(preflight: import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight, params: import(\"sdk/src/lib/read-state/read-state.types\").BuildReadSpecParams, defaults?: {\n refundTo?: `0x${string}`;\n}) => import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead", + "members": {} + }, + "validateReadSpec": { + "type": "(input: import(\"sdk/src/lib/read-state/validate\").ValidateReadSpecInput) => {\n ok: false;\n violations: import(\"sdk/src/lib/read-state/errors\").ReadSpecViolation[];\n} | {\n ok: true;\n}", + "members": {} + }, + "toCallData": { + "type": "(prepared: import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead, target: {\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: (spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpecTuple, callbackGasLimit: bigint) => readonly unknown[];\n functionName: string;\n}) => {\n data: `0x${string}`;\n value: bigint;\n}", + "members": {} + }, + "sizeCallbackBudget": { + "type": "(callbackGasLimit: bigint, pushGasPrice: bigint, buffer?: number) => bigint", + "members": {} + }, + "inferResultShape": { + "type": "(namespace: string, query: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape", + "members": {} + }, + "toRequestIdHex": { + "type": "(id: `0x${string}` | bigint) => `0x${string}`", + "members": {} + }, + "toReadQuery": { + "type": "(subject: string, o: ReadOptionsInput, resolvedTokenProgram?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@solana/web3.js/lib/index\").PublicKey) => import(\"sdk/src/lib/read-state/read-state.types\").ReadQuery", + "members": {} + }, + "UNIVERSAL_CALLBACK_EVM": { + "type": "readonly [\n {\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"requestExternalReadSelf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"estimateFee\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"statusOf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"enum RequestStatus\";\n readonly name: \"\";\n readonly type: \"uint8\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"isFulfilled\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getPendingRead\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly internalType: \"struct PendingRead\";\n readonly name: \"\";\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"totalEscrowed\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"blockedDomains\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly indexed: false;\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"readSpec\";\n readonly type: \"tuple\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"totalPaid\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"protocolFee\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ReadRequested\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"ReadFulfilled\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"reason\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"CallbackFailed\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"gasReported\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"burned\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"CallbackGasReported\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundSent\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundFailed\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RequestExpired\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"vaultPC\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ProtocolFeeDistributed\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidAccountId\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"EmptyQuery\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidMinConfirmations\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"DomainBlocked\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidBlockNumber\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidExpiryHeight\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroRevertRecipient\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroCallbackGasLimit\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint64\";\n readonly name: \"provided\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"max\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"CallbackGasLimitExceeded\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"required\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"InsufficientFee\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ExcessiveFee\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"actual\";\n readonly type: \"uint8\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"expected\";\n readonly type: \"uint8\";\n }\n ];\n readonly name: \"InvalidRequestStatus\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ContractIsPaused\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"CallerIsNotUCallbackModule\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n }\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"requestExternalReadSelf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n}" + }, + "1": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"estimateFee\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "2": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"statusOf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"enum RequestStatus\";\n readonly name: \"\";\n readonly type: \"uint8\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "3": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"isFulfilled\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "4": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getPendingRead\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly internalType: \"struct PendingRead\";\n readonly name: \"\";\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "5": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"totalEscrowed\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "6": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"blockedDomains\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "7": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly indexed: false;\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"readSpec\";\n readonly type: \"tuple\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"totalPaid\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"protocolFee\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ReadRequested\";\n readonly type: \"event\";\n}" + }, + "8": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"ReadFulfilled\";\n readonly type: \"event\";\n}" + }, + "9": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"reason\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"CallbackFailed\";\n readonly type: \"event\";\n}" + }, + "10": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"gasReported\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"burned\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"CallbackGasReported\";\n readonly type: \"event\";\n}" + }, + "11": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundSent\";\n readonly type: \"event\";\n}" + }, + "12": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundFailed\";\n readonly type: \"event\";\n}" + }, + "13": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RequestExpired\";\n readonly type: \"event\";\n}" + }, + "14": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"vaultPC\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ProtocolFeeDistributed\";\n readonly type: \"event\";\n}" + }, + "15": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidAccountId\";\n readonly type: \"error\";\n}" + }, + "16": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"EmptyQuery\";\n readonly type: \"error\";\n}" + }, + "17": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidMinConfirmations\";\n readonly type: \"error\";\n}" + }, + "18": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"DomainBlocked\";\n readonly type: \"error\";\n}" + }, + "19": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidBlockNumber\";\n readonly type: \"error\";\n}" + }, + "20": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidExpiryHeight\";\n readonly type: \"error\";\n}" + }, + "21": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroRevertRecipient\";\n readonly type: \"error\";\n}" + }, + "22": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroCallbackGasLimit\";\n readonly type: \"error\";\n}" + }, + "23": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint64\";\n readonly name: \"provided\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"max\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"CallbackGasLimitExceeded\";\n readonly type: \"error\";\n}" + }, + "24": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"required\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"InsufficientFee\";\n readonly type: \"error\";\n}" + }, + "25": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ExcessiveFee\";\n readonly type: \"error\";\n}" + }, + "26": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"actual\";\n readonly type: \"uint8\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"expected\";\n readonly type: \"uint8\";\n }\n ];\n readonly name: \"InvalidRequestStatus\";\n readonly type: \"error\";\n}" + }, + "27": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ContractIsPaused\";\n readonly type: \"error\";\n}" + }, + "28": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"CallerIsNotUCallbackModule\";\n readonly type: \"error\";\n}" + }, + "29": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n}" + }, + "length": { + "optional": false, + "readonly": true, + "type": "30" + } + } + }, + "UNIVERSAL_READ_REGISTRY_EVM": { + "type": "readonly [\n {\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n },\n {\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"read\";\n readonly outputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"universalCallback_\";\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"constructor\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"initialize\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getLocalContext\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"hasResult\";\n readonly outputs: readonly [\n {\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"onUniversalData\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"queryKeyOf\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes32\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"readerOf\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"requestOrderOf\";\n readonly outputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"universalCallback\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"resultByRequestId\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"latestResult\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"version\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"Initialized\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadRequested\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadStored\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidInitialization\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"NotInitializing\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroAddressInit\";\n readonly type: \"error\";\n }\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n },\n {\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"read\";\n readonly outputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n}" + }, + "1": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"universalCallback_\";\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"constructor\";\n}" + }, + "2": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"initialize\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n}" + }, + "3": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getLocalContext\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "4": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"hasResult\";\n readonly outputs: readonly [\n {\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "5": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"onUniversalData\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n}" + }, + "6": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"queryKeyOf\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes32\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "7": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"readerOf\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "8": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"requestOrderOf\";\n readonly outputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "9": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"universalCallback\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "10": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"resultByRequestId\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "11": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"latestResult\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "12": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"version\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"Initialized\";\n readonly type: \"event\";\n}" + }, + "13": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadRequested\";\n readonly type: \"event\";\n}" + }, + "14": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadStored\";\n readonly type: \"event\";\n}" + }, + "15": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidInitialization\";\n readonly type: \"error\";\n}" + }, + "16": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"NotInitializing\";\n readonly type: \"error\";\n}" + }, + "17": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n}" + }, + "18": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroAddressInit\";\n readonly type: \"error\";\n}" + }, + "length": { + "optional": false, + "readonly": true, + "type": "19" + } + } + }, + "PushChainExecutionError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").PushChainExecutionError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PushChainBatchExecutionError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").PushChainBatchExecutionError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": false, + "readonly": true, + "type": "`0x${string}`[]" + } + } + }, + "DecodedErrorPayload": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload", + "members": { + "decoded": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "name": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "selector": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "PushChainInitializeOptions": { + "type": "import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions", + "members": { + "agenticWallet": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "blockExplorers": { + "optional": true, + "readonly": false, + "type": "Partial> | undefined" + }, + "network": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "printTraces": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "rpcUrls": { + "optional": true, + "readonly": false, + "type": "Partial> | undefined" + } + } + }, + "AGENTIC_ERROR_CODE": { + "type": "{\n readonly AGENT_GAS_INSUFFICIENT: \"AGENT_GAS_INSUFFICIENT\";\n readonly AGENT_IS_OWNER: \"AGENT_IS_OWNER\";\n readonly ASSET_CHAIN_MISMATCH: \"ASSET_CHAIN_MISMATCH\";\n readonly CAPABILITY_UNAVAILABLE: \"CAPABILITY_UNAVAILABLE\";\n readonly CREATE_PARTIAL: \"CREATE_PARTIAL\";\n readonly DUPLICATE_RULE: \"DUPLICATE_RULE\";\n readonly FROM_NOT_ALLOWED: \"FROM_NOT_ALLOWED\";\n readonly GATEWAY_ALLOWANCE_INSUFFICIENT: \"GATEWAY_ALLOWANCE_INSUFFICIENT\";\n readonly GENERATION_UNSUPPORTED: \"GENERATION_UNSUPPORTED\";\n readonly INCONSISTENT_READ: \"INCONSISTENT_READ\";\n readonly INDEX_RACE: \"INDEX_RACE\";\n readonly INVALID_RULE: \"INVALID_RULE\";\n readonly NO_RULES_FOR_CHAIN: \"NO_RULES_FOR_CHAIN\";\n readonly NOT_AGENTIC_WALLET: \"NOT_AGENTIC_WALLET\";\n readonly NOT_ALLOWED_IN_AGENTIC_MODE: \"NOT_ALLOWED_IN_AGENTIC_MODE\";\n readonly NOT_OWNER_OR_AGENT: \"NOT_OWNER_OR_AGENT\";\n readonly NOT_WALLET_OWNER: \"NOT_WALLET_OWNER\";\n readonly READ_ONLY: \"READ_ONLY\";\n readonly RECEIPT_MISMATCH: \"RECEIPT_MISMATCH\";\n readonly RECEIPT_UNAVAILABLE: \"RECEIPT_UNAVAILABLE\";\n readonly REVOKE_NEEDS_TARGET: \"REVOKE_NEEDS_TARGET\";\n readonly RULE_LIMIT_EXCEEDED: \"RULE_LIMIT_EXCEEDED\";\n readonly RULE_NOT_FOUND: \"RULE_NOT_FOUND\";\n readonly RULE_READ_FAILED: \"RULE_READ_FAILED\";\n readonly TARGET_NOT_ON_RULE_CHAIN: \"TARGET_NOT_ON_RULE_CHAIN\";\n readonly WALLET_BALANCE_INSUFFICIENT: \"WALLET_BALANCE_INSUFFICIENT\";\n readonly WALLET_NOT_DEPLOYED: \"WALLET_NOT_DEPLOYED\";\n}", + "members": { + "AGENT_GAS_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\"" + }, + "AGENT_IS_OWNER": { + "optional": false, + "readonly": true, + "type": "\"AGENT_IS_OWNER\"" + }, + "ASSET_CHAIN_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"ASSET_CHAIN_MISMATCH\"" + }, + "CAPABILITY_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"CAPABILITY_UNAVAILABLE\"" + }, + "CREATE_PARTIAL": { + "optional": false, + "readonly": true, + "type": "\"CREATE_PARTIAL\"" + }, + "DUPLICATE_RULE": { + "optional": false, + "readonly": true, + "type": "\"DUPLICATE_RULE\"" + }, + "FROM_NOT_ALLOWED": { + "optional": false, + "readonly": true, + "type": "\"FROM_NOT_ALLOWED\"" + }, + "GATEWAY_ALLOWANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"GATEWAY_ALLOWANCE_INSUFFICIENT\"" + }, + "GENERATION_UNSUPPORTED": { + "optional": false, + "readonly": true, + "type": "\"GENERATION_UNSUPPORTED\"" + }, + "INCONSISTENT_READ": { + "optional": false, + "readonly": true, + "type": "\"INCONSISTENT_READ\"" + }, + "INDEX_RACE": { + "optional": false, + "readonly": true, + "type": "\"INDEX_RACE\"" + }, + "INVALID_RULE": { + "optional": false, + "readonly": true, + "type": "\"INVALID_RULE\"" + }, + "NO_RULES_FOR_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"NO_RULES_FOR_CHAIN\"" + }, + "NOT_AGENTIC_WALLET": { + "optional": false, + "readonly": true, + "type": "\"NOT_AGENTIC_WALLET\"" + }, + "NOT_ALLOWED_IN_AGENTIC_MODE": { + "optional": false, + "readonly": true, + "type": "\"NOT_ALLOWED_IN_AGENTIC_MODE\"" + }, + "NOT_OWNER_OR_AGENT": { + "optional": false, + "readonly": true, + "type": "\"NOT_OWNER_OR_AGENT\"" + }, + "NOT_WALLET_OWNER": { + "optional": false, + "readonly": true, + "type": "\"NOT_WALLET_OWNER\"" + }, + "READ_ONLY": { + "optional": false, + "readonly": true, + "type": "\"READ_ONLY\"" + }, + "RECEIPT_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_MISMATCH\"" + }, + "RECEIPT_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_UNAVAILABLE\"" + }, + "REVOKE_NEEDS_TARGET": { + "optional": false, + "readonly": true, + "type": "\"REVOKE_NEEDS_TARGET\"" + }, + "RULE_LIMIT_EXCEEDED": { + "optional": false, + "readonly": true, + "type": "\"RULE_LIMIT_EXCEEDED\"" + }, + "RULE_NOT_FOUND": { + "optional": false, + "readonly": true, + "type": "\"RULE_NOT_FOUND\"" + }, + "RULE_READ_FAILED": { + "optional": false, + "readonly": true, + "type": "\"RULE_READ_FAILED\"" + }, + "TARGET_NOT_ON_RULE_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"TARGET_NOT_ON_RULE_CHAIN\"" + }, + "WALLET_BALANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"WALLET_BALANCE_INSUFFICIENT\"" + }, + "WALLET_NOT_DEPLOYED": { + "optional": false, + "readonly": true, + "type": "\"WALLET_NOT_DEPLOYED\"" + } + } + }, + "AgenticError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"CREATE_PARTIAL\" | \"DUPLICATE_RULE\" | \"FROM_NOT_ALLOWED\" | \"GATEWAY_ALLOWANCE_INSUFFICIENT\" | \"GENERATION_UNSUPPORTED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"REVOKE_NEEDS_TARGET\" | \"RULE_LIMIT_EXCEEDED\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"" + }, + "details": { + "optional": true, + "readonly": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "AgenticRevertError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticRevertError", + "members": { + "agenticCode": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + } + } + }, + "AgenticAddress": { + "type": "`0x${string}`", + "members": {} + }, + "AgenticDoor": { + "type": "\"agent\" | \"owner\"", + "members": {} + }, + "AgenticErrorCode": { + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"CREATE_PARTIAL\" | \"DUPLICATE_RULE\" | \"FROM_NOT_ALLOWED\" | \"GATEWAY_ALLOWANCE_INSUFFICIENT\" | \"GENERATION_UNSUPPORTED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"REVOKE_NEEDS_TARGET\" | \"RULE_LIMIT_EXCEEDED\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"", + "members": {} + }, + "AgenticHex": { + "type": "`0x${string}`", + "members": {} + }, + "AgenticNamespace": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace", + "members": { + "create": { + "optional": false, + "readonly": false, + "type": "(label: string, options: import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions) => Promise" + }, + "derive": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n index?: number;\n}) => Promise<{\n address: `0x${string}`;\n deployed: boolean;\n index: number;\n}>" + }, + "list": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n wallets: import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary[];\n}>" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "(address: `0x${string}`) => import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet" + } + } + }, + "AgenticNetworkConstants": { + "type": "import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants", + "members": { + "ENVELOPE_VERSION": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "FACTORY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "MAX_ALLOWED_CALLS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "MAX_PINS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "RULES_POLICY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticProgressHook": { + "type": "(event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void", + "members": {} + }, + "AgenticTxMetadata": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticTxMetadata", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destinationAccount": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "destinationCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "door": { + "optional": false, + "readonly": false, + "type": "\"agent\" | \"owner\"" + }, + "nativeCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "rawData": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rawTo": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesId": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticWallet": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "checkpoints": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n sinceBlock?: bigint;\n}) => Promise<{\n checkpoints: import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint[];\n}>" + }, + "info": { + "optional": false, + "readonly": false, + "type": "() => Promise" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n owner: `0x${string}`;\n}>" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "{\n add(rules: import(\"sdk/src/lib/agentic/agentic.types\").Rule[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise<{\n rulesIds: `0x${string}`[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n get(rulesId: `0x${string}`): Promise;\n list(): Promise<{\n rules: import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord[];\n }>;\n revoke(rulesIds: `0x${string}`[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n revoke(params: {\n all: true;\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n update(params: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n rules: {\n rule: import(\"sdk/src/lib/agentic/agentic.types\").Rule;\n rulesId: `0x${string}`;\n }[];\n }): Promise<{\n rules: {\n replaced: `0x${string}`;\n rulesId: `0x${string}`;\n }[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n}" + }, + "setLabel": { + "optional": false, + "readonly": false, + "type": "(label: string, opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n}) => Promise" + } + } + }, + "AllowedCall": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall", + "members": { + "beneficiary": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValue": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "`${string}(${string})` | `0x${string}`" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AssetCap": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap", + "members": { + "maxPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/constants/tokens\").MoveableToken" + } + } + }, + "Checkpoint": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint", + "members": { + "blockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "kind": { + "optional": false, + "readonly": false, + "type": "\"OWNER_ACTION\" | \"RULES_GRANTED\" | \"RULES_REVOKED\"" + }, + "ref": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "seq": { + "optional": false, + "readonly": false, + "type": "number" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "CheckpointKind": { + "type": "\"OWNER_ACTION\" | \"RULES_GRANTED\" | \"RULES_REVOKED\"", + "members": {} + }, + "CreateOptions": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions", + "members": { + "progressHook": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook | undefined" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Rule[]" + } + } + }, + "CreateResult": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateResult", + "members": { + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "rulesIds": { + "optional": false, + "readonly": false, + "type": "`0x${string}`[]" + }, + "tx": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ForeignChainNamespace": { + "type": "`eip155:${string}` | `solana:${string}`", + "members": {} + }, + "NativeRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "amount": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AmountLimit | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "maxCalls": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValuePerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxValueTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "pins": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ArgPin[] | undefined" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Rule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule | import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "RulesRecord": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "enabled": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "ref": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "rule": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule | import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule" + }, + "rulesId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Selector": { + "type": "`${string}(${string})` | `0x${string}`", + "members": {} + }, + "UniversalRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall[]" + }, + "assets": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap[]" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "`eip155:${string}` | `solana:${string}`" + }, + "maxGasPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "WalletInfo": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").WalletInfo", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "label": { + "optional": false, + "readonly": false, + "type": "string" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "rulesCount": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "WalletSummary": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "label": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesCount": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "PushChain": { + "type": "import(\"sdk/src/lib/push-chain/push-chain\").PushChain", + "members": { + "accountStatus": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus" + }, + "accountStatusReady": { + "optional": false, + "readonly": false, + "type": "Promise" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace" + }, + "explorer": { + "optional": false, + "readonly": false, + "type": "{\n getTransactionUrl: (txHash: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n listAllUrls: () => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n listUrls: (options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n}" + }, + "funds": { + "optional": false, + "readonly": false, + "type": "{\n getConversionQuote: (amountIn: bigint, options: {\n from: import(\"sdk/src/lib/constants/tokens\").PayableToken | undefined;\n to: import(\"sdk/src/lib/constants/tokens\").MoveableToken | undefined;\n }) => Promise;\n}" + }, + "getAccountStatus": { + "optional": false, + "readonly": false, + "type": "(options?: {\n forceRefresh?: boolean;\n}) => Promise" + }, + "isReadMode": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "moveable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").MoveableTokenAccessor;\n}" + }, + "payable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").PayableTokenAccessor;\n}" + }, + "reinitialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "universal": { + "optional": false, + "readonly": false, + "type": "{\n readonly account: `0x${string}`;\n executeReads: (reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>;\n executeTransactions: (txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise;\n migrateCEA: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"migrateCEA\"];\n readonly origin: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n prepareRead: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n prepareTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"prepareTransaction\"];\n read: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n rescueFunds: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"rescueFunds\"];\n sendTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"execute\"];\n signMessage: (data: Uint8Array) => Promise;\n signTypedData: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n trackRead: {\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n };\n trackTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"trackTransaction\"];\n}" + }, + "upgradeAccount": { + "optional": false, + "readonly": false, + "type": "(options?: {\n progressHook?: (progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n}) => Promise" + } + } + } + }, + "pushChainStatic": { + "CONSTANTS": { + "optional": false, + "readonly": false, + "type": "{\n AGENTIC: Readonly>>;\n CHAIN: typeof import(\"sdk/src/lib/constants/enums\").CHAIN;\n LIBRARY: typeof import(\"sdk/src/lib/constants/enums\").LIBRARY;\n MOVEABLE: {\n TOKEN: import(\"sdk/src/lib/constants/tokens\").MoveableTokenConstantsMap;\n };\n PAYABLE: {\n TOKEN: import(\"sdk/src/lib/constants/tokens\").PayableTokenConstantsMap;\n };\n PUSH_NETWORK: typeof import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n READ: {\n readonly CALLBACK_BUDGET_BUFFER: 3;\n readonly CHAIN: {\n readonly WEB2: \"web2\";\n } & Readonly<{\n readonly ARBITRUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA;\n readonly BASE_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA;\n readonly BNB_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET;\n readonly ETHEREUM_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET;\n readonly ETHEREUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA;\n readonly PUSH_LOCALNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET;\n readonly PUSH_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET;\n readonly PUSH_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly PUSH_TESTNET_DONUT: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly SOLANA_DEVNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET;\n readonly SOLANA_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET;\n readonly SOLANA_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n readonly WEB2: \"web2\";\n }>;\n readonly DEFAULT_EXPIRY_BLOCKS: 300n;\n readonly ERROR_CODE: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n readonly MAX_CALLBACK_GAS_LIMIT: 1000000n;\n readonly MIN_CONFIRMATIONS_FLOOR: 1;\n readonly NAMESPACE: {\n readonly EVM: \"eip155\";\n readonly SVM: \"solana\";\n readonly WEB2: \"web2\";\n };\n readonly OUTCOME: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME;\n readonly REGISTRY_CALLBACK_GAS: 500000n;\n readonly RESULT_STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n readonly STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS;\n readonly UNIVERSAL_CALLBACK_ADDRESSES: Record;\n readonly UNIVERSAL_CORE_ADDRESSES: Record;\n readonly UNIVERSAL_READ_REGISTRY_ADDRESS: {\n readonly TESTNET_DONUT: \"0x00000000000000000000000000000000000000b2\";\n };\n readonly WEB2: \"web2\";\n readonly WEB2_DEFAULT_TIMEOUT_MS: 5000;\n readonly WEB2_MAX_EXTRACT_ENTRIES: 16;\n };\n}" + }, + "initialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "utils": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/utils\").Utils" + } + }, + "pushChainInstance": { + "accountStatus": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus" + }, + "accountStatusReady": { + "optional": false, + "readonly": false, + "type": "Promise" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace" + }, + "explorer": { + "optional": false, + "readonly": false, + "type": "{\n getTransactionUrl: (txHash: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n listAllUrls: () => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n listUrls: (options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n}" + }, + "funds": { + "optional": false, + "readonly": false, + "type": "{\n getConversionQuote: (amountIn: bigint, options: {\n from: import(\"sdk/src/lib/constants/tokens\").PayableToken | undefined;\n to: import(\"sdk/src/lib/constants/tokens\").MoveableToken | undefined;\n }) => Promise;\n}" + }, + "getAccountStatus": { + "optional": false, + "readonly": false, + "type": "(options?: {\n forceRefresh?: boolean;\n}) => Promise" + }, + "isReadMode": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "moveable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").MoveableTokenAccessor;\n}" + }, + "payable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").PayableTokenAccessor;\n}" + }, + "reinitialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "universal": { + "optional": false, + "readonly": false, + "type": "{\n readonly account: `0x${string}`;\n executeReads: (reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>;\n executeTransactions: (txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise;\n migrateCEA: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"migrateCEA\"];\n readonly origin: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n prepareRead: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n prepareTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"prepareTransaction\"];\n read: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n rescueFunds: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"rescueFunds\"];\n sendTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"execute\"];\n signMessage: (data: Uint8Array) => Promise;\n signTypedData: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n trackRead: {\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n };\n trackTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"trackTransaction\"];\n}" + }, + "upgradeAccount": { + "optional": false, + "readonly": false, + "type": "(options?: {\n progressHook?: (progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n}) => Promise" + } + }, + "transactionMethods": { + "account": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "executeReads": { + "optional": false, + "readonly": false, + "type": "(reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>" + }, + "executeTransactions": { + "optional": false, + "readonly": false, + "type": "(txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise" + }, + "migrateCEA": { + "optional": false, + "readonly": false, + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => Promise" + }, + "origin": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "prepareRead": { + "optional": false, + "readonly": false, + "type": "(subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>" + }, + "prepareTransaction": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions) => Promise" + }, + "read": { + "optional": false, + "readonly": false, + "type": "(subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>" + }, + "rescueFunds": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").RescueFundsParams) => Promise" + }, + "sendTransaction": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").ExecuteParams | import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions) => Promise" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": false, + "readonly": false, + "type": "({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise" + }, + "trackRead": { + "optional": false, + "readonly": false, + "type": "{\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n}" + }, + "trackTransaction": { + "optional": false, + "readonly": false, + "type": "(txHash: string, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TrackTransactionOptions) => Promise" + } + }, + "utilityMethods": { + "account": { + "optional": false, + "readonly": false, + "type": "{\n convertExecutorToOriginAccount: (ueaAddress: `0x${string}`, options?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n }) => Promise;\n convertOriginToExecutor: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n onlyCompute?: boolean;\n }) => Promise;\n deriveExecutorAccount: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n skipNetworkCheck?: boolean;\n }) => Promise;\n fromChainAgnostic: (caip: string) => import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n resolveControllerAccount: (address: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n skipNetworkCheck?: boolean;\n }) => Promise;\n toChainAgnostic: (address: string, options: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n toUniversal: (address: string, options: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n}" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "{\n actionId: (target: `0x${string}`, selector: \"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector) => `0x${string}`;\n configId: (wallet: `0x${string}`, rulesId: `0x${string}`, actionId: `0x${string}`) => `0x${string}`;\n decodeRules: (bytes: `0x${string}`, ctx?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n pushChainNamespace?: string;\n }) => import(\"sdk/src/lib/agentic/agentic.types\").Rule;\n}" + }, + "chains": { + "optional": false, + "readonly": false, + "type": "{\n getChainName: (chainNamespace: string) => string | undefined;\n getChainNamespace: (chainName: string) => string | undefined;\n getSupportedChains: (network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK) => {\n chains: import(\"sdk/src/lib/constants/enums\").CHAIN[];\n };\n getSupportedChainsByName: (network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK) => {\n chains: string[];\n };\n}" + }, + "conversion": { + "optional": false, + "readonly": false, + "type": "{\n slippageToMinAmount(amount: string, options: {\n slippageBps: number;\n }): string;\n}" + }, + "helpers": { + "optional": false, + "readonly": false, + "type": "{\n encodeTxData({ abi, idl, functionName, args, }: {\n abi?: any;\n args?: any[];\n functionName: string;\n idl?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n }): `0x${string}`;\n formatUnits(value: bigint | string, decimalsOrOptions: {\n decimals: number;\n precision?: number;\n } | number): string;\n getChainName: (chainName: string) => string | undefined;\n parseUnits(value: string, exponent: {\n decimals: number;\n } | number): bigint;\n}" + }, + "signer": { + "optional": false, + "readonly": false, + "type": "{\n construct: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options: {\n signAndSendTransaction: (unsignedTx: Uint8Array) => Promise;\n signAuthorization?: (params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise;\n signMessage: (data: Uint8Array) => Promise;\n signTypedData?: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n }) => import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton;\n toUniversal: (signer: import(\"sdk/src/lib/universal/universal.types\").EthersV5SignerType | import(\"sdk/src/lib/universal/universal.types\").EthersV6SignerType | import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton | import(\"sdk/src/lib/universal/universal.types\").ViemSignerType) => Promise;\n toUniversalFromKeypair: (clientOrAccount: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@solana/web3.js/lib/index\").Keypair | import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").WalletClient | import(\"sdk/src/lib/universal/universal.types\").EthersV6SignerType, { chain, library }: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n library: import(\"sdk/src/lib/constants/enums\").LIBRARY;\n }) => Promise;\n}" + }, + "svm": { + "optional": false, + "readonly": false, + "type": "{\n getRegisteredIdls: () => Array<{\n address: `0x${string}`;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n }>;\n registerIdl: (idl: unknown) => void;\n}" + }, + "tokens": { + "optional": false, + "readonly": false, + "type": "{\n getMoveableTokens(chainOrClient?: import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/push-chain/push-chain\").PushChain): {\n tokens: Array<{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n decimals: number;\n mechanism: \"approve\" | \"native\" | \"permit2\";\n prc20Address?: `0x${string}`;\n sourceChain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n symbol: string;\n }>;\n };\n getPayableTokens(chainOrClient?: import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/push-chain/push-chain\").PushChain): {\n tokens: Array<{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n decimals: number;\n mechanism: \"approve\" | \"native\" | \"permit2\";\n symbol: string;\n }>;\n };\n getPC20Address(address: string, options: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n rpcUrls?: Partial>;\n strict?: boolean;\n }): Promise;\n getPRC20Address(token: {\n address: string;\n chain: string;\n } | import(\"sdk/src/lib/constants/tokens\").MoveableToken, options?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n }): {\n address: `0x${string}`;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n decimals: number;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n symbol: string;\n };\n}" + } + }, + "initialize": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise", + "agwConstants": { + "ENVELOPE_VERSION": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "FACTORY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "MAX_ALLOWED_CALLS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "MAX_PINS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "RULES_POLICY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + }, + "constants": { + "AGENTIC": { + "optional": false, + "readonly": false, + "type": "{\n readonly LOCALNET?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n readonly MAINNET?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n readonly TESTNET?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n readonly TESTNET_DONUT?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n}" + }, + "CHAIN": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "LIBRARY": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").LIBRARY" + }, + "MOVEABLE": { + "optional": false, + "readonly": false, + "type": "{\n TOKEN: import(\"sdk/src/lib/constants/tokens\").MoveableTokenConstantsMap;\n}" + }, + "PAYABLE": { + "optional": false, + "readonly": false, + "type": "{\n TOKEN: import(\"sdk/src/lib/constants/tokens\").PayableTokenConstantsMap;\n}" + }, + "PUSH_NETWORK": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "READ": { + "optional": false, + "readonly": false, + "type": "{\n readonly CALLBACK_BUDGET_BUFFER: 3;\n readonly CHAIN: {\n readonly WEB2: \"web2\";\n } & Readonly<{\n readonly ARBITRUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA;\n readonly BASE_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA;\n readonly BNB_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET;\n readonly ETHEREUM_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET;\n readonly ETHEREUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA;\n readonly PUSH_LOCALNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET;\n readonly PUSH_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET;\n readonly PUSH_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly PUSH_TESTNET_DONUT: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly SOLANA_DEVNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET;\n readonly SOLANA_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET;\n readonly SOLANA_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n readonly WEB2: \"web2\";\n }>;\n readonly DEFAULT_EXPIRY_BLOCKS: 300n;\n readonly ERROR_CODE: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n readonly MAX_CALLBACK_GAS_LIMIT: 1000000n;\n readonly MIN_CONFIRMATIONS_FLOOR: 1;\n readonly NAMESPACE: {\n readonly EVM: \"eip155\";\n readonly SVM: \"solana\";\n readonly WEB2: \"web2\";\n };\n readonly OUTCOME: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME;\n readonly REGISTRY_CALLBACK_GAS: 500000n;\n readonly RESULT_STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n readonly STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS;\n readonly UNIVERSAL_CALLBACK_ADDRESSES: Record;\n readonly UNIVERSAL_CORE_ADDRESSES: Record;\n readonly UNIVERSAL_READ_REGISTRY_ADDRESS: {\n readonly TESTNET_DONUT: \"0x00000000000000000000000000000000000000b2\";\n };\n readonly WEB2: \"web2\";\n readonly WEB2_DEFAULT_TIMEOUT_MS: 5000;\n readonly WEB2_MAX_EXTRACT_ENTRIES: 16;\n}" + } + } + }, + "after": { + "exports": [ + "AGENTIC_ERROR_CODE", + "AccountRole", + "AccountStatus", + "AccountType", + "AgenticAddress", + "AgenticDoor", + "AgenticError", + "AgenticErrorCode", + "AgenticHex", + "AgenticNamespace", + "AgenticPresets", + "AgenticProgressHook", + "AgenticRevertError", + "AgenticTxMetadata", + "AgenticWallet", + "AllowedCall", + "AssetCap", + "BatchReadResponse", + "BuildReadSpecParams", + "CHAIN", + "CONTRACT_REQUEST_STATUS", + "CascadeCompletionResult", + "CascadeHopInfo", + "CascadeProgressEvent", + "CascadeTrackOptions", + "CascadedTxResponse", + "ChainSource", + "ChainTarget", + "Checkpoint", + "CheckpointKind", + "ConversionQuote", + "CreateOptions", + "CreateResult", + "DEFAULT_MAX_PC_FOR_GAS_BUFFER_BPS", + "DecodedErrorPayload", + "DecodedReadResult", + "DecodedSolanaRule", + "DerivedExecutorAccount", + "EncodedReadQuery", + "EvmReadQuery", + "ForeignChainNamespace", + "FulfilOutcome", + "FundsToken", + "InsufficientPC20BalanceError", + "InvalidPC20AddressError", + "InvalidPC20MetadataError", + "InvalidReadQueryError", + "InvalidReadSpecError", + "MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT", + "MaxPCForGasCapFromNativeValueInput", + "MaxPCForGasCapInput", + "MaxPCForGasCapQuote", + "MultiChainTxResponse", + "OutboundTxDetails", + "PC20AddressResult", + "PC20AmbiguousAddressError", + "PC20Error", + "PC20ExpectedButPRC20Error", + "PC20ExportRevertedError", + "PC20FactoryMismatchError", + "PC20RegistryEntry", + "PC20RegistryMismatchError", + "PC20TokenChainMismatchError", + "PC20TokenReference", + "PC20UnknownChainNamespaceError", + "PC20UnsafeEmptyPayloadError", + "PC20WrapperNotRegisteredError", + "PC20WrapperPredictionUnavailableError", + "ParsedReadRequest", + "Pin", + "PreparedRead", + "PreparedUniversalTx", + "Preset", + "PresetAsset", + "PresetCategory", + "PresetOptions", + "PresetRuleTemplate", + "PushChain", + "PushChainBatchExecutionError", + "PushChainExecutionError", + "PushChainInitializeOptions", + "READ_ERROR_CODE", + "READ_OUTCOME", + "READ_STATUS", + "ReadCallback", + "ReadCallbackOptions", + "ReadChain", + "ReadDecodeError", + "ReadDestination", + "ReadExecuteOptions", + "ReadFees", + "ReadHeightUnavailableError", + "ReadLifecycleOptions", + "ReadNotFoundError", + "ReadOptions", + "ReadPreflight", + "ReadPrepareOptions", + "ReadQuery", + "ReadQueryOptions", + "ReadRef", + "ReadRegistryUnavailableError", + "ReadResponseTuple", + "ReadResultShape", + "ReadSpec", + "ReadSpecTuple", + "ReadSpecViolation", + "ReadStateError", + "ReadTimeoutError", + "ReadTrackOptions", + "ReadValue", + "ReadWeb2Options", + "ReadyPresetOptions", + "ReceiptLike", + "RescueFundsParams", + "ResolvedAccount", + "ResolvedControllerAccounts", + "ResolvedDestination", + "Rule", + "RuleInput", + "RulesRecord", + "Selector", + "SignAuthorizationParams", + "SignedAuthorization", + "SimulateReadResult", + "Spent", + "SvmExecutePayloadFields", + "SvmGatewayAccountMeta", + "SvmReadQuery", + "TERMINAL_READ_STATUSES", + "TransactionRoute", + "TransactionRouteType", + "UEAStatus", + "UNIVERSAL_CALLBACK_EVM", + "UNIVERSAL_READ_REGISTRY_EVM", + "UNIVERSAL_READ_STATUS", + "UniversalAccount", + "UniversalExecuteParams", + "UniversalOutboundTxRequest", + "UniversalReadResponse", + "UniversalSigner", + "UniversalSignerSkeleton", + "UniversalTo", + "UnsupportedPC20DestinationError", + "UnsupportedReadDestinationError", + "ValidateReadCall", + "WaitForOutboundOptions", + "WalletInfo", + "WalletMarker", + "WalletSummary", + "Web2Extract", + "Web2ReadQuery", + "Web2ValueType", + "buildErc20WithdrawalMulticall", + "buildMigrationPayload", + "buildReadSpecFromPreflight", + "chainSupportsCEA", + "chainSupportsOutbound", + "decodeReadResult", + "detectRoute", + "encodeReadQuery", + "encodeSvmExecutePayload", + "getAllCEAAddresses", + "getCEAAddress", + "getCEAFactoryAddress", + "getPushAccountForCEA", + "inferResultShape", + "isCEA", + "isChainTarget", + "isPC20Reference", + "isSvmChain", + "isValidSolanaHexAddress", + "parseFulfilOutcome", + "parseReadRequestsFromReceipt", + "parseUEAVersion", + "quoteMaxPCForGasCap", + "quoteMaxPCForGasCapFromNativeValue", + "resolveDestination", + "sizeCallbackBudget", + "toCallData", + "toReadQuery", + "toRequestIdHex", + "validateReadSpec" + ], + "agw": { + "AgenticNamespace": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace", + "members": { + "create": { + "optional": false, + "readonly": false, + "type": "(label: string, options: import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions) => Promise" + }, + "derive": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n index?: number;\n}) => Promise<{\n address: `0x${string}`;\n deployed: boolean;\n index: number;\n}>" + }, + "list": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n wallets: import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary[];\n}>" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "(address: `0x${string}`) => import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet" + } + } + }, + "AgenticWallet": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "checkpoints": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n sinceBlock?: bigint;\n}) => Promise<{\n checkpoints: import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint[];\n}>" + }, + "info": { + "optional": false, + "readonly": false, + "type": "() => Promise" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n owner: `0x${string}`;\n}>" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "{\n add(rules: import(\"sdk/src/lib/agentic/agentic.types\").RuleInput[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise<{\n rulesIds: `0x${string}`[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n delete(rulesIds: `0x${string}`[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n delete(params: {\n all: true;\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n get(rulesId: `0x${string}`): Promise;\n list(): Promise<{\n rules: import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord[];\n }>;\n update(params: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n rules: {\n rule: import(\"sdk/src/lib/agentic/agentic.types\").RuleInput;\n rulesId: `0x${string}`;\n }[];\n }): Promise<{\n rules: {\n replaced: `0x${string}`;\n rulesId: `0x${string}`;\n }[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n}" + }, + "setLabel": { + "optional": false, + "readonly": false, + "type": "(label: string, opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n}) => Promise" + } + } + }, + "AgenticError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"AMBIGUOUS_RULE\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"CREATE_PARTIAL\" | \"DELETE_NEEDS_TARGET\" | \"DUPLICATE_RULE\" | \"FROM_NOT_ALLOWED\" | \"GATEWAY_ALLOWANCE_INSUFFICIENT\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"" + }, + "details": { + "optional": true, + "readonly": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "AgenticRevertError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticRevertError", + "members": { + "agenticCode": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + } + } + }, + "AGENTIC_ERROR_CODE": { + "type": "{\n readonly AGENT_GAS_INSUFFICIENT: \"AGENT_GAS_INSUFFICIENT\";\n readonly AGENT_IS_OWNER: \"AGENT_IS_OWNER\";\n readonly AMBIGUOUS_RULE: \"AMBIGUOUS_RULE\";\n readonly ASSET_CHAIN_MISMATCH: \"ASSET_CHAIN_MISMATCH\";\n readonly CAPABILITY_UNAVAILABLE: \"CAPABILITY_UNAVAILABLE\";\n readonly CREATE_PARTIAL: \"CREATE_PARTIAL\";\n readonly DELETE_NEEDS_TARGET: \"DELETE_NEEDS_TARGET\";\n readonly DUPLICATE_RULE: \"DUPLICATE_RULE\";\n readonly FROM_NOT_ALLOWED: \"FROM_NOT_ALLOWED\";\n readonly GATEWAY_ALLOWANCE_INSUFFICIENT: \"GATEWAY_ALLOWANCE_INSUFFICIENT\";\n readonly INCONSISTENT_READ: \"INCONSISTENT_READ\";\n readonly INDEX_RACE: \"INDEX_RACE\";\n readonly INVALID_RULE: \"INVALID_RULE\";\n readonly NO_RULES_FOR_CHAIN: \"NO_RULES_FOR_CHAIN\";\n readonly NOT_AGENTIC_WALLET: \"NOT_AGENTIC_WALLET\";\n readonly NOT_ALLOWED_IN_AGENTIC_MODE: \"NOT_ALLOWED_IN_AGENTIC_MODE\";\n readonly NOT_OWNER_OR_AGENT: \"NOT_OWNER_OR_AGENT\";\n readonly NOT_WALLET_OWNER: \"NOT_WALLET_OWNER\";\n readonly READ_ONLY: \"READ_ONLY\";\n readonly RECEIPT_MISMATCH: \"RECEIPT_MISMATCH\";\n readonly RECEIPT_UNAVAILABLE: \"RECEIPT_UNAVAILABLE\";\n readonly RULE_NOT_FOUND: \"RULE_NOT_FOUND\";\n readonly RULE_READ_FAILED: \"RULE_READ_FAILED\";\n readonly TARGET_NOT_ON_RULE_CHAIN: \"TARGET_NOT_ON_RULE_CHAIN\";\n readonly WALLET_BALANCE_INSUFFICIENT: \"WALLET_BALANCE_INSUFFICIENT\";\n readonly WALLET_NOT_DEPLOYED: \"WALLET_NOT_DEPLOYED\";\n}", + "members": { + "AGENT_GAS_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\"" + }, + "AGENT_IS_OWNER": { + "optional": false, + "readonly": true, + "type": "\"AGENT_IS_OWNER\"" + }, + "AMBIGUOUS_RULE": { + "optional": false, + "readonly": true, + "type": "\"AMBIGUOUS_RULE\"" + }, + "ASSET_CHAIN_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"ASSET_CHAIN_MISMATCH\"" + }, + "CAPABILITY_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"CAPABILITY_UNAVAILABLE\"" + }, + "CREATE_PARTIAL": { + "optional": false, + "readonly": true, + "type": "\"CREATE_PARTIAL\"" + }, + "DELETE_NEEDS_TARGET": { + "optional": false, + "readonly": true, + "type": "\"DELETE_NEEDS_TARGET\"" + }, + "DUPLICATE_RULE": { + "optional": false, + "readonly": true, + "type": "\"DUPLICATE_RULE\"" + }, + "FROM_NOT_ALLOWED": { + "optional": false, + "readonly": true, + "type": "\"FROM_NOT_ALLOWED\"" + }, + "GATEWAY_ALLOWANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"GATEWAY_ALLOWANCE_INSUFFICIENT\"" + }, + "INCONSISTENT_READ": { + "optional": false, + "readonly": true, + "type": "\"INCONSISTENT_READ\"" + }, + "INDEX_RACE": { + "optional": false, + "readonly": true, + "type": "\"INDEX_RACE\"" + }, + "INVALID_RULE": { + "optional": false, + "readonly": true, + "type": "\"INVALID_RULE\"" + }, + "NO_RULES_FOR_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"NO_RULES_FOR_CHAIN\"" + }, + "NOT_AGENTIC_WALLET": { + "optional": false, + "readonly": true, + "type": "\"NOT_AGENTIC_WALLET\"" + }, + "NOT_ALLOWED_IN_AGENTIC_MODE": { + "optional": false, + "readonly": true, + "type": "\"NOT_ALLOWED_IN_AGENTIC_MODE\"" + }, + "NOT_OWNER_OR_AGENT": { + "optional": false, + "readonly": true, + "type": "\"NOT_OWNER_OR_AGENT\"" + }, + "NOT_WALLET_OWNER": { + "optional": false, + "readonly": true, + "type": "\"NOT_WALLET_OWNER\"" + }, + "READ_ONLY": { + "optional": false, + "readonly": true, + "type": "\"READ_ONLY\"" + }, + "RECEIPT_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_MISMATCH\"" + }, + "RECEIPT_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_UNAVAILABLE\"" + }, + "RULE_NOT_FOUND": { + "optional": false, + "readonly": true, + "type": "\"RULE_NOT_FOUND\"" + }, + "RULE_READ_FAILED": { + "optional": false, + "readonly": true, + "type": "\"RULE_READ_FAILED\"" + }, + "TARGET_NOT_ON_RULE_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"TARGET_NOT_ON_RULE_CHAIN\"" + }, + "WALLET_BALANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"WALLET_BALANCE_INSUFFICIENT\"" + }, + "WALLET_NOT_DEPLOYED": { + "optional": false, + "readonly": true, + "type": "\"WALLET_NOT_DEPLOYED\"" + } + } + }, + "Rule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Rule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleCall[]" + }, + "assets": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset[] | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "maxGasPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "RuleInput": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").DecodedSolanaRule | import(\"sdk/src/lib/agentic/agentic.types\").Rule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "assets": { + "optional": true, + "readonly": false, + "type": "{\n maxPerCall: bigint;\n maxTotal: bigint;\n token: string;\n}[] | import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset[] | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "maxGasPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Pin": { + "type": "{\n account: number;\n arg?: never;\n expected: \"agentic:wallet\" | string;\n max?: never;\n token?: import(\"sdk/src/lib/constants/tokens\").MoveableToken | string;\n} | {\n account?: never;\n arg: number;\n expected: \"agentic:wallet\" | `0x${string}` | `0x${string}` | bigint;\n max?: never;\n} | {\n account?: never;\n arg: number;\n expected?: never;\n max: bigint;\n}", + "members": { + "account": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "arg": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "expected": { + "optional": true, + "readonly": false, + "type": "bigint | string | undefined" + }, + "max": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "Spent": { + "type": "{\n actions: {\n amountSpent: bigint;\n callsUsed: number;\n selector: \"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector;\n target: `0x${string}`;\n valueSpent: bigint;\n }[];\n kind: \"native\";\n} | {\n amountSpent: bigint;\n callsUsed: number;\n kind: \"native\";\n valueSpent: bigint;\n} | {\n assets: {\n spent: bigint;\n token: string;\n }[];\n kind: \"universal\";\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"native\" | \"universal\"" + } + } + }, + "AssetCap": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset", + "members": { + "maxPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/tokens\").MoveableToken | string" + } + } + }, + "AllowedCall": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleCall", + "members": { + "app": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "label": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "maxValue": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "pins": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Pin[] | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector" + }, + "target": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "RulesRecord": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "enabled": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "rule": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").DecodedSolanaRule | import(\"sdk/src/lib/agentic/agentic.types\").Rule" + }, + "rulesId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "spent": { + "optional": false, + "readonly": false, + "type": "{\n actions: {\n amountSpent: bigint;\n callsUsed: number;\n selector: \"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector;\n target: `0x${string}`;\n valueSpent: bigint;\n }[];\n kind: \"native\";\n} | {\n amountSpent: bigint;\n callsUsed: number;\n kind: \"native\";\n valueSpent: bigint;\n} | {\n assets: {\n spent: bigint;\n token: string;\n }[];\n kind: \"universal\";\n}" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "CreateOptions": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions", + "members": { + "progressHook": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook | undefined" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleInput[]" + } + } + }, + "CreateResult": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateResult", + "members": { + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "rulesIds": { + "optional": false, + "readonly": false, + "type": "`0x${string}`[]" + }, + "tx": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticTxMetadata": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticTxMetadata", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destinationAccount": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "destinationCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "destinationInstruction": { + "optional": true, + "readonly": false, + "type": "{\n accounts: readonly {\n isWritable: boolean;\n pubkey: `0x${string}`;\n }[];\n data: `0x${string}`;\n program: `0x${string}`;\n} | undefined" + }, + "destinationTransfer": { + "optional": true, + "readonly": false, + "type": "{\n amount: bigint;\n recipient: `0x${string}`;\n token: `0x${string}`;\n} | undefined" + }, + "door": { + "optional": false, + "readonly": false, + "type": "\"agent\" | \"owner\"" + }, + "nativeCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "rawData": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rawTo": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesId": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + } + }, + "publicSurface": { + "CHAIN": { + "type": "typeof import(\"sdk/src/lib/constants/enums\").CHAIN", + "members": { + "ARBITRUM_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA" + }, + "BASE_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA" + }, + "BNB_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET" + }, + "ETHEREUM_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET" + }, + "ETHEREUM_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA" + }, + "PUSH_LOCALNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET" + }, + "PUSH_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET" + }, + "PUSH_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET" + }, + "PUSH_TESTNET_DONUT": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET" + }, + "SOLANA_DEVNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET" + }, + "SOLANA_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET" + }, + "SOLANA_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET" + }, + "WEB2": { + "optional": false, + "readonly": false, + "type": "\"web2\"" + } + } + }, + "ConversionQuote": { + "type": "import(\"sdk/src/lib/constants/tokens\").ConversionQuote", + "members": { + "amountIn": { + "optional": false, + "readonly": false, + "type": "string" + }, + "amountOut": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rate": { + "optional": false, + "readonly": false, + "type": "number" + }, + "route": { + "optional": true, + "readonly": false, + "type": "string[] | undefined" + }, + "timestamp": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "UniversalSigner": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalSigner", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "signAndSendTransaction": { + "optional": false, + "readonly": false, + "type": "(unsignedTx: Uint8Array) => Promise" + }, + "signAuthorization": { + "optional": true, + "readonly": false, + "type": "((params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise) | undefined" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": true, + "readonly": false, + "type": "(({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise) | undefined" + } + } + }, + "UniversalAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "UniversalSignerSkeleton": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "signAndSendTransaction": { + "optional": false, + "readonly": false, + "type": "(unsignedTx: Uint8Array) => Promise" + }, + "signAuthorization": { + "optional": true, + "readonly": false, + "type": "((params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise) | undefined" + }, + "signerId": { + "optional": false, + "readonly": false, + "type": "string" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": true, + "readonly": false, + "type": "(({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise) | undefined" + } + } + }, + "SignAuthorizationParams": { + "type": "{\n chainId?: number;\n contractAddress: `0x${string}`;\n executor?: \"self\";\n nonce?: number;\n}", + "members": { + "chainId": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "contractAddress": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "executor": { + "optional": true, + "readonly": false, + "type": "\"self\" | undefined" + }, + "nonce": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "SignedAuthorization": { + "type": "{\n address: `0x${string}`;\n chainId: number;\n nonce: number;\n r: `0x${string}`;\n s: `0x${string}`;\n v?: bigint;\n yParity: number;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainId": { + "optional": false, + "readonly": false, + "type": "number" + }, + "nonce": { + "optional": false, + "readonly": false, + "type": "number" + }, + "r": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "s": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "v": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "yParity": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "DerivedExecutorAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").DerivedExecutorAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean | null" + } + } + }, + "ResolvedAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainName": { + "optional": false, + "readonly": false, + "type": "string" + }, + "exists": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "role": { + "optional": true, + "readonly": false, + "type": "\"controller\" | undefined" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"cea\" | \"uea\" | \"uoa\"" + } + } + }, + "ResolvedControllerAccounts": { + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedControllerAccounts", + "members": { + "accounts": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedAccount[]" + } + } + }, + "AccountType": { + "type": "\"cea\" | \"uea\" | \"uoa\"", + "members": {} + }, + "AccountRole": { + "type": "\"controller\"", + "members": {} + }, + "PC20TokenReference": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "FundsToken": { + "type": "import(\"sdk/src/lib/constants/tokens\").MoveableToken | import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20TokenReference", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "PC20RegistryEntry": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "chainName": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "PC20AddressResult": { + "type": "{\n address: `0x${string}`;\n decimals: number;\n name: string;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n registry: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20RegistryEntry[];\n symbol: string;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "decimals": { + "optional": false, + "readonly": false, + "type": "number" + }, + "name": { + "optional": false, + "readonly": false, + "type": "string" + }, + "network": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "registry": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20RegistryEntry[]" + }, + "symbol": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "isPC20Reference": { + "type": "(token: import(\"sdk/src/lib/orchestrator/orchestrator.types\").FundsToken | undefined) => token is import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20TokenReference", + "members": {} + }, + "PC20Error": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20Error", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidPC20AddressError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InvalidPC20AddressError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20TokenChainMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20TokenChainMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20WrapperNotRegisteredError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20WrapperNotRegisteredError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20RegistryMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20RegistryMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20FactoryMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20FactoryMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidPC20MetadataError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InvalidPC20MetadataError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20ExpectedButPRC20Error": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20ExpectedButPRC20Error", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20AmbiguousAddressError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20AmbiguousAddressError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "candidates": { + "optional": false, + "readonly": true, + "type": "{\n chain: string;\n pushAddress: string;\n}[]" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "UnsupportedPC20DestinationError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").UnsupportedPC20DestinationError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InsufficientPC20BalanceError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InsufficientPC20BalanceError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20UnknownChainNamespaceError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20UnknownChainNamespaceError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20WrapperPredictionUnavailableError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20WrapperPredictionUnavailableError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20ExportRevertedError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20ExportRevertedError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "lockedAmount": { + "optional": true, + "readonly": true, + "type": "bigint | undefined" + }, + "outboundTxId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "revertRecipient": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20UnsafeEmptyPayloadError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20UnsafeEmptyPayloadError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ChainTarget": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "ChainSource": { + "type": "{\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "UniversalTo": { + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget", + "members": {} + }, + "TransactionRouteType": { + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"", + "members": {} + }, + "UniversalExecuteParams": { + "type": "{\n from?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainSource;\n migration?: boolean;\n to: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTo;\n} & Omit", + "members": { + "_minimumDepositUsd": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "_requiredFundsOverride": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "_skipFeeLocking": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "_ueaStatus": { + "optional": true, + "readonly": false, + "type": "{\n balance: bigint;\n isDeployed: boolean;\n nonce: bigint;\n} | undefined" + }, + "data": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiCall[] | undefined" + }, + "deadline": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "feeLockTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "from": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainSource | undefined" + }, + "funds": { + "optional": true, + "readonly": false, + "type": "{\n amount: bigint;\n token?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").FundsToken;\n} | undefined" + }, + "gasLimit": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFeePerGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxPCForGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxPriorityFeePerGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "migration": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "nonce": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "options": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions | undefined" + }, + "payGasWith": { + "optional": true, + "readonly": false, + "type": "{\n minAmountOut?: bigint | string;\n slippageBps?: number;\n token?: import(\"sdk/src/lib/constants/tokens\").PayableToken;\n} | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "to": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget" + }, + "value": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "UniversalOutboundTxRequest": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalOutboundTxRequest", + "members": { + "amount": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gasPrice": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxPCForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "payload": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "recipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "revertRecipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "PreparedUniversalTx": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx", + "members": { + "_hop": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").HopDescriptor" + }, + "deadline": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "estimatedGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gatewayRequest": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalOutboundTxRequest | import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxRequest" + }, + "nonce": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "payload": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + } + } + }, + "CascadedTxResponse": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadedTxResponse", + "members": { + "finalTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hopCount": { + "optional": false, + "readonly": false, + "type": "number" + }, + "hops": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo[]" + }, + "initialTxHash": { + "optional": false, + "readonly": false, + "type": "string" + }, + "initialTxResponse": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions) => Promise" + }, + "waitForAll": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions) => Promise" + } + } + }, + "CascadeHopInfo": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo", + "members": { + "executionChain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "expectedSubTxId": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hopIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "outboundDetails": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").OutboundTxDetails | undefined" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + }, + "status": { + "optional": false, + "readonly": false, + "type": "\"confirmed\" | \"failed\" | \"pending\" | \"submitted\"" + }, + "txHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "CascadeTrackOptions": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions", + "members": { + "eventHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeProgressEvent) => void) | undefined" + }, + "timeout": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "CascadeProgressEvent": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeProgressEvent", + "members": { + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "elapsed": { + "optional": false, + "readonly": false, + "type": "number" + }, + "hopIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + }, + "status": { + "optional": false, + "readonly": false, + "type": "\"confirmed\" | \"failed\" | \"found\" | \"polling\" | \"timeout\" | \"waiting\"" + }, + "txHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "CascadeCompletionResult": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeCompletionResult", + "members": { + "failedAt": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "finalTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "finalTxResponse": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadedTxResponse | undefined" + }, + "hops": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo[]" + }, + "success": { + "optional": false, + "readonly": false, + "type": "boolean" + } + } + }, + "MultiChainTxResponse": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiChainTxResponse", + "members": { + "chains": { + "optional": false, + "readonly": false, + "type": "{\n blockNumber: bigint;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n hash: string;\n status: \"confirmed\" | \"failed\" | \"pending\";\n}[]" + }, + "transactions": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse[]" + } + } + }, + "OutboundTxDetails": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").OutboundTxDetails", + "members": { + "amount": { + "optional": false, + "readonly": false, + "type": "string" + }, + "assetAddr": { + "optional": false, + "readonly": false, + "type": "string" + }, + "destinationChain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "explorerUrl": { + "optional": false, + "readonly": false, + "type": "string" + }, + "externalTxHash": { + "optional": false, + "readonly": false, + "type": "string" + }, + "recipient": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "WaitForOutboundOptions": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").WaitForOutboundOptions", + "members": { + "_expectedDestinationChain": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "_outboundIndex": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "_resolvedSubTxId": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "initialWaitMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: {\n elapsed: number;\n status: \"failed\" | \"found\" | \"polling\" | \"timeout\" | \"waiting\";\n}) => void) | undefined" + }, + "timeout": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "SvmGatewayAccountMeta": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmGatewayAccountMeta", + "members": { + "isWritable": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "pubkey": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "SvmExecutePayloadFields": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmExecutePayloadFields", + "members": { + "accounts": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmGatewayAccountMeta[]" + }, + "instructionId": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "ixData": { + "optional": false, + "readonly": false, + "type": "Uint8Array" + }, + "targetProgram": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AccountStatus": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus", + "members": { + "mode": { + "optional": false, + "readonly": false, + "type": "\"read-only\" | \"signer\"" + }, + "uea": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UEAStatus" + } + } + }, + "UEAStatus": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UEAStatus", + "members": { + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "loaded": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "minRequiredVersion": { + "optional": false, + "readonly": false, + "type": "string" + }, + "requiresUpgrade": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "version": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "RescueFundsParams": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").RescueFundsParams", + "members": { + "prc20": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "universalTxId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "parseUEAVersion": { + "type": "(version: string) => number", + "members": {} + }, + "TransactionRoute": { + "type": "typeof import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute", + "members": { + "CEA_TO_CEA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.CEA_TO_CEA" + }, + "CEA_TO_PUSH": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.CEA_TO_PUSH" + }, + "UOA_TO_CEA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.UOA_TO_CEA" + }, + "UOA_TO_PUSH": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.UOA_TO_PUSH" + } + } + }, + "detectRoute": { + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams) => import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute", + "members": {} + }, + "isChainTarget": { + "type": "(to: unknown) => to is import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget", + "members": {} + }, + "DEFAULT_MAX_PC_FOR_GAS_BUFFER_BPS": { + "type": "1000", + "members": {} + }, + "MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT": { + "type": "10000", + "members": {} + }, + "quoteMaxPCForGasCap": { + "type": "(input: import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapInput) => import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": {} + }, + "quoteMaxPCForGasCapFromNativeValue": { + "type": "(input: import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapFromNativeValueInput) => import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": {} + }, + "MaxPCForGasCapInput": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapInput", + "members": { + "bufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "gasLegNativePc": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "MaxPCForGasCapFromNativeValueInput": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapFromNativeValueInput", + "members": { + "bufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "nativeValueForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "MaxPCForGasCapQuote": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": { + "bufferBps": { + "optional": false, + "readonly": false, + "type": "number" + }, + "gasLegNativePc": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxPCForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "nativeValueForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "getCEAAddress": { + "type": "(ueaAddress: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise", + "members": {} + }, + "getPushAccountForCEA": { + "type": "(ceaAddress: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise<`0x${string}`>", + "members": {} + }, + "isCEA": { + "type": "(address: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise", + "members": {} + }, + "chainSupportsCEA": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "chainSupportsOutbound": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "getCEAFactoryAddress": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => `0x${string}` | undefined", + "members": {} + }, + "getAllCEAAddresses": { + "type": "(ueaAddress: `0x${string}`, rpcUrls?: Partial>) => Promise", + "members": {} + }, + "encodeSvmExecutePayload": { + "type": "(fields: import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmExecutePayloadFields) => `0x${string}`", + "members": {} + }, + "isSvmChain": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "isValidSolanaHexAddress": { + "type": "(address: string) => boolean", + "members": {} + }, + "buildMigrationPayload": { + "type": "() => `0x${string}`", + "members": {} + }, + "buildErc20WithdrawalMulticall": { + "type": "(tokenAddress: `0x${string}`, recipientAddress: `0x${string}`, amount: bigint) => import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiCall[]", + "members": {} + }, + "ReadChain": { + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain", + "members": {} + }, + "ReadDestination": { + "type": "{\n chain: import(\"sdk/src/lib/read-state/read-state.types\").ReadChain;\n} | {\n chainId: string;\n chainNamespace: string;\n}", + "members": {} + }, + "ResolvedDestination": { + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}", + "members": { + "caip2": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainId": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "namespace": { + "optional": false, + "readonly": false, + "type": "\"eip155\" | \"solana\" | \"web2\"" + } + } + }, + "ReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").SvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery", + "members": { + "type": { + "optional": false, + "readonly": false, + "type": "\"accountBalance\" | \"contractCall\" | \"http\" | \"lamportBalance\" | \"rawAccountData\" | \"splTokenAccount\" | \"storageSlot\"" + } + } + }, + "EvmReadQuery": { + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n target: `0x${string}`;\n type: \"contractCall\";\n} | {\n callData: `0x${string}`;\n target: `0x${string}`;\n type: \"contractCall\";\n} | {\n slot: `0x${string}` | bigint;\n target: `0x${string}`;\n type: \"storageSlot\";\n} | {\n target: `0x${string}`;\n type: \"accountBalance\";\n}", + "members": { + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"accountBalance\" | \"contractCall\" | \"storageSlot\"" + } + } + }, + "SvmReadQuery": { + "type": "{\n account: string | Uint8Array;\n accountName?: string;\n idl?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n type: \"rawAccountData\";\n} | {\n account: string | Uint8Array;\n type: \"lamportBalance\";\n} | {\n account: string | Uint8Array;\n type: \"splTokenAccount\";\n}", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "string | Uint8Array" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"lamportBalance\" | \"rawAccountData\" | \"splTokenAccount\"" + } + } + }, + "Web2ReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery", + "members": { + "body": { + "optional": true, + "readonly": false, + "type": "string | Uint8Array | undefined" + }, + "extract": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[]" + }, + "headers": { + "optional": true, + "readonly": false, + "type": "Record | undefined" + }, + "method": { + "optional": true, + "readonly": false, + "type": "\"GET\" | \"POST\" | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"http\"" + }, + "url": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "Web2Extract": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract", + "members": { + "decimals": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "path": { + "optional": false, + "readonly": false, + "type": "string" + }, + "valueType": { + "optional": false, + "readonly": false, + "type": "\"bool\" | \"bytes\" | \"int256\" | \"string\" | \"uint256\"" + } + } + }, + "Web2ValueType": { + "type": "\"bool\" | \"bytes\" | \"int256\" | \"string\" | \"uint256\"", + "members": {} + }, + "EncodedReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery", + "members": { + "blockRef": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "encoded": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "namespace": { + "optional": false, + "readonly": false, + "type": "\"eip155\" | \"solana\" | \"web2\"" + }, + "ownerBytes": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "queryType": { + "optional": false, + "readonly": false, + "type": "number" + }, + "resultShape": { + "optional": false, + "readonly": false, + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}" + }, + "warnings": { + "optional": false, + "readonly": false, + "type": "string[]" + } + } + }, + "ReadResultShape": { + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"bytes32\" | \"evmCall\" | \"raw\" | \"svmAccount\" | \"uint256\" | \"web2\"" + } + } + }, + "DecodedReadResult": { + "type": "{\n accountName: string;\n kind: \"svmAccount\";\n value: unknown;\n} | {\n kind: \"bytes32\";\n value: `0x${string}`;\n} | {\n kind: \"evmCall\";\n value: unknown;\n} | {\n kind: \"raw\";\n value: `0x${string}`;\n} | {\n kind: \"uint256\";\n value: bigint;\n} | {\n kind: \"web2\";\n values: readonly unknown[];\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"bytes32\" | \"evmCall\" | \"raw\" | \"svmAccount\" | \"uint256\" | \"web2\"" + } + } + }, + "ReadPreflight": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight", + "members": { + "destination": { + "optional": false, + "readonly": false, + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}" + }, + "fetchedAt": { + "optional": false, + "readonly": false, + "type": "number" + }, + "observedChainHeight": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pushBlockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pushGasPrice": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "universalCallback": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "universalCore": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ReadSpec": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "{\n chainId: string;\n chainNamespace: string;\n owner: `0x${string}`;\n}" + }, + "blockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "expiryPushChainHeight": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "minConfirmations": { + "optional": false, + "readonly": false, + "type": "number" + }, + "query": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "revertRecipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ReadSpecTuple": { + "type": "readonly [\n readonly [\n string,\n string,\n `0x${string}`\n ],\n `0x${string}`,\n number,\n bigint,\n bigint,\n bigint,\n `0x${string}`\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "readonly [\n string,\n string,\n `0x${string}`\n]" + }, + "1": { + "optional": false, + "readonly": true, + "type": "`0x${string}`" + }, + "2": { + "optional": false, + "readonly": true, + "type": "number" + }, + "3": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "4": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "5": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "6": { + "optional": false, + "readonly": true, + "type": "`0x${string}`" + }, + "length": { + "optional": false, + "readonly": true, + "type": "7" + } + } + }, + "BuildReadSpecParams": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").BuildReadSpecParams", + "members": { + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "budgetBuffer": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback | undefined" + }, + "callbackBudget": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "destination": { + "optional": false, + "readonly": false, + "type": "{\n chain: import(\"sdk/src/lib/read-state/read-state.types\").ReadChain;\n} | {\n chainId: string;\n chainNamespace: string;\n}" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "expiryPushChainHeight": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFeeBufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "owner": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "query": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").SvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "PreparedRead": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead", + "members": { + "__@preparedReadValue": { + "optional": true, + "readonly": true, + "type": "T | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback | undefined" + }, + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "encodedQuery": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery" + }, + "encodedSpec": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "fees": { + "optional": false, + "readonly": false, + "type": "{\n callbackBudget: bigint;\n protocolFee: bigint;\n total: bigint;\n}" + }, + "preflight": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "queryKey": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "resultShape": { + "optional": false, + "readonly": false, + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}" + }, + "spec": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec" + }, + "specTuple": { + "optional": false, + "readonly": false, + "type": "readonly [\n readonly [\n string,\n string,\n `0x${string}`\n ],\n `0x${string}`,\n number,\n bigint,\n bigint,\n bigint,\n `0x${string}`\n]" + }, + "value": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "warnings": { + "optional": false, + "readonly": false, + "type": "string[]" + } + } + }, + "ReadCallback": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "((spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpecTuple, callbackGasLimit: bigint) => readonly unknown[]) | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "gasLimit": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "target": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "SimulateReadResult": { + "type": "{\n args?: readonly unknown[];\n error: string;\n errorName?: string;\n ok: false;\n} | {\n ok: true;\n}", + "members": { + "ok": { + "optional": false, + "readonly": false, + "type": "boolean" + } + } + }, + "ParsedReadRequest": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ParsedReadRequest", + "members": { + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackTarget": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "logIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "originalFunder": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "requestId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "requestIdUint": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "spec": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec" + }, + "totalPaid": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "FulfilOutcome": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").FulfilOutcome", + "members": { + "burned": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "delivered": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "expired": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "failReason": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "gasReported": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refunded": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refundFailed": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "ReceiptLike": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike", + "members": { + "logs": { + "optional": false, + "readonly": false, + "type": "readonly {\n address: string;\n data: string;\n logIndex?: number | string;\n topics: readonly string[];\n}[]" + } + } + }, + "ReadRef": { + "type": "{\n requestId: `0x${string}` | bigint;\n} | {\n txHash: `0x${string}`;\n}", + "members": {} + }, + "ReadLifecycleOptions": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadLifecycleOptions", + "members": { + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "resultShape": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadFees": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadFees", + "members": { + "burned": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "paid": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "refunded": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refundFailed": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + } + } + }, + "UniversalReadResponse": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse", + "members": { + "callbackDelivered": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "callbackFailReason": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "decoded": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").DecodedReadResult | undefined" + }, + "decodeError": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destination": { + "optional": false, + "readonly": false, + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}" + }, + "errorMsg": { + "optional": false, + "readonly": false, + "type": "string" + }, + "explorerUrl": { + "optional": false, + "readonly": false, + "type": "string" + }, + "fees": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadFees" + }, + "isTerminal": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "outcome": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME" + }, + "pcTx": { + "optional": false, + "readonly": false, + "type": "readonly {\n blockHeight: number;\n errorMsg: string;\n status: string;\n txHash: `0x${string}`;\n}[]" + }, + "raw": { + "optional": false, + "readonly": false, + "type": "{\n errorCode: import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n resultData: `0x${string}`;\n status: import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n} | null" + }, + "refresh": { + "optional": false, + "readonly": false, + "type": "() => Promise>" + }, + "request": { + "optional": false, + "readonly": false, + "type": "{\n callbackGasLimit: bigint;\n callbackTarget: `0x${string}`;\n createdAtHeight: bigint;\n logIndex: number;\n originalFunder: `0x${string}`;\n refundTo: `0x${string}`;\n spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec;\n}" + }, + "requestId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "requestIdUint": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "status": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "value": { + "optional": true, + "readonly": false, + "type": "T | undefined" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/read-state/read-state.types\").ReadLifecycleOptions) => Promise>" + } + } + }, + "ReadResponseTuple": { + "type": "{\n -readonly [K in keyof R]: import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse ? T : unknown>;\n}", + "members": {} + }, + "BatchReadResponse": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").BatchReadResponse", + "members": { + "atomic": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "count": { + "optional": false, + "readonly": false, + "type": "number" + }, + "reads": { + "optional": false, + "readonly": false, + "type": "{\n -readonly [K in keyof R]: import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse ? T : unknown>;\n}" + }, + "transactionHashes": { + "optional": true, + "readonly": false, + "type": "readonly `0x${string}`[] | undefined" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: Omit) => Promise>" + } + } + }, + "ReadOptions": { + "type": "((import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">)) & {\n callback?: (Pick & Required>) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n };\n}", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "advanced": { + "optional": true, + "readonly": false, + "type": "{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n} | undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "({\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} & {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n}) | ({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick & Pick & Required>) | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadPrepareOptions": { + "type": "((((({\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\">) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n}) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">)) & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n}) | ((({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n}) | ({\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\">)) & {\n blockNumber?: never;\n minConfirmations?: never;\n})) & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n}) & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "advanced": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadQueryOptions": { + "type": "({\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\">) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n}) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n}) | ({\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\">)", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadCallbackOptions": { + "type": "{\n callback?: ({\n gasLimit?: bigint;\n target: `0x${string}`;\n } & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n };\n}", + "members": { + "callback": { + "optional": true, + "readonly": false, + "type": "({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} | undefined" + } + } + }, + "ReadValue": { + "type": "O extends {\n abi: infer A extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: infer F extends string;\n} ? number extends A[\"length\"] ? unknown : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, O extends {\n args: infer Args extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n} ? Args : readonly [\n] extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> ? import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> & readonly [\n] : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>> extends infer Selected ? Selected extends {\n outputs: readonly unknown[];\n type: \"function\";\n} & import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiFunction ? {\n [key in keyof {\n [key in keyof import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"]]: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterToPrimitiveType, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"][key], import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterKind>;\n }]: {\n [key in keyof import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"]]: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterToPrimitiveType, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"][key], import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterKind>;\n }[key];\n} extends infer types ? types extends readonly [\n] ? void : types extends readonly [\n infer type\n] ? type : types : never : never : never : O extends {\n web2: {\n extract: infer E extends readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n };\n} ? {\n readonly [K in keyof E]: {\n bool: boolean;\n bytes: `0x${string}`;\n int256: bigint;\n string: string;\n uint256: bigint;\n }[E[K][\"valueType\"]];\n} : O extends {\n storageSlot: unknown;\n} ? `0x${string}` : O extends {\n idl: infer I extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} ? string extends Extract, string> ? unknown : (O extends {\n functionName: infer N extends string;\n} ? N : undefined) extends string ? import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/index\").IdlAccounts[{\n [K in Extract, string>]: Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : K> extends Lowercase<(O extends {\n functionName: infer N extends string;\n } ? N : undefined) & string extends `${infer H}_${infer T}` ? `${H}${Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : (O extends {\n functionName: infer N extends string;\n } ? N : undefined) & string> ? K : never;\n}[Extract, string>]] : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/index\").IdlAccounts[Extract, string>] : bigint", + "members": {} + }, + "ValidateReadCall": { + "type": "O extends {\n abi: infer A extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: infer F extends string;\n} ? (readonly [\n] extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> ? {\n args?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n} : {\n args: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n}) & {\n functionName: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionName;\n} : O extends {\n functionName: infer N extends string;\n idl: infer I extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} ? string extends Extract, string> ? unknown : [\n {\n [K in Extract, string>]: Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : K> extends Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : N> ? K : never;\n }[Extract, string>]\n] extends [\n never\n] ? {\n functionName: Extract, string>;\n} : unknown : unknown", + "members": {} + }, + "ReadWeb2Options": { + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options", + "members": { + "body": { + "optional": true, + "readonly": false, + "type": "string | Uint8Array | undefined" + }, + "extract": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[]" + }, + "headers": { + "optional": true, + "readonly": false, + "type": "Record | undefined" + }, + "method": { + "optional": true, + "readonly": false, + "type": "\"GET\" | \"POST\" | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadTrackOptions": { + "type": "{\n advanced?: Omit, \"enforceGasCheck\">;\n resultShape?: import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape;\n}", + "members": { + "advanced": { + "optional": true, + "readonly": false, + "type": "Omit<{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n}, \"enforceGasCheck\"> | undefined" + }, + "resultShape": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape | undefined" + } + } + }, + "ReadExecuteOptions": { + "type": "{\n advanced?: {\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n } | undefined;\n progressHook?: ((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined;\n waitForCompletion?: boolean | undefined;\n}", + "members": { + "advanced": { + "optional": true, + "readonly": false, + "type": "{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n} | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + } + } + }, + "UNIVERSAL_READ_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS", + "members": { + "ABORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.ABORTED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.EXPIRED" + }, + "FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.FAILED" + }, + "FULFILLED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.FULFILLED" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.PENDING" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.UNSPECIFIED" + }, + "VOTING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.VOTING" + } + } + }, + "READ_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS", + "members": { + "ERROR": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.ERROR" + }, + "SUCCESS": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.SUCCESS" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.UNSPECIFIED" + } + } + }, + "READ_ERROR_CODE": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE", + "members": { + "INVALID_QUERY": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.INVALID_QUERY" + }, + "INVALID_RESULT": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.INVALID_RESULT" + }, + "NOT_FOUND": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.NOT_FOUND" + }, + "REJECTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.REJECTED" + }, + "REVERTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.REVERTED" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.UNSPECIFIED" + }, + "UNSUPPORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.UNSUPPORTED" + } + } + }, + "READ_OUTCOME": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME", + "members": { + "ABORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.ABORTED" + }, + "CALLBACK_FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.CALLBACK_FAILED" + }, + "DECODE_FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.DECODE_FAILED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.EXPIRED" + }, + "FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.FAILED" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.PENDING" + }, + "SOURCE_ERROR": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.SOURCE_ERROR" + }, + "SUCCESS": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.SUCCESS" + }, + "UNKNOWN": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.UNKNOWN" + } + } + }, + "CONTRACT_REQUEST_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS", + "members": { + "EXECUTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.EXECUTED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.EXPIRED" + }, + "NONE": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.NONE" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.PENDING" + }, + "SETTLED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.SETTLED" + } + } + }, + "TERMINAL_READ_STATUSES": { + "type": "ReadonlySet", + "members": {} + }, + "ReadStateError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadStateError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidReadQueryError": { + "type": "import(\"sdk/src/lib/read-state/errors\").InvalidReadQueryError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidReadSpecError": { + "type": "import(\"sdk/src/lib/read-state/errors\").InvalidReadSpecError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "violations": { + "optional": false, + "readonly": true, + "type": "readonly import(\"sdk/src/lib/read-state/errors\").ReadSpecViolation[]" + } + } + }, + "ReadHeightUnavailableError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadHeightUnavailableError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "UnsupportedReadDestinationError": { + "type": "import(\"sdk/src/lib/read-state/errors\").UnsupportedReadDestinationError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadDecodeError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadDecodeError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadTimeoutError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadTimeoutError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "lastStatus": { + "optional": false, + "readonly": true, + "type": "number" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadNotFoundError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadNotFoundError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadRegistryUnavailableError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadRegistryUnavailableError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadSpecViolation": { + "type": "\"CALLBACK_GAS_LIMIT_EXCEEDED\" | \"DOMAIN_BLOCKED\" | \"EMPTY_QUERY\" | \"EXCESSIVE_FEE\" | \"INSUFFICIENT_CALLBACK_BUDGET\" | \"INSUFFICIENT_FEE\" | \"INVALID_ACCOUNT_ID\" | \"INVALID_BLOCK_NUMBER\" | \"INVALID_EXPIRY_HEIGHT\" | \"INVALID_MIN_CONFIRMATIONS\" | \"SVM_OWNER_NOT_32_BYTES\" | \"ZERO_CALLBACK_BUDGET\" | \"ZERO_CALLBACK_GAS_LIMIT\" | \"ZERO_REVERT_RECIPIENT\"", + "members": {} + }, + "resolveDestination": { + "type": "(dest: import(\"sdk/src/lib/read-state/read-state.types\").ReadDestination) => import(\"sdk/src/lib/read-state/read-state.types\").ResolvedDestination", + "members": {} + }, + "encodeReadQuery": { + "type": "(destination: import(\"sdk/src/lib/read-state/read-state.types\").ReadDestination, query: import(\"sdk/src/lib/read-state/read-state.types\").ReadQuery, options?: {\n blockNumber?: bigint;\n minSlot?: bigint;\n}) => import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery", + "members": {} + }, + "decodeReadResult": { + "type": "(resultData: `0x${string}`, shape: import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape) => import(\"sdk/src/lib/read-state/read-state.types\").DecodedReadResult", + "members": {} + }, + "parseReadRequestsFromReceipt": { + "type": "(receipt: import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike, universalCallback: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").ParsedReadRequest[]", + "members": {} + }, + "parseFulfilOutcome": { + "type": "(receipt: import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike, universalCallback: `0x${string}`, requestId: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").FulfilOutcome", + "members": {} + }, + "buildReadSpecFromPreflight": { + "type": "(preflight: import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight, params: import(\"sdk/src/lib/read-state/read-state.types\").BuildReadSpecParams, defaults?: {\n refundTo?: `0x${string}`;\n}) => import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead", + "members": {} + }, + "validateReadSpec": { + "type": "(input: import(\"sdk/src/lib/read-state/validate\").ValidateReadSpecInput) => {\n ok: false;\n violations: import(\"sdk/src/lib/read-state/errors\").ReadSpecViolation[];\n} | {\n ok: true;\n}", + "members": {} + }, + "toCallData": { + "type": "(prepared: import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead, target: {\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: (spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpecTuple, callbackGasLimit: bigint) => readonly unknown[];\n functionName: string;\n}) => {\n data: `0x${string}`;\n value: bigint;\n}", + "members": {} + }, + "sizeCallbackBudget": { + "type": "(callbackGasLimit: bigint, pushGasPrice: bigint, buffer?: number) => bigint", + "members": {} + }, + "inferResultShape": { + "type": "(namespace: string, query: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape", + "members": {} + }, + "toRequestIdHex": { + "type": "(id: `0x${string}` | bigint) => `0x${string}`", + "members": {} + }, + "toReadQuery": { + "type": "(subject: string, o: ReadOptionsInput, resolvedTokenProgram?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@solana/web3.js/lib/index\").PublicKey) => import(\"sdk/src/lib/read-state/read-state.types\").ReadQuery", + "members": {} + }, + "UNIVERSAL_CALLBACK_EVM": { + "type": "readonly [\n {\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"requestExternalReadSelf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"estimateFee\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"statusOf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"enum RequestStatus\";\n readonly name: \"\";\n readonly type: \"uint8\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"isFulfilled\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getPendingRead\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly internalType: \"struct PendingRead\";\n readonly name: \"\";\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"totalEscrowed\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"blockedDomains\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly indexed: false;\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"readSpec\";\n readonly type: \"tuple\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"totalPaid\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"protocolFee\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ReadRequested\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"ReadFulfilled\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"reason\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"CallbackFailed\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"gasReported\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"burned\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"CallbackGasReported\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundSent\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundFailed\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RequestExpired\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"vaultPC\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ProtocolFeeDistributed\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidAccountId\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"EmptyQuery\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidMinConfirmations\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"DomainBlocked\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidBlockNumber\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidExpiryHeight\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroRevertRecipient\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroCallbackGasLimit\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint64\";\n readonly name: \"provided\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"max\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"CallbackGasLimitExceeded\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"required\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"InsufficientFee\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ExcessiveFee\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"actual\";\n readonly type: \"uint8\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"expected\";\n readonly type: \"uint8\";\n }\n ];\n readonly name: \"InvalidRequestStatus\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ContractIsPaused\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"CallerIsNotUCallbackModule\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n }\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"requestExternalReadSelf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n}" + }, + "1": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"estimateFee\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "2": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"statusOf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"enum RequestStatus\";\n readonly name: \"\";\n readonly type: \"uint8\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "3": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"isFulfilled\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "4": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getPendingRead\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly internalType: \"struct PendingRead\";\n readonly name: \"\";\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "5": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"totalEscrowed\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "6": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"blockedDomains\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "7": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly indexed: false;\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"readSpec\";\n readonly type: \"tuple\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"totalPaid\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"protocolFee\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ReadRequested\";\n readonly type: \"event\";\n}" + }, + "8": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"ReadFulfilled\";\n readonly type: \"event\";\n}" + }, + "9": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"reason\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"CallbackFailed\";\n readonly type: \"event\";\n}" + }, + "10": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"gasReported\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"burned\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"CallbackGasReported\";\n readonly type: \"event\";\n}" + }, + "11": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundSent\";\n readonly type: \"event\";\n}" + }, + "12": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundFailed\";\n readonly type: \"event\";\n}" + }, + "13": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RequestExpired\";\n readonly type: \"event\";\n}" + }, + "14": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"vaultPC\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ProtocolFeeDistributed\";\n readonly type: \"event\";\n}" + }, + "15": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidAccountId\";\n readonly type: \"error\";\n}" + }, + "16": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"EmptyQuery\";\n readonly type: \"error\";\n}" + }, + "17": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidMinConfirmations\";\n readonly type: \"error\";\n}" + }, + "18": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"DomainBlocked\";\n readonly type: \"error\";\n}" + }, + "19": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidBlockNumber\";\n readonly type: \"error\";\n}" + }, + "20": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidExpiryHeight\";\n readonly type: \"error\";\n}" + }, + "21": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroRevertRecipient\";\n readonly type: \"error\";\n}" + }, + "22": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroCallbackGasLimit\";\n readonly type: \"error\";\n}" + }, + "23": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint64\";\n readonly name: \"provided\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"max\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"CallbackGasLimitExceeded\";\n readonly type: \"error\";\n}" + }, + "24": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"required\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"InsufficientFee\";\n readonly type: \"error\";\n}" + }, + "25": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ExcessiveFee\";\n readonly type: \"error\";\n}" + }, + "26": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"actual\";\n readonly type: \"uint8\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"expected\";\n readonly type: \"uint8\";\n }\n ];\n readonly name: \"InvalidRequestStatus\";\n readonly type: \"error\";\n}" + }, + "27": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ContractIsPaused\";\n readonly type: \"error\";\n}" + }, + "28": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"CallerIsNotUCallbackModule\";\n readonly type: \"error\";\n}" + }, + "29": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n}" + }, + "length": { + "optional": false, + "readonly": true, + "type": "30" + } + } + }, + "UNIVERSAL_READ_REGISTRY_EVM": { + "type": "readonly [\n {\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n },\n {\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"read\";\n readonly outputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"universalCallback_\";\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"constructor\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"initialize\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getLocalContext\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"hasResult\";\n readonly outputs: readonly [\n {\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"onUniversalData\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"queryKeyOf\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes32\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"readerOf\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"requestOrderOf\";\n readonly outputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"universalCallback\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"resultByRequestId\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"latestResult\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"version\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"Initialized\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadRequested\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadStored\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidInitialization\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"NotInitializing\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroAddressInit\";\n readonly type: \"error\";\n }\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n },\n {\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"read\";\n readonly outputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n}" + }, + "1": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"universalCallback_\";\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"constructor\";\n}" + }, + "2": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"initialize\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n}" + }, + "3": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getLocalContext\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "4": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"hasResult\";\n readonly outputs: readonly [\n {\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "5": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"onUniversalData\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n}" + }, + "6": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"queryKeyOf\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes32\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "7": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"readerOf\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "8": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"requestOrderOf\";\n readonly outputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "9": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"universalCallback\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "10": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"resultByRequestId\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "11": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"latestResult\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "12": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"version\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"Initialized\";\n readonly type: \"event\";\n}" + }, + "13": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadRequested\";\n readonly type: \"event\";\n}" + }, + "14": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadStored\";\n readonly type: \"event\";\n}" + }, + "15": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidInitialization\";\n readonly type: \"error\";\n}" + }, + "16": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"NotInitializing\";\n readonly type: \"error\";\n}" + }, + "17": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n}" + }, + "18": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroAddressInit\";\n readonly type: \"error\";\n}" + }, + "length": { + "optional": false, + "readonly": true, + "type": "19" + } + } + }, + "PushChainExecutionError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").PushChainExecutionError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PushChainBatchExecutionError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").PushChainBatchExecutionError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": false, + "readonly": true, + "type": "`0x${string}`[]" + } + } + }, + "DecodedErrorPayload": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload", + "members": { + "decoded": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "name": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "selector": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "PushChainInitializeOptions": { + "type": "import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions", + "members": { + "agenticWallet": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "blockExplorers": { + "optional": true, + "readonly": false, + "type": "Partial> | undefined" + }, + "network": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "printTraces": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "rpcUrls": { + "optional": true, + "readonly": false, + "type": "Partial> | undefined" + } + } + }, + "AGENTIC_ERROR_CODE": { + "type": "{\n readonly AGENT_GAS_INSUFFICIENT: \"AGENT_GAS_INSUFFICIENT\";\n readonly AGENT_IS_OWNER: \"AGENT_IS_OWNER\";\n readonly AMBIGUOUS_RULE: \"AMBIGUOUS_RULE\";\n readonly ASSET_CHAIN_MISMATCH: \"ASSET_CHAIN_MISMATCH\";\n readonly CAPABILITY_UNAVAILABLE: \"CAPABILITY_UNAVAILABLE\";\n readonly CREATE_PARTIAL: \"CREATE_PARTIAL\";\n readonly DELETE_NEEDS_TARGET: \"DELETE_NEEDS_TARGET\";\n readonly DUPLICATE_RULE: \"DUPLICATE_RULE\";\n readonly FROM_NOT_ALLOWED: \"FROM_NOT_ALLOWED\";\n readonly GATEWAY_ALLOWANCE_INSUFFICIENT: \"GATEWAY_ALLOWANCE_INSUFFICIENT\";\n readonly INCONSISTENT_READ: \"INCONSISTENT_READ\";\n readonly INDEX_RACE: \"INDEX_RACE\";\n readonly INVALID_RULE: \"INVALID_RULE\";\n readonly NO_RULES_FOR_CHAIN: \"NO_RULES_FOR_CHAIN\";\n readonly NOT_AGENTIC_WALLET: \"NOT_AGENTIC_WALLET\";\n readonly NOT_ALLOWED_IN_AGENTIC_MODE: \"NOT_ALLOWED_IN_AGENTIC_MODE\";\n readonly NOT_OWNER_OR_AGENT: \"NOT_OWNER_OR_AGENT\";\n readonly NOT_WALLET_OWNER: \"NOT_WALLET_OWNER\";\n readonly READ_ONLY: \"READ_ONLY\";\n readonly RECEIPT_MISMATCH: \"RECEIPT_MISMATCH\";\n readonly RECEIPT_UNAVAILABLE: \"RECEIPT_UNAVAILABLE\";\n readonly RULE_NOT_FOUND: \"RULE_NOT_FOUND\";\n readonly RULE_READ_FAILED: \"RULE_READ_FAILED\";\n readonly TARGET_NOT_ON_RULE_CHAIN: \"TARGET_NOT_ON_RULE_CHAIN\";\n readonly WALLET_BALANCE_INSUFFICIENT: \"WALLET_BALANCE_INSUFFICIENT\";\n readonly WALLET_NOT_DEPLOYED: \"WALLET_NOT_DEPLOYED\";\n}", + "members": { + "AGENT_GAS_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\"" + }, + "AGENT_IS_OWNER": { + "optional": false, + "readonly": true, + "type": "\"AGENT_IS_OWNER\"" + }, + "AMBIGUOUS_RULE": { + "optional": false, + "readonly": true, + "type": "\"AMBIGUOUS_RULE\"" + }, + "ASSET_CHAIN_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"ASSET_CHAIN_MISMATCH\"" + }, + "CAPABILITY_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"CAPABILITY_UNAVAILABLE\"" + }, + "CREATE_PARTIAL": { + "optional": false, + "readonly": true, + "type": "\"CREATE_PARTIAL\"" + }, + "DELETE_NEEDS_TARGET": { + "optional": false, + "readonly": true, + "type": "\"DELETE_NEEDS_TARGET\"" + }, + "DUPLICATE_RULE": { + "optional": false, + "readonly": true, + "type": "\"DUPLICATE_RULE\"" + }, + "FROM_NOT_ALLOWED": { + "optional": false, + "readonly": true, + "type": "\"FROM_NOT_ALLOWED\"" + }, + "GATEWAY_ALLOWANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"GATEWAY_ALLOWANCE_INSUFFICIENT\"" + }, + "INCONSISTENT_READ": { + "optional": false, + "readonly": true, + "type": "\"INCONSISTENT_READ\"" + }, + "INDEX_RACE": { + "optional": false, + "readonly": true, + "type": "\"INDEX_RACE\"" + }, + "INVALID_RULE": { + "optional": false, + "readonly": true, + "type": "\"INVALID_RULE\"" + }, + "NO_RULES_FOR_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"NO_RULES_FOR_CHAIN\"" + }, + "NOT_AGENTIC_WALLET": { + "optional": false, + "readonly": true, + "type": "\"NOT_AGENTIC_WALLET\"" + }, + "NOT_ALLOWED_IN_AGENTIC_MODE": { + "optional": false, + "readonly": true, + "type": "\"NOT_ALLOWED_IN_AGENTIC_MODE\"" + }, + "NOT_OWNER_OR_AGENT": { + "optional": false, + "readonly": true, + "type": "\"NOT_OWNER_OR_AGENT\"" + }, + "NOT_WALLET_OWNER": { + "optional": false, + "readonly": true, + "type": "\"NOT_WALLET_OWNER\"" + }, + "READ_ONLY": { + "optional": false, + "readonly": true, + "type": "\"READ_ONLY\"" + }, + "RECEIPT_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_MISMATCH\"" + }, + "RECEIPT_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_UNAVAILABLE\"" + }, + "RULE_NOT_FOUND": { + "optional": false, + "readonly": true, + "type": "\"RULE_NOT_FOUND\"" + }, + "RULE_READ_FAILED": { + "optional": false, + "readonly": true, + "type": "\"RULE_READ_FAILED\"" + }, + "TARGET_NOT_ON_RULE_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"TARGET_NOT_ON_RULE_CHAIN\"" + }, + "WALLET_BALANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"WALLET_BALANCE_INSUFFICIENT\"" + }, + "WALLET_NOT_DEPLOYED": { + "optional": false, + "readonly": true, + "type": "\"WALLET_NOT_DEPLOYED\"" + } + } + }, + "AgenticError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"AMBIGUOUS_RULE\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"CREATE_PARTIAL\" | \"DELETE_NEEDS_TARGET\" | \"DUPLICATE_RULE\" | \"FROM_NOT_ALLOWED\" | \"GATEWAY_ALLOWANCE_INSUFFICIENT\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"" + }, + "details": { + "optional": true, + "readonly": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "AgenticRevertError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticRevertError", + "members": { + "agenticCode": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + } + } + }, + "AgenticAddress": { + "type": "`0x${string}`", + "members": {} + }, + "AgenticDoor": { + "type": "\"agent\" | \"owner\"", + "members": {} + }, + "AgenticErrorCode": { + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"AMBIGUOUS_RULE\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"CREATE_PARTIAL\" | \"DELETE_NEEDS_TARGET\" | \"DUPLICATE_RULE\" | \"FROM_NOT_ALLOWED\" | \"GATEWAY_ALLOWANCE_INSUFFICIENT\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"", + "members": {} + }, + "AgenticHex": { + "type": "`0x${string}`", + "members": {} + }, + "AgenticNamespace": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace", + "members": { + "create": { + "optional": false, + "readonly": false, + "type": "(label: string, options: import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions) => Promise" + }, + "derive": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n index?: number;\n}) => Promise<{\n address: `0x${string}`;\n deployed: boolean;\n index: number;\n}>" + }, + "list": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n wallets: import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary[];\n}>" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "(address: `0x${string}`) => import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet" + } + } + }, + "AgenticProgressHook": { + "type": "(event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void", + "members": {} + }, + "AgenticTxMetadata": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticTxMetadata", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destinationAccount": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "destinationCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "destinationInstruction": { + "optional": true, + "readonly": false, + "type": "{\n accounts: readonly {\n isWritable: boolean;\n pubkey: `0x${string}`;\n }[];\n data: `0x${string}`;\n program: `0x${string}`;\n} | undefined" + }, + "destinationTransfer": { + "optional": true, + "readonly": false, + "type": "{\n amount: bigint;\n recipient: `0x${string}`;\n token: `0x${string}`;\n} | undefined" + }, + "door": { + "optional": false, + "readonly": false, + "type": "\"agent\" | \"owner\"" + }, + "nativeCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "rawData": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rawTo": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesId": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticWallet": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "checkpoints": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n sinceBlock?: bigint;\n}) => Promise<{\n checkpoints: import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint[];\n}>" + }, + "info": { + "optional": false, + "readonly": false, + "type": "() => Promise" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n owner: `0x${string}`;\n}>" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "{\n add(rules: import(\"sdk/src/lib/agentic/agentic.types\").RuleInput[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise<{\n rulesIds: `0x${string}`[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n delete(rulesIds: `0x${string}`[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n delete(params: {\n all: true;\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n get(rulesId: `0x${string}`): Promise;\n list(): Promise<{\n rules: import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord[];\n }>;\n update(params: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n rules: {\n rule: import(\"sdk/src/lib/agentic/agentic.types\").RuleInput;\n rulesId: `0x${string}`;\n }[];\n }): Promise<{\n rules: {\n replaced: `0x${string}`;\n rulesId: `0x${string}`;\n }[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n}" + }, + "setLabel": { + "optional": false, + "readonly": false, + "type": "(label: string, opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n}) => Promise" + } + } + }, + "AllowedCall": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleCall", + "members": { + "app": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "label": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "maxValue": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "pins": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Pin[] | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector" + }, + "target": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "AssetCap": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset", + "members": { + "maxPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/tokens\").MoveableToken | string" + } + } + }, + "Checkpoint": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint", + "members": { + "blockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "kind": { + "optional": false, + "readonly": false, + "type": "\"OWNER_ACTION\" | \"RULES_GRANTED\" | \"RULES_REVOKED\"" + }, + "ref": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "seq": { + "optional": false, + "readonly": false, + "type": "number" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "CheckpointKind": { + "type": "\"OWNER_ACTION\" | \"RULES_GRANTED\" | \"RULES_REVOKED\"", + "members": {} + }, + "CreateOptions": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions", + "members": { + "progressHook": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook | undefined" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleInput[]" + } + } + }, + "CreateResult": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateResult", + "members": { + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "rulesIds": { + "optional": false, + "readonly": false, + "type": "`0x${string}`[]" + }, + "tx": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ForeignChainNamespace": { + "type": "`eip155:${string}` | `solana:${string}`", + "members": {} + }, + "DecodedSolanaRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").DecodedSolanaRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "assets": { + "optional": false, + "readonly": false, + "type": "{\n maxPerCall: bigint;\n maxTotal: bigint;\n token: string;\n}[]" + }, + "ceaAccounts": { + "optional": false, + "readonly": false, + "type": "readonly `0x${string}`[]" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "`solana:${string}`" + }, + "dataPins": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/agentic/codec/svm-terms\").SvmDataPinWire[]" + }, + "expectedCEA": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "format": { + "optional": false, + "readonly": false, + "type": "\"decoded\"" + }, + "gatewayProgram": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "maxGasPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pins": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/agentic/codec/svm-terms\").SvmAccountPinWire[]" + }, + "programs": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/agentic/codec/svm-terms\").AllowedProgramWire[]" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Rule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Rule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleCall[]" + }, + "assets": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset[] | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "maxGasPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "RuleInput": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").DecodedSolanaRule | import(\"sdk/src/lib/agentic/agentic.types\").Rule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "assets": { + "optional": true, + "readonly": false, + "type": "{\n maxPerCall: bigint;\n maxTotal: bigint;\n token: string;\n}[] | import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset[] | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "maxGasPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Pin": { + "type": "{\n account: number;\n arg?: never;\n expected: \"agentic:wallet\" | string;\n max?: never;\n token?: import(\"sdk/src/lib/constants/tokens\").MoveableToken | string;\n} | {\n account?: never;\n arg: number;\n expected: \"agentic:wallet\" | `0x${string}` | `0x${string}` | bigint;\n max?: never;\n} | {\n account?: never;\n arg: number;\n expected?: never;\n max: bigint;\n}", + "members": { + "account": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "arg": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "expected": { + "optional": true, + "readonly": false, + "type": "bigint | string | undefined" + }, + "max": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "Spent": { + "type": "{\n actions: {\n amountSpent: bigint;\n callsUsed: number;\n selector: \"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector;\n target: `0x${string}`;\n valueSpent: bigint;\n }[];\n kind: \"native\";\n} | {\n amountSpent: bigint;\n callsUsed: number;\n kind: \"native\";\n valueSpent: bigint;\n} | {\n assets: {\n spent: bigint;\n token: string;\n }[];\n kind: \"universal\";\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"native\" | \"universal\"" + } + } + }, + "WalletMarker": { + "type": "\"agentic:wallet\"", + "members": {} + }, + "RulesRecord": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "enabled": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "rule": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").DecodedSolanaRule | import(\"sdk/src/lib/agentic/agentic.types\").Rule" + }, + "rulesId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "spent": { + "optional": false, + "readonly": false, + "type": "{\n actions: {\n amountSpent: bigint;\n callsUsed: number;\n selector: \"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector;\n target: `0x${string}`;\n valueSpent: bigint;\n }[];\n kind: \"native\";\n} | {\n amountSpent: bigint;\n callsUsed: number;\n kind: \"native\";\n valueSpent: bigint;\n} | {\n assets: {\n spent: bigint;\n token: string;\n }[];\n kind: \"universal\";\n}" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Selector": { + "type": "`${string}(${string})` | `0x${string}`", + "members": {} + }, + "WalletInfo": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").WalletInfo", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "label": { + "optional": false, + "readonly": false, + "type": "string" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "rulesCount": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "WalletSummary": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "label": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesCount": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "PushChain": { + "type": "import(\"sdk/src/lib/push-chain/push-chain\").PushChain", + "members": { + "accountStatus": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus" + }, + "accountStatusReady": { + "optional": false, + "readonly": false, + "type": "Promise" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace" + }, + "explorer": { + "optional": false, + "readonly": false, + "type": "{\n getTransactionUrl: (txHash: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n listAllUrls: () => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n listUrls: (options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n}" + }, + "funds": { + "optional": false, + "readonly": false, + "type": "{\n getConversionQuote: (amountIn: bigint, options: {\n from: import(\"sdk/src/lib/constants/tokens\").PayableToken | undefined;\n to: import(\"sdk/src/lib/constants/tokens\").MoveableToken | undefined;\n }) => Promise;\n}" + }, + "getAccountStatus": { + "optional": false, + "readonly": false, + "type": "(options?: {\n forceRefresh?: boolean;\n}) => Promise" + }, + "isReadMode": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "moveable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").MoveableTokenAccessor;\n}" + }, + "payable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").PayableTokenAccessor;\n}" + }, + "reinitialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "universal": { + "optional": false, + "readonly": false, + "type": "{\n readonly account: `0x${string}`;\n executeReads: (reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>;\n executeTransactions: (txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise;\n migrateCEA: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"migrateCEA\"];\n readonly origin: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n prepareRead: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n prepareTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"prepareTransaction\"];\n read: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n rescueFunds: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"rescueFunds\"];\n sendTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"execute\"];\n signMessage: (data: Uint8Array) => Promise;\n signTypedData: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n trackRead: {\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n };\n trackTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"trackTransaction\"];\n}" + }, + "upgradeAccount": { + "optional": false, + "readonly": false, + "type": "(options?: {\n progressHook?: (progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n}) => Promise" + } + } + }, + "Preset": { + "type": "import(\"sdk/src/lib/agentic/presets/types\").Preset", + "members": { + "chains": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace[]" + }, + "constant": { + "optional": false, + "readonly": false, + "type": "\"DEXES\" | \"LENDING\" | \"PREDICTION\"" + }, + "name": { + "optional": false, + "readonly": false, + "type": "string" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"CATEGORY\"" + } + } + }, + "PresetCategory": { + "type": "\"DEXES\" | \"LENDING\" | \"PREDICTION\"", + "members": {} + }, + "PresetAsset": { + "type": "import(\"sdk/src/lib/agentic/presets/types\").PresetAsset", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "maxPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/tokens\").MoveableToken | string" + } + } + }, + "PresetOptions": { + "type": "import(\"sdk/src/lib/agentic/presets/types\").PresetOptions", + "members": { + "agent": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "assets": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/presets/types\").PresetAsset[] | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "validUntil": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadyPresetOptions": { + "type": "import(\"sdk/src/lib/agentic/presets/types\").ReadyPresetOptions", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "assets": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/presets/types\").PresetAsset[] | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "PresetRuleTemplate": { + "type": "{\n agent?: `0x${string}`;\n validUntil?: number;\n} & Omit", + "members": { + "agent": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleCall[]" + }, + "assets": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset[] | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "maxGasPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "validUntil": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "AgenticPresets": { + "type": "import(\"sdk/src/lib/agentic/presets/types\").AgenticPresets", + "members": { + "get": { + "optional": false, + "readonly": false, + "type": "{\n (preset: import(\"sdk/src/lib/agentic/presets/types\").PresetCategory, options: import(\"sdk/src/lib/agentic/presets/types\").ReadyPresetOptions): {\n rules: import(\"sdk/src/lib/agentic/agentic.types\").Rule[];\n };\n (preset: import(\"sdk/src/lib/agentic/presets/types\").PresetCategory, options?: import(\"sdk/src/lib/agentic/presets/types\").PresetOptions): {\n rules: import(\"sdk/src/lib/agentic/presets/types\").PresetRuleTemplate[];\n };\n}" + }, + "list": { + "optional": false, + "readonly": false, + "type": "(options?: {\n type?: \"CATEGORY\";\n}) => {\n presets: import(\"sdk/src/lib/agentic/presets/types\").Preset[];\n}" + } + } + } + }, + "pushChainStatic": { + "CONSTANTS": { + "optional": false, + "readonly": false, + "type": "{\n AGENTIC: Readonly<{\n PRESETS: Readonly<{\n CATEGORY: Readonly<{\n DEXES: \"DEXES\";\n LENDING: \"LENDING\";\n PREDICTION: \"PREDICTION\";\n }>;\n }>;\n WALLET: \"agentic:wallet\";\n }>;\n CHAIN: typeof import(\"sdk/src/lib/constants/enums\").CHAIN;\n LIBRARY: typeof import(\"sdk/src/lib/constants/enums\").LIBRARY;\n MOVEABLE: {\n TOKEN: import(\"sdk/src/lib/constants/tokens\").MoveableTokenConstantsMap;\n };\n PAYABLE: {\n TOKEN: import(\"sdk/src/lib/constants/tokens\").PayableTokenConstantsMap;\n };\n PUSH_NETWORK: typeof import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n READ: {\n readonly CALLBACK_BUDGET_BUFFER: 3;\n readonly CHAIN: {\n readonly WEB2: \"web2\";\n } & Readonly<{\n readonly ARBITRUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA;\n readonly BASE_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA;\n readonly BNB_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET;\n readonly ETHEREUM_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET;\n readonly ETHEREUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA;\n readonly PUSH_LOCALNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET;\n readonly PUSH_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET;\n readonly PUSH_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly PUSH_TESTNET_DONUT: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly SOLANA_DEVNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET;\n readonly SOLANA_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET;\n readonly SOLANA_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n readonly WEB2: \"web2\";\n }>;\n readonly DEFAULT_EXPIRY_BLOCKS: 300n;\n readonly ERROR_CODE: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n readonly MAX_CALLBACK_GAS_LIMIT: 1000000n;\n readonly MIN_CONFIRMATIONS_FLOOR: 1;\n readonly NAMESPACE: {\n readonly EVM: \"eip155\";\n readonly SVM: \"solana\";\n readonly WEB2: \"web2\";\n };\n readonly OUTCOME: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME;\n readonly REGISTRY_CALLBACK_GAS: 500000n;\n readonly RESULT_STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n readonly STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS;\n readonly UNIVERSAL_CALLBACK_ADDRESSES: Record;\n readonly UNIVERSAL_CORE_ADDRESSES: Record;\n readonly UNIVERSAL_READ_REGISTRY_ADDRESS: {\n readonly TESTNET_DONUT: \"0x00000000000000000000000000000000000000b2\";\n };\n readonly WEB2: \"web2\";\n readonly WEB2_DEFAULT_TIMEOUT_MS: 5000;\n readonly WEB2_MAX_EXTRACT_ENTRIES: 16;\n };\n}" + }, + "initialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "utils": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/utils\").Utils" + } + }, + "pushChainInstance": { + "accountStatus": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus" + }, + "accountStatusReady": { + "optional": false, + "readonly": false, + "type": "Promise" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace" + }, + "explorer": { + "optional": false, + "readonly": false, + "type": "{\n getTransactionUrl: (txHash: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n listAllUrls: () => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n listUrls: (options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n}" + }, + "funds": { + "optional": false, + "readonly": false, + "type": "{\n getConversionQuote: (amountIn: bigint, options: {\n from: import(\"sdk/src/lib/constants/tokens\").PayableToken | undefined;\n to: import(\"sdk/src/lib/constants/tokens\").MoveableToken | undefined;\n }) => Promise;\n}" + }, + "getAccountStatus": { + "optional": false, + "readonly": false, + "type": "(options?: {\n forceRefresh?: boolean;\n}) => Promise" + }, + "isReadMode": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "moveable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").MoveableTokenAccessor;\n}" + }, + "payable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").PayableTokenAccessor;\n}" + }, + "reinitialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "universal": { + "optional": false, + "readonly": false, + "type": "{\n readonly account: `0x${string}`;\n executeReads: (reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>;\n executeTransactions: (txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise;\n migrateCEA: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"migrateCEA\"];\n readonly origin: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n prepareRead: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n prepareTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"prepareTransaction\"];\n read: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n rescueFunds: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"rescueFunds\"];\n sendTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"execute\"];\n signMessage: (data: Uint8Array) => Promise;\n signTypedData: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n trackRead: {\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n };\n trackTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"trackTransaction\"];\n}" + }, + "upgradeAccount": { + "optional": false, + "readonly": false, + "type": "(options?: {\n progressHook?: (progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n}) => Promise" + } + }, + "transactionMethods": { + "account": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "executeReads": { + "optional": false, + "readonly": false, + "type": "(reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>" + }, + "executeTransactions": { + "optional": false, + "readonly": false, + "type": "(txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise" + }, + "migrateCEA": { + "optional": false, + "readonly": false, + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => Promise" + }, + "origin": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "prepareRead": { + "optional": false, + "readonly": false, + "type": "(subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>" + }, + "prepareTransaction": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions) => Promise" + }, + "read": { + "optional": false, + "readonly": false, + "type": "(subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>" + }, + "rescueFunds": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").RescueFundsParams) => Promise" + }, + "sendTransaction": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").ExecuteParams | import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions) => Promise" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": false, + "readonly": false, + "type": "({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise" + }, + "trackRead": { + "optional": false, + "readonly": false, + "type": "{\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n}" + }, + "trackTransaction": { + "optional": false, + "readonly": false, + "type": "(txHash: string, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TrackTransactionOptions) => Promise" + } + }, + "utilityMethods": { + "account": { + "optional": false, + "readonly": false, + "type": "{\n convertExecutorToOriginAccount: (ueaAddress: `0x${string}`, options?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n }) => Promise;\n convertOriginToExecutor: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n onlyCompute?: boolean;\n }) => Promise;\n deriveExecutorAccount: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n skipNetworkCheck?: boolean;\n }) => Promise;\n fromChainAgnostic: (caip: string) => import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n resolveControllerAccount: (address: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n skipNetworkCheck?: boolean;\n }) => Promise;\n toChainAgnostic: (address: string, options: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n toUniversal: (address: string, options: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n}" + }, + "agentic": { + "optional": false, + "readonly": true, + "type": "{\n readonly presets: import(\"sdk/src/lib/agentic/presets/types\").AgenticPresets;\n}" + }, + "chains": { + "optional": false, + "readonly": false, + "type": "{\n getChainName: (chainNamespace: string) => string | undefined;\n getChainNamespace: (chainName: string) => string | undefined;\n getSupportedChains: (network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK) => {\n chains: import(\"sdk/src/lib/constants/enums\").CHAIN[];\n };\n getSupportedChainsByName: (network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK) => {\n chains: string[];\n };\n}" + }, + "conversion": { + "optional": false, + "readonly": false, + "type": "{\n slippageToMinAmount(amount: string, options: {\n slippageBps: number;\n }): string;\n}" + }, + "helpers": { + "optional": false, + "readonly": false, + "type": "{\n encodeTxData({ abi, idl, functionName, args, }: {\n abi?: any;\n args?: any[];\n functionName: string;\n idl?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n }): `0x${string}`;\n formatUnits(value: bigint | string, decimalsOrOptions: {\n decimals: number;\n precision?: number;\n } | number): string;\n getChainName: (chainName: string) => string | undefined;\n parseUnits(value: string, exponent: {\n decimals: number;\n } | number): bigint;\n}" + }, + "signer": { + "optional": false, + "readonly": false, + "type": "{\n construct: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options: {\n signAndSendTransaction: (unsignedTx: Uint8Array) => Promise;\n signAuthorization?: (params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise;\n signMessage: (data: Uint8Array) => Promise;\n signTypedData?: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n }) => import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton;\n toUniversal: (signer: import(\"sdk/src/lib/universal/universal.types\").EthersV5SignerType | import(\"sdk/src/lib/universal/universal.types\").EthersV6SignerType | import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton | import(\"sdk/src/lib/universal/universal.types\").ViemSignerType) => Promise;\n toUniversalFromKeypair: (clientOrAccount: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@solana/web3.js/lib/index\").Keypair | import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").WalletClient | import(\"sdk/src/lib/universal/universal.types\").EthersV6SignerType, { chain, library }: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n library: import(\"sdk/src/lib/constants/enums\").LIBRARY;\n }) => Promise;\n}" + }, + "svm": { + "optional": false, + "readonly": false, + "type": "{\n getRegisteredIdls: () => Array<{\n address: `0x${string}`;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n }>;\n registerIdl: (idl: unknown) => void;\n}" + }, + "tokens": { + "optional": false, + "readonly": false, + "type": "{\n getMoveableTokens(chainOrClient?: import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/push-chain/push-chain\").PushChain): {\n tokens: Array<{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n decimals: number;\n mechanism: \"approve\" | \"native\" | \"permit2\";\n prc20Address?: `0x${string}`;\n sourceChain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n symbol: string;\n }>;\n };\n getPayableTokens(chainOrClient?: import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/push-chain/push-chain\").PushChain): {\n tokens: Array<{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n decimals: number;\n mechanism: \"approve\" | \"native\" | \"permit2\";\n symbol: string;\n }>;\n };\n getPC20Address(address: string, options: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n rpcUrls?: Partial>;\n strict?: boolean;\n }): Promise;\n getPRC20Address: (token: {\n address: string;\n chain: string;\n } | import(\"sdk/src/lib/constants/tokens\").MoveableToken, options?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n }) => {\n address: `0x${string}`;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n decimals: number;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n symbol: string;\n };\n}" + } + }, + "initialize": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise", + "agwConstants": { + "PRESETS": { + "optional": false, + "readonly": true, + "type": "{\n readonly CATEGORY: Readonly<{\n DEXES: \"DEXES\";\n LENDING: \"LENDING\";\n PREDICTION: \"PREDICTION\";\n }>;\n}" + }, + "WALLET": { + "optional": false, + "readonly": true, + "type": "\"agentic:wallet\"" + } + }, + "constants": { + "AGENTIC": { + "optional": false, + "readonly": false, + "type": "{\n readonly PRESETS: Readonly<{\n CATEGORY: Readonly<{\n DEXES: \"DEXES\";\n LENDING: \"LENDING\";\n PREDICTION: \"PREDICTION\";\n }>;\n }>;\n readonly WALLET: \"agentic:wallet\";\n}" + }, + "CHAIN": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "LIBRARY": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").LIBRARY" + }, + "MOVEABLE": { + "optional": false, + "readonly": false, + "type": "{\n TOKEN: import(\"sdk/src/lib/constants/tokens\").MoveableTokenConstantsMap;\n}" + }, + "PAYABLE": { + "optional": false, + "readonly": false, + "type": "{\n TOKEN: import(\"sdk/src/lib/constants/tokens\").PayableTokenConstantsMap;\n}" + }, + "PUSH_NETWORK": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "READ": { + "optional": false, + "readonly": false, + "type": "{\n readonly CALLBACK_BUDGET_BUFFER: 3;\n readonly CHAIN: {\n readonly WEB2: \"web2\";\n } & Readonly<{\n readonly ARBITRUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA;\n readonly BASE_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA;\n readonly BNB_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET;\n readonly ETHEREUM_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET;\n readonly ETHEREUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA;\n readonly PUSH_LOCALNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET;\n readonly PUSH_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET;\n readonly PUSH_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly PUSH_TESTNET_DONUT: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly SOLANA_DEVNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET;\n readonly SOLANA_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET;\n readonly SOLANA_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n readonly WEB2: \"web2\";\n }>;\n readonly DEFAULT_EXPIRY_BLOCKS: 300n;\n readonly ERROR_CODE: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n readonly MAX_CALLBACK_GAS_LIMIT: 1000000n;\n readonly MIN_CONFIRMATIONS_FLOOR: 1;\n readonly NAMESPACE: {\n readonly EVM: \"eip155\";\n readonly SVM: \"solana\";\n readonly WEB2: \"web2\";\n };\n readonly OUTCOME: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME;\n readonly REGISTRY_CALLBACK_GAS: 500000n;\n readonly RESULT_STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n readonly STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS;\n readonly UNIVERSAL_CALLBACK_ADDRESSES: Record;\n readonly UNIVERSAL_CORE_ADDRESSES: Record;\n readonly UNIVERSAL_READ_REGISTRY_ADDRESS: {\n readonly TESTNET_DONUT: \"0x00000000000000000000000000000000000000b2\";\n };\n readonly WEB2: \"web2\";\n readonly WEB2_DEFAULT_TIMEOUT_MS: 5000;\n readonly WEB2_MAX_EXTRACT_ENTRIES: 16;\n}" + } + } + }, + "scope": "All root exports and declared public members, PushChain static/instance members, universal transaction methods, utility groups, readonly/optional markers and constants. Behavior/default/deployment changes need the written session review." +} diff --git a/plan/agw/research/section7-presets-2026-10-12/commands.md b/plan/agw/research/section7-presets-2026-10-12/commands.md new file mode 100644 index 00000000..a5b1d458 --- /dev/null +++ b/plan/agw/research/section7-presets-2026-10-12/commands.md @@ -0,0 +1,12 @@ +# Preset validation commands + +No app addresses were added to the production catalog. No new funded app-preset E2E was run. + +- Unit: `node node_modules/jest/bin/jest.js --config packages/core/jest.config.ts --runInBand --runTestsByPath packages/core/src/lib/agentic/__tests__/presets.spec.ts packages/core/src/lib/agentic/__tests__/response-surface.spec.ts` +- Local contracts: `AGW_LOCAL_DIR=/tmp/agw-oct12-v5 node node_modules/jest/bin/jest.js --config packages/core/jest.agw-local.config.ts --runInBand --runTestsByPath packages/core/__agw-local__/v5-multiasset.spec.ts` +- Library, spec and local typechecks use their existing packages/core tsconfig files with `--noEmit`. +- Build: `NX_DAEMON=false node node_modules/nx/bin/nx.js run core:build --skip-nx-cache` +- Consumer checks: `node packages/core/scripts/check-agw-docs.js`, `check-agw-package.js`, `check-agw-api.js --output /tmp/agw-presets-api.json`. +- Full unit regression uses the normal core Jest config. An initial run had 2,074 passes and one existing 100ms outbound-SVM timeout test failure while other checks ran. The unchanged test passed on retry. A subsequent isolated full run is recorded separately. + +The prior section-6 funded acceptance covered 68 scenarios across a 65/3 full run and a 3/3 targeted rerun. That evidence is distinct from this pure preset framework and fixture-only contract integration. diff --git a/plan/agw/research/section7-presets-2026-10-12/docs.log b/plan/agw/research/section7-presets-2026-10-12/docs.log new file mode 100644 index 00000000..7f37e7a9 --- /dev/null +++ b/plan/agw/research/section7-presets-2026-10-12/docs.log @@ -0,0 +1 @@ +AGW guide: 5 TypeScript blocks typechecked against public exports; no examples executed. diff --git a/plan/agw/research/section7-presets-2026-10-12/full-unit.log b/plan/agw/research/section7-presets-2026-10-12/full-unit.log new file mode 100644 index 00000000..ef6dd277 --- /dev/null +++ b/plan/agw/research/section7-presets-2026-10-12/full-unit.log @@ -0,0 +1,176 @@ +PASS core packages/core/src/lib/universal/account/account.spec.ts + ● Console + + console.warn + [PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead. + + 207 | ): Promise { + 208 | if (!_convertOriginToExecutorWarned) { + > 209 | console.warn( + | ^ + 210 | '[PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead.' + 211 | ); + 212 | _convertOriginToExecutorWarned = true; + + at Object.convertOriginToExecutor (src/lib/universal/account/account.ts:209:13) + at Object. (src/lib/universal/account/account.spec.ts:80:52) + + console.warn + [PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead. + + 425 | ): Promise { + 426 | if (!options?._internal && !_convertExecutorToOriginWarned) { + > 427 | console.warn( + | ^ + 428 | '[PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead.' + 429 | ); + 430 | _convertExecutorToOriginWarned = true; + + at convertExecutorToOrigin (src/lib/universal/account/account.ts:427:13) + at Object. (src/lib/universal/account/account.spec.ts:106:38) + +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-svm-confirmation.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/block-results-client.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-tx-retry.spec.ts +PASS core packages/core/src/lib/push-client/push-client.archive-fallback.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-confirmation-gate.spec.ts +PASS core packages/core/src/lib/utils.spec.ts + ● Console + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:973:17) + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:977:17) + + console.log + 1.23 + + at Object. (src/lib/utils.spec.ts:982:17) + +PASS core packages/core/src/lib/orchestrator/__tests__/r3-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-event-hook-bridge.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/web2-compat.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r3-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-timeout-clamp.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/send.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/management.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-emission.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r2-outbound-revert-flow.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/execute-standard-required-funds.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-executor.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/funds-only-burn-guard.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/native-multi-action.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-svm-r3.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/source-hash-resolution.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/build-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-calculator.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/multichain-hooks.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/response-builder-push-revert.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-svm-rent.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/svm-rent.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r2-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-gas.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/labels.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/public-rule.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gateway-uea-account.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/public-surface.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-evm-r3-native-eoa.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/response-invariant.spec.ts +PASS core packages/core/src/lib/universal/signer/signer.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r1-spec-strings.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/reads-context.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/send-transaction-progress-hook.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-usd-sizer.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/export.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/read-tx-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-builder-progress-hook.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-types.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/account-status.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/scenarios.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/gate.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-tracker.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/inbound-tracker-derivation.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-detector.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/cascade.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/signing-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/rescue-svm-confirmation.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/chain-namespace.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/terminal-suppression.spec.ts +PASS core packages/core/src/lib/push-client/push-client.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/resolve.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/response-surface.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm-rent-pc20.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/resolver.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/context-helpers-tracker.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-composition.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/track-transaction-guard.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-backend.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/payload-builders.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/registry.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-native-multicall.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-idl.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-multichain.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/inbound-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-request-recipient.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-quote.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/svm-account.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/spec-builder.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-params.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/codec.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/revalidate-read.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-wire-fixture.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-evm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-svm.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm-log-index.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/result-decoder.spec.ts +PASS core packages/core/src/lib/constants/__tests__/token-constants.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/address-codec.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/child-inbounds.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/auto-detect.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/abi-selectors.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/__tests__/signing.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/presets.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/normalize.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.chain-symbol.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg-svm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/ucallback-codec.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/validate.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-events.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-web2.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.dynamic-gas.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.batch-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/ix-encoder.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/registry.spec.ts +PASS core packages/core/src/lib/constants/__tests__/svm-gateway-idl.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/classify.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/error-decoder.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/normalize-address.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/errors.spec.ts +PASS core packages/core/src/lib/formatters.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/tracking.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/max-pc-for-gas.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/budget.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-execute-order.spec.ts + +Test Suites: 1 skipped, 123 passed, 123 of 124 total +Tests: 12 skipped, 2075 passed, 2087 total +Snapshots: 0 total +Time: 23.719 s, estimated 33 s +Ran all test suites. diff --git a/plan/agw/research/section7-presets-2026-10-12/local-contract.log b/plan/agw/research/section7-presets-2026-10-12/local-contract.log new file mode 100644 index 00000000..ee5d39d0 --- /dev/null +++ b/plan/agw/research/section7-presets-2026-10-12/local-contract.log @@ -0,0 +1,19 @@ +PASS core-agw-local packages/core/__agw-local__/v5-multiasset.spec.ts (9.845 s) + v5 multi-asset SDK management and execution + ✓ a fixture preset produces rules accepted by public create and enforced by real contracts (528 ms) + ✓ public create encodes two ordered assets; public get reconstructs source-token caps (359 ms) + ✓ a token from the wrong chain fails before deployment (7 ms) + ✓ a same-chain registry identity mismatch fails before deployment (3 ms) + ✓ both tokens execute under one rule and keep independent counters/limits (374 ms) + ✓ omitted and explicit zero totals both prohibit movement (363 ms) + ✓ empty user assets grants one zero-cap gas token and executes a call-only request (357 ms) + ✓ public update resets both counters in one batch and records five checkpoints (375 ms) + ✓ spend on the second asset after snapshot rolls back revoke/grant and checkpoint writes (363 ms) + ✓ out-of-band duplicate contract grants still make sends ambiguous (330 ms) + ✓ a legacy two-field envelope is refused by the actual v5 grant path (314 ms) + +Test Suites: 1 passed, 1 total +Tests: 11 passed, 11 total +Snapshots: 0 total +Time: 9.875 s +Ran all test suites within paths "packages/core/__agw-local__/v5-multiasset.spec.ts". diff --git a/plan/agw/research/section7-presets-2026-10-12/package.log b/plan/agw/research/section7-presets-2026-10-12/package.log new file mode 100644 index 00000000..8e1b97e4 --- /dev/null +++ b/plan/agw/research/section7-presets-2026-10-12/package.log @@ -0,0 +1 @@ +AGW package: CJS/ESM imports, compiled declaration examples and npm contents pass. No examples executed/published. diff --git a/plan/agw/research/section7-presets-2026-10-12/preset-unit.log b/plan/agw/research/section7-presets-2026-10-12/preset-unit.log new file mode 100644 index 00000000..b1d3e1cb --- /dev/null +++ b/plan/agw/research/section7-presets-2026-10-12/preset-unit.log @@ -0,0 +1,8 @@ +PASS core packages/core/src/lib/agentic/__tests__/presets.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/response-surface.spec.ts + +Test Suites: 2 passed, 2 total +Tests: 30 passed, 30 total +Snapshots: 0 total +Time: 2.314 s, estimated 5 s +Ran all test suites within paths "packages/core/src/lib/agentic/__tests__/presets.spec.ts", "packages/core/src/lib/agentic/__tests__/response-surface.spec.ts". diff --git a/plan/agw/research/section7-presets-2026-10-12/timing-test-rerun.log b/plan/agw/research/section7-presets-2026-10-12/timing-test-rerun.log new file mode 100644 index 00000000..0e5113b4 --- /dev/null +++ b/plan/agw/research/section7-presets-2026-10-12/timing-test-rerun.log @@ -0,0 +1,17 @@ +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-svm-confirmation.spec.ts + ✓ confirms pending Cosmos signature EyFYDWDhksPYpRk3DLzeW4izQagJZte6bKCQFagLYBdtJyaEyjbQpAWCbqDhHVymzjPJ4vdeHG1HHQp1qi6FhZD through Solana RPC (3 ms) + ✓ confirms pending Cosmos signature 0x0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c through Solana RPC (4 ms) + ✓ waits through processed status before finalization (2 ms) + ✓ reports a confirmed signature error as failure, preserving the hash (1 ms) + ✓ keeps wrong-cluster pending until timeout (21 ms) + ✓ keeps missing pending until timeout (21 ms) + ✓ keeps processed-error pending until timeout (20 ms) + ✓ keeps rpc-error pending until timeout (20 ms) + ✓ keeps malformed-hash pending until timeout (20 ms) + ✓ keeps an authoritative Cosmos revert ahead of the RPC tiebreaker (1 ms) + +Test Suites: 1 passed, 1 total +Tests: 10 passed, 10 total +Snapshots: 0 total +Time: 2.544 s +Ran all test suites within paths "packages/core/src/lib/orchestrator/__tests__/outbound-svm-confirmation.spec.ts". diff --git a/plan/agw/section6-action-items.md b/plan/agw/section6-action-items.md new file mode 100644 index 00000000..ef1cedb2 --- /dev/null +++ b/plan/agw/section6-action-items.md @@ -0,0 +1,53 @@ +# October 12 feedback — work items and deployment boundary + +Source: native Markdown exports of [SDK page 5](https://app.notion.com/p/pushprotocol/5-SDK-AGW-3e9188aea7f481cf8e8de324956549b9) and [contract page 1](https://app.notion.com/p/pushprotocol/1-AGW-Contract-Changes-nomenclature-standard-change-set-3e9188aea7f4813aa31fc95ceb4e684d), downloaded October 12 at 20:23 IST. Both section 6 introductions say the new text overrides sections above. [Downloads, hashes and diffs](research/section6-feedback-2026-10-12/). The user confirms the new contract changes are not deployed. Planning stays on `feat/agw-sdk-v4`; non-plan changes are also synced to `feat/agw-sdk-v5`. + +## SDK-owned changes available on deployed v5 + +S01–S12 are implemented locally (within the explicit v5 limitations below). S13 has 68/68 passing live coverage across the full run (65 passed, 3 failed) and the three-case rerun (3 passed). This is not one clean full invocation. Section 7 now has a preset-only framework; the catalog remains empty by user decision. Encoding/ID utilities remain private. + + +| Item | Feedback | Required change | +| --- | --- | --- | +| S01 | SDK 6.a, 6.h | Unified `Rule.allowedCalls[]` for native/EVM/SVM; retire public native `actions[]` and single-function shorthand. Preserve internal per-action wire terms. | +| S02 | SDK 6.a | Pins inside calls: `{arg, expected}` / `{arg, max}`; native max compiles to the existing metered argument (at most one). Remove public native lifetime totals/call limits and per-action expiry. | +| S03 | SDK 6.a | `AGENTIC.WALLET = 'agentic:wallet'`; resolve AGW/CEA/ATA context, map existing EVM beneficiary to one WALLET pin, reject unsupported destination pins before signing. | +| S04 | SDK 6.b / contract 6.5 | Omitted asset maxTotal and call maxValue become zero. Explicit zero already works in contracts. | +| S05 | SDK 6.c–d | Restore `spent` in records; per-asset universal spend in asset order. Read pins as arg, support get→change expiry→update. See read-shape questions below. | +| S06 | SDK 6.f / contract 6.6 | Direct wallet setLabel on both EOA/UEA paths; no owner checkpoint; AGENTIC-TX-106 progress event. | +| S07 | SDK 6.g / contract 6.6 | First-use EVM CEA gas default when caller omits gasLimit, preserving explicit caller value and policy checks. | +| S08 | SDK 6.h, 7 | Remove public addresses/limits/encoding/ID helpers. Retain WALLET and the later preset namespace only when preset data/behavior is settled. | +| S09 | SDK 6.i | Solana signature/discriminator and numeric arg/account pins replace IDL-bearing rules. Send-data IDL helper remains. Fixed-width layout only. | +| S10 | SDK 6.l | Restore DUPLICATE_RULE at create/add; retain AMBIGUOUS_RULE for pre-existing overlaps. Reject before signing. | +| S11 | SDK 6.l | Unsupported network/deployment maps to CAPABILITY_UNAVAILABLE rather than public GENERATION_UNSUPPORTED. Preview-only RULE_LIMIT_EXCEEDED becomes internal. | +| S12 | SDK 6.m | rules.delete replaces rules.revoke; DELETE_NEEDS_TARGET replaces REVOKE_NEEDS_TARGET. Contract functions/events/checkpoint names do not change. | +| S13 | Review acceptance | Update unit/local/live scenarios and consumer examples for new behavior, then run the full compatible AGW group. A complete final suite also needs the new deployment. | + +## Keep deferred until contract delivery + +| Item | Contract dependency | Current safe behavior | +| --- | --- | --- | +| C01 | Page 1 §6.1: exact approval inside each outbound, both doors | Do not delete allowance safety checks or claim automatic approval on v5. Switch only with verified source/ABI/deployment. | +| C02 | Page 1 §6.2: createWallet(label, Session[]) and factory-only initial grant path | Do not invent the ABI or remove partial recovery until every supported owner has atomic creation. Decide the signed variant and preserve index-race protection. | +| C03 | Page 1 §6.3: general destination EQ/MAX pins | Use existing WALLET beneficiary support; reject other destination pins until deployed. Native v5 supports 8 EQ pins and one metered MAX per action. | +| C05 | SDK §6.k: contract-owner confirmation of wallet-token-account pins in all supported cases | SDK derives and validates CEA/ATA context. Local SPL and selected live cases provide evidence for those cases, not a claim of universal policy coverage. | +| C04 | SDK §6.l: remove CREATE_PARTIAL, allowance error and split-write recovery fields | Follows C01/C02; removing them early would hide real existing failure states. Core non-AGW transaction fields must not be removed globally. | + +Ref removal is already implemented and deployed. Explicit zero cap semantics are already implemented by the contract; no deployment is needed to change SDK defaults. + +## Specification gaps to highlight + +1. **Native action ceiling:** SDK 6.h says 1..32 allowedCalls for all chains; deployed AGW caps native session actions at 8. Keep the actual cap and identify this unsupported request explicitly. +2. **Native spent with several actions:** the new public Spent shape has one native amountSpent/callsUsed despite per-action contract counters. Summing unrelated token amounts has no useful token meaning; the user approved per-action spend entries on October 12. Keep scalar counters for a single action; return identified action entries for multiple actions. +3. **Argument reconstruction:** contracts keep offsets and four-byte selectors, not ABI signatures/types. Flat 32-byte EVM arguments map to arg; offsets after static tuples/arrays cannot reliably recover original top-level indexes. Reject unsupported round-trips rather than silently re-encode different calldata constraints. Preset §7.e explicitly leaves struct fields open. +4. **Solana read/modify/update:** raw eight-byte selectors and stored byte offsets have no Borsh argument types. Exact numeric arg reconstruction needs layout metadata or a defined raw representation. Account positions can round-trip directly. The user approved a decoded raw representation on October 12. Authored rules use numeric arg/account positions; decoded raw rules preserve offsets and all constraints and are accepted by update. +5. **Presets (§7):** first app/address lists and struct-field pin semantics remain open. The preset framework is implemented; missing caps default to zero per the user. No invented DEX/lending addresses or permissive approval presets. The agent is already one Push address (EOA/UEA) across destinations. +6. **Old statements:** contract §6.2 describes native multicall rejection, but SDK EIP-7702 atomic native creation is already tested. The new factory entry is still a requested target; do not remove index-race protection simply to match its illustrative signature. + +## Discussion check + +The SDK All discussions panel contains the older October 1–7 comments (including the resolved multiple-rules-per-chain comment and ref omission). The contract All discussions panel contains September 29/October 1 comments, including direct cosmetic label guidance. No later inline thread was visible. The fresh section 6 body and the user's supplied Harsh message supersede the older comments. Native Notion exports exclude discussion threads. + +## Live acceptance follow-up + +Donut reported `height 23989983 is not available, lowest height is 24073229` for a default checkpoint-history scan. The SDK now retries from an explicitly reported retention floor only for an unbounded/default scan, and still requires the full sequence 1..checkpointCount at one snapshot. Missing old events remain an error; no partial history is returned as complete. Explicit sinceBlock requests and unrelated RPC errors are not silently truncated. diff --git a/plan/agw/section7-presets.md b/plan/agw/section7-presets.md new file mode 100644 index 00000000..9e0be18a --- /dev/null +++ b/plan/agw/section7-presets.md @@ -0,0 +1,30 @@ +# Section 7 preset framework + +Source: [SDK spec §7](https://app.notion.com/p/pushprotocol/5-SDK-AGW-3e9188aea7f481cf8e8de324956549b9), [October 12 snapshot](notion/5-sdk-agw.md). Implementation is tracked on feat/agw-sdk-v4, with non-plan changes mirrored to feat/agw-sdk-v5. + +## User decisions + +- Build the framework now; approved app/address catalog comes later. +- Missing asset maxPerCall or maxTotal defaults to zero, superseding the spec's proposed throw. +- An incomplete result is an editable PresetRuleTemplate; supplying agent and expiry narrows the return to Rule[]. This avoids pretending a template is ready for create. + +## Implemented + +- Enumerable, frozen CATEGORY constants: DEXES, LENDING, PREDICTION. +- Public utils.agentic.presets.list/get, with no encoder, ID or deployment helpers restored. +- All production categories currently expose chains: []; get without a chain filter returns rules: []. A requested unavailable chain fails explicitly. No placeholder addresses ship. +- Internal bundled catalog schema and fixture-injectable builder; no public runtime registration or network fetching. +- One rule per chain, chain filtering, identity/expiry propagation and asset placement; unknown/mismatched chains and duplicate assets fail. +- Caller/caller-result mutation cannot modify the catalog or subsequent results. +- Missing caps become 0; explicit uint256 values are retained and invalid values fail. +- Approvals for catalog-declared EVM spenders are pinned to that spender and bounded by maxPerCall. Native assets receive none. Conflicting spender entries or duplicate function entries fail rather than broadening permissions. +- Full signatures and the 32-call ceiling (including approvals) are checked. Metadata app/label is display-only. +- Standard create/add capability checks still reject general destination pins on the old policy; presets cannot bypass contract-delivery gates. + +## Remaining activation work + +Approved catalog data, tuple-field convention and review of approval combinations against the new policy. Solana approvals require a separately reviewed instruction template; no EVM approval is fabricated for them. App ABIs stay in the UI. No funded app-preset E2E is meaningful until approved entries exist. + +## Validation + +Preset/public-surface tests: 30 passed (20 new preset cases). Pinned-contract multi-asset suite: 11 passed, including a new fixture preset passed through public create and actual policy execution/accounting (stub gateway, no live app). Guide: 5 TypeScript blocks typechecked. Final full unit regression: 2,075 passed, 12 skipped, no failures. Build, typechecks, compiled package/declaration examples and API comparison pass. [Commands and logs](research/section7-presets-2026-10-12/commands.md). An earlier 100ms timing failure passed on retry and in the final full run. diff --git a/plan/agw/source-manifest.json b/plan/agw/source-manifest.json index a84e12c0..0b3c6a10 100644 --- a/plan/agw/source-manifest.json +++ b/plan/agw/source-manifest.json @@ -22,15 +22,15 @@ "page_id": "3e9188aea7f4813aa31fc95ceb4e684d", "notion_url": "https://app.notion.com/p/pushprotocol/1-AGW-Contract-Changes-nomenclature-standard-change-set-3e9188aea7f4813aa31fc95ceb4e684d", "local_file": "notion/1-agw-contract-changes.md", - "pulled_on": "2026-10-07", - "observed_last_edited_date": "2026-10-02", + "pulled_on": "2026-10-12", + "observed_last_edited_date": "2026-10-12", "authority": "WIP contract target", - "sha256": "f1301d8ff1cf370968b90a3d53037ece8fa4c6783c45a402f9be6998928e3631", - "export_entry": "Private & Shared/AGW + UniversalMarketplace + 8183 + UniversalEvalu/1 AGW Contract Changes (nomenclature standard + ch 3e9188aea7f4813aa31fc95ceb4e684d.md", - "raw_export_sha256": "f1301d8ff1cf370968b90a3d53037ece8fa4c6783c45a402f9be6998928e3631", - "archive": "notion/exports/20261007T102718466408Z/export-1.zip", - "pulled_at": "2026-10-07T10:27:18.466408+00:00", - "observed_last_edited_at": "2026-10-02T20:50:00+05:30" + "sha256": "7d1690747f52a32a2e3c9eac64422db8dbc673729f370156da2c83c06634bac4", + "export_entry": "Private & Shared/1 AGW Contract Changes (nomenclature standard + ch 3e9188aea7f4813aa31fc95ceb4e684d.md", + "raw_export_sha256": "7d1690747f52a32a2e3c9eac64422db8dbc673729f370156da2c83c06634bac4", + "archive": "research/section6-feedback-2026-10-12/contracts-export.zip", + "pulled_at": "2026-10-12T14:53:27.077622+00:00", + "observed_last_edited_at": "2026-10-12T17:01:00+05:30" }, { "title": "2 Universal Marketplace", @@ -79,16 +79,17 @@ "page_id": "3e9188aea7f481cf8e8de324956549b9", "notion_url": "https://app.notion.com/p/pushprotocol/5-SDK-AGW-3e9188aea7f481cf8e8de324956549b9", "local_file": "notion/5-sdk-agw.md", - "pulled_on": "2026-10-07", - "observed_last_edited_date": "2026-10-07", + "pulled_on": "2026-10-12", + "observed_last_edited_date": "2026-10-12", "authority": "Primary SDK API target", - "sha256": "d3bc55b08a37d762c49173149fd8d554a8551682c0956de3e91394a54bfed9a6", - "export_entry": "Private & Shared/AGW + UniversalMarketplace + 8183 + UniversalEvalu/5 SDK AGW 3e9188aea7f481cf8e8de324956549b9.md", - "raw_export_sha256": "8d024eb2bd2955fc772d2194f50a02d601a2d5bf903b0c9cc74882ee11348130", - "archive": "notion/exports/20261007T102718466408Z/export-1.zip", - "pulled_at": "2026-10-07T10:27:18.466408+00:00", + "sha256": "7f8e6e892686fc298bd0a40d66d7e21cb457711e18a272e563322403bc0380ec", + "export_entry": "Private & Shared/5 SDK AGW 3e9188aea7f481cf8e8de324956549b9.md", + "raw_export_sha256": "7f8e6e892686fc298bd0a40d66d7e21cb457711e18a272e563322403bc0380ec", + "archive": "research/section6-feedback-2026-10-12/sdk-export.zip", + "pulled_at": "2026-10-12T14:53:27.075673+00:00", "previous_observed_last_edited_date": "2026-10-01", - "observed_last_edited_ui": "Edited 2h ago (observed October 7)" + "observed_last_edited_ui": "Edited 2h ago (observed October 7)", + "observed_last_edited_at": "2026-10-12T19:42:00+05:30" }, { "title": "6 SDK Universal Marketplace", @@ -175,5 +176,6 @@ "export_entry": "Private & Shared/agentic_wallet_flow ( updated ) 3d1188aea7f4801f9cb3fbd9318ec536.md" } ], - "last_refresh_at": "2026-10-07T10:27:18.466408+00:00" + "last_refresh_at": "2026-10-07T10:27:18.466408+00:00", + "latest_partial_refresh": "2026-10-12: pages 1 and 5 only; other pages retain their individual pull dates." } From 7dca3f2aaafb575e2338bf2dacec5fe5534dbcd7 Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Thu, 15 Oct 2026 06:49:33 +0530 Subject: [PATCH 35/68] feat(core): migrate AGW SDK to deployed v6 contracts --- packages/core/AGW.md | 22 +- .../__agw-local__/agw-local-advanced.spec.ts | 68 +- .../__agw-local__/agw-local-races.spec.ts | 21 +- packages/core/__agw-local__/agw-local.spec.ts | 4 +- packages/core/__agw-local__/harness.ts | 13 +- packages/core/__agw-local__/labels.spec.ts | 14 +- .../__agw-local__/native-multi-action.spec.ts | 6 +- .../core/__agw-local__/svm-backend.spec.ts | 59 +- .../__agw-local__/svm-differential.spec.ts | 18 +- .../core/__agw-local__/svm-internals.spec.ts | 32 +- .../core/__agw-local__/svm-public.spec.ts | 16 +- .../core/__agw-local__/v5-multiasset.spec.ts | 82 +- packages/core/__agw-local__/vectors.spec.ts | 11 +- .../__e2e__/agw-svm-wire/outbound.spec.ts | 466 +++++++++-- .../core/__e2e__/agw-svm-wire/replay.spec.ts | 83 +- packages/core/__e2e__/agw/_manifest.ts | 65 +- packages/core/__e2e__/agw/create.spec.ts | 14 +- packages/core/__e2e__/agw/labels.spec.ts | 26 +- packages/core/__e2e__/agw/lifecycle.spec.ts | 4 +- .../__e2e__/agw/management-extended.spec.ts | 10 +- .../__e2e__/agw/native-multi-action.spec.ts | 26 +- .../agw/native-policy-extended.spec.ts | 12 +- packages/core/__e2e__/agw/svm-public.spec.ts | 64 +- .../core/__e2e__/agw/svm-spl-transfer.spec.ts | 22 +- .../core/__e2e__/agw/universal-evm.spec.ts | 116 ++- .../core/__e2e__/agw/v5-multiasset.spec.ts | 16 +- packages/core/__e2e__/ci/suite.ts | 8 + packages/core/__e2e__/shared/agw-state.ts | 10 +- .../__e2e__/shared/agw-svm-policy-probe.ts | 77 +- .../core/scripts/agw-local/abis/factory.json | 391 +++++++++ .../core/scripts/agw-local/abis/manifest.json | 13 +- .../core/scripts/agw-local/abis/policy.json | 761 ++++++++--------- .../core/scripts/agw-local/abis/wallet.json | 127 ++- packages/core/scripts/agw-local/gen-abi.mjs | 11 +- packages/core/scripts/agw-local/prepare.sh | 4 +- .../{v5-vectors.json => v6-vectors.json} | 29 +- .../src/lib/agentic/__tests__/codec.spec.ts | 67 +- .../src/lib/agentic/__tests__/fake-chain.ts | 15 +- .../src/lib/agentic/__tests__/labels.spec.ts | 8 +- .../lib/agentic/__tests__/management.spec.ts | 163 +--- .../__tests__/native-batch-response.spec.ts | 8 +- .../__tests__/native-multi-action.spec.ts | 6 +- .../__tests__/outbound-response.spec.ts | 6 +- .../src/lib/agentic/__tests__/presets.spec.ts | 67 +- .../lib/agentic/__tests__/public-rule.spec.ts | 73 +- .../agentic/__tests__/reads-context.spec.ts | 12 +- .../__tests__/response-surface.spec.ts | 10 +- .../agentic/__tests__/rules-policy.spec.ts | 19 +- .../src/lib/agentic/__tests__/send.spec.ts | 46 +- .../agentic/__tests__/svm-internals.spec.ts | 2 +- .../core/src/lib/agentic/agentic.types.ts | 5 +- packages/core/src/lib/agentic/capabilities.ts | 2 +- .../core/src/lib/agentic/codec/defaults.ts | 6 +- packages/core/src/lib/agentic/codec/ids.ts | 2 +- packages/core/src/lib/agentic/codec/native.ts | 48 +- packages/core/src/lib/agentic/codec/pins.ts | 32 + packages/core/src/lib/agentic/codec/rules.ts | 4 +- .../core/src/lib/agentic/codec/session.ts | 6 +- .../core/src/lib/agentic/codec/svm-terms.ts | 10 +- .../src/lib/agentic/codec/universal-terms.ts | 8 +- .../core/src/lib/agentic/codec/universal.ts | 28 +- .../abi/{v5 => v6}/agent-validator.ts | 2 +- .../contracts/abi/{v5 => v6}/agw-factory.ts | 395 ++++++++- .../agentic/contracts/abi/{v5 => v6}/agw.ts | 131 ++- .../agentic/contracts/abi/{v5 => v6}/index.ts | 4 +- .../contracts/abi/{v5 => v6}/smart-session.ts | 2 +- .../abi/{v5 => v6}/universal-rules-policy.ts | 765 +++++++++--------- .../src/lib/agentic/contracts/donut-v5.ts | 13 - .../src/lib/agentic/contracts/donut-v6.ts | 13 + .../lib/agentic/contracts/{v5.ts => v6.ts} | 59 +- packages/core/src/lib/agentic/deployments.ts | 44 +- packages/core/src/lib/agentic/errors.ts | 12 +- .../src/lib/agentic/execution/outbound.ts | 10 +- .../core/src/lib/agentic/execution/send.ts | 23 +- .../src/lib/agentic/execution/svm-outbound.ts | 2 +- .../src/lib/agentic/execution/svm-payload.ts | 3 +- .../src/lib/agentic/execution/svm-public.ts | 11 +- .../src/lib/agentic/execution/svm-send.ts | 11 - .../core/src/lib/agentic/management/common.ts | 58 +- .../core/src/lib/agentic/management/create.ts | 238 +----- .../core/src/lib/agentic/management/svm.ts | 2 +- .../core/src/lib/agentic/presets/index.ts | 26 +- packages/core/src/lib/agentic/public-rule.ts | 70 +- packages/core/src/lib/agentic/reads/rules.ts | 47 +- packages/core/src/lib/agentic/reads/svm.ts | 4 +- packages/core/src/lib/agentic/response.ts | 10 +- packages/core/src/lib/agentic/revert.ts | 2 +- packages/core/src/lib/agentic/utils.ts | 4 +- 88 files changed, 3455 insertions(+), 1880 deletions(-) rename packages/core/src/lib/agentic/__fixtures__/{v5-vectors.json => v6-vectors.json} (84%) create mode 100644 packages/core/src/lib/agentic/codec/pins.ts rename packages/core/src/lib/agentic/contracts/abi/{v5 => v6}/agent-validator.ts (97%) rename packages/core/src/lib/agentic/contracts/abi/{v5 => v6}/agw-factory.ts (66%) rename packages/core/src/lib/agentic/contracts/abi/{v5 => v6}/agw.ts (89%) rename packages/core/src/lib/agentic/contracts/abi/{v5 => v6}/index.ts (69%) rename packages/core/src/lib/agentic/contracts/abi/{v5 => v6}/smart-session.ts (99%) rename packages/core/src/lib/agentic/contracts/abi/{v5 => v6}/universal-rules-policy.ts (97%) delete mode 100644 packages/core/src/lib/agentic/contracts/donut-v5.ts create mode 100644 packages/core/src/lib/agentic/contracts/donut-v6.ts rename packages/core/src/lib/agentic/contracts/{v5.ts => v6.ts} (88%) diff --git a/packages/core/AGW.md b/packages/core/AGW.md index b2d91998..3a92f727 100644 --- a/packages/core/AGW.md +++ b/packages/core/AGW.md @@ -1,6 +1,6 @@ # Agentic wallets on Push Chain -This branch implements the SDK-only October 12 feedback against the deployed Donut v5 contracts. Contract-dependent changes remain explicit below. +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. ## Connect @@ -83,7 +83,7 @@ async function manage(owner: PushChain, address: Address, id: Hex) { `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. -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. +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. ## Pins and zero defaults @@ -112,7 +112,7 @@ function evmRule(agent: Address, target: Address): Rule { } ``` -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. +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. 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. @@ -153,15 +153,17 @@ Connect with `PushChain.initialize(signer, { agenticWallet: address })` to send 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. -## Deployment-dependent behavior +## V6 deployment and creation -The October 12 contract feedback is not deployed. Until it is verified: +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. -- 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. -- 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. -- General EVM destination pins and the new atomic factory `createWallet` are unavailable. +`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. -`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`. +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. + +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. + +`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. ## Preset discovery and templates (section 7) @@ -185,7 +187,7 @@ function filledPreset(agent: Address) { 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. -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. +Reviewed EVM catalog spenders generate approvals pinned to that spender and bounded by the asset's per-call cap. Native assets need no approval. Distinct spenders for the same token become separate fully pinned alternatives under v6; unrestricted alternatives are rejected. Presets do not sign, fetch app ABIs or modify wallets. 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. diff --git a/packages/core/__agw-local__/agw-local-advanced.spec.ts b/packages/core/__agw-local__/agw-local-advanced.spec.ts index 9e801d6d..8dd9c360 100644 --- a/packages/core/__agw-local__/agw-local-advanced.spec.ts +++ b/packages/core/__agw-local__/agw-local-advanced.spec.ts @@ -70,7 +70,7 @@ const fund = (h: Harness, to: Address, value: bigint) => account: h.wallets[4].account!, chain: h.wallets[4].chain, }); -describe('AGW advanced paths against real v5 contracts', () => { +describe('AGW advanced paths against real v6 contracts', () => { let h: Harness; let owner: PushChain; let agentAddr: Address; @@ -143,7 +143,7 @@ describe('AGW advanced paths against real v5 contracts', () => { const rec = await owner.agentic.wallet(wallet).rules.list(); expect(rec.rules[0].spent).toMatchObject({ kind: 'native', - amountSpent: BigInt(5), + amountSpent: BigInt(0), callsUsed: 1, }); expect( @@ -153,7 +153,7 @@ describe('AGW advanced paths against real v5 contracts', () => { wallet, rec.rules[0].rulesId ) - ).toMatchObject({ amountSpent: BigInt(5), callsUsed: 1 }); + ).toMatchObject({ amountSpent: BigInt(0), callsUsed: 1 }); }); it('per-call amounts are enforced and repeated valid calls remain usable', async () => { await expect(deposit(beneficiary, BigInt(11))).rejects.toBeInstanceOf( @@ -281,8 +281,9 @@ describe('AGW advanced paths against real v5 contracts', () => { expect(err.decodedError?.name).toBe('PolicyCheckReverted(RulesExpired)'); }); }); - describe('sequential create partial failure and recovery', () => { - it('reports CREATE_PARTIAL with the deployed wallet and granted IDs; rules.add finishes it', async () => { + describe('atomic create rollback', () => { + it('a rejected initial rule rolls back wallet creation and every grant', async () => { + const predicted = await owner.agentic.derive(); // Chain time runs ahead of the local clock: the SDK accepts validUntil, the policy does not. const skewedValidUntil = Math.floor(Date.now() / 1000) + 600; await warp(h, 7200); @@ -312,27 +313,11 @@ describe('AGW advanced paths against real v5 contracts', () => { ], }) .catch((e) => e); - expect(err).toBeInstanceOf(AgenticError); - expect(err.code).toBe(AGENTIC_ERROR_CODE.CREATE_PARTIAL); - expect(err.details.walletDeployed).toBe(true); - expect(err.details.grantedRulesIds).toHaveLength(1); - expect(err.details.confirmedHashes.length).toBeGreaterThanOrEqual(2); - const wallet = err.details.wallet as Address; - const added = await owner.agentic.wallet(wallet).rules.add([ - { - agent: h.wallets[3].account!.address, - validUntil: (await chainNow(h)) + 3600, - allowedCalls: [ - { - target: h.addresses.target, - selector: 'increment()', - }, - ], - }, - ]); - expect(added.rulesIds).toHaveLength(1); - const { rules } = await owner.agentic.wallet(wallet).rules.list(); - expect(rules).toHaveLength(2); + expect(err).toBeInstanceOf(AgenticRevertError); + expect(await owner.agentic.derive()).toEqual(predicted); + expect( + await h.publicClient.getCode({ address: predicted.address }) + ).toBeUndefined(); }); it('rules.add with several rules is one atomic owner batch: OWNER_ACTION + RULES_GRANTED per rule', async () => { const created = await owner.agentic.create('multi-add', { rules: [] }); @@ -378,7 +363,7 @@ describe('AGW advanced paths against real v5 contracts', () => { expect(before).toBe(BigInt(0)); }); }); - describe('agent EVM outbound (v5 multi-asset terms, stub gateway)', () => { + describe('agent EVM outbound (v6 multi-asset terms, stub gateway)', () => { const SEPOLIA = CHAIN.ETHEREUM_SEPOLIA; const CEA = getAddress('0x000000000000000000000000000000000000cea1'); const destTarget = getAddress('0x00000000000000000000000000000000000d0d0d'); @@ -399,7 +384,7 @@ describe('AGW advanced paths against real v5 contracts', () => { await h.publicClient.waitForTransactionReceipt({ hash: await fund(h, wallet, BigInt(10) ** BigInt(17)), }); - // Fixture setup (raw owner call): grant a v5 multi-asset universal rule. + // Fixture setup (raw owner call): grant a v6 multi-asset universal rule. const terms = encodeUniversalTerms({ validUntil: (await chainNow(h)) + 3600, expectedCEA: CEA, @@ -411,6 +396,7 @@ describe('AGW advanced paths against real v5 contracts', () => { { target: destTarget, selector: '0xd09de08a', + pins: [], beneficiaryOffset: 0, hasBeneficiary: false, maxValue: BigInt(0), @@ -479,10 +465,14 @@ describe('AGW advanced paths against real v5 contracts', () => { }, }, }); - it('fails before signing when the owner has not set a gateway allowance', async () => { - await expect(send(BigInt(100))).rejects.toMatchObject({ - code: AGENTIC_ERROR_CODE.GATEWAY_ALLOWANCE_INSUFFICIENT, - }); + it('sends successfully without an owner gateway allowance', async () => { + expect( + ( + await h.publicClient.waitForTransactionReceipt({ + hash: (await send(BigInt(100))).hash as Hex, + }) + ).status + ).toBe('success'); }); it('owner sets a bounded allowance with an ordinary owner-door send; the agent outbound passes URP, pulls and burns', async () => { await ( @@ -526,7 +516,7 @@ describe('AGW advanced paths against real v5 contracts', () => { functionName: 'allowance', args: [wallet, h.addresses.gateway], }) - ).toBe(BigInt(200)); + ).toBe(BigInt(0)); // The request the wallet sent: empty recipient, wallet refund, nonzero gas cap, multicall payload. const payload = `0x2cc2842d${encodeAbiParameters( [ @@ -589,7 +579,7 @@ describe('AGW advanced paths against real v5 contracts', () => { }); expect(keccak256(toBytes(SEPOLIA))).toBeTruthy(); }); - it('owner can remove the allowance; the agent is stopped before signing again', async () => { + it('zero standing allowance does not revoke an otherwise valid rule', async () => { await ( await ownerAgw.universal.sendTransaction({ to: token, @@ -600,9 +590,13 @@ describe('AGW advanced paths against real v5 contracts', () => { }), }) ).wait(); - await expect(send(BigInt(10))).rejects.toMatchObject({ - code: AGENTIC_ERROR_CODE.GATEWAY_ALLOWANCE_INSUFFICIENT, - }); + expect( + ( + await h.publicClient.waitForTransactionReceipt({ + hash: (await send(BigInt(10))).hash as Hex, + }) + ).status + ).toBe('success'); }); it('a call outside the allow-list is rejected by URP on-chain', async () => { await ( diff --git a/packages/core/__agw-local__/agw-local-races.spec.ts b/packages/core/__agw-local__/agw-local-races.spec.ts index efe87bae..251b8ddd 100644 --- a/packages/core/__agw-local__/agw-local-races.spec.ts +++ b/packages/core/__agw-local__/agw-local-races.spec.ts @@ -1,15 +1,15 @@ /** * Race regressions found during independent SDK review, - * against the real pinned v5 contracts on local anvil. + * against the real pinned v6 contracts on local anvil. * R1 — a concurrent creation must never let this create() grant on a wallet it * did not deploy (the deploy is index-bound through deployWalletWithSig). * R4 — an owner outbound must never restore an allowance revoked after the * SDK read it (the SDK never writes allowances). */ -import { encodeFunctionData, parseAbi, type Address } from 'viem'; +import { encodeFunctionData, parseAbi, type Address, type Hex } from 'viem'; import { AgenticRevertError, CHAIN, type PushChain } from '../src'; import type { AgenticRuntime } from '../src/lib/agentic/runtime'; -import { v5 } from '../src/lib/agentic/contracts/v5'; +import { v6 } from '../src/lib/agentic/contracts/v6'; import { AGENTIC_ERROR_CODE } from '../src/lib/agentic/errors'; import { startHarness, type Harness } from './harness'; const TOKEN = parseAbi([ @@ -23,7 +23,7 @@ const internalsOf = (c: PushChain) => agenticRuntime: AgenticRuntime; } ).agenticRuntime; -describe('AGW race regressions (real v5 contracts)', () => { +describe('AGW race regressions (real v6 contracts)', () => { let h: Harness; let owner: PushChain; beforeAll(async () => { @@ -87,7 +87,7 @@ describe('AGW race regressions (real v5 contracts)', () => { const retried = await owner.agentic.create('intended', { rules: [] }); expect(retried.index).toBe(next.index); }); - it('R4 an allowance revoked after the SDK read it stays revoked; the outbound fails on-chain', async () => { + it('v6 outbound succeeds after a standing allowance is revoked and leaves zero allowance', async () => { const { wallet } = await owner.agentic.create('allowance-race', { rules: [], }); @@ -129,7 +129,7 @@ describe('AGW race regressions (real v5 contracts)', () => { const execute = rt.execute; rt.execute = async (params, options) => { rt.execute = execute; - const revoke = v5.encodeExecute([ + const revoke = v6.encodeExecute([ { target: token, value: BigInt(0), @@ -156,8 +156,13 @@ describe('AGW race regressions (real v5 contracts)', () => { .finally(() => { rt.execute = execute; }); - expect(err).toBeInstanceOf(AgenticRevertError); - expect(err.message).toContain('0x10bad147'); // LowAllowance() — the token refused the pull + expect( + ( + await h.publicClient.waitForTransactionReceipt({ + hash: err.hash as Hex, + }) + ).status + ).toBe('success'); expect( await h.publicClient.readContract({ address: token, diff --git a/packages/core/__agw-local__/agw-local.spec.ts b/packages/core/__agw-local__/agw-local.spec.ts index d3ae46d2..efab53b9 100644 --- a/packages/core/__agw-local__/agw-local.spec.ts +++ b/packages/core/__agw-local__/agw-local.spec.ts @@ -1,6 +1,6 @@ import { readNativeCounters } from '../__e2e__/shared/agw-state'; /** - * Real-contract checks of the AGW SDK against the pinned v5 contracts on a + * Real-contract checks of the AGW SDK against the pinned v6 contracts on a * local anvil chain (see harness.ts for scope and limits). Every assertion * about authorization, atomicity, counters and checkpoints is decided by the * real contracts; the only stubbed component is the gateway. @@ -32,7 +32,7 @@ const WALLET_ABI = parseAbi([ 'function owner() view returns (address)', ]); const inAnHour = () => Math.floor(Date.now() / 1000) + 3600; -describe('AGW SDK against real v5 contracts (local anvil)', () => { +describe('AGW SDK against real v6 contracts (local anvil)', () => { let h: Harness; let owner: PushChain; let ownerAddr: Address; diff --git a/packages/core/__agw-local__/harness.ts b/packages/core/__agw-local__/harness.ts index 22ad9328..ce2ac894 100644 --- a/packages/core/__agw-local__/harness.ts +++ b/packages/core/__agw-local__/harness.ts @@ -220,6 +220,7 @@ async function deployHarness( ); const clients = new Set(); + let svmLibrary: Address | undefined; const deploy = async ( walletIndex: number, name: string, @@ -227,6 +228,14 @@ async function deployHarness( args: readonly unknown[] = [] ) => { const art = artifact(dir, file, name); + if (name === 'UniversalRulesPolicy') { + if (!svmLibrary) + svmLibrary = await deploy(0, 'SvmRulebook', 'SvmRulebook.sol'); + art.bytecode = art.bytecode.replace( + /__\$[0-9a-fA-F]{34}\$__/g, + svmLibrary.slice(2) + ) as Hex; + } const hash = await wallets[walletIndex].deployContract({ abi: art.abi, bytecode: art.bytecode, @@ -353,8 +362,8 @@ async function deployHarness( resetAgenticGenerations(); const generation = registerAgenticGeneration({ - id: 'v5', - sourceCommit: '2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb', + id: 'v6', + sourceCommit: 'ffd567d3e49b2d27c6f50ad36093274dbac3090f', network: PUSH_NETWORK.LOCALNET, advertised: false, addresses: { diff --git a/packages/core/__agw-local__/labels.spec.ts b/packages/core/__agw-local__/labels.spec.ts index 1f377f13..d03f51b5 100644 --- a/packages/core/__agw-local__/labels.spec.ts +++ b/packages/core/__agw-local__/labels.spec.ts @@ -1,11 +1,11 @@ /** Real v5 wallet/factory label state; no bridge or destination simulation. */ import { decodeEventLog, type Address } from 'viem'; import { PushChain } from '../src'; -import { v5 } from '../src/lib/agentic/contracts/v5'; +import { v6 } from '../src/lib/agentic/contracts/v6'; import { AGENTIC_ERROR_CODE } from '../src/lib/agentic/errors'; import { startHarness, type Harness } from './harness'; -describe('v5 label SDK against real contracts', () => { +describe('v6 label SDK against real contracts', () => { let h: Harness; let owner: PushChain; beforeAll(async () => { @@ -18,7 +18,7 @@ describe('v5 label SDK against real contracts', () => { const count = (address: Address) => h.publicClient.readContract({ address, - abi: v5.abis.wallet, + abi: v6.abis.wallet, functionName: 'checkpointCount', }); @@ -50,7 +50,7 @@ describe('v5 label SDK against real contracts', () => { if (log.address.toLowerCase() !== made.wallet.toLowerCase()) return []; try { const ev = decodeEventLog({ - abi: v5.abis.wallet, + abi: v6.abis.wallet, data: log.data, topics: log.topics, }); @@ -78,7 +78,7 @@ describe('v5 label SDK against real contracts', () => { it('direct contract rename changes no checkpoint; subsequent SDK reads show it', async () => { const made = await owner.agentic.create('before', { rules: [] }); const before = await count(made.wallet); - await h.write(0, made.wallet, v5.abis.wallet, 'setLabel', ['direct']); + await h.write(0, made.wallet, v6.abis.wallet, 'setLabel', ['direct']); expect(await count(made.wallet)).toBe(before); expect((await owner.agentic.wallet(made.wallet).info()).label).toBe( 'direct' @@ -102,7 +102,7 @@ describe('v5 label SDK against real contracts', () => { await expect( h.publicClient.simulateContract({ address: made.wallet, - abi: v5.abis.wallet, + abi: v6.abis.wallet, functionName: 'setLabel', args: [invalid], account: h.wallets[0].account!.address, @@ -127,7 +127,7 @@ describe('v5 label SDK against real contracts', () => { await expect( h.publicClient.simulateContract({ address: made.wallet, - abi: v5.abis.wallet, + abi: v6.abis.wallet, functionName: 'setLabel', args: ['attack'], account: h.wallets[1].account!.address, diff --git a/packages/core/__agw-local__/native-multi-action.spec.ts b/packages/core/__agw-local__/native-multi-action.spec.ts index ecd23af5..f49dddc6 100644 --- a/packages/core/__agw-local__/native-multi-action.spec.ts +++ b/packages/core/__agw-local__/native-multi-action.spec.ts @@ -1,5 +1,5 @@ /** - * Multi-action native rules against the real pinned v5 contracts: one rule ID + * Multi-action native rules against the real pinned v6 contracts: one rule ID * allows several Push functions, each metered by its own stored terms. * Unified section-6 public shape; the contract support * (AGW MAX_NATIVE_ACTIONS = 8) is what these tests exercise. @@ -73,7 +73,7 @@ async function rule(): Promise { ], }; } -describe('multi-action native rules (real v5 contracts)', () => { +describe('multi-action native rules (real v6 contracts)', () => { let wallet: Address; let rulesId: Hex; let agent: PushChain; @@ -186,7 +186,7 @@ describe('multi-action native rules (real v5 contracts)', () => { kind: 'native', actions: [ { callsUsed: 3, amountSpent: BigInt(0) }, - { callsUsed: 2, amountSpent: BigInt(10) }, + { callsUsed: 2, amountSpent: BigInt(0) }, ], }); }); diff --git a/packages/core/__agw-local__/svm-backend.spec.ts b/packages/core/__agw-local__/svm-backend.spec.ts index 57046e94..c51453c5 100644 --- a/packages/core/__agw-local__/svm-backend.spec.ts +++ b/packages/core/__agw-local__/svm-backend.spec.ts @@ -1,4 +1,4 @@ -/** Internal SVM lifecycle/execution on actual v5 contracts; no Solana/TSS simulation. */ +/** Internal SVM lifecycle/execution on actual v6 contracts; no Solana/TSS simulation. */ import { PublicKey } from '@solana/web3.js'; import { encodeFunctionData, @@ -29,7 +29,7 @@ import { registerIdl, clearRegistry, } from '../src/lib/orchestrator/svm-idl/registry'; -import { v5 } from '../src/lib/agentic/contracts/v5'; +import { v6 } from '../src/lib/agentic/contracts/v6'; import { wrapSendError } from '../src/lib/agentic/management/common'; import { startHarness, type Harness } from './harness'; @@ -41,6 +41,7 @@ const GATEWAY = key('22'), const SPL = 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', TOKEN2022 = 'TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb'; const TOKEN = parseAbi([ + 'function allowance(address,address) view returns(uint256)', 'function mint(address,uint256)', 'function approve(address,uint256) returns (bool)', 'function setSourceTokenAddress(string)', @@ -60,7 +61,7 @@ const metadata: SvmMetadataProvider = { }), }; -describe('internal prepared SVM backend on v5', () => { +describe('internal prepared SVM backend on v6', () => { let h: Harness, owner: PushChain, tokens: Address[]; beforeAll(async () => { h = await startHarness(18554); @@ -173,9 +174,9 @@ describe('internal prepared SVM backend on v5', () => { }); for (const token of tokens) { await h.write(0, token, TOKEN, 'mint', [wallet, BigInt(100)]); - await h.write(0, wallet, v5.abis.wallet, 'execute', [ + await h.write(0, wallet, v6.abis.wallet, 'execute', [ key('00'), - v5.packSingle({ + v6.packSingle({ target: token, value: BigInt(0), data: encodeFunctionData({ @@ -241,11 +242,11 @@ describe('internal prepared SVM backend on v5', () => { ).rejects.toMatchObject({ code: 'NOT_OWNER_OR_AGENT' }); expect(execute).not.toHaveBeenCalled(); }); - it('requires separate allowance and never writes an approval on the agent path', async () => { + it('automatically approves and clears the gateway on the agent path', async () => { const s = await setup(); - await h.write(0, s.wallet, v5.abis.wallet, 'execute', [ + await h.write(0, s.wallet, v6.abis.wallet, 'execute', [ key('00'), - v5.packSingle({ + v6.packSingle({ target: tokens[2], value: BigInt(0), data: encodeFunctionData({ @@ -256,10 +257,22 @@ describe('internal prepared SVM backend on v5', () => { }), ]); const execute = jest.spyOn(rt(s.agent), 'execute'); - await expect( - sendSvmAgentWire(rt(s.agent), h.generation, s.request(), metadata) - ).rejects.toMatchObject({ code: 'GATEWAY_ALLOWANCE_INSUFFICIENT' }); - expect(execute).not.toHaveBeenCalled(); + const sent = await sendSvmAgentWire( + rt(s.agent), + h.generation, + s.request(), + metadata + ); + expect((await sent.tx.wait()).status).toBe(1); + expect(execute).toHaveBeenCalledTimes(1); + expect( + await h.publicClient.readContract({ + address: tokens[2], + abi: TOKEN, + functionName: 'allowance', + args: [s.wallet, h.addresses.gateway], + }) + ).toBe(BigInt(0)); }); it('atomically replaces and resets every asset, recording five checkpoints', async () => { const s = await setup(); @@ -268,7 +281,7 @@ describe('internal prepared SVM backend on v5', () => { ).tx.wait(); const before = await h.publicClient.readContract({ address: s.wallet, - abi: v5.abis.wallet, + abi: v6.abis.wallet, functionName: 'checkpointCount', }); const next = await replaceSvmWire( @@ -287,7 +300,7 @@ describe('internal prepared SVM backend on v5', () => { expect( await h.publicClient.readContract({ address: s.wallet, - abi: v5.abis.wallet, + abi: v6.abis.wallet, functionName: 'checkpointCount', }) ).toBe(before + BigInt(5)); @@ -311,7 +324,7 @@ describe('internal prepared SVM backend on v5', () => { ).tx.wait(); const before = await h.publicClient.readContract({ address: s.wallet, - abi: v5.abis.wallet, + abi: v6.abis.wallet, functionName: 'checkpointCount', }); const error = await rt(owner) @@ -324,7 +337,7 @@ describe('internal prepared SVM backend on v5', () => { expect( await h.publicClient.readContract({ address: s.wallet, - abi: v5.abis.wallet, + abi: v6.abis.wallet, functionName: 'checkpointCount', }) ).toBe(before); @@ -394,7 +407,7 @@ describe('internal prepared SVM backend on v5', () => { rt(owner).execute = execute; } }); - it.each(['allowance', 'balance', 'revocation'])( + it.each(['balance', 'revocation'])( 'on-chain %s change after preflight refuses submission without metering', async (kind) => { const s = await setup(), @@ -412,9 +425,9 @@ describe('internal prepared SVM backend on v5', () => { await owner.agentic.wallet(s.wallet).rules.delete([s.id]) ).wait(); else - await h.write(0, s.wallet, v5.abis.wallet, 'execute', [ + await h.write(0, s.wallet, v6.abis.wallet, 'execute', [ key('00'), - v5.packSingle({ + v6.packSingle({ target: tokens[2], value: BigInt(0), data: encodeFunctionData({ @@ -434,7 +447,7 @@ describe('internal prepared SVM backend on v5', () => { ]); ticks = await h.publicClient.readContract({ address: s.wallet, - abi: v5.abis.wallet, + abi: v6.abis.wallet, functionName: 'checkpointCount', }); return original(params, options); @@ -459,7 +472,7 @@ describe('internal prepared SVM backend on v5', () => { } const stored = await h.publicClient.readContract({ address: h.addresses.rulesPolicy, - abi: v5.abis.policy, + abi: v6.abis.policy, functionName: 'getSvmConfig', args: [before.configId, s.wallet], }); @@ -477,7 +490,7 @@ describe('internal prepared SVM backend on v5', () => { expect( await h.publicClient.readContract({ address: s.wallet, - abi: v5.abis.wallet, + abi: v6.abis.wallet, functionName: 'checkpointCount', }) ).toBe(ticks); @@ -537,7 +550,7 @@ describe('internal prepared SVM backend on v5', () => { expect( await h.publicClient.readContract({ address: s.wallet, - abi: v5.abis.wallet, + abi: v6.abis.wallet, functionName: 'grantNonce', }) ).toBe(BigInt(2)); diff --git a/packages/core/__agw-local__/svm-differential.spec.ts b/packages/core/__agw-local__/svm-differential.spec.ts index 52026155..53385abb 100644 --- a/packages/core/__agw-local__/svm-differential.spec.ts +++ b/packages/core/__agw-local__/svm-differential.spec.ts @@ -16,7 +16,7 @@ import { encodeAgwSvmPayload, validateAgwSvmPayload, } from '../src/lib/agentic/execution/svm-payload'; -import { v5 } from '../src/lib/agentic/contracts/v5'; +import { v6 } from '../src/lib/agentic/contracts/v6'; import { deriveAgwSvmValueAccounts } from '../src/lib/agentic/codec/svm-accounts'; import { decodeAgenticRevert } from '../src/lib/agentic/revert'; import { startHarness, type Harness } from './harness'; @@ -208,7 +208,7 @@ describe('seeded SVM differential validation', () => { try { await h.publicClient.call({ to: wallet, - data: v5.encodeGrantRules(session(c.terms)), + data: v6.encodeGrantRules(session(c.terms)), account: h.wallets[0].account!.address, }); } catch (e) { @@ -237,7 +237,7 @@ describe('seeded SVM differential validation', () => { it('payload mutation corpus agrees with actual URP authorization and rejects without metering', async () => { const t = clone(terms); - t.programs[0].maxAccounts = 0; + t.programs[0].maxAccounts = 255; t.dataPins = [ { ruleIndex: 0, @@ -251,10 +251,10 @@ describe('seeded SVM differential validation', () => { den: BigInt(0), }, ]; - await h.write(0, wallet, v5.abis.wallet, 'grantRules', [session(t)]); + await h.write(0, wallet, v6.abis.wallet, 'grantRules', [session(t)]); const [id] = await h.publicClient.readContract({ address: h.addresses.engine, - abi: v5.abis.engine, + abi: v6.abis.engine, functionName: 'getPermissionIDs', args: [wallet], }); @@ -267,9 +267,9 @@ describe('seeded SVM differential validation', () => { }), }); await h.write(0, token, TOKEN, 'mint', [wallet, BigInt(100)]); - await h.write(0, wallet, v5.abis.wallet, 'execute', [ + await h.write(0, wallet, v6.abis.wallet, 'execute', [ key('00'), - v5.packSingle({ + v6.packSingle({ target: token, value: BigInt(0), data: encodeFunctionData({ @@ -370,12 +370,12 @@ describe('seeded SVM differential validation', () => { try { await h.publicClient.simulateContract({ address: wallet, - abi: v5.abis.wallet, + abi: v6.abis.wallet, functionName: 'executeAsAgent', args: [ id, key('00'), - v5.packSingle({ + v6.packSingle({ target: h.addresses.gateway, value: BigInt(11) * BigInt(10) ** BigInt(14), data, diff --git a/packages/core/__agw-local__/svm-internals.spec.ts b/packages/core/__agw-local__/svm-internals.spec.ts index 24163e4d..9145a861 100644 --- a/packages/core/__agw-local__/svm-internals.spec.ts +++ b/packages/core/__agw-local__/svm-internals.spec.ts @@ -1,4 +1,4 @@ -/** Actual v5 SVM URP checks on Anvil. No Solana execution/TSS is simulated. */ +/** Actual v6 SVM URP checks on Anvil. No Solana execution/TSS is simulated. */ import { encodeFunctionData, parseAbi, type Address, type Hex } from 'viem'; import { CHAIN } from '../src/lib/constants/enums'; import { buildSession, encodeEnvelope } from '../src/lib/agentic/codec/session'; @@ -12,7 +12,7 @@ import { import { deriveAgwSvmValueAccounts } from '../src/lib/agentic/codec/svm-accounts'; import { encodeAgwSvmPayload } from '../src/lib/agentic/execution/svm-payload'; import { composeAgwSvmAction } from '../src/lib/agentic/execution/svm-outbound'; -import { v5, type SvmConfigRead } from '../src/lib/agentic/contracts/v5'; +import { v6, type SvmConfigRead } from '../src/lib/agentic/contracts/v6'; import { startHarness, type Harness } from './harness'; const key = (b: string) => `0x${b.repeat(32)}` as Hex; @@ -25,7 +25,7 @@ const TOKEN = parseAbi([ ]); const UINT256_MAX = BigInt(2) ** BigInt(256) - BigInt(1); -describe('internal SVM codec/payloads against actual v5 contracts', () => { +describe('internal SVM codec/payloads against actual v6 contracts', () => { let h: Harness, token: Address; beforeAll(async () => { h = await startHarness(18552); @@ -57,7 +57,7 @@ describe('internal SVM codec/payloads against actual v5 contracts', () => { discriminator: '0x0100000000000000', discriminatorLen: options.dataless ? 0 : 1, dataless: options.dataless ?? false, - maxAccounts: options.maxAccounts ?? 0, + maxAccounts: options.maxAccounts ?? 255, }, ], pins: [ @@ -92,23 +92,23 @@ describe('internal SVM codec/payloads against actual v5 contracts', () => { }, ], }); - await h.write(0, wallet, v5.abis.wallet, 'grantRules', [session]); + await h.write(0, wallet, v6.abis.wallet, 'grantRules', [session]); const [id] = await h.publicClient.readContract({ address: h.addresses.engine, - abi: v5.abis.engine, + abi: v6.abis.engine, functionName: 'getPermissionIDs', args: [wallet], }); const [action] = await h.publicClient.readContract({ address: h.addresses.engine, - abi: v5.abis.engine, + abi: v6.abis.engine, functionName: 'getEnabledActions', args: [wallet, id], }); const cid = configId(wallet, id, action); const cfg = (await h.publicClient.readContract({ address: h.addresses.rulesPolicy, - abi: v5.abis.policy, + abi: v6.abis.policy, functionName: 'getSvmConfig', args: [cid, wallet], })) as SvmConfigRead; @@ -121,9 +121,9 @@ describe('internal SVM codec/payloads against actual v5 contracts', () => { }), }); await h.write(0, token, TOKEN, 'mint', [wallet, BigInt(100)]); - await h.write(0, wallet, v5.abis.wallet, 'execute', [ + await h.write(0, wallet, v6.abis.wallet, 'execute', [ key('00'), - v5.packSingle({ + v6.packSingle({ target: token, value: BigInt(0), data: encodeFunctionData({ @@ -175,12 +175,12 @@ describe('internal SVM codec/payloads against actual v5 contracts', () => { }); return h.publicClient.simulateContract({ address: wallet, - abi: v5.abis.wallet, + abi: v6.abis.wallet, functionName: 'executeAsAgent', args: [ id, key('00'), - v5.packSingle({ + v6.packSingle({ target: h.addresses.gateway, value: call.value, data, @@ -242,14 +242,14 @@ describe('internal SVM codec/payloads against actual v5 contracts', () => { }); it('the internal composed call passes actual S1–S18 and meters its token', async () => { const { wallet, id, cid, call } = await setup(); - await h.write(1, wallet, v5.abis.wallet, 'executeAsAgent', [ + await h.write(1, wallet, v6.abis.wallet, 'executeAsAgent', [ id, key('00'), - v5.packSingle(call), + v6.packSingle(call), ]); const cfg = await h.publicClient.readContract({ address: h.addresses.rulesPolicy, - abi: v5.abis.policy, + abi: v6.abis.policy, functionName: 'getSvmConfig', args: [cid, wallet], }); @@ -319,7 +319,7 @@ describe('internal SVM codec/payloads against actual v5 contracts', () => { ); const cfg = await h.publicClient.readContract({ address: h.addresses.rulesPolicy, - abi: v5.abis.policy, + abi: v6.abis.policy, functionName: 'getSvmConfig', args: [s.cid, s.wallet], }); diff --git a/packages/core/__agw-local__/svm-public.spec.ts b/packages/core/__agw-local__/svm-public.spec.ts index d28448e2..bd78096e 100644 --- a/packages/core/__agw-local__/svm-public.spec.ts +++ b/packages/core/__agw-local__/svm-public.spec.ts @@ -13,7 +13,7 @@ import { } from 'viem'; import { CHAIN, PushChain, AgenticRevertError, type Rule } from '../src'; import type { AgenticRuntime } from '../src/lib/agentic/runtime'; -import { v5 } from '../src/lib/agentic/contracts/v5'; +import { v6 } from '../src/lib/agentic/contracts/v6'; import { clearRegistry } from '../src/lib/orchestrator/svm-idl/registry'; import { startHarness, type Harness } from './harness'; const program = new PublicKey(Buffer.alloc(32, 51)).toBase58(); @@ -40,7 +40,7 @@ const TOKEN = parseAbi([ const CORE = parseAbi(['function setGasToken(string,address)']); const rt = (c: PushChain) => (c as unknown as { agenticRuntime: AgenticRuntime }).agenticRuntime; -describe('public Solana rules on actual v5', () => { +describe('public Solana rules on actual v6', () => { let h: Harness, owner: PushChain, token: Address; beforeAll(async () => { h = await startHarness(18561); @@ -136,9 +136,9 @@ describe('public Solana rules on actual v5', () => { }), }); await h.write(0, token, TOKEN, 'mint', [made.wallet, BigInt(20)]); - await h.write(0, made.wallet, v5.abis.wallet, 'execute', [ + await h.write(0, made.wallet, v6.abis.wallet, 'execute', [ `0x${'00'.repeat(32)}`, - v5.packSingle({ + v6.packSingle({ target: token, value: BigInt(0), data: encodeFunctionData({ @@ -232,9 +232,9 @@ describe('public Solana rules on actual v5', () => { }), }); await h.write(0, token, TOKEN, 'mint', [made.wallet, BigInt(10)]); - await h.write(0, made.wallet, v5.abis.wallet, 'execute', [ + await h.write(0, made.wallet, v6.abis.wallet, 'execute', [ `0x${'00'.repeat(32)}`, - v5.packSingle({ + v6.packSingle({ target: token, value: BigInt(0), data: encodeFunctionData({ @@ -401,9 +401,9 @@ describe('public Solana rules on actual v5', () => { }), }); await h.write(0, spl, TOKEN, 'mint', [made.wallet, BigInt(10)]); - await h.write(0, made.wallet, v5.abis.wallet, 'execute', [ + await h.write(0, made.wallet, v6.abis.wallet, 'execute', [ `0x${'00'.repeat(32)}`, - v5.packSingle({ + v6.packSingle({ target: spl, value: BigInt(0), data: encodeFunctionData({ diff --git a/packages/core/__agw-local__/v5-multiasset.spec.ts b/packages/core/__agw-local__/v5-multiasset.spec.ts index 2fe6edf4..40659c47 100644 --- a/packages/core/__agw-local__/v5-multiasset.spec.ts +++ b/packages/core/__agw-local__/v5-multiasset.spec.ts @@ -1,6 +1,6 @@ import { buildPresetApi } from '../src/lib/agentic/presets'; import { publicRules } from '../src/lib/agentic/public-rule'; -/** Actual v5 AGW/URP/engine. Token/core/gateway and destination lookup are local fixtures; no bridge/TSS proof. */ +/** Actual v6 AGW/URP/engine. Token/core/gateway and destination lookup are local fixtures; no bridge/TSS proof. */ import { encodeFunctionData, getAddress, @@ -36,7 +36,7 @@ const DEST = getAddress('0x0000000000000000000000000000000000001234'); const internal = (c: PushChain) => (c as unknown as { agenticRuntime: AgenticRuntime }).agenticRuntime; -describe('v5 multi-asset SDK management and execution', () => { +describe('v6 multi-asset SDK management and execution', () => { let h: Harness, owner: PushChain, a: Address, b: Address; beforeAll(async () => { h = await startHarness(18551); @@ -152,6 +152,82 @@ describe('v5 multi-asset SDK management and execution', () => { args: [configId(wallet, id, action), wallet], }); } + it('v6 EVM alternatives enforce both spender and MAX, and reads update losslessly', async () => { + const input = rule(); + input.allowedCalls = [DEST, CEA].map((spender) => ({ + target: a, + selector: 'approve(address,uint256)', + pins: [ + { arg: 0, expected: spender }, + { arg: 1, max: BigInt(5) }, + ], + })); + const { wallet, id, agent } = await setup(input); + const send = (spender: Address, amount: bigint) => + agent.universal.sendTransaction({ + to: { address: a, chain: CHAIN_NS }, + data: [ + { + to: a, + value: BigInt(0), + data: encodeFunctionData({ + abi: TOKEN, + functionName: 'approve', + args: [spender, amount], + }), + }, + ], + }); + await waitPush(send(DEST, BigInt(5))); + await waitPush(send(CEA, BigInt(4))); + await expect( + send(h.wallets[3].account!.address, BigInt(1)) + ).rejects.toMatchObject({ + decodedError: { name: 'PolicyCheckReverted(ArgPinMismatch)' }, + }); + await expect(send(DEST, BigInt(6))).rejects.toMatchObject({ + decodedError: { name: 'PolicyCheckReverted(ArgPinAboveMax)' }, + }); + const handle = owner.agentic.wallet(wallet), + record = await handle.rules.get(id); + expect((record.rule as Rule).allowedCalls).toHaveLength(2); + const updated = await handle.rules.update({ + rules: [ + { + rulesId: id, + rule: { ...record.rule, validUntil: record.validUntil + 60 }, + }, + ], + }); + expect((await handle.rules.get(updated.rules[0].rulesId)).rule).toEqual({ + ...record.rule, + validUntil: record.validUntil + 60, + }); + }); + it('v6 refuses a bare alternative that bypasses a pinned function and too many initial rules', async () => { + const input = rule(); + input.allowedCalls = [ + { target: DEST, selector: 'increment()', pins: [] }, + { + target: DEST, + selector: 'increment()', + pins: [{ arg: 0, max: BigInt(1) }], + }, + ]; + await expect( + owner.agentic.create('bypass', { rules: [input] }) + ).rejects.toMatchObject({ code: 'INVALID_RULE' }); + const rules = Array.from({ length: 9 }, (_, i) => ({ + ...rule(), + agent: getAddress(`0x${(100 + i).toString(16).padStart(40, '0')}`), + })); + const before = await owner.agentic.derive(); + await expect( + owner.agentic.create('too-many', { rules }) + ).rejects.toMatchObject({ code: 'INVALID_RULE' }); + expect(await owner.agentic.derive()).toEqual(before); + }); + it('a fixture preset produces rules accepted by public create and enforced by real contracts', async () => { const presets = buildPresetApi([ { @@ -374,7 +450,7 @@ describe('v5 multi-asset SDK management and execution', () => { }) ).rejects.toMatchObject({ code: 'AMBIGUOUS_RULE' }); }); - it('a legacy two-field envelope is refused by the actual v5 grant path', async () => { + it('a legacy two-field envelope is refused by the actual v6 grant path', async () => { const bare = await owner.agentic.create('old-envelope', { rules: [] }); const { encodeAbiParameters } = await import('viem'); const terms = nativeRuleToTerms( diff --git a/packages/core/__agw-local__/vectors.spec.ts b/packages/core/__agw-local__/vectors.spec.ts index dcc5d291..f75b3e80 100644 --- a/packages/core/__agw-local__/vectors.spec.ts +++ b/packages/core/__agw-local__/vectors.spec.ts @@ -4,7 +4,7 @@ import type { AgenticRuntime } from '../src/lib/agentic/runtime'; * below is computed BY THE PINNED CONTRACTS (pure engine/factory views, or * state read back after a real grant), never by the SDK under test. * - * AGW_WRITE_VECTORS=1 → (re)write src/lib/agentic/__fixtures__/v5-vectors.json + * AGW_WRITE_VECTORS=1 → (re)write src/lib/agentic/__fixtures__/v6-vectors.json * otherwise → assert the committed file still matches the contracts */ import { execSync } from 'node:child_process'; @@ -31,7 +31,7 @@ const FIXTURE = join( 'lib', 'agentic', '__fixtures__', - 'v5-vectors.json' + 'v6-vectors.json' ); const bigintJson = (v: unknown) => JSON.stringify( @@ -40,7 +40,7 @@ const bigintJson = (v: unknown) => 2 ); -describe('contract-generated AGW vectors (v5)', () => { +describe('contract-generated AGW vectors (v6)', () => { let h: Harness; beforeAll(async () => { h = await startHarness(18548); @@ -171,7 +171,7 @@ describe('contract-generated AGW vectors (v5)', () => { initialized: boolean; target: Address; selector: Hex; - pins: readonly { offset: number; expected: Hex }[]; + pins: readonly { offset: number; op: number; value: Hex }[]; amount: { offset: number }; }; const native = { @@ -186,7 +186,8 @@ describe('contract-generated AGW vectors (v5)', () => { storedSelector: stored.selector, storedPins: stored.pins.map((p) => ({ offset: Number(p.offset), - expected: p.expected, + op: p.op, + value: p.value, })), storedAmountOffset: Number(stored.amount.offset), encodedSession: encodeSession(session), diff --git a/packages/core/__e2e__/agw-svm-wire/outbound.spec.ts b/packages/core/__e2e__/agw-svm-wire/outbound.spec.ts index 67359498..19aea3c0 100644 --- a/packages/core/__e2e__/agw-svm-wire/outbound.spec.ts +++ b/packages/core/__e2e__/agw-svm-wire/outbound.spec.ts @@ -1,9 +1,23 @@ /** Internal wire acceptance alongside public Solana coverage. Policy refusals come from URP simulation. */ import '@e2e/shared/setup'; import { PushChain } from '../../src'; -import { Keypair, PublicKey, type ParsedTransactionWithMeta } from '@solana/web3.js'; +import { + Keypair, + PublicKey, + type ParsedTransactionWithMeta, +} from '@solana/web3.js'; import bs58 from 'bs58'; -import { bytesToHex, createPublicClient, http, encodeFunctionData, erc20Abi, parseAbi, parseEther, type Address, type Hex } from 'viem'; +import { + bytesToHex, + createPublicClient, + http, + encodeFunctionData, + erc20Abi, + parseAbi, + parseEther, + type Address, + type Hex, +} from 'viem'; import { privateKeyToAccount } from 'viem/accounts'; import { CHAIN, PUSH_NETWORK } from '../../src/lib/constants/enums'; import { CHAIN_INFO, getPushViemChain } from '../../src/lib/constants/chain'; @@ -14,161 +28,441 @@ import { readSvmRule } from '../../src/lib/agentic/reads/svm'; import { grantSvmWire } from '../../src/lib/agentic/management/svm'; import { createSvmMetadataProvider } from '../../src/lib/agentic/management/svm-metadata'; import { resolveSvmContext } from '../../src/lib/agentic/management/svm-context'; -import { sendSvmAgentWire, prepareSvmAgentExecution, type PreparedSvmRequest } from '../../src/lib/agentic/execution/svm-send'; -import { SvmDataPinMode, type SvmTermsWire } from '../../src/lib/agentic/codec/svm-terms'; +import { + sendSvmAgentWire, + prepareSvmAgentExecution, + type PreparedSvmRequest, +} from '../../src/lib/agentic/execution/svm-send'; +import { + SvmDataPinMode, + type SvmTermsWire, +} from '../../src/lib/agentic/codec/svm-terms'; import { svmKey } from '../../src/lib/agentic/codec/svm-accounts'; import { adaptTrackedResponse } from '../../src/lib/agentic/response'; -import { v5 } from '../../src/lib/agentic/contracts/v5'; -import { setupAgw, evmClient, inSeconds, type AgwFixture } from '../agw/_fixture'; +import { v6 } from '../../src/lib/agentic/contracts/v6'; +import { + setupAgw, + evmClient, + inSeconds, + type AgwFixture, +} from '../agw/_fixture'; import { loadAgwManifest, verifyAgwManifest } from '../agw/_manifest'; -import { inspectSvmWirePrograms, svmWireConnection, SVM_WIRE_CHAIN, SVM_WIRE_GATEWAY, SVM_WIRE_PROGRAM, SVM_WIRE_COUNTER, decodeWireCounter } from '../shared/agw-svm-preflight'; +import { + inspectSvmWirePrograms, + svmWireConnection, + SVM_WIRE_CHAIN, + SVM_WIRE_GATEWAY, + SVM_WIRE_PROGRAM, + SVM_WIRE_COUNTER, + decodeWireCounter, +} from '../shared/agw-svm-preflight'; import { probeSvmWirePolicies } from '../shared/agw-svm-policy-probe'; const d = process.env['AGW_SVM_WIRE_E2E'] === '1' ? describe : describe.skip; // Load the public entry point before internal modules (the existing harness // does the same); keeping this runtime use prevents TypeScript erasing it. -if (PushChain.CONSTANTS.CHAIN.SOLANA_DEVNET !== SVM_WIRE_CHAIN) throw new Error('Solana fixture chain mismatch'); +if (PushChain.CONSTANTS.CHAIN.SOLANA_DEVNET !== SVM_WIRE_CHAIN) + throw new Error('Solana fixture chain mismatch'); const AMOUNT = BigInt(10_000); // 0.00001 SOL, twice at most per run. const MAX_PC = parseEther('20'); const RECEIVE = '0x79f4fa0308e5e101' as Hex; const DECREMENT = '0x6ae3a83bf81b9665' as Hex; const ZERO = `0x${'00'.repeat(32)}` as Hex; -const rt = (c: PushChain) => (c as unknown as { agenticRuntime: AgenticRuntime }).agenticRuntime; +const rt = (c: PushChain) => + (c as unknown as { agenticRuntime: AgenticRuntime }).agenticRuntime; const ixData = (disc: Hex, amount: bigint) => { - const b = Buffer.alloc(16); Buffer.from(disc.slice(2), 'hex').copy(b); b.writeBigUInt64LE(amount, 8); return b; + const b = Buffer.alloc(16); + Buffer.from(disc.slice(2), 'hex').copy(b); + b.writeBigUInt64LE(amount, 8); + return b; }; -function transferFromCea(tx: ParsedTransactionWithMeta, cea: string, recipient: string, amount: bigint) { - return tx.meta?.innerInstructions?.some((group) => group.instructions.some((ix) => - 'parsed' in ix && ix.program === 'system' && ix.parsed.type === 'transfer' && - ix.parsed.info.source === cea && ix.parsed.info.destination === recipient && - BigInt(ix.parsed.info.lamports) === amount - )); +function transferFromCea( + tx: ParsedTransactionWithMeta, + cea: string, + recipient: string, + amount: bigint +) { + return tx.meta?.innerInstructions?.some((group) => + group.instructions.some( + (ix) => + 'parsed' in ix && + ix.program === 'system' && + ix.parsed.type === 'transfer' && + ix.parsed.info.source === cea && + ix.parsed.info.destination === recipient && + BigInt(ix.parsed.info.lamports) === amount + ) + ); } d('agw svm wire', () => { - let f: AgwFixture, wallet: Address, token: Address, rulesId: Hex, agent: PushChain; + let f: AgwFixture, + wallet: Address, + token: Address, + rulesId: Hex, + agent: PushChain; let gen: Awaited>; let recipient: PublicKey, cea: PublicKey; const sol = svmWireConnection(); - const metadata = createSvmMetadataProvider({ [SVM_WIRE_CHAIN]: { - gatewayProgram: SVM_WIRE_GATEWAY, rpcUrls: CHAIN_INFO[SVM_WIRE_CHAIN].defaultRPC, - } }, (url) => svmWireConnection(url)); - const accounts = (failure = false) => failure - ? [{ pubkey: svmKey(SVM_WIRE_COUNTER.toBase58()), isWritable: true }, { pubkey: svmKey(cea.toBase58()), isWritable: false }] - : [{ pubkey: svmKey(SVM_WIRE_COUNTER.toBase58()), isWritable: true }, { pubkey: svmKey(recipient.toBase58()), isWritable: true }, { pubkey: svmKey(cea.toBase58()), isWritable: true }, { pubkey: ZERO, isWritable: false }]; - const request = (failure = false): PreparedSvmRequest => ({ wallet, rulesId, token, amount: AMOUNT, gasLimit: BigInt(0), - program: SVM_WIRE_PROGRAM, instructionData: ixData(failure ? DECREMENT : RECEIVE, failure ? BigInt(1) : AMOUNT), accounts: accounts(failure) }); - const stored = () => Snapshot.at(rt(f.owner).reader).then((snap) => readSvmRule(snap, gen, wallet, rulesId, rt(f.owner).pushChainNamespace)); + const metadata = createSvmMetadataProvider( + { + [SVM_WIRE_CHAIN]: { + gatewayProgram: SVM_WIRE_GATEWAY, + rpcUrls: CHAIN_INFO[SVM_WIRE_CHAIN].defaultRPC, + }, + }, + (url) => svmWireConnection(url) + ); + const accounts = (failure = false) => + failure + ? [ + { pubkey: svmKey(SVM_WIRE_COUNTER.toBase58()), isWritable: true }, + { pubkey: svmKey(cea.toBase58()), isWritable: false }, + ] + : [ + { pubkey: svmKey(SVM_WIRE_COUNTER.toBase58()), isWritable: true }, + { pubkey: svmKey(recipient.toBase58()), isWritable: true }, + { pubkey: svmKey(cea.toBase58()), isWritable: true }, + { pubkey: ZERO, isWritable: false }, + ]; + const request = (failure = false): PreparedSvmRequest => ({ + wallet, + rulesId, + token, + amount: AMOUNT, + gasLimit: BigInt(0), + program: SVM_WIRE_PROGRAM, + instructionData: ixData( + failure ? DECREMENT : RECEIVE, + failure ? BigInt(1) : AMOUNT + ), + accounts: accounts(failure), + }); + const stored = () => + Snapshot.at(rt(f.owner).reader).then((snap) => + readSvmRule(snap, gen, wallet, rulesId, rt(f.owner).pushChainNamespace) + ); beforeAll(async () => { // Every cluster/program check runs before setupAgw can fund anything. const preflight = await inspectSvmWirePrograms(sol); const key = process.env['SOLANA_PRIVATE_KEY']; - if (!key) throw new Error('SOLANA_PRIVATE_KEY is needed only to identify the owned recipient'); - try { recipient = Keypair.fromSecretKey(bs58.decode(key)).publicKey; } - catch { recipient = Keypair.fromSecretKey(Uint8Array.from(JSON.parse(key))).publicKey; } + if (!key) + throw new Error( + 'SOLANA_PRIVATE_KEY is needed only to identify the owned recipient' + ); + try { + recipient = Keypair.fromSecretKey(bs58.decode(key)).publicKey; + } catch { + recipient = Keypair.fromSecretKey( + Uint8Array.from(JSON.parse(key)) + ).publicKey; + } const destination = await sol.getAccountInfo(recipient); - if (!destination || destination.executable || !destination.owner.equals(PublicKey.default)) throw new Error('Owned recipient must be an existing System account'); - if (parseEther(process.env['AGW_E2E_AGENT_PC'] ?? '0.5') > parseEther('0.5')) throw new Error('Wire suite agent funding is bounded to 0.5 PC'); + if ( + !destination || + destination.executable || + !destination.owner.equals(PublicKey.default) + ) + throw new Error('Owned recipient must be an existing System account'); + if ( + parseEther(process.env['AGW_E2E_AGENT_PC'] ?? '0.5') > parseEther('0.5') + ) + throw new Error('Wire suite agent funding is bounded to 0.5 PC'); const manifest = loadAgwManifest(); - if (manifest.network !== PUSH_NETWORK.TESTNET_DONUT) throw new Error('Wire suite is restricted to Donut'); - const push = createPublicClient({ chain: getPushViemChain(CHAIN.PUSH_TESTNET_DONUT), transport: http(CHAIN_INFO[CHAIN.PUSH_TESTNET_DONUT].defaultRPC[0]) }); + if (manifest.network !== PUSH_NETWORK.TESTNET_DONUT) + throw new Error('Wire suite is restricted to Donut'); + const push = createPublicClient({ + chain: getPushViemChain(CHAIN.PUSH_TESTNET_DONUT), + transport: http(CHAIN_INFO[CHAIN.PUSH_TESTNET_DONUT].defaultRPC[0]), + }); await verifyAgwManifest(push, manifest); const ownerKey = process.env['PUSH_PRIVATE_KEY'] as Hex | undefined; if (!ownerKey) throw new Error('PUSH_PRIVATE_KEY is required'); const ownerAddress = privateKeyToAccount(ownerKey).address; - token = await push.readContract({ address: '0x00000000000000000000000000000000000000C0', - abi: parseAbi(['function gasTokenPRC20ByChainNamespace(string) view returns (address)']), - functionName: 'gasTokenPRC20ByChainNamespace', args: [SVM_WIRE_CHAIN] }); - const ownerTokens = await push.readContract({ address: token, abi: erc20Abi, functionName: 'balanceOf', args: [ownerAddress] }); - if (ownerTokens < AMOUNT * BigInt(2)) throw new Error('Push owner needs 0.00002 pSOL for this bounded suite'); - if (await push.getBalance({ address: ownerAddress }) < parseEther('45')) throw new Error('Push owner needs 45 PC to cover bounded setup and outbound budgets'); + token = await push.readContract({ + address: '0x00000000000000000000000000000000000000C0', + abi: parseAbi([ + 'function gasTokenPRC20ByChainNamespace(string) view returns (address)', + ]), + functionName: 'gasTokenPRC20ByChainNamespace', + args: [SVM_WIRE_CHAIN], + }); + const ownerTokens = await push.readContract({ + address: token, + abi: erc20Abi, + functionName: 'balanceOf', + args: [ownerAddress], + }); + if (ownerTokens < AMOUNT * BigInt(2)) + throw new Error('Push owner needs 0.00002 pSOL for this bounded suite'); + if ((await push.getBalance({ address: ownerAddress })) < parseEther('45')) + throw new Error( + 'Push owner needs 45 PC to cover bounded setup and outbound budgets' + ); f = await setupAgw(); f.evidence('svm-wire-program-preflight', preflight); - wallet = (await f.owner.agentic.create('e2e-internal-svm-wire', { rules: [] })).wallet; - gen = await resolveWalletGeneration(rt(f.owner).reader, f.manifest.network, wallet); - const resolved = await resolveSvmContext(await Snapshot.at(rt(f.owner).reader), wallet, SVM_WIRE_CHAIN, - [{ token, maxPerCall: AMOUNT, maxTotal: AMOUNT * BigInt(2) }], metadata); + wallet = ( + await f.owner.agentic.create('e2e-internal-svm-wire', { rules: [] }) + ).wallet; + gen = await resolveWalletGeneration( + rt(f.owner).reader, + f.manifest.network, + wallet + ); + const resolved = await resolveSvmContext( + await Snapshot.at(rt(f.owner).reader), + wallet, + SVM_WIRE_CHAIN, + [{ token, maxPerCall: AMOUNT, maxTotal: AMOUNT * BigInt(2) }], + metadata + ); cea = new PublicKey(Buffer.from(resolved.expectedCEA.slice(2), 'hex')); - if (cea.toBase58() === preflight.counter.authority) throw new Error('Failure fixture requires a counter authority different from the fresh AGW CEA'); - const terms: SvmTermsWire = { ...resolved, validUntil: inSeconds(7200), maxGasPerCall: MAX_PC, - programs: [RECEIVE, DECREMENT].map((discriminator, i) => ({ program: svmKey(SVM_WIRE_PROGRAM), discriminator, - discriminatorLen: 8, dataless: false, maxAccounts: i === 0 ? 4 : 2 })), - pins: [false, true].flatMap((failure, ruleIndex) => accounts(failure).map((a, accountIndex) => ({ ruleIndex, accountIndex, expected: a.pubkey }))), - dataPins: [AMOUNT, BigInt(1)].map((limit, ruleIndex) => ({ ruleIndex, fromEnd: false, offset: 8, offsetB: 0, len: 8, - mode: SvmDataPinMode.LTE_LE, expected: `0x${limit.toString(16).padStart(64, '0')}`, num: BigInt(0), den: BigInt(0) })), + if (cea.toBase58() === preflight.counter.authority) + throw new Error( + 'Failure fixture requires a counter authority different from the fresh AGW CEA' + ); + const terms: SvmTermsWire = { + ...resolved, + validUntil: inSeconds(7200), + maxGasPerCall: MAX_PC, + programs: [RECEIVE, DECREMENT].map((discriminator, i) => ({ + program: svmKey(SVM_WIRE_PROGRAM), + discriminator, + discriminatorLen: 8, + dataless: false, + maxAccounts: i === 0 ? 4 : 2, + })), + pins: [false, true].flatMap((failure, ruleIndex) => + accounts(failure).map((a, accountIndex) => ({ + ruleIndex, + accountIndex, + expected: a.pubkey, + })) + ), + dataPins: [AMOUNT, BigInt(1)].map((limit, ruleIndex) => ({ + ruleIndex, + fromEnd: false, + offset: 8, + offsetB: 0, + len: 8, + mode: SvmDataPinMode.LTE_LE, + expected: `0x${limit.toString(16).padStart(64, '0')}`, + num: BigInt(0), + den: BigInt(0), + })), }; - const grant = await grantSvmWire(rt(f.owner), gen, wallet, { agent: f.agentAddress, chainNamespace: SVM_WIRE_CHAIN, terms }); + const grant = await grantSvmWire(rt(f.owner), gen, wallet, { + agent: f.agentAddress, + chainNamespace: SVM_WIRE_CHAIN, + terms, + }); rulesId = grant.rulesId; await f.fundPC(wallet, MAX_PC * BigInt(2) + parseEther('1')); - await (await f.owner.universal.sendTransaction({ to: token, data: encodeFunctionData({ abi: erc20Abi, functionName: 'transfer', args: [wallet, AMOUNT * BigInt(2)] }) })).wait(); - const ownerWallet = await evmClient(process.env['PUSH_PRIVATE_KEY'] as Hex, CHAIN.PUSH_TESTNET_DONUT, f.manifest.network, wallet); - await (await ownerWallet.universal.sendTransaction({ to: token, data: encodeFunctionData({ abi: erc20Abi, functionName: 'approve', args: [f.manifest.addresses.gateway, AMOUNT * BigInt(2)] }) })).wait(); + await ( + await f.owner.universal.sendTransaction({ + to: token, + data: encodeFunctionData({ + abi: erc20Abi, + functionName: 'transfer', + args: [wallet, AMOUNT * BigInt(2)], + }), + }) + ).wait(); + const ownerWallet = await evmClient( + process.env['PUSH_PRIVATE_KEY'] as Hex, + CHAIN.PUSH_TESTNET_DONUT, + f.manifest.network, + wallet + ); + await ( + await ownerWallet.universal.sendTransaction({ + to: token, + data: encodeFunctionData({ + abi: erc20Abi, + functionName: 'approve', + args: [f.manifest.addresses.gateway, AMOUNT * BigInt(2)], + }), + }) + ).wait(); agent = await f.agent(wallet); - f.evidence('svm-wire-setup', { wallet, rulesId, grantHash: grant.tx.hash, agent: f.agentAddress, recipient: recipient.toBase58(), cea: cea.toBase58(), token, terms, walletPCFunded: MAX_PC * BigInt(2) + parseEther('1'), tokenFunded: AMOUNT * BigInt(2) }); + f.evidence('svm-wire-setup', { + wallet, + rulesId, + grantHash: grant.tx.hash, + agent: f.agentAddress, + recipient: recipient.toBase58(), + cea: cea.toBase58(), + token, + terms, + walletPCFunded: MAX_PC * BigInt(2) + parseEther('1'), + tokenFunded: AMOUNT * BigInt(2), + }); }, 900_000); afterAll(() => f?.teardown()); it('1. positive outbound: actual CEA transfer and counter execution, receipt and replay', async () => { - const before = decodeWireCounter((await sol.getAccountInfo(SVM_WIRE_COUNTER))!.data).value; - const count = await f.push.readContract({ address: wallet, abi: v5.abis.wallet, functionName: 'checkpointCount' }); + const before = decodeWireCounter( + (await sol.getAccountInfo(SVM_WIRE_COUNTER))!.data + ).value; + const count = await f.push.readContract({ + address: wallet, + abi: v6.abis.wallet, + functionName: 'checkpointCount', + }); const { tx } = await sendSvmAgentWire(rt(agent), gen, request(), metadata); - f.evidence('svm-wire-positive-submitted', { wallet, rulesId, hash: tx.hash }); + f.evidence('svm-wire-positive-submitted', { + wallet, + rulesId, + hash: tx.hash, + }); // Existing verified-wallet replay adaptation enables normal outbound wait; // it uses the gateway wire call as the logical summary, not a new SVM API. await adaptTrackedResponse(rt(agent), tx); - expect(tx.from).toBe(wallet); expect(tx.route).toBe('UOA_TO_CEA'); + expect(tx.from).toBe(wallet); + expect(tx.route).toBe('UOA_TO_CEA'); const receipt = await tx.wait({ outboundTimeoutMs: 600_000 }); f.evidence('svm-wire-positive-receipt', { hash: tx.hash, receipt }); - expect(receipt.status).toBe(1); expect(receipt.externalStatus).toBe('success'); - expect(receipt.from).toBe(wallet); expect(receipt.externalChain).toBe(SVM_WIRE_CHAIN); - const destination = await sol.getParsedTransaction(receipt.externalTxHash!, { commitment: 'confirmed', maxSupportedTransactionVersion: 0 }); - expect(destination).not.toBeNull(); expect(destination!.meta!.err).toBeNull(); - expect(transferFromCea(destination!, cea.toBase58(), recipient.toBase58(), AMOUNT)).toBe(true); - expect(destination!.meta!.innerInstructions?.some((g) => g.instructions.some((ix) => - 'data' in ix && ix.programId.toBase58() === SVM_WIRE_PROGRAM && bytesToHex(bs58.decode(ix.data)) === bytesToHex(ixData(RECEIVE, AMOUNT)) && - ix.accounts.some((a) => a.equals(cea)) - ))).toBe(true); - expect(decodeWireCounter((await sol.getAccountInfo(SVM_WIRE_COUNTER))!.data).value).toBeGreaterThanOrEqual(before + AMOUNT); + expect(receipt.status).toBe(1); + expect(receipt.externalStatus).toBe('success'); + expect(receipt.from).toBe(wallet); + expect(receipt.externalChain).toBe(SVM_WIRE_CHAIN); + const destination = await sol.getParsedTransaction( + receipt.externalTxHash!, + { commitment: 'confirmed', maxSupportedTransactionVersion: 0 } + ); + expect(destination).not.toBeNull(); + expect(destination!.meta!.err).toBeNull(); + expect( + transferFromCea( + destination!, + cea.toBase58(), + recipient.toBase58(), + AMOUNT + ) + ).toBe(true); + expect( + destination!.meta!.innerInstructions?.some((g) => + g.instructions.some( + (ix) => + 'data' in ix && + ix.programId.toBase58() === SVM_WIRE_PROGRAM && + bytesToHex(bs58.decode(ix.data)) === + bytesToHex(ixData(RECEIVE, AMOUNT)) && + ix.accounts.some((a) => a.equals(cea)) + ) + ) + ).toBe(true); + expect( + decodeWireCounter((await sol.getAccountInfo(SVM_WIRE_COUNTER))!.data) + .value + ).toBeGreaterThanOrEqual(before + AMOUNT); expect((await stored()).config.assets[0].spent).toBe(AMOUNT); - expect(await f.push.readContract({ address: wallet, abi: v5.abis.wallet, functionName: 'checkpointCount' })).toBe(count); + expect( + await f.push.readContract({ + address: wallet, + abi: v6.abis.wallet, + functionName: 'checkpointCount', + }) + ).toBe(count); const replay = await f.owner.universal.trackTransaction(tx.hash); - expect(replay.from).toBe(wallet); expect(replay.route).toBe('UOA_TO_CEA'); + expect(replay.from).toBe(wallet); + expect(replay.route).toBe('UOA_TO_CEA'); expect(replay.agentic).toMatchObject({ door: 'agent', rulesId }); const replayReceipt = await replay.wait({ outboundTimeoutMs: 600_000 }); expect(replayReceipt.externalTxHash).toBe(receipt.externalTxHash); - f.evidence('svm-wire-positive-destination', { hash: tx.hash, externalTxHash: receipt.externalTxHash, destination, replayReceipt }); + f.evidence('svm-wire-positive-destination', { + hash: tx.hash, + externalTxHash: receipt.externalTxHash, + destination, + replayReceipt, + }); }, 900_000); it('2. substituted account and oversized instruction amount fail before submission', async () => { const base = request(); - const wrong = [...base.accounts!]; wrong[2] = { ...wrong[2], pubkey: svmKey(recipient.toBase58()) }; + const wrong = [...base.accounts!]; + wrong[2] = { ...wrong[2], pubkey: svmKey(recipient.toBase58()) }; const nonce = await f.push.getTransactionCount({ address: f.agentAddress }); - await expect(sendSvmAgentWire(rt(agent), gen, { ...base, accounts: wrong }, metadata)).rejects.toMatchObject({ name: 'AgenticRevertError', decodedError: { name: 'PolicyCheckReverted(SvmAccountPinMismatch)' } }); - await expect(sendSvmAgentWire(rt(agent), gen, { ...base, instructionData: ixData(RECEIVE, AMOUNT + BigInt(1)) }, metadata)).rejects.toMatchObject({ name: 'AgenticRevertError', decodedError: { name: 'PolicyCheckReverted(SvmDataCeilingExceeded)' } }); - const prepared = await prepareSvmAgentExecution(rt(agent), gen, base, metadata); - const policy = await probeSvmWirePolicies(f.push, { from: f.agentAddress, wallet, rulesId, call: prepared.call, blockNumber: await f.push.getBlockNumber() }); - expect(await f.push.getTransactionCount({ address: f.agentAddress })).toBe(nonce); - f.evidence('svm-wire-preflight-refusals', { wallet, rulesId, nonce, policy, transactionsSent: 0 }); + await expect( + sendSvmAgentWire(rt(agent), gen, { ...base, accounts: wrong }, metadata) + ).rejects.toMatchObject({ + name: 'AgenticRevertError', + decodedError: { name: 'PolicyCheckReverted(SvmAccountPinMismatch)' }, + }); + await expect( + sendSvmAgentWire( + rt(agent), + gen, + { ...base, instructionData: ixData(RECEIVE, AMOUNT + BigInt(1)) }, + metadata + ) + ).rejects.toMatchObject({ + name: 'AgenticRevertError', + decodedError: { name: 'PolicyCheckReverted(SvmDataCeilingExceeded)' }, + }); + const prepared = await prepareSvmAgentExecution( + rt(agent), + gen, + base, + metadata + ); + const policy = await probeSvmWirePolicies(f.push, { + from: f.agentAddress, + wallet, + rulesId, + call: prepared.call, + blockNumber: await f.push.getBlockNumber(), + }); + expect(await f.push.getTransactionCount({ address: f.agentAddress })).toBe( + nonce + ); + f.evidence('svm-wire-preflight-refusals', { + wallet, + rulesId, + nonce, + policy, + transactionsSent: 0, + }); }); it('3. destination program failure is classified and does not restore policy spend', async () => { const prior = (await stored()).config.assets[0].spent; - const { tx } = await sendSvmAgentWire(rt(agent), gen, request(true), metadata); - f.evidence('svm-wire-failure-submitted', { wallet, rulesId, hash: tx.hash }); + const { tx } = await sendSvmAgentWire( + rt(agent), + gen, + request(true), + metadata + ); + f.evidence('svm-wire-failure-submitted', { + wallet, + rulesId, + hash: tx.hash, + }); await adaptTrackedResponse(rt(agent), tx); // The observed node rejection lifecycle exceeded ten minutes. Keep the // failed assertion strict while allowing the bounded terminalization window. const receipt = await tx.wait({ outboundTimeoutMs: 1_200_000 }); f.evidence('svm-wire-failure-receipt', { hash: tx.hash, receipt }); - const pushReceipt = await f.push.getTransactionReceipt({ hash: tx.hash as Hex }); - expect(pushReceipt.status).toBe('success'); expect(receipt.externalStatus).toBe('failed'); + const pushReceipt = await f.push.getTransactionReceipt({ + hash: tx.hash as Hex, + }); + expect(pushReceipt.status).toBe('success'); + expect(receipt.externalStatus).toBe('failed'); expect((await stored()).config.assets[0].spent).toBe(prior + AMOUNT); if (receipt.externalTxHash) { - const destination = await sol.getParsedTransaction(receipt.externalTxHash, { commitment: 'confirmed', maxSupportedTransactionVersion: 0 }); - expect(destination).not.toBeNull(); expect(destination!.meta!.err).not.toBeNull(); - f.evidence('svm-wire-failure-destination', { hash: tx.hash, externalTxHash: receipt.externalTxHash, destination }); + const destination = await sol.getParsedTransaction( + receipt.externalTxHash, + { commitment: 'confirmed', maxSupportedTransactionVersion: 0 } + ); + expect(destination).not.toBeNull(); + expect(destination!.meta!.err).not.toBeNull(); + f.evidence('svm-wire-failure-destination', { + hash: tx.hash, + externalTxHash: receipt.externalTxHash, + destination, + }); } }, 1_500_000); }); diff --git a/packages/core/__e2e__/agw-svm-wire/replay.spec.ts b/packages/core/__e2e__/agw-svm-wire/replay.spec.ts index 3ea2196c..a1331363 100644 --- a/packages/core/__e2e__/agw-svm-wire/replay.spec.ts +++ b/packages/core/__e2e__/agw-svm-wire/replay.spec.ts @@ -3,57 +3,100 @@ import { PushChain } from '../../src'; import { createPublicClient, http, type Hex } from 'viem'; import { CHAIN_INFO, getPushViemChain } from '../../src/lib/constants/chain'; import { CHAIN, PUSH_NETWORK } from '../../src/lib/constants/enums'; -import { v5 } from '../../src/lib/agentic/contracts/v5'; +import { v6 } from '../../src/lib/agentic/contracts/v6'; import { chainReaderFromPublicClient } from '../../src/lib/agentic/contracts/reader'; import { resolveWalletGeneration } from '../../src/lib/agentic/deployments'; import { Snapshot } from '../../src/lib/agentic/reads/snapshot'; import { readSvmRule } from '../../src/lib/agentic/reads/svm'; import { probeSvmWirePolicies } from '../shared/agw-svm-policy-probe'; -const d = process.env['AGW_SVM_WIRE_REPLAY_E2E'] === '1' ? describe : describe.skip; -const POSITIVE = '0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8' as Hex; -const REJECTED = '0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc' as Hex; -const EXTERNAL = 'kGUaPUfASg9Poo93aMsztHJjUk27MKuRJBfDZK1WP3FFSaXSYcoPcxjUMFyDxaK6aU6mQkZeowSu3MtvK5PXKgK'; +const d = + process.env['AGW_SVM_WIRE_REPLAY_E2E'] === '1' ? describe : describe.skip; +const POSITIVE = + '0x50a96ff863722ced3464e3e8e5e451621903396c9bc83fcc010756dc1aee73b8' as Hex; +const REJECTED = + '0x51e2227e833e8090844f151c2d5d959225d3ec24828bf11a1c6467e2a74410fc' as Hex; +const EXTERNAL = + 'kGUaPUfASg9Poo93aMsztHJjUk27MKuRJBfDZK1WP3FFSaXSYcoPcxjUMFyDxaK6aU6mQkZeowSu3MtvK5PXKgK'; d('agw svm recorded replay', () => { - const push = createPublicClient({ chain: getPushViemChain(CHAIN.PUSH_TESTNET_DONUT), transport: http(CHAIN_INFO[CHAIN.PUSH_TESTNET_DONUT].defaultRPC[0]) }); + const push = createPublicClient({ + chain: getPushViemChain(CHAIN.PUSH_TESTNET_DONUT), + transport: http(CHAIN_INFO[CHAIN.PUSH_TESTNET_DONUT].defaultRPC[0]), + }); let source: Awaited>; - let decoded: Extract>, { kind: 'executeAsAgent' }>; + let decoded: Extract< + NonNullable>, + { kind: 'executeAsAgent' } + >; let client: PushChain; beforeAll(async () => { source = await push.getTransaction({ hash: POSITIVE }); - const call = v5.decodeWalletCall(source.input); - if (!source.to || call?.kind !== 'executeAsAgent') throw new Error('Recorded fixture is not an AGW agent call'); + const call = v6.decodeWalletCall(source.input); + if (!source.to || call?.kind !== 'executeAsAgent') + throw new Error('Recorded fixture is not an AGW agent call'); decoded = call; - client = await PushChain.initialize({ chain: PushChain.CONSTANTS.CHAIN.PUSH_TESTNET_DONUT, address: source.from }, { network: PUSH_NETWORK.TESTNET_DONUT }); + client = await PushChain.initialize( + { + chain: PushChain.CONSTANTS.CHAIN.PUSH_TESTNET_DONUT, + address: source.from, + }, + { network: PUSH_NETWORK.TESTNET_DONUT } + ); expect(client.isReadMode).toBe(true); }); it('1. positive replay retains wallet, signer origin and actual Solana signature', async () => { const tx = await client.universal.trackTransaction(POSITIVE); expect(tx.from.toLowerCase()).toBe(source.to!.toLowerCase()); - expect(tx.origin.toLowerCase()).toBe(`eip155:42101:${source.from}`.toLowerCase()); - expect(tx.agentic?.rulesId).toBe(decoded.rulesId); expect(tx.route).toBe('UOA_TO_CEA'); + expect(tx.origin.toLowerCase()).toBe( + `eip155:42101:${source.from}`.toLowerCase() + ); + expect(tx.agentic?.rulesId).toBe(decoded.rulesId); + expect(tx.route).toBe('UOA_TO_CEA'); const receipt = await tx.wait({ outboundTimeoutMs: 30_000 }); - expect(receipt.status).toBe(1); expect(receipt.externalStatus).toBe('success'); expect(receipt.externalTxHash).toBe(EXTERNAL); + expect(receipt.status).toBe(1); + expect(receipt.externalStatus).toBe('success'); + expect(receipt.externalTxHash).toBe(EXTERNAL); }, 120_000); it('2. later terminal rejection is failed, while the source succeeded and spend remains charged', async () => { const tx = await client.universal.trackTransaction(REJECTED); const receipt = await tx.wait({ outboundTimeoutMs: 30_000 }); - expect(receipt.status).toBe(1); expect(receipt.externalStatus).toBe('failed'); - expect(receipt.externalError).toContain('tx not executed on destination chain'); + expect(receipt.status).toBe(1); + expect(receipt.externalStatus).toBe('failed'); + expect(receipt.externalError).toContain( + 'tx not executed on destination chain' + ); expect(tx.from.toLowerCase()).toBe(source.to!.toLowerCase()); // Historical snapshot after the actual refund block, immune to later owner changes. const reader = chainReaderFromPublicClient(push); - const gen = await resolveWalletGeneration(reader, PUSH_NETWORK.TESTNET_DONUT, source.to!); + const gen = await resolveWalletGeneration( + reader, + PUSH_NETWORK.TESTNET_DONUT, + source.to! + ); const snapshot = new Snapshot(reader, BigInt(23950160)); - const rule = await readSvmRule(snapshot, gen, source.to!, decoded.rulesId, 'eip155:42101'); + const rule = await readSvmRule( + snapshot, + gen, + source.to!, + decoded.rulesId, + 'eip155:42101' + ); expect(rule.config.assets[0].spent).toBe(BigInt(20_000)); }, 120_000); it('3. pinned live policy calls refuse account and data mutations without submitting', async () => { const receipt = await push.getTransactionReceipt({ hash: POSITIVE }); - const result = await probeSvmWirePolicies(push, { from: source.from, wallet: source.to!, rulesId: decoded.rulesId, call: decoded.calls[0], blockNumber: receipt.blockNumber }); - expect(result.transactionsSent).toBe(0); expect(result.observations.map((r) => r.decoded.name)).toEqual([ - 'PolicyCheckReverted(SvmAccountPinMismatch)', 'PolicyCheckReverted(SvmDataCeilingExceeded)', + const result = await probeSvmWirePolicies(push, { + from: source.from, + wallet: source.to!, + rulesId: decoded.rulesId, + call: decoded.calls[0], + blockNumber: receipt.blockNumber, + }); + expect(result.transactionsSent).toBe(0); + expect(result.observations.map((r) => r.decoded.name)).toEqual([ + 'PolicyCheckReverted(SvmAccountPinMismatch)', + 'PolicyCheckReverted(SvmDataCeilingExceeded)', ]); }); }); diff --git a/packages/core/__e2e__/agw/_manifest.ts b/packages/core/__e2e__/agw/_manifest.ts index d3dc1efc..fa3ac52a 100644 --- a/packages/core/__e2e__/agw/_manifest.ts +++ b/packages/core/__e2e__/agw/_manifest.ts @@ -1,6 +1,6 @@ /** * AGW deployment manifest for live E2E — READ-ONLY. Loaded from the JSON file - * optionally named by AGW_DEPLOYMENT_MANIFEST, otherwise the built-in Donut v5 + * optionally named by AGW_DEPLOYMENT_MANIFEST, otherwise the built-in Donut v6 * manifest. Code/wiring/version are verified before tests or preflight funding. * * Manifest shape: @@ -18,6 +18,7 @@ import { readFileSync } from 'node:fs'; import { getAddress, + getAbiItem, isAddress, type Address, type PublicClient, @@ -25,21 +26,21 @@ import { } from 'viem'; import { PUSH_NETWORK } from '../../src/lib/constants/enums'; import { AgenticCapability } from '../../src/lib/agentic/capabilities'; -import { V5_CAPABILITIES } from '../../src/lib/agentic/deployments'; -import { v5 } from '../../src/lib/agentic/contracts/v5'; +import { V6_CAPABILITIES } from '../../src/lib/agentic/deployments'; +import { v6 } from '../../src/lib/agentic/contracts/v6'; import { - DONUT_V5_ADDRESSES, - DONUT_V5_START_BLOCK, - V5_SOURCE_COMMIT, -} from '../../src/lib/agentic/contracts/donut-v5'; + DONUT_V6_ADDRESSES, + DONUT_V6_START_BLOCK, + V6_SOURCE_COMMIT, +} from '../../src/lib/agentic/contracts/donut-v6'; export const AGW_PREREQ_HINT = 'AGW live E2E needs checked v5 wiring, signer keys and testnet funding. ' + - 'The default is the checked Donut v5 manifest; custom manifests must match the v5 source.'; + 'The default is the checked Donut v6 manifest; custom manifests must match the v5 source.'; export interface AgwManifest { network: PUSH_NETWORK; - generation: 'v5'; + generation: 'v6'; sourceCommit: string; startBlock: bigint; accountId: string; @@ -67,12 +68,12 @@ export function loadAgwManifest( if (!path) return { network: PUSH_NETWORK.TESTNET_DONUT, - generation: 'v5', - sourceCommit: V5_SOURCE_COMMIT, - startBlock: DONUT_V5_START_BLOCK, + generation: 'v6', + sourceCommit: V6_SOURCE_COMMIT, + startBlock: DONUT_V6_START_BLOCK, accountId: 'push.agw.1.0.0', - addresses: DONUT_V5_ADDRESSES, - capabilities: V5_CAPABILITIES, + addresses: DONUT_V6_ADDRESSES, + capabilities: V6_CAPABILITIES, }; let raw: Record; try { @@ -85,14 +86,14 @@ export function loadAgwManifest( const network = raw['network'] as PUSH_NETWORK; if (!Object.values(PUSH_NETWORK).includes(network)) throw new AgwPrerequisiteError(`unknown network ${String(network)}`); - if (raw['generation'] !== v5.id) { + if (raw['generation'] !== v6.id) { throw new AgwPrerequisiteError( `generation ${String(raw['generation'])} has no SDK adapter` ); } - if (raw['sourceCommit'] !== V5_SOURCE_COMMIT) { + if (raw['sourceCommit'] !== V6_SOURCE_COMMIT) { throw new AgwPrerequisiteError( - 'sourceCommit must match the supported v5 source pin' + 'sourceCommit must match the supported v6 source pin' ); } const a = (raw['addresses'] ?? {}) as Record; @@ -111,15 +112,15 @@ export function loadAgwManifest( const caps = Array.isArray(raw['capabilities']) ? new Set( (raw['capabilities'] as string[]).map((c) => { - if (!V5_CAPABILITIES.has(c as AgenticCapability)) + if (!V6_CAPABILITIES.has(c as AgenticCapability)) throw new AgwPrerequisiteError(`unknown capability ${c}`); return c as AgenticCapability; }) ) - : V5_CAPABILITIES; + : V6_CAPABILITIES; return { network, - generation: 'v5', + generation: 'v6', sourceCommit: raw['sourceCommit'], startBlock: BigInt(String(raw['startBlock'] ?? '0')), accountId: String(raw['accountId'] ?? 'push.agw.1.0.0'), @@ -154,7 +155,7 @@ export async function verifyAgwManifest( const impl = getAddress( (await read( m.addresses.factory, - v5.abis.factory, + v6.abis.factory, 'walletImplementation' )) as string ); @@ -164,17 +165,21 @@ export async function verifyAgwManifest( ); } const implementationCode = await client.getCode({ address: impl }); - for (const signature of [ - 'label()', - 'setLabel(string)', - 'initializeAccount(string)', - ]) { + for (const signature of ['label()', 'setLabel(string)']) { if (!implementationCode?.includes(toFunctionSelector(signature).slice(2))) { throw new AgwPrerequisiteError( - `implementation is missing the v5 ${signature} selector` + `implementation is missing the v6 ${signature} selector` ); } } + const initialize = getAbiItem({ + abi: v6.abis.wallet, + name: 'initializeAccount', + }); + if (!implementationCode?.includes(toFunctionSelector(initialize).slice(2))) + throw new AgwPrerequisiteError( + 'wallet implementation lacks the v6 initial-rules initializer' + ); const wiring: [string, Address][] = [ ['SESSION_ENGINE', m.addresses.sessionEngine], ['RULES_POLICY', m.addresses.rulesPolicy], @@ -182,7 +187,7 @@ export async function verifyAgwManifest( ['UNIVERSAL_GATEWAY_PC', m.addresses.gateway], ]; for (const [fn, expected] of wiring) { - const got = getAddress((await read(impl, v5.abis.wallet, fn)) as string); + const got = getAddress((await read(impl, v6.abis.wallet, fn)) as string); if (got !== expected) throw new AgwPrerequisiteError( `implementation ${fn} is ${got}, manifest says ${expected}` @@ -190,14 +195,14 @@ export async function verifyAgwManifest( } const policyVersion = await read( m.addresses.rulesPolicy, - v5.abis.policy, + v6.abis.policy, 'version' ); if (policyVersion !== '3.1.0') throw new AgwPrerequisiteError( `unsupported URP version ${String(policyVersion)}` ); - const accountId = (await read(impl, v5.abis.wallet, 'accountId')) as string; + const accountId = (await read(impl, v6.abis.wallet, 'accountId')) as string; if (accountId !== m.accountId) throw new AgwPrerequisiteError(`implementation accountId is ${accountId}`); } diff --git a/packages/core/__e2e__/agw/create.spec.ts b/packages/core/__e2e__/agw/create.spec.ts index bd05db7c..f05d8b84 100644 --- a/packages/core/__e2e__/agw/create.spec.ts +++ b/packages/core/__e2e__/agw/create.spec.ts @@ -3,8 +3,8 @@ * verified AGW deployment manifest (see _manifest.ts); beforeAll throws when * it is missing so a selected run cannot pass vacuously. */ -import { getAddress, type Address } from 'viem'; -import { v5 } from '../../src/lib/agentic/contracts/v5'; +import { decodeFunctionData, getAddress, type Address, type Hex } from 'viem'; +import { v6 } from '../../src/lib/agentic/contracts/v6'; import { AGW_E2E_ENABLED, inSeconds, @@ -24,7 +24,7 @@ d('agw create', () => { expect(created.wallet).toBe(before.address); expect(created.index).toBe(before.index); expect(created.rulesIds).toEqual([]); - const factoryAbi = v5.abis.factory; + const factoryAbi = v6.abis.factory; const [ownerOf, indexOf, balance] = await Promise.all([ f.push.readContract({ address: f.manifest.addresses.factory, @@ -74,6 +74,14 @@ d('agw create', () => { ], }); expect(created.rulesIds).toHaveLength(1); + const raw = await f.push.getTransaction({ hash: created.tx.hash as Hex }); + expect(getAddress(raw.to as Address)).toBe( + getAddress(f.manifest.addresses.factory) + ); + const call = decodeFunctionData({ abi: v6.abis.factory, data: raw.input }); + expect(call.functionName).toBe('createWalletWithSig'); + expect(call.args[3]).toHaveLength(1); + expect(created.tx.transactionHashes ?? [created.tx.hash]).toHaveLength(1); const { rules } = await f.owner.agentic.wallet(created.wallet).rules.list(); expect(rules.map((r) => r.rulesId)).toEqual(created.rulesIds); expect(rules[0].agent).toBe(getAddress(f.agentAddress)); diff --git a/packages/core/__e2e__/agw/labels.spec.ts b/packages/core/__e2e__/agw/labels.spec.ts index a5ca52d4..b46d5095 100644 --- a/packages/core/__e2e__/agw/labels.spec.ts +++ b/packages/core/__e2e__/agw/labels.spec.ts @@ -15,7 +15,7 @@ import { readNativeCounters } from '@e2e/shared/agw-state'; import { privateKeyToAccount } from 'viem/accounts'; import { PushChain } from '../../src'; import { CHAIN } from '../../src/lib/constants/enums'; -import { v5, MODE_SINGLE } from '../../src/lib/agentic/contracts/v5'; +import { v6, MODE_SINGLE } from '../../src/lib/agentic/contracts/v6'; import { decodeAgenticRevert } from '../../src/lib/agentic/revert'; import { AGW_E2E_ENABLED, @@ -34,7 +34,7 @@ d('agw labels', () => { const count = (address: Address) => f.push.readContract({ address, - abi: v5.abis.wallet, + abi: v6.abis.wallet, functionName: 'checkpointCount', }); it('1. default and custom deployment labels are stored and listed', async () => { @@ -81,7 +81,7 @@ d('agw labels', () => { if (log.address.toLowerCase() !== made.wallet.toLowerCase()) return []; try { const ev = decodeEventLog({ - abi: v5.abis.wallet, + abi: v6.abis.wallet, data: log.data, topics: log.topics, }); @@ -127,7 +127,7 @@ d('agw labels', () => { await expect( f.push.simulateContract({ address: made.wallet, - abi: v5.abis.wallet, + abi: v6.abis.wallet, functionName: 'setLabel', args: [label], account: f.ownerAddress, @@ -166,7 +166,7 @@ d('agw labels', () => { await expect( f.push.simulateContract({ address: made.wallet, - abi: v5.abis.wallet, + abi: v6.abis.wallet, functionName: 'setLabel', args: ['attack'], account: f.agentAddress, @@ -175,15 +175,15 @@ d('agw labels', () => { const agentDoorError = await f.push .simulateContract({ address: made.wallet, - abi: v5.abis.wallet, + abi: v6.abis.wallet, functionName: 'executeAsAgent', args: [ made.rulesIds[0], MODE_SINGLE, - v5.packSingle({ + v6.packSingle({ target: made.wallet, value: BigInt(0), - data: v5.encodeSetLabel('attack'), + data: v6.encodeSetLabel('attack'), }), ], account: f.agentAddress, @@ -332,7 +332,7 @@ d('agw labels', () => { const checkpointsBefore = await count(made.wallet); const nonceBefore = await f.push.readContract({ address: made.wallet, - abi: v5.abis.wallet, + abi: v6.abis.wallet, functionName: 'grantNonce', }); const rename = await w.setLabel('active-after'); @@ -349,7 +349,7 @@ d('agw labels', () => { expect( await f.push.readContract({ address: made.wallet, - abi: v5.abis.wallet, + abi: v6.abis.wallet, functionName: 'grantNonce', }) ).toBe(nonceBefore); @@ -411,12 +411,12 @@ d('agw labels', () => { { to: made.wallet, value: BigInt(0), - data: v5.encodeSetLabel('temporary'), + data: v6.encodeSetLabel('temporary'), }, { to: made.wallet, value: BigInt(0), - data: v5.encodeSetLabel('a'.repeat(65)), + data: v6.encodeSetLabel('a'.repeat(65)), }, ]; await expect( @@ -434,7 +434,7 @@ d('agw labels', () => { chain: client.chain, to: made.wallet, gas: BigInt(400000), - data: v5.encodeExecute( + data: v6.encodeExecute( calls.map((call) => ({ target: call.to, value: call.value, diff --git a/packages/core/__e2e__/agw/lifecycle.spec.ts b/packages/core/__e2e__/agw/lifecycle.spec.ts index 77b3cc1b..f0d06521 100644 --- a/packages/core/__e2e__/agw/lifecycle.spec.ts +++ b/packages/core/__e2e__/agw/lifecycle.spec.ts @@ -5,7 +5,7 @@ import { readNativeCounters } from '@e2e/shared/agw-state'; * The stale-spend race (intervening agent spend) is verified against the * real contracts in the local harness; it cannot be timed reliably live. */ -import { v5 } from '../../src/lib/agentic/contracts/v5'; +import { v6 } from '../../src/lib/agentic/contracts/v6'; import { getAddress, parseEther, type Address, type Hex } from 'viem'; import { AGENTIC_ERROR_CODE } from '../../src/lib/agentic/errors'; import { @@ -34,7 +34,7 @@ d('agw lifecycle', () => { const count = () => f.push.readContract({ address: wallet, - abi: v5.abis.wallet, + abi: v6.abis.wallet, functionName: 'checkpointCount', }) as Promise; beforeAll(async () => { diff --git a/packages/core/__e2e__/agw/management-extended.spec.ts b/packages/core/__e2e__/agw/management-extended.spec.ts index 0a0b1210..014dac5b 100644 --- a/packages/core/__e2e__/agw/management-extended.spec.ts +++ b/packages/core/__e2e__/agw/management-extended.spec.ts @@ -1,7 +1,7 @@ import { PushChain } from '../../src'; import { getAddress, type Address } from 'viem'; import type { AgenticRuntime } from '../../src/lib/agentic/runtime'; -import { v5 } from '../../src/lib/agentic/contracts/v5'; +import { v6 } from '../../src/lib/agentic/contracts/v6'; import { setupAgw, inSeconds, type AgwFixture } from './_fixture'; import { readNativeCounters } from '../shared/agw-state'; const d = process.env['AGW_E2E'] === '1' ? describe : describe.skip; @@ -31,7 +31,7 @@ d('agw extended management', () => { const count = (wallet: Address) => f.push.readContract({ address: wallet, - abi: v5.abis.wallet, + abi: v6.abis.wallet, functionName: 'checkpointCount', }); it('1. prefunding a derived address survives deployment and info/list keep owner index and label', async () => { @@ -166,7 +166,7 @@ d('agw extended management', () => { const before = await count(made.wallet), grantNonce = await f.push.readContract({ address: made.wallet, - abi: v5.abis.wallet, + abi: v6.abis.wallet, functionName: 'grantNonce', }); rt.execute = async (params, opts) => { @@ -200,7 +200,7 @@ d('agw extended management', () => { expect( await f.push.readContract({ address: made.wallet, - abi: v5.abis.wallet, + abi: v6.abis.wallet, functionName: 'grantNonce', }) ).toBe(grantNonce); @@ -234,7 +234,7 @@ d('agw extended management', () => { | undefined, injected = false; rt.execute = async (params, opts) => { - if (!injected && Array.isArray(params.data)) { + if (!injected && params.to === f.manifest.addresses.factory) { injected = true; competing = await f.owner.agentic.create('e2e-race-winner', { rules: [], diff --git a/packages/core/__e2e__/agw/native-multi-action.spec.ts b/packages/core/__e2e__/agw/native-multi-action.spec.ts index d5624ebe..4c3e9af2 100644 --- a/packages/core/__e2e__/agw/native-multi-action.spec.ts +++ b/packages/core/__e2e__/agw/native-multi-action.spec.ts @@ -19,7 +19,7 @@ import { } from '../../src/lib/constants/chain'; import { getNativePRC20ForChain } from '../../src/lib/orchestrator/internals/helpers'; import type { AgenticRuntime } from '../../src/lib/agentic/runtime'; -import { v5 } from '../../src/lib/agentic/contracts/v5'; +import { v6 } from '../../src/lib/agentic/contracts/v6'; import { actionId } from '../../src/lib/agentic/codec/ids'; import { readNativeActionConfigs } from '@e2e/shared/agw-state'; import { @@ -145,13 +145,13 @@ d('agw native multi-action', () => { }), f.push.readContract({ address: s.wallet, - abi: v5.abis.wallet, + abi: v6.abis.wallet, functionName: 'checkpointCount', blockNumber, }), f.push.readContract({ address: s.wallet, - abi: v5.abis.wallet, + abi: v6.abis.wallet, functionName: 'grantNonce', blockNumber, }), @@ -240,7 +240,7 @@ d('agw native multi-action', () => { callsUsed: 1, }); expect(config(after, token, '0xa9059cbb')).toMatchObject({ - amountSpent: BigInt(2), + amountSpent: BigInt(0), callsUsed: 1, }); expect(after.checkpointCount).toBe(before.checkpointCount); @@ -268,7 +268,7 @@ d('agw native multi-action', () => { await refused( s, () => sendToken(s, BigInt(4)), - 'PolicyCheckReverted(NativeAmountExceedsCap)' + 'PolicyCheckReverted(ArgPinAboveMax)' ); await refused( s, @@ -306,7 +306,7 @@ d('agw native multi-action', () => { callsUsed: 3, }); expect(config(final, token, '0xa9059cbb')).toMatchObject({ - amountSpent: BigInt(6), + amountSpent: BigInt(0), callsUsed: 3, }); f.evidence('native-multi-independent-counters', { @@ -336,7 +336,7 @@ d('agw native multi-action', () => { }); expect(config(after, token, '0xa9059cbb')).toMatchObject({ callsUsed: 1, - amountSpent: BigInt(2), + amountSpent: BigInt(0), }); expect(after.checkpointCount).toBe(before.checkpointCount); const replay = await f.owner.universal.trackTransaction(tx.hash); @@ -367,7 +367,7 @@ d('agw native multi-action', () => { to: f.ownerAddress, data: calls(BigInt(4)), }), - 'PolicyCheckReverted(NativeAmountExceedsCap)' + 'PolicyCheckReverted(ArgPinAboveMax)' ); const executor = PUSH_BATCH_EXECUTOR_ADDRESS[CHAIN.PUSH_TESTNET_DONUT]; if (!executor) throw new Error('Missing verified native batch executor'); @@ -381,11 +381,11 @@ d('agw native multi-action', () => { chain: getPushViemChain(CHAIN.PUSH_TESTNET_DONUT), transport: http(CHAIN_INFO[CHAIN.PUSH_TESTNET_DONUT].defaultRPC[0]), }); - const data = v5.encodeExecute( + const data = v6.encodeExecute( calls(BigInt(4)).map((c) => ({ target: s.wallet, value: ZERO, - data: v5.encodeExecuteAsAgent(s.id, { + data: v6.encodeExecuteAsAgent(s.id, { target: c.to, value: c.value, data: c.data, @@ -434,7 +434,7 @@ d('agw native multi-action', () => { expect( await f.push.readContract({ address: s.wallet, - abi: v5.abis.wallet, + abi: v6.abis.wallet, functionName: 'checkpointCount', }) ).toBe(before.checkpointCount + BigInt(6)); @@ -518,7 +518,7 @@ d('agw native multi-action', () => { config(before, f.ownerAddress, '0xffffffff') ); expect(config(after, token, '0xa9059cbb')).toMatchObject({ - amountSpent: ONE, + amountSpent: ZERO, callsUsed: 1, }); expect(after.walletToken).toBe(before.walletToken - ONE); @@ -531,7 +531,7 @@ d('agw native multi-action', () => { expect( await f.push.readContract({ address: s.wallet, - abi: v5.abis.wallet, + abi: v6.abis.wallet, functionName: 'checkpointCount', }) ).toBe(before.checkpointCount + BigInt(6)); diff --git a/packages/core/__e2e__/agw/native-policy-extended.spec.ts b/packages/core/__e2e__/agw/native-policy-extended.spec.ts index c98c7435..0211b4f7 100644 --- a/packages/core/__e2e__/agw/native-policy-extended.spec.ts +++ b/packages/core/__e2e__/agw/native-policy-extended.spec.ts @@ -132,7 +132,7 @@ d('agw extended native policy', () => { expect(await s.tokenBalance()).toBe(BigInt(40)); expect(await s.counters()).toMatchObject({ valueSpent: BigInt(0), - amountSpent: BigInt(10), + amountSpent: BigInt(0), callsUsed: 1, }); expect( @@ -158,15 +158,15 @@ d('agw extended native policy', () => { }); it('3. per-call amount cap refuses cap plus one', async () => { const s = await fixture(); - await refused(s, () => s.send(BigInt(11)), 'NativeAmountExceedsCap'); + await refused(s, () => s.send(BigInt(11)), 'ArgPinAboveMax'); }); it('4. repeated per-call amounts accumulate spend without a removed lifetime cap', async () => { const s = await fixture(BigInt(50), 10); await (await s.send(BigInt(10))).wait(); await (await s.send(BigInt(5))).wait(); - expect((await s.counters()).amountSpent).toBe(BigInt(15)); + expect((await s.counters()).amountSpent).toBe(BigInt(0)); await (await s.send(BigInt(1))).wait(); - expect((await s.counters()).amountSpent).toBe(BigInt(16)); + expect((await s.counters()).amountSpent).toBe(BigInt(0)); }); it('5. repeated calls have no removed maxCalls limit', async () => { const s = await fixture(); @@ -178,7 +178,7 @@ d('agw extended native policy', () => { }); it('6. explicit zero MAX pin forbids positive amount but permits a metered zero call', async () => { const s = await fixture(BigInt(50), 10, BigInt(0)); - await refused(s, () => s.send(BigInt(1)), 'NativeAmountExceedsCap'); + await refused(s, () => s.send(BigInt(1)), 'ArgPinAboveMax'); await (await s.send(BigInt(0))).wait(); expect(await s.counters()).toMatchObject({ amountSpent: BigInt(0), @@ -234,7 +234,7 @@ d('agw extended native policy', () => { expect((await sent.wait()).status).toBe(1); expect(await s.counters()).toMatchObject({ valueSpent: BigInt(0), - amountSpent: BigInt(1), + amountSpent: BigInt(0), }); f.evidence('zero-pc-defaults', { wallet: s.wallet, txHash: sent.hash }); }); diff --git a/packages/core/__e2e__/agw/svm-public.spec.ts b/packages/core/__e2e__/agw/svm-public.spec.ts index a135ea64..d548b8fe 100644 --- a/packages/core/__e2e__/agw/svm-public.spec.ts +++ b/packages/core/__e2e__/agw/svm-public.spec.ts @@ -20,7 +20,7 @@ import { privateKeyToAccount } from 'viem/accounts'; import { CHAIN, PUSH_NETWORK } from '../../src/lib/constants/enums'; import { CHAIN_INFO, getPushViemChain } from '../../src/lib/constants/chain'; import counterIdl from '../../src/lib/orchestrator/svm-idl/__fixtures__/test_counter.idl.json'; -import { v5 } from '../../src/lib/agentic/contracts/v5'; +import { v6 } from '../../src/lib/agentic/contracts/v6'; import { setupAgw, evmClient, inSeconds, type AgwFixture } from './_fixture'; import { loadAgwManifest, verifyAgwManifest } from './_manifest'; import { @@ -148,22 +148,14 @@ d('agw public svm', () => { }), }) ).wait(); - const owner = await evmClient( - ownerKey, - CHAIN.PUSH_TESTNET_DONUT, - manifest.network, - wallet - ); - await ( - await owner.universal.sendTransaction({ - to: token, - data: encodeFunctionData({ - abi: erc20Abi, - functionName: 'approve', - args: [manifest.addresses.gateway, amount * BigInt(2)], - }), + expect( + await f.push.readContract({ + address: token, + abi: erc20Abi, + functionName: 'allowance', + args: [wallet, manifest.addresses.gateway], }) - ).wait(); + ).toBe(BigInt(0)); agent = await f.agent(wallet); f.evidence('public-svm-setup', { wallet, @@ -264,12 +256,12 @@ d('agw public svm', () => { f.push.getBalance({ address: wallet }), f.push.readContract({ address: wallet, - abi: v5.abis.wallet, + abi: v6.abis.wallet, functionName: 'checkpointCount', }), f.push.readContract({ address: f.manifest.addresses.rulesPolicy, - abi: v5.abis.policy, + abi: v6.abis.policy, functionName: 'getSvmConfig', args: [config, wallet], }), @@ -403,34 +395,14 @@ d('agw public svm', () => { expect(await f.push.getTransactionCount({ address: f.agentAddress })).toBe( agentNonce ); - // Both funded sends have consumed the bounded allowance. Funding only the - // token lets this case isolate the separate allowance guard. - await ( - await f.owner.universal.sendTransaction({ - to: token, - data: encodeFunctionData({ - abi: erc20Abi, - functionName: 'transfer', - args: [wallet, BigInt(1)], - }), - }) - ).wait(); - const sender = await evmClient( - process.env['PUSH_PRIVATE_KEY'] as Hex, - CHAIN.PUSH_TESTNET_DONUT, - f.manifest.network, - wallet - ); - const nonce = await f.push.getTransactionCount({ address: f.ownerAddress }); - await expect( - sender.universal.sendTransaction({ - to: { chain: SVM_WIRE_CHAIN, address: recipient.toBase58() }, - value: BigInt(1), - gasLimit: BigInt(0), + // The owner path no longer requires a standing gateway allowance in v6. + expect( + await f.push.readContract({ + address: token, + abi: erc20Abi, + functionName: 'allowance', + args: [wallet, f.manifest.addresses.gateway], }) - ).rejects.toMatchObject({ code: 'GATEWAY_ALLOWANCE_INSUFFICIENT' }); - expect(await f.push.getTransactionCount({ address: f.ownerAddress })).toBe( - nonce - ); + ).toBe(BigInt(0)); }); }); diff --git a/packages/core/__e2e__/agw/svm-spl-transfer.spec.ts b/packages/core/__e2e__/agw/svm-spl-transfer.spec.ts index e35a1110..cb66a938 100644 --- a/packages/core/__e2e__/agw/svm-spl-transfer.spec.ts +++ b/packages/core/__e2e__/agw/svm-spl-transfer.spec.ts @@ -6,7 +6,7 @@ import { encodeFunctionData, erc20Abi, parseEther, type Hex } from 'viem'; import { CHAIN, PUSH_NETWORK } from '../../src/lib/constants/enums'; import { MOVEABLE_TOKEN_CONSTANTS } from '../../src/lib/constants/tokens'; import { getPRC20Address } from '../../src/lib/universal/prc20-address'; -import { v5 } from '../../src/lib/agentic/contracts/v5'; +import { v6 } from '../../src/lib/agentic/contracts/v6'; import { AGW_E2E_ENABLED, evmClient, @@ -102,20 +102,18 @@ d('agw svm spl transfer', () => { f.manifest.network, made.wallet ); - await ( - await owner.universal.sendTransaction({ - to: token, - data: encodeFunctionData({ - abi: erc20Abi, - functionName: 'approve', - args: [f.manifest.addresses.gateway, amount], - }), + expect( + await f.push.readContract({ + address: token, + abi: erc20Abi, + functionName: 'allowance', + args: [made.wallet, f.manifest.addresses.gateway], }) - ).wait(); + ).toBe(BigInt(0)); const beforeRecipient = await recipientBalance(); const beforeCheckpoints = await f.push.readContract({ address: made.wallet, - abi: v5.abis.wallet, + abi: v6.abis.wallet, functionName: 'checkpointCount', }); const tx = await owner.universal.sendTransaction({ @@ -164,7 +162,7 @@ d('agw svm spl transfer', () => { expect( await f.push.readContract({ address: made.wallet, - abi: v5.abis.wallet, + abi: v6.abis.wallet, functionName: 'checkpointCount', }) ).toBe(beforeCheckpoints + BigInt(1)); diff --git a/packages/core/__e2e__/agw/universal-evm.spec.ts b/packages/core/__e2e__/agw/universal-evm.spec.ts index f69d6c18..b2d7fd78 100644 --- a/packages/core/__e2e__/agw/universal-evm.spec.ts +++ b/packages/core/__e2e__/agw/universal-evm.spec.ts @@ -21,12 +21,13 @@ import { type Hex, } from 'viem'; import { sepolia } from 'viem/chains'; +import type { Rule } from '../../src'; import { CHAIN } from '../../src/lib/constants/enums'; import { CHAIN_INFO } from '../../src/lib/constants/chain'; import { MOVEABLE_TOKEN_CONSTANTS } from '../../src/lib/constants/tokens'; import { getCEAAddress } from '../../src/lib/orchestrator/cea-utils'; import { getNativePRC20ForChain } from '../../src/lib/orchestrator/internals/helpers'; -import { v5 } from '../../src/lib/agentic/contracts/v5'; +import { v6 } from '../../src/lib/agentic/contracts/v6'; import { EVM_CHAIN_FIXTURES } from '@e2e/shared/chain-fixtures'; import { COUNTER_ABI } from '@e2e/shared/outbound-helpers'; import { verifyExternalTransaction } from '@e2e/shared/external-tx-verifier'; @@ -97,23 +98,14 @@ d('agw universal evm', () => { }), }) ).wait(); - // Bounded allowance through the owner door. - const ownerAgw = await evmClient( - process.env['PUSH_PRIVATE_KEY'] as Hex, - CHAIN.PUSH_TESTNET_DONUT, - f.manifest.network, - wallet - ); - await ( - await ownerAgw.universal.sendTransaction({ - to: token, - data: encodeFunctionData({ - abi: erc20Abi, - functionName: 'approve', - args: [f.manifest.addresses.gateway, AMOUNT * BigInt(2)], - }), + expect( + await f.push.readContract({ + address: token, + abi: erc20Abi, + functionName: 'allowance', + args: [wallet, f.manifest.addresses.gateway], }) - ).wait(); + ).toBe(BigInt(0)); }, 900_000); afterAll(() => f?.teardown()); @@ -202,7 +194,7 @@ d('agw universal evm', () => { functionName: 'allowance', args: [wallet, f.manifest.addresses.gateway], }) - ).toBe(AMOUNT); + ).toBe(BigInt(0)); expect( (await sep.readContract({ address: counter, @@ -241,4 +233,92 @@ d('agw universal evm', () => { externalStatus: receipt.externalStatus, }); }, 900_000); + it('3. v6 destination EQ/MAX alternatives authorize only the pinned spender and amount', async () => { + const target = MOVEABLE_TOKEN_CONSTANTS.ETHEREUM_SEPOLIA.USDC + .address as Address; + const handle = f.owner.agentic.wallet(wallet); + const record = await handle.rules.get(rulesId); + const updated = await handle.rules.update({ + rules: [ + { + rulesId, + rule: { + ...record.rule, + allowedCalls: [f.ownerAddress, f.agentAddress].map((spender) => ({ + target, + selector: 'approve(address,uint256)', + pins: [ + { arg: 0, expected: spender }, + { arg: 1, max: BigInt(1) }, + ], + })), + } as Rule, + }, + ], + }); + rulesId = updated.rules[0].rulesId; + const agent = await f.agent(wallet); + const send = (spender: Address, amount: bigint) => + agent.universal.sendTransaction({ + to: { address: target, chain: SEPOLIA }, + data: [ + { + to: target, + value: BigInt(0), + data: encodeFunctionData({ + abi: erc20Abi, + functionName: 'approve', + args: [spender, amount], + }), + }, + ], + }); + const nonce = await f.push.getTransactionCount({ address: f.agentAddress }); + await expect( + send('0x000000000000000000000000000000000000dEaD', BigInt(1)) + ).rejects.toMatchObject({ + decodedError: { name: 'PolicyCheckReverted(ArgPinMismatch)' }, + }); + await expect(send(f.ownerAddress, BigInt(2))).rejects.toMatchObject({ + decodedError: { name: 'PolicyCheckReverted(ArgPinAboveMax)' }, + }); + expect(await f.push.getTransactionCount({ address: f.agentAddress })).toBe( + nonce + ); + // Use the SECOND alternative and a zero approval: no persistent spending authority is granted. + const tx = await send(f.agentAddress, BigInt(0)); + const receipt = await tx.wait({ outboundTimeoutMs: 600_000 }); + expect(receipt.externalStatus).toMatch(/success/i); + if (!receipt.externalTxHash) throw Error('missing destination receipt'); + const sep = createPublicClient({ + chain: sepolia, + transport: fallback( + CHAIN_INFO[SEPOLIA].defaultRPC.map((url) => http(url)) + ), + }); + const external = await sep.getTransactionReceipt({ + hash: receipt.externalTxHash as Hex, + }); + const events = parseEventLogs({ + abi: erc20Abi, + eventName: 'Approval', + logs: external.logs, + }); + expect( + events.some( + (e) => + e.address.toLowerCase() === target.toLowerCase() && + e.args.owner.toLowerCase() === cea.toLowerCase() && + e.args.spender.toLowerCase() === f.agentAddress.toLowerCase() && + e.args.value === BigInt(0) + ) + ).toBe(true); + f.evidence('v6-destination-pins', { + wallet, + cea, + rulesId, + pushTx: tx.hash, + destinationTx: receipt.externalTxHash, + }); + }, 900_000); }); diff --git a/packages/core/__e2e__/agw/v5-multiasset.spec.ts b/packages/core/__e2e__/agw/v5-multiasset.spec.ts index 25bb4828..10ec0f97 100644 --- a/packages/core/__e2e__/agw/v5-multiasset.spec.ts +++ b/packages/core/__e2e__/agw/v5-multiasset.spec.ts @@ -19,7 +19,7 @@ import { getCEAAddress } from '../../src/lib/orchestrator/cea-utils'; import { configId } from '../../src/lib/agentic/codec/ids'; import { CHAIN } from '../../src/lib/constants/enums'; import { MOVEABLE_TOKEN_CONSTANTS } from '../../src/lib/constants/tokens'; -import { v5 } from '../../src/lib/agentic/contracts/v5'; +import { v6 } from '../../src/lib/agentic/contracts/v6'; import { EVM_CHAIN_FIXTURES } from '@e2e/shared/chain-fixtures'; import { verifyExternalTransaction } from '@e2e/shared/external-tx-verifier'; import { @@ -83,7 +83,7 @@ d('agw v5 multi-asset', () => { }); const count = await f.push.readContract({ address: created.wallet, - abi: v5.abis.wallet, + abi: v6.abis.wallet, functionName: 'checkpointCount', }); const replacement = await w.rules.update({ @@ -92,7 +92,7 @@ d('agw v5 multi-asset', () => { expect( await f.push.readContract({ address: created.wallet, - abi: v5.abis.wallet, + abi: v6.abis.wallet, functionName: 'checkpointCount', }) ).toBe(count + BigInt(5)); @@ -138,14 +138,14 @@ d('agw v5 multi-asset', () => { await verifyExternalTransaction(receipt.externalTxHash as string, chain); const [action] = await f.push.readContract({ address: f.manifest.addresses.sessionEngine, - abi: v5.abis.engine, + abi: v6.abis.engine, functionName: 'getEnabledActions', args: [created.wallet, created.rulesIds[0]], }); const { configId } = await import('../../src/lib/agentic/codec/ids'); const cfg = await f.push.readContract({ address: f.manifest.addresses.rulesPolicy, - abi: v5.abis.policy, + abi: v6.abis.policy, functionName: 'getConfig', args: [ configId(created.wallet, created.rulesIds[0], action), @@ -230,7 +230,7 @@ d('agw v5 multi-asset', () => { const agent = await f.agent(made.wallet); const [action] = await f.push.readContract({ address: f.manifest.addresses.sessionEngine, - abi: v5.abis.engine, + abi: v6.abis.engine, functionName: 'getEnabledActions', args: [made.wallet, made.rulesIds[0]], }); @@ -239,7 +239,7 @@ d('agw v5 multi-asset', () => { ( await f.push.readContract({ address: f.manifest.addresses.rulesPolicy, - abi: v5.abis.policy, + abi: v6.abis.policy, functionName: 'getConfig', args: [key, made.wallet], }) @@ -321,7 +321,7 @@ d('agw v5 multi-asset', () => { functionName: 'allowance', args: [made.wallet, f.manifest.addresses.gateway], }) - ).toBe(BigInt(1)); + ).toBe(BigInt(0)); const expected = i === 0 ? [amounts[0], BigInt(0)] : amounts; expect(await spent()).toEqual(expected); const nonce = await f.push.getTransactionCount({ diff --git a/packages/core/__e2e__/ci/suite.ts b/packages/core/__e2e__/ci/suite.ts index 9e08598e..8ad742d2 100644 --- a/packages/core/__e2e__/ci/suite.ts +++ b/packages/core/__e2e__/ci/suite.ts @@ -984,6 +984,14 @@ export const SCENARIOS: Scenario[] = [ needs: { masterPC: '0.5' }, env: { AGW_E2E: '1' }, }, + { + id: 'agw-v6-destination-pins', + group: 'agw', + file: '__e2e__/agw/universal-evm.spec.ts', + grep: 'agw universal evm 3\\. v6 destination', + needs: { masterPC: '25' }, + env: { AGW_E2E: '1' }, + }, { id: 'agw-universal-outbound', group: 'agw', diff --git a/packages/core/__e2e__/shared/agw-state.ts b/packages/core/__e2e__/shared/agw-state.ts index 09d83443..32753cff 100644 --- a/packages/core/__e2e__/shared/agw-state.ts +++ b/packages/core/__e2e__/shared/agw-state.ts @@ -1,6 +1,6 @@ /** Independent contract-state assertions for AGW tests; never part of the public SDK. */ import type { Address, Hex, PublicClient } from 'viem'; -import { v5 } from '../../src/lib/agentic/contracts/v5'; +import { v6 } from '../../src/lib/agentic/contracts/v6'; import { configId } from '../../src/lib/agentic/codec/ids'; export async function readNativeCounters( @@ -11,7 +11,7 @@ export async function readNativeCounters( ) { const actions = await client.readContract({ address: addresses.sessionEngine, - abi: v5.abis.engine, + abi: v6.abis.engine, functionName: 'getEnabledActions', args: [wallet, rulesId], }); @@ -19,7 +19,7 @@ export async function readNativeCounters( throw new Error('Native counter fixture expects one action'); const cfg = await client.readContract({ address: addresses.rulesPolicy, - abi: v5.abis.policy, + abi: v6.abis.policy, functionName: 'getNativeConfig', args: [configId(wallet, rulesId, actions[0]), wallet], }); @@ -41,7 +41,7 @@ export async function readNativeActionConfigs( const block = blockNumber ?? (await client.getBlockNumber({ cacheTime: 0 })); const actions = await client.readContract({ address: addresses.sessionEngine, - abi: v5.abis.engine, + abi: v6.abis.engine, functionName: 'getEnabledActions', args: [wallet, rulesId], blockNumber: block, @@ -52,7 +52,7 @@ export async function readNativeActionConfigs( actionId: action, config: await client.readContract({ address: addresses.rulesPolicy, - abi: v5.abis.policy, + abi: v6.abis.policy, functionName: 'getNativeConfig', args: [configId(wallet, rulesId, action), wallet], blockNumber: block, diff --git a/packages/core/__e2e__/shared/agw-svm-policy-probe.ts b/packages/core/__e2e__/shared/agw-svm-policy-probe.ts index 8b5b0d6c..51461174 100644 --- a/packages/core/__e2e__/shared/agw-svm-policy-probe.ts +++ b/packages/core/__e2e__/shared/agw-svm-policy-probe.ts @@ -1,15 +1,35 @@ /** Bypass SDK validation to verify the deployed URP refuses the same mutations. eth_call only. */ -import { decodeFunctionData, encodeFunctionData, type Address, type Hex, type PublicClient } from 'viem'; +import { + decodeFunctionData, + encodeFunctionData, + type Address, + type Hex, + type PublicClient, +} from 'viem'; import { UNIVERSAL_GATEWAY_PC } from '../../src/lib/constants/abi'; -import { v5, type Call } from '../../src/lib/agentic/contracts/v5'; -import { parseAgwSvmPayload, encodeAgwSvmPayload } from '../../src/lib/agentic/execution/svm-payload'; +import { v6, type Call } from '../../src/lib/agentic/contracts/v6'; +import { + parseAgwSvmPayload, + encodeAgwSvmPayload, +} from '../../src/lib/agentic/execution/svm-payload'; import { decodeAgenticRevert } from '../../src/lib/agentic/revert'; -export async function probeSvmWirePolicies(push: PublicClient, input: { - from: Address; wallet: Address; rulesId: Hex; call: Call; blockNumber: bigint; -}) { - const decodedCall = decodeFunctionData({ abi: UNIVERSAL_GATEWAY_PC, data: input.call.data }); - if (decodedCall.functionName !== 'sendUniversalTxOutbound') throw new Error('Expected a gateway outbound request'); +export async function probeSvmWirePolicies( + push: PublicClient, + input: { + from: Address; + wallet: Address; + rulesId: Hex; + call: Call; + blockNumber: bigint; + } +) { + const decodedCall = decodeFunctionData({ + abi: UNIVERSAL_GATEWAY_PC, + data: input.call.data, + }); + if (decodedCall.functionName !== 'sendUniversalTxOutbound') + throw new Error('Expected a gateway outbound request'); const request = decodedCall.args[0]; const parsed = parseAgwSvmPayload(request.payload); const observations = []; @@ -21,14 +41,41 @@ export async function probeSvmWirePolicies(push: PublicClient, input: { const view = new DataView(data.buffer, data.byteOffset, data.byteLength); view.setBigUint64(8, view.getBigUint64(8, true) + BigInt(1), true); } - const altered = { ...request, payload: encodeAgwSvmPayload(parsed.program, accounts, data) }; - const packet = v5.encodeExecuteAsAgent(input.rulesId, { ...input.call, - data: encodeFunctionData({ abi: UNIVERSAL_GATEWAY_PC, functionName: 'sendUniversalTxOutbound', args: [altered] }) }); + const altered = { + ...request, + payload: encodeAgwSvmPayload(parsed.program, accounts, data), + }; + const packet = v6.encodeExecuteAsAgent(input.rulesId, { + ...input.call, + data: encodeFunctionData({ + abi: UNIVERSAL_GATEWAY_PC, + functionName: 'sendUniversalTxOutbound', + args: [altered], + }), + }); let decoded; - try { await push.call({ account: input.from, to: input.wallet, data: packet, blockNumber: input.blockNumber }); } - catch (error) { decoded = decodeAgenticRevert(error); } - if (!decoded?.name?.includes('Svm')) throw new Error(`Expected a decoded SVM policy refusal for ${kind}, got ${decoded?.name ?? 'no decoded refusal'}`); + try { + await push.call({ + account: input.from, + to: input.wallet, + data: packet, + blockNumber: input.blockNumber, + }); + } catch (error) { + decoded = decodeAgenticRevert(error); + } + if (!decoded?.name?.includes('Svm')) + throw new Error( + `Expected a decoded SVM policy refusal for ${kind}, got ${ + decoded?.name ?? 'no decoded refusal' + }` + ); observations.push({ kind, reverted: true, decoded }); } - return { chainId: 42101, block: input.blockNumber.toString(), observations, transactionsSent: 0 }; + return { + chainId: 42101, + block: input.blockNumber.toString(), + observations, + transactionsSent: 0, + }; } diff --git a/packages/core/scripts/agw-local/abis/factory.json b/packages/core/scripts/agw-local/abis/factory.json index 30435540..483490b2 100644 --- a/packages/core/scripts/agw-local/abis/factory.json +++ b/packages/core/scripts/agw-local/abis/factory.json @@ -96,6 +96,364 @@ "outputs": [], "stateMutability": "nonpayable" }, + { + "type": "function", + "name": "createWallet", + "inputs": [ + { + "name": "label", + "type": "string", + "internalType": "string" + }, + { + "name": "rules", + "type": "tuple[]", + "internalType": "struct Session[]", + "components": [ + { + "name": "sessionValidator", + "type": "address", + "internalType": "contract ISessionValidator" + }, + { + "name": "sessionValidatorInitData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "erc7739Policies", + "type": "tuple", + "internalType": "struct ERC7739Data", + "components": [ + { + "name": "allowedERC7739Content", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNames", + "type": "string[]", + "internalType": "string[]" + } + ] + }, + { + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "actions", + "type": "tuple[]", + "internalType": "struct ActionData[]", + "components": [ + { + "name": "actionTargetSelector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "actionTarget", + "type": "address", + "internalType": "address" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "permitERC4337Paymaster", + "type": "bool", + "internalType": "bool" + } + ] + } + ], + "outputs": [ + { + "name": "wallet", + "type": "address", + "internalType": "address" + }, + { + "name": "rulesIds", + "type": "bytes32[]", + "internalType": "bytes32[]" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "createWalletWithSig", + "inputs": [ + { + "name": "intent", + "type": "tuple", + "internalType": "struct OwnerIntent", + "components": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "wallet", + "type": "address", + "internalType": "address" + }, + { + "name": "executor", + "type": "address", + "internalType": "address" + }, + { + "name": "index", + "type": "uint96", + "internalType": "uint96" + }, + { + "name": "sessionHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "mode", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "execCalldataHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "nonceKey", + "type": "uint192", + "internalType": "uint192" + }, + { + "name": "nonceSeq", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "grantNonce", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "deadline", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "signerChainId", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "sig", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "label", + "type": "string", + "internalType": "string" + }, + { + "name": "rules", + "type": "tuple[]", + "internalType": "struct Session[]", + "components": [ + { + "name": "sessionValidator", + "type": "address", + "internalType": "contract ISessionValidator" + }, + { + "name": "sessionValidatorInitData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "erc7739Policies", + "type": "tuple", + "internalType": "struct ERC7739Data", + "components": [ + { + "name": "allowedERC7739Content", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNames", + "type": "string[]", + "internalType": "string[]" + } + ] + }, + { + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "actions", + "type": "tuple[]", + "internalType": "struct ActionData[]", + "components": [ + { + "name": "actionTargetSelector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "actionTarget", + "type": "address", + "internalType": "address" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "permitERC4337Paymaster", + "type": "bool", + "internalType": "bool" + } + ] + } + ], + "outputs": [ + { + "name": "wallet", + "type": "address", + "internalType": "address" + }, + { + "name": "rulesIds", + "type": "bytes32[]", + "internalType": "bytes32[]" + } + ], + "stateMutability": "nonpayable" + }, { "type": "function", "name": "defaultAdmin", @@ -1012,6 +1370,28 @@ } ] }, + { + "type": "error", + "name": "IntentGrantNonceNotZero", + "inputs": [ + { + "name": "provided", + "type": "uint64", + "internalType": "uint64" + } + ] + }, + { + "type": "error", + "name": "IntentRulesMismatch", + "inputs": [ + { + "name": "actual", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, { "type": "error", "name": "IntentWalletMismatch", @@ -1081,6 +1461,17 @@ } ] }, + { + "type": "error", + "name": "TooManyInitialRules", + "inputs": [ + { + "name": "count", + "type": "uint256", + "internalType": "uint256" + } + ] + }, { "type": "error", "name": "UUPSUnauthorizedCallContext", diff --git a/packages/core/scripts/agw-local/abis/manifest.json b/packages/core/scripts/agw-local/abis/manifest.json index 7c13c7e0..206d25bd 100644 --- a/packages/core/scripts/agw-local/abis/manifest.json +++ b/packages/core/scripts/agw-local/abis/manifest.json @@ -1,12 +1,13 @@ { "sourceRepository": "https://github.com/pushchain/push-agentic-wallets", - "sourceCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", - "deployedAbiEvidence": "Donut v5 source compiled in an isolated tree; deployment wiring checked at block 23991912; URP/engine/validator reused from v4", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "deployedAbiEvidence": "v6 isolated source compilation; initial live code sizes/wiring checked at block 24244801", "files": { - "wallet.json": "6a145964d6c43eaa6223dc8f3d59a540ac0c2f447f25c3a99007eea25de9c695", - "factory.json": "b65f66a1556d2a9ddf9aabe9f595c685c2aada436772892f5a40fb1eec846397", - "policy.json": "c7e3cd5c7f8e47be217c77ebebde4c090903cea7db63024838e434eb6f1fd77b", + "wallet.json": "76705e5a25b10d3a84f867f983c3e4f5adfc881fb0d65710fb8684df2ea7abd3", + "factory.json": "08588f8870335492c5abeee32eec6a9bb050f81e234fdd58bbf389c6e9074a12", + "policy.json": "a07661d19b19656afdea560275d45669a908cd96646817884295e0017560f299", "engine.json": "6e5d9cea4dbed01f06af913c1e093743b86b7432195f4a4bf90fb94b282c51b2", "validator.json": "a4570ddc373241580de8742cbb3d9f2c837094c65bfd1cdd52243ca0c38196fd" - } + }, + "note": "Policy ABI includes linked SvmRulebook errors for revert decoding; callable ABI is unchanged." } diff --git a/packages/core/scripts/agw-local/abis/policy.json b/packages/core/scripts/agw-local/abis/policy.json index 88e39505..65270f95 100644 --- a/packages/core/scripts/agw-local/abis/policy.json +++ b/packages/core/scripts/agw-local/abis/policy.json @@ -281,6 +281,28 @@ "name": "maxValue", "type": "uint256", "internalType": "uint256" + }, + { + "name": "pins", + "type": "tuple[]", + "internalType": "struct ArgPin[]", + "components": [ + { + "name": "offset", + "type": "uint16", + "internalType": "uint16" + }, + { + "name": "op", + "type": "uint8", + "internalType": "enum PinOp" + }, + { + "name": "value", + "type": "bytes32", + "internalType": "bytes32" + } + ] } ] } @@ -444,7 +466,12 @@ "internalType": "uint16" }, { - "name": "expected", + "name": "op", + "type": "uint8", + "internalType": "enum PinOp" + }, + { + "name": "value", "type": "bytes32", "internalType": "bytes32" } @@ -981,15 +1008,15 @@ }, { "type": "error", - "name": "AmbiguousRule", + "name": "AmountExceedsCap", "inputs": [ { - "name": "i", + "name": "amount", "type": "uint256", "internalType": "uint256" }, { - "name": "j", + "name": "cap", "type": "uint256", "internalType": "uint256" } @@ -997,26 +1024,20 @@ }, { "type": "error", - "name": "AmountExceedsCap", + "name": "ArgPinAboveMax", "inputs": [ { - "name": "amount", + "name": "actual", "type": "uint256", "internalType": "uint256" }, { - "name": "cap", + "name": "index", "type": "uint256", "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "AmountExceedsU64", - "inputs": [ + }, { - "name": "amount", + "name": "max", "type": "uint256", "internalType": "uint256" } @@ -1097,22 +1118,6 @@ } ] }, - { - "type": "error", - "name": "BeneficiaryMismatch", - "inputs": [ - { - "name": "expected", - "type": "address", - "internalType": "address" - }, - { - "name": "actual", - "type": "address", - "internalType": "address" - } - ] - }, { "type": "error", "name": "CallLimitReached", @@ -1204,27 +1209,6 @@ } ] }, - { - "type": "error", - "name": "CeaAccountAtUnpinnedIndex", - "inputs": [ - { - "name": "accountIndex", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "account", - "type": "bytes32", - "internalType": "bytes32" - } - ] - }, - { - "type": "error", - "name": "CeaAccountsMissExpectedCEA", - "inputs": [] - }, { "type": "error", "name": "ChainMismatch", @@ -1241,22 +1225,6 @@ } ] }, - { - "type": "error", - "name": "DiscriminatorLenOutOfRange", - "inputs": [ - { - "name": "rule", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "len", - "type": "uint8", - "internalType": "uint8" - } - ] - }, { "type": "error", "name": "DuplicateAsset", @@ -1268,22 +1236,6 @@ } ] }, - { - "type": "error", - "name": "DuplicateSvmPin", - "inputs": [ - { - "name": "first", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "second", - "type": "uint256", - "internalType": "uint256" - } - ] - }, { "type": "error", "name": "EmptyChain", @@ -1300,54 +1252,6 @@ } ] }, - { - "type": "error", - "name": "ForbiddenProgramInAllowList", - "inputs": [ - { - "name": "rule", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "program", - "type": "bytes32", - "internalType": "bytes32" - } - ] - }, - { - "type": "error", - "name": "ForbiddenTargetProgram", - "inputs": [ - { - "name": "program", - "type": "bytes32", - "internalType": "bytes32" - } - ] - }, - { - "type": "error", - "name": "InnerValueExceedsAllowance", - "inputs": [ - { - "name": "index", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "value", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "maxValue", - "type": "uint256", - "internalType": "uint256" - } - ] - }, { "type": "error", "name": "InvalidAsset", @@ -1359,17 +1263,6 @@ } ] }, - { - "type": "error", - "name": "InvalidCeaAccount", - "inputs": [ - { - "name": "index", - "type": "uint256", - "internalType": "uint256" - } - ] - }, { "type": "error", "name": "InvalidConfigField", @@ -1418,11 +1311,6 @@ } ] }, - { - "type": "error", - "name": "InvalidSvmConfigField", - "inputs": [] - }, { "type": "error", "name": "InvalidTarget", @@ -1450,17 +1338,6 @@ } ] }, - { - "type": "error", - "name": "MalformedSvmPayload", - "inputs": [ - { - "name": "code", - "type": "uint8", - "internalType": "uint8" - } - ] - }, { "type": "error", "name": "NativeAmountExceedsCap", @@ -1556,76 +1433,11 @@ } ] }, - { - "type": "error", - "name": "ProgramListOutOfRange", - "inputs": [ - { - "name": "length", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "ProgramNotAllowed", - "inputs": [ - { - "name": "program", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "discriminator", - "type": "bytes8", - "internalType": "bytes8" - } - ] - }, { "type": "error", "name": "RecipientMustBeEmpty", "inputs": [] }, - { - "type": "error", - "name": "RecipientNotPubkey", - "inputs": [ - { - "name": "length", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "RecipientTargetMismatch", - "inputs": [ - { - "name": "recipient", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "target", - "type": "bytes32", - "internalType": "bytes32" - } - ] - }, - { - "type": "error", - "name": "RuleWithoutPin", - "inputs": [ - { - "name": "rule", - "type": "uint256", - "internalType": "uint256" - } - ] - }, { "type": "error", "name": "RulesExpired", @@ -1687,73 +1499,85 @@ }, { "type": "error", - "name": "SvmAccountCountBelowPin", + "name": "TargetMismatch", "inputs": [ { - "name": "pin", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "count", - "type": "uint256", - "internalType": "uint256" + "name": "actual", + "type": "address", + "internalType": "address" }, { - "name": "needed", - "type": "uint8", - "internalType": "uint8" + "name": "expected", + "type": "address", + "internalType": "address" } ] }, { "type": "error", - "name": "SvmAccountCountMismatch", + "name": "TooManyAllowedCallPins", "inputs": [ { - "name": "count", + "name": "total", "type": "uint256", "internalType": "uint256" - }, - { - "name": "expected", - "type": "uint8", - "internalType": "uint8" } ] }, { "type": "error", - "name": "SvmAccountPinMismatch", + "name": "TooManyPins", "inputs": [ { - "name": "pin", + "name": "count", "type": "uint256", "internalType": "uint256" - }, + } + ] + }, + { + "type": "error", + "name": "TotalNativeAmountExceeded", + "inputs": [ { - "name": "accountIndex", - "type": "uint8", - "internalType": "uint8" + "name": "newSpent", + "type": "uint256", + "internalType": "uint256" }, { - "name": "expected", - "type": "bytes32", - "internalType": "bytes32" + "name": "cap", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "TotalSpendCapExceeded", + "inputs": [ + { + "name": "wouldBeTotal", + "type": "uint256", + "internalType": "uint256" }, { - "name": "actual", - "type": "bytes32", - "internalType": "bytes32" + "name": "cap", + "type": "uint256", + "internalType": "uint256" } ] }, { "type": "error", - "name": "SvmAccountsOutOfRange", + "name": "TotalValueExceeded", "inputs": [ { - "name": "count", + "name": "newSpent", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "cap", "type": "uint256", "internalType": "uint256" } @@ -1761,20 +1585,42 @@ }, { "type": "error", - "name": "SvmDataCeilingExceeded", + "name": "UncappedGasSwapRejected", + "inputs": [] + }, + { + "type": "error", + "name": "UnsupportedEnvelopeVersion", "inputs": [ { - "name": "pin", + "name": "version", "type": "uint256", "internalType": "uint256" - }, + } + ] + }, + { + "type": "error", + "name": "UnsupportedNamespace", + "inputs": [ { - "name": "actual", + "name": "chainHash", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "ValueExceedsCap", + "inputs": [ + { + "name": "value", "type": "uint256", "internalType": "uint256" }, { - "name": "ceiling", + "name": "cap", "type": "uint256", "internalType": "uint256" } @@ -1782,20 +1628,68 @@ }, { "type": "error", - "name": "SvmDataFloorNotMet", + "name": "ValueOnlyCalldataNotEmpty", "inputs": [ { - "name": "pin", + "name": "length", "type": "uint256", "internalType": "uint256" - }, + } + ] + }, + { + "type": "error", + "name": "ValueOnlyWithAmountRule", + "inputs": [] + }, + { + "type": "error", + "name": "ValueOnlyWithPins", + "inputs": [] + }, + { + "type": "error", + "name": "WrongModeForCall", + "inputs": [ + { + "name": "actual", + "type": "uint8", + "internalType": "enum RulesType" + } + ] + }, + { + "type": "error", + "name": "WrongVmForCall", + "inputs": [ { "name": "actual", + "type": "uint8", + "internalType": "enum VmFamily" + } + ] + }, + { + "type": "error", + "name": "ZeroAddress", + "inputs": [] + }, + { + "type": "error", + "name": "ZeroMaxCalls", + "inputs": [] + }, + { + "type": "error", + "name": "AmbiguousRule", + "inputs": [ + { + "name": "i", "type": "uint256", "internalType": "uint256" }, { - "name": "floor", + "name": "j", "type": "uint256", "internalType": "uint256" } @@ -1803,10 +1697,10 @@ }, { "type": "error", - "name": "SvmDataPinInvalid", + "name": "AmountExceedsU64", "inputs": [ { - "name": "pin", + "name": "amount", "type": "uint256", "internalType": "uint256" } @@ -1814,20 +1708,15 @@ }, { "type": "error", - "name": "SvmDataPinMismatch", + "name": "CeaAccountAtUnpinnedIndex", "inputs": [ { - "name": "pin", + "name": "accountIndex", "type": "uint256", "internalType": "uint256" }, { - "name": "expected", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "actual", + "name": "account", "type": "bytes32", "internalType": "bytes32" } @@ -1835,46 +1724,74 @@ }, { "type": "error", - "name": "SvmDataRatioNotMet", + "name": "CeaAccountsMissExpectedCEA", + "inputs": [] + }, + { + "type": "error", + "name": "DiscriminatorLenOutOfRange", "inputs": [ { - "name": "pin", + "name": "rule", "type": "uint256", "internalType": "uint256" }, { - "name": "a", + "name": "len", + "type": "uint8", + "internalType": "uint8" + } + ] + }, + { + "type": "error", + "name": "DuplicateSvmPin", + "inputs": [ + { + "name": "first", "type": "uint256", "internalType": "uint256" }, { - "name": "b", + "name": "second", "type": "uint256", "internalType": "uint256" - }, - { - "name": "num", - "type": "uint64", - "internalType": "uint64" - }, - { - "name": "den", - "type": "uint64", - "internalType": "uint64" } ] }, { "type": "error", - "name": "SvmDataTooShortForPin", + "name": "ForbiddenProgramInAllowList", "inputs": [ { - "name": "pin", + "name": "rule", "type": "uint256", "internalType": "uint256" }, { - "name": "ixLen", + "name": "program", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "ForbiddenTargetProgram", + "inputs": [ + { + "name": "program", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "InvalidCeaAccount", + "inputs": [ + { + "name": "index", "type": "uint256", "internalType": "uint256" } @@ -1882,10 +1799,15 @@ }, { "type": "error", - "name": "SvmInstructionNotExecute", + "name": "InvalidSvmConfigField", + "inputs": [] + }, + { + "type": "error", + "name": "MalformedSvmPayload", "inputs": [ { - "name": "instructionId", + "name": "code", "type": "uint8", "internalType": "uint8" } @@ -1893,7 +1815,7 @@ }, { "type": "error", - "name": "SvmIxDataTooLong", + "name": "ProgramListOutOfRange", "inputs": [ { "name": "length", @@ -1904,28 +1826,61 @@ }, { "type": "error", - "name": "SvmMaxAccountsOutOfRange", + "name": "ProgramNotAllowed", "inputs": [ { - "name": "rule", + "name": "program", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "discriminator", + "type": "bytes8", + "internalType": "bytes8" + } + ] + }, + { + "type": "error", + "name": "RecipientNotPubkey", + "inputs": [ + { + "name": "length", "type": "uint256", "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "RecipientTargetMismatch", + "inputs": [ + { + "name": "recipient", + "type": "bytes32", + "internalType": "bytes32" }, { - "name": "maxAccounts", - "type": "uint8", - "internalType": "uint8" + "name": "target", + "type": "bytes32", + "internalType": "bytes32" } ] }, { "type": "error", - "name": "SvmPayloadEmpty", - "inputs": [] + "name": "RuleWithoutPin", + "inputs": [ + { + "name": "rule", + "type": "uint256", + "internalType": "uint256" + } + ] }, { "type": "error", - "name": "SvmPinIndexOutOfRange", + "name": "SvmAccountCountBelowPin", "inputs": [ { "name": "pin", @@ -1933,7 +1888,12 @@ "internalType": "uint256" }, { - "name": "accountIndex", + "name": "count", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "needed", "type": "uint8", "internalType": "uint8" } @@ -1941,15 +1901,15 @@ }, { "type": "error", - "name": "SvmPinRuleOutOfRange", + "name": "SvmAccountCountMismatch", "inputs": [ { - "name": "pin", + "name": "count", "type": "uint256", "internalType": "uint256" }, { - "name": "rule", + "name": "expected", "type": "uint8", "internalType": "uint8" } @@ -1957,23 +1917,33 @@ }, { "type": "error", - "name": "TargetMismatch", + "name": "SvmAccountPinMismatch", "inputs": [ { - "name": "actual", - "type": "address", - "internalType": "address" + "name": "pin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "accountIndex", + "type": "uint8", + "internalType": "uint8" }, { "name": "expected", - "type": "address", - "internalType": "address" + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "actual", + "type": "bytes32", + "internalType": "bytes32" } ] }, { "type": "error", - "name": "TooManyCeaAccounts", + "name": "SvmAccountsOutOfRange", "inputs": [ { "name": "count", @@ -1984,10 +1954,20 @@ }, { "type": "error", - "name": "TooManyPins", + "name": "SvmDataCeilingExceeded", "inputs": [ { - "name": "count", + "name": "pin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "actual", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "ceiling", "type": "uint256", "internalType": "uint256" } @@ -1995,10 +1975,20 @@ }, { "type": "error", - "name": "TooManySvmDataPins", + "name": "SvmDataFloorNotMet", "inputs": [ { - "name": "count", + "name": "pin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "actual", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "floor", "type": "uint256", "internalType": "uint256" } @@ -2006,10 +1996,10 @@ }, { "type": "error", - "name": "TooManySvmPins", + "name": "SvmDataPinInvalid", "inputs": [ { - "name": "count", + "name": "pin", "type": "uint256", "internalType": "uint256" } @@ -2017,47 +2007,67 @@ }, { "type": "error", - "name": "TotalNativeAmountExceeded", + "name": "SvmDataPinMismatch", "inputs": [ { - "name": "newSpent", + "name": "pin", "type": "uint256", "internalType": "uint256" }, { - "name": "cap", - "type": "uint256", - "internalType": "uint256" + "name": "expected", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "actual", + "type": "bytes32", + "internalType": "bytes32" } ] }, { "type": "error", - "name": "TotalSpendCapExceeded", + "name": "SvmDataRatioNotMet", "inputs": [ { - "name": "wouldBeTotal", + "name": "pin", "type": "uint256", "internalType": "uint256" }, { - "name": "cap", + "name": "a", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "b", "type": "uint256", "internalType": "uint256" + }, + { + "name": "num", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "den", + "type": "uint64", + "internalType": "uint64" } ] }, { "type": "error", - "name": "TotalValueExceeded", + "name": "SvmDataTooShortForPin", "inputs": [ { - "name": "newSpent", + "name": "pin", "type": "uint256", "internalType": "uint256" }, { - "name": "cap", + "name": "ixLen", "type": "uint256", "internalType": "uint256" } @@ -2065,15 +2075,21 @@ }, { "type": "error", - "name": "UncappedGasSwapRejected", - "inputs": [] + "name": "SvmInstructionNotExecute", + "inputs": [ + { + "name": "instructionId", + "type": "uint8", + "internalType": "uint8" + } + ] }, { "type": "error", - "name": "UnsupportedEnvelopeVersion", + "name": "SvmIxDataTooLong", "inputs": [ { - "name": "version", + "name": "length", "type": "uint256", "internalType": "uint256" } @@ -2081,77 +2097,88 @@ }, { "type": "error", - "name": "UnsupportedNamespace", + "name": "SvmMaxAccountsOutOfRange", "inputs": [ { - "name": "chainHash", - "type": "bytes32", - "internalType": "bytes32" + "name": "rule", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxAccounts", + "type": "uint8", + "internalType": "uint8" } ] }, { "type": "error", - "name": "ValueExceedsCap", + "name": "SvmPayloadEmpty", + "inputs": [] + }, + { + "type": "error", + "name": "SvmPinIndexOutOfRange", "inputs": [ { - "name": "value", + "name": "pin", "type": "uint256", "internalType": "uint256" }, { - "name": "cap", - "type": "uint256", - "internalType": "uint256" + "name": "accountIndex", + "type": "uint8", + "internalType": "uint8" } ] }, { "type": "error", - "name": "ValueOnlyCalldataNotEmpty", + "name": "SvmPinRuleOutOfRange", "inputs": [ { - "name": "length", + "name": "pin", "type": "uint256", "internalType": "uint256" + }, + { + "name": "rule", + "type": "uint8", + "internalType": "uint8" } ] }, { "type": "error", - "name": "ValueOnlyWithAmountRule", - "inputs": [] - }, - { - "type": "error", - "name": "ValueOnlyWithPins", - "inputs": [] - }, - { - "type": "error", - "name": "WrongModeForCall", + "name": "TooManyCeaAccounts", "inputs": [ { - "name": "actual", - "type": "uint8", - "internalType": "enum RulesType" + "name": "count", + "type": "uint256", + "internalType": "uint256" } ] }, { "type": "error", - "name": "WrongVmForCall", + "name": "TooManySvmDataPins", "inputs": [ { - "name": "actual", - "type": "uint8", - "internalType": "enum VmFamily" + "name": "count", + "type": "uint256", + "internalType": "uint256" } ] }, { "type": "error", - "name": "ZeroAddress", - "inputs": [] + "name": "TooManySvmPins", + "inputs": [ + { + "name": "count", + "type": "uint256", + "internalType": "uint256" + } + ] } ] diff --git a/packages/core/scripts/agw-local/abis/wallet.json b/packages/core/scripts/agw-local/abis/wallet.json index 5d5f6612..311c9a6f 100644 --- a/packages/core/scripts/agw-local/abis/wallet.json +++ b/packages/core/scripts/agw-local/abis/wallet.json @@ -667,9 +667,134 @@ "name": "label_", "type": "string", "internalType": "string" + }, + { + "name": "rules", + "type": "tuple[]", + "internalType": "struct Session[]", + "components": [ + { + "name": "sessionValidator", + "type": "address", + "internalType": "contract ISessionValidator" + }, + { + "name": "sessionValidatorInitData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "erc7739Policies", + "type": "tuple", + "internalType": "struct ERC7739Data", + "components": [ + { + "name": "allowedERC7739Content", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNames", + "type": "string[]", + "internalType": "string[]" + } + ] + }, + { + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "actions", + "type": "tuple[]", + "internalType": "struct ActionData[]", + "components": [ + { + "name": "actionTargetSelector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "actionTarget", + "type": "address", + "internalType": "address" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "permitERC4337Paymaster", + "type": "bool", + "internalType": "bool" + } + ] + } + ], + "outputs": [ + { + "name": "rulesIds", + "type": "bytes32[]", + "internalType": "bytes32[]" } ], - "outputs": [], "stateMutability": "nonpayable" }, { diff --git a/packages/core/scripts/agw-local/gen-abi.mjs b/packages/core/scripts/agw-local/gen-abi.mjs index 0430e31a..a8660f78 100644 --- a/packages/core/scripts/agw-local/gen-abi.mjs +++ b/packages/core/scripts/agw-local/gen-abi.mjs @@ -1,5 +1,5 @@ #!/usr/bin/env node -// Regenerates packages/core/src/lib/agentic/contracts/abi/v5/*.ts from the +// Regenerates packages/core/src/lib/agentic/contracts/abi/v6/*.ts from the // pinned ABI snapshots in ./abis/. The JSON files are the source artifact set; // this script only re-serialises them as // `as const` TypeScript so viem can infer types. Run from the repo root: @@ -12,8 +12,8 @@ import { fileURLToPath } from 'node:url'; const here = dirname(fileURLToPath(import.meta.url)); const repo = resolve(here, '../../../..'); const src = join(here, 'abis'); -const dst = join(repo, 'packages/core/src/lib/agentic/contracts/abi/v5'); -const PIN = '2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb'; +const dst = join(repo, 'packages/core/src/lib/agentic/contracts/abi/v6'); +const PIN = 'ffd567d3e49b2d27c6f50ad36093274dbac3090f'; const sourceNames = { AGW: 'wallet', @@ -37,7 +37,6 @@ if (manifest.sourceCommit !== PIN) { throw new Error('ABI source commit does not match the supported generation'); } - mkdirSync(dst, { recursive: true }); const exports = []; for (const [name, [constName, file]] of Object.entries(files)) { @@ -64,8 +63,8 @@ for (const [name, [constName, file]] of Object.entries(files)) { writeFileSync( join(dst, 'index.ts'), `// GENERATED by packages/core/scripts/agw-local/gen-abi.mjs — do not edit.\n` + - `// Review generation v5: Donut v5 deployment; source 2e61e13.\n` + - `export const V5_SOURCE_COMMIT = '${PIN}' as const;\n` + + `// Review generation v6: Donut v6 deployment; source ffd567d.\n` + + `export const V6_SOURCE_COMMIT = '${PIN}' as const;\n` + exports.join('\n') + '\n' ); diff --git a/packages/core/scripts/agw-local/prepare.sh b/packages/core/scripts/agw-local/prepare.sh index 9cd1923c..6e3d487e 100755 --- a/packages/core/scripts/agw-local/prepare.sh +++ b/packages/core/scripts/agw-local/prepare.sh @@ -5,7 +5,7 @@ # AGW_REPO path to a push-agentic-wallets clone (default: ../../../../push-agentic-wallets # relative to this script). Only `git archive` / `git ls-tree` are run against it, # so the clone's working tree, branches and index are never touched. -# AGW_PIN commit to extract (default: the reviewed v5). +# AGW_PIN commit to extract (default: the reviewed v6). # OUT destination directory (default: $TMPDIR/push-agw-local-). # # The script extracts the pinned tree, fetches each git submodule at the exact @@ -15,7 +15,7 @@ set -euo pipefail HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" AGW_REPO="${AGW_REPO:-$HERE/../../../../../push-agentic-wallets}" -AGW_PIN="${AGW_PIN:-2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb}" +AGW_PIN="${AGW_PIN:-ffd567d3e49b2d27c6f50ad36093274dbac3090f}" OUT="${OUT:-${TMPDIR:-/tmp}/push-agw-local-${AGW_PIN:0:7}}" command -v forge >/dev/null || { echo "forge not found (install Foundry)" >&2; exit 1; } diff --git a/packages/core/src/lib/agentic/__fixtures__/v5-vectors.json b/packages/core/src/lib/agentic/__fixtures__/v6-vectors.json similarity index 84% rename from packages/core/src/lib/agentic/__fixtures__/v5-vectors.json rename to packages/core/src/lib/agentic/__fixtures__/v6-vectors.json index 3f037d15..b1ecfd80 100644 --- a/packages/core/src/lib/agentic/__fixtures__/v5-vectors.json +++ b/packages/core/src/lib/agentic/__fixtures__/v6-vectors.json @@ -1,6 +1,6 @@ { "provenance": { - "agwCommit": "2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb", + "agwCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "generatedBy": "packages/core/__agw-local__/vectors.spec.ts", "toolchain": "forge Version: 1.5.1-stable", "chainId": 9000, @@ -118,24 +118,24 @@ ], "deriveWallet": [ { - "factory": "0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6", - "walletImplementation": "0x0165878A594ca255338adfa4d48449f69242Eb8F", + "factory": "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318", + "walletImplementation": "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853", "owner": "0x90F79bf6EB2c4f870365E785982E1f101E93b906", "index": 0, - "expected": "0xE68bD7D2E9b2F21bA9e4e09cE2D20A3d681Ec6e1" + "expected": "0x030A9Ef421d9fEd942Fc5C3629A61FD0E7826c95" }, { - "factory": "0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6", - "walletImplementation": "0x0165878A594ca255338adfa4d48449f69242Eb8F", + "factory": "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318", + "walletImplementation": "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853", "owner": "0x1111111111111111111111111111111111111111", "index": 0, - "expected": "0x3066c721A477afBF4c3732F39A0048684e4641cF" + "expected": "0xaa19c76fe8534a2c859733Bfb11016C375b0302e" } ], "native": { "rule": { "agent": "0x70997970C51812dc3A010C7d01b50e0d17dc79C8", - "target": "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318", + "target": "0x610178dA211FEF7D417bC0e6FeD39F05609AD788", "selector": "deposit(address,uint256)", "validUntil": 4102444800, "pins": [ @@ -162,20 +162,21 @@ "maxCalls": 3 }, "nativeChain": "eip155:9000", - "wallet": "0x3e8FE21F60352CE4e632537113451A6990b9b7e6", + "wallet": "0x619ce4E44bBe9a0EDAb3420848E756FFC6274Fe1", "rulesId": "0xed16789aedd36446aa851df227d231dfdaab75ab95d022e251d179e27fdcee59", - "actionId": "0x95eb75f6723928adc7fd1b4edeec4a558cc76cef41e06b7a16448bf74364d791", - "configId": "0x939681af8de835b5dde52d6056defa47df21b9325892b5945f113a8112179e69", + "actionId": "0x3fc42bf28b699aaf7e81050814910333318858878011ce9ab981ca13b7183afb", + "configId": "0xa813ee3036f4b5f260cad87886da068f472515ed393fa5d797c5ace14fcb2adf", "configInitialized": true, - "storedTarget": "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318", + "storedTarget": "0x610178dA211FEF7D417bC0e6FeD39F05609AD788", "storedSelector": "0x47e7ef24", "storedPins": [ { "offset": 4, - "expected": "0x0000000000000000000000003c44cdddb6a900fa2b585dd299e03d12fa4293bc" + "op": 0, + "value": "0x0000000000000000000000003c44cdddb6a900fa2b585dd299e03d12fa4293bc" } ], "storedAmountOffset": 36, - "encodedSession": "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000e7f1725e7734ce288f8367e1bb143e90bb3f051200000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002047e7ef24000000000000000000000000000000000000000000000000000000000000000000000000000000008a791620dd6260079bf849dc5567adc3f2fdc318000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000cf7ed3acca5a467e9e704c703e8d87f634fb0fc9000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000b6569703135353a3930303000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000f48657000000000000000000000000008a791620dd6260079bf849dc5567adc3f2fdc31847e7ef24000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000003200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000040000000000000000000000003c44cdddb6a900fa2b585dd299e03d12fa4293bc" + "encodedSession": "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000e7f1725e7734ce288f8367e1bb143e90bb3f051200000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002047e7ef2400000000000000000000000000000000000000000000000000000000000000000000000000000000610178da211fef7d417bc0e6fed39f05609ad788000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000dc64a140aa3e981100a9beca4e685f962f0cf6c9000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002c00000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000b6569703135353a393030300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000f4865700000000000000000000000000610178da211fef7d417bc0e6fed39f05609ad78847e7ef24000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000003200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000003c44cdddb6a900fa2b585dd299e03d12fa4293bc" } } diff --git a/packages/core/src/lib/agentic/__tests__/codec.spec.ts b/packages/core/src/lib/agentic/__tests__/codec.spec.ts index 6721ad68..a13680f0 100644 --- a/packages/core/src/lib/agentic/__tests__/codec.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/codec.spec.ts @@ -1,5 +1,5 @@ import { decodeFunctionData, getAddress, type Address, type Hex } from 'viem'; -import vectorsJson from '../__fixtures__/v5-vectors.json'; +import vectorsJson from '../__fixtures__/v6-vectors.json'; import { actionId, agentConfig, @@ -23,8 +23,8 @@ import { import { parseSelector, VALUE_ONLY_SELECTOR } from '../codec/selectors'; import { argumentOffset, headSize } from '../codec/abi-layout'; import { UINT256_MAX } from '../codec/defaults'; -import { v5 } from '../contracts/v5'; -import { AGW_ABI } from '../contracts/abi/v5'; +import { v6 } from '../contracts/v6'; +import { AGW_ABI } from '../contracts/abi/v6'; import { AGENTIC_ERROR_CODE } from '../errors'; import type { NativeRule } from '../agentic.types'; @@ -59,7 +59,7 @@ const vectors = revive(vectorsJson) as unknown as { configInitialized: boolean; storedTarget: Address; storedSelector: Hex; - storedPins: { offset: number; expected: Hex }[]; + storedPins: { offset: number; op: number; value: Hex }[]; storedAmountOffset: number; encodedSession: Hex; }; @@ -141,8 +141,8 @@ describe('native rule codec', () => { expect(back).toEqual({ ...terms, validUntil: terms.validUntil }); const rule = nativeTermsToRule(back, v.rule.agent); // Stored terms carry offsets, not an ABI: decoded rules report the raw offset form. - expect(rule.pins).toEqual([ - { offset: 4, expected: terms.pins[0].expected.toLowerCase() }, + expect(rule.wirePins).toEqual([ + { offset: 4, op: 0, value: terms.pins[0].value.toLowerCase() }, ]); expect(rule.amount).toEqual({ offset: 36, @@ -165,8 +165,8 @@ describe('native rule codec', () => { const { terms } = nativeRuleToTerms(input, { nowSeconds: NOW }); expect(terms.pins[0].offset).toBe(4 + 64); const decoded = nativeTermsToRule(terms, agent); - expect(decoded.pins).toEqual([ - { offset: 68, expected: terms.pins[0].expected }, + expect(decoded.wirePins).toEqual([ + { offset: 68, op: 0, value: terms.pins[0].value }, ]); expect(nativeRuleToTerms(decoded, { nowSeconds: NOW }).terms).toEqual( terms @@ -182,7 +182,7 @@ describe('native rule codec', () => { pins: [{ arg: 0, expected: agent }], }; const { terms } = nativeRuleToTerms(input, { nowSeconds: NOW }); - const word = terms.pins[0].expected; + const word = terms.pins[0].value; expect( nativeRuleToTerms( { ...input, pins: [{ arg: 0, expected: word }] }, @@ -221,7 +221,7 @@ describe('native rule codec', () => { { ...base, pins: [{ offset: 36, expected: `0x${'00'.repeat(31)}01` }] }, { nowSeconds: NOW } ).terms.pins - ).toEqual([{ offset: 36, expected: `0x${'00'.repeat(31)}01` }]); + ).toEqual([{ offset: 36, op: 0, value: `0x${'00'.repeat(31)}01` }]); }); it('applies confirmed zero PC defaults and independent token/call defaults', () => { @@ -235,18 +235,39 @@ describe('native rule codec', () => { }, { nowSeconds: NOW } ); - expect(terms.maxValuePerCall).toBe( - BigInt(0) - ); + expect(terms.maxValuePerCall).toBe(BigInt(0)); expect(terms.maxValueTotal).toBe(BigInt(0)); - expect(terms.maxCalls).toBe(0); + expect(terms.maxCalls).toBe(0xffffffff); expect(terms.amount.maxTotal).toBe(UINT256_MAX); }); it('rejects ambiguous arg-plus-offset authoring for both pins and amount', () => { - const rule = { agent, target, selector: 'transfer(address,uint256)' as const, validUntil: NOW + 10 }; - expect(() => nativeRuleToTerms({ ...rule, pins: [{ arg: 0, offset: 4, expected: `0x${'00'.repeat(32)}` } as never] }, { nowSeconds: NOW })).toThrow('mutually exclusive'); - expect(() => nativeRuleToTerms({ ...rule, amount: { arg: 1, offset: 36, maxPerCall: BigInt(1) } as never }, { nowSeconds: NOW })).toThrow('mutually exclusive'); + const rule = { + agent, + target, + selector: 'transfer(address,uint256)' as const, + validUntil: NOW + 10, + }; + expect(() => + nativeRuleToTerms( + { + ...rule, + pins: [ + { arg: 0, offset: 4, expected: `0x${'00'.repeat(32)}` } as never, + ], + }, + { nowSeconds: NOW } + ) + ).toThrow('mutually exclusive'); + expect(() => + nativeRuleToTerms( + { + ...rule, + amount: { arg: 1, offset: 36, maxPerCall: BigInt(1) } as never, + }, + { nowSeconds: NOW } + ) + ).toThrow('mutually exclusive'); }); it('keeps an explicit zero as zero', () => { @@ -403,12 +424,12 @@ describe('wallet call encoders decode back to the same calls', () => { const call = { target, value: BigInt(7), data: '0xd09de08a' as Hex }; it('execute single uses packed ERC-7579 calldata', () => { - const data = v5.encodeExecute([call]); + const data = v6.encodeExecute([call]); const { functionName, args } = decodeFunctionData({ abi: AGW_ABI, data }); expect(functionName).toBe('execute'); expect(args[0]).toBe(`0x${'00'.repeat(32)}`); expect((args[1] as Hex).length).toBe(2 + 2 * (20 + 32 + 4)); - expect(v5.decodeWalletCall(data)).toEqual({ + expect(v6.decodeWalletCall(data)).toEqual({ kind: 'execute', mode: args[0], calls: [call], @@ -416,8 +437,8 @@ describe('wallet call encoders decode back to the same calls', () => { }); it('execute batch uses abi.encode(Execution[])', () => { - const data = v5.encodeExecute([call, { ...call, value: BigInt(0) }]); - const decoded = v5.decodeWalletCall(data); + const data = v6.encodeExecute([call, { ...call, value: BigInt(0) }]); + const decoded = v6.decodeWalletCall(data); expect(decoded).toMatchObject({ kind: 'execute', mode: `0x01${'00'.repeat(31)}`, @@ -430,7 +451,7 @@ describe('wallet call encoders decode back to the same calls', () => { it('executeAsAgent carries the rule ID and one packed call', () => { const id = `0x${'42'.repeat(32)}` as Hex; - expect(v5.decodeWalletCall(v5.encodeExecuteAsAgent(id, call))).toEqual({ + expect(v6.decodeWalletCall(v6.encodeExecuteAsAgent(id, call))).toEqual({ kind: 'executeAsAgent', rulesId: id, mode: `0x${'00'.repeat(32)}`, @@ -439,6 +460,6 @@ describe('wallet call encoders decode back to the same calls', () => { }); it('unknown calldata is not mistaken for a wallet call', () => { - expect(v5.decodeWalletCall('0xdeadbeef')).toBeNull(); + expect(v6.decodeWalletCall('0xdeadbeef')).toBeNull(); }); }); diff --git a/packages/core/src/lib/agentic/__tests__/fake-chain.ts b/packages/core/src/lib/agentic/__tests__/fake-chain.ts index 1b38300e..d4f824a7 100644 --- a/packages/core/src/lib/agentic/__tests__/fake-chain.ts +++ b/packages/core/src/lib/agentic/__tests__/fake-chain.ts @@ -18,7 +18,7 @@ import { type TransactionReceipt, } from 'viem'; import { PUSH_NETWORK } from '../../constants/enums'; -import { v5 } from '../contracts/v5'; +import { v6 } from '../contracts/v6'; import type { ChainReader } from '../contracts/reader'; import { actionId, configId, deriveWallet } from '../codec/ids'; import { @@ -26,7 +26,7 @@ import { resetAgenticGenerations, type AgenticGeneration, } from '../deployments'; -import type { NativeConfigRead } from '../contracts/v5'; +import type { NativeConfigRead } from '../contracts/v6'; export const ADDR = { factory: getAddress('0x00000000000000000000000000000000000fac70'), @@ -113,7 +113,7 @@ export class FakeChain implements ChainReader { this.extraLogs.push( log( ADDR.factory, - v5.events.walletDeployed, + v6.events.walletDeployed, { owner, index, wallet: address }, { label }, BigInt(10) @@ -253,7 +253,7 @@ export class FakeChain implements ChainReader { maxTotal: BigInt(0), }, amountSpent: BigInt(0), - maxCalls: 0, + maxCalls: 0xffffffff, callsUsed: 0, pins: [], ...n, @@ -279,6 +279,7 @@ export class FakeChain implements ChainReader { selector: '0xd09de08a', beneficiaryOffset: 0, hasBeneficiary: false, + pins: [], maxValue: BigInt(0), }, ], @@ -386,7 +387,7 @@ export function checkpointLog( ): Log { return log( wallet, - v5.events.checkpointed, + v6.events.checkpointed, { seq: BigInt(seq) }, { kind, ref: `0x${'11'.repeat(32)}`, blockNumber: block }, block, @@ -400,8 +401,8 @@ export function registerFakeGeneration( ): AgenticGeneration { resetAgenticGenerations(); return registerAgenticGeneration({ - id: 'v5', - sourceCommit: '2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb', + id: 'v6', + sourceCommit: 'ffd567d3e49b2d27c6f50ad36093274dbac3090f', network, advertised: false, addresses: { diff --git a/packages/core/src/lib/agentic/__tests__/labels.spec.ts b/packages/core/src/lib/agentic/__tests__/labels.spec.ts index 84527c65..c4f88cba 100644 --- a/packages/core/src/lib/agentic/__tests__/labels.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/labels.spec.ts @@ -1,7 +1,7 @@ import { decodeFunctionData, encodeErrorResult } from 'viem'; import { PUSH_NETWORK } from '../../constants/enums'; import { PROGRESS_HOOK } from '../../progress-hook/progress-hook.types'; -import { v5 } from '../contracts/v5'; +import { v6 } from '../contracts/v6'; import { currentGeneration, resetAgenticGenerations } from '../deployments'; import { AGENTIC_ERROR_CODE } from '../errors'; import { createWallet } from '../management/create'; @@ -48,7 +48,7 @@ describe('v5 wallet labels', () => { const sent = rt.executeMock.mock.calls[0][0]; expect(sent).toMatchObject({ to: w.address, value: BigInt(0) }); expect( - decodeFunctionData({ abi: v5.abis.wallet, data: sent.data }) + decodeFunctionData({ abi: v6.abis.wallet, data: sent.data }) ).toMatchObject({ functionName: 'setLabel', args: [''] }); expect(hook).toHaveBeenCalledWith( expect.objectContaining({ id: PROGRESS_HOOK.AGENTIC_TX_106 }) @@ -84,7 +84,7 @@ describe('v5 wallet labels', () => { await setLabel(rt, gen(), w.address, 'UEA label'); expect( decodeFunctionData({ - abi: v5.abis.wallet, + abi: v6.abis.wallet, data: rt.executeMock.mock.calls[0][0].data, }).functionName ).toBe('setLabel'); @@ -94,7 +94,7 @@ describe('v5 wallet labels', () => { const chain = new FakeChain(); const w = chain.addWallet(ADDR.owner, 'x'); const data = encodeErrorResult({ - abi: v5.abis.wallet, + abi: v6.abis.wallet, errorName: 'LabelTooLong', args: [BigInt(65)], }); diff --git a/packages/core/src/lib/agentic/__tests__/management.spec.ts b/packages/core/src/lib/agentic/__tests__/management.spec.ts index f7d305e1..5982d691 100644 --- a/packages/core/src/lib/agentic/__tests__/management.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/management.spec.ts @@ -14,8 +14,8 @@ import { AGW_ABI, AGW_FACTORY_ABI, UNIVERSAL_RULES_POLICY_ABI, -} from '../contracts/abi/v5'; -import { v5 } from '../contracts/v5'; +} from '../contracts/abi/v6'; +import { v6 } from '../contracts/v6'; import { deriveWallet, rulesId as computeRulesId } from '../codec/ids'; import { AGENTIC_ERROR_CODE } from '../errors'; import { createWallet } from '../management/create'; @@ -41,13 +41,13 @@ const rule = (agent = ADDR.agent): NativeRule => ({ const granted = (wallet: `0x${string}`, id: Hex, block = BigInt(101)) => log( wallet, - v5.events.rulesGranted, + v6.events.rulesGranted, { rulesId: id, chainHash: `0x${'00'.repeat(32)}` }, { mode: 1, chainNamespace: PUSH_NS }, block ); const revoked = (wallet: `0x${string}`, id: Hex) => - log(wallet, v5.events.rulesRevoked, { rulesId: id }, {}, BigInt(101)); + log(wallet, v6.events.rulesRevoked, { rulesId: id }, {}, BigInt(101)); function withLogs(logs: Log[], over = {}) { const r = fakeResponse(over); @@ -82,7 +82,7 @@ describe('agentic.create', () => { withLogs([ log( ADDR.factory, - v5.events.walletDeployed, + v6.events.walletDeployed, { owner: ADDR.owner, index: BigInt(0), wallet: nextWallet }, { label: 'ops' }, BigInt(101) @@ -98,15 +98,14 @@ describe('agentic.create', () => { progressHook: perCall, }); expect(res).toMatchObject({ wallet: nextWallet, index: 0, rulesIds: ids }); - const calls = (execute.mock.calls[0][0] as { data: MultiCall[] }).data; - expect(calls.map((c) => c.to)).toEqual([ - ADDR.factory, - nextWallet, - nextWallet, - ]); - expect( - decodeFunctionData({ abi: AGW_ABI, data: calls[1].data }).functionName - ).toBe('grantRules'); + const sent = execute.mock.calls[0][0] as { to: string; data: Hex }; + expect(sent.to).toBe(ADDR.factory); + const decoded = decodeFunctionData({ + abi: AGW_FACTORY_ABI, + data: sent.data, + }); + expect(decoded.functionName).toBe('createWalletWithSig'); + expect(decoded.args[3]).toHaveLength(2); expect(rt.events.map((e) => e.id)).toEqual([ PROGRESS_HOOK.AGENTIC_TX_101, PROGRESS_HOOK.AGENTIC_TX_102, @@ -127,7 +126,7 @@ describe('agentic.create', () => { return withLogs([ log( ADDR.factory, - v5.events.walletDeployed, + v6.events.walletDeployed, { owner: ADDR.owner, index: BigInt(0), wallet: nextWallet }, { label: '' }, BigInt(101) @@ -170,7 +169,7 @@ describe('agentic.create', () => { expect(rt.executeMock).not.toHaveBeenCalled(); }); - it('a different wallet in the receipt is an INDEX_RACE with full details', async () => { + it('a different wallet in the receipt is RECEIPT_MISMATCH, not a safe-to-retry race', async () => { const fake = new FakeChain(); const elsewhere = deriveWallet({ factory: ADDR.factory, @@ -184,7 +183,7 @@ describe('agentic.create', () => { withLogs([ log( ADDR.factory, - v5.events.walletDeployed, + v6.events.walletDeployed, { owner: ADDR.owner, index: BigInt(1), wallet: elsewhere }, { label: '' }, BigInt(101) @@ -192,7 +191,7 @@ describe('agentic.create', () => { ])) as never, }); await expect(createWallet(rt, '', { rules: [] })).rejects.toMatchObject({ - code: AGENTIC_ERROR_CODE.INDEX_RACE, + code: AGENTIC_ERROR_CODE.RECEIPT_MISMATCH, }); }); @@ -204,7 +203,7 @@ describe('agentic.create', () => { withLogs([ log( ADDR.factory, - v5.events.walletDeployed, + v6.events.walletDeployed, { owner: ADDR.owner, index: BigInt(0), wallet: nextWallet }, { label: '' }, BigInt(101) @@ -223,83 +222,18 @@ describe('agentic.create', () => { const receipt = (logs: Log[], status: 'success' | 'reverted' = 'success') => ({ status, logs } as unknown as TransactionReceipt); - it('a sequential failure after deployment is CREATE_PARTIAL; what committed comes from this call’s receipts', async () => { + it('creation never uses the batch transport or a sequential fallback', async () => { const fake = new FakeChain(); - const h1 = `0x${'01'.repeat(32)}` as Hex; - const h2 = `0x${'02'.repeat(32)}` as Hex; - fake.receipts.set( - h1, - receipt([ - log( - ADDR.factory, - v5.events.walletDeployed, - { owner: ADDR.owner, index: BigInt(0), wallet: nextWallet }, - { label: 'ops' }, - BigInt(101) - ), - ]) - ); - fake.receipts.set(h2, receipt([granted(nextWallet, ids[0])])); const rt = mockRuntime(fake, { signer: ADDR.owner, - execute: (async () => { - throw new PushChainBatchExecutionError('grant 2 reverted', [h1, h2]); - }) as never, - }); - const err = await createWallet(rt, 'ops', { - rules: [rule(), rule(ADDR.other)], - }).catch((e) => e); - expect(err.code).toBe(AGENTIC_ERROR_CODE.CREATE_PARTIAL); - expect(err.details).toMatchObject({ - wallet: nextWallet, - walletDeployed: true, - grantedRulesIds: [ids[0]], - confirmedHashes: [h1, h2], - }); - expect(err.hint).toMatch(/rules\.add/); - expect(rt.events.at(-1)?.id).toBe(PROGRESS_HOOK.AGENTIC_TX_199_02); - }); - - it('a pending hash keeps an unconfirmed deployment unknown', async () => { - const fake = new FakeChain(); - const rt = mockRuntime(fake, { - signer: ADDR.owner, - execute: (async () => { - throw new PushChainBatchExecutionError( - 'timed out', - [], - `0x${'03'.repeat(32)}` - ); - }) as never, - }); - const err = await createWallet(rt, 'ops', { rules: [rule()] }).catch( - (e) => e - ); - expect(err.details).toMatchObject({ - walletDeployed: 'unknown', - pendingHash: `0x${'03'.repeat(32)}`, - }); - expect(err.hint).toMatch(/Do not retry/); - }); - - it('failed recovery reads report unknown state, never "not deployed"', async () => { - const fake = new FakeChain(); - const rt = mockRuntime(fake, { - signer: ADDR.owner, - execute: (async () => { - fake.addWallet(ADDR.owner, 'committed'); - throw new PushChainBatchExecutionError('grant failed', [ - `0x${'11'.repeat(32)}`, - ]); - }) as never, + execute: async () => { + throw new Error('simulation refused'); + }, }); - const err = await createWallet(rt, 'review', { rules: [rule()] }).catch( - (e) => e - ); - expect(err.code).toBe('CREATE_PARTIAL'); - expect(err.details.walletDeployed).toBe('unknown'); - expect(err.details.recoveryError).toBeTruthy(); - expect(err.hint).toMatch(/Do not retry/); + await expect( + createWallet(rt, 'atomic', { rules: [rule()] }) + ).rejects.toThrow('simulation refused'); + expect(rt.atomicMock).not.toHaveBeenCalled(); }); it('a receipt that cannot be read after submission keeps the hash and reports unknown state', async () => { @@ -315,10 +249,9 @@ describe('agentic.create', () => { }) as never, }); const err = await createWallet(rt, 'x', { rules: [] }).catch((e) => e); - expect(err.code).toBe(AGENTIC_ERROR_CODE.CREATE_PARTIAL); + expect(err.code).toBe(AGENTIC_ERROR_CODE.RECEIPT_UNAVAILABLE); expect(err.details).toMatchObject({ - walletDeployed: 'unknown', - submitted: { txHash: `0x${'44'.repeat(32)}` }, + txHash: `0x${'44'.repeat(32)}`, }); }); @@ -331,12 +264,12 @@ describe('agentic.create', () => { }); const rt = mockRuntime(fake, { signer: ADDR.owner, - execute: (async (p: { data: MultiCall[] }) => { + execute: (async (p: { data: Hex }) => { const deploy = decodeFunctionData({ abi: AGW_FACTORY_ABI, - data: p.data[0].data, + data: p.data, }); - expect(deploy.functionName).toBe('deployWalletWithSig'); + expect(deploy.functionName).toBe('createWalletWithSig'); expect( (deploy.args[0] as { index: bigint; wallet: string }).index ).toBe(BigInt(0)); @@ -353,31 +286,7 @@ describe('agentic.create', () => { (e) => e ); expect(err.code).toBe(AGENTIC_ERROR_CODE.INDEX_RACE); - expect(err.details).toMatchObject({ committed: false }); - }); - - it('a generic send error is still identified as a race when the fresh slot label proves another create won', async () => { - const fake = new FakeChain(); - const rt = mockRuntime(fake, { - signer: ADDR.owner, - execute: (async () => { - const winner = fake.addWallet(ADDR.owner, 'competing-create'); - winner.label = 'this-create'; // mutable view cannot erase the deploy evidence - throw new Error('opaque sender failure'); - }) as never, - }); - const err = await createWallet(rt, 'this-create', { - rules: [rule()], - }).catch((e) => e); - expect(err).toMatchObject({ - code: AGENTIC_ERROR_CODE.INDEX_RACE, - details: { - wallet: nextWallet, - index: 0, - committed: false, - competingLabel: 'competing-create', - }, - }); + expect(err.details).toMatchObject({ walletDeployed: false }); }); it('a later rename alone does not establish a competing creation', async () => { @@ -471,7 +380,7 @@ describe('rules.add / rules.delete', () => { ).toEqual(ids); const sent = exec.mock.calls[0][0] as { to: string; data: Hex }; expect(Array.isArray(sent.data)).toBe(false); - const outer = v5.decodeWalletCall(sent.data) as { + const outer = v6.decodeWalletCall(sent.data) as { kind: string; calls: { target: string; data: Hex }[]; }; @@ -512,7 +421,7 @@ describe('rules.add / rules.delete', () => { await revokeRules(rt, gen(), w.address, [ruleId(1), ruleId(2)]); const sent = exec.mock.calls[0][0] as { to: string; data: Hex }; expect(sent.to).toBe(w.address); - const decoded = v5.decodeWalletCall(sent.data) as { + const decoded = v6.decodeWalletCall(sent.data) as { kind: string; calls: { target: string; data: Hex }[]; }; @@ -566,7 +475,7 @@ describe('rules.update — one owner batch: assert → revoke → grant', () => expect(exec).toHaveBeenCalledTimes(1); const sent = exec.mock.calls[0][0] as { to: string; data: Hex }; expect(Array.isArray(sent.data)).toBe(false); // never a sequential multi-tx batch - const outer = v5.decodeWalletCall(sent.data) as { + const outer = v6.decodeWalletCall(sent.data) as { kind: string; mode: Hex; calls: { target: string; data: Hex }[]; @@ -632,7 +541,7 @@ describe('rules.update — one owner batch: assert → revoke → grant', () => rules: [{ rulesId: ruleId(1), rule: rule() }], }); const data = (exec.mock.calls[0][0] as { data: Hex }).data; - const outer = v5.decodeWalletCall(data) as { calls: { data: Hex }[] }; + const outer = v6.decodeWalletCall(data) as { calls: { data: Hex }[] }; const assertion = decodeFunctionData({ abi: UNIVERSAL_RULES_POLICY_ABI, data: outer.calls[0].data, diff --git a/packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts b/packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts index ab65c14f..2ac5e249 100644 --- a/packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts @@ -3,7 +3,7 @@ import { CHAIN, PUSH_NETWORK } from '../../constants/enums'; import { PUSH_BATCH_EXECUTOR_ADDRESS } from '../../constants/chain'; import { convertExecutorToOrigin } from '../../universal/account/account'; import { adaptTrackedResponse } from '../response'; -import { v5, UEA_MULTICALL_PREFIX } from '../contracts/v5'; +import { v6, UEA_MULTICALL_PREFIX } from '../contracts/v6'; import { resetAgenticGenerations } from '../deployments'; import { ADDR, FakeChain, registerFakeGeneration, ruleId } from './fake-chain'; import { fakeResponse, mockRuntime } from './mock-runtime'; @@ -27,7 +27,7 @@ function fixture() { const outer = actions.map((c) => ({ target: wallet.address, value: BigInt(0), - data: v5.encodeExecuteAsAgent(ruleId(1), c), + data: v6.encodeExecuteAsAgent(ruleId(1), c), })); const runtime = mockRuntime(fake); return { fake, wallet, actions, outer, runtime }; @@ -47,7 +47,7 @@ it('recognizes a verified 7702 self-call and retains every native agent action', fakeResponse({ from: ADDR.agent, to: ADDR.agent, - data: v5.encodeExecute(outer), + data: v6.encodeExecute(outer), }) ); expect(result).toMatchObject({ @@ -112,7 +112,7 @@ it('does not label an arbitrary forwarding contract as a trusted sender batch', const response = fakeResponse({ from: ADDR.agent, to: ADDR.other, - data: v5.encodeExecute(outer), + data: v6.encodeExecute(outer), }); expect(await adaptTrackedResponse(runtime, response)).toBe(response); expect(response.agentic).toBeUndefined(); diff --git a/packages/core/src/lib/agentic/__tests__/native-multi-action.spec.ts b/packages/core/src/lib/agentic/__tests__/native-multi-action.spec.ts index b317a1a2..967a14eb 100644 --- a/packages/core/src/lib/agentic/__tests__/native-multi-action.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/native-multi-action.spec.ts @@ -17,7 +17,7 @@ import { decodeEnvelope, decodeSession } from '../codec/session'; import { currentGeneration, resetAgenticGenerations, - V5_CAPABILITIES, + V6_CAPABILITIES, } from '../deployments'; import { AGENTIC_ERROR_CODE } from '../errors'; import { decodeActiveRule, readActiveRules } from '../reads/rules'; @@ -58,7 +58,7 @@ const ctx = { validator: ADDR.validator, rulesPolicy: ADDR.policy, gateway: ADDR.gateway, - capabilities: V5_CAPABILITIES, + capabilities: V6_CAPABILITIES, nowSeconds: NOW, forbiddenTargets: [ ADDR.factory, @@ -325,7 +325,7 @@ describe('rules.get / rules.list — reading several stored actions', () => { [a0.toLowerCase()]: { target: ADDR.target, selector: '0xd09de08a', - maxCalls: 0, + maxCalls: 0xffffffff, callsUsed: 5, }, [a1.toLowerCase()]: { diff --git a/packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts b/packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts index 9064b48f..1a941af1 100644 --- a/packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts @@ -8,7 +8,7 @@ import { transformToUniversalTxResponse } from '../../orchestrator/internals/res import { adaptTrackedResponse } from '../response'; import { composeOutbound, type DestinationCall } from '../execution/outbound'; import { agenticSend } from '../execution/send'; -import { v5 } from '../contracts/v5'; +import { v6 } from '../contracts/v6'; import { currentGeneration, resetAgenticGenerations } from '../deployments'; import type { AgenticExecutionContext } from '../context'; import { ADDR, FakeChain, registerFakeGeneration, ruleId } from './fake-chain'; @@ -187,8 +187,8 @@ describe.each(['owner', 'agent'] as const)( ); const input = door === 'owner' - ? v5.encodeExecute([out.gatewayCall]) - : v5.encodeExecuteAsAgent(ruleId(1), out.gatewayCall); + ? v6.encodeExecute([out.gatewayCall]) + : v6.encodeExecuteAsAgent(ruleId(1), out.gatewayCall); const signer = door === 'owner' ? ADDR.owner : ADDR.agent; const tx = { hash: PUSH_HASH, diff --git a/packages/core/src/lib/agentic/__tests__/presets.spec.ts b/packages/core/src/lib/agentic/__tests__/presets.spec.ts index 0b24bd42..bf0a1dde 100644 --- a/packages/core/src/lib/agentic/__tests__/presets.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/presets.spec.ts @@ -197,18 +197,21 @@ it('rejects unknown presets, unsupported list types and unsupported chain filter /no approved entry/ ); }); -it('refuses conflicting spenders rather than emitting unrestricted or ambiguous approvals', () => { +it('produces separate pinned alternatives for multiple spenders', () => { const data = catalog(); data[0].chains[0].approvals = [ { spender: target, app: 'One' }, { spender: ADDR.other, app: 'Two' }, ]; - expect(() => - buildPresetApi(data).get('DEXES', { - chainNamespace: chain, - assets: [{ token }], - }) - ).toThrow(/multiple spenders/); + const result = buildPresetApi(data).get('DEXES', { + chainNamespace: chain, + assets: [{ token }], + }); + expect( + result.rules[0].allowedCalls.filter( + (c) => c.selector === 'approve(address,uint256)' + ) + ).toHaveLength(2); }); it('enforces the 32-call ceiling including generated approvals', () => { const data = catalog(); @@ -232,20 +235,52 @@ it('requires full signatures and rejects duplicate function entries', () => { { target, selector: 'deposit()' }, { target, selector: 'deposit()' }, ]; - expect(() => buildPresetApi(data).get('DEXES')).toThrow(/duplicate target/); + expect(() => buildPresetApi(data).get('DEXES')).toThrow( + /unpinned alternative/ + ); }); -it('cannot bypass current deployment limitations through a preset approval', async () => { +it('compiles preset spender and amount pins with the deployed v6 policy', async () => { const { rules } = buildPresetApi(catalog()).get('DEXES', { chainNamespace: chain, agent, validUntil: until(), assets: [{ token, maxPerCall: BigInt(5) }], }); - await expect( - normalizePublicRule( - publicRules(rules)[0], - ADDR.other, - mockRuntime(new FakeChain()) - ) - ).rejects.toMatchObject({ code: 'CAPABILITY_UNAVAILABLE' }); + const normalized = await normalizePublicRule( + publicRules(rules)[0], + ADDR.other, + mockRuntime(new FakeChain()) + ); + expect( + ( + normalized as import('../agentic.types').UniversalRule + ).allowedCalls[1].pins?.map((p) => p.op) + ).toEqual([0, 1]); +}); + +it('keeps OR alternatives EVM-only: repeated Solana instructions are refused', () => { + const api = buildPresetApi([ + { + constant: 'DEXES', + name: 'fixture', + chains: [ + { + chainNamespace: 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1', + allowedCalls: [ + { + target: '11111111111111111111111111111111', + selector: 'deposit(u64)', + pins: [{ account: 0, expected: AGENTIC.WALLET }], + }, + { + target: '11111111111111111111111111111111', + selector: 'deposit(u64)', + pins: [{ arg: 0, max: BigInt(1) }], + }, + ], + }, + ], + }, + ]); + expect(() => api.get('DEXES')).toThrow(/Solana does not support alternative/); }); diff --git a/packages/core/src/lib/agentic/__tests__/public-rule.spec.ts b/packages/core/src/lib/agentic/__tests__/public-rule.spec.ts index 10c4b587..ddf1d5d9 100644 --- a/packages/core/src/lib/agentic/__tests__/public-rule.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/public-rule.spec.ts @@ -47,9 +47,11 @@ it('normalizes unified native calls into exact EQ/MAX words with zero PC default expect.objectContaining({ maxValuePerCall: BigInt(0), maxValueTotal: UINT256_MAX, - maxCalls: 0, - pins: [{ offset: 4, expected: `0x${wallet.slice(2).padStart(64, '0')}` }], - amount: { offset: 36, maxPerCall: BigInt(5), maxTotal: UINT256_MAX }, + maxCalls: 0xffffffff, + wirePins: [ + { offset: 4, op: 0, value: `0x${wallet.slice(2).padStart(64, '0')}` }, + { offset: 36, op: 1, value: `0x${'0'.repeat(63)}5` }, + ], }), ]); const rt = mockRuntime(fake()); @@ -61,7 +63,10 @@ it('normalizes unified native calls into exact EQ/MAX words with zero PC default publicRules([base()]), await Snapshot.at(rt.reader) ); - expect(p.nativeTerms?.[0].amount.maxPerCall).toBe(BigInt(5)); + expect(p.nativeTerms?.[0].pins[1]).toMatchObject({ + op: 1, + value: `0x${'0'.repeat(63)}5`, + }); }); it.each(['actions', 'target', 'amount', 'maxCalls', 'maxValueTotal', 'ref'])( 'rejects retired top-level %s before signing', @@ -71,15 +76,15 @@ it.each(['actions', 'target', 'amount', 'maxCalls', 'maxValueTotal', 'ref'])( ); } ); -it('rejects two native MAX pins on the deployed policy', async () => { +it('supports multiple native MAX pins', async () => { const r = base(); r.allowedCalls[0].pins = [ { arg: 0, max: BigInt(1) }, { arg: 1, max: BigInt(2) }, ]; - await expect(normalize(r)).rejects.toMatchObject({ - code: 'CAPABILITY_UNAVAILABLE', - }); + expect( + ((await normalize(r)) as NativeMultiRule).actions[0].wirePins + ).toHaveLength(2); }); it('compiles the existing EVM WALLET beneficiary and defaults asset total to zero', async () => { const r = base(); @@ -88,15 +93,17 @@ it('compiles the existing EVM WALLET beneficiary and defaults asset total to zer r.allowedCalls[0].pins = [{ arg: 0, expected: WALLET }]; const out = (await normalize(r)) as UniversalRule; expect(out.allowedCalls[0]).toMatchObject({ - beneficiaryOffset: 4, + pins: [expect.objectContaining({ offset: 4, op: 0 })], maxValue: BigInt(0), }); expect(out.assets[0].maxTotal).toBe(BigInt(0)); }); -it('rejects unavailable destination MAX pins before contract deployment', async () => { - await expect( - normalize({ ...base(), chainNamespace: 'eip155:11155111' }) - ).rejects.toMatchObject({ code: 'CAPABILITY_UNAVAILABLE' }); +it('supports general destination EQ/MAX pins', async () => { + const out = (await normalize({ + ...base(), + chainNamespace: 'eip155:11155111', + })) as UniversalRule; + expect(out.allowedCalls[0].pins?.map((p) => p.op)).toEqual([0, 1]); }); it('refuses layouts whose top-level argument indexes cannot be reconstructed', async () => { const r = base(); @@ -154,7 +161,7 @@ it('compiles numeric Solana arg/account pins without a caller IDL', async () => }, now ); - expect(terms.programs[0].maxAccounts).toBe(0); + expect(terms.programs[0].maxAccounts).toBe(255); expect(terms.pins).toEqual([ { ruleIndex: 0, accountIndex: 0, expected: cea }, ]); @@ -196,12 +203,34 @@ it('does not silently discard a token qualifier on an argument pin', async () => it('reads native wallet equality as WALLET and re-encodes its exact word', async () => { const { getRule } = await import('../reads/rules'); const { ruleId } = await import('./fake-chain'); - const chain=fake();const w=chain.addWallet(ADDR.owner,'wallet-pin'); - const word=`0x${w.address.slice(2).toLowerCase().padStart(64,'0')}` as const; - w.rules.push(chain.nativeRule(ADDR.agent,ruleId(1),{pins:[{offset:4,expected:word}]})); - const rt=mockRuntime(chain); - const rec=await getRule(await Snapshot.at(chain),currentGeneration(PUSH_NETWORK.TESTNET_DONUT),w.address,ruleId(1),rt.pushChainNamespace); - expect(rec.rule).toMatchObject({allowedCalls:[{pins:[{arg:0,expected:WALLET}]}]}); - const normalized=await normalizePublicRule(publicRules([rec.rule])[0],w.address,rt) as NativeMultiRule; - expect(normalized.actions[0].pins).toEqual([{offset:4,expected:word}]); + const chain = fake(); + const w = chain.addWallet(ADDR.owner, 'wallet-pin'); + const word = `0x${w.address + .slice(2) + .toLowerCase() + .padStart(64, '0')}` as const; + w.rules.push( + chain.nativeRule(ADDR.agent, ruleId(1), { + pins: [{ offset: 4, op: 0, value: word }], + }) + ); + const rt = mockRuntime(chain); + const rec = await getRule( + await Snapshot.at(chain), + currentGeneration(PUSH_NETWORK.TESTNET_DONUT), + w.address, + ruleId(1), + rt.pushChainNamespace + ); + expect(rec.rule).toMatchObject({ + allowedCalls: [{ pins: [{ arg: 0, expected: WALLET }] }], + }); + const normalized = (await normalizePublicRule( + publicRules([rec.rule])[0], + w.address, + rt + )) as NativeMultiRule; + expect(normalized.actions[0].wirePins).toEqual([ + { offset: 4, op: 0, value: word }, + ]); }); diff --git a/packages/core/src/lib/agentic/__tests__/reads-context.spec.ts b/packages/core/src/lib/agentic/__tests__/reads-context.spec.ts index 72cf7515..0babc61a 100644 --- a/packages/core/src/lib/agentic/__tests__/reads-context.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/reads-context.spec.ts @@ -18,16 +18,16 @@ import { ruleId, } from './fake-chain'; import { mockRuntime } from './mock-runtime'; -import { v5 } from '../contracts/v5'; +import { v6 } from '../contracts/v6'; import { readOriginToken } from '../contracts/prc20-metadata'; describe('generation registry', () => { afterEach(() => resetAgenticGenerations()); - it('ships Donut v5 only; other networks are unsupported', () => { + it('ships Donut v6 only; other networks are unsupported', () => { resetAgenticGenerations(); expect(currentGeneration(PUSH_NETWORK.TESTNET_DONUT)).toMatchObject({ - id: 'v5', + id: 'v6', advertised: true, }); for (const n of Object.values(PUSH_NETWORK).filter( @@ -61,7 +61,7 @@ describe('Donut log-range limit', () => { const getLogs = jest.spyOn(fake, 'getLogs'); await scanLogs( fake, - { address: ADDR.factory, event: v5.events.walletDeployed }, + { address: ADDR.factory, event: v6.events.walletDeployed }, BigInt(10), BigInt(2010) ); @@ -298,7 +298,7 @@ describe('rules.list / rules.get', () => { fake.nativeRule(ADDR.agent, ruleId(1), { callsUsed: 3, valueSpent: BigInt(5), - maxCalls: 0, + maxCalls: 0xffffffff, }), ]); const rules = await listRules( @@ -396,7 +396,7 @@ describe('rules.list / rules.get', () => { fake.extraLogs.push( log( w.address, - v5.events.rulesRevoked, + v6.events.rulesRevoked, { rulesId: ruleId(9) }, {}, BigInt(50) diff --git a/packages/core/src/lib/agentic/__tests__/response-surface.spec.ts b/packages/core/src/lib/agentic/__tests__/response-surface.spec.ts index e4550ae4..3dac9d67 100644 --- a/packages/core/src/lib/agentic/__tests__/response-surface.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/response-surface.spec.ts @@ -10,8 +10,8 @@ import { PUSH_NETWORK } from '../../constants/enums'; import { UNIVERSAL_GATEWAY_PC } from '../../constants/abi'; import { PushChainExecutionError } from '../../orchestrator/internals/errors'; import { Utils } from '../../utils'; -import { AGW_ABI } from '../contracts/abi/v5'; -import { v5 } from '../contracts/v5'; +import { AGW_ABI } from '../contracts/abi/v6'; +import { v6 } from '../contracts/v6'; import { resetAgenticGenerations } from '../deployments'; import { AgenticRevertError } from '../errors'; import { adaptAgenticResponse, adaptTrackedResponse } from '../response'; @@ -58,7 +58,7 @@ describe('response identity', () => { registerFakeGeneration(); const fake = new FakeChain(); const w = fake.addWallet(ADDR.owner, 'w'); - const data = v5.encodeExecuteAsAgent(ruleId(4), { + const data = v6.encodeExecuteAsAgent(ruleId(4), { target: ADDR.target, value: BigInt(0), data: '0xd09de08a', @@ -120,7 +120,7 @@ describe('response identity', () => { }, ], }); - const data = v5.encodeExecuteAsAgent(ruleId(4), { + const data = v6.encodeExecuteAsAgent(ruleId(4), { target: ADDR.gateway, value: BigInt(5), data: gatewayCall, @@ -155,7 +155,7 @@ describe('response identity', () => { registerFakeGeneration(); const spoof = fakeResponse({ to: ADDR.target, - data: v5.encodeExecute([ + data: v6.encodeExecute([ { target: ADDR.other, value: BigInt(0), data: '0x' }, ]), }); diff --git a/packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts b/packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts index 8127cfc8..3826fe62 100644 --- a/packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts @@ -6,7 +6,7 @@ import { encodeUniversalTerms } from '../codec/universal-terms'; import { buildSession, encodeEnvelope, encodeSession } from '../codec/session'; import { prepareRules } from '../codec/rules'; import { validateUniversalRuleShape } from '../codec/universal'; -import { V5_CAPABILITIES } from '../deployments'; +import { V6_CAPABILITIES } from '../deployments'; import { AGENTIC_ERROR_CODE } from '../errors'; import { internalAgenticUtils } from '../utils'; import type { @@ -22,7 +22,7 @@ const ctx = { pushChainNamespace: PUSH_NS, validator: ADDR.validator, rulesPolicy: ADDR.policy, - capabilities: V5_CAPABILITIES, + capabilities: V6_CAPABILITIES, nowSeconds: NOW, forbiddenTargets: [ ADDR.factory, @@ -217,7 +217,12 @@ describe('universal rules — validated, then capability-gated (A01, A05)', () = validateUniversalRuleShape( universal({ allowedCalls: [ - { target: ADDR.target, selector: '0x617ba037', beneficiary: 2 }, + { + target: ADDR.target, + selector: '0x617ba037', + pins: [], + beneficiary: 2, + }, ], }), NOW @@ -270,10 +275,13 @@ describe('internal generation codecs (pure)', () => { maxCalls: 4, validUntil: NOW + 100, }); - expect((back as NativeRule).pins).toEqual([ + expect( + (back as import('../agentic.types').NativeSingleRule).wirePins + ).toEqual([ { offset: 4, - expected: `0x${'0'.repeat(24)}${ADDR.other.slice(2).toLowerCase()}`, + op: 0, + value: `0x${'0'.repeat(24)}${ADDR.other.slice(2).toLowerCase()}`, }, ]); }); @@ -323,6 +331,7 @@ describe('internal generation codecs (pure)', () => { { target: ADDR.target, selector: '0x617ba037', + pins: [], beneficiaryOffset: 68, hasBeneficiary: true, maxValue: BigInt(0), diff --git a/packages/core/src/lib/agentic/__tests__/send.spec.ts b/packages/core/src/lib/agentic/__tests__/send.spec.ts index a9b567cf..c5ce94e7 100644 --- a/packages/core/src/lib/agentic/__tests__/send.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/send.spec.ts @@ -13,7 +13,7 @@ import { PushChainExecutionError } from '../../orchestrator/internals/errors'; import { PROGRESS_HOOK } from '../../progress-hook/progress-hook.types'; import type { AgenticExecutionContext } from '../context'; import { currentGeneration, resetAgenticGenerations } from '../deployments'; -import { v5 } from '../contracts/v5'; +import { v6 } from '../contracts/v6'; import { actionId } from '../codec/ids'; import { AGENTIC_ERROR_CODE, AgenticRevertError } from '../errors'; import { agenticSend } from '../execution/send'; @@ -111,7 +111,7 @@ describe('guards fail before the signer is ever invoked', () => { data: Hex; }[]; expect(batch.map((c) => c.to)).toEqual([ctx.wallet, ctx.wallet]); - expect(batch.map((c) => v5.decodeWalletCall(c.data))).toEqual( + expect(batch.map((c) => v6.decodeWalletCall(c.data))).toEqual( calls.map((c) => ({ kind: 'executeAsAgent', rulesId: ruleId(1), @@ -186,7 +186,7 @@ describe('explicit Push destinations', () => { data, }); expect( - v5.decodeWalletCall(rt.executeMock.mock.calls[0][0].data) + v6.decodeWalletCall(rt.executeMock.mock.calls[0][0].data) ).toMatchObject({ kind: 'executeAsAgent', rulesId: ruleId(1) }); expect(tx.route).not.toBe('UOA_TO_CEA'); expect(tx.to).toBe(ADDR.target); @@ -199,7 +199,7 @@ describe('explicit Push destinations', () => { data, }); expect( - v5.decodeWalletCall(rt.executeMock.mock.calls[0][0].data) + v6.decodeWalletCall(rt.executeMock.mock.calls[0][0].data) ).toMatchObject({ kind: 'execute', calls: [{ target: ADDR.target }] }); }); @@ -228,7 +228,7 @@ describe('native wrapping and logical identity', () => { const sent = rt.executeMock.mock.calls[0][0]; expect(sent.to).toBe(w.address); expect(sent.value).toBe(BigInt(0)); - expect(v5.decodeWalletCall(sent.data)).toEqual({ + expect(v6.decodeWalletCall(sent.data)).toEqual({ kind: 'executeAsAgent', rulesId: ruleId(1), mode: `0x${'00'.repeat(32)}`, @@ -267,7 +267,7 @@ describe('native wrapping and logical identity', () => { { to: ADDR.other, value: BigInt(1), data: '0x' }, ], }); - const decoded = v5.decodeWalletCall(rt.executeMock.mock.calls[0][0].data); + const decoded = v6.decodeWalletCall(rt.executeMock.mock.calls[0][0].data); expect(decoded).toMatchObject({ kind: 'execute', mode: `0x01${'00'.repeat(31)}`, @@ -398,7 +398,7 @@ describe('EVM outbound composition from the wallet', () => { s.w.address, CHAIN.ETHEREUM_SEPOLIA ); - const outer = v5.decodeWalletCall(rt.executeMock.mock.calls[0][0].data) as { + const outer = v6.decodeWalletCall(rt.executeMock.mock.calls[0][0].data) as { kind: string; rulesId: Hex; calls: { target: Address; value: bigint; data: Hex }[]; @@ -438,19 +438,18 @@ describe('EVM outbound composition from the wallet', () => { ); }); - it('never injects an approval into the agent path; missing allowance fails before signing', async () => { + it('agent sends without a standing allowance; the wallet handles approval', async () => { const s = universalSetup(); s.fake.balances.set(`allowance:${token.toLowerCase()}`, BigInt(10)); const rt = mockRuntime(s.fake, { signer: ADDR.agent, resolvePrc20: () => token, }); - await expect( - agenticSend(rt, s.ctx, send(BigInt(100))) - ).rejects.toMatchObject({ - code: AGENTIC_ERROR_CODE.GATEWAY_ALLOWANCE_INSUFFICIENT, - }); - expect(rt.executeMock).not.toHaveBeenCalled(); + await agenticSend(rt, s.ctx, send(BigInt(100))); + expect(rt.executeMock).toHaveBeenCalledTimes(1); + expect(s.fake.calls.some((c) => c.functionName === 'allowance')).toBe( + false + ); }); it('wallet funding is checked locally; rule PC limits are enforced by the contract', async () => { @@ -532,7 +531,7 @@ describe('EVM outbound composition from the wallet', () => { resolvePrc20: () => token, }); await agenticSend(rt, s.ctx, send(BigInt(100))); - const outer = v5.decodeWalletCall(rt.executeMock.mock.calls[0][0].data) as { + const outer = v6.decodeWalletCall(rt.executeMock.mock.calls[0][0].data) as { kind: string; calls: { target: Address; data: Hex }[]; }; @@ -540,7 +539,7 @@ describe('EVM outbound composition from the wallet', () => { expect(outer.calls.map((c) => c.target)).toEqual([ADDR.gateway]); }); - it('owner door with too small an allowance fails before signing (no implicit approval)', async () => { + it('owner sends without a standing allowance', async () => { const s = universalSetup(); s.ctx.door = 'owner'; s.ctx.signerPushAccount = ADDR.owner; @@ -549,12 +548,11 @@ describe('EVM outbound composition from the wallet', () => { signer: ADDR.owner, resolvePrc20: () => token, }); - await expect( - agenticSend(rt, s.ctx, send(BigInt(100))) - ).rejects.toMatchObject({ - code: AGENTIC_ERROR_CODE.GATEWAY_ALLOWANCE_INSUFFICIENT, - }); - expect(rt.executeMock).not.toHaveBeenCalled(); + await agenticSend(rt, s.ctx, send(BigInt(100))); + expect(rt.executeMock).toHaveBeenCalledTimes(1); + expect(s.fake.calls.some((c) => c.functionName === 'allowance')).toBe( + false + ); }); it('an existing unlimited allowance is consumed as-is', async () => { @@ -590,7 +588,7 @@ describe('EVM outbound composition from the wallet', () => { to: { address: recipient, chain: CHAIN.ETHEREUM_SEPOLIA }, funds: { amount: BigInt(100), token: usdc }, }); - const outer = v5.decodeWalletCall(rt.executeMock.mock.calls[0][0].data) as { + const outer = v6.decodeWalletCall(rt.executeMock.mock.calls[0][0].data) as { calls: { data: Hex }[]; }; const { args } = decodeFunctionData({ @@ -638,7 +636,7 @@ describe('EVM outbound composition from the wallet', () => { to: { address: ADDR.other, chain: CHAIN.ETHEREUM_SEPOLIA }, value: BigInt(7), }); - const outer = v5.decodeWalletCall(rt.executeMock.mock.calls[0][0].data) as { + const outer = v6.decodeWalletCall(rt.executeMock.mock.calls[0][0].data) as { calls: { data: Hex }[]; }; const req = decodeFunctionData({ diff --git a/packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts b/packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts index 0d7317fc..cf8c7912 100644 --- a/packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts @@ -351,7 +351,7 @@ describe('S12–S18 payload checks', () => { ) ) ).toThrow(/SvmAccountPinMismatch/); - t.programs = [{ ...t.programs[0], maxAccounts: 0 }]; + t.programs = [{ ...t.programs[0], maxAccounts: 255 }]; expect(() => validateAgwSvmPayload( t, diff --git a/packages/core/src/lib/agentic/agentic.types.ts b/packages/core/src/lib/agentic/agentic.types.ts index 6dcc6e9a..34acefad 100644 --- a/packages/core/src/lib/agentic/agentic.types.ts +++ b/packages/core/src/lib/agentic/agentic.types.ts @@ -1,4 +1,5 @@ -/** Public section-6 rules and internal adapters for the deployed v5 wire format. +import type { ArgPinWire } from './codec/pins'; +/** Public section-6 rules and internal adapters for the deployed v6 wire format. * Source snapshot: October 12, 2026. Internal normalized types are not package exports. */ import type { Idl } from '@coral-xyz/anchor'; @@ -17,6 +18,7 @@ export type Selector = AgenticHex | `${string}(${string})`; /** One Push function a native rule allows, with its own limits and counters. */ export interface NativeAction { + wirePins?: ArgPinWire[]; target: AgenticAddress; selector: Selector | 'value-only'; /** Default 0: no native PC value allowance. */ @@ -102,6 +104,7 @@ export interface AssetCap { } export interface AllowedCall { + pins?: ArgPinWire[]; target: AgenticAddress; selector: Selector; /** Argument index whose address must be the wallet's destination account. */ diff --git a/packages/core/src/lib/agentic/capabilities.ts b/packages/core/src/lib/agentic/capabilities.ts index 0f6cecf0..5cef0091 100644 --- a/packages/core/src/lib/agentic/capabilities.ts +++ b/packages/core/src/lib/agentic/capabilities.ts @@ -21,7 +21,7 @@ export enum AgenticCapability { ASSERT_SPENT_NATIVE = 'assertSpentNative', /** checkpointCount + Checkpointed events. */ CHECKPOINTS = 'checkpoints', - /** Agent-door EVM outbound composition against v5 per-token caps. */ + /** Agent-door EVM outbound composition against v6 per-token caps. */ UNIVERSAL_EVM_OUTBOUND = 'universalEvmOutbound', /** Target UniversalRule (assets[] / maxGasPerCall) encode/decode. A05/A07. */ UNIVERSAL_EVM_RULES = 'universalEvmRules', diff --git a/packages/core/src/lib/agentic/codec/defaults.ts b/packages/core/src/lib/agentic/codec/defaults.ts index a5fc885b..4f1ba696 100644 --- a/packages/core/src/lib/agentic/codec/defaults.ts +++ b/packages/core/src/lib/agentic/codec/defaults.ts @@ -4,14 +4,14 @@ * a fallback for these fields; update this table for future changes. * * Explicit zero always stays zero. In the native policy a zero value/amount - * cap forbids positive value/amount, while maxCalls = 0 means unlimited. + * cap forbids positive value/amount, while maxCalls = uint32 maximum means unlimited. */ export const UINT256_MAX = BigInt(2) ** BigInt(256) - BigInt(1); export interface DefaultRow { value: bigint; meaning: string; - source: 'product' | 'v5'; + source: 'product' | 'v6'; } export const AGENTIC_DEFAULTS = { @@ -32,7 +32,7 @@ export const AGENTIC_DEFAULTS = { source: 'product', }, maxCalls: { - value: BigInt(0), + value: BigInt(0xffffffff), meaning: 'unlimited calls until expiry', source: 'product', }, diff --git a/packages/core/src/lib/agentic/codec/ids.ts b/packages/core/src/lib/agentic/codec/ids.ts index 56c4f473..6a4b0e99 100644 --- a/packages/core/src/lib/agentic/codec/ids.ts +++ b/packages/core/src/lib/agentic/codec/ids.ts @@ -12,7 +12,7 @@ import { import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; /** - * Pure identity helpers mirroring the pinned AGW generation (v5): + * Pure identity helpers mirroring the pinned AGW generation (v6): * smartsessions IdLib.toActionId / toConfigId / toPermissionId and * AGWFactory._predict (OZ Clones immutable-args CREATE2). * Every input that changes the result is explicit — validator, factory and diff --git a/packages/core/src/lib/agentic/codec/native.ts b/packages/core/src/lib/agentic/codec/native.ts index 57013161..ae6012f3 100644 --- a/packages/core/src/lib/agentic/codec/native.ts +++ b/packages/core/src/lib/agentic/codec/native.ts @@ -1,3 +1,4 @@ +import { ARG_PIN_COMPONENTS, validatePins, type ArgPinWire } from './pins'; import { decodeAbiParameters, encodeAbiParameters, @@ -23,13 +24,13 @@ import { type ParsedSelector, } from './selectors'; -/** URP native limits at v5 (Types.sol MAX_PINS, AGW MAX_NATIVE_ACTIONS). */ +/** URP native limits at v6 (Types.sol MAX_PINS, AGW MAX_NATIVE_ACTIONS). */ export const MAX_PINS = 8; export const MAX_NATIVE_ACTIONS = 8; const UINT32_MAX = 2 ** 32 - 1; const UINT48_MAX = 2 ** 48 - 1; -/** NativeTerms (Types.sol:354-363 at v5). */ +/** NativeTerms in the pinned v6 Types.sol. */ export interface NativeTermsWire { validUntil: number; target: Address; @@ -43,7 +44,7 @@ export interface NativeTermsWire { maxTotal: bigint; }; maxCalls: number; - pins: readonly { offset: number; expected: Hex }[]; + pins: readonly ArgPinWire[]; } export const NATIVE_TERMS_PARAM: AbiParameter = { @@ -68,10 +69,7 @@ export const NATIVE_TERMS_PARAM: AbiParameter = { { name: 'pins', type: 'tuple[]', - components: [ - { name: 'offset', type: 'uint16' }, - { name: 'expected', type: 'bytes32' }, - ], + components: ARG_PIN_COMPONENTS, }, ], }; @@ -107,6 +105,7 @@ const SINGLE_ACTION_FIELDS = [ 'maxValueTotal', 'maxCalls', 'pins', + 'wirePins', 'amount', ] as const; @@ -162,6 +161,7 @@ export function nativeActionsOf( maxValueTotal: single.maxValueTotal, maxCalls: single.maxCalls, pins: single.pins, + wirePins: single.wirePins, amount: single.amount, validUntil: single.validUntil, }, @@ -250,7 +250,10 @@ export function nativeActionToTerms( } const parsed = parseSelector(rule.selector); const pinsIn = rule.pins ?? []; - if (parsed.valueOnly && (pinsIn.length > 0 || rule.amount)) { + if ( + parsed.valueOnly && + (pinsIn.length > 0 || rule.wirePins?.length || rule.amount) + ) { throw invalid('a value-only rule cannot carry pins or an amount rule'); } if (pinsIn.length > MAX_PINS) { @@ -338,10 +341,22 @@ export function nativeActionToTerms( rule.maxCalls === undefined ? Number(AGENTIC_DEFAULTS.native.maxCalls.value) : rule.maxCalls; - if (!Number.isInteger(maxCalls) || maxCalls < 0 || maxCalls > UINT32_MAX) { + if (!Number.isInteger(maxCalls) || maxCalls <= 0 || maxCalls > UINT32_MAX) { throw invalid('maxCalls must be a uint32 integer'); } + try { + validatePins( + rule.wirePins ?? + pins.map((p) => ({ + offset: p.offset, + op: 0 as const, + value: p.expected, + })) + ); + } catch (error) { + throw invalid((error as Error).message); + } return { parsed, terms: { @@ -352,7 +367,13 @@ export function nativeActionToTerms( maxValueTotal, amount, maxCalls, - pins, + pins: + rule.wirePins ?? + pins.map((p) => ({ + offset: p.offset, + op: 0 as const, + value: p.expected, + })), }, }; } @@ -388,12 +409,7 @@ export function nativeTermsToRule( maxValueTotal: terms.maxValueTotal, maxCalls: Number(terms.maxCalls), }; - if (terms.pins.length > 0) { - rule.pins = terms.pins.map((p) => ({ - offset: Number(p.offset), - expected: p.expected.toLowerCase() as AgenticHex, - })); - } + if (terms.pins.length > 0) rule.wirePins = terms.pins.map((p) => ({ ...p })); if (terms.amount.enabled) { rule.amount = { offset: Number(terms.amount.offset), diff --git a/packages/core/src/lib/agentic/codec/pins.ts b/packages/core/src/lib/agentic/codec/pins.ts new file mode 100644 index 00000000..4c81a522 --- /dev/null +++ b/packages/core/src/lib/agentic/codec/pins.ts @@ -0,0 +1,32 @@ +import type { Hex } from 'viem'; +export interface ArgPinWire { + offset: number; + op: 0 | 1; + value: Hex; +} +export const ARG_PIN_COMPONENTS = [ + { name: 'offset', type: 'uint16' }, + { name: 'op', type: 'uint8' }, + { name: 'value', type: 'bytes32' }, +] as const; +export const UNLIMITED_CALLS = 0xffffffff; +export const ANY_ACCOUNT_COUNT = 255; + +/** Validate every encoded constraint before signing. */ +export function validatePins(pins: readonly ArgPinWire[]): void { + if (!Array.isArray(pins) || pins.length > 8) + throw new Error('pins must contain at most eight constraints'); + const seen = new Set(); + for (const p of pins) { + if ( + !Number.isInteger(p.offset) || + p.offset < 4 || + p.offset + 32 > 65535 || + ![0, 1].includes(p.op) || + !/^0x[0-9a-fA-F]{64}$/.test(p.value) + ) + throw new Error('invalid argument pin'); + if (seen.has(p.offset)) throw new Error('duplicate pin offset'); + seen.add(p.offset); + } +} diff --git a/packages/core/src/lib/agentic/codec/rules.ts b/packages/core/src/lib/agentic/codec/rules.ts index 3b9988b0..e180f269 100644 --- a/packages/core/src/lib/agentic/codec/rules.ts +++ b/packages/core/src/lib/agentic/codec/rules.ts @@ -22,7 +22,7 @@ import { import { buildSession, encodeEnvelope, type SessionWire } from './session'; import { encodeUniversalRule, type ResolvedUniversalRule } from './universal'; import { encodeSvmTerms, type SvmTermsWire } from './svm-terms'; -import { SEND_OUTBOUND_SELECTOR } from '../contracts/v5'; +import { SEND_OUTBOUND_SELECTOR } from '../contracts/v6'; import type { UniversalTermsWire } from './universal-terms'; export function isSolanaRule(rule: InternalRule): rule is SolanaRule { @@ -81,7 +81,7 @@ export interface PreparedRule { svmTerms?: SvmTermsWire; } -/** Validate before signing. V5 permits several grants for the same agent/chain. */ +/** Validate before signing. V6 permits several grants for the same agent/chain. */ export function prepareRules( rules: readonly InternalRule[], ctx: RuleEncodeContext & { diff --git a/packages/core/src/lib/agentic/codec/session.ts b/packages/core/src/lib/agentic/codec/session.ts index fc98c1f6..1a7c839c 100644 --- a/packages/core/src/lib/agentic/codec/session.ts +++ b/packages/core/src/lib/agentic/codec/session.ts @@ -6,13 +6,13 @@ import { type Address, type Hex, } from 'viem'; -import { AGW_ABI } from '../contracts/abi/v5'; +import { AGW_ABI } from '../contracts/abi/v6'; import { agentConfig } from './ids'; import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; /** * The smartsessions `Session` a grant carries (DataTypes.sol:56-86, pinned - * v5). The wallet overwrites `salt` with its grant nonce, so the value + * v6). The wallet overwrites `salt` with its grant nonce, so the value * sent is irrelevant; it is always zero here. */ export interface SessionWire { @@ -44,7 +44,7 @@ const ZERO_SALT = `0x${'00'.repeat(32)}` as Hex; export const ENVELOPE_VERSION = 1; -/** V5 URP envelope: abi.encode(uint16(1), string chainNamespace, bytes body). */ +/** V6 URP envelope: abi.encode(uint16(1), string chainNamespace, bytes body). */ export function encodeEnvelope(chainNamespace: string, body: Hex): Hex { return encodeAbiParameters( [{ type: 'uint16' }, { type: 'string' }, { type: 'bytes' }], diff --git a/packages/core/src/lib/agentic/codec/svm-terms.ts b/packages/core/src/lib/agentic/codec/svm-terms.ts index dfae8ad7..3b0e10ab 100644 --- a/packages/core/src/lib/agentic/codec/svm-terms.ts +++ b/packages/core/src/lib/agentic/codec/svm-terms.ts @@ -1,4 +1,4 @@ -/** Internal v5 SVM wire representation; not a proposed public Rule API. */ +/** Internal v6 SVM wire representation; not a proposed public Rule API. */ import { decodeAbiParameters, encodeAbiParameters, @@ -192,7 +192,11 @@ export function validateSvmTerms(t: SvmTermsWire, nowSeconds: number): void { if (typeof r.dataless !== 'boolean') throw svmInvalid('dataless must be boolean'); integer(r.discriminatorLen, 8, 'discriminatorLen'); - integer(r.maxAccounts, SVM_LIMITS.accounts, 'maxAccounts'); + if (r.maxAccounts !== 255) { + integer(r.maxAccounts, SVM_LIMITS.accounts, 'maxAccounts'); + if (r.maxAccounts === 0) + throw svmInvalid('maxAccounts must be 1..64 or 255'); + } if (r.dataless !== (r.discriminatorLen === 0)) throw svmInvalid('dataless and discriminator length disagree'); if (isForbiddenSvmProgram(r.program, t)) @@ -227,7 +231,7 @@ export function validateSvmTerms(t: SvmTermsWire, nowSeconds: number): void { integer(p.accountIndex, SVM_LIMITS.accounts - 1, 'accountIndex'); exactHex(p.expected, 32, 'pin expected'); const count = t.programs[p.ruleIndex].maxAccounts; - if (count && p.accountIndex >= count) + if (count !== 255 && p.accountIndex >= count) throw svmInvalid('pin outside fixed account count'); const key = `${p.ruleIndex}:${p.accountIndex}`; if (positions.has(key)) throw svmInvalid('duplicate account pin'); diff --git a/packages/core/src/lib/agentic/codec/universal-terms.ts b/packages/core/src/lib/agentic/codec/universal-terms.ts index 4ac26304..21af4c21 100644 --- a/packages/core/src/lib/agentic/codec/universal-terms.ts +++ b/packages/core/src/lib/agentic/codec/universal-terms.ts @@ -1,3 +1,4 @@ +import { ARG_PIN_COMPONENTS, type ArgPinWire } from './pins'; import { decodeAbiParameters, encodeAbiParameters, @@ -11,6 +12,7 @@ export interface AssetCapWire { maxTotal: bigint; } export interface AllowedCallWire { + pins: readonly ArgPinWire[]; target: Address; selector: Hex; beneficiaryOffset: number; @@ -48,6 +50,7 @@ export const UNIVERSAL_TERMS_PARAM = { { name: 'beneficiaryOffset', type: 'uint16' }, { name: 'hasBeneficiary', type: 'bool' }, { name: 'maxValue', type: 'uint256' }, + { name: 'pins', type: 'tuple[]', components: ARG_PIN_COMPONENTS }, ], }, ], @@ -56,5 +59,8 @@ export function encodeUniversalTerms(terms: UniversalTermsWire): Hex { return encodeAbiParameters([UNIVERSAL_TERMS_PARAM], [terms]); } export function decodeUniversalTerms(body: Hex): UniversalTermsWire { - return decodeAbiParameters([UNIVERSAL_TERMS_PARAM], body)[0]; + return decodeAbiParameters( + [UNIVERSAL_TERMS_PARAM], + body + )[0] as UniversalTermsWire; } diff --git a/packages/core/src/lib/agentic/codec/universal.ts b/packages/core/src/lib/agentic/codec/universal.ts index d27b48ff..fa6b6d6f 100644 --- a/packages/core/src/lib/agentic/codec/universal.ts +++ b/packages/core/src/lib/agentic/codec/universal.ts @@ -1,3 +1,4 @@ +import { validatePins } from './pins'; import { getAddress, isAddress, type Address } from 'viem'; import { AgenticCapability, requireCapability } from '../capabilities'; import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; @@ -7,7 +8,7 @@ import { argumentOffset, rawOffset } from './abi-layout'; import { parseSelector } from './selectors'; import { AGENTIC_DEFAULTS, UINT256_MAX, withDefault } from './defaults'; import { buildSession, encodeEnvelope } from './session'; -import { SEND_OUTBOUND_SELECTOR } from '../contracts/v5'; +import { SEND_OUTBOUND_SELECTOR } from '../contracts/v6'; import { encodeUniversalTerms, type AssetCapWire, @@ -53,7 +54,8 @@ export function validateUniversalRuleShape( rule.allowedCalls.length > MAX_ALLOWED_CALLS ) throw invalid(`allowedCalls must contain 1..${MAX_ALLOWED_CALLS} entries`); - const seen = new Set(); + const seen = new Map(); + let pinCount = 0; rule.allowedCalls.forEach((call, i) => { if (!isAddress(call.target, { strict: false })) throw invalid(`allowedCalls[${i}].target is not an EVM address`); @@ -79,10 +81,24 @@ export function validateUniversalRuleShape( call.maxValue ?? AGENTIC_DEFAULTS.universal.allowedCallMaxValue.value, `allowedCalls[${i}].maxValue` ); + try { + validatePins(call.pins ?? []); + } catch (error) { + throw invalid((error as Error).message); + } + pinCount += call.pins?.length ?? 0; + if (pinCount > 32) + throw invalid('at most 32 pins across all allowed calls'); const key = `${call.target.toLowerCase()}:${parsed.selector}`; - if (seen.has(key)) - throw invalid(`allowedCalls[${i}] duplicates an earlier target/selector`); - seen.add(key); + const restricted = + !!call.pins?.length || + call.beneficiary !== undefined || + call.beneficiaryOffset !== undefined; + if (seen.has(key) && (!restricted || !seen.get(key))) + throw invalid( + 'an unpinned alternative would bypass restrictions for this target/selector' + ); + seen.set(key, restricted); }); const tokens = new Set(); rule.assets.forEach((a, i) => { @@ -137,6 +153,7 @@ export function encodeUniversalRule( assets: resolved.assets, maxGasPerCall: rule.maxGasPerCall, allowedCalls: rule.allowedCalls.map((call) => ({ + pins: call.pins ?? [], target: getAddress(call.target), selector: parseSelector(call.selector).selector, hasBeneficiary: @@ -200,6 +217,7 @@ export function universalTermsToRule( maxTotal: a.maxTotal, })), allowedCalls: terms.allowedCalls.map((c) => ({ + pins: [...c.pins], target: c.target, selector: c.selector, maxValue: c.maxValue, diff --git a/packages/core/src/lib/agentic/contracts/abi/v5/agent-validator.ts b/packages/core/src/lib/agentic/contracts/abi/v6/agent-validator.ts similarity index 97% rename from packages/core/src/lib/agentic/contracts/abi/v5/agent-validator.ts rename to packages/core/src/lib/agentic/contracts/abi/v6/agent-validator.ts index 069206f6..52e5ded3 100644 --- a/packages/core/src/lib/agentic/contracts/abi/v5/agent-validator.ts +++ b/packages/core/src/lib/agentic/contracts/abi/v6/agent-validator.ts @@ -1,6 +1,6 @@ // GENERATED by packages/core/scripts/agw-local/gen-abi.mjs — do not edit. // Source: packages/core/scripts/agw-local/abis/validator.json -// push-agentic-wallets@2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb +// push-agentic-wallets@ffd567d3e49b2d27c6f50ad36093274dbac3090f // sha256(AgentValidator.json) = a4570ddc373241580de8742cbb3d9f2c837094c65bfd1cdd52243ca0c38196fd export const AGENT_VALIDATOR_ABI = [ { diff --git a/packages/core/src/lib/agentic/contracts/abi/v5/agw-factory.ts b/packages/core/src/lib/agentic/contracts/abi/v6/agw-factory.ts similarity index 66% rename from packages/core/src/lib/agentic/contracts/abi/v5/agw-factory.ts rename to packages/core/src/lib/agentic/contracts/abi/v6/agw-factory.ts index 45519e58..215cf6b2 100644 --- a/packages/core/src/lib/agentic/contracts/abi/v5/agw-factory.ts +++ b/packages/core/src/lib/agentic/contracts/abi/v6/agw-factory.ts @@ -1,7 +1,7 @@ // GENERATED by packages/core/scripts/agw-local/gen-abi.mjs — do not edit. // Source: packages/core/scripts/agw-local/abis/factory.json -// push-agentic-wallets@2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb -// sha256(AGWFactory.json) = b65f66a1556d2a9ddf9aabe9f595c685c2aada436772892f5a40fb1eec846397 +// push-agentic-wallets@ffd567d3e49b2d27c6f50ad36093274dbac3090f +// sha256(AGWFactory.json) = 08588f8870335492c5abeee32eec6a9bb050f81e234fdd58bbf389c6e9074a12 export const AGW_FACTORY_ABI = [ { "type": "function", @@ -95,6 +95,364 @@ export const AGW_FACTORY_ABI = [ "outputs": [], "stateMutability": "nonpayable" }, + { + "type": "function", + "name": "createWallet", + "inputs": [ + { + "name": "label", + "type": "string", + "internalType": "string" + }, + { + "name": "rules", + "type": "tuple[]", + "internalType": "struct Session[]", + "components": [ + { + "name": "sessionValidator", + "type": "address", + "internalType": "contract ISessionValidator" + }, + { + "name": "sessionValidatorInitData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "erc7739Policies", + "type": "tuple", + "internalType": "struct ERC7739Data", + "components": [ + { + "name": "allowedERC7739Content", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNames", + "type": "string[]", + "internalType": "string[]" + } + ] + }, + { + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "actions", + "type": "tuple[]", + "internalType": "struct ActionData[]", + "components": [ + { + "name": "actionTargetSelector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "actionTarget", + "type": "address", + "internalType": "address" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "permitERC4337Paymaster", + "type": "bool", + "internalType": "bool" + } + ] + } + ], + "outputs": [ + { + "name": "wallet", + "type": "address", + "internalType": "address" + }, + { + "name": "rulesIds", + "type": "bytes32[]", + "internalType": "bytes32[]" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "createWalletWithSig", + "inputs": [ + { + "name": "intent", + "type": "tuple", + "internalType": "struct OwnerIntent", + "components": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "wallet", + "type": "address", + "internalType": "address" + }, + { + "name": "executor", + "type": "address", + "internalType": "address" + }, + { + "name": "index", + "type": "uint96", + "internalType": "uint96" + }, + { + "name": "sessionHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "mode", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "execCalldataHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "nonceKey", + "type": "uint192", + "internalType": "uint192" + }, + { + "name": "nonceSeq", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "grantNonce", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "deadline", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "signerChainId", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "sig", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "label", + "type": "string", + "internalType": "string" + }, + { + "name": "rules", + "type": "tuple[]", + "internalType": "struct Session[]", + "components": [ + { + "name": "sessionValidator", + "type": "address", + "internalType": "contract ISessionValidator" + }, + { + "name": "sessionValidatorInitData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "erc7739Policies", + "type": "tuple", + "internalType": "struct ERC7739Data", + "components": [ + { + "name": "allowedERC7739Content", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNames", + "type": "string[]", + "internalType": "string[]" + } + ] + }, + { + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "actions", + "type": "tuple[]", + "internalType": "struct ActionData[]", + "components": [ + { + "name": "actionTargetSelector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "actionTarget", + "type": "address", + "internalType": "address" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "permitERC4337Paymaster", + "type": "bool", + "internalType": "bool" + } + ] + } + ], + "outputs": [ + { + "name": "wallet", + "type": "address", + "internalType": "address" + }, + { + "name": "rulesIds", + "type": "bytes32[]", + "internalType": "bytes32[]" + } + ], + "stateMutability": "nonpayable" + }, { "type": "function", "name": "defaultAdmin", @@ -1011,6 +1369,28 @@ export const AGW_FACTORY_ABI = [ } ] }, + { + "type": "error", + "name": "IntentGrantNonceNotZero", + "inputs": [ + { + "name": "provided", + "type": "uint64", + "internalType": "uint64" + } + ] + }, + { + "type": "error", + "name": "IntentRulesMismatch", + "inputs": [ + { + "name": "actual", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, { "type": "error", "name": "IntentWalletMismatch", @@ -1080,6 +1460,17 @@ export const AGW_FACTORY_ABI = [ } ] }, + { + "type": "error", + "name": "TooManyInitialRules", + "inputs": [ + { + "name": "count", + "type": "uint256", + "internalType": "uint256" + } + ] + }, { "type": "error", "name": "UUPSUnauthorizedCallContext", diff --git a/packages/core/src/lib/agentic/contracts/abi/v5/agw.ts b/packages/core/src/lib/agentic/contracts/abi/v6/agw.ts similarity index 89% rename from packages/core/src/lib/agentic/contracts/abi/v5/agw.ts rename to packages/core/src/lib/agentic/contracts/abi/v6/agw.ts index d3bed329..0ec09cc8 100644 --- a/packages/core/src/lib/agentic/contracts/abi/v5/agw.ts +++ b/packages/core/src/lib/agentic/contracts/abi/v6/agw.ts @@ -1,7 +1,7 @@ // GENERATED by packages/core/scripts/agw-local/gen-abi.mjs — do not edit. // Source: packages/core/scripts/agw-local/abis/wallet.json -// push-agentic-wallets@2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb -// sha256(AGW.json) = 6a145964d6c43eaa6223dc8f3d59a540ac0c2f447f25c3a99007eea25de9c695 +// push-agentic-wallets@ffd567d3e49b2d27c6f50ad36093274dbac3090f +// sha256(AGW.json) = 76705e5a25b10d3a84f867f983c3e4f5adfc881fb0d65710fb8684df2ea7abd3 export const AGW_ABI = [ { "type": "receive", @@ -645,9 +645,134 @@ export const AGW_ABI = [ "name": "label_", "type": "string", "internalType": "string" + }, + { + "name": "rules", + "type": "tuple[]", + "internalType": "struct Session[]", + "components": [ + { + "name": "sessionValidator", + "type": "address", + "internalType": "contract ISessionValidator" + }, + { + "name": "sessionValidatorInitData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "erc7739Policies", + "type": "tuple", + "internalType": "struct ERC7739Data", + "components": [ + { + "name": "allowedERC7739Content", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNames", + "type": "string[]", + "internalType": "string[]" + } + ] + }, + { + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "actions", + "type": "tuple[]", + "internalType": "struct ActionData[]", + "components": [ + { + "name": "actionTargetSelector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "actionTarget", + "type": "address", + "internalType": "address" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "permitERC4337Paymaster", + "type": "bool", + "internalType": "bool" + } + ] + } + ], + "outputs": [ + { + "name": "rulesIds", + "type": "bytes32[]", + "internalType": "bytes32[]" } ], - "outputs": [], "stateMutability": "nonpayable" }, { diff --git a/packages/core/src/lib/agentic/contracts/abi/v5/index.ts b/packages/core/src/lib/agentic/contracts/abi/v6/index.ts similarity index 69% rename from packages/core/src/lib/agentic/contracts/abi/v5/index.ts rename to packages/core/src/lib/agentic/contracts/abi/v6/index.ts index fa7ddd6a..b0883d13 100644 --- a/packages/core/src/lib/agentic/contracts/abi/v5/index.ts +++ b/packages/core/src/lib/agentic/contracts/abi/v6/index.ts @@ -1,6 +1,6 @@ // GENERATED by packages/core/scripts/agw-local/gen-abi.mjs — do not edit. -// Review generation v5: Donut v5 deployment; source 2e61e13. -export const V5_SOURCE_COMMIT = '2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb' as const; +// Review generation v6: Donut v6 deployment; source ffd567d. +export const V6_SOURCE_COMMIT = 'ffd567d3e49b2d27c6f50ad36093274dbac3090f' as const; export { AGW_ABI } from './agw'; export { AGW_FACTORY_ABI } from './agw-factory'; export { UNIVERSAL_RULES_POLICY_ABI } from './universal-rules-policy'; diff --git a/packages/core/src/lib/agentic/contracts/abi/v5/smart-session.ts b/packages/core/src/lib/agentic/contracts/abi/v6/smart-session.ts similarity index 99% rename from packages/core/src/lib/agentic/contracts/abi/v5/smart-session.ts rename to packages/core/src/lib/agentic/contracts/abi/v6/smart-session.ts index 20e207b1..3fe24ed2 100644 --- a/packages/core/src/lib/agentic/contracts/abi/v5/smart-session.ts +++ b/packages/core/src/lib/agentic/contracts/abi/v6/smart-session.ts @@ -1,6 +1,6 @@ // GENERATED by packages/core/scripts/agw-local/gen-abi.mjs — do not edit. // Source: packages/core/scripts/agw-local/abis/engine.json -// push-agentic-wallets@2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb +// push-agentic-wallets@ffd567d3e49b2d27c6f50ad36093274dbac3090f // sha256(SmartSession.json) = 6e5d9cea4dbed01f06af913c1e093743b86b7432195f4a4bf90fb94b282c51b2 export const SMART_SESSION_ABI = [ { diff --git a/packages/core/src/lib/agentic/contracts/abi/v5/universal-rules-policy.ts b/packages/core/src/lib/agentic/contracts/abi/v6/universal-rules-policy.ts similarity index 97% rename from packages/core/src/lib/agentic/contracts/abi/v5/universal-rules-policy.ts rename to packages/core/src/lib/agentic/contracts/abi/v6/universal-rules-policy.ts index 5b0e2f34..089855b0 100644 --- a/packages/core/src/lib/agentic/contracts/abi/v5/universal-rules-policy.ts +++ b/packages/core/src/lib/agentic/contracts/abi/v6/universal-rules-policy.ts @@ -1,7 +1,7 @@ // GENERATED by packages/core/scripts/agw-local/gen-abi.mjs — do not edit. // Source: packages/core/scripts/agw-local/abis/policy.json -// push-agentic-wallets@2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb -// sha256(UniversalRulesPolicy.json) = c7e3cd5c7f8e47be217c77ebebde4c090903cea7db63024838e434eb6f1fd77b +// push-agentic-wallets@ffd567d3e49b2d27c6f50ad36093274dbac3090f +// sha256(UniversalRulesPolicy.json) = a07661d19b19656afdea560275d45669a908cd96646817884295e0017560f299 export const UNIVERSAL_RULES_POLICY_ABI = [ { "type": "function", @@ -280,6 +280,28 @@ export const UNIVERSAL_RULES_POLICY_ABI = [ "name": "maxValue", "type": "uint256", "internalType": "uint256" + }, + { + "name": "pins", + "type": "tuple[]", + "internalType": "struct ArgPin[]", + "components": [ + { + "name": "offset", + "type": "uint16", + "internalType": "uint16" + }, + { + "name": "op", + "type": "uint8", + "internalType": "enum PinOp" + }, + { + "name": "value", + "type": "bytes32", + "internalType": "bytes32" + } + ] } ] } @@ -443,7 +465,12 @@ export const UNIVERSAL_RULES_POLICY_ABI = [ "internalType": "uint16" }, { - "name": "expected", + "name": "op", + "type": "uint8", + "internalType": "enum PinOp" + }, + { + "name": "value", "type": "bytes32", "internalType": "bytes32" } @@ -980,15 +1007,15 @@ export const UNIVERSAL_RULES_POLICY_ABI = [ }, { "type": "error", - "name": "AmbiguousRule", + "name": "AmountExceedsCap", "inputs": [ { - "name": "i", + "name": "amount", "type": "uint256", "internalType": "uint256" }, { - "name": "j", + "name": "cap", "type": "uint256", "internalType": "uint256" } @@ -996,26 +1023,20 @@ export const UNIVERSAL_RULES_POLICY_ABI = [ }, { "type": "error", - "name": "AmountExceedsCap", + "name": "ArgPinAboveMax", "inputs": [ { - "name": "amount", + "name": "actual", "type": "uint256", "internalType": "uint256" }, { - "name": "cap", + "name": "index", "type": "uint256", "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "AmountExceedsU64", - "inputs": [ + }, { - "name": "amount", + "name": "max", "type": "uint256", "internalType": "uint256" } @@ -1096,22 +1117,6 @@ export const UNIVERSAL_RULES_POLICY_ABI = [ } ] }, - { - "type": "error", - "name": "BeneficiaryMismatch", - "inputs": [ - { - "name": "expected", - "type": "address", - "internalType": "address" - }, - { - "name": "actual", - "type": "address", - "internalType": "address" - } - ] - }, { "type": "error", "name": "CallLimitReached", @@ -1203,27 +1208,6 @@ export const UNIVERSAL_RULES_POLICY_ABI = [ } ] }, - { - "type": "error", - "name": "CeaAccountAtUnpinnedIndex", - "inputs": [ - { - "name": "accountIndex", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "account", - "type": "bytes32", - "internalType": "bytes32" - } - ] - }, - { - "type": "error", - "name": "CeaAccountsMissExpectedCEA", - "inputs": [] - }, { "type": "error", "name": "ChainMismatch", @@ -1240,22 +1224,6 @@ export const UNIVERSAL_RULES_POLICY_ABI = [ } ] }, - { - "type": "error", - "name": "DiscriminatorLenOutOfRange", - "inputs": [ - { - "name": "rule", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "len", - "type": "uint8", - "internalType": "uint8" - } - ] - }, { "type": "error", "name": "DuplicateAsset", @@ -1267,22 +1235,6 @@ export const UNIVERSAL_RULES_POLICY_ABI = [ } ] }, - { - "type": "error", - "name": "DuplicateSvmPin", - "inputs": [ - { - "name": "first", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "second", - "type": "uint256", - "internalType": "uint256" - } - ] - }, { "type": "error", "name": "EmptyChain", @@ -1299,54 +1251,6 @@ export const UNIVERSAL_RULES_POLICY_ABI = [ } ] }, - { - "type": "error", - "name": "ForbiddenProgramInAllowList", - "inputs": [ - { - "name": "rule", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "program", - "type": "bytes32", - "internalType": "bytes32" - } - ] - }, - { - "type": "error", - "name": "ForbiddenTargetProgram", - "inputs": [ - { - "name": "program", - "type": "bytes32", - "internalType": "bytes32" - } - ] - }, - { - "type": "error", - "name": "InnerValueExceedsAllowance", - "inputs": [ - { - "name": "index", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "value", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "maxValue", - "type": "uint256", - "internalType": "uint256" - } - ] - }, { "type": "error", "name": "InvalidAsset", @@ -1358,17 +1262,6 @@ export const UNIVERSAL_RULES_POLICY_ABI = [ } ] }, - { - "type": "error", - "name": "InvalidCeaAccount", - "inputs": [ - { - "name": "index", - "type": "uint256", - "internalType": "uint256" - } - ] - }, { "type": "error", "name": "InvalidConfigField", @@ -1417,11 +1310,6 @@ export const UNIVERSAL_RULES_POLICY_ABI = [ } ] }, - { - "type": "error", - "name": "InvalidSvmConfigField", - "inputs": [] - }, { "type": "error", "name": "InvalidTarget", @@ -1449,17 +1337,6 @@ export const UNIVERSAL_RULES_POLICY_ABI = [ } ] }, - { - "type": "error", - "name": "MalformedSvmPayload", - "inputs": [ - { - "name": "code", - "type": "uint8", - "internalType": "uint8" - } - ] - }, { "type": "error", "name": "NativeAmountExceedsCap", @@ -1555,76 +1432,11 @@ export const UNIVERSAL_RULES_POLICY_ABI = [ } ] }, - { - "type": "error", - "name": "ProgramListOutOfRange", - "inputs": [ - { - "name": "length", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "ProgramNotAllowed", - "inputs": [ - { - "name": "program", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "discriminator", - "type": "bytes8", - "internalType": "bytes8" - } - ] - }, { "type": "error", "name": "RecipientMustBeEmpty", "inputs": [] }, - { - "type": "error", - "name": "RecipientNotPubkey", - "inputs": [ - { - "name": "length", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "RecipientTargetMismatch", - "inputs": [ - { - "name": "recipient", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "target", - "type": "bytes32", - "internalType": "bytes32" - } - ] - }, - { - "type": "error", - "name": "RuleWithoutPin", - "inputs": [ - { - "name": "rule", - "type": "uint256", - "internalType": "uint256" - } - ] - }, { "type": "error", "name": "RulesExpired", @@ -1686,73 +1498,85 @@ export const UNIVERSAL_RULES_POLICY_ABI = [ }, { "type": "error", - "name": "SvmAccountCountBelowPin", + "name": "TargetMismatch", "inputs": [ { - "name": "pin", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "count", - "type": "uint256", - "internalType": "uint256" + "name": "actual", + "type": "address", + "internalType": "address" }, { - "name": "needed", - "type": "uint8", - "internalType": "uint8" + "name": "expected", + "type": "address", + "internalType": "address" } ] }, { "type": "error", - "name": "SvmAccountCountMismatch", + "name": "TooManyAllowedCallPins", "inputs": [ { - "name": "count", + "name": "total", "type": "uint256", "internalType": "uint256" - }, - { - "name": "expected", - "type": "uint8", - "internalType": "uint8" } ] }, { "type": "error", - "name": "SvmAccountPinMismatch", + "name": "TooManyPins", "inputs": [ { - "name": "pin", + "name": "count", "type": "uint256", "internalType": "uint256" - }, + } + ] + }, + { + "type": "error", + "name": "TotalNativeAmountExceeded", + "inputs": [ { - "name": "accountIndex", - "type": "uint8", - "internalType": "uint8" + "name": "newSpent", + "type": "uint256", + "internalType": "uint256" }, { - "name": "expected", - "type": "bytes32", - "internalType": "bytes32" + "name": "cap", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "TotalSpendCapExceeded", + "inputs": [ + { + "name": "wouldBeTotal", + "type": "uint256", + "internalType": "uint256" }, { - "name": "actual", - "type": "bytes32", - "internalType": "bytes32" + "name": "cap", + "type": "uint256", + "internalType": "uint256" } ] }, { "type": "error", - "name": "SvmAccountsOutOfRange", + "name": "TotalValueExceeded", "inputs": [ { - "name": "count", + "name": "newSpent", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "cap", "type": "uint256", "internalType": "uint256" } @@ -1760,20 +1584,42 @@ export const UNIVERSAL_RULES_POLICY_ABI = [ }, { "type": "error", - "name": "SvmDataCeilingExceeded", + "name": "UncappedGasSwapRejected", + "inputs": [] + }, + { + "type": "error", + "name": "UnsupportedEnvelopeVersion", "inputs": [ { - "name": "pin", + "name": "version", "type": "uint256", "internalType": "uint256" - }, + } + ] + }, + { + "type": "error", + "name": "UnsupportedNamespace", + "inputs": [ { - "name": "actual", + "name": "chainHash", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "ValueExceedsCap", + "inputs": [ + { + "name": "value", "type": "uint256", "internalType": "uint256" }, { - "name": "ceiling", + "name": "cap", "type": "uint256", "internalType": "uint256" } @@ -1781,20 +1627,68 @@ export const UNIVERSAL_RULES_POLICY_ABI = [ }, { "type": "error", - "name": "SvmDataFloorNotMet", + "name": "ValueOnlyCalldataNotEmpty", "inputs": [ { - "name": "pin", + "name": "length", "type": "uint256", "internalType": "uint256" - }, + } + ] + }, + { + "type": "error", + "name": "ValueOnlyWithAmountRule", + "inputs": [] + }, + { + "type": "error", + "name": "ValueOnlyWithPins", + "inputs": [] + }, + { + "type": "error", + "name": "WrongModeForCall", + "inputs": [ + { + "name": "actual", + "type": "uint8", + "internalType": "enum RulesType" + } + ] + }, + { + "type": "error", + "name": "WrongVmForCall", + "inputs": [ { "name": "actual", + "type": "uint8", + "internalType": "enum VmFamily" + } + ] + }, + { + "type": "error", + "name": "ZeroAddress", + "inputs": [] + }, + { + "type": "error", + "name": "ZeroMaxCalls", + "inputs": [] + }, + { + "type": "error", + "name": "AmbiguousRule", + "inputs": [ + { + "name": "i", "type": "uint256", "internalType": "uint256" }, { - "name": "floor", + "name": "j", "type": "uint256", "internalType": "uint256" } @@ -1802,10 +1696,10 @@ export const UNIVERSAL_RULES_POLICY_ABI = [ }, { "type": "error", - "name": "SvmDataPinInvalid", + "name": "AmountExceedsU64", "inputs": [ { - "name": "pin", + "name": "amount", "type": "uint256", "internalType": "uint256" } @@ -1813,20 +1707,15 @@ export const UNIVERSAL_RULES_POLICY_ABI = [ }, { "type": "error", - "name": "SvmDataPinMismatch", + "name": "CeaAccountAtUnpinnedIndex", "inputs": [ { - "name": "pin", + "name": "accountIndex", "type": "uint256", "internalType": "uint256" }, { - "name": "expected", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "actual", + "name": "account", "type": "bytes32", "internalType": "bytes32" } @@ -1834,46 +1723,74 @@ export const UNIVERSAL_RULES_POLICY_ABI = [ }, { "type": "error", - "name": "SvmDataRatioNotMet", + "name": "CeaAccountsMissExpectedCEA", + "inputs": [] + }, + { + "type": "error", + "name": "DiscriminatorLenOutOfRange", "inputs": [ { - "name": "pin", + "name": "rule", "type": "uint256", "internalType": "uint256" }, { - "name": "a", + "name": "len", + "type": "uint8", + "internalType": "uint8" + } + ] + }, + { + "type": "error", + "name": "DuplicateSvmPin", + "inputs": [ + { + "name": "first", "type": "uint256", "internalType": "uint256" }, { - "name": "b", + "name": "second", "type": "uint256", "internalType": "uint256" - }, - { - "name": "num", - "type": "uint64", - "internalType": "uint64" - }, - { - "name": "den", - "type": "uint64", - "internalType": "uint64" } ] }, { "type": "error", - "name": "SvmDataTooShortForPin", + "name": "ForbiddenProgramInAllowList", "inputs": [ { - "name": "pin", + "name": "rule", "type": "uint256", "internalType": "uint256" }, { - "name": "ixLen", + "name": "program", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "ForbiddenTargetProgram", + "inputs": [ + { + "name": "program", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "InvalidCeaAccount", + "inputs": [ + { + "name": "index", "type": "uint256", "internalType": "uint256" } @@ -1881,10 +1798,15 @@ export const UNIVERSAL_RULES_POLICY_ABI = [ }, { "type": "error", - "name": "SvmInstructionNotExecute", + "name": "InvalidSvmConfigField", + "inputs": [] + }, + { + "type": "error", + "name": "MalformedSvmPayload", "inputs": [ { - "name": "instructionId", + "name": "code", "type": "uint8", "internalType": "uint8" } @@ -1892,7 +1814,7 @@ export const UNIVERSAL_RULES_POLICY_ABI = [ }, { "type": "error", - "name": "SvmIxDataTooLong", + "name": "ProgramListOutOfRange", "inputs": [ { "name": "length", @@ -1903,28 +1825,61 @@ export const UNIVERSAL_RULES_POLICY_ABI = [ }, { "type": "error", - "name": "SvmMaxAccountsOutOfRange", + "name": "ProgramNotAllowed", "inputs": [ { - "name": "rule", + "name": "program", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "discriminator", + "type": "bytes8", + "internalType": "bytes8" + } + ] + }, + { + "type": "error", + "name": "RecipientNotPubkey", + "inputs": [ + { + "name": "length", "type": "uint256", "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "RecipientTargetMismatch", + "inputs": [ + { + "name": "recipient", + "type": "bytes32", + "internalType": "bytes32" }, { - "name": "maxAccounts", - "type": "uint8", - "internalType": "uint8" + "name": "target", + "type": "bytes32", + "internalType": "bytes32" } ] }, { "type": "error", - "name": "SvmPayloadEmpty", - "inputs": [] + "name": "RuleWithoutPin", + "inputs": [ + { + "name": "rule", + "type": "uint256", + "internalType": "uint256" + } + ] }, { "type": "error", - "name": "SvmPinIndexOutOfRange", + "name": "SvmAccountCountBelowPin", "inputs": [ { "name": "pin", @@ -1932,7 +1887,12 @@ export const UNIVERSAL_RULES_POLICY_ABI = [ "internalType": "uint256" }, { - "name": "accountIndex", + "name": "count", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "needed", "type": "uint8", "internalType": "uint8" } @@ -1940,15 +1900,15 @@ export const UNIVERSAL_RULES_POLICY_ABI = [ }, { "type": "error", - "name": "SvmPinRuleOutOfRange", + "name": "SvmAccountCountMismatch", "inputs": [ { - "name": "pin", + "name": "count", "type": "uint256", "internalType": "uint256" }, { - "name": "rule", + "name": "expected", "type": "uint8", "internalType": "uint8" } @@ -1956,23 +1916,33 @@ export const UNIVERSAL_RULES_POLICY_ABI = [ }, { "type": "error", - "name": "TargetMismatch", + "name": "SvmAccountPinMismatch", "inputs": [ { - "name": "actual", - "type": "address", - "internalType": "address" + "name": "pin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "accountIndex", + "type": "uint8", + "internalType": "uint8" }, { "name": "expected", - "type": "address", - "internalType": "address" + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "actual", + "type": "bytes32", + "internalType": "bytes32" } ] }, { "type": "error", - "name": "TooManyCeaAccounts", + "name": "SvmAccountsOutOfRange", "inputs": [ { "name": "count", @@ -1983,10 +1953,20 @@ export const UNIVERSAL_RULES_POLICY_ABI = [ }, { "type": "error", - "name": "TooManyPins", + "name": "SvmDataCeilingExceeded", "inputs": [ { - "name": "count", + "name": "pin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "actual", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "ceiling", "type": "uint256", "internalType": "uint256" } @@ -1994,10 +1974,20 @@ export const UNIVERSAL_RULES_POLICY_ABI = [ }, { "type": "error", - "name": "TooManySvmDataPins", + "name": "SvmDataFloorNotMet", "inputs": [ { - "name": "count", + "name": "pin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "actual", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "floor", "type": "uint256", "internalType": "uint256" } @@ -2005,10 +1995,10 @@ export const UNIVERSAL_RULES_POLICY_ABI = [ }, { "type": "error", - "name": "TooManySvmPins", + "name": "SvmDataPinInvalid", "inputs": [ { - "name": "count", + "name": "pin", "type": "uint256", "internalType": "uint256" } @@ -2016,47 +2006,67 @@ export const UNIVERSAL_RULES_POLICY_ABI = [ }, { "type": "error", - "name": "TotalNativeAmountExceeded", + "name": "SvmDataPinMismatch", "inputs": [ { - "name": "newSpent", + "name": "pin", "type": "uint256", "internalType": "uint256" }, { - "name": "cap", - "type": "uint256", - "internalType": "uint256" + "name": "expected", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "actual", + "type": "bytes32", + "internalType": "bytes32" } ] }, { "type": "error", - "name": "TotalSpendCapExceeded", + "name": "SvmDataRatioNotMet", "inputs": [ { - "name": "wouldBeTotal", + "name": "pin", "type": "uint256", "internalType": "uint256" }, { - "name": "cap", + "name": "a", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "b", "type": "uint256", "internalType": "uint256" + }, + { + "name": "num", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "den", + "type": "uint64", + "internalType": "uint64" } ] }, { "type": "error", - "name": "TotalValueExceeded", + "name": "SvmDataTooShortForPin", "inputs": [ { - "name": "newSpent", + "name": "pin", "type": "uint256", "internalType": "uint256" }, { - "name": "cap", + "name": "ixLen", "type": "uint256", "internalType": "uint256" } @@ -2064,15 +2074,21 @@ export const UNIVERSAL_RULES_POLICY_ABI = [ }, { "type": "error", - "name": "UncappedGasSwapRejected", - "inputs": [] + "name": "SvmInstructionNotExecute", + "inputs": [ + { + "name": "instructionId", + "type": "uint8", + "internalType": "uint8" + } + ] }, { "type": "error", - "name": "UnsupportedEnvelopeVersion", + "name": "SvmIxDataTooLong", "inputs": [ { - "name": "version", + "name": "length", "type": "uint256", "internalType": "uint256" } @@ -2080,77 +2096,88 @@ export const UNIVERSAL_RULES_POLICY_ABI = [ }, { "type": "error", - "name": "UnsupportedNamespace", + "name": "SvmMaxAccountsOutOfRange", "inputs": [ { - "name": "chainHash", - "type": "bytes32", - "internalType": "bytes32" + "name": "rule", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxAccounts", + "type": "uint8", + "internalType": "uint8" } ] }, { "type": "error", - "name": "ValueExceedsCap", + "name": "SvmPayloadEmpty", + "inputs": [] + }, + { + "type": "error", + "name": "SvmPinIndexOutOfRange", "inputs": [ { - "name": "value", + "name": "pin", "type": "uint256", "internalType": "uint256" }, { - "name": "cap", - "type": "uint256", - "internalType": "uint256" + "name": "accountIndex", + "type": "uint8", + "internalType": "uint8" } ] }, { "type": "error", - "name": "ValueOnlyCalldataNotEmpty", + "name": "SvmPinRuleOutOfRange", "inputs": [ { - "name": "length", + "name": "pin", "type": "uint256", "internalType": "uint256" + }, + { + "name": "rule", + "type": "uint8", + "internalType": "uint8" } ] }, { "type": "error", - "name": "ValueOnlyWithAmountRule", - "inputs": [] - }, - { - "type": "error", - "name": "ValueOnlyWithPins", - "inputs": [] - }, - { - "type": "error", - "name": "WrongModeForCall", + "name": "TooManyCeaAccounts", "inputs": [ { - "name": "actual", - "type": "uint8", - "internalType": "enum RulesType" + "name": "count", + "type": "uint256", + "internalType": "uint256" } ] }, { "type": "error", - "name": "WrongVmForCall", + "name": "TooManySvmDataPins", "inputs": [ { - "name": "actual", - "type": "uint8", - "internalType": "enum VmFamily" + "name": "count", + "type": "uint256", + "internalType": "uint256" } ] }, { "type": "error", - "name": "ZeroAddress", - "inputs": [] + "name": "TooManySvmPins", + "inputs": [ + { + "name": "count", + "type": "uint256", + "internalType": "uint256" + } + ] } ] as const; diff --git a/packages/core/src/lib/agentic/contracts/donut-v5.ts b/packages/core/src/lib/agentic/contracts/donut-v5.ts deleted file mode 100644 index c75425ea..00000000 --- a/packages/core/src/lib/agentic/contracts/donut-v5.ts +++ /dev/null @@ -1,13 +0,0 @@ -import type { Address } from 'viem'; - -/** Source 2e61e13; code/proxy wiring checked at Donut block 23991912. */ -export const V5_SOURCE_COMMIT = '2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb'; -export const DONUT_V5_START_BLOCK = BigInt(23989983); -export const DONUT_V5_ADDRESSES = { - factory: '0x8137F96A50EBF41d904e3678c84c391a0D1BCcc5', - walletImplementation: '0x4D459Da499C14548aa16c46c57fD92880A88EBb4', - sessionEngine: '0x165A5E6782f39D30B38c7D97e1303e4CB2aD102a', - rulesPolicy: '0x603E7f0aF6e1aAFf46DDfb28b1e99364f8BC59af', - sessionValidator: '0x068EE2388475A98EE1f5a434C58bFF3444fffFe6', - gateway: '0x00000000000000000000000000000000000000C1', -} as const satisfies Record; diff --git a/packages/core/src/lib/agentic/contracts/donut-v6.ts b/packages/core/src/lib/agentic/contracts/donut-v6.ts new file mode 100644 index 00000000..b1899218 --- /dev/null +++ b/packages/core/src/lib/agentic/contracts/donut-v6.ts @@ -0,0 +1,13 @@ +import type { Address } from 'viem'; + +/** Source ffd567d; code sizes and wiring checked at Donut block 24244801. */ +export const V6_SOURCE_COMMIT = 'ffd567d3e49b2d27c6f50ad36093274dbac3090f'; +export const DONUT_V6_START_BLOCK = BigInt(24229957); +export const DONUT_V6_ADDRESSES = { + factory: '0xFBBEB6a365178fAaA81A9789a5f64b300c37e5bc', + walletImplementation: '0x536D3EA48219ff743ac663C6c224920e9eB476A5', + sessionEngine: '0xf63DC0628fe1B25049FE3E3a3585Ef051CB98c1d', + rulesPolicy: '0xBA32e7A1500cb34311a31127bcD40CA52C8CFd36', + sessionValidator: '0xBf08d8335c1cE41a577DB70666816027814737dD', + gateway: '0x00000000000000000000000000000000000000C1', +} as const satisfies Record; diff --git a/packages/core/src/lib/agentic/contracts/v5.ts b/packages/core/src/lib/agentic/contracts/v6.ts similarity index 88% rename from packages/core/src/lib/agentic/contracts/v5.ts rename to packages/core/src/lib/agentic/contracts/v6.ts index 444dc5de..6d9a3b97 100644 --- a/packages/core/src/lib/agentic/contracts/v5.ts +++ b/packages/core/src/lib/agentic/contracts/v6.ts @@ -18,7 +18,7 @@ import { AGW_FACTORY_ABI, SMART_SESSION_ABI, UNIVERSAL_RULES_POLICY_ABI, -} from './abi/v5'; +} from './abi/v6'; import type { SessionWire } from '../codec/session'; import type { CheckpointKind } from '../agentic.types'; import type { NativeTermsWire } from '../codec/native'; @@ -26,7 +26,7 @@ import type { UniversalTermsWire } from '../codec/universal-terms'; import type { SvmTermsWire } from '../codec/svm-terms'; /** - * Contract adapter for the reviewed v5 ABI generation. All version- + * Contract adapter for the reviewed v6 ABI generation. All version- * sensitive encoding, decoding and view names live here; callers never touch * a raw ABI. A future generation gets its own adapter implementing the same * interface. @@ -104,8 +104,8 @@ const EXECUTION_TUPLE = [ }, ] as const; -export const v5 = { - id: 'v5', +export const v6 = { + id: 'v6', abis: { wallet: AGW_ABI, factory: AGW_FACTORY_ABI, @@ -178,6 +178,39 @@ export const v5 = { ], }); }, + encodeCreateWalletAt( + owner: Address, + index: bigint, + wallet: Address, + label: string, + rules: readonly SessionWire[] + ): Hex { + const zero32 = `0x${'00'.repeat(32)}` as Hex; + const zeroAddress = '0x0000000000000000000000000000000000000000' as Address; + return encodeFunctionData({ + abi: AGW_FACTORY_ABI, + functionName: 'createWalletWithSig', + args: [ + { + owner, + wallet, + executor: zeroAddress, + index, + sessionHash: zero32, + mode: zero32, + execCalldataHash: zero32, + nonceKey: BigInt(0), + nonceSeq: BigInt(0), + grantNonce: BigInt(0), + deadline: 0, + signerChainId: BigInt(0), + }, + '0x', + label, + rules as never, + ], + }); + }, encodeGrantRules(session: SessionWire): Hex { return encodeFunctionData({ abi: AGW_ABI, @@ -219,7 +252,7 @@ export const v5 = { return encodeFunctionData({ abi: AGW_ABI, functionName: 'execute', - args: [MODE_SINGLE, v5.packSingle(calls[0])], + args: [MODE_SINGLE, v6.packSingle(calls[0])], }); } const batch = encodeAbiParameters(EXECUTION_TUPLE, [ @@ -239,7 +272,7 @@ export const v5 = { return encodeFunctionData({ abi: AGW_ABI, functionName: 'executeAsAgent', - args: [rulesId, MODE_SINGLE, v5.packSingle(call)], + args: [rulesId, MODE_SINGLE, v6.packSingle(call)], }); }, encodeAssertSpentNative( @@ -312,7 +345,7 @@ export const v5 = { return k; }, parseWalletDeployed(logs: readonly Log[], factory: Address) { - return decodeMatching(logs, factory, v5.events.walletDeployed).map( + return decodeMatching(logs, factory, v6.events.walletDeployed).map( (args) => ({ owner: getAddress(args['owner'] as Address), index: BigInt(args['index'] as bigint), @@ -322,14 +355,14 @@ export const v5 = { ); }, parseRulesGranted(logs: readonly Log[], wallet: Address) { - return decodeMatching(logs, wallet, v5.events.rulesGranted).map((args) => ({ + return decodeMatching(logs, wallet, v6.events.rulesGranted).map((args) => ({ rulesId: args['rulesId'] as Hex, mode: Number(args['mode']), chainNamespace: args['chainNamespace'] as string, })); }, parseRulesRevoked(logs: readonly Log[], wallet: Address) { - return decodeMatching(logs, wallet, v5.events.rulesRevoked).map((args) => ({ + return decodeMatching(logs, wallet, v6.events.rulesRevoked).map((args) => ({ rulesId: args['rulesId'] as Hex, })); }, @@ -339,12 +372,12 @@ export const v5 = { (l) => sameAddress(l.address, wallet) && l.topics[0]?.toLowerCase() === - toEventSelector(v5.events.checkpointed).toLowerCase() + toEventSelector(v6.events.checkpointed).toLowerCase() ) .flatMap((log) => { try { const ev = decodeEventLog({ - abi: [v5.events.checkpointed], + abi: [v6.events.checkpointed], ...log, strict: true, }); @@ -355,7 +388,7 @@ export const v5 = { }) .map(({ log, args }) => ({ seq: Number(args['seq']), - kind: v5.decodeCheckpointKind(Number(args['kind'])), + kind: v6.decodeCheckpointKind(Number(args['kind'])), ref: args['ref'] as Hex, blockNumber: BigInt(log.blockNumber ?? BigInt(0)), txHash: log.transactionHash as Hex, @@ -419,4 +452,4 @@ function decodeMatching( return out; } -export type AgwContracts = typeof v5; +export type AgwContracts = typeof v6; diff --git a/packages/core/src/lib/agentic/deployments.ts b/packages/core/src/lib/agentic/deployments.ts index e9a9f84e..99e61eb1 100644 --- a/packages/core/src/lib/agentic/deployments.ts +++ b/packages/core/src/lib/agentic/deployments.ts @@ -1,14 +1,14 @@ import { getAddress, type Address } from 'viem'; import { PUSH_NETWORK } from '../constants/enums'; import { AgenticCapability } from './capabilities'; -import { v5, type AgwContracts } from './contracts/v5'; +import { v6, type AgwContracts } from './contracts/v6'; import type { ChainReader } from './contracts/reader'; import { AGENTIC_ERROR_CODE, AgenticError } from './errors'; import { - DONUT_V5_ADDRESSES, - DONUT_V5_START_BLOCK, - V5_SOURCE_COMMIT, -} from './contracts/donut-v5'; + DONUT_V6_ADDRESSES, + DONUT_V6_START_BLOCK, + V6_SOURCE_COMMIT, +} from './contracts/donut-v6'; /** * A verified AGW contract generation on one Push network. The registry is the @@ -17,7 +17,7 @@ import { * are NOT registered because they do not implement this ABI. */ export interface AgenticGeneration { - /** Stable identifier, e.g. 'v5'. */ + /** Stable identifier, e.g. 'v6'. */ id: string; /** Contract source commit the ABI was generated from. */ sourceCommit: string; @@ -40,8 +40,8 @@ export interface AgenticGeneration { contracts: AgwContracts; } -/** Capabilities the v5 ABI actually implements. Target-only features are absent. */ -export const V5_CAPABILITIES: ReadonlySet = new Set([ +/** Capabilities the v6 ABI actually implements. Target-only features are absent. */ +export const V6_CAPABILITIES: ReadonlySet = new Set([ AgenticCapability.WALLET_READS, AgenticCapability.ACTIVE_RULE_READS, AgenticCapability.OWNER_EXECUTE, @@ -57,19 +57,19 @@ export const V5_CAPABILITIES: ReadonlySet = new Set([ ]); /** - * V5 only. Unsupported networks fail before signing; no legacy adapter fallback. + * V6 only. Unsupported networks fail before signing; no legacy adapter fallback. */ const VERIFIED_DEPLOYMENTS: readonly AgenticGeneration[] = [ { - id: 'v5', - sourceCommit: V5_SOURCE_COMMIT, + id: 'v6', + sourceCommit: V6_SOURCE_COMMIT, network: PUSH_NETWORK.TESTNET_DONUT, advertised: true, - addresses: DONUT_V5_ADDRESSES, - startBlock: DONUT_V5_START_BLOCK, + addresses: DONUT_V6_ADDRESSES, + startBlock: DONUT_V6_START_BLOCK, accountId: 'push.agw.1.0.0', - capabilities: V5_CAPABILITIES, - contracts: v5, + capabilities: V6_CAPABILITIES, + contracts: v6, }, ]; @@ -85,7 +85,7 @@ export function registerAgenticGeneration( capabilities?: ReadonlySet; } ): AgenticGeneration { - if (input.id !== v5.id || input.sourceCommit !== V5_SOURCE_COMMIT) { + if (input.id !== v6.id || input.sourceCommit !== V6_SOURCE_COMMIT) { throw new AgenticError( AGENTIC_ERROR_CODE.CAPABILITY_UNAVAILABLE, `no contract adapter for generation "${input.id}"` @@ -101,8 +101,8 @@ export function registerAgenticGeneration( sessionValidator: getAddress(input.addresses.sessionValidator), gateway: getAddress(input.addresses.gateway), }, - capabilities: input.capabilities ?? V5_CAPABILITIES, - contracts: v5, + capabilities: input.capabilities ?? V6_CAPABILITIES, + contracts: v6, }; const existing = registry.findIndex( (g) => @@ -114,7 +114,7 @@ export function registerAgenticGeneration( return gen; } -/** @internal Test/harness cleanup. Restores the checked Donut v5 registry. */ +/** @internal Test/harness cleanup. Restores the checked Donut v6 registry. */ export function resetAgenticGenerations(): void { registry.splice(0, registry.length, ...VERIFIED_DEPLOYMENTS); verifiedWiring.clear(); @@ -133,7 +133,7 @@ export async function verifyPolicyVersion( if (version !== '3.1.0') throw new AgenticError( AGENTIC_ERROR_CODE.CAPABILITY_UNAVAILABLE, - `URP version ${String(version)} is not supported by the v5 adapter` + `URP version ${String(version)} is not supported by the v6 adapter` ); } @@ -152,7 +152,7 @@ export function currentGeneration(network: PUSH_NETWORK): AgenticGeneration { AGENTIC_ERROR_CODE.CAPABILITY_UNAVAILABLE, `no verified AGW deployment is registered for ${network}`, { - hint: 'AGW v5 is configured on Donut only; this Push network has no registered v5 deployment.', + hint: 'AGW v6 is configured on Donut only; this Push network has no registered v6 deployment.', details: { network, assumption: 'A07' }, } ); @@ -233,7 +233,7 @@ export async function resolveWalletGeneration( factory = getAddress( (await reader.readContract({ address: wallet, - abi: v5.abis.wallet, + abi: v6.abis.wallet, functionName: 'factory', })) as Address ); diff --git a/packages/core/src/lib/agentic/errors.ts b/packages/core/src/lib/agentic/errors.ts index b7583887..bbe55e4b 100644 --- a/packages/core/src/lib/agentic/errors.ts +++ b/packages/core/src/lib/agentic/errors.ts @@ -34,12 +34,10 @@ export const AGENTIC_ERROR_CODE = { RULE_READ_FAILED: 'RULE_READ_FAILED', INCONSISTENT_READ: 'INCONSISTENT_READ', INDEX_RACE: 'INDEX_RACE', - CREATE_PARTIAL: 'CREATE_PARTIAL', RECEIPT_MISMATCH: 'RECEIPT_MISMATCH', RECEIPT_UNAVAILABLE: 'RECEIPT_UNAVAILABLE', AGENT_GAS_INSUFFICIENT: 'AGENT_GAS_INSUFFICIENT', WALLET_BALANCE_INSUFFICIENT: 'WALLET_BALANCE_INSUFFICIENT', - GATEWAY_ALLOWANCE_INSUFFICIENT: 'GATEWAY_ALLOWANCE_INSUFFICIENT', } as const; export type AgenticErrorCode = @@ -48,7 +46,7 @@ export type AgenticErrorCode = /** * Pre-signature AGW failure: invalid input, unsupported capability, failed * eligibility or a read that cannot be trusted. Nothing was signed or sent - * unless `details` explicitly records committed hashes (CREATE_PARTIAL). + * except receipt errors, which retain the submitted transaction hash. */ export class AgenticError extends Error { readonly code: AgenticErrorCode; @@ -82,8 +80,6 @@ export class AgenticError extends Error { */ export class AgenticRevertError extends PushChainExecutionError { readonly agenticCode?: string; - readonly transactionHashes?: `0x${string}`[]; - readonly pendingTransactionHash?: `0x${string}`; constructor( message: string, @@ -91,8 +87,6 @@ export class AgenticRevertError extends PushChainExecutionError { decodedError?: DecodedErrorPayload; gatewayTxHash?: string; agenticCode?: string; - transactionHashes?: `0x${string}`[]; - pendingTransactionHash?: `0x${string}`; cause?: unknown; } = {} ) { @@ -103,10 +97,6 @@ export class AgenticRevertError extends PushChainExecutionError { }); this.name = 'AgenticRevertError'; this.agenticCode = opts.agenticCode; - this.transactionHashes = opts.transactionHashes - ? [...opts.transactionHashes] - : undefined; - this.pendingTransactionHash = opts.pendingTransactionHash; } } diff --git a/packages/core/src/lib/agentic/execution/outbound.ts b/packages/core/src/lib/agentic/execution/outbound.ts index 999690ef..5e77b6f6 100644 --- a/packages/core/src/lib/agentic/execution/outbound.ts +++ b/packages/core/src/lib/agentic/execution/outbound.ts @@ -18,8 +18,8 @@ import { isPC20Reference } from '../../orchestrator/orchestrator.types'; import { resolveR2DestinationFundsToken } from '../../orchestrator/internals/route-handlers'; import { AgenticCapability, requireCapability } from '../capabilities'; import type { AgenticGeneration } from '../deployments'; -import type { Call } from '../contracts/v5'; -import { UEA_MULTICALL_PREFIX } from '../contracts/v5'; +import type { Call } from '../contracts/v6'; +import { UEA_MULTICALL_PREFIX } from '../contracts/v6'; import { AGENTIC_ERROR_CODE, AgenticError, @@ -30,7 +30,7 @@ import type { AgenticRuntime } from '../runtime'; /** Includes first-use CEA deployment; explicit caller gas always takes precedence. */ const FIRST_USE_EVM_GAS_LIMIT = BigInt(2_000_000); -/** URP MAX_ACTIONS_PER_REQUEST at v5. */ +/** URP MAX_ACTIONS_PER_REQUEST at v6. */ export const MAX_DESTINATION_CALLS = 10; const MULTICALL_TUPLE = [ @@ -123,8 +123,8 @@ export function destinationCalls( * - payload = UEA_MULTICALL ‖ abi.encode(Multicall[1..10]) executed by the AGW's CEA * - value = protocolFee + maxPCForGas, paid from the AGW's PC * The destination account is resolved from the AGW, never from the signer. - * The SDK never writes a gateway allowance on either door: the gateway pulls - * from an allowance the owner set separately with an ordinary send. + * The SDK does not add approval calls: the v6 wallet approves and clears + * the gateway allowance within its own outbound execution. */ export async function composeOutbound( runtime: AgenticRuntime, diff --git a/packages/core/src/lib/agentic/execution/send.ts b/packages/core/src/lib/agentic/execution/send.ts index 6f18a4ca..ca2b978f 100644 --- a/packages/core/src/lib/agentic/execution/send.ts +++ b/packages/core/src/lib/agentic/execution/send.ts @@ -17,8 +17,8 @@ import { } from '../../orchestrator/internals/helpers'; import { AgenticCapability, requireCapability } from '../capabilities'; import type { AgenticExecutionContext } from '../context'; -import type { Call, UniversalConfigRead } from '../contracts/v5'; -import { SEND_OUTBOUND_SELECTOR } from '../contracts/v5'; +import type { Call, UniversalConfigRead } from '../contracts/v6'; +import { SEND_OUTBOUND_SELECTOR } from '../contracts/v6'; import { actionId, configId } from '../codec/ids'; import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; import { @@ -252,7 +252,7 @@ export async function agenticSend( }); outboundChain = out.chain; meta = { route: 'UOA_TO_CEA', destinationAccount: out.destinationAccount }; - const [walletPc, tokenBalance, allowance] = await Promise.all([ + const [walletPc, tokenBalance] = await Promise.all([ runtime.reader.getBalance({ address: wallet, blockNumber: snap.blockNumber, @@ -265,12 +265,6 @@ export async function agenticSend( [wallet] ) : Promise.resolve(BigInt(0)), - snap.read( - out.token, - ERC20_EVM as unknown as readonly unknown[], - 'allowance', - [wallet, gen.addresses.gateway] - ), ]); if (walletPc < out.value) { throw new AgenticError( @@ -285,17 +279,6 @@ export async function agenticSend( `wallet ${wallet} holds ${tokenBalance} of ${out.token}; this outbound burns ${out.amount}` ); } - // Both doors only consume an allowance the owner set separately; the SDK - // never writes one (a write from a stale read could restore revoked authority). - if (out.amount > allowance) { - throw new AgenticError( - AGENTIC_ERROR_CODE.GATEWAY_ALLOWANCE_INSUFFICIENT, - `the gateway may pull ${allowance} of ${out.token} from the wallet; this outbound needs ${out.amount}`, - { - hint: 'Set a bounded allowance first with an owner-door send: approve(gateway, cap) on the token (approve(gateway, 0) removes it).', - } - ); - } if (actx.door === 'agent') { if (expectedCEA && expectedCEA !== out.destinationAccount) { throw new AgenticError( diff --git a/packages/core/src/lib/agentic/execution/svm-outbound.ts b/packages/core/src/lib/agentic/execution/svm-outbound.ts index 390f3320..822e8f1a 100644 --- a/packages/core/src/lib/agentic/execution/svm-outbound.ts +++ b/packages/core/src/lib/agentic/execution/svm-outbound.ts @@ -2,7 +2,7 @@ import { encodeFunctionData, getAddress, type Address, type Hex } from 'viem'; import { UNIVERSAL_GATEWAY_PC } from '../../constants/abi'; import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; -import type { Call, SvmConfigRead } from '../contracts/v5'; +import type { Call, SvmConfigRead } from '../contracts/v6'; import { UINT256_MAX } from '../codec/defaults'; import { UINT64_MAX } from '../codec/svm-terms'; import { validateAgwSvmPayload } from './svm-payload'; diff --git a/packages/core/src/lib/agentic/execution/svm-payload.ts b/packages/core/src/lib/agentic/execution/svm-payload.ts index da76d7ee..c7f5208b 100644 --- a/packages/core/src/lib/agentic/execution/svm-payload.ts +++ b/packages/core/src/lib/agentic/execution/svm-payload.ts @@ -101,7 +101,8 @@ export function validateAgwSvmPayload( ); if (rule < 0) fail('ProgramNotAllowed'); const fixed = terms.programs[rule].maxAccounts; - if (fixed && fixed !== v.accounts.length) fail('SvmAccountCountMismatch'); + if (fixed !== 255 && fixed !== v.accounts.length) + fail('SvmAccountCountMismatch'); const pins = terms.pins.filter((p) => p.ruleIndex === rule); for (const p of pins) { if (p.accountIndex >= v.accounts.length) fail('SvmAccountCountBelowPin'); diff --git a/packages/core/src/lib/agentic/execution/svm-public.ts b/packages/core/src/lib/agentic/execution/svm-public.ts index 00c9b347..d8c3e575 100644 --- a/packages/core/src/lib/agentic/execution/svm-public.ts +++ b/packages/core/src/lib/agentic/execution/svm-public.ts @@ -156,16 +156,12 @@ export async function sendPublicSvm( destinationTransfer = { recipient: target, token, amount }; transferValue = quote.isNative ? amount : BigInt(0); } - const [pc, balance, allowance] = await Promise.all([ + const [pc, balance] = await Promise.all([ runtime.reader.getBalance({ address: wallet, blockNumber: snap.blockNumber, }), snap.read(token, erc20Abi, 'balanceOf', [wallet]), - snap.read(token, erc20Abi, 'allowance', [ - wallet, - gen.addresses.gateway, - ]), ]); const value = quote.protocolFee + quote.nativeValueForGas; if (pc < value || balance < amount) @@ -173,11 +169,6 @@ export async function sendPublicSvm( AGENTIC_ERROR_CODE.WALLET_BALANCE_INSUFFICIENT, 'wallet cannot cover Solana outbound' ); - if (allowance < amount) - throw new AgenticError( - AGENTIC_ERROR_CODE.GATEWAY_ALLOWANCE_INSUFFICIENT, - 'set the wallet gateway allowance separately' - ); const call = buildAgwSvmAction({ wallet, gateway: gen.addresses.gateway, diff --git a/packages/core/src/lib/agentic/execution/svm-send.ts b/packages/core/src/lib/agentic/execution/svm-send.ts index b28d80d7..68b4be57 100644 --- a/packages/core/src/lib/agentic/execution/svm-send.ts +++ b/packages/core/src/lib/agentic/execution/svm-send.ts @@ -123,17 +123,6 @@ export async function prepareSvmAgentExecution( AGENTIC_ERROR_CODE.WALLET_BALANCE_INSUFFICIENT, 'wallet token balance is below the SVM amount' ); - const allowance = await snap.read( - input.token, - erc20Abi, - 'allowance', - [input.wallet, gen.addresses.gateway] - ); - if (allowance < input.amount) - throw new AgenticError( - AGENTIC_ERROR_CODE.GATEWAY_ALLOWANCE_INSUFFICIENT, - 'owner must establish the SVM gateway allowance separately' - ); } const signerPc = await runtime.signerBalance(); const gasReserve = (await runtime.getGasPrice()) * BigInt(10_000_000); diff --git a/packages/core/src/lib/agentic/management/common.ts b/packages/core/src/lib/agentic/management/common.ts index 5a67bd01..84271b3c 100644 --- a/packages/core/src/lib/agentic/management/common.ts +++ b/packages/core/src/lib/agentic/management/common.ts @@ -1,5 +1,8 @@ import { getAddress, type Address, type Hex, type Log } from 'viem'; -import type { MultiCall, UniversalTxResponse } from '../../orchestrator/orchestrator.types'; +import type { + MultiCall, + UniversalTxResponse, +} from '../../orchestrator/orchestrator.types'; import { PushChainBatchExecutionError, PushChainExecutionError, @@ -8,7 +11,11 @@ import { import PROGRESS_HOOKS from '../../progress-hook/progress-hook'; import { PROGRESS_HOOK } from '../../progress-hook/progress-hook.types'; import type { AgenticGeneration } from '../deployments'; -import { AGENTIC_ERROR_CODE, AgenticError, AgenticRevertError } from '../errors'; +import { + AGENTIC_ERROR_CODE, + AgenticError, + AgenticRevertError, +} from '../errors'; import type { AgenticRuntime } from '../runtime'; import type { AgenticProgressHook } from '../agentic.types'; import { Snapshot } from '../reads/snapshot'; @@ -23,7 +30,10 @@ export function emitAgentic( runtime.emit(PROGRESS_HOOKS[id](...args), perCall); } -export function assertCanSign(runtime: AgenticRuntime, operation: string): void { +export function assertCanSign( + runtime: AgenticRuntime, + operation: string +): void { if (runtime.isReadOnly) { throw new AgenticError( AGENTIC_ERROR_CODE.READ_ONLY, @@ -39,13 +49,17 @@ export async function assertOwner( wallet: Address, snap: Snapshot ): Promise
{ - const owner = getAddress(await snap.read
(wallet, gen.contracts.abis.wallet, 'owner')); + const owner = getAddress( + await snap.read
(wallet, gen.contracts.abis.wallet, 'owner') + ); const signer = runtime.signerPushAccount(); if (owner !== signer) { throw new AgenticError( AGENTIC_ERROR_CODE.NOT_WALLET_OWNER, `${signer} is not the owner of ${wallet} (owner is ${owner})`, - { hint: 'Rule and label writes are owner-only. Initialize with the owner signer.' } + { + hint: 'Rule and label writes are owner-only. Initialize with the owner signer.', + } ); } return owner; @@ -62,12 +76,19 @@ export async function sendOwnerCalls( calls: MultiCall[], progressHook: AgenticProgressHook | undefined ): Promise { - if (calls.length === 0) throw new Error('sendOwnerCalls needs at least one call'); + if (calls.length === 0) + throw new Error('sendOwnerCalls needs at least one call'); const options = progressHook ? { progressHook } : undefined; if (calls.length === 1) { - return runtime.execute({ to: calls[0].to, value: calls[0].value, data: calls[0].data }, options); + return runtime.execute( + { to: calls[0].to, value: calls[0].value, data: calls[0].data }, + options + ); } - return runtime.execute({ to: calls[0].to, value: BigInt(0), data: calls }, options); + return runtime.execute( + { to: calls[0].to, value: BigInt(0), data: calls }, + options + ); } /** @@ -83,7 +104,9 @@ export async function confirmedLogs( const unavailable = (cause: unknown) => new AgenticError( AGENTIC_ERROR_CODE.RECEIPT_UNAVAILABLE, - `submitted ${tx.hash} but could not read its receipt: ${cause instanceof Error ? cause.message : String(cause)}`, + `submitted ${tx.hash} but could not read its receipt: ${ + cause instanceof Error ? cause.message : String(cause) + }`, { hint: 'The transaction may still land. Check these hashes before retrying.', details: { txHash: tx.hash, transactionHashes: hashes }, @@ -99,7 +122,7 @@ export async function confirmedLogs( if (hashes.length === 1) { if (receipt.status !== 1) { throw new AgenticRevertError(`Push transaction ${tx.hash} reverted`, { - transactionHashes: hashes, + cause: { txHash: tx.hash }, }); } return { logs: receipt.logs as Log[], hashes }; @@ -113,7 +136,9 @@ export async function confirmedLogs( throw unavailable(cause); } if (r.status !== 'success') { - throw new AgenticRevertError(`Push transaction ${hash} reverted`, { transactionHashes: hashes }); + throw new AgenticRevertError(`Push transaction ${hash} reverted`, { + cause: { txHash: hash }, + }); } logs.push(...(r.logs as Log[])); } @@ -122,18 +147,21 @@ export async function confirmedLogs( /** Normalize a send failure: keep batch hashes and decoded revert data. */ export function wrapSendError(err: unknown): unknown { - if (err instanceof AgenticError || err instanceof AgenticRevertError) return err; + if (err instanceof AgenticError || err instanceof AgenticRevertError) + return err; const decoded = decodeAgenticRevert(err); if (err instanceof PushChainBatchExecutionError) { return new AgenticRevertError(err.message, { decodedError: decoded ?? err.decodedError, - transactionHashes: err.transactionHashes, - pendingTransactionHash: err.pendingTransactionHash, cause: err, }); } if (decoded || err instanceof PushChainExecutionError) { - const e = err as { message?: string; gatewayTxHash?: string; decodedError?: DecodedErrorPayload }; + const e = err as { + message?: string; + gatewayTxHash?: string; + decodedError?: DecodedErrorPayload; + }; return new AgenticRevertError(e?.message ?? decoded?.name ?? 'AGW revert', { decodedError: decoded ?? e?.decodedError, gatewayTxHash: e?.gatewayTxHash, diff --git a/packages/core/src/lib/agentic/management/create.ts b/packages/core/src/lib/agentic/management/create.ts index a021a99a..fbeb576f 100644 --- a/packages/core/src/lib/agentic/management/create.ts +++ b/packages/core/src/lib/agentic/management/create.ts @@ -1,8 +1,7 @@ import { assertNoDuplicateRules } from './duplicates'; -import { getAddress, type Address, type Hex, type Log } from 'viem'; +import { getAddress, type Address, type Hex } from 'viem'; import { PROGRESS_HOOK } from '../../progress-hook/progress-hook.types'; import type { MultiCall } from '../../orchestrator/orchestrator.types'; -import { PushChainBatchExecutionError } from '../../orchestrator/internals/errors'; import { AgenticCapability, requireCapability } from '../capabilities'; import { currentGeneration, verifyFactoryWiring } from '../deployments'; import { deriveWallet, rulesId as computeRulesId } from '../codec/ids'; @@ -11,8 +10,8 @@ import { assertLabel } from './label'; import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; import type { AgenticRuntime } from '../runtime'; import type { InternalCreateOptions, CreateResult } from '../agentic.types'; -import { Snapshot, scanLogs } from '../reads/snapshot'; -import { walletCount, walletInfo } from '../reads/wallets'; +import { Snapshot } from '../reads/snapshot'; +import { walletCount } from '../reads/wallets'; import { assertCanSign, confirmedLogs, @@ -21,19 +20,7 @@ import { wrapSendError, } from './common'; -/** - * client.agentic.create(label, { rules }): deploy + grants only. Funding and - * approvals are separate ordinary sends. Every input is validated and every - * prediction re-read immediately before signing; IDs are returned from - * receipts in input order. - * - * Strategy follows the signer: an external owner's UEA batches atomically, a - * Push EOA uses an EIP-7702 batch when available and otherwise the documented - * sequential fallback. A sequential failure raises CREATE_PARTIAL with the - * deployed wallet, confirmed/pending hashes and granted IDs so the caller can - * finish with `wallet(w).rules.add(remaining)` — the SDK never deploys another - * wallet on its own. - */ +/** One index-bound v6 factory call deploys and grants atomically for EOA/UEA owners. */ export async function createWallet( runtime: AgenticRuntime, label: string, @@ -110,40 +97,30 @@ export async function createWallet( grantNonce: BigInt(i), }) ); + if (prepared.length > 8) + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'create accepts at most eight initial rules' + ); const calls: MultiCall[] = [ - // Index-bound: reverts (nothing committed) if another creation took this slot. { to: gen.addresses.factory, value: BigInt(0), - data: gen.contracts.encodeDeployWalletAt(owner, index, wallet, label), + data: gen.contracts.encodeCreateWalletAt( + owner, + index, + wallet, + label, + prepared.map((p) => p.session) + ), }, - ...prepared.map((p) => ({ - to: wallet, - value: BigInt(0), - data: gen.contracts.encodeGrantRules(p.session), - })), ]; - const strategy = - calls.length === 1 - ? 'single' - : runtime.signerIsPushNative() - ? 'push-eoa-batch' - : 'uea-multicall'; - emitAgentic(runtime, hook, PROGRESS_HOOK.AGENTIC_TX_102, wallet, strategy); - + emitAgentic(runtime, hook, PROGRESS_HOOK.AGENTIC_TX_102, wallet, 'single'); let tx; try { tx = await sendOwnerCalls(runtime, calls, hook); } catch (err) { - const wrapped = await createFailure( - runtime, - gen, - wallet, - Number(index), - owner, - label, - err - ); + const wrapped = atomicCreateFailure(err); emitFailure(runtime, hook, wrapped); throw wrapped; } @@ -152,15 +129,7 @@ export async function createWallet( try { ({ logs } = await confirmedLogs(runtime, tx)); } catch (err) { - const wrapped = await createFailure( - runtime, - gen, - wallet, - Number(index), - owner, - label, - err - ); + const wrapped = atomicCreateFailure(err); emitFailure(runtime, hook, wrapped); throw wrapped; } @@ -177,13 +146,13 @@ export async function createWallet( deployedEv[0].index !== index ) { const err = new AgenticError( - AGENTIC_ERROR_CODE.INDEX_RACE, - `deployWallet produced ${ + AGENTIC_ERROR_CODE.RECEIPT_MISMATCH, + `createWallet produced ${ deployedEv.map((d) => `${d.wallet}#${d.index}`).join(', ') || 'no wallet' }, expected ${wallet}#${index}; grants targeted ${wallet}`, { - hint: 'Another deployment by this owner raced this call. Inspect both wallets with client.agentic.list() before retrying.', + hint: 'The receipt does not describe the requested atomic creation. Inspect the submitted hash before retrying.', details: { expected: wallet, deployed: deployedEv, @@ -228,163 +197,26 @@ function sameIds(a: readonly Hex[], b: readonly Hex[]): boolean { ); } -const RACE_ERRORS = new Set(['IndexMismatch', 'IntentWalletMismatch']); - -/** - * Turn a create failure into an exact report. What committed is derived from - * THIS operation's own receipts, never from a later state read; when those - * receipts cannot be fetched the outcome is reported as unknown so callers do - * not retry a creation that may have landed. - */ -async function createFailure( - runtime: AgenticRuntime, - gen: ReturnType, - wallet: Address, - index: number, - owner: Address, - label: string, - err: unknown -): Promise { - const wrapped = wrapSendError(err); - const batch = err instanceof PushChainBatchExecutionError ? err : undefined; - const confirmed = (batch?.transactionHashes ?? []) as Hex[]; - const pending = batch?.pendingTransactionHash; - const receiptUnavailable = - wrapped instanceof AgenticError && - wrapped.code === AGENTIC_ERROR_CODE.RECEIPT_UNAVAILABLE; - - // The index-bound deploy reverted: another creation took the slot first and - // nothing from this call committed. - const decodedName = (wrapped as { decodedError?: { name?: string } }) - .decodedError?.name; +function atomicCreateFailure(error: unknown): unknown { + const wrapped = wrapSendError(error) as { decodedError?: { name?: string } }; if ( - confirmed.length === 0 && - !pending && - decodedName && - RACE_ERRORS.has(decodedName) - ) { + ['IndexMismatch', 'IntentWalletMismatch'].includes( + wrapped?.decodedError?.name ?? '' + ) + ) return new AgenticError( AGENTIC_ERROR_CODE.INDEX_RACE, - `wallet slot ${index} (${wallet}) was taken by a concurrent creation; nothing was committed`, + 'the predicted wallet slot changed; atomic creation committed nothing', { - hint: 'Retry agentic.create; it re-reads the next slot.', - details: { wallet, index, committed: false }, cause: wrapped, + details: { + committed: false, + walletDeployed: false, + grantedRulesIds: [], + }, } ); - } - if (confirmed.length === 0 && !pending && !receiptUnavailable) { - // Some send paths flatten the factory revert to a generic execution - // error, losing the IndexMismatch selector. If the owner's next index has - // moved and immutable deployment metadata proves another label owns the - // predicted slot, this call could not have deployed or granted. - try { - const snap = await Snapshot.at(runtime.reader); - const next = await walletCount(snap, gen, owner); - if (next > BigInt(index)) { - const competing = await walletInfo(runtime.reader, gen, wallet); - // label() is mutable in v5: only the immutable deploy event proves - // which creation occupied this slot. A later rename proves nothing. - const logs = await scanLogs( - runtime.reader, - { - address: gen.addresses.factory, - event: gen.contracts.events.walletDeployed, - args: { wallet }, - }, - gen.startBlock, - snap.blockNumber - ); - const deployed = gen.contracts - .parseWalletDeployed(logs, gen.addresses.factory) - .find((entry) => entry.wallet === wallet); - const competingLabel = deployed?.label; - if ( - competing.deployed && - competing.index === index && - getAddress(competing.owner) === owner && - competingLabel !== undefined && - competingLabel !== label - ) { - return new AgenticError( - AGENTIC_ERROR_CODE.INDEX_RACE, - 'wallet slot ' + index + ' was consumed by a concurrent deployment', - { - hint: - 'Slot ' + - index + - ' belongs to "' + - competingLabel + - '". No wallet or rules from this create call were committed; retry agentic.create to use the next slot.', - details: { - wallet, - index, - committed: false, - competingLabel, - }, - cause: wrapped, - } - ); - } - } - } catch { - // If the owner counter/event cannot be reconciled, preserve the original - // error; never infer that a retry is safe from an incomplete read. - } - // Nothing was confirmed (pre-broadcast failure or a reverted atomic batch). - return wrapped; - } - - let walletDeployed: boolean | 'unknown' = 'unknown'; - let grantedRulesIds: Hex[] | undefined; - let recoveryError: string | undefined; - if (!receiptUnavailable) { - try { - const logs: Log[] = []; - for (const hash of confirmed) { - const r = await runtime.reader.getTransactionReceipt({ hash }); - if (r.status === 'success') logs.push(...(r.logs as Log[])); - } - const deployed = gen.contracts - .parseWalletDeployed(logs, gen.addresses.factory) - .some((d) => d.wallet === wallet); - grantedRulesIds = gen.contracts - .parseRulesGranted(logs, wallet) - .map((g) => g.rulesId); - // A pending hash may itself be the deployment; only a confirmed deploy is certain. - walletDeployed = deployed ? true : pending ? 'unknown' : false; - } catch (e) { - recoveryError = e instanceof Error ? e.message : String(e); - } - } - const hint = - walletDeployed === true - ? `Wallet ${wallet} is deployed. Do not call create again; once any pending hash settles, finish with client.agentic.wallet('${wallet}').rules.add().` - : walletDeployed === false - ? 'No wallet was deployed by this call; it is safe to retry.' - : 'The outcome is unknown. Do not retry create until the listed hashes are reconciled (client.agentic.list() shows deployed wallets).'; - return new AgenticError( - AGENTIC_ERROR_CODE.CREATE_PARTIAL, - `agentic.create did not complete: ${ - (wrapped as Error)?.message ?? String(err) - }`, - { - hint, - details: { - wallet, - index, - walletDeployed, - grantedRulesIds, - confirmedHashes: confirmed, - pendingHash: pending, - ...(receiptUnavailable - ? { submitted: (wrapped as AgenticError).details } - : {}), - ...(recoveryError ? { recoveryError } : {}), - }, - cause: wrapped, - } - ); + return wrapped; } function emitFailure( diff --git a/packages/core/src/lib/agentic/management/svm.ts b/packages/core/src/lib/agentic/management/svm.ts index 14aa58ab..d2f6b223 100644 --- a/packages/core/src/lib/agentic/management/svm.ts +++ b/packages/core/src/lib/agentic/management/svm.ts @@ -17,7 +17,7 @@ import { import { encodeSvmTerms, type SvmTermsWire } from '../codec/svm-terms'; import { buildSession, encodeEnvelope } from '../codec/session'; import { rulesId as predictRulesId } from '../codec/ids'; -import { SEND_OUTBOUND_SELECTOR } from '../contracts/v5'; +import { SEND_OUTBOUND_SELECTOR } from '../contracts/v6'; import { deriveAgwSvmCea } from '../codec/svm-accounts'; import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; import { PRC20_SOURCE_ABI } from '../contracts/prc20-metadata'; diff --git a/packages/core/src/lib/agentic/presets/index.ts b/packages/core/src/lib/agentic/presets/index.ts index 60f5a842..82628679 100644 --- a/packages/core/src/lib/agentic/presets/index.ts +++ b/packages/core/src/lib/agentic/presets/index.ts @@ -153,7 +153,7 @@ export function buildPresetApi( } const rules: PresetRuleTemplate[] = chains.map((chain) => { const calls = chain.allowedCalls.map(copyCall); - const approvals = new Map(); + const approvals = new Set(); for (const asset of assets.get(chain.chainNamespace) ?? []) { const token = tokenAddress(asset.token); if ( @@ -170,14 +170,9 @@ export function buildPresetApi( ); const spender = getAddress(approval.spender); const target = getAddress(token); - const previous = approvals.get(target); - if (previous && previous !== spender) - throw capabilityUnavailable( - 'presetApproval', - 'multiple spenders for one token need a reviewed policy representation; no unrestricted approval is generated' - ); - if (previous) continue; - approvals.set(target, spender); + const approvalKey = `${target}:${spender}`; + if (approvals.has(approvalKey)) continue; + approvals.add(approvalKey); calls.push({ target, selector: 'approve(address,uint256)', @@ -195,7 +190,7 @@ export function buildPresetApi( 'presetCalls', 'preset must contain 1..32 allowed calls including approvals' ); - const pairs = new Set(); + const pairs = new Map(); for (const call of calls) { if (!/^[A-Za-z_$][\w$]*\(.*\)$/.test(call.selector)) throw invalid('preset selectors must be full signatures'); @@ -207,12 +202,17 @@ export function buildPresetApi( ? call.target.toLowerCase() : call.target }:${selector}`; - if (pairs.has(pair)) + if (pairs.has(pair) && !chain.chainNamespace.startsWith('eip155:')) + throw capabilityUnavailable( + 'presetCalls', + 'Solana does not support alternative entries for one program/instruction' + ); + if (pairs.has(pair) && (!call.pins?.length || !pairs.get(pair))) throw capabilityUnavailable( 'presetCalls', - 'duplicate target/function entries need a reviewed policy representation' + 'an unpinned alternative would bypass restrictions for this target/function' ); - pairs.add(pair); + pairs.set(pair, !!call.pins?.length); } return { chainNamespace: chain.chainNamespace, diff --git a/packages/core/src/lib/agentic/public-rule.ts b/packages/core/src/lib/agentic/public-rule.ts index bf293415..0f831935 100644 --- a/packages/core/src/lib/agentic/public-rule.ts +++ b/packages/core/src/lib/agentic/public-rule.ts @@ -1,4 +1,9 @@ -/** Public section-6 rule normalization into the deployed v5 wire model. */ +import { + UNLIMITED_CALLS, + ANY_ACCOUNT_COUNT, + type ArgPinWire, +} from './codec/pins'; +/** Public section-6 rule normalization into the deployed v6 wire model. */ import type { Idl } from '@coral-xyz/anchor'; import { PublicKey } from '@solana/web3.js'; import { @@ -180,75 +185,54 @@ export async function normalizePublicRule( if (native && r.allowedCalls.length > 8) throw capabilityUnavailable( 'nativeActions', - 'the deployed v5 wallet permits at most eight native actions' + 'the deployed v6 wallet permits at most eight native actions' ); if (native && (r.assets !== undefined || r.maxGasPerCall !== undefined)) throw invalid('native rules do not carry assets or maxGasPerCall'); const own = native ? wallet - : (await runtime.resolveCEA(wallet, r.chainNamespace as CHAIN)).cea; + : getAddress( + (await runtime.resolveCEA(wallet, r.chainNamespace as CHAIN)).cea + ); const nativeActions: NativeAction[] = []; const calls: UniversalRule['allowedCalls'] = []; for (const call of r.allowedCalls) { const pins = call.pins ?? []; - let amount: NativeAction['amount']; - const eq: NonNullable = []; - let beneficiaryOffset: number | undefined; + const wirePins: ArgPinWire[] = []; const occupied = new Set(); for (const pin of pins) { if ('account' in pin) throw invalid('account pins only apply to Solana'); const offset = evmPinOffset(call.selector, pin.arg); if (occupied.has(offset)) throw invalid('duplicate pin argument'); occupied.add(offset); - if (!native) { - if ( - !('expected' in pin) || - pin.expected !== WALLET || - beneficiaryOffset !== undefined - ) - throw capabilityUnavailable( - 'evmDestinationPins', - 'general or multiple EVM destination pins require contract change 6.3; v5 supports one WALLET pin per call' - ); - beneficiaryOffset = offset; - } else if ('max' in pin) { - if (amount) - throw capabilityUnavailable( - 'nativeMaxPins', - 'v5 supports one max pin per native call' - ); - amount = { - offset, - maxPerCall: uint(pin.max, 'pin.max'), - maxTotal: UINT256_MAX, - }; - } else { - eq.push({ - offset, - expected: expectedWord( - call.selector, - pin.arg, - pin.expected === WALLET ? own : pin.expected - ), - }); - } + wirePins.push({ + offset, + op: 'max' in pin ? 1 : 0, + value: + 'max' in pin + ? numberToHex(uint(pin.max, 'pin.max'), { size: 32 }) + : expectedWord( + call.selector, + pin.arg, + pin.expected === WALLET ? own : pin.expected + ), + }); } if (native) nativeActions.push({ target: getAddress(call.target), selector: call.selector, - pins: eq, - amount, + wirePins, maxValuePerCall: call.maxValue ?? BigInt(0), maxValueTotal: UINT256_MAX, - maxCalls: 0, + maxCalls: UNLIMITED_CALLS, }); else calls.push({ target: getAddress(call.target), selector: call.selector as UniversalRule['allowedCalls'][number]['selector'], - beneficiaryOffset, + pins: wirePins, maxValue: call.maxValue ?? BigInt(0), }); } @@ -375,7 +359,7 @@ function svmRule(rule: Rule, cea: Hex): SolanaRule { ], }; return { - maxAccounts: 0, + maxAccounts: ANY_ACCOUNT_COUNT, program: call.target, instruction: { idl, name }, accounts: accounts.map((p) => ({ diff --git a/packages/core/src/lib/agentic/reads/rules.ts b/packages/core/src/lib/agentic/reads/rules.ts index 44298144..cceddd31 100644 --- a/packages/core/src/lib/agentic/reads/rules.ts +++ b/packages/core/src/lib/agentic/reads/rules.ts @@ -8,7 +8,7 @@ import type { NativeConfigRead, ModeRead, UniversalConfigRead, -} from '../contracts/v5'; +} from '../contracts/v6'; import { configId } from '../codec/ids'; import { nativeActionTermsToRule } from '../codec/native'; import { UINT256_MAX } from '../codec/defaults'; @@ -287,9 +287,26 @@ export async function decodeActiveRule( target: c.target, selector: c.selector, maxValue: c.maxValue, - pins: c.hasBeneficiary - ? [{ arg: storedArg(c.beneficiaryOffset), expected: WALLET }] - : [], + pins: [ + ...c.pins.map((p) => + p.op === 1 + ? { arg: storedArg(p.offset), max: BigInt(p.value) } + : { + arg: storedArg(p.offset), + expected: + p.value.toLowerCase() === + `0x${cfg.expectedCEA + .slice(2) + .toLowerCase() + .padStart(64, '0')}` + ? WALLET + : p.value, + } + ), + ...(c.hasBeneficiary + ? [{ arg: storedArg(c.beneficiaryOffset), expected: WALLET }] + : []), + ], })), }, }; @@ -322,7 +339,7 @@ export async function decodeActiveRule( configs.some( (c) => c.maxValueTotal !== UINT256_MAX || - Number(c.maxCalls) !== 0 || + Number(c.maxCalls) !== 0xffffffff || (c.amount.enabled && c.amount.maxTotal !== UINT256_MAX) || Number(c.validUntil) !== decoded.validUntil ) @@ -338,14 +355,18 @@ export async function decodeActiveRule( c.selector === '0xffffffff' ? ('value-only' as const) : c.selector, maxValue: c.maxValuePerCall, pins: [ - ...c.pins.map((p) => ({ - arg: storedArg(p.offset), - expected: - p.expected.toLowerCase() === - `0x${wallet.slice(2).toLowerCase().padStart(64, '0')}` - ? WALLET - : p.expected, - })), + ...c.pins.map((p) => + p.op === 1 + ? { arg: storedArg(p.offset), max: BigInt(p.value) } + : { + arg: storedArg(p.offset), + expected: + p.value.toLowerCase() === + `0x${wallet.slice(2).toLowerCase().padStart(64, '0')}` + ? WALLET + : p.value, + } + ), ...(c.amount.enabled ? [{ arg: storedArg(c.amount.offset), max: c.amount.maxPerCall }] : []), diff --git a/packages/core/src/lib/agentic/reads/svm.ts b/packages/core/src/lib/agentic/reads/svm.ts index 56767cff..42c9535b 100644 --- a/packages/core/src/lib/agentic/reads/svm.ts +++ b/packages/core/src/lib/agentic/reads/svm.ts @@ -1,10 +1,10 @@ /** Internal lossless SVM state shared by public reads and execution. */ import type { Address, Hex } from 'viem'; import type { AgenticGeneration } from '../deployments'; -import type { SvmConfigRead } from '../contracts/v5'; +import type { SvmConfigRead } from '../contracts/v6'; import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; import { actionId, configId } from '../codec/ids'; -import { SEND_OUTBOUND_SELECTOR } from '../contracts/v5'; +import { SEND_OUTBOUND_SELECTOR } from '../contracts/v6'; import { validateSvmTerms } from '../codec/svm-terms'; import { chainFromHash, readActiveRules, type ActiveRule } from './rules'; import type { Snapshot } from './snapshot'; diff --git a/packages/core/src/lib/agentic/response.ts b/packages/core/src/lib/agentic/response.ts index 111fdf28..c9b2db19 100644 --- a/packages/core/src/lib/agentic/response.ts +++ b/packages/core/src/lib/agentic/response.ts @@ -22,11 +22,11 @@ import type { UniversalTxResponse, } from '../orchestrator/orchestrator.types'; import { - v5, + v6, SEND_OUTBOUND_SELECTOR, UEA_MULTICALL_PREFIX, type Call, -} from './contracts/v5'; +} from './contracts/v6'; import { generationsFor, resolveWalletGeneration } from './deployments'; import type { AgenticRuntime } from './runtime'; import type { @@ -115,7 +115,7 @@ export async function adaptTrackedResponse( if (resp.agentic || generationsFor(runtime.network).length === 0) return resp; const batch = await adaptNativeAgentBatch(runtime, resp); if (batch) return batch; - const decoded = v5.decodeWalletCall(resp.data as Hex); + const decoded = v6.decodeWalletCall(resp.data as Hex); if ( !decoded || (decoded.kind !== 'execute' && decoded.kind !== 'executeAsAgent') @@ -276,7 +276,7 @@ async function adaptNativeAgentBatch( data: c.data, })); } else { - const batch = v5.decodeWalletCall(resp.data as Hex); + const batch = v6.decodeWalletCall(resp.data as Hex); if (batch?.kind !== 'execute' || batch.mode !== `0x01${'00'.repeat(31)}`) return; outer = batch.calls; @@ -286,7 +286,7 @@ async function adaptNativeAgentBatch( outer.some((c) => c.value !== BigInt(0) || c.target !== outer[0].target) ) return; - const inner = outer.map((c) => v5.decodeWalletCall(c.data)); + const inner = outer.map((c) => v6.decodeWalletCall(c.data)); const first = inner[0]; if (first?.kind !== 'executeAsAgent' || first.calls.length !== 1) return; const nativeCalls: { to: Address; value: bigint; data: Hex }[] = []; diff --git a/packages/core/src/lib/agentic/revert.ts b/packages/core/src/lib/agentic/revert.ts index a6a07daa..0c4430ff 100644 --- a/packages/core/src/lib/agentic/revert.ts +++ b/packages/core/src/lib/agentic/revert.ts @@ -11,7 +11,7 @@ import { AGW_FACTORY_ABI, SMART_SESSION_ABI, UNIVERSAL_RULES_POLICY_ABI, -} from './contracts/abi/v5'; +} from './contracts/abi/v6'; /** URP reverts reached through the engine are truncated to this wrapper. */ export const POLICY_CHECK_REVERTED_SELECTOR = '0xf4270752'; diff --git a/packages/core/src/lib/agentic/utils.ts b/packages/core/src/lib/agentic/utils.ts index e2dbcfd9..bbe20b41 100644 --- a/packages/core/src/lib/agentic/utils.ts +++ b/packages/core/src/lib/agentic/utils.ts @@ -5,7 +5,7 @@ import { CHAIN, PUSH_NETWORK } from '../constants/enums'; import { MOVEABLE_TOKENS } from '../constants/tokens'; import { getPRC20Address } from '../universal/prc20-address'; import { AgenticCapability } from './capabilities'; -import { V5_CAPABILITIES } from './deployments'; +import { V6_CAPABILITIES } from './deployments'; import { actionId as actionIdRaw, configId as configIdRaw, @@ -116,7 +116,7 @@ export const internalAgenticUtils = { rulesPolicy: getAddress(ctx.rulesPolicy), gateway: ctx.gateway, universal: ctx.universal, - capabilities: V5_CAPABILITIES, + capabilities: V6_CAPABILITIES, nowSeconds: ctx.nowSeconds ?? Math.floor(Date.now() / 1000), }).map((p) => encodeSession(p.session) as AgenticHex); }, From f040e3fbbb84a3dccd9269e0c18e8777620eec3f Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Thu, 15 Oct 2026 06:49:59 +0530 Subject: [PATCH 36/68] docs(agw): record v6 deployment migration and acceptance --- plan/agw/README.md | 2 + plan/agw/SOURCES.md | 2 + plan/agw/current-baseline.md | 2 + plan/agw/gaps.md | 2 + plan/agw/implementation-status.md | 9 + plan/agw/pending-items.md | 11 +- plan/agw/questions-harsh.md | 2 +- plan/agw/questions-zaryab.md | 10 +- .../address-book.json | 142 + .../v6-integration-2026-10-14/api.json | 11520 ++++++++++++++++ .../atomic-receipt-unit.log | 27 + .../v6-integration-2026-10-14/build.log | 13 + .../bytecode-comparison.json | 190 + .../v6-integration-2026-10-14/commands.md | 13 + .../contract-changes.md | 185 + .../credential-scan.json | 4 + .../v6-integration-2026-10-14/docs.log | 1 + .../e2e-selection.log | 72 + .../v6-integration-2026-10-14/full-unit.log | 176 + .../head-recheck.json | 6 + .../live-evidence.jsonl | 68 + .../live-focused.log | 41 + .../v6-integration-2026-10-14/live-full.log | 262 + .../local-contracts.log | 31 + .../manifest-surface-check.log | 1 + .../v6-integration-2026-10-14/package.log | 1 + .../v6-integration-2026-10-14/preflight.log | 27 + .../v6-integration-2026-10-14/preset-unit.log | 28 + .../proxy-library-wiring.json | 35 + .../spec-typecheck.log | 0 .../v6-integration-2026-10-14/status.md | 25 + .../v6-integration-2026-10-14/validation.json | 42 + plan/agw/section7-presets.md | 4 +- 33 files changed, 12940 insertions(+), 14 deletions(-) create mode 100644 plan/agw/research/v6-integration-2026-10-14/address-book.json create mode 100644 plan/agw/research/v6-integration-2026-10-14/api.json create mode 100644 plan/agw/research/v6-integration-2026-10-14/atomic-receipt-unit.log create mode 100644 plan/agw/research/v6-integration-2026-10-14/build.log create mode 100644 plan/agw/research/v6-integration-2026-10-14/bytecode-comparison.json create mode 100644 plan/agw/research/v6-integration-2026-10-14/commands.md create mode 100644 plan/agw/research/v6-integration-2026-10-14/contract-changes.md create mode 100644 plan/agw/research/v6-integration-2026-10-14/credential-scan.json create mode 100644 plan/agw/research/v6-integration-2026-10-14/docs.log create mode 100644 plan/agw/research/v6-integration-2026-10-14/e2e-selection.log create mode 100644 plan/agw/research/v6-integration-2026-10-14/full-unit.log create mode 100644 plan/agw/research/v6-integration-2026-10-14/head-recheck.json create mode 100644 plan/agw/research/v6-integration-2026-10-14/live-evidence.jsonl create mode 100644 plan/agw/research/v6-integration-2026-10-14/live-focused.log create mode 100644 plan/agw/research/v6-integration-2026-10-14/live-full.log create mode 100644 plan/agw/research/v6-integration-2026-10-14/local-contracts.log create mode 100644 plan/agw/research/v6-integration-2026-10-14/manifest-surface-check.log create mode 100644 plan/agw/research/v6-integration-2026-10-14/package.log create mode 100644 plan/agw/research/v6-integration-2026-10-14/preflight.log create mode 100644 plan/agw/research/v6-integration-2026-10-14/preset-unit.log create mode 100644 plan/agw/research/v6-integration-2026-10-14/proxy-library-wiring.json create mode 100644 plan/agw/research/v6-integration-2026-10-14/spec-typecheck.log create mode 100644 plan/agw/research/v6-integration-2026-10-14/status.md create mode 100644 plan/agw/research/v6-integration-2026-10-14/validation.json diff --git a/plan/agw/README.md b/plan/agw/README.md index 5b696983..0342444c 100644 --- a/plan/agw/README.md +++ b/plan/agw/README.md @@ -1,5 +1,7 @@ # AGW SDK planning +**Current — October 14:** [v6 SDK migration and acceptance](research/v6-integration-2026-10-14/status.md) supersede the deployment-dependent statements below. Code is local on v4: 2,073 units, 99 contract-backed tests, and 69 distinct live cases have passing coverage. V6 code committed on v4 (`7dca3f2a`) and v5 (`700a52a7`); not pushed yet. + **Current — October 12:** [downloaded sections 6/7, changes and deployment dependencies](section6-action-items.md). SDK-only migration and the [preset framework](section7-presets.md) are implemented locally; [open items](pending-items.md) supersede older decision summaries below. Notion pages 1/5 were refreshed; other ten snapshots retain October 7 timestamps. The new contract feedback is not deployed. This package contains planning, source snapshots and review evidence for `feat/agw-sdk-v4`. Current runtime uses Donut v5 source `2e61e13`; legacy runtime adapters have been removed. diff --git a/plan/agw/SOURCES.md b/plan/agw/SOURCES.md index 55c88bc7..ffaf4572 100644 --- a/plan/agw/SOURCES.md +++ b/plan/agw/SOURCES.md @@ -1,5 +1,7 @@ # AGW source links and refresh procedure +**October 14 contract refresh:** deploy-agw head `e57998c`, deployment source `ffd567d`, fresh Donut v6 suite. [Change list](https://github.com/pushchain/push-agentic-wallets/blob/e57998c2d8ef9db15e69a68061ad3101120a6c6c/docs/6_Contract_Changes_v6.md) · [address book](https://github.com/pushchain/push-agentic-wallets/blob/e57998c2d8ef9db15e69a68061ad3101120a6c6c/deployments/address-book-v6/push_agw_contracts.json) · [SDK migration evidence](research/v6-integration-2026-10-14/status.md). No new Notion export is claimed by this contract-only refresh. + **Latest focused refresh — October 12, 2026:** pages 1 and 5 re-exported with section 6 feedback and SDK section 7 presets. [Change list and deployment boundary](section6-action-items.md). Other ten pages retain their October 7 snapshots; this was not a contract deployment verification. **Latest full refresh — October 7, 2026:** all 12 Notion pages downloaded/imported (1 changed, 11 unchanged), current discussions inspected where exposed, and all three contract repositories fetched. AGW/gateway code is unchanged; core marketplace head `9479aef` adds docs only over `cb69e0b`. Donut code/wiring and Solana program fingerprints match prior probes. [Refresh report, evidence and SDK alignment findings](research/source-refresh-2026-10-07/README.md). diff --git a/plan/agw/current-baseline.md b/plan/agw/current-baseline.md index 40fbc3f3..ce98892a 100644 --- a/plan/agw/current-baseline.md +++ b/plan/agw/current-baseline.md @@ -1,3 +1,5 @@ +> October 14 update: v6 source `ffd567d` and its fresh Donut deployment supersede the v5 runtime baseline below. The SDK migration is implemented locally; 69 distinct live cases have passing coverage across the full run and focused follow-up. See [v6 evidence](research/v6-integration-2026-10-14/status.md). Older version-specific details below are historical. + # Current validated AGW baseline Updated October 7, 2026 after confirmed product decisions, fresh contract refs, and public Solana/native acceptance. **The v5 deployment and native/EVM SDK adapter/codecs are integrated locally. The opt-in `agw` group now includes 58 scenarios with selected-run live coverage, including owner funds-only Solana transfers and mapped policy refusals.** [Extended E2E evidence](research/extended-e2e-2026-10-06/README.md); [full deployment review](research/deployment-review-2026-10-06/README.md). diff --git a/plan/agw/gaps.md b/plan/agw/gaps.md index e94117b9..09cf30e7 100644 --- a/plan/agw/gaps.md +++ b/plan/agw/gaps.md @@ -1,5 +1,7 @@ # AGW contract and SDK gap register +**October 14 override:** G31–G33 contract delivery is received in v6 (`ffd567d`). SDK migration is implemented locally; 99 pinned-contract tests and 69 distinct live cases pass (full run plus focused follow-up). The older pending-deployment statements below are historical. Native ceiling 8, preset catalog/tuple convention and downstream refund credit remain open. [V6 migration evidence](research/v6-integration-2026-10-14/status.md). + **Current override — October 12:** new sections 6/7 supersede the October 7 decisions below. [Feedback work list](section6-action-items.md); [only remaining items](pending-items.md). Unified allowedCalls, zero caps, spend reads, numeric Solana authoring/raw decoded updates, duplicate creation checks and direct label calls are implemented locally. Live acceptance of this changed API is in progress. | ID | Status | Current dependency | diff --git a/plan/agw/implementation-status.md b/plan/agw/implementation-status.md index 2307225d..f9a663c2 100644 --- a/plan/agw/implementation-status.md +++ b/plan/agw/implementation-status.md @@ -1,5 +1,14 @@ # AGW SDK implementation status +**October 14 — v6 integration complete locally:** source `ffd567d`; v6-only deployment/ABIs, atomic indexed creation, automatic outbound approvals, native/EVM EQ/MAX pins, new unlimited sentinels and linked Solana error decoding are integrated. + +- **2,073 unit tests passed**, 12 skipped; **99 local contract tests passed**. +- **69 distinct live scenarios pass across the full run and focused follow-up.** The original run was 67 passed/1 failed (stale allowance assertion), followed by 2/2 passing focused cases, including the new EVM pin alternative proof. Not one clean full invocation. +- Build, lib/spec/local typechecks, guide examples, package imports/declarations and API comparison pass. +- V6 code committed on v4 (`7dca3f2a`) and v5 (`700a52a7`); not pushed yet. Preset catalog/struct-field conventions, the native eight-call ceiling clarification, and downstream revert credit remain separate items. + +[Detailed evidence and commands](research/v6-integration-2026-10-14/status.md). + **Current — October 12 sections 6/7:** SDK-only feedback and the preset framework are implemented locally. [Section 6 work list](section6-action-items.md) · [Preset scope/decisions](section7-presets.md) · [Open items](pending-items.md). - Full unit run: **2,075 passed, 0 failed, 12 skipped**. An earlier 100ms timing-test failure passed both on retry and in this final full run. diff --git a/plan/agw/pending-items.md b/plan/agw/pending-items.md index 4d9831d1..dfe5cf3a 100644 --- a/plan/agw/pending-items.md +++ b/plan/agw/pending-items.md @@ -1,20 +1,21 @@ # AGW SDK pending items -October 12, 2026. The newly downloaded SDK sections 6/7 supersede the earlier `actions[]` proposal and multiple-rule creation decision. See [the item-by-item feedback list](section6-action-items.md). +October 14, 2026. The newly downloaded SDK sections 6/7 supersede the earlier `actions[]` proposal and multiple-rule creation decision. See [the item-by-item feedback list](section6-action-items.md). | Item | Owner / dependency | Completion condition | | --- | --- | --- | -| Exact outbound allowance inside both wallet doors | Contract team, §6.1 | Verified source/ABI/deployment; SDK can then remove manual-allowance preflight | -| Atomic factory create and initial grants | Contract team, §6.2 | Verified entry points, owner/signed variants and index-race behavior; remove partial recovery only then | -| General EVM destination EQ/MAX pins | Contract team, §6.3 | Deployed policy encoding; currently only one WALLET beneficiary pin is supported | + + | Native 1..32 calls in spec versus deployed maximum 8 | Product/contracts | Align spec or deploy increased ceiling; SDK enforces 8 now | | Presets (§7) | Product/app catalog | Approved apps/addresses/chains, struct-field pins and multi-spender approval representation; framework is implemented, missing caps default to zero, incomplete results are typed templates | | ABI compound argument reconstruction | Product/spec metadata | Define struct fields and how layouts survive reads; unsupported layouts fail explicitly | | Native historical lifetime limits | Spec/migration | Define a lossless public representation if these old grants must be editable; never drop their restrictions silently | | Revert credit | Push-core executor | Executor invokes creditRevert; verify restored spend independently | | Delivery/terminal latency | Platform | Resolve delayed terminal status and bounded polling expectations | -| Single clean live run / new-contract acceptance | SDK, then new deployment | Current 68 cases pass across the full run plus targeted rerun; a single clean full invocation and new-contract acceptance remain distinct | +| Single clean live run / new-contract acceptance | SDK, then new deployment | All 69 v6 cases have passing coverage across the full run plus focused follow-up. One clean 69-case invocation remains a separate optional release checkpoint | User decisions recorded October 12: multi-action native `spent` uses per-action entries. Decoded Solana rules may use an explicit raw form for lossless get→update; authored rules use arg/account positions. These no longer require clarification. The first-use EVM gas default is being fixed in the SDK and is no longer an external core/gateway question. `setLabel` already exists on v5; direct invocation requires no contract change. + +V6 accounting note: generic native MAX pins enforce a per-call bound but do not increment the separate `amountSpent` meter. The SDK returns the actual counter (normally zero for the new public shape), plus value/call counters per action; it does not infer token spending from arbitrary numeric arguments. If the UI needs native per-token spend totals, that requires an explicit accounting design. diff --git a/plan/agw/questions-harsh.md b/plan/agw/questions-harsh.md index c7705a93..1dcaaa77 100644 --- a/plan/agw/questions-harsh.md +++ b/plan/agw/questions-harsh.md @@ -6,7 +6,7 @@ Updated October 12, 2026 after the user authorized the section-7 framework. Loca Which verified apps, functions, deployed addresses and chains should ship for `DEXES` and `LENDING`? The framework is implemented, but all categories currently have empty `chains` lists. UI callers should hide them. -The contract/SDK review of those entries must settle tuple-field positions and how multiple apps can safely receive approvals for the same token. The framework rejects ambiguous approval combinations instead of generating unrestricted approvals. General EVM pins also need the pending policy deployment. +The contract/SDK review of those entries must settle tuple-field positions and how multiple apps can safely receive approvals for the same token. V6 now supplies general EVM pins and OR-matching alternatives. The SDK supports separate spender-pinned approval alternatives and rejects unpinned bypasses. Approved app-specific entries and tuple-field conventions still need review. ## Decisions already made — no repeated question diff --git a/plan/agw/questions-zaryab.md b/plan/agw/questions-zaryab.md index cf31cb1c..e634f7bf 100644 --- a/plan/agw/questions-zaryab.md +++ b/plan/agw/questions-zaryab.md @@ -1,14 +1,12 @@ # AGW SDK — contract delivery and confirmation -October 12, 2026. Local draft; nothing has been sent. Source: [contract feedback §6](https://app.notion.com/p/pushprotocol/1-AGW-Contract-Changes-nomenclature-standard-change-set-3e9188aea7f4813aa31fc95ceb4e684d). The user confirms these changes are not deployed. Existing v5 labels and ref removal are already delivered. +October 12, 2026. Local draft; nothing has been sent. Source: [contract feedback §6](https://app.notion.com/p/pushprotocol/1-AGW-Contract-Changes-nomenclature-standard-change-set-3e9188aea7f4813aa31fc95ceb4e684d). V6 is deployed; contract-owner dry runs are still ongoing. Existing v5 labels and ref removal are already delivered. -## Delivery already requested by Harsh +## V6 delivery received October 14 -- **§6.1:** exact gateway approval inside each outbound, on both doors, cleared afterward. SDK allowance checks stay until the implementation/deployment is verified. -- **§6.2:** atomic factory create plus grants. Supply the final ABI and owner/signed entry points, preserving the intended wallet/index binding. Partial-create recovery stays until every supported owner uses the atomic path. -- **§6.3:** general EQ/MAX pins on EVM destination calls. SDK supports the current single WALLET pin and rejects other destination pins until the new policy is available. +Atomic factory creation, automatic gateway approvals and general EVM EQ/MAX pins are delivered in source `ffd567d` and the v6 address book. The SDK has migrated these locally; 99 contract-backed cases and all 69 live scenarios have passing coverage (full run plus focused follow-up). Your independent dry runs remain separate. No repeat request for these delivered interfaces or deployment addresses. -These are delivery dependencies, not requests to reconsider the agreed design. Deployment addresses do not need to be supplied again here; the SDK will verify the updated address book and implementation when notified. +New wire details are accounted for: native maxCalls = uint32 maximum, Solana any-count = 255, pins = (offset, op, value). The policy still reports 3.1.0, so deployment wiring/source pin identify v6. ## Confirmations still needed diff --git a/plan/agw/research/v6-integration-2026-10-14/address-book.json b/plan/agw/research/v6-integration-2026-10-14/address-book.json new file mode 100644 index 00000000..bdf79c4a --- /dev/null +++ b/plan/agw/research/v6-integration-2026-10-14/address-book.json @@ -0,0 +1,142 @@ +{ + "network": "push-donut-testnet", + "chainId": 42101, + "generation": "v6", + "explorer": "https://donut.push.network", + "commit": "git:ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "branch": "deploy-agw", + "engineForkCommit": "7dc20e4", + "forge": "1.5.1-stable", + "deployer": "0xa89523351BE1e2De64937AA9AF61Ae06eAd199C7", + "deployScript": "script/Deploy.s.sol", + "blocks": [ + 24229957, + 24229971 + ], + "deploymentGas": 19799340, + "deploymentCostPC": "0.0222742575", + "summary": "Fresh full suite for the SDK review fixes: URP with the Solana rulebook moved into the linked SvmRulebook library, EVM argument pins, zero-means-nothing limits; AGW with gateway auto-approve and createWallet; AGWFactory with createWallet / createWalletWithSig. Engine and validator are fresh too, bytecode-identical to v4/v5.", + "contracts": { + "factoryProxy": { + "address": "0xFBBEB6a365178fAaA81A9789a5f64b300c37e5bc", + "contract": "ERC1967Proxy (UUPS)", + "sizeBytes": 141, + "verified": true, + "explorer": "https://donut.push.network/address/0xFBBEB6a365178fAaA81A9789a5f64b300c37e5bc", + "deployTx": "0x4b83d7c060b24f56c165737addfae7a65d5b767e432d418c096bce8659422311", + "note": "PERMANENT, user-facing: deploy and look up wallets here. Also the EIP-712 verifyingContract for every OwnerIntent." + }, + "factoryLogic": { + "address": "0x64893c611920604a9247530673071D46ac9174c9", + "contract": "AGWFactory", + "sizeBytes": 14313, + "verified": true, + "explorer": "https://donut.push.network/address/0x64893c611920604a9247530673071D46ac9174c9", + "deployTx": "0x89de4ac81ba480f3fbe55a15f8d47d341fd96a55b1960e1d05b927fca7597054", + "note": "Adds createWallet(label, rules) and createWalletWithSig(intent, sig, label, rules) (selector 0x0a8f332b)." + }, + "walletImplementation": { + "address": "0x536D3EA48219ff743ac663C6c224920e9eB476A5", + "contract": "AGW", + "sizeBytes": 18818, + "verified": true, + "explorer": "https://donut.push.network/address/0x536D3EA48219ff743ac663C6c224920e9eB476A5", + "deployTx": "0x1765e66f36e8530321c4232df0e415a4dbcb15c211e807c49f5315ffd81dbf44", + "note": "Clone target; accountId push.agw.1.0.0. Gateway auto-approve on both doors; initializeAccount(string label, Session[] rules)." + }, + "urp": { + "address": "0xBA32e7A1500cb34311a31127bcD40CA52C8CFd36", + "contract": "TransparentUpgradeableProxy", + "sizeBytes": 830, + "verified": true, + "explorer": "https://donut.push.network/address/0xBA32e7A1500cb34311a31127bcD40CA52C8CFd36", + "deployTx": "0x2d5cf99ffa202f488659444e4bf5a35f4e691967688976a317c4b161b8e55b81", + "note": "PERMANENT: every v6 wallet pins it; every rule names it as its only action policy." + }, + "urpImplementation": { + "address": "0xa176b1424018D52711EDCb9d3D8757dc6e174463", + "contract": "UniversalRulesPolicy (version() still reports 3.1.0)", + "sizeBytes": 18538, + "verified": true, + "explorer": "https://donut.push.network/address/0xa176b1424018D52711EDCb9d3D8757dc6e174463", + "deployTx": "0xe26822d47178d2160b2d7fc2b9ea6b887dd55a321e04b9e8c411bf7493e404a2", + "note": "Verified with --libraries src/policies/SvmRulebook.sol:SvmRulebook:0x15c3259490f0625C75b5a00731e4231b2B529c1E." + }, + "svmRulebook": { + "address": "0x15c3259490f0625C75b5a00731e4231b2B529c1E", + "contract": "SvmRulebook (external library, linked into urpImplementation)", + "sizeBytes": 10612, + "verified": false, + "explorer": "https://donut.push.network/address/0x15c3259490f0625C75b5a00731e4231b2B529c1E", + "deployTx": "0x9bcdccc66827f1e65b2199dc279b3fde6f7cae6f23982d5c314ea8bbef43bbaa", + "note": "Deployed by forge through the CREATE2 deployer 0x4e59b44847b379578588920cA78FbF26c0B4956C. Blockscout does not index the internal creation, reports the address as not a contract, and refuses verification. The code is on chain (eth_getCode) and is embedded in urpImplementation." + }, + "urpProxyAdmin": { + "address": "0x5abC6Ae78EfE01c0F3d6b67389f88952Bf31A805", + "contract": "ProxyAdmin", + "sizeBytes": 926, + "verified": true, + "explorer": "https://donut.push.network/address/0x5abC6Ae78EfE01c0F3d6b67389f88952Bf31A805", + "note": "KEEP: no URP upgrade is possible without it. Created internally by the TUP; read from the ERC-1967 admin slot." + }, + "sessionValidator": { + "address": "0xBf08d8335c1cE41a577DB70666816027814737dD", + "contract": "AgentValidator", + "sizeBytes": 806, + "verified": true, + "explorer": "https://donut.push.network/address/0xBf08d8335c1cE41a577DB70666816027814737dD", + "deployTx": "0xd2ec49fff4e929750d77ba484d797b7ebb87e134dc4c4e9e70efb6a39e7779fc" + }, + "sessionEngine": { + "address": "0xf63DC0628fe1B25049FE3E3a3585Ef051CB98c1d", + "contract": "SmartSession (fork 7dc20e4)", + "sizeBytes": 22581, + "verified": true, + "explorer": "https://donut.push.network/address/0xf63DC0628fe1B25049FE3E3a3585Ef051CB98c1d", + "deployTx": "0x7397a445b52979b5596eccc7cd3028b1dd0308319abb25bc17b2e7050e912fdc" + } + }, + "external": { + "universalGateway": "0x00000000000000000000000000000000000000C1", + "universalCore": "0x00000000000000000000000000000000000000C0", + "ueaFactory": "0x00000000000000000000000000000000000000eA", + "universalExecutorModule": "0x14191Ea54B4c176fCf86f51b0FAc7CB1E71Df7d7", + "gatewayImplementationAtDeploy": "0x1e412939780f2b834DC42C7AC58d9f99888Da659", + "gatewayOutboundSelector": "0x77b86bec" + }, + "adminState": { + "factoryDefaultAdmin": "0xa89523351BE1e2De64937AA9AF61Ae06eAd199C7", + "defaultAdminDelaySeconds": 172800, + "urpProxyAdminOwner": "0xa89523351BE1e2De64937AA9AF61Ae06eAd199C7", + "pauserRole": "none", + "operatorRole": "none", + "note": "Testnet: the factory's default admin and the URP ProxyAdmin owner are both the deployer EOA. PAUSER_ROLE and OPERATOR_ROLE are unassigned; grant them before the factory can be paused." + }, + "ruleEncoding": { + "initData": "abi.encode(uint16 version, string chainNamespace, bytes body), version 1", + "argPinTuple": "(uint16,uint8,bytes32) — offset (selector included, 4 = first argument), op (0 = EQ, 1 = MAX), value", + "allowedCallTuple": "(address,bytes4,uint16,bool,uint256,(uint16,uint8,bytes32)[])", + "universalTermsTuple": "(uint48,address,(address,uint256,uint256)[],uint256,(address,bytes4,uint16,bool,uint256,(uint16,uint8,bytes32)[])[])", + "nativeTermsTuple": "(uint48,address,bytes4,uint256,uint256,(bool,uint16,uint256,uint256),uint32,(uint16,uint8,bytes32)[])", + "tokens": "PRC20 addresses on Push, 1..8 per cross-chain rule; type(uint256).max = unlimited, 0 = nothing", + "maxCalls": "native rules: 0 is refused (ZeroMaxCalls); type(uint32).max = unlimited", + "maxAccounts": "Solana programs: 1..64 exact; 255 = any count; 0 and 65..254 refused", + "approvals": "none needed: the wallet approves the gateway for exactly the outbound amount and clears the allowance after the call", + "pushChainHash": "0x3d6bc1f1d3fb03065860265a8e93840b586e57075d956cd41b4319d040be87f9" + }, + "createWallet": { + "maxInitialRules": 8, + "signedForm": "createWalletWithSig: intent.sessionHash == keccak256(abi.encode(rules)) and intent.grantNonce == 0; the label is not signed", + "selector": "0x0a8f332b" + }, + "supersedes": { + "generation": "v5", + "factoryProxy": "0x8137F96A50EBF41d904e3678c84c391a0D1BCcc5", + "factoryLogic": "0xe549d3D4e85cB16F687448D7acA21D9d13A7cD0f", + "walletImplementation": "0x4D459Da499C14548aa16c46c57fD92880A88EBb4", + "urp": "0x603E7f0aF6e1aAFf46DDfb28b1e99364f8BC59af", + "sessionEngine": "0x165A5E6782f39D30B38c7D97e1303e4CB2aD102a", + "sessionValidator": "0x068EE2388475A98EE1f5a434C58bFF3444fffFe6", + "note": "v5 and v4 wallets keep working against the v4 URP and engine, which stay live; they do not get v6 behaviour. The v5 book is kept beside this one in deployments/address-book-v5/." + } +} diff --git a/plan/agw/research/v6-integration-2026-10-14/api.json b/plan/agw/research/v6-integration-2026-10-14/api.json new file mode 100644 index 00000000..fb545c0a --- /dev/null +++ b/plan/agw/research/v6-integration-2026-10-14/api.json @@ -0,0 +1,11520 @@ +{ + "baseline": "b1597b91a25dbf7f691f589b4e1e154add604315", + "head": "31db25bb8f88699ae6daed556704135188b7558a", + "compiledMatchesSource": true, + "initializeSignatureChanged": false, + "addedExports": [ + "AgenticPresets", + "DecodedSolanaRule", + "Pin", + "Preset", + "PresetAsset", + "PresetCategory", + "PresetOptions", + "PresetRuleTemplate", + "ReadyPresetOptions", + "RuleInput", + "Spent", + "WalletMarker" + ], + "removedExports": [ + "AgenticNetworkConstants", + "NativeRule", + "UniversalRule" + ], + "changedAgwTypes": [ + "AgenticWallet", + "AgenticError", + "AgenticRevertError", + "AGENTIC_ERROR_CODE", + "Rule", + "RuleInput", + "Pin", + "Spent", + "NativeRule", + "AssetCap", + "AllowedCall", + "UniversalRule", + "RulesRecord", + "CreateOptions", + "AgenticTxMetadata" + ], + "publicTypeChanges": [ + "AGENTIC_ERROR_CODE", + "AgenticError", + "AgenticRevertError", + "AgenticErrorCode", + "AgenticTxMetadata", + "AgenticWallet", + "AllowedCall", + "AssetCap", + "CreateOptions", + "DecodedSolanaRule", + "Rule", + "RuleInput", + "Pin", + "Spent", + "WalletMarker", + "RulesRecord", + "Preset", + "PresetCategory", + "PresetAsset", + "PresetOptions", + "ReadyPresetOptions", + "PresetRuleTemplate", + "AgenticPresets" + ], + "transactionMethodChanges": [], + "instanceMethodChanges": [], + "agwConstantsChanged": true, + "before": { + "exports": [ + "AGENTIC_ERROR_CODE", + "AccountRole", + "AccountStatus", + "AccountType", + "AgenticAddress", + "AgenticDoor", + "AgenticError", + "AgenticErrorCode", + "AgenticHex", + "AgenticNamespace", + "AgenticNetworkConstants", + "AgenticProgressHook", + "AgenticRevertError", + "AgenticTxMetadata", + "AgenticWallet", + "AllowedCall", + "AssetCap", + "BatchReadResponse", + "BuildReadSpecParams", + "CHAIN", + "CONTRACT_REQUEST_STATUS", + "CascadeCompletionResult", + "CascadeHopInfo", + "CascadeProgressEvent", + "CascadeTrackOptions", + "CascadedTxResponse", + "ChainSource", + "ChainTarget", + "Checkpoint", + "CheckpointKind", + "ConversionQuote", + "CreateOptions", + "CreateResult", + "DEFAULT_MAX_PC_FOR_GAS_BUFFER_BPS", + "DecodedErrorPayload", + "DecodedReadResult", + "DerivedExecutorAccount", + "EncodedReadQuery", + "EvmReadQuery", + "ForeignChainNamespace", + "FulfilOutcome", + "FundsToken", + "InsufficientPC20BalanceError", + "InvalidPC20AddressError", + "InvalidPC20MetadataError", + "InvalidReadQueryError", + "InvalidReadSpecError", + "MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT", + "MaxPCForGasCapFromNativeValueInput", + "MaxPCForGasCapInput", + "MaxPCForGasCapQuote", + "MultiChainTxResponse", + "NativeRule", + "OutboundTxDetails", + "PC20AddressResult", + "PC20AmbiguousAddressError", + "PC20Error", + "PC20ExpectedButPRC20Error", + "PC20ExportRevertedError", + "PC20FactoryMismatchError", + "PC20RegistryEntry", + "PC20RegistryMismatchError", + "PC20TokenChainMismatchError", + "PC20TokenReference", + "PC20UnknownChainNamespaceError", + "PC20UnsafeEmptyPayloadError", + "PC20WrapperNotRegisteredError", + "PC20WrapperPredictionUnavailableError", + "ParsedReadRequest", + "PreparedRead", + "PreparedUniversalTx", + "PushChain", + "PushChainBatchExecutionError", + "PushChainExecutionError", + "PushChainInitializeOptions", + "READ_ERROR_CODE", + "READ_OUTCOME", + "READ_STATUS", + "ReadCallback", + "ReadCallbackOptions", + "ReadChain", + "ReadDecodeError", + "ReadDestination", + "ReadExecuteOptions", + "ReadFees", + "ReadHeightUnavailableError", + "ReadLifecycleOptions", + "ReadNotFoundError", + "ReadOptions", + "ReadPreflight", + "ReadPrepareOptions", + "ReadQuery", + "ReadQueryOptions", + "ReadRef", + "ReadRegistryUnavailableError", + "ReadResponseTuple", + "ReadResultShape", + "ReadSpec", + "ReadSpecTuple", + "ReadSpecViolation", + "ReadStateError", + "ReadTimeoutError", + "ReadTrackOptions", + "ReadValue", + "ReadWeb2Options", + "ReceiptLike", + "RescueFundsParams", + "ResolvedAccount", + "ResolvedControllerAccounts", + "ResolvedDestination", + "Rule", + "RulesRecord", + "Selector", + "SignAuthorizationParams", + "SignedAuthorization", + "SimulateReadResult", + "SvmExecutePayloadFields", + "SvmGatewayAccountMeta", + "SvmReadQuery", + "TERMINAL_READ_STATUSES", + "TransactionRoute", + "TransactionRouteType", + "UEAStatus", + "UNIVERSAL_CALLBACK_EVM", + "UNIVERSAL_READ_REGISTRY_EVM", + "UNIVERSAL_READ_STATUS", + "UniversalAccount", + "UniversalExecuteParams", + "UniversalOutboundTxRequest", + "UniversalReadResponse", + "UniversalRule", + "UniversalSigner", + "UniversalSignerSkeleton", + "UniversalTo", + "UnsupportedPC20DestinationError", + "UnsupportedReadDestinationError", + "ValidateReadCall", + "WaitForOutboundOptions", + "WalletInfo", + "WalletSummary", + "Web2Extract", + "Web2ReadQuery", + "Web2ValueType", + "buildErc20WithdrawalMulticall", + "buildMigrationPayload", + "buildReadSpecFromPreflight", + "chainSupportsCEA", + "chainSupportsOutbound", + "decodeReadResult", + "detectRoute", + "encodeReadQuery", + "encodeSvmExecutePayload", + "getAllCEAAddresses", + "getCEAAddress", + "getCEAFactoryAddress", + "getPushAccountForCEA", + "inferResultShape", + "isCEA", + "isChainTarget", + "isPC20Reference", + "isSvmChain", + "isValidSolanaHexAddress", + "parseFulfilOutcome", + "parseReadRequestsFromReceipt", + "parseUEAVersion", + "quoteMaxPCForGasCap", + "quoteMaxPCForGasCapFromNativeValue", + "resolveDestination", + "sizeCallbackBudget", + "toCallData", + "toReadQuery", + "toRequestIdHex", + "validateReadSpec" + ], + "agw": { + "AgenticNamespace": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace", + "members": { + "create": { + "optional": false, + "readonly": false, + "type": "(label: string, options: import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions) => Promise" + }, + "derive": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n index?: number;\n}) => Promise<{\n address: `0x${string}`;\n deployed: boolean;\n index: number;\n}>" + }, + "list": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n wallets: import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary[];\n}>" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "(address: `0x${string}`) => import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet" + } + } + }, + "AgenticWallet": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "checkpoints": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n sinceBlock?: bigint;\n}) => Promise<{\n checkpoints: import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint[];\n}>" + }, + "info": { + "optional": false, + "readonly": false, + "type": "() => Promise" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n owner: `0x${string}`;\n}>" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "{\n add(rules: import(\"sdk/src/lib/agentic/agentic.types\").Rule[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise<{\n rulesIds: `0x${string}`[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n get(rulesId: `0x${string}`): Promise;\n list(): Promise<{\n rules: import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord[];\n }>;\n revoke(rulesIds: `0x${string}`[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n revoke(params: {\n all: true;\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n update(params: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n rules: {\n rule: import(\"sdk/src/lib/agentic/agentic.types\").Rule;\n rulesId: `0x${string}`;\n }[];\n }): Promise<{\n rules: {\n replaced: `0x${string}`;\n rulesId: `0x${string}`;\n }[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n}" + }, + "setLabel": { + "optional": false, + "readonly": false, + "type": "(label: string, opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n}) => Promise" + } + } + }, + "AgenticError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"CREATE_PARTIAL\" | \"DUPLICATE_RULE\" | \"FROM_NOT_ALLOWED\" | \"GATEWAY_ALLOWANCE_INSUFFICIENT\" | \"GENERATION_UNSUPPORTED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"REVOKE_NEEDS_TARGET\" | \"RULE_LIMIT_EXCEEDED\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"" + }, + "details": { + "optional": true, + "readonly": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "AgenticRevertError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticRevertError", + "members": { + "agenticCode": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + } + } + }, + "AGENTIC_ERROR_CODE": { + "type": "{\n readonly AGENT_GAS_INSUFFICIENT: \"AGENT_GAS_INSUFFICIENT\";\n readonly AGENT_IS_OWNER: \"AGENT_IS_OWNER\";\n readonly ASSET_CHAIN_MISMATCH: \"ASSET_CHAIN_MISMATCH\";\n readonly CAPABILITY_UNAVAILABLE: \"CAPABILITY_UNAVAILABLE\";\n readonly CREATE_PARTIAL: \"CREATE_PARTIAL\";\n readonly DUPLICATE_RULE: \"DUPLICATE_RULE\";\n readonly FROM_NOT_ALLOWED: \"FROM_NOT_ALLOWED\";\n readonly GATEWAY_ALLOWANCE_INSUFFICIENT: \"GATEWAY_ALLOWANCE_INSUFFICIENT\";\n readonly GENERATION_UNSUPPORTED: \"GENERATION_UNSUPPORTED\";\n readonly INCONSISTENT_READ: \"INCONSISTENT_READ\";\n readonly INDEX_RACE: \"INDEX_RACE\";\n readonly INVALID_RULE: \"INVALID_RULE\";\n readonly NO_RULES_FOR_CHAIN: \"NO_RULES_FOR_CHAIN\";\n readonly NOT_AGENTIC_WALLET: \"NOT_AGENTIC_WALLET\";\n readonly NOT_ALLOWED_IN_AGENTIC_MODE: \"NOT_ALLOWED_IN_AGENTIC_MODE\";\n readonly NOT_OWNER_OR_AGENT: \"NOT_OWNER_OR_AGENT\";\n readonly NOT_WALLET_OWNER: \"NOT_WALLET_OWNER\";\n readonly READ_ONLY: \"READ_ONLY\";\n readonly RECEIPT_MISMATCH: \"RECEIPT_MISMATCH\";\n readonly RECEIPT_UNAVAILABLE: \"RECEIPT_UNAVAILABLE\";\n readonly REVOKE_NEEDS_TARGET: \"REVOKE_NEEDS_TARGET\";\n readonly RULE_LIMIT_EXCEEDED: \"RULE_LIMIT_EXCEEDED\";\n readonly RULE_NOT_FOUND: \"RULE_NOT_FOUND\";\n readonly RULE_READ_FAILED: \"RULE_READ_FAILED\";\n readonly TARGET_NOT_ON_RULE_CHAIN: \"TARGET_NOT_ON_RULE_CHAIN\";\n readonly WALLET_BALANCE_INSUFFICIENT: \"WALLET_BALANCE_INSUFFICIENT\";\n readonly WALLET_NOT_DEPLOYED: \"WALLET_NOT_DEPLOYED\";\n}", + "members": { + "AGENT_GAS_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\"" + }, + "AGENT_IS_OWNER": { + "optional": false, + "readonly": true, + "type": "\"AGENT_IS_OWNER\"" + }, + "ASSET_CHAIN_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"ASSET_CHAIN_MISMATCH\"" + }, + "CAPABILITY_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"CAPABILITY_UNAVAILABLE\"" + }, + "CREATE_PARTIAL": { + "optional": false, + "readonly": true, + "type": "\"CREATE_PARTIAL\"" + }, + "DUPLICATE_RULE": { + "optional": false, + "readonly": true, + "type": "\"DUPLICATE_RULE\"" + }, + "FROM_NOT_ALLOWED": { + "optional": false, + "readonly": true, + "type": "\"FROM_NOT_ALLOWED\"" + }, + "GATEWAY_ALLOWANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"GATEWAY_ALLOWANCE_INSUFFICIENT\"" + }, + "GENERATION_UNSUPPORTED": { + "optional": false, + "readonly": true, + "type": "\"GENERATION_UNSUPPORTED\"" + }, + "INCONSISTENT_READ": { + "optional": false, + "readonly": true, + "type": "\"INCONSISTENT_READ\"" + }, + "INDEX_RACE": { + "optional": false, + "readonly": true, + "type": "\"INDEX_RACE\"" + }, + "INVALID_RULE": { + "optional": false, + "readonly": true, + "type": "\"INVALID_RULE\"" + }, + "NO_RULES_FOR_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"NO_RULES_FOR_CHAIN\"" + }, + "NOT_AGENTIC_WALLET": { + "optional": false, + "readonly": true, + "type": "\"NOT_AGENTIC_WALLET\"" + }, + "NOT_ALLOWED_IN_AGENTIC_MODE": { + "optional": false, + "readonly": true, + "type": "\"NOT_ALLOWED_IN_AGENTIC_MODE\"" + }, + "NOT_OWNER_OR_AGENT": { + "optional": false, + "readonly": true, + "type": "\"NOT_OWNER_OR_AGENT\"" + }, + "NOT_WALLET_OWNER": { + "optional": false, + "readonly": true, + "type": "\"NOT_WALLET_OWNER\"" + }, + "READ_ONLY": { + "optional": false, + "readonly": true, + "type": "\"READ_ONLY\"" + }, + "RECEIPT_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_MISMATCH\"" + }, + "RECEIPT_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_UNAVAILABLE\"" + }, + "REVOKE_NEEDS_TARGET": { + "optional": false, + "readonly": true, + "type": "\"REVOKE_NEEDS_TARGET\"" + }, + "RULE_LIMIT_EXCEEDED": { + "optional": false, + "readonly": true, + "type": "\"RULE_LIMIT_EXCEEDED\"" + }, + "RULE_NOT_FOUND": { + "optional": false, + "readonly": true, + "type": "\"RULE_NOT_FOUND\"" + }, + "RULE_READ_FAILED": { + "optional": false, + "readonly": true, + "type": "\"RULE_READ_FAILED\"" + }, + "TARGET_NOT_ON_RULE_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"TARGET_NOT_ON_RULE_CHAIN\"" + }, + "WALLET_BALANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"WALLET_BALANCE_INSUFFICIENT\"" + }, + "WALLET_NOT_DEPLOYED": { + "optional": false, + "readonly": true, + "type": "\"WALLET_NOT_DEPLOYED\"" + } + } + }, + "Rule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule | import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "NativeRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "amount": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AmountLimit | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "maxCalls": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValuePerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxValueTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "pins": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ArgPin[] | undefined" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "AssetCap": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap", + "members": { + "maxPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/constants/tokens\").MoveableToken" + } + } + }, + "AllowedCall": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall", + "members": { + "beneficiary": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValue": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "`${string}(${string})` | `0x${string}`" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "UniversalRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall[]" + }, + "assets": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap[]" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "`eip155:${string}` | `solana:${string}`" + }, + "maxGasPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "RulesRecord": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "enabled": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "ref": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "rule": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule | import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule" + }, + "rulesId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "CreateOptions": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions", + "members": { + "progressHook": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook | undefined" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Rule[]" + } + } + }, + "CreateResult": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateResult", + "members": { + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "rulesIds": { + "optional": false, + "readonly": false, + "type": "`0x${string}`[]" + }, + "tx": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticTxMetadata": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticTxMetadata", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destinationAccount": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "destinationCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "door": { + "optional": false, + "readonly": false, + "type": "\"agent\" | \"owner\"" + }, + "nativeCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "rawData": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rawTo": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesId": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + } + }, + "publicSurface": { + "CHAIN": { + "type": "typeof import(\"sdk/src/lib/constants/enums\").CHAIN", + "members": { + "ARBITRUM_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA" + }, + "BASE_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA" + }, + "BNB_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET" + }, + "ETHEREUM_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET" + }, + "ETHEREUM_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA" + }, + "PUSH_LOCALNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET" + }, + "PUSH_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET" + }, + "PUSH_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET" + }, + "PUSH_TESTNET_DONUT": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET" + }, + "SOLANA_DEVNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET" + }, + "SOLANA_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET" + }, + "SOLANA_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET" + }, + "WEB2": { + "optional": false, + "readonly": false, + "type": "\"web2\"" + } + } + }, + "ConversionQuote": { + "type": "import(\"sdk/src/lib/constants/tokens\").ConversionQuote", + "members": { + "amountIn": { + "optional": false, + "readonly": false, + "type": "string" + }, + "amountOut": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rate": { + "optional": false, + "readonly": false, + "type": "number" + }, + "route": { + "optional": true, + "readonly": false, + "type": "string[] | undefined" + }, + "timestamp": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "UniversalSigner": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalSigner", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "signAndSendTransaction": { + "optional": false, + "readonly": false, + "type": "(unsignedTx: Uint8Array) => Promise" + }, + "signAuthorization": { + "optional": true, + "readonly": false, + "type": "((params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise) | undefined" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": true, + "readonly": false, + "type": "(({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise) | undefined" + } + } + }, + "UniversalAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "UniversalSignerSkeleton": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "signAndSendTransaction": { + "optional": false, + "readonly": false, + "type": "(unsignedTx: Uint8Array) => Promise" + }, + "signAuthorization": { + "optional": true, + "readonly": false, + "type": "((params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise) | undefined" + }, + "signerId": { + "optional": false, + "readonly": false, + "type": "string" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": true, + "readonly": false, + "type": "(({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise) | undefined" + } + } + }, + "SignAuthorizationParams": { + "type": "{\n chainId?: number;\n contractAddress: `0x${string}`;\n executor?: \"self\";\n nonce?: number;\n}", + "members": { + "chainId": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "contractAddress": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "executor": { + "optional": true, + "readonly": false, + "type": "\"self\" | undefined" + }, + "nonce": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "SignedAuthorization": { + "type": "{\n address: `0x${string}`;\n chainId: number;\n nonce: number;\n r: `0x${string}`;\n s: `0x${string}`;\n v?: bigint;\n yParity: number;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainId": { + "optional": false, + "readonly": false, + "type": "number" + }, + "nonce": { + "optional": false, + "readonly": false, + "type": "number" + }, + "r": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "s": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "v": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "yParity": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "DerivedExecutorAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").DerivedExecutorAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean | null" + } + } + }, + "ResolvedAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainName": { + "optional": false, + "readonly": false, + "type": "string" + }, + "exists": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "role": { + "optional": true, + "readonly": false, + "type": "\"controller\" | undefined" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"cea\" | \"uea\" | \"uoa\"" + } + } + }, + "ResolvedControllerAccounts": { + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedControllerAccounts", + "members": { + "accounts": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedAccount[]" + } + } + }, + "AccountType": { + "type": "\"cea\" | \"uea\" | \"uoa\"", + "members": {} + }, + "AccountRole": { + "type": "\"controller\"", + "members": {} + }, + "PC20TokenReference": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "FundsToken": { + "type": "import(\"sdk/src/lib/constants/tokens\").MoveableToken | import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20TokenReference", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "PC20RegistryEntry": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "chainName": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "PC20AddressResult": { + "type": "{\n address: `0x${string}`;\n decimals: number;\n name: string;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n registry: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20RegistryEntry[];\n symbol: string;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "decimals": { + "optional": false, + "readonly": false, + "type": "number" + }, + "name": { + "optional": false, + "readonly": false, + "type": "string" + }, + "network": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "registry": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20RegistryEntry[]" + }, + "symbol": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "isPC20Reference": { + "type": "(token: import(\"sdk/src/lib/orchestrator/orchestrator.types\").FundsToken | undefined) => token is import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20TokenReference", + "members": {} + }, + "PC20Error": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20Error", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidPC20AddressError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InvalidPC20AddressError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20TokenChainMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20TokenChainMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20WrapperNotRegisteredError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20WrapperNotRegisteredError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20RegistryMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20RegistryMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20FactoryMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20FactoryMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidPC20MetadataError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InvalidPC20MetadataError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20ExpectedButPRC20Error": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20ExpectedButPRC20Error", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20AmbiguousAddressError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20AmbiguousAddressError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "candidates": { + "optional": false, + "readonly": true, + "type": "{\n chain: string;\n pushAddress: string;\n}[]" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "UnsupportedPC20DestinationError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").UnsupportedPC20DestinationError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InsufficientPC20BalanceError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InsufficientPC20BalanceError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20UnknownChainNamespaceError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20UnknownChainNamespaceError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20WrapperPredictionUnavailableError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20WrapperPredictionUnavailableError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20ExportRevertedError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20ExportRevertedError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "lockedAmount": { + "optional": true, + "readonly": true, + "type": "bigint | undefined" + }, + "outboundTxId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "revertRecipient": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20UnsafeEmptyPayloadError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20UnsafeEmptyPayloadError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ChainTarget": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "ChainSource": { + "type": "{\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "UniversalTo": { + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget", + "members": {} + }, + "TransactionRouteType": { + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"", + "members": {} + }, + "UniversalExecuteParams": { + "type": "{\n from?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainSource;\n migration?: boolean;\n to: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTo;\n} & Omit", + "members": { + "_minimumDepositUsd": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "_requiredFundsOverride": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "_skipFeeLocking": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "_ueaStatus": { + "optional": true, + "readonly": false, + "type": "{\n balance: bigint;\n isDeployed: boolean;\n nonce: bigint;\n} | undefined" + }, + "data": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiCall[] | undefined" + }, + "deadline": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "feeLockTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "from": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainSource | undefined" + }, + "funds": { + "optional": true, + "readonly": false, + "type": "{\n amount: bigint;\n token?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").FundsToken;\n} | undefined" + }, + "gasLimit": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFeePerGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxPCForGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxPriorityFeePerGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "migration": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "nonce": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "options": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions | undefined" + }, + "payGasWith": { + "optional": true, + "readonly": false, + "type": "{\n minAmountOut?: bigint | string;\n slippageBps?: number;\n token?: import(\"sdk/src/lib/constants/tokens\").PayableToken;\n} | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "to": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget" + }, + "value": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "UniversalOutboundTxRequest": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalOutboundTxRequest", + "members": { + "amount": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gasPrice": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxPCForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "payload": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "recipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "revertRecipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "PreparedUniversalTx": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx", + "members": { + "_hop": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").HopDescriptor" + }, + "deadline": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "estimatedGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gatewayRequest": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalOutboundTxRequest | import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxRequest" + }, + "nonce": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "payload": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + } + } + }, + "CascadedTxResponse": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadedTxResponse", + "members": { + "finalTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hopCount": { + "optional": false, + "readonly": false, + "type": "number" + }, + "hops": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo[]" + }, + "initialTxHash": { + "optional": false, + "readonly": false, + "type": "string" + }, + "initialTxResponse": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions) => Promise" + }, + "waitForAll": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions) => Promise" + } + } + }, + "CascadeHopInfo": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo", + "members": { + "executionChain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "expectedSubTxId": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hopIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "outboundDetails": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").OutboundTxDetails | undefined" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + }, + "status": { + "optional": false, + "readonly": false, + "type": "\"confirmed\" | \"failed\" | \"pending\" | \"submitted\"" + }, + "txHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "CascadeTrackOptions": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions", + "members": { + "eventHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeProgressEvent) => void) | undefined" + }, + "timeout": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "CascadeProgressEvent": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeProgressEvent", + "members": { + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "elapsed": { + "optional": false, + "readonly": false, + "type": "number" + }, + "hopIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + }, + "status": { + "optional": false, + "readonly": false, + "type": "\"confirmed\" | \"failed\" | \"found\" | \"polling\" | \"timeout\" | \"waiting\"" + }, + "txHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "CascadeCompletionResult": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeCompletionResult", + "members": { + "failedAt": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "finalTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "finalTxResponse": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadedTxResponse | undefined" + }, + "hops": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo[]" + }, + "success": { + "optional": false, + "readonly": false, + "type": "boolean" + } + } + }, + "MultiChainTxResponse": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiChainTxResponse", + "members": { + "chains": { + "optional": false, + "readonly": false, + "type": "{\n blockNumber: bigint;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n hash: string;\n status: \"confirmed\" | \"failed\" | \"pending\";\n}[]" + }, + "transactions": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse[]" + } + } + }, + "OutboundTxDetails": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").OutboundTxDetails", + "members": { + "amount": { + "optional": false, + "readonly": false, + "type": "string" + }, + "assetAddr": { + "optional": false, + "readonly": false, + "type": "string" + }, + "destinationChain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "explorerUrl": { + "optional": false, + "readonly": false, + "type": "string" + }, + "externalTxHash": { + "optional": false, + "readonly": false, + "type": "string" + }, + "recipient": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "WaitForOutboundOptions": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").WaitForOutboundOptions", + "members": { + "_expectedDestinationChain": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "_outboundIndex": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "_resolvedSubTxId": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "initialWaitMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: {\n elapsed: number;\n status: \"failed\" | \"found\" | \"polling\" | \"timeout\" | \"waiting\";\n}) => void) | undefined" + }, + "timeout": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "SvmGatewayAccountMeta": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmGatewayAccountMeta", + "members": { + "isWritable": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "pubkey": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "SvmExecutePayloadFields": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmExecutePayloadFields", + "members": { + "accounts": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmGatewayAccountMeta[]" + }, + "instructionId": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "ixData": { + "optional": false, + "readonly": false, + "type": "Uint8Array" + }, + "targetProgram": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AccountStatus": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus", + "members": { + "mode": { + "optional": false, + "readonly": false, + "type": "\"read-only\" | \"signer\"" + }, + "uea": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UEAStatus" + } + } + }, + "UEAStatus": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UEAStatus", + "members": { + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "loaded": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "minRequiredVersion": { + "optional": false, + "readonly": false, + "type": "string" + }, + "requiresUpgrade": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "version": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "RescueFundsParams": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").RescueFundsParams", + "members": { + "prc20": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "universalTxId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "parseUEAVersion": { + "type": "(version: string) => number", + "members": {} + }, + "TransactionRoute": { + "type": "typeof import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute", + "members": { + "CEA_TO_CEA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.CEA_TO_CEA" + }, + "CEA_TO_PUSH": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.CEA_TO_PUSH" + }, + "UOA_TO_CEA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.UOA_TO_CEA" + }, + "UOA_TO_PUSH": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.UOA_TO_PUSH" + } + } + }, + "detectRoute": { + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams) => import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute", + "members": {} + }, + "isChainTarget": { + "type": "(to: unknown) => to is import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget", + "members": {} + }, + "DEFAULT_MAX_PC_FOR_GAS_BUFFER_BPS": { + "type": "1000", + "members": {} + }, + "MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT": { + "type": "10000", + "members": {} + }, + "quoteMaxPCForGasCap": { + "type": "(input: import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapInput) => import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": {} + }, + "quoteMaxPCForGasCapFromNativeValue": { + "type": "(input: import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapFromNativeValueInput) => import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": {} + }, + "MaxPCForGasCapInput": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapInput", + "members": { + "bufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "gasLegNativePc": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "MaxPCForGasCapFromNativeValueInput": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapFromNativeValueInput", + "members": { + "bufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "nativeValueForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "MaxPCForGasCapQuote": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": { + "bufferBps": { + "optional": false, + "readonly": false, + "type": "number" + }, + "gasLegNativePc": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxPCForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "nativeValueForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "getCEAAddress": { + "type": "(ueaAddress: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise", + "members": {} + }, + "getPushAccountForCEA": { + "type": "(ceaAddress: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise<`0x${string}`>", + "members": {} + }, + "isCEA": { + "type": "(address: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise", + "members": {} + }, + "chainSupportsCEA": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "chainSupportsOutbound": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "getCEAFactoryAddress": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => `0x${string}` | undefined", + "members": {} + }, + "getAllCEAAddresses": { + "type": "(ueaAddress: `0x${string}`, rpcUrls?: Partial>) => Promise", + "members": {} + }, + "encodeSvmExecutePayload": { + "type": "(fields: import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmExecutePayloadFields) => `0x${string}`", + "members": {} + }, + "isSvmChain": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "isValidSolanaHexAddress": { + "type": "(address: string) => boolean", + "members": {} + }, + "buildMigrationPayload": { + "type": "() => `0x${string}`", + "members": {} + }, + "buildErc20WithdrawalMulticall": { + "type": "(tokenAddress: `0x${string}`, recipientAddress: `0x${string}`, amount: bigint) => import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiCall[]", + "members": {} + }, + "ReadChain": { + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain", + "members": {} + }, + "ReadDestination": { + "type": "{\n chain: import(\"sdk/src/lib/read-state/read-state.types\").ReadChain;\n} | {\n chainId: string;\n chainNamespace: string;\n}", + "members": {} + }, + "ResolvedDestination": { + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}", + "members": { + "caip2": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainId": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "namespace": { + "optional": false, + "readonly": false, + "type": "\"eip155\" | \"solana\" | \"web2\"" + } + } + }, + "ReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").SvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery", + "members": { + "type": { + "optional": false, + "readonly": false, + "type": "\"accountBalance\" | \"contractCall\" | \"http\" | \"lamportBalance\" | \"rawAccountData\" | \"splTokenAccount\" | \"storageSlot\"" + } + } + }, + "EvmReadQuery": { + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n target: `0x${string}`;\n type: \"contractCall\";\n} | {\n callData: `0x${string}`;\n target: `0x${string}`;\n type: \"contractCall\";\n} | {\n slot: `0x${string}` | bigint;\n target: `0x${string}`;\n type: \"storageSlot\";\n} | {\n target: `0x${string}`;\n type: \"accountBalance\";\n}", + "members": { + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"accountBalance\" | \"contractCall\" | \"storageSlot\"" + } + } + }, + "SvmReadQuery": { + "type": "{\n account: string | Uint8Array;\n accountName?: string;\n idl?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n type: \"rawAccountData\";\n} | {\n account: string | Uint8Array;\n type: \"lamportBalance\";\n} | {\n account: string | Uint8Array;\n type: \"splTokenAccount\";\n}", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "string | Uint8Array" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"lamportBalance\" | \"rawAccountData\" | \"splTokenAccount\"" + } + } + }, + "Web2ReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery", + "members": { + "body": { + "optional": true, + "readonly": false, + "type": "string | Uint8Array | undefined" + }, + "extract": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[]" + }, + "headers": { + "optional": true, + "readonly": false, + "type": "Record | undefined" + }, + "method": { + "optional": true, + "readonly": false, + "type": "\"GET\" | \"POST\" | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"http\"" + }, + "url": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "Web2Extract": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract", + "members": { + "decimals": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "path": { + "optional": false, + "readonly": false, + "type": "string" + }, + "valueType": { + "optional": false, + "readonly": false, + "type": "\"bool\" | \"bytes\" | \"int256\" | \"string\" | \"uint256\"" + } + } + }, + "Web2ValueType": { + "type": "\"bool\" | \"bytes\" | \"int256\" | \"string\" | \"uint256\"", + "members": {} + }, + "EncodedReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery", + "members": { + "blockRef": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "encoded": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "namespace": { + "optional": false, + "readonly": false, + "type": "\"eip155\" | \"solana\" | \"web2\"" + }, + "ownerBytes": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "queryType": { + "optional": false, + "readonly": false, + "type": "number" + }, + "resultShape": { + "optional": false, + "readonly": false, + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}" + }, + "warnings": { + "optional": false, + "readonly": false, + "type": "string[]" + } + } + }, + "ReadResultShape": { + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"bytes32\" | \"evmCall\" | \"raw\" | \"svmAccount\" | \"uint256\" | \"web2\"" + } + } + }, + "DecodedReadResult": { + "type": "{\n accountName: string;\n kind: \"svmAccount\";\n value: unknown;\n} | {\n kind: \"bytes32\";\n value: `0x${string}`;\n} | {\n kind: \"evmCall\";\n value: unknown;\n} | {\n kind: \"raw\";\n value: `0x${string}`;\n} | {\n kind: \"uint256\";\n value: bigint;\n} | {\n kind: \"web2\";\n values: readonly unknown[];\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"bytes32\" | \"evmCall\" | \"raw\" | \"svmAccount\" | \"uint256\" | \"web2\"" + } + } + }, + "ReadPreflight": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight", + "members": { + "destination": { + "optional": false, + "readonly": false, + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}" + }, + "fetchedAt": { + "optional": false, + "readonly": false, + "type": "number" + }, + "observedChainHeight": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pushBlockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pushGasPrice": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "universalCallback": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "universalCore": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ReadSpec": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "{\n chainId: string;\n chainNamespace: string;\n owner: `0x${string}`;\n}" + }, + "blockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "expiryPushChainHeight": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "minConfirmations": { + "optional": false, + "readonly": false, + "type": "number" + }, + "query": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "revertRecipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ReadSpecTuple": { + "type": "readonly [\n readonly [\n string,\n string,\n `0x${string}`\n ],\n `0x${string}`,\n number,\n bigint,\n bigint,\n bigint,\n `0x${string}`\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "readonly [\n string,\n string,\n `0x${string}`\n]" + }, + "1": { + "optional": false, + "readonly": true, + "type": "`0x${string}`" + }, + "2": { + "optional": false, + "readonly": true, + "type": "number" + }, + "3": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "4": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "5": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "6": { + "optional": false, + "readonly": true, + "type": "`0x${string}`" + }, + "length": { + "optional": false, + "readonly": true, + "type": "7" + } + } + }, + "BuildReadSpecParams": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").BuildReadSpecParams", + "members": { + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "budgetBuffer": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback | undefined" + }, + "callbackBudget": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "destination": { + "optional": false, + "readonly": false, + "type": "{\n chain: import(\"sdk/src/lib/read-state/read-state.types\").ReadChain;\n} | {\n chainId: string;\n chainNamespace: string;\n}" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "expiryPushChainHeight": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFeeBufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "owner": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "query": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").SvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "PreparedRead": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead", + "members": { + "__@preparedReadValue": { + "optional": true, + "readonly": true, + "type": "T | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback | undefined" + }, + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "encodedQuery": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery" + }, + "encodedSpec": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "fees": { + "optional": false, + "readonly": false, + "type": "{\n callbackBudget: bigint;\n protocolFee: bigint;\n total: bigint;\n}" + }, + "preflight": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "queryKey": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "resultShape": { + "optional": false, + "readonly": false, + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}" + }, + "spec": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec" + }, + "specTuple": { + "optional": false, + "readonly": false, + "type": "readonly [\n readonly [\n string,\n string,\n `0x${string}`\n ],\n `0x${string}`,\n number,\n bigint,\n bigint,\n bigint,\n `0x${string}`\n]" + }, + "value": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "warnings": { + "optional": false, + "readonly": false, + "type": "string[]" + } + } + }, + "ReadCallback": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "((spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpecTuple, callbackGasLimit: bigint) => readonly unknown[]) | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "gasLimit": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "target": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "SimulateReadResult": { + "type": "{\n args?: readonly unknown[];\n error: string;\n errorName?: string;\n ok: false;\n} | {\n ok: true;\n}", + "members": { + "ok": { + "optional": false, + "readonly": false, + "type": "boolean" + } + } + }, + "ParsedReadRequest": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ParsedReadRequest", + "members": { + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackTarget": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "logIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "originalFunder": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "requestId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "requestIdUint": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "spec": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec" + }, + "totalPaid": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "FulfilOutcome": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").FulfilOutcome", + "members": { + "burned": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "delivered": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "expired": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "failReason": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "gasReported": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refunded": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refundFailed": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "ReceiptLike": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike", + "members": { + "logs": { + "optional": false, + "readonly": false, + "type": "readonly {\n address: string;\n data: string;\n logIndex?: number | string;\n topics: readonly string[];\n}[]" + } + } + }, + "ReadRef": { + "type": "{\n requestId: `0x${string}` | bigint;\n} | {\n txHash: `0x${string}`;\n}", + "members": {} + }, + "ReadLifecycleOptions": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadLifecycleOptions", + "members": { + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "resultShape": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadFees": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadFees", + "members": { + "burned": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "paid": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "refunded": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refundFailed": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + } + } + }, + "UniversalReadResponse": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse", + "members": { + "callbackDelivered": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "callbackFailReason": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "decoded": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").DecodedReadResult | undefined" + }, + "decodeError": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destination": { + "optional": false, + "readonly": false, + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}" + }, + "errorMsg": { + "optional": false, + "readonly": false, + "type": "string" + }, + "explorerUrl": { + "optional": false, + "readonly": false, + "type": "string" + }, + "fees": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadFees" + }, + "isTerminal": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "outcome": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME" + }, + "pcTx": { + "optional": false, + "readonly": false, + "type": "readonly {\n blockHeight: number;\n errorMsg: string;\n status: string;\n txHash: `0x${string}`;\n}[]" + }, + "raw": { + "optional": false, + "readonly": false, + "type": "{\n errorCode: import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n resultData: `0x${string}`;\n status: import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n} | null" + }, + "refresh": { + "optional": false, + "readonly": false, + "type": "() => Promise>" + }, + "request": { + "optional": false, + "readonly": false, + "type": "{\n callbackGasLimit: bigint;\n callbackTarget: `0x${string}`;\n createdAtHeight: bigint;\n logIndex: number;\n originalFunder: `0x${string}`;\n refundTo: `0x${string}`;\n spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec;\n}" + }, + "requestId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "requestIdUint": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "status": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "value": { + "optional": true, + "readonly": false, + "type": "T | undefined" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/read-state/read-state.types\").ReadLifecycleOptions) => Promise>" + } + } + }, + "ReadResponseTuple": { + "type": "{\n -readonly [K in keyof R]: import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse ? T : unknown>;\n}", + "members": {} + }, + "BatchReadResponse": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").BatchReadResponse", + "members": { + "atomic": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "count": { + "optional": false, + "readonly": false, + "type": "number" + }, + "reads": { + "optional": false, + "readonly": false, + "type": "{\n -readonly [K in keyof R]: import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse ? T : unknown>;\n}" + }, + "transactionHashes": { + "optional": true, + "readonly": false, + "type": "readonly `0x${string}`[] | undefined" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: Omit) => Promise>" + } + } + }, + "ReadOptions": { + "type": "((import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">)) & {\n callback?: (Pick & Required>) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n };\n}", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "advanced": { + "optional": true, + "readonly": false, + "type": "{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n} | undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "({\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} & {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n}) | ({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick & Pick & Required>) | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadPrepareOptions": { + "type": "((((({\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\">) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n}) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">)) & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n}) | ((({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n}) | ({\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\">)) & {\n blockNumber?: never;\n minConfirmations?: never;\n})) & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n}) & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "advanced": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadQueryOptions": { + "type": "({\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\">) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n}) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n}) | ({\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\">)", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadCallbackOptions": { + "type": "{\n callback?: ({\n gasLimit?: bigint;\n target: `0x${string}`;\n } & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n };\n}", + "members": { + "callback": { + "optional": true, + "readonly": false, + "type": "({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} | undefined" + } + } + }, + "ReadValue": { + "type": "O extends {\n abi: infer A extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: infer F extends string;\n} ? number extends A[\"length\"] ? unknown : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, O extends {\n args: infer Args extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n} ? Args : readonly [\n] extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> ? import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> & readonly [\n] : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>> extends infer Selected ? Selected extends {\n outputs: readonly unknown[];\n type: \"function\";\n} & import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiFunction ? {\n [key in keyof {\n [key in keyof import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"]]: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterToPrimitiveType, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"][key], import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterKind>;\n }]: {\n [key in keyof import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"]]: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterToPrimitiveType, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"][key], import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterKind>;\n }[key];\n} extends infer types ? types extends readonly [\n] ? void : types extends readonly [\n infer type\n] ? type : types : never : never : never : O extends {\n web2: {\n extract: infer E extends readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n };\n} ? {\n readonly [K in keyof E]: {\n bool: boolean;\n bytes: `0x${string}`;\n int256: bigint;\n string: string;\n uint256: bigint;\n }[E[K][\"valueType\"]];\n} : O extends {\n storageSlot: unknown;\n} ? `0x${string}` : O extends {\n idl: infer I extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} ? string extends Extract, string> ? unknown : (O extends {\n functionName: infer N extends string;\n} ? N : undefined) extends string ? import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/index\").IdlAccounts[{\n [K in Extract, string>]: Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : K> extends Lowercase<(O extends {\n functionName: infer N extends string;\n } ? N : undefined) & string extends `${infer H}_${infer T}` ? `${H}${Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : (O extends {\n functionName: infer N extends string;\n } ? N : undefined) & string> ? K : never;\n}[Extract, string>]] : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/index\").IdlAccounts[Extract, string>] : bigint", + "members": {} + }, + "ValidateReadCall": { + "type": "O extends {\n abi: infer A extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: infer F extends string;\n} ? (readonly [\n] extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> ? {\n args?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n} : {\n args: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n}) & {\n functionName: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionName;\n} : O extends {\n functionName: infer N extends string;\n idl: infer I extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} ? string extends Extract, string> ? unknown : [\n {\n [K in Extract, string>]: Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : K> extends Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : N> ? K : never;\n }[Extract, string>]\n] extends [\n never\n] ? {\n functionName: Extract, string>;\n} : unknown : unknown", + "members": {} + }, + "ReadWeb2Options": { + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options", + "members": { + "body": { + "optional": true, + "readonly": false, + "type": "string | Uint8Array | undefined" + }, + "extract": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[]" + }, + "headers": { + "optional": true, + "readonly": false, + "type": "Record | undefined" + }, + "method": { + "optional": true, + "readonly": false, + "type": "\"GET\" | \"POST\" | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadTrackOptions": { + "type": "{\n advanced?: Omit, \"enforceGasCheck\">;\n resultShape?: import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape;\n}", + "members": { + "advanced": { + "optional": true, + "readonly": false, + "type": "Omit<{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n}, \"enforceGasCheck\"> | undefined" + }, + "resultShape": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape | undefined" + } + } + }, + "ReadExecuteOptions": { + "type": "{\n advanced?: {\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n } | undefined;\n progressHook?: ((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined;\n waitForCompletion?: boolean | undefined;\n}", + "members": { + "advanced": { + "optional": true, + "readonly": false, + "type": "{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n} | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + } + } + }, + "UNIVERSAL_READ_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS", + "members": { + "ABORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.ABORTED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.EXPIRED" + }, + "FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.FAILED" + }, + "FULFILLED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.FULFILLED" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.PENDING" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.UNSPECIFIED" + }, + "VOTING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.VOTING" + } + } + }, + "READ_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS", + "members": { + "ERROR": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.ERROR" + }, + "SUCCESS": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.SUCCESS" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.UNSPECIFIED" + } + } + }, + "READ_ERROR_CODE": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE", + "members": { + "INVALID_QUERY": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.INVALID_QUERY" + }, + "INVALID_RESULT": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.INVALID_RESULT" + }, + "NOT_FOUND": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.NOT_FOUND" + }, + "REJECTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.REJECTED" + }, + "REVERTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.REVERTED" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.UNSPECIFIED" + }, + "UNSUPPORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.UNSUPPORTED" + } + } + }, + "READ_OUTCOME": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME", + "members": { + "ABORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.ABORTED" + }, + "CALLBACK_FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.CALLBACK_FAILED" + }, + "DECODE_FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.DECODE_FAILED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.EXPIRED" + }, + "FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.FAILED" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.PENDING" + }, + "SOURCE_ERROR": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.SOURCE_ERROR" + }, + "SUCCESS": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.SUCCESS" + }, + "UNKNOWN": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.UNKNOWN" + } + } + }, + "CONTRACT_REQUEST_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS", + "members": { + "EXECUTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.EXECUTED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.EXPIRED" + }, + "NONE": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.NONE" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.PENDING" + }, + "SETTLED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.SETTLED" + } + } + }, + "TERMINAL_READ_STATUSES": { + "type": "ReadonlySet", + "members": {} + }, + "ReadStateError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadStateError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidReadQueryError": { + "type": "import(\"sdk/src/lib/read-state/errors\").InvalidReadQueryError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidReadSpecError": { + "type": "import(\"sdk/src/lib/read-state/errors\").InvalidReadSpecError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "violations": { + "optional": false, + "readonly": true, + "type": "readonly import(\"sdk/src/lib/read-state/errors\").ReadSpecViolation[]" + } + } + }, + "ReadHeightUnavailableError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadHeightUnavailableError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "UnsupportedReadDestinationError": { + "type": "import(\"sdk/src/lib/read-state/errors\").UnsupportedReadDestinationError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadDecodeError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadDecodeError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadTimeoutError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadTimeoutError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "lastStatus": { + "optional": false, + "readonly": true, + "type": "number" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadNotFoundError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadNotFoundError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadRegistryUnavailableError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadRegistryUnavailableError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadSpecViolation": { + "type": "\"CALLBACK_GAS_LIMIT_EXCEEDED\" | \"DOMAIN_BLOCKED\" | \"EMPTY_QUERY\" | \"EXCESSIVE_FEE\" | \"INSUFFICIENT_CALLBACK_BUDGET\" | \"INSUFFICIENT_FEE\" | \"INVALID_ACCOUNT_ID\" | \"INVALID_BLOCK_NUMBER\" | \"INVALID_EXPIRY_HEIGHT\" | \"INVALID_MIN_CONFIRMATIONS\" | \"SVM_OWNER_NOT_32_BYTES\" | \"ZERO_CALLBACK_BUDGET\" | \"ZERO_CALLBACK_GAS_LIMIT\" | \"ZERO_REVERT_RECIPIENT\"", + "members": {} + }, + "resolveDestination": { + "type": "(dest: import(\"sdk/src/lib/read-state/read-state.types\").ReadDestination) => import(\"sdk/src/lib/read-state/read-state.types\").ResolvedDestination", + "members": {} + }, + "encodeReadQuery": { + "type": "(destination: import(\"sdk/src/lib/read-state/read-state.types\").ReadDestination, query: import(\"sdk/src/lib/read-state/read-state.types\").ReadQuery, options?: {\n blockNumber?: bigint;\n minSlot?: bigint;\n}) => import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery", + "members": {} + }, + "decodeReadResult": { + "type": "(resultData: `0x${string}`, shape: import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape) => import(\"sdk/src/lib/read-state/read-state.types\").DecodedReadResult", + "members": {} + }, + "parseReadRequestsFromReceipt": { + "type": "(receipt: import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike, universalCallback: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").ParsedReadRequest[]", + "members": {} + }, + "parseFulfilOutcome": { + "type": "(receipt: import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike, universalCallback: `0x${string}`, requestId: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").FulfilOutcome", + "members": {} + }, + "buildReadSpecFromPreflight": { + "type": "(preflight: import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight, params: import(\"sdk/src/lib/read-state/read-state.types\").BuildReadSpecParams, defaults?: {\n refundTo?: `0x${string}`;\n}) => import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead", + "members": {} + }, + "validateReadSpec": { + "type": "(input: import(\"sdk/src/lib/read-state/validate\").ValidateReadSpecInput) => {\n ok: false;\n violations: import(\"sdk/src/lib/read-state/errors\").ReadSpecViolation[];\n} | {\n ok: true;\n}", + "members": {} + }, + "toCallData": { + "type": "(prepared: import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead, target: {\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: (spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpecTuple, callbackGasLimit: bigint) => readonly unknown[];\n functionName: string;\n}) => {\n data: `0x${string}`;\n value: bigint;\n}", + "members": {} + }, + "sizeCallbackBudget": { + "type": "(callbackGasLimit: bigint, pushGasPrice: bigint, buffer?: number) => bigint", + "members": {} + }, + "inferResultShape": { + "type": "(namespace: string, query: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape", + "members": {} + }, + "toRequestIdHex": { + "type": "(id: `0x${string}` | bigint) => `0x${string}`", + "members": {} + }, + "toReadQuery": { + "type": "(subject: string, o: ReadOptionsInput, resolvedTokenProgram?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@solana/web3.js/lib/index\").PublicKey) => import(\"sdk/src/lib/read-state/read-state.types\").ReadQuery", + "members": {} + }, + "UNIVERSAL_CALLBACK_EVM": { + "type": "readonly [\n {\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"requestExternalReadSelf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"estimateFee\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"statusOf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"enum RequestStatus\";\n readonly name: \"\";\n readonly type: \"uint8\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"isFulfilled\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getPendingRead\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly internalType: \"struct PendingRead\";\n readonly name: \"\";\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"totalEscrowed\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"blockedDomains\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly indexed: false;\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"readSpec\";\n readonly type: \"tuple\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"totalPaid\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"protocolFee\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ReadRequested\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"ReadFulfilled\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"reason\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"CallbackFailed\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"gasReported\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"burned\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"CallbackGasReported\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundSent\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundFailed\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RequestExpired\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"vaultPC\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ProtocolFeeDistributed\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidAccountId\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"EmptyQuery\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidMinConfirmations\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"DomainBlocked\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidBlockNumber\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidExpiryHeight\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroRevertRecipient\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroCallbackGasLimit\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint64\";\n readonly name: \"provided\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"max\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"CallbackGasLimitExceeded\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"required\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"InsufficientFee\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ExcessiveFee\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"actual\";\n readonly type: \"uint8\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"expected\";\n readonly type: \"uint8\";\n }\n ];\n readonly name: \"InvalidRequestStatus\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ContractIsPaused\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"CallerIsNotUCallbackModule\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n }\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"requestExternalReadSelf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n}" + }, + "1": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"estimateFee\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "2": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"statusOf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"enum RequestStatus\";\n readonly name: \"\";\n readonly type: \"uint8\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "3": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"isFulfilled\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "4": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getPendingRead\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly internalType: \"struct PendingRead\";\n readonly name: \"\";\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "5": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"totalEscrowed\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "6": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"blockedDomains\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "7": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly indexed: false;\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"readSpec\";\n readonly type: \"tuple\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"totalPaid\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"protocolFee\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ReadRequested\";\n readonly type: \"event\";\n}" + }, + "8": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"ReadFulfilled\";\n readonly type: \"event\";\n}" + }, + "9": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"reason\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"CallbackFailed\";\n readonly type: \"event\";\n}" + }, + "10": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"gasReported\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"burned\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"CallbackGasReported\";\n readonly type: \"event\";\n}" + }, + "11": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundSent\";\n readonly type: \"event\";\n}" + }, + "12": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundFailed\";\n readonly type: \"event\";\n}" + }, + "13": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RequestExpired\";\n readonly type: \"event\";\n}" + }, + "14": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"vaultPC\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ProtocolFeeDistributed\";\n readonly type: \"event\";\n}" + }, + "15": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidAccountId\";\n readonly type: \"error\";\n}" + }, + "16": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"EmptyQuery\";\n readonly type: \"error\";\n}" + }, + "17": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidMinConfirmations\";\n readonly type: \"error\";\n}" + }, + "18": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"DomainBlocked\";\n readonly type: \"error\";\n}" + }, + "19": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidBlockNumber\";\n readonly type: \"error\";\n}" + }, + "20": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidExpiryHeight\";\n readonly type: \"error\";\n}" + }, + "21": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroRevertRecipient\";\n readonly type: \"error\";\n}" + }, + "22": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroCallbackGasLimit\";\n readonly type: \"error\";\n}" + }, + "23": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint64\";\n readonly name: \"provided\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"max\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"CallbackGasLimitExceeded\";\n readonly type: \"error\";\n}" + }, + "24": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"required\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"InsufficientFee\";\n readonly type: \"error\";\n}" + }, + "25": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ExcessiveFee\";\n readonly type: \"error\";\n}" + }, + "26": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"actual\";\n readonly type: \"uint8\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"expected\";\n readonly type: \"uint8\";\n }\n ];\n readonly name: \"InvalidRequestStatus\";\n readonly type: \"error\";\n}" + }, + "27": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ContractIsPaused\";\n readonly type: \"error\";\n}" + }, + "28": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"CallerIsNotUCallbackModule\";\n readonly type: \"error\";\n}" + }, + "29": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n}" + }, + "length": { + "optional": false, + "readonly": true, + "type": "30" + } + } + }, + "UNIVERSAL_READ_REGISTRY_EVM": { + "type": "readonly [\n {\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n },\n {\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"read\";\n readonly outputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"universalCallback_\";\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"constructor\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"initialize\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getLocalContext\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"hasResult\";\n readonly outputs: readonly [\n {\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"onUniversalData\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"queryKeyOf\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes32\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"readerOf\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"requestOrderOf\";\n readonly outputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"universalCallback\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"resultByRequestId\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"latestResult\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"version\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"Initialized\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadRequested\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadStored\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidInitialization\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"NotInitializing\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroAddressInit\";\n readonly type: \"error\";\n }\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n },\n {\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"read\";\n readonly outputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n}" + }, + "1": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"universalCallback_\";\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"constructor\";\n}" + }, + "2": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"initialize\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n}" + }, + "3": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getLocalContext\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "4": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"hasResult\";\n readonly outputs: readonly [\n {\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "5": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"onUniversalData\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n}" + }, + "6": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"queryKeyOf\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes32\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "7": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"readerOf\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "8": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"requestOrderOf\";\n readonly outputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "9": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"universalCallback\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "10": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"resultByRequestId\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "11": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"latestResult\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "12": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"version\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"Initialized\";\n readonly type: \"event\";\n}" + }, + "13": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadRequested\";\n readonly type: \"event\";\n}" + }, + "14": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadStored\";\n readonly type: \"event\";\n}" + }, + "15": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidInitialization\";\n readonly type: \"error\";\n}" + }, + "16": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"NotInitializing\";\n readonly type: \"error\";\n}" + }, + "17": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n}" + }, + "18": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroAddressInit\";\n readonly type: \"error\";\n}" + }, + "length": { + "optional": false, + "readonly": true, + "type": "19" + } + } + }, + "PushChainExecutionError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").PushChainExecutionError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PushChainBatchExecutionError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").PushChainBatchExecutionError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": false, + "readonly": true, + "type": "`0x${string}`[]" + } + } + }, + "DecodedErrorPayload": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload", + "members": { + "decoded": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "name": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "selector": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "PushChainInitializeOptions": { + "type": "import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions", + "members": { + "agenticWallet": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "blockExplorers": { + "optional": true, + "readonly": false, + "type": "Partial> | undefined" + }, + "network": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "printTraces": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "rpcUrls": { + "optional": true, + "readonly": false, + "type": "Partial> | undefined" + } + } + }, + "AGENTIC_ERROR_CODE": { + "type": "{\n readonly AGENT_GAS_INSUFFICIENT: \"AGENT_GAS_INSUFFICIENT\";\n readonly AGENT_IS_OWNER: \"AGENT_IS_OWNER\";\n readonly ASSET_CHAIN_MISMATCH: \"ASSET_CHAIN_MISMATCH\";\n readonly CAPABILITY_UNAVAILABLE: \"CAPABILITY_UNAVAILABLE\";\n readonly CREATE_PARTIAL: \"CREATE_PARTIAL\";\n readonly DUPLICATE_RULE: \"DUPLICATE_RULE\";\n readonly FROM_NOT_ALLOWED: \"FROM_NOT_ALLOWED\";\n readonly GATEWAY_ALLOWANCE_INSUFFICIENT: \"GATEWAY_ALLOWANCE_INSUFFICIENT\";\n readonly GENERATION_UNSUPPORTED: \"GENERATION_UNSUPPORTED\";\n readonly INCONSISTENT_READ: \"INCONSISTENT_READ\";\n readonly INDEX_RACE: \"INDEX_RACE\";\n readonly INVALID_RULE: \"INVALID_RULE\";\n readonly NO_RULES_FOR_CHAIN: \"NO_RULES_FOR_CHAIN\";\n readonly NOT_AGENTIC_WALLET: \"NOT_AGENTIC_WALLET\";\n readonly NOT_ALLOWED_IN_AGENTIC_MODE: \"NOT_ALLOWED_IN_AGENTIC_MODE\";\n readonly NOT_OWNER_OR_AGENT: \"NOT_OWNER_OR_AGENT\";\n readonly NOT_WALLET_OWNER: \"NOT_WALLET_OWNER\";\n readonly READ_ONLY: \"READ_ONLY\";\n readonly RECEIPT_MISMATCH: \"RECEIPT_MISMATCH\";\n readonly RECEIPT_UNAVAILABLE: \"RECEIPT_UNAVAILABLE\";\n readonly REVOKE_NEEDS_TARGET: \"REVOKE_NEEDS_TARGET\";\n readonly RULE_LIMIT_EXCEEDED: \"RULE_LIMIT_EXCEEDED\";\n readonly RULE_NOT_FOUND: \"RULE_NOT_FOUND\";\n readonly RULE_READ_FAILED: \"RULE_READ_FAILED\";\n readonly TARGET_NOT_ON_RULE_CHAIN: \"TARGET_NOT_ON_RULE_CHAIN\";\n readonly WALLET_BALANCE_INSUFFICIENT: \"WALLET_BALANCE_INSUFFICIENT\";\n readonly WALLET_NOT_DEPLOYED: \"WALLET_NOT_DEPLOYED\";\n}", + "members": { + "AGENT_GAS_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\"" + }, + "AGENT_IS_OWNER": { + "optional": false, + "readonly": true, + "type": "\"AGENT_IS_OWNER\"" + }, + "ASSET_CHAIN_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"ASSET_CHAIN_MISMATCH\"" + }, + "CAPABILITY_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"CAPABILITY_UNAVAILABLE\"" + }, + "CREATE_PARTIAL": { + "optional": false, + "readonly": true, + "type": "\"CREATE_PARTIAL\"" + }, + "DUPLICATE_RULE": { + "optional": false, + "readonly": true, + "type": "\"DUPLICATE_RULE\"" + }, + "FROM_NOT_ALLOWED": { + "optional": false, + "readonly": true, + "type": "\"FROM_NOT_ALLOWED\"" + }, + "GATEWAY_ALLOWANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"GATEWAY_ALLOWANCE_INSUFFICIENT\"" + }, + "GENERATION_UNSUPPORTED": { + "optional": false, + "readonly": true, + "type": "\"GENERATION_UNSUPPORTED\"" + }, + "INCONSISTENT_READ": { + "optional": false, + "readonly": true, + "type": "\"INCONSISTENT_READ\"" + }, + "INDEX_RACE": { + "optional": false, + "readonly": true, + "type": "\"INDEX_RACE\"" + }, + "INVALID_RULE": { + "optional": false, + "readonly": true, + "type": "\"INVALID_RULE\"" + }, + "NO_RULES_FOR_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"NO_RULES_FOR_CHAIN\"" + }, + "NOT_AGENTIC_WALLET": { + "optional": false, + "readonly": true, + "type": "\"NOT_AGENTIC_WALLET\"" + }, + "NOT_ALLOWED_IN_AGENTIC_MODE": { + "optional": false, + "readonly": true, + "type": "\"NOT_ALLOWED_IN_AGENTIC_MODE\"" + }, + "NOT_OWNER_OR_AGENT": { + "optional": false, + "readonly": true, + "type": "\"NOT_OWNER_OR_AGENT\"" + }, + "NOT_WALLET_OWNER": { + "optional": false, + "readonly": true, + "type": "\"NOT_WALLET_OWNER\"" + }, + "READ_ONLY": { + "optional": false, + "readonly": true, + "type": "\"READ_ONLY\"" + }, + "RECEIPT_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_MISMATCH\"" + }, + "RECEIPT_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_UNAVAILABLE\"" + }, + "REVOKE_NEEDS_TARGET": { + "optional": false, + "readonly": true, + "type": "\"REVOKE_NEEDS_TARGET\"" + }, + "RULE_LIMIT_EXCEEDED": { + "optional": false, + "readonly": true, + "type": "\"RULE_LIMIT_EXCEEDED\"" + }, + "RULE_NOT_FOUND": { + "optional": false, + "readonly": true, + "type": "\"RULE_NOT_FOUND\"" + }, + "RULE_READ_FAILED": { + "optional": false, + "readonly": true, + "type": "\"RULE_READ_FAILED\"" + }, + "TARGET_NOT_ON_RULE_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"TARGET_NOT_ON_RULE_CHAIN\"" + }, + "WALLET_BALANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"WALLET_BALANCE_INSUFFICIENT\"" + }, + "WALLET_NOT_DEPLOYED": { + "optional": false, + "readonly": true, + "type": "\"WALLET_NOT_DEPLOYED\"" + } + } + }, + "AgenticError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"CREATE_PARTIAL\" | \"DUPLICATE_RULE\" | \"FROM_NOT_ALLOWED\" | \"GATEWAY_ALLOWANCE_INSUFFICIENT\" | \"GENERATION_UNSUPPORTED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"REVOKE_NEEDS_TARGET\" | \"RULE_LIMIT_EXCEEDED\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"" + }, + "details": { + "optional": true, + "readonly": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "AgenticRevertError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticRevertError", + "members": { + "agenticCode": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + } + } + }, + "AgenticAddress": { + "type": "`0x${string}`", + "members": {} + }, + "AgenticDoor": { + "type": "\"agent\" | \"owner\"", + "members": {} + }, + "AgenticErrorCode": { + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"CREATE_PARTIAL\" | \"DUPLICATE_RULE\" | \"FROM_NOT_ALLOWED\" | \"GATEWAY_ALLOWANCE_INSUFFICIENT\" | \"GENERATION_UNSUPPORTED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"REVOKE_NEEDS_TARGET\" | \"RULE_LIMIT_EXCEEDED\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"", + "members": {} + }, + "AgenticHex": { + "type": "`0x${string}`", + "members": {} + }, + "AgenticNamespace": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace", + "members": { + "create": { + "optional": false, + "readonly": false, + "type": "(label: string, options: import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions) => Promise" + }, + "derive": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n index?: number;\n}) => Promise<{\n address: `0x${string}`;\n deployed: boolean;\n index: number;\n}>" + }, + "list": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n wallets: import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary[];\n}>" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "(address: `0x${string}`) => import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet" + } + } + }, + "AgenticNetworkConstants": { + "type": "import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants", + "members": { + "ENVELOPE_VERSION": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "FACTORY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "MAX_ALLOWED_CALLS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "MAX_PINS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "RULES_POLICY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticProgressHook": { + "type": "(event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void", + "members": {} + }, + "AgenticTxMetadata": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticTxMetadata", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destinationAccount": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "destinationCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "door": { + "optional": false, + "readonly": false, + "type": "\"agent\" | \"owner\"" + }, + "nativeCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "rawData": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rawTo": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesId": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticWallet": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "checkpoints": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n sinceBlock?: bigint;\n}) => Promise<{\n checkpoints: import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint[];\n}>" + }, + "info": { + "optional": false, + "readonly": false, + "type": "() => Promise" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n owner: `0x${string}`;\n}>" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "{\n add(rules: import(\"sdk/src/lib/agentic/agentic.types\").Rule[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise<{\n rulesIds: `0x${string}`[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n get(rulesId: `0x${string}`): Promise;\n list(): Promise<{\n rules: import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord[];\n }>;\n revoke(rulesIds: `0x${string}`[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n revoke(params: {\n all: true;\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n update(params: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n rules: {\n rule: import(\"sdk/src/lib/agentic/agentic.types\").Rule;\n rulesId: `0x${string}`;\n }[];\n }): Promise<{\n rules: {\n replaced: `0x${string}`;\n rulesId: `0x${string}`;\n }[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n}" + }, + "setLabel": { + "optional": false, + "readonly": false, + "type": "(label: string, opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n}) => Promise" + } + } + }, + "AllowedCall": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall", + "members": { + "beneficiary": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValue": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "`${string}(${string})` | `0x${string}`" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AssetCap": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap", + "members": { + "maxPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/constants/tokens\").MoveableToken" + } + } + }, + "Checkpoint": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint", + "members": { + "blockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "kind": { + "optional": false, + "readonly": false, + "type": "\"OWNER_ACTION\" | \"RULES_GRANTED\" | \"RULES_REVOKED\"" + }, + "ref": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "seq": { + "optional": false, + "readonly": false, + "type": "number" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "CheckpointKind": { + "type": "\"OWNER_ACTION\" | \"RULES_GRANTED\" | \"RULES_REVOKED\"", + "members": {} + }, + "CreateOptions": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions", + "members": { + "progressHook": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook | undefined" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Rule[]" + } + } + }, + "CreateResult": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateResult", + "members": { + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "rulesIds": { + "optional": false, + "readonly": false, + "type": "`0x${string}`[]" + }, + "tx": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ForeignChainNamespace": { + "type": "`eip155:${string}` | `solana:${string}`", + "members": {} + }, + "NativeRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "amount": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AmountLimit | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "maxCalls": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValuePerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxValueTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "pins": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ArgPin[] | undefined" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Rule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule | import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "RulesRecord": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "enabled": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "ref": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "rule": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule | import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule" + }, + "rulesId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Selector": { + "type": "`${string}(${string})` | `0x${string}`", + "members": {} + }, + "UniversalRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall[]" + }, + "assets": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap[]" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "`eip155:${string}` | `solana:${string}`" + }, + "maxGasPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "WalletInfo": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").WalletInfo", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "label": { + "optional": false, + "readonly": false, + "type": "string" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "rulesCount": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "WalletSummary": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "label": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesCount": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "PushChain": { + "type": "import(\"sdk/src/lib/push-chain/push-chain\").PushChain", + "members": { + "accountStatus": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus" + }, + "accountStatusReady": { + "optional": false, + "readonly": false, + "type": "Promise" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace" + }, + "explorer": { + "optional": false, + "readonly": false, + "type": "{\n getTransactionUrl: (txHash: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n listAllUrls: () => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n listUrls: (options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n}" + }, + "funds": { + "optional": false, + "readonly": false, + "type": "{\n getConversionQuote: (amountIn: bigint, options: {\n from: import(\"sdk/src/lib/constants/tokens\").PayableToken | undefined;\n to: import(\"sdk/src/lib/constants/tokens\").MoveableToken | undefined;\n }) => Promise;\n}" + }, + "getAccountStatus": { + "optional": false, + "readonly": false, + "type": "(options?: {\n forceRefresh?: boolean;\n}) => Promise" + }, + "isReadMode": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "moveable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").MoveableTokenAccessor;\n}" + }, + "payable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").PayableTokenAccessor;\n}" + }, + "reinitialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "universal": { + "optional": false, + "readonly": false, + "type": "{\n readonly account: `0x${string}`;\n executeReads: (reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>;\n executeTransactions: (txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise;\n migrateCEA: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"migrateCEA\"];\n readonly origin: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n prepareRead: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n prepareTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"prepareTransaction\"];\n read: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n rescueFunds: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"rescueFunds\"];\n sendTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"execute\"];\n signMessage: (data: Uint8Array) => Promise;\n signTypedData: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n trackRead: {\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n };\n trackTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"trackTransaction\"];\n}" + }, + "upgradeAccount": { + "optional": false, + "readonly": false, + "type": "(options?: {\n progressHook?: (progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n}) => Promise" + } + } + } + }, + "pushChainStatic": { + "CONSTANTS": { + "optional": false, + "readonly": false, + "type": "{\n AGENTIC: Readonly>>;\n CHAIN: typeof import(\"sdk/src/lib/constants/enums\").CHAIN;\n LIBRARY: typeof import(\"sdk/src/lib/constants/enums\").LIBRARY;\n MOVEABLE: {\n TOKEN: import(\"sdk/src/lib/constants/tokens\").MoveableTokenConstantsMap;\n };\n PAYABLE: {\n TOKEN: import(\"sdk/src/lib/constants/tokens\").PayableTokenConstantsMap;\n };\n PUSH_NETWORK: typeof import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n READ: {\n readonly CALLBACK_BUDGET_BUFFER: 3;\n readonly CHAIN: {\n readonly WEB2: \"web2\";\n } & Readonly<{\n readonly ARBITRUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA;\n readonly BASE_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA;\n readonly BNB_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET;\n readonly ETHEREUM_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET;\n readonly ETHEREUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA;\n readonly PUSH_LOCALNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET;\n readonly PUSH_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET;\n readonly PUSH_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly PUSH_TESTNET_DONUT: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly SOLANA_DEVNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET;\n readonly SOLANA_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET;\n readonly SOLANA_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n readonly WEB2: \"web2\";\n }>;\n readonly DEFAULT_EXPIRY_BLOCKS: 300n;\n readonly ERROR_CODE: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n readonly MAX_CALLBACK_GAS_LIMIT: 1000000n;\n readonly MIN_CONFIRMATIONS_FLOOR: 1;\n readonly NAMESPACE: {\n readonly EVM: \"eip155\";\n readonly SVM: \"solana\";\n readonly WEB2: \"web2\";\n };\n readonly OUTCOME: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME;\n readonly REGISTRY_CALLBACK_GAS: 500000n;\n readonly RESULT_STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n readonly STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS;\n readonly UNIVERSAL_CALLBACK_ADDRESSES: Record;\n readonly UNIVERSAL_CORE_ADDRESSES: Record;\n readonly UNIVERSAL_READ_REGISTRY_ADDRESS: {\n readonly TESTNET_DONUT: \"0x00000000000000000000000000000000000000b2\";\n };\n readonly WEB2: \"web2\";\n readonly WEB2_DEFAULT_TIMEOUT_MS: 5000;\n readonly WEB2_MAX_EXTRACT_ENTRIES: 16;\n };\n}" + }, + "initialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "utils": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/utils\").Utils" + } + }, + "pushChainInstance": { + "accountStatus": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus" + }, + "accountStatusReady": { + "optional": false, + "readonly": false, + "type": "Promise" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace" + }, + "explorer": { + "optional": false, + "readonly": false, + "type": "{\n getTransactionUrl: (txHash: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n listAllUrls: () => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n listUrls: (options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n}" + }, + "funds": { + "optional": false, + "readonly": false, + "type": "{\n getConversionQuote: (amountIn: bigint, options: {\n from: import(\"sdk/src/lib/constants/tokens\").PayableToken | undefined;\n to: import(\"sdk/src/lib/constants/tokens\").MoveableToken | undefined;\n }) => Promise;\n}" + }, + "getAccountStatus": { + "optional": false, + "readonly": false, + "type": "(options?: {\n forceRefresh?: boolean;\n}) => Promise" + }, + "isReadMode": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "moveable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").MoveableTokenAccessor;\n}" + }, + "payable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").PayableTokenAccessor;\n}" + }, + "reinitialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "universal": { + "optional": false, + "readonly": false, + "type": "{\n readonly account: `0x${string}`;\n executeReads: (reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>;\n executeTransactions: (txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise;\n migrateCEA: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"migrateCEA\"];\n readonly origin: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n prepareRead: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n prepareTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"prepareTransaction\"];\n read: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n rescueFunds: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"rescueFunds\"];\n sendTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"execute\"];\n signMessage: (data: Uint8Array) => Promise;\n signTypedData: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n trackRead: {\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n };\n trackTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"trackTransaction\"];\n}" + }, + "upgradeAccount": { + "optional": false, + "readonly": false, + "type": "(options?: {\n progressHook?: (progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n}) => Promise" + } + }, + "transactionMethods": { + "account": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "executeReads": { + "optional": false, + "readonly": false, + "type": "(reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>" + }, + "executeTransactions": { + "optional": false, + "readonly": false, + "type": "(txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise" + }, + "migrateCEA": { + "optional": false, + "readonly": false, + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => Promise" + }, + "origin": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "prepareRead": { + "optional": false, + "readonly": false, + "type": "(subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>" + }, + "prepareTransaction": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions) => Promise" + }, + "read": { + "optional": false, + "readonly": false, + "type": "(subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>" + }, + "rescueFunds": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").RescueFundsParams) => Promise" + }, + "sendTransaction": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").ExecuteParams | import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions) => Promise" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": false, + "readonly": false, + "type": "({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise" + }, + "trackRead": { + "optional": false, + "readonly": false, + "type": "{\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n}" + }, + "trackTransaction": { + "optional": false, + "readonly": false, + "type": "(txHash: string, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TrackTransactionOptions) => Promise" + } + }, + "utilityMethods": { + "account": { + "optional": false, + "readonly": false, + "type": "{\n convertExecutorToOriginAccount: (ueaAddress: `0x${string}`, options?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n }) => Promise;\n convertOriginToExecutor: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n onlyCompute?: boolean;\n }) => Promise;\n deriveExecutorAccount: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n skipNetworkCheck?: boolean;\n }) => Promise;\n fromChainAgnostic: (caip: string) => import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n resolveControllerAccount: (address: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n skipNetworkCheck?: boolean;\n }) => Promise;\n toChainAgnostic: (address: string, options: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n toUniversal: (address: string, options: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n}" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "{\n actionId: (target: `0x${string}`, selector: \"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector) => `0x${string}`;\n configId: (wallet: `0x${string}`, rulesId: `0x${string}`, actionId: `0x${string}`) => `0x${string}`;\n decodeRules: (bytes: `0x${string}`, ctx?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n pushChainNamespace?: string;\n }) => import(\"sdk/src/lib/agentic/agentic.types\").Rule;\n}" + }, + "chains": { + "optional": false, + "readonly": false, + "type": "{\n getChainName: (chainNamespace: string) => string | undefined;\n getChainNamespace: (chainName: string) => string | undefined;\n getSupportedChains: (network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK) => {\n chains: import(\"sdk/src/lib/constants/enums\").CHAIN[];\n };\n getSupportedChainsByName: (network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK) => {\n chains: string[];\n };\n}" + }, + "conversion": { + "optional": false, + "readonly": false, + "type": "{\n slippageToMinAmount(amount: string, options: {\n slippageBps: number;\n }): string;\n}" + }, + "helpers": { + "optional": false, + "readonly": false, + "type": "{\n encodeTxData({ abi, idl, functionName, args, }: {\n abi?: any;\n args?: any[];\n functionName: string;\n idl?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n }): `0x${string}`;\n formatUnits(value: bigint | string, decimalsOrOptions: {\n decimals: number;\n precision?: number;\n } | number): string;\n getChainName: (chainName: string) => string | undefined;\n parseUnits(value: string, exponent: {\n decimals: number;\n } | number): bigint;\n}" + }, + "signer": { + "optional": false, + "readonly": false, + "type": "{\n construct: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options: {\n signAndSendTransaction: (unsignedTx: Uint8Array) => Promise;\n signAuthorization?: (params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise;\n signMessage: (data: Uint8Array) => Promise;\n signTypedData?: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n }) => import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton;\n toUniversal: (signer: import(\"sdk/src/lib/universal/universal.types\").EthersV5SignerType | import(\"sdk/src/lib/universal/universal.types\").EthersV6SignerType | import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton | import(\"sdk/src/lib/universal/universal.types\").ViemSignerType) => Promise;\n toUniversalFromKeypair: (clientOrAccount: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@solana/web3.js/lib/index\").Keypair | import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").WalletClient | import(\"sdk/src/lib/universal/universal.types\").EthersV6SignerType, { chain, library }: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n library: import(\"sdk/src/lib/constants/enums\").LIBRARY;\n }) => Promise;\n}" + }, + "svm": { + "optional": false, + "readonly": false, + "type": "{\n getRegisteredIdls: () => Array<{\n address: `0x${string}`;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n }>;\n registerIdl: (idl: unknown) => void;\n}" + }, + "tokens": { + "optional": false, + "readonly": false, + "type": "{\n getMoveableTokens(chainOrClient?: import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/push-chain/push-chain\").PushChain): {\n tokens: Array<{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n decimals: number;\n mechanism: \"approve\" | \"native\" | \"permit2\";\n prc20Address?: `0x${string}`;\n sourceChain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n symbol: string;\n }>;\n };\n getPayableTokens(chainOrClient?: import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/push-chain/push-chain\").PushChain): {\n tokens: Array<{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n decimals: number;\n mechanism: \"approve\" | \"native\" | \"permit2\";\n symbol: string;\n }>;\n };\n getPC20Address(address: string, options: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n rpcUrls?: Partial>;\n strict?: boolean;\n }): Promise;\n getPRC20Address(token: {\n address: string;\n chain: string;\n } | import(\"sdk/src/lib/constants/tokens\").MoveableToken, options?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n }): {\n address: `0x${string}`;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n decimals: number;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n symbol: string;\n };\n}" + } + }, + "initialize": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise", + "agwConstants": { + "ENVELOPE_VERSION": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "FACTORY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "MAX_ALLOWED_CALLS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "MAX_PINS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "RULES_POLICY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + }, + "constants": { + "AGENTIC": { + "optional": false, + "readonly": false, + "type": "{\n readonly LOCALNET?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n readonly MAINNET?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n readonly TESTNET?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n readonly TESTNET_DONUT?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n}" + }, + "CHAIN": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "LIBRARY": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").LIBRARY" + }, + "MOVEABLE": { + "optional": false, + "readonly": false, + "type": "{\n TOKEN: import(\"sdk/src/lib/constants/tokens\").MoveableTokenConstantsMap;\n}" + }, + "PAYABLE": { + "optional": false, + "readonly": false, + "type": "{\n TOKEN: import(\"sdk/src/lib/constants/tokens\").PayableTokenConstantsMap;\n}" + }, + "PUSH_NETWORK": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "READ": { + "optional": false, + "readonly": false, + "type": "{\n readonly CALLBACK_BUDGET_BUFFER: 3;\n readonly CHAIN: {\n readonly WEB2: \"web2\";\n } & Readonly<{\n readonly ARBITRUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA;\n readonly BASE_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA;\n readonly BNB_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET;\n readonly ETHEREUM_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET;\n readonly ETHEREUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA;\n readonly PUSH_LOCALNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET;\n readonly PUSH_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET;\n readonly PUSH_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly PUSH_TESTNET_DONUT: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly SOLANA_DEVNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET;\n readonly SOLANA_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET;\n readonly SOLANA_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n readonly WEB2: \"web2\";\n }>;\n readonly DEFAULT_EXPIRY_BLOCKS: 300n;\n readonly ERROR_CODE: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n readonly MAX_CALLBACK_GAS_LIMIT: 1000000n;\n readonly MIN_CONFIRMATIONS_FLOOR: 1;\n readonly NAMESPACE: {\n readonly EVM: \"eip155\";\n readonly SVM: \"solana\";\n readonly WEB2: \"web2\";\n };\n readonly OUTCOME: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME;\n readonly REGISTRY_CALLBACK_GAS: 500000n;\n readonly RESULT_STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n readonly STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS;\n readonly UNIVERSAL_CALLBACK_ADDRESSES: Record;\n readonly UNIVERSAL_CORE_ADDRESSES: Record;\n readonly UNIVERSAL_READ_REGISTRY_ADDRESS: {\n readonly TESTNET_DONUT: \"0x00000000000000000000000000000000000000b2\";\n };\n readonly WEB2: \"web2\";\n readonly WEB2_DEFAULT_TIMEOUT_MS: 5000;\n readonly WEB2_MAX_EXTRACT_ENTRIES: 16;\n}" + } + } + }, + "after": { + "exports": [ + "AGENTIC_ERROR_CODE", + "AccountRole", + "AccountStatus", + "AccountType", + "AgenticAddress", + "AgenticDoor", + "AgenticError", + "AgenticErrorCode", + "AgenticHex", + "AgenticNamespace", + "AgenticPresets", + "AgenticProgressHook", + "AgenticRevertError", + "AgenticTxMetadata", + "AgenticWallet", + "AllowedCall", + "AssetCap", + "BatchReadResponse", + "BuildReadSpecParams", + "CHAIN", + "CONTRACT_REQUEST_STATUS", + "CascadeCompletionResult", + "CascadeHopInfo", + "CascadeProgressEvent", + "CascadeTrackOptions", + "CascadedTxResponse", + "ChainSource", + "ChainTarget", + "Checkpoint", + "CheckpointKind", + "ConversionQuote", + "CreateOptions", + "CreateResult", + "DEFAULT_MAX_PC_FOR_GAS_BUFFER_BPS", + "DecodedErrorPayload", + "DecodedReadResult", + "DecodedSolanaRule", + "DerivedExecutorAccount", + "EncodedReadQuery", + "EvmReadQuery", + "ForeignChainNamespace", + "FulfilOutcome", + "FundsToken", + "InsufficientPC20BalanceError", + "InvalidPC20AddressError", + "InvalidPC20MetadataError", + "InvalidReadQueryError", + "InvalidReadSpecError", + "MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT", + "MaxPCForGasCapFromNativeValueInput", + "MaxPCForGasCapInput", + "MaxPCForGasCapQuote", + "MultiChainTxResponse", + "OutboundTxDetails", + "PC20AddressResult", + "PC20AmbiguousAddressError", + "PC20Error", + "PC20ExpectedButPRC20Error", + "PC20ExportRevertedError", + "PC20FactoryMismatchError", + "PC20RegistryEntry", + "PC20RegistryMismatchError", + "PC20TokenChainMismatchError", + "PC20TokenReference", + "PC20UnknownChainNamespaceError", + "PC20UnsafeEmptyPayloadError", + "PC20WrapperNotRegisteredError", + "PC20WrapperPredictionUnavailableError", + "ParsedReadRequest", + "Pin", + "PreparedRead", + "PreparedUniversalTx", + "Preset", + "PresetAsset", + "PresetCategory", + "PresetOptions", + "PresetRuleTemplate", + "PushChain", + "PushChainBatchExecutionError", + "PushChainExecutionError", + "PushChainInitializeOptions", + "READ_ERROR_CODE", + "READ_OUTCOME", + "READ_STATUS", + "ReadCallback", + "ReadCallbackOptions", + "ReadChain", + "ReadDecodeError", + "ReadDestination", + "ReadExecuteOptions", + "ReadFees", + "ReadHeightUnavailableError", + "ReadLifecycleOptions", + "ReadNotFoundError", + "ReadOptions", + "ReadPreflight", + "ReadPrepareOptions", + "ReadQuery", + "ReadQueryOptions", + "ReadRef", + "ReadRegistryUnavailableError", + "ReadResponseTuple", + "ReadResultShape", + "ReadSpec", + "ReadSpecTuple", + "ReadSpecViolation", + "ReadStateError", + "ReadTimeoutError", + "ReadTrackOptions", + "ReadValue", + "ReadWeb2Options", + "ReadyPresetOptions", + "ReceiptLike", + "RescueFundsParams", + "ResolvedAccount", + "ResolvedControllerAccounts", + "ResolvedDestination", + "Rule", + "RuleInput", + "RulesRecord", + "Selector", + "SignAuthorizationParams", + "SignedAuthorization", + "SimulateReadResult", + "Spent", + "SvmExecutePayloadFields", + "SvmGatewayAccountMeta", + "SvmReadQuery", + "TERMINAL_READ_STATUSES", + "TransactionRoute", + "TransactionRouteType", + "UEAStatus", + "UNIVERSAL_CALLBACK_EVM", + "UNIVERSAL_READ_REGISTRY_EVM", + "UNIVERSAL_READ_STATUS", + "UniversalAccount", + "UniversalExecuteParams", + "UniversalOutboundTxRequest", + "UniversalReadResponse", + "UniversalSigner", + "UniversalSignerSkeleton", + "UniversalTo", + "UnsupportedPC20DestinationError", + "UnsupportedReadDestinationError", + "ValidateReadCall", + "WaitForOutboundOptions", + "WalletInfo", + "WalletMarker", + "WalletSummary", + "Web2Extract", + "Web2ReadQuery", + "Web2ValueType", + "buildErc20WithdrawalMulticall", + "buildMigrationPayload", + "buildReadSpecFromPreflight", + "chainSupportsCEA", + "chainSupportsOutbound", + "decodeReadResult", + "detectRoute", + "encodeReadQuery", + "encodeSvmExecutePayload", + "getAllCEAAddresses", + "getCEAAddress", + "getCEAFactoryAddress", + "getPushAccountForCEA", + "inferResultShape", + "isCEA", + "isChainTarget", + "isPC20Reference", + "isSvmChain", + "isValidSolanaHexAddress", + "parseFulfilOutcome", + "parseReadRequestsFromReceipt", + "parseUEAVersion", + "quoteMaxPCForGasCap", + "quoteMaxPCForGasCapFromNativeValue", + "resolveDestination", + "sizeCallbackBudget", + "toCallData", + "toReadQuery", + "toRequestIdHex", + "validateReadSpec" + ], + "agw": { + "AgenticNamespace": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace", + "members": { + "create": { + "optional": false, + "readonly": false, + "type": "(label: string, options: import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions) => Promise" + }, + "derive": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n index?: number;\n}) => Promise<{\n address: `0x${string}`;\n deployed: boolean;\n index: number;\n}>" + }, + "list": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n wallets: import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary[];\n}>" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "(address: `0x${string}`) => import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet" + } + } + }, + "AgenticWallet": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "checkpoints": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n sinceBlock?: bigint;\n}) => Promise<{\n checkpoints: import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint[];\n}>" + }, + "info": { + "optional": false, + "readonly": false, + "type": "() => Promise" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n owner: `0x${string}`;\n}>" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "{\n add(rules: import(\"sdk/src/lib/agentic/agentic.types\").RuleInput[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise<{\n rulesIds: `0x${string}`[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n delete(rulesIds: `0x${string}`[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n delete(params: {\n all: true;\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n get(rulesId: `0x${string}`): Promise;\n list(): Promise<{\n rules: import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord[];\n }>;\n update(params: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n rules: {\n rule: import(\"sdk/src/lib/agentic/agentic.types\").RuleInput;\n rulesId: `0x${string}`;\n }[];\n }): Promise<{\n rules: {\n replaced: `0x${string}`;\n rulesId: `0x${string}`;\n }[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n}" + }, + "setLabel": { + "optional": false, + "readonly": false, + "type": "(label: string, opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n}) => Promise" + } + } + }, + "AgenticError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"AMBIGUOUS_RULE\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"DELETE_NEEDS_TARGET\" | \"DUPLICATE_RULE\" | \"FROM_NOT_ALLOWED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"" + }, + "details": { + "optional": true, + "readonly": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "AgenticRevertError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticRevertError", + "members": { + "agenticCode": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "AGENTIC_ERROR_CODE": { + "type": "{\n readonly AGENT_GAS_INSUFFICIENT: \"AGENT_GAS_INSUFFICIENT\";\n readonly AGENT_IS_OWNER: \"AGENT_IS_OWNER\";\n readonly AMBIGUOUS_RULE: \"AMBIGUOUS_RULE\";\n readonly ASSET_CHAIN_MISMATCH: \"ASSET_CHAIN_MISMATCH\";\n readonly CAPABILITY_UNAVAILABLE: \"CAPABILITY_UNAVAILABLE\";\n readonly DELETE_NEEDS_TARGET: \"DELETE_NEEDS_TARGET\";\n readonly DUPLICATE_RULE: \"DUPLICATE_RULE\";\n readonly FROM_NOT_ALLOWED: \"FROM_NOT_ALLOWED\";\n readonly INCONSISTENT_READ: \"INCONSISTENT_READ\";\n readonly INDEX_RACE: \"INDEX_RACE\";\n readonly INVALID_RULE: \"INVALID_RULE\";\n readonly NO_RULES_FOR_CHAIN: \"NO_RULES_FOR_CHAIN\";\n readonly NOT_AGENTIC_WALLET: \"NOT_AGENTIC_WALLET\";\n readonly NOT_ALLOWED_IN_AGENTIC_MODE: \"NOT_ALLOWED_IN_AGENTIC_MODE\";\n readonly NOT_OWNER_OR_AGENT: \"NOT_OWNER_OR_AGENT\";\n readonly NOT_WALLET_OWNER: \"NOT_WALLET_OWNER\";\n readonly READ_ONLY: \"READ_ONLY\";\n readonly RECEIPT_MISMATCH: \"RECEIPT_MISMATCH\";\n readonly RECEIPT_UNAVAILABLE: \"RECEIPT_UNAVAILABLE\";\n readonly RULE_NOT_FOUND: \"RULE_NOT_FOUND\";\n readonly RULE_READ_FAILED: \"RULE_READ_FAILED\";\n readonly TARGET_NOT_ON_RULE_CHAIN: \"TARGET_NOT_ON_RULE_CHAIN\";\n readonly WALLET_BALANCE_INSUFFICIENT: \"WALLET_BALANCE_INSUFFICIENT\";\n readonly WALLET_NOT_DEPLOYED: \"WALLET_NOT_DEPLOYED\";\n}", + "members": { + "AGENT_GAS_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\"" + }, + "AGENT_IS_OWNER": { + "optional": false, + "readonly": true, + "type": "\"AGENT_IS_OWNER\"" + }, + "AMBIGUOUS_RULE": { + "optional": false, + "readonly": true, + "type": "\"AMBIGUOUS_RULE\"" + }, + "ASSET_CHAIN_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"ASSET_CHAIN_MISMATCH\"" + }, + "CAPABILITY_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"CAPABILITY_UNAVAILABLE\"" + }, + "DELETE_NEEDS_TARGET": { + "optional": false, + "readonly": true, + "type": "\"DELETE_NEEDS_TARGET\"" + }, + "DUPLICATE_RULE": { + "optional": false, + "readonly": true, + "type": "\"DUPLICATE_RULE\"" + }, + "FROM_NOT_ALLOWED": { + "optional": false, + "readonly": true, + "type": "\"FROM_NOT_ALLOWED\"" + }, + "INCONSISTENT_READ": { + "optional": false, + "readonly": true, + "type": "\"INCONSISTENT_READ\"" + }, + "INDEX_RACE": { + "optional": false, + "readonly": true, + "type": "\"INDEX_RACE\"" + }, + "INVALID_RULE": { + "optional": false, + "readonly": true, + "type": "\"INVALID_RULE\"" + }, + "NO_RULES_FOR_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"NO_RULES_FOR_CHAIN\"" + }, + "NOT_AGENTIC_WALLET": { + "optional": false, + "readonly": true, + "type": "\"NOT_AGENTIC_WALLET\"" + }, + "NOT_ALLOWED_IN_AGENTIC_MODE": { + "optional": false, + "readonly": true, + "type": "\"NOT_ALLOWED_IN_AGENTIC_MODE\"" + }, + "NOT_OWNER_OR_AGENT": { + "optional": false, + "readonly": true, + "type": "\"NOT_OWNER_OR_AGENT\"" + }, + "NOT_WALLET_OWNER": { + "optional": false, + "readonly": true, + "type": "\"NOT_WALLET_OWNER\"" + }, + "READ_ONLY": { + "optional": false, + "readonly": true, + "type": "\"READ_ONLY\"" + }, + "RECEIPT_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_MISMATCH\"" + }, + "RECEIPT_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_UNAVAILABLE\"" + }, + "RULE_NOT_FOUND": { + "optional": false, + "readonly": true, + "type": "\"RULE_NOT_FOUND\"" + }, + "RULE_READ_FAILED": { + "optional": false, + "readonly": true, + "type": "\"RULE_READ_FAILED\"" + }, + "TARGET_NOT_ON_RULE_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"TARGET_NOT_ON_RULE_CHAIN\"" + }, + "WALLET_BALANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"WALLET_BALANCE_INSUFFICIENT\"" + }, + "WALLET_NOT_DEPLOYED": { + "optional": false, + "readonly": true, + "type": "\"WALLET_NOT_DEPLOYED\"" + } + } + }, + "Rule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Rule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleCall[]" + }, + "assets": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset[] | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "maxGasPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "RuleInput": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").DecodedSolanaRule | import(\"sdk/src/lib/agentic/agentic.types\").Rule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "assets": { + "optional": true, + "readonly": false, + "type": "{\n maxPerCall: bigint;\n maxTotal: bigint;\n token: string;\n}[] | import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset[] | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "maxGasPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Pin": { + "type": "{\n account: number;\n arg?: never;\n expected: \"agentic:wallet\" | string;\n max?: never;\n token?: import(\"sdk/src/lib/constants/tokens\").MoveableToken | string;\n} | {\n account?: never;\n arg: number;\n expected: \"agentic:wallet\" | `0x${string}` | `0x${string}` | bigint;\n max?: never;\n} | {\n account?: never;\n arg: number;\n expected?: never;\n max: bigint;\n}", + "members": { + "account": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "arg": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "expected": { + "optional": true, + "readonly": false, + "type": "bigint | string | undefined" + }, + "max": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "Spent": { + "type": "{\n actions: {\n amountSpent: bigint;\n callsUsed: number;\n selector: \"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector;\n target: `0x${string}`;\n valueSpent: bigint;\n }[];\n kind: \"native\";\n} | {\n amountSpent: bigint;\n callsUsed: number;\n kind: \"native\";\n valueSpent: bigint;\n} | {\n assets: {\n spent: bigint;\n token: string;\n }[];\n kind: \"universal\";\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"native\" | \"universal\"" + } + } + }, + "AssetCap": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset", + "members": { + "maxPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/tokens\").MoveableToken | string" + } + } + }, + "AllowedCall": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleCall", + "members": { + "app": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "label": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "maxValue": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "pins": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Pin[] | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector" + }, + "target": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "RulesRecord": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "enabled": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "rule": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").DecodedSolanaRule | import(\"sdk/src/lib/agentic/agentic.types\").Rule" + }, + "rulesId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "spent": { + "optional": false, + "readonly": false, + "type": "{\n actions: {\n amountSpent: bigint;\n callsUsed: number;\n selector: \"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector;\n target: `0x${string}`;\n valueSpent: bigint;\n }[];\n kind: \"native\";\n} | {\n amountSpent: bigint;\n callsUsed: number;\n kind: \"native\";\n valueSpent: bigint;\n} | {\n assets: {\n spent: bigint;\n token: string;\n }[];\n kind: \"universal\";\n}" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "CreateOptions": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions", + "members": { + "progressHook": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook | undefined" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleInput[]" + } + } + }, + "CreateResult": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateResult", + "members": { + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "rulesIds": { + "optional": false, + "readonly": false, + "type": "`0x${string}`[]" + }, + "tx": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticTxMetadata": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticTxMetadata", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destinationAccount": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "destinationCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "destinationInstruction": { + "optional": true, + "readonly": false, + "type": "{\n accounts: readonly {\n isWritable: boolean;\n pubkey: `0x${string}`;\n }[];\n data: `0x${string}`;\n program: `0x${string}`;\n} | undefined" + }, + "destinationTransfer": { + "optional": true, + "readonly": false, + "type": "{\n amount: bigint;\n recipient: `0x${string}`;\n token: `0x${string}`;\n} | undefined" + }, + "door": { + "optional": false, + "readonly": false, + "type": "\"agent\" | \"owner\"" + }, + "nativeCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "rawData": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rawTo": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesId": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + } + }, + "publicSurface": { + "CHAIN": { + "type": "typeof import(\"sdk/src/lib/constants/enums\").CHAIN", + "members": { + "ARBITRUM_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA" + }, + "BASE_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA" + }, + "BNB_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET" + }, + "ETHEREUM_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET" + }, + "ETHEREUM_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA" + }, + "PUSH_LOCALNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET" + }, + "PUSH_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET" + }, + "PUSH_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET" + }, + "PUSH_TESTNET_DONUT": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET" + }, + "SOLANA_DEVNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET" + }, + "SOLANA_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET" + }, + "SOLANA_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET" + }, + "WEB2": { + "optional": false, + "readonly": false, + "type": "\"web2\"" + } + } + }, + "ConversionQuote": { + "type": "import(\"sdk/src/lib/constants/tokens\").ConversionQuote", + "members": { + "amountIn": { + "optional": false, + "readonly": false, + "type": "string" + }, + "amountOut": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rate": { + "optional": false, + "readonly": false, + "type": "number" + }, + "route": { + "optional": true, + "readonly": false, + "type": "string[] | undefined" + }, + "timestamp": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "UniversalSigner": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalSigner", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "signAndSendTransaction": { + "optional": false, + "readonly": false, + "type": "(unsignedTx: Uint8Array) => Promise" + }, + "signAuthorization": { + "optional": true, + "readonly": false, + "type": "((params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise) | undefined" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": true, + "readonly": false, + "type": "(({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise) | undefined" + } + } + }, + "UniversalAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "UniversalSignerSkeleton": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "signAndSendTransaction": { + "optional": false, + "readonly": false, + "type": "(unsignedTx: Uint8Array) => Promise" + }, + "signAuthorization": { + "optional": true, + "readonly": false, + "type": "((params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise) | undefined" + }, + "signerId": { + "optional": false, + "readonly": false, + "type": "string" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": true, + "readonly": false, + "type": "(({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise) | undefined" + } + } + }, + "SignAuthorizationParams": { + "type": "{\n chainId?: number;\n contractAddress: `0x${string}`;\n executor?: \"self\";\n nonce?: number;\n}", + "members": { + "chainId": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "contractAddress": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "executor": { + "optional": true, + "readonly": false, + "type": "\"self\" | undefined" + }, + "nonce": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "SignedAuthorization": { + "type": "{\n address: `0x${string}`;\n chainId: number;\n nonce: number;\n r: `0x${string}`;\n s: `0x${string}`;\n v?: bigint;\n yParity: number;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainId": { + "optional": false, + "readonly": false, + "type": "number" + }, + "nonce": { + "optional": false, + "readonly": false, + "type": "number" + }, + "r": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "s": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "v": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "yParity": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "DerivedExecutorAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").DerivedExecutorAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean | null" + } + } + }, + "ResolvedAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainName": { + "optional": false, + "readonly": false, + "type": "string" + }, + "exists": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "role": { + "optional": true, + "readonly": false, + "type": "\"controller\" | undefined" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"cea\" | \"uea\" | \"uoa\"" + } + } + }, + "ResolvedControllerAccounts": { + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedControllerAccounts", + "members": { + "accounts": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedAccount[]" + } + } + }, + "AccountType": { + "type": "\"cea\" | \"uea\" | \"uoa\"", + "members": {} + }, + "AccountRole": { + "type": "\"controller\"", + "members": {} + }, + "PC20TokenReference": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "FundsToken": { + "type": "import(\"sdk/src/lib/constants/tokens\").MoveableToken | import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20TokenReference", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "PC20RegistryEntry": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "chainName": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "PC20AddressResult": { + "type": "{\n address: `0x${string}`;\n decimals: number;\n name: string;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n registry: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20RegistryEntry[];\n symbol: string;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "decimals": { + "optional": false, + "readonly": false, + "type": "number" + }, + "name": { + "optional": false, + "readonly": false, + "type": "string" + }, + "network": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "registry": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20RegistryEntry[]" + }, + "symbol": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "isPC20Reference": { + "type": "(token: import(\"sdk/src/lib/orchestrator/orchestrator.types\").FundsToken | undefined) => token is import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20TokenReference", + "members": {} + }, + "PC20Error": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20Error", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidPC20AddressError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InvalidPC20AddressError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20TokenChainMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20TokenChainMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20WrapperNotRegisteredError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20WrapperNotRegisteredError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20RegistryMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20RegistryMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20FactoryMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20FactoryMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidPC20MetadataError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InvalidPC20MetadataError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20ExpectedButPRC20Error": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20ExpectedButPRC20Error", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20AmbiguousAddressError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20AmbiguousAddressError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "candidates": { + "optional": false, + "readonly": true, + "type": "{\n chain: string;\n pushAddress: string;\n}[]" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "UnsupportedPC20DestinationError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").UnsupportedPC20DestinationError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InsufficientPC20BalanceError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InsufficientPC20BalanceError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20UnknownChainNamespaceError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20UnknownChainNamespaceError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20WrapperPredictionUnavailableError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20WrapperPredictionUnavailableError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20ExportRevertedError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20ExportRevertedError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "lockedAmount": { + "optional": true, + "readonly": true, + "type": "bigint | undefined" + }, + "outboundTxId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "revertRecipient": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20UnsafeEmptyPayloadError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20UnsafeEmptyPayloadError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ChainTarget": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "ChainSource": { + "type": "{\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "UniversalTo": { + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget", + "members": {} + }, + "TransactionRouteType": { + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"", + "members": {} + }, + "UniversalExecuteParams": { + "type": "{\n from?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainSource;\n migration?: boolean;\n to: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTo;\n} & Omit", + "members": { + "_minimumDepositUsd": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "_requiredFundsOverride": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "_skipFeeLocking": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "_ueaStatus": { + "optional": true, + "readonly": false, + "type": "{\n balance: bigint;\n isDeployed: boolean;\n nonce: bigint;\n} | undefined" + }, + "data": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiCall[] | undefined" + }, + "deadline": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "feeLockTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "from": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainSource | undefined" + }, + "funds": { + "optional": true, + "readonly": false, + "type": "{\n amount: bigint;\n token?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").FundsToken;\n} | undefined" + }, + "gasLimit": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFeePerGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxPCForGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxPriorityFeePerGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "migration": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "nonce": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "options": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions | undefined" + }, + "payGasWith": { + "optional": true, + "readonly": false, + "type": "{\n minAmountOut?: bigint | string;\n slippageBps?: number;\n token?: import(\"sdk/src/lib/constants/tokens\").PayableToken;\n} | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "to": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget" + }, + "value": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "UniversalOutboundTxRequest": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalOutboundTxRequest", + "members": { + "amount": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gasPrice": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxPCForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "payload": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "recipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "revertRecipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "PreparedUniversalTx": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx", + "members": { + "_hop": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").HopDescriptor" + }, + "deadline": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "estimatedGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gatewayRequest": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalOutboundTxRequest | import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxRequest" + }, + "nonce": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "payload": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + } + } + }, + "CascadedTxResponse": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadedTxResponse", + "members": { + "finalTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hopCount": { + "optional": false, + "readonly": false, + "type": "number" + }, + "hops": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo[]" + }, + "initialTxHash": { + "optional": false, + "readonly": false, + "type": "string" + }, + "initialTxResponse": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions) => Promise" + }, + "waitForAll": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions) => Promise" + } + } + }, + "CascadeHopInfo": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo", + "members": { + "executionChain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "expectedSubTxId": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hopIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "outboundDetails": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").OutboundTxDetails | undefined" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + }, + "status": { + "optional": false, + "readonly": false, + "type": "\"confirmed\" | \"failed\" | \"pending\" | \"submitted\"" + }, + "txHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "CascadeTrackOptions": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions", + "members": { + "eventHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeProgressEvent) => void) | undefined" + }, + "timeout": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "CascadeProgressEvent": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeProgressEvent", + "members": { + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "elapsed": { + "optional": false, + "readonly": false, + "type": "number" + }, + "hopIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + }, + "status": { + "optional": false, + "readonly": false, + "type": "\"confirmed\" | \"failed\" | \"found\" | \"polling\" | \"timeout\" | \"waiting\"" + }, + "txHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "CascadeCompletionResult": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeCompletionResult", + "members": { + "failedAt": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "finalTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "finalTxResponse": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadedTxResponse | undefined" + }, + "hops": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo[]" + }, + "success": { + "optional": false, + "readonly": false, + "type": "boolean" + } + } + }, + "MultiChainTxResponse": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiChainTxResponse", + "members": { + "chains": { + "optional": false, + "readonly": false, + "type": "{\n blockNumber: bigint;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n hash: string;\n status: \"confirmed\" | \"failed\" | \"pending\";\n}[]" + }, + "transactions": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse[]" + } + } + }, + "OutboundTxDetails": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").OutboundTxDetails", + "members": { + "amount": { + "optional": false, + "readonly": false, + "type": "string" + }, + "assetAddr": { + "optional": false, + "readonly": false, + "type": "string" + }, + "destinationChain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "explorerUrl": { + "optional": false, + "readonly": false, + "type": "string" + }, + "externalTxHash": { + "optional": false, + "readonly": false, + "type": "string" + }, + "recipient": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "WaitForOutboundOptions": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").WaitForOutboundOptions", + "members": { + "_expectedDestinationChain": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "_outboundIndex": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "_resolvedSubTxId": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "initialWaitMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: {\n elapsed: number;\n status: \"failed\" | \"found\" | \"polling\" | \"timeout\" | \"waiting\";\n}) => void) | undefined" + }, + "timeout": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "SvmGatewayAccountMeta": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmGatewayAccountMeta", + "members": { + "isWritable": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "pubkey": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "SvmExecutePayloadFields": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmExecutePayloadFields", + "members": { + "accounts": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmGatewayAccountMeta[]" + }, + "instructionId": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "ixData": { + "optional": false, + "readonly": false, + "type": "Uint8Array" + }, + "targetProgram": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AccountStatus": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus", + "members": { + "mode": { + "optional": false, + "readonly": false, + "type": "\"read-only\" | \"signer\"" + }, + "uea": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UEAStatus" + } + } + }, + "UEAStatus": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UEAStatus", + "members": { + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "loaded": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "minRequiredVersion": { + "optional": false, + "readonly": false, + "type": "string" + }, + "requiresUpgrade": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "version": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "RescueFundsParams": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").RescueFundsParams", + "members": { + "prc20": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "universalTxId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "parseUEAVersion": { + "type": "(version: string) => number", + "members": {} + }, + "TransactionRoute": { + "type": "typeof import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute", + "members": { + "CEA_TO_CEA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.CEA_TO_CEA" + }, + "CEA_TO_PUSH": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.CEA_TO_PUSH" + }, + "UOA_TO_CEA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.UOA_TO_CEA" + }, + "UOA_TO_PUSH": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.UOA_TO_PUSH" + } + } + }, + "detectRoute": { + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams) => import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute", + "members": {} + }, + "isChainTarget": { + "type": "(to: unknown) => to is import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget", + "members": {} + }, + "DEFAULT_MAX_PC_FOR_GAS_BUFFER_BPS": { + "type": "1000", + "members": {} + }, + "MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT": { + "type": "10000", + "members": {} + }, + "quoteMaxPCForGasCap": { + "type": "(input: import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapInput) => import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": {} + }, + "quoteMaxPCForGasCapFromNativeValue": { + "type": "(input: import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapFromNativeValueInput) => import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": {} + }, + "MaxPCForGasCapInput": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapInput", + "members": { + "bufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "gasLegNativePc": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "MaxPCForGasCapFromNativeValueInput": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapFromNativeValueInput", + "members": { + "bufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "nativeValueForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "MaxPCForGasCapQuote": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": { + "bufferBps": { + "optional": false, + "readonly": false, + "type": "number" + }, + "gasLegNativePc": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxPCForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "nativeValueForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "getCEAAddress": { + "type": "(ueaAddress: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise", + "members": {} + }, + "getPushAccountForCEA": { + "type": "(ceaAddress: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise<`0x${string}`>", + "members": {} + }, + "isCEA": { + "type": "(address: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise", + "members": {} + }, + "chainSupportsCEA": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "chainSupportsOutbound": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "getCEAFactoryAddress": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => `0x${string}` | undefined", + "members": {} + }, + "getAllCEAAddresses": { + "type": "(ueaAddress: `0x${string}`, rpcUrls?: Partial>) => Promise", + "members": {} + }, + "encodeSvmExecutePayload": { + "type": "(fields: import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmExecutePayloadFields) => `0x${string}`", + "members": {} + }, + "isSvmChain": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "isValidSolanaHexAddress": { + "type": "(address: string) => boolean", + "members": {} + }, + "buildMigrationPayload": { + "type": "() => `0x${string}`", + "members": {} + }, + "buildErc20WithdrawalMulticall": { + "type": "(tokenAddress: `0x${string}`, recipientAddress: `0x${string}`, amount: bigint) => import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiCall[]", + "members": {} + }, + "ReadChain": { + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain", + "members": {} + }, + "ReadDestination": { + "type": "{\n chain: import(\"sdk/src/lib/read-state/read-state.types\").ReadChain;\n} | {\n chainId: string;\n chainNamespace: string;\n}", + "members": {} + }, + "ResolvedDestination": { + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}", + "members": { + "caip2": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainId": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "namespace": { + "optional": false, + "readonly": false, + "type": "\"eip155\" | \"solana\" | \"web2\"" + } + } + }, + "ReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").SvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery", + "members": { + "type": { + "optional": false, + "readonly": false, + "type": "\"accountBalance\" | \"contractCall\" | \"http\" | \"lamportBalance\" | \"rawAccountData\" | \"splTokenAccount\" | \"storageSlot\"" + } + } + }, + "EvmReadQuery": { + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n target: `0x${string}`;\n type: \"contractCall\";\n} | {\n callData: `0x${string}`;\n target: `0x${string}`;\n type: \"contractCall\";\n} | {\n slot: `0x${string}` | bigint;\n target: `0x${string}`;\n type: \"storageSlot\";\n} | {\n target: `0x${string}`;\n type: \"accountBalance\";\n}", + "members": { + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"accountBalance\" | \"contractCall\" | \"storageSlot\"" + } + } + }, + "SvmReadQuery": { + "type": "{\n account: string | Uint8Array;\n accountName?: string;\n idl?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n type: \"rawAccountData\";\n} | {\n account: string | Uint8Array;\n type: \"lamportBalance\";\n} | {\n account: string | Uint8Array;\n type: \"splTokenAccount\";\n}", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "string | Uint8Array" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"lamportBalance\" | \"rawAccountData\" | \"splTokenAccount\"" + } + } + }, + "Web2ReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery", + "members": { + "body": { + "optional": true, + "readonly": false, + "type": "string | Uint8Array | undefined" + }, + "extract": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[]" + }, + "headers": { + "optional": true, + "readonly": false, + "type": "Record | undefined" + }, + "method": { + "optional": true, + "readonly": false, + "type": "\"GET\" | \"POST\" | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"http\"" + }, + "url": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "Web2Extract": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract", + "members": { + "decimals": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "path": { + "optional": false, + "readonly": false, + "type": "string" + }, + "valueType": { + "optional": false, + "readonly": false, + "type": "\"bool\" | \"bytes\" | \"int256\" | \"string\" | \"uint256\"" + } + } + }, + "Web2ValueType": { + "type": "\"bool\" | \"bytes\" | \"int256\" | \"string\" | \"uint256\"", + "members": {} + }, + "EncodedReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery", + "members": { + "blockRef": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "encoded": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "namespace": { + "optional": false, + "readonly": false, + "type": "\"eip155\" | \"solana\" | \"web2\"" + }, + "ownerBytes": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "queryType": { + "optional": false, + "readonly": false, + "type": "number" + }, + "resultShape": { + "optional": false, + "readonly": false, + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}" + }, + "warnings": { + "optional": false, + "readonly": false, + "type": "string[]" + } + } + }, + "ReadResultShape": { + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"bytes32\" | \"evmCall\" | \"raw\" | \"svmAccount\" | \"uint256\" | \"web2\"" + } + } + }, + "DecodedReadResult": { + "type": "{\n accountName: string;\n kind: \"svmAccount\";\n value: unknown;\n} | {\n kind: \"bytes32\";\n value: `0x${string}`;\n} | {\n kind: \"evmCall\";\n value: unknown;\n} | {\n kind: \"raw\";\n value: `0x${string}`;\n} | {\n kind: \"uint256\";\n value: bigint;\n} | {\n kind: \"web2\";\n values: readonly unknown[];\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"bytes32\" | \"evmCall\" | \"raw\" | \"svmAccount\" | \"uint256\" | \"web2\"" + } + } + }, + "ReadPreflight": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight", + "members": { + "destination": { + "optional": false, + "readonly": false, + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}" + }, + "fetchedAt": { + "optional": false, + "readonly": false, + "type": "number" + }, + "observedChainHeight": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pushBlockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pushGasPrice": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "universalCallback": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "universalCore": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ReadSpec": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "{\n chainId: string;\n chainNamespace: string;\n owner: `0x${string}`;\n}" + }, + "blockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "expiryPushChainHeight": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "minConfirmations": { + "optional": false, + "readonly": false, + "type": "number" + }, + "query": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "revertRecipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ReadSpecTuple": { + "type": "readonly [\n readonly [\n string,\n string,\n `0x${string}`\n ],\n `0x${string}`,\n number,\n bigint,\n bigint,\n bigint,\n `0x${string}`\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "readonly [\n string,\n string,\n `0x${string}`\n]" + }, + "1": { + "optional": false, + "readonly": true, + "type": "`0x${string}`" + }, + "2": { + "optional": false, + "readonly": true, + "type": "number" + }, + "3": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "4": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "5": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "6": { + "optional": false, + "readonly": true, + "type": "`0x${string}`" + }, + "length": { + "optional": false, + "readonly": true, + "type": "7" + } + } + }, + "BuildReadSpecParams": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").BuildReadSpecParams", + "members": { + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "budgetBuffer": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback | undefined" + }, + "callbackBudget": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "destination": { + "optional": false, + "readonly": false, + "type": "{\n chain: import(\"sdk/src/lib/read-state/read-state.types\").ReadChain;\n} | {\n chainId: string;\n chainNamespace: string;\n}" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "expiryPushChainHeight": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFeeBufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "owner": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "query": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").SvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "PreparedRead": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead", + "members": { + "__@preparedReadValue": { + "optional": true, + "readonly": true, + "type": "T | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback | undefined" + }, + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "encodedQuery": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery" + }, + "encodedSpec": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "fees": { + "optional": false, + "readonly": false, + "type": "{\n callbackBudget: bigint;\n protocolFee: bigint;\n total: bigint;\n}" + }, + "preflight": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "queryKey": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "resultShape": { + "optional": false, + "readonly": false, + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}" + }, + "spec": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec" + }, + "specTuple": { + "optional": false, + "readonly": false, + "type": "readonly [\n readonly [\n string,\n string,\n `0x${string}`\n ],\n `0x${string}`,\n number,\n bigint,\n bigint,\n bigint,\n `0x${string}`\n]" + }, + "value": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "warnings": { + "optional": false, + "readonly": false, + "type": "string[]" + } + } + }, + "ReadCallback": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "((spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpecTuple, callbackGasLimit: bigint) => readonly unknown[]) | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "gasLimit": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "target": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "SimulateReadResult": { + "type": "{\n args?: readonly unknown[];\n error: string;\n errorName?: string;\n ok: false;\n} | {\n ok: true;\n}", + "members": { + "ok": { + "optional": false, + "readonly": false, + "type": "boolean" + } + } + }, + "ParsedReadRequest": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ParsedReadRequest", + "members": { + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackTarget": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "logIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "originalFunder": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "requestId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "requestIdUint": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "spec": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec" + }, + "totalPaid": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "FulfilOutcome": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").FulfilOutcome", + "members": { + "burned": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "delivered": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "expired": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "failReason": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "gasReported": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refunded": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refundFailed": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "ReceiptLike": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike", + "members": { + "logs": { + "optional": false, + "readonly": false, + "type": "readonly {\n address: string;\n data: string;\n logIndex?: number | string;\n topics: readonly string[];\n}[]" + } + } + }, + "ReadRef": { + "type": "{\n requestId: `0x${string}` | bigint;\n} | {\n txHash: `0x${string}`;\n}", + "members": {} + }, + "ReadLifecycleOptions": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadLifecycleOptions", + "members": { + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "resultShape": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadFees": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadFees", + "members": { + "burned": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "paid": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "refunded": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refundFailed": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + } + } + }, + "UniversalReadResponse": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse", + "members": { + "callbackDelivered": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "callbackFailReason": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "decoded": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").DecodedReadResult | undefined" + }, + "decodeError": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destination": { + "optional": false, + "readonly": false, + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}" + }, + "errorMsg": { + "optional": false, + "readonly": false, + "type": "string" + }, + "explorerUrl": { + "optional": false, + "readonly": false, + "type": "string" + }, + "fees": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadFees" + }, + "isTerminal": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "outcome": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME" + }, + "pcTx": { + "optional": false, + "readonly": false, + "type": "readonly {\n blockHeight: number;\n errorMsg: string;\n status: string;\n txHash: `0x${string}`;\n}[]" + }, + "raw": { + "optional": false, + "readonly": false, + "type": "{\n errorCode: import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n resultData: `0x${string}`;\n status: import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n} | null" + }, + "refresh": { + "optional": false, + "readonly": false, + "type": "() => Promise>" + }, + "request": { + "optional": false, + "readonly": false, + "type": "{\n callbackGasLimit: bigint;\n callbackTarget: `0x${string}`;\n createdAtHeight: bigint;\n logIndex: number;\n originalFunder: `0x${string}`;\n refundTo: `0x${string}`;\n spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec;\n}" + }, + "requestId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "requestIdUint": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "status": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "value": { + "optional": true, + "readonly": false, + "type": "T | undefined" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/read-state/read-state.types\").ReadLifecycleOptions) => Promise>" + } + } + }, + "ReadResponseTuple": { + "type": "{\n -readonly [K in keyof R]: import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse ? T : unknown>;\n}", + "members": {} + }, + "BatchReadResponse": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").BatchReadResponse", + "members": { + "atomic": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "count": { + "optional": false, + "readonly": false, + "type": "number" + }, + "reads": { + "optional": false, + "readonly": false, + "type": "{\n -readonly [K in keyof R]: import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse ? T : unknown>;\n}" + }, + "transactionHashes": { + "optional": true, + "readonly": false, + "type": "readonly `0x${string}`[] | undefined" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: Omit) => Promise>" + } + } + }, + "ReadOptions": { + "type": "((import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">)) & {\n callback?: (Pick & Required>) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n };\n}", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "advanced": { + "optional": true, + "readonly": false, + "type": "{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n} | undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "({\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} & {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n}) | ({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick & Pick & Required>) | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadPrepareOptions": { + "type": "((((({\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\">) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n}) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">)) & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n}) | ((({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n}) | ({\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\">)) & {\n blockNumber?: never;\n minConfirmations?: never;\n})) & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n}) & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "advanced": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadQueryOptions": { + "type": "({\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\">) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n}) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n}) | ({\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\">)", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadCallbackOptions": { + "type": "{\n callback?: ({\n gasLimit?: bigint;\n target: `0x${string}`;\n } & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n };\n}", + "members": { + "callback": { + "optional": true, + "readonly": false, + "type": "({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} | undefined" + } + } + }, + "ReadValue": { + "type": "O extends {\n abi: infer A extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: infer F extends string;\n} ? number extends A[\"length\"] ? unknown : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, O extends {\n args: infer Args extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n} ? Args : readonly [\n] extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> ? import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> & readonly [\n] : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>> extends infer Selected ? Selected extends {\n outputs: readonly unknown[];\n type: \"function\";\n} & import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiFunction ? {\n [key in keyof {\n [key in keyof import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"]]: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterToPrimitiveType, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"][key], import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterKind>;\n }]: {\n [key in keyof import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"]]: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterToPrimitiveType, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"][key], import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterKind>;\n }[key];\n} extends infer types ? types extends readonly [\n] ? void : types extends readonly [\n infer type\n] ? type : types : never : never : never : O extends {\n web2: {\n extract: infer E extends readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n };\n} ? {\n readonly [K in keyof E]: {\n bool: boolean;\n bytes: `0x${string}`;\n int256: bigint;\n string: string;\n uint256: bigint;\n }[E[K][\"valueType\"]];\n} : O extends {\n storageSlot: unknown;\n} ? `0x${string}` : O extends {\n idl: infer I extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} ? string extends Extract, string> ? unknown : (O extends {\n functionName: infer N extends string;\n} ? N : undefined) extends string ? import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/index\").IdlAccounts[{\n [K in Extract, string>]: Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : K> extends Lowercase<(O extends {\n functionName: infer N extends string;\n } ? N : undefined) & string extends `${infer H}_${infer T}` ? `${H}${Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : (O extends {\n functionName: infer N extends string;\n } ? N : undefined) & string> ? K : never;\n}[Extract, string>]] : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/index\").IdlAccounts[Extract, string>] : bigint", + "members": {} + }, + "ValidateReadCall": { + "type": "O extends {\n abi: infer A extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: infer F extends string;\n} ? (readonly [\n] extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> ? {\n args?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n} : {\n args: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n}) & {\n functionName: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionName;\n} : O extends {\n functionName: infer N extends string;\n idl: infer I extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} ? string extends Extract, string> ? unknown : [\n {\n [K in Extract, string>]: Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : K> extends Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : N> ? K : never;\n }[Extract, string>]\n] extends [\n never\n] ? {\n functionName: Extract, string>;\n} : unknown : unknown", + "members": {} + }, + "ReadWeb2Options": { + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options", + "members": { + "body": { + "optional": true, + "readonly": false, + "type": "string | Uint8Array | undefined" + }, + "extract": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[]" + }, + "headers": { + "optional": true, + "readonly": false, + "type": "Record | undefined" + }, + "method": { + "optional": true, + "readonly": false, + "type": "\"GET\" | \"POST\" | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadTrackOptions": { + "type": "{\n advanced?: Omit, \"enforceGasCheck\">;\n resultShape?: import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape;\n}", + "members": { + "advanced": { + "optional": true, + "readonly": false, + "type": "Omit<{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n}, \"enforceGasCheck\"> | undefined" + }, + "resultShape": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape | undefined" + } + } + }, + "ReadExecuteOptions": { + "type": "{\n advanced?: {\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n } | undefined;\n progressHook?: ((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined;\n waitForCompletion?: boolean | undefined;\n}", + "members": { + "advanced": { + "optional": true, + "readonly": false, + "type": "{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n} | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + } + } + }, + "UNIVERSAL_READ_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS", + "members": { + "ABORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.ABORTED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.EXPIRED" + }, + "FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.FAILED" + }, + "FULFILLED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.FULFILLED" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.PENDING" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.UNSPECIFIED" + }, + "VOTING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.VOTING" + } + } + }, + "READ_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS", + "members": { + "ERROR": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.ERROR" + }, + "SUCCESS": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.SUCCESS" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.UNSPECIFIED" + } + } + }, + "READ_ERROR_CODE": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE", + "members": { + "INVALID_QUERY": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.INVALID_QUERY" + }, + "INVALID_RESULT": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.INVALID_RESULT" + }, + "NOT_FOUND": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.NOT_FOUND" + }, + "REJECTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.REJECTED" + }, + "REVERTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.REVERTED" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.UNSPECIFIED" + }, + "UNSUPPORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.UNSUPPORTED" + } + } + }, + "READ_OUTCOME": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME", + "members": { + "ABORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.ABORTED" + }, + "CALLBACK_FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.CALLBACK_FAILED" + }, + "DECODE_FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.DECODE_FAILED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.EXPIRED" + }, + "FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.FAILED" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.PENDING" + }, + "SOURCE_ERROR": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.SOURCE_ERROR" + }, + "SUCCESS": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.SUCCESS" + }, + "UNKNOWN": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.UNKNOWN" + } + } + }, + "CONTRACT_REQUEST_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS", + "members": { + "EXECUTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.EXECUTED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.EXPIRED" + }, + "NONE": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.NONE" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.PENDING" + }, + "SETTLED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.SETTLED" + } + } + }, + "TERMINAL_READ_STATUSES": { + "type": "ReadonlySet", + "members": {} + }, + "ReadStateError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadStateError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidReadQueryError": { + "type": "import(\"sdk/src/lib/read-state/errors\").InvalidReadQueryError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidReadSpecError": { + "type": "import(\"sdk/src/lib/read-state/errors\").InvalidReadSpecError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "violations": { + "optional": false, + "readonly": true, + "type": "readonly import(\"sdk/src/lib/read-state/errors\").ReadSpecViolation[]" + } + } + }, + "ReadHeightUnavailableError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadHeightUnavailableError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "UnsupportedReadDestinationError": { + "type": "import(\"sdk/src/lib/read-state/errors\").UnsupportedReadDestinationError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadDecodeError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadDecodeError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadTimeoutError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadTimeoutError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "lastStatus": { + "optional": false, + "readonly": true, + "type": "number" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadNotFoundError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadNotFoundError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadRegistryUnavailableError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadRegistryUnavailableError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadSpecViolation": { + "type": "\"CALLBACK_GAS_LIMIT_EXCEEDED\" | \"DOMAIN_BLOCKED\" | \"EMPTY_QUERY\" | \"EXCESSIVE_FEE\" | \"INSUFFICIENT_CALLBACK_BUDGET\" | \"INSUFFICIENT_FEE\" | \"INVALID_ACCOUNT_ID\" | \"INVALID_BLOCK_NUMBER\" | \"INVALID_EXPIRY_HEIGHT\" | \"INVALID_MIN_CONFIRMATIONS\" | \"SVM_OWNER_NOT_32_BYTES\" | \"ZERO_CALLBACK_BUDGET\" | \"ZERO_CALLBACK_GAS_LIMIT\" | \"ZERO_REVERT_RECIPIENT\"", + "members": {} + }, + "resolveDestination": { + "type": "(dest: import(\"sdk/src/lib/read-state/read-state.types\").ReadDestination) => import(\"sdk/src/lib/read-state/read-state.types\").ResolvedDestination", + "members": {} + }, + "encodeReadQuery": { + "type": "(destination: import(\"sdk/src/lib/read-state/read-state.types\").ReadDestination, query: import(\"sdk/src/lib/read-state/read-state.types\").ReadQuery, options?: {\n blockNumber?: bigint;\n minSlot?: bigint;\n}) => import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery", + "members": {} + }, + "decodeReadResult": { + "type": "(resultData: `0x${string}`, shape: import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape) => import(\"sdk/src/lib/read-state/read-state.types\").DecodedReadResult", + "members": {} + }, + "parseReadRequestsFromReceipt": { + "type": "(receipt: import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike, universalCallback: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").ParsedReadRequest[]", + "members": {} + }, + "parseFulfilOutcome": { + "type": "(receipt: import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike, universalCallback: `0x${string}`, requestId: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").FulfilOutcome", + "members": {} + }, + "buildReadSpecFromPreflight": { + "type": "(preflight: import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight, params: import(\"sdk/src/lib/read-state/read-state.types\").BuildReadSpecParams, defaults?: {\n refundTo?: `0x${string}`;\n}) => import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead", + "members": {} + }, + "validateReadSpec": { + "type": "(input: import(\"sdk/src/lib/read-state/validate\").ValidateReadSpecInput) => {\n ok: false;\n violations: import(\"sdk/src/lib/read-state/errors\").ReadSpecViolation[];\n} | {\n ok: true;\n}", + "members": {} + }, + "toCallData": { + "type": "(prepared: import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead, target: {\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: (spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpecTuple, callbackGasLimit: bigint) => readonly unknown[];\n functionName: string;\n}) => {\n data: `0x${string}`;\n value: bigint;\n}", + "members": {} + }, + "sizeCallbackBudget": { + "type": "(callbackGasLimit: bigint, pushGasPrice: bigint, buffer?: number) => bigint", + "members": {} + }, + "inferResultShape": { + "type": "(namespace: string, query: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape", + "members": {} + }, + "toRequestIdHex": { + "type": "(id: `0x${string}` | bigint) => `0x${string}`", + "members": {} + }, + "toReadQuery": { + "type": "(subject: string, o: ReadOptionsInput, resolvedTokenProgram?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@solana/web3.js/lib/index\").PublicKey) => import(\"sdk/src/lib/read-state/read-state.types\").ReadQuery", + "members": {} + }, + "UNIVERSAL_CALLBACK_EVM": { + "type": "readonly [\n {\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"requestExternalReadSelf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"estimateFee\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"statusOf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"enum RequestStatus\";\n readonly name: \"\";\n readonly type: \"uint8\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"isFulfilled\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getPendingRead\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly internalType: \"struct PendingRead\";\n readonly name: \"\";\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"totalEscrowed\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"blockedDomains\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly indexed: false;\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"readSpec\";\n readonly type: \"tuple\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"totalPaid\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"protocolFee\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ReadRequested\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"ReadFulfilled\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"reason\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"CallbackFailed\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"gasReported\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"burned\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"CallbackGasReported\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundSent\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundFailed\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RequestExpired\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"vaultPC\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ProtocolFeeDistributed\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidAccountId\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"EmptyQuery\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidMinConfirmations\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"DomainBlocked\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidBlockNumber\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidExpiryHeight\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroRevertRecipient\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroCallbackGasLimit\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint64\";\n readonly name: \"provided\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"max\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"CallbackGasLimitExceeded\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"required\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"InsufficientFee\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ExcessiveFee\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"actual\";\n readonly type: \"uint8\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"expected\";\n readonly type: \"uint8\";\n }\n ];\n readonly name: \"InvalidRequestStatus\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ContractIsPaused\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"CallerIsNotUCallbackModule\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n }\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"requestExternalReadSelf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n}" + }, + "1": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"estimateFee\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "2": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"statusOf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"enum RequestStatus\";\n readonly name: \"\";\n readonly type: \"uint8\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "3": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"isFulfilled\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "4": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getPendingRead\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly internalType: \"struct PendingRead\";\n readonly name: \"\";\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "5": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"totalEscrowed\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "6": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"blockedDomains\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "7": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly indexed: false;\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"readSpec\";\n readonly type: \"tuple\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"totalPaid\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"protocolFee\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ReadRequested\";\n readonly type: \"event\";\n}" + }, + "8": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"ReadFulfilled\";\n readonly type: \"event\";\n}" + }, + "9": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"reason\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"CallbackFailed\";\n readonly type: \"event\";\n}" + }, + "10": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"gasReported\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"burned\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"CallbackGasReported\";\n readonly type: \"event\";\n}" + }, + "11": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundSent\";\n readonly type: \"event\";\n}" + }, + "12": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundFailed\";\n readonly type: \"event\";\n}" + }, + "13": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RequestExpired\";\n readonly type: \"event\";\n}" + }, + "14": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"vaultPC\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ProtocolFeeDistributed\";\n readonly type: \"event\";\n}" + }, + "15": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidAccountId\";\n readonly type: \"error\";\n}" + }, + "16": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"EmptyQuery\";\n readonly type: \"error\";\n}" + }, + "17": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidMinConfirmations\";\n readonly type: \"error\";\n}" + }, + "18": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"DomainBlocked\";\n readonly type: \"error\";\n}" + }, + "19": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidBlockNumber\";\n readonly type: \"error\";\n}" + }, + "20": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidExpiryHeight\";\n readonly type: \"error\";\n}" + }, + "21": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroRevertRecipient\";\n readonly type: \"error\";\n}" + }, + "22": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroCallbackGasLimit\";\n readonly type: \"error\";\n}" + }, + "23": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint64\";\n readonly name: \"provided\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"max\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"CallbackGasLimitExceeded\";\n readonly type: \"error\";\n}" + }, + "24": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"required\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"InsufficientFee\";\n readonly type: \"error\";\n}" + }, + "25": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ExcessiveFee\";\n readonly type: \"error\";\n}" + }, + "26": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"actual\";\n readonly type: \"uint8\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"expected\";\n readonly type: \"uint8\";\n }\n ];\n readonly name: \"InvalidRequestStatus\";\n readonly type: \"error\";\n}" + }, + "27": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ContractIsPaused\";\n readonly type: \"error\";\n}" + }, + "28": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"CallerIsNotUCallbackModule\";\n readonly type: \"error\";\n}" + }, + "29": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n}" + }, + "length": { + "optional": false, + "readonly": true, + "type": "30" + } + } + }, + "UNIVERSAL_READ_REGISTRY_EVM": { + "type": "readonly [\n {\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n },\n {\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"read\";\n readonly outputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"universalCallback_\";\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"constructor\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"initialize\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getLocalContext\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"hasResult\";\n readonly outputs: readonly [\n {\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"onUniversalData\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"queryKeyOf\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes32\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"readerOf\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"requestOrderOf\";\n readonly outputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"universalCallback\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"resultByRequestId\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"latestResult\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"version\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"Initialized\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadRequested\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadStored\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidInitialization\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"NotInitializing\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroAddressInit\";\n readonly type: \"error\";\n }\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n },\n {\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"read\";\n readonly outputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n}" + }, + "1": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"universalCallback_\";\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"constructor\";\n}" + }, + "2": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"initialize\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n}" + }, + "3": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getLocalContext\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "4": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"hasResult\";\n readonly outputs: readonly [\n {\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "5": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"onUniversalData\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n}" + }, + "6": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"queryKeyOf\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes32\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "7": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"readerOf\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "8": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"requestOrderOf\";\n readonly outputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "9": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"universalCallback\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "10": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"resultByRequestId\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "11": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"latestResult\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "12": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"version\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"Initialized\";\n readonly type: \"event\";\n}" + }, + "13": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadRequested\";\n readonly type: \"event\";\n}" + }, + "14": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadStored\";\n readonly type: \"event\";\n}" + }, + "15": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidInitialization\";\n readonly type: \"error\";\n}" + }, + "16": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"NotInitializing\";\n readonly type: \"error\";\n}" + }, + "17": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n}" + }, + "18": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroAddressInit\";\n readonly type: \"error\";\n}" + }, + "length": { + "optional": false, + "readonly": true, + "type": "19" + } + } + }, + "PushChainExecutionError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").PushChainExecutionError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PushChainBatchExecutionError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").PushChainBatchExecutionError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": false, + "readonly": true, + "type": "`0x${string}`[]" + } + } + }, + "DecodedErrorPayload": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload", + "members": { + "decoded": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "name": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "selector": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "PushChainInitializeOptions": { + "type": "import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions", + "members": { + "agenticWallet": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "blockExplorers": { + "optional": true, + "readonly": false, + "type": "Partial> | undefined" + }, + "network": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "printTraces": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "rpcUrls": { + "optional": true, + "readonly": false, + "type": "Partial> | undefined" + } + } + }, + "AGENTIC_ERROR_CODE": { + "type": "{\n readonly AGENT_GAS_INSUFFICIENT: \"AGENT_GAS_INSUFFICIENT\";\n readonly AGENT_IS_OWNER: \"AGENT_IS_OWNER\";\n readonly AMBIGUOUS_RULE: \"AMBIGUOUS_RULE\";\n readonly ASSET_CHAIN_MISMATCH: \"ASSET_CHAIN_MISMATCH\";\n readonly CAPABILITY_UNAVAILABLE: \"CAPABILITY_UNAVAILABLE\";\n readonly DELETE_NEEDS_TARGET: \"DELETE_NEEDS_TARGET\";\n readonly DUPLICATE_RULE: \"DUPLICATE_RULE\";\n readonly FROM_NOT_ALLOWED: \"FROM_NOT_ALLOWED\";\n readonly INCONSISTENT_READ: \"INCONSISTENT_READ\";\n readonly INDEX_RACE: \"INDEX_RACE\";\n readonly INVALID_RULE: \"INVALID_RULE\";\n readonly NO_RULES_FOR_CHAIN: \"NO_RULES_FOR_CHAIN\";\n readonly NOT_AGENTIC_WALLET: \"NOT_AGENTIC_WALLET\";\n readonly NOT_ALLOWED_IN_AGENTIC_MODE: \"NOT_ALLOWED_IN_AGENTIC_MODE\";\n readonly NOT_OWNER_OR_AGENT: \"NOT_OWNER_OR_AGENT\";\n readonly NOT_WALLET_OWNER: \"NOT_WALLET_OWNER\";\n readonly READ_ONLY: \"READ_ONLY\";\n readonly RECEIPT_MISMATCH: \"RECEIPT_MISMATCH\";\n readonly RECEIPT_UNAVAILABLE: \"RECEIPT_UNAVAILABLE\";\n readonly RULE_NOT_FOUND: \"RULE_NOT_FOUND\";\n readonly RULE_READ_FAILED: \"RULE_READ_FAILED\";\n readonly TARGET_NOT_ON_RULE_CHAIN: \"TARGET_NOT_ON_RULE_CHAIN\";\n readonly WALLET_BALANCE_INSUFFICIENT: \"WALLET_BALANCE_INSUFFICIENT\";\n readonly WALLET_NOT_DEPLOYED: \"WALLET_NOT_DEPLOYED\";\n}", + "members": { + "AGENT_GAS_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\"" + }, + "AGENT_IS_OWNER": { + "optional": false, + "readonly": true, + "type": "\"AGENT_IS_OWNER\"" + }, + "AMBIGUOUS_RULE": { + "optional": false, + "readonly": true, + "type": "\"AMBIGUOUS_RULE\"" + }, + "ASSET_CHAIN_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"ASSET_CHAIN_MISMATCH\"" + }, + "CAPABILITY_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"CAPABILITY_UNAVAILABLE\"" + }, + "DELETE_NEEDS_TARGET": { + "optional": false, + "readonly": true, + "type": "\"DELETE_NEEDS_TARGET\"" + }, + "DUPLICATE_RULE": { + "optional": false, + "readonly": true, + "type": "\"DUPLICATE_RULE\"" + }, + "FROM_NOT_ALLOWED": { + "optional": false, + "readonly": true, + "type": "\"FROM_NOT_ALLOWED\"" + }, + "INCONSISTENT_READ": { + "optional": false, + "readonly": true, + "type": "\"INCONSISTENT_READ\"" + }, + "INDEX_RACE": { + "optional": false, + "readonly": true, + "type": "\"INDEX_RACE\"" + }, + "INVALID_RULE": { + "optional": false, + "readonly": true, + "type": "\"INVALID_RULE\"" + }, + "NO_RULES_FOR_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"NO_RULES_FOR_CHAIN\"" + }, + "NOT_AGENTIC_WALLET": { + "optional": false, + "readonly": true, + "type": "\"NOT_AGENTIC_WALLET\"" + }, + "NOT_ALLOWED_IN_AGENTIC_MODE": { + "optional": false, + "readonly": true, + "type": "\"NOT_ALLOWED_IN_AGENTIC_MODE\"" + }, + "NOT_OWNER_OR_AGENT": { + "optional": false, + "readonly": true, + "type": "\"NOT_OWNER_OR_AGENT\"" + }, + "NOT_WALLET_OWNER": { + "optional": false, + "readonly": true, + "type": "\"NOT_WALLET_OWNER\"" + }, + "READ_ONLY": { + "optional": false, + "readonly": true, + "type": "\"READ_ONLY\"" + }, + "RECEIPT_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_MISMATCH\"" + }, + "RECEIPT_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_UNAVAILABLE\"" + }, + "RULE_NOT_FOUND": { + "optional": false, + "readonly": true, + "type": "\"RULE_NOT_FOUND\"" + }, + "RULE_READ_FAILED": { + "optional": false, + "readonly": true, + "type": "\"RULE_READ_FAILED\"" + }, + "TARGET_NOT_ON_RULE_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"TARGET_NOT_ON_RULE_CHAIN\"" + }, + "WALLET_BALANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"WALLET_BALANCE_INSUFFICIENT\"" + }, + "WALLET_NOT_DEPLOYED": { + "optional": false, + "readonly": true, + "type": "\"WALLET_NOT_DEPLOYED\"" + } + } + }, + "AgenticError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"AMBIGUOUS_RULE\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"DELETE_NEEDS_TARGET\" | \"DUPLICATE_RULE\" | \"FROM_NOT_ALLOWED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"" + }, + "details": { + "optional": true, + "readonly": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "AgenticRevertError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticRevertError", + "members": { + "agenticCode": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "AgenticAddress": { + "type": "`0x${string}`", + "members": {} + }, + "AgenticDoor": { + "type": "\"agent\" | \"owner\"", + "members": {} + }, + "AgenticErrorCode": { + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"AMBIGUOUS_RULE\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"DELETE_NEEDS_TARGET\" | \"DUPLICATE_RULE\" | \"FROM_NOT_ALLOWED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"", + "members": {} + }, + "AgenticHex": { + "type": "`0x${string}`", + "members": {} + }, + "AgenticNamespace": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace", + "members": { + "create": { + "optional": false, + "readonly": false, + "type": "(label: string, options: import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions) => Promise" + }, + "derive": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n index?: number;\n}) => Promise<{\n address: `0x${string}`;\n deployed: boolean;\n index: number;\n}>" + }, + "list": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n wallets: import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary[];\n}>" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "(address: `0x${string}`) => import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet" + } + } + }, + "AgenticProgressHook": { + "type": "(event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void", + "members": {} + }, + "AgenticTxMetadata": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticTxMetadata", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destinationAccount": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "destinationCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "destinationInstruction": { + "optional": true, + "readonly": false, + "type": "{\n accounts: readonly {\n isWritable: boolean;\n pubkey: `0x${string}`;\n }[];\n data: `0x${string}`;\n program: `0x${string}`;\n} | undefined" + }, + "destinationTransfer": { + "optional": true, + "readonly": false, + "type": "{\n amount: bigint;\n recipient: `0x${string}`;\n token: `0x${string}`;\n} | undefined" + }, + "door": { + "optional": false, + "readonly": false, + "type": "\"agent\" | \"owner\"" + }, + "nativeCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "rawData": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rawTo": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesId": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticWallet": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "checkpoints": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n sinceBlock?: bigint;\n}) => Promise<{\n checkpoints: import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint[];\n}>" + }, + "info": { + "optional": false, + "readonly": false, + "type": "() => Promise" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n owner: `0x${string}`;\n}>" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "{\n add(rules: import(\"sdk/src/lib/agentic/agentic.types\").RuleInput[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise<{\n rulesIds: `0x${string}`[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n delete(rulesIds: `0x${string}`[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n delete(params: {\n all: true;\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n get(rulesId: `0x${string}`): Promise;\n list(): Promise<{\n rules: import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord[];\n }>;\n update(params: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n rules: {\n rule: import(\"sdk/src/lib/agentic/agentic.types\").RuleInput;\n rulesId: `0x${string}`;\n }[];\n }): Promise<{\n rules: {\n replaced: `0x${string}`;\n rulesId: `0x${string}`;\n }[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n}" + }, + "setLabel": { + "optional": false, + "readonly": false, + "type": "(label: string, opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n}) => Promise" + } + } + }, + "AllowedCall": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleCall", + "members": { + "app": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "label": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "maxValue": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "pins": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Pin[] | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector" + }, + "target": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "AssetCap": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset", + "members": { + "maxPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/tokens\").MoveableToken | string" + } + } + }, + "Checkpoint": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint", + "members": { + "blockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "kind": { + "optional": false, + "readonly": false, + "type": "\"OWNER_ACTION\" | \"RULES_GRANTED\" | \"RULES_REVOKED\"" + }, + "ref": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "seq": { + "optional": false, + "readonly": false, + "type": "number" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "CheckpointKind": { + "type": "\"OWNER_ACTION\" | \"RULES_GRANTED\" | \"RULES_REVOKED\"", + "members": {} + }, + "CreateOptions": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions", + "members": { + "progressHook": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook | undefined" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleInput[]" + } + } + }, + "CreateResult": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateResult", + "members": { + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "rulesIds": { + "optional": false, + "readonly": false, + "type": "`0x${string}`[]" + }, + "tx": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ForeignChainNamespace": { + "type": "`eip155:${string}` | `solana:${string}`", + "members": {} + }, + "DecodedSolanaRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").DecodedSolanaRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "assets": { + "optional": false, + "readonly": false, + "type": "{\n maxPerCall: bigint;\n maxTotal: bigint;\n token: string;\n}[]" + }, + "ceaAccounts": { + "optional": false, + "readonly": false, + "type": "readonly `0x${string}`[]" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "`solana:${string}`" + }, + "dataPins": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/agentic/codec/svm-terms\").SvmDataPinWire[]" + }, + "expectedCEA": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "format": { + "optional": false, + "readonly": false, + "type": "\"decoded\"" + }, + "gatewayProgram": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "maxGasPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pins": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/agentic/codec/svm-terms\").SvmAccountPinWire[]" + }, + "programs": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/agentic/codec/svm-terms\").AllowedProgramWire[]" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Rule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Rule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleCall[]" + }, + "assets": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset[] | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "maxGasPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "RuleInput": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").DecodedSolanaRule | import(\"sdk/src/lib/agentic/agentic.types\").Rule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "assets": { + "optional": true, + "readonly": false, + "type": "{\n maxPerCall: bigint;\n maxTotal: bigint;\n token: string;\n}[] | import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset[] | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "maxGasPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Pin": { + "type": "{\n account: number;\n arg?: never;\n expected: \"agentic:wallet\" | string;\n max?: never;\n token?: import(\"sdk/src/lib/constants/tokens\").MoveableToken | string;\n} | {\n account?: never;\n arg: number;\n expected: \"agentic:wallet\" | `0x${string}` | `0x${string}` | bigint;\n max?: never;\n} | {\n account?: never;\n arg: number;\n expected?: never;\n max: bigint;\n}", + "members": { + "account": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "arg": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "expected": { + "optional": true, + "readonly": false, + "type": "bigint | string | undefined" + }, + "max": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "Spent": { + "type": "{\n actions: {\n amountSpent: bigint;\n callsUsed: number;\n selector: \"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector;\n target: `0x${string}`;\n valueSpent: bigint;\n }[];\n kind: \"native\";\n} | {\n amountSpent: bigint;\n callsUsed: number;\n kind: \"native\";\n valueSpent: bigint;\n} | {\n assets: {\n spent: bigint;\n token: string;\n }[];\n kind: \"universal\";\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"native\" | \"universal\"" + } + } + }, + "WalletMarker": { + "type": "\"agentic:wallet\"", + "members": {} + }, + "RulesRecord": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "enabled": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "rule": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").DecodedSolanaRule | import(\"sdk/src/lib/agentic/agentic.types\").Rule" + }, + "rulesId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "spent": { + "optional": false, + "readonly": false, + "type": "{\n actions: {\n amountSpent: bigint;\n callsUsed: number;\n selector: \"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector;\n target: `0x${string}`;\n valueSpent: bigint;\n }[];\n kind: \"native\";\n} | {\n amountSpent: bigint;\n callsUsed: number;\n kind: \"native\";\n valueSpent: bigint;\n} | {\n assets: {\n spent: bigint;\n token: string;\n }[];\n kind: \"universal\";\n}" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Selector": { + "type": "`${string}(${string})` | `0x${string}`", + "members": {} + }, + "WalletInfo": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").WalletInfo", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "label": { + "optional": false, + "readonly": false, + "type": "string" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "rulesCount": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "WalletSummary": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "label": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesCount": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "PushChain": { + "type": "import(\"sdk/src/lib/push-chain/push-chain\").PushChain", + "members": { + "accountStatus": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus" + }, + "accountStatusReady": { + "optional": false, + "readonly": false, + "type": "Promise" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace" + }, + "explorer": { + "optional": false, + "readonly": false, + "type": "{\n getTransactionUrl: (txHash: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n listAllUrls: () => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n listUrls: (options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n}" + }, + "funds": { + "optional": false, + "readonly": false, + "type": "{\n getConversionQuote: (amountIn: bigint, options: {\n from: import(\"sdk/src/lib/constants/tokens\").PayableToken | undefined;\n to: import(\"sdk/src/lib/constants/tokens\").MoveableToken | undefined;\n }) => Promise;\n}" + }, + "getAccountStatus": { + "optional": false, + "readonly": false, + "type": "(options?: {\n forceRefresh?: boolean;\n}) => Promise" + }, + "isReadMode": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "moveable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").MoveableTokenAccessor;\n}" + }, + "payable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").PayableTokenAccessor;\n}" + }, + "reinitialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "universal": { + "optional": false, + "readonly": false, + "type": "{\n readonly account: `0x${string}`;\n executeReads: (reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>;\n executeTransactions: (txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise;\n migrateCEA: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"migrateCEA\"];\n readonly origin: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n prepareRead: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n prepareTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"prepareTransaction\"];\n read: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n rescueFunds: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"rescueFunds\"];\n sendTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"execute\"];\n signMessage: (data: Uint8Array) => Promise;\n signTypedData: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n trackRead: {\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n };\n trackTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"trackTransaction\"];\n}" + }, + "upgradeAccount": { + "optional": false, + "readonly": false, + "type": "(options?: {\n progressHook?: (progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n}) => Promise" + } + } + }, + "Preset": { + "type": "import(\"sdk/src/lib/agentic/presets/types\").Preset", + "members": { + "chains": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace[]" + }, + "constant": { + "optional": false, + "readonly": false, + "type": "\"DEXES\" | \"LENDING\" | \"PREDICTION\"" + }, + "name": { + "optional": false, + "readonly": false, + "type": "string" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"CATEGORY\"" + } + } + }, + "PresetCategory": { + "type": "\"DEXES\" | \"LENDING\" | \"PREDICTION\"", + "members": {} + }, + "PresetAsset": { + "type": "import(\"sdk/src/lib/agentic/presets/types\").PresetAsset", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "maxPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/tokens\").MoveableToken | string" + } + } + }, + "PresetOptions": { + "type": "import(\"sdk/src/lib/agentic/presets/types\").PresetOptions", + "members": { + "agent": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "assets": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/presets/types\").PresetAsset[] | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "validUntil": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadyPresetOptions": { + "type": "import(\"sdk/src/lib/agentic/presets/types\").ReadyPresetOptions", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "assets": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/presets/types\").PresetAsset[] | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "PresetRuleTemplate": { + "type": "{\n agent?: `0x${string}`;\n validUntil?: number;\n} & Omit", + "members": { + "agent": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleCall[]" + }, + "assets": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset[] | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "maxGasPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "validUntil": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "AgenticPresets": { + "type": "import(\"sdk/src/lib/agentic/presets/types\").AgenticPresets", + "members": { + "get": { + "optional": false, + "readonly": false, + "type": "{\n (preset: import(\"sdk/src/lib/agentic/presets/types\").PresetCategory, options: import(\"sdk/src/lib/agentic/presets/types\").ReadyPresetOptions): {\n rules: import(\"sdk/src/lib/agentic/agentic.types\").Rule[];\n };\n (preset: import(\"sdk/src/lib/agentic/presets/types\").PresetCategory, options?: import(\"sdk/src/lib/agentic/presets/types\").PresetOptions): {\n rules: import(\"sdk/src/lib/agentic/presets/types\").PresetRuleTemplate[];\n };\n}" + }, + "list": { + "optional": false, + "readonly": false, + "type": "(options?: {\n type?: \"CATEGORY\";\n}) => {\n presets: import(\"sdk/src/lib/agentic/presets/types\").Preset[];\n}" + } + } + } + }, + "pushChainStatic": { + "CONSTANTS": { + "optional": false, + "readonly": false, + "type": "{\n AGENTIC: Readonly<{\n PRESETS: Readonly<{\n CATEGORY: Readonly<{\n DEXES: \"DEXES\";\n LENDING: \"LENDING\";\n PREDICTION: \"PREDICTION\";\n }>;\n }>;\n WALLET: \"agentic:wallet\";\n }>;\n CHAIN: typeof import(\"sdk/src/lib/constants/enums\").CHAIN;\n LIBRARY: typeof import(\"sdk/src/lib/constants/enums\").LIBRARY;\n MOVEABLE: {\n TOKEN: import(\"sdk/src/lib/constants/tokens\").MoveableTokenConstantsMap;\n };\n PAYABLE: {\n TOKEN: import(\"sdk/src/lib/constants/tokens\").PayableTokenConstantsMap;\n };\n PUSH_NETWORK: typeof import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n READ: {\n readonly CALLBACK_BUDGET_BUFFER: 3;\n readonly CHAIN: {\n readonly WEB2: \"web2\";\n } & Readonly<{\n readonly ARBITRUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA;\n readonly BASE_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA;\n readonly BNB_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET;\n readonly ETHEREUM_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET;\n readonly ETHEREUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA;\n readonly PUSH_LOCALNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET;\n readonly PUSH_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET;\n readonly PUSH_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly PUSH_TESTNET_DONUT: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly SOLANA_DEVNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET;\n readonly SOLANA_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET;\n readonly SOLANA_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n readonly WEB2: \"web2\";\n }>;\n readonly DEFAULT_EXPIRY_BLOCKS: 300n;\n readonly ERROR_CODE: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n readonly MAX_CALLBACK_GAS_LIMIT: 1000000n;\n readonly MIN_CONFIRMATIONS_FLOOR: 1;\n readonly NAMESPACE: {\n readonly EVM: \"eip155\";\n readonly SVM: \"solana\";\n readonly WEB2: \"web2\";\n };\n readonly OUTCOME: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME;\n readonly REGISTRY_CALLBACK_GAS: 500000n;\n readonly RESULT_STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n readonly STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS;\n readonly UNIVERSAL_CALLBACK_ADDRESSES: Record;\n readonly UNIVERSAL_CORE_ADDRESSES: Record;\n readonly UNIVERSAL_READ_REGISTRY_ADDRESS: {\n readonly TESTNET_DONUT: \"0x00000000000000000000000000000000000000b2\";\n };\n readonly WEB2: \"web2\";\n readonly WEB2_DEFAULT_TIMEOUT_MS: 5000;\n readonly WEB2_MAX_EXTRACT_ENTRIES: 16;\n };\n}" + }, + "initialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "utils": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/utils\").Utils" + } + }, + "pushChainInstance": { + "accountStatus": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus" + }, + "accountStatusReady": { + "optional": false, + "readonly": false, + "type": "Promise" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace" + }, + "explorer": { + "optional": false, + "readonly": false, + "type": "{\n getTransactionUrl: (txHash: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n listAllUrls: () => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n listUrls: (options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n}" + }, + "funds": { + "optional": false, + "readonly": false, + "type": "{\n getConversionQuote: (amountIn: bigint, options: {\n from: import(\"sdk/src/lib/constants/tokens\").PayableToken | undefined;\n to: import(\"sdk/src/lib/constants/tokens\").MoveableToken | undefined;\n }) => Promise;\n}" + }, + "getAccountStatus": { + "optional": false, + "readonly": false, + "type": "(options?: {\n forceRefresh?: boolean;\n}) => Promise" + }, + "isReadMode": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "moveable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").MoveableTokenAccessor;\n}" + }, + "payable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").PayableTokenAccessor;\n}" + }, + "reinitialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "universal": { + "optional": false, + "readonly": false, + "type": "{\n readonly account: `0x${string}`;\n executeReads: (reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>;\n executeTransactions: (txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise;\n migrateCEA: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"migrateCEA\"];\n readonly origin: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n prepareRead: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n prepareTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"prepareTransaction\"];\n read: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n rescueFunds: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"rescueFunds\"];\n sendTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"execute\"];\n signMessage: (data: Uint8Array) => Promise;\n signTypedData: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n trackRead: {\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n };\n trackTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"trackTransaction\"];\n}" + }, + "upgradeAccount": { + "optional": false, + "readonly": false, + "type": "(options?: {\n progressHook?: (progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n}) => Promise" + } + }, + "transactionMethods": { + "account": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "executeReads": { + "optional": false, + "readonly": false, + "type": "(reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>" + }, + "executeTransactions": { + "optional": false, + "readonly": false, + "type": "(txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise" + }, + "migrateCEA": { + "optional": false, + "readonly": false, + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => Promise" + }, + "origin": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "prepareRead": { + "optional": false, + "readonly": false, + "type": "(subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>" + }, + "prepareTransaction": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions) => Promise" + }, + "read": { + "optional": false, + "readonly": false, + "type": "(subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>" + }, + "rescueFunds": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").RescueFundsParams) => Promise" + }, + "sendTransaction": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").ExecuteParams | import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions) => Promise" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": false, + "readonly": false, + "type": "({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise" + }, + "trackRead": { + "optional": false, + "readonly": false, + "type": "{\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n}" + }, + "trackTransaction": { + "optional": false, + "readonly": false, + "type": "(txHash: string, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TrackTransactionOptions) => Promise" + } + }, + "utilityMethods": { + "account": { + "optional": false, + "readonly": false, + "type": "{\n convertExecutorToOriginAccount: (ueaAddress: `0x${string}`, options?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n }) => Promise;\n convertOriginToExecutor: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n onlyCompute?: boolean;\n }) => Promise;\n deriveExecutorAccount: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n skipNetworkCheck?: boolean;\n }) => Promise;\n fromChainAgnostic: (caip: string) => import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n resolveControllerAccount: (address: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n skipNetworkCheck?: boolean;\n }) => Promise;\n toChainAgnostic: (address: string, options: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n toUniversal: (address: string, options: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n}" + }, + "agentic": { + "optional": false, + "readonly": true, + "type": "{\n readonly presets: import(\"sdk/src/lib/agentic/presets/types\").AgenticPresets;\n}" + }, + "chains": { + "optional": false, + "readonly": false, + "type": "{\n getChainName: (chainNamespace: string) => string | undefined;\n getChainNamespace: (chainName: string) => string | undefined;\n getSupportedChains: (network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK) => {\n chains: import(\"sdk/src/lib/constants/enums\").CHAIN[];\n };\n getSupportedChainsByName: (network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK) => {\n chains: string[];\n };\n}" + }, + "conversion": { + "optional": false, + "readonly": false, + "type": "{\n slippageToMinAmount(amount: string, options: {\n slippageBps: number;\n }): string;\n}" + }, + "helpers": { + "optional": false, + "readonly": false, + "type": "{\n encodeTxData({ abi, idl, functionName, args, }: {\n abi?: any;\n args?: any[];\n functionName: string;\n idl?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n }): `0x${string}`;\n formatUnits(value: bigint | string, decimalsOrOptions: {\n decimals: number;\n precision?: number;\n } | number): string;\n getChainName: (chainName: string) => string | undefined;\n parseUnits(value: string, exponent: {\n decimals: number;\n } | number): bigint;\n}" + }, + "signer": { + "optional": false, + "readonly": false, + "type": "{\n construct: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options: {\n signAndSendTransaction: (unsignedTx: Uint8Array) => Promise;\n signAuthorization?: (params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise;\n signMessage: (data: Uint8Array) => Promise;\n signTypedData?: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n }) => import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton;\n toUniversal: (signer: import(\"sdk/src/lib/universal/universal.types\").EthersV5SignerType | import(\"sdk/src/lib/universal/universal.types\").EthersV6SignerType | import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton | import(\"sdk/src/lib/universal/universal.types\").ViemSignerType) => Promise;\n toUniversalFromKeypair: (clientOrAccount: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@solana/web3.js/lib/index\").Keypair | import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").WalletClient | import(\"sdk/src/lib/universal/universal.types\").EthersV6SignerType, { chain, library }: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n library: import(\"sdk/src/lib/constants/enums\").LIBRARY;\n }) => Promise;\n}" + }, + "svm": { + "optional": false, + "readonly": false, + "type": "{\n getRegisteredIdls: () => Array<{\n address: `0x${string}`;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n }>;\n registerIdl: (idl: unknown) => void;\n}" + }, + "tokens": { + "optional": false, + "readonly": false, + "type": "{\n getMoveableTokens(chainOrClient?: import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/push-chain/push-chain\").PushChain): {\n tokens: Array<{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n decimals: number;\n mechanism: \"approve\" | \"native\" | \"permit2\";\n prc20Address?: `0x${string}`;\n sourceChain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n symbol: string;\n }>;\n };\n getPayableTokens(chainOrClient?: import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/push-chain/push-chain\").PushChain): {\n tokens: Array<{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n decimals: number;\n mechanism: \"approve\" | \"native\" | \"permit2\";\n symbol: string;\n }>;\n };\n getPC20Address(address: string, options: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n rpcUrls?: Partial>;\n strict?: boolean;\n }): Promise;\n getPRC20Address: (token: {\n address: string;\n chain: string;\n } | import(\"sdk/src/lib/constants/tokens\").MoveableToken, options?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n }) => {\n address: `0x${string}`;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n decimals: number;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n symbol: string;\n };\n}" + } + }, + "initialize": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise", + "agwConstants": { + "PRESETS": { + "optional": false, + "readonly": true, + "type": "{\n readonly CATEGORY: Readonly<{\n DEXES: \"DEXES\";\n LENDING: \"LENDING\";\n PREDICTION: \"PREDICTION\";\n }>;\n}" + }, + "WALLET": { + "optional": false, + "readonly": true, + "type": "\"agentic:wallet\"" + } + }, + "constants": { + "AGENTIC": { + "optional": false, + "readonly": false, + "type": "{\n readonly PRESETS: Readonly<{\n CATEGORY: Readonly<{\n DEXES: \"DEXES\";\n LENDING: \"LENDING\";\n PREDICTION: \"PREDICTION\";\n }>;\n }>;\n readonly WALLET: \"agentic:wallet\";\n}" + }, + "CHAIN": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "LIBRARY": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").LIBRARY" + }, + "MOVEABLE": { + "optional": false, + "readonly": false, + "type": "{\n TOKEN: import(\"sdk/src/lib/constants/tokens\").MoveableTokenConstantsMap;\n}" + }, + "PAYABLE": { + "optional": false, + "readonly": false, + "type": "{\n TOKEN: import(\"sdk/src/lib/constants/tokens\").PayableTokenConstantsMap;\n}" + }, + "PUSH_NETWORK": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "READ": { + "optional": false, + "readonly": false, + "type": "{\n readonly CALLBACK_BUDGET_BUFFER: 3;\n readonly CHAIN: {\n readonly WEB2: \"web2\";\n } & Readonly<{\n readonly ARBITRUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA;\n readonly BASE_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA;\n readonly BNB_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET;\n readonly ETHEREUM_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET;\n readonly ETHEREUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA;\n readonly PUSH_LOCALNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET;\n readonly PUSH_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET;\n readonly PUSH_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly PUSH_TESTNET_DONUT: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly SOLANA_DEVNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET;\n readonly SOLANA_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET;\n readonly SOLANA_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n readonly WEB2: \"web2\";\n }>;\n readonly DEFAULT_EXPIRY_BLOCKS: 300n;\n readonly ERROR_CODE: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n readonly MAX_CALLBACK_GAS_LIMIT: 1000000n;\n readonly MIN_CONFIRMATIONS_FLOOR: 1;\n readonly NAMESPACE: {\n readonly EVM: \"eip155\";\n readonly SVM: \"solana\";\n readonly WEB2: \"web2\";\n };\n readonly OUTCOME: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME;\n readonly REGISTRY_CALLBACK_GAS: 500000n;\n readonly RESULT_STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n readonly STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS;\n readonly UNIVERSAL_CALLBACK_ADDRESSES: Record;\n readonly UNIVERSAL_CORE_ADDRESSES: Record;\n readonly UNIVERSAL_READ_REGISTRY_ADDRESS: {\n readonly TESTNET_DONUT: \"0x00000000000000000000000000000000000000b2\";\n };\n readonly WEB2: \"web2\";\n readonly WEB2_DEFAULT_TIMEOUT_MS: 5000;\n readonly WEB2_MAX_EXTRACT_ENTRIES: 16;\n}" + } + } + }, + "scope": "All root exports and declared public members, PushChain static/instance members, universal transaction methods, utility groups, readonly/optional markers and constants. Behavior/default/deployment changes need the written session review." +} diff --git a/plan/agw/research/v6-integration-2026-10-14/atomic-receipt-unit.log b/plan/agw/research/v6-integration-2026-10-14/atomic-receipt-unit.log new file mode 100644 index 00000000..0bd54807 --- /dev/null +++ b/plan/agw/research/v6-integration-2026-10-14/atomic-receipt-unit.log @@ -0,0 +1,27 @@ +PASS core packages/core/src/lib/agentic/__tests__/management.spec.ts + agentic.create + ✓ validates first, then sends deploy + grants in input order and returns receipt IDs (8 ms) + ✓ a bare wallet is one deployWallet call, no funding + ✓ invalid input never reaches the signer (1 ms) + ✓ refuses a changed URP version before grant signing (1 ms) + ✓ a different wallet in the receipt is RECEIPT_MISMATCH, not a safe-to-retry race + ✓ IDs that differ from the input order are a RECEIPT_MISMATCH, not a silent reorder (1 ms) + ✓ creation never uses the batch transport or a sequential fallback (5 ms) + ✓ a receipt that cannot be read after submission keeps the hash and reports unknown state + ✓ the deploy is index-bound: a raced slot reverts and is reported as INDEX_RACE with nothing committed (3 ms) + ✓ a later rename alone does not establish a competing creation (1 ms) + ✓ a slot that is already deployed is refused before signing + rules.add / rules.delete + ✓ add: owner-only, duplicate agent/chain refused before signing (1 ms) + ✓ add: several rules are one atomic owner execute batch (one signature on any signer) (2 ms) + ✓ revoke: bare and empty are refused; unknown IDs fail before signing; several IDs are one atomic owner execute (2 ms) + rules.update — one owner batch: assert → revoke → grant + ✓ builds exactly one execute(batch) with the observed spend asserted per pair (1 ms) + ✓ universal replacement asserts every asset in stored order before revoke/grant (1 ms) + ✓ replacement may name another live agent, but may not repeat an old ID (1 ms) + +Test Suites: 1 passed, 1 total +Tests: 17 passed, 17 total +Snapshots: 0 total +Time: 4.952 s +Ran all test suites within paths "packages/core/src/lib/agentic/__tests__/management.spec.ts". diff --git a/plan/agw/research/v6-integration-2026-10-14/build.log b/plan/agw/research/v6-integration-2026-10-14/build.log new file mode 100644 index 00000000..8e9daca6 --- /dev/null +++ b/plan/agw/research/v6-integration-2026-10-14/build.log @@ -0,0 +1,13 @@ + +> nx run core:build + +Compiling TypeScript files for project "core"... +Done compiling TypeScript files for project "core". +(node:20847) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. +(Use `node --trace-warnings ...` to show where the warning was created) + + + + NX Successfully ran target build for project core + + diff --git a/plan/agw/research/v6-integration-2026-10-14/bytecode-comparison.json b/plan/agw/research/v6-integration-2026-10-14/bytecode-comparison.json new file mode 100644 index 00000000..3e0963e0 --- /dev/null +++ b/plan/agw/research/v6-integration-2026-10-14/bytecode-comparison.json @@ -0,0 +1,190 @@ +{ + "block": "24245374", + "source": "git:ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "contracts": [ + { + "contract": "factoryLogic", + "address": "0x64893c611920604a9247530673071D46ac9174c9", + "executableMatchesOutsideImmutableAndLinkSlots": true, + "runtimeHash": "0xacd72a9e53ad4187ee52b21fc79165eee8b54be16de27be1af41c230a4ac4fe4", + "ignoredSlots": [ + { + "start": 3190, + "length": 32 + }, + { + "start": 3348, + "length": 32 + } + ], + "metadataExcluded": true + }, + { + "contract": "walletImplementation", + "address": "0x536D3EA48219ff743ac663C6c224920e9eB476A5", + "executableMatchesOutsideImmutableAndLinkSlots": true, + "runtimeHash": "0x1076635b6ee6479e3c86f3760015f1746131c5ede0367d84aa77fe0989e9aec2", + "ignoredSlots": [ + { + "start": 1483, + "length": 32 + }, + { + "start": 2134, + "length": 32 + }, + { + "start": 2941, + "length": 32 + }, + { + "start": 4732, + "length": 32 + }, + { + "start": 5260, + "length": 32 + }, + { + "start": 5899, + "length": 32 + }, + { + "start": 12242, + "length": 32 + }, + { + "start": 14129, + "length": 32 + }, + { + "start": 15880, + "length": 32 + }, + { + "start": 16225, + "length": 32 + }, + { + "start": 17414, + "length": 32 + }, + { + "start": 18229, + "length": 32 + }, + { + "start": 2874, + "length": 32 + }, + { + "start": 16857, + "length": 32 + }, + { + "start": 17363, + "length": 32 + }, + { + "start": 1196, + "length": 32 + }, + { + "start": 11950, + "length": 32 + }, + { + "start": 14191, + "length": 32 + }, + { + "start": 17312, + "length": 32 + }, + { + "start": 6166, + "length": 32 + }, + { + "start": 11876, + "length": 32 + }, + { + "start": 14934, + "length": 32 + }, + { + "start": 17171, + "length": 32 + }, + { + "start": 17987, + "length": 32 + }, + { + "start": 18379, + "length": 32 + }, + { + "start": 18478, + "length": 32 + } + ], + "metadataExcluded": true + }, + { + "contract": "urpImplementation", + "address": "0xa176b1424018D52711EDCb9d3D8757dc6e174463", + "executableMatchesOutsideImmutableAndLinkSlots": true, + "runtimeHash": "0x0e6569329ccb464febd53369c71fe377c7570fdf3eb42e71927702080d09176e", + "ignoredSlots": [ + { + "start": 3060, + "length": 20 + }, + { + "start": 3707, + "length": 20 + }, + { + "start": 6121, + "length": 20 + } + ], + "metadataExcluded": true + }, + { + "contract": "sessionValidator", + "address": "0xBf08d8335c1cE41a577DB70666816027814737dD", + "executableMatchesOutsideImmutableAndLinkSlots": true, + "runtimeHash": "0xd76a8e352533b443a78e7cea4798372cd143071ff54377371854b39be64752e2", + "ignoredSlots": [], + "metadataExcluded": true + }, + { + "contract": "sessionEngine", + "address": "0xf63DC0628fe1B25049FE3E3a3585Ef051CB98c1d", + "executableMatchesOutsideImmutableAndLinkSlots": true, + "runtimeHash": "0x5fa747bb1b2fb6635dbc22608f86a18a743d6ed9b3f394abf812ee3d4199bdde", + "ignoredSlots": [], + "metadataExcluded": true + }, + { + "contract": "svmRulebook", + "address": "0x15c3259490f0625C75b5a00731e4231b2B529c1E", + "executableMatchesOutsideImmutableAndLinkSlots": true, + "runtimeHash": "0x917123d637590afda6183f7942449e671e05d9a6f5ab0cb0628c2553111cfc3e", + "ignoredSlots": [ + { + "start": 7, + "length": 32 + }, + { + "start": 1, + "length": 20 + } + ], + "metadataExcluded": true + } + ] +} diff --git a/plan/agw/research/v6-integration-2026-10-14/commands.md b/plan/agw/research/v6-integration-2026-10-14/commands.md new file mode 100644 index 00000000..43ccd822 --- /dev/null +++ b/plan/agw/research/v6-integration-2026-10-14/commands.md @@ -0,0 +1,13 @@ +# V6 validation commands and limits + +- Isolated preparation: `OUT=/tmp/agw-oct14-v6 AGW_PIN=ffd567d3e49b2d27c6f50ad36093274dbac3090f bash packages/core/scripts/agw-local/prepare.sh`. Original contract checkout was fetched/read, never checked out or modified. +- ABI snapshots: isolated Forge output; policy errors include the linked SvmRulebook ABI errors. JSON hashes are in packages/core/scripts/agw-local/abis/manifest.json; gen-abi.mjs reproduces the TS files. +- Full unit suite: `node node_modules/jest/bin/jest.js --config packages/core/jest.config.ts --runInBand`. +- Local suite: `AGW_LOCAL_DIR=/tmp/agw-oct14-v6 node node_modules/jest/bin/jest.js --config packages/core/jest.agw-local.config.ts --runInBand`. +- Build: `NX_DAEMON=false node node_modules/nx/bin/nx.js run core:build --skip-nx-cache`. +- Typechecks: existing lib/spec/agw-local tsconfigs with --noEmit. Consumer checks: check-agw-docs.js, check-agw-package.js and check-agw-api.js. +- Live preflight: ci/preflight.ts --group agw --dry-run, using the existing testnet keys without printing them. +- Full live run: ci/run.ts --group agw, serial. Started with 68 selected scenarios; the later-added v6 destination-pin case was filtered out (69 loaded). Result: 67 passed, one stale allowance assertion failed, one filtered out. V6 correctly cleared a pre-existing allowance to zero; assertion fixed. +- Focused run: Jest E2E config, runInBand, v5-multiasset.spec.ts and universal-evm.spec.ts, testNamePattern `agw v5 multi-asset 3\.|agw universal evm 3\.`. Covers the corrected case and the newly added EVM EQ/MAX alternative case. + +Local gateway/token fixtures prove Push contract execution, not destination delivery. Live evidence covers actual Donut→Sepolia/Solana devnet transactions. No real contracts were deployed by the SDK work. Do not describe combined full/focused coverage as one clean full run. diff --git a/plan/agw/research/v6-integration-2026-10-14/contract-changes.md b/plan/agw/research/v6-integration-2026-10-14/contract-changes.md new file mode 100644 index 00000000..0023be4b --- /dev/null +++ b/plan/agw/research/v6-integration-2026-10-14/contract-changes.md @@ -0,0 +1,185 @@ +# Push Agentic Wallet — what changed in v6 + +**Deployed on Donut (chain `42101`) on 2026-10-14** from branch `deploy-agw`, commit `ffd567d`. Addresses: +[`docs/addresses/donut.md`](addresses/donut.md). + +v6 ships the fixes from the SDK team's first review of v5. It is a **fresh deployment**: every contract has a new +address. The v5 contracts stay on chain and v5 wallets keep working, but they do not get any of the changes below. + +--- + +## At a glance + +| Contract | Changed in v6? | What changed, in one line | +|---|---|---| +| **AGW** (the wallet) | Yes | Approves the gateway by itself before an outbound; can receive its first rules while it is being created | +| **AGWFactory** | Yes | New `createWallet` and `createWalletWithSig`: a wallet and its rules in one transaction | +| **UniversalRulesPolicy (URP)** | Yes | Argument pins on cross-chain calls; a zero limit now means "nothing"; smaller contract | +| **SvmRulebook** | New | The Solana rules, moved out of URP into a linked library; no behaviour change | +| **AgentValidator** | No | Same code, new address | +| **SmartSession** (engine) | No | Same code, new address | + +--- + +## 1. AGW — the wallet + +### No more approve step before sending tokens cross-chain + +**Before:** to send tokens out through the gateway, the owner or the agent first had to call +`token.approve(gateway, amount)`. Without that, the gateway could not pull the tokens and the outbound failed. + +**Now:** the wallet does it automatically. When a call is the gateway's `sendUniversalTxOutbound`, the wallet: + +1. approves the gateway for **exactly** the amount in the request; +2. makes the call; +3. sets the allowance back to **0** afterwards. + +- **It works the same on every door:** the owner (`execute`), a signed owner intent (`executeWithSig`) and the agent + (`executeAsAgent`). +- **On the agent door it runs only after URP has accepted the request,** so only a listed token within its limits is + ever approved. +- **It can never make a call fail.** If the request can't be read, or the token behaves oddly, the wallet skips the + approval and forwards the call unchanged. The gateway still decides whether the transfer happens. +- **Standing allowances don't last.** After any outbound in a token, the wallet's allowance to the gateway for that + token is 0, even if the owner set one on purpose. + +**For integrators:** remove the approve step. Sending one is harmless but unnecessary. + +### A wallet can be created with its rules already granted + +`initializeAccount` now takes the initial rules as well as the label. The factory calls it once, at creation. The rules +go through exactly the same checks as a normal `grantRules`. If any rule is refused, the whole creation is undone, so a +wallet never exists with only some of its rules. + +### Unchanged + +- **`execute`** (the owner door) is byte-for-byte the code that was reviewed. +- The label (`label()`, `setLabel`), the checkpoint counter, revoking rules and the signed-intent doors work as before. + +--- + +## 2. AGWFactory + +### `createWallet` and `createWalletWithSig`: one transaction instead of two + +**Before:** `deployWallet`, then a separate `grantRules` for each rule. + +**Now:** + +| Function | Who is the owner | What it does | +|---|---|---| +| `createWallet(label, rules)` | the caller | Deploys the caller's next wallet and grants up to **8** rules | +| `createWalletWithSig(intent, sig, label, rules)` | whoever signed `intent` | The same, submitted by a relayer on the owner's behalf | + +- **The address is the same** one `predictWallet` returns. Pre-funding the predicted address still works. +- **All or nothing:** either the wallet exists with every rule, or nothing happened. +- **The rule ids come back** in the same order as the rules. +- **An empty rules list** behaves exactly like `deployWallet` / `deployWalletWithSig`. +- **The signed form binds the rules to the signature.** It requires `intent.sessionHash = keccak256(abi.encode(rules))` + over the whole array, and `intent.grantNonce = 0`. The label is not signed, as in `deployWalletWithSig`. The + `OwnerIntent` format is unchanged. +- **Pausing** the factory stops these two as well as the deploy functions. +- **New errors:** `TooManyInitialRules`, `IntentRulesMismatch`, `IntentGrantNonceNotZero`. +- **`createWalletWithSig` selector:** `0x0a8f332b`. + +### Unchanged + +`deployWallet`, `deployWalletWithSig`, `predictWallet`, `ownerOf`, `isWallet` and the address formula are unchanged. +Owner intents must be signed for the **new factory address**, because the factory is the EIP-712 domain. + +--- + +## 3. UniversalRulesPolicy (URP) — the rules engine + +### Argument pins on cross-chain calls + +A cross-chain rule's allow-list says which contract and function the agent may call on the destination chain. **Each +entry can now also pin the call's arguments.** + +```solidity +enum PinOp { EQ, MAX } +struct ArgPin { uint16 offset; PinOp op; bytes32 value; } +struct AllowedCall { + address target; bytes4 selector; uint16 beneficiaryOffset; bool hasBeneficiary; uint256 maxValue; + ArgPin[] pins; // new +} +``` + +- **`EQ`:** the argument must equal `value`, for example "the spender must be Aave's pool". +- **`MAX`:** the argument must not exceed `value`, for example "approve at most 1,000 USDC per call". It limits one + call, not a total. +- **`offset`** counts from the start of the calldata, selector included, so `4` is the first argument. Only + fixed-size arguments can be pinned. +- **Limits:** up to 8 pins per entry, and up to 32 across the whole allow-list. + +**Matching changed as well.** v5 checked only the first entry for a given contract and function. v6 lets the call +through if **any** entry for that contract and function passes in full: beneficiary, value cap and every pin. That's +what lets one rule allow "approve to Aave **or** to Uniswap". If no entry passes, the error reported is the **first** +matching entry's. + +**For integrators:** an entry with no pins sitting beside a pinned entry for the same function makes the pins +pointless. The SDK should refuse that shape. + +### Native rules get `MAX` pins too + +Push-side rules use the same `ArgPin` type. In v5 a native pin could only mean "equals" (`{offset, expected}`); now +it is `{offset, op, value}` and supports `MAX`. + +### A zero limit now means "nothing", never "unlimited" + +In v5, a few fields used `0` to mean "no limit". In v6, zero never means unlimited. + +| Field | v5 | v6 | +|---|---|---| +| Native `maxCalls` | `0` = unlimited | `0` is **refused** (`ZeroMaxCalls`). Unlimited is `type(uint32).max` (`UNLIMITED_CALLS`). | +| Solana program `maxAccounts` | `0` = any number of accounts | `1`–`64` = exactly that many; `255` = any (`ANY_ACCOUNT_COUNT`); `0` and `65`–`254` refused (`SvmMaxAccountsOutOfRange`) | +| Token and value caps | `type(uint256).max` = unlimited, `0` = nothing | unchanged | + +**For integrators:** any rule built with `maxCalls: 0` or `maxAccounts: 0` must be updated, or it will be refused when +granted. + +### Smaller contract + +The Solana rules moved into **`SvmRulebook`** (below), which brought URP from 24,326 bytes, just under the +24,576-byte limit, down to 18,538. That leaves room for future changes. + +### Unchanged + +- The rule envelope `abi.encode(uint16 version, string chainNamespace, bytes body)`, `version = 1`. +- Multi-asset caps, gas caps, expiry, and the rule that the chain string decides the rulebook. +- `version()` still returns `"3.1.0"`. + +--- + +## 4. SvmRulebook — new + +The Solana rulebook (checks S1–S18) as a separate **library linked into URP**. It runs inside URP, through +`DELEGATECALL`, so to callers nothing changed: same errors, same events (emitted from URP's address), same storage. + +- **It holds no funds and no state of its own,** and it calls nothing else. +- **Its address is built into URP's code at deployment.** It can't be swapped later. +- **It isn't verified on the explorer.** Donut's Blockscout doesn't index contracts created through the CREATE2 + helper, so it won't verify this one. URP's own verification names the library's address, which confirms which + code URP runs. + +--- + +## 5. AgentValidator and SmartSession + +**No code changes.** They were redeployed only because v6 is a fresh suite: URP points at the engine, and the wallet +points at all three. + +--- + +## What integrators need to do + +| | Action | +|---|---| +| Addresses | Switch to the v6 factory and URP (see the address book). Sign owner intents for the **new factory**. | +| Outbound | Remove the `approve(gateway, amount)` step. | +| Creating wallets | Optionally use `createWallet` / `createWalletWithSig` to create and grant in one step. | +| Cross-chain rule encoding | `AllowedCall` has a new last field, `ArgPin[] pins` (an empty array is fine). | +| Native rule encoding | `ArgPin` is now `{offset, op, value}`; `maxCalls` must be non-zero (`type(uint32).max` for unlimited). | +| Solana rule encoding | `maxAccounts` must be `1`–`64`, or `255` for any. | + +ABI tuples for the new encodings are in [`docs/addresses/donut.md`](addresses/donut.md#how-to-grant-a-rule-current-encoding). diff --git a/plan/agw/research/v6-integration-2026-10-14/credential-scan.json b/plan/agw/research/v6-integration-2026-10-14/credential-scan.json new file mode 100644 index 00000000..4a32acc9 --- /dev/null +++ b/plan/agw/research/v6-integration-2026-10-14/credential-scan.json @@ -0,0 +1,4 @@ +{ + "scope": "v6 review artifacts only; no environment files read", + "literal_credential_candidates": [] +} diff --git a/plan/agw/research/v6-integration-2026-10-14/docs.log b/plan/agw/research/v6-integration-2026-10-14/docs.log new file mode 100644 index 00000000..7f37e7a9 --- /dev/null +++ b/plan/agw/research/v6-integration-2026-10-14/docs.log @@ -0,0 +1 @@ +AGW guide: 5 TypeScript blocks typechecked against public exports; no examples executed. diff --git a/plan/agw/research/v6-integration-2026-10-14/e2e-selection.log b/plan/agw/research/v6-integration-2026-10-14/e2e-selection.log new file mode 100644 index 00000000..36150c39 --- /dev/null +++ b/plan/agw/research/v6-integration-2026-10-14/e2e-selection.log @@ -0,0 +1,72 @@ +✓ agw-create-bare 1 test +✓ agw-create-rules 1 test +✓ agw-funding-pc 1 test +✓ agw-funding-allowance 1 test +✓ agw-native-batch 1 test +✓ agw-native-batch-rollback 1 test +✓ agw-native-agent 1 test +✓ agw-native-owner 1 test +✓ agw-native-over-cap 1 test +✓ agw-native-stranger 1 test +✓ agw-native-revoked 1 test +✓ agw-native-expired 1 test +✓ agw-lifecycle-add 1 test +✓ agw-lifecycle-update 1 test +✓ agw-lifecycle-checkpoints 1 test +✓ agw-lifecycle-revoke-all 1 test +✓ agw-v6-destination-pins 1 test +✓ agw-universal-outbound 1 test +✓ agw-v5-multi-asset 1 test +✓ agw-v5-call-only 1 test +✓ agw-universal-dest-revert 1 test +✓ agw-identity-evm 1 test +✓ agw-identity-first-use 1 test +✓ agw-identity-solana 1 test +✓ agw-responses-hooks 1 test +✓ agw-responses-replay 1 test +✓ agw-public-svm-1 1 test +✓ agw-public-svm-2 1 test +✓ agw-public-svm-3 1 test +✓ agw-public-svm-4 1 test +✓ agw-public-svm-5 1 test +✓ agw-public-svm-6 1 test +✓ agw-labels-1 1 test +✓ agw-labels-2 1 test +✓ agw-labels-3 1 test +✓ agw-labels-4 1 test +✓ agw-labels-5 1 test +✓ agw-labels-6 1 test +✓ agw-labels-7 1 test +✓ agw-labels-8 1 test +✓ agw-v5-independent-token-budgets 1 test +✓ agw-owner-spl-transfer 1 test +✓ agw-native-multi-action-1 1 test +✓ agw-native-multi-action-2 1 test +✓ agw-native-multi-action-3 1 test +✓ agw-native-multi-action-4 1 test +✓ agw-native-multi-action-5 1 test +✓ agw-native-multi-action-6 1 test +✓ agw-native-multi-action-7 1 test +✓ agw-native-multi-action-8 1 test +✓ agw-native-multi-action-9 1 test +✓ agw-native-multi-action-10 1 test +✓ agw-extended-prefunding 1 test +✓ agw-extended-duplicate-rules 1 test +✓ agw-extended-batched-lifecycle 1 test +✓ agw-extended-invalid-revoke 1 test +✓ agw-extended-stale-update 1 test +✓ agw-extended-index-race 1 test +✓ agw-extended-native-policy-1 1 test +✓ agw-extended-native-policy-2 1 test +✓ agw-extended-native-policy-3 1 test +✓ agw-extended-native-policy-4 1 test +✓ agw-extended-native-policy-5 1 test +✓ agw-extended-native-policy-6 1 test +✓ agw-extended-native-policy-7 1 test +✓ agw-extended-native-policy-8 1 test +✓ agw-extended-native-policy-9 1 test +✓ agw-extended-native-policy-10 1 test +✓ agw-extended-native-policy-11 1 test + +69 scenarios, 15 spec files, 69 distinct tests. +Manifest is consistent with the specs. diff --git a/plan/agw/research/v6-integration-2026-10-14/full-unit.log b/plan/agw/research/v6-integration-2026-10-14/full-unit.log new file mode 100644 index 00000000..e6fa65d8 --- /dev/null +++ b/plan/agw/research/v6-integration-2026-10-14/full-unit.log @@ -0,0 +1,176 @@ +PASS core packages/core/src/lib/agentic/__tests__/management.spec.ts +PASS core packages/core/src/lib/universal/account/account.spec.ts + ● Console + + console.warn + [PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead. + + 207 | ): Promise { + 208 | if (!_convertOriginToExecutorWarned) { + > 209 | console.warn( + | ^ + 210 | '[PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead.' + 211 | ); + 212 | _convertOriginToExecutorWarned = true; + + at Object.convertOriginToExecutor (src/lib/universal/account/account.ts:209:13) + at Object. (src/lib/universal/account/account.spec.ts:80:52) + + console.warn + [PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead. + + 425 | ): Promise { + 426 | if (!options?._internal && !_convertExecutorToOriginWarned) { + > 427 | console.warn( + | ^ + 428 | '[PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead.' + 429 | ); + 430 | _convertExecutorToOriginWarned = true; + + at convertExecutorToOrigin (src/lib/universal/account/account.ts:427:13) + at Object. (src/lib/universal/account/account.spec.ts:106:38) + +PASS core packages/core/src/lib/agentic/__tests__/presets.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/block-results-client.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-timeout-clamp.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/response-invariant.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-tx-retry.spec.ts +PASS core packages/core/src/lib/push-client/push-client.archive-fallback.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-multichain.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-error-classification.spec.ts +PASS core packages/core/src/lib/utils.spec.ts + ● Console + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:973:17) + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:977:17) + + console.log + 1.23 + + at Object. (src/lib/utils.spec.ts:982:17) + +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-confirmation-gate.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/inbound-tracker-derivation.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/gate.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/chain-namespace.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r1-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-svm-confirmation.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/reads-context.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-svm-rent.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-usd-sizer.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-emission.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/signing-payload.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/codec.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/send.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-tracker.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r2-outbound-revert-flow.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/build-payload.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r3-spec-strings.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/labels.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/scenarios.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/source-hash-resolution.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/public-surface.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/funds-only-burn-guard.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/registry.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-event-hook-bridge.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-executor.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/export.spec.ts +PASS core packages/core/src/lib/universal/signer/signer.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r2-spec-strings.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/native-multi-action.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/response-surface.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/public-rule.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-native-multicall.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/terminal-suppression.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/resolve.spec.ts +PASS core packages/core/src/lib/push-client/push-client.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/inbound-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/resolver.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/read-tx-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/payload-builders.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/spec-builder.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/account-status.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-composition.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/track-transaction-guard.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.chain-symbol.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/cascade.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-evm-r3-native-eoa.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-wire-fixture.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm-rent-pc20.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-quote.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-svm-r3.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gateway-uea-account.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/rescue-svm-confirmation.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/response-builder-push-revert.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-backend.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/context-helpers-tracker.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/multichain-hooks.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm-log-index.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/svm-rent.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-evm.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/send-transaction-progress-hook.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-request-recipient.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-detector.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/svm-account.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-builder-progress-hook.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-idl.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/web2-compat.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-error-classification.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-params.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-calculator.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/result-decoder.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-types.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/revalidate-read.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/execute-standard-required-funds.spec.ts +PASS core packages/core/src/lib/constants/__tests__/token-constants.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/abi-selectors.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/address-codec.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-svm.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/child-inbounds.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/normalize.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/auto-detect.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg-svm.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/__tests__/signing.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.dynamic-gas.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.batch-gas.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/ucallback-codec.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/validate.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-web2.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-events.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/ix-encoder.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/registry.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/error-decoder.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/classify.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/errors.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/normalize-address.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/max-pc-for-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/tracking.spec.ts +PASS core packages/core/src/lib/formatters.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/budget.spec.ts +PASS core packages/core/src/lib/constants/__tests__/svm-gateway-idl.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-execute-order.spec.ts + +Test Suites: 1 skipped, 123 passed, 123 of 124 total +Tests: 12 skipped, 2073 passed, 2085 total +Snapshots: 0 total +Time: 31.744 s, estimated 63 s +Ran all test suites. diff --git a/plan/agw/research/v6-integration-2026-10-14/head-recheck.json b/plan/agw/research/v6-integration-2026-10-14/head-recheck.json new file mode 100644 index 00000000..54ba1d09 --- /dev/null +++ b/plan/agw/research/v6-integration-2026-10-14/head-recheck.json @@ -0,0 +1,6 @@ +{ + "checked_at": "2026-10-14T17:35:34.427115+00:00", + "deploy_agw_head": "e57998c2d8ef9db15e69a68061ad3101120a6c6c", + "deployed_source": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "source_diff_from_pin": "" +} diff --git a/plan/agw/research/v6-integration-2026-10-14/live-evidence.jsonl b/plan/agw/research/v6-integration-2026-10-14/live-evidence.jsonl new file mode 100644 index 00000000..bf7dd8d3 --- /dev/null +++ b/plan/agw/research/v6-integration-2026-10-14/live-evidence.jsonl @@ -0,0 +1,68 @@ +{"name":"native-multi-grant-read-send","at":"2026-10-14T16:47:12.099Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0x1E16B0Bdc3C48941d0cB35F6588Da19529AA7D81","id":"0x910a0ca05d23f210ed781e6fdc04639bfc8fd1b3449f2d9c621b53bd534c326c","copy":"0x93fFb6c7c3937A00f36A8542c9215B2168a8d61B","hashes":["0xd695b5cb4b5117d9e1c0bafcf649547efddd135083fdfe086b0f5bb0e5092e5b","0x037a07e5f0de374061fffc1b50b8f353396aa425a9a5b7f6d8cb645993101050","0x53eca49822b9bc27b13bf52fc614262ff98bf500aa5f651eac51ddbc9508fb52","0xaa3333de5275f84257c9ca818eea4d93452995bb72bf225df71c2c8e44cabfd0"],"state":{"configs":[{"actionId":"0x4fe8d98db364b0d0802786da5e61c881c40402aa4663465b7a61732dde03167c","config":{"initialized":true,"validUntil":1791999967,"target":"0x0A16CBa65FfCAa4C2282b27b027Ab4A2fE46E0Bf","selector":"0xffffffff","maxValuePerCall":"1","maxValueTotal":"115792089237316195423570985008687907853269984665640564039457584007913129639935","valueSpent":"1","amount":{"enabled":false,"offset":0,"maxPerCall":"0","maxTotal":"0"},"amountSpent":"0","maxCalls":4294967295,"callsUsed":1,"pins":[]}},{"actionId":"0x0e8617603fbb66bc7458db5803c01fa022ef9f48b47628d52af31c980f10421d","config":{"initialized":true,"validUntil":1791999967,"target":"0x2971824Db68229D087931155C2b8bB820B275809","selector":"0xa9059cbb","maxValuePerCall":"0","maxValueTotal":"115792089237316195423570985008687907853269984665640564039457584007913129639935","valueSpent":"0","amount":{"enabled":false,"offset":0,"maxPerCall":"0","maxTotal":"0"},"amountSpent":"0","maxCalls":4294967295,"callsUsed":1,"pins":[{"offset":4,"op":0,"value":"0x0000000000000000000000000a16cba65ffcaa4c2282b27b027ab4a2fe46e0bf"},{"offset":36,"op":1,"value":"0x0000000000000000000000000000000000000000000000000000000000000003"}]}}],"walletPC":"9","recipientPC":"969371238378936756997459","walletToken":"18","recipientToken":"434311515549551167987","checkpointCount":"1","grantNonce":"1"}} +{"name":"native-multi-refused","at":"2026-10-14T16:47:41.975Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0x20E833F6F2EBcf52F250B2E6f480dCac8Eb1aF62","id":"0x910a0ca05d23f210ed781e6fdc04639bfc8fd1b3449f2d9c621b53bd534c326c","gate":"PolicyCheckReverted(ArgPinMismatch)","state":{"configs":[{"actionId":"0x4fe8d98db364b0d0802786da5e61c881c40402aa4663465b7a61732dde03167c","config":{"initialized":true,"validUntil":1792000032,"target":"0x0A16CBa65FfCAa4C2282b27b027Ab4A2fE46E0Bf","selector":"0xffffffff","maxValuePerCall":"1","maxValueTotal":"115792089237316195423570985008687907853269984665640564039457584007913129639935","valueSpent":"0","amount":{"enabled":false,"offset":0,"maxPerCall":"0","maxTotal":"0"},"amountSpent":"0","maxCalls":4294967295,"callsUsed":0,"pins":[]}},{"actionId":"0x0e8617603fbb66bc7458db5803c01fa022ef9f48b47628d52af31c980f10421d","config":{"initialized":true,"validUntil":1792000032,"target":"0x2971824Db68229D087931155C2b8bB820B275809","selector":"0xa9059cbb","maxValuePerCall":"0","maxValueTotal":"115792089237316195423570985008687907853269984665640564039457584007913129639935","valueSpent":"0","amount":{"enabled":false,"offset":0,"maxPerCall":"0","maxTotal":"0"},"amountSpent":"0","maxCalls":4294967295,"callsUsed":0,"pins":[{"offset":4,"op":0,"value":"0x0000000000000000000000000a16cba65ffcaa4c2282b27b027ab4a2fe46e0bf"},{"offset":36,"op":1,"value":"0x0000000000000000000000000000000000000000000000000000000000000003"}]}}],"walletPC":"10","recipientPC":"969371237041228506997449","walletToken":"20","recipientToken":"434311515549551167967","checkpointCount":"1","grantNonce":"1"},"agentNonce":2} +{"name":"native-multi-refused","at":"2026-10-14T16:47:45.869Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0x20E833F6F2EBcf52F250B2E6f480dCac8Eb1aF62","id":"0x910a0ca05d23f210ed781e6fdc04639bfc8fd1b3449f2d9c621b53bd534c326c","gate":"PolicyCheckReverted(ArgPinAboveMax)","state":{"configs":[{"actionId":"0x4fe8d98db364b0d0802786da5e61c881c40402aa4663465b7a61732dde03167c","config":{"initialized":true,"validUntil":1792000032,"target":"0x0A16CBa65FfCAa4C2282b27b027Ab4A2fE46E0Bf","selector":"0xffffffff","maxValuePerCall":"1","maxValueTotal":"115792089237316195423570985008687907853269984665640564039457584007913129639935","valueSpent":"0","amount":{"enabled":false,"offset":0,"maxPerCall":"0","maxTotal":"0"},"amountSpent":"0","maxCalls":4294967295,"callsUsed":0,"pins":[]}},{"actionId":"0x0e8617603fbb66bc7458db5803c01fa022ef9f48b47628d52af31c980f10421d","config":{"initialized":true,"validUntil":1792000032,"target":"0x2971824Db68229D087931155C2b8bB820B275809","selector":"0xa9059cbb","maxValuePerCall":"0","maxValueTotal":"115792089237316195423570985008687907853269984665640564039457584007913129639935","valueSpent":"0","amount":{"enabled":false,"offset":0,"maxPerCall":"0","maxTotal":"0"},"amountSpent":"0","maxCalls":4294967295,"callsUsed":0,"pins":[{"offset":4,"op":0,"value":"0x0000000000000000000000000a16cba65ffcaa4c2282b27b027ab4a2fe46e0bf"},{"offset":36,"op":1,"value":"0x0000000000000000000000000000000000000000000000000000000000000003"}]}}],"walletPC":"10","recipientPC":"969371237041228506997449","walletToken":"20","recipientToken":"434311515549551167967","checkpointCount":"1","grantNonce":"1"},"agentNonce":2} +{"name":"native-multi-refused","at":"2026-10-14T16:47:49.720Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0x20E833F6F2EBcf52F250B2E6f480dCac8Eb1aF62","id":"0x910a0ca05d23f210ed781e6fdc04639bfc8fd1b3449f2d9c621b53bd534c326c","gate":"NoPoliciesSet","state":{"configs":[{"actionId":"0x4fe8d98db364b0d0802786da5e61c881c40402aa4663465b7a61732dde03167c","config":{"initialized":true,"validUntil":1792000032,"target":"0x0A16CBa65FfCAa4C2282b27b027Ab4A2fE46E0Bf","selector":"0xffffffff","maxValuePerCall":"1","maxValueTotal":"115792089237316195423570985008687907853269984665640564039457584007913129639935","valueSpent":"0","amount":{"enabled":false,"offset":0,"maxPerCall":"0","maxTotal":"0"},"amountSpent":"0","maxCalls":4294967295,"callsUsed":0,"pins":[]}},{"actionId":"0x0e8617603fbb66bc7458db5803c01fa022ef9f48b47628d52af31c980f10421d","config":{"initialized":true,"validUntil":1792000032,"target":"0x2971824Db68229D087931155C2b8bB820B275809","selector":"0xa9059cbb","maxValuePerCall":"0","maxValueTotal":"115792089237316195423570985008687907853269984665640564039457584007913129639935","valueSpent":"0","amount":{"enabled":false,"offset":0,"maxPerCall":"0","maxTotal":"0"},"amountSpent":"0","maxCalls":4294967295,"callsUsed":0,"pins":[{"offset":4,"op":0,"value":"0x0000000000000000000000000a16cba65ffcaa4c2282b27b027ab4a2fe46e0bf"},{"offset":36,"op":1,"value":"0x0000000000000000000000000000000000000000000000000000000000000003"}]}}],"walletPC":"10","recipientPC":"969371237041228506997449","walletToken":"20","recipientToken":"434311515549551167967","checkpointCount":"1","grantNonce":"1"},"agentNonce":2} +{"name":"native-multi-independent-counters","at":"2026-10-14T16:49:04.936Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0x74877361de346757bf4342fEaC0C2eFdAd44343f","id":"0x910a0ca05d23f210ed781e6fdc04639bfc8fd1b3449f2d9c621b53bd534c326c","state":{"configs":[{"actionId":"0x4fe8d98db364b0d0802786da5e61c881c40402aa4663465b7a61732dde03167c","config":{"initialized":true,"validUntil":1792000070,"target":"0x0A16CBa65FfCAa4C2282b27b027Ab4A2fE46E0Bf","selector":"0xffffffff","maxValuePerCall":"1","maxValueTotal":"115792089237316195423570985008687907853269984665640564039457584007913129639935","valueSpent":"2","amount":{"enabled":false,"offset":0,"maxPerCall":"0","maxTotal":"0"},"amountSpent":"0","maxCalls":4294967295,"callsUsed":3,"pins":[]}},{"actionId":"0x0e8617603fbb66bc7458db5803c01fa022ef9f48b47628d52af31c980f10421d","config":{"initialized":true,"validUntil":1792000070,"target":"0x2971824Db68229D087931155C2b8bB820B275809","selector":"0xa9059cbb","maxValuePerCall":"0","maxValueTotal":"115792089237316195423570985008687907853269984665640564039457584007913129639935","valueSpent":"0","amount":{"enabled":false,"offset":0,"maxPerCall":"0","maxTotal":"0"},"amountSpent":"0","maxCalls":4294967295,"callsUsed":3,"pins":[{"offset":4,"op":0,"value":"0x0000000000000000000000000a16cba65ffcaa4c2282b27b027ab4a2fe46e0bf"},{"offset":36,"op":1,"value":"0x0000000000000000000000000000000000000000000000000000000000000003"}]}}],"walletPC":"8","recipientPC":"969371235703520256997441","walletToken":"14","recipientToken":"434311515549551167953","checkpointCount":"1","grantNonce":"1"}} +{"name":"native-multi-mixed-batch","at":"2026-10-14T16:49:50.703Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0x2BF97CF5fd4c15113E5c0be1395101d9e2aaC896","id":"0x910a0ca05d23f210ed781e6fdc04639bfc8fd1b3449f2d9c621b53bd534c326c","hash":"0x1891122599f8c911386acf9045e256681f6d6aee6fad72a451efd982e1e2beb7","state":{"configs":[{"actionId":"0x4fe8d98db364b0d0802786da5e61c881c40402aa4663465b7a61732dde03167c","config":{"initialized":true,"validUntil":1792000144,"target":"0x0A16CBa65FfCAa4C2282b27b027Ab4A2fE46E0Bf","selector":"0xffffffff","maxValuePerCall":"1","maxValueTotal":"115792089237316195423570985008687907853269984665640564039457584007913129639935","valueSpent":"1","amount":{"enabled":false,"offset":0,"maxPerCall":"0","maxTotal":"0"},"amountSpent":"0","maxCalls":4294967295,"callsUsed":1,"pins":[]}},{"actionId":"0x0e8617603fbb66bc7458db5803c01fa022ef9f48b47628d52af31c980f10421d","config":{"initialized":true,"validUntil":1792000144,"target":"0x2971824Db68229D087931155C2b8bB820B275809","selector":"0xa9059cbb","maxValuePerCall":"0","maxValueTotal":"115792089237316195423570985008687907853269984665640564039457584007913129639935","valueSpent":"0","amount":{"enabled":false,"offset":0,"maxPerCall":"0","maxTotal":"0"},"amountSpent":"0","maxCalls":4294967295,"callsUsed":1,"pins":[{"offset":4,"op":0,"value":"0x0000000000000000000000000a16cba65ffcaa4c2282b27b027ab4a2fe46e0bf"},{"offset":36,"op":1,"value":"0x0000000000000000000000000000000000000000000000000000000000000003"}]}}],"walletPC":"9","recipientPC":"969371234365812006997432","walletToken":"18","recipientToken":"434311515549551167935","checkpointCount":"1","grantNonce":"1"}} +{"name":"native-multi-refused","at":"2026-10-14T16:50:35.851Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0xEFbF34702A0b02F1997bCeC705D061B49021bB01","id":"0x910a0ca05d23f210ed781e6fdc04639bfc8fd1b3449f2d9c621b53bd534c326c","gate":"PolicyCheckReverted(ArgPinAboveMax)","state":{"configs":[{"actionId":"0x4fe8d98db364b0d0802786da5e61c881c40402aa4663465b7a61732dde03167c","config":{"initialized":true,"validUntil":1792000190,"target":"0x0A16CBa65FfCAa4C2282b27b027Ab4A2fE46E0Bf","selector":"0xffffffff","maxValuePerCall":"1","maxValueTotal":"115792089237316195423570985008687907853269984665640564039457584007913129639935","valueSpent":"1","amount":{"enabled":false,"offset":0,"maxPerCall":"0","maxTotal":"0"},"amountSpent":"0","maxCalls":4294967295,"callsUsed":1,"pins":[]}},{"actionId":"0x0e8617603fbb66bc7458db5803c01fa022ef9f48b47628d52af31c980f10421d","config":{"initialized":true,"validUntil":1792000190,"target":"0x2971824Db68229D087931155C2b8bB820B275809","selector":"0xa9059cbb","maxValuePerCall":"0","maxValueTotal":"115792089237316195423570985008687907853269984665640564039457584007913129639935","valueSpent":"0","amount":{"enabled":false,"offset":0,"maxPerCall":"0","maxTotal":"0"},"amountSpent":"0","maxCalls":4294967295,"callsUsed":1,"pins":[{"offset":4,"op":0,"value":"0x0000000000000000000000000a16cba65ffcaa4c2282b27b027ab4a2fe46e0bf"},{"offset":36,"op":1,"value":"0x0000000000000000000000000000000000000000000000000000000000000003"}]}}],"walletPC":"9","recipientPC":"969371233028103756997423","walletToken":"19","recipientToken":"434311515549551167916","checkpointCount":"1","grantNonce":"1"},"agentNonce":12} +{"name":"native-multi-mined-rollback","at":"2026-10-14T16:50:40.877Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0xEFbF34702A0b02F1997bCeC705D061B49021bB01","id":"0x910a0ca05d23f210ed781e6fdc04639bfc8fd1b3449f2d9c621b53bd534c326c","hash":"0x7b47a3bfc6e8592829022d24724bdab80e0eab586691fff304a50f109ecba3ca","block":"24245433","gasUsed":"300000","state":{"configs":[{"actionId":"0x4fe8d98db364b0d0802786da5e61c881c40402aa4663465b7a61732dde03167c","config":{"initialized":true,"validUntil":1792000190,"target":"0x0A16CBa65FfCAa4C2282b27b027Ab4A2fE46E0Bf","selector":"0xffffffff","maxValuePerCall":"1","maxValueTotal":"115792089237316195423570985008687907853269984665640564039457584007913129639935","valueSpent":"1","amount":{"enabled":false,"offset":0,"maxPerCall":"0","maxTotal":"0"},"amountSpent":"0","maxCalls":4294967295,"callsUsed":1,"pins":[]}},{"actionId":"0x0e8617603fbb66bc7458db5803c01fa022ef9f48b47628d52af31c980f10421d","config":{"initialized":true,"validUntil":1792000190,"target":"0x2971824Db68229D087931155C2b8bB820B275809","selector":"0xa9059cbb","maxValuePerCall":"0","maxValueTotal":"115792089237316195423570985008687907853269984665640564039457584007913129639935","valueSpent":"0","amount":{"enabled":false,"offset":0,"maxPerCall":"0","maxTotal":"0"},"amountSpent":"0","maxCalls":4294967295,"callsUsed":1,"pins":[{"offset":4,"op":0,"value":"0x0000000000000000000000000a16cba65ffcaa4c2282b27b027ab4a2fe46e0bf"},{"offset":36,"op":1,"value":"0x0000000000000000000000000000000000000000000000000000000000000003"}]}}],"walletPC":"9","recipientPC":"969371233028103756997423","walletToken":"19","recipientToken":"434311515549551167916","checkpointCount":"1","grantNonce":"1"}} +{"name":"native-multi-replacement","at":"2026-10-14T16:52:02.349Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0x22942C91911830857D4378b8247bba0C815B11Da","oldId":"0x910a0ca05d23f210ed781e6fdc04639bfc8fd1b3449f2d9c621b53bd534c326c","newId":"0x4063b2b2dda9e9eb2cdd2a7b55d04c4761f6d306b6b505042492b79ea2f32553","trimmedId":"0xbdd016503001503a1c5c998b2700007687b0659ec4be4ad6b537dba0d1356391","hashes":["0x4eda0ce90e39cff0630d181727b98c6ccbae537b8f0ac8f83013fa3bce379760","0x217c0620fea29e9359bcebdedb925fb468bcbb8b189e32b995b522fffaa9683b","0xad2cc7e81d3f35e183540d1db2dfac742ef0017e7fbb063b1773aba19a9f4378"]} +{"name":"native-multi-second-action-race","at":"2026-10-14T16:52:42.114Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0x66aC85137603f514b873fDb7ce2727FA2BfB21A0","oldId":"0x910a0ca05d23f210ed781e6fdc04639bfc8fd1b3449f2d9c621b53bd534c326c","newId":"0x4063b2b2dda9e9eb2cdd2a7b55d04c4761f6d306b6b505042492b79ea2f32553","spendHash":"0x7f7f06a579b4dd6ca4bd0a4d9a98b175193f39343b94184f286911e63271397e","retryHash":"0xb2f0a95bb8db1398f5aabc9a0b8157775d21e72e81a66d2014cbe67c135d65c3","stateAfterRace":{"configs":[{"actionId":"0x4fe8d98db364b0d0802786da5e61c881c40402aa4663465b7a61732dde03167c","config":{"initialized":true,"validUntil":1792000322,"target":"0x0A16CBa65FfCAa4C2282b27b027Ab4A2fE46E0Bf","selector":"0xffffffff","maxValuePerCall":"1","maxValueTotal":"115792089237316195423570985008687907853269984665640564039457584007913129639935","valueSpent":"0","amount":{"enabled":false,"offset":0,"maxPerCall":"0","maxTotal":"0"},"amountSpent":"0","maxCalls":4294967295,"callsUsed":0,"pins":[]}},{"actionId":"0x0e8617603fbb66bc7458db5803c01fa022ef9f48b47628d52af31c980f10421d","config":{"initialized":true,"validUntil":1792000322,"target":"0x2971824Db68229D087931155C2b8bB820B275809","selector":"0xa9059cbb","maxValuePerCall":"0","maxValueTotal":"115792089237316195423570985008687907853269984665640564039457584007913129639935","valueSpent":"0","amount":{"enabled":false,"offset":0,"maxPerCall":"0","maxTotal":"0"},"amountSpent":"0","maxCalls":4294967295,"callsUsed":1,"pins":[{"offset":4,"op":0,"value":"0x0000000000000000000000000a16cba65ffcaa4c2282b27b027ab4a2fe46e0bf"},{"offset":36,"op":1,"value":"0x0000000000000000000000000000000000000000000000000000000000000003"}]}}],"walletPC":"10","recipientPC":"969371228520144381997404","walletToken":"19","recipientToken":"434311515549551167880","checkpointCount":"1","grantNonce":"1"}} +{"name":"native-multi-eight-boundary","at":"2026-10-14T16:52:57.362Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0xd2ED8C64bD54fA32D905fc7dCFb17aa47C786d13","id":"0x910a0ca05d23f210ed781e6fdc04639bfc8fd1b3449f2d9c621b53bd534c326c","hash":"0xe6e173d9b4fc4754716aad61e4ffab434ad01549be72243f6ed213cfda043d42","unchangedNextSlot":9} +{"name":"native-multi-refused","at":"2026-10-14T16:54:10.531Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0xe38049cCfaf1D74A0AA173c7C8E4840cdaeEE5E0","id":"0x910a0ca05d23f210ed781e6fdc04639bfc8fd1b3449f2d9c621b53bd534c326c","gate":"PolicyCheckReverted(RulesExpired)","state":{"configs":[{"actionId":"0x4fe8d98db364b0d0802786da5e61c881c40402aa4663465b7a61732dde03167c","config":{"initialized":true,"validUntil":1791996837,"target":"0x0A16CBa65FfCAa4C2282b27b027Ab4A2fE46E0Bf","selector":"0xffffffff","maxValuePerCall":"1","maxValueTotal":"115792089237316195423570985008687907853269984665640564039457584007913129639935","valueSpent":"0","amount":{"enabled":false,"offset":0,"maxPerCall":"0","maxTotal":"0"},"amountSpent":"0","maxCalls":4294967295,"callsUsed":0,"pins":[]}},{"actionId":"0x0e8617603fbb66bc7458db5803c01fa022ef9f48b47628d52af31c980f10421d","config":{"initialized":true,"validUntil":1791996837,"target":"0x2971824Db68229D087931155C2b8bB820B275809","selector":"0xa9059cbb","maxValuePerCall":"0","maxValueTotal":"115792089237316195423570985008687907853269984665640564039457584007913129639935","valueSpent":"0","amount":{"enabled":false,"offset":0,"maxPerCall":"0","maxTotal":"0"},"amountSpent":"0","maxCalls":4294967295,"callsUsed":0,"pins":[{"offset":4,"op":0,"value":"0x0000000000000000000000000a16cba65ffcaa4c2282b27b027ab4a2fe46e0bf"},{"offset":36,"op":1,"value":"0x0000000000000000000000000000000000000000000000000000000000000003"}]}}],"walletPC":"10","recipientPC":"969371223076682256997394","walletToken":"20","recipientToken":"434311515549551167860","checkpointCount":"1","grantNonce":"1"},"agentNonce":17} +{"name":"native-multi-refused","at":"2026-10-14T16:54:14.862Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0xe38049cCfaf1D74A0AA173c7C8E4840cdaeEE5E0","id":"0x910a0ca05d23f210ed781e6fdc04639bfc8fd1b3449f2d9c621b53bd534c326c","gate":"PolicyCheckReverted(RulesExpired)","state":{"configs":[{"actionId":"0x4fe8d98db364b0d0802786da5e61c881c40402aa4663465b7a61732dde03167c","config":{"initialized":true,"validUntil":1791996837,"target":"0x0A16CBa65FfCAa4C2282b27b027Ab4A2fE46E0Bf","selector":"0xffffffff","maxValuePerCall":"1","maxValueTotal":"115792089237316195423570985008687907853269984665640564039457584007913129639935","valueSpent":"0","amount":{"enabled":false,"offset":0,"maxPerCall":"0","maxTotal":"0"},"amountSpent":"0","maxCalls":4294967295,"callsUsed":0,"pins":[]}},{"actionId":"0x0e8617603fbb66bc7458db5803c01fa022ef9f48b47628d52af31c980f10421d","config":{"initialized":true,"validUntil":1791996837,"target":"0x2971824Db68229D087931155C2b8bB820B275809","selector":"0xa9059cbb","maxValuePerCall":"0","maxValueTotal":"115792089237316195423570985008687907853269984665640564039457584007913129639935","valueSpent":"0","amount":{"enabled":false,"offset":0,"maxPerCall":"0","maxTotal":"0"},"amountSpent":"0","maxCalls":4294967295,"callsUsed":0,"pins":[{"offset":4,"op":0,"value":"0x0000000000000000000000000a16cba65ffcaa4c2282b27b027ab4a2fe46e0bf"},{"offset":36,"op":1,"value":"0x0000000000000000000000000000000000000000000000000000000000000003"}]}}],"walletPC":"10","recipientPC":"969371223076682256997394","walletToken":"20","recipientToken":"434311515549551167860","checkpointCount":"1","grantNonce":"1"},"agentNonce":17} +{"name":"native-multi-shared-expiry","at":"2026-10-14T16:54:14.862Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0xe38049cCfaf1D74A0AA173c7C8E4840cdaeEE5E0","id":"0x910a0ca05d23f210ed781e6fdc04639bfc8fd1b3449f2d9c621b53bd534c326c","expiry":1791996837} +{"name":"native-multi-invalid-input","at":"2026-10-14T16:54:21.742Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","unchangedNextSlot":10,"ownerNonce":947} +{"name":"v5-two-token-replacement","at":"2026-10-14T16:55:00.339Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0x10fBd63d1Bd5f738307474d3e4a783c13420E076","oldId":"0x7e4c005207046e7610e72b780978225446afe6a4917f2dc31d81c8080cd5c474","newId":"0xe6876f2d3ff94b964e800ffcd3a34ae2d5448f1a73293a7ff0e5d9d5fd5549fe","txHash":"0xa0a22267ce6fbfa160f7448647872cffb4b0c6ea7ae639c9eb5ff708ef337a2b"} +{"name":"v5-call-only","at":"2026-10-14T16:56:45.083Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0x9391B29B898AF99EB1f8B8a67A6E58F595d6ddF9","pushTx":"0x0aece390ed031f343dbc03058ea4e70703d2739aeb51a103b5576f8b63b61a73","externalTx":"0x688f7b1f1e0fd9b9f4980e7373d4bbf33115639dfa3a9bc55ab62c4cb916d879"} +{"name":"v5-budget-outbound-submitted","at":"2026-10-14T16:57:32.562Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0xF92475F8d06a9a06395a54911448A255d10FD7a8","rulesId":"0x7e4c005207046e7610e72b780978225446afe6a4917f2dc31d81c8080cd5c474","token":"0x2971824Db68229D087931155C2b8bB820B275809","amount":"1000000000000","pushTx":"0xf86f91377a38fab44cb79025ed1dab5abfa3d44fd3d144d109581d7d834d0b8c"} +{"name":"extended-native-meter","at":"2026-10-14T16:59:50.095Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0xbB0619dB9E2014642385D8e7656C67482C320858","rulesId":"0xc403e94a466ebe25d96a3123d55852b2b76d58cd5c91a774464af7943cc9b510","txHash":"0xe76265f6ce5c01837cbd0a112dda83fdb2f496b82fd4c105ebaacd8cb50751e5"} +{"name":"extended-native-refusal","at":"2026-10-14T17:00:17.485Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0x26f12Cb0192f46333a03b98D24779Df5d9F0b79b","rulesId":"0xc403e94a466ebe25d96a3123d55852b2b76d58cd5c91a774464af7943cc9b510","gate":"ArgPinMismatch","counters":{"valueSpent":"0","amountSpent":"0","callsUsed":0},"tokenBalance":"50"} +{"name":"extended-native-refusal","at":"2026-10-14T17:00:35.691Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0x5e410Eb62C9C60A72D406653D0d6E6c6E30Bc337","rulesId":"0xc403e94a466ebe25d96a3123d55852b2b76d58cd5c91a774464af7943cc9b510","gate":"ArgPinAboveMax","counters":{"valueSpent":"0","amountSpent":"0","callsUsed":0},"tokenBalance":"50"} +{"name":"extended-native-refusal","at":"2026-10-14T17:02:26.347Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0xB44fbB9a25090C209fC1878773eA210347D41eaa","rulesId":"0xc403e94a466ebe25d96a3123d55852b2b76d58cd5c91a774464af7943cc9b510","gate":"ArgPinAboveMax","counters":{"valueSpent":"0","amountSpent":"0","callsUsed":0},"tokenBalance":"50"} +{"name":"extended-native-refusal","at":"2026-10-14T17:02:55.504Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0x25B4C4f403b632c4C8FC5F2BbBC8D5d0B4161290","rulesId":"0xc403e94a466ebe25d96a3123d55852b2b76d58cd5c91a774464af7943cc9b510","gate":"callee/engine","counters":{"valueSpent":"0","amountSpent":"0","callsUsed":0},"tokenBalance":"5"} +{"name":"extended-native-refusal","at":"2026-10-14T17:03:22.901Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0x8E26dbE7B971d05ca9091BC468fD150616bca2a4","rulesId":"0xc403e94a466ebe25d96a3123d55852b2b76d58cd5c91a774464af7943cc9b510","gate":"callee/engine","counters":{"valueSpent":"0","amountSpent":"0","callsUsed":0},"tokenBalance":"50"} +{"name":"extended-native-refusal","at":"2026-10-14T17:03:51.991Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0x7d951F1835955925FBE03165edDAb3B51b6bfc07","rulesId":"0xc403e94a466ebe25d96a3123d55852b2b76d58cd5c91a774464af7943cc9b510","gate":"ValueExceedsCap","counters":{"valueSpent":"0","amountSpent":"0","callsUsed":0},"tokenBalance":"5"} +{"name":"zero-pc-defaults","at":"2026-10-14T17:03:57.425Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0x7d951F1835955925FBE03165edDAb3B51b6bfc07","txHash":"0x58222df0d5979bb33f895e301ddba0fdf7d082b8d81480378fdf03da8dc1943c"} +{"name":"arg-index-reuse","at":"2026-10-14T17:04:21.290Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0x4D28f8E657EE5ace78B6B9986C6704627568d975","txHash":"0xe2f82f426fdaf45b52cc5e17af7d0872f48bc327a32de53a7905822f8c199d8d"} +{"name":"v5-evm-outbound-submitted","at":"2026-10-14T17:05:16.025Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0x5e98C3D8BE408DA49B05c00d55016865D660096D","cea":"0x20A7d9F1720BA4B5703dEd6115A2f719AcDcfD54","pushTx":"0x69140f7b3505adedd468a0c4667677745d79d251d401f7473ef930b40b7a03be","destinationGasLimit":"2000000"} +{"name":"universal-outbound","at":"2026-10-14T17:07:01.241Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0x5e98C3D8BE408DA49B05c00d55016865D660096D","cea":"0x20A7d9F1720BA4B5703dEd6115A2f719AcDcfD54","rulesId":"0x9654e2f1b8e1f0658b0a69c462769a9e1121b61f80b24043282e03ed2fa3d826","pushTx":"0x69140f7b3505adedd468a0c4667677745d79d251d401f7473ef930b40b7a03be","externalTx":"0x95d0ceef78c3ed71940a51aa89a7d21ab5e26e3beef6a1af4f17bf9da90c4a82","amount":"1000000000000"} +{"name":"universal-destination-revert","at":"2026-10-14T17:08:28.200Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0x5e98C3D8BE408DA49B05c00d55016865D660096D","pushTx":"0x92eb5b772e8dbdb910b4afd951a9a4597c8b7ccdd9a9b9c97dd368fc9308fb40","externalStatus":"failed"} +{"name":"extended-prefunding","at":"2026-10-14T17:09:27.531Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0x716E344F88Ab38EC8e23616417FB56f72a9d8B2a","index":25,"txHash":"0x3b7f77df87b9bb3cd37623b7971d7666f4a30852cd956449ca6f7a8ab7f71827"} +{"name":"duplicate-rule-guards","at":"2026-10-14T17:09:58.219Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0x0381e9c8156Cf4779778235583217051929d9180","deleted":["0x455a5e2e1f3f6e1b55c0f7d90ff10cefcf53e42c085cf5576e57974b3e88c027"],"added":["0x2f1da74e8548d1cadc1786e59af529e56159c76049ba9fa2aea53d49f83c0958"]} +{"name":"extended-management-batches","at":"2026-10-14T17:10:30.270Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0x6f9b23e35E969E11Ed6D2E9995782b0ab0278192","rulesIds":["0x455a5e2e1f3f6e1b55c0f7d90ff10cefcf53e42c085cf5576e57974b3e88c027","0xab892ee1f3df166034d5c1568330d5601aa7186622c9d44e20922909d4b0c9df"],"addHash":"0x4ff61a40e1ec6782dc4e34cacc57667b4ee9d12174e7a6e520b989417d72cacb","checkpoints":8} +{"name":"extended-stale-update","at":"2026-10-14T17:11:13.790Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0x428796a84d74C2a7Aadc64B536641bC4A4B54D18","rulesId":"0x455a5e2e1f3f6e1b55c0f7d90ff10cefcf53e42c085cf5576e57974b3e88c027","spendHash":"0xcc8fe4abbc3505c4d80de9f6f1abca55fafdc60f815b4e2a2efecda6a212fa81","checkpoints":"1","grantNonce":"1"} +{"name":"extended-index-race-error","at":"2026-10-14T17:11:29.972Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","code":"INDEX_RACE","expectedWallet":"0x428Da4EF457EddE0b8614AAF2f7Bc4350978da43","expectedIndex":30,"competingWallet":"0x428Da4EF457EddE0b8614AAF2f7Bc4350978da43","competingIndex":30,"nextAfterRace":{"address":"0xba83f372168De8Eb81A64A1411f1C4E52E503bf8","index":31,"deployed":false},"competingRuleIds":[]} +{"name":"extended-index-race","at":"2026-10-14T17:11:38.125Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","competing":"0x428Da4EF457EddE0b8614AAF2f7Bc4350978da43","winnerHash":"0x4218540c0e38f3f6061a97a5247ece7b9541c87810b570935f2e70ee0f7fe599","retried":"0xba83f372168De8Eb81A64A1411f1C4E52E503bf8","retryHash":"0x88d077426f499e353d658cb21298dce713d50233cb0ccde1262ac286353d6cc9"} +{"name":"v5-label-default-custom","at":"2026-10-14T17:12:54.736Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallets":["0x11FDAdc91A21A3517918933b6e7a5d12f8f48d07","0x40d240472D84C4Dc9aBF59bd78f453e36A7B5383"],"indices":[32,33],"hashes":["0x5468ae1d43628be65295604c7d4582da2a43c7ac64d92a30cec2d3d4d712cb44","0x75467af99fece5e4c3f3cb6868567b695dcd0e095c43f103b405813d38e0ccda","0xa7dd7031dc6245b207976c0aa32e64b233aa288691a445902c9eda0d716c672e"]} +{"name":"v5-label-rename-reset","at":"2026-10-14T17:13:53.872Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0xBf42e7f8bC1dBfCE9B336Dc2A84Cc1f038dc3B44","hashes":["0x2717e4e89cd60697f2f9c8a03ebcf19978b5e7b5e015e7d3cf70af3276c653cf","0xc80b948b2fc91655c837a043304bcca82ab413dcd16b6cffd48fa2b60113117f"],"checkpointsBefore":"0","checkpointsAfter":"0"} +{"name":"v5-label-byte-boundary","at":"2026-10-14T17:14:17.844Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0xFFCfC433ad7a2ba6197486Fb774167734eEBa60d","checkpoints":"0","unchangedNextSlot":36} +{"name":"v5-label-agent-refused","at":"2026-10-14T17:14:32.557Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0xfef6F2579b3Fcd9BAE58A6bd55bAC32933d4b304","checkpoints":"1"} +{"name":"v5-label-uea-owner","at":"2026-10-14T17:15:18.020Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0xAb274a2FBde5C4A09dc3747e58bfCcf75d2Ade4D","owner":"0x5C70C864Cf1aDfB04A0e107fFA248ba3600EAb8D","hashes":["0x5744264def139db50f03437d6e3951badb3fc14395266f96e0770650bea3eb41","0x14819bd1ef8a2ac7e1b5a38438c3cf1718fac47ffaae4c5ed47eb9e7d17df38c","0xe82c825a3a848942b46367908603ed5a1711cc1d4cb62a808a7c78d9d75e51b9"],"checkpointsBefore":"0","checkpointsAfter":"0"} +{"name":"v5-label-solana-owner","at":"2026-10-14T17:16:03.012Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0x150db120b9AadC0dDC24DF6caD1c7E3be3510dCc","owner":"0xad977a75D8BEd06579D6498b7e2e3885f9D31F15","hashes":["0xe7871b5ee6cdac7ca98dee2817bdd8b1ba0c7de1ce1408bad67370722896a11d","0x8d732aac28c063947a848d665355ce9de236cfd4f6fed149274e8e985cd8c1ca","0x7989abcb6fa97372cdfadfe71bfb9e4445d95b71a8d23ef257c0f6af034bdc8e"],"checkpointsBefore":"0","checkpointsAfter":"0"} +{"name":"v5-label-active-rule","at":"2026-10-14T17:16:42.715Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0xB861e7c09FF35A64EdfA7D827e7890B21B36877A","rulesId":"0x1d364d52ece1da8c459536d60b75373414df4b991bc1154f12fd9144945c4f1a","hashes":["0xf09c3cf1774dc1a1f8b684c7d8abb2c9ad110f67160c30a308f4072731c4fd72","0x288f363bbed201ac8df1a2b6a609fa0d61289c113f4512dddc7fbe61c9ecad81","0x216ad61c5257956b2ddf2a14d317d74528bae42acf1a89e46e81fc565b3dcba4"],"spendBefore":{"valueSpent":"1","amountSpent":"0","callsUsed":1},"spendAfter":{"valueSpent":"2","amountSpent":"0","callsUsed":2},"grantNonce":"1"} +{"name":"v5-label-batch-rollback","at":"2026-10-14T17:16:58.692Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0xAF902Ed9cA1036C13f2139A5074e74849Fd2858a","hash":"0x3a5c64dc4c1f11f035ace3f4e9038d95d085a764fb5cc8cc6dd5209c79576149","block":"24246078","gasUsed":"200000","status":"reverted","checkpoints":"0"} +{"name":"public-svm-setup","at":"2026-10-14T17:17:51.199Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0x6E06058B79298809Ef569688665D9BBc0b11EBb0","id":"0xda6c57920b1bf16489d7ce8ce624a3bc579cf94bef00147e9962b177754c16b6","grantHash":"0x7184227e2d4fecec193ab7ec3e90a550987afd282d52cf9e9e165b0bf6be80f5","cea":"8eWvD3yyyqtATfcG1Chu9amdPjkjxteM3Pfv9RWpPAVP","recipient":"3nK8X1re4zLNrgz9Y3xKS4g2fKPJ6M3N9BhNuFfkjwAb"} +{"name":"public-svm-replacement","at":"2026-10-14T17:18:26.070Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0x6E06058B79298809Ef569688665D9BBc0b11EBb0","id":"0x9824d3bb23f029e1169e62924f5b3e6f499a59852464f8d786c5494923883249","txHash":"0x042dd1c81c8b34605d8f2244c14486e0a1bf3c02b254dfdb5b384b22da003ee9"} +{"name":"public-svm-submitted","at":"2026-10-14T17:18:44.774Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0x6E06058B79298809Ef569688665D9BBc0b11EBb0","id":"0x9824d3bb23f029e1169e62924f5b3e6f499a59852464f8d786c5494923883249","hash":"0xfe8517761ba29ce7a8707c6e24110f75466de044d0ff7a1d321c15fba8bd83d9"} +{"name":"public-svm-delivered","at":"2026-10-14T17:19:59.542Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0x6E06058B79298809Ef569688665D9BBc0b11EBb0","hash":"0xfe8517761ba29ce7a8707c6e24110f75466de044d0ff7a1d321c15fba8bd83d9","destinationHash":"3CanzkSEvZvaVPUZ6s2Bpiu143VAo9hPaV6JhvB7FXA6iGgMoThSzthqvNbMbQ4vJmFmkMGD1RxryJCpTQLYcRxd","instruction":{"program":"0x7673075a980bfd5d6b1dffe99c31f63e8938519cc1c2af009dda5e568a94460d","data":"0x79f4fa0308e5e1011027000000000000","accounts":[{"pubkey":"0x4f12fe6816ae7e33ebf7db0b154ec3b09e3bf1a7690481e8e9477d5a278ad3af","isWritable":true},{"pubkey":"0x2953026d328218b107268efe60f7d98635af1ff535a91731f75ca7cf8a859044","isWritable":true},{"pubkey":"0x719e204864e24f8ff1328cb460054042fd086f2f60ac2de6ff3ea87cd5313832","isWritable":true},{"pubkey":"0x0000000000000000000000000000000000000000000000000000000000000000","isWritable":false}]}} +{"name":"public-svm-contract-refusals","at":"2026-10-14T17:20:19.674Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0x6E06058B79298809Ef569688665D9BBc0b11EBb0","id":"0x9824d3bb23f029e1169e62924f5b3e6f499a59852464f8d786c5494923883249","agentNonce":1,"state":{"tokens":"10000","pcBalance":"40369379053802732985","checkpoints":"6","spent":["10000"]}} +{"name":"public-svm-owner-transfer-submitted","at":"2026-10-14T17:20:35.876Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0x6E06058B79298809Ef569688665D9BBc0b11EBb0","hash":"0x5a70c8adfe4794d9ad73e2fb5ccb63b83ae9030a7811a3161f56a39e9d5e2579"} +{"name":"public-svm-owner-transfer-delivered","at":"2026-10-14T17:22:01.645Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0x6E06058B79298809Ef569688665D9BBc0b11EBb0","hash":"0x5a70c8adfe4794d9ad73e2fb5ccb63b83ae9030a7811a3161f56a39e9d5e2579","destinationHash":"24bmc4nPZEb9nMgjxvKfqT2VkMR4XWUz53Pun1MQEyq6BNaefinDihHCE2zQHC8pJFVAZkeyqNxb9Hiheek6gbFD","recipient":"3nK8X1re4zLNrgz9Y3xKS4g2fKPJ6M3N9BhNuFfkjwAb","amount":"10000"} +{"name":"external-evm-agent","at":"2026-10-14T17:22:46.189Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0x330aBe95F0DeA143b067631374795819Aa1c3910","uea":"0x5C70C864Cf1aDfB04A0e107fFA248ba3600EAb8D","tx":"0xc2723059f4e0a3de057631c1ded4697ccd184db971e231fa2a98000eaf069e4f"} +{"name":"first-use-uea","at":"2026-10-14T17:24:10.528Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0xC3571ff8B1F3F3Bf9862CCD9A09C200d3cc94623","uea":"0x29470B9702a26e5c5060d24638FC5A12FC5a81Ba"} +{"name":"solana-origin-agent","at":"2026-10-14T17:24:35.339Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0x12443e7C7F10791c241B38b40039b10dBb47DD3a","uea":"0xad977a75D8BEd06579D6498b7e2e3885f9D31F15","tx":"0xcbf1bb01d3cba0e0105acfa7128c66daf1036f72cee3659ab51256085f0c3c39"} +{"name":"native-agent-send","at":"2026-10-14T17:25:17.158Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0x37c88d8732178682A4bf138C07934a8f3b70B8eA","rulesId":"0x03cc1333a63a1c513f98e81080a0532e7e9d948f2b06c67749e613bc260022e9","tx":"0x197d020fe896edf5d5a7da04d39a33395fa9ad9d6c9d4bc64bd7d0786a671639","block":"24246281"} +{"name":"rules-update","at":"2026-10-14T17:28:13.844Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0x6a22C60A39248e2Fd49Ad18757C87CC4277440ca","original":"0xe45739dfb0771a6a94648358bcab961c3f83eb2bfd711c9fca0254b77a40c74c","replacement":"0x94947d387575199262c3655b1ab1720b52d71abb826e465a0b7b60d97836fc54","tx":"0x440d08535e855ae3febaefcfaf4bbe687d2d51149bbfc3b7bb38ff9647eead5f","checkpointDelta":5} +{"name":"v5-spl-owner-submitted","at":"2026-10-14T17:29:25.025Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0x5530fA3f314e4367bDF873201328A3Bee7b2Feba","hash":"0x0b2808d0b8787913fd8261e4d17410a3c3fc0c8013ab812f148d84a106f52dfa","mint":"EiXDnrAg9ea2Q6vEPV7E5TpTU1vh41jcuZqKjU5Dc4ZF","recipient":"3nK8X1re4zLNrgz9Y3xKS4g2fKPJ6M3N9BhNuFfkjwAb","ata":"oVL4eb7hqoq4iJEZ4mPf9Hgd5ys3EzaXuCpZ434aRRt","amount":"1000"} +{"name":"v5-spl-owner-delivered","at":"2026-10-14T17:30:44.797Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0x5530fA3f314e4367bDF873201328A3Bee7b2Feba","hash":"0x0b2808d0b8787913fd8261e4d17410a3c3fc0c8013ab812f148d84a106f52dfa","destinationHash":"4z7yVHikN2qJRzyGo5ockPTm1bDKzEaYwRzyogN4MqJHpdWbPGQV9VTHM8Ke1HofN5rVhF1ZPR6rVekS7UvrPKve","mint":"EiXDnrAg9ea2Q6vEPV7E5TpTU1vh41jcuZqKjU5Dc4ZF","recipient":"3nK8X1re4zLNrgz9Y3xKS4g2fKPJ6M3N9BhNuFfkjwAb","ata":"oVL4eb7hqoq4iJEZ4mPf9Hgd5ys3EzaXuCpZ434aRRt","beforeRecipient":"9995961000","afterRecipient":"9995962000","amount":"1000"} +{"name":"native-agent-batch","at":"2026-10-14T17:31:40.717Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0x402cd8068544D0E8Ca13db79E3E322d0EA7e8f9C","rulesId":"0x168c9ebc4bb966134b6d4bc58b3bc038397b6c1609649420d26dcc760cfc424c","tx":"0xf6c020959e9e33c1d698ffd2bf34a3e5b6c9f4c48039751d2d82ab4bf1e6e3b6"} +{"name":"native-agent-batch-rollback","at":"2026-10-14T17:32:00.105Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0x9fC6D013Da51428f08dc4De8B2B180DDcF14b0c9","rulesId":"0x168c9ebc4bb966134b6d4bc58b3bc038397b6c1609649420d26dcc760cfc424c"} +{"name":"replay-identity","at":"2026-10-14T17:33:05.566Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0x61e8289223D6B967FC3aC6Ea919c9D7A014fFD04","tx":"0xf8d31a7f2272eca1b10df8bade300912dbfd79c8350e5d38317f7d104bae3b67"} +{"name":"allowance-set-remove","at":"2026-10-14T17:33:50.023Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0xdfa15781a7a253CcAc2E3192931508A2557bACa7","token":"0x2971824Db68229D087931155C2b8bB820B275809","setTx":"0xe3a9bd6325780b10ec8d67e29d302428b7c33a24489dc43127e0159744977c54"} +{"name":"create-bare","at":"2026-10-14T17:34:09.116Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0x1331bF8F04380C893D130084508f3533c81bBca4","index":51,"tx":"0xd40ac44eddfe90bd46fb92b6880a08a59c43c562acd3ed7c5b658f77439aa48e","block":"24246497"} +{"name":"create-with-rule","at":"2026-10-14T17:34:18.700Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0x8c3fAAe149ee3060185fc2fc6A50EEbE067A70c7","rulesIds":["0xc59909d53d2ebb62c1e7ccb37e9cfaba79ac3ba8b673ab465a1320decc8b0331"],"tx":"0x16f7b0d3514819b8278e7d88c7aae1599bf109638939fbe55bdcca0bdf6f9f19","atomic":true} +{"name":"v5-budget-outbound-submitted","at":"2026-10-14T17:36:25.869Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0x2eA13407476639AdEC0ff340862AF7A817395d82","rulesId":"0x324f8363f716ee40f1df59b6d6efc19db18721d6ca4005165770f06e080cea2c","token":"0x2971824Db68229D087931155C2b8bB820B275809","amount":"1000000000000","pushTx":"0x153464b0c2a9b9da777b65ba55ba69735818d1dae156c6b5651bb0ec0424d8a5"} +{"name":"v5-budget-outbound-submitted","at":"2026-10-14T17:37:41.138Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0x2eA13407476639AdEC0ff340862AF7A817395d82","rulesId":"0x324f8363f716ee40f1df59b6d6efc19db18721d6ca4005165770f06e080cea2c","token":"0x7A58048036206bB898008b5bBDA85697DB1e5d66","amount":"10","pushTx":"0x793401f5e845388a47b2dc28b2c2ae9e707157fbda41a5f813e59230f8c6d7ed"} +{"name":"v5-independent-token-budgets","at":"2026-10-14T17:38:44.322Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0x2eA13407476639AdEC0ff340862AF7A817395d82","rulesId":"0x324f8363f716ee40f1df59b6d6efc19db18721d6ca4005165770f06e080cea2c","tokens":["0x2971824Db68229D087931155C2b8bB820B275809","0x7A58048036206bB898008b5bBDA85697DB1e5d66"],"amounts":["1000000000000","10"],"spent":["1000000000000","10"],"hashes":["0x153464b0c2a9b9da777b65ba55ba69735818d1dae156c6b5651bb0ec0424d8a5","0x644cb0d7072bf63857eb4bf1f321cc2fefcad8bcf759f631cb4ad64d8280b097","0x793401f5e845388a47b2dc28b2c2ae9e707157fbda41a5f813e59230f8c6d7ed","0x68c1eb1a6a9d6ac3855e8da8833ecc43c9d40d2bd0ee750ae7a6f41e39298b1c"]} +{"name":"v6-destination-pins","at":"2026-10-14T17:41:06.039Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0xa3318B98f3B277DFc1Fde1a62A704cF24Ca1415c","cea":"0xb33ab2369F991e093BD27cd02A4bf320c1EF67CA","rulesId":"0x0e81cb2d53fb7bdad6c1444d31bb9a94dcefd20a64db53c8279e14427eac90fa","pushTx":"0x8d2c2ed5885b0c707f2f791a31d362040684b9b36eac92b6371b05b9400d2281","destinationTx":"0xa7a7f1d456a8b414c9864b0e556920383b3042b2efb3ccc93990f3ee0b6dc9cf"} diff --git a/plan/agw/research/v6-integration-2026-10-14/live-focused.log b/plan/agw/research/v6-integration-2026-10-14/live-focused.log new file mode 100644 index 00000000..9f4f3498 --- /dev/null +++ b/plan/agw/research/v6-integration-2026-10-14/live-focused.log @@ -0,0 +1,41 @@ +PASS core-e2e packages/core/__e2e__/agw/v5-multiasset.spec.ts (225.533 s) + ● Console + + console.log + [ExternalTxVerifier] Verifying EVM tx on eip155:11155111: 0x644cb0d7072bf63857eb4bf1f321cc2fefcad8bcf759f631cb4ad64d8280b097 + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [ExternalTxVerifier] EVM tx 0x644cb0d7072bf63857eb4bf1f321cc2fefcad8bcf759f631cb4ad64d8280b097 on eip155:11155111: status=0x1 + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [ExternalTxVerifier] EVM tx CONFIRMED SUCCESS on eip155:11155111 + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [ExternalTxVerifier] Verifying EVM tx on eip155:11155111: 0x68c1eb1a6a9d6ac3855e8da8833ecc43c9d40d2bd0ee750ae7a6f41e39298b1c + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [ExternalTxVerifier] EVM tx 0x68c1eb1a6a9d6ac3855e8da8833ecc43c9d40d2bd0ee750ae7a6f41e39298b1c on eip155:11155111: status=0x1 + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [ExternalTxVerifier] EVM tx CONFIRMED SUCCESS on eip155:11155111 + + at console.log (__e2e__/shared/logger.ts:42:5) + +PASS core-e2e packages/core/__e2e__/agw/universal-evm.spec.ts (141.71 s) + +Test Suites: 2 passed, 2 total +Tests: 4 skipped, 2 passed, 6 total +Snapshots: 0 total +Time: 367.291 s, estimated 505 s +Ran all test suites within paths "packages/core/__e2e__/agw/v5-multiasset.spec.ts", "packages/core/__e2e__/agw/universal-evm.spec.ts". +Force exiting Jest: Have you considered using `--detectOpenHandles` to detect async operations that kept running after all tests finished? diff --git a/plan/agw/research/v6-integration-2026-10-14/live-full.log b/plan/agw/research/v6-integration-2026-10-14/live-full.log new file mode 100644 index 00000000..7b76feb9 --- /dev/null +++ b/plan/agw/research/v6-integration-2026-10-14/live-full.log @@ -0,0 +1,262 @@ +Running 68 scenarios (group: agw) across 15 spec files. + +PASS core-e2e __e2e__/agw/native-multi-action.spec.ts (508.98 s) +FAIL core-e2e __e2e__/agw/v5-multiasset.spec.ts (260.148 s) + ● Console + + console.log + [ExternalTxVerifier] Verifying EVM tx on eip155:11155111: 0x688f7b1f1e0fd9b9f4980e7373d4bbf33115639dfa3a9bc55ab62c4cb916d879 + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [ExternalTxVerifier] EVM tx 0x688f7b1f1e0fd9b9f4980e7373d4bbf33115639dfa3a9bc55ab62c4cb916d879 on eip155:11155111: status=0x1 + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [ExternalTxVerifier] EVM tx CONFIRMED SUCCESS on eip155:11155111 + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [ExternalTxVerifier] Verifying EVM tx on eip155:11155111: 0x393204e3277d38d6d32b483e28ace107e77ff250a5f01069b8567b9ae9bff9a6 + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [ExternalTxVerifier] EVM tx 0x393204e3277d38d6d32b483e28ace107e77ff250a5f01069b8567b9ae9bff9a6 on eip155:11155111: status=0x1 + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [ExternalTxVerifier] EVM tx CONFIRMED SUCCESS on eip155:11155111 + + at console.log (__e2e__/shared/logger.ts:42:5) + + ● agw v5 multi-asset › 3. both assets execute independently after one token budget is exhausted + + expect(received).toBe(expected) // Object.is equality + + Expected: 1n + Received: 0n + + 322 | args: [made.wallet, f.manifest.addresses.gateway], + 323 | }) + > 324 | ).toBe(BigInt(1)); + | ^ + 325 | const expected = i === 0 ? [amounts[0], BigInt(0)] : amounts; + 326 | expect(await spent()).toEqual(expected); + 327 | const nonce = await f.push.getTransactionCount({ + + at Object. (__e2e__/agw/v5-multiasset.spec.ts:324:9) + +PASS core-e2e __e2e__/agw/native-policy-extended.spec.ts (342.326 s) +PASS core-e2e __e2e__/agw/universal-evm.spec.ts (243.886 s) + ● Console + + console.log + [ExternalTxVerifier] Verifying EVM tx on eip155:11155111: 0x95d0ceef78c3ed71940a51aa89a7d21ab5e26e3beef6a1af4f17bf9da90c4a82 + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [ExternalTxVerifier] EVM tx 0x95d0ceef78c3ed71940a51aa89a7d21ab5e26e3beef6a1af4f17bf9da90c4a82 on eip155:11155111: status=0x1 + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [ExternalTxVerifier] EVM tx CONFIRMED SUCCESS on eip155:11155111 + + at console.log (__e2e__/shared/logger.ts:42:5) + +PASS core-e2e __e2e__/agw/management-extended.spec.ts (189.914 s) +PASS core-e2e __e2e__/agw/labels.spec.ts (320.545 s) +PASS core-e2e __e2e__/agw/svm-public.spec.ts (303.803 s) +PASS core-e2e __e2e__/agw/identity-gas.spec.ts (152.794 s) + ● Console + + console.log + [4.00s] AGENTIC-TX-107: Rule Resolved + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [4.01s] SEND-TX-101: Origin Chain Detected + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [4.02s] SEND-TX-102-01: Estimating Gas + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [4.33s] SEND-TX-103-01: Resolving Universal Execution Account + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [4.63s] SEND-TX-103-02: Universal Execution Account Resolved + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [4.63s] SEND-TX-103-03-04: Prepaid Deposit Estimated + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [6.57s] SEND-TX-104-01: Awaiting Transaction + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [7.79s] SEND-TX-105-01: Gas Funding In Progress + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [17.35s] SEND-TX-105-02: Gas Funding Confirmed + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [17.35s] SEND-TX-107: Broadcasting to Push Chain + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [48.56s] SEND-TX-199-01: Push Chain Tx Success + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [48.56s] AGENTIC-TX-199-01: Agentic Operation Done + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [50.63s] AGENTIC-TX-107: Rule Resolved + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [1.21s] AGENTIC-TX-107: Rule Resolved + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [50.63s] SEND-TX-101: Origin Chain Detected + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [1.21s] SEND-TX-101: Origin Chain Detected + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [50.63s] SEND-TX-102-01: Estimating Gas + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [1.21s] SEND-TX-102-01: Estimating Gas + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [50.92s] SEND-TX-103-01: Resolving Universal Execution Account + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [1.50s] SEND-TX-103-01: Resolving Universal Execution Account + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [51.51s] SEND-TX-103-02: Universal Execution Account Resolved + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [2.09s] SEND-TX-103-02: Universal Execution Account Resolved + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [51.51s] SEND-TX-103-03-04: Prepaid Deposit Estimated + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [2.09s] SEND-TX-103-03-04: Prepaid Deposit Estimated + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [52.14s] SEND-TX-104-02: Awaiting Signature + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [2.72s] SEND-TX-104-02: Awaiting Signature + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [52.15s] SEND-TX-104-03: Verification Success + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [2.73s] SEND-TX-104-03: Verification Success + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [52.15s] SEND-TX-107: Broadcasting to Push Chain + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [2.73s] SEND-TX-107: Broadcasting to Push Chain + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [59.21s] SEND-TX-199-01: Push Chain Tx Success + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [9.79s] SEND-TX-199-01: Push Chain Tx Success + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [59.21s] AGENTIC-TX-199-01: Agentic Operation Done + + at console.log (__e2e__/shared/logger.ts:42:5) + + console.log + [9.79s] AGENTIC-TX-199-01: Agentic Operation Done + + at console.log (__e2e__/shared/logger.ts:42:5) + +PASS core-e2e __e2e__/agw/native-exec.spec.ts (149.925 s) +PASS core-e2e __e2e__/agw/lifecycle.spec.ts (91.985 s) +PASS core-e2e __e2e__/agw/svm-spl-transfer.spec.ts (127.507 s) +PASS core-e2e __e2e__/agw/native-batch.spec.ts (75.302 s) +PASS core-e2e __e2e__/agw/responses-hooks.spec.ts (65.453 s) +PASS core-e2e __e2e__/agw/funding-allowance.spec.ts (44.439 s) +PASS core-e2e __e2e__/agw/create.spec.ts (28.674 s) + +Test Suites: 1 failed, 14 passed, 15 total +Tests: 1 failed, 1 skipped, 67 passed, 69 total +Snapshots: 0 total +Time: 2905.962 s +Ran all test suites within paths "__e2e__/agw/create.spec.ts", "__e2e__/agw/funding-allowance.spec.ts", "__e2e__/agw/native-batch.spec.ts", "__e2e__/agw/native-exec.spec.ts", "__e2e__/agw/lifecycle.spec.ts", "__e2e__/agw/universal-evm.spec.ts", "__e2e__/agw/v5-multiasset.spec.ts", "__e2e__/agw/identity-gas.spec.ts", "__e2e__/agw/responses-hooks.spec.ts", "__e2e__/agw/svm-public.spec.ts", "__e2e__/agw/labels.spec.ts", "__e2e__/agw/svm-spl-transfer.spec.ts", "__e2e__/agw/native-multi-action.spec.ts", "__e2e__/agw/management-extended.spec.ts", "__e2e__/agw/native-policy-extended.spec.ts". +Force exiting Jest: Have you considered using `--detectOpenHandles` to detect async operations that kept running after all tests finished? diff --git a/plan/agw/research/v6-integration-2026-10-14/local-contracts.log b/plan/agw/research/v6-integration-2026-10-14/local-contracts.log new file mode 100644 index 00000000..d7de7eb1 --- /dev/null +++ b/plan/agw/research/v6-integration-2026-10-14/local-contracts.log @@ -0,0 +1,31 @@ +PASS core-agw-local packages/core/__agw-local__/svm-backend.spec.ts (11.046 s) +PASS core-agw-local packages/core/__agw-local__/agw-local-advanced.spec.ts +PASS core-agw-local packages/core/__agw-local__/svm-differential.spec.ts + ● Console + + console.log + {"corpus":"svm-grant","seed":23063,"cases":107,"accepted":37,"rejected":70,"mismatches":[]} + + at Object. (__agw-local__/svm-differential.spec.ts:226:13) + + console.log + {"corpus":"svm-payload","seed":23063,"cases":88,"accepted":6,"rejected":82,"mismatches":[]} + + at Object. (__agw-local__/svm-differential.spec.ts:407:13) + +PASS core-agw-local packages/core/__agw-local__/svm-internals.spec.ts +PASS core-agw-local packages/core/__agw-local__/svm-public.spec.ts +PASS core-agw-local packages/core/__agw-local__/v5-multiasset.spec.ts +PASS core-agw-local packages/core/__agw-local__/labels.spec.ts +PASS core-agw-local packages/core/__agw-local__/native-multi-action.spec.ts +PASS core-agw-local packages/core/__agw-local__/delayed-index.spec.ts +PASS core-agw-local packages/core/__agw-local__/agw-local.spec.ts +PASS core-agw-local packages/core/__agw-local__/agw-local-batch.spec.ts +PASS core-agw-local packages/core/__agw-local__/vectors.spec.ts +PASS core-agw-local packages/core/__agw-local__/agw-local-races.spec.ts + +Test Suites: 13 passed, 13 total +Tests: 99 passed, 99 total +Snapshots: 0 total +Time: 36.253 s +Ran all test suites. diff --git a/plan/agw/research/v6-integration-2026-10-14/manifest-surface-check.log b/plan/agw/research/v6-integration-2026-10-14/manifest-surface-check.log new file mode 100644 index 00000000..77708181 --- /dev/null +++ b/plan/agw/research/v6-integration-2026-10-14/manifest-surface-check.log @@ -0,0 +1 @@ +v6 manifest and initializer selector verified diff --git a/plan/agw/research/v6-integration-2026-10-14/package.log b/plan/agw/research/v6-integration-2026-10-14/package.log new file mode 100644 index 00000000..8e1b97e4 --- /dev/null +++ b/plan/agw/research/v6-integration-2026-10-14/package.log @@ -0,0 +1 @@ +AGW package: CJS/ESM imports, compiled declaration examples and npm contents pass. No examples executed/published. diff --git a/plan/agw/research/v6-integration-2026-10-14/preflight.log b/plan/agw/research/v6-integration-2026-10-14/preflight.log new file mode 100644 index 00000000..1e3c6a1f --- /dev/null +++ b/plan/agw/research/v6-integration-2026-10-14/preflight.log @@ -0,0 +1,27 @@ +AGW deployment manifest verified on-chain. +Solana wire fixture verified read-only before funding. + +Wallets + EVM master (Sepolia) 0x0A16CBa65FfCAa4C2282b27b027Ab4A2fE46E0Bf + Push master (Donut) 0x0A16CBa65FfCAa4C2282b27b027Ab4A2fE46E0Bf + Solana master (Devnet) 3nK8X1re4zLNrgz9Y3xKS4g2fKPJ6M3N9BhNuFfkjwAb + Shared UEA (Donut) 0x5C70C864Cf1aDfB04A0e107fFA248ba3600EAb8D + UEA CEA PDA (Devnet) Fqp8UeJxEWvN1Ciu5jqrA3opGXwNvRL2HfJxNQotj3Qh + +Group "agw" — 68 scenarios, headroom ×1.25. + +┌────────────────────────┬───────────┬──────────┬─────────────┬────────┐ +│ Scope │ Asset │ Need │ Have │ Status │ +├────────────────────────┼───────────┼──────────┼─────────────┼────────┤ +│ EVM master (Sepolia) │ ETH │ 0.027500 │ 3.8342 │ ✓ │ +│ Push master (Donut) │ PC │ 601.3125 │ 969371.7410 │ ✓ │ +│ Push master (Donut) │ pETH │ 0.000014 │ 434.3115 │ ✓ │ +│ Push master (Donut) │ pSOL │ 0.000150 │ 5.7689 │ ✓ │ +│ Push master (Donut) │ pUSDT.sol │ 0.001250 │ 10006.8139 │ ✓ │ +│ Push master (Donut) │ pUSDC.eth │ 0.000014 │ 44642.9076 │ ✓ │ +│ Solana master (Devnet) │ SOL │ 0.013750 │ 0.615431 │ ✓ │ +│ UEA (Donut) │ PC │ 15.0000 │ 6196.4993 │ ✓ │ +└────────────────────────┴───────────┴──────────┴─────────────┴────────┘ + +All master wallets can cover this run. +Derived accounts are already at target. Ready to run. diff --git a/plan/agw/research/v6-integration-2026-10-14/preset-unit.log b/plan/agw/research/v6-integration-2026-10-14/preset-unit.log new file mode 100644 index 00000000..773f3a1f --- /dev/null +++ b/plan/agw/research/v6-integration-2026-10-14/preset-unit.log @@ -0,0 +1,28 @@ +PASS core packages/core/src/lib/agentic/__tests__/presets.spec.ts + ✓ exposes enumerable frozen categories with no invented production addresses (5 ms) + ✓ groups all apps on a chain into one editable template and omits unspecified fields (1 ms) + ✓ returns ready Rule types with identity and expiry; routes assets and defaults missing caps to zero + ✓ does not type an incomplete template as a ready rule + ✓ adds only spender-pinned and amount-bounded ERC20 approvals; native assets have none (1 ms) + ✓ does not mutate caller assets, returned records, or the bundled catalog + ✓ rejects malformed or mismatched options before returning templates (case 0) (1 ms) + ✓ rejects malformed or mismatched options before returning templates (case 1) + ✓ rejects malformed or mismatched options before returning templates (case 2) + ✓ rejects malformed or mismatched options before returning templates (case 3) (1 ms) + ✓ rejects malformed or mismatched options before returning templates (case 4) + ✓ rejects malformed or mismatched options before returning templates (case 5) + ✓ rejects malformed or mismatched options before returning templates (case 6) + ✓ rejects malformed or mismatched options before returning templates (case 7) + ✓ rejects malformed or mismatched options before returning templates (case 8) + ✓ rejects unknown presets, unsupported list types and unsupported chain filters + ✓ produces separate pinned alternatives for multiple spenders + ✓ enforces the 32-call ceiling including generated approvals (1 ms) + ✓ requires full signatures and rejects duplicate function entries + ✓ compiles preset spender and amount pins with the deployed v6 policy (1 ms) + ✓ keeps OR alternatives EVM-only: repeated Solana instructions are refused + +Test Suites: 1 passed, 1 total +Tests: 21 passed, 21 total +Snapshots: 0 total +Time: 2.312 s +Ran all test suites within paths "packages/core/src/lib/agentic/__tests__/presets.spec.ts". diff --git a/plan/agw/research/v6-integration-2026-10-14/proxy-library-wiring.json b/plan/agw/research/v6-integration-2026-10-14/proxy-library-wiring.json new file mode 100644 index 00000000..d4c2d5db --- /dev/null +++ b/plan/agw/research/v6-integration-2026-10-14/proxy-library-wiring.json @@ -0,0 +1,35 @@ +{ + "block": "24245415", + "references": [ + { + "file": "src/policies/SvmRulebook.sol", + "name": "SvmRulebook", + "address": "0x15c3259490f0625c75b5a00731e4231b2b529c1e", + "matches": true + }, + { + "file": "src/policies/SvmRulebook.sol", + "name": "SvmRulebook", + "address": "0x15c3259490f0625c75b5a00731e4231b2b529c1e", + "matches": true + }, + { + "file": "src/policies/SvmRulebook.sol", + "name": "SvmRulebook", + "address": "0x15c3259490f0625c75b5a00731e4231b2b529c1e", + "matches": true + } + ], + "proxies": [ + { + "proxy": "factoryProxy", + "implementation": "0x64893c611920604a9247530673071d46ac9174c9", + "matches": true + }, + { + "proxy": "urp", + "implementation": "0xa176b1424018d52711edcb9d3d8757dc6e174463", + "matches": true + } + ] +} diff --git a/plan/agw/research/v6-integration-2026-10-14/spec-typecheck.log b/plan/agw/research/v6-integration-2026-10-14/spec-typecheck.log new file mode 100644 index 00000000..e69de29b diff --git a/plan/agw/research/v6-integration-2026-10-14/status.md b/plan/agw/research/v6-integration-2026-10-14/status.md new file mode 100644 index 00000000..6fbfc9fc --- /dev/null +++ b/plan/agw/research/v6-integration-2026-10-14/status.md @@ -0,0 +1,25 @@ +# V6 SDK migration — completed locally + +Source pin: `ffd567d3e49b2d27c6f50ad36093274dbac3090f`; documentation head `e57998c2d8ef9db15e69a68061ad3101120a6c6c`. Factory/URP/wallet wiring and nine bytecode sizes were checked on Donut at block 24244801. Executable runtimes of factory logic, wallet, URP, engine, validator and SvmRulebook match the isolated source build after excluding metadata and constructor/link slots (block 24245374); [comparison](bytecode-comparison.json). Both proxy implementation slots and all three URP SvmRulebook link slots independently match the address book at block 24245415 ([wiring](proxy-library-wiring.json)). This is not a full audit or a claim that all constructor bytes were compared byte-for-byte. + +## Implemented locally + +- Replace the v5 runtime, ABI snapshots and deployment constants with v6; no legacy fallback. +- One index-bound createWalletWithSig call with the documented owner empty-signature path. Both index and predicted wallet are checked; up to eight initial rules. Rollback is atomic. Remove CREATE_PARTIAL; keep receipt-unavailable hash evidence. +- Remove allowance reads/requirements on owner and agent outbounds (EVM/SVM). Wallet performs the exact approval/cleanup. Remove GATEWAY_ALLOWANCE_INSUFFICIENT. Core response fields used outside AGW remain unchanged. +- Native and EVM pins encode (offset, op, value), including general EQ/MAX and multiple native MAX pins. Native maxCalls uses uint32 max. Solana unspecified account count uses 255. Native MAX pins do not increment the separate amountSpent meter. +- Multiple EVM entries for one target/selector are OR alternatives. Unpinned/pinned combinations are refused. Presets can now generate separate spender-pinned alternatives; approved app catalog remains empty. +- Include linked SvmRulebook error definitions with the policy ABI so nested revert names remain readable. +- Link the SvmRulebook in the isolated contract fixture. Regenerate contract-derived v6 vectors. +- Native call ceiling remains eight (not the spec's generic 32). Source still reports policy version 3.1.0, so address/wiring/source registration identifies the generation. + +## Validation so far + +- Full units: 2,073 passed, 12 skipped, zero failed. +- Real pinned contracts: 99 passed across 13 suites. Includes atomic initial-rule rollback, index race, zero-allowance send/cleanup, EVM alternative EQ/MAX constraints/read-update and Solana errors. +- Build, lib/spec/local typechecks, guide examples, built CJS/ESM imports and declaration/API comparison pass. +- Funded acceptance: **69 distinct scenarios have passing v6 coverage**. Original run selected 68: 67 passed and one stale allowance assertion failed. The corrected case and newly added EVM EQ/MAX alternative case both passed in the focused run. This is combined coverage, not one clean full invocation. [Full log](live-full.log), [focused log](live-focused.log), [structured results](validation.json), [transaction evidence](live-evidence.jsonl). +- Live proof includes one-call indexed creation, initial grants, owner/agent outbounds with automatic allowance handling, native/Solana execution, decoded-rule updates, zero defaults, concurrency rollback, and a real Sepolia Approval event through the second pinned EVM alternative. Wrong-spender and over-cap attempts fail before signing. +- A final remote recheck found the same deploy-agw head and no source difference from the pinned deployment ([recheck](head-recheck.json)). + +V6 code is committed locally on v4 (`7dca3f2a`) and v5 (`700a52a7`); planning stays on v4. Neither migration commit has been pushed. No real contracts were deployed by this work; local Anvil fixtures are isolated. Contract-owner testnet dry runs are still ongoing. diff --git a/plan/agw/research/v6-integration-2026-10-14/validation.json b/plan/agw/research/v6-integration-2026-10-14/validation.json new file mode 100644 index 00000000..0b77d136 --- /dev/null +++ b/plan/agw/research/v6-integration-2026-10-14/validation.json @@ -0,0 +1,42 @@ +{ + "completed_at": "2026-10-14T17:44:22.870452+00:00", + "source_commit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "unit": { + "passed": 2073, + "failed": 0, + "skipped": 12 + }, + "local_contracts": { + "passed": 99, + "failed": 0, + "suites": 13 + }, + "live_full": { + "selected": 68, + "passed": 67, + "failed": 1, + "filtered": 1, + "reason": "stale v5 expectation of leftover gateway allowance; v6 correctly cleared it to zero" + }, + "live_focused": { + "selected": 2, + "passed": 2, + "failed": 0, + "filtered": 4, + "cases": [ + "corrected multi-asset allowance/budget case", + "new v6 EVM EQ/MAX OR alternative case" + ] + }, + "distinct_live_cases_with_passing_coverage": 69, + "single_clean_full_run": false, + "build": "pass", + "typechecks": "lib/spec/agw-local pass", + "consumer_checks": "docs/package/API pass", + "committed": true, + "pushed": false, + "code_commits": { + "feat/agw-sdk-v4": "7dca3f2a", + "feat/agw-sdk-v5": "700a52a7" + } +} diff --git a/plan/agw/section7-presets.md b/plan/agw/section7-presets.md index 9e0be18a..a71270bd 100644 --- a/plan/agw/section7-presets.md +++ b/plan/agw/section7-presets.md @@ -17,9 +17,9 @@ Source: [SDK spec §7](https://app.notion.com/p/pushprotocol/5-SDK-AGW-3e9188aea - One rule per chain, chain filtering, identity/expiry propagation and asset placement; unknown/mismatched chains and duplicate assets fail. - Caller/caller-result mutation cannot modify the catalog or subsequent results. - Missing caps become 0; explicit uint256 values are retained and invalid values fail. -- Approvals for catalog-declared EVM spenders are pinned to that spender and bounded by maxPerCall. Native assets receive none. Conflicting spender entries or duplicate function entries fail rather than broadening permissions. +- Approvals for catalog-declared EVM spenders are pinned to that spender and bounded by maxPerCall. Native assets receive none. With the October 14 v6 migration, distinct spender entries are separate pinned alternatives; an unpinned alternative beside them is refused. - Full signatures and the 32-call ceiling (including approvals) are checked. Metadata app/label is display-only. -- Standard create/add capability checks still reject general destination pins on the old policy; presets cannot bypass contract-delivery gates. +- The October 14 v6 adapter supports general destination EQ/MAX pins. Presets use the same create/add validation and do not bypass policy checks. ## Remaining activation work From 0bb829d4c440636fe09c2f90a0c7b959fc5c726b Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Thu, 15 Oct 2026 07:07:11 +0530 Subject: [PATCH 37/68] feat(core): add verified testnet AGW preset templates --- packages/core/AGW.md | 34 ++- .../core/__agw-local__/v5-multiasset.spec.ts | 68 ++++++ .../agentic/__tests__/preset-catalog.spec.ts | 198 ++++++++++++++++++ .../src/lib/agentic/__tests__/presets.spec.ts | 38 ++-- .../lib/agentic/__tests__/public-rule.spec.ts | 7 +- .../core/src/lib/agentic/agentic.types.ts | 6 +- .../core/src/lib/agentic/codec/abi-layout.ts | 93 +++++++- packages/core/src/lib/agentic/constants.ts | 1 + packages/core/src/lib/agentic/index.ts | 1 + .../core/src/lib/agentic/presets/catalog.ts | 166 ++++++++++++++- .../core/src/lib/agentic/presets/index.ts | 92 +++++++- .../core/src/lib/agentic/presets/types.ts | 4 +- packages/core/src/lib/agentic/public-rule.ts | 31 +-- packages/core/src/lib/index.ts | 1 + 14 files changed, 671 insertions(+), 69 deletions(-) create mode 100644 packages/core/src/lib/agentic/__tests__/preset-catalog.spec.ts diff --git a/packages/core/AGW.md b/packages/core/AGW.md index 3a92f727..cb3106d7 100644 --- a/packages/core/AGW.md +++ b/packages/core/AGW.md @@ -87,7 +87,7 @@ On deployed v6, native rules allow at most **eight** calls, eight equality/maxim ## Pins and zero defaults -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. +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. `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. @@ -167,29 +167,41 @@ The wire encoder uses uint32 maximum for unlimited native calls and 255 for unsp ## Preset discovery and templates (section 7) -`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. +`PushChain.utils.agentic` contains `presets.list/get`. The categories are `AGENTIC.PRESETS.CATEGORY.DEXES`, `LENDING`, `STAKING` and `PREDICTION`. The catalog ships testnet templates only: + +- DEXES: Uniswap V3 on Sepolia, Base Sepolia and Arbitrum Sepolia; PancakeSwap V3 on BSC testnet. +- LENDING: Aave on the three Ethereum testnets above, Moonwell on Base Sepolia and Venus on BSC testnet. +- STAKING: EigenLayer deposits on Sepolia; withdrawals are not included. +- PREDICTION: no entries yet. Hide categories with empty `chains` lists. ```ts const { presets } = PushChain.utils.agentic.presets.list({ type: 'CATEGORY' }); const availablePresets = presets.filter(preset => preset.chains.length > 0); -const { rules: reviewTemplates } = PushChain.utils.agentic.presets.get( - PushChain.CONSTANTS.AGENTIC.PRESETS.CATEGORY.DEXES, -); -// Currently [], since there is no approved catalog. Never treat an empty result as an active preset. -function filledPreset(agent: Address) { +function filledPreset(agent: Address, tokenIn: Address, tokenOut: Address) { return PushChain.utils.agentic.presets.get( PushChain.CONSTANTS.AGENTIC.PRESETS.CATEGORY.DEXES, - { agent, validUntil: Math.floor(Date.now() / 1000) + 3600 }, + { + chainNamespace: 'eip155:11155111', + agent, + validUntil: Math.floor(Date.now() / 1000) + 3600, + maxGasPerCall: BigInt(10) ** BigInt(18), + assets: [ + { token: tokenIn, maxPerCall: BigInt(100), maxTotal: BigInt(1000) }, + { token: tokenOut, maxPerCall: BigInt(100), maxTotal: BigInt(1000) }, + ], + }, ).rules; } ``` -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. +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. 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. Omitted asset caps and `maxGasPerCall` default to zero. + +DEX templates require explicit ERC20 tokens for each selected chain. They expand ordered token pairs into exact-input and exact-output calls with token, wallet-recipient and input-amount pins. Missing tokens, 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]`. -Reviewed EVM catalog spenders generate approvals pinned to that spender and bounded by the asset's per-call cap. Native assets need no approval. Distinct spenders for the same token become separate fully pinned alternatives under v6; unrestricted alternatives are rejected. Presets do not sign, fetch app ABIs or modify wallets. +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. -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. +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. No mainnet templates, dynamic-path swaps, Solana protocol templates or unconfirmed deployments ship in this catalog. Local policy tests do not execute the destination protocols. ## Validation diff --git a/packages/core/__agw-local__/v5-multiasset.spec.ts b/packages/core/__agw-local__/v5-multiasset.spec.ts index 40659c47..36a33b9b 100644 --- a/packages/core/__agw-local__/v5-multiasset.spec.ts +++ b/packages/core/__agw-local__/v5-multiasset.spec.ts @@ -1,3 +1,4 @@ +import { agenticPresets } from '../src/lib/agentic/presets'; import { buildPresetApi } from '../src/lib/agentic/presets'; import { publicRules } from '../src/lib/agentic/public-rule'; /** Actual v6 AGW/URP/engine. Token/core/gateway and destination lookup are local fixtures; no bridge/TSS proof. */ @@ -228,6 +229,73 @@ describe('v6 multi-asset SDK management and execution', () => { expect(await owner.agentic.derive()).toEqual(before); }); + it('the shipped DEX catalog enforces tuple receiver/token/amount pins on actual v6 URP', async () => { + const { rules } = agenticPresets.get('DEXES', { + chainNamespace: CHAIN_NS, + agent: h.wallets[1].account!.address, + validUntil: Math.floor(Date.now() / 1000) + 3600, + maxGasPerCall: BigInt(10) ** BigInt(16), + assets: [ + { token: a, maxPerCall: BigInt(5), maxTotal: BigInt(20) }, + { token: b, maxPerCall: BigInt(7), maxTotal: BigInt(20) }, + ], + }); + const { wallet, id, agent } = await setup(rules[0]); + const router = rules[0].allowedCalls[0].target as Address; + const abi = parseAbi([ + 'function exactInputSingle((address tokenIn,address tokenOut,uint24 fee,address recipient,uint256 amountIn,uint256 amountOutMinimum,uint160 sqrtPriceLimitX96)) returns (uint256)', + ]); + const send = (recipient = CEA, input = a, amount = BigInt(5)) => + agent.universal.sendTransaction({ + to: { address: router, chain: CHAIN_NS }, + data: [ + { + to: router, + value: BigInt(0), + data: encodeFunctionData({ + abi, + functionName: 'exactInputSingle', + args: [ + { + tokenIn: input, + tokenOut: b, + fee: 3000, + recipient, + amountIn: amount, + amountOutMinimum: BigInt(0), + sqrtPriceLimitX96: BigInt(0), + }, + ], + }), + }, + ], + }); + await waitPush(send()); + await expect(send(DEST)).rejects.toMatchObject({ + decodedError: { name: 'PolicyCheckReverted(ArgPinMismatch)' }, + }); + await expect(send(CEA, DEST)).rejects.toMatchObject({ + decodedError: { name: 'PolicyCheckReverted(ArgPinMismatch)' }, + }); + await expect(send(CEA, a, BigInt(6))).rejects.toMatchObject({ + decodedError: { name: 'PolicyCheckReverted(ArgPinAboveMax)' }, + }); + const handle = owner.agentic.wallet(wallet), + record = await handle.rules.get(id); + const changed = await handle.rules.update({ + rules: [ + { + rulesId: id, + rule: { ...record.rule, validUntil: record.validUntil + 60 }, + }, + ], + }); + expect((await handle.rules.get(changed.rules[0].rulesId)).rule).toEqual({ + ...record.rule, + validUntil: record.validUntil + 60, + }); + }); + it('a fixture preset produces rules accepted by public create and enforced by real contracts', async () => { const presets = buildPresetApi([ { diff --git a/packages/core/src/lib/agentic/__tests__/preset-catalog.spec.ts b/packages/core/src/lib/agentic/__tests__/preset-catalog.spec.ts new file mode 100644 index 00000000..8e28e839 --- /dev/null +++ b/packages/core/src/lib/agentic/__tests__/preset-catalog.spec.ts @@ -0,0 +1,198 @@ +import { + encodeFunctionData, + parseAbi, + getAddress, + type Address, + type Hex, +} from 'viem'; +import { agenticPresets } from '../presets'; +import { AGENTIC } from '../constants'; +import { evmPinOffset, normalizePublicRule, publicRules } from '../public-rule'; +import { parseSelector } from '../codec/selectors'; +import type { Rule, UniversalRule } from '../agentic.types'; +import { FakeChain, ADDR } from './fake-chain'; +import { mockRuntime } from './mock-runtime'; +const tokenA = ADDR.target, + tokenB = ADDR.other; +const chain = 'eip155:11155111'; +const input: import('../presets/types').ReadyPresetOptions = { + chainNamespace: chain, + agent: ADDR.agent, + validUntil: 2_000_000_000, + maxGasPerCall: BigInt(1), + assets: [ + { token: tokenA, maxPerCall: BigInt(5), maxTotal: BigInt(10) }, + { token: tokenB, maxPerCall: BigInt(7), maxTotal: BigInt(14) }, + ], +}; +it('expands both token directions and exact-input/output with wallet and amount pins', () => { + const { rules } = agenticPresets.get('DEXES', input); + expect(rules).toHaveLength(1); + expect(rules[0].allowedCalls).toHaveLength(6); + const swaps = rules[0].allowedCalls.filter((c) => + c.selector.startsWith('exact') + ); + expect(swaps).toHaveLength(4); + expect(swaps[0].pins).toEqual([ + { arg: [0, 0], expected: tokenA }, + { arg: [0, 1], expected: tokenB }, + { arg: [0, 3], expected: AGENTIC.WALLET }, + { arg: [0, 4], max: BigInt(5) }, + ]); + expect(swaps[1].pins?.at(-1)).toEqual({ arg: [0, 5], max: BigInt(5) }); + expect(swaps[2].pins?.at(-1)).toEqual({ arg: [0, 4], max: BigInt(7) }); + expect( + rules[0].allowedCalls.reduce((n, c) => n + (c.pins?.length ?? 0), 0) + ).toBe(20); +}); +it('rejects native-token markers, omitted tokens and oversized pin expansion', () => { + expect(() => agenticPresets.get('DEXES', { ...input, assets: [] })).toThrow( + /two explicit/ + ); + expect(() => + agenticPresets.get('DEXES', { + ...input, + assets: [...input.assets!, { token: ADDR.owner }], + }) + ).toThrow(/32 pins/); + expect(() => + agenticPresets.get('DEXES', { + ...input, + assets: [ + { token: '0x0000000000000000000000000000000000000000' }, + input.assets![1], + ], + }) + ).toThrow(/ERC20/); +}); +it('defaults omitted caps to zero without introducing an unlimited approval', () => { + const r = agenticPresets.get('DEXES', { + ...input, + assets: [{ token: tokenA }, { token: tokenB }], + }).rules[0]; + expect( + r.assets?.every( + (a) => a.maxPerCall === BigInt(0) && a.maxTotal === BigInt(0) + ) + ).toBe(true); + expect( + r.allowedCalls.every((c) => c.pins?.some((p) => p.max === BigInt(0))) + ).toBe(true); +}); +it('scopes money-market approvals to their actual underlying token', () => { + const underlying = '0x4616975f7E6045FD9737e95bC527e9e14c727BD2' as Address; + const r = agenticPresets.get('LENDING', { + chainNamespace: 'eip155:84532', + assets: [{ token: underlying, maxPerCall: BigInt(2) }], + }).rules[0]; + const approvals = r.allowedCalls.filter( + (c) => c.selector === 'approve(address,uint256)' + ); + expect(approvals).toHaveLength(2); // Aave and mUSDbC, never the mWETH market. + expect(approvals.flatMap((c) => c.pins ?? [])).not.toContainEqual({ + arg: 0, + expected: getAddress('0x2F39a349A79492a70E152760ce7123A1933eCf28'), + }); +}); +it.each([ + 'eip155:11155111', + 'eip155:84532', + 'eip155:421614', + 'eip155:97', +] as const)( + 'normalizes every DEX call on %s to the exact ABI bytes', + async (chainNamespace) => { + const r = agenticPresets.get('DEXES', { ...input, chainNamespace }) + .rules[0]; + const rt = mockRuntime(new FakeChain()); + const out = (await normalizePublicRule( + publicRules([r])[0], + ADDR.owner, + rt + )) as UniversalRule; + const cea = getAddress( + (await rt.resolveCEA(ADDR.owner, chainNamespace as never)).cea + ); + for (const call of out.allowedCalls.filter((c) => + String(c.selector).startsWith('exact') + )) { + const pins = call.pins!; + const values = [ + `0x${pins[0].value.slice(-40)}`, + `0x${pins[1].value.slice(-40)}`, + 3000, + cea, + BigInt(1), + BigInt(1), + BigInt(0), + ] as const; + const data = encodeFunctionData({ + abi: parseAbi([`function ${call.selector}`] as string[]), + functionName: String(call.selector).split('(')[0], + args: [values], + }); + for (const pin of pins.filter((p) => p.op === 0)) + expect( + `0x${data.slice( + 2 + pin.offset * 2, + 2 + (pin.offset + 32) * 2 + )}`.toLowerCase() + ).toBe(pin.value.toLowerCase()); + expect(pins.map((p) => p.offset)).toEqual([ + 4, + 36, + 100, + String(call.selector).startsWith('exactInput') ? 132 : 164, + ]); + } + } +); +it('supports tuple/fixed-array positions but never descends into dynamic storage', () => { + const sig = + 'exchange(address[11],uint256[5][5],uint256,uint256,address[5],address)' as const; + expect(evmPinOffset(sig, 5)).toBe(4 + 43 * 32); + expect(evmPinOffset(sig, [0, 0])).toBe(4); + expect(evmPinOffset(sig, [1, 2, 3])).toBe(4 + 24 * 32); + expect(evmPinOffset('f((address,address,uint256))', [0, 1])).toBe(36); + expect(() => evmPinOffset('f((bytes,address))', [0, 1])).toThrow(/dynamic/); + expect(() => evmPinOffset('f(address[])', [0, 0])).toThrow(/dynamic/); + expect(() => evmPinOffset('f((address,address))', [0, 2])).toThrow(/range/); + expect(() => evmPinOffset('0x12345678', [0, 1])).toThrow(/scalar/); +}); +it('tuple-authored pins re-encode using the raw-selector word indexes returned by reads', async () => { + const r = agenticPresets.get('DEXES', input).rules[0]; + const rt = mockRuntime(new FakeChain()); + const first = (await normalizePublicRule( + publicRules([r])[0], + ADDR.owner, + rt + )) as UniversalRule; + const decoded: Rule = { + ...r, + allowedCalls: first.allowedCalls.map((c) => ({ + target: c.target, + selector: parseSelector(c.selector).selector, + maxValue: c.maxValue, + pins: c.pins?.map((p) => + p.op === 0 + ? { arg: (p.offset - 4) / 32, expected: p.value } + : { arg: (p.offset - 4) / 32, max: BigInt(p.value) } + ), + })), + }; + const second = (await normalizePublicRule( + publicRules([decoded])[0], + ADDR.owner, + rt + )) as UniversalRule; + expect(second.allowedCalls.map((c) => c.pins)).toEqual( + first.allowedCalls.map((c) => c.pins) + ); +}); +it('mutating a returned tuple path cannot change a later preset', () => { + const r = agenticPresets.get('DEXES', input).rules[0]; + (r.allowedCalls[0].pins![0].arg as number[])[1] = 99; + expect( + agenticPresets.get('DEXES', input).rules[0].allowedCalls[0].pins![0].arg + ).toEqual([0, 0]); +}); diff --git a/packages/core/src/lib/agentic/__tests__/presets.spec.ts b/packages/core/src/lib/agentic/__tests__/presets.spec.ts index bf0a1dde..da6f3e98 100644 --- a/packages/core/src/lib/agentic/__tests__/presets.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/presets.spec.ts @@ -45,27 +45,37 @@ function catalog(): PresetDefinition[] { }, ]; } -it('exposes enumerable frozen categories with no invented production addresses', () => { +it('ships only verified testnet catalog entries and keeps prediction empty', () => { expect(Object.values(AGENTIC.PRESETS.CATEGORY)).toEqual([ 'DEXES', 'LENDING', + 'STAKING', 'PREDICTION', ]); - expect(Object.isFrozen(AGENTIC.PRESETS.CATEGORY)).toBe(true); - expect( - agenticPresets.list().presets.map((p) => [p.constant, p.chains]) - ).toEqual([ - ['DEXES', []], - ['LENDING', []], - ['PREDICTION', []], + const entries = agenticPresets.list().presets; + expect(entries.map((p) => [p.constant, p.chains.length])).toEqual([ + ['DEXES', 4], + ['LENDING', 4], + ['STAKING', 1], + ['PREDICTION', 0], ]); - expect(agenticPresets.get('DEXES')).toEqual({ rules: [] }); - expect(() => agenticPresets.get('DEXES', { chainNamespace: chain })).toThrow( - /no approved entry/ - ); + expect( + entries + .flatMap((p) => p.chains) + .every((c) => + [ + 'eip155:11155111', + 'eip155:84532', + 'eip155:421614', + 'eip155:97', + ].includes(c) + ) + ).toBe(true); + expect(agenticPresets.get('PREDICTION')).toEqual({ rules: [] }); + expect(() => agenticPresets.get('DEXES')).toThrow(/two explicit ERC20/); expect(() => - agenticPresets.get('DEXES', { assets: [{ chainNamespace: chain, token }] }) - ).toThrow(/no approved app entries/); + agenticPresets.get('LENDING', { chainNamespace: 'eip155:1' }) + ).toThrow(/no approved entry/); }); it('groups all apps on a chain into one editable template and omits unspecified fields', () => { const data = catalog(); diff --git a/packages/core/src/lib/agentic/__tests__/public-rule.spec.ts b/packages/core/src/lib/agentic/__tests__/public-rule.spec.ts index ddf1d5d9..684b6230 100644 --- a/packages/core/src/lib/agentic/__tests__/public-rule.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/public-rule.spec.ts @@ -105,16 +105,15 @@ it('supports general destination EQ/MAX pins', async () => { })) as UniversalRule; expect(out.allowedCalls[0].pins?.map((p) => p.op)).toEqual([0, 1]); }); -it('refuses layouts whose top-level argument indexes cannot be reconstructed', async () => { +it('computes top-level offsets after static arrays and preserves a raw-word round trip', async () => { const r = base(); r.allowedCalls[0] = { target: ADDR.target, selector: 'f(uint256[2],uint256)', pins: [{ arg: 1, max: BigInt(1) }], }; - await expect(normalize(r)).rejects.toMatchObject({ - code: 'CAPABILITY_UNAVAILABLE', - }); + const out = (await normalize(r)) as NativeMultiRule; + expect(out.actions[0].wirePins?.[0].offset).toBe(68); }); it('compiles numeric Solana arg/account pins without a caller IDL', async () => { const program = new PublicKey(Buffer.alloc(32, 3)).toBase58(); diff --git a/packages/core/src/lib/agentic/agentic.types.ts b/packages/core/src/lib/agentic/agentic.types.ts index 34acefad..b8c5d465 100644 --- a/packages/core/src/lib/agentic/agentic.types.ts +++ b/packages/core/src/lib/agentic/agentic.types.ts @@ -184,14 +184,16 @@ export interface InternalRulesRecord { /** Current SDK section 6 public rule shape; contract wire types above are internal. */ export type WalletMarker = 'agentic:wallet'; +/** Top-level ABI argument, or a path through static tuple/fixed-array fields. */ +export type ArgumentPath = number | readonly number[]; export type Pin = | { - arg: number; + arg: ArgumentPath; expected: AgenticHex | AgenticAddress | bigint | WalletMarker; max?: never; account?: never; } - | { arg: number; max: bigint; expected?: never; account?: never } + | { arg: ArgumentPath; max: bigint; expected?: never; account?: never } | { account: number; expected: string | WalletMarker; diff --git a/packages/core/src/lib/agentic/codec/abi-layout.ts b/packages/core/src/lib/agentic/codec/abi-layout.ts index 2e1d4629..430ae3b3 100644 --- a/packages/core/src/lib/agentic/codec/abi-layout.ts +++ b/packages/core/src/lib/agentic/codec/abi-layout.ts @@ -24,7 +24,9 @@ function components(p: AbiParameter): readonly AbiParameter[] { } /** Parse a trailing fixed/dynamic array suffix: 'uint256[3]' → base 'uint256', length 3. */ -function arraySuffix(type: string): { base: string; length: number | null } | null { +function arraySuffix( + type: string +): { base: string; length: number | null } | null { const m = /^(.*)\[(\d*)\]$/.exec(type); if (!m) return null; return { base: m[1], length: m[2] === '' ? null : Number(m[2]) }; @@ -54,7 +56,8 @@ export function headSize(p: AbiParameter): number { return 32; } -const ELEMENTARY = /^(address|bool|u?int(8|16|24|32|40|48|56|64|72|80|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256)?|bytes([1-9]|[12][0-9]|3[0-2]))$/; +const ELEMENTARY = + /^(address|bool|u?int(8|16|24|32|40|48|56|64|72|80|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256)?|bytes([1-9]|[12][0-9]|3[0-2]))$/; export function isSingleWordStatic(p: AbiParameter): boolean { return ELEMENTARY.test(p.type); @@ -75,7 +78,9 @@ export function argumentOffset( ); } if (!Number.isInteger(arg) || arg < 0 || arg >= inputs.length) { - throw invalid(`${what} argument index ${arg} is out of range (0..${inputs.length - 1})`); + throw invalid( + `${what} argument index ${arg} is out of range (0..${inputs.length - 1})` + ); } const target = inputs[arg]; if (!isSingleWordStatic(target)) { @@ -86,7 +91,9 @@ export function argumentOffset( let offset = 4; for (let i = 0; i < arg; i++) offset += headSize(inputs[i]); if (offset + 32 > UINT16_MAX) { - throw invalid(`${what} argument ${arg} lies beyond the uint16 offset range`); + throw invalid( + `${what} argument ${arg} lies beyond the uint16 offset range` + ); } return offset; } @@ -98,19 +105,32 @@ export function encodeArgWord( what: string ): AgenticHex { try { - const isWord = typeof expected === 'string' && isHex(expected) && expected.length === 66; + const isWord = + typeof expected === 'string' && isHex(expected) && expected.length === 66; if (param.type === 'address' && !isWord) { - if (typeof expected !== 'string' || !isAddress(expected, { strict: false })) { + if ( + typeof expected !== 'string' || + !isAddress(expected, { strict: false }) + ) { throw new Error('expected an address'); } } else if (param.type.startsWith('bytes') && !isWord) { - if (typeof expected !== 'string' || !isHex(expected)) throw new Error('expected hex'); + if (typeof expected !== 'string' || !isHex(expected)) + throw new Error('expected hex'); } // An already-encoded 32-byte word (as decoded rules return) is accepted // when it is a canonical encoding of this argument type. - if (typeof expected === 'string' && isHex(expected) && expected.length === 66 && param.type !== 'bytes32') { + if ( + typeof expected === 'string' && + isHex(expected) && + expected.length === 66 && + param.type !== 'bytes32' + ) { const [value] = decodeAbiParameters([param], expected as AgenticHex); - if (encodeAbiParameters([param], [value]).toLowerCase() !== expected.toLowerCase()) { + if ( + encodeAbiParameters([param], [value]).toLowerCase() !== + expected.toLowerCase() + ) { throw new Error('word is not a canonical encoding'); } return expected.toLowerCase() as AgenticHex; @@ -129,7 +149,11 @@ export function encodeArgWord( /** Validate a raw calldata offset given directly (offset form). */ export function rawOffset(offset: number, what: string): number { if (!Number.isInteger(offset) || offset < 4 || offset + 32 > UINT16_MAX) { - throw invalid(`${what} offset ${offset} must be an integer in [4, ${UINT16_MAX - 32}] (selector included)`); + throw invalid( + `${what} offset ${offset} must be an integer in [4, ${ + UINT16_MAX - 32 + }] (selector included)` + ); } return offset; } @@ -137,3 +161,52 @@ export function rawOffset(offset: number, what: string): number { function invalid(message: string, cause?: unknown): AgenticError { return new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, message, { cause }); } + +/** Absolute location of a scalar reached through static tuple/fixed-array indexes. */ +export function argumentLocation( + inputs: readonly AbiParameter[] | undefined, + arg: number | readonly number[], + what: string +): { offset: number; param: AbiParameter } { + if (!inputs) throw invalid(`${what} paths require a full function signature`); + const path = typeof arg === 'number' ? [arg] : arg; + if ( + !Array.isArray(path) || + path.length === 0 || + path.length > 16 || + path.some((i) => !Number.isSafeInteger(i) || i < 0) + ) + throw invalid(`${what} has an invalid argument path`); + if (path[0] >= inputs.length) + throw invalid(`${what} argument path is out of range`); + let offset = + 4 + inputs.slice(0, path[0]).reduce((n, p) => n + headSize(p), 0); + let param = inputs[path[0]]; + for (const index of path.slice(1)) { + if (isDynamic(param)) + throw invalid(`${what} cannot descend into a dynamic argument`); + const arr = arraySuffix(param.type); + if (arr && arr.length !== null) { + if (!Number.isSafeInteger(arr.length) || index >= arr.length) + throw invalid(`${what} fixed-array index is out of range`); + const child = { ...param, type: arr.base } as AbiParameter; + offset += index * headSize(child); + param = child; + } else if (param.type === 'tuple') { + const fields = components(param); + if (index >= fields.length) + throw invalid(`${what} tuple index is out of range`); + offset += fields.slice(0, index).reduce((n, p) => n + headSize(p), 0); + param = fields[index]; + } else throw invalid(`${what} path descends into a scalar`); + } + if ( + !isSingleWordStatic(param) || + !Number.isSafeInteger(offset) || + offset + 32 > UINT16_MAX + ) + throw invalid( + `${what} must identify one static ABI word within the uint16 offset range` + ); + return { offset, param }; +} diff --git a/packages/core/src/lib/agentic/constants.ts b/packages/core/src/lib/agentic/constants.ts index 1b3640a2..943b896c 100644 --- a/packages/core/src/lib/agentic/constants.ts +++ b/packages/core/src/lib/agentic/constants.ts @@ -5,6 +5,7 @@ export const AGENTIC = Object.freeze({ CATEGORY: Object.freeze({ DEXES: 'DEXES' as const, LENDING: 'LENDING' as const, + STAKING: 'STAKING' as const, PREDICTION: 'PREDICTION' as const, }), }), diff --git a/packages/core/src/lib/agentic/index.ts b/packages/core/src/lib/agentic/index.ts index 667d5155..520fb306 100644 --- a/packages/core/src/lib/agentic/index.ts +++ b/packages/core/src/lib/agentic/index.ts @@ -19,6 +19,7 @@ export type { Pin, Spent, WalletMarker, + ArgumentPath, RulesRecord, Selector, WalletInfo, diff --git a/packages/core/src/lib/agentic/presets/catalog.ts b/packages/core/src/lib/agentic/presets/catalog.ts index 5edbbec6..31e26546 100644 --- a/packages/core/src/lib/agentic/presets/catalog.ts +++ b/packages/core/src/lib/agentic/presets/catalog.ts @@ -1,4 +1,4 @@ -import type { Address } from 'viem'; +import { getAddress, type Address } from 'viem'; import type { RuleCall, ForeignChainNamespace } from '../agentic.types'; import type { PresetCategory } from './types'; @@ -6,8 +6,10 @@ import type { PresetCategory } from './types'; export interface PresetChainDefinition { chainNamespace: ForeignChainNamespace; allowedCalls: readonly RuleCall[]; + /** Static single-hop routers; calls are expanded only for the supplied token pairs. */ + swapRouters?: readonly { address: Address; app: string }[]; /** Exact spenders that need an approval for each non-native supplied asset. */ - approvals?: readonly { spender: Address; app: string }[]; + approvals?: readonly { spender: Address; app: string; token?: Address }[]; maxGasPerCall?: bigint; } export interface PresetDefinition { @@ -15,9 +17,163 @@ export interface PresetDefinition { name: string; chains: readonly PresetChainDefinition[]; } -/** No approved app/address catalog yet. Empty categories must be hidden by UIs. */ +/** Testnet-only catalog from the October 15 Notion export and protocol sources. + * Read-only deployment/code evidence and exclusions: plan/agw/research/preset-catalog-2026-10-15/. + * No mainnet addresses, unmaintained Compound market or unconfirmed Morpho deployment. + */ +const address = (value: string): Address => getAddress(value.toLowerCase()); +const wallet = 'agentic:wallet' as const; +const aave = (pool: Address): RuleCall[] => + [ + ['supply(address,uint256,address,uint16)', 2, 'Supply'], + ['withdraw(address,uint256,address)', 2, 'Withdraw'], + ['borrow(address,uint256,uint256,uint16,address)', 4, 'Borrow'], + ['repay(address,uint256,uint256,address)', 3, 'Repay'], + ].map(([selector, arg, label]) => ({ + target: pool, + selector: selector as RuleCall['selector'], + pins: [{ arg: arg as number, expected: wallet }], + app: 'Aave V3', + label: label as string, + })); +const market = (target: Address, app: string): RuleCall[] => + [ + 'mint(uint256)', + 'redeem(uint256)', + 'redeemUnderlying(uint256)', + 'borrow(uint256)', + 'repayBorrow(uint256)', + ].map((selector) => ({ + target, + selector: selector as RuleCall['selector'], + app, + label: selector.split('(')[0], + })); +const sepoliaPool = address('0x6Ae43d3271ff6888e7Fc43Fd7321a503ff738951'); +const basePool = address('0x8bAB6d1b75f19e9eD9fCe8b9BD338844fF79aE27'); +const arbitrumPool = address('0xBfC91D59fdAA134A4ED45f7B584cAf96D7792Eff'); +const moonUSDBC = address('0x876852425331a113d8E432eFFB3aC5BEf38f033a'); +const moonWETH = address('0x2F39a349A79492a70E152760ce7123A1933eCf28'); +const venusUSDT = address('0xb7526572FFE56AB9D7489838Bf2E18e3323b441A'); +const venusUSDC = address('0xD5C4C2e2facBEB59D0216D0595d63FcDc6F9A1a7'); +const eigen = address('0x2E3D6c0744b10eb0A4e6F679F71554a39Ec47a5D'); export const PRESET_CATALOG: readonly PresetDefinition[] = [ - { constant: 'DEXES', name: 'Popular DEXes', chains: [] }, - { constant: 'LENDING', name: 'Lending', chains: [] }, + { + constant: 'DEXES', + name: 'Popular DEXes', + chains: [ + [ + 'eip155:11155111', + '0x3bFA4769FB09eefC5a80d6E87c3B9C650f7Ae48E', + 'Uniswap V3', + ], + [ + 'eip155:84532', + '0x94cC0AaC535CCDB3C01d6787D6413C739ae12bc4', + 'Uniswap V3', + ], + [ + 'eip155:421614', + '0x101F443B4d1b059569D643917553c771E1b9663E', + 'Uniswap V3', + ], + [ + 'eip155:97', + '0x9a489505a00cE272eAa5e07Dba6491314CaE3796', + 'PancakeSwap V3', + ], + ].map(([chain, router, app]) => ({ + chainNamespace: chain as ForeignChainNamespace, + allowedCalls: [], + swapRouters: [{ address: address(router), app }], + approvals: [{ spender: address(router), app }], + })), + }, + { + constant: 'LENDING', + name: 'Lending', + chains: [ + { + chainNamespace: 'eip155:11155111', + allowedCalls: aave(sepoliaPool), + approvals: [{ spender: sepoliaPool, app: 'Aave V3' }], + }, + { + chainNamespace: 'eip155:421614', + allowedCalls: aave(arbitrumPool), + approvals: [{ spender: arbitrumPool, app: 'Aave V3' }], + }, + { + chainNamespace: 'eip155:84532', + allowedCalls: [ + ...aave(basePool), + ...market(moonUSDBC, 'Moonwell mUSDbC'), + ...market(moonWETH, 'Moonwell mWETH'), + { + target: address('0xC72ba45f2Ae134F21DAEb2b7B5fd5De0064Ee9bB'), + selector: 'enterMarkets(address[])', + app: 'Moonwell', + label: 'Enter markets', + }, + ], + approvals: [ + { spender: basePool, app: 'Aave V3' }, + { + spender: moonUSDBC, + app: 'Moonwell mUSDbC', + token: address('0x4616975f7E6045FD9737e95bC527e9e14c727BD2'), + }, + { + spender: moonWETH, + app: 'Moonwell mWETH', + token: address('0x663A6F02d547dFd639BF689FED298712f2FB69Fb'), + }, + ], + }, + { + chainNamespace: 'eip155:97', + allowedCalls: [ + ...market(venusUSDT, 'Venus vUSDT'), + ...market(venusUSDC, 'Venus vUSDC'), + { + target: address('0x94d1820b2D1c7c7452A163983Dc888CEC546b77D'), + selector: 'enterMarkets(address[])', + app: 'Venus', + label: 'Enter markets', + }, + ], + approvals: [ + { + spender: venusUSDT, + app: 'Venus vUSDT', + token: address('0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c'), + }, + { + spender: venusUSDC, + app: 'Venus vUSDC', + token: address('0x16227D60f7a0e586C66B005219dfc887D13C9531'), + }, + ], + }, + ], + }, + { + constant: 'STAKING', + name: 'Staking', + chains: [ + { + chainNamespace: 'eip155:11155111', + allowedCalls: [ + { + target: eigen, + selector: 'depositIntoStrategy(address,address,uint256)', + app: 'EigenLayer', + label: 'Deposit into strategy (withdrawals not included)', + }, + ], + approvals: [{ spender: eigen, app: 'EigenLayer' }], + }, + ], + }, { constant: 'PREDICTION', name: 'Prediction markets', chains: [] }, ]; diff --git a/packages/core/src/lib/agentic/presets/index.ts b/packages/core/src/lib/agentic/presets/index.ts index 82628679..0b1d521f 100644 --- a/packages/core/src/lib/agentic/presets/index.ts +++ b/packages/core/src/lib/agentic/presets/index.ts @@ -4,7 +4,7 @@ import { AGENTIC_ERROR_CODE, capabilityUnavailable, } from '../errors'; -import type { RuleAsset, RuleCall } from '../agentic.types'; +import type { RuleAsset, RuleCall, Pin } from '../agentic.types'; import type { AgenticPresets, PresetOptions, @@ -27,12 +27,19 @@ function copyCall(call: RuleCall): RuleCall { ...call, ...(call.pins ? { - pins: call.pins.map((p) => ({ - ...p, - ...('token' in p && p.token && typeof p.token === 'object' - ? { token: { ...p.token } } - : {}), - })), + pins: call.pins.map((pin): Pin => { + if (pin.account !== undefined) + return { + ...pin, + ...(pin.token && typeof pin.token === 'object' + ? { token: { ...pin.token } } + : {}), + }; + return { + ...pin, + arg: typeof pin.arg === 'number' ? pin.arg : [...pin.arg], + }; + }), } : {}), }; @@ -54,6 +61,7 @@ export function buildPresetApi( ...c, allowedCalls: c.allowedCalls.map(copyCall), approvals: c.approvals?.map((a) => ({ ...a })), + swapRouters: c.swapRouters?.map((r) => ({ ...r })), })), })); if ( @@ -95,6 +103,8 @@ export function buildPresetApi( options.validUntil >= 2 ** 48) ) throw invalid('preset validUntil must be a future uint48 timestamp'); + if (options.maxGasPerCall !== undefined) + cap(options.maxGasPerCall, 'maxGasPerCall'); if (options.assets !== undefined && !Array.isArray(options.assets)) throw invalid('preset assets must be an array'); const chains = @@ -153,6 +163,55 @@ export function buildPresetApi( } const rules: PresetRuleTemplate[] = chains.map((chain) => { const calls = chain.allowedCalls.map(copyCall); + if (chain.swapRouters?.length) { + const tokens = assets.get(chain.chainNamespace) ?? []; + if (tokens.length < 2) + throw invalid( + 'DEX presets require at least two explicit ERC20 assets per selected chain; select one chain or supply assets for every chain' + ); + if ( + tokens.some( + (a) => + tokenAddress(a.token) === zeroAddress || + (typeof a.token !== 'string' && a.token.mechanism === 'native') + ) + ) + throw invalid( + 'DEX token pins require explicit ERC20 addresses; use wrapped-native tokens instead of the native marker' + ); + for (const router of chain.swapRouters) + for (const input of tokens) + for (const output of tokens) { + if ( + tokenAddress(input.token).toLowerCase() === + tokenAddress(output.token).toLowerCase() + ) + continue; + for (const exactInput of [true, false]) + calls.push({ + target: router.address, + selector: `${ + exactInput ? 'exactInputSingle' : 'exactOutputSingle' + }((address,address,uint24,address,uint256,uint256,uint160))`, + pins: [ + { + arg: [0, 0], + expected: getAddress(tokenAddress(input.token)), + }, + { + arg: [0, 1], + expected: getAddress(tokenAddress(output.token)), + }, + { arg: [0, 3], expected: 'agentic:wallet' }, + { arg: [0, exactInput ? 4 : 5], max: input.maxPerCall }, + ], + app: router.app, + label: exactInput + ? 'Swap exact input' + : 'Swap exact output', + }); + } + } const approvals = new Set(); for (const asset of assets.get(chain.chainNamespace) ?? []) { const token = tokenAddress(asset.token); @@ -168,6 +227,11 @@ export function buildPresetApi( 'presetApproval', 'Solana approvals require a separately reviewed instruction template' ); + if ( + approval.token && + getAddress(token) !== getAddress(approval.token) + ) + continue; const spender = getAddress(approval.spender); const target = getAddress(token); const approvalKey = `${target}:${spender}`; @@ -190,6 +254,11 @@ export function buildPresetApi( 'presetCalls', 'preset must contain 1..32 allowed calls including approvals' ); + if (calls.reduce((n, c) => n + (c.pins?.length ?? 0), 0) > 32) + throw capabilityUnavailable( + 'presetPins', + 'preset expansion exceeds 32 pins; reduce the token list or split rules across wallets' + ); const pairs = new Map(); for (const call of calls) { if (!/^[A-Za-z_$][\w$]*\(.*\)$/.test(call.selector)) @@ -226,8 +295,13 @@ export function buildPresetApi( ...(options.assets !== undefined ? { assets: assets.get(chain.chainNamespace) ?? [] } : {}), - ...(chain.maxGasPerCall !== undefined - ? { maxGasPerCall: cap(chain.maxGasPerCall, 'maxGasPerCall') } + ...((options.maxGasPerCall ?? chain.maxGasPerCall) !== undefined + ? { + maxGasPerCall: cap( + options.maxGasPerCall ?? chain.maxGasPerCall, + 'maxGasPerCall' + ), + } : {}), }; }); diff --git a/packages/core/src/lib/agentic/presets/types.ts b/packages/core/src/lib/agentic/presets/types.ts index 5e3a6bc7..ec0e82bb 100644 --- a/packages/core/src/lib/agentic/presets/types.ts +++ b/packages/core/src/lib/agentic/presets/types.ts @@ -1,7 +1,7 @@ import type { Address } from 'viem'; import type { Rule, RuleAsset, ForeignChainNamespace } from '../agentic.types'; -export type PresetCategory = 'DEXES' | 'LENDING' | 'PREDICTION'; +export type PresetCategory = 'DEXES' | 'LENDING' | 'STAKING' | 'PREDICTION'; export interface Preset { type: 'CATEGORY'; constant: PresetCategory; @@ -21,6 +21,8 @@ export interface PresetAsset { maxTotal?: bigint; } export interface PresetOptions { + /** Explicit Push-PC gas budget per outbound; omitted = zero. */ + maxGasPerCall?: bigint; chainNamespace?: ForeignChainNamespace; agent?: Address; validUntil?: number; diff --git a/packages/core/src/lib/agentic/public-rule.ts b/packages/core/src/lib/agentic/public-rule.ts index 0f831935..8dd8f9f0 100644 --- a/packages/core/src/lib/agentic/public-rule.ts +++ b/packages/core/src/lib/agentic/public-rule.ts @@ -25,6 +25,7 @@ import type { SolanaRule, UniversalRule, Pin, + ArgumentPath, } from './agentic.types'; import { AGENTIC_ERROR_CODE, @@ -32,7 +33,7 @@ import { capabilityUnavailable, } from './errors'; import { parseSelector } from './codec/selectors'; -import { argumentOffset, encodeArgWord, headSize } from './codec/abi-layout'; +import { argumentLocation, encodeArgWord } from './codec/abi-layout'; import { UINT256_MAX } from './codec/defaults'; import { deriveAgwSvmCea, svmKey } from './codec/svm-accounts'; import type { AgenticRuntime } from './runtime'; @@ -69,29 +70,33 @@ function uint(value: unknown, name: string): bigint { } export function evmPinOffset( selector: Rule['allowedCalls'][number]['selector'], - arg: number + arg: ArgumentPath ): number { - if (!Number.isInteger(arg) || arg < 0 || 4 + 32 * arg + 32 > 65535) - throw invalid('pin arg is outside the supported calldata range'); const parsed = parseSelector(selector); if (parsed.valueOnly) throw invalid('value-only calls cannot have argument pins'); - if (!parsed.inputs) return 4 + 32 * arg; - if (parsed.inputs.slice(0, arg).some((p) => headSize(p) !== 32)) - throw capabilityUnavailable( - 'argumentLayout', - 'pins after multi-word tuple/array arguments need an explicit lossless index convention' - ); - return argumentOffset(parsed.inputs, arg, 'pin'); + if (parsed.inputs) return argumentLocation(parsed.inputs, arg, 'pin').offset; + if ( + typeof arg !== 'number' || + !Number.isSafeInteger(arg) || + arg < 0 || + 4 + 32 * arg + 32 > 65535 + ) + throw invalid('a raw selector needs a valid scalar ABI word index'); + return 4 + 32 * arg; } function expectedWord( selector: Rule['allowedCalls'][number]['selector'], - arg: number, + arg: ArgumentPath, value: unknown ): Hex { const parsed = parseSelector(selector); if (parsed.inputs) - return encodeArgWord(parsed.inputs[arg], value as Hex | bigint, 'pin'); + return encodeArgWord( + argumentLocation(parsed.inputs, arg, 'pin').param, + value as Hex | bigint, + 'pin' + ); if (typeof value === 'bigint') return numberToHex(uint(value, 'pin.expected'), { size: 32 }); if (typeof value === 'string' && isAddress(value, { strict: false })) diff --git a/packages/core/src/lib/index.ts b/packages/core/src/lib/index.ts index 1767a522..25edbc94 100644 --- a/packages/core/src/lib/index.ts +++ b/packages/core/src/lib/index.ts @@ -225,6 +225,7 @@ export type { Pin, Spent, WalletMarker, + ArgumentPath, RulesRecord, Selector, WalletInfo, From b886fc3618b6ea093b47609e9dae9b2b42feabb9 Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Thu, 15 Oct 2026 07:07:20 +0530 Subject: [PATCH 38/68] docs(agw): preserve preset catalog sources and validation --- plan/agw/SOURCES.md | 2 + .../notion/agw-presets-proposal-and-rules.md | 291 + .../preset-catalog-2026-10-15/84532.json | 217 + .../AaveV3ArbitrumSepolia.sol | 113 + .../AaveV3BaseSepolia.sol | 227 + .../AaveV3Sepolia.sol | 261 + .../preset-catalog-2026-10-15/Comptroller.sol | 1418 +++ .../EigenStrategyManager.sol | 573 + .../preset-catalog-2026-10-15/IPool.sol | 848 ++ .../IV3SwapRouter.sol | 69 + .../preset-catalog-2026-10-15/MERC20.sol | 295 + .../preset-catalog-2026-10-15/MToken.sol | 2222 ++++ .../preset-catalog-2026-10-15/README.md | 402 + .../preset-catalog-2026-10-15/StakeHub.sol | 1306 ++ .../preset-catalog-2026-10-15/VBep20.sol | 272 + .../additional-sources.json | 22 + .../preset-catalog-2026-10-15/addresses.md | 71 + .../preset-catalog-2026-10-15/addresses.ts | 714 ++ .../bsctestnet_addresses.json | 257 + .../preset-catalog-2026-10-15/catalog.md | 291 + .../implementation-status.md | 35 + .../notion-export.zip | Bin 0 -> 137253 bytes .../pancake-package-source.json | 8 + .../pancake-router-package.txt | 10233 ++++++++++++++++ .../protocol-sources.json | 67 + .../rpc-verification.json | 148 + .../preset-catalog-2026-10-15/source.json | 7 + plan/agw/source-manifest.json | 11 + 28 files changed, 20380 insertions(+) create mode 100644 plan/agw/notion/agw-presets-proposal-and-rules.md create mode 100644 plan/agw/research/preset-catalog-2026-10-15/84532.json create mode 100644 plan/agw/research/preset-catalog-2026-10-15/AaveV3ArbitrumSepolia.sol create mode 100644 plan/agw/research/preset-catalog-2026-10-15/AaveV3BaseSepolia.sol create mode 100644 plan/agw/research/preset-catalog-2026-10-15/AaveV3Sepolia.sol create mode 100644 plan/agw/research/preset-catalog-2026-10-15/Comptroller.sol create mode 100644 plan/agw/research/preset-catalog-2026-10-15/EigenStrategyManager.sol create mode 100644 plan/agw/research/preset-catalog-2026-10-15/IPool.sol create mode 100644 plan/agw/research/preset-catalog-2026-10-15/IV3SwapRouter.sol create mode 100644 plan/agw/research/preset-catalog-2026-10-15/MERC20.sol create mode 100644 plan/agw/research/preset-catalog-2026-10-15/MToken.sol create mode 100644 plan/agw/research/preset-catalog-2026-10-15/README.md create mode 100644 plan/agw/research/preset-catalog-2026-10-15/StakeHub.sol create mode 100644 plan/agw/research/preset-catalog-2026-10-15/VBep20.sol create mode 100644 plan/agw/research/preset-catalog-2026-10-15/additional-sources.json create mode 100644 plan/agw/research/preset-catalog-2026-10-15/addresses.md create mode 100644 plan/agw/research/preset-catalog-2026-10-15/addresses.ts create mode 100644 plan/agw/research/preset-catalog-2026-10-15/bsctestnet_addresses.json create mode 100644 plan/agw/research/preset-catalog-2026-10-15/catalog.md create mode 100644 plan/agw/research/preset-catalog-2026-10-15/implementation-status.md create mode 100644 plan/agw/research/preset-catalog-2026-10-15/notion-export.zip create mode 100644 plan/agw/research/preset-catalog-2026-10-15/pancake-package-source.json create mode 100644 plan/agw/research/preset-catalog-2026-10-15/pancake-router-package.txt create mode 100644 plan/agw/research/preset-catalog-2026-10-15/protocol-sources.json create mode 100644 plan/agw/research/preset-catalog-2026-10-15/rpc-verification.json create mode 100644 plan/agw/research/preset-catalog-2026-10-15/source.json diff --git a/plan/agw/SOURCES.md b/plan/agw/SOURCES.md index ffaf4572..26c3e0b2 100644 --- a/plan/agw/SOURCES.md +++ b/plan/agw/SOURCES.md @@ -71,3 +71,5 @@ Use actual ZIP paths. The script does not download or authenticate to Notion. It The historical SDK refers to AGW-SDK-v1-agent.md, 05-universal-marketplace-startjob.md and SDK_HELPER.md. Their source URLs/files were not included in its export; those original unresolved references remain as written. October 7 v5 deployment: label contract dependency delivered. [New source snapshots and live read-only check](research/deployment-review-2026-10-07-v5/README.md); [SDK implementation and test evidence](research/v5-implementation-2026-10-07/README.md). Earlier dated deployment statements above are historical. + +October 15 focused import: [AGW Presets proposal and rules](https://app.notion.com/p/pushprotocol/AGW-Presets-proposal-and-rules-3f8188aea7f48020a9f0d10ea5325467), [snapshot](notion/agw-presets-proposal-and-rules.md), [catalog scope and verification](research/preset-catalog-2026-10-15/implementation-status.md). This was a single-page import, not a refresh of all sources. diff --git a/plan/agw/notion/agw-presets-proposal-and-rules.md b/plan/agw/notion/agw-presets-proposal-and-rules.md new file mode 100644 index 00000000..711941e6 --- /dev/null +++ b/plan/agw/notion/agw-presets-proposal-and-rules.md @@ -0,0 +1,291 @@ +# AGW Presets: proposal and rules + +Presets are ready-made rule sets for `client.agentic.create`: pick a category, add an agent, a token budget and an expiry, and get one `Rule` per chain that already names the right contracts, calls and pins. The wallet UI and developers read the same presets from `PushChain.utils.agentic.presets`. + +This doc proposes the first preset list, the allowed calls and pins per app, and the contract and SDK changes the rest depends on. It extends page 5 (SDK: AGW), section 7. + +- Addresses: read from each protocol's deployment files or docs on 2026-10-13 (Sources at the end). Three carry caveats, listed in section 11, item 12. + +# Prerequisites + +> +> +> +> [7. Changes proposed on 12 Oct 2026: Presets](https://app.notion.com/p/7-Changes-proposed-on-12-Oct-2026-Presets-07ce163677ef44dfae03a38ea4c16da0?pvs=21) +> +> Contract source, what the rules policy checks today: [push-agentic-wallets, branch demo-v2](https://github.com/pushchain/push-agentic-wallets/tree/demo-v2/src), `src/libraries/Types.sol` (the rule shapes) and `src/policies/UniversalRulesPolicy.sol` (the gates); URP 3.1.0, the version on Donut +> +> [https://www.figma.com/design/FvJL0JWHlsVohsHTERB1Lh/Push-Design-Foundations?node-id=50458-26112&t=GpO3AVzquTow00Gj-0](https://www.figma.com/design/FvJL0JWHlsVohsHTERB1Lh/Push-Design-Foundations?node-id=50458-26112&t=GpO3AVzquTow00Gj-0) +> + +![image.png](AGW%20Presets%20proposal%20and%20rules/image.png) + +# Categories + +Custom is always open: a user can write any rule by hand in `client.agentic.create`, so a category left out here is not blocked, only not pre-filled. Presets are shortcuts for the common cases. + +**Factors a category must pass to be a preset** + +1. **Fixed strategy, user fills the blanks.** The preset picks the contracts and functions. The user picks the agent, fn params. If the user would have to pick the contracts too, it is Custom. +2. **The receiver can be locked to the wallet.** Every call that moves funds has a "to" argument we can pin. Aggregators, order books and Universal Router hide it inside a bytes blob, so they are out. +3. **Popular.** Top apps by volume or TVL. + +| Category | In v1? | Why | +| --- | --- | --- | +| DEXES | Yes | Swaps on routers with the recipient at a fixed position, 2 to 3 routers. The user names the tokens, the preset pins them (section 7) | +| LENDING | Yes | Supply, withdraw, borrow, repay on 2 to 3 money markets, with the position owner pinned to the wallet | +| STAKING | Yes | Liquid staking and restaking. Pins well: the receipt token goes to `msg.sender`, and the native coin sent is capped per call by `maxValue` | +| VAULTS | No, next | ERC-4626 `deposit`, `withdraw`, `redeem` with the receiver pinned; the most pinnable category. Needs the vault list first | +| PREDICTION | No | The live venues (Polymarket, Kalshi, Limitless) are order books: the user signs an order off-chain and an operator fills it, and a rule allows contract calls, not signed orders. The on-chain AMM-style markets have no volume. Constant ships empty, hidden by the UI | +| PERPS | No | Dynamic order structs (GMX, Drift), so the receiver cannot be pinned; leverage makes the loss case worse | +| AGGREGATORS | No | 1inch, 0x, Paraswap: dynamic calldata by design, nothing to pin. Jupiter `route` on Solana is the exception (user accounts at fixed positions, amounts pinnable from the end of the data) and sits in DEXES as a candidate | +| NFT MARKETS | No | Dynamic order structs (Seaport, Magic Eden) | +| BRIDGES | No | The recipient is on another chain; the AGW already moves funds across chains through Push | +| LAUNCHPADS | No | pump.fun pins fine, but it is the DEXES risk with worse odds | +| PAYMENTS | No, later | ERC-20 `transfer(address,uint256)` and SPL transfer with the recipient pinned to addresses the user passes as a parameter. Pins well and loss is bounded; left out of v1 only because agent payments (vendors, subscriptions) are not a demo case yet. GOVERNANCE (`castVote`, `delegate`) is the same shape with no funds moving and little demand | + +# Chains in scope + + + +| Chain | Mainnet | Testnet | +| --- | --- | --- | +| Ethereum | eip155:1 | Sepolia, eip155:11155111 | +| Base | eip155:8453 | Base Sepolia, eip155:84532 | +| Arbitrum | eip155:42161 | Arbitrum Sepolia, eip155:421614 | +| BNB Chain | eip155:56 | BSC testnet, eip155:97 | +| Solana | mainnet-beta | devnet | + +# DEXES + +One rule per chain, two or three routers per chain, single-hop and `address[]`-path swaps only. Every swap pins its recipient to the wallet. An app's calls are the same on every chain it is listed for; addresses are in section 6. + +| App | Chains | Allowed call | Pin | +| --- | --- | --- | --- | +| Uniswap V3 SwapRouter02 | Ethereum, Base, Arbitrum, BNB | `exactInputSingle((address,address,uint24,address,uint256,uint256,uint160))` | `[0,3]` = WALLET (word 3); `[0,0]` = tokenIn, `[0,1]` = tokenOut from the user's list (after page 1, 6.3) | +| Uniswap V3 SwapRouter02 | same | `exactOutputSingle((address,address,uint24,address,uint256,uint256,uint160))` | `[0,3]` = WALLET; `[0,0]` and `[0,1]` = the user's tokens (after 6.3) | +| Uniswap V3 SwapRouter02 | same | `swapExactTokensForTokens(uint256,uint256,address[],address)` (V2 pools through the same router) | `3` = WALLET (word 3); tokens sit inside `path`, not pinnable | +| Uniswap V2 Router02 | Ethereum | `swapExactTokensForTokens(uint256,uint256,address[],address,uint256)` | `3` = WALLET (word 3); tokens not pinnable | +| Uniswap V2 Router02 | Ethereum | `swapTokensForExactTokens(uint256,uint256,address[],address,uint256)` | `3` = WALLET (word 3); tokens not pinnable | +| Curve Router NG | Ethereum | `exchange(address[11],uint256[5][5],uint256,uint256,address[5],address)` | `5` = WALLET (word 43, fixed arrays inlined); `[0,0]` = tokenIn pinnable, tokenOut sits at a variable position in `route`, not pinnable | +| Aerodrome Router | Base | `swapExactTokensForTokens(uint256,uint256,(address,address,bool,address)[],address,uint256)` | `3` = WALLET (word 3); tokens sit inside `routes`, not pinnable | +| Aerodrome Slipstream SwapRouter | Base | `exactInputSingle((address,address,int24,address,uint256,uint256,uint256,uint160))` | `[0,3]` = WALLET; `[0,0]` and `[0,1]` = the user's tokens (after 6.3) | +| Aerodrome Slipstream SwapRouter | Base | `exactOutputSingle((address,address,int24,address,uint256,uint256,uint256,uint160))` | `[0,3]` = WALLET; `[0,0]` and `[0,1]` = the user's tokens (after 6.3) | +| PancakeSwap V3 SmartRouter | Arbitrum, BNB | `exactInputSingle((address,address,uint24,address,uint256,uint256,uint160))` | `[0,3]` = WALLET; `[0,0]` and `[0,1]` = the user's tokens (after 6.3) | +| PancakeSwap V3 SmartRouter | same | `exactOutputSingle((address,address,uint24,address,uint256,uint256,uint160))` | `[0,3]` = WALLET; `[0,0]` and `[0,1]` = the user's tokens (after 6.3) | +| PancakeSwap V3 SmartRouter | same | `swapExactTokensForTokens(uint256,uint256,address[],address)` | `3` = WALLET (word 3); tokens not pinnable | +| PancakeSwap V2 Router02 | BNB | `swapExactTokensForTokens(uint256,uint256,address[],address,uint256)` | `3` = WALLET (word 3); tokens not pinnable | +| PancakeSwap V2 Router02 | BNB | `swapTokensForExactTokens(uint256,uint256,address[],address,uint256)` | `3` = WALLET (word 3); tokens not pinnable | +| Camelot V3 SwapRouter | Arbitrum | `exactInputSingle((address,address,address,uint256,uint256,uint256,uint160))` (Algebra: recipient is field 2) | `[0,2]` = WALLET (word 2); `[0,0]` and `[0,1]` = the user's tokens (after 6.3) | +| Camelot V3 SwapRouter | Arbitrum | `exactOutputSingle((address,address,uint24,address,uint256,uint256,uint256,uint160))` | `[0,3]` = WALLET (word 3); `[0,0]` and `[0,1]` = the user's tokens (after 6.3) | +| Raydium CPMM | Solana | `swap_base_input(u64,u64)`, discriminator `8fbe5adac41e33de`; 13 accounts, `maxAccounts` 13 | account 0 = WALLET; account 5 = WALLET ATA(output mint); data pin: min-out ratio on `(amount_in, minimum_amount_out)` | +| Raydium CPMM | Solana | `swap_base_output(u64,u64)`, discriminator `37d96256a34ab4ad` | same | +| Orca Whirlpool | Solana | `swap(u64,u64,u128,bool,bool)`, discriminator `f8c69e91e17587c8`; 11 accounts plus trailing, `maxAccounts` 0 | account 1 = WALLET; accounts 3 and 5 = WALLET ATA(mint A), WALLET ATA(mint B); data pin: `a_to_b` EQ and the min-out ratio | +| Raydium AMM V4 | Solana | `swapBaseIn(u64,u64)`, 1-byte tag 9; `maxAccounts` 17 | account 16 = WALLET; account 15 = WALLET ATA(output mint); min-out ratio | +| Jupiter v6 (candidate) | Solana | `route(Vec,u64,u64,u16,u8)`, discriminator `e517cb977ae3ad2a`; pools as trailing accounts, `maxAccounts` 0 | account 1 = WALLET; account 3 = WALLET ATA(output mint); amounts pinned from the end of `ix_data` (`fromEnd`), since Borsh writes the vector first | +- Token pins: only the struct-based single-hop calls (`exactInputSingle`, `exactOutputSingle`) can carry them, since `tokenIn` and `tokenOut` are static fields at words 0 and 1. The path-based calls keep the tokens inside a dynamic array, so once 6.3 lands and the user's token list is enforced, the path rows should be dropped or kept with the warning in section 7. Until 6.3 none of the EVM token pins is checked. +- Out on EVM: `exactInput` and `exactOutput` (recipient inside a struct with `bytes path`), Universal Router `execute`, `multicall`, Curve's four- and five-argument `exchange` overloads. +- Solana: the SVM rulebook already exists in the demo-v2 source. An account pin names one key from `ceaAccounts`, so a swap rule allows one output mint; `maxAccounts` 0 admits the trailing tick, bin and pool accounts Orca, Meteora and Jupiter need; the `RATIO_GTE_LE` data pin enforces a minimum output relative to the input. Jupiter `route` is therefore a candidate, to confirm against the program (`shared_accounts_route` uses program-owned intermediates and stays out). Orca, Raydium CLMM and Meteora share the `swap` discriminator `f8c69e91e17587c8`; a rule keys on program and discriminator. + +# LENDING + +Supply, withdraw, borrow and repay on two or three money markets per chain. Every position is the wallet's: the call acts on `msg.sender` (Compound-style markets, where the CEA is the sender) or pins `onBehalfOf` on the way in and `to` or `receiver` on the way out. Solana is supply and withdraw only. + +| App | Chains | Allowed call | Pin | +| --- | --- | --- | --- | +| Aave V3 Pool | Ethereum, Base, Arbitrum, BNB | `supply(address,uint256,address,uint16)` | `2` = WALLET (onBehalfOf, word 2) | +| Aave V3 Pool | same | `withdraw(address,uint256,address)` | `2` = WALLET (to, word 2) | +| Aave V3 Pool | same | `borrow(address,uint256,uint256,uint16,address)` | `4` = WALLET (onBehalfOf, word 4) | +| Aave V3 Pool | same | `repay(address,uint256,uint256,address)` | `3` = WALLET (onBehalfOf, word 3) | +| Compound V3 Comet (cUSDCv3, cWETHv3) | Ethereum, Arbitrum | `supply(address,uint256)` | none; credits `msg.sender` | +| Compound V3 Comet | same | `withdraw(address,uint256)` | none; pays `msg.sender`. Withdrawing the base asset beyond the balance opens a borrow | +| Morpho Blue | Ethereum, Base, Arbitrum | `supply((address,address,address,address,uint256),uint256,uint256,address,bytes)` | `3` = WALLET (onBehalf, word 7) | +| Morpho Blue | same | `supplyCollateral((address,address,address,address,uint256),uint256,address,bytes)` | `2` = WALLET (onBehalf, word 6) | +| Morpho Blue | same | `withdraw((address,address,address,address,uint256),uint256,uint256,address,address)` | `4` = WALLET (receiver, word 8) | +| Morpho Blue | same | `withdrawCollateral((address,address,address,address,uint256),uint256,address,address)` | `3` = WALLET (receiver, word 7) | +| Morpho Blue | same | `borrow((address,address,address,address,uint256),uint256,uint256,address,address)` | `4` = WALLET (receiver, word 8) | +| Morpho Blue | same | `repay((address,address,address,address,uint256),uint256,uint256,address,bytes)` | `3` = WALLET (onBehalf, word 7) | +| Lista Moolah | BNB | the six Morpho Blue calls, same signatures and selectors | as Morpho Blue | +| Moonwell (mUSDC, mWETH) | Base | `mint(uint256)`, `redeem(uint256)`, `redeemUnderlying(uint256)`, `borrow(uint256)`, `repayBorrow(uint256)` | none; every call acts on `msg.sender` | +| Moonwell Comptroller | Base | `enterMarkets(address[])` | none; needed once before borrowing against a market | +| Venus (vUSDT, vUSDC) | BNB | the same five calls as Moonwell | none | +| Venus Unitroller | BNB | `enterMarkets(address[])` | none | +| Kamino Lend | Solana | `deposit_reserve_liquidity(u64)`, discriminator `a9c91e7e06cd6644`; owner 0, reserve liquidity mint 4, reserve collateral mint 6, user source 7, user destination 8 | account 0 = WALLET; account 8 = WALLET ATA(collateral mint at account 6); `maxAccounts` 12 | +| Kamino Lend | Solana | `redeem_reserve_collateral(u64)`, discriminator `ea75b57db98edc1d`; user source 7, user destination 8 | account 0 = WALLET; account 8 = WALLET ATA(liquidity mint at account 4) | +| Jupiter Lend (Earn) | Solana | `deposit(u64)`, discriminator `f223c68952e1f2b6`; signer 0, depositor token account 1, recipient token account 2 | account 0 = WALLET; account 2 = WALLET ATA(fToken mint); `maxAccounts` 17 | +| Jupiter Lend (Earn) | Solana | `withdraw(u64)`, discriminator `b712469c946da122`; signer 0, owner token account 1, recipient 2 | account 0 = WALLET; account 2 = WALLET ATA(underlying mint); `maxAccounts` 18 | + +# PREDICTION, venue by venue + +Every live venue on the five chains, plus Polymarket for reference. "Signed order" means the user signs an EIP-712 order off-chain and an operator-only `matchOrders` settles it: nothing for a rule to allow. + +| Venue | Chain | How a trade happens | Fits a rule? | 30-day volume | +| --- | --- | --- | --- | --- | +| PancakeSwap Prediction | BNB (BNB, BTC, ETH markets), Arbitrum (ETH) | Direct call: `betBull(uint256)` and `betBear(uint256)` payable, stake is the value, `claim(uint256[])`; position = `msg.sender` | Yes: one static argument, stake capped by `maxValue` | $7.8M | +| Predict.fun (absorbed Probable, March 2026) | BNB | Signed order, operator `matchOrders`; CTF `splitPosition`, `mergePositions`, `redeemPositions` are direct | No for trading; mint and redeem only | $314M | +| Opinion | BNB | Signed order ("OPINION CTF Exchange"), positions held in a Safe; CTF `0xAD1a38cEc043e70E83a3eC30443dB285ED10D774` | No for trading | $274M | +| Limitless | Base | Order book for new markets; legacy Gnosis FPMM markets still live: `buy(uint256,uint256,uint256)`, `sell(uint256,uint256,uint256)`, buyer = `msg.sender`; CTF `0xC9c98965297Bc527861c898329Ee280632B76e18` | Partial: the AMM calls fit, but each market is its own contract and the volume is in the order book | $4.9M | +| Overtime (Thales) SportsAMMV2 | Arbitrum, Base, Optimism | Direct call `trade(TradeData[],uint256,uint256,uint256,address,address,bool)`, ticket to `msg.sender` | Weak: the bet is a dynamic `TradeData[]` (odds, merkle proofs) a rule cannot read; only the stake at word 1 and the collateral at word 5 are pinnable | $7.6M (Arbitrum $2.3M, Base $1.4M) | +| Azuro | Base (Arbitrum dead since 2023) | v3: bettor signature plus oracle signature, relayer calls `betFor`; v2 `bet` carries `bytes data` | No | $2.8M (Base $96k) | +| Polymarket (reference) | Polygon only; the Jupiter tie-up is a front end | Signed order, `CTFExchangeV2.matchOrders` is `onlyOperator`; NegRiskAdapter split, merge, redeem are direct | No, and not on a chain in scope | $5.2B | +| Jupiter Predict (Polymarket and Kalshi liquidity) | Solana | Jupiter's API returns an unsigned transaction; a keeper fills on the underlying market; program id not published | No: keeper front end, program unverified | not listed | +| Drift BET | Solana | Perp orders: `place_perp_order(OrderParams)` with Borsh `Option` fields, many remaining accounts | No: variable-length arguments | not broken out | +| Augur, Gnosis v1 and every Ethereum L1 market | Ethereum | AMM-style, direct calls | Would fit, but dead | $0 | + +Out of scope by chain: Myriad (Abstract, Linea), XO Market (own rollup), Kalshi (off-chain). Sport.fun on Base ($4.8M) publishes no contracts. To open the big venues, the wallet's CEA would have to sign orders under a rule (ERC-1271, with maker, assets and amounts pinned): + +# STAKING + +| App | Chains | Allowed call | Pin | +| --- | --- | --- | --- | +| Lido stETH | Ethereum | `submit(address)` payable | none; stETH to `msg.sender` (the referral may be pinned to 0) | +| Lido wstETH | Ethereum | `wrap(uint256)`, `unwrap(uint256)` | none | +| Lido WithdrawalQueue | Ethereum | `requestWithdrawals(uint256[],address)` | `1` = WALLET (owner, word 1) | +| Lido WithdrawalQueue | Ethereum | `claimWithdrawals(uint256[],uint256[])`, `claimWithdrawal(uint256)` | none; owner must be `msg.sender`, ETH paid to `msg.sender` | +| Rocket Pool DepositPool | Ethereum | `deposit()` payable | none; rETH to `msg.sender` | +| Rocket Pool rETH | Ethereum | `burn(uint256)` | none; ETH to `msg.sender` | +| ether.fi LiquidityPool | Ethereum | `deposit()` payable, `deposit(address)` payable | none; eETH to `msg.sender` | +| ether.fi weETH | Ethereum | `wrap(uint256)`, `unwrap(uint256)` | none | +| ether.fi LiquidityPool | Ethereum | `requestWithdraw(address,uint256)` | `0` = WALLET (recipient, word 0) | +| ether.fi WithdrawRequestNFT | Ethereum | `claimWithdraw(uint256)` | none; ETH to the NFT's owner | +| EigenLayer StrategyManager | Ethereum | `depositIntoStrategy(address,address,uint256)` | none needed (shares to `msg.sender`); optional `0` = strategy and `1` = token to lock the pair | +| EigenLayer DelegationManager | Ethereum | `queueWithdrawals(...)`, `completeQueuedWithdrawal(...)` | none; withdrawer is forced to `msg.sender`, assets go to the staker | +| Lista StakeManager | BNB | `deposit()` payable | none; slisBNB to `msg.sender` | +| Lista StakeManager | BNB | `requestWithdraw(uint256)`, `claimWithdraw(uint256)` | none; BNB to `msg.sender` | +| BNB StakeHub (native) | BNB | `delegate(address,bool)` payable | `0` = validator, a user parameter; credit to `msg.sender` | +| BNB StakeHub (native) | BNB | `undelegate(address,uint256)`, `claim(address,uint256)` | `0` = the same validator | +| Jito (SPL stake pool) | Solana | `DepositSol(u64)`, tag 14; 10 accounts | 0 = Jito pool; 3 (lamports source) = WALLET; 4 = WALLET ATA(JitoSOL); 6 (referrer fee) = the same account; `maxAccounts` 10 | +| Jito (SPL stake pool) | Solana | `WithdrawSol(u64)`, tag 16; 12 accounts | 0 = Jito pool; 2 (authority) = WALLET; 3 = WALLET ATA(JitoSOL); 5 (SOL destination) = WALLET; `maxAccounts` 12 | +| Marinade | Solana | `deposit(u64)`, discriminator `f223c68952e1f2b6`; 11 accounts, none remaining | 6 (transfer_from) = WALLET; 7 (mint_to) = WALLET ATA(mSOL); `maxAccounts` 11 | +| Marinade | Solana | `liquid_unstake(u64)`, discriminator `1e1e77f0bfe30c10`; 10 accounts | 5 = WALLET ATA(mSOL); 6 (authority) = WALLET; 7 (transfer_sol_to) = WALLET; `maxAccounts` 10 | +- Out: Lido `claimWithdrawalsTo(uint256[],uint256[],address)` (names another recipient); Stader BNBx (deposits disabled 29 Jan 2026, protocol sunset); Marinade `order_unstake` (needs a fresh ticket account per call); Jito restaking `mint_to` (takes an SPL token in, so it belongs with VAULTS). +- Approvals: `wrap`, `requestWithdrawals`, `requestWithdraw`, `depositIntoStrategy` and Lista `requestWithdraw` pull a token from the wallet. Covered by scoped approval (section 8, item 3). +- Rocket Pool's deposit pool address changes on upgrades (the Saturn release deployed a new one in 2026 and the old one reverts on `deposit()`). The SDK should resolve it from `RocketStorage.getAddress(keccak256("contract.addressrocketDepositPool"))` at release time rather than hard-code it. +- `deposit()` has the same selector on Rocket Pool, ether.fi and WETH, and `wrap` and `unwrap` the same on wstETH and weETH; rules key on target plus selector, so no clash. +- Jito's `DepositSol` requires the pool to have been updated this epoch. BlazeStake, vSOL and the Sanctum pools use the same program and instruction, so adding one is a pool address. The StakeHub validator is a user parameter (categories, factor 1). + +# Addresses + +Read from each protocol's deployment files or docs. + +"none" means no official testnet deployment was found. + + + +### DEXES + +| App | Chain | Mainnet | Testnet | +| --- | --- | --- | --- | +| Uniswap V3 SwapRouter02 | Ethereum | `0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45` | `0x3bFA4769FB09eefC5a80d6E87c3B9C650f7Ae48E` | +| Uniswap V3 SwapRouter02 | Base | `0x2626664c2603336E57B271c5C0b26F421741e481` | `0x94cC0AaC535CCDB3C01d6787D6413C739ae12bc4` | +| Uniswap V3 SwapRouter02 | Arbitrum | `0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45` | `0x101F443B4d1b059569D643917553c771E1b9663E` | +| Uniswap V3 SwapRouter02 | BNB | `0xB971eF87ede563556b2ED4b1C0b0019111Dd85d2` | none | +| Uniswap V2 Router02 | Ethereum | `0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D` | `0xeE567Fe1712Faf6149d80dA1E6934E354124CfE3` | +| Curve Router NG v1.2 | Ethereum | `0x45312ea0eFf7E09C83CBE249fa1d7598c4C8cd4e` | none | +| Aerodrome Router | Base | `0xcF77a3Ba9A5CA399B7c97c74d54e5b1Beb874E43` | none | +| Aerodrome Slipstream SwapRouter | Base | `0x698Cb2b6dd822994581fEa6eA4Fc755d1363A92F` | none | +| PancakeSwap V3 SmartRouter | Arbitrum | `0x32226588378236Fd0c7c4053999F88aC0e5cAc77` | none | +| PancakeSwap V3 SmartRouter | BNB | `0x13f4EA83D0bd40E75C8222255bc855a974568Dd4` | `0x9a489505a00cE272eAa5e07Dba6491314CaE3796` | +| PancakeSwap V2 Router02 | BNB | `0x10ED43C718714eb63d5aA57B78B54704E256024E` | `0xD99D1c33F9fC3444f8101754aBC46c52416550D1` | +| Camelot V3 SwapRouter | Arbitrum | `0x1F721E2E82F6676FCE4eA07A5958cF098D339e18` | none | +| Raydium CPMM | Solana | `CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C` | `DRaycpLY18LhpbydsBWbVJtxpNv9oXPgjRSfpF2bWpYb` | +| Orca Whirlpool | Solana | `whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc` | same id | +| Raydium AMM V4 | Solana | `675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8` | `DRaya7Kj3aMWQSy19kSjvmuwq9docCHofyP9kanQGaav` | + +### LENDING + +| App | Chain | Mainnet | Testnet | +| --- | --- | --- | --- | +| Aave V3 Pool | Ethereum | `0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2` | `0x6Ae43d3271ff6888e7Fc43Fd7321a503ff738951` | +| Aave V3 Pool | Base | `0xA238Dd80C259a72e81d7e4664a9801593F98d1c5` | `0x8bAB6d1b75f19e9eD9fCe8b9BD338844fF79aE27` | +| Aave V3 Pool | Arbitrum | `0x794a61358D6845594F94dc1DB02A252b5b4814aD` | `0xBfC91D59fdAA134A4ED45f7B584cAf96D7792Eff` | +| Aave V3 Pool | BNB | `0x6807dc923806fE8Fd134338EABCA509979a7e0cB` | none | +| Compound V3 cUSDCv3 | Ethereum | `0xc3d688B66703497DAA19211EEdff47f25384cdc3` | `0xAec1F48e02Cfb822Be958B68C7957156EB3F0b6e`, unmaintained since June 2026 | +| Compound V3 cWETHv3 | Ethereum | `0xA17581A9E3356d9A858b789D68B4d866e593aE94` | none | +| Compound V3 cUSDCv3 | Arbitrum | `0x9c4ec768c28520B50860ea7a15bd7213a9fF58bf` | none | +| Compound V3 cWETHv3 | Arbitrum | `0x6f7D514bbD4aFf3BcD1140B7344b32f063dEe486` | none | +| Morpho Blue | Ethereum | `0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb` | none | +| Morpho Blue | Base | `0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb` | unconfirmed by Morpho's own sources | +| Morpho Blue | Arbitrum | `0x6c247b1F6182318877311737BaC0844bAa518F5e` | none | +| Lista Moolah | BNB | `0x8F73b65B4caAf64FBA2aF91cC5D4a2A1318E5D8C` | none | +| Moonwell mUSDC | Base | `0xEdc817A28E8B93B03976FBd4a3dDBc9f7D176c22` | mUSDbC `0x876852425331a113d8E432eFFB3aC5BEf38f033a` | +| Moonwell mWETH | Base | `0x628ff693426583D9a7FB391E54366292F509D457` | `0x2F39a349A79492a70E152760ce7123A1933eCf28` | +| Moonwell Comptroller | Base | `0xfBb21d0380beE3312B33c4353c8936a0F13EF26C` | `0xC72ba45f2Ae134F21DAEb2b7B5fd5De0064Ee9bB` | +| Venus vUSDT | BNB | `0xfD5840Cd36d94D7229439859C0112a4185BC0255` | `0xb7526572FFE56AB9D7489838Bf2E18e3323b441A` | +| Venus vUSDC | BNB | `0xecA88125a5ADbe82614ffC12D0DB554E2e2867C8` | `0xD5C4C2e2facBEB59D0216D0595d63FcDc6F9A1a7` | +| Venus Unitroller | BNB | `0xfD36E2c2a6789Db23113685031d7F16329158384` | `0x94d1820b2D1c7c7452A163983Dc888CEC546b77D` | +| Kamino Lend | Solana | `KLend2g3cP87fffoy8q1mQqGKjrxjC8boSyAYavgmjD` | same id | +| Jupiter Lend (Earn) | Solana | `jup3YeL8QhtSx1e253b2FDvsMNC87fDrgQZivbrndc9` | `7tjE28izRUjzmxC1QNXnNwcc4N82CNYCexf3k8mw67s3`, stale since May 2025, do not use | + +### STAKING + +Testnets: Hoodi (eip155:560048) for Lido, Rocket Pool and EigenLayer; EigenLayer is also on Sepolia. ether.fi and Lista have no official testnet deployment. + + + +| App | Chain | Mainnet | Testnet | +| --- | --- | --- | --- | +| Lido stETH | Ethereum | `0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84` | Hoodi `0x3508A952176b3c15387C97BE809eaffB1982176a` | +| Lido wstETH | Ethereum | `0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0` | Hoodi `0x7E99eE3C66636DE415D2d7C880938F2f40f94De4` | +| Lido WithdrawalQueue | Ethereum | `0x889edC2eDab5f40e902b864aD4d7AdE8E412F9B1` | Hoodi `0xfe56573178f1bcdf53F01A6E9977670dcBBD9186` | +| Rocket Pool RocketStorage | Ethereum | `0x1d8f8f00cfa6758d7bE78336684788Fb0ee0Fa46` | Hoodi `0x594Fb75D3dc2DFa0150Ad03F99F97817747dd4E1` | +| Rocket Pool DepositPool (current) | Ethereum | `0xCE15294273CFb9D9b628F4D61636623decDF4fdC` | Hoodi `0x425E6f83e27f1676AD78BC39dA79C2C7b33d3Fd8` | +| Rocket Pool rETH | Ethereum | `0xae78736Cd615f374D3085123A210448E74Fc6393` | Hoodi `0x7322c24752f79c05FFD1E2a6FCB97020C1C264F1` | +| ether.fi LiquidityPool | Ethereum | `0x308861A430be4cce5502d0A12724771Fc6DaF216` | none | +| ether.fi weETH | Ethereum | `0xCd5fE23C85820F7B72D0926FC9b05b43E359b7ee` | none | +| ether.fi WithdrawRequestNFT | Ethereum | `0x7d5706f6ef3F89B3951E23e557CDFBC3239D4E2c` | none | +| EigenLayer StrategyManager | Ethereum | `0x858646372CC42E1A627fcE94aa7A7033e7CF075A` | Hoodi `0xeE45e76ddbEDdA2918b8C7E3035cd37Eab3b5D41`; Sepolia `0x2E3D6c0744b10eb0A4e6F679F71554a39Ec47a5D` | +| EigenLayer DelegationManager | Ethereum | `0x39053D51B77DC0d36036Fc1fCc8Cb819df8Ef37A` | Hoodi `0x867837a9722C512e0862d8c2E15b8bE220E8b87d`; Sepolia `0xD4A7E1Bd8015057293f0D0A557088c286942e84b` | +| EigenLayer stETH strategy | Ethereum | `0x93c4b944D05dfe6df7645A86cd2206016c51564D` | Hoodi `0xf8a1a66130d614c7360e868576d5e59203475fe0` | +| Lista StakeManager | BNB | `0x1adB950d8bB3dA4bE104211D5AB038628e477fE6` | none published | +| Lista slisBNB | BNB | `0xB0b84D294e0C75A6abe60171b70edEb2EFd14A1B` | unverified | +| BNB StakeHub | BNB | `0x0000000000000000000000000000000000002002` | same (system contract) | +| SPL stake pool program (Jito) | Solana | `SPoo1Ku8WFXoNDMHPsrGSTSG1Y47rzgn41SLUNakuHy` | devnet build `DPoo15wWDqpPJJtS2MUZ49aRxqz5ZaaJCJP4z8bLuib` | +| Jito pool, JitoSOL mint | Solana | `Jito4APyf642JPZPx3hGc6WWJ8zPKtRbRs4P815Awbb`, `J1toso1uCk3RLmjorhTtrVwY9HJ7X8V9yYac6Y7kGCPn` | `JitoY5pcAxWX6iyP2QdFwTznGb8A99PRCUCVVxB46WZ`, `J1tos8mqbhdGcF3pgj4PCKyVjzWSURcpLZU7pPGHxSYi` | +| Marinade program | Solana | `MarBmsSgKXdrN1egZf5sqe1TMai9K1rChYNDJgjq7aD` | same id | +| Marinade state, mSOL mint | Solana | `8szGkuLTAux9XMgZ2vtY39jVSowEcpBfFfD8hXSEqdGC`, `mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So` | state not documented for devnet; mint the same | + +# Open questions and decisions needed + +1. **Approvals.** Scoped approval in URP, or one spender per token per rule for v1, which means one app per chain per preset and an allowance that outlives the rule? (Rules policy owner) +2. **Output tokens.** Until page 1, 6.3 lands no token pin is checked on EVM, and a pin holds one value. Ship DEXES with one output token per rule, or ship LENDING first and DEXES after the set pin +3. **One instruction per transaction on Solana.** Blocks every borrow flow (Kamino, Save, MarginFi need refresh instructions in the same transaction) and creating the output token account before a first swap. Relax to one allowed instruction plus instructions from a fixed list (refresh, create token account, compute budget)? (Rules policy owner) +4. **Missing cap.** Should `presets.get` throw when an asset has no `maxTotal`, since a missing cap means zero and the rule would move nothing? + +# Sources + +Deployment files and interfaces opened on 2026-10-13. Where a docs site was unreachable, the protocol's GitHub deployment file or published npm package was used instead. + +- Uniswap: [V3 Ethereum deployments](https://github.com/Uniswap/docs/blob/main/docs/content/protocols/v3/deployments/v3-ethereum-deployments.mdx), [V3 Base deployments](https://developers.uniswap.org/docs/protocols/v3/deployments/v3-base-deployments), [V3 Arbitrum deployments](https://developers.uniswap.org/docs/protocols/v3/deployments/v3-arbitrum-deployments.md), [sdk-core addresses](https://raw.githubusercontent.com/Uniswap/sdks/main/sdks/sdk-core/src/addresses.ts), [IV3SwapRouter](https://raw.githubusercontent.com/Uniswap/swap-router-contracts/main/contracts/interfaces/IV3SwapRouter.sol), [IV2SwapRouter](https://raw.githubusercontent.com/Uniswap/swap-router-contracts/main/contracts/interfaces/IV2SwapRouter.sol), [IUniswapV2Router02](https://raw.githubusercontent.com/Uniswap/v2-periphery/master/contracts/interfaces/IUniswapV2Router02.sol) +- Curve: [curve-router-ng](https://raw.githubusercontent.com/curvefi/curve-router-ng/master/README.md), [deployed contracts](https://raw.githubusercontent.com/CurveDocs/curve-docs/master/docs/references/deployed-contracts.md) +- Aerodrome: [contracts README](https://raw.githubusercontent.com/aerodrome-finance/contracts/main/README.md), [IRouter](https://raw.githubusercontent.com/aerodrome-finance/contracts/main/contracts/interfaces/IRouter.sol), [Slipstream README](https://raw.githubusercontent.com/aerodrome-finance/slipstream/main/README.md), [Slipstream ISwapRouter](https://raw.githubusercontent.com/aerodrome-finance/slipstream/main/contracts/periphery/interfaces/ISwapRouter.sol) +- PancakeSwap: [v3 addresses](https://raw.githubusercontent.com/pancakeswap/pancake-developer/master/docs/pages/contracts/v3/addresses.md), [v3-periphery deployments](https://raw.githubusercontent.com/pancakeswap/pancake-v3-contracts/main/projects/v3-periphery/deployments/bscMainnet.json), [IPancakeRouter02](https://raw.githubusercontent.com/pancakeswap/pancake-swap-periphery/master/contracts/interfaces/IPancakeRouter02.sol), npm `@pancakeswap/smart-router@7.8.0` +- Camelot: [Algebra V1.9 ISwapRouter](https://raw.githubusercontent.com/cryptoalgebra/AlgebraV1.9/main/src/periphery/contracts/interfaces/ISwapRouter.sol), [verified source mirror, Router v3](https://www.codeslaw.app/contracts/arbitrum/0x1f721e2e82f6676fce4ea07a5958cf098d339e18) +- Aave: [address book, Ethereum](https://raw.githubusercontent.com/bgd-labs/aave-address-book/main/src/AaveV3Ethereum.sol), [Sepolia](https://raw.githubusercontent.com/bgd-labs/aave-address-book/main/src/AaveV3Sepolia.sol), [Base](https://raw.githubusercontent.com/bgd-labs/aave-address-book/main/src/AaveV3Base.sol), [Base Sepolia](https://raw.githubusercontent.com/bgd-labs/aave-address-book/main/src/AaveV3BaseSepolia.sol), [Arbitrum](https://raw.githubusercontent.com/bgd-labs/aave-address-book/main/src/AaveV3Arbitrum.sol), [Arbitrum Sepolia](https://raw.githubusercontent.com/bgd-labs/aave-address-book/main/src/AaveV3ArbitrumSepolia.sol), [BNB](https://raw.githubusercontent.com/bgd-labs/aave-address-book/main/src/AaveV3BNB.sol), [IPool](https://raw.githubusercontent.com/aave-dao/aave-v3-origin/main/src/contracts/interfaces/IPool.sol) +- Compound V3: [mainnet USDC roots](https://raw.githubusercontent.com/compound-finance/comet/main/deployments/mainnet/usdc/roots.json), [Arbitrum USDC roots](https://raw.githubusercontent.com/compound-finance/comet/main/deployments/arbitrum/usdc/roots.json), [CometMainInterface](https://raw.githubusercontent.com/compound-finance/comet/main/contracts/CometMainInterface.sol) +- Morpho: [IMorpho](https://raw.githubusercontent.com/morpho-org/morpho-blue/main/src/interfaces/IMorpho.sol), [SDK addresses](https://raw.githubusercontent.com/morpho-org/sdks/main/packages/morpho-ts/src/addresses.ts), [docs addresses](https://docs.morpho.org/get-started/resources/addresses/) +- Moonwell: [Base addresses](https://raw.githubusercontent.com/moonwell-fi/moonwell-contracts-v2/main/chains/8453.json), [Base Sepolia addresses](https://raw.githubusercontent.com/moonwell-fi/moonwell-contracts-v2/main/chains/84532.json), [MToken](https://raw.githubusercontent.com/moonwell-fi/moonwell-contracts-v2/main/src/MToken.sol) +- Venus: [mainnet addresses](https://raw.githubusercontent.com/VenusProtocol/venus-protocol/develop/deployments/bscmainnet_addresses.json), [testnet addresses](https://raw.githubusercontent.com/VenusProtocol/venus-protocol/develop/deployments/bsctestnet_addresses.json), [VBep20](https://raw.githubusercontent.com/VenusProtocol/venus-protocol/develop/contracts/Tokens/VTokens/VBep20.sol) +- Lista: [lista-skills](https://raw.githubusercontent.com/lista-dao/lista-skills/main/skills/lista-lending/SKILL.md), npm `@lista-dao/moolah-sdk-core@1.0.12` +- Raydium: [program addresses](https://docs.raydium.io/reference/program-addresses.md), [CPMM IDL](https://github.com/raydium-io/raydium-idl), [AMM V4 instruction.rs](https://raw.githubusercontent.com/raydium-io/raydium-amm/master/program/src/instruction.rs) +- Orca: [whirlpools](https://github.com/orca-so/whirlpools) +- Meteora: [DLMM overview](https://docs.meteora.ag/developer-guide/guides/dlmm/overview), [dlmm-sdk](https://github.com/MeteoraAg/dlmm-sdk) +- Jupiter: [jupiter-cpi IDL](https://raw.githubusercontent.com/jup-ag/jupiter-cpi/main/idl.json), [development basics](https://developers.jup.ag/docs/get-started/development-basics.md), [Lend program addresses](https://developers.jup.ag/docs/lend/program-addresses.md), [jupiter-lend](https://github.com/jup-ag/jupiter-lend) +- Kamino: [klend](https://github.com/Kamino-Finance/klend), [klend-sdk](https://github.com/Kamino-Finance/klend-sdk) +- MarginFi: [marginfi-v2](https://github.com/mrgnlabs/marginfi-v2) +- Save: [token-lending instruction.rs](https://raw.githubusercontent.com/solendprotocol/solana-program-library/master/token-lending/program/src/instruction.rs) +- Volume and TVL: [DefiLlama DEXes, Ethereum](https://defillama.com/dexs/chains/Ethereum), [Base](https://defillama.com/dexs/chains/base), [Arbitrum](https://defillama.com/dexs/chain/arbitrum), [Arbitrum lending](https://defillama.com/protocols/lending/arbitrum), [prediction markets, Ethereum](https://defillama.com/protocols/prediction-market/ethereum), [Polymarket](https://defillama.com/protocol/polymarket) +- Prediction markets: [Drift BET launch](https://www.theblock.co/post/311888/solana-based-drift-protocol-launches-prediction-market), [Jupiter and Polymarket](https://www.coindesk.com/markets/2026/02/02/jupiter-brings-polymarket-to-solana-and-lands-usd35-million-investment-deal), [Jupiter Forecast](https://solanacompass.com/news/jupiter-launches-forecast-solanas-first-native-prediction-market-with-multi-market-maker-quoting) +- Staking: [Lido deployed contracts](https://raw.githubusercontent.com/lidofinance/docs/main/docs/deployed-contracts/index.md), [Lido Hoodi](https://raw.githubusercontent.com/lidofinance/docs/main/docs/deployed-contracts/hoodi.md), [WithdrawalQueue.sol](https://raw.githubusercontent.com/lidofinance/core/master/contracts/0.8.9/WithdrawalQueue.sol), [Rocket Pool contracts](https://raw.githubusercontent.com/rocket-pool/docs.rocketpool.net/main/docs/en/protocol/contracts-integrations.md), [RocketDepositPool.sol](https://raw.githubusercontent.com/rocket-pool/rocketpool/master/contracts/contract/deposit/RocketDepositPool.sol), [ether.fi deployed contracts](https://etherfi.gitbook.io/etherfi/developers/contracts-and-integrations/deployed-contracts), [LiquidityPool.sol](https://raw.githubusercontent.com/etherfi-protocol/smart-contracts/master/src/core/LiquidityPool.sol), [eigenlayer-contracts README](https://raw.githubusercontent.com/Layr-Labs/eigenlayer-contracts/main/README.md), [Lista smart contracts](https://docs.bsc.lista.org/for-developer/liquid-staking-slisbnb/smart-contract.md), [ListaStakeManager.sol](https://raw.githubusercontent.com/lista-dao/synclub-contracts/master/contracts/ListaStakeManager.sol), [BNB staking developer guide](https://docs.bnbchain.org/bnb-smart-chain/staking/developer-guide/), [StakeHub.sol](https://raw.githubusercontent.com/bnb-chain/bsc-genesis-contract/master/contracts/StakeHub.sol), [Stader BNBx sunset](https://www.staderlabs.com/blogs/sunsetting-bnbx-focusing-stader-on-high-impact-ecosystems/), [SPL stake pool instruction.rs](https://raw.githubusercontent.com/solana-program/stake-pool/main/program/src/instruction.rs), [Jito deployed programs](https://www.jito.network/docs/jitosol/jitosol-liquid-staking/security/deployed-programs/), [Marinade contract addresses](https://docs.marinade.finance/developers/contract-addresses), [Marinade deposit.rs](https://raw.githubusercontent.com/marinade-finance/liquid-staking-program/main/programs/marinade-finance/src/instructions/user/deposit.rs), [BlazeStake addresses](https://stake-docs.solblaze.org/developers/addresses.md) \ No newline at end of file diff --git a/plan/agw/research/preset-catalog-2026-10-15/84532.json b/plan/agw/research/preset-catalog-2026-10-15/84532.json new file mode 100644 index 00000000..18d3e0e0 --- /dev/null +++ b/plan/agw/research/preset-catalog-2026-10-15/84532.json @@ -0,0 +1,217 @@ +[ + { + "addr": "0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb", + "isContract": true, + "name": "MORPHO_BLUE" + }, + { + "addr": "0x036CbD53842c5426634e7929541eC2318f3dCF7e", + "isContract": true, + "name": "USDC" + }, + { + "addr": "0x79A1027a6A159502049F10906D333EC57E95F083", + "name": "WORMHOLE_CORE", + "isContract": true + }, + { + "addr": "0x4616975f7E6045FD9737e95bC527e9e14c727BD2", + "name": "USDBC", + "isContract": true + }, + { + "addr": "0xdbc885569E711262926803184eC9Ff73816fc953", + "name": "cbETH", + "isContract": true + }, + { + "addr": "0x663A6F02d547dFd639BF689FED298712f2FB69Fb", + "name": "WETH", + "isContract": true + }, + { + "addr": "0x21A36dE5734BE165f7bFa42a086a51C466Cb90EE", + "name": "USDC_ORACLE", + "isContract": true + }, + { + "addr": "0xbf7491f119bCC33E5a697D3528e7d8D64E35b3F2", + "name": "ETH_ORACLE", + "isContract": true + }, + { + "addr": "0x3E4589Ca47F41f6DEFC78929D210976678960754", + "name": "cbETH_COMPOSITE_ORACLE", + "isContract": true + }, + { + "addr": "0x8967d9F9fdD2be7A712d83dD15D79123BdAe872e", + "name": "PAUSE_GUARDIAN_DEPRECATED", + "isContract": false + }, + { + "addr": "0x8967d9F9fdD2be7A712d83dD15D79123BdAe872e", + "name": "EMISSIONS_ADMIN", + "isContract": false + }, + { + "addr": "0x8967d9F9fdD2be7A712d83dD15D79123BdAe872e", + "name": "SECURITY_COUNCIL", + "isContract": false + }, + { + "addr": "0x35b3314EA652899154BbfE937E3cCC2775ba712e", + "name": "BORROW_SUPPLY_GUARDIAN", + "isContract": false + }, + { + "addr": "0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE", + "name": "WORMHOLE_BRIDGE_RELAYER_PROXY", + "isContract": true + }, + { + "addr": "0xDbFACEfA114f79B7aAa8676A9cae9dF6edb76e11", + "name": "MRD_PROXY_ADMIN", + "isContract": true + }, + { + "addr": "0xc01EA381A64F8BE3bDBb01A7c34D809f80783662", + "name": "TEMPORAL_GOVERNOR", + "isContract": true + }, + { + "addr": "0x778F1bc4865F60201Dd0adAb2a57e9495bA9B80f", + "name": "MRD_IMPL", + "isContract": true + }, + { + "addr": "0xE193BE0A14D86BA554b11075b4235ab2Bd4F7D16", + "name": "COMPTROLLER", + "isContract": true + }, + { + "addr": "0xC72ba45f2Ae134F21DAEb2b7B5fd5De0064Ee9bB", + "name": "UNITROLLER", + "isContract": true + }, + { + "addr": "0xcdC49088c040f1209F1aa548b2Ae40d8E24B53A5", + "name": "MRD_PROXY", + "isContract": true + }, + { + "addr": "0x1c7b1689809F9f572e3DF9c1e063473549bdf37c", + "name": "MTOKEN_IMPLEMENTATION", + "isContract": true + }, + { + "addr": "0x7073814cfF6c183010df4D2BEC895a04bdB7f8cd", + "name": "JUMP_RATE_IRM_MOONWELL_USDBC", + "isContract": true + }, + { + "addr": "0x876852425331a113d8E432eFFB3aC5BEf38f033a", + "name": "MOONWELL_USDBC", + "isContract": true + }, + { + "addr": "0x2fdF038b9D09F7fA5E775cEF6787cdf0C780961c", + "name": "JUMP_RATE_IRM_MOONWELL_WETH", + "isContract": true + }, + { + "addr": "0x2F39a349A79492a70E152760ce7123A1933eCf28", + "name": "MOONWELL_WETH", + "isContract": true + }, + { + "addr": "0x38D292Adf50f0cceb12e06e1303d875F553D9b29", + "name": "JUMP_RATE_IRM_MOONWELL_cbETH", + "isContract": true + }, + { + "addr": "0x5302EbD8BC32435C823c2e22B04Cd6c45f593e89", + "name": "MOONWELL_cbETH", + "isContract": true + }, + { + "addr": "0xB7eAfB1B503c189CA4E5f19bCe272029cD98Cf1F", + "name": "WETH_ROUTER", + "isContract": true + }, + { + "addr": "0x13C0d0a89E7c3C747cc3A15234AB6942238d2ECb", + "name": "GOVTOKEN", + "isContract": true + }, + { + "addr": "0x1AbEA09b07276669de5BC3a11F820fdC4ba529d1", + "name": "CHAINLINK_ORACLE", + "isContract": true + }, + { + "addr": "0x6bD7f004Dda748dB47Eb764a816eD2AA26EB4e40", + "name": "WORMHOLE_BRIDGE_ADAPTER_PROXY", + "isContract": true + }, + { + "addr": "0xF81d39f4F2f98B5D804FCCF3Db194D17c78145Ff", + "name": "WORMHOLE_BRIDGE_ADAPTER_LOGIC", + "isContract": true + }, + { + "addr": "0xC18f4443e92D62Df803aA267E3117A1F244f09E3", + "name": "xWELL_LOGIC", + "isContract": true + }, + { + "addr": "0xE8F339C51cb2700113ec6ef552eE1D6cCA3BfB95", + "name": "xWELL_PROXY", + "isContract": true + }, + { + "addr": "0x9AC4520143F86538CdF325Ec9141e060e5896d7a", + "isContract": true, + "name": "ECOSYSTEM_RESERVE_PROXY" + }, + { + "addr": "0x4462233cA8899316540ffE976990D77D486A3f9c", + "isContract": true, + "name": "ECOSYSTEM_RESERVE_IMPL" + }, + { + "addr": "0xCEdb41D3D274326a6a72F03215BA2E8aA0fA0A6a", + "isContract": true, + "name": "ECOSYSTEM_RESERVE_CONTROLLER" + }, + { + "addr": "0x136b89Fc7e52493AadC7710a64603793a857dAfA", + "isContract": true, + "name": "STK_GOVTOKEN_PROXY" + }, + { + "addr": "0xa48382Da31A70EFecDF0a77d454cdE07b25b4B8D", + "isContract": true, + "name": "STK_GOVTOKEN_IMPL" + }, + { + "addr": "0xBdD86164da753C1a25e72603d266Dc1CC32e8acf", + "isContract": true, + "name": "VOTE_COLLECTION_PROXY" + }, + { + "addr": "0xb6cbE1de9878547BbC8DdB7288A668AbF9F43d16", + "isContract": true, + "name": "VOTE_COLLECTION_IMPL" + }, + { + "addr": "0x2dF0598Caa354D546dac1aAa0716553cEB81E8D8", + "isContract": false, + "name": "DEX_RELAYER" + }, + { + "addr": "0xE9fFd686Ca83CeB308962f4e50c5Fd7F2E3c037e", + "isContract": true, + "name": "MARKET_ADD_CHECKER" + } +] diff --git a/plan/agw/research/preset-catalog-2026-10-15/AaveV3ArbitrumSepolia.sol b/plan/agw/research/preset-catalog-2026-10-15/AaveV3ArbitrumSepolia.sol new file mode 100644 index 00000000..24b46a7e --- /dev/null +++ b/plan/agw/research/preset-catalog-2026-10-15/AaveV3ArbitrumSepolia.sol @@ -0,0 +1,113 @@ +// AUTOGENERATED - MANUAL CHANGES WILL BE REVERTED BY THE GENERATOR +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.0; + +import {IPoolAddressesProvider, IPool, IPoolConfigurator, IAaveOracle, IPoolDataProvider, IACLManager, ICollector} from './AaveV3.sol'; +library AaveV3ArbitrumSepolia { + // https://sepolia.arbiscan.io/address/0xB25a5D144626a0D488e52AE717A051a2E9997076 + IPoolAddressesProvider internal constant POOL_ADDRESSES_PROVIDER = + IPoolAddressesProvider(0xB25a5D144626a0D488e52AE717A051a2E9997076); + + // https://sepolia.arbiscan.io/address/0xBfC91D59fdAA134A4ED45f7B584cAf96D7792Eff + IPool internal constant POOL = IPool(0xBfC91D59fdAA134A4ED45f7B584cAf96D7792Eff); + + // https://sepolia.arbiscan.io/address/0x8E4Bb46E6245a507F1a267ef488228B08c0dc664 + IPoolConfigurator internal constant POOL_CONFIGURATOR = + IPoolConfigurator(0x8E4Bb46E6245a507F1a267ef488228B08c0dc664); + + // https://sepolia.arbiscan.io/address/0xEf95A6B9e88Bd509Fd67BA741cf2b263DaC65c00 + IAaveOracle internal constant ORACLE = IAaveOracle(0xEf95A6B9e88Bd509Fd67BA741cf2b263DaC65c00); + + // https://sepolia.arbiscan.io/address/0xC08C599C22bfD4a729E33e1Ed9b49456Abad0005 + address internal constant ACL_ADMIN = 0xC08C599C22bfD4a729E33e1Ed9b49456Abad0005; + + // https://sepolia.arbiscan.io/address/0xB66f0fF09f256A73d2E2b5faF596b363A21a7D68 + IACLManager internal constant ACL_MANAGER = + IACLManager(0xB66f0fF09f256A73d2E2b5faF596b363A21a7D68); + + // https://sepolia.arbiscan.io/address/0x12373B5085e3b42D42C1D4ABF3B3Cf4Df0E0Fa01 + IPoolDataProvider internal constant AAVE_PROTOCOL_DATA_PROVIDER = + IPoolDataProvider(0x12373B5085e3b42D42C1D4ABF3B3Cf4Df0E0Fa01); + + // https://sepolia.arbiscan.io/address/0x82405D1a189bd6cE4667809C35B37fBE136A4c5B + address internal constant POOL_IMPL = 0x82405D1a189bd6cE4667809C35B37fBE136A4c5B; + + // https://sepolia.arbiscan.io/address/0x629A5a607aC4901252e4C48a0Fde156785598F5b + address internal constant POOL_CONFIGURATOR_IMPL = 0x629A5a607aC4901252e4C48a0Fde156785598F5b; + + // https://sepolia.arbiscan.io/address/0x3A203B14CF8749a1e3b7314c6c49004B77Ee667A + address internal constant DEFAULT_INCENTIVES_CONTROLLER = + 0x3A203B14CF8749a1e3b7314c6c49004B77Ee667A; + + // https://sepolia.arbiscan.io/address/0x54E3aa872c3d2A89D1A6495F770f2cCa2C4Fc185 + address internal constant EMISSION_MANAGER = 0x54E3aa872c3d2A89D1A6495F770f2cCa2C4Fc185; + + // https://sepolia.arbiscan.io/address/0xa0208CE8356ad6C5EC6dFb8996c9A6B828212022 + ICollector internal constant COLLECTOR = ICollector(0xa0208CE8356ad6C5EC6dFb8996c9A6B828212022); + + // https://sepolia.arbiscan.io/address/0xc0Bac16A64FbAa7EE6483bD12a759e28cD13dcBe + address internal constant DEFAULT_A_TOKEN_IMPL = 0xc0Bac16A64FbAa7EE6483bD12a759e28cD13dcBe; + + // https://sepolia.arbiscan.io/address/0x486C2D3F59E4d72f3cAa301a7eF19E3db657F5b0 + address internal constant DEFAULT_VARIABLE_DEBT_TOKEN_IMPL = + 0x486C2D3F59E4d72f3cAa301a7eF19E3db657F5b0; + + // https://sepolia.arbiscan.io/address/0x2E45e7dCD1e94d8edf1605FfF4602912FDC662bC + address internal constant L2_ENCODER = 0x2E45e7dCD1e94d8edf1605FfF4602912FDC662bC; + + // https://sepolia.arbiscan.io/address/0x0a275C06556EeB3c7Ff2b0f0cfD462A7645772EF + address internal constant CONFIG_ENGINE = 0x0a275C06556EeB3c7Ff2b0f0cfD462A7645772EF; + + // https://sepolia.arbiscan.io/address/0xbB7492Cce831eE6F349960a6E2da8eadC4b50cA3 + address internal constant POOL_ADDRESSES_PROVIDER_REGISTRY = + 0xbB7492Cce831eE6F349960a6E2da8eadC4b50cA3; + + // https://sepolia.arbiscan.io/address/0xB90fa850a4af6D30feA8b41989eaAecDcA8fd414 + address internal constant UI_INCENTIVE_DATA_PROVIDER = 0xB90fa850a4af6D30feA8b41989eaAecDcA8fd414; + + // https://sepolia.arbiscan.io/address/0x97Cf44bF6a9A3D2B4F32b05C480dBEdC018F72A9 + address internal constant UI_POOL_DATA_PROVIDER = 0x97Cf44bF6a9A3D2B4F32b05C480dBEdC018F72A9; + + // https://sepolia.arbiscan.io/address/0x1Be33D186a081eFDf15310e4bdEd81E828C47f9b + address internal constant WALLET_BALANCE_PROVIDER = 0x1Be33D186a081eFDf15310e4bdEd81E828C47f9b; + + // https://sepolia.arbiscan.io/address/0x20040a64612555042335926d72B4E5F667a67fA1 + address internal constant WETH_GATEWAY = 0x20040a64612555042335926d72B4E5F667a67fA1; +} +library AaveV3ArbitrumSepoliaAssets { + // https://sepolia.arbiscan.io/address/0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d + address internal constant USDC_UNDERLYING = 0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d; + + uint8 internal constant USDC_DECIMALS = 6; + + // https://sepolia.arbiscan.io/address/0x460b97BD498E1157530AEb3086301d5225b91216 + address internal constant USDC_A_TOKEN = 0x460b97BD498E1157530AEb3086301d5225b91216; + + // https://sepolia.arbiscan.io/address/0x4fBE3A94C60A5085dA6a2D309965DcF34c36711d + address internal constant USDC_V_TOKEN = 0x4fBE3A94C60A5085dA6a2D309965DcF34c36711d; + + // https://sepolia.arbiscan.io/address/0x0153002d20B96532C639313c2d54c3dA09109309 + address internal constant USDC_ORACLE = 0x0153002d20B96532C639313c2d54c3dA09109309; + + // https://sepolia.arbiscan.io/address/0x5C0A210C9C0df2Ab147BDE7D9583c07cEb3131CD + address internal constant USDC_INTEREST_RATE_STRATEGY = + 0x5C0A210C9C0df2Ab147BDE7D9583c07cEb3131CD; + + // https://sepolia.arbiscan.io/address/0x1dF462e2712496373A347f8ad10802a5E95f053D + address internal constant WETH_UNDERLYING = 0x1dF462e2712496373A347f8ad10802a5E95f053D; + + uint8 internal constant WETH_DECIMALS = 18; + + // https://sepolia.arbiscan.io/address/0xf5f17EbE81E516Dc7cB38D61908EC252F150CE60 + address internal constant WETH_A_TOKEN = 0xf5f17EbE81E516Dc7cB38D61908EC252F150CE60; + + // https://sepolia.arbiscan.io/address/0x372eB464296D8D78acaa462b41eaaf2D3663dAD3 + address internal constant WETH_V_TOKEN = 0x372eB464296D8D78acaa462b41eaaf2D3663dAD3; + + // https://sepolia.arbiscan.io/address/0xd30e2101a97dcbAeBCBC04F14C3f624E67A35165 + address internal constant WETH_ORACLE = 0xd30e2101a97dcbAeBCBC04F14C3f624E67A35165; + + // https://sepolia.arbiscan.io/address/0x46d3a2A27E2c700d74f21AD3290A20cB8437F7b7 + address internal constant WETH_INTEREST_RATE_STRATEGY = + 0x46d3a2A27E2c700d74f21AD3290A20cB8437F7b7; +} diff --git a/plan/agw/research/preset-catalog-2026-10-15/AaveV3BaseSepolia.sol b/plan/agw/research/preset-catalog-2026-10-15/AaveV3BaseSepolia.sol new file mode 100644 index 00000000..66952969 --- /dev/null +++ b/plan/agw/research/preset-catalog-2026-10-15/AaveV3BaseSepolia.sol @@ -0,0 +1,227 @@ +// AUTOGENERATED - MANUAL CHANGES WILL BE REVERTED BY THE GENERATOR +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.0; + +import {IPoolAddressesProvider, IPool, IPoolConfigurator, IAaveOracle, IPoolDataProvider, IACLManager, ICollector} from './AaveV3.sol'; +library AaveV3BaseSepolia { + // https://sepolia.basescan.org/address/0xE4C23309117Aa30342BFaae6c95c6478e0A4Ad00 + IPoolAddressesProvider internal constant POOL_ADDRESSES_PROVIDER = + IPoolAddressesProvider(0xE4C23309117Aa30342BFaae6c95c6478e0A4Ad00); + + // https://sepolia.basescan.org/address/0x8bAB6d1b75f19e9eD9fCe8b9BD338844fF79aE27 + IPool internal constant POOL = IPool(0x8bAB6d1b75f19e9eD9fCe8b9BD338844fF79aE27); + + // https://sepolia.basescan.org/address/0x0Bf6bdFF4da24C272BC524d521Ab0db20601D384 + IPoolConfigurator internal constant POOL_CONFIGURATOR = + IPoolConfigurator(0x0Bf6bdFF4da24C272BC524d521Ab0db20601D384); + + // https://sepolia.basescan.org/address/0x943b0dE18d4abf4eF02A85912F8fc07684C141dF + IAaveOracle internal constant ORACLE = IAaveOracle(0x943b0dE18d4abf4eF02A85912F8fc07684C141dF); + + // https://sepolia.basescan.org/address/0x956DE559DFc27678FD69d4f49f485196b50BDD0F + address internal constant ACL_ADMIN = 0x956DE559DFc27678FD69d4f49f485196b50BDD0F; + + // https://sepolia.basescan.org/address/0x9f09F541Adf314341d8d45E5B18961147b9050E9 + IACLManager internal constant ACL_MANAGER = + IACLManager(0x9f09F541Adf314341d8d45E5B18961147b9050E9); + + // https://sepolia.basescan.org/address/0xBc9f5b7E248451CdD7cA54e717a2BFe1F32b566b + IPoolDataProvider internal constant AAVE_PROTOCOL_DATA_PROVIDER = + IPoolDataProvider(0xBc9f5b7E248451CdD7cA54e717a2BFe1F32b566b); + + // https://sepolia.basescan.org/address/0xE9fb54369E85b9714F9d86366D918c5C7C87783A + address internal constant POOL_IMPL = 0xE9fb54369E85b9714F9d86366D918c5C7C87783A; + + // https://sepolia.basescan.org/address/0x6fDdde45f777a4E461B0721a578b169b44579623 + address internal constant POOL_CONFIGURATOR_IMPL = 0x6fDdde45f777a4E461B0721a578b169b44579623; + + // https://sepolia.basescan.org/address/0x71B448405c803A3982aBa448133133D2DEAFBE5F + address internal constant DEFAULT_INCENTIVES_CONTROLLER = + 0x71B448405c803A3982aBa448133133D2DEAFBE5F; + + // https://sepolia.basescan.org/address/0x49ECA4d8e7EaE6a1e7c02516851fF9038b277e96 + address internal constant EMISSION_MANAGER = 0x49ECA4d8e7EaE6a1e7c02516851fF9038b277e96; + + // https://sepolia.basescan.org/address/0x6414DE3F58d54Fb90636e8393F065fDFe34Da420 + ICollector internal constant COLLECTOR = ICollector(0x6414DE3F58d54Fb90636e8393F065fDFe34Da420); + + // https://sepolia.basescan.org/address/0xF83D6A049FE62b8A1270525E1516F93b61C7D113 + address internal constant DEFAULT_A_TOKEN_IMPL = 0xF83D6A049FE62b8A1270525E1516F93b61C7D113; + + // https://sepolia.basescan.org/address/0x1A91BEfb27d0DB4FDE68D28bf0cbdD5BC9C5FdF2 + address internal constant DEFAULT_VARIABLE_DEBT_TOKEN_IMPL = + 0x1A91BEfb27d0DB4FDE68D28bf0cbdD5BC9C5FdF2; + + // https://sepolia.basescan.org/address/0x4Afb5ADe7Bd7a670B61f303ab0C740eE8350918f + address internal constant STATA_FACTORY = 0x4Afb5ADe7Bd7a670B61f303ab0C740eE8350918f; + + // https://sepolia.basescan.org/address/0xD3a3f523100e1eaa740A6eE72Ae94710A0fAcFCe + address internal constant CONFIG_ENGINE = 0xD3a3f523100e1eaa740A6eE72Ae94710A0fAcFCe; + + // https://sepolia.basescan.org/address/0x8eB0791E0981947df2eA074D2479dB9A258b0312 + address internal constant L2_ENCODER = 0x8eB0791E0981947df2eA074D2479dB9A258b0312; + + // https://sepolia.basescan.org/address/0x34473a6Ef69d92191d7b25352b5D266f3a5BAca2 + address internal constant POOL_ADDRESSES_PROVIDER_REGISTRY = + 0x34473a6Ef69d92191d7b25352b5D266f3a5BAca2; + + // https://sepolia.basescan.org/address/0xDB1412acf288D5bE057f8e90fd7b1BF4f84bB3B1 + address internal constant UI_INCENTIVE_DATA_PROVIDER = 0xDB1412acf288D5bE057f8e90fd7b1BF4f84bB3B1; + + // https://sepolia.basescan.org/address/0x3cB7B00B6C09B71998124196691e8bF2694De863 + address internal constant UI_POOL_DATA_PROVIDER = 0x3cB7B00B6C09B71998124196691e8bF2694De863; + + // https://sepolia.basescan.org/address/0x2c4D1F4EC7F4FfA09a5E1C9e74fD3A10f21Bd811 + address internal constant WALLET_BALANCE_PROVIDER = 0x2c4D1F4EC7F4FfA09a5E1C9e74fD3A10f21Bd811; + + // https://sepolia.basescan.org/address/0x0568130e794429D2eEBC4dafE18f25Ff1a1ed8b6 + address internal constant WETH_GATEWAY = 0x0568130e794429D2eEBC4dafE18f25Ff1a1ed8b6; +} +library AaveV3BaseSepoliaAssets { + // https://sepolia.basescan.org/address/0xba50Cd2A20f6DA35D788639E581bca8d0B5d4D5f + address internal constant USDC_UNDERLYING = 0xba50Cd2A20f6DA35D788639E581bca8d0B5d4D5f; + + uint8 internal constant USDC_DECIMALS = 6; + + // https://sepolia.basescan.org/address/0x10F1A9D11CDf50041f3f8cB7191CBE2f31750ACC + address internal constant USDC_A_TOKEN = 0x10F1A9D11CDf50041f3f8cB7191CBE2f31750ACC; + + // https://sepolia.basescan.org/address/0xFB3e85601b7fEb3691bbb8779Ef0E1069E347204 + address internal constant USDC_V_TOKEN = 0xFB3e85601b7fEb3691bbb8779Ef0E1069E347204; + + // https://sepolia.basescan.org/address/0xd30e2101a97dcbAeBCBC04F14C3f624E67A35165 + address internal constant USDC_ORACLE = 0xd30e2101a97dcbAeBCBC04F14C3f624E67A35165; + + // https://sepolia.basescan.org/address/0x705F7D9Ed0Ac3724eC974DaF6A099bA59d254b92 + address internal constant USDC_INTEREST_RATE_STRATEGY = + 0x705F7D9Ed0Ac3724eC974DaF6A099bA59d254b92; + + // https://sepolia.basescan.org/address/0xf430cb6E2b85f99222fBFA6dFEa18Ff60FA6B32a + address internal constant USDC_STATA_TOKEN = 0xf430cb6E2b85f99222fBFA6dFEa18Ff60FA6B32a; + + // https://sepolia.basescan.org/address/0x0a215D8ba66387DCA84B284D18c3B4ec3de6E54a + address internal constant USDT_UNDERLYING = 0x0a215D8ba66387DCA84B284D18c3B4ec3de6E54a; + + uint8 internal constant USDT_DECIMALS = 6; + + // https://sepolia.basescan.org/address/0xcE3CAae5Ed17A7AafCEEbc897DE843fA6CC0c018 + address internal constant USDT_A_TOKEN = 0xcE3CAae5Ed17A7AafCEEbc897DE843fA6CC0c018; + + // https://sepolia.basescan.org/address/0xE3C742c88EE6A610157C16b60bBDD62351daeE39 + address internal constant USDT_V_TOKEN = 0xE3C742c88EE6A610157C16b60bBDD62351daeE39; + + // https://sepolia.basescan.org/address/0x3ec8593F930EA45ea58c968260e6e9FF53FC934f + address internal constant USDT_ORACLE = 0x3ec8593F930EA45ea58c968260e6e9FF53FC934f; + + // https://sepolia.basescan.org/address/0x705F7D9Ed0Ac3724eC974DaF6A099bA59d254b92 + address internal constant USDT_INTEREST_RATE_STRATEGY = + 0x705F7D9Ed0Ac3724eC974DaF6A099bA59d254b92; + + // https://sepolia.basescan.org/address/0xf63dA51069FAe9448747FA425F8Cb84B0149eC0F + address internal constant USDT_STATA_TOKEN = 0xf63dA51069FAe9448747FA425F8Cb84B0149eC0F; + + // https://sepolia.basescan.org/address/0x54114591963CF60EF3aA63bEfD6eC263D98145a4 + address internal constant WBTC_UNDERLYING = 0x54114591963CF60EF3aA63bEfD6eC263D98145a4; + + uint8 internal constant WBTC_DECIMALS = 8; + + // https://sepolia.basescan.org/address/0x47Db195BAf46898302C06c31bCF46c01C64ACcF9 + address internal constant WBTC_A_TOKEN = 0x47Db195BAf46898302C06c31bCF46c01C64ACcF9; + + // https://sepolia.basescan.org/address/0x638291B5Ccb9fEd339FdD351Eb086e607fCA9561 + address internal constant WBTC_V_TOKEN = 0x638291B5Ccb9fEd339FdD351Eb086e607fCA9561; + + // https://sepolia.basescan.org/address/0x0FB99723Aee6f420beAD13e6bBB79b7E6F034298 + address internal constant WBTC_ORACLE = 0x0FB99723Aee6f420beAD13e6bBB79b7E6F034298; + + // https://sepolia.basescan.org/address/0x705F7D9Ed0Ac3724eC974DaF6A099bA59d254b92 + address internal constant WBTC_INTEREST_RATE_STRATEGY = + 0x705F7D9Ed0Ac3724eC974DaF6A099bA59d254b92; + + // https://sepolia.basescan.org/address/0x5d7538579560F5fdD54F9D264DBe0e697b5BF668 + address internal constant WBTC_STATA_TOKEN = 0x5d7538579560F5fdD54F9D264DBe0e697b5BF668; + + // https://sepolia.basescan.org/address/0x4200000000000000000000000000000000000006 + address internal constant WETH_UNDERLYING = 0x4200000000000000000000000000000000000006; + + uint8 internal constant WETH_DECIMALS = 18; + + // https://sepolia.basescan.org/address/0x73a5bB60b0B0fc35710DDc0ea9c407031E31Bdbb + address internal constant WETH_A_TOKEN = 0x73a5bB60b0B0fc35710DDc0ea9c407031E31Bdbb; + + // https://sepolia.basescan.org/address/0x562abf6562d6A2b165aDa02b5946bc3E7b4dD653 + address internal constant WETH_V_TOKEN = 0x562abf6562d6A2b165aDa02b5946bc3E7b4dD653; + + // https://sepolia.basescan.org/address/0x4aDC67696bA383F43DD60A9e78F2C97Fbbfc7cb1 + address internal constant WETH_ORACLE = 0x4aDC67696bA383F43DD60A9e78F2C97Fbbfc7cb1; + + // https://sepolia.basescan.org/address/0x705F7D9Ed0Ac3724eC974DaF6A099bA59d254b92 + address internal constant WETH_INTEREST_RATE_STRATEGY = + 0x705F7D9Ed0Ac3724eC974DaF6A099bA59d254b92; + + // https://sepolia.basescan.org/address/0xde7820fFb73059608928cb9e29F6EB1369Ad1342 + address internal constant WETH_STATA_TOKEN = 0xde7820fFb73059608928cb9e29F6EB1369Ad1342; + + // https://sepolia.basescan.org/address/0xD171b9694f7A2597Ed006D41f7509aaD4B485c4B + address internal constant cbETH_UNDERLYING = 0xD171b9694f7A2597Ed006D41f7509aaD4B485c4B; + + uint8 internal constant cbETH_DECIMALS = 18; + + // https://sepolia.basescan.org/address/0x9Fd6d1DBAd7c052e0c43f46df36eEc6a68814B63 + address internal constant cbETH_A_TOKEN = 0x9Fd6d1DBAd7c052e0c43f46df36eEc6a68814B63; + + // https://sepolia.basescan.org/address/0xa1a483652b157FF006292CDb0e9EB7FFad2a5142 + address internal constant cbETH_V_TOKEN = 0xa1a483652b157FF006292CDb0e9EB7FFad2a5142; + + // https://sepolia.basescan.org/address/0x3c65e28D357a37589e1C7C86044a9f44dDC17134 + address internal constant cbETH_ORACLE = 0x3c65e28D357a37589e1C7C86044a9f44dDC17134; + + // https://sepolia.basescan.org/address/0x705F7D9Ed0Ac3724eC974DaF6A099bA59d254b92 + address internal constant cbETH_INTEREST_RATE_STRATEGY = + 0x705F7D9Ed0Ac3724eC974DaF6A099bA59d254b92; + + // https://sepolia.basescan.org/address/0x9F56ff6c3441bb89eBFf1c0bc75D4096C33230d1 + address internal constant cbETH_STATA_TOKEN = 0x9F56ff6c3441bb89eBFf1c0bc75D4096C33230d1; + + // https://sepolia.basescan.org/address/0x810D46F9a9027E28F9B01F75E2bdde839dA61115 + address internal constant LINK_UNDERLYING = 0x810D46F9a9027E28F9B01F75E2bdde839dA61115; + + uint8 internal constant LINK_DECIMALS = 18; + + // https://sepolia.basescan.org/address/0x0aD46dE765522399d7b25B438b230A894d72272B + address internal constant LINK_A_TOKEN = 0x0aD46dE765522399d7b25B438b230A894d72272B; + + // https://sepolia.basescan.org/address/0xBA42C6752F347e3c22DD0A4e5578dCB0137C1325 + address internal constant LINK_V_TOKEN = 0xBA42C6752F347e3c22DD0A4e5578dCB0137C1325; + + // https://sepolia.basescan.org/address/0xb113F5A928BCfF189C998ab20d753a47F9dE5A61 + address internal constant LINK_ORACLE = 0xb113F5A928BCfF189C998ab20d753a47F9dE5A61; + + // https://sepolia.basescan.org/address/0x705F7D9Ed0Ac3724eC974DaF6A099bA59d254b92 + address internal constant LINK_INTEREST_RATE_STRATEGY = + 0x705F7D9Ed0Ac3724eC974DaF6A099bA59d254b92; + + // https://sepolia.basescan.org/address/0xFb3AB5ABd3dE4703C0F296B1fe6f5E570e1631Ff + address internal constant LINK_STATA_TOKEN = 0xFb3AB5ABd3dE4703C0F296B1fe6f5E570e1631Ff; +} +library AaveV3BaseSepoliaEModes { + uint8 internal constant NONE = 0; + + uint8 internal constant WETH_cbETH__WETH_cbETH = 1; +} +library AaveV3BaseSepoliaExternalLibraries { + // https://sepolia.basescan.org/address/0xE66AdcF153d0bD67a74e5d23e23F90b4011024EC + address internal constant FLASHLOAN_LOGIC = 0xE66AdcF153d0bD67a74e5d23e23F90b4011024EC; + + // https://sepolia.basescan.org/address/0x1Fb8f7C906cddD28B42ae6Eb76abC04A91188635 + address internal constant BORROW_LOGIC = 0x1Fb8f7C906cddD28B42ae6Eb76abC04A91188635; + + // https://sepolia.basescan.org/address/0x8dc095F287dBEBD9e15f75BB3DfBF18389BB8104 + address internal constant LIQUIDATION_LOGIC = 0x8dc095F287dBEBD9e15f75BB3DfBF18389BB8104; + + // https://sepolia.basescan.org/address/0x25Ed699a052B820d772765E26Ed4dD9f0A26F3E5 + address internal constant POOL_LOGIC = 0x25Ed699a052B820d772765E26Ed4dD9f0A26F3E5; + + // https://sepolia.basescan.org/address/0x33654b16A4De97bCE05d7dD06803Bf1066f3123C + address internal constant SUPPLY_LOGIC = 0x33654b16A4De97bCE05d7dD06803Bf1066f3123C; +} diff --git a/plan/agw/research/preset-catalog-2026-10-15/AaveV3Sepolia.sol b/plan/agw/research/preset-catalog-2026-10-15/AaveV3Sepolia.sol new file mode 100644 index 00000000..4e1fc549 --- /dev/null +++ b/plan/agw/research/preset-catalog-2026-10-15/AaveV3Sepolia.sol @@ -0,0 +1,261 @@ +// AUTOGENERATED - MANUAL CHANGES WILL BE REVERTED BY THE GENERATOR +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.0; + +import {IPoolAddressesProvider, IPool, IPoolConfigurator, IAaveOracle, IPoolDataProvider, IACLManager, ICollector} from './AaveV3.sol'; +library AaveV3Sepolia { + // https://sepolia.etherscan.io/address/0x012bAC54348C0E635dCAc9D5FB99f06F24136C9A + IPoolAddressesProvider internal constant POOL_ADDRESSES_PROVIDER = + IPoolAddressesProvider(0x012bAC54348C0E635dCAc9D5FB99f06F24136C9A); + + // https://sepolia.etherscan.io/address/0x6Ae43d3271ff6888e7Fc43Fd7321a503ff738951 + IPool internal constant POOL = IPool(0x6Ae43d3271ff6888e7Fc43Fd7321a503ff738951); + + // https://sepolia.etherscan.io/address/0x7Ee60D184C24Ef7AfC1Ec7Be59A0f448A0abd138 + IPoolConfigurator internal constant POOL_CONFIGURATOR = + IPoolConfigurator(0x7Ee60D184C24Ef7AfC1Ec7Be59A0f448A0abd138); + + // https://sepolia.etherscan.io/address/0x2da88497588bf89281816106C7259e31AF45a663 + IAaveOracle internal constant ORACLE = IAaveOracle(0x2da88497588bf89281816106C7259e31AF45a663); + + // https://sepolia.etherscan.io/address/0xfA0e305E0f46AB04f00ae6b5f4560d61a2183E00 + address internal constant ACL_ADMIN = 0xfA0e305E0f46AB04f00ae6b5f4560d61a2183E00; + + // https://sepolia.etherscan.io/address/0x7F2bE3b178deeFF716CD6Ff03Ef79A1dFf360ddD + IACLManager internal constant ACL_MANAGER = + IACLManager(0x7F2bE3b178deeFF716CD6Ff03Ef79A1dFf360ddD); + + // https://sepolia.etherscan.io/address/0x3e9708d80f7B3e43118013075F7e95CE3AB31F31 + IPoolDataProvider internal constant AAVE_PROTOCOL_DATA_PROVIDER = + IPoolDataProvider(0x3e9708d80f7B3e43118013075F7e95CE3AB31F31); + + // https://sepolia.etherscan.io/address/0x0562453c3DAFBB5e625483af58f4E6D668c44e19 + address internal constant POOL_IMPL = 0x0562453c3DAFBB5e625483af58f4E6D668c44e19; + + // https://sepolia.etherscan.io/address/0x63Dea961A0B2e2dF4F7A4bb61CBc39BF53A6eb32 + address internal constant POOL_CONFIGURATOR_IMPL = 0x63Dea961A0B2e2dF4F7A4bb61CBc39BF53A6eb32; + + // https://sepolia.etherscan.io/address/0x4DA5c4da71C5a167171cC839487536d86e083483 + address internal constant DEFAULT_INCENTIVES_CONTROLLER = + 0x4DA5c4da71C5a167171cC839487536d86e083483; + + // https://sepolia.etherscan.io/address/0x098a890BAfDf6FB4ACD24bF107D20EA15D229C62 + address internal constant EMISSION_MANAGER = 0x098a890BAfDf6FB4ACD24bF107D20EA15D229C62; + + // https://sepolia.etherscan.io/address/0x604264f8017fEF3b11B3dD63537CB501560380B5 + ICollector internal constant COLLECTOR = ICollector(0x604264f8017fEF3b11B3dD63537CB501560380B5); + + // https://sepolia.etherscan.io/address/0x48424f2779be0f03cDF6F02E17A591A9BF7AF89f + address internal constant DEFAULT_A_TOKEN_IMPL = 0x48424f2779be0f03cDF6F02E17A591A9BF7AF89f; + + // https://sepolia.etherscan.io/address/0x54bdE009156053108E73E2401aEA755e38f92098 + address internal constant DEFAULT_VARIABLE_DEBT_TOKEN_IMPL = + 0x54bdE009156053108E73E2401aEA755e38f92098; + + // https://sepolia.etherscan.io/address/0xC959483DBa39aa9E78757139af0e9a2EDEb3f42D + address internal constant FAUCET = 0xC959483DBa39aa9E78757139af0e9a2EDEb3f42D; + + // https://sepolia.etherscan.io/address/0xBA25de9a7DC623B30799F33B770d31B44c2C3b77 + address internal constant UI_INCENTIVE_DATA_PROVIDER = 0xBA25de9a7DC623B30799F33B770d31B44c2C3b77; + + // https://sepolia.etherscan.io/address/0x69529987FA4A075D0C00B0128fa848dc9ebbE9CE + address internal constant UI_POOL_DATA_PROVIDER = 0x69529987FA4A075D0C00B0128fa848dc9ebbE9CE; + + // https://sepolia.etherscan.io/address/0xCD4e0d6D2b1252E2A709B8aE97DBA31164C5a709 + address internal constant WALLET_BALANCE_PROVIDER = 0xCD4e0d6D2b1252E2A709B8aE97DBA31164C5a709; + + // https://sepolia.etherscan.io/address/0x387d311e47e80b498169e6fb51d3193167d89F7D + address internal constant WETH_GATEWAY = 0x387d311e47e80b498169e6fb51d3193167d89F7D; + + // https://sepolia.etherscan.io/address/0xd210dFB43B694430B8d31762B5199e30c31266C8 + address internal constant LEGACY_STATIC_A_TOKEN_FACTORY = + 0xd210dFB43B694430B8d31762B5199e30c31266C8; + + // https://sepolia.etherscan.io/address/0x69B9843A16a6E9933125EBD97659BA3CCbE2Ef8A + address internal constant UI_GHO_DATA_PROVIDER = 0x69B9843A16a6E9933125EBD97659BA3CCbE2Ef8A; +} +library AaveV3SepoliaAssets { + // https://sepolia.etherscan.io/address/0xFF34B3d4Aee8ddCd6F9AFFFB6Fe49bD371b8a357 + address internal constant DAI_UNDERLYING = 0xFF34B3d4Aee8ddCd6F9AFFFB6Fe49bD371b8a357; + + uint8 internal constant DAI_DECIMALS = 18; + + // https://sepolia.etherscan.io/address/0x29598b72eb5CeBd806C5dCD549490FdA35B13cD8 + address internal constant DAI_A_TOKEN = 0x29598b72eb5CeBd806C5dCD549490FdA35B13cD8; + + // https://sepolia.etherscan.io/address/0x22675C506A8FC26447aFFfa33640f6af5d4D4cF0 + address internal constant DAI_V_TOKEN = 0x22675C506A8FC26447aFFfa33640f6af5d4D4cF0; + + // https://sepolia.etherscan.io/address/0x9aF11c35c5d3Ae182C0050438972aac4376f9516 + address internal constant DAI_ORACLE = 0x9aF11c35c5d3Ae182C0050438972aac4376f9516; + + // https://sepolia.etherscan.io/address/0xA813CC4d67821fbAcF24659e414A1Cf6c551373c + address internal constant DAI_INTEREST_RATE_STRATEGY = 0xA813CC4d67821fbAcF24659e414A1Cf6c551373c; + + // https://sepolia.etherscan.io/address/0xDE46e43F46ff74A23a65EBb0580cbe3dFE684a17 + address internal constant DAI_STATIC_A_TOKEN = 0xDE46e43F46ff74A23a65EBb0580cbe3dFE684a17; + + // https://sepolia.etherscan.io/address/0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5 + address internal constant LINK_UNDERLYING = 0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5; + + uint8 internal constant LINK_DECIMALS = 18; + + // https://sepolia.etherscan.io/address/0x3FfAf50D4F4E96eB78f2407c090b72e86eCaed24 + address internal constant LINK_A_TOKEN = 0x3FfAf50D4F4E96eB78f2407c090b72e86eCaed24; + + // https://sepolia.etherscan.io/address/0x34a4d932E722b9dFb492B9D8131127690CE2430B + address internal constant LINK_V_TOKEN = 0x34a4d932E722b9dFb492B9D8131127690CE2430B; + + // https://sepolia.etherscan.io/address/0x14fC51b7df22b4D393cD45504B9f0A3002A63F3F + address internal constant LINK_ORACLE = 0x14fC51b7df22b4D393cD45504B9f0A3002A63F3F; + + // https://sepolia.etherscan.io/address/0xCA30c502d52F905FB3D04eE60cA48F5A1A89f8dB + address internal constant LINK_INTEREST_RATE_STRATEGY = + 0xCA30c502d52F905FB3D04eE60cA48F5A1A89f8dB; + + // https://sepolia.etherscan.io/address/0x8227a989709a757f25dF251C3C3e71CA38627836 + address internal constant LINK_STATIC_A_TOKEN = 0x8227a989709a757f25dF251C3C3e71CA38627836; + + // https://sepolia.etherscan.io/address/0x94a9D9AC8a22534E3FaCa9F4e7F2E2cf85d5E4C8 + address internal constant USDC_UNDERLYING = 0x94a9D9AC8a22534E3FaCa9F4e7F2E2cf85d5E4C8; + + uint8 internal constant USDC_DECIMALS = 6; + + // https://sepolia.etherscan.io/address/0x16dA4541aD1807f4443d92D26044C1147406EB80 + address internal constant USDC_A_TOKEN = 0x16dA4541aD1807f4443d92D26044C1147406EB80; + + // https://sepolia.etherscan.io/address/0x36B5dE936eF1710E1d22EabE5231b28581a92ECc + address internal constant USDC_V_TOKEN = 0x36B5dE936eF1710E1d22EabE5231b28581a92ECc; + + // https://sepolia.etherscan.io/address/0x98458D6A99489F15e6eB5aFa67ACFAcf6F211051 + address internal constant USDC_ORACLE = 0x98458D6A99489F15e6eB5aFa67ACFAcf6F211051; + + // https://sepolia.etherscan.io/address/0x5CB1008969a2d5FAcE8eF32732e6A306d0D0EF2A + address internal constant USDC_INTEREST_RATE_STRATEGY = + 0x5CB1008969a2d5FAcE8eF32732e6A306d0D0EF2A; + + // https://sepolia.etherscan.io/address/0x8A88124522dbBF1E56352ba3DE1d9F78C143751e + address internal constant USDC_STATIC_A_TOKEN = 0x8A88124522dbBF1E56352ba3DE1d9F78C143751e; + + // https://sepolia.etherscan.io/address/0x29f2D40B0605204364af54EC677bD022dA425d03 + address internal constant WBTC_UNDERLYING = 0x29f2D40B0605204364af54EC677bD022dA425d03; + + uint8 internal constant WBTC_DECIMALS = 8; + + // https://sepolia.etherscan.io/address/0x1804Bf30507dc2EB3bDEbbbdd859991EAeF6EefF + address internal constant WBTC_A_TOKEN = 0x1804Bf30507dc2EB3bDEbbbdd859991EAeF6EefF; + + // https://sepolia.etherscan.io/address/0xEB016dFd303F19fbDdFb6300eB4AeB2DA7Ceac37 + address internal constant WBTC_V_TOKEN = 0xEB016dFd303F19fbDdFb6300eB4AeB2DA7Ceac37; + + // https://sepolia.etherscan.io/address/0x784B90bA1E9a8cf3C9939c2e072F058B024C4b8a + address internal constant WBTC_ORACLE = 0x784B90bA1E9a8cf3C9939c2e072F058B024C4b8a; + + // https://sepolia.etherscan.io/address/0xCA30c502d52F905FB3D04eE60cA48F5A1A89f8dB + address internal constant WBTC_INTEREST_RATE_STRATEGY = + 0xCA30c502d52F905FB3D04eE60cA48F5A1A89f8dB; + + // https://sepolia.etherscan.io/address/0x131a121bda71ED810bCAf2aC9079214925e59C18 + address internal constant WBTC_STATIC_A_TOKEN = 0x131a121bda71ED810bCAf2aC9079214925e59C18; + + // https://sepolia.etherscan.io/address/0xC558DBdd856501FCd9aaF1E62eae57A9F0629a3c + address internal constant WETH_UNDERLYING = 0xC558DBdd856501FCd9aaF1E62eae57A9F0629a3c; + + uint8 internal constant WETH_DECIMALS = 18; + + // https://sepolia.etherscan.io/address/0x5b071b590a59395fE4025A0Ccc1FcC931AAc1830 + address internal constant WETH_A_TOKEN = 0x5b071b590a59395fE4025A0Ccc1FcC931AAc1830; + + // https://sepolia.etherscan.io/address/0x22a35DB253f4F6D0029025D6312A3BdAb20C2c6A + address internal constant WETH_V_TOKEN = 0x22a35DB253f4F6D0029025D6312A3BdAb20C2c6A; + + // https://sepolia.etherscan.io/address/0xDde0E8E6d3653614878Bf5009EDC317BC129fE2F + address internal constant WETH_ORACLE = 0xDde0E8E6d3653614878Bf5009EDC317BC129fE2F; + + // https://sepolia.etherscan.io/address/0xCA30c502d52F905FB3D04eE60cA48F5A1A89f8dB + address internal constant WETH_INTEREST_RATE_STRATEGY = + 0xCA30c502d52F905FB3D04eE60cA48F5A1A89f8dB; + + // https://sepolia.etherscan.io/address/0x162B500569F42D9eCe937e6a61EDfef660A12E98 + address internal constant WETH_STATIC_A_TOKEN = 0x162B500569F42D9eCe937e6a61EDfef660A12E98; + + // https://sepolia.etherscan.io/address/0xaA8E23Fb1079EA71e0a56F48a2aA51851D8433D0 + address internal constant USDT_UNDERLYING = 0xaA8E23Fb1079EA71e0a56F48a2aA51851D8433D0; + + uint8 internal constant USDT_DECIMALS = 6; + + // https://sepolia.etherscan.io/address/0xAF0F6e8b0Dc5c913bbF4d14c22B4E78Dd14310B6 + address internal constant USDT_A_TOKEN = 0xAF0F6e8b0Dc5c913bbF4d14c22B4E78Dd14310B6; + + // https://sepolia.etherscan.io/address/0x9844386d29EEd970B9F6a2B9a676083b0478210e + address internal constant USDT_V_TOKEN = 0x9844386d29EEd970B9F6a2B9a676083b0478210e; + + // https://sepolia.etherscan.io/address/0x4e86D3Aa271Fa418F38D7262fdBa2989C94aa5Ba + address internal constant USDT_ORACLE = 0x4e86D3Aa271Fa418F38D7262fdBa2989C94aa5Ba; + + // https://sepolia.etherscan.io/address/0x5CB1008969a2d5FAcE8eF32732e6A306d0D0EF2A + address internal constant USDT_INTEREST_RATE_STRATEGY = + 0x5CB1008969a2d5FAcE8eF32732e6A306d0D0EF2A; + + // https://sepolia.etherscan.io/address/0x978206fAe13faF5a8d293FB614326B237684B750 + address internal constant USDT_STATIC_A_TOKEN = 0x978206fAe13faF5a8d293FB614326B237684B750; + + // https://sepolia.etherscan.io/address/0x88541670E55cC00bEEFD87eB59EDd1b7C511AC9a + address internal constant AAVE_UNDERLYING = 0x88541670E55cC00bEEFD87eB59EDd1b7C511AC9a; + + uint8 internal constant AAVE_DECIMALS = 18; + + // https://sepolia.etherscan.io/address/0x6b8558764d3b7572136F17174Cb9aB1DDc7E1259 + address internal constant AAVE_A_TOKEN = 0x6b8558764d3b7572136F17174Cb9aB1DDc7E1259; + + // https://sepolia.etherscan.io/address/0xf12fdFc4c631F6D361b48723c2F2800b84B519e6 + address internal constant AAVE_V_TOKEN = 0xf12fdFc4c631F6D361b48723c2F2800b84B519e6; + + // https://sepolia.etherscan.io/address/0xda678Ef100c13504edDb8a228A1e8e4CB139f189 + address internal constant AAVE_ORACLE = 0xda678Ef100c13504edDb8a228A1e8e4CB139f189; + + // https://sepolia.etherscan.io/address/0xCA30c502d52F905FB3D04eE60cA48F5A1A89f8dB + address internal constant AAVE_INTEREST_RATE_STRATEGY = + 0xCA30c502d52F905FB3D04eE60cA48F5A1A89f8dB; + + // https://sepolia.etherscan.io/address/0x56771cEF0cb422e125564CcCC98BB05fdc718E77 + address internal constant AAVE_STATIC_A_TOKEN = 0x56771cEF0cb422e125564CcCC98BB05fdc718E77; + + // https://sepolia.etherscan.io/address/0x6d906e526a4e2Ca02097BA9d0caA3c382F52278E + address internal constant EURS_UNDERLYING = 0x6d906e526a4e2Ca02097BA9d0caA3c382F52278E; + + uint8 internal constant EURS_DECIMALS = 2; + + // https://sepolia.etherscan.io/address/0xB20691021F9AcED8631eDaa3c0Cd2949EB45662D + address internal constant EURS_A_TOKEN = 0xB20691021F9AcED8631eDaa3c0Cd2949EB45662D; + + // https://sepolia.etherscan.io/address/0x94482C7A7477196259D8a0f74fB853277Fa5a75b + address internal constant EURS_V_TOKEN = 0x94482C7A7477196259D8a0f74fB853277Fa5a75b; + + // https://sepolia.etherscan.io/address/0xCbE15C1f40f1D7eE1De3756D1557d5Fdc2A50bBD + address internal constant EURS_ORACLE = 0xCbE15C1f40f1D7eE1De3756D1557d5Fdc2A50bBD; + + // https://sepolia.etherscan.io/address/0x5CB1008969a2d5FAcE8eF32732e6A306d0D0EF2A + address internal constant EURS_INTEREST_RATE_STRATEGY = + 0x5CB1008969a2d5FAcE8eF32732e6A306d0D0EF2A; + + // https://sepolia.etherscan.io/address/0x72B49a461900e11632C95dfa563e7173438D4e3E + address internal constant EURS_STATIC_A_TOKEN = 0x72B49a461900e11632C95dfa563e7173438D4e3E; + + // https://sepolia.etherscan.io/address/0xc4bF5CbDaBE595361438F8c6a187bDc330539c60 + address internal constant GHO_UNDERLYING = 0xc4bF5CbDaBE595361438F8c6a187bDc330539c60; + + uint8 internal constant GHO_DECIMALS = 18; + + // https://sepolia.etherscan.io/address/0xd190eF37dB51Bb955A680fF1A85763CC72d083D4 + address internal constant GHO_A_TOKEN = 0xd190eF37dB51Bb955A680fF1A85763CC72d083D4; + + // https://sepolia.etherscan.io/address/0x67ae46EF043F7A4508BD1d6B94DB6c33F0915844 + address internal constant GHO_V_TOKEN = 0x67ae46EF043F7A4508BD1d6B94DB6c33F0915844; + + // https://sepolia.etherscan.io/address/0x00f7fecFAEbEd9499e1f3f9d04E755a21E5fc47C + address internal constant GHO_ORACLE = 0x00f7fecFAEbEd9499e1f3f9d04E755a21E5fc47C; + + // https://sepolia.etherscan.io/address/0x521247B4d0a51E71DE580dA2cBF99EB40a44b3Bf + address internal constant GHO_INTEREST_RATE_STRATEGY = 0x521247B4d0a51E71DE580dA2cBF99EB40a44b3Bf; +} diff --git a/plan/agw/research/preset-catalog-2026-10-15/Comptroller.sol b/plan/agw/research/preset-catalog-2026-10-15/Comptroller.sol new file mode 100644 index 00000000..f429dd34 --- /dev/null +++ b/plan/agw/research/preset-catalog-2026-10-15/Comptroller.sol @@ -0,0 +1,1418 @@ +// SPDX-License-Identifier: BSD-3-Clause +pragma solidity 0.8.19; + +import "./MToken.sol"; +import "./TokenErrorReporter.sol"; +import "./oracles/PriceOracle.sol"; +import "./ComptrollerInterface.sol"; +import "./ComptrollerStorage.sol"; +import "./Unitroller.sol"; + +/** + * @title Moonwell's Comptroller Contract + * @author Moonwell + */ +contract Comptroller is + ComptrollerV2Storage, + ComptrollerInterface, + ComptrollerErrorReporter, + ExponentialNoError +{ + /// @notice Emitted when an admin supports a market + event MarketListed(MToken mToken); + + /// @notice Emitted when an account enters a market + event MarketEntered(MToken mToken, address account); + + /// @notice Emitted when an account exits a market + event MarketExited(MToken mToken, address account); + + /// @notice Emitted when close factor is changed by admin + event NewCloseFactor( + uint oldCloseFactorMantissa, + uint newCloseFactorMantissa + ); + + /// @notice Emitted when a collateral factor is changed by admin + event NewCollateralFactor( + MToken mToken, + uint oldCollateralFactorMantissa, + uint newCollateralFactorMantissa + ); + + /// @notice Emitted when liquidation incentive is changed by admin + event NewLiquidationIncentive( + uint oldLiquidationIncentiveMantissa, + uint newLiquidationIncentiveMantissa + ); + + /// @notice Emitted when price oracle is changed + event NewPriceOracle( + PriceOracle oldPriceOracle, + PriceOracle newPriceOracle + ); + + /// @notice Emitted when pause guardian is changed + event NewPauseGuardian(address oldPauseGuardian, address newPauseGuardian); + + /// @notice Emitted when an action is paused globally + event ActionPaused(string action, bool pauseState); + + /// @notice Emitted when an action is paused on a market + event ActionPaused(MToken mToken, string action, bool pauseState); + + /// @notice Emitted when borrow cap for a mToken is changed + event NewBorrowCap(MToken indexed mToken, uint newBorrowCap); + + /// @notice Emitted when borrow cap guardian is changed + event NewBorrowCapGuardian( + address oldBorrowCapGuardian, + address newBorrowCapGuardian + ); + + /// @notice Emitted when supply cap for a mToken is changed + event NewSupplyCap(MToken indexed mToken, uint newSupplyCap); + + /// @notice Emitted when supply cap guardian is changed + event NewSupplyCapGuardian( + address oldSupplyCapGuardian, + address newSupplyCapGuardian + ); + + /// @notice Emitted when reward distributor is changed + event NewRewardDistributor( + MultiRewardDistributor oldRewardDistributor, + MultiRewardDistributor newRewardDistributor + ); + + // closeFactorMantissa must be strictly greater than this value + uint internal constant closeFactorMinMantissa = 0.05e18; // 0.05 + + // closeFactorMantissa must not exceed this value + uint internal constant closeFactorMaxMantissa = 0.9e18; // 0.9 + + // No collateralFactorMantissa may exceed this value + uint internal constant collateralFactorMaxMantissa = 0.9e18; // 0.9 + + constructor() { + admin = msg.sender; + } + + /*** Assets You Are In ***/ + + /** + * @notice Returns the assets an account has entered + * @param account The address of the account to pull assets for + * @return A dynamic list with the assets the account has entered + */ + function getAssetsIn( + address account + ) external view returns (MToken[] memory) { + MToken[] memory assetsIn = accountAssets[account]; + + return assetsIn; + } + + /** + * @notice Returns whether the given account is entered in the given asset + * @param account The address of the account to check + * @param mToken The mToken to check + * @return True if the account is in the asset, otherwise false. + */ + function checkMembership( + address account, + MToken mToken + ) external view returns (bool) { + return markets[address(mToken)].accountMembership[account]; + } + + /** + * @notice Add assets to be included in account liquidity calculation + * @param mTokens The list of addresses of the mToken markets to be enabled + * @return Success indicator for whether each corresponding market was entered + */ + function enterMarkets( + address[] memory mTokens + ) public override returns (uint[] memory) { + uint len = mTokens.length; + + uint[] memory results = new uint[](len); + for (uint i = 0; i < len; i++) { + MToken mToken = MToken(mTokens[i]); + + results[i] = uint(addToMarketInternal(mToken, msg.sender)); + } + + return results; + } + + /** + * @notice Add the market to the borrower's "assets in" for liquidity calculations + * @param mToken The market to enter + * @param borrower The address of the account to modify + * @return Success indicator for whether the market was entered + */ + function addToMarketInternal( + MToken mToken, + address borrower + ) internal returns (Error) { + Market storage marketToJoin = markets[address(mToken)]; + + if (!marketToJoin.isListed) { + // market is not listed, cannot join + return Error.MARKET_NOT_LISTED; + } + + if (marketToJoin.accountMembership[borrower] == true) { + // already joined + return Error.NO_ERROR; + } + + // survived the gauntlet, add to list + // NOTE: we store these somewhat redundantly as a significant optimization + // this avoids having to iterate through the list for the most common use cases + // that is, only when we need to perform liquidity checks + // and not whenever we want to check if an account is in a particular market + marketToJoin.accountMembership[borrower] = true; + accountAssets[borrower].push(mToken); + + emit MarketEntered(mToken, borrower); + + return Error.NO_ERROR; + } + + /** + * @notice Removes asset from sender's account liquidity calculation + * @dev Sender must not have an outstanding borrow balance in the asset, + * or be providing necessary collateral for an outstanding borrow. + * @param mTokenAddress The address of the asset to be removed + * @return Whether or not the account successfully exited the market + */ + function exitMarket( + address mTokenAddress + ) external override returns (uint) { + MToken mToken = MToken(mTokenAddress); + /* Get sender tokensHeld and amountOwed underlying from the mToken */ + (uint oErr, uint tokensHeld, uint amountOwed, ) = mToken + .getAccountSnapshot(msg.sender); + require(oErr == 0, "exitMarket: getAccountSnapshot failed"); // semi-opaque error code + + /* Fail if the sender has a borrow balance */ + if (amountOwed != 0) { + return + fail( + Error.NONZERO_BORROW_BALANCE, + FailureInfo.EXIT_MARKET_BALANCE_OWED + ); + } + + /* Fail if the sender is not permitted to redeem all of their tokens */ + uint allowed = redeemAllowedInternal( + mTokenAddress, + msg.sender, + tokensHeld + ); + if (allowed != 0) { + return + failOpaque( + Error.REJECTION, + FailureInfo.EXIT_MARKET_REJECTION, + allowed + ); + } + + Market storage marketToExit = markets[address(mToken)]; + + /* Return true if the sender is not already ‘in’ the market */ + if (!marketToExit.accountMembership[msg.sender]) { + return uint(Error.NO_ERROR); + } + + /* Set mToken account membership to false */ + delete marketToExit.accountMembership[msg.sender]; + + /* Delete mToken from the account’s list of assets */ + // load into memory for faster iteration + MToken[] memory userAssetList = accountAssets[msg.sender]; + uint len = userAssetList.length; + uint assetIndex = len; + for (uint i = 0; i < len; i++) { + if (userAssetList[i] == mToken) { + assetIndex = i; + break; + } + } + + // We *must* have found the asset in the list or our redundant data structure is broken + assert(assetIndex < len); + + // copy last item in list to location of item to be removed, reduce length by 1 + MToken[] storage storedList = accountAssets[msg.sender]; + storedList[assetIndex] = storedList[storedList.length - 1]; + storedList.pop(); + + emit MarketExited(mToken, msg.sender); + + return uint(Error.NO_ERROR); + } + + /*** Policy Hooks ***/ + + /** + * @notice Checks if the account should be allowed to mint tokens in the given market + * @param mToken The market to verify the mint against + * @param minter The account which would get the minted tokens + * @param mintAmount The amount of underlying being supplied to the market in exchange for tokens + * @return 0 if the mint is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) + */ + function mintAllowed( + address mToken, + address minter, + uint mintAmount + ) external override returns (uint) { + // Pausing is a very serious situation - we revert to sound the alarms + require(!mintGuardianPaused[mToken], "mint is paused"); + + // Shh - currently unused + mintAmount; + + if (!markets[mToken].isListed) { + return uint(Error.MARKET_NOT_LISTED); + } + + uint supplyCap = supplyCaps[mToken]; + // Supply cap of 0 corresponds to unlimited supplying + if (supplyCap != 0) { + uint totalCash = MToken(mToken).getCash(); + uint totalBorrows = MToken(mToken).totalBorrows(); + uint totalReserves = MToken(mToken).totalReserves(); + // totalSupplies = totalCash + totalBorrows - totalReserves + uint totalSupplies = sub_( + add_(totalCash, totalBorrows), + totalReserves + ); + + uint nextTotalSupplies = add_(totalSupplies, mintAmount); + require(nextTotalSupplies < supplyCap, "market supply cap reached"); + } + + // Keep the flywheel moving + updateAndDistributeSupplierRewardsForToken(mToken, minter); + return uint(Error.NO_ERROR); + } + + /** + * @notice Checks if the account should be allowed to redeem tokens in the given market + * @param mToken The market to verify the redeem against + * @param redeemer The account which would redeem the tokens + * @param redeemTokens The number of mTokens to exchange for the underlying asset in the market + * @return 0 if the redeem is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) + */ + function redeemAllowed( + address mToken, + address redeemer, + uint redeemTokens + ) external override returns (uint) { + uint allowed = redeemAllowedInternal(mToken, redeemer, redeemTokens); + if (allowed != uint(Error.NO_ERROR)) { + return allowed; + } + + // Keep the flywheel moving + updateAndDistributeSupplierRewardsForToken(mToken, redeemer); + + return uint(Error.NO_ERROR); + } + + function redeemAllowedInternal( + address mToken, + address redeemer, + uint redeemTokens + ) internal view returns (uint) { + if (!markets[mToken].isListed) { + return uint(Error.MARKET_NOT_LISTED); + } + + /* If the redeemer is not 'in' the market, then we can bypass the liquidity check */ + if (!markets[mToken].accountMembership[redeemer]) { + return uint(Error.NO_ERROR); + } + + /* Otherwise, perform a hypothetical liquidity check to guard against shortfall */ + (Error err, , uint shortfall) = getHypotheticalAccountLiquidityInternal( + redeemer, + MToken(mToken), + redeemTokens, + 0 + ); + if (err != Error.NO_ERROR) { + return uint(err); + } + if (shortfall > 0) { + return uint(Error.INSUFFICIENT_LIQUIDITY); + } + + return uint(Error.NO_ERROR); + } + + /** + * @notice Validates redeem and reverts on rejection. May emit logs. + * @param mToken Asset being redeemed + * @param redeemer The address redeeming the tokens + * @param redeemAmount The amount of the underlying asset being redeemed + * @param redeemTokens The number of tokens being redeemed + */ + function redeemVerify( + address mToken, + address redeemer, + uint redeemAmount, + uint redeemTokens + ) external pure override { + // Shh - currently unused + mToken; + redeemer; + + // Require tokens is zero or amount is also zero + if (redeemTokens == 0 && redeemAmount > 0) { + revert("redeemTokens zero"); + } + } + + /** + * @notice Checks if the account should be allowed to borrow the underlying asset of the given market + * @param mToken The market to verify the borrow against + * @param borrower The account which would borrow the asset + * @param borrowAmount The amount of underlying the account would borrow + * @return 0 if the borrow is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) + */ + function borrowAllowed( + address mToken, + address borrower, + uint borrowAmount + ) external override returns (uint) { + // Pausing is a very serious situation - we revert to sound the alarms + require(!borrowGuardianPaused[mToken], "borrow is paused"); + + if (!markets[mToken].isListed) { + return uint(Error.MARKET_NOT_LISTED); + } + + if (!markets[mToken].accountMembership[borrower]) { + // only mTokens may call borrowAllowed if borrower not in market + require(msg.sender == mToken, "sender must be mToken"); + + // attempt to add borrower to the market + Error addToMarketErr = addToMarketInternal( + MToken(msg.sender), + borrower + ); + if (addToMarketErr != Error.NO_ERROR) { + return uint(addToMarketErr); + } + + // it should be impossible to break the important invariant + assert(markets[mToken].accountMembership[borrower]); + } + + if (oracle.getUnderlyingPrice(MToken(mToken)) == 0) { + return uint(Error.PRICE_ERROR); + } + + uint borrowCap = borrowCaps[mToken]; + // Borrow cap of 0 corresponds to unlimited borrowing + if (borrowCap != 0) { + uint totalBorrows = MToken(mToken).totalBorrows(); + uint nextTotalBorrows = add_(totalBorrows, borrowAmount); + require(nextTotalBorrows < borrowCap, "market borrow cap reached"); + } + + (Error err, , uint shortfall) = getHypotheticalAccountLiquidityInternal( + borrower, + MToken(mToken), + 0, + borrowAmount + ); + if (err != Error.NO_ERROR) { + return uint(err); + } + if (shortfall > 0) { + return uint(Error.INSUFFICIENT_LIQUIDITY); + } + + // Keep the flywheel moving + updateAndDistributeBorrowerRewardsForToken(mToken, borrower); + + return uint(Error.NO_ERROR); + } + + /** + * @notice Checks if the account should be allowed to repay a borrow in the given market + * @param mToken The market to verify the repay against + * @param payer The account which would repay the asset + * @param borrower The account which would borrowed the asset + * @param repayAmount The amount of the underlying asset the account would repay + * @return 0 if the repay is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) + */ + function repayBorrowAllowed( + address mToken, + address payer, + address borrower, + uint repayAmount + ) external override returns (uint) { + // Shh - currently unused + payer; + borrower; + repayAmount; + + if (!markets[mToken].isListed) { + return uint(Error.MARKET_NOT_LISTED); + } + + // Keep the flywheel moving + updateAndDistributeBorrowerRewardsForToken(mToken, borrower); + + return uint(Error.NO_ERROR); + } + + /** + * @notice Checks if the liquidation should be allowed to occur + * @param mTokenBorrowed Asset which was borrowed by the borrower + * @param mTokenCollateral Asset which was used as collateral and will be seized + * @param liquidator The address repaying the borrow and seizing the collateral + * @param borrower The address of the borrower + * @param repayAmount The amount of underlying being repaid + */ + function liquidateBorrowAllowed( + address mTokenBorrowed, + address mTokenCollateral, + address liquidator, + address borrower, + uint repayAmount + ) external view override returns (uint) { + // Shh - currently unused + liquidator; + + if ( + !markets[mTokenBorrowed].isListed || + !markets[mTokenCollateral].isListed + ) { + return uint(Error.MARKET_NOT_LISTED); + } + + /* The borrower must have shortfall in order to be liquidatable */ + (Error err, , uint shortfall) = getAccountLiquidityInternal(borrower); + if (err != Error.NO_ERROR) { + return uint(err); + } + if (shortfall == 0) { + return uint(Error.INSUFFICIENT_SHORTFALL); + } + + /* The liquidator may not repay more than what is allowed by the closeFactor */ + uint borrowBalance = MToken(mTokenBorrowed).borrowBalanceStored( + borrower + ); + uint maxClose = mul_ScalarTruncate( + Exp({mantissa: closeFactorMantissa}), + borrowBalance + ); + if (repayAmount > maxClose) { + return uint(Error.TOO_MUCH_REPAY); + } + + return uint(Error.NO_ERROR); + } + + /** + * @notice Checks if the seizing of assets should be allowed to occur + * @param mTokenCollateral Asset which was used as collateral and will be seized + * @param mTokenBorrowed Asset which was borrowed by the borrower + * @param liquidator The address repaying the borrow and seizing the collateral + * @param borrower The address of the borrower + * @param seizeTokens The number of collateral tokens to seize + */ + function seizeAllowed( + address mTokenCollateral, + address mTokenBorrowed, + address liquidator, + address borrower, + uint seizeTokens + ) external override returns (uint) { + // Pausing is a very serious situation - we revert to sound the alarms + require(!seizeGuardianPaused, "seize is paused"); + + // Shh - currently unused + seizeTokens; + + if ( + !markets[mTokenCollateral].isListed || + !markets[mTokenBorrowed].isListed + ) { + return uint(Error.MARKET_NOT_LISTED); + } + + if ( + MToken(mTokenCollateral).comptroller() != + MToken(mTokenBorrowed).comptroller() + ) { + return uint(Error.COMPTROLLER_MISMATCH); + } + + // Keep the flywheel moving + // Note: We don't update borrower indices here because as part of liquidations + // repayBorrowFresh is called, which in turn calls `borrowAllow`, which updates + // the liquidated borrower's indices. + updateAndDistributeSupplierRewardsForToken(mTokenCollateral, borrower); + updateAndDistributeSupplierRewardsForToken( + mTokenCollateral, + liquidator + ); + + return uint(Error.NO_ERROR); + } + + /** + * @notice Checks if the account should be allowed to transfer tokens in the given market + * @param mToken The market to verify the transfer against + * @param src The account which sources the tokens + * @param dst The account which receives the tokens + * @param transferTokens The number of mTokens to transfer + * @return 0 if the transfer is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) + */ + function transferAllowed( + address mToken, + address src, + address dst, + uint transferTokens + ) external override returns (uint) { + // Pausing is a very serious situation - we revert to sound the alarms + require(!transferGuardianPaused, "transfer is paused"); + + // Currently the only consideration is whether or not + // the src is allowed to redeem this many tokens + uint allowed = redeemAllowedInternal(mToken, src, transferTokens); + if (allowed != uint(Error.NO_ERROR)) { + return allowed; + } + + // Keep the flywheel moving + updateAndDistributeSupplierRewardsForToken(mToken, src); + updateAndDistributeSupplierRewardsForToken(mToken, dst); + + return uint(Error.NO_ERROR); + } + + /*** Liquidity/Liquidation Calculations ***/ + + /** + * @dev Local vars for avoiding stack-depth limits in calculating account liquidity. + * Note that `mTokenBalance` is the number of mTokens the account owns in the market, + * whereas `borrowBalance` is the amount of underlying that the account has borrowed. + */ + struct AccountLiquidityLocalVars { + uint sumCollateral; + uint sumBorrowPlusEffects; + uint mTokenBalance; + uint borrowBalance; + uint exchangeRateMantissa; + uint oraclePriceMantissa; + Exp collateralFactor; + Exp exchangeRate; + Exp oraclePrice; + Exp tokensToDenom; + } + + /** + * @notice Determine the current account liquidity wrt collateral requirements + * @return (possible error code (semi-opaque), + account liquidity in excess of collateral requirements, + * account shortfall below collateral requirements) + */ + function getAccountLiquidity( + address account + ) public view returns (uint, uint, uint) { + ( + Error err, + uint liquidity, + uint shortfall + ) = getHypotheticalAccountLiquidityInternal( + account, + MToken(address(0)), + 0, + 0 + ); + + return (uint(err), liquidity, shortfall); + } + + /** + * @notice Determine the current account liquidity wrt collateral requirements + * @return (possible error code, + account liquidity in excess of collateral requirements, + * account shortfall below collateral requirements) + */ + function getAccountLiquidityInternal( + address account + ) internal view returns (Error, uint, uint) { + return + getHypotheticalAccountLiquidityInternal( + account, + MToken(address(0)), + 0, + 0 + ); + } + + /** + * @notice Determine what the account liquidity would be if the given amounts were redeemed/borrowed + * @param mTokenModify The market to hypothetically redeem/borrow in + * @param account The account to determine liquidity for + * @param redeemTokens The number of tokens to hypothetically redeem + * @param borrowAmount The amount of underlying to hypothetically borrow + * @return (possible error code (semi-opaque), + hypothetical account liquidity in excess of collateral requirements, + * hypothetical account shortfall below collateral requirements) + */ + function getHypotheticalAccountLiquidity( + address account, + address mTokenModify, + uint redeemTokens, + uint borrowAmount + ) public view returns (uint, uint, uint) { + ( + Error err, + uint liquidity, + uint shortfall + ) = getHypotheticalAccountLiquidityInternal( + account, + MToken(mTokenModify), + redeemTokens, + borrowAmount + ); + return (uint(err), liquidity, shortfall); + } + + /** + * @notice Determine what the account liquidity would be if the given amounts were redeemed/borrowed + * @param mTokenModify The market to hypothetically redeem/borrow in + * @param account The account to determine liquidity for + * @param redeemTokens The number of tokens to hypothetically redeem + * @param borrowAmount The amount of underlying to hypothetically borrow + * @dev Note that we calculate the exchangeRateStored for each collateral mToken using stored data, + * without calculating accumulated interest. + * @return (possible error code, + hypothetical account liquidity in excess of collateral requirements, + * hypothetical account shortfall below collateral requirements) + */ + function getHypotheticalAccountLiquidityInternal( + address account, + MToken mTokenModify, + uint redeemTokens, + uint borrowAmount + ) internal view returns (Error, uint, uint) { + AccountLiquidityLocalVars memory vars; // Holds all our calculation results + uint oErr; + + // For each asset the account is in + MToken[] memory assets = accountAssets[account]; + for (uint i = 0; i < assets.length; i++) { + MToken asset = assets[i]; + + // Read the balances and exchange rate from the mToken + ( + oErr, + vars.mTokenBalance, + vars.borrowBalance, + vars.exchangeRateMantissa + ) = asset.getAccountSnapshot(account); + if (oErr != 0) { + // semi-opaque error code, we assume NO_ERROR == 0 is invariant between upgrades + return (Error.SNAPSHOT_ERROR, 0, 0); + } + vars.collateralFactor = Exp({ + mantissa: markets[address(asset)].collateralFactorMantissa + }); + vars.exchangeRate = Exp({mantissa: vars.exchangeRateMantissa}); + + // Get the normalized price of the asset + vars.oraclePriceMantissa = oracle.getUnderlyingPrice(asset); + if (vars.oraclePriceMantissa == 0) { + return (Error.PRICE_ERROR, 0, 0); + } + vars.oraclePrice = Exp({mantissa: vars.oraclePriceMantissa}); + + // Pre-compute a conversion factor from tokens -> glmr (normalized price value) + vars.tokensToDenom = mul_( + mul_(vars.collateralFactor, vars.exchangeRate), + vars.oraclePrice + ); + + // sumCollateral += tokensToDenom * mTokenBalance + vars.sumCollateral = mul_ScalarTruncateAddUInt( + vars.tokensToDenom, + vars.mTokenBalance, + vars.sumCollateral + ); + + // sumBorrowPlusEffects += oraclePrice * borrowBalance + vars.sumBorrowPlusEffects = mul_ScalarTruncateAddUInt( + vars.oraclePrice, + vars.borrowBalance, + vars.sumBorrowPlusEffects + ); + + // Calculate effects of interacting with mTokenModify + if (asset == mTokenModify) { + // redeem effect + // sumBorrowPlusEffects += tokensToDenom * redeemTokens + vars.sumBorrowPlusEffects = mul_ScalarTruncateAddUInt( + vars.tokensToDenom, + redeemTokens, + vars.sumBorrowPlusEffects + ); + + // borrow effect + // sumBorrowPlusEffects += oraclePrice * borrowAmount + vars.sumBorrowPlusEffects = mul_ScalarTruncateAddUInt( + vars.oraclePrice, + borrowAmount, + vars.sumBorrowPlusEffects + ); + } + } + + // These are safe, as the underflow condition is checked first + if (vars.sumCollateral > vars.sumBorrowPlusEffects) { + return ( + Error.NO_ERROR, + vars.sumCollateral - vars.sumBorrowPlusEffects, + 0 + ); + } else { + return ( + Error.NO_ERROR, + 0, + vars.sumBorrowPlusEffects - vars.sumCollateral + ); + } + } + + /** + * @notice Calculate number of tokens of collateral asset to seize given an underlying amount + * @dev Used in liquidation (called in mToken.liquidateBorrowFresh) + * @param mTokenBorrowed The address of the borrowed mToken + * @param mTokenCollateral The address of the collateral mToken + * @param actualRepayAmount The amount of mTokenBorrowed underlying to convert into mTokenCollateral tokens + * @return (errorCode, number of mTokenCollateral tokens to be seized in a liquidation) + */ + function liquidateCalculateSeizeTokens( + address mTokenBorrowed, + address mTokenCollateral, + uint actualRepayAmount + ) external view override returns (uint, uint) { + /* Read oracle prices for borrowed and collateral markets */ + uint priceBorrowedMantissa = oracle.getUnderlyingPrice( + MToken(mTokenBorrowed) + ); + uint priceCollateralMantissa = oracle.getUnderlyingPrice( + MToken(mTokenCollateral) + ); + if (priceBorrowedMantissa == 0 || priceCollateralMantissa == 0) { + return (uint(Error.PRICE_ERROR), 0); + } + + /* + * Get the exchange rate and calculate the number of collateral tokens to seize: + * seizeAmount = actualRepayAmount * liquidationIncentive * priceBorrowed / priceCollateral + * seizeTokens = seizeAmount / exchangeRate + * = actualRepayAmount * (liquidationIncentive * priceBorrowed) / (priceCollateral * exchangeRate) + */ + uint exchangeRateMantissa = MToken(mTokenCollateral) + .exchangeRateStored(); // Note: reverts on error + uint seizeTokens; + Exp memory numerator; + Exp memory denominator; + Exp memory ratio; + + numerator = mul_( + Exp({mantissa: liquidationIncentiveMantissa}), + Exp({mantissa: priceBorrowedMantissa}) + ); + denominator = mul_( + Exp({mantissa: priceCollateralMantissa}), + Exp({mantissa: exchangeRateMantissa}) + ); + ratio = div_(numerator, denominator); + + seizeTokens = mul_ScalarTruncate(ratio, actualRepayAmount); + + return (uint(Error.NO_ERROR), seizeTokens); + } + + /*** Admin Functions ***/ + + /** + * @notice Sets a new price oracle for the comptroller + * @dev Admin function to set a new price oracle + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function _setPriceOracle(PriceOracle newOracle) public returns (uint) { + // Check caller is admin + if (msg.sender != admin) { + return + fail( + Error.UNAUTHORIZED, + FailureInfo.SET_PRICE_ORACLE_OWNER_CHECK + ); + } + + // Track the old oracle for the comptroller + PriceOracle oldOracle = oracle; + + // Set comptroller's oracle to newOracle + oracle = newOracle; + + // Emit NewPriceOracle(oldOracle, newOracle) + emit NewPriceOracle(oldOracle, newOracle); + + return uint(Error.NO_ERROR); + } + + /** + * @notice Sets the closeFactor used when liquidating borrows + * @dev Admin function to set closeFactor + * @param newCloseFactorMantissa New close factor, scaled by 1e18 + * @return uint 0=success, otherwise a failure + */ + function _setCloseFactor( + uint newCloseFactorMantissa + ) external returns (uint) { + // Check caller is admin + require(msg.sender == admin, "only admin can set close factor"); + + uint oldCloseFactorMantissa = closeFactorMantissa; + closeFactorMantissa = newCloseFactorMantissa; + emit NewCloseFactor(oldCloseFactorMantissa, closeFactorMantissa); + + return uint(Error.NO_ERROR); + } + + /** + * @notice Sets the collateralFactor for a market + * @dev Admin function to set per-market collateralFactor + * @param mToken The market to set the factor on + * @param newCollateralFactorMantissa The new collateral factor, scaled by 1e18 + * @return uint 0=success, otherwise a failure. (See ErrorReporter for details) + */ + function _setCollateralFactor( + MToken mToken, + uint newCollateralFactorMantissa + ) external returns (uint) { + // Check caller is admin + if (msg.sender != admin) { + return + fail( + Error.UNAUTHORIZED, + FailureInfo.SET_COLLATERAL_FACTOR_OWNER_CHECK + ); + } + + // Verify market is listed + Market storage market = markets[address(mToken)]; + if (!market.isListed) { + return + fail( + Error.MARKET_NOT_LISTED, + FailureInfo.SET_COLLATERAL_FACTOR_NO_EXISTS + ); + } + + Exp memory newCollateralFactorExp = Exp({ + mantissa: newCollateralFactorMantissa + }); + + // Check collateral factor <= 0.9 + Exp memory highLimit = Exp({mantissa: collateralFactorMaxMantissa}); + if (lessThanExp(highLimit, newCollateralFactorExp)) { + return + fail( + Error.INVALID_COLLATERAL_FACTOR, + FailureInfo.SET_COLLATERAL_FACTOR_VALIDATION + ); + } + + // If collateral factor != 0, fail if price == 0 + if ( + newCollateralFactorMantissa != 0 && + oracle.getUnderlyingPrice(mToken) == 0 + ) { + return + fail( + Error.PRICE_ERROR, + FailureInfo.SET_COLLATERAL_FACTOR_WITHOUT_PRICE + ); + } + + // Set market's collateral factor to new collateral factor, remember old value + uint oldCollateralFactorMantissa = market.collateralFactorMantissa; + market.collateralFactorMantissa = newCollateralFactorMantissa; + + // Emit event with asset, old collateral factor, and new collateral factor + emit NewCollateralFactor( + mToken, + oldCollateralFactorMantissa, + newCollateralFactorMantissa + ); + + return uint(Error.NO_ERROR); + } + + /** + * @notice Sets liquidationIncentive + * @dev Admin function to set liquidationIncentive + * @param newLiquidationIncentiveMantissa New liquidationIncentive scaled by 1e18 + * @return uint 0=success, otherwise a failure. (See ErrorReporter for details) + */ + function _setLiquidationIncentive( + uint newLiquidationIncentiveMantissa + ) external returns (uint) { + // Check caller is admin + if (msg.sender != admin) { + return + fail( + Error.UNAUTHORIZED, + FailureInfo.SET_LIQUIDATION_INCENTIVE_OWNER_CHECK + ); + } + + // Save current value for use in log + uint oldLiquidationIncentiveMantissa = liquidationIncentiveMantissa; + + // Set liquidation incentive to new incentive + liquidationIncentiveMantissa = newLiquidationIncentiveMantissa; + + // Emit event with old incentive, new incentive + emit NewLiquidationIncentive( + oldLiquidationIncentiveMantissa, + newLiquidationIncentiveMantissa + ); + + return uint(Error.NO_ERROR); + } + + /** + * @notice Add the market to the markets mapping and set it as listed + * @dev Admin function to set isListed and add support for the market + * @param mToken The address of the market (token) to list + * @return uint 0=success, otherwise a failure. (See enum Error for details) + */ + function _supportMarket(MToken mToken) external returns (uint) { + if (msg.sender != admin) { + return + fail( + Error.UNAUTHORIZED, + FailureInfo.SUPPORT_MARKET_OWNER_CHECK + ); + } + + if (markets[address(mToken)].isListed) { + return + fail( + Error.MARKET_ALREADY_LISTED, + FailureInfo.SUPPORT_MARKET_EXISTS + ); + } + + require(mToken.isMToken(), "Must be an MToken"); // Sanity check to make sure its really a MToken + + Market storage newMarket = markets[address(mToken)]; + newMarket.isListed = true; + newMarket.collateralFactorMantissa = 0; + + _addMarketInternal(address(mToken)); + + emit MarketListed(mToken); + + return uint(Error.NO_ERROR); + } + + function _addMarketInternal(address mToken) internal { + for (uint i = 0; i < allMarkets.length; i++) { + require(allMarkets[i] != MToken(mToken), "market already added"); + } + allMarkets.push(MToken(mToken)); + } + + /** + * @notice Set the given borrow caps for the given mToken markets. Borrowing that brings total borrows to or above borrow cap will revert. + * @dev Admin or borrowCapGuardian function to set the borrow caps. A borrow cap of 0 corresponds to unlimited borrowing. + * @param mTokens The addresses of the markets (tokens) to change the borrow caps for + * @param newBorrowCaps The new borrow cap values in underlying to be set. A value of 0 corresponds to unlimited borrowing. + */ + function _setMarketBorrowCaps( + MToken[] calldata mTokens, + uint[] calldata newBorrowCaps + ) external { + require( + msg.sender == admin || msg.sender == borrowCapGuardian, + "only admin or borrow cap guardian can set borrow caps" + ); + + uint numMarkets = mTokens.length; + uint numBorrowCaps = newBorrowCaps.length; + + require( + numMarkets != 0 && numMarkets == numBorrowCaps, + "invalid input" + ); + + for (uint i = 0; i < numMarkets; i++) { + borrowCaps[address(mTokens[i])] = newBorrowCaps[i]; + emit NewBorrowCap(mTokens[i], newBorrowCaps[i]); + } + } + + /** + * @notice Admin function to change the Borrow Cap Guardian + * @param newBorrowCapGuardian The address of the new Borrow Cap Guardian + */ + function _setBorrowCapGuardian(address newBorrowCapGuardian) external { + require(msg.sender == admin, "only admin can set borrow cap guardian"); + + // Save current value for inclusion in log + address oldBorrowCapGuardian = borrowCapGuardian; + + // Store borrowCapGuardian with value newBorrowCapGuardian + borrowCapGuardian = newBorrowCapGuardian; + + // Emit NewBorrowCapGuardian(OldBorrowCapGuardian, NewBorrowCapGuardian) + emit NewBorrowCapGuardian(oldBorrowCapGuardian, newBorrowCapGuardian); + } + + /** + * @notice Set the given supply caps for the given mToken markets. Supplying that brings total supplies to or above supply cap will revert. + * @dev Admin or supplyCapGuardian function to set the supply caps. A supply cap of 0 corresponds to unlimited supplying. + * @param mTokens The addresses of the markets (tokens) to change the supply caps for + * @param newSupplyCaps The new supply cap values in underlying to be set. A value of 0 corresponds to unlimited supplying. + */ + function _setMarketSupplyCaps( + MToken[] calldata mTokens, + uint[] calldata newSupplyCaps + ) external { + require( + msg.sender == admin || msg.sender == supplyCapGuardian, + "only admin or supply cap guardian can set supply caps" + ); + + uint numMarkets = mTokens.length; + uint numSupplyCaps = newSupplyCaps.length; + + require( + numMarkets != 0 && numMarkets == numSupplyCaps, + "invalid input" + ); + + for (uint i = 0; i < numMarkets; i++) { + supplyCaps[address(mTokens[i])] = newSupplyCaps[i]; + emit NewSupplyCap(mTokens[i], newSupplyCaps[i]); + } + } + + /** + * @notice Admin function to change the Supply Cap Guardian + * @param newSupplyCapGuardian The address of the new Supply Cap Guardian + */ + function _setSupplyCapGuardian(address newSupplyCapGuardian) external { + require(msg.sender == admin, "only admin can set supply cap guardian"); + + // Save current value for inclusion in log + address oldSupplyCapGuardian = supplyCapGuardian; + + // Store supplyCapGuardian with value newSupplyCapGuardian + supplyCapGuardian = newSupplyCapGuardian; + + // Emit NewSupplyCapGuardian(OldSupplyCapGuardian, NewSupplyCapGuardian) + emit NewSupplyCapGuardian(oldSupplyCapGuardian, newSupplyCapGuardian); + } + + /** + * @notice Admin function to change the Pause Guardian + * @param newPauseGuardian The address of the new Pause Guardian + * @return uint 0=success, otherwise a failure. (See enum Error for details) + */ + function _setPauseGuardian(address newPauseGuardian) public returns (uint) { + if (msg.sender != admin) { + return + fail( + Error.UNAUTHORIZED, + FailureInfo.SET_PAUSE_GUARDIAN_OWNER_CHECK + ); + } + + // Save current value for inclusion in log + address oldPauseGuardian = pauseGuardian; + + // Store pauseGuardian with value newPauseGuardian + pauseGuardian = newPauseGuardian; + + // Emit NewPauseGuardian(OldPauseGuardian, NewPauseGuardian) + emit NewPauseGuardian(oldPauseGuardian, pauseGuardian); + + return uint(Error.NO_ERROR); + } + + /** + * @notice Admin function to change the Reward Distributor + * @param newRewardDistributor The address of the new Reward Distributor + */ + function _setRewardDistributor( + MultiRewardDistributor newRewardDistributor + ) public { + require(msg.sender == admin, "Unauthorized"); + + MultiRewardDistributor oldRewardDistributor = rewardDistributor; + + rewardDistributor = newRewardDistributor; + + emit NewRewardDistributor(oldRewardDistributor, newRewardDistributor); + } + + function _setMintPaused(MToken mToken, bool state) public returns (bool) { + require( + markets[address(mToken)].isListed, + "cannot pause a market that is not listed" + ); + require( + msg.sender == pauseGuardian || msg.sender == admin, + "only pause guardian and admin can pause" + ); + require(msg.sender == admin || state == true, "only admin can unpause"); + + mintGuardianPaused[address(mToken)] = state; + emit ActionPaused(mToken, "Mint", state); + return state; + } + + function _setBorrowPaused(MToken mToken, bool state) public returns (bool) { + require( + markets[address(mToken)].isListed, + "cannot pause a market that is not listed" + ); + require( + msg.sender == pauseGuardian || msg.sender == admin, + "only pause guardian and admin can pause" + ); + require(msg.sender == admin || state == true, "only admin can unpause"); + + borrowGuardianPaused[address(mToken)] = state; + emit ActionPaused(mToken, "Borrow", state); + return state; + } + + function _setTransferPaused(bool state) public returns (bool) { + require( + msg.sender == pauseGuardian || msg.sender == admin, + "only pause guardian and admin can pause" + ); + require(msg.sender == admin || state == true, "only admin can unpause"); + + transferGuardianPaused = state; + emit ActionPaused("Transfer", state); + return state; + } + + function _setSeizePaused(bool state) public returns (bool) { + require( + msg.sender == pauseGuardian || msg.sender == admin, + "only pause guardian and admin can pause" + ); + require(msg.sender == admin || state == true, "only admin can unpause"); + + seizeGuardianPaused = state; + emit ActionPaused("Seize", state); + return state; + } + + function _become(Unitroller unitroller) public { + require( + msg.sender == unitroller.admin(), + "only unitroller admin can change brains" + ); + require( + unitroller._acceptImplementation() == 0, + "change not authorized" + ); + } + + /** + * @notice Sweep ERC-20 tokens from the comptroller to the admin + * @param _tokenAddress The address of the token to transfer + * @param _amount The amount of tokens to sweep, uint.max means everything + */ + function _rescueFunds(address _tokenAddress, uint _amount) external { + require(msg.sender == admin, "Unauthorized"); + + IERC20 token = IERC20(_tokenAddress); + // Similar to mTokens, if this is uint.max that means "transfer everything" + if (_amount == type(uint).max) { + token.transfer(admin, token.balanceOf(address(this))); + } else { + token.transfer(admin, _amount); + } + } + + /*** WELL Distribution ***/ + + /** + * @notice Call out to the reward distributor to update its supply index and this user's index too + * @param mToken The market to synchronize indexes for + * @param supplier The supplier to whom rewards are going + */ + function updateAndDistributeSupplierRewardsForToken( + address mToken, + address supplier + ) internal { + if (address(rewardDistributor) != address(0)) { + rewardDistributor.updateMarketSupplyIndexAndDisburseSupplierRewards( + MToken(mToken), + supplier, + false + ); + } + } + + /** + * @notice Call out to the reward distributor to update its borrow index and this user's index too + * @param mToken The market to synchronize indexes for + * @param borrower The borrower to whom rewards are going + */ + function updateAndDistributeBorrowerRewardsForToken( + address mToken, + address borrower + ) internal { + if (address(rewardDistributor) != address(0)) { + rewardDistributor.updateMarketBorrowIndexAndDisburseBorrowerRewards( + MToken(mToken), + borrower, + false + ); + } + } + + /** + * @notice Claim all the WELL accrued by holder in all markets + */ + function claimReward() public { + claimReward(msg.sender, allMarkets); + } + + /** + * @notice Claim all the rewards accrued by specified holder in all markets + * @param holder The address to claim rewards for + */ + function claimReward(address holder) public { + claimReward(holder, allMarkets); + } + + /** + * @notice Claim all the rewards accrued by holder in the specified markets + * @param holder The address to claim rewards for + * @param mTokens The list of markets to claim rewards in + */ + function claimReward(address holder, MToken[] memory mTokens) public { + address[] memory holders = new address[](1); + holders[0] = holder; + claimReward(holders, mTokens, true, true); + } + + /** + * @notice Claim all rewards for a specified group of users, tokens, and market sides + * @param holders The addresses to claim for + * @param mTokens The list of markets to claim in + * @param borrowers Whether or not to claim earned by borrowing + * @param suppliers Whether or not to claim earned by supplying + */ + function claimReward( + address[] memory holders, + MToken[] memory mTokens, + bool borrowers, + bool suppliers + ) public { + require( + address(rewardDistributor) != address(0), + "No reward distributor configured!" + ); + + for (uint i = 0; i < mTokens.length; i++) { + // Safety check that the supplied mTokens are active/listed + MToken mToken = mTokens[i]; + require(markets[address(mToken)].isListed, "market must be listed"); + + // Disburse supply side + if (suppliers == true) { + rewardDistributor.updateMarketSupplyIndex(mToken); + for ( + uint holderIndex = 0; + holderIndex < holders.length; + holderIndex++ + ) { + rewardDistributor.disburseSupplierRewards( + mToken, + holders[holderIndex], + true + ); + } + } + + // Disburse borrow side + if (borrowers == true) { + rewardDistributor.updateMarketBorrowIndex(mToken); + for ( + uint holderIndex = 0; + holderIndex < holders.length; + holderIndex++ + ) { + rewardDistributor.disburseBorrowerRewards( + mToken, + holders[holderIndex], + true + ); + } + } + } + } + + /** + * @notice Return all of the markets + * @dev The automatic getter may be used to access an individual market. + * @return The list of market addresses + */ + function getAllMarkets() public view returns (MToken[] memory) { + return allMarkets; + } + + function getBlockTimestamp() public view returns (uint) { + return block.timestamp; + } + + /** + * @dev Prevents a contract from calling itself, directly or indirectly. + * Calling a `nonReentrant` function from another `nonReentrant` + * function is not supported. It is possible to prevent this from happening + * by making the `nonReentrant` function external, and make it call a + * `private` function that does the actual work. + */ + modifier nonReentrant() { + // On the first call to nonReentrant, _notEntered will be true + require(_locked != 1, "ReentrancyGuard: reentrant call"); + + // Any calls to nonReentrant after this point will fail + _locked = 1; + + _; + + // By storing the original value once again, a refund is triggered (see + // https://eips.ethereum.org/EIPS/eip-2200) + _locked = 0; + } +} diff --git a/plan/agw/research/preset-catalog-2026-10-15/EigenStrategyManager.sol b/plan/agw/research/preset-catalog-2026-10-15/EigenStrategyManager.sol new file mode 100644 index 00000000..02f6717e --- /dev/null +++ b/plan/agw/research/preset-catalog-2026-10-15/EigenStrategyManager.sol @@ -0,0 +1,573 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.27; + +import "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol"; +import "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol"; +import "@openzeppelin-upgrades/contracts/security/ReentrancyGuardUpgradeable.sol"; +import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; + +import "../mixins/SignatureUtilsMixin.sol"; +import "../interfaces/IEigenPodManager.sol"; +import "../permissions/Pausable.sol"; +import "./StrategyManagerStorage.sol"; + +/** + * @title The primary entry- and exit-point for funds into and out of EigenLayer. + * @author Layr Labs, Inc. + * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service + * @notice This contract is for managing deposits in different strategies. The main + * functionalities are: + * - adding and removing strategies that any delegator can deposit into + * - enabling deposit of assets into specified strategy(s) + */ +contract StrategyManager is + Initializable, + OwnableUpgradeable, + ReentrancyGuardUpgradeable, + Pausable, + StrategyManagerStorage, + SignatureUtilsMixin +{ + using OperatorSetLib for *; + using SlashingLib for *; + using SafeERC20 for IERC20; + using EnumerableMap for EnumerableMap.AddressToUintMap; + using EnumerableSet for EnumerableSet.Bytes32Set; + using EnumerableSet for EnumerableSet.UintSet; + + modifier onlyStrategyWhitelister() { + require(msg.sender == strategyWhitelister, OnlyStrategyWhitelister()); + _; + } + + modifier onlyStrategiesWhitelistedForDeposit( + IStrategy strategy + ) { + require(strategyIsWhitelistedForDeposit[strategy], StrategyNotWhitelisted()); + _; + } + + modifier onlyDelegationManager() { + require(msg.sender == address(delegation), OnlyDelegationManager()); + _; + } + + /** + * @param _delegation The delegation contract of EigenLayer. + */ + constructor( + IAllocationManager _allocationManager, + IDelegationManager _delegation, + IPauserRegistry _pauserRegistry, + string memory _version + ) StrategyManagerStorage(_allocationManager, _delegation) Pausable(_pauserRegistry) SignatureUtilsMixin(_version) { + _disableInitializers(); + } + + // EXTERNAL FUNCTIONS + + /** + * @notice Initializes the strategy manager contract. Sets the `pauserRegistry` (currently **not** modifiable after being set), + * and transfers contract ownership to the specified `initialOwner`. + * @param initialOwner Ownership of this contract is transferred to this address. + * @param initialStrategyWhitelister The initial value of `strategyWhitelister` to set. + */ + function initialize( + address initialOwner, + address initialStrategyWhitelister, + uint256 initialPausedStatus + ) external initializer { + _setPausedStatus(initialPausedStatus); + _transferOwnership(initialOwner); + _setStrategyWhitelister(initialStrategyWhitelister); + } + + /// @inheritdoc IStrategyManager + function depositIntoStrategy( + IStrategy strategy, + IERC20 token, + uint256 amount + ) external onlyWhenNotPaused(PAUSED_DEPOSITS) nonReentrant returns (uint256 depositShares) { + depositShares = _depositIntoStrategy(msg.sender, strategy, token, amount); + } + + /// @inheritdoc IStrategyManager + function depositIntoStrategyWithSignature( + IStrategy strategy, + IERC20 token, + uint256 amount, + address staker, + uint256 expiry, + bytes memory signature + ) external onlyWhenNotPaused(PAUSED_DEPOSITS) nonReentrant returns (uint256 depositShares) { + // Cache staker's nonce to avoid sloads. + uint256 nonce = nonces[staker]; + // Assert that the signature is valid. + _checkIsValidSignatureNow({ + signer: staker, + signableDigest: calculateStrategyDepositDigestHash(staker, strategy, token, amount, nonce, expiry), + signature: signature, + expiry: expiry + }); + // Increment the nonce for the staker. + unchecked { + nonces[staker] = nonce + 1; + } + // deposit the tokens (from the `msg.sender`) and credit the new shares to the `staker` + depositShares = _depositIntoStrategy(staker, strategy, token, amount); + } + + /// @inheritdoc IShareManager + function removeDepositShares( + address staker, + IStrategy strategy, + uint256 depositSharesToRemove + ) external onlyDelegationManager nonReentrant returns (uint256) { + return _removeDepositShares(staker, strategy, depositSharesToRemove); + } + + /// @inheritdoc IShareManager + function addShares( + address staker, + IStrategy strategy, + uint256 shares + ) external onlyDelegationManager nonReentrant returns (uint256, uint256) { + return _addShares(staker, strategy, shares); + } + + /// @inheritdoc IShareManager + function withdrawSharesAsTokens( + address staker, + IStrategy strategy, + IERC20 token, + uint256 shares + ) external onlyDelegationManager nonReentrant { + strategy.withdraw(staker, token, shares); + } + + /// @inheritdoc IShareManager + function increaseBurnOrRedistributableShares( + OperatorSet calldata operatorSet, + uint256 slashId, + IStrategy strategy, + uint256 sharesToBurn + ) external onlyDelegationManager nonReentrant { + // Create storage pointer for readability. + EnumerableMap.AddressToUintMap storage burnOrRedistributableShares = + _burnOrRedistributableShares[operatorSet.key()][slashId]; + + // Sanity check that the strategy is not already in the slash's burn or redistributable shares. + // This should never happen because the `AllocationManager` ensures that strategies for a given slash are unique. + // Add the shares to the operator set's burn or redistributable shares. + require(burnOrRedistributableShares.set(address(strategy), sharesToBurn), StrategyAlreadyInSlash()); + + // NOTE: Duplicate operator sets and slash ids will not revert, but will not be added. + _pendingOperatorSets.add(operatorSet.key()); + _pendingSlashIds[operatorSet.key()].add(slashId); + + emit BurnOrRedistributableSharesIncreased(operatorSet, slashId, strategy, sharesToBurn); + } + + /// @inheritdoc IStrategyManager + function clearBurnOrRedistributableShares( + OperatorSet calldata operatorSet, + uint256 slashId + ) external nonReentrant returns (uint256[] memory) { + // Get the strategies to clear. + address[] memory strategies = _burnOrRedistributableShares[operatorSet.key()][slashId].keys(); + uint256 length = strategies.length; + uint256[] memory amounts = new uint256[](length); + + // Note: We don't need to iterate backwards since we're indexing into the `EnumerableMap` directly. + for (uint256 i = 0; i < length; ++i) { + amounts[i] = _clearBurnOrRedistributableShares({ + operatorSet: operatorSet, + slashId: slashId, + strategy: IStrategy(strategies[i]), + recipient: allocationManager.getRedistributionRecipient(operatorSet) + }); + } + + return amounts; + } + + /// @inheritdoc IStrategyManager + function clearBurnOrRedistributableSharesByStrategy( + OperatorSet calldata operatorSet, + uint256 slashId, + IStrategy strategy + ) external nonReentrant returns (uint256) { + return _clearBurnOrRedistributableShares({ + operatorSet: operatorSet, + slashId: slashId, + strategy: strategy, + recipient: allocationManager.getRedistributionRecipient(operatorSet) + }); + } + + /// @inheritdoc IStrategyManager + function burnShares( + IStrategy strategy + ) external nonReentrant { + (, uint256 sharesToBurn) = EnumerableMap.tryGet(burnableShares, address(strategy)); + EnumerableMap.remove(burnableShares, address(strategy)); + emit BurnableSharesDecreased(strategy, sharesToBurn); + + // Burning acts like withdrawing, except that the destination is to the burn address. + // If we have no shares to burn, we don't need to call the strategy. + if (sharesToBurn != 0) { + strategy.withdraw(DEFAULT_BURN_ADDRESS, strategy.underlyingToken(), sharesToBurn); + } + } + + /// @inheritdoc IStrategyManager + function setStrategyWhitelister( + address newStrategyWhitelister + ) external onlyOwner nonReentrant { + _setStrategyWhitelister(newStrategyWhitelister); + } + + /// @inheritdoc IStrategyManager + function addStrategiesToDepositWhitelist( + IStrategy[] calldata strategiesToWhitelist + ) external onlyStrategyWhitelister nonReentrant { + uint256 strategiesToWhitelistLength = strategiesToWhitelist.length; + for (uint256 i = 0; i < strategiesToWhitelistLength; ++i) { + // change storage and emit event only if strategy is not already in whitelist + if (!strategyIsWhitelistedForDeposit[strategiesToWhitelist[i]]) { + strategyIsWhitelistedForDeposit[strategiesToWhitelist[i]] = true; + emit StrategyAddedToDepositWhitelist(strategiesToWhitelist[i]); + } + } + } + + /// @inheritdoc IStrategyManager + function removeStrategiesFromDepositWhitelist( + IStrategy[] calldata strategiesToRemoveFromWhitelist + ) external onlyStrategyWhitelister nonReentrant { + uint256 strategiesToRemoveFromWhitelistLength = strategiesToRemoveFromWhitelist.length; + for (uint256 i = 0; i < strategiesToRemoveFromWhitelistLength; ++i) { + // change storage and emit event only if strategy is already in whitelist + if (strategyIsWhitelistedForDeposit[strategiesToRemoveFromWhitelist[i]]) { + strategyIsWhitelistedForDeposit[strategiesToRemoveFromWhitelist[i]] = false; + emit StrategyRemovedFromDepositWhitelist(strategiesToRemoveFromWhitelist[i]); + } + } + } + + // INTERNAL FUNCTIONS + + /** + * @notice This function adds `shares` for a given `strategy` to the `staker` and runs through the necessary update logic. + * @param staker The address to add shares to + * @param strategy The Strategy in which the `staker` is receiving shares + * @param shares The amount of shares to grant to the `staker` + * @dev In particular, this function calls `delegation.increaseDelegatedShares(staker, strategy, shares)` to ensure that all + * delegated shares are tracked, increases the stored share amount in `stakerDepositShares[staker][strategy]`, and adds `strategy` + * to the `staker`'s list of strategies, if it is not in the list already. + */ + function _addShares(address staker, IStrategy strategy, uint256 shares) internal returns (uint256, uint256) { + // sanity checks on inputs + require(staker != address(0), StakerAddressZero()); + require(shares != 0, SharesAmountZero()); + + uint256 prevDepositShares = stakerDepositShares[staker][strategy]; + + // if they dont have prevDepositShares of this strategy, add it to their strats + if (prevDepositShares == 0) { + require(stakerStrategyList[staker].length < MAX_STAKER_STRATEGY_LIST_LENGTH, MaxStrategiesExceeded()); + stakerStrategyList[staker].push(strategy); + } + + // add the returned depositedShares to their existing shares for this strategy + stakerDepositShares[staker][strategy] = prevDepositShares + shares; + + emit Deposit(staker, strategy, shares); + return (prevDepositShares, shares); + } + + /** + * @notice Internal function in which `amount` of ERC20 `token` is transferred from `msg.sender` to the Strategy-type contract + * `strategy`, with the resulting shares credited to `staker`. + * @param staker The address that will be credited with the new shares. + * @param strategy The Strategy contract to deposit into. + * @param token The ERC20 token to deposit. + * @param amount The amount of `token` to deposit. + * @return shares The amount of *new* shares in `strategy` that have been credited to the `staker`. + */ + function _depositIntoStrategy( + address staker, + IStrategy strategy, + IERC20 token, + uint256 amount + ) internal onlyStrategiesWhitelistedForDeposit(strategy) returns (uint256 shares) { + // transfer tokens from the sender to the strategy + token.safeTransferFrom(msg.sender, address(strategy), amount); + + // deposit the assets into the specified strategy and get the equivalent amount of shares in that strategy + shares = strategy.deposit(token, amount); + + // add the returned shares to the staker's existing shares for this strategy + (uint256 prevDepositShares, uint256 addedShares) = _addShares(staker, strategy, shares); + + // Increase shares delegated to operator + delegation.increaseDelegatedShares({ + staker: staker, + strategy: strategy, + prevDepositShares: prevDepositShares, + addedShares: addedShares + }); + + return shares; + } + + /** + * @notice Decreases the shares that `staker` holds in `strategy` by `depositSharesToRemove`. + * @param staker The address to decrement shares from + * @param strategy The strategy for which the `staker`'s shares are being decremented + * @param depositSharesToRemove The amount of deposit shares to decrement + * @dev If the amount of shares represents all of the staker`s shares in said strategy, + * then the strategy is removed from stakerStrategyList[staker] and 'true' is returned. Otherwise 'false' is returned. + * Also returns the user's updated deposit shares after decrement. + */ + function _removeDepositShares( + address staker, + IStrategy strategy, + uint256 depositSharesToRemove + ) internal returns (uint256) { + // sanity checks on inputs + require(depositSharesToRemove != 0, SharesAmountZero()); + + //check that the user has sufficient shares + uint256 userDepositShares = stakerDepositShares[staker][strategy]; + + // This check technically shouldn't actually ever revert because depositSharesToRemove is already + // checked to not exceed max amount of shares when the withdrawal was queued in the DelegationManager + require(depositSharesToRemove <= userDepositShares, SharesAmountTooHigh()); + userDepositShares = userDepositShares - depositSharesToRemove; + + // subtract the shares from the staker's existing shares for this strategy + stakerDepositShares[staker][strategy] = userDepositShares; + + // if no existing shares, remove the strategy from the staker's dynamic array of strategies + if (userDepositShares == 0) { + _removeStrategyFromStakerStrategyList(staker, strategy); + } + + return userDepositShares; + } + + /** + * @notice Removes `strategy` from `staker`'s dynamic array of strategies, i.e. from `stakerStrategyList[staker]` + * @param staker The user whose array will have an entry removed + * @param strategy The Strategy to remove from `stakerStrategyList[staker]` + */ + function _removeStrategyFromStakerStrategyList(address staker, IStrategy strategy) internal { + //loop through all of the strategies, find the right one, then replace + uint256 stratsLength = stakerStrategyList[staker].length; + uint256 j = 0; + for (; j < stratsLength; ++j) { + if (stakerStrategyList[staker][j] == strategy) { + //replace the strategy with the last strategy in the list + stakerStrategyList[staker][j] = stakerStrategyList[staker][stakerStrategyList[staker].length - 1]; + break; + } + } + // if we didn't find the strategy, revert + require(j != stratsLength, StrategyNotFound()); + // pop off the last entry in the list of strategies + stakerStrategyList[staker].pop(); + } + + /** + * @notice Clears burn/redistributable shares and sends underlying tokens to recipient. + * @param operatorSet The operator set to clear the shares for. + * @param slashId The slash id to clear the shares for. + * @param strategy The strategy to clear the shares for. + * @param recipient The recipient to withdraw the shares to. + */ + function _clearBurnOrRedistributableShares( + OperatorSet calldata operatorSet, + uint256 slashId, + IStrategy strategy, + address recipient + ) internal returns (uint256) { + EnumerableMap.AddressToUintMap storage burnOrRedistributableShares = + _burnOrRedistributableShares[operatorSet.key()][slashId]; + + (, uint256 sharesToRemove) = burnOrRedistributableShares.tryGet(address(strategy)); + burnOrRedistributableShares.remove(address(strategy)); + + uint256 amountOut; + if (sharesToRemove != 0) { + // Withdraw the shares to the burn address. + amountOut = IStrategy(strategy).withdraw({ + recipient: recipient, + token: IStrategy(strategy).underlyingToken(), + amountShares: sharesToRemove + }); + + // Emit an event to notify the that burnable shares have been decreased. + emit BurnOrRedistributableSharesDecreased(operatorSet, slashId, strategy, sharesToRemove); + } + + uint256 remainingStrategies = burnOrRedistributableShares.keys().length; + + // If there are no more strategies to burn or redistribute... + if (remainingStrategies == 0) { + // Remove the slash id from the pending slash ids. + _pendingSlashIds[operatorSet.key()].remove(slashId); + + // If there are no more pending slash ids for this operator set, remove the operator set from the pending operator sets. + if (_pendingSlashIds[operatorSet.key()].length() == 0) { + _pendingOperatorSets.remove(operatorSet.key()); + } + } + + return amountOut; + } + + /** + * @notice Internal function for modifying the `strategyWhitelister`. Used inside of the `setStrategyWhitelister` and `initialize` functions. + * @param newStrategyWhitelister The new address for the `strategyWhitelister` to take. + */ + function _setStrategyWhitelister( + address newStrategyWhitelister + ) internal { + emit StrategyWhitelisterChanged(strategyWhitelister, newStrategyWhitelister); + strategyWhitelister = newStrategyWhitelister; + } + + // VIEW FUNCTIONS + + /// @inheritdoc IStrategyManager + function getDeposits( + address staker + ) external view returns (IStrategy[] memory, uint256[] memory) { + uint256 strategiesLength = stakerStrategyList[staker].length; + uint256[] memory depositedShares = new uint256[](strategiesLength); + + for (uint256 i = 0; i < strategiesLength; ++i) { + depositedShares[i] = stakerDepositShares[staker][stakerStrategyList[staker][i]]; + } + return (stakerStrategyList[staker], depositedShares); + } + + function getStakerStrategyList( + address staker + ) external view returns (IStrategy[] memory) { + return stakerStrategyList[staker]; + } + + /// @inheritdoc IStrategyManager + function stakerStrategyListLength( + address staker + ) external view returns (uint256) { + return stakerStrategyList[staker].length; + } + + /// @inheritdoc IStrategyManager + function calculateStrategyDepositDigestHash( + address staker, + IStrategy strategy, + IERC20 token, + uint256 amount, + uint256 nonce, + uint256 expiry + ) public view returns (bytes32) { + /// forgefmt: disable-next-item + return _calculateSignableDigest( + keccak256( + abi.encode( + DEPOSIT_TYPEHASH, + staker, + strategy, + token, + amount, + nonce, + expiry + ) + ) + ); + } + + /// @inheritdoc IStrategyManager + function getBurnOrRedistributableShares( + OperatorSet calldata operatorSet, + uint256 slashId + ) external view returns (IStrategy[] memory, uint256[] memory) { + // Store the data structure for readability + EnumerableMap.AddressToUintMap storage burnOrRedistributableShares = + _burnOrRedistributableShares[operatorSet.key()][slashId]; + + address[] memory keys = burnOrRedistributableShares.keys(); + IStrategy[] memory strategies = new IStrategy[](keys.length); + uint256[] memory shares = new uint256[](keys.length); + + for (uint256 i = 0; i < keys.length; ++i) { + strategies[i] = IStrategy(keys[i]); + (, shares[i]) = burnOrRedistributableShares.tryGet(keys[i]); + } + + return (strategies, shares); + } + + /// @inheritdoc IStrategyManager + function getBurnOrRedistributableShares( + OperatorSet calldata operatorSet, + uint256 slashId, + IStrategy strategy + ) external view returns (uint256) { + (, uint256 shares) = _burnOrRedistributableShares[operatorSet.key()][slashId].tryGet(address(strategy)); + return shares; + } + + /// @inheritdoc IStrategyManager + function getBurnOrRedistributableCount( + OperatorSet calldata operatorSet, + uint256 slashId + ) external view returns (uint256) { + return _burnOrRedistributableShares[operatorSet.key()][slashId].length(); + } + + /// @inheritdoc IStrategyManager + function getBurnableShares( + IStrategy strategy + ) external view returns (uint256) { + (, uint256 shares) = EnumerableMap.tryGet(burnableShares, address(strategy)); + return shares; + } + + /// @inheritdoc IStrategyManager + function getStrategiesWithBurnableShares() external view returns (address[] memory, uint256[] memory) { + uint256 totalEntries = EnumerableMap.length(burnableShares); + + address[] memory strategies = new address[](totalEntries); + uint256[] memory shares = new uint256[](totalEntries); + + for (uint256 i = 0; i < totalEntries; i++) { + (address strategy, uint256 shareAmount) = EnumerableMap.at(burnableShares, i); + strategies[i] = strategy; + shares[i] = shareAmount; + } + + return (strategies, shares); + } + + /// @inheritdoc IStrategyManager + function getPendingOperatorSets() external view returns (OperatorSet[] memory) { + uint256 totalEntries = _pendingOperatorSets.length(); + OperatorSet[] memory operatorSets = new OperatorSet[](totalEntries); + for (uint256 i = 0; i < totalEntries; i++) { + operatorSets[i] = _pendingOperatorSets.at(i).decode(); + } + return operatorSets; + } + + /// @inheritdoc IStrategyManager + function getPendingSlashIds( + OperatorSet calldata operatorSet + ) external view returns (uint256[] memory) { + return _pendingSlashIds[operatorSet.key()].values(); + } +} diff --git a/plan/agw/research/preset-catalog-2026-10-15/IPool.sol b/plan/agw/research/preset-catalog-2026-10-15/IPool.sol new file mode 100644 index 00000000..2f2b88e7 --- /dev/null +++ b/plan/agw/research/preset-catalog-2026-10-15/IPool.sol @@ -0,0 +1,848 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {IPoolAddressesProvider} from './IPoolAddressesProvider.sol'; +import {DataTypes} from '../protocol/libraries/types/DataTypes.sol'; + +/** + * @title IPool + * @author Aave + * @notice Defines the basic interface for an Aave Pool. + */ +interface IPool { + /** + * @dev Emitted on supply() + * @param reserve The address of the underlying asset of the reserve + * @param user The address initiating the supply + * @param onBehalfOf The beneficiary of the supply, receiving the aTokens + * @param amount The amount supplied + * @param referralCode The referral code used + */ + event Supply( + address indexed reserve, + address user, + address indexed onBehalfOf, + uint256 amount, + uint16 indexed referralCode + ); + + /** + * @dev Emitted on withdraw() + * @param reserve The address of the underlying asset being withdrawn + * @param user The address initiating the withdrawal, owner of aTokens + * @param to The address that will receive the underlying + * @param amount The amount to be withdrawn + */ + event Withdraw(address indexed reserve, address indexed user, address indexed to, uint256 amount); + + /** + * @dev Emitted on borrow() and flashLoan() when debt needs to be opened + * @param reserve The address of the underlying asset being borrowed + * @param user The address of the user initiating the borrow(), receiving the funds on borrow() or just + * initiator of the transaction on flashLoan() + * @param onBehalfOf The address that will be getting the debt + * @param amount The amount borrowed out + * @param interestRateMode The rate mode: 2 for Variable, 1 is deprecated (changed on v3.2.0) + * @param borrowRate The numeric rate at which the user has borrowed, expressed in ray + * @param referralCode The referral code used + */ + event Borrow( + address indexed reserve, + address user, + address indexed onBehalfOf, + uint256 amount, + DataTypes.InterestRateMode interestRateMode, + uint256 borrowRate, + uint16 indexed referralCode + ); + + /** + * @dev Emitted on repay() + * @param reserve The address of the underlying asset of the reserve + * @param user The beneficiary of the repayment, getting his debt reduced + * @param repayer The address of the user initiating the repay(), providing the funds + * @param amount The amount repaid + * @param useATokens True if the repayment is done using aTokens, `false` if done with underlying asset directly + */ + event Repay( + address indexed reserve, + address indexed user, + address indexed repayer, + uint256 amount, + bool useATokens + ); + + /** + * @dev Emitted when the user selects a certain asset category for eMode + * @param user The address of the user + * @param categoryId The category id + */ + event UserEModeSet(address indexed user, uint8 categoryId); + + /** + * @dev Emitted on setUserUseReserveAsCollateral() + * @param reserve The address of the underlying asset of the reserve + * @param user The address of the user enabling the usage as collateral + */ + event ReserveUsedAsCollateralEnabled(address indexed reserve, address indexed user); + + /** + * @dev Emitted on setUserUseReserveAsCollateral() + * @param reserve The address of the underlying asset of the reserve + * @param user The address of the user enabling the usage as collateral + */ + event ReserveUsedAsCollateralDisabled(address indexed reserve, address indexed user); + + /** + * @dev Emitted on flashLoan() + * @param target The address of the flash loan receiver contract + * @param initiator The address initiating the flash loan + * @param asset The address of the asset being flash borrowed + * @param amount The amount flash borrowed + * @param interestRateMode The flashloan mode: 0 for regular flashloan, + * 1 for Stable (Deprecated on v3.2.0), 2 for Variable + * @param premium The fee flash borrowed + * @param referralCode The referral code used + */ + event FlashLoan( + address indexed target, + address initiator, + address indexed asset, + uint256 amount, + DataTypes.InterestRateMode interestRateMode, + uint256 premium, + uint16 indexed referralCode + ); + + /** + * @dev Emitted when a borrower is liquidated. + * @param collateralAsset The address of the underlying asset used as collateral, to receive as result of the liquidation + * @param debtAsset The address of the underlying borrowed asset to be repaid with the liquidation + * @param user The address of the borrower getting liquidated + * @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover + * @param liquidatedCollateralAmount The amount of collateral received by the liquidator + * @param liquidator The address of the liquidator + * @param receiveAToken True if the liquidators wants to receive the collateral aTokens, `false` if he wants + * to receive the underlying collateral asset directly + */ + event LiquidationCall( + address indexed collateralAsset, + address indexed debtAsset, + address indexed user, + uint256 debtToCover, + uint256 liquidatedCollateralAmount, + address liquidator, + bool receiveAToken + ); + + /** + * @dev Emitted when the state of a reserve is updated. + * @param reserve The address of the underlying asset of the reserve + * @param liquidityRate The next liquidity rate + * @param stableBorrowRate The next stable borrow rate @note deprecated on v3.2.0 + * @param variableBorrowRate The next variable borrow rate + * @param liquidityIndex The next liquidity index + * @param variableBorrowIndex The next variable borrow index + */ + event ReserveDataUpdated( + address indexed reserve, + uint256 liquidityRate, + uint256 stableBorrowRate, + uint256 variableBorrowRate, + uint256 liquidityIndex, + uint256 variableBorrowIndex + ); + + /** + * @dev Emitted when the deficit of a reserve is covered. + * @param reserve The address of the underlying asset of the reserve + * @param caller The caller that triggered the DeficitCovered event + * @param amountCovered The amount of deficit covered + */ + event DeficitCovered(address indexed reserve, address caller, uint256 amountCovered); + + /** + * @dev Emitted when the protocol treasury receives minted aTokens from the accrued interest. + * @param reserve The address of the reserve + * @param amountMinted The amount minted to the treasury + */ + event MintedToTreasury(address indexed reserve, uint256 amountMinted); + + /** + * @dev Emitted when deficit is realized on a liquidation. + * @param user The user address where the bad debt will be burned + * @param debtAsset The address of the underlying borrowed asset to be burned + * @param amountCreated The amount of deficit created + */ + event DeficitCreated(address indexed user, address indexed debtAsset, uint256 amountCreated); + + /** + * @dev Emitted when a position manager is approved by the user. + * @param user The user address + * @param positionManager The address of the position manager + */ + event PositionManagerApproved(address indexed user, address indexed positionManager); + + /** + * @dev Emitted when a position manager is revoked by the user. + * @param user The user address + * @param positionManager The address of the position manager + */ + event PositionManagerRevoked(address indexed user, address indexed positionManager); + + /** + * @notice Supplies an `amount` of underlying asset into the reserve, receiving in return overlying aTokens. + * - E.g. User supplies 100 USDC and gets in return 100 aUSDC + * @param asset The address of the underlying asset to supply + * @param amount The amount to be supplied + * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user + * wants to receive them on his own wallet, or a different address if the beneficiary of aTokens + * is a different wallet + * @param referralCode Code used to register the integrator originating the operation, for potential rewards. + * 0 if the action is executed directly by the user, without any middle-man + */ + function supply(address asset, uint256 amount, address onBehalfOf, uint16 referralCode) external; + + /** + * @notice Supply with transfer approval of asset to be supplied done via permit function + * see: https://eips.ethereum.org/EIPS/eip-2612 and https://eips.ethereum.org/EIPS/eip-713 + * @param asset The address of the underlying asset to supply + * @param amount The amount to be supplied + * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user + * wants to receive them on his own wallet, or a different address if the beneficiary of aTokens + * is a different wallet + * @param deadline The deadline timestamp that the permit is valid + * @param referralCode Code used to register the integrator originating the operation, for potential rewards. + * 0 if the action is executed directly by the user, without any middle-man + * @param permitV The V parameter of ERC712 permit sig + * @param permitR The R parameter of ERC712 permit sig + * @param permitS The S parameter of ERC712 permit sig + */ + function supplyWithPermit( + address asset, + uint256 amount, + address onBehalfOf, + uint16 referralCode, + uint256 deadline, + uint8 permitV, + bytes32 permitR, + bytes32 permitS + ) external; + + /** + * @notice Withdraws an `amount` of underlying asset from the reserve, burning the equivalent aTokens owned + * E.g. User has 100 aUSDC, calls withdraw() and receives 100 USDC, burning the 100 aUSDC + * @param asset The address of the underlying asset to withdraw + * @param amount The underlying amount to be withdrawn + * - Send the value type(uint256).max in order to withdraw the whole aToken balance + * @param to The address that will receive the underlying, same as msg.sender if the user + * wants to receive it on his own wallet, or a different address if the beneficiary is a + * different wallet + * @return The final amount withdrawn + */ + function withdraw(address asset, uint256 amount, address to) external returns (uint256); + + /** + * @notice Allows users to borrow a specific `amount` of the reserve underlying asset, provided that the borrower + * already supplied enough collateral, or he was given enough allowance by a credit delegator on the VariableDebtToken + * - E.g. User borrows 100 USDC passing as `onBehalfOf` his own address, receiving the 100 USDC in his wallet + * and 100 variable debt tokens + * @param asset The address of the underlying asset to borrow + * @param amount The amount to be borrowed + * @param interestRateMode 2 for Variable, 1 is deprecated on v3.2.0 + * @param referralCode The code used to register the integrator originating the operation, for potential rewards. + * 0 if the action is executed directly by the user, without any middle-man + * @param onBehalfOf The address of the user who will receive the debt. Should be the address of the borrower itself + * calling the function if he wants to borrow against his own collateral, or the address of the credit delegator + * if he has been given credit delegation allowance + */ + function borrow( + address asset, + uint256 amount, + uint256 interestRateMode, + uint16 referralCode, + address onBehalfOf + ) external; + + /** + * @notice Repays a borrowed `amount` on a specific reserve, burning the equivalent debt tokens owned + * - E.g. User repays 100 USDC, burning 100 variable debt tokens of the `onBehalfOf` address + * @param asset The address of the borrowed underlying asset previously borrowed + * @param amount The amount to repay + * - Send the value type(uint256).max in order to repay the whole debt for `asset` on the specific `debtMode` + * @param interestRateMode 2 for Variable, 1 is deprecated on v3.2.0 + * @param onBehalfOf The address of the user who will get his debt reduced/removed. Should be the address of the + * user calling the function if he wants to reduce/remove his own debt, or the address of any other + * other borrower whose debt should be removed + * @return The final amount repaid + */ + function repay( + address asset, + uint256 amount, + uint256 interestRateMode, + address onBehalfOf + ) external returns (uint256); + + /** + * @notice Repay with transfer approval of asset to be repaid done via permit function + * see: https://eips.ethereum.org/EIPS/eip-2612 and https://eips.ethereum.org/EIPS/eip-713 + * @param asset The address of the borrowed underlying asset previously borrowed + * @param amount The amount to repay + * - Send the value type(uint256).max in order to repay the whole debt for `asset` on the specific `debtMode` + * @param interestRateMode 2 for Variable, 1 is deprecated on v3.2.0 + * @param onBehalfOf Address of the user who will get his debt reduced/removed. Should be the address of the + * user calling the function if he wants to reduce/remove his own debt, or the address of any other + * other borrower whose debt should be removed + * @param deadline The deadline timestamp that the permit is valid + * @param permitV The V parameter of ERC712 permit sig + * @param permitR The R parameter of ERC712 permit sig + * @param permitS The S parameter of ERC712 permit sig + * @return The final amount repaid + */ + function repayWithPermit( + address asset, + uint256 amount, + uint256 interestRateMode, + address onBehalfOf, + uint256 deadline, + uint8 permitV, + bytes32 permitR, + bytes32 permitS + ) external returns (uint256); + + /** + * @notice Repays a borrowed `amount` on a specific reserve using the reserve aTokens, burning the + * equivalent debt tokens + * - E.g. User repays 100 USDC using 100 aUSDC, burning 100 variable debt tokens + * @dev Passing uint256.max as amount will clean up any residual aToken dust balance, if the user aToken + * balance is not enough to cover the whole debt + * @param asset The address of the borrowed underlying asset previously borrowed + * @param amount The amount to repay + * - Send the value type(uint256).max in order to repay the whole debt for `asset` on the specific `debtMode` + * @param interestRateMode DEPRECATED in v3.2.0 + * @return The final amount repaid + */ + function repayWithATokens( + address asset, + uint256 amount, + uint256 interestRateMode + ) external returns (uint256); + + /** + * @notice Allows suppliers to enable/disable a specific supplied asset as collateral + * @param asset The address of the underlying asset supplied + * @param useAsCollateral True if the user wants to use the supply as collateral, false otherwise + */ + function setUserUseReserveAsCollateral(address asset, bool useAsCollateral) external; + + /** + * @notice Function to liquidate a non-healthy position collateral-wise, with Health Factor below 1 + * - The caller (liquidator) covers `debtToCover` amount of debt of the user getting liquidated, and receives + * a proportionally amount of the `collateralAsset` plus a bonus to cover market risk + * @param collateralAsset The address of the underlying asset used as collateral, to receive as result of the liquidation + * @param debtAsset The address of the underlying borrowed asset to be repaid with the liquidation + * @param borrower The address of the borrower getting liquidated + * @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover + * @param receiveAToken True if the liquidators wants to receive the collateral aTokens, `false` if he wants + * to receive the underlying collateral asset directly + */ + function liquidationCall( + address collateralAsset, + address debtAsset, + address borrower, + uint256 debtToCover, + bool receiveAToken + ) external; + + /** + * @notice Allows smartcontracts to access the liquidity of the pool within one transaction, + * as long as the amount taken plus a fee is returned. + * @dev IMPORTANT There are security concerns for developers of flashloan receiver contracts that must be kept + * into consideration. For further details please visit https://docs.aave.com/developers/ + * @param receiverAddress The address of the contract receiving the funds, implementing IFlashLoanReceiver interface + * @param assets The addresses of the assets being flash-borrowed + * @param amounts The amounts of the assets being flash-borrowed + * @param interestRateModes Types of the debt to open if the flash loan is not returned: + * 0 -> Don't open any debt, just revert if funds can't be transferred from the receiver + * 1 -> Deprecated on v3.2.0 + * 2 -> Open debt at variable rate for the value of the amount flash-borrowed to the `onBehalfOf` address + * @param onBehalfOf The address that will receive the debt in the case of using 2 on `modes` + * @param params Variadic packed params to pass to the receiver as extra information + * @param referralCode The code used to register the integrator originating the operation, for potential rewards. + * 0 if the action is executed directly by the user, without any middle-man + */ + function flashLoan( + address receiverAddress, + address[] calldata assets, + uint256[] calldata amounts, + uint256[] calldata interestRateModes, + address onBehalfOf, + bytes calldata params, + uint16 referralCode + ) external; + + /** + * @notice Allows smartcontracts to access the liquidity of the pool within one transaction, + * as long as the amount taken plus a fee is returned. + * @dev IMPORTANT There are security concerns for developers of flashloan receiver contracts that must be kept + * into consideration. For further details please visit https://docs.aave.com/developers/ + * @param receiverAddress The address of the contract receiving the funds, implementing IFlashLoanSimpleReceiver interface + * @param asset The address of the asset being flash-borrowed + * @param amount The amount of the asset being flash-borrowed + * @param params Variadic packed params to pass to the receiver as extra information + * @param referralCode The code used to register the integrator originating the operation, for potential rewards. + * 0 if the action is executed directly by the user, without any middle-man + */ + function flashLoanSimple( + address receiverAddress, + address asset, + uint256 amount, + bytes calldata params, + uint16 referralCode + ) external; + + /** + * @notice Returns the user account data across all the reserves + * @param user The address of the user + * @return totalCollateralBase The total collateral of the user in the base currency used by the price feed + * @return totalDebtBase The total debt of the user in the base currency used by the price feed + * @return availableBorrowsBase The borrowing power left of the user in the base currency used by the price feed + * @return currentLiquidationThreshold The liquidation threshold of the user + * @return ltv The loan to value of The user + * @return healthFactor The current health factor of the user + */ + function getUserAccountData( + address user + ) + external + view + returns ( + uint256 totalCollateralBase, + uint256 totalDebtBase, + uint256 availableBorrowsBase, + uint256 currentLiquidationThreshold, + uint256 ltv, + uint256 healthFactor + ); + + /** + * @notice Initializes a reserve, activating it, assigning an aToken and debt tokens + * @dev Only callable by the PoolConfigurator contract + * @param asset The address of the underlying asset of the reserve + * @param aTokenAddress The address of the aToken that will be assigned to the reserve + * @param variableDebtAddress The address of the VariableDebtToken that will be assigned to the reserve + */ + function initReserve(address asset, address aTokenAddress, address variableDebtAddress) external; + + /** + * @notice Accumulates interest to all indexes of the reserve + * @dev Only callable by the PoolConfigurator contract + * @dev To be used when required by the configurator, for example when updating interest rates strategy data + * @param asset The address of the underlying asset of the reserve + */ + function syncIndexesState(address asset) external; + + /** + * @notice Updates interest rates on the reserve data + * @dev Only callable by the PoolConfigurator contract + * @dev To be used when required by the configurator, for example when updating interest rates strategy data + * @param asset The address of the underlying asset of the reserve + */ + function syncRatesState(address asset) external; + + /** + * @notice Sets the configuration bitmap of the reserve as a whole + * @dev Only callable by the PoolConfigurator contract + * @param asset The address of the underlying asset of the reserve + * @param configuration The new configuration bitmap + */ + function setConfiguration( + address asset, + DataTypes.ReserveConfigurationMap calldata configuration + ) external; + + /** + * @notice Returns the configuration of the reserve + * @param asset The address of the underlying asset of the reserve + * @return The configuration of the reserve + */ + function getConfiguration( + address asset + ) external view returns (DataTypes.ReserveConfigurationMap memory); + + /** + * @notice Returns the configuration of the user across all the reserves + * @param user The user address + * @return The configuration of the user + */ + function getUserConfiguration( + address user + ) external view returns (DataTypes.UserConfigurationMap memory); + + /** + * @notice Returns the normalized income of the reserve + * @param asset The address of the underlying asset of the reserve + * @return The reserve's normalized income + */ + function getReserveNormalizedIncome(address asset) external view returns (uint256); + + /** + * @notice Returns the normalized variable debt per unit of asset + * @dev WARNING: This function is intended to be used primarily by the protocol itself to get a + * "dynamic" variable index based on time, current stored index and virtual rate at the current + * moment (approx. a borrower would get if opening a position). This means that is always used in + * combination with variable debt supply/balances. + * If using this function externally, consider that is possible to have an increasing normalized + * variable debt that is not equivalent to how the variable debt index would be updated in storage + * (e.g. only updates with non-zero variable debt supply) + * @param asset The address of the underlying asset of the reserve + * @return The reserve normalized variable debt + */ + function getReserveNormalizedVariableDebt(address asset) external view returns (uint256); + + /** + * @notice Returns the state and configuration of the reserve + * @param asset The address of the underlying asset of the reserve + * @return The state and configuration data of the reserve + */ + function getReserveData(address asset) external view returns (DataTypes.ReserveDataLegacy memory); + + /** + * @notice Returns the virtual underlying balance of the reserve + * @param asset The address of the underlying asset of the reserve + * @return The reserve virtual underlying balance + */ + function getVirtualUnderlyingBalance(address asset) external view returns (uint128); + + /** + * @notice Validates and finalizes an aToken transfer + * @dev Only callable by the overlying aToken of the `asset` + * @param asset The address of the underlying asset of the aToken + * @param from The user from which the aTokens are transferred + * @param to The user receiving the aTokens + * @param scaledAmount The scaled amount being transferred/withdrawn + * @param scaledBalanceFromBefore The aToken scaled balance of the `from` user before the transfer + */ + function finalizeTransfer( + address asset, + address from, + address to, + uint256 scaledAmount, + uint256 scaledBalanceFromBefore + ) external; + + /** + * @notice Returns the list of the underlying assets of all the initialized reserves + * @dev It does not include dropped reserves + * @return The addresses of the underlying assets of the initialized reserves + */ + function getReservesList() external view returns (address[] memory); + + /** + * @notice Returns the number of initialized reserves + * @dev It includes dropped reserves + * @return The count + */ + function getReservesCount() external view returns (uint256); + + /** + * @notice Returns the address of the underlying asset of a reserve by the reserve id as stored in the DataTypes.ReserveData struct + * @param id The id of the reserve as stored in the DataTypes.ReserveData struct + * @return The address of the reserve associated with id + */ + function getReserveAddressById(uint16 id) external view returns (address); + + /** + * @notice Returns the PoolAddressesProvider connected to this contract + * @return The address of the PoolAddressesProvider + */ + function ADDRESSES_PROVIDER() external view returns (IPoolAddressesProvider); + + /** + * @notice Returns the ReserveInterestRateStrategy connected to all the reserves + * @return The address of the ReserveInterestRateStrategy contract + */ + function RESERVE_INTEREST_RATE_STRATEGY() external view returns (address); + + /** + * @notice Updates flash loan premium. All this premium is collected by the protocol treasury. + * @dev The premium is calculated on the total borrowed amount + * @dev Only callable by the PoolConfigurator contract + * @param flashLoanPremium The flash loan premium, expressed in bps + */ + function updateFlashloanPremium(uint128 flashLoanPremium) external; + + /** + * @notice Configures a new or alters an existing collateral configuration of an eMode. + * @dev In eMode, the protocol allows very high borrowing power to borrow assets of the same category. + * The category 0 is reserved as it's the default for volatile assets + * @param id The id of the category + * @param config The configuration of the category + */ + function configureEModeCategory( + uint8 id, + DataTypes.EModeCategoryBaseConfiguration memory config + ) external; + + /** + * @notice Replaces the current eMode collateralBitmap. + * @param id The id of the category + * @param collateralBitmap The collateralBitmap of the category + */ + function configureEModeCategoryCollateralBitmap(uint8 id, uint128 collateralBitmap) external; + + /** + * @notice Replaces the current eMode borrowableBitmap. + * @param id The id of the category + * @param borrowableBitmap The borrowableBitmap of the category + */ + function configureEModeCategoryBorrowableBitmap(uint8 id, uint128 borrowableBitmap) external; + + /** + * @notice Replaces the current eMode ltvzeroBitmap. + * @param id The id of the category + * @param ltvzeroBitmap The ltvzeroBitmap of the category + */ + function configureEModeCategoryLtvzeroBitmap(uint8 id, uint128 ltvzeroBitmap) external; + + /** + * @notice Sets the isolated flag of an eMode category. + * @param id The id of the category + * @param isolated True if the eMode should be isolated + */ + function configureEModeCategoryIsolated(uint8 id, bool isolated) external; + + /** + * @notice Returns the data of an eMode category + * @dev DEPRECATED use independent getters instead + * @param id The id of the category + * @return The configuration data of the category + */ + function getEModeCategoryData( + uint8 id + ) external view returns (DataTypes.EModeCategoryLegacy memory); + + /** + * @notice Returns the label of an eMode category + * @dev This function is deprecated and will be removed in a future version. + * @custom:deprecated + * @param id The id of the category + * @return The label of the category + */ + function getEModeCategoryLabel(uint8 id) external view returns (string memory); + + /** + * @notice Returns the collateral config of an eMode category + * @param id The id of the category + * @return The ltv,lt,lb of the category + */ + function getEModeCategoryCollateralConfig( + uint8 id + ) external view returns (DataTypes.CollateralConfig memory); + + /** + * @notice Returns the collateralBitmap of an eMode category + * @param id The id of the category + * @return The collateralBitmap of the category + */ + function getEModeCategoryCollateralBitmap(uint8 id) external view returns (uint128); + + /** + * @notice Returns the borrowableBitmap of an eMode category + * @param id The id of the category + * @return The borrowableBitmap of the category + */ + function getEModeCategoryBorrowableBitmap(uint8 id) external view returns (uint128); + + /** + * @notice Returns the ltvzero of an eMode category + * @param id The id of the category + * @return The ltvzeroBitmap of the category + */ + function getEModeCategoryLtvzeroBitmap(uint8 id) external view returns (uint128); + + /** + * @notice Returns the isolated flag of an eMode category + * @param id The id of the category + * @return True if the eMode category is isolated + */ + function getIsEModeCategoryIsolated(uint8 id) external view returns (bool); + + /** + * @notice Allows a user to use the protocol in eMode + * @param categoryId The id of the category + */ + function setUserEMode(uint8 categoryId) external; + + /** + * @notice Returns the eMode the user is using + * @param user The address of the user + * @return The eMode id + */ + function getUserEMode(address user) external view returns (uint256); + + /** + * @notice Sets the liquidation grace period of the given asset + * @dev To enable a liquidation grace period, a timestamp in the future should be set, + * To disable a liquidation grace period, any timestamp in the past works, like 0 + * @param asset The address of the underlying asset to set the liquidationGracePeriod + * @param until Timestamp when the liquidation grace period will end + **/ + function setLiquidationGracePeriod(address asset, uint40 until) external; + + /** + * @notice Returns the liquidation grace period of the given asset + * @param asset The address of the underlying asset + * @return Timestamp when the liquidation grace period will end + **/ + function getLiquidationGracePeriod(address asset) external view returns (uint40); + + /** + * @notice Returns the total fee on flash loans. + * @dev From v3.4 all flashloan fees will be send to the treasury. + * @return The total fee on flashloans + */ + function FLASHLOAN_PREMIUM_TOTAL() external view returns (uint128); + + /** + * @notice Returns the part of the flashloan fees sent to protocol + * @dev From v3.4 all flashloan fees will be send to the treasury and this value + * is always 100_00. + * @return The flashloan fee sent to the protocol treasury + */ + function FLASHLOAN_PREMIUM_TO_PROTOCOL() external view returns (uint128); + + /** + * @notice Returns the maximum number of reserves supported to be listed in this Pool + * @return The maximum number of reserves supported + */ + function MAX_NUMBER_RESERVES() external view returns (uint16); + + /** + * @notice Mints the assets accrued through the reserve factor to the treasury in the form of aTokens + * @param assets The list of reserves for which the minting needs to be executed + */ + function mintToTreasury(address[] calldata assets) external; + + /** + * @notice Rescue and transfer tokens locked in this contract + * @param token The address of the token + * @param to The address of the recipient + * @param amount The amount of token to transfer + */ + function rescueTokens(address token, address to, uint256 amount) external; + + /** + * @notice Supplies an `amount` of underlying asset into the reserve, receiving in return overlying aTokens. + * - E.g. User supplies 100 USDC and gets in return 100 aUSDC + * @dev Deprecated: Use the `supply` function instead + * @param asset The address of the underlying asset to supply + * @param amount The amount to be supplied + * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user + * wants to receive them on his own wallet, or a different address if the beneficiary of aTokens + * is a different wallet + * @param referralCode Code used to register the integrator originating the operation, for potential rewards. + * 0 if the action is executed directly by the user, without any middle-man + */ + function deposit(address asset, uint256 amount, address onBehalfOf, uint16 referralCode) external; + + /** + * @notice It covers the deficit of a specified reserve by burning the equivalent aToken `amount` for assets + * @dev The deficit of a reserve can occur due to situations where borrowed assets are not repaid, leading to bad debt. + * @param asset The address of the underlying asset to cover the deficit. + * @param amount The amount to be covered, in aToken + * @return The amount of tokens burned + */ + function eliminateReserveDeficit(address asset, uint256 amount) external returns (uint256); + + /** + * @notice Approves or disapproves a position manager. This position manager will be able + * to call the `setUserUseReserveAsCollateralOnBehalfOf` and the + * `setUserEModeOnBehalfOf` function on behalf of the user. + * @param positionManager The address of the position manager + * @param approve True if the position manager should be approved, false otherwise + */ + function approvePositionManager(address positionManager, bool approve) external; + + /** + * @notice Renounces a position manager role for a given user. + * @param user The address of the user + */ + function renouncePositionManagerRole(address user) external; + + /** + * @notice Sets the use as collateral flag for the user on the specific reserve on behalf of the user. + * @param asset The address of the underlying asset of the reserve + * @param useAsCollateral True if the user wants to use the reserve as collateral, false otherwise + * @param onBehalfOf The address of the user + */ + function setUserUseReserveAsCollateralOnBehalfOf( + address asset, + bool useAsCollateral, + address onBehalfOf + ) external; + + /** + * @notice Sets the eMode category for the user on the specific reserve on behalf of the user. + * @param categoryId The id of the category + * @param onBehalfOf The address of the user + */ + function setUserEModeOnBehalfOf(uint8 categoryId, address onBehalfOf) external; + + /** + * @notice Returns true if the `positionManager` address is approved to use the position manager role on behalf of the user. + * @param user The address of the user + * @param positionManager The address of the position manager + * @return True if the user is approved to use the position manager, false otherwise + */ + function isApprovedPositionManager( + address user, + address positionManager + ) external view returns (bool); + + /** + * @notice Returns the current deficit of a reserve. + * @param asset The address of the underlying asset of the reserve + * @return The current deficit of the reserve + */ + function getReserveDeficit(address asset) external view returns (uint256); + + /** + * @notice Returns the aToken address of a reserve. + * @param asset The address of the underlying asset of the reserve + * @return The address of the aToken + */ + function getReserveAToken(address asset) external view returns (address); + + /** + * @notice Returns the variableDebtToken address of a reserve. + * @param asset The address of the underlying asset of the reserve + * @return The address of the variableDebtToken + */ + function getReserveVariableDebtToken(address asset) external view returns (address); + + /** + * @notice Gets the address of the external FlashLoanLogic + */ + function getFlashLoanLogic() external view returns (address); + + /** + * @notice Gets the address of the external BorrowLogic + */ + function getBorrowLogic() external view returns (address); + + /** + * @notice Gets the address of the external LiquidationLogic + */ + function getLiquidationLogic() external view returns (address); + + /** + * @notice Gets the address of the external PoolLogic + */ + function getPoolLogic() external view returns (address); + + /** + * @notice Gets the address of the external SupplyLogic + */ + function getSupplyLogic() external view returns (address); +} diff --git a/plan/agw/research/preset-catalog-2026-10-15/IV3SwapRouter.sol b/plan/agw/research/preset-catalog-2026-10-15/IV3SwapRouter.sol new file mode 100644 index 00000000..f5d64597 --- /dev/null +++ b/plan/agw/research/preset-catalog-2026-10-15/IV3SwapRouter.sol @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.7.5; +pragma abicoder v2; + +import '@uniswap/v3-core/contracts/interfaces/callback/IUniswapV3SwapCallback.sol'; + +/// @title Router token swapping functionality +/// @notice Functions for swapping tokens via Uniswap V3 +interface IV3SwapRouter is IUniswapV3SwapCallback { + struct ExactInputSingleParams { + address tokenIn; + address tokenOut; + uint24 fee; + address recipient; + uint256 amountIn; + uint256 amountOutMinimum; + uint160 sqrtPriceLimitX96; + } + + /// @notice Swaps `amountIn` of one token for as much as possible of another token + /// @dev Setting `amountIn` to 0 will cause the contract to look up its own balance, + /// and swap the entire amount, enabling contracts to send tokens before calling this function. + /// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata + /// @return amountOut The amount of the received token + function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut); + + struct ExactInputParams { + bytes path; + address recipient; + uint256 amountIn; + uint256 amountOutMinimum; + } + + /// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path + /// @dev Setting `amountIn` to 0 will cause the contract to look up its own balance, + /// and swap the entire amount, enabling contracts to send tokens before calling this function. + /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata + /// @return amountOut The amount of the received token + function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut); + + struct ExactOutputSingleParams { + address tokenIn; + address tokenOut; + uint24 fee; + address recipient; + uint256 amountOut; + uint256 amountInMaximum; + uint160 sqrtPriceLimitX96; + } + + /// @notice Swaps as little as possible of one token for `amountOut` of another token + /// that may remain in the router after the swap. + /// @param params The parameters necessary for the swap, encoded as `ExactOutputSingleParams` in calldata + /// @return amountIn The amount of the input token + function exactOutputSingle(ExactOutputSingleParams calldata params) external payable returns (uint256 amountIn); + + struct ExactOutputParams { + bytes path; + address recipient; + uint256 amountOut; + uint256 amountInMaximum; + } + + /// @notice Swaps as little as possible of one token for `amountOut` of another along the specified path (reversed) + /// that may remain in the router after the swap. + /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactOutputParams` in calldata + /// @return amountIn The amount of the input token + function exactOutput(ExactOutputParams calldata params) external payable returns (uint256 amountIn); +} diff --git a/plan/agw/research/preset-catalog-2026-10-15/MERC20.sol b/plan/agw/research/preset-catalog-2026-10-15/MERC20.sol new file mode 100644 index 00000000..4f2d2897 --- /dev/null +++ b/plan/agw/research/preset-catalog-2026-10-15/MERC20.sol @@ -0,0 +1,295 @@ +// SPDX-License-Identifier: BSD-3-Clause +pragma solidity 0.8.19; + +import "@openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol"; +import "./MToken.sol"; + +/** + * @title Moonwell's MErc20 Contract + * @notice MTokens which wrap an EIP-20 underlying + * @author Moonwell + */ +contract MErc20 is MToken, MErc20Interface { + /** + * @notice Initialize the new money market + * @param underlying_ The address of the underlying asset + * @param comptroller_ The address of the Comptroller + * @param interestRateModel_ The address of the interest rate model + * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18 + * @param name_ ERC-20 name of this token + * @param symbol_ ERC-20 symbol of this token + * @param decimals_ ERC-20 decimal precision of this token + */ + function initialize( + address underlying_, + ComptrollerInterface comptroller_, + InterestRateModel interestRateModel_, + uint initialExchangeRateMantissa_, + string memory name_, + string memory symbol_, + uint8 decimals_ + ) public { + // MToken initialize does the bulk of the work + super.initialize( + comptroller_, + interestRateModel_, + initialExchangeRateMantissa_, + name_, + symbol_, + decimals_ + ); + + // Set underlying and sanity check it + underlying = underlying_; + EIP20Interface(underlying).totalSupply(); + } + + /*** User Interface ***/ + + /** + * @notice Sender supplies assets into the market and receives mTokens in exchange + * @dev Accrues interest whether or not the operation succeeds, unless reverted + * @param mintAmount The amount of the underlying asset to supply + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function mint(uint mintAmount) external override returns (uint) { + (uint err, ) = mintInternal(mintAmount); + return err; + } + + /** + * @notice Supply assets but without a 2-step approval process, EIP-2612 + * @dev Simply calls the underlying token's `permit()` function and then assumes things worked + * @param mintAmount The amount of the underlying asset to supply + * @param deadline The amount of the underlying asset to supply + * @param v ECDSA recovery id for the signature + * @param r ECDSA r parameter for the signature + * @param s ECDSA s parameter for the signature + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function mintWithPermit( + uint mintAmount, + uint deadline, + uint8 v, + bytes32 r, + bytes32 s + ) external override returns (uint) { + IERC20Permit token = IERC20Permit(underlying); + + // Go submit our pre-approval signature data to the underlying token, but + // explicitly fail if there is an issue. + SafeERC20.safePermit( + token, + msg.sender, + address(this), + mintAmount, + deadline, + v, + r, + s + ); + + (uint err, ) = mintInternal(mintAmount); + return err; + } + + /** + * @notice Sender redeems mTokens in exchange for the underlying asset + * @dev Accrues interest whether or not the operation succeeds, unless reverted + * @param redeemTokens The number of mTokens to redeem into underlying + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function redeem(uint redeemTokens) external override returns (uint) { + return redeemInternal(redeemTokens); + } + + /** + * @notice Sender redeems mTokens in exchange for a specified amount of underlying asset + * @dev Accrues interest whether or not the operation succeeds, unless reverted + * @param redeemAmount The amount of underlying to redeem + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function redeemUnderlying( + uint redeemAmount + ) external override returns (uint) { + return redeemUnderlyingInternal(redeemAmount); + } + + /** + * @notice Sender borrows assets from the protocol to their own address + * @param borrowAmount The amount of the underlying asset to borrow + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function borrow(uint borrowAmount) external override returns (uint) { + return borrowInternal(borrowAmount); + } + + /** + * @notice Sender repays their own borrow + * @param repayAmount The amount to repay, or uint.max for the full outstanding amount + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function repayBorrow(uint repayAmount) external override returns (uint) { + (uint err, ) = repayBorrowInternal(repayAmount); + return err; + } + + /** + * @notice Sender repays a borrow belonging to borrower + * @param borrower the account with the debt being payed off + * @param repayAmount The amount to repay, or uint.max for the full outstanding amount + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function repayBorrowBehalf( + address borrower, + uint repayAmount + ) external override returns (uint) { + (uint err, ) = repayBorrowBehalfInternal(borrower, repayAmount); + return err; + } + + /** + * @notice The sender liquidates the borrowers collateral. + * The collateral seized is transferred to the liquidator. + * @param borrower The borrower of this mToken to be liquidated + * @param repayAmount The amount of the underlying borrowed asset to repay + * @param mTokenCollateral The market in which to seize collateral from the borrower + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function liquidateBorrow( + address borrower, + uint repayAmount, + MTokenInterface mTokenCollateral + ) external override returns (uint) { + (uint err, ) = liquidateBorrowInternal( + borrower, + repayAmount, + mTokenCollateral + ); + return err; + } + + /** + * @notice A public function to sweep accidental ERC-20 transfers to this contract. Tokens are sent to admin (timelock) + * @param token The address of the ERC-20 token to sweep + */ + function sweepToken(EIP20NonStandardInterface token) external override { + require( + msg.sender == admin, + "MErc20::sweepToken: only admin can sweep tokens" + ); + require( + address(token) != underlying, + "MErc20::sweepToken: can not sweep underlying token" + ); + uint256 balance = token.balanceOf(address(this)); + token.transfer(admin, balance); + } + + /** + * @notice The sender adds to reserves. + * @param addAmount The amount fo underlying token to add as reserves + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function _addReserves(uint addAmount) external override returns (uint) { + return _addReservesInternal(addAmount); + } + + /*** Safe Token ***/ + + /** + * @notice Gets balance of this contract in terms of the underlying + * @dev This excludes the value of the current message, if any + * @return The quantity of underlying tokens owned by this contract + */ + function getCashPrior() internal view virtual override returns (uint) { + EIP20Interface token = EIP20Interface(underlying); + return token.balanceOf(address(this)); + } + + /** + * @dev Similar to EIP20 transfer, except it handles a False result from `transferFrom` and reverts in that case. + * This will revert due to insufficient balance or insufficient allowance. + * This function returns the actual amount received, + * which may be less than `amount` if there is a fee attached to the transfer. + * + * Note: This wrapper safely handles non-standard ERC-20 tokens that do not return a value. + * See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca + */ + function doTransferIn( + address from, + uint amount + ) internal virtual override returns (uint) { + // Read from storage once + address underlying_ = underlying; + EIP20NonStandardInterface token = EIP20NonStandardInterface( + underlying_ + ); + uint balanceBefore = EIP20Interface(underlying_).balanceOf( + address(this) + ); + token.transferFrom(from, address(this), amount); + + bool success; + assembly { + switch returndatasize() + case 0 { + // This is a non-standard ERC-20 + success := not(0) // set success to true + } + case 32 { + // This is a compliant ERC-20 + returndatacopy(0, 0, 32) + success := mload(0) // Set `success = returndata` of external call + } + default { + // This is an excessively non-compliant ERC-20, revert. + revert(0, 0) + } + } + require(success, "TOKEN_TRANSFER_IN_FAILED"); + + // Calculate the amount that was *actually* transferred + uint balanceAfter = EIP20Interface(underlying_).balanceOf( + address(this) + ); + require(balanceAfter >= balanceBefore, "TOKEN_TRANSFER_IN_OVERFLOW"); + return balanceAfter - balanceBefore; // underflow already checked above, just subtract + } + + /** + * @dev Similar to EIP20 transfer, except it handles a False success from `transfer` and returns an explanatory + * error code rather than reverting. If caller has not called checked protocol's balance, this may revert due to + * insufficient cash held in this contract. If caller has checked protocol's balance prior to this call, and verified + * it is >= amount, this should not revert in normal conditions. + * + * Note: This wrapper safely handles non-standard ERC-20 tokens that do not return a value. + * See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca + */ + function doTransferOut( + address payable to, + uint amount + ) internal virtual override { + EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying); + token.transfer(to, amount); + + bool success; + assembly { + switch returndatasize() + case 0 { + // This is a non-standard ERC-20 + success := not(0) // set success to true + } + case 32 { + // This is a compliant ERC-20 + returndatacopy(0, 0, 32) + success := mload(0) // Set `success = returndata` of override external call + } + default { + // This is an excessively non-compliant ERC-20, revert. + revert(0, 0) + } + } + require(success, "TOKEN_TRANSFER_OUT_FAILED"); + } +} diff --git a/plan/agw/research/preset-catalog-2026-10-15/MToken.sol b/plan/agw/research/preset-catalog-2026-10-15/MToken.sol new file mode 100644 index 00000000..bc0384e4 --- /dev/null +++ b/plan/agw/research/preset-catalog-2026-10-15/MToken.sol @@ -0,0 +1,2222 @@ +// SPDX-License-Identifier: BSD-3-Clause +pragma solidity 0.8.19; + +import "./ComptrollerInterface.sol"; +import "./MTokenInterfaces.sol"; +import "./TokenErrorReporter.sol"; +import "./Exponential.sol"; +import "./EIP20Interface.sol"; +import "./irm/InterestRateModel.sol"; + +/** + * @title Moonwell's MToken Contract + * @notice Abstract base for MTokens + * @author Moonwell + */ +abstract contract MToken is MTokenInterface, Exponential, TokenErrorReporter { + /** + * @notice Initialize the money market + * @param comptroller_ The address of the Comptroller + * @param interestRateModel_ The address of the interest rate model + * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18 + * @param name_ EIP-20 name of this token + * @param symbol_ EIP-20 symbol of this token + * @param decimals_ EIP-20 decimal precision of this token + */ + function initialize( + ComptrollerInterface comptroller_, + InterestRateModel interestRateModel_, + uint initialExchangeRateMantissa_, + string memory name_, + string memory symbol_, + uint8 decimals_ + ) public { + require(msg.sender == admin, "only admin may initialize the market"); + require( + accrualBlockTimestamp == 0 && borrowIndex == 0, + "market may only be initialized once" + ); + + // Set initial exchange rate + initialExchangeRateMantissa = initialExchangeRateMantissa_; + require( + initialExchangeRateMantissa > 0, + "initial exchange rate must be greater than zero." + ); + + // Set the comptroller + uint err = _setComptroller(comptroller_); + require(err == uint(Error.NO_ERROR), "setting comptroller failed"); + + // Initialize block timestamp and borrow index (block timestamp mocks depend on comptroller being set) + accrualBlockTimestamp = getBlockTimestamp(); + borrowIndex = mantissaOne; + + // Set the interest rate model (depends on block timestamp / borrow index) + err = _setInterestRateModelFresh(interestRateModel_); + require( + err == uint(Error.NO_ERROR), + "setting interest rate model failed" + ); + + name = name_; + symbol = symbol_; + decimals = decimals_; + + // The counter starts true to prevent changing it from zero to non-zero (i.e. smaller cost/refund) + _notEntered = true; + } + + /** + * @notice Transfer `tokens` tokens from `src` to `dst` by `spender` + * @dev Called by both `transfer` and `transferFrom` internally + * @param spender The address of the account performing the transfer + * @param src The address of the source account + * @param dst The address of the destination account + * @param tokens The number of tokens to transfer + * @return Whether or not the transfer succeeded + */ + function transferTokens( + address spender, + address src, + address dst, + uint tokens + ) internal returns (uint) { + /* Fail if transfer not allowed */ + uint allowed = comptroller.transferAllowed( + address(this), + src, + dst, + tokens + ); + if (allowed != 0) { + return + failOpaque( + Error.COMPTROLLER_REJECTION, + FailureInfo.TRANSFER_COMPTROLLER_REJECTION, + allowed + ); + } + + /* Do not allow self-transfers */ + if (src == dst) { + return fail(Error.BAD_INPUT, FailureInfo.TRANSFER_NOT_ALLOWED); + } + + /* Get the allowance, infinite for the account owner */ + uint startingAllowance = 0; + if (spender == src) { + startingAllowance = type(uint).max; + } else { + startingAllowance = transferAllowances[src][spender]; + } + + /* Do the calculations, checking for {under,over}flow */ + MathError mathErr; + uint allowanceNew; + uint srcTokensNew; + uint dstTokensNew; + + (mathErr, allowanceNew) = subUInt(startingAllowance, tokens); + if (mathErr != MathError.NO_ERROR) { + return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ALLOWED); + } + + (mathErr, srcTokensNew) = subUInt(accountTokens[src], tokens); + if (mathErr != MathError.NO_ERROR) { + return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ENOUGH); + } + + (mathErr, dstTokensNew) = addUInt(accountTokens[dst], tokens); + if (mathErr != MathError.NO_ERROR) { + return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_TOO_MUCH); + } + + ///////////////////////// + // EFFECTS & INTERACTIONS + // (No safe failures beyond this point) + + accountTokens[src] = srcTokensNew; + accountTokens[dst] = dstTokensNew; + + /* Eat some of the allowance (if necessary) */ + if (startingAllowance != type(uint).max) { + transferAllowances[src][spender] = allowanceNew; + } + + /* We emit a Transfer event */ + emit Transfer(src, dst, tokens); + + // unused function + // comptroller.transferVerify(address(this), src, dst, tokens); + + return uint(Error.NO_ERROR); + } + + /** + * @notice Transfer `amount` tokens from `msg.sender` to `dst` + * @param dst The address of the destination account + * @param amount The number of tokens to transfer + * @return Whether or not the transfer succeeded + */ + function transfer( + address dst, + uint256 amount + ) external override nonReentrant returns (bool) { + return + transferTokens(msg.sender, msg.sender, dst, amount) == + uint(Error.NO_ERROR); + } + + /** + * @notice Transfer `amount` tokens from `src` to `dst` + * @param src The address of the source account + * @param dst The address of the destination account + * @param amount The number of tokens to transfer + * @return Whether or not the transfer succeeded + */ + function transferFrom( + address src, + address dst, + uint256 amount + ) external override nonReentrant returns (bool) { + return + transferTokens(msg.sender, src, dst, amount) == + uint(Error.NO_ERROR); + } + + /** + * @notice Approve `spender` to transfer up to `amount` from `src` + * @dev This will overwrite the approval amount for `spender` + * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) + * @param spender The address of the account which may transfer tokens + * @param amount The number of tokens that are approved (uint.max means infinite) + * @return Whether or not the approval succeeded + */ + function approve( + address spender, + uint256 amount + ) external override returns (bool) { + address src = msg.sender; + transferAllowances[src][spender] = amount; + emit Approval(src, spender, amount); + return true; + } + + /** + * @notice Get the current allowance from `owner` for `spender` + * @param owner The address of the account which owns the tokens to be spent + * @param spender The address of the account which may transfer tokens + * @return The number of tokens allowed to be spent (uint.max means infinite) + */ + function allowance( + address owner, + address spender + ) external view override returns (uint256) { + return transferAllowances[owner][spender]; + } + + /** + * @notice Get the token balance of the `owner` + * @param owner The address of the account to query + * @return The number of tokens owned by `owner` + */ + function balanceOf(address owner) external view override returns (uint256) { + return accountTokens[owner]; + } + + /** + * @notice Get the underlying balance of the `owner` + * @dev This also accrues interest in a transaction + * @param owner The address of the account to query + * @return The amount of underlying owned by `owner` + */ + function balanceOfUnderlying( + address owner + ) external override returns (uint) { + Exp memory exchangeRate = Exp({mantissa: exchangeRateCurrent()}); + (MathError mErr, uint balance) = mulScalarTruncate( + exchangeRate, + accountTokens[owner] + ); + require(mErr == MathError.NO_ERROR, "balance could not be calculated"); + return balance; + } + + /** + * @notice Get a snapshot of the account's balances, and the cached exchange rate + * @dev This is used by comptroller to more efficiently perform liquidity checks. + * @param account Address of the account to snapshot + * @return (possible error, token balance, borrow balance, exchange rate mantissa) + */ + function getAccountSnapshot( + address account + ) external view override returns (uint, uint, uint, uint) { + uint mTokenBalance = accountTokens[account]; + uint borrowBalance; + uint exchangeRateMantissa; + + MathError mErr; + + (mErr, borrowBalance) = borrowBalanceStoredInternal(account); + if (mErr != MathError.NO_ERROR) { + return (uint(Error.MATH_ERROR), 0, 0, 0); + } + + (mErr, exchangeRateMantissa) = exchangeRateStoredInternal(); + if (mErr != MathError.NO_ERROR) { + return (uint(Error.MATH_ERROR), 0, 0, 0); + } + + return ( + uint(Error.NO_ERROR), + mTokenBalance, + borrowBalance, + exchangeRateMantissa + ); + } + + /** + * @dev Function to simply retrieve block timestamp + * This exists mainly for inheriting test contracts to stub this result. + */ + function getBlockTimestamp() internal view virtual returns (uint) { + return block.timestamp; + } + + /** + * @notice Returns the current per-timestamp borrow interest rate for this mToken + * @return The borrow interest rate per timestamp, scaled by 1e18 + */ + function borrowRatePerTimestamp() external view override returns (uint) { + return + interestRateModel.getBorrowRate( + getCashPrior(), + totalBorrows, + totalReserves + ); + } + + /** + * @notice Returns the current per-timestamp supply interest rate for this mToken + * @return The supply interest rate per timestamp, scaled by 1e18 + */ + function supplyRatePerTimestamp() external view override returns (uint) { + return + interestRateModel.getSupplyRate( + getCashPrior(), + totalBorrows, + totalReserves, + reserveFactorMantissa + ); + } + + /** + * @notice Returns the current total borrows plus accrued interest + * @return The total borrows with interest + */ + function totalBorrowsCurrent() + external + override + nonReentrant + returns (uint) + { + require( + accrueInterest() == uint(Error.NO_ERROR), + "accrue interest failed" + ); + return totalBorrows; + } + + /** + * @notice Accrue interest to updated borrowIndex and then calculate account's borrow balance using the updated borrowIndex + * @param account The address whose balance should be calculated after updating borrowIndex + * @return The calculated balance + */ + function borrowBalanceCurrent( + address account + ) external override nonReentrant returns (uint) { + require( + accrueInterest() == uint(Error.NO_ERROR), + "accrue interest failed" + ); + return borrowBalanceStored(account); + } + + /** + * @notice Return the borrow balance of account based on stored data + * @param account The address whose balance should be calculated + * @return The calculated balance + */ + function borrowBalanceStored( + address account + ) public view override returns (uint) { + (MathError err, uint result) = borrowBalanceStoredInternal(account); + require( + err == MathError.NO_ERROR, + "borrowBalanceStored: borrowBalanceStoredInternal failed" + ); + return result; + } + + /** + * @notice Return the borrow balance of account based on stored data + * @param account The address whose balance should be calculated + * @return (error code, the calculated balance or 0 if error code is non-zero) + */ + function borrowBalanceStoredInternal( + address account + ) internal view returns (MathError, uint) { + /* Note: we do not assert that the market is up to date */ + MathError mathErr; + uint principalTimesIndex; + uint result; + + /* Get borrowBalance and borrowIndex */ + BorrowSnapshot storage borrowSnapshot = accountBorrows[account]; + + /* If borrowBalance = 0 then borrowIndex is likely also 0. + * Rather than failing the calculation with a division by 0, we immediately return 0 in this case. + */ + if (borrowSnapshot.principal == 0) { + return (MathError.NO_ERROR, 0); + } + + /* Calculate new borrow balance using the interest index: + * recentBorrowBalance = borrower.borrowBalance * market.borrowIndex / borrower.borrowIndex + */ + (mathErr, principalTimesIndex) = mulUInt( + borrowSnapshot.principal, + borrowIndex + ); + if (mathErr != MathError.NO_ERROR) { + return (mathErr, 0); + } + + (mathErr, result) = divUInt( + principalTimesIndex, + borrowSnapshot.interestIndex + ); + if (mathErr != MathError.NO_ERROR) { + return (mathErr, 0); + } + + return (MathError.NO_ERROR, result); + } + + /** + * @notice Accrue interest then return the up-to-date exchange rate + * @return Calculated exchange rate scaled by 1e18 + */ + function exchangeRateCurrent() public override nonReentrant returns (uint) { + require( + accrueInterest() == uint(Error.NO_ERROR), + "accrue interest failed" + ); + return exchangeRateStored(); + } + + /** + * @notice Calculates the exchange rate from the underlying to the MToken + * @dev This function does not accrue interest before calculating the exchange rate + * @return Calculated exchange rate scaled by 1e18 + */ + function exchangeRateStored() public view override returns (uint) { + (MathError err, uint result) = exchangeRateStoredInternal(); + require( + err == MathError.NO_ERROR, + "exchangeRateStored: exchangeRateStoredInternal failed" + ); + return result; + } + + /** + * @notice Calculates the exchange rate from the underlying to the MToken + * @dev This function does not accrue interest before calculating the exchange rate + * @return (error code, calculated exchange rate scaled by 1e18) + */ + function exchangeRateStoredInternal() + internal + view + virtual + returns (MathError, uint) + { + uint _totalSupply = totalSupply; + if (_totalSupply == 0) { + /* + * If there are no tokens minted: + * exchangeRate = initialExchangeRate + */ + return (MathError.NO_ERROR, initialExchangeRateMantissa); + } else { + /* + * Otherwise: + * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply + */ + uint totalCash = getCashPrior(); + uint cashPlusBorrowsMinusReserves; + Exp memory exchangeRate; + MathError mathErr; + + (mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt( + totalCash, + totalBorrows, + totalReserves + ); + if (mathErr != MathError.NO_ERROR) { + return (mathErr, 0); + } + + (mathErr, exchangeRate) = getExp( + cashPlusBorrowsMinusReserves, + _totalSupply + ); + if (mathErr != MathError.NO_ERROR) { + return (mathErr, 0); + } + + return (MathError.NO_ERROR, exchangeRate.mantissa); + } + } + + /** + * @notice Get cash balance of this mToken in the underlying asset + * @return The quantity of underlying asset owned by this contract + */ + function getCash() external view override returns (uint) { + return getCashPrior(); + } + + /** + * @notice Applies accrued interest to total borrows and reserves + * @dev This calculates interest accrued from the last checkpointed block + * up to the current block and writes new checkpoint to storage. + */ + function accrueInterest() public virtual override returns (uint) { + /* Remember the initial block timestamp */ + uint currentBlockTimestamp = getBlockTimestamp(); + uint accrualBlockTimestampPrior = accrualBlockTimestamp; + + /* Short-circuit accumulating 0 interest */ + if (accrualBlockTimestampPrior == currentBlockTimestamp) { + return uint(Error.NO_ERROR); + } + + /* Read the previous values out of storage */ + uint cashPrior = getCashPrior(); + uint borrowsPrior = totalBorrows; + uint reservesPrior = totalReserves; + uint borrowIndexPrior = borrowIndex; + + /* Calculate the current borrow interest rate */ + uint borrowRateMantissa = interestRateModel.getBorrowRate( + cashPrior, + borrowsPrior, + reservesPrior + ); + require( + borrowRateMantissa <= borrowRateMaxMantissa, + "borrow rate is absurdly high" + ); + + /* Calculate the number of blocks elapsed since the last accrual */ + (MathError mathErr, uint blockDelta) = subUInt( + currentBlockTimestamp, + accrualBlockTimestampPrior + ); + require( + mathErr == MathError.NO_ERROR, + "could not calculate block delta" + ); + + /* + * Calculate the interest accumulated into borrows and reserves and the new index: + * simpleInterestFactor = borrowRate * blockDelta + * interestAccumulated = simpleInterestFactor * totalBorrows + * totalBorrowsNew = interestAccumulated + totalBorrows + * totalReservesNew = interestAccumulated * reserveFactor + totalReserves + * borrowIndexNew = simpleInterestFactor * borrowIndex + borrowIndex + */ + + Exp memory simpleInterestFactor; + uint interestAccumulated; + uint totalBorrowsNew; + uint totalReservesNew; + uint borrowIndexNew; + + (mathErr, simpleInterestFactor) = mulScalar( + Exp({mantissa: borrowRateMantissa}), + blockDelta + ); + if (mathErr != MathError.NO_ERROR) { + return + failOpaque( + Error.MATH_ERROR, + FailureInfo + .ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, + uint(mathErr) + ); + } + + (mathErr, interestAccumulated) = mulScalarTruncate( + simpleInterestFactor, + borrowsPrior + ); + if (mathErr != MathError.NO_ERROR) { + return + failOpaque( + Error.MATH_ERROR, + FailureInfo + .ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, + uint(mathErr) + ); + } + + (mathErr, totalBorrowsNew) = addUInt(interestAccumulated, borrowsPrior); + if (mathErr != MathError.NO_ERROR) { + return + failOpaque( + Error.MATH_ERROR, + FailureInfo + .ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, + uint(mathErr) + ); + } + + (mathErr, totalReservesNew) = mulScalarTruncateAddUInt( + Exp({mantissa: reserveFactorMantissa}), + interestAccumulated, + reservesPrior + ); + if (mathErr != MathError.NO_ERROR) { + return + failOpaque( + Error.MATH_ERROR, + FailureInfo + .ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, + uint(mathErr) + ); + } + + (mathErr, borrowIndexNew) = mulScalarTruncateAddUInt( + simpleInterestFactor, + borrowIndexPrior, + borrowIndexPrior + ); + if (mathErr != MathError.NO_ERROR) { + return + failOpaque( + Error.MATH_ERROR, + FailureInfo + .ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, + uint(mathErr) + ); + } + + ///////////////////////// + // EFFECTS & INTERACTIONS + // (No safe failures beyond this point) + + /* We write the previously calculated values into storage */ + accrualBlockTimestamp = currentBlockTimestamp; + borrowIndex = borrowIndexNew; + totalBorrows = totalBorrowsNew; + totalReserves = totalReservesNew; + + /* We emit an AccrueInterest event */ + emit AccrueInterest( + cashPrior, + interestAccumulated, + borrowIndexNew, + totalBorrowsNew + ); + + return uint(Error.NO_ERROR); + } + + /** + * @notice Sender supplies assets into the market and receives mTokens in exchange + * @dev Accrues interest whether or not the operation succeeds, unless reverted + * @param mintAmount The amount of the underlying asset to supply + * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount. + */ + function mintInternal( + uint mintAmount + ) internal nonReentrant returns (uint, uint) { + uint error = accrueInterest(); + if (error != uint(Error.NO_ERROR)) { + // accrueInterest emits logs on errors, but we still want to log the fact that an attempted borrow failed + return ( + fail(Error(error), FailureInfo.MINT_ACCRUE_INTEREST_FAILED), + 0 + ); + } + // mintFresh emits the actual Mint event if successful and logs on errors, so we don't need to + return mintFresh(msg.sender, mintAmount); + } + + struct MintLocalVars { + Error err; + MathError mathErr; + uint exchangeRateMantissa; + uint mintTokens; + uint totalSupplyNew; + uint accountTokensNew; + uint actualMintAmount; + } + + /** + * @notice User supplies assets into the market and receives mTokens in exchange + * @dev Assumes interest has already been accrued up to the current block + * @param minter The address of the account which is supplying the assets + * @param mintAmount The amount of the underlying asset to supply + * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount. + */ + function mintFresh( + address minter, + uint mintAmount + ) internal returns (uint, uint) { + /* Fail if mint not allowed */ + uint allowed = comptroller.mintAllowed( + address(this), + minter, + mintAmount + ); + if (allowed != 0) { + return ( + failOpaque( + Error.COMPTROLLER_REJECTION, + FailureInfo.MINT_COMPTROLLER_REJECTION, + allowed + ), + 0 + ); + } + + /* Verify market's block timestamp equals current block timestamp */ + if (accrualBlockTimestamp != getBlockTimestamp()) { + return ( + fail(Error.MARKET_NOT_FRESH, FailureInfo.MINT_FRESHNESS_CHECK), + 0 + ); + } + + MintLocalVars memory vars; + + ( + vars.mathErr, + vars.exchangeRateMantissa + ) = exchangeRateStoredInternal(); + if (vars.mathErr != MathError.NO_ERROR) { + return ( + failOpaque( + Error.MATH_ERROR, + FailureInfo.MINT_EXCHANGE_RATE_READ_FAILED, + uint(vars.mathErr) + ), + 0 + ); + } + + ///////////////////////// + // EFFECTS & INTERACTIONS + // (No safe failures beyond this point) + + /* + * We call `doTransferIn` for the minter and the mintAmount. + * Note: The mToken must handle variations between ERC-20 and GLMR underlying. + * `doTransferIn` reverts if anything goes wrong, since we can't be sure if + * side-effects occurred. The function returns the amount actually transferred, + * in case of a fee. On success, the mToken holds an additional `actualMintAmount` + * of cash. + */ + vars.actualMintAmount = doTransferIn(minter, mintAmount); + + /* + * We get the current exchange rate and calculate the number of mTokens to be minted: + * mintTokens = actualMintAmount / exchangeRate + */ + + (vars.mathErr, vars.mintTokens) = divScalarByExpTruncate( + vars.actualMintAmount, + Exp({mantissa: vars.exchangeRateMantissa}) + ); + require( + vars.mathErr == MathError.NO_ERROR, + "MINT_EXCHANGE_CALCULATION_FAILED" + ); + + /* + * We calculate the new total supply of mTokens and minter token balance, checking for overflow: + * totalSupplyNew = totalSupply + mintTokens + * accountTokensNew = accountTokens[minter] + mintTokens + */ + (vars.mathErr, vars.totalSupplyNew) = addUInt( + totalSupply, + vars.mintTokens + ); + require( + vars.mathErr == MathError.NO_ERROR, + "MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED" + ); + + (vars.mathErr, vars.accountTokensNew) = addUInt( + accountTokens[minter], + vars.mintTokens + ); + require( + vars.mathErr == MathError.NO_ERROR, + "MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED" + ); + + /* We write previously calculated values into storage */ + totalSupply = vars.totalSupplyNew; + accountTokens[minter] = vars.accountTokensNew; + + /* We emit a Mint event, and a Transfer event */ + emit Mint(minter, vars.actualMintAmount, vars.mintTokens); + emit Transfer(address(this), minter, vars.mintTokens); + + /* We call the defense hook */ + // unused function + // comptroller.mintVerify(address(this), minter, vars.actualMintAmount, vars.mintTokens); + + return (uint(Error.NO_ERROR), vars.actualMintAmount); + } + + /** + * @notice Sender redeems mTokens in exchange for the underlying asset + * @dev Accrues interest whether or not the operation succeeds, unless reverted + * @param redeemTokens The number of mTokens to redeem into underlying + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function redeemInternal( + uint redeemTokens + ) internal nonReentrant returns (uint) { + uint error = accrueInterest(); + if (error != uint(Error.NO_ERROR)) { + // accrueInterest emits logs on errors, but we still want to log the fact that an attempted redeem failed + return + fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED); + } + // redeemFresh emits redeem-specific logs on errors, so we don't need to + return redeemFresh(payable(msg.sender), redeemTokens, 0); + } + + /** + * @notice Sender redeems mTokens in exchange for a specified amount of underlying asset + * @dev Accrues interest whether or not the operation succeeds, unless reverted + * @param redeemAmount The amount of underlying to receive from redeeming mTokens + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function redeemUnderlyingInternal( + uint redeemAmount + ) internal nonReentrant returns (uint) { + uint error = accrueInterest(); + if (error != uint(Error.NO_ERROR)) { + // accrueInterest emits logs on errors, but we still want to log the fact that an attempted redeem failed + return + fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED); + } + // redeemFresh emits redeem-specific logs on errors, so we don't need to + return redeemFresh(payable(msg.sender), 0, redeemAmount); + } + + struct RedeemLocalVars { + Error err; + MathError mathErr; + uint exchangeRateMantissa; + uint redeemTokens; + uint redeemAmount; + uint totalSupplyNew; + uint accountTokensNew; + } + + /** + * @notice User redeems mTokens in exchange for the underlying asset + * @dev Assumes interest has already been accrued up to the current block + * @param redeemer The address of the account which is redeeming the tokens + * @param redeemTokensIn The number of mTokens to redeem into underlying (only one of redeemTokensIn or redeemAmountIn may be non-zero) + * @param redeemAmountIn The number of underlying tokens to receive from redeeming mTokens (only one of redeemTokensIn or redeemAmountIn may be non-zero) + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function redeemFresh( + address payable redeemer, + uint redeemTokensIn, + uint redeemAmountIn + ) internal returns (uint) { + require( + redeemTokensIn == 0 || redeemAmountIn == 0, + "one of redeemTokensIn or redeemAmountIn must be zero" + ); + + RedeemLocalVars memory vars; + + /* exchangeRate = invoke Exchange Rate Stored() */ + ( + vars.mathErr, + vars.exchangeRateMantissa + ) = exchangeRateStoredInternal(); + if (vars.mathErr != MathError.NO_ERROR) { + return + failOpaque( + Error.MATH_ERROR, + FailureInfo.REDEEM_EXCHANGE_RATE_READ_FAILED, + uint(vars.mathErr) + ); + } + + /* If redeemTokensIn > 0: */ + if (redeemTokensIn > 0) { + /* + * We calculate the exchange rate and the amount of underlying to be redeemed: + * redeemTokens = redeemTokensIn + * redeemAmount = redeemTokensIn x exchangeRateCurrent + */ + if (redeemTokensIn == type(uint).max) { + vars.redeemTokens = accountTokens[redeemer]; + } else { + vars.redeemTokens = redeemTokensIn; + } + + (vars.mathErr, vars.redeemAmount) = mulScalarTruncate( + Exp({mantissa: vars.exchangeRateMantissa}), + vars.redeemTokens + ); + if (vars.mathErr != MathError.NO_ERROR) { + return + failOpaque( + Error.MATH_ERROR, + FailureInfo.REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED, + uint(vars.mathErr) + ); + } + } else { + /* + * We get the current exchange rate and calculate the amount to be redeemed: + * redeemTokens = redeemAmountIn / exchangeRate + * redeemAmount = redeemAmountIn + */ + if (redeemAmountIn == type(uint).max) { + vars.redeemTokens = accountTokens[redeemer]; + + (vars.mathErr, vars.redeemAmount) = mulScalarTruncate( + Exp({mantissa: vars.exchangeRateMantissa}), + vars.redeemTokens + ); + if (vars.mathErr != MathError.NO_ERROR) { + return + failOpaque( + Error.MATH_ERROR, + FailureInfo + .REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED, + uint(vars.mathErr) + ); + } + } else { + vars.redeemAmount = redeemAmountIn; + + (vars.mathErr, vars.redeemTokens) = divScalarByExpTruncate( + redeemAmountIn, + Exp({mantissa: vars.exchangeRateMantissa}) + ); + if (vars.mathErr != MathError.NO_ERROR) { + return + failOpaque( + Error.MATH_ERROR, + FailureInfo + .REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, + uint(vars.mathErr) + ); + } + } + } + + /* Fail if redeem not allowed */ + uint allowed = comptroller.redeemAllowed( + address(this), + redeemer, + vars.redeemTokens + ); + if (allowed != 0) { + return + failOpaque( + Error.COMPTROLLER_REJECTION, + FailureInfo.REDEEM_COMPTROLLER_REJECTION, + allowed + ); + } + + /* Verify market's block timestamp equals current block timestamp */ + if (accrualBlockTimestamp != getBlockTimestamp()) { + return + fail( + Error.MARKET_NOT_FRESH, + FailureInfo.REDEEM_FRESHNESS_CHECK + ); + } + + /* + * We calculate the new total supply and redeemer balance, checking for underflow: + * totalSupplyNew = totalSupply - redeemTokens + * accountTokensNew = accountTokens[redeemer] - redeemTokens + */ + (vars.mathErr, vars.totalSupplyNew) = subUInt( + totalSupply, + vars.redeemTokens + ); + if (vars.mathErr != MathError.NO_ERROR) { + return + failOpaque( + Error.MATH_ERROR, + FailureInfo.REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, + uint(vars.mathErr) + ); + } + + (vars.mathErr, vars.accountTokensNew) = subUInt( + accountTokens[redeemer], + vars.redeemTokens + ); + if (vars.mathErr != MathError.NO_ERROR) { + return + failOpaque( + Error.MATH_ERROR, + FailureInfo.REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, + uint(vars.mathErr) + ); + } + + /* Fail gracefully if protocol has insufficient cash */ + if (getCashPrior() < vars.redeemAmount) { + return + fail( + Error.TOKEN_INSUFFICIENT_CASH, + FailureInfo.REDEEM_TRANSFER_OUT_NOT_POSSIBLE + ); + } + + ///////////////////////// + // EFFECTS & INTERACTIONS + // (No safe failures beyond this point) + + /* We write previously calculated values into storage */ + totalSupply = vars.totalSupplyNew; + accountTokens[redeemer] = vars.accountTokensNew; + + /* We emit a Transfer event, and a Redeem event */ + emit Transfer(redeemer, address(this), vars.redeemTokens); + emit Redeem(redeemer, vars.redeemAmount, vars.redeemTokens); + + /* We call the defense hook */ + comptroller.redeemVerify( + address(this), + redeemer, + vars.redeemAmount, + vars.redeemTokens + ); + + /* + * We invoke doTransferOut for the redeemer and the redeemAmount. + * Note: The mToken must handle variations between ERC-20 and GLMR underlying. + * On success, the mToken has redeemAmount less of cash. + * doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred. + */ + doTransferOut(redeemer, vars.redeemAmount); + + return uint(Error.NO_ERROR); + } + + /** + * @notice Sender borrows assets from the protocol to their own address + * @param borrowAmount The amount of the underlying asset to borrow + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function borrowInternal( + uint borrowAmount + ) internal nonReentrant returns (uint) { + uint error = accrueInterest(); + if (error != uint(Error.NO_ERROR)) { + // accrueInterest emits logs on errors, but we still want to log the fact that an attempted borrow failed + return + fail(Error(error), FailureInfo.BORROW_ACCRUE_INTEREST_FAILED); + } + // borrowFresh emits borrow-specific logs on errors, so we don't need to + return borrowFresh(payable(msg.sender), borrowAmount); + } + + struct BorrowLocalVars { + MathError mathErr; + uint accountBorrows; + uint accountBorrowsNew; + uint totalBorrowsNew; + } + + /** + * @notice Users borrow assets from the protocol to their own address + * @param borrowAmount The amount of the underlying asset to borrow + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function borrowFresh( + address payable borrower, + uint borrowAmount + ) internal returns (uint) { + /* Fail if borrow not allowed */ + uint allowed = comptroller.borrowAllowed( + address(this), + borrower, + borrowAmount + ); + if (allowed != 0) { + return + failOpaque( + Error.COMPTROLLER_REJECTION, + FailureInfo.BORROW_COMPTROLLER_REJECTION, + allowed + ); + } + + /* Verify market's block timestamp equals current block timestamp */ + if (accrualBlockTimestamp != getBlockTimestamp()) { + return + fail( + Error.MARKET_NOT_FRESH, + FailureInfo.BORROW_FRESHNESS_CHECK + ); + } + + /* Fail gracefully if protocol has insufficient underlying cash */ + if (getCashPrior() < borrowAmount) { + return + fail( + Error.TOKEN_INSUFFICIENT_CASH, + FailureInfo.BORROW_CASH_NOT_AVAILABLE + ); + } + + BorrowLocalVars memory vars; + + /* + * We calculate the new borrower and total borrow balances, failing on overflow: + * accountBorrowsNew = accountBorrows + borrowAmount + * totalBorrowsNew = totalBorrows + borrowAmount + */ + (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal( + borrower + ); + if (vars.mathErr != MathError.NO_ERROR) { + return + failOpaque( + Error.MATH_ERROR, + FailureInfo.BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, + uint(vars.mathErr) + ); + } + + (vars.mathErr, vars.accountBorrowsNew) = addUInt( + vars.accountBorrows, + borrowAmount + ); + if (vars.mathErr != MathError.NO_ERROR) { + return + failOpaque( + Error.MATH_ERROR, + FailureInfo + .BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, + uint(vars.mathErr) + ); + } + + (vars.mathErr, vars.totalBorrowsNew) = addUInt( + totalBorrows, + borrowAmount + ); + if (vars.mathErr != MathError.NO_ERROR) { + return + failOpaque( + Error.MATH_ERROR, + FailureInfo.BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, + uint(vars.mathErr) + ); + } + + ///////////////////////// + // EFFECTS & INTERACTIONS + // (No safe failures beyond this point) + + /* We write the previously calculated values into storage */ + accountBorrows[borrower].principal = vars.accountBorrowsNew; + accountBorrows[borrower].interestIndex = borrowIndex; + totalBorrows = vars.totalBorrowsNew; + + /* We emit a Borrow event */ + emit Borrow( + borrower, + borrowAmount, + vars.accountBorrowsNew, + vars.totalBorrowsNew + ); + + /* + * We invoke doTransferOut for the borrower and the borrowAmount. + * Note: The mToken must handle variations between ERC-20 and GLMR underlying. + * On success, the mToken borrowAmount less of cash. + * doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred. + */ + doTransferOut(borrower, borrowAmount); + + /* We call the defense hook */ + // unused function + // comptroller.borrowVerify(address(this), borrower, borrowAmount); + + return uint(Error.NO_ERROR); + } + + /** + * @notice Sender repays their own borrow + * @param repayAmount The amount to repay + * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. + */ + function repayBorrowInternal( + uint repayAmount + ) internal nonReentrant returns (uint, uint) { + uint error = accrueInterest(); + if (error != uint(Error.NO_ERROR)) { + // accrueInterest emits logs on errors, but we still want to log the fact that an attempted borrow failed + return ( + fail( + Error(error), + FailureInfo.REPAY_BORROW_ACCRUE_INTEREST_FAILED + ), + 0 + ); + } + // repayBorrowFresh emits repay-borrow-specific logs on errors, so we don't need to + return repayBorrowFresh(msg.sender, msg.sender, repayAmount); + } + + /** + * @notice Sender repays a borrow belonging to borrower + * @param borrower the account with the debt being payed off + * @param repayAmount The amount to repay + * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. + */ + function repayBorrowBehalfInternal( + address borrower, + uint repayAmount + ) internal nonReentrant returns (uint, uint) { + uint error = accrueInterest(); + if (error != uint(Error.NO_ERROR)) { + // accrueInterest emits logs on errors, but we still want to log the fact that an attempted borrow failed + return ( + fail( + Error(error), + FailureInfo.REPAY_BEHALF_ACCRUE_INTEREST_FAILED + ), + 0 + ); + } + // repayBorrowFresh emits repay-borrow-specific logs on errors, so we don't need to + return repayBorrowFresh(msg.sender, borrower, repayAmount); + } + + struct RepayBorrowLocalVars { + Error err; + MathError mathErr; + uint repayAmount; + uint borrowerIndex; + uint accountBorrows; + uint accountBorrowsNew; + uint totalBorrowsNew; + uint actualRepayAmount; + } + + /** + * @notice Borrows are repaid by another user (possibly the borrower). + * @param payer the account paying off the borrow + * @param borrower the account with the debt being payed off + * @param repayAmount the amount of underlying tokens being returned + * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. + */ + function repayBorrowFresh( + address payer, + address borrower, + uint repayAmount + ) internal returns (uint, uint) { + /* Fail if repayBorrow not allowed */ + uint allowed = comptroller.repayBorrowAllowed( + address(this), + payer, + borrower, + repayAmount + ); + if (allowed != 0) { + return ( + failOpaque( + Error.COMPTROLLER_REJECTION, + FailureInfo.REPAY_BORROW_COMPTROLLER_REJECTION, + allowed + ), + 0 + ); + } + + /* Verify market's block timestamp equals current block timestamp */ + if (accrualBlockTimestamp != getBlockTimestamp()) { + return ( + fail( + Error.MARKET_NOT_FRESH, + FailureInfo.REPAY_BORROW_FRESHNESS_CHECK + ), + 0 + ); + } + + RepayBorrowLocalVars memory vars; + + /* We remember the original borrowerIndex for verification purposes */ + vars.borrowerIndex = accountBorrows[borrower].interestIndex; + + /* We fetch the amount the borrower owes, with accumulated interest */ + (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal( + borrower + ); + if (vars.mathErr != MathError.NO_ERROR) { + return ( + failOpaque( + Error.MATH_ERROR, + FailureInfo + .REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, + uint(vars.mathErr) + ), + 0 + ); + } + + /* If repayAmount == uint.max, repayAmount = accountBorrows */ + if (repayAmount == type(uint).max) { + vars.repayAmount = vars.accountBorrows; + } else { + vars.repayAmount = repayAmount; + } + + ///////////////////////// + // EFFECTS & INTERACTIONS + // (No safe failures beyond this point) + + /* + * We call doTransferIn for the payer and the repayAmount + * Note: The mToken must handle variations between ERC-20 and GLMR underlying. + * On success, the mToken holds an additional repayAmount of cash. + * doTransferIn reverts if anything goes wrong, since we can't be sure if side effects occurred. + * it returns the amount actually transferred, in case of a fee. + */ + vars.actualRepayAmount = doTransferIn(payer, vars.repayAmount); + + /* + * We calculate the new borrower and total borrow balances, failing on underflow: + * accountBorrowsNew = accountBorrows - actualRepayAmount + * totalBorrowsNew = totalBorrows - actualRepayAmount + */ + (vars.mathErr, vars.accountBorrowsNew) = subUInt( + vars.accountBorrows, + vars.actualRepayAmount + ); + require( + vars.mathErr == MathError.NO_ERROR, + "REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED" + ); + + (vars.mathErr, vars.totalBorrowsNew) = subUInt( + totalBorrows, + vars.actualRepayAmount + ); + require( + vars.mathErr == MathError.NO_ERROR, + "REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED" + ); + + /* We write the previously calculated values into storage */ + accountBorrows[borrower].principal = vars.accountBorrowsNew; + accountBorrows[borrower].interestIndex = borrowIndex; + totalBorrows = vars.totalBorrowsNew; + + /* We emit a RepayBorrow event */ + emit RepayBorrow( + payer, + borrower, + vars.actualRepayAmount, + vars.accountBorrowsNew, + vars.totalBorrowsNew + ); + + /* We call the defense hook */ + // unused function + // comptroller.repayBorrowVerify(address(this), payer, borrower, vars.actualRepayAmount, vars.borrowerIndex); + + return (uint(Error.NO_ERROR), vars.actualRepayAmount); + } + + /** + * @notice The sender liquidates the borrowers collateral. + * The collateral seized is transferred to the liquidator. + * @param borrower The borrower of this mToken to be liquidated + * @param mTokenCollateral The market in which to seize collateral from the borrower + * @param repayAmount The amount of the underlying borrowed asset to repay + * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. + */ + function liquidateBorrowInternal( + address borrower, + uint repayAmount, + MTokenInterface mTokenCollateral + ) internal nonReentrant returns (uint, uint) { + uint error = accrueInterest(); + if (error != uint(Error.NO_ERROR)) { + // accrueInterest emits logs on errors, but we still want to log the fact that an attempted liquidation failed + return ( + fail( + Error(error), + FailureInfo.LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED + ), + 0 + ); + } + + error = mTokenCollateral.accrueInterest(); + if (error != uint(Error.NO_ERROR)) { + // accrueInterest emits logs on errors, but we still want to log the fact that an attempted liquidation failed + return ( + fail( + Error(error), + FailureInfo.LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED + ), + 0 + ); + } + + // liquidateBorrowFresh emits borrow-specific logs on errors, so we don't need to + return + liquidateBorrowFresh( + msg.sender, + borrower, + repayAmount, + mTokenCollateral + ); + } + + /** + * @notice The liquidator liquidates the borrowers collateral. + * The collateral seized is transferred to the liquidator. + * @param borrower The borrower of this mToken to be liquidated + * @param liquidator The address repaying the borrow and seizing collateral + * @param mTokenCollateral The market in which to seize collateral from the borrower + * @param repayAmount The amount of the underlying borrowed asset to repay + * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. + */ + function liquidateBorrowFresh( + address liquidator, + address borrower, + uint repayAmount, + MTokenInterface mTokenCollateral + ) internal returns (uint, uint) { + /* Fail if liquidate not allowed */ + uint allowed = comptroller.liquidateBorrowAllowed( + address(this), + address(mTokenCollateral), + liquidator, + borrower, + repayAmount + ); + if (allowed != 0) { + return ( + failOpaque( + Error.COMPTROLLER_REJECTION, + FailureInfo.LIQUIDATE_COMPTROLLER_REJECTION, + allowed + ), + 0 + ); + } + + /* Verify market's block timestamp equals current block timestamp */ + if (accrualBlockTimestamp != getBlockTimestamp()) { + return ( + fail( + Error.MARKET_NOT_FRESH, + FailureInfo.LIQUIDATE_FRESHNESS_CHECK + ), + 0 + ); + } + + /* Verify mTokenCollateral market's block timestamp equals current block timestamp */ + if (mTokenCollateral.accrualBlockTimestamp() != getBlockTimestamp()) { + return ( + fail( + Error.MARKET_NOT_FRESH, + FailureInfo.LIQUIDATE_COLLATERAL_FRESHNESS_CHECK + ), + 0 + ); + } + + /* Fail if borrower = liquidator */ + if (borrower == liquidator) { + return ( + fail( + Error.INVALID_ACCOUNT_PAIR, + FailureInfo.LIQUIDATE_LIQUIDATOR_IS_BORROWER + ), + 0 + ); + } + + /* Fail if repayAmount = 0 */ + if (repayAmount == 0) { + return ( + fail( + Error.INVALID_CLOSE_AMOUNT_REQUESTED, + FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_ZERO + ), + 0 + ); + } + + /* Fail if repayAmount = uint.max */ + if (repayAmount == type(uint).max) { + return ( + fail( + Error.INVALID_CLOSE_AMOUNT_REQUESTED, + FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX + ), + 0 + ); + } + + /* Fail if repayBorrow fails */ + (uint repayBorrowError, uint actualRepayAmount) = repayBorrowFresh( + liquidator, + borrower, + repayAmount + ); + if (repayBorrowError != uint(Error.NO_ERROR)) { + return ( + fail( + Error(repayBorrowError), + FailureInfo.LIQUIDATE_REPAY_BORROW_FRESH_FAILED + ), + 0 + ); + } + + ///////////////////////// + // EFFECTS & INTERACTIONS + // (No safe failures beyond this point) + + /* We calculate the number of collateral tokens that will be seized */ + (uint amountSeizeError, uint seizeTokens) = comptroller + .liquidateCalculateSeizeTokens( + address(this), + address(mTokenCollateral), + actualRepayAmount + ); + require( + amountSeizeError == uint(Error.NO_ERROR), + "LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED" + ); + + /* Revert if borrower collateral token balance < seizeTokens */ + require( + mTokenCollateral.balanceOf(borrower) >= seizeTokens, + "LIQUIDATE_SEIZE_TOO_MUCH" + ); + + // If this is also the collateral, run seizeInternal to avoid re-entrancy, otherwise make an external call + uint seizeError; + if (address(mTokenCollateral) == address(this)) { + seizeError = seizeInternal( + address(this), + liquidator, + borrower, + seizeTokens + ); + } else { + seizeError = mTokenCollateral.seize( + liquidator, + borrower, + seizeTokens + ); + } + + /* Revert if seize tokens fails (since we cannot be sure of side effects) */ + require(seizeError == uint(Error.NO_ERROR), "token seizure failed"); + + /* We emit a LiquidateBorrow event */ + emit LiquidateBorrow( + liquidator, + borrower, + actualRepayAmount, + address(mTokenCollateral), + seizeTokens + ); + + /* We call the defense hook */ + // unused function + // comptroller.liquidateBorrowVerify(address(this), address(mTokenCollateral), liquidator, borrower, actualRepayAmount, seizeTokens); + + return (uint(Error.NO_ERROR), actualRepayAmount); + } + + /** + * @notice Transfers collateral tokens (this market) to the liquidator. + * @dev Will fail unless called by another mToken during the process of liquidation. + * Its absolutely critical to use msg.sender as the borrowed mToken and not a parameter. + * @param liquidator The account receiving seized collateral + * @param borrower The account having collateral seized + * @param seizeTokens The number of mTokens to seize + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function seize( + address liquidator, + address borrower, + uint seizeTokens + ) external override nonReentrant returns (uint) { + return seizeInternal(msg.sender, liquidator, borrower, seizeTokens); + } + + struct SeizeInternalLocalVars { + MathError mathErr; + uint borrowerTokensNew; + uint liquidatorTokensNew; + uint liquidatorSeizeTokens; + uint protocolSeizeTokens; + uint protocolSeizeAmount; + uint exchangeRateMantissa; + uint totalReservesNew; + uint totalSupplyNew; + } + + /** + * @notice Transfers collateral tokens (this market) to the liquidator. + * @dev Called only during an in-kind liquidation, or by liquidateBorrow during the liquidation of another MToken. + * Its absolutely critical to use msg.sender as the seizer mToken and not a parameter. + * @param seizerToken The contract seizing the collateral (i.e. borrowed mToken) + * @param liquidator The account receiving seized collateral + * @param borrower The account having collateral seized + * @param seizeTokens The number of mTokens to seize + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function seizeInternal( + address seizerToken, + address liquidator, + address borrower, + uint seizeTokens + ) internal returns (uint) { + /* Fail if seize not allowed */ + uint allowed = comptroller.seizeAllowed( + address(this), + seizerToken, + liquidator, + borrower, + seizeTokens + ); + if (allowed != 0) { + return + failOpaque( + Error.COMPTROLLER_REJECTION, + FailureInfo.LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, + allowed + ); + } + + /* Fail if borrower = liquidator */ + if (borrower == liquidator) { + return + fail( + Error.INVALID_ACCOUNT_PAIR, + FailureInfo.LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER + ); + } + + SeizeInternalLocalVars memory vars; + + /* + * We calculate the new borrower and liquidator token balances, failing on underflow/overflow: + * borrowerTokensNew = accountTokens[borrower] - seizeTokens + * liquidatorTokensNew = accountTokens[liquidator] + seizeTokens + */ + (vars.mathErr, vars.borrowerTokensNew) = subUInt( + accountTokens[borrower], + seizeTokens + ); + if (vars.mathErr != MathError.NO_ERROR) { + return + failOpaque( + Error.MATH_ERROR, + FailureInfo.LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, + uint(vars.mathErr) + ); + } + + vars.protocolSeizeTokens = mul_( + seizeTokens, + Exp({mantissa: protocolSeizeShareMantissa}) + ); + vars.liquidatorSeizeTokens = sub_( + seizeTokens, + vars.protocolSeizeTokens + ); + + ( + vars.mathErr, + vars.exchangeRateMantissa + ) = exchangeRateStoredInternal(); + require(vars.mathErr == MathError.NO_ERROR, "exchange rate math error"); + + vars.protocolSeizeAmount = mul_ScalarTruncate( + Exp({mantissa: vars.exchangeRateMantissa}), + vars.protocolSeizeTokens + ); + + vars.totalReservesNew = add_(totalReserves, vars.protocolSeizeAmount); + vars.totalSupplyNew = sub_(totalSupply, vars.protocolSeizeTokens); + + (vars.mathErr, vars.liquidatorTokensNew) = addUInt( + accountTokens[liquidator], + vars.liquidatorSeizeTokens + ); + if (vars.mathErr != MathError.NO_ERROR) { + return + failOpaque( + Error.MATH_ERROR, + FailureInfo.LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, + uint(vars.mathErr) + ); + } + + ///////////////////////// + // EFFECTS & INTERACTIONS + // (No safe failures beyond this point) + + /* We write the previously calculated values into storage */ + totalReserves = vars.totalReservesNew; + totalSupply = vars.totalSupplyNew; + accountTokens[borrower] = vars.borrowerTokensNew; + accountTokens[liquidator] = vars.liquidatorTokensNew; + + /* Emit a Transfer event */ + emit Transfer(borrower, liquidator, vars.liquidatorSeizeTokens); + emit Transfer(borrower, address(this), vars.protocolSeizeTokens); + emit ReservesAdded( + address(this), + vars.protocolSeizeAmount, + vars.totalReservesNew + ); + + /* We call the defense hook */ + // unused function + // comptroller.seizeVerify(address(this), seizerToken, liquidator, borrower, seizeTokens); + + return uint(Error.NO_ERROR); + } + + /*** Admin Functions ***/ + + /** + * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. + * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. + * @param newPendingAdmin New pending admin. + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function _setPendingAdmin( + address payable newPendingAdmin + ) external override returns (uint) { + // Check caller = admin + if (msg.sender != admin) { + return + fail( + Error.UNAUTHORIZED, + FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK + ); + } + + // Save current value, if any, for inclusion in log + address oldPendingAdmin = pendingAdmin; + + // Store pendingAdmin with value newPendingAdmin + pendingAdmin = newPendingAdmin; + + // Emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin) + emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin); + + return uint(Error.NO_ERROR); + } + + /** + * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin + * @dev Admin function for pending admin to accept role and update admin + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function _acceptAdmin() external override returns (uint) { + // Check caller is pendingAdmin and pendingAdmin ≠ address(0) + if (msg.sender != pendingAdmin || msg.sender == address(0)) { + return + fail( + Error.UNAUTHORIZED, + FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK + ); + } + + // Save current values for inclusion in log + address oldAdmin = admin; + address oldPendingAdmin = pendingAdmin; + + // Store admin with value pendingAdmin + admin = pendingAdmin; + + // Clear the pending value + pendingAdmin = payable(address(0)); + + emit NewAdmin(oldAdmin, admin); + emit NewPendingAdmin(oldPendingAdmin, pendingAdmin); + + return uint(Error.NO_ERROR); + } + + /** + * @notice Sets a new comptroller for the market + * @dev Admin function to set a new comptroller + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function _setComptroller( + ComptrollerInterface newComptroller + ) public override returns (uint) { + // Check caller is admin + if (msg.sender != admin) { + return + fail( + Error.UNAUTHORIZED, + FailureInfo.SET_COMPTROLLER_OWNER_CHECK + ); + } + + ComptrollerInterface oldComptroller = comptroller; + // Ensure invoke comptroller.isComptroller() returns true + require(newComptroller.isComptroller(), "marker method returned false"); + + // Set market's comptroller to newComptroller + comptroller = newComptroller; + + // Emit NewComptroller(oldComptroller, newComptroller) + emit NewComptroller(oldComptroller, newComptroller); + + return uint(Error.NO_ERROR); + } + + /** + * @notice accrues interest and sets a new reserve factor for the protocol using _setReserveFactorFresh + * @dev Admin function to accrue interest and set a new reserve factor + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function _setReserveFactor( + uint newReserveFactorMantissa + ) external override nonReentrant returns (uint) { + uint error = accrueInterest(); + if (error != uint(Error.NO_ERROR)) { + // accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted reserve factor change failed. + return + fail( + Error(error), + FailureInfo.SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED + ); + } + // _setReserveFactorFresh emits reserve-factor-specific logs on errors, so we don't need to. + return _setReserveFactorFresh(newReserveFactorMantissa); + } + + /** + * @notice Sets a new reserve factor for the protocol (*requires fresh interest accrual) + * @dev Admin function to set a new reserve factor + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function _setReserveFactorFresh( + uint newReserveFactorMantissa + ) internal returns (uint) { + // Check caller is admin + if (msg.sender != admin) { + return + fail( + Error.UNAUTHORIZED, + FailureInfo.SET_RESERVE_FACTOR_ADMIN_CHECK + ); + } + + // Verify market's block timestamp equals current block timestamp + if (accrualBlockTimestamp != getBlockTimestamp()) { + return + fail( + Error.MARKET_NOT_FRESH, + FailureInfo.SET_RESERVE_FACTOR_FRESH_CHECK + ); + } + + // Check newReserveFactor ≤ maxReserveFactor + if (newReserveFactorMantissa > reserveFactorMaxMantissa) { + return + fail( + Error.BAD_INPUT, + FailureInfo.SET_RESERVE_FACTOR_BOUNDS_CHECK + ); + } + + uint oldReserveFactorMantissa = reserveFactorMantissa; + reserveFactorMantissa = newReserveFactorMantissa; + + emit NewReserveFactor( + oldReserveFactorMantissa, + newReserveFactorMantissa + ); + + return uint(Error.NO_ERROR); + } + + /** + * @notice Accrues interest and reduces reserves by transferring from msg.sender + * @param addAmount Amount of addition to reserves + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function _addReservesInternal( + uint addAmount + ) internal nonReentrant returns (uint) { + uint error = accrueInterest(); + if (error != uint(Error.NO_ERROR)) { + // accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted reduce reserves failed. + return + fail( + Error(error), + FailureInfo.ADD_RESERVES_ACCRUE_INTEREST_FAILED + ); + } + + // _addReservesFresh emits reserve-addition-specific logs on errors, so we don't need to. + (error, ) = _addReservesFresh(addAmount); + return error; + } + + /** + * @notice Add reserves by transferring from caller + * @dev Requires fresh interest accrual + * @param addAmount Amount of addition to reserves + * @return (uint, uint) An error code (0=success, otherwise a failure (see ErrorReporter.sol for details)) and the actual amount added, net token fees + */ + function _addReservesFresh(uint addAmount) internal returns (uint, uint) { + // totalReserves + actualAddAmount + uint totalReservesNew; + uint actualAddAmount; + + // We fail gracefully unless market's block timestamp equals current block timestamp + if (accrualBlockTimestamp != getBlockTimestamp()) { + return ( + fail( + Error.MARKET_NOT_FRESH, + FailureInfo.ADD_RESERVES_FRESH_CHECK + ), + actualAddAmount + ); + } + + ///////////////////////// + // EFFECTS & INTERACTIONS + // (No safe failures beyond this point) + + /* + * We call doTransferIn for the caller and the addAmount + * Note: The mToken must handle variations between ERC-20 and GLMR underlying. + * On success, the mToken holds an additional addAmount of cash. + * doTransferIn reverts if anything goes wrong, since we can't be sure if side effects occurred. + * it returns the amount actually transferred, in case of a fee. + */ + + actualAddAmount = doTransferIn(msg.sender, addAmount); + + totalReservesNew = totalReserves + actualAddAmount; + + /* Revert on overflow */ + require( + totalReservesNew >= totalReserves, + "add reserves unexpected overflow" + ); + + // Store reserves[n+1] = reserves[n] + actualAddAmount + totalReserves = totalReservesNew; + + /* Emit NewReserves(admin, actualAddAmount, reserves[n+1]) */ + emit ReservesAdded(msg.sender, actualAddAmount, totalReservesNew); + + /* Return (NO_ERROR, actualAddAmount) */ + return (uint(Error.NO_ERROR), actualAddAmount); + } + + /** + * @notice Accrues interest and reduces reserves by transferring to admin + * @param reduceAmount Amount of reduction to reserves + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function _reduceReserves( + uint reduceAmount + ) external override nonReentrant returns (uint) { + uint error = accrueInterest(); + if (error != uint(Error.NO_ERROR)) { + // accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted reduce reserves failed. + return + fail( + Error(error), + FailureInfo.REDUCE_RESERVES_ACCRUE_INTEREST_FAILED + ); + } + // _reduceReservesFresh emits reserve-reduction-specific logs on errors, so we don't need to. + return _reduceReservesFresh(reduceAmount); + } + + /** + * @notice Reduces reserves by transferring to admin + * @dev Requires fresh interest accrual + * @param reduceAmount Amount of reduction to reserves + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function _reduceReservesFresh(uint reduceAmount) internal returns (uint) { + // totalReserves - reduceAmount + uint totalReservesNew; + + // Check caller is admin + if (msg.sender != admin) { + return + fail( + Error.UNAUTHORIZED, + FailureInfo.REDUCE_RESERVES_ADMIN_CHECK + ); + } + + // We fail gracefully unless market's block timestamp equals current block timestamp + if (accrualBlockTimestamp != getBlockTimestamp()) { + return + fail( + Error.MARKET_NOT_FRESH, + FailureInfo.REDUCE_RESERVES_FRESH_CHECK + ); + } + + // Fail gracefully if protocol has insufficient underlying cash + if (getCashPrior() < reduceAmount) { + return + fail( + Error.TOKEN_INSUFFICIENT_CASH, + FailureInfo.REDUCE_RESERVES_CASH_NOT_AVAILABLE + ); + } + + // Check reduceAmount ≤ reserves[n] (totalReserves) + if (reduceAmount > totalReserves) { + return + fail(Error.BAD_INPUT, FailureInfo.REDUCE_RESERVES_VALIDATION); + } + + ///////////////////////// + // EFFECTS & INTERACTIONS + // (No safe failures beyond this point) + + totalReservesNew = totalReserves - reduceAmount; + // We checked reduceAmount <= totalReserves above, so this should never revert. + require( + totalReservesNew <= totalReserves, + "reduce reserves unexpected underflow" + ); + + // Store reserves[n+1] = reserves[n] - reduceAmount + totalReserves = totalReservesNew; + + // doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred. + doTransferOut(admin, reduceAmount); + + emit ReservesReduced(admin, reduceAmount, totalReservesNew); + + return uint(Error.NO_ERROR); + } + + /** + * @notice accrues interest and updates the interest rate model using _setInterestRateModelFresh + * @dev Admin function to accrue interest and update the interest rate model + * @param newInterestRateModel the new interest rate model to use + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function _setInterestRateModel( + InterestRateModel newInterestRateModel + ) public override returns (uint) { + uint error = accrueInterest(); + if (error != uint(Error.NO_ERROR)) { + // accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted change of interest rate model failed + return + fail( + Error(error), + FailureInfo.SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED + ); + } + // _setInterestRateModelFresh emits interest-rate-model-update-specific logs on errors, so we don't need to. + return _setInterestRateModelFresh(newInterestRateModel); + } + + /** + * @notice updates the interest rate model (*requires fresh interest accrual) + * @dev Admin function to update the interest rate model + * @param newInterestRateModel the new interest rate model to use + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function _setInterestRateModelFresh( + InterestRateModel newInterestRateModel + ) internal returns (uint) { + // Used to store old model for use in the event that is emitted on success + InterestRateModel oldInterestRateModel; + + // Check caller is admin + if (msg.sender != admin) { + return + fail( + Error.UNAUTHORIZED, + FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK + ); + } + + // We fail gracefully unless market's block timestamp equals current block timestamp + if (accrualBlockTimestamp != getBlockTimestamp()) { + return + fail( + Error.MARKET_NOT_FRESH, + FailureInfo.SET_INTEREST_RATE_MODEL_FRESH_CHECK + ); + } + + // Track the market's current interest rate model + oldInterestRateModel = interestRateModel; + + // Ensure invoke newInterestRateModel.isInterestRateModel() returns true + require( + newInterestRateModel.isInterestRateModel(), + "marker method returned false" + ); + + // Set the interest rate model to newInterestRateModel + interestRateModel = newInterestRateModel; + + // Emit NewMarketInterestRateModel(oldInterestRateModel, newInterestRateModel) + emit NewMarketInterestRateModel( + oldInterestRateModel, + newInterestRateModel + ); + + return uint(Error.NO_ERROR); + } + + /** + * @notice accrues interest and updates the protocol seize share using _setProtocolSeizeShareFresh + * @dev Admin function to accrue interest and update the protocol seize share + * @param newProtocolSeizeShareMantissa the new protocol seize share to use + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function _setProtocolSeizeShare( + uint newProtocolSeizeShareMantissa + ) external override nonReentrant returns (uint) { + uint error = accrueInterest(); + if (error != uint(Error.NO_ERROR)) { + // accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted change of protocol seize share failed + return + fail( + Error(error), + FailureInfo.SET_PROTOCOL_SEIZE_SHARE_ACCRUE_INTEREST_FAILED + ); + } + // _setProtocolSeizeShareFresh emits protocol-seize-share-update-specific logs on errors, so we don't need to. + return _setProtocolSeizeShareFresh(newProtocolSeizeShareMantissa); + } + + /** + * @notice updates the protocol seize share (*requires fresh interest accrual) + * @dev Admin function to update the protocol seize share + * @param newProtocolSeizeShareMantissa the new protocol seize share to use + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function _setProtocolSeizeShareFresh( + uint newProtocolSeizeShareMantissa + ) internal returns (uint) { + // Used to store old share for use in the event that is emitted on success + uint oldProtocolSeizeShareMantissa; + + // Check caller is admin + if (msg.sender != admin) { + return + fail( + Error.UNAUTHORIZED, + FailureInfo.SET_PROTOCOL_SEIZE_SHARE_OWNER_CHECK + ); + } + + // We fail gracefully unless market's block timestamp equals current block timestamp + if (accrualBlockTimestamp != getBlockTimestamp()) { + return + fail( + Error.MARKET_NOT_FRESH, + FailureInfo.SET_PROTOCOL_SEIZE_SHARE_FRESH_CHECK + ); + } + + // Track the market's current protocol seize share + oldProtocolSeizeShareMantissa = protocolSeizeShareMantissa; + + // Set the protocol seize share to newProtocolSeizeShareMantissa + protocolSeizeShareMantissa = newProtocolSeizeShareMantissa; + + // Emit NewProtocolSeizeShareMantissa(oldProtocolSeizeShareMantissa, newProtocolSeizeShareMantissa) + emit NewProtocolSeizeShare( + oldProtocolSeizeShareMantissa, + newProtocolSeizeShareMantissa + ); + + return uint(Error.NO_ERROR); + } + + /*** Safe Token ***/ + + /** + * @notice Gets balance of this contract in terms of the underlying + * @dev This excludes the value of the current message, if any + * @return The quantity of underlying owned by this contract + */ + function getCashPrior() internal view virtual returns (uint); + + /** + * @dev Performs a transfer in, reverting upon failure. Returns the amount actually transferred to the protocol, in case of a fee. + * This may revert due to insufficient balance or insufficient allowance. + */ + function doTransferIn( + address from, + uint amount + ) internal virtual returns (uint); + + /** + * @dev Performs a transfer out, ideally returning an explanatory error code upon failure tather than reverting. + * If caller has not called checked protocol's balance, may revert due to insufficient cash held in the contract. + * If caller has checked protocol's balance, and verified it is >= amount, this should not revert in normal conditions. + */ + function doTransferOut(address payable to, uint amount) internal virtual; + + /*** Reentrancy Guard ***/ + + /** + * @dev Prevents a contract from calling itself, directly or indirectly. + */ + modifier nonReentrant() { + require(_notEntered, "re-entered"); + _notEntered = false; + _; + _notEntered = true; // get a gas-refund post-Istanbul + } +} diff --git a/plan/agw/research/preset-catalog-2026-10-15/README.md b/plan/agw/research/preset-catalog-2026-10-15/README.md new file mode 100644 index 00000000..3cf86023 --- /dev/null +++ b/plan/agw/research/preset-catalog-2026-10-15/README.md @@ -0,0 +1,402 @@ + + +# EigenLayer + +**EigenLayer** is a protocol built on Ethereum that introduces Restaking, a primitive for app and service builders to make verifiable commitments to their users. + +EigenLayer brings together Restakers, Operators, and Autonomous Verifiable Services (AVSs) to extend Ethereum's cryptoeconomic security with penalty and reward commitments (like slashing) on staked assets acting as security. The protocol supports permissionless security; EIGEN, Native ETH, LSTs, and ERC-20s. + +## Deployments + +The deployments on `mainnet`, `base`, `sepolia`, `hoodi`, and `base sepolia` are on the below versions: + +| Environment | Version | Core Protocol Deployed | Supports Native Restaking | Supports Multichain | +| -------- | -------- | -------- | -------- | -------- | +| Mainnet Ethereum | [`v1.13.0`](https://github.com/Layr-Labs/eigenlayer-contracts/releases/tag/v1.13.0) | Yes | Yes | Yes (source & destination) | +| Base | [`v1.9.0`](https://github.com/Layr-Labs/eigenlayer-contracts/releases/tag/v1.9.0) | No | No | Yes (destination) | +| Testnet Sepolia | [`v1.12.1`](https://github.com/Layr-Labs/eigenlayer-contracts/releases/tag/v1.12.1) | Yes | No | Yes (source & destination) | +| Testnet Hoodi | [`v1.11.0`](https://github.com/Layr-Labs/eigenlayer-contracts/releases/tag/v1.11.0) | Yes | Yes | No | +| Testnet Base Sepolia | [`v1.9.0`](https://github.com/Layr-Labs/eigenlayer-contracts/releases/tag/v1.9.0) | No | No | Yes (destination) | + +### Current Deployment Contracts + +
+ Mainnet Ethereum + + +###### Core + +| Name | Proxy | Implementation | Notes | +| -------- | -------- | -------- | -------- | +| [`DelegationManager`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.6.0/src/contracts/core/DelegationManager.sol) | [`0x39053D51B77DC0d36036Fc1fCc8Cb819df8Ef37A`](https://etherscan.io/address/0x39053D51B77DC0d36036Fc1fCc8Cb819df8Ef37A) | [`0xE702...cE75`](https://etherscan.io/address/0xE7022a128Acd4C6cad7aFf6FA874D61f984BcE75) | Proxy: [`TUP@4.7.1`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.7.1/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| [`StrategyManager`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.12.0/src/contracts/core/StrategyManager.sol) | [`0x858646372CC42E1A627fcE94aa7A7033e7CF075A`](https://etherscan.io/address/0x858646372CC42E1A627fcE94aa7A7033e7CF075A) | [`0xa753...656A`](https://etherscan.io/address/0xa7536C85898dC424c6BFe8592F983661f830656A) | Proxy: [`TUP@4.7.1`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.7.1/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| [`EigenPodManager`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.6.0/src/contracts/pods/EigenPodManager.sol) | [`0x91E677b07F7AF907ec9a428aafA9fc14a0d3A338`](https://etherscan.io/address/0x91E677b07F7AF907ec9a428aafA9fc14a0d3A338) | [`0xd22d...E9dB`](https://etherscan.io/address/0xd22dd829779ADBf3869fb224F703452f7F95E9dB) | Proxy: [`TUP@4.7.1`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.7.1/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| [`AVSDirectory`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.3.0/src/contracts/core/AVSDirectory.sol) | [`0x135dda560e946695d6f155dacafc6f1f25c1f5af`](https://etherscan.io/address/0x135dda560e946695d6f155dacafc6f1f25c1f5af) | [`0xcD35...862b`](https://etherscan.io/address/0xcD35Cef328b496fA9d70a8d7C34EF3434614862b) | Proxy: [`TUP@4.7.1`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.7.1/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| [`RewardsCoordinator`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.12.0/src/contracts/core/RewardsCoordinator.sol) | [`0x7750d328b314EfFa365A0402CcfD489B80B0adda`](https://etherscan.io/address/0x7750d328b314EfFa365A0402CcfD489B80B0adda) | [`0xa067...3C26`](https://etherscan.io/address/0xa0673C53980665a706352412D2538bA005403C26) | Proxy: [`TUP@4.7.1`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.7.1/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| [`PermissionController`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.3.0/src/contracts/permissions/PermissionController.sol) | [`0x25E5F8B1E7aDf44518d35D5B2271f114e081f0E5`](https://etherscan.io/address/0x25E5F8B1E7aDf44518d35D5B2271f114e081f0E5) | [`0x36dd...EEd2`](https://etherscan.io/address/0x36dd260AbF606172875E6B5B7A96B435DC74EEd2) | Proxy: [`TUP@4.9.0`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| [`AllocationManager`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.6.0/src/contracts/core/AllocationManager.sol) | [`0x948a420b8CC1d6BFd0B6087C2E7c344a2CD0bc39`](https://etherscan.io/address/0x948a420b8CC1d6BFd0B6087C2E7c344a2CD0bc39) | [`0xdA2A...97C4`](https://etherscan.io/address/0xdA2A68D318A571dD550F2EcbCb09bf50497e97C4) | Proxy: [`TUP@4.9.0`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| [`EmissionsController`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.12.0/src/contracts/core/EmissionsController.sol) | [`0x619F988b4EA2f896ED068d84cE6F52550d6acE84`](https://etherscan.io/address/0x619F988b4EA2f896ED068d84cE6F52550d6acE84) | [`0x29Db...CA01`](https://etherscan.io/address/0x29Db9526F3A95F3059A5d3a9A05B611eBA7dcA01) | Proxy: [`TUP@4.7.1`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.7.1/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | + +###### Strategies + +Anyone can deploy and whitelist strategies for standard ERC20s by using the `StrategyFactory` deployed to the address below (see [docs](./docs/core/StrategyManager.md#strategyfactorydeploynewstrategy)). Strategies deployed from the `StrategyFactory` are deployed using the beacon proxy pattern: + +| Name | Proxy | Implementation | Notes | +| -------- | -------- | -------- | -------- | +| [`StrategyFactory`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.12.0/src/contracts/strategies/StrategyFactory.sol) | [`0x5e4C39Ad7A3E881585e383dB9827EB4811f6F647`](https://etherscan.io/address/0x5e4C39Ad7A3E881585e383dB9827EB4811f6F647) | [`0xbbc4...2b76`](https://etherscan.io/address/0xbbc4124C74C567396181fBfbaE746b80619D2b76) | Proxy: [`TUP@4.7.1`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.7.1/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| [`StrategyBase`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.12.0/src/contracts/strategies/StrategyBase.sol) | [`0x0ed6703C298d28aE0878d1b28e88cA87F9662fE9`](https://etherscan.io/address/0x0ed6703c298d28ae0878d1b28e88ca87f9662fe9) | [`0x8F6b...1Ce`](https://etherscan.io/address/0x8F6be4A906376bB4481E78cBF6FC783Cc0f8D1Ce) | - Beacon: [`BeaconProxy`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.7.0/contracts/proxy/beacon/BeaconProxy.sol)
- Strategies: [`UpgradeableBeacon`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.4.1/contracts/proxy/beacon/UpgradeableBeacon.sol) | +| [`DurationVaultStrategy`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.12.0/src/contracts/strategies/DurationVaultStrategy.sol) | [`0x0fCE0A591D96BB76883323eF555867111E2050a9`](https://etherscan.io/address/0x0fCE0A591D96BB76883323eF555867111E2050a9) | [`0xc946...8903`](https://etherscan.io/address/0xc946787cFd6c155886C673BF9815C841c1718903) | - Beacon: [`BeaconProxy`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.7.0/contracts/proxy/beacon/BeaconProxy.sol)
- Strategies: [`UpgradeableBeacon`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.4.1/contracts/proxy/beacon/UpgradeableBeacon.sol) | + +The following strategies were originally deployed and whitelisted outside of the `StrategyFactory`: + +| Name | Proxy | Implementation | Notes | +| -------- | -------- | -------- | -------- | +| [`StrategyBase (cbETH)`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.12.0/src/contracts/strategies/StrategyBaseTVLLimits.sol) | [`0x54945180dB7943c0ed0FEE7EdaB2Bd24620256bc`](https://etherscan.io/address/0x54945180dB7943c0ed0FEE7EdaB2Bd24620256bc) | [`0xB427...7230`](https://etherscan.io/address/0xB427E2Eb4Bb33eE3f1ee72dc9e347e8625a72230) | Proxy: [`TUP@4.7.1`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.7.1/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| [`StrategyBase (stETH)`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.12.0/src/contracts/strategies/StrategyBaseTVLLimits.sol) | [`0x93c4b944D05dfe6df7645A86cd2206016c51564D`](https://etherscan.io/address/0x93c4b944D05dfe6df7645A86cd2206016c51564D) | [`0xB427...7230`](https://etherscan.io/address/0xB427E2Eb4Bb33eE3f1ee72dc9e347e8625a72230) | Proxy: [`TUP@4.7.1`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.7.1/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| [`StrategyBase (rETH)`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.12.0/src/contracts/strategies/StrategyBaseTVLLimits.sol) | [`0x1BeE69b7dFFfA4E2d53C2a2Df135C388AD25dCD2`](https://etherscan.io/address/0x1BeE69b7dFFfA4E2d53C2a2Df135C388AD25dCD2) | [`0xB427...7230`](https://etherscan.io/address/0xB427E2Eb4Bb33eE3f1ee72dc9e347e8625a72230) | Proxy: [`TUP@4.7.1`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.7.1/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| [`StrategyBase (ETHx)`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.12.0/src/contracts/strategies/StrategyBaseTVLLimits.sol) | [`0x9d7eD45EE2E8FC5482fa2428f15C971e6369011d`](https://etherscan.io/address/0x9d7eD45EE2E8FC5482fa2428f15C971e6369011d) | [`0xB427...7230`](https://etherscan.io/address/0xB427E2Eb4Bb33eE3f1ee72dc9e347e8625a72230) | Proxy: [`TUP@4.7.1`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.7.1/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| [`StrategyBase (ankrETH)`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.12.0/src/contracts/strategies/StrategyBaseTVLLimits.sol) | [`0x13760F50a9d7377e4F20CB8CF9e4c26586c658ff`](https://etherscan.io/address/0x13760F50a9d7377e4F20CB8CF9e4c26586c658ff) | [`0xB427...7230`](https://etherscan.io/address/0xB427E2Eb4Bb33eE3f1ee72dc9e347e8625a72230) | Proxy: [`TUP@4.7.1`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.7.1/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| [`StrategyBase (OETH)`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.12.0/src/contracts/strategies/StrategyBaseTVLLimits.sol) | [`0xa4C637e0F704745D182e4D38cAb7E7485321d059`](https://etherscan.io/address/0xa4C637e0F704745D182e4D38cAb7E7485321d059) | [`0xB427...7230`](https://etherscan.io/address/0xB427E2Eb4Bb33eE3f1ee72dc9e347e8625a72230) | Proxy: [`TUP@4.7.1`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.7.1/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| [`StrategyBase (osETH)`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.12.0/src/contracts/strategies/StrategyBaseTVLLimits.sol) | [`0x57ba429517c3473B6d34CA9aCd56c0e735b94c02`](https://etherscan.io/address/0x57ba429517c3473B6d34CA9aCd56c0e735b94c02) | [`0xB427...7230`](https://etherscan.io/address/0xB427E2Eb4Bb33eE3f1ee72dc9e347e8625a72230) | Proxy: [`TUP@4.7.1`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.7.1/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| [`StrategyBase (swETH)`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.12.0/src/contracts/strategies/StrategyBaseTVLLimits.sol) | [`0x0Fe4F44beE93503346A3Ac9EE5A26b130a5796d6`](https://etherscan.io/address/0x0Fe4F44beE93503346A3Ac9EE5A26b130a5796d6) | [`0xB427...7230`](https://etherscan.io/address/0xB427E2Eb4Bb33eE3f1ee72dc9e347e8625a72230) | Proxy: [`TUP@4.7.1`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.7.1/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| [`StrategyBase (wBETH)`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.12.0/src/contracts/strategies/StrategyBaseTVLLimits.sol) | [`0x7CA911E83dabf90C90dD3De5411a10F1A6112184`](https://etherscan.io/address/0x7CA911E83dabf90C90dD3De5411a10F1A6112184) | [`0xB427...7230`](https://etherscan.io/address/0xB427E2Eb4Bb33eE3f1ee72dc9e347e8625a72230) | Proxy: [`TUP@4.7.1`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.7.1/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| [`StrategyBase (sfrxETH)`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.12.0/src/contracts/strategies/StrategyBaseTVLLimits.sol) | [`0x8CA7A5d6f3acd3A7A8bC468a8CD0FB14B6BD28b6`](https://etherscan.io/address/0x8CA7A5d6f3acd3A7A8bC468a8CD0FB14B6BD28b6) | [`0xB427...7230`](https://etherscan.io/address/0xB427E2Eb4Bb33eE3f1ee72dc9e347e8625a72230) | Proxy: [`TUP@4.7.1`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.7.1/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| [`StrategyBase (lsETH)`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.12.0/src/contracts/strategies/StrategyBaseTVLLimits.sol) | [`0xAe60d8180437b5C34bB956822ac2710972584473`](https://etherscan.io/address/0xAe60d8180437b5C34bB956822ac2710972584473) | [`0xB427...7230`](https://etherscan.io/address/0xB427E2Eb4Bb33eE3f1ee72dc9e347e8625a72230) | Proxy: [`TUP@4.7.1`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.7.1/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| [`StrategyBase (mETH)`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.12.0/src/contracts/strategies/StrategyBaseTVLLimits.sol) | [`0x298aFB19A105D59E74658C4C334Ff360BadE6dd2`](https://etherscan.io/address/0x298aFB19A105D59E74658C4C334Ff360BadE6dd2) | [`0xB427...7230`](https://etherscan.io/address/0xB427E2Eb4Bb33eE3f1ee72dc9e347e8625a72230) | Proxy: [`TUP@4.7.1`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.7.1/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | + +###### Strategies - Special + +The following strategies differ significantly from the other strategies deployed/used above: + +| Name | Proxy | Implementation | Notes | +| -------- | -------- | -------- | -------- | +| [`EigenStrategy (EIGEN)`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.12.0/src/contracts/strategies/EigenStrategy.sol) | [`0xaCB55C530Acdb2849e6d4f36992Cd8c9D50ED8F7`](https://etherscan.io/address/0xaCB55C530Acdb2849e6d4f36992Cd8c9D50ED8F7) | [`0x509A...8f40`](https://etherscan.io/address/0x509Aadb99487182b21fF4E9e7Eb362a9Ea8E8f40) | Proxy: [`TUP@4.9.0`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| `Beacon Chain ETH` | `0xbeaC0eeEeeeeEEeEeEEEEeeEEeEeeeEeeEEBEaC0` | - | - Used for Beacon Chain ETH shares
- Not a real contract! | + +###### EigenPods + +| Name | Proxy | Implementation | Notes | +| -------- | -------- | -------- | -------- | +| [`EigenPod (beacon)`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.6.0/src/contracts/pods/EigenPod.sol) | [`0x5a2a4F2F3C18f09179B6703e63D9eDD165909073`](https://etherscan.io/address/0x5a2a4F2F3C18f09179B6703e63D9eDD165909073) | [`0x53cC...e868`](https://etherscan.io/address/0x53cC2D82E08370Fe1e44a96f69CEc7d5b54ae868) | - Beacon: [`BeaconProxy`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.7.0/contracts/proxy/beacon/BeaconProxy.sol)
- Pods: [`UpgradeableBeacon`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.4.1/contracts/proxy/beacon/UpgradeableBeacon.sol) | + +###### EIGEN/bEIGEN + +| Name | Proxy | Implementation | Notes | +| -------- | -------- | -------- | -------- | +| [`Eigen`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.6.0/src/contracts/token/Eigen.sol) | [`0xec53bf9167f50cdeb3ae105f56099aaab9061f83`](https://etherscan.io/address/0xec53bf9167f50cdeb3ae105f56099aaab9061f83) | [`0x2C4A...2E50`](https://etherscan.io/address/0x2C4A81e257381F87F5A5C4bd525116466D972E50) | Proxy: [`TUP@4.9.0`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| [`Backing Eigen`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.6.0/src/contracts/token/BackingEigen.sol) | [`0x83E9115d334D248Ce39a6f36144aEaB5b3456e75`](https://etherscan.io/address/0x83E9115d334D248Ce39a6f36144aEaB5b3456e75) | [`0xF2b2...9b17`](https://etherscan.io/address/0xF2b225815F70c9b327DC9db758A36c92A4279b17) | Proxy: [`TUP@4.9.0`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| [`SignedDistributor`](https://etherscan.io/address/0x035bdAeaB85E47710C27EdA7FD754bA80aD4ad02#code) | - | [`0x035b...ad02`](https://etherscan.io/address/0x035bdAeaB85E47710C27EdA7FD754bA80aD4ad02) | - | + +###### AVS + +The following contracts are used by AVSs. + +| Name | Proxy | Implementation | Notes | +| -------- | -------- | -------- | -------- | +| [`ReleaseManager`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.8.1/src/contracts/core/ReleaseManager.sol) | [`0xeDA3CAd031c0cf367cF3f517Ee0DC98F9bA80C8F`](https://etherscan.io/address/0xeDA3CAd031c0cf367cF3f517Ee0DC98F9bA80C8F) | [`0xD0cb...13bd`](https://etherscan.io/address/0xD0cb07Df397b122bB7ebaA453356F21f8Ff813bd) | Proxy: [`TUP@4.9.0`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| [`TaskMailbox`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.8.1/src/contracts/avs/task/TaskMailbox.sol) | [`0x132b466d9d5723531F68797519DfED701aC2C749`](https://etherscan.io/address/0x132b466d9d5723531F68797519DfED701aC2C749) | [`0xA2A9...c55e`](https://etherscan.io/address/0xA2A9D0F957D81A0f8134F68803240f1CAD81c55e) | Proxy: [`TUP@4.9.0`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | + +###### Multichain - Source + +The multichain protocol expects AVSs to register on the source chain. AVS's stakes are then transported to supported destination chains. For the mainnet Ethereum network, the destination chains include Base. + +| Name | Proxy | Implementation | Notes | +| -------- | -------- | -------- | -------- | +| [`CrossChainRegistry`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.8.1/src/contracts/multichain/CrossChainRegistry.sol) | [`0x9376A5863F2193cdE13e1aB7c678F22554E2Ea2b`](https://etherscan.io/address/0x9376A5863F2193cdE13e1aB7c678F22554E2Ea2b) | [`0xdc23...642C`](https://etherscan.io/address/0xdc2354FaDd4bf0f9857038381917D0089880642C) | Proxy: [`TUP@4.9.0`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| [`KeyRegistrar`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.8.1/src/contracts/permissions/KeyRegistrar.sol) | [`0x54f4bC6bDEbe479173a2bbDc31dD7178408A57A4`](https://etherscan.io/address/0x54f4bC6bDEbe479173a2bbDc31dD7178408A57A4) | [`0x0f93...C219`](https://etherscan.io/address/0x0f939726Ab8514c13546804311149a8CC244C219) | Proxy: [`TUP@4.9.0`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | + +###### Multichain - Destination + +| Name | Proxy | Implementation | Notes | +| -------- | -------- | -------- | -------- | +| [`OperatorTableUpdater`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.8.1/src/contracts/multichain/OperatorTableUpdater.sol) | [`0x5557E1fE3068A1e823cE5Dcd052c6C352E2617B5`](https://etherscan.io/address/0x5557E1fE3068A1e823cE5Dcd052c6C352E2617B5) | [`0x8c4F...adF7`](https://etherscan.io/address/0x8c4F429e6d884899ebf4602bd2691920B056adF7) | Proxy: [`TUP@4.9.0`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| [`ECDSACertificateVerifier`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.8.1/src/contracts/multichain/ECDSACertificateVerifier.sol) | [`0xd0930ee96D07de4F9d493c259232222e46B6EC25`](https://etherscan.io/address/0xd0930ee96D07de4F9d493c259232222e46B6EC25) | [`0x2d52...40dC`](https://etherscan.io/address/0x2d52c39461795835b1F8F6cD242f4955AaC040dC) | Proxy: [`TUP@4.9.0`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| [`BN254CertificateVerifier`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.8.1/src/contracts/multichain/BN254CertificateVerifier.sol) | [`0x3F55654b2b2b86bB11bE2f72657f9C33bf88120A`](https://etherscan.io/address/0x3F55654b2b2b86bB11bE2f72657f9C33bf88120A) | [`0x9907...eaD2`](https://etherscan.io/address/0x9907690007b7ECFE1E03F96beca1a957faE3eaD2) | Proxy: [`TUP@4.9.0`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | + +###### Multisigs + +| Name | Proxy | Implementation | Notes | +| -------- | -------- | -------- | -------- | +| [`PauserRegistry`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.8.1/src/contracts/permissions/PauserRegistry.sol) | - | [`0xB876...2806`](https://etherscan.io/address/0xB8765ed72235d279c3Fb53936E4606db0Ef12806) | | +| [`OZ: TimelockController`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v4.7/contracts/governance/TimelockController.sol) | - | [`0xC06F...Aa2d`](https://etherscan.io/address/0xC06Fd4F821eaC1fF1ae8067b36342899b57BAa2d) | | +| [`OZ: TimelockController (BEIGEN)`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v4.7/contracts/governance/TimelockController.sol) | - | [`0x7381...bc53`](https://etherscan.io/address/0x738130BC8eADe1Bc65A9c056DEa636835896bc53) | | +| [`OZ: Proxy Admin`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.7.1/contracts/proxy/transparent/ProxyAdmin.sol) | - | [`0x8b95...2444`](https://etherscan.io/address/0x8b9566AdA63B64d1E1dcF1418b43fd1433b72444) | | +| [`Pauser Multisig`](https://github.com/safe-global/safe-contracts/blob/v1.3.0/contracts/GnosisSafe.sol) | [`0x5050389572f2d220ad927CcbeA0D406831012390`](https://etherscan.io/address/0x5050389572f2d220ad927CcbeA0D406831012390) | - | | +| [`Community Multisig`](https://github.com/safe-global/safe-contracts/blob/v1.3.0/contracts/GnosisSafe.sol) | [`0xFEA47018D632A77bA579846c840d5706705Dc598`](https://etherscan.io/address/0xFEA47018D632A77bA579846c840d5706705Dc598) | - | | +| [`Executor Multisig`](https://github.com/safe-global/safe-contracts/blob/v1.3.0/contracts/GnosisSafe.sol) | [`0x369e6F597e22EaB55fFb173C6d9cD234BD699111`](https://etherscan.io/address/0x369e6F597e22EaB55fFb173C6d9cD234BD699111) | - | | +| [`Operations Multisig`](https://github.com/safe-global/safe-contracts/blob/v1.3.0/contracts/GnosisSafe.sol) | [`0xBE1685C81aA44FF9FB319dD389addd9374383e90`](https://etherscan.io/address/0xBE1685C81aA44FF9FB319dD389addd9374383e90) | - | | +| [`Protocol Council Multisig`](https://github.com/safe-global/safe-contracts/blob/v1.3.0/contracts/GnosisSafe.sol) | [`0x461854d84ee845f905e0ecf6c288ddeeb4a9533f`](https://etherscan.io/address/0x461854d84ee845f905e0ecf6c288ddeeb4a9533f) | - | | +| [`Foundation Multisig`](https://github.com/safe-global/safe-contracts/blob/v1.3.0/contracts/GnosisSafe.sol) | [`0xbb00DDa2832850a43840A3A86515E3Fe226865F2`](https://etherscan.io/address/0xbb00DDa2832850a43840A3A86515E3Fe226865F2) | - | | +| [`BEIGEN Executor Multisig`](https://github.com/safe-global/safe-contracts/blob/v1.3.0/contracts/GnosisSafe.sol) | [`0x942eaF324971440384e4cA0ffA39fC3bb369D67d`](https://etherscan.io/address/0x942eaF324971440384e4cA0ffA39fC3bb369D67d) | - | | +| [`Multichain Deployer Multisig`](https://github.com/safe-global/safe-contracts/blob/v1.3.0/contracts/GnosisSafe.sol) | [`0xa3053EF25F1F7d9D55a7655372B8a31D0f40eCA9`](https://etherscan.io/address/0xa3053EF25F1F7d9D55a7655372B8a31D0f40eCA9) | - | | + + +
+ + + +
+ Base + + +**Note: Base only supports verification of tasks from stake that lives on Mainnet Ethereum. Standard core protocol functionality (restaking, slashing) does not exist on Base.** + +###### Multichain - Destination + +| Name | Proxy | Implementation | Notes | +| -------- | -------- | -------- | -------- | +| [`OperatorTableUpdater`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.8.1/src/contracts/multichain/OperatorTableUpdater.sol) | [`0x5557E1fE3068A1e823cE5Dcd052c6C352E2617B5`](https://basescan.org/address/0x5557E1fE3068A1e823cE5Dcd052c6C352E2617B5) | [`0x792F...419D`](https://basescan.org/address/0x792FfeA0D8734695670697f8b9f03DE3F666419D) | Proxy: [`TUP@4.9.0`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| [`ECDSACertificateVerifier`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.8.1/src/contracts/multichain/ECDSACertificateVerifier.sol) | [`0xd0930ee96D07de4F9d493c259232222e46B6EC25`](https://basescan.org/address/0xd0930ee96D07de4F9d493c259232222e46B6EC25) | [`0xf2cC...025F`](https://basescan.org/address/0xf2cC35A48561c2344577489a0873339F5B7E025F) | Proxy: [`TUP@4.9.0`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| [`BN254CertificateVerifier`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.8.1/src/contracts/multichain/BN254CertificateVerifier.sol) | [`0x3F55654b2b2b86bB11bE2f72657f9C33bf88120A`](https://basescan.org/address/0x3F55654b2b2b86bB11bE2f72657f9C33bf88120A) | [`0xc6c7...5D7d`](https://basescan.org/address/0xc6c7a63518d0150D57C6b00CDC7F13eB4b275D7d) | Proxy: [`TUP@4.9.0`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | + +###### AVS + +The following contracts are used by AVSs. + +| Name | Proxy | Implementation | Notes | +| -------- | -------- | -------- | -------- | +| [`TaskMailbox`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.8.1/src/contracts/avs/task/TaskMailbox.sol) | [`0x132b466d9d5723531F68797519DfED701aC2C749`](https://basescan.org/address/0x132b466d9d5723531F68797519DfED701aC2C749) | [`0x6eD2...c1bd`](https://basescan.org/address/0x6eD28c7dfEa8F70a7edec02A1E295DA6307Fc1bd) | Proxy: [`TUP@4.9.0`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | + +###### Multisigs + +| Name | Proxy | Implementation | Notes | +| -------- | -------- | -------- | -------- | +| [`PauserRegistry`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.8.1/src/contracts/permissions/PauserRegistry.sol) | - | [`0xb175...6ea`](https://basescan.org/address/0xb1754226917e866c1701f1d9F9E135D88f2e86ea) | | +| [`OZ: TimelockController`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v4.7/contracts/governance/TimelockController.sol) | - | [`0xE48D...ABd`](https://basescan.org/address/0xE48D7CaeC1790b293667e4bB2dE1E00536F2bABd) | | +| [`OZ: Proxy Admin`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/ProxyAdmin.sol) | - | [`0xDb00...9CE`](https://basescan.org/address/0xDb0052E272D1D126617c36A9D6d65C801d1549CE) | | +| [`Pauser Multisig`](https://github.com/safe-global/safe-contracts/blob/v1.3.0/contracts/GnosisSafe.sol) | [`0x1a051eF1524cbaEa57Ca04319ef93fE78903D5E6`](https://basescan.org/address/0x1a051eF1524cbaEa57Ca04319ef93fE78903D5E6) | - | | +| [`Operations Multisig`](https://github.com/safe-global/safe-contracts/blob/v1.3.0/contracts/GnosisSafe.sol) | [`0x8eD55c7640497Db15aC32c698c1a06E2E604d865`](https://basescan.org/address/0x8eD55c7640497Db15aC32c698c1a06E2E604d865) | - | | +| [`Protocol Council Multisig`](https://github.com/safe-global/safe-contracts/blob/v1.3.0/contracts/GnosisSafe.sol) | [`0x841B988aaEafce13b6456ff34015FBc42Aedb7e6`](https://basescan.org/address/0x841B988aaEafce13b6456ff34015FBc42Aedb7e6) | - | | +| [`Community Multisig`](https://github.com/safe-global/safe-contracts/blob/v1.3.0/contracts/GnosisSafe.sol) | [`0xC107547924C7D1d3E2d10eA8DF534BBfC5F373e6`](https://basescan.org/address/0xC107547924C7D1d3E2d10eA8DF534BBfC5F373e6) | - | | +| [`Executor Multisig`](https://github.com/safe-global/safe-contracts/blob/v1.3.0/contracts/GnosisSafe.sol) | [`0x5d808608Ad70873ca4dE50F83416264dc15264C2`](https://basescan.org/address/0x5d808608Ad70873ca4dE50F83416264dc15264C2) | - | | +| [`Multichain Deployer Multisig`](https://github.com/safe-global/safe-contracts/blob/v1.3.0/contracts/GnosisSafe.sol) | [`0xa3053EF25F1F7d9D55a7655372B8a31D0f40eCA9`](https://basescan.org/address/0xa3053EF25F1F7d9D55a7655372B8a31D0f40eCA9) | - | | + +
+ + + +
+ Testnet Sepolia + + +You can view the deployed contract addresses below, or check out the code itself on the [`testnet-sepolia`](https://github.com/Layr-Labs/eigenlayer-contracts/tree/testnet-sepolia) branch. + +###### Core + +| Name | Proxy | Implementation | Notes | +| -------- | -------- | -------- | -------- | +| [`DelegationManager`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.5.0/src/contracts/core/DelegationManager.sol) | [`0xD4A7E1Bd8015057293f0D0A557088c286942e84b`](https://sepolia.etherscan.io/address/0xD4A7E1Bd8015057293f0D0A557088c286942e84b) | [`0xa6Fe...C0f5`](https://sepolia.etherscan.io/address/0xa6FeC50d15FCaE6d3Ac8755e350C747F7733C0f5) | Proxy: [`TUP@4.9.0`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| [`StrategyManager`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.5.0/src/contracts/core/StrategyManager.sol) | [`0x2E3D6c0744b10eb0A4e6F679F71554a39Ec47a5D`](https://sepolia.etherscan.io/address/0x2E3D6c0744b10eb0A4e6F679F71554a39Ec47a5D) | [`0x7D59...E6F1`](https://sepolia.etherscan.io/address/0x7D59F252Bd32733f8850c50bF6BB2e46BF37E6F1) | Proxy: [`TUP@4.9.0`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| [`EigenPodManager`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.5.0/src/contracts/pods/EigenPodManager.sol) | [`0x56BfEb94879F4543E756d26103976c567256034a`](https://sepolia.etherscan.io/address/0x56BfEb94879F4543E756d26103976c567256034a) | [`0x151e...75D4`](https://sepolia.etherscan.io/address/0x151eCe1662E530f4889F016a63FC58F4b72175D4) | Proxy: [`TUP@4.9.0`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | All EigenPod functionality is paused on Sepolia | +| [`AVSDirectory`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.3.0/src/contracts/core/AVSDirectory.sol) | [`0xa789c91ECDdae96865913130B786140Ee17aF545`](https://sepolia.etherscan.io/address/0xa789c91ECDdae96865913130B786140Ee17aF545) | [`0x3216...6D69`](https://sepolia.etherscan.io/address/0x321604fDA757e8728d7b338C284613E2A0136D69) | Proxy: [`TUP@4.9.0`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| [`RewardsCoordinator`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.3.0/src/contracts/core/RewardsCoordinator.sol) | [`0x5ae8152fb88c26ff9ca5C014c94fca3c68029349`](https://sepolia.etherscan.io/address/0x5ae8152fb88c26ff9ca5C014c94fca3c68029349) | [`0x5Ac1...FF61`](https://sepolia.etherscan.io/address/0x5Ac1705931E999aa267167DaE57b41fA690bFF61) | Proxy: [`TUP@4.9.0`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| [`AllocationManager`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.5.0/src/contracts/core/AllocationManager.sol) | [`0x42583067658071247ec8CE0A516A58f682002d07`](https://sepolia.etherscan.io/address/0x42583067658071247ec8CE0A516A58f682002d07) | [`0x87cf...4f31`](https://sepolia.etherscan.io/address/0x87cffb49a29d4dC1C0842c70a75eDBa9B62e4f31) | Proxy: [`TUP@4.9.0`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| [`PermissionController`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.3.0/src/contracts/permissions/PermissionController.sol) | [`0x44632dfBdCb6D3E21EF613B0ca8A6A0c618F5a37`](https://sepolia.etherscan.io/address/0x44632dfBdCb6D3E21EF613B0ca8A6A0c618F5a37) | [`0xEBDa...B720`](https://sepolia.etherscan.io/address/0xEBDa1FCe8527C0c9ac94a60D7ECA37640415B720) | Proxy: [`TUP@4.9.0`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| [`KeyRegistrar`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.8.0-testnet-final/src/contracts/permissions/KeyRegistrar.sol) | [`0xA4dB30D08d8bbcA00D40600bee9F029984dB162a`](https://sepolia.etherscan.io/address/0xA4dB30D08d8bbcA00D40600bee9F029984dB162a) | [`0x1AFc...68e6`](https://sepolia.etherscan.io/address/0x1AFc1E6c6bA44B21Ce621B5B41fAa085682c68e6) | Proxy: [`TUP@4.9.0`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | + +###### Strategies + +Anyone can deploy and whitelist strategies for standard ERC20s by using the `StrategyFactory` deployed to the address below (see [docs](./docs/core/StrategyManager.md#strategyfactorydeploynewstrategy)). Strategies deployed from the `StrategyFactory` are deployed using the beacon proxy pattern: + +| Name | Proxy | Implementation | Notes | +| -------- | -------- | -------- | -------- | +| [`StrategyFactory`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.3.0/src/contracts/strategies/StrategyFactory.sol) | [`0x066cF95c1bf0927124DFB8B02B401bc23A79730D`](https://sepolia.etherscan.io/address/0x066cF95c1bf0927124DFB8B02B401bc23A79730D) | [`0x3f98...c5Ac`](https://sepolia.etherscan.io/address/0x3f98d8B9CFa2102aD340C19648E8BB3C06fbc5Ac) | Proxy: [`TUP@4.9.0`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| [`StrategyBase`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.5.0/src/contracts/strategies/StrategyBase.sol) | [`0x427e627Bc7E83cac0f84337d3Ad94230C32697D3`](https://sepolia.etherscan.io/address/0x427e627Bc7E83cac0f84337d3Ad94230C32697D3) | [`0x8f31...5cEf`](https://sepolia.etherscan.io/address/0x8f31bFC631B51A39f027A7C9750F7B5cCe9E5cEf) | - Beacon: [`BeaconProxy`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.7.0/contracts/proxy/beacon/BeaconProxy.sol)
- Strategies: [`UpgradeableBeacon`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.4.1/contracts/proxy/beacon/UpgradeableBeacon.sol) | +| [`StETH Strategy`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.5.0/src/contracts/strategies/StrategyBase.sol) | [`0x8b29d91e67b013e855EaFe0ad704aC4Ab086a574`](https://sepolia.etherscan.io/address/0x8b29d91e67b013e855EaFe0ad704aC4Ab086a574) | [`0x8f31...5cEf`](https://sepolia.etherscan.io/address/0x8f31bFC631B51A39f027A7C9750F7B5cCe9E5cEf) | Strategy Factory deployed | +| [`WETH Strategy`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.5.0/src/contracts/strategies/StrategyBase.sol) | [`0x424246eF71b01ee33aA33aC590fd9a0855F5eFbc`](https://sepolia.etherscan.io/address/0x424246eF71b01ee33aA33aC590fd9a0855F5eFbc) | [`0x8f31...5cEf`](https://sepolia.etherscan.io/address/0x8f31bFC631B51A39f027A7C9750F7B5cCe9E5cEf) | Strategy Factory deployed | + +###### Strategies - Special + +The following strategies differ significantly from the other strategies deployed/used above: + +| Name | Proxy | Implementation | Notes | +| -------- | -------- | -------- | -------- | +| [`EigenStrategy (EIGEN)`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.5.0/src/contracts/strategies/EigenStrategy.sol) | [`0x8E93249a6C37a32024756aaBd813E6139b17D1d5`](https://sepolia.etherscan.io/address/0x8E93249a6C37a32024756aaBd813E6139b17D1d5) | [`0xE8E4...7afC`](https://sepolia.etherscan.io/address/0xE8E469151e8d561Be94a4838B582B7da25487afC) | Proxy: [`TUP@4.9.0`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| `Beacon Chain ETH` | `0xbeaC0eeEeeeeEEeEeEEEEeeEEeEeeeEeeEEBEaC0` | - | - Used for Beacon Chain ETH shares
- Not a real contract! | + +###### EigenPods + +**NOTE: Due to the permissioned validator set on Sepolia, all EigenPod functionality is *PAUSED*.** + +| Name | Proxy | Implementation | Notes | +| -------- | -------- | -------- | -------- | +| [`EigenPod (beacon)`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.6.0/src/contracts/pods/EigenPod.sol) | [`0x0e19E56E41D42137d00dD4f51EC2F613E50cAcf4`](https://sepolia.etherscan.io/address/0x0e19E56E41D42137d00dD4f51EC2F613E50cAcf4) | [`0xb1B6...B533`](https://sepolia.etherscan.io/address/0xb1B6dAD80AD719BC5A700f8F3C9Da46224D3B533) | - Beacon: [`BeaconProxy`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.4.1/contracts/proxy/beacon/BeaconProxy.sol)
- Pods: [`UpgradeableBeacon`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.4.1/contracts/proxy/beacon/UpgradeableBeacon.sol) | + +###### EIGEN/bEIGEN + +| Name | Proxy | Implementation | Notes | +| -------- | -------- | -------- | -------- | +| [`Eigen`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.6.0/src/contracts/token/Eigen.sol) | [`0x0011FA2c512063C495f77296Af8d195F33A8Dd38`](https://sepolia.etherscan.io/address/0x0011FA2c512063C495f77296Af8d195F33A8Dd38) | [`0x7ec6...BD6F`](https://sepolia.etherscan.io/address/0x7ec6a02235Bf8d8a1fDB894AD2E1573192bfBD6F) | Proxy: [`TUP@4.9.0`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| [`Backing Eigen`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.3.0/src/contracts/token/BackingEigen.sol) | [`0xc5B857A92245f64e9D90cCc5b096Db82eB77eB5c`](https://sepolia.etherscan.io/address/0xc5B857A92245f64e9D90cCc5b096Db82eB77eB5c) | [`0x1298...3173`](https://sepolia.etherscan.io/address/0x12988B679AA497C30A8D1850eCC4Dc7700383173) | Proxy: [`TUP@4.9.0`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | + +###### AVS + +The following contracts are used by AVSs. + +| Name | Proxy | Implementation | Notes | +| -------- | -------- | -------- | -------- | +| [`ReleaseManager`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.8.0-testnet-final/src/contracts/core/ReleaseManager.sol) | [`0x59c8D715DCa616e032B744a753C017c9f3E16bf4`](https://sepolia.etherscan.io/address/0x59c8D715DCa616e032B744a753C017c9f3E16bf4) | [`0x67cE...2ac6`](https://sepolia.etherscan.io/address/0x67cEc1bE4De9D4a96Bd6dB28F9ceD6A1bD562ac6) | Proxy: [`TUP@4.9.0`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| [`TaskMailbox`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.8.0-testnet-final/src/contracts/avs/task/TaskMailbox.sol) | [`0xB99CC53e8db7018f557606C2a5B066527bF96b26`](https://sepolia.etherscan.io/address/0xB99CC53e8db7018f557606C2a5B066527bF96b26) | [`0x49A8...5AdB`](https://sepolia.etherscan.io/address/0x49A800bfFa5B561daD94Adf4Ea9bfe35bBEB5AdB) | Proxy: [`TUP@4.9.0`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | + +###### Multichain - Source + +The multichain protocol expects AVSs to register on the source chain. AVS's stakes are then transported to supported destination chains. For the sepolia network, the destination chains are sepolia and base-sepolia. + +| Name | Proxy | Implementation | Notes | +| -------- | -------- | -------- | -------- | +| [`CrossChainRegistry`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.8.0-testnet-final/src/contracts/multichain/source/CrossChainRegistry.sol) | [`0x287381B1570d9048c4B4C7EC94d21dDb8Aa1352a`](https://sepolia.etherscan.io/address/0x287381B1570d9048c4B4C7EC94d21dDb8Aa1352a) | [`0x4a93...3084`](https://sepolia.etherscan.io/address/0x4a93d276ea78B48be9D8BB864BACDD5D5A713084) | Proxy: [`TUP@4.9.0`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | + +###### Multichain - Destination + +| Name | Proxy | Implementation | Notes | +| -------- | -------- | -------- | -------- | +| [`OperatorTableUpdater`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.8.0-testnet-final/src/contracts/multichain/destination/OperatorTableUpdater.sol) | [`0xB02A15c6Bd0882b35e9936A9579f35FB26E11476`](https://sepolia.etherscan.io/address/0xB02A15c6Bd0882b35e9936A9579f35FB26E11476) | [`0x0F26...0F5C`](https://sepolia.etherscan.io/address/0x0F264E714a3c03309F4041Db26229EF4E9B00F5C) | Proxy: [`TUP@4.9.0`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| [`ECDSACertificateVerifier`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.8.0-testnet-final/src/contracts/multichain/destination/ECDSACertificateVerifier.sol) | [`0xb3Cd1A457dEa9A9A6F6406c6419B1c326670A96F`](https://sepolia.etherscan.io/address/0xb3Cd1A457dEa9A9A6F6406c6419B1c326670A96F) | [`0xFc86...7B26`](https://sepolia.etherscan.io/address/0xFc868562d93c4DC192419e970C220279cdAb7B26) | Proxy: [`TUP@4.9.0`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| [`BN254CertificateVerifier`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.8.0-testnet-final/src/contracts/multichain/destination/BN254CertificateVerifier.sol) | [`0xff58A373c18268F483C1F5cA03Cf885c0C43373a`](https://sepolia.etherscan.io/address/0xff58A373c18268F483C1F5cA03Cf885c0C43373a) | [`0x7a2b...8f5d`](https://sepolia.etherscan.io/address/0x7a2b8c559a8C8c71A9d364Ad250Fce5A24b18f5d) | Proxy: [`TUP@4.9.0`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | + +###### Multisigs + +| Name | Proxy | Implementation | Notes | +| -------- | -------- | -------- | -------- | +| [`PauserRegistry`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.3.0/src/contracts/permissions/PauserRegistry.sol) | - | [`0x63AA...20f3`](https://sepolia.etherscan.io/address/0x63AAe451780090f50Ad323aAEF155F63a29D20f3) | | +| [`OZ: TimelockController`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v4.7/contracts/governance/TimelockController.sol) | - | [`0x1BEF...1b5B`](https://sepolia.etherscan.io/address/0x1BEF05C7303d44e0E2FCD2A19d993eDEd4c51b5B) | | +| [`OZ: Proxy Admin`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.7.1/contracts/proxy/transparent/ProxyAdmin.sol) | - | [`0x56E8...6Fa1`](https://sepolia.etherscan.io/address/0x56E88cb4f0136fC27D95499dE4BE2acf47946Fa1) | | +| [`Pauser Multisig`](https://github.com/safe-global/safe-contracts/blob/v1.3.0/contracts/GnosisSafe.sol) | [`0x0B415f75980D863872C3eb8caa76E6eC8Bc81536`](https://sepolia.etherscan.io/address/0x0B415f75980D863872C3eb8caa76E6eC8Bc81536) | [`0x4167...461a`](https://sepolia.etherscan.io/address/0xd9db270c1b5e3bd161e8c8503c55ceabee709552) | Proxy: [`Gnosis@1.3.0`](https://github.com/safe-global/safe-contracts/blob/v1.3.0/contracts/proxies/GnosisSafeProxy.sol) | +| [`Community Multisig`](https://github.com/safe-global/safe-contracts/blob/v1.3.0/contracts/GnosisSafe.sol) | [`0x6f8459810197cc9fE123BBeB918451757a4fBAc6`](https://sepolia.etherscan.io/address/0x6f8459810197cc9fE123BBeB918451757a4fBAc6) | [`0x4167...461a`](https://sepolia.etherscan.io/address/0xd9db270c1b5e3bd161e8c8503c55ceabee709552) | Proxy: [`Gnosis@1.3.0`](https://github.com/safe-global/safe-contracts/blob/v1.3.0/contracts/proxies/GnosisSafeProxy.sol) | +| [`Executor Multisig`](https://github.com/safe-global/safe-contracts/blob/v1.3.0/contracts/GnosisSafe.sol) | [`0x4FDA8998EC3b7d4b4A612d45FeB8fB36734470f2`](https://sepolia.etherscan.io/address/0x4FDA8998EC3b7d4b4A612d45FeB8fB36734470f2) | [`0x4167...461a`](https://sepolia.etherscan.io/address/0xd9db270c1b5e3bd161e8c8503c55ceabee709552) | Proxy: [`Gnosis@1.3.0`](https://github.com/safe-global/safe-contracts/blob/v1.3.0/contracts/proxies/GnosisSafeProxy.sol) | +| [`Operations Multisig`](https://github.com/safe-global/safe-contracts/blob/v1.3.0/contracts/GnosisSafe.sol) | [`0xb094Ba769b4976Dc37fC689A76675f31bc4923b0`](https://sepolia.etherscan.io/address/0xb094Ba769b4976Dc37fC689A76675f31bc4923b0) | [`0x4167...461a`](https://sepolia.etherscan.io/address/0x41675C099F32341bf84BFc5382aF534df5C7461a) | Proxy: [`Gnosis@1.3.0`](https://github.com/safe-global/safe-contracts/blob/v1.3.0/contracts/proxies/GnosisSafeProxy.sol) | + +
+ + + +
+ Testnet Hoodi + + +You can view the deployed contract addresses below, or check out the code itself on the [`testnet-hoodi`](https://github.com/Layr-Labs/eigenlayer-contracts/tree/testnet-hoodi) branch. + +###### Core + +| Name | Proxy | Implementation | Notes | +| -------- | -------- | -------- | -------- | +| [`DelegationManager`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.5.0/src/contracts/core/DelegationManager.sol) | [`0x867837a9722C512e0862d8c2E15b8bE220E8b87d`](https://hoodi.etherscan.io/address/0x867837a9722C512e0862d8c2E15b8bE220E8b87d) | [`0x6FE5...1407`](https://hoodi.etherscan.io/address/0x6FE5eBE3ED0F4b2419263868efb5CC640e541407) | Proxy: [`TUP@4.9.0`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| [`StrategyManager`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.5.0/src/contracts/core/StrategyManager.sol) | [`0xeE45e76ddbEDdA2918b8C7E3035cd37Eab3b5D41`](https://hoodi.etherscan.io/address/0xeE45e76ddbEDdA2918b8C7E3035cd37Eab3b5D41) | [`0x1B76...0f62`](https://hoodi.etherscan.io/address/0x1B76a41b1128a5Cd92dAE7C4c0DEC0bfe12B0f62) | Proxy: [`TUP@4.9.0`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| [`EigenPodManager`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.5.0/src/contracts/pods/EigenPodManager.sol) | [`0xcd1442415Fc5C29Aa848A49d2e232720BE07976c`](https://hoodi.etherscan.io/address/0xcd1442415Fc5C29Aa848A49d2e232720BE07976c) | [`0x0F26...0F5C`](https://hoodi.etherscan.io/address/0x0F264E714a3c03309F4041Db26229EF4E9B00F5C) | Proxy: [`TUP@4.9.0`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| [`AVSDirectory`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.3.0/src/contracts/core/AVSDirectory.sol) | [`0xD58f6844f79eB1fbd9f7091d05f7cb30d3363926`](https://hoodi.etherscan.io/address/0xD58f6844f79eB1fbd9f7091d05f7cb30d3363926) | [`0xE368...13Eb`](https://hoodi.etherscan.io/address/0xE368218aDDc4d2dDC5b0AFd70f5878DD8c1713Eb) | Proxy: [`TUP@4.9.0`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| [`RewardsCoordinator`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.3.0/src/contracts/core/RewardsCoordinator.sol) | [`0x29e8572678e0c272350aa0b4B8f304E47EBcd5e7`](https://hoodi.etherscan.io/address/0x29e8572678e0c272350aa0b4B8f304E47EBcd5e7) | [`0x35a8...0525`](https://hoodi.etherscan.io/address/0x35a8198E98cB76f1DD81D977fBd2a8F2a62C0525) | Proxy: [`TUP@4.9.0`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| [`AllocationManager`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.5.0/src/contracts/core/AllocationManager.sol) | [`0x95a7431400F362F3647a69535C5666cA0133CAA0`](https://hoodi.etherscan.io/address/0x95a7431400F362F3647a69535C5666cA0133CAA0) | [`0xe1b7...fFB9`](https://hoodi.etherscan.io/address/0xe1b7A1249C71b538CC183B0080FfC3eFD02BFfB9) | Proxy: [`TUP@4.9.0`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| [`PermissionController`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.3.0/src/contracts/permissions/PermissionController.sol) | [`0xdcCF401fD121d8C542E96BC1d0078884422aFAD2`](https://hoodi.etherscan.io/address/0xdcCF401fD121d8C542E96BC1d0078884422aFAD2) | [`0x151e...75D4`](https://hoodi.etherscan.io/address/0x151eCe1662E530f4889F016a63FC58F4b72175D4) | Proxy: [`TUP@4.9.0`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | + + +###### Strategies + +Anyone can deploy and whitelist strategies for standard ERC20s by using the `StrategyFactory` deployed to the address below (see [docs](./docs/core/StrategyManager.md#strategyfactorydeploynewstrategy)). Strategies deployed from the `StrategyFactory` are deployed using the beacon proxy pattern: + +| Name | Proxy | Implementation | Notes | +| -------- | -------- | -------- | -------- | +| [`StrategyFactory`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.4.1/src/contracts/strategies/StrategyFactory.sol) | [`0xfB7d94501E4d4ACC264833Ef4ede70a11517422B`](https://hoodi.etherscan.io/address/0xfB7d94501E4d4ACC264833Ef4ede70a11517422B) | [`0x0d82...A3f3`](https://hoodi.etherscan.io/address/0x0d824D128eb5bBF5a0dEDD7D58332a00de57A3f3) | Proxy: [`TUP@4.9.0`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| [`StrategyBase`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.5.0/src/contracts/strategies/StrategyBase.sol) | [`0x6d28cEC1659BC3a9BC814c3EFc1412878B406579`](https://hoodi.etherscan.io/address/0x6d28cEC1659BC3a9BC814c3EFc1412878B406579) | [`0xa621...063A`](https://hoodi.etherscan.io/address/0xa621Ebb0Df923e87e9C527C9fC55b9C6F6E0063A) | - Beacon: [`BeaconProxy`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.7.0/contracts/proxy/beacon/BeaconProxy.sol)
- Strategies: [`UpgradeableBeacon`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.4.1/contracts/proxy/beacon/UpgradeableBeacon.sol) | +| [`StETH Strategy`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.5.0/src/contracts/strategies/StrategyBase.sol) | [`0xf8a1a66130d614c7360e868576d5e59203475fe0`](https://hoodi.etherscan.io/address/0xf8a1a66130d614c7360e868576d5e59203475fe0) | [`0xa621...063A`](https://hoodi.etherscan.io/address/0xa621Ebb0Df923e87e9C527C9fC55b9C6F6E0063A) | Strategy Factory deployed | +| [`WETH Strategy`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.5.0/src/contracts/strategies/StrategyBase.sol) | [`0x24579aD4fe83aC53546E5c2D3dF5F85D6383420d`](https://hoodi.etherscan.io/address/0x24579aD4fe83aC53546E5c2D3dF5F85D6383420d) | [`0xa621...063A`](https://hoodi.etherscan.io/address/0xa621Ebb0Df923e87e9C527C9fC55b9C6F6E0063A) | Strategy Factory deployed | + +###### Strategies - Special + +The following strategies differ significantly from the other strategies deployed/used above: + +| Name | Proxy | Implementation | Notes | +| -------- | -------- | -------- | -------- | +| [`EigenStrategy (EIGEN)`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.5.0/src/contracts/strategies/EigenStrategy.sol) | [`0xB27b10291DBFE6576d17afF3e251c954Ae14f1D3`](https://hoodi.etherscan.io/address/0xB27b10291DBFE6576d17afF3e251c954Ae14f1D3) | [`0xd318...caE8`](https://hoodi.etherscan.io/address/0xd318ECAcaf8998FB4508FA07159B758253FbcaE8) | Proxy: [`TUP@4.9.0`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| `Beacon Chain ETH` | `0xbeaC0eeEeeeeEEeEeEEEEeeEEeEeeeEeeEEBEaC0` | - | - Used for Beacon Chain ETH shares
- Not a real contract! | + +###### EigenPods + +| Name | Proxy | Implementation | Notes | +| -------- | -------- | -------- | -------- | +| [`EigenPod (beacon)`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.6.0/src/contracts/pods/EigenPod.sol) | [`0x5e1577f8efB21b229cD5Eb4C5Aa3d6C4b228f650`](https://hoodi.etherscan.io/address/0x5e1577f8efB21b229cD5Eb4C5Aa3d6C4b228f650) | [`0x49A8...5AdB`](https://hoodi.etherscan.io/address/0x49A800bfFa5B561daD94Adf4Ea9bfe35bBEB5AdB) | - Beacon: [`BeaconProxy`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.4.1/contracts/proxy/beacon/BeaconProxy.sol)
- Pods: [`UpgradeableBeacon`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.4.1/contracts/proxy/beacon/UpgradeableBeacon.sol) | + +###### EIGEN/bEIGEN + +| Name | Proxy | Implementation | Notes | +| -------- | -------- | -------- | -------- | +| [`Eigen`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.6.0/src/contracts/token/Eigen.sol) | [`0x8ae2520954db7D80D66835cB71E692835bbA45bf`](https://hoodi.etherscan.io/address/0x8ae2520954db7D80D66835cB71E692835bbA45bf) | [`0x68F3...2FE9`](https://hoodi.etherscan.io/address/0x68F3E0B02b15F96B50aC73d7680F020B646D2FE9) | Proxy: [`TUP@4.9.0`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| [`Backing Eigen`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.3.0/src/contracts/token/BackingEigen.sol) | [`0x6e60888132Cc7e637488379B4B40c42b3751f63a`](https://hoodi.etherscan.io/address/0x6e60888132Cc7e637488379B4B40c42b3751f63a) | [`0x43e4...1C4`](https://hoodi.etherscan.io/address/0x43e4940aCeb1C1F5a57e307EEB212007F0f6a1C4) | Proxy: [`TUP@4.9.0`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | + +###### Multisigs + +| Name | Proxy | Implementation | Notes | +| -------- | -------- | -------- | -------- | +| [`PauserRegistry`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.4.1/src/contracts/permissions/PauserRegistry.sol) | - | [`0x64D7...c13D`](https://hoodi.etherscan.io/address/0x64D78399B0fa32EA72959f33edCF313159F3c13D) | | +| [`OZ: TimelockController`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v4.7/contracts/governance/TimelockController.sol) | - | [`0xE332...2d15`](https://hoodi.etherscan.io/address/0xE3328cb5068924119d6170496c4AB2dD12c12d15) | | +| [`OZ: Proxy Admin`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/ProxyAdmin.sol) | - | [`0xE7f4...2257`](https://hoodi.etherscan.io/address/0xE7f4E30D2619273468afe9EC0Acf805E55532257) | | + +
+ + + +
+ Testnet Base Sepolia + + +**Note: Testnet Base Sepolia only supports verification of tasks from stake that lives on Sepolia. Standard core protocol functionality (restaking, slashing) does not exist on Base Sepolia.** + +###### Multichain - Destination + +| Name | Proxy | Implementation | Notes | +| -------- | -------- | -------- | -------- | +| [`OperatorTableUpdater`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.8.0-testnet-final/src/contracts/multichain/destination/OperatorTableUpdater.sol) | [`0xB02A15c6Bd0882b35e9936A9579f35FB26E11476`](https://sepolia.basescan.org/address/0xB02A15c6Bd0882b35e9936A9579f35FB26E11476) | [`0x6514...2D6F`](https://sepolia.basescan.org/address/0x65147e9916152C1EbdBaD8A6f3e145b4BDeE2D6F) | Proxy: [`TUP@4.9.0`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| [`ECDSACertificateVerifier`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.8.0-testnet-final/src/contracts/multichain/destination/ECDSACertificateVerifier.sol) | [`0xb3Cd1A457dEa9A9A6F6406c6419B1c326670A96F`](https://sepolia.basescan.org/address/0xb3Cd1A457dEa9A9A6F6406c6419B1c326670A96F) | [`0xEE41...ca1A`](https://sepolia.basescan.org/address/0xEE41826B7D5B89e7F5eED6a831b4eFD69FC9ca1A) | Proxy: [`TUP@4.9.0`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | +| [`BN254CertificateVerifier`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.8.0-testnet-final/src/contracts/multichain/destination/BN254CertificateVerifier.sol) | [`0xff58A373c18268F483C1F5cA03Cf885c0C43373a`](https://sepolia.basescan.org/address/0xff58A373c18268F483C1F5cA03Cf885c0C43373a) | [`0x59B1...f525`](https://sepolia.basescan.org/address/0x59B11b191B572888703E150E45F5015e0fFcf525) | Proxy: [`TUP@4.9.0`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | + +###### AVS + +The following contracts are used by AVSs. + +| Name | Proxy | Implementation | Notes | +| -------- | -------- | -------- | -------- | +| [`TaskMailbox`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.8.0-testnet-final/src/contracts/avs/task/TaskMailbox.sol) | [`0xB99CC53e8db7018f557606C2a5B066527bF96b26`](https://sepolia.basescan.org/address/0xB99CC53e8db7018f557606C2a5B066527bF96b26) | [`0x46CF...16db`](https://sepolia.basescan.org/address/0x46CFA3C2eaDe97D53739120b87A63F739B9616db) | Proxy: [`TUP@4.9.0`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | + +###### Multisigs + +| Name | Proxy | Implementation | Notes | +| -------- | -------- | -------- | -------- | +| [`PauserRegistry`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v1.7.0-rc.4/src/contracts/permissions/PauserRegistry.sol) | - | [`0x6ffE...672B`](https://sepolia.basescan.org/address/0x6ffE77C321a773e2A27B0B0a31C5e1bBda83672B) | | +| [`OZ: Proxy Admin`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/transparent/ProxyAdmin.sol) | - | [`0xbe2F...0b5`](https://sepolia.basescan.org/address/0xbe2F96Efff467c6773Dc91eA62Ab34C73195a0b5) | | +| [`Pauser Multisig`](https://github.com/safe-global/safe-contracts/blob/v1.3.0/contracts/GnosisSafe.sol) | [`0x2DD9BDDf299C846f61C0105905f9a60ee99242d6`](https://sepolia.basescan.org/address/0x2DD9BDDf299C846f61C0105905f9a60ee99242d6) | - | | +| [`Operations Multisig`](https://github.com/safe-global/safe-contracts/blob/v1.3.0/contracts/GnosisSafe.sol) | [`0x4ACA7e09eF90612941A9185A6690Dbe9e39aae8f`](https://sepolia.basescan.org/address/0x4ACA7e09eF90612941A9185A6690Dbe9e39aae8f) | - | | +| [`Multichain Deployer Multisig`](https://github.com/safe-global/safe-contracts/blob/v1.3.0/contracts/GnosisSafe.sol) | [`0xA591635DE4C254BD3fa9C9Db9000eA6488344C28`](https://sepolia.basescan.org/address/0xA591635DE4C254BD3fa9C9Db9000eA6488344C28) | - | | + +
+ +## Branching + +Branches we use: +* `main`: The canonical, most up-to-date branch, containing the work-in-progress code for upcoming releases +* `Vx.y.z`: Release branch with version `x.y.z` that matches a release of EigenLayer, release branch is always cut from `main` via cherry-picking +* `release-dev/xxx`: A development branch for a large feature to be released, the branch should eventually be deleted after merge to `main` + +## Building Apps & Services on EigenLayer + +### Developer & User Basics + +[Our documentation](https://docs.eigenlayer.xyz/) is a great place to start to understand EigenLayer and the Eigen ecosystem. If you are an audio/visual learner, check out the "[You Could've Invented EigenLayer](https://www.blog.eigenlayer.xyz/ycie/)" video. + +To understand more about how our ecosystem and its participants work, checkout the guides below. These are split out by who you are: AVS developers, restakers and Operators. All have different roles and interactioons with EigenLayer: + +* [AVS Developer Guide](https://docs.eigenlayer.xyz/developers/Concepts/avs-developer-guide) +* [Operator Guide](https://docs.eigenlayer.xyz/operators/concepts/operator-introduction) +* [Restaker Guide](https://docs.eigenlayer.xyz/restakers/concepts/overview) + +### Contract Docs & Deep Dive + +The most up-to-date and technical documentation on our core contracts can be found in [/docs](/docs). If you're a shadowy super coder, this is a great place to get an overview of the contracts before diving into the code. + +To learn more about interfacing with the EigenLayer core contracts onchain, see our [middleware repo.](https://github.com/Layr-Labs/eigenlayer-middleware) + +To get an idea of how users interact with these contracts, check out our integration tests: [/src/test/integration](./src/test/integration/). + +## Contribute to the Core + +See [CONTRIBUTING](CONTRIBUTING.md). + +Contributions that do not follow our fork base PR practices will be either rejected or immediately deleted based on your role, preventing branch pollution, keeping our repository clean, make it more readable and searchable. diff --git a/plan/agw/research/preset-catalog-2026-10-15/StakeHub.sol b/plan/agw/research/preset-catalog-2026-10-15/StakeHub.sol new file mode 100644 index 00000000..f1992c2f --- /dev/null +++ b/plan/agw/research/preset-catalog-2026-10-15/StakeHub.sol @@ -0,0 +1,1306 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity 0.8.17; + +import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; +import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; + +import "./SystemV2.sol"; +import "./extension/Protectable.sol"; +import "./interface/0.8.x/IBSCValidatorSet.sol"; +import "./interface/0.8.x/IGovToken.sol"; +import "./interface/0.8.x/IStakeCredit.sol"; +import "./lib/0.8.x/Utils.sol"; + +contract StakeHub is SystemV2, Initializable, Protectable { + using Utils for string; + using Utils for bytes; + using EnumerableSet for EnumerableSet.AddressSet; + + /*----------------- constants -----------------*/ + uint256 private constant BLS_PUBKEY_LENGTH = 48; + uint256 private constant BLS_SIG_LENGTH = 96; + + address public constant DEAD_ADDRESS = address(0xdEaD); + uint256 public constant LOCK_AMOUNT = 1 ether; + uint256 public constant REDELEGATE_FEE_RATE_BASE = 100000; // 100% + + uint256 public constant BREATHE_BLOCK_INTERVAL = 1 days; + + uint256 public constant INIT_MAX_NUMBER_NODE_ID = 5; + + // receive fund status + uint8 private constant _DISABLE = 0; + uint8 private constant _ENABLE = 1; + + /*----------------- errors -----------------*/ + // @notice signature: 0x5f28f62b + error ValidatorExisted(); + // @notice signature: 0x056e8811 + error ValidatorNotExisted(); + // @notice signature: 0x4b6b857d + error ValidatorNotJailed(); + // @notice signature: 0x3cdeb0ea + error DuplicateConsensusAddress(); + // @notice signature: 0x11fdb947 + error DuplicateVoteAddress(); + // @notice signature: 0xc0bf4143 + error DuplicateMoniker(); + // @notice signature: 0x2f64097e + error SelfDelegationNotEnough(); + // @notice signature: 0xdc81db85 + error InvalidCommission(); + // @notice signature: 0x5dba5ad7 + error InvalidMoniker(); + // @notice signature: 0x2c8fc796 + error InvalidVoteAddress(); + // @notice signature: 0xca40c236 + error InvalidConsensusAddress(); + // @notice signature: 0x3f259b7a + error UpdateTooFrequently(); + // @notice signature: 0x5c32dd9c + error JailTimeNotExpired(); + // @notice signature: 0xdc6f0bdd + error DelegationAmountTooSmall(); + // @notice signature: 0x64689203 + error OnlySelfDelegation(); + // @notice signature: 0x9811e0c7 + error ZeroShares(); + // @notice signature: 0xf0e3e629 + error SameValidator(); + // @notice signature: 0xbd52fcdb + error NoMoreFelonyAllowed(); + // @notice signature: 0x37233762 + error AlreadySlashed(); + // @notice signature: 0x90b8ec18 + error TransferFailed(); + // @notice signature: 0x41abc801 + error InvalidRequest(); + // @notice signature: 0x1898eb6b + error VoteAddressExpired(); + // @notice signature: 0xc2aee074 + error ConsensusAddressExpired(); + // @notice signature: 0x0d7b78d4 + error InvalidSynPackage(); + // @notice signature: 0xbebdc757 + error InvalidAgent(); + // @notice signature: 0x682a6e7c + error InvalidValidator(); + // @notice signature: 0x6490ffd3 + error InvalidNodeID(); + // @notice signature: 0x246be614 + error ExceedsMaxNodeIDs(); + // @notice signature: 0x440bc78e + error DuplicateNodeID(); + + /*----------------- storage -----------------*/ + uint8 private _receiveFundStatus; + uint256 public transferGasLimit; + + // stake params + uint256 public minSelfDelegationBNB; + uint256 public minDelegationBNBChange; + uint256 public maxElectedValidators; + uint256 public unbondPeriod; + uint256 public redelegateFeeRate; + + // slash params + uint256 public downtimeSlashAmount; + uint256 public felonySlashAmount; + uint256 public downtimeJailTime; + uint256 public felonyJailTime; + + // validator operator address set + EnumerableSet.AddressSet private _validatorSet; + // validator operator address => validator info + mapping(address => Validator) private _validators; + // validator moniker set(hash of the moniker) + mapping(bytes32 => bool) private _monikerSet; + // validator consensus address => validator operator address + mapping(address => address) public consensusToOperator; + // validator consensus address => expiry date + mapping(address => uint256) public consensusExpiration; + // validator vote address => validator operator address + mapping(bytes => address) public voteToOperator; + // validator vote address => expiry date + mapping(bytes => uint256) public voteExpiration; + + // legacy addresses of BC + mapping(address => bool) private _legacyConsensusAddress; // @dev deprecated + mapping(bytes => bool) private _legacyVoteAddress; // @dev deprecated + + // total number of current jailed validators + uint256 public numOfJailed; + // max number of jailed validators between breathe block(only for malicious vote and double sign) + uint256 public maxFelonyBetweenBreatheBlock; + // index(timestamp / breatheBlockInterval) => number of malicious vote and double sign slash + mapping(uint256 => uint256) private _felonyMap; + // slash key => slash jail time + mapping(bytes32 => uint256) private _felonyRecords; + + // agent => validator operator address + mapping(address => address) public agentToOperator; + + // network related values // + + // governance controlled maximum number of NodeIDs per validator (default is 5). + uint256 public maxNodeIDs; + + // mapping from a validator's operator address to an array of their registered NodeIDs, + // where each NodeID is stored as a fixed 32-byte value. + mapping(address => bytes32[]) private validatorNodeIDs; + + /*----------------- structs and events -----------------*/ + struct StakeMigrationPackage { + address operatorAddress; // the operator address of the target validator to delegate to + address delegator; // the beneficiary of the delegation + address refundAddress; // the Beacon Chain address to refund the fund if migration failed + uint256 amount; // the amount of BNB to be migrated(decimal: 18) + } + + enum StakeMigrationRespCode { + MIGRATE_SUCCESS, + CLAIM_FUND_FAILED, + VALIDATOR_NOT_EXISTED, + VALIDATOR_JAILED, + INVALID_DELEGATOR + } + + struct Validator { + address consensusAddress; + address operatorAddress; + address creditContract; + uint256 createdTime; + bytes voteAddress; + Description description; + Commission commission; + bool jailed; + uint256 jailUntil; + uint256 updateTime; + // The agent can perform transactions on behalf of the operatorAddress in certain scenarios. + address agent; + uint256[19] __reservedSlots; + } + + struct Description { + string moniker; + string identity; + string website; + string details; + } + + struct Commission { + uint64 rate; // the commission rate charged to delegators(10000 is 100%) + uint64 maxRate; // maximum commission rate which validator can ever charge + uint64 maxChangeRate; // maximum daily increase of the validator commission + } + + enum SlashType { + DoubleSign, + DownTime, + MaliciousVote + } + + event ValidatorCreated( + address indexed consensusAddress, + address indexed operatorAddress, + address indexed creditContract, + bytes voteAddress + ); + event StakeCreditInitialized(address indexed operatorAddress, address indexed creditContract); + event ConsensusAddressEdited(address indexed operatorAddress, address indexed newConsensusAddress); + event CommissionRateEdited(address indexed operatorAddress, uint64 newCommissionRate); + event DescriptionEdited(address indexed operatorAddress); + event VoteAddressEdited(address indexed operatorAddress, bytes newVoteAddress); + event Delegated(address indexed operatorAddress, address indexed delegator, uint256 shares, uint256 bnbAmount); + event Undelegated(address indexed operatorAddress, address indexed delegator, uint256 shares, uint256 bnbAmount); + event Redelegated( + address indexed srcValidator, + address indexed dstValidator, + address indexed delegator, + uint256 oldShares, + uint256 newShares, + uint256 bnbAmount + ); + event RewardDistributed(address indexed operatorAddress, uint256 reward); + event RewardDistributeFailed(address indexed operatorAddress, bytes failReason); + event ValidatorSlashed( + address indexed operatorAddress, uint256 jailUntil, uint256 slashAmount, SlashType slashType + ); + event ValidatorJailed(address indexed operatorAddress); + event ValidatorEmptyJailed(address indexed operatorAddress); + event ValidatorUnjailed(address indexed operatorAddress); + event Claimed(address indexed operatorAddress, address indexed delegator, uint256 bnbAmount); + event AgentChanged(address indexed operatorAddress, address indexed oldAgent, address indexed newAgent); + + // Events for adding and removing NodeIDs. + event NodeIDAdded(address indexed validator, bytes32 nodeID); + event NodeIDRemoved(address indexed validator, bytes32 nodeID); + + event MigrateSuccess(address indexed operatorAddress, address indexed delegator, uint256 shares, uint256 bnbAmount); // @dev deprecated + event MigrateFailed( + address indexed operatorAddress, address indexed delegator, uint256 bnbAmount, StakeMigrationRespCode respCode + ); // @dev deprecated + event UnexpectedPackage(uint8 channelId, bytes msgBytes); // @dev deprecated + + /*----------------- modifiers -----------------*/ + modifier validatorExist( + address operatorAddress + ) { + if (!_validatorSet.contains(operatorAddress)) revert ValidatorNotExisted(); + _; + } + + modifier enableReceivingFund() { + _receiveFundStatus = _ENABLE; + _; + _receiveFundStatus = _DISABLE; + } + + receive() external payable { + // to prevent BNB from being lost + if (_receiveFundStatus != _ENABLE) revert(); + } + + /** + * @dev this function is invoked by BSC Parlia consensus engine during the hard fork + */ + function initialize() external initializer onlyCoinbase onlyZeroGasPrice { + transferGasLimit = 5000; + minSelfDelegationBNB = 2_000 ether; + minDelegationBNBChange = 1 ether; + maxElectedValidators = 45; + unbondPeriod = 7 days; + redelegateFeeRate = 2; + downtimeSlashAmount = 10 ether; + felonySlashAmount = 200 ether; + downtimeJailTime = 2 days; + felonyJailTime = 30 days; + maxFelonyBetweenBreatheBlock = 2; + // Different address will be set depending on the environment + __Protectable_init_unchained(0x08E68Ec70FA3b629784fDB28887e206ce8561E08); + } + + /*----------------- Implement cross chain app -----------------*/ + function handleSynPackage( + uint8, + bytes calldata msgBytes + ) external onlyCrossChainContract whenNotPaused enableReceivingFund returns (bytes memory) { + revert("deprecated"); + } + + function handleAckPackage(uint8 channelId, bytes calldata msgBytes) external onlyCrossChainContract { + revert("deprecated"); + } + + function handleFailAckPackage(uint8 channelId, bytes calldata msgBytes) external onlyCrossChainContract { + revert("deprecated"); + } + + /*----------------- external functions -----------------*/ + /** + * @param newAgent the new agent address of the validator, updating to address(0) means remove the old agent. + */ + function updateAgent( + address newAgent + ) external validatorExist(msg.sender) whenNotPaused notInBlackList { + if (agentToOperator[newAgent] != address(0)) revert InvalidAgent(); + if (_validatorSet.contains(newAgent)) revert InvalidAgent(); + + address operatorAddress = msg.sender; + address oldAgent = _validators[operatorAddress].agent; + if (oldAgent == newAgent) revert InvalidAgent(); + + if (oldAgent != address(0)) { + delete agentToOperator[oldAgent]; + } + + _validators[operatorAddress].agent = newAgent; + + if (newAgent != address(0)) { + agentToOperator[newAgent] = operatorAddress; + } + + emit AgentChanged(operatorAddress, oldAgent, newAgent); + } + + /** + * @param consensusAddress the consensus address of the validator + * @param voteAddress the vote address of the validator + * @param blsProof the bls proof of the vote address + * @param commission the commission of the validator + * @param description the description of the validator + */ + function createValidator( + address consensusAddress, + bytes calldata voteAddress, + bytes calldata blsProof, + Commission calldata commission, + Description calldata description + ) external payable whenNotPaused notInBlackList { + // basic check + address operatorAddress = msg.sender; + if (_validatorSet.contains(operatorAddress)) revert ValidatorExisted(); + if (agentToOperator[operatorAddress] != address(0)) revert InvalidValidator(); + + if (consensusToOperator[consensusAddress] != address(0)) { + revert DuplicateConsensusAddress(); + } + if (voteToOperator[voteAddress] != address(0)) { + revert DuplicateVoteAddress(); + } + bytes32 monikerHash = keccak256(abi.encodePacked(description.moniker)); + if (_monikerSet[monikerHash]) revert DuplicateMoniker(); + + uint256 delegation = msg.value - LOCK_AMOUNT; // create validator need to lock 1 BNB + if (delegation < minSelfDelegationBNB) revert SelfDelegationNotEnough(); + + if (consensusAddress == address(0)) revert InvalidConsensusAddress(); + if ( + commission.maxRate > 5_000 || commission.rate > commission.maxRate + || commission.maxChangeRate > commission.maxRate + ) revert InvalidCommission(); + if (!_checkMoniker(description.moniker)) revert InvalidMoniker(); + // proof-of-possession verify + if (!_checkVoteAddress(operatorAddress, voteAddress, blsProof)) revert InvalidVoteAddress(); + + // deploy stake credit proxy contract + address creditContract = _deployStakeCredit(operatorAddress, description.moniker); + + _validatorSet.add(operatorAddress); + _monikerSet[monikerHash] = true; + Validator storage valInfo = _validators[operatorAddress]; + valInfo.consensusAddress = consensusAddress; + valInfo.operatorAddress = operatorAddress; + valInfo.creditContract = creditContract; + valInfo.createdTime = block.timestamp; + valInfo.voteAddress = voteAddress; + valInfo.description = description; + valInfo.commission = commission; + valInfo.updateTime = block.timestamp; + consensusToOperator[consensusAddress] = operatorAddress; + voteToOperator[voteAddress] = operatorAddress; + + emit ValidatorCreated(consensusAddress, operatorAddress, creditContract, voteAddress); + emit Delegated(operatorAddress, operatorAddress, delegation, delegation); + emit Delegated(operatorAddress, DEAD_ADDRESS, LOCK_AMOUNT, LOCK_AMOUNT); + + IGovToken(GOV_TOKEN_ADDR).sync(creditContract, operatorAddress); + } + + /** + * @param newConsensusAddress the new consensus address of the validator + */ + function editConsensusAddress( + address newConsensusAddress + ) external whenNotPaused notInBlackList validatorExist(_bep410MsgSender()) { + if (newConsensusAddress == address(0)) revert InvalidConsensusAddress(); + if (consensusToOperator[newConsensusAddress] != address(0)) { + revert DuplicateConsensusAddress(); + } + + address operatorAddress = _bep410MsgSender(); + Validator storage valInfo = _validators[operatorAddress]; + if (valInfo.updateTime + BREATHE_BLOCK_INTERVAL > block.timestamp) revert UpdateTooFrequently(); + + consensusExpiration[valInfo.consensusAddress] = block.timestamp; + valInfo.consensusAddress = newConsensusAddress; + valInfo.updateTime = block.timestamp; + consensusToOperator[newConsensusAddress] = operatorAddress; + + emit ConsensusAddressEdited(operatorAddress, newConsensusAddress); + } + + /** + * @param commissionRate the new commission rate of the validator + */ + function editCommissionRate( + uint64 commissionRate + ) external whenNotPaused notInBlackList validatorExist(_bep410MsgSender()) { + address operatorAddress = _bep410MsgSender(); + Validator storage valInfo = _validators[operatorAddress]; + if (valInfo.updateTime + BREATHE_BLOCK_INTERVAL > block.timestamp) revert UpdateTooFrequently(); + + if (commissionRate > valInfo.commission.maxRate) revert InvalidCommission(); + uint256 changeRate = commissionRate >= valInfo.commission.rate + ? commissionRate - valInfo.commission.rate + : valInfo.commission.rate - commissionRate; + if (changeRate > valInfo.commission.maxChangeRate) revert InvalidCommission(); + + valInfo.commission.rate = commissionRate; + valInfo.updateTime = block.timestamp; + + emit CommissionRateEdited(operatorAddress, commissionRate); + } + + /** + * @notice the moniker of the validator will be ignored as it is not editable + * @param description the new description of the validator + */ + function editDescription( + Description memory description + ) external whenNotPaused notInBlackList validatorExist(_bep410MsgSender()) { + address operatorAddress = _bep410MsgSender(); + Validator storage valInfo = _validators[operatorAddress]; + if (valInfo.updateTime + BREATHE_BLOCK_INTERVAL > block.timestamp) revert UpdateTooFrequently(); + + description.moniker = valInfo.description.moniker; + valInfo.description = description; + valInfo.updateTime = block.timestamp; + + emit DescriptionEdited(operatorAddress); + } + + /** + * @param newVoteAddress the new vote address of the validator + * @param blsProof the bls proof of the vote address + */ + function editVoteAddress( + bytes calldata newVoteAddress, + bytes calldata blsProof + ) external whenNotPaused notInBlackList validatorExist(_bep410MsgSender()) { + // proof-of-possession verify + address operatorAddress = _bep410MsgSender(); + if (!_checkVoteAddress(operatorAddress, newVoteAddress, blsProof)) revert InvalidVoteAddress(); + if (voteToOperator[newVoteAddress] != address(0)) { + revert DuplicateVoteAddress(); + } + + Validator storage valInfo = _validators[operatorAddress]; + if (valInfo.updateTime + BREATHE_BLOCK_INTERVAL > block.timestamp) revert UpdateTooFrequently(); + + voteExpiration[valInfo.voteAddress] = block.timestamp; + valInfo.voteAddress = newVoteAddress; + valInfo.updateTime = block.timestamp; + voteToOperator[newVoteAddress] = operatorAddress; + + emit VoteAddressEdited(operatorAddress, newVoteAddress); + } + + /** + * @param operatorAddress the operator address of the validator to be unjailed + */ + function unjail( + address operatorAddress + ) external whenNotPaused notInBlackList validatorExist(operatorAddress) { + Validator storage valInfo = _validators[operatorAddress]; + if (!valInfo.jailed) revert ValidatorNotJailed(); + + if (IStakeCredit(valInfo.creditContract).getPooledBNB(operatorAddress) < minSelfDelegationBNB) { + revert SelfDelegationNotEnough(); + } + if (valInfo.jailUntil > block.timestamp) revert JailTimeNotExpired(); + + valInfo.jailed = false; + numOfJailed -= 1; + emit ValidatorUnjailed(operatorAddress); + } + + /** + * @param operatorAddress the operator address of the validator to be delegated to + * @param delegateVotePower whether to delegate vote power to the validator + */ + function delegate( + address operatorAddress, + bool delegateVotePower + ) external payable whenNotPaused notInBlackList validatorExist(operatorAddress) { + uint256 bnbAmount = msg.value; + if (bnbAmount < minDelegationBNBChange) revert DelegationAmountTooSmall(); + + address delegator = msg.sender; + Validator memory valInfo = _validators[operatorAddress]; + if (valInfo.jailed && delegator != operatorAddress) revert OnlySelfDelegation(); + + uint256 shares = IStakeCredit(valInfo.creditContract).delegate{ value: bnbAmount }(delegator); + emit Delegated(operatorAddress, delegator, shares, bnbAmount); + + IGovToken(GOV_TOKEN_ADDR).sync(valInfo.creditContract, delegator); + if (delegateVotePower) { + IGovToken(GOV_TOKEN_ADDR).delegateVote(delegator, operatorAddress); + } + } + + /** + * @dev Undelegate BNB from a validator, fund is only claimable few days later + * @param operatorAddress the operator address of the validator to be undelegated from + * @param shares the shares to be undelegated + */ + function undelegate( + address operatorAddress, + uint256 shares + ) external whenNotPaused notInBlackList validatorExist(operatorAddress) { + if (shares == 0) revert ZeroShares(); + + address delegator = msg.sender; + Validator memory valInfo = _validators[operatorAddress]; + + uint256 bnbAmount = IStakeCredit(valInfo.creditContract).undelegate(delegator, shares); + emit Undelegated(operatorAddress, delegator, shares, bnbAmount); + + if (delegator == operatorAddress) { + _checkValidatorSelfDelegation(operatorAddress); + } + + IGovToken(GOV_TOKEN_ADDR).sync(valInfo.creditContract, delegator); + } + + /** + * @param srcValidator the operator address of the validator to be redelegated from + * @param dstValidator the operator address of the validator to be redelegated to + * @param shares the shares to be redelegated + * @param delegateVotePower whether to delegate vote power to the dstValidator + */ + function redelegate( + address srcValidator, + address dstValidator, + uint256 shares, + bool delegateVotePower + ) + external + whenNotPaused + notInBlackList + validatorExist(srcValidator) + validatorExist(dstValidator) + enableReceivingFund + { + if (shares == 0) revert ZeroShares(); + if (srcValidator == dstValidator) revert SameValidator(); + + address delegator = msg.sender; + Validator memory srcValInfo = _validators[srcValidator]; + Validator memory dstValInfo = _validators[dstValidator]; + if (dstValInfo.jailed && delegator != dstValidator) revert OnlySelfDelegation(); + + uint256 bnbAmount = IStakeCredit(srcValInfo.creditContract).unbond(delegator, shares); + if (bnbAmount < minDelegationBNBChange) revert DelegationAmountTooSmall(); + // check if the srcValidator has enough self delegation + if ( + delegator == srcValidator + && IStakeCredit(srcValInfo.creditContract).getPooledBNB(srcValidator) < minSelfDelegationBNB + ) { + revert SelfDelegationNotEnough(); + } + + uint256 feeCharge = bnbAmount * redelegateFeeRate / REDELEGATE_FEE_RATE_BASE; + (bool success,) = dstValInfo.creditContract.call{ value: feeCharge }(""); + if (!success) revert TransferFailed(); + + bnbAmount -= feeCharge; + uint256 newShares = IStakeCredit(dstValInfo.creditContract).delegate{ value: bnbAmount }(delegator); + emit Redelegated(srcValidator, dstValidator, delegator, shares, newShares, bnbAmount); + + address[] memory stakeCredits = new address[](2); + stakeCredits[0] = srcValInfo.creditContract; + stakeCredits[1] = dstValInfo.creditContract; + IGovToken(GOV_TOKEN_ADDR).syncBatch(stakeCredits, delegator); + if (delegateVotePower) { + IGovToken(GOV_TOKEN_ADDR).delegateVote(delegator, dstValidator); + } + } + + /** + * @dev Claim the undelegated BNB from the pool after unbondPeriod + * @param operatorAddress the operator address of the validator + * @param requestNumber the request number of the undelegation. 0 means claim all + */ + function claim(address operatorAddress, uint256 requestNumber) external whenNotPaused notInBlackList { + _claim(operatorAddress, requestNumber); + } + + /** + * @dev Claim the undelegated BNB from the pools after unbondPeriod + * @param operatorAddresses the operator addresses of the validator + * @param requestNumbers numbers of the undelegation requests. 0 means claim all + */ + function claimBatch( + address[] calldata operatorAddresses, + uint256[] calldata requestNumbers + ) external whenNotPaused notInBlackList { + if (operatorAddresses.length != requestNumbers.length) revert InvalidRequest(); + for (uint256 i; i < operatorAddresses.length; ++i) { + _claim(operatorAddresses[i], requestNumbers[i]); + } + } + + /** + * @dev Sync the gov tokens of validators in operatorAddresses + * @param operatorAddresses the operator addresses of the validators + * @param account the account to sync gov tokens to + */ + function syncGovToken( + address[] calldata operatorAddresses, + address account + ) external whenNotPaused notInBlackList { + uint256 _length = operatorAddresses.length; + address[] memory stakeCredits = new address[](_length); + address credit; + for (uint256 i = 0; i < _length; ++i) { + if (!_validatorSet.contains(operatorAddresses[i])) revert ValidatorNotExisted(); + credit = _validators[operatorAddresses[i]].creditContract; + stakeCredits[i] = credit; + } + + IGovToken(GOV_TOKEN_ADDR).syncBatch(stakeCredits, account); + } + + /*----------------- system functions -----------------*/ + /** + * @dev This function will be called by consensus engine. So it should never revert. + */ + function distributeReward( + address consensusAddress + ) external payable onlyValidatorContract { + address operatorAddress = consensusToOperator[consensusAddress]; + Validator memory valInfo = _validators[operatorAddress]; + if (valInfo.creditContract == address(0) || valInfo.jailed) { + SYSTEM_REWARD_ADDR.call{ value: msg.value }(""); + emit RewardDistributeFailed(operatorAddress, "INVALID_VALIDATOR"); + return; + } + + IStakeCredit(valInfo.creditContract).distributeReward{ value: msg.value }(valInfo.commission.rate); + emit RewardDistributed(operatorAddress, msg.value); + + IGovToken(GOV_TOKEN_ADDR).sync(valInfo.creditContract, operatorAddress); + } + + /** + * @dev Downtime slash. Only the `SlashIndicator` contract can call this function. + */ + function downtimeSlash( + address consensusAddress + ) external onlySlash { + address operatorAddress = consensusToOperator[consensusAddress]; + if (!_validatorSet.contains(operatorAddress)) revert ValidatorNotExisted(); // should never happen + Validator storage valInfo = _validators[operatorAddress]; + + // slash + uint256 slashAmount = IStakeCredit(valInfo.creditContract).slash(downtimeSlashAmount); + uint256 jailUntil = block.timestamp + downtimeJailTime; + _jailValidator(valInfo, jailUntil); + + emit ValidatorSlashed(operatorAddress, jailUntil, slashAmount, SlashType.DownTime); + + IGovToken(GOV_TOKEN_ADDR).sync(valInfo.creditContract, operatorAddress); + } + + /** + * @dev Malicious vote slash. Only the `SlashIndicator` contract can call this function. + */ + function maliciousVoteSlash( + bytes calldata voteAddress + ) external onlySlash whenNotPaused { + address operatorAddress = voteToOperator[voteAddress]; + if (!_validatorSet.contains(operatorAddress)) revert ValidatorNotExisted(); // should never happen + Validator storage valInfo = _validators[operatorAddress]; + + uint256 index = block.timestamp / BREATHE_BLOCK_INTERVAL; + // This is to prevent many honest validators being slashed at the same time because of implementation bugs + if (_felonyMap[index] >= maxFelonyBetweenBreatheBlock) revert NoMoreFelonyAllowed(); + _felonyMap[index] += 1; + + // check if the voteAddress has already expired + if (voteExpiration[voteAddress] != 0 && voteExpiration[voteAddress] + BREATHE_BLOCK_INTERVAL < block.timestamp) + { + revert VoteAddressExpired(); + } + + // slash + (bool canSlash, uint256 jailUntil) = _checkFelonyRecord(operatorAddress, SlashType.MaliciousVote); + if (!canSlash) revert AlreadySlashed(); + uint256 slashAmount = IStakeCredit(valInfo.creditContract).slash(felonySlashAmount); + _jailValidator(valInfo, jailUntil); + // Evict using the post-rotation consensus key; SlashIndicator's voteAddr-based + // eviction covers the case where BSCValidatorSet has not yet synced K_new. + IBSCValidatorSet(VALIDATOR_CONTRACT_ADDR).felony(valInfo.consensusAddress); + + emit ValidatorSlashed(operatorAddress, jailUntil, slashAmount, SlashType.MaliciousVote); + + IGovToken(GOV_TOKEN_ADDR).sync(valInfo.creditContract, operatorAddress); + } + + /** + * @dev Double sign slash. Only the `SlashIndicator` contract can call this function. + */ + function doubleSignSlash( + address consensusAddress + ) external onlySlash whenNotPaused { + address operatorAddress = consensusToOperator[consensusAddress]; + if (!_validatorSet.contains(operatorAddress)) revert ValidatorNotExisted(); // should never happen + Validator storage valInfo = _validators[operatorAddress]; + + uint256 index = block.timestamp / BREATHE_BLOCK_INTERVAL; + // This is to prevent many honest validators being slashed at the same time because of implementation bugs + if (_felonyMap[index] >= maxFelonyBetweenBreatheBlock) revert NoMoreFelonyAllowed(); + _felonyMap[index] += 1; + + // check if the consensusAddress has already expired + if ( + consensusExpiration[consensusAddress] != 0 + && consensusExpiration[consensusAddress] + BREATHE_BLOCK_INTERVAL < block.timestamp + ) { + revert ConsensusAddressExpired(); + } + + // slash + (bool canSlash, uint256 jailUntil) = _checkFelonyRecord(operatorAddress, SlashType.DoubleSign); + if (!canSlash) revert AlreadySlashed(); + uint256 slashAmount = IStakeCredit(valInfo.creditContract).slash(felonySlashAmount); + _jailValidator(valInfo, jailUntil); + // Evict using the post-rotation consensus key; SlashIndicator's felony(K_old) + // covers the case where BSCValidatorSet has not yet synced K_new. + IBSCValidatorSet(VALIDATOR_CONTRACT_ADDR).felony(valInfo.consensusAddress); + + emit ValidatorSlashed(operatorAddress, jailUntil, slashAmount, SlashType.DoubleSign); + + IGovToken(GOV_TOKEN_ADDR).sync(valInfo.creditContract, operatorAddress); + } + + /** + * @param key the key of the param + * @param value the value of the param + */ + function updateParam(string calldata key, bytes calldata value) external onlyGov { + if (key.compareStrings("transferGasLimit")) { + if (value.length != 32) revert InvalidValue(key, value); + uint256 newTransferGasLimit = value.bytesToUint256(32); + if (newTransferGasLimit < 2300 || newTransferGasLimit > 10_000) revert InvalidValue(key, value); + transferGasLimit = newTransferGasLimit; + } else if (key.compareStrings("minSelfDelegationBNB")) { + if (value.length != 32) revert InvalidValue(key, value); + uint256 newMinSelfDelegationBNB = value.bytesToUint256(32); + if (newMinSelfDelegationBNB < 1000 ether || newMinSelfDelegationBNB > 100_000 ether) { + revert InvalidValue(key, value); + } + minSelfDelegationBNB = newMinSelfDelegationBNB; + } else if (key.compareStrings("minDelegationBNBChange")) { + if (value.length != 32) revert InvalidValue(key, value); + uint256 newMinDelegationBNBChange = value.bytesToUint256(32); + if (newMinDelegationBNBChange < 0.1 ether || newMinDelegationBNBChange > 10 ether) { + revert InvalidValue(key, value); + } + minDelegationBNBChange = newMinDelegationBNBChange; + } else if (key.compareStrings("maxElectedValidators")) { + if (value.length != 32) revert InvalidValue(key, value); + uint256 newMaxElectedValidators = value.bytesToUint256(32); + if (newMaxElectedValidators == 0 || newMaxElectedValidators > 500) revert InvalidValue(key, value); + maxElectedValidators = newMaxElectedValidators; + } else if (key.compareStrings("unbondPeriod")) { + if (value.length != 32) revert InvalidValue(key, value); + uint256 newUnbondPeriod = value.bytesToUint256(32); + if (newUnbondPeriod < 3 days || newUnbondPeriod > 30 days) revert InvalidValue(key, value); + unbondPeriod = newUnbondPeriod; + } else if (key.compareStrings("redelegateFeeRate")) { + if (value.length != 32) revert InvalidValue(key, value); + uint256 newRedelegateFeeRate = value.bytesToUint256(32); + if (newRedelegateFeeRate > 100) { + revert InvalidValue(key, value); + } + redelegateFeeRate = newRedelegateFeeRate; + } else if (key.compareStrings("downtimeSlashAmount")) { + if (value.length != 32) revert InvalidValue(key, value); + uint256 newDowntimeSlashAmount = value.bytesToUint256(32); + if (newDowntimeSlashAmount < 1 ether || newDowntimeSlashAmount >= felonySlashAmount) { + revert InvalidValue(key, value); + } + downtimeSlashAmount = newDowntimeSlashAmount; + } else if (key.compareStrings("felonySlashAmount")) { + if (value.length != 32) revert InvalidValue(key, value); + uint256 newFelonySlashAmount = value.bytesToUint256(32); + if (newFelonySlashAmount < 10 ether || newFelonySlashAmount <= downtimeSlashAmount) { + revert InvalidValue(key, value); + } + felonySlashAmount = newFelonySlashAmount; + } else if (key.compareStrings("downtimeJailTime")) { + if (value.length != 32) revert InvalidValue(key, value); + uint256 newDowntimeJailTime = value.bytesToUint256(32); + if (newDowntimeJailTime < 1 days || newDowntimeJailTime >= felonyJailTime) revert InvalidValue(key, value); + downtimeJailTime = newDowntimeJailTime; + } else if (key.compareStrings("felonyJailTime")) { + if (value.length != 32) revert InvalidValue(key, value); + uint256 newFelonyJailTime = value.bytesToUint256(32); + if (newFelonyJailTime < 3 days || newFelonyJailTime <= downtimeJailTime) revert InvalidValue(key, value); + felonyJailTime = newFelonyJailTime; + } else if (key.compareStrings("maxFelonyBetweenBreatheBlock")) { + if (value.length != 32) revert InvalidValue(key, value); + uint256 newJailedPerDay = value.bytesToUint256(32); + if (newJailedPerDay == 0) revert InvalidValue(key, value); + maxFelonyBetweenBreatheBlock = newJailedPerDay; + } else if (key.compareStrings("stakeHubProtector")) { + if (value.length != 20) revert InvalidValue(key, value); + address newStakeHubProtector = value.bytesToAddress(20); + if (newStakeHubProtector == address(0)) revert InvalidValue(key, value); + _setProtector(newStakeHubProtector); + } else if (key.compareStrings("maxNodeIDs")) { + if (value.length != 32) revert InvalidValue(key, value); + uint256 newMaxNodeIDs = value.bytesToUint256(32); + if (newMaxNodeIDs == 0) revert InvalidValue(key, value); + maxNodeIDs = newMaxNodeIDs; + } else { + revert UnknownParam(key, value); + } + emit ParamChange(key, value); + } + + /*----------------- view functions -----------------*/ + /** + * @param operatorAddress the operator address of the validator + * @param index the index of the day to query(timestamp / 1 days) + * + * @return the validator's reward of the day + */ + function getValidatorRewardRecord(address operatorAddress, uint256 index) external view returns (uint256) { + if (!_validatorSet.contains(operatorAddress)) revert ValidatorNotExisted(); + return IStakeCredit(_validators[operatorAddress].creditContract).rewardRecord(index); + } + + /** + * @param operatorAddress the operator address of the validator + * @param index the index of the day to query(timestamp / 1 days) + * + * @return the validator's total pooled BNB of the day + */ + function getValidatorTotalPooledBNBRecord(address operatorAddress, uint256 index) external view returns (uint256) { + if (!_validatorSet.contains(operatorAddress)) revert ValidatorNotExisted(); + return IStakeCredit(_validators[operatorAddress].creditContract).totalPooledBNBRecord(index); + } + + /** + * @notice pagination query all validators' operator address and credit contract address + * + * @param offset the offset of the query + * @param limit the limit of the query + * + * @return operatorAddrs operator addresses + * @return creditAddrs credit contract addresses + * @return totalLength total number of validators + */ + function getValidators( + uint256 offset, + uint256 limit + ) external view returns (address[] memory operatorAddrs, address[] memory creditAddrs, uint256 totalLength) { + totalLength = _validatorSet.length(); + if (offset >= totalLength) { + return (operatorAddrs, creditAddrs, totalLength); + } + + limit = limit == 0 ? totalLength : limit; + uint256 count = (totalLength - offset) > limit ? limit : (totalLength - offset); + operatorAddrs = new address[](count); + creditAddrs = new address[](count); + for (uint256 i; i < count; ++i) { + operatorAddrs[i] = _validatorSet.at(offset + i); + creditAddrs[i] = _validators[operatorAddrs[i]].creditContract; + } + } + + /** + * @notice get the consensus address of a validator + * + * @param operatorAddress the operator address of the validator + * + * @return consensusAddress the consensus address of the validator + */ + function getValidatorConsensusAddress( + address operatorAddress + ) external view returns (address consensusAddress) { + Validator memory valInfo = _validators[operatorAddress]; + consensusAddress = valInfo.consensusAddress; + } + + /** + * @notice get the credit contract address of a validator + * + * @param operatorAddress the operator address of the validator + * + * @return creditContract the credit contract address of the validator + */ + function getValidatorCreditContract( + address operatorAddress + ) external view returns (address creditContract) { + Validator memory valInfo = _validators[operatorAddress]; + creditContract = valInfo.creditContract; + } + + /** + * @notice get the vote address of a validator + * + * @param operatorAddress the operator address of the validator + * + * @return voteAddress the vote address of the validator + */ + function getValidatorVoteAddress( + address operatorAddress + ) external view returns (bytes memory voteAddress) { + Validator memory valInfo = _validators[operatorAddress]; + voteAddress = valInfo.voteAddress; + } + + /** + * @notice get the basic info of a validator + * + * @param operatorAddress the operator address of the validator + * + * @return createdTime the creation time of the validator + * @return jailed whether the validator is jailed + * @return jailUntil the jail time of the validator + */ + function getValidatorBasicInfo( + address operatorAddress + ) external view returns (uint256 createdTime, bool jailed, uint256 jailUntil) { + Validator memory valInfo = _validators[operatorAddress]; + createdTime = valInfo.createdTime; + jailed = valInfo.jailed; + jailUntil = valInfo.jailUntil; + } + + /** + * @param operatorAddress the operator address of the validator + * + * @return the description of a validator + */ + function getValidatorDescription( + address operatorAddress + ) external view validatorExist(operatorAddress) returns (Description memory) { + return _validators[operatorAddress].description; + } + + /** + * @param operatorAddress the operator address of the validator + * + * @return the commission of a validator + */ + function getValidatorCommission( + address operatorAddress + ) external view validatorExist(operatorAddress) returns (Commission memory) { + return _validators[operatorAddress].commission; + } + + /** + * @param operatorAddress the operator address of the validator + * + * @return the agent of a validator + */ + function getValidatorAgent( + address operatorAddress + ) external view validatorExist(operatorAddress) returns (address) { + return _validators[operatorAddress].agent; + } + + /** + * @param operatorAddress the operator address of the validator + * + * @return the updateTime of a validator + */ + function getValidatorUpdateTime( + address operatorAddress + ) external view validatorExist(operatorAddress) returns (uint256) { + return _validators[operatorAddress].updateTime; + } + + /** + * @dev this function will be used by Parlia consensus engine. + * + * @notice get the election info of a validator + * + * @param offset the offset of the query + * @param limit the limit of the query + * + * @return consensusAddrs the consensus addresses of the validators + * @return votingPowers the voting powers of the validators. The voting power will be 0 if the validator is jailed. + * @return voteAddrs the vote addresses of the validators + * @return totalLength the total number of validators + */ + function getValidatorElectionInfo( + uint256 offset, + uint256 limit + ) + external + view + returns ( + address[] memory consensusAddrs, + uint256[] memory votingPowers, + bytes[] memory voteAddrs, + uint256 totalLength + ) + { + totalLength = _validatorSet.length(); + if (offset >= totalLength) { + return (consensusAddrs, votingPowers, voteAddrs, totalLength); + } + + limit = limit == 0 ? totalLength : limit; + uint256 count = (totalLength - offset) > limit ? limit : (totalLength - offset); + consensusAddrs = new address[](count); + votingPowers = new uint256[](count); + voteAddrs = new bytes[](count); + for (uint256 i; i < count; ++i) { + address operatorAddress = _validatorSet.at(offset + i); + Validator memory valInfo = _validators[operatorAddress]; + consensusAddrs[i] = valInfo.consensusAddress; + votingPowers[i] = valInfo.jailed ? 0 : IStakeCredit(valInfo.creditContract).totalPooledBNB(); + voteAddrs[i] = valInfo.voteAddress; + } + } + + /** + * @notice Adds multiple new NodeIDs to the validator's registry. + * @param nodeIDs Array of NodeIDs to be added. + */ + function addNodeIDs( + bytes32[] calldata nodeIDs + ) external whenNotPaused notInBlackList validatorExist(_bep563MsgSender()) { + maxNodeIDsInitializer(); + + if (nodeIDs.length == 0) { + revert InvalidNodeID(); + } + + address operatorAddress = _bep563MsgSender(); + bytes32[] storage existingNodeIDs = validatorNodeIDs[operatorAddress]; + uint256 currentLength = existingNodeIDs.length; + + if (currentLength + nodeIDs.length > maxNodeIDs) { + revert ExceedsMaxNodeIDs(); + } + + // Check for duplicates in new NodeIDs + for (uint256 i = 0; i < nodeIDs.length; i++) { + if (nodeIDs[i] == bytes32(0)) { + revert InvalidNodeID(); + } + for (uint256 j = i + 1; j < nodeIDs.length; j++) { + if (nodeIDs[i] == nodeIDs[j]) { + revert DuplicateNodeID(); + } + } + } + + // Check for duplicates in existing NodeIDs + for (uint256 i = 0; i < nodeIDs.length; i++) { + for (uint256 j = 0; j < currentLength; j++) { + if (nodeIDs[i] == existingNodeIDs[j]) { + revert DuplicateNodeID(); + } + } + } + + // Add new NodeIDs + for (uint256 i = 0; i < nodeIDs.length; i++) { + existingNodeIDs.push(nodeIDs[i]); + emit NodeIDAdded(operatorAddress, nodeIDs[i]); + } + } + + /** + * @notice Removes multiple NodeIDs from the validator's registry. + * @param targetNodeIDs Array of NodeIDs to be removed. + */ + function removeNodeIDs( + bytes32[] calldata targetNodeIDs + ) external whenNotPaused notInBlackList validatorExist(_bep563MsgSender()) { + address validator = _bep563MsgSender(); + bytes32[] storage nodeIDs = validatorNodeIDs[validator]; + uint256 length = nodeIDs.length; + + // If targetNodeIDs is empty, remove all NodeIDs + if (targetNodeIDs.length == 0) { + for (uint256 i = 0; i < length; i++) { + emit NodeIDRemoved(validator, nodeIDs[i]); + } + delete validatorNodeIDs[validator]; + return; + } + + // Otherwise, remove specific NodeIDs + for (uint256 i = 0; i < targetNodeIDs.length; i++) { + bytes32 nodeID = targetNodeIDs[i]; + for (uint256 j = 0; j < length; j++) { + if (nodeIDs[j] == nodeID) { + // Swap and pop + nodeIDs[j] = nodeIDs[length - 1]; + nodeIDs.pop(); + length--; + emit NodeIDRemoved(validator, nodeID); + break; + } + } + } + + // Clean up storage if no NodeIDs left + if (nodeIDs.length == 0) { + delete validatorNodeIDs[validator]; + } + } + + /** + * @notice Returns all validators with their consensus addresses and registered NodeIDs. + * @param validatorsToQuery The operator addresses of the validators. + * @return consensusAddresses Array of consensus addresses corresponding to the validators. + * @return nodeIDsList Array of NodeIDs for each validator. + */ + function getNodeIDs( + address[] calldata validatorsToQuery + ) external view returns (address[] memory consensusAddresses, bytes32[][] memory nodeIDsList) { + uint256 len = validatorsToQuery.length; + consensusAddresses = new address[](len); + nodeIDsList = new bytes32[][](len); + + for (uint256 i = 0; i < len; i++) { + address operator = validatorsToQuery[i]; + Validator memory valInfo = _validators[operator]; + consensusAddresses[i] = valInfo.consensusAddress; + nodeIDsList[i] = validatorNodeIDs[operator]; + } + + return (consensusAddresses, nodeIDsList); + } + + /*----------------- internal functions -----------------*/ + function _checkMoniker( + string memory moniker + ) internal pure returns (bool) { + bytes memory bz = bytes(moniker); + + // 1. moniker length should be between 3 and 9 + if (bz.length < 3 || bz.length > 9) { + return false; + } + + // 2. first character should be uppercase + if (uint8(bz[0]) < 65 || uint8(bz[0]) > 90) { + return false; + } + + // 3. only alphanumeric characters are allowed + for (uint256 i = 1; i < bz.length; ++i) { + // Check if the ASCII value of the character falls outside the range of alphanumeric characters + if ( + (uint8(bz[i]) < 48 || uint8(bz[i]) > 57) && (uint8(bz[i]) < 65 || uint8(bz[i]) > 90) + && (uint8(bz[i]) < 97 || uint8(bz[i]) > 122) + ) { + // Character is a special character + return false; + } + } + + // No special characters found + return true; + } + + function _checkVoteAddress( + address operatorAddress, + bytes calldata voteAddress, + bytes calldata blsProof + ) internal view returns (bool) { + if (voteAddress.length != BLS_PUBKEY_LENGTH || blsProof.length != BLS_SIG_LENGTH) { + return false; + } + + // get msg hash + bytes32 msgHash = keccak256(abi.encodePacked(operatorAddress, voteAddress, block.chainid)); + bytes memory msgBz = new bytes(32); + assembly { + mstore(add(msgBz, 32), msgHash) + } + + // call the precompiled contract to verify the BLS signature + // the precompiled contract's address is 0x66 + bytes memory input = bytes.concat(msgBz, blsProof, voteAddress); // length: 32 + 96 + 48 = 176 + bytes memory output = new bytes(1); + assembly { + let len := mload(input) + if iszero(staticcall(not(0), 0x66, add(input, 0x20), len, add(output, 0x20), 0x01)) { revert(0, 0) } + } + uint8 result = uint8(output[0]); + if (result != uint8(1)) { + return false; + } + return true; + } + + function _deployStakeCredit(address operatorAddress, string memory moniker) internal returns (address) { + address creditProxy = address(new TransparentUpgradeableProxy(STAKE_CREDIT_ADDR, DEAD_ADDRESS, "")); + IStakeCredit(creditProxy).initialize{ value: msg.value }(operatorAddress, moniker); + emit StakeCreditInitialized(operatorAddress, creditProxy); + + return creditProxy; + } + + function _checkValidatorSelfDelegation( + address operatorAddress + ) internal { + Validator storage valInfo = _validators[operatorAddress]; + if (valInfo.jailed) { + return; + } + if (IStakeCredit(valInfo.creditContract).getPooledBNB(operatorAddress) < minSelfDelegationBNB) { + _jailValidator(valInfo, block.timestamp + downtimeJailTime); + IBSCValidatorSet(VALIDATOR_CONTRACT_ADDR).felony(valInfo.consensusAddress); + } + } + + function _checkFelonyRecord(address operatorAddress, SlashType slashType) internal returns (bool, uint256) { + bytes32 slashKey = keccak256(abi.encodePacked(operatorAddress, slashType)); + uint256 jailUntil = _felonyRecords[slashKey]; + // for double sign and malicious vote slash + // if the validator is already jailed, no need to slash again + if (jailUntil > block.timestamp) { + return (false, 0); + } + jailUntil = block.timestamp + felonyJailTime; + _felonyRecords[slashKey] = jailUntil; + return (true, jailUntil); + } + + function _jailValidator(Validator storage valInfo, uint256 jailUntil) internal { + // keep the last eligible validator + bool isLast = (numOfJailed >= _validatorSet.length() - 1); + if (isLast) { + // If staking channel is closed, then BC-fusion is finished and we should keep the last eligible validator here + emit ValidatorEmptyJailed(valInfo.operatorAddress); + return; + } + + if (jailUntil > valInfo.jailUntil) { + valInfo.jailUntil = jailUntil; + } + + if (!valInfo.jailed) { + valInfo.jailed = true; + numOfJailed += 1; + + emit ValidatorJailed(valInfo.operatorAddress); + } + } + + function _claim(address operatorAddress, uint256 requestNumber) internal validatorExist(operatorAddress) { + uint256 bnbAmount = IStakeCredit(_validators[operatorAddress].creditContract).claim(msg.sender, requestNumber); + emit Claimed(operatorAddress, msg.sender, bnbAmount); + } + + function _bep410MsgSender() internal view returns (address) { + if (agentToOperator[msg.sender] != address(0)) { + return agentToOperator[msg.sender]; + } + + return msg.sender; + } + + function _bep563MsgSender() internal view returns (address) { + // Rotated consensus addresses must no longer authorize validator-admin + // actions, but the stale mapping is intentionally retained for system + // paths such as slash/reward handling. + if (consensusToOperator[msg.sender] != address(0) && consensusExpiration[msg.sender] == 0) { + return consensusToOperator[msg.sender]; + } + + return _bep410MsgSender(); + } + + function maxNodeIDsInitializer() internal { + if (maxNodeIDs == 0) { + maxNodeIDs = INIT_MAX_NUMBER_NODE_ID; + } + } +} diff --git a/plan/agw/research/preset-catalog-2026-10-15/VBep20.sol b/plan/agw/research/preset-catalog-2026-10-15/VBep20.sol new file mode 100644 index 00000000..d2d5e1c0 --- /dev/null +++ b/plan/agw/research/preset-catalog-2026-10-15/VBep20.sol @@ -0,0 +1,272 @@ +// SPDX-License-Identifier: BSD-3-Clause + +pragma solidity 0.8.25; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import { ComptrollerInterface } from "../../Comptroller/ComptrollerInterface.sol"; +import { InterestRateModelV8 } from "../../InterestRateModels/InterestRateModelV8.sol"; +import { VBep20Interface, VTokenInterface } from "./VTokenInterfaces.sol"; +import { VToken } from "./VToken.sol"; + +/** + * @title Venus's VBep20 Contract + * @notice vTokens which wrap an ERC-20 underlying + * @author Venus + */ +contract VBep20 is VToken, VBep20Interface { + using SafeERC20 for IERC20; + + /*** User Interface ***/ + + /** + * @notice Sender supplies assets into the market and receives vTokens in exchange + * @dev Accrues interest whether or not the operation succeeds, unless reverted + * @param mintAmount The amount of the underlying asset to supply + * @return uint Returns 0 on success, otherwise returns a failure code (see ErrorReporter.sol for details). + */ + // @custom:event Emits Transfer event + // @custom:event Emits Mint event + function mint(uint mintAmount) external returns (uint) { + (uint err, ) = mintInternal(mintAmount); + return err; + } + + /** + * @notice Sender supplies assets into the market and receiver receives vTokens in exchange + * @dev Accrues interest whether or not the operation succeeds, unless reverted + * @param receiver The account which is receiving the vTokens + * @param mintAmount The amount of the underlying asset to supply + * @return uint Returns 0 on success, otherwise returns a failure code (see ErrorReporter.sol for details). + */ + // @custom:event Emits Transfer event + // @custom:event Emits MintBehalf event + function mintBehalf(address receiver, uint mintAmount) external returns (uint) { + (uint err, ) = mintBehalfInternal(receiver, mintAmount); + return err; + } + + /** + * @notice Sender redeems vTokens in exchange for the underlying asset + * @dev Accrues interest whether or not the operation succeeds, unless reverted + * @param redeemTokens The number of vTokens to redeem into underlying + * @return uint Returns 0 on success, otherwise returns a failure code (see ErrorReporter.sol for details). + */ + // @custom:event Emits Redeem event on success + // @custom:event Emits Transfer event on success + // @custom:event Emits RedeemFee when fee is charged by the treasury + function redeem(uint redeemTokens) external returns (uint) { + return redeemInternal(msg.sender, payable(msg.sender), redeemTokens); + } + + /** + * @notice Sender redeems assets on behalf of some other address. This function is only available + * for senders, explicitly marked as delegates of the supplier using `comptroller.updateDelegate` + * @dev Accrues interest whether or not the operation succeeds, unless reverted + * @param redeemer The user on behalf of whom to redeem + * @param redeemTokens The number of vTokens to redeem into underlying + * @return uint Returns 0 on success, otherwise returns a failure code (see ErrorReporter.sol for details). + */ + // @custom:event Emits Redeem event on success + // @custom:event Emits Transfer event on success + // @custom:event Emits RedeemFee when fee is charged by the treasury + function redeemBehalf(address redeemer, uint redeemTokens) external returns (uint) { + require(comptroller.approvedDelegates(redeemer, msg.sender), "not an approved delegate"); + + return redeemInternal(redeemer, payable(msg.sender), redeemTokens); + } + + /** + * @notice Sender redeems vTokens in exchange for a specified amount of underlying asset + * @dev Accrues interest whether or not the operation succeeds, unless reverted + * @param redeemAmount The amount of underlying to redeem + * @return uint Returns 0 on success, otherwise returns a failure code (see ErrorReporter.sol for details). + */ + // @custom:event Emits Redeem event on success + // @custom:event Emits Transfer event on success + // @custom:event Emits RedeemFee when fee is charged by the treasury + function redeemUnderlying(uint redeemAmount) external returns (uint) { + return redeemUnderlyingInternal(msg.sender, payable(msg.sender), redeemAmount); + } + + /** + * @notice Sender redeems underlying assets on behalf of some other address. This function is only available + * for senders, explicitly marked as delegates of the supplier using `comptroller.updateDelegate` + * @dev Accrues interest whether or not the operation succeeds, unless reverted + * @param redeemer, on behalf of whom to redeem + * @param redeemAmount The amount of underlying to receive from redeeming vTokens + * @return uint Returns 0 on success, otherwise returns a failure code (see ErrorReporter.sol for details). + */ + // @custom:event Emits Redeem event on success + // @custom:event Emits Transfer event on success + // @custom:event Emits RedeemFee when fee is charged by the treasury + function redeemUnderlyingBehalf(address redeemer, uint redeemAmount) external returns (uint) { + require(comptroller.approvedDelegates(redeemer, msg.sender), "not an approved delegate"); + + return redeemUnderlyingInternal(redeemer, payable(msg.sender), redeemAmount); + } + + /** + * @notice Sender borrows assets from the protocol to their own address + * @param borrowAmount The amount of the underlying asset to borrow + * @return uint Returns 0 on success, otherwise returns a failure code (see ErrorReporter.sol for details). + */ + // @custom:event Emits Borrow event on success + function borrow(uint borrowAmount) external returns (uint) { + return borrowInternal(msg.sender, payable(msg.sender), borrowAmount); + } + + /** + * @notice Sender borrows assets on behalf of some other address. This function is only available + * for senders, explicitly marked as delegates of the borrower using `comptroller.updateDelegate` + * @param borrower The borrower, on behalf of whom to borrow. + * @param borrowAmount The amount of the underlying asset to borrow + * @return uint Returns 0 on success, otherwise returns a failure code (see ErrorReporter.sol for details). + */ + // @custom:event Emits Borrow event on success + function borrowBehalf(address borrower, uint borrowAmount) external returns (uint) { + require(comptroller.approvedDelegates(borrower, msg.sender), "not an approved delegate"); + return borrowInternal(borrower, payable(msg.sender), borrowAmount); + } + + /** + * @notice Sender repays their own borrow + * @param repayAmount The amount to repay + * @return uint Returns 0 on success, otherwise returns a failure code (see ErrorReporter.sol for details). + */ + // @custom:event Emits RepayBorrow event on success + function repayBorrow(uint repayAmount) external returns (uint) { + (uint err, ) = repayBorrowInternal(repayAmount); + return err; + } + + /** + * @notice Sender repays a borrow belonging to another borrowing account + * @param borrower The account with the debt being payed off + * @param repayAmount The amount to repay + * @return uint Returns 0 on success, otherwise returns a failure code (see ErrorReporter.sol for details). + */ + // @custom:event Emits RepayBorrow event on success + function repayBorrowBehalf(address borrower, uint repayAmount) external returns (uint) { + (uint err, ) = repayBorrowBehalfInternal(borrower, repayAmount); + return err; + } + + /** + * @notice The sender liquidates the borrowers collateral. + * The collateral seized is transferred to the liquidator. + * @param borrower The borrower of this vToken to be liquidated + * @param repayAmount The amount of the underlying borrowed asset to repay + * @param vTokenCollateral The market in which to seize collateral from the borrower + * @return uint Returns 0 on success, otherwise returns a failure code (see ErrorReporter.sol for details). + */ + // @custom:event Emit LiquidateBorrow event on success + function liquidateBorrow( + address borrower, + uint repayAmount, + VTokenInterface vTokenCollateral + ) external returns (uint) { + (uint err, ) = liquidateBorrowInternal(borrower, repayAmount, vTokenCollateral); + return err; + } + + /** + * @notice The sender adds to reserves. + * @param addAmount The amount of underlying tokens to add as reserves + * @return uint Returns 0 on success, otherwise returns a failure code (see ErrorReporter.sol for details). + */ + // @custom:event Emits ReservesAdded event + function _addReserves(uint addAmount) external returns (uint) { + return _addReservesInternal(addAmount); + } + + /** + * @notice Initialize the new money market + * @param underlying_ The address of the underlying asset + * @param comptroller_ The address of the Comptroller + * @param interestRateModel_ The address of the interest rate model + * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18 + * @param name_ BEP-20 name of this token + * @param symbol_ BEP-20 symbol of this token + * @param decimals_ BEP-20 decimal precision of this token + */ + function initialize( + address underlying_, + ComptrollerInterface comptroller_, + InterestRateModelV8 interestRateModel_, + uint initialExchangeRateMantissa_, + string memory name_, + string memory symbol_, + uint8 decimals_ + ) public { + // VToken initialize does the bulk of the work + super.initialize(comptroller_, interestRateModel_, initialExchangeRateMantissa_, name_, symbol_, decimals_); + + // Set underlying and sanity check it + underlying = underlying_; + IERC20(underlying).totalSupply(); + } + + /*** Safe Token ***/ + + /** + * @dev Similar to ERC-20 transfer, but handles tokens that have transfer fees. + * This function returns the actual amount received, + * which may be less than `amount` if there is a fee attached to the transfer. + * Increments `internalCash` by the actual amount received. + * @param from Sender of the underlying tokens + * @param amount Amount of underlying to transfer + * @return Actual amount received + */ + function doTransferIn(address from, uint256 amount) internal virtual override returns (uint256) { + IERC20 token = IERC20(underlying); + uint256 balanceBefore = token.balanceOf(address(this)); + token.safeTransferFrom(from, address(this), amount); + uint256 balanceAfter = token.balanceOf(address(this)); + uint256 actualAmount = balanceAfter - balanceBefore; + internalCash += actualAmount; + // Return the amount that was *actually* transferred + return actualAmount; + } + + /** + * @dev Just a regular ERC-20 transfer, reverts on failure. + * Decrements `internalCash` by `amount` before transferring. + * @param to Receiver of the underlying tokens + * @param amount Amount of underlying to transfer + */ + function doTransferOut(address payable to, uint256 amount) internal virtual override { + internalCash -= amount; + IERC20 token = IERC20(underlying); + token.safeTransfer(to, amount); + } + + /** + * @notice Gets the tracked internal cash balance of this contract + * @dev Returns `internalCash` rather than the actual token balance, making it immune to donation attacks. + * @return The internally tracked cash balance of underlying tokens + */ + function getCashPrior() internal view override returns (uint) { + return internalCash; + } + + /** + * @notice Transfer excess tokens to caller and sync internalCash with actual balance + * @dev Admin-only. `sweepTokenAndSync(0)` is the general admin resync entry for internalCash — + * use it for migration, donation-attack protection, and intentional donation incorporation. + * Transfers `transferAmount` of underlying to msg.sender, then sets internalCash = balanceOf(address(this)). + * @param transferAmount Amount of underlying to transfer to msg.sender before syncing + */ + function sweepTokenAndSync(uint256 transferAmount) external { + require(msg.sender == admin); + + if (transferAmount > 0) { + IERC20(underlying).safeTransfer(msg.sender, transferAmount); + emit TokenSwept(msg.sender, transferAmount); + } + + uint256 oldInternalCash = internalCash; + internalCash = IERC20(underlying).balanceOf(address(this)); + emit CashSynced(oldInternalCash, internalCash); + } +} diff --git a/plan/agw/research/preset-catalog-2026-10-15/additional-sources.json b/plan/agw/research/preset-catalog-2026-10-15/additional-sources.json new file mode 100644 index 00000000..befa930b --- /dev/null +++ b/plan/agw/research/preset-catalog-2026-10-15/additional-sources.json @@ -0,0 +1,22 @@ +[ + { + "file": "PancakeIV3SwapRouter.sol", + "url": "https://raw.githubusercontent.com/pancakeswap/pancake-v3-contracts/main/projects/smart-router/contracts/interfaces/IV3SwapRouter.sol", + "error": "HTTP Error 404: Not Found" + }, + { + "file": "MERC20.sol", + "url": "https://raw.githubusercontent.com/moonwell-fi/moonwell-contracts-v2/main/src/MErc20.sol", + "bytes": 11341 + }, + { + "file": "EigenStrategyManager.sol", + "url": "https://raw.githubusercontent.com/Layr-Labs/eigenlayer-contracts/v1.5.0/src/contracts/core/StrategyManager.sol", + "bytes": 23355 + }, + { + "file": "Comptroller.sol", + "url": "https://raw.githubusercontent.com/moonwell-fi/moonwell-contracts-v2/main/src/Comptroller.sol", + "bytes": 50692 + } +] diff --git a/plan/agw/research/preset-catalog-2026-10-15/addresses.md b/plan/agw/research/preset-catalog-2026-10-15/addresses.md new file mode 100644 index 00000000..27da8949 --- /dev/null +++ b/plan/agw/research/preset-catalog-2026-10-15/addresses.md @@ -0,0 +1,71 @@ +--- +description: Fork of Uniswap v3 +--- + +# PancakeSwap v3 Addresses + +## Core + +| Contract | BSC, ETH, ARB, Linea, Base, opBNB, BSC TESTNET / MAINNET, Monad, Robinhood | zkSync | +| --------------------- | -------------------------------------------------------------------- | ------------------------------------------ | +| PancakeV3Factory | 0x0BFbCF9fa4f9C56B0F40a671Ad40E0805A091865 | 0x1BB72E0CbbEA93c08f535fc7856E0338D7F7a8aB | +| PancakeV3PoolDeployer | 0x41ff9AA7e16B8B1a8a8dc4f0eFacd93D02d071c9 | 0x7f71382044A6a62595D5D357fE75CA8199123aD6 | + +## Periphery + +| Contract | BSC, ETH, Arbitrum, Linea, Base, opBNB, Monad | zkSync | BSC TESTNET | Robinhood | +| -------------------------- | --------------------------------------------- | ------------------------------------------ | ------------------------------------------ | ------------------------------------------ | +| SwapRouter (v3) | 0x1b81D678ffb9C0263b24A97847620C99d213eB14 | 0xD70C70AD87aa8D45b8D59600342FB3AEe76E3c68 | 0x1b81D678ffb9C0263b24A97847620C99d213eB14 | n/a | +| V3Migrator | 0xbC203d7f83677c7ed3F7acEc959963E7F4ECC5C2 | 0x556A72A7A3bB3bbd293D923e59b6B56898fB405D | 0x46A15B0b27311cedF172AB29E4f4766fbE7F4364 | 0xbC203d7f83677c7ed3F7acEc959963E7F4ECC5C2 | +| NonfungiblePositionManager | 0x46A15B0b27311cedF172AB29E4f4766fbE7F4364 | 0xa815e2eD7f7d5B0c49fda367F249232a1B9D2883 | 0x427bF5b37357632377eCbEC9de3626C71A5396c1 | 0x46A15B0b27311cedF172AB29E4f4766fbE7F4364 | +| QuoterV2 | 0xB048Bbc1Ee6b733FFfCFb9e9CeF7375518e25997 | 0x3d146FcE6c1006857750cBe8aF44f76a28041CCc | 0xbC203d7f83677c7ed3F7acEc959963E7F4ECC5C2 | 0x8553AA1615549A86882151784b329B017aA7c832 | +| TickLens | 0x9a489505a00cE272eAa5e07Dba6491314CaE3796 | 0x7b08978FA77910f77d273c353C62b5BFB9E6D17B | 0xac1cE734566f390A94b00eb9bf561c2625BF44ea | 0x9a489505a00cE272eAa5e07Dba6491314CaE3796 | +| PancakeInterfaceMulticall | 0xac1cE734566f390A94b00eb9bf561c2625BF44ea | 0x2a76b93B9Cd441AE8aDA529e0e95826e00556351 | 0x3D00CdB4785F0ef20C903A13596e0b9B2c652227 | 0xcf05Fc31A6B693DD0bEB76e958ae4BCD490dc985 | + +| Contract | BSC, ETH, Linea | Linea, Base, opBNB | Arbitrum | zkSync | Monad | BSC TESTNET | Robinhood | +| ------------------ | ------------------------------------------ | ------------------------------------------ | ------------------------------------------ | ------------------------------------------ | ------------------------------------------ | ------------------------------------------ | ------------------------------------------ | +| MixedRouteQuoterV1 | 0x678Aa4bF4E210cf2166753e054d5b7c31cc7fa86 | 0x4c650FB471fe4e0f476fD3437C3411B1122c4e3B | 0x3652Fc6EDcbD76161b8554388867d3dAb65eCA93 | 0x9B1edFB3848660402E4f1DC25733764e80aA627A | 0x77b482D9A4E391d682C857C630B8d869FdeE5c44 | 0xB048Bbc1Ee6b733FFfCFb9e9CeF7375518e25997 | 0x2b792b99ae08483D45d79833408439674C6Daf1B | +| TokenValidator | 0x864ED564875BdDD6F421e226494a0E7c071C06f8 | 0x556B9306565093C855AEA9AE92A594704c2Cd59e | 0x8be9EA9C6015985AB2F5A216093305A9AaEb8164 | 0x08529A4be615746ef31CdbeD46Ce556406787E2F | 0xfcB76dfDf9c79AE5d334C0E1901449c8A893DF22 | 0x678Aa4bF4E210cf2166753e054d5b7c31cc7fa86 | n/a | + +## Smart Router +Able to route to v3, v2 and stable pool + +| Chain | Address +| ------------------------------------------ | ------------------------------------------ | +| BSC, ETH, Robinhood | 0x13f4EA83D0bd40E75C8222255bc855a974568Dd4 | +| Linea, Base, opBNB | 0x678Aa4bF4E210cf2166753e054d5b7c31cc7fa86 | +| Arbitrum | 0x32226588378236Fd0c7c4053999F88aC0e5cAc77 | +| zkSync | 0xf8b59f3c3Ab33200ec80a8A58b2aA5F5D2a8944C | +| Monad | 0x21114915Ac6d5A2e156931e20B20b038dEd0Be7C | + +**Testnet** + +| Chain | Address +| ------------------------------------------ | ------------------------------------------ | +| BSC testnet | 0x9a489505a00cE272eAa5e07Dba6491314CaE3796 | + + +## MasterchefV3 + +**Mainnet** + +| Chain | Address +| ------------------------------------------ | ------------------------------------------ | +| BSC, ETH | 0x556B9306565093C855AEA9AE92A594704c2Cd59e | +| Arbitrum | 0x5e09ACf80C0296740eC5d6F643005a4ef8DaA694 | +| zkSync | 0x4c615E78c5fCA1Ad31e4d66eb0D8688d84307463 | +| Linea | 0x22E2f236065B780FA33EC8C4E58b99ebc8B55c57 | +| Base | 0xC6A2Db661D5a5690172d8eB0a7DEA2d3008665A3 | +| opBNB | 0x05ddEDd07C51739d2aE21F6A9d97a8d69C2C3aaA | + +**Testnet** + +| Chain | Address +| ------------------------------------------ | ------------------------------------------ | +| BSC testnet | 0x4c650FB471fe4e0f476fD3437C3411B1122c4e3B | +| Arbitrum | 0x66A9870FF7707936B0B0278cF999C5f2Ac2e42F5 | +| zkSync | 0x3c6Aa61f72932aD5D7C917737367be32D5509e6f | +| Linea | 0xb66b07590B30d4E6E22e45Ddc83B06Bb018A7B44 | +| Base | 0xAd3fe5Aeabf79B8291F877B367139466c221216e | +| opBNB | 0x236e713bFF45adb30e25D1c29A887aBCb0Ea7E21 | + diff --git a/plan/agw/research/preset-catalog-2026-10-15/addresses.ts b/plan/agw/research/preset-catalog-2026-10-15/addresses.ts new file mode 100644 index 00000000..8076118f --- /dev/null +++ b/plan/agw/research/preset-catalog-2026-10-15/addresses.ts @@ -0,0 +1,714 @@ +import { ChainId, SUPPORTED_CHAINS, SupportedChainsType } from './chains' + +type AddressMap = { [chainId: number]: string } + +type ChainAddresses = { + v3CoreFactoryAddress: string + multicallAddress: string + quoterAddress: string + v3MigratorAddress?: string + nonfungiblePositionManagerAddress?: string + tickLensAddress?: string + swapRouter02Address?: string + mixedRouteQuoterV1Address?: string + mixedRouteQuoterV2Address?: string + + // v4 + v4PoolManagerAddress?: string + v4PositionManagerAddress?: string + v4StateView?: string + v4QuoterAddress?: string + permissionedV4PositionManagerAddress?: string + permissionedV4HooksAddress?: string +} + +const DEFAULT_NETWORKS = [ChainId.MAINNET, ChainId.GOERLI, ChainId.SEPOLIA] + +function constructSameAddressMap(address: string, additionalNetworks: ChainId[] = []): AddressMap { + return DEFAULT_NETWORKS.concat(additionalNetworks).reduce((memo, chainId) => { + memo[chainId] = address + return memo + }, {}) +} + +export const UNI_ADDRESSES: AddressMap = constructSameAddressMap('0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984', [ + ChainId.OPTIMISM, + ChainId.ARBITRUM_ONE, + ChainId.POLYGON, + ChainId.POLYGON_MUMBAI, + ChainId.SEPOLIA, +]) + +export const UNISWAP_NFT_AIRDROP_CLAIM_ADDRESS = '0x8B799381ac40b838BBA4131ffB26197C432AFe78' + +/** + * @deprecated use V2_FACTORY_ADDRESSES instead + */ +export const V2_FACTORY_ADDRESS = '0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f' +export const V2_FACTORY_ADDRESSES: AddressMap = { + [ChainId.MAINNET]: '0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f', + [ChainId.GOERLI]: '0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f', + [ChainId.SEPOLIA]: '0xF62c03E08ada871A0bEb309762E260a7a6a880E6', + [ChainId.OPTIMISM]: '0x0c3c1c532F1e39EdF36BE9Fe0bE1410313E074Bf', + [ChainId.ARBITRUM_ONE]: '0xf1D7CC64Fb4452F05c498126312eBE29f30Fbcf9', + [ChainId.AVALANCHE]: '0x9e5A52f57b3038F1B8EeE45F28b3C1967e22799C', + [ChainId.BASE_SEPOLIA]: '0x7Ae58f10f7849cA6F5fB71b7f45CB416c9204b1e', + [ChainId.BASE]: '0x8909dc15e40173ff4699343b6eb8132c65e18ec6', + [ChainId.BNB]: '0x8909Dc15e40173Ff4699343b6eB8132c65e18eC6', + [ChainId.POLYGON]: '0x9e5A52f57b3038F1B8EeE45F28b3C1967e22799C', + [ChainId.CELO]: '0x79a530c8e2fA8748B7B40dd3629C0520c2cCf03f', + [ChainId.BLAST]: '0x5C346464d33F90bABaf70dB6388507CC889C1070', + [ChainId.WORLDCHAIN]: '0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f', + [ChainId.UNICHAIN_SEPOLIA]: '0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f', + [ChainId.UNICHAIN]: '0x1f98400000000000000000000000000000000002', + [ChainId.MONAD_TESTNET]: '0x733e88f248b742db6c14c0b1713af5ad7fdd59d0', + [ChainId.SONEIUM]: '0x97febbc2adbd5644ba22736e962564b23f5828ce', + [ChainId.MONAD]: '0x182a927119d56008d921126764bf884221b10f59', + [ChainId.XLAYER]: '0xdf38f24fe153761634be942f9d859f3dba857e95', + [ChainId.LINEA]: '0x114A43DF6C5f54EBB8A9d70Cd1951D3dD68004c7', + [ChainId.TEMPO]: '0xf9ec577a4e45b5278bb7cf60fcbc20c3acaef68f', + [ChainId.MEGAETH]: '0xbf56488c857a881ae7e3bed27cf99c10a7ab7e50', + [ChainId.ARC]: '0x89e5db8b5aa49aa85ac63f691524311aeb649eba', + [ChainId.ROBINHOOD]: '0x8bceaa40b9acdfaedf85adf4ff01f5ad6517937f', + [ChainId.INK]: '0xfe57a6ba1951f69ae2ed4abe23e0f095df500c04', +} +/** + * @deprecated use V2_ROUTER_ADDRESSES instead + */ +export const V2_ROUTER_ADDRESS = '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D' +export const V2_ROUTER_ADDRESSES: AddressMap = { + [ChainId.MAINNET]: '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D', + [ChainId.GOERLI]: '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D', + [ChainId.SEPOLIA]: '0xeE567Fe1712Faf6149d80dA1E6934E354124CfE3', + [ChainId.ARBITRUM_ONE]: '0x4752ba5dbc23f44d87826276bf6fd6b1c372ad24', + [ChainId.OPTIMISM]: '0x4a7b5da61326a6379179b40d00f57e5bbdc962c2', + [ChainId.BASE_SEPOLIA]: '0x1689E7B1F10000AE47eBfE339a4f69dECd19F602', + [ChainId.BASE]: '0x4752ba5dbc23f44d87826276bf6fd6b1c372ad24', + [ChainId.AVALANCHE]: '0x4752ba5dbc23f44d87826276bf6fd6b1c372ad24', + [ChainId.BNB]: '0x4752ba5dbc23f44d87826276bf6fd6b1c372ad24', + [ChainId.POLYGON]: '0xedf6066a2b290c185783862c7f4776a2c8077ad1', + [ChainId.BLAST]: '0xBB66Eb1c5e875933D44DAe661dbD80e5D9B03035', + [ChainId.WORLDCHAIN]: '0x541aB7c31A119441eF3575F6973277DE0eF460bd', + [ChainId.UNICHAIN_SEPOLIA]: '0x920b806E40A00E02E7D2b94fFc89860fDaEd3640', + [ChainId.UNICHAIN]: '0x284f11109359a7e1306c3e447ef14d38400063ff', + [ChainId.MONAD_TESTNET]: '0xfb8e1c3b833f9e67a71c859a132cf783b645e436', + [ChainId.SONEIUM]: '0x273f68c234fa55b550b40e563c4a488e0d334320', + [ChainId.MONAD]: '0x4b2ab38dbf28d31d467aa8993f6c2585981d6804', + [ChainId.XLAYER]: '0x182a927119d56008d921126764bf884221b10f59', + [ChainId.LINEA]: '0x8702463e73f74d0b6765abceb314ef07acb92650', + [ChainId.TEMPO]: '0x0fbac3c46f6f83b44c7fb4ea986d7309c701d73e', + [ChainId.MEGAETH]: '0xb73055db2b3a3eae87a331dd88e4a80b43602690', + [ChainId.ARC]: '0x1f7d7550b1b028f7571e69a784071f0205fd2efa', + [ChainId.ROBINHOOD]: '0x89e5db8b5aa49aa85ac63f691524311aeb649eba', +} + +// Networks that share most of the same addresses i.e. Mainnet, Goerli, Optimism, Arbitrum, Polygon +const DEFAULT_ADDRESSES: ChainAddresses = { + v3CoreFactoryAddress: '0x1F98431c8aD98523631AE4a59f267346ea31F984', + multicallAddress: '0x1F98415757620B543A52E61c46B32eB19261F984', + quoterAddress: '0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6', + v3MigratorAddress: '0xA5644E29708357803b5A882D272c41cC0dF92B34', + nonfungiblePositionManagerAddress: '0xC36442b4a4522E871399CD717aBDD847Ab11FE88', +} +const MAINNET_ADDRESSES: ChainAddresses = { + ...DEFAULT_ADDRESSES, + mixedRouteQuoterV1Address: '0x84E44095eeBfEC7793Cd7d5b57B7e401D7f1cA2E', + + v4PoolManagerAddress: '0x000000000004444c5dc75cB358380D2e3dE08A90', + v4PositionManagerAddress: '0xbd216513d74c8cf14cf4747e6aaa6420ff64ee9e', + v4StateView: '0x7ffe42c4a5deea5b0fec41c94c136cf115597227', + v4QuoterAddress: '0x52f0e24d1c21c8a0cb1e5a5dd6198556bd9e1203', + permissionedV4PositionManagerAddress: '0xD7BE746B6b29f6185A01013E944313E1704C971F', + permissionedV4HooksAddress: '0x499a724Ab630549f14C995EC41a8E04fA3fd28c0', +} +const GOERLI_ADDRESSES: ChainAddresses = { + ...DEFAULT_ADDRESSES, + mixedRouteQuoterV1Address: '0xBa60b6e6fF25488308789E6e0A65D838be34194e', +} + +const OPTIMISM_ADDRESSES: ChainAddresses = { + ...DEFAULT_ADDRESSES, + + v4PoolManagerAddress: '0x9a13f98cb987694c9f086b1f5eb990eea8264ec3', + v4PositionManagerAddress: '0x3c3ea4b57a46241e54610e5f022e5c45859a1017', + v4StateView: '0xc18a3169788f4f75a170290584eca6395c75ecdb', + v4QuoterAddress: '0x1f3131a13296fb91c90870043742c3cdbff1a8d7', +} + +const ARBITRUM_ONE_ADDRESSES: ChainAddresses = { + ...DEFAULT_ADDRESSES, + multicallAddress: '0xadF885960B47eA2CD9B55E6DAc6B42b7Cb2806dB', + tickLensAddress: '0xbfd8137f7d1516D3ea5cA83523914859ec47F573', + + v4PoolManagerAddress: '0x360e68faccca8ca495c1b759fd9eee466db9fb32', + v4PositionManagerAddress: '0xd88f38f930b7952f2db2432cb002e7abbf3dd869', + v4StateView: '0x76fd297e2d437cd7f76d50f01afe6160f86e9990', + v4QuoterAddress: '0x3972c00f7ed4885e145823eb7c655375d275a1c5', +} +const POLYGON_ADDRESSES: ChainAddresses = { + ...DEFAULT_ADDRESSES, + + v4PoolManagerAddress: '0x67366782805870060151383f4bbff9dab53e5cd6', + v4PositionManagerAddress: '0x1ec2ebf4f37e7363fdfe3551602425af0b3ceef9', + v4StateView: '0x5ea1bd7974c8a611cbab0bdcafcb1d9cc9b3ba5a', + v4QuoterAddress: '0xb3d5c3dfc3a7aebff71895a7191796bffc2c81b9', +} + +// celo v3 and v4 addresses +const CELO_ADDRESSES: ChainAddresses = { + v3CoreFactoryAddress: '0xAfE208a311B21f13EF87E33A90049fC17A7acDEc', + multicallAddress: '0x633987602DE5C4F337e3DbF265303A1080324204', + quoterAddress: '0x82825d0554fA07f7FC52Ab63c961F330fdEFa8E8', + v3MigratorAddress: '0x3cFd4d48EDfDCC53D3f173F596f621064614C582', + nonfungiblePositionManagerAddress: '0x3d79EdAaBC0EaB6F08ED885C05Fc0B014290D95A', + tickLensAddress: '0x5f115D9113F88e0a0Db1b5033D90D4a9690AcD3D', + + v4PoolManagerAddress: '0x288dc841A52FCA2707c6947B3A777c5E56cd87BC', + v4PositionManagerAddress: '0xf7965f3981e4d5bc383bfbcb61501763e9068ca9', + v4StateView: '0xbc21f8720babf4b20d195ee5c6e99c52b76f2bfb', + v4QuoterAddress: '0x28566da1093609182dff2cb2a91cfd72e61d66cd', +} + +// BNB v3 addresses +const BNB_ADDRESSES: ChainAddresses = { + v3CoreFactoryAddress: '0xdB1d10011AD0Ff90774D0C6Bb92e5C5c8b4461F7', + multicallAddress: '0x963Df249eD09c358A4819E39d9Cd5736c3087184', + quoterAddress: '0x78D78E420Da98ad378D7799bE8f4AF69033EB077', + v3MigratorAddress: '0x32681814957e0C13117ddc0c2aba232b5c9e760f', + nonfungiblePositionManagerAddress: '0x7b8A01B39D58278b5DE7e48c8449c9f4F5170613', + tickLensAddress: '0xD9270014D396281579760619CCf4c3af0501A47C', + swapRouter02Address: '0xB971eF87ede563556b2ED4b1C0b0019111Dd85d2', + + v4PoolManagerAddress: '0x28e2ea090877bf75740558f6bfb36a5ffee9e9df', + v4PositionManagerAddress: '0x7a4a5c919ae2541aed11041a1aeee68f1287f95b', + v4StateView: '0xd13dd3d6e93f276fafc9db9e6bb47c1180aee0c4', + v4QuoterAddress: '0x9f75dd27d6664c475b90e105573e550ff69437b0', +} + +// optimism goerli addresses +const OPTIMISM_GOERLI_ADDRESSES: ChainAddresses = { + v3CoreFactoryAddress: '0xB656dA17129e7EB733A557f4EBc57B76CFbB5d10', + multicallAddress: '0x07F2D8a2a02251B62af965f22fC4744A5f96BCCd', + quoterAddress: '0x9569CbA925c8ca2248772A9A4976A516743A246F', + v3MigratorAddress: '0xf6c55fBe84B1C8c3283533c53F51bC32F5C7Aba8', + nonfungiblePositionManagerAddress: '0x39Ca85Af2F383190cBf7d7c41ED9202D27426EF6', + tickLensAddress: '0xe6140Bd164b63E8BfCfc40D5dF952f83e171758e', +} + +// optimism sepolia addresses +const OPTIMISM_SEPOLIA_ADDRESSES: ChainAddresses = { + v3CoreFactoryAddress: '0x8CE191193D15ea94e11d327b4c7ad8bbE520f6aF', + multicallAddress: '0x80e4e06841bb76AA9735E0448cB8d003C0EF009a', + quoterAddress: '0x0FBEa6cf957d95ee9313490050F6A0DA68039404', + v3MigratorAddress: '0xE7EcbAAaA54D007A00dbb6c1d2f150066D69dA07', + nonfungiblePositionManagerAddress: '0xdA75cEf1C93078e8b736FCA5D5a30adb97C8957d', + tickLensAddress: '0xCb7f54747F58F8944973cea5b8f4ac2209BadDC5', + swapRouter02Address: '0x94cC0AaC535CCDB3C01d6787D6413C739ae12bc4', +} + +// arbitrum goerli v3 addresses +const ARBITRUM_GOERLI_ADDRESSES: ChainAddresses = { + v3CoreFactoryAddress: '0x4893376342d5D7b3e31d4184c08b265e5aB2A3f6', + multicallAddress: '0x8260CB40247290317a4c062F3542622367F206Ee', + quoterAddress: '0x1dd92b83591781D0C6d98d07391eea4b9a6008FA', + v3MigratorAddress: '0xA815919D2584Ac3F76ea9CB62E6Fd40a43BCe0C3', + nonfungiblePositionManagerAddress: '0x622e4726a167799826d1E1D150b076A7725f5D81', + tickLensAddress: '0xb52429333da969a0C79a60930a4Bf0020E5D1DE8', +} + +// arbitrum sepolia v3 addresses +const ARBITRUM_SEPOLIA_ADDRESSES: ChainAddresses = { + v3CoreFactoryAddress: '0x248AB79Bbb9bC29bB72f7Cd42F17e054Fc40188e', + multicallAddress: '0x2B718b475e385eD29F56775a66aAB1F5cC6B2A0A', + quoterAddress: '0x2779a0CC1c3e0E44D2542EC3e79e3864Ae93Ef0B', + v3MigratorAddress: '0x398f43ef2c67B941147157DA1c5a868E906E043D', + nonfungiblePositionManagerAddress: '0x6b2937Bde17889EDCf8fbD8dE31C3C2a70Bc4d65', + tickLensAddress: '0x0fd18587734e5C2dcE2dccDcC7DD1EC89ba557d9', + swapRouter02Address: '0x101F443B4d1b059569D643917553c771E1b9663E', + + v4PoolManagerAddress: '0xFB3e0C6F74eB1a21CC1Da29aeC80D2Dfe6C9a317', + v4PositionManagerAddress: '0xAc631556d3d4019C95769033B5E719dD77124BAc', + v4StateView: '0x9d467fa9062b6e9b1a46e26007ad82db116c67cb', + v4QuoterAddress: '0x7de51022d70a725b508085468052e25e22b5c4c9', +} + +// sepolia v3 addresses +const SEPOLIA_ADDRESSES: ChainAddresses = { + v3CoreFactoryAddress: '0x0227628f3F023bb0B980b67D528571c95c6DaC1c', + multicallAddress: '0xD7F33bCdb21b359c8ee6F0251d30E94832baAd07', + quoterAddress: '0xEd1f6473345F45b75F8179591dd5bA1888cf2FB3', + v3MigratorAddress: '0x729004182cF005CEC8Bd85df140094b6aCbe8b15', + nonfungiblePositionManagerAddress: '0x1238536071E1c677A632429e3655c799b22cDA52', + tickLensAddress: '0x0b343475d44EC2b4b8243EBF81dc888BF0A14b36', + swapRouter02Address: '0x3bFA4769FB09eefC5a80d6E87c3B9C650f7Ae48E', + + // TODO: update mixedRouteQuoterV2Address once v4 on sepolia redeployed + mixedRouteQuoterV2Address: '0x4745f77b56a0e2294426e3936dc4fab68d9543cd', + + // TODO: update all below once v4 on sepolia redeployed + v4PoolManagerAddress: '0xE03A1074c86CFeDd5C142C4F04F1a1536e203543', + v4PositionManagerAddress: '0x429ba70129df741B2Ca2a85BC3A2a3328e5c09b4', + v4StateView: '0xe1dd9c3fa50edb962e442f60dfbc432e24537e4c', + v4QuoterAddress: '0x61b3f2011a92d183c7dbadbda940a7555ccf9227', + permissionedV4PositionManagerAddress: '0x864C37908Aa5e10b100CaCEe1c62E3954d76f5E1', + permissionedV4HooksAddress: '0x51247E2291d290d17C08813A175AC86465EdE8c0', +} + +// Avalanche v3 addresses +const AVALANCHE_ADDRESSES: ChainAddresses = { + v3CoreFactoryAddress: '0x740b1c1de25031C31FF4fC9A62f554A55cdC1baD', + multicallAddress: '0x0139141Cd4Ee88dF3Cdb65881D411bAE271Ef0C2', + quoterAddress: '0xbe0F5544EC67e9B3b2D979aaA43f18Fd87E6257F', + v3MigratorAddress: '0x44f5f1f5E452ea8d29C890E8F6e893fC0f1f0f97', + nonfungiblePositionManagerAddress: '0x655C406EBFa14EE2006250925e54ec43AD184f8B', + tickLensAddress: '0xEB9fFC8bf81b4fFd11fb6A63a6B0f098c6e21950', + swapRouter02Address: '0xbb00FF08d01D300023C629E8fFfFcb65A5a578cE', + + v4PoolManagerAddress: '0x06380c0e0912312b5150364b9dc4542ba0dbbc85', + v4PositionManagerAddress: '0xb74b1f14d2754acfcbbe1a221023a5cf50ab8acd', + v4StateView: '0xc3c9e198c735a4b97e3e683f391ccbdd60b69286', + v4QuoterAddress: '0xbe40675bb704506a3c2ccfb762dcfd1e979845c2', +} + +const BASE_ADDRESSES: ChainAddresses = { + v3CoreFactoryAddress: '0x33128a8fC17869897dcE68Ed026d694621f6FDfD', + multicallAddress: '0x091e99cb1C49331a94dD62755D168E941AbD0693', + quoterAddress: '0x3d4e44Eb1374240CE5F1B871ab261CD16335B76a', + v3MigratorAddress: '0x23cF10b1ee3AdfCA73B0eF17C07F7577e7ACd2d7', + nonfungiblePositionManagerAddress: '0x03a520b32C04BF3bEEf7BEb72E919cf822Ed34f1', + tickLensAddress: '0x0CdeE061c75D43c82520eD998C23ac2991c9ac6d', + swapRouter02Address: '0x2626664c2603336E57B271c5C0b26F421741e481', + mixedRouteQuoterV1Address: '0xe544efae946f0008ae9a8d64493efa7886b73776', + + v4PoolManagerAddress: '0x498581ff718922c3f8e6a244956af099b2652b2b', + v4PositionManagerAddress: '0x7c5f5a4bbd8fd63184577525326123b519429bdc', + v4StateView: '0xa3c0c9b65bad0b08107aa264b0f3db444b867a71', + v4QuoterAddress: '0x0d5e0f971ed27fbff6c2837bf31316121532048d', + permissionedV4PositionManagerAddress: '0xC09255D86DB563cBc11C2fCf4a0C512e160111B4', + permissionedV4HooksAddress: '0x5750be78fEdfb2fA48FAa6C6623400Ba4538A8c0', +} + +// Base Goerli v3 addresses +const BASE_GOERLI_ADDRESSES: ChainAddresses = { + v3CoreFactoryAddress: '0x9323c1d6D800ed51Bd7C6B216cfBec678B7d0BC2', + multicallAddress: '0xB206027a9E0E13F05eBEFa5D2402Bab3eA716439', + quoterAddress: '0xedf539058e28E5937dAef3f69cEd0b25fbE66Ae9', + v3MigratorAddress: '0x3efe5d02a04b7351D671Db7008ec6eBA9AD9e3aE', + nonfungiblePositionManagerAddress: '0x3c61369ef0D1D2AFa70d8feC2F31C5D6Ce134F30', + tickLensAddress: '0x1acB873Ee909D0c98adB18e4474943249F931b92', + swapRouter02Address: '0x8357227D4eDc78991Db6FDB9bD6ADE250536dE1d', +} + +// Base Sepolia v3 addresses +const BASE_SEPOLIA_ADDRESSES: ChainAddresses = { + v3CoreFactoryAddress: '0x4752ba5DBc23f44D87826276BF6Fd6b1C372aD24', + multicallAddress: '0xd867e273eAbD6c853fCd0Ca0bFB6a3aE6491d2C1', + quoterAddress: '0xC5290058841028F1614F3A6F0F5816cAd0df5E27', + v3MigratorAddress: '0xCbf8b7f80800bd4888Fbc7bf1713B80FE4E23E10', + nonfungiblePositionManagerAddress: '0x27F971cb582BF9E50F397e4d29a5C7A34f11faA2', + tickLensAddress: '0xedf6066a2b290C185783862C7F4776A2C8077AD1', + swapRouter02Address: '0x94cC0AaC535CCDB3C01d6787D6413C739ae12bc4', + + // v4 + v4PoolManagerAddress: '0x05E73354cFDd6745C338b50BcFDfA3Aa6fA03408', + v4PositionManagerAddress: '0x4b2c77d209d3405f41a037ec6c77f7f5b8e2ca80', + v4StateView: '0x571291b572ed32ce6751a2cb2486ebee8defb9b4', + v4QuoterAddress: '0x4a6513c898fe1b2d0e78d3b0e0a4a151589b1cba', +} + +const ZORA_ADDRESSES: ChainAddresses = { + v3CoreFactoryAddress: '0x7145F8aeef1f6510E92164038E1B6F8cB2c42Cbb', + multicallAddress: '0xA51c76bEE6746cB487a7e9312E43e2b8f4A37C15', + quoterAddress: '0x11867e1b3348F3ce4FcC170BC5af3d23E07E64Df', + v3MigratorAddress: '0x048352d8dCF13686982C799da63fA6426a9D0b60', + nonfungiblePositionManagerAddress: '0xbC91e8DfA3fF18De43853372A3d7dfe585137D78', + tickLensAddress: '0x209AAda09D74Ad3B8D0E92910Eaf85D2357e3044', + swapRouter02Address: '0x7De04c96BE5159c3b5CeffC82aa176dc81281557', + + v4PoolManagerAddress: '0x0575338e4c17006ae181b47900a84404247ca30f', + v4PositionManagerAddress: '0xf66c7b99e2040f0d9b326b3b7c152e9663543d63', + v4StateView: '0x385785af07d63b50d0a0ea57c4ff89d06adf7328', + v4QuoterAddress: '0x5edaccc0660e0a2c44b06e07ce8b915e625dc2c6', +} + +const ZORA_SEPOLIA_ADDRESSES: ChainAddresses = { + v3CoreFactoryAddress: '0x4324A677D74764f46f33ED447964252441aA8Db6', + multicallAddress: '0xA1E7e3A69671C4494EC59Dbd442de930a93F911A', + quoterAddress: '0xC195976fEF0985886E37036E2DF62bF371E12Df0', + v3MigratorAddress: '0x65ef259b31bf1d977c37e9434658694267674897', + nonfungiblePositionManagerAddress: '0xB8458EaAe43292e3c1F7994EFd016bd653d23c20', + tickLensAddress: '0x23C0F71877a1Fc4e20A78018f9831365c85f3064', +} + +const ROOTSTOCK_ADDRESSES: ChainAddresses = { + v3CoreFactoryAddress: '0xaF37EC98A00FD63689CF3060BF3B6784E00caD82', + multicallAddress: '0x996a9858cDfa45Ad68E47c9A30a7201E29c6a386', + quoterAddress: '0xb51727c996C68E60F598A923a5006853cd2fEB31', + v3MigratorAddress: '0x16678977CA4ec3DAD5efc7b15780295FE5f56162', + nonfungiblePositionManagerAddress: '0x9d9386c042F194B460Ec424a1e57ACDE25f5C4b1', + tickLensAddress: '0x55B9dF5bF68ADe972191a91980459f48ecA16afC', + swapRouter02Address: '0x0B14ff67f0014046b4b99057Aec4509640b3947A', +} + +const BLAST_ADDRESSES: ChainAddresses = { + v3CoreFactoryAddress: '0x792edAdE80af5fC680d96a2eD80A44247D2Cf6Fd', + multicallAddress: '0xdC7f370de7631cE9e2c2e1DCDA6B3B5744Cf4705', + quoterAddress: '0x6Cdcd65e03c1CEc3730AeeCd45bc140D57A25C77', + v3MigratorAddress: '0x15CA7043CD84C5D21Ae76Ba0A1A967d42c40ecE0', + nonfungiblePositionManagerAddress: '0xB218e4f7cF0533d4696fDfC419A0023D33345F28', + tickLensAddress: '0x2E95185bCdD928a3e984B7e2D6560Ab1b17d7274', + swapRouter02Address: '0x549FEB8c9bd4c12Ad2AB27022dA12492aC452B66', + + v4PoolManagerAddress: '0x1631559198a9e474033433b2958dabc135ab6446', + v4PositionManagerAddress: '0x4ad2f4cca2682cbb5b950d660dd458a1d3f1baad', + v4StateView: '0x12a88ae16f46dce4e8b15368008ab3380885df30', + v4QuoterAddress: '0x6f71cdcb0d119ff72c6eb501abceb576fbf62bcf', +} + +const ZKSYNC_ADDRESSES: ChainAddresses = { + v3CoreFactoryAddress: '0x8FdA5a7a8dCA67BBcDd10F02Fa0649A937215422', + multicallAddress: '0x0c68a7C72f074d1c45C16d41fa74eEbC6D16a65C', + quoterAddress: '0x8Cb537fc92E26d8EBBb760E632c95484b6Ea3e28', + v3MigratorAddress: '0x611841b24E43C4ACfd290B427a3D6cf1A59dac8E', + nonfungiblePositionManagerAddress: '0x0616e5762c1E7Dc3723c50663dF10a162D690a86', + tickLensAddress: '0xe10FF11b809f8EE07b056B452c3B2caa7FE24f89', + swapRouter02Address: '0x99c56385daBCE3E81d8499d0b8d0257aBC07E8A3', +} + +const WORLDCHAIN_ADDRESSES: ChainAddresses = { + v3CoreFactoryAddress: '0x7a5028BDa40e7B173C278C5342087826455ea25a', + multicallAddress: '0x0a22c04215c97E3F532F4eF30e0aD9458792dAB9', + quoterAddress: '0x10158D43e6cc414deE1Bd1eB0EfC6a5cBCfF244c', + v3MigratorAddress: '0x9EBDdCBa71C9027E1eB45135672a30bcFEec9de3', + nonfungiblePositionManagerAddress: '0xec12a9F9a09f50550686363766Cc153D03c27b5e', + tickLensAddress: '0xE61df0CaC9d85876aCE5E3037005D80943570623', + swapRouter02Address: '0x091AD9e2e6e5eD44c1c66dB50e49A601F9f36cF6', + + v4PoolManagerAddress: '0xb1860d529182ac3bc1f51fa2abd56662b7d13f33', + v4PositionManagerAddress: '0xc585e0f504613b5fbf874f21af14c65260fb41fa', + v4StateView: '0x51d394718bc09297262e368c1a481217fdeb71eb', + v4QuoterAddress: '0x55d235b3ff2daf7c3ede0defc9521f1d6fe6c5c0', +} + +const UNICHAIN_SEPOLIA_ADDRESSES: ChainAddresses = { + v3CoreFactoryAddress: '0x1F98431c8aD98523631AE4a59f267346ea31F984', + multicallAddress: '0x9D0F15f2cf58655fDDcD1EE6129C547fDaeD01b1', + quoterAddress: '0x6Dd37329A1A225a6Fca658265D460423DCafBF89', + v3MigratorAddress: '0xb5FA244C9d6D04B2FBac84418b3c4910ED1Ae5f2', + nonfungiblePositionManagerAddress: '0xB7F724d6dDDFd008eFf5cc2834edDE5F9eF0d075', + tickLensAddress: '0x5f739c790a48E97eec0efb81bab5D152c0A0ecA0', + swapRouter02Address: '0xd1AAE39293221B77B0C71fBD6dCb7Ea29Bb5B166', + + v4PoolManagerAddress: '0x00b036b58a818b1bc34d502d3fe730db729e62ac', + v4PositionManagerAddress: '0xf969aee60879c54baaed9f3ed26147db216fd664', + v4StateView: '0xc199f1072a74d4e905aba1a84d9a45e2546b6222', + v4QuoterAddress: '0x56dcd40a3f2d466f48e7f48bdbe5cc9b92ae4472', +} + +const UNICHAIN_ADDRESSES: ChainAddresses = { + v3CoreFactoryAddress: '0x1f98400000000000000000000000000000000003', + multicallAddress: '0xb7610f9b733e7d45184be3a1bc966960ccc54f0b', + quoterAddress: '0x565ac8c7863d9bb16d07e809ff49fe5cd467634c', + v3MigratorAddress: '0xb9d0c246f306b1aaf02ae6ba112d5ef25e5b60dc', + nonfungiblePositionManagerAddress: '0x943e6e07a7e8e791dafc44083e54041d743c46e9', + tickLensAddress: '0xd5d76fa166ab8d8ad4c9f61aaa81457b66cbe443', + swapRouter02Address: '0x73855d06de49d0fe4a9c42636ba96c62da12ff9c', + + v4PoolManagerAddress: '0x1f98400000000000000000000000000000000004', + v4PositionManagerAddress: '0x4529a01c7a0410167c5740c487a8de60232617bf', + v4StateView: '0x86e8631a016f9068c3f085faf484ee3f5fdee8f2', + v4QuoterAddress: '0x333e3c607b141b18ff6de9f258db6e77fe7491e0', +} + +const MONAD_TESTNET_ADDRESSES: ChainAddresses = { + v3CoreFactoryAddress: '0x961235a9020b05c44df1026d956d1f4d78014276', + multicallAddress: '0xa707ceb989cc3728551ed0e6e44b718dd114cf44', + quoterAddress: '0x1ba215c17565de7b0cb7ecab971bcf540c24a862', + v3MigratorAddress: '0x0a78348b71f8ae8caff2f8f9d4d74a2f36516661', + nonfungiblePositionManagerAddress: '0x3dcc735c74f10fe2b9db2bb55c40fbbbf24490f7', + tickLensAddress: '0x337478eb6058455ecb3696184b30dd6a29e3a893', + swapRouter02Address: '0x4c4eabd5fb1d1a7234a48692551eaecff8194ca7', +} + +const MONAD_ADDRESSES: ChainAddresses = { + v3CoreFactoryAddress: '0x204faca1764b154221e35c0d20abb3c525710498', + multicallAddress: '0xd1b797d92d87b688193a2b976efc8d577d204343', + quoterAddress: '0x2d01411773c8c24805306e89a41f7855c3c4fe65', + v3MigratorAddress: '0x7078c4537c04c2b2e52ddba06074dbdacf23ca15', + nonfungiblePositionManagerAddress: '0x7197e214c0b767cfb76fb734ab638e2c192f4e53', + tickLensAddress: '0xf025e0fe9e331a0ef05c2ad3c4e9c64b625cda6f', + swapRouter02Address: '0xfe31f71c1b106eac32f1a19239c9a9a72ddfb900', + // v4 + v4PoolManagerAddress: '0x188d586ddcf52439676ca21a244753fa19f9ea8e', + v4PositionManagerAddress: '0x5b7ec4a94ff9bedb700fb82ab09d5846972f4016', + v4StateView: '0x77395f3b2e73ae90843717371294fa97cc419d64', + v4QuoterAddress: '0xa222dd357a9076d1091ed6aa2e16c9742dd26891', +} + +const SONEIUM_ADDRESSES: ChainAddresses = { + v3CoreFactoryAddress: '0x42ae7ec7ff020412639d443e245d936429fbe717', + multicallAddress: '0x8ad5ef2f2508288d2de66f04dd883ad5f4ef62b2', + quoterAddress: '0x3e6c707d0125226ff60f291b6bd1404634f00aba', + v3MigratorAddress: '0xa107580f73bd797bd8b87ff24e98346d99f93ddb', + nonfungiblePositionManagerAddress: '0x56c1205b0244332011c1e866f4ea5384eb6bfa2c', + tickLensAddress: '0xcd08eefb928c86499e6235ac155906bb7c4dc41a', + swapRouter02Address: '0x7e40db01736f88464e5f4e42394f3d5bbb6705b9', + + v4PoolManagerAddress: '0x360e68faccca8ca495c1b759fd9eee466db9fb32', + v4PositionManagerAddress: '0x1b35d13a2e2528f192637f14b05f0dc0e7deb566', + v4StateView: '0x76fd297e2d437cd7f76d50f01afe6160f86e9990', + v4QuoterAddress: '0x3972c00f7ed4885e145823eb7c655375d275a1c5', +} + +const XLAYER_ADDRESSES: ChainAddresses = { + v3CoreFactoryAddress: '0x4b2ab38dbf28d31d467aa8993f6c2585981d6804', + multicallAddress: '0xe2023f3fa515cf070e07fd9d51c1d236e07843f4', + quoterAddress: '0x976183ac3d09840d243a88c0268badb3b3e3259f', + v3MigratorAddress: '0x7197e214c0b767cfb76fb734ab638e2c192f4e53', + nonfungiblePositionManagerAddress: '0x315e413a11ab0df498ef83873012430ca36638ae', + tickLensAddress: '0x661e93cca42afacb172121ef892830ca3b70f08d', + swapRouter02Address: '0x4f0c28f5926afda16bf2506d5d9e57ea190f9bca', + mixedRouteQuoterV2Address: '0x2d01411773c8c24805306e89a41f7855c3c4fe65', + + v4PoolManagerAddress: '0x360e68faccca8ca495c1b759fd9eee466db9fb32', + v4PositionManagerAddress: '0xcF1EAFC6928dC385A342E7C6491d371d2871458b', + v4StateView: '0x76fd297e2d437cd7f76d50f01afe6160f86e9990', + v4QuoterAddress: '0x8928074ca1b241d8ec02815881c1af11e8bc5219', +} + +const LINEA_ADDRESSES: ChainAddresses = { + v3CoreFactoryAddress: '0x31FAfd4889FA1269F7a13A66eE0fB458f27D72A9', + multicallAddress: '0x93e253D101519578A8DF0BCe2A43D8292BFb3A1F', + quoterAddress: '0x58ead433ea99708604c4dd7c9b7e80c70976e202', + v3MigratorAddress: '0x03a520b32C04BF3bEEf7BEb72E919cf822Ed34f1', + nonfungiblePositionManagerAddress: '0x4615C383F85D0a2BbED973d83ccecf5CB7121463', + tickLensAddress: '0x3334d83e224aF5ef9C2E7DDA7c7C98Efd9621fA9', + swapRouter02Address: '0x3d4e44Eb1374240CE5F1B871ab261CD16335B76a', + mixedRouteQuoterV2Address: '0xe2023f3fa515cf070e07fd9d51c1d236e07843f4', + + v4PoolManagerAddress: '0x248083fb965359d82b06c1f5322480dcfc1ad857', + v4PositionManagerAddress: '0xddcad5775b2816a87495f207731b3571d7ee3c76', + v4StateView: '0xe861de206e460a8b936b05ad3816520b58ccdf9b', + v4QuoterAddress: '0x2c125569c0bee20a66e33e5491c552b37ebd9934', +} + +const TEMPO_ADDRESSES: ChainAddresses = { + v3CoreFactoryAddress: '0x24a3d4757e330890a8b8978028c9e58e04611fd6', + multicallAddress: '0x64eb6294fd6072b2c20d31a54e39d5d3bf69d982', + quoterAddress: '0x53ab5d7a69db158f621b43ee70423da1e1403c2a', + v3MigratorAddress: '0x2352328bd3313549d6d908646c82c2b7136901a9', + nonfungiblePositionManagerAddress: '0xb71c33f096ceabdc0229110e0d76a6382d01c633', + tickLensAddress: '0x95cb27f323a03b03528096a527ee75704db28ef5', + swapRouter02Address: '0x7e9d53081e961201837336bcd81f52ae92691a8f', + mixedRouteQuoterV2Address: '0x741abcaeb95da1b0766c8db7819bb6c4fed27e3d', + + v4PoolManagerAddress: '0x33620f62c5b9b2086dd6b62f4a297a9f30347029', + v4PositionManagerAddress: '0x3fc79444f8eacc1894775493ff3fa41f1e35ce11', + v4StateView: '0x21b954fba3f5ddebe77ef2d47a3100c066908b2a', + v4QuoterAddress: '0x20e6487c371a2086f841ef453f85378223df4f4e', +} + +const MEGAETH_ADDRESSES: ChainAddresses = { + v3CoreFactoryAddress: '0x3a5f0cd7d62452b7f899b2a5758bfa57be0de478', + multicallAddress: '0x61f3272a3619d9f20788c6822fed2e5471bfc477', + quoterAddress: '0x5affda77bc34d945f9632bd080ebfcf24133b90e', + v3MigratorAddress: '0xed30f6c25fe915dc710f168fa3ab66199ee84454', + nonfungiblePositionManagerAddress: '0xcdc86e98184e96436f733a8bf31bd4f0214e6d7d', + tickLensAddress: '0xe7a2d824722addcb21e7a203ae7b372bf3a29ec5', + swapRouter02Address: '0x48020de9208bafc183f5cad5118ffbe8f0f913f5', + mixedRouteQuoterV2Address: '0x1768d0b0f8ee6638986aab8f775ceb87c45f8730', + + v4PoolManagerAddress: '0xacb7e78fa05d562e0a5d3089ec896d57d057d38e', + v4PositionManagerAddress: '0x9ae0921e981aaa7308f176f8d4f9129b9247c89d', + v4StateView: '0x726f84e1dfb8d375a365e0808282f40d52d3e4e8', + v4QuoterAddress: '0x94bdc671f0c35f44a1daa53143fd1f868d1623b9', +} + +const ARC_ADDRESSES: ChainAddresses = { + v3CoreFactoryAddress: '0xf0db7b58379503491d857db50ac9ece64c653918', + multicallAddress: '0x33e885ed0ec9bf04ecfb19341582aadcb4c8a9e7', + quoterAddress: '0x7dfd4f31be6814d2906bde155c3e1b146eac1468', + nonfungiblePositionManagerAddress: '0x39654a85a4c05127f5fd6ed22caec077a0fb1377', + tickLensAddress: '0x9eb8600665b55d10c1eb2316ca5127a9ca6e2e76', + swapRouter02Address: '0x53bf6b0684ec7ef91e1387da3d1a1769bc5a6f77', + + v4PoolManagerAddress: '0x8366a39cc670b4001a1121b8f6a443a643e40951', + v4PositionManagerAddress: '0x6049c9a0e26405c0985f9e3685c87d0ae917f82b', + v4StateView: '0xf3334192d15450cdd385c8b70e03f9a6bd9e673b', + v4QuoterAddress: '0x8dc178efb8111bb0973dd9d722ebeff267c98f94', +} + +const ROBINHOOD_ADDRESSES: ChainAddresses = { + v3CoreFactoryAddress: '0x1f7d7550b1b028f7571e69a784071f0205fd2efa', + multicallAddress: '0x282a3c4d320cc7f0d5eaf56b8029e4b88338f0a3', + quoterAddress: '0x33e885ed0ec9bf04ecfb19341582aadcb4c8a9e7', + nonfungiblePositionManagerAddress: '0x73991a25c818bf1f1128deaab1492d45638de0d3', + tickLensAddress: '0x7dfd4f31be6814d2906bde155c3e1b146eac1468', + swapRouter02Address: '0xcaf681a66d020601342297493863e78c959e5cb2', + + v4PoolManagerAddress: '0x8366a39cc670b4001a1121b8f6a443a643e40951', + v4PositionManagerAddress: '0x58daec3116aae6d93017baaea7749052e8a04fa7', + v4StateView: '0xf3334192d15450cdd385c8b70e03f9a6bd9e673b', + v4QuoterAddress: '0x8dc178efb8111bb0973dd9d722ebeff267c98f94', +} + +const INK_ADDRESSES: ChainAddresses = { + v3CoreFactoryAddress: '0x640887a9ba3a9c53ed27d0f7e8246a4f933f3424', + multicallAddress: '0xa0fcec583aee6176527c07b198e5561722332014', + quoterAddress: '0x96b572d2d880cf2fa2563651bd23ade6f5516652', + nonfungiblePositionManagerAddress: '0xc0836e5b058bbe22ae2266e1ac488a1a0fd8dce8', + tickLensAddress: '0x3e6dba802d62aba2361dd632fbc9f547aa6789ae', + swapRouter02Address: '0x177778f19e89dd1012bdbe603f144088a95c4b53', + mixedRouteQuoterV2Address: '0x1f7d7550b1b028f7571e69a784071f0205fd2efa', + + v4PoolManagerAddress: '0x360e68faccca8ca495c1b759fd9eee466db9fb32', + v4PositionManagerAddress: '0x1b35d13a2e2528f192637f14b05f0dc0e7deb566', + v4StateView: '0x76fd297e2d437cd7f76d50f01afe6160f86e9990', + v4QuoterAddress: '0x3972c00f7ed4885e145823eb7c655375d275a1c5', + permissionedV4PositionManagerAddress: '0x003aa18c6E682dB80Cf4aa17261CcbFfd28690CE', + permissionedV4HooksAddress: '0x3c5903cEa9F15e1e59758c8f9267d39C16ea28c0', +} + +export const CHAIN_TO_ADDRESSES_MAP: Record = { + [ChainId.MAINNET]: MAINNET_ADDRESSES, + [ChainId.OPTIMISM]: OPTIMISM_ADDRESSES, + [ChainId.ARBITRUM_ONE]: ARBITRUM_ONE_ADDRESSES, + [ChainId.POLYGON]: POLYGON_ADDRESSES, + [ChainId.POLYGON_MUMBAI]: POLYGON_ADDRESSES, + [ChainId.GOERLI]: GOERLI_ADDRESSES, + [ChainId.CELO]: CELO_ADDRESSES, + [ChainId.CELO_ALFAJORES]: CELO_ADDRESSES, + [ChainId.BNB]: BNB_ADDRESSES, + [ChainId.OPTIMISM_GOERLI]: OPTIMISM_GOERLI_ADDRESSES, + [ChainId.OPTIMISM_SEPOLIA]: OPTIMISM_SEPOLIA_ADDRESSES, + [ChainId.ARBITRUM_GOERLI]: ARBITRUM_GOERLI_ADDRESSES, + [ChainId.ARBITRUM_SEPOLIA]: ARBITRUM_SEPOLIA_ADDRESSES, + [ChainId.SEPOLIA]: SEPOLIA_ADDRESSES, + [ChainId.AVALANCHE]: AVALANCHE_ADDRESSES, + [ChainId.BASE]: BASE_ADDRESSES, + [ChainId.BASE_GOERLI]: BASE_GOERLI_ADDRESSES, + [ChainId.BASE_SEPOLIA]: BASE_SEPOLIA_ADDRESSES, + [ChainId.ZORA]: ZORA_ADDRESSES, + [ChainId.ZORA_SEPOLIA]: ZORA_SEPOLIA_ADDRESSES, + [ChainId.ROOTSTOCK]: ROOTSTOCK_ADDRESSES, + [ChainId.BLAST]: BLAST_ADDRESSES, + [ChainId.ZKSYNC]: ZKSYNC_ADDRESSES, + [ChainId.WORLDCHAIN]: WORLDCHAIN_ADDRESSES, + [ChainId.UNICHAIN_SEPOLIA]: UNICHAIN_SEPOLIA_ADDRESSES, + [ChainId.UNICHAIN]: UNICHAIN_ADDRESSES, + [ChainId.MONAD_TESTNET]: MONAD_TESTNET_ADDRESSES, + [ChainId.SONEIUM]: SONEIUM_ADDRESSES, + [ChainId.MONAD]: MONAD_ADDRESSES, + [ChainId.XLAYER]: XLAYER_ADDRESSES, + [ChainId.LINEA]: LINEA_ADDRESSES, + [ChainId.TEMPO]: TEMPO_ADDRESSES, + [ChainId.MEGAETH]: MEGAETH_ADDRESSES, + [ChainId.ARC]: ARC_ADDRESSES, + [ChainId.ROBINHOOD]: ROBINHOOD_ADDRESSES, + [ChainId.INK]: INK_ADDRESSES, +} + +/* V3 Contract Addresses */ +export const V3_CORE_FACTORY_ADDRESSES: AddressMap = { + ...SUPPORTED_CHAINS.reduce((memo, chainId) => { + memo[chainId] = CHAIN_TO_ADDRESSES_MAP[chainId].v3CoreFactoryAddress + return memo + }, {}), +} + +export const V3_MIGRATOR_ADDRESSES: AddressMap = { + ...SUPPORTED_CHAINS.reduce((memo, chainId) => { + const v3MigratorAddress = CHAIN_TO_ADDRESSES_MAP[chainId].v3MigratorAddress + if (v3MigratorAddress) { + memo[chainId] = v3MigratorAddress + } + return memo + }, {}), +} + +export const MULTICALL_ADDRESSES: AddressMap = { + ...SUPPORTED_CHAINS.reduce((memo, chainId) => { + memo[chainId] = CHAIN_TO_ADDRESSES_MAP[chainId].multicallAddress + return memo + }, {}), +} + +/** + * The oldest V0 governance address + */ +export const GOVERNANCE_ALPHA_V0_ADDRESSES: AddressMap = constructSameAddressMap( + '0x5e4be8Bc9637f0EAA1A755019e06A68ce081D58F' +) +/** + * The older V1 governance address + */ +export const GOVERNANCE_ALPHA_V1_ADDRESSES: AddressMap = { + [ChainId.MAINNET]: '0xC4e172459f1E7939D522503B81AFAaC1014CE6F6', +} +/** + * The latest governor bravo that is currently admin of timelock + */ +export const GOVERNANCE_BRAVO_ADDRESSES: AddressMap = { + [ChainId.MAINNET]: '0x408ED6354d4973f66138C91495F2f2FCbd8724C3', +} + +export const TIMELOCK_ADDRESSES: AddressMap = constructSameAddressMap('0x1a9C8182C09F50C8318d769245beA52c32BE35BC') + +export const MERKLE_DISTRIBUTOR_ADDRESS: AddressMap = { + [ChainId.MAINNET]: '0x090D4613473dEE047c3f2706764f49E0821D256e', +} + +export const ARGENT_WALLET_DETECTOR_ADDRESS: AddressMap = { + [ChainId.MAINNET]: '0xeca4B0bDBf7c55E9b7925919d03CbF8Dc82537E8', +} + +export const QUOTER_ADDRESSES: AddressMap = { + ...SUPPORTED_CHAINS.reduce((memo, chainId) => { + memo[chainId] = CHAIN_TO_ADDRESSES_MAP[chainId].quoterAddress + return memo + }, {}), +} + +export const NONFUNGIBLE_POSITION_MANAGER_ADDRESSES: AddressMap = { + ...SUPPORTED_CHAINS.reduce((memo, chainId) => { + const nonfungiblePositionManagerAddress = CHAIN_TO_ADDRESSES_MAP[chainId].nonfungiblePositionManagerAddress + if (nonfungiblePositionManagerAddress) { + memo[chainId] = nonfungiblePositionManagerAddress + } + return memo + }, {}), +} + +export const ENS_REGISTRAR_ADDRESSES: AddressMap = { + ...constructSameAddressMap('0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e'), +} + +export const SOCKS_CONTROLLER_ADDRESSES: AddressMap = { + [ChainId.MAINNET]: '0x65770b5283117639760beA3F867b69b3697a91dd', +} + +export const TICK_LENS_ADDRESSES: AddressMap = { + ...SUPPORTED_CHAINS.reduce((memo, chainId) => { + const tickLensAddress = CHAIN_TO_ADDRESSES_MAP[chainId].tickLensAddress + if (tickLensAddress) { + memo[chainId] = tickLensAddress + } + return memo + }, {}), +} + +export const MIXED_ROUTE_QUOTER_V1_ADDRESSES: AddressMap = SUPPORTED_CHAINS.reduce((memo, chainId) => { + const mixedRouteQuoterV1Address = CHAIN_TO_ADDRESSES_MAP[chainId].mixedRouteQuoterV1Address + if (mixedRouteQuoterV1Address) { + memo[chainId] = mixedRouteQuoterV1Address + } + return memo +}, {}) + +export const SWAP_ROUTER_02_ADDRESSES = (chainId: number) => { + if (SUPPORTED_CHAINS.includes(chainId)) { + const id = chainId as SupportedChainsType + return CHAIN_TO_ADDRESSES_MAP[id].swapRouter02Address ?? '0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45' + } + return '' +} diff --git a/plan/agw/research/preset-catalog-2026-10-15/bsctestnet_addresses.json b/plan/agw/research/preset-catalog-2026-10-15/bsctestnet_addresses.json new file mode 100644 index 00000000..4dad5437 --- /dev/null +++ b/plan/agw/research/preset-catalog-2026-10-15/bsctestnet_addresses.json @@ -0,0 +1,257 @@ +{ + "name": "bsctestnet", + "chainId": "97", + "addresses": { + "AccessControlManagerMockTest": "0x4eA05Cb383a258212C46D19299d6e7F14D79fDEC", + "BTCB": "0xA808e341e8e723DC6BA0Bb5204Bafc2330d7B8e4", + "BUSD": "0x8301F2213c0eeD49a7E28Ae4c3e91722919B8B47", + "CheckpointView_From_JumpRateModel_base0bps_slope1000bps_jump10900bps_kink8000bps_bpy21024000_To_bpy42048000_At_1748243100": "0x137352dC1d46746Bdea02b29911bfE4144A7391F", + "CheckpointView_From_JumpRateModel_base0bps_slope1000bps_jump10900bps_kink8000bps_bpy42048000_To_bpy70080000_At_1762741500": "0xd32721dfF0C69C52C14b14205784C4A4E1F223cc", + "CheckpointView_From_JumpRateModel_base0bps_slope1000bps_jump20000bps_kink7500bps_bpy10512000_To_bpy21024000_At_1744097580": "0x962edf115d24240930f7B1CF95EaEC9E49f06F92", + "CheckpointView_From_JumpRateModel_base0bps_slope1000bps_jump20000bps_kink7500bps_bpy21024000_To_bpy42048000_At_1748243100": "0x447512e07C6aad8D356174Adf88645E54480697D", + "CheckpointView_From_JumpRateModel_base0bps_slope1000bps_jump20000bps_kink7500bps_bpy42048000_To_bpy70080000_At_1762741500": "0x8273779013E74DF618faddc28e2eE770A6372874", + "CheckpointView_From_JumpRateModel_base0bps_slope1000bps_jump25000bps_kink8000bps_bpy10512000_To_bpy21024000_At_1744097580": "0xa5f1d44f7D2Ea604aAEba6eEd438E07C31Ee1dd2", + "CheckpointView_From_JumpRateModel_base0bps_slope1000bps_jump25000bps_kink8000bps_bpy21024000_To_bpy42048000_At_1748243100": "0x798Ac25e651734781d9fF2816A1E1A8dD1Ec5a4e", + "CheckpointView_From_JumpRateModel_base0bps_slope1000bps_jump25000bps_kink8000bps_bpy42048000_To_bpy70080000_At_1762741500": "0x2B12Fe8267b6742Dd1Cd02A6f91E6f333eE641b6", + "CheckpointView_From_JumpRateModel_base0bps_slope2000bps_jump30000bps_kink5000bps_bpy10512000_To_bpy21024000_At_1744097580": "0x9657300eEa812f2920f416cE4008713690253716", + "CheckpointView_From_JumpRateModel_base0bps_slope2000bps_jump30000bps_kink5000bps_bpy21024000_To_bpy42048000_At_1748243100": "0xdB49a057ab4a3D402ABe31b58a04EE04000025f7", + "CheckpointView_From_JumpRateModel_base0bps_slope2000bps_jump30000bps_kink5000bps_bpy42048000_To_bpy70080000_At_1762741500": "0x8BFC2afD0b0AC204Fd9e06103eF9e1b66c057723", + "CheckpointView_From_JumpRateModel_base0bps_slope500bps_jump10900bps_kink8000bps_bpy10512000_To_bpy21024000_At_1744097580": "0xdE06A850D42dcff216e1EfCa5358cB167Da247ca", + "CheckpointView_From_JumpRateModel_base0bps_slope500bps_jump5000bps_kink8000bps_bpy10512000_To_bpy21024000_At_1744097580": "0x3985fd3fa7975BB08c962797640A84297fDbe262", + "CheckpointView_From_JumpRateModel_base0bps_slope500bps_jump5000bps_kink8000bps_bpy21024000_To_bpy42048000_At_1748243100": "0x3D1c435930b52B197a5861E8F9F62509445434fC", + "CheckpointView_From_JumpRateModel_base0bps_slope500bps_jump5000bps_kink8000bps_bpy42048000_To_bpy70080000_At_1762741500": "0x04Cdb7DC0a6ed631DF5e7926622bDBDF2543cd3F", + "CheckpointView_From_JumpRateModel_base0bps_slope687bps_jump25000bps_kink8000bps_bpy10512000_To_bpy21024000_At_1744097580": "0x2182450eC9780F17511FeAcE6FC3ED8F774157b3", + "CheckpointView_From_JumpRateModel_base0bps_slope750bps_jump5000bps_kink8000bps_bpy10512000_To_bpy21024000_At_1744097580": "0x24B5bDe69D8e4280a30e1dAbB2f8B0152c30228c", + "CheckpointView_From_JumpRateModel_base0bps_slope750bps_jump5000bps_kink8000bps_bpy21024000_To_bpy42048000_At_1748243100": "0xB83Ec5A6994ED5779815c7aC3f9668160a210cae", + "CheckpointView_From_JumpRateModel_base0bps_slope750bps_jump5000bps_kink8000bps_bpy42048000_To_bpy70080000_At_1762741500": "0x60386490E654d5529eD1cb6146bFcec08B9a3876", + "CheckpointView_From_JumpRateModel_base0bps_slope900bps_jump20000bps_kink5000bps_bpy10512000_To_bpy21024000_At_1744097580": "0x8f63Ca20A6F0805F44d56Afb4B32520488218540", + "CheckpointView_From_JumpRateModel_base0bps_slope900bps_jump20000bps_kink5000bps_bpy21024000_To_bpy42048000_At_1748243100": "0xCf744EF5472951Cda24283348E62CE86B2C53235", + "CheckpointView_From_JumpRateModel_base0bps_slope900bps_jump20000bps_kink5000bps_bpy42048000_To_bpy70080000_At_1762741500": "0x8734dBD8Ba959BbC75f2701a022f8d1D47e0722d", + "CheckpointView_From_JumpRateModel_base0bps_slope900bps_jump35000bps_kink4500bps_bpy10512000_To_bpy21024000_At_1744097580": "0x6D95fcD7f086a6EA2e0f1B057c1fbddC1c18C146", + "CheckpointView_From_JumpRateModel_base0bps_slope900bps_jump35000bps_kink4500bps_bpy21024000_To_bpy42048000_At_1748243100": "0x2612eA702d1d87CA31EF189492C4924Ee8174CB9", + "CheckpointView_From_JumpRateModel_base0bps_slope900bps_jump35000bps_kink4500bps_bpy42048000_To_bpy70080000_At_1762741500": "0x3B7BE12BE569c8D2F451B441f14b4576f4489D49", + "CheckpointView_From_JumpRateModel_base200bps_slope1500bps_jump30000bps_kink6000bps_bpy10512000_To_bpy21024000_At_1744097580": "0x253B09357D5D1CDE57dB6356cDE77cD0bd963a09", + "CheckpointView_From_JumpRateModel_base200bps_slope1500bps_jump30000bps_kink6000bps_bpy21024000_To_bpy42048000_At_1748243100": "0x429D0a66DA5E785155B66842447d0Bb4Ee6930e8", + "CheckpointView_From_JumpRateModel_base200bps_slope1500bps_jump30000bps_kink6000bps_bpy42048000_To_bpy70080000_At_1762741500": "0x53C22998e06A3Bc4DC859ee5e234173f4CC30976", + "CheckpointView_From_JumpRateModel_base200bps_slope2000bps_jump30000bps_kink5000bps_bpy10512000_To_bpy21024000_At_1744097580": "0x93ad9750cA2F89984EE6790A7cEcc4Aa9C07CfeC", + "CheckpointView_From_JumpRateModel_base200bps_slope2000bps_jump30000bps_kink5000bps_bpy21024000_To_bpy42048000_At_1748243100": "0xA3244E4719b96E8930aaF24d7D98b77a79131454", + "CheckpointView_From_JumpRateModel_base200bps_slope2000bps_jump30000bps_kink5000bps_bpy42048000_To_bpy70080000_At_1762741500": "0xbD99C5f21C457BBe11F79151e949fDBD1990273d", + "CheckpointView_From_TwoKinks_base0bps_slope1000bps_kink8000bps_slope27000bps_base20bps_kink29000bps_jump30000bps_bpy21024000_To_bpy42048000_At_1748243100": "0x6B31cBD9636496B8FcfFac2EDBDaC28162B35890", + "CheckpointView_From_TwoKinks_base0bps_slope1000bps_kink8000bps_slope27000bps_base20bps_kink29000bps_jump30000bps_bpy42048000_To_bpy70080000_At_1762741500": "0xa1D93E797bbf70Bd2296B394D21eb4B341CdEcA9", + "CheckpointView_From_TwoKinks_base0bps_slope350bps_kink8000bps_slope217500bps_base20bps_kink29000bps_jump30000bps_bpy10512000_To_bpy21024000_At_1744097580": "0x4FAE14f71c3ee15635d7161292eC5F1F09f70Ad7", + "CheckpointView_From_TwoKinks_base0bps_slope350bps_kink8000bps_slope217500bps_base20bps_kink29000bps_jump30000bps_bpy21024000_To_bpy42048000_At_1748243100": "0x4D387015542262057b2ddb3d117aC4eFA24ea563", + "CheckpointView_From_TwoKinks_base0bps_slope350bps_kink8000bps_slope217500bps_base20bps_kink29000bps_jump30000bps_bpy42048000_To_bpy70080000_At_1762741500": "0x5c764D2E220C210C872c0d6224b55FBb8287c53c", + "CheckpointView_From_TwoKinks_base0bps_slope450bps_kink7000bps_slope214000bps_base20bps_kink28000bps_jump30000bps_bpy42048000_To_bpy70080000_At_1762741500": "0x51B17Dd2DF3934a579c59D875BAC643e8a72Ce74", + "CheckpointView_From_WhitePaperInterestRateModel_base0bps_slope10000bps_bpy10512000_To_bpy21024000_At_1744097580": "0x9c2666E33aee517975D61e573DbF5b829c342c03", + "CheckpointView_From_WhitePaperInterestRateModel_base0bps_slope10000bps_bpy21024000_To_bpy42048000_At_1748243100": "0xa6EE5513d4bC1F4541e5a98A09eF808F4f9e7477", + "CheckpointView_From_WhitePaperInterestRateModel_base0bps_slope10000bps_bpy42048000_To_bpy70080000_At_1762741500": "0xA8694CA042F8038Dcd4c6104b8574841226050A2", + "CheckpointView_From_WhitePaperInterestRateModel_base200bps_slope1000bps_bpy10512000_To_bpy21024000_At_1744097580": "0xc8dC4a0a29e2423664556a31349Da3FF26850e8D", + "CheckpointView_From_WhitePaperInterestRateModel_base200bps_slope1000bps_bpy21024000_To_bpy42048000_At_1748243100": "0x0F8F7633AdBea7025107421A5FBe354219B33FaF", + "CheckpointView_From_WhitePaperInterestRateModel_base200bps_slope1000bps_bpy42048000_To_bpy70080000_At_1762741500": "0x4048c69928993023eD5D3fA9Da8708FfB4a21fe8", + "ComptrollerLens": "0x0Dab769617B2d690DDbe8A6D730D9C9b85F26ca0", + "DefaultProxyAdmin": "0x7877ffd62649b6a1557b55d4c20fcbab17344c91", + "ETH": "0x98f7A83361F7Ac8765CcEBAB1425da6b341958a7", + "FlashLoanFacet": "0x528A428748dfE73DFcc844176B401475D1831057", + "JumpRateModel_base0bps_slope1000bps_jump10900bps_kink8000bps_bpy21024000": "0xb1993AA3E9ee53D37096C58a4B86A8B1B6ED2F8e", + "JumpRateModel_base0bps_slope1000bps_jump10900bps_kink8000bps_bpy42048000": "0x18A31286b462345A21Eb467c67e1C6282fa8E852", + "JumpRateModel_base0bps_slope1000bps_jump10900bps_kink8000bps_bpy70080000": "0x66d8Ac8ef8C5A46909343be425b3Ed1C8b9c9373", + "JumpRateModel_base0bps_slope1000bps_jump20000bps_kink7500bps_bpy10512000": "0xebb0B3Ca7c4095b1392C75e96f8Dc565c9047FAa", + "JumpRateModel_base0bps_slope1000bps_jump20000bps_kink7500bps_bpy21024000": "0x20Da556A8cd887Ff3AB1AD84f4645c8F2413D884", + "JumpRateModel_base0bps_slope1000bps_jump20000bps_kink7500bps_bpy42048000": "0xb889f359Ab4eD32EEa9E4E78D6e9f44655449c95", + "JumpRateModel_base0bps_slope1000bps_jump20000bps_kink7500bps_bpy70080000": "0xD1e35044F9624497b08360CBa77a174B148e93eD", + "JumpRateModel_base0bps_slope1000bps_jump25000bps_kink8000bps_bpy10512000": "0x4348FC0CBD4ab6E46311ef90ba706169e50fC804", + "JumpRateModel_base0bps_slope1000bps_jump25000bps_kink8000bps_bpy21024000": "0xaE81cA4E6eA7f7E72165dc68dBa2A0B1465E3B1f", + "JumpRateModel_base0bps_slope1000bps_jump25000bps_kink8000bps_bpy42048000": "0x0acdc336EA232E4C31D91FCb9B93b10921A3fCEF", + "JumpRateModel_base0bps_slope1000bps_jump25000bps_kink8000bps_bpy70080000": "0xf621b106020031fDa4b8920B26ea82F724A992eB", + "JumpRateModel_base0bps_slope2000bps_jump30000bps_kink5000bps_bpy10512000": "0x40e5d89ca4FED67F4C48A4eA5fe40bC1a1af1726", + "JumpRateModel_base0bps_slope2000bps_jump30000bps_kink5000bps_bpy21024000": "0x72c341Ed005c84446acB280059F44974Ba51F39a", + "JumpRateModel_base0bps_slope2000bps_jump30000bps_kink5000bps_bpy42048000": "0x59a76C684385Cf27d0BE0e2Bcec2012A88622C68", + "JumpRateModel_base0bps_slope2000bps_jump30000bps_kink5000bps_bpy70080000": "0xf40E0e047e24825740D18e435F533d75a4A2e9f9", + "JumpRateModel_base0bps_slope200bps_jump400bps_kink8000bps_bpy70080000": "0x08a2F4387BcAe9776243dF1f5BFfb6Ea2bE9c7dD", + "JumpRateModel_base0bps_slope500bps_jump10900bps_kink8000bps_bpy10512000": "0xB200dBd23cff696Cf2E95C0FbccDd3AF7814c00F", + "JumpRateModel_base0bps_slope500bps_jump10900bps_kink8000bps_bpy21024000": "0xe33B7a74Db5F6CEb0FB5cA9c03D4E6521b46D0B0", + "JumpRateModel_base0bps_slope500bps_jump5000bps_kink8000bps_bpy10512000": "0xfB14Dd85A26e41E4fD62b3B142b17f279c7Bb8B0", + "JumpRateModel_base0bps_slope500bps_jump5000bps_kink8000bps_bpy21024000": "0x7cBA76eB5A9A89E7179bCf3c71875706e0c8Af2e", + "JumpRateModel_base0bps_slope500bps_jump5000bps_kink8000bps_bpy42048000": "0xA313F761cc79Fb8C27D0f5d35b88DB7075A61653", + "JumpRateModel_base0bps_slope500bps_jump5000bps_kink8000bps_bpy70080000": "0x4B22c785101401e6EB906F5C10548A6Cf6A059f4", + "JumpRateModel_base0bps_slope667bps_jump62700bps_kink7500bps_bpy70080000": "0x1CcDaf39085bae4e27c3Ba100561b1AD1B5A6b80", + "JumpRateModel_base0bps_slope687bps_jump25000bps_kink8000bps_bpy10512000": "0xf59B7f2733a549dCF82b804d69d9c6a38985B90B", + "JumpRateModel_base0bps_slope687bps_jump25000bps_kink8000bps_bpy21024000": "0x5E68358e77673A6E17b1C7dE1C519a070033b698", + "JumpRateModel_base0bps_slope750bps_jump5000bps_kink8000bps_bpy10512000": "0x37bD1aFb1E9965FB9a229f85f71f8bEB5afdA91C", + "JumpRateModel_base0bps_slope750bps_jump5000bps_kink8000bps_bpy21024000": "0x12a1Be021756cd66CdA146b7485c00Baf6Ff63F9", + "JumpRateModel_base0bps_slope750bps_jump5000bps_kink8000bps_bpy42048000": "0x0f5F4e273335A605d478F0a4B75AF2e16D037b00", + "JumpRateModel_base0bps_slope750bps_jump5000bps_kink8000bps_bpy70080000": "0x92336573c47a55F2E418bf5452B00832b3bF2855", + "JumpRateModel_base0bps_slope900bps_jump20000bps_kink5000bps_bpy10512000": "0x12b88631a2033c0e9afA36b295cdFCf49493E89e", + "JumpRateModel_base0bps_slope900bps_jump20000bps_kink5000bps_bpy21024000": "0xE0d3774406296322f42CBf25e96e8388cDAf0A66", + "JumpRateModel_base0bps_slope900bps_jump20000bps_kink5000bps_bpy42048000": "0x2aFDF0f2377158cD45C12f4a5c70269baF15fcc5", + "JumpRateModel_base0bps_slope900bps_jump20000bps_kink5000bps_bpy70080000": "0x274362695401Bb1B0468BfcFE448AD7021D97562", + "JumpRateModel_base0bps_slope900bps_jump35000bps_kink4500bps_bpy10512000": "0xBbA0DEC733d5217A14B934710Cf07F070BA6c01e", + "JumpRateModel_base0bps_slope900bps_jump35000bps_kink4500bps_bpy21024000": "0xfC5538BDb73548127b392e9dFA420fdFdaF9438B", + "JumpRateModel_base0bps_slope900bps_jump35000bps_kink4500bps_bpy42048000": "0x0Cf272DBF1691271b9f56a3CDb8e574C8B5AD387", + "JumpRateModel_base0bps_slope900bps_jump35000bps_kink4500bps_bpy70080000": "0x8a637EB581150D1C0d8f8A2036D790c9a94803E6", + "JumpRateModel_base200bps_slope1500bps_jump30000bps_kink6000bps_bpy10512000": "0xf334E44BA510079833EcC8eb00fD5Bd26d8048F5", + "JumpRateModel_base200bps_slope1500bps_jump30000bps_kink6000bps_bpy21024000": "0x4b7c161640ee88307f6e544f60F7523e6Ee1cca9", + "JumpRateModel_base200bps_slope1500bps_jump30000bps_kink6000bps_bpy42048000": "0xfB778F06cafA439825cAd4095f31e83740eC7364", + "JumpRateModel_base200bps_slope1500bps_jump30000bps_kink6000bps_bpy70080000": "0x16e0d26D08eeb3CEdF7991C5525f2d202bEcF797", + "JumpRateModel_base200bps_slope2000bps_jump30000bps_kink5000bps_bpy10512000": "0xF1A8B40CA68d08EFfa31a16a83f4fd9b5c174872", + "JumpRateModel_base200bps_slope2000bps_jump30000bps_kink5000bps_bpy21024000": "0x0122b6aE004b90f080587b8921Ea32Fd1F2AFa11", + "JumpRateModel_base200bps_slope2000bps_jump30000bps_kink5000bps_bpy42048000": "0xE3087584EA86dc9eAe6DfcFd68BCAb69BC0D728A", + "JumpRateModel_base200bps_slope2000bps_jump30000bps_kink5000bps_bpy70080000": "0xb8dB7D937D32C111Ddc89af962A8a3e3E2A51Ac2", + "LTC": "0x969F147B6b8D81f86175de33206A4FD43dF17913", + "Liquidator": "0x55AEABa76ecf144031Ef64E222166eb28Cb4865F", + "Liquidator_Implementation": "0x56E364C3e5A556479e08b671A3d35eF4168d632f", + "Liquidator_Proxy": "0x55AEABa76ecf144031Ef64E222166eb28Cb4865F", + "MarketFacet": "0x3372D6aeb32aa6AB0933127ac9194E8915172752", + "MockFDUSD": "0xcF27439fA231af9931ee40c4f27Bb77B83826F3C", + "MockNVDAB": "0x8A7d8589A597619A7842d3BC284b9a5a276FaE56", + "MockPT-USDe-30OCT2025": "0x0c98334aCF440b9936D9cc1d99dc1A77bf26a93B", + "MockPT-clisBNB-25JUN2026": "0x60825e8eBbed5C32c1DAA7eA68ceCA70BEA65040", + "MockPT-sUSDE-26JUN2025": "0x95e58161BA2423c3034658d957F3f5b94DeAbf81", + "MockSKHYB": "0xb52DE23C6D4be6Bb3E87fF64527E856Ab346FDf2", + "MockSOL": "0xC337Dd0390FdFD0Ee5D2b682E425986EDD7b59da", + "MockSPCXB": "0x6D9e91cB766259af42619c14c994E694E57e6E85", + "MockSolvBTC": "0x6855E14A6df91b8E4D55163d068E9ef2530fd4CE", + "MockTHE": "0x952653d23cB9bef19E442D2BF8fBc8843A968052", + "MockTSLAB": "0x10d63B1203E5A0719AbbE927C8BFc87135b2F129", + "MockU": "0x180Bc1a9843A65D4116e44886FD3558515a56A49", + "MockUSD1": "0x7792af341a10ccc4B1CDd7B317F0460a37346a0A", + "MockUSDe": "0x986C30591f5aAb401ea3aa63aFA595608721B1B9", + "MockXAUM": "0xd2e2575c24302C82d38A9079c85722e0D0C0D2cD", + "MocksUSDe": "0xcFec590e417Abb378cfEfE6296829E35fa25cEbd", + "MockxSolvBTC": "0x3ea87323806586A0282b50377e0FEa76070F532B", + "PegStability_USDT": "0xB21E69eef4Bc1D64903fa28D9b32491B1c0786F1", + "PegStability_USDT_Implementation": "0xDDa903294fB71141302aD3Bf2AF37dD6Cbd5DBbF", + "PegStability_USDT_Proxy": "0xB21E69eef4Bc1D64903fa28D9b32491B1c0786F1", + "PolicyFacet": "0x808746E246393a98209990844951826D67da970A", + "Prime": "0xe840F8EC2Dc50E7D22e5e2991975b9F6e34b62Ad", + "PrimeLeaderboard": "0x1a4408613eec291f2d338F7A88E9D550fa9cD8dC", + "PrimeLeaderboard_Implementation": "0x3f4869b098E6a781e86475eF5C79888F266ec257", + "PrimeLeaderboard_Proxy": "0x1a4408613eec291f2d338F7A88E9D550fa9cD8dC", + "PrimeLens": "0x13b3C3442e5fD642bc31D34db43d547E8C4322f7", + "PrimeLiquidityProvider": "0xAdeddc73eAFCbed174e6C400165b111b0cb80B7E", + "PrimeLiquidityProviderTest": "0x7a780FbBa026568025a82101De65863A94CcD8f7", + "PrimeLiquidityProviderTest_Implementation": "0x9Ac449Fe41e67E5161C01d9366f655a8A7406A76", + "PrimeLiquidityProviderTest_Proxy": "0x7a780FbBa026568025a82101De65863A94CcD8f7", + "PrimeLiquidityProvider_Implementation": "0xbc85D7c9F7BdB348bd31d726ADa716d7efAEaBfB", + "PrimeLiquidityProvider_Proxy": "0xAdeddc73eAFCbed174e6C400165b111b0cb80B7E", + "PrimeV2": "0xeC22366d2572e52BCB29B50C905b945BA421B9b2", + "PrimeV2_Implementation": "0x9Ab9dA79df616a4b55B1f9c9994d582D6865aB08", + "PrimeV2_Proxy": "0xeC22366d2572e52BCB29B50C905b945BA421B9b2", + "Prime_Implementation": "0x3C439A567C0f66b3D2Ca682327fC303Ec3Fb82D9", + "Prime_Proxy": "0xe840F8EC2Dc50E7D22e5e2991975b9F6e34b62Ad", + "RewardFacet": "0x68C120C4b35874593EE494faf4Db6deFcEFf53b4", + "SXP": "0x75107940Cf1121232C0559c747A986DEfbc69DA9", + "SetCheckpointBsctestnet": "0x69B83Bf4e8501D97217b545ce4151b62a5b550c9", + "SetterFacet": "0x4eC6D748a2647000895b455c408f85602A144Ed6", + "SnapshotLens": "0xdC888D97d6cBA15d2733ce14bF292F8ae6e0450e", + "SwapRouterCorePool": "0x83edf1deE1B730b7e8e13C00ba76027D63a51ac0", + "SwapRouterDefi": "0x76B88ff4579B35D2722B7383b9B9ce831dc89B72", + "SwapRouterGamefi": "0xFdeBF4530F9c7d352ffFE88cd0e96C8Bb7391BD9", + "SwapRouterLiquidStakedBNB": "0x7DcBd10E3479907e0B8C79d01D0572C8cc00227B", + "SwapRouterStableCoins": "0x6cE131c2321e25d7b4C63283b75DB160Ce3Fb710", + "SwapRouterTronFamily": "0x51Fd03aD1132e8cb5a5a793528c9F4ec918667d4", + "TUSD": "0xB32171ecD878607FFc4F8FC0bCcE6852BB3149E0", + "TwoKinks_base0bps_slope1000bps_kink8000bps_slope27000bps_base20bps_kink29000bps_jump30000bps_bpy21024000": "0x0e072E068851279b4573A3e445FA259d9d47f03C", + "TwoKinks_base0bps_slope1000bps_kink8000bps_slope27000bps_base20bps_kink29000bps_jump30000bps_bpy42048000": "0x31DeE85C1A1d1DfC074F4206AA26CF06C9E764B9", + "TwoKinks_base0bps_slope1000bps_kink8000bps_slope27000bps_base20bps_kink29000bps_jump30000bps_bpy70080000": "0x87971b23F5977CC7e98474ebeF1582CADfbCfC6a", + "TwoKinks_base0bps_slope350bps_kink8000bps_slope217500bps_base20bps_kink29000bps_jump30000bps_bpy10512000": "0x46D9269a8Db9623ac2baAB305B119a39BAfd8668", + "TwoKinks_base0bps_slope350bps_kink8000bps_slope217500bps_base20bps_kink29000bps_jump30000bps_bpy21024000": "0xb39D9F97Ad7Cf08C0Bef592aADD4CbBac8F8078E", + "TwoKinks_base0bps_slope350bps_kink8000bps_slope217500bps_base20bps_kink29000bps_jump30000bps_bpy42048000": "0xE85AD8bd7ADbEEDd818dAE20ED669d238e7cBCd3", + "TwoKinks_base0bps_slope350bps_kink8000bps_slope217500bps_base20bps_kink29000bps_jump30000bps_bpy70080000": "0x2f3be8fE4E24C63F27C091d3BD4CeF39242c6C09", + "TwoKinks_base0bps_slope450bps_kink7000bps_slope214000bps_base20bps_kink28000bps_jump30000bps_bpy42048000": "0xa84848Bd2E24a829D97c882Fb86AF90F811540F3", + "TwoKinks_base0bps_slope450bps_kink7000bps_slope214000bps_base20bps_kink28000bps_jump30000bps_bpy70080000": "0x2cdB649D70c3b183b4BA6BeFD240601A3bdD292D", + "TwoKinks_base0bps_slope625bps_kink8000bps_slope26000bps_base20bps_kink29000bps_jump34000bps_bpy70080000": "0x27670709C5CD7EA594a887Af5D4eBA926F36c561", + "USDC": "0x16227D60f7a0e586C66B005219dfc887D13C9531", + "USDT": "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", + "Unitroller": "0x94d1820b2D1c7c7452A163983Dc888CEC546b77D", + "Unitroller_Implementation": "0xbb34bBC161C9dbBE1dbCbC0A03478581f04b0E44", + "Unitroller_Proxy": "0x94d1820b2D1c7c7452A163983Dc888CEC546b77D", + "VAI": "0x5fFbE5302BadED40941A403228E6AD03f93752d9", + "VAIVault": "0x5c1c23ac038059c7B4EC1659728c166facab590b", + "VAIVaultProxy": "0x7Db4f5cC3bBA3e12FF1F528D2e3417afb0a57118", + "VAIVaultProxy_Implementation": "0x3f047c3022b35ed59484a4ee12b28849903a8c3b", + "VAIVaultProxy_Proxy": "0x7Db4f5cC3bBA3e12FF1F528D2e3417afb0a57118", + "VBNBAdmin": "0x04109575c1dbB4ac2e59e60c783800ea10441BBe", + "VBNBAdmin_Implementation": "0x920863fB3965fc411A1c0aC610C768F4347570fE", + "VBNBAdmin_Proxy": "0x04109575c1dbB4ac2e59e60c783800ea10441BBe", + "VBep20Delegate": "0x73fF75092Da265b87b25ffB943c47C90419a04A6", + "VRT": "0x331F639B4F3CF6E391CD244e0b5027C5968Ec325", + "VRTConverter": "0xF0fCB229031A386C672e291cE183390c1a7705dA", + "VRTConverterProxy": "0xAb81e79F9607eC4C7b69Ab4f7cf6c0AF607aA131", + "VRTVault": "0xa298713eCaE4e2C35C3af5241AAf81E0cc34Da84", + "VRTVaultProxy": "0x1ffD1b8B67A1AE0C189c734B0F58B0954522FF71", + "VRTVaultProxy_Implementation": "0x06ad3e299dc946fef2afa1f5e251682d52f4ebb6", + "VRTVaultProxy_Proxy": "0x1ffD1b8B67A1AE0C189c734B0F58B0954522FF71", + "VTreasury": "0x8b293600c50d6fbdc6ed4251cc75ece29880276f", + "VaiUnitroller": "0xf70C3C6b749BbAb89C081737334E74C9aFD4BE16", + "VaiUnitroller_Implementation": "0xd2848305b0ee7646C930240D79549D50d6Ed024F", + "VaiUnitroller_Proxy": "0xf70C3C6b749BbAb89C081737334E74C9aFD4BE16", + "VenusLens": "0x17A6222fB8b4b6D852cA54f5bc376a6A2c6224Bd", + "WBETH": "0xf9F98365566F4D55234f24b99caA1AfBE6428D44", + "WBNB": "0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd", + "WhitePaperInterestRateModel_base0bps_slope10000bps_bpy10512000": "0x562639bbbf595806d910d6bD82d215ac18604A12", + "WhitePaperInterestRateModel_base0bps_slope10000bps_bpy21024000": "0xef4017690CA2EF6831BBBA6bEBb6E9A116Ac332E", + "WhitePaperInterestRateModel_base0bps_slope10000bps_bpy42048000": "0x8d90aDaCCc998Fa7B0E71f0c03484b47bc5a3121", + "WhitePaperInterestRateModel_base0bps_slope10000bps_bpy70080000": "0x3b99ce268673e77E59e511f68cd183DAeC5Dffc6", + "WhitePaperInterestRateModel_base200bps_slope1000bps_bpy10512000": "0xdE9beC5102ee897a2c934321309517dD6c0106F4", + "WhitePaperInterestRateModel_base200bps_slope1000bps_bpy21024000": "0xc24A551Fcea07F53eB9d4a7F95411dD49D8B51D9", + "WhitePaperInterestRateModel_base200bps_slope1000bps_bpy42048000": "0x95829232e71616cc3B595AAd47d3674552e88FC0", + "WhitePaperInterestRateModel_base200bps_slope1000bps_bpy70080000": "0x1ac040e357fD9C613D76baFA305b05B998a6A969", + "XRP": "0x3022A32fdAdB4f02281E8Fab33e0A6811237aab0", + "XVS": "0xB9e0E753630434d7863528cc73CB7AC638a7c8ff", + "XVSStore": "0x7B4dba3b320E7D421A213e1a73bB9858bb6839F8", + "XVSVault": "0x9801565BE8fe2c9fD12C17992ecDeb510BaF677A", + "XVSVaultProxy": "0x9aB56bAD2D7631B2A857ccf36d998232A8b82280", + "XVSVaultProxy_Implementation": "0x471A33538D8A73fc7148F8B72A2A8BE6Ab9E3723", + "XVSVaultProxy_Proxy": "0x9aB56bAD2D7631B2A857ccf36d998232A8b82280", + "XVSVesting": "0x9667B6E438232925525F26CeC0acC3A39B9980C8", + "XVSVestingProxy": "0xcfa3a6bc934EcA22fa39e854c823cD3dE79D9BC8", + "XVSVestingProxy_Implementation": "0x9667b6e438232925525f26cec0acc3a39b9980c8", + "XVSVestingProxy_Proxy": "0xcfa3a6bc934EcA22fa39e854c823cD3dE79D9BC8", + "pancakeFactory": "0x182859893230dC89b114d6e2D547BFFE30474a21", + "vAAVE": "0x714db6c38A17883964B68a07d56cE331501d9eb6", + "vADA": "0x37C28DE42bA3d22217995D146FC684B2326Ede64", + "vBNB": "0x2E7222e51c0f6e98610A1543Aa3836E092CDe62c", + "vBTC": "0xb6e9322C49FD75a367Fcb17B0Fcd62C5070EbCBe", + "vBUSD": "0x08e0A5575De71037aE36AbfAfb516595fE68e5e4", + "vCAKE": "0xeDaC03D29ff74b5fDc0CC936F6288312e1459BC6", + "vDOGE": "0xF912d3001CAf6DC4ADD366A62Cc9115B4303c9A9", + "vETH": "0x162D005F0Fff510E54958Cfc5CF32A3180A84aab", + "vFDUSD": "0xF06e662a00796c122AaAE935EC4F0Be3F74f5636", + "vLTC": "0xAfc13BC065ABeE838540823431055D2ea52eBA52", + "vMATIC": "0x3619bdDc61189F33365CC572DF3a68FB3b316516", + "vNVDAB": "0x9e1ECb2671AfabE9eaAA2e74Cb2318a9b6A2Eb5d", + "vPT-USDe-30OCT2025": "0x86a94290f2B8295daA3e53bA1286f2Ff21199143", + "vPT-clisBNB-25JUN2026": "0xCd5A0037ebfC4a22A755923bB5C983947FaBdCe7", + "vPT-sUSDE-26JUN2025": "0x90535B06ddB00453a5e5f2bC094d498F1cc86032", + "vSKHYB": "0x101843eAbA6b98fbF4bba078b86EFdE62DF0fc16", + "vSOL": "0xbd9EB061444665Df7282Ec0888b72D60aC41Eb8C", + "vSPCXB": "0x05B2EC5B7437FB188175bf440e3EB36af79fe319", + "vSXP": "0x74469281310195A04840Daf6EdF576F559a3dE80", + "vSolvBTC": "0xA38110ae4451A86ab754695057d5B5a9BEAd0387", + "vTHE": "0x39A239F5117BFaC7a1b0b3A517c454113323451d", + "vTRX": "0x6AF3Fdb3282c5bb6926269Db10837fa8Aec67C04", + "vTRXOLD": "0x369Fea97f6fB7510755DCA389088d9E2e2819278", + "vTSLAB": "0x3Ed56f6937fc8549f9325405d1e8E650739647Fa", + "vTUSD": "0xEFAACF73CE2D38ED40991f29E72B12C74bd4cf23", + "vTUSDOLD": "0x3A00d9B02781f47d033BAd62edc55fBF8D083Fb0", + "vTWT": "0x95DaED37fdD3F557b3A5cCEb7D50Be65b36721DF", + "vU": "0x93969F17d4c1C7B22000eA26D5C2766E0f616D90", + "vUNI": "0x171B468b52d7027F12cEF90cd065d6776a25E24e", + "vUSD1": "0x519e61D2CDA04184FB086bbD2322C1bfEa0917Cf", + "vUSDC": "0xD5C4C2e2facBEB59D0216D0595d63FcDc6F9A1a7", + "vUSDT": "0xb7526572FFE56AB9D7489838Bf2E18e3323b441A", + "vUSDe": "0x86f8DfB7CA84455174EE9C3edd94867b51Da46BD", + "vWBETH": "0x35566ED3AF9E537Be487C98b1811cDf95ad0C32b", + "vWBNB": "0xd9E77847ec815E56ae2B9E69596C69b6972b0B1C", + "vXAUM": "0xc93CBF6CA7F3124737F2f4daDa8dBBC7be56d125", + "vXRP": "0x488aB2826a154da01CC4CC16A8C83d4720D3cA2C", + "vXVS": "0x6d6F697e34145Bb95c54E77482d97cc261Dc237E", + "vasBNB": "0x73F506Aefd5e169D48Ea21A373B9B0a200E37585", + "vlisUSD": "0x9447b1D4Bd192f25416B6aCc3B7f06be2f7D6309", + "vsUSDe": "0x8c8A1a0b6e1cb8058037F7bF24de6b79Aca5B7B0", + "vslisBNB": "0xaB5504A3cde0d8253E8F981D663c7Ff7128B3e56", + "vvhUSDT": "0xb846eEbaC8b014296709dc660Bfcb6ea182718e8", + "vxSolvBTC": "0x97cB97B05697c377C0bd09feDce67DBd86B7aB1e" + } +} diff --git a/plan/agw/research/preset-catalog-2026-10-15/catalog.md b/plan/agw/research/preset-catalog-2026-10-15/catalog.md new file mode 100644 index 00000000..711941e6 --- /dev/null +++ b/plan/agw/research/preset-catalog-2026-10-15/catalog.md @@ -0,0 +1,291 @@ +# AGW Presets: proposal and rules + +Presets are ready-made rule sets for `client.agentic.create`: pick a category, add an agent, a token budget and an expiry, and get one `Rule` per chain that already names the right contracts, calls and pins. The wallet UI and developers read the same presets from `PushChain.utils.agentic.presets`. + +This doc proposes the first preset list, the allowed calls and pins per app, and the contract and SDK changes the rest depends on. It extends page 5 (SDK: AGW), section 7. + +- Addresses: read from each protocol's deployment files or docs on 2026-10-13 (Sources at the end). Three carry caveats, listed in section 11, item 12. + +# Prerequisites + +> +> +> +> [7. Changes proposed on 12 Oct 2026: Presets](https://app.notion.com/p/7-Changes-proposed-on-12-Oct-2026-Presets-07ce163677ef44dfae03a38ea4c16da0?pvs=21) +> +> Contract source, what the rules policy checks today: [push-agentic-wallets, branch demo-v2](https://github.com/pushchain/push-agentic-wallets/tree/demo-v2/src), `src/libraries/Types.sol` (the rule shapes) and `src/policies/UniversalRulesPolicy.sol` (the gates); URP 3.1.0, the version on Donut +> +> [https://www.figma.com/design/FvJL0JWHlsVohsHTERB1Lh/Push-Design-Foundations?node-id=50458-26112&t=GpO3AVzquTow00Gj-0](https://www.figma.com/design/FvJL0JWHlsVohsHTERB1Lh/Push-Design-Foundations?node-id=50458-26112&t=GpO3AVzquTow00Gj-0) +> + +![image.png](AGW%20Presets%20proposal%20and%20rules/image.png) + +# Categories + +Custom is always open: a user can write any rule by hand in `client.agentic.create`, so a category left out here is not blocked, only not pre-filled. Presets are shortcuts for the common cases. + +**Factors a category must pass to be a preset** + +1. **Fixed strategy, user fills the blanks.** The preset picks the contracts and functions. The user picks the agent, fn params. If the user would have to pick the contracts too, it is Custom. +2. **The receiver can be locked to the wallet.** Every call that moves funds has a "to" argument we can pin. Aggregators, order books and Universal Router hide it inside a bytes blob, so they are out. +3. **Popular.** Top apps by volume or TVL. + +| Category | In v1? | Why | +| --- | --- | --- | +| DEXES | Yes | Swaps on routers with the recipient at a fixed position, 2 to 3 routers. The user names the tokens, the preset pins them (section 7) | +| LENDING | Yes | Supply, withdraw, borrow, repay on 2 to 3 money markets, with the position owner pinned to the wallet | +| STAKING | Yes | Liquid staking and restaking. Pins well: the receipt token goes to `msg.sender`, and the native coin sent is capped per call by `maxValue` | +| VAULTS | No, next | ERC-4626 `deposit`, `withdraw`, `redeem` with the receiver pinned; the most pinnable category. Needs the vault list first | +| PREDICTION | No | The live venues (Polymarket, Kalshi, Limitless) are order books: the user signs an order off-chain and an operator fills it, and a rule allows contract calls, not signed orders. The on-chain AMM-style markets have no volume. Constant ships empty, hidden by the UI | +| PERPS | No | Dynamic order structs (GMX, Drift), so the receiver cannot be pinned; leverage makes the loss case worse | +| AGGREGATORS | No | 1inch, 0x, Paraswap: dynamic calldata by design, nothing to pin. Jupiter `route` on Solana is the exception (user accounts at fixed positions, amounts pinnable from the end of the data) and sits in DEXES as a candidate | +| NFT MARKETS | No | Dynamic order structs (Seaport, Magic Eden) | +| BRIDGES | No | The recipient is on another chain; the AGW already moves funds across chains through Push | +| LAUNCHPADS | No | pump.fun pins fine, but it is the DEXES risk with worse odds | +| PAYMENTS | No, later | ERC-20 `transfer(address,uint256)` and SPL transfer with the recipient pinned to addresses the user passes as a parameter. Pins well and loss is bounded; left out of v1 only because agent payments (vendors, subscriptions) are not a demo case yet. GOVERNANCE (`castVote`, `delegate`) is the same shape with no funds moving and little demand | + +# Chains in scope + + + +| Chain | Mainnet | Testnet | +| --- | --- | --- | +| Ethereum | eip155:1 | Sepolia, eip155:11155111 | +| Base | eip155:8453 | Base Sepolia, eip155:84532 | +| Arbitrum | eip155:42161 | Arbitrum Sepolia, eip155:421614 | +| BNB Chain | eip155:56 | BSC testnet, eip155:97 | +| Solana | mainnet-beta | devnet | + +# DEXES + +One rule per chain, two or three routers per chain, single-hop and `address[]`-path swaps only. Every swap pins its recipient to the wallet. An app's calls are the same on every chain it is listed for; addresses are in section 6. + +| App | Chains | Allowed call | Pin | +| --- | --- | --- | --- | +| Uniswap V3 SwapRouter02 | Ethereum, Base, Arbitrum, BNB | `exactInputSingle((address,address,uint24,address,uint256,uint256,uint160))` | `[0,3]` = WALLET (word 3); `[0,0]` = tokenIn, `[0,1]` = tokenOut from the user's list (after page 1, 6.3) | +| Uniswap V3 SwapRouter02 | same | `exactOutputSingle((address,address,uint24,address,uint256,uint256,uint160))` | `[0,3]` = WALLET; `[0,0]` and `[0,1]` = the user's tokens (after 6.3) | +| Uniswap V3 SwapRouter02 | same | `swapExactTokensForTokens(uint256,uint256,address[],address)` (V2 pools through the same router) | `3` = WALLET (word 3); tokens sit inside `path`, not pinnable | +| Uniswap V2 Router02 | Ethereum | `swapExactTokensForTokens(uint256,uint256,address[],address,uint256)` | `3` = WALLET (word 3); tokens not pinnable | +| Uniswap V2 Router02 | Ethereum | `swapTokensForExactTokens(uint256,uint256,address[],address,uint256)` | `3` = WALLET (word 3); tokens not pinnable | +| Curve Router NG | Ethereum | `exchange(address[11],uint256[5][5],uint256,uint256,address[5],address)` | `5` = WALLET (word 43, fixed arrays inlined); `[0,0]` = tokenIn pinnable, tokenOut sits at a variable position in `route`, not pinnable | +| Aerodrome Router | Base | `swapExactTokensForTokens(uint256,uint256,(address,address,bool,address)[],address,uint256)` | `3` = WALLET (word 3); tokens sit inside `routes`, not pinnable | +| Aerodrome Slipstream SwapRouter | Base | `exactInputSingle((address,address,int24,address,uint256,uint256,uint256,uint160))` | `[0,3]` = WALLET; `[0,0]` and `[0,1]` = the user's tokens (after 6.3) | +| Aerodrome Slipstream SwapRouter | Base | `exactOutputSingle((address,address,int24,address,uint256,uint256,uint256,uint160))` | `[0,3]` = WALLET; `[0,0]` and `[0,1]` = the user's tokens (after 6.3) | +| PancakeSwap V3 SmartRouter | Arbitrum, BNB | `exactInputSingle((address,address,uint24,address,uint256,uint256,uint160))` | `[0,3]` = WALLET; `[0,0]` and `[0,1]` = the user's tokens (after 6.3) | +| PancakeSwap V3 SmartRouter | same | `exactOutputSingle((address,address,uint24,address,uint256,uint256,uint160))` | `[0,3]` = WALLET; `[0,0]` and `[0,1]` = the user's tokens (after 6.3) | +| PancakeSwap V3 SmartRouter | same | `swapExactTokensForTokens(uint256,uint256,address[],address)` | `3` = WALLET (word 3); tokens not pinnable | +| PancakeSwap V2 Router02 | BNB | `swapExactTokensForTokens(uint256,uint256,address[],address,uint256)` | `3` = WALLET (word 3); tokens not pinnable | +| PancakeSwap V2 Router02 | BNB | `swapTokensForExactTokens(uint256,uint256,address[],address,uint256)` | `3` = WALLET (word 3); tokens not pinnable | +| Camelot V3 SwapRouter | Arbitrum | `exactInputSingle((address,address,address,uint256,uint256,uint256,uint160))` (Algebra: recipient is field 2) | `[0,2]` = WALLET (word 2); `[0,0]` and `[0,1]` = the user's tokens (after 6.3) | +| Camelot V3 SwapRouter | Arbitrum | `exactOutputSingle((address,address,uint24,address,uint256,uint256,uint256,uint160))` | `[0,3]` = WALLET (word 3); `[0,0]` and `[0,1]` = the user's tokens (after 6.3) | +| Raydium CPMM | Solana | `swap_base_input(u64,u64)`, discriminator `8fbe5adac41e33de`; 13 accounts, `maxAccounts` 13 | account 0 = WALLET; account 5 = WALLET ATA(output mint); data pin: min-out ratio on `(amount_in, minimum_amount_out)` | +| Raydium CPMM | Solana | `swap_base_output(u64,u64)`, discriminator `37d96256a34ab4ad` | same | +| Orca Whirlpool | Solana | `swap(u64,u64,u128,bool,bool)`, discriminator `f8c69e91e17587c8`; 11 accounts plus trailing, `maxAccounts` 0 | account 1 = WALLET; accounts 3 and 5 = WALLET ATA(mint A), WALLET ATA(mint B); data pin: `a_to_b` EQ and the min-out ratio | +| Raydium AMM V4 | Solana | `swapBaseIn(u64,u64)`, 1-byte tag 9; `maxAccounts` 17 | account 16 = WALLET; account 15 = WALLET ATA(output mint); min-out ratio | +| Jupiter v6 (candidate) | Solana | `route(Vec,u64,u64,u16,u8)`, discriminator `e517cb977ae3ad2a`; pools as trailing accounts, `maxAccounts` 0 | account 1 = WALLET; account 3 = WALLET ATA(output mint); amounts pinned from the end of `ix_data` (`fromEnd`), since Borsh writes the vector first | +- Token pins: only the struct-based single-hop calls (`exactInputSingle`, `exactOutputSingle`) can carry them, since `tokenIn` and `tokenOut` are static fields at words 0 and 1. The path-based calls keep the tokens inside a dynamic array, so once 6.3 lands and the user's token list is enforced, the path rows should be dropped or kept with the warning in section 7. Until 6.3 none of the EVM token pins is checked. +- Out on EVM: `exactInput` and `exactOutput` (recipient inside a struct with `bytes path`), Universal Router `execute`, `multicall`, Curve's four- and five-argument `exchange` overloads. +- Solana: the SVM rulebook already exists in the demo-v2 source. An account pin names one key from `ceaAccounts`, so a swap rule allows one output mint; `maxAccounts` 0 admits the trailing tick, bin and pool accounts Orca, Meteora and Jupiter need; the `RATIO_GTE_LE` data pin enforces a minimum output relative to the input. Jupiter `route` is therefore a candidate, to confirm against the program (`shared_accounts_route` uses program-owned intermediates and stays out). Orca, Raydium CLMM and Meteora share the `swap` discriminator `f8c69e91e17587c8`; a rule keys on program and discriminator. + +# LENDING + +Supply, withdraw, borrow and repay on two or three money markets per chain. Every position is the wallet's: the call acts on `msg.sender` (Compound-style markets, where the CEA is the sender) or pins `onBehalfOf` on the way in and `to` or `receiver` on the way out. Solana is supply and withdraw only. + +| App | Chains | Allowed call | Pin | +| --- | --- | --- | --- | +| Aave V3 Pool | Ethereum, Base, Arbitrum, BNB | `supply(address,uint256,address,uint16)` | `2` = WALLET (onBehalfOf, word 2) | +| Aave V3 Pool | same | `withdraw(address,uint256,address)` | `2` = WALLET (to, word 2) | +| Aave V3 Pool | same | `borrow(address,uint256,uint256,uint16,address)` | `4` = WALLET (onBehalfOf, word 4) | +| Aave V3 Pool | same | `repay(address,uint256,uint256,address)` | `3` = WALLET (onBehalfOf, word 3) | +| Compound V3 Comet (cUSDCv3, cWETHv3) | Ethereum, Arbitrum | `supply(address,uint256)` | none; credits `msg.sender` | +| Compound V3 Comet | same | `withdraw(address,uint256)` | none; pays `msg.sender`. Withdrawing the base asset beyond the balance opens a borrow | +| Morpho Blue | Ethereum, Base, Arbitrum | `supply((address,address,address,address,uint256),uint256,uint256,address,bytes)` | `3` = WALLET (onBehalf, word 7) | +| Morpho Blue | same | `supplyCollateral((address,address,address,address,uint256),uint256,address,bytes)` | `2` = WALLET (onBehalf, word 6) | +| Morpho Blue | same | `withdraw((address,address,address,address,uint256),uint256,uint256,address,address)` | `4` = WALLET (receiver, word 8) | +| Morpho Blue | same | `withdrawCollateral((address,address,address,address,uint256),uint256,address,address)` | `3` = WALLET (receiver, word 7) | +| Morpho Blue | same | `borrow((address,address,address,address,uint256),uint256,uint256,address,address)` | `4` = WALLET (receiver, word 8) | +| Morpho Blue | same | `repay((address,address,address,address,uint256),uint256,uint256,address,bytes)` | `3` = WALLET (onBehalf, word 7) | +| Lista Moolah | BNB | the six Morpho Blue calls, same signatures and selectors | as Morpho Blue | +| Moonwell (mUSDC, mWETH) | Base | `mint(uint256)`, `redeem(uint256)`, `redeemUnderlying(uint256)`, `borrow(uint256)`, `repayBorrow(uint256)` | none; every call acts on `msg.sender` | +| Moonwell Comptroller | Base | `enterMarkets(address[])` | none; needed once before borrowing against a market | +| Venus (vUSDT, vUSDC) | BNB | the same five calls as Moonwell | none | +| Venus Unitroller | BNB | `enterMarkets(address[])` | none | +| Kamino Lend | Solana | `deposit_reserve_liquidity(u64)`, discriminator `a9c91e7e06cd6644`; owner 0, reserve liquidity mint 4, reserve collateral mint 6, user source 7, user destination 8 | account 0 = WALLET; account 8 = WALLET ATA(collateral mint at account 6); `maxAccounts` 12 | +| Kamino Lend | Solana | `redeem_reserve_collateral(u64)`, discriminator `ea75b57db98edc1d`; user source 7, user destination 8 | account 0 = WALLET; account 8 = WALLET ATA(liquidity mint at account 4) | +| Jupiter Lend (Earn) | Solana | `deposit(u64)`, discriminator `f223c68952e1f2b6`; signer 0, depositor token account 1, recipient token account 2 | account 0 = WALLET; account 2 = WALLET ATA(fToken mint); `maxAccounts` 17 | +| Jupiter Lend (Earn) | Solana | `withdraw(u64)`, discriminator `b712469c946da122`; signer 0, owner token account 1, recipient 2 | account 0 = WALLET; account 2 = WALLET ATA(underlying mint); `maxAccounts` 18 | + +# PREDICTION, venue by venue + +Every live venue on the five chains, plus Polymarket for reference. "Signed order" means the user signs an EIP-712 order off-chain and an operator-only `matchOrders` settles it: nothing for a rule to allow. + +| Venue | Chain | How a trade happens | Fits a rule? | 30-day volume | +| --- | --- | --- | --- | --- | +| PancakeSwap Prediction | BNB (BNB, BTC, ETH markets), Arbitrum (ETH) | Direct call: `betBull(uint256)` and `betBear(uint256)` payable, stake is the value, `claim(uint256[])`; position = `msg.sender` | Yes: one static argument, stake capped by `maxValue` | $7.8M | +| Predict.fun (absorbed Probable, March 2026) | BNB | Signed order, operator `matchOrders`; CTF `splitPosition`, `mergePositions`, `redeemPositions` are direct | No for trading; mint and redeem only | $314M | +| Opinion | BNB | Signed order ("OPINION CTF Exchange"), positions held in a Safe; CTF `0xAD1a38cEc043e70E83a3eC30443dB285ED10D774` | No for trading | $274M | +| Limitless | Base | Order book for new markets; legacy Gnosis FPMM markets still live: `buy(uint256,uint256,uint256)`, `sell(uint256,uint256,uint256)`, buyer = `msg.sender`; CTF `0xC9c98965297Bc527861c898329Ee280632B76e18` | Partial: the AMM calls fit, but each market is its own contract and the volume is in the order book | $4.9M | +| Overtime (Thales) SportsAMMV2 | Arbitrum, Base, Optimism | Direct call `trade(TradeData[],uint256,uint256,uint256,address,address,bool)`, ticket to `msg.sender` | Weak: the bet is a dynamic `TradeData[]` (odds, merkle proofs) a rule cannot read; only the stake at word 1 and the collateral at word 5 are pinnable | $7.6M (Arbitrum $2.3M, Base $1.4M) | +| Azuro | Base (Arbitrum dead since 2023) | v3: bettor signature plus oracle signature, relayer calls `betFor`; v2 `bet` carries `bytes data` | No | $2.8M (Base $96k) | +| Polymarket (reference) | Polygon only; the Jupiter tie-up is a front end | Signed order, `CTFExchangeV2.matchOrders` is `onlyOperator`; NegRiskAdapter split, merge, redeem are direct | No, and not on a chain in scope | $5.2B | +| Jupiter Predict (Polymarket and Kalshi liquidity) | Solana | Jupiter's API returns an unsigned transaction; a keeper fills on the underlying market; program id not published | No: keeper front end, program unverified | not listed | +| Drift BET | Solana | Perp orders: `place_perp_order(OrderParams)` with Borsh `Option` fields, many remaining accounts | No: variable-length arguments | not broken out | +| Augur, Gnosis v1 and every Ethereum L1 market | Ethereum | AMM-style, direct calls | Would fit, but dead | $0 | + +Out of scope by chain: Myriad (Abstract, Linea), XO Market (own rollup), Kalshi (off-chain). Sport.fun on Base ($4.8M) publishes no contracts. To open the big venues, the wallet's CEA would have to sign orders under a rule (ERC-1271, with maker, assets and amounts pinned): + +# STAKING + +| App | Chains | Allowed call | Pin | +| --- | --- | --- | --- | +| Lido stETH | Ethereum | `submit(address)` payable | none; stETH to `msg.sender` (the referral may be pinned to 0) | +| Lido wstETH | Ethereum | `wrap(uint256)`, `unwrap(uint256)` | none | +| Lido WithdrawalQueue | Ethereum | `requestWithdrawals(uint256[],address)` | `1` = WALLET (owner, word 1) | +| Lido WithdrawalQueue | Ethereum | `claimWithdrawals(uint256[],uint256[])`, `claimWithdrawal(uint256)` | none; owner must be `msg.sender`, ETH paid to `msg.sender` | +| Rocket Pool DepositPool | Ethereum | `deposit()` payable | none; rETH to `msg.sender` | +| Rocket Pool rETH | Ethereum | `burn(uint256)` | none; ETH to `msg.sender` | +| ether.fi LiquidityPool | Ethereum | `deposit()` payable, `deposit(address)` payable | none; eETH to `msg.sender` | +| ether.fi weETH | Ethereum | `wrap(uint256)`, `unwrap(uint256)` | none | +| ether.fi LiquidityPool | Ethereum | `requestWithdraw(address,uint256)` | `0` = WALLET (recipient, word 0) | +| ether.fi WithdrawRequestNFT | Ethereum | `claimWithdraw(uint256)` | none; ETH to the NFT's owner | +| EigenLayer StrategyManager | Ethereum | `depositIntoStrategy(address,address,uint256)` | none needed (shares to `msg.sender`); optional `0` = strategy and `1` = token to lock the pair | +| EigenLayer DelegationManager | Ethereum | `queueWithdrawals(...)`, `completeQueuedWithdrawal(...)` | none; withdrawer is forced to `msg.sender`, assets go to the staker | +| Lista StakeManager | BNB | `deposit()` payable | none; slisBNB to `msg.sender` | +| Lista StakeManager | BNB | `requestWithdraw(uint256)`, `claimWithdraw(uint256)` | none; BNB to `msg.sender` | +| BNB StakeHub (native) | BNB | `delegate(address,bool)` payable | `0` = validator, a user parameter; credit to `msg.sender` | +| BNB StakeHub (native) | BNB | `undelegate(address,uint256)`, `claim(address,uint256)` | `0` = the same validator | +| Jito (SPL stake pool) | Solana | `DepositSol(u64)`, tag 14; 10 accounts | 0 = Jito pool; 3 (lamports source) = WALLET; 4 = WALLET ATA(JitoSOL); 6 (referrer fee) = the same account; `maxAccounts` 10 | +| Jito (SPL stake pool) | Solana | `WithdrawSol(u64)`, tag 16; 12 accounts | 0 = Jito pool; 2 (authority) = WALLET; 3 = WALLET ATA(JitoSOL); 5 (SOL destination) = WALLET; `maxAccounts` 12 | +| Marinade | Solana | `deposit(u64)`, discriminator `f223c68952e1f2b6`; 11 accounts, none remaining | 6 (transfer_from) = WALLET; 7 (mint_to) = WALLET ATA(mSOL); `maxAccounts` 11 | +| Marinade | Solana | `liquid_unstake(u64)`, discriminator `1e1e77f0bfe30c10`; 10 accounts | 5 = WALLET ATA(mSOL); 6 (authority) = WALLET; 7 (transfer_sol_to) = WALLET; `maxAccounts` 10 | +- Out: Lido `claimWithdrawalsTo(uint256[],uint256[],address)` (names another recipient); Stader BNBx (deposits disabled 29 Jan 2026, protocol sunset); Marinade `order_unstake` (needs a fresh ticket account per call); Jito restaking `mint_to` (takes an SPL token in, so it belongs with VAULTS). +- Approvals: `wrap`, `requestWithdrawals`, `requestWithdraw`, `depositIntoStrategy` and Lista `requestWithdraw` pull a token from the wallet. Covered by scoped approval (section 8, item 3). +- Rocket Pool's deposit pool address changes on upgrades (the Saturn release deployed a new one in 2026 and the old one reverts on `deposit()`). The SDK should resolve it from `RocketStorage.getAddress(keccak256("contract.addressrocketDepositPool"))` at release time rather than hard-code it. +- `deposit()` has the same selector on Rocket Pool, ether.fi and WETH, and `wrap` and `unwrap` the same on wstETH and weETH; rules key on target plus selector, so no clash. +- Jito's `DepositSol` requires the pool to have been updated this epoch. BlazeStake, vSOL and the Sanctum pools use the same program and instruction, so adding one is a pool address. The StakeHub validator is a user parameter (categories, factor 1). + +# Addresses + +Read from each protocol's deployment files or docs. + +"none" means no official testnet deployment was found. + + + +### DEXES + +| App | Chain | Mainnet | Testnet | +| --- | --- | --- | --- | +| Uniswap V3 SwapRouter02 | Ethereum | `0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45` | `0x3bFA4769FB09eefC5a80d6E87c3B9C650f7Ae48E` | +| Uniswap V3 SwapRouter02 | Base | `0x2626664c2603336E57B271c5C0b26F421741e481` | `0x94cC0AaC535CCDB3C01d6787D6413C739ae12bc4` | +| Uniswap V3 SwapRouter02 | Arbitrum | `0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45` | `0x101F443B4d1b059569D643917553c771E1b9663E` | +| Uniswap V3 SwapRouter02 | BNB | `0xB971eF87ede563556b2ED4b1C0b0019111Dd85d2` | none | +| Uniswap V2 Router02 | Ethereum | `0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D` | `0xeE567Fe1712Faf6149d80dA1E6934E354124CfE3` | +| Curve Router NG v1.2 | Ethereum | `0x45312ea0eFf7E09C83CBE249fa1d7598c4C8cd4e` | none | +| Aerodrome Router | Base | `0xcF77a3Ba9A5CA399B7c97c74d54e5b1Beb874E43` | none | +| Aerodrome Slipstream SwapRouter | Base | `0x698Cb2b6dd822994581fEa6eA4Fc755d1363A92F` | none | +| PancakeSwap V3 SmartRouter | Arbitrum | `0x32226588378236Fd0c7c4053999F88aC0e5cAc77` | none | +| PancakeSwap V3 SmartRouter | BNB | `0x13f4EA83D0bd40E75C8222255bc855a974568Dd4` | `0x9a489505a00cE272eAa5e07Dba6491314CaE3796` | +| PancakeSwap V2 Router02 | BNB | `0x10ED43C718714eb63d5aA57B78B54704E256024E` | `0xD99D1c33F9fC3444f8101754aBC46c52416550D1` | +| Camelot V3 SwapRouter | Arbitrum | `0x1F721E2E82F6676FCE4eA07A5958cF098D339e18` | none | +| Raydium CPMM | Solana | `CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C` | `DRaycpLY18LhpbydsBWbVJtxpNv9oXPgjRSfpF2bWpYb` | +| Orca Whirlpool | Solana | `whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc` | same id | +| Raydium AMM V4 | Solana | `675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8` | `DRaya7Kj3aMWQSy19kSjvmuwq9docCHofyP9kanQGaav` | + +### LENDING + +| App | Chain | Mainnet | Testnet | +| --- | --- | --- | --- | +| Aave V3 Pool | Ethereum | `0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2` | `0x6Ae43d3271ff6888e7Fc43Fd7321a503ff738951` | +| Aave V3 Pool | Base | `0xA238Dd80C259a72e81d7e4664a9801593F98d1c5` | `0x8bAB6d1b75f19e9eD9fCe8b9BD338844fF79aE27` | +| Aave V3 Pool | Arbitrum | `0x794a61358D6845594F94dc1DB02A252b5b4814aD` | `0xBfC91D59fdAA134A4ED45f7B584cAf96D7792Eff` | +| Aave V3 Pool | BNB | `0x6807dc923806fE8Fd134338EABCA509979a7e0cB` | none | +| Compound V3 cUSDCv3 | Ethereum | `0xc3d688B66703497DAA19211EEdff47f25384cdc3` | `0xAec1F48e02Cfb822Be958B68C7957156EB3F0b6e`, unmaintained since June 2026 | +| Compound V3 cWETHv3 | Ethereum | `0xA17581A9E3356d9A858b789D68B4d866e593aE94` | none | +| Compound V3 cUSDCv3 | Arbitrum | `0x9c4ec768c28520B50860ea7a15bd7213a9fF58bf` | none | +| Compound V3 cWETHv3 | Arbitrum | `0x6f7D514bbD4aFf3BcD1140B7344b32f063dEe486` | none | +| Morpho Blue | Ethereum | `0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb` | none | +| Morpho Blue | Base | `0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb` | unconfirmed by Morpho's own sources | +| Morpho Blue | Arbitrum | `0x6c247b1F6182318877311737BaC0844bAa518F5e` | none | +| Lista Moolah | BNB | `0x8F73b65B4caAf64FBA2aF91cC5D4a2A1318E5D8C` | none | +| Moonwell mUSDC | Base | `0xEdc817A28E8B93B03976FBd4a3dDBc9f7D176c22` | mUSDbC `0x876852425331a113d8E432eFFB3aC5BEf38f033a` | +| Moonwell mWETH | Base | `0x628ff693426583D9a7FB391E54366292F509D457` | `0x2F39a349A79492a70E152760ce7123A1933eCf28` | +| Moonwell Comptroller | Base | `0xfBb21d0380beE3312B33c4353c8936a0F13EF26C` | `0xC72ba45f2Ae134F21DAEb2b7B5fd5De0064Ee9bB` | +| Venus vUSDT | BNB | `0xfD5840Cd36d94D7229439859C0112a4185BC0255` | `0xb7526572FFE56AB9D7489838Bf2E18e3323b441A` | +| Venus vUSDC | BNB | `0xecA88125a5ADbe82614ffC12D0DB554E2e2867C8` | `0xD5C4C2e2facBEB59D0216D0595d63FcDc6F9A1a7` | +| Venus Unitroller | BNB | `0xfD36E2c2a6789Db23113685031d7F16329158384` | `0x94d1820b2D1c7c7452A163983Dc888CEC546b77D` | +| Kamino Lend | Solana | `KLend2g3cP87fffoy8q1mQqGKjrxjC8boSyAYavgmjD` | same id | +| Jupiter Lend (Earn) | Solana | `jup3YeL8QhtSx1e253b2FDvsMNC87fDrgQZivbrndc9` | `7tjE28izRUjzmxC1QNXnNwcc4N82CNYCexf3k8mw67s3`, stale since May 2025, do not use | + +### STAKING + +Testnets: Hoodi (eip155:560048) for Lido, Rocket Pool and EigenLayer; EigenLayer is also on Sepolia. ether.fi and Lista have no official testnet deployment. + + + +| App | Chain | Mainnet | Testnet | +| --- | --- | --- | --- | +| Lido stETH | Ethereum | `0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84` | Hoodi `0x3508A952176b3c15387C97BE809eaffB1982176a` | +| Lido wstETH | Ethereum | `0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0` | Hoodi `0x7E99eE3C66636DE415D2d7C880938F2f40f94De4` | +| Lido WithdrawalQueue | Ethereum | `0x889edC2eDab5f40e902b864aD4d7AdE8E412F9B1` | Hoodi `0xfe56573178f1bcdf53F01A6E9977670dcBBD9186` | +| Rocket Pool RocketStorage | Ethereum | `0x1d8f8f00cfa6758d7bE78336684788Fb0ee0Fa46` | Hoodi `0x594Fb75D3dc2DFa0150Ad03F99F97817747dd4E1` | +| Rocket Pool DepositPool (current) | Ethereum | `0xCE15294273CFb9D9b628F4D61636623decDF4fdC` | Hoodi `0x425E6f83e27f1676AD78BC39dA79C2C7b33d3Fd8` | +| Rocket Pool rETH | Ethereum | `0xae78736Cd615f374D3085123A210448E74Fc6393` | Hoodi `0x7322c24752f79c05FFD1E2a6FCB97020C1C264F1` | +| ether.fi LiquidityPool | Ethereum | `0x308861A430be4cce5502d0A12724771Fc6DaF216` | none | +| ether.fi weETH | Ethereum | `0xCd5fE23C85820F7B72D0926FC9b05b43E359b7ee` | none | +| ether.fi WithdrawRequestNFT | Ethereum | `0x7d5706f6ef3F89B3951E23e557CDFBC3239D4E2c` | none | +| EigenLayer StrategyManager | Ethereum | `0x858646372CC42E1A627fcE94aa7A7033e7CF075A` | Hoodi `0xeE45e76ddbEDdA2918b8C7E3035cd37Eab3b5D41`; Sepolia `0x2E3D6c0744b10eb0A4e6F679F71554a39Ec47a5D` | +| EigenLayer DelegationManager | Ethereum | `0x39053D51B77DC0d36036Fc1fCc8Cb819df8Ef37A` | Hoodi `0x867837a9722C512e0862d8c2E15b8bE220E8b87d`; Sepolia `0xD4A7E1Bd8015057293f0D0A557088c286942e84b` | +| EigenLayer stETH strategy | Ethereum | `0x93c4b944D05dfe6df7645A86cd2206016c51564D` | Hoodi `0xf8a1a66130d614c7360e868576d5e59203475fe0` | +| Lista StakeManager | BNB | `0x1adB950d8bB3dA4bE104211D5AB038628e477fE6` | none published | +| Lista slisBNB | BNB | `0xB0b84D294e0C75A6abe60171b70edEb2EFd14A1B` | unverified | +| BNB StakeHub | BNB | `0x0000000000000000000000000000000000002002` | same (system contract) | +| SPL stake pool program (Jito) | Solana | `SPoo1Ku8WFXoNDMHPsrGSTSG1Y47rzgn41SLUNakuHy` | devnet build `DPoo15wWDqpPJJtS2MUZ49aRxqz5ZaaJCJP4z8bLuib` | +| Jito pool, JitoSOL mint | Solana | `Jito4APyf642JPZPx3hGc6WWJ8zPKtRbRs4P815Awbb`, `J1toso1uCk3RLmjorhTtrVwY9HJ7X8V9yYac6Y7kGCPn` | `JitoY5pcAxWX6iyP2QdFwTznGb8A99PRCUCVVxB46WZ`, `J1tos8mqbhdGcF3pgj4PCKyVjzWSURcpLZU7pPGHxSYi` | +| Marinade program | Solana | `MarBmsSgKXdrN1egZf5sqe1TMai9K1rChYNDJgjq7aD` | same id | +| Marinade state, mSOL mint | Solana | `8szGkuLTAux9XMgZ2vtY39jVSowEcpBfFfD8hXSEqdGC`, `mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So` | state not documented for devnet; mint the same | + +# Open questions and decisions needed + +1. **Approvals.** Scoped approval in URP, or one spender per token per rule for v1, which means one app per chain per preset and an allowance that outlives the rule? (Rules policy owner) +2. **Output tokens.** Until page 1, 6.3 lands no token pin is checked on EVM, and a pin holds one value. Ship DEXES with one output token per rule, or ship LENDING first and DEXES after the set pin +3. **One instruction per transaction on Solana.** Blocks every borrow flow (Kamino, Save, MarginFi need refresh instructions in the same transaction) and creating the output token account before a first swap. Relax to one allowed instruction plus instructions from a fixed list (refresh, create token account, compute budget)? (Rules policy owner) +4. **Missing cap.** Should `presets.get` throw when an asset has no `maxTotal`, since a missing cap means zero and the rule would move nothing? + +# Sources + +Deployment files and interfaces opened on 2026-10-13. Where a docs site was unreachable, the protocol's GitHub deployment file or published npm package was used instead. + +- Uniswap: [V3 Ethereum deployments](https://github.com/Uniswap/docs/blob/main/docs/content/protocols/v3/deployments/v3-ethereum-deployments.mdx), [V3 Base deployments](https://developers.uniswap.org/docs/protocols/v3/deployments/v3-base-deployments), [V3 Arbitrum deployments](https://developers.uniswap.org/docs/protocols/v3/deployments/v3-arbitrum-deployments.md), [sdk-core addresses](https://raw.githubusercontent.com/Uniswap/sdks/main/sdks/sdk-core/src/addresses.ts), [IV3SwapRouter](https://raw.githubusercontent.com/Uniswap/swap-router-contracts/main/contracts/interfaces/IV3SwapRouter.sol), [IV2SwapRouter](https://raw.githubusercontent.com/Uniswap/swap-router-contracts/main/contracts/interfaces/IV2SwapRouter.sol), [IUniswapV2Router02](https://raw.githubusercontent.com/Uniswap/v2-periphery/master/contracts/interfaces/IUniswapV2Router02.sol) +- Curve: [curve-router-ng](https://raw.githubusercontent.com/curvefi/curve-router-ng/master/README.md), [deployed contracts](https://raw.githubusercontent.com/CurveDocs/curve-docs/master/docs/references/deployed-contracts.md) +- Aerodrome: [contracts README](https://raw.githubusercontent.com/aerodrome-finance/contracts/main/README.md), [IRouter](https://raw.githubusercontent.com/aerodrome-finance/contracts/main/contracts/interfaces/IRouter.sol), [Slipstream README](https://raw.githubusercontent.com/aerodrome-finance/slipstream/main/README.md), [Slipstream ISwapRouter](https://raw.githubusercontent.com/aerodrome-finance/slipstream/main/contracts/periphery/interfaces/ISwapRouter.sol) +- PancakeSwap: [v3 addresses](https://raw.githubusercontent.com/pancakeswap/pancake-developer/master/docs/pages/contracts/v3/addresses.md), [v3-periphery deployments](https://raw.githubusercontent.com/pancakeswap/pancake-v3-contracts/main/projects/v3-periphery/deployments/bscMainnet.json), [IPancakeRouter02](https://raw.githubusercontent.com/pancakeswap/pancake-swap-periphery/master/contracts/interfaces/IPancakeRouter02.sol), npm `@pancakeswap/smart-router@7.8.0` +- Camelot: [Algebra V1.9 ISwapRouter](https://raw.githubusercontent.com/cryptoalgebra/AlgebraV1.9/main/src/periphery/contracts/interfaces/ISwapRouter.sol), [verified source mirror, Router v3](https://www.codeslaw.app/contracts/arbitrum/0x1f721e2e82f6676fce4ea07a5958cf098d339e18) +- Aave: [address book, Ethereum](https://raw.githubusercontent.com/bgd-labs/aave-address-book/main/src/AaveV3Ethereum.sol), [Sepolia](https://raw.githubusercontent.com/bgd-labs/aave-address-book/main/src/AaveV3Sepolia.sol), [Base](https://raw.githubusercontent.com/bgd-labs/aave-address-book/main/src/AaveV3Base.sol), [Base Sepolia](https://raw.githubusercontent.com/bgd-labs/aave-address-book/main/src/AaveV3BaseSepolia.sol), [Arbitrum](https://raw.githubusercontent.com/bgd-labs/aave-address-book/main/src/AaveV3Arbitrum.sol), [Arbitrum Sepolia](https://raw.githubusercontent.com/bgd-labs/aave-address-book/main/src/AaveV3ArbitrumSepolia.sol), [BNB](https://raw.githubusercontent.com/bgd-labs/aave-address-book/main/src/AaveV3BNB.sol), [IPool](https://raw.githubusercontent.com/aave-dao/aave-v3-origin/main/src/contracts/interfaces/IPool.sol) +- Compound V3: [mainnet USDC roots](https://raw.githubusercontent.com/compound-finance/comet/main/deployments/mainnet/usdc/roots.json), [Arbitrum USDC roots](https://raw.githubusercontent.com/compound-finance/comet/main/deployments/arbitrum/usdc/roots.json), [CometMainInterface](https://raw.githubusercontent.com/compound-finance/comet/main/contracts/CometMainInterface.sol) +- Morpho: [IMorpho](https://raw.githubusercontent.com/morpho-org/morpho-blue/main/src/interfaces/IMorpho.sol), [SDK addresses](https://raw.githubusercontent.com/morpho-org/sdks/main/packages/morpho-ts/src/addresses.ts), [docs addresses](https://docs.morpho.org/get-started/resources/addresses/) +- Moonwell: [Base addresses](https://raw.githubusercontent.com/moonwell-fi/moonwell-contracts-v2/main/chains/8453.json), [Base Sepolia addresses](https://raw.githubusercontent.com/moonwell-fi/moonwell-contracts-v2/main/chains/84532.json), [MToken](https://raw.githubusercontent.com/moonwell-fi/moonwell-contracts-v2/main/src/MToken.sol) +- Venus: [mainnet addresses](https://raw.githubusercontent.com/VenusProtocol/venus-protocol/develop/deployments/bscmainnet_addresses.json), [testnet addresses](https://raw.githubusercontent.com/VenusProtocol/venus-protocol/develop/deployments/bsctestnet_addresses.json), [VBep20](https://raw.githubusercontent.com/VenusProtocol/venus-protocol/develop/contracts/Tokens/VTokens/VBep20.sol) +- Lista: [lista-skills](https://raw.githubusercontent.com/lista-dao/lista-skills/main/skills/lista-lending/SKILL.md), npm `@lista-dao/moolah-sdk-core@1.0.12` +- Raydium: [program addresses](https://docs.raydium.io/reference/program-addresses.md), [CPMM IDL](https://github.com/raydium-io/raydium-idl), [AMM V4 instruction.rs](https://raw.githubusercontent.com/raydium-io/raydium-amm/master/program/src/instruction.rs) +- Orca: [whirlpools](https://github.com/orca-so/whirlpools) +- Meteora: [DLMM overview](https://docs.meteora.ag/developer-guide/guides/dlmm/overview), [dlmm-sdk](https://github.com/MeteoraAg/dlmm-sdk) +- Jupiter: [jupiter-cpi IDL](https://raw.githubusercontent.com/jup-ag/jupiter-cpi/main/idl.json), [development basics](https://developers.jup.ag/docs/get-started/development-basics.md), [Lend program addresses](https://developers.jup.ag/docs/lend/program-addresses.md), [jupiter-lend](https://github.com/jup-ag/jupiter-lend) +- Kamino: [klend](https://github.com/Kamino-Finance/klend), [klend-sdk](https://github.com/Kamino-Finance/klend-sdk) +- MarginFi: [marginfi-v2](https://github.com/mrgnlabs/marginfi-v2) +- Save: [token-lending instruction.rs](https://raw.githubusercontent.com/solendprotocol/solana-program-library/master/token-lending/program/src/instruction.rs) +- Volume and TVL: [DefiLlama DEXes, Ethereum](https://defillama.com/dexs/chains/Ethereum), [Base](https://defillama.com/dexs/chains/base), [Arbitrum](https://defillama.com/dexs/chain/arbitrum), [Arbitrum lending](https://defillama.com/protocols/lending/arbitrum), [prediction markets, Ethereum](https://defillama.com/protocols/prediction-market/ethereum), [Polymarket](https://defillama.com/protocol/polymarket) +- Prediction markets: [Drift BET launch](https://www.theblock.co/post/311888/solana-based-drift-protocol-launches-prediction-market), [Jupiter and Polymarket](https://www.coindesk.com/markets/2026/02/02/jupiter-brings-polymarket-to-solana-and-lands-usd35-million-investment-deal), [Jupiter Forecast](https://solanacompass.com/news/jupiter-launches-forecast-solanas-first-native-prediction-market-with-multi-market-maker-quoting) +- Staking: [Lido deployed contracts](https://raw.githubusercontent.com/lidofinance/docs/main/docs/deployed-contracts/index.md), [Lido Hoodi](https://raw.githubusercontent.com/lidofinance/docs/main/docs/deployed-contracts/hoodi.md), [WithdrawalQueue.sol](https://raw.githubusercontent.com/lidofinance/core/master/contracts/0.8.9/WithdrawalQueue.sol), [Rocket Pool contracts](https://raw.githubusercontent.com/rocket-pool/docs.rocketpool.net/main/docs/en/protocol/contracts-integrations.md), [RocketDepositPool.sol](https://raw.githubusercontent.com/rocket-pool/rocketpool/master/contracts/contract/deposit/RocketDepositPool.sol), [ether.fi deployed contracts](https://etherfi.gitbook.io/etherfi/developers/contracts-and-integrations/deployed-contracts), [LiquidityPool.sol](https://raw.githubusercontent.com/etherfi-protocol/smart-contracts/master/src/core/LiquidityPool.sol), [eigenlayer-contracts README](https://raw.githubusercontent.com/Layr-Labs/eigenlayer-contracts/main/README.md), [Lista smart contracts](https://docs.bsc.lista.org/for-developer/liquid-staking-slisbnb/smart-contract.md), [ListaStakeManager.sol](https://raw.githubusercontent.com/lista-dao/synclub-contracts/master/contracts/ListaStakeManager.sol), [BNB staking developer guide](https://docs.bnbchain.org/bnb-smart-chain/staking/developer-guide/), [StakeHub.sol](https://raw.githubusercontent.com/bnb-chain/bsc-genesis-contract/master/contracts/StakeHub.sol), [Stader BNBx sunset](https://www.staderlabs.com/blogs/sunsetting-bnbx-focusing-stader-on-high-impact-ecosystems/), [SPL stake pool instruction.rs](https://raw.githubusercontent.com/solana-program/stake-pool/main/program/src/instruction.rs), [Jito deployed programs](https://www.jito.network/docs/jitosol/jitosol-liquid-staking/security/deployed-programs/), [Marinade contract addresses](https://docs.marinade.finance/developers/contract-addresses), [Marinade deposit.rs](https://raw.githubusercontent.com/marinade-finance/liquid-staking-program/main/programs/marinade-finance/src/instructions/user/deposit.rs), [BlazeStake addresses](https://stake-docs.solblaze.org/developers/addresses.md) \ No newline at end of file diff --git a/plan/agw/research/preset-catalog-2026-10-15/implementation-status.md b/plan/agw/research/preset-catalog-2026-10-15/implementation-status.md new file mode 100644 index 00000000..2760287b --- /dev/null +++ b/plan/agw/research/preset-catalog-2026-10-15/implementation-status.md @@ -0,0 +1,35 @@ +# Testnet preset catalog — October 15, 2026 + +User scope: testnet templates only. Missing caps default to zero. Source body and original native export are retained here; source.json records the Notion URL and observed edit date. The sibling README.md is downloaded EigenLayer documentation, not this implementation report. + +## Implemented + +- DEXES: Uniswap V3 (Sepolia, Base Sepolia, Arbitrum Sepolia), PancakeSwap V3 (BSC testnet). Explicit ERC20 pairs, wallet-recipient pins, amount caps, spender-pinned approvals. +- LENDING: Aave on the three Ethereum testnets, Moonwell Base Sepolia mUSDbC/mWETH, Venus BSC testnet vUSDT/vUSDC and their controllers. +- STAKING: EigenLayer Sepolia deposits only. +- Static tuple/fixed-array argument paths; exact decoded word-offset roundtrips remain supported. +- Explicit optional maxGasPerCall; omitted caps remain zero. + +DEX token omission is rejected rather than granting unrestricted swaps. This follows the conservative assumption stated during implementation; the optional follow-up question had no answer. Two supplied tokens fit; larger expansions exceeding 32 pins fail explicitly. + +## Exclusions and limits + +| Entry | Reason | +| --- | --- | +| Mainnet | User requested testnets only | +| Prediction | No approved entries | +| Dynamic-path V2 swaps | Cannot statically pin token paths with this policy | +| Solana protocol templates | Required ratios/layouts or multi-instruction flows are not represented by the current template API | +| Hoodi | Not a supported Push destination | +| Morpho, Compound, Jupiter Lend entries | Unconfirmed, unmaintained or stale deployments in the proposal | +| BNB StakeHub | Needs an explicit validator input | +| EigenLayer withdrawals | Proposal omits complete usable signatures; deposit-only template is labelled | + +Protocol sources and rpc-verification.json record official addresses, signatures, code presence and block numbers. These checks are not protocol audits or live trade tests. Aave/Moonwell/Venus testnet mock underlying assets can differ from SDK MOVEABLE tokens. Verify reserves, liquidity, destination balances and PRC20 routes separately. + +## Validation + +- Full unit suite: 2,084 passed, 12 skipped; 124 passing suites, one skipped. +- Targeted real-v6 contract suite: 14 passed, including generated DEX permissions, invalid recipient/token/amount rejection and get-to-update roundtrip. Gateway is a local recording fixture; destination protocols are not executed. +- Library, unit and local-harness TypeScript checks passed. +- No funded protocol transactions or mainnet broadcasts performed for this catalog. diff --git a/plan/agw/research/preset-catalog-2026-10-15/notion-export.zip b/plan/agw/research/preset-catalog-2026-10-15/notion-export.zip new file mode 100644 index 0000000000000000000000000000000000000000..c72aac5a80117aa00bcdd39a0797438202873a55 GIT binary patch literal 137253 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

d%pwG`^fLq4v?Ib!J6Q_sn9hu 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 C2`W$k literal 0 HcmV?d00001 diff --git a/plan/agw/research/preset-catalog-2026-10-15/pancake-package-source.json b/plan/agw/research/preset-catalog-2026-10-15/pancake-package-source.json new file mode 100644 index 00000000..bf9032b4 --- /dev/null +++ b/plan/agw/research/preset-catalog-2026-10-15/pancake-package-source.json @@ -0,0 +1,8 @@ +{ + "url": "https://registry.npmjs.org/@pancakeswap/smart-router/-/smart-router-7.8.0.tgz", + "integrity": "sha512-sBO48pIdWIsrBsclf/zdYlDJ/7n4f45HLterJW9yLPaLVzAY65/GbJbbFAxbPlIyIByyjwmeq1OB8V/5hIq11w==", + "files": [ + "package/dist/evm/abis/ISwapRouter02.d.ts.map", + "package/dist/evm/abis/ISwapRouter02.d.ts" + ] +} \ No newline at end of file diff --git a/plan/agw/research/preset-catalog-2026-10-15/pancake-router-package.txt b/plan/agw/research/preset-catalog-2026-10-15/pancake-router-package.txt new file mode 100644 index 00000000..3e9fa8d3 --- /dev/null +++ b/plan/agw/research/preset-catalog-2026-10-15/pancake-router-package.txt @@ -0,0 +1,10233 @@ +'use strict'; + +var chunkZNSTBYLO_js = require('./chunk-ZNSTBYLO.js'); +var chains = require('@pancakeswap/chains'); +var sdk = require('@pancakeswap/sdk'); +var viem = require('viem'); +var infinitySdk = require('@pancakeswap/infinity-sdk'); +var multicall = require('@pancakeswap/multicall'); +var swapSdkCore = require('@pancakeswap/swap-sdk-core'); +var stableSwapSdk = require('@pancakeswap/stable-swap-sdk'); +var v3Sdk = require('@pancakeswap/v3-sdk'); +var invariant6 = require('tiny-invariant'); +var debug = require('debug'); +var FixedReverseHeap = require('mnemonist/fixed-reverse-heap.js'); +var Queue = require('mnemonist/queue.js'); +var graphqlRequest = require('graphql-request'); +var tokenLists = require('@pancakeswap/token-lists'); +var tokens = require('@pancakeswap/tokens'); +var retry = require('async-retry'); +var stats = require('stats-lite'); +var zod = require('zod'); +var sum = require('lodash/sum.js'); + +function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; } + +var invariant6__default = /*#__PURE__*/_interopDefault(invariant6); +var debug__default = /*#__PURE__*/_interopDefault(debug); +var FixedReverseHeap__default = /*#__PURE__*/_interopDefault(FixedReverseHeap); +var Queue__default = /*#__PURE__*/_interopDefault(Queue); +var retry__default = /*#__PURE__*/_interopDefault(retry); +var stats__default = /*#__PURE__*/_interopDefault(stats); +var sum__default = /*#__PURE__*/_interopDefault(sum); + +// evm/abis/FeeOnTransferDetector.ts +var feeOnTransferDetectorAbi = [ + { + inputs: [ + { + internalType: "address", + name: "_factoryV2", + type: "address" + } + ], + stateMutability: "nonpayable", + type: "constructor" + }, + { + inputs: [], + name: "PairLookupFailed", + type: "error" + }, + { + inputs: [], + name: "SameToken", + type: "error" + }, + { + inputs: [ + { + internalType: "address[]", + name: "tokens", + type: "address[]" + }, + { + internalType: "address", + name: "baseToken", + type: "address" + }, + { + internalType: "uint256", + name: "amountToBorrow", + type: "uint256" + } + ], + name: "batchValidate", + outputs: [ + { + components: [ + { + internalType: "uint256", + name: "buyFeeBps", + type: "uint256" + }, + { + internalType: "uint256", + name: "sellFeeBps", + type: "uint256" + } + ], + internalType: "struct TokenFees[]", + name: "fotResults", + type: "tuple[]" + } + ], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + internalType: "address", + name: "", + type: "address" + }, + { + internalType: "uint256", + name: "amount0", + type: "uint256" + }, + { + internalType: "uint256", + name: "", + type: "uint256" + }, + { + internalType: "bytes", + name: "data", + type: "bytes" + } + ], + name: "pancakeCall", + outputs: [], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + internalType: "address", + name: "token", + type: "address" + }, + { + internalType: "address", + name: "baseToken", + type: "address" + }, + { + internalType: "uint256", + name: "amountToBorrow", + type: "uint256" + } + ], + name: "validate", + outputs: [ + { + components: [ + { + internalType: "uint256", + name: "buyFeeBps", + type: "uint256" + }, + { + internalType: "uint256", + name: "sellFeeBps", + type: "uint256" + } + ], + internalType: "struct TokenFees", + name: "fotResult", + type: "tuple" + } + ], + stateMutability: "nonpayable", + type: "function" + } +]; + +// evm/fot.ts +var feeOnTransferDetectorAddresses = { + [chains.ChainId.ETHEREUM]: "0xe9200516a475b9e6FD4D1c452858097F345A6760", + [chains.ChainId.SEPOLIA]: "0xD8b14F915b1b4b1c4EE4bF8321Bea018E72E5cf3", + [chains.ChainId.BSC]: "0x003BD52f589F23346E03fA431209C29cD599d693", + [chains.ChainId.BSC_TESTNET]: "0xE83BD854c1fBf54424b4d914163BF855aB1131Aa", + [chains.ChainId.ARBITRUM_ONE]: "0xD8b14F915b1b4b1c4EE4bF8321Bea018E72E5cf3", + [chains.ChainId.ARBITRUM_SEPOLIA]: "0xD8b14F915b1b4b1c4EE4bF8321Bea018E72E5cf3", + [chains.ChainId.BASE]: "0xD8b14F915b1b4b1c4EE4bF8321Bea018E72E5cf3", + [chains.ChainId.BASE_SEPOLIA]: "0xD8b14F915b1b4b1c4EE4bF8321Bea018E72E5cf3", + [chains.ChainId.ZKSYNC]: "0xED87D01674199355CEfC05648d17E037306d7962", + [chains.ChainId.ZKSYNC_TESTNET]: "0x869505373d830104130F95c1E7d578dE7E58C0a8", + [chains.ChainId.LINEA]: "0xD8b14F915b1b4b1c4EE4bF8321Bea018E72E5cf3", + [chains.ChainId.LINEA_TESTNET]: "0x3412378f17B1b44E8bcFD157EcE1a4f59DA5A77a" +}; +var getFeeOnTransferDetectorContract = (publicClient) => { + if (publicClient.chain && publicClient.chain.id in feeOnTransferDetectorAddresses) { + return viem.getContract({ + abi: feeOnTransferDetectorAbi, + address: feeOnTransferDetectorAddresses[publicClient.chain.id], + client: publicClient + }); + } + return null; +}; +var AMOUNT = 100000n; +async function fetchTokenFeeOnTransfer(publicClient, tokenAddress) { + if (!publicClient.chain) { + throw new Error("Chain not found"); + } + const contract = getFeeOnTransferDetectorContract(publicClient); + const baseToken = sdk.WNATIVE[publicClient.chain.id]; + if (!contract) { + throw new Error("Fee on transfer detector contract not found"); + } + if (!baseToken) { + throw new Error("Base token not found"); + } + if (tokenAddress.toLowerCase() === baseToken.address.toLowerCase()) { + throw new Error("Token is base token"); + } + return contract.simulate.validate([tokenAddress, baseToken.address, AMOUNT]); +} +async function fetchTokenFeeOnTransferBatch(publicClient, tokens) { + if (!publicClient.chain) { + throw new Error("Chain not found"); + } + const contract = getFeeOnTransferDetectorContract(publicClient); + if (!contract) { + throw new Error("Fee on transfer detector contract not found"); + } + const baseToken = sdk.WNATIVE[publicClient.chain.id]; + if (!baseToken) { + throw new Error("Base token not found"); + } + const tokensWithoutBaseToken = tokens.filter( + (token) => token.address.toLowerCase() !== baseToken.address.toLowerCase() + ); + return publicClient.multicall({ + allowFailure: true, + contracts: tokensWithoutBaseToken.map( + (token) => ({ + address: contract.address, + abi: feeOnTransferDetectorAbi, + functionName: "validate", + args: [token.address, baseToken.address, AMOUNT] + }) + ) + }); +} + +// evm/infinity-router/index.ts +var infinity_router_exports = {}; +chunkZNSTBYLO_js.__export(infinity_router_exports, { + APISchema: () => schema_exports, + Transformer: () => transformer_exports2, + fillClPoolsWithTicks: () => fillClPoolsWithTicks, + fillPoolsWithBins: () => fillPoolsWithBins, + getBestTrade: () => getBestTrade2, + getInfinityBinCandidatePools: () => getInfinityBinCandidatePools, + getInfinityBinCandidatePoolsWithoutBins: () => getInfinityBinCandidatePoolsWithoutBins, + getInfinityBinPoolsWithoutBins: () => getInfinityBinPoolsWithoutBins, + getInfinityCandidatePools: () => getInfinityCandidatePools, + getInfinityCandidatePoolsLite: () => getInfinityCandidatePoolsLite, + getInfinityClCandidatePools: () => getInfinityClCandidatePools, + getInfinityClCandidatePoolsWithoutTicks: () => getInfinityClCandidatePoolsWithoutTicks, + getInfinityClPoolsWithoutTicks: () => getInfinityClPoolsWithoutTicks, + getInfinityPoolFetchConfig: () => getInfinityPoolFetchConfig, + getInfinityPoolTvl: () => getInfinityPoolTvl, + getTickLensFetchConfig: () => getTickLensFetchConfig, + getTickQueryFetchConfig: () => getTickQueryFetchConfig, + getV3CandidatePools: () => getV3CandidatePools2, + getV3PoolFetchConfig: () => getV3PoolFetchConfig, + getV3Pools: () => getV3Pools, + log: () => log3, + logger: () => logger2, + metric: () => metric2, + parseRemoteInfinityStablePool: () => parseRemoteInfinityStablePool, + parseRemotePool: () => parseRemotePool, + parseRemoteStablePool: () => parseRemoteStablePool, + parseRemoteV2Pool: () => parseRemoteV2Pool, + parseRemoteV3Pool: () => parseRemoteV3Pool, + toLocalInfinityPool: () => toLocalInfinityPool, + toRemoteInfinityPool: () => toRemoteInfinityPool +}); + +// evm/infinity-router/constants/v3PoolFetchGasLimit.ts +var DEFAULT_FETCH_CONFIG = { + gasLimit: 3000000n, + retryGasMultiplier: 2 +}; +var INFI_BIN_POOL_FETCH_CONFIG = { + gasLimit: 300000n, + retryGasMultiplier: 2 +}; +var TICK_QUERY_FETCH_CONFIG = { + gasLimit: 10000000n, + retryGasMultiplier: 2 +}; +var TICK_LENS_FETCH_CONFIG = { + gasLimit: 500000n, + retryGasMultiplier: 2 +}; +var V3_POOL_FETCH_CONFIG = {}; +var INFI_POOL_FETCH_CONFIG = {}; +function getV3PoolFetchConfig(chainId) { + return V3_POOL_FETCH_CONFIG[chainId] || DEFAULT_FETCH_CONFIG; +} +function getInfinityPoolFetchConfig(chainId) { + return INFI_POOL_FETCH_CONFIG[chainId] || INFI_BIN_POOL_FETCH_CONFIG; +} +function getTickQueryFetchConfig() { + return TICK_QUERY_FETCH_CONFIG; +} +function getTickLensFetchConfig() { + return TICK_LENS_FETCH_CONFIG; +} +function getAmountDistribution(amount, distributionPercent) { + const percents = []; + const amounts = []; + for (let i = 1; i <= 100 / distributionPercent; i++) { + percents.push(i * distributionPercent); + amounts.push(amount.multiply(new sdk.Fraction(i * distributionPercent, 100))); + } + return [percents, amounts]; +} + +// ../utils/memoize.ts +function memoize(fn, resolver2) { + const cache = /* @__PURE__ */ new Map(); + const memoized = (...args) => { + const key = resolver2 ? resolver2(...args) : args[0]; + if (cache.has(key)) { + return cache.get(key); + } + const result = fn(...args); + cache.set(key, result); + return result; + }; + memoized.cache = cache; + return memoized; +} + +// ../utils/uniqBy.ts +function uniqBy(array, iteratee) { + const seen = /* @__PURE__ */ new Set(); + const result = []; + const getKey = typeof iteratee === "function" ? iteratee : (item) => item[iteratee]; + for (const item of array) { + const key = getKey(item); + if (!seen.has(key)) { + seen.add(key); + result.push(item); + } + } + return result; +} + +// ../utils/viem/parseUnits.ts +function parseUnits(value, decimals) { + let [integer, fraction = "0"] = value.split("."); + const negative = integer.startsWith("-"); + if (negative) + integer = integer.slice(1); + fraction = fraction.replace(/(0+)$/, ""); + if (decimals === 0) { + if (Math.round(Number(`.${fraction}`)) === 1) + integer = `${BigInt(integer) + 1n}`; + fraction = ""; + } else if (fraction.length > decimals) { + const [left, unit, right] = [ + fraction.slice(0, decimals - 1), + fraction.slice(decimals - 1, decimals), + fraction.slice(decimals) + ]; + const rounded = Math.round(Number(`${unit}.${right}`)); + if (rounded > 9) + fraction = `${BigInt(left) + BigInt(1)}0`.padStart(left.length + 1, "0"); + else + fraction = `${left}${rounded}`; + if (fraction.length > decimals) { + fraction = fraction.slice(1); + integer = `${BigInt(integer) + 1n}`; + } + fraction = fraction.slice(0, decimals); + } else { + fraction = fraction.padEnd(decimals, "0"); + } + return BigInt(`${negative ? "-" : ""}${integer}${fraction}`); +} + +// ../utils/tryParseAmount.ts +function tryParseAmount(value, currency, multiplier) { + if (!value || !currency) { + return void 0; + } + try { + const uiTypedValueParsed = parseUnits(value, currency.decimals).toString(); + const rawAmount = swapSdkCore.fromScaledUIAmount(BigInt(uiTypedValueParsed), multiplier ?? swapSdkCore.SCALED_UI_DENOMINATOR); + if (rawAmount !== 0n) { + if ("chainId" in currency && !("programId" in currency)) { + return swapSdkCore.CurrencyAmount.fromRawAmount(currency, rawAmount); + } + return swapSdkCore.UnifiedCurrencyAmount.fromRawAmount(currency, rawAmount); + } + } catch (error) { + console.debug(`Failed to parse input amount: "${value}"`, error); + } + return void 0; +} +var tryParseAmount_default = tryParseAmount; + +// evm/v3-router/types/infinityMixedQuoter.ts +var InfinityMixedQuoterActions = /* @__PURE__ */ ((InfinityMixedQuoterActions2) => { + InfinityMixedQuoterActions2[InfinityMixedQuoterActions2["SS_2_EXACT_INPUT_SINGLE"] = 0] = "SS_2_EXACT_INPUT_SINGLE"; + InfinityMixedQuoterActions2[InfinityMixedQuoterActions2["SS_3_EXACT_INPUT_SINGLE"] = 1] = "SS_3_EXACT_INPUT_SINGLE"; + InfinityMixedQuoterActions2[InfinityMixedQuoterActions2["V2_EXACT_INPUT_SINGLE"] = 2] = "V2_EXACT_INPUT_SINGLE"; + InfinityMixedQuoterActions2[InfinityMixedQuoterActions2["V3_EXACT_INPUT_SINGLE"] = 3] = "V3_EXACT_INPUT_SINGLE"; + InfinityMixedQuoterActions2[InfinityMixedQuoterActions2["INFI_CL_EXACT_INPUT_SINGLE"] = 4] = "INFI_CL_EXACT_INPUT_SINGLE"; + InfinityMixedQuoterActions2[InfinityMixedQuoterActions2["INFI_BIN_EXACT_INPUT_SINGLE"] = 5] = "INFI_BIN_EXACT_INPUT_SINGLE"; + return InfinityMixedQuoterActions2; +})(InfinityMixedQuoterActions || {}); + +// evm/v3-router/types/pool.ts +var PoolType = /* @__PURE__ */ ((PoolType2) => { + PoolType2[PoolType2["V2"] = 0] = "V2"; + PoolType2[PoolType2["V3"] = 1] = "V3"; + PoolType2[PoolType2["STABLE"] = 2] = "STABLE"; + PoolType2[PoolType2["InfinityCL"] = 3] = "InfinityCL"; + PoolType2[PoolType2["InfinityBIN"] = 4] = "InfinityBIN"; + PoolType2[PoolType2["InfinityStable"] = 5] = "InfinityStable"; + PoolType2[PoolType2["SVM"] = 6] = "SVM"; + PoolType2[PoolType2["MM"] = 7] = "MM"; + return PoolType2; +})(PoolType || {}); + +// evm/v3-router/types/route.ts +var RouteType = /* @__PURE__ */ ((RouteType2) => { + RouteType2[RouteType2["V2"] = 0] = "V2"; + RouteType2[RouteType2["V3"] = 1] = "V3"; + RouteType2[RouteType2["STABLE"] = 2] = "STABLE"; + RouteType2[RouteType2["MIXED"] = 3] = "MIXED"; + RouteType2[RouteType2["MM"] = 4] = "MM"; + RouteType2[RouteType2["InfinityCL"] = 5] = "InfinityCL"; + RouteType2[RouteType2["InfinityBIN"] = 6] = "InfinityBIN"; + RouteType2[RouteType2["InfinityStable"] = 7] = "InfinityStable"; + RouteType2[RouteType2["BRIDGE"] = 8] = "BRIDGE"; + RouteType2[RouteType2["SVM"] = 9] = "SVM"; + return RouteType2; +})(RouteType || {}); + +// evm/v3-router/utils/pool.ts +var INFINITY_STABLE_POOL_FEE_DENOMINATOR = 1e10; +function isV2Pool(pool) { + return pool.type === 0 /* V2 */; +} +function isV3Pool(pool) { + return pool.type === 1 /* V3 */; +} +function isStablePool(pool) { + return pool.type === 2 /* STABLE */ && pool.balances.length >= 2; +} +function isMMPool(pool) { + return pool.type === 7 /* MM */; +} +function isInfinityBinPool(pool) { + return pool.type === 4 /* InfinityBIN */; +} +function isInfinityClPool(pool) { + return pool.type === 3 /* InfinityCL */; +} +function isInfinityStablePool(pool) { + return pool.type === 5 /* InfinityStable */; +} +function involvesCurrency(pool, currency) { + const token = currency.wrapped; + if (isV2Pool(pool)) { + const { reserve0, reserve1 } = pool; + return reserve0.currency.equals(token) || reserve1.currency.equals(token); + } + if (isV3Pool(pool)) { + const { token0, token1 } = pool; + return token0.equals(token) || token1.equals(token); + } + if (isInfinityClPool(pool) || isInfinityBinPool(pool)) { + const { currency0, currency1 } = pool; + return currency0.equals(currency) || currency1.equals(currency) || currency0.wrapped.equals(token) || currency1.wrapped.equals(token); + } + if (isStablePool(pool)) { + const { balances } = pool; + return balances.some((b) => b.currency.equals(token)); + } + if (isMMPool(pool)) { + const { currency0, currency1 } = pool; + return currency0.wrapped.equals(token) || currency1.wrapped.equals(token); + } + if (isInfinityStablePool(pool)) { + const { reserve0, reserve1 } = pool; + return reserve0?.currency.equals(token) || reserve1?.currency.equals(token); + } + return false; +} +function getOutputCurrency(pool, currencyIn) { + const tokenIn = currencyIn.wrapped; + if (isV2Pool(pool)) { + const { reserve0, reserve1 } = pool; + return reserve0.currency.equals(tokenIn) ? reserve1.currency : reserve0.currency; + } + if (isV3Pool(pool)) { + const { token0, token1 } = pool; + return token0.equals(tokenIn) ? token1 : token0; + } + if (isStablePool(pool)) { + const { balances } = pool; + return balances[0].currency.equals(tokenIn) ? balances[1].currency : balances[0].currency; + } + if (isMMPool(pool)) { + const { currency0, currency1 } = pool; + return currency0.wrapped.equals(tokenIn) ? currency1 : currency0; + } + if (isInfinityClPool(pool) || isInfinityBinPool(pool) || isInfinityStablePool(pool)) { + const { currency0, currency1 } = pool; + return currency0.wrapped.equals(tokenIn) ? currency1 : currency0; + } + throw new Error("Cannot get output currency by invalid pool"); +} +var computeV3PoolAddress = memoize( + v3Sdk.computePoolAddress, + ({ deployerAddress, tokenA, tokenB, fee }) => `${tokenA.chainId}_${deployerAddress}_${tokenA.address}_${tokenB.address}_${fee}` +); +var computeV2PoolAddress = memoize( + sdk.Pair.getAddress, + (tokenA, tokenB) => `${tokenA.chainId}_${tokenA.address}_${tokenB.address}` +); +var getPoolAddress = (pool) => { + if (isStablePool(pool) || isV3Pool(pool)) { + return pool.address; + } + if (isV2Pool(pool)) { + const { reserve0, reserve1 } = pool; + return computeV2PoolAddress(reserve0.currency.wrapped, reserve1.currency.wrapped); + } + if (isInfinityBinPool(pool) || isInfinityClPool(pool) || isInfinityStablePool(pool)) { + return pool.id; + } + if (isMMPool(pool)) { + return ""; + } + return ""; +}; +var getPoolCurrency0 = (pool) => { + if (isV2Pool(pool)) { + return pool.reserve0.currency; + } + if (isV3Pool(pool)) { + return pool.token0; + } + if (isInfinityClPool(pool) || isInfinityBinPool(pool) || isInfinityStablePool(pool)) { + return pool.currency0; + } + if (isStablePool(pool)) { + return pool.balances[0].currency; + } + if (isMMPool(pool)) { + return pool.currency0; + } + throw new Error("Cannot get currency0 by invalid pool"); +}; +function getTokenPrice(pool, base, quote) { + if (isMMPool(pool)) { + const { inputAmount, outputAmount } = pool; + const baseIsInput = inputAmount.currency.wrapped.equals(base.wrapped); + return baseIsInput ? new sdk.Price(base, quote, inputAmount.quotient, outputAmount.quotient) : new sdk.Price(base, quote, outputAmount.quotient, inputAmount.quotient); + } + if (isV3Pool(pool)) { + const { token0, token1, fee, liquidity, sqrtRatioX96, tick } = pool; + const v3Pool = new v3Sdk.Pool(token0.wrapped, token1.wrapped, fee, sqrtRatioX96, liquidity, tick); + return v3Pool.priceOf(base.wrapped); + } + if (isInfinityClPool(pool)) { + const { currency0, currency1, fee, liquidity, sqrtRatioX96, tick } = pool; + const v3Pool = new v3Sdk.Pool(currency0.asToken, currency1.asToken, fee, sqrtRatioX96, liquidity, tick); + const baseToken = currency0.wrapped.equals(base.wrapped) ? currency0.asToken : base.wrapped; + const tokenPrice = v3Pool.priceOf(baseToken); + const [baseCurrency, quoteCurrency] = baseToken.equals(currency0.asToken) ? [currency0, currency1] : [currency1, currency0]; + return new sdk.Price(baseCurrency, quoteCurrency, tokenPrice.denominator, tokenPrice.numerator); + } + if (isInfinityBinPool(pool)) { + const { activeId, binStep, currency0, currency1 } = pool; + return infinitySdk.getBinPoolTokenPrice( + { + currencyX: currency0, + currencyY: currency1, + binStep: BigInt(binStep), + activeId: BigInt(activeId) + }, + base + ); + } + if (isV2Pool(pool)) { + const pair = new sdk.Pair(pool.reserve0.wrapped, pool.reserve1.wrapped); + return pair.priceOf(base.wrapped); + } + if (isStablePool(pool) || isInfinityStablePool(pool)) { + const stablePool = isInfinityStablePool(pool) ? convertInfinityStablePoolToStablePool(pool) : pool; + const { amplifier, balances, fee } = stablePool; + const baseBalance = balances.find((b) => b.currency.wrapped.equals(base.wrapped)); + const quoteBalance = balances.find((b) => b.currency.wrapped.equals(quote.wrapped)); + let probeAmountStr = "1"; + if (baseBalance && quoteBalance) { + const baseInTokens = Number(baseBalance.quotient) / 10 ** base.decimals; + const quoteInTokens = Number(quoteBalance.quotient) / 10 ** quote.decimals; + if (baseInTokens < 1 || quoteInTokens < 1) { + const smallerInTokens = baseInTokens < quoteInTokens ? baseInTokens : quoteInTokens; + probeAmountStr = smallerInTokens > 0 ? String(smallerInTokens) : "1"; + } + } + const baseIn = tryParseAmount_default(probeAmountStr, base); + if (!baseIn) { + throw new Error(`Cannot parse amount for ${base.symbol}`); + } + const quoteOut = stableSwapSdk.getSwapOutput({ + amplifier, + balances, + fee, + outputCurrency: quote, + amount: baseIn + }); + return new sdk.Price({ + baseAmount: baseIn, + quoteAmount: quoteOut + }); + } + return new sdk.Price(base, quote, 1n, 0n); +} +function convertInfinityStablePoolToStablePool(pool) { + if (!pool.hooks || pool.type !== 5 /* InfinityStable */) { + throw new Error(`convertInfinityStablePoolToStablePool: Invalid pool type: ${pool.type}`); + } + const balance0 = pool.reserve0 ?? sdk.CurrencyAmount.fromRawAmount(pool.currency0, 0); + const balance1 = pool.reserve1 ?? sdk.CurrencyAmount.fromRawAmount(pool.currency1, 0); + return { + type: 2 /* STABLE */, + address: pool.hooks, + balances: [balance0, balance1], + amplifier: BigInt(pool.amplifier ?? 0), + fee: new sdk.Percent(BigInt(pool.stableFee ?? 0), INFINITY_STABLE_POOL_FEE_DENOMINATOR) + }; +} + +// evm/v3-router/utils/encodeInfinityRouteToPath.ts +function encodeInfinityRouteToPath(route, exactOutput) { + if (route.pools.some((p) => !isInfinityClPool(p) && !isInfinityBinPool(p) && !isInfinityStablePool(p))) { + throw new Error("Failed to encode path keys. Invalid Infinity pool found in route."); + } + const currencyStart = exactOutput ? route.output : route.input; + const pools = exactOutput ? [...route.pools].reverse() : route.pools; + const { path } = pools.reduce( + ({ baseCurrency, path: path2 }, pool) => { + const isInfinityCl = isInfinityClPool(pool); + const isInfinityBin = isInfinityBinPool(pool); + const isInfinityStable = isInfinityStablePool(pool); + if (!isInfinityCl && !isInfinityBin && !isInfinityStable) + throw new Error(`Invalid Infinity pool ${pool}`); + const quoteCurrency = getOutputCurrency(pool, baseCurrency); + const hooksRegistration = pool.hooksRegistrationBitmap !== void 0 ? infinitySdk.decodeHooksRegistration(pool.hooksRegistrationBitmap) : void 0; + const parameters = infinitySdk.encodePoolParameters( + isInfinityCl || isInfinityStable ? { + tickSpacing: pool.tickSpacing, + hooksRegistration + } : { + binStep: pool.binStep, + hooksRegistration + } + ); + return { + baseCurrency: quoteCurrency, + path: [ + ...path2, + { + intermediateCurrency: swapSdkCore.getCurrencyAddress(quoteCurrency), + fee: infinitySdk.isDynamicFeeHook(pool.currency0.chainId, pool.hooks) ? infinitySdk.DYNAMIC_FEE_FLAG : pool.fee, + hooks: pool.hooks ?? viem.zeroAddress, + poolManager: pool.poolManager, + hookData: "0x", + parameters + } + ] + }; + }, + { baseCurrency: currencyStart, path: [] } + ); + return exactOutput ? path.reverse() : path; +} +function encodeMixedRouteToPath(route, exactOutput) { + const firstInputToken = route.input.wrapped; + const { path, types } = route.pools.reduce( + ({ inputToken, path: path2, types: types2 }, pool, index) => { + const outputToken = getOutputCurrency(pool, inputToken).wrapped; + const fee = isV3Pool(pool) ? pool.fee : chunkZNSTBYLO_js.V2_FEE_PATH_PLACEHOLDER; + if (index === 0) { + return { + inputToken: outputToken, + types: ["address", "uint24", "address"], + path: [inputToken.address, fee, outputToken.address] + }; + } + return { + inputToken: outputToken, + types: [...types2, "uint24", "address"], + path: [...path2, fee, outputToken.address] + }; + }, + { inputToken: firstInputToken, path: [], types: [] } + ); + return exactOutput ? viem.encodePacked(types.reverse(), path.reverse()) : viem.encodePacked(types, path); +} + +// evm/v3-router/utils/getCurrenciesOfPool.ts +function getCurrenciesOfPool(pool) { + if (isV2Pool(pool)) { + const { reserve0, reserve1 } = pool; + return [reserve0.currency, reserve1.currency]; + } + if (isV3Pool(pool)) { + const { token0, token1 } = pool; + return [token0, token1]; + } + if (isStablePool(pool)) { + const { balances } = pool; + return balances.map((b) => b.currency); + } + if (isInfinityClPool(pool) || isInfinityBinPool(pool) || isInfinityStablePool(pool)) { + const { currency0, currency1 } = pool; + return [currency0, currency1]; + } + throw new Error("Cannot get tokens by invalid pool"); +} +function getExecutionPrice(trade) { + if (!trade) { + return void 0; + } + const { inputAmount, outputAmount } = trade; + if (!inputAmount || !outputAmount) { + return void 0; + } + if (inputAmount.quotient === sdk.ZERO || outputAmount.quotient === sdk.ZERO) { + return void 0; + } + return new sdk.Price(inputAmount.currency, outputAmount.currency, inputAmount.quotient, outputAmount.quotient); +} +function getGasAccountingToken(chainId) { + const wnative = sdk.WNATIVE[chainId]; + if (wnative) { + return { token: wnative, nativeDecimals: wnative.decimals }; + } + const config = chains.getChainConfig(chainId); + const override = config?.gasTokenOverride; + const nativeDecimals = config?.nativeCurrency?.decimals; + if (!override || nativeDecimals === void 0) { + return null; + } + return { + token: new sdk.ERC20Token(chainId, override.address, override.decimals, override.symbol, override.name), + nativeDecimals + }; +} +function rescaleRawAmount(raw, from, to) { + if (from === to) + return raw; + return from > to ? raw / 10n ** BigInt(from - to) : raw * 10n ** BigInt(to - from); +} + +// evm/v3-router/utils/getOutputOfPools.ts +var getOutputOfPools = (pools, firstInputToken) => { + const { inputToken: outputToken } = pools.reduce( + ({ inputToken }, pool) => { + if (!involvesCurrency(pool, inputToken)) + throw new Error("PATH"); + const output = getOutputCurrency(pool, inputToken); + return { + inputToken: output + }; + }, + { inputToken: firstInputToken } + ); + return outputToken; +}; +function buildBaseRoute(pools, currencyIn, currencyOut) { + const path = [currencyIn]; + let prevIn = path[0]; + let routeType = null; + const updateRouteType = (pool, currentRouteType) => { + if (currentRouteType === null) { + return getRouteTypeFromPool(pool); + } + if (currentRouteType === 3 /* MIXED */ || currentRouteType !== getRouteTypeFromPool(pool)) { + return 3 /* MIXED */; + } + return currentRouteType; + }; + const lastPool = pools[pools.length - 1]; + for (const pool of pools) { + routeType = updateRouteType(pool, routeType); + if (pool === lastPool) { + path.push(currencyOut); + continue; + } + prevIn = getOutputCurrency(pool, prevIn); + path.push(prevIn); + } + if (routeType === null) { + throw new Error(`Invalid route type when constructing base route`); + } + return { + path, + pools, + type: routeType, + input: currencyIn, + output: currencyOut + }; +} +function getRouteTypeFromPool(pool) { + switch (pool.type) { + case 0 /* V2 */: + return 0 /* V2 */; + case 1 /* V3 */: + return 1 /* V3 */; + case 2 /* STABLE */: + return 2 /* STABLE */; + case 7 /* MM */: + return 4 /* MM */; + case 3 /* InfinityCL */: + case 5 /* InfinityStable */: + return 5 /* InfinityCL */; + case 4 /* InfinityBIN */: + return 6 /* InfinityBIN */; + default: + return 3 /* MIXED */; + } +} +function getRouteTypeByPools(pools) { + let routeType; + for (const p of pools) { + if (routeType === void 0) { + routeType = getRouteTypeFromPool(p); + continue; + } + if (routeType === 3 /* MIXED */ || routeType !== getRouteTypeFromPool(p)) { + routeType = 3 /* MIXED */; + continue; + } + } + invariant6__default.default(routeType !== void 0, "INVALID_ROUTE_TYPE"); + return routeType; +} +function getQuoteCurrency({ input, output }, baseCurrency) { + return baseCurrency.equals(input) ? output : input; +} +function wrapPrice(price) { + return new sdk.Price(price.baseCurrency.wrapped, price.quoteCurrency.wrapped, price.denominator, price.numerator); +} +function getMidPrice({ path, pools }) { + let i = 0; + let price = null; + const currencyIn = path[0]; + const currencyOut = path[path.length - 1]; + for (const pool of pools) { + const input = path[i]; + const output = path[i + 1]; + const poolPrice = wrapPrice(getTokenPrice(pool, input, output)); + price = price ? price.multiply(poolPrice) : poolPrice; + i += 1; + } + if (!price) { + throw new Error("Get mid price failed"); + } + return new sdk.Price(currencyIn, currencyOut, price.denominator, price.numerator); +} + +// evm/v3-router/utils/getPriceImpact.ts +function getPriceImpact(trade) { + let spotOutputAmount = sdk.CurrencyAmount.fromRawAmount(trade.outputAmount.currency, 0); + for (const route of trade.routes) { + const { inputAmount } = route; + const midPrice = getMidPrice(route); + spotOutputAmount = spotOutputAmount.add( + sdk.CurrencyAmount.fromRawAmount(trade.outputAmount.currency, midPrice.wrapped.quote(inputAmount.wrapped).quotient) + ); + } + if (spotOutputAmount.equalTo(0)) { + return sdk.ONE_HUNDRED_PERCENT; + } + const priceImpact = spotOutputAmount.subtract(trade.outputAmount).divide(spotOutputAmount); + return new sdk.Percent(priceImpact.numerator, priceImpact.denominator); +} + +// evm/v3-router/utils/getUsdGasToken.ts +function getUsdGasToken(chainId) { + return chunkZNSTBYLO_js.usdGasTokensByChain[chainId]?.[0] ?? null; +} + +// evm/v3-router/utils/isCurrenciesSameChain.ts +function isCurrenciesSameChain(...currencies) { + const chainId = currencies[0]?.chainId; + for (const currency of currencies) { + if (currency.chainId !== chainId) { + return false; + } + } + return true; +} +var SCOPE_PREFIX = "smart-router"; +var SCOPE = { + metric: "metric", + log: "log", + error: "error" +}; +var log_ = debug__default.default(SCOPE_PREFIX); +var metric = log_.extend(SCOPE.metric); +var log = log_.extend(SCOPE.log); +var logger = { + metric, + log, + error: debug__default.default(SCOPE_PREFIX).extend(SCOPE.error), + enable: (namespace) => { + let namespaces = namespace; + if (namespace.includes(",")) { + namespaces = namespace.split(",").map((ns) => `${SCOPE_PREFIX}:${ns}`).join(","); + } else { + namespaces = `${SCOPE_PREFIX}:${namespace}`; + } + debug__default.default.enable(namespaces); + } +}; +function maximumAmountIn(trade, slippage, amountIn = trade.inputAmount) { + if (trade.tradeType === sdk.TradeType.EXACT_INPUT) { + return amountIn; + } + const slippageAdjustedAmountIn = new sdk.Fraction(sdk.ONE).add(slippage).multiply(amountIn.quotient).quotient; + return sdk.CurrencyAmount.fromRawAmount(amountIn.currency, slippageAdjustedAmountIn); +} +function minimumAmountOut(trade, slippage, amountOut = trade.outputAmount) { + if (trade.tradeType === sdk.TradeType.EXACT_OUTPUT) { + return amountOut; + } + const slippageAdjustedAmountOut = new sdk.Fraction(sdk.ONE).add(slippage).invert().multiply(amountOut.quotient).quotient; + return sdk.CurrencyAmount.fromRawAmount(amountOut.currency, slippageAdjustedAmountOut); +} + +// evm/v3-router/utils/partitionMixedRouteByProtocol.ts +var partitionMixedRouteByProtocol = (route) => { + const acc = []; + let left = 0; + let right = 0; + while (right < route.pools.length) { + if (route.pools[left].type !== route.pools[right].type) { + acc.push(route.pools.slice(left, right)); + left = right; + } + right++; + if (right === route.pools.length) { + acc.push(route.pools.slice(left, right)); + } + } + return acc; +}; + +// evm/abis/ISwapRouter02.ts +var swapRouter02Abi = [ + { + inputs: [ + { internalType: "address", name: "_factoryV2", type: "address" }, + { internalType: "address", name: "_deployer", type: "address" }, + { internalType: "address", name: "_factoryV3", type: "address" }, + { internalType: "address", name: "_positionManager", type: "address" }, + { internalType: "address", name: "_stableFactory", type: "address" }, + { internalType: "address", name: "_stableInfo", type: "address" }, + { internalType: "address", name: "_WETH9", type: "address" } + ], + stateMutability: "nonpayable", + type: "constructor" + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "previousOwner", type: "address" }, + { indexed: true, internalType: "address", name: "newOwner", type: "address" } + ], + name: "OwnershipTransferred", + type: "event" + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "factory", type: "address" }, + { indexed: true, internalType: "address", name: "info", type: "address" } + ], + name: "SetStableSwap", + type: "event" + }, + { + inputs: [], + name: "WETH9", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function" + }, + { + inputs: [{ internalType: "address", name: "token", type: "address" }], + name: "approveMax", + outputs: [], + stateMutability: "payable", + type: "function" + }, + { + inputs: [{ internalType: "address", name: "token", type: "address" }], + name: "approveMaxMinusOne", + outputs: [], + stateMutability: "payable", + type: "function" + }, + { + inputs: [{ internalType: "address", name: "token", type: "address" }], + name: "approveZeroThenMax", + outputs: [], + stateMutability: "payable", + type: "function" + }, + { + inputs: [{ internalType: "address", name: "token", type: "address" }], + name: "approveZeroThenMaxMinusOne", + outputs: [], + stateMutability: "payable", + type: "function" + }, + { + inputs: [{ internalType: "bytes", name: "data", type: "bytes" }], + name: "callPositionManager", + outputs: [{ internalType: "bytes", name: "result", type: "bytes" }], + stateMutability: "payable", + type: "function" + }, + { + inputs: [ + { internalType: "bytes[]", name: "paths", type: "bytes[]" }, + { internalType: "uint128[]", name: "amounts", type: "uint128[]" }, + { internalType: "uint24", name: "maximumTickDivergence", type: "uint24" }, + { internalType: "uint32", name: "secondsAgo", type: "uint32" } + ], + name: "checkOracleSlippage", + outputs: [], + stateMutability: "view", + type: "function" + }, + { + inputs: [ + { internalType: "bytes", name: "path", type: "bytes" }, + { internalType: "uint24", name: "maximumTickDivergence", type: "uint24" }, + { internalType: "uint32", name: "secondsAgo", type: "uint32" } + ], + name: "checkOracleSlippage", + outputs: [], + stateMutability: "view", + type: "function" + }, + { + inputs: [], + name: "deployer", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function" + }, + { + inputs: [ + { + components: [ + { internalType: "bytes", name: "path", type: "bytes" }, + { internalType: "address", name: "recipient", type: "address" }, + { internalType: "uint256", name: "amountIn", type: "uint256" }, + { internalType: "uint256", name: "amountOutMinimum", type: "uint256" } + ], + internalType: "struct IV3SwapRouter.ExactInputParams", + name: "params", + type: "tuple" + } + ], + name: "exactInput", + outputs: [{ internalType: "uint256", name: "amountOut", type: "uint256" }], + stateMutability: "payable", + type: "function" + }, + { + inputs: [ + { + components: [ + { internalType: "address", name: "tokenIn", type: "address" }, + { internalType: "address", name: "tokenOut", type: "address" }, + { internalType: "uint24", name: "fee", type: "uint24" }, + { internalType: "address", name: "recipient", type: "address" }, + { internalType: "uint256", name: "amountIn", type: "uint256" }, + { internalType: "uint256", name: "amountOutMinimum", type: "uint256" }, + { internalType: "uint160", name: "sqrtPriceLimitX96", type: "uint160" } + ], + internalType: "struct IV3SwapRouter.ExactInputSingleParams", + name: "params", + type: "tuple" + } + ], + name: "exactInputSingle", + outputs: [{ internalType: "uint256", name: "amountOut", type: "uint256" }], + stateMutability: "payable", + type: "function" + }, + { + inputs: [ + { internalType: "address[]", name: "path", type: "address[]" }, + { internalType: "uint256[]", name: "flag", type: "uint256[]" }, + { internalType: "uint256", name: "amountIn", type: "uint256" }, + { internalType: "uint256", name: "amountOutMin", type: "uint256" }, + { internalType: "address", name: "to", type: "address" } + ], + name: "exactInputStableSwap", + outputs: [{ internalType: "uint256", name: "amountOut", type: "uint256" }], + stateMutability: "payable", + type: "function" + }, + { + inputs: [ + { + components: [ + { internalType: "bytes", name: "path", type: "bytes" }, + { internalType: "address", name: "recipient", type: "address" }, + { internalType: "uint256", name: "amountOut", type: "uint256" }, + { internalType: "uint256", name: "amountInMaximum", type: "uint256" } + ], + internalType: "struct IV3SwapRouter.ExactOutputParams", + name: "params", + type: "tuple" + } + ], + name: "exactOutput", + outputs: [{ internalType: "uint256", name: "amountIn", type: "uint256" }], + stateMutability: "payable", + type: "function" + }, + { + inputs: [ + { + components: [ + { internalType: "address", name: "tokenIn", type: "address" }, + { internalType: "address", name: "tokenOut", type: "address" }, + { internalType: "uint24", name: "fee", type: "uint24" }, + { internalType: "address", name: "recipient", type: "address" }, + { internalType: "uint256", name: "amountOut", type: "uint256" }, + { internalType: "uint256", name: "amountInMaximum", type: "uint256" }, + { internalType: "uint160", name: "sqrtPriceLimitX96", type: "uint160" } + ], + internalType: "struct IV3SwapRouter.ExactOutputSingleParams", + name: "params", + type: "tuple" + } + ], + name: "exactOutputSingle", + outputs: [{ internalType: "uint256", name: "amountIn", type: "uint256" }], + stateMutability: "payable", + type: "function" + }, + { + inputs: [ + { internalType: "address[]", name: "path", type: "address[]" }, + { internalType: "uint256[]", name: "flag", type: "uint256[]" }, + { internalType: "uint256", name: "amountOut", type: "uint256" }, + { internalType: "uint256", name: "amountInMax", type: "uint256" }, + { internalType: "address", name: "to", type: "address" } + ], + name: "exactOutputStableSwap", + outputs: [{ internalType: "uint256", name: "amountIn", type: "uint256" }], + stateMutability: "payable", + type: "function" + }, + { + inputs: [], + name: "factory", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function" + }, + { + inputs: [], + name: "factoryV2", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function" + }, + { + inputs: [ + { internalType: "address", name: "token", type: "address" }, + { internalType: "uint256", name: "amount", type: "uint256" } + ], + name: "getApprovalType", + outputs: [{ internalType: "enum IApproveAndCall.ApprovalType", name: "", type: "uint8" }], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + components: [ + { internalType: "address", name: "token0", type: "address" }, + { internalType: "address", name: "token1", type: "address" }, + { internalType: "uint256", name: "tokenId", type: "uint256" }, + { internalType: "uint256", name: "amount0Min", type: "uint256" }, + { internalType: "uint256", name: "amount1Min", type: "uint256" } + ], + internalType: "struct IApproveAndCall.IncreaseLiquidityParams", + name: "params", + type: "tuple" + } + ], + name: "increaseLiquidity", + outputs: [{ internalType: "bytes", name: "result", type: "bytes" }], + stateMutability: "payable", + type: "function" + }, + { + inputs: [ + { + components: [ + { internalType: "address", name: "token0", type: "address" }, + { internalType: "address", name: "token1", type: "address" }, + { internalType: "uint24", name: "fee", type: "uint24" }, + { internalType: "int24", name: "tickLower", type: "int24" }, + { internalType: "int24", name: "tickUpper", type: "int24" }, + { internalType: "uint256", name: "amount0Min", type: "uint256" }, + { internalType: "uint256", name: "amount1Min", type: "uint256" }, + { internalType: "address", name: "recipient", type: "address" } + ], + internalType: "struct IApproveAndCall.MintParams", + name: "params", + type: "tuple" + } + ], + name: "mint", + outputs: [{ internalType: "bytes", name: "result", type: "bytes" }], + stateMutability: "payable", + type: "function" + }, + { + inputs: [ + { internalType: "bytes32", name: "previousBlockhash", type: "bytes32" }, + { internalType: "bytes[]", name: "data", type: "bytes[]" } + ], + name: "multicall", + outputs: [{ internalType: "bytes[]", name: "", type: "bytes[]" }], + stateMutability: "payable", + type: "function" + }, + { + inputs: [ + { internalType: "uint256", name: "deadline", type: "uint256" }, + { internalType: "bytes[]", name: "data", type: "bytes[]" } + ], + name: "multicall", + outputs: [{ internalType: "bytes[]", name: "", type: "bytes[]" }], + stateMutability: "payable", + type: "function" + }, + { + inputs: [{ internalType: "bytes[]", name: "data", type: "bytes[]" }], + name: "multicall", + outputs: [{ internalType: "bytes[]", name: "results", type: "bytes[]" }], + stateMutability: "payable", + type: "function" + }, + { + inputs: [], + name: "owner", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function" + }, + { + inputs: [ + { internalType: "int256", name: "amount0Delta", type: "int256" }, + { internalType: "int256", name: "amount1Delta", type: "int256" }, + { internalType: "bytes", name: "_data", type: "bytes" } + ], + name: "pancakeV3SwapCallback", + outputs: [], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [], + name: "positionManager", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function" + }, + { + inputs: [ + { internalType: "address", name: "token", type: "address" }, + { internalType: "uint256", name: "value", type: "uint256" } + ], + name: "pull", + outputs: [], + stateMutability: "payable", + type: "function" + }, + { inputs: [], name: "refundETH", outputs: [], stateMutability: "payable", type: "function" }, + { inputs: [], name: "renounceOwnership", outputs: [], stateMutability: "nonpayable", type: "function" }, + { + inputs: [ + { internalType: "address", name: "token", type: "address" }, + { internalType: "uint256", name: "value", type: "uint256" }, + { internalType: "uint256", name: "deadline", type: "uint256" }, + { internalType: "uint8", name: "v", type: "uint8" }, + { internalType: "bytes32", name: "r", type: "bytes32" }, + { internalType: "bytes32", name: "s", type: "bytes32" } + ], + name: "selfPermit", + outputs: [], + stateMutability: "payable", + type: "function" + }, + { + inputs: [ + { internalType: "address", name: "token", type: "address" }, + { internalType: "uint256", name: "nonce", type: "uint256" }, + { internalType: "uint256", name: "expiry", type: "uint256" }, + { internalType: "uint8", name: "v", type: "uint8" }, + { internalType: "bytes32", name: "r", type: "bytes32" }, + { internalType: "bytes32", name: "s", type: "bytes32" } + ], + name: "selfPermitAllowed", + outputs: [], + stateMutability: "payable", + type: "function" + }, + { + inputs: [ + { internalType: "address", name: "token", type: "address" }, + { internalType: "uint256", name: "nonce", type: "uint256" }, + { internalType: "uint256", name: "expiry", type: "uint256" }, + { internalType: "uint8", name: "v", type: "uint8" }, + { internalType: "bytes32", name: "r", type: "bytes32" }, + { internalType: "bytes32", name: "s", type: "bytes32" } + ], + name: "selfPermitAllowedIfNecessary", + outputs: [], + stateMutability: "payable", + type: "function" + }, + { + inputs: [ + { internalType: "address", name: "token", type: "address" }, + { internalType: "uint256", name: "value", type: "uint256" }, + { internalType: "uint256", name: "deadline", type: "uint256" }, + { internalType: "uint8", name: "v", type: "uint8" }, + { internalType: "bytes32", name: "r", type: "bytes32" }, + { internalType: "bytes32", name: "s", type: "bytes32" } + ], + name: "selfPermitIfNecessary", + outputs: [], + stateMutability: "payable", + type: "function" + }, + { + inputs: [ + { internalType: "address", name: "_factory", type: "address" }, + { internalType: "address", name: "_info", type: "address" } + ], + name: "setStableSwap", + outputs: [], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [], + name: "stableSwapFactory", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function" + }, + { + inputs: [], + name: "stableSwapInfo", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function" + }, + { + inputs: [ + { internalType: "uint256", name: "amountIn", type: "uint256" }, + { internalType: "uint256", name: "amountOutMin", type: "uint256" }, + { internalType: "address[]", name: "path", type: "address[]" }, + { internalType: "address", name: "to", type: "address" } + ], + name: "swapExactTokensForTokens", + outputs: [{ internalType: "uint256", name: "amountOut", type: "uint256" }], + stateMutability: "payable", + type: "function" + }, + { + inputs: [ + { internalType: "uint256", name: "amountOut", type: "uint256" }, + { internalType: "uint256", name: "amountInMax", type: "uint256" }, + { internalType: "address[]", name: "path", type: "address[]" }, + { internalType: "address", name: "to", type: "address" } + ], + name: "swapTokensForExactTokens", + outputs: [{ internalType: "uint256", name: "amountIn", type: "uint256" }], + stateMutability: "payable", + type: "function" + }, + { + inputs: [ + { internalType: "address", name: "token", type: "address" }, + { internalType: "uint256", name: "amountMinimum", type: "uint256" }, + { internalType: "address", name: "recipient", type: "address" } + ], + name: "sweepToken", + outputs: [], + stateMutability: "payable", + type: "function" + }, + { + inputs: [ + { internalType: "address", name: "token", type: "address" }, + { internalType: "uint256", name: "amountMinimum", type: "uint256" } + ], + name: "sweepToken", + outputs: [], + stateMutability: "payable", + type: "function" + }, + { + inputs: [ + { internalType: "address", name: "token", type: "address" }, + { internalType: "uint256", name: "amountMinimum", type: "uint256" }, + { internalType: "uint256", name: "feeBips", type: "uint256" }, + { internalType: "address", name: "feeRecipient", type: "address" } + ], + name: "sweepTokenWithFee", + outputs: [], + stateMutability: "payable", + type: "function" + }, + { + inputs: [ + { internalType: "address", name: "token", type: "address" }, + { internalType: "uint256", name: "amountMinimum", type: "uint256" }, + { internalType: "address", name: "recipient", type: "address" }, + { internalType: "uint256", name: "feeBips", type: "uint256" }, + { internalType: "address", name: "feeRecipient", type: "address" } + ], + name: "sweepTokenWithFee", + outputs: [], + stateMutability: "payable", + type: "function" + }, + { + inputs: [{ internalType: "address", name: "newOwner", type: "address" }], + name: "transferOwnership", + outputs: [], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { internalType: "uint256", name: "amountMinimum", type: "uint256" }, + { internalType: "address", name: "recipient", type: "address" } + ], + name: "unwrapWETH9", + outputs: [], + stateMutability: "payable", + type: "function" + }, + { + inputs: [ + { internalType: "uint256", name: "amountMinimum", type: "uint256" }, + { internalType: "address", name: "recipient", type: "address" }, + { internalType: "uint256", name: "feeBips", type: "uint256" }, + { internalType: "address", name: "feeRecipient", type: "address" } + ], + name: "unwrapWETH9WithFee", + outputs: [], + stateMutability: "payable", + type: "function" + }, + { + inputs: [ + { internalType: "uint256", name: "amountMinimum", type: "uint256" }, + { internalType: "uint256", name: "feeBips", type: "uint256" }, + { internalType: "address", name: "feeRecipient", type: "address" } + ], + name: "unwrapWETH9WithFee", + outputs: [], + stateMutability: "payable", + type: "function" + }, + { + inputs: [{ internalType: "uint256", name: "value", type: "uint256" }], + name: "wrapETH", + outputs: [], + stateMutability: "payable", + type: "function" + }, + { stateMutability: "payable", type: "receive" } +]; + +// evm/abis/IApproveAndCall.ts +var approveAndCallAbi = [ + { + inputs: [ + { + internalType: "address", + name: "token", + type: "address" + } + ], + name: "approveMax", + outputs: [], + stateMutability: "payable", + type: "function" + }, + { + inputs: [ + { + internalType: "address", + name: "token", + type: "address" + } + ], + name: "approveMaxMinusOne", + outputs: [], + stateMutability: "payable", + type: "function" + }, + { + inputs: [ + { + internalType: "address", + name: "token", + type: "address" + } + ], + name: "approveZeroThenMax", + outputs: [], + stateMutability: "payable", + type: "function" + }, + { + inputs: [ + { + internalType: "address", + name: "token", + type: "address" + } + ], + name: "approveZeroThenMaxMinusOne", + outputs: [], + stateMutability: "payable", + type: "function" + }, + { + inputs: [ + { + internalType: "bytes", + name: "data", + type: "bytes" + } + ], + name: "callPositionManager", + outputs: [ + { + internalType: "bytes", + name: "result", + type: "bytes" + } + ], + stateMutability: "payable", + type: "function" + }, + { + inputs: [ + { + internalType: "address", + name: "token", + type: "address" + }, + { + internalType: "uint256", + name: "amount", + type: "uint256" + } + ], + name: "getApprovalType", + outputs: [ + { + internalType: "enum IApproveAndCall.ApprovalType", + name: "", + type: "uint8" + } + ], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + components: [ + { + internalType: "address", + name: "token0", + type: "address" + }, + { + internalType: "address", + name: "token1", + type: "address" + }, + { + internalType: "uint256", + name: "tokenId", + type: "uint256" + }, + { + internalType: "uint256", + name: "amount0Min", + type: "uint256" + }, + { + internalType: "uint256", + name: "amount1Min", + type: "uint256" + } + ], + internalType: "struct IApproveAndCall.IncreaseLiquidityParams", + name: "params", + type: "tuple" + } + ], + name: "increaseLiquidity", + outputs: [ + { + internalType: "bytes", + name: "result", + type: "bytes" + } + ], + stateMutability: "payable", + type: "function" + }, + { + inputs: [ + { + components: [ + { + internalType: "address", + name: "token0", + type: "address" + }, + { + internalType: "address", + name: "token1", + type: "address" + }, + { + internalType: "uint24", + name: "fee", + type: "uint24" + }, + { + internalType: "int24", + name: "tickLower", + type: "int24" + }, + { + internalType: "int24", + name: "tickUpper", + type: "int24" + }, + { + internalType: "uint256", + name: "amount0Min", + type: "uint256" + }, + { + internalType: "uint256", + name: "amount1Min", + type: "uint256" + }, + { + internalType: "address", + name: "recipient", + type: "address" + } + ], + internalType: "struct IApproveAndCall.MintParams", + name: "params", + type: "tuple" + } + ], + name: "mint", + outputs: [ + { + internalType: "bytes", + name: "result", + type: "bytes" + } + ], + stateMutability: "payable", + type: "function" + } +]; + +// evm/v3-router/utils/approveAndCall.ts +function isMint(options) { + return Object.keys(options).some((k) => k === "recipient"); +} +var _ApproveAndCall = class { + /** + * Cannot be constructed. + */ + // eslint-disable-next-line no-useless-constructor, @typescript-eslint/no-empty-function + constructor() { + } + static encodeApproveMax(token) { + return viem.encodeFunctionData({ + abi: _ApproveAndCall.ABI, + functionName: "approveMax", + args: [token.address] + }); + } + static encodeApproveMaxMinusOne(token) { + return viem.encodeFunctionData({ + abi: _ApproveAndCall.ABI, + functionName: "approveMaxMinusOne", + args: [token.address] + }); + } + static encodeApproveZeroThenMax(token) { + return viem.encodeFunctionData({ + abi: _ApproveAndCall.ABI, + functionName: "approveZeroThenMax", + args: [token.address] + }); + } + static encodeApproveZeroThenMaxMinusOne(token) { + return viem.encodeFunctionData({ + abi: _ApproveAndCall.ABI, + functionName: "approveZeroThenMaxMinusOne", + args: [token.address] + }); + } + static encodeCallPositionManager(calldatas) { + invariant6__default.default(calldatas.length > 0, "NULL_CALLDATA"); + if (calldatas.length === 1) { + return viem.encodeFunctionData({ + abi: _ApproveAndCall.ABI, + functionName: "callPositionManager", + args: calldatas + }); + } + const encodedMulticall = viem.encodeFunctionData({ + abi: v3Sdk.NonfungiblePositionManager.ABI, + functionName: "multicall", + args: [calldatas] + }); + return viem.encodeFunctionData({ + abi: _ApproveAndCall.ABI, + functionName: "callPositionManager", + args: [encodedMulticall] + }); + } + /** + * Encode adding liquidity to a position in the nft manager contract + * @param position Forcasted position with expected amount out from swap + * @param minimalPosition Forcasted position with custom minimal token amounts + * @param addLiquidityOptions Options for adding liquidity + * @param slippageTolerance Defines maximum slippage + */ + static encodeAddLiquidity(position, minimalPosition, addLiquidityOptions, slippageTolerance) { + let { amount0: amount0Min, amount1: amount1Min } = position.mintAmountsWithSlippage(slippageTolerance); + if (minimalPosition.amount0.quotient < amount0Min) { + amount0Min = minimalPosition.amount0.quotient; + } + if (minimalPosition.amount1.quotient < amount1Min) { + amount1Min = minimalPosition.amount1.quotient; + } + if (isMint(addLiquidityOptions)) { + return viem.encodeFunctionData({ + abi: _ApproveAndCall.ABI, + functionName: "mint", + args: [ + { + token0: position.pool.token0.address, + token1: position.pool.token1.address, + fee: position.pool.fee, + tickLower: position.tickLower, + tickUpper: position.tickUpper, + amount0Min, + amount1Min, + recipient: addLiquidityOptions.recipient + } + ] + }); + } + return viem.encodeFunctionData({ + abi: _ApproveAndCall.ABI, + functionName: "increaseLiquidity", + args: [ + { + token0: position.pool.token0.address, + token1: position.pool.token1.address, + amount0Min, + amount1Min, + tokenId: BigInt(addLiquidityOptions.tokenId) + } + ] + }); + } + static encodeApprove(token, approvalType) { + switch (approvalType) { + case 1 /* MAX */: + return _ApproveAndCall.encodeApproveMax(token.wrapped); + case 2 /* MAX_MINUS_ONE */: + return _ApproveAndCall.encodeApproveMaxMinusOne(token.wrapped); + case 3 /* ZERO_THEN_MAX */: + return _ApproveAndCall.encodeApproveZeroThenMax(token.wrapped); + case 4 /* ZERO_THEN_MAX_MINUS_ONE */: + return _ApproveAndCall.encodeApproveZeroThenMaxMinusOne(token.wrapped); + default: + throw new Error("Error: invalid ApprovalType"); + } + } +}; +var ApproveAndCall = _ApproveAndCall; +ApproveAndCall.ABI = approveAndCallAbi; + +// evm/abis/IMulticallExtended.ts +var multicallExtendedAbi = [ + { + inputs: [ + { + internalType: "bytes32", + name: "previousBlockhash", + type: "bytes32" + }, + { + internalType: "bytes[]", + name: "data", + type: "bytes[]" + } + ], + name: "multicall", + outputs: [ + { + internalType: "bytes[]", + name: "results", + type: "bytes[]" + } + ], + stateMutability: "payable", + type: "function" + }, + { + inputs: [ + { + internalType: "uint256", + name: "deadline", + type: "uint256" + }, + { + internalType: "bytes[]", + name: "data", + type: "bytes[]" + } + ], + name: "multicall", + outputs: [ + { + internalType: "bytes[]", + name: "results", + type: "bytes[]" + } + ], + stateMutability: "payable", + type: "function" + }, + { + inputs: [ + { + internalType: "bytes[]", + name: "data", + type: "bytes[]" + } + ], + name: "multicall", + outputs: [ + { + internalType: "bytes[]", + name: "results", + type: "bytes[]" + } + ], + stateMutability: "payable", + type: "function" + } +]; + +// evm/v3-router/utils/multicallExtended.ts +function validateAndParseBytes32(bytes32) { + if (!bytes32.match(/^0x[0-9a-fA-F]{64}$/)) { + throw new Error(`${bytes32} is not valid bytes32.`); + } + return bytes32.toLowerCase(); +} +var _MulticallExtended = class { + /** + * Cannot be constructed. + */ + // eslint-disable-next-line no-useless-constructor, @typescript-eslint/no-empty-function + constructor() { + } + static encodeMulticall(calldatas, validation) { + if (typeof validation === "undefined") { + return v3Sdk.Multicall.encodeMulticall(calldatas); + } + if (!Array.isArray(calldatas)) { + calldatas = [calldatas]; + } + if (typeof validation === "string" && validation.startsWith("0x")) { + const previousBlockhash = validateAndParseBytes32(validation); + return viem.encodeFunctionData({ + abi: _MulticallExtended.ABI, + functionName: "multicall", + args: [previousBlockhash, calldatas] + }); + } + const deadline = BigInt(validation); + return viem.encodeFunctionData({ + abi: _MulticallExtended.ABI, + functionName: "multicall", + args: [deadline, calldatas] + }); + } +}; +var MulticallExtended = _MulticallExtended; +MulticallExtended.ABI = multicallExtendedAbi; + +// evm/abis/IPeripheryPaymentsWithFeeExtended.ts +var peripheryPaymentsWithFeeExtendedAbi = [ + { + inputs: [ + { + internalType: "address", + name: "token", + type: "address" + }, + { + internalType: "uint256", + name: "value", + type: "uint256" + } + ], + name: "pull", + outputs: [], + stateMutability: "payable", + type: "function" + }, + { + inputs: [], + name: "refundETH", + outputs: [], + stateMutability: "payable", + type: "function" + }, + { + inputs: [ + { + internalType: "address", + name: "token", + type: "address" + }, + { + internalType: "uint256", + name: "amountMinimum", + type: "uint256" + } + ], + name: "sweepToken", + outputs: [], + stateMutability: "payable", + type: "function" + }, + { + inputs: [ + { + internalType: "address", + name: "token", + type: "address" + }, + { + internalType: "uint256", + name: "amountMinimum", + type: "uint256" + }, + { + internalType: "address", + name: "recipient", + type: "address" + } + ], + name: "sweepToken", + outputs: [], + stateMutability: "payable", + type: "function" + }, + { + inputs: [ + { + internalType: "address", + name: "token", + type: "address" + }, + { + internalType: "uint256", + name: "amountMinimum", + type: "uint256" + }, + { + internalType: "uint256", + name: "feeBips", + type: "uint256" + }, + { + internalType: "address", + name: "feeRecipient", + type: "address" + } + ], + name: "sweepTokenWithFee", + outputs: [], + stateMutability: "payable", + type: "function" + }, + { + inputs: [ + { + internalType: "address", + name: "token", + type: "address" + }, + { + internalType: "uint256", + name: "amountMinimum", + type: "uint256" + }, + { + internalType: "address", + name: "recipient", + type: "address" + }, + { + internalType: "uint256", + name: "feeBips", + type: "uint256" + }, + { + internalType: "address", + name: "feeRecipient", + type: "address" + } + ], + name: "sweepTokenWithFee", + outputs: [], + stateMutability: "payable", + type: "function" + }, + { + inputs: [ + { + internalType: "uint256", + name: "amountMinimum", + type: "uint256" + } + ], + name: "unwrapWETH9", + outputs: [], + stateMutability: "payable", + type: "function" + }, + { + inputs: [ + { + internalType: "uint256", + name: "amountMinimum", + type: "uint256" + }, + { + internalType: "address", + name: "recipient", + type: "address" + } + ], + name: "unwrapWETH9", + outputs: [], + stateMutability: "payable", + type: "function" + }, + { + inputs: [ + { + internalType: "uint256", + name: "amountMinimum", + type: "uint256" + }, + { + internalType: "uint256", + name: "feeBips", + type: "uint256" + }, + { + internalType: "address", + name: "feeRecipient", + type: "address" + } + ], + name: "unwrapWETH9WithFee", + outputs: [], + stateMutability: "payable", + type: "function" + }, + { + inputs: [ + { + internalType: "uint256", + name: "amountMinimum", + type: "uint256" + }, + { + internalType: "address", + name: "recipient", + type: "address" + }, + { + internalType: "uint256", + name: "feeBips", + type: "uint256" + }, + { + internalType: "address", + name: "feeRecipient", + type: "address" + } + ], + name: "unwrapWETH9WithFee", + outputs: [], + stateMutability: "payable", + type: "function" + }, + { + inputs: [ + { + internalType: "uint256", + name: "value", + type: "uint256" + } + ], + name: "wrapETH", + outputs: [], + stateMutability: "payable", + type: "function" + } +]; + +// evm/v3-router/utils/paymentsExtended.ts +function encodeFeeBips(fee) { + return fee.multiply(1e4).quotient; +} +var _PaymentsExtended = class { + /** + * Cannot be constructed. + */ + // eslint-disable-next-line no-useless-constructor, @typescript-eslint/no-empty-function + constructor() { + } + static encodeUnwrapWETH9(amountMinimum, recipient, feeOptions) { + if (typeof recipient === "string") { + return v3Sdk.Payments.encodeUnwrapWETH9(amountMinimum, recipient, feeOptions); + } + if (!!feeOptions) { + const feeBips = encodeFeeBips(feeOptions.fee); + const feeRecipient = sdk.validateAndParseAddress(feeOptions.recipient); + return viem.encodeFunctionData({ + abi: _PaymentsExtended.ABI, + functionName: "unwrapWETH9WithFee", + args: [amountMinimum, feeBips, feeRecipient] + }); + } + return viem.encodeFunctionData({ + abi: _PaymentsExtended.ABI, + functionName: "unwrapWETH9", + args: [amountMinimum] + }); + } + static encodeSweepToken(token, amountMinimum, recipient, feeOptions) { + if (typeof recipient === "string") { + return v3Sdk.Payments.encodeSweepToken(token, amountMinimum, recipient, feeOptions); + } + if (!!feeOptions) { + const feeBips = encodeFeeBips(feeOptions.fee); + const feeRecipient = sdk.validateAndParseAddress(feeOptions.recipient); + return viem.encodeFunctionData({ + abi: _PaymentsExtended.ABI, + functionName: "sweepTokenWithFee", + args: [token.address, amountMinimum, feeBips, feeRecipient] + }); + } + return viem.encodeFunctionData({ + abi: _PaymentsExtended.ABI, + functionName: "sweepToken", + args: [token.address, amountMinimum] + }); + } + static encodePull(token, amount) { + return viem.encodeFunctionData({ abi: _PaymentsExtended.ABI, functionName: "pull", args: [token.address, amount] }); + } + static encodeWrapETH(amount) { + return viem.encodeFunctionData({ abi: _PaymentsExtended.ABI, functionName: "wrapETH", args: [amount] }); + } +}; +var PaymentsExtended = _PaymentsExtended; +PaymentsExtended.ABI = peripheryPaymentsWithFeeExtendedAbi; + +// evm/v3-router/utils/swapRouter.ts +var ZERO2 = 0n; +var REFUND_ETH_PRICE_IMPACT_THRESHOLD = new sdk.Percent(50n, 100n); +var _SwapRouter = class { + /** + * Cannot be constructed. + */ + // eslint-disable-next-line no-useless-constructor, @typescript-eslint/no-empty-function + constructor() { + } + /** + * @notice Generates the calldata for a Swap with a V2 Route. + * @param trade The V2Trade to encode. + * @param options SwapOptions to use for the trade. + * @param routerMustCustody Flag for whether funds should be sent to the router + * @param performAggregatedSlippageCheck Flag for whether we want to perform an aggregated slippage check + * @returns A string array of calldatas for the trade. + */ + static encodeV2Swap(trade, options, routerMustCustody, performAggregatedSlippageCheck) { + const amountIn = maximumAmountIn(trade, options.slippageTolerance).quotient; + const amountOut = minimumAmountOut(trade, options.slippageTolerance).quotient; + const route = trade.routes[0]; + const path = route.path.map((token) => token.wrapped.address); + const recipient = routerMustCustody ? chunkZNSTBYLO_js.ADDRESS_THIS : typeof options.recipient === "undefined" ? chunkZNSTBYLO_js.MSG_SENDER : sdk.validateAndParseAddress(options.recipient); + if (trade.tradeType === sdk.TradeType.EXACT_INPUT) { + const exactInputParams = [amountIn, performAggregatedSlippageCheck ? 0n : amountOut, path, recipient]; + return viem.encodeFunctionData({ + abi: _SwapRouter.ABI, + functionName: "swapExactTokensForTokens", + args: exactInputParams + }); + } + const exactOutputParams = [amountOut, amountIn, path, recipient]; + return viem.encodeFunctionData({ + abi: _SwapRouter.ABI, + functionName: "swapTokensForExactTokens", + args: exactOutputParams + }); + } + /** + * @notice Generates the calldata for a Swap with a Stable Route. + * @param trade The Trade to encode. + * @param options SwapOptions to use for the trade. + * @param routerMustCustody Flag for whether funds should be sent to the router + * @param performAggregatedSlippageCheck Flag for whether we want to perform an aggregated slippage check + * @returns A string array of calldatas for the trade. + */ + static encodeStableSwap(trade, options, routerMustCustody, performAggregatedSlippageCheck) { + const amountIn = maximumAmountIn(trade, options.slippageTolerance).quotient; + const amountOut = minimumAmountOut(trade, options.slippageTolerance).quotient; + if (trade.routes.length > 1 || trade.routes[0].pools.some((p) => !isStablePool(p))) { + throw new Error("Unsupported trade to encode"); + } + const route = trade.routes[0]; + const path = route.path.map((token) => token.wrapped.address); + const flags = route.pools.map((p) => BigInt(p.balances.length)); + const recipient = routerMustCustody ? chunkZNSTBYLO_js.ADDRESS_THIS : typeof options.recipient === "undefined" ? chunkZNSTBYLO_js.MSG_SENDER : sdk.validateAndParseAddress(options.recipient); + if (trade.tradeType === sdk.TradeType.EXACT_INPUT) { + const exactInputParams = [ + path, + flags, + amountIn, + performAggregatedSlippageCheck ? 0n : amountOut, + recipient + ]; + return viem.encodeFunctionData({ + abi: _SwapRouter.ABI, + functionName: "exactInputStableSwap", + args: exactInputParams + }); + } + const exactOutputParams = [path, flags, amountOut, amountIn, recipient]; + return viem.encodeFunctionData({ + abi: _SwapRouter.ABI, + functionName: "exactOutputStableSwap", + args: exactOutputParams + }); + } + /** + * @notice Generates the calldata for a Swap with a V3 Route. + * @param trade The V3Trade to encode. + * @param options SwapOptions to use for the trade. + * @param routerMustCustody Flag for whether funds should be sent to the router + * @param performAggregatedSlippageCheck Flag for whether we want to perform an aggregated slippage check + * @returns A string array of calldatas for the trade. + */ + static encodeV3Swap(trade, options, routerMustCustody, performAggregatedSlippageCheck) { + const calldatas = []; + for (const route of trade.routes) { + const { inputAmount, outputAmount, pools, path } = route; + const amountIn = maximumAmountIn(trade, options.slippageTolerance, inputAmount).quotient; + const amountOut = minimumAmountOut(trade, options.slippageTolerance, outputAmount).quotient; + const singleHop = pools.length === 1; + const recipient = routerMustCustody ? chunkZNSTBYLO_js.ADDRESS_THIS : typeof options.recipient === "undefined" ? chunkZNSTBYLO_js.MSG_SENDER : sdk.validateAndParseAddress(options.recipient); + if (singleHop) { + if (trade.tradeType === sdk.TradeType.EXACT_INPUT) { + const exactInputSingleParams = { + tokenIn: path[0].wrapped.address, + tokenOut: path[1].wrapped.address, + fee: pools[0].fee, + recipient, + amountIn, + amountOutMinimum: performAggregatedSlippageCheck ? 0n : amountOut, + sqrtPriceLimitX96: 0n + }; + calldatas.push( + viem.encodeFunctionData({ + abi: _SwapRouter.ABI, + functionName: "exactInputSingle", + args: [exactInputSingleParams] + }) + ); + } else { + const exactOutputSingleParams = { + tokenIn: path[0].wrapped.address, + tokenOut: path[1].wrapped.address, + fee: pools[0].fee, + recipient, + amountOut, + amountInMaximum: amountIn, + sqrtPriceLimitX96: 0n + }; + calldatas.push( + viem.encodeFunctionData({ + abi: _SwapRouter.ABI, + functionName: "exactOutputSingle", + args: [exactOutputSingleParams] + }) + ); + } + } else { + const pathStr = encodeMixedRouteToPath( + { ...route, input: inputAmount.currency, output: outputAmount.currency }, + trade.tradeType === sdk.TradeType.EXACT_OUTPUT + ); + if (trade.tradeType === sdk.TradeType.EXACT_INPUT) { + const exactInputParams = { + path: pathStr, + recipient, + amountIn, + amountOutMinimum: performAggregatedSlippageCheck ? 0n : amountOut + }; + calldatas.push( + viem.encodeFunctionData({ + abi: _SwapRouter.ABI, + functionName: "exactInput", + args: [exactInputParams] + }) + ); + } else { + const exactOutputParams = { + path: pathStr, + recipient, + amountOut, + amountInMaximum: amountIn + }; + calldatas.push( + viem.encodeFunctionData({ + abi: _SwapRouter.ABI, + functionName: "exactOutput", + args: [exactOutputParams] + }) + ); + } + } + } + return calldatas; + } + /** + * @notice Generates the calldata for a MixedRouteSwap. Since single hop routes are not MixedRoutes, we will instead generate + * them via the existing encodeV3Swap and encodeV2Swap methods. + * @param trade The MixedRouteTrade to encode. + * @param options SwapOptions to use for the trade. + * @param routerMustCustody Flag for whether funds should be sent to the router + * @param performAggregatedSlippageCheck Flag for whether we want to perform an aggregated slippage check + * @returns A string array of calldatas for the trade. + */ + static encodeMixedRouteSwap(trade, options, routerMustCustody, performAggregatedSlippageCheck) { + let calldatas = []; + const isExactIn = trade.tradeType === sdk.TradeType.EXACT_INPUT; + for (const route of trade.routes) { + const { inputAmount, outputAmount, pools } = route; + const amountIn = maximumAmountIn(trade, options.slippageTolerance, inputAmount).quotient; + const amountOut = minimumAmountOut(trade, options.slippageTolerance, outputAmount).quotient; + const singleHop = pools.length === 1; + const recipient = routerMustCustody ? chunkZNSTBYLO_js.ADDRESS_THIS : typeof options.recipient === "undefined" ? chunkZNSTBYLO_js.MSG_SENDER : sdk.validateAndParseAddress(options.recipient); + const mixedRouteIsAllV3 = (r) => { + return r.pools.every(isV3Pool); + }; + const mixedRouteIsAllV2 = (r) => { + return r.pools.every(isV2Pool); + }; + const mixedRouteIsAllStable = (r) => { + return r.pools.every(isStablePool); + }; + if (singleHop) { + if (mixedRouteIsAllV3(route)) { + calldatas = [ + ...calldatas, + ..._SwapRouter.encodeV3Swap( + { + ...trade, + routes: [route], + inputAmount, + outputAmount + }, + options, + routerMustCustody, + performAggregatedSlippageCheck + ) + ]; + } else if (mixedRouteIsAllV2(route)) { + calldatas = [ + ...calldatas, + _SwapRouter.encodeV2Swap( + { + ...trade, + routes: [route], + inputAmount, + outputAmount + }, + options, + routerMustCustody, + performAggregatedSlippageCheck + ) + ]; + } else if (mixedRouteIsAllStable(route)) { + calldatas = [ + ...calldatas, + _SwapRouter.encodeStableSwap( + { + ...trade, + routes: [route], + inputAmount, + outputAmount + }, + options, + routerMustCustody, + performAggregatedSlippageCheck + ) + ]; + } else { + throw new Error("Unsupported route to encode"); + } + } else { + const sections = partitionMixedRouteByProtocol(route); + const isLastSectionInRoute = (i) => { + return i === sections.length - 1; + }; + let outputToken; + let inputToken = inputAmount.currency.wrapped; + for (let i = 0; i < sections.length; i++) { + const section = sections[i]; + outputToken = getOutputOfPools(section, inputToken); + const newRoute = buildBaseRoute([...section], inputToken, outputToken); + inputToken = outputToken.wrapped; + const lastSectionInRoute = isLastSectionInRoute(i); + const recipientAddress = lastSectionInRoute ? recipient : chunkZNSTBYLO_js.ADDRESS_THIS; + const inAmount = i === 0 ? amountIn : 0n; + const outAmount = !lastSectionInRoute ? 0n : amountOut; + if (mixedRouteIsAllV3(newRoute)) { + const pathStr = encodeMixedRouteToPath(newRoute, !isExactIn); + if (isExactIn) { + const exactInputParams = { + path: pathStr, + recipient: recipientAddress, + amountIn: inAmount, + amountOutMinimum: outAmount + }; + calldatas.push( + viem.encodeFunctionData({ + abi: _SwapRouter.ABI, + functionName: "exactInput", + args: [exactInputParams] + }) + ); + } else { + const exactOutputParams = { + path: pathStr, + recipient, + amountOut: outAmount, + amountInMaximum: inAmount + }; + calldatas.push( + viem.encodeFunctionData({ + abi: _SwapRouter.ABI, + functionName: "exactOutput", + args: [exactOutputParams] + }) + ); + } + } else if (mixedRouteIsAllV2(newRoute)) { + const path = newRoute.path.map((token) => token.wrapped.address); + if (isExactIn) { + const exactInputParams = [ + inAmount, + // amountIn + outAmount, + // amountOutMin + path, + // path + recipientAddress + // to + ]; + calldatas.push( + viem.encodeFunctionData({ + abi: _SwapRouter.ABI, + functionName: "swapExactTokensForTokens", + args: exactInputParams + }) + ); + } else { + const exactOutputParams = [outAmount, inAmount, path, recipientAddress]; + calldatas.push( + viem.encodeFunctionData({ + abi: _SwapRouter.ABI, + functionName: "swapTokensForExactTokens", + args: exactOutputParams + }) + ); + } + } else if (mixedRouteIsAllStable(newRoute)) { + const path = newRoute.path.map((token) => token.wrapped.address); + const flags = newRoute.pools.map((pool) => BigInt(pool.balances.length)); + if (isExactIn) { + const exactInputParams = [ + path, + // path + flags, + // stable pool types + inAmount, + // amountIn + outAmount, + // amountOutMin + recipientAddress + // to + ]; + calldatas.push( + viem.encodeFunctionData({ + abi: _SwapRouter.ABI, + functionName: "exactInputStableSwap", + args: exactInputParams + }) + ); + } else { + const exactOutputParams = [path, flags, outAmount, inAmount, recipientAddress]; + calldatas.push( + viem.encodeFunctionData({ + abi: _SwapRouter.ABI, + functionName: "exactOutputStableSwap", + args: exactOutputParams + }) + ); + } + } else { + throw new Error("Unsupported route"); + } + } + } + } + return calldatas; + } + static encodeSwaps(anyTrade, options, isSwapAndAdd) { + const trades = !Array.isArray(anyTrade) ? [anyTrade] : anyTrade; + const numberOfTrades = trades.reduce((numOfTrades, trade) => numOfTrades + trade.routes.length, 0); + const sampleTrade = trades[0]; + invariant6__default.default( + trades.every((trade) => trade.inputAmount.currency.equals(sampleTrade.inputAmount.currency)), + "TOKEN_IN_DIFF" + ); + invariant6__default.default( + trades.every((trade) => trade.outputAmount.currency.equals(sampleTrade.outputAmount.currency)), + "TOKEN_OUT_DIFF" + ); + invariant6__default.default( + trades.every((trade) => trade.tradeType === sampleTrade.tradeType), + "TRADE_TYPE_DIFF" + ); + const calldatas = []; + const inputIsNative = sampleTrade.inputAmount.currency.isNative; + const outputIsNative = sampleTrade.outputAmount.currency.isNative; + const performAggregatedSlippageCheck = sampleTrade.tradeType === sdk.TradeType.EXACT_INPUT && numberOfTrades > 2; + const routerMustCustody = outputIsNative || !!options.fee || !!isSwapAndAdd || performAggregatedSlippageCheck; + if (options.inputTokenPermit) { + invariant6__default.default(sampleTrade.inputAmount.currency.isToken, "NON_TOKEN_PERMIT"); + calldatas.push(v3Sdk.SelfPermit.encodePermit(sampleTrade.inputAmount.currency, options.inputTokenPermit)); + } + for (const trade of trades) { + if (trade.routes.length === 1 && trade.routes[0].type === 0 /* V2 */) { + calldatas.push(_SwapRouter.encodeV2Swap(trade, options, routerMustCustody, performAggregatedSlippageCheck)); + } else if (trade.routes.every((r) => r.type === 1 /* V3 */)) { + for (const calldata of _SwapRouter.encodeV3Swap( + trade, + options, + routerMustCustody, + performAggregatedSlippageCheck + )) { + calldatas.push(calldata); + } + } else { + for (const calldata of _SwapRouter.encodeMixedRouteSwap( + trade, + options, + routerMustCustody, + performAggregatedSlippageCheck + )) { + calldatas.push(calldata); + } + } + } + const ZERO_IN = sdk.CurrencyAmount.fromRawAmount(sampleTrade.inputAmount.currency, 0); + const ZERO_OUT = sdk.CurrencyAmount.fromRawAmount(sampleTrade.outputAmount.currency, 0); + const minAmountOut = trades.reduce( + (sum2, trade) => sum2.add(minimumAmountOut(trade, options.slippageTolerance)), + ZERO_OUT + ); + const quoteAmountOut = trades.reduce( + (sum2, trade) => sum2.add(trade.outputAmount), + ZERO_OUT + ); + const totalAmountIn = trades.reduce( + (sum2, trade) => sum2.add(maximumAmountIn(trade, options.slippageTolerance)), + ZERO_IN + ); + return { + calldatas, + sampleTrade, + routerMustCustody, + inputIsNative, + outputIsNative, + totalAmountIn, + minimumAmountOut: minAmountOut, + quoteAmountOut + }; + } + /** + * Produces the on-chain method name to call and the hex encoded parameters to pass as arguments for a given trade. + * @param trades to produce call parameters for + * @param options options for the call parameters + */ + static swapCallParameters(trades, options) { + const { + calldatas, + sampleTrade, + routerMustCustody, + inputIsNative, + outputIsNative, + totalAmountIn, + minimumAmountOut: minAmountOut + } = _SwapRouter.encodeSwaps(trades, options); + if (routerMustCustody) { + if (outputIsNative) { + calldatas.push(PaymentsExtended.encodeUnwrapWETH9(minAmountOut.quotient, options.recipient, options.fee)); + } else { + calldatas.push( + PaymentsExtended.encodeSweepToken( + sampleTrade.outputAmount.currency.wrapped, + minAmountOut.quotient, + options.recipient, + options.fee + ) + ); + } + } + if (inputIsNative && (sampleTrade.tradeType === sdk.TradeType.EXACT_OUTPUT || _SwapRouter.riskOfPartialFill(trades))) { + calldatas.push(v3Sdk.Payments.encodeRefundETH()); + } + return { + calldata: MulticallExtended.encodeMulticall(calldatas, options.deadlineOrPreviousBlockhash), + value: v3Sdk.toHex(inputIsNative ? totalAmountIn.quotient : ZERO2) + }; + } + /** + * Produces the on-chain method name to call and the hex encoded parameters to pass as arguments for a given trade. + * @param trades to produce call parameters for + * @param options options for the call parameters + */ + static swapAndAddCallParameters(trades, options, position, addLiquidityOptions, tokenInApprovalType, tokenOutApprovalType) { + const { + calldatas, + inputIsNative, + outputIsNative, + sampleTrade, + totalAmountIn: totalAmountSwapped, + quoteAmountOut, + minimumAmountOut: minAmountOut + } = _SwapRouter.encodeSwaps(trades, options, true); + if (options.outputTokenPermit) { + invariant6__default.default(quoteAmountOut.currency.isToken, "NON_TOKEN_PERMIT_OUTPUT"); + calldatas.push(v3Sdk.SelfPermit.encodePermit(quoteAmountOut.currency, options.outputTokenPermit)); + } + const { + inputAmount: { + currency: { chainId } + } + } = sampleTrade; + const zeroForOne = position.pool.token0.wrapped.address === totalAmountSwapped.currency.wrapped.address; + const { positionAmountIn, positionAmountOut } = _SwapRouter.getPositionAmounts(position, zeroForOne); + const wnative = sdk.WNATIVE[chainId]; + if ((inputIsNative || outputIsNative) && !wnative) { + throw new Error(`Chain ${chainId} has no wrapped native token; a native swap leg is not encodable`); + } + const tokenIn = inputIsNative && wnative ? wnative : positionAmountIn.currency.wrapped; + const tokenOut = outputIsNative && wnative ? wnative : positionAmountOut.currency.wrapped; + const amountOutRemaining = positionAmountOut.subtract(quoteAmountOut.wrapped); + if (amountOutRemaining.greaterThan(sdk.CurrencyAmount.fromRawAmount(positionAmountOut.currency, 0))) { + if (outputIsNative) { + calldatas.push(PaymentsExtended.encodeWrapETH(amountOutRemaining.quotient)); + } else { + calldatas.push(PaymentsExtended.encodePull(tokenOut, amountOutRemaining.quotient)); + } + } + if (inputIsNative) { + calldatas.push(PaymentsExtended.encodeWrapETH(positionAmountIn.quotient)); + } else { + calldatas.push(PaymentsExtended.encodePull(tokenIn, positionAmountIn.quotient)); + } + if (tokenInApprovalType !== 0 /* NOT_REQUIRED */) + calldatas.push(ApproveAndCall.encodeApprove(tokenIn, tokenInApprovalType)); + if (tokenOutApprovalType !== 0 /* NOT_REQUIRED */) + calldatas.push(ApproveAndCall.encodeApprove(tokenOut, tokenOutApprovalType)); + const minimalPosition = v3Sdk.Position.fromAmounts({ + pool: position.pool, + tickLower: position.tickLower, + tickUpper: position.tickUpper, + amount0: zeroForOne ? position.amount0.quotient.toString() : minAmountOut.quotient.toString(), + amount1: zeroForOne ? minAmountOut.quotient.toString() : position.amount1.quotient.toString(), + useFullPrecision: false + }); + calldatas.push( + ApproveAndCall.encodeAddLiquidity(position, minimalPosition, addLiquidityOptions, options.slippageTolerance) + ); + if (inputIsNative) { + calldatas.push(PaymentsExtended.encodeUnwrapWETH9(ZERO2)); + } else { + calldatas.push(PaymentsExtended.encodeSweepToken(tokenIn, ZERO2)); + } + if (outputIsNative) { + calldatas.push(PaymentsExtended.encodeUnwrapWETH9(ZERO2)); + } else { + calldatas.push(PaymentsExtended.encodeSweepToken(tokenOut, ZERO2)); + } + let value; + if (inputIsNative) { + value = totalAmountSwapped.wrapped.add(positionAmountIn.wrapped).quotient; + } else if (outputIsNative) { + value = amountOutRemaining.quotient; + } else { + value = ZERO2; + } + return { + calldata: MulticallExtended.encodeMulticall(calldatas, options.deadlineOrPreviousBlockhash), + value: v3Sdk.toHex(value.toString()) + }; + } + // if price impact is very high, there's a chance of hitting max/min prices resulting in a partial fill of the swap + static riskOfPartialFill(trades) { + if (Array.isArray(trades)) { + return trades.some((trade) => { + return _SwapRouter.v3TradeWithHighPriceImpact(trade); + }); + } + return _SwapRouter.v3TradeWithHighPriceImpact(trades); + } + static v3TradeWithHighPriceImpact(trade) { + return !(trade.routes.length === 1 && trade.routes[0].type === 0 /* V2 */) && getPriceImpact(trade).greaterThan(REFUND_ETH_PRICE_IMPACT_THRESHOLD); + } + static getPositionAmounts(position, zeroForOne) { + const { amount0, amount1 } = position.mintAmounts; + const currencyAmount0 = sdk.CurrencyAmount.fromRawAmount(position.pool.token0, amount0); + const currencyAmount1 = sdk.CurrencyAmount.fromRawAmount(position.pool.token1, amount1); + const [positionAmountIn, positionAmountOut] = zeroForOne ? [currencyAmount0, currencyAmount1] : [currencyAmount1, currencyAmount0]; + return { positionAmountIn, positionAmountOut }; + } +}; +var SwapRouter = _SwapRouter; +SwapRouter.ABI = swapRouter02Abi; + +// evm/v3-router/utils/transformer.ts +var transformer_exports = {}; +chunkZNSTBYLO_js.__export(transformer_exports, { + parseBinPoolBinReserves: () => parseBinPoolBinReserves, + parseCurrency: () => parseCurrency, + parseCurrencyAmount: () => parseCurrencyAmount, + parsePool: () => parsePool, + parseRoute: () => parseRoute, + parseTick: () => parseTick, + parseTrade: () => parseTrade, + serializeBinPoolBinReserves: () => serializeBinPoolBinReserves, + serializeCurrency: () => serializeCurrency, + serializeCurrencyAmount: () => serializeCurrencyAmount, + serializePool: () => serializePool, + serializeRoute: () => serializeRoute, + serializeTick: () => serializeTick, + serializeTrade: () => serializeTrade +}); +var ONE_HUNDRED = 100n; +function serializeCurrency(currency) { + return { + address: currency.isNative ? v3Sdk.ADDRESS_ZERO : currency.wrapped.address, + decimals: currency.decimals, + symbol: currency.symbol + }; +} +function serializeCurrencyAmount(amount) { + return { + currency: serializeCurrency(amount.currency), + value: amount.quotient.toString() + }; +} +function serializeTick(tick) { + return { + index: tick.index, + liquidityNet: String(tick.liquidityNet), + liquidityGross: String(tick.liquidityGross) + }; +} +function serializePool(pool) { + if (isV2Pool(pool)) { + return { + ...pool, + reserve0: serializeCurrencyAmount(pool.reserve0), + reserve1: serializeCurrencyAmount(pool.reserve1) + }; + } + if (isV3Pool(pool)) { + return { + ...pool, + token0: serializeCurrency(pool.token0), + token1: serializeCurrency(pool.token1), + liquidity: pool.liquidity.toString(), + sqrtRatioX96: pool.sqrtRatioX96.toString(), + token0ProtocolFee: pool.token0ProtocolFee.toFixed(0), + token1ProtocolFee: pool.token1ProtocolFee.toFixed(0), + ticks: pool.ticks?.map(serializeTick), + reserve0: pool.reserve0 && serializeCurrencyAmount(pool.reserve0), + reserve1: pool.reserve1 && serializeCurrencyAmount(pool.reserve1) + }; + } + if (isStablePool(pool)) { + return { + ...pool, + balances: pool.balances.map(serializeCurrencyAmount), + amplifier: pool.amplifier.toString(), + fee: pool.fee.toSignificant(6) + }; + } + if (isInfinityStablePool(pool)) { + return { + currency0: serializeCurrency(pool.currency0), + currency1: serializeCurrency(pool.currency1), + hooks: pool.hooks, + hooksRegistrationBitmap: pool.hooksRegistrationBitmap, + id: pool.id, + poolManager: pool.poolManager, + fee: pool.fee, + amplifier: pool.amplifier || 0, + stableFee: pool.stableFee, + type: 5 /* InfinityStable */, + tickSpacing: pool.tickSpacing, + reserve0: pool.reserve0 && serializeCurrencyAmount(pool.reserve0), + reserve1: pool.reserve1 && serializeCurrencyAmount(pool.reserve1) + }; + } + if (isInfinityClPool(pool)) { + return { + ...pool, + currency0: serializeCurrency(pool.currency0), + currency1: serializeCurrency(pool.currency1), + liquidity: pool.liquidity.toString(), + sqrtRatioX96: pool.sqrtRatioX96.toString(), + ticks: pool.ticks?.map(serializeTick), + reserve0: pool.reserve0 && serializeCurrencyAmount(pool.reserve0), + reserve1: pool.reserve1 && serializeCurrencyAmount(pool.reserve1) + }; + } + if (isInfinityBinPool(pool)) { + return { + ...pool, + reserveOfBin: serializeBinPoolBinReserves(pool.reserveOfBin), + currency0: serializeCurrency(pool.currency0), + currency1: serializeCurrency(pool.currency1), + reserve0: pool.reserve0 && serializeCurrencyAmount(pool.reserve0), + reserve1: pool.reserve1 && serializeCurrencyAmount(pool.reserve1) + }; + } + throw new Error("Cannot serialize unsupoorted pool"); +} +function serializeBinPoolBinReserves(reserveOfBin) { + if (!reserveOfBin) + return void 0; + const binIds = Object.keys(reserveOfBin); + const binReserves = {}; + for (const b of binIds) { + const binId = Number(b); + binReserves[binId] = { + reserveX: String(reserveOfBin[binId].reserveX), + reserveY: String(reserveOfBin[binId].reserveY) + }; + } + return binReserves; +} +function parseBinPoolBinReserves(reserveOfBin) { + if (!reserveOfBin) + return void 0; + const binIds = Object.keys(reserveOfBin); + const binReserves = {}; + for (const b of binIds) { + const binId = Number(b); + binReserves[binId] = { + reserveX: BigInt(reserveOfBin[binId].reserveX), + reserveY: BigInt(reserveOfBin[binId].reserveY) + }; + } + return binReserves; +} +function serializeRoute(route) { + return { + ...route, + pools: route.pools.map(serializePool), + path: route.path.map(serializeCurrency), + inputAmount: serializeCurrencyAmount(route.inputAmount), + outputAmount: serializeCurrencyAmount(route.outputAmount) + }; +} +function serializeTrade(trade) { + return { + ...trade, + inputAmount: serializeCurrencyAmount(trade.inputAmount), + outputAmount: serializeCurrencyAmount(trade.outputAmount), + routes: trade.routes.map(serializeRoute), + gasEstimate: trade.gasEstimate.toString(), + gasEstimateInUSD: trade.gasEstimateInUSD && serializeCurrencyAmount(trade.gasEstimateInUSD) + }; +} +function parseTick(tick) { + return new v3Sdk.Tick(tick); +} +function parseCurrency(chainId, currency) { + if (currency.address === v3Sdk.ADDRESS_ZERO) { + return sdk.Native.onChain(chainId); + } + const { address, decimals, symbol } = currency; + return new sdk.ERC20Token(chainId, address, decimals, symbol); +} +function parseCurrencyAmount(chainId, amount) { + return sdk.CurrencyAmount.fromRawAmount(parseCurrency(chainId, amount.currency), amount.value); +} +function parsePool(chainId, pool) { + if (pool.type === 0 /* V2 */) { + return { + ...pool, + reserve0: parseCurrencyAmount(chainId, pool.reserve0), + reserve1: parseCurrencyAmount(chainId, pool.reserve1) + }; + } + if (pool.type === 1 /* V3 */) { + return { + ...pool, + token0: parseCurrency(chainId, pool.token0), + token1: parseCurrency(chainId, pool.token1), + liquidity: BigInt(pool.liquidity), + sqrtRatioX96: BigInt(pool.sqrtRatioX96), + token0ProtocolFee: new sdk.Percent(pool.token0ProtocolFee, ONE_HUNDRED), + token1ProtocolFee: new sdk.Percent(pool.token1ProtocolFee, ONE_HUNDRED), + ticks: pool.ticks?.map(parseTick), + reserve0: pool.reserve0 && parseCurrencyAmount(chainId, pool.reserve0), + reserve1: pool.reserve1 && parseCurrencyAmount(chainId, pool.reserve1) + }; + } + if (pool.type === 2 /* STABLE */) { + return { + ...pool, + balances: pool.balances.map((b) => parseCurrencyAmount(chainId, b)), + amplifier: BigInt(pool.amplifier), + fee: new sdk.Percent(parseFloat(pool.fee) * 1e6, ONE_HUNDRED * 1000000n) + }; + } + if (pool.type === 5 /* InfinityStable */) { + return { + ...pool, + currency0: parseCurrency(chainId, pool.currency0), + currency1: parseCurrency(chainId, pool.currency1), + reserve0: pool.reserve0 && parseCurrencyAmount(chainId, pool.reserve0), + reserve1: pool.reserve1 && parseCurrencyAmount(chainId, pool.reserve1) + }; + } + if (pool.type === 3 /* InfinityCL */) { + return { + ...pool, + currency0: parseCurrency(chainId, pool.currency0), + currency1: parseCurrency(chainId, pool.currency1), + liquidity: BigInt(pool.liquidity), + sqrtRatioX96: BigInt(pool.sqrtRatioX96), + ticks: pool.ticks?.map(parseTick), + reserve0: pool.reserve0 && parseCurrencyAmount(chainId, pool.reserve0), + reserve1: pool.reserve1 && parseCurrencyAmount(chainId, pool.reserve1) + }; + } + if (pool.type === 4 /* InfinityBIN */) { + return { + ...pool, + reserveOfBin: parseBinPoolBinReserves(pool.reserveOfBin), + currency0: parseCurrency(chainId, pool.currency0), + currency1: parseCurrency(chainId, pool.currency1), + reserve0: pool.reserve0 && parseCurrencyAmount(chainId, pool.reserve0), + reserve1: pool.reserve1 && parseCurrencyAmount(chainId, pool.reserve1) + }; + } + throw new Error("Cannot parse unsupoorted pool"); +} +function parseRoute(chainId, route) { + return { + ...route, + pools: route.pools.map((p) => parsePool(chainId, p)), + path: route.path.map((c) => parseCurrency(chainId, c)), + inputAmount: parseCurrencyAmount(chainId, route.inputAmount), + outputAmount: parseCurrencyAmount(chainId, route.outputAmount) + }; +} +function parseTrade(chainId, trade) { + return { + ...trade, + inputAmount: parseCurrencyAmount(chainId, trade.inputAmount), + outputAmount: parseCurrencyAmount(chainId, trade.outputAmount), + routes: trade.routes.map((r) => parseRoute(chainId, r)), + gasEstimate: trade.gasEstimate ? BigInt(trade.gasEstimate) : 0n, + gasEstimateInUSD: trade.gasEstimateInUSD && parseCurrencyAmount(chainId, trade.gasEstimateInUSD) + }; +} +var fetchConfig = memoize( + async () => { + const url = `https://proofs.pancakeswap.com/cms-config/routing-base-config.json`; + try { + const response = await fetch(url); + const data = await response.json(); + const table = {}; + Object.keys(data).forEach((key) => { + const chainId = Number(key); + table[chainId] = {}; + for (const [address, list] of Object.entries(data[key])) { + const src = viem.checksumAddress(address); + const to = list.map((item) => { + return new swapSdkCore.Token(chainId, viem.checksumAddress(item.address), item.decimals, item.symbol, ""); + }); + table[chainId][src] = to; + } + }); + return table; + } catch { + return chunkZNSTBYLO_js.ADDITIONAL_BASES; + } + }, + () => { + return Math.floor(Date.now() / 601e3); + } +); +async function getAdditionalBases(chainId) { + if (!chainId) { + return {}; + } + const table = await fetchConfig(); + return table[chainId] ?? {}; +} + +// evm/v3-router/functions/getPairCombinations.ts +var resolver = (currencyA, currencyB) => { + if (!currencyA || !currencyB || currencyA.chainId !== currencyB.chainId || currencyA.wrapped.equals(currencyB.wrapped)) { + return `${currencyA?.chainId}_${currencyA?.wrapped?.address}_${currencyB?.wrapped?.address}`; + } + const [token0, token1] = currencyA.wrapped.sortsBefore(currencyB.wrapped) ? [currencyA.wrapped, currencyB.wrapped] : [currencyB.wrapped, currencyA.wrapped]; + return `${token0.chainId}_${token0.address}_${token1.address}`; +}; +async function getAdditionalCheckAgainstBaseTokens(currencyA, currencyB) { + const chainId = currencyA?.chainId; + const additionalBases = await getAdditionalBases(chainId); + const uniq = (tokens) => uniqBy(tokens, (t) => t.address); + const additionalA = currencyA && chainId ? uniq([...additionalBases[currencyA.wrapped.address] || []]) : []; + const additionalB = currencyB && chainId ? uniq([...additionalBases[currencyB.wrapped.address] || []]) : []; + return [...additionalA, ...additionalB]; +} +var getCheckAgainstBaseTokens = memoize( + async (currencyA, currencyB) => { + const chainId = currencyA?.chainId; + if (!chainId || !currencyA || !currencyB || !isCurrenciesSameChain(currencyA, currencyB)) { + return []; + } + const [tokenA, tokenB] = chainId ? [chunkZNSTBYLO_js.wrappedCurrency(currencyA, chainId), chunkZNSTBYLO_js.wrappedCurrency(currencyB, chainId)] : [void 0, void 0]; + if (!tokenA || !tokenB) { + return []; + } + const common = chunkZNSTBYLO_js.BASES_TO_CHECK_TRADES_AGAINST[chainId] ?? []; + return [...common, ...await getAdditionalCheckAgainstBaseTokens(currencyA, currencyB)]; + }, + resolver +); +var getPairCombinations = memoize( + async (currencyA, currencyB) => { + const chainId = currencyA?.chainId; + if (!chainId || !currencyA || !currencyB || !isCurrenciesSameChain(currencyA, currencyB)) { + return []; + } + const [tokenA, tokenB] = chainId ? [chunkZNSTBYLO_js.wrappedCurrency(currencyA, chainId), chunkZNSTBYLO_js.wrappedCurrency(currencyB, chainId)] : [void 0, void 0]; + if (!tokenA || !tokenB) { + return []; + } + const bases = await getCheckAgainstBaseTokens(currencyA, currencyB); + const basePairs = bases.flatMap( + (base) => bases.map((otherBase) => [base, otherBase]) + ); + return [ + // the direct pair + [tokenA, tokenB], + // token A against all bases + ...bases.map((base) => [tokenA, base]), + // token B against all bases + ...bases.map((base) => [tokenB, base]), + // each base against all bases + ...basePairs + ].filter((tokens) => Boolean(tokens[0] && tokens[1])).filter(([t0, t1]) => !t0.equals(t1)).filter(([tokenA_, tokenB_]) => { + if (!chainId) + return true; + const customBases = chunkZNSTBYLO_js.CUSTOM_BASES[chainId]; + const customBasesA = customBases?.[tokenA_.wrapped.address]; + const customBasesB = customBases?.[tokenB_.wrapped.address]; + if (!customBasesA && !customBasesB) + return true; + if (customBasesA && !customBasesA.find((base) => tokenB_.equals(base))) + return false; + if (customBasesB && !customBasesB.find((base) => tokenA_.equals(base))) + return false; + return true; + }); + }, + resolver +); + +// ../utils/RemoteLogger.ts +var ENABLED = process.env.NODE_ENV === "development"; +var _RemoteLogger = class { + constructor(_id) { + this.logs = []; + this.id = ""; + this.createTime = (/* @__PURE__ */ new Date()).getTime(); + this.id = _id; + } + debug(log4, indent = 0) { + if (ENABLED && this.id !== "__dummy__") { + const indentStr = " ".repeat(indent); + this.logs.push(`${indentStr}${log4}`); + } + } + metric(log4, indent = 0) { + if (ENABLED && this.id !== "__dummy__") { + const indentStr = " ".repeat(indent); + const time = (/* @__PURE__ */ new Date()).getTime() - this.createTime; + this.logs.push(`[${time}ms]${indentStr}${log4}`); + } + } + debugJson(obj, indent = 0) { + if (ENABLED && this.id !== "__dummy__") { + try { + const str = JSON.stringify(obj, (_, value) => typeof value === "bigint" ? value.toString() : value, 2); + const lines = str.split("\n"); + const indentStr = " ".repeat(indent); + const logs = lines.map((line) => `${indentStr}${line}`); + this.logs.push(...logs); + } catch (e) { + this.logs.push(`Error in json, ${e}`); + } + } + } + async flush() { + if (ENABLED && this.id !== "__dummy__") { + try { + const origin = self.origin || window.location.origin; + await fetch(`${origin}/api/logger`, { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify({ + id: this.id, + logs: this.logs + }) + }); + } catch (ex) { + } + } + } + static getLogger(id) { + if (!id) { + return new _RemoteLogger("__dummy__"); + } + if (!_RemoteLogger.__loggers.has(id)) { + _RemoteLogger.__loggers.set(id, new _RemoteLogger(id)); + } + return _RemoteLogger.__loggers.get(id); + } + static generateUniqId(topic) { + const t = (/* @__PURE__ */ new Date()).getTime(); + const rnd = Math.floor(Math.random() * 1e6); + return `${topic}-${t}-${rnd}`; + } +}; +var RemoteLogger = _RemoteLogger; +RemoteLogger.__loggers = /* @__PURE__ */ new Map(); +var logPools = (quoteId, pools, indent = 1) => { + const logger3 = RemoteLogger.getLogger(quoteId); + for (const pool of pools) { + logger3.debug(poolInfoStr(pool), indent); + } +}; +var poolInfoStr = (pool) => { + switch (pool.type) { + case 1 /* V3 */: + return `[V3] id=${pool.address}, ${pool.token0.symbol}/${pool.token1.symbol}`; + case 0 /* V2 */: { + const id = sdk.Pair.getAddress(pool.reserve0.currency.wrapped, pool.reserve1.currency.wrapped); + return `[V2] id=${id}, ${pool.reserve0.currency.symbol}/${pool.reserve1.currency.symbol}`; + } + case 2 /* STABLE */: + return `[Stable] id=${pool.address}, ${pool.balances[0].currency.symbol}/${pool.balances[1].currency.symbol}`; + case 4 /* InfinityBIN */: + return `[InfinityBIN] id=${pool.id}, ${pool.currency0.symbol}/${pool.currency1.symbol}`; + case 3 /* InfinityCL */: + return `[InfinityCL] id=${pool.id}, ${pool.currency0.symbol}/${pool.currency1.symbol}`; + case 5 /* InfinityStable */: + return `[InfinityStable] id=${pool.id}, ${pool.currency0.symbol}/${pool.currency1.symbol}`; + default: + throw new Error("[poolInfoStr]: Unknown pool type"); + } +}; +var logRoutes = (quoteId, routes, indent = 1) => { + for (const [i, route] of Object.entries(routes)) { + const logger3 = RemoteLogger.getLogger(quoteId); + const { type, pools, input, output } = route; + logger3.debug(`- #${i} ${RouteType[type]}, pools=${pools.length}, ${input.symbol}/${output.symbol}`, indent); + logPools(quoteId, pools, indent + 1); + } +}; + +// evm/v3-router/functions/getBestRouteCombinationByQuotes.ts +function getBestRouteCombinationByQuotes(amount, quoteCurrency, routesWithQuote, tradeType, config, quoteId) { + const logger3 = RemoteLogger.getLogger(quoteId); + const chainId = amount.currency.chainId; + const percents = []; + const percentToQuotes = {}; + for (const routeWithQuote of routesWithQuote) { + if (!percentToQuotes[routeWithQuote.percent]) { + percentToQuotes[routeWithQuote.percent] = []; + percents.push(routeWithQuote.percent); + } + percentToQuotes[routeWithQuote.percent].push(routeWithQuote); + } + logger3.debug("--- percentToQuotes ---"); + logger3.debugJson( + Object.fromEntries( + Object.entries(percentToQuotes).map(([key, value]) => [ + key, + value.map((y) => ({ + pools: y.pools.map((pool) => poolInfoStr(pool)), + quoteAdjustedForGas: y.quoteAdjustedForGas.info() + })) + ]) + ), + 2 + ); + logger3.debug("--- END percentToQuotes ---"); + const swapRoute = getBestSwapRouteBy( + tradeType, + percentToQuotes, + percents.sort((a, b) => a - b), + chainId, + (rq) => rq.quoteAdjustedForGas, + config, + quoteId + ); + if (!swapRoute) { + logger3.debug(`Could not find a valid swap route`); + return null; + } + const { routes: routeAmounts } = swapRoute; + const totalAmount = routeAmounts.reduce( + (total, routeAmount) => total.add(routeAmount.amount), + sdk.CurrencyAmount.fromRawAmount(routeAmounts[0].amount.currency, 0) + ); + const missingAmount = amount.subtract(totalAmount); + if (missingAmount.greaterThan(0)) { + logger3.debug( + `Optimal route's amounts did not equal exactIn/exactOut total. Adding missing amount to last route in array. missingAmount=${missingAmount.quotient.toString()}` + ); + routeAmounts[routeAmounts.length - 1].amount = routeAmounts[routeAmounts.length - 1].amount.add(missingAmount); + } + logger3.debug(`Found best swap route. ${routeAmounts.length} split.`); + const _log = { + routes: routeAmounts, + numSplits: routeAmounts.length, + amount: amount.toExact(), + quote: swapRoute.quote.toExact(), + quoteGasAdjusted: swapRoute.quoteGasAdjusted.toFixed(Math.min(swapRoute.quoteGasAdjusted.currency.decimals, 2)), + estimatedGasUSD: swapRoute.estimatedGasUsedUSD.toFixed( + Math.min(swapRoute.estimatedGasUsedUSD.currency.decimals, 2) + ), + estimatedGasToken: swapRoute.estimatedGasUsedQuoteToken.toFixed( + Math.min(swapRoute.estimatedGasUsedQuoteToken.currency.decimals, 2) + ) + }; + logger3.debugJson(_log); + const { routes, quote: quoteAmount, estimatedGasUsed, estimatedGasUsedUSD } = swapRoute; + const quote = sdk.CurrencyAmount.fromRawAmount(quoteCurrency, quoteAmount.quotient); + const isExactIn = tradeType === sdk.TradeType.EXACT_INPUT; + return { + routes: routes.map(({ type, amount: routeAmount, quote: routeQuoteAmount, pools, path, percent }) => { + const routeQuote = sdk.CurrencyAmount.fromRawAmount(quoteCurrency, routeQuoteAmount.quotient); + return { + percent, + type, + pools, + path, + inputAmount: isExactIn ? routeAmount : routeQuote, + outputAmount: isExactIn ? routeQuote : routeAmount + }; + }), + gasEstimate: estimatedGasUsed, + gasEstimateInUSD: estimatedGasUsedUSD, + inputAmount: isExactIn ? amount : quote, + outputAmount: isExactIn ? quote : amount + }; +} +function getBestSwapRouteBy(tradeType, percentToQuotes, percents, chainId, by, { maxSplits = 4, minSplits = 0 }, quoteId) { + const logger3 = RemoteLogger.getLogger(quoteId); + const percentToSortedQuotes = Object.fromEntries( + Object.entries(percentToQuotes).map(([percent, routeQuotes]) => { + const sorted = routeQuotes.sort((routeQuoteA, routeQuoteB) => { + if (tradeType === sdk.TradeType.EXACT_INPUT) { + return by(routeQuoteA).greaterThan(by(routeQuoteB)) ? -1 : 1; + } + return by(routeQuoteA).lessThan(by(routeQuoteB)) ? -1 : 1; + }); + return [percent, sorted]; + }) + ); + const quoteCompFn = tradeType === sdk.TradeType.EXACT_INPUT ? (a, b) => a.greaterThan(b) : (a, b) => a.lessThan(b); + const sumFn = (currencyAmounts) => { + let sum2 = currencyAmounts[0]; + for (let i = 1; i < currencyAmounts.length; i++) { + sum2 = sum2.add(currencyAmounts[i]); + } + return sum2; + }; + let bestQuote; + let bestSwap; + const bestSwapsPerSplit = new FixedReverseHeap__default.default( + Array, + (a, b) => { + return quoteCompFn(a.quote, b.quote) ? -1 : 1; + }, + 3 + ); + if (!percentToSortedQuotes[100] || minSplits > 1) { + logger3.debug(`Did not find a valid route without any splits. Continuing search anyway`); + } else { + bestQuote = by(percentToSortedQuotes[100][0]); + bestSwap = [percentToSortedQuotes[100][0]]; + logger3.debug("---bestQuote---"); + logger3.debugJson(bestQuote, 3); + logger3.debug("---bestSwap---"); + logger3.debugJson(bestSwap, 3); + for (const routeWithQuote of percentToSortedQuotes[100].slice(0, 5)) { + bestSwapsPerSplit.push({ + quote: by(routeWithQuote), + routes: [routeWithQuote] + }); + } + } + logger3.debug("--- start BFS ---"); + const queue = new Queue__default.default(); + for (let i = percents.length; i >= 0; i--) { + const percent = percents[i]; + if (!percentToSortedQuotes[percent]) { + continue; + } + queue.enqueue({ + curRoutes: [percentToSortedQuotes[percent][0]], + percentIndex: i, + remainingPercent: 100 - percent, + special: false + }); + if (!percentToSortedQuotes[percent] || !percentToSortedQuotes[percent][1]) { + continue; + } + queue.enqueue({ + curRoutes: [percentToSortedQuotes[percent][1]], + percentIndex: i, + remainingPercent: 100 - percent, + special: true + }); + } + let splits = 1; + while (queue.size > 0) { + logger3.debug(`bfs loop: queue.size=${queue.size}, splits=${splits}`, 2); + logger3.debugJson( + { + top3: Array.from(bestSwapsPerSplit.consume()).map( + (q) => `${q.quote.toExact()} (${q.routes.map( + (r) => `${r.percent}% ${r.amount.toExact()} ${r.pools.map((p) => { + if (isV2Pool(p)) { + return `V2 ${p.reserve0.currency.symbol}-${p.reserve1.currency.symbol}`; + } + if (isV3Pool(p)) { + return `V3 fee ${p.fee} ${p.token0.symbol}-${p.token1.symbol}`; + } + if (isStablePool(p)) { + return `Stable ${p.balances.map((b) => b.currency).join("-")}`; + } + return `Unsupported pool ${p}`; + }).join(", ")} ${r.quote.toExact()}` + ).join(", ")})` + ), + onQueue: queue.size + }, + 2 + ); + bestSwapsPerSplit.clear(); + let layer = queue.size; + splits++; + if (splits >= 3 && bestSwap && bestSwap.length < splits - 1) { + break; + } + if (splits > maxSplits) { + logger3.debug(`Max splits ${maxSplits} reached. Stopping search.`); + break; + } + while (layer > 0) { + layer--; + const { remainingPercent, curRoutes, percentIndex, special } = queue.dequeue(); + logger3.debug(`dequeue remainingPercent=${remainingPercent}%, percentIndex=${percentIndex}`, 3); + logger3.debug(routesStr(curRoutes), 3); + for (let i = percentIndex; i >= 0; i--) { + const percentA = percents[i]; + if (percentA > remainingPercent) { + continue; + } + if (!percentToSortedQuotes[percentA]) { + continue; + } + const candidateRoutesA = percentToSortedQuotes[percentA]; + const routeWithQuoteA = findFirstRouteNotUsingUsedPools(curRoutes, candidateRoutesA); + if (!routeWithQuoteA) { + continue; + } + const remainingPercentNew = remainingPercent - percentA; + const curRoutesNew = [...curRoutes, routeWithQuoteA]; + if (remainingPercentNew === 0 && splits >= minSplits) { + const quotesNew = curRoutesNew.map((r) => by(r)); + const quoteNew = sumFn(quotesNew); + const gasCostL1QuoteToken2 = sdk.CurrencyAmount.fromRawAmount(quoteNew.currency, 0); + const quoteAfterL1Adjust = tradeType === sdk.TradeType.EXACT_INPUT ? quoteNew.subtract(gasCostL1QuoteToken2) : quoteNew.add(gasCostL1QuoteToken2); + bestSwapsPerSplit.push({ + quote: quoteAfterL1Adjust, + routes: curRoutesNew + }); + if (!bestQuote || quoteCompFn(quoteAfterL1Adjust, bestQuote)) { + bestQuote = quoteAfterL1Adjust; + bestSwap = curRoutesNew; + } + } else { + queue.enqueue({ + curRoutes: curRoutesNew, + remainingPercent: remainingPercentNew, + percentIndex: i, + special + }); + } + } + } + } + if (!bestSwap) { + logger3.debug(`Could not find a valid swap`); + return null; + } + let quoteGasAdjusted = sumFn(bestSwap.map((routeWithValidQuote) => routeWithValidQuote.quoteAdjustedForGas)); + const estimatedGasUsed = bestSwap.map((routeWithValidQuote) => routeWithValidQuote.gasEstimate).reduce((sum2, routeWithValidQuote) => sum2 + routeWithValidQuote, 0n); + if (!chunkZNSTBYLO_js.usdGasTokensByChain[chainId] || !chunkZNSTBYLO_js.usdGasTokensByChain[chainId][0]) { + throw new Error(`Could not find a USD token for computing gas costs on ${chainId}`); + } + const usdToken = chunkZNSTBYLO_js.usdGasTokensByChain[chainId][0]; + const usdTokenDecimals = usdToken.decimals; + const gasCostsL1ToL2 = { + gasUsedL1: 0n, + gasCostL1USD: sdk.CurrencyAmount.fromRawAmount(usdToken, 0), + gasCostL1QuoteToken: sdk.CurrencyAmount.fromRawAmount( + // eslint-disable-next-line @typescript-eslint/no-non-null-asserted-optional-chain + bestSwap[0]?.quote.currency, + 0 + ) + }; + const { gasCostL1USD, gasCostL1QuoteToken } = gasCostsL1ToL2; + const estimatedGasUsedUSDs = bestSwap.map((routeWithValidQuote) => { + const decimalsDiff = usdTokenDecimals - routeWithValidQuote.gasCostInUSD.currency.decimals; + if (decimalsDiff === 0) { + return sdk.CurrencyAmount.fromRawAmount(usdToken, routeWithValidQuote.gasCostInUSD.quotient); + } + return sdk.CurrencyAmount.fromRawAmount( + usdToken, + routeWithValidQuote.gasCostInUSD.quotient * 10n ** BigInt(decimalsDiff) + ); + }); + let estimatedGasUsedUSD = sumFn(estimatedGasUsedUSDs); + if (!estimatedGasUsedUSD.currency.equals(gasCostL1USD.currency)) { + const decimalsDiff = usdTokenDecimals - gasCostL1USD.currency.decimals; + estimatedGasUsedUSD = estimatedGasUsedUSD.add( + sdk.CurrencyAmount.fromRawAmount(usdToken, gasCostL1USD.quotient * 10n ** BigInt(decimalsDiff)) + ); + } else { + estimatedGasUsedUSD = estimatedGasUsedUSD.add(gasCostL1USD); + } + const estimatedGasUsedQuoteToken = sumFn( + bestSwap.map((routeWithValidQuote) => routeWithValidQuote.gasCostInToken) + ).add(gasCostL1QuoteToken); + const quote = sumFn(bestSwap.map((routeWithValidQuote) => routeWithValidQuote.quote)); + if (tradeType === sdk.TradeType.EXACT_INPUT) { + const quoteGasAdjustedForL1 = quoteGasAdjusted.subtract(gasCostL1QuoteToken); + quoteGasAdjusted = quoteGasAdjustedForL1; + } else { + const quoteGasAdjustedForL1 = quoteGasAdjusted.add(gasCostL1QuoteToken); + quoteGasAdjusted = quoteGasAdjustedForL1; + } + const routeWithQuotes = bestSwap.sort( + (routeAmountA, routeAmountB) => routeAmountB.amount.greaterThan(routeAmountA.amount) ? 1 : -1 + ); + return { + quote, + quoteGasAdjusted, + estimatedGasUsed, + estimatedGasUsedUSD, + estimatedGasUsedQuoteToken, + routes: routeWithQuotes + }; +} +var findFirstRouteNotUsingUsedPools = (usedRoutes, candidateRouteQuotes) => { + const poolAddressSet = /* @__PURE__ */ new Set(); + const usedPoolAddresses = usedRoutes.flatMap(({ pools }) => pools.map(getPoolAddress)); + for (const poolAddress of usedPoolAddresses) { + poolAddressSet.add(poolAddress); + } + for (const routeQuote of candidateRouteQuotes) { + const { pools } = routeQuote; + const poolAddresses = pools.map(getPoolAddress); + if (poolAddresses.some((poolAddress) => poolAddressSet.has(poolAddress))) { + continue; + } + return routeQuote; + } + return null; +}; +var routesStr = (routes) => { + return routes.map((route) => { + return route.pools.map((p) => PoolType[p.type]).join(", "); + }).join(";"); +}; + +// evm/v3-router/providers/poolProviders/poolProviderWithCache.ts +function createPoolProviderWithCache(provider) { + return provider; +} +function formatFraction(fraction, precision = 6, rounding = void 0) { + if (!fraction || fraction.denominator === 0n) { + return void 0; + } + if (precision === 0 || fraction.greaterThan(10n ** BigInt(precision))) { + return fraction.toFixed(0); + } + return fraction.toSignificant(precision, void 0, rounding); +} +function formatPrice(price, precision) { + if (!price) { + return void 0; + } + return formatFraction(price?.asFraction.multiply(price?.scalar), precision); +} + +// evm/utils/withFallback.ts +function withTimeout(fn, duration) { + return function callWithTimeout(...args) { + return Promise.race([ + fn(...args), + new Promise((_, reject) => { + setTimeout(() => reject(new Error(`Request timeout ${duration}ms`)), duration); + }) + ]); + }; +} +function withFallback(calls) { + return async function asyncCall(...args) { + const numOfCalls = calls.length; + if (numOfCalls === 0) { + throw new Error("No valid calls"); + } + for (const [index, { timeout = 2e3, asyncFn }] of calls.entries()) { + const fn = index < numOfCalls - 1 ? withTimeout(asyncFn, timeout) : asyncFn; + try { + const result = await fn(...args); + return result; + } catch (e) { + if (index === numOfCalls - 1) { + throw e; + } + if (process.env.NODE_ENV !== "production") { + console.warn(`Call failed with error %O, try next fallback`, e); + } + } + } + throw new Error("Unexpected end of call"); + }; +} +function createAsyncCallWithFallbacks(defaultCall, options) { + const { fallbacks = [], fallbackTimeout: timeout = 3e3 } = options || {}; + return withFallback( + [defaultCall, ...fallbacks].map((asyncFn) => ({ + asyncFn, + timeout + })) + ); +} +var tokenPriceQuery = graphqlRequest.gql` + query getTokens($pageSize: Int!, $tokenAddrs: [ID!]) { + tokens(first: $pageSize, where: { id_in: $tokenAddrs }) { + id + derivedUSD + } + } +`; +function createCommonTokenPriceProvider(getTokenPrices) { + return async function getCommonTokenPrices2({ currencyA, currencyB, ...rest }) { + const baseTokens = await getCheckAgainstBaseTokens(currencyA, currencyB); + if (!baseTokens) { + return null; + } + const map = /* @__PURE__ */ new Map(); + const idToToken = {}; + const addresses = baseTokens.map((t) => { + const address = viem.getAddress(t.address); + idToToken[address] = t; + return address; + }); + const tokenPrices = await getTokenPrices({ addresses, chainId: currencyA?.chainId, ...rest }); + for (const { address, priceUSD } of tokenPrices) { + const token = idToToken[viem.getAddress(address)]; + if (token) { + map.set(token.wrapped.address, parseFloat(priceUSD) || 0); + } + } + return map; + }; +} +var getTokenUsdPricesBySubgraph = async ({ + addresses, + chainId, + provider +}) => { + const client = provider?.({ chainId }); + if (!client) { + throw new Error("No valid subgraph data provider"); + } + const { tokens: tokenPrices } = await client.request( + tokenPriceQuery, + { + pageSize: 1e3, + tokenAddrs: addresses.map((addr) => addr.toLocaleLowerCase()) + } + ); + return tokenPrices.map(({ id, derivedUSD }) => ({ + address: id, + priceUSD: derivedUSD + })); +}; +var getCommonTokenPricesBySubgraph = createCommonTokenPriceProvider(getTokenUsdPricesBySubgraph); +function withCache(fetchPrices, options) { + const cache = /* @__PURE__ */ new Map(); + const { requireLlamaChain = false } = options || {}; + return async ({ addresses, chainId }) => { + if (!chainId) { + return []; + } + if (requireLlamaChain && !chains.getLlamaChainName(chainId)) { + throw new Error(`Chain ${chainId} is not supported by Llama API`); + } + const [cachedResults, addressesToFetch] = addresses.reduce( + ([cachedAddrs, newAddrs], address) => { + const cached = cache.get(address); + if (!cached) { + newAddrs.push(address); + } else { + cachedAddrs.push(cached); + } + return [cachedAddrs, newAddrs]; + }, + [[], []] + ); + if (!addressesToFetch.length) { + return cachedResults; + } + const freshResults = await fetchPrices({ addresses: addressesToFetch, chainId }); + for (const result of freshResults) { + cache.set(viem.getAddress(result.address), result); + } + return [...cachedResults, ...freshResults]; + }; +} +var createGetTokenPriceFromLlma = ({ endpoint }) => { + return async ({ addresses, chainId }) => { + const list = addresses.map((address) => `${chains.getLlamaChainName(chainId)}:${address.toLocaleLowerCase()}`).join(","); + const result = await fetch(`${endpoint}/${list}`).then( + (res) => res.json() + ); + const { coins = {} } = result; + return Object.entries(coins).map(([key, value]) => { + const [, address] = key.split(":"); + return { address, priceUSD: value.price }; + }); + }; +}; +var getCommonTokenPricesByLlma = createCommonTokenPriceProvider( + withCache( + createGetTokenPriceFromLlma({ + endpoint: "https://coins.llama.fi/prices/current" + }), + { requireLlamaChain: true } + ) +); +var createGetTokenPriceFromWalletApi = ({ endpoint }) => { + return async ({ addresses, chainId }) => { + const list = addresses.map((address) => `${chainId}:${address.toLowerCase()}`).join(","); + const encodedList = encodeURIComponent(list); + const result = await fetch(`${endpoint}/list/${encodedList}`).then((res) => res.json()); + return Object.entries(result).map(([key, price]) => { + const [, address] = key.split(":"); + return { address, priceUSD: String(price) }; + }); + }; +}; +var normalizeEndpoint = (value) => value?.replace(/\/+$/, "") ?? ""; +var WALLET_API_ENDPOINT = normalizeEndpoint(process.env.NEXT_PUBLIC_WALLET_API); +var getCommonTokenPricesByWalletApi = createCommonTokenPriceProvider( + withCache( + createGetTokenPriceFromWalletApi({ + endpoint: `${WALLET_API_ENDPOINT}/v1/prices` + }) + ) +); +var getCommonTokenPrices = withFallback([ + { + asyncFn: ({ currencyA, currencyB }) => getCommonTokenPricesByLlma({ currencyA, currencyB }), + timeout: 3e3 + }, + { + asyncFn: ({ currencyA, currencyB }) => getCommonTokenPricesByWalletApi({ currencyA, currencyB }), + timeout: 3e3 + }, + { + asyncFn: ({ currencyA, currencyB, v3SubgraphProvider }) => getCommonTokenPricesBySubgraph({ currencyA, currencyB, provider: v3SubgraphProvider }) + } +]); +var getV2PoolsOnChain = createOnChainPoolFactory({ + abi: chunkZNSTBYLO_js.pancakePairABI, + getPossiblePoolMetas: async ([currencyA, currencyB]) => { + if (chains.getChainConfig(currencyA.chainId)?.features?.v2 === false) { + return []; + } + return [{ id: computeV2PoolAddress(currencyA.wrapped, currencyB.wrapped), currencyA, currencyB }]; + }, + buildPoolInfoCalls: ({ id: address }) => [ + { + address, + functionName: "getReserves", + args: [] + } + ], + buildPool: ({ currencyA, currencyB }, [reserves]) => { + if (!reserves) { + return null; + } + const [reserve0, reserve1] = reserves; + const [token0, token1] = currencyA.wrapped.sortsBefore(currencyB.wrapped) ? [currencyA, currencyB] : [currencyB, currencyA]; + return { + type: 0 /* V2 */, + reserve0: sdk.CurrencyAmount.fromRawAmount(token0, reserve0.toString()), + reserve1: sdk.CurrencyAmount.fromRawAmount(token1, reserve1.toString()) + }; + } +}); +var getStablePoolsOnChain = createOnChainPoolFactory({ + abi: chunkZNSTBYLO_js.stableSwapPairABI, + getPossiblePoolMetas: async ([currencyA, currencyB]) => { + const poolConfigs = await stableSwapSdk.getStableSwapPools(currencyA.chainId); + return poolConfigs.filter(({ token, quoteToken }) => { + const tokenA = tokenLists.deserializeToken(token); + const tokenB = tokenLists.deserializeToken(quoteToken); + return tokenA.equals(currencyA.wrapped) && tokenB.equals(currencyB.wrapped) || tokenA.equals(currencyB.wrapped) && tokenB.equals(currencyA.wrapped); + }).map(({ stableSwapAddress }) => ({ + id: stableSwapAddress, + currencyA, + currencyB + })); + }, + buildPoolInfoCalls: ({ id: address }) => [ + { + address, + functionName: "balances", + args: [0] + }, + { + address, + functionName: "balances", + args: [1] + }, + { + address, + functionName: "A", + args: [] + }, + { + address, + functionName: "fee", + args: [] + }, + { + address, + functionName: "FEE_DENOMINATOR", + args: [] + } + ], + buildPool: ({ currencyA, currencyB, id: address }, [balance0, balance1, a, fee, feeDenominator]) => { + if (!balance0 || !balance1 || !a || !fee || !feeDenominator) { + return null; + } + const [token0, token1] = currencyA.wrapped.sortsBefore(currencyB.wrapped) ? [currencyA, currencyB] : [currencyB, currencyA]; + return { + address, + type: 2 /* STABLE */, + balances: [ + sdk.CurrencyAmount.fromRawAmount(token0, balance0.toString()), + sdk.CurrencyAmount.fromRawAmount(token1, balance1.toString()) + ], + amplifier: BigInt(a.toString()), + fee: new sdk.Percent(BigInt(fee.toString()), BigInt(feeDenominator.toString())) + }; + } +}); +var getV3PoolsWithoutTicksOnChain = createOnChainPoolFactory({ + abi: v3Sdk.pancakeV3PoolABI, + getPossiblePoolMetas: async ([currencyA, currencyB]) => { + const deployerAddress = v3Sdk.DEPLOYER_ADDRESSES[currencyA.chainId]; + if (chains.getChainConfig(currencyA.chainId)?.features?.v3 === false || !viem.isAddress(deployerAddress ?? "")) { + return []; + } + return [v3Sdk.FeeAmount.LOWEST, v3Sdk.FeeAmount.LOW, v3Sdk.FeeAmount.MEDIUM, v3Sdk.FeeAmount.HIGH].map((fee) => ({ + id: computeV3PoolAddress({ + deployerAddress, + tokenA: currencyA.wrapped, + tokenB: currencyB.wrapped, + fee + }), + currencyA, + currencyB, + fee + })); + }, + buildPoolInfoCalls: ({ id: address, currencyA, currencyB }) => [ + { + address, + functionName: "liquidity" + }, + { + address, + functionName: "slot0" + }, + { + abi: sdk.erc20Abi, + address: currencyA.wrapped.address, + functionName: "balanceOf", + args: [address] + }, + { + abi: sdk.erc20Abi, + address: currencyB.wrapped.address, + functionName: "balanceOf", + args: [address] + } + ], + buildPool: ({ currencyA, currencyB, fee, id: address }, [liquidity, slot0, balanceA, balanceB]) => { + if (!slot0) { + return null; + } + const [sqrtPriceX96, tick, , , , feeProtocol] = slot0; + const sorted = currencyA.wrapped.sortsBefore(currencyB.wrapped); + const [balance0, balance1] = sorted ? [balanceA, balanceB] : [balanceB, balanceA]; + const [token0, token1] = sorted ? [currencyA, currencyB] : [currencyB, currencyA]; + const [token0ProtocolFee, token1ProtocolFee] = v3Sdk.parseProtocolFees(feeProtocol); + return { + type: 1 /* V3 */, + token0, + token1, + reserve0: sdk.CurrencyAmount.fromRawAmount(token0, balance0), + reserve1: sdk.CurrencyAmount.fromRawAmount(token1, balance1), + fee, + liquidity: BigInt(liquidity.toString()), + sqrtRatioX96: BigInt(sqrtPriceX96.toString()), + tick: Number(tick), + address, + token0ProtocolFee, + token1ProtocolFee + }; + } +}); +function createOnChainPoolFactory({ abi, getPossiblePoolMetas, buildPoolInfoCalls, buildPool }) { + return async function poolFactory(pairs, provider, _blockNumber) { + if (!provider) { + throw new Error("No valid onchain data provider"); + } + const chainId = pairs[0]?.[0]?.chainId; + const client = provider({ chainId }); + if (!chainId || !client) { + return []; + } + const poolAddressSet = /* @__PURE__ */ new Set(); + const poolMetas = []; + const allPossibleMetas = await Promise.all(pairs.map((pair) => getPossiblePoolMetas(pair, client))); + for (const possiblePoolMetas of allPossibleMetas) { + for (const meta of possiblePoolMetas) { + if (!poolAddressSet.has(meta.id)) { + poolMetas.push(meta); + poolAddressSet.add(meta.id); + } + } + } + let calls = []; + let poolCallSize = 0; + for (const meta of poolMetas) { + const poolCalls = buildPoolInfoCalls(meta); + if (!poolCallSize) { + poolCallSize = poolCalls.length; + } + if (!poolCallSize || poolCallSize !== poolCalls.length) { + throw new Error("Inconsistent pool data call"); + } + calls = [...calls, ...poolCalls]; + } + if (!calls.length) { + return []; + } + const results = await client.multicall({ + contracts: calls.map((call) => ({ + abi: call.abi || abi, + address: call.address, + functionName: call.functionName, + args: call.args + })), + allowFailure: true + }); + const pools = []; + for (let i = 0; i < poolMetas.length; i += 1) { + const poolResults = results.slice(i * poolCallSize, (i + 1) * poolCallSize); + const pool = buildPool( + poolMetas[i], + poolResults.map((result) => result.result) + ); + if (pool) { + pools.push(pool); + } + } + return pools; + }; +} +var DEFAULT_POOL_SELECTOR_CONFIG = { + topN: 2, + topNDirectSwaps: 2, + topNTokenInOut: 2, + topNSecondHop: 1, + topNWithEachBaseToken: 3, + topNWithBaseToken: 3 +}; +var INFINITY_DEFAULT_POOL_SELECTOR_CONFIG = { + [chains.ChainId.BSC]: { + topN: 1, + topNDirectSwaps: 1, + topNTokenInOut: 1, + topNSecondHop: 1, + topNWithEachBaseToken: 1, + topNWithBaseToken: 1 + }, + [chains.ChainId.BSC_TESTNET]: { + topN: 1, + topNDirectSwaps: 1, + topNTokenInOut: 1, + topNSecondHop: 1, + topNWithEachBaseToken: 1, + topNWithBaseToken: 1 + }, + [chains.ChainId.ETHEREUM]: { + topN: 1, + topNDirectSwaps: 1, + topNTokenInOut: 1, + topNSecondHop: 1, + topNWithEachBaseToken: 1, + topNWithBaseToken: 1 + }, + [chains.ChainId.GOERLI]: { + topN: 1, + topNDirectSwaps: 1, + topNTokenInOut: 1, + topNSecondHop: 1, + topNWithEachBaseToken: 1, + topNWithBaseToken: 1 + } +}; +var V3_DEFAULT_POOL_SELECTOR_CONFIG = { + [chains.ChainId.BSC]: { + topN: 2, + topNDirectSwaps: 2, + topNTokenInOut: 2, + topNSecondHop: 1, + topNWithEachBaseToken: 3, + topNWithBaseToken: 4 + }, + [chains.ChainId.BSC_TESTNET]: { + topN: 2, + topNDirectSwaps: 2, + topNTokenInOut: 2, + topNSecondHop: 1, + topNWithEachBaseToken: 3, + topNWithBaseToken: 4 + }, + [chains.ChainId.ETHEREUM]: { + topN: 2, + topNDirectSwaps: 2, + topNTokenInOut: 2, + topNSecondHop: 1, + topNWithEachBaseToken: 3, + topNWithBaseToken: 4 + }, + [chains.ChainId.GOERLI]: { + topN: 2, + topNDirectSwaps: 2, + topNTokenInOut: 2, + topNSecondHop: 1, + topNWithEachBaseToken: 3, + topNWithBaseToken: 4 + } +}; +var V2_DEFAULT_POOL_SELECTOR_CONFIG = { + [chains.ChainId.BSC]: { + topN: 3, + topNDirectSwaps: 2, + topNTokenInOut: 2, + topNSecondHop: 1, + topNWithEachBaseToken: 3, + topNWithBaseToken: 3 + }, + [chains.ChainId.BSC_TESTNET]: { + topN: 3, + topNDirectSwaps: 2, + topNTokenInOut: 2, + topNSecondHop: 1, + topNWithEachBaseToken: 3, + topNWithBaseToken: 3 + }, + [chains.ChainId.ETHEREUM]: { + topN: 3, + topNDirectSwaps: 2, + topNTokenInOut: 2, + topNSecondHop: 1, + topNWithEachBaseToken: 3, + topNWithBaseToken: 3 + }, + [chains.ChainId.GOERLI]: { + topN: 3, + topNDirectSwaps: 2, + topNTokenInOut: 2, + topNSecondHop: 1, + topNWithEachBaseToken: 3, + topNWithBaseToken: 3 + } +}; +var V3_TOKEN_POOL_SELECTOR_CONFIG = { + [chains.ChainId.BSC]: { + [tokens.bscTokens.ankr.address]: { + topNTokenInOut: 4 + }, + [tokens.bscTokens.ankrbnb.address]: { + topNTokenInOut: 4 + }, + [tokens.bscTokens.ankrETH.address]: { + topNTokenInOut: 4 + }, + [tokens.bscTokens.wbeth.address]: { + topNSecondHop: 3 + } + } +}; +var V2_TOKEN_POOL_SELECTOR_CONFIG = { + [chains.ChainId.BSC]: { + // GEM + "0x701F1ed50Aa5e784B8Fb89d1Ba05cCCd627839a7": { + topNTokenInOut: 4 + } + } +}; +var ROUTE_CONFIG_BY_CHAIN = { + [chains.ChainId.ZKSYNC]: { + distributionPercent: 20 + }, + [chains.ChainId.BASE]: { + distributionPercent: 10 + } +}; + +// evm/v3-router/utils/mergePoolSelectorConfig.ts +function mergePoolSelectorConfig(baseConfig, customConfig) { + if (!customConfig) { + return baseConfig; + } + const merged = { ...baseConfig }; + const keys = Object.keys(merged); + for (const key of keys) { + merged[key] = Math.max(merged[key], customConfig[key] || 0); + } + return merged; +} + +// evm/v3-router/utils/getPoolSelectorConfig.ts +function poolSelectorConfigFactory(poolSelecorConfigMap, tokenPoolSelectorConfigMap) { + return function getPoolSelectorConfig(currencyA, currencyB) { + const chainId = currencyA?.chainId; + if (!chainId || !poolSelecorConfigMap[chainId]) { + return DEFAULT_POOL_SELECTOR_CONFIG; + } + const additionalConfigA = tokenPoolSelectorConfigMap[chainId]?.[currencyA?.wrapped?.address || "0x"]; + const additionalConfigB = tokenPoolSelectorConfigMap[chainId]?.[currencyB?.wrapped?.address || "0x"]; + return mergePoolSelectorConfig( + mergePoolSelectorConfig(poolSelecorConfigMap[chainId], additionalConfigA), + additionalConfigB + ); + }; +} +var getV3PoolSelectorConfig = poolSelectorConfigFactory( + V3_DEFAULT_POOL_SELECTOR_CONFIG, + V3_TOKEN_POOL_SELECTOR_CONFIG +); +var getV2PoolSelectorConfig = poolSelectorConfigFactory( + V2_DEFAULT_POOL_SELECTOR_CONFIG, + V2_TOKEN_POOL_SELECTOR_CONFIG +); +var getInfinityPoolSelectorConfig = poolSelectorConfigFactory(INFINITY_DEFAULT_POOL_SELECTOR_CONFIG, {}); + +// evm/v3-router/providers/poolProviders/poolTvlSelectors.ts +var sortByTvl = (a, b) => a.tvlUSD >= b.tvlUSD ? -1 : 1; +function poolSelectorFactory({ + getPoolSelectorConfig, + getToken0, + getToken1, + getPoolAddress: getPoolAddress2 +}) { + return function tvlSelector(currencyA, currencyB, unorderedPoolsWithTvl) { + const POOL_SELECTION_CONFIG = getPoolSelectorConfig(currencyA, currencyB); + if (!currencyA || !currencyB || !unorderedPoolsWithTvl.length) { + return []; + } + const poolsFromSubgraph = unorderedPoolsWithTvl.sort(sortByTvl); + const { chainId } = getToken0(poolsFromSubgraph[0]); + const baseTokens = chunkZNSTBYLO_js.BASES_TO_CHECK_TRADES_AGAINST[chainId] ?? []; + const poolSet = /* @__PURE__ */ new Set(); + const addToPoolSet = (pools2) => { + for (const pool of pools2) { + poolSet.add(getPoolAddress2(pool)); + } + }; + const topByBaseWithTokenIn = baseTokens.map((token) => { + return poolsFromSubgraph.filter((subgraphPool) => { + return getToken0(subgraphPool).wrapped.equals(token) && getToken1(subgraphPool).wrapped.equals(currencyA.wrapped) || getToken1(subgraphPool).wrapped.equals(token) && getToken0(subgraphPool).wrapped.equals(currencyA.wrapped); + }).sort(sortByTvl).slice(0, POOL_SELECTION_CONFIG.topNWithEachBaseToken); + }).reduce((acc, cur) => { + acc.push(...cur); + return acc; + }, []).sort(sortByTvl).slice(0, POOL_SELECTION_CONFIG.topNWithBaseToken); + addToPoolSet(topByBaseWithTokenIn); + const topByBaseWithTokenOut = baseTokens.map((token) => { + return poolsFromSubgraph.filter((subgraphPool) => { + if (poolSet.has(getPoolAddress2(subgraphPool))) { + return false; + } + return getToken0(subgraphPool).wrapped.equals(token) && getToken1(subgraphPool).wrapped.equals(currencyB.wrapped) || getToken1(subgraphPool).wrapped.equals(token) && getToken0(subgraphPool).wrapped.equals(currencyB.wrapped); + }).sort(sortByTvl).slice(0, POOL_SELECTION_CONFIG.topNWithEachBaseToken); + }).reduce((acc, cur) => { + acc.push(...cur); + return acc; + }, []).sort(sortByTvl).slice(0, POOL_SELECTION_CONFIG.topNWithBaseToken); + addToPoolSet(topByBaseWithTokenOut); + const top2DirectPools = poolsFromSubgraph.filter((subgraphPool) => { + if (poolSet.has(getPoolAddress2(subgraphPool))) { + return false; + } + return getToken0(subgraphPool).wrapped.equals(currencyA.wrapped) && getToken1(subgraphPool).wrapped.equals(currencyB.wrapped) || getToken1(subgraphPool).wrapped.equals(currencyA.wrapped) && getToken0(subgraphPool).wrapped.equals(currencyB.wrapped); + }).slice(0, POOL_SELECTION_CONFIG.topNDirectSwaps); + addToPoolSet(top2DirectPools); + const nativeToken = sdk.WNATIVE[chainId]; + const top2EthBaseTokenPool = nativeToken ? poolsFromSubgraph.filter((subgraphPool) => { + if (poolSet.has(getPoolAddress2(subgraphPool))) { + return false; + } + return getToken0(subgraphPool).wrapped.equals(nativeToken) && getToken1(subgraphPool).wrapped.equals(currencyA.wrapped) || getToken1(subgraphPool).wrapped.equals(nativeToken) && getToken0(subgraphPool).wrapped.equals(currencyA.wrapped); + }).slice(0, 1) : []; + addToPoolSet(top2EthBaseTokenPool); + const top2EthQuoteTokenPool = nativeToken ? poolsFromSubgraph.filter((subgraphPool) => { + if (poolSet.has(getPoolAddress2(subgraphPool))) { + return false; + } + return getToken0(subgraphPool).wrapped.equals(nativeToken) && getToken1(subgraphPool).wrapped.equals(currencyB.wrapped) || getToken1(subgraphPool).wrapped.equals(nativeToken) && getToken0(subgraphPool).wrapped.equals(currencyB.wrapped); + }).slice(0, 1) : []; + addToPoolSet(top2EthQuoteTokenPool); + const topByTVL = poolsFromSubgraph.slice(0, POOL_SELECTION_CONFIG.topN).filter((pool) => !poolSet.has(getPoolAddress2(pool))); + addToPoolSet(topByTVL); + const topByTVLUsingTokenBase = poolsFromSubgraph.filter((subgraphPool) => { + if (poolSet.has(getPoolAddress2(subgraphPool))) { + return false; + } + return getToken0(subgraphPool).wrapped.equals(currencyA.wrapped) || getToken1(subgraphPool).wrapped.equals(currencyA.wrapped); + }).slice(0, POOL_SELECTION_CONFIG.topNTokenInOut); + addToPoolSet(topByTVLUsingTokenBase); + const topByTVLUsingTokenQuote = poolsFromSubgraph.filter((subgraphPool) => { + if (poolSet.has(getPoolAddress2(subgraphPool))) { + return false; + } + return getToken0(subgraphPool).wrapped.equals(currencyB.wrapped) || getToken1(subgraphPool).wrapped.equals(currencyB.wrapped); + }).slice(0, POOL_SELECTION_CONFIG.topNTokenInOut); + addToPoolSet(topByTVLUsingTokenQuote); + const getTopByTVLUsingTokenSecondHops = (base, tokenToCompare) => base.map((subgraphPool) => { + return getToken0(subgraphPool).wrapped.equals(tokenToCompare.wrapped) ? getToken1(subgraphPool) : getToken0(subgraphPool); + }).map((secondHopToken) => { + return poolsFromSubgraph.filter((subgraphPool) => { + if (poolSet.has(getPoolAddress2(subgraphPool))) { + return false; + } + return getToken0(subgraphPool).wrapped.equals(secondHopToken.wrapped) || getToken1(subgraphPool).wrapped.equals(secondHopToken.wrapped); + }); + }).reduce((acc, cur) => { + acc.push(...cur); + return acc; + }, []).reduce((acc, cur) => { + if (!acc.some((p) => p === cur)) { + acc.push(cur); + } + return acc; + }, []).sort(sortByTvl).slice(0, POOL_SELECTION_CONFIG.topNSecondHop); + const topByTVLUsingTokenInSecondHops = getTopByTVLUsingTokenSecondHops( + [...topByTVLUsingTokenBase, ...topByBaseWithTokenIn], + currencyA + ); + addToPoolSet(topByTVLUsingTokenInSecondHops); + const topByTVLUsingTokenOutSecondHops = getTopByTVLUsingTokenSecondHops( + [...topByTVLUsingTokenQuote, ...topByBaseWithTokenOut], + currencyB + ); + addToPoolSet(topByTVLUsingTokenOutSecondHops); + const pools = [ + ...topByBaseWithTokenIn, + ...topByBaseWithTokenOut, + ...top2DirectPools, + ...top2EthBaseTokenPool, + ...top2EthQuoteTokenPool, + ...topByTVL, + ...topByTVLUsingTokenBase, + ...topByTVLUsingTokenQuote, + ...topByTVLUsingTokenInSecondHops, + ...topByTVLUsingTokenOutSecondHops + ]; + return pools.map(({ tvlUSD, ...rest }) => rest); + }; +} +var v3PoolTvlSelector = poolSelectorFactory({ + getPoolSelectorConfig: getV3PoolSelectorConfig, + getToken0: (p) => p.token0, + getToken1: (p) => p.token1, + getPoolAddress: (p) => p.address +}); +var v2PoolTvlSelector = poolSelectorFactory({ + getPoolSelectorConfig: getV2PoolSelectorConfig, + getToken0: (p) => p.reserve0.currency, + getToken1: (p) => p.reserve1.currency, + getPoolAddress: (p) => getPoolAddress(p) || "0x" +}); +var infinityPoolTvlSelector = poolSelectorFactory({ + getPoolSelectorConfig: getInfinityPoolSelectorConfig, + getToken0: (p) => p.currency0, + getToken1: (p) => p.currency1, + getPoolAddress: (p) => p.id +}); + +// evm/v3-router/providers/poolProviders/getV2CandidatePools.ts +function createV2PoolsProviderByCommonTokenPrices(getCommonTokenPrices2) { + return async function getV2Pools({ + currencyA, + currencyB, + pairs: providedPairs, + onChainProvider, + blockNumber, + ...rest + }) { + const pairs = providedPairs || await getPairCombinations(currencyA, currencyB); + const chainId = currencyA?.chainId ?? currencyB?.chainId; + const testnetMode = Boolean(chainId && chains.isTestnetChainId(chainId)); + const poolsFromOnChain = await getV2PoolsOnChain(pairs, onChainProvider, blockNumber); + let baseTokenUsdPrices = null; + if (testnetMode) { + try { + baseTokenUsdPrices = await getCommonTokenPrices2({ currencyA, currencyB, ...rest }); + } catch (error) { + logger.log("[v2] failed to get base token prices on testnet, continue with on-chain pools only", error); + } + } else { + baseTokenUsdPrices = await getCommonTokenPrices2({ currencyA, currencyB, ...rest }); + } + if (!poolsFromOnChain) { + throw new Error("Failed to get v2 candidate pools"); + } + if (!baseTokenUsdPrices) { + logger.log("Failed to get base token prices"); + return poolsFromOnChain.map((pool) => { + return { + ...pool, + tvlUSD: BigInt(0), + address: getPoolAddress(pool) + }; + }); + } + return poolsFromOnChain.map((pool) => { + const getAmountUsd = (amount) => { + if (amount.equalTo(sdk.ZERO)) { + return 0; + } + const price = baseTokenUsdPrices.get(amount.currency.wrapped.address); + if (price !== void 0) { + return parseFloat(amount.toExact()) * price; + } + const againstAmount = pool.reserve0.currency.equals(amount.currency) ? pool.reserve1 : pool.reserve0; + const againstUsdPrice = baseTokenUsdPrices.get(againstAmount.currency.wrapped.address); + if (againstUsdPrice) { + const poolPrice = new sdk.Price({ baseAmount: amount, quoteAmount: againstAmount }); + return parseFloat(amount.toExact()) * parseFloat(formatPrice(poolPrice, 6) || "0"); + } + return 0; + }; + return { + ...pool, + tvlUSD: BigInt(Math.floor(getAmountUsd(pool.reserve0) + getAmountUsd(pool.reserve1))), + address: getPoolAddress(pool) + }; + }); + }; +} +var getV2PoolsWithTvlByCommonTokenPrices = createV2PoolsProviderByCommonTokenPrices(getCommonTokenPrices); +function createGetV2CandidatePools(defaultGetV2Pools, options) { + const getV2PoolsWithFallbacks = createAsyncCallWithFallbacks(defaultGetV2Pools, options); + return async function getV2Pools(params) { + const { currencyA, currencyB } = params; + const pools = await getV2PoolsWithFallbacks(params); + return v2PoolTvlSelector(currencyA, currencyB, pools); + }; +} +async function getV2CandidatePools(params) { + const getV2PoolsWithFallbacks = createGetV2CandidatePools(getV2PoolsWithTvlByCommonTokenPrices); + return getV2PoolsWithFallbacks(params); +} +function subgraphPoolProviderFactory({ + id, + getPoolMetas, + getPoolsFromSubgraph +}) { + return async function subgraphPoolProvider({ + provider, + pairs + }) { + if (!provider) { + throw new Error("No valid subgraph data provider"); + } + const chainId = pairs[0]?.[0]?.chainId; + if (!chainId) { + return []; + } + const client = provider({ chainId }); + if (!client) { + logger.error("No subgraph client found for chainId", chainId); + return []; + } + metric(`SUBGRAPH_POOLS_START(${id})`, pairs); + const metaMap = /* @__PURE__ */ new Map(); + for (const pair of pairs) { + const metas = getPoolMetas(pair); + for (const meta of metas) { + metaMap.set(meta.id.toLocaleLowerCase(), meta); + } + } + const addresses = Array.from(metaMap.keys()); + const pools = await getPoolsFromSubgraph({ + addresses, + getPoolMetaByAddress: (address) => metaMap.get(address.toLocaleLowerCase()) ?? null, + client + }); + metric(`SUBGRAPH_POOLS_END(${id})`, pools); + return pools.filter((p) => !!p); + }; +} +var getV3PoolMeta = memoize( + ([currencyA, currencyB, feeAmount]) => ({ + id: v3Sdk.Pool.getAddress(currencyA.wrapped, currencyB.wrapped, feeAmount), + currencyA, + currencyB, + fee: feeAmount + }), + ([currencyA, currencyB, feeAmount]) => { + if (currencyA.wrapped.equals(currencyB.wrapped)) { + return [currencyA.chainId, currencyA.wrapped.address, feeAmount].join("_"); + } + const [token0, token1] = currencyA.wrapped.sortsBefore(currencyB.wrapped) ? [currencyA.wrapped, currencyB.wrapped] : [currencyB.wrapped, currencyA.wrapped]; + return [token0.chainId, token0.address, token1.address, feeAmount].join("_"); + } +); +var getV3PoolMetas = memoize( + (pair) => [v3Sdk.FeeAmount.LOWEST, v3Sdk.FeeAmount.LOW, v3Sdk.FeeAmount.MEDIUM, v3Sdk.FeeAmount.HIGH].map((fee) => getV3PoolMeta([...pair, fee])), + ([currencyA, currencyB]) => { + if (currencyA.wrapped.equals(currencyB.wrapped)) { + return [currencyA.chainId, currencyA.wrapped.address].join("_"); + } + const [token0, token1] = currencyA.wrapped.sortsBefore(currencyB.wrapped) ? [currencyA.wrapped, currencyB.wrapped] : [currencyB.wrapped, currencyA.wrapped]; + return [token0.chainId, token0.address, token1.address].join("_"); + } +); +var queryV3Pools = graphqlRequest.gql` + query getPools($pageSize: Int!, $poolAddrs: [String]) { + pools(first: $pageSize, where: { id_in: $poolAddrs }) { + id + tick + sqrtPrice + feeTier + liquidity + feeProtocol + totalValueLockedUSD + } + } +`; +var getV3PoolSubgraph = subgraphPoolProviderFactory({ + id: "V3", + getPoolMetas: getV3PoolMetas, + getPoolsFromSubgraph: async ({ addresses, getPoolMetaByAddress, client }) => { + const { pools: poolsFromSubgraph } = await client.request(queryV3Pools, { + pageSize: 1e3, + poolAddrs: addresses + }); + return poolsFromSubgraph.map(({ id, liquidity, sqrtPrice, tick, totalValueLockedUSD, feeProtocol }) => { + const meta = getPoolMetaByAddress(id); + if (!meta) { + return null; + } + const { fee, currencyA, currencyB, id: address } = meta; + const [token0, token1] = currencyA.wrapped.sortsBefore(currencyB.wrapped) ? [currencyA, currencyB] : [currencyB, currencyA]; + const [token0ProtocolFee, token1ProtocolFee] = v3Sdk.parseProtocolFees(feeProtocol); + return { + type: 1 /* V3 */, + fee, + token0, + token1, + liquidity: BigInt(liquidity), + sqrtRatioX96: BigInt(sqrtPrice), + tick: Number(tick), + address, + tvlUSD: BigInt(Number.parseInt(totalValueLockedUSD)), + token0ProtocolFee, + token1ProtocolFee + }; + }); + } +}); +var queryV2Pools = graphqlRequest.gql` + query getPools($pageSize: Int!, $poolAddrs: [ID!]) { + pairs(first: $pageSize, where: { id_in: $poolAddrs }) { + id + reserve0 + reserve1 + reserveUSD + } + } +`; +var getV2PoolSubgraph = subgraphPoolProviderFactory({ + id: "V2", + getPoolMetas: ([currencyA, currencyB]) => [ + { + currencyA, + currencyB, + id: computeV2PoolAddress(currencyA.wrapped, currencyB.wrapped) + } + ], + getPoolsFromSubgraph: async ({ addresses, getPoolMetaByAddress, client }) => { + const { pairs: poolsFromSubgraph } = await client.request(queryV2Pools, { + pageSize: 1e3, + poolAddrs: addresses + }); + return poolsFromSubgraph.map(({ id, reserveUSD, reserve0, reserve1 }) => { + const meta = getPoolMetaByAddress(id); + if (!meta) { + return null; + } + const { currencyA, currencyB, id: address } = meta; + const [token0, token1] = currencyA.wrapped.sortsBefore(currencyB.wrapped) ? [currencyA, currencyB] : [currencyB, currencyA]; + const reserve0Amount = tryParseAmount_default(reserve0, token0); + const reserve1Amount = tryParseAmount_default(reserve1, token1); + if (!reserve0Amount || !reserve1Amount) { + return null; + } + return { + address, + type: 0 /* V2 */, + reserve0: reserve0Amount, + reserve1: reserve1Amount, + tvlUSD: BigInt(Number.parseInt(reserveUSD)) + }; + }); + } +}); +function subgraphAllPoolsQueryFactory({ + getPoolsFromSubgraph, + getPoolId: getPoolId3 +}) { + return async function getAllPools({ + provider, + chainId, + pageSize = 1e3 + }) { + if (!provider || !chainId) { + throw new Error("No valid subgraph data provider"); + } + const client = provider({ chainId }); + if (!client) { + throw new Error(`No subgraph client found for chainId ${chainId}`); + } + let hasMorePools = true; + let lastId = ""; + let pools = []; + while (hasMorePools) { + const poolsAtCurrentPage = await getPoolsFromSubgraph({ client, lastId, pageSize, chainId }); + if (poolsAtCurrentPage.length < pageSize) { + hasMorePools = false; + pools = [...pools, ...poolsAtCurrentPage]; + break; + } + lastId = getPoolId3(poolsAtCurrentPage[poolsAtCurrentPage.length - 1]); + pools = [...pools, ...poolsAtCurrentPage]; + } + return pools; + }; +} +var queryAllV3Pools = graphqlRequest.gql` + query getPools($pageSize: Int!, $id: String) { + pools(first: $pageSize, where: { id_gt: $id }) { + id + tick + token0 { + symbol + id + decimals + } + token1 { + symbol + id + decimals + } + sqrtPrice + feeTier + liquidity + feeProtocol + totalValueLockedUSD + } + } +`; +var getAllV3PoolsFromSubgraph = subgraphAllPoolsQueryFactory({ + id: "getAllV3PoolsFromSubgraph", + getPoolsFromSubgraph: async ({ lastId, pageSize, client, chainId }) => { + const { pools: poolsFromSubgraph } = await client.request( + queryAllV3Pools, + { + pageSize, + id: lastId + } + ); + return poolsFromSubgraph.map( + ({ id, liquidity, sqrtPrice, tick, totalValueLockedUSD, feeProtocol, token0, token1, feeTier }) => { + const [token0ProtocolFee, token1ProtocolFee] = v3Sdk.parseProtocolFees(feeProtocol); + return { + type: 1 /* V3 */, + fee: Number(feeTier), + token0: new sdk.Token(chainId, viem.getAddress(token0.id), Number(token0.decimals), token0.symbol), + token1: new sdk.Token(chainId, viem.getAddress(token1.id), Number(token1.decimals), token1.symbol), + liquidity: BigInt(liquidity), + sqrtRatioX96: BigInt(sqrtPrice), + tick: Number(tick), + address: viem.getAddress(id), + tvlUSD: BigInt(Number.parseInt(totalValueLockedUSD)), + token0ProtocolFee, + token1ProtocolFee + }; + } + ); + }, + getPoolId: (p) => p.address +}); + +// evm/v3-router/providers/poolProviders/getV3CandidatePools.ts +var getV3PoolTvl = memoize( + (pools, poolAddress) => { + const poolWithTvl = pools.find((p) => p.address === poolAddress); + return poolWithTvl?.tvlUSD || 0n; + }, + (_, poolAddress) => poolAddress +); +var v3PoolsOnChainProviderFactory = (tvlReferenceProvider) => { + return async function getV3PoolsWithTvlFromOnChain2(params) { + const { currencyA, currencyB, pairs: providedPairs, onChainProvider, blockNumber } = params; + const pairs = providedPairs || await getPairCombinations(currencyA, currencyB); + const [fromOnChain, tvlReference] = await Promise.allSettled([ + getV3PoolsWithoutTicksOnChain(pairs, onChainProvider, blockNumber), + tvlReferenceProvider(params) + ]); + if (fromOnChain.status === "fulfilled" && tvlReference.status === "fulfilled") { + const { value: poolsFromOnChain } = fromOnChain; + const { value: poolTvlReferences } = tvlReference; + if (!Array.isArray(poolTvlReferences)) { + throw new Error("Failed to get tvl references"); + } + return poolsFromOnChain.map((pool) => { + const tvlUSD = BigInt(getV3PoolTvl(poolTvlReferences, pool.address)); + return { + ...pool, + tvlUSD + }; + }); + } + throw new Error(`Getting v3 pools failed. Onchain ${fromOnChain.status}, tvl references ${tvlReference.status}`); + }; +}; +var getV3PoolsWithTvlFromOnChain = v3PoolsOnChainProviderFactory(async (params) => { + const { currencyA, currencyB, pairs: providedPairs, subgraphProvider } = params; + const pairs = providedPairs || await getPairCombinations(currencyA, currencyB); + return getV3PoolSubgraph({ provider: subgraphProvider, pairs }); +}); +var createFallbackTvlRefGetter = () => { + const cache = /* @__PURE__ */ new Map(); + return async (params) => { + const { currencyA } = params; + if (!currencyA?.chainId) { + throw new Error(`Cannot get tvl references at chain ${currencyA?.chainId}`); + } + if (chains.isTestnetChainId(currencyA?.chainId)) { + return []; + } + const cached = cache.get(currencyA.chainId); + if (cached) { + return cached; + } + const res = await fetch(`https://routing-api.pancakeswap.com/v0/v3-pools-tvl/${currencyA.chainId}`); + const refs = await res.json(); + cache.set(currencyA.chainId, refs); + return refs; + }; +}; +var getV3PoolsWithTvlFromOnChainFallback = v3PoolsOnChainProviderFactory(createFallbackTvlRefGetter()); +var getV3PoolsWithTvlFromOnChainStaticFallback = v3PoolsOnChainProviderFactory(() => Promise.resolve([])); +function createGetV3CandidatePools(defaultGetV3Pools, options) { + const getV3PoolsWithFallbacks = createAsyncCallWithFallbacks(defaultGetV3Pools, options); + return async function getV3Pools2(params) { + const { currencyA, currencyB } = params; + const pools = await getV3PoolsWithFallbacks(params); + return v3PoolTvlSelector(currencyA, currencyB, pools); + }; +} +async function getV3CandidatePools(params) { + const { subgraphFallback = true, staticFallback = true, fallbackTimeout, ...rest } = params; + const fallbacks = []; + if (subgraphFallback) { + fallbacks.push(getV3PoolsWithTvlFromOnChain); + fallbacks.push(async (p) => { + const { currencyA, currencyB, pairs: providedPairs, subgraphProvider } = p; + const pairs = providedPairs || await getPairCombinations(currencyA, currencyB); + return getV3PoolSubgraph({ provider: subgraphProvider, pairs }); + }); + } + if (staticFallback) { + fallbacks.push(getV3PoolsWithTvlFromOnChainStaticFallback); + } + const getV3PoolsWithFallback = createGetV3CandidatePools(getV3PoolsWithTvlFromOnChainFallback, { + fallbacks, + fallbackTimeout + }); + return getV3PoolsWithFallback(rest); +} + +// evm/v3-router/providers/poolProviders/getStableCandidatePools.ts +async function getStableCandidatePools(params) { + const { onChainProvider, currencyA, currencyB, pairs: providedPairs, blockNumber } = params; + const pairs = providedPairs || await getPairCombinations(currencyA, currencyB); + return getStablePoolsOnChain(pairs, onChainProvider, blockNumber); +} + +// evm/v3-router/providers/poolProviders/getCandidatePools.ts +async function getCandidatePools({ + protocols = [1 /* V3 */, 0 /* V2 */, 2 /* STABLE */], + v3SubgraphProvider, + ...rest +}) { + const { currencyA } = rest; + const chainId = currencyA?.chainId; + if (!chainId) { + return []; + } + const poolSets = await Promise.all( + protocols.map((protocol) => { + if (protocol === 0 /* V2 */) { + return getV2CandidatePools({ ...rest, v3SubgraphProvider }); + } + if (protocol === 1 /* V3 */) { + return getV3CandidatePools({ ...rest, subgraphProvider: v3SubgraphProvider }); + } + return getStableCandidatePools(rest); + }) + ); + return poolSets.reduce((acc, cur) => { + acc.push(...cur); + return acc; + }, []); +} + +// evm/v3-router/providers/poolProviders/hybridPoolProvider.ts +function createHybridPoolProvider({ + onChainProvider, + v3SubgraphProvider +}) { + const hybridPoolProvider = { + getCandidatePools: async (params) => { + return getCandidatePools({ ...params, onChainProvider, v3SubgraphProvider }); + } + }; + return createPoolProviderWithCache(hybridPoolProvider); +} + +// evm/v3-router/providers/poolProviders/staticPoolProvider.ts +function createStaticPoolProvider(pools) { + const defaultAllowedProtocols = [0 /* V2 */, 2 /* STABLE */, 1 /* V3 */]; + return { + getCandidatePools: async ({ protocols = defaultAllowedProtocols, pairs }) => { + if (!pools) { + return []; + } + if (!pairs) { + return pools.filter((pool) => protocols.includes(pool.type)); + } + const relatedPools = []; + for (const [currencyA, currencyB] of pairs) { + for (const pool of pools) { + if (involvesCurrency(pool, currencyA) && involvesCurrency(pool, currencyB) && protocols.includes(pool.type)) { + relatedPools.push(pool); + } + } + } + return relatedPools; + } + }; +} + +// evm/v3-router/providers/poolProviders/index.ts +function createPoolProvider(config) { + const hybridPoolProvider = createHybridPoolProvider(config); + return hybridPoolProvider; +} +function createOffChainQuoteProvider() { + const createGetRoutesWithQuotes = (isExactIn = true) => { + const getV2Quote = createGetV2Quote(isExactIn); + const getStableQuote = createGetStableQuote(isExactIn); + const getV3Quote = createGetV3Quote(isExactIn); + function* each(pools) { + let i = isExactIn ? 0 : pools.length - 1; + const hasNext = () => isExactIn ? i < pools.length : i >= 0; + while (hasNext()) { + yield [pools[i], i]; + if (isExactIn) { + i += 1; + } else { + i -= 1; + } + } + } + const adjustQuoteForGas = (quote, gasCostInToken) => { + if (isExactIn) { + return quote.subtract(gasCostInToken); + } + return quote.add(gasCostInToken); + }; + return async function getRoutesWithQuotes(routes, { gasModel }) { + const routesWithQuote = []; + for (const route of routes) { + try { + const { pools, amount, output, input } = route; + const quoteCurrency = amount.currency.wrapped.equals(input.wrapped) ? output : input; + let quote = amount; + const initializedTickCrossedList = Array(pools.length).fill(0); + let quoteSuccess = true; + for (const [pool, i] of each(pools)) { + if (isV2Pool(pool)) { + ; + [quote] = getV2Quote(pool, quote); + continue; + } + if (isStablePool(pool)) { + ; + [quote] = getStableQuote(pool, quote); + continue; + } + if (isV3Pool(pool)) { + const v3QuoteResult = await getV3Quote(pool, quote); + if (!v3QuoteResult || v3QuoteResult.quote.quotient === sdk.ZERO) { + quoteSuccess = false; + break; + } + const { quote: v3Quote, numOfTicksCrossed } = v3QuoteResult; + quote = v3Quote; + initializedTickCrossedList[i] = numOfTicksCrossed; + } + } + if (!quoteSuccess) { + continue; + } + const finalQuote = sdk.CurrencyAmount.fromRawAmount(quoteCurrency, quote.quotient); + const { gasEstimate, gasCostInUSD, gasCostInToken } = gasModel.estimateGasCost( + { + ...route, + quote: finalQuote + }, + { initializedTickCrossedList } + ); + routesWithQuote.push({ + ...route, + quote: finalQuote, + quoteAdjustedForGas: adjustQuoteForGas(finalQuote, gasCostInToken), + gasEstimate, + gasCostInUSD, + gasCostInToken + }); + } catch (e) { + } + } + return routesWithQuote; + }; + }; + return { + getRouteWithQuotesExactIn: createGetRoutesWithQuotes(true), + getRouteWithQuotesExactOut: createGetRoutesWithQuotes(false) + }; +} +function createGetV2Quote(isExactIn = true) { + return function getV2Quote(p, amount) { + const { reserve0, reserve1 } = p; + const pair = new sdk.Pair(reserve0.wrapped, reserve1.wrapped); + const [quote, newPair] = isExactIn ? pair.getOutputAmount(amount.wrapped) : pair.getInputAmount(amount.wrapped); + const newPool = { ...p, reserve0: newPair.reserve0, reserve1: newPair.reserve1 }; + return [quote, newPool]; + }; +} +function createGetStableQuote(isExactIn = true) { + const getQuote = isExactIn ? stableSwapSdk.getQuoteExactIn : stableSwapSdk.getQuoteExactOut; + return function getStableQuote(pool, amount) { + const { amplifier, balances, fee } = pool; + const [quote, { balances: newBalances }] = getQuote({ + amount, + balances, + amplifier, + outputCurrency: getOutputCurrency(pool, amount.currency), + fee + }); + return [quote, { ...pool, balances: newBalances }]; + }; +} +function createGetV3Quote(isExactIn = true) { + return async function getV3Quote(pool, amount) { + const { token0, token1, fee, sqrtRatioX96, liquidity, ticks, tick } = pool; + if (!ticks?.length) { + return null; + } + try { + const v3Pool = new v3Sdk.Pool(token0.wrapped, token1.wrapped, fee, sqrtRatioX96, liquidity, tick, ticks); + const [quote, poolAfter] = isExactIn ? await v3Pool.getOutputAmount(amount.wrapped) : await v3Pool.getInputAmountByExactOut(amount.wrapped); + if (quote.quotient <= 0n) { + return null; + } + const { tickCurrent: tickAfter } = poolAfter; + const newPool = { + ...pool, + tick: tickAfter, + sqrtRatioX96: poolAfter.sqrtRatioX96, + liquidity: poolAfter.liquidity + }; + const numOfTicksCrossed = v3Sdk.TickList.countInitializedTicksCrossed(ticks, tick, tickAfter); + return { + quote, + numOfTicksCrossed, + pool: newPool + }; + } catch (e) { + return null; + } + }; +} +function createPoolQuoteGetter(isExactIn = true) { + const getV2Quote = createGetV2Quote(isExactIn); + const getStableQuote = createGetStableQuote(isExactIn); + const getV3Quote = createGetV3Quote(isExactIn); + return async function getPoolQuote(pool, amount) { + if (isV2Pool(pool)) { + const [quote, newPool] = getV2Quote(pool, amount); + return { quote, pool, poolAfter: newPool }; + } + if (isV3Pool(pool)) { + const quote = await getV3Quote(pool, amount); + return quote ? { quote: quote.quote, pool, poolAfter: quote.pool } : void 0; + } + if (isStablePool(pool)) { + const [quote, newPool] = getStableQuote(pool, amount); + return { quote, pool, poolAfter: newPool }; + } + return void 0; + }; +} + +// ../utils/abortControl.ts +function isAbortError(error) { + return error instanceof Error && error.name === "AbortError"; +} + +// evm/abis/IBinQuoter.ts +var binQuoterAbi = [ + { + inputs: [{ internalType: "address", name: "_poolManager", type: "address" }], + stateMutability: "nonpayable", + type: "constructor" + }, + { inputs: [{ internalType: "PoolId", name: "poolId", type: "bytes32" }], name: "NotEnoughLiquidity", type: "error" }, + { inputs: [], name: "NotSelf", type: "error" }, + { inputs: [], name: "NotVault", type: "error" }, + { inputs: [{ internalType: "uint256", name: "amount", type: "uint256" }], name: "QuoteSwap", type: "error" }, + { inputs: [], name: "UnexpectedCallSuccess", type: "error" }, + { + inputs: [{ internalType: "bytes", name: "revertData", type: "bytes" }], + name: "UnexpectedRevertBytes", + type: "error" + }, + { + inputs: [ + { + components: [ + { internalType: "Currency", name: "exactCurrency", type: "address" }, + { + components: [ + { internalType: "Currency", name: "intermediateCurrency", type: "address" }, + { internalType: "uint24", name: "fee", type: "uint24" }, + { internalType: "contract IHooks", name: "hooks", type: "address" }, + { internalType: "contract IPoolManager", name: "poolManager", type: "address" }, + { internalType: "bytes", name: "hookData", type: "bytes" }, + { internalType: "bytes32", name: "parameters", type: "bytes32" } + ], + internalType: "struct PathKey[]", + name: "path", + type: "tuple[]" + }, + { internalType: "uint128", name: "exactAmount", type: "uint128" } + ], + internalType: "struct IQuoter.QuoteExactParams", + name: "params", + type: "tuple" + } + ], + name: "_quoteExactInput", + outputs: [{ internalType: "bytes", name: "", type: "bytes" }], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + components: [ + { + components: [ + { internalType: "Currency", name: "currency0", type: "address" }, + { internalType: "Currency", name: "currency1", type: "address" }, + { internalType: "contract IHooks", name: "hooks", type: "address" }, + { internalType: "contract IPoolManager", name: "poolManager", type: "address" }, + { internalType: "uint24", name: "fee", type: "uint24" }, + { internalType: "bytes32", name: "parameters", type: "bytes32" } + ], + internalType: "struct PoolKey", + name: "poolKey", + type: "tuple" + }, + { internalType: "bool", name: "zeroForOne", type: "bool" }, + { internalType: "uint128", name: "exactAmount", type: "uint128" }, + { internalType: "bytes", name: "hookData", type: "bytes" } + ], + internalType: "struct IQuoter.QuoteExactSingleParams", + name: "params", + type: "tuple" + } + ], + name: "_quoteExactInputSingle", + outputs: [{ internalType: "bytes", name: "", type: "bytes" }], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + components: [ + { internalType: "Currency", name: "exactCurrency", type: "address" }, + { + components: [ + { internalType: "Currency", name: "intermediateCurrency", type: "address" }, + { internalType: "uint24", name: "fee", type: "uint24" }, + { internalType: "contract IHooks", name: "hooks", type: "address" }, + { internalType: "contract IPoolManager", name: "poolManager", type: "address" }, + { internalType: "bytes", name: "hookData", type: "bytes" }, + { internalType: "bytes32", name: "parameters", type: "bytes32" } + ], + internalType: "struct PathKey[]", + name: "path", + type: "tuple[]" + }, + { internalType: "uint128", name: "exactAmount", type: "uint128" } + ], + internalType: "struct IQuoter.QuoteExactParams", + name: "params", + type: "tuple" + } + ], + name: "_quoteExactOutput", + outputs: [{ internalType: "bytes", name: "", type: "bytes" }], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + components: [ + { + components: [ + { internalType: "Currency", name: "currency0", type: "address" }, + { internalType: "Currency", name: "currency1", type: "address" }, + { internalType: "contract IHooks", name: "hooks", type: "address" }, + { internalType: "contract IPoolManager", name: "poolManager", type: "address" }, + { internalType: "uint24", name: "fee", type: "uint24" }, + { internalType: "bytes32", name: "parameters", type: "bytes32" } + ], + internalType: "struct PoolKey", + name: "poolKey", + type: "tuple" + }, + { internalType: "bool", name: "zeroForOne", type: "bool" }, + { internalType: "uint128", name: "exactAmount", type: "uint128" }, + { internalType: "bytes", name: "hookData", type: "bytes" } + ], + internalType: "struct IQuoter.QuoteExactSingleParams", + name: "params", + type: "tuple" + } + ], + name: "_quoteExactOutputSingle", + outputs: [{ internalType: "bytes", name: "", type: "bytes" }], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [{ internalType: "bytes", name: "data", type: "bytes" }], + name: "lockAcquired", + outputs: [{ internalType: "bytes", name: "", type: "bytes" }], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [], + name: "poolManager", + outputs: [{ internalType: "contract IBinPoolManager", name: "", type: "address" }], + stateMutability: "view", + type: "function" + }, + { + inputs: [ + { + components: [ + { internalType: "Currency", name: "exactCurrency", type: "address" }, + { + components: [ + { internalType: "Currency", name: "intermediateCurrency", type: "address" }, + { internalType: "uint24", name: "fee", type: "uint24" }, + { internalType: "contract IHooks", name: "hooks", type: "address" }, + { internalType: "contract IPoolManager", name: "poolManager", type: "address" }, + { internalType: "bytes", name: "hookData", type: "bytes" }, + { internalType: "bytes32", name: "parameters", type: "bytes32" } + ], + internalType: "struct PathKey[]", + name: "path", + type: "tuple[]" + }, + { internalType: "uint128", name: "exactAmount", type: "uint128" } + ], + internalType: "struct IQuoter.QuoteExactParams", + name: "params", + type: "tuple" + } + ], + name: "quoteExactInput", + outputs: [ + { internalType: "uint256", name: "amountOut", type: "uint256" }, + { internalType: "uint256", name: "gasEstimate", type: "uint256" } + ], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + components: [ + { + components: [ + { internalType: "Currency", name: "currency0", type: "address" }, + { internalType: "Currency", name: "currency1", type: "address" }, + { internalType: "contract IHooks", name: "hooks", type: "address" }, + { internalType: "contract IPoolManager", name: "poolManager", type: "address" }, + { internalType: "uint24", name: "fee", type: "uint24" }, + { internalType: "bytes32", name: "parameters", type: "bytes32" } + ], + internalType: "struct PoolKey", + name: "poolKey", + type: "tuple" + }, + { internalType: "bool", name: "zeroForOne", type: "bool" }, + { internalType: "uint128", name: "exactAmount", type: "uint128" }, + { internalType: "bytes", name: "hookData", type: "bytes" } + ], + internalType: "struct IQuoter.QuoteExactSingleParams", + name: "params", + type: "tuple" + } + ], + name: "quoteExactInputSingle", + outputs: [ + { internalType: "uint256", name: "amountOut", type: "uint256" }, + { internalType: "uint256", name: "gasEstimate", type: "uint256" } + ], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + components: [ + { internalType: "Currency", name: "exactCurrency", type: "address" }, + { + components: [ + { internalType: "Currency", name: "intermediateCurrency", type: "address" }, + { internalType: "uint24", name: "fee", type: "uint24" }, + { internalType: "contract IHooks", name: "hooks", type: "address" }, + { internalType: "contract IPoolManager", name: "poolManager", type: "address" }, + { internalType: "bytes", name: "hookData", type: "bytes" }, + { internalType: "bytes32", name: "parameters", type: "bytes32" } + ], + internalType: "struct PathKey[]", + name: "path", + type: "tuple[]" + }, + { internalType: "uint128", name: "exactAmount", type: "uint128" } + ], + internalType: "struct IQuoter.QuoteExactParams", + name: "params", + type: "tuple" + } + ], + name: "quoteExactOutput", + outputs: [ + { internalType: "uint256", name: "amountIn", type: "uint256" }, + { internalType: "uint256", name: "gasEstimate", type: "uint256" } + ], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + components: [ + { + components: [ + { internalType: "Currency", name: "currency0", type: "address" }, + { internalType: "Currency", name: "currency1", type: "address" }, + { internalType: "contract IHooks", name: "hooks", type: "address" }, + { internalType: "contract IPoolManager", name: "poolManager", type: "address" }, + { internalType: "uint24", name: "fee", type: "uint24" }, + { internalType: "bytes32", name: "parameters", type: "bytes32" } + ], + internalType: "struct PoolKey", + name: "poolKey", + type: "tuple" + }, + { internalType: "bool", name: "zeroForOne", type: "bool" }, + { internalType: "uint128", name: "exactAmount", type: "uint128" }, + { internalType: "bytes", name: "hookData", type: "bytes" } + ], + internalType: "struct IQuoter.QuoteExactSingleParams", + name: "params", + type: "tuple" + } + ], + name: "quoteExactOutputSingle", + outputs: [ + { internalType: "uint256", name: "amountIn", type: "uint256" }, + { internalType: "uint256", name: "gasEstimate", type: "uint256" } + ], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [], + name: "vault", + outputs: [{ internalType: "contract IVault", name: "", type: "address" }], + stateMutability: "view", + type: "function" + } +]; + +// evm/abis/ICLQuoter.ts +var clQuoterAbi = [ + { + inputs: [{ internalType: "address", name: "_poolManager", type: "address" }], + stateMutability: "nonpayable", + type: "constructor" + }, + { inputs: [{ internalType: "PoolId", name: "poolId", type: "bytes32" }], name: "NotEnoughLiquidity", type: "error" }, + { inputs: [], name: "NotSelf", type: "error" }, + { inputs: [], name: "NotVault", type: "error" }, + { inputs: [{ internalType: "uint256", name: "amount", type: "uint256" }], name: "QuoteSwap", type: "error" }, + { inputs: [], name: "UnexpectedCallSuccess", type: "error" }, + { + inputs: [{ internalType: "bytes", name: "revertData", type: "bytes" }], + name: "UnexpectedRevertBytes", + type: "error" + }, + { + inputs: [ + { + components: [ + { internalType: "Currency", name: "exactCurrency", type: "address" }, + { + components: [ + { internalType: "Currency", name: "intermediateCurrency", type: "address" }, + { internalType: "uint24", name: "fee", type: "uint24" }, + { internalType: "contract IHooks", name: "hooks", type: "address" }, + { internalType: "contract IPoolManager", name: "poolManager", type: "address" }, + { internalType: "bytes", name: "hookData", type: "bytes" }, + { internalType: "bytes32", name: "parameters", type: "bytes32" } + ], + internalType: "struct PathKey[]", + name: "path", + type: "tuple[]" + }, + { internalType: "uint128", name: "exactAmount", type: "uint128" } + ], + internalType: "struct IQuoter.QuoteExactParams", + name: "params", + type: "tuple" + } + ], + name: "_quoteExactInput", + outputs: [{ internalType: "bytes", name: "", type: "bytes" }], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + components: [ + { + components: [ + { internalType: "Currency", name: "currency0", type: "address" }, + { internalType: "Currency", name: "currency1", type: "address" }, + { internalType: "contract IHooks", name: "hooks", type: "address" }, + { internalType: "contract IPoolManager", name: "poolManager", type: "address" }, + { internalType: "uint24", name: "fee", type: "uint24" }, + { internalType: "bytes32", name: "parameters", type: "bytes32" } + ], + internalType: "struct PoolKey", + name: "poolKey", + type: "tuple" + }, + { internalType: "bool", name: "zeroForOne", type: "bool" }, + { internalType: "uint128", name: "exactAmount", type: "uint128" }, + { internalType: "bytes", name: "hookData", type: "bytes" } + ], + internalType: "struct IQuoter.QuoteExactSingleParams", + name: "params", + type: "tuple" + } + ], + name: "_quoteExactInputSingle", + outputs: [{ internalType: "bytes", name: "", type: "bytes" }], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + components: [ + { internalType: "Currency", name: "exactCurrency", type: "address" }, + { + components: [ + { internalType: "Currency", name: "intermediateCurrency", type: "address" }, + { internalType: "uint24", name: "fee", type: "uint24" }, + { internalType: "contract IHooks", name: "hooks", type: "address" }, + { internalType: "contract IPoolManager", name: "poolManager", type: "address" }, + { internalType: "bytes", name: "hookData", type: "bytes" }, + { internalType: "bytes32", name: "parameters", type: "bytes32" } + ], + internalType: "struct PathKey[]", + name: "path", + type: "tuple[]" + }, + { internalType: "uint128", name: "exactAmount", type: "uint128" } + ], + internalType: "struct IQuoter.QuoteExactParams", + name: "params", + type: "tuple" + } + ], + name: "_quoteExactOutput", + outputs: [{ internalType: "bytes", name: "", type: "bytes" }], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + components: [ + { + components: [ + { internalType: "Currency", name: "currency0", type: "address" }, + { internalType: "Currency", name: "currency1", type: "address" }, + { internalType: "contract IHooks", name: "hooks", type: "address" }, + { internalType: "contract IPoolManager", name: "poolManager", type: "address" }, + { internalType: "uint24", name: "fee", type: "uint24" }, + { internalType: "bytes32", name: "parameters", type: "bytes32" } + ], + internalType: "struct PoolKey", + name: "poolKey", + type: "tuple" + }, + { internalType: "bool", name: "zeroForOne", type: "bool" }, + { internalType: "uint128", name: "exactAmount", type: "uint128" }, + { internalType: "bytes", name: "hookData", type: "bytes" } + ], + internalType: "struct IQuoter.QuoteExactSingleParams", + name: "params", + type: "tuple" + } + ], + name: "_quoteExactOutputSingle", + outputs: [{ internalType: "bytes", name: "", type: "bytes" }], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [{ internalType: "bytes", name: "data", type: "bytes" }], + name: "lockAcquired", + outputs: [{ internalType: "bytes", name: "", type: "bytes" }], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [], + name: "poolManager", + outputs: [{ internalType: "contract ICLPoolManager", name: "", type: "address" }], + stateMutability: "view", + type: "function" + }, + { + inputs: [ + { + components: [ + { internalType: "Currency", name: "exactCurrency", type: "address" }, + { + components: [ + { internalType: "Currency", name: "intermediateCurrency", type: "address" }, + { internalType: "uint24", name: "fee", type: "uint24" }, + { internalType: "contract IHooks", name: "hooks", type: "address" }, + { internalType: "contract IPoolManager", name: "poolManager", type: "address" }, + { internalType: "bytes", name: "hookData", type: "bytes" }, + { internalType: "bytes32", name: "parameters", type: "bytes32" } + ], + internalType: "struct PathKey[]", + name: "path", + type: "tuple[]" + }, + { internalType: "uint128", name: "exactAmount", type: "uint128" } + ], + internalType: "struct IQuoter.QuoteExactParams", + name: "params", + type: "tuple" + } + ], + name: "quoteExactInput", + outputs: [ + { internalType: "uint256", name: "amountOut", type: "uint256" }, + { internalType: "uint256", name: "gasEstimate", type: "uint256" } + ], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + components: [ + { + components: [ + { internalType: "Currency", name: "currency0", type: "address" }, + { internalType: "Currency", name: "currency1", type: "address" }, + { internalType: "contract IHooks", name: "hooks", type: "address" }, + { internalType: "contract IPoolManager", name: "poolManager", type: "address" }, + { internalType: "uint24", name: "fee", type: "uint24" }, + { internalType: "bytes32", name: "parameters", type: "bytes32" } + ], + internalType: "struct PoolKey", + name: "poolKey", + type: "tuple" + }, + { internalType: "bool", name: "zeroForOne", type: "bool" }, + { internalType: "uint128", name: "exactAmount", type: "uint128" }, + { internalType: "bytes", name: "hookData", type: "bytes" } + ], + internalType: "struct IQuoter.QuoteExactSingleParams", + name: "params", + type: "tuple" + } + ], + name: "quoteExactInputSingle", + outputs: [ + { internalType: "uint256", name: "amountOut", type: "uint256" }, + { internalType: "uint256", name: "gasEstimate", type: "uint256" } + ], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + components: [ + { internalType: "Currency", name: "exactCurrency", type: "address" }, + { + components: [ + { internalType: "Currency", name: "intermediateCurrency", type: "address" }, + { internalType: "uint24", name: "fee", type: "uint24" }, + { internalType: "contract IHooks", name: "hooks", type: "address" }, + { internalType: "contract IPoolManager", name: "poolManager", type: "address" }, + { internalType: "bytes", name: "hookData", type: "bytes" }, + { internalType: "bytes32", name: "parameters", type: "bytes32" } + ], + internalType: "struct PathKey[]", + name: "path", + type: "tuple[]" + }, + { internalType: "uint128", name: "exactAmount", type: "uint128" } + ], + internalType: "struct IQuoter.QuoteExactParams", + name: "params", + type: "tuple" + } + ], + name: "quoteExactOutput", + outputs: [ + { internalType: "uint256", name: "amountIn", type: "uint256" }, + { internalType: "uint256", name: "gasEstimate", type: "uint256" } + ], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + components: [ + { + components: [ + { internalType: "Currency", name: "currency0", type: "address" }, + { internalType: "Currency", name: "currency1", type: "address" }, + { internalType: "contract IHooks", name: "hooks", type: "address" }, + { internalType: "contract IPoolManager", name: "poolManager", type: "address" }, + { internalType: "uint24", name: "fee", type: "uint24" }, + { internalType: "bytes32", name: "parameters", type: "bytes32" } + ], + internalType: "struct PoolKey", + name: "poolKey", + type: "tuple" + }, + { internalType: "bool", name: "zeroForOne", type: "bool" }, + { internalType: "uint128", name: "exactAmount", type: "uint128" }, + { internalType: "bytes", name: "hookData", type: "bytes" } + ], + internalType: "struct IQuoter.QuoteExactSingleParams", + name: "params", + type: "tuple" + } + ], + name: "quoteExactOutputSingle", + outputs: [ + { internalType: "uint256", name: "amountIn", type: "uint256" }, + { internalType: "uint256", name: "gasEstimate", type: "uint256" } + ], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [], + name: "vault", + outputs: [{ internalType: "contract IVault", name: "", type: "address" }], + stateMutability: "view", + type: "function" + } +]; + +// evm/abis/IInfinityMixedRouteQuoter.ts +var infinityMixedRouteQuoterAbi = [ + { + type: "constructor", + inputs: [ + { name: "_factoryV3", type: "address", internalType: "address" }, + { name: "_factoryV2", type: "address", internalType: "address" }, + { name: "_factoryStable", type: "address", internalType: "address" }, + { name: "_WETH9", type: "address", internalType: "address" }, + { name: "_clQuoter", type: "address", internalType: "contract ICLQuoter" }, + { name: "_binQuoter", type: "address", internalType: "contract IBinQuoter" } + ], + stateMutability: "nonpayable" + }, + { + type: "function", + name: "WETH9", + inputs: [], + outputs: [{ name: "", type: "address", internalType: "address" }], + stateMutability: "view" + }, + { + type: "function", + name: "binQuoter", + inputs: [], + outputs: [{ name: "", type: "address", internalType: "contract IBinQuoter" }], + stateMutability: "view" + }, + { + type: "function", + name: "clQuoter", + inputs: [], + outputs: [{ name: "", type: "address", internalType: "contract ICLQuoter" }], + stateMutability: "view" + }, + { + type: "function", + name: "factoryStable", + inputs: [], + outputs: [{ name: "", type: "address", internalType: "address" }], + stateMutability: "view" + }, + { + type: "function", + name: "factoryV2", + inputs: [], + outputs: [{ name: "", type: "address", internalType: "address" }], + stateMutability: "view" + }, + { + type: "function", + name: "factoryV3", + inputs: [], + outputs: [{ name: "", type: "address", internalType: "address" }], + stateMutability: "view" + }, + { + type: "function", + name: "multicall", + inputs: [{ name: "data", type: "bytes[]", internalType: "bytes[]" }], + outputs: [{ name: "results", type: "bytes[]", internalType: "bytes[]" }], + stateMutability: "payable" + }, + { + type: "function", + name: "pancakeV3SwapCallback", + inputs: [ + { name: "amount0Delta", type: "int256", internalType: "int256" }, + { name: "amount1Delta", type: "int256", internalType: "int256" }, + { name: "data", type: "bytes", internalType: "bytes" } + ], + outputs: [], + stateMutability: "view" + }, + { + type: "function", + name: "quoteExactInputSingleStable", + inputs: [ + { + name: "params", + type: "tuple", + internalType: "struct IMixedQuoter.QuoteExactInputSingleStableParams", + components: [ + { name: "tokenIn", type: "address", internalType: "address" }, + { name: "tokenOut", type: "address", internalType: "address" }, + { name: "amountIn", type: "uint256", internalType: "uint256" }, + { name: "flag", type: "uint256", internalType: "uint256" } + ] + } + ], + outputs: [ + { name: "amountOut", type: "uint256", internalType: "uint256" }, + { name: "gasEstimate", type: "uint256", internalType: "uint256" } + ], + stateMutability: "view" + }, + { + type: "function", + name: "quoteExactInputSingleV2", + inputs: [ + { + name: "params", + type: "tuple", + internalType: "struct IMixedQuoter.QuoteExactInputSingleV2Params", + components: [ + { name: "tokenIn", type: "address", internalType: "address" }, + { name: "tokenOut", type: "address", internalType: "address" }, + { name: "amountIn", type: "uint256", internalType: "uint256" } + ] + } + ], + outputs: [ + { name: "amountOut", type: "uint256", internalType: "uint256" }, + { name: "gasEstimate", type: "uint256", internalType: "uint256" } + ], + stateMutability: "view" + }, + { + type: "function", + name: "quoteExactInputSingleV3", + inputs: [ + { + name: "params", + type: "tuple", + internalType: "struct IMixedQuoter.QuoteExactInputSingleV3Params", + components: [ + { name: "tokenIn", type: "address", internalType: "address" }, + { name: "tokenOut", type: "address", internalType: "address" }, + { name: "amountIn", type: "uint256", internalType: "uint256" }, + { name: "fee", type: "uint24", internalType: "uint24" }, + { name: "sqrtPriceLimitX96", type: "uint160", internalType: "uint160" } + ] + } + ], + outputs: [ + { name: "amountOut", type: "uint256", internalType: "uint256" }, + { name: "sqrtPriceX96After", type: "uint160", internalType: "uint160" }, + { name: "initializedTicksCrossed", type: "uint32", internalType: "uint32" }, + { name: "gasEstimate", type: "uint256", internalType: "uint256" } + ], + stateMutability: "nonpayable" + }, + { + type: "function", + name: "quoteMixedExactInput", + inputs: [ + { name: "paths", type: "address[]", internalType: "address[]" }, + { name: "actions", type: "bytes", internalType: "bytes" }, + { name: "params", type: "bytes[]", internalType: "bytes[]" }, + { name: "amountIn", type: "uint256", internalType: "uint256" } + ], + outputs: [ + { name: "amountOut", type: "uint256", internalType: "uint256" }, + { name: "gasEstimate", type: "uint256", internalType: "uint256" } + ], + stateMutability: "nonpayable" + }, + { + type: "function", + name: "quoteMixedExactInputSharedContext", + inputs: [ + { name: "paths", type: "address[]", internalType: "address[]" }, + { name: "actions", type: "bytes", internalType: "bytes" }, + { name: "params", type: "bytes[]", internalType: "bytes[]" }, + { name: "amountIn", type: "uint256", internalType: "uint256" } + ], + outputs: [ + { name: "amountOut", type: "uint256", internalType: "uint256" }, + { name: "gasEstimate", type: "uint256", internalType: "uint256" } + ], + stateMutability: "nonpayable" + }, + { type: "error", name: "INVALID_ADDRESS", inputs: [] }, + { type: "error", name: "INVALID_SWAP_DIRECTION", inputs: [] }, + { type: "error", name: "InputLengthMismatch", inputs: [] }, + { type: "error", name: "InvalidPath", inputs: [] }, + { type: "error", name: "InvalidPoolKeyCurrency", inputs: [] }, + { type: "error", name: "NoActions", inputs: [] }, + { + type: "error", + name: "SafeCastOverflowedUintDowncast", + inputs: [ + { name: "bits", type: "uint8", internalType: "uint8" }, + { name: "value", type: "uint256", internalType: "uint256" } + ] + }, + { + type: "error", + name: "SafeCastOverflowedUintToInt", + inputs: [{ name: "value", type: "uint256", internalType: "uint256" }] + }, + { type: "error", name: "UnsupportedAction", inputs: [{ name: "action", type: "uint256", internalType: "uint256" }] } +]; + +// evm/abis/IMixedRouteQuoterV1.ts +var mixedRouteQuoterV1ABI = [ + { + inputs: [ + { + internalType: "address", + name: "_deployer", + type: "address" + }, + { + internalType: "address", + name: "_factory", + type: "address" + }, + { + internalType: "address", + name: "_factoryV2", + type: "address" + }, + { + internalType: "address", + name: "_factoryStable", + type: "address" + }, + { + internalType: "address", + name: "_WETH9", + type: "address" + } + ], + stateMutability: "nonpayable", + type: "constructor" + }, + { + inputs: [], + name: "WETH9", + outputs: [ + { + internalType: "address", + name: "", + type: "address" + } + ], + stateMutability: "view", + type: "function" + }, + { + inputs: [], + name: "deployer", + outputs: [ + { + internalType: "address", + name: "", + type: "address" + } + ], + stateMutability: "view", + type: "function" + }, + { + inputs: [], + name: "factory", + outputs: [ + { + internalType: "address", + name: "", + type: "address" + } + ], + stateMutability: "view", + type: "function" + }, + { + inputs: [], + name: "factoryStable", + outputs: [ + { + internalType: "address", + name: "", + type: "address" + } + ], + stateMutability: "view", + type: "function" + }, + { + inputs: [], + name: "factoryV2", + outputs: [ + { + internalType: "address", + name: "", + type: "address" + } + ], + stateMutability: "view", + type: "function" + }, + { + inputs: [ + { + internalType: "int256", + name: "amount0Delta", + type: "int256" + }, + { + internalType: "int256", + name: "amount1Delta", + type: "int256" + }, + { + internalType: "bytes", + name: "path", + type: "bytes" + } + ], + name: "pancakeV3SwapCallback", + outputs: [], + stateMutability: "view", + type: "function" + }, + { + inputs: [ + { + internalType: "bytes", + name: "path", + type: "bytes" + }, + { + internalType: "uint256[]", + name: "flag", + type: "uint256[]" + }, + { + internalType: "uint256", + name: "amountIn", + type: "uint256" + } + ], + name: "quoteExactInput", + outputs: [ + { + internalType: "uint256", + name: "amountOut", + type: "uint256" + }, + { + internalType: "uint160[]", + name: "v3SqrtPriceX96AfterList", + type: "uint160[]" + }, + { + internalType: "uint32[]", + name: "v3InitializedTicksCrossedList", + type: "uint32[]" + }, + { + internalType: "uint256", + name: "v3SwapGasEstimate", + type: "uint256" + } + ], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + components: [ + { + internalType: "address", + name: "tokenIn", + type: "address" + }, + { + internalType: "address", + name: "tokenOut", + type: "address" + }, + { + internalType: "uint256", + name: "amountIn", + type: "uint256" + }, + { + internalType: "uint256", + name: "flag", + type: "uint256" + } + ], + internalType: "struct IMixedRouteQuoterV1.QuoteExactInputSingleStableParams", + name: "params", + type: "tuple" + } + ], + name: "quoteExactInputSingleStable", + outputs: [ + { + internalType: "uint256", + name: "amountOut", + type: "uint256" + } + ], + stateMutability: "view", + type: "function" + }, + { + inputs: [ + { + components: [ + { + internalType: "address", + name: "tokenIn", + type: "address" + }, + { + internalType: "address", + name: "tokenOut", + type: "address" + }, + { + internalType: "uint256", + name: "amountIn", + type: "uint256" + } + ], + internalType: "struct IMixedRouteQuoterV1.QuoteExactInputSingleV2Params", + name: "params", + type: "tuple" + } + ], + name: "quoteExactInputSingleV2", + outputs: [ + { + internalType: "uint256", + name: "amountOut", + type: "uint256" + } + ], + stateMutability: "view", + type: "function" + }, + { + inputs: [ + { + components: [ + { + internalType: "address", + name: "tokenIn", + type: "address" + }, + { + internalType: "address", + name: "tokenOut", + type: "address" + }, + { + internalType: "uint256", + name: "amountIn", + type: "uint256" + }, + { + internalType: "uint24", + name: "fee", + type: "uint24" + }, + { + internalType: "uint160", + name: "sqrtPriceLimitX96", + type: "uint160" + } + ], + internalType: "struct IMixedRouteQuoterV1.QuoteExactInputSingleV3Params", + name: "params", + type: "tuple" + } + ], + name: "quoteExactInputSingleV3", + outputs: [ + { + internalType: "uint256", + name: "amountOut", + type: "uint256" + }, + { + internalType: "uint160", + name: "sqrtPriceX96After", + type: "uint160" + }, + { + internalType: "uint32", + name: "initializedTicksCrossed", + type: "uint32" + }, + { + internalType: "uint256", + name: "gasEstimate", + type: "uint256" + } + ], + stateMutability: "nonpayable", + type: "function" + } +]; + +// evm/abis/IQuoterV2.ts +var quoterV2ABI = [ + { + inputs: [ + { + internalType: "bytes", + name: "path", + type: "bytes" + }, + { + internalType: "uint256", + name: "amountIn", + type: "uint256" + } + ], + name: "quoteExactInput", + outputs: [ + { + internalType: "uint256", + name: "amountOut", + type: "uint256" + }, + { + internalType: "uint160[]", + name: "sqrtPriceX96AfterList", + type: "uint160[]" + }, + { + internalType: "uint32[]", + name: "initializedTicksCrossedList", + type: "uint32[]" + }, + { + internalType: "uint256", + name: "gasEstimate", + type: "uint256" + } + ], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + components: [ + { + internalType: "address", + name: "tokenIn", + type: "address" + }, + { + internalType: "address", + name: "tokenOut", + type: "address" + }, + { + internalType: "uint256", + name: "amountIn", + type: "uint256" + }, + { + internalType: "uint24", + name: "fee", + type: "uint24" + }, + { + internalType: "uint160", + name: "sqrtPriceLimitX96", + type: "uint160" + } + ], + internalType: "struct IQuoterV2.QuoteExactInputSingleParams", + name: "params", + type: "tuple" + } + ], + name: "quoteExactInputSingle", + outputs: [ + { + internalType: "uint256", + name: "amountOut", + type: "uint256" + }, + { + internalType: "uint160", + name: "sqrtPriceX96After", + type: "uint160" + }, + { + internalType: "uint32", + name: "initializedTicksCrossed", + type: "uint32" + }, + { + internalType: "uint256", + name: "gasEstimate", + type: "uint256" + } + ], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + internalType: "bytes", + name: "path", + type: "bytes" + }, + { + internalType: "uint256", + name: "amountOut", + type: "uint256" + } + ], + name: "quoteExactOutput", + outputs: [ + { + internalType: "uint256", + name: "amountIn", + type: "uint256" + }, + { + internalType: "uint160[]", + name: "sqrtPriceX96AfterList", + type: "uint160[]" + }, + { + internalType: "uint32[]", + name: "initializedTicksCrossedList", + type: "uint32[]" + }, + { + internalType: "uint256", + name: "gasEstimate", + type: "uint256" + } + ], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + components: [ + { + internalType: "address", + name: "tokenIn", + type: "address" + }, + { + internalType: "address", + name: "tokenOut", + type: "address" + }, + { + internalType: "uint256", + name: "amount", + type: "uint256" + }, + { + internalType: "uint24", + name: "fee", + type: "uint24" + }, + { + internalType: "uint160", + name: "sqrtPriceLimitX96", + type: "uint160" + } + ], + internalType: "struct IQuoterV2.QuoteExactOutputSingleParams", + name: "params", + type: "tuple" + } + ], + name: "quoteExactOutputSingle", + outputs: [ + { + internalType: "uint256", + name: "amountIn", + type: "uint256" + }, + { + internalType: "uint160", + name: "sqrtPriceX96After", + type: "uint160" + }, + { + internalType: "uint32", + name: "initializedTicksCrossed", + type: "uint32" + }, + { + internalType: "uint256", + name: "gasEstimate", + type: "uint256" + } + ], + stateMutability: "nonpayable", + type: "function" + } +]; +function encodeInfinityMixedRouteActions(route) { + return viem.bytesToHex( + new Uint8Array( + route.pools.map((p) => { + if (isV2Pool(p)) { + return 2 /* V2_EXACT_INPUT_SINGLE */; + } + if (isV3Pool(p)) { + return 3 /* V3_EXACT_INPUT_SINGLE */; + } + if (isStablePool(p)) { + return 0 /* SS_2_EXACT_INPUT_SINGLE */; + } + if (isInfinityClPool(p) || isInfinityStablePool(p)) { + return 4 /* INFI_CL_EXACT_INPUT_SINGLE */; + } + if (isInfinityBinPool(p)) { + return 5 /* INFI_BIN_EXACT_INPUT_SINGLE */; + } + throw new Error(`Unrecognized pool type ${p}`); + }) + ) + ); +} +function getPoolCurrencies(pool) { + if (isV2Pool(pool)) { + return [pool.reserve0.currency, pool.reserve1.currency]; + } + if (isV3Pool(pool)) { + return [pool.token0, pool.token1]; + } + if (isStablePool(pool)) { + return pool.balances.map((b) => b.currency); + } + if (isInfinityClPool(pool) || isInfinityBinPool(pool) || isInfinityStablePool(pool)) { + return [pool.currency0, pool.currency1]; + } + throw new Error("Failed to get pool currencies. Unrecognized pool type"); +} +function encodeInfinityMixedRouteCurrencyPath(route) { + const { pools } = route; + const currencyStart = route.path[0]; + const pathStart = swapSdkCore.getMatchedCurrency(currencyStart, getPoolCurrencies(pools[0])); + if (!pathStart) { + throw new Error("Failed to encode path keys. Invalid start currency."); + } + const { path } = pools.reduce( + ({ baseCurrency, path: path2 }, p) => { + const quoteCurrency = getOutputCurrency(p, baseCurrency); + return { + baseCurrency: quoteCurrency, + path: [...path2, swapSdkCore.getCurrencyAddress(quoteCurrency)] + }; + }, + { baseCurrency: pathStart, path: [swapSdkCore.getCurrencyAddress(pathStart)] } + ); + return path; +} +var infinityRouteParamsAbi = [ + { + components: [ + { + components: [ + { name: "currency0", type: "address" }, + { name: "currency1", type: "address" }, + { name: "hooks", type: "address" }, + { name: "poolManager", type: "address" }, + { name: "fee", type: "uint24" }, + { name: "parameters", type: "bytes32" } + ], + name: "poolKey", + type: "tuple" + }, + { name: "hookData", type: "bytes" } + ], + name: "params", + type: "tuple" + } +]; +function encodeInfinityMixedRouteParams(route) { + return route.pools.map((p) => { + if (isV2Pool(p) || isStablePool(p)) { + return "0x"; + } + if (isV3Pool(p)) { + return viem.encodeAbiParameters(viem.parseAbiParameters("uint24"), [p.fee]); + } + if (isInfinityClPool(p) || isInfinityStablePool(p)) { + const poolKey = { + currency0: swapSdkCore.getCurrencyAddress(p.currency0), + currency1: swapSdkCore.getCurrencyAddress(p.currency1), + fee: infinitySdk.isDynamicFeeHook(p.currency0.chainId, p.hooks) ? infinitySdk.DYNAMIC_FEE_FLAG : p.fee, + hooks: p.hooks, + poolManager: p.poolManager, + parameters: { + tickSpacing: p.tickSpacing, + hooksRegistration: p.hooksRegistrationBitmap !== void 0 ? infinitySdk.decodeHooksRegistration(p.hooksRegistrationBitmap) : void 0 + } + }; + return viem.encodeAbiParameters(infinityRouteParamsAbi, [ + { + poolKey: infinitySdk.encodePoolKey(poolKey), + hookData: "0x" + } + ]); + } + if (isInfinityBinPool(p)) { + const poolKey = { + currency0: swapSdkCore.getCurrencyAddress(p.currency0), + currency1: swapSdkCore.getCurrencyAddress(p.currency1), + fee: infinitySdk.isDynamicFeeHook(p.currency0.chainId, p.hooks) ? infinitySdk.DYNAMIC_FEE_FLAG : p.fee, + hooks: p.hooks, + poolManager: p.poolManager, + parameters: { + binStep: Number(p.binStep), + hooksRegistration: p.hooksRegistrationBitmap !== void 0 ? infinitySdk.decodeHooksRegistration(p.hooksRegistrationBitmap) : void 0 + } + }; + return viem.encodeAbiParameters(infinityRouteParamsAbi, [ + { + poolKey: infinitySdk.encodePoolKey(poolKey), + hookData: "0x" + } + ]); + } + throw new Error(`Invalid pool type ${p}`); + }); +} + +// evm/abis/InterfaceMulticall.ts +var InterfaceMulticall_default = [ + { + inputs: [], + name: "getCurrentBlockTimestamp", + outputs: [ + { + internalType: "uint256", + name: "timestamp", + type: "uint256" + } + ], + stateMutability: "view", + type: "function" + }, + { + inputs: [ + { + internalType: "address", + name: "addr", + type: "address" + } + ], + name: "getEthBalance", + outputs: [ + { + internalType: "uint256", + name: "balance", + type: "uint256" + } + ], + stateMutability: "view", + type: "function" + }, + { + inputs: [ + { + components: [ + { + internalType: "address", + name: "target", + type: "address" + }, + { + internalType: "uint256", + name: "gasLimit", + type: "uint256" + }, + { + internalType: "bytes", + name: "callData", + type: "bytes" + } + ], + internalType: "struct PancakeInterfaceMulticall.Call[]", + name: "calls", + type: "tuple[]" + } + ], + name: "multicall", + outputs: [ + { + internalType: "uint256", + name: "blockNumber", + type: "uint256" + }, + { + components: [ + { + internalType: "bool", + name: "success", + type: "bool" + }, + { + internalType: "uint256", + name: "gasUsed", + type: "uint256" + }, + { + internalType: "bytes", + name: "returnData", + type: "bytes" + } + ], + internalType: "struct PancakeInterfaceMulticall.Result[]", + name: "returnData", + type: "tuple[]" + } + ], + stateMutability: "nonpayable", + type: "function" + } +]; + +// evm/v3-router/providers/multicallProvider.ts +var IMulticallProvider = class { +}; + +// evm/v3-router/providers/multicallSwapProvider.ts +var PancakeMulticallProvider = class extends IMulticallProvider { + constructor(chainId, provider, gasLimitPerCall = 1e6) { + super(); + this.chainId = chainId; + this.provider = provider; + this.gasLimitPerCall = gasLimitPerCall; + this.provider = provider; + } + async callSameFunctionOnMultipleContracts(params) { + const { addresses, functionName, functionParams, abi, additionalConfig } = params; + const gasLimitPerCall = additionalConfig?.gasLimitPerCall ?? this.gasLimitPerCall; + const callData = viem.encodeFunctionData({ + abi, + functionName, + args: functionParams + }); + const calls = addresses.map((address) => { + return { + target: address, + callData, + gasLimit: BigInt(gasLimitPerCall) + }; + }); + const { results: result, blockNumber } = await multicall.multicallByGasLimit(calls, { + gasLimit: additionalConfig?.gasLimit, + gasBuffer: additionalConfig?.gasBuffer, + dropUnexecutedCalls: additionalConfig?.dropUnexecutedCalls, + chainId: this.chainId, + client: this.provider, + signal: additionalConfig?.signal + }); + const results = []; + const gasUsedForSuccess = []; + const gasUsedForFail = []; + for (const { result: callResult, success, gasUsed } of result) { + if (callResult === "0x" || !success) { + results.push({ + success: false, + returnData: callResult + }); + gasUsedForFail.push(Number(gasUsed)); + continue; + } + try { + results.push({ + success: true, + result: viem.decodeFunctionResult({ + abi, + functionName, + data: callResult + }) + }); + gasUsedForSuccess.push(Number(gasUsed)); + } catch (e) { + results.push({ + success: false, + returnData: callResult + }); + } + } + return { + blockNumber, + results, + approxGasUsedPerSuccessCall: stats__default.default.percentile(gasUsedForSuccess, 99), + approxGasUsedPerFailCall: stats__default.default.percentile(gasUsedForFail, 99) + }; + } + async callSameFunctionOnContractWithMultipleParams(params) { + const { address, functionName, functionParams, abi, additionalConfig, account } = params; + const gasLimitPerCall = additionalConfig?.gasLimitPerCall ?? this.gasLimitPerCall; + const calls = functionParams.map((functionParam) => { + const callData = viem.encodeFunctionData({ + abi, + functionName, + args: functionParam + }); + return { + target: address, + callData, + gasLimit: BigInt(gasLimitPerCall) + }; + }); + const { results: result, blockNumber } = await multicall.multicallByGasLimit(calls, { + gasLimit: additionalConfig?.gasLimit, + gasBuffer: additionalConfig?.gasBuffer, + dropUnexecutedCalls: additionalConfig?.dropUnexecutedCalls, + chainId: this.chainId, + client: this.provider, + signal: additionalConfig?.signal, + account + }); + const results = []; + const gasUsedForSuccess = []; + const gasUsedForFail = []; + for (const { result: callResult, success, gasUsed } of result) { + if (callResult === "0x" || !success) { + results.push({ + success: false, + returnData: callResult + }); + gasUsedForFail.push(Number(gasUsed)); + continue; + } + try { + results.push({ + success: true, + result: viem.decodeFunctionResult({ + abi, + functionName, + data: callResult + }) + }); + gasUsedForSuccess.push(Number(gasUsed)); + } catch (e) { + results.push({ + success: false, + returnData: callResult + }); + } + } + return { + blockNumber, + results, + approxGasUsedPerSuccessCall: stats__default.default.percentile(gasUsedForSuccess, 99), + approxGasUsedPerFailCall: stats__default.default.percentile(gasUsedForFail, 99) + }; + } + async callMultipleFunctionsOnSameContract(params) { + const { address, functionNames, functionParams, additionalConfig, abi } = params; + const gasLimitPerCall = additionalConfig?.gasLimitPerCall ?? this.gasLimitPerCall; + const calls = functionNames.map((functionName, i) => { + const callData = viem.encodeFunctionData({ + abi, + functionName, + args: functionParams ? functionParams[i] : [] + }); + return { + target: address, + callData, + gasLimit: BigInt(gasLimitPerCall) + }; + }); + const { results: result, blockNumber } = await multicall.multicallByGasLimit(calls, { + gasLimit: additionalConfig?.gasLimit, + gasBuffer: additionalConfig?.gasBuffer, + dropUnexecutedCalls: additionalConfig?.dropUnexecutedCalls, + chainId: this.chainId, + client: this.provider, + signal: additionalConfig?.signal + }); + const results = []; + const gasUsedForSuccess = []; + const gasUsedForFail = []; + for (const [i, { result: callResult, success, gasUsed }] of result.entries()) { + if (callResult === "0x" || !success) { + results.push({ + success: false, + returnData: callResult + }); + gasUsedForFail.push(Number(gasUsed)); + continue; + } + try { + results.push({ + success: true, + result: viem.decodeFunctionResult({ + abi, + functionName: functionNames[i], + data: callResult + }) + }); + gasUsedForSuccess.push(Number(gasUsed)); + } catch (e) { + results.push({ + success: false, + returnData: callResult + }); + } + } + return { + blockNumber, + results, + approxGasUsedPerSuccessCall: stats__default.default.percentile(gasUsedForSuccess, 99), + approxGasUsedPerFailCall: stats__default.default.percentile(gasUsedForFail, 99) + }; + } +}; +PancakeMulticallProvider.abi = InterfaceMulticall_default; + +// evm/v3-router/providers/onChainQuoteProvider.ts +var DEFAULT_BATCH_RETRIES = 2; +var SUCCESS_RATE_CONFIG = { + [chains.ChainId.BSC_TESTNET]: 0.1, + [chains.ChainId.BSC]: 0.1, + [chains.ChainId.ETHEREUM]: 0.1, + [chains.ChainId.GOERLI]: 0.1, + [chains.ChainId.ARBITRUM_ONE]: 0.1, + [chains.ChainId.ARBITRUM_GOERLI]: 0.1, + [chains.ChainId.ZKSYNC]: 0.2, + [chains.ChainId.ZKSYNC_TESTNET]: 0.1, + [chains.ChainId.LINEA]: 0.1, + [chains.ChainId.LINEA_TESTNET]: 0.1, + [chains.ChainId.OPBNB]: 0.1, + [chains.ChainId.OPBNB_TESTNET]: 0.1, + [chains.ChainId.BASE]: 0.1, + [chains.ChainId.BASE_TESTNET]: 0.1, + [chains.ChainId.SCROLL_SEPOLIA]: 0.1, + [chains.ChainId.SEPOLIA]: 0.1, + [chains.ChainId.ARBITRUM_SEPOLIA]: 0.1, + [chains.ChainId.BASE_SEPOLIA]: 0.1, + [chains.ChainId.MONAD_TESTNET]: 0.1, + [chains.ChainId.MONAD_MAINNET]: 0.1, + [chains.ChainId.ROBINHOOD]: 0.1, + [chains.ChainId.ARC]: 0.1 +}; +var BlockConflictError = class extends Error { + constructor() { + super(...arguments); + this.name = "BlockConflictError"; + } +}; +var SuccessRateError = class extends Error { + constructor() { + super(...arguments); + this.name = "SuccessRateError"; + } +}; +var ProviderBlockHeaderError = class extends Error { + constructor() { + super(...arguments); + this.name = "ProviderBlockHeaderError"; + } +}; +var ProviderTimeoutError = class extends Error { + constructor() { + super(...arguments); + this.name = "ProviderTimeoutError"; + } +}; +var ProviderGasError = class extends Error { + constructor() { + super(...arguments); + this.name = "ProviderGasError"; + } +}; +var retryControllerFactory = ({ retries }) => { + const errors = []; + let remainingRetries = retries || 0; + return { + shouldRetry: (error) => !isAbortError(error) && remainingRetries > 0 && errors.every((err) => err.name !== error.name), + onRetry: (error) => { + errors.push(error); + remainingRetries -= 1; + }, + getErrorsOnPreviousRetries: () => errors + }; +}; +var defaultAdjustQuoteForGas = ({ isExactIn, quote, gasCostInToken }) => isExactIn ? quote.subtract(gasCostInToken) : quote.add(gasCostInToken); +function onChainQuoteProviderFactory({ getQuoteFunctionName, getQuoterAddress, abi, getCallInputs }) { + return function createOnChainQuoteProvider({ + onChainProvider, + gasLimit, + multicallConfigs: multicallConfigsOverride, + onAdjustQuoteForGas = defaultAdjustQuoteForGas, + account + }) { + const createGetRoutesWithQuotes = (isExactIn = true) => { + const functionName = getQuoteFunctionName(isExactIn); + const adjustQuoteForGas = ({ quote, gasCostInToken }) => onAdjustQuoteForGas({ quote, gasCostInToken, isExactIn }); + return async function getRoutesWithQuote(routes, { blockNumber: blockNumberFromConfig, gasModel, retry: retryOptions, signal, quoteId }) { + const logger3 = RemoteLogger.getLogger(quoteId); + if (!routes.length) { + return []; + } + const { + amount: { + currency: { chainId } + } + } = routes[0]; + const quoterAddress = getQuoterAddress(chainId); + const minSuccessRate = SUCCESS_RATE_CONFIG[chainId]; + const multicallConfigs = multicallConfigsOverride?.[chainId] || chunkZNSTBYLO_js.BATCH_MULTICALL_CONFIGS[chainId] || chunkZNSTBYLO_js.BATCH_MULTICALL_CONFIGS[chains.ChainId.ETHEREUM]; + const { + defaultConfig: { gasLimitPerCall: defaultGasLimitPerCall, dropUnexecutedCalls } + } = multicallConfigs; + const chainProvider = onChainProvider({ chainId }); + const providerConfig = { blockNumber: blockNumberFromConfig }; + const multicall2Provider = new PancakeMulticallProvider(chainId, chainProvider, defaultGasLimitPerCall); + const inputs = routes.map((route) => getCallInputs(route, isExactIn)); + logger3.debug(`Try quoter with Inputs: ${inputs.length}`, 3); + logger3.debug(`:${quoterAddress} ${functionName}`, 3); + logger3.debugJson(inputs[0], 3); + const retryOptionsWithDefault = { + retries: DEFAULT_BATCH_RETRIES, + minTimeout: 25, + maxTimeout: 250, + ...retryOptions + }; + const { shouldRetry, onRetry } = retryControllerFactory(retryOptionsWithDefault); + async function getQuotes({ gasLimitPerCall }) { + try { + const { results, blockNumber, approxGasUsedPerSuccessCall } = await multicall2Provider.callSameFunctionOnContractWithMultipleParams({ + address: quoterAddress, + abi, + functionName, + functionParams: inputs, + providerConfig, + account, + additionalConfig: { + dropUnexecutedCalls, + gasLimitPerCall, + gasLimit, + signal + } + }); + const successRateError = validateSuccessRate(results, minSuccessRate); + if (successRateError) { + throw successRateError; + } + return { + results, + blockNumber, + approxGasUsedPerSuccessCall + }; + } catch (err) { + if (err instanceof SuccessRateError || err instanceof BlockConflictError || isAbortError(err)) { + throw err; + } + const slicedErrMsg = err.message.slice(0, 500); + if (err.message.includes("header not found")) { + throw new ProviderBlockHeaderError(slicedErrMsg); + } + if (err.message.includes("timeout")) { + throw new ProviderTimeoutError(`Request had ${inputs.length} inputs. ${slicedErrMsg}`); + } + if (err.message.includes("out of gas")) { + throw new ProviderGasError(slicedErrMsg); + } + throw new Error(`Unknown error from provider: ${slicedErrMsg}`); + } + } + const quoteResult = await retry__default.default(async (bail) => { + try { + const quotes = await getQuotes({ + gasLimitPerCall: defaultGasLimitPerCall + }); + return quotes; + } catch (e) { + logger3.debug(`Error getting quotes: ${e}`, 2); + const error = e instanceof Error ? e : new Error(`Unexpected error type ${e}`); + if (!shouldRetry(error)) { + return bail(error); + } + if (error instanceof SuccessRateError) { + onRetry(error); + const { successRateFailureOverrides } = multicallConfigs; + return getQuotes({ + gasLimitPerCall: successRateFailureOverrides.gasLimitPerCall + }); + } + if (error instanceof ProviderGasError) { + onRetry(error); + const { gasErrorFailureOverride } = multicallConfigs; + return getQuotes({ + gasLimitPerCall: gasErrorFailureOverride.gasLimitPerCall + }); + } + throw error; + } + }, retryOptionsWithDefault); + if (!quoteResult) { + logger3.debug(`Empty quote result`, 2); + logger3.debugJson(quoteResult, 2); + throw new Error(`Unexpected empty quote result ${quoteResult}`); + } + const { results: quoteResults } = quoteResult; + const routesWithQuote = processQuoteResults(quoteResults, routes, gasModel, adjustQuoteForGas); + return routesWithQuote; + }; + }; + return { + getRouteWithQuotesExactIn: createGetRoutesWithQuotes(true), + getRouteWithQuotesExactOut: createGetRoutesWithQuotes(false) + }; + }; +} +function validateSuccessRate(allResults, quoteMinSuccessRate) { + const numResults = allResults.length; + const numSuccessResults = allResults.filter((result) => result.success).length; + const successRate = 1 * numSuccessResults / numResults; + if (successRate < quoteMinSuccessRate) { + return new SuccessRateError(`Quote success rate below threshold of ${quoteMinSuccessRate}: ${successRate}`); + } + return void 0; +} +function processQuoteResults(quoteResults, routes, gasModel, adjustQuoteForGas) { + const routesWithQuote = []; + for (let i = 0; i < quoteResults.length; i += 1) { + const route = routes[i]; + const quoteResult = quoteResults[i]; + if (!quoteResult) { + continue; + } + const { success } = quoteResult; + if (!success) { + continue; + } + const [quoteRaw] = quoteResult.result; + const initializedTickCrossedList = quoteResult.result.length === 4 ? quoteResult.result[2] : []; + const quoteCurrency = getQuoteCurrency(route, route.amount.currency); + const quote = swapSdkCore.CurrencyAmount.fromRawAmount(quoteCurrency, quoteRaw.toString()); + const { gasEstimate, gasCostInToken, gasCostInUSD } = gasModel.estimateGasCost( + { + ...route, + quote + }, + { initializedTickCrossedList } + ); + routesWithQuote.push({ + ...route, + quote, + quoteAdjustedForGas: adjustQuoteForGas({ quote, gasCostInToken }), + // sqrtPriceX96AfterList: quoteResult.result[1], + gasEstimate, + gasCostInToken, + gasCostInUSD + }); + } + return routesWithQuote; +} +var createMixedRouteOnChainQuoteProvider = onChainQuoteProviderFactory({ + getQuoterAddress: (chainId) => chunkZNSTBYLO_js.MIXED_ROUTE_QUOTER_ADDRESSES[chainId], + getQuoteFunctionName: () => "quoteExactInput", + abi: mixedRouteQuoterV1ABI, + getCallInputs: (route, isExactIn) => [ + encodeMixedRouteToPath(route, !isExactIn), + route.pools.map((pool) => { + if (isV3Pool(pool)) { + return 0; + } + if (isV2Pool(pool)) { + return 1; + } + if (isStablePool(pool)) { + if (pool.balances.length === 2) { + return 2; + } + if (pool.balances.length === 3) { + return 3; + } + } + return -1; + }).filter((index) => index >= 0), + `0x${route.amount.quotient.toString(16)}` + ] +}); +var createV3OnChainQuoteProvider = onChainQuoteProviderFactory({ + getQuoterAddress: (chainId) => chunkZNSTBYLO_js.V3_QUOTER_ADDRESSES[chainId], + getQuoteFunctionName: (isExactIn) => isExactIn ? "quoteExactInput" : "quoteExactOutput", + abi: quoterV2ABI, + getCallInputs: (route, isExactIn) => [ + encodeMixedRouteToPath(route, !isExactIn), + `0x${route.amount.quotient.toString(16)}` + ] +}); +var createInfinityClOnChainQuoteProvider = onChainQuoteProviderFactory({ + getQuoterAddress: (chainId) => infinitySdk.INFI_CL_QUOTER_ADDRESSES[chainId], + getQuoteFunctionName: (isExactIn) => isExactIn ? "quoteExactInput" : "quoteExactOutput", + abi: clQuoterAbi, + getCallInputs: (route, isExactIn) => { + const firstPool = route.pools[isExactIn ? 0 : route.pools.length - 1]; + const baseCurrency = swapSdkCore.getMatchedCurrency(isExactIn ? route.input : route.output, [ + firstPool.currency0, + firstPool.currency1 + ]); + if (!baseCurrency) { + throw new Error("CL_ONCHAIN_QUOTER_CALL_INPUTS: INVALID_POOL"); + } + const exactCurrency = swapSdkCore.getCurrencyAddress(baseCurrency); + return [ + { + exactCurrency, + path: encodeInfinityRouteToPath(route, !isExactIn), + exactAmount: `0x${route.amount.quotient.toString(16)}` + } + ]; + } +}); +var createMixedRouteOnChainQuoteProviderV2 = onChainQuoteProviderFactory({ + getQuoterAddress: (chainId) => infinitySdk.INFI_MIXED_QUOTER_ADDRESSES[chainId], + getQuoteFunctionName: () => "quoteMixedExactInput", + abi: infinityMixedRouteQuoterAbi, + getCallInputs: (route) => [ + encodeInfinityMixedRouteCurrencyPath(route), + encodeInfinityMixedRouteActions(route), + encodeInfinityMixedRouteParams(route), + `0x${route.amount.quotient.toString(16)}` + ] +}); +var createInfinityBinOnChainQuoteProvider = onChainQuoteProviderFactory({ + getQuoterAddress: (chainId) => infinitySdk.INFI_BIN_QUOTER_ADDRESSES[chainId], + getQuoteFunctionName: (isExactIn) => isExactIn ? "quoteExactInput" : "quoteExactOutput", + abi: binQuoterAbi, + getCallInputs: (route, isExactIn) => { + const firstPool = route.pools[isExactIn ? 0 : route.pools.length - 1]; + const baseCurrency = swapSdkCore.getMatchedCurrency(isExactIn ? route.input : route.output, [ + firstPool.currency0, + firstPool.currency1 + ]); + if (!baseCurrency) { + throw new Error("BIN_ONCHAIN_QUOTER_CALL_INPUTS: INVALID_POOL"); + } + const exactCurrency = swapSdkCore.getCurrencyAddress(baseCurrency); + return [ + { + exactCurrency, + path: encodeInfinityRouteToPath(route, !isExactIn), + exactAmount: `0x${route.amount.quotient.toString(16)}` + } + ]; + } +}); + +// evm/v3-router/providers/quoteProviders.ts +function createQuoteProvider(config) { + const { onChainProvider, multicallConfigs, gasLimit, account } = config; + const offChainQuoteProvider = createOffChainQuoteProvider(); + const mixedRouteOnChainQuoteProviderV1 = createMixedRouteOnChainQuoteProvider({ + onChainProvider, + multicallConfigs, + gasLimit, + account + }); + const mixedRouteOnChainQuoteProviderV2 = createMixedRouteOnChainQuoteProviderV2({ + onChainProvider, + multicallConfigs, + gasLimit, + account + }); + const v3OnChainQuoteProvider = createV3OnChainQuoteProvider({ onChainProvider, multicallConfigs, gasLimit, account }); + const infinityClOnChainQuoteProvider = createInfinityClOnChainQuoteProvider({ + onChainProvider, + multicallConfigs, + gasLimit, + account + }); + const infinityBinOnChainQuoteProvider = createInfinityBinOnChainQuoteProvider({ + onChainProvider, + multicallConfigs, + gasLimit, + account + }); + const createGetRouteWithQuotes = (isExactIn = true) => { + const getOffChainQuotes = isExactIn ? offChainQuoteProvider.getRouteWithQuotesExactIn : offChainQuoteProvider.getRouteWithQuotesExactOut; + const getV3Quotes = isExactIn ? v3OnChainQuoteProvider.getRouteWithQuotesExactIn : v3OnChainQuoteProvider.getRouteWithQuotesExactOut; + const getInfinityClQuotes = isExactIn ? infinityClOnChainQuoteProvider.getRouteWithQuotesExactIn : infinityClOnChainQuoteProvider.getRouteWithQuotesExactOut; + const getInfinityBinQuotes = isExactIn ? infinityBinOnChainQuoteProvider.getRouteWithQuotesExactIn : infinityBinOnChainQuoteProvider.getRouteWithQuotesExactOut; + const createMixedRouteQuoteFetcher = (chainId) => { + const mixedRouteOnChainQuoteProvider = infinitySdk.INFINITY_SUPPORTED_CHAINS.includes(chainId) ? mixedRouteOnChainQuoteProviderV2 : mixedRouteOnChainQuoteProviderV1; + return isExactIn ? mixedRouteOnChainQuoteProvider.getRouteWithQuotesExactIn : mixedRouteOnChainQuoteProvider.getRouteWithQuotesExactOut; + }; + return async function getRoutesWithQuotes(routes, { blockNumber, gasModel, signal, quoteId }) { + const { chainId } = routes[0]?.input || {}; + const getMixedRouteQuotes = createMixedRouteQuoteFetcher(chainId); + const infinityClRoutes = []; + const infinityBinRoutes = []; + const v3SingleHopRoutes = []; + const v3MultihopRoutes = []; + const mixedRoutesHaveV3Pool = []; + const routesCanQuoteOffChain = []; + for (const route of routes) { + if (route.type === 0 /* V2 */ || route.type === 2 /* STABLE */) { + routesCanQuoteOffChain.push(route); + continue; + } + if (route.type === 1 /* V3 */) { + if (route.pools.length === 1) { + v3SingleHopRoutes.push(route); + continue; + } + v3MultihopRoutes.push(route); + continue; + } + if (route.type === 7 /* InfinityStable */) { + if (isExactIn) { + mixedRoutesHaveV3Pool.push(route); + continue; + } + continue; + } + if (route.type === 5 /* InfinityCL */) { + if (isExactIn) { + mixedRoutesHaveV3Pool.push(route); + continue; + } + infinityClRoutes.push(route); + continue; + } + if (route.type === 6 /* InfinityBIN */) { + if (isExactIn) { + mixedRoutesHaveV3Pool.push(route); + continue; + } + infinityBinRoutes.push(route); + continue; + } + const { pools } = route; + if (pools.some( + (pool) => isV3Pool(pool) || isInfinityClPool(pool) || isInfinityBinPool(pool) || isInfinityStablePool(pool) + )) { + mixedRoutesHaveV3Pool.push(route); + continue; + } + routesCanQuoteOffChain.push(route); + } + logQuoters( + quoteId, + routesCanQuoteOffChain, + mixedRoutesHaveV3Pool, + v3SingleHopRoutes, + v3MultihopRoutes, + infinityClRoutes, + infinityBinRoutes + ); + const results = await Promise.allSettled([ + getOffChainQuotes(routesCanQuoteOffChain, { blockNumber, gasModel, signal, quoteId }), + getMixedRouteQuotes(mixedRoutesHaveV3Pool, { blockNumber, gasModel, retry: { retries: 0 }, signal, quoteId }), + getV3Quotes(v3SingleHopRoutes, { blockNumber, gasModel, signal, quoteId }), + getV3Quotes(v3MultihopRoutes, { blockNumber, gasModel, retry: { retries: 1 }, signal, quoteId }), + getInfinityClQuotes(infinityClRoutes, { blockNumber, gasModel, signal, quoteId }), + getInfinityBinQuotes(infinityBinRoutes, { blockNumber, gasModel, signal, quoteId }) + ]); + if (results.every((result) => result.status === "rejected")) { + throw new Error(results.map((result) => result.reason).join(",")); + } + return results.filter((result) => result.status === "fulfilled").reduce((acc, cur) => [...acc, ...cur.value], []); + }; + }; + return { + getRouteWithQuotesExactIn: createGetRouteWithQuotes(true), + getRouteWithQuotesExactOut: createGetRouteWithQuotes(false), + getConfig: () => config + }; +} +function logQuoters(quoteId, routesCanQuoteOffChain, mixedRoutesHaveV3Pool, v3SingleHopRoutes, v3MultihopRoutes, infinityClRoutes, infinityBinRoutes) { + const logger3 = RemoteLogger.getLogger(quoteId); + if (routesCanQuoteOffChain.length) { + logger3.debug(`try getOffChainQuotes=${routesCanQuoteOffChain.length}`, 2); + } + if (mixedRoutesHaveV3Pool.length) { + logger3.debug(`try getMixedRouteQuotes=${mixedRoutesHaveV3Pool.length}`, 2); + } + if (v3SingleHopRoutes.length) { + logger3.debug(`try getV3Quotes=${v3SingleHopRoutes.length}`, 2); + } + if (v3MultihopRoutes.length) { + logger3.debug(`try getV3Quotes=${v3MultihopRoutes.length}`, 2); + } + if (infinityClRoutes.length) { + logger3.debug(`try getInfinityClQuotes=${infinityClRoutes.length}`, 2); + } + if (infinityBinRoutes.length) { + logger3.debug(`try getInfinityBinQuotes=${infinityBinRoutes.length}`, 2); + } +} + +// evm/infinity-router/queries/getInfinityBinPools.ts +async function getInfinityBinCandidatePools({ + currencyA, + currencyB, + clientProvider, + gasLimit +}) { + const pools = await getInfinityBinCandidatePoolsWithoutBins({ + currencyA, + currencyB, + clientProvider + }); + if (!pools.length) { + return []; + } + return fillPoolsWithBins({ + pools, + clientProvider, + gasLimit + }); +} +async function getInfinityBinCandidatePoolsWithoutBins({ + currencyA, + currencyB, + clientProvider +}) { + if (!currencyA || !currencyB) { + throw new Error(`Invalid currencyA ${currencyA} or currencyB ${currencyB}`); + } + const wnative = sdk.getWrappedNative(currencyA.chainId); + const pairs = await getPairCombinations(currencyA, currencyB); + const pairsWithNative = [...pairs]; + if (wnative) { + const native = sdk.Native.onChain(currencyA.chainId); + for (const pair of pairs) { + const index = pair.findIndex((c) => c.wrapped.equals(wnative)); + if (index >= 0) { + const pairWithNative = [...pair]; + pairWithNative[index] = native; + pairsWithNative.push(pairWithNative); + } + } + } + return getInfinityBinPoolsWithoutBins(pairsWithNative, clientProvider); +} +var getInfinityBinPoolsWithoutBins = createOnChainPoolFactory({ + abi: infinitySdk.BinPoolManagerAbi, + getPossiblePoolMetas: async ([currencyA, currencyB]) => { + const { chainId } = currencyA; + if (!infinitySdk.isInfinitySupported(chainId)) + throw new Error(`Failed to get bin pools. Infinity not supported on chain ${chainId}`); + if (!infinitySdk.isInfinityBinSupported(chainId)) + return []; + const [currency0, currency1] = swapSdkCore.sortCurrencies([currencyA, currencyB]); + const poolIdList = /* @__PURE__ */ new Set(); + const metas = []; + const binPresets = chunkZNSTBYLO_js.BIN_PRESETS_BY_CHAIN[chainId]; + for (const { fee, binStep } of binPresets) { + const hookPresets = chunkZNSTBYLO_js.BIN_HOOK_PRESETS_BY_CHAIN[chainId]; + for (const { address: hooks, registrationBitmap, poolKeyOverride } of hookPresets) { + const poolKey = { + currency0: swapSdkCore.getCurrencyAddress(currency0), + currency1: swapSdkCore.getCurrencyAddress(currency1), + fee, + parameters: { + binStep, + hooksRegistration: registrationBitmap !== void 0 ? infinitySdk.decodeHooksRegistration(registrationBitmap) : void 0 + }, + poolManager: infinitySdk.INFI_BIN_POOL_MANAGER_ADDRESSES[chainId], + hooks, + ...poolKeyOverride ?? {} + }; + const id = infinitySdk.getPoolId(poolKey); + if (poolIdList.has(id)) { + continue; + } + poolIdList.add(id); + metas.push({ + currencyA, + currencyB, + fee, + binStep, + hooks, + poolManager: poolKey.poolManager, + id, + hooksRegistrationBitmap: registrationBitmap, + ...poolKeyOverride + }); + } + } + return metas; + }, + buildPoolInfoCalls: ({ id, poolManager: address }) => [ + { + address, + functionName: "getSlot0", + args: [id] + } + ], + buildPool: ({ currencyA, currencyB, id, binStep, poolManager, hooks, hooksRegistrationBitmap }, [slot0]) => { + if (!slot0 || !slot0[0]) { + return null; + } + const [activeId, protocolFee, lpFee] = slot0; + const [currency0, currency1] = swapSdkCore.sortCurrencies([currencyA, currencyB]); + return { + id, + type: 4 /* InfinityBIN */, + currency0, + currency1, + fee: lpFee, + protocolFee, + activeId, + binStep, + poolManager, + hooks, + hooksRegistrationBitmap + }; + } +}); +function getBinIdList({ + activeId, + binStep, + priceRange, + ...rest +}) { + const price = infinitySdk.getPriceFromId(activeId, binStep); + const [idLower, idUpper] = [ + infinitySdk.getIdFromPrice(price * (1 - priceRange), binStep), + infinitySdk.getIdFromPrice(price * (1 + priceRange), binStep) + ]; + const binIds = []; + for (let i = idLower; i <= idUpper; i += 1) { + binIds.push({ + ...rest, + binId: i + }); + } + return binIds; +} +async function fillPoolsWithBins({ + pools, + clientProvider, + gasLimit, + priceRange = 0.05 +}) { + if (!pools.length) { + return []; + } + const chainId = pools[0]?.currency0.chainId; + const client = clientProvider?.({ chainId }); + if (!client) { + throw new Error("Fill pools with ticks failed. No valid public client or tick lens found."); + } + const { gasLimit: gasLimitPerCall, retryGasMultiplier } = getInfinityPoolFetchConfig(chainId); + const binIds = pools.map( + ({ binStep, activeId }, i) => getBinIdList({ activeId, binStep, poolIndex: i, priceRange }) + ).reduce((acc, cur) => { + acc.push(...cur); + return acc; + }, []); + const res = await multicall.multicallByGasLimit( + binIds.map(({ poolIndex, binId }) => ({ + target: pools[poolIndex].poolManager, + callData: viem.encodeFunctionData({ + abi: infinitySdk.BinPoolManagerAbi, + args: [pools[poolIndex].id, binId], + functionName: "getBin" + }), + gasLimit: gasLimitPerCall / 20n + // get Bin is small + })), + { + chainId, + client, + gasLimit, + retryFailedCallsWithGreaterLimit: { + gasLimitMultiplier: retryGasMultiplier + } + } + ); + const poolsWithBins = pools.map((p) => ({ ...p })); + for (const [index, result] of res.results.entries()) { + const { poolIndex, binId } = binIds[index]; + const pool = poolsWithBins[poolIndex]; + const data = result.success ? viem.decodeFunctionResult({ + abi: infinitySdk.BinPoolManagerAbi, + functionName: "getBin", + data: result.result + }) : void 0; + if (!data) { + continue; + } + const [reserveX, reserveY] = data; + if (reserveX === 0n && reserveY === 0n) { + continue; + } + const binReserve = { + reserveX, + reserveY + }; + if (!pool.reserveOfBin) { + pool.reserveOfBin = { + [binId]: binReserve + }; + continue; + } + pool.reserveOfBin[binId] = binReserve; + } + return poolsWithBins.filter((p) => p.reserveOfBin); +} + +// evm/abis/QueryData.ts +var queryDataAbi = [ + { + inputs: [ + { internalType: "address", name: "_infinityClPoolManager", type: "address" }, + { internalType: "address", name: "_infinityClPositionManager", type: "address" }, + { internalType: "address", name: "_owner", type: "address" } + ], + stateMutability: "nonpayable", + type: "constructor" + }, + { inputs: [{ internalType: "address", name: "owner", type: "address" }], name: "OwnableInvalidOwner", type: "error" }, + { + inputs: [{ internalType: "address", name: "account", type: "address" }], + name: "OwnableUnauthorizedAccount", + type: "error" + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "previousOwner", type: "address" }, + { indexed: true, internalType: "address", name: "newOwner", type: "address" } + ], + name: "OwnershipTransferStarted", + type: "event" + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "previousOwner", type: "address" }, + { indexed: true, internalType: "address", name: "newOwner", type: "address" } + ], + name: "OwnershipTransferred", + type: "event" + }, + { + anonymous: false, + inputs: [ + { indexed: false, internalType: "address", name: "clPoolManager", type: "address" }, + { indexed: false, internalType: "address", name: "clPositionManager", type: "address" } + ], + name: "SetInfinityContract", + type: "event" + }, + { inputs: [], name: "acceptOwnership", outputs: [], stateMutability: "nonpayable", type: "function" }, + { + inputs: [], + name: "infinityClPoolManager", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function" + }, + { + inputs: [], + name: "infinityClPositionManager", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function" + }, + { + inputs: [], + name: "owner", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function" + }, + { + inputs: [], + name: "pendingOwner", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function" + }, + { + inputs: [ + { internalType: "bytes32", name: "poolId", type: "bytes32" }, + { internalType: "uint256", name: "len", type: "uint256" } + ], + name: "queryPancakeInfinityTicksSuperCompact", + outputs: [{ internalType: "bytes", name: "", type: "bytes" }], + stateMutability: "view", + type: "function" + }, + { + inputs: [ + { internalType: "address", name: "pool", type: "address" }, + { internalType: "uint256", name: "len", type: "uint256" } + ], + name: "queryUniv3TicksSuperCompact", + outputs: [{ internalType: "bytes", name: "", type: "bytes" }], + stateMutability: "view", + type: "function" + }, + { inputs: [], name: "renounceOwnership", outputs: [], stateMutability: "nonpayable", type: "function" }, + { + inputs: [ + { internalType: "address", name: "_clPoolManager", type: "address" }, + { internalType: "address", name: "_clPositionManager", type: "address" } + ], + name: "setInfinityContract", + outputs: [], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [{ internalType: "address", name: "newOwner", type: "address" }], + name: "transferOwnership", + outputs: [], + stateMutability: "nonpayable", + type: "function" + } +]; + +// evm/utils/compactTickQuery.helper.ts +var LIQUIDITY_NET_MASK = (1n << 128n) - 1n; +function decideCompactTickLen(priceRangeBps, tickSpacing, maxLen = 1n) { + const targetTicks = Math.log(1 + priceRangeBps / 1e4) / Math.log(1.0001); + const slotsNeeded = Math.ceil(targetTicks / tickSpacing / 256); + const len = BigInt(slotsNeeded * 2 * 256); + return len > maxLen ? maxLen : len; +} +function decodeTicksFromBytes(data) { + if (!data || data === "0x") { + return []; + } + const tickMap = /* @__PURE__ */ new Map(); + const hexString = data.slice(2); + const chunkSize = 64; + for (let offset = 0; offset + chunkSize <= hexString.length; offset += chunkSize) { + const chunk2 = `0x${hexString.slice(offset, offset + chunkSize)}`; + const raw = BigInt(chunk2); + const tickIndex = Number(BigInt.asIntN(128, raw >> 128n)); + const liquidityNet = BigInt.asIntN(128, raw & LIQUIDITY_NET_MASK); + const liquidityGross = liquidityNet < 0n ? -liquidityNet : liquidityNet; + tickMap.set( + tickIndex, + new v3Sdk.Tick({ + index: tickIndex, + liquidityNet, + liquidityGross + }) + ); + } + return Array.from(tickMap.values()).sort((a, b) => a.index - b.index); +} +function getCompactTickQueryCalldata(pool, len) { + switch (pool.type) { + case 1 /* V3 */: + return viem.encodeFunctionData({ + abi: queryDataAbi, + args: [pool.address, len], + functionName: "queryUniv3TicksSuperCompact" + }); + case 3 /* InfinityCL */: + return viem.encodeFunctionData({ + abi: queryDataAbi, + args: [pool.id, len], + functionName: "queryPancakeInfinityTicksSuperCompact" + }); + default: + throw new Error("Unsupported pool type for tick query"); + } +} +function decodeCompactTickResult(result, pool) { + const rawTicks = viem.decodeFunctionResult({ + abi: queryDataAbi, + functionName: pool.type === 3 /* InfinityCL */ ? "queryPancakeInfinityTicksSuperCompact" : "queryUniv3TicksSuperCompact", + data: result + }); + return decodeTicksFromBytes(rawTicks); +} +function getTickSpacing(pool) { + if (pool.type === 1 /* V3 */) { + return v3Sdk.TICK_SPACINGS[Number(pool.fee)]; + } + return pool.tickSpacing; +} +async function fetchCompactPoolsTick({ + pools, + clientProvider, + gasLimit +}) { + if (!pools.length) + return {}; + const currency = getPoolCurrency0(pools[0]); + const { chainId } = currency; + const client = clientProvider?.({ chainId }); + if (!client) + throw new Error("No valid public client found."); + const queryHelperAddress = chunkZNSTBYLO_js.TICK_QUERY_HELPER_ADDRESSES[chainId]; + if (!queryHelperAddress) + return {}; + const { retryGasMultiplier } = getTickQueryFetchConfig(); + const gasLimitPerCall = 10000000n; + const multiCallArgs = pools.map((pool) => ({ + target: queryHelperAddress, + callData: getCompactTickQueryCalldata(pool, decideCompactTickLen(1e3, getTickSpacing(pool))), + gasLimit: gasLimitPerCall + })); + const res = await multicall.multicallByGasLimit(multiCallArgs, { + chainId, + client, + gasLimit, + retryFailedCallsWithGreaterLimit: { gasLimitMultiplier: retryGasMultiplier } + }); + const ticksByPool = {}; + for (const [i, result] of res.results.entries()) { + if (!result.success || !result.result) + continue; + const decoded = decodeCompactTickResult(result.result, pools[i]); + if (decoded.length) { + if (pools[i].type === 3 /* InfinityCL */) { + ticksByPool[pools[i].id.toLocaleLowerCase()] = decoded; + } else if (pools[i].type === 1 /* V3 */) { + ticksByPool[pools[i].address.toLowerCase()] = decoded; + } + } + } + return ticksByPool; +} + +// evm/abis/IInfinityCLTickLens.ts +var infinityCLTickLensAbi = [ + { + type: "constructor", + inputs: [{ name: "_poolManager", type: "address", internalType: "contract ICLPoolManager" }], + stateMutability: "nonpayable" + }, + { + type: "function", + name: "getPopulatedTicksInWord", + inputs: [ + { + name: "key", + type: "tuple", + internalType: "struct PoolKey", + components: [ + { name: "currency0", type: "address", internalType: "Currency" }, + { name: "currency1", type: "address", internalType: "Currency" }, + { name: "hooks", type: "address", internalType: "contract IHooks" }, + { name: "poolManager", type: "address", internalType: "contract IPoolManager" }, + { name: "fee", type: "uint24", internalType: "uint24" }, + { name: "parameters", type: "bytes32", internalType: "bytes32" } + ] + }, + { name: "tickBitmapIndex", type: "int16", internalType: "int16" } + ], + outputs: [ + { + name: "populatedTicks", + type: "tuple[]", + internalType: "struct ITickLens.PopulatedTick[]", + components: [ + { name: "tick", type: "int24", internalType: "int24" }, + { name: "liquidityNet", type: "int128", internalType: "int128" }, + { name: "liquidityGross", type: "uint128", internalType: "uint128" } + ] + } + ], + stateMutability: "view" + }, + { + type: "function", + name: "getPopulatedTicksInWord", + inputs: [ + { name: "id", type: "bytes32", internalType: "PoolId" }, + { name: "tickBitmapIndex", type: "int16", internalType: "int16" } + ], + outputs: [ + { + name: "populatedTicks", + type: "tuple[]", + internalType: "struct ITickLens.PopulatedTick[]", + components: [ + { name: "tick", type: "int24", internalType: "int24" }, + { name: "liquidityNet", type: "int128", internalType: "int128" }, + { name: "liquidityGross", type: "uint128", internalType: "uint128" } + ] + } + ], + stateMutability: "view" + }, + { + type: "function", + name: "poolManager", + inputs: [], + outputs: [{ name: "", type: "address", internalType: "contract ICLPoolManager" }], + stateMutability: "view" + }, + { type: "error", name: "PoolNotInitialized", inputs: [] } +]; + +// evm/abis/ITickLens.ts +var tickLensAbi = [ + { + inputs: [ + { internalType: "address", name: "pool", type: "address" }, + { internalType: "int16", name: "tickBitmapIndex", type: "int16" } + ], + name: "getPopulatedTicksInWord", + outputs: [ + { + components: [ + { internalType: "int24", name: "tick", type: "int24" }, + { internalType: "int128", name: "liquidityNet", type: "int128" }, + { internalType: "uint128", name: "liquidityGross", type: "uint128" } + ], + internalType: "struct ITickLens.PopulatedTick[]", + name: "populatedTicks", + type: "tuple[]" + } + ], + stateMutability: "view", + type: "function" + } +]; + +// evm/utils/tickLenQuery.helper.ts +var TICK_RANGE_BY_POOL_TYPE = { + [1 /* V3 */]: 1e3, + [3 /* InfinityCL */]: 10 +}; +function getPoolChainId(pool) { + if (pool.type === 1 /* V3 */) { + return pool.token0.chainId; + } + return pool.currency0.chainId; +} +var MIN_TICK = -887272; +var MAX_TICK = 887272; +function getBoundaryBitmapIndexes(tickSpacing) { + const minUsable = Math.ceil(MIN_TICK / tickSpacing) * tickSpacing; + const maxUsable = Math.floor(MAX_TICK / tickSpacing) * tickSpacing; + return [.../* @__PURE__ */ new Set([getBitmapIndex(minUsable, tickSpacing), getBitmapIndex(maxUsable, tickSpacing)])]; +} +function getBitmapIndex(tick, tickSpacing) { + return Math.floor(tick / tickSpacing / 256); +} +function createBitmapIndexListBuilder(tickRange) { + return function buildBitmapIndexList({ currentTick, tickSpacing, ...rest }) { + const minIndex = getBitmapIndex(currentTick - tickRange, tickSpacing); + const maxIndex = getBitmapIndex(currentTick + tickRange, tickSpacing); + return Array.from({ length: maxIndex - minIndex + 1 }, (_, i) => ({ + bitmapIndex: minIndex + i, + ...rest + })); + }; +} +var buildV3BitmapIndexList = createBitmapIndexListBuilder(TICK_RANGE_BY_POOL_TYPE[1 /* V3 */]); +var buildInfinityBitmapIndexList = createBitmapIndexListBuilder(TICK_RANGE_BY_POOL_TYPE[3 /* InfinityCL */]); +function ensureSameChain(pools) { + const [first, ...rest] = pools; + const chainId = getPoolChainId(first); + for (const pool of rest) { + if (getPoolChainId(pool) !== chainId) { + throw new Error("Cannot fetch ticks for pools across different chains in a single call"); + } + } + return chainId; +} +function normalizePoolKey(pool) { + return pool.type === 1 /* V3 */ ? pool.address.toLowerCase() : pool.id.toLowerCase(); +} +async function fetchTickLensTicksInRange({ + pool, + numSurroundingTicks, + clientProvider, + gasLimit +}) { + const client = clientProvider?.({ chainId: pool.chainId }); + if (!client) + throw new Error("Fetch ticks failed. No valid public client found."); + const tickLensAddress = pool.type === 1 /* V3 */ ? chunkZNSTBYLO_js.V3_TICK_LENS_ADDRESSES[pool.chainId] : infinitySdk.INFI_CL_TICK_LENS_ADDRESSES[pool.chainId]; + if (!tickLensAddress) + throw new Error("Fetch ticks failed. No tick lens found."); + const bitmapIndexes = createBitmapIndexListBuilder(numSurroundingTicks * pool.tickSpacing)({ + currentTick: pool.currentTick, + tickSpacing: pool.tickSpacing + }); + const { gasLimit: gasLimitPerCall, retryGasMultiplier } = getTickLensFetchConfig(); + const isV3 = pool.type === 1 /* V3 */; + const abi = isV3 ? tickLensAbi : infinityCLTickLensAbi; + const functionName = "getPopulatedTicksInWord"; + const poolIdentifier = isV3 ? pool.address : pool.poolId; + const res = await multicall.multicallByGasLimit( + bitmapIndexes.map(({ bitmapIndex }) => ({ + target: tickLensAddress, + callData: viem.encodeFunctionData({ + abi, + args: [poolIdentifier, bitmapIndex], + functionName + }), + gasLimit: gasLimitPerCall + })), + { + chainId: pool.chainId, + client, + gasLimit, + retryFailedCallsWithGreaterLimit: { gasLimitMultiplier: retryGasMultiplier } + } + ); + if (res.results.some((result) => !result.success || !result.result)) { + throw new Error("Fetch ticks failed. TickLens returned an incomplete bitmap range."); + } + const ticks = res.results.flatMap((result) => { + if (!result.success || !result.result) + return []; + const data = viem.decodeFunctionResult({ + abi, + functionName, + data: result.result + }); + return data.map(({ tick, liquidityNet, liquidityGross }) => new v3Sdk.Tick({ index: tick, liquidityNet, liquidityGross })); + }); + return ticks.sort((a, b) => a.index - b.index); +} +async function fetchTickLenPoolsTick({ + pools, + clientProvider, + gasLimit, + disableFilterNoTicks +}) { + if (!pools.length) { + return {}; + } + const chainId = ensureSameChain(pools); + const client = clientProvider?.({ chainId }); + if (!client) { + throw new Error("Fill pools with ticks failed. No valid public client found."); + } + const { gasLimit: gasLimitPerCall, retryGasMultiplier } = getTickLensFetchConfig(); + const ticksByPool = {}; + const v3Pools = pools.filter((pool) => pool.type === 1 /* V3 */); + if (v3Pools.length) { + const tickLensAddress = chunkZNSTBYLO_js.V3_TICK_LENS_ADDRESSES[chainId]; + if (!tickLensAddress) { + throw new Error("Fill pools with ticks failed. No V3 tick lens found."); + } + const bitmapIndexes = v3Pools.flatMap( + (pool) => buildV3BitmapIndexList({ + currentTick: pool.tick, + tickSpacing: v3Sdk.TICK_SPACINGS[Number(pool.fee)], + pool + }) + ); + if (bitmapIndexes.length) { + const res = await multicall.multicallByGasLimit( + bitmapIndexes.map(({ pool, bitmapIndex }) => ({ + target: tickLensAddress, + callData: viem.encodeFunctionData({ + abi: tickLensAbi, + args: [pool.address, bitmapIndex], + functionName: "getPopulatedTicksInWord" + }), + gasLimit: gasLimitPerCall + })), + { + chainId, + client, + gasLimit, + retryFailedCallsWithGreaterLimit: { + gasLimitMultiplier: retryGasMultiplier + } + } + ); + for (const [index, result] of res.results.entries()) { + const { pool } = bitmapIndexes[index]; + if (!result.success || !result.result) { + if (disableFilterNoTicks) { + ticksByPool[normalizePoolKey(pool)] = ticksByPool[normalizePoolKey(pool)] ?? []; + } + continue; + } + const data = viem.decodeFunctionResult({ + abi: tickLensAbi, + functionName: "getPopulatedTicksInWord", + data: result.result + }); + const newTicks = data?.map( + ({ tick, liquidityNet, liquidityGross }) => new v3Sdk.Tick({ + index: tick, + liquidityNet, + liquidityGross + }) + ).reverse(); + if (!newTicks?.length) { + if (disableFilterNoTicks) { + ticksByPool[normalizePoolKey(pool)] = ticksByPool[normalizePoolKey(pool)] ?? []; + } + continue; + } + const key = normalizePoolKey(pool); + ticksByPool[key] = [...ticksByPool[key] ?? [], ...newTicks]; + } + } + } + const infinityPools = pools.filter((pool) => pool.type === 3 /* InfinityCL */); + if (infinityPools.length) { + const tickLensAddress = infinitySdk.INFI_CL_TICK_LENS_ADDRESSES[chainId]; + if (!tickLensAddress) { + throw new Error("Fill pools with ticks failed. No Infinity tick lens found."); + } + const bitmapIndexes = infinityPools.flatMap( + (pool) => buildInfinityBitmapIndexList({ + currentTick: pool.tick, + tickSpacing: pool.tickSpacing, + pool + }) + ); + if (bitmapIndexes.length) { + const res = await multicall.multicallByGasLimit( + bitmapIndexes.map(({ pool, bitmapIndex }) => ({ + target: tickLensAddress, + callData: viem.encodeFunctionData({ + abi: infinityCLTickLensAbi, + args: [pool.id, bitmapIndex], + functionName: "getPopulatedTicksInWord" + }), + gasLimit: gasLimitPerCall + })), + { + chainId, + client, + gasLimit, + retryFailedCallsWithGreaterLimit: { + gasLimitMultiplier: retryGasMultiplier + } + } + ); + for (const [index, result] of res.results.entries()) { + const { pool } = bitmapIndexes[index]; + if (!result.success || !result.result) { + if (disableFilterNoTicks) { + ticksByPool[normalizePoolKey(pool)] = ticksByPool[normalizePoolKey(pool)] ?? []; + } + continue; + } + const data = viem.decodeFunctionResult({ + abi: infinityCLTickLensAbi, + functionName: "getPopulatedTicksInWord", + data: result.result + }); + const newTicks = data?.map( + ({ tick, liquidityNet, liquidityGross }) => new v3Sdk.Tick({ + index: tick, + liquidityNet, + liquidityGross + }) + ).reverse(); + if (!newTicks?.length) { + if (disableFilterNoTicks) { + ticksByPool[normalizePoolKey(pool)] = ticksByPool[normalizePoolKey(pool)] ?? []; + } + continue; + } + const key = normalizePoolKey(pool); + ticksByPool[key] = [...ticksByPool[key] ?? [], ...newTicks]; + } + } + const emptyPools = infinityPools.filter((pool) => !ticksByPool[normalizePoolKey(pool)]?.length); + const boundaryCalls = emptyPools.flatMap( + (pool) => getBoundaryBitmapIndexes(pool.tickSpacing).map((bitmapIndex) => ({ pool, bitmapIndex })) + ); + if (boundaryCalls.length) { + const res = await multicall.multicallByGasLimit( + boundaryCalls.map(({ pool, bitmapIndex }) => ({ + target: tickLensAddress, + callData: viem.encodeFunctionData({ + abi: infinityCLTickLensAbi, + args: [pool.id, bitmapIndex], + functionName: "getPopulatedTicksInWord" + }), + gasLimit: gasLimitPerCall + })), + { chainId, client, gasLimit, retryFailedCallsWithGreaterLimit: { gasLimitMultiplier: retryGasMultiplier } } + ); + const boundaryTicksByPool = {}; + for (const [index, result] of res.results.entries()) { + if (!result.success || !result.result) + continue; + const { pool } = boundaryCalls[index]; + const data = viem.decodeFunctionResult({ + abi: infinityCLTickLensAbi, + functionName: "getPopulatedTicksInWord", + data: result.result + }); + const newTicks = data?.map(({ tick, liquidityNet, liquidityGross }) => new v3Sdk.Tick({ index: tick, liquidityNet, liquidityGross })).reverse(); + if (!newTicks?.length) + continue; + const key = normalizePoolKey(pool); + boundaryTicksByPool[key] = [...boundaryTicksByPool[key] ?? [], ...newTicks]; + } + for (const pool of emptyPools) { + const key = normalizePoolKey(pool); + const ticks = boundaryTicksByPool[key]; + if (!ticks?.length) + continue; + const liquidityAtSpot = ticks.filter((t) => t.index <= pool.tick).reduce((acc, t) => acc + t.liquidityNet, 0n); + if (liquidityAtSpot !== pool.liquidity) + continue; + const liquidityNetTotal = ticks.reduce((acc, t) => acc + t.liquidityNet, 0n); + if (liquidityNetTotal !== 0n) + continue; + ticksByPool[key] = [...ticksByPool[key] ?? [], ...ticks]; + } + } + } + if (!disableFilterNoTicks) { + for (const key of Object.keys(ticksByPool)) { + if (!ticksByPool[key]?.length) { + delete ticksByPool[key]; + } + } + } + for (const key of Object.keys(ticksByPool)) { + ticksByPool[key] = ticksByPool[key].sort((a, b) => a.index - b.index); + } + return ticksByPool; +} + +// evm/utils/combinedTickQuery.helper.ts +function getPoolChainId2(pool) { + if (pool.type === 1 /* V3 */) { + return pool.token0.chainId; + } + return pool.currency0.chainId; +} +async function fetchCombinedPoolsTick({ + pools, + clientProvider, + gasLimit, + disableFilterNoTicks +}) { + if (!pools.length) { + return {}; + } + const tickLenTicksByPool = await fetchTickLenPoolsTick({ + pools, + clientProvider, + gasLimit, + disableFilterNoTicks + }); + const poolsNeedingCompactFallback = []; + const finalTicksByPool = {}; + for (const pool of pools) { + const poolKey = getPoolKey(pool); + const tickLenTicks = tickLenTicksByPool[poolKey] || []; + if (tickLenTicks.length === 0) { + poolsNeedingCompactFallback.push(pool); + } else { + finalTicksByPool[poolKey] = tickLenTicks; + } + } + const skipCompactTickFallback = chains.getChainConfig(getPoolChainId2(pools[0]))?.routing?.skipCompactTickFallback; + if (skipCompactTickFallback) { + return finalTicksByPool; + } + if (poolsNeedingCompactFallback.length > 0) { + const compactTicksByPool = await fetchCompactPoolsTick({ + pools: poolsNeedingCompactFallback, + clientProvider, + gasLimit + }); + for (const pool of poolsNeedingCompactFallback) { + const poolKey = getPoolKey(pool); + const compactTicks = compactTicksByPool[poolKey] || []; + if (compactTicks.length > 0) { + finalTicksByPool[poolKey] = compactTicks; + } else if (disableFilterNoTicks) { + finalTicksByPool[poolKey] = []; + } + } + } + return finalTicksByPool; +} +function getPoolKey(pool) { + if (pool.type === 1 /* V3 */) { + return pool.address.toLowerCase(); + } + return pool.id.toLowerCase(); +} + +// evm/infinity-router/queries/getInfinityClPools.ts +async function getInfinityClCandidatePools({ + currencyA, + currencyB, + clientProvider, + gasLimit +}) { + const pools = await getInfinityClCandidatePoolsWithoutTicks({ + currencyA, + currencyB, + clientProvider + }); + return fillClPoolsWithTicks({ + pools, + clientProvider, + gasLimit + }); +} +async function getInfinityClCandidatePoolsWithoutTicks({ + currencyA, + currencyB, + clientProvider +}) { + if (!currencyA || !currencyB) { + throw new Error(`Invalid currencyA ${currencyA} or currencyB ${currencyB}`); + } + const wnative = sdk.getWrappedNative(currencyA.chainId); + const pairs = await getPairCombinations(currencyA, currencyB); + const pairsWithNative = [...pairs]; + if (wnative) { + const native = sdk.Native.onChain(currencyA.chainId); + for (const pair of pairs) { + const index = pair.findIndex((c) => c.wrapped.equals(wnative)); + if (index >= 0) { + const pairWithNative = [...pair]; + pairWithNative[index] = native; + pairsWithNative.push(pairWithNative); + } + } + } + return getInfinityClPoolsWithoutTicks(pairsWithNative, clientProvider); +} +var getInfinityClPoolsWithoutTicks = createOnChainPoolFactory({ + abi: infinitySdk.CLPoolManagerAbi, + getPossiblePoolMetas: async ([currencyA, currencyB]) => { + const { chainId } = currencyA; + if (!infinitySdk.isInfinitySupported(chainId)) + throw new Error(`Failed to get cl pools. Infinity not supported on chain ${chainId}`); + const [currency0, currency1] = swapSdkCore.sortCurrencies([currencyA, currencyB]); + const poolIdList = /* @__PURE__ */ new Set(); + const metas = []; + const presets = chunkZNSTBYLO_js.CL_PRESETS_BY_CHAIN[chainId]; + const defaultHookPresets = chunkZNSTBYLO_js.CL_HOOK_PRESETS_BY_CHAIN[chainId]; + const whitelistLabeledHooksWithoutMetadata = (infinitySdk.whitelistLabeledHooksList[chainId] ?? []).map((hook) => ({ + address: hook, + // Default 0x55 for whitelist labeled hooks + // Similar to 0x9a9B5331ce8d74b2B721291D57DE696E878353fd hook registration bitmap + registrationBitmap: "0x55", + poolKeyOverride: void 0 + })); + const addPoolMeta = (fee, tickSpacing, hooks, registrationBitmap, poolKeyOverride) => { + const poolKey = { + currency0: swapSdkCore.getCurrencyAddress(currency0), + currency1: swapSdkCore.getCurrencyAddress(currency1), + fee, + parameters: { + tickSpacing, + hooksRegistration: registrationBitmap !== void 0 ? infinitySdk.decodeHooksRegistration(registrationBitmap) : void 0 + }, + poolManager: infinitySdk.INFI_CL_POOL_MANAGER_ADDRESSES[chainId], + hooks, + ...poolKeyOverride ?? {} + }; + const id = infinitySdk.getPoolId(poolKey); + if (poolIdList.has(id)) { + return; + } + poolIdList.add(id); + metas.push({ + currencyA, + currencyB, + fee, + tickSpacing, + hooks, + poolManager: poolKey.poolManager, + id, + hooksRegistrationBitmap: registrationBitmap, + ...poolKeyOverride ?? {} + }); + }; + for (const { fee, tickSpacing } of presets) { + for (const { address: hooks, registrationBitmap, poolKeyOverride } of defaultHookPresets) { + addPoolMeta(fee, tickSpacing, hooks, registrationBitmap, poolKeyOverride); + } + } + const fees = presets.map((p) => p.fee); + const tickSpacings = presets.map((p) => p.tickSpacing); + for (const fee of fees) { + for (const tickSpacing of tickSpacings) { + for (const { address: hooks, registrationBitmap, poolKeyOverride } of whitelistLabeledHooksWithoutMetadata) { + addPoolMeta(fee, tickSpacing, hooks, registrationBitmap, poolKeyOverride); + } + } + } + return metas; + }, + buildPoolInfoCalls: ({ id, poolManager: address }) => [ + { + address, + functionName: "getLiquidity", + args: [id] + }, + { + address, + functionName: "getSlot0", + args: [id] + } + ], + buildPool: ({ currencyA, currencyB, id, tickSpacing, poolManager, hooks, hooksRegistrationBitmap }, [liquidity, slot0]) => { + if (!slot0 || !slot0[0]) { + return null; + } + const [sqrtPriceX96, tick, protocolFee, lpFee] = slot0; + const [currency0, currency1] = swapSdkCore.sortCurrencies([currencyA, currencyB]); + const whitelistHook = infinitySdk.findHook(hooks, currencyA.wrapped.chainId); + return { + id, + type: 3 /* InfinityCL */, + currency0, + currency1, + fee: whitelistHook?.defaultFee ?? lpFee, + protocolFee, + liquidity: BigInt(liquidity.toString()), + sqrtRatioX96: BigInt(sqrtPriceX96.toString()), + tick: Number(tick), + tickSpacing, + poolManager, + hooks, + hooksRegistrationBitmap + }; + } +}); +async function fillClPoolsWithTicks({ + pools, + clientProvider, + gasLimit +}) { + if (pools.length === 0) { + return []; + } + const chainId = pools[0]?.currency0.chainId; + const client = clientProvider?.({ chainId }); + if (!client) { + throw new Error("Fill pools with ticks failed. No valid public client found."); + } + const ticksByPool = await fetchCombinedPoolsTick({ pools, clientProvider, gasLimit }); + const poolsWithTicks = pools.map((p) => ({ + ...p, + ticks: ticksByPool[p.id.toLowerCase()] ?? [] + })); + return poolsWithTicks.filter((p) => p.ticks.length); +} + +// evm/infinity-router/queries/getPoolTvl.ts +var getInfinityPoolTvl = (map, poolId) => { + const ref = map[poolId]; + const tvlUsd = BigInt(ref ? ref.tvlUSD : 0n); + return tvlUsd; +}; + +// evm/infinity-router/queries/getInfinityPools.ts +var getInfinityCandidatePools = async (params) => { + const pools = await getInfinityCandidatePoolsLite(params); + const clPools = pools.filter((pool) => pool.type === 3 /* InfinityCL */); + const binPools = pools.filter((pool) => pool.type === 4 /* InfinityBIN */); + const [poolWithTicks, poolWithBins] = await Promise.all([ + fillClPoolsWithTicks({ + pools: clPools, + clientProvider: params.clientProvider, + gasLimit: params.gasLimit + }), + fillPoolsWithBins({ + pools: binPools, + clientProvider: params.clientProvider, + gasLimit: params.gasLimit + }) + ]); + return [...poolWithTicks, ...poolWithBins]; +}; +async function fetchPoolsOnChain(params) { + const [clPools, binPools] = await Promise.all([ + getInfinityClCandidatePoolsWithoutTicks(params), + getInfinityBinCandidatePoolsWithoutBins(params) + ]); + const pools = [...clPools, ...binPools]; + const poolsWithTvl = pools.map((pool) => { + return { + ...pool, + tvlUSD: params.tvlRefMap ? getInfinityPoolTvl(params.tvlRefMap, pool.id) : 0n + }; + }); + return poolsWithTvl; +} +var getInfinityCandidatePoolsLite = async (params) => { + const pools = await fetchPoolsOnChain(params); + const filtered = infinityPoolTvlSelector(params.currencyA, params.currencyB, pools); + return filtered; +}; + +// evm/infinity-router/queries/getV3Pools.ts +async function getV3CandidatePools2({ + currencyA, + currencyB, + clientProvider, + gasLimit, + disableFilterNoTicks +}) { + const pairs = await getPairCombinations(currencyA, currencyB); + return getV3Pools({ pairs, clientProvider, gasLimit, disableFilterNoTicks }); +} +async function getV3Pools({ pairs, clientProvider, gasLimit, disableFilterNoTicks }) { + const pools = await getV3PoolsWithoutTicksOnChain(pairs || [], clientProvider); + if (!pools.length) { + return pools; + } + return fillPoolsWithTicks({ pools, clientProvider, gasLimit, disableFilterNoTicks }); +} +async function fillPoolsWithTicks({ + pools, + clientProvider, + gasLimit, + disableFilterNoTicks +}) { + const finalTicksByPool = await fetchCombinedPoolsTick({ + pools, + clientProvider, + gasLimit, + disableFilterNoTicks + }); + const poolsWithTicks = pools.map((p) => ({ + ...p, + ticks: finalTicksByPool[p.address.toLowerCase()] ?? [] + })); + return disableFilterNoTicks ? poolsWithTicks : poolsWithTicks.filter((p) => p.ticks.length); +} +function getValidToken(chainId, token) { + try { + const raw = { + address: viem.checksumAddress(token.id), + decimals: token.decimals, + symbol: token.symbol + }; + return parseCurrency(chainId, raw); + } catch (ex) { + console.warn("invalid token", token, ex); + throw ex; + } +} +function normalizeTvlUSD(tvlUSD) { + const val = Number(tvlUSD); + return Number.isFinite(val) ? Math.ceil(val).toString() : "0"; +} +function parseRemotePool(remote) { + if (remote.protocol === "infinityCl") { + return toLocalInfinityPool(remote, remote.chainId); + } + if (remote.protocol === "infinityBin") { + return toLocalInfinityPool(remote, remote.chainId); + } + if (remote.protocol === "infinityStable") { + return parseRemoteInfinityStablePool(remote); + } + if (remote.protocol === "v2") { + return parseRemoteV2Pool(remote); + } + if (remote.protocol === "v3") { + if (remote.chainId === chains.NonEVMChainId.SOLANA) + return parseRemoteV3Pool(remote); + return parseRemoteV3Pool(remote); + } + if (remote.protocol === "stable") { + return parseRemoteStablePool(remote); + } + throw new Error(`Unsupported pool protocol`); +} +function parseRemoteStablePool(remote) { + const chainId = remote.chainId; + const currency0 = getValidToken(chainId, remote.token0); + const currency1 = getValidToken(chainId, remote.token1); + return { + type: 2 /* STABLE */, + address: viem.checksumAddress(remote.id), + balances: [swapSdkCore.CurrencyAmount.fromRawAmount(currency0, 0), swapSdkCore.CurrencyAmount.fromRawAmount(currency1, 0)], + amplifier: 0n, + fee: new swapSdkCore.Percent(remote.feeTier || 0, 1e3) + }; +} +function parseRemoteInfinityStablePool(remote) { + const chainId = remote.chainId; + const currency0 = getValidToken(chainId, remote.token0); + const currency1 = getValidToken(chainId, remote.token1); + const tvlUSD = BigInt(normalizeTvlUSD(remote.tvlUSD)); + const poolManagerAddress = infinitySdk.INFI_CL_POOL_MANAGER_ADDRESSES[chainId]; + return { + type: 5 /* InfinityStable */, + id: viem.checksumAddress(remote.id), + chainId, + currency0, + currency1, + fee: remote.feeTier, + tickSpacing: 1, + // NOTE: amplifier and stableFee are not available in the remote pool yet + amplifier: 0, + stableFee: 0, + hooks: remote.hookAddress ? viem.checksumAddress(remote.hookAddress) : void 0, + poolManager: poolManagerAddress, + tvlUSD + }; +} +function parseRemoteV2Pool(remote) { + const chainId = remote.chainId; + const currency0 = getValidToken(chainId, remote.token0); + const currency1 = getValidToken(chainId, remote.token1); + return { + type: 0 /* V2 */, + address: viem.checksumAddress(remote.id), + reserve0: swapSdkCore.CurrencyAmount.fromRawAmount(currency0, 0), + reserve1: swapSdkCore.CurrencyAmount.fromRawAmount(currency1, 0) + }; +} +function parseRemoteV3Pool(remote) { + const { chainId } = remote; + const isSol = chainId === chains.NonEVMChainId.SOLANA; + return { + type: 1 /* V3 */, + token0: isSol ? parseSolanaToken(chainId, remote.token0) : getValidToken(chainId, remote.token0), + token1: isSol ? parseSolanaToken(chainId, remote.token1) : getValidToken(chainId, remote.token1), + fee: remote.feeTier, + liquidity: remote.liquidity ? BigInt(remote.liquidity) : 0n, + sqrtRatioX96: 0n, + token0ProtocolFee: new swapSdkCore.Percent(0, 1e6), + token1ProtocolFee: new swapSdkCore.Percent(0, 1e6) + }; +} +var DEFAULT_SOLANA_PROGRAM_ID = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"; +function parseSolanaToken(chainId, token) { + const programId = DEFAULT_SOLANA_PROGRAM_ID; + return new swapSdkCore.SPLToken({ + chainId, + address: token.id, + decimals: token.decimals, + symbol: token.symbol, + logoURI: "", + programId + }); +} +function toLocalInfinityPool(remote, chainId, hooksMap) { + const { id, feeTier, protocol, protocolFee, hookAddress, tvlUSD } = remote; + const type = protocol === "infinityCl" ? 3 /* InfinityCL */ : 4 /* InfinityBIN */; + let relatedHook = infinitySdk.hooksList[chainId]?.find((hook) => hook.address.toLowerCase() === hookAddress?.toLowerCase()); + if (hooksMap && !relatedHook && hookAddress) { + relatedHook = hooksMap?.[hookAddress.toLowerCase()]; + } + const currency0 = getValidToken(chainId, remote.token0); + const currency1 = getValidToken(chainId, remote.token1); + const bnTvlUsd = BigInt(normalizeTvlUSD(tvlUSD)); + const pool = { + id: viem.checksumAddress(id), + chainId, + type, + fee: feeTier, + protocolFee, + hooks: hookAddress ? viem.checksumAddress(hookAddress) : void 0, + hooksRegistrationBitmap: relatedHook ? infinitySdk.encodeHooksRegistration(relatedHook.hooksRegistration) : void 0, + poolManager: type === 4 /* InfinityBIN */ ? infinitySdk.INFI_BIN_POOL_MANAGER_ADDRESSES[chainId] : infinitySdk.INFI_CL_POOL_MANAGER_ADDRESSES[chainId], + currency0, + currency1, + tvlUSD: bnTvlUsd + }; + if (pool.type === 3 /* InfinityCL */) { + const remoteClPool = remote; + return { + ...pool, + type: 3 /* InfinityCL */, + sqrtRatioX96: remoteClPool.sqrtPrice ? BigInt(remoteClPool.sqrtPrice) : 0n, + tick: remoteClPool.tick, + ticks: remoteClPool.ticks ? remoteClPool.ticks.map((x) => parseTick(x)) : [], + tickSpacing: Number(remoteClPool.tickSpacing), + liquidity: remoteClPool.liquidity ? BigInt(remoteClPool.liquidity) : 0n + }; + } + if (pool.type === 4 /* InfinityBIN */) { + const removeBinPool = remote; + const binPool = { + ...pool, + type: 4 /* InfinityBIN */, + binStep: removeBinPool.binStep, + activeId: removeBinPool.activeId, + reserveOfBin: parseBinPoolBinReserves(removeBinPool.reserveOfBin) + }; + return binPool; + } + throw new Error(`Unknown pool type: ${type}`); +} +function toRemoteInfinityPool(pool) { + const base = { + id: pool.id, + chainId: pool.currency0.chainId, + token0: { + id: pool.currency0.wrapped.address, + decimals: pool.currency0.decimals, + symbol: pool.currency0.symbol || "" + }, + token1: { + id: pool.currency1.wrapped.address, + decimals: pool.currency1.decimals, + symbol: pool.currency1.symbol || "" + }, + tvlUSD: pool.tvlUSD.toString(), + apr24h: "0", + volumeUSD24h: "0", + hookAddress: pool.hooks, + isDynamicFee: false, + // Assuming default; adjust based on your logic + protocol: pool.type === 3 /* InfinityCL */ ? "infinityCl" : "infinityBin", + feeTier: pool.fee + }; + if (pool.type === 3 /* InfinityCL */) { + const ticks = pool.ticks ? pool.ticks.map((x) => serializeTick(x)) : []; + return { + ...base, + sqrtPrice: pool.sqrtRatioX96.toString(), + tick: pool.tick, + ticks, + tickSpacing: pool.tickSpacing, + protocolFee: pool.protocolFee || 0, + feeTier: pool.fee + }; + } + if (pool.type === 4 /* InfinityBIN */) { + const bins = serializeBinPoolBinReserves(pool.reserveOfBin); + return { + ...base, + binStep: pool.binStep, + activeId: pool.activeId, + reserveOfBin: bins, + protocolFee: pool.protocolFee || 0, + feeTier: pool.fee + }; + } + throw new Error(`Unsupported pool type: ${pool}`); +} + +// evm/infinity-router/schema.ts +var schema_exports = {}; +chunkZNSTBYLO_js.__export(schema_exports, { + zPools: () => zPools, + zRouterPostParams: () => zRouterPostParams +}); +var zChainId = zod.z.nativeEnum(chains.ChainId); +var zFee = zod.z.number(); +var zTradeType = zod.z.nativeEnum(sdk.TradeType); +var zAddress = zod.z.custom((val) => /^0x[a-fA-F0-9]{40}$/.test(val)); +var zBigNumber = zod.z.string().regex(/^[0-9]+$/); +var zSignedBigInt = zod.z.string().regex(/^-?[0-9]+$/); +var zHex = zod.z.custom((val) => /^0x[a-fA-F0-9]*$/.test(val)); +var zHooksRegistrationBitmap = zod.z.number().or(zHex); +var zCurrency = zod.z.object({ + address: zAddress, + decimals: zod.z.number(), + symbol: zod.z.string() +}).required(); +var zTick = zod.z.object({ + index: zod.z.number(), + liquidityGross: zSignedBigInt, + liquidityNet: zSignedBigInt +}).required(); +var zCurrencyAmountBase = zod.z.object({ + currency: zCurrency.required(), + value: zBigNumber +}); +var zCurrencyAmountOptional = zCurrencyAmountBase.optional(); +var zCurrencyAmount = zCurrencyAmountBase.required(); +var zV2Pool = zod.z.object({ + type: zod.z.literal(0 /* V2 */), + reserve0: zCurrencyAmount, + reserve1: zCurrencyAmount +}).required(); +var zV3Pool = zod.z.object({ + type: zod.z.literal(1 /* V3 */), + token0: zCurrency, + token1: zCurrency, + fee: zFee, + liquidity: zBigNumber, + sqrtRatioX96: zBigNumber, + tick: zod.z.number(), + address: zAddress, + token0ProtocolFee: zod.z.string(), + token1ProtocolFee: zod.z.string(), + reserve0: zCurrencyAmountOptional, + reserve1: zCurrencyAmountOptional, + ticks: zod.z.array(zTick).optional() +}).required({ + type: true, + token0: true, + token1: true, + fee: true, + liquidity: true, + sqrtRatioX96: true, + tick: true, + address: true, + token0ProtocolFee: true, + token1ProtocolFee: true +}); +var zStablePool = zod.z.object({ + type: zod.z.literal(2 /* STABLE */), + balances: zod.z.array(zCurrencyAmount), + amplifier: zBigNumber, + fee: zod.z.string(), + address: zAddress +}).required(); +var zInfinityClPool = zod.z.object({ + type: zod.z.literal(3 /* InfinityCL */), + currency0: zCurrency, + currency1: zCurrency, + fee: zFee, + liquidity: zBigNumber, + sqrtRatioX96: zBigNumber, + tick: zod.z.number(), + tickSpacing: zod.z.number(), + poolManager: zAddress, + id: zHex +}).required().extend({ + protocolFee: zFee.optional(), + reserve0: zCurrencyAmountOptional, + reserve1: zCurrencyAmountOptional, + hooks: zAddress.optional(), + hooksRegistrationBitmap: zHooksRegistrationBitmap.optional(), + ticks: zod.z.array(zTick).optional() +}); +var zBinReserves = zod.z.object({ + reserveX: zBigNumber, + reserveY: zBigNumber +}).required(); +var zInfinityBinPool = zod.z.object({ + type: zod.z.literal(4 /* InfinityBIN */), + currency0: zCurrency, + currency1: zCurrency, + fee: zFee, + activeId: zod.z.number(), + binStep: zod.z.number(), + poolManager: zAddress, + id: zHex +}).required().extend({ + protocolFee: zFee.optional(), + reserve0: zCurrencyAmountOptional, + reserve1: zCurrencyAmountOptional, + hooks: zAddress.optional(), + hooksRegistrationBitmap: zHooksRegistrationBitmap.optional(), + reserveOfBin: zod.z.record(zBigNumber, zBinReserves).optional() +}); +var zInfinityStablePool = zod.z.object({ + type: zod.z.literal(5 /* InfinityStable */), + currency0: zCurrency, + currency1: zCurrency, + fee: zFee, + tickSpacing: zod.z.number(), + id: zHex, + poolManager: zAddress +}).required().extend({ + hooks: zAddress.optional(), + hooksRegistrationBitmap: zHooksRegistrationBitmap.optional(), + reserve0: zCurrencyAmountOptional, + reserve1: zCurrencyAmountOptional, + stableFee: zFee, + amplifier: zod.z.number() +}); +var zPools = zod.z.array( + zod.z.union([zV3Pool, zV2Pool, zStablePool, zInfinityClPool, zInfinityBinPool, zInfinityStablePool]) +); +var zRouterPostParams = zod.z.object({ + chainId: zChainId, + tradeType: zTradeType, + amount: zCurrencyAmount, + currency: zCurrency, + candidatePools: zPools, + gasPriceWei: zBigNumber.optional(), + maxHops: zod.z.number().optional(), + maxSplits: zod.z.number().optional() +}).required({ + chainId: true, + tradeType: true, + amount: true, + currency: true, + candidatePools: true +}); +function estimateGasCost({ pool, poolAfter }) { + if (isV2Pool(pool)) { + return chunkZNSTBYLO_js.BASE_SWAP_COST_V2; + } + if (isV3Pool(pool) && isV3Pool(poolAfter)) { + const { ticks, token0, tick } = pool; + invariant6__default.default(ticks !== void 0, "[Estimate gas]: No valid tick list found"); + const { tick: tickAfter } = poolAfter; + const { chainId } = token0; + const numOfTicksCrossed = v3Sdk.TickList.countInitializedTicksCrossed(ticks, tick, tickAfter); + const tickGasUse = chunkZNSTBYLO_js.COST_PER_INIT_TICK(chainId) * BigInt(numOfTicksCrossed); + return chunkZNSTBYLO_js.BASE_SWAP_COST_V3(chainId) + chunkZNSTBYLO_js.COST_PER_HOP_V3(chainId) + tickGasUse; + } + if (isStablePool(pool)) { + return chunkZNSTBYLO_js.BASE_SWAP_COST_STABLE_SWAP; + } + throw new Error("[Estimate gas]: Unknown pool type"); +} + +// evm/infinity-router/pool.ts +function getCurrencyPairs(p) { + if (isV3Pool(p)) { + return [[p.token0, p.token1]]; + } + if (isV2Pool(p)) { + return [[p.reserve0.currency, p.reserve1.currency]]; + } + if (isStablePool(p)) { + const currencies = p.balances.map((b) => b.currency); + const pairs = []; + for (let i = 0; i < currencies.length; i++) { + for (let j = i + 1; j < currencies.length; j++) { + pairs.push([currencies[i], currencies[j]]); + } + } + return pairs; + } + throw new Error("[Get currency pairs]: Unknown pool type"); +} +function getReserve(p, currency) { + if (isV3Pool(p)) { + return p.token0.equals(currency.wrapped) ? p.reserve0 : p.reserve1; + } + if (isV2Pool(p)) { + return p.reserve0.currency.wrapped.equals(currency.wrapped) ? p.reserve0 : p.reserve1; + } + if (isStablePool(p)) { + return p.balances.find((b) => b.currency.wrapped.equals(currency.wrapped)); + } + throw new Error("[Get reserve]: Unknown pool type"); +} + +// evm/infinity-router/utils/groupPoolsPyType.ts +function groupPoolsByType(pools) { + const poolsByType = /* @__PURE__ */ new Map(); + for (const pool of pools) { + poolsByType.set(pool.type, [...poolsByType.get(pool.type) || [], pool]); + } + return Array.from(poolsByType.values()); +} +function getBetterTrade(tradeA, tradeB) { + if (!tradeA && !tradeB) + return void 0; + if (!tradeA && tradeB) + return tradeB; + if (tradeA && !tradeB) + return tradeA; + const isExactIn = tradeA.tradeType === sdk.TradeType.EXACT_INPUT; + if (isExactIn) { + if (tradeB.outputAmountWithGasAdjusted.greaterThan(tradeA.outputAmountWithGasAdjusted)) { + return tradeB; + } + return tradeA; + } + if (tradeB.inputAmountWithGasAdjusted.lessThan(tradeA.inputAmountWithGasAdjusted)) { + return tradeB; + } + return tradeA; +} + +// evm/infinity-router/graph/edge.ts +function getNeighbour(e, v) { + return e.vertice0.currency.equals(v.currency) ? e.vertice1 : e.vertice0; +} +function createPriceCalculator({ graph, quote, gasPriceWei }) { + const { chainId } = quote.currency; + const priceMap = /* @__PURE__ */ new Map(); + const processedVert = /* @__PURE__ */ new Set(); + const edgeWeight = /* @__PURE__ */ new Map(); + let nextEdges = []; + const getWeight = (e) => { + const weight = edgeWeight.get(e); + if (weight === void 0) { + throw new Error(`Invalid weight for edge ${e}`); + } + return weight; + }; + priceMap.set(quote, new sdk.Price(quote.currency, quote.currency, 1, 1)); + nextEdges = getNextEdges(quote); + processedVert.add(quote); + while (nextEdges.length) { + const bestEdge = nextEdges.pop(); + const [vFrom, vTo] = processedVert.has(bestEdge.vertice1) ? [bestEdge.vertice1, bestEdge.vertice0] : [bestEdge.vertice0, bestEdge.vertice1]; + if (processedVert.has(vTo)) + continue; + const p = getTokenPrice(bestEdge.pool, vTo.currency, vFrom.currency); + const vFromQuotePrice = getQuotePrice(vFrom); + invariant6__default.default(vFromQuotePrice !== void 0, "Invalid quote price"); + priceMap.set(vTo, p.multiply(vFromQuotePrice)); + nextEdges = getNextEdges(vTo); + processedVert.add(vTo); + } + const native = sdk.Native.onChain(chainId).wrapped; + const nativeVertice = graph.getVertice(native); + if (!nativeVertice) { + throw new Error("No valid native currency price found"); + } + const nativePriceInQuote = getQuotePrice(nativeVertice); + const gasPriceInQuote = nativePriceInQuote?.quote(sdk.CurrencyAmount.fromRawAmount(native, gasPriceWei)); + if (!gasPriceInQuote) { + throw new Error("Failed to get gas price in quote"); + } + function getNextEdges(v) { + const price = priceMap.get(v); + if (!price) { + throw new Error("Invalid price"); + } + const newEdges = v.edges.filter((e) => { + if (processedVert.has(getNeighbour(e, v))) { + return false; + } + const tokenReserve = getReserve(e.pool, v.currency); + invariant6__default.default(tokenReserve !== void 0, "Unexpected empty token reserve"); + const liquidity = price.quote(tokenReserve).quotient; + edgeWeight.set(e, liquidity); + return true; + }); + newEdges.sort((e1, e2) => Number(getWeight(e1) - getWeight(e2))); + const res = []; + while (nextEdges.length && newEdges.length) { + if (getWeight(nextEdges[0]) < getWeight(newEdges[0])) { + res.push(nextEdges.shift()); + } else { + res.push(newEdges.shift()); + } + } + return [...res, ...nextEdges, ...newEdges]; + } + function getPrice(base, targetQuote) { + const basePrice = getQuotePrice(base); + const quotePrice = getQuotePrice(targetQuote); + return basePrice && quotePrice ? basePrice.multiply(quotePrice.invert()) : void 0; + } + function getQuotePrice(base) { + return priceMap.get(base); + } + function getGasPriceInBase(base) { + const basePrice = getQuotePrice(base); + return gasPriceInQuote ? basePrice?.invert().quote(gasPriceInQuote) : void 0; + } + return { + graph, + getGasPriceInBase, + getQuotePrice, + getPrice + }; +} + +// evm/infinity-router/graph/route.ts +function isSameRoute(one, another) { + if (one.pools.length !== another.pools.length) { + return false; + } + for (const [index, p] of one.pools.entries()) { + if (p.type !== another.pools[index].type) { + return false; + } + if (getPoolAddress(p) !== getPoolAddress(another.pools[index])) { + return false; + } + } + return true; +} +function mergeRoute(one, another) { + return { + ...one, + inputAmount: one.inputAmount.add(another.inputAmount), + outputAmount: one.outputAmount.add(another.outputAmount), + gasUseEstimateQuote: another.gasUseEstimateQuote ? one.gasUseEstimateQuote?.add(another.gasUseEstimateQuote) : one.gasUseEstimateQuote, + gasUseEstimate: one.gasUseEstimate + another.gasUseEstimate, + inputAmountWithGasAdjusted: another.inputAmountWithGasAdjusted ? one.inputAmountWithGasAdjusted?.add(another.inputAmountWithGasAdjusted) : one.inputAmountWithGasAdjusted, + outputAmountWithGasAdjusted: another.outputAmountWithGasAdjusted ? one.outputAmountWithGasAdjusted?.add(another.outputAmountWithGasAdjusted) : one.outputAmountWithGasAdjusted, + percent: one.percent + another.percent + }; +} + +// evm/infinity-router/graph/graph.ts +function getEdgeKey(p, vertA, vertB) { + const [vert0, vert1] = vertA.currency.wrapped.sortsBefore(vertB.currency.wrapped) ? [vertA, vertB] : [vertB, vertA]; + return `${vert0.currency.chainId}-${vert0.currency.wrapped.address}-${vert1.currency.wrapped.address}-${getPoolAddress(p)}`; +} +function cloneGraph(graph) { + const pools = graph.edges.map((e) => e.pool); + return createGraph({ pools }); +} +function createGraph({ pools, graph }) { + if (graph) { + return cloneGraph(graph); + } + if (!pools) { + throw new Error("[Create graph]: Invalid pools"); + } + const verticeMap = /* @__PURE__ */ new Map(); + const edgeMap = /* @__PURE__ */ new Map(); + for (const p of pools) { + const pairs = getCurrencyPairs(p); + for (const [currency0, currency1] of pairs) { + const vertice0 = createVertice(currency0); + const vertice1 = createVertice(currency1); + const edge = createEdge(p, vertice0, vertice1); + if (!vertice0.edges.includes(edge)) + vertice0.edges.push(edge); + if (!vertice1.edges.includes(edge)) + vertice1.edges.push(edge); + } + } + function getVertice(c) { + return verticeMap.get(c.wrapped.address); + } + function getEdge(p, vert0, vert1) { + return edgeMap.get(getEdgeKey(p, vert0, vert1)); + } + function createVertice(c) { + const vert = getVertice(c); + if (vert) { + return vert; + } + const vertice = { currency: c, edges: [] }; + verticeMap.set(c.wrapped.address, vertice); + return vertice; + } + function createEdge(p, vertice0, vertice1) { + const edgeKey = getEdgeKey(p, vertice0, vertice1); + if (!edgeKey) { + throw new Error(`Create edge failed. Cannot get valid edge key for ${p}`); + } + const e = edgeMap.get(edgeKey); + if (e) { + return e; + } + const edge = { + vertice0, + vertice1, + pool: p + }; + edgeMap.set(edgeKey, edge); + return edge; + } + const hasValidRouteToVerticeWithinHops = memoize( + (vertice, target, hops, visitedVertices) => { + if (vertice === target) { + return true; + } + if (hops <= 0) { + return false; + } + const visited = visitedVertices || /* @__PURE__ */ new Set(); + visited.add(vertice); + for (const edge of vertice.edges) { + const nextVertice = getNeighbour(edge, vertice); + if (nextVertice && !visited.has(nextVertice)) { + if (hasValidRouteToVerticeWithinHops(nextVertice, target, hops - 1, visited)) { + return true; + } + } + } + return false; + }, + (v1, v2, hops) => `${v1.currency.chainId}-${v1.currency.wrapped.address}-${v2.currency.wrapped.address}-${hops}` + ); + return { + vertices: Array.from(verticeMap.values()), + edges: Array.from(edgeMap.values()), + getVertice, + getEdge, + hasValidRouteToVerticeWithinHops, + applySwap: async ({ isExactIn, route }) => { + const getPoolQuote = createPoolQuoteGetter(isExactIn); + function* loopPools() { + let i = isExactIn ? 0 : route.pools.length - 1; + const getNext = () => isExactIn ? i + 1 : i - 1; + const hasNext = isExactIn ? () => i < route.pools.length : () => i >= 0; + for (; hasNext(); i = getNext()) { + yield i; + } + } + const amount = isExactIn ? route.inputAmount : route.outputAmount; + invariant6__default.default(amount !== void 0, "[Apply swap]: Invalid base amount"); + let quote = amount; + let gasCost = 0n; + for (const i of loopPools()) { + const vertA = getVertice(route.path[i]); + const vertB = getVertice(route.path[i + 1]); + const p = route.pools[i]; + invariant6__default.default( + vertA !== void 0 && vertB !== void 0 && p !== void 0, + "[Apply swap]: Invalid vertice and pool" + ); + const edge = getEdge(p, vertA, vertB); + invariant6__default.default(edge !== void 0, "[Apply swap]: No valid edge found"); + const quoteResult = await getPoolQuote(edge.pool, quote); + invariant6__default.default(quoteResult !== void 0, "[Apply swap]: Failed to get quote"); + edge.pool = quoteResult.poolAfter; + quote = quoteResult.quote; + gasCost += estimateGasCost(quoteResult); + } + return { + amount, + quote, + gasCost + }; + } + }; +} +function getStreamedAmounts(amount, streams) { + const streamSum = Array.isArray(streams) ? streams.reduce((sum3, s) => sum3 + s, 0) : streams; + const streamDistributions = Array.isArray(streams) ? streams.map((stream) => new sdk.Fraction(stream, streamSum)) : Array.from({ length: streams }).map(() => new sdk.Fraction(1, streamSum)); + const numOfStreams = streamDistributions.length; + let sum2 = new sdk.Fraction(0); + const amounts = []; + for (const [index, stream] of streamDistributions.entries()) { + const streamAmount = index === numOfStreams - 1 ? amount.subtract(amount.multiply(sum2)) : amount.multiply(stream); + const revisedStream = index === numOfStreams - 1 ? new sdk.Fraction(1).subtract(sum2) : stream; + const percent = Number(formatFraction(revisedStream) || 0) * 100; + amounts.push({ amount: streamAmount, percent }); + sum2 = sum2.add(stream); + } + return amounts; +} +var getGasCostInCurrency = ({ + priceCalculator, + gasCost, + currency +}) => { + const v = priceCalculator.graph.getVertice(currency); + const gasPriceInCurrency = v && priceCalculator.getGasPriceInBase(v); + const gasCostInCurrencyRaw = gasPriceInCurrency?.multiply(gasCost); + return sdk.CurrencyAmount.fromRawAmount(currency, gasCostInCurrencyRaw?.quotient || 0); +}; +async function findBestTrade(params) { + const { tradeType, candidatePools, ...rest } = params; + const isExactIn = tradeType === sdk.TradeType.EXACT_INPUT; + if (isExactIn) { + return getBestTrade(params); + } + const poolsByType = groupPoolsByType(candidatePools).filter((pools) => !isStablePool(pools[0])); + const trades = await Promise.allSettled( + poolsByType.map((pools) => getBestTrade({ tradeType, candidatePools: pools, ...rest })) + ); + let bestTrade; + for (const result of trades) { + if (result.status === "rejected") { + continue; + } + const { value: trade } = result; + if (!trade) { + continue; + } + if (!bestTrade) { + bestTrade = trade; + continue; + } + bestTrade = getBetterTrade(bestTrade, trade); + } + return bestTrade; +} +async function getBestTrade({ + amount: totalAmount, + candidatePools, + quoteCurrency, + gasPriceWei, + streams, + graph: graphOverride, + tradeType, + maxHops = 3 +}) { + const isExactIn = tradeType === sdk.TradeType.EXACT_INPUT; + const baseCurrency = totalAmount.currency; + const inputCurrency = isExactIn ? baseCurrency : quoteCurrency; + const outputCurrency = isExactIn ? quoteCurrency : baseCurrency; + const graph = graphOverride || createGraph({ pools: candidatePools }); + const amounts = getStreamedAmounts(totalAmount, streams); + const getPoolQuote = createPoolQuoteGetter(isExactIn); + const gasPrice = BigInt(typeof gasPriceWei === "function" ? await gasPriceWei() : gasPriceWei); + const start = graph.getVertice(baseCurrency); + const finish = graph.getVertice(quoteCurrency); + if (!start || !finish) { + throw new Error(`Invalid start vertice or finish vertice. Start ${start}, finish ${finish}`); + } + const priceCalculator = createPriceCalculator({ quote: start, gasPriceWei: gasPrice, graph }); + const adjustQuoteByGas = (quote, gasCostInQuote) => isExactIn ? quote.subtract(gasCostInQuote) : quote.add(gasCostInQuote); + const isQuoteBetter = (quote, compareTo) => isExactIn ? quote.greaterThan(compareTo) : quote.lessThan(compareTo); + const getInputAmount = (amount, quote) => isExactIn ? amount : quote; + const getOutputAmount = (amount, quote) => isExactIn ? quote : amount; + const getQuoteAmount = (r) => isExactIn ? r.outputAmount : r.inputAmount; + const buildTrade = (g, routes2) => { + const { + gasUseEstimate, + quoteAmount, + gasUseEstimateQuote, + gasUseEstimateBase, + inputAmountWithGasAdjusted, + outputAmountWithGasAdjusted + } = routes2.reduce( + (result, r) => { + return { + gasUseEstimate: result.gasUseEstimate + r.gasUseEstimate, + quoteAmount: result.quoteAmount.add(getQuoteAmount(r)), + gasUseEstimateBase: result.gasUseEstimateBase.add(r.gasUseEstimateBase), + gasUseEstimateQuote: result.gasUseEstimateQuote.add(r.gasUseEstimateQuote), + inputAmountWithGasAdjusted: result.inputAmountWithGasAdjusted.add(r.inputAmountWithGasAdjusted), + outputAmountWithGasAdjusted: result.outputAmountWithGasAdjusted.add(r.outputAmountWithGasAdjusted) + }; + }, + { + gasUseEstimate: 0n, + quoteAmount: sdk.CurrencyAmount.fromRawAmount(quoteCurrency, 0), + gasUseEstimateBase: sdk.CurrencyAmount.fromRawAmount(baseCurrency, 0), + gasUseEstimateQuote: sdk.CurrencyAmount.fromRawAmount(quoteCurrency, 0), + inputAmountWithGasAdjusted: sdk.CurrencyAmount.fromRawAmount(inputCurrency, 0), + outputAmountWithGasAdjusted: sdk.CurrencyAmount.fromRawAmount(outputCurrency, 0) + } + ); + return { + gasUseEstimate, + gasUseEstimateQuote, + gasUseEstimateBase, + inputAmountWithGasAdjusted, + outputAmountWithGasAdjusted, + inputAmount: getInputAmount(totalAmount, quoteAmount), + outputAmount: getOutputAmount(totalAmount, quoteAmount), + tradeType, + graph: g, + routes: routes2 + }; + }; + async function findBestRoute(amount) { + invariant6__default.default(start !== void 0 && finish !== void 0, "Invalid start/finish vertice"); + const bestResult = /* @__PURE__ */ new Map(); + const processedVert = /* @__PURE__ */ new Set(); + bestResult.set(start, { + hops: 0, + bestAmount: amount, + gasSpent: 0n + }); + const nextVertList = [start]; + const getHops = (vert) => bestResult.get(vert)?.hops || 0; + const getBestAmount = (vert) => bestResult.get(vert)?.bestAmount; + const getBestQuote = (vert) => bestResult.get(vert)?.bestQuote; + const getBestSource = (vert) => bestResult.get(vert)?.bestSource; + const getGasSpent = (vert) => bestResult.get(vert)?.gasSpent || 0n; + const getNextVert = () => { + let vert; + let bestQuote; + let bestVertIndex; + for (const [i, vertice] of nextVertList.entries()) { + const currentBestQuote = getBestQuote(vertice); + if (vert === void 0 || bestQuote === void 0 || currentBestQuote && isQuoteBetter(currentBestQuote, bestQuote)) { + vert = vertice; + bestQuote = currentBestQuote; + bestVertIndex = i; + } + } + return { vert, index: bestVertIndex }; + }; + const getBestRoute = (vert) => { + const pools = []; + const path = [vert.currency]; + for (let v = finish; getBestSource(v); v = getNeighbour(getBestSource(v), v)) { + const bestSource = getBestSource(v); + invariant6__default.default(bestSource !== void 0, "Invalid best source"); + const neighbour = getNeighbour(bestSource, v); + if (isExactIn) { + pools.unshift(bestSource.pool); + path.unshift(neighbour?.currency); + } else { + pools.push(bestSource.pool); + path.push(neighbour?.currency); + } + } + const gasCost = getGasSpent(vert); + const quoteAmountRaw = getBestAmount(vert); + invariant6__default.default(quoteAmountRaw !== void 0, "Invalid quote amount"); + const quoteAmount = sdk.CurrencyAmount.fromRawAmount(quoteCurrency, quoteAmountRaw.quotient); + const gasUseEstimateBase = getGasCostInCurrency({ priceCalculator, gasCost, currency: baseCurrency }); + const gasUseEstimateQuote = getGasCostInCurrency({ priceCalculator, gasCost, currency: quoteCurrency }); + const quoteAmountWithGasAdjusted = sdk.CurrencyAmount.fromRawAmount( + quoteCurrency, + gasUseEstimateQuote ? adjustQuoteByGas(quoteAmount, gasUseEstimateQuote).quotient : 0 + ); + const { type } = buildBaseRoute(pools, start.currency, finish.currency); + return { + type, + path, + pools, + gasUseEstimate: gasCost, + inputAmount: getInputAmount(amount, quoteAmount), + outputAmount: getOutputAmount(amount, quoteAmount), + inputAmountWithGasAdjusted: getInputAmount(amount, quoteAmountWithGasAdjusted), + outputAmountWithGasAdjusted: getOutputAmount(amount, quoteAmountWithGasAdjusted), + gasUseEstimateQuote, + gasUseEstimateBase + }; + }; + for (; ; ) { + const { vert, index } = getNextVert(); + if (!vert || index === void 0) + return void 0; + if (vert === finish) { + return getBestRoute(vert); + } + nextVertList.splice(index, 1); + const currentHop = getHops(vert); + for (const e of vert.edges) { + const v2 = vert === e.vertice0 ? e.vertice1 : e.vertice0; + if (processedVert.has(v2)) + continue; + if (!graph.hasValidRouteToVerticeWithinHops(v2, finish, maxHops - currentHop - 1)) { + continue; + } + try { + const bestAmount = getBestAmount(vert); + invariant6__default.default(bestAmount !== void 0, "Invalid amount"); + const quoteResult = await getPoolQuote(e.pool, bestAmount); + invariant6__default.default(quoteResult !== void 0, "Invalid quote result"); + const { quote } = quoteResult; + const gasPriceInV2 = priceCalculator.getGasPriceInBase(v2); + invariant6__default.default(gasPriceInV2 !== void 0, "Invalid gas price in v2"); + const gasSpent = estimateGasCost(quoteResult) + getGasSpent(vert); + const price = priceCalculator.getPrice(v2, finish); + invariant6__default.default( + price !== void 0, + `Failed to get price, base ${v2.currency.symbol}, quote ${finish.currency.symbol}` + ); + const gasSpentInQuote = price.quote(gasPriceInV2.multiply(gasSpent)); + const newQuote = adjustQuoteByGas(price.quote(quote), gasSpentInQuote); + const bestSource = getBestSource(v2); + const v2BestQuote = getBestQuote(v2); + if (!bestSource) + nextVertList.push(v2); + if (!bestSource || !v2BestQuote || isQuoteBetter(newQuote, v2BestQuote)) { + bestResult.set(v2, { + hops: currentHop + 1, + gasSpent, + bestAmount: quote, + bestSource: e, + bestQuote: newQuote + }); + } + } catch (_err) { + continue; + } + } + processedVert.add(vert); + } + } + let routeMerged = false; + const routes = []; + for (const { amount, percent } of amounts) { + const route = await findBestRoute(amount); + invariant6__default.default( + route !== void 0, + `No valid route found for base amount ${amount.toExact()} ${amount.currency.symbol} and quote currency ${quoteCurrency.symbol}` + ); + await graph.applySwap({ route, isExactIn }); + const newRoute = { + ...route, + percent + }; + const index = routes.findIndex((r) => isSameRoute(r, newRoute)); + if (index < 0) { + routes.push(newRoute); + } else { + routes[index] = mergeRoute(routes[index], newRoute); + routeMerged = true; + } + } + if (!routes.length) { + return void 0; + } + if (!routeMerged) { + return buildTrade(graph, routes); + } + const finalGraph = createGraph({ graph: graphOverride, pools: candidatePools }); + const s = finalGraph.getVertice(baseCurrency); + invariant6__default.default(s !== void 0, "[Graph rebuild]: Invalid start vertice"); + const pc = createPriceCalculator({ quote: s, gasPriceWei: gasPrice, graph: finalGraph }); + const finalRoutes = []; + for (const r of routes) { + const { amount, quote: quoteRaw, gasCost } = await finalGraph.applySwap({ isExactIn, route: r }); + const quote = sdk.CurrencyAmount.fromRawAmount(quoteCurrency, quoteRaw.quotient); + const gasUseEstimateBase = getGasCostInCurrency({ priceCalculator: pc, gasCost, currency: baseCurrency }); + const gasUseEstimateQuote = getGasCostInCurrency({ priceCalculator: pc, gasCost, currency: quoteCurrency }); + const quoteAmountWithGasAdjusted = sdk.CurrencyAmount.fromRawAmount( + quoteCurrency, + gasUseEstimateQuote ? adjustQuoteByGas(quote, gasUseEstimateQuote).quotient : 0 + ); + finalRoutes.push({ + ...r, + gasUseEstimate: gasCost, + inputAmount: getInputAmount(amount, quote), + outputAmount: getOutputAmount(amount, quote), + inputAmountWithGasAdjusted: getInputAmount(amount, quoteAmountWithGasAdjusted), + outputAmountWithGasAdjusted: getOutputAmount(amount, quoteAmountWithGasAdjusted), + gasUseEstimateQuote, + gasUseEstimateBase + }); + } + return buildTrade(finalGraph, finalRoutes); +} + +// evm/infinity-router/trade.ts +var DEFAULT_STREAM = 10; +function getBestStreamsConfig(trade) { + const maxStreams = 100; + if (!trade) { + return DEFAULT_STREAM; + } + const priceImpact = getPriceImpact(trade); + if (!priceImpact) { + return DEFAULT_STREAM; + } + const { gasUseEstimateBase, inputAmount, outputAmount } = trade; + if (!gasUseEstimateBase) { + return DEFAULT_STREAM; + } + const amount = trade.tradeType === sdk.TradeType.EXACT_INPUT ? inputAmount : outputAmount; + const bestFlowAmount = Math.sqrt( + Number(gasUseEstimateBase.toExact()) * Number(amount.toExact()) / Number(formatFraction(priceImpact.asFraction)) + ); + const streams = Math.round(Number(amount.toExact()) / bestFlowAmount); + if (!Number.isFinite(streams)) { + return DEFAULT_STREAM; + } + return Math.max(1, Math.min(streams, maxStreams)); +} +async function getBestTrade2(amount, quoteCurrency, tradeType, { candidatePools, gasPriceWei, maxHops, maxSplits }) { + const splitDisabled = maxSplits !== void 0 && maxSplits === 0; + let bestTrade; + try { + bestTrade = await findBestTrade({ + tradeType, + amount, + quoteCurrency, + gasPriceWei, + candidatePools, + maxHops, + streams: 1 + }); + } catch (e) { + if (splitDisabled) { + throw e; + } + bestTrade = await findBestTrade({ + tradeType, + amount, + quoteCurrency, + gasPriceWei, + candidatePools, + maxHops, + streams: DEFAULT_STREAM + }); + } + if (splitDisabled) { + return bestTrade; + } + const streams = getBestStreamsConfig(bestTrade); + if (streams === 1) { + return bestTrade; + } + const bestTradeWithStreams = await findBestTrade({ + tradeType, + amount, + quoteCurrency, + gasPriceWei, + candidatePools, + maxHops, + streams + }); + return getBetterTrade(bestTrade, bestTradeWithStreams); +} + +// evm/infinity-router/transformer.ts +var transformer_exports2 = {}; +chunkZNSTBYLO_js.__export(transformer_exports2, { + parseRoute: () => parseRoute2, + parseTrade: () => parseTrade2, + serializeRoute: () => serializeRoute2, + serializeTrade: () => serializeTrade2 +}); +function serializeRoute2(route) { + return { + ...route, + pools: route.pools.map(serializePool), + path: route.path.map(serializeCurrency), + inputAmount: serializeCurrencyAmount(route.inputAmount), + outputAmount: serializeCurrencyAmount(route.outputAmount), + gasUseEstimate: String(route.gasUseEstimate), + gasUseEstimateBase: serializeCurrencyAmount(route.gasUseEstimateBase), + gasUseEstimateQuote: serializeCurrencyAmount(route.gasUseEstimateQuote), + inputAmountWithGasAdjusted: serializeCurrencyAmount(route.inputAmountWithGasAdjusted), + outputAmountWithGasAdjusted: serializeCurrencyAmount(route.outputAmountWithGasAdjusted) + }; +} +function parseRoute2(chainId, route) { + return { + ...route, + pools: route.pools.map((p) => parsePool(chainId, p)), + path: route.path.map((c) => parseCurrency(chainId, c)), + inputAmount: parseCurrencyAmount(chainId, route.inputAmount), + outputAmount: parseCurrencyAmount(chainId, route.outputAmount), + gasUseEstimate: BigInt(route.gasUseEstimate), + gasUseEstimateBase: parseCurrencyAmount(chainId, route.gasUseEstimateBase), + gasUseEstimateQuote: parseCurrencyAmount(chainId, route.gasUseEstimateQuote), + inputAmountWithGasAdjusted: parseCurrencyAmount(chainId, route.inputAmountWithGasAdjusted), + outputAmountWithGasAdjusted: parseCurrencyAmount(chainId, route.outputAmountWithGasAdjusted) + }; +} +function serializeTrade2(trade) { + const { graph: _graph, ...rest } = trade; + return { + ...rest, + inputAmount: serializeCurrencyAmount(trade.inputAmount), + outputAmount: serializeCurrencyAmount(trade.outputAmount), + routes: trade.routes.map(serializeRoute2), + gasUseEstimate: trade.gasUseEstimate.toString(), + gasUseEstimateBase: serializeCurrencyAmount(trade.gasUseEstimateBase), + gasUseEstimateQuote: serializeCurrencyAmount(trade.gasUseEstimateQuote), + inputAmountWithGasAdjusted: serializeCurrencyAmount(trade.inputAmountWithGasAdjusted), + outputAmountWithGasAdjusted: serializeCurrencyAmount(trade.outputAmountWithGasAdjusted) + }; +} +function parseTrade2(chainId, trade) { + return { + ...trade, + tradeType: trade.tradeType, + inputAmount: parseCurrencyAmount(chainId, trade.inputAmount), + outputAmount: parseCurrencyAmount(chainId, trade.outputAmount), + routes: trade.routes.map((r) => parseRoute2(chainId, r)), + gasUseEstimate: trade.gasUseEstimate ? BigInt(trade.gasUseEstimate) : 0n, + gasUseEstimateBase: parseCurrencyAmount(chainId, trade.gasUseEstimateBase), + gasUseEstimateQuote: parseCurrencyAmount(chainId, trade.gasUseEstimateQuote), + inputAmountWithGasAdjusted: parseCurrencyAmount(chainId, trade.inputAmountWithGasAdjusted), + outputAmountWithGasAdjusted: parseCurrencyAmount(chainId, trade.outputAmountWithGasAdjusted) + }; +} +var SCOPE_PREFIX2 = "infinity-router"; +var SCOPE2 = { + metric: "metric", + log: "log", + error: "error" +}; +var log_2 = debug__default.default(SCOPE_PREFIX2); +var metric2 = log_2.extend(SCOPE2.metric); +var log3 = log_2.extend(SCOPE2.log); +var logger2 = { + metric: metric2, + log: log3, + error: debug__default.default(SCOPE_PREFIX2).extend(SCOPE2.error), + enable: (namespace) => { + let namespaces = namespace; + if (namespace.includes(",")) { + namespaces = namespace.split(",").map((ns) => `${SCOPE_PREFIX2}:${ns}`).join(","); + } else { + namespaces = `${SCOPE_PREFIX2}:${namespace}`; + } + debug__default.default.enable(namespaces); + } +}; + +// evm/v3-router/smartRouter.ts +var smartRouter_exports = {}; +chunkZNSTBYLO_js.__export(smartRouter_exports, { + APISchema: () => schema_exports2, + PancakeMulticallProvider: () => PancakeMulticallProvider, + Transformer: () => transformer_exports, + buildBaseRoute: () => buildBaseRoute, + createCommonTokenPriceProvider: () => createCommonTokenPriceProvider, + createGetV2CandidatePools: () => createGetV2CandidatePools, + createGetV3CandidatePools: () => createGetV3CandidatePools, + createGetV3CandidatePoolsWithFallbacks: () => createGetV3CandidatePools, + createHybridPoolProvider: () => createHybridPoolProvider, + createOffChainQuoteProvider: () => createOffChainQuoteProvider, + createOnChainPoolFactory: () => createOnChainPoolFactory, + createPoolProvider: () => createPoolProvider, + createPoolQuoteGetter: () => createPoolQuoteGetter, + createQuoteProvider: () => createQuoteProvider, + createStaticPoolProvider: () => createStaticPoolProvider, + createV2PoolsProviderByCommonTokenPrices: () => createV2PoolsProviderByCommonTokenPrices, + encodeInfinityRouteToPath: () => encodeInfinityRouteToPath, + encodeMixedRouteToPath: () => encodeMixedRouteToPath, + getAllV3PoolsFromSubgraph: () => getAllV3PoolsFromSubgraph, + getBestTrade: () => getBestTrade3, + getCandidatePools: () => getCandidatePools, + getCheckAgainstBaseTokens: () => getCheckAgainstBaseTokens, + getCommonTokenPrices: () => getCommonTokenPrices, + getCommonTokenPricesByLlma: () => getCommonTokenPricesByLlma, + getCommonTokenPricesBySubgraph: () => getCommonTokenPricesBySubgraph, + getCommonTokenPricesByWalletApi: () => getCommonTokenPricesByWalletApi, + getCurrenciesOfPool: () => getCurrenciesOfPool, + getExecutionPrice: () => getExecutionPrice, + getMidPrice: () => getMidPrice, + getOutputCurrency: () => getOutputCurrency, + getOutputOfPools: () => getOutputOfPools, + getPairCombinations: () => getPairCombinations, + getPoolAddress: () => getPoolAddress, + getPriceImpact: () => getPriceImpact, + getStableCandidatePools: () => getStableCandidatePools, + getStablePoolsOnChain: () => getStablePoolsOnChain, + getTokenUsdPricesBySubgraph: () => getTokenUsdPricesBySubgraph, + getV2CandidatePools: () => getV2CandidatePools, + getV2PoolSubgraph: () => getV2PoolSubgraph, + getV2PoolsOnChain: () => getV2PoolsOnChain, + getV2PoolsWithTvlByCommonTokenPrices: () => getV2PoolsWithTvlByCommonTokenPrices, + getV3CandidatePools: () => getV3CandidatePools, + getV3PoolSubgraph: () => getV3PoolSubgraph, + getV3PoolsWithTvlFromOnChain: () => getV3PoolsWithTvlFromOnChain, + getV3PoolsWithTvlFromOnChainFallback: () => getV3PoolsWithTvlFromOnChainFallback, + getV3PoolsWithTvlFromOnChainStaticFallback: () => getV3PoolsWithTvlFromOnChainStaticFallback, + getV3PoolsWithoutTicksOnChain: () => getV3PoolsWithoutTicksOnChain, + infinityPoolTvlSelector: () => infinityPoolTvlSelector, + involvesCurrency: () => involvesCurrency, + isInfinityBinPool: () => isInfinityBinPool, + isInfinityClPool: () => isInfinityClPool, + isInfinityStablePool: () => isInfinityStablePool, + isMMPool: () => isMMPool, + isStablePool: () => isStablePool, + isV2Pool: () => isV2Pool, + isV3Pool: () => isV3Pool, + log: () => log, + logger: () => logger, + maximumAmountIn: () => maximumAmountIn, + metric: () => metric, + minimumAmountOut: () => minimumAmountOut, + partitionMixedRouteByProtocol: () => partitionMixedRouteByProtocol, + v2PoolSubgraphSelection: () => v2PoolTvlSelector, + v2PoolTvlSelector: () => v2PoolTvlSelector, + v3PoolSubgraphSelection: () => v3PoolTvlSelector, + v3PoolTvlSelector: () => v3PoolTvlSelector, + v3PoolsOnChainProviderFactory: () => v3PoolsOnChainProviderFactory +}); + +// ../utils/Graph.ts +var Graph = class { + constructor(getVertexKey) { + this.adjacencyMap = /* @__PURE__ */ new Map(); + this.vertexMap = /* @__PURE__ */ new Map(); + this.getVertexKey = getVertexKey; + } + addVertex(vertex) { + const key = this.getVertexKey(vertex); + if (!this.adjacencyMap.has(key)) { + this.adjacencyMap.set(key, []); + this.vertexMap.set(key, vertex); + } + } + addEdge(from, to, edge, cost = 1) { + this.addVertex(from); + this.addVertex(to); + const fromKey = this.getVertexKey(from); + const neighbors = this.adjacencyMap.get(fromKey); + const existingNeighbor = neighbors.find((n) => this.getVertexKey(n.node) === this.getVertexKey(to)); + if (existingNeighbor) { + existingNeighbor.edges.push({ edge, cost }); + } else { + neighbors.push({ + node: to, + edges: [{ edge, cost }] + }); + } + } + findPaths(from, to, type = "dijkstra", maxHops = Infinity) { + switch (type) { + case "dijkstra": + return this.dijkstra(from, to, maxHops); + case "dfs": + return this.dfsAllPaths(from, to, maxHops); + default: + throw new Error(`Unsupported algorithm type: ${type}`); + } + } + dfsAllPaths(from, to, maxHops) { + const fromKey = this.getVertexKey(from); + const toKey = this.getVertexKey(to); + const results = []; + const visited = /* @__PURE__ */ new Set(); + const dfs = (currentKey, path, edges, cost) => { + if (path.length > maxHops + 1) + return; + if (currentKey === toKey) { + results.push({ + path: path.map((key) => this.vertexMap.get(key)), + edges: [...edges], + totalCost: cost + }); + return; + } + visited.add(currentKey); + const neighbors = this.adjacencyMap.get(currentKey) || []; + for (const neighbor of neighbors) { + const neighborKey = this.getVertexKey(neighbor.node); + if (!visited.has(neighborKey)) { + for (const { edge, cost: edgeCost } of neighbor.edges) { + dfs(neighborKey, [...path, neighborKey], [...edges, edge], cost + edgeCost); + } + } + } + visited.delete(currentKey); + }; + dfs(fromKey, [fromKey], [], 0); + return results; + } + dijkstra(from, to, maxHops) { + const fromKey = this.getVertexKey(from); + const toKey = this.getVertexKey(to); + const bestCost = /* @__PURE__ */ new Map(); + const queue = [{ vertexKey: fromKey, cost: 0, path: [fromKey], edges: [] }]; + const results = []; + while (queue.length > 0) { + queue.sort((a, b) => a.cost - b.cost); + const current = queue.shift(); + if ((bestCost.get(current.vertexKey) ?? Infinity) < current.cost) + continue; + bestCost.set(current.vertexKey, current.cost); + if (current.vertexKey === toKey && current.path.length <= maxHops + 1) { + results.push(current); + continue; + } + if (current.path.length > maxHops + 1) + continue; + const neighbors = this.adjacencyMap.get(current.vertexKey) || []; + for (const neighbor of neighbors) { + const neighborKey = this.getVertexKey(neighbor.node); + for (const { edge, cost } of neighbor.edges) { + const newCost = current.cost + cost; + if ((bestCost.get(neighborKey) ?? Infinity) > newCost) { + queue.push({ + vertexKey: neighborKey, + cost: newCost, + path: [...current.path, neighborKey], + edges: [...current.edges, edge] + }); + } + } + } + } + return results.map((res) => ({ + path: res.path.map((key) => this.vertexMap.get(key)), + edges: res.edges, + totalCost: res.cost + })); + } +}; + +// evm/v3-router/functions/computeAllRoutesNew.ts +function computeAllRoutesNew(input, output, candidatePools, maxHops = 3, quoteId) { + const logger3 = RemoteLogger.getLogger(quoteId); + logger3.metric(`computeAllRoutesNew`, 1); + const graph = new Graph((c) => c.wrapped.address); + candidatePools.forEach((pool) => { + const currencies = getCurrenciesOfPool(pool); + const tokenA = currencies[0]; + const tokenB = currencies[1]; + graph.addEdge(tokenA, tokenB, pool); + graph.addEdge(tokenB, tokenA, pool); + logger3.debug(`add pool ${poolInfoStr(pool)}`); + }); + const paths = graph.findPaths(input, output, "dfs", maxHops); + const routes = paths.map(({ edges }) => buildBaseRoute(edges, input, output)); + logger3.metric(`route find`, 1); + return routes; +} +function getTokenPriceByNumber(baseCurrency, quoteCurrency, price) { + const quoteAmount = tryParseAmount_default(String(price), baseCurrency); + const baseAmount = tryParseAmount_default("1", quoteCurrency); + if (!baseAmount || !quoteAmount) { + return void 0; + } + return new sdk.Price({ baseAmount, quoteAmount }); +} +async function createGasModel({ + gasPriceWei, + poolProvider, + quoteCurrency, + blockNumber, + quoteCurrencyUsdPrice, + nativeCurrencyUsdPrice +}) { + const { chainId } = quoteCurrency; + const usdToken = getUsdGasToken(chainId); + if (!usdToken) { + throw new Error(`No valid usd token found on chain ${chainId}`); + } + const gasAccounting = getGasAccountingToken(chainId); + if (!gasAccounting) { + throw new Error(`Unsupported chain ${chainId}. No gas accounting token found.`); + } + const { token: nativeWrappedToken, nativeDecimals } = gasAccounting; + const gasPrice = BigInt(typeof gasPriceWei === "function" ? await gasPriceWei() : gasPriceWei); + const [usdPool, nativePool] = await Promise.all([ + getHighestLiquidityUSDPool(poolProvider, chainId, blockNumber), + getHighestLiquidityNativePool(poolProvider, quoteCurrency, blockNumber) + ]); + const priceInUsd = quoteCurrencyUsdPrice ? getTokenPriceByNumber(usdToken, quoteCurrency, quoteCurrencyUsdPrice) : void 0; + const nativePriceInUsd = nativeCurrencyUsdPrice ? getTokenPriceByNumber(usdToken, nativeWrappedToken, nativeCurrencyUsdPrice) : void 0; + const priceInNative = priceInUsd && nativePriceInUsd ? nativePriceInUsd.multiply(priceInUsd.invert()) : void 0; + const estimateGasCost2 = ({ pools }, { initializedTickCrossedList }) => { + const isQuoteNative = nativeWrappedToken.equals(quoteCurrency.wrapped); + const totalInitializedTicksCrossed = BigInt(Math.max(1, sum__default.default(initializedTickCrossedList))); + const poolTypeSet = /* @__PURE__ */ new Set(); + let baseGasUse = 0n; + for (const pool of pools) { + const { type } = pool; + if (isV2Pool(pool)) { + if (!poolTypeSet.has(type)) { + baseGasUse += chunkZNSTBYLO_js.BASE_SWAP_COST_V2; + poolTypeSet.add(type); + continue; + } + baseGasUse += chunkZNSTBYLO_js.COST_PER_EXTRA_HOP_V2; + continue; + } + if (isV3Pool(pool)) { + if (!poolTypeSet.has(type)) { + baseGasUse += chunkZNSTBYLO_js.BASE_SWAP_COST_V3(chainId); + poolTypeSet.add(type); + } + baseGasUse += chunkZNSTBYLO_js.COST_PER_HOP_V3(chainId); + continue; + } + if (isStablePool(pool) || isInfinityStablePool(pool)) { + if (!poolTypeSet.has(type)) { + baseGasUse += chunkZNSTBYLO_js.BASE_SWAP_COST_STABLE_SWAP; + poolTypeSet.add(type); + continue; + } + baseGasUse += chunkZNSTBYLO_js.COST_PER_EXTRA_HOP_STABLE_SWAP; + continue; + } + } + const tickGasUse = chunkZNSTBYLO_js.COST_PER_INIT_TICK(chainId) * totalInitializedTicksCrossed; + const uninitializedTickGasUse = chunkZNSTBYLO_js.COST_PER_UNINIT_TICK * 0n; + baseGasUse = baseGasUse + tickGasUse + uninitializedTickGasUse; + const baseGasCostWei = gasPrice * baseGasUse; + const totalGasCostNativeCurrency = sdk.CurrencyAmount.fromRawAmount( + nativeWrappedToken, + rescaleRawAmount(baseGasCostWei, nativeDecimals, nativeWrappedToken.decimals) + ); + let gasCostInToken = sdk.CurrencyAmount.fromRawAmount(quoteCurrency.wrapped, 0); + let gasCostInUSD = sdk.CurrencyAmount.fromRawAmount(usdToken, 0); + try { + if (isQuoteNative) { + gasCostInToken = totalGasCostNativeCurrency; + } + if (!isQuoteNative) { + const price = priceInNative || nativePool && getTokenPrice(nativePool, nativeWrappedToken, quoteCurrency.wrapped); + if (price) { + gasCostInToken = price.quote(totalGasCostNativeCurrency); + } + } + const nativeTokenUsdPrice = nativePriceInUsd || usdPool && getTokenPrice(usdPool, nativeWrappedToken, usdToken); + if (nativeTokenUsdPrice) { + gasCostInUSD = nativeTokenUsdPrice.quote(totalGasCostNativeCurrency); + } + } catch (e) { + } + return { + gasEstimate: baseGasUse, + gasCostInToken: isQuoteNative && quoteCurrency.isNative ? sdk.CurrencyAmount.fromRawAmount(sdk.Native.onChain(chainId), gasCostInToken.quotient) : gasCostInToken, + gasCostInUSD + }; + }; + return { + estimateGasCost: estimateGasCost2 + }; +} +async function getHighestLiquidityNativePool(poolProvider, currency, blockNumber) { + const nativeWrappedToken = getGasAccountingToken(currency.chainId)?.token; + if (!nativeWrappedToken || currency.wrapped.equals(nativeWrappedToken)) { + return null; + } + const pools = await poolProvider.getCandidatePools({ + blockNumber, + pairs: [[nativeWrappedToken, currency]], + currencyA: nativeWrappedToken, + currencyB: currency + }); + return pools[0] ?? null; +} +async function getHighestLiquidityUSDPool(poolProvider, chainId, blockNumber) { + const usdToken = getUsdGasToken(chainId); + const nativeWrappedToken = getGasAccountingToken(chainId)?.token; + if (!usdToken || !nativeWrappedToken) { + return null; + } + const pools = await poolProvider.getCandidatePools({ + blockNumber, + pairs: [[nativeWrappedToken, usdToken]], + currencyA: nativeWrappedToken, + currencyB: usdToken + }); + return pools[0] ?? null; +} + +// ../utils/chunk.ts +function chunk(array, size) { + if (size <= 0) + throw new Error("Chunk size must be greater than 0"); + const result = []; + for (let i = 0; i < array.length; i += size) { + result.push(array.slice(i, i + size)); + } + return result; +} + +// evm/v3-router/getRoutesWithValidQuote.ts +async function getRoutesWithValidQuote({ + amount, + baseRoutes, + distributionPercent = 5, + quoteProvider, + tradeType, + blockNumber, + gasModel, + quoterOptimization = true, + signal, + quoteId +}) { + const logger3 = RemoteLogger.getLogger(quoteId); + logger3.debug("run getRoutesWithValidQuote"); + const [percents, amounts] = getAmountDistribution(amount, distributionPercent); + const routesWithoutQuote = amounts.reduce( + (acc, curAmount, i) => [ + ...acc, + ...baseRoutes.map((r) => ({ + ...r, + amount: curAmount, + percent: percents[i] + })) + ], + [] + ); + logger3.debug(`quote calls=${routesWithoutQuote.length}`, 2); + for (const route of routesWithoutQuote) { + logger3.debug( + `quote call, ${route.percent}% ${route.pools.map((x) => getPoolAddress(x)).join(",")} ${route.input.symbol} ${route.output.symbol} ${route.amount.quotient}`, + 3 + ); + } + const getRoutesWithQuote = tradeType === sdk.TradeType.EXACT_INPUT ? quoteProvider.getRouteWithQuotesExactIn : quoteProvider.getRouteWithQuotesExactOut; + if (!quoterOptimization) { + return getRoutesWithQuote(routesWithoutQuote, { blockNumber, gasModel, signal, quoteId }); + } + logger3.debug("via quote optimization", 2); + const requestCallback = typeof window === "undefined" ? setTimeout : window.requestIdleCallback || window.setTimeout; + logger3.debug(`Get quotes from ${routesWithoutQuote.length} routes routesWithoutQuote`, 2); + const getQuotes = (routes) => new Promise((resolve, reject) => { + requestCallback(async () => { + try { + const result2 = await getRoutesWithQuote(routes, { blockNumber, gasModel, signal }); + resolve(result2); + } catch (e) { + reject(e); + } + }); + }); + const chunks = chunk(routesWithoutQuote, 10); + const result = await Promise.all(chunks.map(getQuotes)); + const quotes = result.reduce((acc, cur) => { + acc.push(...cur); + return acc; + }, []); + logger3.debug(`Get quotes success, got, ${quotes.length}`); + return quotes; +} + +// evm/v3-router/getBestTrade.ts +async function getBestTrade3(amount, currency, tradeType, config) { + const logger3 = RemoteLogger.getLogger(config.quoteId); + logger3.debug( + `[SmartRouter] getBestTrade ${config.quoteId}, [${sdk.TradeType[tradeType]}] input=${amount.toExact()} ${currency.symbol} maxSplits=${config.maxSplits} maxHops=${config.maxHops}` + ); + try { + const { blockNumber: blockNumberFromConfig } = config; + const blockNumber = typeof blockNumberFromConfig === "function" ? await blockNumberFromConfig() : blockNumberFromConfig; + const bestRoutes = await getBestRoutes( + amount, + currency, + tradeType, + { + ...config, + blockNumber + }, + config.quoteId + ); + if (!bestRoutes || bestRoutes.outputAmount.equalTo(sdk.ZERO)) { + logger3.debug("No valid route found"); + throw new Error("Cannot find a valid swap route"); + } + const { routes, gasEstimateInUSD, gasEstimate, inputAmount, outputAmount } = bestRoutes; + const trade = { + tradeType, + routes, + gasEstimate, + gasEstimateInUSD, + inputAmount, + outputAmount, + blockNumber + }; + logger3.debug(`find trade`); + return trade; + } catch (ex) { + logger3.debug(`Error in getBestTrade ${ex}`); + throw ex; + } finally { + logger3.flush(); + } +} +async function getBestRoutes(amount, currency, tradeType, routeConfig, quoteId) { + const { chainId } = currency; + const { + maxHops = 3, + maxSplits = 4, + distributionPercent: _distributionPercent = 5, + poolProvider, + quoteProvider, + blockNumber, + gasPriceWei, + allowedPoolTypes, + quoterOptimization, + quoteCurrencyUsdPrice, + nativeCurrencyUsdPrice, + signal + } = { + ...routeConfig, + ...ROUTE_CONFIG_BY_CHAIN[chainId] || {} + }; + const distributionPercent = maxSplits ? _distributionPercent : 100; + const logger3 = RemoteLogger.getLogger(quoteId); + const isExactIn = tradeType === sdk.TradeType.EXACT_INPUT; + const inputCurrency = isExactIn ? amount.currency : currency; + const outputCurrency = isExactIn ? currency : amount.currency; + const candidatePools = await poolProvider?.getCandidatePools({ + currencyA: amount.currency, + currencyB: currency, + blockNumber, + protocols: allowedPoolTypes, + signal + }); + logger3.debug( + `Candidate pools: ${candidatePools.length}, maxSplits=${maxSplits}, maxHops=${maxHops}, distributionPercent=${distributionPercent}` + ); + logPools(quoteId, candidatePools, 2); + let baseRoutes = computeAllRoutesNew(inputCurrency, outputCurrency, candidatePools, maxHops, quoteId); + if (tradeType === sdk.TradeType.EXACT_OUTPUT) { + baseRoutes = baseRoutes.filter(({ type }) => type !== 3 /* MIXED */); + } + logger3.debug(`Discovered ${baseRoutes.length} Base routes, maxShow = 10`); + logRoutes(quoteId, baseRoutes.slice(0, 10), 2); + const gasModel = await createGasModel({ + gasPriceWei, + poolProvider, + quoteCurrency: currency, + blockNumber, + quoteCurrencyUsdPrice, + nativeCurrencyUsdPrice + }); + const routesWithValidQuote = await getRoutesWithValidQuote({ + amount, + baseRoutes, + distributionPercent, + quoteProvider, + tradeType, + blockNumber, + gasModel, + quoterOptimization, + quoteId, + signal + }); + logger3.debug(`valid route=${routesWithValidQuote.length}, maxShow=100`); + return getBestRouteCombinationByQuotes(amount, currency, routesWithValidQuote, tradeType, { maxSplits }, quoteId); +} + +// evm/v3-router/schema.ts +var schema_exports2 = {}; +chunkZNSTBYLO_js.__export(schema_exports2, { + zPools: () => zPools2, + zRouterGetParams: () => zRouterGetParams, + zRouterPostParams: () => zRouterPostParams2 +}); +var zChainId2 = zod.z.nativeEnum(chains.ChainId); +var zFee2 = zod.z.number(); +var zTradeType2 = zod.z.nativeEnum(sdk.TradeType); +var zPoolType = zod.z.nativeEnum(PoolType); +var zPoolTypes = zod.z.array(zPoolType); +var zAddress2 = zod.z.custom((val) => /^0x[a-fA-F0-9]{40}$/.test(val)); +var zHex2 = zod.z.custom((val) => /^0x[a-fA-F0-9]*$/.test(val)); +var zHooksRegistrationBitmap2 = zod.z.number().or(zHex2); +var zBigNumber2 = zod.z.string().regex(/^[0-9]+$/); +var zCurrency2 = zod.z.object({ + address: zAddress2, + decimals: zod.z.number(), + symbol: zod.z.string() +}).required(); +var zCurrencyAmount2 = zod.z.object({ + currency: zCurrency2.required(), + value: zBigNumber2 +}).required(); +var zCurrencyAmountOptional2 = zCurrencyAmount2.optional(); +var zV2Pool2 = zod.z.object({ + type: zod.z.literal(0 /* V2 */), + reserve0: zCurrencyAmount2, + reserve1: zCurrencyAmount2 +}).required(); +var zV3Pool2 = zod.z.object({ + type: zod.z.literal(1 /* V3 */), + token0: zCurrency2, + token1: zCurrency2, + fee: zFee2, + liquidity: zBigNumber2, + sqrtRatioX96: zBigNumber2, + tick: zod.z.number(), + address: zAddress2, + token0ProtocolFee: zod.z.string(), + token1ProtocolFee: zod.z.string() +}).required(); +var zStablePool2 = zod.z.object({ + type: zod.z.literal(2 /* STABLE */), + balances: zod.z.array(zCurrencyAmount2), + amplifier: zBigNumber2, + fee: zod.z.string(), + address: zAddress2 +}).required(); +var zInfinityClPool2 = zod.z.object({ + type: zod.z.literal(3 /* InfinityCL */), + currency0: zCurrency2, + currency1: zCurrency2, + fee: zFee2, + liquidity: zBigNumber2, + sqrtRatioX96: zBigNumber2, + tick: zod.z.number(), + tickSpacing: zod.z.number(), + poolManager: zAddress2, + id: zHex2 +}).required().extend({ + protocolFee: zFee2.optional(), + hooks: zAddress2.optional(), + hooksRegistrationBitmap: zHooksRegistrationBitmap2.optional() +}); +var zInfinityBinPool2 = zod.z.object({ + type: zod.z.literal(4 /* InfinityBIN */), + currency0: zCurrency2, + currency1: zCurrency2, + fee: zFee2, + activeId: zod.z.number(), + binStep: zod.z.number(), + poolManager: zAddress2, + id: zHex2 +}).required().extend({ + protocolFee: zFee2.optional(), + hooks: zAddress2.optional(), + hooksRegistrationBitmap: zHooksRegistrationBitmap2.optional() +}); +var zInfinityStablePool2 = zod.z.object({ + type: zod.z.literal(5 /* InfinityStable */), + currency0: zCurrency2, + currency1: zCurrency2, + fee: zFee2, + tickSpacing: zod.z.number(), + id: zHex2, + poolManager: zAddress2 +}).required().extend({ + hooks: zAddress2.optional(), + hooksRegistrationBitmap: zHooksRegistrationBitmap2.optional(), + reserve0: zCurrencyAmountOptional2, + reserve1: zCurrencyAmountOptional2, + stableFee: zFee2, + amplifier: zod.z.number() +}); +var zPools2 = zod.z.array( + zod.z.union([zV2Pool2, zV3Pool2, zStablePool2, zInfinityClPool2, zInfinityBinPool2, zInfinityStablePool2]) +); +var zRouterGetParams = zod.z.object({ + chainId: zChainId2, + tradeType: zTradeType2, + amount: zCurrencyAmount2, + currency: zCurrency2, + gasPriceWei: zBigNumber2.optional(), + maxHops: zod.z.number().optional(), + maxSplits: zod.z.number().optional(), + blockNumber: zBigNumber2.optional(), + poolTypes: zPoolTypes.optional(), + candidatePools: zPools2 +}).required({ + chainId: true, + tradeType: true, + amount: true, + currency: true, + candidatePools: true +}); +var zRouterPostParams2 = zod.z.object({ + chainId: zChainId2, + tradeType: zTradeType2, + amount: zCurrencyAmount2, + currency: zCurrency2, + candidatePools: zPools2, + gasPriceWei: zBigNumber2.optional(), + maxHops: zod.z.number().optional(), + maxSplits: zod.z.number().optional(), + blockNumber: zBigNumber2.optional(), + poolTypes: zPoolTypes.optional(), + onChainQuoterGasLimit: zBigNumber2.optional(), + nativeCurrencyUsdPrice: zod.z.number().optional(), + quoteCurrencyUsdPrice: zod.z.number().optional(), + account: zAddress2.optional() +}).required({ + chainId: true, + tradeType: true, + amount: true, + currency: true, + candidatePools: true +}); + +Object.defineProperty(exports, 'ADDITIONAL_BASES', { + enumerable: true, + get: function () { return chunkZNSTBYLO_js.ADDITIONAL_BASES; } +}); +Object.defineProperty(exports, 'ADDRESS_THIS', { + enumerable: true, + get: function () { return chunkZNSTBYLO_js.ADDRESS_THIS; } +}); +Object.defineProperty(exports, 'BASES_TO_CHECK_TRADES_AGAINST', { + enumerable: true, + get: function () { return chunkZNSTBYLO_js.BASES_TO_CHECK_TRADES_AGAINST; } +}); +Object.defineProperty(exports, 'BASE_SWAP_COST_STABLE_SWAP', { + enumerable: true, + get: function () { return chunkZNSTBYLO_js.BASE_SWAP_COST_STABLE_SWAP; } +}); +Object.defineProperty(exports, 'BASE_SWAP_COST_V2', { + enumerable: true, + get: function () { return chunkZNSTBYLO_js.BASE_SWAP_COST_V2; } +}); +Object.defineProperty(exports, 'BASE_SWAP_COST_V3', { + enumerable: true, + get: function () { return chunkZNSTBYLO_js.BASE_SWAP_COST_V3; } +}); +Object.defineProperty(exports, 'BATCH_MULTICALL_CONFIGS', { + enumerable: true, + get: function () { return chunkZNSTBYLO_js.BATCH_MULTICALL_CONFIGS; } +}); +Object.defineProperty(exports, 'BETTER_TRADE_LESS_HOPS_THRESHOLD', { + enumerable: true, + get: function () { return chunkZNSTBYLO_js.BETTER_TRADE_LESS_HOPS_THRESHOLD; } +}); +Object.defineProperty(exports, 'BIG_INT_TEN', { + enumerable: true, + get: function () { return chunkZNSTBYLO_js.BIG_INT_TEN; } +}); +Object.defineProperty(exports, 'BIN_HOOK_PRESETS_BY_CHAIN', { + enumerable: true, + get: function () { return chunkZNSTBYLO_js.BIN_HOOK_PRESETS_BY_CHAIN; } +}); +Object.defineProperty(exports, 'BIN_PRESETS_BY_CHAIN', { + enumerable: true, + get: function () { return chunkZNSTBYLO_js.BIN_PRESETS_BY_CHAIN; } +}); +Object.defineProperty(exports, 'BIPS_BASE', { + enumerable: true, + get: function () { return chunkZNSTBYLO_js.BIPS_BASE; } +}); +Object.defineProperty(exports, 'CL_HOOK_PRESETS_BY_CHAIN', { + enumerable: true, + get: function () { return chunkZNSTBYLO_js.CL_HOOK_PRESETS_BY_CHAIN; } +}); +Object.defineProperty(exports, 'CL_PRESETS', { + enumerable: true, + get: function () { return chunkZNSTBYLO_js.CL_PRESETS; } +}); +Object.defineProperty(exports, 'CL_PRESETS_BY_CHAIN', { + enumerable: true, + get: function () { return chunkZNSTBYLO_js.CL_PRESETS_BY_CHAIN; } +}); +Object.defineProperty(exports, 'COST_PER_EXTRA_HOP_STABLE_SWAP', { + enumerable: true, + get: function () { return chunkZNSTBYLO_js.COST_PER_EXTRA_HOP_STABLE_SWAP; } +}); +Object.defineProperty(exports, 'COST_PER_EXTRA_HOP_V2', { + enumerable: true, + get: function () { return chunkZNSTBYLO_js.COST_PER_EXTRA_HOP_V2; } +}); +Object.defineProperty(exports, 'COST_PER_HOP_V3', { + enumerable: true, + get: function () { return chunkZNSTBYLO_js.COST_PER_HOP_V3; } +}); +Object.defineProperty(exports, 'COST_PER_INIT_TICK', { + enumerable: true, + get: function () { return chunkZNSTBYLO_js.COST_PER_INIT_TICK; } +}); +Object.defineProperty(exports, 'COST_PER_UNINIT_TICK', { + enumerable: true, + get: function () { return chunkZNSTBYLO_js.COST_PER_UNINIT_TICK; } +}); +Object.defineProperty(exports, 'CUSTOM_BASES', { + enumerable: true, + get: function () { return chunkZNSTBYLO_js.CUSTOM_BASES; } +}); +Object.defineProperty(exports, 'EMPTY_HOOK', { + enumerable: true, + get: function () { return chunkZNSTBYLO_js.EMPTY_HOOK; } +}); +Object.defineProperty(exports, 'InfinityFeeTier', { + enumerable: true, + get: function () { return chunkZNSTBYLO_js.InfinityFeeTier; } +}); +Object.defineProperty(exports, 'MIN_BNB', { + enumerable: true, + get: function () { return chunkZNSTBYLO_js.MIN_BNB; } +}); +Object.defineProperty(exports, 'MIXED_ROUTE_QUOTER_ADDRESSES', { + enumerable: true, + get: function () { return chunkZNSTBYLO_js.MIXED_ROUTE_QUOTER_ADDRESSES; } +}); +Object.defineProperty(exports, 'MSG_SENDER', { + enumerable: true, + get: function () { return chunkZNSTBYLO_js.MSG_SENDER; } +}); +Object.defineProperty(exports, 'SMART_ROUTER_ADDRESSES', { + enumerable: true, + get: function () { return chunkZNSTBYLO_js.SMART_ROUTER_ADDRESSES; } +}); +Object.defineProperty(exports, 'STABLE_SWAP_INFO_ADDRESS', { + enumerable: true, + get: function () { return chunkZNSTBYLO_js.STABLE_SWAP_INFO_ADDRESS; } +}); +Object.defineProperty(exports, 'TICK_QUERY_HELPER_ADDRESSES', { + enumerable: true, + get: function () { return chunkZNSTBYLO_js.TICK_QUERY_HELPER_ADDRESSES; } +}); +Object.defineProperty(exports, 'V2_FEE_PATH_PLACEHOLDER', { + enumerable: true, + get: function () { return chunkZNSTBYLO_js.V2_FEE_PATH_PLACEHOLDER; } +}); +Object.defineProperty(exports, 'V2_ROUTER_ADDRESS', { + enumerable: true, + get: function () { return chunkZNSTBYLO_js.V2_ROUTER_ADDRESS; } +}); +Object.defineProperty(exports, 'V3_QUOTER_ADDRESSES', { + enumerable: true, + get: function () { return chunkZNSTBYLO_js.V3_QUOTER_ADDRESSES; } +}); +Object.defineProperty(exports, 'V3_TICK_LENS_ADDRESSES', { + enumerable: true, + get: function () { return chunkZNSTBYLO_js.V3_TICK_LENS_ADDRESSES; } +}); +Object.defineProperty(exports, 'usdGasTokensByChain', { + enumerable: true, + get: function () { return chunkZNSTBYLO_js.usdGasTokensByChain; } +}); +exports.InfinityMixedQuoterActions = InfinityMixedQuoterActions; +exports.InfinityRouter = infinity_router_exports; +exports.PoolType = PoolType; +exports.RouteType = RouteType; +exports.SmartRouter = smartRouter_exports; +exports.SwapRouter = SwapRouter; +exports.Transformer = transformer_exports; +exports.feeOnTransferDetectorAddresses = feeOnTransferDetectorAddresses; +exports.fetchTickLensTicksInRange = fetchTickLensTicksInRange; +exports.fetchTokenFeeOnTransfer = fetchTokenFeeOnTransfer; +exports.fetchTokenFeeOnTransferBatch = fetchTokenFeeOnTransferBatch; +exports.getPoolAddress = getPoolAddress; +exports.getRouteTypeByPools = getRouteTypeByPools; +exports.getTokenPrice = getTokenPrice; diff --git a/plan/agw/research/preset-catalog-2026-10-15/protocol-sources.json b/plan/agw/research/preset-catalog-2026-10-15/protocol-sources.json new file mode 100644 index 00000000..fa803d04 --- /dev/null +++ b/plan/agw/research/preset-catalog-2026-10-15/protocol-sources.json @@ -0,0 +1,67 @@ +[ + { + "url": "https://raw.githubusercontent.com/Uniswap/sdks/main/sdks/sdk-core/src/addresses.ts", + "file": "addresses.ts", + "bytes": 34373 + }, + { + "url": "https://raw.githubusercontent.com/Uniswap/swap-router-contracts/main/contracts/interfaces/IV3SwapRouter.sol", + "file": "IV3SwapRouter.sol", + "bytes": 3104 + }, + { + "url": "https://raw.githubusercontent.com/pancakeswap/pancake-developer/master/docs/pages/contracts/v3/addresses.md", + "file": "addresses.md", + "bytes": 5240 + }, + { + "url": "https://raw.githubusercontent.com/bgd-labs/aave-address-book/main/src/AaveV3Sepolia.sol", + "file": "AaveV3Sepolia.sol", + "bytes": 14061 + }, + { + "url": "https://raw.githubusercontent.com/bgd-labs/aave-address-book/main/src/AaveV3BaseSepolia.sol", + "file": "AaveV3BaseSepolia.sol", + "bytes": 12139 + }, + { + "url": "https://raw.githubusercontent.com/bgd-labs/aave-address-book/main/src/AaveV3ArbitrumSepolia.sol", + "file": "AaveV3ArbitrumSepolia.sol", + "bytes": 6099 + }, + { + "url": "https://raw.githubusercontent.com/aave-dao/aave-v3-origin/main/src/contracts/interfaces/IPool.sol", + "file": "IPool.sol", + "bytes": 36349 + }, + { + "url": "https://raw.githubusercontent.com/moonwell-fi/moonwell-contracts-v2/main/chains/84532.json", + "file": "84532.json", + "bytes": 5954 + }, + { + "url": "https://raw.githubusercontent.com/moonwell-fi/moonwell-contracts-v2/main/src/MToken.sol", + "file": "MToken.sol", + "bytes": 79960 + }, + { + "url": "https://raw.githubusercontent.com/VenusProtocol/venus-protocol/develop/deployments/bsctestnet_addresses.json", + "file": "bsctestnet_addresses.json", + "bytes": 25480 + }, + { + "url": "https://raw.githubusercontent.com/VenusProtocol/venus-protocol/develop/contracts/Tokens/VTokens/VBep20.sol", + "file": "VBep20.sol", + "bytes": 12891 + }, + { + "url": "https://raw.githubusercontent.com/Layr-Labs/eigenlayer-contracts/main/README.md", + "file": "README.md", + "bytes": 61045 + }, + { + "url": "https://raw.githubusercontent.com/bnb-chain/bsc-genesis-contract/master/contracts/StakeHub.sol", + "file": "StakeHub.sol", + "bytes": 53484 + } +] diff --git a/plan/agw/research/preset-catalog-2026-10-15/rpc-verification.json b/plan/agw/research/preset-catalog-2026-10-15/rpc-verification.json new file mode 100644 index 00000000..d2ccbbb2 --- /dev/null +++ b/plan/agw/research/preset-catalog-2026-10-15/rpc-verification.json @@ -0,0 +1,148 @@ +[ + { + "chain": "eip155:11155111", + "block": "11917113", + "contracts": [ + { + "name": "uniswap", + "address": "0x3bFA4769FB09eefC5a80d6E87c3B9C650f7Ae48E", + "bytes": 24497, + "codeHash": "0xe7f98ee73dfe6d5c96cbf8936920f496b1b82f24326d6a415b4144a2252271de" + }, + { + "name": "aave", + "address": "0x6Ae43d3271ff6888e7Fc43Fd7321a503ff738951", + "bytes": 2333, + "codeHash": "0xdfd31513a60cc252ec0bbcf0e7bdb7f9ba35fab80c1bb9ce0543436b8fe92e49", + "reserves": [ + "0xFF34B3d4Aee8ddCd6F9AFFFB6Fe49bD371b8a357", + "0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5", + "0x94a9D9AC8a22534E3FaCa9F4e7F2E2cf85d5E4C8", + "0x29f2D40B0605204364af54EC677bD022dA425d03", + "0xC558DBdd856501FCd9aaF1E62eae57A9F0629a3c", + "0xaA8E23Fb1079EA71e0a56F48a2aA51851D8433D0", + "0x88541670E55cC00bEEFD87eB59EDd1b7C511AC9a", + "0x6d906e526a4e2Ca02097BA9d0caA3c382F52278E", + "0xc4bF5CbDaBE595361438F8c6a187bDc330539c60" + ] + }, + { + "name": "eigen", + "address": "0x2E3D6c0744b10eb0A4e6F679F71554a39Ec47a5D", + "bytes": 2115, + "codeHash": "0x54a3a9ef2209a3bc2f00d3ca72d5b987776a6cb8db96acefb244610d08de0174", + "paused": "0" + } + ], + "actualChainId": 11155111 + }, + { + "chain": "eip155:84532", + "block": "48129503", + "contracts": [ + { + "name": "uniswap", + "address": "0x94cC0AaC535CCDB3C01d6787D6413C739ae12bc4", + "bytes": 24497, + "codeHash": "0x60e9352f5af4eee63b41456f85bf80c63044e98123ad599d41d87f2d068de0be" + }, + { + "name": "aave", + "address": "0x8bAB6d1b75f19e9eD9fCe8b9BD338844fF79aE27", + "bytes": 1853, + "codeHash": "0xc97b7e16966b0eafd8bc9eebf8937ee34f1bf0f3d3907d978dedc6148811b0f5", + "reserves": [ + "0xba50Cd2A20f6DA35D788639E581bca8d0B5d4D5f", + "0x0a215D8ba66387DCA84B284D18c3B4ec3de6E54a", + "0x54114591963CF60EF3aA63bEfD6eC263D98145a4", + "0x4200000000000000000000000000000000000006", + "0xD171b9694f7A2597Ed006D41f7509aaD4B485c4B", + "0x810D46F9a9027E28F9B01F75E2bdde839dA61115" + ] + }, + { + "name": "moonwellUSDBC", + "address": "0x876852425331a113d8E432eFFB3aC5BEf38f033a", + "bytes": 7261, + "codeHash": "0x2efdd202d2faf3c6f2e7fcae24b7b42a8ccc39b34691a8817e8765d33d79d569", + "underlying": "0x4616975f7E6045FD9737e95bC527e9e14c727BD2" + }, + { + "name": "moonwellWETH", + "address": "0x2F39a349A79492a70E152760ce7123A1933eCf28", + "bytes": 7261, + "codeHash": "0x2efdd202d2faf3c6f2e7fcae24b7b42a8ccc39b34691a8817e8765d33d79d569", + "underlying": "0x663A6F02d547dFd639BF689FED298712f2FB69Fb" + }, + { + "name": "comptroller", + "address": "0xC72ba45f2Ae134F21DAEb2b7B5fd5De0064Ee9bB", + "bytes": 1391, + "codeHash": "0xe0cfbdabe281c5e3cba2e1670f2f18c96ae98d9c942a5df487200278a79ee40c" + } + ], + "actualChainId": 84532 + }, + { + "chain": "eip155:421614", + "block": "319263861", + "contracts": [ + { + "name": "uniswap", + "address": "0x101F443B4d1b059569D643917553c771E1b9663E", + "bytes": 24497, + "codeHash": "0xb7f0bed5258473e73513f604660efed135a05124470796b6b9fec9ca12e22367" + }, + { + "name": "aave", + "address": "0xBfC91D59fdAA134A4ED45f7B584cAf96D7792Eff", + "bytes": 1892, + "codeHash": "0xd75b4365d675956c42b20584bb92e557c2a0cd1b692d8c0c2b4fea848bc9a44e", + "reserves": [ + "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "0x1dF462e2712496373A347f8ad10802a5E95f053D" + ] + } + ], + "actualChainId": 421614 + }, + { + "chain": "eip155:97", + "block": "136845129", + "contracts": [ + { + "name": "pancake", + "address": "0x9a489505a00cE272eAa5e07Dba6491314CaE3796", + "bytes": 24316, + "codeHash": "0xb1f063c41d7b1ea99d1d2e4f85bb1ca6e655ec0f028e0d5c41a3338884e169d4" + }, + { + "name": "venusUSDT", + "address": "0xb7526572FFE56AB9D7489838Bf2E18e3323b441A", + "bytes": 4744, + "codeHash": "0x064370ceee002fe570b8800e8f1b69231a6448667dc40f65e58047778d408813", + "underlying": "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c" + }, + { + "name": "venusUSDC", + "address": "0xD5C4C2e2facBEB59D0216D0595d63FcDc6F9A1a7", + "bytes": 4744, + "codeHash": "0x064370ceee002fe570b8800e8f1b69231a6448667dc40f65e58047778d408813", + "underlying": "0x16227D60f7a0e586C66B005219dfc887D13C9531" + }, + { + "name": "comptroller", + "address": "0x94d1820b2D1c7c7452A163983Dc888CEC546b77D", + "bytes": 1508, + "codeHash": "0x4b4e586288eed4781d5ccd0ff329746c38ed2c4bfd4472c1986f5bf663ad0ba0" + }, + { + "name": "stakeHub", + "address": "0x0000000000000000000000000000000000002002", + "bytes": 47087, + "codeHash": "0xdd27dda318f66bdc14973b8a35e7681ead1c1f75228696c2e75f0483bd6ecc64" + } + ], + "actualChainId": 97 + } +] diff --git a/plan/agw/research/preset-catalog-2026-10-15/source.json b/plan/agw/research/preset-catalog-2026-10-15/source.json new file mode 100644 index 00000000..9338136d --- /dev/null +++ b/plan/agw/research/preset-catalog-2026-10-15/source.json @@ -0,0 +1,7 @@ +{ + "url": "https://app.notion.com/p/pushprotocol/AGW-Presets-proposal-and-rules-3f8188aea7f48020a9f0d10ea5325467", + "observed_edit": "2026-10-13 20:57 IST", + "author": "Aman Gupta", + "sha256": "bdbf56ceaad6a46cc7f71286e2094cd698b671a7e1fa77acac121a3587e4a4f4", + "scope": "testnet only, user confirmed" +} diff --git a/plan/agw/source-manifest.json b/plan/agw/source-manifest.json index 0b3c6a10..deae120d 100644 --- a/plan/agw/source-manifest.json +++ b/plan/agw/source-manifest.json @@ -174,6 +174,17 @@ "pulled_at": "2026-10-07T10:27:18.466408+00:00", "archive": "notion/exports/20261007T102718466408Z/export-4.zip", "export_entry": "Private & Shared/agentic_wallet_flow ( updated ) 3d1188aea7f4801f9cb3fbd9318ec536.md" + }, + { + "title": "AGW Presets proposal and rules", + "page_id": "3f8188aea7f48020a9f0d10ea5325467", + "notion_url": "https://app.notion.com/p/pushprotocol/AGW-Presets-proposal-and-rules-3f8188aea7f48020a9f0d10ea5325467", + "local_file": "notion/agw-presets-proposal-and-rules.md", + "pulled_on": "2026-10-15", + "observed_last_edited_date": "2026-10-13", + "authority": "Preset proposal; testnet-only scope confirmed by user", + "sha256": "bdbf56ceaad6a46cc7f71286e2094cd698b671a7e1fa77acac121a3587e4a4f4", + "archive": "research/preset-catalog-2026-10-15/notion-export.zip" } ], "last_refresh_at": "2026-10-07T10:27:18.466408+00:00", From 26d4eb8db62b96226591499b221582f8a5cfd169 Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Thu, 15 Oct 2026 07:22:59 +0530 Subject: [PATCH 39/68] fix(core): return safe AGW preset review templates --- packages/core/AGW.md | 8 +- .../core/__agw-local__/v5-multiasset.spec.ts | 37 ++++++++++ .../agentic/__tests__/preset-catalog.spec.ts | 73 ++++++++++++++++--- .../src/lib/agentic/__tests__/presets.spec.ts | 2 +- .../core/src/lib/agentic/presets/catalog.ts | 2 +- .../core/src/lib/agentic/presets/index.ts | 32 +++++++- .../core/src/lib/agentic/presets/types.ts | 2 + 7 files changed, 138 insertions(+), 18 deletions(-) diff --git a/packages/core/AGW.md b/packages/core/AGW.md index cb3106d7..af3cd914 100644 --- a/packages/core/AGW.md +++ b/packages/core/AGW.md @@ -177,6 +177,10 @@ The wire encoder uses uint32 maximum for unlimited native calls and 255 for unsp ```ts const { presets } = PushChain.utils.agentic.presets.list({ type: 'CATEGORY' }); const availablePresets = presets.filter(preset => preset.chains.length > 0); +const { rules: reviewTemplates } = PushChain.utils.agentic.presets.get( + PushChain.CONSTANTS.AGENTIC.PRESETS.CATEGORY.DEXES, +); +// Choose tokens in the review UI, then call get again as below. function filledPreset(agent: Address, tokenIn: Address, tokenOut: Address) { return PushChain.utils.agentic.presets.get( @@ -197,7 +201,9 @@ function filledPreset(agent: Address, tokenIn: Address, tokenOut: Address) { 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. 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. Omitted asset caps and `maxGasPerCall` default to zero. -DEX templates require explicit ERC20 tokens for each selected chain. They expand ordered token pairs into exact-input and exact-output calls with token, wallet-recipient and input-amount pins. Missing tokens, 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]`. +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. + +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]`. 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. diff --git a/packages/core/__agw-local__/v5-multiasset.spec.ts b/packages/core/__agw-local__/v5-multiasset.spec.ts index 36a33b9b..57290f61 100644 --- a/packages/core/__agw-local__/v5-multiasset.spec.ts +++ b/packages/core/__agw-local__/v5-multiasset.spec.ts @@ -296,6 +296,43 @@ describe('v6 multi-asset SDK management and execution', () => { }); }); + it.each(['exactInputSingle', 'exactOutputSingle'] as const)( + 'a review-only DEX %s call cannot spend tokens even after asset budgets are filled', + async (functionName) => { + const preview = agenticPresets.get('DEXES', { chainNamespace: CHAIN_NS }) + .rules[0]; + const { agent } = await setup({ + ...preview, + agent: h.wallets[1].account!.address, + validUntil: Math.floor(Date.now() / 1000) + 3600, + maxGasPerCall: BigInt(10) ** BigInt(16), + assets: [{ token: a, maxPerCall: BigInt(5), maxTotal: BigInt(20) }], + }); + const router = preview.allowedCalls[0].target as Address; + const abi = parseAbi([ + `function ${functionName}((address,address,uint24,address,uint256,uint256,uint160))`, + ]); + await expect( + agent.universal.sendTransaction({ + to: { address: router, chain: CHAIN_NS }, + data: [ + { + to: router, + value: BigInt(0), + data: encodeFunctionData({ + abi, + functionName, + args: [[a, b, 3000, CEA, BigInt(1), BigInt(1), BigInt(0)]], + }), + }, + ], + }) + ).rejects.toMatchObject({ + decodedError: { name: 'PolicyCheckReverted(ArgPinAboveMax)' }, + }); + } + ); + it('a fixture preset produces rules accepted by public create and enforced by real contracts', async () => { const presets = buildPresetApi([ { diff --git a/packages/core/src/lib/agentic/__tests__/preset-catalog.spec.ts b/packages/core/src/lib/agentic/__tests__/preset-catalog.spec.ts index 8e28e839..c93bc2bd 100644 --- a/packages/core/src/lib/agentic/__tests__/preset-catalog.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/preset-catalog.spec.ts @@ -1,10 +1,4 @@ -import { - encodeFunctionData, - parseAbi, - getAddress, - type Address, - type Hex, -} from 'viem'; +import { encodeFunctionData, parseAbi, getAddress, type Address } from 'viem'; import { agenticPresets } from '../presets'; import { AGENTIC } from '../constants'; import { evmPinOffset, normalizePublicRule, publicRules } from '../public-rule'; @@ -45,10 +39,7 @@ it('expands both token directions and exact-input/output with wallet and amount rules[0].allowedCalls.reduce((n, c) => n + (c.pins?.length ?? 0), 0) ).toBe(20); }); -it('rejects native-token markers, omitted tokens and oversized pin expansion', () => { - expect(() => agenticPresets.get('DEXES', { ...input, assets: [] })).toThrow( - /two explicit/ - ); +it('rejects native-token markers and oversized pin expansion', () => { expect(() => agenticPresets.get('DEXES', { ...input, @@ -196,3 +187,63 @@ it('mutating a returned tuple path cannot change a later preset', () => { agenticPresets.get('DEXES', input).rules[0].allowedCalls[0].pins![0].arg ).toEqual([0, 0]); }); + +it('returns one zero-input-cap review template per chain without options', () => { + const { rules } = agenticPresets.get('DEXES'); + expect(rules.map((r) => r.chainNamespace)).toEqual( + agenticPresets.list().presets.find((p) => p.constant === 'DEXES')!.chains + ); + for (const rule of rules) { + expect(rule).not.toHaveProperty('agent'); + expect(rule).not.toHaveProperty('validUntil'); + expect(rule).not.toHaveProperty('assets'); + expect(rule.allowedCalls).toHaveLength(2); + rule.allowedCalls.forEach((call, i) => { + expect(call.pins).toEqual([ + { arg: [0, 3], expected: AGENTIC.WALLET }, + { arg: [0, i === 0 ? 4 : 5], max: BigInt(0) }, + ]); + expect(call.label).toContain('select two tokens'); + }); + } +}); +it('keeps single-token swaps disabled and generates approvals only for the supplied asset', () => { + const rule = agenticPresets.get('DEXES', { + ...input, + assets: [input.assets![0]], + }).rules[0]; + expect(rule.assets).toEqual([input.assets![0]]); + expect(rule.allowedCalls).toHaveLength(3); + for (const call of rule.allowedCalls.slice(0, 2)) { + expect(call.pins).toContainEqual({ arg: [0, 0], expected: tokenA }); + expect(call.pins?.at(-1)?.max).toBe(BigInt(0)); + } + expect(rule.allowedCalls[2].selector).toBe('approve(address,uint256)'); + expect(rule.allowedCalls[2].target).toBe(tokenA); +}); +it('keeps chains without supplied assets discoverable and regenerates complete pairs without disabled alternatives', () => { + const { rules } = agenticPresets.get('DEXES', { + assets: input.assets!.map((a) => ({ ...a, chainNamespace: chain })), + }); + expect(rules).toHaveLength(4); + expect( + rules.find((r) => r.chainNamespace === chain)?.allowedCalls + ).toHaveLength(6); + for (const r of rules.filter((r) => r.chainNamespace !== chain)) { + expect(r.assets).toEqual([]); + expect(r.allowedCalls).toHaveLength(2); + expect(r.allowedCalls.every((c) => c.pins?.at(-1)?.max === BigInt(0))).toBe( + true + ); + } + const preview = agenticPresets.get('DEXES', { + chainNamespace: chain, + assets: [], + }).rules[0]; + const ready = agenticPresets.get('DEXES', input).rules[0]; + expect(preview.allowedCalls).toHaveLength(2); + expect(ready.allowedCalls).toHaveLength(6); + expect( + ready.allowedCalls.every((c) => !c.label?.includes('select two tokens')) + ).toBe(true); +}); diff --git a/packages/core/src/lib/agentic/__tests__/presets.spec.ts b/packages/core/src/lib/agentic/__tests__/presets.spec.ts index da6f3e98..6a8d7595 100644 --- a/packages/core/src/lib/agentic/__tests__/presets.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/presets.spec.ts @@ -72,7 +72,7 @@ it('ships only verified testnet catalog entries and keeps prediction empty', () ) ).toBe(true); expect(agenticPresets.get('PREDICTION')).toEqual({ rules: [] }); - expect(() => agenticPresets.get('DEXES')).toThrow(/two explicit ERC20/); + expect(agenticPresets.get('DEXES').rules).toHaveLength(4); expect(() => agenticPresets.get('LENDING', { chainNamespace: 'eip155:1' }) ).toThrow(/no approved entry/); diff --git a/packages/core/src/lib/agentic/presets/catalog.ts b/packages/core/src/lib/agentic/presets/catalog.ts index 31e26546..9c7c1ebf 100644 --- a/packages/core/src/lib/agentic/presets/catalog.ts +++ b/packages/core/src/lib/agentic/presets/catalog.ts @@ -6,7 +6,7 @@ import type { PresetCategory } from './types'; export interface PresetChainDefinition { chainNamespace: ForeignChainNamespace; allowedCalls: readonly RuleCall[]; - /** Static single-hop routers; calls are expanded only for the supplied token pairs. */ + /** Static single-hop routers; incomplete pairs return zero-input-cap review calls. */ swapRouters?: readonly { address: Address; app: string }[]; /** Exact spenders that need an approval for each non-native supplied asset. */ approvals?: readonly { spender: Address; app: string; token?: Address }[]; diff --git a/packages/core/src/lib/agentic/presets/index.ts b/packages/core/src/lib/agentic/presets/index.ts index 0b1d521f..61c5ce4b 100644 --- a/packages/core/src/lib/agentic/presets/index.ts +++ b/packages/core/src/lib/agentic/presets/index.ts @@ -165,10 +165,6 @@ export function buildPresetApi( const calls = chain.allowedCalls.map(copyCall); if (chain.swapRouters?.length) { const tokens = assets.get(chain.chainNamespace) ?? []; - if (tokens.length < 2) - throw invalid( - 'DEX presets require at least two explicit ERC20 assets per selected chain; select one chain or supply assets for every chain' - ); if ( tokens.some( (a) => @@ -179,6 +175,34 @@ export function buildPresetApi( throw invalid( 'DEX token pins require explicit ERC20 addresses; use wrapped-native tokens instead of the native marker' ); + // Keep discovery useful before a swap pair is selected. These review + // calls cannot spend input tokens: the amount maximum is explicitly zero. + // Re-run get with both tokens to generate the executable pair pins. + if (tokens.length < 2) + for (const router of chain.swapRouters) + for (const exactInput of [true, false]) + calls.push({ + target: router.address, + selector: `${ + exactInput ? 'exactInputSingle' : 'exactOutputSingle' + }((address,address,uint24,address,uint256,uint256,uint160))`, + pins: [ + ...(tokens.length + ? [ + { + arg: [0, 0], + expected: getAddress(tokenAddress(tokens[0].token)), + }, + ] + : []), + { arg: [0, 3], expected: 'agentic:wallet' }, + { arg: [0, exactInput ? 4 : 5], max: BigInt(0) }, + ], + app: router.app, + label: `${ + exactInput ? 'Swap exact input' : 'Swap exact output' + } (select two tokens to enable)`, + }); for (const router of chain.swapRouters) for (const input of tokens) for (const output of tokens) { diff --git a/packages/core/src/lib/agentic/presets/types.ts b/packages/core/src/lib/agentic/presets/types.ts index ec0e82bb..d7c88642 100644 --- a/packages/core/src/lib/agentic/presets/types.ts +++ b/packages/core/src/lib/agentic/presets/types.ts @@ -26,6 +26,8 @@ export interface PresetOptions { chainNamespace?: ForeignChainNamespace; agent?: Address; validUntil?: number; + /** DEX swaps with fewer than two tokens are zero-input-cap review templates. + * Call get again with a complete pair to generate token pins and amount limits. */ assets?: PresetAsset[]; } export interface ReadyPresetOptions extends PresetOptions { From 0e40221567a16b26b123f1440d6ccb025803ed39 Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Thu, 15 Oct 2026 07:23:37 +0530 Subject: [PATCH 40/68] docs(agw): record approved preset review flow --- .../implementation-status.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/plan/agw/research/preset-catalog-2026-10-15/implementation-status.md b/plan/agw/research/preset-catalog-2026-10-15/implementation-status.md index 2760287b..aa9667c2 100644 --- a/plan/agw/research/preset-catalog-2026-10-15/implementation-status.md +++ b/plan/agw/research/preset-catalog-2026-10-15/implementation-status.md @@ -10,7 +10,9 @@ User scope: testnet templates only. Missing caps default to zero. Source body an - Static tuple/fixed-array argument paths; exact decoded word-offset roundtrips remain supported. - Explicit optional maxGasPerCall; omitted caps remain zero. -DEX token omission is rejected rather than granting unrestricted swaps. This follows the conservative assumption stated during implementation; the optional follow-up question had no answer. Two supplied tokens fit; larger expansions exceeding 32 pins fail explicitly. +Section 7 alignment follow-up: the user approved zero-cap review templates followed by regeneration with selected tokens. DEX get now accepts omitted assets, empty lists and a single token. Each incomplete chain returns full-signature calls with a wallet-recipient pin and an explicit zero swap-input cap. A single token also gets an input-token pin and its bounded spender approval. Call get again with two tokens to generate the complete input/output pins; filling rule.assets alone does not enable swaps. Chains without supplied tokens remain visible when no chain filter is set. Two supplied tokens fit; larger expansions exceeding 32 pins fail explicitly. + +The SDK page still needs editorial synchronization for this approved two-stage flow, omitted caps defaulting to zero, the catalog's STAKING category, and tuple paths such as [0,3]. These are documentation differences, not outstanding contract changes. This follow-up does not edit the remote Notion page. ## Exclusions and limits @@ -33,3 +35,10 @@ Protocol sources and rpc-verification.json record official addresses, signatures - Targeted real-v6 contract suite: 14 passed, including generated DEX permissions, invalid recipient/token/amount rejection and get-to-update roundtrip. Gateway is a local recording fixture; destination protocols are not executed. - Library, unit and local-harness TypeScript checks passed. - No funded protocol transactions or mainnet broadcasts performed for this catalog. + +## Section 7 follow-up validation + +- 35 focused preset unit tests passed. +- 16 real-v6 local contract tests passed. Both exact-input and exact-output review calls reject positive input amounts after adding asset budgets, proving the zero swap-input maximum is enforced by URP. +- No destination protocol trade or new live-network transaction was run for this follow-up. +- Remaining catalog expansion: excluded/unverified protocols, Solana templates requiring additional capabilities, and actual destination-protocol trade acceptance. These do not block the implemented review UI flow. From b2aa959ae7d5ff67d37675161061bd6d185d630d Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Thu, 15 Oct 2026 07:44:07 +0530 Subject: [PATCH 41/68] feat(core): add mainnet AGW presets and live protocol coverage --- packages/core/AGW.md | 17 +- .../core/__e2e__/agw/presets-live.spec.ts | 453 ++++++++++++++++++ packages/core/__e2e__/ci/suite.ts | 17 + .../agentic/__tests__/preset-catalog.spec.ts | 53 +- .../src/lib/agentic/__tests__/presets.spec.ts | 18 +- .../core/src/lib/agentic/presets/catalog.ts | 158 +++++- 6 files changed, 701 insertions(+), 15 deletions(-) create mode 100644 packages/core/__e2e__/agw/presets-live.spec.ts diff --git a/packages/core/AGW.md b/packages/core/AGW.md index af3cd914..772201aa 100644 --- a/packages/core/AGW.md +++ b/packages/core/AGW.md @@ -167,11 +167,11 @@ The wire encoder uses uint32 maximum for unlimited native calls and 255 for unsp ## Preset discovery and templates (section 7) -`PushChain.utils.agentic` contains `presets.list/get`. The categories are `AGENTIC.PRESETS.CATEGORY.DEXES`, `LENDING`, `STAKING` and `PREDICTION`. The catalog ships testnet templates only: +`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: -- DEXES: Uniswap V3 on Sepolia, Base Sepolia and Arbitrum Sepolia; PancakeSwap V3 on BSC testnet. -- LENDING: Aave on the three Ethereum testnets above, Moonwell on Base Sepolia and Venus on BSC testnet. -- STAKING: EigenLayer deposits on Sepolia; withdrawals are not included. +- DEXES: Uniswap V3 on Ethereum, Base and Arbitrum (mainnet and their Sepolia testnets); PancakeSwap V3 on BNB mainnet and BSC testnet. +- 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. +- STAKING: EigenLayer deposits on Ethereum mainnet and Sepolia (EigenLayer withdrawals excluded); Lido stake, wrap/unwrap and withdrawal requests/claims on Ethereum mainnet. Lido ETH staking defaults to `maxValue: 0`; explicitly set a value cap before use. - PREDICTION: no entries yet. Hide categories with empty `chains` lists. ```ts @@ -207,8 +207,15 @@ With two ERC20 tokens, `get` expands ordered pairs into exact-input and exact-ou 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. -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. No mainnet templates, dynamic-path swaps, Solana protocol templates or unconfirmed deployments ship in this catalog. Local policy tests do not execute the destination protocols. +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. ## Validation 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. + + +### Live preset acceptance + +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. + +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. diff --git a/packages/core/__e2e__/agw/presets-live.spec.ts b/packages/core/__e2e__/agw/presets-live.spec.ts new file mode 100644 index 00000000..d0567d5d --- /dev/null +++ b/packages/core/__e2e__/agw/presets-live.spec.ts @@ -0,0 +1,453 @@ +/** Real Donut -> Sepolia preset execution. No mainnet transactions. + * Destination WETH/Circle USDC are intentionally prefunded, not bridged assets: + * those two tokens have no usable SDK PRC20 pair. Generated call pins are unchanged. + */ +import { + createPublicClient, + encodeFunctionData, + erc20Abi, + http, + parseAbi, + parseEther, + parseEventLogs, + type Address, + type Hex, +} from 'viem'; +import { sepolia } from 'viem/chains'; +import { PushChain, CHAIN } from '../../src'; +import { MOVEABLE_TOKEN_CONSTANTS } from '../../src/lib/constants/tokens'; +import { getNativePRC20ForChain } from '../../src/lib/orchestrator/internals/helpers'; +import { getCEAAddress } from '../../src/lib/orchestrator/cea-utils'; +import { + AGW_E2E_ENABLED, + setupAgw, + evmClient, + inSeconds, + type AgwFixture, +} from './_fixture'; + +const d = AGW_E2E_ENABLED ? describe : describe.skip; +const WETH = '0xfff9976782d46cc05630d1f6ebab18b2324d6b14' as Address; +const USDC = '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238' as Address; +const FACTORY = '0x0227628f3F023bb0B980b67D528571c95c6DaC1c' as Address; +const AMOUNT = BigInt(10) ** BigInt(12); +const MAX_PC = parseEther('20'); +const SWAP = parseAbi([ + 'function exactInputSingle((address tokenIn,address tokenOut,uint24 fee,address recipient,uint256 amountIn,uint256 amountOutMinimum,uint160 sqrtPriceLimitX96)) returns(uint256)', +]); +const EXECUTED = parseAbi([ + 'event UniversalTxExecuted(bytes32 indexed subTxId, bytes32 indexed universalTxId, address indexed originCaller, address target, bytes data)', +]); +const sep = createPublicClient({ + chain: sepolia, + transport: http('https://ethereum-sepolia-rpc.publicnode.com'), +}); + +d('agw presets live', () => { + let f: AgwFixture; + afterAll(() => f?.teardown()); + it('1. Uniswap preset swaps from the wallet CEA and rejects a different recipient', async () => { + // Read-only protocol prerequisites run before any funding. + const block = await sep.getBlockNumber(); + const pool = await sep.readContract({ + address: FACTORY, + abi: parseAbi([ + 'function getPool(address,address,uint24) view returns(address)', + ]), + functionName: 'getPool', + args: [WETH, USDC, 500], + blockNumber: block, + }); + if (/^0x0+$/.test(pool)) + throw new Error( + 'PRESET_PREREQUISITE: Sepolia WETH/Circle USDC pool is absent' + ); + const liquidity = await sep.readContract({ + address: pool, + abi: parseAbi(['function liquidity() view returns(uint128)']), + functionName: 'liquidity', + blockNumber: block, + }); + if (!liquidity) + throw new Error( + 'PRESET_PREREQUISITE: Sepolia pool has no active liquidity' + ); + f = await setupAgw(); + const { rules } = PushChain.utils.agentic.presets.get('DEXES', { + chainNamespace: CHAIN.ETHEREUM_SEPOLIA, + agent: f.agentAddress, + validUntil: inSeconds(3600), + maxGasPerCall: MAX_PC, + assets: [ + { token: WETH, maxPerCall: AMOUNT, maxTotal: AMOUNT * BigInt(2) }, + { + token: USDC, + maxPerCall: BigInt(1_000_000), + maxTotal: BigInt(2_000_000), + }, + ], + }); + // assets[] budgets bridge burns on Push. This test spends already-held CEA + // tokens, so omit bridge assets without changing any generated call or pin. + const { wallet, rulesIds } = await f.owner.agentic.create( + 'e2e-preset-uniswap', + { rules: [{ ...rules[0], assets: [] }] } + ); + const cea = (await getCEAAddress(wallet, CHAIN.ETHEREUM_SEPOLIA)) + .cea as Address; + const router = rules[0].allowedCalls[0].target as Address; + await f.fundPC(wallet, parseEther('65')); + const peth = getNativePRC20ForChain( + CHAIN.ETHEREUM_SEPOLIA, + f.manifest.network + ); + await ( + await f.owner.universal.sendTransaction({ + to: peth, + data: encodeFunctionData({ + abi: erc20Abi, + functionName: 'transfer', + args: [wallet, AMOUNT * BigInt(2)], + }), + }) + ).wait(); + const owner = await evmClient( + process.env['PUSH_PRIVATE_KEY'] as Hex, + CHAIN.PUSH_TESTNET_DONUT, + f.manifest.network, + wallet + ); + const wrap = await owner.universal.sendTransaction({ + to: { address: WETH, chain: CHAIN.ETHEREUM_SEPOLIA }, + data: [ + { + to: WETH, + value: AMOUNT * BigInt(2), + data: encodeFunctionData({ + abi: parseAbi(['function deposit() payable']), + functionName: 'deposit', + }), + }, + ], + funds: { + token: MOVEABLE_TOKEN_CONSTANTS.ETHEREUM_SEPOLIA.ETH, + amount: AMOUNT * BigInt(2), + }, + gasLimit: BigInt(2_000_000), + }); + const wrapped = await wrap.wait(); + expect(wrapped.externalTxHash).toBeTruthy(); + expect( + (await sep.getTransactionReceipt({ hash: wrapped.externalTxHash as Hex })) + .status + ).toBe('success'); + const balance = (token: Address) => + sep.readContract({ + address: token, + abi: erc20Abi, + functionName: 'balanceOf', + args: [cea], + }); + expect(await balance(WETH)).toBe(AMOUNT * BigInt(2)); + const before = await balance(USDC); + const agent = await f.agent(wallet); + const swap = (recipient: Address) => + encodeFunctionData({ + abi: SWAP, + functionName: 'exactInputSingle', + args: [ + { + tokenIn: WETH, + tokenOut: USDC, + fee: 500, + recipient, + amountIn: AMOUNT, + amountOutMinimum: BigInt(1), + sqrtPriceLimitX96: BigInt(0), + }, + ], + }); + await expect( + agent.universal.sendTransaction({ + to: { address: router, chain: CHAIN.ETHEREUM_SEPOLIA }, + data: [{ to: router, value: BigInt(0), data: swap(f.agentAddress) }], + gasLimit: BigInt(700_000), + }) + ).rejects.toMatchObject({ + decodedError: { name: 'PolicyCheckReverted(ArgPinMismatch)' }, + }); + const tx = await agent.universal.sendTransaction({ + to: { address: router, chain: CHAIN.ETHEREUM_SEPOLIA }, + gasLimit: BigInt(700_000), + data: [ + { + to: WETH, + value: BigInt(0), + data: encodeFunctionData({ + abi: erc20Abi, + functionName: 'approve', + args: [router, AMOUNT], + }), + }, + { to: router, value: BigInt(0), data: swap(cea) }, + ], + }); + const receipt = await tx.wait(); + expect(receipt.externalTxHash).toBeTruthy(); + const dest = await sep.getTransactionReceipt({ + hash: receipt.externalTxHash as Hex, + }); + expect(dest.status).toBe('success'); + expect(await balance(WETH)).toBe(AMOUNT); + const after = await balance(USDC); + expect(after).toBeGreaterThan(before); + expect( + parseEventLogs({ abi: EXECUTED, logs: dest.logs }).some( + (e) => + e.address.toLowerCase() === cea.toLowerCase() && + e.args.originCaller.toLowerCase() === wallet.toLowerCase() && + e.args.target.toLowerCase() === router.toLowerCase() && + e.args.data === swap(cea) + ) + ).toBe(true); + f.evidence('preset-uniswap-live', { + wallet, + cea, + rulesId: rulesIds[0], + pool, + prerequisiteBlock: block, + wrapTx: wrap.hash, + wrapExternal: wrapped.externalTxHash, + pushTx: tx.hash, + externalTx: receipt.externalTxHash, + amountIn: AMOUNT, + amountOut: after - before, + }); + }, 900_000); + it('2. Aave preset supplies and withdraws the wallet position', async () => { + const mockLINK = '0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5' as Address; + const faucet = '0xC959483DBa39aa9E78757139af0e9a2EDEb3f42D' as Address; + const amount = BigInt(10) ** BigInt(12); + const faucetAbi = parseAbi(['function mint(address,address,uint256)']); + // Testnet USDC/DAI/USDT supply caps are exhausted; use faucet LINK. + // Mock LINK is a destination-only asset, not an SDK bridge token. + await sep.simulateContract({ + address: faucet, + abi: faucetAbi, + functionName: 'mint', + args: [mockLINK, '0x0000000000000000000000000000000000001234', amount], + account: '0x0000000000000000000000000000000000001234', + }); + const readinessPool = PushChain.utils.agentic.presets.get('LENDING', { + chainNamespace: CHAIN.ETHEREUM_SEPOLIA, + }).rules[0].allowedCalls[0].target as Address; + // Fail before funding if protocol gates (cap, pause, freeze) reject supply. + // An unfunded probe reaching token transfer is the expected result. + let readiness = ''; + try { + await sep.simulateContract({ + address: readinessPool, + abi: parseAbi(['function supply(address,uint256,address,uint16)']), + functionName: 'supply', + args: [ + mockLINK, + amount, + '0x0000000000000000000000000000000000001234', + 0, + ], + account: '0x0000000000000000000000000000000000001234', + }); + } catch (error) { + readiness = String( + (error as { shortMessage?: string }).shortMessage ?? error + ); + } + if (!readiness.includes('transfer amount exceeds balance')) + throw new Error( + `PRESET_PREREQUISITE: Aave reserve rejected unfunded supply probe: ${readiness}` + ); + f?.teardown(); + f = await setupAgw(); + const { rules } = PushChain.utils.agentic.presets.get('LENDING', { + chainNamespace: CHAIN.ETHEREUM_SEPOLIA, + agent: f.agentAddress, + validUntil: inSeconds(3600), + maxGasPerCall: MAX_PC, + assets: [{ token: mockLINK, maxPerCall: amount, maxTotal: amount }], + }); + const { wallet, rulesIds } = await f.owner.agentic.create( + 'e2e-preset-aave', + { rules: [{ ...rules[0], assets: [] }] } + ); + const cea = (await getCEAAddress(wallet, CHAIN.ETHEREUM_SEPOLIA)) + .cea as Address; + const pool = rules[0].allowedCalls[0].target as Address; + await f.fundPC(wallet, parseEther('65')); + const owner = await evmClient( + process.env['PUSH_PRIVATE_KEY'] as Hex, + CHAIN.PUSH_TESTNET_DONUT, + f.manifest.network, + wallet + ); + const mint = await owner.universal.sendTransaction({ + to: { address: faucet, chain: CHAIN.ETHEREUM_SEPOLIA }, + gasLimit: BigInt(2_000_000), + data: [ + { + to: faucet, + value: BigInt(0), + data: encodeFunctionData({ + abi: faucetAbi, + functionName: 'mint', + args: [mockLINK, cea, amount], + }), + }, + ], + }); + f.evidence('preset-aave-stage', { + stage: 'mint-submitted', + wallet, + cea, + pushTx: mint.hash, + }); + const minted = await mint.wait(); + f.evidence('preset-aave-stage', { + stage: 'mint-completed', + wallet, + cea, + externalTx: minted.externalTxHash, + }); + expect( + (await sep.getTransactionReceipt({ hash: minted.externalTxHash as Hex })) + .status + ).toBe('success'); + const balance = () => + sep.readContract({ + address: mockLINK, + abi: erc20Abi, + functionName: 'balanceOf', + args: [cea], + }); + expect(await balance()).toBe(amount); + const abi = parseAbi([ + 'function supply(address,uint256,address,uint16)', + 'function withdraw(address,uint256,address) returns(uint256)', + 'event Supply(address indexed reserve,address user,address indexed onBehalfOf,uint256 amount,uint16 indexed referralCode)', + 'event Withdraw(address indexed reserve,address indexed user,address indexed to,uint256 amount)', + ]); + const agent = await f.agent(wallet); + const supplyData = encodeFunctionData({ + abi, + functionName: 'supply', + args: [mockLINK, amount, cea, 0], + }); + const supply = await agent.universal.sendTransaction({ + to: { address: pool, chain: CHAIN.ETHEREUM_SEPOLIA }, + gasLimit: BigInt(900_000), + data: [ + { + to: mockLINK, + value: BigInt(0), + data: encodeFunctionData({ + abi: erc20Abi, + functionName: 'approve', + args: [pool, amount], + }), + }, + { to: pool, value: BigInt(0), data: supplyData }, + ], + }); + f.evidence('preset-aave-stage', { + stage: 'supply-submitted', + wallet, + cea, + pushTx: supply.hash, + }); + const supplied = await supply.wait(); + f.evidence('preset-aave-stage', { + stage: 'supply-completed', + wallet, + cea, + externalTx: supplied.externalTxHash, + }); + const supplyReceipt = await sep.getTransactionReceipt({ + hash: supplied.externalTxHash as Hex, + }); + expect(supplyReceipt.status).toBe('success'); + expect(await balance()).toBe(BigInt(0)); + const events = parseEventLogs({ + abi, + eventName: 'Supply', + logs: supplyReceipt.logs, + }); + expect( + events.some( + (e) => + e.address.toLowerCase() === pool.toLowerCase() && + e.args.user.toLowerCase() === cea.toLowerCase() && + e.args.onBehalfOf.toLowerCase() === cea.toLowerCase() && + e.args.amount === amount + ) + ).toBe(true); + const withdraw = await agent.universal.sendTransaction({ + to: { address: pool, chain: CHAIN.ETHEREUM_SEPOLIA }, + gasLimit: BigInt(900_000), + data: [ + { + to: pool, + value: BigInt(0), + data: encodeFunctionData({ + abi, + functionName: 'withdraw', + args: [mockLINK, amount, cea], + }), + }, + ], + }); + f.evidence('preset-aave-stage', { + stage: 'withdraw-submitted', + wallet, + cea, + pushTx: withdraw.hash, + }); + const withdrawn = await withdraw.wait(); + f.evidence('preset-aave-stage', { + stage: 'withdraw-completed', + wallet, + cea, + externalTx: withdrawn.externalTxHash, + }); + const withdrawalReceipt = await sep.getTransactionReceipt({ + hash: withdrawn.externalTxHash as Hex, + }); + expect(withdrawalReceipt.status).toBe('success'); + expect(await balance()).toBe(amount); + expect( + parseEventLogs({ + abi, + eventName: 'Withdraw', + logs: withdrawalReceipt.logs, + }).some( + (e) => + e.address.toLowerCase() === pool.toLowerCase() && + e.args.user.toLowerCase() === cea.toLowerCase() && + e.args.to.toLowerCase() === cea.toLowerCase() && + e.args.amount === amount + ) + ).toBe(true); + f.evidence('preset-aave-live', { + wallet, + cea, + rulesId: rulesIds[0], + mockLINK, + pool, + mintTx: mint.hash, + mintExternal: minted.externalTxHash, + supplyTx: supply.hash, + supplyExternal: supplied.externalTxHash, + withdrawTx: withdraw.hash, + withdrawExternal: withdrawn.externalTxHash, + amount, + }); + }, 900_000); +}); diff --git a/packages/core/__e2e__/ci/suite.ts b/packages/core/__e2e__/ci/suite.ts index 8ad742d2..c0869ece 100644 --- a/packages/core/__e2e__/ci/suite.ts +++ b/packages/core/__e2e__/ci/suite.ts @@ -37,6 +37,7 @@ export const GROUPS = [ 'agw', 'agw-svm-wire', 'agw-svm-replay', + 'agw-presets', ] as const; export type Group = (typeof GROUPS)[number]; @@ -984,6 +985,22 @@ export const SCENARIOS: Scenario[] = [ needs: { masterPC: '0.5' }, env: { AGW_E2E: '1' }, }, + { + id: 'agw-preset-uniswap-live', + group: 'agw-presets', + file: '__e2e__/agw/presets-live.spec.ts', + grep: 'agw presets live 1', + needs: { masterPC: '75', masterPETH: '0.000002' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-preset-aave-live', + group: 'agw-presets', + file: '__e2e__/agw/presets-live.spec.ts', + grep: 'agw presets live 2', + needs: { masterPC: '75' }, + env: { AGW_E2E: '1' }, + }, { id: 'agw-v6-destination-pins', group: 'agw', diff --git a/packages/core/src/lib/agentic/__tests__/preset-catalog.spec.ts b/packages/core/src/lib/agentic/__tests__/preset-catalog.spec.ts index c93bc2bd..622abe7d 100644 --- a/packages/core/src/lib/agentic/__tests__/preset-catalog.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/preset-catalog.spec.ts @@ -86,6 +86,10 @@ it('scopes money-market approvals to their actual underlying token', () => { }); }); it.each([ + 'eip155:1', + 'eip155:8453', + 'eip155:42161', + 'eip155:56', 'eip155:11155111', 'eip155:84532', 'eip155:421614', @@ -225,7 +229,7 @@ it('keeps chains without supplied assets discoverable and regenerates complete p const { rules } = agenticPresets.get('DEXES', { assets: input.assets!.map((a) => ({ ...a, chainNamespace: chain })), }); - expect(rules).toHaveLength(4); + expect(rules).toHaveLength(8); expect( rules.find((r) => r.chainNamespace === chain)?.allowedCalls ).toHaveLength(6); @@ -247,3 +251,50 @@ it('keeps chains without supplied assets discoverable and regenerates complete p ready.allowedCalls.every((c) => !c.label?.includes('select two tokens')) ).toBe(true); }); + +it.each(['eip155:1', 'eip155:8453', 'eip155:42161', 'eip155:56'] as const)( + 'mainnet %s templates preserve one rule per chain, selectors and wallet pins', + (chainNamespace) => { + for (const category of ['DEXES', 'LENDING'] as const) { + const { rules } = agenticPresets.get(category, { chainNamespace }); + expect(rules).toHaveLength(1); + expect(rules[0].chainNamespace).toBe(chainNamespace); + expect(rules[0].allowedCalls.length).toBeLessThanOrEqual(32); + expect(rules[0].allowedCalls.every((c) => c.selector.includes('('))).toBe( + true + ); + expect( + rules[0].allowedCalls.some((c) => + c.pins?.some((p) => p.expected === AGENTIC.WALLET) + ) + ).toBe(true); + expect(rules[0]).not.toHaveProperty('agent'); + } + } +); + +it('mainnet Lido templates pin withdrawal ownership and keep ETH staking disabled until explicitly capped', () => { + const stETH = getAddress('0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84'); + const { rules } = agenticPresets.get('STAKING', { + chainNamespace: 'eip155:1', + assets: [{ token: stETH, maxPerCall: BigInt(5), maxTotal: BigInt(10) }], + }); + expect(rules).toHaveLength(1); + const calls = rules[0].allowedCalls; + expect(calls.find((c) => c.selector === 'submit(address)')?.maxValue).toBe( + BigInt(0) + ); + const request = calls.find( + (c) => c.selector === 'requestWithdrawals(uint256[],address)' + )!; + expect(request.pins).toEqual([{ arg: 1, expected: AGENTIC.WALLET }]); + expect(evmPinOffset(request.selector, 1)).toBe(36); + expect( + calls.filter((c) => c.selector === 'approve(address,uint256)') + ).toHaveLength(3); + expect( + calls + .filter((c) => c.selector === 'approve(address,uint256)') + .every((c) => c.target === stETH && c.pins?.[1].max === BigInt(5)) + ).toBe(true); +}); diff --git a/packages/core/src/lib/agentic/__tests__/presets.spec.ts b/packages/core/src/lib/agentic/__tests__/presets.spec.ts index 6a8d7595..cefe7479 100644 --- a/packages/core/src/lib/agentic/__tests__/presets.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/presets.spec.ts @@ -45,7 +45,7 @@ function catalog(): PresetDefinition[] { }, ]; } -it('ships only verified testnet catalog entries and keeps prediction empty', () => { +it('ships verified mainnet and testnet templates and keeps prediction empty', () => { expect(Object.values(AGENTIC.PRESETS.CATEGORY)).toEqual([ 'DEXES', 'LENDING', @@ -54,9 +54,9 @@ it('ships only verified testnet catalog entries and keeps prediction empty', () ]); const entries = agenticPresets.list().presets; expect(entries.map((p) => [p.constant, p.chains.length])).toEqual([ - ['DEXES', 4], - ['LENDING', 4], - ['STAKING', 1], + ['DEXES', 8], + ['LENDING', 8], + ['STAKING', 2], ['PREDICTION', 0], ]); expect( @@ -64,6 +64,10 @@ it('ships only verified testnet catalog entries and keeps prediction empty', () .flatMap((p) => p.chains) .every((c) => [ + 'eip155:1', + 'eip155:8453', + 'eip155:42161', + 'eip155:56', 'eip155:11155111', 'eip155:84532', 'eip155:421614', @@ -72,9 +76,9 @@ it('ships only verified testnet catalog entries and keeps prediction empty', () ) ).toBe(true); expect(agenticPresets.get('PREDICTION')).toEqual({ rules: [] }); - expect(agenticPresets.get('DEXES').rules).toHaveLength(4); + expect(agenticPresets.get('DEXES').rules).toHaveLength(8); expect(() => - agenticPresets.get('LENDING', { chainNamespace: 'eip155:1' }) + agenticPresets.get('LENDING', { chainNamespace: 'eip155:999999' }) ).toThrow(/no approved entry/); }); it('groups all apps on a chain into one editable template and omits unspecified fields', () => { @@ -203,7 +207,7 @@ it('rejects unknown presets, unsupported list types and unsupported chain filter const api = buildPresetApi(catalog()); expect(() => api.get('UNKNOWN' as never)).toThrow(/unknown preset/); expect(() => api.list({ type: 'APP' } as never)).toThrow(/only CATEGORY/); - expect(() => api.get('DEXES', { chainNamespace: 'eip155:1' })).toThrow( + expect(() => api.get('DEXES', { chainNamespace: 'eip155:999999' })).toThrow( /no approved entry/ ); }); diff --git a/packages/core/src/lib/agentic/presets/catalog.ts b/packages/core/src/lib/agentic/presets/catalog.ts index 9c7c1ebf..732243fb 100644 --- a/packages/core/src/lib/agentic/presets/catalog.ts +++ b/packages/core/src/lib/agentic/presets/catalog.ts @@ -17,9 +17,9 @@ export interface PresetDefinition { name: string; chains: readonly PresetChainDefinition[]; } -/** Testnet-only catalog from the October 15 Notion export and protocol sources. +/** Mainnet and testnet templates from the October 15 Notion export and protocol sources. * Read-only deployment/code evidence and exclusions: plan/agw/research/preset-catalog-2026-10-15/. - * No mainnet addresses, unmaintained Compound market or unconfirmed Morpho deployment. + * Mainnet entries are templates only; no mainnet deployment or execution guarantee. */ const address = (value: string): Address => getAddress(value.toLowerCase()); const wallet = 'agentic:wallet' as const; @@ -57,11 +57,86 @@ const moonWETH = address('0x2F39a349A79492a70E152760ce7123A1933eCf28'); const venusUSDT = address('0xb7526572FFE56AB9D7489838Bf2E18e3323b441A'); const venusUSDC = address('0xD5C4C2e2facBEB59D0216D0595d63FcDc6F9A1a7'); const eigen = address('0x2E3D6c0744b10eb0A4e6F679F71554a39Ec47a5D'); +const stETH = address('0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84'); +const wstETH = address('0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0'); +const lidoQueue = address('0x889edC2eDab5f40e902b864aD4d7AdE8E412F9B1'); +const mainnetMarkets = ( + chain: string +): Pick => { + const entries = + chain === 'eip155:8453' + ? [ + [ + '0xEdc817A28E8B93B03976FBd4a3dDBc9f7D176c22', + 'Moonwell mUSDC', + '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', + ], + [ + '0x628ff693426583D9a7FB391E54366292F509D457', + 'Moonwell mWETH', + '0x4200000000000000000000000000000000000006', + ], + ] + : chain === 'eip155:56' + ? [ + [ + '0xfD5840Cd36d94D7229439859C0112a4185BC0255', + 'Venus vUSDT', + '0x55d398326f99059fF775485246999027B3197955', + ], + [ + '0xecA88125a5ADbe82614ffC12D0DB554E2e2867C8', + 'Venus vUSDC', + '0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d', + ], + ] + : []; + const controller = + chain === 'eip155:8453' + ? '0xfBb21d0380beE3312B33c4353c8936a0F13EF26C' + : '0xfD36E2c2a6789Db23113685031d7F16329158384'; + return { + allowedCalls: [ + ...entries.flatMap(([target, app]) => market(address(target), app)), + ...(entries.length + ? [ + { + target: address(controller), + selector: 'enterMarkets(address[])' as const, + app: chain === 'eip155:8453' ? 'Moonwell' : 'Venus', + label: 'Enter markets', + }, + ] + : []), + ], + approvals: entries.map(([spender, app, token]) => ({ + spender: address(spender), + app, + token: address(token), + })), + }; +}; export const PRESET_CATALOG: readonly PresetDefinition[] = [ { constant: 'DEXES', name: 'Popular DEXes', chains: [ + ['eip155:1', '0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45', 'Uniswap V3'], + [ + 'eip155:8453', + '0x2626664c2603336E57B271c5C0b26F421741e481', + 'Uniswap V3', + ], + [ + 'eip155:42161', + '0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45', + 'Uniswap V3', + ], + [ + 'eip155:56', + '0x13f4EA83D0bd40E75C8222255bc855a974568Dd4', + 'PancakeSwap V3', + ], [ 'eip155:11155111', '0x3bFA4769FB09eefC5a80d6E87c3B9C650f7Ae48E', @@ -93,6 +168,25 @@ export const PRESET_CATALOG: readonly PresetDefinition[] = [ constant: 'LENDING', name: 'Lending', chains: [ + ...( + [ + ['eip155:1', '0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2'], + ['eip155:8453', '0xA238Dd80C259a72e81d7e4664a9801593F98d1c5'], + ['eip155:42161', '0x794a61358D6845594F94dc1DB02A252b5b4814aD'], + ['eip155:56', '0x6807dc923806fE8Fd134338EABCA509979a7e0cB'], + ] as const + ).map(([chainNamespace, pool]) => ({ + chainNamespace, + allowedCalls: [ + ...aave(address(pool)), + ...mainnetMarkets(chainNamespace).allowedCalls, + ], + approvals: [ + { spender: address(pool), app: 'Aave V3' }, + ...(mainnetMarkets(chainNamespace).approvals ?? []), + ], + })), + { chainNamespace: 'eip155:11155111', allowedCalls: aave(sepoliaPool), @@ -161,6 +255,66 @@ export const PRESET_CATALOG: readonly PresetDefinition[] = [ constant: 'STAKING', name: 'Staking', chains: [ + { + chainNamespace: 'eip155:1', + allowedCalls: [ + { + target: stETH, + selector: 'submit(address)', + maxValue: BigInt(0), + app: 'Lido', + label: 'Stake ETH (set an explicit value cap)', + }, + { + target: wstETH, + selector: 'wrap(uint256)', + app: 'Lido wstETH', + label: 'Wrap stETH', + }, + { + target: wstETH, + selector: 'unwrap(uint256)', + app: 'Lido wstETH', + label: 'Unwrap wstETH', + }, + { + target: lidoQueue, + selector: 'requestWithdrawals(uint256[],address)', + pins: [{ arg: 1, expected: wallet }], + app: 'Lido withdrawal queue', + label: 'Request withdrawal', + }, + { + target: lidoQueue, + selector: 'claimWithdrawals(uint256[],uint256[])', + app: 'Lido withdrawal queue', + label: 'Claim finalized withdrawals', + }, + { + target: lidoQueue, + selector: 'claimWithdrawal(uint256)', + app: 'Lido withdrawal queue', + label: 'Claim finalized withdrawal', + }, + + { + target: address('0x858646372CC42E1A627fcE94aa7A7033e7CF075A'), + selector: 'depositIntoStrategy(address,address,uint256)', + app: 'EigenLayer', + label: 'Deposit into strategy (withdrawals not included)', + }, + ], + approvals: [ + { spender: wstETH, token: stETH, app: 'Lido wstETH' }, + { spender: lidoQueue, token: stETH, app: 'Lido withdrawal queue' }, + + { + spender: address('0x858646372CC42E1A627fcE94aa7A7033e7CF075A'), + app: 'EigenLayer', + }, + ], + }, + { chainNamespace: 'eip155:11155111', allowedCalls: [ From 1f74e891c6f84f9c8bfc183c5e3d20d06e30ab48 Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Thu, 15 Oct 2026 07:44:16 +0530 Subject: [PATCH 42/68] docs(agw): record preset alignment and live protocol acceptance --- plan/agw/SOURCES.md | 2 + plan/agw/implementation-status.md | 6 +- plan/agw/pending-items.md | 10 +- plan/agw/questions-harsh.md | 19 +- .../implementation-status.md | 4 +- .../preset-live-2026-10-15/AaveErrors.sol | 100 + .../research/preset-live-2026-10-15/README.md | 40 + .../preset-live-2026-10-15/aave-link-live.log | 11 + .../aave-prerequisites.json | 50 + .../aave-usdc-cap-failure.log | 28 + .../research/preset-live-2026-10-15/api.json | 11537 ++++++++++++++++ .../research/preset-live-2026-10-15/build.log | 13 + .../research/preset-live-2026-10-15/lint.log | 20 + .../live-evidence.jsonl | 8 + .../preset-live-2026-10-15/preflight.log | 20 + .../preset-live-2026-10-15/preset-focused.log | 8 + .../scenario-selection.log | 5 + .../preset-live-2026-10-15/uniswap-live.log | 12 + .../research/preset-live-2026-10-15/unit.log | 177 + .../AaveV3Arbitrum.sol | 613 + .../preset-mainnet-2026-10-15/AaveV3BNB.sol | 303 + .../preset-mainnet-2026-10-15/AaveV3Base.sol | 503 + .../AaveV3Ethereum.sol | 1602 +++ .../preset-mainnet-2026-10-15/README.md | 27 + .../lido-rpc-verification.json | 24 + .../moonwell-8453.json | 1677 +++ .../read-only-probe.cjs | 8 + .../rpc-verification.json | 124 + .../preset-mainnet-2026-10-15/sources.json | 48 + .../venus-bscmainnet.json | 324 + plan/agw/section7-presets.md | 34 +- 31 files changed, 17317 insertions(+), 40 deletions(-) create mode 100644 plan/agw/research/preset-live-2026-10-15/AaveErrors.sol create mode 100644 plan/agw/research/preset-live-2026-10-15/README.md create mode 100644 plan/agw/research/preset-live-2026-10-15/aave-link-live.log create mode 100644 plan/agw/research/preset-live-2026-10-15/aave-prerequisites.json create mode 100644 plan/agw/research/preset-live-2026-10-15/aave-usdc-cap-failure.log create mode 100644 plan/agw/research/preset-live-2026-10-15/api.json create mode 100644 plan/agw/research/preset-live-2026-10-15/build.log create mode 100644 plan/agw/research/preset-live-2026-10-15/lint.log create mode 100644 plan/agw/research/preset-live-2026-10-15/live-evidence.jsonl create mode 100644 plan/agw/research/preset-live-2026-10-15/preflight.log create mode 100644 plan/agw/research/preset-live-2026-10-15/preset-focused.log create mode 100644 plan/agw/research/preset-live-2026-10-15/scenario-selection.log create mode 100644 plan/agw/research/preset-live-2026-10-15/uniswap-live.log create mode 100644 plan/agw/research/preset-live-2026-10-15/unit.log create mode 100644 plan/agw/research/preset-mainnet-2026-10-15/AaveV3Arbitrum.sol create mode 100644 plan/agw/research/preset-mainnet-2026-10-15/AaveV3BNB.sol create mode 100644 plan/agw/research/preset-mainnet-2026-10-15/AaveV3Base.sol create mode 100644 plan/agw/research/preset-mainnet-2026-10-15/AaveV3Ethereum.sol create mode 100644 plan/agw/research/preset-mainnet-2026-10-15/README.md create mode 100644 plan/agw/research/preset-mainnet-2026-10-15/lido-rpc-verification.json create mode 100644 plan/agw/research/preset-mainnet-2026-10-15/moonwell-8453.json create mode 100644 plan/agw/research/preset-mainnet-2026-10-15/read-only-probe.cjs create mode 100644 plan/agw/research/preset-mainnet-2026-10-15/rpc-verification.json create mode 100644 plan/agw/research/preset-mainnet-2026-10-15/sources.json create mode 100644 plan/agw/research/preset-mainnet-2026-10-15/venus-bscmainnet.json diff --git a/plan/agw/SOURCES.md b/plan/agw/SOURCES.md index 26c3e0b2..d6c235a0 100644 --- a/plan/agw/SOURCES.md +++ b/plan/agw/SOURCES.md @@ -73,3 +73,5 @@ The historical SDK refers to AGW-SDK-v1-agent.md, 05-universal-marketplace-start October 7 v5 deployment: label contract dependency delivered. [New source snapshots and live read-only check](research/deployment-review-2026-10-07-v5/README.md); [SDK implementation and test evidence](research/v5-implementation-2026-10-07/README.md). Earlier dated deployment statements above are historical. October 15 focused import: [AGW Presets proposal and rules](https://app.notion.com/p/pushprotocol/AGW-Presets-proposal-and-rules-3f8188aea7f48020a9f0d10ea5325467), [snapshot](notion/agw-presets-proposal-and-rules.md), [catalog scope and verification](research/preset-catalog-2026-10-15/implementation-status.md). This was a single-page import, not a refresh of all sources. + +October 15 mainnet scope expansion: [official snapshots and pinned read-only verification](research/preset-mainnet-2026-10-15/README.md). [Separate live testnet acceptance](research/preset-live-2026-10-15/README.md). No mainnet transactions were broadcast. diff --git a/plan/agw/implementation-status.md b/plan/agw/implementation-status.md index f9a663c2..a2eb4cd5 100644 --- a/plan/agw/implementation-status.md +++ b/plan/agw/implementation-status.md @@ -1,15 +1,17 @@ # AGW SDK implementation status +**October 15 — presets:** Verified mainnet/testnet templates, static tuple paths and the approved zero-cap review/regenerate flow are implemented. Full unit suite: **2,096 passed**, 12 skipped. Preset-focused tests: **44 passed**; review-flow local contract suite: **16 passed**. [Current scope and remaining work](section7-presets.md). Dated entries below are historical where they differ. **Two real Donut→Sepolia protocol scenarios passed** (Uniswap swap and Aave LINK supply/withdraw, separate runs). Mainnet templates are read-only verified. Live app coverage is tracked in [preset acceptance](research/preset-live-2026-10-15/README.md). + **October 14 — v6 integration complete locally:** source `ffd567d`; v6-only deployment/ABIs, atomic indexed creation, automatic outbound approvals, native/EVM EQ/MAX pins, new unlimited sentinels and linked Solana error decoding are integrated. - **2,073 unit tests passed**, 12 skipped; **99 local contract tests passed**. - **69 distinct live scenarios pass across the full run and focused follow-up.** The original run was 67 passed/1 failed (stale allowance assertion), followed by 2/2 passing focused cases, including the new EVM pin alternative proof. Not one clean full invocation. - Build, lib/spec/local typechecks, guide examples, package imports/declarations and API comparison pass. -- V6 code committed on v4 (`7dca3f2a`) and v5 (`700a52a7`); not pushed yet. Preset catalog/struct-field conventions, the native eight-call ceiling clarification, and downstream revert credit remain separate items. +- V6 code and preset review fixes are now pushed on v4/v5. Native eight-call ceiling clarification and downstream revert credit remain separate items. [Detailed evidence and commands](research/v6-integration-2026-10-14/status.md). -**Current — October 12 sections 6/7:** SDK-only feedback and the preset framework are implemented locally. [Section 6 work list](section6-action-items.md) · [Preset scope/decisions](section7-presets.md) · [Open items](pending-items.md). +**Historical — October 12 sections 6/7:** SDK-only feedback and the preset framework are implemented locally. [Section 6 work list](section6-action-items.md) · [Preset scope/decisions](section7-presets.md) · [Open items](pending-items.md). - Full unit run: **2,075 passed, 0 failed, 12 skipped**. An earlier 100ms timing-test failure passed both on retry and in this final full run. - Section-6 real-contract coverage: all 97 cases pass across the suite and focused correction run. Presets add one fixture integration; its complete 11-case multi-asset suite passes. diff --git a/plan/agw/pending-items.md b/plan/agw/pending-items.md index dfe5cf3a..299227de 100644 --- a/plan/agw/pending-items.md +++ b/plan/agw/pending-items.md @@ -1,14 +1,12 @@ # AGW SDK pending items -October 14, 2026. The newly downloaded SDK sections 6/7 supersede the earlier `actions[]` proposal and multiple-rule creation decision. See [the item-by-item feedback list](section6-action-items.md). +October 15, 2026. The newly downloaded SDK sections 6/7 supersede the earlier `actions[]` proposal and multiple-rule creation decision. See [the item-by-item feedback list](section6-action-items.md). | Item | Owner / dependency | Completion condition | | --- | --- | --- | - - | Native 1..32 calls in spec versus deployed maximum 8 | Product/contracts | Align spec or deploy increased ceiling; SDK enforces 8 now | -| Presets (§7) | Product/app catalog | Approved apps/addresses/chains, struct-field pins and multi-spender approval representation; framework is implemented, missing caps default to zero, incomplete results are typed templates | -| ABI compound argument reconstruction | Product/spec metadata | Define struct fields and how layouts survive reads; unsupported layouts fail explicitly | +| Additional preset protocols / chains | SDK + protocol prerequisites | Verified subset is implemented on mainnet/testnet; expand excluded rows only after deployment/function/permission checks; live acceptance is per protocol/chain | +| Exact authored ABI reconstruction on reads | Spec metadata, optional | Static tuple/fixed-array paths now work. Raw selector + word positions roundtrip losslessly; recovering original names/types requires metadata not stored by contracts | | Native historical lifetime limits | Spec/migration | Define a lossless public representation if these old grants must be editable; never drop their restrictions silently | | Revert credit | Push-core executor | Executor invokes creditRevert; verify restored spend independently | | Delivery/terminal latency | Platform | Resolve delayed terminal status and bounded polling expectations | @@ -16,6 +14,6 @@ October 14, 2026. The newly downloaded SDK sections 6/7 supersede the earlier `a User decisions recorded October 12: multi-action native `spent` uses per-action entries. Decoded Solana rules may use an explicit raw form for lossless get→update; authored rules use arg/account positions. These no longer require clarification. -The first-use EVM gas default is being fixed in the SDK and is no longer an external core/gateway question. `setLabel` already exists on v5; direct invocation requires no contract change. +The first-use EVM gas default is implemented and is no longer an external core/gateway question. `setLabel` already exists on v5; direct invocation requires no contract change. V6 accounting note: generic native MAX pins enforce a per-call bound but do not increment the separate `amountSpent` meter. The SDK returns the actual counter (normally zero for the new public shape), plus value/call counters per action; it does not infer token spending from arbitrary numeric arguments. If the UI needs native per-token spend totals, that requires an explicit accounting design. diff --git a/plan/agw/questions-harsh.md b/plan/agw/questions-harsh.md index 1dcaaa77..f1bc56a7 100644 --- a/plan/agw/questions-harsh.md +++ b/plan/agw/questions-harsh.md @@ -1,15 +1,12 @@ -# AGW SDK — remaining preset catalog decisions +# AGW presets — documentation follow-up -Updated October 12, 2026 after the user authorized the section-7 framework. Local draft; nothing sent. +Updated October 15, 2026. Local draft; nothing sent. No blocking preset product question remains for the implemented scope. -## Catalog to provide later +Please synchronize SDK section 7 with the decisions recorded during implementation: -Which verified apps, functions, deployed addresses and chains should ship for `DEXES` and `LENDING`? The framework is implemented, but all categories currently have empty `chains` lists. UI callers should hide them. +1. Missing preset asset caps default to zero, rather than throwing. +2. DEX get can populate a review screen before tokens are selected. Incomplete pairs have a zero swap-input maximum; call get again with both tokens to generate usable token-pinned rules. +3. The catalog includes STAKING (EigenLayer deposits and mainnet Lido), and mainnet as well as testnet templates. Discovery does not guarantee destination support on the connected Push network. +4. Static tuple fields use paths such as arg: [0,3], replacing the ambiguous Uniswap arg: 3 example. Decoded rules preserve exact ABI word positions with a raw selector. -The contract/SDK review of those entries must settle tuple-field positions and how multiple apps can safely receive approvals for the same token. V6 now supplies general EVM pins and OR-matching alternatives. The SDK supports separate spender-pinned approval alternatives and rejects unpinned bypasses. Approved app-specific entries and tuple-field conventions still need review. - -## Decisions already made — no repeated question - -The user chose zero defaults for either omitted preset asset cap and deferred the catalog. Omitting agent or expiry returns a typed `PresetRuleTemplate`; providing both yields `Rule[]`. Per-action native spend and raw decoded Solana get→update were already approved. The new preset namespace contains only `list/get`; encoding and ID helpers remain internal. - -[Implementation and acceptance](section7-presets.md). +These decisions are already approved in the user session; this is documentation synchronization, not a request to approve them again. [Current scope and remaining expansion](section7-presets.md). diff --git a/plan/agw/research/preset-catalog-2026-10-15/implementation-status.md b/plan/agw/research/preset-catalog-2026-10-15/implementation-status.md index aa9667c2..c39c6ca0 100644 --- a/plan/agw/research/preset-catalog-2026-10-15/implementation-status.md +++ b/plan/agw/research/preset-catalog-2026-10-15/implementation-status.md @@ -1,6 +1,6 @@ # Testnet preset catalog — October 15, 2026 -User scope: testnet templates only. Missing caps default to zero. Source body and original native export are retained here; source.json records the Notion URL and observed edit date. The sibling README.md is downloaded EigenLayer documentation, not this implementation report. +Initial user scope: testnet templates only; subsequently expanded to mainnet templates on October 15 (see ../preset-mainnet-2026-10-15/README.md). Missing caps default to zero. Source body and original native export are retained here; source.json records the Notion URL and observed edit date. The sibling README.md is downloaded EigenLayer documentation, not this implementation report. ## Implemented @@ -18,7 +18,7 @@ The SDK page still needs editorial synchronization for this approved two-stage f | Entry | Reason | | --- | --- | -| Mainnet | User requested testnets only | +| Mainnet | Initial exclusion superseded by the October 15 scope expansion; verified counterparts now included | | Prediction | No approved entries | | Dynamic-path V2 swaps | Cannot statically pin token paths with this policy | | Solana protocol templates | Required ratios/layouts or multi-instruction flows are not represented by the current template API | diff --git a/plan/agw/research/preset-live-2026-10-15/AaveErrors.sol b/plan/agw/research/preset-live-2026-10-15/AaveErrors.sol new file mode 100644 index 00000000..990069e0 --- /dev/null +++ b/plan/agw/research/preset-live-2026-10-15/AaveErrors.sol @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.0; + +/** + * @title Errors library + * @author Aave + * @notice Defines the error messages emitted by the different contracts of the Aave protocol + */ +library Errors { + string public constant CALLER_NOT_POOL_ADMIN = '1'; // 'The caller of the function is not a pool admin' + string public constant CALLER_NOT_EMERGENCY_ADMIN = '2'; // 'The caller of the function is not an emergency admin' + string public constant CALLER_NOT_POOL_OR_EMERGENCY_ADMIN = '3'; // 'The caller of the function is not a pool or emergency admin' + string public constant CALLER_NOT_RISK_OR_POOL_ADMIN = '4'; // 'The caller of the function is not a risk or pool admin' + string public constant CALLER_NOT_ASSET_LISTING_OR_POOL_ADMIN = '5'; // 'The caller of the function is not an asset listing or pool admin' + string public constant CALLER_NOT_BRIDGE = '6'; // 'The caller of the function is not a bridge' + string public constant ADDRESSES_PROVIDER_NOT_REGISTERED = '7'; // 'Pool addresses provider is not registered' + string public constant INVALID_ADDRESSES_PROVIDER_ID = '8'; // 'Invalid id for the pool addresses provider' + string public constant NOT_CONTRACT = '9'; // 'Address is not a contract' + string public constant CALLER_NOT_POOL_CONFIGURATOR = '10'; // 'The caller of the function is not the pool configurator' + string public constant CALLER_NOT_ATOKEN = '11'; // 'The caller of the function is not an AToken' + string public constant INVALID_ADDRESSES_PROVIDER = '12'; // 'The address of the pool addresses provider is invalid' + string public constant INVALID_FLASHLOAN_EXECUTOR_RETURN = '13'; // 'Invalid return value of the flashloan executor function' + string public constant RESERVE_ALREADY_ADDED = '14'; // 'Reserve has already been added to reserve list' + string public constant NO_MORE_RESERVES_ALLOWED = '15'; // 'Maximum amount of reserves in the pool reached' + string public constant EMODE_CATEGORY_RESERVED = '16'; // 'Zero eMode category is reserved for volatile heterogeneous assets' + string public constant INVALID_EMODE_CATEGORY_ASSIGNMENT = '17'; // 'Invalid eMode category assignment to asset' + string public constant RESERVE_LIQUIDITY_NOT_ZERO = '18'; // 'The liquidity of the reserve needs to be 0' + string public constant FLASHLOAN_PREMIUM_INVALID = '19'; // 'Invalid flashloan premium' + string public constant INVALID_RESERVE_PARAMS = '20'; // 'Invalid risk parameters for the reserve' + string public constant INVALID_EMODE_CATEGORY_PARAMS = '21'; // 'Invalid risk parameters for the eMode category' + string public constant BRIDGE_PROTOCOL_FEE_INVALID = '22'; // 'Invalid bridge protocol fee' + string public constant CALLER_MUST_BE_POOL = '23'; // 'The caller of this function must be a pool' + string public constant INVALID_MINT_AMOUNT = '24'; // 'Invalid amount to mint' + string public constant INVALID_BURN_AMOUNT = '25'; // 'Invalid amount to burn' + string public constant INVALID_AMOUNT = '26'; // 'Amount must be greater than 0' + string public constant RESERVE_INACTIVE = '27'; // 'Action requires an active reserve' + string public constant RESERVE_FROZEN = '28'; // 'Action cannot be performed because the reserve is frozen' + string public constant RESERVE_PAUSED = '29'; // 'Action cannot be performed because the reserve is paused' + string public constant BORROWING_NOT_ENABLED = '30'; // 'Borrowing is not enabled' + string public constant STABLE_BORROWING_NOT_ENABLED = '31'; // 'Stable borrowing is not enabled' + string public constant NOT_ENOUGH_AVAILABLE_USER_BALANCE = '32'; // 'User cannot withdraw more than the available balance' + string public constant INVALID_INTEREST_RATE_MODE_SELECTED = '33'; // 'Invalid interest rate mode selected' + string public constant COLLATERAL_BALANCE_IS_ZERO = '34'; // 'The collateral balance is 0' + string public constant HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD = '35'; // 'Health factor is lesser than the liquidation threshold' + string public constant COLLATERAL_CANNOT_COVER_NEW_BORROW = '36'; // 'There is not enough collateral to cover a new borrow' + string public constant COLLATERAL_SAME_AS_BORROWING_CURRENCY = '37'; // 'Collateral is (mostly) the same currency that is being borrowed' + string public constant AMOUNT_BIGGER_THAN_MAX_LOAN_SIZE_STABLE = '38'; // 'The requested amount is greater than the max loan size in stable rate mode' + string public constant NO_DEBT_OF_SELECTED_TYPE = '39'; // 'For repayment of a specific type of debt, the user needs to have debt that type' + string public constant NO_EXPLICIT_AMOUNT_TO_REPAY_ON_BEHALF = '40'; // 'To repay on behalf of a user an explicit amount to repay is needed' + string public constant NO_OUTSTANDING_STABLE_DEBT = '41'; // 'User does not have outstanding stable rate debt on this reserve' + string public constant NO_OUTSTANDING_VARIABLE_DEBT = '42'; // 'User does not have outstanding variable rate debt on this reserve' + string public constant UNDERLYING_BALANCE_ZERO = '43'; // 'The underlying balance needs to be greater than 0' + string public constant INTEREST_RATE_REBALANCE_CONDITIONS_NOT_MET = '44'; // 'Interest rate rebalance conditions were not met' + string public constant HEALTH_FACTOR_NOT_BELOW_THRESHOLD = '45'; // 'Health factor is not below the threshold' + string public constant COLLATERAL_CANNOT_BE_LIQUIDATED = '46'; // 'The collateral chosen cannot be liquidated' + string public constant SPECIFIED_CURRENCY_NOT_BORROWED_BY_USER = '47'; // 'User did not borrow the specified currency' + string public constant INCONSISTENT_FLASHLOAN_PARAMS = '49'; // 'Inconsistent flashloan parameters' + string public constant BORROW_CAP_EXCEEDED = '50'; // 'Borrow cap is exceeded' + string public constant SUPPLY_CAP_EXCEEDED = '51'; // 'Supply cap is exceeded' + string public constant UNBACKED_MINT_CAP_EXCEEDED = '52'; // 'Unbacked mint cap is exceeded' + string public constant DEBT_CEILING_EXCEEDED = '53'; // 'Debt ceiling is exceeded' + string public constant UNDERLYING_CLAIMABLE_RIGHTS_NOT_ZERO = '54'; // 'Claimable rights over underlying not zero (aToken supply or accruedToTreasury)' + string public constant STABLE_DEBT_NOT_ZERO = '55'; // 'Stable debt supply is not zero' + string public constant VARIABLE_DEBT_SUPPLY_NOT_ZERO = '56'; // 'Variable debt supply is not zero' + string public constant LTV_VALIDATION_FAILED = '57'; // 'Ltv validation failed' + string public constant INCONSISTENT_EMODE_CATEGORY = '58'; // 'Inconsistent eMode category' + string public constant PRICE_ORACLE_SENTINEL_CHECK_FAILED = '59'; // 'Price oracle sentinel validation failed' + string public constant ASSET_NOT_BORROWABLE_IN_ISOLATION = '60'; // 'Asset is not borrowable in isolation mode' + string public constant RESERVE_ALREADY_INITIALIZED = '61'; // 'Reserve has already been initialized' + string public constant USER_IN_ISOLATION_MODE_OR_LTV_ZERO = '62'; // 'User is in isolation mode or ltv is zero' + string public constant INVALID_LTV = '63'; // 'Invalid ltv parameter for the reserve' + string public constant INVALID_LIQ_THRESHOLD = '64'; // 'Invalid liquidity threshold parameter for the reserve' + string public constant INVALID_LIQ_BONUS = '65'; // 'Invalid liquidity bonus parameter for the reserve' + string public constant INVALID_DECIMALS = '66'; // 'Invalid decimals parameter of the underlying asset of the reserve' + string public constant INVALID_RESERVE_FACTOR = '67'; // 'Invalid reserve factor parameter for the reserve' + string public constant INVALID_BORROW_CAP = '68'; // 'Invalid borrow cap for the reserve' + string public constant INVALID_SUPPLY_CAP = '69'; // 'Invalid supply cap for the reserve' + string public constant INVALID_LIQUIDATION_PROTOCOL_FEE = '70'; // 'Invalid liquidation protocol fee for the reserve' + string public constant INVALID_EMODE_CATEGORY = '71'; // 'Invalid eMode category for the reserve' + string public constant INVALID_UNBACKED_MINT_CAP = '72'; // 'Invalid unbacked mint cap for the reserve' + string public constant INVALID_DEBT_CEILING = '73'; // 'Invalid debt ceiling for the reserve + string public constant INVALID_RESERVE_INDEX = '74'; // 'Invalid reserve index' + string public constant ACL_ADMIN_CANNOT_BE_ZERO = '75'; // 'ACL admin cannot be set to the zero address' + string public constant INCONSISTENT_PARAMS_LENGTH = '76'; // 'Array parameters that should be equal length are not' + string public constant ZERO_ADDRESS_NOT_VALID = '77'; // 'Zero address not valid' + string public constant INVALID_EXPIRATION = '78'; // 'Invalid expiration' + string public constant INVALID_SIGNATURE = '79'; // 'Invalid signature' + string public constant OPERATION_NOT_SUPPORTED = '80'; // 'Operation not supported' + string public constant DEBT_CEILING_NOT_ZERO = '81'; // 'Debt ceiling is not zero' + string public constant ASSET_NOT_LISTED = '82'; // 'Asset is not listed' + string public constant INVALID_OPTIMAL_USAGE_RATIO = '83'; // 'Invalid optimal usage ratio' + string public constant INVALID_OPTIMAL_STABLE_TO_TOTAL_DEBT_RATIO = '84'; // 'Invalid optimal stable to total debt ratio' + string public constant UNDERLYING_CANNOT_BE_RESCUED = '85'; // 'The underlying asset cannot be rescued' + string public constant ADDRESSES_PROVIDER_ALREADY_ADDED = '86'; // 'Reserve has already been added to reserve list' + string public constant POOL_ADDRESSES_DO_NOT_MATCH = '87'; // 'The token implementation pool address and the pool address provided by the initializing pool do not match' + string public constant STABLE_BORROWING_ENABLED = '88'; // 'Stable borrowing is enabled' + string public constant SILOED_BORROWING_VIOLATION = '89'; // 'User is trying to borrow multiple assets including a siloed one' + string public constant RESERVE_DEBT_NOT_ZERO = '90'; // the total debt of the reserve needs to be 0 + string public constant FLASHLOAN_DISABLED = '91'; // FlashLoaning for this asset is disabled +} diff --git a/plan/agw/research/preset-live-2026-10-15/README.md b/plan/agw/research/preset-live-2026-10-15/README.md new file mode 100644 index 00000000..a1a5fc64 --- /dev/null +++ b/plan/agw/research/preset-live-2026-10-15/README.md @@ -0,0 +1,40 @@ +# Preset live acceptance — October 15, 2026 + +## Scope + +Real Donut v6 wallets and real Sepolia protocol contracts; no mainnet broadcasts. Test group `agw-presets` is opt-in and excluded from `all`. It contains two distinct scenarios, verified against the actual test names. + +The tests generate allowed calls through public presets.get and preserve their pins/approvals. They intentionally set the rule's bridge assets to []: Uniswap's WETH/Circle USDC and Aave's mock LINK do not form a supported SDK PRC20 pair. Destination accounts are prefunded separately (owner bridges ETH and wraps WETH; owner calls Aave's official testnet faucet). These tests prove destination balances can be used under preset permissions, not support for bridging arbitrary preset tokens. + +## Uniswap — passed + +- Fresh AGW, owner outbound wraps 0.000002 Sepolia ETH in its CEA. +- Agent uses the catalog's approval and exactInputSingle calls, with token, amount and wallet-recipient pins. +- Different recipient rejected by URP. +- 0.000001 WETH consumed; Circle USDC balance increased by 45,586 raw units. +- Destination success receipt and CEA UniversalTxExecuted event attribute the exact swap to the wallet. Exact output amount is observed evidence, not a future expectation. + +Transaction hashes are retained in live-evidence.jsonl. No mainnet or mocked destination execution is included in this result. + +## Aave — LINK passed; original USDC prerequisite failure retained + +The initial USDC supply reverted on Sepolia with Error(51), SUPPLY_CAP_EXCEEDED in the official Aave Errors.sol. DAI and USDT also fail this gate. Read-only probes are in aave-prerequisites.json (block is an observed head, not a pinned snapshot across the calls). The test now uses faucet LINK and fails before funding if an unfunded supply probe cannot reach the expected token-balance check. The revised LINK test passed: faucet funding, agent approval/supply, and withdrawal of the same 10^12 raw LINK units all succeeded. Supply/Withdraw events identify the wallet CEA as user/beneficiary, and balances independently confirm the round trip. Direct mint on the underlying token is owner-restricted and is not used. + +Error source: https://raw.githubusercontent.com/aave/aave-v3-core/master/contracts/protocol/libraries/helpers/Errors.sol. This is a protocol capacity issue, not a passing test or a silent skip. + +Both scenarios passed in separate focused runs, not one combined invocation. The USDC attempt failed and remains in the evidence; the LINK result does not assert USDC capacity. + +## Commands + +From packages/core: + +- `node ../../node_modules/ts-node/dist/bin.js --transpile-only __e2e__/ci/preflight.ts --group agw-presets --dry-run` (run with initial one-scenario manifest; balances exceeded the subsequent combined budget). +- `node ../../node_modules/ts-node/dist/bin.js --transpile-only __e2e__/ci/run.ts --group agw-presets` (initial Uniswap-only run). +- `AGW_E2E=1 node ../../node_modules/jest/bin/jest.js --config jest.e2e.config.ts --runInBand --forceExit --runTestsByPath __e2e__/agw/presets-live.spec.ts --testNamePattern 'agw presets live 2'` (Aave focused follow-up). +- `node ../../node_modules/ts-node/dist/bin.js --transpile-only __e2e__/ci/run.ts --group agw-presets --list --verify` (two scenarios, two distinct tests). + +Root validation: full unit suite 2,096 passed / 12 skipped; build, library/spec typechecks, public guide typecheck, package import/declaration check and source/compiled API check passed. No full old AGW live rerun was needed for the catalog-only additions. + +## Remaining coverage + +Real trades/deposits on Base, Arbitrum and BNB and EigenLayer staking are not established by these Sepolia results. Mainnet templates have official-source and read-only code checks only. Unsupported/unverified proposal entries are documented in the mainnet catalog review. No external protocol address was deployed or changed by this work. diff --git a/plan/agw/research/preset-live-2026-10-15/aave-link-live.log b/plan/agw/research/preset-live-2026-10-15/aave-link-live.log new file mode 100644 index 00000000..a260ae82 --- /dev/null +++ b/plan/agw/research/preset-live-2026-10-15/aave-link-live.log @@ -0,0 +1,11 @@ +PASS core-e2e __e2e__/agw/presets-live.spec.ts (276.918 s) + agw presets live + ✓ 2. Aave preset supplies and withdraws the wallet position (275014 ms) + ○ skipped 1. Uniswap preset swaps from the wallet CEA and rejects a different recipient + +Test Suites: 1 passed, 1 total +Tests: 1 skipped, 1 passed, 2 total +Snapshots: 0 total +Time: 276.939 s +Ran all test suites within paths "__e2e__/agw/presets-live.spec.ts". +Force exiting Jest: Have you considered using `--detectOpenHandles` to detect async operations that kept running after all tests finished? diff --git a/plan/agw/research/preset-live-2026-10-15/aave-prerequisites.json b/plan/agw/research/preset-live-2026-10-15/aave-prerequisites.json new file mode 100644 index 00000000..8db9f159 --- /dev/null +++ b/plan/agw/research/preset-live-2026-10-15/aave-prerequisites.json @@ -0,0 +1,50 @@ +{ + "block": "11917343", + "rows": [ + { + "token": "0xFF34B3d4Aee8ddCd6F9AFFFB6Fe49bD371b8a357", + "symbol": "DAI", + "result": "The contract function \"supply\" reverted with the following reason:\n51" + }, + { + "token": "0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5", + "symbol": "LINK", + "result": "The contract function \"supply\" reverted with the following reason:\nERC20: transfer amount exceeds balance" + }, + { + "token": "0x94a9D9AC8a22534E3FaCa9F4e7F2E2cf85d5E4C8", + "symbol": "USDC", + "result": "The contract function \"supply\" reverted with the following reason:\n51" + }, + { + "token": "0x29f2D40B0605204364af54EC677bD022dA425d03", + "symbol": "WBTC", + "result": "The contract function \"supply\" reverted with the following reason:\nERC20: transfer amount exceeds balance" + }, + { + "token": "0xC558DBdd856501FCd9aaF1E62eae57A9F0629a3c", + "symbol": "WETH", + "result": "The contract function \"supply\" reverted." + }, + { + "token": "0xaA8E23Fb1079EA71e0a56F48a2aA51851D8433D0", + "symbol": "USDT", + "result": "The contract function \"supply\" reverted with the following reason:\n51" + }, + { + "token": "0x88541670E55cC00bEEFD87eB59EDd1b7C511AC9a", + "symbol": "AAVE", + "result": "The contract function \"supply\" reverted with the following reason:\nERC20: transfer amount exceeds balance" + }, + { + "token": "0x6d906e526a4e2Ca02097BA9d0caA3c382F52278E", + "symbol": "EURS", + "result": "The contract function \"supply\" reverted with the following reason:\nERC20: transfer amount exceeds balance" + }, + { + "token": "0xc4bF5CbDaBE595361438F8c6a187bDc330539c60", + "symbol": "GHO", + "result": "The contract function \"supply\" reverted with the following reason:\nArithmetic operation resulted in underflow or overflow." + } + ] +} diff --git a/plan/agw/research/preset-live-2026-10-15/aave-usdc-cap-failure.log b/plan/agw/research/preset-live-2026-10-15/aave-usdc-cap-failure.log new file mode 100644 index 00000000..1937ba3d --- /dev/null +++ b/plan/agw/research/preset-live-2026-10-15/aave-usdc-cap-failure.log @@ -0,0 +1,28 @@ +FAIL core-e2e __e2e__/agw/presets-live.spec.ts (211.735 s) + agw presets live + ✕ 2. Aave preset supplies and withdraws the wallet position (209529 ms) + ○ skipped 1. Uniswap preset swaps from the wallet CEA and rejects a different recipient + + ● agw presets live › 2. Aave preset supplies and withdraws the wallet position + + expect(received).toBe(expected) // Object.is equality + + Expected: "success" + Received: "reverted" + + 321 | hash: supplied.externalTxHash as Hex, + 322 | }); + > 323 | expect(supplyReceipt.status).toBe('success'); + | ^ + 324 | expect(await balance()).toBe(BigInt(0)); + 325 | const events = parseEventLogs({ + 326 | abi, + + at Object. (__e2e__/agw/presets-live.spec.ts:323:34) + +Test Suites: 1 failed, 1 total +Tests: 1 failed, 1 skipped, 2 total +Snapshots: 0 total +Time: 211.754 s, estimated 218 s +Ran all test suites within paths "__e2e__/agw/presets-live.spec.ts". +Force exiting Jest: Have you considered using `--detectOpenHandles` to detect async operations that kept running after all tests finished? diff --git a/plan/agw/research/preset-live-2026-10-15/api.json b/plan/agw/research/preset-live-2026-10-15/api.json new file mode 100644 index 00000000..337e2bd8 --- /dev/null +++ b/plan/agw/research/preset-live-2026-10-15/api.json @@ -0,0 +1,11537 @@ +{ + "baseline": "b1597b91a25dbf7f691f589b4e1e154add604315", + "head": "0e40221567a16b26b123f1440d6ccb025803ed39", + "compiledMatchesSource": true, + "initializeSignatureChanged": false, + "addedExports": [ + "AgenticPresets", + "ArgumentPath", + "DecodedSolanaRule", + "Pin", + "Preset", + "PresetAsset", + "PresetCategory", + "PresetOptions", + "PresetRuleTemplate", + "ReadyPresetOptions", + "RuleInput", + "Spent", + "WalletMarker" + ], + "removedExports": [ + "AgenticNetworkConstants", + "NativeRule", + "UniversalRule" + ], + "changedAgwTypes": [ + "AgenticWallet", + "AgenticError", + "AgenticRevertError", + "AGENTIC_ERROR_CODE", + "Rule", + "RuleInput", + "Pin", + "Spent", + "NativeRule", + "AssetCap", + "AllowedCall", + "UniversalRule", + "RulesRecord", + "CreateOptions", + "AgenticTxMetadata" + ], + "publicTypeChanges": [ + "AGENTIC_ERROR_CODE", + "AgenticError", + "AgenticRevertError", + "AgenticErrorCode", + "AgenticTxMetadata", + "AgenticWallet", + "AllowedCall", + "AssetCap", + "CreateOptions", + "DecodedSolanaRule", + "Rule", + "RuleInput", + "Pin", + "Spent", + "WalletMarker", + "ArgumentPath", + "RulesRecord", + "Preset", + "PresetCategory", + "PresetAsset", + "PresetOptions", + "ReadyPresetOptions", + "PresetRuleTemplate", + "AgenticPresets" + ], + "transactionMethodChanges": [], + "instanceMethodChanges": [], + "agwConstantsChanged": true, + "before": { + "exports": [ + "AGENTIC_ERROR_CODE", + "AccountRole", + "AccountStatus", + "AccountType", + "AgenticAddress", + "AgenticDoor", + "AgenticError", + "AgenticErrorCode", + "AgenticHex", + "AgenticNamespace", + "AgenticNetworkConstants", + "AgenticProgressHook", + "AgenticRevertError", + "AgenticTxMetadata", + "AgenticWallet", + "AllowedCall", + "AssetCap", + "BatchReadResponse", + "BuildReadSpecParams", + "CHAIN", + "CONTRACT_REQUEST_STATUS", + "CascadeCompletionResult", + "CascadeHopInfo", + "CascadeProgressEvent", + "CascadeTrackOptions", + "CascadedTxResponse", + "ChainSource", + "ChainTarget", + "Checkpoint", + "CheckpointKind", + "ConversionQuote", + "CreateOptions", + "CreateResult", + "DEFAULT_MAX_PC_FOR_GAS_BUFFER_BPS", + "DecodedErrorPayload", + "DecodedReadResult", + "DerivedExecutorAccount", + "EncodedReadQuery", + "EvmReadQuery", + "ForeignChainNamespace", + "FulfilOutcome", + "FundsToken", + "InsufficientPC20BalanceError", + "InvalidPC20AddressError", + "InvalidPC20MetadataError", + "InvalidReadQueryError", + "InvalidReadSpecError", + "MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT", + "MaxPCForGasCapFromNativeValueInput", + "MaxPCForGasCapInput", + "MaxPCForGasCapQuote", + "MultiChainTxResponse", + "NativeRule", + "OutboundTxDetails", + "PC20AddressResult", + "PC20AmbiguousAddressError", + "PC20Error", + "PC20ExpectedButPRC20Error", + "PC20ExportRevertedError", + "PC20FactoryMismatchError", + "PC20RegistryEntry", + "PC20RegistryMismatchError", + "PC20TokenChainMismatchError", + "PC20TokenReference", + "PC20UnknownChainNamespaceError", + "PC20UnsafeEmptyPayloadError", + "PC20WrapperNotRegisteredError", + "PC20WrapperPredictionUnavailableError", + "ParsedReadRequest", + "PreparedRead", + "PreparedUniversalTx", + "PushChain", + "PushChainBatchExecutionError", + "PushChainExecutionError", + "PushChainInitializeOptions", + "READ_ERROR_CODE", + "READ_OUTCOME", + "READ_STATUS", + "ReadCallback", + "ReadCallbackOptions", + "ReadChain", + "ReadDecodeError", + "ReadDestination", + "ReadExecuteOptions", + "ReadFees", + "ReadHeightUnavailableError", + "ReadLifecycleOptions", + "ReadNotFoundError", + "ReadOptions", + "ReadPreflight", + "ReadPrepareOptions", + "ReadQuery", + "ReadQueryOptions", + "ReadRef", + "ReadRegistryUnavailableError", + "ReadResponseTuple", + "ReadResultShape", + "ReadSpec", + "ReadSpecTuple", + "ReadSpecViolation", + "ReadStateError", + "ReadTimeoutError", + "ReadTrackOptions", + "ReadValue", + "ReadWeb2Options", + "ReceiptLike", + "RescueFundsParams", + "ResolvedAccount", + "ResolvedControllerAccounts", + "ResolvedDestination", + "Rule", + "RulesRecord", + "Selector", + "SignAuthorizationParams", + "SignedAuthorization", + "SimulateReadResult", + "SvmExecutePayloadFields", + "SvmGatewayAccountMeta", + "SvmReadQuery", + "TERMINAL_READ_STATUSES", + "TransactionRoute", + "TransactionRouteType", + "UEAStatus", + "UNIVERSAL_CALLBACK_EVM", + "UNIVERSAL_READ_REGISTRY_EVM", + "UNIVERSAL_READ_STATUS", + "UniversalAccount", + "UniversalExecuteParams", + "UniversalOutboundTxRequest", + "UniversalReadResponse", + "UniversalRule", + "UniversalSigner", + "UniversalSignerSkeleton", + "UniversalTo", + "UnsupportedPC20DestinationError", + "UnsupportedReadDestinationError", + "ValidateReadCall", + "WaitForOutboundOptions", + "WalletInfo", + "WalletSummary", + "Web2Extract", + "Web2ReadQuery", + "Web2ValueType", + "buildErc20WithdrawalMulticall", + "buildMigrationPayload", + "buildReadSpecFromPreflight", + "chainSupportsCEA", + "chainSupportsOutbound", + "decodeReadResult", + "detectRoute", + "encodeReadQuery", + "encodeSvmExecutePayload", + "getAllCEAAddresses", + "getCEAAddress", + "getCEAFactoryAddress", + "getPushAccountForCEA", + "inferResultShape", + "isCEA", + "isChainTarget", + "isPC20Reference", + "isSvmChain", + "isValidSolanaHexAddress", + "parseFulfilOutcome", + "parseReadRequestsFromReceipt", + "parseUEAVersion", + "quoteMaxPCForGasCap", + "quoteMaxPCForGasCapFromNativeValue", + "resolveDestination", + "sizeCallbackBudget", + "toCallData", + "toReadQuery", + "toRequestIdHex", + "validateReadSpec" + ], + "agw": { + "AgenticNamespace": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace", + "members": { + "create": { + "optional": false, + "readonly": false, + "type": "(label: string, options: import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions) => Promise" + }, + "derive": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n index?: number;\n}) => Promise<{\n address: `0x${string}`;\n deployed: boolean;\n index: number;\n}>" + }, + "list": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n wallets: import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary[];\n}>" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "(address: `0x${string}`) => import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet" + } + } + }, + "AgenticWallet": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "checkpoints": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n sinceBlock?: bigint;\n}) => Promise<{\n checkpoints: import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint[];\n}>" + }, + "info": { + "optional": false, + "readonly": false, + "type": "() => Promise" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n owner: `0x${string}`;\n}>" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "{\n add(rules: import(\"sdk/src/lib/agentic/agentic.types\").Rule[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise<{\n rulesIds: `0x${string}`[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n get(rulesId: `0x${string}`): Promise;\n list(): Promise<{\n rules: import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord[];\n }>;\n revoke(rulesIds: `0x${string}`[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n revoke(params: {\n all: true;\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n update(params: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n rules: {\n rule: import(\"sdk/src/lib/agentic/agentic.types\").Rule;\n rulesId: `0x${string}`;\n }[];\n }): Promise<{\n rules: {\n replaced: `0x${string}`;\n rulesId: `0x${string}`;\n }[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n}" + }, + "setLabel": { + "optional": false, + "readonly": false, + "type": "(label: string, opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n}) => Promise" + } + } + }, + "AgenticError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"CREATE_PARTIAL\" | \"DUPLICATE_RULE\" | \"FROM_NOT_ALLOWED\" | \"GATEWAY_ALLOWANCE_INSUFFICIENT\" | \"GENERATION_UNSUPPORTED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"REVOKE_NEEDS_TARGET\" | \"RULE_LIMIT_EXCEEDED\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"" + }, + "details": { + "optional": true, + "readonly": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "AgenticRevertError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticRevertError", + "members": { + "agenticCode": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + } + } + }, + "AGENTIC_ERROR_CODE": { + "type": "{\n readonly AGENT_GAS_INSUFFICIENT: \"AGENT_GAS_INSUFFICIENT\";\n readonly AGENT_IS_OWNER: \"AGENT_IS_OWNER\";\n readonly ASSET_CHAIN_MISMATCH: \"ASSET_CHAIN_MISMATCH\";\n readonly CAPABILITY_UNAVAILABLE: \"CAPABILITY_UNAVAILABLE\";\n readonly CREATE_PARTIAL: \"CREATE_PARTIAL\";\n readonly DUPLICATE_RULE: \"DUPLICATE_RULE\";\n readonly FROM_NOT_ALLOWED: \"FROM_NOT_ALLOWED\";\n readonly GATEWAY_ALLOWANCE_INSUFFICIENT: \"GATEWAY_ALLOWANCE_INSUFFICIENT\";\n readonly GENERATION_UNSUPPORTED: \"GENERATION_UNSUPPORTED\";\n readonly INCONSISTENT_READ: \"INCONSISTENT_READ\";\n readonly INDEX_RACE: \"INDEX_RACE\";\n readonly INVALID_RULE: \"INVALID_RULE\";\n readonly NO_RULES_FOR_CHAIN: \"NO_RULES_FOR_CHAIN\";\n readonly NOT_AGENTIC_WALLET: \"NOT_AGENTIC_WALLET\";\n readonly NOT_ALLOWED_IN_AGENTIC_MODE: \"NOT_ALLOWED_IN_AGENTIC_MODE\";\n readonly NOT_OWNER_OR_AGENT: \"NOT_OWNER_OR_AGENT\";\n readonly NOT_WALLET_OWNER: \"NOT_WALLET_OWNER\";\n readonly READ_ONLY: \"READ_ONLY\";\n readonly RECEIPT_MISMATCH: \"RECEIPT_MISMATCH\";\n readonly RECEIPT_UNAVAILABLE: \"RECEIPT_UNAVAILABLE\";\n readonly REVOKE_NEEDS_TARGET: \"REVOKE_NEEDS_TARGET\";\n readonly RULE_LIMIT_EXCEEDED: \"RULE_LIMIT_EXCEEDED\";\n readonly RULE_NOT_FOUND: \"RULE_NOT_FOUND\";\n readonly RULE_READ_FAILED: \"RULE_READ_FAILED\";\n readonly TARGET_NOT_ON_RULE_CHAIN: \"TARGET_NOT_ON_RULE_CHAIN\";\n readonly WALLET_BALANCE_INSUFFICIENT: \"WALLET_BALANCE_INSUFFICIENT\";\n readonly WALLET_NOT_DEPLOYED: \"WALLET_NOT_DEPLOYED\";\n}", + "members": { + "AGENT_GAS_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\"" + }, + "AGENT_IS_OWNER": { + "optional": false, + "readonly": true, + "type": "\"AGENT_IS_OWNER\"" + }, + "ASSET_CHAIN_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"ASSET_CHAIN_MISMATCH\"" + }, + "CAPABILITY_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"CAPABILITY_UNAVAILABLE\"" + }, + "CREATE_PARTIAL": { + "optional": false, + "readonly": true, + "type": "\"CREATE_PARTIAL\"" + }, + "DUPLICATE_RULE": { + "optional": false, + "readonly": true, + "type": "\"DUPLICATE_RULE\"" + }, + "FROM_NOT_ALLOWED": { + "optional": false, + "readonly": true, + "type": "\"FROM_NOT_ALLOWED\"" + }, + "GATEWAY_ALLOWANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"GATEWAY_ALLOWANCE_INSUFFICIENT\"" + }, + "GENERATION_UNSUPPORTED": { + "optional": false, + "readonly": true, + "type": "\"GENERATION_UNSUPPORTED\"" + }, + "INCONSISTENT_READ": { + "optional": false, + "readonly": true, + "type": "\"INCONSISTENT_READ\"" + }, + "INDEX_RACE": { + "optional": false, + "readonly": true, + "type": "\"INDEX_RACE\"" + }, + "INVALID_RULE": { + "optional": false, + "readonly": true, + "type": "\"INVALID_RULE\"" + }, + "NO_RULES_FOR_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"NO_RULES_FOR_CHAIN\"" + }, + "NOT_AGENTIC_WALLET": { + "optional": false, + "readonly": true, + "type": "\"NOT_AGENTIC_WALLET\"" + }, + "NOT_ALLOWED_IN_AGENTIC_MODE": { + "optional": false, + "readonly": true, + "type": "\"NOT_ALLOWED_IN_AGENTIC_MODE\"" + }, + "NOT_OWNER_OR_AGENT": { + "optional": false, + "readonly": true, + "type": "\"NOT_OWNER_OR_AGENT\"" + }, + "NOT_WALLET_OWNER": { + "optional": false, + "readonly": true, + "type": "\"NOT_WALLET_OWNER\"" + }, + "READ_ONLY": { + "optional": false, + "readonly": true, + "type": "\"READ_ONLY\"" + }, + "RECEIPT_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_MISMATCH\"" + }, + "RECEIPT_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_UNAVAILABLE\"" + }, + "REVOKE_NEEDS_TARGET": { + "optional": false, + "readonly": true, + "type": "\"REVOKE_NEEDS_TARGET\"" + }, + "RULE_LIMIT_EXCEEDED": { + "optional": false, + "readonly": true, + "type": "\"RULE_LIMIT_EXCEEDED\"" + }, + "RULE_NOT_FOUND": { + "optional": false, + "readonly": true, + "type": "\"RULE_NOT_FOUND\"" + }, + "RULE_READ_FAILED": { + "optional": false, + "readonly": true, + "type": "\"RULE_READ_FAILED\"" + }, + "TARGET_NOT_ON_RULE_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"TARGET_NOT_ON_RULE_CHAIN\"" + }, + "WALLET_BALANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"WALLET_BALANCE_INSUFFICIENT\"" + }, + "WALLET_NOT_DEPLOYED": { + "optional": false, + "readonly": true, + "type": "\"WALLET_NOT_DEPLOYED\"" + } + } + }, + "Rule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule | import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "NativeRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "amount": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AmountLimit | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "maxCalls": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValuePerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxValueTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "pins": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ArgPin[] | undefined" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "AssetCap": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap", + "members": { + "maxPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/constants/tokens\").MoveableToken" + } + } + }, + "AllowedCall": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall", + "members": { + "beneficiary": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValue": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "`${string}(${string})` | `0x${string}`" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "UniversalRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall[]" + }, + "assets": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap[]" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "`eip155:${string}` | `solana:${string}`" + }, + "maxGasPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "RulesRecord": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "enabled": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "ref": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "rule": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule | import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule" + }, + "rulesId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "CreateOptions": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions", + "members": { + "progressHook": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook | undefined" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Rule[]" + } + } + }, + "CreateResult": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateResult", + "members": { + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "rulesIds": { + "optional": false, + "readonly": false, + "type": "`0x${string}`[]" + }, + "tx": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticTxMetadata": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticTxMetadata", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destinationAccount": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "destinationCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "door": { + "optional": false, + "readonly": false, + "type": "\"agent\" | \"owner\"" + }, + "nativeCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "rawData": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rawTo": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesId": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + } + }, + "publicSurface": { + "CHAIN": { + "type": "typeof import(\"sdk/src/lib/constants/enums\").CHAIN", + "members": { + "ARBITRUM_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA" + }, + "BASE_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA" + }, + "BNB_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET" + }, + "ETHEREUM_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET" + }, + "ETHEREUM_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA" + }, + "PUSH_LOCALNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET" + }, + "PUSH_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET" + }, + "PUSH_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET" + }, + "PUSH_TESTNET_DONUT": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET" + }, + "SOLANA_DEVNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET" + }, + "SOLANA_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET" + }, + "SOLANA_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET" + }, + "WEB2": { + "optional": false, + "readonly": false, + "type": "\"web2\"" + } + } + }, + "ConversionQuote": { + "type": "import(\"sdk/src/lib/constants/tokens\").ConversionQuote", + "members": { + "amountIn": { + "optional": false, + "readonly": false, + "type": "string" + }, + "amountOut": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rate": { + "optional": false, + "readonly": false, + "type": "number" + }, + "route": { + "optional": true, + "readonly": false, + "type": "string[] | undefined" + }, + "timestamp": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "UniversalSigner": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalSigner", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "signAndSendTransaction": { + "optional": false, + "readonly": false, + "type": "(unsignedTx: Uint8Array) => Promise" + }, + "signAuthorization": { + "optional": true, + "readonly": false, + "type": "((params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise) | undefined" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": true, + "readonly": false, + "type": "(({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise) | undefined" + } + } + }, + "UniversalAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "UniversalSignerSkeleton": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "signAndSendTransaction": { + "optional": false, + "readonly": false, + "type": "(unsignedTx: Uint8Array) => Promise" + }, + "signAuthorization": { + "optional": true, + "readonly": false, + "type": "((params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise) | undefined" + }, + "signerId": { + "optional": false, + "readonly": false, + "type": "string" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": true, + "readonly": false, + "type": "(({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise) | undefined" + } + } + }, + "SignAuthorizationParams": { + "type": "{\n chainId?: number;\n contractAddress: `0x${string}`;\n executor?: \"self\";\n nonce?: number;\n}", + "members": { + "chainId": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "contractAddress": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "executor": { + "optional": true, + "readonly": false, + "type": "\"self\" | undefined" + }, + "nonce": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "SignedAuthorization": { + "type": "{\n address: `0x${string}`;\n chainId: number;\n nonce: number;\n r: `0x${string}`;\n s: `0x${string}`;\n v?: bigint;\n yParity: number;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainId": { + "optional": false, + "readonly": false, + "type": "number" + }, + "nonce": { + "optional": false, + "readonly": false, + "type": "number" + }, + "r": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "s": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "v": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "yParity": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "DerivedExecutorAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").DerivedExecutorAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean | null" + } + } + }, + "ResolvedAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainName": { + "optional": false, + "readonly": false, + "type": "string" + }, + "exists": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "role": { + "optional": true, + "readonly": false, + "type": "\"controller\" | undefined" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"cea\" | \"uea\" | \"uoa\"" + } + } + }, + "ResolvedControllerAccounts": { + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedControllerAccounts", + "members": { + "accounts": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedAccount[]" + } + } + }, + "AccountType": { + "type": "\"cea\" | \"uea\" | \"uoa\"", + "members": {} + }, + "AccountRole": { + "type": "\"controller\"", + "members": {} + }, + "PC20TokenReference": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "FundsToken": { + "type": "import(\"sdk/src/lib/constants/tokens\").MoveableToken | import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20TokenReference", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "PC20RegistryEntry": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "chainName": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "PC20AddressResult": { + "type": "{\n address: `0x${string}`;\n decimals: number;\n name: string;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n registry: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20RegistryEntry[];\n symbol: string;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "decimals": { + "optional": false, + "readonly": false, + "type": "number" + }, + "name": { + "optional": false, + "readonly": false, + "type": "string" + }, + "network": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "registry": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20RegistryEntry[]" + }, + "symbol": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "isPC20Reference": { + "type": "(token: import(\"sdk/src/lib/orchestrator/orchestrator.types\").FundsToken | undefined) => token is import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20TokenReference", + "members": {} + }, + "PC20Error": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20Error", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidPC20AddressError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InvalidPC20AddressError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20TokenChainMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20TokenChainMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20WrapperNotRegisteredError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20WrapperNotRegisteredError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20RegistryMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20RegistryMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20FactoryMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20FactoryMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidPC20MetadataError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InvalidPC20MetadataError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20ExpectedButPRC20Error": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20ExpectedButPRC20Error", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20AmbiguousAddressError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20AmbiguousAddressError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "candidates": { + "optional": false, + "readonly": true, + "type": "{\n chain: string;\n pushAddress: string;\n}[]" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "UnsupportedPC20DestinationError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").UnsupportedPC20DestinationError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InsufficientPC20BalanceError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InsufficientPC20BalanceError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20UnknownChainNamespaceError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20UnknownChainNamespaceError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20WrapperPredictionUnavailableError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20WrapperPredictionUnavailableError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20ExportRevertedError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20ExportRevertedError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "lockedAmount": { + "optional": true, + "readonly": true, + "type": "bigint | undefined" + }, + "outboundTxId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "revertRecipient": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20UnsafeEmptyPayloadError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20UnsafeEmptyPayloadError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ChainTarget": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "ChainSource": { + "type": "{\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "UniversalTo": { + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget", + "members": {} + }, + "TransactionRouteType": { + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"", + "members": {} + }, + "UniversalExecuteParams": { + "type": "{\n from?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainSource;\n migration?: boolean;\n to: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTo;\n} & Omit", + "members": { + "_minimumDepositUsd": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "_requiredFundsOverride": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "_skipFeeLocking": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "_ueaStatus": { + "optional": true, + "readonly": false, + "type": "{\n balance: bigint;\n isDeployed: boolean;\n nonce: bigint;\n} | undefined" + }, + "data": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiCall[] | undefined" + }, + "deadline": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "feeLockTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "from": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainSource | undefined" + }, + "funds": { + "optional": true, + "readonly": false, + "type": "{\n amount: bigint;\n token?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").FundsToken;\n} | undefined" + }, + "gasLimit": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFeePerGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxPCForGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxPriorityFeePerGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "migration": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "nonce": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "options": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions | undefined" + }, + "payGasWith": { + "optional": true, + "readonly": false, + "type": "{\n minAmountOut?: bigint | string;\n slippageBps?: number;\n token?: import(\"sdk/src/lib/constants/tokens\").PayableToken;\n} | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "to": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget" + }, + "value": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "UniversalOutboundTxRequest": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalOutboundTxRequest", + "members": { + "amount": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gasPrice": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxPCForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "payload": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "recipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "revertRecipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "PreparedUniversalTx": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx", + "members": { + "_hop": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").HopDescriptor" + }, + "deadline": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "estimatedGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gatewayRequest": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalOutboundTxRequest | import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxRequest" + }, + "nonce": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "payload": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + } + } + }, + "CascadedTxResponse": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadedTxResponse", + "members": { + "finalTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hopCount": { + "optional": false, + "readonly": false, + "type": "number" + }, + "hops": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo[]" + }, + "initialTxHash": { + "optional": false, + "readonly": false, + "type": "string" + }, + "initialTxResponse": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions) => Promise" + }, + "waitForAll": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions) => Promise" + } + } + }, + "CascadeHopInfo": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo", + "members": { + "executionChain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "expectedSubTxId": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hopIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "outboundDetails": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").OutboundTxDetails | undefined" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + }, + "status": { + "optional": false, + "readonly": false, + "type": "\"confirmed\" | \"failed\" | \"pending\" | \"submitted\"" + }, + "txHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "CascadeTrackOptions": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions", + "members": { + "eventHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeProgressEvent) => void) | undefined" + }, + "timeout": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "CascadeProgressEvent": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeProgressEvent", + "members": { + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "elapsed": { + "optional": false, + "readonly": false, + "type": "number" + }, + "hopIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + }, + "status": { + "optional": false, + "readonly": false, + "type": "\"confirmed\" | \"failed\" | \"found\" | \"polling\" | \"timeout\" | \"waiting\"" + }, + "txHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "CascadeCompletionResult": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeCompletionResult", + "members": { + "failedAt": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "finalTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "finalTxResponse": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadedTxResponse | undefined" + }, + "hops": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo[]" + }, + "success": { + "optional": false, + "readonly": false, + "type": "boolean" + } + } + }, + "MultiChainTxResponse": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiChainTxResponse", + "members": { + "chains": { + "optional": false, + "readonly": false, + "type": "{\n blockNumber: bigint;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n hash: string;\n status: \"confirmed\" | \"failed\" | \"pending\";\n}[]" + }, + "transactions": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse[]" + } + } + }, + "OutboundTxDetails": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").OutboundTxDetails", + "members": { + "amount": { + "optional": false, + "readonly": false, + "type": "string" + }, + "assetAddr": { + "optional": false, + "readonly": false, + "type": "string" + }, + "destinationChain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "explorerUrl": { + "optional": false, + "readonly": false, + "type": "string" + }, + "externalTxHash": { + "optional": false, + "readonly": false, + "type": "string" + }, + "recipient": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "WaitForOutboundOptions": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").WaitForOutboundOptions", + "members": { + "_expectedDestinationChain": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "_outboundIndex": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "_resolvedSubTxId": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "initialWaitMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: {\n elapsed: number;\n status: \"failed\" | \"found\" | \"polling\" | \"timeout\" | \"waiting\";\n}) => void) | undefined" + }, + "timeout": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "SvmGatewayAccountMeta": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmGatewayAccountMeta", + "members": { + "isWritable": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "pubkey": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "SvmExecutePayloadFields": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmExecutePayloadFields", + "members": { + "accounts": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmGatewayAccountMeta[]" + }, + "instructionId": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "ixData": { + "optional": false, + "readonly": false, + "type": "Uint8Array" + }, + "targetProgram": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AccountStatus": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus", + "members": { + "mode": { + "optional": false, + "readonly": false, + "type": "\"read-only\" | \"signer\"" + }, + "uea": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UEAStatus" + } + } + }, + "UEAStatus": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UEAStatus", + "members": { + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "loaded": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "minRequiredVersion": { + "optional": false, + "readonly": false, + "type": "string" + }, + "requiresUpgrade": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "version": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "RescueFundsParams": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").RescueFundsParams", + "members": { + "prc20": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "universalTxId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "parseUEAVersion": { + "type": "(version: string) => number", + "members": {} + }, + "TransactionRoute": { + "type": "typeof import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute", + "members": { + "CEA_TO_CEA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.CEA_TO_CEA" + }, + "CEA_TO_PUSH": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.CEA_TO_PUSH" + }, + "UOA_TO_CEA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.UOA_TO_CEA" + }, + "UOA_TO_PUSH": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.UOA_TO_PUSH" + } + } + }, + "detectRoute": { + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams) => import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute", + "members": {} + }, + "isChainTarget": { + "type": "(to: unknown) => to is import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget", + "members": {} + }, + "DEFAULT_MAX_PC_FOR_GAS_BUFFER_BPS": { + "type": "1000", + "members": {} + }, + "MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT": { + "type": "10000", + "members": {} + }, + "quoteMaxPCForGasCap": { + "type": "(input: import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapInput) => import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": {} + }, + "quoteMaxPCForGasCapFromNativeValue": { + "type": "(input: import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapFromNativeValueInput) => import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": {} + }, + "MaxPCForGasCapInput": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapInput", + "members": { + "bufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "gasLegNativePc": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "MaxPCForGasCapFromNativeValueInput": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapFromNativeValueInput", + "members": { + "bufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "nativeValueForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "MaxPCForGasCapQuote": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": { + "bufferBps": { + "optional": false, + "readonly": false, + "type": "number" + }, + "gasLegNativePc": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxPCForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "nativeValueForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "getCEAAddress": { + "type": "(ueaAddress: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise", + "members": {} + }, + "getPushAccountForCEA": { + "type": "(ceaAddress: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise<`0x${string}`>", + "members": {} + }, + "isCEA": { + "type": "(address: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise", + "members": {} + }, + "chainSupportsCEA": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "chainSupportsOutbound": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "getCEAFactoryAddress": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => `0x${string}` | undefined", + "members": {} + }, + "getAllCEAAddresses": { + "type": "(ueaAddress: `0x${string}`, rpcUrls?: Partial>) => Promise", + "members": {} + }, + "encodeSvmExecutePayload": { + "type": "(fields: import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmExecutePayloadFields) => `0x${string}`", + "members": {} + }, + "isSvmChain": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "isValidSolanaHexAddress": { + "type": "(address: string) => boolean", + "members": {} + }, + "buildMigrationPayload": { + "type": "() => `0x${string}`", + "members": {} + }, + "buildErc20WithdrawalMulticall": { + "type": "(tokenAddress: `0x${string}`, recipientAddress: `0x${string}`, amount: bigint) => import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiCall[]", + "members": {} + }, + "ReadChain": { + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain", + "members": {} + }, + "ReadDestination": { + "type": "{\n chain: import(\"sdk/src/lib/read-state/read-state.types\").ReadChain;\n} | {\n chainId: string;\n chainNamespace: string;\n}", + "members": {} + }, + "ResolvedDestination": { + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}", + "members": { + "caip2": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainId": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "namespace": { + "optional": false, + "readonly": false, + "type": "\"eip155\" | \"solana\" | \"web2\"" + } + } + }, + "ReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").SvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery", + "members": { + "type": { + "optional": false, + "readonly": false, + "type": "\"accountBalance\" | \"contractCall\" | \"http\" | \"lamportBalance\" | \"rawAccountData\" | \"splTokenAccount\" | \"storageSlot\"" + } + } + }, + "EvmReadQuery": { + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n target: `0x${string}`;\n type: \"contractCall\";\n} | {\n callData: `0x${string}`;\n target: `0x${string}`;\n type: \"contractCall\";\n} | {\n slot: `0x${string}` | bigint;\n target: `0x${string}`;\n type: \"storageSlot\";\n} | {\n target: `0x${string}`;\n type: \"accountBalance\";\n}", + "members": { + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"accountBalance\" | \"contractCall\" | \"storageSlot\"" + } + } + }, + "SvmReadQuery": { + "type": "{\n account: string | Uint8Array;\n accountName?: string;\n idl?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n type: \"rawAccountData\";\n} | {\n account: string | Uint8Array;\n type: \"lamportBalance\";\n} | {\n account: string | Uint8Array;\n type: \"splTokenAccount\";\n}", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "string | Uint8Array" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"lamportBalance\" | \"rawAccountData\" | \"splTokenAccount\"" + } + } + }, + "Web2ReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery", + "members": { + "body": { + "optional": true, + "readonly": false, + "type": "string | Uint8Array | undefined" + }, + "extract": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[]" + }, + "headers": { + "optional": true, + "readonly": false, + "type": "Record | undefined" + }, + "method": { + "optional": true, + "readonly": false, + "type": "\"GET\" | \"POST\" | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"http\"" + }, + "url": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "Web2Extract": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract", + "members": { + "decimals": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "path": { + "optional": false, + "readonly": false, + "type": "string" + }, + "valueType": { + "optional": false, + "readonly": false, + "type": "\"bool\" | \"bytes\" | \"int256\" | \"string\" | \"uint256\"" + } + } + }, + "Web2ValueType": { + "type": "\"bool\" | \"bytes\" | \"int256\" | \"string\" | \"uint256\"", + "members": {} + }, + "EncodedReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery", + "members": { + "blockRef": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "encoded": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "namespace": { + "optional": false, + "readonly": false, + "type": "\"eip155\" | \"solana\" | \"web2\"" + }, + "ownerBytes": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "queryType": { + "optional": false, + "readonly": false, + "type": "number" + }, + "resultShape": { + "optional": false, + "readonly": false, + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}" + }, + "warnings": { + "optional": false, + "readonly": false, + "type": "string[]" + } + } + }, + "ReadResultShape": { + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"bytes32\" | \"evmCall\" | \"raw\" | \"svmAccount\" | \"uint256\" | \"web2\"" + } + } + }, + "DecodedReadResult": { + "type": "{\n accountName: string;\n kind: \"svmAccount\";\n value: unknown;\n} | {\n kind: \"bytes32\";\n value: `0x${string}`;\n} | {\n kind: \"evmCall\";\n value: unknown;\n} | {\n kind: \"raw\";\n value: `0x${string}`;\n} | {\n kind: \"uint256\";\n value: bigint;\n} | {\n kind: \"web2\";\n values: readonly unknown[];\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"bytes32\" | \"evmCall\" | \"raw\" | \"svmAccount\" | \"uint256\" | \"web2\"" + } + } + }, + "ReadPreflight": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight", + "members": { + "destination": { + "optional": false, + "readonly": false, + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}" + }, + "fetchedAt": { + "optional": false, + "readonly": false, + "type": "number" + }, + "observedChainHeight": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pushBlockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pushGasPrice": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "universalCallback": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "universalCore": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ReadSpec": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "{\n chainId: string;\n chainNamespace: string;\n owner: `0x${string}`;\n}" + }, + "blockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "expiryPushChainHeight": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "minConfirmations": { + "optional": false, + "readonly": false, + "type": "number" + }, + "query": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "revertRecipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ReadSpecTuple": { + "type": "readonly [\n readonly [\n string,\n string,\n `0x${string}`\n ],\n `0x${string}`,\n number,\n bigint,\n bigint,\n bigint,\n `0x${string}`\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "readonly [\n string,\n string,\n `0x${string}`\n]" + }, + "1": { + "optional": false, + "readonly": true, + "type": "`0x${string}`" + }, + "2": { + "optional": false, + "readonly": true, + "type": "number" + }, + "3": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "4": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "5": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "6": { + "optional": false, + "readonly": true, + "type": "`0x${string}`" + }, + "length": { + "optional": false, + "readonly": true, + "type": "7" + } + } + }, + "BuildReadSpecParams": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").BuildReadSpecParams", + "members": { + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "budgetBuffer": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback | undefined" + }, + "callbackBudget": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "destination": { + "optional": false, + "readonly": false, + "type": "{\n chain: import(\"sdk/src/lib/read-state/read-state.types\").ReadChain;\n} | {\n chainId: string;\n chainNamespace: string;\n}" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "expiryPushChainHeight": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFeeBufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "owner": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "query": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").SvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "PreparedRead": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead", + "members": { + "__@preparedReadValue": { + "optional": true, + "readonly": true, + "type": "T | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback | undefined" + }, + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "encodedQuery": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery" + }, + "encodedSpec": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "fees": { + "optional": false, + "readonly": false, + "type": "{\n callbackBudget: bigint;\n protocolFee: bigint;\n total: bigint;\n}" + }, + "preflight": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "queryKey": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "resultShape": { + "optional": false, + "readonly": false, + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}" + }, + "spec": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec" + }, + "specTuple": { + "optional": false, + "readonly": false, + "type": "readonly [\n readonly [\n string,\n string,\n `0x${string}`\n ],\n `0x${string}`,\n number,\n bigint,\n bigint,\n bigint,\n `0x${string}`\n]" + }, + "value": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "warnings": { + "optional": false, + "readonly": false, + "type": "string[]" + } + } + }, + "ReadCallback": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "((spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpecTuple, callbackGasLimit: bigint) => readonly unknown[]) | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "gasLimit": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "target": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "SimulateReadResult": { + "type": "{\n args?: readonly unknown[];\n error: string;\n errorName?: string;\n ok: false;\n} | {\n ok: true;\n}", + "members": { + "ok": { + "optional": false, + "readonly": false, + "type": "boolean" + } + } + }, + "ParsedReadRequest": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ParsedReadRequest", + "members": { + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackTarget": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "logIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "originalFunder": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "requestId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "requestIdUint": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "spec": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec" + }, + "totalPaid": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "FulfilOutcome": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").FulfilOutcome", + "members": { + "burned": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "delivered": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "expired": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "failReason": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "gasReported": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refunded": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refundFailed": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "ReceiptLike": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike", + "members": { + "logs": { + "optional": false, + "readonly": false, + "type": "readonly {\n address: string;\n data: string;\n logIndex?: number | string;\n topics: readonly string[];\n}[]" + } + } + }, + "ReadRef": { + "type": "{\n requestId: `0x${string}` | bigint;\n} | {\n txHash: `0x${string}`;\n}", + "members": {} + }, + "ReadLifecycleOptions": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadLifecycleOptions", + "members": { + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "resultShape": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadFees": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadFees", + "members": { + "burned": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "paid": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "refunded": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refundFailed": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + } + } + }, + "UniversalReadResponse": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse", + "members": { + "callbackDelivered": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "callbackFailReason": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "decoded": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").DecodedReadResult | undefined" + }, + "decodeError": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destination": { + "optional": false, + "readonly": false, + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}" + }, + "errorMsg": { + "optional": false, + "readonly": false, + "type": "string" + }, + "explorerUrl": { + "optional": false, + "readonly": false, + "type": "string" + }, + "fees": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadFees" + }, + "isTerminal": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "outcome": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME" + }, + "pcTx": { + "optional": false, + "readonly": false, + "type": "readonly {\n blockHeight: number;\n errorMsg: string;\n status: string;\n txHash: `0x${string}`;\n}[]" + }, + "raw": { + "optional": false, + "readonly": false, + "type": "{\n errorCode: import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n resultData: `0x${string}`;\n status: import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n} | null" + }, + "refresh": { + "optional": false, + "readonly": false, + "type": "() => Promise>" + }, + "request": { + "optional": false, + "readonly": false, + "type": "{\n callbackGasLimit: bigint;\n callbackTarget: `0x${string}`;\n createdAtHeight: bigint;\n logIndex: number;\n originalFunder: `0x${string}`;\n refundTo: `0x${string}`;\n spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec;\n}" + }, + "requestId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "requestIdUint": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "status": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "value": { + "optional": true, + "readonly": false, + "type": "T | undefined" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/read-state/read-state.types\").ReadLifecycleOptions) => Promise>" + } + } + }, + "ReadResponseTuple": { + "type": "{\n -readonly [K in keyof R]: import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse ? T : unknown>;\n}", + "members": {} + }, + "BatchReadResponse": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").BatchReadResponse", + "members": { + "atomic": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "count": { + "optional": false, + "readonly": false, + "type": "number" + }, + "reads": { + "optional": false, + "readonly": false, + "type": "{\n -readonly [K in keyof R]: import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse ? T : unknown>;\n}" + }, + "transactionHashes": { + "optional": true, + "readonly": false, + "type": "readonly `0x${string}`[] | undefined" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: Omit) => Promise>" + } + } + }, + "ReadOptions": { + "type": "((import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">)) & {\n callback?: (Pick & Required>) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n };\n}", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "advanced": { + "optional": true, + "readonly": false, + "type": "{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n} | undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "({\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} & {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n}) | ({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick & Pick & Required>) | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadPrepareOptions": { + "type": "((((({\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\">) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n}) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">)) & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n}) | ((({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n}) | ({\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\">)) & {\n blockNumber?: never;\n minConfirmations?: never;\n})) & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n}) & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "advanced": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadQueryOptions": { + "type": "({\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\">) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n}) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n}) | ({\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\">)", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadCallbackOptions": { + "type": "{\n callback?: ({\n gasLimit?: bigint;\n target: `0x${string}`;\n } & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n };\n}", + "members": { + "callback": { + "optional": true, + "readonly": false, + "type": "({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} | undefined" + } + } + }, + "ReadValue": { + "type": "O extends {\n abi: infer A extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: infer F extends string;\n} ? number extends A[\"length\"] ? unknown : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, O extends {\n args: infer Args extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n} ? Args : readonly [\n] extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> ? import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> & readonly [\n] : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>> extends infer Selected ? Selected extends {\n outputs: readonly unknown[];\n type: \"function\";\n} & import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiFunction ? {\n [key in keyof {\n [key in keyof import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"]]: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterToPrimitiveType, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"][key], import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterKind>;\n }]: {\n [key in keyof import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"]]: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterToPrimitiveType, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"][key], import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterKind>;\n }[key];\n} extends infer types ? types extends readonly [\n] ? void : types extends readonly [\n infer type\n] ? type : types : never : never : never : O extends {\n web2: {\n extract: infer E extends readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n };\n} ? {\n readonly [K in keyof E]: {\n bool: boolean;\n bytes: `0x${string}`;\n int256: bigint;\n string: string;\n uint256: bigint;\n }[E[K][\"valueType\"]];\n} : O extends {\n storageSlot: unknown;\n} ? `0x${string}` : O extends {\n idl: infer I extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} ? string extends Extract, string> ? unknown : (O extends {\n functionName: infer N extends string;\n} ? N : undefined) extends string ? import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/index\").IdlAccounts[{\n [K in Extract, string>]: Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : K> extends Lowercase<(O extends {\n functionName: infer N extends string;\n } ? N : undefined) & string extends `${infer H}_${infer T}` ? `${H}${Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : (O extends {\n functionName: infer N extends string;\n } ? N : undefined) & string> ? K : never;\n}[Extract, string>]] : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/index\").IdlAccounts[Extract, string>] : bigint", + "members": {} + }, + "ValidateReadCall": { + "type": "O extends {\n abi: infer A extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: infer F extends string;\n} ? (readonly [\n] extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> ? {\n args?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n} : {\n args: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n}) & {\n functionName: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionName;\n} : O extends {\n functionName: infer N extends string;\n idl: infer I extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} ? string extends Extract, string> ? unknown : [\n {\n [K in Extract, string>]: Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : K> extends Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : N> ? K : never;\n }[Extract, string>]\n] extends [\n never\n] ? {\n functionName: Extract, string>;\n} : unknown : unknown", + "members": {} + }, + "ReadWeb2Options": { + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options", + "members": { + "body": { + "optional": true, + "readonly": false, + "type": "string | Uint8Array | undefined" + }, + "extract": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[]" + }, + "headers": { + "optional": true, + "readonly": false, + "type": "Record | undefined" + }, + "method": { + "optional": true, + "readonly": false, + "type": "\"GET\" | \"POST\" | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadTrackOptions": { + "type": "{\n advanced?: Omit, \"enforceGasCheck\">;\n resultShape?: import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape;\n}", + "members": { + "advanced": { + "optional": true, + "readonly": false, + "type": "Omit<{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n}, \"enforceGasCheck\"> | undefined" + }, + "resultShape": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape | undefined" + } + } + }, + "ReadExecuteOptions": { + "type": "{\n advanced?: {\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n } | undefined;\n progressHook?: ((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined;\n waitForCompletion?: boolean | undefined;\n}", + "members": { + "advanced": { + "optional": true, + "readonly": false, + "type": "{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n} | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + } + } + }, + "UNIVERSAL_READ_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS", + "members": { + "ABORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.ABORTED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.EXPIRED" + }, + "FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.FAILED" + }, + "FULFILLED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.FULFILLED" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.PENDING" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.UNSPECIFIED" + }, + "VOTING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.VOTING" + } + } + }, + "READ_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS", + "members": { + "ERROR": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.ERROR" + }, + "SUCCESS": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.SUCCESS" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.UNSPECIFIED" + } + } + }, + "READ_ERROR_CODE": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE", + "members": { + "INVALID_QUERY": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.INVALID_QUERY" + }, + "INVALID_RESULT": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.INVALID_RESULT" + }, + "NOT_FOUND": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.NOT_FOUND" + }, + "REJECTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.REJECTED" + }, + "REVERTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.REVERTED" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.UNSPECIFIED" + }, + "UNSUPPORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.UNSUPPORTED" + } + } + }, + "READ_OUTCOME": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME", + "members": { + "ABORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.ABORTED" + }, + "CALLBACK_FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.CALLBACK_FAILED" + }, + "DECODE_FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.DECODE_FAILED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.EXPIRED" + }, + "FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.FAILED" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.PENDING" + }, + "SOURCE_ERROR": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.SOURCE_ERROR" + }, + "SUCCESS": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.SUCCESS" + }, + "UNKNOWN": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.UNKNOWN" + } + } + }, + "CONTRACT_REQUEST_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS", + "members": { + "EXECUTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.EXECUTED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.EXPIRED" + }, + "NONE": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.NONE" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.PENDING" + }, + "SETTLED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.SETTLED" + } + } + }, + "TERMINAL_READ_STATUSES": { + "type": "ReadonlySet", + "members": {} + }, + "ReadStateError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadStateError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidReadQueryError": { + "type": "import(\"sdk/src/lib/read-state/errors\").InvalidReadQueryError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidReadSpecError": { + "type": "import(\"sdk/src/lib/read-state/errors\").InvalidReadSpecError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "violations": { + "optional": false, + "readonly": true, + "type": "readonly import(\"sdk/src/lib/read-state/errors\").ReadSpecViolation[]" + } + } + }, + "ReadHeightUnavailableError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadHeightUnavailableError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "UnsupportedReadDestinationError": { + "type": "import(\"sdk/src/lib/read-state/errors\").UnsupportedReadDestinationError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadDecodeError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadDecodeError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadTimeoutError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadTimeoutError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "lastStatus": { + "optional": false, + "readonly": true, + "type": "number" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadNotFoundError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadNotFoundError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadRegistryUnavailableError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadRegistryUnavailableError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadSpecViolation": { + "type": "\"CALLBACK_GAS_LIMIT_EXCEEDED\" | \"DOMAIN_BLOCKED\" | \"EMPTY_QUERY\" | \"EXCESSIVE_FEE\" | \"INSUFFICIENT_CALLBACK_BUDGET\" | \"INSUFFICIENT_FEE\" | \"INVALID_ACCOUNT_ID\" | \"INVALID_BLOCK_NUMBER\" | \"INVALID_EXPIRY_HEIGHT\" | \"INVALID_MIN_CONFIRMATIONS\" | \"SVM_OWNER_NOT_32_BYTES\" | \"ZERO_CALLBACK_BUDGET\" | \"ZERO_CALLBACK_GAS_LIMIT\" | \"ZERO_REVERT_RECIPIENT\"", + "members": {} + }, + "resolveDestination": { + "type": "(dest: import(\"sdk/src/lib/read-state/read-state.types\").ReadDestination) => import(\"sdk/src/lib/read-state/read-state.types\").ResolvedDestination", + "members": {} + }, + "encodeReadQuery": { + "type": "(destination: import(\"sdk/src/lib/read-state/read-state.types\").ReadDestination, query: import(\"sdk/src/lib/read-state/read-state.types\").ReadQuery, options?: {\n blockNumber?: bigint;\n minSlot?: bigint;\n}) => import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery", + "members": {} + }, + "decodeReadResult": { + "type": "(resultData: `0x${string}`, shape: import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape) => import(\"sdk/src/lib/read-state/read-state.types\").DecodedReadResult", + "members": {} + }, + "parseReadRequestsFromReceipt": { + "type": "(receipt: import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike, universalCallback: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").ParsedReadRequest[]", + "members": {} + }, + "parseFulfilOutcome": { + "type": "(receipt: import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike, universalCallback: `0x${string}`, requestId: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").FulfilOutcome", + "members": {} + }, + "buildReadSpecFromPreflight": { + "type": "(preflight: import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight, params: import(\"sdk/src/lib/read-state/read-state.types\").BuildReadSpecParams, defaults?: {\n refundTo?: `0x${string}`;\n}) => import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead", + "members": {} + }, + "validateReadSpec": { + "type": "(input: import(\"sdk/src/lib/read-state/validate\").ValidateReadSpecInput) => {\n ok: false;\n violations: import(\"sdk/src/lib/read-state/errors\").ReadSpecViolation[];\n} | {\n ok: true;\n}", + "members": {} + }, + "toCallData": { + "type": "(prepared: import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead, target: {\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: (spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpecTuple, callbackGasLimit: bigint) => readonly unknown[];\n functionName: string;\n}) => {\n data: `0x${string}`;\n value: bigint;\n}", + "members": {} + }, + "sizeCallbackBudget": { + "type": "(callbackGasLimit: bigint, pushGasPrice: bigint, buffer?: number) => bigint", + "members": {} + }, + "inferResultShape": { + "type": "(namespace: string, query: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape", + "members": {} + }, + "toRequestIdHex": { + "type": "(id: `0x${string}` | bigint) => `0x${string}`", + "members": {} + }, + "toReadQuery": { + "type": "(subject: string, o: ReadOptionsInput, resolvedTokenProgram?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@solana/web3.js/lib/index\").PublicKey) => import(\"sdk/src/lib/read-state/read-state.types\").ReadQuery", + "members": {} + }, + "UNIVERSAL_CALLBACK_EVM": { + "type": "readonly [\n {\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"requestExternalReadSelf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"estimateFee\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"statusOf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"enum RequestStatus\";\n readonly name: \"\";\n readonly type: \"uint8\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"isFulfilled\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getPendingRead\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly internalType: \"struct PendingRead\";\n readonly name: \"\";\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"totalEscrowed\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"blockedDomains\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly indexed: false;\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"readSpec\";\n readonly type: \"tuple\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"totalPaid\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"protocolFee\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ReadRequested\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"ReadFulfilled\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"reason\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"CallbackFailed\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"gasReported\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"burned\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"CallbackGasReported\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundSent\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundFailed\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RequestExpired\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"vaultPC\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ProtocolFeeDistributed\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidAccountId\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"EmptyQuery\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidMinConfirmations\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"DomainBlocked\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidBlockNumber\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidExpiryHeight\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroRevertRecipient\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroCallbackGasLimit\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint64\";\n readonly name: \"provided\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"max\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"CallbackGasLimitExceeded\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"required\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"InsufficientFee\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ExcessiveFee\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"actual\";\n readonly type: \"uint8\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"expected\";\n readonly type: \"uint8\";\n }\n ];\n readonly name: \"InvalidRequestStatus\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ContractIsPaused\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"CallerIsNotUCallbackModule\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n }\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"requestExternalReadSelf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n}" + }, + "1": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"estimateFee\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "2": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"statusOf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"enum RequestStatus\";\n readonly name: \"\";\n readonly type: \"uint8\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "3": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"isFulfilled\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "4": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getPendingRead\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly internalType: \"struct PendingRead\";\n readonly name: \"\";\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "5": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"totalEscrowed\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "6": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"blockedDomains\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "7": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly indexed: false;\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"readSpec\";\n readonly type: \"tuple\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"totalPaid\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"protocolFee\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ReadRequested\";\n readonly type: \"event\";\n}" + }, + "8": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"ReadFulfilled\";\n readonly type: \"event\";\n}" + }, + "9": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"reason\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"CallbackFailed\";\n readonly type: \"event\";\n}" + }, + "10": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"gasReported\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"burned\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"CallbackGasReported\";\n readonly type: \"event\";\n}" + }, + "11": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundSent\";\n readonly type: \"event\";\n}" + }, + "12": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundFailed\";\n readonly type: \"event\";\n}" + }, + "13": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RequestExpired\";\n readonly type: \"event\";\n}" + }, + "14": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"vaultPC\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ProtocolFeeDistributed\";\n readonly type: \"event\";\n}" + }, + "15": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidAccountId\";\n readonly type: \"error\";\n}" + }, + "16": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"EmptyQuery\";\n readonly type: \"error\";\n}" + }, + "17": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidMinConfirmations\";\n readonly type: \"error\";\n}" + }, + "18": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"DomainBlocked\";\n readonly type: \"error\";\n}" + }, + "19": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidBlockNumber\";\n readonly type: \"error\";\n}" + }, + "20": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidExpiryHeight\";\n readonly type: \"error\";\n}" + }, + "21": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroRevertRecipient\";\n readonly type: \"error\";\n}" + }, + "22": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroCallbackGasLimit\";\n readonly type: \"error\";\n}" + }, + "23": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint64\";\n readonly name: \"provided\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"max\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"CallbackGasLimitExceeded\";\n readonly type: \"error\";\n}" + }, + "24": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"required\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"InsufficientFee\";\n readonly type: \"error\";\n}" + }, + "25": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ExcessiveFee\";\n readonly type: \"error\";\n}" + }, + "26": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"actual\";\n readonly type: \"uint8\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"expected\";\n readonly type: \"uint8\";\n }\n ];\n readonly name: \"InvalidRequestStatus\";\n readonly type: \"error\";\n}" + }, + "27": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ContractIsPaused\";\n readonly type: \"error\";\n}" + }, + "28": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"CallerIsNotUCallbackModule\";\n readonly type: \"error\";\n}" + }, + "29": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n}" + }, + "length": { + "optional": false, + "readonly": true, + "type": "30" + } + } + }, + "UNIVERSAL_READ_REGISTRY_EVM": { + "type": "readonly [\n {\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n },\n {\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"read\";\n readonly outputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"universalCallback_\";\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"constructor\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"initialize\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getLocalContext\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"hasResult\";\n readonly outputs: readonly [\n {\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"onUniversalData\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"queryKeyOf\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes32\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"readerOf\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"requestOrderOf\";\n readonly outputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"universalCallback\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"resultByRequestId\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"latestResult\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"version\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"Initialized\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadRequested\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadStored\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidInitialization\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"NotInitializing\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroAddressInit\";\n readonly type: \"error\";\n }\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n },\n {\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"read\";\n readonly outputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n}" + }, + "1": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"universalCallback_\";\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"constructor\";\n}" + }, + "2": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"initialize\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n}" + }, + "3": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getLocalContext\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "4": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"hasResult\";\n readonly outputs: readonly [\n {\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "5": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"onUniversalData\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n}" + }, + "6": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"queryKeyOf\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes32\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "7": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"readerOf\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "8": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"requestOrderOf\";\n readonly outputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "9": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"universalCallback\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "10": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"resultByRequestId\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "11": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"latestResult\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "12": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"version\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"Initialized\";\n readonly type: \"event\";\n}" + }, + "13": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadRequested\";\n readonly type: \"event\";\n}" + }, + "14": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadStored\";\n readonly type: \"event\";\n}" + }, + "15": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidInitialization\";\n readonly type: \"error\";\n}" + }, + "16": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"NotInitializing\";\n readonly type: \"error\";\n}" + }, + "17": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n}" + }, + "18": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroAddressInit\";\n readonly type: \"error\";\n}" + }, + "length": { + "optional": false, + "readonly": true, + "type": "19" + } + } + }, + "PushChainExecutionError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").PushChainExecutionError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PushChainBatchExecutionError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").PushChainBatchExecutionError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": false, + "readonly": true, + "type": "`0x${string}`[]" + } + } + }, + "DecodedErrorPayload": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload", + "members": { + "decoded": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "name": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "selector": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "PushChainInitializeOptions": { + "type": "import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions", + "members": { + "agenticWallet": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "blockExplorers": { + "optional": true, + "readonly": false, + "type": "Partial> | undefined" + }, + "network": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "printTraces": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "rpcUrls": { + "optional": true, + "readonly": false, + "type": "Partial> | undefined" + } + } + }, + "AGENTIC_ERROR_CODE": { + "type": "{\n readonly AGENT_GAS_INSUFFICIENT: \"AGENT_GAS_INSUFFICIENT\";\n readonly AGENT_IS_OWNER: \"AGENT_IS_OWNER\";\n readonly ASSET_CHAIN_MISMATCH: \"ASSET_CHAIN_MISMATCH\";\n readonly CAPABILITY_UNAVAILABLE: \"CAPABILITY_UNAVAILABLE\";\n readonly CREATE_PARTIAL: \"CREATE_PARTIAL\";\n readonly DUPLICATE_RULE: \"DUPLICATE_RULE\";\n readonly FROM_NOT_ALLOWED: \"FROM_NOT_ALLOWED\";\n readonly GATEWAY_ALLOWANCE_INSUFFICIENT: \"GATEWAY_ALLOWANCE_INSUFFICIENT\";\n readonly GENERATION_UNSUPPORTED: \"GENERATION_UNSUPPORTED\";\n readonly INCONSISTENT_READ: \"INCONSISTENT_READ\";\n readonly INDEX_RACE: \"INDEX_RACE\";\n readonly INVALID_RULE: \"INVALID_RULE\";\n readonly NO_RULES_FOR_CHAIN: \"NO_RULES_FOR_CHAIN\";\n readonly NOT_AGENTIC_WALLET: \"NOT_AGENTIC_WALLET\";\n readonly NOT_ALLOWED_IN_AGENTIC_MODE: \"NOT_ALLOWED_IN_AGENTIC_MODE\";\n readonly NOT_OWNER_OR_AGENT: \"NOT_OWNER_OR_AGENT\";\n readonly NOT_WALLET_OWNER: \"NOT_WALLET_OWNER\";\n readonly READ_ONLY: \"READ_ONLY\";\n readonly RECEIPT_MISMATCH: \"RECEIPT_MISMATCH\";\n readonly RECEIPT_UNAVAILABLE: \"RECEIPT_UNAVAILABLE\";\n readonly REVOKE_NEEDS_TARGET: \"REVOKE_NEEDS_TARGET\";\n readonly RULE_LIMIT_EXCEEDED: \"RULE_LIMIT_EXCEEDED\";\n readonly RULE_NOT_FOUND: \"RULE_NOT_FOUND\";\n readonly RULE_READ_FAILED: \"RULE_READ_FAILED\";\n readonly TARGET_NOT_ON_RULE_CHAIN: \"TARGET_NOT_ON_RULE_CHAIN\";\n readonly WALLET_BALANCE_INSUFFICIENT: \"WALLET_BALANCE_INSUFFICIENT\";\n readonly WALLET_NOT_DEPLOYED: \"WALLET_NOT_DEPLOYED\";\n}", + "members": { + "AGENT_GAS_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\"" + }, + "AGENT_IS_OWNER": { + "optional": false, + "readonly": true, + "type": "\"AGENT_IS_OWNER\"" + }, + "ASSET_CHAIN_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"ASSET_CHAIN_MISMATCH\"" + }, + "CAPABILITY_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"CAPABILITY_UNAVAILABLE\"" + }, + "CREATE_PARTIAL": { + "optional": false, + "readonly": true, + "type": "\"CREATE_PARTIAL\"" + }, + "DUPLICATE_RULE": { + "optional": false, + "readonly": true, + "type": "\"DUPLICATE_RULE\"" + }, + "FROM_NOT_ALLOWED": { + "optional": false, + "readonly": true, + "type": "\"FROM_NOT_ALLOWED\"" + }, + "GATEWAY_ALLOWANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"GATEWAY_ALLOWANCE_INSUFFICIENT\"" + }, + "GENERATION_UNSUPPORTED": { + "optional": false, + "readonly": true, + "type": "\"GENERATION_UNSUPPORTED\"" + }, + "INCONSISTENT_READ": { + "optional": false, + "readonly": true, + "type": "\"INCONSISTENT_READ\"" + }, + "INDEX_RACE": { + "optional": false, + "readonly": true, + "type": "\"INDEX_RACE\"" + }, + "INVALID_RULE": { + "optional": false, + "readonly": true, + "type": "\"INVALID_RULE\"" + }, + "NO_RULES_FOR_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"NO_RULES_FOR_CHAIN\"" + }, + "NOT_AGENTIC_WALLET": { + "optional": false, + "readonly": true, + "type": "\"NOT_AGENTIC_WALLET\"" + }, + "NOT_ALLOWED_IN_AGENTIC_MODE": { + "optional": false, + "readonly": true, + "type": "\"NOT_ALLOWED_IN_AGENTIC_MODE\"" + }, + "NOT_OWNER_OR_AGENT": { + "optional": false, + "readonly": true, + "type": "\"NOT_OWNER_OR_AGENT\"" + }, + "NOT_WALLET_OWNER": { + "optional": false, + "readonly": true, + "type": "\"NOT_WALLET_OWNER\"" + }, + "READ_ONLY": { + "optional": false, + "readonly": true, + "type": "\"READ_ONLY\"" + }, + "RECEIPT_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_MISMATCH\"" + }, + "RECEIPT_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_UNAVAILABLE\"" + }, + "REVOKE_NEEDS_TARGET": { + "optional": false, + "readonly": true, + "type": "\"REVOKE_NEEDS_TARGET\"" + }, + "RULE_LIMIT_EXCEEDED": { + "optional": false, + "readonly": true, + "type": "\"RULE_LIMIT_EXCEEDED\"" + }, + "RULE_NOT_FOUND": { + "optional": false, + "readonly": true, + "type": "\"RULE_NOT_FOUND\"" + }, + "RULE_READ_FAILED": { + "optional": false, + "readonly": true, + "type": "\"RULE_READ_FAILED\"" + }, + "TARGET_NOT_ON_RULE_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"TARGET_NOT_ON_RULE_CHAIN\"" + }, + "WALLET_BALANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"WALLET_BALANCE_INSUFFICIENT\"" + }, + "WALLET_NOT_DEPLOYED": { + "optional": false, + "readonly": true, + "type": "\"WALLET_NOT_DEPLOYED\"" + } + } + }, + "AgenticError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"CREATE_PARTIAL\" | \"DUPLICATE_RULE\" | \"FROM_NOT_ALLOWED\" | \"GATEWAY_ALLOWANCE_INSUFFICIENT\" | \"GENERATION_UNSUPPORTED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"REVOKE_NEEDS_TARGET\" | \"RULE_LIMIT_EXCEEDED\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"" + }, + "details": { + "optional": true, + "readonly": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "AgenticRevertError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticRevertError", + "members": { + "agenticCode": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + } + } + }, + "AgenticAddress": { + "type": "`0x${string}`", + "members": {} + }, + "AgenticDoor": { + "type": "\"agent\" | \"owner\"", + "members": {} + }, + "AgenticErrorCode": { + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"CREATE_PARTIAL\" | \"DUPLICATE_RULE\" | \"FROM_NOT_ALLOWED\" | \"GATEWAY_ALLOWANCE_INSUFFICIENT\" | \"GENERATION_UNSUPPORTED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"REVOKE_NEEDS_TARGET\" | \"RULE_LIMIT_EXCEEDED\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"", + "members": {} + }, + "AgenticHex": { + "type": "`0x${string}`", + "members": {} + }, + "AgenticNamespace": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace", + "members": { + "create": { + "optional": false, + "readonly": false, + "type": "(label: string, options: import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions) => Promise" + }, + "derive": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n index?: number;\n}) => Promise<{\n address: `0x${string}`;\n deployed: boolean;\n index: number;\n}>" + }, + "list": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n wallets: import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary[];\n}>" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "(address: `0x${string}`) => import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet" + } + } + }, + "AgenticNetworkConstants": { + "type": "import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants", + "members": { + "ENVELOPE_VERSION": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "FACTORY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "MAX_ALLOWED_CALLS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "MAX_PINS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "RULES_POLICY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticProgressHook": { + "type": "(event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void", + "members": {} + }, + "AgenticTxMetadata": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticTxMetadata", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destinationAccount": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "destinationCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "door": { + "optional": false, + "readonly": false, + "type": "\"agent\" | \"owner\"" + }, + "nativeCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "rawData": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rawTo": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesId": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticWallet": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "checkpoints": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n sinceBlock?: bigint;\n}) => Promise<{\n checkpoints: import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint[];\n}>" + }, + "info": { + "optional": false, + "readonly": false, + "type": "() => Promise" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n owner: `0x${string}`;\n}>" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "{\n add(rules: import(\"sdk/src/lib/agentic/agentic.types\").Rule[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise<{\n rulesIds: `0x${string}`[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n get(rulesId: `0x${string}`): Promise;\n list(): Promise<{\n rules: import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord[];\n }>;\n revoke(rulesIds: `0x${string}`[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n revoke(params: {\n all: true;\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n update(params: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n rules: {\n rule: import(\"sdk/src/lib/agentic/agentic.types\").Rule;\n rulesId: `0x${string}`;\n }[];\n }): Promise<{\n rules: {\n replaced: `0x${string}`;\n rulesId: `0x${string}`;\n }[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n}" + }, + "setLabel": { + "optional": false, + "readonly": false, + "type": "(label: string, opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n}) => Promise" + } + } + }, + "AllowedCall": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall", + "members": { + "beneficiary": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValue": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "`${string}(${string})` | `0x${string}`" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AssetCap": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap", + "members": { + "maxPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/constants/tokens\").MoveableToken" + } + } + }, + "Checkpoint": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint", + "members": { + "blockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "kind": { + "optional": false, + "readonly": false, + "type": "\"OWNER_ACTION\" | \"RULES_GRANTED\" | \"RULES_REVOKED\"" + }, + "ref": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "seq": { + "optional": false, + "readonly": false, + "type": "number" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "CheckpointKind": { + "type": "\"OWNER_ACTION\" | \"RULES_GRANTED\" | \"RULES_REVOKED\"", + "members": {} + }, + "CreateOptions": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions", + "members": { + "progressHook": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook | undefined" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Rule[]" + } + } + }, + "CreateResult": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateResult", + "members": { + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "rulesIds": { + "optional": false, + "readonly": false, + "type": "`0x${string}`[]" + }, + "tx": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ForeignChainNamespace": { + "type": "`eip155:${string}` | `solana:${string}`", + "members": {} + }, + "NativeRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "amount": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AmountLimit | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "maxCalls": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValuePerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxValueTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "pins": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ArgPin[] | undefined" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Rule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule | import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "RulesRecord": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "enabled": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "ref": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "rule": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule | import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule" + }, + "rulesId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Selector": { + "type": "`${string}(${string})` | `0x${string}`", + "members": {} + }, + "UniversalRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall[]" + }, + "assets": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap[]" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "`eip155:${string}` | `solana:${string}`" + }, + "maxGasPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "WalletInfo": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").WalletInfo", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "label": { + "optional": false, + "readonly": false, + "type": "string" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "rulesCount": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "WalletSummary": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "label": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesCount": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "PushChain": { + "type": "import(\"sdk/src/lib/push-chain/push-chain\").PushChain", + "members": { + "accountStatus": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus" + }, + "accountStatusReady": { + "optional": false, + "readonly": false, + "type": "Promise" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace" + }, + "explorer": { + "optional": false, + "readonly": false, + "type": "{\n getTransactionUrl: (txHash: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n listAllUrls: () => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n listUrls: (options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n}" + }, + "funds": { + "optional": false, + "readonly": false, + "type": "{\n getConversionQuote: (amountIn: bigint, options: {\n from: import(\"sdk/src/lib/constants/tokens\").PayableToken | undefined;\n to: import(\"sdk/src/lib/constants/tokens\").MoveableToken | undefined;\n }) => Promise;\n}" + }, + "getAccountStatus": { + "optional": false, + "readonly": false, + "type": "(options?: {\n forceRefresh?: boolean;\n}) => Promise" + }, + "isReadMode": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "moveable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").MoveableTokenAccessor;\n}" + }, + "payable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").PayableTokenAccessor;\n}" + }, + "reinitialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "universal": { + "optional": false, + "readonly": false, + "type": "{\n readonly account: `0x${string}`;\n executeReads: (reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>;\n executeTransactions: (txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise;\n migrateCEA: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"migrateCEA\"];\n readonly origin: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n prepareRead: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n prepareTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"prepareTransaction\"];\n read: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n rescueFunds: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"rescueFunds\"];\n sendTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"execute\"];\n signMessage: (data: Uint8Array) => Promise;\n signTypedData: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n trackRead: {\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n };\n trackTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"trackTransaction\"];\n}" + }, + "upgradeAccount": { + "optional": false, + "readonly": false, + "type": "(options?: {\n progressHook?: (progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n}) => Promise" + } + } + } + }, + "pushChainStatic": { + "CONSTANTS": { + "optional": false, + "readonly": false, + "type": "{\n AGENTIC: Readonly>>;\n CHAIN: typeof import(\"sdk/src/lib/constants/enums\").CHAIN;\n LIBRARY: typeof import(\"sdk/src/lib/constants/enums\").LIBRARY;\n MOVEABLE: {\n TOKEN: import(\"sdk/src/lib/constants/tokens\").MoveableTokenConstantsMap;\n };\n PAYABLE: {\n TOKEN: import(\"sdk/src/lib/constants/tokens\").PayableTokenConstantsMap;\n };\n PUSH_NETWORK: typeof import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n READ: {\n readonly CALLBACK_BUDGET_BUFFER: 3;\n readonly CHAIN: {\n readonly WEB2: \"web2\";\n } & Readonly<{\n readonly ARBITRUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA;\n readonly BASE_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA;\n readonly BNB_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET;\n readonly ETHEREUM_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET;\n readonly ETHEREUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA;\n readonly PUSH_LOCALNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET;\n readonly PUSH_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET;\n readonly PUSH_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly PUSH_TESTNET_DONUT: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly SOLANA_DEVNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET;\n readonly SOLANA_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET;\n readonly SOLANA_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n readonly WEB2: \"web2\";\n }>;\n readonly DEFAULT_EXPIRY_BLOCKS: 300n;\n readonly ERROR_CODE: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n readonly MAX_CALLBACK_GAS_LIMIT: 1000000n;\n readonly MIN_CONFIRMATIONS_FLOOR: 1;\n readonly NAMESPACE: {\n readonly EVM: \"eip155\";\n readonly SVM: \"solana\";\n readonly WEB2: \"web2\";\n };\n readonly OUTCOME: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME;\n readonly REGISTRY_CALLBACK_GAS: 500000n;\n readonly RESULT_STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n readonly STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS;\n readonly UNIVERSAL_CALLBACK_ADDRESSES: Record;\n readonly UNIVERSAL_CORE_ADDRESSES: Record;\n readonly UNIVERSAL_READ_REGISTRY_ADDRESS: {\n readonly TESTNET_DONUT: \"0x00000000000000000000000000000000000000b2\";\n };\n readonly WEB2: \"web2\";\n readonly WEB2_DEFAULT_TIMEOUT_MS: 5000;\n readonly WEB2_MAX_EXTRACT_ENTRIES: 16;\n };\n}" + }, + "initialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "utils": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/utils\").Utils" + } + }, + "pushChainInstance": { + "accountStatus": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus" + }, + "accountStatusReady": { + "optional": false, + "readonly": false, + "type": "Promise" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace" + }, + "explorer": { + "optional": false, + "readonly": false, + "type": "{\n getTransactionUrl: (txHash: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n listAllUrls: () => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n listUrls: (options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n}" + }, + "funds": { + "optional": false, + "readonly": false, + "type": "{\n getConversionQuote: (amountIn: bigint, options: {\n from: import(\"sdk/src/lib/constants/tokens\").PayableToken | undefined;\n to: import(\"sdk/src/lib/constants/tokens\").MoveableToken | undefined;\n }) => Promise;\n}" + }, + "getAccountStatus": { + "optional": false, + "readonly": false, + "type": "(options?: {\n forceRefresh?: boolean;\n}) => Promise" + }, + "isReadMode": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "moveable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").MoveableTokenAccessor;\n}" + }, + "payable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").PayableTokenAccessor;\n}" + }, + "reinitialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "universal": { + "optional": false, + "readonly": false, + "type": "{\n readonly account: `0x${string}`;\n executeReads: (reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>;\n executeTransactions: (txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise;\n migrateCEA: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"migrateCEA\"];\n readonly origin: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n prepareRead: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n prepareTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"prepareTransaction\"];\n read: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n rescueFunds: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"rescueFunds\"];\n sendTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"execute\"];\n signMessage: (data: Uint8Array) => Promise;\n signTypedData: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n trackRead: {\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n };\n trackTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"trackTransaction\"];\n}" + }, + "upgradeAccount": { + "optional": false, + "readonly": false, + "type": "(options?: {\n progressHook?: (progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n}) => Promise" + } + }, + "transactionMethods": { + "account": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "executeReads": { + "optional": false, + "readonly": false, + "type": "(reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>" + }, + "executeTransactions": { + "optional": false, + "readonly": false, + "type": "(txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise" + }, + "migrateCEA": { + "optional": false, + "readonly": false, + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => Promise" + }, + "origin": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "prepareRead": { + "optional": false, + "readonly": false, + "type": "(subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>" + }, + "prepareTransaction": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions) => Promise" + }, + "read": { + "optional": false, + "readonly": false, + "type": "(subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>" + }, + "rescueFunds": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").RescueFundsParams) => Promise" + }, + "sendTransaction": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").ExecuteParams | import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions) => Promise" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": false, + "readonly": false, + "type": "({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise" + }, + "trackRead": { + "optional": false, + "readonly": false, + "type": "{\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n}" + }, + "trackTransaction": { + "optional": false, + "readonly": false, + "type": "(txHash: string, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TrackTransactionOptions) => Promise" + } + }, + "utilityMethods": { + "account": { + "optional": false, + "readonly": false, + "type": "{\n convertExecutorToOriginAccount: (ueaAddress: `0x${string}`, options?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n }) => Promise;\n convertOriginToExecutor: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n onlyCompute?: boolean;\n }) => Promise;\n deriveExecutorAccount: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n skipNetworkCheck?: boolean;\n }) => Promise;\n fromChainAgnostic: (caip: string) => import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n resolveControllerAccount: (address: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n skipNetworkCheck?: boolean;\n }) => Promise;\n toChainAgnostic: (address: string, options: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n toUniversal: (address: string, options: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n}" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "{\n actionId: (target: `0x${string}`, selector: \"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector) => `0x${string}`;\n configId: (wallet: `0x${string}`, rulesId: `0x${string}`, actionId: `0x${string}`) => `0x${string}`;\n decodeRules: (bytes: `0x${string}`, ctx?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n pushChainNamespace?: string;\n }) => import(\"sdk/src/lib/agentic/agentic.types\").Rule;\n}" + }, + "chains": { + "optional": false, + "readonly": false, + "type": "{\n getChainName: (chainNamespace: string) => string | undefined;\n getChainNamespace: (chainName: string) => string | undefined;\n getSupportedChains: (network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK) => {\n chains: import(\"sdk/src/lib/constants/enums\").CHAIN[];\n };\n getSupportedChainsByName: (network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK) => {\n chains: string[];\n };\n}" + }, + "conversion": { + "optional": false, + "readonly": false, + "type": "{\n slippageToMinAmount(amount: string, options: {\n slippageBps: number;\n }): string;\n}" + }, + "helpers": { + "optional": false, + "readonly": false, + "type": "{\n encodeTxData({ abi, idl, functionName, args, }: {\n abi?: any;\n args?: any[];\n functionName: string;\n idl?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n }): `0x${string}`;\n formatUnits(value: bigint | string, decimalsOrOptions: {\n decimals: number;\n precision?: number;\n } | number): string;\n getChainName: (chainName: string) => string | undefined;\n parseUnits(value: string, exponent: {\n decimals: number;\n } | number): bigint;\n}" + }, + "signer": { + "optional": false, + "readonly": false, + "type": "{\n construct: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options: {\n signAndSendTransaction: (unsignedTx: Uint8Array) => Promise;\n signAuthorization?: (params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise;\n signMessage: (data: Uint8Array) => Promise;\n signTypedData?: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n }) => import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton;\n toUniversal: (signer: import(\"sdk/src/lib/universal/universal.types\").EthersV5SignerType | import(\"sdk/src/lib/universal/universal.types\").EthersV6SignerType | import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton | import(\"sdk/src/lib/universal/universal.types\").ViemSignerType) => Promise;\n toUniversalFromKeypair: (clientOrAccount: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@solana/web3.js/lib/index\").Keypair | import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").WalletClient | import(\"sdk/src/lib/universal/universal.types\").EthersV6SignerType, { chain, library }: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n library: import(\"sdk/src/lib/constants/enums\").LIBRARY;\n }) => Promise;\n}" + }, + "svm": { + "optional": false, + "readonly": false, + "type": "{\n getRegisteredIdls: () => Array<{\n address: `0x${string}`;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n }>;\n registerIdl: (idl: unknown) => void;\n}" + }, + "tokens": { + "optional": false, + "readonly": false, + "type": "{\n getMoveableTokens(chainOrClient?: import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/push-chain/push-chain\").PushChain): {\n tokens: Array<{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n decimals: number;\n mechanism: \"approve\" | \"native\" | \"permit2\";\n prc20Address?: `0x${string}`;\n sourceChain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n symbol: string;\n }>;\n };\n getPayableTokens(chainOrClient?: import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/push-chain/push-chain\").PushChain): {\n tokens: Array<{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n decimals: number;\n mechanism: \"approve\" | \"native\" | \"permit2\";\n symbol: string;\n }>;\n };\n getPC20Address(address: string, options: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n rpcUrls?: Partial>;\n strict?: boolean;\n }): Promise;\n getPRC20Address(token: {\n address: string;\n chain: string;\n } | import(\"sdk/src/lib/constants/tokens\").MoveableToken, options?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n }): {\n address: `0x${string}`;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n decimals: number;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n symbol: string;\n };\n}" + } + }, + "initialize": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise", + "agwConstants": { + "ENVELOPE_VERSION": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "FACTORY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "MAX_ALLOWED_CALLS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "MAX_PINS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "RULES_POLICY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + }, + "constants": { + "AGENTIC": { + "optional": false, + "readonly": false, + "type": "{\n readonly LOCALNET?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n readonly MAINNET?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n readonly TESTNET?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n readonly TESTNET_DONUT?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n}" + }, + "CHAIN": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "LIBRARY": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").LIBRARY" + }, + "MOVEABLE": { + "optional": false, + "readonly": false, + "type": "{\n TOKEN: import(\"sdk/src/lib/constants/tokens\").MoveableTokenConstantsMap;\n}" + }, + "PAYABLE": { + "optional": false, + "readonly": false, + "type": "{\n TOKEN: import(\"sdk/src/lib/constants/tokens\").PayableTokenConstantsMap;\n}" + }, + "PUSH_NETWORK": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "READ": { + "optional": false, + "readonly": false, + "type": "{\n readonly CALLBACK_BUDGET_BUFFER: 3;\n readonly CHAIN: {\n readonly WEB2: \"web2\";\n } & Readonly<{\n readonly ARBITRUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA;\n readonly BASE_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA;\n readonly BNB_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET;\n readonly ETHEREUM_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET;\n readonly ETHEREUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA;\n readonly PUSH_LOCALNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET;\n readonly PUSH_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET;\n readonly PUSH_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly PUSH_TESTNET_DONUT: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly SOLANA_DEVNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET;\n readonly SOLANA_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET;\n readonly SOLANA_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n readonly WEB2: \"web2\";\n }>;\n readonly DEFAULT_EXPIRY_BLOCKS: 300n;\n readonly ERROR_CODE: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n readonly MAX_CALLBACK_GAS_LIMIT: 1000000n;\n readonly MIN_CONFIRMATIONS_FLOOR: 1;\n readonly NAMESPACE: {\n readonly EVM: \"eip155\";\n readonly SVM: \"solana\";\n readonly WEB2: \"web2\";\n };\n readonly OUTCOME: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME;\n readonly REGISTRY_CALLBACK_GAS: 500000n;\n readonly RESULT_STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n readonly STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS;\n readonly UNIVERSAL_CALLBACK_ADDRESSES: Record;\n readonly UNIVERSAL_CORE_ADDRESSES: Record;\n readonly UNIVERSAL_READ_REGISTRY_ADDRESS: {\n readonly TESTNET_DONUT: \"0x00000000000000000000000000000000000000b2\";\n };\n readonly WEB2: \"web2\";\n readonly WEB2_DEFAULT_TIMEOUT_MS: 5000;\n readonly WEB2_MAX_EXTRACT_ENTRIES: 16;\n}" + } + } + }, + "after": { + "exports": [ + "AGENTIC_ERROR_CODE", + "AccountRole", + "AccountStatus", + "AccountType", + "AgenticAddress", + "AgenticDoor", + "AgenticError", + "AgenticErrorCode", + "AgenticHex", + "AgenticNamespace", + "AgenticPresets", + "AgenticProgressHook", + "AgenticRevertError", + "AgenticTxMetadata", + "AgenticWallet", + "AllowedCall", + "ArgumentPath", + "AssetCap", + "BatchReadResponse", + "BuildReadSpecParams", + "CHAIN", + "CONTRACT_REQUEST_STATUS", + "CascadeCompletionResult", + "CascadeHopInfo", + "CascadeProgressEvent", + "CascadeTrackOptions", + "CascadedTxResponse", + "ChainSource", + "ChainTarget", + "Checkpoint", + "CheckpointKind", + "ConversionQuote", + "CreateOptions", + "CreateResult", + "DEFAULT_MAX_PC_FOR_GAS_BUFFER_BPS", + "DecodedErrorPayload", + "DecodedReadResult", + "DecodedSolanaRule", + "DerivedExecutorAccount", + "EncodedReadQuery", + "EvmReadQuery", + "ForeignChainNamespace", + "FulfilOutcome", + "FundsToken", + "InsufficientPC20BalanceError", + "InvalidPC20AddressError", + "InvalidPC20MetadataError", + "InvalidReadQueryError", + "InvalidReadSpecError", + "MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT", + "MaxPCForGasCapFromNativeValueInput", + "MaxPCForGasCapInput", + "MaxPCForGasCapQuote", + "MultiChainTxResponse", + "OutboundTxDetails", + "PC20AddressResult", + "PC20AmbiguousAddressError", + "PC20Error", + "PC20ExpectedButPRC20Error", + "PC20ExportRevertedError", + "PC20FactoryMismatchError", + "PC20RegistryEntry", + "PC20RegistryMismatchError", + "PC20TokenChainMismatchError", + "PC20TokenReference", + "PC20UnknownChainNamespaceError", + "PC20UnsafeEmptyPayloadError", + "PC20WrapperNotRegisteredError", + "PC20WrapperPredictionUnavailableError", + "ParsedReadRequest", + "Pin", + "PreparedRead", + "PreparedUniversalTx", + "Preset", + "PresetAsset", + "PresetCategory", + "PresetOptions", + "PresetRuleTemplate", + "PushChain", + "PushChainBatchExecutionError", + "PushChainExecutionError", + "PushChainInitializeOptions", + "READ_ERROR_CODE", + "READ_OUTCOME", + "READ_STATUS", + "ReadCallback", + "ReadCallbackOptions", + "ReadChain", + "ReadDecodeError", + "ReadDestination", + "ReadExecuteOptions", + "ReadFees", + "ReadHeightUnavailableError", + "ReadLifecycleOptions", + "ReadNotFoundError", + "ReadOptions", + "ReadPreflight", + "ReadPrepareOptions", + "ReadQuery", + "ReadQueryOptions", + "ReadRef", + "ReadRegistryUnavailableError", + "ReadResponseTuple", + "ReadResultShape", + "ReadSpec", + "ReadSpecTuple", + "ReadSpecViolation", + "ReadStateError", + "ReadTimeoutError", + "ReadTrackOptions", + "ReadValue", + "ReadWeb2Options", + "ReadyPresetOptions", + "ReceiptLike", + "RescueFundsParams", + "ResolvedAccount", + "ResolvedControllerAccounts", + "ResolvedDestination", + "Rule", + "RuleInput", + "RulesRecord", + "Selector", + "SignAuthorizationParams", + "SignedAuthorization", + "SimulateReadResult", + "Spent", + "SvmExecutePayloadFields", + "SvmGatewayAccountMeta", + "SvmReadQuery", + "TERMINAL_READ_STATUSES", + "TransactionRoute", + "TransactionRouteType", + "UEAStatus", + "UNIVERSAL_CALLBACK_EVM", + "UNIVERSAL_READ_REGISTRY_EVM", + "UNIVERSAL_READ_STATUS", + "UniversalAccount", + "UniversalExecuteParams", + "UniversalOutboundTxRequest", + "UniversalReadResponse", + "UniversalSigner", + "UniversalSignerSkeleton", + "UniversalTo", + "UnsupportedPC20DestinationError", + "UnsupportedReadDestinationError", + "ValidateReadCall", + "WaitForOutboundOptions", + "WalletInfo", + "WalletMarker", + "WalletSummary", + "Web2Extract", + "Web2ReadQuery", + "Web2ValueType", + "buildErc20WithdrawalMulticall", + "buildMigrationPayload", + "buildReadSpecFromPreflight", + "chainSupportsCEA", + "chainSupportsOutbound", + "decodeReadResult", + "detectRoute", + "encodeReadQuery", + "encodeSvmExecutePayload", + "getAllCEAAddresses", + "getCEAAddress", + "getCEAFactoryAddress", + "getPushAccountForCEA", + "inferResultShape", + "isCEA", + "isChainTarget", + "isPC20Reference", + "isSvmChain", + "isValidSolanaHexAddress", + "parseFulfilOutcome", + "parseReadRequestsFromReceipt", + "parseUEAVersion", + "quoteMaxPCForGasCap", + "quoteMaxPCForGasCapFromNativeValue", + "resolveDestination", + "sizeCallbackBudget", + "toCallData", + "toReadQuery", + "toRequestIdHex", + "validateReadSpec" + ], + "agw": { + "AgenticNamespace": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace", + "members": { + "create": { + "optional": false, + "readonly": false, + "type": "(label: string, options: import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions) => Promise" + }, + "derive": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n index?: number;\n}) => Promise<{\n address: `0x${string}`;\n deployed: boolean;\n index: number;\n}>" + }, + "list": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n wallets: import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary[];\n}>" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "(address: `0x${string}`) => import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet" + } + } + }, + "AgenticWallet": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "checkpoints": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n sinceBlock?: bigint;\n}) => Promise<{\n checkpoints: import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint[];\n}>" + }, + "info": { + "optional": false, + "readonly": false, + "type": "() => Promise" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n owner: `0x${string}`;\n}>" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "{\n add(rules: import(\"sdk/src/lib/agentic/agentic.types\").RuleInput[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise<{\n rulesIds: `0x${string}`[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n delete(rulesIds: `0x${string}`[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n delete(params: {\n all: true;\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n get(rulesId: `0x${string}`): Promise;\n list(): Promise<{\n rules: import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord[];\n }>;\n update(params: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n rules: {\n rule: import(\"sdk/src/lib/agentic/agentic.types\").RuleInput;\n rulesId: `0x${string}`;\n }[];\n }): Promise<{\n rules: {\n replaced: `0x${string}`;\n rulesId: `0x${string}`;\n }[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n}" + }, + "setLabel": { + "optional": false, + "readonly": false, + "type": "(label: string, opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n}) => Promise" + } + } + }, + "AgenticError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"AMBIGUOUS_RULE\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"DELETE_NEEDS_TARGET\" | \"DUPLICATE_RULE\" | \"FROM_NOT_ALLOWED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"" + }, + "details": { + "optional": true, + "readonly": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "AgenticRevertError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticRevertError", + "members": { + "agenticCode": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "AGENTIC_ERROR_CODE": { + "type": "{\n readonly AGENT_GAS_INSUFFICIENT: \"AGENT_GAS_INSUFFICIENT\";\n readonly AGENT_IS_OWNER: \"AGENT_IS_OWNER\";\n readonly AMBIGUOUS_RULE: \"AMBIGUOUS_RULE\";\n readonly ASSET_CHAIN_MISMATCH: \"ASSET_CHAIN_MISMATCH\";\n readonly CAPABILITY_UNAVAILABLE: \"CAPABILITY_UNAVAILABLE\";\n readonly DELETE_NEEDS_TARGET: \"DELETE_NEEDS_TARGET\";\n readonly DUPLICATE_RULE: \"DUPLICATE_RULE\";\n readonly FROM_NOT_ALLOWED: \"FROM_NOT_ALLOWED\";\n readonly INCONSISTENT_READ: \"INCONSISTENT_READ\";\n readonly INDEX_RACE: \"INDEX_RACE\";\n readonly INVALID_RULE: \"INVALID_RULE\";\n readonly NO_RULES_FOR_CHAIN: \"NO_RULES_FOR_CHAIN\";\n readonly NOT_AGENTIC_WALLET: \"NOT_AGENTIC_WALLET\";\n readonly NOT_ALLOWED_IN_AGENTIC_MODE: \"NOT_ALLOWED_IN_AGENTIC_MODE\";\n readonly NOT_OWNER_OR_AGENT: \"NOT_OWNER_OR_AGENT\";\n readonly NOT_WALLET_OWNER: \"NOT_WALLET_OWNER\";\n readonly READ_ONLY: \"READ_ONLY\";\n readonly RECEIPT_MISMATCH: \"RECEIPT_MISMATCH\";\n readonly RECEIPT_UNAVAILABLE: \"RECEIPT_UNAVAILABLE\";\n readonly RULE_NOT_FOUND: \"RULE_NOT_FOUND\";\n readonly RULE_READ_FAILED: \"RULE_READ_FAILED\";\n readonly TARGET_NOT_ON_RULE_CHAIN: \"TARGET_NOT_ON_RULE_CHAIN\";\n readonly WALLET_BALANCE_INSUFFICIENT: \"WALLET_BALANCE_INSUFFICIENT\";\n readonly WALLET_NOT_DEPLOYED: \"WALLET_NOT_DEPLOYED\";\n}", + "members": { + "AGENT_GAS_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\"" + }, + "AGENT_IS_OWNER": { + "optional": false, + "readonly": true, + "type": "\"AGENT_IS_OWNER\"" + }, + "AMBIGUOUS_RULE": { + "optional": false, + "readonly": true, + "type": "\"AMBIGUOUS_RULE\"" + }, + "ASSET_CHAIN_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"ASSET_CHAIN_MISMATCH\"" + }, + "CAPABILITY_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"CAPABILITY_UNAVAILABLE\"" + }, + "DELETE_NEEDS_TARGET": { + "optional": false, + "readonly": true, + "type": "\"DELETE_NEEDS_TARGET\"" + }, + "DUPLICATE_RULE": { + "optional": false, + "readonly": true, + "type": "\"DUPLICATE_RULE\"" + }, + "FROM_NOT_ALLOWED": { + "optional": false, + "readonly": true, + "type": "\"FROM_NOT_ALLOWED\"" + }, + "INCONSISTENT_READ": { + "optional": false, + "readonly": true, + "type": "\"INCONSISTENT_READ\"" + }, + "INDEX_RACE": { + "optional": false, + "readonly": true, + "type": "\"INDEX_RACE\"" + }, + "INVALID_RULE": { + "optional": false, + "readonly": true, + "type": "\"INVALID_RULE\"" + }, + "NO_RULES_FOR_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"NO_RULES_FOR_CHAIN\"" + }, + "NOT_AGENTIC_WALLET": { + "optional": false, + "readonly": true, + "type": "\"NOT_AGENTIC_WALLET\"" + }, + "NOT_ALLOWED_IN_AGENTIC_MODE": { + "optional": false, + "readonly": true, + "type": "\"NOT_ALLOWED_IN_AGENTIC_MODE\"" + }, + "NOT_OWNER_OR_AGENT": { + "optional": false, + "readonly": true, + "type": "\"NOT_OWNER_OR_AGENT\"" + }, + "NOT_WALLET_OWNER": { + "optional": false, + "readonly": true, + "type": "\"NOT_WALLET_OWNER\"" + }, + "READ_ONLY": { + "optional": false, + "readonly": true, + "type": "\"READ_ONLY\"" + }, + "RECEIPT_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_MISMATCH\"" + }, + "RECEIPT_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_UNAVAILABLE\"" + }, + "RULE_NOT_FOUND": { + "optional": false, + "readonly": true, + "type": "\"RULE_NOT_FOUND\"" + }, + "RULE_READ_FAILED": { + "optional": false, + "readonly": true, + "type": "\"RULE_READ_FAILED\"" + }, + "TARGET_NOT_ON_RULE_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"TARGET_NOT_ON_RULE_CHAIN\"" + }, + "WALLET_BALANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"WALLET_BALANCE_INSUFFICIENT\"" + }, + "WALLET_NOT_DEPLOYED": { + "optional": false, + "readonly": true, + "type": "\"WALLET_NOT_DEPLOYED\"" + } + } + }, + "Rule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Rule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleCall[]" + }, + "assets": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset[] | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "maxGasPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "RuleInput": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").DecodedSolanaRule | import(\"sdk/src/lib/agentic/agentic.types\").Rule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "assets": { + "optional": true, + "readonly": false, + "type": "{\n maxPerCall: bigint;\n maxTotal: bigint;\n token: string;\n}[] | import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset[] | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "maxGasPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Pin": { + "type": "{\n account: number;\n arg?: never;\n expected: \"agentic:wallet\" | string;\n max?: never;\n token?: import(\"sdk/src/lib/constants/tokens\").MoveableToken | string;\n} | {\n account?: never;\n arg: import(\"sdk/src/lib/agentic/agentic.types\").ArgumentPath;\n expected: \"agentic:wallet\" | `0x${string}` | `0x${string}` | bigint;\n max?: never;\n} | {\n account?: never;\n arg: import(\"sdk/src/lib/agentic/agentic.types\").ArgumentPath;\n expected?: never;\n max: bigint;\n}", + "members": { + "account": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "arg": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ArgumentPath | undefined" + }, + "expected": { + "optional": true, + "readonly": false, + "type": "bigint | string | undefined" + }, + "max": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "Spent": { + "type": "{\n actions: {\n amountSpent: bigint;\n callsUsed: number;\n selector: \"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector;\n target: `0x${string}`;\n valueSpent: bigint;\n }[];\n kind: \"native\";\n} | {\n amountSpent: bigint;\n callsUsed: number;\n kind: \"native\";\n valueSpent: bigint;\n} | {\n assets: {\n spent: bigint;\n token: string;\n }[];\n kind: \"universal\";\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"native\" | \"universal\"" + } + } + }, + "AssetCap": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset", + "members": { + "maxPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/tokens\").MoveableToken | string" + } + } + }, + "AllowedCall": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleCall", + "members": { + "app": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "label": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "maxValue": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "pins": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Pin[] | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector" + }, + "target": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "RulesRecord": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "enabled": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "rule": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").DecodedSolanaRule | import(\"sdk/src/lib/agentic/agentic.types\").Rule" + }, + "rulesId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "spent": { + "optional": false, + "readonly": false, + "type": "{\n actions: {\n amountSpent: bigint;\n callsUsed: number;\n selector: \"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector;\n target: `0x${string}`;\n valueSpent: bigint;\n }[];\n kind: \"native\";\n} | {\n amountSpent: bigint;\n callsUsed: number;\n kind: \"native\";\n valueSpent: bigint;\n} | {\n assets: {\n spent: bigint;\n token: string;\n }[];\n kind: \"universal\";\n}" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "CreateOptions": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions", + "members": { + "progressHook": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook | undefined" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleInput[]" + } + } + }, + "CreateResult": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateResult", + "members": { + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "rulesIds": { + "optional": false, + "readonly": false, + "type": "`0x${string}`[]" + }, + "tx": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticTxMetadata": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticTxMetadata", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destinationAccount": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "destinationCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "destinationInstruction": { + "optional": true, + "readonly": false, + "type": "{\n accounts: readonly {\n isWritable: boolean;\n pubkey: `0x${string}`;\n }[];\n data: `0x${string}`;\n program: `0x${string}`;\n} | undefined" + }, + "destinationTransfer": { + "optional": true, + "readonly": false, + "type": "{\n amount: bigint;\n recipient: `0x${string}`;\n token: `0x${string}`;\n} | undefined" + }, + "door": { + "optional": false, + "readonly": false, + "type": "\"agent\" | \"owner\"" + }, + "nativeCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "rawData": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rawTo": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesId": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + } + }, + "publicSurface": { + "CHAIN": { + "type": "typeof import(\"sdk/src/lib/constants/enums\").CHAIN", + "members": { + "ARBITRUM_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA" + }, + "BASE_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA" + }, + "BNB_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET" + }, + "ETHEREUM_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET" + }, + "ETHEREUM_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA" + }, + "PUSH_LOCALNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET" + }, + "PUSH_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET" + }, + "PUSH_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET" + }, + "PUSH_TESTNET_DONUT": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET" + }, + "SOLANA_DEVNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET" + }, + "SOLANA_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET" + }, + "SOLANA_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET" + }, + "WEB2": { + "optional": false, + "readonly": false, + "type": "\"web2\"" + } + } + }, + "ConversionQuote": { + "type": "import(\"sdk/src/lib/constants/tokens\").ConversionQuote", + "members": { + "amountIn": { + "optional": false, + "readonly": false, + "type": "string" + }, + "amountOut": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rate": { + "optional": false, + "readonly": false, + "type": "number" + }, + "route": { + "optional": true, + "readonly": false, + "type": "string[] | undefined" + }, + "timestamp": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "UniversalSigner": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalSigner", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "signAndSendTransaction": { + "optional": false, + "readonly": false, + "type": "(unsignedTx: Uint8Array) => Promise" + }, + "signAuthorization": { + "optional": true, + "readonly": false, + "type": "((params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise) | undefined" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": true, + "readonly": false, + "type": "(({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise) | undefined" + } + } + }, + "UniversalAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "UniversalSignerSkeleton": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "signAndSendTransaction": { + "optional": false, + "readonly": false, + "type": "(unsignedTx: Uint8Array) => Promise" + }, + "signAuthorization": { + "optional": true, + "readonly": false, + "type": "((params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise) | undefined" + }, + "signerId": { + "optional": false, + "readonly": false, + "type": "string" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": true, + "readonly": false, + "type": "(({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise) | undefined" + } + } + }, + "SignAuthorizationParams": { + "type": "{\n chainId?: number;\n contractAddress: `0x${string}`;\n executor?: \"self\";\n nonce?: number;\n}", + "members": { + "chainId": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "contractAddress": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "executor": { + "optional": true, + "readonly": false, + "type": "\"self\" | undefined" + }, + "nonce": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "SignedAuthorization": { + "type": "{\n address: `0x${string}`;\n chainId: number;\n nonce: number;\n r: `0x${string}`;\n s: `0x${string}`;\n v?: bigint;\n yParity: number;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainId": { + "optional": false, + "readonly": false, + "type": "number" + }, + "nonce": { + "optional": false, + "readonly": false, + "type": "number" + }, + "r": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "s": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "v": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "yParity": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "DerivedExecutorAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").DerivedExecutorAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean | null" + } + } + }, + "ResolvedAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainName": { + "optional": false, + "readonly": false, + "type": "string" + }, + "exists": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "role": { + "optional": true, + "readonly": false, + "type": "\"controller\" | undefined" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"cea\" | \"uea\" | \"uoa\"" + } + } + }, + "ResolvedControllerAccounts": { + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedControllerAccounts", + "members": { + "accounts": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedAccount[]" + } + } + }, + "AccountType": { + "type": "\"cea\" | \"uea\" | \"uoa\"", + "members": {} + }, + "AccountRole": { + "type": "\"controller\"", + "members": {} + }, + "PC20TokenReference": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "FundsToken": { + "type": "import(\"sdk/src/lib/constants/tokens\").MoveableToken | import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20TokenReference", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "PC20RegistryEntry": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "chainName": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "PC20AddressResult": { + "type": "{\n address: `0x${string}`;\n decimals: number;\n name: string;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n registry: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20RegistryEntry[];\n symbol: string;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "decimals": { + "optional": false, + "readonly": false, + "type": "number" + }, + "name": { + "optional": false, + "readonly": false, + "type": "string" + }, + "network": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "registry": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20RegistryEntry[]" + }, + "symbol": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "isPC20Reference": { + "type": "(token: import(\"sdk/src/lib/orchestrator/orchestrator.types\").FundsToken | undefined) => token is import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20TokenReference", + "members": {} + }, + "PC20Error": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20Error", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidPC20AddressError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InvalidPC20AddressError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20TokenChainMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20TokenChainMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20WrapperNotRegisteredError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20WrapperNotRegisteredError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20RegistryMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20RegistryMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20FactoryMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20FactoryMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidPC20MetadataError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InvalidPC20MetadataError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20ExpectedButPRC20Error": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20ExpectedButPRC20Error", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20AmbiguousAddressError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20AmbiguousAddressError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "candidates": { + "optional": false, + "readonly": true, + "type": "{\n chain: string;\n pushAddress: string;\n}[]" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "UnsupportedPC20DestinationError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").UnsupportedPC20DestinationError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InsufficientPC20BalanceError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InsufficientPC20BalanceError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20UnknownChainNamespaceError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20UnknownChainNamespaceError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20WrapperPredictionUnavailableError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20WrapperPredictionUnavailableError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20ExportRevertedError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20ExportRevertedError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "lockedAmount": { + "optional": true, + "readonly": true, + "type": "bigint | undefined" + }, + "outboundTxId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "revertRecipient": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20UnsafeEmptyPayloadError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20UnsafeEmptyPayloadError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ChainTarget": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "ChainSource": { + "type": "{\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "UniversalTo": { + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget", + "members": {} + }, + "TransactionRouteType": { + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"", + "members": {} + }, + "UniversalExecuteParams": { + "type": "{\n from?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainSource;\n migration?: boolean;\n to: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTo;\n} & Omit", + "members": { + "_minimumDepositUsd": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "_requiredFundsOverride": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "_skipFeeLocking": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "_ueaStatus": { + "optional": true, + "readonly": false, + "type": "{\n balance: bigint;\n isDeployed: boolean;\n nonce: bigint;\n} | undefined" + }, + "data": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiCall[] | undefined" + }, + "deadline": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "feeLockTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "from": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainSource | undefined" + }, + "funds": { + "optional": true, + "readonly": false, + "type": "{\n amount: bigint;\n token?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").FundsToken;\n} | undefined" + }, + "gasLimit": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFeePerGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxPCForGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxPriorityFeePerGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "migration": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "nonce": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "options": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions | undefined" + }, + "payGasWith": { + "optional": true, + "readonly": false, + "type": "{\n minAmountOut?: bigint | string;\n slippageBps?: number;\n token?: import(\"sdk/src/lib/constants/tokens\").PayableToken;\n} | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "to": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget" + }, + "value": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "UniversalOutboundTxRequest": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalOutboundTxRequest", + "members": { + "amount": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gasPrice": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxPCForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "payload": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "recipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "revertRecipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "PreparedUniversalTx": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx", + "members": { + "_hop": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").HopDescriptor" + }, + "deadline": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "estimatedGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gatewayRequest": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalOutboundTxRequest | import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxRequest" + }, + "nonce": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "payload": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + } + } + }, + "CascadedTxResponse": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadedTxResponse", + "members": { + "finalTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hopCount": { + "optional": false, + "readonly": false, + "type": "number" + }, + "hops": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo[]" + }, + "initialTxHash": { + "optional": false, + "readonly": false, + "type": "string" + }, + "initialTxResponse": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions) => Promise" + }, + "waitForAll": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions) => Promise" + } + } + }, + "CascadeHopInfo": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo", + "members": { + "executionChain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "expectedSubTxId": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hopIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "outboundDetails": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").OutboundTxDetails | undefined" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + }, + "status": { + "optional": false, + "readonly": false, + "type": "\"confirmed\" | \"failed\" | \"pending\" | \"submitted\"" + }, + "txHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "CascadeTrackOptions": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions", + "members": { + "eventHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeProgressEvent) => void) | undefined" + }, + "timeout": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "CascadeProgressEvent": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeProgressEvent", + "members": { + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "elapsed": { + "optional": false, + "readonly": false, + "type": "number" + }, + "hopIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + }, + "status": { + "optional": false, + "readonly": false, + "type": "\"confirmed\" | \"failed\" | \"found\" | \"polling\" | \"timeout\" | \"waiting\"" + }, + "txHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "CascadeCompletionResult": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeCompletionResult", + "members": { + "failedAt": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "finalTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "finalTxResponse": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadedTxResponse | undefined" + }, + "hops": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo[]" + }, + "success": { + "optional": false, + "readonly": false, + "type": "boolean" + } + } + }, + "MultiChainTxResponse": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiChainTxResponse", + "members": { + "chains": { + "optional": false, + "readonly": false, + "type": "{\n blockNumber: bigint;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n hash: string;\n status: \"confirmed\" | \"failed\" | \"pending\";\n}[]" + }, + "transactions": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse[]" + } + } + }, + "OutboundTxDetails": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").OutboundTxDetails", + "members": { + "amount": { + "optional": false, + "readonly": false, + "type": "string" + }, + "assetAddr": { + "optional": false, + "readonly": false, + "type": "string" + }, + "destinationChain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "explorerUrl": { + "optional": false, + "readonly": false, + "type": "string" + }, + "externalTxHash": { + "optional": false, + "readonly": false, + "type": "string" + }, + "recipient": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "WaitForOutboundOptions": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").WaitForOutboundOptions", + "members": { + "_expectedDestinationChain": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "_outboundIndex": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "_resolvedSubTxId": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "initialWaitMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: {\n elapsed: number;\n status: \"failed\" | \"found\" | \"polling\" | \"timeout\" | \"waiting\";\n}) => void) | undefined" + }, + "timeout": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "SvmGatewayAccountMeta": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmGatewayAccountMeta", + "members": { + "isWritable": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "pubkey": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "SvmExecutePayloadFields": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmExecutePayloadFields", + "members": { + "accounts": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmGatewayAccountMeta[]" + }, + "instructionId": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "ixData": { + "optional": false, + "readonly": false, + "type": "Uint8Array" + }, + "targetProgram": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AccountStatus": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus", + "members": { + "mode": { + "optional": false, + "readonly": false, + "type": "\"read-only\" | \"signer\"" + }, + "uea": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UEAStatus" + } + } + }, + "UEAStatus": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UEAStatus", + "members": { + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "loaded": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "minRequiredVersion": { + "optional": false, + "readonly": false, + "type": "string" + }, + "requiresUpgrade": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "version": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "RescueFundsParams": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").RescueFundsParams", + "members": { + "prc20": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "universalTxId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "parseUEAVersion": { + "type": "(version: string) => number", + "members": {} + }, + "TransactionRoute": { + "type": "typeof import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute", + "members": { + "CEA_TO_CEA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.CEA_TO_CEA" + }, + "CEA_TO_PUSH": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.CEA_TO_PUSH" + }, + "UOA_TO_CEA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.UOA_TO_CEA" + }, + "UOA_TO_PUSH": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.UOA_TO_PUSH" + } + } + }, + "detectRoute": { + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams) => import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute", + "members": {} + }, + "isChainTarget": { + "type": "(to: unknown) => to is import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget", + "members": {} + }, + "DEFAULT_MAX_PC_FOR_GAS_BUFFER_BPS": { + "type": "1000", + "members": {} + }, + "MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT": { + "type": "10000", + "members": {} + }, + "quoteMaxPCForGasCap": { + "type": "(input: import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapInput) => import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": {} + }, + "quoteMaxPCForGasCapFromNativeValue": { + "type": "(input: import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapFromNativeValueInput) => import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": {} + }, + "MaxPCForGasCapInput": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapInput", + "members": { + "bufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "gasLegNativePc": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "MaxPCForGasCapFromNativeValueInput": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapFromNativeValueInput", + "members": { + "bufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "nativeValueForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "MaxPCForGasCapQuote": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": { + "bufferBps": { + "optional": false, + "readonly": false, + "type": "number" + }, + "gasLegNativePc": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxPCForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "nativeValueForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "getCEAAddress": { + "type": "(ueaAddress: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise", + "members": {} + }, + "getPushAccountForCEA": { + "type": "(ceaAddress: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise<`0x${string}`>", + "members": {} + }, + "isCEA": { + "type": "(address: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise", + "members": {} + }, + "chainSupportsCEA": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "chainSupportsOutbound": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "getCEAFactoryAddress": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => `0x${string}` | undefined", + "members": {} + }, + "getAllCEAAddresses": { + "type": "(ueaAddress: `0x${string}`, rpcUrls?: Partial>) => Promise", + "members": {} + }, + "encodeSvmExecutePayload": { + "type": "(fields: import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmExecutePayloadFields) => `0x${string}`", + "members": {} + }, + "isSvmChain": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "isValidSolanaHexAddress": { + "type": "(address: string) => boolean", + "members": {} + }, + "buildMigrationPayload": { + "type": "() => `0x${string}`", + "members": {} + }, + "buildErc20WithdrawalMulticall": { + "type": "(tokenAddress: `0x${string}`, recipientAddress: `0x${string}`, amount: bigint) => import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiCall[]", + "members": {} + }, + "ReadChain": { + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain", + "members": {} + }, + "ReadDestination": { + "type": "{\n chain: import(\"sdk/src/lib/read-state/read-state.types\").ReadChain;\n} | {\n chainId: string;\n chainNamespace: string;\n}", + "members": {} + }, + "ResolvedDestination": { + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}", + "members": { + "caip2": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainId": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "namespace": { + "optional": false, + "readonly": false, + "type": "\"eip155\" | \"solana\" | \"web2\"" + } + } + }, + "ReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").SvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery", + "members": { + "type": { + "optional": false, + "readonly": false, + "type": "\"accountBalance\" | \"contractCall\" | \"http\" | \"lamportBalance\" | \"rawAccountData\" | \"splTokenAccount\" | \"storageSlot\"" + } + } + }, + "EvmReadQuery": { + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n target: `0x${string}`;\n type: \"contractCall\";\n} | {\n callData: `0x${string}`;\n target: `0x${string}`;\n type: \"contractCall\";\n} | {\n slot: `0x${string}` | bigint;\n target: `0x${string}`;\n type: \"storageSlot\";\n} | {\n target: `0x${string}`;\n type: \"accountBalance\";\n}", + "members": { + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"accountBalance\" | \"contractCall\" | \"storageSlot\"" + } + } + }, + "SvmReadQuery": { + "type": "{\n account: string | Uint8Array;\n accountName?: string;\n idl?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n type: \"rawAccountData\";\n} | {\n account: string | Uint8Array;\n type: \"lamportBalance\";\n} | {\n account: string | Uint8Array;\n type: \"splTokenAccount\";\n}", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "string | Uint8Array" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"lamportBalance\" | \"rawAccountData\" | \"splTokenAccount\"" + } + } + }, + "Web2ReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery", + "members": { + "body": { + "optional": true, + "readonly": false, + "type": "string | Uint8Array | undefined" + }, + "extract": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[]" + }, + "headers": { + "optional": true, + "readonly": false, + "type": "Record | undefined" + }, + "method": { + "optional": true, + "readonly": false, + "type": "\"GET\" | \"POST\" | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"http\"" + }, + "url": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "Web2Extract": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract", + "members": { + "decimals": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "path": { + "optional": false, + "readonly": false, + "type": "string" + }, + "valueType": { + "optional": false, + "readonly": false, + "type": "\"bool\" | \"bytes\" | \"int256\" | \"string\" | \"uint256\"" + } + } + }, + "Web2ValueType": { + "type": "\"bool\" | \"bytes\" | \"int256\" | \"string\" | \"uint256\"", + "members": {} + }, + "EncodedReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery", + "members": { + "blockRef": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "encoded": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "namespace": { + "optional": false, + "readonly": false, + "type": "\"eip155\" | \"solana\" | \"web2\"" + }, + "ownerBytes": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "queryType": { + "optional": false, + "readonly": false, + "type": "number" + }, + "resultShape": { + "optional": false, + "readonly": false, + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}" + }, + "warnings": { + "optional": false, + "readonly": false, + "type": "string[]" + } + } + }, + "ReadResultShape": { + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"bytes32\" | \"evmCall\" | \"raw\" | \"svmAccount\" | \"uint256\" | \"web2\"" + } + } + }, + "DecodedReadResult": { + "type": "{\n accountName: string;\n kind: \"svmAccount\";\n value: unknown;\n} | {\n kind: \"bytes32\";\n value: `0x${string}`;\n} | {\n kind: \"evmCall\";\n value: unknown;\n} | {\n kind: \"raw\";\n value: `0x${string}`;\n} | {\n kind: \"uint256\";\n value: bigint;\n} | {\n kind: \"web2\";\n values: readonly unknown[];\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"bytes32\" | \"evmCall\" | \"raw\" | \"svmAccount\" | \"uint256\" | \"web2\"" + } + } + }, + "ReadPreflight": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight", + "members": { + "destination": { + "optional": false, + "readonly": false, + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}" + }, + "fetchedAt": { + "optional": false, + "readonly": false, + "type": "number" + }, + "observedChainHeight": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pushBlockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pushGasPrice": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "universalCallback": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "universalCore": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ReadSpec": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "{\n chainId: string;\n chainNamespace: string;\n owner: `0x${string}`;\n}" + }, + "blockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "expiryPushChainHeight": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "minConfirmations": { + "optional": false, + "readonly": false, + "type": "number" + }, + "query": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "revertRecipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ReadSpecTuple": { + "type": "readonly [\n readonly [\n string,\n string,\n `0x${string}`\n ],\n `0x${string}`,\n number,\n bigint,\n bigint,\n bigint,\n `0x${string}`\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "readonly [\n string,\n string,\n `0x${string}`\n]" + }, + "1": { + "optional": false, + "readonly": true, + "type": "`0x${string}`" + }, + "2": { + "optional": false, + "readonly": true, + "type": "number" + }, + "3": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "4": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "5": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "6": { + "optional": false, + "readonly": true, + "type": "`0x${string}`" + }, + "length": { + "optional": false, + "readonly": true, + "type": "7" + } + } + }, + "BuildReadSpecParams": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").BuildReadSpecParams", + "members": { + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "budgetBuffer": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback | undefined" + }, + "callbackBudget": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "destination": { + "optional": false, + "readonly": false, + "type": "{\n chain: import(\"sdk/src/lib/read-state/read-state.types\").ReadChain;\n} | {\n chainId: string;\n chainNamespace: string;\n}" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "expiryPushChainHeight": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFeeBufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "owner": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "query": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").SvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "PreparedRead": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead", + "members": { + "__@preparedReadValue": { + "optional": true, + "readonly": true, + "type": "T | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback | undefined" + }, + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "encodedQuery": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery" + }, + "encodedSpec": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "fees": { + "optional": false, + "readonly": false, + "type": "{\n callbackBudget: bigint;\n protocolFee: bigint;\n total: bigint;\n}" + }, + "preflight": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "queryKey": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "resultShape": { + "optional": false, + "readonly": false, + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}" + }, + "spec": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec" + }, + "specTuple": { + "optional": false, + "readonly": false, + "type": "readonly [\n readonly [\n string,\n string,\n `0x${string}`\n ],\n `0x${string}`,\n number,\n bigint,\n bigint,\n bigint,\n `0x${string}`\n]" + }, + "value": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "warnings": { + "optional": false, + "readonly": false, + "type": "string[]" + } + } + }, + "ReadCallback": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "((spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpecTuple, callbackGasLimit: bigint) => readonly unknown[]) | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "gasLimit": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "target": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "SimulateReadResult": { + "type": "{\n args?: readonly unknown[];\n error: string;\n errorName?: string;\n ok: false;\n} | {\n ok: true;\n}", + "members": { + "ok": { + "optional": false, + "readonly": false, + "type": "boolean" + } + } + }, + "ParsedReadRequest": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ParsedReadRequest", + "members": { + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackTarget": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "logIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "originalFunder": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "requestId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "requestIdUint": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "spec": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec" + }, + "totalPaid": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "FulfilOutcome": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").FulfilOutcome", + "members": { + "burned": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "delivered": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "expired": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "failReason": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "gasReported": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refunded": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refundFailed": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "ReceiptLike": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike", + "members": { + "logs": { + "optional": false, + "readonly": false, + "type": "readonly {\n address: string;\n data: string;\n logIndex?: number | string;\n topics: readonly string[];\n}[]" + } + } + }, + "ReadRef": { + "type": "{\n requestId: `0x${string}` | bigint;\n} | {\n txHash: `0x${string}`;\n}", + "members": {} + }, + "ReadLifecycleOptions": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadLifecycleOptions", + "members": { + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "resultShape": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadFees": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadFees", + "members": { + "burned": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "paid": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "refunded": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refundFailed": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + } + } + }, + "UniversalReadResponse": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse", + "members": { + "callbackDelivered": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "callbackFailReason": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "decoded": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").DecodedReadResult | undefined" + }, + "decodeError": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destination": { + "optional": false, + "readonly": false, + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}" + }, + "errorMsg": { + "optional": false, + "readonly": false, + "type": "string" + }, + "explorerUrl": { + "optional": false, + "readonly": false, + "type": "string" + }, + "fees": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadFees" + }, + "isTerminal": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "outcome": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME" + }, + "pcTx": { + "optional": false, + "readonly": false, + "type": "readonly {\n blockHeight: number;\n errorMsg: string;\n status: string;\n txHash: `0x${string}`;\n}[]" + }, + "raw": { + "optional": false, + "readonly": false, + "type": "{\n errorCode: import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n resultData: `0x${string}`;\n status: import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n} | null" + }, + "refresh": { + "optional": false, + "readonly": false, + "type": "() => Promise>" + }, + "request": { + "optional": false, + "readonly": false, + "type": "{\n callbackGasLimit: bigint;\n callbackTarget: `0x${string}`;\n createdAtHeight: bigint;\n logIndex: number;\n originalFunder: `0x${string}`;\n refundTo: `0x${string}`;\n spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec;\n}" + }, + "requestId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "requestIdUint": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "status": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "value": { + "optional": true, + "readonly": false, + "type": "T | undefined" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/read-state/read-state.types\").ReadLifecycleOptions) => Promise>" + } + } + }, + "ReadResponseTuple": { + "type": "{\n -readonly [K in keyof R]: import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse ? T : unknown>;\n}", + "members": {} + }, + "BatchReadResponse": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").BatchReadResponse", + "members": { + "atomic": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "count": { + "optional": false, + "readonly": false, + "type": "number" + }, + "reads": { + "optional": false, + "readonly": false, + "type": "{\n -readonly [K in keyof R]: import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse ? T : unknown>;\n}" + }, + "transactionHashes": { + "optional": true, + "readonly": false, + "type": "readonly `0x${string}`[] | undefined" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: Omit) => Promise>" + } + } + }, + "ReadOptions": { + "type": "((import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">)) & {\n callback?: (Pick & Required>) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n };\n}", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "advanced": { + "optional": true, + "readonly": false, + "type": "{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n} | undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "({\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} & {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n}) | ({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick & Pick & Required>) | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadPrepareOptions": { + "type": "((((({\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\">) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n}) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">)) & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n}) | ((({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n}) | ({\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\">)) & {\n blockNumber?: never;\n minConfirmations?: never;\n})) & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n}) & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "advanced": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadQueryOptions": { + "type": "({\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\">) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n}) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n}) | ({\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\">)", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadCallbackOptions": { + "type": "{\n callback?: ({\n gasLimit?: bigint;\n target: `0x${string}`;\n } & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n };\n}", + "members": { + "callback": { + "optional": true, + "readonly": false, + "type": "({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} | undefined" + } + } + }, + "ReadValue": { + "type": "O extends {\n abi: infer A extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: infer F extends string;\n} ? number extends A[\"length\"] ? unknown : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, O extends {\n args: infer Args extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n} ? Args : readonly [\n] extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> ? import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> & readonly [\n] : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>> extends infer Selected ? Selected extends {\n outputs: readonly unknown[];\n type: \"function\";\n} & import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiFunction ? {\n [key in keyof {\n [key in keyof import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"]]: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterToPrimitiveType, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"][key], import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterKind>;\n }]: {\n [key in keyof import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"]]: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterToPrimitiveType, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"][key], import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterKind>;\n }[key];\n} extends infer types ? types extends readonly [\n] ? void : types extends readonly [\n infer type\n] ? type : types : never : never : never : O extends {\n web2: {\n extract: infer E extends readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n };\n} ? {\n readonly [K in keyof E]: {\n bool: boolean;\n bytes: `0x${string}`;\n int256: bigint;\n string: string;\n uint256: bigint;\n }[E[K][\"valueType\"]];\n} : O extends {\n storageSlot: unknown;\n} ? `0x${string}` : O extends {\n idl: infer I extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} ? string extends Extract, string> ? unknown : (O extends {\n functionName: infer N extends string;\n} ? N : undefined) extends string ? import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/index\").IdlAccounts[{\n [K in Extract, string>]: Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : K> extends Lowercase<(O extends {\n functionName: infer N extends string;\n } ? N : undefined) & string extends `${infer H}_${infer T}` ? `${H}${Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : (O extends {\n functionName: infer N extends string;\n } ? N : undefined) & string> ? K : never;\n}[Extract, string>]] : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/index\").IdlAccounts[Extract, string>] : bigint", + "members": {} + }, + "ValidateReadCall": { + "type": "O extends {\n abi: infer A extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: infer F extends string;\n} ? (readonly [\n] extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> ? {\n args?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n} : {\n args: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n}) & {\n functionName: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionName;\n} : O extends {\n functionName: infer N extends string;\n idl: infer I extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} ? string extends Extract, string> ? unknown : [\n {\n [K in Extract, string>]: Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : K> extends Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : N> ? K : never;\n }[Extract, string>]\n] extends [\n never\n] ? {\n functionName: Extract, string>;\n} : unknown : unknown", + "members": {} + }, + "ReadWeb2Options": { + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options", + "members": { + "body": { + "optional": true, + "readonly": false, + "type": "string | Uint8Array | undefined" + }, + "extract": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[]" + }, + "headers": { + "optional": true, + "readonly": false, + "type": "Record | undefined" + }, + "method": { + "optional": true, + "readonly": false, + "type": "\"GET\" | \"POST\" | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadTrackOptions": { + "type": "{\n advanced?: Omit, \"enforceGasCheck\">;\n resultShape?: import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape;\n}", + "members": { + "advanced": { + "optional": true, + "readonly": false, + "type": "Omit<{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n}, \"enforceGasCheck\"> | undefined" + }, + "resultShape": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape | undefined" + } + } + }, + "ReadExecuteOptions": { + "type": "{\n advanced?: {\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n } | undefined;\n progressHook?: ((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined;\n waitForCompletion?: boolean | undefined;\n}", + "members": { + "advanced": { + "optional": true, + "readonly": false, + "type": "{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n} | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + } + } + }, + "UNIVERSAL_READ_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS", + "members": { + "ABORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.ABORTED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.EXPIRED" + }, + "FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.FAILED" + }, + "FULFILLED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.FULFILLED" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.PENDING" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.UNSPECIFIED" + }, + "VOTING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.VOTING" + } + } + }, + "READ_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS", + "members": { + "ERROR": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.ERROR" + }, + "SUCCESS": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.SUCCESS" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.UNSPECIFIED" + } + } + }, + "READ_ERROR_CODE": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE", + "members": { + "INVALID_QUERY": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.INVALID_QUERY" + }, + "INVALID_RESULT": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.INVALID_RESULT" + }, + "NOT_FOUND": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.NOT_FOUND" + }, + "REJECTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.REJECTED" + }, + "REVERTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.REVERTED" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.UNSPECIFIED" + }, + "UNSUPPORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.UNSUPPORTED" + } + } + }, + "READ_OUTCOME": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME", + "members": { + "ABORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.ABORTED" + }, + "CALLBACK_FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.CALLBACK_FAILED" + }, + "DECODE_FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.DECODE_FAILED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.EXPIRED" + }, + "FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.FAILED" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.PENDING" + }, + "SOURCE_ERROR": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.SOURCE_ERROR" + }, + "SUCCESS": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.SUCCESS" + }, + "UNKNOWN": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.UNKNOWN" + } + } + }, + "CONTRACT_REQUEST_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS", + "members": { + "EXECUTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.EXECUTED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.EXPIRED" + }, + "NONE": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.NONE" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.PENDING" + }, + "SETTLED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.SETTLED" + } + } + }, + "TERMINAL_READ_STATUSES": { + "type": "ReadonlySet", + "members": {} + }, + "ReadStateError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadStateError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidReadQueryError": { + "type": "import(\"sdk/src/lib/read-state/errors\").InvalidReadQueryError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidReadSpecError": { + "type": "import(\"sdk/src/lib/read-state/errors\").InvalidReadSpecError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "violations": { + "optional": false, + "readonly": true, + "type": "readonly import(\"sdk/src/lib/read-state/errors\").ReadSpecViolation[]" + } + } + }, + "ReadHeightUnavailableError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadHeightUnavailableError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "UnsupportedReadDestinationError": { + "type": "import(\"sdk/src/lib/read-state/errors\").UnsupportedReadDestinationError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadDecodeError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadDecodeError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadTimeoutError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadTimeoutError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "lastStatus": { + "optional": false, + "readonly": true, + "type": "number" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadNotFoundError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadNotFoundError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadRegistryUnavailableError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadRegistryUnavailableError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadSpecViolation": { + "type": "\"CALLBACK_GAS_LIMIT_EXCEEDED\" | \"DOMAIN_BLOCKED\" | \"EMPTY_QUERY\" | \"EXCESSIVE_FEE\" | \"INSUFFICIENT_CALLBACK_BUDGET\" | \"INSUFFICIENT_FEE\" | \"INVALID_ACCOUNT_ID\" | \"INVALID_BLOCK_NUMBER\" | \"INVALID_EXPIRY_HEIGHT\" | \"INVALID_MIN_CONFIRMATIONS\" | \"SVM_OWNER_NOT_32_BYTES\" | \"ZERO_CALLBACK_BUDGET\" | \"ZERO_CALLBACK_GAS_LIMIT\" | \"ZERO_REVERT_RECIPIENT\"", + "members": {} + }, + "resolveDestination": { + "type": "(dest: import(\"sdk/src/lib/read-state/read-state.types\").ReadDestination) => import(\"sdk/src/lib/read-state/read-state.types\").ResolvedDestination", + "members": {} + }, + "encodeReadQuery": { + "type": "(destination: import(\"sdk/src/lib/read-state/read-state.types\").ReadDestination, query: import(\"sdk/src/lib/read-state/read-state.types\").ReadQuery, options?: {\n blockNumber?: bigint;\n minSlot?: bigint;\n}) => import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery", + "members": {} + }, + "decodeReadResult": { + "type": "(resultData: `0x${string}`, shape: import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape) => import(\"sdk/src/lib/read-state/read-state.types\").DecodedReadResult", + "members": {} + }, + "parseReadRequestsFromReceipt": { + "type": "(receipt: import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike, universalCallback: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").ParsedReadRequest[]", + "members": {} + }, + "parseFulfilOutcome": { + "type": "(receipt: import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike, universalCallback: `0x${string}`, requestId: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").FulfilOutcome", + "members": {} + }, + "buildReadSpecFromPreflight": { + "type": "(preflight: import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight, params: import(\"sdk/src/lib/read-state/read-state.types\").BuildReadSpecParams, defaults?: {\n refundTo?: `0x${string}`;\n}) => import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead", + "members": {} + }, + "validateReadSpec": { + "type": "(input: import(\"sdk/src/lib/read-state/validate\").ValidateReadSpecInput) => {\n ok: false;\n violations: import(\"sdk/src/lib/read-state/errors\").ReadSpecViolation[];\n} | {\n ok: true;\n}", + "members": {} + }, + "toCallData": { + "type": "(prepared: import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead, target: {\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: (spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpecTuple, callbackGasLimit: bigint) => readonly unknown[];\n functionName: string;\n}) => {\n data: `0x${string}`;\n value: bigint;\n}", + "members": {} + }, + "sizeCallbackBudget": { + "type": "(callbackGasLimit: bigint, pushGasPrice: bigint, buffer?: number) => bigint", + "members": {} + }, + "inferResultShape": { + "type": "(namespace: string, query: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape", + "members": {} + }, + "toRequestIdHex": { + "type": "(id: `0x${string}` | bigint) => `0x${string}`", + "members": {} + }, + "toReadQuery": { + "type": "(subject: string, o: ReadOptionsInput, resolvedTokenProgram?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@solana/web3.js/lib/index\").PublicKey) => import(\"sdk/src/lib/read-state/read-state.types\").ReadQuery", + "members": {} + }, + "UNIVERSAL_CALLBACK_EVM": { + "type": "readonly [\n {\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"requestExternalReadSelf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"estimateFee\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"statusOf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"enum RequestStatus\";\n readonly name: \"\";\n readonly type: \"uint8\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"isFulfilled\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getPendingRead\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly internalType: \"struct PendingRead\";\n readonly name: \"\";\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"totalEscrowed\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"blockedDomains\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly indexed: false;\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"readSpec\";\n readonly type: \"tuple\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"totalPaid\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"protocolFee\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ReadRequested\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"ReadFulfilled\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"reason\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"CallbackFailed\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"gasReported\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"burned\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"CallbackGasReported\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundSent\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundFailed\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RequestExpired\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"vaultPC\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ProtocolFeeDistributed\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidAccountId\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"EmptyQuery\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidMinConfirmations\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"DomainBlocked\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidBlockNumber\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidExpiryHeight\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroRevertRecipient\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroCallbackGasLimit\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint64\";\n readonly name: \"provided\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"max\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"CallbackGasLimitExceeded\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"required\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"InsufficientFee\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ExcessiveFee\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"actual\";\n readonly type: \"uint8\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"expected\";\n readonly type: \"uint8\";\n }\n ];\n readonly name: \"InvalidRequestStatus\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ContractIsPaused\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"CallerIsNotUCallbackModule\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n }\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"requestExternalReadSelf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n}" + }, + "1": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"estimateFee\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "2": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"statusOf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"enum RequestStatus\";\n readonly name: \"\";\n readonly type: \"uint8\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "3": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"isFulfilled\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "4": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getPendingRead\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly internalType: \"struct PendingRead\";\n readonly name: \"\";\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "5": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"totalEscrowed\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "6": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"blockedDomains\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "7": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly indexed: false;\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"readSpec\";\n readonly type: \"tuple\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"totalPaid\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"protocolFee\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ReadRequested\";\n readonly type: \"event\";\n}" + }, + "8": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"ReadFulfilled\";\n readonly type: \"event\";\n}" + }, + "9": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"reason\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"CallbackFailed\";\n readonly type: \"event\";\n}" + }, + "10": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"gasReported\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"burned\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"CallbackGasReported\";\n readonly type: \"event\";\n}" + }, + "11": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundSent\";\n readonly type: \"event\";\n}" + }, + "12": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundFailed\";\n readonly type: \"event\";\n}" + }, + "13": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RequestExpired\";\n readonly type: \"event\";\n}" + }, + "14": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"vaultPC\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ProtocolFeeDistributed\";\n readonly type: \"event\";\n}" + }, + "15": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidAccountId\";\n readonly type: \"error\";\n}" + }, + "16": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"EmptyQuery\";\n readonly type: \"error\";\n}" + }, + "17": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidMinConfirmations\";\n readonly type: \"error\";\n}" + }, + "18": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"DomainBlocked\";\n readonly type: \"error\";\n}" + }, + "19": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidBlockNumber\";\n readonly type: \"error\";\n}" + }, + "20": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidExpiryHeight\";\n readonly type: \"error\";\n}" + }, + "21": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroRevertRecipient\";\n readonly type: \"error\";\n}" + }, + "22": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroCallbackGasLimit\";\n readonly type: \"error\";\n}" + }, + "23": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint64\";\n readonly name: \"provided\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"max\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"CallbackGasLimitExceeded\";\n readonly type: \"error\";\n}" + }, + "24": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"required\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"InsufficientFee\";\n readonly type: \"error\";\n}" + }, + "25": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ExcessiveFee\";\n readonly type: \"error\";\n}" + }, + "26": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"actual\";\n readonly type: \"uint8\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"expected\";\n readonly type: \"uint8\";\n }\n ];\n readonly name: \"InvalidRequestStatus\";\n readonly type: \"error\";\n}" + }, + "27": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ContractIsPaused\";\n readonly type: \"error\";\n}" + }, + "28": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"CallerIsNotUCallbackModule\";\n readonly type: \"error\";\n}" + }, + "29": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n}" + }, + "length": { + "optional": false, + "readonly": true, + "type": "30" + } + } + }, + "UNIVERSAL_READ_REGISTRY_EVM": { + "type": "readonly [\n {\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n },\n {\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"read\";\n readonly outputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"universalCallback_\";\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"constructor\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"initialize\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getLocalContext\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"hasResult\";\n readonly outputs: readonly [\n {\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"onUniversalData\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"queryKeyOf\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes32\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"readerOf\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"requestOrderOf\";\n readonly outputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"universalCallback\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"resultByRequestId\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"latestResult\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"version\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"Initialized\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadRequested\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadStored\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidInitialization\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"NotInitializing\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroAddressInit\";\n readonly type: \"error\";\n }\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n },\n {\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"read\";\n readonly outputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n}" + }, + "1": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"universalCallback_\";\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"constructor\";\n}" + }, + "2": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"initialize\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n}" + }, + "3": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getLocalContext\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "4": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"hasResult\";\n readonly outputs: readonly [\n {\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "5": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"onUniversalData\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n}" + }, + "6": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"queryKeyOf\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes32\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "7": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"readerOf\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "8": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"requestOrderOf\";\n readonly outputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "9": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"universalCallback\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "10": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"resultByRequestId\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "11": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"latestResult\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "12": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"version\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"Initialized\";\n readonly type: \"event\";\n}" + }, + "13": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadRequested\";\n readonly type: \"event\";\n}" + }, + "14": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadStored\";\n readonly type: \"event\";\n}" + }, + "15": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidInitialization\";\n readonly type: \"error\";\n}" + }, + "16": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"NotInitializing\";\n readonly type: \"error\";\n}" + }, + "17": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n}" + }, + "18": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroAddressInit\";\n readonly type: \"error\";\n}" + }, + "length": { + "optional": false, + "readonly": true, + "type": "19" + } + } + }, + "PushChainExecutionError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").PushChainExecutionError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PushChainBatchExecutionError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").PushChainBatchExecutionError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": false, + "readonly": true, + "type": "`0x${string}`[]" + } + } + }, + "DecodedErrorPayload": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload", + "members": { + "decoded": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "name": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "selector": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "PushChainInitializeOptions": { + "type": "import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions", + "members": { + "agenticWallet": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "blockExplorers": { + "optional": true, + "readonly": false, + "type": "Partial> | undefined" + }, + "network": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "printTraces": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "rpcUrls": { + "optional": true, + "readonly": false, + "type": "Partial> | undefined" + } + } + }, + "AGENTIC_ERROR_CODE": { + "type": "{\n readonly AGENT_GAS_INSUFFICIENT: \"AGENT_GAS_INSUFFICIENT\";\n readonly AGENT_IS_OWNER: \"AGENT_IS_OWNER\";\n readonly AMBIGUOUS_RULE: \"AMBIGUOUS_RULE\";\n readonly ASSET_CHAIN_MISMATCH: \"ASSET_CHAIN_MISMATCH\";\n readonly CAPABILITY_UNAVAILABLE: \"CAPABILITY_UNAVAILABLE\";\n readonly DELETE_NEEDS_TARGET: \"DELETE_NEEDS_TARGET\";\n readonly DUPLICATE_RULE: \"DUPLICATE_RULE\";\n readonly FROM_NOT_ALLOWED: \"FROM_NOT_ALLOWED\";\n readonly INCONSISTENT_READ: \"INCONSISTENT_READ\";\n readonly INDEX_RACE: \"INDEX_RACE\";\n readonly INVALID_RULE: \"INVALID_RULE\";\n readonly NO_RULES_FOR_CHAIN: \"NO_RULES_FOR_CHAIN\";\n readonly NOT_AGENTIC_WALLET: \"NOT_AGENTIC_WALLET\";\n readonly NOT_ALLOWED_IN_AGENTIC_MODE: \"NOT_ALLOWED_IN_AGENTIC_MODE\";\n readonly NOT_OWNER_OR_AGENT: \"NOT_OWNER_OR_AGENT\";\n readonly NOT_WALLET_OWNER: \"NOT_WALLET_OWNER\";\n readonly READ_ONLY: \"READ_ONLY\";\n readonly RECEIPT_MISMATCH: \"RECEIPT_MISMATCH\";\n readonly RECEIPT_UNAVAILABLE: \"RECEIPT_UNAVAILABLE\";\n readonly RULE_NOT_FOUND: \"RULE_NOT_FOUND\";\n readonly RULE_READ_FAILED: \"RULE_READ_FAILED\";\n readonly TARGET_NOT_ON_RULE_CHAIN: \"TARGET_NOT_ON_RULE_CHAIN\";\n readonly WALLET_BALANCE_INSUFFICIENT: \"WALLET_BALANCE_INSUFFICIENT\";\n readonly WALLET_NOT_DEPLOYED: \"WALLET_NOT_DEPLOYED\";\n}", + "members": { + "AGENT_GAS_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\"" + }, + "AGENT_IS_OWNER": { + "optional": false, + "readonly": true, + "type": "\"AGENT_IS_OWNER\"" + }, + "AMBIGUOUS_RULE": { + "optional": false, + "readonly": true, + "type": "\"AMBIGUOUS_RULE\"" + }, + "ASSET_CHAIN_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"ASSET_CHAIN_MISMATCH\"" + }, + "CAPABILITY_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"CAPABILITY_UNAVAILABLE\"" + }, + "DELETE_NEEDS_TARGET": { + "optional": false, + "readonly": true, + "type": "\"DELETE_NEEDS_TARGET\"" + }, + "DUPLICATE_RULE": { + "optional": false, + "readonly": true, + "type": "\"DUPLICATE_RULE\"" + }, + "FROM_NOT_ALLOWED": { + "optional": false, + "readonly": true, + "type": "\"FROM_NOT_ALLOWED\"" + }, + "INCONSISTENT_READ": { + "optional": false, + "readonly": true, + "type": "\"INCONSISTENT_READ\"" + }, + "INDEX_RACE": { + "optional": false, + "readonly": true, + "type": "\"INDEX_RACE\"" + }, + "INVALID_RULE": { + "optional": false, + "readonly": true, + "type": "\"INVALID_RULE\"" + }, + "NO_RULES_FOR_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"NO_RULES_FOR_CHAIN\"" + }, + "NOT_AGENTIC_WALLET": { + "optional": false, + "readonly": true, + "type": "\"NOT_AGENTIC_WALLET\"" + }, + "NOT_ALLOWED_IN_AGENTIC_MODE": { + "optional": false, + "readonly": true, + "type": "\"NOT_ALLOWED_IN_AGENTIC_MODE\"" + }, + "NOT_OWNER_OR_AGENT": { + "optional": false, + "readonly": true, + "type": "\"NOT_OWNER_OR_AGENT\"" + }, + "NOT_WALLET_OWNER": { + "optional": false, + "readonly": true, + "type": "\"NOT_WALLET_OWNER\"" + }, + "READ_ONLY": { + "optional": false, + "readonly": true, + "type": "\"READ_ONLY\"" + }, + "RECEIPT_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_MISMATCH\"" + }, + "RECEIPT_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_UNAVAILABLE\"" + }, + "RULE_NOT_FOUND": { + "optional": false, + "readonly": true, + "type": "\"RULE_NOT_FOUND\"" + }, + "RULE_READ_FAILED": { + "optional": false, + "readonly": true, + "type": "\"RULE_READ_FAILED\"" + }, + "TARGET_NOT_ON_RULE_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"TARGET_NOT_ON_RULE_CHAIN\"" + }, + "WALLET_BALANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"WALLET_BALANCE_INSUFFICIENT\"" + }, + "WALLET_NOT_DEPLOYED": { + "optional": false, + "readonly": true, + "type": "\"WALLET_NOT_DEPLOYED\"" + } + } + }, + "AgenticError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"AMBIGUOUS_RULE\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"DELETE_NEEDS_TARGET\" | \"DUPLICATE_RULE\" | \"FROM_NOT_ALLOWED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"" + }, + "details": { + "optional": true, + "readonly": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "AgenticRevertError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticRevertError", + "members": { + "agenticCode": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "AgenticAddress": { + "type": "`0x${string}`", + "members": {} + }, + "AgenticDoor": { + "type": "\"agent\" | \"owner\"", + "members": {} + }, + "AgenticErrorCode": { + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"AMBIGUOUS_RULE\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"DELETE_NEEDS_TARGET\" | \"DUPLICATE_RULE\" | \"FROM_NOT_ALLOWED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"", + "members": {} + }, + "AgenticHex": { + "type": "`0x${string}`", + "members": {} + }, + "AgenticNamespace": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace", + "members": { + "create": { + "optional": false, + "readonly": false, + "type": "(label: string, options: import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions) => Promise" + }, + "derive": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n index?: number;\n}) => Promise<{\n address: `0x${string}`;\n deployed: boolean;\n index: number;\n}>" + }, + "list": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n wallets: import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary[];\n}>" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "(address: `0x${string}`) => import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet" + } + } + }, + "AgenticProgressHook": { + "type": "(event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void", + "members": {} + }, + "AgenticTxMetadata": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticTxMetadata", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destinationAccount": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "destinationCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "destinationInstruction": { + "optional": true, + "readonly": false, + "type": "{\n accounts: readonly {\n isWritable: boolean;\n pubkey: `0x${string}`;\n }[];\n data: `0x${string}`;\n program: `0x${string}`;\n} | undefined" + }, + "destinationTransfer": { + "optional": true, + "readonly": false, + "type": "{\n amount: bigint;\n recipient: `0x${string}`;\n token: `0x${string}`;\n} | undefined" + }, + "door": { + "optional": false, + "readonly": false, + "type": "\"agent\" | \"owner\"" + }, + "nativeCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "rawData": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rawTo": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesId": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticWallet": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "checkpoints": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n sinceBlock?: bigint;\n}) => Promise<{\n checkpoints: import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint[];\n}>" + }, + "info": { + "optional": false, + "readonly": false, + "type": "() => Promise" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n owner: `0x${string}`;\n}>" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "{\n add(rules: import(\"sdk/src/lib/agentic/agentic.types\").RuleInput[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise<{\n rulesIds: `0x${string}`[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n delete(rulesIds: `0x${string}`[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n delete(params: {\n all: true;\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n get(rulesId: `0x${string}`): Promise;\n list(): Promise<{\n rules: import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord[];\n }>;\n update(params: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n rules: {\n rule: import(\"sdk/src/lib/agentic/agentic.types\").RuleInput;\n rulesId: `0x${string}`;\n }[];\n }): Promise<{\n rules: {\n replaced: `0x${string}`;\n rulesId: `0x${string}`;\n }[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n}" + }, + "setLabel": { + "optional": false, + "readonly": false, + "type": "(label: string, opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n}) => Promise" + } + } + }, + "AllowedCall": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleCall", + "members": { + "app": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "label": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "maxValue": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "pins": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Pin[] | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector" + }, + "target": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "AssetCap": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset", + "members": { + "maxPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/tokens\").MoveableToken | string" + } + } + }, + "Checkpoint": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint", + "members": { + "blockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "kind": { + "optional": false, + "readonly": false, + "type": "\"OWNER_ACTION\" | \"RULES_GRANTED\" | \"RULES_REVOKED\"" + }, + "ref": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "seq": { + "optional": false, + "readonly": false, + "type": "number" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "CheckpointKind": { + "type": "\"OWNER_ACTION\" | \"RULES_GRANTED\" | \"RULES_REVOKED\"", + "members": {} + }, + "CreateOptions": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions", + "members": { + "progressHook": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook | undefined" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleInput[]" + } + } + }, + "CreateResult": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateResult", + "members": { + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "rulesIds": { + "optional": false, + "readonly": false, + "type": "`0x${string}`[]" + }, + "tx": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ForeignChainNamespace": { + "type": "`eip155:${string}` | `solana:${string}`", + "members": {} + }, + "DecodedSolanaRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").DecodedSolanaRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "assets": { + "optional": false, + "readonly": false, + "type": "{\n maxPerCall: bigint;\n maxTotal: bigint;\n token: string;\n}[]" + }, + "ceaAccounts": { + "optional": false, + "readonly": false, + "type": "readonly `0x${string}`[]" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "`solana:${string}`" + }, + "dataPins": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/agentic/codec/svm-terms\").SvmDataPinWire[]" + }, + "expectedCEA": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "format": { + "optional": false, + "readonly": false, + "type": "\"decoded\"" + }, + "gatewayProgram": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "maxGasPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pins": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/agentic/codec/svm-terms\").SvmAccountPinWire[]" + }, + "programs": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/agentic/codec/svm-terms\").AllowedProgramWire[]" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Rule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Rule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleCall[]" + }, + "assets": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset[] | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "maxGasPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "RuleInput": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").DecodedSolanaRule | import(\"sdk/src/lib/agentic/agentic.types\").Rule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "assets": { + "optional": true, + "readonly": false, + "type": "{\n maxPerCall: bigint;\n maxTotal: bigint;\n token: string;\n}[] | import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset[] | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "maxGasPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Pin": { + "type": "{\n account: number;\n arg?: never;\n expected: \"agentic:wallet\" | string;\n max?: never;\n token?: import(\"sdk/src/lib/constants/tokens\").MoveableToken | string;\n} | {\n account?: never;\n arg: import(\"sdk/src/lib/agentic/agentic.types\").ArgumentPath;\n expected: \"agentic:wallet\" | `0x${string}` | `0x${string}` | bigint;\n max?: never;\n} | {\n account?: never;\n arg: import(\"sdk/src/lib/agentic/agentic.types\").ArgumentPath;\n expected?: never;\n max: bigint;\n}", + "members": { + "account": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "arg": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ArgumentPath | undefined" + }, + "expected": { + "optional": true, + "readonly": false, + "type": "bigint | string | undefined" + }, + "max": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "Spent": { + "type": "{\n actions: {\n amountSpent: bigint;\n callsUsed: number;\n selector: \"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector;\n target: `0x${string}`;\n valueSpent: bigint;\n }[];\n kind: \"native\";\n} | {\n amountSpent: bigint;\n callsUsed: number;\n kind: \"native\";\n valueSpent: bigint;\n} | {\n assets: {\n spent: bigint;\n token: string;\n }[];\n kind: \"universal\";\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"native\" | \"universal\"" + } + } + }, + "WalletMarker": { + "type": "\"agentic:wallet\"", + "members": {} + }, + "ArgumentPath": { + "type": "number | readonly number[]", + "members": {} + }, + "RulesRecord": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "enabled": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "rule": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").DecodedSolanaRule | import(\"sdk/src/lib/agentic/agentic.types\").Rule" + }, + "rulesId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "spent": { + "optional": false, + "readonly": false, + "type": "{\n actions: {\n amountSpent: bigint;\n callsUsed: number;\n selector: \"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector;\n target: `0x${string}`;\n valueSpent: bigint;\n }[];\n kind: \"native\";\n} | {\n amountSpent: bigint;\n callsUsed: number;\n kind: \"native\";\n valueSpent: bigint;\n} | {\n assets: {\n spent: bigint;\n token: string;\n }[];\n kind: \"universal\";\n}" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Selector": { + "type": "`${string}(${string})` | `0x${string}`", + "members": {} + }, + "WalletInfo": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").WalletInfo", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "label": { + "optional": false, + "readonly": false, + "type": "string" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "rulesCount": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "WalletSummary": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "label": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesCount": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "PushChain": { + "type": "import(\"sdk/src/lib/push-chain/push-chain\").PushChain", + "members": { + "accountStatus": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus" + }, + "accountStatusReady": { + "optional": false, + "readonly": false, + "type": "Promise" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace" + }, + "explorer": { + "optional": false, + "readonly": false, + "type": "{\n getTransactionUrl: (txHash: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n listAllUrls: () => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n listUrls: (options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n}" + }, + "funds": { + "optional": false, + "readonly": false, + "type": "{\n getConversionQuote: (amountIn: bigint, options: {\n from: import(\"sdk/src/lib/constants/tokens\").PayableToken | undefined;\n to: import(\"sdk/src/lib/constants/tokens\").MoveableToken | undefined;\n }) => Promise;\n}" + }, + "getAccountStatus": { + "optional": false, + "readonly": false, + "type": "(options?: {\n forceRefresh?: boolean;\n}) => Promise" + }, + "isReadMode": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "moveable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").MoveableTokenAccessor;\n}" + }, + "payable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").PayableTokenAccessor;\n}" + }, + "reinitialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "universal": { + "optional": false, + "readonly": false, + "type": "{\n readonly account: `0x${string}`;\n executeReads: (reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>;\n executeTransactions: (txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise;\n migrateCEA: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"migrateCEA\"];\n readonly origin: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n prepareRead: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n prepareTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"prepareTransaction\"];\n read: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n rescueFunds: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"rescueFunds\"];\n sendTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"execute\"];\n signMessage: (data: Uint8Array) => Promise;\n signTypedData: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n trackRead: {\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n };\n trackTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"trackTransaction\"];\n}" + }, + "upgradeAccount": { + "optional": false, + "readonly": false, + "type": "(options?: {\n progressHook?: (progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n}) => Promise" + } + } + }, + "Preset": { + "type": "import(\"sdk/src/lib/agentic/presets/types\").Preset", + "members": { + "chains": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace[]" + }, + "constant": { + "optional": false, + "readonly": false, + "type": "\"DEXES\" | \"LENDING\" | \"PREDICTION\" | \"STAKING\"" + }, + "name": { + "optional": false, + "readonly": false, + "type": "string" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"CATEGORY\"" + } + } + }, + "PresetCategory": { + "type": "\"DEXES\" | \"LENDING\" | \"PREDICTION\" | \"STAKING\"", + "members": {} + }, + "PresetAsset": { + "type": "import(\"sdk/src/lib/agentic/presets/types\").PresetAsset", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "maxPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/tokens\").MoveableToken | string" + } + } + }, + "PresetOptions": { + "type": "import(\"sdk/src/lib/agentic/presets/types\").PresetOptions", + "members": { + "agent": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "assets": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/presets/types\").PresetAsset[] | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "maxGasPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "validUntil": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadyPresetOptions": { + "type": "import(\"sdk/src/lib/agentic/presets/types\").ReadyPresetOptions", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "assets": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/presets/types\").PresetAsset[] | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "maxGasPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "PresetRuleTemplate": { + "type": "{\n agent?: `0x${string}`;\n validUntil?: number;\n} & Omit", + "members": { + "agent": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleCall[]" + }, + "assets": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset[] | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "maxGasPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "validUntil": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "AgenticPresets": { + "type": "import(\"sdk/src/lib/agentic/presets/types\").AgenticPresets", + "members": { + "get": { + "optional": false, + "readonly": false, + "type": "{\n (preset: import(\"sdk/src/lib/agentic/presets/types\").PresetCategory, options: import(\"sdk/src/lib/agentic/presets/types\").ReadyPresetOptions): {\n rules: import(\"sdk/src/lib/agentic/agentic.types\").Rule[];\n };\n (preset: import(\"sdk/src/lib/agentic/presets/types\").PresetCategory, options?: import(\"sdk/src/lib/agentic/presets/types\").PresetOptions): {\n rules: import(\"sdk/src/lib/agentic/presets/types\").PresetRuleTemplate[];\n };\n}" + }, + "list": { + "optional": false, + "readonly": false, + "type": "(options?: {\n type?: \"CATEGORY\";\n}) => {\n presets: import(\"sdk/src/lib/agentic/presets/types\").Preset[];\n}" + } + } + } + }, + "pushChainStatic": { + "CONSTANTS": { + "optional": false, + "readonly": false, + "type": "{\n AGENTIC: Readonly<{\n PRESETS: Readonly<{\n CATEGORY: Readonly<{\n DEXES: \"DEXES\";\n LENDING: \"LENDING\";\n PREDICTION: \"PREDICTION\";\n STAKING: \"STAKING\";\n }>;\n }>;\n WALLET: \"agentic:wallet\";\n }>;\n CHAIN: typeof import(\"sdk/src/lib/constants/enums\").CHAIN;\n LIBRARY: typeof import(\"sdk/src/lib/constants/enums\").LIBRARY;\n MOVEABLE: {\n TOKEN: import(\"sdk/src/lib/constants/tokens\").MoveableTokenConstantsMap;\n };\n PAYABLE: {\n TOKEN: import(\"sdk/src/lib/constants/tokens\").PayableTokenConstantsMap;\n };\n PUSH_NETWORK: typeof import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n READ: {\n readonly CALLBACK_BUDGET_BUFFER: 3;\n readonly CHAIN: {\n readonly WEB2: \"web2\";\n } & Readonly<{\n readonly ARBITRUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA;\n readonly BASE_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA;\n readonly BNB_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET;\n readonly ETHEREUM_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET;\n readonly ETHEREUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA;\n readonly PUSH_LOCALNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET;\n readonly PUSH_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET;\n readonly PUSH_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly PUSH_TESTNET_DONUT: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly SOLANA_DEVNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET;\n readonly SOLANA_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET;\n readonly SOLANA_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n readonly WEB2: \"web2\";\n }>;\n readonly DEFAULT_EXPIRY_BLOCKS: 300n;\n readonly ERROR_CODE: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n readonly MAX_CALLBACK_GAS_LIMIT: 1000000n;\n readonly MIN_CONFIRMATIONS_FLOOR: 1;\n readonly NAMESPACE: {\n readonly EVM: \"eip155\";\n readonly SVM: \"solana\";\n readonly WEB2: \"web2\";\n };\n readonly OUTCOME: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME;\n readonly REGISTRY_CALLBACK_GAS: 500000n;\n readonly RESULT_STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n readonly STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS;\n readonly UNIVERSAL_CALLBACK_ADDRESSES: Record;\n readonly UNIVERSAL_CORE_ADDRESSES: Record;\n readonly UNIVERSAL_READ_REGISTRY_ADDRESS: {\n readonly TESTNET_DONUT: \"0x00000000000000000000000000000000000000b2\";\n };\n readonly WEB2: \"web2\";\n readonly WEB2_DEFAULT_TIMEOUT_MS: 5000;\n readonly WEB2_MAX_EXTRACT_ENTRIES: 16;\n };\n}" + }, + "initialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "utils": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/utils\").Utils" + } + }, + "pushChainInstance": { + "accountStatus": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus" + }, + "accountStatusReady": { + "optional": false, + "readonly": false, + "type": "Promise" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace" + }, + "explorer": { + "optional": false, + "readonly": false, + "type": "{\n getTransactionUrl: (txHash: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n listAllUrls: () => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n listUrls: (options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n}" + }, + "funds": { + "optional": false, + "readonly": false, + "type": "{\n getConversionQuote: (amountIn: bigint, options: {\n from: import(\"sdk/src/lib/constants/tokens\").PayableToken | undefined;\n to: import(\"sdk/src/lib/constants/tokens\").MoveableToken | undefined;\n }) => Promise;\n}" + }, + "getAccountStatus": { + "optional": false, + "readonly": false, + "type": "(options?: {\n forceRefresh?: boolean;\n}) => Promise" + }, + "isReadMode": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "moveable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").MoveableTokenAccessor;\n}" + }, + "payable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").PayableTokenAccessor;\n}" + }, + "reinitialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "universal": { + "optional": false, + "readonly": false, + "type": "{\n readonly account: `0x${string}`;\n executeReads: (reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>;\n executeTransactions: (txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise;\n migrateCEA: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"migrateCEA\"];\n readonly origin: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n prepareRead: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n prepareTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"prepareTransaction\"];\n read: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n rescueFunds: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"rescueFunds\"];\n sendTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"execute\"];\n signMessage: (data: Uint8Array) => Promise;\n signTypedData: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n trackRead: {\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n };\n trackTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"trackTransaction\"];\n}" + }, + "upgradeAccount": { + "optional": false, + "readonly": false, + "type": "(options?: {\n progressHook?: (progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n}) => Promise" + } + }, + "transactionMethods": { + "account": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "executeReads": { + "optional": false, + "readonly": false, + "type": "(reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>" + }, + "executeTransactions": { + "optional": false, + "readonly": false, + "type": "(txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise" + }, + "migrateCEA": { + "optional": false, + "readonly": false, + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => Promise" + }, + "origin": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "prepareRead": { + "optional": false, + "readonly": false, + "type": "(subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>" + }, + "prepareTransaction": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions) => Promise" + }, + "read": { + "optional": false, + "readonly": false, + "type": "(subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>" + }, + "rescueFunds": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").RescueFundsParams) => Promise" + }, + "sendTransaction": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").ExecuteParams | import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions) => Promise" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": false, + "readonly": false, + "type": "({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise" + }, + "trackRead": { + "optional": false, + "readonly": false, + "type": "{\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n}" + }, + "trackTransaction": { + "optional": false, + "readonly": false, + "type": "(txHash: string, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TrackTransactionOptions) => Promise" + } + }, + "utilityMethods": { + "account": { + "optional": false, + "readonly": false, + "type": "{\n convertExecutorToOriginAccount: (ueaAddress: `0x${string}`, options?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n }) => Promise;\n convertOriginToExecutor: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n onlyCompute?: boolean;\n }) => Promise;\n deriveExecutorAccount: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n skipNetworkCheck?: boolean;\n }) => Promise;\n fromChainAgnostic: (caip: string) => import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n resolveControllerAccount: (address: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n skipNetworkCheck?: boolean;\n }) => Promise;\n toChainAgnostic: (address: string, options: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n toUniversal: (address: string, options: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n}" + }, + "agentic": { + "optional": false, + "readonly": true, + "type": "{\n readonly presets: import(\"sdk/src/lib/agentic/presets/types\").AgenticPresets;\n}" + }, + "chains": { + "optional": false, + "readonly": false, + "type": "{\n getChainName: (chainNamespace: string) => string | undefined;\n getChainNamespace: (chainName: string) => string | undefined;\n getSupportedChains: (network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK) => {\n chains: import(\"sdk/src/lib/constants/enums\").CHAIN[];\n };\n getSupportedChainsByName: (network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK) => {\n chains: string[];\n };\n}" + }, + "conversion": { + "optional": false, + "readonly": false, + "type": "{\n slippageToMinAmount(amount: string, options: {\n slippageBps: number;\n }): string;\n}" + }, + "helpers": { + "optional": false, + "readonly": false, + "type": "{\n encodeTxData({ abi, idl, functionName, args, }: {\n abi?: any;\n args?: any[];\n functionName: string;\n idl?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n }): `0x${string}`;\n formatUnits(value: bigint | string, decimalsOrOptions: {\n decimals: number;\n precision?: number;\n } | number): string;\n getChainName: (chainName: string) => string | undefined;\n parseUnits(value: string, exponent: {\n decimals: number;\n } | number): bigint;\n}" + }, + "signer": { + "optional": false, + "readonly": false, + "type": "{\n construct: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options: {\n signAndSendTransaction: (unsignedTx: Uint8Array) => Promise;\n signAuthorization?: (params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise;\n signMessage: (data: Uint8Array) => Promise;\n signTypedData?: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n }) => import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton;\n toUniversal: (signer: import(\"sdk/src/lib/universal/universal.types\").EthersV5SignerType | import(\"sdk/src/lib/universal/universal.types\").EthersV6SignerType | import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton | import(\"sdk/src/lib/universal/universal.types\").ViemSignerType) => Promise;\n toUniversalFromKeypair: (clientOrAccount: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@solana/web3.js/lib/index\").Keypair | import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").WalletClient | import(\"sdk/src/lib/universal/universal.types\").EthersV6SignerType, { chain, library }: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n library: import(\"sdk/src/lib/constants/enums\").LIBRARY;\n }) => Promise;\n}" + }, + "svm": { + "optional": false, + "readonly": false, + "type": "{\n getRegisteredIdls: () => Array<{\n address: `0x${string}`;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n }>;\n registerIdl: (idl: unknown) => void;\n}" + }, + "tokens": { + "optional": false, + "readonly": false, + "type": "{\n getMoveableTokens(chainOrClient?: import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/push-chain/push-chain\").PushChain): {\n tokens: Array<{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n decimals: number;\n mechanism: \"approve\" | \"native\" | \"permit2\";\n prc20Address?: `0x${string}`;\n sourceChain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n symbol: string;\n }>;\n };\n getPayableTokens(chainOrClient?: import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/push-chain/push-chain\").PushChain): {\n tokens: Array<{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n decimals: number;\n mechanism: \"approve\" | \"native\" | \"permit2\";\n symbol: string;\n }>;\n };\n getPC20Address(address: string, options: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n rpcUrls?: Partial>;\n strict?: boolean;\n }): Promise;\n getPRC20Address: (token: {\n address: string;\n chain: string;\n } | import(\"sdk/src/lib/constants/tokens\").MoveableToken, options?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n }) => {\n address: `0x${string}`;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n decimals: number;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n symbol: string;\n };\n}" + } + }, + "initialize": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise", + "agwConstants": { + "PRESETS": { + "optional": false, + "readonly": true, + "type": "{\n readonly CATEGORY: Readonly<{\n DEXES: \"DEXES\";\n LENDING: \"LENDING\";\n PREDICTION: \"PREDICTION\";\n STAKING: \"STAKING\";\n }>;\n}" + }, + "WALLET": { + "optional": false, + "readonly": true, + "type": "\"agentic:wallet\"" + } + }, + "constants": { + "AGENTIC": { + "optional": false, + "readonly": false, + "type": "{\n readonly PRESETS: Readonly<{\n CATEGORY: Readonly<{\n DEXES: \"DEXES\";\n LENDING: \"LENDING\";\n PREDICTION: \"PREDICTION\";\n STAKING: \"STAKING\";\n }>;\n }>;\n readonly WALLET: \"agentic:wallet\";\n}" + }, + "CHAIN": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "LIBRARY": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").LIBRARY" + }, + "MOVEABLE": { + "optional": false, + "readonly": false, + "type": "{\n TOKEN: import(\"sdk/src/lib/constants/tokens\").MoveableTokenConstantsMap;\n}" + }, + "PAYABLE": { + "optional": false, + "readonly": false, + "type": "{\n TOKEN: import(\"sdk/src/lib/constants/tokens\").PayableTokenConstantsMap;\n}" + }, + "PUSH_NETWORK": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "READ": { + "optional": false, + "readonly": false, + "type": "{\n readonly CALLBACK_BUDGET_BUFFER: 3;\n readonly CHAIN: {\n readonly WEB2: \"web2\";\n } & Readonly<{\n readonly ARBITRUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA;\n readonly BASE_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA;\n readonly BNB_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET;\n readonly ETHEREUM_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET;\n readonly ETHEREUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA;\n readonly PUSH_LOCALNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET;\n readonly PUSH_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET;\n readonly PUSH_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly PUSH_TESTNET_DONUT: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly SOLANA_DEVNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET;\n readonly SOLANA_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET;\n readonly SOLANA_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n readonly WEB2: \"web2\";\n }>;\n readonly DEFAULT_EXPIRY_BLOCKS: 300n;\n readonly ERROR_CODE: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n readonly MAX_CALLBACK_GAS_LIMIT: 1000000n;\n readonly MIN_CONFIRMATIONS_FLOOR: 1;\n readonly NAMESPACE: {\n readonly EVM: \"eip155\";\n readonly SVM: \"solana\";\n readonly WEB2: \"web2\";\n };\n readonly OUTCOME: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME;\n readonly REGISTRY_CALLBACK_GAS: 500000n;\n readonly RESULT_STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n readonly STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS;\n readonly UNIVERSAL_CALLBACK_ADDRESSES: Record;\n readonly UNIVERSAL_CORE_ADDRESSES: Record;\n readonly UNIVERSAL_READ_REGISTRY_ADDRESS: {\n readonly TESTNET_DONUT: \"0x00000000000000000000000000000000000000b2\";\n };\n readonly WEB2: \"web2\";\n readonly WEB2_DEFAULT_TIMEOUT_MS: 5000;\n readonly WEB2_MAX_EXTRACT_ENTRIES: 16;\n}" + } + } + }, + "scope": "All root exports and declared public members, PushChain static/instance members, universal transaction methods, utility groups, readonly/optional markers and constants. Behavior/default/deployment changes need the written session review." +} diff --git a/plan/agw/research/preset-live-2026-10-15/build.log b/plan/agw/research/preset-live-2026-10-15/build.log new file mode 100644 index 00000000..cdeb4133 --- /dev/null +++ b/plan/agw/research/preset-live-2026-10-15/build.log @@ -0,0 +1,13 @@ + +> nx run core:build + +Compiling TypeScript files for project "core"... +Done compiling TypeScript files for project "core". +(node:34057) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. +(Use `node --trace-warnings ...` to show where the warning was created) + + + + NX Successfully ran target build for project core + + diff --git a/plan/agw/research/preset-live-2026-10-15/lint.log b/plan/agw/research/preset-live-2026-10-15/lint.log new file mode 100644 index 00000000..d062426e --- /dev/null +++ b/plan/agw/research/preset-live-2026-10-15/lint.log @@ -0,0 +1,20 @@ + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/preset-catalog.spec.ts + 46:19 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 54:9 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 114:20 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 189:4 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 191:5 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 198:5 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 217:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 219:32 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 230:13 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 287:19 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/presets.spec.ts + 156:10 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 170:3 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 171:4 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +✖ 13 problems (0 errors, 13 warnings) + diff --git a/plan/agw/research/preset-live-2026-10-15/live-evidence.jsonl b/plan/agw/research/preset-live-2026-10-15/live-evidence.jsonl new file mode 100644 index 00000000..ed2212d1 --- /dev/null +++ b/plan/agw/research/preset-live-2026-10-15/live-evidence.jsonl @@ -0,0 +1,8 @@ +{"name": "preset-uniswap-live", "at": "2026-10-15T02:00:31.874Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "wallet": "0xAF1B9f6f6886E5B5285Bafa7b5d87b1B5A79644E", "cea": "0x35143BA539fF5D08D1bcBdB4C9497A0E689F4240", "rulesId": "0x1a4ebcc3cd970147b1245f25382d829cfebb4faae7907b24357e5febc8528963", "pool": "0x3289680dD4d6C10bb19b899729cda5eEF58AEfF1", "prerequisiteBlock": "11917290", "wrapTx": "0xc114250b2a72346e8769cbcf87d48f2a91fd50738bdeedbcfe43fc81e0d1dae1", "wrapExternal": "0x51ea353350c19a24c790c314c5ddff2df46d5f13c06b9a229bb143baa97ca41e", "pushTx": "0x43205feedddf38d0cbeb6196d35d30842af81c3c38b80f2b5fdcb77f04e3c442", "externalTx": "0x8947cea1b51592f2fc81deecc20ae544dad411bc2a4ff28a50567fff31816a5d", "amountIn": "1000000000000", "amountOut": "45586"} +{"name": "preset-aave-stage", "at": "2026-10-15T02:09:22.276Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "stage": "mint-submitted", "wallet": "0x6b109E94A8fdEe0569F49d0C9E9CEAE5a059b6DF", "cea": "0xc7DF2D3D45EF0cE6a77faDB902009F1874C32Aa4", "pushTx": "0x8b08b6a71a13de857e98b833625165a1d5ee8ecf17948078b822aad07720a541"} +{"name": "preset-aave-stage", "at": "2026-10-15T02:10:52.152Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "stage": "mint-completed", "wallet": "0x6b109E94A8fdEe0569F49d0C9E9CEAE5a059b6DF", "cea": "0xc7DF2D3D45EF0cE6a77faDB902009F1874C32Aa4", "externalTx": "0xfcca437b61ee2689e0f1d69807aa65d4c0bd1d92466a2453c8258de81311cdeb"} +{"name": "preset-aave-stage", "at": "2026-10-15T02:11:00.956Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "stage": "supply-submitted", "wallet": "0x6b109E94A8fdEe0569F49d0C9E9CEAE5a059b6DF", "cea": "0xc7DF2D3D45EF0cE6a77faDB902009F1874C32Aa4", "pushTx": "0x1e96a7b1f2d31ab88d6530ef6de9d4fdaf239eeb64f305773750eb54c86739a9"} +{"name": "preset-aave-stage", "at": "2026-10-15T02:12:09.280Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "stage": "supply-completed", "wallet": "0x6b109E94A8fdEe0569F49d0C9E9CEAE5a059b6DF", "cea": "0xc7DF2D3D45EF0cE6a77faDB902009F1874C32Aa4", "externalTx": "0x02782e8343a429db7548e9fe973f2869cda0376ad89fa1e1d84caf9a27d9bc8a"} +{"name": "preset-aave-stage", "at": "2026-10-15T02:12:20.943Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "stage": "withdraw-submitted", "wallet": "0x6b109E94A8fdEe0569F49d0C9E9CEAE5a059b6DF", "cea": "0xc7DF2D3D45EF0cE6a77faDB902009F1874C32Aa4", "pushTx": "0x7dcc019ae3c0683052e1cab3b7e373ab18b85f199b2c15afb0b729d743e51a1d"} +{"name": "preset-aave-stage", "at": "2026-10-15T02:13:18.389Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "stage": "withdraw-completed", "wallet": "0x6b109E94A8fdEe0569F49d0C9E9CEAE5a059b6DF", "cea": "0xc7DF2D3D45EF0cE6a77faDB902009F1874C32Aa4", "externalTx": "0x9a93286cf1803bd8572ad4a838ee63e6f5d8bdc4b63ffc2db0c7e0b9d14be7fd"} +{"name": "preset-aave-live", "at": "2026-10-15T02:13:18.672Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "wallet": "0x6b109E94A8fdEe0569F49d0C9E9CEAE5a059b6DF", "cea": "0xc7DF2D3D45EF0cE6a77faDB902009F1874C32Aa4", "rulesId": "0xc5f18cd898ba56f4de71a607985b69859edfd28bc28a34111887652602f267dc", "mockLINK": "0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5", "pool": "0x6Ae43d3271ff6888e7Fc43Fd7321a503ff738951", "mintTx": "0x8b08b6a71a13de857e98b833625165a1d5ee8ecf17948078b822aad07720a541", "mintExternal": "0xfcca437b61ee2689e0f1d69807aa65d4c0bd1d92466a2453c8258de81311cdeb", "supplyTx": "0x1e96a7b1f2d31ab88d6530ef6de9d4fdaf239eeb64f305773750eb54c86739a9", "supplyExternal": "0x02782e8343a429db7548e9fe973f2869cda0376ad89fa1e1d84caf9a27d9bc8a", "withdrawTx": "0x7dcc019ae3c0683052e1cab3b7e373ab18b85f199b2c15afb0b729d743e51a1d", "withdrawExternal": "0x9a93286cf1803bd8572ad4a838ee63e6f5d8bdc4b63ffc2db0c7e0b9d14be7fd", "amount": "1000000000000"} diff --git a/plan/agw/research/preset-live-2026-10-15/preflight.log b/plan/agw/research/preset-live-2026-10-15/preflight.log new file mode 100644 index 00000000..7f935e2e --- /dev/null +++ b/plan/agw/research/preset-live-2026-10-15/preflight.log @@ -0,0 +1,20 @@ +AGW deployment manifest verified on-chain. + +Wallets + EVM master (Sepolia) 0x0A16CBa65FfCAa4C2282b27b027Ab4A2fE46E0Bf + Push master (Donut) 0x0A16CBa65FfCAa4C2282b27b027Ab4A2fE46E0Bf + Solana master (Devnet) 3nK8X1re4zLNrgz9Y3xKS4g2fKPJ6M3N9BhNuFfkjwAb + Shared UEA (Donut) 0x5C70C864Cf1aDfB04A0e107fFA248ba3600EAb8D + UEA CEA PDA (Devnet) Fqp8UeJxEWvN1Ciu5jqrA3opGXwNvRL2HfJxNQotj3Qh + +Group "agw-presets" — 1 scenarios, headroom ×1.25. + +┌─────────────────────┬───────┬──────────┬─────────────┬────────┐ +│ Scope │ Asset │ Need │ Have │ Status │ +├─────────────────────┼───────┼──────────┼─────────────┼────────┤ +│ Push master (Donut) │ PC │ 95.7500 │ 969150.1424 │ ✓ │ +│ Push master (Donut) │ pETH │ 0.000003 │ 434.3115 │ ✓ │ +└─────────────────────┴───────┴──────────┴─────────────┴────────┘ + +All master wallets can cover this run. +Derived accounts are already at target. Ready to run. diff --git a/plan/agw/research/preset-live-2026-10-15/preset-focused.log b/plan/agw/research/preset-live-2026-10-15/preset-focused.log new file mode 100644 index 00000000..1899543c --- /dev/null +++ b/plan/agw/research/preset-live-2026-10-15/preset-focused.log @@ -0,0 +1,8 @@ +PASS core packages/core/src/lib/agentic/__tests__/preset-catalog.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/presets.spec.ts + +Test Suites: 2 passed, 2 total +Tests: 44 passed, 44 total +Snapshots: 0 total +Time: 2.029 s +Ran all test suites within paths "packages/core/src/lib/agentic/__tests__/presets.spec.ts", "packages/core/src/lib/agentic/__tests__/preset-catalog.spec.ts". diff --git a/plan/agw/research/preset-live-2026-10-15/scenario-selection.log b/plan/agw/research/preset-live-2026-10-15/scenario-selection.log new file mode 100644 index 00000000..19f2b167 --- /dev/null +++ b/plan/agw/research/preset-live-2026-10-15/scenario-selection.log @@ -0,0 +1,5 @@ +✓ agw-preset-uniswap-live 1 test +✓ agw-preset-aave-live 1 test + +2 scenarios, 1 spec files, 2 distinct tests. +Manifest is consistent with the specs. diff --git a/plan/agw/research/preset-live-2026-10-15/uniswap-live.log b/plan/agw/research/preset-live-2026-10-15/uniswap-live.log new file mode 100644 index 00000000..7c474c3a --- /dev/null +++ b/plan/agw/research/preset-live-2026-10-15/uniswap-live.log @@ -0,0 +1,12 @@ +Running 1 scenarios (group: agw-presets) across 1 spec files. + +PASS core-e2e __e2e__/agw/presets-live.spec.ts (217.711 s) + agw presets live + ✓ 1. Uniswap preset swaps from the wallet CEA and rejects a different recipient (212684 ms) + +Test Suites: 1 passed, 1 total +Tests: 1 passed, 1 total +Snapshots: 0 total +Time: 217.735 s +Ran all test suites within paths "__e2e__/agw/presets-live.spec.ts". +Force exiting Jest: Have you considered using `--detectOpenHandles` to detect async operations that kept running after all tests finished? diff --git a/plan/agw/research/preset-live-2026-10-15/unit.log b/plan/agw/research/preset-live-2026-10-15/unit.log new file mode 100644 index 00000000..1c91bfaa --- /dev/null +++ b/plan/agw/research/preset-live-2026-10-15/unit.log @@ -0,0 +1,177 @@ +PASS core packages/core/src/lib/universal/account/account.spec.ts + ● Console + + console.warn + [PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead. + + 207 | ): Promise { + 208 | if (!_convertOriginToExecutorWarned) { + > 209 | console.warn( + | ^ + 210 | '[PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead.' + 211 | ); + 212 | _convertOriginToExecutorWarned = true; + + at Object.convertOriginToExecutor (src/lib/universal/account/account.ts:209:13) + at Object. (src/lib/universal/account/account.spec.ts:80:52) + + console.warn + [PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead. + + 425 | ): Promise { + 426 | if (!options?._internal && !_convertExecutorToOriginWarned) { + > 427 | console.warn( + | ^ + 428 | '[PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead.' + 429 | ); + 430 | _convertExecutorToOriginWarned = true; + + at convertExecutorToOrigin (src/lib/universal/account/account.ts:427:13) + at Object. (src/lib/universal/account/account.spec.ts:106:38) + +PASS core packages/core/src/lib/agentic/__tests__/preset-catalog.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/block-results-client.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-tx-retry.spec.ts +PASS core packages/core/src/lib/push-client/push-client.archive-fallback.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-confirmation-gate.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-timeout-clamp.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/response-surface.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r2-outbound-revert-flow.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-svm-confirmation.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/inbound-payload.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-executor.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/inbound-tracker-derivation.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/track-transaction-guard.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/source-hash-resolution.spec.ts +PASS core packages/core/src/lib/push-client/push-client.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/presets.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-event-hook-bridge.spec.ts +PASS core packages/core/src/lib/universal/signer/signer.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r1-spec-strings.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/registry.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/send-transaction-progress-hook.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-detector.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-error-classification.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/scenarios.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-error-classification.spec.ts +PASS core packages/core/src/lib/utils.spec.ts + ● Console + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:973:17) + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:977:17) + + console.log + 1.23 + + at Object. (src/lib/utils.spec.ts:982:17) + +PASS core packages/core/src/lib/progress-hook/__tests__/multichain-hooks.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-tracker.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/payload-builders.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/send.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/management.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/web2-compat.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/response-invariant.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/rescue-svm-confirmation.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/signing-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-composition.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/resolver.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/read-tx-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-multichain.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gateway-uea-account.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/context-helpers-tracker.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/export.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-idl.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-backend.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/cascade.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-emission.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/build-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-builder-progress-hook.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/public-rule.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/gate.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/resolve.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/svm-rent.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-svm-r3.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-native-multicall.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/account-status.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r2-spec-strings.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/labels.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/funds-only-burn-guard.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-classification.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r3-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-calculator.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-svm-rent.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/chain-namespace.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-usd-sizer.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/execute-standard-required-funds.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/public-surface.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-evm-r3-native-eoa.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/response-builder-push-revert.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/terminal-suppression.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm-rent-pc20.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-request-recipient.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-quote.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/abi-selectors.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/svm-account.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/reads-context.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/revalidate-read.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-params.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/native-multi-action.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/spec-builder.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-wire-fixture.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-evm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-svm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/result-decoder.spec.ts +PASS core packages/core/src/lib/constants/__tests__/token-constants.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm-log-index.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/address-codec.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/child-inbounds.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/normalize.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/__tests__/signing.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/auto-detect.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/codec.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.chain-symbol.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg-svm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/ucallback-codec.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/validate.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-web2.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-events.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.batch-gas.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.dynamic-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/registry.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-types.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/ix-encoder.spec.ts +PASS core packages/core/src/lib/constants/__tests__/svm-gateway-idl.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/normalize-address.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/max-pc-for-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/error-decoder.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/tracking.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/errors.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/classify.spec.ts +PASS core packages/core/src/lib/formatters.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/budget.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-execute-order.spec.ts + +Test Suites: 1 skipped, 124 passed, 124 of 125 total +Tests: 12 skipped, 2096 passed, 2108 total +Snapshots: 0 total +Time: 25.163 s +Ran all test suites. diff --git a/plan/agw/research/preset-mainnet-2026-10-15/AaveV3Arbitrum.sol b/plan/agw/research/preset-mainnet-2026-10-15/AaveV3Arbitrum.sol new file mode 100644 index 00000000..1c8b2838 --- /dev/null +++ b/plan/agw/research/preset-mainnet-2026-10-15/AaveV3Arbitrum.sol @@ -0,0 +1,613 @@ +// AUTOGENERATED - MANUAL CHANGES WILL BE REVERTED BY THE GENERATOR +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.0; + +import {IPoolAddressesProvider, IPool, IPoolConfigurator, IAaveOracle, IPoolDataProvider, IACLManager, ICollector} from './AaveV3.sol'; +library AaveV3Arbitrum { + // https://arbiscan.io/address/0xa97684ead0e402dC232d5A977953DF7ECBaB3CDb + IPoolAddressesProvider internal constant POOL_ADDRESSES_PROVIDER = + IPoolAddressesProvider(0xa97684ead0e402dC232d5A977953DF7ECBaB3CDb); + + // https://arbiscan.io/address/0x794a61358D6845594F94dc1DB02A252b5b4814aD + IPool internal constant POOL = IPool(0x794a61358D6845594F94dc1DB02A252b5b4814aD); + + // https://arbiscan.io/address/0x8145eddDf43f50276641b55bd3AD95944510021E + IPoolConfigurator internal constant POOL_CONFIGURATOR = + IPoolConfigurator(0x8145eddDf43f50276641b55bd3AD95944510021E); + + // https://arbiscan.io/address/0xb56c2F0B653B2e0b10C9b928C8580Ac5Df02C7C7 + IAaveOracle internal constant ORACLE = IAaveOracle(0xb56c2F0B653B2e0b10C9b928C8580Ac5Df02C7C7); + + // https://arbiscan.io/address/0xFF1137243698CaA18EE364Cc966CF0e02A4e6327 + address internal constant ACL_ADMIN = 0xFF1137243698CaA18EE364Cc966CF0e02A4e6327; + + // https://arbiscan.io/address/0xa72636CbcAa8F5FF95B2cc47F3CDEe83F3294a0B + IACLManager internal constant ACL_MANAGER = + IACLManager(0xa72636CbcAa8F5FF95B2cc47F3CDEe83F3294a0B); + + // https://arbiscan.io/address/0x243Aa95cAC2a25651eda86e80bEe66114413c43b + IPoolDataProvider internal constant AAVE_PROTOCOL_DATA_PROVIDER = + IPoolDataProvider(0x243Aa95cAC2a25651eda86e80bEe66114413c43b); + + // https://arbiscan.io/address/0xF05Fd3cC911b4c5E36e53c00354F645E22922C9A + address internal constant POOL_IMPL = 0xF05Fd3cC911b4c5E36e53c00354F645E22922C9A; + + // https://arbiscan.io/address/0xFF42Ce30054dcE7dc7C1282a9a497aa58eaBCe99 + address internal constant POOL_CONFIGURATOR_IMPL = 0xFF42Ce30054dcE7dc7C1282a9a497aa58eaBCe99; + + // https://arbiscan.io/address/0x929EC64c34a17401F460460D4B9390518E5B473e + address internal constant DEFAULT_INCENTIVES_CONTROLLER = + 0x929EC64c34a17401F460460D4B9390518E5B473e; + + // https://arbiscan.io/address/0x048f2228D7Bf6776f99aB50cB1b1eaB4D1d4cA73 + address internal constant EMISSION_MANAGER = 0x048f2228D7Bf6776f99aB50cB1b1eaB4D1d4cA73; + + // https://arbiscan.io/address/0x053D55f9B5AF8694c503EB288a1B7E552f590710 + ICollector internal constant COLLECTOR = ICollector(0x053D55f9B5AF8694c503EB288a1B7E552f590710); + + // https://arbiscan.io/address/0xadcb7e98A462AA2375D03145083eE68A2148F077 + address internal constant DEFAULT_A_TOKEN_IMPL = 0xadcb7e98A462AA2375D03145083eE68A2148F077; + + // https://arbiscan.io/address/0xC0442C25FE517ac37D6a0D485446307D97d24712 + address internal constant DEFAULT_VARIABLE_DEBT_TOKEN_IMPL = + 0xC0442C25FE517ac37D6a0D485446307D97d24712; + + // https://arbiscan.io/address/0xC5762E5A5c12886D4F6768549A9C605823d029E9 + address internal constant RISK_STEWARD = 0xC5762E5A5c12886D4F6768549A9C605823d029E9; + + // https://arbiscan.io/address/0x3Be327F22eB4BD8042e6944073b8826dCf357Aa2 + address internal constant RISK_COUNCIL = 0x3Be327F22eB4BD8042e6944073b8826dCf357Aa2; + + // https://arbiscan.io/address/0x085E34722e04567Df9E6d2c32e82fd74f3342e79 + address internal constant EDGE_RISK_STEWARD_CAPS = 0x085E34722e04567Df9E6d2c32e82fd74f3342e79; + + // https://arbiscan.io/address/0x35d53dEB2F6f40Ea7af32B6F8BEd88eA966DF1D9 + address internal constant EDGE_INJECTOR_CAPS = 0x35d53dEB2F6f40Ea7af32B6F8BEd88eA966DF1D9; + + // https://arbiscan.io/address/0x861eeAdB55E41f161F31Acb1BFD4c70E3a964Aed + address internal constant EDGE_RISK_ORACLE = 0x861eeAdB55E41f161F31Acb1BFD4c70E3a964Aed; + + // https://arbiscan.io/address/0x63dfa7c09Dc2Ff4030d6B8Dc2ce6262BF898C8A4 + address internal constant DEBT_SWAP_ADAPTER = 0x63dfa7c09Dc2Ff4030d6B8Dc2ce6262BF898C8A4; + + // https://arbiscan.io/address/0x9abADECD08572e0eA5aF4d47A9C7984a5AA503dC + address internal constant L2_ENCODER = 0x9abADECD08572e0eA5aF4d47A9C7984a5AA503dC; + + // https://arbiscan.io/address/0xFaEe011b679330A42fFc33c6444800F78b69Dc58 + address internal constant CONFIG_ENGINE = 0xFaEe011b679330A42fFc33c6444800F78b69Dc58; + + // https://arbiscan.io/address/0x770ef9f4fe897e59daCc474EF11238303F9552b6 + address internal constant POOL_ADDRESSES_PROVIDER_REGISTRY = + 0x770ef9f4fe897e59daCc474EF11238303F9552b6; + + // https://arbiscan.io/address/0xcC47c4Fe1F7f29ff31A8b62197023aC8553C7896 + address internal constant RATES_FACTORY = 0xcC47c4Fe1F7f29ff31A8b62197023aC8553C7896; + + // https://arbiscan.io/address/0xE28E2c8d240dd5eBd0adcab86fbD79df7a052034 + address internal constant REPAY_WITH_COLLATERAL_ADAPTER = + 0xE28E2c8d240dd5eBd0adcab86fbD79df7a052034; + + // https://arbiscan.io/address/0x411D79b8cC43384FDE66CaBf9b6a17180c842511 + address internal constant LEGACY_STATIC_A_TOKEN_FACTORY = + 0x411D79b8cC43384FDE66CaBf9b6a17180c842511; + + // https://arbiscan.io/address/0xD61BF98649EA8F8D09e184184777b1867F00E5CB + address internal constant LEGACY_STATIC_A_TOKEN_ORACLE = + 0xD61BF98649EA8F8D09e184184777b1867F00E5CB; + + // https://arbiscan.io/address/0xF3C3F14dd7BDb7E03e6EBc3bc5Ffc6D66De12251 + address internal constant SWAP_COLLATERAL_ADAPTER = 0xF3C3F14dd7BDb7E03e6EBc3bc5Ffc6D66De12251; + + // https://arbiscan.io/address/0x68100bD5345eA474D93577127C11F39FF8463e93 + address internal constant UI_INCENTIVE_DATA_PROVIDER = 0x68100bD5345eA474D93577127C11F39FF8463e93; + + // https://arbiscan.io/address/0x91E04cf78e53aEBe609e8a7f2003e7EECD743F2B + address internal constant UI_POOL_DATA_PROVIDER = 0x91E04cf78e53aEBe609e8a7f2003e7EECD743F2B; + + // https://arbiscan.io/address/0xBc790382B3686abffE4be14A030A96aC6154023a + address internal constant WALLET_BALANCE_PROVIDER = 0xBc790382B3686abffE4be14A030A96aC6154023a; + + // https://arbiscan.io/address/0x5283BEcEd7ADF6D003225C13896E536f2D4264FF + address internal constant WETH_GATEWAY = 0x5283BEcEd7ADF6D003225C13896E536f2D4264FF; + + // https://arbiscan.io/address/0x5598BbFA2f4fE8151f45bBA0a3edE1b54B51a0a9 + address internal constant WITHDRAW_SWAP_ADAPTER = 0x5598BbFA2f4fE8151f45bBA0a3edE1b54B51a0a9; + + // https://arbiscan.io/address/0xd85922fFF51ba4130cEC7c499db4Ac3Eb9981EaD + address internal constant STATA_FACTORY = 0xd85922fFF51ba4130cEC7c499db4Ac3Eb9981EaD; + + // https://arbiscan.io/address/0x897c76905A3d17F71d5ea033916B65154Cf4b4f0 + address internal constant DUST_BIN = 0x897c76905A3d17F71d5ea033916B65154Cf4b4f0; + + // https://arbiscan.io/address/0x7B58055fC6bE4B23cF8c9287b7d3C4adBE919a9c + address internal constant CLINIC_STEWARD = 0x7B58055fC6bE4B23cF8c9287b7d3C4adBE919a9c; + + // https://arbiscan.io/address/0xfB1D12D7C9c3Eb6b40fe0502801CdFCE816a0d18 + address internal constant POOL_EXPOSURE_STEWARD = 0xfB1D12D7C9c3Eb6b40fe0502801CdFCE816a0d18; +} +library AaveV3ArbitrumAssets { + // https://arbiscan.io/address/0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1 + address internal constant DAI_UNDERLYING = 0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1; + + uint8 internal constant DAI_DECIMALS = 18; + + // https://arbiscan.io/address/0x82E64f49Ed5EC1bC6e43DAD4FC8Af9bb3A2312EE + address internal constant DAI_A_TOKEN = 0x82E64f49Ed5EC1bC6e43DAD4FC8Af9bb3A2312EE; + + // https://arbiscan.io/address/0x8619d80FB0141ba7F184CbF22fd724116D9f7ffC + address internal constant DAI_V_TOKEN = 0x8619d80FB0141ba7F184CbF22fd724116D9f7ffC; + + // https://arbiscan.io/address/0xF44a2B5605b07a1CBA7CF3907A9D0bB4A515C3F1 + address internal constant DAI_ORACLE = 0xF44a2B5605b07a1CBA7CF3907A9D0bB4A515C3F1; + + // https://arbiscan.io/address/0x429F16dBA3B9e1900087Cbaa7b50D38Bc60fB73F + address internal constant DAI_INTEREST_RATE_STRATEGY = 0x429F16dBA3B9e1900087Cbaa7b50D38Bc60fB73F; + + // https://arbiscan.io/address/0xc91c5297d7E161aCC74b482aAfCc75B85cc0bfeD + address internal constant DAI_STATIC_A_TOKEN = 0xc91c5297d7E161aCC74b482aAfCc75B85cc0bfeD; + + // https://arbiscan.io/address/0xf253BD61aEd0E9D62523eA76CD6F38B4a51dA145 + address internal constant DAI_STATA_TOKEN = 0xf253BD61aEd0E9D62523eA76CD6F38B4a51dA145; + + // https://arbiscan.io/address/0xf97f4df75117a78c1A5a0DBb814Af92458539FB4 + address internal constant LINK_UNDERLYING = 0xf97f4df75117a78c1A5a0DBb814Af92458539FB4; + + uint8 internal constant LINK_DECIMALS = 18; + + // https://arbiscan.io/address/0x191c10Aa4AF7C30e871E70C95dB0E4eb77237530 + address internal constant LINK_A_TOKEN = 0x191c10Aa4AF7C30e871E70C95dB0E4eb77237530; + + // https://arbiscan.io/address/0x953A573793604aF8d41F306FEb8274190dB4aE0e + address internal constant LINK_V_TOKEN = 0x953A573793604aF8d41F306FEb8274190dB4aE0e; + + // https://arbiscan.io/address/0x2C1C5eaB455A91cEAD280B12650faaA7bfDd59e6 + address internal constant LINK_ORACLE = 0x2C1C5eaB455A91cEAD280B12650faaA7bfDd59e6; + + // https://arbiscan.io/address/0x429F16dBA3B9e1900087Cbaa7b50D38Bc60fB73F + address internal constant LINK_INTEREST_RATE_STRATEGY = + 0x429F16dBA3B9e1900087Cbaa7b50D38Bc60fB73F; + + // https://arbiscan.io/address/0x27dE098EF2772386cBCf1a4c8BEb886368b7F9a9 + address internal constant LINK_STATIC_A_TOKEN = 0x27dE098EF2772386cBCf1a4c8BEb886368b7F9a9; + + // https://arbiscan.io/address/0xEAB84053B99f2ec4433F5121A1CB1524c8c998F8 + address internal constant LINK_STATA_TOKEN = 0xEAB84053B99f2ec4433F5121A1CB1524c8c998F8; + + // https://arbiscan.io/address/0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8 + address internal constant USDCe_UNDERLYING = 0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8; + + uint8 internal constant USDCe_DECIMALS = 6; + + // https://arbiscan.io/address/0x625E7708f30cA75bfd92586e17077590C60eb4cD + address internal constant USDCe_A_TOKEN = 0x625E7708f30cA75bfd92586e17077590C60eb4cD; + + // https://arbiscan.io/address/0xFCCf3cAbbe80101232d343252614b6A3eE81C989 + address internal constant USDCe_V_TOKEN = 0xFCCf3cAbbe80101232d343252614b6A3eE81C989; + + // https://arbiscan.io/address/0xB0C9A7122aaB68F75CffD9851E867144DBFF113b + address internal constant USDCe_ORACLE = 0xB0C9A7122aaB68F75CffD9851E867144DBFF113b; + + // https://arbiscan.io/address/0x429F16dBA3B9e1900087Cbaa7b50D38Bc60fB73F + address internal constant USDCe_INTEREST_RATE_STRATEGY = + 0x429F16dBA3B9e1900087Cbaa7b50D38Bc60fB73F; + + // https://arbiscan.io/address/0x0Bc9E52051f553E75550CA22C196bf132c52Cf0B + address internal constant USDCe_STATIC_A_TOKEN = 0x0Bc9E52051f553E75550CA22C196bf132c52Cf0B; + + // https://arbiscan.io/address/0xE6D5923281c89DC989D00817387292387552d5C1 + address internal constant USDCe_STATA_TOKEN = 0xE6D5923281c89DC989D00817387292387552d5C1; + + // https://arbiscan.io/address/0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f + address internal constant WBTC_UNDERLYING = 0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f; + + uint8 internal constant WBTC_DECIMALS = 8; + + // https://arbiscan.io/address/0x078f358208685046a11C85e8ad32895DED33A249 + address internal constant WBTC_A_TOKEN = 0x078f358208685046a11C85e8ad32895DED33A249; + + // https://arbiscan.io/address/0x92b42c66840C7AD907b4BF74879FF3eF7c529473 + address internal constant WBTC_V_TOKEN = 0x92b42c66840C7AD907b4BF74879FF3eF7c529473; + + // https://arbiscan.io/address/0xDe4Af8b4747192Ea29339D0FeB36d9830d399134 + address internal constant WBTC_ORACLE = 0xDe4Af8b4747192Ea29339D0FeB36d9830d399134; + + // https://arbiscan.io/address/0x429F16dBA3B9e1900087Cbaa7b50D38Bc60fB73F + address internal constant WBTC_INTEREST_RATE_STRATEGY = + 0x429F16dBA3B9e1900087Cbaa7b50D38Bc60fB73F; + + // https://arbiscan.io/address/0x32B95Fbe04e5a51cF99FeeF4e57Cf7e3FC9c5A93 + address internal constant WBTC_STATIC_A_TOKEN = 0x32B95Fbe04e5a51cF99FeeF4e57Cf7e3FC9c5A93; + + // https://arbiscan.io/address/0x52Dc1FEeFA4f9a99221F93D79da46Ae89b8c0967 + address internal constant WBTC_STATA_TOKEN = 0x52Dc1FEeFA4f9a99221F93D79da46Ae89b8c0967; + + // https://arbiscan.io/address/0x82aF49447D8a07e3bd95BD0d56f35241523fBab1 + address internal constant WETH_UNDERLYING = 0x82aF49447D8a07e3bd95BD0d56f35241523fBab1; + + uint8 internal constant WETH_DECIMALS = 18; + + // https://arbiscan.io/address/0xe50fA9b3c56FfB159cB0FCA61F5c9D750e8128c8 + address internal constant WETH_A_TOKEN = 0xe50fA9b3c56FfB159cB0FCA61F5c9D750e8128c8; + + // https://arbiscan.io/address/0x0c84331e39d6658Cd6e6b9ba04736cC4c4734351 + address internal constant WETH_V_TOKEN = 0x0c84331e39d6658Cd6e6b9ba04736cC4c4734351; + + // https://arbiscan.io/address/0xbD41b1548a5A06544cBcf87c0c54864312842C00 + address internal constant WETH_ORACLE = 0xbD41b1548a5A06544cBcf87c0c54864312842C00; + + // https://arbiscan.io/address/0x429F16dBA3B9e1900087Cbaa7b50D38Bc60fB73F + address internal constant WETH_INTEREST_RATE_STRATEGY = + 0x429F16dBA3B9e1900087Cbaa7b50D38Bc60fB73F; + + // https://arbiscan.io/address/0x352F3475716261dCC991Bd5F2aF973eB3D0F5878 + address internal constant WETH_STATIC_A_TOKEN = 0x352F3475716261dCC991Bd5F2aF973eB3D0F5878; + + // https://arbiscan.io/address/0x4cE13a79f45C1Be00BdABD38B764aC28C082704E + address internal constant WETH_STATA_TOKEN = 0x4cE13a79f45C1Be00BdABD38B764aC28C082704E; + + // https://arbiscan.io/address/0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9 + address internal constant USDT_UNDERLYING = 0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9; + + uint8 internal constant USDT_DECIMALS = 6; + + // https://arbiscan.io/address/0x6ab707Aca953eDAeFBc4fD23bA73294241490620 + address internal constant USDT_A_TOKEN = 0x6ab707Aca953eDAeFBc4fD23bA73294241490620; + + // https://arbiscan.io/address/0xfb00AC187a8Eb5AFAE4eACE434F493Eb62672df7 + address internal constant USDT_V_TOKEN = 0xfb00AC187a8Eb5AFAE4eACE434F493Eb62672df7; + + // https://arbiscan.io/address/0x03f1203a32DF3a941D41dE07F5fD2E71D2a70172 + address internal constant USDT_ORACLE = 0x03f1203a32DF3a941D41dE07F5fD2E71D2a70172; + + // https://arbiscan.io/address/0x429F16dBA3B9e1900087Cbaa7b50D38Bc60fB73F + address internal constant USDT_INTEREST_RATE_STRATEGY = + 0x429F16dBA3B9e1900087Cbaa7b50D38Bc60fB73F; + + // https://arbiscan.io/address/0xb165a74407fE1e519d6bCbDeC1Ed3202B35a4140 + address internal constant USDT_STATIC_A_TOKEN = 0xb165a74407fE1e519d6bCbDeC1Ed3202B35a4140; + + // https://arbiscan.io/address/0xa6D12574eFB239FC1D2099732bd8b5dC6306897F + address internal constant USDT_STATA_TOKEN = 0xa6D12574eFB239FC1D2099732bd8b5dC6306897F; + + // https://arbiscan.io/address/0xba5DdD1f9d7F570dc94a51479a000E3BCE967196 + address internal constant AAVE_UNDERLYING = 0xba5DdD1f9d7F570dc94a51479a000E3BCE967196; + + uint8 internal constant AAVE_DECIMALS = 18; + + // https://arbiscan.io/address/0xf329e36C7bF6E5E86ce2150875a84Ce77f477375 + address internal constant AAVE_A_TOKEN = 0xf329e36C7bF6E5E86ce2150875a84Ce77f477375; + + // https://arbiscan.io/address/0xE80761Ea617F66F96274eA5e8c37f03960ecC679 + address internal constant AAVE_V_TOKEN = 0xE80761Ea617F66F96274eA5e8c37f03960ecC679; + + // https://arbiscan.io/address/0xf97eEAac36bdd096bb2445c7582F9095bfCE04C7 + address internal constant AAVE_ORACLE = 0xf97eEAac36bdd096bb2445c7582F9095bfCE04C7; + + // https://arbiscan.io/address/0x429F16dBA3B9e1900087Cbaa7b50D38Bc60fB73F + address internal constant AAVE_INTEREST_RATE_STRATEGY = + 0x429F16dBA3B9e1900087Cbaa7b50D38Bc60fB73F; + + // https://arbiscan.io/address/0x1C0c8EcED17aE093b3C1a1a8fFeBE2E9513a9346 + address internal constant AAVE_STATIC_A_TOKEN = 0x1C0c8EcED17aE093b3C1a1a8fFeBE2E9513a9346; + + // https://arbiscan.io/address/0xd3642A6e9fa95961130497727DC3aE6c38D625E7 + address internal constant AAVE_STATA_TOKEN = 0xd3642A6e9fa95961130497727DC3aE6c38D625E7; + + // https://arbiscan.io/address/0xD22a58f79e9481D1a88e00c343885A588b34b68B + address internal constant EURS_UNDERLYING = 0xD22a58f79e9481D1a88e00c343885A588b34b68B; + + uint8 internal constant EURS_DECIMALS = 2; + + // https://arbiscan.io/address/0x6d80113e533a2C0fe82EaBD35f1875DcEA89Ea97 + address internal constant EURS_A_TOKEN = 0x6d80113e533a2C0fe82EaBD35f1875DcEA89Ea97; + + // https://arbiscan.io/address/0x4a1c3aD6Ed28a636ee1751C69071f6be75DEb8B8 + address internal constant EURS_V_TOKEN = 0x4a1c3aD6Ed28a636ee1751C69071f6be75DEb8B8; + + // https://arbiscan.io/address/0xA14d53bC1F1c0F31B4aA3BD109344E5009051a84 + address internal constant EURS_ORACLE = 0xA14d53bC1F1c0F31B4aA3BD109344E5009051a84; + + // https://arbiscan.io/address/0x429F16dBA3B9e1900087Cbaa7b50D38Bc60fB73F + address internal constant EURS_INTEREST_RATE_STRATEGY = + 0x429F16dBA3B9e1900087Cbaa7b50D38Bc60fB73F; + + // https://arbiscan.io/address/0x9a40747BE51185A416B181789B671E78a8d045dD + address internal constant EURS_STATIC_A_TOKEN = 0x9a40747BE51185A416B181789B671E78a8d045dD; + + // https://arbiscan.io/address/0x5979D7b546E38E414F7E9822514be443A4800529 + address internal constant wstETH_UNDERLYING = 0x5979D7b546E38E414F7E9822514be443A4800529; + + uint8 internal constant wstETH_DECIMALS = 18; + + // https://arbiscan.io/address/0x513c7E3a9c69cA3e22550eF58AC1C0088e918FFf + address internal constant wstETH_A_TOKEN = 0x513c7E3a9c69cA3e22550eF58AC1C0088e918FFf; + + // https://arbiscan.io/address/0x77CA01483f379E58174739308945f044e1a764dc + address internal constant wstETH_V_TOKEN = 0x77CA01483f379E58174739308945f044e1a764dc; + + // https://arbiscan.io/address/0xb4a28DF1b926646f94e6fE6f15828c491b4def5F + address internal constant wstETH_ORACLE = 0xb4a28DF1b926646f94e6fE6f15828c491b4def5F; + + // https://arbiscan.io/address/0x429F16dBA3B9e1900087Cbaa7b50D38Bc60fB73F + address internal constant wstETH_INTEREST_RATE_STRATEGY = + 0x429F16dBA3B9e1900087Cbaa7b50D38Bc60fB73F; + + // https://arbiscan.io/address/0x7775d4Ae4Dbb79a624fB96AAcDB8Ca74F671c0DF + address internal constant wstETH_STATIC_A_TOKEN = 0x7775d4Ae4Dbb79a624fB96AAcDB8Ca74F671c0DF; + + // https://arbiscan.io/address/0xe98fc055c99DECD8Da0c111B090885d5d15C774E + address internal constant wstETH_STATA_TOKEN = 0xe98fc055c99DECD8Da0c111B090885d5d15C774E; + + // https://arbiscan.io/address/0x3F56e0c36d275367b8C502090EDF38289b3dEa0d + address internal constant MAI_UNDERLYING = 0x3F56e0c36d275367b8C502090EDF38289b3dEa0d; + + uint8 internal constant MAI_DECIMALS = 18; + + // https://arbiscan.io/address/0xc45A479877e1e9Dfe9FcD4056c699575a1045dAA + address internal constant MAI_A_TOKEN = 0xc45A479877e1e9Dfe9FcD4056c699575a1045dAA; + + // https://arbiscan.io/address/0x34e2eD44EF7466D5f9E0b782B5c08b57475e7907 + address internal constant MAI_V_TOKEN = 0x34e2eD44EF7466D5f9E0b782B5c08b57475e7907; + + // https://arbiscan.io/address/0x80e8F4b3698A079d7f2397cd71ab4bb17a12924e + address internal constant MAI_ORACLE = 0x80e8F4b3698A079d7f2397cd71ab4bb17a12924e; + + // https://arbiscan.io/address/0x429F16dBA3B9e1900087Cbaa7b50D38Bc60fB73F + address internal constant MAI_INTEREST_RATE_STRATEGY = 0x429F16dBA3B9e1900087Cbaa7b50D38Bc60fB73F; + + // https://arbiscan.io/address/0xB4a0a2692D82301703B27082Cda45B083F68CAcE + address internal constant MAI_STATIC_A_TOKEN = 0xB4a0a2692D82301703B27082Cda45B083F68CAcE; + + // https://arbiscan.io/address/0xEC70Dcb4A1EFa46b8F2D97C310C9c4790ba5ffA8 + address internal constant rETH_UNDERLYING = 0xEC70Dcb4A1EFa46b8F2D97C310C9c4790ba5ffA8; + + uint8 internal constant rETH_DECIMALS = 18; + + // https://arbiscan.io/address/0x8Eb270e296023E9D92081fdF967dDd7878724424 + address internal constant rETH_A_TOKEN = 0x8Eb270e296023E9D92081fdF967dDd7878724424; + + // https://arbiscan.io/address/0xCE186F6Cccb0c955445bb9d10C59caE488Fea559 + address internal constant rETH_V_TOKEN = 0xCE186F6Cccb0c955445bb9d10C59caE488Fea559; + + // https://arbiscan.io/address/0x0E82D4e66B8C41c532184BCd0d89781c0040d07A + address internal constant rETH_ORACLE = 0x0E82D4e66B8C41c532184BCd0d89781c0040d07A; + + // https://arbiscan.io/address/0x429F16dBA3B9e1900087Cbaa7b50D38Bc60fB73F + address internal constant rETH_INTEREST_RATE_STRATEGY = + 0x429F16dBA3B9e1900087Cbaa7b50D38Bc60fB73F; + + // https://arbiscan.io/address/0x68235105d6d33A19369D24b746cb7481FB2b34fd + address internal constant rETH_STATIC_A_TOKEN = 0x68235105d6d33A19369D24b746cb7481FB2b34fd; + + // https://arbiscan.io/address/0xbB8A61425DFE172AA3a6f882aAFaBA00B32b7d59 + address internal constant rETH_STATA_TOKEN = 0xbB8A61425DFE172AA3a6f882aAFaBA00B32b7d59; + + // https://arbiscan.io/address/0x93b346b6BC2548dA6A1E7d98E9a421B42541425b + address internal constant LUSD_UNDERLYING = 0x93b346b6BC2548dA6A1E7d98E9a421B42541425b; + + uint8 internal constant LUSD_DECIMALS = 18; + + // https://arbiscan.io/address/0x8ffDf2DE812095b1D19CB146E4c004587C0A0692 + address internal constant LUSD_A_TOKEN = 0x8ffDf2DE812095b1D19CB146E4c004587C0A0692; + + // https://arbiscan.io/address/0xA8669021776Bc142DfcA87c21b4A52595bCbB40a + address internal constant LUSD_V_TOKEN = 0xA8669021776Bc142DfcA87c21b4A52595bCbB40a; + + // https://arbiscan.io/address/0x0EB34b917D500a7736555f4508BFE77452cb261d + address internal constant LUSD_ORACLE = 0x0EB34b917D500a7736555f4508BFE77452cb261d; + + // https://arbiscan.io/address/0x429F16dBA3B9e1900087Cbaa7b50D38Bc60fB73F + address internal constant LUSD_INTEREST_RATE_STRATEGY = + 0x429F16dBA3B9e1900087Cbaa7b50D38Bc60fB73F; + + // https://arbiscan.io/address/0xDbB6314b5b07E63B7101844c0346309B79f8C20A + address internal constant LUSD_STATIC_A_TOKEN = 0xDbB6314b5b07E63B7101844c0346309B79f8C20A; + + // https://arbiscan.io/address/0xaf88d065e77c8cC2239327C5EDb3A432268e5831 + address internal constant USDCn_UNDERLYING = 0xaf88d065e77c8cC2239327C5EDb3A432268e5831; + + uint8 internal constant USDCn_DECIMALS = 6; + + // https://arbiscan.io/address/0x724dc807b04555b71ed48a6896b6F41593b8C637 + address internal constant USDCn_A_TOKEN = 0x724dc807b04555b71ed48a6896b6F41593b8C637; + + // https://arbiscan.io/address/0xf611aEb5013fD2c0511c9CD55c7dc5C1140741A6 + address internal constant USDCn_V_TOKEN = 0xf611aEb5013fD2c0511c9CD55c7dc5C1140741A6; + + // https://arbiscan.io/address/0xB0C9A7122aaB68F75CffD9851E867144DBFF113b + address internal constant USDCn_ORACLE = 0xB0C9A7122aaB68F75CffD9851E867144DBFF113b; + + // https://arbiscan.io/address/0x429F16dBA3B9e1900087Cbaa7b50D38Bc60fB73F + address internal constant USDCn_INTEREST_RATE_STRATEGY = + 0x429F16dBA3B9e1900087Cbaa7b50D38Bc60fB73F; + + // https://arbiscan.io/address/0x7CFaDFD5645B50bE87d546f42699d863648251ad + address internal constant USDCn_STATIC_A_TOKEN = 0x7CFaDFD5645B50bE87d546f42699d863648251ad; + + // https://arbiscan.io/address/0x7F6501d3B98eE91f9b9535E4b0ac710Fb0f9e0bc + address internal constant USDCn_STATA_TOKEN = 0x7F6501d3B98eE91f9b9535E4b0ac710Fb0f9e0bc; + + // https://arbiscan.io/address/0x17FC002b466eEc40DaE837Fc4bE5c67993ddBd6F + address internal constant FRAX_UNDERLYING = 0x17FC002b466eEc40DaE837Fc4bE5c67993ddBd6F; + + uint8 internal constant FRAX_DECIMALS = 18; + + // https://arbiscan.io/address/0x38d693cE1dF5AaDF7bC62595A37D667aD57922e5 + address internal constant FRAX_A_TOKEN = 0x38d693cE1dF5AaDF7bC62595A37D667aD57922e5; + + // https://arbiscan.io/address/0x5D557B07776D12967914379C71a1310e917C7555 + address internal constant FRAX_V_TOKEN = 0x5D557B07776D12967914379C71a1310e917C7555; + + // https://arbiscan.io/address/0xC3B102d52dB93fE3B22B356085C5854c6Bcc2091 + address internal constant FRAX_ORACLE = 0xC3B102d52dB93fE3B22B356085C5854c6Bcc2091; + + // https://arbiscan.io/address/0x429F16dBA3B9e1900087Cbaa7b50D38Bc60fB73F + address internal constant FRAX_INTEREST_RATE_STRATEGY = + 0x429F16dBA3B9e1900087Cbaa7b50D38Bc60fB73F; + + // https://arbiscan.io/address/0x89AEc2023f89E26Dbb7eaa7a98fe3996f9d112A8 + address internal constant FRAX_STATIC_A_TOKEN = 0x89AEc2023f89E26Dbb7eaa7a98fe3996f9d112A8; + + // https://arbiscan.io/address/0x912CE59144191C1204E64559FE8253a0e49E6548 + address internal constant ARB_UNDERLYING = 0x912CE59144191C1204E64559FE8253a0e49E6548; + + uint8 internal constant ARB_DECIMALS = 18; + + // https://arbiscan.io/address/0x6533afac2E7BCCB20dca161449A13A32D391fb00 + address internal constant ARB_A_TOKEN = 0x6533afac2E7BCCB20dca161449A13A32D391fb00; + + // https://arbiscan.io/address/0x44705f578135cC5d703b4c9c122528C73Eb87145 + address internal constant ARB_V_TOKEN = 0x44705f578135cC5d703b4c9c122528C73Eb87145; + + // https://arbiscan.io/address/0x339a66699167D8bc7105C4B9772492D2576E5183 + address internal constant ARB_ORACLE = 0x339a66699167D8bc7105C4B9772492D2576E5183; + + // https://arbiscan.io/address/0x429F16dBA3B9e1900087Cbaa7b50D38Bc60fB73F + address internal constant ARB_INTEREST_RATE_STRATEGY = 0x429F16dBA3B9e1900087Cbaa7b50D38Bc60fB73F; + + // https://arbiscan.io/address/0x9b5637d7952BC9fa2D693aAE51f3103760Bf2693 + address internal constant ARB_STATIC_A_TOKEN = 0x9b5637d7952BC9fa2D693aAE51f3103760Bf2693; + + // https://arbiscan.io/address/0xf09EDbF2655B2A56753bD60D22CeAB2AC5D04188 + address internal constant ARB_STATA_TOKEN = 0xf09EDbF2655B2A56753bD60D22CeAB2AC5D04188; + + // https://arbiscan.io/address/0x35751007a407ca6FEFfE80b3cB397736D2cf4dbe + address internal constant weETH_UNDERLYING = 0x35751007a407ca6FEFfE80b3cB397736D2cf4dbe; + + uint8 internal constant weETH_DECIMALS = 18; + + // https://arbiscan.io/address/0x8437d7C167dFB82ED4Cb79CD44B7a32A1dd95c77 + address internal constant weETH_A_TOKEN = 0x8437d7C167dFB82ED4Cb79CD44B7a32A1dd95c77; + + // https://arbiscan.io/address/0x3ca5FA07689F266e907439aFd1fBB59c44fe12f6 + address internal constant weETH_V_TOKEN = 0x3ca5FA07689F266e907439aFd1fBB59c44fe12f6; + + // https://arbiscan.io/address/0x258a576895DC50c990500775d6591ff2D52059f2 + address internal constant weETH_ORACLE = 0x258a576895DC50c990500775d6591ff2D52059f2; + + // https://arbiscan.io/address/0x429F16dBA3B9e1900087Cbaa7b50D38Bc60fB73F + address internal constant weETH_INTEREST_RATE_STRATEGY = + 0x429F16dBA3B9e1900087Cbaa7b50D38Bc60fB73F; + + // https://arbiscan.io/address/0xD9E3Ef2c12de90E3b03F7b7E3964956a71920d40 + address internal constant weETH_STATA_TOKEN = 0xD9E3Ef2c12de90E3b03F7b7E3964956a71920d40; + + // https://arbiscan.io/address/0x7dfF72693f6A4149b17e7C6314655f6A9F7c8B33 + address internal constant GHO_UNDERLYING = 0x7dfF72693f6A4149b17e7C6314655f6A9F7c8B33; + + uint8 internal constant GHO_DECIMALS = 18; + + // https://arbiscan.io/address/0xeBe517846d0F36eCEd99C735cbF6131e1fEB775D + address internal constant GHO_A_TOKEN = 0xeBe517846d0F36eCEd99C735cbF6131e1fEB775D; + + // https://arbiscan.io/address/0x18248226C16BF76c032817854E7C83a2113B4f06 + address internal constant GHO_V_TOKEN = 0x18248226C16BF76c032817854E7C83a2113B4f06; + + // https://arbiscan.io/address/0xB05984aD83C20b3ADE7bf97a9a0Cb539DDE28DBb + address internal constant GHO_ORACLE = 0xB05984aD83C20b3ADE7bf97a9a0Cb539DDE28DBb; + + // https://arbiscan.io/address/0x429F16dBA3B9e1900087Cbaa7b50D38Bc60fB73F + address internal constant GHO_INTEREST_RATE_STRATEGY = 0x429F16dBA3B9e1900087Cbaa7b50D38Bc60fB73F; + + // https://arbiscan.io/address/0xD9FBA68D89178e3538e708939332c79efC540179 + address internal constant GHO_STATIC_A_TOKEN = 0xD9FBA68D89178e3538e708939332c79efC540179; + + // https://arbiscan.io/address/0xD089B4cb88Dacf4e27be869A00e9f7e2E3C18193 + address internal constant GHO_STATA_TOKEN = 0xD089B4cb88Dacf4e27be869A00e9f7e2E3C18193; + + // https://arbiscan.io/address/0x2416092f143378750bb29b79eD961ab195CcEea5 + address internal constant ezETH_UNDERLYING = 0x2416092f143378750bb29b79eD961ab195CcEea5; + + uint8 internal constant ezETH_DECIMALS = 18; + + // https://arbiscan.io/address/0xEA1132120ddcDDA2F119e99Fa7A27a0d036F7Ac9 + address internal constant ezETH_A_TOKEN = 0xEA1132120ddcDDA2F119e99Fa7A27a0d036F7Ac9; + + // https://arbiscan.io/address/0x1fFD28689DA7d0148ff0fCB669e9f9f0Fc13a219 + address internal constant ezETH_V_TOKEN = 0x1fFD28689DA7d0148ff0fCB669e9f9f0Fc13a219; + + // https://arbiscan.io/address/0x3c4B37b69E7e1FFD1669fe085C74a89c6C79D908 + address internal constant ezETH_ORACLE = 0x3c4B37b69E7e1FFD1669fe085C74a89c6C79D908; + + // https://arbiscan.io/address/0x429F16dBA3B9e1900087Cbaa7b50D38Bc60fB73F + address internal constant ezETH_INTEREST_RATE_STRATEGY = + 0x429F16dBA3B9e1900087Cbaa7b50D38Bc60fB73F; + + // https://arbiscan.io/address/0x4ff50C17df0D1b788d021ACd85039810a1aA68A1 + address internal constant ezETH_STATA_TOKEN = 0x4ff50C17df0D1b788d021ACd85039810a1aA68A1; + + // https://arbiscan.io/address/0x4186BFC76E2E237523CBC30FD220FE055156b41F + address internal constant rsETH_UNDERLYING = 0x4186BFC76E2E237523CBC30FD220FE055156b41F; + + uint8 internal constant rsETH_DECIMALS = 18; + + // https://arbiscan.io/address/0x6b030Ff3FB9956B1B69f475B77aE0d3Cf2CC5aFa + address internal constant rsETH_A_TOKEN = 0x6b030Ff3FB9956B1B69f475B77aE0d3Cf2CC5aFa; + + // https://arbiscan.io/address/0x80cA0d8C38d2e2BcbaB66aA1648Bd1C7160500FE + address internal constant rsETH_V_TOKEN = 0x80cA0d8C38d2e2BcbaB66aA1648Bd1C7160500FE; + + // https://arbiscan.io/address/0x9F54122B14dAf2211989446868B9aa1CF207292B + address internal constant rsETH_ORACLE = 0x9F54122B14dAf2211989446868B9aa1CF207292B; + + // https://arbiscan.io/address/0x429F16dBA3B9e1900087Cbaa7b50D38Bc60fB73F + address internal constant rsETH_INTEREST_RATE_STRATEGY = + 0x429F16dBA3B9e1900087Cbaa7b50D38Bc60fB73F; + + // https://arbiscan.io/address/0x6c84a8f1c29108F47a79964b5Fe888D4f4D0dE40 + address internal constant tBTC_UNDERLYING = 0x6c84a8f1c29108F47a79964b5Fe888D4f4D0dE40; + + uint8 internal constant tBTC_DECIMALS = 18; + + // https://arbiscan.io/address/0x62fC96b27a510cF4977B59FF952Dc32378Cc221d + address internal constant tBTC_A_TOKEN = 0x62fC96b27a510cF4977B59FF952Dc32378Cc221d; + + // https://arbiscan.io/address/0xB5b46F918C2923fC7f26DB76e8a6A6e9C4347Cf9 + address internal constant tBTC_V_TOKEN = 0xB5b46F918C2923fC7f26DB76e8a6A6e9C4347Cf9; + + // https://arbiscan.io/address/0xDe4Af8b4747192Ea29339D0FeB36d9830d399134 + address internal constant tBTC_ORACLE = 0xDe4Af8b4747192Ea29339D0FeB36d9830d399134; + + // https://arbiscan.io/address/0x429F16dBA3B9e1900087Cbaa7b50D38Bc60fB73F + address internal constant tBTC_INTEREST_RATE_STRATEGY = + 0x429F16dBA3B9e1900087Cbaa7b50D38Bc60fB73F; +} +library AaveV3ArbitrumEModes { + uint8 internal constant NONE = 0; + + uint8 internal constant DAI_USDCe_USDT_EURS_USDCn__ = 1; + + uint8 internal constant WETH_wstETH_weETH__WETH = 2; + + uint8 internal constant ezETH__WETH_wstETH = 3; + + uint8 internal constant ezETH__USDT_USDCn = 4; + + uint8 internal constant rsETH__WETH_wstETH = 5; + + uint8 internal constant rsETH__USDCe_USDT = 6; + + uint8 internal constant wstETH__WETH = 7; + + uint8 internal constant AAVE__USDT_USDCn = 8; + + uint8 internal constant ARB__USDT_USDCn = 9; + + uint8 internal constant tBTC__USDT_USDCn = 10; +} +library AaveV3ArbitrumExternalLibraries { + // https://arbiscan.io/address/0x6D414cd0d5eAf8C43200ac0c325A7E2Ad83B8be6 + address internal constant FLASHLOAN_LOGIC = 0x6D414cd0d5eAf8C43200ac0c325A7E2Ad83B8be6; + + // https://arbiscan.io/address/0x52Da0ce88202D1542543598D1e1e27F0d344726A + address internal constant BORROW_LOGIC = 0x52Da0ce88202D1542543598D1e1e27F0d344726A; + + // https://arbiscan.io/address/0x96D5686812e33Ab509ECCDb38C89d15607B2a413 + address internal constant LIQUIDATION_LOGIC = 0x96D5686812e33Ab509ECCDb38C89d15607B2a413; + + // https://arbiscan.io/address/0xD70593841C57cbaA04957cc3EAcE95708e48853b + address internal constant POOL_LOGIC = 0xD70593841C57cbaA04957cc3EAcE95708e48853b; + + // https://arbiscan.io/address/0x584C7d8c4cb05304FE5Ac7fbc97f20A10Fb07564 + address internal constant SUPPLY_LOGIC = 0x584C7d8c4cb05304FE5Ac7fbc97f20A10Fb07564; +} diff --git a/plan/agw/research/preset-mainnet-2026-10-15/AaveV3BNB.sol b/plan/agw/research/preset-mainnet-2026-10-15/AaveV3BNB.sol new file mode 100644 index 00000000..f19bebe3 --- /dev/null +++ b/plan/agw/research/preset-mainnet-2026-10-15/AaveV3BNB.sol @@ -0,0 +1,303 @@ +// AUTOGENERATED - MANUAL CHANGES WILL BE REVERTED BY THE GENERATOR +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.0; + +import {IPoolAddressesProvider, IPool, IPoolConfigurator, IAaveOracle, IPoolDataProvider, IACLManager, ICollector} from './AaveV3.sol'; +library AaveV3BNB { + // https://bscscan.com/address/0xff75B6da14FfbbfD355Daf7a2731456b3562Ba6D + IPoolAddressesProvider internal constant POOL_ADDRESSES_PROVIDER = + IPoolAddressesProvider(0xff75B6da14FfbbfD355Daf7a2731456b3562Ba6D); + + // https://bscscan.com/address/0x6807dc923806fE8Fd134338EABCA509979a7e0cB + IPool internal constant POOL = IPool(0x6807dc923806fE8Fd134338EABCA509979a7e0cB); + + // https://bscscan.com/address/0x67bdF23C7fCE7C65fF7415Ba3F2520B45D6f9584 + IPoolConfigurator internal constant POOL_CONFIGURATOR = + IPoolConfigurator(0x67bdF23C7fCE7C65fF7415Ba3F2520B45D6f9584); + + // https://bscscan.com/address/0x39bc1bfDa2130d6Bb6DBEfd366939b4c7aa7C697 + IAaveOracle internal constant ORACLE = IAaveOracle(0x39bc1bfDa2130d6Bb6DBEfd366939b4c7aa7C697); + + // https://bscscan.com/address/0x9390B1735def18560c509E2d0bc090E9d6BA257a + address internal constant ACL_ADMIN = 0x9390B1735def18560c509E2d0bc090E9d6BA257a; + + // https://bscscan.com/address/0x2D97F8FA96886Fd923c065F5457F9DDd494e3877 + IACLManager internal constant ACL_MANAGER = + IACLManager(0x2D97F8FA96886Fd923c065F5457F9DDd494e3877); + + // https://bscscan.com/address/0xc90Df74A7c16245c5F5C5870327Ceb38Fe5d5328 + IPoolDataProvider internal constant AAVE_PROTOCOL_DATA_PROVIDER = + IPoolDataProvider(0xc90Df74A7c16245c5F5C5870327Ceb38Fe5d5328); + + // https://bscscan.com/address/0x5e2B0FcC5b9734C7Ec0A03401ee9e6805F783B6d + address internal constant POOL_IMPL = 0x5e2B0FcC5b9734C7Ec0A03401ee9e6805F783B6d; + + // https://bscscan.com/address/0xFF42Ce30054dcE7dc7C1282a9a497aa58eaBCe99 + address internal constant POOL_CONFIGURATOR_IMPL = 0xFF42Ce30054dcE7dc7C1282a9a497aa58eaBCe99; + + // https://bscscan.com/address/0xC206C2764A9dBF27d599613b8F9A63ACd1160ab4 + address internal constant DEFAULT_INCENTIVES_CONTROLLER = + 0xC206C2764A9dBF27d599613b8F9A63ACd1160ab4; + + // https://bscscan.com/address/0x6eD1c70aa357fB8a7e1Eac85aa59e33287Df8f85 + address internal constant EMISSION_MANAGER = 0x6eD1c70aa357fB8a7e1Eac85aa59e33287Df8f85; + + // https://bscscan.com/address/0x25Ec457d1778b0E5316e7f38f3c22baF413F1A8C + ICollector internal constant COLLECTOR = ICollector(0x25Ec457d1778b0E5316e7f38f3c22baF413F1A8C); + + // https://bscscan.com/address/0x7e199Fc666368d95B9EaEfA7D2d8081AcAb74134 + address internal constant DEFAULT_A_TOKEN_IMPL = 0x7e199Fc666368d95B9EaEfA7D2d8081AcAb74134; + + // https://bscscan.com/address/0x929CD8EE3d0b6e04324Ee1171D4f594a2c47166d + address internal constant DEFAULT_VARIABLE_DEBT_TOKEN_IMPL = + 0x929CD8EE3d0b6e04324Ee1171D4f594a2c47166d; + + // https://bscscan.com/address/0x42ca9E62C9B61d01Bb222d6E69f095eE98e61cE8 + address internal constant RISK_STEWARD = 0x42ca9E62C9B61d01Bb222d6E69f095eE98e61cE8; + + // https://bscscan.com/address/0x126dc589cc75f17385dD95516F3F1788d862E7bc + address internal constant RISK_COUNCIL = 0x126dc589cc75f17385dD95516F3F1788d862E7bc; + + // https://bscscan.com/address/0x5d4D4007A4c6336550DdAa2a7c0d5e7972eebd16 + address internal constant DEBT_SWAP_ADAPTER = 0x5d4D4007A4c6336550DdAa2a7c0d5e7972eebd16; + + // https://bscscan.com/address/0xAdDb96Fb6A795faf042DD25BD4710267C41D1F74 + address internal constant CONFIG_ENGINE = 0xAdDb96Fb6A795faf042DD25BD4710267C41D1F74; + + // https://bscscan.com/address/0x117684358D990E42Eb1649E7e8C4691951dc1E71 + address internal constant POOL_ADDRESSES_PROVIDER_REGISTRY = + 0x117684358D990E42Eb1649E7e8C4691951dc1E71; + + // https://bscscan.com/address/0x5598BbFA2f4fE8151f45bBA0a3edE1b54B51a0a9 + address internal constant REPAY_WITH_COLLATERAL_ADAPTER = + 0x5598BbFA2f4fE8151f45bBA0a3edE1b54B51a0a9; + + // https://bscscan.com/address/0x33E0b3fc976DC9C516926BA48CfC0A9E10a2aAA5 + address internal constant SWAP_COLLATERAL_ADAPTER = 0x33E0b3fc976DC9C516926BA48CfC0A9E10a2aAA5; + + // https://bscscan.com/address/0x5c5228aC8BC1528482514aF3e27E692495148717 + address internal constant UI_INCENTIVE_DATA_PROVIDER = 0x5c5228aC8BC1528482514aF3e27E692495148717; + + // https://bscscan.com/address/0x68100bD5345eA474D93577127C11F39FF8463e93 + address internal constant UI_POOL_DATA_PROVIDER = 0x68100bD5345eA474D93577127C11F39FF8463e93; + + // https://bscscan.com/address/0x36616cf17557639614c1cdDb356b1B83fc0B2132 + address internal constant WALLET_BALANCE_PROVIDER = 0x36616cf17557639614c1cdDb356b1B83fc0B2132; + + // https://bscscan.com/address/0x0c2C95b24529664fE55D4437D7A31175CFE6c4f7 + address internal constant WETH_GATEWAY = 0x0c2C95b24529664fE55D4437D7A31175CFE6c4f7; + + // https://bscscan.com/address/0x5E2d083417D12d4B0824E14Ecd48D26831F4Da7D + address internal constant WITHDRAW_SWAP_ADAPTER = 0x5E2d083417D12d4B0824E14Ecd48D26831F4Da7D; + + // https://bscscan.com/address/0x326aB0868bD279382Be2DF5E228Cb8AF38649AB4 + address internal constant LEGACY_STATIC_A_TOKEN_FACTORY = + 0x326aB0868bD279382Be2DF5E228Cb8AF38649AB4; + + // https://bscscan.com/address/0x3870D459d2fC2Edbb03E0DdeE6c0Ccb268caf202 + address internal constant DUST_BIN = 0x3870D459d2fC2Edbb03E0DdeE6c0Ccb268caf202; + + // https://bscscan.com/address/0x9e842f55Fdbb8F332D7c7aCe2B67fa5e4CCAAc43 + address internal constant CLINIC_STEWARD = 0x9e842f55Fdbb8F332D7c7aCe2B67fa5e4CCAAc43; + + // https://bscscan.com/address/0x58AfE45eE7D7f2AE9c26827F33A6f319Feb68Df8 + address internal constant POOL_EXPOSURE_STEWARD = 0x58AfE45eE7D7f2AE9c26827F33A6f319Feb68Df8; + + // https://bscscan.com/address/0x929B8a21a604b93DD7e95d5b9aAa3aDf5bE250ae + address internal constant STATA_FACTORY = 0x929B8a21a604b93DD7e95d5b9aAa3aDf5bE250ae; + + // https://bscscan.com/address/0x239d3Bc5fa247337287cb03f53B8bc63DBBc332D + address internal constant EDGE_RISK_ORACLE = 0x239d3Bc5fa247337287cb03f53B8bc63DBBc332D; + + // https://bscscan.com/address/0x655252250f4A453854040A49E8280951A76f3033 + address internal constant EDGE_RISK_STEWARD_CAPS = 0x655252250f4A453854040A49E8280951A76f3033; + + // https://bscscan.com/address/0x54714FAc85b0bf627288CC3a186dE81A42f1D635 + address internal constant EDGE_INJECTOR_CAPS = 0x54714FAc85b0bf627288CC3a186dE81A42f1D635; +} +library AaveV3BNBAssets { + // https://bscscan.com/address/0x0E09FaBB73Bd3Ade0a17ECC321fD13a19e81cE82 + address internal constant Cake_UNDERLYING = 0x0E09FaBB73Bd3Ade0a17ECC321fD13a19e81cE82; + + uint8 internal constant Cake_DECIMALS = 18; + + // https://bscscan.com/address/0x4199CC1F5ed0d796563d7CcB2e036253E2C18281 + address internal constant Cake_A_TOKEN = 0x4199CC1F5ed0d796563d7CcB2e036253E2C18281; + + // https://bscscan.com/address/0xE20dBC7119c635B1B51462f844861258770e0699 + address internal constant Cake_V_TOKEN = 0xE20dBC7119c635B1B51462f844861258770e0699; + + // https://bscscan.com/address/0xB6064eD41d4f67e353768aA239cA86f4F73665a1 + address internal constant Cake_ORACLE = 0xB6064eD41d4f67e353768aA239cA86f4F73665a1; + + // https://bscscan.com/address/0x86AB1C62A8bf868E1b3E1ab87d587Aba6fbCbDC5 + address internal constant Cake_INTEREST_RATE_STRATEGY = + 0x86AB1C62A8bf868E1b3E1ab87d587Aba6fbCbDC5; + + // https://bscscan.com/address/0x3854354CE3681da1D7F550073061E92a4a7d1B27 + address internal constant Cake_STATIC_A_TOKEN = 0x3854354CE3681da1D7F550073061E92a4a7d1B27; + + // https://bscscan.com/address/0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c + address internal constant WBNB_UNDERLYING = 0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c; + + uint8 internal constant WBNB_DECIMALS = 18; + + // https://bscscan.com/address/0x9B00a09492a626678E5A3009982191586C444Df9 + address internal constant WBNB_A_TOKEN = 0x9B00a09492a626678E5A3009982191586C444Df9; + + // https://bscscan.com/address/0x0E76414d433ddfe8004d2A7505d218874875a996 + address internal constant WBNB_V_TOKEN = 0x0E76414d433ddfe8004d2A7505d218874875a996; + + // https://bscscan.com/address/0x0567F2323251f0Aab15c8dFb1967E4e8A7D42aeE + address internal constant WBNB_ORACLE = 0x0567F2323251f0Aab15c8dFb1967E4e8A7D42aeE; + + // https://bscscan.com/address/0x86AB1C62A8bf868E1b3E1ab87d587Aba6fbCbDC5 + address internal constant WBNB_INTEREST_RATE_STRATEGY = + 0x86AB1C62A8bf868E1b3E1ab87d587Aba6fbCbDC5; + + // https://bscscan.com/address/0x436baCb4C66583de4Cb16e13a1A0D9A3075DE425 + address internal constant WBNB_STATIC_A_TOKEN = 0x436baCb4C66583de4Cb16e13a1A0D9A3075DE425; + + // https://bscscan.com/address/0x7130d2A12B9BCbFAe4f2634d864A1Ee1Ce3Ead9c + address internal constant BTCB_UNDERLYING = 0x7130d2A12B9BCbFAe4f2634d864A1Ee1Ce3Ead9c; + + uint8 internal constant BTCB_DECIMALS = 18; + + // https://bscscan.com/address/0x56a7ddc4e848EbF43845854205ad71D5D5F72d3D + address internal constant BTCB_A_TOKEN = 0x56a7ddc4e848EbF43845854205ad71D5D5F72d3D; + + // https://bscscan.com/address/0x7b1E82F4f542fbB25D64c5523Fe3e44aBe4F2702 + address internal constant BTCB_V_TOKEN = 0x7b1E82F4f542fbB25D64c5523Fe3e44aBe4F2702; + + // https://bscscan.com/address/0x264990fbd0A4796A3E3d8E37C4d5F87a3aCa5Ebf + address internal constant BTCB_ORACLE = 0x264990fbd0A4796A3E3d8E37C4d5F87a3aCa5Ebf; + + // https://bscscan.com/address/0x86AB1C62A8bf868E1b3E1ab87d587Aba6fbCbDC5 + address internal constant BTCB_INTEREST_RATE_STRATEGY = + 0x86AB1C62A8bf868E1b3E1ab87d587Aba6fbCbDC5; + + // https://bscscan.com/address/0x1F66b530084079d35478A069d9c4424F9c9C320c + address internal constant BTCB_STATIC_A_TOKEN = 0x1F66b530084079d35478A069d9c4424F9c9C320c; + + // https://bscscan.com/address/0x2170Ed0880ac9A755fd29B2688956BD959F933F8 + address internal constant ETH_UNDERLYING = 0x2170Ed0880ac9A755fd29B2688956BD959F933F8; + + uint8 internal constant ETH_DECIMALS = 18; + + // https://bscscan.com/address/0x2E94171493fAbE316b6205f1585779C887771E2F + address internal constant ETH_A_TOKEN = 0x2E94171493fAbE316b6205f1585779C887771E2F; + + // https://bscscan.com/address/0x8FDea7891b4D6dbdc746309245B316aF691A636C + address internal constant ETH_V_TOKEN = 0x8FDea7891b4D6dbdc746309245B316aF691A636C; + + // https://bscscan.com/address/0x9ef1B8c0E4F7dc8bF5719Ea496883DC6401d5b2e + address internal constant ETH_ORACLE = 0x9ef1B8c0E4F7dc8bF5719Ea496883DC6401d5b2e; + + // https://bscscan.com/address/0x86AB1C62A8bf868E1b3E1ab87d587Aba6fbCbDC5 + address internal constant ETH_INTEREST_RATE_STRATEGY = 0x86AB1C62A8bf868E1b3E1ab87d587Aba6fbCbDC5; + + // https://bscscan.com/address/0x52077433fB7053D747E2846aD0C18ff5015C368E + address internal constant ETH_STATIC_A_TOKEN = 0x52077433fB7053D747E2846aD0C18ff5015C368E; + + // https://bscscan.com/address/0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d + address internal constant USDC_UNDERLYING = 0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d; + + uint8 internal constant USDC_DECIMALS = 18; + + // https://bscscan.com/address/0x00901a076785e0906d1028c7d6372d247bec7d61 + address internal constant USDC_A_TOKEN = 0x00901a076785e0906d1028c7d6372d247bec7d61; + + // https://bscscan.com/address/0xcDBBEd5606d9c5C98eEedd67933991dC17F0c68d + address internal constant USDC_V_TOKEN = 0xcDBBEd5606d9c5C98eEedd67933991dC17F0c68d; + + // https://bscscan.com/address/0x9102a9553B470dbD0dC74009a870A5886C92902C + address internal constant USDC_ORACLE = 0x9102a9553B470dbD0dC74009a870A5886C92902C; + + // https://bscscan.com/address/0x86AB1C62A8bf868E1b3E1ab87d587Aba6fbCbDC5 + address internal constant USDC_INTEREST_RATE_STRATEGY = + 0x86AB1C62A8bf868E1b3E1ab87d587Aba6fbCbDC5; + + // https://bscscan.com/address/0x3906cDdfb781f02B21f21BD81ed7Fd8DC37075E1 + address internal constant USDC_STATIC_A_TOKEN = 0x3906cDdfb781f02B21f21BD81ed7Fd8DC37075E1; + + // https://bscscan.com/address/0x55d398326f99059fF775485246999027B3197955 + address internal constant USDT_UNDERLYING = 0x55d398326f99059fF775485246999027B3197955; + + uint8 internal constant USDT_DECIMALS = 18; + + // https://bscscan.com/address/0xa9251ca9DE909CB71783723713B21E4233fbf1B1 + address internal constant USDT_A_TOKEN = 0xa9251ca9DE909CB71783723713B21E4233fbf1B1; + + // https://bscscan.com/address/0xF8bb2Be50647447Fb355e3a77b81be4db64107cd + address internal constant USDT_V_TOKEN = 0xF8bb2Be50647447Fb355e3a77b81be4db64107cd; + + // https://bscscan.com/address/0xee845A7A40A090Da256420A293803C35B7F436b6 + address internal constant USDT_ORACLE = 0xee845A7A40A090Da256420A293803C35B7F436b6; + + // https://bscscan.com/address/0x86AB1C62A8bf868E1b3E1ab87d587Aba6fbCbDC5 + address internal constant USDT_INTEREST_RATE_STRATEGY = + 0x86AB1C62A8bf868E1b3E1ab87d587Aba6fbCbDC5; + + // https://bscscan.com/address/0x0471D185cc7Be61E154277cAB2396cD397663da6 + address internal constant USDT_STATIC_A_TOKEN = 0x0471D185cc7Be61E154277cAB2396cD397663da6; + + // https://bscscan.com/address/0xc5f0f7b66764F6ec8C8Dff7BA683102295E16409 + address internal constant FDUSD_UNDERLYING = 0xc5f0f7b66764F6ec8C8Dff7BA683102295E16409; + + uint8 internal constant FDUSD_DECIMALS = 18; + + // https://bscscan.com/address/0x75bd1A659bdC62e4C313950d44A2416faB43E785 + address internal constant FDUSD_A_TOKEN = 0x75bd1A659bdC62e4C313950d44A2416faB43E785; + + // https://bscscan.com/address/0xE628B8a123e6037f1542e662B9F55141a16945C8 + address internal constant FDUSD_V_TOKEN = 0xE628B8a123e6037f1542e662B9F55141a16945C8; + + // https://bscscan.com/address/0x72Cb7a00D439296A6fC3c9face9Eca96bfdEf825 + address internal constant FDUSD_ORACLE = 0x72Cb7a00D439296A6fC3c9face9Eca96bfdEf825; + + // https://bscscan.com/address/0x86AB1C62A8bf868E1b3E1ab87d587Aba6fbCbDC5 + address internal constant FDUSD_INTEREST_RATE_STRATEGY = + 0x86AB1C62A8bf868E1b3E1ab87d587Aba6fbCbDC5; + + // https://bscscan.com/address/0x4d074aAa0821073dA827f7bf6a02cF905b394ed0 + address internal constant FDUSD_STATIC_A_TOKEN = 0x4d074aAa0821073dA827f7bf6a02cF905b394ed0; + + // https://bscscan.com/address/0x26c5e01524d2E6280A48F2c50fF6De7e52E9611C + address internal constant wstETH_UNDERLYING = 0x26c5e01524d2E6280A48F2c50fF6De7e52E9611C; + + uint8 internal constant wstETH_DECIMALS = 18; + + // https://bscscan.com/address/0xBDFd4E51D3c14a232135f04988a42576eFb31519 + address internal constant wstETH_A_TOKEN = 0xBDFd4E51D3c14a232135f04988a42576eFb31519; + + // https://bscscan.com/address/0x2c391998308c56D7572A8F501D58CB56fB9Fe1C5 + address internal constant wstETH_V_TOKEN = 0x2c391998308c56D7572A8F501D58CB56fB9Fe1C5; + + // https://bscscan.com/address/0xc1377B4cdF9116bf7b3d7F72A4f8A7Be8506cE80 + address internal constant wstETH_ORACLE = 0xc1377B4cdF9116bf7b3d7F72A4f8A7Be8506cE80; + + // https://bscscan.com/address/0x86AB1C62A8bf868E1b3E1ab87d587Aba6fbCbDC5 + address internal constant wstETH_INTEREST_RATE_STRATEGY = + 0x86AB1C62A8bf868E1b3E1ab87d587Aba6fbCbDC5; +} +library AaveV3BNBEModes { + uint8 internal constant NONE = 0; + + uint8 internal constant wstETH__ETH = 1; +} +library AaveV3BNBExternalLibraries { + // https://bscscan.com/address/0x6D414cd0d5eAf8C43200ac0c325A7E2Ad83B8be6 + address internal constant FLASHLOAN_LOGIC = 0x6D414cd0d5eAf8C43200ac0c325A7E2Ad83B8be6; + + // https://bscscan.com/address/0x52Da0ce88202D1542543598D1e1e27F0d344726A + address internal constant BORROW_LOGIC = 0x52Da0ce88202D1542543598D1e1e27F0d344726A; + + // https://bscscan.com/address/0x96D5686812e33Ab509ECCDb38C89d15607B2a413 + address internal constant LIQUIDATION_LOGIC = 0x96D5686812e33Ab509ECCDb38C89d15607B2a413; + + // https://bscscan.com/address/0xD70593841C57cbaA04957cc3EAcE95708e48853b + address internal constant POOL_LOGIC = 0xD70593841C57cbaA04957cc3EAcE95708e48853b; + + // https://bscscan.com/address/0x584C7d8c4cb05304FE5Ac7fbc97f20A10Fb07564 + address internal constant SUPPLY_LOGIC = 0x584C7d8c4cb05304FE5Ac7fbc97f20A10Fb07564; +} diff --git a/plan/agw/research/preset-mainnet-2026-10-15/AaveV3Base.sol b/plan/agw/research/preset-mainnet-2026-10-15/AaveV3Base.sol new file mode 100644 index 00000000..704c4f9f --- /dev/null +++ b/plan/agw/research/preset-mainnet-2026-10-15/AaveV3Base.sol @@ -0,0 +1,503 @@ +// AUTOGENERATED - MANUAL CHANGES WILL BE REVERTED BY THE GENERATOR +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.0; + +import {IPoolAddressesProvider, IPool, IPoolConfigurator, IAaveOracle, IPoolDataProvider, IACLManager, ICollector} from './AaveV3.sol'; +library AaveV3Base { + // https://basescan.org/address/0xe20fCBdBfFC4Dd138cE8b2E6FBb6CB49777ad64D + IPoolAddressesProvider internal constant POOL_ADDRESSES_PROVIDER = + IPoolAddressesProvider(0xe20fCBdBfFC4Dd138cE8b2E6FBb6CB49777ad64D); + + // https://basescan.org/address/0xA238Dd80C259a72e81d7e4664a9801593F98d1c5 + IPool internal constant POOL = IPool(0xA238Dd80C259a72e81d7e4664a9801593F98d1c5); + + // https://basescan.org/address/0x5731a04B1E775f0fdd454Bf70f3335886e9A96be + IPoolConfigurator internal constant POOL_CONFIGURATOR = + IPoolConfigurator(0x5731a04B1E775f0fdd454Bf70f3335886e9A96be); + + // https://basescan.org/address/0x2Cc0Fc26eD4563A5ce5e8bdcfe1A2878676Ae156 + IAaveOracle internal constant ORACLE = IAaveOracle(0x2Cc0Fc26eD4563A5ce5e8bdcfe1A2878676Ae156); + + // https://basescan.org/address/0x9390B1735def18560c509E2d0bc090E9d6BA257a + address internal constant ACL_ADMIN = 0x9390B1735def18560c509E2d0bc090E9d6BA257a; + + // https://basescan.org/address/0x43955b0899Ab7232E3a454cf84AedD22Ad46FD33 + IACLManager internal constant ACL_MANAGER = + IACLManager(0x43955b0899Ab7232E3a454cf84AedD22Ad46FD33); + + // https://basescan.org/address/0x0F43731EB8d45A581f4a36DD74F5f358bc90C73A + IPoolDataProvider internal constant AAVE_PROTOCOL_DATA_PROVIDER = + IPoolDataProvider(0x0F43731EB8d45A581f4a36DD74F5f358bc90C73A); + + // https://basescan.org/address/0xA4AbC5FcBA6D0d7E3D144d6dbF6cb6128599dFdB + address internal constant POOL_IMPL = 0xA4AbC5FcBA6D0d7E3D144d6dbF6cb6128599dFdB; + + // https://basescan.org/address/0xFF42Ce30054dcE7dc7C1282a9a497aa58eaBCe99 + address internal constant POOL_CONFIGURATOR_IMPL = 0xFF42Ce30054dcE7dc7C1282a9a497aa58eaBCe99; + + // https://basescan.org/address/0xf9cc4F0D883F1a1eb2c253bdb46c254Ca51E1F44 + address internal constant DEFAULT_INCENTIVES_CONTROLLER = + 0xf9cc4F0D883F1a1eb2c253bdb46c254Ca51E1F44; + + // https://basescan.org/address/0x6533A273F3aC84Df91DCD654D6EBAbA73687e246 + address internal constant EMISSION_MANAGER = 0x6533A273F3aC84Df91DCD654D6EBAbA73687e246; + + // https://basescan.org/address/0xBA9424d650A4F5c80a0dA641254d1AcCE2A37057 + ICollector internal constant COLLECTOR = ICollector(0xBA9424d650A4F5c80a0dA641254d1AcCE2A37057); + + // https://basescan.org/address/0x273E4B97C3f5280AFf4949Aa19a27fF54968458D + address internal constant DEFAULT_A_TOKEN_IMPL = 0x273E4B97C3f5280AFf4949Aa19a27fF54968458D; + + // https://basescan.org/address/0x7354Dc700A1A2ab9622f2292B60Ca1ceD5B204D0 + address internal constant DEFAULT_VARIABLE_DEBT_TOKEN_IMPL = + 0x7354Dc700A1A2ab9622f2292B60Ca1ceD5B204D0; + + // https://basescan.org/address/0x494bcfd3937aBdebEF3D2c2eae1CE8A2Fb629032 + address internal constant RISK_STEWARD = 0x494bcfd3937aBdebEF3D2c2eae1CE8A2Fb629032; + + // https://basescan.org/address/0xfbeB4AcB31340bA4de9C87B11dfBf7e2bc8C0bF1 + address internal constant RISK_COUNCIL = 0xfbeB4AcB31340bA4de9C87B11dfBf7e2bc8C0bF1; + + // https://basescan.org/address/0xB892202d9Ce2C16C565A492a5168689b215Eb269 + address internal constant EDGE_RISK_STEWARD_CAPS = 0xB892202d9Ce2C16C565A492a5168689b215Eb269; + + // https://basescan.org/address/0x4f84A364B66Eb6280350da011829a6BD02B4712f + address internal constant EDGE_INJECTOR_CAPS = 0x4f84A364B66Eb6280350da011829a6BD02B4712f; + + // https://basescan.org/address/0x239d3Bc5fa247337287cb03f53B8bc63DBBc332D + address internal constant EDGE_RISK_ORACLE = 0x239d3Bc5fa247337287cb03f53B8bc63DBBc332D; + + // https://basescan.org/address/0xb12e82DF057BF16ecFa89D7D089dc7E5C1Dc057B + address internal constant DEBT_SWAP_ADAPTER = 0xb12e82DF057BF16ecFa89D7D089dc7E5C1Dc057B; + + // https://basescan.org/address/0x5598BbFA2f4fE8151f45bBA0a3edE1b54B51a0a9 + address internal constant WITHDRAW_SWAP_ADAPTER = 0x5598BbFA2f4fE8151f45bBA0a3edE1b54B51a0a9; + + // https://basescan.org/address/0x2E549104c516b8657A7D888494DfbAbD7C70b464 + address internal constant SWAP_COLLATERAL_ADAPTER = 0x2E549104c516b8657A7D888494DfbAbD7C70b464; + + // https://basescan.org/address/0x63dfa7c09Dc2Ff4030d6B8Dc2ce6262BF898C8A4 + address internal constant REPAY_WITH_COLLATERAL_ADAPTER = + 0x63dfa7c09Dc2Ff4030d6B8Dc2ce6262BF898C8A4; + + // https://basescan.org/address/0x940F9a5d5F9ED264990D0eaee1F3DD60B4Cb9A22 + address internal constant LEGACY_STATIC_A_TOKEN_FACTORY = + 0x940F9a5d5F9ED264990D0eaee1F3DD60B4Cb9A22; + + // https://basescan.org/address/0xe63eAf6DAb1045689BD3a332bC596FfcF54A5C88 + address internal constant LEGACY_STATIC_A_TOKEN_ORACLE = + 0xe63eAf6DAb1045689BD3a332bC596FfcF54A5C88; + + // https://basescan.org/address/0xa5008BC7Fd697F458482205Ed52Dc51e91d37446 + address internal constant CONFIG_ENGINE = 0xa5008BC7Fd697F458482205Ed52Dc51e91d37446; + + // https://basescan.org/address/0x39e97c588B2907Fb67F44fea256Ae3BA064207C5 + address internal constant L2_ENCODER = 0x39e97c588B2907Fb67F44fea256Ae3BA064207C5; + + // https://basescan.org/address/0x2f6571d3Eb9a4e350C68C36bCD2afe39530078E2 + address internal constant POOL_ADDRESSES_PROVIDER_REGISTRY = + 0x2f6571d3Eb9a4e350C68C36bCD2afe39530078E2; + + // https://basescan.org/address/0x91E04cf78e53aEBe609e8a7f2003e7EECD743F2B + address internal constant UI_INCENTIVE_DATA_PROVIDER = 0x91E04cf78e53aEBe609e8a7f2003e7EECD743F2B; + + // https://basescan.org/address/0x0C6BC4a12039788be08F87e87Cff87FEDbd1D386 + address internal constant UI_POOL_DATA_PROVIDER = 0x0C6BC4a12039788be08F87e87Cff87FEDbd1D386; + + // https://basescan.org/address/0x5779b29B0a34577d927E8D511B595ef9abbFAE82 + address internal constant WALLET_BALANCE_PROVIDER = 0x5779b29B0a34577d927E8D511B595ef9abbFAE82; + + // https://basescan.org/address/0xa0d9C1E9E48Ca30c8d8C3B5D69FF5dc1f6DFfC24 + address internal constant WETH_GATEWAY = 0xa0d9C1E9E48Ca30c8d8C3B5D69FF5dc1f6DFfC24; + + // https://basescan.org/address/0x78d33BF0014ab169725F2Ea5a62b200F2977faeE + address internal constant STATA_FACTORY = 0x78d33BF0014ab169725F2Ea5a62b200F2977faeE; + + // https://basescan.org/address/0x3870D459d2fC2Edbb03E0DdeE6c0Ccb268caf202 + address internal constant DUST_BIN = 0x3870D459d2fC2Edbb03E0DdeE6c0Ccb268caf202; + + // https://basescan.org/address/0x1a79098C3149020ACdEfb3EE44AA1d9509305530 + address internal constant CLINIC_STEWARD = 0x1a79098C3149020ACdEfb3EE44AA1d9509305530; + + // https://basescan.org/address/0x4f1F3E32f20847a4c9F002882eB607aD750b6115 + address internal constant POOL_EXPOSURE_STEWARD = 0x4f1F3E32f20847a4c9F002882eB607aD750b6115; +} +library AaveV3BaseAssets { + // https://basescan.org/address/0x4200000000000000000000000000000000000006 + address internal constant WETH_UNDERLYING = 0x4200000000000000000000000000000000000006; + + uint8 internal constant WETH_DECIMALS = 18; + + // https://basescan.org/address/0xD4a0e0b9149BCee3C920d2E00b5dE09138fd8bb7 + address internal constant WETH_A_TOKEN = 0xD4a0e0b9149BCee3C920d2E00b5dE09138fd8bb7; + + // https://basescan.org/address/0x24e6e0795b3c7c71D965fCc4f371803d1c1DcA1E + address internal constant WETH_V_TOKEN = 0x24e6e0795b3c7c71D965fCc4f371803d1c1DcA1E; + + // https://basescan.org/address/0x9dA00D23465282005DB222a441a663eE7B9dfCc8 + address internal constant WETH_ORACLE = 0x9dA00D23465282005DB222a441a663eE7B9dfCc8; + + // https://basescan.org/address/0x86AB1C62A8bf868E1b3E1ab87d587Aba6fbCbDC5 + address internal constant WETH_INTEREST_RATE_STRATEGY = + 0x86AB1C62A8bf868E1b3E1ab87d587Aba6fbCbDC5; + + // https://basescan.org/address/0x468973e3264F2aEba0417A8f2cD0Ec397E738898 + address internal constant WETH_STATIC_A_TOKEN = 0x468973e3264F2aEba0417A8f2cD0Ec397E738898; + + // https://basescan.org/address/0xe298b938631f750DD409fB18227C4a23dCdaab9b + address internal constant WETH_STATA_TOKEN = 0xe298b938631f750DD409fB18227C4a23dCdaab9b; + + // https://basescan.org/address/0x2Ae3F1Ec7F1F5012CFEab0185bfc7aa3cf0DEc22 + address internal constant cbETH_UNDERLYING = 0x2Ae3F1Ec7F1F5012CFEab0185bfc7aa3cf0DEc22; + + uint8 internal constant cbETH_DECIMALS = 18; + + // https://basescan.org/address/0xcf3D55c10DB69f28fD1A75Bd73f3D8A2d9c595ad + address internal constant cbETH_A_TOKEN = 0xcf3D55c10DB69f28fD1A75Bd73f3D8A2d9c595ad; + + // https://basescan.org/address/0x1DabC36f19909425f654777249815c073E8Fd79F + address internal constant cbETH_V_TOKEN = 0x1DabC36f19909425f654777249815c073E8Fd79F; + + // https://basescan.org/address/0xB6E9fbba669763BD811B10A761110C449824b5BB + address internal constant cbETH_ORACLE = 0xB6E9fbba669763BD811B10A761110C449824b5BB; + + // https://basescan.org/address/0x86AB1C62A8bf868E1b3E1ab87d587Aba6fbCbDC5 + address internal constant cbETH_INTEREST_RATE_STRATEGY = + 0x86AB1C62A8bf868E1b3E1ab87d587Aba6fbCbDC5; + + // https://basescan.org/address/0x16A004065dfb11276DcB29Dc03fb8A85f9A43C6e + address internal constant cbETH_STATIC_A_TOKEN = 0x16A004065dfb11276DcB29Dc03fb8A85f9A43C6e; + + // https://basescan.org/address/0x5e8B674127B321DC344c078e58BBACc3f3008962 + address internal constant cbETH_STATA_TOKEN = 0x5e8B674127B321DC344c078e58BBACc3f3008962; + + // https://basescan.org/address/0xd9aAEc86B65D86f6A7B5B1b0c42FFA531710b6CA + address internal constant USDbC_UNDERLYING = 0xd9aAEc86B65D86f6A7B5B1b0c42FFA531710b6CA; + + uint8 internal constant USDbC_DECIMALS = 6; + + // https://basescan.org/address/0x0a1d576f3eFeF75b330424287a95A366e8281D54 + address internal constant USDbC_A_TOKEN = 0x0a1d576f3eFeF75b330424287a95A366e8281D54; + + // https://basescan.org/address/0x7376b2F323dC56fCd4C191B34163ac8a84702DAB + address internal constant USDbC_V_TOKEN = 0x7376b2F323dC56fCd4C191B34163ac8a84702DAB; + + // https://basescan.org/address/0xf52D010c7d4ecBfda92c2509900593CE34535D86 + address internal constant USDbC_ORACLE = 0xf52D010c7d4ecBfda92c2509900593CE34535D86; + + // https://basescan.org/address/0x86AB1C62A8bf868E1b3E1ab87d587Aba6fbCbDC5 + address internal constant USDbC_INTEREST_RATE_STRATEGY = + 0x86AB1C62A8bf868E1b3E1ab87d587Aba6fbCbDC5; + + // https://basescan.org/address/0x6fCe2756794128B1771324caA860965801DCbCdB + address internal constant USDbC_STATIC_A_TOKEN = 0x6fCe2756794128B1771324caA860965801DCbCdB; + + // https://basescan.org/address/0x74D4D1D440c9679b1013999Bd91507eAa2fff651 + address internal constant USDbC_STATA_TOKEN = 0x74D4D1D440c9679b1013999Bd91507eAa2fff651; + + // https://basescan.org/address/0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452 + address internal constant wstETH_UNDERLYING = 0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452; + + uint8 internal constant wstETH_DECIMALS = 18; + + // https://basescan.org/address/0x99CBC45ea5bb7eF3a5BC08FB1B7E56bB2442Ef0D + address internal constant wstETH_A_TOKEN = 0x99CBC45ea5bb7eF3a5BC08FB1B7E56bB2442Ef0D; + + // https://basescan.org/address/0x41A7C3f5904ad176dACbb1D99101F59ef0811DC1 + address internal constant wstETH_V_TOKEN = 0x41A7C3f5904ad176dACbb1D99101F59ef0811DC1; + + // https://basescan.org/address/0x1AFC5010Fb182B6e62D6a3B522F09F644Fb62EfD + address internal constant wstETH_ORACLE = 0x1AFC5010Fb182B6e62D6a3B522F09F644Fb62EfD; + + // https://basescan.org/address/0x86AB1C62A8bf868E1b3E1ab87d587Aba6fbCbDC5 + address internal constant wstETH_INTEREST_RATE_STRATEGY = + 0x86AB1C62A8bf868E1b3E1ab87d587Aba6fbCbDC5; + + // https://basescan.org/address/0x03916e49f794Ab877eFA23597627eE8094E6cbB0 + address internal constant wstETH_STATIC_A_TOKEN = 0x03916e49f794Ab877eFA23597627eE8094E6cbB0; + + // https://basescan.org/address/0x0830820D1A9aa1554364752d6D8F55C836871B74 + address internal constant wstETH_STATA_TOKEN = 0x0830820D1A9aa1554364752d6D8F55C836871B74; + + // https://basescan.org/address/0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 + address internal constant USDC_UNDERLYING = 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913; + + uint8 internal constant USDC_DECIMALS = 6; + + // https://basescan.org/address/0x4e65fE4DbA92790696d040ac24Aa414708F5c0AB + address internal constant USDC_A_TOKEN = 0x4e65fE4DbA92790696d040ac24Aa414708F5c0AB; + + // https://basescan.org/address/0x59dca05b6c26dbd64b5381374aAaC5CD05644C28 + address internal constant USDC_V_TOKEN = 0x59dca05b6c26dbd64b5381374aAaC5CD05644C28; + + // https://basescan.org/address/0xf52D010c7d4ecBfda92c2509900593CE34535D86 + address internal constant USDC_ORACLE = 0xf52D010c7d4ecBfda92c2509900593CE34535D86; + + // https://basescan.org/address/0x86AB1C62A8bf868E1b3E1ab87d587Aba6fbCbDC5 + address internal constant USDC_INTEREST_RATE_STRATEGY = + 0x86AB1C62A8bf868E1b3E1ab87d587Aba6fbCbDC5; + + // https://basescan.org/address/0x4EA71A20e655794051D1eE8b6e4A3269B13ccaCc + address internal constant USDC_STATIC_A_TOKEN = 0x4EA71A20e655794051D1eE8b6e4A3269B13ccaCc; + + // https://basescan.org/address/0xC768c589647798a6EE01A91FdE98EF2ed046DBD6 + address internal constant USDC_STATA_TOKEN = 0xC768c589647798a6EE01A91FdE98EF2ed046DBD6; + + // https://basescan.org/address/0x04C0599Ae5A44757c0af6F9eC3b93da8976c150A + address internal constant weETH_UNDERLYING = 0x04C0599Ae5A44757c0af6F9eC3b93da8976c150A; + + uint8 internal constant weETH_DECIMALS = 18; + + // https://basescan.org/address/0x7C307e128efA31F540F2E2d976C995E0B65F51F6 + address internal constant weETH_A_TOKEN = 0x7C307e128efA31F540F2E2d976C995E0B65F51F6; + + // https://basescan.org/address/0x8D2e3F1f4b38AA9f1ceD22ac06019c7561B03901 + address internal constant weETH_V_TOKEN = 0x8D2e3F1f4b38AA9f1ceD22ac06019c7561B03901; + + // https://basescan.org/address/0x0A0fFc2952B682eb36cde5Bdb03169C2c5F5305c + address internal constant weETH_ORACLE = 0x0A0fFc2952B682eb36cde5Bdb03169C2c5F5305c; + + // https://basescan.org/address/0x86AB1C62A8bf868E1b3E1ab87d587Aba6fbCbDC5 + address internal constant weETH_INTEREST_RATE_STRATEGY = + 0x86AB1C62A8bf868E1b3E1ab87d587Aba6fbCbDC5; + + // https://basescan.org/address/0x588159E0d360ffAA978330812f9234818ab46E8E + address internal constant weETH_STATIC_A_TOKEN = 0x588159E0d360ffAA978330812f9234818ab46E8E; + + // https://basescan.org/address/0x6acD0a165fD70A84b6b50d955ff3628700bAAf4b + address internal constant weETH_STATA_TOKEN = 0x6acD0a165fD70A84b6b50d955ff3628700bAAf4b; + + // https://basescan.org/address/0xcbB7C0000aB88B473b1f5aFd9ef808440eed33Bf + address internal constant cbBTC_UNDERLYING = 0xcbB7C0000aB88B473b1f5aFd9ef808440eed33Bf; + + uint8 internal constant cbBTC_DECIMALS = 8; + + // https://basescan.org/address/0xBdb9300b7CDE636d9cD4AFF00f6F009fFBBc8EE6 + address internal constant cbBTC_A_TOKEN = 0xBdb9300b7CDE636d9cD4AFF00f6F009fFBBc8EE6; + + // https://basescan.org/address/0x05e08702028de6AaD395DC6478b554a56920b9AD + address internal constant cbBTC_V_TOKEN = 0x05e08702028de6AaD395DC6478b554a56920b9AD; + + // https://basescan.org/address/0x3A932b286715abc4A86a4ACAF68A6cdD89E0d446 + address internal constant cbBTC_ORACLE = 0x3A932b286715abc4A86a4ACAF68A6cdD89E0d446; + + // https://basescan.org/address/0x86AB1C62A8bf868E1b3E1ab87d587Aba6fbCbDC5 + address internal constant cbBTC_INTEREST_RATE_STRATEGY = + 0x86AB1C62A8bf868E1b3E1ab87d587Aba6fbCbDC5; + + // https://basescan.org/address/0xeaCFa728623d0958e3C386bACed79138BCAfC50F + address internal constant cbBTC_STATIC_A_TOKEN = 0xeaCFa728623d0958e3C386bACed79138BCAfC50F; + + // https://basescan.org/address/0xFA2A03b6f4A65fB1Af64f7d935fDBf78693df9aF + address internal constant cbBTC_STATA_TOKEN = 0xFA2A03b6f4A65fB1Af64f7d935fDBf78693df9aF; + + // https://basescan.org/address/0x2416092f143378750bb29b79eD961ab195CcEea5 + address internal constant ezETH_UNDERLYING = 0x2416092f143378750bb29b79eD961ab195CcEea5; + + uint8 internal constant ezETH_DECIMALS = 18; + + // https://basescan.org/address/0xDD5745756C2de109183c6B5bB886F9207bEF114D + address internal constant ezETH_A_TOKEN = 0xDD5745756C2de109183c6B5bB886F9207bEF114D; + + // https://basescan.org/address/0xbc4f5631f2843488792e4F1660d0A51Ba489bdBd + address internal constant ezETH_V_TOKEN = 0xbc4f5631f2843488792e4F1660d0A51Ba489bdBd; + + // https://basescan.org/address/0x0B472c80cAf27B3238Ae6cF0f13a362D2522bf6d + address internal constant ezETH_ORACLE = 0x0B472c80cAf27B3238Ae6cF0f13a362D2522bf6d; + + // https://basescan.org/address/0x86AB1C62A8bf868E1b3E1ab87d587Aba6fbCbDC5 + address internal constant ezETH_INTEREST_RATE_STRATEGY = + 0x86AB1C62A8bf868E1b3E1ab87d587Aba6fbCbDC5; + + // https://basescan.org/address/0xF8F10f39116716e89498c1c5E94137ADa11b2BC7 + address internal constant ezETH_STATA_TOKEN = 0xF8F10f39116716e89498c1c5E94137ADa11b2BC7; + + // https://basescan.org/address/0x6Bb7a212910682DCFdbd5BCBb3e28FB4E8da10Ee + address internal constant GHO_UNDERLYING = 0x6Bb7a212910682DCFdbd5BCBb3e28FB4E8da10Ee; + + uint8 internal constant GHO_DECIMALS = 18; + + // https://basescan.org/address/0x067ae75628177FD257c2B1e500993e1a0baBcBd1 + address internal constant GHO_A_TOKEN = 0x067ae75628177FD257c2B1e500993e1a0baBcBd1; + + // https://basescan.org/address/0x38e59ADE183BbEb94583d44213c8f3297e9933e9 + address internal constant GHO_V_TOKEN = 0x38e59ADE183BbEb94583d44213c8f3297e9933e9; + + // https://basescan.org/address/0xfc421aD3C883Bf9E7C4f42dE845C4e4405799e73 + address internal constant GHO_ORACLE = 0xfc421aD3C883Bf9E7C4f42dE845C4e4405799e73; + + // https://basescan.org/address/0x86AB1C62A8bf868E1b3E1ab87d587Aba6fbCbDC5 + address internal constant GHO_INTEREST_RATE_STRATEGY = 0x86AB1C62A8bf868E1b3E1ab87d587Aba6fbCbDC5; + + // https://basescan.org/address/0x88b1Cd4b430D95b406E382C3cDBaE54697a0286E + address internal constant GHO_STATA_TOKEN = 0x88b1Cd4b430D95b406E382C3cDBaE54697a0286E; + + // https://basescan.org/address/0xEDfa23602D0EC14714057867A78d01e94176BEA0 + address internal constant wrsETH_UNDERLYING = 0xEDfa23602D0EC14714057867A78d01e94176BEA0; + + uint8 internal constant wrsETH_DECIMALS = 18; + + // https://basescan.org/address/0x80a94C36747CF51b2FbabDfF045f6D22c1930eD1 + address internal constant wrsETH_A_TOKEN = 0x80a94C36747CF51b2FbabDfF045f6D22c1930eD1; + + // https://basescan.org/address/0xe9541C77a111bCAa5dF56839bbC50894eba7aFcb + address internal constant wrsETH_V_TOKEN = 0xe9541C77a111bCAa5dF56839bbC50894eba7aFcb; + + // https://basescan.org/address/0x87445df51b4A2E5BbD2F0F8564C5bfe65cC3dB61 + address internal constant wrsETH_ORACLE = 0x87445df51b4A2E5BbD2F0F8564C5bfe65cC3dB61; + + // https://basescan.org/address/0x86AB1C62A8bf868E1b3E1ab87d587Aba6fbCbDC5 + address internal constant wrsETH_INTEREST_RATE_STRATEGY = + 0x86AB1C62A8bf868E1b3E1ab87d587Aba6fbCbDC5; + + // https://basescan.org/address/0xCa79190050739D27B61e24B085DD4Af990254Ec2 + address internal constant wrsETH_STATA_TOKEN = 0xCa79190050739D27B61e24B085DD4Af990254Ec2; + + // https://basescan.org/address/0xecAc9C5F704e954931349Da37F60E39f515c11c1 + address internal constant LBTC_UNDERLYING = 0xecAc9C5F704e954931349Da37F60E39f515c11c1; + + uint8 internal constant LBTC_DECIMALS = 8; + + // https://basescan.org/address/0x90072A4aA69B5Eb74984Ab823EFC5f91e90b3a72 + address internal constant LBTC_A_TOKEN = 0x90072A4aA69B5Eb74984Ab823EFC5f91e90b3a72; + + // https://basescan.org/address/0xa2525b3f058846075506903d792d58C5a0D834c9 + address internal constant LBTC_V_TOKEN = 0xa2525b3f058846075506903d792d58C5a0D834c9; + + // https://basescan.org/address/0x7a52aEb0461Ff4De29D5849A9E9885ca4E0d62D0 + address internal constant LBTC_ORACLE = 0x7a52aEb0461Ff4De29D5849A9E9885ca4E0d62D0; + + // https://basescan.org/address/0x86AB1C62A8bf868E1b3E1ab87d587Aba6fbCbDC5 + address internal constant LBTC_INTEREST_RATE_STRATEGY = + 0x86AB1C62A8bf868E1b3E1ab87d587Aba6fbCbDC5; + + // https://basescan.org/address/0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42 + address internal constant EURC_UNDERLYING = 0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42; + + uint8 internal constant EURC_DECIMALS = 6; + + // https://basescan.org/address/0x90DA57E0A6C0d166Bf15764E03b83745Dc90025B + address internal constant EURC_A_TOKEN = 0x90DA57E0A6C0d166Bf15764E03b83745Dc90025B; + + // https://basescan.org/address/0x03D01595769333174036832e18fA2f17C74f8161 + address internal constant EURC_V_TOKEN = 0x03D01595769333174036832e18fA2f17C74f8161; + + // https://basescan.org/address/0x8438ee84b847FA4e462d906bbdf4B11341434d13 + address internal constant EURC_ORACLE = 0x8438ee84b847FA4e462d906bbdf4B11341434d13; + + // https://basescan.org/address/0x86AB1C62A8bf868E1b3E1ab87d587Aba6fbCbDC5 + address internal constant EURC_INTEREST_RATE_STRATEGY = + 0x86AB1C62A8bf868E1b3E1ab87d587Aba6fbCbDC5; + + // https://basescan.org/address/0x729F75Aff28c726e32403e80cef2aFb518CFbfa7 + address internal constant EURC_STATA_TOKEN = 0x729F75Aff28c726e32403e80cef2aFb518CFbfa7; + + // https://basescan.org/address/0x63706e401c06ac8513145b7687A14804d17f814b + address internal constant AAVE_UNDERLYING = 0x63706e401c06ac8513145b7687A14804d17f814b; + + uint8 internal constant AAVE_DECIMALS = 18; + + // https://basescan.org/address/0x67EAF2BeE4384a2f84Da9Eb8105C661C123736BA + address internal constant AAVE_A_TOKEN = 0x67EAF2BeE4384a2f84Da9Eb8105C661C123736BA; + + // https://basescan.org/address/0xcEC1Ea95dDEF7CFC27D3D9615E05b035af460978 + address internal constant AAVE_V_TOKEN = 0xcEC1Ea95dDEF7CFC27D3D9615E05b035af460978; + + // https://basescan.org/address/0xAAEbc0287EC3BF3fe56fCA1E4bcC793b219De551 + address internal constant AAVE_ORACLE = 0xAAEbc0287EC3BF3fe56fCA1E4bcC793b219De551; + + // https://basescan.org/address/0x86AB1C62A8bf868E1b3E1ab87d587Aba6fbCbDC5 + address internal constant AAVE_INTEREST_RATE_STRATEGY = + 0x86AB1C62A8bf868E1b3E1ab87d587Aba6fbCbDC5; + + // https://basescan.org/address/0x4170aa42631d60160171C60d523A2783565261b9 + address internal constant AAVE_STATA_TOKEN = 0x4170aa42631d60160171C60d523A2783565261b9; + + // https://basescan.org/address/0x236aa50979D5f3De3Bd1Eeb40E81137F22ab794b + address internal constant tBTC_UNDERLYING = 0x236aa50979D5f3De3Bd1Eeb40E81137F22ab794b; + + uint8 internal constant tBTC_DECIMALS = 18; + + // https://basescan.org/address/0xbcFFB4B3beADc989Bd1458740952aF6EC8fBE431 + address internal constant tBTC_A_TOKEN = 0xbcFFB4B3beADc989Bd1458740952aF6EC8fBE431; + + // https://basescan.org/address/0x182cDEEC1D52ccad869d621bA422F449FA5809f5 + address internal constant tBTC_V_TOKEN = 0x182cDEEC1D52ccad869d621bA422F449FA5809f5; + + // https://basescan.org/address/0x3A932b286715abc4A86a4ACAF68A6cdD89E0d446 + address internal constant tBTC_ORACLE = 0x3A932b286715abc4A86a4ACAF68A6cdD89E0d446; + + // https://basescan.org/address/0x86AB1C62A8bf868E1b3E1ab87d587Aba6fbCbDC5 + address internal constant tBTC_INTEREST_RATE_STRATEGY = + 0x86AB1C62A8bf868E1b3E1ab87d587Aba6fbCbDC5; + + // https://basescan.org/address/0x660975730059246A68521a3e2FBD4740173100f5 + address internal constant syrupUSDC_UNDERLYING = 0x660975730059246A68521a3e2FBD4740173100f5; + + uint8 internal constant syrupUSDC_DECIMALS = 6; + + // https://basescan.org/address/0xD7424238CcbE7b7198Ab3cFE232e0271E22da7bd + address internal constant syrupUSDC_A_TOKEN = 0xD7424238CcbE7b7198Ab3cFE232e0271E22da7bd; + + // https://basescan.org/address/0x57B8C05ee2cD9d0143eBC21FBD9288C39B9F716c + address internal constant syrupUSDC_V_TOKEN = 0x57B8C05ee2cD9d0143eBC21FBD9288C39B9F716c; + + // https://basescan.org/address/0x5e9eCce4aCBBc8172A40f7b8A7c086A4bb5CDeac + address internal constant syrupUSDC_ORACLE = 0x5e9eCce4aCBBc8172A40f7b8A7c086A4bb5CDeac; + + // https://basescan.org/address/0x86AB1C62A8bf868E1b3E1ab87d587Aba6fbCbDC5 + address internal constant syrupUSDC_INTEREST_RATE_STRATEGY = + 0x86AB1C62A8bf868E1b3E1ab87d587Aba6fbCbDC5; + + // https://basescan.org/address/0xaD785bd1666c582FcAb74088ce73BDF4c9da1f20 + address internal constant syrupUSDC_STATA_TOKEN = 0xaD785bd1666c582FcAb74088ce73BDF4c9da1f20; +} +library AaveV3BaseEModes { + uint8 internal constant NONE = 0; + + uint8 internal constant WETH_cbETH_wstETH_weETH__WETH = 1; + + uint8 internal constant ezETH__wstETH = 2; + + uint8 internal constant ezETH__USDC = 3; + + uint8 internal constant LBTC__cbBTC = 4; + + uint8 internal constant wrsETH__WETH_wstETH = 5; + + uint8 internal constant wrsETH__USDC = 6; + + uint8 internal constant weETH__WETH = 7; + + uint8 internal constant wstETH__WETH = 8; + + uint8 internal constant cbETH__WETH = 9; + + uint8 internal constant cbBTC__USDC_GHO = 10; + + uint8 internal constant syrupUSDC__USDC_GHO = 11; + + uint8 internal constant AAVE__USDC_GHO = 12; + + uint8 internal constant EURC__USDC_GHO = 13; + + uint8 internal constant LBTC__USDC_GHO = 14; + + uint8 internal constant tBTC__USDC_GHO = 15; +} +library AaveV3BaseExternalLibraries { + // https://basescan.org/address/0x6D414cd0d5eAf8C43200ac0c325A7E2Ad83B8be6 + address internal constant FLASHLOAN_LOGIC = 0x6D414cd0d5eAf8C43200ac0c325A7E2Ad83B8be6; + + // https://basescan.org/address/0x52Da0ce88202D1542543598D1e1e27F0d344726A + address internal constant BORROW_LOGIC = 0x52Da0ce88202D1542543598D1e1e27F0d344726A; + + // https://basescan.org/address/0x96D5686812e33Ab509ECCDb38C89d15607B2a413 + address internal constant LIQUIDATION_LOGIC = 0x96D5686812e33Ab509ECCDb38C89d15607B2a413; + + // https://basescan.org/address/0xD70593841C57cbaA04957cc3EAcE95708e48853b + address internal constant POOL_LOGIC = 0xD70593841C57cbaA04957cc3EAcE95708e48853b; + + // https://basescan.org/address/0x584C7d8c4cb05304FE5Ac7fbc97f20A10Fb07564 + address internal constant SUPPLY_LOGIC = 0x584C7d8c4cb05304FE5Ac7fbc97f20A10Fb07564; +} diff --git a/plan/agw/research/preset-mainnet-2026-10-15/AaveV3Ethereum.sol b/plan/agw/research/preset-mainnet-2026-10-15/AaveV3Ethereum.sol new file mode 100644 index 00000000..75c7b74e --- /dev/null +++ b/plan/agw/research/preset-mainnet-2026-10-15/AaveV3Ethereum.sol @@ -0,0 +1,1602 @@ +// AUTOGENERATED - MANUAL CHANGES WILL BE REVERTED BY THE GENERATOR +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.0; + +import {IPoolAddressesProvider, IPool, IPoolConfigurator, IAaveOracle, IPoolDataProvider, IACLManager, ICollector} from './AaveV3.sol'; +library AaveV3Ethereum { + // https://etherscan.io/address/0x2f39d218133AFaB8F2B819B1066c7E434Ad94E9e + IPoolAddressesProvider internal constant POOL_ADDRESSES_PROVIDER = + IPoolAddressesProvider(0x2f39d218133AFaB8F2B819B1066c7E434Ad94E9e); + + // https://etherscan.io/address/0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2 + IPool internal constant POOL = IPool(0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2); + + // https://etherscan.io/address/0x64b761D848206f447Fe2dd461b0c635Ec39EbB27 + IPoolConfigurator internal constant POOL_CONFIGURATOR = + IPoolConfigurator(0x64b761D848206f447Fe2dd461b0c635Ec39EbB27); + + // https://etherscan.io/address/0x54586bE62E3c3580375aE3723C145253060Ca0C2 + IAaveOracle internal constant ORACLE = IAaveOracle(0x54586bE62E3c3580375aE3723C145253060Ca0C2); + + // https://etherscan.io/address/0x5300A1a15135EA4dc7aD5a167152C01EFc9b192A + address internal constant ACL_ADMIN = 0x5300A1a15135EA4dc7aD5a167152C01EFc9b192A; + + // https://etherscan.io/address/0xc2aaCf6553D20d1e9d78E365AAba8032af9c85b0 + IACLManager internal constant ACL_MANAGER = + IACLManager(0xc2aaCf6553D20d1e9d78E365AAba8032af9c85b0); + + // https://etherscan.io/address/0x0a16f2FCC0D44FaE41cc54e079281D84A363bECD + IPoolDataProvider internal constant AAVE_PROTOCOL_DATA_PROVIDER = + IPoolDataProvider(0x0a16f2FCC0D44FaE41cc54e079281D84A363bECD); + + // https://etherscan.io/address/0x728a138A4823392C2EFA55e028d434F526fE03CF + address internal constant POOL_IMPL = 0x728a138A4823392C2EFA55e028d434F526fE03CF; + + // https://etherscan.io/address/0xFF42Ce30054dcE7dc7C1282a9a497aa58eaBCe99 + address internal constant POOL_CONFIGURATOR_IMPL = 0xFF42Ce30054dcE7dc7C1282a9a497aa58eaBCe99; + + // https://etherscan.io/address/0x8164Cc65827dcFe994AB23944CBC90e0aa80bFcb + address internal constant DEFAULT_INCENTIVES_CONTROLLER = + 0x8164Cc65827dcFe994AB23944CBC90e0aa80bFcb; + + // https://etherscan.io/address/0x223d844fc4B006D67c0cDbd39371A9F73f69d974 + address internal constant EMISSION_MANAGER = 0x223d844fc4B006D67c0cDbd39371A9F73f69d974; + + // https://etherscan.io/address/0x464C71f6c2F760DdA6093dCB91C24c39e5d6e18c + ICollector internal constant COLLECTOR = ICollector(0x464C71f6c2F760DdA6093dCB91C24c39e5d6e18c); + + // https://etherscan.io/address/0xadC45Df3cf1584624C97338BEF33363BF5b97AdA + address internal constant DEFAULT_A_TOKEN_IMPL = 0xadC45Df3cf1584624C97338BEF33363BF5b97AdA; + + // https://etherscan.io/address/0xb27C52c7f84819e3157993489741cB60786aE330 + address internal constant DEFAULT_VARIABLE_DEBT_TOKEN_IMPL = + 0xb27C52c7f84819e3157993489741cB60786aE330; + + // https://etherscan.io/address/0x13a9CC64344b02bACC5AD9Cf38B5711F1B9ec3d4 + address internal constant RISK_STEWARD = 0x13a9CC64344b02bACC5AD9Cf38B5711F1B9ec3d4; + + // https://etherscan.io/address/0x47c71dFEB55Ebaa431Ae3fbF99Ea50e0D3d30fA8 + address internal constant RISK_COUNCIL = 0x47c71dFEB55Ebaa431Ae3fbF99Ea50e0D3d30fA8; + + // https://etherscan.io/address/0xd7852E139a7097E119623de0751AE53a61efb442 + address internal constant DEBT_SWAP_ADAPTER = 0xd7852E139a7097E119623de0751AE53a61efb442; + + // https://etherscan.io/address/0x21714092D90c7265F52fdfDae068EC11a23C6248 + address internal constant DELEGATION_AWARE_A_TOKEN_IMPL_REV_1 = + 0x21714092D90c7265F52fdfDae068EC11a23C6248; + + // https://etherscan.io/address/0xEaFAeFa93c6aaBd5ab7E76F4c37Aebe9da1e8318 + address internal constant CONFIG_ENGINE = 0xEaFAeFa93c6aaBd5ab7E76F4c37Aebe9da1e8318; + + // https://etherscan.io/address/0xbaA999AC55EAce41CcAE355c77809e68Bb345170 + address internal constant POOL_ADDRESSES_PROVIDER_REGISTRY = + 0xbaA999AC55EAce41CcAE355c77809e68Bb345170; + + // https://etherscan.io/address/0x35bb522b102326ea3F1141661dF4626C87000e3E + address internal constant REPAY_WITH_COLLATERAL_ADAPTER = + 0x35bb522b102326ea3F1141661dF4626C87000e3E; + + // https://etherscan.io/address/0x411D79b8cC43384FDE66CaBf9b6a17180c842511 + address internal constant LEGACY_STATIC_A_TOKEN_FACTORY = + 0x411D79b8cC43384FDE66CaBf9b6a17180c842511; + + // https://etherscan.io/address/0xADC0A53095A0af87F3aa29FE0715B5c28016364e + address internal constant SWAP_COLLATERAL_ADAPTER = 0xADC0A53095A0af87F3aa29FE0715B5c28016364e; + + // https://etherscan.io/address/0xe3dFf4052F0bF6134ACb73bEaE8fe2317d71F047 + address internal constant UI_INCENTIVE_DATA_PROVIDER = 0xe3dFf4052F0bF6134ACb73bEaE8fe2317d71F047; + + // https://etherscan.io/address/0x2dAd8162A989cd99D673dE4425Bb2298Db1E1aA2 + address internal constant UI_POOL_DATA_PROVIDER = 0x2dAd8162A989cd99D673dE4425Bb2298Db1E1aA2; + + // https://etherscan.io/address/0xC7be5307ba715ce89b152f3Df0658295b3dbA8E2 + address internal constant WALLET_BALANCE_PROVIDER = 0xC7be5307ba715ce89b152f3Df0658295b3dbA8E2; + + // https://etherscan.io/address/0xd01607c3C5eCABa394D8be377a08590149325722 + address internal constant WETH_GATEWAY = 0xd01607c3C5eCABa394D8be377a08590149325722; + + // https://etherscan.io/address/0x78F8Bd884C3D738B74B420540659c82f392820e0 + address internal constant WITHDRAW_SWAP_ADAPTER = 0x78F8Bd884C3D738B74B420540659c82f392820e0; + + // https://etherscan.io/address/0xE28E2c8d240dd5eBd0adcab86fbD79df7a052034 + address internal constant SAVINGS_DAI_TOKEN_WRAPPER = 0xE28E2c8d240dd5eBd0adcab86fbD79df7a052034; + + // https://etherscan.io/address/0xCb0b5cA20b6C5C02A9A3B2cE433650768eD2974F + address internal constant STATA_FACTORY = 0xCb0b5cA20b6C5C02A9A3B2cE433650768eD2974F; + + // https://etherscan.io/address/0x5513224daaEABCa31af5280727878d52097afA05 + address internal constant GHO_DIRECT_MINTER = 0x5513224daaEABCa31af5280727878d52097afA05; + + // https://etherscan.io/address/0x31a0Ba3C2242a095dBF58A7C53751eCBd27dBA9b + address internal constant DUST_BIN = 0x31a0Ba3C2242a095dBF58A7C53751eCBd27dBA9b; + + // https://etherscan.io/address/0xf00E2de0E78DFf055A92AD4719a179CE275b6Ef7 + address internal constant CLINIC_STEWARD = 0xf00E2de0E78DFf055A92AD4719a179CE275b6Ef7; + + // https://etherscan.io/address/0x8b493f416F5F7933cC146b1899c069F2361cad60 + address internal constant SVR_STEWARD = 0x8b493f416F5F7933cC146b1899c069F2361cad60; + + // https://etherscan.io/address/0x22aC12a6937BBBC0a301AF9154d08EaD95673122 + address internal constant POOL_EXPOSURE_STEWARD = 0x22aC12a6937BBBC0a301AF9154d08EaD95673122; + + // https://etherscan.io/address/0x7ABB46C690C52E919687D19ebF89C81A6136C1F2 + address internal constant EDGE_RISK_ORACLE = 0x7ABB46C690C52E919687D19ebF89C81A6136C1F2; + + // https://etherscan.io/address/0xf721bE7AA57a987F3e4D05DAc6fcb5aBF9F7cE9A + address internal constant EDGE_RISK_STEWARD_PENDLE_EMODE = + 0xf721bE7AA57a987F3e4D05DAc6fcb5aBF9F7cE9A; + + // https://etherscan.io/address/0x9F76954f5b55B4908d178f31C07F9537AC8328E7 + address internal constant EDGE_RISK_STEWARD_DISCOUNT_RATE = + 0x9F76954f5b55B4908d178f31C07F9537AC8328E7; + + // https://etherscan.io/address/0x83ab600cE8a61b43e1757b89C0589928f765c1C4 + address internal constant EDGE_INJECTOR_PENDLE_EMODE = 0x83ab600cE8a61b43e1757b89C0589928f765c1C4; + + // https://etherscan.io/address/0x15885A83936EB943e98EeFFb91e9A49040d93993 + address internal constant EDGE_INJECTOR_DISCOUNT_RATE = + 0x15885A83936EB943e98EeFFb91e9A49040d93993; + + // https://etherscan.io/address/0x80CFd14236409107c220d1D0a3dE845b48fdcDfc + address internal constant EDGE_RISK_STEWARD_RATES = 0x80CFd14236409107c220d1D0a3dE845b48fdcDfc; + + // https://etherscan.io/address/0x74dc6321A338420238CBD77abA5fEa8679393A66 + address internal constant EDGE_INJECTOR_RATES = 0x74dc6321A338420238CBD77abA5fEa8679393A66; + + // https://etherscan.io/address/0xb7D402138Cb01BfE97d95181C849379d6AD14d19 + address internal constant COLLECTOR_SWAP_STEWARD = 0xb7D402138Cb01BfE97d95181C849379d6AD14d19; +} +library AaveV3EthereumAssets { + // https://etherscan.io/address/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 + address internal constant WETH_UNDERLYING = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; + + uint8 internal constant WETH_DECIMALS = 18; + + // https://etherscan.io/address/0x4d5F47FA6A74757f35C14fD3a6Ef8E3C9BC514E8 + address internal constant WETH_A_TOKEN = 0x4d5F47FA6A74757f35C14fD3a6Ef8E3C9BC514E8; + + // https://etherscan.io/address/0xeA51d7853EEFb32b6ee06b1C12E6dcCA88Be0fFE + address internal constant WETH_V_TOKEN = 0xeA51d7853EEFb32b6ee06b1C12E6dcCA88Be0fFE; + + // https://etherscan.io/address/0x5424384B256154046E9667dDFaaa5e550145215e + address internal constant WETH_ORACLE = 0x5424384B256154046E9667dDFaaa5e550145215e; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant WETH_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0x252231882FB38481497f3C767469106297c8d93b + address internal constant WETH_STATIC_A_TOKEN = 0x252231882FB38481497f3C767469106297c8d93b; + + // https://etherscan.io/address/0x0bfc9d54Fc184518A81162F8fB99c2eACa081202 + address internal constant WETH_STATA_TOKEN = 0x0bfc9d54Fc184518A81162F8fB99c2eACa081202; + + // https://etherscan.io/address/0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0 + address internal constant wstETH_UNDERLYING = 0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0; + + uint8 internal constant wstETH_DECIMALS = 18; + + // https://etherscan.io/address/0x0B925eD163218f6662a35e0f0371Ac234f9E9371 + address internal constant wstETH_A_TOKEN = 0x0B925eD163218f6662a35e0f0371Ac234f9E9371; + + // https://etherscan.io/address/0xC96113eED8cAB59cD8A66813bCB0cEb29F06D2e4 + address internal constant wstETH_V_TOKEN = 0xC96113eED8cAB59cD8A66813bCB0cEb29F06D2e4; + + // https://etherscan.io/address/0xe1D97bF61901B075E9626c8A2340a7De385861Ef + address internal constant wstETH_ORACLE = 0xe1D97bF61901B075E9626c8A2340a7De385861Ef; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant wstETH_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0x322AA5F5Be95644d6c36544B6c5061F072D16DF5 + address internal constant wstETH_STATIC_A_TOKEN = 0x322AA5F5Be95644d6c36544B6c5061F072D16DF5; + + // https://etherscan.io/address/0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599 + address internal constant WBTC_UNDERLYING = 0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599; + + uint8 internal constant WBTC_DECIMALS = 8; + + // https://etherscan.io/address/0x5Ee5bf7ae06D1Be5997A1A72006FE6C607eC6DE8 + address internal constant WBTC_A_TOKEN = 0x5Ee5bf7ae06D1Be5997A1A72006FE6C607eC6DE8; + + // https://etherscan.io/address/0x40aAbEf1aa8f0eEc637E0E7d92fbfFB2F26A8b7B + address internal constant WBTC_V_TOKEN = 0x40aAbEf1aa8f0eEc637E0E7d92fbfFB2F26A8b7B; + + // https://etherscan.io/address/0xDaa4B74C6bAc4e25188e64ebc68DB5050b690cAc + address internal constant WBTC_ORACLE = 0xDaa4B74C6bAc4e25188e64ebc68DB5050b690cAc; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant WBTC_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0xB07E357cc262E92eee03D8B81464D596B258eA7a + address internal constant WBTC_STATIC_A_TOKEN = 0xB07E357cc262E92eee03D8B81464D596B258eA7a; + + // https://etherscan.io/address/0x2A5D51e22A8010701674E0c3D45E9aCf7b9C8a62 + address internal constant WBTC_STATA_TOKEN = 0x2A5D51e22A8010701674E0c3D45E9aCf7b9C8a62; + + // https://etherscan.io/address/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 + address internal constant USDC_UNDERLYING = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; + + uint8 internal constant USDC_DECIMALS = 6; + + // https://etherscan.io/address/0x98C23E9d8f34FEFb1B7BD6a91B7FF122F4e16F5c + address internal constant USDC_A_TOKEN = 0x98C23E9d8f34FEFb1B7BD6a91B7FF122F4e16F5c; + + // https://etherscan.io/address/0x72E95b8931767C79bA4EeE721354d6E99a61D004 + address internal constant USDC_V_TOKEN = 0x72E95b8931767C79bA4EeE721354d6E99a61D004; + + // https://etherscan.io/address/0x3f73F03aa83B2A48ed27E964eD0fDb590332095B + address internal constant USDC_ORACLE = 0x3f73F03aa83B2A48ed27E964eD0fDb590332095B; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant USDC_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0x73edDFa87C71ADdC275c2b9890f5c3a8480bC9E6 + address internal constant USDC_STATIC_A_TOKEN = 0x73edDFa87C71ADdC275c2b9890f5c3a8480bC9E6; + + // https://etherscan.io/address/0xD4fa2D31b7968E448877f69A96DE69f5de8cD23E + address internal constant USDC_STATA_TOKEN = 0xD4fa2D31b7968E448877f69A96DE69f5de8cD23E; + + // https://etherscan.io/address/0x6B175474E89094C44Da98b954EedeAC495271d0F + address internal constant DAI_UNDERLYING = 0x6B175474E89094C44Da98b954EedeAC495271d0F; + + uint8 internal constant DAI_DECIMALS = 18; + + // https://etherscan.io/address/0x018008bfb33d285247A21d44E50697654f754e63 + address internal constant DAI_A_TOKEN = 0x018008bfb33d285247A21d44E50697654f754e63; + + // https://etherscan.io/address/0xcF8d0c70c850859266f5C338b38F9D663181C314 + address internal constant DAI_V_TOKEN = 0xcF8d0c70c850859266f5C338b38F9D663181C314; + + // https://etherscan.io/address/0x5c66322CA59bB61e867B28195576DbD8dA4b08dE + address internal constant DAI_ORACLE = 0x5c66322CA59bB61e867B28195576DbD8dA4b08dE; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant DAI_INTEREST_RATE_STRATEGY = 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0xaf270C38fF895EA3f95Ed488CEACe2386F038249 + address internal constant DAI_STATIC_A_TOKEN = 0xaf270C38fF895EA3f95Ed488CEACe2386F038249; + + // https://etherscan.io/address/0x5caF5a86f39073637Ac7c8A7b5290871de80cb9b + address internal constant DAI_STATA_TOKEN = 0x5caF5a86f39073637Ac7c8A7b5290871de80cb9b; + + // https://etherscan.io/address/0x514910771AF9Ca656af840dff83E8264EcF986CA + address internal constant LINK_UNDERLYING = 0x514910771AF9Ca656af840dff83E8264EcF986CA; + + uint8 internal constant LINK_DECIMALS = 18; + + // https://etherscan.io/address/0x5E8C8A7243651DB1384C0dDfDbE39761E8e7E51a + address internal constant LINK_A_TOKEN = 0x5E8C8A7243651DB1384C0dDfDbE39761E8e7E51a; + + // https://etherscan.io/address/0x4228F8895C7dDA20227F6a5c6751b8Ebf19a6ba8 + address internal constant LINK_V_TOKEN = 0x4228F8895C7dDA20227F6a5c6751b8Ebf19a6ba8; + + // https://etherscan.io/address/0xC7e9b623ed51F033b32AE7f1282b1AD62C28C183 + address internal constant LINK_ORACLE = 0xC7e9b623ed51F033b32AE7f1282b1AD62C28C183; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant LINK_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0x57bd8C73838d1781b4f6E0d5Cf89eb676488d3df + address internal constant LINK_STATIC_A_TOKEN = 0x57bd8C73838d1781b4f6E0d5Cf89eb676488d3df; + + // https://etherscan.io/address/0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9 + address internal constant AAVE_UNDERLYING = 0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9; + + uint8 internal constant AAVE_DECIMALS = 18; + + // https://etherscan.io/address/0xA700b4eB416Be35b2911fd5Dee80678ff64fF6C9 + address internal constant AAVE_A_TOKEN = 0xA700b4eB416Be35b2911fd5Dee80678ff64fF6C9; + + // https://etherscan.io/address/0xBae535520Abd9f8C85E58929e0006A2c8B372F74 + address internal constant AAVE_V_TOKEN = 0xBae535520Abd9f8C85E58929e0006A2c8B372F74; + + // https://etherscan.io/address/0xF02C1e2A3B77c1cacC72f72B44f7d0a4c62e4a85 + address internal constant AAVE_ORACLE = 0xF02C1e2A3B77c1cacC72f72B44f7d0a4c62e4a85; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant AAVE_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0xFEB859A50f92C6D5ad7C9eF7C2c060D164B3280f + address internal constant AAVE_STATIC_A_TOKEN = 0xFEB859A50f92C6D5ad7C9eF7C2c060D164B3280f; + + // https://etherscan.io/address/0xBe9895146f7AF43049ca1c1AE358B0541Ea49704 + address internal constant cbETH_UNDERLYING = 0xBe9895146f7AF43049ca1c1AE358B0541Ea49704; + + uint8 internal constant cbETH_DECIMALS = 18; + + // https://etherscan.io/address/0x977b6fc5dE62598B08C85AC8Cf2b745874E8b78c + address internal constant cbETH_A_TOKEN = 0x977b6fc5dE62598B08C85AC8Cf2b745874E8b78c; + + // https://etherscan.io/address/0x0c91bcA95b5FE69164cE583A2ec9429A569798Ed + address internal constant cbETH_V_TOKEN = 0x0c91bcA95b5FE69164cE583A2ec9429A569798Ed; + + // https://etherscan.io/address/0x889399C34461b25d70d43931e6cE9E40280E617B + address internal constant cbETH_ORACLE = 0x889399C34461b25d70d43931e6cE9E40280E617B; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant cbETH_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0xe2a6863C8f043457B497667Ef3c43073e2D69089 + address internal constant cbETH_STATIC_A_TOKEN = 0xe2a6863C8f043457B497667Ef3c43073e2D69089; + + // https://etherscan.io/address/0xdAC17F958D2ee523a2206206994597C13D831ec7 + address internal constant USDT_UNDERLYING = 0xdAC17F958D2ee523a2206206994597C13D831ec7; + + uint8 internal constant USDT_DECIMALS = 6; + + // https://etherscan.io/address/0x23878914EFE38d27C4D67Ab83ed1b93A74D4086a + address internal constant USDT_A_TOKEN = 0x23878914EFE38d27C4D67Ab83ed1b93A74D4086a; + + // https://etherscan.io/address/0x6df1C1E379bC5a00a7b4C6e67A203333772f45A8 + address internal constant USDT_V_TOKEN = 0x6df1C1E379bC5a00a7b4C6e67A203333772f45A8; + + // https://etherscan.io/address/0x260326c220E469358846b187eE53328303Efe19C + address internal constant USDT_ORACLE = 0x260326c220E469358846b187eE53328303Efe19C; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant USDT_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0x862c57d48becB45583AEbA3f489696D22466Ca1b + address internal constant USDT_STATIC_A_TOKEN = 0x862c57d48becB45583AEbA3f489696D22466Ca1b; + + // https://etherscan.io/address/0x7Bc3485026Ac48b6cf9BaF0A377477Fff5703Af8 + address internal constant USDT_STATA_TOKEN = 0x7Bc3485026Ac48b6cf9BaF0A377477Fff5703Af8; + + // https://etherscan.io/address/0xae78736Cd615f374D3085123A210448E74Fc6393 + address internal constant rETH_UNDERLYING = 0xae78736Cd615f374D3085123A210448E74Fc6393; + + uint8 internal constant rETH_DECIMALS = 18; + + // https://etherscan.io/address/0xCc9EE9483f662091a1de4795249E24aC0aC2630f + address internal constant rETH_A_TOKEN = 0xCc9EE9483f662091a1de4795249E24aC0aC2630f; + + // https://etherscan.io/address/0xae8593DD575FE29A9745056aA91C4b746eee62C8 + address internal constant rETH_V_TOKEN = 0xae8593DD575FE29A9745056aA91C4b746eee62C8; + + // https://etherscan.io/address/0x6929706c42d637DF5Ebf7F0BcfF2aF47F84Ea69D + address internal constant rETH_ORACLE = 0x6929706c42d637DF5Ebf7F0BcfF2aF47F84Ea69D; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant rETH_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0x867Cf025B5dA438c4e215c60B59bBB3aFe896Fda + address internal constant rETH_STATIC_A_TOKEN = 0x867Cf025B5dA438c4e215c60B59bBB3aFe896Fda; + + // https://etherscan.io/address/0x5f98805A4E8be255a32880FDeC7F6728C6568bA0 + address internal constant LUSD_UNDERLYING = 0x5f98805A4E8be255a32880FDeC7F6728C6568bA0; + + uint8 internal constant LUSD_DECIMALS = 18; + + // https://etherscan.io/address/0x3Fe6a295459FAe07DF8A0ceCC36F37160FE86AA9 + address internal constant LUSD_A_TOKEN = 0x3Fe6a295459FAe07DF8A0ceCC36F37160FE86AA9; + + // https://etherscan.io/address/0x33652e48e4B74D18520f11BfE58Edd2ED2cEc5A2 + address internal constant LUSD_V_TOKEN = 0x33652e48e4B74D18520f11BfE58Edd2ED2cEc5A2; + + // https://etherscan.io/address/0xc6E7e1ff334313CeBDe98b7a8A487119CFb6e654 + address internal constant LUSD_ORACLE = 0xc6E7e1ff334313CeBDe98b7a8A487119CFb6e654; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant LUSD_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0xDBf5E36569798D1E39eE9d7B1c61A7409a74F23A + address internal constant LUSD_STATIC_A_TOKEN = 0xDBf5E36569798D1E39eE9d7B1c61A7409a74F23A; + + // https://etherscan.io/address/0xD533a949740bb3306d119CC777fa900bA034cd52 + address internal constant CRV_UNDERLYING = 0xD533a949740bb3306d119CC777fa900bA034cd52; + + uint8 internal constant CRV_DECIMALS = 18; + + // https://etherscan.io/address/0x7B95Ec873268a6BFC6427e7a28e396Db9D0ebc65 + address internal constant CRV_A_TOKEN = 0x7B95Ec873268a6BFC6427e7a28e396Db9D0ebc65; + + // https://etherscan.io/address/0x1b7D3F4b3c032a5AE656e30eeA4e8E1Ba376068F + address internal constant CRV_V_TOKEN = 0x1b7D3F4b3c032a5AE656e30eeA4e8E1Ba376068F; + + // https://etherscan.io/address/0xCd627aA160A6fA45Eb793D19Ef54f5062F20f33f + address internal constant CRV_ORACLE = 0xCd627aA160A6fA45Eb793D19Ef54f5062F20f33f; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant CRV_INTEREST_RATE_STRATEGY = 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0x149EE12310D499F701B6A5714eDAd2C832008fd2 + address internal constant CRV_STATIC_A_TOKEN = 0x149EE12310D499F701B6A5714eDAd2C832008fd2; + + // https://etherscan.io/address/0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2 + address internal constant MKR_UNDERLYING = 0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2; + + uint8 internal constant MKR_DECIMALS = 18; + + // https://etherscan.io/address/0x8A458A9dc9048e005d22849F470891b840296619 + address internal constant MKR_A_TOKEN = 0x8A458A9dc9048e005d22849F470891b840296619; + + // https://etherscan.io/address/0x6Efc73E54E41b27d2134fF9f98F15550f30DF9B1 + address internal constant MKR_V_TOKEN = 0x6Efc73E54E41b27d2134fF9f98F15550f30DF9B1; + + // https://etherscan.io/address/0x44Bb2a64bAf94210B583338D3D97b1e8288Bd478 + address internal constant MKR_ORACLE = 0x44Bb2a64bAf94210B583338D3D97b1e8288Bd478; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant MKR_INTEREST_RATE_STRATEGY = 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F + address internal constant SNX_UNDERLYING = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F; + + uint8 internal constant SNX_DECIMALS = 18; + + // https://etherscan.io/address/0xC7B4c17861357B8ABB91F25581E7263E08DCB59c + address internal constant SNX_A_TOKEN = 0xC7B4c17861357B8ABB91F25581E7263E08DCB59c; + + // https://etherscan.io/address/0x8d0de040e8aAd872eC3c33A3776dE9152D3c34ca + address internal constant SNX_V_TOKEN = 0x8d0de040e8aAd872eC3c33A3776dE9152D3c34ca; + + // https://etherscan.io/address/0xDC3EA94CD0AC27d9A86C180091e7f78C683d3699 + address internal constant SNX_ORACLE = 0xDC3EA94CD0AC27d9A86C180091e7f78C683d3699; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant SNX_INTEREST_RATE_STRATEGY = 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0xaECEbdfE454d869A626cAb38226C52a1575D1866 + address internal constant SNX_STATIC_A_TOKEN = 0xaECEbdfE454d869A626cAb38226C52a1575D1866; + + // https://etherscan.io/address/0xba100000625a3754423978a60c9317c58a424e3D + address internal constant BAL_UNDERLYING = 0xba100000625a3754423978a60c9317c58a424e3D; + + uint8 internal constant BAL_DECIMALS = 18; + + // https://etherscan.io/address/0x2516E7B3F76294e03C42AA4c5b5b4DCE9C436fB8 + address internal constant BAL_A_TOKEN = 0x2516E7B3F76294e03C42AA4c5b5b4DCE9C436fB8; + + // https://etherscan.io/address/0x3D3efceb4Ff0966D34d9545D3A2fa2dcdBf451f2 + address internal constant BAL_V_TOKEN = 0x3D3efceb4Ff0966D34d9545D3A2fa2dcdBf451f2; + + // https://etherscan.io/address/0xfFa88E79E6be7AB1048F44112f56C8F1Cfc33F66 + address internal constant BAL_ORACLE = 0xfFa88E79E6be7AB1048F44112f56C8F1Cfc33F66; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant BAL_INTEREST_RATE_STRATEGY = 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984 + address internal constant UNI_UNDERLYING = 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984; + + uint8 internal constant UNI_DECIMALS = 18; + + // https://etherscan.io/address/0xF6D2224916DDFbbab6e6bd0D1B7034f4Ae0CaB18 + address internal constant UNI_A_TOKEN = 0xF6D2224916DDFbbab6e6bd0D1B7034f4Ae0CaB18; + + // https://etherscan.io/address/0xF64178Ebd2E2719F2B1233bCb5Ef6DB4bCc4d09a + address internal constant UNI_V_TOKEN = 0xF64178Ebd2E2719F2B1233bCb5Ef6DB4bCc4d09a; + + // https://etherscan.io/address/0x553303d460EE0afB37EdFf9bE42922D8FF63220e + address internal constant UNI_ORACLE = 0x553303d460EE0afB37EdFf9bE42922D8FF63220e; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant UNI_INTEREST_RATE_STRATEGY = 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0x78fb5E79D5cb59729D0cd72bEA7879aD2683454D + address internal constant UNI_STATIC_A_TOKEN = 0x78fb5E79D5cb59729D0cd72bEA7879aD2683454D; + + // https://etherscan.io/address/0x5A98FcBEA516Cf06857215779Fd812CA3beF1B32 + address internal constant LDO_UNDERLYING = 0x5A98FcBEA516Cf06857215779Fd812CA3beF1B32; + + uint8 internal constant LDO_DECIMALS = 18; + + // https://etherscan.io/address/0x9A44fd41566876A39655f74971a3A6eA0a17a454 + address internal constant LDO_A_TOKEN = 0x9A44fd41566876A39655f74971a3A6eA0a17a454; + + // https://etherscan.io/address/0xc30808705C01289A3D306ca9CAB081Ba9114eC82 + address internal constant LDO_V_TOKEN = 0xc30808705C01289A3D306ca9CAB081Ba9114eC82; + + // https://etherscan.io/address/0xb01e6C9af83879B8e06a092f0DD94309c0D497E4 + address internal constant LDO_ORACLE = 0xb01e6C9af83879B8e06a092f0DD94309c0D497E4; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant LDO_INTEREST_RATE_STRATEGY = 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0x1eA6E1ba21601258401d0B9DB24eA0a07948458e + address internal constant LDO_STATIC_A_TOKEN = 0x1eA6E1ba21601258401d0B9DB24eA0a07948458e; + + // https://etherscan.io/address/0xC18360217D8F7Ab5e7c516566761Ea12Ce7F9D72 + address internal constant ENS_UNDERLYING = 0xC18360217D8F7Ab5e7c516566761Ea12Ce7F9D72; + + uint8 internal constant ENS_DECIMALS = 18; + + // https://etherscan.io/address/0x545bD6c032eFdde65A377A6719DEF2796C8E0f2e + address internal constant ENS_A_TOKEN = 0x545bD6c032eFdde65A377A6719DEF2796C8E0f2e; + + // https://etherscan.io/address/0xd180D7fdD4092f07428eFE801E17BC03576b3192 + address internal constant ENS_V_TOKEN = 0xd180D7fdD4092f07428eFE801E17BC03576b3192; + + // https://etherscan.io/address/0x5C00128d4d1c2F4f652C267d7bcdD7aC99C16E16 + address internal constant ENS_ORACLE = 0x5C00128d4d1c2F4f652C267d7bcdD7aC99C16E16; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant ENS_INTEREST_RATE_STRATEGY = 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0x2767C27Eeaf3566082E74b963B6A0f5c9a46C8a1 + address internal constant ENS_STATIC_A_TOKEN = 0x2767C27Eeaf3566082E74b963B6A0f5c9a46C8a1; + + // https://etherscan.io/address/0x111111111117dC0aa78b770fA6A738034120C302 + address internal constant ONE_INCH_UNDERLYING = 0x111111111117dC0aa78b770fA6A738034120C302; + + uint8 internal constant ONE_INCH_DECIMALS = 18; + + // https://etherscan.io/address/0x71Aef7b30728b9BB371578f36c5A1f1502a5723e + address internal constant ONE_INCH_A_TOKEN = 0x71Aef7b30728b9BB371578f36c5A1f1502a5723e; + + // https://etherscan.io/address/0xA38fCa8c6Bf9BdA52E76EB78f08CaA3BE7c5A970 + address internal constant ONE_INCH_V_TOKEN = 0xA38fCa8c6Bf9BdA52E76EB78f08CaA3BE7c5A970; + + // https://etherscan.io/address/0xc929ad75B72593967DE83E7F7Cda0493458261D9 + address internal constant ONE_INCH_ORACLE = 0xc929ad75B72593967DE83E7F7Cda0493458261D9; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant ONE_INCH_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0xB490fF18e55b8881C9527FE7E358dd363780449F + address internal constant ONE_INCH_STATIC_A_TOKEN = 0xB490fF18e55b8881C9527FE7E358dd363780449F; + + // https://etherscan.io/address/0x853d955aCEf822Db058eb8505911ED77F175b99e + address internal constant FRAX_UNDERLYING = 0x853d955aCEf822Db058eb8505911ED77F175b99e; + + uint8 internal constant FRAX_DECIMALS = 18; + + // https://etherscan.io/address/0xd4e245848d6E1220DBE62e155d89fa327E43CB06 + address internal constant FRAX_A_TOKEN = 0xd4e245848d6E1220DBE62e155d89fa327E43CB06; + + // https://etherscan.io/address/0x88B8358F5BC87c2D7E116cCA5b65A9eEb2c5EA3F + address internal constant FRAX_V_TOKEN = 0x88B8358F5BC87c2D7E116cCA5b65A9eEb2c5EA3F; + + // https://etherscan.io/address/0xE7A4a6fCB1E7d5052e64E70aEd37b0fD2548bAE7 + address internal constant FRAX_ORACLE = 0xE7A4a6fCB1E7d5052e64E70aEd37b0fD2548bAE7; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant FRAX_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0xEE66abD4D0f9908A48E08AE354B0f425De3e237E + address internal constant FRAX_STATIC_A_TOKEN = 0xEE66abD4D0f9908A48E08AE354B0f425De3e237E; + + // https://etherscan.io/address/0x40D16FC0246aD3160Ccc09B8D0D3A2cD28aE6C2f + address internal constant GHO_UNDERLYING = 0x40D16FC0246aD3160Ccc09B8D0D3A2cD28aE6C2f; + + uint8 internal constant GHO_DECIMALS = 18; + + // https://etherscan.io/address/0x00907f9921424583e7ffBfEdf84F92B7B2Be4977 + address internal constant GHO_A_TOKEN = 0x00907f9921424583e7ffBfEdf84F92B7B2Be4977; + + // https://etherscan.io/address/0x786dBff3f1292ae8F92ea68Cf93c30b34B1ed04B + address internal constant GHO_V_TOKEN = 0x786dBff3f1292ae8F92ea68Cf93c30b34B1ed04B; + + // https://etherscan.io/address/0xD110cac5d8682A3b045D5524a9903E031d70FCCd + address internal constant GHO_ORACLE = 0xD110cac5d8682A3b045D5524a9903E031d70FCCd; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant GHO_INTEREST_RATE_STRATEGY = 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0x048459E4fb3402e58d8900aF7283Ad574B91d742 + address internal constant GHO_STATIC_A_TOKEN = 0x048459E4fb3402e58d8900aF7283Ad574B91d742; + + // https://etherscan.io/address/0xD33526068D116cE69F19A9ee46F0bd304F21A51f + address internal constant RPL_UNDERLYING = 0xD33526068D116cE69F19A9ee46F0bd304F21A51f; + + uint8 internal constant RPL_DECIMALS = 18; + + // https://etherscan.io/address/0xB76CF92076adBF1D9C39294FA8e7A67579FDe357 + address internal constant RPL_A_TOKEN = 0xB76CF92076adBF1D9C39294FA8e7A67579FDe357; + + // https://etherscan.io/address/0x8988ECA19D502fd8b9CCd03fA3bD20a6f599bc2A + address internal constant RPL_V_TOKEN = 0x8988ECA19D502fd8b9CCd03fA3bD20a6f599bc2A; + + // https://etherscan.io/address/0x3455c45D29f022Ba9367c2c2Ad95432A5d1E9Ed0 + address internal constant RPL_ORACLE = 0x3455c45D29f022Ba9367c2c2Ad95432A5d1E9Ed0; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant RPL_INTEREST_RATE_STRATEGY = 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0x95EF7cb3494e65dA4926bA330dBf540a13afFD17 + address internal constant RPL_STATIC_A_TOKEN = 0x95EF7cb3494e65dA4926bA330dBf540a13afFD17; + + // https://etherscan.io/address/0x91ad1f5443cF356010D2171D6D26B11C309c4b16 + address internal constant RPL_STATA_TOKEN = 0x91ad1f5443cF356010D2171D6D26B11C309c4b16; + + // https://etherscan.io/address/0x83F20F44975D03b1b09e64809B757c47f942BEeA + address internal constant sDAI_UNDERLYING = 0x83F20F44975D03b1b09e64809B757c47f942BEeA; + + uint8 internal constant sDAI_DECIMALS = 18; + + // https://etherscan.io/address/0x4C612E3B15b96Ff9A6faED838F8d07d479a8dD4c + address internal constant sDAI_A_TOKEN = 0x4C612E3B15b96Ff9A6faED838F8d07d479a8dD4c; + + // https://etherscan.io/address/0x8Db9D35e117d8b93C6Ca9b644b25BaD5d9908141 + address internal constant sDAI_V_TOKEN = 0x8Db9D35e117d8b93C6Ca9b644b25BaD5d9908141; + + // https://etherscan.io/address/0xf83B85205241c3BCCA0a09D32FaE65c16e0CF236 + address internal constant sDAI_ORACLE = 0xf83B85205241c3BCCA0a09D32FaE65c16e0CF236; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant sDAI_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0xFa7E3571786CE9489bBC58d9Cb8ecE8aAe6B56F3 + address internal constant sDAI_STATIC_A_TOKEN = 0xFa7E3571786CE9489bBC58d9Cb8ecE8aAe6B56F3; + + // https://etherscan.io/address/0xAf5191B0De278C7286d6C7CC6ab6BB8A73bA2Cd6 + address internal constant STG_UNDERLYING = 0xAf5191B0De278C7286d6C7CC6ab6BB8A73bA2Cd6; + + uint8 internal constant STG_DECIMALS = 18; + + // https://etherscan.io/address/0x1bA9843bD4327c6c77011406dE5fA8749F7E3479 + address internal constant STG_A_TOKEN = 0x1bA9843bD4327c6c77011406dE5fA8749F7E3479; + + // https://etherscan.io/address/0x655568bDd6168325EC7e58Bf39b21A856F906Dc2 + address internal constant STG_V_TOKEN = 0x655568bDd6168325EC7e58Bf39b21A856F906Dc2; + + // https://etherscan.io/address/0x30efE459B6A08a8E92b41e0563bdB15a29DA377e + address internal constant STG_ORACLE = 0x30efE459B6A08a8E92b41e0563bdB15a29DA377e; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant STG_INTEREST_RATE_STRATEGY = 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0xdeFA4e8a7bcBA345F687a2f1456F5Edd9CE97202 + address internal constant KNC_UNDERLYING = 0xdeFA4e8a7bcBA345F687a2f1456F5Edd9CE97202; + + uint8 internal constant KNC_DECIMALS = 18; + + // https://etherscan.io/address/0x5b502e3796385E1e9755d7043B9C945C3aCCeC9C + address internal constant KNC_A_TOKEN = 0x5b502e3796385E1e9755d7043B9C945C3aCCeC9C; + + // https://etherscan.io/address/0x253127Ffc04981cEA8932F406710661c2f2c3fD2 + address internal constant KNC_V_TOKEN = 0x253127Ffc04981cEA8932F406710661c2f2c3fD2; + + // https://etherscan.io/address/0xfbBa1Fd5dFce36860e46738dc9b83bb0A99551e2 + address internal constant KNC_ORACLE = 0xfbBa1Fd5dFce36860e46738dc9b83bb0A99551e2; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant KNC_INTEREST_RATE_STRATEGY = 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0x3432B6A60D23Ca0dFCa7761B7ab56459D9C964D0 + address internal constant FXS_UNDERLYING = 0x3432B6A60D23Ca0dFCa7761B7ab56459D9C964D0; + + uint8 internal constant FXS_DECIMALS = 18; + + // https://etherscan.io/address/0x82F9c5ad306BBa1AD0De49bB5FA6F01bf61085ef + address internal constant FXS_A_TOKEN = 0x82F9c5ad306BBa1AD0De49bB5FA6F01bf61085ef; + + // https://etherscan.io/address/0x68e9f0aD4e6f8F5DB70F6923d4d6d5b225B83b16 + address internal constant FXS_V_TOKEN = 0x68e9f0aD4e6f8F5DB70F6923d4d6d5b225B83b16; + + // https://etherscan.io/address/0x4124b23341FcEa31CF098FE9d801D59BB9F4B3F7 + address internal constant FXS_ORACLE = 0x4124b23341FcEa31CF098FE9d801D59BB9F4B3F7; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant FXS_INTEREST_RATE_STRATEGY = 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0xf939E0A03FB07F59A73314E73794Be0E57ac1b4E + address internal constant crvUSD_UNDERLYING = 0xf939E0A03FB07F59A73314E73794Be0E57ac1b4E; + + uint8 internal constant crvUSD_DECIMALS = 18; + + // https://etherscan.io/address/0xb82fa9f31612989525992FCfBB09AB22Eff5c85A + address internal constant crvUSD_A_TOKEN = 0xb82fa9f31612989525992FCfBB09AB22Eff5c85A; + + // https://etherscan.io/address/0x028f7886F3e937f8479efaD64f31B3fE1119857a + address internal constant crvUSD_V_TOKEN = 0x028f7886F3e937f8479efaD64f31B3fE1119857a; + + // https://etherscan.io/address/0x9Dc30dc58c72f5B669aEa01d02A2e4da194eE893 + address internal constant crvUSD_ORACLE = 0x9Dc30dc58c72f5B669aEa01d02A2e4da194eE893; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant crvUSD_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0x848107491E029AFDe0AC543779c7790382f15929 + address internal constant crvUSD_STATIC_A_TOKEN = 0x848107491E029AFDe0AC543779c7790382f15929; + + // https://etherscan.io/address/0x6c3ea9036406852006290770BEdFcAbA0e23A0e8 + address internal constant PYUSD_UNDERLYING = 0x6c3ea9036406852006290770BEdFcAbA0e23A0e8; + + uint8 internal constant PYUSD_DECIMALS = 6; + + // https://etherscan.io/address/0x0C0d01AbF3e6aDfcA0989eBbA9d6e85dD58EaB1E + address internal constant PYUSD_A_TOKEN = 0x0C0d01AbF3e6aDfcA0989eBbA9d6e85dD58EaB1E; + + // https://etherscan.io/address/0x57B67e4DE077085Fd0AF2174e9c14871BE664546 + address internal constant PYUSD_V_TOKEN = 0x57B67e4DE077085Fd0AF2174e9c14871BE664546; + + // https://etherscan.io/address/0x36964C0579D02E0a5AaAb89E24Cf8d7CDF3549EE + address internal constant PYUSD_ORACLE = 0x36964C0579D02E0a5AaAb89E24Cf8d7CDF3549EE; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant PYUSD_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0x00F2a835758B33f3aC53516Ebd69f3dc77B0D152 + address internal constant PYUSD_STATIC_A_TOKEN = 0x00F2a835758B33f3aC53516Ebd69f3dc77B0D152; + + // https://etherscan.io/address/0xb51EDdDD8c47856D81C8681EA71404Cec93E92c6 + address internal constant PYUSD_STATA_TOKEN = 0xb51EDdDD8c47856D81C8681EA71404Cec93E92c6; + + // https://etherscan.io/address/0xCd5fE23C85820F7B72D0926FC9b05b43E359b7ee + address internal constant weETH_UNDERLYING = 0xCd5fE23C85820F7B72D0926FC9b05b43E359b7ee; + + uint8 internal constant weETH_DECIMALS = 18; + + // https://etherscan.io/address/0xBdfa7b7893081B35Fb54027489e2Bc7A38275129 + address internal constant weETH_A_TOKEN = 0xBdfa7b7893081B35Fb54027489e2Bc7A38275129; + + // https://etherscan.io/address/0x77ad9BF13a52517AD698D65913e8D381300c8Bf3 + address internal constant weETH_V_TOKEN = 0x77ad9BF13a52517AD698D65913e8D381300c8Bf3; + + // https://etherscan.io/address/0x87625393534d5C102cADB66D37201dF24cc26d4C + address internal constant weETH_ORACLE = 0x87625393534d5C102cADB66D37201dF24cc26d4C; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant weETH_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0x867b0CDC4B39a19945E616c29639b0390b39db3B + address internal constant weETH_STATIC_A_TOKEN = 0x867b0CDC4B39a19945E616c29639b0390b39db3B; + + // https://etherscan.io/address/0xf1C9acDc66974dFB6dEcB12aA385b9cD01190E38 + address internal constant osETH_UNDERLYING = 0xf1C9acDc66974dFB6dEcB12aA385b9cD01190E38; + + uint8 internal constant osETH_DECIMALS = 18; + + // https://etherscan.io/address/0x927709711794F3De5DdBF1D176bEE2D55Ba13c21 + address internal constant osETH_A_TOKEN = 0x927709711794F3De5DdBF1D176bEE2D55Ba13c21; + + // https://etherscan.io/address/0x8838eefF2af391863E1Bb8b1dF563F86743a8470 + address internal constant osETH_V_TOKEN = 0x8838eefF2af391863E1Bb8b1dF563F86743a8470; + + // https://etherscan.io/address/0x2b86D519eF34f8Adfc9349CDeA17c09Aa9dB60E2 + address internal constant osETH_ORACLE = 0x2b86D519eF34f8Adfc9349CDeA17c09Aa9dB60E2; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant osETH_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0xE5248968166206d14ab57345971E32facD839aDA + address internal constant osETH_STATIC_A_TOKEN = 0xE5248968166206d14ab57345971E32facD839aDA; + + // https://etherscan.io/address/0x4c9EDD5852cd905f086C759E8383e09bff1E68B3 + address internal constant USDe_UNDERLYING = 0x4c9EDD5852cd905f086C759E8383e09bff1E68B3; + + uint8 internal constant USDe_DECIMALS = 18; + + // https://etherscan.io/address/0x4F5923Fc5FD4a93352581b38B7cD26943012DECF + address internal constant USDe_A_TOKEN = 0x4F5923Fc5FD4a93352581b38B7cD26943012DECF; + + // https://etherscan.io/address/0x015396E1F286289aE23a762088E863b3ec465145 + address internal constant USDe_V_TOKEN = 0x015396E1F286289aE23a762088E863b3ec465145; + + // https://etherscan.io/address/0xC26D4a1c46d884cfF6dE9800B6aE7A8Cf48B4Ff8 + address internal constant USDe_ORACLE = 0xC26D4a1c46d884cfF6dE9800B6aE7A8Cf48B4Ff8; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant USDe_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0x46e5d6A33C8Bd8eD38F3c95991C78C9B2FF3bC99 + address internal constant USDe_STATIC_A_TOKEN = 0x46e5d6A33C8Bd8eD38F3c95991C78C9B2FF3bC99; + + // https://etherscan.io/address/0x5F9D59db355b4A60501544637b00e94082cA575b + address internal constant USDe_STATA_TOKEN = 0x5F9D59db355b4A60501544637b00e94082cA575b; + + // https://etherscan.io/address/0xA35b1B31Ce002FBF2058D22F30f95D405200A15b + address internal constant ETHx_UNDERLYING = 0xA35b1B31Ce002FBF2058D22F30f95D405200A15b; + + uint8 internal constant ETHx_DECIMALS = 18; + + // https://etherscan.io/address/0x1c0E06a0b1A4c160c17545FF2A951bfcA57C0002 + address internal constant ETHx_A_TOKEN = 0x1c0E06a0b1A4c160c17545FF2A951bfcA57C0002; + + // https://etherscan.io/address/0x08a8Dc81AeA67F84745623aC6c72CDA3967aab8b + address internal constant ETHx_V_TOKEN = 0x08a8Dc81AeA67F84745623aC6c72CDA3967aab8b; + + // https://etherscan.io/address/0xd7b163B671f8cE9379DF8Ff7F75fA72Ccec1841c + address internal constant ETHx_ORACLE = 0xd7b163B671f8cE9379DF8Ff7F75fA72Ccec1841c; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant ETHx_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0x7CC6694CF75C18D488d16FB4bf3c71A3B31cc7FB + address internal constant ETHx_STATIC_A_TOKEN = 0x7CC6694CF75C18D488d16FB4bf3c71A3B31cc7FB; + + // https://etherscan.io/address/0x9D39A5DE30e57443BfF2A8307A4256c8797A3497 + address internal constant sUSDe_UNDERLYING = 0x9D39A5DE30e57443BfF2A8307A4256c8797A3497; + + uint8 internal constant sUSDe_DECIMALS = 18; + + // https://etherscan.io/address/0x4579a27aF00A62C0EB156349f31B345c08386419 + address internal constant sUSDe_A_TOKEN = 0x4579a27aF00A62C0EB156349f31B345c08386419; + + // https://etherscan.io/address/0xeFFDE9BFA8EC77c14C364055a200746d6e12BeD6 + address internal constant sUSDe_V_TOKEN = 0xeFFDE9BFA8EC77c14C364055a200746d6e12BeD6; + + // https://etherscan.io/address/0x42bc86f2f08419280a99d8fbEa4672e7c30a86ec + address internal constant sUSDe_ORACLE = 0x42bc86f2f08419280a99d8fbEa4672e7c30a86ec; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant sUSDe_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0x54D612b000697bd8B0094889D7d6A92bA0Bf2DEa + address internal constant sUSDe_STATIC_A_TOKEN = 0x54D612b000697bd8B0094889D7d6A92bA0Bf2DEa; + + // https://etherscan.io/address/0x18084fbA666a33d37592fA2633fD49a74DD93a88 + address internal constant tBTC_UNDERLYING = 0x18084fbA666a33d37592fA2633fD49a74DD93a88; + + uint8 internal constant tBTC_DECIMALS = 18; + + // https://etherscan.io/address/0x10Ac93971cdb1F5c778144084242374473c350Da + address internal constant tBTC_A_TOKEN = 0x10Ac93971cdb1F5c778144084242374473c350Da; + + // https://etherscan.io/address/0xAC50890a80A2731eb1eA2e9B4F29569CeB06D960 + address internal constant tBTC_V_TOKEN = 0xAC50890a80A2731eb1eA2e9B4F29569CeB06D960; + + // https://etherscan.io/address/0xb41E773f507F7a7EA890b1afB7d2b660c30C8B0A + address internal constant tBTC_ORACLE = 0xb41E773f507F7a7EA890b1afB7d2b660c30C8B0A; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant tBTC_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0xcbB7C0000aB88B473b1f5aFd9ef808440eed33Bf + address internal constant cbBTC_UNDERLYING = 0xcbB7C0000aB88B473b1f5aFd9ef808440eed33Bf; + + uint8 internal constant cbBTC_DECIMALS = 8; + + // https://etherscan.io/address/0x5c647cE0Ae10658ec44FA4E11A51c96e94efd1Dd + address internal constant cbBTC_A_TOKEN = 0x5c647cE0Ae10658ec44FA4E11A51c96e94efd1Dd; + + // https://etherscan.io/address/0xeB284A70557EFe3591b9e6D9D720040E02c54a4d + address internal constant cbBTC_V_TOKEN = 0xeB284A70557EFe3591b9e6D9D720040E02c54a4d; + + // https://etherscan.io/address/0xb41E773f507F7a7EA890b1afB7d2b660c30C8B0A + address internal constant cbBTC_ORACLE = 0xb41E773f507F7a7EA890b1afB7d2b660c30C8B0A; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant cbBTC_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0xdC035D45d973E3EC169d2276DDab16f1e407384F + address internal constant USDS_UNDERLYING = 0xdC035D45d973E3EC169d2276DDab16f1e407384F; + + uint8 internal constant USDS_DECIMALS = 18; + + // https://etherscan.io/address/0x32a6268f9Ba3642Dda7892aDd74f1D34469A4259 + address internal constant USDS_A_TOKEN = 0x32a6268f9Ba3642Dda7892aDd74f1D34469A4259; + + // https://etherscan.io/address/0x490E0E6255bF65b43E2e02F7acB783c5e04572Ff + address internal constant USDS_V_TOKEN = 0x490E0E6255bF65b43E2e02F7acB783c5e04572Ff; + + // https://etherscan.io/address/0x94C7FD62fd0506e71d8142E9D36687fC72A86B02 + address internal constant USDS_ORACLE = 0x94C7FD62fd0506e71d8142E9D36687fC72A86B02; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant USDS_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0xb80B3215EA8183a064073f9892eb64236160a4dF + address internal constant USDS_STATA_TOKEN = 0xb80B3215EA8183a064073f9892eb64236160a4dF; + + // https://etherscan.io/address/0xA1290d69c65A6Fe4DF752f95823fae25cB99e5A7 + address internal constant rsETH_UNDERLYING = 0xA1290d69c65A6Fe4DF752f95823fae25cB99e5A7; + + uint8 internal constant rsETH_DECIMALS = 18; + + // https://etherscan.io/address/0x2D62109243b87C4bA3EE7bA1D91B0dD0A074d7b1 + address internal constant rsETH_A_TOKEN = 0x2D62109243b87C4bA3EE7bA1D91B0dD0A074d7b1; + + // https://etherscan.io/address/0x6De3E52A1B7294A34e271a508082b1Ff4a37E30e + address internal constant rsETH_V_TOKEN = 0x6De3E52A1B7294A34e271a508082b1Ff4a37E30e; + + // https://etherscan.io/address/0x7292C95A5f6A501a9c4B34f6393e221F2A0139c3 + address internal constant rsETH_ORACLE = 0x7292C95A5f6A501a9c4B34f6393e221F2A0139c3; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant rsETH_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0x8236a87084f8B84306f72007F36F2618A5634494 + address internal constant LBTC_UNDERLYING = 0x8236a87084f8B84306f72007F36F2618A5634494; + + uint8 internal constant LBTC_DECIMALS = 8; + + // https://etherscan.io/address/0x65906988ADEe75306021C417a1A3458040239602 + address internal constant LBTC_A_TOKEN = 0x65906988ADEe75306021C417a1A3458040239602; + + // https://etherscan.io/address/0x68aeB290C7727D899B47c56d1c96AEAC475cD0dD + address internal constant LBTC_V_TOKEN = 0x68aeB290C7727D899B47c56d1c96AEAC475cD0dD; + + // https://etherscan.io/address/0xf8c04B50499872A5B5137219DEc0F791f7f620D0 + address internal constant LBTC_ORACLE = 0xf8c04B50499872A5B5137219DEc0F791f7f620D0; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant LBTC_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0x657e8C867D8B37dCC18fA4Caead9C45EB088C642 + address internal constant eBTC_UNDERLYING = 0x657e8C867D8B37dCC18fA4Caead9C45EB088C642; + + uint8 internal constant eBTC_DECIMALS = 8; + + // https://etherscan.io/address/0x5fefd7069a7D91d01f269DADE14526CCF3487810 + address internal constant eBTC_A_TOKEN = 0x5fefd7069a7D91d01f269DADE14526CCF3487810; + + // https://etherscan.io/address/0x47eD0509e64615c0d5C6d39AF1B38D02Bc9fE58f + address internal constant eBTC_V_TOKEN = 0x47eD0509e64615c0d5C6d39AF1B38D02Bc9fE58f; + + // https://etherscan.io/address/0x03bB418e89B75407585f8198178f253DA3216218 + address internal constant eBTC_ORACLE = 0x03bB418e89B75407585f8198178f253DA3216218; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant eBTC_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0x8292Bb45bf1Ee4d140127049757C2E0fF06317eD + address internal constant RLUSD_UNDERLYING = 0x8292Bb45bf1Ee4d140127049757C2E0fF06317eD; + + uint8 internal constant RLUSD_DECIMALS = 18; + + // https://etherscan.io/address/0xFa82580c16A31D0c1bC632A36F82e83EfEF3Eec0 + address internal constant RLUSD_A_TOKEN = 0xFa82580c16A31D0c1bC632A36F82e83EfEF3Eec0; + + // https://etherscan.io/address/0xBdFe7aD7976d5d7E0965ea83a81Ca1bCfF7e84a9 + address internal constant RLUSD_V_TOKEN = 0xBdFe7aD7976d5d7E0965ea83a81Ca1bCfF7e84a9; + + // https://etherscan.io/address/0xf0eaC18E908B34770FDEe46d069c846bDa866759 + address internal constant RLUSD_ORACLE = 0xf0eaC18E908B34770FDEe46d069c846bDa866759; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant RLUSD_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0x6A1792a91C08e9f0bFe7a990871B786643237f0F + address internal constant RLUSD_STATA_TOKEN = 0x6A1792a91C08e9f0bFe7a990871B786643237f0F; + + // https://etherscan.io/address/0x50D2C7992b802Eef16c04FeADAB310f31866a545 + address internal constant PT_eUSDE_29MAY2025_UNDERLYING = + 0x50D2C7992b802Eef16c04FeADAB310f31866a545; + + uint8 internal constant PT_eUSDE_29MAY2025_DECIMALS = 18; + + // https://etherscan.io/address/0x4B0821e768Ed9039a70eD1E80E15E76a5bE5Df5F + address internal constant PT_eUSDE_29MAY2025_A_TOKEN = 0x4B0821e768Ed9039a70eD1E80E15E76a5bE5Df5F; + + // https://etherscan.io/address/0x3c20fbFD32243Dd9899301C84bCe17413EeE0A0C + address internal constant PT_eUSDE_29MAY2025_V_TOKEN = 0x3c20fbFD32243Dd9899301C84bCe17413EeE0A0C; + + // https://etherscan.io/address/0x5292AB3292D076271f853Ed8e05e61cc02F0A2C6 + address internal constant PT_eUSDE_29MAY2025_ORACLE = 0x5292AB3292D076271f853Ed8e05e61cc02F0A2C6; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant PT_eUSDE_29MAY2025_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0x3b3fB9C57858EF816833dC91565EFcd85D96f634 + address internal constant PT_sUSDE_31JUL2025_UNDERLYING = + 0x3b3fB9C57858EF816833dC91565EFcd85D96f634; + + uint8 internal constant PT_sUSDE_31JUL2025_DECIMALS = 18; + + // https://etherscan.io/address/0xDE6eF6CB4aBd3A473ffC2942eEf5D84536F8E864 + address internal constant PT_sUSDE_31JUL2025_A_TOKEN = 0xDE6eF6CB4aBd3A473ffC2942eEf5D84536F8E864; + + // https://etherscan.io/address/0x8C6FeaF5d58BA1A6541F9c4aF685f62bFCBaC3b1 + address internal constant PT_sUSDE_31JUL2025_V_TOKEN = 0x8C6FeaF5d58BA1A6541F9c4aF685f62bFCBaC3b1; + + // https://etherscan.io/address/0x759B9B72700A129CD7AD8e53F9c99cb48Fd57105 + address internal constant PT_sUSDE_31JUL2025_ORACLE = 0x759B9B72700A129CD7AD8e53F9c99cb48Fd57105; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant PT_sUSDE_31JUL2025_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0xC139190F447e929f090Edeb554D95AbB8b18aC1C + address internal constant USDtb_UNDERLYING = 0xC139190F447e929f090Edeb554D95AbB8b18aC1C; + + uint8 internal constant USDtb_DECIMALS = 18; + + // https://etherscan.io/address/0xEc4ef66D4fCeEba34aBB4dE69dB391Bc5476ccc8 + address internal constant USDtb_A_TOKEN = 0xEc4ef66D4fCeEba34aBB4dE69dB391Bc5476ccc8; + + // https://etherscan.io/address/0xeA85a065F87FE28Aa8Fbf0D6C7deC472b106252C + address internal constant USDtb_V_TOKEN = 0xeA85a065F87FE28Aa8Fbf0D6C7deC472b106252C; + + // https://etherscan.io/address/0x88025072A7dB6Db5e54E46d43850bb44CA93D6C0 + address internal constant USDtb_ORACLE = 0x88025072A7dB6Db5e54E46d43850bb44CA93D6C0; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant USDtb_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0x2FE4dC166ADbc0B39EdB47F4324F00A7374daBF7 + address internal constant USDtb_STATA_TOKEN = 0x2FE4dC166ADbc0B39EdB47F4324F00A7374daBF7; + + // https://etherscan.io/address/0x917459337CaAC939D41d7493B3999f571D20D667 + address internal constant PT_USDe_31JUL2025_UNDERLYING = + 0x917459337CaAC939D41d7493B3999f571D20D667; + + uint8 internal constant PT_USDe_31JUL2025_DECIMALS = 18; + + // https://etherscan.io/address/0x312ffC57778CEfa11989733e6E08143E7E229c1c + address internal constant PT_USDe_31JUL2025_A_TOKEN = 0x312ffC57778CEfa11989733e6E08143E7E229c1c; + + // https://etherscan.io/address/0xd90DA2Df915B87fE1621A7F2201FbF4ff2cCA031 + address internal constant PT_USDe_31JUL2025_V_TOKEN = 0xd90DA2Df915B87fE1621A7F2201FbF4ff2cCA031; + + // https://etherscan.io/address/0x6b99e86B48Fee533B7Bee602e7959f024051Eca0 + address internal constant PT_USDe_31JUL2025_ORACLE = 0x6b99e86B48Fee533B7Bee602e7959f024051Eca0; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant PT_USDe_31JUL2025_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0x14Bdc3A3AE09f5518b923b69489CBcAfB238e617 + address internal constant PT_eUSDE_14AUG2025_UNDERLYING = + 0x14Bdc3A3AE09f5518b923b69489CBcAfB238e617; + + uint8 internal constant PT_eUSDE_14AUG2025_DECIMALS = 18; + + // https://etherscan.io/address/0x2eDff5AF94334fBd7C38ae318edf1c40e072b73B + address internal constant PT_eUSDE_14AUG2025_A_TOKEN = 0x2eDff5AF94334fBd7C38ae318edf1c40e072b73B; + + // https://etherscan.io/address/0x22517fE16DEd08e52E7EA3423A2EA4995b1f1731 + address internal constant PT_eUSDE_14AUG2025_V_TOKEN = 0x22517fE16DEd08e52E7EA3423A2EA4995b1f1731; + + // https://etherscan.io/address/0x03f9bA9A897241985c1f12bCe97fAC1B0bd4a7A7 + address internal constant PT_eUSDE_14AUG2025_ORACLE = 0x03f9bA9A897241985c1f12bCe97fAC1B0bd4a7A7; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant PT_eUSDE_14AUG2025_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0x90D2af7d622ca3141efA4d8f1F24d86E5974Cc8F + address internal constant eUSDe_UNDERLYING = 0x90D2af7d622ca3141efA4d8f1F24d86E5974Cc8F; + + uint8 internal constant eUSDe_DECIMALS = 18; + + // https://etherscan.io/address/0x5F9190496e0DFC831C3bd307978de4a245E2F5cD + address internal constant eUSDe_A_TOKEN = 0x5F9190496e0DFC831C3bd307978de4a245E2F5cD; + + // https://etherscan.io/address/0x48351fCc9536dA440AE9471220F6dC921b0eB703 + address internal constant eUSDe_V_TOKEN = 0x48351fCc9536dA440AE9471220F6dC921b0eB703; + + // https://etherscan.io/address/0xc7Ad695ac0ae38Ae308640897E51468977A862a2 + address internal constant eUSDe_ORACLE = 0xc7Ad695ac0ae38Ae308640897E51468977A862a2; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant eUSDe_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0xC96dE26018A54D51c097160568752c4E3BD6C364 + address internal constant FBTC_UNDERLYING = 0xC96dE26018A54D51c097160568752c4E3BD6C364; + + uint8 internal constant FBTC_DECIMALS = 8; + + // https://etherscan.io/address/0xcCA43ceF272c30415866914351fdfc3E881bb7c2 + address internal constant FBTC_A_TOKEN = 0xcCA43ceF272c30415866914351fdfc3E881bb7c2; + + // https://etherscan.io/address/0x4A35FD7F93324Cc48bc12190D3F37493437b1Eff + address internal constant FBTC_V_TOKEN = 0x4A35FD7F93324Cc48bc12190D3F37493437b1Eff; + + // https://etherscan.io/address/0xb41E773f507F7a7EA890b1afB7d2b660c30C8B0A + address internal constant FBTC_ORACLE = 0xb41E773f507F7a7EA890b1afB7d2b660c30C8B0A; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant FBTC_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c + address internal constant EURC_UNDERLYING = 0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c; + + uint8 internal constant EURC_DECIMALS = 6; + + // https://etherscan.io/address/0xAA6e91C82942aeAE040303Bf96c15a6dBcB82CA0 + address internal constant EURC_A_TOKEN = 0xAA6e91C82942aeAE040303Bf96c15a6dBcB82CA0; + + // https://etherscan.io/address/0x6c82c66622Eb360FC973D3F492f9D8E9eA538b08 + address internal constant EURC_V_TOKEN = 0x6c82c66622Eb360FC973D3F492f9D8E9eA538b08; + + // https://etherscan.io/address/0xa6aB031A4d189B24628EC9Eb155F0a0f1A0E55a3 + address internal constant EURC_ORACLE = 0xa6aB031A4d189B24628EC9Eb155F0a0f1A0E55a3; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant EURC_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0x476a2D04AB8A7fb93E13aC14f2c077866ff13500 + address internal constant EURC_STATA_TOKEN = 0x476a2D04AB8A7fb93E13aC14f2c077866ff13500; + + // https://etherscan.io/address/0x9F56094C450763769BA0EA9Fe2876070c0fD5F77 + address internal constant PT_sUSDE_25SEP2025_UNDERLYING = + 0x9F56094C450763769BA0EA9Fe2876070c0fD5F77; + + uint8 internal constant PT_sUSDE_25SEP2025_DECIMALS = 18; + + // https://etherscan.io/address/0x5f4a0873a3A02f7C0CB0e13a1d4362a1AD90e751 + address internal constant PT_sUSDE_25SEP2025_A_TOKEN = 0x5f4a0873a3A02f7C0CB0e13a1d4362a1AD90e751; + + // https://etherscan.io/address/0xc9AD8Dd111e6384128146467aAf92B81EC422848 + address internal constant PT_sUSDE_25SEP2025_V_TOKEN = 0xc9AD8Dd111e6384128146467aAf92B81EC422848; + + // https://etherscan.io/address/0x7585693910f39df4959912B27D09EAEef06C1a93 + address internal constant PT_sUSDE_25SEP2025_ORACLE = 0x7585693910f39df4959912B27D09EAEef06C1a93; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant PT_sUSDE_25SEP2025_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0xBC6736d346a5eBC0dEbc997397912CD9b8FAe10a + address internal constant PT_USDe_25SEP2025_UNDERLYING = + 0xBC6736d346a5eBC0dEbc997397912CD9b8FAe10a; + + uint8 internal constant PT_USDe_25SEP2025_DECIMALS = 18; + + // https://etherscan.io/address/0x38A5357Ce55c81add62aBc84Fb32981e2626ADEf + address internal constant PT_USDe_25SEP2025_A_TOKEN = 0x38A5357Ce55c81add62aBc84Fb32981e2626ADEf; + + // https://etherscan.io/address/0x0D8486E1CAbf3C9407B3DdA0cfc4d9C3101fB683 + address internal constant PT_USDe_25SEP2025_V_TOKEN = 0x0D8486E1CAbf3C9407B3DdA0cfc4d9C3101fB683; + + // https://etherscan.io/address/0x8B17C02d22EE7D6B8D6829ceB710A458de41E84a + address internal constant PT_USDe_25SEP2025_ORACLE = 0x8B17C02d22EE7D6B8D6829ceB710A458de41E84a; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant PT_USDe_25SEP2025_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0xD11c452fc99cF405034ee446803b6F6c1F6d5ED8 + address internal constant tETH_UNDERLYING = 0xD11c452fc99cF405034ee446803b6F6c1F6d5ED8; + + uint8 internal constant tETH_DECIMALS = 18; + + // https://etherscan.io/address/0x481a2acf3A72ffDc602A9541896Ca1DB87f86cf7 + address internal constant tETH_A_TOKEN = 0x481a2acf3A72ffDc602A9541896Ca1DB87f86cf7; + + // https://etherscan.io/address/0x7EC9Afe70f8FD603282eBAcbc9058A83623E2899 + address internal constant tETH_V_TOKEN = 0x7EC9Afe70f8FD603282eBAcbc9058A83623E2899; + + // https://etherscan.io/address/0x85968026294b8f8Fb86d6bF3Cda079f9376aD05A + address internal constant tETH_ORACLE = 0x85968026294b8f8Fb86d6bF3Cda079f9376aD05A; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant tETH_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0xbf5495Efe5DB9ce00f80364C8B423567e58d2110 + address internal constant ezETH_UNDERLYING = 0xbf5495Efe5DB9ce00f80364C8B423567e58d2110; + + uint8 internal constant ezETH_DECIMALS = 18; + + // https://etherscan.io/address/0x4E2a4d9B3DF7Aae73b418Bd39F3af9e148E3F479 + address internal constant ezETH_A_TOKEN = 0x4E2a4d9B3DF7Aae73b418Bd39F3af9e148E3F479; + + // https://etherscan.io/address/0x730318dB7b830d324fC3fEDDB1d212Ec64bD3141 + address internal constant ezETH_V_TOKEN = 0x730318dB7b830d324fC3fEDDB1d212Ec64bD3141; + + // https://etherscan.io/address/0xF3d49021fF3bbBFDfC1992A4b09E5D1d141D044C + address internal constant ezETH_ORACLE = 0xF3d49021fF3bbBFDfC1992A4b09E5D1d141D044C; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant ezETH_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0x68749665FF8D2d112Fa859AA293F07A622782F38 + address internal constant XAUt_UNDERLYING = 0x68749665FF8D2d112Fa859AA293F07A622782F38; + + uint8 internal constant XAUt_DECIMALS = 6; + + // https://etherscan.io/address/0x8A2b6f94Ff3A89a03E8c02Ee92b55aF90c9454A2 + address internal constant XAUt_A_TOKEN = 0x8A2b6f94Ff3A89a03E8c02Ee92b55aF90c9454A2; + + // https://etherscan.io/address/0xa665bB258D2a732C170dFD505924214c0b1AC74F + address internal constant XAUt_V_TOKEN = 0xa665bB258D2a732C170dFD505924214c0b1AC74F; + + // https://etherscan.io/address/0x214eD9Da11D2fbe465a6fc601a91E62EbEc1a0D6 + address internal constant XAUt_ORACLE = 0x214eD9Da11D2fbe465a6fc601a91E62EbEc1a0D6; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant XAUt_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0xe6A934089BBEe34F832060CE98848359883749B3 + address internal constant PT_sUSDE_27NOV2025_UNDERLYING = + 0xe6A934089BBEe34F832060CE98848359883749B3; + + uint8 internal constant PT_sUSDE_27NOV2025_DECIMALS = 18; + + // https://etherscan.io/address/0x285866acB0d60105B4Ed350a463361c2d9afA0E2 + address internal constant PT_sUSDE_27NOV2025_A_TOKEN = 0x285866acB0d60105B4Ed350a463361c2d9afA0E2; + + // https://etherscan.io/address/0x690Df181701C11C53EA33bBF303C25834b66bD14 + address internal constant PT_sUSDE_27NOV2025_V_TOKEN = 0x690Df181701C11C53EA33bBF303C25834b66bD14; + + // https://etherscan.io/address/0x8B8B73598a2c4b1de6d3b075618434CfC4826632 + address internal constant PT_sUSDE_27NOV2025_ORACLE = 0x8B8B73598a2c4b1de6d3b075618434CfC4826632; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant PT_sUSDE_27NOV2025_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0x62C6E813b9589C3631Ba0Cdb013acdB8544038B7 + address internal constant PT_USDe_27NOV2025_UNDERLYING = + 0x62C6E813b9589C3631Ba0Cdb013acdB8544038B7; + + uint8 internal constant PT_USDe_27NOV2025_DECIMALS = 18; + + // https://etherscan.io/address/0x38C503a438185cDE29b5cF4dC1442FD6F074F1cc + address internal constant PT_USDe_27NOV2025_A_TOKEN = 0x38C503a438185cDE29b5cF4dC1442FD6F074F1cc; + + // https://etherscan.io/address/0x2CE7e7b238985A8aD3863De03F200B245B0c1216 + address internal constant PT_USDe_27NOV2025_V_TOKEN = 0x2CE7e7b238985A8aD3863De03F200B245B0c1216; + + // https://etherscan.io/address/0x6A196A7B498C4EFBFEfB55364106EC80CceF0C3F + address internal constant PT_USDe_27NOV2025_ORACLE = 0x6A196A7B498C4EFBFEfB55364106EC80CceF0C3F; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant PT_USDe_27NOV2025_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0x1F84a51296691320478c98b8d77f2Bbd17D34350 + address internal constant PT_USDe_5FEB2026_UNDERLYING = + 0x1F84a51296691320478c98b8d77f2Bbd17D34350; + + uint8 internal constant PT_USDe_5FEB2026_DECIMALS = 18; + + // https://etherscan.io/address/0xE728577e9a1Fe7032bc309B4541F58f45443866e + address internal constant PT_USDe_5FEB2026_A_TOKEN = 0xE728577e9a1Fe7032bc309B4541F58f45443866e; + + // https://etherscan.io/address/0x9D244A99801dc05cbC04183769c17056B8A1Ad53 + address internal constant PT_USDe_5FEB2026_V_TOKEN = 0x9D244A99801dc05cbC04183769c17056B8A1Ad53; + + // https://etherscan.io/address/0xc35D319FA5FEc2BBE0eB4d0a826465b60f821F81 + address internal constant PT_USDe_5FEB2026_ORACLE = 0xc35D319FA5FEc2BBE0eB4d0a826465b60f821F81; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant PT_USDe_5FEB2026_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0xE8483517077afa11A9B07f849cee2552f040d7b2 + address internal constant PT_sUSDE_5FEB2026_UNDERLYING = + 0xE8483517077afa11A9B07f849cee2552f040d7b2; + + uint8 internal constant PT_sUSDE_5FEB2026_DECIMALS = 18; + + // https://etherscan.io/address/0xbe54767735fB7Acca2aa7E2d209a6f705073536D + address internal constant PT_sUSDE_5FEB2026_A_TOKEN = 0xbe54767735fB7Acca2aa7E2d209a6f705073536D; + + // https://etherscan.io/address/0xA803414f84fCEF00e745bE7CC2A315908927f15D + address internal constant PT_sUSDE_5FEB2026_V_TOKEN = 0xA803414f84fCEF00e745bE7CC2A315908927f15D; + + // https://etherscan.io/address/0x4e89f87F24C13819bBDDb56f99b38746C91677D8 + address internal constant PT_sUSDE_5FEB2026_ORACLE = 0x4e89f87F24C13819bBDDb56f99b38746C91677D8; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant PT_sUSDE_5FEB2026_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0xacA92E438df0B2401fF60dA7E4337B687a2435DA + address internal constant mUSD_UNDERLYING = 0xacA92E438df0B2401fF60dA7E4337B687a2435DA; + + uint8 internal constant mUSD_DECIMALS = 6; + + // https://etherscan.io/address/0xAa0200d169fF3ba9385c12E073c5d1d30434AE7b + address internal constant mUSD_A_TOKEN = 0xAa0200d169fF3ba9385c12E073c5d1d30434AE7b; + + // https://etherscan.io/address/0xE35e6A0D3AbC28289f5d4C2d262a133Df936b98D + address internal constant mUSD_V_TOKEN = 0xE35e6A0D3AbC28289f5d4C2d262a133Df936b98D; + + // https://etherscan.io/address/0x8adb5187695F773513dEC4b569d21db0341931dA + address internal constant mUSD_ORACLE = 0x8adb5187695F773513dEC4b569d21db0341931dA; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant mUSD_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0x356B8d89c1e1239Cbbb9dE4815c39A1474d5BA7D + address internal constant syrupUSDT_UNDERLYING = 0x356B8d89c1e1239Cbbb9dE4815c39A1474d5BA7D; + + uint8 internal constant syrupUSDT_DECIMALS = 6; + + // https://etherscan.io/address/0x24Ab03a9a5Bc2C49E5523e8d915A3536ac38B91D + address internal constant syrupUSDT_A_TOKEN = 0x24Ab03a9a5Bc2C49E5523e8d915A3536ac38B91D; + + // https://etherscan.io/address/0xAEf73b04654931B94920a3D7AE62032b79fB6d0c + address internal constant syrupUSDT_V_TOKEN = 0xAEf73b04654931B94920a3D7AE62032b79fB6d0c; + + // https://etherscan.io/address/0x982aC260B5a4e5bCAb6A437e79168390cFbDe70D + address internal constant syrupUSDT_ORACLE = 0x982aC260B5a4e5bCAb6A437e79168390cFbDe70D; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant syrupUSDT_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0xe343167631d89B6Ffc58B88d6b7fB0228795491D + address internal constant USDG_UNDERLYING = 0xe343167631d89B6Ffc58B88d6b7fB0228795491D; + + uint8 internal constant USDG_DECIMALS = 6; + + // https://etherscan.io/address/0x7c0477d085ECb607CF8429f3eC91Ae5E1e460F4F + address internal constant USDG_A_TOKEN = 0x7c0477d085ECb607CF8429f3eC91Ae5E1e460F4F; + + // https://etherscan.io/address/0x4f97B950a30321c181E974971E156E19fAD184A3 + address internal constant USDG_V_TOKEN = 0x4f97B950a30321c181E974971E156E19fAD184A3; + + // https://etherscan.io/address/0x83D20dEEdcd4aC1313496c8CBcAad0fa298c0CE4 + address internal constant USDG_ORACLE = 0x83D20dEEdcd4aC1313496c8CBcAad0fa298c0CE4; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant USDG_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0x2DF6DfbD281F127a3690c87E4572076778a9EDa5 + address internal constant USDG_STATA_TOKEN = 0x2DF6DfbD281F127a3690c87E4572076778a9EDa5; + + // https://etherscan.io/address/0xAeBf0Bb9f57E89260d57f31AF34eB58657d96Ce0 + address internal constant PT_USDe_7MAY2026_UNDERLYING = + 0xAeBf0Bb9f57E89260d57f31AF34eB58657d96Ce0; + + uint8 internal constant PT_USDe_7MAY2026_DECIMALS = 18; + + // https://etherscan.io/address/0xE036478Da9A7ed89b56FE39A06e1FC1a4b38D4Ea + address internal constant PT_USDe_7MAY2026_A_TOKEN = 0xE036478Da9A7ed89b56FE39A06e1FC1a4b38D4Ea; + + // https://etherscan.io/address/0x04142fc546D59838852873bba5C8827601A13FC8 + address internal constant PT_USDe_7MAY2026_V_TOKEN = 0x04142fc546D59838852873bba5C8827601A13FC8; + + // https://etherscan.io/address/0x0a72df02CE3E4185b6CEDf561f0AE651E9BeE235 + address internal constant PT_USDe_7MAY2026_ORACLE = 0x0a72df02CE3E4185b6CEDf561f0AE651E9BeE235; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant PT_USDe_7MAY2026_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0x3de0ff76E8b528C092d47b9DaC775931cef80F49 + address internal constant PT_sUSDE_7MAY2026_UNDERLYING = + 0x3de0ff76E8b528C092d47b9DaC775931cef80F49; + + uint8 internal constant PT_sUSDE_7MAY2026_DECIMALS = 18; + + // https://etherscan.io/address/0x81b76ff3FeD28BA0B4a5D4c76Bd5C13Bd0641d86 + address internal constant PT_sUSDE_7MAY2026_A_TOKEN = 0x81b76ff3FeD28BA0B4a5D4c76Bd5C13Bd0641d86; + + // https://etherscan.io/address/0x762Edb8D79b97487F82093f85059e42EeEf61E9e + address internal constant PT_sUSDE_7MAY2026_V_TOKEN = 0x762Edb8D79b97487F82093f85059e42EeEf61E9e; + + // https://etherscan.io/address/0xa0dc0249c32fa79e8B9b17c735908a60b1141B40 + address internal constant PT_sUSDE_7MAY2026_ORACLE = 0xa0dc0249c32fa79e8B9b17c735908a60b1141B40; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant PT_sUSDE_7MAY2026_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0x9Bf45ab47747F4B4dD09B3C2c73953484b4eB375 + address internal constant PT_srUSDe_2APR2026_UNDERLYING = + 0x9Bf45ab47747F4B4dD09B3C2c73953484b4eB375; + + uint8 internal constant PT_srUSDe_2APR2026_DECIMALS = 18; + + // https://etherscan.io/address/0x1241ec22C9BdF16BA1Eb636F2a8de7e28A4343Cf + address internal constant PT_srUSDe_2APR2026_A_TOKEN = 0x1241ec22C9BdF16BA1Eb636F2a8de7e28A4343Cf; + + // https://etherscan.io/address/0xacD3d3FaCeA0424984F662827B988f4581a3cE31 + address internal constant PT_srUSDe_2APR2026_V_TOKEN = 0xacD3d3FaCeA0424984F662827B988f4581a3cE31; + + // https://etherscan.io/address/0xB539C6C0fc36ff1572B13ACec343B854937db576 + address internal constant PT_srUSDe_2APR2026_ORACLE = 0xB539C6C0fc36ff1572B13ACec343B854937db576; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant PT_srUSDe_2APR2026_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0xB0F70C0bD6FD87dbEb7C10dC692a2a6106817072 + address internal constant BTCb_UNDERLYING = 0xB0F70C0bD6FD87dbEb7C10dC692a2a6106817072; + + uint8 internal constant BTCb_DECIMALS = 8; + + // https://etherscan.io/address/0x12b70410D60f926558245f769059eA3Fc7A7353E + address internal constant BTCb_A_TOKEN = 0x12b70410D60f926558245f769059eA3Fc7A7353E; + + // https://etherscan.io/address/0x6C67e666BB954d4bE23e9F1cE20e7E8699d29339 + address internal constant BTCb_V_TOKEN = 0x6C67e666BB954d4bE23e9F1cE20e7E8699d29339; + + // https://etherscan.io/address/0xb41E773f507F7a7EA890b1afB7d2b660c30C8B0A + address internal constant BTCb_ORACLE = 0xb41E773f507F7a7EA890b1afB7d2b660c30C8B0A; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant BTCb_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0x619D75E3b790eBC21c289f2805Bb7177A7D732E2 + address internal constant PT_srUSDe_25JUN2026_UNDERLYING = + 0x619D75E3b790eBC21c289f2805Bb7177A7D732E2; + + uint8 internal constant PT_srUSDe_25JUN2026_DECIMALS = 18; + + // https://etherscan.io/address/0xA78Eba24D89e70A03ddB7AC195A15E53315aA5b4 + address internal constant PT_srUSDe_25JUN2026_A_TOKEN = + 0xA78Eba24D89e70A03ddB7AC195A15E53315aA5b4; + + // https://etherscan.io/address/0x9Ba896531F878Ed5f0A4F73E82d63bA7b424F910 + address internal constant PT_srUSDe_25JUN2026_V_TOKEN = + 0x9Ba896531F878Ed5f0A4F73E82d63bA7b424F910; + + // https://etherscan.io/address/0x9f336eB940730596548C342A8BF1fC530B10cc96 + address internal constant PT_srUSDe_25JUN2026_ORACLE = 0x9f336eB940730596548C342A8BF1fC530B10cc96; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant PT_srUSDe_25JUN2026_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0x9db38D74a0D29380899aD354121DfB521aDb0548 + address internal constant PT_USDG_28MAY2026_UNDERLYING = + 0x9db38D74a0D29380899aD354121DfB521aDb0548; + + uint8 internal constant PT_USDG_28MAY2026_DECIMALS = 6; + + // https://etherscan.io/address/0xA9ecb0503075124cc0B786096849A331FBe9EE6D + address internal constant PT_USDG_28MAY2026_A_TOKEN = 0xA9ecb0503075124cc0B786096849A331FBe9EE6D; + + // https://etherscan.io/address/0x1a83eCA2d3b0cea2595Fb11Ec60cb2D428217C2e + address internal constant PT_USDG_28MAY2026_V_TOKEN = 0x1a83eCA2d3b0cea2595Fb11Ec60cb2D428217C2e; + + // https://etherscan.io/address/0x83D20dEEdcd4aC1313496c8CBcAad0fa298c0CE4 + address internal constant PT_USDG_28MAY2026_ORACLE = 0x83D20dEEdcd4aC1313496c8CBcAad0fa298c0CE4; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant PT_USDG_28MAY2026_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; + + // https://etherscan.io/address/0x59bC9FaE5D62B19d4f8d07D758047aCb9EE19d34 + address internal constant PT_srUSDe_22OCT2026_UNDERLYING = + 0x59bC9FaE5D62B19d4f8d07D758047aCb9EE19d34; + + uint8 internal constant PT_srUSDe_22OCT2026_DECIMALS = 18; + + // https://etherscan.io/address/0x01E69a58ca3ddc695820ce6f66FBdf3fA55D0545 + address internal constant PT_srUSDe_22OCT2026_A_TOKEN = + 0x01E69a58ca3ddc695820ce6f66FBdf3fA55D0545; + + // https://etherscan.io/address/0x4Af166c6F2CF882f7B196E3625c3E8f2Fe2a8083 + address internal constant PT_srUSDe_22OCT2026_V_TOKEN = + 0x4Af166c6F2CF882f7B196E3625c3E8f2Fe2a8083; + + // https://etherscan.io/address/0xBD1bc41479D0b58167584980fE57fDA913d4fB73 + address internal constant PT_srUSDe_22OCT2026_ORACLE = 0xBD1bc41479D0b58167584980fE57fDA913d4fB73; + + // https://etherscan.io/address/0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB + address internal constant PT_srUSDe_22OCT2026_INTEREST_RATE_STRATEGY = + 0x9ec6F08190DeA04A54f8Afc53Db96134e5E3FdFB; +} +library AaveV3EthereumEModes { + uint8 internal constant NONE = 0; + + uint8 internal constant WETH_wstETH_cbETH_rETH_weETH_osETH_ETHx__WETH = 1; + + uint8 internal constant USDe_sUSDe__USDC_USDT = 2; + + uint8 internal constant rsETH__WETH_wstETH_ETHx = 3; + + uint8 internal constant LBTC__WBTC = 4; + + uint8 internal constant LBTC__cbBTC = 5; + + uint8 internal constant LBTC__tBTC = 6; + + uint8 internal constant eBTC__WBTC = 7; + + uint8 internal constant sUSDe_PT_sUSDE_31JUL2025__USDC_USDT = 8; + + uint8 internal constant PT_eUSDE_29MAY2025_eUSDe__USDC_USDT = 9; + + uint8 internal constant USDe_PT_USDe_31JUL2025__USDC_USDT = 10; + + uint8 internal constant USDe__USDC_USDT = 11; + + uint8 internal constant USDe_PT_USDe_31JUL2025__USDe = 12; + + uint8 internal constant PT_eUSDE_14AUG2025_eUSDe__USDC_USDT = 13; + + uint8 internal constant PT_eUSDE_14AUG2025_eUSDe__USDe = 14; + + uint8 internal constant eUSDe__USDC_USDT = 15; + + uint8 internal constant FBTC__WBTC = 16; + + uint8 internal constant sUSDe_PT_sUSDE_31JUL2025_PT_sUSDE_25SEP2025__USDC_USDT_USDe_USDtb = 17; + + uint8 internal constant PT_sUSDE_25SEP2025__USDe = 18; + + uint8 + internal constant USDe_PT_USDe_31JUL2025_PT_eUSDE_14AUG2025_PT_USDe_25SEP2025__USDC_USDT_USDe = + 19; + + uint8 internal constant USDe_PT_USDe_31JUL2025_PT_eUSDE_14AUG2025_PT_USDe_25SEP2025__USDe = 20; + + uint8 internal constant tETH__USDC_USDT = 21; + + uint8 internal constant ezETH__wstETH = 22; + + uint8 internal constant ezETH__USDC_USDT = 23; + + uint8 internal constant sUSDe_PT_sUSDE_25SEP2025_PT_sUSDE_27NOV2025__USDC_USDT_USDe_USDtb = 24; + + uint8 internal constant PT_sUSDE_25SEP2025_PT_sUSDE_27NOV2025__USDe = 25; + + uint8 internal constant weETH__WETH_wstETH = 26; + + uint8 internal constant PT_USDe_25SEP2025_PT_USDe_27NOV2025__USDC_USDT_USDe_USDtb = 27; + + uint8 internal constant PT_USDe_25SEP2025_PT_USDe_27NOV2025__USDe = 28; + + uint8 internal constant USDe_PT_USDe_27NOV2025_PT_USDe_5FEB2026__USDC_USDT_USDe_USDtb = 29; + + uint8 internal constant USDe_PT_USDe_27NOV2025_PT_USDe_5FEB2026__USDe = 30; + + uint8 internal constant sUSDe_PT_sUSDE_27NOV2025_PT_sUSDE_5FEB2026__USDC_USDT_USDe_USDtb = 31; + + uint8 internal constant sUSDe_PT_sUSDE_27NOV2025_PT_sUSDE_5FEB2026__USDe = 32; + + uint8 internal constant syrupUSDT__USDT_GHO = 33; + + uint8 internal constant USDe_PT_USDe_5FEB2026_PT_USDe_7MAY2026__USDC_USDT_USDe_USDtb = 34; + + uint8 internal constant USDe_PT_USDe_5FEB2026_PT_USDe_7MAY2026__USDe = 35; + + uint8 internal constant sUSDe_PT_sUSDE_5FEB2026_PT_sUSDE_7MAY2026__USDC_USDT_USDe_USDtb = 36; + + uint8 internal constant sUSDe_PT_sUSDE_5FEB2026_PT_sUSDE_7MAY2026__USDe = 37; + + uint8 internal constant sUSDe_PT_srUSDe_2APR2026__USDC_USDT_USDe = 38; + + uint8 internal constant sUSDe_PT_srUSDe_2APR2026__USDe = 39; + + uint8 internal constant LINK__USDC_USDT = 40; + + uint8 internal constant EURC__USDC_USDT_GHO = 41; + + uint8 internal constant rsETH__USDC_USDT = 42; + + uint8 internal constant XAUt__USDC_USDT_GHO = 43; + + uint8 internal constant sUSDe_PT_srUSDe_2APR2026_PT_srUSDe_25JUN2026__USDC_USDT_USDe = 44; + + uint8 internal constant sUSDe_PT_srUSDe_2APR2026_PT_srUSDe_25JUN2026__USDe = 45; + + uint8 internal constant PT_USDG_28MAY2026__USDC_USDT_USDe_USDG = 46; + + uint8 internal constant sUSDe_PT_srUSDe_22OCT2026__USDC_USDT_USDe = 47; + + uint8 internal constant sUSDe_PT_srUSDe_22OCT2026__USDe = 48; +} +library AaveV3EthereumExternalLibraries { + // https://etherscan.io/address/0x6D414cd0d5eAf8C43200ac0c325A7E2Ad83B8be6 + address internal constant FLASHLOAN_LOGIC = 0x6D414cd0d5eAf8C43200ac0c325A7E2Ad83B8be6; + + // https://etherscan.io/address/0x52Da0ce88202D1542543598D1e1e27F0d344726A + address internal constant BORROW_LOGIC = 0x52Da0ce88202D1542543598D1e1e27F0d344726A; + + // https://etherscan.io/address/0x96D5686812e33Ab509ECCDb38C89d15607B2a413 + address internal constant LIQUIDATION_LOGIC = 0x96D5686812e33Ab509ECCDb38C89d15607B2a413; + + // https://etherscan.io/address/0xD70593841C57cbaA04957cc3EAcE95708e48853b + address internal constant POOL_LOGIC = 0xD70593841C57cbaA04957cc3EAcE95708e48853b; + + // https://etherscan.io/address/0x584C7d8c4cb05304FE5Ac7fbc97f20A10Fb07564 + address internal constant SUPPLY_LOGIC = 0x584C7d8c4cb05304FE5Ac7fbc97f20A10Fb07564; +} diff --git a/plan/agw/research/preset-mainnet-2026-10-15/README.md b/plan/agw/research/preset-mainnet-2026-10-15/README.md new file mode 100644 index 00000000..9be17f8d --- /dev/null +++ b/plan/agw/research/preset-mainnet-2026-10-15/README.md @@ -0,0 +1,27 @@ +# Mainnet preset templates — October 15, 2026 + +The user expanded the earlier testnet-only scope to include mainnet templates. Execution tests remain testnet-only. No mainnet signatures, approvals or transactions were made. + +## Included + +| Category | Mainnet coverage | +| --- | --- | +| DEXES | Uniswap SwapRouter02: Ethereum, Base, Arbitrum; PancakeSwap V3 SmartRouter: BNB | +| LENDING | Aave V3: Ethereum, Base, Arbitrum, BNB; Moonwell USDC/WETH + controller: Base; Venus USDT/USDC + controller: BNB | +| STAKING | Ethereum: EigenLayer deposits; Lido stake/wrap/unwrap/request withdrawal/claim | + +Existing testnet entries remain. `list` and unfiltered `get` now include both environments. Use a chainNamespace filter for a specific environment. Catalog discovery is pure: it does not imply the connected Push network supports a destination or that every token has a PRC20 mapping. + +## Verification + +Official protocol address/source snapshots are in sources.json and ../preset-catalog-2026-10-15/protocol-sources.json. Uniswap addresses.ts supplies the default Ethereum/Arbitrum SwapRouter02 at its fallback and the explicit Base address. PancakeSwap addresses.md supplies the BNB SmartRouter. EigenLayer README.md names the StrategyManager proxy. Aave, Moonwell and Venus mainnet address files are retained here. + +rpc-verification.json records chain IDs, pinned blocks, code hashes/lengths and money-market underlying addresses. All 18 included mainnet contract addresses had code (15 in rpc-verification.json, three Lido contracts in lido-rpc-verification.json). These are read-only presence/wiring checks, not an audit or proof of execution/liquidity. Existing call shapes are reused, with Lido additions checked against its official method documentation. Lido request ownership is pinned to WALLET; claim methods require/payout to msg.sender. ETH submit has maxValue zero until a caller explicitly supplies a value cap. + +## Exclusions + +This adds mainnet counterparts of the verified/representable testnet catalog. It does not activate every proposal row. Compound, Morpho/Lista, Rocket Pool/ether.fi, additional routers and prediction venues still require independent deployment/function/permission review. Dynamic-path swaps and currently unrepresentable Solana protocol flows remain excluded. One V3 router per chain keeps the two-token expansion below the 32-pin policy limit; two routers with both exact-input/output and both directions would exceed it. + +## Validation + +44 focused preset tests pass, including full-signature pin offsets for all eight DEX chains, one-rule-per-chain discovery, review templates and complete-pair generation. No mainnet transaction was used as validation. diff --git a/plan/agw/research/preset-mainnet-2026-10-15/lido-rpc-verification.json b/plan/agw/research/preset-mainnet-2026-10-15/lido-rpc-verification.json new file mode 100644 index 00000000..cf8c62e8 --- /dev/null +++ b/plan/agw/research/preset-mainnet-2026-10-15/lido-rpc-verification.json @@ -0,0 +1,24 @@ +{ + "chainId": 1, + "block": "26194814", + "contracts": [ + { + "name": "Lido stETH", + "address": "0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84", + "bytes": 1035, + "codeHash": "0xb9c1c929064cd21734c102a698e68bf617feefcfa5a9f62407c45401546736bf" + }, + { + "name": "Lido wstETH", + "address": "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0", + "bytes": 6492, + "codeHash": "0x630181884786c962140041cffa3acffbf39d8c93bde1a62b7b55046e57400557" + }, + { + "name": "Lido withdrawal queue", + "address": "0x889edC2eDab5f40e902b864aD4d7AdE8E412F9B1", + "bytes": 2497, + "codeHash": "0x9bc25fa4b2f98d56db4aa4156a6dc98360ccd4ef9c7bc7f891797b0024272100" + } + ] +} diff --git a/plan/agw/research/preset-mainnet-2026-10-15/moonwell-8453.json b/plan/agw/research/preset-mainnet-2026-10-15/moonwell-8453.json new file mode 100644 index 00000000..e333831d --- /dev/null +++ b/plan/agw/research/preset-mainnet-2026-10-15/moonwell-8453.json @@ -0,0 +1,1677 @@ +[ + { + "addr": "0x76e1e2F2E3239A15bAD01f027B5A4bcDE5797f3C", + "isContract": true, + "name": "JUMP_RATE_IRM_USDC_MIP_X61" + }, + { + "addr": "0xc6845C053d29396DA966be052CF4F6b08453dbbD", + "isContract": true, + "name": "JUMP_RATE_IRM_MAMO_MIP_X61" + }, + { + "addr": "0x9c4b2B98b24F36f906517139F5f9bAca732a3cF0", + "isContract": true, + "name": "JUMP_RATE_IRM_BASE_FLAT_MIP_X55" + }, + { + "addr": "0x4DdD7968113A037e84034eDDEc4524497B77d200", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_USDC_EURC_MIP_X50" + }, + { + "addr": "0xF203236B9CEf1FaaEa4aCE8e8e2EB65431ef7697", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_USDC_MIP_X46" + }, + { + "addr": "0xc3831D840243C4Df57F52C063eEE2a6b44d1840e", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_cbETH_MIP_X46" + }, + { + "addr": "0x2D0c1616CaeD53e3d161e53Fe0Ca1402017f2766", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_cbBTC_LBTC_TBTC_MIP_X42" + }, + { + "addr": "0x1b2a5f458b627Fb995F834A7B40112c27c2f77e8", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_VIRTUAL_MIP_B53" + }, + { + "addr": "0x6515fAb53Ab28D179CFf4258CdDb8f4745EBb348", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_USDC_MIP_X35" + }, + { + "addr": "0xB290615c4f5348aEFDC301a42896906212C80e46", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_USDC_EURC_MIP_X33" + }, + { + "addr": "0x4e41B935f49eB4F82A4F41B0a4b19c36A35DA4DA", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_USDC_MIP_X31" + }, + { + "addr": "0xDcB85eCF9746302aC59d4BA565dc322BB0b173B3", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_cbXRP_MIP_X29" + }, + { + "addr": "0x0F704fD3A00780779551046D492B1c64d15e6cab", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_USDC_MIP_X29" + }, + { + "addr": "0x86CBee66b3FF313Af153e697f4DC02d423ACD5CE", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_WETH_MIP_X24" + }, + { + "addr": "0xc27e9327a81bfAF33e5b0CC3Edc7112cC259b96b", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_cbBTC_MIP_X24" + }, + { + "addr": "0xbcC4D66cFFbF3A5D75669984700FbC1FeaBE8487", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_LBTC_MIP_X24" + }, + { + "addr": "0x670136DBdb194b051fc9A5e973ccfB825E7f45F6", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_TBTC_MIP_X24" + }, + { + "addr": "0xe8A41eC7fE1C991E7cfBa7f5AA1b5895EAc8307D", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_AERO_MIP_X24" + }, + { + "addr": "0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb", + "isContract": true, + "name": "MORPHO_BLUE" + }, + { + "addr": "0xe770BD40b6976Efbbb095174395DD2cb794c938a", + "name": "ERC20_FACTORY_4626", + "isContract": true + }, + { + "addr": "0x6250e204bA6f722c7d498f659f8d3C5550Ec811E", + "name": "ETH_FACTORY_4626", + "isContract": true + }, + { + "addr": "0xc095cb1A6B41A5Cd7dAaF993a904afDD74758D71", + "name": "ETH_ROUTER_4626", + "isContract": true + }, + { + "addr": "0xA9c3D3a366466Fa809d1Ae982Fb2c46E5fC41101", + "name": "META_MORPHO_FACTORY", + "isContract": true + }, + { + "addr": "0x4756c26E01E61c7c2F86b10f4316e179db8F9425", + "name": "MORPHO_CHAINLINK_cbETH_ORACLE", + "isContract": true + }, + { + "addr": "0x46415998764C29aB2a25CbeA6254146D50D22687", + "name": "MORPHO_ADAPTIVE_CURVE_IRM", + "isContract": true + }, + { + "addr": "0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6", + "name": "WORMHOLE_CORE", + "isContract": true + }, + { + "addr": "0x9E1936E91A4a5AE5A5F75fFc472D6cb8e93597ea", + "isContract": true, + "name": "WORMHOLE_EXECUTOR" + }, + { + "addr": "0x265fd0500a430d65d6D79Cd8707F24C048604658", + "isContract": true, + "name": "WORMHOLE_QUOTER_ROUTER" + }, + { + "addr": "0xA25862D222Eb8343505c12d96e097e4332468D60", + "isContract": true, + "name": "WORMHOLE_QUOTER" + }, + { + "addr": "0xa54008017941EcE968623a0Dd8Ee907E2b133596", + "isContract": false, + "name": "WORMHOLE_QUOTER_SIGNER" + }, + { + "addr": "0xd9aAEc86B65D86f6A7B5B1b0c42FFA531710b6CA", + "name": "USDBC", + "isContract": true + }, + { + "addr": "0x9e3380f8B29E8f85cA19EFFA80Fb41149417D943", + "isContract": true, + "name": "MOONWELL_METAMORPHO_URD" + }, + { + "addr": "0x1e1b4a620d1A840bcD56706d87903e3583c8B26f", + "isContract": true, + "name": "USDC_METAMORPHO_FEE_SPLITTER" + }, + { + "addr": "0xd5F9BaE72F6D8334ac4BB6C14463A81A43037E1C", + "isContract": true, + "name": "WETH_METAMORPHO_FEE_SPLITTER" + }, + { + "addr": "0xEB59E94B48B0fa68f8dD981a4b4CD9E30ebB44Cd", + "isContract": true, + "name": "EURC_METAMORPHO_FEE_SPLITTER" + }, + { + "addr": "0x5E868C8C6Fd597f436fBE60f1eBd5A3A07B3C320", + "isContract": true, + "name": "USDC_METAMORPHO_FEE_SPLITTER_V2" + }, + { + "addr": "0x1f0221cF50B97e1B503fb4D616eC1D883e04a7D4", + "isContract": true, + "name": "WETH_METAMORPHO_FEE_SPLITTER_V2" + }, + { + "addr": "0xc75cd0991778143089B69d0AA89E8d50763259ef", + "isContract": true, + "name": "EURC_METAMORPHO_FEE_SPLITTER_V2" + }, + { + "addr": "0x5994f9a49E9a5203A63daB2d4a7893F7fe9510ec", + "isContract": true, + "name": "cbBTC_METAMORPHO_FEE_SPLITTER" + }, + { + "addr": "0x1a8ae46098FF418E2054243491544ed8564c3CDB", + "isContract": true, + "name": "meUSDC_METAMORPHO_FEE_SPLITTER" + }, + { + "addr": "0x543257eF2161176D7C8cD90BA65C2d4CaEF5a796", + "isContract": true, + "name": "cbBTC_METAMORPHO_VAULT" + }, + { + "addr": "0xc1256Ae5FF1cf2719D4937adb3bbCCab2E00A2Ca", + "isContract": true, + "name": "USDC_METAMORPHO_VAULT" + }, + { + "addr": "0xa0E430870c4604CcfC7B38Ca7845B1FF653D0ff1", + "isContract": true, + "name": "WETH_METAMORPHO_VAULT" + }, + { + "addr": "0xf24608E0CCb972b0b0f4A6446a0BBf58c701a026", + "isContract": true, + "name": "EURC_METAMORPHO_VAULT" + }, + { + "addr": "0x89BeDBB1C4837444Da215A377275Ff96A84D6f53", + "isContract": true, + "name": "WETH_FLAGSHIP_METAMORPHO_VAULT" + }, + { + "addr": "0x48a90E85be5C56b0A669985A12ee7C449fC79965", + "isContract": true, + "name": "USDC_FLAGSHIP_METAMORPHO_VAULT" + }, + { + "addr": "0x5083b1387Ec3d4Ee6467B83890D98f1AF93F7c48", + "isContract": true, + "name": "EURC_FLAGSHIP_METAMORPHO_VAULT" + }, + { + "addr": "0xdbA76Bc542bb07538e046B40F2e8a215B409F7A8", + "isContract": true, + "name": "cbBTC_FRONTIER_METAMORPHO_VAULT" + }, + { + "addr": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", + "name": "USDC", + "isContract": true + }, + { + "addr": "0x4200000000000000000000000000000000000006", + "name": "WETH", + "isContract": true + }, + { + "addr": "0xFF8adeC2221f9f4D8dfbAFa6B9a297d17603493D", + "name": "GOVTOKEN", + "isContract": true + }, + { + "addr": "0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb", + "name": "DAI", + "isContract": true + }, + { + "addr": "0x2Ae3F1Ec7F1F5012CFEab0185bfc7aa3cf0DEc22", + "name": "cbETH", + "isContract": true + }, + { + "addr": "0x04c0599ae5a44757c0af6f9ec3b93da8976c150a", + "name": "weETH", + "isContract": true + }, + { + "addr": "0xFC1415403EbB0c693f9a7844b92aD2Ff24775C65", + "name": "CHAINLINK_WEETH_ORACLE", + "isContract": true + }, + { + "addr": "0xe44b816FE6bc5047C22b9fA5e4D4c5c9747476b3", + "isContract": true, + "name": "CHAINLINK_WEETH_USD_COMPOSITE_ORACLE" + }, + { + "addr": "0x6ac79dF84FA8A704711a2fb8c3763e48Ed2c0Ed6", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_weETH" + }, + { + "addr": "0x7e860098F58bBFC8648a4311b374B1D669a2bc6B", + "name": "USDC_ORACLE", + "isContract": true + }, + { + "addr": "0x71041dddad3595F9CEd3DcCFBe3D1F4b0a16Bb70", + "name": "ETH_ORACLE", + "isContract": true + }, + { + "addr": "0x591e79239a7d679378eC8c847e5038150364C78F", + "name": "DAI_ORACLE", + "isContract": true + }, + { + "addr": "0xf586d0728a47229e747d824a939000Cf21dEF5A0", + "name": "stETHETH_ORACLE", + "isContract": true + }, + { + "addr": "0x806b4Ac04501c29769051e42783cF04dCE41440b", + "name": "cbETHETH_ORACLE", + "isContract": true + }, + { + "addr": "0xD791292655A1d382FcC1a6Cb9171476cf91F2caa", + "name": "DEPRECATED_WARDEN_EMISSIONS_ADMIN", + "isContract": false + }, + { + "addr": "0x8b621804a7637b781e2BbD58e256a591F2dF7d51", + "name": "EMISSIONS_ADMIN", + "isContract": true + }, + { + "addr": "0xB9d4acf113a423Bc4A64110B8738a52E51C2AB38", + "name": "PAUSE_GUARDIAN_DEPRECATED", + "isContract": true + }, + { + "addr": "0x446342AF4F3bCD374276891C6bb3411bf2F8779E", + "name": "SECURITY_COUNCIL", + "isContract": true + }, + { + "addr": "0x35b3314EA652899154BbfE937E3cCC2775ba712e", + "name": "BORROW_SUPPLY_GUARDIAN", + "isContract": true + }, + { + "addr": "0x8b621804a7637b781e2BbD58e256a591F2dF7d51", + "name": "TEMPORAL_GOVERNOR", + "isContract": true + }, + { + "addr": "0xB0Ba0C5D7DA4ec400C1C3E5ef2485134F89918C5", + "name": "cbETH_COMPOSITE_ORACLE", + "isContract": true + }, + { + "addr": "0xdC649f4fa047a3C98e8705E85B8b1BafCbCFef0f", + "name": "MRD_IMPL", + "isContract": true + }, + { + "addr": "0x73D8A3bF62aACa6690791E57EBaEE4e1d875d8Fe", + "name": "COMPTROLLER", + "isContract": true + }, + { + "addr": "0xfBb21d0380beE3312B33c4353c8936a0F13EF26C", + "name": "UNITROLLER", + "isContract": true + }, + { + "addr": "0xe9005b078701e2A0948D2EaC43010D35870Ad9d2", + "name": "MRD_PROXY", + "isContract": true + }, + { + "addr": "0x8D7d2230A2d195F023588eDd13dBAd56dd69770F", + "name": "MRD_PROXY_ADMIN", + "isContract": true + }, + { + "addr": "0x1FADFF493529C3Fcc7EE04F1f15D19816ddA45B7", + "name": "MTOKEN_IMPLEMENTATION", + "isContract": true + }, + { + "addr": "0xF22c8255eA615b3Da6CA5CF5aeCc8956bfF07Aa8", + "name": "JUMP_RATE_IRM_MOONWELL_USDBC", + "isContract": true + }, + { + "addr": "0x73b06D8d18De422E269645eaCe15400DE7462417", + "name": "MOONWELL_DAI", + "isContract": true + }, + { + "addr": "0x32f3A6134590fc2d9440663d35a2F0a6265F04c4", + "name": "JUMP_RATE_IRM_MOONWELL_DAI", + "isContract": true + }, + { + "addr": "0x703843C3379b52F9FF486c9f5892218d2a065cC8", + "name": "MOONWELL_USDBC", + "isContract": true + }, + { + "addr": "0x54dC357F7461BcEEE5BdbA80996f5CB7d7512445", + "name": "JUMP_RATE_IRM_MOONWELL_USDC", + "isContract": true + }, + { + "addr": "0x97E310638D59d2464b39328DBbFdAbc307aB00E2", + "name": "JUMP_RATE_IRM_MOONWELL_USDC_MIP_B27", + "isContract": true + }, + { + "addr": "0x6182b94bF494eb796C476a4Cf549f2bDD249Bf09", + "name": "JUMP_RATE_IRM_MOONWELL_USDC_MIP_B32", + "isContract": true + }, + { + "addr": "0xEdc817A28E8B93B03976FBd4a3dDBc9f7D176c22", + "name": "MOONWELL_USDC", + "isContract": true + }, + { + "addr": "0x22aD8a160e4785223cD03A86d02c3ccc2838E9FF", + "name": "JUMP_RATE_IRM_MOONWELL_USDC_MIP_X07", + "isContract": true + }, + { + "addr": "0x01635c141C070944EAE7919443ff61dB2a6a4597", + "name": "JUMP_RATE_IRM_MOONWELL_USDC_EURC_MIP_X10", + "isContract": true + }, + { + "addr": "0xBAB813eB17de29137dBe292a82ad6b50464D948f", + "name": "JUMP_RATE_IRM_MOONWELL_USDC_MIP_X12", + "isContract": true + }, + { + "addr": "0xB7056D2Dd2eb1681Ee838E79d2E742642b0c76b0", + "name": "JUMP_RATE_IRM_MOONWELL_USDC_MIP_X15", + "isContract": true + }, + { + "addr": "0xa4a1B5033F8a5B6455310bD8e1943CC5f08f9Cab", + "name": "JUMP_RATE_IRM_MOONWELL_USDC_MIP_X22", + "isContract": true + }, + { + "addr": "0x5828fE276f2238EAd59537bfFD6B82a676770061", + "name": "JUMP_RATE_IRM_MOONWELL_cbBTC_MIP_X22", + "isContract": true + }, + { + "addr": "0xB878bF6a87888b06FEDBc76B5D7557adaA1DFC18", + "name": "JUMP_RATE_IRM_MOONWELL_LBTC_MIP_X22", + "isContract": true + }, + { + "addr": "0x284c0755F1e102f0E334Dea2cc0e8f2bd6ABcBB0", + "name": "JUMP_RATE_IRM_MOONWELL_TBTC_MIP_X22", + "isContract": true + }, + { + "addr": "0xd1AbF6615767DA1Fa9b944194C68E3e0ca16B83B", + "name": "JUMP_RATE_IRM_MOONWELL_VIRTUAL_MIP_X22", + "isContract": true + }, + { + "addr": "0xfC7b55cc7C5BD3aE89aC679c7250AB30754C5cC5", + "name": "JUMP_RATE_IRM_MOONWELL_DAI_MIP_B14", + "isContract": true + }, + { + "addr": "0x8781110995cBdC58EFf7425D4A31BDc9DB8B3Cdd", + "name": "JUMP_RATE_IRM_MOONWELL_DAI_MIP_B34", + "isContract": true + }, + { + "addr": "0x0568a3aeb8E78262dEFf75ee68fAC20ae35ffA91", + "name": "JUMP_RATE_IRM_MOONWELL_WETH_MIP_B14", + "isContract": true + }, + { + "addr": "0xF5C73A4198941b49831cc95C5E407571851fbA4b", + "name": "JUMP_RATE_IRM_MOONWELL_WETH_MIP_B19", + "isContract": true + }, + { + "addr": "0x822d0b61d7d79d0AC2170D0A5bd634d7E11df06e", + "name": "JUMP_RATE_IRM_MOONWELL_WETH_MIP_B22", + "isContract": true + }, + { + "addr": "0x0FC39BF0dEA1ce1bEE4Be77680f4F55f4ef3f8eF", + "name": "JUMP_RATE_IRM_MOONWELL_WETH_MIP_B34", + "isContract": true + }, + { + "addr": "0x9249c9E427F14f78A332DC67400d1E4D36472191", + "name": "JUMP_RATE_IRM_MOONWELL_WETH_MIP_X15", + "isContract": true + }, + { + "addr": "0x628ff693426583D9a7FB391E54366292F509D457", + "name": "MOONWELL_WETH", + "isContract": true + }, + { + "addr": "0xff374aD1be52fF54Cf576586253a113d3F48D4B7", + "name": "JUMP_RATE_IRM_MOONWELL_CBETH_MIP_B18", + "isContract": true + }, + { + "addr": "0x9c3431faf6aF953815893ca4661B8F437ce0Ee22", + "name": "JUMP_RATE_IRM_MOONWELL_CBETH_MIP_B22", + "isContract": true + }, + { + "addr": "0x3bf93770f2d4a794c3d9EBEfBAeBAE2a8f09A5E5", + "name": "MOONWELL_cbETH", + "isContract": true + }, + { + "addr": "0x70778cfcFC475c7eA0f24cC625Baf6EaE475D0c9", + "name": "WETH_ROUTER", + "isContract": true + }, + { + "addr": "0xEC942bE8A8114bFD0396A5052c36027f2cA6a9d0", + "name": "CHAINLINK_ORACLE", + "isContract": true + }, + { + "addr": "0x1382cFf3CeE10D283DccA55A30496187759e4cAf", + "name": "WETH_UNWRAPPER", + "isContract": true + }, + { + "addr": "0x599D4a1538d686814eE11b331EACBBa166D7C41a", + "name": "MWETH_IMPLEMENTATION", + "isContract": true + }, + { + "addr": "0x74Cbb1E8B68dDD13B28684ECA202a351afD45EAa", + "name": "FOUNDATION_MULTISIG", + "isContract": true + }, + { + "addr": "0x4942E15F4B3B684EEbB7eE28C922fc634Cc751B1", + "name": "C-BASE", + "isContract": true + }, + { + "addr": "0x71041dddad3595F9CEd3DcCFBe3D1F4b0a16Bb70", + "name": "CHAINLINK_ETH_USD", + "isContract": true + }, + { + "addr": "0xf586d0728a47229e747d824a939000Cf21dEF5A0", + "name": "CHAINLINK_STETH_ETH", + "isContract": true + }, + { + "addr": "0xB88BAc61a4Ca37C43a3725912B1f472c9A5bc061", + "name": "CHAINLINK_WSTETH_STETH", + "isContract": true + }, + { + "addr": "0xa5A5892bCfca4642c6bD789Ca75f27774309Dcb7", + "name": "CHAINLINK_WSTETH_STETH_COMPOSITE_ORACLE", + "isContract": true + }, + { + "addr": "0x1E6c22AAA11F507af12034A5Dc4126A6A25DC8d2", + "name": "CHAINLINK_LBTC_MARKET", + "isContract": true + }, + { + "addr": "0x5C4c8d6f6Bf79B718F3e8399AaBdFEd01cB7e48f", + "name": "REDSTONE_LBTC_BTC", + "isContract": true + }, + { + "addr": "0x497e43aF113e71929871C85C56022893B9Ac968C", + "name": "REDSTONE_LBTC_BTC_CHAINLINK_BOUNDED_ORACLE_IMPL", + "isContract": true + }, + { + "addr": "0x31d099C106cd73E731972Fdf1390Cab77F59DaDe", + "name": "REDSTONE_LBTC_BTC_CHAINLINK_BOUNDED_ORACLE_PROXY", + "isContract": true + }, + { + "addr": "0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452", + "name": "wstETH", + "isContract": true + }, + { + "addr": "0xb96887502797c07Fc5b0F0938C61cC3D46e16e18", + "name": "JUMP_RATE_IRM_MOONWELL_WSTETH_MIP_B18", + "isContract": true + }, + { + "addr": "0x1dA5101eD155750FAF18beB51B17d1ffcEFc8D52", + "name": "JUMP_RATE_IRM_MOONWELL_WSTETH_MIP_B22", + "isContract": true + }, + { + "addr": "0x627Fe393Bc6EdDA28e99AE648fD6fF362514304b", + "name": "MOONWELL_wstETH", + "isContract": true + }, + { + "addr": "0x706f82e9bb5b0813501714ab5974216704980e31", + "name": "WORMHOLE_BRIDGE_RELAYER_PROXY", + "isContract": true + }, + { + "addr": "0x29eA8B56341EE95C819F4438bc048C6239AE5b71", + "name": "MOONWELL_VIEWS_IMPLEMENTATION", + "isContract": true + }, + { + "addr": "0xFf0731337F615aC5403cb243623283BC04cDe121", + "name": "MOONWELL_VIEWS_PROXY_ADMIN", + "isContract": true + }, + { + "addr": "0x6834770ABA6c2028f448E3259DDEE4BCB879d459", + "name": "MOONWELL_VIEWS_PROXY", + "isContract": true + }, + { + "addr": "0xB6fe221Fe9EeF5aBa221c348bA20A1Bf5e73624c", + "name": "rETH", + "isContract": true + }, + { + "addr": "0xf397bF97280B488cA19ee3093E81C0a77F02e9a5", + "name": "CHAINLINK_RETH_ETH", + "isContract": true + }, + { + "addr": "0x106c7f4f7f0F1B1B5973dD7b89CF3ac46420945F", + "name": "CHAINLINK_RETH_ETH_COMPOSITE_ORACLE", + "isContract": true + }, + { + "addr": "0x9260fa4D0284549ffEDc7B7003489a2837B3121d", + "name": "JUMP_RATE_IRM_MOONWELL_RETH_MIP_B18", + "isContract": true + }, + { + "addr": "0x6147Be7E92242B9119Da9aE81a6a14e64caCe094", + "name": "JUMP_RATE_IRM_MOONWELL_RETH_MIP_B22", + "isContract": true + }, + { + "addr": "0xCB1DaCd30638ae38F2B94eA64F066045B7D45f44", + "name": "MOONWELL_rETH", + "isContract": true + }, + { + "addr": "0x734AbBCe07679C9A6B4Fe3bC16325e028fA6DbB7", + "name": "WORMHOLE_BRIDGE_ADAPTER_PROXY", + "isContract": true + }, + { + "addr": "0xEF68C8f8BDeEF8e938F519ee818DeC80e320CE6b", + "name": "WORMHOLE_BRIDGE_ADAPTER_LOGIC", + "isContract": true + }, + { + "addr": "0xBe08A91ADe130aD61193bE2321ea06c4c39E124A", + "name": "xWELL_LOGIC", + "isContract": true + }, + { + "addr": "0xA88594D404727625A9437C3f886C7643872296AE", + "name": "xWELL_PROXY", + "isContract": true + }, + { + "addr": "0x65A633E8E379F9358C389c75ff1D913a92ab95B8", + "isContract": true, + "name": "ECOSYSTEM_RESERVE_PROXY" + }, + { + "addr": "0x3343b3EFeBB99B543da30d272d6363d672372aF1", + "isContract": true, + "name": "ECOSYSTEM_RESERVE_IMPL" + }, + { + "addr": "0x938FD93CBc45eCC4Bb8f2d1A69F45e593EEed514", + "isContract": true, + "name": "ECOSYSTEM_RESERVE_CONTROLLER" + }, + { + "addr": "0xe66E3A37C3274Ac24FE8590f7D84A2427194DC17", + "isContract": true, + "name": "STK_GOVTOKEN_PROXY" + }, + { + "addr": "0x4439640C018E541eC6b29a5828bc876327cf556C", + "isContract": true, + "name": "STK_GOVTOKEN_IMPL" + }, + { + "addr": "0xe0278B32c627FF6fFbbe7de6A18Ade145603e949", + "isContract": true, + "name": "VOTE_COLLECTION_PROXY" + }, + { + "addr": "0x98E708bbce1f158C1bde25f206afA7562fd0157f", + "isContract": true, + "name": "VOTE_COLLECTION_IMPL" + }, + { + "addr": "0x940181a94a35a4569e4529a3cdfb74e38fd98631", + "isContract": true, + "name": "AERO" + }, + { + "addr": "0x4EC5970fC728C5f65ba413992CD5fF6FD70fcfF0", + "isContract": true, + "name": "CHAINLINK_AERO_ORACLE" + }, + { + "addr": "0x0A72A4c3c9FC1345C1Cdaf52E0195367F8b688d0", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_AERO_MIP_B19" + }, + { + "addr": "0x78aCeC1B92dF516DA14B3dbed91219772180330A", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_AERO_MIP_B22" + }, + { + "addr": "0xF50eFEAA85E101b32E11944D6b45b61EF2C5bFeb", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_AERO_MIP_B24" + }, + { + "addr": "0x745e8CC80E30F4497c56bc5E010FbBD23079049C", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_AERO_MIP_B27" + }, + { + "addr": "0x73902f619CEB9B31FD8EFecf435CbDf89E369Ba6", + "isContract": true, + "name": "MOONWELL_AERO" + }, + { + "addr": "0x4393277B02ef3cA293990A772B7160a8c76F2443", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_WETH_MIP_B01" + }, + { + "addr": "0x6bcE15B789e537f3abA3C60CB183F0E8737f05eC", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_WETH_MIP_B05" + }, + { + "addr": "0x33DeAc0861FD6a9235b86172AA939E79085c6f52", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_USD_MIP_B05" + }, + { + "addr": "0x142DCAEC322aAA25141B2597bf348487aDBd596d", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_WETH_MIP_B06" + }, + { + "addr": "0x492dcEF1fc5253413fC5576B9522840a1A774DCe", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_USD_MIP_B06" + }, + { + "addr": "0x78Fe5d0427E669ba9F964C3495fF381a805a0487", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_CBETH_MIP_B06" + }, + { + "addr": "0x1Cdb984008dcEe9d06c28654ed31cf82680EeA62", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_CBETH_MIP_B12" + }, + { + "addr": "0xE1Dd796dBEB5A67CE37CbC52dCD164D0535c901E", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_CBETH_MIP_B13" + }, + { + "addr": "0x24bdAcf6bbEBAf567123Da16CDb79A266597e92B", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_USD_MIP_B13" + }, + { + "addr": "0x0f36Dda2b47984434051AeCAa5F9587DEA7f95B7", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_USD_MIP_B15" + }, + { + "addr": "0xAf3642bAc06cDA85340ECf18D40b8Bf89958B69E", + "isContract": false, + "name": "DEX_RELAYER" + }, + { + "addr": "0xb8051464C8c92209C92F3a4CD9C73746C4c3CFb3", + "isContract": true, + "name": "MOONWELL_weETH" + }, + { + "addr": "0xE9fFd686Ca83CeB308962f4e50c5Fd7F2E3c037e", + "isContract": true, + "name": "MARKET_ADD_CHECKER" + }, + { + "addr": "0x3b23090F40b6Dc9919942396386FC0977055cdB5", + "isContract": true, + "name": "DEPRECATED_MARKET_ADD_CHECKER" + }, + { + "addr": "0xcbB7C0000aB88B473b1f5aFd9ef808440eed33Bf", + "isContract": true, + "name": "cbBTC" + }, + { + "addr": "0x64c911996D3c6aC71f9b455B1E8E7266BcbD848F", + "isContract": true, + "name": "CHAINLINK_BTC_USD" + }, + { + "addr": "0x0738483Add6ab8620B731aEc0121d1d3A70BD6EA", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_cbBTC" + }, + { + "addr": "0x61e0dEC383Ef2E4be7e198F0e33605A553Da281d", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_cbBTC_MIP_B32" + }, + { + "addr": "0x2B42e79f46e4E5d8966b098140915d1E7355E1E6", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_cbBTC_MIP_X10" + }, + { + "addr": "0x2aC1a1bb4B1c05f4410c1a76318a966d9f063236", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_cbBTC_MIP_X12" + }, + { + "addr": "0xF877ACaFA28c19b96727966690b2f44d35aD5976", + "isContract": true, + "name": "MOONWELL_cbBTC" + }, + { + "addr": "0xDAe398520e2B67cd3f27aeF9Cf14D93D927f8250", + "isContract": true, + "name": "CHAINLINK_EURC_USD" + }, + { + "addr": "0x60a3e35cc302bfa44cb288bc5a4f316fdb1adb42", + "isContract": true, + "name": "EURC" + }, + { + "addr": "0x7830f646E6cb7460eF1069E4Fec8CF5B10F7BBea", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_EURC" + }, + { + "addr": "0xb682c840B5F4FC58B20769E691A6fa1305A501a2", + "isContract": true, + "name": "MOONWELL_EURC" + }, + { + "addr": "0x5a4E19842e09000a582c20A4f524C26Fb48Dd4D0", + "isContract": true, + "name": "GAUNTLET_MULTISIG" + }, + { + "addr": "0xEDfa23602D0EC14714057867A78d01e94176BEA0", + "isContract": true, + "name": "wrsETH" + }, + { + "addr": "0xd7221b10FBBC1e1ba95Fd0B4D031C15f7F365296", + "name": "CHAINLINK_rsETH_ETH", + "isContract": true + }, + { + "addr": "0x79C613B4f07080963C3B0CA58Eb2745dD4C744A5", + "name": "CHAINLINK_wrsETH_COMPOSITE_ORACLE_DEPRECATED", + "isContract": true + }, + { + "addr": "0x63f9f904CE2912853C2F7bb43dD1c1A6136F09b1", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_wrsETH" + }, + { + "addr": "0xfC41B49d064Ac646015b459C522820DB9472F4B5", + "isContract": true, + "name": "MOONWELL_wrsETH" + }, + { + "addr": "0xAf3642bAc06cDA85340ECf18D40b8Bf89958B69E", + "isContract": false, + "name": "DEFENDER_RELAYER" + }, + { + "addr": "0x84eAF5e855514685927B75876e0C9798895C249A", + "isContract": true, + "name": "PROPOSAL_VIEW" + }, + { + "addr": "0x7CEEf5D34448E127252f621EDfFCb57DCDBac5b1", + "isContract": true, + "name": "F-AERO_MULTISIG" + }, + { + "addr": "0xA090dD1a701408Df1d4d0B85b716c87565f90467", + "isContract": true, + "name": "MORPHO_PUBLIC_ALLOCATOR" + }, + { + "addr": "0x996a5b8d983FA76A1555730E01c6117D90A4E6a3", + "name": "CYPHER_EXECUTOR", + "isContract": false + }, + { + "addr": "0x3cb7367aC1E6a439dA1f1717f8055f02E3C9d56e", + "name": "CYPHER_BENEFICIARY", + "isContract": false + }, + { + "addr": "0xDE9255FB1A82dAAaCEFCE845dAdAf6635734FC58", + "name": "CYPHER_ADMIN", + "isContract": true + }, + { + "addr": "0x9E3ca32B18316f022fdFae503edA7E788e112AC6", + "isContract": true, + "name": "CYPHER_AUTO_LOAD" + }, + { + "addr": "0xF08CEF2EE2e5BE584a581209637B02637F312072", + "isContract": true, + "name": "CYPHER_ERC4626_RATE_LIMITED_ALLOWANCE" + }, + { + "addr": "0xc15d9944dAefE2dB03e53bef8DDA25a56832C5fe", + "isContract": true, + "name": "CHAINLINK_WELL_USD" + }, + { + "addr": "0x2A62AC4f8BE9E07bB0686c070A811027452D4dA1", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_WELL" + }, + { + "addr": "0xdC7810B47eAAb250De623F0eE07764afa5F71ED1", + "isContract": true, + "name": "MOONWELL_WELL" + }, + { + "addr": "0x2330aaE3bca5F05169d5f4597964D44522F62930", + "isContract": true, + "name": "CHAINLINK_USDS_USD" + }, + { + "addr": "0x820c137fa70c8691f0e44dc420a5e53c168921dc", + "isContract": true, + "name": "USDS" + }, + { + "addr": "0x310FBf531Ba386B0f4Cc207dcdE9f8BDBfdBdB52", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_USDS" + }, + { + "addr": "0xb6419c6C2e60c4025D6D06eE4F913ce89425a357", + "isContract": true, + "name": "MOONWELL_USDS" + }, + { + "addr": "0x236aa50979d5f3de3bd1eeb40e81137f22ab794b", + "isContract": true, + "name": "TBTC" + }, + { + "addr": "0x6D75BFB5A5885f841b132198C9f0bE8c872057BF", + "isContract": true, + "name": "CHAINLINK_TBTC_USD" + }, + { + "addr": "0x13820AA528Dc5Ce2dE39F9A4495272e9500452C2", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_TBTC" + }, + { + "addr": "0x9A858ebfF1bEb0D3495BB0e2897c1528eD84A218", + "isContract": true, + "name": "MOONWELL_TBTC" + }, + { + "addr": "0xecac9c5f704e954931349da37f60e39f515c11c1", + "isContract": true, + "name": "LBTC" + }, + { + "addr": "0xb9059d6ace87b699e67ec750fe4399d29797d232", + "isContract": true, + "name": "CHAINLINK_LBTC_BTC_COMPOSITE_ORACLE" + }, + { + "addr": "0x01177F591C4D4fC89cDEE039f7E17d7412CE9A7b", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_LBTC" + }, + { + "addr": "0x10fF57877b79e9bd949B3815220eC87B9fc5D2ee", + "isContract": true, + "name": "MOONWELL_LBTC" + }, + { + "addr": "0x0b3e328455c4059EEb9e3f84b5543F74E24e7E1b", + "isContract": true, + "name": "VIRTUAL" + }, + { + "addr": "0xEaf310161c9eF7c813A14f8FEF6Fb271434019F7", + "isContract": true, + "name": "CHAINLINK_VIRTUAL_USD" + }, + { + "addr": "0x048442d10E4c54655440f1C580bfcd27961b5bD8", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_VIRTUAL" + }, + { + "addr": "0xdE8Df9d942D78edE3Ca06e60712582F79CFfFC64", + "isContract": true, + "name": "MOONWELL_VIRTUAL" + }, + { + "addr": "0xE1bBF1304584895A215eB3478eAdEF2AaFF5D63f", + "isContract": true, + "name": "RESERVE_WELL_HOLDING_DEPOSIT" + }, + { + "addr": "0x8373155335839e3D078f3F224E8B6618Fc26eF17", + "isContract": true, + "name": "RESERVE_AUTOMATION_USDC" + }, + { + "addr": "0x89b89c30E2f60Bd30059c3924eF5b8c0Fcd1B64A", + "isContract": true, + "name": "RESERVE_AUTOMATION_USDBC" + }, + { + "addr": "0x9f2ca3c6Cd1dddb7aD473a0a893C3104E2af15Ad", + "isContract": true, + "name": "RESERVE_AUTOMATION_DAI" + }, + { + "addr": "0x064D8Cb3B7a22F4cFBdd602eBC7E722Bb71405D8", + "isContract": true, + "name": "RESERVE_AUTOMATION_WETH" + }, + { + "addr": "0x48bc4876D33Db30929c373c3B949b66CB8d641F3", + "isContract": true, + "name": "RESERVE_AUTOMATION_cbETH" + }, + { + "addr": "0xbd22DaFeF550094A32f388CD256FE133a0A14387", + "isContract": true, + "name": "RESERVE_AUTOMATION_wstETH" + }, + { + "addr": "0xEfE30785362225106367039971d82715dcB35192", + "isContract": true, + "name": "RESERVE_AUTOMATION_rETH" + }, + { + "addr": "0xc7840e86A0aa22c23BCbC153CE61f6009733bf2C", + "isContract": true, + "name": "RESERVE_AUTOMATION_AERO" + }, + { + "addr": "0x75494780E76bB41c0fDf29DBA4b2Ce82501c12b0", + "isContract": true, + "name": "RESERVE_AUTOMATION_weETH" + }, + { + "addr": "0x83D37e3df05F1507667AF4dfc83Ec8A38Cf2dA08", + "isContract": true, + "name": "RESERVE_AUTOMATION_cbBTC" + }, + { + "addr": "0x7bBe5972e01BAc64fE3AD7EFfBa6D164f0a1F15f", + "isContract": true, + "name": "RESERVE_AUTOMATION_EURC" + }, + { + "addr": "0xe34D7D109B97e1b1DAc9A9920e6A6769814Ac7eE", + "isContract": true, + "name": "RESERVE_AUTOMATION_wrsETH" + }, + { + "addr": "0xA078017f827DC7B8540C98A3bF7b2153B2aF6cB3", + "isContract": true, + "name": "RESERVE_AUTOMATION_USDS" + }, + { + "addr": "0x84C74431200Bcd3Ba4b557024734891857b43354", + "isContract": true, + "name": "RESERVE_AUTOMATION_TBTC" + }, + { + "addr": "0xf8f7b937a4CC6Cc16b600B3611ce0c1152a5b3F9", + "isContract": true, + "name": "RESERVE_AUTOMATION_LBTC" + }, + { + "addr": "0x665B7dD0260AE7a7Dd57E7F4278efdb6262c6993", + "isContract": true, + "name": "RESERVE_AUTOMATION_VIRTUAL" + }, + { + "addr": "0xc2dA00D538237822e3c7dcb95114FA1474e4c884", + "isContract": true, + "name": "CHAINLINK_ETH_USD_OEV_WRAPPER_DEPRECATED" + }, + { + "addr": "0xfEA70a74d94A6b6F9764DB9C4867bBE4678A5Da6", + "isContract": true, + "name": "CHAINLINK_BTC_USD_OEV_WRAPPER" + }, + { + "addr": "0x945ab3891D7963214833B4D51F54f068c8e6b55e", + "isContract": true, + "name": "CHAINLINK_EURC_USD_OEV_WRAPPER" + }, + { + "addr": "0x605F14438A6B44a78975FA6BEC37F041687a8bAe", + "isContract": true, + "name": "CHAINLINK_WELL_USD_OEV_WRAPPER" + }, + { + "addr": "0xF655eeDeDE0cD9f7a3de5E8018909c429dCfbf9B", + "isContract": true, + "name": "CHAINLINK_USDS_USD_OEV_WRAPPER" + }, + { + "addr": "0xd46e01f8517319784c58dFe2004440999a75Ea66", + "isContract": true, + "name": "CHAINLINK_TBTC_USD_OEV_WRAPPER" + }, + { + "addr": "0xF6475307E139d77BaCEf384eeEbbC2424C059c8F", + "name": "JUMP_RATE_IRM_MOONWELL_USDC_MIP_X18", + "isContract": true + }, + { + "addr": "0x59427E4e2EEDC6E7366a72CC91Bf324d2d35E88c", + "name": "JUMP_RATE_IRM_MOONWELL_USDC_MIP_X20", + "isContract": true + }, + { + "addr": "0xc57723C94e9F7524aaDD2F6eeeC6D640BCd1FDca", + "name": "JUMP_RATE_IRM_MOONWELL_WETH_MIP_X20", + "isContract": true + }, + { + "addr": "0xC19B9FF59E445E267283ca6618Ea647268F200b0", + "isContract": true, + "name": "CHAINLINK_VIRTUAL_USD_OEV_WRAPPER" + }, + { + "addr": "0xBAa5CC21fd487B8Fcc2F632f3F4E8D37262a0842", + "isContract": true, + "name": "MORPHO" + }, + { + "addr": "0xe95e258bb6615d47515Fc849f8542dA651f12bF6", + "isContract": true, + "name": "CHAINLINK_MORPHO_USD" + }, + { + "addr": "0xfeA5a5927645C0DC5C1E740Ec1B24AD320c7e58f", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_MORPHO" + }, + { + "addr": "0x6308204872BdB7432dF97b04B42443c714904F3E", + "isContract": true, + "name": "MOONWELL_MORPHO" + }, + { + "addr": "0xcb585250f852c6c6bf90434ab21a00f02833a4af", + "isContract": true, + "name": "cbXRP" + }, + { + "addr": "0x9f0C1dD78C4CBdF5b9cf923a549A201EdC676D34", + "isContract": true, + "name": "CHAINLINK_cbXRP_USD" + }, + { + "addr": "0xcB95579c706144f3150f7C3b1BD3F24A48d3463e", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_cbXRP" + }, + { + "addr": "0xb4fb8fed5b3AaA8434f0B19b1b623d977e07e86d", + "isContract": true, + "name": "MOONWELL_cbXRP" + }, + { + "addr": "0x08eDEbFFaE68970DCf751baa826182b3a4aCFC05", + "isContract": true, + "name": "ANTHIAS_MULTISIG" + }, + { + "addr": "0x09f96462CA418aCf8f4570149d1533Ab5030EAdC", + "isContract": false, + "name": "ANTHIAS_EOA" + }, + { + "addr": "0x8BB4C975Ff3c250e0ceEA271728547f3802B36Fd", + "isContract": true, + "name": "MERKLE_CAMPAIGN_CREATOR" + }, + { + "addr": "0xFf62A7c278C62eD665133147129245053Bbf5918", + "isContract": true, + "name": "MORPHO_FACTORY_V1_1" + }, + { + "addr": "0x2DC205F24BCb6B311E5cdf0745B0741648Aebd3d", + "isContract": true, + "name": "MORPHO_CHAINLINK_ORACLE_FACTORY" + }, + { + "addr": "0x7e860098F58bBFC8648a4311b374B1D669a2bc6B", + "isContract": true, + "name": "CHAINLINK_USDC_USD" + }, + { + "addr": "0x245951c8a17Dd700a35a3CB6E2007C3E8D133F0b", + "isContract": true, + "name": "MORPHO_CHAINLINK_WELL_USD_ORACLE_DEPRECATED" + }, + { + "addr": "0xd4669fCee3BE73b51438ad1f1debEB3505Eab308", + "isContract": false, + "name": "LUKE_EOA" + }, + { + "addr": "0xF4d4fCDdE388408C7A295E1C34C7B204bC0b4BAC", + "isContract": true, + "name": "llUSDC_METAMORPHO_VAULT" + }, + { + "addr": "0xE1bA476304255353aEF290e6474A417D06e7b773", + "isContract": true, + "name": "meUSDC_METAMORPHO_VAULT" + }, + { + "addr": "0x7300B37DfdfAb110d83290A29DfB31B1740219fE", + "isContract": true, + "name": "MAMO" + }, + { + "addr": "0xeF7541b388a77C1709a3d44BfBfC5c1ED3F0Ac94", + "isContract": true, + "name": "CHAINLINK_MAMO_USD" + }, + { + "addr": "0x6D8CB0C4C5caA9876939cB6e5EED8ca84d474c0c", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_MAMO" + }, + { + "addr": "0x2F90Bb22eB3979f5FfAd31EA6C3F0792ca66dA32", + "isContract": true, + "name": "MOONWELL_MAMO" + }, + { + "addr": "0xb62f6CcE22d414483c3BC4Dea6f4Fe6B6dF50239", + "isContract": true, + "name": "CHAINLINK_WELL_USD_ORACLE_IMPL_DEPRECATED" + }, + { + "addr": "0x3fCA08493283E79cbD1E733Ca3Cb8eC8C6074deC", + "isContract": true, + "name": "CHAINLINK_ORACLE_PROXY_ADMIN" + }, + { + "addr": "0xAEeE6335f50e1f8aF924DF0742b1879C9761F5f5", + "isContract": true, + "name": "CHAINLINK_WELL_USD_ORACLE_PROXY" + }, + { + "addr": "0x71FBaD6c2200C8A5B89380f9B6bb8a35d411c852", + "isContract": true, + "name": "MORPHO_CHAINLINK_WELL_USD_ORACLE" + }, + { + "addr": "0x4073bA1AF0bD159BF5c6F85D2FC9f43EEf43b02A", + "isContract": true, + "name": "CHAINLINK_MAMO_USD_ORACLE_IMPL" + }, + { + "addr": "0xF4DCcaE864EDF2b218B40A950c4407C3383Dadb9", + "isContract": true, + "name": "CHAINLINK_MAMO_USD_ORACLE_PROXY" + }, + { + "addr": "0x18d1325e8528E3ceafBf9a77F3bE3f76Fec42D5C", + "isContract": true, + "name": "MORPHO_CHAINLINK_MAMO_USD_ORACLE" + }, + { + "addr": "0xFf37a7467a80EF462Ad5d73f67F619Ca2dbb2D4B", + "isContract": true, + "name": "CHAINLINK_stkWELL_USD_ORACLE_IMPL" + }, + { + "addr": "0x593355Faef3075AF1b20Ca22FeDAbF6F3D2FD66C", + "isContract": true, + "name": "CHAINLINK_stkWELL_USD_ORACLE_PROXY" + }, + { + "addr": "0xc842d95b9C35bf97842110408A8C501645Fb1722", + "isContract": true, + "name": "MORPHO_CHAINLINK_stkWELL_USD_ORACLE" + }, + { + "addr": "0x74Cbb1E8B68dDD13B28684ECA202a351afD45EAa", + "isContract": true, + "name": "F-DEVGRANT" + }, + { + "addr": "0xe8dD07CCf5BC4922424140E44Eb970F5950725ef", + "isContract": true, + "name": "CHAINLINK_wrsETH_ETH_EXCHANGE_RATE" + }, + { + "addr": "0xccC994a46c0d81c934fd6c82d89f626aee336ade", + "isContract": true, + "name": "CHAINLINK_wrsETH_COMPOSITE_ORACLE" + }, + { + "addr": "0xadcC226082E878371a3fc33c1f914dad7FB6a28D", + "isContract": false, + "name": "BAD_DEBT_REPAYER_EOA" + }, + { + "addr": "0x1796720C9441F8f18a3AA570aB7c10597a57C08e", + "isContract": true, + "name": "MWETH_OWNER_WRAPPER_IMPL" + }, + { + "addr": "0x82e5e038A1D93f371f02768b09B2C6C4b98f6250", + "isContract": true, + "name": "MWETH_OWNER_WRAPPER" + }, + { + "addr": "0xab05F7216B4ecD0594E703F21fb0dE6183BFeCF3", + "isContract": true, + "name": "OEV_PROTOCOL_FEE_REDEEMER" + }, + { + "addr": "0x57DA741aD933869cC9EBfb9668288053A0738f3c", + "isContract": true, + "name": "CHAINLINK_ETH_USD_OEV_WRAPPER" + }, + { + "addr": "0xB5421a112f07C31820f413852E7e39E2d765e4B8", + "isContract": true, + "name": "CHAINLINK_OEV_MORPHO_WRAPPER_IMPL" + }, + { + "addr": "0x1E6A29666288a310326B37d823Fe4Ea3937424D2", + "isContract": true, + "name": "CHAINLINK_RETH_ETH_EXCHANGE_RATE" + }, + { + "addr": "0x98819cC6C48eE912508454b0f1f4e68BD35ca313", + "isContract": true, + "name": "CHAINLINK_RETH_ETH_EXCHANGE_RATE_ORACLE" + }, + { + "addr": "0x24b53b15dca212d7ba6da287b5e2b801db37c24e", + "isContract": true, + "name": "MORPHO_VIEWS_V2_IMPLEMENTATION" + }, + { + "addr": "0x7465c2cfa4a9ab6acaacbf8eaa28257f6a1d1486", + "isContract": true, + "name": "MORPHO_VIEWS_V2_PROXY_ADMIN" + }, + { + "addr": "0x7fc0dbc713649b96e984b2a5935016d3a5d1ed31", + "isContract": true, + "name": "MORPHO_VIEWS_V2_PROXY" + }, + { + "addr": "0xbB2F06CeAE42CBcF5559Ed0713538c8892D977c9", + "isContract": true, + "name": "MORPHO_meUSDC_VAULT_V2" + }, + { + "addr": "0xF03499F8AE0b883e630558F23760a6A89b1dae7e", + "isContract": true, + "name": "MORPHO_VAULT_V2_VIEWS_IMPLEMENTATION" + }, + { + "addr": "0x8D189997ccD6ab6909eF89836e5bcEf94599Cce0", + "isContract": true, + "name": "MORPHO_VAULT_V2_VIEWS_PROXY" + }, + { + "addr": "0x0eaB3B9aE08B43077aD1Aeb9820462FAF99BCEc8", + "isContract": true, + "name": "DAI_ORACLE_OEV_WRAPPER" + }, + { + "addr": "0xb7967D184907737a955f39a8067Bc1a0CC313292", + "isContract": true, + "name": "CHAINLINK_USDC_USD_OEV_WRAPPER" + }, + { + "addr": "0x67996D1ff7a3711a91E2839d1059Fcb950C0495D", + "isContract": true, + "name": "cbETHETH_ORACLE_OEV_WRAPPER" + }, + { + "addr": "0x3623c921bfD9d7E9D88E5CBb436B68bE2C2Bc0B7", + "isContract": true, + "name": "CHAINLINK_AERO_ORACLE_OEV_WRAPPER" + }, + { + "addr": "0x6F0cC02e5a7640B28F538fcc06bCA3BdFA57d1BB", + "isContract": true, + "name": "CHAINLINK_BTC_USD_OEV_WRAPPER_DEPRECATED" + }, + { + "addr": "0x48F86A23aDE243F7a1028108aA65274FC84f382F", + "isContract": true, + "name": "CHAINLINK_EURC_USD_OEV_WRAPPER_DEPRECATED" + }, + { + "addr": "0x1E0E8bcFb5FFa86749B8b89fb6e055337Ba74A39", + "isContract": true, + "name": "CHAINLINK_WELL_USD_OEV_WRAPPER_DEPRECATED" + }, + { + "addr": "0xAeC8E8E3696fc5fcd954eb3ebC26B72FC2FE8E8e", + "isContract": true, + "name": "CHAINLINK_USDS_USD_OEV_WRAPPER_DEPRECATED" + }, + { + "addr": "0x94423903EaAf8638bDE262c417fEEf5E2Ec507E5", + "isContract": true, + "name": "CHAINLINK_TBTC_USD_OEV_WRAPPER_DEPRECATED" + }, + { + "addr": "0x6aa41dF8FB0deC976B59bf0824FC5fFB88ccA958", + "isContract": true, + "name": "CHAINLINK_VIRTUAL_USD_OEV_WRAPPER_DEPRECATED" + }, + { + "addr": "0x769E8D347C75502878c1844eAFaCEa3547D9a225", + "isContract": true, + "name": "CHAINLINK_MORPHO_USD_OEV_WRAPPER" + }, + { + "addr": "0xE5C91119dFF7e04cd6834a9c9D0A66380EdB4aF5", + "isContract": true, + "name": "CHAINLINK_cbXRP_USD_OEV_WRAPPER" + }, + { + "addr": "0xDBD37C274A70A8A3f92A227c843a6a8d3203afe6", + "isContract": true, + "name": "CHAINLINK_MAMO_USD_OEV_WRAPPER" + }, + { + "addr": "0xe2747A3f7dD8585eB04c7632a9561D9616454B29", + "isContract": true, + "name": "STK_GOVTOKEN_IMPL_V2" + }, + { + "addr": "0x5B710010586C1b728B047c3E42473c700eeA4026", + "isContract": true, + "name": "PAUSE_GUARDIAN" + }, + { + "addr": "0xb84543e036054E2cD5394A9D99fa701Eef666df4", + "isContract": true, + "name": "WORMHOLE_BRIDGE_ADAPTER_IMPL_V3" + }, + { + "addr": "0xf81094eedd37DA759E837D727D940f14b18b6c76", + "isContract": true, + "name": "VOTE_COLLECTION_IMPL_V2" + }, + { + "addr": "0xacfE6019Ed1A7Dc6f7B508C02d1b04ec88cC21bf", + "isContract": true, + "name": "VVV" + }, + { + "addr": "0xaABc55Ca55D70B034e4daA2551A224239890282F", + "isContract": true, + "name": "CHAINLINK_VVV_USD" + }, + { + "addr": "0xCF1A3322977ef557899ad2BF3056d8411EdC87A1", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_VVV" + }, + { + "addr": "0xD64BCb70C613a6D1F4D7D57Ba64bb4a0767A9682", + "isContract": true, + "name": "MOONWELL_VVV" + }, + { + "addr": "0x0208810d9d0D639D6e212Ad1B42cFB22Ab3E51A2", + "isContract": true, + "name": "CHAINLINK_VVV_USD_OEV_WRAPPER" + }, + { + "addr": "0x7599aa7F32bda9Ef644f6cB0482c64fC26f68799", + "isContract": true, + "name": "WORMHOLE_BRIDGE_ADAPTER_IMPL_V4" + }, + { + "addr": "0x3fBB877C8d5cF56b30FD29D21E865cA58f127472", + "isContract": true, + "name": "VOTE_COLLECTION_IMPL_V3" + }, + { + "addr": "0x78Feb72aeA00B912ac45438e0764A02213266568", + "isContract": true, + "name": "WORMHOLE_BRIDGE_ADAPTER_IMPL_V5" + }, + { + "addr": "0x2481BFB0DfA54Dc155011eF2E90ADAB9556b8D99", + "isContract": true, + "name": "WORMHOLE_BRIDGE_ADAPTER_IMPL_V6" + }, + { + "addr": "0x4916EC6773e14CA873be3d65022BB122CB8b89a2", + "isContract": true, + "name": "DAI_ORACLE_OEV_WRAPPER_DEPRECATED_V3" + }, + { + "addr": "0x7600b9068bB0aFEA6adf70eD6CD0f8492117236d", + "isContract": true, + "name": "CHAINLINK_USDC_USD_OEV_WRAPPER_DEPRECATED_V3" + }, + { + "addr": "0xeb083d234ec636A10325ea42bCbbE09Aa56d1547", + "isContract": true, + "name": "CHAINLINK_ETH_USD_OEV_WRAPPER_DEPRECATED_V3" + }, + { + "addr": "0xdC79C7D5D4dA3b237D2d078a1ee06F2FD1FfEf98", + "isContract": true, + "name": "CHAINLINK_AERO_ORACLE_OEV_WRAPPER_DEPRECATED_V3" + }, + { + "addr": "0x6a3c960Bcfb69BAe78f706c9c6B168bB7693E119", + "isContract": true, + "name": "CHAINLINK_BTC_USD_OEV_WRAPPER_DEPRECATED_V3" + }, + { + "addr": "0xd5669e0175D01cc5F6Be9607129668D0833DcbEC", + "isContract": true, + "name": "CHAINLINK_EURC_USD_OEV_WRAPPER_DEPRECATED_V3" + }, + { + "addr": "0xBA5220805E43194Ff12A434fBb745f3a2E1a09db", + "isContract": true, + "name": "CHAINLINK_WELL_USD_OEV_WRAPPER_DEPRECATED_V3" + }, + { + "addr": "0x6621069673C61a143DaDF376389e82DA372BF405", + "isContract": true, + "name": "CHAINLINK_USDS_USD_OEV_WRAPPER_DEPRECATED_V3" + }, + { + "addr": "0xBfAaA8B347dA80B909504d403CB4C8F245e921ab", + "isContract": true, + "name": "CHAINLINK_TBTC_USD_OEV_WRAPPER_DEPRECATED_V3" + }, + { + "addr": "0x12EC8CfEbCF5728774925feC1502733f906CB6e3", + "isContract": true, + "name": "CHAINLINK_VIRTUAL_USD_OEV_WRAPPER_DEPRECATED_V3" + }, + { + "addr": "0x09793267120dbF519B2B0e8Ea77A689e2Ba453F0", + "isContract": true, + "name": "CHAINLINK_MORPHO_USD_OEV_WRAPPER_DEPRECATED_V3" + }, + { + "addr": "0xf2Ac6F14A094A82A6f9489364CdE9e1ba2548d49", + "isContract": true, + "name": "CHAINLINK_cbXRP_USD_OEV_WRAPPER_DEPRECATED_V3" + }, + { + "addr": "0xfbA86a013f7FD93B5454e147242CF2Bf419e120D", + "isContract": true, + "name": "CHAINLINK_MAMO_USD_OEV_WRAPPER_DEPRECATED_V3" + }, + { + "addr": "0xD6aFC41DD78043C55273e217f69E5e1248793B7A", + "isContract": true, + "name": "CHAINLINK_VVV_USD_OEV_WRAPPER_DEPRECATED_V3" + }, + { + "addr": "0xb22694F7280DB8832B37240C4e40C240a4eecC8a", + "isContract": true, + "name": "CHAINLINK_OEV_MORPHO_WRAPPER_IMPL_V2" + }, + { + "addr": "0x701551a3cd30A29cCC012e8f160fB2Cac9b0f5Af", + "isContract": true, + "name": "VOTING_POWER_AGGREGATOR_IMPL" + }, + { + "addr": "0xb3a9E0DCf37658a48aa9f018C44f90378ddD4357", + "isContract": true, + "name": "VOTING_POWER_AGGREGATOR" + }, + { + "addr": "0x9d465d56d235674693A158Af40c8d53ddE59B0CE", + "isContract": true, + "name": "VOTE_COLLECTION_V2_IMPL" + }, + { + "addr": "0xcD6b4B047e55A513b8efc2B61F58B9f7Fa6096FC", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_USDC_MIP_X66" + }, + { + "addr": "0xa1a0cD8f2A37689a84B93814Cb4BFAF356620933", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_wstETH_MIP_X66" + }, + { + "addr": "0xaa144B847f55efb63C8a8651541fD6af1cb23BB1", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_cbBTC_MIP_X66" + }, + { + "addr": "0x1fB29b6632Ad7c590Df8Cf1498D4952B95170101", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_EURC_MIP_X66" + }, + { + "addr": "0xe214B2BC13DCf0FCf1481f75918C84Eb5Bd7c2Db", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_MAMO_MIP_X66" + }, + { + "addr": "0x1e55782FeDC3e09c40A90f5A67DEcFfB55EcD412", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_MORPHO_MIP_X66" + }, + { + "addr": "0x3C10e4B6d60d4b2ec88aBb5aa1F613f030872B5a", + "isContract": true, + "name": "JUMP_RATE_IRM_MOONWELL_USDS_MIP_X66" + } +] diff --git a/plan/agw/research/preset-mainnet-2026-10-15/read-only-probe.cjs b/plan/agw/research/preset-mainnet-2026-10-15/read-only-probe.cjs new file mode 100644 index 00000000..04ca3a0d --- /dev/null +++ b/plan/agw/research/preset-mainnet-2026-10-15/read-only-probe.cjs @@ -0,0 +1,8 @@ +const {createPublicClient,http,keccak256,getAddress,parseAbi}=require(process.cwd()+'/node_modules/viem');const fs=require('fs'); +const configs=[ +[1,'https://ethereum-rpc.publicnode.com',{'Uniswap V3':'0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45','Aave V3':'0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2','EigenLayer':'0x858646372CC42E1A627fcE94aa7A7033e7CF075A'}], +[8453,'https://base-rpc.publicnode.com',{'Uniswap V3':'0x2626664c2603336E57B271c5C0b26F421741e481','Aave V3':'0xA238Dd80C259a72e81d7e4664a9801593F98d1c5','Moonwell USDC':'0xEdc817A28E8B93B03976FBd4a3dDBc9f7D176c22','Moonwell WETH':'0x628ff693426583D9a7FB391E54366292F509D457','Moonwell controller':'0xfBb21d0380beE3312B33c4353c8936a0F13EF26C'}], +[42161,'https://arbitrum-one-rpc.publicnode.com',{'Uniswap V3':'0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45','Aave V3':'0x794a61358D6845594F94dc1DB02A252b5b4814aD'}], +[56,'https://bsc-rpc.publicnode.com',{'PancakeSwap V3':'0x13f4EA83D0bd40E75C8222255bc855a974568Dd4','Aave V3':'0x6807dc923806fE8Fd134338EABCA509979a7e0cB','Venus USDT':'0xfD5840Cd36d94D7229439859C0112a4185BC0255','Venus USDC':'0xecA88125a5ADbe82614ffC12D0DB554E2e2867C8','Venus controller':'0xfD36E2c2a6789Db23113685031d7F16329158384'}], +]; +(async()=>{const result=await Promise.all(configs.map(async([chainId,rpc,entries])=>{const c=createPublicClient({transport:http(rpc,{timeout:15000,retryCount:1})});if(await c.getChainId()!==chainId)throw Error('Wrong chain');const block=await c.getBlockNumber();const contracts=await Promise.all(Object.entries(entries).map(async([name,a])=>{const address=getAddress(a.toLowerCase());const code=await c.getCode({address,blockNumber:block});if(!code||code==='0x')throw Error('No code '+name);const r={name,address,bytes:(code.length-2)/2,codeHash:keccak256(code)};if(/(Moonwell|Venus) (USDT|USDC|WETH)/.test(name))r.underlying=await c.readContract({address,abi:parseAbi(['function underlying() view returns(address)']),functionName:'underlying',blockNumber:block});return r;}));return{chainId,rpc,block:String(block),contracts};}));fs.writeFileSync('plan/agw/research/preset-mainnet-2026-10-15/rpc-verification.json',JSON.stringify(result,null,2)+'\n');console.log(result.map(x=>({chainId:x.chainId,block:x.block,contracts:x.contracts.length})));})().catch(e=>{console.error(e.shortMessage||e.message);process.exitCode=1;}); diff --git a/plan/agw/research/preset-mainnet-2026-10-15/rpc-verification.json b/plan/agw/research/preset-mainnet-2026-10-15/rpc-verification.json new file mode 100644 index 00000000..068bef48 --- /dev/null +++ b/plan/agw/research/preset-mainnet-2026-10-15/rpc-verification.json @@ -0,0 +1,124 @@ +[ + { + "chainId": 1, + "rpc": "https://ethereum-rpc.publicnode.com", + "block": "26194775", + "contracts": [ + { + "name": "Uniswap V3", + "address": "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45", + "bytes": 24497, + "codeHash": "0x6ec798e80f3a19de650826338677604e54d6664f44a33b53a20b22b1939f402e" + }, + { + "name": "Aave V3", + "address": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", + "bytes": 2400, + "codeHash": "0x96107dc4006b4c7fecd1827cfb275ffeef31e6194cd50466f85f8eb24ccf2679" + }, + { + "name": "EigenLayer", + "address": "0x858646372CC42E1A627fcE94aa7A7033e7CF075A", + "bytes": 2151, + "codeHash": "0x073c6ec3b11b1c79a5e70af69992743e1f9857ca449d45cf954c164b0e464a9a" + } + ] + }, + { + "chainId": 8453, + "rpc": "https://base-rpc.publicnode.com", + "block": "52620057", + "contracts": [ + { + "name": "Uniswap V3", + "address": "0x2626664c2603336E57B271c5C0b26F421741e481", + "bytes": 24497, + "codeHash": "0x38bd640f47df62b2fd5a6755a63f4976ad847dc9b946ae0d145d21d16bb124e4" + }, + { + "name": "Aave V3", + "address": "0xA238Dd80C259a72e81d7e4664a9801593F98d1c5", + "bytes": 1933, + "codeHash": "0xffcb26fbebbe09d9b0d8baef76a1fa218989be6c279b7acf9865d8fb6e0718ce" + }, + { + "name": "Moonwell USDC", + "address": "0xEdc817A28E8B93B03976FBd4a3dDBc9f7D176c22", + "bytes": 7544, + "codeHash": "0xcd7e22e6eef009b831781d4de03f20777094f437a9719c597c45cf9725a7dca9", + "underlying": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" + }, + { + "name": "Moonwell WETH", + "address": "0x628ff693426583D9a7FB391E54366292F509D457", + "bytes": 7544, + "codeHash": "0x041dbd5067f87816c0c8d6af9992f04e71aa99c87d1a8e9fb1d27e3e7ed99985", + "underlying": "0x4200000000000000000000000000000000000006" + }, + { + "name": "Moonwell controller", + "address": "0xfBb21d0380beE3312B33c4353c8936a0F13EF26C", + "bytes": 1412, + "codeHash": "0x86a2f6bebe3e171b8d4231544a9925e94e586139762d0164d37c34831a3d0240" + } + ] + }, + { + "chainId": 42161, + "rpc": "https://arbitrum-one-rpc.publicnode.com", + "block": "514919525", + "contracts": [ + { + "name": "Uniswap V3", + "address": "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45", + "bytes": 24497, + "codeHash": "0x209f9820ed7257d51c2f96ee837e8ec057b44774899f4be16fc45bd30cbb16f6" + }, + { + "name": "Aave V3", + "address": "0x794a61358D6845594F94dc1DB02A252b5b4814aD", + "bytes": 2400, + "codeHash": "0xf168c2e9e4d04292c7d5d526a9a917175a44369ab63a2f9997537acf0ffaaf2e" + } + ] + }, + { + "chainId": 56, + "rpc": "https://bsc-rpc.publicnode.com", + "block": "127702568", + "contracts": [ + { + "name": "PancakeSwap V3", + "address": "0x13f4EA83D0bd40E75C8222255bc855a974568Dd4", + "bytes": 24316, + "codeHash": "0x25cbde77f2ef6d474c31f738e67ab99e604471170d8a0ab4f544cbaba969d078" + }, + { + "name": "Aave V3", + "address": "0x6807dc923806fE8Fd134338EABCA509979a7e0cB", + "bytes": 1933, + "codeHash": "0xa2aac688c1cbeae86c0b468a926632c775c7a40f1b5dec59948f9f1562c53e9e" + }, + { + "name": "Venus USDT", + "address": "0xfD5840Cd36d94D7229439859C0112a4185BC0255", + "bytes": 4744, + "codeHash": "0xd6e00b8c8f24fb40df4eaeb95fcce7f605177339f239d1b04b2c21664c1b3ab2", + "underlying": "0x55d398326f99059fF775485246999027B3197955" + }, + { + "name": "Venus USDC", + "address": "0xecA88125a5ADbe82614ffC12D0DB554E2e2867C8", + "bytes": 4744, + "codeHash": "0xd6e00b8c8f24fb40df4eaeb95fcce7f605177339f239d1b04b2c21664c1b3ab2", + "underlying": "0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d" + }, + { + "name": "Venus controller", + "address": "0xfD36E2c2a6789Db23113685031d7F16329158384", + "bytes": 1508, + "codeHash": "0x7fc5c25e2e62f7d22d3340e21d5faf867c0039b404c02bb26ba8972e0be2ac97" + } + ] + } +] diff --git a/plan/agw/research/preset-mainnet-2026-10-15/sources.json b/plan/agw/research/preset-mainnet-2026-10-15/sources.json new file mode 100644 index 00000000..0de18f79 --- /dev/null +++ b/plan/agw/research/preset-mainnet-2026-10-15/sources.json @@ -0,0 +1,48 @@ +[ + { + "url": "https://raw.githubusercontent.com/bgd-labs/aave-address-book/main/src/AaveV3Ethereum.sol", + "file": "AaveV3Ethereum.sol", + "sha256": "afe8adbbf8fe7d709ae1d2168b8d97ccb8110fdedb572fc2120ecae10ae7588b" + }, + { + "url": "https://raw.githubusercontent.com/bgd-labs/aave-address-book/main/src/AaveV3Base.sol", + "file": "AaveV3Base.sol", + "sha256": "135e2f325b53140c5a82895cf40debc80323fed77bd3ebb240a8d00248ba02ae" + }, + { + "url": "https://raw.githubusercontent.com/bgd-labs/aave-address-book/main/src/AaveV3Arbitrum.sol", + "file": "AaveV3Arbitrum.sol", + "sha256": "6b8f9a12a904a2c13d59423fe9c60fd66ec868761704cbcc776d0c2fe1510b1c" + }, + { + "url": "https://raw.githubusercontent.com/bgd-labs/aave-address-book/main/src/AaveV3BNB.sol", + "file": "AaveV3BNB.sol", + "sha256": "190523aa7f4bd0654e4155eed60a88852b374f3bc28855750a497b45f2efd36b" + }, + { + "url": "https://raw.githubusercontent.com/moonwell-fi/moonwell-contracts-v2/main/chains/8453.json", + "file": "moonwell-8453.json", + "sha256": "9c57bfb2bd1c17e384c4113b6c82de05b2b4bc4671c2fb25202babe90dd2079d" + }, + { + "url": "https://raw.githubusercontent.com/VenusProtocol/venus-protocol/develop/deployments/bscmainnet_addresses.json", + "file": "venus-bscmainnet.json", + "sha256": "d126b3cb0ac0221cbeb20ac20f5f63bfec458fd79f03ab92c7ccee1bb63aedc0" + }, + { + "url": "https://docs.lido.fi/deployed-contracts/", + "purpose": "Official Lido deployed addresses and caller/recipient/function semantics; read October 15" + }, + { + "url": "https://docs.lido.fi/contracts/lido/", + "purpose": "Official Lido deployed addresses and caller/recipient/function semantics; read October 15" + }, + { + "url": "https://docs.lido.fi/contracts/wsteth/", + "purpose": "Official Lido deployed addresses and caller/recipient/function semantics; read October 15" + }, + { + "url": "https://docs.lido.fi/contracts/withdrawal-queue-erc721/", + "purpose": "Official Lido deployed addresses and caller/recipient/function semantics; read October 15" + } +] diff --git a/plan/agw/research/preset-mainnet-2026-10-15/venus-bscmainnet.json b/plan/agw/research/preset-mainnet-2026-10-15/venus-bscmainnet.json new file mode 100644 index 00000000..5faf322a --- /dev/null +++ b/plan/agw/research/preset-mainnet-2026-10-15/venus-bscmainnet.json @@ -0,0 +1,324 @@ +{ + "name": "bscmainnet", + "chainId": "56", + "addresses": { + "AAVE": "0xfb6115445Bff7b52FeB98650C87f44907E58f802", + "ADA": "0x3EE2200Efb3400fAbB9AacF31297cBdD1d435D47", + "BCH": "0x8fF795a6F4D97E7887C79beA79aba5cc76444aDf", + "BETH": "0x250632378E573c6Be1AC2f97Fcdf00515d0Aa91B", + "BStockLiquidator": "0x5974Badab6911a78Ba15229045514C2C1bD42343", + "BStockLiquidator_Implementation": "0xde9734DD7AEad610Dd41FFE9Abc25C5cCf142487", + "BStockLiquidator_Proxy": "0x5974Badab6911a78Ba15229045514C2C1bD42343", + "BTCB": "0x7130d2A12B9BCbFAe4f2634d864A1Ee1Ce3Ead9c", + "BUSD": "0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56", + "CAKE": "0x0E09FaBB73Bd3Ade0a17ECC321fD13a19e81cE82", + "CheckpointView_From_JumpRateModel_base0bps_slope1000bps_jump20000bps_kink7500bps_bpy10512000_To_bpy21024000_At_1745903100": "0x747943C45eB782Db9E04f6f54Ea5f27Cc6627e4A", + "CheckpointView_From_JumpRateModel_base0bps_slope1000bps_jump20000bps_kink7500bps_bpy21024000_To_bpy42048000_At_1751250600": "0xd7079bCE4A9cA17a71787928E40252547444C3D3", + "CheckpointView_From_JumpRateModel_base0bps_slope1000bps_jump20000bps_kink7500bps_bpy42048000_To_bpy70080000_At_1768357800": "0x0c61acDC057e894eC7c282EC779b67ef654ADDCe", + "CheckpointView_From_JumpRateModel_base0bps_slope1000bps_jump25000bps_kink8000bps_bpy10512000_To_bpy21024000_At_1745903100": "0xF8e641695f89A5919DF03Edd9ECdA3D0dc89aAA9", + "CheckpointView_From_JumpRateModel_base0bps_slope1000bps_jump25000bps_kink8000bps_bpy21024000_To_bpy42048000_At_1751250600": "0xBB951B0B38ae86CeF2f3d642F5ac7591FD5D2f4b", + "CheckpointView_From_JumpRateModel_base0bps_slope1000bps_jump25000bps_kink8000bps_bpy42048000_To_bpy70080000_At_1768357800": "0x8AFaE0979c793411648e476388C83E190285c9b1", + "CheckpointView_From_JumpRateModel_base0bps_slope1000bps_jump50000bps_kink8000bps_bpy21024000_To_bpy42048000_At_1751250600": "0x8D3A052b88acF368Da24f5313901e4e63E0E78Cf", + "CheckpointView_From_JumpRateModel_base0bps_slope1000bps_jump50000bps_kink8000bps_bpy42048000_To_bpy70080000_At_1768357800": "0xdba6A250027049c4033970e224E61EDCD84eA630", + "CheckpointView_From_JumpRateModel_base0bps_slope1500bps_jump30000bps_kink6000bps_bpy10512000_To_bpy21024000_At_1745903100": "0x7857738486E813b5BCb6cA62B46F6b2ee029609B", + "CheckpointView_From_JumpRateModel_base0bps_slope1500bps_jump30000bps_kink6000bps_bpy21024000_To_bpy42048000_At_1751250600": "0x968D2f613F0517eaE22f898529c4658Db8C578BC", + "CheckpointView_From_JumpRateModel_base0bps_slope1500bps_jump30000bps_kink6000bps_bpy42048000_To_bpy70080000_At_1768357800": "0xC3723cf801cDbb8C9A79bD67B17d20cA9d5ec3ed", + "CheckpointView_From_JumpRateModel_base0bps_slope1750bps_jump25000bps_kink8000bps_bpy10512000_To_bpy21024000_At_1745903100": "0x42Ef8ecCEe0782a4E644B3EB39761fb6c696ccF2", + "CheckpointView_From_JumpRateModel_base0bps_slope2000bps_jump30000bps_kink5000bps_bpy10512000_To_bpy21024000_At_1745903100": "0x83671a928e8D4c34F9f8faD06bd8356Fdb524A0F", + "CheckpointView_From_JumpRateModel_base0bps_slope2000bps_jump30000bps_kink5000bps_bpy21024000_To_bpy42048000_At_1751250600": "0x107F2b97dcd259Aa373709bF1021aD120a2FED98", + "CheckpointView_From_JumpRateModel_base0bps_slope2000bps_jump30000bps_kink5000bps_bpy42048000_To_bpy70080000_At_1768357800": "0x30457D82246512B891DAD51ecC1deAbFB1870f8C", + "CheckpointView_From_JumpRateModel_base0bps_slope300bps_jump45000bps_kink9000bps_bpy10512000_To_bpy21024000_At_1745903100": "0xEBb072c6336f1d0a7d8BBf1c82d9C9F7D6485Fa4", + "CheckpointView_From_JumpRateModel_base0bps_slope300bps_jump45000bps_kink9000bps_bpy21024000_To_bpy42048000_At_1751250600": "0x38Dd273fE7590403f554F350a7c3c592e8227EB7", + "CheckpointView_From_JumpRateModel_base0bps_slope300bps_jump45000bps_kink9000bps_bpy42048000_To_bpy70080000_At_1768357800": "0x7c164b24B4393fe5cf5b8A1E1EBb6496EC7Db4EF", + "CheckpointView_From_JumpRateModel_base0bps_slope750bps_jump50000bps_kink8000bps_bpy10512000_To_bpy21024000_At_1745903100": "0x717dbabeCc502c8712e7646ab6801F802a997C20", + "CheckpointView_From_JumpRateModel_base0bps_slope750bps_jump5000bps_kink8000bps_bpy10512000_To_bpy21024000_At_1745903100": "0xa91617Ba1a6CCF61a70c7e4b0a2A36c7726bb3f6", + "CheckpointView_From_JumpRateModel_base0bps_slope750bps_jump5000bps_kink8000bps_bpy21024000_To_bpy42048000_At_1751250600": "0xfEA1ca128dDbAf830EFC4e0d5CD5E152AE504cC7", + "CheckpointView_From_JumpRateModel_base0bps_slope750bps_jump5000bps_kink8000bps_bpy42048000_To_bpy70080000_At_1768357800": "0x4F0cfA4a97ee2E99D58724ae8cC169F9704d458d", + "CheckpointView_From_JumpRateModel_base0bps_slope900bps_jump20000bps_kink5000bps_bpy10512000_To_bpy21024000_At_1745903100": "0x3BA66110c585Cb4032A0289bf4Cd8F983d556b10", + "CheckpointView_From_JumpRateModel_base0bps_slope900bps_jump20000bps_kink5000bps_bpy21024000_To_bpy42048000_At_1751250600": "0x44a94a5e96bc6e36f4775E6229e2487860d4b7F0", + "CheckpointView_From_JumpRateModel_base0bps_slope900bps_jump20000bps_kink5000bps_bpy42048000_To_bpy70080000_At_1768357800": "0x1Ef3b851CE40B663dBbF91B86A4EE51A4a0999C5", + "CheckpointView_From_JumpRateModel_base0bps_slope900bps_jump20000bps_kink7500bps_bpy10512000_To_bpy21024000_At_1745903100": "0x4a03AbcC888020c779bB362b4C1D2869485bDEe4", + "CheckpointView_From_JumpRateModel_base0bps_slope900bps_jump20000bps_kink7500bps_bpy21024000_To_bpy42048000_At_1751250600": "0xa84189107aF59BF132F3e7dd45DD201C0bb25bF4", + "CheckpointView_From_JumpRateModel_base0bps_slope900bps_jump35000bps_kink4500bps_bpy10512000_To_bpy21024000_At_1745903100": "0xc6cC40ca4e90d151261f6524b97C3D4997479621", + "CheckpointView_From_JumpRateModel_base0bps_slope900bps_jump35000bps_kink4500bps_bpy21024000_To_bpy42048000_At_1751250600": "0x44C49a0Df8bBfA49ED967C65db0E92BA7B40DF65", + "CheckpointView_From_JumpRateModel_base0bps_slope900bps_jump35000bps_kink4500bps_bpy42048000_To_bpy70080000_At_1768357800": "0x6F869480eEEbB66b58a930892AddC0067Fb43B20", + "CheckpointView_From_JumpRateModel_base200bps_slope10000bps_jump30000bps_kink100bps_bpy10512000_To_bpy21024000_At_1745903100": "0x06Da1E5e6Ba1E0CA26ac92907b5b30D32789426A", + "CheckpointView_From_JumpRateModel_base200bps_slope10000bps_jump30000bps_kink100bps_bpy21024000_To_bpy42048000_At_1751250600": "0xb2bd70eD38E928470B5aF2F01E799c1d3b4d8796", + "CheckpointView_From_JumpRateModel_base200bps_slope10000bps_jump30000bps_kink100bps_bpy42048000_To_bpy70080000_At_1768357800": "0x6d967293192E9Cc395f4F6D2327C09A1F3F2C920", + "CheckpointView_From_JumpRateModel_base200bps_slope1200bps_jump30000bps_kink6000bps_bpy10512000_To_bpy21024000_At_1745903100": "0xD574F5186cEEf3f4801A9A8C6fe257ef71493371", + "CheckpointView_From_JumpRateModel_base200bps_slope1200bps_jump30000bps_kink6000bps_bpy21024000_To_bpy42048000_At_1751250600": "0xf7B5F7856E0520D66c03F32D576eECD9156dAb29", + "CheckpointView_From_JumpRateModel_base200bps_slope1200bps_jump30000bps_kink6000bps_bpy42048000_To_bpy70080000_At_1768357800": "0xb0B318816537Aa1a63fb30CEca9F5f39F8bB9770", + "CheckpointView_From_JumpRateModel_base200bps_slope1500bps_jump30000bps_kink6000bps_bpy10512000_To_bpy21024000_At_1745903100": "0x0E6F99766c947F85c242b8328837b39c8bB887c6", + "CheckpointView_From_JumpRateModel_base200bps_slope1500bps_jump30000bps_kink6000bps_bpy21024000_To_bpy42048000_At_1751250600": "0x1326346bDA0BFC3AC7F5BFb0F6eA7f4302A65bCd", + "CheckpointView_From_JumpRateModel_base200bps_slope1500bps_jump30000bps_kink6000bps_bpy42048000_To_bpy70080000_At_1768357800": "0x6125BC439EE2caa2Fd737b14d0f68B364099a19E", + "CheckpointView_From_JumpRateModel_base200bps_slope2000bps_jump30000bps_kink5000bps_bpy10512000_To_bpy21024000_At_1745903100": "0xEd279B5eAde8E54175941F188d16067c6341Cd1A", + "CheckpointView_From_JumpRateModel_base200bps_slope2000bps_jump30000bps_kink5000bps_bpy21024000_To_bpy42048000_At_1751250600": "0x7611a9A201524594633B2eb5A8Ea42A9418c9811", + "CheckpointView_From_JumpRateModel_base200bps_slope2000bps_jump30000bps_kink5000bps_bpy42048000_To_bpy70080000_At_1768357800": "0xD6B3A3e73860A5b75C130bE1AfB9D76C2E572373", + "CheckpointView_From_JumpRateModel_base25bps_slope367bps_jump20000bps_kink7500bps_bpy42048000_To_bpy70080000_At_1768357800": "0x7D47671514A1b13F0E376D70fcF13B2eb2694c3A", + "CheckpointView_From_JumpRateModel_base5000bps_slope3000bps_jump30000bps_kink6000bps_bpy10512000_To_bpy21024000_At_1745903100": "0xE508AF8fE95D508EF284DDFd76610EDBef8Cb8E9", + "CheckpointView_From_JumpRateModel_base5000bps_slope3000bps_jump30000bps_kink6000bps_bpy21024000_To_bpy42048000_At_1751250600": "0xbF6BdB41dbCB5ABA54189767d113e7c5155aB70A", + "CheckpointView_From_JumpRateModel_base5000bps_slope3000bps_jump30000bps_kink6000bps_bpy42048000_To_bpy70080000_At_1768357800": "0x4E1fE613E8cE7d0DF1E2F5BC48F50a18Ef4d353c", + "CheckpointView_From_TwoKinks_base0bps_slope1000bps_kink8000bps_slope27000bps_base20bps_kink29000bps_jump30000bps_bpy21024000_To_bpy42048000_At_1751250600": "0x08437b3C0BeA58fE6eC696a04c9675E0980b9469", + "CheckpointView_From_TwoKinks_base0bps_slope1500bps_kink8000bps_slope29000bps_base20bps_kink29000bps_jump30000bps_bpy10512000_To_bpy21024000_At_1745903100": "0x81d6ae3EEa177d5D052B329dc74d39B935569359", + "CheckpointView_From_TwoKinks_base0bps_slope312bps_kink8000bps_slope28499bps_base20bps_kink29000bps_jump34000bps_bpy42048000_To_bpy70080000_At_1768357800": "0x650b2F1DC7F6E6734909Ad1Df2367537219584b8", + "CheckpointView_From_TwoKinks_base0bps_slope350bps_kink8000bps_slope217500bps_base20bps_kink29000bps_jump30000bps_bpy10512000_To_bpy21024000_At_1745903100": "0xfCFE909330FF50D2c72715cBEC4E54c476c27CEC", + "CheckpointView_From_TwoKinks_base0bps_slope450bps_kink7000bps_slope214000bps_base20bps_kink28000bps_jump30000bps_bpy21024000_To_bpy42048000_At_1751250600": "0xF78db86E58dc1b76569a0b3105EF5186033911A1", + "CheckpointView_From_TwoKinks_base0bps_slope624bps_kink8000bps_slope26001bps_base20bps_kink29000bps_jump34000bps_bpy42048000_To_bpy70080000_At_1768357800": "0x979566A212460cA7EC767C9BF3dEB3D6585A2b38", + "CheckpointView_From_TwoKinks_base0bps_slope625bps_kink8000bps_slope26000bps_base20bps_kink29000bps_jump34000bps_bpy42048000_To_bpy70080000_At_1768357800": "0x381829DBb51cD74F3172574f4111F2F58d8b0E53", + "CheckpointView_From_TwoKinks_base0bps_slope654bps_kink8400bps_slope22499bps_base20bps_kink29200bps_jump40625bps_bpy42048000_To_bpy70080000_At_1768357800": "0x2CF0e211c99dFd28892cf80D142aA27a9042Dbf4", + "CheckpointView_From_WhitePaperInterestRateModel_base0bps_slope0bps_bpy10512000_To_bpy21024000_At_1745903100": "0x4088e11DF221314896c2Aaed72074F89928e5b59", + "CheckpointView_From_WhitePaperInterestRateModel_base0bps_slope0bps_bpy21024000_To_bpy42048000_At_1751250600": "0x02448c05fdd44c1dCcdc54A29fe02E8f43f31BF7", + "CheckpointView_From_WhitePaperInterestRateModel_base0bps_slope0bps_bpy42048000_To_bpy70080000_At_1768357800": "0xa60b28FDDaAB87240C3AF319892e7A4ad6FbF41F", + "CheckpointView_From_WhitePaperInterestRateModel_base0bps_slope24000bps_bpy10512000_To_bpy21024000_At_1745903100": "0x9318f66729007281D4C4545c04b046C437bD77E5", + "CheckpointView_From_WhitePaperInterestRateModel_base0bps_slope24000bps_bpy21024000_To_bpy42048000_At_1751250600": "0x170bE58D5C1983f03DC287AB9aBffC7DA16f862b", + "CheckpointView_From_WhitePaperInterestRateModel_base0bps_slope24000bps_bpy42048000_To_bpy70080000_At_1768357800": "0x9E3f9A97285E2694Ea32c37EBFfE427492888edD", + "ComptrollerLens": "0xd5DEb631cB6c6a667e926a482aadc95a471b120c", + "DAI": "0x1AF3F329e8BE154074D8769D1FFa4eE058B1DBc3", + "DOGE": "0xbA2aE424d960c26247Dd6c32edC70B295c744C43", + "DOT": "0x7083609fCE4d1d8Dc0C979AAb8c869Ea2C873402", + "DefaultProxyAdmin": "0x6beb6D2695B67FEb73ad4f172E8E2975497187e4", + "ETH": "0x2170Ed0880ac9A755fd29B2688956BD959F933F8", + "FIL": "0x0D8Ce2A99Bb6e3B7Db580eD848240e4a0F9aE153", + "FlashLoanFacet": "0xAC54A4D148690b7FDA22B1D29c4439aCBF668fb2", + "JumpRateModel_base0bps_slope10000bps_jump25000bps_kink8000bps_bpy10512000": "0x9e8fbACBfbD811Fc561af3Af7df8e38dEd4c52F3", + "JumpRateModel_base0bps_slope10000bps_jump50000bps_kink8000bps_bpy10512000": "0x958F4C84d3ad523Fa9936Dc465A123C7AD43D69B", + "JumpRateModel_base0bps_slope1000bps_jump20000bps_kink7500bps_bpy10512000": "0x871A82082482657B9df62Dea21509023F28c147C", + "JumpRateModel_base0bps_slope1000bps_jump20000bps_kink7500bps_bpy21024000": "0xd1E1f4Fc02cAe664893a227E7CAAdc50D655f8f7", + "JumpRateModel_base0bps_slope1000bps_jump20000bps_kink7500bps_bpy42048000": "0xcc542643521D5e4dE63f48682e7f577f805e7651", + "JumpRateModel_base0bps_slope1000bps_jump20000bps_kink7500bps_bpy70080000": "0xe678399CF9A5964604DD055A4aDd1982d3F7d23F", + "JumpRateModel_base0bps_slope1000bps_jump25000bps_kink8000bps_bpy10512000": "0x62A8919C4C413fd4F9aef7348540Bc4B1b5CC805", + "JumpRateModel_base0bps_slope1000bps_jump25000bps_kink8000bps_bpy21024000": "0x4eFbf2f6E63eCad12dE015E5be2a1094721633EE", + "JumpRateModel_base0bps_slope1000bps_jump25000bps_kink8000bps_bpy42048000": "0x6D7c746D4A9170F1731F89580414235dA47787fc", + "JumpRateModel_base0bps_slope1000bps_jump25000bps_kink8000bps_bpy70080000": "0xad6aa8Bb4829560412A94AA930745f407BF8000B", + "JumpRateModel_base0bps_slope1000bps_jump50000bps_kink8000bps_bpy10512000": "0x05c68eE7c9c66BE3a42476fe3838DE65ddE968f1", + "JumpRateModel_base0bps_slope1000bps_jump50000bps_kink8000bps_bpy21024000": "0x76cB08c25EF426F5444C28179D05F77cB1a6aBD0", + "JumpRateModel_base0bps_slope1000bps_jump50000bps_kink8000bps_bpy42048000": "0xE3394c5A871bf893B41196F0aa843C64C2Da0A5C", + "JumpRateModel_base0bps_slope1000bps_jump50000bps_kink8000bps_bpy70080000": "0xF2F2aE5480c4527787Fb7Cde1Ed9A3EdfD40A60d", + "JumpRateModel_base0bps_slope1250bps_jump25000bps_kink8000bps_bpy10512000": "0x1485A27D95D3d2878a6641055dD3a643F296CCf6", + "JumpRateModel_base0bps_slope1250bps_jump50000bps_kink8000bps_bpy10512000": "0x9Fca5d66Cc0DF990080825051E825A8104a7ffA4", + "JumpRateModel_base0bps_slope1500bps_jump30000bps_kink6000bps_bpy10512000": "0xEa464DfB1B0BB8964c250427bb5B0DD4f315141A", + "JumpRateModel_base0bps_slope1500bps_jump30000bps_kink6000bps_bpy21024000": "0x927EA36cE0a926b0Ed9358A0ed899EFCE4574fC0", + "JumpRateModel_base0bps_slope1500bps_jump30000bps_kink6000bps_bpy42048000": "0x7B91a129A4C58c1Ea9b805e4D7ef677C290A003a", + "JumpRateModel_base0bps_slope1500bps_jump30000bps_kink6000bps_bpy70080000": "0xaBdE9599a4aEcE4fEC59fBF2b8445149bc8B2c70", + "JumpRateModel_base0bps_slope1750bps_jump25000bps_kink8000bps_bpy10512000": "0x0be3ca99FBBE16b86C3b00E2C4c30C3892F31647", + "JumpRateModel_base0bps_slope1750bps_jump25000bps_kink8000bps_bpy21024000": "0x16d55426f0439613260e1F4b2A76B493B36f8ba5", + "JumpRateModel_base0bps_slope2000bps_jump30000bps_kink5000bps_bpy10512000": "0x637e19b6EE87758506d6eA34bF11BE8F43AD8d61", + "JumpRateModel_base0bps_slope2000bps_jump30000bps_kink5000bps_bpy21024000": "0xb831F6aC79121d0a7Cf11a452E4254516899Ea16", + "JumpRateModel_base0bps_slope2000bps_jump30000bps_kink5000bps_bpy42048000": "0x06FF3190895aec1656b99Acdb3A4D556b4205669", + "JumpRateModel_base0bps_slope2000bps_jump30000bps_kink5000bps_bpy70080000": "0x1D5F9752bA40cF7047db2E24Cb6Aa196E3c334DA", + "JumpRateModel_base0bps_slope200bps_jump400bps_kink8000bps_bpy70080000": "0xCDAE733D8aB71cdD4D183CD25685500e8F502329", + "JumpRateModel_base0bps_slope300bps_jump45000bps_kink9000bps_bpy10512000": "0x3aa125788FC6b9F801772baEa887aA40328015e9", + "JumpRateModel_base0bps_slope300bps_jump45000bps_kink9000bps_bpy21024000": "0xFFB9d1556Cb6323115c0E8658edfB4c090a427e8", + "JumpRateModel_base0bps_slope300bps_jump45000bps_kink9000bps_bpy42048000": "0x5D1dd238F70854F4914Db67035f79F42a38c79C2", + "JumpRateModel_base0bps_slope300bps_jump45000bps_kink9000bps_bpy70080000": "0xCe1a0389767cF155b0f3c475c1283e1951923770", + "JumpRateModel_base0bps_slope667bps_jump62700bps_kink7500bps_bpy70080000": "0xe589E884f69dF3137B43A760C4Ec9E55D944439D", + "JumpRateModel_base0bps_slope687bps_jump25000bps_kink8000bps_bpy10512000": "0xB105F9B511836cc7dF9F3dD0Ec4873766b5b6660", + "JumpRateModel_base0bps_slope750bps_jump50000bps_kink8000bps_bpy10512000": "0xdEf4b9462223c9a44E61d217a145063C7836FD7B", + "JumpRateModel_base0bps_slope750bps_jump50000bps_kink8000bps_bpy21024000": "0x76EdDEfad0C348B0075217EE8d9E5c1Eb4bB4Fd3", + "JumpRateModel_base0bps_slope750bps_jump5000bps_kink8000bps_bpy10512000": "0xF874A969d504e0b1b2021d76A2c438B841124715", + "JumpRateModel_base0bps_slope750bps_jump5000bps_kink8000bps_bpy21024000": "0x8c60091fdE10BC44143cB7C306Ff954E047e164c", + "JumpRateModel_base0bps_slope750bps_jump5000bps_kink8000bps_bpy42048000": "0xaf1618C88b1C6304f0F9c76ab722088A4268fd3D", + "JumpRateModel_base0bps_slope750bps_jump5000bps_kink8000bps_bpy70080000": "0xCf4C75398DaD73f16c762026144a1496f6869CD1", + "JumpRateModel_base0bps_slope875bps_jump25000bps_kink8000bps_bpy10512000": "0xBe4609d972FdEBAa9DC870F4A957F40C301bEb1D", + "JumpRateModel_base0bps_slope875bps_jump50000bps_kink8000bps_bpy10512000": "0xE19C14171C2aC6CA63E008133e4B0D8571164BA3", + "JumpRateModel_base0bps_slope900bps_jump20000bps_kink5000bps_bpy10512000": "0xf092558eD27Df036144f6d92cC657BAc9682A324", + "JumpRateModel_base0bps_slope900bps_jump20000bps_kink5000bps_bpy21024000": "0x52F63686D09d92c367c90BCDBF79A562f81bd6BF", + "JumpRateModel_base0bps_slope900bps_jump20000bps_kink5000bps_bpy42048000": "0x68Cb22f8664546E19B7BfCC4F86Fd0fCbDd0b02e", + "JumpRateModel_base0bps_slope900bps_jump20000bps_kink5000bps_bpy70080000": "0x6463ab803FF081616ac4daC31B9B66854cc28Bc0", + "JumpRateModel_base0bps_slope900bps_jump20000bps_kink7500bps_bpy10512000": "0xAA69D9B80B5b303F66227932489669538027783F", + "JumpRateModel_base0bps_slope900bps_jump20000bps_kink7500bps_bpy21024000": "0xbB32a50FeA5AB822A1B52245D1Fbea7fC49659fc", + "JumpRateModel_base0bps_slope900bps_jump20000bps_kink7500bps_bpy42048000": "0x8AD7D983196cEB75dC4B28d0b1fE64F95547692e", + "JumpRateModel_base0bps_slope900bps_jump35000bps_kink4500bps_bpy10512000": "0x77C50b4d5d8b84511a4787aaF5BC22E5A496B1Ef", + "JumpRateModel_base0bps_slope900bps_jump35000bps_kink4500bps_bpy21024000": "0x4699bA39B8E7da3ef178020b69dcb9E25103D0a3", + "JumpRateModel_base0bps_slope900bps_jump35000bps_kink4500bps_bpy42048000": "0x2349decE4B56541DE2dc7F2C3F433F95095D4B8B", + "JumpRateModel_base0bps_slope900bps_jump35000bps_kink4500bps_bpy70080000": "0x8ecfD11473C30a508a386bea715F0cd7B9baD7a5", + "JumpRateModel_base200bps_slope10000bps_jump30000bps_kink100bps_bpy10512000": "0x6b7C3d1ced49604c66e2C8125989E78B1E5356F5", + "JumpRateModel_base200bps_slope10000bps_jump30000bps_kink100bps_bpy21024000": "0xe42B289b630930EdF126cA944C0FC6899a0b249b", + "JumpRateModel_base200bps_slope10000bps_jump30000bps_kink100bps_bpy42048000": "0xCb7f4fe025eE97c544c8ad367a497B54911f0026", + "JumpRateModel_base200bps_slope10000bps_jump30000bps_kink100bps_bpy70080000": "0x875535EEEb75c5Cd392708796c618cdaC787A3CF", + "JumpRateModel_base200bps_slope1200bps_jump30000bps_kink6000bps_bpy10512000": "0xda6cdE1F47AE792FA40Aa85C9F6901d5E64a6769", + "JumpRateModel_base200bps_slope1200bps_jump30000bps_kink6000bps_bpy21024000": "0x02555201356B063Cf2ff83D02D91af6529a69627", + "JumpRateModel_base200bps_slope1200bps_jump30000bps_kink6000bps_bpy42048000": "0xd26FfBa546e0447668f8C7b86811f31F010C7803", + "JumpRateModel_base200bps_slope1200bps_jump30000bps_kink6000bps_bpy70080000": "0xbcA3d5E7a66D97E0415662c2394Ed2605944b614", + "JumpRateModel_base200bps_slope1500bps_jump30000bps_kink6000bps_bpy10512000": "0x32450305D6c692269B3cBf9730d99104f80fce23", + "JumpRateModel_base200bps_slope1500bps_jump30000bps_kink6000bps_bpy21024000": "0xFDA9274718c1C64F0631396eB8CaC12625309BFE", + "JumpRateModel_base200bps_slope1500bps_jump30000bps_kink6000bps_bpy42048000": "0x5Ef791b3B73cBb1b961CD0136d0EBc3F9309710E", + "JumpRateModel_base200bps_slope1500bps_jump30000bps_kink6000bps_bpy70080000": "0xdB1869CA9E008E102350f2e0c356500503A4d043", + "JumpRateModel_base200bps_slope2000bps_jump30000bps_kink5000bps_bpy10512000": "0x2dE4739a9C68B02B54C0d8323752551d724b3cc2", + "JumpRateModel_base200bps_slope2000bps_jump30000bps_kink5000bps_bpy21024000": "0x1063A02E500Ae1448DDd6767ead97368FEeCafE7", + "JumpRateModel_base200bps_slope2000bps_jump30000bps_kink5000bps_bpy42048000": "0x6BBb4FAAE927Df5a299892217dFB354E5F5000A2", + "JumpRateModel_base200bps_slope2000bps_jump30000bps_kink5000bps_bpy70080000": "0x905006DCD5DbAa9B67359bcB341a0C49AfC8d0A6", + "JumpRateModel_base25bps_slope367bps_jump20000bps_kink7500bps_bpy42048000": "0xE74FE49e07c8f0Cc4398a481206e2d835b88b8F4", + "JumpRateModel_base25bps_slope367bps_jump20000bps_kink7500bps_bpy70080000": "0xae5A30d694DFF2268C864834DEDa745B784c48bD", + "JumpRateModel_base30000bps_slope0bps_jump36364bps_kink4500bps_bpy70080000": "0xc255352947ef3594C45b0Fe8bcB690e51C3D744A", + "JumpRateModel_base5000bps_slope3000bps_jump30000bps_kink6000bps_bpy10512000": "0x91475A3f288841bce074Ec7edF27ec3fE58e18d1", + "JumpRateModel_base5000bps_slope3000bps_jump30000bps_kink6000bps_bpy21024000": "0xF34AfA5B6a9F828da41f146321221B60977F20E0", + "JumpRateModel_base5000bps_slope3000bps_jump30000bps_kink6000bps_bpy42048000": "0x3DC78Fe78fd3084CAAd0DC881b4Eb98B6151A5f3", + "JumpRateModel_base5000bps_slope3000bps_jump30000bps_kink6000bps_bpy70080000": "0xE1Ac99E486EBEcD40Ab4C9FF29Fe4d28be244D33", + "LINK": "0xF8A0BF9cF54Bb92F17374d9e9A321E6a111a51bD", + "LTC": "0x4338665CBB7B2485A8855A139b75D5e34AB0DB94", + "LUNA": "0x156ab3346823B651294766e23e6Cf87254d68962", + "Liquidator": "0x0870793286aada55d39ce7f82fb2766e8004cf43", + "Liquidator_Implementation": "0xC8c6f55DEBb47f724761920B79DC3ab5399DBC62", + "Liquidator_Proxy": "0x0870793286aada55d39ce7f82fb2766e8004cf43", + "MATIC": "0xCC42724C6683B7E57334c4E856f4c9965ED682bD", + "MarketFacet": "0x21f8E1471b153f49BE1d645A008E4a57434eEd23", + "MoveDebtDelegate": "0x89621C48EeC04A85AfadFD37d32077e65aFe2226", + "MoveDebtDelegate_Implementation": "0x8439932C45e646FcC1009690417A65BF48f68Ce7", + "MoveDebtDelegate_Proxy": "0x89621C48EeC04A85AfadFD37d32077e65aFe2226", + "PSMProxyAdmin": "0x3f918bA9446552AB184C6Ffd2e2fcB1FA5ee1e59", + "PegStability_USDT": "0xC138aa4E424D1A8539e8F38Af5a754a2B7c3Cc36", + "PegStability_USDT_Implementation": "0x9664568e5131e85f67d87fCD55B249F5D25fa43e", + "PegStability_USDT_Proxy": "0xC138aa4E424D1A8539e8F38Af5a754a2B7c3Cc36", + "PolicyFacet": "0x8930B02c69EDd37464B50991680D306Bb9B8FDBD", + "Prime": "0xBbCD063efE506c3D42a0Fa2dB5C08430288C71FC", + "PrimeLeaderboard": "0x55e2ccF68B7A276dc28AfA107997b8B1Be932c0b", + "PrimeLeaderboard_Implementation": "0xD80de9EcB6596dF95dd67aF73b67122054C2d1a1", + "PrimeLeaderboard_Proxy": "0x55e2ccF68B7A276dc28AfA107997b8B1Be932c0b", + "PrimeLens": "0x2f8c5e4562E22DB7908C56Bf99961C053436473c", + "PrimeLiquidityProvider": "0x23c4F844ffDdC6161174eB32c770D4D8C07833F2", + "PrimeLiquidityProvider_Implementation": "0x46BED43b29D73835fF075bBa1A0002A1eD1E4de8", + "PrimeLiquidityProvider_Proxy": "0x23c4F844ffDdC6161174eB32c770D4D8C07833F2", + "PrimeV2": "0x059EabA8676b03e4e8f009eFb7F587C28450F50f", + "PrimeV2_Implementation": "0x18cB7198CBB6D6e94001458CF3Cf47C106D83a1B", + "PrimeV2_Proxy": "0x059EabA8676b03e4e8f009eFb7F587C28450F50f", + "Prime_Implementation": "0x1a6660059E61e88402bD34FC96C2332c5EeAF195", + "Prime_Proxy": "0xBbCD063efE506c3D42a0Fa2dB5C08430288C71FC", + "RewardFacet": "0x9e0CCD70b5E0030472D5013bbBd37B6E868d416f", + "SXP": "0x47BEAd2563dCBf3bF2c9407fEa4dC236fAbA485A", + "SetCheckpointBscmainnet": "0x8f4C73dDb18875979803f9416bD42d8A1002457d", + "SetterFacet": "0xbc4885e5A27050E321d094503597aC6734AB1871", + "SnapshotLens": "0x4556a5eDf9AbA75669EB23842BC4318b5ED5e1E0", + "SwapRouterCorePool": "0x8938E6dA30b59c1E27d5f70a94688A89F7c815a4", + "TRX": "0xCE7de646e7208a4Ef112cb6ed5038FA6cC6b12e3", + "TRXOLD": "0x85EAC5Ac2F758618dFa09bDbe0cf174e7d574D5B", + "TUSD": "0x40af3827F39D0EAcBF4A168f8D4ee67c121D11c9", + "TUSDOLD": "0x14016E85a25aeb13065688cAFB43044C2ef86784", + "TokenRedeemer": "0xC53ffda840B51068C64b2E052a5715043f634bcd", + "TwoKinks_base0bps_slope1000bps_kink8000bps_slope27000bps_base20bps_kink29000bps_jump30000bps_bpy21024000": "0x31d20C36A4804AB30F04fB606555f545b2bAE3b3", + "TwoKinks_base0bps_slope1000bps_kink8000bps_slope27000bps_base20bps_kink29000bps_jump30000bps_bpy42048000": "0xa7581334a8131a45bCc3A07D5988F586108947f7", + "TwoKinks_base0bps_slope1500bps_kink8000bps_slope29000bps_base20bps_kink29000bps_jump30000bps_bpy10512000": "0x4D712A88Ff15a7147a9966c5ED2ccb392F1760c9", + "TwoKinks_base0bps_slope1500bps_kink8000bps_slope29000bps_base20bps_kink29000bps_jump30000bps_bpy21024000": "0x66fA99894aEbB83180a052ef4Cc8cCFaD0F8f8aB", + "TwoKinks_base0bps_slope312bps_kink8000bps_slope28499bps_base20bps_kink29000bps_jump34000bps_bpy42048000": "0x5dff09a6D241eac6ccc63A7665CaC6eff55b38E7", + "TwoKinks_base0bps_slope312bps_kink8000bps_slope28499bps_base20bps_kink29000bps_jump34000bps_bpy70080000": "0xBE4166675172545aAae830BeEe6c01C2514d40B8", + "TwoKinks_base0bps_slope350bps_kink8000bps_slope217500bps_base20bps_kink29000bps_jump30000bps_bpy10512000": "0x01B1DA0D0e7c92BE46405565e34fc7C23f0a5A2A", + "TwoKinks_base0bps_slope350bps_kink8000bps_slope217500bps_base20bps_kink29000bps_jump30000bps_bpy21024000": "0xb0a41574C87318265BC4c93acC8D32299dAdF022", + "TwoKinks_base0bps_slope450bps_kink6500bps_slope214000bps_base20bps_kink28000bps_jump30000bps_bpy21024000": "0x939c9458Bee63Bc21031be3d56dDD30Af7f2230A", + "TwoKinks_base0bps_slope450bps_kink7000bps_slope214000bps_base20bps_kink28000bps_jump30000bps_bpy21024000": "0x66C928605F123d91462dCB3859811eC8403977a9", + "TwoKinks_base0bps_slope450bps_kink7000bps_slope214000bps_base20bps_kink28000bps_jump30000bps_bpy42048000": "0xE82B36f4CE8A9B769036B74354588D427a724763", + "TwoKinks_base0bps_slope624bps_kink8000bps_slope26001bps_base20bps_kink29000bps_jump34000bps_bpy42048000": "0xb1c97b14dE87928845FCf0016b48B3a61aa3e1AD", + "TwoKinks_base0bps_slope624bps_kink8000bps_slope26001bps_base20bps_kink29000bps_jump34000bps_bpy70080000": "0x04f928517736A57840F0fD544fF2a1819B1bDcE0", + "TwoKinks_base0bps_slope625bps_kink8000bps_slope26000bps_base20bps_kink29000bps_jump34000bps_bpy42048000": "0x846883aC2AFdaeF9d226182e82f3640d3D6D4d3f", + "TwoKinks_base0bps_slope625bps_kink8000bps_slope26000bps_base20bps_kink29000bps_jump34000bps_bpy70080000": "0x8c3D5f698005B40B48e729938bdDC405Aad28872", + "TwoKinks_base0bps_slope654bps_kink8400bps_slope22499bps_base20bps_kink29200bps_jump40625bps_bpy42048000": "0x1AAADE04A970043756D90e11af57e03A3A10E2c4", + "TwoKinks_base0bps_slope654bps_kink8400bps_slope22499bps_base20bps_kink29200bps_jump40625bps_bpy70080000": "0x857ebb8CAcb97DE5ab719320c9FB3aa16076bFe3", + "TwoKinks_base0bps_slope812bps_kink8000bps_slope22000bps_base20bps_kink29000bps_jump30000bps_bpy42048000": "0xF48508A44da9C7D210a668eCe4d31Bc98702602b", + "TwoKinks_base0bps_slope875bps_kink8000bps_slope22000bps_base20bps_kink29000bps_jump30000bps_bpy42048000": "0x1a7c9091973CABc491e361A9eaEFD047b48a3647", + "USDC": "0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d", + "USDT": "0x55d398326f99059fF775485246999027B3197955", + "UST": "0x3d4350cD54aeF9f9b2C29435e0fa809957B3F30a", + "Unitroller": "0xfD36E2c2a6789Db23113685031d7F16329158384", + "Unitroller_Implementation": "0xA66B2b5D50ce68A125bBad6B2265b637868c6E66", + "Unitroller_Proxy": "0xfD36E2c2a6789Db23113685031d7F16329158384", + "VAI": "0x4BD17003473389A42DAF6a0a729f6Fdb328BbBd7", + "VAIVault": "0x0B4d7776b87deD4a0958E32D5155598057D2620D", + "VAIVaultProxy": "0x0667Eed0a0aAb930af74a3dfeDD263A73994f216", + "VAIVaultProxy_Implementation": "0xa52f2a56abb7cbdd378bc36c6088fafeaf9ac423", + "VAIVaultProxy_Proxy": "0x0667Eed0a0aAb930af74a3dfeDD263A73994f216", + "VBNBAdmin": "0x9A7890534d9d91d473F28cB97962d176e2B65f1d", + "VBNBAdmin_Implementation": "0xae2713FbdF95d914182f7055ec1Ff6C64F41c275", + "VBNBAdmin_Proxy": "0x9A7890534d9d91d473F28cB97962d176e2B65f1d", + "VBep20Delegate": "0xCDfea50f7CECCB24Fe804657DB8E6c93b689941e", + "VRT": "0x5f84ce30dc3cf7909101c69086c50de191895883", + "VRTConverterProxy": "0x92572fB60f4874d37917C53599cAe5b085B9Facd", + "VRTConverterProxy_Implementation": "0x3192d0fb11c15629c403a6416abfcd7587b180b7", + "VRTConverterProxy_Proxy": "0x92572fB60f4874d37917C53599cAe5b085B9Facd", + "VRTVault": "0x1405899732Cfe963EaB935a8bBa49c47FE996048", + "VRTVaultProxy": "0x98bF4786D72AAEF6c714425126Dd92f149e3F334", + "VRTVaultProxy_Implementation": "0xea98e94d35120b23f9f9f20a7314804d4ab491f1", + "VRTVaultProxy_Proxy": "0x98bF4786D72AAEF6c714425126Dd92f149e3F334", + "VTreasury": "0xF322942f644A996A617BD29c16bd7d231d9F35E9", + "VaiUnitroller": "0x004065D34C6b18cE4370ced1CeBDE94865DbFAFE", + "VaiUnitroller_Implementation": "0x8A7d8589A597619A7842d3BC284b9a5a276FaE56", + "VaiUnitroller_Proxy": "0x004065D34C6b18cE4370ced1CeBDE94865DbFAFE", + "VenusChainlinkOracle": "0x7FabdD617200C9CB4dcf3dd2C41273e60552068A", + "VenusLens": "0xe797804c5d4410777c70EF8769c4eB9C39BEF662", + "WBETH": "0xa2e3356610840701bdf5611a53974510ae27e2e1", + "WBNB": "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c", + "WhitePaperInterestRateModel_base0bps_slope0bps_bpy10512000": "0x93FBc248e83bc8931141ffC7f457EC882595135A", + "WhitePaperInterestRateModel_base0bps_slope0bps_bpy21024000": "0xAdA65304DDDC86d2873CfC018486b7f4F53edb7E", + "WhitePaperInterestRateModel_base0bps_slope0bps_bpy42048000": "0xB66d19E4bFF26eaE1c5C14E1dAAB418B9573B875", + "WhitePaperInterestRateModel_base0bps_slope0bps_bpy70080000": "0x42Ec3Eb6F23460dFDfa3aE5688f3415CDfE0C6AD", + "WhitePaperInterestRateModel_base0bps_slope24000bps_bpy10512000": "0xa166Ca91a570747708a318A771F0C9AB84DD984b", + "WhitePaperInterestRateModel_base0bps_slope24000bps_bpy21024000": "0x2d0A2955C3321743ea3B63109Ce2d7E388Bb35DB", + "WhitePaperInterestRateModel_base0bps_slope24000bps_bpy42048000": "0x92cdF922902440Fdcdd1c987F984Bf86eEd10397", + "WhitePaperInterestRateModel_base0bps_slope24000bps_bpy70080000": "0xF83362aF1722b1762e21369225901B90D9b980d9", + "WhitePaperInterestRateModel_base2629bps_slope30000bps_bpy10512000": "0xb53504Cb74e395Ec10B9BcEc7089Bdaef1CcA042", + "WhitepaperInterestRateModel": "0x49fADE95f94e5EC7C1f4AE13a6d6f9ca18B2F430", + "XRP": "0x1D2F0da169ceB9fC7B3144628dB156f3F6c60dBE", + "XVS": "0xcF6BB5389c92Bdda8a3747Ddb454cB7a64626C63", + "XVSStore": "0x1e25CF968f12850003Db17E0Dba32108509C4359", + "XVSVaultProxy": "0x051100480289e704d20e9DB4804837068f3f9204", + "XVSVaultProxy_Implementation": "0x74c8a97BE672db3e9a224648bE566AdA5F43B378", + "XVSVaultProxy_Proxy": "0x051100480289e704d20e9DB4804837068f3f9204", + "XVSVesting": "0xA9dD0536Ab0699D60c28CE369Ff366a1e621BFf1", + "XVSVestingProxy": "0xb28Dec7C7Ac80f4D0B6a1B711c39e444cDE8B2cE", + "XVSVestingProxy_Implementation": "0xa9dd0536ab0699d60c28ce369ff366a1e621bff1", + "XVSVestingProxy_Proxy": "0xb28Dec7C7Ac80f4D0B6a1B711c39e444cDE8B2cE", + "pancakeFactory": "0xcA143Ce32Fe78f1f7019d7d551a6402fC5350c73", + "vAAVE": "0x26DA28954763B92139ED49283625ceCAf52C6f94", + "vADA": "0x9A0AF7FDb2065Ce470D72664DE73cAE409dA28Ec", + "vBCH": "0x5F0388EBc2B94FA8E123F404b79cCF5f40b29176", + "vBETH": "0x972207A639CC1B374B893cc33Fa251b55CEB7c07", + "vBNB": "0xA07c5b74C9B40447a954e1466938b865b6BBea36", + "vBTC": "0x882C173bC7Ff3b7786CA16dfeD3DFFfb9Ee7847B", + "vBUSD": "0x95c78222B3D6e262426483D42CfA53685A67Ab9D", + "vCAKE": "0x86aC3974e2BD0d60825230fa6F355fF11409df5c", + "vDAI": "0x334b3eCB4DCa3593BCCC3c7EBD1A1C1d1780FBF1", + "vDOGE": "0xec3422Ef92B2fb59e84c8B02Ba73F1fE84Ed8D71", + "vDOT": "0x1610bc33319e9398de5f57B33a5b184c806aD217", + "vETH": "0xf508fCD89b8bd15579dc79A6827cB4686A3592c8", + "vFDUSD": "0xC4eF4229FEc74Ccfe17B2bdeF7715fAC740BA0ba", + "vFIL": "0xf91d58b5aE142DAcC749f58A49FCBac340Cb0343", + "vLINK": "0x650b940a1033B8A1b1873f78730FcFC73ec11f1f", + "vLTC": "0x57A5297F2cB2c0AaC9D554660acd6D385Ab50c6B", + "vLUNA": "0xb91A659E88B51474767CD97EF3196A3e7cEDD2c8", + "vMATIC": "0x5c9476FcD6a4F9a3654139721c949c2233bBbBc8", + "vNVDAB": "0xEb8Ca841cBe1BC4832A10b15c7dAB1081eDaD371", + "vPT-USDe-30OCT2025": "0x6D0cDb3355c93A0cD20071aBbb3622731a95c73E", + "vPT-clisBNB-25JUN2026": "0x6d3BD68E90B42615cb5abF4B8DE92b154ADc435e", + "vPT-sUSDE-26JUN2025": "0x9e4E5fed5Ac5B9F732d0D850A615206330Bf1866", + "vSKHYB": "0x3E281461efb3D53EC20DB207674373Ed8Ef3BbA9", + "vSOL": "0xBf515bA4D1b52FFdCeaBF20d31D705Ce789F2cEC", + "vSPCXB": "0xC36dFaCc7a125859C106F29b9F2d874CCF29A55A", + "vSXP": "0x2fF3d0F6990a40261c66E1ff2017aCBc282EB6d0", + "vSolvBTC": "0xf841cb62c19fCd4fF5CD0AaB5939f3140BaaC3Ea", + "vTHE": "0x86e06EAfa6A1eA631Eab51DE500E3D474933739f", + "vTRX": "0xC5D3466aA484B040eE977073fcF337f2c00071c1", + "vTRXOLD": "0x61eDcFe8Dd6bA3c891CB9bEc2dc7657B3B422E93", + "vTSLAB": "0x97421799419Eb782628e73e7220d8E0A207469a3", + "vTUSD": "0xBf762cd5991cA1DCdDaC9ae5C638F5B5Dc3Bee6E", + "vTUSDOLD": "0x08CEB3F4a7ed3500cA0982bcd0FC7816688084c3", + "vTWT": "0x4d41a36D04D97785bcEA57b057C412b278e6Edcc", + "vU": "0x3d5E269787d562b74aCC55F18Bd26C5D09Fa245E", + "vUNI": "0x27FF564707786720C71A2e5c1490A63266683612", + "vUSD1": "0x0C1DA220D301155b87318B90692Da8dc43B67340", + "vUSDC": "0xecA88125a5ADbe82614ffC12D0DB554E2e2867C8", + "vUSDT": "0xfD5840Cd36d94D7229439859C0112a4185BC0255", + "vUSDe": "0x74ca6930108F775CC667894EEa33843e691680d7", + "vUST": "0x78366446547D062f45b4C0f320cDaa6d710D87bb", + "vWBETH": "0x6CFdEc747f37DAf3b87a35a1D9c8AD3063A1A8A0", + "vWBNB": "0x6bCa74586218dB34cdB402295796b79663d816e9", + "vXAUM": "0x92e6Ea74a1A3047DabF4186405a21c7D63a0612A", + "vXRP": "0xB248a295732e0225acd3337607cc01068e3b9c10", + "vXVS": "0x151B1e2635A717bcDc836ECd6FbB62B674FE3E1D", + "vasBNB": "0xCC1dB43a06d97f736C7B045AedD03C6707c09BDF", + "vlisUSD": "0x689E0daB47Ab16bcae87Ec18491692BF621Dc6Ab", + "vsUSDe": "0x699658323d58eE25c69F1a29d476946ab011bD18", + "vslisBNB": "0x89c910Eb8c90df818b4649b508Ba22130Dc73Adc", + "vvhU": "0x80a5694441810d2b871BEeD644b6d16D113ce06E", + "vvhUSDC": "0xb1AB0399766997C5d66a30b2f2055277B7FA5D6C", + "vvhUSDT": "0xc0768948e668B7BacFf8b4BD1BaBe0eD2b512d3c", + "vxSolvBTC": "0xd804dE60aFD05EE6B89aab5D152258fD461B07D5" + } +} diff --git a/plan/agw/section7-presets.md b/plan/agw/section7-presets.md index a71270bd..94d9c605 100644 --- a/plan/agw/section7-presets.md +++ b/plan/agw/section7-presets.md @@ -1,30 +1,26 @@ -# Section 7 preset framework +# Section 7 presets — current alignment -Source: [SDK spec §7](https://app.notion.com/p/pushprotocol/5-SDK-AGW-3e9188aea7f481cf8e8de324956549b9), [October 12 snapshot](notion/5-sdk-agw.md). Implementation is tracked on feat/agw-sdk-v4, with non-plan changes mirrored to feat/agw-sdk-v5. +Updated October 15, 2026. [Live SDK §7](https://app.notion.com/p/pushprotocol/5-SDK-AGW-3e9188aea7f481cf8e8de324956549b9#07ce163677ef44dfae03a38ea4c16da0) and the [catalog proposal snapshot](notion/agw-presets-proposal-and-rules.md) are the sources. Work is on v4; non-plan changes are mirrored to v5. -## User decisions +## Approved decisions -- Build the framework now; approved app/address catalog comes later. -- Missing asset maxPerCall or maxTotal defaults to zero, superseding the spec's proposed throw. -- An incomplete result is an editable PresetRuleTemplate; supplying agent and expiry narrows the return to Rule[]. This avoids pretending a template is ready for create. +- Missing asset caps default to zero, superseding the SDK page's proposed throw. +- Mainnet templates are included following the user's October 15 scope expansion. Live tests remain testnet-only. +- DEX get without a complete token pair returns zero-input-cap review templates. Call get again after choosing both tokens. The user explicitly approved this flow; merely adding assets to an earlier result cannot enable its swaps. +- Static struct/fixed-array fields use argument paths such as [0,3]. Decoded EVM rules use raw selectors and exact ABI word positions for lossless get/update; no ABI metadata is invented. ## Implemented -- Enumerable, frozen CATEGORY constants: DEXES, LENDING, PREDICTION. -- Public utils.agentic.presets.list/get, with no encoder, ID or deployment helpers restored. -- All production categories currently expose chains: []; get without a chain filter returns rules: []. A requested unavailable chain fails explicitly. No placeholder addresses ship. -- Internal bundled catalog schema and fixture-injectable builder; no public runtime registration or network fetching. -- One rule per chain, chain filtering, identity/expiry propagation and asset placement; unknown/mismatched chains and duplicate assets fail. -- Caller/caller-result mutation cannot modify the catalog or subsequent results. -- Missing caps become 0; explicit uint256 values are retained and invalid values fail. -- Approvals for catalog-declared EVM spenders are pinned to that spender and bounded by maxPerCall. Native assets receive none. With the October 14 v6 migration, distinct spender entries are separate pinned alternatives; an unpinned alternative beside them is refused. -- Full signatures and the 32-call ceiling (including approvals) are checked. Metadata app/label is display-only. -- The October 14 v6 adapter supports general destination EQ/MAX pins. Presets use the same create/add validation and do not bypass policy checks. +Enumerable DEXES/LENDING/STAKING/PREDICTION constants; list/get only; one rule per chain; full signatures; wallet recipient pins; token pair pins; bounded spender-pinned approvals; mutation isolation; omitted identity/expiry; explicit chain filtering; zero cap defaults; 32-call and 32-pin limits. Unfiltered discovery includes both mainnet and testnet templates. PREDICTION remains empty. -## Remaining activation work +[Catalog coverage, read-only mainnet verification and exclusions](research/preset-mainnet-2026-10-15/README.md). [Testnet source snapshots and review flow](research/preset-catalog-2026-10-15/implementation-status.md). -Approved catalog data, tuple-field convention and review of approval combinations against the new policy. Solana approvals require a separately reviewed instruction template; no EVM approval is fabricated for them. App ABIs stay in the UI. No funded app-preset E2E is meaningful until approved entries exist. +## Remaining + +- Remote Notion wording needs synchronization: zero-cap review/regenerate flow, missing caps default zero, STAKING, [0,3] tuple paths. No remote page was edited. +- Additional protocol rows need deployment/function/permission review. Dynamic paths and currently unrepresentable Solana flows are not silently enabled. +- Live protocol tests are separate from local policy tests and from read-only address verification. Coverage does not extend to every app/chain merely because its templates are present. ## Validation -Preset/public-surface tests: 30 passed (20 new preset cases). Pinned-contract multi-asset suite: 11 passed, including a new fixture preset passed through public create and actual policy execution/accounting (stub gateway, no live app). Guide: 5 TypeScript blocks typechecked. Final full unit regression: 2,075 passed, 12 skipped, no failures. Build, typechecks, compiled package/declaration examples and API comparison pass. [Commands and logs](research/section7-presets-2026-10-12/commands.md). An earlier 100ms timing failure passed on retry and in the final full run. +Latest full unit run: 2,096 passed, 12 skipped, zero failures. Focused preset tests: 44 passed. The zero-cap review flow passed 16 local real-v6 contract tests. Test selection includes two separate opt-in agw-presets scenarios (Uniswap and Aave), and leaves the default all group unchanged. Uniswap and Aave LINK live scenarios passed in separate runs; Aave USDC hit its protocol supply cap before the LINK correction. [Live results and transaction evidence](research/preset-live-2026-10-15/README.md). From 25e9b558c24e4e04d3b084ea46f1e202a4543e4b Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Thu, 15 Oct 2026 08:18:09 +0530 Subject: [PATCH 43/68] fix(core): resolve AGW tokens by destination and expand live coverage --- packages/core/AGW.md | 5 + .../__e2e__/agw/presets-expanded-live.spec.ts | 748 ++++++++++++++++++ packages/core/__e2e__/ci/suite.ts | 41 + .../__tests__/runtime-token-chain.spec.ts | 69 ++ packages/core/src/lib/agentic/runtime.ts | 34 +- 5 files changed, 887 insertions(+), 10 deletions(-) create mode 100644 packages/core/__e2e__/agw/presets-expanded-live.spec.ts create mode 100644 packages/core/src/lib/agentic/__tests__/runtime-token-chain.spec.ts diff --git a/packages/core/AGW.md b/packages/core/AGW.md index 772201aa..2873ebfe 100644 --- a/packages/core/AGW.md +++ b/packages/core/AGW.md @@ -219,3 +219,8 @@ Run `node packages/core/scripts/check-agw-docs.js` to typecheck these examples. 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. 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. + + +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. + +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. diff --git a/packages/core/__e2e__/agw/presets-expanded-live.spec.ts b/packages/core/__e2e__/agw/presets-expanded-live.spec.ts new file mode 100644 index 00000000..67b44a32 --- /dev/null +++ b/packages/core/__e2e__/agw/presets-expanded-live.spec.ts @@ -0,0 +1,748 @@ +/** Real protocol tests on supported testnets only. All signing uses Donut. + * Destination-only assets are prefunded; generated preset calls/pins are retained. + */ +import { + createPublicClient, + encodeFunctionData, + erc20Abi, + http, + parseAbi, + parseEther, + parseEventLogs, + type Address, + type Hex, +} from 'viem'; +import { PushChain, CHAIN, type Rule } from '../../src'; +import { MOVEABLE_TOKEN_CONSTANTS } from '../../src/lib/constants/tokens'; +import { getNativePRC20ForChain } from '../../src/lib/orchestrator/internals/helpers'; +import { getCEAAddress } from '../../src/lib/orchestrator/cea-utils'; +import { + AGW_E2E_ENABLED, + setupAgw, + evmClient, + inSeconds, + type AgwFixture, +} from './_fixture'; +const d = AGW_E2E_ENABLED ? describe : describe.skip; +const ZERO = BigInt(0), + SMALL = BigInt(10) ** BigInt(12), + MAX_PC = parseEther('20'); +const rpc = { + [CHAIN.ETHEREUM_SEPOLIA]: 'https://ethereum-sepolia-rpc.publicnode.com', + [CHAIN.BASE_SEPOLIA]: 'https://base-sepolia-rpc.publicnode.com', + [CHAIN.ARBITRUM_SEPOLIA]: 'https://arbitrum-sepolia-rpc.publicnode.com', + [CHAIN.BNB_TESTNET]: 'https://bsc-testnet-rpc.publicnode.com', +}; +type Destination = keyof typeof rpc; +type Call = { to: Address; value: bigint; data: Hex }; +const ERC20 = erc20Abi; +const EXECUTED = parseAbi([ + 'event UniversalTxExecuted(bytes32 indexed subTxId, bytes32 indexed universalTxId, address indexed originCaller, address target, bytes data)', +]); +const WETH = parseAbi(['function deposit() payable']); +const AAVE = parseAbi([ + 'function supply(address,uint256,address,uint16)', + 'function withdraw(address,uint256,address) returns(uint256)', +]); +const MARKET = parseAbi([ + 'function mint(uint256) returns(uint256)', + 'function redeem(uint256) returns(uint256)', + 'function balanceOf(address) view returns(uint256)', +]); +const read = (chain: Destination) => + createPublicClient({ transport: http(rpc[chain], { timeout: 20_000 }) }); +const call = (to: Address, data: Hex, value = ZERO): Call => ({ + to, + data, + value, +}); +const approve = (token: Address, spender: Address, amount: bigint) => + call( + token, + encodeFunctionData({ + abi: ERC20, + functionName: 'approve', + args: [spender, amount], + }) + ); +const balance = (chain: Destination, token: Address, owner: Address) => + read(chain).readContract({ + address: token, + abi: ERC20, + functionName: 'balanceOf', + args: [owner], + }); +const preset = ( + category: 'DEXES' | 'LENDING' | 'STAKING', + chain: Destination, + agent: Address, + tokens: { token: Address; maxPerCall: bigint; maxTotal: bigint }[] +): Rule => ({ + ...PushChain.utils.agentic.presets.get(category, { + chainNamespace: chain, + agent, + validUntil: inSeconds(7200), + maxGasPerCall: MAX_PC, + assets: tokens, + }).rules[0], + assets: [], +}); + +async function walletFor( + f: AgwFixture, + chain: Destination, + rule: Rule, + label: string +) { + const { wallet, rulesIds } = await f.owner.agentic.create(label, { + rules: [rule], + }); + const cea = (await getCEAAddress(wallet, chain)).cea as Address; + await f.fundPC(wallet, parseEther('100')); + const owner = await evmClient( + process.env['PUSH_PRIVATE_KEY'] as Hex, + CHAIN.PUSH_TESTNET_DONUT, + f.manifest.network, + wallet + ); + const agent = await f.agent(wallet); + f.evidence('preset-expanded-wallet', { + label, + chain, + wallet, + cea, + rulesId: rulesIds[0], + }); + return { wallet, cea, owner, agent, rulesId: rulesIds[0] }; +} +async function send( + f: AgwFixture, + w: Awaited>, + chain: Destination, + client: PushChain, + calls: Call[], + stage: string, + funds?: { + token: typeof MOVEABLE_TOKEN_CONSTANTS.ETHEREUM_SEPOLIA.ETH; + amount: bigint; + } +) { + const tx = await client.universal.sendTransaction({ + to: { address: calls[0].to, chain }, + data: calls, + gasLimit: BigInt(2_000_000), + ...(funds ? { funds } : {}), + }); + f.evidence('preset-expanded-stage', { + chain, + wallet: w.wallet, + cea: w.cea, + stage: `${stage}-submitted`, + pushTx: tx.hash, + }); + const receipt = await tx.wait(); + expect(receipt.externalTxHash).toBeTruthy(); + const dest = await read(chain).getTransactionReceipt({ + hash: receipt.externalTxHash as Hex, + }); + f.evidence('preset-expanded-stage', { + chain, + wallet: w.wallet, + cea: w.cea, + stage: `${stage}-completed`, + pushTx: tx.hash, + externalTx: receipt.externalTxHash, + status: dest.status, + }); + expect(dest.status).toBe('success'); + const events = parseEventLogs({ abi: EXECUTED, logs: dest.logs }); + for (const c of calls) + expect( + events.some( + (e) => + e.address.toLowerCase() === w.cea.toLowerCase() && + e.args.originCaller.toLowerCase() === w.wallet.toLowerCase() && + e.args.target.toLowerCase() === c.to.toLowerCase() && + e.args.data === c.data + ) + ).toBe(true); + return dest; +} +// Moonwell and Venus use different Redeem event signatures. Require the +// protocol's entire burned-share amount and payout to match the CEA balances. +function assertRedemption( + receipt: Awaited>, + market: Address, + cea: Address, + shares: bigint, + received: bigint +) { + const events = parseEventLogs({ + abi: parseAbi([ + 'event Redeem(address redeemer,uint256 redeemAmount,uint256 redeemTokens)', + 'event Redeem(address redeemer,uint256 redeemAmount,uint256 redeemTokens,uint256 totalSupply)', + ]), + logs: receipt.logs, + }); + const event = events.find( + (e) => + e.address.toLowerCase() === market.toLowerCase() && + e.args.redeemer.toLowerCase() === cea.toLowerCase() + ); + expect(event?.args.redeemTokens).toBe(shares); + expect(event?.args.redeemAmount).toBe(received); +} + +async function wrap( + f: AgwFixture, + w: Awaited>, + chain: Destination, + token: Address, + amount: bigint +) { + const prc20 = getNativePRC20ForChain(chain, f.manifest.network); + if ( + (await f.push.readContract({ + address: prc20, + abi: ERC20, + functionName: 'balanceOf', + args: [f.ownerAddress], + })) < amount + ) + throw new Error( + `PRESET_PREREQUISITE: master lacks native PRC20 for ${chain}` + ); + await ( + await f.owner.universal.sendTransaction({ + to: prc20, + data: encodeFunctionData({ + abi: ERC20, + functionName: 'transfer', + args: [w.wallet, amount], + }), + }) + ).wait(); + const native = + chain === CHAIN.BNB_TESTNET + ? MOVEABLE_TOKEN_CONSTANTS.BNB_TESTNET.BNB + : chain === CHAIN.BASE_SEPOLIA + ? MOVEABLE_TOKEN_CONSTANTS.BASE_SEPOLIA.ETH + : chain === CHAIN.ARBITRUM_SEPOLIA + ? MOVEABLE_TOKEN_CONSTANTS.ARBITRUM_SEPOLIA.ETH + : MOVEABLE_TOKEN_CONSTANTS.ETHEREUM_SEPOLIA.ETH; + await send( + f, + w, + chain, + w.owner, + [ + call( + token, + encodeFunctionData({ abi: WETH, functionName: 'deposit' }), + amount + ), + ], + 'wrap', + { token: native, amount } + ); + expect(await balance(chain, token, w.cea)).toBe(amount); +} + +d('agw presets expanded', () => { + let f: AgwFixture; + afterEach(() => f?.teardown()); + it('1. EigenLayer Sepolia deposit credits shares to the wallet', async () => { + const chain = CHAIN.ETHEREUM_SEPOLIA; + const manager = '0x2E3D6c0744b10eb0A4e6F679F71554a39Ec47a5D' as Address; + const strategy = '0x424246eF71b01ee33aA33aC590fd9a0855F5eFbc' as Address; + const abi = parseAbi([ + 'function strategyIsWhitelistedForDeposit(address) view returns(bool)', + 'function paused() view returns(uint256)', + 'function depositIntoStrategy(address,address,uint256) returns(uint256)', + 'function stakerDepositShares(address,address) view returns(uint256)', + ]); + expect( + await read(chain).readContract({ + address: manager, + abi, + functionName: 'strategyIsWhitelistedForDeposit', + args: [strategy], + }) + ).toBe(true); + expect( + (await read(chain).readContract({ + address: manager, + abi, + functionName: 'paused', + })) & BigInt(1) + ).toBe(ZERO); + const token = await read(chain).readContract({ + address: strategy, + abi: parseAbi(['function underlyingToken() view returns(address)']), + functionName: 'underlyingToken', + }); + f = await setupAgw(); + const rule = preset('STAKING', chain, f.agentAddress, [ + { token, maxPerCall: SMALL, maxTotal: SMALL }, + ]); + const w = await walletFor(f, chain, rule, 'e2e-preset-eigen'); + await wrap(f, w, chain, token, SMALL); + const before = await read(chain).readContract({ + address: manager, + abi, + functionName: 'stakerDepositShares', + args: [w.cea, strategy], + }); + await send( + f, + w, + chain, + w.agent, + [ + approve(token, manager, SMALL), + call( + manager, + encodeFunctionData({ + abi, + functionName: 'depositIntoStrategy', + args: [strategy, token, SMALL], + }) + ), + ], + 'eigen-deposit' + ); + const after = await read(chain).readContract({ + address: manager, + abi, + functionName: 'stakerDepositShares', + args: [w.cea, strategy], + }); + expect(after).toBeGreaterThan(before); + expect(await balance(chain, token, w.cea)).toBe(ZERO); + f.evidence('preset-eigen-live', { + wallet: w.wallet, + cea: w.cea, + strategy, + amount: SMALL, + shares: after - before, + }); + }, 900_000); + const dexCases = [ + { + id: 2, + chain: CHAIN.BASE_SEPOLIA, + wrapped: '0x4200000000000000000000000000000000000006', + output: '0x036CbD53842c5426634e7929541eC2318f3dCF7e', + fee: 3000, + }, + { + id: 3, + chain: CHAIN.ARBITRUM_SEPOLIA, + wrapped: '0x980B62Da83eFf3D4576C647993b0c1D7faf17c73', + output: '0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d', + fee: 3000, + }, + { + id: 4, + chain: CHAIN.BNB_TESTNET, + wrapped: '0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd', + output: '0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c', + fee: 100, + }, + ] as const; + async function dexAndLend({ + chain, + wrapped, + output, + fee, + }: (typeof dexCases)[number]) { + const discovery = PushChain.utils.agentic.presets.get('DEXES', { + chainNamespace: chain, + }).rules[0]; + const router = discovery.allowedCalls[0].target as Address; + const factory = await read(chain).readContract({ + address: router, + abi: parseAbi(['function factory() view returns(address)']), + functionName: 'factory', + }); + const pool = await read(chain).readContract({ + address: factory, + abi: parseAbi([ + 'function getPool(address,address,uint24) view returns(address)', + ]), + functionName: 'getPool', + args: [wrapped, output, fee], + }); + if (/^0x0+$/.test(pool)) + throw new Error(`PRESET_PREREQUISITE: ${chain} pool missing`); + expect( + await read(chain).readContract({ + address: pool, + abi: parseAbi(['function liquidity() view returns(uint128)']), + functionName: 'liquidity', + }) + ).toBeGreaterThan(ZERO); + f = await setupAgw(); + const w = await walletFor( + f, + chain, + preset('DEXES', chain, f.agentAddress, [ + { token: wrapped, maxPerCall: SMALL, maxTotal: SMALL }, + { token: output, maxPerCall: SMALL, maxTotal: SMALL }, + ]), + `e2e-preset-dex-${chain}` + ); + await wrap(f, w, chain, wrapped, SMALL); + const abi = parseAbi([ + 'function exactInputSingle((address tokenIn,address tokenOut,uint24 fee,address recipient,uint256 amountIn,uint256 amountOutMinimum,uint160 sqrtPriceLimitX96)) returns(uint256)', + ]); + const swap = (recipient: Address, amountIn = SMALL) => + call( + router, + encodeFunctionData({ + abi, + functionName: 'exactInputSingle', + args: [ + { + tokenIn: wrapped, + tokenOut: output, + fee, + recipient, + amountIn, + amountOutMinimum: BigInt(1), + sqrtPriceLimitX96: ZERO, + }, + ], + }) + ); + await expect( + w.agent.universal.sendTransaction({ + to: { address: router, chain }, + gasLimit: BigInt(2_000_000), + data: [swap(f.agentAddress)], + }) + ).rejects.toMatchObject({ + decodedError: { name: 'PolicyCheckReverted(ArgPinMismatch)' }, + }); + await expect( + w.agent.universal.sendTransaction({ + to: { address: router, chain }, + gasLimit: BigInt(2_000_000), + data: [swap(w.cea, SMALL + BigInt(1))], + }) + ).rejects.toMatchObject({ + decodedError: { name: 'PolicyCheckReverted(ArgPinAboveMax)' }, + }); + const before = await balance(chain, output, w.cea); + await send( + f, + w, + chain, + w.agent, + [approve(wrapped, router, SMALL), swap(w.cea)], + 'dex-swap' + ); + const received = (await balance(chain, output, w.cea)) - before; + expect(received).toBeGreaterThan(ZERO); + expect(await balance(chain, wrapped, w.cea)).toBe(ZERO); + f.evidence('preset-expanded-dex', { + chain, + wallet: w.wallet, + cea: w.cea, + pool, + router, + amountIn: SMALL, + amountOut: received, + }); + if (chain === CHAIN.BASE_SEPOLIA) return; // its Aave reserve uses a different test token; exercised in case 5. + const rule = preset('LENDING', chain, f.agentAddress, [ + { token: output, maxPerCall: received, maxTotal: received }, + ]); + await f.owner.agentic + .wallet(w.wallet) + .rules.update({ rules: [{ rulesId: w.rulesId, rule }] }); + if (chain === CHAIN.ARBITRUM_SEPOLIA) { + const aave = rule.allowedCalls.find((c) => c.app === 'Aave V3')! + .target as Address; + await send( + f, + w, + chain, + w.agent, + [ + approve(output, aave, received), + call( + aave, + encodeFunctionData({ + abi: AAVE, + functionName: 'supply', + args: [output, received, w.cea, 0], + }) + ), + ], + 'aave-supply' + ); + expect(await balance(chain, output, w.cea)).toBe(before); + await send( + f, + w, + chain, + w.agent, + [ + call( + aave, + encodeFunctionData({ + abi: AAVE, + functionName: 'withdraw', + args: [output, received, w.cea], + }) + ), + ], + 'aave-withdraw' + ); + expect(await balance(chain, output, w.cea)).toBe(before + received); + f.evidence('preset-expanded-aave', { + chain, + wallet: w.wallet, + cea: w.cea, + amount: received, + asset: output, + }); + } else { + const venus = rule.allowedCalls.find((c) => c.app === 'Venus vUSDT')! + .target as Address; + await send( + f, + w, + chain, + w.agent, + [ + approve(output, venus, received), + call( + venus, + encodeFunctionData({ + abi: MARKET, + functionName: 'mint', + args: [received], + }) + ), + ], + 'venus-mint' + ); + const shares = await balance(chain, venus, w.cea); + expect(shares).toBeGreaterThan(ZERO); + expect(await balance(chain, output, w.cea)).toBe(before); + const redemption = await send( + f, + w, + chain, + w.agent, + [ + call( + venus, + encodeFunctionData({ + abi: MARKET, + functionName: 'redeem', + args: [shares], + }) + ), + ], + 'venus-redeem' + ); + const redeemed = (await balance(chain, output, w.cea)) - before; + expect(await balance(chain, venus, w.cea)).toBe(ZERO); + assertRedemption(redemption, venus, w.cea, shares, redeemed); + expect(redeemed).toBeGreaterThanOrEqual( + (received * BigInt(99)) / BigInt(100) + ); + f.evidence('preset-expanded-venus', { + chain, + wallet: w.wallet, + cea: w.cea, + deposited: received, + redeemed, + shares, + asset: output, + }); + } + } + it('2. DEX swap on eip155:84532', () => dexAndLend(dexCases[0]), 1_200_000); + it( + '3. DEX swap and Aave round trip on eip155:421614', + () => dexAndLend(dexCases[1]), + 1_200_000 + ); + it( + '4. DEX swap and Venus round trip on eip155:97', + () => dexAndLend(dexCases[2]), + 1_200_000 + ); + + it('5. Base Aave and both Moonwell markets supply and redeem wallet positions', async () => { + const chain = CHAIN.BASE_SEPOLIA; + const link = '0x810D46F9a9027E28F9B01F75E2bdde839dA61115' as Address; + const usdbc = '0x4616975f7E6045FD9737e95bC527e9e14c727BD2' as Address; + const weth = '0x663A6F02d547dFd639BF689FED298712f2FB69Fb' as Address; + const faucet = '0xD9145b5F45Ad4519c7ACcD6E0A4A82e83bB8A6Dc' as Address; + const amountUSDBC = BigInt(10_000); + expect(await read(chain).getCode({ address: faucet })).not.toBeUndefined(); + f = await setupAgw(); + const rule = preset('LENDING', chain, f.agentAddress, [ + { token: link, maxPerCall: SMALL, maxTotal: SMALL }, + { token: usdbc, maxPerCall: amountUSDBC, maxTotal: amountUSDBC }, + { token: weth, maxPerCall: SMALL, maxTotal: SMALL }, + ]); + const w = await walletFor(f, chain, rule, 'e2e-preset-base-lending'); + const aave = rule.allowedCalls.find((c) => c.app === 'Aave V3')! + .target as Address; + const mUSDBC = rule.allowedCalls.find((c) => c.app === 'Moonwell mUSDbC')! + .target as Address; + const mWETH = rule.allowedCalls.find((c) => c.app === 'Moonwell mWETH')! + .target as Address; + await send( + f, + w, + chain, + w.owner, + [ + call( + faucet, + encodeFunctionData({ + abi: parseAbi(['function mint(address,address,uint256)']), + functionName: 'mint', + args: [link, w.cea, SMALL], + }) + ), + call( + usdbc, + encodeFunctionData({ + abi: parseAbi(['function allocateTo(address,uint256)']), + functionName: 'allocateTo', + args: [w.cea, amountUSDBC], + }) + ), + call( + weth, + encodeFunctionData({ + abi: parseAbi(['function mint(address,uint256)']), + functionName: 'mint', + args: [w.cea, SMALL], + }) + ), + ], + 'faucets' + ); + expect(await balance(chain, link, w.cea)).toBe(SMALL); + expect(await balance(chain, usdbc, w.cea)).toBe(amountUSDBC); + expect(await balance(chain, weth, w.cea)).toBe(SMALL); + await send( + f, + w, + chain, + w.agent, + [ + approve(link, aave, SMALL), + call( + aave, + encodeFunctionData({ + abi: AAVE, + functionName: 'supply', + args: [link, SMALL, w.cea, 0], + }) + ), + approve(usdbc, mUSDBC, amountUSDBC), + call( + mUSDBC, + encodeFunctionData({ + abi: MARKET, + functionName: 'mint', + args: [amountUSDBC], + }) + ), + approve(weth, mWETH, SMALL), + call( + mWETH, + encodeFunctionData({ + abi: MARKET, + functionName: 'mint', + args: [SMALL], + }) + ), + ], + 'lending-supply' + ); + const sharesUSDBC = await balance(chain, mUSDBC, w.cea), + sharesWETH = await balance(chain, mWETH, w.cea); + expect(sharesUSDBC).toBeGreaterThan(ZERO); + expect(sharesWETH).toBeGreaterThan(ZERO); + expect(await balance(chain, link, w.cea)).toBe(ZERO); + expect(await balance(chain, usdbc, w.cea)).toBe(ZERO); + expect(await balance(chain, weth, w.cea)).toBe(ZERO); + const redemption = await send( + f, + w, + chain, + w.agent, + [ + call( + aave, + encodeFunctionData({ + abi: AAVE, + functionName: 'withdraw', + args: [link, SMALL, w.cea], + }) + ), + call( + mUSDBC, + encodeFunctionData({ + abi: MARKET, + functionName: 'redeem', + args: [sharesUSDBC], + }) + ), + call( + mWETH, + encodeFunctionData({ + abi: MARKET, + functionName: 'redeem', + args: [sharesWETH], + }) + ), + ], + 'lending-withdraw' + ); + expect(await balance(chain, link, w.cea)).toBe(SMALL); + expect(await balance(chain, usdbc, w.cea)).toBeGreaterThanOrEqual( + (amountUSDBC * BigInt(99)) / BigInt(100) + ); + expect(await balance(chain, weth, w.cea)).toBeGreaterThanOrEqual( + (SMALL * BigInt(99)) / BigInt(100) + ); + expect(await balance(chain, mUSDBC, w.cea)).toBe(ZERO); + expect(await balance(chain, mWETH, w.cea)).toBe(ZERO); + assertRedemption( + redemption, + mUSDBC, + w.cea, + sharesUSDBC, + await balance(chain, usdbc, w.cea) + ); + assertRedemption( + redemption, + mWETH, + w.cea, + sharesWETH, + await balance(chain, weth, w.cea) + ); + f.evidence('preset-expanded-base-lending', { + chain, + wallet: w.wallet, + cea: w.cea, + link: SMALL, + usdbc: amountUSDBC, + weth: SMALL, + sharesUSDBC, + sharesWETH, + }); + }, 1_200_000); +}); diff --git a/packages/core/__e2e__/ci/suite.ts b/packages/core/__e2e__/ci/suite.ts index c0869ece..56dd7c9a 100644 --- a/packages/core/__e2e__/ci/suite.ts +++ b/packages/core/__e2e__/ci/suite.ts @@ -38,6 +38,7 @@ export const GROUPS = [ 'agw-svm-wire', 'agw-svm-replay', 'agw-presets', + 'agw-presets-expanded', ] as const; export type Group = (typeof GROUPS)[number]; @@ -985,6 +986,46 @@ export const SCENARIOS: Scenario[] = [ needs: { masterPC: '0.5' }, env: { AGW_E2E: '1' }, }, + { + id: 'agw-preset-eigen-sepolia', + group: 'agw-presets-expanded', + file: '__e2e__/agw/presets-expanded-live.spec.ts', + grep: 'agw presets expanded 1', + needs: { masterPC: '110', masterPETH: '0.000001' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-preset-dex-base', + group: 'agw-presets-expanded', + file: '__e2e__/agw/presets-expanded-live.spec.ts', + grep: 'agw presets expanded 2', + needs: { masterPC: '110' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-preset-dex-aave-arbitrum', + group: 'agw-presets-expanded', + file: '__e2e__/agw/presets-expanded-live.spec.ts', + grep: 'agw presets expanded 3', + needs: { masterPC: '110' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-preset-dex-venus-bnb', + group: 'agw-presets-expanded', + file: '__e2e__/agw/presets-expanded-live.spec.ts', + grep: 'agw presets expanded 4', + needs: { masterPC: '110' }, + env: { AGW_E2E: '1' }, + }, + { + id: 'agw-preset-base-aave-moonwell', + group: 'agw-presets-expanded', + file: '__e2e__/agw/presets-expanded-live.spec.ts', + grep: 'agw presets expanded 5', + needs: { masterPC: '110' }, + env: { AGW_E2E: '1' }, + }, { id: 'agw-preset-uniswap-live', group: 'agw-presets', diff --git a/packages/core/src/lib/agentic/__tests__/runtime-token-chain.spec.ts b/packages/core/src/lib/agentic/__tests__/runtime-token-chain.spec.ts new file mode 100644 index 00000000..aff9e9c9 --- /dev/null +++ b/packages/core/src/lib/agentic/__tests__/runtime-token-chain.spec.ts @@ -0,0 +1,69 @@ +import { getAddress } from 'viem'; +import { createAgenticRuntime } from '../runtime'; +import { CHAIN, PUSH_NETWORK } from '../../constants/enums'; +import { SYNTHETIC_PUSH_ERC20 } from '../../constants/chain'; +import { + MOVEABLE_TOKEN_CONSTANTS, + type PushChainMoveableToken, +} from '../../constants/tokens'; +import type { Orchestrator } from '../../orchestrator/orchestrator'; +const runtime = () => + createAgenticRuntime( + { + getNetwork: () => PUSH_NETWORK.TESTNET_DONUT, + getRpcUrls: () => ({}), + } as unknown as Orchestrator, + false + ); +const addresses = SYNTHETIC_PUSH_ERC20[PUSH_NETWORK.TESTNET_DONUT]; +it.each([ + [ + CHAIN.ETHEREUM_SEPOLIA, + MOVEABLE_TOKEN_CONSTANTS.ETHEREUM_SEPOLIA.ETH, + addresses.pETH, + ], + [ + CHAIN.BASE_SEPOLIA, + MOVEABLE_TOKEN_CONSTANTS.BASE_SEPOLIA.ETH, + addresses.pETH_BASE, + ], + [ + CHAIN.ARBITRUM_SEPOLIA, + MOVEABLE_TOKEN_CONSTANTS.ARBITRUM_SEPOLIA.ETH, + addresses.pETH_ARB, + ], +] as const)( + 'resolves explicit native ETH on %s to the same burn token as omitted native funds', + (chain, token, expected) => { + const rt = runtime(); + expect(rt.resolvePrc20(token, chain)).toBe(getAddress(expected)); + expect(rt.resolvePrc20({ ...token }, chain)).toBe( + rt.resolvePrc20(undefined, chain) + ); + expect(rt.resolvePrc20(token.address, chain)).toBe(getAddress(expected)); + } +); +it('does not infer a token from a different destination chain', () => { + expect(() => + runtime().resolvePrc20( + MOVEABLE_TOKEN_CONSTANTS.BASE_SEPOLIA.USDC, + CHAIN.ARBITRUM_SEPOLIA + ) + ).toThrow(); +}); +it('preserves a matching explicit Push PRC20 reference and rejects a different destination', () => { + const token: PushChainMoveableToken = { + symbol: 'pETH_ARB', + decimals: 18, + mechanism: 'approve', + address: addresses.pETH_ARB, + prc20Address: addresses.pETH_ARB, + sourceChain: CHAIN.ARBITRUM_SEPOLIA, + }; + expect(runtime().resolvePrc20(token, CHAIN.ARBITRUM_SEPOLIA)).toBe( + getAddress(addresses.pETH_ARB) + ); + expect(() => runtime().resolvePrc20(token, CHAIN.BASE_SEPOLIA)).toThrow( + 'source chain must match' + ); +}); diff --git a/packages/core/src/lib/agentic/runtime.ts b/packages/core/src/lib/agentic/runtime.ts index 0068f20e..530e672e 100644 --- a/packages/core/src/lib/agentic/runtime.ts +++ b/packages/core/src/lib/agentic/runtime.ts @@ -2,7 +2,11 @@ import { getAddress, type Address } from 'viem'; import { CHAIN, PUSH_NETWORK } from '../constants/enums'; import type { MoveableToken } from '../constants/tokens'; import { AtomicBatchUnavailableError } from '../orchestrator/internals/errors'; -import { capabilityUnavailable } from './errors'; +import { + AgenticError, + AGENTIC_ERROR_CODE, + capabilityUnavailable, +} from './errors'; import type { Orchestrator } from '../orchestrator/orchestrator'; import type { ExecuteParams, @@ -162,15 +166,25 @@ export function createAgenticRuntime( ); return { cea: getAddress(r.cea), isDeployed: r.isDeployed }; }, - resolvePrc20: (token, chain) => - getAddress( - token - ? getPRC20Address( - typeof token === 'string' ? { chain, address: token } : token, - { network } - ).address - : getNativePRC20ForChain(chain, network) - ), + resolvePrc20: (token, chain) => { + if (!token) return getAddress(getNativePRC20ForChain(chain, network)); + // Native ETH shares a symbol/address across chains. A plain token must + // resolve within the known destination, never the first global match. + if (typeof token === 'object' && 'prc20Address' in token) { + if (!('sourceChain' in token) || token.sourceChain !== chain) + throw new AgenticError( + AGENTIC_ERROR_CODE.ASSET_CHAIN_MISMATCH, + 'Push token source chain must match the destination chain' + ); + return getAddress(getPRC20Address(token, { network }).address); + } + return getAddress( + getPRC20Address( + { chain, address: typeof token === 'string' ? token : token.address }, + { network } + ).address + ); + }, nowSeconds: () => Math.floor(Date.now() / 1000), }; } From bb52e17e2b548b52d6548c9439e2b4c139367322 Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Thu, 15 Oct 2026 08:18:17 +0530 Subject: [PATCH 44/68] docs(agw): record expanded live acceptance and token regression --- plan/agw/SOURCES.md | 2 + plan/agw/implementation-status.md | 2 + plan/agw/pending-items.md | 2 +- .../MTokenInterfaces.sol | 316 + .../preset-expanded-live-2026-10-15/README.md | 59 + .../VTokenInterfaces.sol | 484 + .../preset-expanded-live-2026-10-15/api.json | 11537 ++++++++++++++++ .../base-arbitrum-fixed-live.log | 14 + .../preset-expanded-live-2026-10-15/build.log | 13 + .../check-redemptions.cjs | 11 + .../e2e-lint.log | 10 + .../eigen-live.log | 10 + .../eigen-prerequisites.json | 9 + .../initial-live.log | 48 + .../live-evidence.jsonl | 44 + .../local-contracts.log | 24 + .../preflight.log | 20 + .../prerequisites.json | 203 + .../preset-expanded-live-2026-10-15/probe.cjs | 9 + .../redemptions.json | 47 + .../runtime-lint.log | 0 .../runtime-regression-before.log | 62 + .../runtime-regression-focused.log | 10 + .../scenario-selection.log | 8 + .../preset-expanded-live-2026-10-15/unit.log | 178 + .../research/preset-live-2026-10-15/README.md | 2 +- plan/agw/section7-presets.md | 5 + 27 files changed, 13127 insertions(+), 2 deletions(-) create mode 100644 plan/agw/research/preset-expanded-live-2026-10-15/MTokenInterfaces.sol create mode 100644 plan/agw/research/preset-expanded-live-2026-10-15/README.md create mode 100644 plan/agw/research/preset-expanded-live-2026-10-15/VTokenInterfaces.sol create mode 100644 plan/agw/research/preset-expanded-live-2026-10-15/api.json create mode 100644 plan/agw/research/preset-expanded-live-2026-10-15/base-arbitrum-fixed-live.log create mode 100644 plan/agw/research/preset-expanded-live-2026-10-15/build.log create mode 100644 plan/agw/research/preset-expanded-live-2026-10-15/check-redemptions.cjs create mode 100644 plan/agw/research/preset-expanded-live-2026-10-15/e2e-lint.log create mode 100644 plan/agw/research/preset-expanded-live-2026-10-15/eigen-live.log create mode 100644 plan/agw/research/preset-expanded-live-2026-10-15/eigen-prerequisites.json create mode 100644 plan/agw/research/preset-expanded-live-2026-10-15/initial-live.log create mode 100644 plan/agw/research/preset-expanded-live-2026-10-15/live-evidence.jsonl create mode 100644 plan/agw/research/preset-expanded-live-2026-10-15/local-contracts.log create mode 100644 plan/agw/research/preset-expanded-live-2026-10-15/preflight.log create mode 100644 plan/agw/research/preset-expanded-live-2026-10-15/prerequisites.json create mode 100644 plan/agw/research/preset-expanded-live-2026-10-15/probe.cjs create mode 100644 plan/agw/research/preset-expanded-live-2026-10-15/redemptions.json create mode 100644 plan/agw/research/preset-expanded-live-2026-10-15/runtime-lint.log create mode 100644 plan/agw/research/preset-expanded-live-2026-10-15/runtime-regression-before.log create mode 100644 plan/agw/research/preset-expanded-live-2026-10-15/runtime-regression-focused.log create mode 100644 plan/agw/research/preset-expanded-live-2026-10-15/scenario-selection.log create mode 100644 plan/agw/research/preset-expanded-live-2026-10-15/unit.log diff --git a/plan/agw/SOURCES.md b/plan/agw/SOURCES.md index d6c235a0..dc0bce8f 100644 --- a/plan/agw/SOURCES.md +++ b/plan/agw/SOURCES.md @@ -75,3 +75,5 @@ October 7 v5 deployment: label contract dependency delivered. [New source snapsh October 15 focused import: [AGW Presets proposal and rules](https://app.notion.com/p/pushprotocol/AGW-Presets-proposal-and-rules-3f8188aea7f48020a9f0d10ea5325467), [snapshot](notion/agw-presets-proposal-and-rules.md), [catalog scope and verification](research/preset-catalog-2026-10-15/implementation-status.md). This was a single-page import, not a refresh of all sources. October 15 mainnet scope expansion: [official snapshots and pinned read-only verification](research/preset-mainnet-2026-10-15/README.md). [Separate live testnet acceptance](research/preset-live-2026-10-15/README.md). No mainnet transactions were broadcast. + +October 15 expanded testnet protocol acceptance and destination-aware token resolution: [fresh RPC probes, protocol interfaces, transactions and regression evidence](research/preset-expanded-live-2026-10-15/README.md). diff --git a/plan/agw/implementation-status.md b/plan/agw/implementation-status.md index a2eb4cd5..ea667589 100644 --- a/plan/agw/implementation-status.md +++ b/plan/agw/implementation-status.md @@ -1,5 +1,7 @@ # AGW SDK implementation status +**October 15 — expanded preset live acceptance:** Five additional scenarios passed across focused runs, covering every shipped testnet protocol/chain combination together with the earlier two Sepolia scenarios. Found and fixed AGW explicit ETH token resolution on Base/Arbitrum; no public signature changed. **2,101 unit tests**, **16 local contract tests**, build/typechecks/package checks pass. [Evidence, initial failures and scope limits](research/preset-expanded-live-2026-10-15/README.md). + **October 15 — presets:** Verified mainnet/testnet templates, static tuple paths and the approved zero-cap review/regenerate flow are implemented. Full unit suite: **2,096 passed**, 12 skipped. Preset-focused tests: **44 passed**; review-flow local contract suite: **16 passed**. [Current scope and remaining work](section7-presets.md). Dated entries below are historical where they differ. **Two real Donut→Sepolia protocol scenarios passed** (Uniswap swap and Aave LINK supply/withdraw, separate runs). Mainnet templates are read-only verified. Live app coverage is tracked in [preset acceptance](research/preset-live-2026-10-15/README.md). **October 14 — v6 integration complete locally:** source `ffd567d`; v6-only deployment/ABIs, atomic indexed creation, automatic outbound approvals, native/EVM EQ/MAX pins, new unlimited sentinels and linked Solana error decoding are integrated. diff --git a/plan/agw/pending-items.md b/plan/agw/pending-items.md index 299227de..5a38ed0a 100644 --- a/plan/agw/pending-items.md +++ b/plan/agw/pending-items.md @@ -5,7 +5,7 @@ October 15, 2026. The newly downloaded SDK sections 6/7 supersede the earlier `a | Item | Owner / dependency | Completion condition | | --- | --- | --- | | Native 1..32 calls in spec versus deployed maximum 8 | Product/contracts | Align spec or deploy increased ceiling; SDK enforces 8 now | -| Additional preset protocols / chains | SDK + protocol prerequisites | Verified subset is implemented on mainnet/testnet; expand excluded rows only after deployment/function/permission checks; live acceptance is per protocol/chain | +| Additional preset protocols / chains | SDK + protocol prerequisites | Every shipped testnet protocol/chain combination now has a positive live flow. Remaining coverage is borrow/repay, other markets/methods and mainnet; expand excluded protocol rows only after deployment/function/permission checks | | Exact authored ABI reconstruction on reads | Spec metadata, optional | Static tuple/fixed-array paths now work. Raw selector + word positions roundtrip losslessly; recovering original names/types requires metadata not stored by contracts | | Native historical lifetime limits | Spec/migration | Define a lossless public representation if these old grants must be editable; never drop their restrictions silently | | Revert credit | Push-core executor | Executor invokes creditRevert; verify restored spend independently | diff --git a/plan/agw/research/preset-expanded-live-2026-10-15/MTokenInterfaces.sol b/plan/agw/research/preset-expanded-live-2026-10-15/MTokenInterfaces.sol new file mode 100644 index 00000000..c7ba978a --- /dev/null +++ b/plan/agw/research/preset-expanded-live-2026-10-15/MTokenInterfaces.sol @@ -0,0 +1,316 @@ +// SPDX-License-Identifier: BSD-3-Clause +pragma solidity 0.8.19; + +import "./ComptrollerInterface.sol"; +import "./irm/InterestRateModel.sol"; +import "./EIP20NonStandardInterface.sol"; +import "./TokenErrorReporter.sol"; + +contract MTokenStorage { + /// @dev Guard variable for re-entrancy checks + bool internal _notEntered; + + /// @notice EIP-20 token name for this token + string public name; + + /// @notice EIP-20 token symbol for this token + string public symbol; + + /// @notice EIP-20 token decimals for this token + uint8 public decimals; + + /// @notice Maximum borrow rate that can ever be applied (.0005% / block) + uint internal constant borrowRateMaxMantissa = 0.0005e16; + + // @notice Maximum fraction of interest that can be set aside for reserves + uint internal constant reserveFactorMaxMantissa = 1e18; + + /// @notice Administrator for this contract + address payable public admin; + + /// @notice Pending administrator for this contract + address payable public pendingAdmin; + + /// @notice Contract which oversees inter-mToken operations + ComptrollerInterface public comptroller; + + /// @notice Model which tells what the current interest rate should be + InterestRateModel public interestRateModel; + + // @notice Initial exchange rate used when minting the first MTokens (used when totalSupply = 0) + uint internal initialExchangeRateMantissa; + + /// @notice Fraction of interest currently set aside for reserves + uint public reserveFactorMantissa; + + /// @notice Block number that interest was last accrued at + uint public accrualBlockTimestamp; + + /// @notice Accumulator of the total earned interest rate since the opening of the market + uint public borrowIndex; + + /// @notice Total amount of outstanding borrows of the underlying in this market + uint public totalBorrows; + + /// @notice Total amount of reserves of the underlying held in this market + uint public totalReserves; + + /// @notice Total number of tokens in circulation + uint public totalSupply; + + /// @notice Official record of token balances for each account + mapping(address => uint) internal accountTokens; + + /// @notice Approved token transfer amounts on behalf of others + mapping(address => mapping(address => uint)) internal transferAllowances; + + /** + * @notice Container for borrow balance information + * @member principal Total balance (with accrued interest), after applying the most recent balance-changing action + * @member interestIndex Global borrowIndex as of the most recent balance-changing action + */ + struct BorrowSnapshot { + uint principal; + uint interestIndex; + } + + // @notice Mapping of account addresses to outstanding borrow balances + mapping(address => BorrowSnapshot) internal accountBorrows; + + /// @notice Share of seized collateral that is added to reserves + uint public protocolSeizeShareMantissa; +} + +abstract contract MTokenInterface is MTokenStorage { + /// @notice Indicator that this is a MToken contract (for inspection) + bool public constant isMToken = true; + + /*** Market Events ***/ + + /// @notice Event emitted when interest is accrued + event AccrueInterest( + uint cashPrior, + uint interestAccumulated, + uint borrowIndex, + uint totalBorrows + ); + + /// @notice Event emitted when tokens are minted + event Mint(address minter, uint mintAmount, uint mintTokens); + + /// @notice Event emitted when tokens are redeemed + event Redeem(address redeemer, uint redeemAmount, uint redeemTokens); + + /// @notice Event emitted when underlying is borrowed + event Borrow( + address borrower, + uint borrowAmount, + uint accountBorrows, + uint totalBorrows + ); + + /// @notice Event emitted when a borrow is repaid + event RepayBorrow( + address payer, + address borrower, + uint repayAmount, + uint accountBorrows, + uint totalBorrows + ); + + /// @notice Event emitted when a borrow is liquidated + event LiquidateBorrow( + address liquidator, + address borrower, + uint repayAmount, + address mTokenCollateral, + uint seizeTokens + ); + + /*** Admin Events ***/ + + /// @notice Event emitted when pendingAdmin is changed + event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin); + + /// @notice Event emitted when pendingAdmin is accepted, which means admin is updated + event NewAdmin(address oldAdmin, address newAdmin); + + /// @notice Event emitted when comptroller is changed + event NewComptroller( + ComptrollerInterface oldComptroller, + ComptrollerInterface newComptroller + ); + + /// @notice Event emitted when interestRateModel is changed + event NewMarketInterestRateModel( + InterestRateModel oldInterestRateModel, + InterestRateModel newInterestRateModel + ); + + /// @notice Event emitted when the reserve factor is changed + event NewReserveFactor( + uint oldReserveFactorMantissa, + uint newReserveFactorMantissa + ); + + /// @notice Event emitted when the protocol seize share is changed + event NewProtocolSeizeShare( + uint oldProtocolSeizeShareMantissa, + uint newProtocolSeizeShareMantissa + ); + + /// @notice Event emitted when the reserves are added + event ReservesAdded( + address benefactor, + uint addAmount, + uint newTotalReserves + ); + + /// @notice Event emitted when the reserves are reduced + event ReservesReduced( + address admin, + uint reduceAmount, + uint newTotalReserves + ); + + /// @notice EIP20 Transfer event + event Transfer(address indexed from, address indexed to, uint amount); + + /// @notice EIP20 Approval event + event Approval(address indexed owner, address indexed spender, uint amount); + + /*** User Interface ***/ + + function transfer(address dst, uint amount) external virtual returns (bool); + function transferFrom( + address src, + address dst, + uint amount + ) external virtual returns (bool); + function approve( + address spender, + uint amount + ) external virtual returns (bool); + function allowance( + address owner, + address spender + ) external view virtual returns (uint); + function balanceOf(address owner) external view virtual returns (uint); + function balanceOfUnderlying(address owner) external virtual returns (uint); + function getAccountSnapshot( + address account + ) external view virtual returns (uint, uint, uint, uint); + function borrowRatePerTimestamp() external view virtual returns (uint); + function supplyRatePerTimestamp() external view virtual returns (uint); + function totalBorrowsCurrent() external virtual returns (uint); + function borrowBalanceCurrent( + address account + ) external virtual returns (uint); + function borrowBalanceStored( + address account + ) external view virtual returns (uint); + function exchangeRateCurrent() external virtual returns (uint); + function exchangeRateStored() external view virtual returns (uint); + function getCash() external view virtual returns (uint); + function accrueInterest() external virtual returns (uint); + function seize( + address liquidator, + address borrower, + uint seizeTokens + ) external virtual returns (uint); + + /*** Admin Functions ***/ + + function _setPendingAdmin( + address payable newPendingAdmin + ) external virtual returns (uint); + function _acceptAdmin() external virtual returns (uint); + function _setComptroller( + ComptrollerInterface newComptroller + ) external virtual returns (uint); + function _setReserveFactor( + uint newReserveFactorMantissa + ) external virtual returns (uint); + function _reduceReserves(uint reduceAmount) external virtual returns (uint); + function _setInterestRateModel( + InterestRateModel newInterestRateModel + ) external virtual returns (uint); + function _setProtocolSeizeShare( + uint newProtocolSeizeShareMantissa + ) external virtual returns (uint); +} + +contract MErc20Storage { + /// @notice Underlying asset for this MToken + address public underlying; +} + +abstract contract MErc20Interface is MErc20Storage { + /*** User Interface ***/ + + function mint(uint mintAmount) external virtual returns (uint); + function mintWithPermit( + uint mintAmount, + uint deadline, + uint8 v, + bytes32 r, + bytes32 s + ) external virtual returns (uint); + function redeem(uint redeemTokens) external virtual returns (uint); + function redeemUnderlying( + uint redeemAmount + ) external virtual returns (uint); + function borrow(uint borrowAmount) external virtual returns (uint); + function repayBorrow(uint repayAmount) external virtual returns (uint); + function repayBorrowBehalf( + address borrower, + uint repayAmount + ) external virtual returns (uint); + function liquidateBorrow( + address borrower, + uint repayAmount, + MTokenInterface mTokenCollateral + ) external virtual returns (uint); + function sweepToken(EIP20NonStandardInterface token) external virtual; + + /*** Admin Functions ***/ + + function _addReserves(uint addAmount) external virtual returns (uint); +} + +contract MDelegationStorage { + /// @notice Implementation address for this contract + address public implementation; +} + +abstract contract MDelegatorInterface is MDelegationStorage { + /// @notice Emitted when implementation is changed + event NewImplementation( + address oldImplementation, + address newImplementation + ); + + /** + * @notice Called by the admin to update the implementation of the delegator + * @param implementation_ The address of the new implementation for delegation + * @param allowResign Flag to indicate whether to call _resignImplementation on the old implementation + * @param becomeImplementationData The encoded bytes data to be passed to _becomeImplementation + */ + function _setImplementation( + address implementation_, + bool allowResign, + bytes memory becomeImplementationData + ) external virtual; +} + +abstract contract MDelegateInterface is MDelegationStorage { + /** + * @notice Called by the delegator on a delegate to initialize it for duty + * @dev Should revert if any issues arise which make it unfit for delegation + * @param data The encoded bytes data for any initialization + */ + function _becomeImplementation(bytes memory data) external virtual; + + /// @notice Called by the delegator on a delegate to forfeit its responsibility + function _resignImplementation() external virtual; +} diff --git a/plan/agw/research/preset-expanded-live-2026-10-15/README.md b/plan/agw/research/preset-expanded-live-2026-10-15/README.md new file mode 100644 index 00000000..3ce2a707 --- /dev/null +++ b/plan/agw/research/preset-expanded-live-2026-10-15/README.md @@ -0,0 +1,59 @@ +# Expanded preset live coverage — October 15, 2026 + +## Results + +All five additional scenarios have passing live coverage: EigenLayer 1/1; the initial multi-chain run 2 passed / 2 failed (Base and Arbitrum ETH resolution); corrected Base/Arbitrum rerun 2/2 passed. This is coverage across focused runs, not one clean five-case invocation. Original failures remain in initial-live.log. No prerequisite was silently skipped as a pass. + +Together with the earlier Sepolia Uniswap/Aave scenarios, all ten currently shipped testnet protocol/chain combinations have at least one positive live flow across seven scenarios: DEXes on all four testnets; Aave on Sepolia/Base/Arbitrum; Moonwell on Base; Venus on BNB; EigenLayer on Sepolia. This does not cover every function/market or mainnet. + +Validation: 2,101 unit tests passed / 12 skipped; 16 local contract tests passed; build, library/spec typechecks, guide, package/import/declaration/API checks and scenario-selection verification passed. Runtime lint has no errors; E2E lint has only non-null-assertion warnings. + +## Scope and checks + +Five additional opt-in scenarios under `agw-presets-expanded`. All transactions originate on Donut and execute on supported testnets. No mainnet transactions or protocol deployments. Each new wallet receives at most 100 PC, plus its fresh agent's configured gas allocation. Wrapped-native cases use 10^12 raw native-token units each. `all` continues to exclude AGW groups. + +Each destination receipt must succeed and contain CEA UniversalTxExecuted events matching the wallet, target and exact call bytes. Token balance changes and protocol shares are checked independently; a successful outer receipt alone is insufficient for Compound-style market calls that can return an error code. + +| Scenario | Destination | Assertions | +| --- | --- | --- | +| EigenLayer | Sepolia | WETH deposit, CEA underlying debit, stakerDepositShares increase | +| Uniswap | Base Sepolia | Receiver and amount rejection, actual swap output, input debit | +| Uniswap + Aave | Arbitrum Sepolia | Swap then supply/withdraw received USDC; exact underlying round trip | +| PancakeSwap + Venus | BNB testnet | Swap then mint/redeem Venus vUSDT; positive shares then zero shares; underlying return within rounding tolerance | +| Aave + Moonwell | Base Sepolia | Faucet LINK/USDbC/mock WETH; Aave supply/withdraw, both Moonwell mint/redeem balances | + +The protocol matrices use generated preset calls/pins unchanged, with bridge assets set to [] for destination-held assets. The owner funds CEAs separately. They do not establish arbitrary PRC20 bridge support, borrow/repay coverage, every market, or mainnet execution. EigenLayer withdrawal and Lido's Hoodi flows are outside current supported testnet routes/catalog scope. + +## Prerequisite investigation + +`probe.cjs` is read-only and records protocol state in `prerequisites.json`. Reads use latest state with an observed starting block, not an atomic snapshot. Initial pinned-block reads gave empty data on Base; fresh reads from publicnode and the Base public endpoint agreed on real V3 pools, so no deployment defect is claimed. Pancake's deployed router points to factory 0x0BFbCF9fa4f9C56B0F40a671Ad40E0805A091865 on BNB testnet; the older documented testnet factory address had no code. Tests read factory() from the included router. Underlying ERC20 mint probes are not proof of faucet effects; live tests assert actual received balances. + +EigenLayer WETH strategy 0x424246eF71b01ee33aA33aC590fd9a0855F5eFbc is listed in the official README retained in ../preset-catalog-2026-10-15/README.md. Its live underlying is 0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9, whitelist is enabled and deposits are unpaused (eigen-prerequisites.json). + +## SDK defect found and corrected + +Explicit Base/Arbitrum ETH token objects resolved globally by symbol/address and selected Sepolia's PRC20. Omitted native funds already used the correct chain. The real AgenticRuntime now resolves plain token objects against the destination chain, and rejects explicit Push PRC20 references with a different source chain. No public signature changed. Unit reproduction: three failures before the fix, all five cases pass after it. The full unit suite passes 2,101 tests / 12 skipped. + +Initial Base/Arbitrum attempts and subsequent corrected live results are recorded separately. Failed attempts are not counted as passing coverage. Live results and hashes are retained in the evidence file when complete. + +## Run + +From packages/core: + +- `npm run e2e:verify -- --group agw-presets-expanded` — five scenarios select five distinct tests. +- `npm run e2e:preflight -- --group agw-presets-expanded --dry-run` — master balance gate. Wrapped-native cases additionally check their chain's actual PRC20 balance before transfer. +- `npm run e2e:ci -- --group agw-presets-expanded` — serial funded run. + +Focused acceptance runs use Jest's `--testNamePattern` to avoid rebroadcasting already-passing cases. Source test names were made explicit for compatibility with the existing static manifest verifier; the initial run used equivalent parameterized names. + +## Additional redemption checks + +`check-redemptions.cjs` independently replays the three successful market redemption receipts. It verifies that all minted shares were redeemed, no shares remain, and the protocol's emitted redeemAmount exactly equals the CEA's underlying balance. These stronger event checks were also added to the E2E assertions and typechecked; they were validated against the already-completed real receipts without funding duplicate redemptions. Venus uses a four-field Redeem event; Moonwell uses three fields, as confirmed in the retained protocol interfaces. + +Observed raw returns: Venus USDT 3,360 (from 3,361 supplied), Moonwell USDbC 9,999 (from 10,000), Moonwell WETH 999,943,876,358 (from 1,000,000,000,000). The tests allow bounded share-rounding loss, and the replay proves full redemption of the position rather than merely an approximately restored balance. See redemptions.json. + +Protocol interface sources: +- https://raw.githubusercontent.com/moonwell-fi/moonwell-contracts-v2/main/src/MTokenInterfaces.sol +- https://raw.githubusercontent.com/VenusProtocol/venus-protocol/develop/contracts/Tokens/VTokens/VTokenInterfaces.sol + +Uniswap Base official source: https://developers.uniswap.org/docs/protocols/v3/deployments/v3-base-deployments. Fresh RPC checks, not just address listings, were used before swaps. diff --git a/plan/agw/research/preset-expanded-live-2026-10-15/VTokenInterfaces.sol b/plan/agw/research/preset-expanded-live-2026-10-15/VTokenInterfaces.sol new file mode 100644 index 00000000..792e3873 --- /dev/null +++ b/plan/agw/research/preset-expanded-live-2026-10-15/VTokenInterfaces.sol @@ -0,0 +1,484 @@ +// SPDX-License-Identifier: BSD-3-Clause + +pragma solidity 0.8.25; + +import { ComptrollerInterface } from "../../Comptroller/ComptrollerInterface.sol"; +import { InterestRateModelV8 } from "../../InterestRateModels/InterestRateModelV8.sol"; + +contract VTokenStorageBase { + /** + * @notice Container for borrow balance information + * @member principal Total balance (with accrued interest), after applying the most recent balance-changing action + * @member interestIndex Global borrowIndex as of the most recent balance-changing action + */ + struct BorrowSnapshot { + uint principal; + uint interestIndex; + } + + /** + * @dev Guard variable for re-entrancy checks + */ + bool internal _notEntered; + + /** + * @notice EIP-20 token name for this token + */ + string public name; + + /** + * @notice EIP-20 token symbol for this token + */ + string public symbol; + + /** + * @notice EIP-20 token decimals for this token + */ + uint8 public decimals; + + /** + * @notice Maximum borrow rate that can ever be applied (.0005% / block) + */ + + uint internal constant borrowRateMaxMantissa = 0.0005e16; + + /** + * @notice Maximum fraction of interest that can be set aside for reserves + */ + uint internal constant reserveFactorMaxMantissa = 1e18; + + /** + * @notice Administrator for this contract + */ + address payable public admin; + + /** + * @notice Pending administrator for this contract + */ + address payable public pendingAdmin; + + /** + * @notice Contract which oversees inter-vToken operations + */ + ComptrollerInterface public comptroller; + + /** + * @notice Model which tells what the current interest rate should be + */ + InterestRateModelV8 public interestRateModel; + + /** + * @notice Initial exchange rate used when minting the first VTokens (used when totalSupply = 0) + */ + uint internal initialExchangeRateMantissa; + + /** + * @notice Fraction of interest currently set aside for reserves + */ + uint public reserveFactorMantissa; + + /** + * @notice Block number that interest was last accrued at + */ + uint public accrualBlockNumber; + + /** + * @notice Accumulator of the total earned interest rate since the opening of the market + */ + uint public borrowIndex; + + /** + * @notice Total amount of outstanding borrows of the underlying in this market + */ + uint public totalBorrows; + + /** + * @notice Total amount of reserves of the underlying held in this market + */ + uint public totalReserves; + + /** + * @notice Total number of tokens in circulation + */ + uint public totalSupply; + + /** + * @notice Official record of token balances for each account + */ + mapping(address => uint) internal accountTokens; + + /** + * @notice Approved token transfer amounts on behalf of others + */ + mapping(address => mapping(address => uint)) internal transferAllowances; + + /** + * @notice Mapping of account addresses to outstanding borrow balances + */ + mapping(address => BorrowSnapshot) internal accountBorrows; + + /** + * @notice Underlying asset for this VToken + */ + address public underlying; + + /** + * @notice Implementation address for this contract + */ + address public implementation; + + /** + * @notice delta block after which reserves will be reduced + */ + uint public reduceReservesBlockDelta; + + /** + * @notice last block number at which reserves were reduced + */ + uint public reduceReservesBlockNumber; + + /** + * @notice address of protocol share reserve contract + */ + address payable public protocolShareReserve; + + /** + * @notice address of accessControlManager + */ + + address public accessControlManager; +} + +contract VTokenStorage is VTokenStorageBase { + /** + * @notice flashLoan is enabled for this market or not + */ + bool public isFlashLoanEnabled; + + /** + * @notice total fee percentage collected on flashLoan (scaled by 1e18) + */ + uint256 public flashLoanFeeMantissa; + + /** + * @notice fee percentage of flashLoan that goes to protocol (scaled by 1e18) + */ + uint256 public flashLoanProtocolShareMantissa; + + /** + * @notice Amount of flashLoan taken by the receiver + * @dev This is used to track the amount of flashLoan taken to correctly calculate the exchange rate + * during the flashLoan process. It is added to the total cash when calculating the exchange rate. + */ + uint256 public flashLoanAmount; + + /** + * @notice Tracked internal cash balance, immune to direct token transfers (donation attacks) + * @dev Updated only via doTransferIn/doTransferOut. Must be initialized via sweepTokenAndSync() after upgrade. + */ + uint256 public internalCash; + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[45] private __gap; +} + +abstract contract VTokenInterface is VTokenStorage { + /** + * @notice Indicator that this is a vToken contract (for inspection) + */ + bool public constant isVToken = true; + + /*** Market Events ***/ + + /** + * @notice Event emitted when interest is accrued + */ + event AccrueInterest(uint cashPrior, uint interestAccumulated, uint borrowIndex, uint totalBorrows); + + /** + * @notice Event emitted when tokens are minted + */ + event Mint(address minter, uint mintAmount, uint mintTokens, uint256 totalSupply); + + /** + * @notice Event emitted when tokens are minted behalf by payer to receiver + */ + event MintBehalf(address payer, address receiver, uint mintAmount, uint mintTokens, uint256 totalSupply); + + /** + * @notice Event emitted when tokens are redeemed + */ + event Redeem(address redeemer, uint redeemAmount, uint redeemTokens, uint256 totalSupply); + + /** + * @notice Event emitted when tokens are redeemed and fee is transferred + */ + event RedeemFee(address redeemer, uint feeAmount, uint redeemTokens); + + /** + * @notice Event emitted when underlying is borrowed + */ + event Borrow(address borrower, uint borrowAmount, uint accountBorrows, uint totalBorrows); + + /** + * @notice Event emitted when a borrow is repaid + */ + event RepayBorrow(address payer, address borrower, uint repayAmount, uint accountBorrows, uint totalBorrows); + + /** + * @notice Event emitted when a borrow is liquidated + */ + event LiquidateBorrow( + address liquidator, + address borrower, + uint repayAmount, + address vTokenCollateral, + uint seizeTokens + ); + + /*** Admin Events ***/ + + /** + * @notice Event emitted when pendingAdmin is changed + */ + event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin); + + /** + * @notice Event emitted when pendingAdmin is accepted, which means admin has been updated + */ + event NewAdmin(address oldAdmin, address newAdmin); + + /** + * @notice Event emitted when comptroller is changed + */ + event NewComptroller(ComptrollerInterface oldComptroller, ComptrollerInterface newComptroller); + + /** + * @notice Event emitted when interestRateModel is changed + */ + event NewMarketInterestRateModel( + InterestRateModelV8 oldInterestRateModel, + InterestRateModelV8 newInterestRateModel + ); + + /** + * @notice Event emitted when the reserve factor is changed + */ + event NewReserveFactor(uint oldReserveFactorMantissa, uint newReserveFactorMantissa); + + /** + * @notice Event emitted when the reserves are added + */ + event ReservesAdded(address benefactor, uint addAmount, uint newTotalReserves); + + /** + * @notice Event emitted when the reserves are reduced + */ + event ReservesReduced(address protocolShareReserve, uint reduceAmount, uint newTotalReserves); + + /** + * @notice EIP20 Transfer event + */ + event Transfer(address indexed from, address indexed to, uint amount); + + /** + * @notice EIP20 Approval event + */ + event Approval(address indexed owner, address indexed spender, uint amount); + + /** + * @notice Event emitted when block delta for reduce reserves get updated + */ + event NewReduceReservesBlockDelta(uint256 oldReduceReservesBlockDelta, uint256 newReduceReservesBlockDelta); + + /** + * @notice Event emitted when address of ProtocolShareReserve contract get updated + */ + event NewProtocolShareReserve(address indexed oldProtocolShareReserve, address indexed newProtocolShareReserve); + + /** + * @notice Emitted when access control address is changed by admin + */ + event NewAccessControlManager(address oldAccessControlAddress, address newAccessControlAddress); + + /** + * @notice Event emitted when flashLoanEnabled status is changed + */ + event FlashLoanStatusChanged(bool previousStatus, bool newStatus); + + /** + * @notice Event emitted when asset is transferred to receiver + */ + event TransferOutUnderlyingFlashLoan(address asset, address receiver, uint256 amount); + + /** + * @notice Event emitted when asset is transferred from sender and verified + */ + event TransferInUnderlyingFlashLoan( + address indexed asset, + address indexed sender, + uint256 amount, + uint256 totalFee, + uint256 protocolFee + ); + + /** + * @notice Event emitted when internalCash is synced with actual token balance + */ + event CashSynced(uint256 oldInternalCash, uint256 newInternalCash); + + /** + * @notice Event emitted when excess tokens are swept by admin + */ + event TokenSwept(address indexed recipient, uint256 amount); + + /** + * @notice Event emitted when flashLoan fee mantissa is updated + */ + event FlashLoanFeeUpdated( + uint256 oldFlashLoanFeeMantissa, + uint256 newFlashLoanFeeMantissa, + uint256 oldFlashLoanProtocolShare, + uint256 newFlashLoanProtocolShare + ); + + // @notice Thrown when comptroller is not valid + error InvalidComptroller(); + + // @notice Thrown when there is already an active flashLoan + error FlashLoanAlreadyActive(); + + /// @notice Thrown when flash loan fee exceeds maximum allowed + error FlashLoanFeeTooHigh(uint256 fee, uint256 maxFee); + + /// @notice Thrown when flash loan fee protocol share exceeds maximum allowed + error FlashLoanProtocolShareTooHigh(uint256 fee, uint256 maxFee); + + // @notice Thrown when the vToken does not have enough cash to lend + error InsufficientCash(); + + /// @notice Thrown when the repayment amount is insufficient to cover the total fee + error InsufficientRepayment(uint256 actualAmount, uint256 requiredTotalFee); + + /// @notice Thrown when interest accrual fails; errorCode is the underlying Error code + error AccrueInterestFailed(uint256 errorCode); + + /*** User Interface ***/ + + function transfer(address dst, uint amount) external virtual returns (bool); + + function transferFrom(address src, address dst, uint amount) external virtual returns (bool); + + function approve(address spender, uint amount) external virtual returns (bool); + + function balanceOfUnderlying(address owner) external virtual returns (uint); + + function totalBorrowsCurrent() external virtual returns (uint); + + function borrowBalanceCurrent(address account) external virtual returns (uint); + + function seize(address liquidator, address borrower, uint seizeTokens) external virtual returns (uint); + + /*** Admin Function ***/ + function _setPendingAdmin(address payable newPendingAdmin) external virtual returns (uint); + + /*** Admin Function ***/ + function _acceptAdmin() external virtual returns (uint); + + /*** Admin Function ***/ + function _setReserveFactor(uint newReserveFactorMantissa) external virtual returns (uint); + + /*** Admin Function ***/ + function _reduceReserves(uint reduceAmount) external virtual returns (uint); + + function balanceOf(address owner) external view virtual returns (uint); + + function allowance(address owner, address spender) external view virtual returns (uint); + + function getAccountSnapshot(address account) external view virtual returns (uint, uint, uint, uint); + + function borrowRatePerBlock() external view virtual returns (uint); + + function supplyRatePerBlock() external view virtual returns (uint); + + function getCash() external view virtual returns (uint); + + function exchangeRateCurrent() public virtual returns (uint); + + function accrueInterest() public virtual returns (uint); + + /*** Admin Function ***/ + function _setComptroller(ComptrollerInterface newComptroller) public virtual returns (uint); + + /*** Admin Function ***/ + function _setInterestRateModel(InterestRateModelV8 newInterestRateModel) public virtual returns (uint); + + function borrowBalanceStored(address account) public view virtual returns (uint); + + function exchangeRateStored() public view virtual returns (uint); +} + +interface VBep20Interface { + /*** User Interface ***/ + + function mint(uint mintAmount) external returns (uint); + + function mintBehalf(address receiver, uint mintAmount) external returns (uint); + + function redeem(uint redeemTokens) external returns (uint); + + function redeemUnderlying(uint redeemAmount) external returns (uint); + + function borrow(uint borrowAmount) external returns (uint); + + function repayBorrow(uint repayAmount) external returns (uint); + + function repayBorrowBehalf(address borrower, uint repayAmount) external returns (uint); + + function liquidateBorrow( + address borrower, + uint repayAmount, + VTokenInterface vTokenCollateral + ) external returns (uint); + + /*** Admin Functions ***/ + + function _addReserves(uint addAmount) external returns (uint); +} + +interface VDelegatorInterface { + /** + * @notice Emitted when implementation is changed + */ + event NewImplementation(address oldImplementation, address newImplementation); + + /** + * @notice Called by the admin to update the implementation of the delegator + * @param implementation_ The address of the new implementation for delegation + * @param allowResign Flag to indicate whether to call _resignImplementation on the old implementation + * @param becomeImplementationData The encoded bytes data to be passed to _becomeImplementation + */ + function _setImplementation( + address implementation_, + bool allowResign, + bytes memory becomeImplementationData + ) external; +} + +interface VDelegateInterface { + /** + * @notice Called by the delegator on a delegate to initialize it for duty + * @dev Should revert if any issues arise which make it unfit for delegation + * @param data The encoded bytes data for any initialization + */ + function _becomeImplementation(bytes memory data) external; + + /** + * @notice Called by the delegator on a delegate to forfeit its responsibility + */ + function _resignImplementation() external; +} diff --git a/plan/agw/research/preset-expanded-live-2026-10-15/api.json b/plan/agw/research/preset-expanded-live-2026-10-15/api.json new file mode 100644 index 00000000..9557b2b2 --- /dev/null +++ b/plan/agw/research/preset-expanded-live-2026-10-15/api.json @@ -0,0 +1,11537 @@ +{ + "baseline": "b1597b91a25dbf7f691f589b4e1e154add604315", + "head": "1f74e891c6f84f9c8bfc183c5e3d20d06e30ab48", + "compiledMatchesSource": true, + "initializeSignatureChanged": false, + "addedExports": [ + "AgenticPresets", + "ArgumentPath", + "DecodedSolanaRule", + "Pin", + "Preset", + "PresetAsset", + "PresetCategory", + "PresetOptions", + "PresetRuleTemplate", + "ReadyPresetOptions", + "RuleInput", + "Spent", + "WalletMarker" + ], + "removedExports": [ + "AgenticNetworkConstants", + "NativeRule", + "UniversalRule" + ], + "changedAgwTypes": [ + "AgenticWallet", + "AgenticError", + "AgenticRevertError", + "AGENTIC_ERROR_CODE", + "Rule", + "RuleInput", + "Pin", + "Spent", + "NativeRule", + "AssetCap", + "AllowedCall", + "UniversalRule", + "RulesRecord", + "CreateOptions", + "AgenticTxMetadata" + ], + "publicTypeChanges": [ + "AGENTIC_ERROR_CODE", + "AgenticError", + "AgenticRevertError", + "AgenticErrorCode", + "AgenticTxMetadata", + "AgenticWallet", + "AllowedCall", + "AssetCap", + "CreateOptions", + "DecodedSolanaRule", + "Rule", + "RuleInput", + "Pin", + "Spent", + "WalletMarker", + "ArgumentPath", + "RulesRecord", + "Preset", + "PresetCategory", + "PresetAsset", + "PresetOptions", + "ReadyPresetOptions", + "PresetRuleTemplate", + "AgenticPresets" + ], + "transactionMethodChanges": [], + "instanceMethodChanges": [], + "agwConstantsChanged": true, + "before": { + "exports": [ + "AGENTIC_ERROR_CODE", + "AccountRole", + "AccountStatus", + "AccountType", + "AgenticAddress", + "AgenticDoor", + "AgenticError", + "AgenticErrorCode", + "AgenticHex", + "AgenticNamespace", + "AgenticNetworkConstants", + "AgenticProgressHook", + "AgenticRevertError", + "AgenticTxMetadata", + "AgenticWallet", + "AllowedCall", + "AssetCap", + "BatchReadResponse", + "BuildReadSpecParams", + "CHAIN", + "CONTRACT_REQUEST_STATUS", + "CascadeCompletionResult", + "CascadeHopInfo", + "CascadeProgressEvent", + "CascadeTrackOptions", + "CascadedTxResponse", + "ChainSource", + "ChainTarget", + "Checkpoint", + "CheckpointKind", + "ConversionQuote", + "CreateOptions", + "CreateResult", + "DEFAULT_MAX_PC_FOR_GAS_BUFFER_BPS", + "DecodedErrorPayload", + "DecodedReadResult", + "DerivedExecutorAccount", + "EncodedReadQuery", + "EvmReadQuery", + "ForeignChainNamespace", + "FulfilOutcome", + "FundsToken", + "InsufficientPC20BalanceError", + "InvalidPC20AddressError", + "InvalidPC20MetadataError", + "InvalidReadQueryError", + "InvalidReadSpecError", + "MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT", + "MaxPCForGasCapFromNativeValueInput", + "MaxPCForGasCapInput", + "MaxPCForGasCapQuote", + "MultiChainTxResponse", + "NativeRule", + "OutboundTxDetails", + "PC20AddressResult", + "PC20AmbiguousAddressError", + "PC20Error", + "PC20ExpectedButPRC20Error", + "PC20ExportRevertedError", + "PC20FactoryMismatchError", + "PC20RegistryEntry", + "PC20RegistryMismatchError", + "PC20TokenChainMismatchError", + "PC20TokenReference", + "PC20UnknownChainNamespaceError", + "PC20UnsafeEmptyPayloadError", + "PC20WrapperNotRegisteredError", + "PC20WrapperPredictionUnavailableError", + "ParsedReadRequest", + "PreparedRead", + "PreparedUniversalTx", + "PushChain", + "PushChainBatchExecutionError", + "PushChainExecutionError", + "PushChainInitializeOptions", + "READ_ERROR_CODE", + "READ_OUTCOME", + "READ_STATUS", + "ReadCallback", + "ReadCallbackOptions", + "ReadChain", + "ReadDecodeError", + "ReadDestination", + "ReadExecuteOptions", + "ReadFees", + "ReadHeightUnavailableError", + "ReadLifecycleOptions", + "ReadNotFoundError", + "ReadOptions", + "ReadPreflight", + "ReadPrepareOptions", + "ReadQuery", + "ReadQueryOptions", + "ReadRef", + "ReadRegistryUnavailableError", + "ReadResponseTuple", + "ReadResultShape", + "ReadSpec", + "ReadSpecTuple", + "ReadSpecViolation", + "ReadStateError", + "ReadTimeoutError", + "ReadTrackOptions", + "ReadValue", + "ReadWeb2Options", + "ReceiptLike", + "RescueFundsParams", + "ResolvedAccount", + "ResolvedControllerAccounts", + "ResolvedDestination", + "Rule", + "RulesRecord", + "Selector", + "SignAuthorizationParams", + "SignedAuthorization", + "SimulateReadResult", + "SvmExecutePayloadFields", + "SvmGatewayAccountMeta", + "SvmReadQuery", + "TERMINAL_READ_STATUSES", + "TransactionRoute", + "TransactionRouteType", + "UEAStatus", + "UNIVERSAL_CALLBACK_EVM", + "UNIVERSAL_READ_REGISTRY_EVM", + "UNIVERSAL_READ_STATUS", + "UniversalAccount", + "UniversalExecuteParams", + "UniversalOutboundTxRequest", + "UniversalReadResponse", + "UniversalRule", + "UniversalSigner", + "UniversalSignerSkeleton", + "UniversalTo", + "UnsupportedPC20DestinationError", + "UnsupportedReadDestinationError", + "ValidateReadCall", + "WaitForOutboundOptions", + "WalletInfo", + "WalletSummary", + "Web2Extract", + "Web2ReadQuery", + "Web2ValueType", + "buildErc20WithdrawalMulticall", + "buildMigrationPayload", + "buildReadSpecFromPreflight", + "chainSupportsCEA", + "chainSupportsOutbound", + "decodeReadResult", + "detectRoute", + "encodeReadQuery", + "encodeSvmExecutePayload", + "getAllCEAAddresses", + "getCEAAddress", + "getCEAFactoryAddress", + "getPushAccountForCEA", + "inferResultShape", + "isCEA", + "isChainTarget", + "isPC20Reference", + "isSvmChain", + "isValidSolanaHexAddress", + "parseFulfilOutcome", + "parseReadRequestsFromReceipt", + "parseUEAVersion", + "quoteMaxPCForGasCap", + "quoteMaxPCForGasCapFromNativeValue", + "resolveDestination", + "sizeCallbackBudget", + "toCallData", + "toReadQuery", + "toRequestIdHex", + "validateReadSpec" + ], + "agw": { + "AgenticNamespace": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace", + "members": { + "create": { + "optional": false, + "readonly": false, + "type": "(label: string, options: import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions) => Promise" + }, + "derive": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n index?: number;\n}) => Promise<{\n address: `0x${string}`;\n deployed: boolean;\n index: number;\n}>" + }, + "list": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n wallets: import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary[];\n}>" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "(address: `0x${string}`) => import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet" + } + } + }, + "AgenticWallet": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "checkpoints": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n sinceBlock?: bigint;\n}) => Promise<{\n checkpoints: import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint[];\n}>" + }, + "info": { + "optional": false, + "readonly": false, + "type": "() => Promise" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n owner: `0x${string}`;\n}>" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "{\n add(rules: import(\"sdk/src/lib/agentic/agentic.types\").Rule[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise<{\n rulesIds: `0x${string}`[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n get(rulesId: `0x${string}`): Promise;\n list(): Promise<{\n rules: import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord[];\n }>;\n revoke(rulesIds: `0x${string}`[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n revoke(params: {\n all: true;\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n update(params: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n rules: {\n rule: import(\"sdk/src/lib/agentic/agentic.types\").Rule;\n rulesId: `0x${string}`;\n }[];\n }): Promise<{\n rules: {\n replaced: `0x${string}`;\n rulesId: `0x${string}`;\n }[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n}" + }, + "setLabel": { + "optional": false, + "readonly": false, + "type": "(label: string, opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n}) => Promise" + } + } + }, + "AgenticError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"CREATE_PARTIAL\" | \"DUPLICATE_RULE\" | \"FROM_NOT_ALLOWED\" | \"GATEWAY_ALLOWANCE_INSUFFICIENT\" | \"GENERATION_UNSUPPORTED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"REVOKE_NEEDS_TARGET\" | \"RULE_LIMIT_EXCEEDED\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"" + }, + "details": { + "optional": true, + "readonly": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "AgenticRevertError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticRevertError", + "members": { + "agenticCode": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + } + } + }, + "AGENTIC_ERROR_CODE": { + "type": "{\n readonly AGENT_GAS_INSUFFICIENT: \"AGENT_GAS_INSUFFICIENT\";\n readonly AGENT_IS_OWNER: \"AGENT_IS_OWNER\";\n readonly ASSET_CHAIN_MISMATCH: \"ASSET_CHAIN_MISMATCH\";\n readonly CAPABILITY_UNAVAILABLE: \"CAPABILITY_UNAVAILABLE\";\n readonly CREATE_PARTIAL: \"CREATE_PARTIAL\";\n readonly DUPLICATE_RULE: \"DUPLICATE_RULE\";\n readonly FROM_NOT_ALLOWED: \"FROM_NOT_ALLOWED\";\n readonly GATEWAY_ALLOWANCE_INSUFFICIENT: \"GATEWAY_ALLOWANCE_INSUFFICIENT\";\n readonly GENERATION_UNSUPPORTED: \"GENERATION_UNSUPPORTED\";\n readonly INCONSISTENT_READ: \"INCONSISTENT_READ\";\n readonly INDEX_RACE: \"INDEX_RACE\";\n readonly INVALID_RULE: \"INVALID_RULE\";\n readonly NO_RULES_FOR_CHAIN: \"NO_RULES_FOR_CHAIN\";\n readonly NOT_AGENTIC_WALLET: \"NOT_AGENTIC_WALLET\";\n readonly NOT_ALLOWED_IN_AGENTIC_MODE: \"NOT_ALLOWED_IN_AGENTIC_MODE\";\n readonly NOT_OWNER_OR_AGENT: \"NOT_OWNER_OR_AGENT\";\n readonly NOT_WALLET_OWNER: \"NOT_WALLET_OWNER\";\n readonly READ_ONLY: \"READ_ONLY\";\n readonly RECEIPT_MISMATCH: \"RECEIPT_MISMATCH\";\n readonly RECEIPT_UNAVAILABLE: \"RECEIPT_UNAVAILABLE\";\n readonly REVOKE_NEEDS_TARGET: \"REVOKE_NEEDS_TARGET\";\n readonly RULE_LIMIT_EXCEEDED: \"RULE_LIMIT_EXCEEDED\";\n readonly RULE_NOT_FOUND: \"RULE_NOT_FOUND\";\n readonly RULE_READ_FAILED: \"RULE_READ_FAILED\";\n readonly TARGET_NOT_ON_RULE_CHAIN: \"TARGET_NOT_ON_RULE_CHAIN\";\n readonly WALLET_BALANCE_INSUFFICIENT: \"WALLET_BALANCE_INSUFFICIENT\";\n readonly WALLET_NOT_DEPLOYED: \"WALLET_NOT_DEPLOYED\";\n}", + "members": { + "AGENT_GAS_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\"" + }, + "AGENT_IS_OWNER": { + "optional": false, + "readonly": true, + "type": "\"AGENT_IS_OWNER\"" + }, + "ASSET_CHAIN_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"ASSET_CHAIN_MISMATCH\"" + }, + "CAPABILITY_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"CAPABILITY_UNAVAILABLE\"" + }, + "CREATE_PARTIAL": { + "optional": false, + "readonly": true, + "type": "\"CREATE_PARTIAL\"" + }, + "DUPLICATE_RULE": { + "optional": false, + "readonly": true, + "type": "\"DUPLICATE_RULE\"" + }, + "FROM_NOT_ALLOWED": { + "optional": false, + "readonly": true, + "type": "\"FROM_NOT_ALLOWED\"" + }, + "GATEWAY_ALLOWANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"GATEWAY_ALLOWANCE_INSUFFICIENT\"" + }, + "GENERATION_UNSUPPORTED": { + "optional": false, + "readonly": true, + "type": "\"GENERATION_UNSUPPORTED\"" + }, + "INCONSISTENT_READ": { + "optional": false, + "readonly": true, + "type": "\"INCONSISTENT_READ\"" + }, + "INDEX_RACE": { + "optional": false, + "readonly": true, + "type": "\"INDEX_RACE\"" + }, + "INVALID_RULE": { + "optional": false, + "readonly": true, + "type": "\"INVALID_RULE\"" + }, + "NO_RULES_FOR_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"NO_RULES_FOR_CHAIN\"" + }, + "NOT_AGENTIC_WALLET": { + "optional": false, + "readonly": true, + "type": "\"NOT_AGENTIC_WALLET\"" + }, + "NOT_ALLOWED_IN_AGENTIC_MODE": { + "optional": false, + "readonly": true, + "type": "\"NOT_ALLOWED_IN_AGENTIC_MODE\"" + }, + "NOT_OWNER_OR_AGENT": { + "optional": false, + "readonly": true, + "type": "\"NOT_OWNER_OR_AGENT\"" + }, + "NOT_WALLET_OWNER": { + "optional": false, + "readonly": true, + "type": "\"NOT_WALLET_OWNER\"" + }, + "READ_ONLY": { + "optional": false, + "readonly": true, + "type": "\"READ_ONLY\"" + }, + "RECEIPT_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_MISMATCH\"" + }, + "RECEIPT_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_UNAVAILABLE\"" + }, + "REVOKE_NEEDS_TARGET": { + "optional": false, + "readonly": true, + "type": "\"REVOKE_NEEDS_TARGET\"" + }, + "RULE_LIMIT_EXCEEDED": { + "optional": false, + "readonly": true, + "type": "\"RULE_LIMIT_EXCEEDED\"" + }, + "RULE_NOT_FOUND": { + "optional": false, + "readonly": true, + "type": "\"RULE_NOT_FOUND\"" + }, + "RULE_READ_FAILED": { + "optional": false, + "readonly": true, + "type": "\"RULE_READ_FAILED\"" + }, + "TARGET_NOT_ON_RULE_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"TARGET_NOT_ON_RULE_CHAIN\"" + }, + "WALLET_BALANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"WALLET_BALANCE_INSUFFICIENT\"" + }, + "WALLET_NOT_DEPLOYED": { + "optional": false, + "readonly": true, + "type": "\"WALLET_NOT_DEPLOYED\"" + } + } + }, + "Rule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule | import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "NativeRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "amount": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AmountLimit | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "maxCalls": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValuePerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxValueTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "pins": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ArgPin[] | undefined" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "AssetCap": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap", + "members": { + "maxPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/constants/tokens\").MoveableToken" + } + } + }, + "AllowedCall": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall", + "members": { + "beneficiary": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValue": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "`${string}(${string})` | `0x${string}`" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "UniversalRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall[]" + }, + "assets": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap[]" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "`eip155:${string}` | `solana:${string}`" + }, + "maxGasPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "RulesRecord": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "enabled": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "ref": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "rule": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule | import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule" + }, + "rulesId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "CreateOptions": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions", + "members": { + "progressHook": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook | undefined" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Rule[]" + } + } + }, + "CreateResult": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateResult", + "members": { + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "rulesIds": { + "optional": false, + "readonly": false, + "type": "`0x${string}`[]" + }, + "tx": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticTxMetadata": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticTxMetadata", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destinationAccount": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "destinationCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "door": { + "optional": false, + "readonly": false, + "type": "\"agent\" | \"owner\"" + }, + "nativeCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "rawData": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rawTo": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesId": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + } + }, + "publicSurface": { + "CHAIN": { + "type": "typeof import(\"sdk/src/lib/constants/enums\").CHAIN", + "members": { + "ARBITRUM_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA" + }, + "BASE_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA" + }, + "BNB_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET" + }, + "ETHEREUM_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET" + }, + "ETHEREUM_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA" + }, + "PUSH_LOCALNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET" + }, + "PUSH_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET" + }, + "PUSH_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET" + }, + "PUSH_TESTNET_DONUT": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET" + }, + "SOLANA_DEVNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET" + }, + "SOLANA_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET" + }, + "SOLANA_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET" + }, + "WEB2": { + "optional": false, + "readonly": false, + "type": "\"web2\"" + } + } + }, + "ConversionQuote": { + "type": "import(\"sdk/src/lib/constants/tokens\").ConversionQuote", + "members": { + "amountIn": { + "optional": false, + "readonly": false, + "type": "string" + }, + "amountOut": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rate": { + "optional": false, + "readonly": false, + "type": "number" + }, + "route": { + "optional": true, + "readonly": false, + "type": "string[] | undefined" + }, + "timestamp": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "UniversalSigner": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalSigner", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "signAndSendTransaction": { + "optional": false, + "readonly": false, + "type": "(unsignedTx: Uint8Array) => Promise" + }, + "signAuthorization": { + "optional": true, + "readonly": false, + "type": "((params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise) | undefined" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": true, + "readonly": false, + "type": "(({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise) | undefined" + } + } + }, + "UniversalAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "UniversalSignerSkeleton": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "signAndSendTransaction": { + "optional": false, + "readonly": false, + "type": "(unsignedTx: Uint8Array) => Promise" + }, + "signAuthorization": { + "optional": true, + "readonly": false, + "type": "((params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise) | undefined" + }, + "signerId": { + "optional": false, + "readonly": false, + "type": "string" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": true, + "readonly": false, + "type": "(({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise) | undefined" + } + } + }, + "SignAuthorizationParams": { + "type": "{\n chainId?: number;\n contractAddress: `0x${string}`;\n executor?: \"self\";\n nonce?: number;\n}", + "members": { + "chainId": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "contractAddress": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "executor": { + "optional": true, + "readonly": false, + "type": "\"self\" | undefined" + }, + "nonce": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "SignedAuthorization": { + "type": "{\n address: `0x${string}`;\n chainId: number;\n nonce: number;\n r: `0x${string}`;\n s: `0x${string}`;\n v?: bigint;\n yParity: number;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainId": { + "optional": false, + "readonly": false, + "type": "number" + }, + "nonce": { + "optional": false, + "readonly": false, + "type": "number" + }, + "r": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "s": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "v": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "yParity": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "DerivedExecutorAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").DerivedExecutorAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean | null" + } + } + }, + "ResolvedAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainName": { + "optional": false, + "readonly": false, + "type": "string" + }, + "exists": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "role": { + "optional": true, + "readonly": false, + "type": "\"controller\" | undefined" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"cea\" | \"uea\" | \"uoa\"" + } + } + }, + "ResolvedControllerAccounts": { + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedControllerAccounts", + "members": { + "accounts": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedAccount[]" + } + } + }, + "AccountType": { + "type": "\"cea\" | \"uea\" | \"uoa\"", + "members": {} + }, + "AccountRole": { + "type": "\"controller\"", + "members": {} + }, + "PC20TokenReference": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "FundsToken": { + "type": "import(\"sdk/src/lib/constants/tokens\").MoveableToken | import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20TokenReference", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "PC20RegistryEntry": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "chainName": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "PC20AddressResult": { + "type": "{\n address: `0x${string}`;\n decimals: number;\n name: string;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n registry: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20RegistryEntry[];\n symbol: string;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "decimals": { + "optional": false, + "readonly": false, + "type": "number" + }, + "name": { + "optional": false, + "readonly": false, + "type": "string" + }, + "network": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "registry": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20RegistryEntry[]" + }, + "symbol": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "isPC20Reference": { + "type": "(token: import(\"sdk/src/lib/orchestrator/orchestrator.types\").FundsToken | undefined) => token is import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20TokenReference", + "members": {} + }, + "PC20Error": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20Error", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidPC20AddressError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InvalidPC20AddressError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20TokenChainMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20TokenChainMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20WrapperNotRegisteredError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20WrapperNotRegisteredError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20RegistryMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20RegistryMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20FactoryMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20FactoryMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidPC20MetadataError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InvalidPC20MetadataError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20ExpectedButPRC20Error": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20ExpectedButPRC20Error", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20AmbiguousAddressError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20AmbiguousAddressError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "candidates": { + "optional": false, + "readonly": true, + "type": "{\n chain: string;\n pushAddress: string;\n}[]" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "UnsupportedPC20DestinationError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").UnsupportedPC20DestinationError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InsufficientPC20BalanceError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InsufficientPC20BalanceError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20UnknownChainNamespaceError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20UnknownChainNamespaceError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20WrapperPredictionUnavailableError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20WrapperPredictionUnavailableError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20ExportRevertedError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20ExportRevertedError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "lockedAmount": { + "optional": true, + "readonly": true, + "type": "bigint | undefined" + }, + "outboundTxId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "revertRecipient": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20UnsafeEmptyPayloadError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20UnsafeEmptyPayloadError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ChainTarget": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "ChainSource": { + "type": "{\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "UniversalTo": { + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget", + "members": {} + }, + "TransactionRouteType": { + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"", + "members": {} + }, + "UniversalExecuteParams": { + "type": "{\n from?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainSource;\n migration?: boolean;\n to: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTo;\n} & Omit", + "members": { + "_minimumDepositUsd": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "_requiredFundsOverride": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "_skipFeeLocking": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "_ueaStatus": { + "optional": true, + "readonly": false, + "type": "{\n balance: bigint;\n isDeployed: boolean;\n nonce: bigint;\n} | undefined" + }, + "data": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiCall[] | undefined" + }, + "deadline": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "feeLockTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "from": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainSource | undefined" + }, + "funds": { + "optional": true, + "readonly": false, + "type": "{\n amount: bigint;\n token?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").FundsToken;\n} | undefined" + }, + "gasLimit": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFeePerGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxPCForGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxPriorityFeePerGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "migration": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "nonce": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "options": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions | undefined" + }, + "payGasWith": { + "optional": true, + "readonly": false, + "type": "{\n minAmountOut?: bigint | string;\n slippageBps?: number;\n token?: import(\"sdk/src/lib/constants/tokens\").PayableToken;\n} | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "to": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget" + }, + "value": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "UniversalOutboundTxRequest": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalOutboundTxRequest", + "members": { + "amount": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gasPrice": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxPCForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "payload": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "recipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "revertRecipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "PreparedUniversalTx": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx", + "members": { + "_hop": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").HopDescriptor" + }, + "deadline": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "estimatedGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gatewayRequest": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalOutboundTxRequest | import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxRequest" + }, + "nonce": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "payload": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + } + } + }, + "CascadedTxResponse": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadedTxResponse", + "members": { + "finalTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hopCount": { + "optional": false, + "readonly": false, + "type": "number" + }, + "hops": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo[]" + }, + "initialTxHash": { + "optional": false, + "readonly": false, + "type": "string" + }, + "initialTxResponse": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions) => Promise" + }, + "waitForAll": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions) => Promise" + } + } + }, + "CascadeHopInfo": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo", + "members": { + "executionChain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "expectedSubTxId": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hopIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "outboundDetails": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").OutboundTxDetails | undefined" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + }, + "status": { + "optional": false, + "readonly": false, + "type": "\"confirmed\" | \"failed\" | \"pending\" | \"submitted\"" + }, + "txHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "CascadeTrackOptions": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions", + "members": { + "eventHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeProgressEvent) => void) | undefined" + }, + "timeout": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "CascadeProgressEvent": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeProgressEvent", + "members": { + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "elapsed": { + "optional": false, + "readonly": false, + "type": "number" + }, + "hopIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + }, + "status": { + "optional": false, + "readonly": false, + "type": "\"confirmed\" | \"failed\" | \"found\" | \"polling\" | \"timeout\" | \"waiting\"" + }, + "txHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "CascadeCompletionResult": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeCompletionResult", + "members": { + "failedAt": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "finalTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "finalTxResponse": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadedTxResponse | undefined" + }, + "hops": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo[]" + }, + "success": { + "optional": false, + "readonly": false, + "type": "boolean" + } + } + }, + "MultiChainTxResponse": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiChainTxResponse", + "members": { + "chains": { + "optional": false, + "readonly": false, + "type": "{\n blockNumber: bigint;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n hash: string;\n status: \"confirmed\" | \"failed\" | \"pending\";\n}[]" + }, + "transactions": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse[]" + } + } + }, + "OutboundTxDetails": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").OutboundTxDetails", + "members": { + "amount": { + "optional": false, + "readonly": false, + "type": "string" + }, + "assetAddr": { + "optional": false, + "readonly": false, + "type": "string" + }, + "destinationChain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "explorerUrl": { + "optional": false, + "readonly": false, + "type": "string" + }, + "externalTxHash": { + "optional": false, + "readonly": false, + "type": "string" + }, + "recipient": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "WaitForOutboundOptions": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").WaitForOutboundOptions", + "members": { + "_expectedDestinationChain": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "_outboundIndex": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "_resolvedSubTxId": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "initialWaitMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: {\n elapsed: number;\n status: \"failed\" | \"found\" | \"polling\" | \"timeout\" | \"waiting\";\n}) => void) | undefined" + }, + "timeout": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "SvmGatewayAccountMeta": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmGatewayAccountMeta", + "members": { + "isWritable": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "pubkey": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "SvmExecutePayloadFields": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmExecutePayloadFields", + "members": { + "accounts": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmGatewayAccountMeta[]" + }, + "instructionId": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "ixData": { + "optional": false, + "readonly": false, + "type": "Uint8Array" + }, + "targetProgram": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AccountStatus": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus", + "members": { + "mode": { + "optional": false, + "readonly": false, + "type": "\"read-only\" | \"signer\"" + }, + "uea": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UEAStatus" + } + } + }, + "UEAStatus": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UEAStatus", + "members": { + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "loaded": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "minRequiredVersion": { + "optional": false, + "readonly": false, + "type": "string" + }, + "requiresUpgrade": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "version": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "RescueFundsParams": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").RescueFundsParams", + "members": { + "prc20": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "universalTxId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "parseUEAVersion": { + "type": "(version: string) => number", + "members": {} + }, + "TransactionRoute": { + "type": "typeof import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute", + "members": { + "CEA_TO_CEA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.CEA_TO_CEA" + }, + "CEA_TO_PUSH": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.CEA_TO_PUSH" + }, + "UOA_TO_CEA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.UOA_TO_CEA" + }, + "UOA_TO_PUSH": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.UOA_TO_PUSH" + } + } + }, + "detectRoute": { + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams) => import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute", + "members": {} + }, + "isChainTarget": { + "type": "(to: unknown) => to is import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget", + "members": {} + }, + "DEFAULT_MAX_PC_FOR_GAS_BUFFER_BPS": { + "type": "1000", + "members": {} + }, + "MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT": { + "type": "10000", + "members": {} + }, + "quoteMaxPCForGasCap": { + "type": "(input: import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapInput) => import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": {} + }, + "quoteMaxPCForGasCapFromNativeValue": { + "type": "(input: import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapFromNativeValueInput) => import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": {} + }, + "MaxPCForGasCapInput": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapInput", + "members": { + "bufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "gasLegNativePc": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "MaxPCForGasCapFromNativeValueInput": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapFromNativeValueInput", + "members": { + "bufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "nativeValueForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "MaxPCForGasCapQuote": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": { + "bufferBps": { + "optional": false, + "readonly": false, + "type": "number" + }, + "gasLegNativePc": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxPCForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "nativeValueForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "getCEAAddress": { + "type": "(ueaAddress: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise", + "members": {} + }, + "getPushAccountForCEA": { + "type": "(ceaAddress: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise<`0x${string}`>", + "members": {} + }, + "isCEA": { + "type": "(address: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise", + "members": {} + }, + "chainSupportsCEA": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "chainSupportsOutbound": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "getCEAFactoryAddress": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => `0x${string}` | undefined", + "members": {} + }, + "getAllCEAAddresses": { + "type": "(ueaAddress: `0x${string}`, rpcUrls?: Partial>) => Promise", + "members": {} + }, + "encodeSvmExecutePayload": { + "type": "(fields: import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmExecutePayloadFields) => `0x${string}`", + "members": {} + }, + "isSvmChain": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "isValidSolanaHexAddress": { + "type": "(address: string) => boolean", + "members": {} + }, + "buildMigrationPayload": { + "type": "() => `0x${string}`", + "members": {} + }, + "buildErc20WithdrawalMulticall": { + "type": "(tokenAddress: `0x${string}`, recipientAddress: `0x${string}`, amount: bigint) => import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiCall[]", + "members": {} + }, + "ReadChain": { + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain", + "members": {} + }, + "ReadDestination": { + "type": "{\n chain: import(\"sdk/src/lib/read-state/read-state.types\").ReadChain;\n} | {\n chainId: string;\n chainNamespace: string;\n}", + "members": {} + }, + "ResolvedDestination": { + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}", + "members": { + "caip2": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainId": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "namespace": { + "optional": false, + "readonly": false, + "type": "\"eip155\" | \"solana\" | \"web2\"" + } + } + }, + "ReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").SvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery", + "members": { + "type": { + "optional": false, + "readonly": false, + "type": "\"accountBalance\" | \"contractCall\" | \"http\" | \"lamportBalance\" | \"rawAccountData\" | \"splTokenAccount\" | \"storageSlot\"" + } + } + }, + "EvmReadQuery": { + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n target: `0x${string}`;\n type: \"contractCall\";\n} | {\n callData: `0x${string}`;\n target: `0x${string}`;\n type: \"contractCall\";\n} | {\n slot: `0x${string}` | bigint;\n target: `0x${string}`;\n type: \"storageSlot\";\n} | {\n target: `0x${string}`;\n type: \"accountBalance\";\n}", + "members": { + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"accountBalance\" | \"contractCall\" | \"storageSlot\"" + } + } + }, + "SvmReadQuery": { + "type": "{\n account: string | Uint8Array;\n accountName?: string;\n idl?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n type: \"rawAccountData\";\n} | {\n account: string | Uint8Array;\n type: \"lamportBalance\";\n} | {\n account: string | Uint8Array;\n type: \"splTokenAccount\";\n}", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "string | Uint8Array" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"lamportBalance\" | \"rawAccountData\" | \"splTokenAccount\"" + } + } + }, + "Web2ReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery", + "members": { + "body": { + "optional": true, + "readonly": false, + "type": "string | Uint8Array | undefined" + }, + "extract": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[]" + }, + "headers": { + "optional": true, + "readonly": false, + "type": "Record | undefined" + }, + "method": { + "optional": true, + "readonly": false, + "type": "\"GET\" | \"POST\" | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"http\"" + }, + "url": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "Web2Extract": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract", + "members": { + "decimals": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "path": { + "optional": false, + "readonly": false, + "type": "string" + }, + "valueType": { + "optional": false, + "readonly": false, + "type": "\"bool\" | \"bytes\" | \"int256\" | \"string\" | \"uint256\"" + } + } + }, + "Web2ValueType": { + "type": "\"bool\" | \"bytes\" | \"int256\" | \"string\" | \"uint256\"", + "members": {} + }, + "EncodedReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery", + "members": { + "blockRef": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "encoded": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "namespace": { + "optional": false, + "readonly": false, + "type": "\"eip155\" | \"solana\" | \"web2\"" + }, + "ownerBytes": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "queryType": { + "optional": false, + "readonly": false, + "type": "number" + }, + "resultShape": { + "optional": false, + "readonly": false, + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}" + }, + "warnings": { + "optional": false, + "readonly": false, + "type": "string[]" + } + } + }, + "ReadResultShape": { + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"bytes32\" | \"evmCall\" | \"raw\" | \"svmAccount\" | \"uint256\" | \"web2\"" + } + } + }, + "DecodedReadResult": { + "type": "{\n accountName: string;\n kind: \"svmAccount\";\n value: unknown;\n} | {\n kind: \"bytes32\";\n value: `0x${string}`;\n} | {\n kind: \"evmCall\";\n value: unknown;\n} | {\n kind: \"raw\";\n value: `0x${string}`;\n} | {\n kind: \"uint256\";\n value: bigint;\n} | {\n kind: \"web2\";\n values: readonly unknown[];\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"bytes32\" | \"evmCall\" | \"raw\" | \"svmAccount\" | \"uint256\" | \"web2\"" + } + } + }, + "ReadPreflight": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight", + "members": { + "destination": { + "optional": false, + "readonly": false, + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}" + }, + "fetchedAt": { + "optional": false, + "readonly": false, + "type": "number" + }, + "observedChainHeight": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pushBlockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pushGasPrice": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "universalCallback": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "universalCore": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ReadSpec": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "{\n chainId: string;\n chainNamespace: string;\n owner: `0x${string}`;\n}" + }, + "blockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "expiryPushChainHeight": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "minConfirmations": { + "optional": false, + "readonly": false, + "type": "number" + }, + "query": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "revertRecipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ReadSpecTuple": { + "type": "readonly [\n readonly [\n string,\n string,\n `0x${string}`\n ],\n `0x${string}`,\n number,\n bigint,\n bigint,\n bigint,\n `0x${string}`\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "readonly [\n string,\n string,\n `0x${string}`\n]" + }, + "1": { + "optional": false, + "readonly": true, + "type": "`0x${string}`" + }, + "2": { + "optional": false, + "readonly": true, + "type": "number" + }, + "3": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "4": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "5": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "6": { + "optional": false, + "readonly": true, + "type": "`0x${string}`" + }, + "length": { + "optional": false, + "readonly": true, + "type": "7" + } + } + }, + "BuildReadSpecParams": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").BuildReadSpecParams", + "members": { + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "budgetBuffer": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback | undefined" + }, + "callbackBudget": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "destination": { + "optional": false, + "readonly": false, + "type": "{\n chain: import(\"sdk/src/lib/read-state/read-state.types\").ReadChain;\n} | {\n chainId: string;\n chainNamespace: string;\n}" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "expiryPushChainHeight": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFeeBufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "owner": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "query": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").SvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "PreparedRead": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead", + "members": { + "__@preparedReadValue": { + "optional": true, + "readonly": true, + "type": "T | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback | undefined" + }, + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "encodedQuery": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery" + }, + "encodedSpec": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "fees": { + "optional": false, + "readonly": false, + "type": "{\n callbackBudget: bigint;\n protocolFee: bigint;\n total: bigint;\n}" + }, + "preflight": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "queryKey": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "resultShape": { + "optional": false, + "readonly": false, + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}" + }, + "spec": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec" + }, + "specTuple": { + "optional": false, + "readonly": false, + "type": "readonly [\n readonly [\n string,\n string,\n `0x${string}`\n ],\n `0x${string}`,\n number,\n bigint,\n bigint,\n bigint,\n `0x${string}`\n]" + }, + "value": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "warnings": { + "optional": false, + "readonly": false, + "type": "string[]" + } + } + }, + "ReadCallback": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "((spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpecTuple, callbackGasLimit: bigint) => readonly unknown[]) | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "gasLimit": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "target": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "SimulateReadResult": { + "type": "{\n args?: readonly unknown[];\n error: string;\n errorName?: string;\n ok: false;\n} | {\n ok: true;\n}", + "members": { + "ok": { + "optional": false, + "readonly": false, + "type": "boolean" + } + } + }, + "ParsedReadRequest": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ParsedReadRequest", + "members": { + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackTarget": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "logIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "originalFunder": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "requestId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "requestIdUint": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "spec": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec" + }, + "totalPaid": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "FulfilOutcome": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").FulfilOutcome", + "members": { + "burned": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "delivered": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "expired": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "failReason": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "gasReported": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refunded": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refundFailed": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "ReceiptLike": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike", + "members": { + "logs": { + "optional": false, + "readonly": false, + "type": "readonly {\n address: string;\n data: string;\n logIndex?: number | string;\n topics: readonly string[];\n}[]" + } + } + }, + "ReadRef": { + "type": "{\n requestId: `0x${string}` | bigint;\n} | {\n txHash: `0x${string}`;\n}", + "members": {} + }, + "ReadLifecycleOptions": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadLifecycleOptions", + "members": { + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "resultShape": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadFees": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadFees", + "members": { + "burned": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "paid": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "refunded": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refundFailed": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + } + } + }, + "UniversalReadResponse": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse", + "members": { + "callbackDelivered": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "callbackFailReason": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "decoded": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").DecodedReadResult | undefined" + }, + "decodeError": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destination": { + "optional": false, + "readonly": false, + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}" + }, + "errorMsg": { + "optional": false, + "readonly": false, + "type": "string" + }, + "explorerUrl": { + "optional": false, + "readonly": false, + "type": "string" + }, + "fees": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadFees" + }, + "isTerminal": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "outcome": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME" + }, + "pcTx": { + "optional": false, + "readonly": false, + "type": "readonly {\n blockHeight: number;\n errorMsg: string;\n status: string;\n txHash: `0x${string}`;\n}[]" + }, + "raw": { + "optional": false, + "readonly": false, + "type": "{\n errorCode: import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n resultData: `0x${string}`;\n status: import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n} | null" + }, + "refresh": { + "optional": false, + "readonly": false, + "type": "() => Promise>" + }, + "request": { + "optional": false, + "readonly": false, + "type": "{\n callbackGasLimit: bigint;\n callbackTarget: `0x${string}`;\n createdAtHeight: bigint;\n logIndex: number;\n originalFunder: `0x${string}`;\n refundTo: `0x${string}`;\n spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec;\n}" + }, + "requestId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "requestIdUint": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "status": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "value": { + "optional": true, + "readonly": false, + "type": "T | undefined" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/read-state/read-state.types\").ReadLifecycleOptions) => Promise>" + } + } + }, + "ReadResponseTuple": { + "type": "{\n -readonly [K in keyof R]: import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse ? T : unknown>;\n}", + "members": {} + }, + "BatchReadResponse": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").BatchReadResponse", + "members": { + "atomic": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "count": { + "optional": false, + "readonly": false, + "type": "number" + }, + "reads": { + "optional": false, + "readonly": false, + "type": "{\n -readonly [K in keyof R]: import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse ? T : unknown>;\n}" + }, + "transactionHashes": { + "optional": true, + "readonly": false, + "type": "readonly `0x${string}`[] | undefined" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: Omit) => Promise>" + } + } + }, + "ReadOptions": { + "type": "((import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">)) & {\n callback?: (Pick & Required>) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n };\n}", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "advanced": { + "optional": true, + "readonly": false, + "type": "{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n} | undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "({\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} & {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n}) | ({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick & Pick & Required>) | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadPrepareOptions": { + "type": "((((({\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\">) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n}) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">)) & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n}) | ((({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n}) | ({\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\">)) & {\n blockNumber?: never;\n minConfirmations?: never;\n})) & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n}) & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "advanced": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadQueryOptions": { + "type": "({\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\">) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n}) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n}) | ({\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\">)", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadCallbackOptions": { + "type": "{\n callback?: ({\n gasLimit?: bigint;\n target: `0x${string}`;\n } & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n };\n}", + "members": { + "callback": { + "optional": true, + "readonly": false, + "type": "({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} | undefined" + } + } + }, + "ReadValue": { + "type": "O extends {\n abi: infer A extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: infer F extends string;\n} ? number extends A[\"length\"] ? unknown : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, O extends {\n args: infer Args extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n} ? Args : readonly [\n] extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> ? import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> & readonly [\n] : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>> extends infer Selected ? Selected extends {\n outputs: readonly unknown[];\n type: \"function\";\n} & import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiFunction ? {\n [key in keyof {\n [key in keyof import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"]]: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterToPrimitiveType, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"][key], import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterKind>;\n }]: {\n [key in keyof import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"]]: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterToPrimitiveType, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"][key], import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterKind>;\n }[key];\n} extends infer types ? types extends readonly [\n] ? void : types extends readonly [\n infer type\n] ? type : types : never : never : never : O extends {\n web2: {\n extract: infer E extends readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n };\n} ? {\n readonly [K in keyof E]: {\n bool: boolean;\n bytes: `0x${string}`;\n int256: bigint;\n string: string;\n uint256: bigint;\n }[E[K][\"valueType\"]];\n} : O extends {\n storageSlot: unknown;\n} ? `0x${string}` : O extends {\n idl: infer I extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} ? string extends Extract, string> ? unknown : (O extends {\n functionName: infer N extends string;\n} ? N : undefined) extends string ? import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/index\").IdlAccounts[{\n [K in Extract, string>]: Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : K> extends Lowercase<(O extends {\n functionName: infer N extends string;\n } ? N : undefined) & string extends `${infer H}_${infer T}` ? `${H}${Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : (O extends {\n functionName: infer N extends string;\n } ? N : undefined) & string> ? K : never;\n}[Extract, string>]] : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/index\").IdlAccounts[Extract, string>] : bigint", + "members": {} + }, + "ValidateReadCall": { + "type": "O extends {\n abi: infer A extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: infer F extends string;\n} ? (readonly [\n] extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> ? {\n args?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n} : {\n args: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n}) & {\n functionName: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionName;\n} : O extends {\n functionName: infer N extends string;\n idl: infer I extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} ? string extends Extract, string> ? unknown : [\n {\n [K in Extract, string>]: Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : K> extends Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : N> ? K : never;\n }[Extract, string>]\n] extends [\n never\n] ? {\n functionName: Extract, string>;\n} : unknown : unknown", + "members": {} + }, + "ReadWeb2Options": { + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options", + "members": { + "body": { + "optional": true, + "readonly": false, + "type": "string | Uint8Array | undefined" + }, + "extract": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[]" + }, + "headers": { + "optional": true, + "readonly": false, + "type": "Record | undefined" + }, + "method": { + "optional": true, + "readonly": false, + "type": "\"GET\" | \"POST\" | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadTrackOptions": { + "type": "{\n advanced?: Omit, \"enforceGasCheck\">;\n resultShape?: import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape;\n}", + "members": { + "advanced": { + "optional": true, + "readonly": false, + "type": "Omit<{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n}, \"enforceGasCheck\"> | undefined" + }, + "resultShape": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape | undefined" + } + } + }, + "ReadExecuteOptions": { + "type": "{\n advanced?: {\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n } | undefined;\n progressHook?: ((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined;\n waitForCompletion?: boolean | undefined;\n}", + "members": { + "advanced": { + "optional": true, + "readonly": false, + "type": "{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n} | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + } + } + }, + "UNIVERSAL_READ_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS", + "members": { + "ABORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.ABORTED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.EXPIRED" + }, + "FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.FAILED" + }, + "FULFILLED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.FULFILLED" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.PENDING" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.UNSPECIFIED" + }, + "VOTING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.VOTING" + } + } + }, + "READ_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS", + "members": { + "ERROR": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.ERROR" + }, + "SUCCESS": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.SUCCESS" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.UNSPECIFIED" + } + } + }, + "READ_ERROR_CODE": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE", + "members": { + "INVALID_QUERY": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.INVALID_QUERY" + }, + "INVALID_RESULT": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.INVALID_RESULT" + }, + "NOT_FOUND": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.NOT_FOUND" + }, + "REJECTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.REJECTED" + }, + "REVERTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.REVERTED" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.UNSPECIFIED" + }, + "UNSUPPORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.UNSUPPORTED" + } + } + }, + "READ_OUTCOME": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME", + "members": { + "ABORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.ABORTED" + }, + "CALLBACK_FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.CALLBACK_FAILED" + }, + "DECODE_FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.DECODE_FAILED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.EXPIRED" + }, + "FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.FAILED" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.PENDING" + }, + "SOURCE_ERROR": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.SOURCE_ERROR" + }, + "SUCCESS": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.SUCCESS" + }, + "UNKNOWN": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.UNKNOWN" + } + } + }, + "CONTRACT_REQUEST_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS", + "members": { + "EXECUTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.EXECUTED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.EXPIRED" + }, + "NONE": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.NONE" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.PENDING" + }, + "SETTLED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.SETTLED" + } + } + }, + "TERMINAL_READ_STATUSES": { + "type": "ReadonlySet", + "members": {} + }, + "ReadStateError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadStateError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidReadQueryError": { + "type": "import(\"sdk/src/lib/read-state/errors\").InvalidReadQueryError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidReadSpecError": { + "type": "import(\"sdk/src/lib/read-state/errors\").InvalidReadSpecError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "violations": { + "optional": false, + "readonly": true, + "type": "readonly import(\"sdk/src/lib/read-state/errors\").ReadSpecViolation[]" + } + } + }, + "ReadHeightUnavailableError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadHeightUnavailableError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "UnsupportedReadDestinationError": { + "type": "import(\"sdk/src/lib/read-state/errors\").UnsupportedReadDestinationError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadDecodeError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadDecodeError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadTimeoutError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadTimeoutError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "lastStatus": { + "optional": false, + "readonly": true, + "type": "number" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadNotFoundError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadNotFoundError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadRegistryUnavailableError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadRegistryUnavailableError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadSpecViolation": { + "type": "\"CALLBACK_GAS_LIMIT_EXCEEDED\" | \"DOMAIN_BLOCKED\" | \"EMPTY_QUERY\" | \"EXCESSIVE_FEE\" | \"INSUFFICIENT_CALLBACK_BUDGET\" | \"INSUFFICIENT_FEE\" | \"INVALID_ACCOUNT_ID\" | \"INVALID_BLOCK_NUMBER\" | \"INVALID_EXPIRY_HEIGHT\" | \"INVALID_MIN_CONFIRMATIONS\" | \"SVM_OWNER_NOT_32_BYTES\" | \"ZERO_CALLBACK_BUDGET\" | \"ZERO_CALLBACK_GAS_LIMIT\" | \"ZERO_REVERT_RECIPIENT\"", + "members": {} + }, + "resolveDestination": { + "type": "(dest: import(\"sdk/src/lib/read-state/read-state.types\").ReadDestination) => import(\"sdk/src/lib/read-state/read-state.types\").ResolvedDestination", + "members": {} + }, + "encodeReadQuery": { + "type": "(destination: import(\"sdk/src/lib/read-state/read-state.types\").ReadDestination, query: import(\"sdk/src/lib/read-state/read-state.types\").ReadQuery, options?: {\n blockNumber?: bigint;\n minSlot?: bigint;\n}) => import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery", + "members": {} + }, + "decodeReadResult": { + "type": "(resultData: `0x${string}`, shape: import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape) => import(\"sdk/src/lib/read-state/read-state.types\").DecodedReadResult", + "members": {} + }, + "parseReadRequestsFromReceipt": { + "type": "(receipt: import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike, universalCallback: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").ParsedReadRequest[]", + "members": {} + }, + "parseFulfilOutcome": { + "type": "(receipt: import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike, universalCallback: `0x${string}`, requestId: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").FulfilOutcome", + "members": {} + }, + "buildReadSpecFromPreflight": { + "type": "(preflight: import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight, params: import(\"sdk/src/lib/read-state/read-state.types\").BuildReadSpecParams, defaults?: {\n refundTo?: `0x${string}`;\n}) => import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead", + "members": {} + }, + "validateReadSpec": { + "type": "(input: import(\"sdk/src/lib/read-state/validate\").ValidateReadSpecInput) => {\n ok: false;\n violations: import(\"sdk/src/lib/read-state/errors\").ReadSpecViolation[];\n} | {\n ok: true;\n}", + "members": {} + }, + "toCallData": { + "type": "(prepared: import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead, target: {\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: (spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpecTuple, callbackGasLimit: bigint) => readonly unknown[];\n functionName: string;\n}) => {\n data: `0x${string}`;\n value: bigint;\n}", + "members": {} + }, + "sizeCallbackBudget": { + "type": "(callbackGasLimit: bigint, pushGasPrice: bigint, buffer?: number) => bigint", + "members": {} + }, + "inferResultShape": { + "type": "(namespace: string, query: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape", + "members": {} + }, + "toRequestIdHex": { + "type": "(id: `0x${string}` | bigint) => `0x${string}`", + "members": {} + }, + "toReadQuery": { + "type": "(subject: string, o: ReadOptionsInput, resolvedTokenProgram?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@solana/web3.js/lib/index\").PublicKey) => import(\"sdk/src/lib/read-state/read-state.types\").ReadQuery", + "members": {} + }, + "UNIVERSAL_CALLBACK_EVM": { + "type": "readonly [\n {\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"requestExternalReadSelf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"estimateFee\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"statusOf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"enum RequestStatus\";\n readonly name: \"\";\n readonly type: \"uint8\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"isFulfilled\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getPendingRead\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly internalType: \"struct PendingRead\";\n readonly name: \"\";\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"totalEscrowed\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"blockedDomains\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly indexed: false;\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"readSpec\";\n readonly type: \"tuple\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"totalPaid\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"protocolFee\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ReadRequested\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"ReadFulfilled\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"reason\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"CallbackFailed\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"gasReported\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"burned\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"CallbackGasReported\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundSent\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundFailed\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RequestExpired\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"vaultPC\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ProtocolFeeDistributed\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidAccountId\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"EmptyQuery\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidMinConfirmations\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"DomainBlocked\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidBlockNumber\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidExpiryHeight\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroRevertRecipient\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroCallbackGasLimit\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint64\";\n readonly name: \"provided\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"max\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"CallbackGasLimitExceeded\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"required\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"InsufficientFee\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ExcessiveFee\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"actual\";\n readonly type: \"uint8\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"expected\";\n readonly type: \"uint8\";\n }\n ];\n readonly name: \"InvalidRequestStatus\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ContractIsPaused\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"CallerIsNotUCallbackModule\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n }\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"requestExternalReadSelf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n}" + }, + "1": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"estimateFee\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "2": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"statusOf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"enum RequestStatus\";\n readonly name: \"\";\n readonly type: \"uint8\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "3": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"isFulfilled\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "4": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getPendingRead\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly internalType: \"struct PendingRead\";\n readonly name: \"\";\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "5": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"totalEscrowed\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "6": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"blockedDomains\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "7": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly indexed: false;\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"readSpec\";\n readonly type: \"tuple\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"totalPaid\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"protocolFee\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ReadRequested\";\n readonly type: \"event\";\n}" + }, + "8": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"ReadFulfilled\";\n readonly type: \"event\";\n}" + }, + "9": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"reason\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"CallbackFailed\";\n readonly type: \"event\";\n}" + }, + "10": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"gasReported\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"burned\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"CallbackGasReported\";\n readonly type: \"event\";\n}" + }, + "11": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundSent\";\n readonly type: \"event\";\n}" + }, + "12": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundFailed\";\n readonly type: \"event\";\n}" + }, + "13": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RequestExpired\";\n readonly type: \"event\";\n}" + }, + "14": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"vaultPC\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ProtocolFeeDistributed\";\n readonly type: \"event\";\n}" + }, + "15": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidAccountId\";\n readonly type: \"error\";\n}" + }, + "16": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"EmptyQuery\";\n readonly type: \"error\";\n}" + }, + "17": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidMinConfirmations\";\n readonly type: \"error\";\n}" + }, + "18": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"DomainBlocked\";\n readonly type: \"error\";\n}" + }, + "19": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidBlockNumber\";\n readonly type: \"error\";\n}" + }, + "20": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidExpiryHeight\";\n readonly type: \"error\";\n}" + }, + "21": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroRevertRecipient\";\n readonly type: \"error\";\n}" + }, + "22": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroCallbackGasLimit\";\n readonly type: \"error\";\n}" + }, + "23": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint64\";\n readonly name: \"provided\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"max\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"CallbackGasLimitExceeded\";\n readonly type: \"error\";\n}" + }, + "24": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"required\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"InsufficientFee\";\n readonly type: \"error\";\n}" + }, + "25": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ExcessiveFee\";\n readonly type: \"error\";\n}" + }, + "26": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"actual\";\n readonly type: \"uint8\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"expected\";\n readonly type: \"uint8\";\n }\n ];\n readonly name: \"InvalidRequestStatus\";\n readonly type: \"error\";\n}" + }, + "27": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ContractIsPaused\";\n readonly type: \"error\";\n}" + }, + "28": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"CallerIsNotUCallbackModule\";\n readonly type: \"error\";\n}" + }, + "29": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n}" + }, + "length": { + "optional": false, + "readonly": true, + "type": "30" + } + } + }, + "UNIVERSAL_READ_REGISTRY_EVM": { + "type": "readonly [\n {\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n },\n {\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"read\";\n readonly outputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"universalCallback_\";\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"constructor\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"initialize\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getLocalContext\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"hasResult\";\n readonly outputs: readonly [\n {\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"onUniversalData\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"queryKeyOf\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes32\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"readerOf\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"requestOrderOf\";\n readonly outputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"universalCallback\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"resultByRequestId\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"latestResult\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"version\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"Initialized\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadRequested\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadStored\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidInitialization\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"NotInitializing\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroAddressInit\";\n readonly type: \"error\";\n }\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n },\n {\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"read\";\n readonly outputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n}" + }, + "1": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"universalCallback_\";\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"constructor\";\n}" + }, + "2": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"initialize\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n}" + }, + "3": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getLocalContext\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "4": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"hasResult\";\n readonly outputs: readonly [\n {\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "5": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"onUniversalData\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n}" + }, + "6": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"queryKeyOf\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes32\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "7": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"readerOf\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "8": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"requestOrderOf\";\n readonly outputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "9": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"universalCallback\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "10": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"resultByRequestId\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "11": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"latestResult\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "12": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"version\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"Initialized\";\n readonly type: \"event\";\n}" + }, + "13": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadRequested\";\n readonly type: \"event\";\n}" + }, + "14": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadStored\";\n readonly type: \"event\";\n}" + }, + "15": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidInitialization\";\n readonly type: \"error\";\n}" + }, + "16": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"NotInitializing\";\n readonly type: \"error\";\n}" + }, + "17": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n}" + }, + "18": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroAddressInit\";\n readonly type: \"error\";\n}" + }, + "length": { + "optional": false, + "readonly": true, + "type": "19" + } + } + }, + "PushChainExecutionError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").PushChainExecutionError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PushChainBatchExecutionError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").PushChainBatchExecutionError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": false, + "readonly": true, + "type": "`0x${string}`[]" + } + } + }, + "DecodedErrorPayload": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload", + "members": { + "decoded": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "name": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "selector": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "PushChainInitializeOptions": { + "type": "import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions", + "members": { + "agenticWallet": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "blockExplorers": { + "optional": true, + "readonly": false, + "type": "Partial> | undefined" + }, + "network": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "printTraces": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "rpcUrls": { + "optional": true, + "readonly": false, + "type": "Partial> | undefined" + } + } + }, + "AGENTIC_ERROR_CODE": { + "type": "{\n readonly AGENT_GAS_INSUFFICIENT: \"AGENT_GAS_INSUFFICIENT\";\n readonly AGENT_IS_OWNER: \"AGENT_IS_OWNER\";\n readonly ASSET_CHAIN_MISMATCH: \"ASSET_CHAIN_MISMATCH\";\n readonly CAPABILITY_UNAVAILABLE: \"CAPABILITY_UNAVAILABLE\";\n readonly CREATE_PARTIAL: \"CREATE_PARTIAL\";\n readonly DUPLICATE_RULE: \"DUPLICATE_RULE\";\n readonly FROM_NOT_ALLOWED: \"FROM_NOT_ALLOWED\";\n readonly GATEWAY_ALLOWANCE_INSUFFICIENT: \"GATEWAY_ALLOWANCE_INSUFFICIENT\";\n readonly GENERATION_UNSUPPORTED: \"GENERATION_UNSUPPORTED\";\n readonly INCONSISTENT_READ: \"INCONSISTENT_READ\";\n readonly INDEX_RACE: \"INDEX_RACE\";\n readonly INVALID_RULE: \"INVALID_RULE\";\n readonly NO_RULES_FOR_CHAIN: \"NO_RULES_FOR_CHAIN\";\n readonly NOT_AGENTIC_WALLET: \"NOT_AGENTIC_WALLET\";\n readonly NOT_ALLOWED_IN_AGENTIC_MODE: \"NOT_ALLOWED_IN_AGENTIC_MODE\";\n readonly NOT_OWNER_OR_AGENT: \"NOT_OWNER_OR_AGENT\";\n readonly NOT_WALLET_OWNER: \"NOT_WALLET_OWNER\";\n readonly READ_ONLY: \"READ_ONLY\";\n readonly RECEIPT_MISMATCH: \"RECEIPT_MISMATCH\";\n readonly RECEIPT_UNAVAILABLE: \"RECEIPT_UNAVAILABLE\";\n readonly REVOKE_NEEDS_TARGET: \"REVOKE_NEEDS_TARGET\";\n readonly RULE_LIMIT_EXCEEDED: \"RULE_LIMIT_EXCEEDED\";\n readonly RULE_NOT_FOUND: \"RULE_NOT_FOUND\";\n readonly RULE_READ_FAILED: \"RULE_READ_FAILED\";\n readonly TARGET_NOT_ON_RULE_CHAIN: \"TARGET_NOT_ON_RULE_CHAIN\";\n readonly WALLET_BALANCE_INSUFFICIENT: \"WALLET_BALANCE_INSUFFICIENT\";\n readonly WALLET_NOT_DEPLOYED: \"WALLET_NOT_DEPLOYED\";\n}", + "members": { + "AGENT_GAS_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\"" + }, + "AGENT_IS_OWNER": { + "optional": false, + "readonly": true, + "type": "\"AGENT_IS_OWNER\"" + }, + "ASSET_CHAIN_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"ASSET_CHAIN_MISMATCH\"" + }, + "CAPABILITY_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"CAPABILITY_UNAVAILABLE\"" + }, + "CREATE_PARTIAL": { + "optional": false, + "readonly": true, + "type": "\"CREATE_PARTIAL\"" + }, + "DUPLICATE_RULE": { + "optional": false, + "readonly": true, + "type": "\"DUPLICATE_RULE\"" + }, + "FROM_NOT_ALLOWED": { + "optional": false, + "readonly": true, + "type": "\"FROM_NOT_ALLOWED\"" + }, + "GATEWAY_ALLOWANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"GATEWAY_ALLOWANCE_INSUFFICIENT\"" + }, + "GENERATION_UNSUPPORTED": { + "optional": false, + "readonly": true, + "type": "\"GENERATION_UNSUPPORTED\"" + }, + "INCONSISTENT_READ": { + "optional": false, + "readonly": true, + "type": "\"INCONSISTENT_READ\"" + }, + "INDEX_RACE": { + "optional": false, + "readonly": true, + "type": "\"INDEX_RACE\"" + }, + "INVALID_RULE": { + "optional": false, + "readonly": true, + "type": "\"INVALID_RULE\"" + }, + "NO_RULES_FOR_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"NO_RULES_FOR_CHAIN\"" + }, + "NOT_AGENTIC_WALLET": { + "optional": false, + "readonly": true, + "type": "\"NOT_AGENTIC_WALLET\"" + }, + "NOT_ALLOWED_IN_AGENTIC_MODE": { + "optional": false, + "readonly": true, + "type": "\"NOT_ALLOWED_IN_AGENTIC_MODE\"" + }, + "NOT_OWNER_OR_AGENT": { + "optional": false, + "readonly": true, + "type": "\"NOT_OWNER_OR_AGENT\"" + }, + "NOT_WALLET_OWNER": { + "optional": false, + "readonly": true, + "type": "\"NOT_WALLET_OWNER\"" + }, + "READ_ONLY": { + "optional": false, + "readonly": true, + "type": "\"READ_ONLY\"" + }, + "RECEIPT_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_MISMATCH\"" + }, + "RECEIPT_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_UNAVAILABLE\"" + }, + "REVOKE_NEEDS_TARGET": { + "optional": false, + "readonly": true, + "type": "\"REVOKE_NEEDS_TARGET\"" + }, + "RULE_LIMIT_EXCEEDED": { + "optional": false, + "readonly": true, + "type": "\"RULE_LIMIT_EXCEEDED\"" + }, + "RULE_NOT_FOUND": { + "optional": false, + "readonly": true, + "type": "\"RULE_NOT_FOUND\"" + }, + "RULE_READ_FAILED": { + "optional": false, + "readonly": true, + "type": "\"RULE_READ_FAILED\"" + }, + "TARGET_NOT_ON_RULE_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"TARGET_NOT_ON_RULE_CHAIN\"" + }, + "WALLET_BALANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"WALLET_BALANCE_INSUFFICIENT\"" + }, + "WALLET_NOT_DEPLOYED": { + "optional": false, + "readonly": true, + "type": "\"WALLET_NOT_DEPLOYED\"" + } + } + }, + "AgenticError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"CREATE_PARTIAL\" | \"DUPLICATE_RULE\" | \"FROM_NOT_ALLOWED\" | \"GATEWAY_ALLOWANCE_INSUFFICIENT\" | \"GENERATION_UNSUPPORTED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"REVOKE_NEEDS_TARGET\" | \"RULE_LIMIT_EXCEEDED\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"" + }, + "details": { + "optional": true, + "readonly": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "AgenticRevertError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticRevertError", + "members": { + "agenticCode": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + } + } + }, + "AgenticAddress": { + "type": "`0x${string}`", + "members": {} + }, + "AgenticDoor": { + "type": "\"agent\" | \"owner\"", + "members": {} + }, + "AgenticErrorCode": { + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"CREATE_PARTIAL\" | \"DUPLICATE_RULE\" | \"FROM_NOT_ALLOWED\" | \"GATEWAY_ALLOWANCE_INSUFFICIENT\" | \"GENERATION_UNSUPPORTED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"REVOKE_NEEDS_TARGET\" | \"RULE_LIMIT_EXCEEDED\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"", + "members": {} + }, + "AgenticHex": { + "type": "`0x${string}`", + "members": {} + }, + "AgenticNamespace": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace", + "members": { + "create": { + "optional": false, + "readonly": false, + "type": "(label: string, options: import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions) => Promise" + }, + "derive": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n index?: number;\n}) => Promise<{\n address: `0x${string}`;\n deployed: boolean;\n index: number;\n}>" + }, + "list": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n wallets: import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary[];\n}>" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "(address: `0x${string}`) => import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet" + } + } + }, + "AgenticNetworkConstants": { + "type": "import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants", + "members": { + "ENVELOPE_VERSION": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "FACTORY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "MAX_ALLOWED_CALLS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "MAX_PINS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "RULES_POLICY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticProgressHook": { + "type": "(event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void", + "members": {} + }, + "AgenticTxMetadata": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticTxMetadata", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destinationAccount": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "destinationCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "door": { + "optional": false, + "readonly": false, + "type": "\"agent\" | \"owner\"" + }, + "nativeCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "rawData": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rawTo": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesId": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticWallet": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "checkpoints": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n sinceBlock?: bigint;\n}) => Promise<{\n checkpoints: import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint[];\n}>" + }, + "info": { + "optional": false, + "readonly": false, + "type": "() => Promise" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n owner: `0x${string}`;\n}>" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "{\n add(rules: import(\"sdk/src/lib/agentic/agentic.types\").Rule[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise<{\n rulesIds: `0x${string}`[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n get(rulesId: `0x${string}`): Promise;\n list(): Promise<{\n rules: import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord[];\n }>;\n revoke(rulesIds: `0x${string}`[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n revoke(params: {\n all: true;\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n update(params: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n rules: {\n rule: import(\"sdk/src/lib/agentic/agentic.types\").Rule;\n rulesId: `0x${string}`;\n }[];\n }): Promise<{\n rules: {\n replaced: `0x${string}`;\n rulesId: `0x${string}`;\n }[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n}" + }, + "setLabel": { + "optional": false, + "readonly": false, + "type": "(label: string, opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n}) => Promise" + } + } + }, + "AllowedCall": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall", + "members": { + "beneficiary": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValue": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "`${string}(${string})` | `0x${string}`" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AssetCap": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap", + "members": { + "maxPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/constants/tokens\").MoveableToken" + } + } + }, + "Checkpoint": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint", + "members": { + "blockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "kind": { + "optional": false, + "readonly": false, + "type": "\"OWNER_ACTION\" | \"RULES_GRANTED\" | \"RULES_REVOKED\"" + }, + "ref": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "seq": { + "optional": false, + "readonly": false, + "type": "number" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "CheckpointKind": { + "type": "\"OWNER_ACTION\" | \"RULES_GRANTED\" | \"RULES_REVOKED\"", + "members": {} + }, + "CreateOptions": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions", + "members": { + "progressHook": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook | undefined" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Rule[]" + } + } + }, + "CreateResult": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateResult", + "members": { + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "rulesIds": { + "optional": false, + "readonly": false, + "type": "`0x${string}`[]" + }, + "tx": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ForeignChainNamespace": { + "type": "`eip155:${string}` | `solana:${string}`", + "members": {} + }, + "NativeRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "amount": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AmountLimit | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "maxCalls": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValuePerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxValueTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "pins": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ArgPin[] | undefined" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Rule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule | import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "RulesRecord": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "enabled": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "ref": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "rule": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule | import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule" + }, + "rulesId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Selector": { + "type": "`${string}(${string})` | `0x${string}`", + "members": {} + }, + "UniversalRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall[]" + }, + "assets": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap[]" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "`eip155:${string}` | `solana:${string}`" + }, + "maxGasPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "WalletInfo": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").WalletInfo", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "label": { + "optional": false, + "readonly": false, + "type": "string" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "rulesCount": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "WalletSummary": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "label": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesCount": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "PushChain": { + "type": "import(\"sdk/src/lib/push-chain/push-chain\").PushChain", + "members": { + "accountStatus": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus" + }, + "accountStatusReady": { + "optional": false, + "readonly": false, + "type": "Promise" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace" + }, + "explorer": { + "optional": false, + "readonly": false, + "type": "{\n getTransactionUrl: (txHash: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n listAllUrls: () => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n listUrls: (options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n}" + }, + "funds": { + "optional": false, + "readonly": false, + "type": "{\n getConversionQuote: (amountIn: bigint, options: {\n from: import(\"sdk/src/lib/constants/tokens\").PayableToken | undefined;\n to: import(\"sdk/src/lib/constants/tokens\").MoveableToken | undefined;\n }) => Promise;\n}" + }, + "getAccountStatus": { + "optional": false, + "readonly": false, + "type": "(options?: {\n forceRefresh?: boolean;\n}) => Promise" + }, + "isReadMode": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "moveable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").MoveableTokenAccessor;\n}" + }, + "payable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").PayableTokenAccessor;\n}" + }, + "reinitialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "universal": { + "optional": false, + "readonly": false, + "type": "{\n readonly account: `0x${string}`;\n executeReads: (reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>;\n executeTransactions: (txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise;\n migrateCEA: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"migrateCEA\"];\n readonly origin: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n prepareRead: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n prepareTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"prepareTransaction\"];\n read: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n rescueFunds: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"rescueFunds\"];\n sendTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"execute\"];\n signMessage: (data: Uint8Array) => Promise;\n signTypedData: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n trackRead: {\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n };\n trackTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"trackTransaction\"];\n}" + }, + "upgradeAccount": { + "optional": false, + "readonly": false, + "type": "(options?: {\n progressHook?: (progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n}) => Promise" + } + } + } + }, + "pushChainStatic": { + "CONSTANTS": { + "optional": false, + "readonly": false, + "type": "{\n AGENTIC: Readonly>>;\n CHAIN: typeof import(\"sdk/src/lib/constants/enums\").CHAIN;\n LIBRARY: typeof import(\"sdk/src/lib/constants/enums\").LIBRARY;\n MOVEABLE: {\n TOKEN: import(\"sdk/src/lib/constants/tokens\").MoveableTokenConstantsMap;\n };\n PAYABLE: {\n TOKEN: import(\"sdk/src/lib/constants/tokens\").PayableTokenConstantsMap;\n };\n PUSH_NETWORK: typeof import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n READ: {\n readonly CALLBACK_BUDGET_BUFFER: 3;\n readonly CHAIN: {\n readonly WEB2: \"web2\";\n } & Readonly<{\n readonly ARBITRUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA;\n readonly BASE_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA;\n readonly BNB_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET;\n readonly ETHEREUM_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET;\n readonly ETHEREUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA;\n readonly PUSH_LOCALNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET;\n readonly PUSH_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET;\n readonly PUSH_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly PUSH_TESTNET_DONUT: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly SOLANA_DEVNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET;\n readonly SOLANA_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET;\n readonly SOLANA_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n readonly WEB2: \"web2\";\n }>;\n readonly DEFAULT_EXPIRY_BLOCKS: 300n;\n readonly ERROR_CODE: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n readonly MAX_CALLBACK_GAS_LIMIT: 1000000n;\n readonly MIN_CONFIRMATIONS_FLOOR: 1;\n readonly NAMESPACE: {\n readonly EVM: \"eip155\";\n readonly SVM: \"solana\";\n readonly WEB2: \"web2\";\n };\n readonly OUTCOME: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME;\n readonly REGISTRY_CALLBACK_GAS: 500000n;\n readonly RESULT_STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n readonly STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS;\n readonly UNIVERSAL_CALLBACK_ADDRESSES: Record;\n readonly UNIVERSAL_CORE_ADDRESSES: Record;\n readonly UNIVERSAL_READ_REGISTRY_ADDRESS: {\n readonly TESTNET_DONUT: \"0x00000000000000000000000000000000000000b2\";\n };\n readonly WEB2: \"web2\";\n readonly WEB2_DEFAULT_TIMEOUT_MS: 5000;\n readonly WEB2_MAX_EXTRACT_ENTRIES: 16;\n };\n}" + }, + "initialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "utils": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/utils\").Utils" + } + }, + "pushChainInstance": { + "accountStatus": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus" + }, + "accountStatusReady": { + "optional": false, + "readonly": false, + "type": "Promise" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace" + }, + "explorer": { + "optional": false, + "readonly": false, + "type": "{\n getTransactionUrl: (txHash: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n listAllUrls: () => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n listUrls: (options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n}" + }, + "funds": { + "optional": false, + "readonly": false, + "type": "{\n getConversionQuote: (amountIn: bigint, options: {\n from: import(\"sdk/src/lib/constants/tokens\").PayableToken | undefined;\n to: import(\"sdk/src/lib/constants/tokens\").MoveableToken | undefined;\n }) => Promise;\n}" + }, + "getAccountStatus": { + "optional": false, + "readonly": false, + "type": "(options?: {\n forceRefresh?: boolean;\n}) => Promise" + }, + "isReadMode": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "moveable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").MoveableTokenAccessor;\n}" + }, + "payable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").PayableTokenAccessor;\n}" + }, + "reinitialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "universal": { + "optional": false, + "readonly": false, + "type": "{\n readonly account: `0x${string}`;\n executeReads: (reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>;\n executeTransactions: (txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise;\n migrateCEA: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"migrateCEA\"];\n readonly origin: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n prepareRead: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n prepareTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"prepareTransaction\"];\n read: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n rescueFunds: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"rescueFunds\"];\n sendTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"execute\"];\n signMessage: (data: Uint8Array) => Promise;\n signTypedData: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n trackRead: {\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n };\n trackTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"trackTransaction\"];\n}" + }, + "upgradeAccount": { + "optional": false, + "readonly": false, + "type": "(options?: {\n progressHook?: (progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n}) => Promise" + } + }, + "transactionMethods": { + "account": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "executeReads": { + "optional": false, + "readonly": false, + "type": "(reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>" + }, + "executeTransactions": { + "optional": false, + "readonly": false, + "type": "(txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise" + }, + "migrateCEA": { + "optional": false, + "readonly": false, + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => Promise" + }, + "origin": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "prepareRead": { + "optional": false, + "readonly": false, + "type": "(subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>" + }, + "prepareTransaction": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions) => Promise" + }, + "read": { + "optional": false, + "readonly": false, + "type": "(subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>" + }, + "rescueFunds": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").RescueFundsParams) => Promise" + }, + "sendTransaction": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").ExecuteParams | import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions) => Promise" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": false, + "readonly": false, + "type": "({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise" + }, + "trackRead": { + "optional": false, + "readonly": false, + "type": "{\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n}" + }, + "trackTransaction": { + "optional": false, + "readonly": false, + "type": "(txHash: string, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TrackTransactionOptions) => Promise" + } + }, + "utilityMethods": { + "account": { + "optional": false, + "readonly": false, + "type": "{\n convertExecutorToOriginAccount: (ueaAddress: `0x${string}`, options?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n }) => Promise;\n convertOriginToExecutor: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n onlyCompute?: boolean;\n }) => Promise;\n deriveExecutorAccount: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n skipNetworkCheck?: boolean;\n }) => Promise;\n fromChainAgnostic: (caip: string) => import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n resolveControllerAccount: (address: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n skipNetworkCheck?: boolean;\n }) => Promise;\n toChainAgnostic: (address: string, options: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n toUniversal: (address: string, options: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n}" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "{\n actionId: (target: `0x${string}`, selector: \"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector) => `0x${string}`;\n configId: (wallet: `0x${string}`, rulesId: `0x${string}`, actionId: `0x${string}`) => `0x${string}`;\n decodeRules: (bytes: `0x${string}`, ctx?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n pushChainNamespace?: string;\n }) => import(\"sdk/src/lib/agentic/agentic.types\").Rule;\n}" + }, + "chains": { + "optional": false, + "readonly": false, + "type": "{\n getChainName: (chainNamespace: string) => string | undefined;\n getChainNamespace: (chainName: string) => string | undefined;\n getSupportedChains: (network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK) => {\n chains: import(\"sdk/src/lib/constants/enums\").CHAIN[];\n };\n getSupportedChainsByName: (network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK) => {\n chains: string[];\n };\n}" + }, + "conversion": { + "optional": false, + "readonly": false, + "type": "{\n slippageToMinAmount(amount: string, options: {\n slippageBps: number;\n }): string;\n}" + }, + "helpers": { + "optional": false, + "readonly": false, + "type": "{\n encodeTxData({ abi, idl, functionName, args, }: {\n abi?: any;\n args?: any[];\n functionName: string;\n idl?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n }): `0x${string}`;\n formatUnits(value: bigint | string, decimalsOrOptions: {\n decimals: number;\n precision?: number;\n } | number): string;\n getChainName: (chainName: string) => string | undefined;\n parseUnits(value: string, exponent: {\n decimals: number;\n } | number): bigint;\n}" + }, + "signer": { + "optional": false, + "readonly": false, + "type": "{\n construct: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options: {\n signAndSendTransaction: (unsignedTx: Uint8Array) => Promise;\n signAuthorization?: (params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise;\n signMessage: (data: Uint8Array) => Promise;\n signTypedData?: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n }) => import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton;\n toUniversal: (signer: import(\"sdk/src/lib/universal/universal.types\").EthersV5SignerType | import(\"sdk/src/lib/universal/universal.types\").EthersV6SignerType | import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton | import(\"sdk/src/lib/universal/universal.types\").ViemSignerType) => Promise;\n toUniversalFromKeypair: (clientOrAccount: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@solana/web3.js/lib/index\").Keypair | import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").WalletClient | import(\"sdk/src/lib/universal/universal.types\").EthersV6SignerType, { chain, library }: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n library: import(\"sdk/src/lib/constants/enums\").LIBRARY;\n }) => Promise;\n}" + }, + "svm": { + "optional": false, + "readonly": false, + "type": "{\n getRegisteredIdls: () => Array<{\n address: `0x${string}`;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n }>;\n registerIdl: (idl: unknown) => void;\n}" + }, + "tokens": { + "optional": false, + "readonly": false, + "type": "{\n getMoveableTokens(chainOrClient?: import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/push-chain/push-chain\").PushChain): {\n tokens: Array<{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n decimals: number;\n mechanism: \"approve\" | \"native\" | \"permit2\";\n prc20Address?: `0x${string}`;\n sourceChain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n symbol: string;\n }>;\n };\n getPayableTokens(chainOrClient?: import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/push-chain/push-chain\").PushChain): {\n tokens: Array<{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n decimals: number;\n mechanism: \"approve\" | \"native\" | \"permit2\";\n symbol: string;\n }>;\n };\n getPC20Address(address: string, options: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n rpcUrls?: Partial>;\n strict?: boolean;\n }): Promise;\n getPRC20Address(token: {\n address: string;\n chain: string;\n } | import(\"sdk/src/lib/constants/tokens\").MoveableToken, options?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n }): {\n address: `0x${string}`;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n decimals: number;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n symbol: string;\n };\n}" + } + }, + "initialize": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise", + "agwConstants": { + "ENVELOPE_VERSION": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "FACTORY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "MAX_ALLOWED_CALLS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "MAX_PINS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "RULES_POLICY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + }, + "constants": { + "AGENTIC": { + "optional": false, + "readonly": false, + "type": "{\n readonly LOCALNET?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n readonly MAINNET?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n readonly TESTNET?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n readonly TESTNET_DONUT?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n}" + }, + "CHAIN": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "LIBRARY": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").LIBRARY" + }, + "MOVEABLE": { + "optional": false, + "readonly": false, + "type": "{\n TOKEN: import(\"sdk/src/lib/constants/tokens\").MoveableTokenConstantsMap;\n}" + }, + "PAYABLE": { + "optional": false, + "readonly": false, + "type": "{\n TOKEN: import(\"sdk/src/lib/constants/tokens\").PayableTokenConstantsMap;\n}" + }, + "PUSH_NETWORK": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "READ": { + "optional": false, + "readonly": false, + "type": "{\n readonly CALLBACK_BUDGET_BUFFER: 3;\n readonly CHAIN: {\n readonly WEB2: \"web2\";\n } & Readonly<{\n readonly ARBITRUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA;\n readonly BASE_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA;\n readonly BNB_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET;\n readonly ETHEREUM_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET;\n readonly ETHEREUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA;\n readonly PUSH_LOCALNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET;\n readonly PUSH_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET;\n readonly PUSH_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly PUSH_TESTNET_DONUT: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly SOLANA_DEVNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET;\n readonly SOLANA_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET;\n readonly SOLANA_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n readonly WEB2: \"web2\";\n }>;\n readonly DEFAULT_EXPIRY_BLOCKS: 300n;\n readonly ERROR_CODE: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n readonly MAX_CALLBACK_GAS_LIMIT: 1000000n;\n readonly MIN_CONFIRMATIONS_FLOOR: 1;\n readonly NAMESPACE: {\n readonly EVM: \"eip155\";\n readonly SVM: \"solana\";\n readonly WEB2: \"web2\";\n };\n readonly OUTCOME: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME;\n readonly REGISTRY_CALLBACK_GAS: 500000n;\n readonly RESULT_STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n readonly STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS;\n readonly UNIVERSAL_CALLBACK_ADDRESSES: Record;\n readonly UNIVERSAL_CORE_ADDRESSES: Record;\n readonly UNIVERSAL_READ_REGISTRY_ADDRESS: {\n readonly TESTNET_DONUT: \"0x00000000000000000000000000000000000000b2\";\n };\n readonly WEB2: \"web2\";\n readonly WEB2_DEFAULT_TIMEOUT_MS: 5000;\n readonly WEB2_MAX_EXTRACT_ENTRIES: 16;\n}" + } + } + }, + "after": { + "exports": [ + "AGENTIC_ERROR_CODE", + "AccountRole", + "AccountStatus", + "AccountType", + "AgenticAddress", + "AgenticDoor", + "AgenticError", + "AgenticErrorCode", + "AgenticHex", + "AgenticNamespace", + "AgenticPresets", + "AgenticProgressHook", + "AgenticRevertError", + "AgenticTxMetadata", + "AgenticWallet", + "AllowedCall", + "ArgumentPath", + "AssetCap", + "BatchReadResponse", + "BuildReadSpecParams", + "CHAIN", + "CONTRACT_REQUEST_STATUS", + "CascadeCompletionResult", + "CascadeHopInfo", + "CascadeProgressEvent", + "CascadeTrackOptions", + "CascadedTxResponse", + "ChainSource", + "ChainTarget", + "Checkpoint", + "CheckpointKind", + "ConversionQuote", + "CreateOptions", + "CreateResult", + "DEFAULT_MAX_PC_FOR_GAS_BUFFER_BPS", + "DecodedErrorPayload", + "DecodedReadResult", + "DecodedSolanaRule", + "DerivedExecutorAccount", + "EncodedReadQuery", + "EvmReadQuery", + "ForeignChainNamespace", + "FulfilOutcome", + "FundsToken", + "InsufficientPC20BalanceError", + "InvalidPC20AddressError", + "InvalidPC20MetadataError", + "InvalidReadQueryError", + "InvalidReadSpecError", + "MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT", + "MaxPCForGasCapFromNativeValueInput", + "MaxPCForGasCapInput", + "MaxPCForGasCapQuote", + "MultiChainTxResponse", + "OutboundTxDetails", + "PC20AddressResult", + "PC20AmbiguousAddressError", + "PC20Error", + "PC20ExpectedButPRC20Error", + "PC20ExportRevertedError", + "PC20FactoryMismatchError", + "PC20RegistryEntry", + "PC20RegistryMismatchError", + "PC20TokenChainMismatchError", + "PC20TokenReference", + "PC20UnknownChainNamespaceError", + "PC20UnsafeEmptyPayloadError", + "PC20WrapperNotRegisteredError", + "PC20WrapperPredictionUnavailableError", + "ParsedReadRequest", + "Pin", + "PreparedRead", + "PreparedUniversalTx", + "Preset", + "PresetAsset", + "PresetCategory", + "PresetOptions", + "PresetRuleTemplate", + "PushChain", + "PushChainBatchExecutionError", + "PushChainExecutionError", + "PushChainInitializeOptions", + "READ_ERROR_CODE", + "READ_OUTCOME", + "READ_STATUS", + "ReadCallback", + "ReadCallbackOptions", + "ReadChain", + "ReadDecodeError", + "ReadDestination", + "ReadExecuteOptions", + "ReadFees", + "ReadHeightUnavailableError", + "ReadLifecycleOptions", + "ReadNotFoundError", + "ReadOptions", + "ReadPreflight", + "ReadPrepareOptions", + "ReadQuery", + "ReadQueryOptions", + "ReadRef", + "ReadRegistryUnavailableError", + "ReadResponseTuple", + "ReadResultShape", + "ReadSpec", + "ReadSpecTuple", + "ReadSpecViolation", + "ReadStateError", + "ReadTimeoutError", + "ReadTrackOptions", + "ReadValue", + "ReadWeb2Options", + "ReadyPresetOptions", + "ReceiptLike", + "RescueFundsParams", + "ResolvedAccount", + "ResolvedControllerAccounts", + "ResolvedDestination", + "Rule", + "RuleInput", + "RulesRecord", + "Selector", + "SignAuthorizationParams", + "SignedAuthorization", + "SimulateReadResult", + "Spent", + "SvmExecutePayloadFields", + "SvmGatewayAccountMeta", + "SvmReadQuery", + "TERMINAL_READ_STATUSES", + "TransactionRoute", + "TransactionRouteType", + "UEAStatus", + "UNIVERSAL_CALLBACK_EVM", + "UNIVERSAL_READ_REGISTRY_EVM", + "UNIVERSAL_READ_STATUS", + "UniversalAccount", + "UniversalExecuteParams", + "UniversalOutboundTxRequest", + "UniversalReadResponse", + "UniversalSigner", + "UniversalSignerSkeleton", + "UniversalTo", + "UnsupportedPC20DestinationError", + "UnsupportedReadDestinationError", + "ValidateReadCall", + "WaitForOutboundOptions", + "WalletInfo", + "WalletMarker", + "WalletSummary", + "Web2Extract", + "Web2ReadQuery", + "Web2ValueType", + "buildErc20WithdrawalMulticall", + "buildMigrationPayload", + "buildReadSpecFromPreflight", + "chainSupportsCEA", + "chainSupportsOutbound", + "decodeReadResult", + "detectRoute", + "encodeReadQuery", + "encodeSvmExecutePayload", + "getAllCEAAddresses", + "getCEAAddress", + "getCEAFactoryAddress", + "getPushAccountForCEA", + "inferResultShape", + "isCEA", + "isChainTarget", + "isPC20Reference", + "isSvmChain", + "isValidSolanaHexAddress", + "parseFulfilOutcome", + "parseReadRequestsFromReceipt", + "parseUEAVersion", + "quoteMaxPCForGasCap", + "quoteMaxPCForGasCapFromNativeValue", + "resolveDestination", + "sizeCallbackBudget", + "toCallData", + "toReadQuery", + "toRequestIdHex", + "validateReadSpec" + ], + "agw": { + "AgenticNamespace": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace", + "members": { + "create": { + "optional": false, + "readonly": false, + "type": "(label: string, options: import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions) => Promise" + }, + "derive": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n index?: number;\n}) => Promise<{\n address: `0x${string}`;\n deployed: boolean;\n index: number;\n}>" + }, + "list": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n wallets: import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary[];\n}>" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "(address: `0x${string}`) => import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet" + } + } + }, + "AgenticWallet": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "checkpoints": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n sinceBlock?: bigint;\n}) => Promise<{\n checkpoints: import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint[];\n}>" + }, + "info": { + "optional": false, + "readonly": false, + "type": "() => Promise" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n owner: `0x${string}`;\n}>" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "{\n add(rules: import(\"sdk/src/lib/agentic/agentic.types\").RuleInput[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise<{\n rulesIds: `0x${string}`[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n delete(rulesIds: `0x${string}`[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n delete(params: {\n all: true;\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n get(rulesId: `0x${string}`): Promise;\n list(): Promise<{\n rules: import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord[];\n }>;\n update(params: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n rules: {\n rule: import(\"sdk/src/lib/agentic/agentic.types\").RuleInput;\n rulesId: `0x${string}`;\n }[];\n }): Promise<{\n rules: {\n replaced: `0x${string}`;\n rulesId: `0x${string}`;\n }[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n}" + }, + "setLabel": { + "optional": false, + "readonly": false, + "type": "(label: string, opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n}) => Promise" + } + } + }, + "AgenticError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"AMBIGUOUS_RULE\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"DELETE_NEEDS_TARGET\" | \"DUPLICATE_RULE\" | \"FROM_NOT_ALLOWED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"" + }, + "details": { + "optional": true, + "readonly": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "AgenticRevertError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticRevertError", + "members": { + "agenticCode": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "AGENTIC_ERROR_CODE": { + "type": "{\n readonly AGENT_GAS_INSUFFICIENT: \"AGENT_GAS_INSUFFICIENT\";\n readonly AGENT_IS_OWNER: \"AGENT_IS_OWNER\";\n readonly AMBIGUOUS_RULE: \"AMBIGUOUS_RULE\";\n readonly ASSET_CHAIN_MISMATCH: \"ASSET_CHAIN_MISMATCH\";\n readonly CAPABILITY_UNAVAILABLE: \"CAPABILITY_UNAVAILABLE\";\n readonly DELETE_NEEDS_TARGET: \"DELETE_NEEDS_TARGET\";\n readonly DUPLICATE_RULE: \"DUPLICATE_RULE\";\n readonly FROM_NOT_ALLOWED: \"FROM_NOT_ALLOWED\";\n readonly INCONSISTENT_READ: \"INCONSISTENT_READ\";\n readonly INDEX_RACE: \"INDEX_RACE\";\n readonly INVALID_RULE: \"INVALID_RULE\";\n readonly NO_RULES_FOR_CHAIN: \"NO_RULES_FOR_CHAIN\";\n readonly NOT_AGENTIC_WALLET: \"NOT_AGENTIC_WALLET\";\n readonly NOT_ALLOWED_IN_AGENTIC_MODE: \"NOT_ALLOWED_IN_AGENTIC_MODE\";\n readonly NOT_OWNER_OR_AGENT: \"NOT_OWNER_OR_AGENT\";\n readonly NOT_WALLET_OWNER: \"NOT_WALLET_OWNER\";\n readonly READ_ONLY: \"READ_ONLY\";\n readonly RECEIPT_MISMATCH: \"RECEIPT_MISMATCH\";\n readonly RECEIPT_UNAVAILABLE: \"RECEIPT_UNAVAILABLE\";\n readonly RULE_NOT_FOUND: \"RULE_NOT_FOUND\";\n readonly RULE_READ_FAILED: \"RULE_READ_FAILED\";\n readonly TARGET_NOT_ON_RULE_CHAIN: \"TARGET_NOT_ON_RULE_CHAIN\";\n readonly WALLET_BALANCE_INSUFFICIENT: \"WALLET_BALANCE_INSUFFICIENT\";\n readonly WALLET_NOT_DEPLOYED: \"WALLET_NOT_DEPLOYED\";\n}", + "members": { + "AGENT_GAS_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\"" + }, + "AGENT_IS_OWNER": { + "optional": false, + "readonly": true, + "type": "\"AGENT_IS_OWNER\"" + }, + "AMBIGUOUS_RULE": { + "optional": false, + "readonly": true, + "type": "\"AMBIGUOUS_RULE\"" + }, + "ASSET_CHAIN_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"ASSET_CHAIN_MISMATCH\"" + }, + "CAPABILITY_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"CAPABILITY_UNAVAILABLE\"" + }, + "DELETE_NEEDS_TARGET": { + "optional": false, + "readonly": true, + "type": "\"DELETE_NEEDS_TARGET\"" + }, + "DUPLICATE_RULE": { + "optional": false, + "readonly": true, + "type": "\"DUPLICATE_RULE\"" + }, + "FROM_NOT_ALLOWED": { + "optional": false, + "readonly": true, + "type": "\"FROM_NOT_ALLOWED\"" + }, + "INCONSISTENT_READ": { + "optional": false, + "readonly": true, + "type": "\"INCONSISTENT_READ\"" + }, + "INDEX_RACE": { + "optional": false, + "readonly": true, + "type": "\"INDEX_RACE\"" + }, + "INVALID_RULE": { + "optional": false, + "readonly": true, + "type": "\"INVALID_RULE\"" + }, + "NO_RULES_FOR_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"NO_RULES_FOR_CHAIN\"" + }, + "NOT_AGENTIC_WALLET": { + "optional": false, + "readonly": true, + "type": "\"NOT_AGENTIC_WALLET\"" + }, + "NOT_ALLOWED_IN_AGENTIC_MODE": { + "optional": false, + "readonly": true, + "type": "\"NOT_ALLOWED_IN_AGENTIC_MODE\"" + }, + "NOT_OWNER_OR_AGENT": { + "optional": false, + "readonly": true, + "type": "\"NOT_OWNER_OR_AGENT\"" + }, + "NOT_WALLET_OWNER": { + "optional": false, + "readonly": true, + "type": "\"NOT_WALLET_OWNER\"" + }, + "READ_ONLY": { + "optional": false, + "readonly": true, + "type": "\"READ_ONLY\"" + }, + "RECEIPT_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_MISMATCH\"" + }, + "RECEIPT_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_UNAVAILABLE\"" + }, + "RULE_NOT_FOUND": { + "optional": false, + "readonly": true, + "type": "\"RULE_NOT_FOUND\"" + }, + "RULE_READ_FAILED": { + "optional": false, + "readonly": true, + "type": "\"RULE_READ_FAILED\"" + }, + "TARGET_NOT_ON_RULE_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"TARGET_NOT_ON_RULE_CHAIN\"" + }, + "WALLET_BALANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"WALLET_BALANCE_INSUFFICIENT\"" + }, + "WALLET_NOT_DEPLOYED": { + "optional": false, + "readonly": true, + "type": "\"WALLET_NOT_DEPLOYED\"" + } + } + }, + "Rule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Rule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleCall[]" + }, + "assets": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset[] | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "maxGasPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "RuleInput": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").DecodedSolanaRule | import(\"sdk/src/lib/agentic/agentic.types\").Rule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "assets": { + "optional": true, + "readonly": false, + "type": "{\n maxPerCall: bigint;\n maxTotal: bigint;\n token: string;\n}[] | import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset[] | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "maxGasPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Pin": { + "type": "{\n account: number;\n arg?: never;\n expected: \"agentic:wallet\" | string;\n max?: never;\n token?: import(\"sdk/src/lib/constants/tokens\").MoveableToken | string;\n} | {\n account?: never;\n arg: import(\"sdk/src/lib/agentic/agentic.types\").ArgumentPath;\n expected: \"agentic:wallet\" | `0x${string}` | `0x${string}` | bigint;\n max?: never;\n} | {\n account?: never;\n arg: import(\"sdk/src/lib/agentic/agentic.types\").ArgumentPath;\n expected?: never;\n max: bigint;\n}", + "members": { + "account": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "arg": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ArgumentPath | undefined" + }, + "expected": { + "optional": true, + "readonly": false, + "type": "bigint | string | undefined" + }, + "max": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "Spent": { + "type": "{\n actions: {\n amountSpent: bigint;\n callsUsed: number;\n selector: \"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector;\n target: `0x${string}`;\n valueSpent: bigint;\n }[];\n kind: \"native\";\n} | {\n amountSpent: bigint;\n callsUsed: number;\n kind: \"native\";\n valueSpent: bigint;\n} | {\n assets: {\n spent: bigint;\n token: string;\n }[];\n kind: \"universal\";\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"native\" | \"universal\"" + } + } + }, + "AssetCap": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset", + "members": { + "maxPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/tokens\").MoveableToken | string" + } + } + }, + "AllowedCall": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleCall", + "members": { + "app": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "label": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "maxValue": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "pins": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Pin[] | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector" + }, + "target": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "RulesRecord": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "enabled": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "rule": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").DecodedSolanaRule | import(\"sdk/src/lib/agentic/agentic.types\").Rule" + }, + "rulesId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "spent": { + "optional": false, + "readonly": false, + "type": "{\n actions: {\n amountSpent: bigint;\n callsUsed: number;\n selector: \"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector;\n target: `0x${string}`;\n valueSpent: bigint;\n }[];\n kind: \"native\";\n} | {\n amountSpent: bigint;\n callsUsed: number;\n kind: \"native\";\n valueSpent: bigint;\n} | {\n assets: {\n spent: bigint;\n token: string;\n }[];\n kind: \"universal\";\n}" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "CreateOptions": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions", + "members": { + "progressHook": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook | undefined" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleInput[]" + } + } + }, + "CreateResult": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateResult", + "members": { + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "rulesIds": { + "optional": false, + "readonly": false, + "type": "`0x${string}`[]" + }, + "tx": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticTxMetadata": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticTxMetadata", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destinationAccount": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "destinationCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "destinationInstruction": { + "optional": true, + "readonly": false, + "type": "{\n accounts: readonly {\n isWritable: boolean;\n pubkey: `0x${string}`;\n }[];\n data: `0x${string}`;\n program: `0x${string}`;\n} | undefined" + }, + "destinationTransfer": { + "optional": true, + "readonly": false, + "type": "{\n amount: bigint;\n recipient: `0x${string}`;\n token: `0x${string}`;\n} | undefined" + }, + "door": { + "optional": false, + "readonly": false, + "type": "\"agent\" | \"owner\"" + }, + "nativeCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "rawData": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rawTo": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesId": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + } + }, + "publicSurface": { + "CHAIN": { + "type": "typeof import(\"sdk/src/lib/constants/enums\").CHAIN", + "members": { + "ARBITRUM_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA" + }, + "BASE_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA" + }, + "BNB_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET" + }, + "ETHEREUM_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET" + }, + "ETHEREUM_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA" + }, + "PUSH_LOCALNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET" + }, + "PUSH_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET" + }, + "PUSH_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET" + }, + "PUSH_TESTNET_DONUT": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET" + }, + "SOLANA_DEVNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET" + }, + "SOLANA_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET" + }, + "SOLANA_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET" + }, + "WEB2": { + "optional": false, + "readonly": false, + "type": "\"web2\"" + } + } + }, + "ConversionQuote": { + "type": "import(\"sdk/src/lib/constants/tokens\").ConversionQuote", + "members": { + "amountIn": { + "optional": false, + "readonly": false, + "type": "string" + }, + "amountOut": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rate": { + "optional": false, + "readonly": false, + "type": "number" + }, + "route": { + "optional": true, + "readonly": false, + "type": "string[] | undefined" + }, + "timestamp": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "UniversalSigner": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalSigner", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "signAndSendTransaction": { + "optional": false, + "readonly": false, + "type": "(unsignedTx: Uint8Array) => Promise" + }, + "signAuthorization": { + "optional": true, + "readonly": false, + "type": "((params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise) | undefined" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": true, + "readonly": false, + "type": "(({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise) | undefined" + } + } + }, + "UniversalAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "UniversalSignerSkeleton": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "signAndSendTransaction": { + "optional": false, + "readonly": false, + "type": "(unsignedTx: Uint8Array) => Promise" + }, + "signAuthorization": { + "optional": true, + "readonly": false, + "type": "((params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise) | undefined" + }, + "signerId": { + "optional": false, + "readonly": false, + "type": "string" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": true, + "readonly": false, + "type": "(({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise) | undefined" + } + } + }, + "SignAuthorizationParams": { + "type": "{\n chainId?: number;\n contractAddress: `0x${string}`;\n executor?: \"self\";\n nonce?: number;\n}", + "members": { + "chainId": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "contractAddress": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "executor": { + "optional": true, + "readonly": false, + "type": "\"self\" | undefined" + }, + "nonce": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "SignedAuthorization": { + "type": "{\n address: `0x${string}`;\n chainId: number;\n nonce: number;\n r: `0x${string}`;\n s: `0x${string}`;\n v?: bigint;\n yParity: number;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainId": { + "optional": false, + "readonly": false, + "type": "number" + }, + "nonce": { + "optional": false, + "readonly": false, + "type": "number" + }, + "r": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "s": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "v": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "yParity": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "DerivedExecutorAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").DerivedExecutorAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean | null" + } + } + }, + "ResolvedAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainName": { + "optional": false, + "readonly": false, + "type": "string" + }, + "exists": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "role": { + "optional": true, + "readonly": false, + "type": "\"controller\" | undefined" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"cea\" | \"uea\" | \"uoa\"" + } + } + }, + "ResolvedControllerAccounts": { + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedControllerAccounts", + "members": { + "accounts": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedAccount[]" + } + } + }, + "AccountType": { + "type": "\"cea\" | \"uea\" | \"uoa\"", + "members": {} + }, + "AccountRole": { + "type": "\"controller\"", + "members": {} + }, + "PC20TokenReference": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "FundsToken": { + "type": "import(\"sdk/src/lib/constants/tokens\").MoveableToken | import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20TokenReference", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "PC20RegistryEntry": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "chainName": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "PC20AddressResult": { + "type": "{\n address: `0x${string}`;\n decimals: number;\n name: string;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n registry: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20RegistryEntry[];\n symbol: string;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "decimals": { + "optional": false, + "readonly": false, + "type": "number" + }, + "name": { + "optional": false, + "readonly": false, + "type": "string" + }, + "network": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "registry": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20RegistryEntry[]" + }, + "symbol": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "isPC20Reference": { + "type": "(token: import(\"sdk/src/lib/orchestrator/orchestrator.types\").FundsToken | undefined) => token is import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20TokenReference", + "members": {} + }, + "PC20Error": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20Error", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidPC20AddressError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InvalidPC20AddressError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20TokenChainMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20TokenChainMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20WrapperNotRegisteredError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20WrapperNotRegisteredError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20RegistryMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20RegistryMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20FactoryMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20FactoryMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidPC20MetadataError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InvalidPC20MetadataError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20ExpectedButPRC20Error": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20ExpectedButPRC20Error", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20AmbiguousAddressError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20AmbiguousAddressError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "candidates": { + "optional": false, + "readonly": true, + "type": "{\n chain: string;\n pushAddress: string;\n}[]" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "UnsupportedPC20DestinationError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").UnsupportedPC20DestinationError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InsufficientPC20BalanceError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InsufficientPC20BalanceError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20UnknownChainNamespaceError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20UnknownChainNamespaceError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20WrapperPredictionUnavailableError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20WrapperPredictionUnavailableError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20ExportRevertedError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20ExportRevertedError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "lockedAmount": { + "optional": true, + "readonly": true, + "type": "bigint | undefined" + }, + "outboundTxId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "revertRecipient": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20UnsafeEmptyPayloadError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20UnsafeEmptyPayloadError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ChainTarget": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "ChainSource": { + "type": "{\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "UniversalTo": { + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget", + "members": {} + }, + "TransactionRouteType": { + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"", + "members": {} + }, + "UniversalExecuteParams": { + "type": "{\n from?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainSource;\n migration?: boolean;\n to: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTo;\n} & Omit", + "members": { + "_minimumDepositUsd": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "_requiredFundsOverride": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "_skipFeeLocking": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "_ueaStatus": { + "optional": true, + "readonly": false, + "type": "{\n balance: bigint;\n isDeployed: boolean;\n nonce: bigint;\n} | undefined" + }, + "data": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiCall[] | undefined" + }, + "deadline": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "feeLockTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "from": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainSource | undefined" + }, + "funds": { + "optional": true, + "readonly": false, + "type": "{\n amount: bigint;\n token?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").FundsToken;\n} | undefined" + }, + "gasLimit": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFeePerGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxPCForGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxPriorityFeePerGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "migration": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "nonce": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "options": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions | undefined" + }, + "payGasWith": { + "optional": true, + "readonly": false, + "type": "{\n minAmountOut?: bigint | string;\n slippageBps?: number;\n token?: import(\"sdk/src/lib/constants/tokens\").PayableToken;\n} | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "to": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget" + }, + "value": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "UniversalOutboundTxRequest": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalOutboundTxRequest", + "members": { + "amount": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gasPrice": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxPCForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "payload": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "recipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "revertRecipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "PreparedUniversalTx": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx", + "members": { + "_hop": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").HopDescriptor" + }, + "deadline": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "estimatedGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gatewayRequest": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalOutboundTxRequest | import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxRequest" + }, + "nonce": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "payload": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + } + } + }, + "CascadedTxResponse": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadedTxResponse", + "members": { + "finalTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hopCount": { + "optional": false, + "readonly": false, + "type": "number" + }, + "hops": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo[]" + }, + "initialTxHash": { + "optional": false, + "readonly": false, + "type": "string" + }, + "initialTxResponse": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions) => Promise" + }, + "waitForAll": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions) => Promise" + } + } + }, + "CascadeHopInfo": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo", + "members": { + "executionChain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "expectedSubTxId": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hopIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "outboundDetails": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").OutboundTxDetails | undefined" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + }, + "status": { + "optional": false, + "readonly": false, + "type": "\"confirmed\" | \"failed\" | \"pending\" | \"submitted\"" + }, + "txHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "CascadeTrackOptions": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions", + "members": { + "eventHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeProgressEvent) => void) | undefined" + }, + "timeout": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "CascadeProgressEvent": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeProgressEvent", + "members": { + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "elapsed": { + "optional": false, + "readonly": false, + "type": "number" + }, + "hopIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + }, + "status": { + "optional": false, + "readonly": false, + "type": "\"confirmed\" | \"failed\" | \"found\" | \"polling\" | \"timeout\" | \"waiting\"" + }, + "txHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "CascadeCompletionResult": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeCompletionResult", + "members": { + "failedAt": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "finalTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "finalTxResponse": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadedTxResponse | undefined" + }, + "hops": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo[]" + }, + "success": { + "optional": false, + "readonly": false, + "type": "boolean" + } + } + }, + "MultiChainTxResponse": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiChainTxResponse", + "members": { + "chains": { + "optional": false, + "readonly": false, + "type": "{\n blockNumber: bigint;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n hash: string;\n status: \"confirmed\" | \"failed\" | \"pending\";\n}[]" + }, + "transactions": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse[]" + } + } + }, + "OutboundTxDetails": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").OutboundTxDetails", + "members": { + "amount": { + "optional": false, + "readonly": false, + "type": "string" + }, + "assetAddr": { + "optional": false, + "readonly": false, + "type": "string" + }, + "destinationChain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "explorerUrl": { + "optional": false, + "readonly": false, + "type": "string" + }, + "externalTxHash": { + "optional": false, + "readonly": false, + "type": "string" + }, + "recipient": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "WaitForOutboundOptions": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").WaitForOutboundOptions", + "members": { + "_expectedDestinationChain": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "_outboundIndex": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "_resolvedSubTxId": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "initialWaitMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: {\n elapsed: number;\n status: \"failed\" | \"found\" | \"polling\" | \"timeout\" | \"waiting\";\n}) => void) | undefined" + }, + "timeout": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "SvmGatewayAccountMeta": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmGatewayAccountMeta", + "members": { + "isWritable": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "pubkey": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "SvmExecutePayloadFields": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmExecutePayloadFields", + "members": { + "accounts": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmGatewayAccountMeta[]" + }, + "instructionId": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "ixData": { + "optional": false, + "readonly": false, + "type": "Uint8Array" + }, + "targetProgram": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AccountStatus": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus", + "members": { + "mode": { + "optional": false, + "readonly": false, + "type": "\"read-only\" | \"signer\"" + }, + "uea": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UEAStatus" + } + } + }, + "UEAStatus": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UEAStatus", + "members": { + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "loaded": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "minRequiredVersion": { + "optional": false, + "readonly": false, + "type": "string" + }, + "requiresUpgrade": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "version": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "RescueFundsParams": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").RescueFundsParams", + "members": { + "prc20": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "universalTxId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "parseUEAVersion": { + "type": "(version: string) => number", + "members": {} + }, + "TransactionRoute": { + "type": "typeof import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute", + "members": { + "CEA_TO_CEA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.CEA_TO_CEA" + }, + "CEA_TO_PUSH": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.CEA_TO_PUSH" + }, + "UOA_TO_CEA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.UOA_TO_CEA" + }, + "UOA_TO_PUSH": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.UOA_TO_PUSH" + } + } + }, + "detectRoute": { + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams) => import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute", + "members": {} + }, + "isChainTarget": { + "type": "(to: unknown) => to is import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget", + "members": {} + }, + "DEFAULT_MAX_PC_FOR_GAS_BUFFER_BPS": { + "type": "1000", + "members": {} + }, + "MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT": { + "type": "10000", + "members": {} + }, + "quoteMaxPCForGasCap": { + "type": "(input: import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapInput) => import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": {} + }, + "quoteMaxPCForGasCapFromNativeValue": { + "type": "(input: import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapFromNativeValueInput) => import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": {} + }, + "MaxPCForGasCapInput": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapInput", + "members": { + "bufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "gasLegNativePc": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "MaxPCForGasCapFromNativeValueInput": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapFromNativeValueInput", + "members": { + "bufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "nativeValueForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "MaxPCForGasCapQuote": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": { + "bufferBps": { + "optional": false, + "readonly": false, + "type": "number" + }, + "gasLegNativePc": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxPCForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "nativeValueForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "getCEAAddress": { + "type": "(ueaAddress: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise", + "members": {} + }, + "getPushAccountForCEA": { + "type": "(ceaAddress: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise<`0x${string}`>", + "members": {} + }, + "isCEA": { + "type": "(address: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise", + "members": {} + }, + "chainSupportsCEA": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "chainSupportsOutbound": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "getCEAFactoryAddress": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => `0x${string}` | undefined", + "members": {} + }, + "getAllCEAAddresses": { + "type": "(ueaAddress: `0x${string}`, rpcUrls?: Partial>) => Promise", + "members": {} + }, + "encodeSvmExecutePayload": { + "type": "(fields: import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmExecutePayloadFields) => `0x${string}`", + "members": {} + }, + "isSvmChain": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "isValidSolanaHexAddress": { + "type": "(address: string) => boolean", + "members": {} + }, + "buildMigrationPayload": { + "type": "() => `0x${string}`", + "members": {} + }, + "buildErc20WithdrawalMulticall": { + "type": "(tokenAddress: `0x${string}`, recipientAddress: `0x${string}`, amount: bigint) => import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiCall[]", + "members": {} + }, + "ReadChain": { + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain", + "members": {} + }, + "ReadDestination": { + "type": "{\n chain: import(\"sdk/src/lib/read-state/read-state.types\").ReadChain;\n} | {\n chainId: string;\n chainNamespace: string;\n}", + "members": {} + }, + "ResolvedDestination": { + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}", + "members": { + "caip2": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainId": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "namespace": { + "optional": false, + "readonly": false, + "type": "\"eip155\" | \"solana\" | \"web2\"" + } + } + }, + "ReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").SvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery", + "members": { + "type": { + "optional": false, + "readonly": false, + "type": "\"accountBalance\" | \"contractCall\" | \"http\" | \"lamportBalance\" | \"rawAccountData\" | \"splTokenAccount\" | \"storageSlot\"" + } + } + }, + "EvmReadQuery": { + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n target: `0x${string}`;\n type: \"contractCall\";\n} | {\n callData: `0x${string}`;\n target: `0x${string}`;\n type: \"contractCall\";\n} | {\n slot: `0x${string}` | bigint;\n target: `0x${string}`;\n type: \"storageSlot\";\n} | {\n target: `0x${string}`;\n type: \"accountBalance\";\n}", + "members": { + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"accountBalance\" | \"contractCall\" | \"storageSlot\"" + } + } + }, + "SvmReadQuery": { + "type": "{\n account: string | Uint8Array;\n accountName?: string;\n idl?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n type: \"rawAccountData\";\n} | {\n account: string | Uint8Array;\n type: \"lamportBalance\";\n} | {\n account: string | Uint8Array;\n type: \"splTokenAccount\";\n}", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "string | Uint8Array" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"lamportBalance\" | \"rawAccountData\" | \"splTokenAccount\"" + } + } + }, + "Web2ReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery", + "members": { + "body": { + "optional": true, + "readonly": false, + "type": "string | Uint8Array | undefined" + }, + "extract": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[]" + }, + "headers": { + "optional": true, + "readonly": false, + "type": "Record | undefined" + }, + "method": { + "optional": true, + "readonly": false, + "type": "\"GET\" | \"POST\" | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"http\"" + }, + "url": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "Web2Extract": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract", + "members": { + "decimals": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "path": { + "optional": false, + "readonly": false, + "type": "string" + }, + "valueType": { + "optional": false, + "readonly": false, + "type": "\"bool\" | \"bytes\" | \"int256\" | \"string\" | \"uint256\"" + } + } + }, + "Web2ValueType": { + "type": "\"bool\" | \"bytes\" | \"int256\" | \"string\" | \"uint256\"", + "members": {} + }, + "EncodedReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery", + "members": { + "blockRef": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "encoded": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "namespace": { + "optional": false, + "readonly": false, + "type": "\"eip155\" | \"solana\" | \"web2\"" + }, + "ownerBytes": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "queryType": { + "optional": false, + "readonly": false, + "type": "number" + }, + "resultShape": { + "optional": false, + "readonly": false, + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}" + }, + "warnings": { + "optional": false, + "readonly": false, + "type": "string[]" + } + } + }, + "ReadResultShape": { + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"bytes32\" | \"evmCall\" | \"raw\" | \"svmAccount\" | \"uint256\" | \"web2\"" + } + } + }, + "DecodedReadResult": { + "type": "{\n accountName: string;\n kind: \"svmAccount\";\n value: unknown;\n} | {\n kind: \"bytes32\";\n value: `0x${string}`;\n} | {\n kind: \"evmCall\";\n value: unknown;\n} | {\n kind: \"raw\";\n value: `0x${string}`;\n} | {\n kind: \"uint256\";\n value: bigint;\n} | {\n kind: \"web2\";\n values: readonly unknown[];\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"bytes32\" | \"evmCall\" | \"raw\" | \"svmAccount\" | \"uint256\" | \"web2\"" + } + } + }, + "ReadPreflight": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight", + "members": { + "destination": { + "optional": false, + "readonly": false, + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}" + }, + "fetchedAt": { + "optional": false, + "readonly": false, + "type": "number" + }, + "observedChainHeight": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pushBlockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pushGasPrice": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "universalCallback": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "universalCore": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ReadSpec": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "{\n chainId: string;\n chainNamespace: string;\n owner: `0x${string}`;\n}" + }, + "blockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "expiryPushChainHeight": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "minConfirmations": { + "optional": false, + "readonly": false, + "type": "number" + }, + "query": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "revertRecipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ReadSpecTuple": { + "type": "readonly [\n readonly [\n string,\n string,\n `0x${string}`\n ],\n `0x${string}`,\n number,\n bigint,\n bigint,\n bigint,\n `0x${string}`\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "readonly [\n string,\n string,\n `0x${string}`\n]" + }, + "1": { + "optional": false, + "readonly": true, + "type": "`0x${string}`" + }, + "2": { + "optional": false, + "readonly": true, + "type": "number" + }, + "3": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "4": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "5": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "6": { + "optional": false, + "readonly": true, + "type": "`0x${string}`" + }, + "length": { + "optional": false, + "readonly": true, + "type": "7" + } + } + }, + "BuildReadSpecParams": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").BuildReadSpecParams", + "members": { + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "budgetBuffer": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback | undefined" + }, + "callbackBudget": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "destination": { + "optional": false, + "readonly": false, + "type": "{\n chain: import(\"sdk/src/lib/read-state/read-state.types\").ReadChain;\n} | {\n chainId: string;\n chainNamespace: string;\n}" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "expiryPushChainHeight": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFeeBufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "owner": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "query": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").SvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "PreparedRead": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead", + "members": { + "__@preparedReadValue": { + "optional": true, + "readonly": true, + "type": "T | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback | undefined" + }, + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "encodedQuery": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery" + }, + "encodedSpec": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "fees": { + "optional": false, + "readonly": false, + "type": "{\n callbackBudget: bigint;\n protocolFee: bigint;\n total: bigint;\n}" + }, + "preflight": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "queryKey": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "resultShape": { + "optional": false, + "readonly": false, + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}" + }, + "spec": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec" + }, + "specTuple": { + "optional": false, + "readonly": false, + "type": "readonly [\n readonly [\n string,\n string,\n `0x${string}`\n ],\n `0x${string}`,\n number,\n bigint,\n bigint,\n bigint,\n `0x${string}`\n]" + }, + "value": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "warnings": { + "optional": false, + "readonly": false, + "type": "string[]" + } + } + }, + "ReadCallback": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "((spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpecTuple, callbackGasLimit: bigint) => readonly unknown[]) | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "gasLimit": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "target": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "SimulateReadResult": { + "type": "{\n args?: readonly unknown[];\n error: string;\n errorName?: string;\n ok: false;\n} | {\n ok: true;\n}", + "members": { + "ok": { + "optional": false, + "readonly": false, + "type": "boolean" + } + } + }, + "ParsedReadRequest": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ParsedReadRequest", + "members": { + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackTarget": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "logIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "originalFunder": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "requestId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "requestIdUint": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "spec": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec" + }, + "totalPaid": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "FulfilOutcome": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").FulfilOutcome", + "members": { + "burned": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "delivered": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "expired": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "failReason": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "gasReported": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refunded": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refundFailed": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "ReceiptLike": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike", + "members": { + "logs": { + "optional": false, + "readonly": false, + "type": "readonly {\n address: string;\n data: string;\n logIndex?: number | string;\n topics: readonly string[];\n}[]" + } + } + }, + "ReadRef": { + "type": "{\n requestId: `0x${string}` | bigint;\n} | {\n txHash: `0x${string}`;\n}", + "members": {} + }, + "ReadLifecycleOptions": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadLifecycleOptions", + "members": { + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "resultShape": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadFees": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadFees", + "members": { + "burned": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "paid": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "refunded": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refundFailed": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + } + } + }, + "UniversalReadResponse": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse", + "members": { + "callbackDelivered": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "callbackFailReason": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "decoded": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").DecodedReadResult | undefined" + }, + "decodeError": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destination": { + "optional": false, + "readonly": false, + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}" + }, + "errorMsg": { + "optional": false, + "readonly": false, + "type": "string" + }, + "explorerUrl": { + "optional": false, + "readonly": false, + "type": "string" + }, + "fees": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadFees" + }, + "isTerminal": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "outcome": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME" + }, + "pcTx": { + "optional": false, + "readonly": false, + "type": "readonly {\n blockHeight: number;\n errorMsg: string;\n status: string;\n txHash: `0x${string}`;\n}[]" + }, + "raw": { + "optional": false, + "readonly": false, + "type": "{\n errorCode: import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n resultData: `0x${string}`;\n status: import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n} | null" + }, + "refresh": { + "optional": false, + "readonly": false, + "type": "() => Promise>" + }, + "request": { + "optional": false, + "readonly": false, + "type": "{\n callbackGasLimit: bigint;\n callbackTarget: `0x${string}`;\n createdAtHeight: bigint;\n logIndex: number;\n originalFunder: `0x${string}`;\n refundTo: `0x${string}`;\n spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec;\n}" + }, + "requestId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "requestIdUint": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "status": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "value": { + "optional": true, + "readonly": false, + "type": "T | undefined" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/read-state/read-state.types\").ReadLifecycleOptions) => Promise>" + } + } + }, + "ReadResponseTuple": { + "type": "{\n -readonly [K in keyof R]: import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse ? T : unknown>;\n}", + "members": {} + }, + "BatchReadResponse": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").BatchReadResponse", + "members": { + "atomic": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "count": { + "optional": false, + "readonly": false, + "type": "number" + }, + "reads": { + "optional": false, + "readonly": false, + "type": "{\n -readonly [K in keyof R]: import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse ? T : unknown>;\n}" + }, + "transactionHashes": { + "optional": true, + "readonly": false, + "type": "readonly `0x${string}`[] | undefined" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: Omit) => Promise>" + } + } + }, + "ReadOptions": { + "type": "((import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">)) & {\n callback?: (Pick & Required>) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n };\n}", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "advanced": { + "optional": true, + "readonly": false, + "type": "{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n} | undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "({\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} & {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n}) | ({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick & Pick & Required>) | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadPrepareOptions": { + "type": "((((({\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\">) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n}) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">)) & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n}) | ((({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n}) | ({\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\">)) & {\n blockNumber?: never;\n minConfirmations?: never;\n})) & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n}) & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "advanced": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadQueryOptions": { + "type": "({\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\">) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n}) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n}) | ({\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\">)", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadCallbackOptions": { + "type": "{\n callback?: ({\n gasLimit?: bigint;\n target: `0x${string}`;\n } & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n };\n}", + "members": { + "callback": { + "optional": true, + "readonly": false, + "type": "({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} | undefined" + } + } + }, + "ReadValue": { + "type": "O extends {\n abi: infer A extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: infer F extends string;\n} ? number extends A[\"length\"] ? unknown : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, O extends {\n args: infer Args extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n} ? Args : readonly [\n] extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> ? import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> & readonly [\n] : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>> extends infer Selected ? Selected extends {\n outputs: readonly unknown[];\n type: \"function\";\n} & import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiFunction ? {\n [key in keyof {\n [key in keyof import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"]]: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterToPrimitiveType, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"][key], import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterKind>;\n }]: {\n [key in keyof import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"]]: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterToPrimitiveType, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"][key], import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterKind>;\n }[key];\n} extends infer types ? types extends readonly [\n] ? void : types extends readonly [\n infer type\n] ? type : types : never : never : never : O extends {\n web2: {\n extract: infer E extends readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n };\n} ? {\n readonly [K in keyof E]: {\n bool: boolean;\n bytes: `0x${string}`;\n int256: bigint;\n string: string;\n uint256: bigint;\n }[E[K][\"valueType\"]];\n} : O extends {\n storageSlot: unknown;\n} ? `0x${string}` : O extends {\n idl: infer I extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} ? string extends Extract, string> ? unknown : (O extends {\n functionName: infer N extends string;\n} ? N : undefined) extends string ? import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/index\").IdlAccounts[{\n [K in Extract, string>]: Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : K> extends Lowercase<(O extends {\n functionName: infer N extends string;\n } ? N : undefined) & string extends `${infer H}_${infer T}` ? `${H}${Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : (O extends {\n functionName: infer N extends string;\n } ? N : undefined) & string> ? K : never;\n}[Extract, string>]] : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/index\").IdlAccounts[Extract, string>] : bigint", + "members": {} + }, + "ValidateReadCall": { + "type": "O extends {\n abi: infer A extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: infer F extends string;\n} ? (readonly [\n] extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> ? {\n args?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n} : {\n args: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n}) & {\n functionName: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionName;\n} : O extends {\n functionName: infer N extends string;\n idl: infer I extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} ? string extends Extract, string> ? unknown : [\n {\n [K in Extract, string>]: Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : K> extends Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : N> ? K : never;\n }[Extract, string>]\n] extends [\n never\n] ? {\n functionName: Extract, string>;\n} : unknown : unknown", + "members": {} + }, + "ReadWeb2Options": { + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options", + "members": { + "body": { + "optional": true, + "readonly": false, + "type": "string | Uint8Array | undefined" + }, + "extract": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[]" + }, + "headers": { + "optional": true, + "readonly": false, + "type": "Record | undefined" + }, + "method": { + "optional": true, + "readonly": false, + "type": "\"GET\" | \"POST\" | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadTrackOptions": { + "type": "{\n advanced?: Omit, \"enforceGasCheck\">;\n resultShape?: import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape;\n}", + "members": { + "advanced": { + "optional": true, + "readonly": false, + "type": "Omit<{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n}, \"enforceGasCheck\"> | undefined" + }, + "resultShape": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape | undefined" + } + } + }, + "ReadExecuteOptions": { + "type": "{\n advanced?: {\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n } | undefined;\n progressHook?: ((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined;\n waitForCompletion?: boolean | undefined;\n}", + "members": { + "advanced": { + "optional": true, + "readonly": false, + "type": "{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n} | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + } + } + }, + "UNIVERSAL_READ_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS", + "members": { + "ABORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.ABORTED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.EXPIRED" + }, + "FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.FAILED" + }, + "FULFILLED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.FULFILLED" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.PENDING" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.UNSPECIFIED" + }, + "VOTING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.VOTING" + } + } + }, + "READ_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS", + "members": { + "ERROR": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.ERROR" + }, + "SUCCESS": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.SUCCESS" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.UNSPECIFIED" + } + } + }, + "READ_ERROR_CODE": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE", + "members": { + "INVALID_QUERY": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.INVALID_QUERY" + }, + "INVALID_RESULT": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.INVALID_RESULT" + }, + "NOT_FOUND": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.NOT_FOUND" + }, + "REJECTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.REJECTED" + }, + "REVERTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.REVERTED" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.UNSPECIFIED" + }, + "UNSUPPORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.UNSUPPORTED" + } + } + }, + "READ_OUTCOME": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME", + "members": { + "ABORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.ABORTED" + }, + "CALLBACK_FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.CALLBACK_FAILED" + }, + "DECODE_FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.DECODE_FAILED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.EXPIRED" + }, + "FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.FAILED" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.PENDING" + }, + "SOURCE_ERROR": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.SOURCE_ERROR" + }, + "SUCCESS": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.SUCCESS" + }, + "UNKNOWN": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.UNKNOWN" + } + } + }, + "CONTRACT_REQUEST_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS", + "members": { + "EXECUTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.EXECUTED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.EXPIRED" + }, + "NONE": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.NONE" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.PENDING" + }, + "SETTLED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.SETTLED" + } + } + }, + "TERMINAL_READ_STATUSES": { + "type": "ReadonlySet", + "members": {} + }, + "ReadStateError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadStateError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidReadQueryError": { + "type": "import(\"sdk/src/lib/read-state/errors\").InvalidReadQueryError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidReadSpecError": { + "type": "import(\"sdk/src/lib/read-state/errors\").InvalidReadSpecError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "violations": { + "optional": false, + "readonly": true, + "type": "readonly import(\"sdk/src/lib/read-state/errors\").ReadSpecViolation[]" + } + } + }, + "ReadHeightUnavailableError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadHeightUnavailableError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "UnsupportedReadDestinationError": { + "type": "import(\"sdk/src/lib/read-state/errors\").UnsupportedReadDestinationError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadDecodeError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadDecodeError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadTimeoutError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadTimeoutError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "lastStatus": { + "optional": false, + "readonly": true, + "type": "number" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadNotFoundError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadNotFoundError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadRegistryUnavailableError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadRegistryUnavailableError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadSpecViolation": { + "type": "\"CALLBACK_GAS_LIMIT_EXCEEDED\" | \"DOMAIN_BLOCKED\" | \"EMPTY_QUERY\" | \"EXCESSIVE_FEE\" | \"INSUFFICIENT_CALLBACK_BUDGET\" | \"INSUFFICIENT_FEE\" | \"INVALID_ACCOUNT_ID\" | \"INVALID_BLOCK_NUMBER\" | \"INVALID_EXPIRY_HEIGHT\" | \"INVALID_MIN_CONFIRMATIONS\" | \"SVM_OWNER_NOT_32_BYTES\" | \"ZERO_CALLBACK_BUDGET\" | \"ZERO_CALLBACK_GAS_LIMIT\" | \"ZERO_REVERT_RECIPIENT\"", + "members": {} + }, + "resolveDestination": { + "type": "(dest: import(\"sdk/src/lib/read-state/read-state.types\").ReadDestination) => import(\"sdk/src/lib/read-state/read-state.types\").ResolvedDestination", + "members": {} + }, + "encodeReadQuery": { + "type": "(destination: import(\"sdk/src/lib/read-state/read-state.types\").ReadDestination, query: import(\"sdk/src/lib/read-state/read-state.types\").ReadQuery, options?: {\n blockNumber?: bigint;\n minSlot?: bigint;\n}) => import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery", + "members": {} + }, + "decodeReadResult": { + "type": "(resultData: `0x${string}`, shape: import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape) => import(\"sdk/src/lib/read-state/read-state.types\").DecodedReadResult", + "members": {} + }, + "parseReadRequestsFromReceipt": { + "type": "(receipt: import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike, universalCallback: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").ParsedReadRequest[]", + "members": {} + }, + "parseFulfilOutcome": { + "type": "(receipt: import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike, universalCallback: `0x${string}`, requestId: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").FulfilOutcome", + "members": {} + }, + "buildReadSpecFromPreflight": { + "type": "(preflight: import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight, params: import(\"sdk/src/lib/read-state/read-state.types\").BuildReadSpecParams, defaults?: {\n refundTo?: `0x${string}`;\n}) => import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead", + "members": {} + }, + "validateReadSpec": { + "type": "(input: import(\"sdk/src/lib/read-state/validate\").ValidateReadSpecInput) => {\n ok: false;\n violations: import(\"sdk/src/lib/read-state/errors\").ReadSpecViolation[];\n} | {\n ok: true;\n}", + "members": {} + }, + "toCallData": { + "type": "(prepared: import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead, target: {\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: (spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpecTuple, callbackGasLimit: bigint) => readonly unknown[];\n functionName: string;\n}) => {\n data: `0x${string}`;\n value: bigint;\n}", + "members": {} + }, + "sizeCallbackBudget": { + "type": "(callbackGasLimit: bigint, pushGasPrice: bigint, buffer?: number) => bigint", + "members": {} + }, + "inferResultShape": { + "type": "(namespace: string, query: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape", + "members": {} + }, + "toRequestIdHex": { + "type": "(id: `0x${string}` | bigint) => `0x${string}`", + "members": {} + }, + "toReadQuery": { + "type": "(subject: string, o: ReadOptionsInput, resolvedTokenProgram?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@solana/web3.js/lib/index\").PublicKey) => import(\"sdk/src/lib/read-state/read-state.types\").ReadQuery", + "members": {} + }, + "UNIVERSAL_CALLBACK_EVM": { + "type": "readonly [\n {\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"requestExternalReadSelf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"estimateFee\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"statusOf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"enum RequestStatus\";\n readonly name: \"\";\n readonly type: \"uint8\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"isFulfilled\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getPendingRead\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly internalType: \"struct PendingRead\";\n readonly name: \"\";\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"totalEscrowed\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"blockedDomains\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly indexed: false;\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"readSpec\";\n readonly type: \"tuple\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"totalPaid\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"protocolFee\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ReadRequested\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"ReadFulfilled\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"reason\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"CallbackFailed\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"gasReported\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"burned\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"CallbackGasReported\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundSent\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundFailed\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RequestExpired\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"vaultPC\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ProtocolFeeDistributed\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidAccountId\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"EmptyQuery\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidMinConfirmations\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"DomainBlocked\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidBlockNumber\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidExpiryHeight\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroRevertRecipient\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroCallbackGasLimit\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint64\";\n readonly name: \"provided\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"max\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"CallbackGasLimitExceeded\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"required\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"InsufficientFee\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ExcessiveFee\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"actual\";\n readonly type: \"uint8\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"expected\";\n readonly type: \"uint8\";\n }\n ];\n readonly name: \"InvalidRequestStatus\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ContractIsPaused\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"CallerIsNotUCallbackModule\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n }\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"requestExternalReadSelf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n}" + }, + "1": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"estimateFee\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "2": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"statusOf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"enum RequestStatus\";\n readonly name: \"\";\n readonly type: \"uint8\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "3": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"isFulfilled\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "4": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getPendingRead\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly internalType: \"struct PendingRead\";\n readonly name: \"\";\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "5": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"totalEscrowed\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "6": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"blockedDomains\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "7": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly indexed: false;\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"readSpec\";\n readonly type: \"tuple\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"totalPaid\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"protocolFee\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ReadRequested\";\n readonly type: \"event\";\n}" + }, + "8": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"ReadFulfilled\";\n readonly type: \"event\";\n}" + }, + "9": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"reason\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"CallbackFailed\";\n readonly type: \"event\";\n}" + }, + "10": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"gasReported\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"burned\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"CallbackGasReported\";\n readonly type: \"event\";\n}" + }, + "11": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundSent\";\n readonly type: \"event\";\n}" + }, + "12": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundFailed\";\n readonly type: \"event\";\n}" + }, + "13": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RequestExpired\";\n readonly type: \"event\";\n}" + }, + "14": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"vaultPC\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ProtocolFeeDistributed\";\n readonly type: \"event\";\n}" + }, + "15": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidAccountId\";\n readonly type: \"error\";\n}" + }, + "16": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"EmptyQuery\";\n readonly type: \"error\";\n}" + }, + "17": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidMinConfirmations\";\n readonly type: \"error\";\n}" + }, + "18": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"DomainBlocked\";\n readonly type: \"error\";\n}" + }, + "19": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidBlockNumber\";\n readonly type: \"error\";\n}" + }, + "20": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidExpiryHeight\";\n readonly type: \"error\";\n}" + }, + "21": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroRevertRecipient\";\n readonly type: \"error\";\n}" + }, + "22": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroCallbackGasLimit\";\n readonly type: \"error\";\n}" + }, + "23": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint64\";\n readonly name: \"provided\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"max\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"CallbackGasLimitExceeded\";\n readonly type: \"error\";\n}" + }, + "24": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"required\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"InsufficientFee\";\n readonly type: \"error\";\n}" + }, + "25": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ExcessiveFee\";\n readonly type: \"error\";\n}" + }, + "26": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"actual\";\n readonly type: \"uint8\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"expected\";\n readonly type: \"uint8\";\n }\n ];\n readonly name: \"InvalidRequestStatus\";\n readonly type: \"error\";\n}" + }, + "27": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ContractIsPaused\";\n readonly type: \"error\";\n}" + }, + "28": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"CallerIsNotUCallbackModule\";\n readonly type: \"error\";\n}" + }, + "29": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n}" + }, + "length": { + "optional": false, + "readonly": true, + "type": "30" + } + } + }, + "UNIVERSAL_READ_REGISTRY_EVM": { + "type": "readonly [\n {\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n },\n {\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"read\";\n readonly outputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"universalCallback_\";\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"constructor\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"initialize\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getLocalContext\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"hasResult\";\n readonly outputs: readonly [\n {\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"onUniversalData\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"queryKeyOf\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes32\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"readerOf\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"requestOrderOf\";\n readonly outputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"universalCallback\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"resultByRequestId\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"latestResult\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"version\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"Initialized\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadRequested\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadStored\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidInitialization\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"NotInitializing\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroAddressInit\";\n readonly type: \"error\";\n }\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n },\n {\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"read\";\n readonly outputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n}" + }, + "1": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"universalCallback_\";\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"constructor\";\n}" + }, + "2": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"initialize\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n}" + }, + "3": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getLocalContext\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "4": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"hasResult\";\n readonly outputs: readonly [\n {\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "5": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"onUniversalData\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n}" + }, + "6": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"queryKeyOf\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes32\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "7": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"readerOf\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "8": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"requestOrderOf\";\n readonly outputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "9": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"universalCallback\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "10": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"resultByRequestId\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "11": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"latestResult\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "12": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"version\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"Initialized\";\n readonly type: \"event\";\n}" + }, + "13": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadRequested\";\n readonly type: \"event\";\n}" + }, + "14": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadStored\";\n readonly type: \"event\";\n}" + }, + "15": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidInitialization\";\n readonly type: \"error\";\n}" + }, + "16": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"NotInitializing\";\n readonly type: \"error\";\n}" + }, + "17": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n}" + }, + "18": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroAddressInit\";\n readonly type: \"error\";\n}" + }, + "length": { + "optional": false, + "readonly": true, + "type": "19" + } + } + }, + "PushChainExecutionError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").PushChainExecutionError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PushChainBatchExecutionError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").PushChainBatchExecutionError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": false, + "readonly": true, + "type": "`0x${string}`[]" + } + } + }, + "DecodedErrorPayload": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload", + "members": { + "decoded": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "name": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "selector": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "PushChainInitializeOptions": { + "type": "import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions", + "members": { + "agenticWallet": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "blockExplorers": { + "optional": true, + "readonly": false, + "type": "Partial> | undefined" + }, + "network": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "printTraces": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "rpcUrls": { + "optional": true, + "readonly": false, + "type": "Partial> | undefined" + } + } + }, + "AGENTIC_ERROR_CODE": { + "type": "{\n readonly AGENT_GAS_INSUFFICIENT: \"AGENT_GAS_INSUFFICIENT\";\n readonly AGENT_IS_OWNER: \"AGENT_IS_OWNER\";\n readonly AMBIGUOUS_RULE: \"AMBIGUOUS_RULE\";\n readonly ASSET_CHAIN_MISMATCH: \"ASSET_CHAIN_MISMATCH\";\n readonly CAPABILITY_UNAVAILABLE: \"CAPABILITY_UNAVAILABLE\";\n readonly DELETE_NEEDS_TARGET: \"DELETE_NEEDS_TARGET\";\n readonly DUPLICATE_RULE: \"DUPLICATE_RULE\";\n readonly FROM_NOT_ALLOWED: \"FROM_NOT_ALLOWED\";\n readonly INCONSISTENT_READ: \"INCONSISTENT_READ\";\n readonly INDEX_RACE: \"INDEX_RACE\";\n readonly INVALID_RULE: \"INVALID_RULE\";\n readonly NO_RULES_FOR_CHAIN: \"NO_RULES_FOR_CHAIN\";\n readonly NOT_AGENTIC_WALLET: \"NOT_AGENTIC_WALLET\";\n readonly NOT_ALLOWED_IN_AGENTIC_MODE: \"NOT_ALLOWED_IN_AGENTIC_MODE\";\n readonly NOT_OWNER_OR_AGENT: \"NOT_OWNER_OR_AGENT\";\n readonly NOT_WALLET_OWNER: \"NOT_WALLET_OWNER\";\n readonly READ_ONLY: \"READ_ONLY\";\n readonly RECEIPT_MISMATCH: \"RECEIPT_MISMATCH\";\n readonly RECEIPT_UNAVAILABLE: \"RECEIPT_UNAVAILABLE\";\n readonly RULE_NOT_FOUND: \"RULE_NOT_FOUND\";\n readonly RULE_READ_FAILED: \"RULE_READ_FAILED\";\n readonly TARGET_NOT_ON_RULE_CHAIN: \"TARGET_NOT_ON_RULE_CHAIN\";\n readonly WALLET_BALANCE_INSUFFICIENT: \"WALLET_BALANCE_INSUFFICIENT\";\n readonly WALLET_NOT_DEPLOYED: \"WALLET_NOT_DEPLOYED\";\n}", + "members": { + "AGENT_GAS_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\"" + }, + "AGENT_IS_OWNER": { + "optional": false, + "readonly": true, + "type": "\"AGENT_IS_OWNER\"" + }, + "AMBIGUOUS_RULE": { + "optional": false, + "readonly": true, + "type": "\"AMBIGUOUS_RULE\"" + }, + "ASSET_CHAIN_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"ASSET_CHAIN_MISMATCH\"" + }, + "CAPABILITY_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"CAPABILITY_UNAVAILABLE\"" + }, + "DELETE_NEEDS_TARGET": { + "optional": false, + "readonly": true, + "type": "\"DELETE_NEEDS_TARGET\"" + }, + "DUPLICATE_RULE": { + "optional": false, + "readonly": true, + "type": "\"DUPLICATE_RULE\"" + }, + "FROM_NOT_ALLOWED": { + "optional": false, + "readonly": true, + "type": "\"FROM_NOT_ALLOWED\"" + }, + "INCONSISTENT_READ": { + "optional": false, + "readonly": true, + "type": "\"INCONSISTENT_READ\"" + }, + "INDEX_RACE": { + "optional": false, + "readonly": true, + "type": "\"INDEX_RACE\"" + }, + "INVALID_RULE": { + "optional": false, + "readonly": true, + "type": "\"INVALID_RULE\"" + }, + "NO_RULES_FOR_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"NO_RULES_FOR_CHAIN\"" + }, + "NOT_AGENTIC_WALLET": { + "optional": false, + "readonly": true, + "type": "\"NOT_AGENTIC_WALLET\"" + }, + "NOT_ALLOWED_IN_AGENTIC_MODE": { + "optional": false, + "readonly": true, + "type": "\"NOT_ALLOWED_IN_AGENTIC_MODE\"" + }, + "NOT_OWNER_OR_AGENT": { + "optional": false, + "readonly": true, + "type": "\"NOT_OWNER_OR_AGENT\"" + }, + "NOT_WALLET_OWNER": { + "optional": false, + "readonly": true, + "type": "\"NOT_WALLET_OWNER\"" + }, + "READ_ONLY": { + "optional": false, + "readonly": true, + "type": "\"READ_ONLY\"" + }, + "RECEIPT_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_MISMATCH\"" + }, + "RECEIPT_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_UNAVAILABLE\"" + }, + "RULE_NOT_FOUND": { + "optional": false, + "readonly": true, + "type": "\"RULE_NOT_FOUND\"" + }, + "RULE_READ_FAILED": { + "optional": false, + "readonly": true, + "type": "\"RULE_READ_FAILED\"" + }, + "TARGET_NOT_ON_RULE_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"TARGET_NOT_ON_RULE_CHAIN\"" + }, + "WALLET_BALANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"WALLET_BALANCE_INSUFFICIENT\"" + }, + "WALLET_NOT_DEPLOYED": { + "optional": false, + "readonly": true, + "type": "\"WALLET_NOT_DEPLOYED\"" + } + } + }, + "AgenticError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"AMBIGUOUS_RULE\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"DELETE_NEEDS_TARGET\" | \"DUPLICATE_RULE\" | \"FROM_NOT_ALLOWED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"" + }, + "details": { + "optional": true, + "readonly": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "AgenticRevertError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticRevertError", + "members": { + "agenticCode": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "AgenticAddress": { + "type": "`0x${string}`", + "members": {} + }, + "AgenticDoor": { + "type": "\"agent\" | \"owner\"", + "members": {} + }, + "AgenticErrorCode": { + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"AMBIGUOUS_RULE\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"DELETE_NEEDS_TARGET\" | \"DUPLICATE_RULE\" | \"FROM_NOT_ALLOWED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"", + "members": {} + }, + "AgenticHex": { + "type": "`0x${string}`", + "members": {} + }, + "AgenticNamespace": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace", + "members": { + "create": { + "optional": false, + "readonly": false, + "type": "(label: string, options: import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions) => Promise" + }, + "derive": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n index?: number;\n}) => Promise<{\n address: `0x${string}`;\n deployed: boolean;\n index: number;\n}>" + }, + "list": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n wallets: import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary[];\n}>" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "(address: `0x${string}`) => import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet" + } + } + }, + "AgenticProgressHook": { + "type": "(event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void", + "members": {} + }, + "AgenticTxMetadata": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticTxMetadata", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destinationAccount": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "destinationCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "destinationInstruction": { + "optional": true, + "readonly": false, + "type": "{\n accounts: readonly {\n isWritable: boolean;\n pubkey: `0x${string}`;\n }[];\n data: `0x${string}`;\n program: `0x${string}`;\n} | undefined" + }, + "destinationTransfer": { + "optional": true, + "readonly": false, + "type": "{\n amount: bigint;\n recipient: `0x${string}`;\n token: `0x${string}`;\n} | undefined" + }, + "door": { + "optional": false, + "readonly": false, + "type": "\"agent\" | \"owner\"" + }, + "nativeCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "rawData": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rawTo": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesId": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticWallet": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "checkpoints": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n sinceBlock?: bigint;\n}) => Promise<{\n checkpoints: import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint[];\n}>" + }, + "info": { + "optional": false, + "readonly": false, + "type": "() => Promise" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n owner: `0x${string}`;\n}>" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "{\n add(rules: import(\"sdk/src/lib/agentic/agentic.types\").RuleInput[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise<{\n rulesIds: `0x${string}`[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n delete(rulesIds: `0x${string}`[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n delete(params: {\n all: true;\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n get(rulesId: `0x${string}`): Promise;\n list(): Promise<{\n rules: import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord[];\n }>;\n update(params: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n rules: {\n rule: import(\"sdk/src/lib/agentic/agentic.types\").RuleInput;\n rulesId: `0x${string}`;\n }[];\n }): Promise<{\n rules: {\n replaced: `0x${string}`;\n rulesId: `0x${string}`;\n }[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n}" + }, + "setLabel": { + "optional": false, + "readonly": false, + "type": "(label: string, opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n}) => Promise" + } + } + }, + "AllowedCall": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleCall", + "members": { + "app": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "label": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "maxValue": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "pins": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Pin[] | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector" + }, + "target": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "AssetCap": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset", + "members": { + "maxPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/tokens\").MoveableToken | string" + } + } + }, + "Checkpoint": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint", + "members": { + "blockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "kind": { + "optional": false, + "readonly": false, + "type": "\"OWNER_ACTION\" | \"RULES_GRANTED\" | \"RULES_REVOKED\"" + }, + "ref": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "seq": { + "optional": false, + "readonly": false, + "type": "number" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "CheckpointKind": { + "type": "\"OWNER_ACTION\" | \"RULES_GRANTED\" | \"RULES_REVOKED\"", + "members": {} + }, + "CreateOptions": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions", + "members": { + "progressHook": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook | undefined" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleInput[]" + } + } + }, + "CreateResult": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateResult", + "members": { + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "rulesIds": { + "optional": false, + "readonly": false, + "type": "`0x${string}`[]" + }, + "tx": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ForeignChainNamespace": { + "type": "`eip155:${string}` | `solana:${string}`", + "members": {} + }, + "DecodedSolanaRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").DecodedSolanaRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "assets": { + "optional": false, + "readonly": false, + "type": "{\n maxPerCall: bigint;\n maxTotal: bigint;\n token: string;\n}[]" + }, + "ceaAccounts": { + "optional": false, + "readonly": false, + "type": "readonly `0x${string}`[]" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "`solana:${string}`" + }, + "dataPins": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/agentic/codec/svm-terms\").SvmDataPinWire[]" + }, + "expectedCEA": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "format": { + "optional": false, + "readonly": false, + "type": "\"decoded\"" + }, + "gatewayProgram": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "maxGasPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pins": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/agentic/codec/svm-terms\").SvmAccountPinWire[]" + }, + "programs": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/agentic/codec/svm-terms\").AllowedProgramWire[]" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Rule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Rule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleCall[]" + }, + "assets": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset[] | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "maxGasPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "RuleInput": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").DecodedSolanaRule | import(\"sdk/src/lib/agentic/agentic.types\").Rule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "assets": { + "optional": true, + "readonly": false, + "type": "{\n maxPerCall: bigint;\n maxTotal: bigint;\n token: string;\n}[] | import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset[] | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "maxGasPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Pin": { + "type": "{\n account: number;\n arg?: never;\n expected: \"agentic:wallet\" | string;\n max?: never;\n token?: import(\"sdk/src/lib/constants/tokens\").MoveableToken | string;\n} | {\n account?: never;\n arg: import(\"sdk/src/lib/agentic/agentic.types\").ArgumentPath;\n expected: \"agentic:wallet\" | `0x${string}` | `0x${string}` | bigint;\n max?: never;\n} | {\n account?: never;\n arg: import(\"sdk/src/lib/agentic/agentic.types\").ArgumentPath;\n expected?: never;\n max: bigint;\n}", + "members": { + "account": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "arg": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ArgumentPath | undefined" + }, + "expected": { + "optional": true, + "readonly": false, + "type": "bigint | string | undefined" + }, + "max": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "Spent": { + "type": "{\n actions: {\n amountSpent: bigint;\n callsUsed: number;\n selector: \"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector;\n target: `0x${string}`;\n valueSpent: bigint;\n }[];\n kind: \"native\";\n} | {\n amountSpent: bigint;\n callsUsed: number;\n kind: \"native\";\n valueSpent: bigint;\n} | {\n assets: {\n spent: bigint;\n token: string;\n }[];\n kind: \"universal\";\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"native\" | \"universal\"" + } + } + }, + "WalletMarker": { + "type": "\"agentic:wallet\"", + "members": {} + }, + "ArgumentPath": { + "type": "number | readonly number[]", + "members": {} + }, + "RulesRecord": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "enabled": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "rule": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").DecodedSolanaRule | import(\"sdk/src/lib/agentic/agentic.types\").Rule" + }, + "rulesId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "spent": { + "optional": false, + "readonly": false, + "type": "{\n actions: {\n amountSpent: bigint;\n callsUsed: number;\n selector: \"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector;\n target: `0x${string}`;\n valueSpent: bigint;\n }[];\n kind: \"native\";\n} | {\n amountSpent: bigint;\n callsUsed: number;\n kind: \"native\";\n valueSpent: bigint;\n} | {\n assets: {\n spent: bigint;\n token: string;\n }[];\n kind: \"universal\";\n}" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Selector": { + "type": "`${string}(${string})` | `0x${string}`", + "members": {} + }, + "WalletInfo": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").WalletInfo", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "label": { + "optional": false, + "readonly": false, + "type": "string" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "rulesCount": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "WalletSummary": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "label": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesCount": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "PushChain": { + "type": "import(\"sdk/src/lib/push-chain/push-chain\").PushChain", + "members": { + "accountStatus": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus" + }, + "accountStatusReady": { + "optional": false, + "readonly": false, + "type": "Promise" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace" + }, + "explorer": { + "optional": false, + "readonly": false, + "type": "{\n getTransactionUrl: (txHash: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n listAllUrls: () => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n listUrls: (options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n}" + }, + "funds": { + "optional": false, + "readonly": false, + "type": "{\n getConversionQuote: (amountIn: bigint, options: {\n from: import(\"sdk/src/lib/constants/tokens\").PayableToken | undefined;\n to: import(\"sdk/src/lib/constants/tokens\").MoveableToken | undefined;\n }) => Promise;\n}" + }, + "getAccountStatus": { + "optional": false, + "readonly": false, + "type": "(options?: {\n forceRefresh?: boolean;\n}) => Promise" + }, + "isReadMode": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "moveable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").MoveableTokenAccessor;\n}" + }, + "payable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").PayableTokenAccessor;\n}" + }, + "reinitialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "universal": { + "optional": false, + "readonly": false, + "type": "{\n readonly account: `0x${string}`;\n executeReads: (reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>;\n executeTransactions: (txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise;\n migrateCEA: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"migrateCEA\"];\n readonly origin: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n prepareRead: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n prepareTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"prepareTransaction\"];\n read: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n rescueFunds: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"rescueFunds\"];\n sendTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"execute\"];\n signMessage: (data: Uint8Array) => Promise;\n signTypedData: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n trackRead: {\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n };\n trackTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"trackTransaction\"];\n}" + }, + "upgradeAccount": { + "optional": false, + "readonly": false, + "type": "(options?: {\n progressHook?: (progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n}) => Promise" + } + } + }, + "Preset": { + "type": "import(\"sdk/src/lib/agentic/presets/types\").Preset", + "members": { + "chains": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace[]" + }, + "constant": { + "optional": false, + "readonly": false, + "type": "\"DEXES\" | \"LENDING\" | \"PREDICTION\" | \"STAKING\"" + }, + "name": { + "optional": false, + "readonly": false, + "type": "string" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"CATEGORY\"" + } + } + }, + "PresetCategory": { + "type": "\"DEXES\" | \"LENDING\" | \"PREDICTION\" | \"STAKING\"", + "members": {} + }, + "PresetAsset": { + "type": "import(\"sdk/src/lib/agentic/presets/types\").PresetAsset", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "maxPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/tokens\").MoveableToken | string" + } + } + }, + "PresetOptions": { + "type": "import(\"sdk/src/lib/agentic/presets/types\").PresetOptions", + "members": { + "agent": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "assets": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/presets/types\").PresetAsset[] | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "maxGasPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "validUntil": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadyPresetOptions": { + "type": "import(\"sdk/src/lib/agentic/presets/types\").ReadyPresetOptions", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "assets": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/presets/types\").PresetAsset[] | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "maxGasPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "PresetRuleTemplate": { + "type": "{\n agent?: `0x${string}`;\n validUntil?: number;\n} & Omit", + "members": { + "agent": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleCall[]" + }, + "assets": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset[] | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "maxGasPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "validUntil": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "AgenticPresets": { + "type": "import(\"sdk/src/lib/agentic/presets/types\").AgenticPresets", + "members": { + "get": { + "optional": false, + "readonly": false, + "type": "{\n (preset: import(\"sdk/src/lib/agentic/presets/types\").PresetCategory, options: import(\"sdk/src/lib/agentic/presets/types\").ReadyPresetOptions): {\n rules: import(\"sdk/src/lib/agentic/agentic.types\").Rule[];\n };\n (preset: import(\"sdk/src/lib/agentic/presets/types\").PresetCategory, options?: import(\"sdk/src/lib/agentic/presets/types\").PresetOptions): {\n rules: import(\"sdk/src/lib/agentic/presets/types\").PresetRuleTemplate[];\n };\n}" + }, + "list": { + "optional": false, + "readonly": false, + "type": "(options?: {\n type?: \"CATEGORY\";\n}) => {\n presets: import(\"sdk/src/lib/agentic/presets/types\").Preset[];\n}" + } + } + } + }, + "pushChainStatic": { + "CONSTANTS": { + "optional": false, + "readonly": false, + "type": "{\n AGENTIC: Readonly<{\n PRESETS: Readonly<{\n CATEGORY: Readonly<{\n DEXES: \"DEXES\";\n LENDING: \"LENDING\";\n PREDICTION: \"PREDICTION\";\n STAKING: \"STAKING\";\n }>;\n }>;\n WALLET: \"agentic:wallet\";\n }>;\n CHAIN: typeof import(\"sdk/src/lib/constants/enums\").CHAIN;\n LIBRARY: typeof import(\"sdk/src/lib/constants/enums\").LIBRARY;\n MOVEABLE: {\n TOKEN: import(\"sdk/src/lib/constants/tokens\").MoveableTokenConstantsMap;\n };\n PAYABLE: {\n TOKEN: import(\"sdk/src/lib/constants/tokens\").PayableTokenConstantsMap;\n };\n PUSH_NETWORK: typeof import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n READ: {\n readonly CALLBACK_BUDGET_BUFFER: 3;\n readonly CHAIN: {\n readonly WEB2: \"web2\";\n } & Readonly<{\n readonly ARBITRUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA;\n readonly BASE_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA;\n readonly BNB_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET;\n readonly ETHEREUM_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET;\n readonly ETHEREUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA;\n readonly PUSH_LOCALNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET;\n readonly PUSH_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET;\n readonly PUSH_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly PUSH_TESTNET_DONUT: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly SOLANA_DEVNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET;\n readonly SOLANA_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET;\n readonly SOLANA_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n readonly WEB2: \"web2\";\n }>;\n readonly DEFAULT_EXPIRY_BLOCKS: 300n;\n readonly ERROR_CODE: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n readonly MAX_CALLBACK_GAS_LIMIT: 1000000n;\n readonly MIN_CONFIRMATIONS_FLOOR: 1;\n readonly NAMESPACE: {\n readonly EVM: \"eip155\";\n readonly SVM: \"solana\";\n readonly WEB2: \"web2\";\n };\n readonly OUTCOME: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME;\n readonly REGISTRY_CALLBACK_GAS: 500000n;\n readonly RESULT_STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n readonly STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS;\n readonly UNIVERSAL_CALLBACK_ADDRESSES: Record;\n readonly UNIVERSAL_CORE_ADDRESSES: Record;\n readonly UNIVERSAL_READ_REGISTRY_ADDRESS: {\n readonly TESTNET_DONUT: \"0x00000000000000000000000000000000000000b2\";\n };\n readonly WEB2: \"web2\";\n readonly WEB2_DEFAULT_TIMEOUT_MS: 5000;\n readonly WEB2_MAX_EXTRACT_ENTRIES: 16;\n };\n}" + }, + "initialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "utils": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/utils\").Utils" + } + }, + "pushChainInstance": { + "accountStatus": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus" + }, + "accountStatusReady": { + "optional": false, + "readonly": false, + "type": "Promise" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace" + }, + "explorer": { + "optional": false, + "readonly": false, + "type": "{\n getTransactionUrl: (txHash: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n listAllUrls: () => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n listUrls: (options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n}" + }, + "funds": { + "optional": false, + "readonly": false, + "type": "{\n getConversionQuote: (amountIn: bigint, options: {\n from: import(\"sdk/src/lib/constants/tokens\").PayableToken | undefined;\n to: import(\"sdk/src/lib/constants/tokens\").MoveableToken | undefined;\n }) => Promise;\n}" + }, + "getAccountStatus": { + "optional": false, + "readonly": false, + "type": "(options?: {\n forceRefresh?: boolean;\n}) => Promise" + }, + "isReadMode": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "moveable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").MoveableTokenAccessor;\n}" + }, + "payable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").PayableTokenAccessor;\n}" + }, + "reinitialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "universal": { + "optional": false, + "readonly": false, + "type": "{\n readonly account: `0x${string}`;\n executeReads: (reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>;\n executeTransactions: (txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise;\n migrateCEA: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"migrateCEA\"];\n readonly origin: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n prepareRead: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n prepareTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"prepareTransaction\"];\n read: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n rescueFunds: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"rescueFunds\"];\n sendTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"execute\"];\n signMessage: (data: Uint8Array) => Promise;\n signTypedData: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n trackRead: {\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n };\n trackTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"trackTransaction\"];\n}" + }, + "upgradeAccount": { + "optional": false, + "readonly": false, + "type": "(options?: {\n progressHook?: (progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n}) => Promise" + } + }, + "transactionMethods": { + "account": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "executeReads": { + "optional": false, + "readonly": false, + "type": "(reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>" + }, + "executeTransactions": { + "optional": false, + "readonly": false, + "type": "(txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise" + }, + "migrateCEA": { + "optional": false, + "readonly": false, + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => Promise" + }, + "origin": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "prepareRead": { + "optional": false, + "readonly": false, + "type": "(subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>" + }, + "prepareTransaction": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions) => Promise" + }, + "read": { + "optional": false, + "readonly": false, + "type": "(subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>" + }, + "rescueFunds": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").RescueFundsParams) => Promise" + }, + "sendTransaction": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").ExecuteParams | import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions) => Promise" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": false, + "readonly": false, + "type": "({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise" + }, + "trackRead": { + "optional": false, + "readonly": false, + "type": "{\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n}" + }, + "trackTransaction": { + "optional": false, + "readonly": false, + "type": "(txHash: string, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TrackTransactionOptions) => Promise" + } + }, + "utilityMethods": { + "account": { + "optional": false, + "readonly": false, + "type": "{\n convertExecutorToOriginAccount: (ueaAddress: `0x${string}`, options?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n }) => Promise;\n convertOriginToExecutor: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n onlyCompute?: boolean;\n }) => Promise;\n deriveExecutorAccount: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n skipNetworkCheck?: boolean;\n }) => Promise;\n fromChainAgnostic: (caip: string) => import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n resolveControllerAccount: (address: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n skipNetworkCheck?: boolean;\n }) => Promise;\n toChainAgnostic: (address: string, options: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n toUniversal: (address: string, options: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n}" + }, + "agentic": { + "optional": false, + "readonly": true, + "type": "{\n readonly presets: import(\"sdk/src/lib/agentic/presets/types\").AgenticPresets;\n}" + }, + "chains": { + "optional": false, + "readonly": false, + "type": "{\n getChainName: (chainNamespace: string) => string | undefined;\n getChainNamespace: (chainName: string) => string | undefined;\n getSupportedChains: (network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK) => {\n chains: import(\"sdk/src/lib/constants/enums\").CHAIN[];\n };\n getSupportedChainsByName: (network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK) => {\n chains: string[];\n };\n}" + }, + "conversion": { + "optional": false, + "readonly": false, + "type": "{\n slippageToMinAmount(amount: string, options: {\n slippageBps: number;\n }): string;\n}" + }, + "helpers": { + "optional": false, + "readonly": false, + "type": "{\n encodeTxData({ abi, idl, functionName, args, }: {\n abi?: any;\n args?: any[];\n functionName: string;\n idl?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n }): `0x${string}`;\n formatUnits(value: bigint | string, decimalsOrOptions: {\n decimals: number;\n precision?: number;\n } | number): string;\n getChainName: (chainName: string) => string | undefined;\n parseUnits(value: string, exponent: {\n decimals: number;\n } | number): bigint;\n}" + }, + "signer": { + "optional": false, + "readonly": false, + "type": "{\n construct: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options: {\n signAndSendTransaction: (unsignedTx: Uint8Array) => Promise;\n signAuthorization?: (params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise;\n signMessage: (data: Uint8Array) => Promise;\n signTypedData?: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n }) => import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton;\n toUniversal: (signer: import(\"sdk/src/lib/universal/universal.types\").EthersV5SignerType | import(\"sdk/src/lib/universal/universal.types\").EthersV6SignerType | import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton | import(\"sdk/src/lib/universal/universal.types\").ViemSignerType) => Promise;\n toUniversalFromKeypair: (clientOrAccount: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@solana/web3.js/lib/index\").Keypair | import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").WalletClient | import(\"sdk/src/lib/universal/universal.types\").EthersV6SignerType, { chain, library }: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n library: import(\"sdk/src/lib/constants/enums\").LIBRARY;\n }) => Promise;\n}" + }, + "svm": { + "optional": false, + "readonly": false, + "type": "{\n getRegisteredIdls: () => Array<{\n address: `0x${string}`;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n }>;\n registerIdl: (idl: unknown) => void;\n}" + }, + "tokens": { + "optional": false, + "readonly": false, + "type": "{\n getMoveableTokens(chainOrClient?: import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/push-chain/push-chain\").PushChain): {\n tokens: Array<{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n decimals: number;\n mechanism: \"approve\" | \"native\" | \"permit2\";\n prc20Address?: `0x${string}`;\n sourceChain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n symbol: string;\n }>;\n };\n getPayableTokens(chainOrClient?: import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/push-chain/push-chain\").PushChain): {\n tokens: Array<{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n decimals: number;\n mechanism: \"approve\" | \"native\" | \"permit2\";\n symbol: string;\n }>;\n };\n getPC20Address(address: string, options: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n rpcUrls?: Partial>;\n strict?: boolean;\n }): Promise;\n getPRC20Address: (token: {\n address: string;\n chain: string;\n } | import(\"sdk/src/lib/constants/tokens\").MoveableToken, options?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n }) => {\n address: `0x${string}`;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n decimals: number;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n symbol: string;\n };\n}" + } + }, + "initialize": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise", + "agwConstants": { + "PRESETS": { + "optional": false, + "readonly": true, + "type": "{\n readonly CATEGORY: Readonly<{\n DEXES: \"DEXES\";\n LENDING: \"LENDING\";\n PREDICTION: \"PREDICTION\";\n STAKING: \"STAKING\";\n }>;\n}" + }, + "WALLET": { + "optional": false, + "readonly": true, + "type": "\"agentic:wallet\"" + } + }, + "constants": { + "AGENTIC": { + "optional": false, + "readonly": false, + "type": "{\n readonly PRESETS: Readonly<{\n CATEGORY: Readonly<{\n DEXES: \"DEXES\";\n LENDING: \"LENDING\";\n PREDICTION: \"PREDICTION\";\n STAKING: \"STAKING\";\n }>;\n }>;\n readonly WALLET: \"agentic:wallet\";\n}" + }, + "CHAIN": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "LIBRARY": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").LIBRARY" + }, + "MOVEABLE": { + "optional": false, + "readonly": false, + "type": "{\n TOKEN: import(\"sdk/src/lib/constants/tokens\").MoveableTokenConstantsMap;\n}" + }, + "PAYABLE": { + "optional": false, + "readonly": false, + "type": "{\n TOKEN: import(\"sdk/src/lib/constants/tokens\").PayableTokenConstantsMap;\n}" + }, + "PUSH_NETWORK": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "READ": { + "optional": false, + "readonly": false, + "type": "{\n readonly CALLBACK_BUDGET_BUFFER: 3;\n readonly CHAIN: {\n readonly WEB2: \"web2\";\n } & Readonly<{\n readonly ARBITRUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA;\n readonly BASE_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA;\n readonly BNB_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET;\n readonly ETHEREUM_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET;\n readonly ETHEREUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA;\n readonly PUSH_LOCALNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET;\n readonly PUSH_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET;\n readonly PUSH_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly PUSH_TESTNET_DONUT: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly SOLANA_DEVNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET;\n readonly SOLANA_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET;\n readonly SOLANA_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n readonly WEB2: \"web2\";\n }>;\n readonly DEFAULT_EXPIRY_BLOCKS: 300n;\n readonly ERROR_CODE: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n readonly MAX_CALLBACK_GAS_LIMIT: 1000000n;\n readonly MIN_CONFIRMATIONS_FLOOR: 1;\n readonly NAMESPACE: {\n readonly EVM: \"eip155\";\n readonly SVM: \"solana\";\n readonly WEB2: \"web2\";\n };\n readonly OUTCOME: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME;\n readonly REGISTRY_CALLBACK_GAS: 500000n;\n readonly RESULT_STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n readonly STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS;\n readonly UNIVERSAL_CALLBACK_ADDRESSES: Record;\n readonly UNIVERSAL_CORE_ADDRESSES: Record;\n readonly UNIVERSAL_READ_REGISTRY_ADDRESS: {\n readonly TESTNET_DONUT: \"0x00000000000000000000000000000000000000b2\";\n };\n readonly WEB2: \"web2\";\n readonly WEB2_DEFAULT_TIMEOUT_MS: 5000;\n readonly WEB2_MAX_EXTRACT_ENTRIES: 16;\n}" + } + } + }, + "scope": "All root exports and declared public members, PushChain static/instance members, universal transaction methods, utility groups, readonly/optional markers and constants. Behavior/default/deployment changes need the written session review." +} diff --git a/plan/agw/research/preset-expanded-live-2026-10-15/base-arbitrum-fixed-live.log b/plan/agw/research/preset-expanded-live-2026-10-15/base-arbitrum-fixed-live.log new file mode 100644 index 00000000..62a068a9 --- /dev/null +++ b/plan/agw/research/preset-expanded-live-2026-10-15/base-arbitrum-fixed-live.log @@ -0,0 +1,14 @@ +PASS core-e2e __e2e__/agw/presets-expanded-live.spec.ts (493.47 s) + agw presets expanded + ✓ 2. DEX swap on eip155:84532 (188470 ms) + ✓ 3. DEX swap and Aave round trip on eip155:421614 (302405 ms) + ○ skipped 1. EigenLayer Sepolia deposit credits shares to the wallet + ○ skipped 4. DEX swap and Venus round trip on eip155:97 + ○ skipped 5. Base Aave and both Moonwell markets supply and redeem wallet positions + +Test Suites: 1 passed, 1 total +Tests: 3 skipped, 2 passed, 5 total +Snapshots: 0 total +Time: 493.525 s +Ran all test suites within paths "__e2e__/agw/presets-expanded-live.spec.ts". +Force exiting Jest: Have you considered using `--detectOpenHandles` to detect async operations that kept running after all tests finished? diff --git a/plan/agw/research/preset-expanded-live-2026-10-15/build.log b/plan/agw/research/preset-expanded-live-2026-10-15/build.log new file mode 100644 index 00000000..0c276d11 --- /dev/null +++ b/plan/agw/research/preset-expanded-live-2026-10-15/build.log @@ -0,0 +1,13 @@ + +> nx run core:build + +Compiling TypeScript files for project "core"... +Done compiling TypeScript files for project "core". +(node:36080) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. +(Use `node --trace-warnings ...` to show where the warning was created) + + + + NX Successfully ran target build for project core + + diff --git a/plan/agw/research/preset-expanded-live-2026-10-15/check-redemptions.cjs b/plan/agw/research/preset-expanded-live-2026-10-15/check-redemptions.cjs new file mode 100644 index 00000000..4f48cef5 --- /dev/null +++ b/plan/agw/research/preset-expanded-live-2026-10-15/check-redemptions.cjs @@ -0,0 +1,11 @@ +// Read-only receipt and balance checks; no keys loaded. +const fs=require('fs');const {createPublicClient,http,parseAbi,parseEventLogs,erc20Abi}=require(process.cwd()+'/node_modules/viem'); +const events=fs.readFileSync('packages/core/e2e-logs/agw-evidence.jsonl','utf8').trim().split('\n').map(JSON.parse); +const last=n=>events.filter(x=>x.name===n).at(-1); +const venus=last('preset-expanded-venus'),base=last('preset-expanded-base-lending'); +const cases=[ +{chain:'eip155:97',rpc:'https://bsc-testnet-rpc.publicnode.com',wallet:venus.wallet,cea:venus.cea,expectedShares:venus.shares,stage:'venus-redeem-completed',market:'0xb7526572FFE56AB9D7489838Bf2E18e3323b441A',underlying:'0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c'}, +{chain:'eip155:84532',rpc:'https://base-sepolia-rpc.publicnode.com',wallet:base.wallet,cea:base.cea,expectedShares:base.sharesUSDBC,stage:'lending-withdraw-completed',market:'0x876852425331a113d8E432eFFB3aC5BEf38f033a',underlying:'0x4616975f7E6045FD9737e95bC527e9e14c727BD2'}, +{chain:'eip155:84532',rpc:'https://base-sepolia-rpc.publicnode.com',wallet:base.wallet,cea:base.cea,expectedShares:base.sharesWETH,stage:'lending-withdraw-completed',market:'0x2F39a349A79492a70E152760ce7123A1933eCf28',underlying:'0x663A6F02d547dFd639BF689FED298712f2FB69Fb'}, +]; +(async()=>{const result=await Promise.all(cases.map(async x=>{const c=createPublicClient({transport:http(x.rpc)});const stage=events.find(e=>e.wallet===x.wallet&&e.stage===x.stage);const r=await c.getTransactionReceipt({hash:stage.externalTx});const redeemed=parseEventLogs({abi:parseAbi(['event Redeem(address redeemer,uint256 redeemAmount,uint256 redeemTokens)', 'event Redeem(address redeemer,uint256 redeemAmount,uint256 redeemTokens,uint256 totalSupply)']),logs:r.logs}).find(e=>e.address.toLowerCase()===x.market.toLowerCase()&&e.args.redeemer.toLowerCase()===x.cea.toLowerCase());if(!redeemed)throw Error('Missing Redeem event');if(redeemed.args.redeemTokens!==BigInt(x.expectedShares))throw Error('Redeemed shares differ from minted shares');const balance=await c.readContract({address:x.underlying,abi:erc20Abi,functionName:'balanceOf',args:[x.cea]});const shares=await c.readContract({address:x.market,abi:erc20Abi,functionName:'balanceOf',args:[x.cea]});if(balance!==redeemed.args.redeemAmount||shares!==0n)throw Error('Balance does not match redeemed amount / shares remain');return{...x,tx:stage.externalTx,block:String(r.blockNumber),redeemAmount:String(balance),redeemedShares:String(redeemed.args.redeemTokens),remainingShares:String(shares)};}));fs.writeFileSync('plan/agw/research/preset-expanded-live-2026-10-15/redemptions.json',JSON.stringify(result,null,2)+'\n');console.log(result.map(x=>({chain:x.chain,market:x.market,redeemAmount:x.redeemAmount,remainingShares:x.remainingShares})));})().catch(e=>{console.error(e.shortMessage||e.message);process.exitCode=1;}); diff --git a/plan/agw/research/preset-expanded-live-2026-10-15/e2e-lint.log b/plan/agw/research/preset-expanded-live-2026-10-15/e2e-lint.log new file mode 100644 index 00000000..f0c407b5 --- /dev/null +++ b/plan/agw/research/preset-expanded-live-2026-10-15/e2e-lint.log @@ -0,0 +1,10 @@ + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/agw/presets-expanded-live.spec.ts + 440:20 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 487:21 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 570:18 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 572:20 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 574:19 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +✖ 5 problems (0 errors, 5 warnings) + diff --git a/plan/agw/research/preset-expanded-live-2026-10-15/eigen-live.log b/plan/agw/research/preset-expanded-live-2026-10-15/eigen-live.log new file mode 100644 index 00000000..b5e5bc27 --- /dev/null +++ b/plan/agw/research/preset-expanded-live-2026-10-15/eigen-live.log @@ -0,0 +1,10 @@ +PASS core-e2e __e2e__/agw/presets-expanded-live.spec.ts (175.399 s) + agw presets expanded + ✓ 1. EigenLayer Sepolia deposit credits shares to the wallet (174162 ms) + +Test Suites: 1 passed, 1 total +Tests: 1 passed, 1 total +Snapshots: 0 total +Time: 175.423 s +Ran all test suites within paths "__e2e__/agw/presets-expanded-live.spec.ts". +Force exiting Jest: Have you considered using `--detectOpenHandles` to detect async operations that kept running after all tests finished? diff --git a/plan/agw/research/preset-expanded-live-2026-10-15/eigen-prerequisites.json b/plan/agw/research/preset-expanded-live-2026-10-15/eigen-prerequisites.json new file mode 100644 index 00000000..a55e3d9f --- /dev/null +++ b/plan/agw/research/preset-expanded-live-2026-10-15/eigen-prerequisites.json @@ -0,0 +1,9 @@ +{ + "block": "11917418", + "strategy": "0x424246eF71b01ee33aA33aC590fd9a0855F5eFbc", + "manager": "0x2E3D6c0744b10eb0A4e6F679F71554a39Ec47a5D", + "underlying": "0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9", + "whitelisted": true, + "paused": "0", + "wrap": "ok" +} diff --git a/plan/agw/research/preset-expanded-live-2026-10-15/initial-live.log b/plan/agw/research/preset-expanded-live-2026-10-15/initial-live.log new file mode 100644 index 00000000..f7fc1458 --- /dev/null +++ b/plan/agw/research/preset-expanded-live-2026-10-15/initial-live.log @@ -0,0 +1,48 @@ +FAIL core-e2e __e2e__/agw/presets-expanded-live.spec.ts (602.662 s) + agw presets expanded + ✕ 2 DEX swap on eip155:84532 and matching lending round trip where available (41322 ms) + ✕ 3 DEX swap on eip155:421614 and matching lending round trip where available (38665 ms) + ✓ 4 DEX swap on eip155:97 and matching lending round trip where available (303120 ms) + ✓ 5. Base Aave and both Moonwell markets supply and redeem wallet positions (218165 ms) + ○ skipped 1. EigenLayer Sepolia deposit credits shares to the wallet + + ● agw presets expanded › 2 DEX swap on eip155:84532 and matching lending round trip where available + + AgenticError: wallet 0x075524ed04cFa47f28e2e79641c93dc3aDAFeE57 holds 0 of 0x2971824Db68229D087931155C2b8bB820B275809; this outbound burns 1000000000000 + + 275 | } + 276 | if (tokenBalance < out.amount) { + > 277 | throw new AgenticError( + | ^ + 278 | AGENTIC_ERROR_CODE.WALLET_BALANCE_INSUFFICIENT, + 279 | `wallet ${wallet} holds ${tokenBalance} of ${out.token}; this outbound burns ${out.amount}` + 280 | ); + + at agenticSend (src/lib/agentic/execution/send.ts:277:13) + at async send (__e2e__/agw/presets-expanded-live.spec.ts:130:14) + at async wrap (__e2e__/agw/presets-expanded-live.spec.ts:208:3) + at async /Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/agw/presets-expanded-live.spec.ts:366:7 + + ● agw presets expanded › 3 DEX swap on eip155:421614 and matching lending round trip where available + + AgenticError: wallet 0x9Cb7c388E67A94f40aDeFdbF8b09a93a3Bedeb63 holds 0 of 0x2971824Db68229D087931155C2b8bB820B275809; this outbound burns 1000000000000 + + 275 | } + 276 | if (tokenBalance < out.amount) { + > 277 | throw new AgenticError( + | ^ + 278 | AGENTIC_ERROR_CODE.WALLET_BALANCE_INSUFFICIENT, + 279 | `wallet ${wallet} holds ${tokenBalance} of ${out.token}; this outbound burns ${out.amount}` + 280 | ); + + at agenticSend (src/lib/agentic/execution/send.ts:277:13) + at async send (__e2e__/agw/presets-expanded-live.spec.ts:130:14) + at async wrap (__e2e__/agw/presets-expanded-live.spec.ts:208:3) + at async /Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/agw/presets-expanded-live.spec.ts:366:7 + +Test Suites: 1 failed, 1 total +Tests: 2 failed, 1 skipped, 2 passed, 5 total +Snapshots: 0 total +Time: 602.684 s +Ran all test suites within paths "__e2e__/agw/presets-expanded-live.spec.ts". +Force exiting Jest: Have you considered using `--detectOpenHandles` to detect async operations that kept running after all tests finished? diff --git a/plan/agw/research/preset-expanded-live-2026-10-15/live-evidence.jsonl b/plan/agw/research/preset-expanded-live-2026-10-15/live-evidence.jsonl new file mode 100644 index 00000000..6478cb1c --- /dev/null +++ b/plan/agw/research/preset-expanded-live-2026-10-15/live-evidence.jsonl @@ -0,0 +1,44 @@ +{"name": "preset-expanded-wallet", "at": "2026-10-15T02:28:28.946Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "label": "e2e-preset-eigen", "chain": "eip155:11155111", "wallet": "0x14BA212b2079843dE5a1569A3e774237C46971A6", "cea": "0x5Cd0C01Aca68A6Ac8640Bd7373Fb6Ffa5d152564", "rulesId": "0x6dcb90ae819b47920f0c2beeb12f2c17c5b9760897de26db5e078966c76c723a"} +{"name": "preset-expanded-stage", "at": "2026-10-15T02:28:41.265Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "chain": "eip155:11155111", "wallet": "0x14BA212b2079843dE5a1569A3e774237C46971A6", "cea": "0x5Cd0C01Aca68A6Ac8640Bd7373Fb6Ffa5d152564", "stage": "wrap-submitted", "pushTx": "0x6ba0740bcb04790b7ff9d1749e808c7ae3dd181c6ca6622d6e98483911ae9962"} +{"name": "preset-expanded-stage", "at": "2026-10-15T02:29:42.350Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "chain": "eip155:11155111", "wallet": "0x14BA212b2079843dE5a1569A3e774237C46971A6", "cea": "0x5Cd0C01Aca68A6Ac8640Bd7373Fb6Ffa5d152564", "stage": "wrap-completed", "pushTx": "0x6ba0740bcb04790b7ff9d1749e808c7ae3dd181c6ca6622d6e98483911ae9962", "externalTx": "0xc03555c7e6f8d854d137ee06ced983f02b752109b03f70ff83edfc919d1eb049", "status": "success"} +{"name": "preset-expanded-stage", "at": "2026-10-15T02:29:51.095Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "chain": "eip155:11155111", "wallet": "0x14BA212b2079843dE5a1569A3e774237C46971A6", "cea": "0x5Cd0C01Aca68A6Ac8640Bd7373Fb6Ffa5d152564", "stage": "eigen-deposit-submitted", "pushTx": "0xd6bb903bbd0b2ca7219fc823c0b025fa76be3a691d711969053f678f28452df8"} +{"name": "preset-expanded-stage", "at": "2026-10-15T02:30:52.565Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "chain": "eip155:11155111", "wallet": "0x14BA212b2079843dE5a1569A3e774237C46971A6", "cea": "0x5Cd0C01Aca68A6Ac8640Bd7373Fb6Ffa5d152564", "stage": "eigen-deposit-completed", "pushTx": "0xd6bb903bbd0b2ca7219fc823c0b025fa76be3a691d711969053f678f28452df8", "externalTx": "0x0c449911eb4dbaec980af7977fc559097b25a31cb963a659baa81887c6b95646", "status": "success"} +{"name": "preset-eigen-live", "at": "2026-10-15T02:30:52.840Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "wallet": "0x14BA212b2079843dE5a1569A3e774237C46971A6", "cea": "0x5Cd0C01Aca68A6Ac8640Bd7373Fb6Ffa5d152564", "strategy": "0x424246eF71b01ee33aA33aC590fd9a0855F5eFbc", "amount": "1000000000000", "shares": "1000000000000"} +{"name": "preset-expanded-wallet", "at": "2026-10-15T02:31:06.236Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "label": "e2e-preset-dex-eip155:84532", "chain": "eip155:84532", "wallet": "0x075524ed04cFa47f28e2e79641c93dc3aDAFeE57", "cea": "0xBbaA46648c80211a28683F0A5Db819eAe2Aef7f3", "rulesId": "0x9637c535f543a944252d90121392030c30e374696519d255b676b6cdd029ec6e"} +{"name": "preset-expanded-wallet", "at": "2026-10-15T02:31:45.074Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "label": "e2e-preset-dex-eip155:421614", "chain": "eip155:421614", "wallet": "0x9Cb7c388E67A94f40aDeFdbF8b09a93a3Bedeb63", "cea": "0xeb77d934Ed96018dC7c49dD822bc1d8dfe54fB10", "rulesId": "0x135bd125886df267055ef9f828dbb2438b9fa41c237cfb21f05954d16673efa0"} +{"name": "preset-expanded-wallet", "at": "2026-10-15T02:32:23.253Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "label": "e2e-preset-dex-eip155:97", "chain": "eip155:97", "wallet": "0xce76840d3ee4579217D5F2de1d3767b7EAe54605", "cea": "0x3c0a4e2f349059D5d1309d0f57871b1b9a4E1192", "rulesId": "0xa547377731a0265ee2ff0b6d7487d62f5809786f40d6456b18bada4f1e6359e8"} +{"name": "preset-expanded-stage", "at": "2026-10-15T02:32:39.150Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "chain": "eip155:97", "wallet": "0xce76840d3ee4579217D5F2de1d3767b7EAe54605", "cea": "0x3c0a4e2f349059D5d1309d0f57871b1b9a4E1192", "stage": "wrap-submitted", "pushTx": "0x47035167e0106f9b71af4f5ded6e0a27e11293615d847390ad8b2981e25f4120"} +{"name": "preset-expanded-stage", "at": "2026-10-15T02:33:26.061Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "chain": "eip155:97", "wallet": "0xce76840d3ee4579217D5F2de1d3767b7EAe54605", "cea": "0x3c0a4e2f349059D5d1309d0f57871b1b9a4E1192", "stage": "wrap-completed", "pushTx": "0x47035167e0106f9b71af4f5ded6e0a27e11293615d847390ad8b2981e25f4120", "externalTx": "0x9bdfe6e595cd4e2decca63c5065a690015c4d70d9646e5c537fbf6cabf8bb651", "status": "success"} +{"name": "preset-expanded-stage", "at": "2026-10-15T02:33:39.236Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "chain": "eip155:97", "wallet": "0xce76840d3ee4579217D5F2de1d3767b7EAe54605", "cea": "0x3c0a4e2f349059D5d1309d0f57871b1b9a4E1192", "stage": "dex-swap-submitted", "pushTx": "0x9d8fab2f61db2c007e312330165f5bd82a30c53d2a5d63d011b8c01ffcc80f8e"} +{"name": "preset-expanded-stage", "at": "2026-10-15T02:34:36.803Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "chain": "eip155:97", "wallet": "0xce76840d3ee4579217D5F2de1d3767b7EAe54605", "cea": "0x3c0a4e2f349059D5d1309d0f57871b1b9a4E1192", "stage": "dex-swap-completed", "pushTx": "0x9d8fab2f61db2c007e312330165f5bd82a30c53d2a5d63d011b8c01ffcc80f8e", "externalTx": "0x8756031cb1f023066d5b57e9c059ee1beb729666724c509a444d927a7668f3cc", "status": "success"} +{"name": "preset-expanded-dex", "at": "2026-10-15T02:34:37.071Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "chain": "eip155:97", "wallet": "0xce76840d3ee4579217D5F2de1d3767b7EAe54605", "cea": "0x3c0a4e2f349059D5d1309d0f57871b1b9a4E1192", "pool": "0xCed0844e421F856D2de472F9e7037f873987887C", "router": "0x9a489505a00cE272eAa5e07Dba6491314CaE3796", "amountIn": "1000000000000", "amountOut": "3361"} +{"name": "preset-expanded-stage", "at": "2026-10-15T02:34:55.563Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "chain": "eip155:97", "wallet": "0xce76840d3ee4579217D5F2de1d3767b7EAe54605", "cea": "0x3c0a4e2f349059D5d1309d0f57871b1b9a4E1192", "stage": "venus-mint-submitted", "pushTx": "0xac44b8931e28aa5e06a2bd8c9f06f9a94f7bcb21ea1b70dd18e9c5f275a0d563"} +{"name": "preset-expanded-stage", "at": "2026-10-15T02:35:56.666Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "chain": "eip155:97", "wallet": "0xce76840d3ee4579217D5F2de1d3767b7EAe54605", "cea": "0x3c0a4e2f349059D5d1309d0f57871b1b9a4E1192", "stage": "venus-mint-completed", "pushTx": "0xac44b8931e28aa5e06a2bd8c9f06f9a94f7bcb21ea1b70dd18e9c5f275a0d563", "externalTx": "0x7e647b624e05ef0b4bf31e492e3ccb40af7e1b938cab49f0a52d48181746927d", "status": "success"} +{"name": "preset-expanded-stage", "at": "2026-10-15T02:36:03.250Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "chain": "eip155:97", "wallet": "0xce76840d3ee4579217D5F2de1d3767b7EAe54605", "cea": "0x3c0a4e2f349059D5d1309d0f57871b1b9a4E1192", "stage": "venus-redeem-submitted", "pushTx": "0xe92a338ededec7a88b5740478440bf4e3e2249214912e30159ca943c22238077"} +{"name": "preset-expanded-stage", "at": "2026-10-15T02:36:53.420Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "chain": "eip155:97", "wallet": "0xce76840d3ee4579217D5F2de1d3767b7EAe54605", "cea": "0x3c0a4e2f349059D5d1309d0f57871b1b9a4E1192", "stage": "venus-redeem-completed", "pushTx": "0xe92a338ededec7a88b5740478440bf4e3e2249214912e30159ca943c22238077", "externalTx": "0xc7ab68b6f72171c83a2ec5cce9c3a0df66a53be60e3f46e9a2d4a6c49f25c4e0", "status": "success"} +{"name": "preset-expanded-venus", "at": "2026-10-15T02:36:53.699Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "chain": "eip155:97", "wallet": "0xce76840d3ee4579217D5F2de1d3767b7EAe54605", "cea": "0x3c0a4e2f349059D5d1309d0f57871b1b9a4E1192", "deposited": "3361", "redeemed": "3360", "shares": "16740010", "asset": "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c"} +{"name": "preset-expanded-wallet", "at": "2026-10-15T02:37:29.408Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "label": "e2e-preset-base-lending", "chain": "eip155:84532", "wallet": "0xF3445c8d5557Fab0519dA9c75eaB2B995F42B32f", "cea": "0xe37A1890878CEF71210Be37fae802e234E55eD44", "rulesId": "0xba1a524fc6b81b15581ae23ff882878bd76acd3f81c44c4000e172277bb63aaa"} +{"name": "preset-expanded-stage", "at": "2026-10-15T02:37:33.691Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "chain": "eip155:84532", "wallet": "0xF3445c8d5557Fab0519dA9c75eaB2B995F42B32f", "cea": "0xe37A1890878CEF71210Be37fae802e234E55eD44", "stage": "faucets-submitted", "pushTx": "0x637f532d9b18fbc9437c8ac487523c10249ecd03c5d7dcf1e397d51acd101a8b"} +{"name": "preset-expanded-wallet", "at": "2026-10-15T02:38:22.129Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "label": "e2e-preset-dex-eip155:84532", "chain": "eip155:84532", "wallet": "0x10a330D3FBe1694D78D0DeC0786376B9b82DE6BE", "cea": "0xDC28da449E1fC2e1e59AD25a39D9f044314938fD", "rulesId": "0x7169bc5a5be42589339fbb27afaed1b099c3d19ca8661c93d3c15671721c200d"} +{"name": "preset-expanded-stage", "at": "2026-10-15T02:38:27.499Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "chain": "eip155:84532", "wallet": "0xF3445c8d5557Fab0519dA9c75eaB2B995F42B32f", "cea": "0xe37A1890878CEF71210Be37fae802e234E55eD44", "stage": "faucets-completed", "pushTx": "0x637f532d9b18fbc9437c8ac487523c10249ecd03c5d7dcf1e397d51acd101a8b", "externalTx": "0x45e49ec224ec14f605e6d75d7137666246256abd9edae8e1a353307ec80c4921", "status": "success"} +{"name": "preset-expanded-stage", "at": "2026-10-15T02:38:33.116Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "chain": "eip155:84532", "wallet": "0x10a330D3FBe1694D78D0DeC0786376B9b82DE6BE", "cea": "0xDC28da449E1fC2e1e59AD25a39D9f044314938fD", "stage": "wrap-submitted", "pushTx": "0x3ab252858291f9ffdc8201eff4030e3b60f794eb1b9bfba661c5c96fc1ec8a8f"} +{"name": "preset-expanded-stage", "at": "2026-10-15T02:38:34.119Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "chain": "eip155:84532", "wallet": "0xF3445c8d5557Fab0519dA9c75eaB2B995F42B32f", "cea": "0xe37A1890878CEF71210Be37fae802e234E55eD44", "stage": "lending-supply-submitted", "pushTx": "0xb064c84ae20e1d41896f3391adecfa1e6bb682716ff9ca8d35ac9cc5ea11dd35"} +{"name": "preset-expanded-stage", "at": "2026-10-15T02:39:30.588Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "chain": "eip155:84532", "wallet": "0x10a330D3FBe1694D78D0DeC0786376B9b82DE6BE", "cea": "0xDC28da449E1fC2e1e59AD25a39D9f044314938fD", "stage": "wrap-completed", "pushTx": "0x3ab252858291f9ffdc8201eff4030e3b60f794eb1b9bfba661c5c96fc1ec8a8f", "externalTx": "0x8a1393a60c6e3b22bfbf324fd886186794a086daa2dc84c5eeeb545ac0066f52", "status": "success"} +{"name": "preset-expanded-stage", "at": "2026-10-15T02:39:31.511Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "chain": "eip155:84532", "wallet": "0xF3445c8d5557Fab0519dA9c75eaB2B995F42B32f", "cea": "0xe37A1890878CEF71210Be37fae802e234E55eD44", "stage": "lending-supply-completed", "pushTx": "0xb064c84ae20e1d41896f3391adecfa1e6bb682716ff9ca8d35ac9cc5ea11dd35", "externalTx": "0xde381c409fb2fac33cc973482b2198e3381b93f4e380f1c12784d766550bed91", "status": "success"} +{"name": "preset-expanded-stage", "at": "2026-10-15T02:39:40.631Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "chain": "eip155:84532", "wallet": "0xF3445c8d5557Fab0519dA9c75eaB2B995F42B32f", "cea": "0xe37A1890878CEF71210Be37fae802e234E55eD44", "stage": "lending-withdraw-submitted", "pushTx": "0x562e36fa4ba9e0873e901e643c75564fe193748cf09dedd64e96ae4b84d471a9"} +{"name": "preset-expanded-stage", "at": "2026-10-15T02:39:42.525Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "chain": "eip155:84532", "wallet": "0x10a330D3FBe1694D78D0DeC0786376B9b82DE6BE", "cea": "0xDC28da449E1fC2e1e59AD25a39D9f044314938fD", "stage": "dex-swap-submitted", "pushTx": "0x405b150a79f791b303923c527be9c528e855085d7bd53651e17bd0e4feb467e6"} +{"name": "preset-expanded-stage", "at": "2026-10-15T02:40:31.063Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "chain": "eip155:84532", "wallet": "0xF3445c8d5557Fab0519dA9c75eaB2B995F42B32f", "cea": "0xe37A1890878CEF71210Be37fae802e234E55eD44", "stage": "lending-withdraw-completed", "pushTx": "0x562e36fa4ba9e0873e901e643c75564fe193748cf09dedd64e96ae4b84d471a9", "externalTx": "0x1bc2a2e5849d3e61c7e7927360c6f7936d0399a8c27cc2f988f6f4e54256366e", "status": "success"} +{"name": "preset-expanded-base-lending", "at": "2026-10-15T02:40:31.865Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "chain": "eip155:84532", "wallet": "0xF3445c8d5557Fab0519dA9c75eaB2B995F42B32f", "cea": "0xe37A1890878CEF71210Be37fae802e234E55eD44", "link": "1000000000000", "usdbc": "10000", "weth": "1000000000000", "sharesUSDBC": "49999832", "sharesWETH": "2945"} +{"name": "preset-expanded-stage", "at": "2026-10-15T02:41:01.614Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "chain": "eip155:84532", "wallet": "0x10a330D3FBe1694D78D0DeC0786376B9b82DE6BE", "cea": "0xDC28da449E1fC2e1e59AD25a39D9f044314938fD", "stage": "dex-swap-completed", "pushTx": "0x405b150a79f791b303923c527be9c528e855085d7bd53651e17bd0e4feb467e6", "externalTx": "0xf09a982297c6f3a65a96270fbbfa304681cd85cb7da1172d4e15045be5fb4be4", "status": "success"} +{"name": "preset-expanded-dex", "at": "2026-10-15T02:41:01.906Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "chain": "eip155:84532", "wallet": "0x10a330D3FBe1694D78D0DeC0786376B9b82DE6BE", "cea": "0xDC28da449E1fC2e1e59AD25a39D9f044314938fD", "pool": "0x46880b404CD35c165EDdefF7421019F8dD25F4Ad", "router": "0x94cC0AaC535CCDB3C01d6787D6413C739ae12bc4", "amountIn": "1000000000000", "amountOut": "4874"} +{"name": "preset-expanded-wallet", "at": "2026-10-15T02:41:35.205Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "label": "e2e-preset-dex-eip155:421614", "chain": "eip155:421614", "wallet": "0x0466A29B7869676f58A78542F6Cb3C1414e5B1fe", "cea": "0xB681934F411c966f38F3AC5A756933AADB7896B9", "rulesId": "0xdf7e3e27d5d114ce4eed4bc2980408d925821b7c9cfa8518255ea4c8798f43bc"} +{"name": "preset-expanded-stage", "at": "2026-10-15T02:41:47.811Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "chain": "eip155:421614", "wallet": "0x0466A29B7869676f58A78542F6Cb3C1414e5B1fe", "cea": "0xB681934F411c966f38F3AC5A756933AADB7896B9", "stage": "wrap-submitted", "pushTx": "0x50a191c8cc5e0675361e9edea2a2dd4c1fe02c63032d6c142b0ee50af4131e27"} +{"name": "preset-expanded-stage", "at": "2026-10-15T02:42:37.971Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "chain": "eip155:421614", "wallet": "0x0466A29B7869676f58A78542F6Cb3C1414e5B1fe", "cea": "0xB681934F411c966f38F3AC5A756933AADB7896B9", "stage": "wrap-completed", "pushTx": "0x50a191c8cc5e0675361e9edea2a2dd4c1fe02c63032d6c142b0ee50af4131e27", "externalTx": "0xe587bce9e3fb2d0e9bc56aad4cb745a7ce8e15ae75a9dcbf7b1e20ddabebe582", "status": "success"} +{"name": "preset-expanded-stage", "at": "2026-10-15T02:42:50.383Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "chain": "eip155:421614", "wallet": "0x0466A29B7869676f58A78542F6Cb3C1414e5B1fe", "cea": "0xB681934F411c966f38F3AC5A756933AADB7896B9", "stage": "dex-swap-submitted", "pushTx": "0xf22eb1c0437c88e663b981653d7b03c173529dc6c43934efce934407c70eda26"} +{"name": "preset-expanded-stage", "at": "2026-10-15T02:43:55.500Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "chain": "eip155:421614", "wallet": "0x0466A29B7869676f58A78542F6Cb3C1414e5B1fe", "cea": "0xB681934F411c966f38F3AC5A756933AADB7896B9", "stage": "dex-swap-completed", "pushTx": "0xf22eb1c0437c88e663b981653d7b03c173529dc6c43934efce934407c70eda26", "externalTx": "0xeb5332e23ef674047cd98742d718bccfa1676c9d78a2d6bfec828373fc56c05c", "status": "success"} +{"name": "preset-expanded-dex", "at": "2026-10-15T02:43:55.766Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "chain": "eip155:421614", "wallet": "0x0466A29B7869676f58A78542F6Cb3C1414e5B1fe", "cea": "0xB681934F411c966f38F3AC5A756933AADB7896B9", "pool": "0x66EEAB70aC52459Dd74C6AD50D578Ef76a441bbf", "router": "0x101F443B4d1b059569D643917553c771E1b9663E", "amountIn": "1000000000000", "amountOut": "1912"} +{"name": "preset-expanded-stage", "at": "2026-10-15T02:44:15.138Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "chain": "eip155:421614", "wallet": "0x0466A29B7869676f58A78542F6Cb3C1414e5B1fe", "cea": "0xB681934F411c966f38F3AC5A756933AADB7896B9", "stage": "aave-supply-submitted", "pushTx": "0x7dae2ea5715eb04eef41f45960da197f53f5cf26bb7359ae107891c33d4f4c7f"} +{"name": "preset-expanded-stage", "at": "2026-10-15T02:45:05.518Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "chain": "eip155:421614", "wallet": "0x0466A29B7869676f58A78542F6Cb3C1414e5B1fe", "cea": "0xB681934F411c966f38F3AC5A756933AADB7896B9", "stage": "aave-supply-completed", "pushTx": "0x7dae2ea5715eb04eef41f45960da197f53f5cf26bb7359ae107891c33d4f4c7f", "externalTx": "0xcc4c6edfdad9f8daa8a889a07469ef358ecbe26ba914d5c57483c64bda1e6bc2", "status": "success"} +{"name": "preset-expanded-stage", "at": "2026-10-15T02:45:14.014Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "chain": "eip155:421614", "wallet": "0x0466A29B7869676f58A78542F6Cb3C1414e5B1fe", "cea": "0xB681934F411c966f38F3AC5A756933AADB7896B9", "stage": "aave-withdraw-submitted", "pushTx": "0x0ebc129e7f347cdb7680174e646f78139711f3bbe8ef5fa4a82faee2995f4649"} +{"name": "preset-expanded-stage", "at": "2026-10-15T02:46:04.175Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "chain": "eip155:421614", "wallet": "0x0466A29B7869676f58A78542F6Cb3C1414e5B1fe", "cea": "0xB681934F411c966f38F3AC5A756933AADB7896B9", "stage": "aave-withdraw-completed", "pushTx": "0x0ebc129e7f347cdb7680174e646f78139711f3bbe8ef5fa4a82faee2995f4649", "externalTx": "0xe528d15940c2e8b2b17e0e8bf63927c7b4a75fff7c1c35b515c80de4d32be86a", "status": "success"} +{"name": "preset-expanded-aave", "at": "2026-10-15T02:46:04.312Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "chain": "eip155:421614", "wallet": "0x0466A29B7869676f58A78542F6Cb3C1414e5B1fe", "cea": "0xB681934F411c966f38F3AC5A756933AADB7896B9", "amount": "1912", "asset": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d"} diff --git a/plan/agw/research/preset-expanded-live-2026-10-15/local-contracts.log b/plan/agw/research/preset-expanded-live-2026-10-15/local-contracts.log new file mode 100644 index 00000000..749e39e5 --- /dev/null +++ b/plan/agw/research/preset-expanded-live-2026-10-15/local-contracts.log @@ -0,0 +1,24 @@ +PASS core-agw-local packages/core/__agw-local__/v5-multiasset.spec.ts (9.055 s) + v6 multi-asset SDK management and execution + ✓ v6 EVM alternatives enforce both spender and MAX, and reads update losslessly (902 ms) + ✓ v6 refuses a bare alternative that bypasses a pinned function and too many initial rules (31 ms) + ✓ the shipped DEX catalog enforces tuple receiver/token/amount pins on actual v6 URP (404 ms) + ✓ a review-only DEX exactInputSingle call cannot spend tokens even after asset budgets are filled (377 ms) + ✓ a review-only DEX exactOutputSingle call cannot spend tokens even after asset budgets are filled (360 ms) + ✓ a fixture preset produces rules accepted by public create and enforced by real contracts (380 ms) + ✓ public create encodes two ordered assets; public get reconstructs source-token caps (356 ms) + ✓ a token from the wrong chain fails before deployment (9 ms) + ✓ a same-chain registry identity mismatch fails before deployment (3 ms) + ✓ both tokens execute under one rule and keep independent counters/limits (364 ms) + ✓ omitted and explicit zero totals both prohibit movement (350 ms) + ✓ empty user assets grants one zero-cap gas token and executes a call-only request (358 ms) + ✓ public update resets both counters in one batch and records five checkpoints (365 ms) + ✓ spend on the second asset after snapshot rolls back revoke/grant and checkpoint writes (367 ms) + ✓ out-of-band duplicate contract grants still make sends ambiguous (22 ms) + ✓ a legacy two-field envelope is refused by the actual v6 grant path (6 ms) + +Test Suites: 1 passed, 1 total +Tests: 16 passed, 16 total +Snapshots: 0 total +Time: 9.082 s +Ran all test suites within paths "packages/core/__agw-local__/v5-multiasset.spec.ts". diff --git a/plan/agw/research/preset-expanded-live-2026-10-15/preflight.log b/plan/agw/research/preset-expanded-live-2026-10-15/preflight.log new file mode 100644 index 00000000..e398218a --- /dev/null +++ b/plan/agw/research/preset-expanded-live-2026-10-15/preflight.log @@ -0,0 +1,20 @@ +AGW deployment manifest verified on-chain. + +Wallets + EVM master (Sepolia) 0x0A16CBa65FfCAa4C2282b27b027Ab4A2fE46E0Bf + Push master (Donut) 0x0A16CBa65FfCAa4C2282b27b027Ab4A2fE46E0Bf + Solana master (Devnet) 3nK8X1re4zLNrgz9Y3xKS4g2fKPJ6M3N9BhNuFfkjwAb + Shared UEA (Donut) 0x5C70C864Cf1aDfB04A0e107fFA248ba3600EAb8D + UEA CEA PDA (Devnet) Fqp8UeJxEWvN1Ciu5jqrA3opGXwNvRL2HfJxNQotj3Qh + +Group "agw-presets-expanded" — 5 scenarios, headroom ×1.25. + +┌─────────────────────┬───────┬──────────┬─────────────┬────────┐ +│ Scope │ Asset │ Need │ Have │ Status │ +├─────────────────────┼───────┼──────────┼─────────────┼────────┤ +│ Push master (Donut) │ PC │ 689.5000 │ 968752.1300 │ ✓ │ +│ Push master (Donut) │ pETH │ 0.000001 │ 434.3115 │ ✓ │ +└─────────────────────┴───────┴──────────┴─────────────┴────────┘ + +All master wallets can cover this run. +Derived accounts are already at target. Ready to run. diff --git a/plan/agw/research/preset-expanded-live-2026-10-15/prerequisites.json b/plan/agw/research/preset-expanded-live-2026-10-15/prerequisites.json new file mode 100644 index 00000000..67188b03 --- /dev/null +++ b/plan/agw/research/preset-expanded-live-2026-10-15/prerequisites.json @@ -0,0 +1,203 @@ +[ + { + "chain": 84532, + "actualChain": 84532, + "observedStartBlock": "48131419", + "wrapped": "0x4200000000000000000000000000000000000006", + "pools": [ + { + "token": "0x036CbD53842c5426634e7929541eC2318f3dCF7e", + "fee": 100, + "pool": "0x57183717A087d2fe3Ad890873877244c3B96156c", + "liquidity": "2890001491047" + }, + { + "token": "0x036CbD53842c5426634e7929541eC2318f3dCF7e", + "fee": 500, + "pool": "0x94bfc0574FF48E92cE43d495376C477B1d0EEeC0", + "liquidity": "5303698200342" + }, + { + "token": "0x036CbD53842c5426634e7929541eC2318f3dCF7e", + "fee": 3000, + "pool": "0x46880b404CD35c165EDdefF7421019F8dD25F4Ad", + "liquidity": "315598590516394" + }, + { + "token": "0x036CbD53842c5426634e7929541eC2318f3dCF7e", + "fee": 10000, + "pool": "0x4664755562152EDDa3a3073850FB62835451926a", + "liquidity": "57734017049" + }, + { + "token": "0xba50Cd2A20f6DA35D788639E581bca8d0B5d4D5f", + "fee": 100, + "pool": "0x068e0DF9DFcCe57df2C2b60BdB2318CE49A07a31", + "liquidity": "8639839568058" + }, + { + "token": "0xba50Cd2A20f6DA35D788639E581bca8d0B5d4D5f", + "fee": 500, + "pool": "0x9d9203f8a29c600D567b240692DB569B77D1F4A9", + "liquidity": "0" + }, + { + "token": "0xba50Cd2A20f6DA35D788639E581bca8d0B5d4D5f", + "fee": 3000, + "pool": "0x92266210FacF124f190fbad79AA230dfB85926Ce", + "liquidity": "4957986963561" + }, + { + "token": "0xba50Cd2A20f6DA35D788639E581bca8d0B5d4D5f", + "fee": 10000, + "pool": "0xC8AaD20fA4278886e64d279Fe39B1E7a2d6E10E8", + "liquidity": "0" + } + ], + "mints": [ + { + "token": "0x810D46F9a9027E28F9B01F75E2bdde839dA61115", + "owner": "0xD9145b5F45Ad4519c7ACcD6E0A4A82e83bB8A6Dc", + "mint(address,uint256)": "The contract function \"mint\" reverted with the following reason:\nOwnable: caller is not the owner", + "mint(uint256)": "The contract function \"mint\" reverted with the following reason:\nOwnable: caller is not the owner", + "allocateTo(address,uint256)": "The contract function \"allocateTo\" reverted.", + "faucet": "ok", + "supply": "The contract function \"supply\" reverted with the following reason:\nERC20: transfer amount exceeds balance" + }, + { + "token": "0x4616975f7E6045FD9737e95bC527e9e14c727BD2", + "mint(address,uint256)": "The contract function \"mint\" reverted.", + "mint(uint256)": "The contract function \"mint\" reverted.", + "allocateTo(address,uint256)": "ok", + "supply": "The contract function \"supply\" reverted." + }, + { + "token": "0x663A6F02d547dFd639BF689FED298712f2FB69Fb", + "mint(address,uint256)": "ok", + "mint(uint256)": "The contract function \"mint\" reverted.", + "allocateTo(address,uint256)": "The contract function \"allocateTo\" reverted.", + "supply": "The contract function \"supply\" reverted." + } + ] + }, + { + "chain": 421614, + "actualChain": 421614, + "observedStartBlock": "319278801", + "wrapped": "0x980B62Da83eFf3D4576C647993b0c1D7faf17c73", + "pools": [ + { + "token": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "fee": 100, + "pool": "0x152c469626C706E201721F13eb470691E4E81c5D", + "liquidity": "0" + }, + { + "token": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "fee": 500, + "pool": "0x6F112d524DC998381C09b4e53C7e5e2cc260f877", + "liquidity": "122" + }, + { + "token": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "fee": 3000, + "pool": "0x66EEAB70aC52459Dd74C6AD50D578Ef76a441bbf", + "liquidity": "40704947517717" + }, + { + "token": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "fee": 10000, + "pool": "0x3eCedaB7E9479E29B694d8590dc34e0Ce6059868", + "liquidity": "3225673603183" + } + ], + "mints": [ + { + "token": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "owner": "0xaB7Dbf0Fc9d32349c484419073098DcD52C14798", + "mint(address,uint256)": "The contract function \"mint\" reverted with the following reason:\nFiatToken: caller is not a minter", + "mint(uint256)": "The contract function \"mint\" reverted.", + "allocateTo(address,uint256)": "The contract function \"allocateTo\" reverted.", + "faucet": "ok", + "supply": "The contract function \"supply\" reverted with the following reason:\nERC20: transfer amount exceeds allowance" + }, + { + "token": "0x1dF462e2712496373A347f8ad10802a5E95f053D", + "mint(address,uint256)": "The contract function \"mint\" reverted.", + "mint(uint256)": "The contract function \"mint\" reverted.", + "allocateTo(address,uint256)": "The contract function \"allocateTo\" reverted.", + "supply": "The contract function \"supply\" reverted." + } + ] + }, + { + "chain": 97, + "actualChain": 97, + "observedStartBlock": "136853649", + "wrapped": "0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd", + "pools": [ + { + "token": "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", + "fee": 100, + "pool": "0xCed0844e421F856D2de472F9e7037f873987887C", + "liquidity": "229529662705916" + }, + { + "token": "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", + "fee": 500, + "pool": "0xc2F0629Dd29AB0EcfF7476560bc8FD5c0c4D19Cd", + "liquidity": "0" + }, + { + "token": "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", + "fee": 3000, + "pool": "0x0000000000000000000000000000000000000000", + "liquidity": "0" + }, + { + "token": "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", + "fee": 10000, + "pool": "0xa5316a3418e0643BB977A97689E584a3b6c35080", + "liquidity": "0" + }, + { + "token": "0x16227D60f7a0e586C66B005219dfc887D13C9531", + "fee": 100, + "pool": "0x0000000000000000000000000000000000000000", + "liquidity": "0" + }, + { + "token": "0x16227D60f7a0e586C66B005219dfc887D13C9531", + "fee": 500, + "pool": "0x0000000000000000000000000000000000000000", + "liquidity": "0" + }, + { + "token": "0x16227D60f7a0e586C66B005219dfc887D13C9531", + "fee": 3000, + "pool": "0x0000000000000000000000000000000000000000", + "liquidity": "0" + }, + { + "token": "0x16227D60f7a0e586C66B005219dfc887D13C9531", + "fee": 10000, + "pool": "0x0000000000000000000000000000000000000000", + "liquidity": "0" + } + ], + "mints": [ + { + "token": "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", + "mint(address,uint256)": "The contract function \"mint\" reverted.", + "mint(uint256)": "The contract function \"mint\" reverted.", + "allocateTo(address,uint256)": "ok" + }, + { + "token": "0x16227D60f7a0e586C66B005219dfc887D13C9531", + "mint(address,uint256)": "The contract function \"mint\" reverted.", + "mint(uint256)": "The contract function \"mint\" reverted.", + "allocateTo(address,uint256)": "ok" + } + ] + } +] diff --git a/plan/agw/research/preset-expanded-live-2026-10-15/probe.cjs b/plan/agw/research/preset-expanded-live-2026-10-15/probe.cjs new file mode 100644 index 00000000..d1166673 --- /dev/null +++ b/plan/agw/research/preset-expanded-live-2026-10-15/probe.cjs @@ -0,0 +1,9 @@ +// Read-only prerequisites. Run from repository root; never loads signer keys. +const {createPublicClient,http,parseAbi,erc20Abi}=require(process.cwd()+'/node_modules/viem');const fs=require('fs'); +const dummy='0x0000000000000000000000000000000000001234'; +const configs=[ +{chain:84532,rpc:'https://base-sepolia-rpc.publicnode.com',factory:'0x4752ba5DBc23f44D87826276BF6Fd6b1C372aD24',router:'0x94cC0AaC535CCDB3C01d6787D6413C739ae12bc4',tokens:['0x036CbD53842c5426634e7929541eC2318f3dCF7e','0xba50Cd2A20f6DA35D788639E581bca8d0B5d4D5f'],mintTokens:['0x810D46F9a9027E28F9B01F75E2bdde839dA61115','0x4616975f7E6045FD9737e95bC527e9e14c727BD2','0x663A6F02d547dFd639BF689FED298712f2FB69Fb'],aave:'0x8bAB6d1b75f19e9eD9fCe8b9BD338844fF79aE27'}, +{chain:421614,rpc:'https://arbitrum-sepolia-rpc.publicnode.com',factory:'0x248AB79Bbb9bC29bB72f7Cd42F17e054Fc40188e',router:'0x101F443B4d1b059569D643917553c771E1b9663E',tokens:['0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d'],mintTokens:['0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d','0x1dF462e2712496373A347f8ad10802a5E95f053D'],aave:'0xBfC91D59fdAA134A4ED45f7B584cAf96D7792Eff'}, +{chain:97,rpc:'https://bsc-testnet-rpc.publicnode.com',factory:'0x0BFbCF9fa4f9C56B0F40a671Ad40E0805A091865',router:'0x9a489505a00cE272eAa5e07Dba6491314CaE3796',tokens:['0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c','0x16227D60f7a0e586C66B005219dfc887D13C9531'],mintTokens:['0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c','0x16227D60f7a0e586C66B005219dfc887D13C9531']}, +]; +(async()=>{const results=await Promise.all(configs.map(async cfg=>{try{const c=createPublicClient({transport:http(cfg.rpc,{timeout:20000,retryCount:1})});const block=await c.getBlockNumber();const read=(address,sig,fn,args=[])=>c.readContract({address,abi:parseAbi([sig]),functionName:fn,args});const simulate=async(address,sig,fn,args,value)=>{try{await c.simulateContract({address,abi:parseAbi([sig]),functionName:fn,args,account:dummy,value});return 'ok';}catch(e){return e.shortMessage||e.message;}};const wrapped=await read(cfg.router,'function WETH9() view returns(address)','WETH9');const pools=[];for(const token of cfg.tokens)for(const fee of [100,500,3000,10000]){try{const pool=await read(cfg.factory,'function getPool(address,address,uint24) view returns(address)','getPool',[wrapped,token,fee]);let liquidity='0';if(!/^0x0+$/.test(pool))liquidity=String(await read(pool,'function liquidity() view returns(uint128)','liquidity'));pools.push({token,fee,pool,liquidity});}catch(e){pools.push({token,fee,error:e.shortMessage||e.message});}}const mints=[];for(const token of cfg.mintTokens){let owner;try{owner=await read(token,'function owner() view returns(address)','owner');}catch{}const r={token,owner};for(const [sig,args]of [['mint(address,uint256)',[dummy,1000000n]],['mint(uint256)',[1000000n]],['allocateTo(address,uint256)',[dummy,1000000n]]])r[sig]=await simulate(token,'function '+sig,sig.split('(')[0],args);if(owner&&!/^0x0+$/.test(owner))r.faucet=await simulate(owner,'function mint(address,address,uint256)','mint',[token,dummy,1000000n]);if(cfg.aave)r.supply=await simulate(cfg.aave,'function supply(address,uint256,address,uint16)','supply',[token,1000000n,dummy,0]);mints.push(r);}return {chain:cfg.chain,actualChain:await c.getChainId(),observedStartBlock:String(block),wrapped,pools,mints};}catch(e){return {chain:cfg.chain,error:e.shortMessage||e.message};}}));fs.writeFileSync('plan/agw/research/preset-expanded-live-2026-10-15/prerequisites.json',JSON.stringify(results,null,2)+'\n');console.log(JSON.stringify(results,null,2));})().catch(e=>{console.error(e.shortMessage||e.message);process.exitCode=1;}); diff --git a/plan/agw/research/preset-expanded-live-2026-10-15/redemptions.json b/plan/agw/research/preset-expanded-live-2026-10-15/redemptions.json new file mode 100644 index 00000000..531464aa --- /dev/null +++ b/plan/agw/research/preset-expanded-live-2026-10-15/redemptions.json @@ -0,0 +1,47 @@ +[ + { + "chain": "eip155:97", + "rpc": "https://bsc-testnet-rpc.publicnode.com", + "wallet": "0xce76840d3ee4579217D5F2de1d3767b7EAe54605", + "cea": "0x3c0a4e2f349059D5d1309d0f57871b1b9a4E1192", + "expectedShares": "16740010", + "stage": "venus-redeem-completed", + "market": "0xb7526572FFE56AB9D7489838Bf2E18e3323b441A", + "underlying": "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", + "tx": "0xc7ab68b6f72171c83a2ec5cce9c3a0df66a53be60e3f46e9a2d4a6c49f25c4e0", + "block": "136855138", + "redeemAmount": "3360", + "redeemedShares": "16740010", + "remainingShares": "0" + }, + { + "chain": "eip155:84532", + "rpc": "https://base-sepolia-rpc.publicnode.com", + "wallet": "0xF3445c8d5557Fab0519dA9c75eaB2B995F42B32f", + "cea": "0xe37A1890878CEF71210Be37fae802e234E55eD44", + "expectedShares": "49999832", + "stage": "lending-withdraw-completed", + "market": "0x876852425331a113d8E432eFFB3aC5BEf38f033a", + "underlying": "0x4616975f7E6045FD9737e95bC527e9e14c727BD2", + "tx": "0x1bc2a2e5849d3e61c7e7927360c6f7936d0399a8c27cc2f988f6f4e54256366e", + "block": "48131861", + "redeemAmount": "9999", + "redeemedShares": "49999832", + "remainingShares": "0" + }, + { + "chain": "eip155:84532", + "rpc": "https://base-sepolia-rpc.publicnode.com", + "wallet": "0xF3445c8d5557Fab0519dA9c75eaB2B995F42B32f", + "cea": "0xe37A1890878CEF71210Be37fae802e234E55eD44", + "expectedShares": "2945", + "stage": "lending-withdraw-completed", + "market": "0x2F39a349A79492a70E152760ce7123A1933eCf28", + "underlying": "0x663A6F02d547dFd639BF689FED298712f2FB69Fb", + "tx": "0x1bc2a2e5849d3e61c7e7927360c6f7936d0399a8c27cc2f988f6f4e54256366e", + "block": "48131861", + "redeemAmount": "999943876358", + "redeemedShares": "2945", + "remainingShares": "0" + } +] diff --git a/plan/agw/research/preset-expanded-live-2026-10-15/runtime-lint.log b/plan/agw/research/preset-expanded-live-2026-10-15/runtime-lint.log new file mode 100644 index 00000000..e69de29b diff --git a/plan/agw/research/preset-expanded-live-2026-10-15/runtime-regression-before.log b/plan/agw/research/preset-expanded-live-2026-10-15/runtime-regression-before.log new file mode 100644 index 00000000..e4eba1e8 --- /dev/null +++ b/plan/agw/research/preset-expanded-live-2026-10-15/runtime-regression-before.log @@ -0,0 +1,62 @@ +FAIL core packages/core/src/lib/agentic/__tests__/runtime-token-chain.spec.ts + ✓ resolves explicit native ETH on eip155:11155111 to the same burn token as omitted native funds (1 ms) + ✕ resolves explicit native ETH on eip155:84532 to the same burn token as omitted native funds (2 ms) + ✕ resolves explicit native ETH on eip155:421614 to the same burn token as omitted native funds + ✕ does not infer a token from a different destination chain + ✓ preserves an explicit Push PRC20 reference for subsequent source-chain validation + + ● resolves explicit native ETH on eip155:84532 to the same burn token as omitted native funds + + expect(received).toBe(expected) // Object.is equality + + Expected: "0xc7007af2B24D4eb963fc9633B0c66e1d2D90Fc21" + Received: "0x2971824Db68229D087931155C2b8bB820B275809" + + 16 | ] as const)('resolves explicit native ETH on %s to the same burn token as omitted native funds', (chain, token, expected) => { + 17 | const rt = runtime(); + > 18 | expect(rt.resolvePrc20(token, chain)).toBe(getAddress(expected)); + | ^ + 19 | expect(rt.resolvePrc20({ ...token }, chain)).toBe(rt.resolvePrc20(undefined, chain)); + 20 | expect(rt.resolvePrc20(token.address, chain)).toBe(getAddress(expected)); + 21 | }); + + at src/lib/agentic/__tests__/runtime-token-chain.spec.ts:18:41 + + ● resolves explicit native ETH on eip155:421614 to the same burn token as omitted native funds + + expect(received).toBe(expected) // Object.is equality + + Expected: "0xc0a821a1AfEd1322c5e15f1F4586C0B8cE65400e" + Received: "0x2971824Db68229D087931155C2b8bB820B275809" + + 16 | ] as const)('resolves explicit native ETH on %s to the same burn token as omitted native funds', (chain, token, expected) => { + 17 | const rt = runtime(); + > 18 | expect(rt.resolvePrc20(token, chain)).toBe(getAddress(expected)); + | ^ + 19 | expect(rt.resolvePrc20({ ...token }, chain)).toBe(rt.resolvePrc20(undefined, chain)); + 20 | expect(rt.resolvePrc20(token.address, chain)).toBe(getAddress(expected)); + 21 | }); + + at src/lib/agentic/__tests__/runtime-token-chain.spec.ts:18:41 + + ● does not infer a token from a different destination chain + + expect(received).toThrow() + + Received function did not throw + + 21 | }); + 22 | it('does not infer a token from a different destination chain', () => { + > 23 | expect(() => runtime().resolvePrc20(MOVEABLE_TOKEN_CONSTANTS.BASE_SEPOLIA.USDC, CHAIN.ARBITRUM_SEPOLIA)).toThrow(); + | ^ + 24 | }); + 25 | it('preserves an explicit Push PRC20 reference for subsequent source-chain validation', () => { + 26 | const token: PushChainMoveableToken = { symbol: 'pETH_ARB', decimals: 18, mechanism: 'approve', address: addresses.pETH_ARB, prc20Address: addresses.pETH_ARB, sourceChain: CHAIN.ARBITRUM_SEPOLIA }; + + at Object. (src/lib/agentic/__tests__/runtime-token-chain.spec.ts:23:108) + +Test Suites: 1 failed, 1 total +Tests: 3 failed, 2 passed, 5 total +Snapshots: 0 total +Time: 2.386 s +Ran all test suites within paths "packages/core/src/lib/agentic/__tests__/runtime-token-chain.spec.ts". diff --git a/plan/agw/research/preset-expanded-live-2026-10-15/runtime-regression-focused.log b/plan/agw/research/preset-expanded-live-2026-10-15/runtime-regression-focused.log new file mode 100644 index 00000000..a00fe23c --- /dev/null +++ b/plan/agw/research/preset-expanded-live-2026-10-15/runtime-regression-focused.log @@ -0,0 +1,10 @@ +PASS core packages/core/src/lib/agentic/__tests__/runtime-token-chain.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/send.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/public-rule.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-quote.spec.ts + +Test Suites: 4 passed, 4 total +Tests: 64 passed, 64 total +Snapshots: 0 total +Time: 4.339 s +Ran all test suites within paths "packages/core/src/lib/agentic/__tests__/runtime-token-chain.spec.ts", "packages/core/src/lib/agentic/__tests__/send.spec.ts", "packages/core/src/lib/agentic/__tests__/public-rule.spec.ts", "packages/core/src/lib/agentic/__tests__/svm-quote.spec.ts". diff --git a/plan/agw/research/preset-expanded-live-2026-10-15/scenario-selection.log b/plan/agw/research/preset-expanded-live-2026-10-15/scenario-selection.log new file mode 100644 index 00000000..caa0c9ed --- /dev/null +++ b/plan/agw/research/preset-expanded-live-2026-10-15/scenario-selection.log @@ -0,0 +1,8 @@ +✓ agw-preset-eigen-sepolia 1 test +✓ agw-preset-dex-base 1 test +✓ agw-preset-dex-aave-arbitrum 1 test +✓ agw-preset-dex-venus-bnb 1 test +✓ agw-preset-base-aave-moonwell 1 test + +5 scenarios, 1 spec files, 5 distinct tests. +Manifest is consistent with the specs. diff --git a/plan/agw/research/preset-expanded-live-2026-10-15/unit.log b/plan/agw/research/preset-expanded-live-2026-10-15/unit.log new file mode 100644 index 00000000..59e2c577 --- /dev/null +++ b/plan/agw/research/preset-expanded-live-2026-10-15/unit.log @@ -0,0 +1,178 @@ +PASS core packages/core/src/lib/agentic/__tests__/runtime-token-chain.spec.ts +PASS core packages/core/src/lib/universal/account/account.spec.ts + ● Console + + console.warn + [PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead. + + 207 | ): Promise { + 208 | if (!_convertOriginToExecutorWarned) { + > 209 | console.warn( + | ^ + 210 | '[PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead.' + 211 | ); + 212 | _convertOriginToExecutorWarned = true; + + at Object.convertOriginToExecutor (src/lib/universal/account/account.ts:209:13) + at Object. (src/lib/universal/account/account.spec.ts:80:52) + + console.warn + [PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead. + + 425 | ): Promise { + 426 | if (!options?._internal && !_convertExecutorToOriginWarned) { + > 427 | console.warn( + | ^ + 428 | '[PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead.' + 429 | ); + 430 | _convertExecutorToOriginWarned = true; + + at convertExecutorToOrigin (src/lib/universal/account/account.ts:427:13) + at Object. (src/lib/universal/account/account.spec.ts:106:38) + +PASS core packages/core/src/lib/read-state/__tests__/block-results-client.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-tx-retry.spec.ts +PASS core packages/core/src/lib/push-client/push-client.archive-fallback.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-confirmation-gate.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/send.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/resolve.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-timeout-clamp.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/svm-rent.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r2-outbound-revert-flow.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/public-rule.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/context-helpers-tracker.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-svm-confirmation.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-quote.spec.ts +PASS core packages/core/src/lib/universal/signer/signer.spec.ts +PASS core packages/core/src/lib/utils.spec.ts + ● Console + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:973:17) + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:977:17) + + console.log + 1.23 + + at Object. (src/lib/utils.spec.ts:982:17) + +PASS core packages/core/src/lib/orchestrator/__tests__/inbound-tracker-derivation.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-calculator.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-builder-progress-hook.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/signing-payload.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/labels.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/source-hash-resolution.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/resolver.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/track-transaction-guard.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/execute-standard-required-funds.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/cascade.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-svm-r3.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/terminal-suppression.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-detector.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-tracker.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gateway-uea-account.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/response-surface.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/management.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/response-invariant.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-native-multicall.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/account-status.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/abi-selectors.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-executor.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-composition.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-backend.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/address-codec.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/web2-compat.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r2-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/rescue-svm-confirmation.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/read-tx-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-classification.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/scenarios.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/payload-builders.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/public-surface.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-svm-rent.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-idl.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-usd-sizer.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/chain-namespace.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r3-spec-strings.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-event-hook-bridge.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/registry.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-emission.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/export.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/build-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/funds-only-burn-guard.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/send-transaction-progress-hook.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/gate.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/multichain-hooks.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/inbound-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-error-classification.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r1-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-multichain.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-evm-r3-native-eoa.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/response-builder-push-revert.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-request-recipient.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm-rent-pc20.spec.ts +PASS core packages/core/src/lib/push-client/push-client.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/preset-catalog.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/svm-account.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/reads-context.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/native-multi-action.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/spec-builder.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-params.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-evm.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-wire-fixture.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/revalidate-read.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-svm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/result-decoder.spec.ts +PASS core packages/core/src/lib/constants/__tests__/token-constants.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm-log-index.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/presets.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/child-inbounds.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/__tests__/signing.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/normalize.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.chain-symbol.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/auto-detect.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/codec.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg-svm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/ucallback-codec.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/validate.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-events.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-web2.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.dynamic-gas.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.batch-gas.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-types.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/registry.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/ix-encoder.spec.ts +PASS core packages/core/src/lib/constants/__tests__/svm-gateway-idl.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/normalize-address.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/budget.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/classify.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/errors.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/tracking.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/max-pc-for-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/error-decoder.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-execute-order.spec.ts +PASS core packages/core/src/lib/formatters.spec.ts + +Test Suites: 1 skipped, 125 passed, 125 of 126 total +Tests: 12 skipped, 2101 passed, 2113 total +Snapshots: 0 total +Time: 29.698 s +Ran all test suites. diff --git a/plan/agw/research/preset-live-2026-10-15/README.md b/plan/agw/research/preset-live-2026-10-15/README.md index a1a5fc64..3604eecf 100644 --- a/plan/agw/research/preset-live-2026-10-15/README.md +++ b/plan/agw/research/preset-live-2026-10-15/README.md @@ -37,4 +37,4 @@ Root validation: full unit suite 2,096 passed / 12 skipped; build, library/spec ## Remaining coverage -Real trades/deposits on Base, Arbitrum and BNB and EigenLayer staking are not established by these Sepolia results. Mainnet templates have official-source and read-only code checks only. Unsupported/unverified proposal entries are documented in the mainnet catalog review. No external protocol address was deployed or changed by this work. +These original Sepolia results do not establish other-chain coverage. A subsequent [expanded run](../preset-expanded-live-2026-10-15/README.md) now establishes Base/Arbitrum Uniswap, BNB PancakeSwap/Venus, Base/Arbitrum Aave, Base Moonwell and Sepolia EigenLayer flows. Mainnet templates have official-source and read-only code checks only. Unsupported/unverified proposal entries are documented in the mainnet catalog review. No external protocol address was deployed or changed by this work. diff --git a/plan/agw/section7-presets.md b/plan/agw/section7-presets.md index 94d9c605..a506b148 100644 --- a/plan/agw/section7-presets.md +++ b/plan/agw/section7-presets.md @@ -24,3 +24,8 @@ Enumerable DEXES/LENDING/STAKING/PREDICTION constants; list/get only; one rule p ## Validation Latest full unit run: 2,096 passed, 12 skipped, zero failures. Focused preset tests: 44 passed. The zero-cap review flow passed 16 local real-v6 contract tests. Test selection includes two separate opt-in agw-presets scenarios (Uniswap and Aave), and leaves the default all group unchanged. Uniswap and Aave LINK live scenarios passed in separate runs; Aave USDC hit its protocol supply cap before the LINK correction. [Live results and transaction evidence](research/preset-live-2026-10-15/README.md). + + +## Expanded live acceptance (October 15) + +Five additional scenarios now pass across focused runs: EigenLayer Sepolia; Base Uniswap; Arbitrum Uniswap/Aave; BNB PancakeSwap/Venus; Base Aave/Moonwell. Combined with the earlier Sepolia runs, every shipped testnet protocol/chain combination has at least one positive live flow. The runs found and fixed destination-aware native ETH PRC20 resolution. Borrow/repay, every market and mainnet execution are not claimed. [Evidence and exact limits](research/preset-expanded-live-2026-10-15/README.md). From 11f29ae923298657d87647021e06294642444264 Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Thu, 15 Oct 2026 08:45:38 +0530 Subject: [PATCH 45/68] fix(release): refresh and commit lockfile after version bumps --- scripts/release-automated.sh | 8 ++++++-- scripts/release.sh | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/scripts/release-automated.sh b/scripts/release-automated.sh index 04b4476c..187a4dba 100755 --- a/scripts/release-automated.sh +++ b/scripts/release-automated.sh @@ -44,6 +44,10 @@ else npx ts-node scripts/bumpAndGenerateChangelog.ts "$SCOPE" "$BUMP" fi +# Version bumps can change workspace semver matching (especially stable -> alpha). +# Refresh the lockfile deliberately; the workflow's initial install stays immutable. +YARN_ENABLE_IMMUTABLE_INSTALLS=false yarn install --mode=update-lockfile + # Step 2: Build the package npx nx run "$SCOPE:build" @@ -68,8 +72,8 @@ else npm publish "$PACKAGE_DIR" --access public fi -# Step 5: Commit version + changelog -git add "packages/$SCOPE/package.json" "packages/$SCOPE/CHANGELOG.md" +# Step 5: Commit version + changelog + lockfile +git add "packages/$SCOPE/package.json" "packages/$SCOPE/CHANGELOG.md" yarn.lock git commit -m "release($SCOPE): bump to $VERSION [skip ci]" # Step 6: Git tag + push diff --git a/scripts/release.sh b/scripts/release.sh index f1f9fb07..56fa8045 100644 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -36,6 +36,10 @@ echo "🚀 Releasing @$SCOPE with a $BUMP bump..." # Step 1: Bump version and generate changelog markdown ts-node scripts/bumpAndGenerateChangelog.ts "$SCOPE" "$BUMP" +# Version bumps can change workspace semver matching (especially stable -> alpha). +# Refresh the lockfile deliberately; the workflow's initial install stays immutable. +YARN_ENABLE_IMMUTABLE_INSTALLS=false yarn install --mode=update-lockfile + # Step 2: Build the package nx run "$SCOPE:build" @@ -46,8 +50,8 @@ VERSION=$(node -p "require('./packages/$SCOPE/package.json').version") npm publish "$PACKAGE_DIR" --access public --otp="$OTP" -# Step 4: Commit version + changelog -git add "packages/$SCOPE/package.json" "packages/$SCOPE/CHANGELOG.md" +# Step 4: Commit version + changelog + lockfile +git add "packages/$SCOPE/package.json" "packages/$SCOPE/CHANGELOG.md" yarn.lock git commit -m "release($SCOPE): bump to $VERSION" # Step 5: Git tag + push From a77a104b2a9c6d8477851d3b4cb83b8daf542d14 Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Thu, 15 Oct 2026 08:45:44 +0530 Subject: [PATCH 46/68] docs(agw): record publish lockfile failure and validation --- .../release-lockfile-2026-10-15/README.md | 20 ++++++++++++++++ .../immutable-install.log | 23 +++++++++++++++++++ .../release-regression.log | 5 ++++ 3 files changed, 48 insertions(+) create mode 100644 plan/agw/research/release-lockfile-2026-10-15/README.md create mode 100644 plan/agw/research/release-lockfile-2026-10-15/immutable-install.log create mode 100644 plan/agw/research/release-lockfile-2026-10-15/release-regression.log diff --git a/plan/agw/research/release-lockfile-2026-10-15/README.md b/plan/agw/research/release-lockfile-2026-10-15/README.md new file mode 100644 index 00000000..55418a42 --- /dev/null +++ b/plan/agw/research/release-lockfile-2026-10-15/README.md @@ -0,0 +1,20 @@ +# Publish dependency-install correction — October 15, 2026 + +Failed job: https://github.com/pushchain/push-chain-sdk/actions/runs/38673825795/job/116222785501, at feat/agw-sdk-v5@574a4002. + +The install failed with YN0028. Release commit 6eafa004 changed core 6.0.26 to 6.0.27-alpha.0 without refreshing yarn.lock. UI kit's ^6.0.26 no longer matches the local prerelease. Yarn needs a separate npm 6.0.26 resolution alongside the workspace entry; immutable installation correctly rejected the stale combined entry. + +## Changes + +- Regenerated v5 yarn.lock using pinned Yarn 4.2.2, install --mode=update-lockfile. Exactly one entry split; existing workspace/package versions preserved. +- Both release scripts now deliberately refresh the lockfile after version bumps, before building/publishing, and stage yarn.lock in their release commit. +- The workflow's initial immutable check stays enabled. No workflow dispatch or real package publication was performed. +- V4 stays on core 6.0.26, so its existing lockfile remains correct. The lockfiles intentionally differ between branches, just like the existing release version/changelog. + +## Validation + +- Bash syntax checks passed for both scripts. +- A copy of v5's root and workspace manifests, lockfile and Yarn configuration passed install --immutable --mode=skip-build in a temporary node-modules workspace. Lifecycle scripts were disabled and no existing workspace node_modules was changed. Local Node 20.19.2/Yarn 4.2.2; CI uses Node 24.18.0/Yarn 4.2.2. +- An isolated miniature workspace reproduced YN0028 with the original automated release script on stable-to-alpha transition. +- The corrected automated script passed stable-to-alpha and alpha-to-alpha transitions. The fixture used real Yarn/semver and verified immutable consistency at the simulated publish boundary and yarn.lock staging. npm publish and every git operation were intercepted; no real package, tag or push was produced by the test. +- The scripts' real publish commands were not executed. The user will trigger the action. diff --git a/plan/agw/research/release-lockfile-2026-10-15/immutable-install.log b/plan/agw/research/release-lockfile-2026-10-15/immutable-install.log new file mode 100644 index 00000000..709b14bb --- /dev/null +++ b/plan/agw/research/release-lockfile-2026-10-15/immutable-install.log @@ -0,0 +1,23 @@ +➤ YN0000: · Yarn 4.2.2 +➤ YN0000: ┌ Project validation +➤ YN0057: │ @pushprotocol/common-components: Resolutions field will be ignored +➤ YN0057: │ @pushchain/ui-kit: Resolutions field will be ignored +➤ YN0000: └ Completed +➤ YN0000: ┌ Resolution step +➤ YN0000: └ Completed +➤ YN0000: ┌ Post-resolution validation +➤ YN0002: │ @pushchain/core@workspace:packages/core doesn't provide @types/node (p360d1), requested by ts-node. +➤ YN0002: │ @pushchain/core@workspace:packages/core doesn't provide typescript (p97602), requested by ts-node. +➤ YN0002: │ @pushchain/ui-kit@workspace:packages/ui-kit doesn't provide eslint (p05da2), requested by typescript-eslint. +➤ YN0002: │ @pushchain/ui-kit@workspace:packages/ui-kit doesn't provide eslint (p7d515), requested by eslint-plugin-react-refresh. +➤ YN0002: │ @pushchain/ui-kit@workspace:packages/ui-kit doesn't provide eslint (pafac7), requested by eslint-plugin-react-hooks. +➤ YN0002: │ @pushchain/ui-kit@workspace:packages/ui-kit doesn't provide typescript (pc5a0d), requested by typescript-eslint. +➤ YN0002: │ @pushprotocol/common-components@workspace:packages/shared-components doesn't provide react-is (p3a3ff), requested by styled-components. +➤ YN0086: │ Some peer dependencies are incorrectly met; run yarn explain peer-requirements for details, where is the six-letter p-prefixed code. +➤ YN0000: └ Completed +➤ YN0000: ┌ Fetch step +➤ YN0013: │ A package was added to the project (+ 605.19 KiB). +➤ YN0000: └ Completed in 0s 201ms +➤ YN0000: ┌ Link step +➤ YN0000: └ Completed in 9s 392ms +➤ YN0000: · Done with warnings in 9s 857ms diff --git a/plan/agw/research/release-lockfile-2026-10-15/release-regression.log b/plan/agw/research/release-lockfile-2026-10-15/release-regression.log new file mode 100644 index 00000000..855b07dd --- /dev/null +++ b/plan/agw/research/release-lockfile-2026-10-15/release-regression.log @@ -0,0 +1,5 @@ +Original script: reproduced YN0028 after stable-to-alpha bump +Fixed script: 7.0.1-alpha.0 immutable install passed; lock included in release commit +Fixed script: 7.0.1-alpha.1 immutable install passed; lock included in release commit +No publish/tag/push occurred: npm and git were intercepted in isolated fixtures +Fixture logs: /var/folders/4_/d47r2_4s1wb3x2dvmt2ghp800000gp/T/release-lock-regression-9io04tzg From 89d043863438e6dd12435d7198d01bef2fd5a571 Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Fri, 16 Oct 2026 19:42:26 +0530 Subject: [PATCH 47/68] feat(core): add bounded preset operations and configuration readiness --- packages/core/AGW.md | 61 ++++- .../core/__agw-local__/v5-multiasset.spec.ts | 123 +++++++++- .../__e2e__/agw/presets-expanded-live.spec.ts | 97 ++++++-- .../core/__e2e__/agw/presets-live.spec.ts | 116 +++++++-- .../agentic/__tests__/preset-catalog.spec.ts | 43 ++-- .../__tests__/preset-operation-limits.spec.ts | 220 ++++++++++++++++++ .../src/lib/agentic/__tests__/presets.spec.ts | 5 +- packages/core/src/lib/agentic/index.ts | 4 + .../src/lib/agentic/presets/aave-reserves.ts | 146 ++++++++++++ .../core/src/lib/agentic/presets/catalog.ts | 129 ++++++++-- .../core/src/lib/agentic/presets/index.ts | 111 ++++++++- .../lib/agentic/presets/operation-limits.ts | 116 +++++++++ .../core/src/lib/agentic/presets/types.ts | 62 ++++- packages/core/src/lib/index.ts | 4 + 14 files changed, 1147 insertions(+), 90 deletions(-) create mode 100644 packages/core/src/lib/agentic/__tests__/preset-operation-limits.spec.ts create mode 100644 packages/core/src/lib/agentic/presets/aave-reserves.ts create mode 100644 packages/core/src/lib/agentic/presets/operation-limits.ts diff --git a/packages/core/AGW.md b/packages/core/AGW.md index 2873ebfe..7d5b71be 100644 --- a/packages/core/AGW.md +++ b/packages/core/AGW.md @@ -91,7 +91,7 @@ An equality pin fixes an argument; a maximum pin bounds it. For EVM signatures, `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. -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. +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. ## EVM destinations @@ -171,7 +171,7 @@ The wire encoder uses uint32 maximum for unlimited native calls and 255 for unsp - DEXES: Uniswap V3 on Ethereum, Base and Arbitrum (mainnet and their Sepolia testnets); PancakeSwap V3 on BNB mainnet and BSC testnet. - 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. -- STAKING: EigenLayer deposits on Ethereum mainnet and Sepolia (EigenLayer withdrawals excluded); Lido stake, wrap/unwrap and withdrawal requests/claims on Ethereum mainnet. Lido ETH staking defaults to `maxValue: 0`; explicitly set a value cap before use. +- 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. - PREDICTION: no entries yet. Hide categories with empty `chains` lists. ```ts @@ -195,11 +195,11 @@ function filledPreset(agent: Address, tokenIn: Address, tokenOut: Address) { { token: tokenOut, maxPerCall: BigInt(100), maxTotal: BigInt(1000) }, ], }, - ).rules; + ); } ``` -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. 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. Omitted asset caps and `maxGasPerCall` default to zero. +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. 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. @@ -209,6 +209,59 @@ Reviewed EVM spenders generate approvals pinned to that spender and bounded by t 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. +### Configure, inspect and regenerate + +`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. + +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. + +```ts +async function createConfiguredDex( + client: PushChain, agent: Address, tokenIn: Address, tokenOut: Address, +) { + const configured = filledPreset(agent, tokenIn, tokenOut); + if (!configured.readiness.ready) { + // Render these issues in the configuration screen; do not present it as ready. + return { issues: configured.readiness.chains }; + } + return client.agentic.create('My DEX agent', { rules: configured.rules }); +} + +async function replaceConfiguredDex( + client: PushChain, wallet: Address, rulesId: Hex, + agent: Address, tokenIn: Address, tokenOut: Address, +) { + // Re-run get after editing tokens or limits. Changing rule.assets alone + // does not regenerate allowedCalls, token pins or approvals. + const configured = filledPreset(agent, tokenIn, tokenOut); + if (!configured.readiness.ready) throw new Error('Complete the preset inputs'); + return client.agentic.wallet(wallet).rules.update({ + rules: [{ rulesId, rule: configured.rules[0] }], + }); +} +``` + +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. + +### Amount units and enforcement scope + +| Preset operation | Generated restriction | +| --- | --- | +| DEX swap | Selected input/output token equality, wallet recipient, maximum input amount | +| Aave supply/withdraw/borrow/repay | Listed reserve token equality, wallet beneficiary, amount maximum | +| Moonwell/Venus mint/redeemUnderlying/borrow/repayBorrow | Maximum in the market's underlying-token units | +| EigenLayer deposit | Selected token equality and deposit amount maximum | +| Lido wrap/unwrap | stETH/wstETH input limits respectively; their units are not interchangeable | +| Lido submit | Native-value cap from the selected native asset's maxPerCall | + +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. + +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. + +**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. + +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. + ## Validation 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. diff --git a/packages/core/__agw-local__/v5-multiasset.spec.ts b/packages/core/__agw-local__/v5-multiasset.spec.ts index 57290f61..ba06384a 100644 --- a/packages/core/__agw-local__/v5-multiasset.spec.ts +++ b/packages/core/__agw-local__/v5-multiasset.spec.ts @@ -1,4 +1,5 @@ import { agenticPresets } from '../src/lib/agentic/presets'; +import * as accountLookup from '../src/lib/universal/account/account'; import { buildPresetApi } from '../src/lib/agentic/presets'; import { publicRules } from '../src/lib/agentic/public-rule'; /** Actual v6 AGW/URP/engine. Token/core/gateway and destination lookup are local fixtures; no bridge/TSS proof. */ @@ -39,7 +40,13 @@ const internal = (c: PushChain) => describe('v6 multi-asset SDK management and execution', () => { let h: Harness, owner: PushChain, a: Address, b: Address; + let originLookup: jest.SpyInstance; beforeAll(async () => { + // This harness deploys no UEA factory; its receivers are local contracts. + // Keep actual AGW/RPC execution while isolating response-origin metadata. + originLookup = jest + .spyOn(accountLookup, 'convertExecutorToOrigin') + .mockResolvedValue({ account: null, exists: false }); h = await startHarness(18551); owner = await h.client(0); a = await h.deploy(0, 'HarnessPRC20', 'HarnessFixtures.sol', [CHAIN_NS, 6]); @@ -54,7 +61,11 @@ describe('v6 multi-asset SDK management and execution', () => { configure(internal(owner)); }); afterAll(async () => { - await h?.stop(); + try { + await h?.stop(); + } finally { + originLookup?.mockRestore(); + } }); function configure(rt: AgenticRuntime) { // Fixture source token addresses equal fixture PRC20s; production uses the token registry. @@ -333,6 +344,116 @@ describe('v6 multi-asset SDK management and execution', () => { } ); + it.each(['LENDING', 'STAKING'] as const)( + 'regenerated %s presets enforce new token/amount pins through atomic rules.update', + async (category) => { + const firstToken = getAddress( + '0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5' + ); + const nextToken = getAddress( + '0x29f2D40B0605204364af54EC677bD022dA425d03' + ); + const opts = { + chainNamespace: CHAIN_NS, + agent: h.wallets[1].account!.address, + validUntil: Math.floor(Date.now() / 1000) + 3600, + maxGasPerCall: BigInt(10) ** BigInt(16), + }; + const preview = agenticPresets.get(category, opts); + expect(preview.readiness.ready).toBe(false); + const { wallet, id, agent } = await setup({ + ...preview.rules[0], + assets: [], + }); + const target = preview.rules[0].allowedCalls[0].target as Address; + const abi = parseAbi([ + 'function supply(address,uint256,address,uint16)', + 'function depositIntoStrategy(address,address,uint256)', + ]); + const send = (token: Address, amount: bigint, count = 1) => + agent.universal.sendTransaction({ + to: { address: target, chain: CHAIN_NS }, + data: Array.from({ length: count }, () => ({ + to: target, + value: BigInt(0), + data: + category === 'LENDING' + ? encodeFunctionData({ + abi, + functionName: 'supply', + args: [token, amount, CEA, 0], + }) + : encodeFunctionData({ + abi, + functionName: 'depositIntoStrategy', + args: [DEST, token, amount], + }), + })), + }); + await expect(send(firstToken, BigInt(1))).rejects.toMatchObject({ + decodedError: { name: 'PolicyCheckReverted(ArgPinAboveMax)' }, + }); + const w = owner.agentic.wallet(wallet); + const first = agenticPresets.get(category, { + ...opts, + assets: [ + { token: firstToken, maxPerCall: BigInt(5), maxTotal: BigInt(10) }, + ], + }); + expect(first.readiness.ready).toBe(true); + const before = await h.publicClient.readContract({ + address: wallet, + abi: h.generation.contracts.abis.wallet, + functionName: 'checkpointCount', + }); + const added = await w.rules.update({ + rules: [{ rulesId: id, rule: { ...first.rules[0], assets: [] } }], + }); + expect( + await h.publicClient.readContract({ + address: wallet, + abi: h.generation.contracts.abis.wallet, + functionName: 'checkpointCount', + }) + ).toBe(before + BigInt(5)); + await waitPush(send(firstToken, BigInt(5))); + // Per-call MAX permits two calls of 5 in one outbound; it is not a batch-total cap. + await waitPush(send(firstToken, BigInt(5), 2)); + await expect(send(firstToken, BigInt(6))).rejects.toMatchObject({ + decodedError: { name: 'PolicyCheckReverted(ArgPinAboveMax)' }, + }); + await expect(send(nextToken, BigInt(1))).rejects.toMatchObject({ + decodedError: { name: 'PolicyCheckReverted(ArgPinMismatch)' }, + }); + const changed = agenticPresets.get(category, { + ...opts, + assets: [ + { token: nextToken, maxPerCall: BigInt(2), maxTotal: BigInt(10) }, + ], + }); + const replaced = await w.rules.update({ + rules: [ + { + rulesId: added.rules[0].rulesId, + rule: { ...changed.rules[0], assets: [] }, + }, + ], + }); + expect(replaced.rules[0].rulesId).not.toBe(added.rules[0].rulesId); + await expect(send(firstToken, BigInt(1))).rejects.toMatchObject({ + decodedError: { name: 'PolicyCheckReverted(ArgPinMismatch)' }, + }); + await expect(send(nextToken, BigInt(3))).rejects.toMatchObject({ + decodedError: { name: 'PolicyCheckReverted(ArgPinAboveMax)' }, + }); + await waitPush(send(nextToken, BigInt(2))); + // Calls using destination-held capital do not consume the Push bridge counter. + expect( + (await stored(wallet, replaced.rules[0].rulesId)).assets[0].spent + ).toBe(BigInt(0)); + } + ); + it('a fixture preset produces rules accepted by public create and enforced by real contracts', async () => { const presets = buildPresetApi([ { diff --git a/packages/core/__e2e__/agw/presets-expanded-live.spec.ts b/packages/core/__e2e__/agw/presets-expanded-live.spec.ts index 67b44a32..59470e62 100644 --- a/packages/core/__e2e__/agw/presets-expanded-live.spec.ts +++ b/packages/core/__e2e__/agw/presets-expanded-live.spec.ts @@ -46,7 +46,8 @@ const AAVE = parseAbi([ ]); const MARKET = parseAbi([ 'function mint(uint256) returns(uint256)', - 'function redeem(uint256) returns(uint256)', + 'function redeemUnderlying(uint256) returns(uint256)', + 'function exchangeRateStored() view returns(uint256)', 'function balanceOf(address) view returns(uint256)', ]); const read = (chain: Destination) => @@ -193,6 +194,22 @@ function assertRedemption( expect(event?.args.redeemAmount).toBe(received); } +async function underlyingRedemption( + chain: Destination, + market: Address, + shares: bigint, + cap: bigint +) { + const rate = await read(chain).readContract({ + address: market, + abi: MARKET, + functionName: 'exchangeRateStored', + }); + const amount = (shares * rate) / BigInt(10) ** BigInt(18); + const bounded = amount < cap ? amount : cap; + expect(bounded).toBeGreaterThan(ZERO); + return bounded; +} async function wrap( f: AgwFixture, w: Awaited>, @@ -293,6 +310,29 @@ d('agw presets expanded', () => { functionName: 'stakerDepositShares', args: [w.cea, strategy], }); + for (const [inputToken, amount, error] of [ + [token, SMALL + BigInt(1), 'ArgPinAboveMax'], + [strategy, SMALL, 'ArgPinMismatch'], + ] as const) { + await expect( + w.agent.universal.sendTransaction({ + to: { address: manager, chain }, + gasLimit: BigInt(2_000_000), + data: [ + call( + manager, + encodeFunctionData({ + abi, + functionName: 'depositIntoStrategy', + args: [strategy, inputToken, amount], + }) + ), + ], + }) + ).rejects.toMatchObject({ + decodedError: { name: `PolicyCheckReverted(${error})` }, + }); + } await send( f, w, @@ -532,6 +572,12 @@ d('agw presets expanded', () => { const shares = await balance(chain, venus, w.cea); expect(shares).toBeGreaterThan(ZERO); expect(await balance(chain, output, w.cea)).toBe(before); + const redeemAmount = await underlyingRedemption( + chain, + venus, + shares, + received + ); const redemption = await send( f, w, @@ -542,16 +588,24 @@ d('agw presets expanded', () => { venus, encodeFunctionData({ abi: MARKET, - functionName: 'redeem', - args: [shares], + functionName: 'redeemUnderlying', + args: [redeemAmount], }) ), ], 'venus-redeem' ); const redeemed = (await balance(chain, output, w.cea)) - before; - expect(await balance(chain, venus, w.cea)).toBe(ZERO); - assertRedemption(redemption, venus, w.cea, shares, redeemed); + const remainingShares = await balance(chain, venus, w.cea); + expect(remainingShares).toBeLessThan(shares); + expect(redeemed).toBe(redeemAmount); + assertRedemption( + redemption, + venus, + w.cea, + shares - remainingShares, + redeemed + ); expect(redeemed).toBeGreaterThanOrEqual( (received * BigInt(99)) / BigInt(100) ); @@ -562,6 +616,7 @@ d('agw presets expanded', () => { deposited: received, redeemed, shares, + remainingShares, asset: output, }); } @@ -678,6 +733,18 @@ d('agw presets expanded', () => { expect(await balance(chain, link, w.cea)).toBe(ZERO); expect(await balance(chain, usdbc, w.cea)).toBe(ZERO); expect(await balance(chain, weth, w.cea)).toBe(ZERO); + const redeemUSDBC = await underlyingRedemption( + chain, + mUSDBC, + sharesUSDBC, + amountUSDBC + ); + const redeemWETH = await underlyingRedemption( + chain, + mWETH, + sharesWETH, + SMALL + ); const redemption = await send( f, w, @@ -696,16 +763,16 @@ d('agw presets expanded', () => { mUSDBC, encodeFunctionData({ abi: MARKET, - functionName: 'redeem', - args: [sharesUSDBC], + functionName: 'redeemUnderlying', + args: [redeemUSDBC], }) ), call( mWETH, encodeFunctionData({ abi: MARKET, - functionName: 'redeem', - args: [sharesWETH], + functionName: 'redeemUnderlying', + args: [redeemWETH], }) ), ], @@ -718,20 +785,24 @@ d('agw presets expanded', () => { expect(await balance(chain, weth, w.cea)).toBeGreaterThanOrEqual( (SMALL * BigInt(99)) / BigInt(100) ); - expect(await balance(chain, mUSDBC, w.cea)).toBe(ZERO); - expect(await balance(chain, mWETH, w.cea)).toBe(ZERO); + const remainingUSDBC = await balance(chain, mUSDBC, w.cea), + remainingWETH = await balance(chain, mWETH, w.cea); + expect(remainingUSDBC).toBeLessThan(sharesUSDBC); + expect(remainingWETH).toBeLessThan(sharesWETH); + expect(await balance(chain, usdbc, w.cea)).toBe(redeemUSDBC); + expect(await balance(chain, weth, w.cea)).toBe(redeemWETH); assertRedemption( redemption, mUSDBC, w.cea, - sharesUSDBC, + sharesUSDBC - remainingUSDBC, await balance(chain, usdbc, w.cea) ); assertRedemption( redemption, mWETH, w.cea, - sharesWETH, + sharesWETH - remainingWETH, await balance(chain, weth, w.cea) ); f.evidence('preset-expanded-base-lending', { diff --git a/packages/core/__e2e__/agw/presets-live.spec.ts b/packages/core/__e2e__/agw/presets-live.spec.ts index d0567d5d..dfcfe611 100644 --- a/packages/core/__e2e__/agw/presets-live.spec.ts +++ b/packages/core/__e2e__/agw/presets-live.spec.ts @@ -341,6 +341,25 @@ d('agw presets live', () => { functionName: 'supply', args: [mockLINK, amount, cea, 0], }); + await expect( + agent.universal.sendTransaction({ + to: { address: pool, chain: CHAIN.ETHEREUM_SEPOLIA }, + gasLimit: BigInt(900_000), + data: [ + { + to: pool, + value: BigInt(0), + data: encodeFunctionData({ + abi, + functionName: 'supply', + args: [mockLINK, amount + BigInt(1), cea, 0], + }), + }, + ], + }) + ).rejects.toMatchObject({ + decodedError: { name: 'PolicyCheckReverted(ArgPinAboveMax)' }, + }); const supply = await agent.universal.sendTransaction({ to: { address: pool, chain: CHAIN.ETHEREUM_SEPOLIA }, gasLimit: BigInt(900_000), @@ -389,20 +408,57 @@ d('agw presets live', () => { e.args.amount === amount ) ).toBe(true); + const half = amount / BigInt(2); + const regenerated = PushChain.utils.agentic.presets.get('LENDING', { + chainNamespace: CHAIN.ETHEREUM_SEPOLIA, + agent: f.agentAddress, + validUntil: inSeconds(3600), + maxGasPerCall: MAX_PC, + assets: [{ token: mockLINK, maxPerCall: half, maxTotal: amount }], + }); + expect(regenerated.readiness.ready).toBe(true); + const changed = await f.owner.agentic + .wallet(wallet) + .rules.update({ + rules: [ + { + rulesId: rulesIds[0], + rule: { ...regenerated.rules[0], assets: [] }, + }, + ], + }); + await expect( + agent.universal.sendTransaction({ + to: { address: pool, chain: CHAIN.ETHEREUM_SEPOLIA }, + gasLimit: BigInt(900_000), + data: [ + { + to: pool, + value: BigInt(0), + data: encodeFunctionData({ + abi, + functionName: 'withdraw', + args: [mockLINK, amount, cea], + }), + }, + ], + }) + ).rejects.toMatchObject({ + decodedError: { name: 'PolicyCheckReverted(ArgPinAboveMax)' }, + }); + // The cap applies to each allowed call, not their aggregate in a batch. const withdraw = await agent.universal.sendTransaction({ to: { address: pool, chain: CHAIN.ETHEREUM_SEPOLIA }, gasLimit: BigInt(900_000), - data: [ - { - to: pool, - value: BigInt(0), - data: encodeFunctionData({ - abi, - functionName: 'withdraw', - args: [mockLINK, amount, cea], - }), - }, - ], + data: [0, 1].map(() => ({ + to: pool, + value: BigInt(0), + data: encodeFunctionData({ + abi, + functionName: 'withdraw', + args: [mockLINK, half, cea], + }), + })), }); f.evidence('preset-aave-stage', { stage: 'withdraw-submitted', @@ -422,19 +478,31 @@ d('agw presets live', () => { }); expect(withdrawalReceipt.status).toBe('success'); expect(await balance()).toBe(amount); - expect( - parseEventLogs({ - abi, - eventName: 'Withdraw', - logs: withdrawalReceipt.logs, - }).some( - (e) => - e.address.toLowerCase() === pool.toLowerCase() && - e.args.user.toLowerCase() === cea.toLowerCase() && - e.args.to.toLowerCase() === cea.toLowerCase() && - e.args.amount === amount - ) - ).toBe(true); + const withdrawals = parseEventLogs({ + abi, + eventName: 'Withdraw', + logs: withdrawalReceipt.logs, + }).filter( + (e) => + e.address.toLowerCase() === pool.toLowerCase() && + e.args.user.toLowerCase() === cea.toLowerCase() && + e.args.to.toLowerCase() === cea.toLowerCase() + ); + expect(withdrawals).toHaveLength(2); + expect(withdrawals.every((e) => e.args.amount === half)).toBe(true); + expect(withdrawals.reduce((sum, e) => sum + e.args.amount, BigInt(0))).toBe( + amount + ); + f.evidence('preset-limits-regeneration-live', { + wallet, + cea, + oldRulesId: rulesIds[0], + newRulesId: changed.rules[0].rulesId, + oldCap: amount, + newCap: half, + rejectedAboveCap: true, + destinationTx: withdrawn.externalTxHash, + }); f.evidence('preset-aave-live', { wallet, cea, diff --git a/packages/core/src/lib/agentic/__tests__/preset-catalog.spec.ts b/packages/core/src/lib/agentic/__tests__/preset-catalog.spec.ts index 622abe7d..1ce41fda 100644 --- a/packages/core/src/lib/agentic/__tests__/preset-catalog.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/preset-catalog.spec.ts @@ -79,7 +79,7 @@ it('scopes money-market approvals to their actual underlying token', () => { const approvals = r.allowedCalls.filter( (c) => c.selector === 'approve(address,uint256)' ); - expect(approvals).toHaveLength(2); // Aave and mUSDbC, never the mWETH market. + expect(approvals).toHaveLength(1); // Only mUSDbC: this mock token is not an Aave reserve. expect(approvals.flatMap((c) => c.pins ?? [])).not.toContainEqual({ arg: 0, expected: getAddress('0x2F39a349A79492a70E152760ce7123A1933eCf28'), @@ -273,28 +273,37 @@ it.each(['eip155:1', 'eip155:8453', 'eip155:42161', 'eip155:56'] as const)( } ); -it('mainnet Lido templates pin withdrawal ownership and keep ETH staking disabled until explicitly capped', () => { +it('mainnet Lido uses the selected token units and excludes unbounded withdrawal/claim methods', () => { const stETH = getAddress('0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84'); - const { rules } = agenticPresets.get('STAKING', { + const { rules, readiness } = agenticPresets.get('STAKING', { chainNamespace: 'eip155:1', assets: [{ token: stETH, maxPerCall: BigInt(5), maxTotal: BigInt(10) }], }); - expect(rules).toHaveLength(1); const calls = rules[0].allowedCalls; - expect(calls.find((c) => c.selector === 'submit(address)')?.maxValue).toBe( - BigInt(0) + expect( + calls.find((c) => c.selector === 'wrap(uint256)')?.pins + ).toContainEqual({ arg: 0, max: BigInt(5) }); + expect(calls.some((c) => c.selector === 'submit(address)')).toBe(false); + expect( + calls.some( + (c) => + c.selector.startsWith('requestWithdrawals') || + c.selector.startsWith('claimWithdraw') + ) + ).toBe(false); + expect(readiness.chains[0].excludedCalls).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + selector: 'requestWithdrawals(uint256[],address)', + reason: 'DYNAMIC_AMOUNT', + }), + expect.objectContaining({ + selector: 'claimWithdrawal(uint256)', + reason: 'POSITION_AMOUNT', + }), + ]) ); - const request = calls.find( - (c) => c.selector === 'requestWithdrawals(uint256[],address)' - )!; - expect(request.pins).toEqual([{ arg: 1, expected: AGENTIC.WALLET }]); - expect(evmPinOffset(request.selector, 1)).toBe(36); expect( calls.filter((c) => c.selector === 'approve(address,uint256)') - ).toHaveLength(3); - expect( - calls - .filter((c) => c.selector === 'approve(address,uint256)') - .every((c) => c.target === stETH && c.pins?.[1].max === BigInt(5)) - ).toBe(true); + ).toHaveLength(2); }); diff --git a/packages/core/src/lib/agentic/__tests__/preset-operation-limits.spec.ts b/packages/core/src/lib/agentic/__tests__/preset-operation-limits.spec.ts new file mode 100644 index 00000000..42a2dcbe --- /dev/null +++ b/packages/core/src/lib/agentic/__tests__/preset-operation-limits.spec.ts @@ -0,0 +1,220 @@ +import { getAddress, zeroAddress } from 'viem'; +import { agenticPresets } from '../presets'; +import { AGENTIC } from '../constants'; +import { ADDR } from './fake-chain'; +const LINK = getAddress('0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5'); +const WBTC = getAddress('0x29f2D40B0605204364af54EC677bD022dA425d03'); +const chainNamespace = 'eip155:11155111' as const; +const options = { + chainNamespace, + agent: ADDR.agent, + validUntil: 2_000_000_000, + maxGasPerCall: BigInt(1), +}; +const asset = (token = LINK, limit = BigInt(5)) => ({ + token, + maxPerCall: limit, + maxTotal: BigInt(10), +}); + +it('Aave pins the selected reserve, operation amount and wallet beneficiary for every method', () => { + const { rules, readiness } = agenticPresets.get('LENDING', { + ...options, + assets: [asset(), asset(WBTC, BigInt(7))], + }); + expect(readiness.ready).toBe(true); + expect(rules).toHaveLength(1); + for (const [selector, walletArg] of [ + ['supply(address,uint256,address,uint16)', 2], + ['withdraw(address,uint256,address)', 2], + ['borrow(address,uint256,uint256,uint16,address)', 4], + ['repay(address,uint256,uint256,address)', 3], + ] as const) { + const calls = rules[0].allowedCalls.filter((c) => c.selector === selector); + expect(calls).toHaveLength(2); + for (const [i, token] of [LINK, WBTC].entries()) { + expect(calls[i].pins).toEqual( + expect.arrayContaining([ + { arg: 0, expected: token }, + { arg: 1, max: i ? BigInt(7) : BigInt(5) }, + { arg: walletArg, expected: AGENTIC.WALLET }, + ]) + ); + expect(calls[i]).not.toHaveProperty('budget'); + } + } +}); +it('returns actionable readiness without silently choosing tokens, caps, gas or expiry', () => { + const result = agenticPresets.get('LENDING', { chainNamespace }); + expect(result.readiness.ready).toBe(false); + expect(result.readiness.chains[0].issues.map((i) => i.code)).toEqual( + expect.arrayContaining([ + 'AGENT_REQUIRED', + 'EXPIRY_REQUIRED', + 'GAS_BUDGET_REQUIRED', + 'ASSETS_REQUIRED', + 'NO_ENABLED_OPERATION', + ]) + ); + expect(result.rules[0]).not.toHaveProperty('assets'); + expect(result.rules[0]).not.toHaveProperty('validUntil'); + expect(result.rules[0]).not.toHaveProperty('maxGasPerCall'); + expect( + result.rules[0].allowedCalls.every((c) => + c.pins?.some((p) => p.max === BigInt(0)) + ) + ).toBe(true); + expect(result.readiness.chains[0].knownTokens).toContain(LINK); +}); +it('zero operation caps remain valid disabled configurations, while zero bridge totals are separately reported', () => { + const disabled = agenticPresets.get('LENDING', { + ...options, + assets: [{ token: LINK }], + }); + expect(disabled.readiness.ready).toBe(false); + expect( + disabled.readiness.chains[0].disabledCalls.every( + (c) => c.reason === 'ZERO_CAP' + ) + ).toBe(true); + const enabled = agenticPresets.get('LENDING', { + ...options, + assets: [{ token: LINK, maxPerCall: BigInt(5) }], + }); + expect(enabled.readiness.ready).toBe(true); + expect(enabled.readiness.chains[0].zeroBridgeLimits).toEqual([LINK]); + expect(enabled.rules[0].assets?.[0].maxTotal).toBe(BigInt(0)); +}); +it('does not approve or grant a positive amount for an unlisted Aave asset', () => { + const { rules, readiness } = agenticPresets.get('LENDING', { + ...options, + assets: [asset(ADDR.other)], + }); + expect(readiness.ready).toBe(false); + expect( + rules[0].allowedCalls.some((c) => c.selector.startsWith('approve')) + ).toBe(false); + expect( + rules[0].allowedCalls.every((c) => c.pins?.some((p) => p.max === BigInt(0))) + ).toBe(true); +}); +it('regenerating a token/limit replaces old operation and approval constraints without mutating the old template', () => { + const first = agenticPresets.get('LENDING', { + ...options, + assets: [asset()], + }); + const next = agenticPresets.get('LENDING', { + ...options, + assets: [asset(WBTC, BigInt(2))], + }); + expect( + next.rules[0].allowedCalls.some( + (c) => c.target === LINK || c.pins?.some((p) => p.expected === LINK) + ) + ).toBe(false); + expect( + next.rules[0].allowedCalls.every((c) => + c.pins?.some((p) => p.max === BigInt(2)) + ) + ).toBe(true); + expect( + first.rules[0].allowedCalls.every((c) => + c.pins?.some((p) => p.max === BigInt(5)) + ) + ).toBe(true); +}); +it('Moonwell applies underlying units and reports the share-based redeem alternative', () => { + const token = getAddress('0x4616975f7E6045FD9737e95bC527e9e14c727BD2'); + const { rules, readiness } = agenticPresets.get('LENDING', { + ...options, + chainNamespace: 'eip155:84532', + assets: [asset(token)], + }); + const calls = rules[0].allowedCalls.filter( + (c) => c.app === 'Moonwell mUSDbC' && !c.selector.startsWith('approve') + ); + expect(calls.map((c) => c.selector)).toEqual([ + 'mint(uint256)', + 'redeemUnderlying(uint256)', + 'borrow(uint256)', + 'repayBorrow(uint256)', + ]); + expect( + calls.every((c) => c.pins?.some((p) => p.arg === 0 && p.max === BigInt(5))) + ).toBe(true); + expect(readiness.chains[0].excludedCalls).toContainEqual( + expect.objectContaining({ + selector: 'redeem(uint256)', + reason: 'SHARE_AMOUNT', + alternative: 'redeemUnderlying(uint256)', + }) + ); +}); +it('EigenLayer pins the chosen token and deposit amount', () => { + const { rules } = agenticPresets.get('STAKING', { + ...options, + assets: [asset()], + }); + const deposit = rules[0].allowedCalls.find((c) => + c.selector.startsWith('depositIntoStrategy') + )!; + expect(deposit.pins).toEqual([ + { arg: 1, expected: LINK }, + { arg: 2, max: BigInt(5) }, + ]); +}); +it('Lido distinguishes stETH, wstETH and native value units', () => { + const stETH = getAddress('0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84'), + wstETH = getAddress('0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0'); + const { rules } = agenticPresets.get('STAKING', { + ...options, + chainNamespace: 'eip155:1', + assets: [ + asset(stETH, BigInt(2)), + asset(wstETH, BigInt(3)), + asset(zeroAddress, BigInt(4)), + ], + }); + expect( + rules[0].allowedCalls.find((c) => c.selector === 'wrap(uint256)')?.pins + ).toEqual([{ arg: 0, max: BigInt(2) }]); + expect( + rules[0].allowedCalls.find((c) => c.selector === 'unwrap(uint256)')?.pins + ).toEqual([{ arg: 0, max: BigInt(3) }]); + expect( + rules[0].allowedCalls.find((c) => c.selector === 'submit(address)') + ?.maxValue + ).toBe(BigInt(4)); +}); +it('readiness is per chain and cannot be mutated to change later results', () => { + const res = agenticPresets.get('LENDING', { + agent: options.agent, + validUntil: options.validUntil, + maxGasPerCall: options.maxGasPerCall, + assets: [{ ...asset(), chainNamespace }], + }); + expect(res.readiness.ready).toBe(false); + expect( + res.readiness.chains.find((c) => c.chainNamespace === chainNamespace)?.ready + ).toBe(true); + const expected = agenticPresets.get('LENDING', { chainNamespace }).readiness; + res.readiness.chains.forEach((c) => { + c.knownTokens.length = 0; + c.disabledCalls.length = 0; + }); + expect(agenticPresets.get('LENDING', { chainNamespace }).readiness).toEqual( + expected + ); +}); +it('refuses an overlarge token expansion without dropping restrictions', () => { + expect(() => + agenticPresets.get('LENDING', { + ...options, + assets: [ + asset(), + asset(WBTC), + asset(getAddress('0x88541670E55cC00bEEFD87eB59EDd1b7C511AC9a')), + ], + }) + ).toThrow(/32 pins/); +}); diff --git a/packages/core/src/lib/agentic/__tests__/presets.spec.ts b/packages/core/src/lib/agentic/__tests__/presets.spec.ts index cefe7479..ffb41709 100644 --- a/packages/core/src/lib/agentic/__tests__/presets.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/presets.spec.ts @@ -75,7 +75,10 @@ it('ships verified mainnet and testnet templates and keeps prediction empty', () ].includes(c) ) ).toBe(true); - expect(agenticPresets.get('PREDICTION')).toEqual({ rules: [] }); + expect(agenticPresets.get('PREDICTION')).toEqual({ + rules: [], + readiness: { ready: false, chains: [] }, + }); expect(agenticPresets.get('DEXES').rules).toHaveLength(8); expect(() => agenticPresets.get('LENDING', { chainNamespace: 'eip155:999999' }) diff --git a/packages/core/src/lib/agentic/index.ts b/packages/core/src/lib/agentic/index.ts index 520fb306..396c39c2 100644 --- a/packages/core/src/lib/agentic/index.ts +++ b/packages/core/src/lib/agentic/index.ts @@ -36,5 +36,9 @@ export type { PresetOptions, ReadyPresetOptions, PresetRuleTemplate, + PresetResult, + PresetChainReadiness, + PresetConfigurationIssue, + PresetCallIssue, AgenticPresets, } from './presets/types'; diff --git a/packages/core/src/lib/agentic/presets/aave-reserves.ts b/packages/core/src/lib/agentic/presets/aave-reserves.ts new file mode 100644 index 00000000..bdd07638 --- /dev/null +++ b/packages/core/src/lib/agentic/presets/aave-reserves.ts @@ -0,0 +1,146 @@ +/** Aave V3 reserve addresses from the official bgd-labs/aave-address-book + * snapshots reviewed October 15, 2026. Listings are not liquidity/availability guarantees. */ +import type { Address } from 'viem'; +export const AAVE_RESERVES: Readonly> = { + 'eip155:1': [ + '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', + '0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0', + '0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599', + '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', + '0x6B175474E89094C44Da98b954EedeAC495271d0F', + '0x514910771AF9Ca656af840dff83E8264EcF986CA', + '0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9', + '0xBe9895146f7AF43049ca1c1AE358B0541Ea49704', + '0xdAC17F958D2ee523a2206206994597C13D831ec7', + '0xae78736Cd615f374D3085123A210448E74Fc6393', + '0x5f98805A4E8be255a32880FDeC7F6728C6568bA0', + '0xD533a949740bb3306d119CC777fa900bA034cd52', + '0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2', + '0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F', + '0xba100000625a3754423978a60c9317c58a424e3D', + '0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984', + '0x5A98FcBEA516Cf06857215779Fd812CA3beF1B32', + '0xC18360217D8F7Ab5e7c516566761Ea12Ce7F9D72', + '0x111111111117dC0aa78b770fA6A738034120C302', + '0x853d955aCEf822Db058eb8505911ED77F175b99e', + '0x40D16FC0246aD3160Ccc09B8D0D3A2cD28aE6C2f', + '0xD33526068D116cE69F19A9ee46F0bd304F21A51f', + '0x83F20F44975D03b1b09e64809B757c47f942BEeA', + '0xAf5191B0De278C7286d6C7CC6ab6BB8A73bA2Cd6', + '0xdeFA4e8a7bcBA345F687a2f1456F5Edd9CE97202', + '0x3432B6A60D23Ca0dFCa7761B7ab56459D9C964D0', + '0xf939E0A03FB07F59A73314E73794Be0E57ac1b4E', + '0x6c3ea9036406852006290770BEdFcAbA0e23A0e8', + '0xCd5fE23C85820F7B72D0926FC9b05b43E359b7ee', + '0xf1C9acDc66974dFB6dEcB12aA385b9cD01190E38', + '0x4c9EDD5852cd905f086C759E8383e09bff1E68B3', + '0xA35b1B31Ce002FBF2058D22F30f95D405200A15b', + '0x9D39A5DE30e57443BfF2A8307A4256c8797A3497', + '0x18084fbA666a33d37592fA2633fD49a74DD93a88', + '0xcbB7C0000aB88B473b1f5aFd9ef808440eed33Bf', + '0xdC035D45d973E3EC169d2276DDab16f1e407384F', + '0xA1290d69c65A6Fe4DF752f95823fae25cB99e5A7', + '0x8236a87084f8B84306f72007F36F2618A5634494', + '0x657e8C867D8B37dCC18fA4Caead9C45EB088C642', + '0x8292Bb45bf1Ee4d140127049757C2E0fF06317eD', + '0x50D2C7992b802Eef16c04FeADAB310f31866a545', + '0x3b3fB9C57858EF816833dC91565EFcd85D96f634', + '0xC139190F447e929f090Edeb554D95AbB8b18aC1C', + '0x917459337CaAC939D41d7493B3999f571D20D667', + '0x14Bdc3A3AE09f5518b923b69489CBcAfB238e617', + '0x90D2af7d622ca3141efA4d8f1F24d86E5974Cc8F', + '0xC96dE26018A54D51c097160568752c4E3BD6C364', + '0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c', + '0x9F56094C450763769BA0EA9Fe2876070c0fD5F77', + '0xBC6736d346a5eBC0dEbc997397912CD9b8FAe10a', + '0xD11c452fc99cF405034ee446803b6F6c1F6d5ED8', + '0xbf5495Efe5DB9ce00f80364C8B423567e58d2110', + '0x68749665FF8D2d112Fa859AA293F07A622782F38', + '0xe6A934089BBEe34F832060CE98848359883749B3', + '0x62C6E813b9589C3631Ba0Cdb013acdB8544038B7', + '0x1F84a51296691320478c98b8d77f2Bbd17D34350', + '0xE8483517077afa11A9B07f849cee2552f040d7b2', + '0xacA92E438df0B2401fF60dA7E4337B687a2435DA', + '0x356B8d89c1e1239Cbbb9dE4815c39A1474d5BA7D', + '0xe343167631d89B6Ffc58B88d6b7fB0228795491D', + '0xAeBf0Bb9f57E89260d57f31AF34eB58657d96Ce0', + '0x3de0ff76E8b528C092d47b9DaC775931cef80F49', + '0x9Bf45ab47747F4B4dD09B3C2c73953484b4eB375', + '0xB0F70C0bD6FD87dbEb7C10dC692a2a6106817072', + '0x619D75E3b790eBC21c289f2805Bb7177A7D732E2', + '0x9db38D74a0D29380899aD354121DfB521aDb0548', + '0x59bC9FaE5D62B19d4f8d07D758047aCb9EE19d34', + ], + 'eip155:8453': [ + '0x4200000000000000000000000000000000000006', + '0x2Ae3F1Ec7F1F5012CFEab0185bfc7aa3cf0DEc22', + '0xd9aAEc86B65D86f6A7B5B1b0c42FFA531710b6CA', + '0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452', + '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', + '0x04C0599Ae5A44757c0af6F9eC3b93da8976c150A', + '0xcbB7C0000aB88B473b1f5aFd9ef808440eed33Bf', + '0x2416092f143378750bb29b79eD961ab195CcEea5', + '0x6Bb7a212910682DCFdbd5BCBb3e28FB4E8da10Ee', + '0xEDfa23602D0EC14714057867A78d01e94176BEA0', + '0xecAc9C5F704e954931349Da37F60E39f515c11c1', + '0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42', + '0x63706e401c06ac8513145b7687A14804d17f814b', + '0x236aa50979D5f3De3Bd1Eeb40E81137F22ab794b', + '0x660975730059246A68521a3e2FBD4740173100f5', + ], + 'eip155:42161': [ + '0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1', + '0xf97f4df75117a78c1A5a0DBb814Af92458539FB4', + '0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8', + '0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f', + '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1', + '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9', + '0xba5DdD1f9d7F570dc94a51479a000E3BCE967196', + '0xD22a58f79e9481D1a88e00c343885A588b34b68B', + '0x5979D7b546E38E414F7E9822514be443A4800529', + '0x3F56e0c36d275367b8C502090EDF38289b3dEa0d', + '0xEC70Dcb4A1EFa46b8F2D97C310C9c4790ba5ffA8', + '0x93b346b6BC2548dA6A1E7d98E9a421B42541425b', + '0xaf88d065e77c8cC2239327C5EDb3A432268e5831', + '0x17FC002b466eEc40DaE837Fc4bE5c67993ddBd6F', + '0x912CE59144191C1204E64559FE8253a0e49E6548', + '0x35751007a407ca6FEFfE80b3cB397736D2cf4dbe', + '0x7dfF72693f6A4149b17e7C6314655f6A9F7c8B33', + '0x2416092f143378750bb29b79eD961ab195CcEea5', + '0x4186BFC76E2E237523CBC30FD220FE055156b41F', + '0x6c84a8f1c29108F47a79964b5Fe888D4f4D0dE40', + ], + 'eip155:56': [ + '0x0E09FaBB73Bd3Ade0a17ECC321fD13a19e81cE82', + '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c', + '0x7130d2A12B9BCbFAe4f2634d864A1Ee1Ce3Ead9c', + '0x2170Ed0880ac9A755fd29B2688956BD959F933F8', + '0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d', + '0x55d398326f99059fF775485246999027B3197955', + '0xc5f0f7b66764F6ec8C8Dff7BA683102295E16409', + '0x26c5e01524d2E6280A48F2c50fF6De7e52E9611C', + ], + 'eip155:11155111': [ + '0xFF34B3d4Aee8ddCd6F9AFFFB6Fe49bD371b8a357', + '0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5', + '0x94a9D9AC8a22534E3FaCa9F4e7F2E2cf85d5E4C8', + '0x29f2D40B0605204364af54EC677bD022dA425d03', + '0xC558DBdd856501FCd9aaF1E62eae57A9F0629a3c', + '0xaA8E23Fb1079EA71e0a56F48a2aA51851D8433D0', + '0x88541670E55cC00bEEFD87eB59EDd1b7C511AC9a', + '0x6d906e526a4e2Ca02097BA9d0caA3c382F52278E', + '0xc4bF5CbDaBE595361438F8c6a187bDc330539c60', + ], + 'eip155:84532': [ + '0xba50Cd2A20f6DA35D788639E581bca8d0B5d4D5f', + '0x0a215D8ba66387DCA84B284D18c3B4ec3de6E54a', + '0x54114591963CF60EF3aA63bEfD6eC263D98145a4', + '0x4200000000000000000000000000000000000006', + '0xD171b9694f7A2597Ed006D41f7509aaD4B485c4B', + '0x810D46F9a9027E28F9B01F75E2bdde839dA61115', + ], + 'eip155:421614': [ + '0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d', + '0x1dF462e2712496373A347f8ad10802a5E95f053D', + ], +}; diff --git a/packages/core/src/lib/agentic/presets/catalog.ts b/packages/core/src/lib/agentic/presets/catalog.ts index 732243fb..c7d7b2e2 100644 --- a/packages/core/src/lib/agentic/presets/catalog.ts +++ b/packages/core/src/lib/agentic/presets/catalog.ts @@ -1,15 +1,40 @@ import { getAddress, type Address } from 'viem'; import type { RuleCall, ForeignChainNamespace } from '../agentic.types'; import type { PresetCategory } from './types'; +import { AAVE_RESERVES } from './aave-reserves'; + +export type PresetBudget = + | { + kind: 'token-argument'; + tokenArg: number; + amountArg: number; + tokens?: readonly Address[]; + } + | { kind: 'fixed-token'; token: Address; amountArg: number } + | { kind: 'native-value' } + | { kind: 'setup' } + | { + kind: 'unsupported'; + reason: 'SHARE_AMOUNT' | 'DYNAMIC_AMOUNT' | 'POSITION_AMOUNT'; + alternative?: RuleCall['selector']; + }; +export interface PresetCallDefinition extends RuleCall { + budget?: PresetBudget; +} /** Internal catalog: reviewed addresses and explicit calls only; never fetched at runtime. */ export interface PresetChainDefinition { chainNamespace: ForeignChainNamespace; - allowedCalls: readonly RuleCall[]; + allowedCalls: readonly PresetCallDefinition[]; /** Static single-hop routers; incomplete pairs return zero-input-cap review calls. */ swapRouters?: readonly { address: Address; app: string }[]; /** Exact spenders that need an approval for each non-native supplied asset. */ - approvals?: readonly { spender: Address; app: string; token?: Address }[]; + approvals?: readonly { + spender: Address; + app: string; + token?: Address; + tokens?: readonly Address[]; + }[]; maxGasPerCall?: bigint; } export interface PresetDefinition { @@ -23,7 +48,7 @@ export interface PresetDefinition { */ const address = (value: string): Address => getAddress(value.toLowerCase()); const wallet = 'agentic:wallet' as const; -const aave = (pool: Address): RuleCall[] => +const aave = (pool: Address, chain: string): PresetCallDefinition[] => [ ['supply(address,uint256,address,uint16)', 2, 'Supply'], ['withdraw(address,uint256,address)', 2, 'Withdraw'], @@ -35,8 +60,18 @@ const aave = (pool: Address): RuleCall[] => pins: [{ arg: arg as number, expected: wallet }], app: 'Aave V3', label: label as string, + budget: { + kind: 'token-argument', + tokenArg: 0, + amountArg: 1, + tokens: AAVE_RESERVES[chain], + }, })); -const market = (target: Address, app: string): RuleCall[] => +const market = ( + target: Address, + app: string, + token: Address +): PresetCallDefinition[] => [ 'mint(uint256)', 'redeem(uint256)', @@ -48,6 +83,14 @@ const market = (target: Address, app: string): RuleCall[] => selector: selector as RuleCall['selector'], app, label: selector.split('(')[0], + budget: + selector === 'redeem(uint256)' + ? { + kind: 'unsupported', + reason: 'SHARE_AMOUNT', + alternative: 'redeemUnderlying(uint256)', + } + : { kind: 'fixed-token', token, amountArg: 0 }, })); const sepoliaPool = address('0x6Ae43d3271ff6888e7Fc43Fd7321a503ff738951'); const basePool = address('0x8bAB6d1b75f19e9eD9fCe8b9BD338844fF79aE27'); @@ -97,7 +140,9 @@ const mainnetMarkets = ( : '0xfD36E2c2a6789Db23113685031d7F16329158384'; return { allowedCalls: [ - ...entries.flatMap(([target, app]) => market(address(target), app)), + ...entries.flatMap(([target, app, token]) => + market(address(target), app, address(token)) + ), ...(entries.length ? [ { @@ -105,6 +150,7 @@ const mainnetMarkets = ( selector: 'enterMarkets(address[])' as const, app: chain === 'eip155:8453' ? 'Moonwell' : 'Venus', label: 'Enter markets', + budget: { kind: 'setup' as const }, }, ] : []), @@ -178,40 +224,69 @@ export const PRESET_CATALOG: readonly PresetDefinition[] = [ ).map(([chainNamespace, pool]) => ({ chainNamespace, allowedCalls: [ - ...aave(address(pool)), + ...aave(address(pool), chainNamespace), ...mainnetMarkets(chainNamespace).allowedCalls, ], approvals: [ - { spender: address(pool), app: 'Aave V3' }, + { + spender: address(pool), + app: 'Aave V3', + tokens: AAVE_RESERVES[chainNamespace], + }, ...(mainnetMarkets(chainNamespace).approvals ?? []), ], })), { chainNamespace: 'eip155:11155111', - allowedCalls: aave(sepoliaPool), - approvals: [{ spender: sepoliaPool, app: 'Aave V3' }], + allowedCalls: aave(sepoliaPool, 'eip155:11155111'), + approvals: [ + { + spender: sepoliaPool, + app: 'Aave V3', + tokens: AAVE_RESERVES['eip155:11155111'], + }, + ], }, { chainNamespace: 'eip155:421614', - allowedCalls: aave(arbitrumPool), - approvals: [{ spender: arbitrumPool, app: 'Aave V3' }], + allowedCalls: aave(arbitrumPool, 'eip155:421614'), + approvals: [ + { + spender: arbitrumPool, + app: 'Aave V3', + tokens: AAVE_RESERVES['eip155:421614'], + }, + ], }, { chainNamespace: 'eip155:84532', allowedCalls: [ - ...aave(basePool), - ...market(moonUSDBC, 'Moonwell mUSDbC'), - ...market(moonWETH, 'Moonwell mWETH'), + ...aave(basePool, 'eip155:84532'), + ...market( + moonUSDBC, + 'Moonwell mUSDbC', + address('0x4616975f7E6045FD9737e95bC527e9e14c727BD2') + ), + ...market( + moonWETH, + 'Moonwell mWETH', + address('0x663A6F02d547dFd639BF689FED298712f2FB69Fb') + ), { target: address('0xC72ba45f2Ae134F21DAEb2b7B5fd5De0064Ee9bB'), selector: 'enterMarkets(address[])', app: 'Moonwell', label: 'Enter markets', + budget: { kind: 'setup' as const }, }, ], approvals: [ - { spender: basePool, app: 'Aave V3' }, + { + spender: basePool, + app: 'Aave V3', + tokens: AAVE_RESERVES['eip155:84532'], + }, { spender: moonUSDBC, app: 'Moonwell mUSDbC', @@ -227,13 +302,22 @@ export const PRESET_CATALOG: readonly PresetDefinition[] = [ { chainNamespace: 'eip155:97', allowedCalls: [ - ...market(venusUSDT, 'Venus vUSDT'), - ...market(venusUSDC, 'Venus vUSDC'), + ...market( + venusUSDT, + 'Venus vUSDT', + address('0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c') + ), + ...market( + venusUSDC, + 'Venus vUSDC', + address('0x16227D60f7a0e586C66B005219dfc887D13C9531') + ), { target: address('0x94d1820b2D1c7c7452A163983Dc888CEC546b77D'), selector: 'enterMarkets(address[])', app: 'Venus', label: 'Enter markets', + budget: { kind: 'setup' as const }, }, ], approvals: [ @@ -263,19 +347,22 @@ export const PRESET_CATALOG: readonly PresetDefinition[] = [ selector: 'submit(address)', maxValue: BigInt(0), app: 'Lido', - label: 'Stake ETH (set an explicit value cap)', + label: 'Stake ETH', + budget: { kind: 'native-value' }, }, { target: wstETH, selector: 'wrap(uint256)', app: 'Lido wstETH', label: 'Wrap stETH', + budget: { kind: 'fixed-token', token: stETH, amountArg: 0 }, }, { target: wstETH, selector: 'unwrap(uint256)', app: 'Lido wstETH', label: 'Unwrap wstETH', + budget: { kind: 'fixed-token', token: wstETH, amountArg: 0 }, }, { target: lidoQueue, @@ -283,18 +370,21 @@ export const PRESET_CATALOG: readonly PresetDefinition[] = [ pins: [{ arg: 1, expected: wallet }], app: 'Lido withdrawal queue', label: 'Request withdrawal', + budget: { kind: 'unsupported', reason: 'DYNAMIC_AMOUNT' }, }, { target: lidoQueue, selector: 'claimWithdrawals(uint256[],uint256[])', app: 'Lido withdrawal queue', label: 'Claim finalized withdrawals', + budget: { kind: 'unsupported', reason: 'POSITION_AMOUNT' }, }, { target: lidoQueue, selector: 'claimWithdrawal(uint256)', app: 'Lido withdrawal queue', label: 'Claim finalized withdrawal', + budget: { kind: 'unsupported', reason: 'POSITION_AMOUNT' }, }, { @@ -302,11 +392,11 @@ export const PRESET_CATALOG: readonly PresetDefinition[] = [ selector: 'depositIntoStrategy(address,address,uint256)', app: 'EigenLayer', label: 'Deposit into strategy (withdrawals not included)', + budget: { kind: 'token-argument', tokenArg: 1, amountArg: 2 }, }, ], approvals: [ { spender: wstETH, token: stETH, app: 'Lido wstETH' }, - { spender: lidoQueue, token: stETH, app: 'Lido withdrawal queue' }, { spender: address('0x858646372CC42E1A627fcE94aa7A7033e7CF075A'), @@ -323,6 +413,7 @@ export const PRESET_CATALOG: readonly PresetDefinition[] = [ selector: 'depositIntoStrategy(address,address,uint256)', app: 'EigenLayer', label: 'Deposit into strategy (withdrawals not included)', + budget: { kind: 'token-argument', tokenArg: 1, amountArg: 2 }, }, ], approvals: [{ spender: eigen, app: 'EigenLayer' }], diff --git a/packages/core/src/lib/agentic/presets/index.ts b/packages/core/src/lib/agentic/presets/index.ts index 61c5ce4b..9ba56b05 100644 --- a/packages/core/src/lib/agentic/presets/index.ts +++ b/packages/core/src/lib/agentic/presets/index.ts @@ -9,9 +9,12 @@ import type { AgenticPresets, PresetOptions, PresetRuleTemplate, + PresetChainReadiness, + PresetConfigurationIssue, } from './types'; import { parseSelector } from '../codec/selectors'; import { PRESET_CATALOG, type PresetDefinition } from './catalog'; +import { applyOperationLimits, assetAddress } from './operation-limits'; const MAX_UINT256 = (BigInt(1) << BigInt(256)) - BigInt(1); const invalid = (message: string) => @@ -59,8 +62,23 @@ export function buildPresetApi( ...p, chains: p.chains.map((c) => ({ ...c, - allowedCalls: c.allowedCalls.map(copyCall), - approvals: c.approvals?.map((a) => ({ ...a })), + allowedCalls: c.allowedCalls.map((call) => ({ + ...copyCall(call), + ...(call.budget + ? { + budget: { + ...call.budget, + ...(call.budget.kind === 'token-argument' && call.budget.tokens + ? { tokens: [...call.budget.tokens] } + : {}), + }, + } + : {}), + })), + approvals: c.approvals?.map((a) => ({ + ...a, + ...(a.tokens ? { tokens: [...a.tokens] } : {}), + })), swapRouters: c.swapRouters?.map((r) => ({ ...r })), })), })); @@ -161,8 +179,17 @@ export function buildPresetApi( }); assets.set(chain, group); } + const readiness: PresetChainReadiness[] = []; const rules: PresetRuleTemplate[] = chains.map((chain) => { - const calls = chain.allowedCalls.map(copyCall); + const selectedAssets = assets.get(chain.chainNamespace) ?? []; + const limits = applyOperationLimits( + chain.allowedCalls.map((c) => ({ + ...copyCall(c), + ...(c.budget ? { budget: c.budget } : {}), + })), + selectedAssets + ); + const calls = limits.calls; if (chain.swapRouters?.length) { const tokens = assets.get(chain.chainNamespace) ?? []; if ( @@ -236,6 +263,23 @@ export function buildPresetApi( }); } } + if (chain.swapRouters?.length) { + const swaps = calls.filter((c) => c.selector.startsWith('exact')); + for (const c of swaps) { + const positive = c.pins?.some( + (p) => 'max' in p && p.max !== undefined && p.max > BigInt(0) + ); + if (positive) limits.enabled = true; + else + limits.disabledCalls.push({ + target: c.target, + selector: c.selector, + app: c.app, + reason: + selectedAssets.length < 2 ? 'TOKEN_REQUIRED' : 'ZERO_CAP', + }); + } + } const approvals = new Set(); for (const asset of assets.get(chain.chainNamespace) ?? []) { const token = tokenAddress(asset.token); @@ -256,6 +300,11 @@ export function buildPresetApi( getAddress(token) !== getAddress(approval.token) ) continue; + if ( + approval.tokens && + !approval.tokens.some((t) => getAddress(t) === getAddress(token)) + ) + continue; const spender = getAddress(approval.spender); const target = getAddress(token); const approvalKey = `${target}:${spender}`; @@ -307,6 +356,54 @@ export function buildPresetApi( ); pairs.set(pair, !!call.pins?.length); } + const issues: PresetConfigurationIssue[] = []; + if (!options.agent) + issues.push({ + code: 'AGENT_REQUIRED', + message: 'Choose the agent Push address.', + }); + if (!options.validUntil) + issues.push({ + code: 'EXPIRY_REQUIRED', + message: 'Choose an expiry.', + }); + if ( + (options.maxGasPerCall ?? chain.maxGasPerCall ?? BigInt(0)) === + BigInt(0) + ) + issues.push({ + code: 'GAS_BUDGET_REQUIRED', + message: 'Set a positive PC gas budget per outbound.', + }); + if (!selectedAssets.length) + issues.push({ + code: 'ASSETS_REQUIRED', + message: + 'Choose tokens and their limits, then regenerate this preset.', + }); + if (chain.swapRouters?.length && selectedAssets.length < 2) + issues.push({ + code: 'TOKEN_PAIR_REQUIRED', + message: 'Choose both swap tokens, then regenerate this preset.', + }); + if (!limits.enabled) + issues.push({ + code: 'NO_ENABLED_OPERATION', + message: 'No asset operation has a positive per-call limit.', + }); + readiness.push({ + chainNamespace: chain.chainNamespace, + ready: issues.length === 0, + issues, + disabledCalls: limits.disabledCalls, + excludedCalls: limits.excludedCalls, + knownTokens: limits.knownTokens, + zeroBridgeLimits: selectedAssets + .filter( + (a) => a.maxPerCall === BigInt(0) || a.maxTotal === BigInt(0) + ) + .map(assetAddress), + }); return { chainNamespace: chain.chainNamespace, allowedCalls: calls, @@ -329,7 +426,13 @@ export function buildPresetApi( : {}), }; }); - return { rules }; + return { + rules, + readiness: { + ready: readiness.length > 0 && readiness.every((c) => c.ready), + chains: readiness, + }, + }; }, }; // The overload narrows templates only when both required fields were supplied and validated. diff --git a/packages/core/src/lib/agentic/presets/operation-limits.ts b/packages/core/src/lib/agentic/presets/operation-limits.ts new file mode 100644 index 00000000..4466eb93 --- /dev/null +++ b/packages/core/src/lib/agentic/presets/operation-limits.ts @@ -0,0 +1,116 @@ +import { getAddress, zeroAddress } from 'viem'; +import type { RuleAsset, RuleCall } from '../agentic.types'; +import type { PresetCallDefinition } from './catalog'; +import type { PresetCallIssue } from './types'; + +export const assetAddress = (asset: RuleAsset): string => + typeof asset.token === 'string' ? asset.token : asset.token.address; +export const nativeAsset = (asset: RuleAsset): boolean => + assetAddress(asset) === zeroAddress || + (typeof asset.token !== 'string' && asset.token.mechanism === 'native'); + +/** Compile reviewed protocol argument positions. No exchange-rate or share guesses. */ +export function applyOperationLimits( + definitions: readonly PresetCallDefinition[], + assets: RuleAsset[] +) { + const matches = (definition: PresetCallDefinition): RuleAsset[] => { + const b = definition.budget; + if (!b) return []; + if (b.kind === 'native-value') return assets.filter(nativeAsset); + if (b.kind === 'fixed-token') + return assets.filter( + (a) => + !nativeAsset(a) && getAddress(assetAddress(a)) === getAddress(b.token) + ); + if (b.kind === 'token-argument') + return assets.filter( + (a) => + !nativeAsset(a) && + (!b.tokens || + b.tokens.some((t) => getAddress(t) === getAddress(assetAddress(a)))) + ); + return []; + }; + const previewAll = !definitions.some((d) => matches(d).length > 0); + const calls: RuleCall[] = []; + const disabledCalls: PresetCallIssue[] = [], + excludedCalls: PresetCallIssue[] = []; + const knownTokens = new Set(); + let enabled = false; + for (const definition of definitions) { + const { budget, ...call } = definition; + if (!budget || budget.kind === 'setup') { + calls.push(call); + if (!budget) enabled = true; // Non-budgeted internal fixture entries only. + continue; + } + const info = { + target: call.target, + selector: call.selector, + ...(call.app ? { app: call.app } : {}), + }; + if (budget.kind === 'unsupported') { + excludedCalls.push({ + ...info, + reason: budget.reason, + ...(budget.alternative ? { alternative: budget.alternative } : {}), + }); + continue; + } + if (budget.kind === 'fixed-token') + knownTokens.add(getAddress(budget.token)); + if (budget.kind === 'native-value') knownTokens.add(zeroAddress); + if (budget.kind === 'token-argument') + budget.tokens?.forEach((t) => knownTokens.add(getAddress(t))); + const selected = matches(definition); + if (!selected.length && !previewAll) { + excludedCalls.push({ + ...info, + reason: 'UNSELECTED_TOKEN', + ...(budget.kind === 'fixed-token' + ? { token: getAddress(budget.token) } + : {}), + }); + continue; + } + for (const asset of selected.length ? selected : [undefined]) { + const maximum = asset?.maxPerCall ?? BigInt(0); + const pins = [...(call.pins ?? [])]; + if (budget.kind === 'token-argument' && asset) + pins.push({ + arg: budget.tokenArg, + expected: getAddress(assetAddress(asset)), + }); + if (budget.kind !== 'native-value') + pins.push({ arg: budget.amountArg, max: maximum }); + calls.push({ + ...call, + ...(pins.length ? { pins } : {}), + ...(budget.kind === 'native-value' ? { maxValue: maximum } : {}), + }); + if (maximum > BigInt(0)) enabled = true; + else + disabledCalls.push({ + ...info, + reason: asset + ? 'ZERO_CAP' + : assets.length + ? 'UNSELECTED_TOKEN' + : 'TOKEN_REQUIRED', + ...(asset + ? { token: assetAddress(asset) } + : budget.kind === 'fixed-token' + ? { token: getAddress(budget.token) } + : {}), + }); + } + } + return { + calls, + enabled, + disabledCalls, + excludedCalls, + knownTokens: [...knownTokens], + }; +} diff --git a/packages/core/src/lib/agentic/presets/types.ts b/packages/core/src/lib/agentic/presets/types.ts index d7c88642..5f89ffbb 100644 --- a/packages/core/src/lib/agentic/presets/types.ts +++ b/packages/core/src/lib/agentic/presets/types.ts @@ -1,5 +1,10 @@ import type { Address } from 'viem'; -import type { Rule, RuleAsset, ForeignChainNamespace } from '../agentic.types'; +import type { + Rule, + RuleAsset, + RuleCall, + ForeignChainNamespace, +} from '../agentic.types'; export type PresetCategory = 'DEXES' | 'LENDING' | 'STAKING' | 'PREDICTION'; export interface Preset { @@ -16,8 +21,10 @@ export type PresetRuleTemplate = Omit & { export interface PresetAsset { chainNamespace?: ForeignChainNamespace; token: RuleAsset['token']; - /** Omitted caps are zero, by the user's October 12 decision. */ + /** Per allowed operation and per Push outbound, in raw token units. Omitted = 0. + * Does not aggregate multiple destination calls in one transaction. */ maxPerCall?: bigint; + /** Cumulative Push-outbound amount only; not lifetime activity on destination-held assets. Omitted = 0. */ maxTotal?: bigint; } export interface PresetOptions { @@ -34,11 +41,52 @@ export interface ReadyPresetOptions extends PresetOptions { agent: Address; validUntil: number; } +/** Offline configuration only: does not check deployment, reserves, balances or liquidity. */ +export interface PresetConfigurationIssue { + code: + | 'AGENT_REQUIRED' + | 'EXPIRY_REQUIRED' + | 'GAS_BUDGET_REQUIRED' + | 'ASSETS_REQUIRED' + | 'TOKEN_PAIR_REQUIRED' + | 'NO_ENABLED_OPERATION'; + message: string; +} +export interface PresetCallIssue { + target: string; + selector: RuleCall['selector']; + app?: string; + reason: + | 'TOKEN_REQUIRED' + | 'ZERO_CAP' + | 'UNSELECTED_TOKEN' + | 'SHARE_AMOUNT' + | 'DYNAMIC_AMOUNT' + | 'POSITION_AMOUNT'; + token?: string; + alternative?: RuleCall['selector']; +} +export interface PresetChainReadiness { + chainNamespace: ForeignChainNamespace; + ready: boolean; + issues: PresetConfigurationIssue[]; + /** Calls present in the rule but disabled by a zero amount/value maximum. */ + disabledCalls: PresetCallIssue[]; + /** Calls deliberately omitted, including operations with incompatible amount units. */ + excludedCalls: PresetCallIssue[]; + /** Known fixed-token/reserve addresses in this catalog, not selected defaults. */ + knownTokens: string[]; + /** Selected tokens with a zero Push-outbound budget; destination-held assets are separate. */ + zeroBridgeLimits: string[]; +} +export interface PresetResult< + T extends PresetRuleTemplate = PresetRuleTemplate +> { + rules: T[]; + readiness: { ready: boolean; chains: PresetChainReadiness[] }; +} export interface AgenticPresets { list(options?: { type?: 'CATEGORY' }): { presets: Preset[] }; - get(preset: PresetCategory, options: ReadyPresetOptions): { rules: Rule[] }; - get( - preset: PresetCategory, - options?: PresetOptions - ): { rules: PresetRuleTemplate[] }; + get(preset: PresetCategory, options: ReadyPresetOptions): PresetResult; + get(preset: PresetCategory, options?: PresetOptions): PresetResult; } diff --git a/packages/core/src/lib/index.ts b/packages/core/src/lib/index.ts index 25edbc94..1783b439 100644 --- a/packages/core/src/lib/index.ts +++ b/packages/core/src/lib/index.ts @@ -241,5 +241,9 @@ export type { PresetOptions, ReadyPresetOptions, PresetRuleTemplate, + PresetResult, + PresetChainReadiness, + PresetConfigurationIssue, + PresetCallIssue, AgenticPresets, } from './agentic'; From b115b66c6888cde5ff4b6a09e6c4b224a8874729 Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Fri, 16 Oct 2026 19:42:45 +0530 Subject: [PATCH 48/68] docs(agw): record preset configuration changes and validation limits --- plan/agw/implementation-status.md | 2 + plan/agw/pending-items.md | 2 + plan/agw/questions-harsh.md | 24 +- .../preset-configuration-2026-10-16/README.md | 45 + .../aave-first-timeout.log | 50 + .../aave-second-timeout.log | 27 + .../preset-configuration-2026-10-16/api.json | 11654 ++++++++++++++++ .../preset-configuration-2026-10-16/build.log | 13 + .../preset-configuration-2026-10-16/docs.log | 1 + .../focused-unit.log | 9 + .../preset-configuration-2026-10-16/lint.log | 6 + .../live-attempt-evidence.jsonl | 4 + .../local-contracts.log | 26 + .../local-origin-lookup-timeout.log | 148 + .../markets-timeout.log | 103 + .../preset-configuration-2026-10-16/unit.log | 179 + plan/agw/section7-presets.md | 5 + 17 files changed, 12290 insertions(+), 8 deletions(-) create mode 100644 plan/agw/research/preset-configuration-2026-10-16/README.md create mode 100644 plan/agw/research/preset-configuration-2026-10-16/aave-first-timeout.log create mode 100644 plan/agw/research/preset-configuration-2026-10-16/aave-second-timeout.log create mode 100644 plan/agw/research/preset-configuration-2026-10-16/api.json create mode 100644 plan/agw/research/preset-configuration-2026-10-16/build.log create mode 100644 plan/agw/research/preset-configuration-2026-10-16/docs.log create mode 100644 plan/agw/research/preset-configuration-2026-10-16/focused-unit.log create mode 100644 plan/agw/research/preset-configuration-2026-10-16/lint.log create mode 100644 plan/agw/research/preset-configuration-2026-10-16/live-attempt-evidence.jsonl create mode 100644 plan/agw/research/preset-configuration-2026-10-16/local-contracts.log create mode 100644 plan/agw/research/preset-configuration-2026-10-16/local-origin-lookup-timeout.log create mode 100644 plan/agw/research/preset-configuration-2026-10-16/markets-timeout.log create mode 100644 plan/agw/research/preset-configuration-2026-10-16/unit.log diff --git a/plan/agw/implementation-status.md b/plan/agw/implementation-status.md index ea667589..551b5768 100644 --- a/plan/agw/implementation-status.md +++ b/plan/agw/implementation-status.md @@ -1,5 +1,7 @@ # AGW SDK implementation status +**October 16 — preset operation limits and UI readiness:** Implemented token/amount pins, underlying-unit redemption, explicit excluded-call metadata and additive get().readiness. Regenerate then rules.update is documented and contract-tested. **2,111 unit tests**, **54 focused tests**, build/typechecks/package checks pass. **Fresh live acceptance is pending:** Aave, BNB and Base setup/receipt waits timed out; some Push receipts later succeeded. Earlier live results do not certify the new limits. [Changes and evidence](research/preset-configuration-2026-10-16/README.md). + **October 15 — expanded preset live acceptance:** Five additional scenarios passed across focused runs, covering every shipped testnet protocol/chain combination together with the earlier two Sepolia scenarios. Found and fixed AGW explicit ETH token resolution on Base/Arbitrum; no public signature changed. **2,101 unit tests**, **16 local contract tests**, build/typechecks/package checks pass. [Evidence, initial failures and scope limits](research/preset-expanded-live-2026-10-15/README.md). **October 15 — presets:** Verified mainnet/testnet templates, static tuple paths and the approved zero-cap review/regenerate flow are implemented. Full unit suite: **2,096 passed**, 12 skipped. Preset-focused tests: **44 passed**; review-flow local contract suite: **16 passed**. [Current scope and remaining work](section7-presets.md). Dated entries below are historical where they differ. **Two real Donut→Sepolia protocol scenarios passed** (Uniswap swap and Aave LINK supply/withdraw, separate runs). Mainnet templates are read-only verified. Live app coverage is tracked in [preset acceptance](research/preset-live-2026-10-15/README.md). diff --git a/plan/agw/pending-items.md b/plan/agw/pending-items.md index 5a38ed0a..cce1a652 100644 --- a/plan/agw/pending-items.md +++ b/plan/agw/pending-items.md @@ -4,6 +4,8 @@ October 15, 2026. The newly downloaded SDK sections 6/7 supersede the earlier `a | Item | Owner / dependency | Completion condition | | --- | --- | --- | +| New preset-limit live acceptance | SDK / network processing | Updated local policy tests pass; funded Aave/BNB/Base setup waits timed out. Re-run affected scenarios without counting earlier unrestricted catalog results | +| Destination aggregate spend semantics | Product/contracts | Confirm whether limits must aggregate a batch or destination lifetime activity; current pins are per allowed call and maxTotal is Push-outbound only | | Native 1..32 calls in spec versus deployed maximum 8 | Product/contracts | Align spec or deploy increased ceiling; SDK enforces 8 now | | Additional preset protocols / chains | SDK + protocol prerequisites | Every shipped testnet protocol/chain combination now has a positive live flow. Remaining coverage is borrow/repay, other markets/methods and mainnet; expand excluded protocol rows only after deployment/function/permission checks | | Exact authored ABI reconstruction on reads | Spec metadata, optional | Static tuple/fixed-array paths now work. Raw selector + word positions roundtrip losslessly; recovering original names/types requires metadata not stored by contracts | diff --git a/plan/agw/questions-harsh.md b/plan/agw/questions-harsh.md index f1bc56a7..a4e52342 100644 --- a/plan/agw/questions-harsh.md +++ b/plan/agw/questions-harsh.md @@ -1,12 +1,20 @@ -# AGW presets — documentation follow-up +# AGW preset limit semantics — remaining product clarification -Updated October 15, 2026. Local draft; nothing sent. No blocking preset product question remains for the implemented scope. +Updated October 16, 2026. Local draft; nothing sent. -Please synchronize SDK section 7 with the decisions recorded during implementation: +## What should the UI's spending limits mean? -1. Missing preset asset caps default to zero, rather than throwing. -2. DEX get can populate a review screen before tokens are selected. Incomplete pairs have a zero swap-input maximum; call get again with both tokens to generate usable token-pinned rules. -3. The catalog includes STAKING (EigenLayer deposits and mainnet Lido), and mainnet as well as testnet templates. Discovery does not guarantee destination support on the connected Push network. -4. Static tuple fields use paths such as arg: [0,3], replacing the ambiguous Uniswap arg: 3 example. Decoded rules preserve exact ABI word positions with a raw selector. +Current contracts enforce two different scopes: -These decisions are already approved in the user session; this is documentation synchronization, not a request to approve them again. [Current scope and remaining expansion](section7-presets.md). +- An operation amount maximum applies to each allowed call. A batch can contain several calls, each within that maximum. +- Asset maxTotal counts tokens sent from Push. It does not count repeated swaps/lending/staking using assets already in the destination CEA. + +Should the product require a combined limit across destination calls in one transaction, or a cumulative destination-spend limit? Either requires contract accounting beyond the current limits. Until then, the UI should label the implemented scopes explicitly and must not describe maxTotal as a lifetime trading budget. + +## SDK delivery and documentation synchronization + +The SDK now generates token/amount restrictions for supported lending/staking calls and returns readiness, disabled/excluded call reasons and known token choices. The wallet UI must collect inputs, call presets.get again when they change, and pass the regenerated rule to rules.update. Missing caps remain zero; the SDK supplies no 0.1 PC or 30-day defaults. + +Share-based redeem uses the bounded redeemUnderlying alternative. Dynamic/position-derived withdrawals are excluded from bounded presets. No answer is required to continue the implemented scope; the question above determines whether a larger contract change is wanted. + +[Implementation and evidence](research/preset-configuration-2026-10-16/README.md). diff --git a/plan/agw/research/preset-configuration-2026-10-16/README.md b/plan/agw/research/preset-configuration-2026-10-16/README.md new file mode 100644 index 00000000..abe516cc --- /dev/null +++ b/plan/agw/research/preset-configuration-2026-10-16/README.md @@ -0,0 +1,45 @@ +# Preset configuration and per-operation limits — October 16, 2026 + +Implemented after Riyanshu's UI feedback and the user's request to complete the SDK-owned changes. Production code was developed on v4; v5 receives non-plan changes separately. No contracts or UI repository were changed. + +## Public API addition + +presets.get now returns { rules, readiness }. The existing rules/create/update call shapes remain. New exported types: PresetResult, PresetChainReadiness, PresetConfigurationIssue, PresetCallIssue. Readiness checks local input completeness and at least one enabled asset operation, not deployment, PRC20 support, funds, reserve caps, pauses or liquidity. + +Per-chain metadata names missing identity/expiry/assets/token pair/gas, zero-cap calls, excluded operations, known catalog token addresses, and zero bridge limits. A positive operation cap with maxTotal zero can be ready for destination-held capital; this does not authorize exporting new tokens from Push. No arbitrary token, 0.1 PC budget or 30-day expiry is chosen. + +## Generated restrictions + +- Aave: reserve token EQ, operation amount MAX and wallet beneficiary EQ. Reserve addresses come from the reviewed official bgd-labs address-book snapshots. Unlisted tokens get no positive operation/approval. +- Moonwell/Venus: fixed underlying-token amounts. redeemUnderlying is bounded; share-denominated redeem is excluded and reported with the alternative. +- EigenLayer: chosen token EQ and deposit amount MAX. +- Lido: stETH/wstETH-specific wrap/unwrap caps; native submit value from a selected native asset cap. Dynamic withdrawal arrays and position-derived claims are excluded from bounded presets, with reasons exposed to the UI. +- Approvals retain spender EQ and per-call MAX. Pin/count ceilings are enforced after expansion; no restrictions are silently dropped. + +Regenerate with presets.get after changing inputs, then replace the old rule with rules.update. Merely assigning rule.assets does not regenerate pins/approvals. Save preset provenance/inputs in the UI; contracts do not retain them. [Consumer guide](../../../../packages/core/AGW.md) contains typechecked create/update examples. + +## Important contract boundary + +Operation MAX pins constrain each allowed call. Two calls each at the maximum can share one transaction. Asset maxTotal meters Push outbound amounts, not destination turnover or a lifetime limit on prefunded assets. Neither the SDK nor bounded approvals can supply missing contract-wide accounting. This is stated in the types and guide; ask product/contracts if a different aggregate policy is required. + +## Validation + +- Full unit suite: 2,111 passed, 12 skipped, no failures. +- Focused preset suite: 54 passed. +- Actual v6 local policy tests: 18/18 passed, including the final batch-scope assertion (local-contracts.log). Covers zero-cap previews, token changes, lower limits, old-token rejection, checkpoint-count change of five on update and zero Push spent for destination-only actions. Gateway and UEA-origin response metadata are fixtures; AGW/URP/engine execution uses actual local contracts. An unrelated getOriginForUEA response lookup initially reached Donut and timed out; the test fixture now isolates that metadata lookup, matching the existing delayed-index harness pattern. These tests do not prove destination execution. +- Build, lib/spec/local typechecks, guide and package/import/declaration checks passed. Source/compiled public API comparison matches. Preset lint has no errors (one test non-null assertion warning). + +## Live attempts: not passing acceptance + +The updated Aave test adds an above-cap refusal, regeneration with a lower cap, refusal of the old amount and two bounded withdrawals in one batch. Market tests now redeem in underlying units and check actual burned shares/payout, allowing residual rounding dust. EigenLayer adds wrong-token and above-cap refusals. + +Live attempts timed out before reaching the new operation assertions: + +| Attempt | Recorded transaction / observation | +| --- | --- | +| Aave first | 0xe685f4205cbe59c3acd52a4b4588ae656b7e23127ca68d96ead0b70df2f00578; later read-only Push receipt success at block 24282737 | +| Aave retry | 0xc8b66f3c89b869f9b047baaf52cccf65e9ee176a368b1889ded77b3a5d816b93; Push receipt success at block 24286115; test timed out during destination wait | +| BNB market setup | 0x52732156d51caf9d3d1aa08fd4397be09508553cc4119fc218b92f50eee126e3; receipt wait timed out; subsequent lookup HTTP failed, final state not confirmed | +| Base market setup | 0x72d53c5d0faad5a16eec8f1a1f413757d425ec4237488551b5d2f2436d4e60b2; receipt wait timed out; later Push receipt success at block 24290217 | + +Do not treat these as contract-policy reverts or live passes. Prior successful catalog flows predate these restrictions. Re-run the affected live scenarios once receipt/destination processing is reliable. No further funded retries are running. diff --git a/plan/agw/research/preset-configuration-2026-10-16/aave-first-timeout.log b/plan/agw/research/preset-configuration-2026-10-16/aave-first-timeout.log new file mode 100644 index 00000000..6951c118 --- /dev/null +++ b/plan/agw/research/preset-configuration-2026-10-16/aave-first-timeout.log @@ -0,0 +1,50 @@ +FAIL core-e2e __e2e__/agw/presets-live.spec.ts (1849.518 s) + agw presets live + ✕ 2. Aave preset supplies and withdraws the wallet position (945264 ms) + ○ skipped 1. Uniswap preset swaps from the wallet CEA and rejects a different recipient + + ● agw presets live › 2. Aave preset supplies and withdraws the wallet position + + AgenticRevertError: Timed out while waiting for transaction with hash "0xe685f4205cbe59c3acd52a4b4588ae656b7e23127ca68d96ead0b70df2f00578" to be confirmed. + + 163 | decodedError?: DecodedErrorPayload; + 164 | }; + > 165 | return new AgenticRevertError(e?.message ?? decoded?.name ?? 'AGW revert', { + | ^ + 166 | decodedError: decoded ?? e?.decodedError, + 167 | gatewayTxHash: e?.gatewayTxHash, + 168 | agenticCode: decoded?.name, + + at wrapSendError (src/lib/agentic/management/common.ts:165:12) + at agenticSend (src/lib/agentic/execution/send.ts:340:34) + at async Object. (__e2e__/agw/presets-live.spec.ts:292:18) + + Cause: + PushChainExecutionError: Timed out while waiting for transaction with hash "0xe685f4205cbe59c3acd52a4b4588ae656b7e23127ca68d96ead0b70df2f00578" to be confirmed. + + 186 | ctx._routeTerminalEmitted = true; + 187 | if (!isUserDecline && !(err instanceof PushChainExecutionError)) { + > 188 | throw new PushChainExecutionError(errMsg, { cause: err }); + | ^ + 189 | } + 190 | throw err; + 191 | } + + at executeStandardPayload (src/lib/orchestrator/internals/execute-standard.ts:188:15) + at async Orchestrator.executeWithPolicy (src/lib/orchestrator/orchestrator.ts:471:11) + at async agenticSend (src/lib/agentic/execution/send.ts:330:9) + at async Object. (__e2e__/agw/presets-live.spec.ts:292:18) + + Cause: + WaitForTransactionReceiptTimeoutError: Timed out while waiting for transaction with hash "0xe685f4205cbe59c3acd52a4b4588ae656b7e23127ca68d96ead0b70df2f00578" to be confirmed. + + Version: viem@2.27.2 + + at Timeout._onTimeout (../../node_modules/viem/actions/public/waitForTransactionReceipt.ts:160:22) + +Test Suites: 1 failed, 1 total +Tests: 1 failed, 1 skipped, 2 total +Snapshots: 0 total +Time: 1849.528 s +Ran all test suites within paths "__e2e__/agw/presets-live.spec.ts". +Force exiting Jest: Have you considered using `--detectOpenHandles` to detect async operations that kept running after all tests finished? diff --git a/plan/agw/research/preset-configuration-2026-10-16/aave-second-timeout.log b/plan/agw/research/preset-configuration-2026-10-16/aave-second-timeout.log new file mode 100644 index 00000000..692bf77d --- /dev/null +++ b/plan/agw/research/preset-configuration-2026-10-16/aave-second-timeout.log @@ -0,0 +1,27 @@ +FAIL core-e2e __e2e__/agw/presets-live.spec.ts (1847.916 s) + agw presets live + ✕ 2. Aave preset supplies and withdraws the wallet position (946467 ms) + ○ skipped 1. Uniswap preset swaps from the wallet CEA and rejects a different recipient + + ● agw presets live › 2. Aave preset supplies and withdraws the wallet position + + thrown: "Exceeded timeout of 900000 ms for a test. + Add a timeout value to this test to increase the timeout, if this is a long-running test. See https://jestjs.io/docs/api#testname-fn-timeout." + + 225 | }); + 226 | }, 900_000); + > 227 | it('2. Aave preset supplies and withdraws the wallet position', async () => { + | ^ + 228 | const mockLINK = '0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5' as Address; + 229 | const faucet = '0xC959483DBa39aa9E78757139af0e9a2EDEb3f42D' as Address; + 230 | const amount = BigInt(10) ** BigInt(12); + + at __e2e__/agw/presets-live.spec.ts:227:3 + at Object. (__e2e__/agw/presets-live.spec.ts:46:1) + +Test Suites: 1 failed, 1 total +Tests: 1 failed, 1 skipped, 2 total +Snapshots: 0 total +Time: 1847.938 s, estimated 1850 s +Ran all test suites within paths "__e2e__/agw/presets-live.spec.ts". +Force exiting Jest: Have you considered using `--detectOpenHandles` to detect async operations that kept running after all tests finished? diff --git a/plan/agw/research/preset-configuration-2026-10-16/api.json b/plan/agw/research/preset-configuration-2026-10-16/api.json new file mode 100644 index 00000000..a13a6f22 --- /dev/null +++ b/plan/agw/research/preset-configuration-2026-10-16/api.json @@ -0,0 +1,11654 @@ +{ + "baseline": "b1597b91a25dbf7f691f589b4e1e154add604315", + "head": "a77a104b2a9c6d8477851d3b4cb83b8daf542d14", + "compiledMatchesSource": true, + "initializeSignatureChanged": false, + "addedExports": [ + "AgenticPresets", + "ArgumentPath", + "DecodedSolanaRule", + "Pin", + "Preset", + "PresetAsset", + "PresetCallIssue", + "PresetCategory", + "PresetChainReadiness", + "PresetConfigurationIssue", + "PresetOptions", + "PresetResult", + "PresetRuleTemplate", + "ReadyPresetOptions", + "RuleInput", + "Spent", + "WalletMarker" + ], + "removedExports": [ + "AgenticNetworkConstants", + "NativeRule", + "UniversalRule" + ], + "changedAgwTypes": [ + "AgenticWallet", + "AgenticError", + "AgenticRevertError", + "AGENTIC_ERROR_CODE", + "Rule", + "RuleInput", + "Pin", + "Spent", + "NativeRule", + "AssetCap", + "AllowedCall", + "UniversalRule", + "RulesRecord", + "CreateOptions", + "AgenticTxMetadata" + ], + "publicTypeChanges": [ + "AGENTIC_ERROR_CODE", + "AgenticError", + "AgenticRevertError", + "AgenticErrorCode", + "AgenticTxMetadata", + "AgenticWallet", + "AllowedCall", + "AssetCap", + "CreateOptions", + "DecodedSolanaRule", + "Rule", + "RuleInput", + "Pin", + "Spent", + "WalletMarker", + "ArgumentPath", + "RulesRecord", + "Preset", + "PresetCategory", + "PresetAsset", + "PresetOptions", + "ReadyPresetOptions", + "PresetRuleTemplate", + "PresetResult", + "PresetChainReadiness", + "PresetConfigurationIssue", + "PresetCallIssue", + "AgenticPresets" + ], + "transactionMethodChanges": [], + "instanceMethodChanges": [], + "agwConstantsChanged": true, + "before": { + "exports": [ + "AGENTIC_ERROR_CODE", + "AccountRole", + "AccountStatus", + "AccountType", + "AgenticAddress", + "AgenticDoor", + "AgenticError", + "AgenticErrorCode", + "AgenticHex", + "AgenticNamespace", + "AgenticNetworkConstants", + "AgenticProgressHook", + "AgenticRevertError", + "AgenticTxMetadata", + "AgenticWallet", + "AllowedCall", + "AssetCap", + "BatchReadResponse", + "BuildReadSpecParams", + "CHAIN", + "CONTRACT_REQUEST_STATUS", + "CascadeCompletionResult", + "CascadeHopInfo", + "CascadeProgressEvent", + "CascadeTrackOptions", + "CascadedTxResponse", + "ChainSource", + "ChainTarget", + "Checkpoint", + "CheckpointKind", + "ConversionQuote", + "CreateOptions", + "CreateResult", + "DEFAULT_MAX_PC_FOR_GAS_BUFFER_BPS", + "DecodedErrorPayload", + "DecodedReadResult", + "DerivedExecutorAccount", + "EncodedReadQuery", + "EvmReadQuery", + "ForeignChainNamespace", + "FulfilOutcome", + "FundsToken", + "InsufficientPC20BalanceError", + "InvalidPC20AddressError", + "InvalidPC20MetadataError", + "InvalidReadQueryError", + "InvalidReadSpecError", + "MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT", + "MaxPCForGasCapFromNativeValueInput", + "MaxPCForGasCapInput", + "MaxPCForGasCapQuote", + "MultiChainTxResponse", + "NativeRule", + "OutboundTxDetails", + "PC20AddressResult", + "PC20AmbiguousAddressError", + "PC20Error", + "PC20ExpectedButPRC20Error", + "PC20ExportRevertedError", + "PC20FactoryMismatchError", + "PC20RegistryEntry", + "PC20RegistryMismatchError", + "PC20TokenChainMismatchError", + "PC20TokenReference", + "PC20UnknownChainNamespaceError", + "PC20UnsafeEmptyPayloadError", + "PC20WrapperNotRegisteredError", + "PC20WrapperPredictionUnavailableError", + "ParsedReadRequest", + "PreparedRead", + "PreparedUniversalTx", + "PushChain", + "PushChainBatchExecutionError", + "PushChainExecutionError", + "PushChainInitializeOptions", + "READ_ERROR_CODE", + "READ_OUTCOME", + "READ_STATUS", + "ReadCallback", + "ReadCallbackOptions", + "ReadChain", + "ReadDecodeError", + "ReadDestination", + "ReadExecuteOptions", + "ReadFees", + "ReadHeightUnavailableError", + "ReadLifecycleOptions", + "ReadNotFoundError", + "ReadOptions", + "ReadPreflight", + "ReadPrepareOptions", + "ReadQuery", + "ReadQueryOptions", + "ReadRef", + "ReadRegistryUnavailableError", + "ReadResponseTuple", + "ReadResultShape", + "ReadSpec", + "ReadSpecTuple", + "ReadSpecViolation", + "ReadStateError", + "ReadTimeoutError", + "ReadTrackOptions", + "ReadValue", + "ReadWeb2Options", + "ReceiptLike", + "RescueFundsParams", + "ResolvedAccount", + "ResolvedControllerAccounts", + "ResolvedDestination", + "Rule", + "RulesRecord", + "Selector", + "SignAuthorizationParams", + "SignedAuthorization", + "SimulateReadResult", + "SvmExecutePayloadFields", + "SvmGatewayAccountMeta", + "SvmReadQuery", + "TERMINAL_READ_STATUSES", + "TransactionRoute", + "TransactionRouteType", + "UEAStatus", + "UNIVERSAL_CALLBACK_EVM", + "UNIVERSAL_READ_REGISTRY_EVM", + "UNIVERSAL_READ_STATUS", + "UniversalAccount", + "UniversalExecuteParams", + "UniversalOutboundTxRequest", + "UniversalReadResponse", + "UniversalRule", + "UniversalSigner", + "UniversalSignerSkeleton", + "UniversalTo", + "UnsupportedPC20DestinationError", + "UnsupportedReadDestinationError", + "ValidateReadCall", + "WaitForOutboundOptions", + "WalletInfo", + "WalletSummary", + "Web2Extract", + "Web2ReadQuery", + "Web2ValueType", + "buildErc20WithdrawalMulticall", + "buildMigrationPayload", + "buildReadSpecFromPreflight", + "chainSupportsCEA", + "chainSupportsOutbound", + "decodeReadResult", + "detectRoute", + "encodeReadQuery", + "encodeSvmExecutePayload", + "getAllCEAAddresses", + "getCEAAddress", + "getCEAFactoryAddress", + "getPushAccountForCEA", + "inferResultShape", + "isCEA", + "isChainTarget", + "isPC20Reference", + "isSvmChain", + "isValidSolanaHexAddress", + "parseFulfilOutcome", + "parseReadRequestsFromReceipt", + "parseUEAVersion", + "quoteMaxPCForGasCap", + "quoteMaxPCForGasCapFromNativeValue", + "resolveDestination", + "sizeCallbackBudget", + "toCallData", + "toReadQuery", + "toRequestIdHex", + "validateReadSpec" + ], + "agw": { + "AgenticNamespace": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace", + "members": { + "create": { + "optional": false, + "readonly": false, + "type": "(label: string, options: import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions) => Promise" + }, + "derive": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n index?: number;\n}) => Promise<{\n address: `0x${string}`;\n deployed: boolean;\n index: number;\n}>" + }, + "list": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n wallets: import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary[];\n}>" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "(address: `0x${string}`) => import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet" + } + } + }, + "AgenticWallet": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "checkpoints": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n sinceBlock?: bigint;\n}) => Promise<{\n checkpoints: import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint[];\n}>" + }, + "info": { + "optional": false, + "readonly": false, + "type": "() => Promise" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n owner: `0x${string}`;\n}>" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "{\n add(rules: import(\"sdk/src/lib/agentic/agentic.types\").Rule[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise<{\n rulesIds: `0x${string}`[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n get(rulesId: `0x${string}`): Promise;\n list(): Promise<{\n rules: import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord[];\n }>;\n revoke(rulesIds: `0x${string}`[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n revoke(params: {\n all: true;\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n update(params: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n rules: {\n rule: import(\"sdk/src/lib/agentic/agentic.types\").Rule;\n rulesId: `0x${string}`;\n }[];\n }): Promise<{\n rules: {\n replaced: `0x${string}`;\n rulesId: `0x${string}`;\n }[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n}" + }, + "setLabel": { + "optional": false, + "readonly": false, + "type": "(label: string, opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n}) => Promise" + } + } + }, + "AgenticError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"CREATE_PARTIAL\" | \"DUPLICATE_RULE\" | \"FROM_NOT_ALLOWED\" | \"GATEWAY_ALLOWANCE_INSUFFICIENT\" | \"GENERATION_UNSUPPORTED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"REVOKE_NEEDS_TARGET\" | \"RULE_LIMIT_EXCEEDED\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"" + }, + "details": { + "optional": true, + "readonly": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "AgenticRevertError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticRevertError", + "members": { + "agenticCode": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + } + } + }, + "AGENTIC_ERROR_CODE": { + "type": "{\n readonly AGENT_GAS_INSUFFICIENT: \"AGENT_GAS_INSUFFICIENT\";\n readonly AGENT_IS_OWNER: \"AGENT_IS_OWNER\";\n readonly ASSET_CHAIN_MISMATCH: \"ASSET_CHAIN_MISMATCH\";\n readonly CAPABILITY_UNAVAILABLE: \"CAPABILITY_UNAVAILABLE\";\n readonly CREATE_PARTIAL: \"CREATE_PARTIAL\";\n readonly DUPLICATE_RULE: \"DUPLICATE_RULE\";\n readonly FROM_NOT_ALLOWED: \"FROM_NOT_ALLOWED\";\n readonly GATEWAY_ALLOWANCE_INSUFFICIENT: \"GATEWAY_ALLOWANCE_INSUFFICIENT\";\n readonly GENERATION_UNSUPPORTED: \"GENERATION_UNSUPPORTED\";\n readonly INCONSISTENT_READ: \"INCONSISTENT_READ\";\n readonly INDEX_RACE: \"INDEX_RACE\";\n readonly INVALID_RULE: \"INVALID_RULE\";\n readonly NO_RULES_FOR_CHAIN: \"NO_RULES_FOR_CHAIN\";\n readonly NOT_AGENTIC_WALLET: \"NOT_AGENTIC_WALLET\";\n readonly NOT_ALLOWED_IN_AGENTIC_MODE: \"NOT_ALLOWED_IN_AGENTIC_MODE\";\n readonly NOT_OWNER_OR_AGENT: \"NOT_OWNER_OR_AGENT\";\n readonly NOT_WALLET_OWNER: \"NOT_WALLET_OWNER\";\n readonly READ_ONLY: \"READ_ONLY\";\n readonly RECEIPT_MISMATCH: \"RECEIPT_MISMATCH\";\n readonly RECEIPT_UNAVAILABLE: \"RECEIPT_UNAVAILABLE\";\n readonly REVOKE_NEEDS_TARGET: \"REVOKE_NEEDS_TARGET\";\n readonly RULE_LIMIT_EXCEEDED: \"RULE_LIMIT_EXCEEDED\";\n readonly RULE_NOT_FOUND: \"RULE_NOT_FOUND\";\n readonly RULE_READ_FAILED: \"RULE_READ_FAILED\";\n readonly TARGET_NOT_ON_RULE_CHAIN: \"TARGET_NOT_ON_RULE_CHAIN\";\n readonly WALLET_BALANCE_INSUFFICIENT: \"WALLET_BALANCE_INSUFFICIENT\";\n readonly WALLET_NOT_DEPLOYED: \"WALLET_NOT_DEPLOYED\";\n}", + "members": { + "AGENT_GAS_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\"" + }, + "AGENT_IS_OWNER": { + "optional": false, + "readonly": true, + "type": "\"AGENT_IS_OWNER\"" + }, + "ASSET_CHAIN_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"ASSET_CHAIN_MISMATCH\"" + }, + "CAPABILITY_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"CAPABILITY_UNAVAILABLE\"" + }, + "CREATE_PARTIAL": { + "optional": false, + "readonly": true, + "type": "\"CREATE_PARTIAL\"" + }, + "DUPLICATE_RULE": { + "optional": false, + "readonly": true, + "type": "\"DUPLICATE_RULE\"" + }, + "FROM_NOT_ALLOWED": { + "optional": false, + "readonly": true, + "type": "\"FROM_NOT_ALLOWED\"" + }, + "GATEWAY_ALLOWANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"GATEWAY_ALLOWANCE_INSUFFICIENT\"" + }, + "GENERATION_UNSUPPORTED": { + "optional": false, + "readonly": true, + "type": "\"GENERATION_UNSUPPORTED\"" + }, + "INCONSISTENT_READ": { + "optional": false, + "readonly": true, + "type": "\"INCONSISTENT_READ\"" + }, + "INDEX_RACE": { + "optional": false, + "readonly": true, + "type": "\"INDEX_RACE\"" + }, + "INVALID_RULE": { + "optional": false, + "readonly": true, + "type": "\"INVALID_RULE\"" + }, + "NO_RULES_FOR_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"NO_RULES_FOR_CHAIN\"" + }, + "NOT_AGENTIC_WALLET": { + "optional": false, + "readonly": true, + "type": "\"NOT_AGENTIC_WALLET\"" + }, + "NOT_ALLOWED_IN_AGENTIC_MODE": { + "optional": false, + "readonly": true, + "type": "\"NOT_ALLOWED_IN_AGENTIC_MODE\"" + }, + "NOT_OWNER_OR_AGENT": { + "optional": false, + "readonly": true, + "type": "\"NOT_OWNER_OR_AGENT\"" + }, + "NOT_WALLET_OWNER": { + "optional": false, + "readonly": true, + "type": "\"NOT_WALLET_OWNER\"" + }, + "READ_ONLY": { + "optional": false, + "readonly": true, + "type": "\"READ_ONLY\"" + }, + "RECEIPT_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_MISMATCH\"" + }, + "RECEIPT_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_UNAVAILABLE\"" + }, + "REVOKE_NEEDS_TARGET": { + "optional": false, + "readonly": true, + "type": "\"REVOKE_NEEDS_TARGET\"" + }, + "RULE_LIMIT_EXCEEDED": { + "optional": false, + "readonly": true, + "type": "\"RULE_LIMIT_EXCEEDED\"" + }, + "RULE_NOT_FOUND": { + "optional": false, + "readonly": true, + "type": "\"RULE_NOT_FOUND\"" + }, + "RULE_READ_FAILED": { + "optional": false, + "readonly": true, + "type": "\"RULE_READ_FAILED\"" + }, + "TARGET_NOT_ON_RULE_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"TARGET_NOT_ON_RULE_CHAIN\"" + }, + "WALLET_BALANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"WALLET_BALANCE_INSUFFICIENT\"" + }, + "WALLET_NOT_DEPLOYED": { + "optional": false, + "readonly": true, + "type": "\"WALLET_NOT_DEPLOYED\"" + } + } + }, + "Rule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule | import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "NativeRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "amount": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AmountLimit | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "maxCalls": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValuePerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxValueTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "pins": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ArgPin[] | undefined" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "AssetCap": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap", + "members": { + "maxPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/constants/tokens\").MoveableToken" + } + } + }, + "AllowedCall": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall", + "members": { + "beneficiary": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValue": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "`${string}(${string})` | `0x${string}`" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "UniversalRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall[]" + }, + "assets": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap[]" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "`eip155:${string}` | `solana:${string}`" + }, + "maxGasPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "RulesRecord": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "enabled": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "ref": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "rule": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule | import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule" + }, + "rulesId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "CreateOptions": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions", + "members": { + "progressHook": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook | undefined" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Rule[]" + } + } + }, + "CreateResult": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateResult", + "members": { + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "rulesIds": { + "optional": false, + "readonly": false, + "type": "`0x${string}`[]" + }, + "tx": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticTxMetadata": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticTxMetadata", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destinationAccount": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "destinationCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "door": { + "optional": false, + "readonly": false, + "type": "\"agent\" | \"owner\"" + }, + "nativeCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "rawData": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rawTo": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesId": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + } + }, + "publicSurface": { + "CHAIN": { + "type": "typeof import(\"sdk/src/lib/constants/enums\").CHAIN", + "members": { + "ARBITRUM_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA" + }, + "BASE_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA" + }, + "BNB_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET" + }, + "ETHEREUM_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET" + }, + "ETHEREUM_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA" + }, + "PUSH_LOCALNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET" + }, + "PUSH_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET" + }, + "PUSH_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET" + }, + "PUSH_TESTNET_DONUT": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET" + }, + "SOLANA_DEVNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET" + }, + "SOLANA_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET" + }, + "SOLANA_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET" + }, + "WEB2": { + "optional": false, + "readonly": false, + "type": "\"web2\"" + } + } + }, + "ConversionQuote": { + "type": "import(\"sdk/src/lib/constants/tokens\").ConversionQuote", + "members": { + "amountIn": { + "optional": false, + "readonly": false, + "type": "string" + }, + "amountOut": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rate": { + "optional": false, + "readonly": false, + "type": "number" + }, + "route": { + "optional": true, + "readonly": false, + "type": "string[] | undefined" + }, + "timestamp": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "UniversalSigner": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalSigner", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "signAndSendTransaction": { + "optional": false, + "readonly": false, + "type": "(unsignedTx: Uint8Array) => Promise" + }, + "signAuthorization": { + "optional": true, + "readonly": false, + "type": "((params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise) | undefined" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": true, + "readonly": false, + "type": "(({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise) | undefined" + } + } + }, + "UniversalAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "UniversalSignerSkeleton": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "signAndSendTransaction": { + "optional": false, + "readonly": false, + "type": "(unsignedTx: Uint8Array) => Promise" + }, + "signAuthorization": { + "optional": true, + "readonly": false, + "type": "((params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise) | undefined" + }, + "signerId": { + "optional": false, + "readonly": false, + "type": "string" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": true, + "readonly": false, + "type": "(({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise) | undefined" + } + } + }, + "SignAuthorizationParams": { + "type": "{\n chainId?: number;\n contractAddress: `0x${string}`;\n executor?: \"self\";\n nonce?: number;\n}", + "members": { + "chainId": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "contractAddress": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "executor": { + "optional": true, + "readonly": false, + "type": "\"self\" | undefined" + }, + "nonce": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "SignedAuthorization": { + "type": "{\n address: `0x${string}`;\n chainId: number;\n nonce: number;\n r: `0x${string}`;\n s: `0x${string}`;\n v?: bigint;\n yParity: number;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainId": { + "optional": false, + "readonly": false, + "type": "number" + }, + "nonce": { + "optional": false, + "readonly": false, + "type": "number" + }, + "r": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "s": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "v": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "yParity": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "DerivedExecutorAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").DerivedExecutorAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean | null" + } + } + }, + "ResolvedAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainName": { + "optional": false, + "readonly": false, + "type": "string" + }, + "exists": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "role": { + "optional": true, + "readonly": false, + "type": "\"controller\" | undefined" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"cea\" | \"uea\" | \"uoa\"" + } + } + }, + "ResolvedControllerAccounts": { + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedControllerAccounts", + "members": { + "accounts": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedAccount[]" + } + } + }, + "AccountType": { + "type": "\"cea\" | \"uea\" | \"uoa\"", + "members": {} + }, + "AccountRole": { + "type": "\"controller\"", + "members": {} + }, + "PC20TokenReference": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "FundsToken": { + "type": "import(\"sdk/src/lib/constants/tokens\").MoveableToken | import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20TokenReference", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "PC20RegistryEntry": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "chainName": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "PC20AddressResult": { + "type": "{\n address: `0x${string}`;\n decimals: number;\n name: string;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n registry: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20RegistryEntry[];\n symbol: string;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "decimals": { + "optional": false, + "readonly": false, + "type": "number" + }, + "name": { + "optional": false, + "readonly": false, + "type": "string" + }, + "network": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "registry": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20RegistryEntry[]" + }, + "symbol": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "isPC20Reference": { + "type": "(token: import(\"sdk/src/lib/orchestrator/orchestrator.types\").FundsToken | undefined) => token is import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20TokenReference", + "members": {} + }, + "PC20Error": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20Error", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidPC20AddressError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InvalidPC20AddressError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20TokenChainMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20TokenChainMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20WrapperNotRegisteredError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20WrapperNotRegisteredError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20RegistryMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20RegistryMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20FactoryMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20FactoryMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidPC20MetadataError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InvalidPC20MetadataError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20ExpectedButPRC20Error": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20ExpectedButPRC20Error", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20AmbiguousAddressError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20AmbiguousAddressError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "candidates": { + "optional": false, + "readonly": true, + "type": "{\n chain: string;\n pushAddress: string;\n}[]" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "UnsupportedPC20DestinationError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").UnsupportedPC20DestinationError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InsufficientPC20BalanceError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InsufficientPC20BalanceError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20UnknownChainNamespaceError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20UnknownChainNamespaceError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20WrapperPredictionUnavailableError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20WrapperPredictionUnavailableError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20ExportRevertedError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20ExportRevertedError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "lockedAmount": { + "optional": true, + "readonly": true, + "type": "bigint | undefined" + }, + "outboundTxId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "revertRecipient": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20UnsafeEmptyPayloadError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20UnsafeEmptyPayloadError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ChainTarget": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "ChainSource": { + "type": "{\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "UniversalTo": { + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget", + "members": {} + }, + "TransactionRouteType": { + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"", + "members": {} + }, + "UniversalExecuteParams": { + "type": "{\n from?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainSource;\n migration?: boolean;\n to: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTo;\n} & Omit", + "members": { + "_minimumDepositUsd": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "_requiredFundsOverride": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "_skipFeeLocking": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "_ueaStatus": { + "optional": true, + "readonly": false, + "type": "{\n balance: bigint;\n isDeployed: boolean;\n nonce: bigint;\n} | undefined" + }, + "data": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiCall[] | undefined" + }, + "deadline": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "feeLockTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "from": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainSource | undefined" + }, + "funds": { + "optional": true, + "readonly": false, + "type": "{\n amount: bigint;\n token?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").FundsToken;\n} | undefined" + }, + "gasLimit": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFeePerGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxPCForGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxPriorityFeePerGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "migration": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "nonce": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "options": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions | undefined" + }, + "payGasWith": { + "optional": true, + "readonly": false, + "type": "{\n minAmountOut?: bigint | string;\n slippageBps?: number;\n token?: import(\"sdk/src/lib/constants/tokens\").PayableToken;\n} | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "to": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget" + }, + "value": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "UniversalOutboundTxRequest": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalOutboundTxRequest", + "members": { + "amount": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gasPrice": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxPCForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "payload": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "recipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "revertRecipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "PreparedUniversalTx": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx", + "members": { + "_hop": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").HopDescriptor" + }, + "deadline": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "estimatedGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gatewayRequest": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalOutboundTxRequest | import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxRequest" + }, + "nonce": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "payload": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + } + } + }, + "CascadedTxResponse": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadedTxResponse", + "members": { + "finalTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hopCount": { + "optional": false, + "readonly": false, + "type": "number" + }, + "hops": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo[]" + }, + "initialTxHash": { + "optional": false, + "readonly": false, + "type": "string" + }, + "initialTxResponse": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions) => Promise" + }, + "waitForAll": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions) => Promise" + } + } + }, + "CascadeHopInfo": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo", + "members": { + "executionChain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "expectedSubTxId": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hopIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "outboundDetails": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").OutboundTxDetails | undefined" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + }, + "status": { + "optional": false, + "readonly": false, + "type": "\"confirmed\" | \"failed\" | \"pending\" | \"submitted\"" + }, + "txHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "CascadeTrackOptions": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions", + "members": { + "eventHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeProgressEvent) => void) | undefined" + }, + "timeout": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "CascadeProgressEvent": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeProgressEvent", + "members": { + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "elapsed": { + "optional": false, + "readonly": false, + "type": "number" + }, + "hopIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + }, + "status": { + "optional": false, + "readonly": false, + "type": "\"confirmed\" | \"failed\" | \"found\" | \"polling\" | \"timeout\" | \"waiting\"" + }, + "txHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "CascadeCompletionResult": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeCompletionResult", + "members": { + "failedAt": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "finalTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "finalTxResponse": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadedTxResponse | undefined" + }, + "hops": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo[]" + }, + "success": { + "optional": false, + "readonly": false, + "type": "boolean" + } + } + }, + "MultiChainTxResponse": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiChainTxResponse", + "members": { + "chains": { + "optional": false, + "readonly": false, + "type": "{\n blockNumber: bigint;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n hash: string;\n status: \"confirmed\" | \"failed\" | \"pending\";\n}[]" + }, + "transactions": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse[]" + } + } + }, + "OutboundTxDetails": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").OutboundTxDetails", + "members": { + "amount": { + "optional": false, + "readonly": false, + "type": "string" + }, + "assetAddr": { + "optional": false, + "readonly": false, + "type": "string" + }, + "destinationChain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "explorerUrl": { + "optional": false, + "readonly": false, + "type": "string" + }, + "externalTxHash": { + "optional": false, + "readonly": false, + "type": "string" + }, + "recipient": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "WaitForOutboundOptions": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").WaitForOutboundOptions", + "members": { + "_expectedDestinationChain": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "_outboundIndex": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "_resolvedSubTxId": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "initialWaitMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: {\n elapsed: number;\n status: \"failed\" | \"found\" | \"polling\" | \"timeout\" | \"waiting\";\n}) => void) | undefined" + }, + "timeout": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "SvmGatewayAccountMeta": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmGatewayAccountMeta", + "members": { + "isWritable": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "pubkey": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "SvmExecutePayloadFields": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmExecutePayloadFields", + "members": { + "accounts": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmGatewayAccountMeta[]" + }, + "instructionId": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "ixData": { + "optional": false, + "readonly": false, + "type": "Uint8Array" + }, + "targetProgram": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AccountStatus": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus", + "members": { + "mode": { + "optional": false, + "readonly": false, + "type": "\"read-only\" | \"signer\"" + }, + "uea": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UEAStatus" + } + } + }, + "UEAStatus": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UEAStatus", + "members": { + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "loaded": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "minRequiredVersion": { + "optional": false, + "readonly": false, + "type": "string" + }, + "requiresUpgrade": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "version": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "RescueFundsParams": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").RescueFundsParams", + "members": { + "prc20": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "universalTxId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "parseUEAVersion": { + "type": "(version: string) => number", + "members": {} + }, + "TransactionRoute": { + "type": "typeof import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute", + "members": { + "CEA_TO_CEA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.CEA_TO_CEA" + }, + "CEA_TO_PUSH": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.CEA_TO_PUSH" + }, + "UOA_TO_CEA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.UOA_TO_CEA" + }, + "UOA_TO_PUSH": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.UOA_TO_PUSH" + } + } + }, + "detectRoute": { + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams) => import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute", + "members": {} + }, + "isChainTarget": { + "type": "(to: unknown) => to is import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget", + "members": {} + }, + "DEFAULT_MAX_PC_FOR_GAS_BUFFER_BPS": { + "type": "1000", + "members": {} + }, + "MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT": { + "type": "10000", + "members": {} + }, + "quoteMaxPCForGasCap": { + "type": "(input: import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapInput) => import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": {} + }, + "quoteMaxPCForGasCapFromNativeValue": { + "type": "(input: import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapFromNativeValueInput) => import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": {} + }, + "MaxPCForGasCapInput": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapInput", + "members": { + "bufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "gasLegNativePc": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "MaxPCForGasCapFromNativeValueInput": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapFromNativeValueInput", + "members": { + "bufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "nativeValueForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "MaxPCForGasCapQuote": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": { + "bufferBps": { + "optional": false, + "readonly": false, + "type": "number" + }, + "gasLegNativePc": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxPCForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "nativeValueForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "getCEAAddress": { + "type": "(ueaAddress: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise", + "members": {} + }, + "getPushAccountForCEA": { + "type": "(ceaAddress: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise<`0x${string}`>", + "members": {} + }, + "isCEA": { + "type": "(address: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise", + "members": {} + }, + "chainSupportsCEA": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "chainSupportsOutbound": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "getCEAFactoryAddress": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => `0x${string}` | undefined", + "members": {} + }, + "getAllCEAAddresses": { + "type": "(ueaAddress: `0x${string}`, rpcUrls?: Partial>) => Promise", + "members": {} + }, + "encodeSvmExecutePayload": { + "type": "(fields: import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmExecutePayloadFields) => `0x${string}`", + "members": {} + }, + "isSvmChain": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "isValidSolanaHexAddress": { + "type": "(address: string) => boolean", + "members": {} + }, + "buildMigrationPayload": { + "type": "() => `0x${string}`", + "members": {} + }, + "buildErc20WithdrawalMulticall": { + "type": "(tokenAddress: `0x${string}`, recipientAddress: `0x${string}`, amount: bigint) => import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiCall[]", + "members": {} + }, + "ReadChain": { + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain", + "members": {} + }, + "ReadDestination": { + "type": "{\n chain: import(\"sdk/src/lib/read-state/read-state.types\").ReadChain;\n} | {\n chainId: string;\n chainNamespace: string;\n}", + "members": {} + }, + "ResolvedDestination": { + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}", + "members": { + "caip2": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainId": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "namespace": { + "optional": false, + "readonly": false, + "type": "\"eip155\" | \"solana\" | \"web2\"" + } + } + }, + "ReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").SvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery", + "members": { + "type": { + "optional": false, + "readonly": false, + "type": "\"accountBalance\" | \"contractCall\" | \"http\" | \"lamportBalance\" | \"rawAccountData\" | \"splTokenAccount\" | \"storageSlot\"" + } + } + }, + "EvmReadQuery": { + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n target: `0x${string}`;\n type: \"contractCall\";\n} | {\n callData: `0x${string}`;\n target: `0x${string}`;\n type: \"contractCall\";\n} | {\n slot: `0x${string}` | bigint;\n target: `0x${string}`;\n type: \"storageSlot\";\n} | {\n target: `0x${string}`;\n type: \"accountBalance\";\n}", + "members": { + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"accountBalance\" | \"contractCall\" | \"storageSlot\"" + } + } + }, + "SvmReadQuery": { + "type": "{\n account: string | Uint8Array;\n accountName?: string;\n idl?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n type: \"rawAccountData\";\n} | {\n account: string | Uint8Array;\n type: \"lamportBalance\";\n} | {\n account: string | Uint8Array;\n type: \"splTokenAccount\";\n}", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "string | Uint8Array" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"lamportBalance\" | \"rawAccountData\" | \"splTokenAccount\"" + } + } + }, + "Web2ReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery", + "members": { + "body": { + "optional": true, + "readonly": false, + "type": "string | Uint8Array | undefined" + }, + "extract": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[]" + }, + "headers": { + "optional": true, + "readonly": false, + "type": "Record | undefined" + }, + "method": { + "optional": true, + "readonly": false, + "type": "\"GET\" | \"POST\" | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"http\"" + }, + "url": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "Web2Extract": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract", + "members": { + "decimals": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "path": { + "optional": false, + "readonly": false, + "type": "string" + }, + "valueType": { + "optional": false, + "readonly": false, + "type": "\"bool\" | \"bytes\" | \"int256\" | \"string\" | \"uint256\"" + } + } + }, + "Web2ValueType": { + "type": "\"bool\" | \"bytes\" | \"int256\" | \"string\" | \"uint256\"", + "members": {} + }, + "EncodedReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery", + "members": { + "blockRef": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "encoded": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "namespace": { + "optional": false, + "readonly": false, + "type": "\"eip155\" | \"solana\" | \"web2\"" + }, + "ownerBytes": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "queryType": { + "optional": false, + "readonly": false, + "type": "number" + }, + "resultShape": { + "optional": false, + "readonly": false, + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}" + }, + "warnings": { + "optional": false, + "readonly": false, + "type": "string[]" + } + } + }, + "ReadResultShape": { + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"bytes32\" | \"evmCall\" | \"raw\" | \"svmAccount\" | \"uint256\" | \"web2\"" + } + } + }, + "DecodedReadResult": { + "type": "{\n accountName: string;\n kind: \"svmAccount\";\n value: unknown;\n} | {\n kind: \"bytes32\";\n value: `0x${string}`;\n} | {\n kind: \"evmCall\";\n value: unknown;\n} | {\n kind: \"raw\";\n value: `0x${string}`;\n} | {\n kind: \"uint256\";\n value: bigint;\n} | {\n kind: \"web2\";\n values: readonly unknown[];\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"bytes32\" | \"evmCall\" | \"raw\" | \"svmAccount\" | \"uint256\" | \"web2\"" + } + } + }, + "ReadPreflight": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight", + "members": { + "destination": { + "optional": false, + "readonly": false, + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}" + }, + "fetchedAt": { + "optional": false, + "readonly": false, + "type": "number" + }, + "observedChainHeight": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pushBlockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pushGasPrice": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "universalCallback": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "universalCore": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ReadSpec": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "{\n chainId: string;\n chainNamespace: string;\n owner: `0x${string}`;\n}" + }, + "blockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "expiryPushChainHeight": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "minConfirmations": { + "optional": false, + "readonly": false, + "type": "number" + }, + "query": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "revertRecipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ReadSpecTuple": { + "type": "readonly [\n readonly [\n string,\n string,\n `0x${string}`\n ],\n `0x${string}`,\n number,\n bigint,\n bigint,\n bigint,\n `0x${string}`\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "readonly [\n string,\n string,\n `0x${string}`\n]" + }, + "1": { + "optional": false, + "readonly": true, + "type": "`0x${string}`" + }, + "2": { + "optional": false, + "readonly": true, + "type": "number" + }, + "3": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "4": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "5": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "6": { + "optional": false, + "readonly": true, + "type": "`0x${string}`" + }, + "length": { + "optional": false, + "readonly": true, + "type": "7" + } + } + }, + "BuildReadSpecParams": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").BuildReadSpecParams", + "members": { + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "budgetBuffer": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback | undefined" + }, + "callbackBudget": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "destination": { + "optional": false, + "readonly": false, + "type": "{\n chain: import(\"sdk/src/lib/read-state/read-state.types\").ReadChain;\n} | {\n chainId: string;\n chainNamespace: string;\n}" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "expiryPushChainHeight": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFeeBufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "owner": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "query": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").SvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "PreparedRead": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead", + "members": { + "__@preparedReadValue": { + "optional": true, + "readonly": true, + "type": "T | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback | undefined" + }, + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "encodedQuery": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery" + }, + "encodedSpec": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "fees": { + "optional": false, + "readonly": false, + "type": "{\n callbackBudget: bigint;\n protocolFee: bigint;\n total: bigint;\n}" + }, + "preflight": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "queryKey": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "resultShape": { + "optional": false, + "readonly": false, + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}" + }, + "spec": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec" + }, + "specTuple": { + "optional": false, + "readonly": false, + "type": "readonly [\n readonly [\n string,\n string,\n `0x${string}`\n ],\n `0x${string}`,\n number,\n bigint,\n bigint,\n bigint,\n `0x${string}`\n]" + }, + "value": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "warnings": { + "optional": false, + "readonly": false, + "type": "string[]" + } + } + }, + "ReadCallback": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "((spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpecTuple, callbackGasLimit: bigint) => readonly unknown[]) | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "gasLimit": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "target": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "SimulateReadResult": { + "type": "{\n args?: readonly unknown[];\n error: string;\n errorName?: string;\n ok: false;\n} | {\n ok: true;\n}", + "members": { + "ok": { + "optional": false, + "readonly": false, + "type": "boolean" + } + } + }, + "ParsedReadRequest": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ParsedReadRequest", + "members": { + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackTarget": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "logIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "originalFunder": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "requestId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "requestIdUint": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "spec": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec" + }, + "totalPaid": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "FulfilOutcome": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").FulfilOutcome", + "members": { + "burned": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "delivered": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "expired": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "failReason": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "gasReported": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refunded": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refundFailed": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "ReceiptLike": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike", + "members": { + "logs": { + "optional": false, + "readonly": false, + "type": "readonly {\n address: string;\n data: string;\n logIndex?: number | string;\n topics: readonly string[];\n}[]" + } + } + }, + "ReadRef": { + "type": "{\n requestId: `0x${string}` | bigint;\n} | {\n txHash: `0x${string}`;\n}", + "members": {} + }, + "ReadLifecycleOptions": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadLifecycleOptions", + "members": { + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "resultShape": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadFees": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadFees", + "members": { + "burned": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "paid": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "refunded": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refundFailed": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + } + } + }, + "UniversalReadResponse": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse", + "members": { + "callbackDelivered": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "callbackFailReason": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "decoded": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").DecodedReadResult | undefined" + }, + "decodeError": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destination": { + "optional": false, + "readonly": false, + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}" + }, + "errorMsg": { + "optional": false, + "readonly": false, + "type": "string" + }, + "explorerUrl": { + "optional": false, + "readonly": false, + "type": "string" + }, + "fees": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadFees" + }, + "isTerminal": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "outcome": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME" + }, + "pcTx": { + "optional": false, + "readonly": false, + "type": "readonly {\n blockHeight: number;\n errorMsg: string;\n status: string;\n txHash: `0x${string}`;\n}[]" + }, + "raw": { + "optional": false, + "readonly": false, + "type": "{\n errorCode: import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n resultData: `0x${string}`;\n status: import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n} | null" + }, + "refresh": { + "optional": false, + "readonly": false, + "type": "() => Promise>" + }, + "request": { + "optional": false, + "readonly": false, + "type": "{\n callbackGasLimit: bigint;\n callbackTarget: `0x${string}`;\n createdAtHeight: bigint;\n logIndex: number;\n originalFunder: `0x${string}`;\n refundTo: `0x${string}`;\n spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec;\n}" + }, + "requestId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "requestIdUint": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "status": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "value": { + "optional": true, + "readonly": false, + "type": "T | undefined" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/read-state/read-state.types\").ReadLifecycleOptions) => Promise>" + } + } + }, + "ReadResponseTuple": { + "type": "{\n -readonly [K in keyof R]: import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse ? T : unknown>;\n}", + "members": {} + }, + "BatchReadResponse": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").BatchReadResponse", + "members": { + "atomic": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "count": { + "optional": false, + "readonly": false, + "type": "number" + }, + "reads": { + "optional": false, + "readonly": false, + "type": "{\n -readonly [K in keyof R]: import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse ? T : unknown>;\n}" + }, + "transactionHashes": { + "optional": true, + "readonly": false, + "type": "readonly `0x${string}`[] | undefined" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: Omit) => Promise>" + } + } + }, + "ReadOptions": { + "type": "((import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">)) & {\n callback?: (Pick & Required>) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n };\n}", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "advanced": { + "optional": true, + "readonly": false, + "type": "{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n} | undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "({\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} & {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n}) | ({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick & Pick & Required>) | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadPrepareOptions": { + "type": "((((({\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\">) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n}) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">)) & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n}) | ((({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n}) | ({\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\">)) & {\n blockNumber?: never;\n minConfirmations?: never;\n})) & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n}) & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "advanced": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadQueryOptions": { + "type": "({\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\">) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n}) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n}) | ({\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\">)", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadCallbackOptions": { + "type": "{\n callback?: ({\n gasLimit?: bigint;\n target: `0x${string}`;\n } & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n };\n}", + "members": { + "callback": { + "optional": true, + "readonly": false, + "type": "({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} | undefined" + } + } + }, + "ReadValue": { + "type": "O extends {\n abi: infer A extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: infer F extends string;\n} ? number extends A[\"length\"] ? unknown : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, O extends {\n args: infer Args extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n} ? Args : readonly [\n] extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> ? import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> & readonly [\n] : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>> extends infer Selected ? Selected extends {\n outputs: readonly unknown[];\n type: \"function\";\n} & import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiFunction ? {\n [key in keyof {\n [key in keyof import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"]]: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterToPrimitiveType, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"][key], import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterKind>;\n }]: {\n [key in keyof import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"]]: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterToPrimitiveType, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"][key], import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterKind>;\n }[key];\n} extends infer types ? types extends readonly [\n] ? void : types extends readonly [\n infer type\n] ? type : types : never : never : never : O extends {\n web2: {\n extract: infer E extends readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n };\n} ? {\n readonly [K in keyof E]: {\n bool: boolean;\n bytes: `0x${string}`;\n int256: bigint;\n string: string;\n uint256: bigint;\n }[E[K][\"valueType\"]];\n} : O extends {\n storageSlot: unknown;\n} ? `0x${string}` : O extends {\n idl: infer I extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} ? string extends Extract, string> ? unknown : (O extends {\n functionName: infer N extends string;\n} ? N : undefined) extends string ? import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/index\").IdlAccounts[{\n [K in Extract, string>]: Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : K> extends Lowercase<(O extends {\n functionName: infer N extends string;\n } ? N : undefined) & string extends `${infer H}_${infer T}` ? `${H}${Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : (O extends {\n functionName: infer N extends string;\n } ? N : undefined) & string> ? K : never;\n}[Extract, string>]] : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/index\").IdlAccounts[Extract, string>] : bigint", + "members": {} + }, + "ValidateReadCall": { + "type": "O extends {\n abi: infer A extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: infer F extends string;\n} ? (readonly [\n] extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> ? {\n args?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n} : {\n args: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n}) & {\n functionName: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionName;\n} : O extends {\n functionName: infer N extends string;\n idl: infer I extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} ? string extends Extract, string> ? unknown : [\n {\n [K in Extract, string>]: Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : K> extends Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : N> ? K : never;\n }[Extract, string>]\n] extends [\n never\n] ? {\n functionName: Extract, string>;\n} : unknown : unknown", + "members": {} + }, + "ReadWeb2Options": { + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options", + "members": { + "body": { + "optional": true, + "readonly": false, + "type": "string | Uint8Array | undefined" + }, + "extract": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[]" + }, + "headers": { + "optional": true, + "readonly": false, + "type": "Record | undefined" + }, + "method": { + "optional": true, + "readonly": false, + "type": "\"GET\" | \"POST\" | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadTrackOptions": { + "type": "{\n advanced?: Omit, \"enforceGasCheck\">;\n resultShape?: import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape;\n}", + "members": { + "advanced": { + "optional": true, + "readonly": false, + "type": "Omit<{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n}, \"enforceGasCheck\"> | undefined" + }, + "resultShape": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape | undefined" + } + } + }, + "ReadExecuteOptions": { + "type": "{\n advanced?: {\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n } | undefined;\n progressHook?: ((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined;\n waitForCompletion?: boolean | undefined;\n}", + "members": { + "advanced": { + "optional": true, + "readonly": false, + "type": "{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n} | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + } + } + }, + "UNIVERSAL_READ_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS", + "members": { + "ABORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.ABORTED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.EXPIRED" + }, + "FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.FAILED" + }, + "FULFILLED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.FULFILLED" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.PENDING" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.UNSPECIFIED" + }, + "VOTING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.VOTING" + } + } + }, + "READ_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS", + "members": { + "ERROR": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.ERROR" + }, + "SUCCESS": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.SUCCESS" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.UNSPECIFIED" + } + } + }, + "READ_ERROR_CODE": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE", + "members": { + "INVALID_QUERY": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.INVALID_QUERY" + }, + "INVALID_RESULT": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.INVALID_RESULT" + }, + "NOT_FOUND": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.NOT_FOUND" + }, + "REJECTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.REJECTED" + }, + "REVERTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.REVERTED" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.UNSPECIFIED" + }, + "UNSUPPORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.UNSUPPORTED" + } + } + }, + "READ_OUTCOME": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME", + "members": { + "ABORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.ABORTED" + }, + "CALLBACK_FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.CALLBACK_FAILED" + }, + "DECODE_FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.DECODE_FAILED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.EXPIRED" + }, + "FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.FAILED" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.PENDING" + }, + "SOURCE_ERROR": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.SOURCE_ERROR" + }, + "SUCCESS": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.SUCCESS" + }, + "UNKNOWN": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.UNKNOWN" + } + } + }, + "CONTRACT_REQUEST_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS", + "members": { + "EXECUTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.EXECUTED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.EXPIRED" + }, + "NONE": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.NONE" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.PENDING" + }, + "SETTLED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.SETTLED" + } + } + }, + "TERMINAL_READ_STATUSES": { + "type": "ReadonlySet", + "members": {} + }, + "ReadStateError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadStateError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidReadQueryError": { + "type": "import(\"sdk/src/lib/read-state/errors\").InvalidReadQueryError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidReadSpecError": { + "type": "import(\"sdk/src/lib/read-state/errors\").InvalidReadSpecError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "violations": { + "optional": false, + "readonly": true, + "type": "readonly import(\"sdk/src/lib/read-state/errors\").ReadSpecViolation[]" + } + } + }, + "ReadHeightUnavailableError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadHeightUnavailableError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "UnsupportedReadDestinationError": { + "type": "import(\"sdk/src/lib/read-state/errors\").UnsupportedReadDestinationError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadDecodeError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadDecodeError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadTimeoutError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadTimeoutError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "lastStatus": { + "optional": false, + "readonly": true, + "type": "number" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadNotFoundError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadNotFoundError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadRegistryUnavailableError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadRegistryUnavailableError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadSpecViolation": { + "type": "\"CALLBACK_GAS_LIMIT_EXCEEDED\" | \"DOMAIN_BLOCKED\" | \"EMPTY_QUERY\" | \"EXCESSIVE_FEE\" | \"INSUFFICIENT_CALLBACK_BUDGET\" | \"INSUFFICIENT_FEE\" | \"INVALID_ACCOUNT_ID\" | \"INVALID_BLOCK_NUMBER\" | \"INVALID_EXPIRY_HEIGHT\" | \"INVALID_MIN_CONFIRMATIONS\" | \"SVM_OWNER_NOT_32_BYTES\" | \"ZERO_CALLBACK_BUDGET\" | \"ZERO_CALLBACK_GAS_LIMIT\" | \"ZERO_REVERT_RECIPIENT\"", + "members": {} + }, + "resolveDestination": { + "type": "(dest: import(\"sdk/src/lib/read-state/read-state.types\").ReadDestination) => import(\"sdk/src/lib/read-state/read-state.types\").ResolvedDestination", + "members": {} + }, + "encodeReadQuery": { + "type": "(destination: import(\"sdk/src/lib/read-state/read-state.types\").ReadDestination, query: import(\"sdk/src/lib/read-state/read-state.types\").ReadQuery, options?: {\n blockNumber?: bigint;\n minSlot?: bigint;\n}) => import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery", + "members": {} + }, + "decodeReadResult": { + "type": "(resultData: `0x${string}`, shape: import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape) => import(\"sdk/src/lib/read-state/read-state.types\").DecodedReadResult", + "members": {} + }, + "parseReadRequestsFromReceipt": { + "type": "(receipt: import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike, universalCallback: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").ParsedReadRequest[]", + "members": {} + }, + "parseFulfilOutcome": { + "type": "(receipt: import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike, universalCallback: `0x${string}`, requestId: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").FulfilOutcome", + "members": {} + }, + "buildReadSpecFromPreflight": { + "type": "(preflight: import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight, params: import(\"sdk/src/lib/read-state/read-state.types\").BuildReadSpecParams, defaults?: {\n refundTo?: `0x${string}`;\n}) => import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead", + "members": {} + }, + "validateReadSpec": { + "type": "(input: import(\"sdk/src/lib/read-state/validate\").ValidateReadSpecInput) => {\n ok: false;\n violations: import(\"sdk/src/lib/read-state/errors\").ReadSpecViolation[];\n} | {\n ok: true;\n}", + "members": {} + }, + "toCallData": { + "type": "(prepared: import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead, target: {\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: (spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpecTuple, callbackGasLimit: bigint) => readonly unknown[];\n functionName: string;\n}) => {\n data: `0x${string}`;\n value: bigint;\n}", + "members": {} + }, + "sizeCallbackBudget": { + "type": "(callbackGasLimit: bigint, pushGasPrice: bigint, buffer?: number) => bigint", + "members": {} + }, + "inferResultShape": { + "type": "(namespace: string, query: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape", + "members": {} + }, + "toRequestIdHex": { + "type": "(id: `0x${string}` | bigint) => `0x${string}`", + "members": {} + }, + "toReadQuery": { + "type": "(subject: string, o: ReadOptionsInput, resolvedTokenProgram?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@solana/web3.js/lib/index\").PublicKey) => import(\"sdk/src/lib/read-state/read-state.types\").ReadQuery", + "members": {} + }, + "UNIVERSAL_CALLBACK_EVM": { + "type": "readonly [\n {\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"requestExternalReadSelf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"estimateFee\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"statusOf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"enum RequestStatus\";\n readonly name: \"\";\n readonly type: \"uint8\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"isFulfilled\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getPendingRead\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly internalType: \"struct PendingRead\";\n readonly name: \"\";\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"totalEscrowed\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"blockedDomains\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly indexed: false;\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"readSpec\";\n readonly type: \"tuple\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"totalPaid\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"protocolFee\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ReadRequested\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"ReadFulfilled\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"reason\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"CallbackFailed\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"gasReported\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"burned\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"CallbackGasReported\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundSent\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundFailed\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RequestExpired\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"vaultPC\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ProtocolFeeDistributed\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidAccountId\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"EmptyQuery\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidMinConfirmations\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"DomainBlocked\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidBlockNumber\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidExpiryHeight\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroRevertRecipient\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroCallbackGasLimit\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint64\";\n readonly name: \"provided\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"max\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"CallbackGasLimitExceeded\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"required\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"InsufficientFee\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ExcessiveFee\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"actual\";\n readonly type: \"uint8\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"expected\";\n readonly type: \"uint8\";\n }\n ];\n readonly name: \"InvalidRequestStatus\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ContractIsPaused\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"CallerIsNotUCallbackModule\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n }\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"requestExternalReadSelf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n}" + }, + "1": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"estimateFee\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "2": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"statusOf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"enum RequestStatus\";\n readonly name: \"\";\n readonly type: \"uint8\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "3": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"isFulfilled\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "4": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getPendingRead\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly internalType: \"struct PendingRead\";\n readonly name: \"\";\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "5": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"totalEscrowed\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "6": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"blockedDomains\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "7": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly indexed: false;\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"readSpec\";\n readonly type: \"tuple\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"totalPaid\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"protocolFee\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ReadRequested\";\n readonly type: \"event\";\n}" + }, + "8": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"ReadFulfilled\";\n readonly type: \"event\";\n}" + }, + "9": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"reason\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"CallbackFailed\";\n readonly type: \"event\";\n}" + }, + "10": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"gasReported\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"burned\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"CallbackGasReported\";\n readonly type: \"event\";\n}" + }, + "11": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundSent\";\n readonly type: \"event\";\n}" + }, + "12": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundFailed\";\n readonly type: \"event\";\n}" + }, + "13": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RequestExpired\";\n readonly type: \"event\";\n}" + }, + "14": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"vaultPC\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ProtocolFeeDistributed\";\n readonly type: \"event\";\n}" + }, + "15": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidAccountId\";\n readonly type: \"error\";\n}" + }, + "16": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"EmptyQuery\";\n readonly type: \"error\";\n}" + }, + "17": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidMinConfirmations\";\n readonly type: \"error\";\n}" + }, + "18": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"DomainBlocked\";\n readonly type: \"error\";\n}" + }, + "19": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidBlockNumber\";\n readonly type: \"error\";\n}" + }, + "20": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidExpiryHeight\";\n readonly type: \"error\";\n}" + }, + "21": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroRevertRecipient\";\n readonly type: \"error\";\n}" + }, + "22": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroCallbackGasLimit\";\n readonly type: \"error\";\n}" + }, + "23": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint64\";\n readonly name: \"provided\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"max\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"CallbackGasLimitExceeded\";\n readonly type: \"error\";\n}" + }, + "24": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"required\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"InsufficientFee\";\n readonly type: \"error\";\n}" + }, + "25": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ExcessiveFee\";\n readonly type: \"error\";\n}" + }, + "26": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"actual\";\n readonly type: \"uint8\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"expected\";\n readonly type: \"uint8\";\n }\n ];\n readonly name: \"InvalidRequestStatus\";\n readonly type: \"error\";\n}" + }, + "27": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ContractIsPaused\";\n readonly type: \"error\";\n}" + }, + "28": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"CallerIsNotUCallbackModule\";\n readonly type: \"error\";\n}" + }, + "29": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n}" + }, + "length": { + "optional": false, + "readonly": true, + "type": "30" + } + } + }, + "UNIVERSAL_READ_REGISTRY_EVM": { + "type": "readonly [\n {\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n },\n {\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"read\";\n readonly outputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"universalCallback_\";\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"constructor\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"initialize\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getLocalContext\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"hasResult\";\n readonly outputs: readonly [\n {\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"onUniversalData\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"queryKeyOf\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes32\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"readerOf\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"requestOrderOf\";\n readonly outputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"universalCallback\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"resultByRequestId\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"latestResult\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"version\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"Initialized\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadRequested\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadStored\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidInitialization\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"NotInitializing\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroAddressInit\";\n readonly type: \"error\";\n }\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n },\n {\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"read\";\n readonly outputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n}" + }, + "1": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"universalCallback_\";\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"constructor\";\n}" + }, + "2": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"initialize\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n}" + }, + "3": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getLocalContext\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "4": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"hasResult\";\n readonly outputs: readonly [\n {\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "5": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"onUniversalData\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n}" + }, + "6": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"queryKeyOf\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes32\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "7": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"readerOf\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "8": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"requestOrderOf\";\n readonly outputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "9": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"universalCallback\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "10": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"resultByRequestId\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "11": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"latestResult\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "12": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"version\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"Initialized\";\n readonly type: \"event\";\n}" + }, + "13": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadRequested\";\n readonly type: \"event\";\n}" + }, + "14": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadStored\";\n readonly type: \"event\";\n}" + }, + "15": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidInitialization\";\n readonly type: \"error\";\n}" + }, + "16": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"NotInitializing\";\n readonly type: \"error\";\n}" + }, + "17": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n}" + }, + "18": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroAddressInit\";\n readonly type: \"error\";\n}" + }, + "length": { + "optional": false, + "readonly": true, + "type": "19" + } + } + }, + "PushChainExecutionError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").PushChainExecutionError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PushChainBatchExecutionError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").PushChainBatchExecutionError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": false, + "readonly": true, + "type": "`0x${string}`[]" + } + } + }, + "DecodedErrorPayload": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload", + "members": { + "decoded": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "name": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "selector": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "PushChainInitializeOptions": { + "type": "import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions", + "members": { + "agenticWallet": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "blockExplorers": { + "optional": true, + "readonly": false, + "type": "Partial> | undefined" + }, + "network": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "printTraces": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "rpcUrls": { + "optional": true, + "readonly": false, + "type": "Partial> | undefined" + } + } + }, + "AGENTIC_ERROR_CODE": { + "type": "{\n readonly AGENT_GAS_INSUFFICIENT: \"AGENT_GAS_INSUFFICIENT\";\n readonly AGENT_IS_OWNER: \"AGENT_IS_OWNER\";\n readonly ASSET_CHAIN_MISMATCH: \"ASSET_CHAIN_MISMATCH\";\n readonly CAPABILITY_UNAVAILABLE: \"CAPABILITY_UNAVAILABLE\";\n readonly CREATE_PARTIAL: \"CREATE_PARTIAL\";\n readonly DUPLICATE_RULE: \"DUPLICATE_RULE\";\n readonly FROM_NOT_ALLOWED: \"FROM_NOT_ALLOWED\";\n readonly GATEWAY_ALLOWANCE_INSUFFICIENT: \"GATEWAY_ALLOWANCE_INSUFFICIENT\";\n readonly GENERATION_UNSUPPORTED: \"GENERATION_UNSUPPORTED\";\n readonly INCONSISTENT_READ: \"INCONSISTENT_READ\";\n readonly INDEX_RACE: \"INDEX_RACE\";\n readonly INVALID_RULE: \"INVALID_RULE\";\n readonly NO_RULES_FOR_CHAIN: \"NO_RULES_FOR_CHAIN\";\n readonly NOT_AGENTIC_WALLET: \"NOT_AGENTIC_WALLET\";\n readonly NOT_ALLOWED_IN_AGENTIC_MODE: \"NOT_ALLOWED_IN_AGENTIC_MODE\";\n readonly NOT_OWNER_OR_AGENT: \"NOT_OWNER_OR_AGENT\";\n readonly NOT_WALLET_OWNER: \"NOT_WALLET_OWNER\";\n readonly READ_ONLY: \"READ_ONLY\";\n readonly RECEIPT_MISMATCH: \"RECEIPT_MISMATCH\";\n readonly RECEIPT_UNAVAILABLE: \"RECEIPT_UNAVAILABLE\";\n readonly REVOKE_NEEDS_TARGET: \"REVOKE_NEEDS_TARGET\";\n readonly RULE_LIMIT_EXCEEDED: \"RULE_LIMIT_EXCEEDED\";\n readonly RULE_NOT_FOUND: \"RULE_NOT_FOUND\";\n readonly RULE_READ_FAILED: \"RULE_READ_FAILED\";\n readonly TARGET_NOT_ON_RULE_CHAIN: \"TARGET_NOT_ON_RULE_CHAIN\";\n readonly WALLET_BALANCE_INSUFFICIENT: \"WALLET_BALANCE_INSUFFICIENT\";\n readonly WALLET_NOT_DEPLOYED: \"WALLET_NOT_DEPLOYED\";\n}", + "members": { + "AGENT_GAS_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\"" + }, + "AGENT_IS_OWNER": { + "optional": false, + "readonly": true, + "type": "\"AGENT_IS_OWNER\"" + }, + "ASSET_CHAIN_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"ASSET_CHAIN_MISMATCH\"" + }, + "CAPABILITY_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"CAPABILITY_UNAVAILABLE\"" + }, + "CREATE_PARTIAL": { + "optional": false, + "readonly": true, + "type": "\"CREATE_PARTIAL\"" + }, + "DUPLICATE_RULE": { + "optional": false, + "readonly": true, + "type": "\"DUPLICATE_RULE\"" + }, + "FROM_NOT_ALLOWED": { + "optional": false, + "readonly": true, + "type": "\"FROM_NOT_ALLOWED\"" + }, + "GATEWAY_ALLOWANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"GATEWAY_ALLOWANCE_INSUFFICIENT\"" + }, + "GENERATION_UNSUPPORTED": { + "optional": false, + "readonly": true, + "type": "\"GENERATION_UNSUPPORTED\"" + }, + "INCONSISTENT_READ": { + "optional": false, + "readonly": true, + "type": "\"INCONSISTENT_READ\"" + }, + "INDEX_RACE": { + "optional": false, + "readonly": true, + "type": "\"INDEX_RACE\"" + }, + "INVALID_RULE": { + "optional": false, + "readonly": true, + "type": "\"INVALID_RULE\"" + }, + "NO_RULES_FOR_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"NO_RULES_FOR_CHAIN\"" + }, + "NOT_AGENTIC_WALLET": { + "optional": false, + "readonly": true, + "type": "\"NOT_AGENTIC_WALLET\"" + }, + "NOT_ALLOWED_IN_AGENTIC_MODE": { + "optional": false, + "readonly": true, + "type": "\"NOT_ALLOWED_IN_AGENTIC_MODE\"" + }, + "NOT_OWNER_OR_AGENT": { + "optional": false, + "readonly": true, + "type": "\"NOT_OWNER_OR_AGENT\"" + }, + "NOT_WALLET_OWNER": { + "optional": false, + "readonly": true, + "type": "\"NOT_WALLET_OWNER\"" + }, + "READ_ONLY": { + "optional": false, + "readonly": true, + "type": "\"READ_ONLY\"" + }, + "RECEIPT_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_MISMATCH\"" + }, + "RECEIPT_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_UNAVAILABLE\"" + }, + "REVOKE_NEEDS_TARGET": { + "optional": false, + "readonly": true, + "type": "\"REVOKE_NEEDS_TARGET\"" + }, + "RULE_LIMIT_EXCEEDED": { + "optional": false, + "readonly": true, + "type": "\"RULE_LIMIT_EXCEEDED\"" + }, + "RULE_NOT_FOUND": { + "optional": false, + "readonly": true, + "type": "\"RULE_NOT_FOUND\"" + }, + "RULE_READ_FAILED": { + "optional": false, + "readonly": true, + "type": "\"RULE_READ_FAILED\"" + }, + "TARGET_NOT_ON_RULE_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"TARGET_NOT_ON_RULE_CHAIN\"" + }, + "WALLET_BALANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"WALLET_BALANCE_INSUFFICIENT\"" + }, + "WALLET_NOT_DEPLOYED": { + "optional": false, + "readonly": true, + "type": "\"WALLET_NOT_DEPLOYED\"" + } + } + }, + "AgenticError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"CREATE_PARTIAL\" | \"DUPLICATE_RULE\" | \"FROM_NOT_ALLOWED\" | \"GATEWAY_ALLOWANCE_INSUFFICIENT\" | \"GENERATION_UNSUPPORTED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"REVOKE_NEEDS_TARGET\" | \"RULE_LIMIT_EXCEEDED\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"" + }, + "details": { + "optional": true, + "readonly": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "AgenticRevertError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticRevertError", + "members": { + "agenticCode": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + } + } + }, + "AgenticAddress": { + "type": "`0x${string}`", + "members": {} + }, + "AgenticDoor": { + "type": "\"agent\" | \"owner\"", + "members": {} + }, + "AgenticErrorCode": { + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"CREATE_PARTIAL\" | \"DUPLICATE_RULE\" | \"FROM_NOT_ALLOWED\" | \"GATEWAY_ALLOWANCE_INSUFFICIENT\" | \"GENERATION_UNSUPPORTED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"REVOKE_NEEDS_TARGET\" | \"RULE_LIMIT_EXCEEDED\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"", + "members": {} + }, + "AgenticHex": { + "type": "`0x${string}`", + "members": {} + }, + "AgenticNamespace": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace", + "members": { + "create": { + "optional": false, + "readonly": false, + "type": "(label: string, options: import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions) => Promise" + }, + "derive": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n index?: number;\n}) => Promise<{\n address: `0x${string}`;\n deployed: boolean;\n index: number;\n}>" + }, + "list": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n wallets: import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary[];\n}>" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "(address: `0x${string}`) => import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet" + } + } + }, + "AgenticNetworkConstants": { + "type": "import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants", + "members": { + "ENVELOPE_VERSION": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "FACTORY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "MAX_ALLOWED_CALLS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "MAX_PINS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "RULES_POLICY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticProgressHook": { + "type": "(event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void", + "members": {} + }, + "AgenticTxMetadata": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticTxMetadata", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destinationAccount": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "destinationCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "door": { + "optional": false, + "readonly": false, + "type": "\"agent\" | \"owner\"" + }, + "nativeCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "rawData": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rawTo": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesId": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticWallet": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "checkpoints": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n sinceBlock?: bigint;\n}) => Promise<{\n checkpoints: import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint[];\n}>" + }, + "info": { + "optional": false, + "readonly": false, + "type": "() => Promise" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n owner: `0x${string}`;\n}>" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "{\n add(rules: import(\"sdk/src/lib/agentic/agentic.types\").Rule[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise<{\n rulesIds: `0x${string}`[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n get(rulesId: `0x${string}`): Promise;\n list(): Promise<{\n rules: import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord[];\n }>;\n revoke(rulesIds: `0x${string}`[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n revoke(params: {\n all: true;\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n update(params: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n rules: {\n rule: import(\"sdk/src/lib/agentic/agentic.types\").Rule;\n rulesId: `0x${string}`;\n }[];\n }): Promise<{\n rules: {\n replaced: `0x${string}`;\n rulesId: `0x${string}`;\n }[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n}" + }, + "setLabel": { + "optional": false, + "readonly": false, + "type": "(label: string, opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n}) => Promise" + } + } + }, + "AllowedCall": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall", + "members": { + "beneficiary": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValue": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "`${string}(${string})` | `0x${string}`" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AssetCap": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap", + "members": { + "maxPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/constants/tokens\").MoveableToken" + } + } + }, + "Checkpoint": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint", + "members": { + "blockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "kind": { + "optional": false, + "readonly": false, + "type": "\"OWNER_ACTION\" | \"RULES_GRANTED\" | \"RULES_REVOKED\"" + }, + "ref": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "seq": { + "optional": false, + "readonly": false, + "type": "number" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "CheckpointKind": { + "type": "\"OWNER_ACTION\" | \"RULES_GRANTED\" | \"RULES_REVOKED\"", + "members": {} + }, + "CreateOptions": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions", + "members": { + "progressHook": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook | undefined" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Rule[]" + } + } + }, + "CreateResult": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateResult", + "members": { + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "rulesIds": { + "optional": false, + "readonly": false, + "type": "`0x${string}`[]" + }, + "tx": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ForeignChainNamespace": { + "type": "`eip155:${string}` | `solana:${string}`", + "members": {} + }, + "NativeRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "amount": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AmountLimit | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "maxCalls": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValuePerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxValueTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "pins": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ArgPin[] | undefined" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Rule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule | import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "RulesRecord": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "enabled": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "ref": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "rule": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule | import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule" + }, + "rulesId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Selector": { + "type": "`${string}(${string})` | `0x${string}`", + "members": {} + }, + "UniversalRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall[]" + }, + "assets": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap[]" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "`eip155:${string}` | `solana:${string}`" + }, + "maxGasPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "WalletInfo": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").WalletInfo", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "label": { + "optional": false, + "readonly": false, + "type": "string" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "rulesCount": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "WalletSummary": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "label": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesCount": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "PushChain": { + "type": "import(\"sdk/src/lib/push-chain/push-chain\").PushChain", + "members": { + "accountStatus": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus" + }, + "accountStatusReady": { + "optional": false, + "readonly": false, + "type": "Promise" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace" + }, + "explorer": { + "optional": false, + "readonly": false, + "type": "{\n getTransactionUrl: (txHash: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n listAllUrls: () => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n listUrls: (options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n}" + }, + "funds": { + "optional": false, + "readonly": false, + "type": "{\n getConversionQuote: (amountIn: bigint, options: {\n from: import(\"sdk/src/lib/constants/tokens\").PayableToken | undefined;\n to: import(\"sdk/src/lib/constants/tokens\").MoveableToken | undefined;\n }) => Promise;\n}" + }, + "getAccountStatus": { + "optional": false, + "readonly": false, + "type": "(options?: {\n forceRefresh?: boolean;\n}) => Promise" + }, + "isReadMode": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "moveable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").MoveableTokenAccessor;\n}" + }, + "payable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").PayableTokenAccessor;\n}" + }, + "reinitialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "universal": { + "optional": false, + "readonly": false, + "type": "{\n readonly account: `0x${string}`;\n executeReads: (reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>;\n executeTransactions: (txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise;\n migrateCEA: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"migrateCEA\"];\n readonly origin: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n prepareRead: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n prepareTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"prepareTransaction\"];\n read: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n rescueFunds: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"rescueFunds\"];\n sendTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"execute\"];\n signMessage: (data: Uint8Array) => Promise;\n signTypedData: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n trackRead: {\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n };\n trackTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"trackTransaction\"];\n}" + }, + "upgradeAccount": { + "optional": false, + "readonly": false, + "type": "(options?: {\n progressHook?: (progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n}) => Promise" + } + } + } + }, + "pushChainStatic": { + "CONSTANTS": { + "optional": false, + "readonly": false, + "type": "{\n AGENTIC: Readonly>>;\n CHAIN: typeof import(\"sdk/src/lib/constants/enums\").CHAIN;\n LIBRARY: typeof import(\"sdk/src/lib/constants/enums\").LIBRARY;\n MOVEABLE: {\n TOKEN: import(\"sdk/src/lib/constants/tokens\").MoveableTokenConstantsMap;\n };\n PAYABLE: {\n TOKEN: import(\"sdk/src/lib/constants/tokens\").PayableTokenConstantsMap;\n };\n PUSH_NETWORK: typeof import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n READ: {\n readonly CALLBACK_BUDGET_BUFFER: 3;\n readonly CHAIN: {\n readonly WEB2: \"web2\";\n } & Readonly<{\n readonly ARBITRUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA;\n readonly BASE_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA;\n readonly BNB_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET;\n readonly ETHEREUM_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET;\n readonly ETHEREUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA;\n readonly PUSH_LOCALNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET;\n readonly PUSH_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET;\n readonly PUSH_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly PUSH_TESTNET_DONUT: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly SOLANA_DEVNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET;\n readonly SOLANA_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET;\n readonly SOLANA_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n readonly WEB2: \"web2\";\n }>;\n readonly DEFAULT_EXPIRY_BLOCKS: 300n;\n readonly ERROR_CODE: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n readonly MAX_CALLBACK_GAS_LIMIT: 1000000n;\n readonly MIN_CONFIRMATIONS_FLOOR: 1;\n readonly NAMESPACE: {\n readonly EVM: \"eip155\";\n readonly SVM: \"solana\";\n readonly WEB2: \"web2\";\n };\n readonly OUTCOME: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME;\n readonly REGISTRY_CALLBACK_GAS: 500000n;\n readonly RESULT_STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n readonly STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS;\n readonly UNIVERSAL_CALLBACK_ADDRESSES: Record;\n readonly UNIVERSAL_CORE_ADDRESSES: Record;\n readonly UNIVERSAL_READ_REGISTRY_ADDRESS: {\n readonly TESTNET_DONUT: \"0x00000000000000000000000000000000000000b2\";\n };\n readonly WEB2: \"web2\";\n readonly WEB2_DEFAULT_TIMEOUT_MS: 5000;\n readonly WEB2_MAX_EXTRACT_ENTRIES: 16;\n };\n}" + }, + "initialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "utils": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/utils\").Utils" + } + }, + "pushChainInstance": { + "accountStatus": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus" + }, + "accountStatusReady": { + "optional": false, + "readonly": false, + "type": "Promise" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace" + }, + "explorer": { + "optional": false, + "readonly": false, + "type": "{\n getTransactionUrl: (txHash: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n listAllUrls: () => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n listUrls: (options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n}" + }, + "funds": { + "optional": false, + "readonly": false, + "type": "{\n getConversionQuote: (amountIn: bigint, options: {\n from: import(\"sdk/src/lib/constants/tokens\").PayableToken | undefined;\n to: import(\"sdk/src/lib/constants/tokens\").MoveableToken | undefined;\n }) => Promise;\n}" + }, + "getAccountStatus": { + "optional": false, + "readonly": false, + "type": "(options?: {\n forceRefresh?: boolean;\n}) => Promise" + }, + "isReadMode": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "moveable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").MoveableTokenAccessor;\n}" + }, + "payable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").PayableTokenAccessor;\n}" + }, + "reinitialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "universal": { + "optional": false, + "readonly": false, + "type": "{\n readonly account: `0x${string}`;\n executeReads: (reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>;\n executeTransactions: (txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise;\n migrateCEA: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"migrateCEA\"];\n readonly origin: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n prepareRead: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n prepareTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"prepareTransaction\"];\n read: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n rescueFunds: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"rescueFunds\"];\n sendTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"execute\"];\n signMessage: (data: Uint8Array) => Promise;\n signTypedData: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n trackRead: {\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n };\n trackTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"trackTransaction\"];\n}" + }, + "upgradeAccount": { + "optional": false, + "readonly": false, + "type": "(options?: {\n progressHook?: (progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n}) => Promise" + } + }, + "transactionMethods": { + "account": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "executeReads": { + "optional": false, + "readonly": false, + "type": "(reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>" + }, + "executeTransactions": { + "optional": false, + "readonly": false, + "type": "(txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise" + }, + "migrateCEA": { + "optional": false, + "readonly": false, + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => Promise" + }, + "origin": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "prepareRead": { + "optional": false, + "readonly": false, + "type": "(subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>" + }, + "prepareTransaction": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions) => Promise" + }, + "read": { + "optional": false, + "readonly": false, + "type": "(subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>" + }, + "rescueFunds": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").RescueFundsParams) => Promise" + }, + "sendTransaction": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").ExecuteParams | import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions) => Promise" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": false, + "readonly": false, + "type": "({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise" + }, + "trackRead": { + "optional": false, + "readonly": false, + "type": "{\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n}" + }, + "trackTransaction": { + "optional": false, + "readonly": false, + "type": "(txHash: string, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TrackTransactionOptions) => Promise" + } + }, + "utilityMethods": { + "account": { + "optional": false, + "readonly": false, + "type": "{\n convertExecutorToOriginAccount: (ueaAddress: `0x${string}`, options?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n }) => Promise;\n convertOriginToExecutor: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n onlyCompute?: boolean;\n }) => Promise;\n deriveExecutorAccount: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n skipNetworkCheck?: boolean;\n }) => Promise;\n fromChainAgnostic: (caip: string) => import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n resolveControllerAccount: (address: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n skipNetworkCheck?: boolean;\n }) => Promise;\n toChainAgnostic: (address: string, options: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n toUniversal: (address: string, options: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n}" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "{\n actionId: (target: `0x${string}`, selector: \"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector) => `0x${string}`;\n configId: (wallet: `0x${string}`, rulesId: `0x${string}`, actionId: `0x${string}`) => `0x${string}`;\n decodeRules: (bytes: `0x${string}`, ctx?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n pushChainNamespace?: string;\n }) => import(\"sdk/src/lib/agentic/agentic.types\").Rule;\n}" + }, + "chains": { + "optional": false, + "readonly": false, + "type": "{\n getChainName: (chainNamespace: string) => string | undefined;\n getChainNamespace: (chainName: string) => string | undefined;\n getSupportedChains: (network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK) => {\n chains: import(\"sdk/src/lib/constants/enums\").CHAIN[];\n };\n getSupportedChainsByName: (network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK) => {\n chains: string[];\n };\n}" + }, + "conversion": { + "optional": false, + "readonly": false, + "type": "{\n slippageToMinAmount(amount: string, options: {\n slippageBps: number;\n }): string;\n}" + }, + "helpers": { + "optional": false, + "readonly": false, + "type": "{\n encodeTxData({ abi, idl, functionName, args, }: {\n abi?: any;\n args?: any[];\n functionName: string;\n idl?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n }): `0x${string}`;\n formatUnits(value: bigint | string, decimalsOrOptions: {\n decimals: number;\n precision?: number;\n } | number): string;\n getChainName: (chainName: string) => string | undefined;\n parseUnits(value: string, exponent: {\n decimals: number;\n } | number): bigint;\n}" + }, + "signer": { + "optional": false, + "readonly": false, + "type": "{\n construct: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options: {\n signAndSendTransaction: (unsignedTx: Uint8Array) => Promise;\n signAuthorization?: (params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise;\n signMessage: (data: Uint8Array) => Promise;\n signTypedData?: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n }) => import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton;\n toUniversal: (signer: import(\"sdk/src/lib/universal/universal.types\").EthersV5SignerType | import(\"sdk/src/lib/universal/universal.types\").EthersV6SignerType | import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton | import(\"sdk/src/lib/universal/universal.types\").ViemSignerType) => Promise;\n toUniversalFromKeypair: (clientOrAccount: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@solana/web3.js/lib/index\").Keypair | import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").WalletClient | import(\"sdk/src/lib/universal/universal.types\").EthersV6SignerType, { chain, library }: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n library: import(\"sdk/src/lib/constants/enums\").LIBRARY;\n }) => Promise;\n}" + }, + "svm": { + "optional": false, + "readonly": false, + "type": "{\n getRegisteredIdls: () => Array<{\n address: `0x${string}`;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n }>;\n registerIdl: (idl: unknown) => void;\n}" + }, + "tokens": { + "optional": false, + "readonly": false, + "type": "{\n getMoveableTokens(chainOrClient?: import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/push-chain/push-chain\").PushChain): {\n tokens: Array<{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n decimals: number;\n mechanism: \"approve\" | \"native\" | \"permit2\";\n prc20Address?: `0x${string}`;\n sourceChain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n symbol: string;\n }>;\n };\n getPayableTokens(chainOrClient?: import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/push-chain/push-chain\").PushChain): {\n tokens: Array<{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n decimals: number;\n mechanism: \"approve\" | \"native\" | \"permit2\";\n symbol: string;\n }>;\n };\n getPC20Address(address: string, options: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n rpcUrls?: Partial>;\n strict?: boolean;\n }): Promise;\n getPRC20Address(token: {\n address: string;\n chain: string;\n } | import(\"sdk/src/lib/constants/tokens\").MoveableToken, options?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n }): {\n address: `0x${string}`;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n decimals: number;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n symbol: string;\n };\n}" + } + }, + "initialize": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise", + "agwConstants": { + "ENVELOPE_VERSION": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "FACTORY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "MAX_ALLOWED_CALLS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "MAX_PINS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "RULES_POLICY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + }, + "constants": { + "AGENTIC": { + "optional": false, + "readonly": false, + "type": "{\n readonly LOCALNET?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n readonly MAINNET?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n readonly TESTNET?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n readonly TESTNET_DONUT?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n}" + }, + "CHAIN": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "LIBRARY": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").LIBRARY" + }, + "MOVEABLE": { + "optional": false, + "readonly": false, + "type": "{\n TOKEN: import(\"sdk/src/lib/constants/tokens\").MoveableTokenConstantsMap;\n}" + }, + "PAYABLE": { + "optional": false, + "readonly": false, + "type": "{\n TOKEN: import(\"sdk/src/lib/constants/tokens\").PayableTokenConstantsMap;\n}" + }, + "PUSH_NETWORK": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "READ": { + "optional": false, + "readonly": false, + "type": "{\n readonly CALLBACK_BUDGET_BUFFER: 3;\n readonly CHAIN: {\n readonly WEB2: \"web2\";\n } & Readonly<{\n readonly ARBITRUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA;\n readonly BASE_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA;\n readonly BNB_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET;\n readonly ETHEREUM_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET;\n readonly ETHEREUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA;\n readonly PUSH_LOCALNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET;\n readonly PUSH_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET;\n readonly PUSH_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly PUSH_TESTNET_DONUT: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly SOLANA_DEVNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET;\n readonly SOLANA_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET;\n readonly SOLANA_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n readonly WEB2: \"web2\";\n }>;\n readonly DEFAULT_EXPIRY_BLOCKS: 300n;\n readonly ERROR_CODE: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n readonly MAX_CALLBACK_GAS_LIMIT: 1000000n;\n readonly MIN_CONFIRMATIONS_FLOOR: 1;\n readonly NAMESPACE: {\n readonly EVM: \"eip155\";\n readonly SVM: \"solana\";\n readonly WEB2: \"web2\";\n };\n readonly OUTCOME: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME;\n readonly REGISTRY_CALLBACK_GAS: 500000n;\n readonly RESULT_STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n readonly STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS;\n readonly UNIVERSAL_CALLBACK_ADDRESSES: Record;\n readonly UNIVERSAL_CORE_ADDRESSES: Record;\n readonly UNIVERSAL_READ_REGISTRY_ADDRESS: {\n readonly TESTNET_DONUT: \"0x00000000000000000000000000000000000000b2\";\n };\n readonly WEB2: \"web2\";\n readonly WEB2_DEFAULT_TIMEOUT_MS: 5000;\n readonly WEB2_MAX_EXTRACT_ENTRIES: 16;\n}" + } + } + }, + "after": { + "exports": [ + "AGENTIC_ERROR_CODE", + "AccountRole", + "AccountStatus", + "AccountType", + "AgenticAddress", + "AgenticDoor", + "AgenticError", + "AgenticErrorCode", + "AgenticHex", + "AgenticNamespace", + "AgenticPresets", + "AgenticProgressHook", + "AgenticRevertError", + "AgenticTxMetadata", + "AgenticWallet", + "AllowedCall", + "ArgumentPath", + "AssetCap", + "BatchReadResponse", + "BuildReadSpecParams", + "CHAIN", + "CONTRACT_REQUEST_STATUS", + "CascadeCompletionResult", + "CascadeHopInfo", + "CascadeProgressEvent", + "CascadeTrackOptions", + "CascadedTxResponse", + "ChainSource", + "ChainTarget", + "Checkpoint", + "CheckpointKind", + "ConversionQuote", + "CreateOptions", + "CreateResult", + "DEFAULT_MAX_PC_FOR_GAS_BUFFER_BPS", + "DecodedErrorPayload", + "DecodedReadResult", + "DecodedSolanaRule", + "DerivedExecutorAccount", + "EncodedReadQuery", + "EvmReadQuery", + "ForeignChainNamespace", + "FulfilOutcome", + "FundsToken", + "InsufficientPC20BalanceError", + "InvalidPC20AddressError", + "InvalidPC20MetadataError", + "InvalidReadQueryError", + "InvalidReadSpecError", + "MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT", + "MaxPCForGasCapFromNativeValueInput", + "MaxPCForGasCapInput", + "MaxPCForGasCapQuote", + "MultiChainTxResponse", + "OutboundTxDetails", + "PC20AddressResult", + "PC20AmbiguousAddressError", + "PC20Error", + "PC20ExpectedButPRC20Error", + "PC20ExportRevertedError", + "PC20FactoryMismatchError", + "PC20RegistryEntry", + "PC20RegistryMismatchError", + "PC20TokenChainMismatchError", + "PC20TokenReference", + "PC20UnknownChainNamespaceError", + "PC20UnsafeEmptyPayloadError", + "PC20WrapperNotRegisteredError", + "PC20WrapperPredictionUnavailableError", + "ParsedReadRequest", + "Pin", + "PreparedRead", + "PreparedUniversalTx", + "Preset", + "PresetAsset", + "PresetCallIssue", + "PresetCategory", + "PresetChainReadiness", + "PresetConfigurationIssue", + "PresetOptions", + "PresetResult", + "PresetRuleTemplate", + "PushChain", + "PushChainBatchExecutionError", + "PushChainExecutionError", + "PushChainInitializeOptions", + "READ_ERROR_CODE", + "READ_OUTCOME", + "READ_STATUS", + "ReadCallback", + "ReadCallbackOptions", + "ReadChain", + "ReadDecodeError", + "ReadDestination", + "ReadExecuteOptions", + "ReadFees", + "ReadHeightUnavailableError", + "ReadLifecycleOptions", + "ReadNotFoundError", + "ReadOptions", + "ReadPreflight", + "ReadPrepareOptions", + "ReadQuery", + "ReadQueryOptions", + "ReadRef", + "ReadRegistryUnavailableError", + "ReadResponseTuple", + "ReadResultShape", + "ReadSpec", + "ReadSpecTuple", + "ReadSpecViolation", + "ReadStateError", + "ReadTimeoutError", + "ReadTrackOptions", + "ReadValue", + "ReadWeb2Options", + "ReadyPresetOptions", + "ReceiptLike", + "RescueFundsParams", + "ResolvedAccount", + "ResolvedControllerAccounts", + "ResolvedDestination", + "Rule", + "RuleInput", + "RulesRecord", + "Selector", + "SignAuthorizationParams", + "SignedAuthorization", + "SimulateReadResult", + "Spent", + "SvmExecutePayloadFields", + "SvmGatewayAccountMeta", + "SvmReadQuery", + "TERMINAL_READ_STATUSES", + "TransactionRoute", + "TransactionRouteType", + "UEAStatus", + "UNIVERSAL_CALLBACK_EVM", + "UNIVERSAL_READ_REGISTRY_EVM", + "UNIVERSAL_READ_STATUS", + "UniversalAccount", + "UniversalExecuteParams", + "UniversalOutboundTxRequest", + "UniversalReadResponse", + "UniversalSigner", + "UniversalSignerSkeleton", + "UniversalTo", + "UnsupportedPC20DestinationError", + "UnsupportedReadDestinationError", + "ValidateReadCall", + "WaitForOutboundOptions", + "WalletInfo", + "WalletMarker", + "WalletSummary", + "Web2Extract", + "Web2ReadQuery", + "Web2ValueType", + "buildErc20WithdrawalMulticall", + "buildMigrationPayload", + "buildReadSpecFromPreflight", + "chainSupportsCEA", + "chainSupportsOutbound", + "decodeReadResult", + "detectRoute", + "encodeReadQuery", + "encodeSvmExecutePayload", + "getAllCEAAddresses", + "getCEAAddress", + "getCEAFactoryAddress", + "getPushAccountForCEA", + "inferResultShape", + "isCEA", + "isChainTarget", + "isPC20Reference", + "isSvmChain", + "isValidSolanaHexAddress", + "parseFulfilOutcome", + "parseReadRequestsFromReceipt", + "parseUEAVersion", + "quoteMaxPCForGasCap", + "quoteMaxPCForGasCapFromNativeValue", + "resolveDestination", + "sizeCallbackBudget", + "toCallData", + "toReadQuery", + "toRequestIdHex", + "validateReadSpec" + ], + "agw": { + "AgenticNamespace": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace", + "members": { + "create": { + "optional": false, + "readonly": false, + "type": "(label: string, options: import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions) => Promise" + }, + "derive": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n index?: number;\n}) => Promise<{\n address: `0x${string}`;\n deployed: boolean;\n index: number;\n}>" + }, + "list": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n wallets: import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary[];\n}>" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "(address: `0x${string}`) => import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet" + } + } + }, + "AgenticWallet": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "checkpoints": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n sinceBlock?: bigint;\n}) => Promise<{\n checkpoints: import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint[];\n}>" + }, + "info": { + "optional": false, + "readonly": false, + "type": "() => Promise" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n owner: `0x${string}`;\n}>" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "{\n add(rules: import(\"sdk/src/lib/agentic/agentic.types\").RuleInput[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise<{\n rulesIds: `0x${string}`[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n delete(rulesIds: `0x${string}`[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n delete(params: {\n all: true;\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n get(rulesId: `0x${string}`): Promise;\n list(): Promise<{\n rules: import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord[];\n }>;\n update(params: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n rules: {\n rule: import(\"sdk/src/lib/agentic/agentic.types\").RuleInput;\n rulesId: `0x${string}`;\n }[];\n }): Promise<{\n rules: {\n replaced: `0x${string}`;\n rulesId: `0x${string}`;\n }[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n}" + }, + "setLabel": { + "optional": false, + "readonly": false, + "type": "(label: string, opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n}) => Promise" + } + } + }, + "AgenticError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"AMBIGUOUS_RULE\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"DELETE_NEEDS_TARGET\" | \"DUPLICATE_RULE\" | \"FROM_NOT_ALLOWED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"" + }, + "details": { + "optional": true, + "readonly": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "AgenticRevertError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticRevertError", + "members": { + "agenticCode": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "AGENTIC_ERROR_CODE": { + "type": "{\n readonly AGENT_GAS_INSUFFICIENT: \"AGENT_GAS_INSUFFICIENT\";\n readonly AGENT_IS_OWNER: \"AGENT_IS_OWNER\";\n readonly AMBIGUOUS_RULE: \"AMBIGUOUS_RULE\";\n readonly ASSET_CHAIN_MISMATCH: \"ASSET_CHAIN_MISMATCH\";\n readonly CAPABILITY_UNAVAILABLE: \"CAPABILITY_UNAVAILABLE\";\n readonly DELETE_NEEDS_TARGET: \"DELETE_NEEDS_TARGET\";\n readonly DUPLICATE_RULE: \"DUPLICATE_RULE\";\n readonly FROM_NOT_ALLOWED: \"FROM_NOT_ALLOWED\";\n readonly INCONSISTENT_READ: \"INCONSISTENT_READ\";\n readonly INDEX_RACE: \"INDEX_RACE\";\n readonly INVALID_RULE: \"INVALID_RULE\";\n readonly NO_RULES_FOR_CHAIN: \"NO_RULES_FOR_CHAIN\";\n readonly NOT_AGENTIC_WALLET: \"NOT_AGENTIC_WALLET\";\n readonly NOT_ALLOWED_IN_AGENTIC_MODE: \"NOT_ALLOWED_IN_AGENTIC_MODE\";\n readonly NOT_OWNER_OR_AGENT: \"NOT_OWNER_OR_AGENT\";\n readonly NOT_WALLET_OWNER: \"NOT_WALLET_OWNER\";\n readonly READ_ONLY: \"READ_ONLY\";\n readonly RECEIPT_MISMATCH: \"RECEIPT_MISMATCH\";\n readonly RECEIPT_UNAVAILABLE: \"RECEIPT_UNAVAILABLE\";\n readonly RULE_NOT_FOUND: \"RULE_NOT_FOUND\";\n readonly RULE_READ_FAILED: \"RULE_READ_FAILED\";\n readonly TARGET_NOT_ON_RULE_CHAIN: \"TARGET_NOT_ON_RULE_CHAIN\";\n readonly WALLET_BALANCE_INSUFFICIENT: \"WALLET_BALANCE_INSUFFICIENT\";\n readonly WALLET_NOT_DEPLOYED: \"WALLET_NOT_DEPLOYED\";\n}", + "members": { + "AGENT_GAS_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\"" + }, + "AGENT_IS_OWNER": { + "optional": false, + "readonly": true, + "type": "\"AGENT_IS_OWNER\"" + }, + "AMBIGUOUS_RULE": { + "optional": false, + "readonly": true, + "type": "\"AMBIGUOUS_RULE\"" + }, + "ASSET_CHAIN_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"ASSET_CHAIN_MISMATCH\"" + }, + "CAPABILITY_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"CAPABILITY_UNAVAILABLE\"" + }, + "DELETE_NEEDS_TARGET": { + "optional": false, + "readonly": true, + "type": "\"DELETE_NEEDS_TARGET\"" + }, + "DUPLICATE_RULE": { + "optional": false, + "readonly": true, + "type": "\"DUPLICATE_RULE\"" + }, + "FROM_NOT_ALLOWED": { + "optional": false, + "readonly": true, + "type": "\"FROM_NOT_ALLOWED\"" + }, + "INCONSISTENT_READ": { + "optional": false, + "readonly": true, + "type": "\"INCONSISTENT_READ\"" + }, + "INDEX_RACE": { + "optional": false, + "readonly": true, + "type": "\"INDEX_RACE\"" + }, + "INVALID_RULE": { + "optional": false, + "readonly": true, + "type": "\"INVALID_RULE\"" + }, + "NO_RULES_FOR_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"NO_RULES_FOR_CHAIN\"" + }, + "NOT_AGENTIC_WALLET": { + "optional": false, + "readonly": true, + "type": "\"NOT_AGENTIC_WALLET\"" + }, + "NOT_ALLOWED_IN_AGENTIC_MODE": { + "optional": false, + "readonly": true, + "type": "\"NOT_ALLOWED_IN_AGENTIC_MODE\"" + }, + "NOT_OWNER_OR_AGENT": { + "optional": false, + "readonly": true, + "type": "\"NOT_OWNER_OR_AGENT\"" + }, + "NOT_WALLET_OWNER": { + "optional": false, + "readonly": true, + "type": "\"NOT_WALLET_OWNER\"" + }, + "READ_ONLY": { + "optional": false, + "readonly": true, + "type": "\"READ_ONLY\"" + }, + "RECEIPT_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_MISMATCH\"" + }, + "RECEIPT_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_UNAVAILABLE\"" + }, + "RULE_NOT_FOUND": { + "optional": false, + "readonly": true, + "type": "\"RULE_NOT_FOUND\"" + }, + "RULE_READ_FAILED": { + "optional": false, + "readonly": true, + "type": "\"RULE_READ_FAILED\"" + }, + "TARGET_NOT_ON_RULE_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"TARGET_NOT_ON_RULE_CHAIN\"" + }, + "WALLET_BALANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"WALLET_BALANCE_INSUFFICIENT\"" + }, + "WALLET_NOT_DEPLOYED": { + "optional": false, + "readonly": true, + "type": "\"WALLET_NOT_DEPLOYED\"" + } + } + }, + "Rule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Rule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleCall[]" + }, + "assets": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset[] | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "maxGasPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "RuleInput": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").DecodedSolanaRule | import(\"sdk/src/lib/agentic/agentic.types\").Rule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "assets": { + "optional": true, + "readonly": false, + "type": "{\n maxPerCall: bigint;\n maxTotal: bigint;\n token: string;\n}[] | import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset[] | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "maxGasPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Pin": { + "type": "{\n account: number;\n arg?: never;\n expected: \"agentic:wallet\" | string;\n max?: never;\n token?: import(\"sdk/src/lib/constants/tokens\").MoveableToken | string;\n} | {\n account?: never;\n arg: import(\"sdk/src/lib/agentic/agentic.types\").ArgumentPath;\n expected: \"agentic:wallet\" | `0x${string}` | `0x${string}` | bigint;\n max?: never;\n} | {\n account?: never;\n arg: import(\"sdk/src/lib/agentic/agentic.types\").ArgumentPath;\n expected?: never;\n max: bigint;\n}", + "members": { + "account": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "arg": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ArgumentPath | undefined" + }, + "expected": { + "optional": true, + "readonly": false, + "type": "bigint | string | undefined" + }, + "max": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "Spent": { + "type": "{\n actions: {\n amountSpent: bigint;\n callsUsed: number;\n selector: \"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector;\n target: `0x${string}`;\n valueSpent: bigint;\n }[];\n kind: \"native\";\n} | {\n amountSpent: bigint;\n callsUsed: number;\n kind: \"native\";\n valueSpent: bigint;\n} | {\n assets: {\n spent: bigint;\n token: string;\n }[];\n kind: \"universal\";\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"native\" | \"universal\"" + } + } + }, + "AssetCap": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset", + "members": { + "maxPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/tokens\").MoveableToken | string" + } + } + }, + "AllowedCall": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleCall", + "members": { + "app": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "label": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "maxValue": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "pins": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Pin[] | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector" + }, + "target": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "RulesRecord": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "enabled": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "rule": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").DecodedSolanaRule | import(\"sdk/src/lib/agentic/agentic.types\").Rule" + }, + "rulesId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "spent": { + "optional": false, + "readonly": false, + "type": "{\n actions: {\n amountSpent: bigint;\n callsUsed: number;\n selector: \"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector;\n target: `0x${string}`;\n valueSpent: bigint;\n }[];\n kind: \"native\";\n} | {\n amountSpent: bigint;\n callsUsed: number;\n kind: \"native\";\n valueSpent: bigint;\n} | {\n assets: {\n spent: bigint;\n token: string;\n }[];\n kind: \"universal\";\n}" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "CreateOptions": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions", + "members": { + "progressHook": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook | undefined" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleInput[]" + } + } + }, + "CreateResult": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateResult", + "members": { + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "rulesIds": { + "optional": false, + "readonly": false, + "type": "`0x${string}`[]" + }, + "tx": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticTxMetadata": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticTxMetadata", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destinationAccount": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "destinationCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "destinationInstruction": { + "optional": true, + "readonly": false, + "type": "{\n accounts: readonly {\n isWritable: boolean;\n pubkey: `0x${string}`;\n }[];\n data: `0x${string}`;\n program: `0x${string}`;\n} | undefined" + }, + "destinationTransfer": { + "optional": true, + "readonly": false, + "type": "{\n amount: bigint;\n recipient: `0x${string}`;\n token: `0x${string}`;\n} | undefined" + }, + "door": { + "optional": false, + "readonly": false, + "type": "\"agent\" | \"owner\"" + }, + "nativeCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "rawData": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rawTo": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesId": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + } + }, + "publicSurface": { + "CHAIN": { + "type": "typeof import(\"sdk/src/lib/constants/enums\").CHAIN", + "members": { + "ARBITRUM_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA" + }, + "BASE_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA" + }, + "BNB_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET" + }, + "ETHEREUM_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET" + }, + "ETHEREUM_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA" + }, + "PUSH_LOCALNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET" + }, + "PUSH_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET" + }, + "PUSH_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET" + }, + "PUSH_TESTNET_DONUT": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET" + }, + "SOLANA_DEVNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET" + }, + "SOLANA_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET" + }, + "SOLANA_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET" + }, + "WEB2": { + "optional": false, + "readonly": false, + "type": "\"web2\"" + } + } + }, + "ConversionQuote": { + "type": "import(\"sdk/src/lib/constants/tokens\").ConversionQuote", + "members": { + "amountIn": { + "optional": false, + "readonly": false, + "type": "string" + }, + "amountOut": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rate": { + "optional": false, + "readonly": false, + "type": "number" + }, + "route": { + "optional": true, + "readonly": false, + "type": "string[] | undefined" + }, + "timestamp": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "UniversalSigner": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalSigner", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "signAndSendTransaction": { + "optional": false, + "readonly": false, + "type": "(unsignedTx: Uint8Array) => Promise" + }, + "signAuthorization": { + "optional": true, + "readonly": false, + "type": "((params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise) | undefined" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": true, + "readonly": false, + "type": "(({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise) | undefined" + } + } + }, + "UniversalAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "UniversalSignerSkeleton": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "signAndSendTransaction": { + "optional": false, + "readonly": false, + "type": "(unsignedTx: Uint8Array) => Promise" + }, + "signAuthorization": { + "optional": true, + "readonly": false, + "type": "((params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise) | undefined" + }, + "signerId": { + "optional": false, + "readonly": false, + "type": "string" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": true, + "readonly": false, + "type": "(({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise) | undefined" + } + } + }, + "SignAuthorizationParams": { + "type": "{\n chainId?: number;\n contractAddress: `0x${string}`;\n executor?: \"self\";\n nonce?: number;\n}", + "members": { + "chainId": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "contractAddress": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "executor": { + "optional": true, + "readonly": false, + "type": "\"self\" | undefined" + }, + "nonce": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "SignedAuthorization": { + "type": "{\n address: `0x${string}`;\n chainId: number;\n nonce: number;\n r: `0x${string}`;\n s: `0x${string}`;\n v?: bigint;\n yParity: number;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainId": { + "optional": false, + "readonly": false, + "type": "number" + }, + "nonce": { + "optional": false, + "readonly": false, + "type": "number" + }, + "r": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "s": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "v": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "yParity": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "DerivedExecutorAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").DerivedExecutorAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean | null" + } + } + }, + "ResolvedAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainName": { + "optional": false, + "readonly": false, + "type": "string" + }, + "exists": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "role": { + "optional": true, + "readonly": false, + "type": "\"controller\" | undefined" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"cea\" | \"uea\" | \"uoa\"" + } + } + }, + "ResolvedControllerAccounts": { + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedControllerAccounts", + "members": { + "accounts": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedAccount[]" + } + } + }, + "AccountType": { + "type": "\"cea\" | \"uea\" | \"uoa\"", + "members": {} + }, + "AccountRole": { + "type": "\"controller\"", + "members": {} + }, + "PC20TokenReference": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "FundsToken": { + "type": "import(\"sdk/src/lib/constants/tokens\").MoveableToken | import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20TokenReference", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "PC20RegistryEntry": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "chainName": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "PC20AddressResult": { + "type": "{\n address: `0x${string}`;\n decimals: number;\n name: string;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n registry: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20RegistryEntry[];\n symbol: string;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "decimals": { + "optional": false, + "readonly": false, + "type": "number" + }, + "name": { + "optional": false, + "readonly": false, + "type": "string" + }, + "network": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "registry": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20RegistryEntry[]" + }, + "symbol": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "isPC20Reference": { + "type": "(token: import(\"sdk/src/lib/orchestrator/orchestrator.types\").FundsToken | undefined) => token is import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20TokenReference", + "members": {} + }, + "PC20Error": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20Error", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidPC20AddressError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InvalidPC20AddressError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20TokenChainMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20TokenChainMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20WrapperNotRegisteredError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20WrapperNotRegisteredError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20RegistryMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20RegistryMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20FactoryMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20FactoryMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidPC20MetadataError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InvalidPC20MetadataError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20ExpectedButPRC20Error": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20ExpectedButPRC20Error", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20AmbiguousAddressError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20AmbiguousAddressError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "candidates": { + "optional": false, + "readonly": true, + "type": "{\n chain: string;\n pushAddress: string;\n}[]" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "UnsupportedPC20DestinationError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").UnsupportedPC20DestinationError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InsufficientPC20BalanceError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InsufficientPC20BalanceError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20UnknownChainNamespaceError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20UnknownChainNamespaceError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20WrapperPredictionUnavailableError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20WrapperPredictionUnavailableError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20ExportRevertedError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20ExportRevertedError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "lockedAmount": { + "optional": true, + "readonly": true, + "type": "bigint | undefined" + }, + "outboundTxId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "revertRecipient": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20UnsafeEmptyPayloadError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20UnsafeEmptyPayloadError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ChainTarget": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "ChainSource": { + "type": "{\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "UniversalTo": { + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget", + "members": {} + }, + "TransactionRouteType": { + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"", + "members": {} + }, + "UniversalExecuteParams": { + "type": "{\n from?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainSource;\n migration?: boolean;\n to: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTo;\n} & Omit", + "members": { + "_minimumDepositUsd": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "_requiredFundsOverride": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "_skipFeeLocking": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "_ueaStatus": { + "optional": true, + "readonly": false, + "type": "{\n balance: bigint;\n isDeployed: boolean;\n nonce: bigint;\n} | undefined" + }, + "data": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiCall[] | undefined" + }, + "deadline": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "feeLockTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "from": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainSource | undefined" + }, + "funds": { + "optional": true, + "readonly": false, + "type": "{\n amount: bigint;\n token?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").FundsToken;\n} | undefined" + }, + "gasLimit": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFeePerGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxPCForGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxPriorityFeePerGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "migration": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "nonce": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "options": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions | undefined" + }, + "payGasWith": { + "optional": true, + "readonly": false, + "type": "{\n minAmountOut?: bigint | string;\n slippageBps?: number;\n token?: import(\"sdk/src/lib/constants/tokens\").PayableToken;\n} | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "to": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget" + }, + "value": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "UniversalOutboundTxRequest": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalOutboundTxRequest", + "members": { + "amount": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gasPrice": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxPCForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "payload": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "recipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "revertRecipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "PreparedUniversalTx": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx", + "members": { + "_hop": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").HopDescriptor" + }, + "deadline": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "estimatedGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gatewayRequest": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalOutboundTxRequest | import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxRequest" + }, + "nonce": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "payload": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + } + } + }, + "CascadedTxResponse": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadedTxResponse", + "members": { + "finalTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hopCount": { + "optional": false, + "readonly": false, + "type": "number" + }, + "hops": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo[]" + }, + "initialTxHash": { + "optional": false, + "readonly": false, + "type": "string" + }, + "initialTxResponse": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions) => Promise" + }, + "waitForAll": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions) => Promise" + } + } + }, + "CascadeHopInfo": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo", + "members": { + "executionChain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "expectedSubTxId": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hopIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "outboundDetails": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").OutboundTxDetails | undefined" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + }, + "status": { + "optional": false, + "readonly": false, + "type": "\"confirmed\" | \"failed\" | \"pending\" | \"submitted\"" + }, + "txHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "CascadeTrackOptions": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions", + "members": { + "eventHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeProgressEvent) => void) | undefined" + }, + "timeout": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "CascadeProgressEvent": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeProgressEvent", + "members": { + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "elapsed": { + "optional": false, + "readonly": false, + "type": "number" + }, + "hopIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + }, + "status": { + "optional": false, + "readonly": false, + "type": "\"confirmed\" | \"failed\" | \"found\" | \"polling\" | \"timeout\" | \"waiting\"" + }, + "txHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "CascadeCompletionResult": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeCompletionResult", + "members": { + "failedAt": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "finalTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "finalTxResponse": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadedTxResponse | undefined" + }, + "hops": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo[]" + }, + "success": { + "optional": false, + "readonly": false, + "type": "boolean" + } + } + }, + "MultiChainTxResponse": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiChainTxResponse", + "members": { + "chains": { + "optional": false, + "readonly": false, + "type": "{\n blockNumber: bigint;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n hash: string;\n status: \"confirmed\" | \"failed\" | \"pending\";\n}[]" + }, + "transactions": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse[]" + } + } + }, + "OutboundTxDetails": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").OutboundTxDetails", + "members": { + "amount": { + "optional": false, + "readonly": false, + "type": "string" + }, + "assetAddr": { + "optional": false, + "readonly": false, + "type": "string" + }, + "destinationChain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "explorerUrl": { + "optional": false, + "readonly": false, + "type": "string" + }, + "externalTxHash": { + "optional": false, + "readonly": false, + "type": "string" + }, + "recipient": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "WaitForOutboundOptions": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").WaitForOutboundOptions", + "members": { + "_expectedDestinationChain": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "_outboundIndex": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "_resolvedSubTxId": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "initialWaitMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: {\n elapsed: number;\n status: \"failed\" | \"found\" | \"polling\" | \"timeout\" | \"waiting\";\n}) => void) | undefined" + }, + "timeout": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "SvmGatewayAccountMeta": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmGatewayAccountMeta", + "members": { + "isWritable": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "pubkey": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "SvmExecutePayloadFields": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmExecutePayloadFields", + "members": { + "accounts": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmGatewayAccountMeta[]" + }, + "instructionId": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "ixData": { + "optional": false, + "readonly": false, + "type": "Uint8Array" + }, + "targetProgram": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AccountStatus": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus", + "members": { + "mode": { + "optional": false, + "readonly": false, + "type": "\"read-only\" | \"signer\"" + }, + "uea": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UEAStatus" + } + } + }, + "UEAStatus": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UEAStatus", + "members": { + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "loaded": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "minRequiredVersion": { + "optional": false, + "readonly": false, + "type": "string" + }, + "requiresUpgrade": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "version": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "RescueFundsParams": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").RescueFundsParams", + "members": { + "prc20": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "universalTxId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "parseUEAVersion": { + "type": "(version: string) => number", + "members": {} + }, + "TransactionRoute": { + "type": "typeof import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute", + "members": { + "CEA_TO_CEA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.CEA_TO_CEA" + }, + "CEA_TO_PUSH": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.CEA_TO_PUSH" + }, + "UOA_TO_CEA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.UOA_TO_CEA" + }, + "UOA_TO_PUSH": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.UOA_TO_PUSH" + } + } + }, + "detectRoute": { + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams) => import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute", + "members": {} + }, + "isChainTarget": { + "type": "(to: unknown) => to is import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget", + "members": {} + }, + "DEFAULT_MAX_PC_FOR_GAS_BUFFER_BPS": { + "type": "1000", + "members": {} + }, + "MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT": { + "type": "10000", + "members": {} + }, + "quoteMaxPCForGasCap": { + "type": "(input: import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapInput) => import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": {} + }, + "quoteMaxPCForGasCapFromNativeValue": { + "type": "(input: import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapFromNativeValueInput) => import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": {} + }, + "MaxPCForGasCapInput": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapInput", + "members": { + "bufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "gasLegNativePc": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "MaxPCForGasCapFromNativeValueInput": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapFromNativeValueInput", + "members": { + "bufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "nativeValueForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "MaxPCForGasCapQuote": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": { + "bufferBps": { + "optional": false, + "readonly": false, + "type": "number" + }, + "gasLegNativePc": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxPCForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "nativeValueForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "getCEAAddress": { + "type": "(ueaAddress: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise", + "members": {} + }, + "getPushAccountForCEA": { + "type": "(ceaAddress: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise<`0x${string}`>", + "members": {} + }, + "isCEA": { + "type": "(address: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise", + "members": {} + }, + "chainSupportsCEA": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "chainSupportsOutbound": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "getCEAFactoryAddress": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => `0x${string}` | undefined", + "members": {} + }, + "getAllCEAAddresses": { + "type": "(ueaAddress: `0x${string}`, rpcUrls?: Partial>) => Promise", + "members": {} + }, + "encodeSvmExecutePayload": { + "type": "(fields: import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmExecutePayloadFields) => `0x${string}`", + "members": {} + }, + "isSvmChain": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "isValidSolanaHexAddress": { + "type": "(address: string) => boolean", + "members": {} + }, + "buildMigrationPayload": { + "type": "() => `0x${string}`", + "members": {} + }, + "buildErc20WithdrawalMulticall": { + "type": "(tokenAddress: `0x${string}`, recipientAddress: `0x${string}`, amount: bigint) => import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiCall[]", + "members": {} + }, + "ReadChain": { + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain", + "members": {} + }, + "ReadDestination": { + "type": "{\n chain: import(\"sdk/src/lib/read-state/read-state.types\").ReadChain;\n} | {\n chainId: string;\n chainNamespace: string;\n}", + "members": {} + }, + "ResolvedDestination": { + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}", + "members": { + "caip2": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainId": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "namespace": { + "optional": false, + "readonly": false, + "type": "\"eip155\" | \"solana\" | \"web2\"" + } + } + }, + "ReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").SvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery", + "members": { + "type": { + "optional": false, + "readonly": false, + "type": "\"accountBalance\" | \"contractCall\" | \"http\" | \"lamportBalance\" | \"rawAccountData\" | \"splTokenAccount\" | \"storageSlot\"" + } + } + }, + "EvmReadQuery": { + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n target: `0x${string}`;\n type: \"contractCall\";\n} | {\n callData: `0x${string}`;\n target: `0x${string}`;\n type: \"contractCall\";\n} | {\n slot: `0x${string}` | bigint;\n target: `0x${string}`;\n type: \"storageSlot\";\n} | {\n target: `0x${string}`;\n type: \"accountBalance\";\n}", + "members": { + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"accountBalance\" | \"contractCall\" | \"storageSlot\"" + } + } + }, + "SvmReadQuery": { + "type": "{\n account: string | Uint8Array;\n accountName?: string;\n idl?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n type: \"rawAccountData\";\n} | {\n account: string | Uint8Array;\n type: \"lamportBalance\";\n} | {\n account: string | Uint8Array;\n type: \"splTokenAccount\";\n}", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "string | Uint8Array" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"lamportBalance\" | \"rawAccountData\" | \"splTokenAccount\"" + } + } + }, + "Web2ReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery", + "members": { + "body": { + "optional": true, + "readonly": false, + "type": "string | Uint8Array | undefined" + }, + "extract": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[]" + }, + "headers": { + "optional": true, + "readonly": false, + "type": "Record | undefined" + }, + "method": { + "optional": true, + "readonly": false, + "type": "\"GET\" | \"POST\" | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"http\"" + }, + "url": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "Web2Extract": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract", + "members": { + "decimals": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "path": { + "optional": false, + "readonly": false, + "type": "string" + }, + "valueType": { + "optional": false, + "readonly": false, + "type": "\"bool\" | \"bytes\" | \"int256\" | \"string\" | \"uint256\"" + } + } + }, + "Web2ValueType": { + "type": "\"bool\" | \"bytes\" | \"int256\" | \"string\" | \"uint256\"", + "members": {} + }, + "EncodedReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery", + "members": { + "blockRef": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "encoded": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "namespace": { + "optional": false, + "readonly": false, + "type": "\"eip155\" | \"solana\" | \"web2\"" + }, + "ownerBytes": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "queryType": { + "optional": false, + "readonly": false, + "type": "number" + }, + "resultShape": { + "optional": false, + "readonly": false, + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}" + }, + "warnings": { + "optional": false, + "readonly": false, + "type": "string[]" + } + } + }, + "ReadResultShape": { + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"bytes32\" | \"evmCall\" | \"raw\" | \"svmAccount\" | \"uint256\" | \"web2\"" + } + } + }, + "DecodedReadResult": { + "type": "{\n accountName: string;\n kind: \"svmAccount\";\n value: unknown;\n} | {\n kind: \"bytes32\";\n value: `0x${string}`;\n} | {\n kind: \"evmCall\";\n value: unknown;\n} | {\n kind: \"raw\";\n value: `0x${string}`;\n} | {\n kind: \"uint256\";\n value: bigint;\n} | {\n kind: \"web2\";\n values: readonly unknown[];\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"bytes32\" | \"evmCall\" | \"raw\" | \"svmAccount\" | \"uint256\" | \"web2\"" + } + } + }, + "ReadPreflight": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight", + "members": { + "destination": { + "optional": false, + "readonly": false, + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}" + }, + "fetchedAt": { + "optional": false, + "readonly": false, + "type": "number" + }, + "observedChainHeight": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pushBlockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pushGasPrice": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "universalCallback": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "universalCore": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ReadSpec": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "{\n chainId: string;\n chainNamespace: string;\n owner: `0x${string}`;\n}" + }, + "blockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "expiryPushChainHeight": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "minConfirmations": { + "optional": false, + "readonly": false, + "type": "number" + }, + "query": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "revertRecipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ReadSpecTuple": { + "type": "readonly [\n readonly [\n string,\n string,\n `0x${string}`\n ],\n `0x${string}`,\n number,\n bigint,\n bigint,\n bigint,\n `0x${string}`\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "readonly [\n string,\n string,\n `0x${string}`\n]" + }, + "1": { + "optional": false, + "readonly": true, + "type": "`0x${string}`" + }, + "2": { + "optional": false, + "readonly": true, + "type": "number" + }, + "3": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "4": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "5": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "6": { + "optional": false, + "readonly": true, + "type": "`0x${string}`" + }, + "length": { + "optional": false, + "readonly": true, + "type": "7" + } + } + }, + "BuildReadSpecParams": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").BuildReadSpecParams", + "members": { + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "budgetBuffer": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback | undefined" + }, + "callbackBudget": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "destination": { + "optional": false, + "readonly": false, + "type": "{\n chain: import(\"sdk/src/lib/read-state/read-state.types\").ReadChain;\n} | {\n chainId: string;\n chainNamespace: string;\n}" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "expiryPushChainHeight": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFeeBufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "owner": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "query": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").SvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "PreparedRead": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead", + "members": { + "__@preparedReadValue": { + "optional": true, + "readonly": true, + "type": "T | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback | undefined" + }, + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "encodedQuery": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery" + }, + "encodedSpec": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "fees": { + "optional": false, + "readonly": false, + "type": "{\n callbackBudget: bigint;\n protocolFee: bigint;\n total: bigint;\n}" + }, + "preflight": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "queryKey": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "resultShape": { + "optional": false, + "readonly": false, + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}" + }, + "spec": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec" + }, + "specTuple": { + "optional": false, + "readonly": false, + "type": "readonly [\n readonly [\n string,\n string,\n `0x${string}`\n ],\n `0x${string}`,\n number,\n bigint,\n bigint,\n bigint,\n `0x${string}`\n]" + }, + "value": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "warnings": { + "optional": false, + "readonly": false, + "type": "string[]" + } + } + }, + "ReadCallback": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "((spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpecTuple, callbackGasLimit: bigint) => readonly unknown[]) | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "gasLimit": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "target": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "SimulateReadResult": { + "type": "{\n args?: readonly unknown[];\n error: string;\n errorName?: string;\n ok: false;\n} | {\n ok: true;\n}", + "members": { + "ok": { + "optional": false, + "readonly": false, + "type": "boolean" + } + } + }, + "ParsedReadRequest": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ParsedReadRequest", + "members": { + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackTarget": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "logIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "originalFunder": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "requestId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "requestIdUint": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "spec": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec" + }, + "totalPaid": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "FulfilOutcome": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").FulfilOutcome", + "members": { + "burned": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "delivered": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "expired": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "failReason": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "gasReported": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refunded": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refundFailed": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "ReceiptLike": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike", + "members": { + "logs": { + "optional": false, + "readonly": false, + "type": "readonly {\n address: string;\n data: string;\n logIndex?: number | string;\n topics: readonly string[];\n}[]" + } + } + }, + "ReadRef": { + "type": "{\n requestId: `0x${string}` | bigint;\n} | {\n txHash: `0x${string}`;\n}", + "members": {} + }, + "ReadLifecycleOptions": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadLifecycleOptions", + "members": { + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "resultShape": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadFees": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadFees", + "members": { + "burned": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "paid": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "refunded": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refundFailed": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + } + } + }, + "UniversalReadResponse": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse", + "members": { + "callbackDelivered": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "callbackFailReason": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "decoded": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").DecodedReadResult | undefined" + }, + "decodeError": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destination": { + "optional": false, + "readonly": false, + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}" + }, + "errorMsg": { + "optional": false, + "readonly": false, + "type": "string" + }, + "explorerUrl": { + "optional": false, + "readonly": false, + "type": "string" + }, + "fees": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadFees" + }, + "isTerminal": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "outcome": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME" + }, + "pcTx": { + "optional": false, + "readonly": false, + "type": "readonly {\n blockHeight: number;\n errorMsg: string;\n status: string;\n txHash: `0x${string}`;\n}[]" + }, + "raw": { + "optional": false, + "readonly": false, + "type": "{\n errorCode: import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n resultData: `0x${string}`;\n status: import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n} | null" + }, + "refresh": { + "optional": false, + "readonly": false, + "type": "() => Promise>" + }, + "request": { + "optional": false, + "readonly": false, + "type": "{\n callbackGasLimit: bigint;\n callbackTarget: `0x${string}`;\n createdAtHeight: bigint;\n logIndex: number;\n originalFunder: `0x${string}`;\n refundTo: `0x${string}`;\n spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec;\n}" + }, + "requestId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "requestIdUint": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "status": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "value": { + "optional": true, + "readonly": false, + "type": "T | undefined" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/read-state/read-state.types\").ReadLifecycleOptions) => Promise>" + } + } + }, + "ReadResponseTuple": { + "type": "{\n -readonly [K in keyof R]: import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse ? T : unknown>;\n}", + "members": {} + }, + "BatchReadResponse": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").BatchReadResponse", + "members": { + "atomic": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "count": { + "optional": false, + "readonly": false, + "type": "number" + }, + "reads": { + "optional": false, + "readonly": false, + "type": "{\n -readonly [K in keyof R]: import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse ? T : unknown>;\n}" + }, + "transactionHashes": { + "optional": true, + "readonly": false, + "type": "readonly `0x${string}`[] | undefined" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: Omit) => Promise>" + } + } + }, + "ReadOptions": { + "type": "((import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">)) & {\n callback?: (Pick & Required>) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n };\n}", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "advanced": { + "optional": true, + "readonly": false, + "type": "{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n} | undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "({\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} & {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n}) | ({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick & Pick & Required>) | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadPrepareOptions": { + "type": "((((({\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\">) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n}) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">)) & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n}) | ((({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n}) | ({\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\">)) & {\n blockNumber?: never;\n minConfirmations?: never;\n})) & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n}) & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "advanced": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadQueryOptions": { + "type": "({\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\">) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n}) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n}) | ({\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\">)", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadCallbackOptions": { + "type": "{\n callback?: ({\n gasLimit?: bigint;\n target: `0x${string}`;\n } & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n };\n}", + "members": { + "callback": { + "optional": true, + "readonly": false, + "type": "({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} | undefined" + } + } + }, + "ReadValue": { + "type": "O extends {\n abi: infer A extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: infer F extends string;\n} ? number extends A[\"length\"] ? unknown : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, O extends {\n args: infer Args extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n} ? Args : readonly [\n] extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> ? import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> & readonly [\n] : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>> extends infer Selected ? Selected extends {\n outputs: readonly unknown[];\n type: \"function\";\n} & import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiFunction ? {\n [key in keyof {\n [key in keyof import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"]]: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterToPrimitiveType, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"][key], import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterKind>;\n }]: {\n [key in keyof import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"]]: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterToPrimitiveType, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"][key], import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterKind>;\n }[key];\n} extends infer types ? types extends readonly [\n] ? void : types extends readonly [\n infer type\n] ? type : types : never : never : never : O extends {\n web2: {\n extract: infer E extends readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n };\n} ? {\n readonly [K in keyof E]: {\n bool: boolean;\n bytes: `0x${string}`;\n int256: bigint;\n string: string;\n uint256: bigint;\n }[E[K][\"valueType\"]];\n} : O extends {\n storageSlot: unknown;\n} ? `0x${string}` : O extends {\n idl: infer I extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} ? string extends Extract, string> ? unknown : (O extends {\n functionName: infer N extends string;\n} ? N : undefined) extends string ? import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/index\").IdlAccounts[{\n [K in Extract, string>]: Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : K> extends Lowercase<(O extends {\n functionName: infer N extends string;\n } ? N : undefined) & string extends `${infer H}_${infer T}` ? `${H}${Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : (O extends {\n functionName: infer N extends string;\n } ? N : undefined) & string> ? K : never;\n}[Extract, string>]] : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/index\").IdlAccounts[Extract, string>] : bigint", + "members": {} + }, + "ValidateReadCall": { + "type": "O extends {\n abi: infer A extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: infer F extends string;\n} ? (readonly [\n] extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> ? {\n args?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n} : {\n args: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n}) & {\n functionName: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionName;\n} : O extends {\n functionName: infer N extends string;\n idl: infer I extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} ? string extends Extract, string> ? unknown : [\n {\n [K in Extract, string>]: Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : K> extends Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : N> ? K : never;\n }[Extract, string>]\n] extends [\n never\n] ? {\n functionName: Extract, string>;\n} : unknown : unknown", + "members": {} + }, + "ReadWeb2Options": { + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options", + "members": { + "body": { + "optional": true, + "readonly": false, + "type": "string | Uint8Array | undefined" + }, + "extract": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[]" + }, + "headers": { + "optional": true, + "readonly": false, + "type": "Record | undefined" + }, + "method": { + "optional": true, + "readonly": false, + "type": "\"GET\" | \"POST\" | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadTrackOptions": { + "type": "{\n advanced?: Omit, \"enforceGasCheck\">;\n resultShape?: import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape;\n}", + "members": { + "advanced": { + "optional": true, + "readonly": false, + "type": "Omit<{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n}, \"enforceGasCheck\"> | undefined" + }, + "resultShape": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape | undefined" + } + } + }, + "ReadExecuteOptions": { + "type": "{\n advanced?: {\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n } | undefined;\n progressHook?: ((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined;\n waitForCompletion?: boolean | undefined;\n}", + "members": { + "advanced": { + "optional": true, + "readonly": false, + "type": "{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n} | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + } + } + }, + "UNIVERSAL_READ_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS", + "members": { + "ABORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.ABORTED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.EXPIRED" + }, + "FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.FAILED" + }, + "FULFILLED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.FULFILLED" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.PENDING" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.UNSPECIFIED" + }, + "VOTING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.VOTING" + } + } + }, + "READ_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS", + "members": { + "ERROR": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.ERROR" + }, + "SUCCESS": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.SUCCESS" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.UNSPECIFIED" + } + } + }, + "READ_ERROR_CODE": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE", + "members": { + "INVALID_QUERY": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.INVALID_QUERY" + }, + "INVALID_RESULT": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.INVALID_RESULT" + }, + "NOT_FOUND": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.NOT_FOUND" + }, + "REJECTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.REJECTED" + }, + "REVERTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.REVERTED" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.UNSPECIFIED" + }, + "UNSUPPORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.UNSUPPORTED" + } + } + }, + "READ_OUTCOME": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME", + "members": { + "ABORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.ABORTED" + }, + "CALLBACK_FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.CALLBACK_FAILED" + }, + "DECODE_FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.DECODE_FAILED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.EXPIRED" + }, + "FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.FAILED" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.PENDING" + }, + "SOURCE_ERROR": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.SOURCE_ERROR" + }, + "SUCCESS": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.SUCCESS" + }, + "UNKNOWN": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.UNKNOWN" + } + } + }, + "CONTRACT_REQUEST_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS", + "members": { + "EXECUTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.EXECUTED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.EXPIRED" + }, + "NONE": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.NONE" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.PENDING" + }, + "SETTLED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.SETTLED" + } + } + }, + "TERMINAL_READ_STATUSES": { + "type": "ReadonlySet", + "members": {} + }, + "ReadStateError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadStateError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidReadQueryError": { + "type": "import(\"sdk/src/lib/read-state/errors\").InvalidReadQueryError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidReadSpecError": { + "type": "import(\"sdk/src/lib/read-state/errors\").InvalidReadSpecError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "violations": { + "optional": false, + "readonly": true, + "type": "readonly import(\"sdk/src/lib/read-state/errors\").ReadSpecViolation[]" + } + } + }, + "ReadHeightUnavailableError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadHeightUnavailableError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "UnsupportedReadDestinationError": { + "type": "import(\"sdk/src/lib/read-state/errors\").UnsupportedReadDestinationError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadDecodeError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadDecodeError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadTimeoutError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadTimeoutError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "lastStatus": { + "optional": false, + "readonly": true, + "type": "number" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadNotFoundError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadNotFoundError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadRegistryUnavailableError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadRegistryUnavailableError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadSpecViolation": { + "type": "\"CALLBACK_GAS_LIMIT_EXCEEDED\" | \"DOMAIN_BLOCKED\" | \"EMPTY_QUERY\" | \"EXCESSIVE_FEE\" | \"INSUFFICIENT_CALLBACK_BUDGET\" | \"INSUFFICIENT_FEE\" | \"INVALID_ACCOUNT_ID\" | \"INVALID_BLOCK_NUMBER\" | \"INVALID_EXPIRY_HEIGHT\" | \"INVALID_MIN_CONFIRMATIONS\" | \"SVM_OWNER_NOT_32_BYTES\" | \"ZERO_CALLBACK_BUDGET\" | \"ZERO_CALLBACK_GAS_LIMIT\" | \"ZERO_REVERT_RECIPIENT\"", + "members": {} + }, + "resolveDestination": { + "type": "(dest: import(\"sdk/src/lib/read-state/read-state.types\").ReadDestination) => import(\"sdk/src/lib/read-state/read-state.types\").ResolvedDestination", + "members": {} + }, + "encodeReadQuery": { + "type": "(destination: import(\"sdk/src/lib/read-state/read-state.types\").ReadDestination, query: import(\"sdk/src/lib/read-state/read-state.types\").ReadQuery, options?: {\n blockNumber?: bigint;\n minSlot?: bigint;\n}) => import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery", + "members": {} + }, + "decodeReadResult": { + "type": "(resultData: `0x${string}`, shape: import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape) => import(\"sdk/src/lib/read-state/read-state.types\").DecodedReadResult", + "members": {} + }, + "parseReadRequestsFromReceipt": { + "type": "(receipt: import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike, universalCallback: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").ParsedReadRequest[]", + "members": {} + }, + "parseFulfilOutcome": { + "type": "(receipt: import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike, universalCallback: `0x${string}`, requestId: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").FulfilOutcome", + "members": {} + }, + "buildReadSpecFromPreflight": { + "type": "(preflight: import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight, params: import(\"sdk/src/lib/read-state/read-state.types\").BuildReadSpecParams, defaults?: {\n refundTo?: `0x${string}`;\n}) => import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead", + "members": {} + }, + "validateReadSpec": { + "type": "(input: import(\"sdk/src/lib/read-state/validate\").ValidateReadSpecInput) => {\n ok: false;\n violations: import(\"sdk/src/lib/read-state/errors\").ReadSpecViolation[];\n} | {\n ok: true;\n}", + "members": {} + }, + "toCallData": { + "type": "(prepared: import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead, target: {\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: (spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpecTuple, callbackGasLimit: bigint) => readonly unknown[];\n functionName: string;\n}) => {\n data: `0x${string}`;\n value: bigint;\n}", + "members": {} + }, + "sizeCallbackBudget": { + "type": "(callbackGasLimit: bigint, pushGasPrice: bigint, buffer?: number) => bigint", + "members": {} + }, + "inferResultShape": { + "type": "(namespace: string, query: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape", + "members": {} + }, + "toRequestIdHex": { + "type": "(id: `0x${string}` | bigint) => `0x${string}`", + "members": {} + }, + "toReadQuery": { + "type": "(subject: string, o: ReadOptionsInput, resolvedTokenProgram?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@solana/web3.js/lib/index\").PublicKey) => import(\"sdk/src/lib/read-state/read-state.types\").ReadQuery", + "members": {} + }, + "UNIVERSAL_CALLBACK_EVM": { + "type": "readonly [\n {\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"requestExternalReadSelf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"estimateFee\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"statusOf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"enum RequestStatus\";\n readonly name: \"\";\n readonly type: \"uint8\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"isFulfilled\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getPendingRead\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly internalType: \"struct PendingRead\";\n readonly name: \"\";\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"totalEscrowed\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"blockedDomains\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly indexed: false;\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"readSpec\";\n readonly type: \"tuple\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"totalPaid\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"protocolFee\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ReadRequested\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"ReadFulfilled\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"reason\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"CallbackFailed\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"gasReported\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"burned\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"CallbackGasReported\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundSent\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundFailed\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RequestExpired\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"vaultPC\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ProtocolFeeDistributed\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidAccountId\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"EmptyQuery\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidMinConfirmations\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"DomainBlocked\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidBlockNumber\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidExpiryHeight\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroRevertRecipient\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroCallbackGasLimit\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint64\";\n readonly name: \"provided\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"max\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"CallbackGasLimitExceeded\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"required\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"InsufficientFee\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ExcessiveFee\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"actual\";\n readonly type: \"uint8\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"expected\";\n readonly type: \"uint8\";\n }\n ];\n readonly name: \"InvalidRequestStatus\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ContractIsPaused\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"CallerIsNotUCallbackModule\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n }\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"requestExternalReadSelf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n}" + }, + "1": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"estimateFee\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "2": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"statusOf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"enum RequestStatus\";\n readonly name: \"\";\n readonly type: \"uint8\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "3": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"isFulfilled\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "4": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getPendingRead\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly internalType: \"struct PendingRead\";\n readonly name: \"\";\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "5": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"totalEscrowed\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "6": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"blockedDomains\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "7": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly indexed: false;\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"readSpec\";\n readonly type: \"tuple\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"totalPaid\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"protocolFee\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ReadRequested\";\n readonly type: \"event\";\n}" + }, + "8": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"ReadFulfilled\";\n readonly type: \"event\";\n}" + }, + "9": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"reason\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"CallbackFailed\";\n readonly type: \"event\";\n}" + }, + "10": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"gasReported\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"burned\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"CallbackGasReported\";\n readonly type: \"event\";\n}" + }, + "11": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundSent\";\n readonly type: \"event\";\n}" + }, + "12": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundFailed\";\n readonly type: \"event\";\n}" + }, + "13": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RequestExpired\";\n readonly type: \"event\";\n}" + }, + "14": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"vaultPC\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ProtocolFeeDistributed\";\n readonly type: \"event\";\n}" + }, + "15": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidAccountId\";\n readonly type: \"error\";\n}" + }, + "16": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"EmptyQuery\";\n readonly type: \"error\";\n}" + }, + "17": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidMinConfirmations\";\n readonly type: \"error\";\n}" + }, + "18": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"DomainBlocked\";\n readonly type: \"error\";\n}" + }, + "19": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidBlockNumber\";\n readonly type: \"error\";\n}" + }, + "20": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidExpiryHeight\";\n readonly type: \"error\";\n}" + }, + "21": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroRevertRecipient\";\n readonly type: \"error\";\n}" + }, + "22": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroCallbackGasLimit\";\n readonly type: \"error\";\n}" + }, + "23": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint64\";\n readonly name: \"provided\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"max\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"CallbackGasLimitExceeded\";\n readonly type: \"error\";\n}" + }, + "24": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"required\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"InsufficientFee\";\n readonly type: \"error\";\n}" + }, + "25": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ExcessiveFee\";\n readonly type: \"error\";\n}" + }, + "26": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"actual\";\n readonly type: \"uint8\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"expected\";\n readonly type: \"uint8\";\n }\n ];\n readonly name: \"InvalidRequestStatus\";\n readonly type: \"error\";\n}" + }, + "27": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ContractIsPaused\";\n readonly type: \"error\";\n}" + }, + "28": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"CallerIsNotUCallbackModule\";\n readonly type: \"error\";\n}" + }, + "29": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n}" + }, + "length": { + "optional": false, + "readonly": true, + "type": "30" + } + } + }, + "UNIVERSAL_READ_REGISTRY_EVM": { + "type": "readonly [\n {\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n },\n {\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"read\";\n readonly outputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"universalCallback_\";\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"constructor\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"initialize\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getLocalContext\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"hasResult\";\n readonly outputs: readonly [\n {\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"onUniversalData\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"queryKeyOf\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes32\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"readerOf\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"requestOrderOf\";\n readonly outputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"universalCallback\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"resultByRequestId\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"latestResult\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"version\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"Initialized\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadRequested\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadStored\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidInitialization\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"NotInitializing\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroAddressInit\";\n readonly type: \"error\";\n }\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n },\n {\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"read\";\n readonly outputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n}" + }, + "1": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"universalCallback_\";\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"constructor\";\n}" + }, + "2": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"initialize\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n}" + }, + "3": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getLocalContext\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "4": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"hasResult\";\n readonly outputs: readonly [\n {\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "5": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"onUniversalData\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n}" + }, + "6": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"queryKeyOf\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes32\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "7": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"readerOf\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "8": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"requestOrderOf\";\n readonly outputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "9": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"universalCallback\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "10": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"resultByRequestId\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "11": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"latestResult\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "12": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"version\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"Initialized\";\n readonly type: \"event\";\n}" + }, + "13": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadRequested\";\n readonly type: \"event\";\n}" + }, + "14": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadStored\";\n readonly type: \"event\";\n}" + }, + "15": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidInitialization\";\n readonly type: \"error\";\n}" + }, + "16": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"NotInitializing\";\n readonly type: \"error\";\n}" + }, + "17": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n}" + }, + "18": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroAddressInit\";\n readonly type: \"error\";\n}" + }, + "length": { + "optional": false, + "readonly": true, + "type": "19" + } + } + }, + "PushChainExecutionError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").PushChainExecutionError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PushChainBatchExecutionError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").PushChainBatchExecutionError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": false, + "readonly": true, + "type": "`0x${string}`[]" + } + } + }, + "DecodedErrorPayload": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload", + "members": { + "decoded": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "name": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "selector": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "PushChainInitializeOptions": { + "type": "import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions", + "members": { + "agenticWallet": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "blockExplorers": { + "optional": true, + "readonly": false, + "type": "Partial> | undefined" + }, + "network": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "printTraces": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "rpcUrls": { + "optional": true, + "readonly": false, + "type": "Partial> | undefined" + } + } + }, + "AGENTIC_ERROR_CODE": { + "type": "{\n readonly AGENT_GAS_INSUFFICIENT: \"AGENT_GAS_INSUFFICIENT\";\n readonly AGENT_IS_OWNER: \"AGENT_IS_OWNER\";\n readonly AMBIGUOUS_RULE: \"AMBIGUOUS_RULE\";\n readonly ASSET_CHAIN_MISMATCH: \"ASSET_CHAIN_MISMATCH\";\n readonly CAPABILITY_UNAVAILABLE: \"CAPABILITY_UNAVAILABLE\";\n readonly DELETE_NEEDS_TARGET: \"DELETE_NEEDS_TARGET\";\n readonly DUPLICATE_RULE: \"DUPLICATE_RULE\";\n readonly FROM_NOT_ALLOWED: \"FROM_NOT_ALLOWED\";\n readonly INCONSISTENT_READ: \"INCONSISTENT_READ\";\n readonly INDEX_RACE: \"INDEX_RACE\";\n readonly INVALID_RULE: \"INVALID_RULE\";\n readonly NO_RULES_FOR_CHAIN: \"NO_RULES_FOR_CHAIN\";\n readonly NOT_AGENTIC_WALLET: \"NOT_AGENTIC_WALLET\";\n readonly NOT_ALLOWED_IN_AGENTIC_MODE: \"NOT_ALLOWED_IN_AGENTIC_MODE\";\n readonly NOT_OWNER_OR_AGENT: \"NOT_OWNER_OR_AGENT\";\n readonly NOT_WALLET_OWNER: \"NOT_WALLET_OWNER\";\n readonly READ_ONLY: \"READ_ONLY\";\n readonly RECEIPT_MISMATCH: \"RECEIPT_MISMATCH\";\n readonly RECEIPT_UNAVAILABLE: \"RECEIPT_UNAVAILABLE\";\n readonly RULE_NOT_FOUND: \"RULE_NOT_FOUND\";\n readonly RULE_READ_FAILED: \"RULE_READ_FAILED\";\n readonly TARGET_NOT_ON_RULE_CHAIN: \"TARGET_NOT_ON_RULE_CHAIN\";\n readonly WALLET_BALANCE_INSUFFICIENT: \"WALLET_BALANCE_INSUFFICIENT\";\n readonly WALLET_NOT_DEPLOYED: \"WALLET_NOT_DEPLOYED\";\n}", + "members": { + "AGENT_GAS_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\"" + }, + "AGENT_IS_OWNER": { + "optional": false, + "readonly": true, + "type": "\"AGENT_IS_OWNER\"" + }, + "AMBIGUOUS_RULE": { + "optional": false, + "readonly": true, + "type": "\"AMBIGUOUS_RULE\"" + }, + "ASSET_CHAIN_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"ASSET_CHAIN_MISMATCH\"" + }, + "CAPABILITY_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"CAPABILITY_UNAVAILABLE\"" + }, + "DELETE_NEEDS_TARGET": { + "optional": false, + "readonly": true, + "type": "\"DELETE_NEEDS_TARGET\"" + }, + "DUPLICATE_RULE": { + "optional": false, + "readonly": true, + "type": "\"DUPLICATE_RULE\"" + }, + "FROM_NOT_ALLOWED": { + "optional": false, + "readonly": true, + "type": "\"FROM_NOT_ALLOWED\"" + }, + "INCONSISTENT_READ": { + "optional": false, + "readonly": true, + "type": "\"INCONSISTENT_READ\"" + }, + "INDEX_RACE": { + "optional": false, + "readonly": true, + "type": "\"INDEX_RACE\"" + }, + "INVALID_RULE": { + "optional": false, + "readonly": true, + "type": "\"INVALID_RULE\"" + }, + "NO_RULES_FOR_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"NO_RULES_FOR_CHAIN\"" + }, + "NOT_AGENTIC_WALLET": { + "optional": false, + "readonly": true, + "type": "\"NOT_AGENTIC_WALLET\"" + }, + "NOT_ALLOWED_IN_AGENTIC_MODE": { + "optional": false, + "readonly": true, + "type": "\"NOT_ALLOWED_IN_AGENTIC_MODE\"" + }, + "NOT_OWNER_OR_AGENT": { + "optional": false, + "readonly": true, + "type": "\"NOT_OWNER_OR_AGENT\"" + }, + "NOT_WALLET_OWNER": { + "optional": false, + "readonly": true, + "type": "\"NOT_WALLET_OWNER\"" + }, + "READ_ONLY": { + "optional": false, + "readonly": true, + "type": "\"READ_ONLY\"" + }, + "RECEIPT_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_MISMATCH\"" + }, + "RECEIPT_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_UNAVAILABLE\"" + }, + "RULE_NOT_FOUND": { + "optional": false, + "readonly": true, + "type": "\"RULE_NOT_FOUND\"" + }, + "RULE_READ_FAILED": { + "optional": false, + "readonly": true, + "type": "\"RULE_READ_FAILED\"" + }, + "TARGET_NOT_ON_RULE_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"TARGET_NOT_ON_RULE_CHAIN\"" + }, + "WALLET_BALANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"WALLET_BALANCE_INSUFFICIENT\"" + }, + "WALLET_NOT_DEPLOYED": { + "optional": false, + "readonly": true, + "type": "\"WALLET_NOT_DEPLOYED\"" + } + } + }, + "AgenticError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"AMBIGUOUS_RULE\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"DELETE_NEEDS_TARGET\" | \"DUPLICATE_RULE\" | \"FROM_NOT_ALLOWED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"" + }, + "details": { + "optional": true, + "readonly": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "AgenticRevertError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticRevertError", + "members": { + "agenticCode": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "AgenticAddress": { + "type": "`0x${string}`", + "members": {} + }, + "AgenticDoor": { + "type": "\"agent\" | \"owner\"", + "members": {} + }, + "AgenticErrorCode": { + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"AMBIGUOUS_RULE\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"DELETE_NEEDS_TARGET\" | \"DUPLICATE_RULE\" | \"FROM_NOT_ALLOWED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"", + "members": {} + }, + "AgenticHex": { + "type": "`0x${string}`", + "members": {} + }, + "AgenticNamespace": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace", + "members": { + "create": { + "optional": false, + "readonly": false, + "type": "(label: string, options: import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions) => Promise" + }, + "derive": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n index?: number;\n}) => Promise<{\n address: `0x${string}`;\n deployed: boolean;\n index: number;\n}>" + }, + "list": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n wallets: import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary[];\n}>" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "(address: `0x${string}`) => import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet" + } + } + }, + "AgenticProgressHook": { + "type": "(event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void", + "members": {} + }, + "AgenticTxMetadata": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticTxMetadata", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destinationAccount": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "destinationCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "destinationInstruction": { + "optional": true, + "readonly": false, + "type": "{\n accounts: readonly {\n isWritable: boolean;\n pubkey: `0x${string}`;\n }[];\n data: `0x${string}`;\n program: `0x${string}`;\n} | undefined" + }, + "destinationTransfer": { + "optional": true, + "readonly": false, + "type": "{\n amount: bigint;\n recipient: `0x${string}`;\n token: `0x${string}`;\n} | undefined" + }, + "door": { + "optional": false, + "readonly": false, + "type": "\"agent\" | \"owner\"" + }, + "nativeCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "rawData": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rawTo": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesId": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticWallet": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "checkpoints": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n sinceBlock?: bigint;\n}) => Promise<{\n checkpoints: import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint[];\n}>" + }, + "info": { + "optional": false, + "readonly": false, + "type": "() => Promise" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n owner: `0x${string}`;\n}>" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "{\n add(rules: import(\"sdk/src/lib/agentic/agentic.types\").RuleInput[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise<{\n rulesIds: `0x${string}`[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n delete(rulesIds: `0x${string}`[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n delete(params: {\n all: true;\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n get(rulesId: `0x${string}`): Promise;\n list(): Promise<{\n rules: import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord[];\n }>;\n update(params: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n rules: {\n rule: import(\"sdk/src/lib/agentic/agentic.types\").RuleInput;\n rulesId: `0x${string}`;\n }[];\n }): Promise<{\n rules: {\n replaced: `0x${string}`;\n rulesId: `0x${string}`;\n }[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n}" + }, + "setLabel": { + "optional": false, + "readonly": false, + "type": "(label: string, opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n}) => Promise" + } + } + }, + "AllowedCall": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleCall", + "members": { + "app": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "label": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "maxValue": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "pins": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Pin[] | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector" + }, + "target": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "AssetCap": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset", + "members": { + "maxPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/tokens\").MoveableToken | string" + } + } + }, + "Checkpoint": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint", + "members": { + "blockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "kind": { + "optional": false, + "readonly": false, + "type": "\"OWNER_ACTION\" | \"RULES_GRANTED\" | \"RULES_REVOKED\"" + }, + "ref": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "seq": { + "optional": false, + "readonly": false, + "type": "number" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "CheckpointKind": { + "type": "\"OWNER_ACTION\" | \"RULES_GRANTED\" | \"RULES_REVOKED\"", + "members": {} + }, + "CreateOptions": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions", + "members": { + "progressHook": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook | undefined" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleInput[]" + } + } + }, + "CreateResult": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateResult", + "members": { + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "rulesIds": { + "optional": false, + "readonly": false, + "type": "`0x${string}`[]" + }, + "tx": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ForeignChainNamespace": { + "type": "`eip155:${string}` | `solana:${string}`", + "members": {} + }, + "DecodedSolanaRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").DecodedSolanaRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "assets": { + "optional": false, + "readonly": false, + "type": "{\n maxPerCall: bigint;\n maxTotal: bigint;\n token: string;\n}[]" + }, + "ceaAccounts": { + "optional": false, + "readonly": false, + "type": "readonly `0x${string}`[]" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "`solana:${string}`" + }, + "dataPins": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/agentic/codec/svm-terms\").SvmDataPinWire[]" + }, + "expectedCEA": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "format": { + "optional": false, + "readonly": false, + "type": "\"decoded\"" + }, + "gatewayProgram": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "maxGasPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pins": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/agentic/codec/svm-terms\").SvmAccountPinWire[]" + }, + "programs": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/agentic/codec/svm-terms\").AllowedProgramWire[]" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Rule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Rule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleCall[]" + }, + "assets": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset[] | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "maxGasPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "RuleInput": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").DecodedSolanaRule | import(\"sdk/src/lib/agentic/agentic.types\").Rule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "assets": { + "optional": true, + "readonly": false, + "type": "{\n maxPerCall: bigint;\n maxTotal: bigint;\n token: string;\n}[] | import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset[] | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "maxGasPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Pin": { + "type": "{\n account: number;\n arg?: never;\n expected: \"agentic:wallet\" | string;\n max?: never;\n token?: import(\"sdk/src/lib/constants/tokens\").MoveableToken | string;\n} | {\n account?: never;\n arg: import(\"sdk/src/lib/agentic/agentic.types\").ArgumentPath;\n expected: \"agentic:wallet\" | `0x${string}` | `0x${string}` | bigint;\n max?: never;\n} | {\n account?: never;\n arg: import(\"sdk/src/lib/agentic/agentic.types\").ArgumentPath;\n expected?: never;\n max: bigint;\n}", + "members": { + "account": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "arg": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ArgumentPath | undefined" + }, + "expected": { + "optional": true, + "readonly": false, + "type": "bigint | string | undefined" + }, + "max": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "Spent": { + "type": "{\n actions: {\n amountSpent: bigint;\n callsUsed: number;\n selector: \"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector;\n target: `0x${string}`;\n valueSpent: bigint;\n }[];\n kind: \"native\";\n} | {\n amountSpent: bigint;\n callsUsed: number;\n kind: \"native\";\n valueSpent: bigint;\n} | {\n assets: {\n spent: bigint;\n token: string;\n }[];\n kind: \"universal\";\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"native\" | \"universal\"" + } + } + }, + "WalletMarker": { + "type": "\"agentic:wallet\"", + "members": {} + }, + "ArgumentPath": { + "type": "number | readonly number[]", + "members": {} + }, + "RulesRecord": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "enabled": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "rule": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").DecodedSolanaRule | import(\"sdk/src/lib/agentic/agentic.types\").Rule" + }, + "rulesId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "spent": { + "optional": false, + "readonly": false, + "type": "{\n actions: {\n amountSpent: bigint;\n callsUsed: number;\n selector: \"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector;\n target: `0x${string}`;\n valueSpent: bigint;\n }[];\n kind: \"native\";\n} | {\n amountSpent: bigint;\n callsUsed: number;\n kind: \"native\";\n valueSpent: bigint;\n} | {\n assets: {\n spent: bigint;\n token: string;\n }[];\n kind: \"universal\";\n}" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Selector": { + "type": "`${string}(${string})` | `0x${string}`", + "members": {} + }, + "WalletInfo": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").WalletInfo", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "label": { + "optional": false, + "readonly": false, + "type": "string" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "rulesCount": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "WalletSummary": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "label": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesCount": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "PushChain": { + "type": "import(\"sdk/src/lib/push-chain/push-chain\").PushChain", + "members": { + "accountStatus": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus" + }, + "accountStatusReady": { + "optional": false, + "readonly": false, + "type": "Promise" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace" + }, + "explorer": { + "optional": false, + "readonly": false, + "type": "{\n getTransactionUrl: (txHash: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n listAllUrls: () => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n listUrls: (options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n}" + }, + "funds": { + "optional": false, + "readonly": false, + "type": "{\n getConversionQuote: (amountIn: bigint, options: {\n from: import(\"sdk/src/lib/constants/tokens\").PayableToken | undefined;\n to: import(\"sdk/src/lib/constants/tokens\").MoveableToken | undefined;\n }) => Promise;\n}" + }, + "getAccountStatus": { + "optional": false, + "readonly": false, + "type": "(options?: {\n forceRefresh?: boolean;\n}) => Promise" + }, + "isReadMode": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "moveable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").MoveableTokenAccessor;\n}" + }, + "payable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").PayableTokenAccessor;\n}" + }, + "reinitialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "universal": { + "optional": false, + "readonly": false, + "type": "{\n readonly account: `0x${string}`;\n executeReads: (reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>;\n executeTransactions: (txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise;\n migrateCEA: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"migrateCEA\"];\n readonly origin: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n prepareRead: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n prepareTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"prepareTransaction\"];\n read: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n rescueFunds: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"rescueFunds\"];\n sendTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"execute\"];\n signMessage: (data: Uint8Array) => Promise;\n signTypedData: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n trackRead: {\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n };\n trackTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"trackTransaction\"];\n}" + }, + "upgradeAccount": { + "optional": false, + "readonly": false, + "type": "(options?: {\n progressHook?: (progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n}) => Promise" + } + } + }, + "Preset": { + "type": "import(\"sdk/src/lib/agentic/presets/types\").Preset", + "members": { + "chains": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace[]" + }, + "constant": { + "optional": false, + "readonly": false, + "type": "\"DEXES\" | \"LENDING\" | \"PREDICTION\" | \"STAKING\"" + }, + "name": { + "optional": false, + "readonly": false, + "type": "string" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"CATEGORY\"" + } + } + }, + "PresetCategory": { + "type": "\"DEXES\" | \"LENDING\" | \"PREDICTION\" | \"STAKING\"", + "members": {} + }, + "PresetAsset": { + "type": "import(\"sdk/src/lib/agentic/presets/types\").PresetAsset", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "maxPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/tokens\").MoveableToken | string" + } + } + }, + "PresetOptions": { + "type": "import(\"sdk/src/lib/agentic/presets/types\").PresetOptions", + "members": { + "agent": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "assets": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/presets/types\").PresetAsset[] | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "maxGasPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "validUntil": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadyPresetOptions": { + "type": "import(\"sdk/src/lib/agentic/presets/types\").ReadyPresetOptions", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "assets": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/presets/types\").PresetAsset[] | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "maxGasPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "PresetRuleTemplate": { + "type": "{\n agent?: `0x${string}`;\n validUntil?: number;\n} & Omit", + "members": { + "agent": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleCall[]" + }, + "assets": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset[] | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "maxGasPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "validUntil": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "PresetResult": { + "type": "import(\"sdk/src/lib/agentic/presets/types\").PresetResult", + "members": { + "readiness": { + "optional": false, + "readonly": false, + "type": "{\n chains: import(\"sdk/src/lib/agentic/presets/types\").PresetChainReadiness[];\n ready: boolean;\n}" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "T[]" + } + } + }, + "PresetChainReadiness": { + "type": "import(\"sdk/src/lib/agentic/presets/types\").PresetChainReadiness", + "members": { + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "`eip155:${string}` | `solana:${string}`" + }, + "disabledCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/presets/types\").PresetCallIssue[]" + }, + "excludedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/presets/types\").PresetCallIssue[]" + }, + "issues": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/presets/types\").PresetConfigurationIssue[]" + }, + "knownTokens": { + "optional": false, + "readonly": false, + "type": "string[]" + }, + "ready": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "zeroBridgeLimits": { + "optional": false, + "readonly": false, + "type": "string[]" + } + } + }, + "PresetConfigurationIssue": { + "type": "import(\"sdk/src/lib/agentic/presets/types\").PresetConfigurationIssue", + "members": { + "code": { + "optional": false, + "readonly": false, + "type": "\"AGENT_REQUIRED\" | \"ASSETS_REQUIRED\" | \"EXPIRY_REQUIRED\" | \"GAS_BUDGET_REQUIRED\" | \"NO_ENABLED_OPERATION\" | \"TOKEN_PAIR_REQUIRED\"" + }, + "message": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "PresetCallIssue": { + "type": "import(\"sdk/src/lib/agentic/presets/types\").PresetCallIssue", + "members": { + "alternative": { + "optional": true, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector | undefined" + }, + "app": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "reason": { + "optional": false, + "readonly": false, + "type": "\"DYNAMIC_AMOUNT\" | \"POSITION_AMOUNT\" | \"SHARE_AMOUNT\" | \"TOKEN_REQUIRED\" | \"UNSELECTED_TOKEN\" | \"ZERO_CAP\"" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector" + }, + "target": { + "optional": false, + "readonly": false, + "type": "string" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "AgenticPresets": { + "type": "import(\"sdk/src/lib/agentic/presets/types\").AgenticPresets", + "members": { + "get": { + "optional": false, + "readonly": false, + "type": "{\n (preset: import(\"sdk/src/lib/agentic/presets/types\").PresetCategory, options: import(\"sdk/src/lib/agentic/presets/types\").ReadyPresetOptions): import(\"sdk/src/lib/agentic/presets/types\").PresetResult;\n (preset: import(\"sdk/src/lib/agentic/presets/types\").PresetCategory, options?: import(\"sdk/src/lib/agentic/presets/types\").PresetOptions): import(\"sdk/src/lib/agentic/presets/types\").PresetResult;\n}" + }, + "list": { + "optional": false, + "readonly": false, + "type": "(options?: {\n type?: \"CATEGORY\";\n}) => {\n presets: import(\"sdk/src/lib/agentic/presets/types\").Preset[];\n}" + } + } + } + }, + "pushChainStatic": { + "CONSTANTS": { + "optional": false, + "readonly": false, + "type": "{\n AGENTIC: Readonly<{\n PRESETS: Readonly<{\n CATEGORY: Readonly<{\n DEXES: \"DEXES\";\n LENDING: \"LENDING\";\n PREDICTION: \"PREDICTION\";\n STAKING: \"STAKING\";\n }>;\n }>;\n WALLET: \"agentic:wallet\";\n }>;\n CHAIN: typeof import(\"sdk/src/lib/constants/enums\").CHAIN;\n LIBRARY: typeof import(\"sdk/src/lib/constants/enums\").LIBRARY;\n MOVEABLE: {\n TOKEN: import(\"sdk/src/lib/constants/tokens\").MoveableTokenConstantsMap;\n };\n PAYABLE: {\n TOKEN: import(\"sdk/src/lib/constants/tokens\").PayableTokenConstantsMap;\n };\n PUSH_NETWORK: typeof import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n READ: {\n readonly CALLBACK_BUDGET_BUFFER: 3;\n readonly CHAIN: {\n readonly WEB2: \"web2\";\n } & Readonly<{\n readonly ARBITRUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA;\n readonly BASE_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA;\n readonly BNB_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET;\n readonly ETHEREUM_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET;\n readonly ETHEREUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA;\n readonly PUSH_LOCALNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET;\n readonly PUSH_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET;\n readonly PUSH_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly PUSH_TESTNET_DONUT: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly SOLANA_DEVNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET;\n readonly SOLANA_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET;\n readonly SOLANA_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n readonly WEB2: \"web2\";\n }>;\n readonly DEFAULT_EXPIRY_BLOCKS: 300n;\n readonly ERROR_CODE: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n readonly MAX_CALLBACK_GAS_LIMIT: 1000000n;\n readonly MIN_CONFIRMATIONS_FLOOR: 1;\n readonly NAMESPACE: {\n readonly EVM: \"eip155\";\n readonly SVM: \"solana\";\n readonly WEB2: \"web2\";\n };\n readonly OUTCOME: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME;\n readonly REGISTRY_CALLBACK_GAS: 500000n;\n readonly RESULT_STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n readonly STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS;\n readonly UNIVERSAL_CALLBACK_ADDRESSES: Record;\n readonly UNIVERSAL_CORE_ADDRESSES: Record;\n readonly UNIVERSAL_READ_REGISTRY_ADDRESS: {\n readonly TESTNET_DONUT: \"0x00000000000000000000000000000000000000b2\";\n };\n readonly WEB2: \"web2\";\n readonly WEB2_DEFAULT_TIMEOUT_MS: 5000;\n readonly WEB2_MAX_EXTRACT_ENTRIES: 16;\n };\n}" + }, + "initialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "utils": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/utils\").Utils" + } + }, + "pushChainInstance": { + "accountStatus": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus" + }, + "accountStatusReady": { + "optional": false, + "readonly": false, + "type": "Promise" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace" + }, + "explorer": { + "optional": false, + "readonly": false, + "type": "{\n getTransactionUrl: (txHash: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n listAllUrls: () => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n listUrls: (options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n}" + }, + "funds": { + "optional": false, + "readonly": false, + "type": "{\n getConversionQuote: (amountIn: bigint, options: {\n from: import(\"sdk/src/lib/constants/tokens\").PayableToken | undefined;\n to: import(\"sdk/src/lib/constants/tokens\").MoveableToken | undefined;\n }) => Promise;\n}" + }, + "getAccountStatus": { + "optional": false, + "readonly": false, + "type": "(options?: {\n forceRefresh?: boolean;\n}) => Promise" + }, + "isReadMode": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "moveable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").MoveableTokenAccessor;\n}" + }, + "payable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").PayableTokenAccessor;\n}" + }, + "reinitialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "universal": { + "optional": false, + "readonly": false, + "type": "{\n readonly account: `0x${string}`;\n executeReads: (reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>;\n executeTransactions: (txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise;\n migrateCEA: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"migrateCEA\"];\n readonly origin: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n prepareRead: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n prepareTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"prepareTransaction\"];\n read: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n rescueFunds: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"rescueFunds\"];\n sendTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"execute\"];\n signMessage: (data: Uint8Array) => Promise;\n signTypedData: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n trackRead: {\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n };\n trackTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"trackTransaction\"];\n}" + }, + "upgradeAccount": { + "optional": false, + "readonly": false, + "type": "(options?: {\n progressHook?: (progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n}) => Promise" + } + }, + "transactionMethods": { + "account": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "executeReads": { + "optional": false, + "readonly": false, + "type": "(reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>" + }, + "executeTransactions": { + "optional": false, + "readonly": false, + "type": "(txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise" + }, + "migrateCEA": { + "optional": false, + "readonly": false, + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => Promise" + }, + "origin": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "prepareRead": { + "optional": false, + "readonly": false, + "type": "(subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>" + }, + "prepareTransaction": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions) => Promise" + }, + "read": { + "optional": false, + "readonly": false, + "type": "(subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>" + }, + "rescueFunds": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").RescueFundsParams) => Promise" + }, + "sendTransaction": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").ExecuteParams | import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions) => Promise" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": false, + "readonly": false, + "type": "({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise" + }, + "trackRead": { + "optional": false, + "readonly": false, + "type": "{\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n}" + }, + "trackTransaction": { + "optional": false, + "readonly": false, + "type": "(txHash: string, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TrackTransactionOptions) => Promise" + } + }, + "utilityMethods": { + "account": { + "optional": false, + "readonly": false, + "type": "{\n convertExecutorToOriginAccount: (ueaAddress: `0x${string}`, options?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n }) => Promise;\n convertOriginToExecutor: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n onlyCompute?: boolean;\n }) => Promise;\n deriveExecutorAccount: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n skipNetworkCheck?: boolean;\n }) => Promise;\n fromChainAgnostic: (caip: string) => import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n resolveControllerAccount: (address: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n skipNetworkCheck?: boolean;\n }) => Promise;\n toChainAgnostic: (address: string, options: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n toUniversal: (address: string, options: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n}" + }, + "agentic": { + "optional": false, + "readonly": true, + "type": "{\n readonly presets: import(\"sdk/src/lib/agentic/presets/types\").AgenticPresets;\n}" + }, + "chains": { + "optional": false, + "readonly": false, + "type": "{\n getChainName: (chainNamespace: string) => string | undefined;\n getChainNamespace: (chainName: string) => string | undefined;\n getSupportedChains: (network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK) => {\n chains: import(\"sdk/src/lib/constants/enums\").CHAIN[];\n };\n getSupportedChainsByName: (network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK) => {\n chains: string[];\n };\n}" + }, + "conversion": { + "optional": false, + "readonly": false, + "type": "{\n slippageToMinAmount(amount: string, options: {\n slippageBps: number;\n }): string;\n}" + }, + "helpers": { + "optional": false, + "readonly": false, + "type": "{\n encodeTxData({ abi, idl, functionName, args, }: {\n abi?: any;\n args?: any[];\n functionName: string;\n idl?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n }): `0x${string}`;\n formatUnits(value: bigint | string, decimalsOrOptions: {\n decimals: number;\n precision?: number;\n } | number): string;\n getChainName: (chainName: string) => string | undefined;\n parseUnits(value: string, exponent: {\n decimals: number;\n } | number): bigint;\n}" + }, + "signer": { + "optional": false, + "readonly": false, + "type": "{\n construct: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options: {\n signAndSendTransaction: (unsignedTx: Uint8Array) => Promise;\n signAuthorization?: (params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise;\n signMessage: (data: Uint8Array) => Promise;\n signTypedData?: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n }) => import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton;\n toUniversal: (signer: import(\"sdk/src/lib/universal/universal.types\").EthersV5SignerType | import(\"sdk/src/lib/universal/universal.types\").EthersV6SignerType | import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton | import(\"sdk/src/lib/universal/universal.types\").ViemSignerType) => Promise;\n toUniversalFromKeypair: (clientOrAccount: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@solana/web3.js/lib/index\").Keypair | import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").WalletClient | import(\"sdk/src/lib/universal/universal.types\").EthersV6SignerType, { chain, library }: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n library: import(\"sdk/src/lib/constants/enums\").LIBRARY;\n }) => Promise;\n}" + }, + "svm": { + "optional": false, + "readonly": false, + "type": "{\n getRegisteredIdls: () => Array<{\n address: `0x${string}`;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n }>;\n registerIdl: (idl: unknown) => void;\n}" + }, + "tokens": { + "optional": false, + "readonly": false, + "type": "{\n getMoveableTokens(chainOrClient?: import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/push-chain/push-chain\").PushChain): {\n tokens: Array<{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n decimals: number;\n mechanism: \"approve\" | \"native\" | \"permit2\";\n prc20Address?: `0x${string}`;\n sourceChain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n symbol: string;\n }>;\n };\n getPayableTokens(chainOrClient?: import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/push-chain/push-chain\").PushChain): {\n tokens: Array<{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n decimals: number;\n mechanism: \"approve\" | \"native\" | \"permit2\";\n symbol: string;\n }>;\n };\n getPC20Address(address: string, options: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n rpcUrls?: Partial>;\n strict?: boolean;\n }): Promise;\n getPRC20Address: (token: {\n address: string;\n chain: string;\n } | import(\"sdk/src/lib/constants/tokens\").MoveableToken, options?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n }) => {\n address: `0x${string}`;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n decimals: number;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n symbol: string;\n };\n}" + } + }, + "initialize": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise", + "agwConstants": { + "PRESETS": { + "optional": false, + "readonly": true, + "type": "{\n readonly CATEGORY: Readonly<{\n DEXES: \"DEXES\";\n LENDING: \"LENDING\";\n PREDICTION: \"PREDICTION\";\n STAKING: \"STAKING\";\n }>;\n}" + }, + "WALLET": { + "optional": false, + "readonly": true, + "type": "\"agentic:wallet\"" + } + }, + "constants": { + "AGENTIC": { + "optional": false, + "readonly": false, + "type": "{\n readonly PRESETS: Readonly<{\n CATEGORY: Readonly<{\n DEXES: \"DEXES\";\n LENDING: \"LENDING\";\n PREDICTION: \"PREDICTION\";\n STAKING: \"STAKING\";\n }>;\n }>;\n readonly WALLET: \"agentic:wallet\";\n}" + }, + "CHAIN": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "LIBRARY": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").LIBRARY" + }, + "MOVEABLE": { + "optional": false, + "readonly": false, + "type": "{\n TOKEN: import(\"sdk/src/lib/constants/tokens\").MoveableTokenConstantsMap;\n}" + }, + "PAYABLE": { + "optional": false, + "readonly": false, + "type": "{\n TOKEN: import(\"sdk/src/lib/constants/tokens\").PayableTokenConstantsMap;\n}" + }, + "PUSH_NETWORK": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "READ": { + "optional": false, + "readonly": false, + "type": "{\n readonly CALLBACK_BUDGET_BUFFER: 3;\n readonly CHAIN: {\n readonly WEB2: \"web2\";\n } & Readonly<{\n readonly ARBITRUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA;\n readonly BASE_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA;\n readonly BNB_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET;\n readonly ETHEREUM_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET;\n readonly ETHEREUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA;\n readonly PUSH_LOCALNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET;\n readonly PUSH_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET;\n readonly PUSH_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly PUSH_TESTNET_DONUT: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly SOLANA_DEVNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET;\n readonly SOLANA_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET;\n readonly SOLANA_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n readonly WEB2: \"web2\";\n }>;\n readonly DEFAULT_EXPIRY_BLOCKS: 300n;\n readonly ERROR_CODE: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n readonly MAX_CALLBACK_GAS_LIMIT: 1000000n;\n readonly MIN_CONFIRMATIONS_FLOOR: 1;\n readonly NAMESPACE: {\n readonly EVM: \"eip155\";\n readonly SVM: \"solana\";\n readonly WEB2: \"web2\";\n };\n readonly OUTCOME: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME;\n readonly REGISTRY_CALLBACK_GAS: 500000n;\n readonly RESULT_STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n readonly STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS;\n readonly UNIVERSAL_CALLBACK_ADDRESSES: Record;\n readonly UNIVERSAL_CORE_ADDRESSES: Record;\n readonly UNIVERSAL_READ_REGISTRY_ADDRESS: {\n readonly TESTNET_DONUT: \"0x00000000000000000000000000000000000000b2\";\n };\n readonly WEB2: \"web2\";\n readonly WEB2_DEFAULT_TIMEOUT_MS: 5000;\n readonly WEB2_MAX_EXTRACT_ENTRIES: 16;\n}" + } + } + }, + "scope": "All root exports and declared public members, PushChain static/instance members, universal transaction methods, utility groups, readonly/optional markers and constants. Behavior/default/deployment changes need the written session review." +} diff --git a/plan/agw/research/preset-configuration-2026-10-16/build.log b/plan/agw/research/preset-configuration-2026-10-16/build.log new file mode 100644 index 00000000..72f46153 --- /dev/null +++ b/plan/agw/research/preset-configuration-2026-10-16/build.log @@ -0,0 +1,13 @@ + +> nx run core:build + +Compiling TypeScript files for project "core"... +Done compiling TypeScript files for project "core". +(node:52492) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. +(Use `node --trace-warnings ...` to show where the warning was created) + + + + NX Successfully ran target build for project core + + diff --git a/plan/agw/research/preset-configuration-2026-10-16/docs.log b/plan/agw/research/preset-configuration-2026-10-16/docs.log new file mode 100644 index 00000000..2755478b --- /dev/null +++ b/plan/agw/research/preset-configuration-2026-10-16/docs.log @@ -0,0 +1 @@ +AGW guide: 6 TypeScript blocks typechecked against public exports; no examples executed. diff --git a/plan/agw/research/preset-configuration-2026-10-16/focused-unit.log b/plan/agw/research/preset-configuration-2026-10-16/focused-unit.log new file mode 100644 index 00000000..3e744188 --- /dev/null +++ b/plan/agw/research/preset-configuration-2026-10-16/focused-unit.log @@ -0,0 +1,9 @@ +PASS core packages/core/src/lib/agentic/__tests__/preset-catalog.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/presets.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/preset-operation-limits.spec.ts + +Test Suites: 3 passed, 3 total +Tests: 54 passed, 54 total +Snapshots: 0 total +Time: 3.618 s +Ran all test suites within paths "packages/core/src/lib/agentic/__tests__/presets.spec.ts", "packages/core/src/lib/agentic/__tests__/preset-catalog.spec.ts", "packages/core/src/lib/agentic/__tests__/preset-operation-limits.spec.ts". diff --git a/plan/agw/research/preset-configuration-2026-10-16/lint.log b/plan/agw/research/preset-configuration-2026-10-16/lint.log new file mode 100644 index 00000000..71e637df --- /dev/null +++ b/plan/agw/research/preset-configuration-2026-10-16/lint.log @@ -0,0 +1,6 @@ + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/preset-operation-limits.spec.ts + 158:19 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +✖ 1 problem (0 errors, 1 warning) + diff --git a/plan/agw/research/preset-configuration-2026-10-16/live-attempt-evidence.jsonl b/plan/agw/research/preset-configuration-2026-10-16/live-attempt-evidence.jsonl new file mode 100644 index 00000000..810f4763 --- /dev/null +++ b/plan/agw/research/preset-configuration-2026-10-16/live-attempt-evidence.jsonl @@ -0,0 +1,4 @@ +{"name": "preset-aave-stage", "at": "2026-10-15T20:30:20.480Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "stage": "mint-submitted", "wallet": "0xa637F6Cfd678e0681B230EcbB6048DACf99cD879", "cea": "0x9DA9AbEF7385Fc6F29CF043dFf33c37c808E9470", "pushTx": "0xc8b66f3c89b869f9b047baaf52cccf65e9ee176a368b1889ded77b3a5d816b93"} +{"name": "preset-aave-stage", "at": "2026-10-15T20:45:29.813Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "stage": "mint-completed", "wallet": "0xa637F6Cfd678e0681B230EcbB6048DACf99cD879", "cea": "0x9DA9AbEF7385Fc6F29CF043dFf33c37c808E9470"} +{"name": "preset-expanded-wallet", "at": "2026-10-15T23:01:43.644Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "label": "e2e-preset-dex-eip155:97", "chain": "eip155:97", "wallet": "0x428C2015D6dbF89AF39E37749348CF532b0B0aAc", "cea": "0xFA6E5AF18Ad5471801F061e9fB9C8b8213E03731", "rulesId": "0x30b549e4e1a08a9284ff4128632329f07107935a9aff5a6e60222665f0f34a0c"} +{"name": "preset-expanded-wallet", "at": "2026-10-15T23:17:37.769Z", "network": "TESTNET_DONUT", "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", "label": "e2e-preset-base-lending", "chain": "eip155:84532", "wallet": "0x688bE5423F3B4b1156A1Cd41E9a7ea77224187FA", "cea": "0xFdb11460F139D3179661278cd4b5d9f7fCD0C4Fd", "rulesId": "0x067f98ef527a453b68ce09206c055734a1c22d67673b449854f35c2494233fe2"} diff --git a/plan/agw/research/preset-configuration-2026-10-16/local-contracts.log b/plan/agw/research/preset-configuration-2026-10-16/local-contracts.log new file mode 100644 index 00000000..d22f47d0 --- /dev/null +++ b/plan/agw/research/preset-configuration-2026-10-16/local-contracts.log @@ -0,0 +1,26 @@ +PASS core-agw-local packages/core/__agw-local__/v5-multiasset.spec.ts (7.871 s) + v6 multi-asset SDK management and execution + ✓ v6 EVM alternatives enforce both spender and MAX, and reads update losslessly (299 ms) + ✓ v6 refuses a bare alternative that bypasses a pinned function and too many initial rules (71 ms) + ✓ the shipped DEX catalog enforces tuple receiver/token/amount pins on actual v6 URP (394 ms) + ✓ a review-only DEX exactInputSingle call cannot spend tokens even after asset budgets are filled (200 ms) + ✓ a review-only DEX exactOutputSingle call cannot spend tokens even after asset budgets are filled (176 ms) + ✓ regenerated LENDING presets enforce new token/amount pins through atomic rules.update (694 ms) + ✓ regenerated STAKING presets enforce new token/amount pins through atomic rules.update (470 ms) + ✓ a fixture preset produces rules accepted by public create and enforced by real contracts (211 ms) + ✓ public create encodes two ordered assets; public get reconstructs source-token caps (143 ms) + ✓ a token from the wrong chain fails before deployment (32 ms) + ✓ a same-chain registry identity mismatch fails before deployment (15 ms) + ✓ both tokens execute under one rule and keep independent counters/limits (190 ms) + ✓ omitted and explicit zero totals both prohibit movement (239 ms) + ✓ empty user assets grants one zero-cap gas token and executes a call-only request (213 ms) + ✓ public update resets both counters in one batch and records five checkpoints (262 ms) + ✓ spend on the second asset after snapshot rolls back revoke/grant and checkpoint writes (159 ms) + ✓ out-of-band duplicate contract grants still make sends ambiguous (65 ms) + ✓ a legacy two-field envelope is refused by the actual v6 grant path (28 ms) + +Test Suites: 1 passed, 1 total +Tests: 18 passed, 18 total +Snapshots: 0 total +Time: 7.906 s, estimated 61 s +Ran all test suites within paths "packages/core/__agw-local__/v5-multiasset.spec.ts". diff --git a/plan/agw/research/preset-configuration-2026-10-16/local-origin-lookup-timeout.log b/plan/agw/research/preset-configuration-2026-10-16/local-origin-lookup-timeout.log new file mode 100644 index 00000000..a8e2aa64 --- /dev/null +++ b/plan/agw/research/preset-configuration-2026-10-16/local-origin-lookup-timeout.log @@ -0,0 +1,148 @@ +FAIL core-agw-local packages/core/__agw-local__/v5-multiasset.spec.ts (60.45 s) + v6 multi-asset SDK management and execution + ✕ v6 EVM alternatives enforce both spender and MAX, and reads update losslessly (41135 ms) + ✓ v6 refuses a bare alternative that bypasses a pinned function and too many initial rules (30 ms) + ✓ the shipped DEX catalog enforces tuple receiver/token/amount pins on actual v6 URP (2327 ms) + ✓ a review-only DEX exactInputSingle call cannot spend tokens even after asset budgets are filled (406 ms) + ✓ a review-only DEX exactOutputSingle call cannot spend tokens even after asset budgets are filled (424 ms) + ✓ regenerated LENDING presets enforce new token/amount pins through atomic rules.update (911 ms) + ✓ regenerated STAKING presets enforce new token/amount pins through atomic rules.update (1110 ms) + ✓ a fixture preset produces rules accepted by public create and enforced by real contracts (2746 ms) + ✓ public create encodes two ordered assets; public get reconstructs source-token caps (1896 ms) + ✓ a token from the wrong chain fails before deployment (11 ms) + ✓ a same-chain registry identity mismatch fails before deployment (2 ms) + ✓ both tokens execute under one rule and keep independent counters/limits (1810 ms) + ✓ omitted and explicit zero totals both prohibit movement (2050 ms) + ✓ empty user assets grants one zero-cap gas token and executes a call-only request (473 ms) + ✓ public update resets both counters in one batch and records five checkpoints (559 ms) + ✓ spend on the second asset after snapshot rolls back revoke/grant and checkpoint writes (861 ms) + ✓ out-of-band duplicate contract grants still make sends ambiguous (49 ms) + ✓ a legacy two-field envelope is refused by the actual v6 grant path (7 ms) + + ● v6 multi-asset SDK management and execution › v6 EVM alternatives enforce both spender and MAX, and reads update losslessly + + AgenticRevertError: The request took too long to respond. + + 163 | decodedError?: DecodedErrorPayload; + 164 | }; + > 165 | return new AgenticRevertError(e?.message ?? decoded?.name ?? 'AGW revert', { + | ^ + 166 | decodedError: decoded ?? e?.decodedError, + 167 | gatewayTxHash: e?.gatewayTxHash, + 168 | agenticCode: decoded?.name, + + at wrapSendError (src/lib/agentic/management/common.ts:165:12) + at atomicCreateFailure (src/lib/agentic/management/create.ts:201:32) + at createWallet (src/lib/agentic/management/create.ts:123:21) + at async setup (__agw-local__/v5-multiasset.spec.ts:91:21) + at async Object. (__agw-local__/v5-multiasset.spec.ts:166:35) + + Cause: + PushChainExecutionError: The request took too long to respond. + + 186 | ctx._routeTerminalEmitted = true; + 187 | if (!isUserDecline && !(err instanceof PushChainExecutionError)) { + > 188 | throw new PushChainExecutionError(errMsg, { cause: err }); + | ^ + 189 | } + 190 | throw err; + 191 | } + + at executeStandardPayload (src/lib/orchestrator/internals/execute-standard.ts:188:15) + at async Orchestrator.executeWithPolicy (src/lib/orchestrator/orchestrator.ts:471:11) + at async createWallet (src/lib/agentic/management/create.ts:121:10) + at async setup (__agw-local__/v5-multiasset.spec.ts:91:21) + at async Object. (__agw-local__/v5-multiasset.spec.ts:166:35) + + Cause: + ContractFunctionExecutionError: The request took too long to respond. + + URL: https://evm.donut.rpc.push.org/ + Request body: {"method":"eth_call","params":[{"data":"0xd0f4b0970000000000000000000000008a791620dd6260079bf849dc5567adc3f2fdc318","to":"0x00000000000000000000000000000000000000eA"},"latest"]} + + Raw Call Arguments: + to: 0x00000000000000000000000000000000000000eA + data: 0xd0f4b0970000000000000000000000008a791620dd6260079bf849dc5567adc3f2fdc318 + + Contract Call: + address: 0x00000000000000000000000000000000000000eA + function: getOriginForUEA(address addr) + args: (0x8a791620dd6260079bf849dc5567adc3f2fdc318) + + Docs: https://viem.sh/docs/contract/readContract + Details: The request timed out. + Version: viem@2.27.2 + + 486 | }); + 487 | + > 488 | const originResult = (await client.readContract({ + | ^ + 489 | address: FACTORY_ADDRESS, + 490 | abi: FACTORY_V1, + 491 | functionName: 'getOriginForUEA', + + at getContractError (../../node_modules/viem/utils/errors/getContractError.ts:78:10) + at readContract (../../node_modules/viem/actions/public/readContract.ts:136:27) + at async convertExecutorToOrigin (src/lib/universal/account/account.ts:488:25) + at async transformToUniversalTxResponse (src/lib/orchestrator/internals/response-builder.ts:625:5) + at async sendPushTx (src/lib/orchestrator/internals/push-chain-tx.ts:321:10) + at async executeStandardPayload (src/lib/orchestrator/internals/execute-standard.ts:173:12) + at async Orchestrator.executeWithPolicy (src/lib/orchestrator/orchestrator.ts:471:11) + at async createWallet (src/lib/agentic/management/create.ts:121:10) + at async setup (__agw-local__/v5-multiasset.spec.ts:91:21) + at async Object. (__agw-local__/v5-multiasset.spec.ts:166:35) + + Cause: + CallExecutionError: The request took too long to respond. + + URL: https://evm.donut.rpc.push.org/ + Request body: {"method":"eth_call","params":[{"data":"0xd0f4b0970000000000000000000000008a791620dd6260079bf849dc5567adc3f2fdc318","to":"0x00000000000000000000000000000000000000eA"},"latest"]} + + Raw Call Arguments: + to: 0x00000000000000000000000000000000000000eA + data: 0xd0f4b0970000000000000000000000008a791620dd6260079bf849dc5567adc3f2fdc318 + + Details: The request timed out. + Version: viem@2.27.2 + + 486 | }); + 487 | + > 488 | const originResult = (await client.readContract({ + | ^ + 489 | address: FACTORY_ADDRESS, + 490 | abi: FACTORY_V1, + 491 | functionName: 'getOriginForUEA', + + at getCallError (../../node_modules/viem/utils/errors/getCallError.ts:42:10) + at call (../../node_modules/viem/actions/public/call.ts:282:23) + at async readContract (../../node_modules/viem/actions/public/readContract.ts:120:22) + at async convertExecutorToOrigin (src/lib/universal/account/account.ts:488:25) + at async transformToUniversalTxResponse (src/lib/orchestrator/internals/response-builder.ts:625:5) + at async sendPushTx (src/lib/orchestrator/internals/push-chain-tx.ts:321:10) + at async executeStandardPayload (src/lib/orchestrator/internals/execute-standard.ts:173:12) + at async Orchestrator.executeWithPolicy (src/lib/orchestrator/orchestrator.ts:471:11) + at async createWallet (src/lib/agentic/management/create.ts:121:10) + at async setup (__agw-local__/v5-multiasset.spec.ts:91:21) + at async Object. (__agw-local__/v5-multiasset.spec.ts:166:35) + + Cause: + TimeoutError: The request took too long to respond. + + URL: https://evm.donut.rpc.push.org/ + Request body: {"method":"eth_call","params":[{"data":"0xd0f4b0970000000000000000000000008a791620dd6260079bf849dc5567adc3f2fdc318","to":"0x00000000000000000000000000000000000000eA"},"latest"]} + + Details: The request timed out. + Version: viem@2.27.2 + + at Object.request (../../node_modules/viem/utils/rpc/http.ts:124:28) + at fn (../../node_modules/viem/clients/transports/http.ts:145:35) + at request (../../node_modules/viem/clients/transports/http.ts:150:45) + at delay.count.count (../../node_modules/viem/utils/buildRequest.ts:150:28) + at attemptRetry (../../node_modules/viem/utils/promise/withRetry.ts:44:28) + at retry (../../node_modules/viem/utils/promise/withRetry.ts:40:9) + +Test Suites: 1 failed, 1 total +Tests: 1 failed, 17 passed, 18 total +Snapshots: 0 total +Time: 60.487 s +Ran all test suites within paths "packages/core/__agw-local__/v5-multiasset.spec.ts". diff --git a/plan/agw/research/preset-configuration-2026-10-16/markets-timeout.log b/plan/agw/research/preset-configuration-2026-10-16/markets-timeout.log new file mode 100644 index 00000000..23f5e546 --- /dev/null +++ b/plan/agw/research/preset-configuration-2026-10-16/markets-timeout.log @@ -0,0 +1,103 @@ +FAIL core-e2e __e2e__/agw/presets-expanded-live.spec.ts (2671.529 s) + agw presets expanded + ✕ 4. DEX swap and Venus round trip on eip155:97 (1719393 ms) + ✕ 5. Base Aave and both Moonwell markets supply and redeem wallet positions (947926 ms) + ○ skipped 1. EigenLayer Sepolia deposit credits shares to the wallet + ○ skipped 2. DEX swap on eip155:84532 + ○ skipped 3. DEX swap and Aave round trip on eip155:421614 + + ● agw presets expanded › 4. DEX swap and Venus round trip on eip155:97 + + AgenticRevertError: Timed out while waiting for transaction with hash "0x52732156d51caf9d3d1aa08fd4397be09508553cc4119fc218b92f50eee126e3" to be confirmed. + + 163 | decodedError?: DecodedErrorPayload; + 164 | }; + > 165 | return new AgenticRevertError(e?.message ?? decoded?.name ?? 'AGW revert', { + | ^ + 166 | decodedError: decoded ?? e?.decodedError, + 167 | gatewayTxHash: e?.gatewayTxHash, + 168 | agenticCode: decoded?.name, + + at wrapSendError (src/lib/agentic/management/common.ts:165:12) + at agenticSend (src/lib/agentic/execution/send.ts:340:34) + at async send (__e2e__/agw/presets-expanded-live.spec.ts:131:14) + at async wrap (__e2e__/agw/presets-expanded-live.spec.ts:250:3) + at async dexAndLend (__e2e__/agw/presets-expanded-live.spec.ts:435:5) + + Cause: + PushChainExecutionError: Timed out while waiting for transaction with hash "0x52732156d51caf9d3d1aa08fd4397be09508553cc4119fc218b92f50eee126e3" to be confirmed. + + 186 | ctx._routeTerminalEmitted = true; + 187 | if (!isUserDecline && !(err instanceof PushChainExecutionError)) { + > 188 | throw new PushChainExecutionError(errMsg, { cause: err }); + | ^ + 189 | } + 190 | throw err; + 191 | } + + at executeStandardPayload (src/lib/orchestrator/internals/execute-standard.ts:188:15) + at async Orchestrator.executeWithPolicy (src/lib/orchestrator/orchestrator.ts:471:11) + at async agenticSend (src/lib/agentic/execution/send.ts:330:9) + at async send (__e2e__/agw/presets-expanded-live.spec.ts:131:14) + at async wrap (__e2e__/agw/presets-expanded-live.spec.ts:250:3) + at async dexAndLend (__e2e__/agw/presets-expanded-live.spec.ts:435:5) + + Cause: + WaitForTransactionReceiptTimeoutError: Timed out while waiting for transaction with hash "0x52732156d51caf9d3d1aa08fd4397be09508553cc4119fc218b92f50eee126e3" to be confirmed. + + Version: viem@2.27.2 + + at Timeout._onTimeout (../../node_modules/viem/actions/public/waitForTransactionReceipt.ts:160:22) + + ● agw presets expanded › 5. Base Aave and both Moonwell markets supply and redeem wallet positions + + AgenticRevertError: Timed out while waiting for transaction with hash "0x72d53c5d0faad5a16eec8f1a1f413757d425ec4237488551b5d2f2436d4e60b2" to be confirmed. + + 163 | decodedError?: DecodedErrorPayload; + 164 | }; + > 165 | return new AgenticRevertError(e?.message ?? decoded?.name ?? 'AGW revert', { + | ^ + 166 | decodedError: decoded ?? e?.decodedError, + 167 | gatewayTxHash: e?.gatewayTxHash, + 168 | agenticCode: decoded?.name, + + at wrapSendError (src/lib/agentic/management/common.ts:165:12) + at agenticSend (src/lib/agentic/execution/send.ts:340:34) + at async send (__e2e__/agw/presets-expanded-live.spec.ts:131:14) + at async Object. (__e2e__/agw/presets-expanded-live.spec.ts:657:5) + + Cause: + PushChainExecutionError: Timed out while waiting for transaction with hash "0x72d53c5d0faad5a16eec8f1a1f413757d425ec4237488551b5d2f2436d4e60b2" to be confirmed. + + 186 | ctx._routeTerminalEmitted = true; + 187 | if (!isUserDecline && !(err instanceof PushChainExecutionError)) { + > 188 | throw new PushChainExecutionError(errMsg, { cause: err }); + | ^ + 189 | } + 190 | throw err; + 191 | } + + at executeStandardPayload (src/lib/orchestrator/internals/execute-standard.ts:188:15) + at async Orchestrator.executeWithPolicy (src/lib/orchestrator/orchestrator.ts:471:11) + at async agenticSend (src/lib/agentic/execution/send.ts:330:9) + at async send (__e2e__/agw/presets-expanded-live.spec.ts:131:14) + at async Object. (__e2e__/agw/presets-expanded-live.spec.ts:657:5) + + Cause: + WaitForTransactionReceiptTimeoutError: Timed out while waiting for transaction with hash "0x72d53c5d0faad5a16eec8f1a1f413757d425ec4237488551b5d2f2436d4e60b2" to be confirmed. + + Version: viem@2.27.2 + + at Timeout._onTimeout (../../node_modules/viem/actions/public/waitForTransactionReceipt.ts:160:22) + +Test Suites: 1 failed, 1 total +Tests: 2 failed, 3 skipped, 5 total +Snapshots: 0 total +Time: 2671.595 s +Ran all test suites within paths "__e2e__/agw/presets-expanded-live.spec.ts". +Test Suites: 1 failed, 1 total +Tests: 2 failed, 3 skipped, 5 total +Snapshots: 0 total +Time: 2671.599 s +Ran all test suites within paths "__e2e__/agw/presets-expanded-live.spec.ts". +Force exiting Jest: Have you considered using `--detectOpenHandles` to detect async operations that kept running after all tests finished? diff --git a/plan/agw/research/preset-configuration-2026-10-16/unit.log b/plan/agw/research/preset-configuration-2026-10-16/unit.log new file mode 100644 index 00000000..cf916bd8 --- /dev/null +++ b/plan/agw/research/preset-configuration-2026-10-16/unit.log @@ -0,0 +1,179 @@ +PASS core packages/core/src/lib/agentic/__tests__/preset-catalog.spec.ts +PASS core packages/core/src/lib/universal/account/account.spec.ts + ● Console + + console.warn + [PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead. + + 207 | ): Promise { + 208 | if (!_convertOriginToExecutorWarned) { + > 209 | console.warn( + | ^ + 210 | '[PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead.' + 211 | ); + 212 | _convertOriginToExecutorWarned = true; + + at Object.convertOriginToExecutor (src/lib/universal/account/account.ts:209:13) + at Object. (src/lib/universal/account/account.spec.ts:80:52) + + console.warn + [PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead. + + 425 | ): Promise { + 426 | if (!options?._internal && !_convertExecutorToOriginWarned) { + > 427 | console.warn( + | ^ + 428 | '[PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead.' + 429 | ); + 430 | _convertExecutorToOriginWarned = true; + + at convertExecutorToOrigin (src/lib/universal/account/account.ts:427:13) + at Object. (src/lib/universal/account/account.spec.ts:106:38) + +PASS core packages/core/src/lib/read-state/__tests__/block-results-client.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-tx-retry.spec.ts +PASS core packages/core/src/lib/push-client/push-client.archive-fallback.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-confirmation-gate.spec.ts +PASS core packages/core/src/lib/utils.spec.ts + ● Console + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:973:17) + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:977:17) + + console.log + 1.23 + + at Object. (src/lib/utils.spec.ts:982:17) + +PASS core packages/core/src/lib/agentic/__tests__/send.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-timeout-clamp.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r2-outbound-revert-flow.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/management.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/response-surface.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/labels.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/public-rule.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/runtime-token-chain.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/response-invariant.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/source-hash-resolution.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-tracker.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r2-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-svm-r3.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/inbound-tracker-derivation.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/reads-context.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-quote.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-svm-confirmation.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-executor.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-idl.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/presets.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/context-helpers-tracker.spec.ts +PASS core packages/core/src/lib/universal/signer/signer.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/cascade.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-calculator.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/export.spec.ts +PASS core packages/core/src/lib/push-client/push-client.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/preset-operation-limits.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/gate.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/signing-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-emission.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/scenarios.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-composition.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gateway-uea-account.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-gas.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/rescue-svm-confirmation.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/payload-builders.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/resolve.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/svm-rent.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/registry.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-backend.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-builder-progress-hook.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/read-tx-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/resolver.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/web2-compat.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-detector.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r1-spec-strings.spec.ts +PASS core packages/core/src/lib/constants/__tests__/token-constants.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/send-transaction-progress-hook.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-native-multicall.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-usd-sizer.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-svm-rent.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/funds-only-burn-guard.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/account-status.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r3-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/chain-namespace.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-multichain.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/build-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/inbound-payload.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/public-surface.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-event-hook-bridge.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/track-transaction-guard.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/multichain-hooks.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/response-builder-push-revert.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-evm-r3-native-eoa.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-request-recipient.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/terminal-suppression.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm-rent-pc20.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/execute-standard-required-funds.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/native-multi-action.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/svm-account.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/spec-builder.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-params.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/revalidate-read.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-evm.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-wire-fixture.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-svm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/result-decoder.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm-log-index.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/address-codec.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/codec.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/__tests__/signing.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/normalize.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/child-inbounds.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/auto-detect.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/abi-selectors.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.chain-symbol.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg-svm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/validate.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/ucallback-codec.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-events.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.dynamic-gas.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-web2.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/ix-encoder.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.batch-gas.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-types.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/registry.spec.ts +PASS core packages/core/src/lib/constants/__tests__/svm-gateway-idl.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/budget.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/tracking.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/normalize-address.spec.ts +PASS core packages/core/src/lib/formatters.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/classify.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/max-pc-for-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/errors.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/error-decoder.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-execute-order.spec.ts + +Test Suites: 1 skipped, 126 passed, 126 of 127 total +Tests: 12 skipped, 2111 passed, 2123 total +Snapshots: 0 total +Time: 948.807 s +Ran all test suites. diff --git a/plan/agw/section7-presets.md b/plan/agw/section7-presets.md index a506b148..74adfa10 100644 --- a/plan/agw/section7-presets.md +++ b/plan/agw/section7-presets.md @@ -29,3 +29,8 @@ Latest full unit run: 2,096 passed, 12 skipped, zero failures. Focused preset te ## Expanded live acceptance (October 15) Five additional scenarios now pass across focused runs: EigenLayer Sepolia; Base Uniswap; Arbitrum Uniswap/Aave; BNB PancakeSwap/Venus; Base Aave/Moonwell. Combined with the earlier Sepolia runs, every shipped testnet protocol/chain combination has at least one positive live flow. The runs found and fixed destination-aware native ETH PRC20 resolution. Borrow/repay, every market and mainnet execution are not claimed. [Evidence and exact limits](research/preset-expanded-live-2026-10-15/README.md). + + +## October 16 — operation limits and readiness supersede earlier behavior + +get returns additive readiness metadata; supported lending/staking calls now have token/amount restrictions. Market redemption uses underlying units. Dynamic/position-derived claims are excluded and explained. [Current implementation, API changes and live validation boundary](research/preset-configuration-2026-10-16/README.md). Earlier live runs predate these restrictions; new live attempts timed out during setup and are not accepted as passes. From 2d16bfe0429fd680558eca1a48bf983358940698 Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Sun, 18 Oct 2026 18:50:43 +0530 Subject: [PATCH 49/68] feat(core): ship bounded preset defaults with funding checks --- packages/core/AGW.md | 69 +++++- .../core/__agw-local__/v5-multiasset.spec.ts | 61 +++++- .../core/__e2e__/agw/presets-live.spec.ts | 63 ++++-- packages/core/scripts/check-agw-package.js | 20 ++ .../core/scripts/check-agw-preset-routes.js | 202 ++++++++++++++++++ .../__tests__/prc20-source-encoding.spec.ts | 63 ++++++ .../agentic/__tests__/preset-catalog.spec.ts | 42 ++-- .../__tests__/preset-default-policy.spec.ts | 168 +++++++++++++++ .../__tests__/preset-default-tokens.spec.ts | 154 +++++++++++++ .../__tests__/preset-operation-limits.spec.ts | 43 ++-- .../agentic/__tests__/preset-routes.spec.ts | 103 +++++++++ .../src/lib/agentic/__tests__/presets.spec.ts | 6 +- .../lib/agentic/contracts/prc20-metadata.ts | 27 ++- .../core/src/lib/agentic/presets/catalog.ts | 15 ++ .../src/lib/agentic/presets/default-policy.ts | 98 +++++++++ .../src/lib/agentic/presets/default-tokens.ts | 80 +++++++ .../core/src/lib/agentic/presets/index.ts | 86 +++++--- .../core/src/lib/agentic/presets/routes.ts | 56 +++++ .../core/src/lib/agentic/presets/types.ts | 40 +++- .../src/lib/universal/prc20-address.spec.ts | 65 ++++++ .../core/src/lib/universal/prc20-address.ts | 32 ++- 21 files changed, 1383 insertions(+), 110 deletions(-) create mode 100644 packages/core/scripts/check-agw-preset-routes.js create mode 100644 packages/core/src/lib/agentic/__tests__/prc20-source-encoding.spec.ts create mode 100644 packages/core/src/lib/agentic/__tests__/preset-default-policy.spec.ts create mode 100644 packages/core/src/lib/agentic/__tests__/preset-default-tokens.spec.ts create mode 100644 packages/core/src/lib/agentic/__tests__/preset-routes.spec.ts create mode 100644 packages/core/src/lib/agentic/presets/default-policy.ts create mode 100644 packages/core/src/lib/agentic/presets/default-tokens.ts create mode 100644 packages/core/src/lib/agentic/presets/routes.ts create mode 100644 packages/core/src/lib/universal/prc20-address.spec.ts diff --git a/packages/core/AGW.md b/packages/core/AGW.md index 7d5b71be..0a8a7c60 100644 --- a/packages/core/AGW.md +++ b/packages/core/AGW.md @@ -91,7 +91,7 @@ An equality pin fixes an argument; a maximum pin bounds it. For EVM signatures, `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. -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. +For directly authored rules, omitted `maxValue`, `assets[].maxTotal`, and `maxGasPerCall` default to **zero**. Presets supply explicit policy values as described below. 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. ## EVM destinations @@ -171,7 +171,7 @@ The wire encoder uses uint32 maximum for unlimited native calls and 255 for unsp - DEXES: Uniswap V3 on Ethereum, Base and Arbitrum (mainnet and their Sepolia testnets); PancakeSwap V3 on BNB mainnet and BSC testnet. - 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. -- 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. +- 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 in explicitly supplied assets remain zero. - PREDICTION: no entries yet. Hide categories with empty `chains` lists. ```ts @@ -180,13 +180,24 @@ const availablePresets = presets.filter(preset => preset.chains.length > 0); const { rules: reviewTemplates } = PushChain.utils.agentic.presets.get( PushChain.CONSTANTS.AGENTIC.PRESETS.CATEGORY.DEXES, ); -// Choose tokens in the review UI, then call get again as below. +// Every populated chain includes curated destination tokens in rule.assets. +// The SDK supplies spending limits, a PC budget and a seven-day expiry. +// Supply the agent to get complete Rule[] configuration. +const configuredPreset = PushChain.utils.agentic.presets.get( + PushChain.CONSTANTS.AGENTIC.PRESETS.CATEGORY.LENDING, + { chainNamespace: 'eip155:11155111', agent: '0x0000000000000000000000000000000000001234', funding: 'destination' }, +); +// Destination assets must already be funded; no Push token exports are granted. +// Show configuredPreset.readiness.chains[0].selectedAssets in the review UI. +// Pass configuredPreset.rules directly to create after checking readiness. +// The helper below illustrates explicit overrides, rather than required UI input. function filledPreset(agent: Address, tokenIn: Address, tokenOut: Address) { return PushChain.utils.agentic.presets.get( PushChain.CONSTANTS.AGENTIC.PRESETS.CATEGORY.DEXES, { chainNamespace: 'eip155:11155111', + funding: 'destination', agent, validUntil: Math.floor(Date.now() / 1000) + 3600, maxGasPerCall: BigInt(10) ** BigInt(18), @@ -199,9 +210,9 @@ function filledPreset(agent: Address, tokenIn: Address, tokenOut: Address) { } ``` -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. +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 an agent supplied, `rules` is typed as `Rule[]`; otherwise it is `PresetRuleTemplate[]` with a generated expiry and missing agent. This type distinction alone does not establish readiness. When `assets` is omitted, each chain includes its curated destination tokens with the explicit spending limits below. An explicit `assets` array replaces the defaults for every returned chain; `[]` selects no tokens. Assets in an explicit list must name their chain unless a single chain filter is supplied. For an explicit asset list, omitted caps still default to zero. An omitted gas budget uses the preset policy; an explicit zero remains zero. -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. +DEX discovery without `assets` includes a curated wrapped-native/stablecoin pair per chain, with both swap directions, exact-input/output functions and the token-specific input caps below. It does not require the UI to select tokens separately for every network. DEX discovery also works with an explicit empty asset list or with assets for only some chains. A chain with fewer than two explicitly supplied 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. 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]`. @@ -209,11 +220,55 @@ Reviewed EVM spenders generate approvals pinned to that spender and bounded by t 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. +### Curated token defaults + +These are small, protocol-specific subsets chosen to fit the 32-call/32-pin ceilings. The full reserve catalog is not automatically granted. + +| Network | DEX pair | Lending tokens | +| --- | --- | --- | +| Ethereum | WETH / USDC | WETH, USDC | +| Base | WETH / USDC | USDC (Aave and Moonwell) | +| Arbitrum | WETH / native USDC | WETH, native USDC | +| BNB | WBNB / USDT | USDT (Aave and Venus) | +| Sepolia | DEX WETH / Circle USDC | Aave faucet LINK | +| Base Sepolia | WETH / Circle USDC | Aave faucet LINK, Moonwell mock USDbC and WETH | +| Arbitrum Sepolia | WETH / Circle USDC | Aave USDC | +| BSC testnet | WBNB / Venus USDT | Venus USDT, USDC | + +Staking defaults are ETH/stETH/wstETH on Ethereum and the reviewed EigenLayer strategy's WETH on Sepolia. Testnet tokens with similar names can have different addresses; the returned addresses are authoritative. These tokens may lack Push PRC20 routes and can instead be used with destination-held balances. Defaults do not guarantee active reserves, liquidity, a Push PRC20 route or execution. In particular, an unmodified preset can fail rule preparation if its default assets lack PRC20 mappings. For destination-only use, pass `funding: 'destination'`: the SDK generates the operation constraints, returns empty rule bridge assets and retains selected token limits in readiness metadata. This grants no token export budget from Push and requires already-funded destination balances. Token addresses are returned as before; metadata was verified when defining the policy. No runtime metadata/price fetch is added to get. + +### Funding and release-network checks + +`funding` defaults to `'push'`. Missing PRC20 registry entries produce `BRIDGE_ASSET_UNAVAILABLE`, and readiness is false while the returned rule retains all requested assets. No address or cap is silently replaced. `network` defaults to `TESTNET_DONUT` (`TESTNET` is accepted as an alias); use the connected client's Push network when supplying it. Networks without a verified AGW deployment report `AGW_NETWORK_UNAVAILABLE`. + +Use `funding: 'destination'` for the prefunded CEA workflow. Selected tokens still generate the same target/function/amount/recipient/spender restrictions, exposed alongside their caps in `readiness.chains[].selectedAssets`. Returned `rule.assets` is intentionally empty, which grants zero Push token-export authority. It is safe to pass these returned rules directly to create/update. The mode does not fund the destination, wrap ETH, mint testnet tokens or enable an unsupported network. Do not relabel it as bridge funding in the UI. + +Existing mappings distinguish token identity by chain and address, including address casing for EVM. WETH/stETH Sepolia mappings and string/address-word source metadata are supported; mainnet or other-chain WETH is never aliased to them. Protocol mock LINK, Moonwell/Venus mocks and Circle testnet USDC can differ from the supported source tokens; they remain unavailable for bridge funding until real matching routes exist. + +### Default permission policy + +Only preset-generated assets receive these positive values. Direct rules, unknown tokens and explicit asset lists do not acquire guessed limits. + +| Selected token | Per allowed call / Push outbound | Cumulative Push-outbound total | +| --- | --- | --- | +| USDC / USDT / mock USDbC | 10 tokens | 100 tokens | +| ETH / WETH / stETH / wstETH | 0.001 token | 0.01 token | +| WBNB | 0.01 token | 0.1 token | +| LINK | 1 token | 10 tokens | + +Amounts use verified token decimals, keyed by chain and address, rather than symbol or live prices. For example, the USDT per-call limit is `10 * 10^18` on BNB mainnet and `10 * 10^6` on BSC testnet. These are fixed token quantities, not USD budgets. + +The default expiry is seven days from each get call, computed once for all returned rules. The default gas ceiling is **20 PC per outbound**, including the value checked by URP; it is not a flat fee or a reservation. Actual sends obtain a fresh quote and remain subject to the rule cap. This ceiling has testnet protocol-flow coverage; mainnet templates do not have funded execution acceptance. Quotes may exceed the cap, requiring an explicit higher budget. + +Explicit `validUntil` and `maxGasPerCall` override policy values; zero gas is preserved and reports incomplete readiness. An explicit `assets` array replaces all default tokens and limits, and omitted caps inside it remain zero. To change a preset cap while retaining its token set, take the returned assets, replace the caps and pass them back to get. Do not just edit the returned rule assets: the allowed-call pins and approvals also need regeneration. + +`maxPerCall` applies to each allowed destination call; multiple calls may each consume that amount. `maxTotal` meters assets sent from Push, not aggregate destination activity. No destination lifetime limit is implied by these defaults. The general rules API continues to treat omitted caps as zero. + ### Configure, inspect and regenerate -`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. +`readiness.ready` requires complete configuration plus offline SDK deployment/destination/bridge-registry support for the selected funding mode. Per-chain `configurationReady` reports input completeness separately. These checks do not verify live balances, reserve flags, liquidity, current deployed bytecode or source identity; grant preparation still verifies wiring and token metadata on-chain before signing. `readiness.chains` gives per-chain `issues`, `disabledCalls`, `excludedCalls`, catalog `knownTokens`, `selectedAssets`, `bridgeAssets`, `funding` and `zeroBridgeLimits`. Display `selectedAssets` as the reviewed token/amount permissions in either mode; `rule.assets` describes Push bridge permissions only. `bridgeAssets` reports registry presence, not verified live deployment. Mainnet templates remain discoverable but have `DESTINATION_UNAVAILABLE` on Donut. These are additive result fields; `rules` remains accepted by the existing create/update methods. -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. +Tokens and permission defaults come directly from the SDK: omitted `assets` populates the curated subset and its caps in every returned `rule.assets`. Omitted gas and expiry use the policy below. The caller supplies the agent and can filter chains; no per-network token selection is required. Show the generated permissions for owner review and allow explicit overrides. Regenerate via get after an edit so operation pins/approvals match the new caps. Show explicitly zero-cap calls as disabled and present excluded calls clearly. A zero bridge limit can be intentional when assets are already at the destination; it is reported separately from operation readiness. ```ts async function createConfiguredDex( diff --git a/packages/core/__agw-local__/v5-multiasset.spec.ts b/packages/core/__agw-local__/v5-multiasset.spec.ts index ba06384a..859d1247 100644 --- a/packages/core/__agw-local__/v5-multiasset.spec.ts +++ b/packages/core/__agw-local__/v5-multiasset.spec.ts @@ -308,17 +308,19 @@ describe('v6 multi-asset SDK management and execution', () => { }); it.each(['exactInputSingle', 'exactOutputSingle'] as const)( - 'a review-only DEX %s call cannot spend tokens even after asset budgets are filled', + 'a default-token DEX %s call rejects spending above its policy cap despite edited bridge budgets', async (functionName) => { - const preview = agenticPresets.get('DEXES', { chainNamespace: CHAIN_NS }) - .rules[0]; - const { agent } = await setup({ - ...preview, + const preview = agenticPresets.get('DEXES', { + chainNamespace: CHAIN_NS, agent: h.wallets[1].account!.address, - validUntil: Math.floor(Date.now() / 1000) + 3600, - maxGasPerCall: BigInt(10) ** BigInt(16), + }).rules[0]; + const { wallet, id, agent } = await setup({ + ...preview, assets: [{ token: a, maxPerCall: BigInt(5), maxTotal: BigInt(20) }], }); + const stored = await owner.agentic.wallet(wallet).rules.get(id); + expect(stored.rule.validUntil).toBe(preview.validUntil); + expect(stored.rule.maxGasPerCall).toBe(preview.maxGasPerCall); const router = preview.allowedCalls[0].target as Address; const abi = parseAbi([ `function ${functionName}((address,address,uint24,address,uint256,uint256,uint160))`, @@ -333,7 +335,17 @@ describe('v6 multi-asset SDK management and execution', () => { data: encodeFunctionData({ abi, functionName, - args: [[a, b, 3000, CEA, BigInt(1), BigInt(1), BigInt(0)]], + args: [ + [ + preview.assets![0].token as Address, + preview.assets![1].token as Address, + 3000, + CEA, + preview.assets![0].maxPerCall + BigInt(1), + preview.assets![0].maxPerCall + BigInt(1), + BigInt(0), + ], + ], }), }, ], @@ -344,6 +356,35 @@ describe('v6 multi-asset SDK management and execution', () => { } ); + it.each(['DEXES', 'LENDING', 'STAKING'] as const)( + 'public %s destination-funded defaults create directly without rewriting returned rules', + async (category) => { + const generated = agenticPresets.get(category, { + chainNamespace: CHAIN_NS, + agent: h.wallets[1].account!.address, + funding: 'destination', + }); + expect(generated.readiness.ready).toBe(true); + expect( + generated.readiness.chains[0].selectedAssets.length + ).toBeGreaterThan(0); + expect(generated.rules[0].assets).toEqual([]); + const { wallet, id } = await setup(generated.rules[0]); + const actual = await stored(wallet, id); + expect(actual.assets).toEqual([ + { + token: a, + maxPerCall: BigInt(0), + maxTotal: BigInt(0), + spent: BigInt(0), + }, + ]); + const record = await owner.agentic.wallet(wallet).rules.get(id); + expect(record.rule.maxGasPerCall).toBe(generated.rules[0].maxGasPerCall); + expect(record.rule.validUntil).toBe(generated.rules[0].validUntil); + } + ); + it.each(['LENDING', 'STAKING'] as const)( 'regenerated %s presets enforce new token/amount pins through atomic rules.update', async (category) => { @@ -359,7 +400,7 @@ describe('v6 multi-asset SDK management and execution', () => { validUntil: Math.floor(Date.now() / 1000) + 3600, maxGasPerCall: BigInt(10) ** BigInt(16), }; - const preview = agenticPresets.get(category, opts); + const preview = agenticPresets.get(category, { ...opts, assets: [] }); expect(preview.readiness.ready).toBe(false); const { wallet, id, agent } = await setup({ ...preview.rules[0], @@ -400,7 +441,7 @@ describe('v6 multi-asset SDK management and execution', () => { { token: firstToken, maxPerCall: BigInt(5), maxTotal: BigInt(10) }, ], }); - expect(first.readiness.ready).toBe(true); + expect(first.readiness.chains[0].configurationReady).toBe(true); const before = await h.publicClient.readContract({ address: wallet, abi: h.generation.contracts.abis.wallet, diff --git a/packages/core/__e2e__/agw/presets-live.spec.ts b/packages/core/__e2e__/agw/presets-live.spec.ts index dfcfe611..48fab87e 100644 --- a/packages/core/__e2e__/agw/presets-live.spec.ts +++ b/packages/core/__e2e__/agw/presets-live.spec.ts @@ -73,7 +73,26 @@ d('agw presets live', () => { 'PRESET_PREREQUISITE: Sepolia pool has no active liquidity' ); f = await setupAgw(); + const defaults = PushChain.utils.agentic.presets.get('DEXES', { + chainNamespace: CHAIN.ETHEREUM_SEPOLIA, + agent: f.agentAddress, + funding: 'destination', + }); + expect(defaults.readiness.ready).toBe(true); + expect(defaults.rules[0].maxGasPerCall).toBe(MAX_PC); + expect(defaults.rules[0].validUntil).toBeGreaterThan(inSeconds(6 * 86400)); + expect( + defaults.readiness.chains[0].selectedAssets.map((a) => + a.token.toString().toLowerCase() + ) + ).toEqual([WETH.toLowerCase(), USDC.toLowerCase()]); + expect( + defaults.readiness.chains[0].selectedAssets.every( + (a) => a.maxPerCall > BigInt(0) + ) + ).toBe(true); const { rules } = PushChain.utils.agentic.presets.get('DEXES', { + funding: 'destination', chainNamespace: CHAIN.ETHEREUM_SEPOLIA, agent: f.agentAddress, validUntil: inSeconds(3600), @@ -91,7 +110,7 @@ d('agw presets live', () => { // tokens, so omit bridge assets without changing any generated call or pin. const { wallet, rulesIds } = await f.owner.agentic.create( 'e2e-preset-uniswap', - { rules: [{ ...rules[0], assets: [] }] } + { rules } ); const cea = (await getCEAAddress(wallet, CHAIN.ETHEREUM_SEPOLIA)) .cea as Address; @@ -268,16 +287,36 @@ d('agw presets live', () => { ); f?.teardown(); f = await setupAgw(); + const defaults = PushChain.utils.agentic.presets.get('LENDING', { + chainNamespace: CHAIN.ETHEREUM_SEPOLIA, + agent: f.agentAddress, + funding: 'destination', + }); + expect(defaults.readiness.ready).toBe(true); + expect(defaults.readiness.chains[0].selectedAssets[0].maxPerCall).toBe( + parseEther('1') + ); + expect(defaults.rules[0].maxGasPerCall).toBe(MAX_PC); + expect( + defaults.readiness.chains[0].selectedAssets.map((a) => + a.token.toString().toLowerCase() + ) + ).toEqual([mockLINK.toLowerCase()]); const { rules } = PushChain.utils.agentic.presets.get('LENDING', { + funding: 'destination', chainNamespace: CHAIN.ETHEREUM_SEPOLIA, agent: f.agentAddress, validUntil: inSeconds(3600), maxGasPerCall: MAX_PC, - assets: [{ token: mockLINK, maxPerCall: amount, maxTotal: amount }], + assets: defaults.readiness.chains[0].selectedAssets.map((a) => ({ + ...a, + maxPerCall: amount, + maxTotal: amount, + })), }); const { wallet, rulesIds } = await f.owner.agentic.create( 'e2e-preset-aave', - { rules: [{ ...rules[0], assets: [] }] } + { rules } ); const cea = (await getCEAAddress(wallet, CHAIN.ETHEREUM_SEPOLIA)) .cea as Address; @@ -417,16 +456,14 @@ d('agw presets live', () => { assets: [{ token: mockLINK, maxPerCall: half, maxTotal: amount }], }); expect(regenerated.readiness.ready).toBe(true); - const changed = await f.owner.agentic - .wallet(wallet) - .rules.update({ - rules: [ - { - rulesId: rulesIds[0], - rule: { ...regenerated.rules[0], assets: [] }, - }, - ], - }); + const changed = await f.owner.agentic.wallet(wallet).rules.update({ + rules: [ + { + rulesId: rulesIds[0], + rule: { ...regenerated.rules[0], assets: [] }, + }, + ], + }); await expect( agent.universal.sendTransaction({ to: { address: pool, chain: CHAIN.ETHEREUM_SEPOLIA }, diff --git a/packages/core/scripts/check-agw-package.js b/packages/core/scripts/check-agw-package.js index 85e87be4..7384461d 100644 --- a/packages/core/scripts/check-agw-package.js +++ b/packages/core/scripts/check-agw-package.js @@ -23,6 +23,26 @@ async function main() { ); assert(pack.files.some((f) => f.path === 'AGW.md')); assert(!pack.files.some((f) => /(^|\/)\.env($|\.)/.test(f.path))); + assert( + !pack.files.some((f) => + /(^|\/)(plan|__e2e__|__agw-local__|scripts)(\/|$)/.test(f.path) + ) + ); + const preset = cjs.PushChain.utils.agentic.presets.get('LENDING', { + agent: '0x0000000000000000000000000000000000005678', + chainNamespace: 'eip155:11155111', + funding: 'destination', + }); + assert.equal(preset.readiness.ready, true); + assert.deepEqual(preset.rules[0].assets, []); + assert(preset.readiness.chains[0].selectedAssets.length > 0); + assert.equal( + cjs.PushChain.utils.agentic.presets.get('LENDING', { + agent: '0x0000000000000000000000000000000000005678', + chainNamespace: 'eip155:11155111', + }).readiness.ready, + false + ); const guide = fs.readFileSync(path.join(built, 'AGW.md'), 'utf8'); const source = [...guide.matchAll(/```ts\n([\s\S]*?)```/g)] .map((m) => m[1]) diff --git a/packages/core/scripts/check-agw-preset-routes.js b/packages/core/scripts/check-agw-preset-routes.js new file mode 100644 index 00000000..ff524ea3 --- /dev/null +++ b/packages/core/scripts/check-agw-preset-routes.js @@ -0,0 +1,202 @@ +/** Read-only Donut acceptance of built preset configuration and factory calldata. + * Build core first. No keys, signing, funding, deployments or broadcasts. + * Usage: node packages/core/scripts/check-agw-preset-routes.js /tmp/report.json + */ +const fs = require('node:fs'); +const path = require('node:path'); +const assert = require('node:assert/strict'); +const { createPublicClient, http, getAddress } = require('viem'); +const built = path.resolve(__dirname, '../../..', 'dist/packages/core/src'); +const { PushChain } = require(built); +const { CHAIN, PUSH_NETWORK } = PushChain.CONSTANTS; +const { currentGeneration, verifyFactoryWiring } = require(path.join( + built, + 'lib/agentic/deployments' +)); +const { Snapshot } = require(path.join(built, 'lib/agentic/reads/snapshot')); +const { publicRules } = require(path.join(built, 'lib/agentic/public-rule')); +const { prepareWalletRules } = require(path.join( + built, + 'lib/agentic/management/prepare' +)); +const { getCEAAddress } = require(path.join( + built, + 'lib/orchestrator/cea-utils' +)); +const { readOriginToken, PRC20_SOURCE_ABI } = require(path.join( + built, + 'lib/agentic/contracts/prc20-metadata' +)); +const { getPRC20Address } = require(path.join( + built, + 'lib/universal/prc20-address' +)); + +const endpoints = { + [CHAIN.ETHEREUM_SEPOLIA]: 'https://ethereum-sepolia-rpc.publicnode.com', + [CHAIN.BASE_SEPOLIA]: 'https://base-sepolia-rpc.publicnode.com', + [CHAIN.ARBITRUM_SEPOLIA]: 'https://arbitrum-sepolia-rpc.publicnode.com', + [CHAIN.BNB_TESTNET]: 'https://bsc-testnet-rpc.publicnode.com', +}; + +async function main() { + const report = { + at: new Date().toISOString(), + readOnly: true, + network: PUSH_NETWORK.TESTNET_DONUT, + cases: [], + }; + const rpc = createPublicClient({ + transport: http('https://evm.donut.rpc.push.org/', { + timeout: 15000, + retryCount: 1, + }), + }); + assert.equal(await rpc.getChainId(), 42101); + const owner = getAddress('0x0A16CBa65FfCAa4C2282b27b027Ab4A2fE46E0Bf'); + const agent = getAddress('0x0000000000000000000000000000000000005678'); + // A UniversalAccount creates a read-mode client: there is no signer here. + const client = await PushChain.initialize( + { address: owner, chain: CHAIN.PUSH_TESTNET_DONUT }, + { network: PUSH_NETWORK.TESTNET_DONUT } + ); + const runtime = client.agenticRuntime; + assert.equal(runtime.isReadOnly, true); + // Same CEA factory read, with explicit public endpoints for reproducibility. + runtime.resolveCEA = (wallet, chain) => + getCEAAddress(wallet, chain, endpoints[chain]); + const gen = currentGeneration(runtime.network); + await verifyFactoryWiring(runtime.reader, gen); + const snap = await Snapshot.at(runtime.reader); + report.blockNumber = String(snap.blockNumber); + report.factory = gen.addresses.factory; + report.verifiedERC20Mappings = []; + for (const source of [ + '0xfff9976782d46cc05630d1f6ebab18b2324d6b14', + '0x3e3FE7dBc6B4C189E7128855dD526361c49b40Af', + ]) { + const mapped = getPRC20Address({ + chain: CHAIN.ETHEREUM_SEPOLIA, + address: getAddress(source), + }); + assert.equal( + await snap.read( + mapped.address, + PRC20_SOURCE_ABI, + 'SOURCE_CHAIN_NAMESPACE' + ), + CHAIN.ETHEREUM_SEPOLIA + ); + assert.equal( + await readOriginToken(snap, mapped.address, CHAIN.ETHEREUM_SEPOLIA), + getAddress(source) + ); + report.verifiedERC20Mappings.push({ + source: getAddress(source), + prc20: mapped.address, + status: 'source-identity-verified', + }); + } + const index = await snap.read( + gen.addresses.factory, + gen.contracts.abis.factory, + 'walletCount', + [owner] + ); + const [wallet, deployed] = await snap.read( + gen.addresses.factory, + gen.contracts.abis.factory, + 'predictWallet', + [owner, index] + ); + assert.equal(deployed, false); + report.counterfactualWallet = wallet; + for (const category of ['DEXES', 'LENDING', 'STAKING']) { + const chains = PushChain.utils.agentic.presets + .list() + .presets.find((p) => p.constant === category) + .chains.filter((c) => endpoints[c]); + for (const chainNamespace of chains) { + const result = { category, chainNamespace }; + try { + const push = PushChain.utils.agentic.presets.get(category, { + agent, + chainNamespace, + }); + result.pushReadiness = push.readiness; + const destination = PushChain.utils.agentic.presets.get(category, { + agent, + chainNamespace, + funding: 'destination', + }); + assert.equal(destination.readiness.ready, true); + assert.deepEqual(destination.rules[0].assets, []); + const prepared = await prepareWalletRules( + runtime, + gen, + owner, + wallet, + publicRules(destination.rules), + snap + ); + const data = gen.contracts.encodeCreateWalletAt( + owner, + index, + wallet, + 'preset-readonly-check', + prepared.map((p) => p.session) + ); + const simulated = await rpc.call({ + account: owner, + to: gen.addresses.factory, + data, + blockNumber: snap.blockNumber, + gas: BigInt(20000000), + }); + assert(simulated.data && simulated.data !== '0x'); + result.destinationFactorySimulation = 'passed'; + result.selectedAssets = destination.readiness.chains[0].selectedAssets; + // If static registry support is advertised, verify preparation against real metadata too. + if (push.readiness.ready) { + await prepareWalletRules( + runtime, + gen, + owner, + wallet, + publicRules(push.rules), + snap + ); + result.pushPreparation = 'passed'; + } else { + result.pushPreparation = 'unavailable-in-registry'; + } + console.log( + `${category} ${chainNamespace}: destination factory eth_call passed; Push ${result.pushPreparation}` + ); + } catch (error) { + result.error = error.shortMessage || error.message; + process.exitCode = 1; + console.error(`${category} ${chainNamespace}: ${result.error}`); + } + report.cases.push(result); + } + } + const output = process.argv[2] || '/tmp/agw-preset-route-acceptance.json'; + fs.writeFileSync( + output, + JSON.stringify( + report, + (_, value) => (typeof value === 'bigint' ? value.toString() : value), + 2 + ) + ); + console.log( + `Read-only report: ${output}; ${ + report.cases.filter((c) => !c.error).length + }/${report.cases.length} passed.` + ); +} +main().catch((error) => { + console.error(error.shortMessage || error.message); + process.exitCode = 1; +}); diff --git a/packages/core/src/lib/agentic/__tests__/prc20-source-encoding.spec.ts b/packages/core/src/lib/agentic/__tests__/prc20-source-encoding.spec.ts new file mode 100644 index 00000000..61e1ba95 --- /dev/null +++ b/packages/core/src/lib/agentic/__tests__/prc20-source-encoding.spec.ts @@ -0,0 +1,63 @@ +import { getAddress, zeroAddress } from 'viem'; +import { readOriginToken, CORE_ADDRESS } from '../contracts/prc20-metadata'; +import { Snapshot } from '../reads/snapshot'; +import type { ChainReader } from '../contracts/reader'; +import { ADDR } from './fake-chain'; + +it.each(['string', 'address'] as const)( + 'reads exact non-native source identity from the %s ABI', + async (encoding) => { + const readContract = jest.fn(async (request) => { + const output = request.abi.find( + (f: { name: string }) => f.name === request.functionName + ).outputs[0].type; + if (output !== encoding) throw new Error('different source ABI'); + return ADDR.target; + }); + const snap = new Snapshot( + { readContract } as unknown as ChainReader, + BigInt(123) + ); + expect(await readOriginToken(snap, ADDR.other, 'eip155:11155111')).toBe( + getAddress(ADDR.target) + ); + expect( + readContract.mock.calls.every(([r]) => r.blockNumber === BigInt(123)) + ).toBe(true); + } +); +it('accepts an address-word zero only for the registered native gas token', async () => { + const readContract = jest.fn(async (request) => { + if (request.address === CORE_ADDRESS) return ADDR.other; + const output = request.abi.find( + (f: { name: string }) => f.name === request.functionName + ).outputs[0].type; + if (output === 'string') throw new Error('address ABI'); + return zeroAddress; + }); + const snap = new Snapshot( + { readContract } as unknown as ChainReader, + BigInt(123) + ); + expect(await readOriginToken(snap, ADDR.other, 'eip155:11155111')).toBe( + zeroAddress + ); + await expect( + readOriginToken(snap, ADDR.target, 'eip155:11155111') + ).rejects.toThrow(/non-native.*empty source/); +}); +it('preserves a failed read when neither source encoding can be read', async () => { + const snap = new Snapshot( + { + readContract: async () => { + throw new Error('rpc offline'); + }, + } as unknown as ChainReader, + BigInt(123) + ); + await expect( + readOriginToken(snap, ADDR.other, 'eip155:11155111') + ).rejects.toMatchObject({ + details: { blockNumber: BigInt(123), functionName: 'SOURCE_TOKEN_ADDRESS' }, + }); +}); diff --git a/packages/core/src/lib/agentic/__tests__/preset-catalog.spec.ts b/packages/core/src/lib/agentic/__tests__/preset-catalog.spec.ts index 1ce41fda..0adcce47 100644 --- a/packages/core/src/lib/agentic/__tests__/preset-catalog.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/preset-catalog.spec.ts @@ -192,24 +192,42 @@ it('mutating a returned tuple path cannot change a later preset', () => { ).toEqual([0, 0]); }); -it('returns one zero-input-cap review template per chain without options', () => { - const { rules } = agenticPresets.get('DEXES'); +it('includes a curated capped token pair and exact pair pins on every DEX chain', () => { + const { rules, readiness } = agenticPresets.get('DEXES'); expect(rules.map((r) => r.chainNamespace)).toEqual( agenticPresets.list().presets.find((p) => p.constant === 'DEXES')!.chains ); for (const rule of rules) { expect(rule).not.toHaveProperty('agent'); - expect(rule).not.toHaveProperty('validUntil'); - expect(rule).not.toHaveProperty('assets'); - expect(rule.allowedCalls).toHaveLength(2); - rule.allowedCalls.forEach((call, i) => { - expect(call.pins).toEqual([ - { arg: [0, 3], expected: AGENTIC.WALLET }, - { arg: [0, i === 0 ? 4 : 5], max: BigInt(0) }, - ]); - expect(call.label).toContain('select two tokens'); - }); + expect(rule.validUntil).toBeGreaterThan(Math.floor(Date.now() / 1000)); + expect(rule.assets).toHaveLength(2); + expect( + rule.assets!.every( + (a) => + a.maxPerCall > BigInt(0) && (a.maxTotal ?? BigInt(0)) >= a.maxPerCall + ) + ).toBe(true); + expect(rule.allowedCalls).toHaveLength(6); + const swaps = rule.allowedCalls.filter((c) => + c.selector.startsWith('exact') + ); + expect(swaps).toHaveLength(4); + for (const call of swaps) { + expect(call.pins).toHaveLength(4); + expect(call.pins).toContainEqual({ + arg: [0, 3], + expected: AGENTIC.WALLET, + }); + expect(call.pins?.at(-1)?.max).toBeGreaterThan(BigInt(0)); + expect(call.label).not.toContain('select two tokens'); + } } + expect(readiness.chains.every((c) => c.knownTokens.length >= 2)).toBe(true); + expect( + readiness.chains.every( + (c) => !c.issues.some((i) => i.code === 'TOKEN_PAIR_REQUIRED') + ) + ).toBe(true); }); it('keeps single-token swaps disabled and generates approvals only for the supplied asset', () => { const rule = agenticPresets.get('DEXES', { diff --git a/packages/core/src/lib/agentic/__tests__/preset-default-policy.spec.ts b/packages/core/src/lib/agentic/__tests__/preset-default-policy.spec.ts new file mode 100644 index 00000000..5e72d2bd --- /dev/null +++ b/packages/core/src/lib/agentic/__tests__/preset-default-policy.spec.ts @@ -0,0 +1,168 @@ +import { getAddress, parseEther, zeroAddress } from 'viem'; +import { agenticPresets } from '../presets'; +import { defaultPresetAsset } from '../presets/default-policy'; +import type { Rule } from '../agentic.types'; +import { ADDR } from './fake-chain'; + +const chainNamespace = 'eip155:11155111' as const; +const agent = ADDR.agent; + +it.each(['DEXES', 'LENDING', 'STAKING'] as const)( + 'an agent alone produces typed, locally complete %s rules on all catalog chains', + (category) => { + const { rules, readiness } = agenticPresets.get(category, { agent }); + const typed: Rule[] = rules; + expect(typed.length).toBeGreaterThan(0); + expect(readiness.chains.every((c) => c.configurationReady)).toBe(true); + for (const rule of typed) { + expect(rule.agent).toBe(agent); + expect(rule.maxGasPerCall).toBe(parseEther('20')); + expect(rule.validUntil).toBeGreaterThan(Math.floor(Date.now() / 1000)); + expect(rule.assets?.every((a) => a.maxPerCall > BigInt(0))).toBe(true); + } + } +); + +it('generates one expiry seven days from this get call, refreshing on the next call', () => { + const clock = jest.spyOn(Date, 'now'); + try { + const now = 1_800_000_000; + clock.mockReturnValue(now * 1000); + const first = agenticPresets.get('DEXES', { agent }); + expect(new Set(first.rules.map((r) => r.validUntil))).toEqual( + new Set([now + 604800]) + ); + clock.mockReturnValue((now + 60) * 1000); + expect(agenticPresets.get('DEXES', { agent }).rules[0].validUntil).toBe( + now + 60 + 604800 + ); + expect(first.rules[0].validUntil).toBe(now + 604800); + } finally { + clock.mockRestore(); + } +}); + +it('uses verified raw-unit limits for stablecoins with different decimals', () => { + const mainnet = agenticPresets.get('DEXES', { + agent, + chainNamespace: 'eip155:56', + }).rules[0]; + const testnet = agenticPresets.get('DEXES', { + agent, + chainNamespace: 'eip155:97', + }).rules[0]; + expect(mainnet.assets?.[1]).toMatchObject({ + maxPerCall: BigInt('10000000000000000000'), + maxTotal: BigInt('100000000000000000000'), + }); + expect(testnet.assets?.[1]).toMatchObject({ + maxPerCall: BigInt('10000000'), + maxTotal: BigInt('100000000'), + }); + const aave = agenticPresets.get('LENDING', { + agent, + chainNamespace: 'eip155:1', + }).rules[0]; + expect(aave.assets?.[1]).toMatchObject({ + token: getAddress('0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'), + maxPerCall: BigInt('10000000'), + maxTotal: BigInt('100000000'), + }); +}); + +it('uses token quantities for native, wrapped-native and LINK defaults', () => { + const eth = agenticPresets.get('STAKING', { + agent, + chainNamespace: 'eip155:1', + }).rules[0]; + expect(eth.assets?.[0]).toEqual({ + token: zeroAddress, + maxPerCall: parseEther('0.001'), + maxTotal: parseEther('0.01'), + }); + expect( + eth.allowedCalls.find((c) => c.selector === 'submit(address)')?.maxValue + ).toBe(parseEther('0.001')); + const link = agenticPresets.get('LENDING', { agent, chainNamespace }) + .rules[0]; + expect(link.assets?.[0]).toMatchObject({ + maxPerCall: parseEther('1'), + maxTotal: parseEther('10'), + }); + const bnb = agenticPresets.get('DEXES', { + agent, + chainNamespace: 'eip155:97', + }).rules[0]; + expect(bnb.assets?.[0]).toMatchObject({ + maxPerCall: parseEther('0.01'), + maxTotal: parseEther('0.1'), + }); +}); + +it('preserves explicit expiry and gas, including a zero gas ceiling', () => { + const validUntil = Math.floor(Date.now() / 1000) + 600; + const disabled = agenticPresets.get('LENDING', { + agent, + chainNamespace, + validUntil, + maxGasPerCall: BigInt(0), + }); + expect(disabled.rules[0].validUntil).toBe(validUntil); + expect(disabled.rules[0].maxGasPerCall).toBe(BigInt(0)); + expect(disabled.readiness.ready).toBe(false); + expect(disabled.readiness.chains[0].issues.map((i) => i.code)).toEqual( + expect.arrayContaining(['GAS_BUDGET_REQUIRED', 'BRIDGE_ASSET_UNAVAILABLE']) + ); + expect( + agenticPresets.get('LENDING', { + agent, + chainNamespace, + maxGasPerCall: BigInt(123), + }).rules[0].maxGasPerCall + ).toBe(BigInt(123)); +}); + +it('never invents caps for explicit assets, even when their address is a default', () => { + const defaults = agenticPresets.get('LENDING', { agent, chainNamespace }) + .rules[0]; + const token = defaults.assets?.[0].token; + if (!token) throw new Error('missing default asset'); + const supplied = agenticPresets.get('LENDING', { + agent, + chainNamespace, + assets: [{ token }], + }); + expect(supplied.rules[0].assets).toEqual([ + { token, maxPerCall: BigInt(0), maxTotal: BigInt(0) }, + ]); + expect(supplied.readiness.ready).toBe(false); + const totalZero = agenticPresets.get('LENDING', { + agent, + chainNamespace, + assets: [{ token, maxPerCall: BigInt(5), maxTotal: BigInt(0) }], + }); + expect(totalZero.rules[0].assets?.[0].maxTotal).toBe(BigInt(0)); + expect(totalZero.readiness.chains[0].zeroBridgeLimits).toEqual([token]); +}); + +it('does not grant the default tokens on a different chain when assets is explicit', () => { + const res = agenticPresets.get('LENDING', { + agent, + assets: [{ chainNamespace, token: ADDR.other, maxPerCall: BigInt(5) }], + }); + expect( + res.rules + .filter((r) => r.chainNamespace !== chainNamespace) + .every((r) => r.assets?.length === 0) + ).toBe(true); + expect(res.readiness.ready).toBe(false); +}); + +it('refuses unreviewed default tokens instead of inferring permissions from symbols', () => { + expect(() => defaultPresetAsset('eip155:999', ADDR.other)).toThrow( + /No reviewed default spending policy/ + ); + expect(() => defaultPresetAsset(chainNamespace, ADDR.other)).toThrow( + /No reviewed default spending policy/ + ); +}); diff --git a/packages/core/src/lib/agentic/__tests__/preset-default-tokens.spec.ts b/packages/core/src/lib/agentic/__tests__/preset-default-tokens.spec.ts new file mode 100644 index 00000000..d8412660 --- /dev/null +++ b/packages/core/src/lib/agentic/__tests__/preset-default-tokens.spec.ts @@ -0,0 +1,154 @@ +import { getAddress } from 'viem'; +import { agenticPresets } from '../presets'; +import { buildPresetApi } from '../presets'; +import type { PresetDefinition } from '../presets/catalog'; +import { ADDR } from './fake-chain'; + +const options = { + agent: ADDR.agent, + validUntil: 2_000_000_000, + maxGasPerCall: BigInt(1), +}; + +it.each(['DEXES', 'LENDING', 'STAKING'] as const)( + '%s includes destination tokens independently on every supported network within policy limits', + (category) => { + const result = agenticPresets.get(category, options); + expect(result.rules.length).toBeGreaterThan(0); + for (const rule of result.rules) { + expect(rule.assets!.length).toBeGreaterThan(0); + expect(rule.assets!.length).toBeLessThanOrEqual(8); + expect(rule.allowedCalls.length).toBeLessThanOrEqual(32); + expect( + rule.allowedCalls.reduce((n, c) => n + (c.pins?.length ?? 0), 0) + ).toBeLessThanOrEqual(32); + expect( + rule.assets!.every( + (a) => + a.maxPerCall > BigInt(0) && + (a.maxTotal ?? BigInt(0)) >= a.maxPerCall + ) + ).toBe(true); + } + expect(result.readiness.chains.every((c) => c.configurationReady)).toBe( + true + ); + expect(result.readiness.chains.every((c) => c.configurationReady)).toBe( + true + ); + } +); + +it('selects protocol-specific testnet tokens rather than reusing the DEX pair for lending', () => { + const lending = agenticPresets.get('LENDING', { + chainNamespace: 'eip155:11155111', + }).rules[0]; + const dex = agenticPresets.get('DEXES', { chainNamespace: 'eip155:11155111' }) + .rules[0]; + expect(lending.assets!.map((a) => a.token)).toEqual([ + getAddress('0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5'), + ]); + expect(dex.assets!.map((a) => a.token)).toEqual([ + getAddress('0xfff9976782d46cc05630d1f6ebab18b2324d6b14'), + getAddress('0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238'), + ]); + expect( + agenticPresets.get('STAKING', { chainNamespace: 'eip155:11155111' }) + .rules[0].assets![0].token + ).toBe(getAddress('0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9')); +}); + +it('preserves an explicit empty list instead of silently repopulating tokens', () => { + const result = agenticPresets.get('DEXES', { ...options, assets: [] }); + expect( + result.rules.every( + (r) => r.assets?.length === 0 && r.allowedCalls.length === 2 + ) + ).toBe(true); + expect( + result.readiness.chains.every((c) => + c.issues.some((i) => i.code === 'ASSETS_REQUIRED') + ) + ).toBe(true); +}); + +it('an explicit selection replaces defaults on all chains without filling other networks', () => { + const assets = [ + { + chainNamespace: 'eip155:11155111' as const, + token: ADDR.target, + maxPerCall: BigInt(2), + }, + ]; + const result = agenticPresets.get('STAKING', { ...options, assets }); + expect( + result.rules.find((r) => r.chainNamespace === 'eip155:11155111')!.assets + ).toEqual([ + { token: ADDR.target, maxPerCall: BigInt(2), maxTotal: BigInt(0) }, + ]); + expect( + result.rules.find((r) => r.chainNamespace === 'eip155:1')!.assets + ).toEqual([]); + expect(assets).toHaveLength(1); +}); + +it('regenerates token constraints and approvals from returned default assets with supplied caps', () => { + const request = { ...options, chainNamespace: 'eip155:11155111' as const }; + const preview = agenticPresets.get('LENDING', request); + const result = agenticPresets.get('LENDING', { + ...request, + assets: preview.rules[0].assets!.map((a) => ({ + ...a, + maxPerCall: BigInt(5), + maxTotal: BigInt(10), + })), + }); + expect(result.readiness.chains.every((c) => c.configurationReady)).toBe(true); + expect( + result.rules[0].allowedCalls.every((c) => + c.pins?.some((p) => p.max === BigInt(5)) + ) + ).toBe(true); + expect(preview.rules[0].assets![0].maxPerCall).toBe(BigInt(10) ** BigInt(18)); +}); + +it('isolates defaults from returned assets, caller mutations and input catalog mutations', () => { + const catalog: PresetDefinition[] = [ + { + constant: 'STAKING', + name: 'Fixture', + chains: [ + { + chainNamespace: 'eip155:11155111', + defaultTokens: [ + getAddress('0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5'), + ], + allowedCalls: [ + { + target: ADDR.other, + selector: 'deposit(uint256)', + budget: { + kind: 'fixed-token', + token: getAddress('0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5'), + amountArg: 0, + }, + }, + ], + }, + ], + }, + ]; + const api = buildPresetApi(catalog); + const first = api.get('STAKING'); + first.rules[0].assets![0].token = ADDR.other; + first.rules[0].assets!.push({ token: ADDR.agent, maxPerCall: BigInt(1) }); + first.readiness.chains[0].knownTokens.length = 0; + catalog[0].chains[0].defaultTokens = [ADDR.other]; + expect(api.get('STAKING').rules[0].assets).toEqual([ + { + token: getAddress('0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5'), + maxPerCall: BigInt(10) ** BigInt(18), + maxTotal: BigInt(10) ** BigInt(19), + }, + ]); +}); diff --git a/packages/core/src/lib/agentic/__tests__/preset-operation-limits.spec.ts b/packages/core/src/lib/agentic/__tests__/preset-operation-limits.spec.ts index 42a2dcbe..5d1a73f1 100644 --- a/packages/core/src/lib/agentic/__tests__/preset-operation-limits.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/preset-operation-limits.spec.ts @@ -22,7 +22,7 @@ it('Aave pins the selected reserve, operation amount and wallet beneficiary for ...options, assets: [asset(), asset(WBTC, BigInt(7))], }); - expect(readiness.ready).toBe(true); + expect(readiness.chains[0].configurationReady).toBe(true); expect(rules).toHaveLength(1); for (const [selector, walletArg] of [ ['supply(address,uint256,address,uint16)', 2], @@ -44,27 +44,33 @@ it('Aave pins the selected reserve, operation amount and wallet beneficiary for } } }); -it('returns actionable readiness without silently choosing tokens, caps, gas or expiry', () => { +it('default lending policy needs only the agent to become locally ready', () => { const result = agenticPresets.get('LENDING', { chainNamespace }); expect(result.readiness.ready).toBe(false); expect(result.readiness.chains[0].issues.map((i) => i.code)).toEqual( - expect.arrayContaining([ - 'AGENT_REQUIRED', - 'EXPIRY_REQUIRED', - 'GAS_BUDGET_REQUIRED', - 'ASSETS_REQUIRED', - 'NO_ENABLED_OPERATION', - ]) + expect.arrayContaining(['AGENT_REQUIRED', 'BRIDGE_ASSET_UNAVAILABLE']) ); - expect(result.rules[0]).not.toHaveProperty('assets'); - expect(result.rules[0]).not.toHaveProperty('validUntil'); - expect(result.rules[0]).not.toHaveProperty('maxGasPerCall'); + expect(result.rules[0].assets).toEqual([ + { + token: LINK, + maxPerCall: BigInt(10) ** BigInt(18), + maxTotal: BigInt(10) ** BigInt(19), + }, + ]); + expect(result.rules[0].validUntil).toBeGreaterThan( + Math.floor(Date.now() / 1000) + ); + expect(result.rules[0].maxGasPerCall).toBe( + BigInt(20) * BigInt(10) ** BigInt(18) + ); + expect(result.readiness.chains[0].knownTokens).toContain(LINK); expect( - result.rules[0].allowedCalls.every((c) => - c.pins?.some((p) => p.max === BigInt(0)) - ) + agenticPresets.get('LENDING', { + chainNamespace, + agent: ADDR.agent, + funding: 'destination', + }).readiness.ready ).toBe(true); - expect(result.readiness.chains[0].knownTokens).toContain(LINK); }); it('zero operation caps remain valid disabled configurations, while zero bridge totals are separately reported', () => { const disabled = agenticPresets.get('LENDING', { @@ -81,7 +87,7 @@ it('zero operation caps remain valid disabled configurations, while zero bridge ...options, assets: [{ token: LINK, maxPerCall: BigInt(5) }], }); - expect(enabled.readiness.ready).toBe(true); + expect(enabled.readiness.chains[0].configurationReady).toBe(true); expect(enabled.readiness.chains[0].zeroBridgeLimits).toEqual([LINK]); expect(enabled.rules[0].assets?.[0].maxTotal).toBe(BigInt(0)); }); @@ -195,7 +201,8 @@ it('readiness is per chain and cannot be mutated to change later results', () => }); expect(res.readiness.ready).toBe(false); expect( - res.readiness.chains.find((c) => c.chainNamespace === chainNamespace)?.ready + res.readiness.chains.find((c) => c.chainNamespace === chainNamespace) + ?.configurationReady ).toBe(true); const expected = agenticPresets.get('LENDING', { chainNamespace }).readiness; res.readiness.chains.forEach((c) => { diff --git a/packages/core/src/lib/agentic/__tests__/preset-routes.spec.ts b/packages/core/src/lib/agentic/__tests__/preset-routes.spec.ts new file mode 100644 index 00000000..077b2351 --- /dev/null +++ b/packages/core/src/lib/agentic/__tests__/preset-routes.spec.ts @@ -0,0 +1,103 @@ +import { agenticPresets } from '../presets'; +import { CHAIN, PUSH_NETWORK } from '../../constants/enums'; +import { MOVEABLE_TOKEN_CONSTANTS } from '../../constants/tokens'; +import { ADDR } from './fake-chain'; + +const options = { chainNamespace: CHAIN.ETHEREUM_SEPOLIA, agent: ADDR.agent }; +it('reports unmapped source tokens without silently changing the default Push grant', () => { + const res = agenticPresets.get('LENDING', options); + expect(res.readiness.ready).toBe(false); + const state = res.readiness.chains[0]; + expect(state.configurationReady).toBe(true); + expect(state.funding).toBe('push'); + expect(state.issues).toContainEqual( + expect.objectContaining({ + code: 'BRIDGE_ASSET_UNAVAILABLE', + token: '0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5', + }) + ); + expect(res.rules[0].assets).toEqual(state.selectedAssets); + expect(res.rules[0].assets).toHaveLength(1); +}); +it('supports the explicit destination-funded grant with preserved token/amount pins and review metadata', () => { + const push = agenticPresets.get('DEXES', options); + const dest = agenticPresets.get('DEXES', { + ...options, + funding: 'destination', + }); + expect(push.readiness.ready).toBe(false); + expect(dest.readiness.ready).toBe(true); + expect(dest.rules[0].assets).toEqual([]); + expect(dest.readiness.chains[0].selectedAssets).toEqual(push.rules[0].assets); + expect(dest.rules[0].allowedCalls).toEqual(push.rules[0].allowedCalls); + expect(dest.readiness.chains[0].bridgeAssets.map((a) => a.status)).toEqual([ + 'registered', + 'unavailable', + ]); + const returned = dest.readiness.chains[0].selectedAssets[0]; + returned.maxPerCall = BigInt(0); + expect( + agenticPresets.get('DEXES', options).rules[0].assets?.[0].maxPerCall + ).toBeGreaterThan(BigInt(0)); +}); +it('an explicitly selected mapped source token can be ready for Push funding', () => { + const token = MOVEABLE_TOKEN_CONSTANTS.BNB_TESTNET.USDT; + const res = agenticPresets.get('DEXES', { + chainNamespace: CHAIN.BNB_TESTNET, + agent: ADDR.agent, + assets: [ + { + token: MOVEABLE_TOKEN_CONSTANTS.BNB_TESTNET.USDC, + maxPerCall: BigInt(5), + maxTotal: BigInt(10), + }, + { token, maxPerCall: BigInt(5), maxTotal: BigInt(10) }, + ], + }); + expect(res.readiness.ready).toBe(true); + expect( + res.readiness.chains[0].bridgeAssets.every((a) => a.status === 'registered') + ).toBe(true); +}); +it('never treats a mainnet template or undeployed Push generation as executable', () => { + const mainnet = agenticPresets.get('DEXES', { + agent: ADDR.agent, + chainNamespace: CHAIN.ETHEREUM_MAINNET, + funding: 'destination', + }); + expect(mainnet.readiness.ready).toBe(false); + expect(mainnet.readiness.chains[0].issues).toContainEqual( + expect.objectContaining({ code: 'DESTINATION_UNAVAILABLE' }) + ); + const missing = agenticPresets.get('LENDING', { + ...options, + funding: 'destination', + network: PUSH_NETWORK.MAINNET, + }); + expect(missing.readiness.ready).toBe(false); + expect(missing.readiness.chains[0].issues).toContainEqual( + expect.objectContaining({ code: 'AGW_NETWORK_UNAVAILABLE' }) + ); +}); +it('supports the TESTNET alias, rejects invalid modes and preserves empty selections', () => { + expect( + agenticPresets.get('LENDING', { + ...options, + funding: 'destination', + network: PUSH_NETWORK.TESTNET, + }).readiness.ready + ).toBe(true); + expect(() => + agenticPresets.get('LENDING', { ...options, funding: 'auto' as never }) + ).toThrow(/funding/); + expect(() => + agenticPresets.get('LENDING', { ...options, network: 'OTHER' as never }) + ).toThrow(/network/); + const empty = agenticPresets.get('LENDING', { + ...options, + funding: 'destination', + assets: [], + }); + expect(empty.readiness.chains[0].selectedAssets).toEqual([]); + expect(empty.readiness.ready).toBe(false); +}); diff --git a/packages/core/src/lib/agentic/__tests__/presets.spec.ts b/packages/core/src/lib/agentic/__tests__/presets.spec.ts index ffb41709..9ea62bad 100644 --- a/packages/core/src/lib/agentic/__tests__/presets.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/presets.spec.ts @@ -84,7 +84,7 @@ it('ships verified mainnet and testnet templates and keeps prediction empty', () agenticPresets.get('LENDING', { chainNamespace: 'eip155:999999' }) ).toThrow(/no approved entry/); }); -it('groups all apps on a chain into one editable template and omits unspecified fields', () => { +it('groups apps on a chain into one editable template with default expiry and omitted identity', () => { const data = catalog(); data[0].chains[0].allowedCalls = [ ...data[0].chains[0].allowedCalls, @@ -101,7 +101,7 @@ it('groups all apps on a chain into one editable template and omits unspecified for (const rule of res.rules) { expect(rule).not.toHaveProperty('agent'); expect(rule).not.toHaveProperty('assets'); - expect(rule).not.toHaveProperty('validUntil'); + expect(rule.validUntil).toBeGreaterThan(Math.floor(Date.now() / 1000)); } expect(api.list({ type: 'CATEGORY' }).presets[0].chains).toEqual([ chain, @@ -134,7 +134,7 @@ it('returns ready Rule types with identity and expiry; routes assets and default }); it('does not type an incomplete template as a ready rule', () => { const { rules } = buildPresetApi(catalog()).get('DEXES'); - // @ts-expect-error callers must fill agent and expiry before create + // @ts-expect-error callers must fill agent before create const ready: Rule[] = rules; expect(ready[0].agent).toBeUndefined(); }); diff --git a/packages/core/src/lib/agentic/contracts/prc20-metadata.ts b/packages/core/src/lib/agentic/contracts/prc20-metadata.ts index 332bb0b6..e5eff6b3 100644 --- a/packages/core/src/lib/agentic/contracts/prc20-metadata.ts +++ b/packages/core/src/lib/agentic/contracts/prc20-metadata.ts @@ -95,7 +95,7 @@ export async function readGasPrc20( ) ); } -/** Donut native precompile returns a zero word; ERC20 metadata is a dynamic string. */ +/** Solidity PRC20s return a string; Donut precompiles can return an address word. */ export async function readOriginToken( snap: Snapshot, token: Address, @@ -109,14 +109,25 @@ export async function readOriginToken( 'SOURCE_TOKEN_ADDRESS' ); } catch (cause) { - if ((await readGasPrc20(snap, chain)) !== getAddress(token)) throw cause; - const native = await snap.read

( - token, - NATIVE_SOURCE_ABI, - 'SOURCE_TOKEN_ADDRESS' + let sourceWord: Address; + try { + sourceWord = getAddress( + await snap.read
( + token, + NATIVE_SOURCE_ABI, + 'SOURCE_TOKEN_ADDRESS' + ) + ); + } catch { + throw cause; + } + if (sourceWord !== zeroAddress) return sourceWord; + if ((await readGasPrc20(snap, chain)) === getAddress(token)) + return zeroAddress; + throw new AgenticError( + AGENTIC_ERROR_CODE.RULE_READ_FAILED, + `non-native PRC20 ${token} has an empty source token address` ); - if (getAddress(native) === zeroAddress) return zeroAddress; - throw cause; } if (isAddress(source, { strict: false })) return getAddress(source); if (source === '' && (await readGasPrc20(snap, chain)) === getAddress(token)) diff --git a/packages/core/src/lib/agentic/presets/catalog.ts b/packages/core/src/lib/agentic/presets/catalog.ts index c7d7b2e2..263ddd92 100644 --- a/packages/core/src/lib/agentic/presets/catalog.ts +++ b/packages/core/src/lib/agentic/presets/catalog.ts @@ -2,6 +2,11 @@ import { getAddress, type Address } from 'viem'; import type { RuleCall, ForeignChainNamespace } from '../agentic.types'; import type { PresetCategory } from './types'; import { AAVE_RESERVES } from './aave-reserves'; +import { + DEX_DEFAULT_TOKENS, + LENDING_DEFAULT_TOKENS, + STAKING_DEFAULT_TOKENS, +} from './default-tokens'; export type PresetBudget = | { @@ -25,6 +30,8 @@ export interface PresetCallDefinition extends RuleCall { /** Internal catalog: reviewed addresses and explicit calls only; never fetched at runtime. */ export interface PresetChainDefinition { chainNamespace: ForeignChainNamespace; + /** Used with the bundled permission policy only when assets is omitted. */ + defaultTokens?: readonly Address[]; allowedCalls: readonly PresetCallDefinition[]; /** Static single-hop routers; incomplete pairs return zero-input-cap review calls. */ swapRouters?: readonly { address: Address; app: string }[]; @@ -205,6 +212,7 @@ export const PRESET_CATALOG: readonly PresetDefinition[] = [ ], ].map(([chain, router, app]) => ({ chainNamespace: chain as ForeignChainNamespace, + defaultTokens: DEX_DEFAULT_TOKENS[chain], allowedCalls: [], swapRouters: [{ address: address(router), app }], approvals: [{ spender: address(router), app }], @@ -223,6 +231,7 @@ export const PRESET_CATALOG: readonly PresetDefinition[] = [ ] as const ).map(([chainNamespace, pool]) => ({ chainNamespace, + defaultTokens: LENDING_DEFAULT_TOKENS[chainNamespace], allowedCalls: [ ...aave(address(pool), chainNamespace), ...mainnetMarkets(chainNamespace).allowedCalls, @@ -239,6 +248,7 @@ export const PRESET_CATALOG: readonly PresetDefinition[] = [ { chainNamespace: 'eip155:11155111', + defaultTokens: LENDING_DEFAULT_TOKENS['eip155:11155111'], allowedCalls: aave(sepoliaPool, 'eip155:11155111'), approvals: [ { @@ -250,6 +260,7 @@ export const PRESET_CATALOG: readonly PresetDefinition[] = [ }, { chainNamespace: 'eip155:421614', + defaultTokens: LENDING_DEFAULT_TOKENS['eip155:421614'], allowedCalls: aave(arbitrumPool, 'eip155:421614'), approvals: [ { @@ -261,6 +272,7 @@ export const PRESET_CATALOG: readonly PresetDefinition[] = [ }, { chainNamespace: 'eip155:84532', + defaultTokens: LENDING_DEFAULT_TOKENS['eip155:84532'], allowedCalls: [ ...aave(basePool, 'eip155:84532'), ...market( @@ -301,6 +313,7 @@ export const PRESET_CATALOG: readonly PresetDefinition[] = [ }, { chainNamespace: 'eip155:97', + defaultTokens: LENDING_DEFAULT_TOKENS['eip155:97'], allowedCalls: [ ...market( venusUSDT, @@ -341,6 +354,7 @@ export const PRESET_CATALOG: readonly PresetDefinition[] = [ chains: [ { chainNamespace: 'eip155:1', + defaultTokens: STAKING_DEFAULT_TOKENS['eip155:1'], allowedCalls: [ { target: stETH, @@ -407,6 +421,7 @@ export const PRESET_CATALOG: readonly PresetDefinition[] = [ { chainNamespace: 'eip155:11155111', + defaultTokens: STAKING_DEFAULT_TOKENS['eip155:11155111'], allowedCalls: [ { target: eigen, diff --git a/packages/core/src/lib/agentic/presets/default-policy.ts b/packages/core/src/lib/agentic/presets/default-policy.ts new file mode 100644 index 00000000..dc1cf5dd --- /dev/null +++ b/packages/core/src/lib/agentic/presets/default-policy.ts @@ -0,0 +1,98 @@ +import { getAddress, parseUnits } from 'viem'; +import type { Address } from 'viem'; +import type { RuleAsset } from '../agentic.types'; +import { capabilityUnavailable } from '../errors'; + +/** Preset-only permission policy. Ordinary rule authoring retains zero defaults. + * Amounts are token quantities, not USD valuations or destination lifetime caps. + * Metadata verified read-only on October 18; evidence is retained under plan/agw/. + */ +export const PRESET_VALIDITY_SECONDS = 7 * 24 * 60 * 60; + +// Explicit profiles keep future chains from inheriting an unreviewed budget. +// 20 PC is a ceiling, not the amount charged: execution obtains a fresh quote. +// This budget has testnet protocol-flow coverage; mainnet remains template-only. +export const PRESET_GAS_BUDGETS: Readonly> = + Object.fromEntries( + [ + 'eip155:1', + 'eip155:8453', + 'eip155:42161', + 'eip155:56', + 'eip155:11155111', + 'eip155:84532', + 'eip155:421614', + 'eip155:97', + ].map((chain) => [chain, parseUnits('20', 18)]) + ); + +type TokenBudget = { decimals: number; perCall: string; total: string }; +const stable6: TokenBudget = { decimals: 6, perCall: '10', total: '100' }; +const stable18: TokenBudget = { ...stable6, decimals: 18 }; +const eth: TokenBudget = { decimals: 18, perCall: '0.001', total: '0.01' }; +const bnb: TokenBudget = { decimals: 18, perCall: '0.01', total: '0.1' }; +const link: TokenBudget = { decimals: 18, perCall: '1', total: '10' }; + +// Match by chain AND address. Never infer decimals or limits from a symbol, +// caller metadata, or the position of a token in an arbitrary selection. +const TOKEN_BUDGETS: Readonly< + Record +> = { + 'eip155:1': [ + ['0x0000000000000000000000000000000000000000', eth], + ['0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', eth], + ['0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', stable6], + ['0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84', eth], + ['0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0', eth], + ], + 'eip155:8453': [ + ['0x4200000000000000000000000000000000000006', eth], + ['0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', stable6], + ], + 'eip155:42161': [ + ['0x82aF49447D8a07e3bd95BD0d56f35241523fBab1', eth], + ['0xaf88d065e77c8cC2239327C5EDb3A432268e5831', stable6], + ], + 'eip155:56': [ + ['0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c', bnb], + ['0x55d398326f99059fF775485246999027B3197955', stable18], + ], + 'eip155:11155111': [ + ['0xfff9976782d46cc05630d1f6ebab18b2324d6b14', eth], + ['0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238', stable6], + ['0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5', link], + ['0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9', eth], + ], + 'eip155:84532': [ + ['0x4200000000000000000000000000000000000006', eth], + ['0x036CbD53842c5426634e7929541eC2318f3dCF7e', stable6], + ['0x810D46F9a9027E28F9B01F75E2bdde839dA61115', link], + ['0x4616975f7E6045FD9737e95bC527e9e14c727BD2', stable6], + ['0x663A6F02d547dFd639BF689FED298712f2FB69Fb', eth], + ], + 'eip155:421614': [ + ['0x980B62Da83eFf3D4576C647993b0c1D7faf17c73', eth], + ['0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d', stable6], + ], + 'eip155:97': [ + ['0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd', bnb], + ['0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c', stable6], + ['0x16227D60f7a0e586C66B005219dfc887D13C9531', stable6], + ], +}; + +export function defaultPresetAsset(chain: string, token: Address): RuleAsset { + const budget = TOKEN_BUDGETS[chain]?.find( + ([address]) => getAddress(address) === getAddress(token) + )?.[1]; + if (!budget) + throw capabilityUnavailable( + 'presetPolicy', + `No reviewed default spending policy for ${chain}:${token}` + ); + return { + token, + maxPerCall: parseUnits(budget.perCall, budget.decimals), + maxTotal: parseUnits(budget.total, budget.decimals), + }; +} diff --git a/packages/core/src/lib/agentic/presets/default-tokens.ts b/packages/core/src/lib/agentic/presets/default-tokens.ts new file mode 100644 index 00000000..09f38ece --- /dev/null +++ b/packages/core/src/lib/agentic/presets/default-tokens.ts @@ -0,0 +1,80 @@ +import { getAddress, zeroAddress, type Address } from 'viem'; + +/** Curated subsets of the reviewed catalog. Addresses are destination tokens, + * not a promise that a Push PRC20 route or protocol liquidity is available. + * Keep these sets within the policy's 32-call/32-pin limits after expansion. + * Testnet DEX pairs and lending/staking assets match the live preset fixtures. + * Mainnet addresses share the catalog's October 15 read-only source baseline. + * Spending caps are intentionally separate from token selection. + */ +const addresses = (...values: string[]): readonly Address[] => + values.map((value) => getAddress(value.toLowerCase())); + +export const DEX_DEFAULT_TOKENS: Readonly> = + { + 'eip155:1': addresses( + '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', + '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' + ), + 'eip155:8453': addresses( + '0x4200000000000000000000000000000000000006', + '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913' + ), + 'eip155:42161': addresses( + '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1', + '0xaf88d065e77c8cC2239327C5EDb3A432268e5831' + ), + 'eip155:56': addresses( + '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c', + '0x55d398326f99059fF775485246999027B3197955' + ), + 'eip155:11155111': addresses( + '0xfff9976782d46cc05630d1f6ebab18b2324d6b14', + '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238' + ), + 'eip155:84532': addresses( + '0x4200000000000000000000000000000000000006', + '0x036CbD53842c5426634e7929541eC2318f3dCF7e' + ), + 'eip155:421614': addresses( + '0x980B62Da83eFf3D4576C647993b0c1D7faf17c73', + '0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d' + ), + 'eip155:97': addresses( + '0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd', + '0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c' + ), + }; + +export const LENDING_DEFAULT_TOKENS: Readonly< + Record +> = { + 'eip155:1': DEX_DEFAULT_TOKENS['eip155:1'], + // One shared reserve/market token keeps Aave + Moonwell/Venus within 32 pins. + 'eip155:8453': addresses('0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913'), + 'eip155:42161': DEX_DEFAULT_TOKENS['eip155:42161'], + 'eip155:56': addresses('0x55d398326f99059fF775485246999027B3197955'), + // Protocol testnet reserves differ from Circle USDC and DEX wrapped ETH. + 'eip155:11155111': addresses('0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5'), + 'eip155:84532': addresses( + '0x810D46F9a9027E28F9B01F75E2bdde839dA61115', + '0x4616975f7E6045FD9737e95bC527e9e14c727BD2', + '0x663A6F02d547dFd639BF689FED298712f2FB69Fb' + ), + 'eip155:421614': addresses('0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d'), + 'eip155:97': addresses( + '0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c', + '0x16227D60f7a0e586C66B005219dfc887D13C9531' + ), +}; + +export const STAKING_DEFAULT_TOKENS: Readonly< + Record +> = { + 'eip155:1': addresses( + zeroAddress, + '0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84', + '0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0' + ), + 'eip155:11155111': addresses('0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9'), +}; diff --git a/packages/core/src/lib/agentic/presets/index.ts b/packages/core/src/lib/agentic/presets/index.ts index 9ba56b05..e8014551 100644 --- a/packages/core/src/lib/agentic/presets/index.ts +++ b/packages/core/src/lib/agentic/presets/index.ts @@ -15,6 +15,13 @@ import type { import { parseSelector } from '../codec/selectors'; import { PRESET_CATALOG, type PresetDefinition } from './catalog'; import { applyOperationLimits, assetAddress } from './operation-limits'; +import { PUSH_NETWORK } from '../../constants/enums'; +import { presetRoutes } from './routes'; +import { + defaultPresetAsset, + PRESET_GAS_BUDGETS, + PRESET_VALIDITY_SECONDS, +} from './default-policy'; const MAX_UINT256 = (BigInt(1) << BigInt(256)) - BigInt(1); const invalid = (message: string) => @@ -62,6 +69,7 @@ export function buildPresetApi( ...p, chains: p.chains.map((c) => ({ ...c, + ...(c.defaultTokens ? { defaultTokens: [...c.defaultTokens] } : {}), allowedCalls: c.allowedCalls.map((call) => ({ ...copyCall(call), ...(call.budget @@ -108,6 +116,13 @@ export function buildPresetApi( if (!entry) throw invalid(`unknown preset ${String(preset)}`); if (!options || typeof options !== 'object' || Array.isArray(options)) throw invalid('preset options must be an object'); + const now = Math.floor(Date.now() / 1000); + const network = options.network ?? PUSH_NETWORK.TESTNET_DONUT; + const funding = options.funding ?? 'push'; + if (!Object.values(PUSH_NETWORK).includes(network)) + throw invalid('unknown preset Push network'); + if (funding !== 'push' && funding !== 'destination') + throw invalid('preset funding must be push or destination'); if ( options.agent !== undefined && (!isAddress(options.agent, { strict: false }) || @@ -117,10 +132,11 @@ export function buildPresetApi( if ( options.validUntil !== undefined && (!Number.isSafeInteger(options.validUntil) || - options.validUntil <= Math.floor(Date.now() / 1000) || + options.validUntil <= now || options.validUntil >= 2 ** 48) ) throw invalid('preset validUntil must be a future uint48 timestamp'); + const validUntil = options.validUntil ?? now + PRESET_VALIDITY_SECONDS; if (options.maxGasPerCall !== undefined) cap(options.maxGasPerCall, 'maxGasPerCall'); if (options.assets !== undefined && !Array.isArray(options.assets)) @@ -142,6 +158,17 @@ export function buildPresetApi( `preset ${preset} has no approved app entries` ); const assets = new Map(); + // An explicit array (including []) replaces the defaults for all selected + // chains. Never add permissions on chains the caller left unconfigured. + if (options.assets === undefined) + for (const chain of chains) + if (chain.defaultTokens) + assets.set( + chain.chainNamespace, + chain.defaultTokens.map((token) => + defaultPresetAsset(chain.chainNamespace, token) + ) + ); for (const asset of options.assets ?? []) { if (!asset || typeof asset !== 'object') throw invalid('preset asset must be an object'); @@ -181,6 +208,12 @@ export function buildPresetApi( } const readiness: PresetChainReadiness[] = []; const rules: PresetRuleTemplate[] = chains.map((chain) => { + const maxGasPerCall = + options.maxGasPerCall ?? + chain.maxGasPerCall ?? + (chain.defaultTokens + ? PRESET_GAS_BUDGETS[chain.chainNamespace] + : undefined); const selectedAssets = assets.get(chain.chainNamespace) ?? []; const limits = applyOperationLimits( chain.allowedCalls.map((c) => ({ @@ -362,15 +395,7 @@ export function buildPresetApi( code: 'AGENT_REQUIRED', message: 'Choose the agent Push address.', }); - if (!options.validUntil) - issues.push({ - code: 'EXPIRY_REQUIRED', - message: 'Choose an expiry.', - }); - if ( - (options.maxGasPerCall ?? chain.maxGasPerCall ?? BigInt(0)) === - BigInt(0) - ) + if ((maxGasPerCall ?? BigInt(0)) === BigInt(0)) issues.push({ code: 'GAS_BUDGET_REQUIRED', message: 'Set a positive PC gas budget per outbound.', @@ -391,14 +416,32 @@ export function buildPresetApi( code: 'NO_ENABLED_OPERATION', message: 'No asset operation has a positive per-call limit.', }); + const configurationReady = issues.length === 0; + const routes = presetRoutes( + chain.chainNamespace, + selectedAssets, + network, + funding + ); + issues.push(...routes.issues); + const bridgeAssets = funding === 'destination' ? [] : selectedAssets; readiness.push({ chainNamespace: chain.chainNamespace, ready: issues.length === 0, + configurationReady, + funding, + selectedAssets: selectedAssets.map((a) => ({ + ...a, + token: typeof a.token === 'string' ? a.token : { ...a.token }, + })), + bridgeAssets: routes.bridgeAssets, issues, disabledCalls: limits.disabledCalls, excludedCalls: limits.excludedCalls, - knownTokens: limits.knownTokens, - zeroBridgeLimits: selectedAssets + knownTokens: [ + ...new Set([...limits.knownTokens, ...(chain.defaultTokens ?? [])]), + ], + zeroBridgeLimits: bridgeAssets .filter( (a) => a.maxPerCall === BigInt(0) || a.maxTotal === BigInt(0) ) @@ -410,19 +453,12 @@ export function buildPresetApi( ...(options.agent !== undefined ? { agent: getAddress(options.agent) } : {}), - ...(options.validUntil !== undefined - ? { validUntil: options.validUntil } + validUntil, + ...(options.assets !== undefined || chain.defaultTokens + ? { assets: bridgeAssets } : {}), - ...(options.assets !== undefined - ? { assets: assets.get(chain.chainNamespace) ?? [] } - : {}), - ...((options.maxGasPerCall ?? chain.maxGasPerCall) !== undefined - ? { - maxGasPerCall: cap( - options.maxGasPerCall ?? chain.maxGasPerCall, - 'maxGasPerCall' - ), - } + ...(maxGasPerCall !== undefined + ? { maxGasPerCall: cap(maxGasPerCall, 'maxGasPerCall') } : {}), }; }); @@ -435,7 +471,7 @@ export function buildPresetApi( }; }, }; - // The overload narrows templates only when both required fields were supplied and validated. + // Expiry is generated; the overload narrows templates when the agent is supplied. return Object.freeze(api) as AgenticPresets; } export const agenticPresets = buildPresetApi(PRESET_CATALOG); diff --git a/packages/core/src/lib/agentic/presets/routes.ts b/packages/core/src/lib/agentic/presets/routes.ts new file mode 100644 index 00000000..fc0babf4 --- /dev/null +++ b/packages/core/src/lib/agentic/presets/routes.ts @@ -0,0 +1,56 @@ +import { getAddress } from 'viem'; +import { PUSH_NETWORK, type CHAIN } from '../../constants/enums'; +import { SUPPORTED_GATEWAY_CHAINS } from '../../orchestrator/internals/helpers'; +import { getPRC20Address } from '../../universal/prc20-address'; +import { generationsFor } from '../deployments'; +import type { RuleAsset } from '../agentic.types'; +import type { PresetChainReadiness, PresetConfigurationIssue } from './types'; +import { assetAddress } from './operation-limits'; + +/** Offline registry checks only. Grant preparation still verifies source metadata + * and wiring against chain state before any signature or transaction. */ +export function presetRoutes( + chain: string, + assets: RuleAsset[], + network: PUSH_NETWORK, + funding: 'push' | 'destination' +): { + bridgeAssets: PresetChainReadiness['bridgeAssets']; + issues: PresetConfigurationIssue[]; +} { + const issues: PresetConfigurationIssue[] = []; + network = + network === PUSH_NETWORK.TESTNET ? PUSH_NETWORK.TESTNET_DONUT : network; + if (!generationsFor(network).some((g) => g.advertised)) + issues.push({ + code: 'AGW_NETWORK_UNAVAILABLE', + message: `No verified AGW deployment is registered for ${network}.`, + }); + const supported = SUPPORTED_GATEWAY_CHAINS.includes(chain as CHAIN); + if (!supported) + issues.push({ + code: 'DESTINATION_UNAVAILABLE', + message: `The SDK has no supported gateway route to ${chain}; this is a catalog template.`, + }); + const bridgeAssets = assets.map((asset) => { + const token = assetAddress(asset); + try { + if (!supported) throw new Error(`No supported gateway route to ${chain}`); + const prc20 = getPRC20Address({ chain, address: token }, { network }); + return { + token, + prc20: getAddress(prc20.address), + status: 'registered' as const, + }; + } catch { + if (funding === 'push') + issues.push({ + code: 'BRIDGE_ASSET_UNAVAILABLE', + token, + message: `No SDK PRC20 mapping for ${chain}:${token} on ${network}. Use a supported source asset or explicitly choose destination funding for assets already at the CEA.`, + }); + return { token, status: 'unavailable' as const }; + } + }); + return { bridgeAssets, issues }; +} diff --git a/packages/core/src/lib/agentic/presets/types.ts b/packages/core/src/lib/agentic/presets/types.ts index 5f89ffbb..f014991c 100644 --- a/packages/core/src/lib/agentic/presets/types.ts +++ b/packages/core/src/lib/agentic/presets/types.ts @@ -1,4 +1,5 @@ import type { Address } from 'viem'; +import type { PUSH_NETWORK } from '../../constants/enums'; import type { Rule, RuleAsset, @@ -13,7 +14,7 @@ export interface Preset { name: string; chains: ForeignChainNamespace[]; } -/** An editable review-screen template; both identity and expiry are required by create. */ +/** Presets generate expiry; optional fields retain editable-template compatibility. */ export type PresetRuleTemplate = Omit & { agent?: Address; validUntil?: number; @@ -28,20 +29,29 @@ export interface PresetAsset { maxTotal?: bigint; } export interface PresetOptions { - /** Explicit Push-PC gas budget per outbound; omitted = zero. */ + /** Offline route/deployment checks; defaults to TESTNET_DONUT. */ + network?: PUSH_NETWORK; + /** Push funding requires PRC20 routes. Destination funding explicitly emits + * empty bridge assets while preserving selected token/call limits in metadata. + * The CEA must already hold the required destination assets. Default: push. */ + funding?: 'push' | 'destination'; + /** Push-PC budget ceiling per outbound; omitted uses the catalog policy (20 PC). + * Explicit zero is preserved. This is not the fee charged. */ maxGasPerCall?: bigint; chainNamespace?: ForeignChainNamespace; agent?: Address; + /** Omitted: seven days from generation time. Explicit expiry is preserved. */ validUntil?: number; - /** DEX swaps with fewer than two tokens are zero-input-cap review templates. - * Call get again with a complete pair to generate token pins and amount limits. */ + /** Omitted: include the catalog's curated tokens and explicit spending policy. + * An explicit array replaces all defaults (including [] to select no tokens). + * Supplied assets retain zero for omitted caps; no policy is guessed for them. + * DEX swaps with fewer than two tokens remain zero-input-cap review templates. */ assets?: PresetAsset[]; } export interface ReadyPresetOptions extends PresetOptions { agent: Address; - validUntil: number; } -/** Offline configuration only: does not check deployment, reserves, balances or liquidity. */ +/** Offline configuration/registry checks; chain state and balances are not checked. */ export interface PresetConfigurationIssue { code: | 'AGENT_REQUIRED' @@ -49,8 +59,12 @@ export interface PresetConfigurationIssue { | 'GAS_BUDGET_REQUIRED' | 'ASSETS_REQUIRED' | 'TOKEN_PAIR_REQUIRED' - | 'NO_ENABLED_OPERATION'; + | 'NO_ENABLED_OPERATION' + | 'AGW_NETWORK_UNAVAILABLE' + | 'DESTINATION_UNAVAILABLE' + | 'BRIDGE_ASSET_UNAVAILABLE'; message: string; + token?: string; } export interface PresetCallIssue { target: string; @@ -69,12 +83,22 @@ export interface PresetCallIssue { export interface PresetChainReadiness { chainNamespace: ForeignChainNamespace; ready: boolean; + configurationReady: boolean; + funding: 'push' | 'destination'; + /** Selected destination permissions, retained even when bridge assets is empty. */ + selectedAssets: RuleAsset[]; + /** Registry presence only; grant preparation verifies exact on-chain identity. */ + bridgeAssets: { + token: string; + status: 'registered' | 'unavailable'; + prc20?: Address; + }[]; issues: PresetConfigurationIssue[]; /** Calls present in the rule but disabled by a zero amount/value maximum. */ disabledCalls: PresetCallIssue[]; /** Calls deliberately omitted, including operations with incompatible amount units. */ excludedCalls: PresetCallIssue[]; - /** Known fixed-token/reserve addresses in this catalog, not selected defaults. */ + /** Known catalog token addresses, including the curated default subset. */ knownTokens: string[]; /** Selected tokens with a zero Push-outbound budget; destination-held assets are separate. */ zeroBridgeLimits: string[]; diff --git a/packages/core/src/lib/universal/prc20-address.spec.ts b/packages/core/src/lib/universal/prc20-address.spec.ts new file mode 100644 index 00000000..42aa2f81 --- /dev/null +++ b/packages/core/src/lib/universal/prc20-address.spec.ts @@ -0,0 +1,65 @@ +import { getAddress } from 'viem'; +import { getPRC20Address } from './prc20-address'; +import { CHAIN, PUSH_NETWORK } from '../constants/enums'; +import { MOVEABLE_TOKEN_CONSTANTS } from '../constants/tokens'; +import { SYNTHETIC_PUSH_ERC20 } from '../constants/chain'; + +const addresses = SYNTHETIC_PUSH_ERC20[PUSH_NETWORK.TESTNET_DONUT]; +it.each([ + ['WETH', '0xfff9976782d46cc05630d1f6ebab18b2324d6b14', addresses.WETH_ETH], + ['stETH', '0x3e3FE7dBc6B4C189E7128855dD526361c49b40Af', addresses.stETH_ETH], +] as const)( + 'resolves verified Sepolia %s for lowercase/checksummed address input', + (symbol, address, prc20) => { + for (const input of [address.toLowerCase(), getAddress(address)]) { + expect( + getPRC20Address({ chain: CHAIN.ETHEREUM_SEPOLIA, address: input }) + ).toMatchObject({ + chain: CHAIN.ETHEREUM_SEPOLIA, + symbol, + address: prc20, + decimals: 18, + }); + } + } +); +it('preserves case-sensitive Solana identities while accepting EVM casing variations', () => { + const token = MOVEABLE_TOKEN_CONSTANTS.BASE_SEPOLIA.USDC; + expect( + getPRC20Address({ + chain: CHAIN.BASE_SEPOLIA, + address: token.address.toLowerCase(), + }).address + ).toBe(addresses.USDC_BASE); + const mint = MOVEABLE_TOKEN_CONSTANTS.SOLANA_DEVNET.USDC; + expect(() => + getPRC20Address({ + chain: CHAIN.SOLANA_DEVNET, + address: mint.address.toLowerCase(), + }) + ).toThrow(/infer/); + expect( + getPRC20Address({ chain: CHAIN.SOLANA_DEVNET, address: mint.address }) + .address + ).toBe(addresses.USDC_SOL); +}); +it('never aliases mainnet ETH/WETH or a different chain WETH to Sepolia', () => { + expect(() => + getPRC20Address({ + chain: CHAIN.ETHEREUM_MAINNET, + address: MOVEABLE_TOKEN_CONSTANTS.ETHEREUM_MAINNET.ETH.address, + }) + ).toThrow(/Unsupported ETH origin/); + expect(() => + getPRC20Address({ + chain: CHAIN.ETHEREUM_MAINNET, + address: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', + }) + ).toThrow(/Unsupported WETH origin/); + expect(() => + getPRC20Address({ + chain: CHAIN.ARBITRUM_SEPOLIA, + address: '0x980B62Da83eFf3D4576C647993b0c1D7faf17c73', + }) + ).toThrow(/Unsupported WETH origin/); +}); diff --git a/packages/core/src/lib/universal/prc20-address.ts b/packages/core/src/lib/universal/prc20-address.ts index 693aa28e..db40f912 100644 --- a/packages/core/src/lib/universal/prc20-address.ts +++ b/packages/core/src/lib/universal/prc20-address.ts @@ -1,6 +1,12 @@ import { CHAIN, PUSH_NETWORK } from '../constants/enums'; import { MOVEABLE_TOKENS, type MoveableToken } from '../constants/tokens'; import { SYNTHETIC_PUSH_ERC20 } from '../constants/chain'; +import { isAddress } from 'viem'; + +const sameTokenAddress = (a: string, b: string) => + isAddress(a, { strict: false }) && isAddress(b, { strict: false }) + ? a.toLowerCase() === b.toLowerCase() + : a === b; /** Shared pure origin-to-PRC20 mapping; no signer or network reads. */ export function getPRC20Address( @@ -58,7 +64,9 @@ export function getPRC20Address( for (const [key, list] of Object.entries(MOVEABLE_TOKENS)) { const k = key as CHAIN; const match = (list ?? []).find( - (t) => t.symbol === token.symbol && t.address === token.address + (t) => + t.symbol === token.symbol && + sameTokenAddress(t.address, token.address) ); if (match) { originChain = k; @@ -71,7 +79,7 @@ export function getPRC20Address( // { chain, address } path: trust the provided chain and resolve symbol via registry originChain = token.chain as CHAIN; const list = MOVEABLE_TOKENS[originChain] ?? []; - const match = list.find((t) => t.address === token.address); + const match = list.find((t) => sameTokenAddress(t.address, token.address)); if (match) { tokenSymbol = match.symbol; tokenDecimals = match.decimals; @@ -88,9 +96,9 @@ export function getPRC20Address( } // Map token → synthetic key by origin chain family - const isEthFamily = - originChain === CHAIN.ETHEREUM_MAINNET || - originChain === CHAIN.ETHEREUM_SEPOLIA; + // Current synthetic keys represent testnet sources. Mainnet assets must never + // resolve to a same-symbol Sepolia token on Donut. + const isEthFamily = originChain === CHAIN.ETHEREUM_SEPOLIA; const isArbFamily = originChain === CHAIN.ARBITRUM_SEPOLIA; const isBaseFamily = originChain === CHAIN.BASE_SEPOLIA; const isBnbFamily = originChain === CHAIN.BNB_TESTNET; @@ -111,9 +119,21 @@ export function getPRC20Address( | 'USDC_ARB' | 'USDC_SOL' | 'USDC_BSC' - | 'USDC_BASE'; + | 'USDC_BASE' + | 'WETH_ETH' + | 'stETH_ETH'; switch (tokenSymbol) { + case 'WETH': + case 'stETH': { + // These deployments represent Sepolia tokens, not other chains' assets. + if (originChain !== CHAIN.ETHEREUM_SEPOLIA) + throw new Error( + `Unsupported ${tokenSymbol} origin chain for synthetic mapping` + ); + key = tokenSymbol === 'WETH' ? 'WETH_ETH' : 'stETH_ETH'; + break; + } case 'ETH': { if (isEthFamily) key = 'pETH'; else if (isArbFamily) key = 'pETH_ARB'; From 49906a0ab5a08e8826714af8fa74510de8b95610 Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Sun, 18 Oct 2026 18:55:38 +0530 Subject: [PATCH 50/68] docs(agw): record preset release acceptance and funding limits --- plan/agw/implementation-status.md | 8 +- plan/agw/pending-items.md | 9 +- .../preset-configuration-2026-10-16/README.md | 19 +- .../live-aave-acceptance.log | 11 + .../live-acceptance-evidence.jsonl | 27 + .../live-acceptance-preflight.log | 20 + .../live-expanded-interrupted.log | 0 .../README.md | 34 + .../preset-default-tokens-2026-10-18/api.json | 64 ++ .../build.log | 11 + .../preset-default-tokens-2026-10-18/docs.log | 1 + .../full-unit.log | 180 +++++ .../preset-default-tokens-2026-10-18/lint.log | 31 + .../local-contracts.log | 26 + .../package.log | 1 + .../preset-default-tokens-2026-10-18/unit.log | 10 + .../README.md | 31 + .../api.json | 64 ++ .../api.log | 1 + .../build.log | 11 + .../docs.log | 1 + .../focused.log | 11 + .../full-unit.log | 181 +++++ .../lint.log | 0 .../local-types.log | 0 .../local.log | 26 + .../metadata-comparison.json | 256 +++++++ .../package.log | 1 + .../registry.json | 204 ++++++ .../token-metadata.json | 188 +++++ .../types.log | 0 .../README.md | 38 + .../acceptance.json | 652 ++++++++++++++++++ .../acceptance.log | 10 + .../api.json | 64 ++ .../build.log | 11 + .../docs.log | 1 + .../full-unit.log | 184 +++++ .../lint.log | 0 .../local-types.log | 0 .../local.log | 29 + .../package.log | 1 + .../routes.json | 130 ++++ .../types.log | 0 .../v5-build.log | 11 + .../v5-immutable.log | 26 + .../v5-package.log | 1 + plan/agw/section7-presets.md | 25 +- 48 files changed, 2603 insertions(+), 7 deletions(-) create mode 100644 plan/agw/research/preset-configuration-2026-10-16/live-aave-acceptance.log create mode 100644 plan/agw/research/preset-configuration-2026-10-16/live-acceptance-evidence.jsonl create mode 100644 plan/agw/research/preset-configuration-2026-10-16/live-acceptance-preflight.log create mode 100644 plan/agw/research/preset-configuration-2026-10-16/live-expanded-interrupted.log create mode 100644 plan/agw/research/preset-default-tokens-2026-10-18/README.md create mode 100644 plan/agw/research/preset-default-tokens-2026-10-18/api.json create mode 100644 plan/agw/research/preset-default-tokens-2026-10-18/build.log create mode 100644 plan/agw/research/preset-default-tokens-2026-10-18/docs.log create mode 100644 plan/agw/research/preset-default-tokens-2026-10-18/full-unit.log create mode 100644 plan/agw/research/preset-default-tokens-2026-10-18/lint.log create mode 100644 plan/agw/research/preset-default-tokens-2026-10-18/local-contracts.log create mode 100644 plan/agw/research/preset-default-tokens-2026-10-18/package.log create mode 100644 plan/agw/research/preset-default-tokens-2026-10-18/unit.log create mode 100644 plan/agw/research/preset-permission-policy-2026-10-18/README.md create mode 100644 plan/agw/research/preset-permission-policy-2026-10-18/api.json create mode 100644 plan/agw/research/preset-permission-policy-2026-10-18/api.log create mode 100644 plan/agw/research/preset-permission-policy-2026-10-18/build.log create mode 100644 plan/agw/research/preset-permission-policy-2026-10-18/docs.log create mode 100644 plan/agw/research/preset-permission-policy-2026-10-18/focused.log create mode 100644 plan/agw/research/preset-permission-policy-2026-10-18/full-unit.log create mode 100644 plan/agw/research/preset-permission-policy-2026-10-18/lint.log create mode 100644 plan/agw/research/preset-permission-policy-2026-10-18/local-types.log create mode 100644 plan/agw/research/preset-permission-policy-2026-10-18/local.log create mode 100644 plan/agw/research/preset-permission-policy-2026-10-18/metadata-comparison.json create mode 100644 plan/agw/research/preset-permission-policy-2026-10-18/package.log create mode 100644 plan/agw/research/preset-permission-policy-2026-10-18/registry.json create mode 100644 plan/agw/research/preset-permission-policy-2026-10-18/token-metadata.json create mode 100644 plan/agw/research/preset-permission-policy-2026-10-18/types.log create mode 100644 plan/agw/research/preset-release-readiness-2026-10-18/README.md create mode 100644 plan/agw/research/preset-release-readiness-2026-10-18/acceptance.json create mode 100644 plan/agw/research/preset-release-readiness-2026-10-18/acceptance.log create mode 100644 plan/agw/research/preset-release-readiness-2026-10-18/api.json create mode 100644 plan/agw/research/preset-release-readiness-2026-10-18/build.log create mode 100644 plan/agw/research/preset-release-readiness-2026-10-18/docs.log create mode 100644 plan/agw/research/preset-release-readiness-2026-10-18/full-unit.log create mode 100644 plan/agw/research/preset-release-readiness-2026-10-18/lint.log create mode 100644 plan/agw/research/preset-release-readiness-2026-10-18/local-types.log create mode 100644 plan/agw/research/preset-release-readiness-2026-10-18/local.log create mode 100644 plan/agw/research/preset-release-readiness-2026-10-18/package.log create mode 100644 plan/agw/research/preset-release-readiness-2026-10-18/routes.json create mode 100644 plan/agw/research/preset-release-readiness-2026-10-18/types.log create mode 100644 plan/agw/research/preset-release-readiness-2026-10-18/v5-build.log create mode 100644 plan/agw/research/preset-release-readiness-2026-10-18/v5-immutable.log create mode 100644 plan/agw/research/preset-release-readiness-2026-10-18/v5-package.log diff --git a/plan/agw/implementation-status.md b/plan/agw/implementation-status.md index 551b5768..bddd7318 100644 --- a/plan/agw/implementation-status.md +++ b/plan/agw/implementation-status.md @@ -1,6 +1,12 @@ # AGW SDK implementation status -**October 16 — preset operation limits and UI readiness:** Implemented token/amount pins, underlying-unit redemption, explicit excluded-call metadata and additive get().readiness. Regenerate then rules.update is documented and contract-tested. **2,111 unit tests**, **54 focused tests**, build/typechecks/package checks pass. **Fresh live acceptance is pending:** Aave, BNB and Base setup/receipt waits timed out; some Push receipts later succeeded. Earlier live results do not certify the new limits. [Changes and evidence](research/preset-configuration-2026-10-16/README.md). +**October 18 — alpha release readiness:** automatic token/permission defaults, route-aware readiness and explicit destination-funded grants are committed on v4 `2d16bfe0` / v5 `83f9a713`. Sepolia WETH/stETH mappings and address-word metadata are fixed. **2,142 units**, **21 local contract tests**, **9/9 read-only Donut factory simulations**, package checks and isolated v5 immutable install pass. No funded live run or publication was triggered. [Release evidence and limits](research/preset-release-readiness-2026-10-18/README.md). Earlier same-day entries are intermediate states. + +**October 18 — preset permission defaults:** user-approved explicit preset policy now supplies token caps, 20 PC outbound ceilings and seven-day expiries. An agent alone returns Rule[] and complete configuration; general-rule/explicit-asset zero defaults remain. **2,129 unit tests**, **18 local contract tests**, build/typechecks/package checks pass. Existing PRC20 availability still limits unmodified default-asset grants. [Preset policy evidence](research/preset-permission-policy-2026-10-18/README.md). + +**October 18 — automatic preset tokens:** omitted `assets` now includes curated destination tokens per chain; explicit arrays replace defaults, including `[]`. DEX pairs and lending/staking constraints are generated within v6 size ceilings. This token-only stage is superseded by the preset permission defaults above. **2,119 unit tests**, **18 local v6 contract tests**, build/typechecks/package checks pass. See [evidence](research/preset-default-tokens-2026-10-18/README.md). + +**October 16 — preset operation limits and UI readiness:** Implemented token/amount pins, underlying-unit redemption, explicit excluded-call metadata and additive get().readiness. Regenerate then rules.update is documented and contract-tested. **2,111 unit tests**, **54 focused tests**, build/typechecks/package checks pass. **Fresh live acceptance:** Aave passed; EigenLayer and BNB/Venus completed their scenario assertions. Stopped the expanded process at the user’s request during Base setup, so fresh Base/Moonwell acceptance remains incomplete and there is no expanded-suite pass summary. [Changes and evidence](research/preset-configuration-2026-10-16/README.md). **October 15 — expanded preset live acceptance:** Five additional scenarios passed across focused runs, covering every shipped testnet protocol/chain combination together with the earlier two Sepolia scenarios. Found and fixed AGW explicit ETH token resolution on Base/Arbitrum; no public signature changed. **2,101 unit tests**, **16 local contract tests**, build/typechecks/package checks pass. [Evidence, initial failures and scope limits](research/preset-expanded-live-2026-10-15/README.md). diff --git a/plan/agw/pending-items.md b/plan/agw/pending-items.md index cce1a652..1c4af84d 100644 --- a/plan/agw/pending-items.md +++ b/plan/agw/pending-items.md @@ -1,10 +1,11 @@ # AGW SDK pending items -October 15, 2026. The newly downloaded SDK sections 6/7 supersede the earlier `actions[]` proposal and multiple-rule creation decision. See [the item-by-item feedback list](section6-action-items.md). +October 18, 2026. The newly downloaded SDK sections 6/7 supersede the earlier `actions[]` proposal and multiple-rule creation decision. See [the item-by-item feedback list](section6-action-items.md). | Item | Owner / dependency | Completion condition | | --- | --- | --- | -| New preset-limit live acceptance | SDK / network processing | Updated local policy tests pass; funded Aave/BNB/Base setup waits timed out. Re-run affected scenarios without counting earlier unrestricted catalog results | +| Preset bridge-token coverage | SDK registry / core token routes | SDK readiness/explicit destination-funded flow is complete and 9/9 grant simulations pass. Sepolia WETH/stETH mappings are verified/fixed; other mocks/Circle routes still need real deployments before registry expansion. Selected tokens remain in review metadata; no silent alias or cap removal. | +| New preset-limit live acceptance | SDK / network processing | Aave passed; EigenLayer and BNB/Venus completed all scenario assertions. Fresh Base/Moonwell acceptance remains incomplete: stopped at user request during setup. No tests running | | Destination aggregate spend semantics | Product/contracts | Confirm whether limits must aggregate a batch or destination lifetime activity; current pins are per allowed call and maxTotal is Push-outbound only | | Native 1..32 calls in spec versus deployed maximum 8 | Product/contracts | Align spec or deploy increased ceiling; SDK enforces 8 now | | Additional preset protocols / chains | SDK + protocol prerequisites | Every shipped testnet protocol/chain combination now has a positive live flow. Remaining coverage is borrow/repay, other markets/methods and mainnet; expand excluded protocol rows only after deployment/function/permission checks | @@ -19,3 +20,7 @@ User decisions recorded October 12: multi-action native `spent` uses per-action The first-use EVM gas default is implemented and is no longer an external core/gateway question. `setLabel` already exists on v5; direct invocation requires no contract change. V6 accounting note: generic native MAX pins enforce a per-call bound but do not increment the separate `amountSpent` meter. The SDK returns the actual counter (normally zero for the new public shape), plus value/call counters per action; it does not infer token spending from arbitrary numeric arguments. If the UI needs native per-token spend totals, that requires an explicit accounting design. + +Preset permission defaults are now implemented following the user’s October 18 approval: seven-day expiry, 20 PC per-outbound ceiling, and token-specific positive caps. Explicit asset lists retain zero defaults for omitted caps. This resolves the configuration-policy item; it does not supply missing PRC20 routes, liquidity or destination aggregate accounting. + +Publish readiness: preset configuration, route diagnostics, explicit destination-funded direct creation, package checks and v5 immutable-install checks are complete. See research/preset-release-readiness-2026-10-18/README.md. Remaining destination funding/liquidity/routes are operational prerequisites. Publication is manual; no publish action was run. diff --git a/plan/agw/research/preset-configuration-2026-10-16/README.md b/plan/agw/research/preset-configuration-2026-10-16/README.md index abe516cc..e0dc7921 100644 --- a/plan/agw/research/preset-configuration-2026-10-16/README.md +++ b/plan/agw/research/preset-configuration-2026-10-16/README.md @@ -29,7 +29,7 @@ Operation MAX pins constrain each allowed call. Two calls each at the maximum ca - Actual v6 local policy tests: 18/18 passed, including the final batch-scope assertion (local-contracts.log). Covers zero-cap previews, token changes, lower limits, old-token rejection, checkpoint-count change of five on update and zero Push spent for destination-only actions. Gateway and UEA-origin response metadata are fixtures; AGW/URP/engine execution uses actual local contracts. An unrelated getOriginForUEA response lookup initially reached Donut and timed out; the test fixture now isolates that metadata lookup, matching the existing delayed-index harness pattern. These tests do not prove destination execution. - Build, lib/spec/local typechecks, guide and package/import/declaration checks passed. Source/compiled public API comparison matches. Preset lint has no errors (one test non-null assertion warning). -## Live attempts: not passing acceptance +## Earlier live attempts: not passing acceptance The updated Aave test adds an above-cap refusal, regeneration with a lower cap, refusal of the old amount and two bounded withdrawals in one batch. Market tests now redeem in underlying units and check actual burned shares/payout, allowing residual rounding dust. EigenLayer adds wrong-token and above-cap refusals. @@ -39,7 +39,20 @@ Live attempts timed out before reaching the new operation assertions: | --- | --- | | Aave first | 0xe685f4205cbe59c3acd52a4b4588ae656b7e23127ca68d96ead0b70df2f00578; later read-only Push receipt success at block 24282737 | | Aave retry | 0xc8b66f3c89b869f9b047baaf52cccf65e9ee176a368b1889ded77b3a5d816b93; Push receipt success at block 24286115; test timed out during destination wait | -| BNB market setup | 0x52732156d51caf9d3d1aa08fd4397be09508553cc4119fc218b92f50eee126e3; receipt wait timed out; subsequent lookup HTTP failed, final state not confirmed | +| BNB market setup | 0x52732156d51caf9d3d1aa08fd4397be09508553cc4119fc218b92f50eee126e3; receipt wait timed out; October 16 read-only recheck confirms Push receipt success at block 24289830 | | Base market setup | 0x72d53c5d0faad5a16eec8f1a1f413757d425ec4237488551b5d2f2436d4e60b2; receipt wait timed out; later Push receipt success at block 24290217 | -Do not treat these as contract-policy reverts or live passes. Prior successful catalog flows predate these restrictions. Re-run the affected live scenarios once receipt/destination processing is reliable. No further funded retries are running. +Do not treat these as contract-policy reverts or live passes. Prior successful catalog flows predate these restrictions. Fresh acceptance results are recorded below; the earlier timeouts remain preserved as historical evidence. + +## Fresh live acceptance — October 16 + +Deployment preflight verified v6 wiring on-chain and sufficient testnet funds. SDK source tested: `89d04386` (documentation HEAD `b115b66c`). No production code changes were needed. + +- Aave Sepolia: **passed** (284 seconds). Above-cap supply rejected; permitted supply credited to the CEA; rule regenerated with half the cap; old amount rejected; two withdrawals each at the new cap succeeded, with destination events and balances verified. See [Jest log](live-aave-acceptance.log). +- EigenLayer Sepolia: completed all scenario assertions, including wrong-token/above-cap rejection and deposit shares credited to the CEA. +- BNB PancakeSwap/Venus: completed all scenario assertions, including swap, mint and underlying-unit redemption. Deposited 3,361 raw units, redeemed 3,360, with rounding dust retained. +- Base Aave/Moonwell: stopped at the user’s request after faucet submission, before new operation checks. Transaction `0x05493d40928a9bf8d439502cb60aa09b000c42a661320d60e15546709bf7f4aa` may finish independently; not replayed. + +The expanded Jest process was terminated (exit 143) during Base setup, so there is no successful whole-suite summary. EigenLayer and BNB completion is supported by their terminal evidence entries, emitted after their assertions, and progression to the next scenario. No test process remains running. Base fresh acceptance remains incomplete; no production code was changed or package published. + +Transaction evidence: [fresh live records](live-acceptance-evidence.jsonl). These scenarios exercise generated destination constraints with prefunded CEAs; they do not establish aggregate destination turnover limits or mainnet acceptance. diff --git a/plan/agw/research/preset-configuration-2026-10-16/live-aave-acceptance.log b/plan/agw/research/preset-configuration-2026-10-16/live-aave-acceptance.log new file mode 100644 index 00000000..32ec1bf3 --- /dev/null +++ b/plan/agw/research/preset-configuration-2026-10-16/live-aave-acceptance.log @@ -0,0 +1,11 @@ +PASS core-e2e __e2e__/agw/presets-live.spec.ts (284.596 s) + agw presets live + ✓ 2. Aave preset supplies and withdraws the wallet position (283628 ms) + ○ skipped 1. Uniswap preset swaps from the wallet CEA and rejects a different recipient + +Test Suites: 1 passed, 1 total +Tests: 1 skipped, 1 passed, 2 total +Snapshots: 0 total +Time: 284.63 s, estimated 1848 s +Ran all test suites within paths "__e2e__/agw/presets-live.spec.ts". +Force exiting Jest: Have you considered using `--detectOpenHandles` to detect async operations that kept running after all tests finished? diff --git a/plan/agw/research/preset-configuration-2026-10-16/live-acceptance-evidence.jsonl b/plan/agw/research/preset-configuration-2026-10-16/live-acceptance-evidence.jsonl new file mode 100644 index 00000000..858dd39b --- /dev/null +++ b/plan/agw/research/preset-configuration-2026-10-16/live-acceptance-evidence.jsonl @@ -0,0 +1,27 @@ +{"name":"preset-aave-stage","at":"2026-10-16T14:19:29.947Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","stage":"mint-submitted","wallet":"0x77a26E59980935e0d7aA125b5d2c95A67F194BCA","cea":"0x864f30c67Ec4703eA9572E3DCCac94d56F82Cbf0","pushTx":"0x8eaf713fb6035522f3fb410e65b20de7dfc90c72359e557835c707250e0c35a5"} +{"name":"preset-aave-stage","at":"2026-10-16T14:20:32.352Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","stage":"mint-completed","wallet":"0x77a26E59980935e0d7aA125b5d2c95A67F194BCA","cea":"0x864f30c67Ec4703eA9572E3DCCac94d56F82Cbf0","externalTx":"0x85ac4ebda4fff38c72a24b6b11ea3698ec9769b223de04e1a5c497ebc56ca00a"} +{"name":"preset-aave-stage","at":"2026-10-16T14:20:46.731Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","stage":"supply-submitted","wallet":"0x77a26E59980935e0d7aA125b5d2c95A67F194BCA","cea":"0x864f30c67Ec4703eA9572E3DCCac94d56F82Cbf0","pushTx":"0x35b8b0eb26f333815e5d34b54cc79dfe71e504c308d8c37edffe69f087555e1d"} +{"name":"preset-aave-stage","at":"2026-10-16T14:21:52.318Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","stage":"supply-completed","wallet":"0x77a26E59980935e0d7aA125b5d2c95A67F194BCA","cea":"0x864f30c67Ec4703eA9572E3DCCac94d56F82Cbf0","externalTx":"0xcfaed8a9efd2ced9d288fb9cbe1d2ad62682870ec277b38e75b18a8cd178ad34"} +{"name":"preset-aave-stage","at":"2026-10-16T14:22:15.800Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","stage":"withdraw-submitted","wallet":"0x77a26E59980935e0d7aA125b5d2c95A67F194BCA","cea":"0x864f30c67Ec4703eA9572E3DCCac94d56F82Cbf0","pushTx":"0x072354349499d529a3564850f6a433bdf32b2685d9dc07e71fa654d779243de3"} +{"name":"preset-expanded-wallet","at":"2026-10-16T14:23:19.346Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","label":"e2e-preset-eigen","chain":"eip155:11155111","wallet":"0xde073E54372C7e0b9E65CC6f99959cE8B0678C6D","cea":"0xD80552eF6A5F2Fa8B4C44D921b343B96d248770e","rulesId":"0xab32de551d4de0e7d6ca0622e9027c6db8f0e628fd2ba03204fa97c5afd613aa"} +{"name":"preset-expanded-stage","at":"2026-10-16T14:23:32.799Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","chain":"eip155:11155111","wallet":"0xde073E54372C7e0b9E65CC6f99959cE8B0678C6D","cea":"0xD80552eF6A5F2Fa8B4C44D921b343B96d248770e","stage":"wrap-submitted","pushTx":"0xca71ebc2a372d1e634c9979042a4bab44881d0f7ef0e3c9d365bd8b4e1147e6f"} +{"name":"preset-aave-stage","at":"2026-10-16T14:23:33.837Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","stage":"withdraw-completed","wallet":"0x77a26E59980935e0d7aA125b5d2c95A67F194BCA","cea":"0x864f30c67Ec4703eA9572E3DCCac94d56F82Cbf0","externalTx":"0x3ec1e27c54d53fdfc0a4bc25f639afa1c20ec050362abb34ede761ce2823fcc8"} +{"name":"preset-limits-regeneration-live","at":"2026-10-16T14:23:34.365Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0x77a26E59980935e0d7aA125b5d2c95A67F194BCA","cea":"0x864f30c67Ec4703eA9572E3DCCac94d56F82Cbf0","oldRulesId":"0x7cfaf096659a570c6f0cb6e837a67fd0afdab36d29a918d34ff422020e4d5662","newRulesId":"0xf78b3459933612f022e11da960904f54af986259b5cff524594d5cd2ee311df1","oldCap":"1000000000000","newCap":"500000000000","rejectedAboveCap":true,"destinationTx":"0x3ec1e27c54d53fdfc0a4bc25f639afa1c20ec050362abb34ede761ce2823fcc8"} +{"name":"preset-aave-live","at":"2026-10-16T14:23:34.365Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0x77a26E59980935e0d7aA125b5d2c95A67F194BCA","cea":"0x864f30c67Ec4703eA9572E3DCCac94d56F82Cbf0","rulesId":"0x7cfaf096659a570c6f0cb6e837a67fd0afdab36d29a918d34ff422020e4d5662","mockLINK":"0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5","pool":"0x6Ae43d3271ff6888e7Fc43Fd7321a503ff738951","mintTx":"0x8eaf713fb6035522f3fb410e65b20de7dfc90c72359e557835c707250e0c35a5","mintExternal":"0x85ac4ebda4fff38c72a24b6b11ea3698ec9769b223de04e1a5c497ebc56ca00a","supplyTx":"0x35b8b0eb26f333815e5d34b54cc79dfe71e504c308d8c37edffe69f087555e1d","supplyExternal":"0xcfaed8a9efd2ced9d288fb9cbe1d2ad62682870ec277b38e75b18a8cd178ad34","withdrawTx":"0x072354349499d529a3564850f6a433bdf32b2685d9dc07e71fa654d779243de3","withdrawExternal":"0x3ec1e27c54d53fdfc0a4bc25f639afa1c20ec050362abb34ede761ce2823fcc8","amount":"1000000000000"} +{"name":"preset-expanded-stage","at":"2026-10-16T14:24:43.675Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","chain":"eip155:11155111","wallet":"0xde073E54372C7e0b9E65CC6f99959cE8B0678C6D","cea":"0xD80552eF6A5F2Fa8B4C44D921b343B96d248770e","stage":"wrap-completed","pushTx":"0xca71ebc2a372d1e634c9979042a4bab44881d0f7ef0e3c9d365bd8b4e1147e6f","externalTx":"0xc20682c90056f8b2fc0486391664f8771bbbbe95dc6ba42b08dc0ff8a797000e","status":"success"} +{"name":"preset-expanded-stage","at":"2026-10-16T14:25:01.023Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","chain":"eip155:11155111","wallet":"0xde073E54372C7e0b9E65CC6f99959cE8B0678C6D","cea":"0xD80552eF6A5F2Fa8B4C44D921b343B96d248770e","stage":"eigen-deposit-submitted","pushTx":"0x753ad504b341d979bdbffae6aad539a301a58c038effbe6de664c59cff1211f0"} +{"name":"preset-expanded-stage","at":"2026-10-16T14:27:07.926Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","chain":"eip155:11155111","wallet":"0xde073E54372C7e0b9E65CC6f99959cE8B0678C6D","cea":"0xD80552eF6A5F2Fa8B4C44D921b343B96d248770e","stage":"eigen-deposit-completed","pushTx":"0x753ad504b341d979bdbffae6aad539a301a58c038effbe6de664c59cff1211f0","externalTx":"0xb8b74452c5169161186963e4697f4a2dea21573f4c375f9a66bf59e4bfe38398","status":"success"} +{"name":"preset-eigen-live","at":"2026-10-16T14:27:08.298Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","wallet":"0xde073E54372C7e0b9E65CC6f99959cE8B0678C6D","cea":"0xD80552eF6A5F2Fa8B4C44D921b343B96d248770e","strategy":"0x424246eF71b01ee33aA33aC590fd9a0855F5eFbc","amount":"1000000000000","shares":"1000000000000"} +{"name":"preset-expanded-wallet","at":"2026-10-16T14:27:45.140Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","label":"e2e-preset-dex-eip155:97","chain":"eip155:97","wallet":"0xbaE2f41FD9DA5cF91C0D63Ef2198858d77ca30E1","cea":"0xfE553E8Ad0A3b06Ed740Db50EEb593C0DF046867","rulesId":"0x9eb3a91361cedd52664ce400263c479525ad22214338d38b0cf1437e77a02934"} +{"name":"preset-expanded-stage","at":"2026-10-16T14:27:57.182Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","chain":"eip155:97","wallet":"0xbaE2f41FD9DA5cF91C0D63Ef2198858d77ca30E1","cea":"0xfE553E8Ad0A3b06Ed740Db50EEb593C0DF046867","stage":"wrap-submitted","pushTx":"0xa744e0814cf77da4051969fe6ba2bf2e4714dd806ae1e0c4065cd06e19bb7138"} +{"name":"preset-expanded-stage","at":"2026-10-16T14:28:56.306Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","chain":"eip155:97","wallet":"0xbaE2f41FD9DA5cF91C0D63Ef2198858d77ca30E1","cea":"0xfE553E8Ad0A3b06Ed740Db50EEb593C0DF046867","stage":"wrap-completed","pushTx":"0xa744e0814cf77da4051969fe6ba2bf2e4714dd806ae1e0c4065cd06e19bb7138","externalTx":"0xc2c74937dbb615b443dd31a29a9d9602b07dfaf1661df8dd290e72cb3a86744d","status":"success"} +{"name":"preset-expanded-stage","at":"2026-10-16T14:29:16.568Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","chain":"eip155:97","wallet":"0xbaE2f41FD9DA5cF91C0D63Ef2198858d77ca30E1","cea":"0xfE553E8Ad0A3b06Ed740Db50EEb593C0DF046867","stage":"dex-swap-submitted","pushTx":"0xa9c678dd1cd4dda0451582626929cd1365b9086a9edf064729033762f7682c3f"} +{"name":"preset-expanded-stage","at":"2026-10-16T14:30:09.124Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","chain":"eip155:97","wallet":"0xbaE2f41FD9DA5cF91C0D63Ef2198858d77ca30E1","cea":"0xfE553E8Ad0A3b06Ed740Db50EEb593C0DF046867","stage":"dex-swap-completed","pushTx":"0xa9c678dd1cd4dda0451582626929cd1365b9086a9edf064729033762f7682c3f","externalTx":"0x464047db3e50c6a916b01f515bc1dede09d3f7b596296ef66c51ac93144c66a6","status":"success"} +{"name":"preset-expanded-dex","at":"2026-10-16T14:30:09.473Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","chain":"eip155:97","wallet":"0xbaE2f41FD9DA5cF91C0D63Ef2198858d77ca30E1","cea":"0xfE553E8Ad0A3b06Ed740Db50EEb593C0DF046867","pool":"0xCed0844e421F856D2de472F9e7037f873987887C","router":"0x9a489505a00cE272eAa5e07Dba6491314CaE3796","amountIn":"1000000000000","amountOut":"3361"} +{"name":"preset-expanded-stage","at":"2026-10-16T14:30:32.580Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","chain":"eip155:97","wallet":"0xbaE2f41FD9DA5cF91C0D63Ef2198858d77ca30E1","cea":"0xfE553E8Ad0A3b06Ed740Db50EEb593C0DF046867","stage":"venus-mint-submitted","pushTx":"0xb517c1bbcdddb1f62c8c3d944a8bfa86f0a50019d66a2a99bec3f542ab0a8381"} +{"name":"preset-expanded-stage","at":"2026-10-16T14:31:22.531Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","chain":"eip155:97","wallet":"0xbaE2f41FD9DA5cF91C0D63Ef2198858d77ca30E1","cea":"0xfE553E8Ad0A3b06Ed740Db50EEb593C0DF046867","stage":"venus-mint-completed","pushTx":"0xb517c1bbcdddb1f62c8c3d944a8bfa86f0a50019d66a2a99bec3f542ab0a8381","externalTx":"0x9c00687978e2949d665536b59d821e98bbbbe2faae593e4384bec640586faff3","status":"success"} +{"name":"preset-expanded-stage","at":"2026-10-16T14:31:31.590Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","chain":"eip155:97","wallet":"0xbaE2f41FD9DA5cF91C0D63Ef2198858d77ca30E1","cea":"0xfE553E8Ad0A3b06Ed740Db50EEb593C0DF046867","stage":"venus-redeem-submitted","pushTx":"0x11b96746f5bbc71d97405b40cbe1e0f26dc14032c6745b02f994e21dab9d4698"} +{"name":"preset-expanded-stage","at":"2026-10-16T14:32:30.289Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","chain":"eip155:97","wallet":"0xbaE2f41FD9DA5cF91C0D63Ef2198858d77ca30E1","cea":"0xfE553E8Ad0A3b06Ed740Db50EEb593C0DF046867","stage":"venus-redeem-completed","pushTx":"0x11b96746f5bbc71d97405b40cbe1e0f26dc14032c6745b02f994e21dab9d4698","externalTx":"0x5540aa0b27c3882deccd2ad854a305d4afaaa11fcbd7c51a6f2ed0e0df193cb2","status":"success"} +{"name":"preset-expanded-venus","at":"2026-10-16T14:32:30.648Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","chain":"eip155:97","wallet":"0xbaE2f41FD9DA5cF91C0D63Ef2198858d77ca30E1","cea":"0xfE553E8Ad0A3b06Ed740Db50EEb593C0DF046867","deposited":"3361","redeemed":"3360","shares":"16740010","remainingShares":"4981","asset":"0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c"} +{"name":"preset-expanded-wallet","at":"2026-10-16T14:33:05.795Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","label":"e2e-preset-base-lending","chain":"eip155:84532","wallet":"0x10975626FC9757C9D423c34E0280e501b5595f6a","cea":"0xB7FaD9Fc61504C148F8852b87a48d18Ced0906e6","rulesId":"0x37a36763f71f21aa9de1a3575795d336d5916beb34dbad21e97ffc664a75ce89"} +{"name":"preset-expanded-stage","at":"2026-10-16T14:33:11.131Z","network":"TESTNET_DONUT","sourceCommit":"ffd567d3e49b2d27c6f50ad36093274dbac3090f","chain":"eip155:84532","wallet":"0x10975626FC9757C9D423c34E0280e501b5595f6a","cea":"0xB7FaD9Fc61504C148F8852b87a48d18Ced0906e6","stage":"faucets-submitted","pushTx":"0x05493d40928a9bf8d439502cb60aa09b000c42a661320d60e15546709bf7f4aa"} diff --git a/plan/agw/research/preset-configuration-2026-10-16/live-acceptance-preflight.log b/plan/agw/research/preset-configuration-2026-10-16/live-acceptance-preflight.log new file mode 100644 index 00000000..73068dd6 --- /dev/null +++ b/plan/agw/research/preset-configuration-2026-10-16/live-acceptance-preflight.log @@ -0,0 +1,20 @@ +AGW deployment manifest verified on-chain. + +Wallets + EVM master (Sepolia) 0x0A16CBa65FfCAa4C2282b27b027Ab4A2fE46E0Bf + Push master (Donut) 0x0A16CBa65FfCAa4C2282b27b027Ab4A2fE46E0Bf + Solana master (Devnet) 3nK8X1re4zLNrgz9Y3xKS4g2fKPJ6M3N9BhNuFfkjwAb + Shared UEA (Donut) 0x5C70C864Cf1aDfB04A0e107fFA248ba3600EAb8D + UEA CEA PDA (Devnet) Fqp8UeJxEWvN1Ciu5jqrA3opGXwNvRL2HfJxNQotj3Qh + +Group "agw-presets-expanded" — 5 scenarios, headroom ×1.25. + +┌─────────────────────┬───────┬──────────┬─────────────┬────────┐ +│ Scope │ Asset │ Need │ Have │ Status │ +├─────────────────────┼───────┼──────────┼─────────────┼────────┤ +│ Push master (Donut) │ PC │ 689.5000 │ 967918.1059 │ ✓ │ +│ Push master (Donut) │ pETH │ 0.000001 │ 434.3115 │ ✓ │ +└─────────────────────┴───────┴──────────┴─────────────┴────────┘ + +All master wallets can cover this run. +Derived accounts are already at target. Ready to run. diff --git a/plan/agw/research/preset-configuration-2026-10-16/live-expanded-interrupted.log b/plan/agw/research/preset-configuration-2026-10-16/live-expanded-interrupted.log new file mode 100644 index 00000000..e69de29b diff --git a/plan/agw/research/preset-default-tokens-2026-10-18/README.md b/plan/agw/research/preset-default-tokens-2026-10-18/README.md new file mode 100644 index 00000000..eaf783ba --- /dev/null +++ b/plan/agw/research/preset-default-tokens-2026-10-18/README.md @@ -0,0 +1,34 @@ +# Automatic preset tokens — October 18, 2026 + +> Intermediate stage. Final funding behavior, commits and release checks are recorded in [release readiness](../preset-release-readiness-2026-10-18/README.md). + +Riyanshu clarified that presets must provide token selections per network. SDK-only changes are local on feat/agw-sdk-v4; nothing is committed, pushed or published by this change. + +## Behavior + +- Omitted assets includes curated destination tokens per chain for DEXES, LENDING and STAKING. PREDICTION remains empty. +- DEX includes the complete pair, both directions, exact-input/output constraints and spender-pinned approvals. +- Lending defaults are protocol-specific, including testnet reserve/mock addresses rather than unrelated DEX tokens. +- Every default expansion stays within 8 assets, 32 calls and 32 pins. Base/BNB mainnet lending uses a shared market/reserve token to fit; other markets remain selectable explicitly. The complete Aave reserve list is not selected automatically. +- Explicit assets replaces defaults across all returned chains, including [] or a list limited to one chain. No tokens are appended to explicit selections. +- Returned defaults and metadata cannot mutate subsequent results. +- KnownTokens includes the default subset, including DEX pairs. + +Source selection reuses the reviewed October 15 catalog, Aave reserve snapshots and live protocol fixtures. See default-tokens.ts and the network/token table in packages/core/AGW.md. No new address freshness/liquidity guarantee is made. + +## Remaining permission-policy decision + +Tokens are now preselected, but caps retain the existing zero default. No spending, PC gas budget or expiry is invented. These templates are disabled until a permission policy is applied via get with capped assets. UI can use the SDK-provided selections without asking users to choose tokens per chain; fully automatic execution still needs approved positive caps, a gas budget and expiry. + +Suggested 10 USDC per call, 100 USDC cumulative Push-outbound and 7-day expiry are proposals only. Per-token values/decimals and chain-specific gas budgets need agreement. These numbers are not implemented and are not equivalent to a destination lifetime/batch cap. + +## Verification + +- 62 focused preset tests pass. +- Full unit suite: 2,119 passed, 12 skipped, no failures. +- Local pinned v6 AGW/URP/engine suite: 18 passed. Default DEX token constraints reject positive input under zero MAX even if bridge asset budgets are edited; explicit empty-list preview/regeneration remains covered. +- Build, spec/local typechecks, 6 guide TypeScript blocks and package CJS/ESM/declaration/import checks pass. +- Source/compiled API comparison matches. Lint has no errors; test non-null assertion warnings remain. +- Existing live Sepolia DEX/Aave scenarios now check the default token lists; Aave regenerates its executable rule from returned tokens. They were typechecked, not broadcast again. + +The first local invocation failed setup because its previous temporary build directory had been removed. Rebuilt the pinned ffd567d contracts in /tmp/agw-preset-defaults-v6 using the existing prepare script; the actual local suite then passed. No contract checkout was modified and no live E2E was started. diff --git a/plan/agw/research/preset-default-tokens-2026-10-18/api.json b/plan/agw/research/preset-default-tokens-2026-10-18/api.json new file mode 100644 index 00000000..97ae2de9 --- /dev/null +++ b/plan/agw/research/preset-default-tokens-2026-10-18/api.json @@ -0,0 +1,64 @@ +{ + "baseline": "b1597b91a25dbf7f691f589b4e1e154add604315", + "head": "b115b66c6888cde5ff4b6a09e6c4b224a8874729", + "compiledMatchesSource": true, + "initializeSignatureChanged": false, + "addedExports": [ + "AgenticPresets", + "ArgumentPath", + "DecodedSolanaRule", + "Pin", + "Preset", + "PresetAsset", + "PresetCallIssue", + "PresetCategory", + "PresetChainReadiness", + "PresetConfigurationIssue", + "PresetOptions", + "PresetResult", + "PresetRuleTemplate", + "ReadyPresetOptions", + "RuleInput", + "Spent", + "WalletMarker" + ], + "removedExports": [ + "AgenticNetworkConstants", + "NativeRule", + "UniversalRule" + ], + "publicTypeChanges": [ + "AGENTIC_ERROR_CODE", + "AgenticError", + "AgenticRevertError", + "AgenticErrorCode", + "AgenticTxMetadata", + "AgenticWallet", + "AllowedCall", + "AssetCap", + "CreateOptions", + "DecodedSolanaRule", + "Rule", + "RuleInput", + "Pin", + "Spent", + "WalletMarker", + "ArgumentPath", + "RulesRecord", + "Preset", + "PresetCategory", + "PresetAsset", + "PresetOptions", + "ReadyPresetOptions", + "PresetRuleTemplate", + "PresetResult", + "PresetChainReadiness", + "PresetConfigurationIssue", + "PresetCallIssue", + "AgenticPresets" + ], + "transactionMethodChanges": [], + "instanceMethodChanges": [], + "agwConstantsChanged": true, + "scope": "Summary of check-agw-api.js output; redundant full source/declaration snapshots omitted." +} diff --git a/plan/agw/research/preset-default-tokens-2026-10-18/build.log b/plan/agw/research/preset-default-tokens-2026-10-18/build.log new file mode 100644 index 00000000..12fa4134 --- /dev/null +++ b/plan/agw/research/preset-default-tokens-2026-10-18/build.log @@ -0,0 +1,11 @@ + +> nx run core:build + +Compiling TypeScript files for project "core"... +Done compiling TypeScript files for project "core". +(node:20842) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. +(Use `node --trace-warnings ...` to show where the warning was created) + + + + NX Successfully ran target build for project core diff --git a/plan/agw/research/preset-default-tokens-2026-10-18/docs.log b/plan/agw/research/preset-default-tokens-2026-10-18/docs.log new file mode 100644 index 00000000..2755478b --- /dev/null +++ b/plan/agw/research/preset-default-tokens-2026-10-18/docs.log @@ -0,0 +1 @@ +AGW guide: 6 TypeScript blocks typechecked against public exports; no examples executed. diff --git a/plan/agw/research/preset-default-tokens-2026-10-18/full-unit.log b/plan/agw/research/preset-default-tokens-2026-10-18/full-unit.log new file mode 100644 index 00000000..e9e41eb0 --- /dev/null +++ b/plan/agw/research/preset-default-tokens-2026-10-18/full-unit.log @@ -0,0 +1,180 @@ +PASS core packages/core/src/lib/utils.spec.ts (6.711 s) + ● Console + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:973:17) + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:977:17) + + console.log + 1.23 + + at Object. (src/lib/utils.spec.ts:982:17) + +PASS core packages/core/src/lib/orchestrator/__tests__/signing-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-gas.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-tracker.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-composition.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/rescue-svm-confirmation.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/payload-builders.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/context-helpers-tracker.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gateway-uea-account.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/send.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/management.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/reads-context.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-executor.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-detector.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-error-classification.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/resolver.spec.ts +PASS core packages/core/src/lib/universal/signer/signer.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-usd-sizer.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/codec.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/cascade.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-builder-progress-hook.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r3-spec-strings.spec.ts +PASS core packages/core/src/lib/constants/__tests__/token-constants.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/spec-builder.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/svm-account.spec.ts +PASS core packages/core/src/lib/universal/account/account.spec.ts + ● Console + + console.warn + [PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead. + + 207 | ): Promise { + 208 | if (!_convertOriginToExecutorWarned) { + > 209 | console.warn( + | ^ + 210 | '[PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead.' + 211 | ); + 212 | _convertOriginToExecutorWarned = true; + + at Object.convertOriginToExecutor (src/lib/universal/account/account.ts:209:13) + at Object. (src/lib/universal/account/account.spec.ts:80:52) + + console.warn + [PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead. + + 425 | ): Promise { + 426 | if (!options?._internal && !_convertExecutorToOriginWarned) { + > 427 | console.warn( + | ^ + 428 | '[PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead.' + 429 | ); + 430 | _convertExecutorToOriginWarned = true; + + at convertExecutorToOrigin (src/lib/universal/account/account.ts:427:13) + at Object. (src/lib/universal/account/account.spec.ts:106:38) + +PASS core packages/core/src/lib/read-state/__tests__/read-types.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/native-multi-action.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-multichain.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/response-invariant.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/svm-rent.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-native-multicall.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-backend.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-emission.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-svm-r3.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-tx-retry.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-confirmation-gate.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/classify.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/account-status.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r1-spec-strings.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/normalize.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/send-transaction-progress-hook.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/inbound-tracker-derivation.spec.ts +PASS core packages/core/src/lib/push-client/push-client.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-event-hook-bridge.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-quote.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/terminal-suppression.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-svm-rent.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-classification.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/response-surface.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/public-rule.spec.ts +PASS core packages/core/src/lib/push-client/push-client.archive-fallback.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/export.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r2-spec-strings.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/ucallback-codec.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r2-outbound-revert-flow.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/read-tx-spec-strings.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/registry.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-params.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/child-inbounds.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.dynamic-gas.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-evm.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/__tests__/signing.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/gate.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/validate.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/revalidate-read.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-events.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/error-decoder.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/scenarios.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-idl.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-error-classification.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/result-decoder.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/auto-detect.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/build-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-calculator.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/labels.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-web2.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.chain-symbol.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg-svm.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/inbound-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/funds-only-burn-guard.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-svm-confirmation.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-wire-fixture.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/errors.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm-log-index.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/resolve.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-request-recipient.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-svm.spec.ts +PASS core packages/core/src/lib/formatters.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/multichain-hooks.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/source-hash-resolution.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-evm-r3-native-eoa.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-execute-order.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/response-builder-push-revert.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/address-codec.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/abi-selectors.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/web2-compat.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/chain-namespace.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-timeout-clamp.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.batch-gas.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/public-surface.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/block-results-client.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/max-pc-for-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm-rent-pc20.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/tracking.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/ix-encoder.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/normalize-address.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/runtime-token-chain.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/track-transaction-guard.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/registry.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/budget.spec.ts +PASS core packages/core/src/lib/constants/__tests__/svm-gateway-idl.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/execute-standard-required-funds.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/preset-catalog.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/presets.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/preset-operation-limits.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/preset-default-tokens.spec.ts + +Test Suites: 1 skipped, 127 passed, 127 of 128 total +Tests: 12 skipped, 2119 passed, 2131 total +Snapshots: 0 total +Time: 54.207 s +Ran all test suites. diff --git a/plan/agw/research/preset-default-tokens-2026-10-18/lint.log b/plan/agw/research/preset-default-tokens-2026-10-18/lint.log new file mode 100644 index 00000000..6b99786c --- /dev/null +++ b/plan/agw/research/preset-default-tokens-2026-10-18/lint.log @@ -0,0 +1,31 @@ + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/preset-catalog.spec.ts + 46:19 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 54:9 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 114:20 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 189:4 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 191:5 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 198:5 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 205:7 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 234:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 236:32 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 247:13 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/preset-default-tokens.spec.ts + 19:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 20:14 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 26:9 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 48:10 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 51:10 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 56:5 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 85:5 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 90:5 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 100:13 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 112:10 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 137:3 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + 138:3 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/preset-operation-limits.spec.ts + 159:19 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion + +✖ 23 problems (0 errors, 23 warnings) diff --git a/plan/agw/research/preset-default-tokens-2026-10-18/local-contracts.log b/plan/agw/research/preset-default-tokens-2026-10-18/local-contracts.log new file mode 100644 index 00000000..6bfa7232 --- /dev/null +++ b/plan/agw/research/preset-default-tokens-2026-10-18/local-contracts.log @@ -0,0 +1,26 @@ +PASS core-agw-local packages/core/__agw-local__/v5-multiasset.spec.ts + v6 multi-asset SDK management and execution + ✓ v6 EVM alternatives enforce both spender and MAX, and reads update losslessly (105 ms) + ✓ v6 refuses a bare alternative that bypasses a pinned function and too many initial rules (20 ms) + ✓ the shipped DEX catalog enforces tuple receiver/token/amount pins on actual v6 URP (94 ms) + ✓ a default-token DEX exactInputSingle call cannot spend tokens even after asset budgets are filled (41 ms) + ✓ a default-token DEX exactOutputSingle call cannot spend tokens even after asset budgets are filled (42 ms) + ✓ regenerated LENDING presets enforce new token/amount pins through atomic rules.update (112 ms) + ✓ regenerated STAKING presets enforce new token/amount pins through atomic rules.update (119 ms) + ✓ a fixture preset produces rules accepted by public create and enforced by real contracts (42 ms) + ✓ public create encodes two ordered assets; public get reconstructs source-token caps (35 ms) + ✓ a token from the wrong chain fails before deployment (8 ms) + ✓ a same-chain registry identity mismatch fails before deployment (2 ms) + ✓ both tokens execute under one rule and keep independent counters/limits (125 ms) + ✓ omitted and explicit zero totals both prohibit movement (63 ms) + ✓ empty user assets grants one zero-cap gas token and executes a call-only request (118 ms) + ✓ public update resets both counters in one batch and records five checkpoints (153 ms) + ✓ spend on the second asset after snapshot rolls back revoke/grant and checkpoint writes (198 ms) + ✓ out-of-band duplicate contract grants still make sends ambiguous (75 ms) + ✓ a legacy two-field envelope is refused by the actual v6 grant path (34 ms) + +Test Suites: 1 passed, 1 total +Tests: 18 passed, 18 total +Snapshots: 0 total +Time: 3.614 s, estimated 8 s +Ran all test suites within paths "packages/core/__agw-local__/v5-multiasset.spec.ts". diff --git a/plan/agw/research/preset-default-tokens-2026-10-18/package.log b/plan/agw/research/preset-default-tokens-2026-10-18/package.log new file mode 100644 index 00000000..8e1b97e4 --- /dev/null +++ b/plan/agw/research/preset-default-tokens-2026-10-18/package.log @@ -0,0 +1 @@ +AGW package: CJS/ESM imports, compiled declaration examples and npm contents pass. No examples executed/published. diff --git a/plan/agw/research/preset-default-tokens-2026-10-18/unit.log b/plan/agw/research/preset-default-tokens-2026-10-18/unit.log new file mode 100644 index 00000000..903e76ef --- /dev/null +++ b/plan/agw/research/preset-default-tokens-2026-10-18/unit.log @@ -0,0 +1,10 @@ +PASS core packages/core/src/lib/agentic/__tests__/preset-catalog.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/presets.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/preset-operation-limits.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/preset-default-tokens.spec.ts + +Test Suites: 4 passed, 4 total +Tests: 62 passed, 62 total +Snapshots: 0 total +Time: 3.566 s +Ran all test suites within paths "packages/core/src/lib/agentic/__tests__/presets.spec.ts", "packages/core/src/lib/agentic/__tests__/preset-catalog.spec.ts", "packages/core/src/lib/agentic/__tests__/preset-operation-limits.spec.ts", "packages/core/src/lib/agentic/__tests__/preset-default-tokens.spec.ts". diff --git a/plan/agw/research/preset-permission-policy-2026-10-18/README.md b/plan/agw/research/preset-permission-policy-2026-10-18/README.md new file mode 100644 index 00000000..224491be --- /dev/null +++ b/plan/agw/research/preset-permission-policy-2026-10-18/README.md @@ -0,0 +1,31 @@ +# Preset permission defaults — October 18, 2026 + +> Intermediate stage. Final funding behavior, commits and release checks are recorded in [release readiness](../preset-release-readiness-2026-10-18/README.md). + +User authorization: after confirming the SDK can supply spending caps, gas ceilings and expiry centrally, the user requested implementation. This supersedes the earlier pending-policy notes. Changes remain local on feat/agw-sdk-v4; no commit, push, package publication or live transaction is part of this task. + +## Delivered policy + +Omitted assets selects the curated tokens and explicit caps: stablecoins 10 per call / 100 cumulative Push outbound; ETH/WETH/stETH/wstETH 0.001 / 0.01; WBNB 0.01 / 0.1; LINK 1 / 10. Values are fixed token quantities, not USD equivalents. Every token is matched by chain and address; no symbol-based or unknown-token inference runs in production. + +Omitted validUntil becomes seven days from the current get call, computed once for all returned rules. Omitted maxGasPerCall uses an explicit chain profile, currently 20 PC for the eight catalog EVM chains. This is an URP value ceiling, not an actual fee or guaranteed sufficient quote. Testnet protocol flows previously used this ceiling; mainnet policy templates have no funded execution acceptance. Each send still obtains a fresh quote and is subject to contract policy and wallet funds. + +An agent alone now narrows the get result to Rule[]. The existing editable-template type remains compatible. The get API stays synchronous and performs no token metadata, price or quote fetch. Missing identity remains an actionable readiness issue. PREDICTION remains empty and no Solana preset is introduced. + +Explicit assets replaces all selected-chain defaults. Omitted caps inside explicit assets still mean zero. Explicit gas zero stays zero, and explicit expiry is validated/preserved. These defaults do not alter ordinary rules, produce unlimited allowances, aggregate destination batches or meter destination lifetime spend. A new default token without a reviewed budget fails instead of receiving a guessed policy. + +## Evidence + +- Read-only RPC metadata checks covered 25 unique chain/token pairs across eight networks. Network, block and symbol/decimals are in token-metadata.json. No account/credential access was needed. +- Compiled policy compared against all 25 RPC metadata entries: metadata-comparison.json. BNB mainnet USDT uses 18 decimals; BSC testnet USDT uses 6. +- Focused preset tests: 72 passed. +- Full units: 2,129 passed, 12 skipped, no failures. +- Actual pinned v6 local AGW/URP/engine suite: 18 passed. Default DEX gas and expiry survive grant/read; amount above the generated policy MAX is rejected by the contract even after bridge budgets are edited. Gateway/core/token/origin metadata remain local fixtures; these are not destination-protocol execution tests. +- Build, spec and local typechecks pass. Six guide TypeScript examples and package CJS/ESM/declaration/import checks pass. Compiled API matches source; production policy and new policy tests have no lint errors/warnings. +- Existing funded E2E scenarios now assert the default configuration and then apply their small fixture-specific execution caps. They were typechecked, not broadcast again. + +## Execution prerequisites remain + +Configuration readiness is not full execution readiness. An offline Donut registry check (registry.json) found only 1 of 33 category/chain/token entries mapped; this count includes mainnet templates, which Donut does not support, and duplicate assets across categories. This is mapping evidence only, not an on-chain source-identity check or proof all unmapped tokens are deployable. + +Most testnet protocol mock/wrapped tokens have no usable current SDK PRC20 mapping. The earlier live tests therefore prefunded destination accounts and granted the generated call constraints with bridge assets empty. The SDK cannot silently drop a default asset or pretend a different token has the same source identity. Passing unmodified generated default assets into create can fail preparation when those mappings are unavailable. The user must have a supported token route or use the documented destination-only grant workflow. Further bridge-token coverage depends on actual supported assets/deployments and registry validation, not permission-policy constants. diff --git a/plan/agw/research/preset-permission-policy-2026-10-18/api.json b/plan/agw/research/preset-permission-policy-2026-10-18/api.json new file mode 100644 index 00000000..97ae2de9 --- /dev/null +++ b/plan/agw/research/preset-permission-policy-2026-10-18/api.json @@ -0,0 +1,64 @@ +{ + "baseline": "b1597b91a25dbf7f691f589b4e1e154add604315", + "head": "b115b66c6888cde5ff4b6a09e6c4b224a8874729", + "compiledMatchesSource": true, + "initializeSignatureChanged": false, + "addedExports": [ + "AgenticPresets", + "ArgumentPath", + "DecodedSolanaRule", + "Pin", + "Preset", + "PresetAsset", + "PresetCallIssue", + "PresetCategory", + "PresetChainReadiness", + "PresetConfigurationIssue", + "PresetOptions", + "PresetResult", + "PresetRuleTemplate", + "ReadyPresetOptions", + "RuleInput", + "Spent", + "WalletMarker" + ], + "removedExports": [ + "AgenticNetworkConstants", + "NativeRule", + "UniversalRule" + ], + "publicTypeChanges": [ + "AGENTIC_ERROR_CODE", + "AgenticError", + "AgenticRevertError", + "AgenticErrorCode", + "AgenticTxMetadata", + "AgenticWallet", + "AllowedCall", + "AssetCap", + "CreateOptions", + "DecodedSolanaRule", + "Rule", + "RuleInput", + "Pin", + "Spent", + "WalletMarker", + "ArgumentPath", + "RulesRecord", + "Preset", + "PresetCategory", + "PresetAsset", + "PresetOptions", + "ReadyPresetOptions", + "PresetRuleTemplate", + "PresetResult", + "PresetChainReadiness", + "PresetConfigurationIssue", + "PresetCallIssue", + "AgenticPresets" + ], + "transactionMethodChanges": [], + "instanceMethodChanges": [], + "agwConstantsChanged": true, + "scope": "Summary of check-agw-api.js output; redundant full source/declaration snapshots omitted." +} diff --git a/plan/agw/research/preset-permission-policy-2026-10-18/api.log b/plan/agw/research/preset-permission-policy-2026-10-18/api.log new file mode 100644 index 00000000..a4e4152e --- /dev/null +++ b/plan/agw/research/preset-permission-policy-2026-10-18/api.log @@ -0,0 +1 @@ +{"compiledMatchesSource":true,"addedExports":["AgenticPresets","ArgumentPath","DecodedSolanaRule","Pin","Preset","PresetAsset","PresetCallIssue","PresetCategory","PresetChainReadiness","PresetConfigurationIssue","PresetOptions","PresetResult","PresetRuleTemplate","ReadyPresetOptions","RuleInput","Spent","WalletMarker"],"removedExports":["AgenticNetworkConstants","NativeRule","UniversalRule"],"changedAgwTypes":["AgenticWallet","AgenticError","AgenticRevertError","AGENTIC_ERROR_CODE","Rule","RuleInput","Pin","Spent","NativeRule","AssetCap","AllowedCall","UniversalRule","RulesRecord","CreateOptions","AgenticTxMetadata"],"publicTypeChanges":["AGENTIC_ERROR_CODE","AgenticError","AgenticRevertError","AgenticErrorCode","AgenticTxMetadata","AgenticWallet","AllowedCall","AssetCap","CreateOptions","DecodedSolanaRule","Rule","RuleInput","Pin","Spent","WalletMarker","ArgumentPath","RulesRecord","Preset","PresetCategory","PresetAsset","PresetOptions","ReadyPresetOptions","PresetRuleTemplate","PresetResult","PresetChainReadiness","PresetConfigurationIssue","PresetCallIssue","AgenticPresets"],"transactionMethodChanges":[],"instanceMethodChanges":[],"initializeSignatureChanged":false,"agwConstantsChanged":true} diff --git a/plan/agw/research/preset-permission-policy-2026-10-18/build.log b/plan/agw/research/preset-permission-policy-2026-10-18/build.log new file mode 100644 index 00000000..2e1f5af4 --- /dev/null +++ b/plan/agw/research/preset-permission-policy-2026-10-18/build.log @@ -0,0 +1,11 @@ + +> nx run core:build + +Compiling TypeScript files for project "core"... +Done compiling TypeScript files for project "core". +(node:23736) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. +(Use `node --trace-warnings ...` to show where the warning was created) + + + + NX Successfully ran target build for project core diff --git a/plan/agw/research/preset-permission-policy-2026-10-18/docs.log b/plan/agw/research/preset-permission-policy-2026-10-18/docs.log new file mode 100644 index 00000000..2755478b --- /dev/null +++ b/plan/agw/research/preset-permission-policy-2026-10-18/docs.log @@ -0,0 +1 @@ +AGW guide: 6 TypeScript blocks typechecked against public exports; no examples executed. diff --git a/plan/agw/research/preset-permission-policy-2026-10-18/focused.log b/plan/agw/research/preset-permission-policy-2026-10-18/focused.log new file mode 100644 index 00000000..7932c173 --- /dev/null +++ b/plan/agw/research/preset-permission-policy-2026-10-18/focused.log @@ -0,0 +1,11 @@ +PASS core packages/core/src/lib/agentic/__tests__/preset-default-policy.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/preset-catalog.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/presets.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/preset-operation-limits.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/preset-default-tokens.spec.ts + +Test Suites: 5 passed, 5 total +Tests: 72 passed, 72 total +Snapshots: 0 total +Time: 2.495 s, estimated 3 s +Ran all test suites within paths "packages/core/src/lib/agentic/__tests__/presets.spec.ts", "packages/core/src/lib/agentic/__tests__/preset-catalog.spec.ts", "packages/core/src/lib/agentic/__tests__/preset-operation-limits.spec.ts", "packages/core/src/lib/agentic/__tests__/preset-default-tokens.spec.ts", "packages/core/src/lib/agentic/__tests__/preset-default-policy.spec.ts". diff --git a/plan/agw/research/preset-permission-policy-2026-10-18/full-unit.log b/plan/agw/research/preset-permission-policy-2026-10-18/full-unit.log new file mode 100644 index 00000000..10563a2c --- /dev/null +++ b/plan/agw/research/preset-permission-policy-2026-10-18/full-unit.log @@ -0,0 +1,181 @@ +PASS core packages/core/src/lib/utils.spec.ts + ● Console + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:973:17) + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:977:17) + + console.log + 1.23 + + at Object. (src/lib/utils.spec.ts:982:17) + +PASS core packages/core/src/lib/universal/account/account.spec.ts + ● Console + + console.warn + [PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead. + + 207 | ): Promise { + 208 | if (!_convertOriginToExecutorWarned) { + > 209 | console.warn( + | ^ + 210 | '[PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead.' + 211 | ); + 212 | _convertOriginToExecutorWarned = true; + + at Object.convertOriginToExecutor (src/lib/universal/account/account.ts:209:13) + at Object. (src/lib/universal/account/account.spec.ts:80:52) + + console.warn + [PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead. + + 425 | ): Promise { + 426 | if (!options?._internal && !_convertExecutorToOriginWarned) { + > 427 | console.warn( + | ^ + 428 | '[PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead.' + 429 | ); + 430 | _convertExecutorToOriginWarned = true; + + at convertExecutorToOrigin (src/lib/universal/account/account.ts:427:13) + at Object. (src/lib/universal/account/account.spec.ts:106:38) + +PASS core packages/core/src/lib/agentic/__tests__/preset-default-policy.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/block-results-client.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-tx-retry.spec.ts +PASS core packages/core/src/lib/push-client/push-client.archive-fallback.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-confirmation-gate.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/signing-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-composition.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-tracker.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gateway-uea-account.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/send.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/rescue-svm-confirmation.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/management.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-timeout-clamp.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/scenarios.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r2-outbound-revert-flow.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/payload-builders.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-executor.spec.ts +PASS core packages/core/src/lib/universal/signer/signer.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/source-hash-resolution.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-svm-confirmation.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/result-decoder.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/resolve.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/build-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-calculator.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/context-helpers-tracker.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/labels.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/web2-compat.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/cascade.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-error-classification.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/multichain-hooks.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/reads-context.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/inbound-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-idl.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/auto-detect.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/inbound-tracker-derivation.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.chain-symbol.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/registry.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/native-multi-action.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/gate.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/response-surface.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-native-multicall.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-evm-r3-native-eoa.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/public-rule.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/funds-only-burn-guard.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/public-surface.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-request-recipient.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/resolver.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-quote.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-detector.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-usd-sizer.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/response-builder-push-revert.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/chain-namespace.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/export.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/spec-builder.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/response-invariant.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-backend.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r1-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm-rent-pc20.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/read-tx-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-builder-progress-hook.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-wire-fixture.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-multichain.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/svm-rent.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-svm-r3.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/account-status.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r3-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-svm-rent.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/codec.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-emission.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/send-transaction-progress-hook.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg-svm.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/execute-standard-required-funds.spec.ts +PASS core packages/core/src/lib/push-client/push-client.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/runtime-token-chain.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/track-transaction-guard.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/terminal-suppression.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-types.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-event-hook-bridge.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r2-spec-strings.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/abi-selectors.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-svm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/normalize.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-evm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/svm-account.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm-log-index.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/revalidate-read.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/registry.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.batch-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/address-codec.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-params.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-web2.spec.ts +PASS core packages/core/src/lib/constants/__tests__/token-constants.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/preset-catalog.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.dynamic-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/errors.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/validate.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/__tests__/signing.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/child-inbounds.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/ucallback-codec.spec.ts +PASS core packages/core/src/lib/constants/__tests__/svm-gateway-idl.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-events.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-execute-order.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/ix-encoder.spec.ts +PASS core packages/core/src/lib/formatters.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/classify.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/max-pc-for-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/tracking.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/normalize-address.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/budget.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/error-decoder.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/presets.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/preset-default-tokens.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/preset-operation-limits.spec.ts + +Test Suites: 1 skipped, 128 passed, 128 of 129 total +Tests: 12 skipped, 2129 passed, 2141 total +Snapshots: 0 total +Time: 32.905 s, estimated 56 s +Ran all test suites. diff --git a/plan/agw/research/preset-permission-policy-2026-10-18/lint.log b/plan/agw/research/preset-permission-policy-2026-10-18/lint.log new file mode 100644 index 00000000..e69de29b diff --git a/plan/agw/research/preset-permission-policy-2026-10-18/local-types.log b/plan/agw/research/preset-permission-policy-2026-10-18/local-types.log new file mode 100644 index 00000000..e69de29b diff --git a/plan/agw/research/preset-permission-policy-2026-10-18/local.log b/plan/agw/research/preset-permission-policy-2026-10-18/local.log new file mode 100644 index 00000000..29864221 --- /dev/null +++ b/plan/agw/research/preset-permission-policy-2026-10-18/local.log @@ -0,0 +1,26 @@ +PASS core-agw-local packages/core/__agw-local__/v5-multiasset.spec.ts (5.049 s) + v6 multi-asset SDK management and execution + ✓ v6 EVM alternatives enforce both spender and MAX, and reads update losslessly (168 ms) + ✓ v6 refuses a bare alternative that bypasses a pinned function and too many initial rules (25 ms) + ✓ the shipped DEX catalog enforces tuple receiver/token/amount pins on actual v6 URP (151 ms) + ✓ a default-token DEX exactInputSingle call rejects spending above its policy cap despite edited bridge budgets (111 ms) + ✓ a default-token DEX exactOutputSingle call rejects spending above its policy cap despite edited bridge budgets (91 ms) + ✓ regenerated LENDING presets enforce new token/amount pins through atomic rules.update (171 ms) + ✓ regenerated STAKING presets enforce new token/amount pins through atomic rules.update (136 ms) + ✓ a fixture preset produces rules accepted by public create and enforced by real contracts (63 ms) + ✓ public create encodes two ordered assets; public get reconstructs source-token caps (53 ms) + ✓ a token from the wrong chain fails before deployment (13 ms) + ✓ a same-chain registry identity mismatch fails before deployment (2 ms) + ✓ both tokens execute under one rule and keep independent counters/limits (99 ms) + ✓ omitted and explicit zero totals both prohibit movement (80 ms) + ✓ empty user assets grants one zero-cap gas token and executes a call-only request (101 ms) + ✓ public update resets both counters in one batch and records five checkpoints (110 ms) + ✓ spend on the second asset after snapshot rolls back revoke/grant and checkpoint writes (82 ms) + ✓ out-of-band duplicate contract grants still make sends ambiguous (28 ms) + ✓ a legacy two-field envelope is refused by the actual v6 grant path (38 ms) + +Test Suites: 1 passed, 1 total +Tests: 18 passed, 18 total +Snapshots: 0 total +Time: 5.092 s, estimated 8 s +Ran all test suites within paths "packages/core/__agw-local__/v5-multiasset.spec.ts". diff --git a/plan/agw/research/preset-permission-policy-2026-10-18/metadata-comparison.json b/plan/agw/research/preset-permission-policy-2026-10-18/metadata-comparison.json new file mode 100644 index 00000000..09e5b64b --- /dev/null +++ b/plan/agw/research/preset-permission-policy-2026-10-18/metadata-comparison.json @@ -0,0 +1,256 @@ +{ + "readOnly": true, + "verified": [ + { + "chain": "eip155:1", + "block": "26217257", + "address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "symbol": "WETH", + "decimals": 18, + "perCall": "0.001", + "total": "0.01", + "presetUses": 2 + }, + { + "chain": "eip155:1", + "block": "26217257", + "address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "symbol": "USDC", + "decimals": 6, + "perCall": "10", + "total": "100", + "presetUses": 2 + }, + { + "chain": "eip155:1", + "block": "26217257", + "address": "0x0000000000000000000000000000000000000000", + "symbol": "ETH", + "decimals": 18, + "native": true, + "perCall": "0.001", + "total": "0.01", + "presetUses": 1 + }, + { + "chain": "eip155:1", + "block": "26217257", + "address": "0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84", + "symbol": "stETH", + "decimals": 18, + "perCall": "0.001", + "total": "0.01", + "presetUses": 1 + }, + { + "chain": "eip155:1", + "block": "26217257", + "address": "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0", + "symbol": "wstETH", + "decimals": 18, + "perCall": "0.001", + "total": "0.01", + "presetUses": 1 + }, + { + "chain": "eip155:8453", + "block": "52755391", + "address": "0x4200000000000000000000000000000000000006", + "symbol": "WETH", + "decimals": 18, + "perCall": "0.001", + "total": "0.01", + "presetUses": 1 + }, + { + "chain": "eip155:8453", + "block": "52755391", + "address": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", + "symbol": "USDC", + "decimals": 6, + "perCall": "10", + "total": "100", + "presetUses": 2 + }, + { + "chain": "eip155:42161", + "block": "515879645", + "address": "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1", + "symbol": "WETH", + "decimals": 18, + "perCall": "0.001", + "total": "0.01", + "presetUses": 2 + }, + { + "chain": "eip155:42161", + "block": "515879645", + "address": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", + "symbol": "USDC", + "decimals": 6, + "perCall": "10", + "total": "100", + "presetUses": 2 + }, + { + "chain": "eip155:56", + "block": "128303716", + "address": "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c", + "symbol": "WBNB", + "decimals": 18, + "perCall": "0.01", + "total": "0.1", + "presetUses": 1 + }, + { + "chain": "eip155:56", + "block": "128303716", + "address": "0x55d398326f99059fF775485246999027B3197955", + "symbol": "USDT", + "decimals": 18, + "perCall": "10", + "total": "100", + "presetUses": 2 + }, + { + "chain": "eip155:11155111", + "block": "11938903", + "address": "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14", + "symbol": "WETH", + "decimals": 18, + "perCall": "0.001", + "total": "0.01", + "presetUses": 1 + }, + { + "chain": "eip155:11155111", + "block": "11938903", + "address": "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238", + "symbol": "USDC", + "decimals": 6, + "perCall": "10", + "total": "100", + "presetUses": 1 + }, + { + "chain": "eip155:11155111", + "block": "11938903", + "address": "0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5", + "symbol": "LINK", + "decimals": 18, + "perCall": "1", + "total": "10", + "presetUses": 1 + }, + { + "chain": "eip155:11155111", + "block": "11938903", + "address": "0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9", + "symbol": "WETH", + "decimals": 18, + "perCall": "0.001", + "total": "0.01", + "presetUses": 1 + }, + { + "chain": "eip155:84532", + "block": "48265921", + "address": "0x4200000000000000000000000000000000000006", + "symbol": "WETH", + "decimals": 18, + "perCall": "0.001", + "total": "0.01", + "presetUses": 1 + }, + { + "chain": "eip155:84532", + "block": "48265921", + "address": "0x036CbD53842c5426634e7929541eC2318f3dCF7e", + "symbol": "USDC", + "decimals": 6, + "perCall": "10", + "total": "100", + "presetUses": 1 + }, + { + "chain": "eip155:84532", + "block": "48265921", + "address": "0x810D46F9a9027E28F9B01F75E2bdde839dA61115", + "symbol": "LINK", + "decimals": 18, + "perCall": "1", + "total": "10", + "presetUses": 1 + }, + { + "chain": "eip155:84532", + "block": "48265921", + "address": "0x4616975f7E6045FD9737e95bC527e9e14c727BD2", + "symbol": "USDBC", + "decimals": 6, + "perCall": "10", + "total": "100", + "presetUses": 1 + }, + { + "chain": "eip155:84532", + "block": "48265921", + "address": "0x663A6F02d547dFd639BF689FED298712f2FB69Fb", + "symbol": "WETH", + "decimals": 18, + "perCall": "0.001", + "total": "0.01", + "presetUses": 1 + }, + { + "chain": "eip155:421614", + "block": "320300290", + "address": "0x980B62Da83eFf3D4576C647993b0c1D7faf17c73", + "symbol": "WETH", + "decimals": 18, + "perCall": "0.001", + "total": "0.01", + "presetUses": 1 + }, + { + "chain": "eip155:421614", + "block": "320300290", + "address": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "symbol": "USDC", + "decimals": 6, + "perCall": "10", + "total": "100", + "presetUses": 2 + }, + { + "chain": "eip155:97", + "block": "137451289", + "address": "0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd", + "symbol": "WBNB", + "decimals": 18, + "perCall": "0.01", + "total": "0.1", + "presetUses": 1 + }, + { + "chain": "eip155:97", + "block": "137451289", + "address": "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", + "symbol": "USDT", + "decimals": 6, + "perCall": "10", + "total": "100", + "presetUses": 2 + }, + { + "chain": "eip155:97", + "block": "137451289", + "address": "0x16227D60f7a0e586C66B005219dfc887D13C9531", + "symbol": "USDC", + "decimals": 6, + "perCall": "10", + "total": "100", + "presetUses": 1 + } + ] +} \ No newline at end of file diff --git a/plan/agw/research/preset-permission-policy-2026-10-18/package.log b/plan/agw/research/preset-permission-policy-2026-10-18/package.log new file mode 100644 index 00000000..8e1b97e4 --- /dev/null +++ b/plan/agw/research/preset-permission-policy-2026-10-18/package.log @@ -0,0 +1 @@ +AGW package: CJS/ESM imports, compiled declaration examples and npm contents pass. No examples executed/published. diff --git a/plan/agw/research/preset-permission-policy-2026-10-18/registry.json b/plan/agw/research/preset-permission-policy-2026-10-18/registry.json new file mode 100644 index 00000000..c4b28893 --- /dev/null +++ b/plan/agw/research/preset-permission-policy-2026-10-18/registry.json @@ -0,0 +1,204 @@ +{ + "network": "TESTNET_DONUT", + "scope": "Offline mapping only; no on-chain source check", + "rows": [ + { + "category": "DEXES", + "chain": "eip155:1", + "token": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "unavailable": "Unsupported token symbol: WETH" + }, + { + "category": "DEXES", + "chain": "eip155:1", + "token": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "unavailable": "Unable to infer origin chain or token symbol for token" + }, + { + "category": "DEXES", + "chain": "eip155:8453", + "token": "0x4200000000000000000000000000000000000006", + "unavailable": "Unable to infer origin chain or token symbol for token" + }, + { + "category": "DEXES", + "chain": "eip155:8453", + "token": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", + "unavailable": "Unable to infer origin chain or token symbol for token" + }, + { + "category": "DEXES", + "chain": "eip155:42161", + "token": "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1", + "unavailable": "Unable to infer origin chain or token symbol for token" + }, + { + "category": "DEXES", + "chain": "eip155:42161", + "token": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", + "unavailable": "Unable to infer origin chain or token symbol for token" + }, + { + "category": "DEXES", + "chain": "eip155:56", + "token": "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c", + "unavailable": "Unable to infer origin chain or token symbol for token" + }, + { + "category": "DEXES", + "chain": "eip155:56", + "token": "0x55d398326f99059fF775485246999027B3197955", + "unavailable": "Unable to infer origin chain or token symbol for token" + }, + { + "category": "DEXES", + "chain": "eip155:11155111", + "token": "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14", + "unavailable": "Unable to infer origin chain or token symbol for token" + }, + { + "category": "DEXES", + "chain": "eip155:11155111", + "token": "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238", + "unavailable": "Unable to infer origin chain or token symbol for token" + }, + { + "category": "DEXES", + "chain": "eip155:84532", + "token": "0x4200000000000000000000000000000000000006", + "unavailable": "Unable to infer origin chain or token symbol for token" + }, + { + "category": "DEXES", + "chain": "eip155:84532", + "token": "0x036CbD53842c5426634e7929541eC2318f3dCF7e", + "unavailable": "Unable to infer origin chain or token symbol for token" + }, + { + "category": "DEXES", + "chain": "eip155:421614", + "token": "0x980B62Da83eFf3D4576C647993b0c1D7faf17c73", + "unavailable": "Unsupported token symbol: WETH" + }, + { + "category": "DEXES", + "chain": "eip155:421614", + "token": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "unavailable": "Unable to infer origin chain or token symbol for token" + }, + { + "category": "DEXES", + "chain": "eip155:97", + "token": "0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd", + "unavailable": "Unable to infer origin chain or token symbol for token" + }, + { + "category": "DEXES", + "chain": "eip155:97", + "token": "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", + "unavailable": "Unable to infer origin chain or token symbol for token" + }, + { + "category": "LENDING", + "chain": "eip155:1", + "token": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "unavailable": "Unsupported token symbol: WETH" + }, + { + "category": "LENDING", + "chain": "eip155:1", + "token": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "unavailable": "Unable to infer origin chain or token symbol for token" + }, + { + "category": "LENDING", + "chain": "eip155:8453", + "token": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", + "unavailable": "Unable to infer origin chain or token symbol for token" + }, + { + "category": "LENDING", + "chain": "eip155:42161", + "token": "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1", + "unavailable": "Unable to infer origin chain or token symbol for token" + }, + { + "category": "LENDING", + "chain": "eip155:42161", + "token": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", + "unavailable": "Unable to infer origin chain or token symbol for token" + }, + { + "category": "LENDING", + "chain": "eip155:56", + "token": "0x55d398326f99059fF775485246999027B3197955", + "unavailable": "Unable to infer origin chain or token symbol for token" + }, + { + "category": "LENDING", + "chain": "eip155:11155111", + "token": "0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5", + "unavailable": "Unable to infer origin chain or token symbol for token" + }, + { + "category": "LENDING", + "chain": "eip155:421614", + "token": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "unavailable": "Unable to infer origin chain or token symbol for token" + }, + { + "category": "LENDING", + "chain": "eip155:84532", + "token": "0x810D46F9a9027E28F9B01F75E2bdde839dA61115", + "unavailable": "Unable to infer origin chain or token symbol for token" + }, + { + "category": "LENDING", + "chain": "eip155:84532", + "token": "0x4616975f7E6045FD9737e95bC527e9e14c727BD2", + "unavailable": "Unable to infer origin chain or token symbol for token" + }, + { + "category": "LENDING", + "chain": "eip155:84532", + "token": "0x663A6F02d547dFd639BF689FED298712f2FB69Fb", + "unavailable": "Unable to infer origin chain or token symbol for token" + }, + { + "category": "LENDING", + "chain": "eip155:97", + "token": "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", + "unavailable": "Unable to infer origin chain or token symbol for token" + }, + { + "category": "LENDING", + "chain": "eip155:97", + "token": "0x16227D60f7a0e586C66B005219dfc887D13C9531", + "unavailable": "Unable to infer origin chain or token symbol for token" + }, + { + "category": "STAKING", + "chain": "eip155:1", + "token": "0x0000000000000000000000000000000000000000", + "prc20": "0x2971824Db68229D087931155C2b8bB820B275809" + }, + { + "category": "STAKING", + "chain": "eip155:1", + "token": "0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84", + "unavailable": "Unable to infer origin chain or token symbol for token" + }, + { + "category": "STAKING", + "chain": "eip155:1", + "token": "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0", + "unavailable": "Unable to infer origin chain or token symbol for token" + }, + { + "category": "STAKING", + "chain": "eip155:11155111", + "token": "0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9", + "unavailable": "Unable to infer origin chain or token symbol for token" + } + ] +} \ No newline at end of file diff --git a/plan/agw/research/preset-permission-policy-2026-10-18/token-metadata.json b/plan/agw/research/preset-permission-policy-2026-10-18/token-metadata.json new file mode 100644 index 00000000..fc3c5f10 --- /dev/null +++ b/plan/agw/research/preset-permission-policy-2026-10-18/token-metadata.json @@ -0,0 +1,188 @@ +{ + "at": "2026-10-18T05:08:51.736Z", + "readOnly": true, + "results": [ + { + "chain": "eip155:1", + "rpc": "https://ethereum-rpc.publicnode.com", + "blockNumber": "26217257", + "entries": [ + { + "address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "symbol": "WETH", + "decimals": 18 + }, + { + "address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "symbol": "USDC", + "decimals": 6 + }, + { + "address": "0x0000000000000000000000000000000000000000", + "symbol": "ETH", + "decimals": 18, + "native": true + }, + { + "address": "0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84", + "symbol": "stETH", + "decimals": 18 + }, + { + "address": "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0", + "symbol": "wstETH", + "decimals": 18 + } + ] + }, + { + "chain": "eip155:8453", + "rpc": "https://base-rpc.publicnode.com", + "blockNumber": "52755391", + "entries": [ + { + "address": "0x4200000000000000000000000000000000000006", + "symbol": "WETH", + "decimals": 18 + }, + { + "address": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", + "symbol": "USDC", + "decimals": 6 + } + ] + }, + { + "chain": "eip155:42161", + "rpc": "https://arbitrum-one-rpc.publicnode.com", + "blockNumber": "515879645", + "entries": [ + { + "address": "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1", + "symbol": "WETH", + "decimals": 18 + }, + { + "address": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", + "symbol": "USDC", + "decimals": 6 + } + ] + }, + { + "chain": "eip155:56", + "rpc": "https://bsc-rpc.publicnode.com", + "blockNumber": "128303716", + "entries": [ + { + "address": "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c", + "symbol": "WBNB", + "decimals": 18 + }, + { + "address": "0x55d398326f99059fF775485246999027B3197955", + "symbol": "USDT", + "decimals": 18 + } + ] + }, + { + "chain": "eip155:11155111", + "rpc": "https://ethereum-sepolia-rpc.publicnode.com", + "blockNumber": "11938903", + "entries": [ + { + "address": "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14", + "symbol": "WETH", + "decimals": 18 + }, + { + "address": "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238", + "symbol": "USDC", + "decimals": 6 + }, + { + "address": "0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5", + "symbol": "LINK", + "decimals": 18 + }, + { + "address": "0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9", + "symbol": "WETH", + "decimals": 18 + } + ] + }, + { + "chain": "eip155:84532", + "rpc": "https://base-sepolia-rpc.publicnode.com", + "blockNumber": "48265921", + "entries": [ + { + "address": "0x4200000000000000000000000000000000000006", + "symbol": "WETH", + "decimals": 18 + }, + { + "address": "0x036CbD53842c5426634e7929541eC2318f3dCF7e", + "symbol": "USDC", + "decimals": 6 + }, + { + "address": "0x810D46F9a9027E28F9B01F75E2bdde839dA61115", + "symbol": "LINK", + "decimals": 18 + }, + { + "address": "0x4616975f7E6045FD9737e95bC527e9e14c727BD2", + "symbol": "USDBC", + "decimals": 6 + }, + { + "address": "0x663A6F02d547dFd639BF689FED298712f2FB69Fb", + "symbol": "WETH", + "decimals": 18 + } + ] + }, + { + "chain": "eip155:421614", + "rpc": "https://arbitrum-sepolia-rpc.publicnode.com", + "blockNumber": "320300290", + "entries": [ + { + "address": "0x980B62Da83eFf3D4576C647993b0c1D7faf17c73", + "symbol": "WETH", + "decimals": 18 + }, + { + "address": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "symbol": "USDC", + "decimals": 6 + } + ] + }, + { + "chain": "eip155:97", + "rpc": "https://bsc-testnet-rpc.publicnode.com", + "blockNumber": "137451289", + "entries": [ + { + "address": "0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd", + "symbol": "WBNB", + "decimals": 18 + }, + { + "address": "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", + "symbol": "USDT", + "decimals": 6 + }, + { + "address": "0x16227D60f7a0e586C66B005219dfc887D13C9531", + "symbol": "USDC", + "decimals": 6 + } + ] + } + ] +} \ No newline at end of file diff --git a/plan/agw/research/preset-permission-policy-2026-10-18/types.log b/plan/agw/research/preset-permission-policy-2026-10-18/types.log new file mode 100644 index 00000000..e69de29b diff --git a/plan/agw/research/preset-release-readiness-2026-10-18/README.md b/plan/agw/research/preset-release-readiness-2026-10-18/README.md new file mode 100644 index 00000000..d15f3bb0 --- /dev/null +++ b/plan/agw/research/preset-release-readiness-2026-10-18/README.md @@ -0,0 +1,38 @@ +# Preset alpha release readiness — October 18, 2026 + +Source commit: v4 `2d16bfe0`; equivalent v5 `83f9a713`. V5 keeps its existing 6.0.27-alpha.2 version/changelog/lockfile. Publication remains the user's manual workflow action. No package was published or workflow dispatched by this work. + +## Shipped behavior + +- Curated tokens, explicit modest raw-unit caps, 20 PC value ceiling and seven-day expiry. Explicit overrides/zeros are preserved. General rules and supplied-asset missing caps remain zero. +- Funding defaults to Push: unmapped assets stay in the output and yield BRIDGE_ASSET_UNAVAILABLE instead of a misleading ready result. Unsupported gateway destinations and unadvertised AGW networks are reported separately. +- Explicit destination funding returns rules with empty bridge assets and unchanged token/call constraints. Selected tokens/limits remain visible in readiness.chains[].selectedAssets. These rules grant no Push token-export budget and require destination balances already funded. +- ConfigurationReady is separate from Ready: Ready additionally requires offline release-network, destination and registry support for the selected mode. It is not a live balance/liquidity/current-chain guarantee. Mainnet templates remain discoverable and unavailable for Donut execution. +- Sepolia WETH/stETH registry resolutions now use already-deployed mappings, verified by exact chain/source identity. EVM casing is normalized without changing case-sensitive Solana matching. Explicit mainnet references cannot alias a Sepolia source. String and address-word PRC20 source metadata are supported. +- No source token, route or deployment was invented; unavailable mocks/Circle tokens are not aliased to same-symbol registered tokens. + +## Verification + +| Check | Result | +| --- | --- | +| Full unit suite | 2,142 passed, 12 skipped, no failures | +| Actual v6 local policy suite | 21 passed; includes direct get → create for destination-funded DEX/lending/staking without rewriting the rules | +| Donut factory simulations | 9/9 destination-funded testnet preset cases passed, including preparation, CEA lookup and index-bound create calldata | +| Source identity | WETH and stETH resolutions verified against actual PRC20 metadata | +| Build / spec and local typechecks | Passed | +| Guide | Six TypeScript blocks typechecked | +| API comparison | Compiled matches source | +| Production lint | No errors/warnings in changed production modules | +| Package | CJS/ESM imports and declaration examples pass; no plan/E2E/local-harness/scripts/.env folders in npm contents; built preset smoke checks pass | +| V5 | Build/package checks pass; core sources identical to v4 except preserved package version and changelog | +| V5 immutable install | Passed in an isolated workspace copied from release manifests/lockfile; builds skipped. Existing peer/optional TypeScript patch warnings remain, no lockfile rewrite | + +Donut read-only evidence pins block 24381571 and factory 0xFBBEB6a365178fAaA81A9789a5f64b300c37e5bc. The checker initializes a read-mode UniversalAccount with no key. Calls are RPC reads and eth_call; simulated wallet deployments/grants are transient, not broadcasts. Reports are acceptance.json and routes.json. The initial standalone checker had a wrong relative build path and used a non-exported enum import; both were corrected before these final passing results. + +No funded live E2E was repeated for this release. Previous Aave/EigenLayer/BNB live flows remain historical execution evidence, with fresh Base/Moonwell acceptance incomplete at the user's stop request. Nine factory simulations establish default grant acceptance, not actual cross-chain settlement/protocol execution, funding, reserves or liquidity. + +## UI handoff + +Use presets.get(category, { agent, chainNamespace, funding: 'destination' }) for prefunded destination execution. Display selectedAssets as token permissions; returned rules.assets is Push bridge authority and intentionally empty in that mode. Check readiness.ready and show issues. Use default Push mode only with registered, verified source routes. Missing routes and mainnet execution remain external availability limits, not reasons to invent registry entries. + +The repository read-only checker is packages/core/scripts/check-agw-preset-routes.js. It runs against built artifacts, never loads keys, and is excluded from the npm package. Publishing remains manual; select feat/agw-sdk-v5 and an alpha release. diff --git a/plan/agw/research/preset-release-readiness-2026-10-18/acceptance.json b/plan/agw/research/preset-release-readiness-2026-10-18/acceptance.json new file mode 100644 index 00000000..02be6759 --- /dev/null +++ b/plan/agw/research/preset-release-readiness-2026-10-18/acceptance.json @@ -0,0 +1,652 @@ +{ + "at": "2026-10-18T13:16:48.622Z", + "readOnly": true, + "network": "TESTNET_DONUT", + "cases": [ + { + "category": "DEXES", + "chainNamespace": "eip155:11155111", + "pushReadiness": { + "ready": false, + "chains": [ + { + "chainNamespace": "eip155:11155111", + "ready": false, + "configurationReady": true, + "funding": "push", + "selectedAssets": [ + { + "token": "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14", + "maxPerCall": "1000000000000000", + "maxTotal": "10000000000000000" + }, + { + "token": "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238", + "maxPerCall": "10000000", + "maxTotal": "100000000" + } + ], + "bridgeAssets": [ + { + "token": "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14", + "prc20": "0x0d0dF7E8807430A81104EA84d926139816eC7586", + "status": "registered" + }, + { + "token": "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238", + "status": "unavailable" + } + ], + "issues": [ + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238", + "message": "No SDK PRC20 mapping for eip155:11155111:0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238 on TESTNET_DONUT. Use a supported source asset or explicitly choose destination funding for assets already at the CEA." + } + ], + "disabledCalls": [], + "excludedCalls": [], + "knownTokens": [ + "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14", + "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238" + ], + "zeroBridgeLimits": [] + } + ] + }, + "destinationFactorySimulation": "passed", + "selectedAssets": [ + { + "token": "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14", + "maxPerCall": "1000000000000000", + "maxTotal": "10000000000000000" + }, + { + "token": "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238", + "maxPerCall": "10000000", + "maxTotal": "100000000" + } + ], + "pushPreparation": "unavailable-in-registry" + }, + { + "category": "DEXES", + "chainNamespace": "eip155:84532", + "pushReadiness": { + "ready": false, + "chains": [ + { + "chainNamespace": "eip155:84532", + "ready": false, + "configurationReady": true, + "funding": "push", + "selectedAssets": [ + { + "token": "0x4200000000000000000000000000000000000006", + "maxPerCall": "1000000000000000", + "maxTotal": "10000000000000000" + }, + { + "token": "0x036CbD53842c5426634e7929541eC2318f3dCF7e", + "maxPerCall": "10000000", + "maxTotal": "100000000" + } + ], + "bridgeAssets": [ + { + "token": "0x4200000000000000000000000000000000000006", + "status": "unavailable" + }, + { + "token": "0x036CbD53842c5426634e7929541eC2318f3dCF7e", + "status": "unavailable" + } + ], + "issues": [ + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0x4200000000000000000000000000000000000006", + "message": "No SDK PRC20 mapping for eip155:84532:0x4200000000000000000000000000000000000006 on TESTNET_DONUT. Use a supported source asset or explicitly choose destination funding for assets already at the CEA." + }, + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0x036CbD53842c5426634e7929541eC2318f3dCF7e", + "message": "No SDK PRC20 mapping for eip155:84532:0x036CbD53842c5426634e7929541eC2318f3dCF7e on TESTNET_DONUT. Use a supported source asset or explicitly choose destination funding for assets already at the CEA." + } + ], + "disabledCalls": [], + "excludedCalls": [], + "knownTokens": [ + "0x4200000000000000000000000000000000000006", + "0x036CbD53842c5426634e7929541eC2318f3dCF7e" + ], + "zeroBridgeLimits": [] + } + ] + }, + "destinationFactorySimulation": "passed", + "selectedAssets": [ + { + "token": "0x4200000000000000000000000000000000000006", + "maxPerCall": "1000000000000000", + "maxTotal": "10000000000000000" + }, + { + "token": "0x036CbD53842c5426634e7929541eC2318f3dCF7e", + "maxPerCall": "10000000", + "maxTotal": "100000000" + } + ], + "pushPreparation": "unavailable-in-registry" + }, + { + "category": "DEXES", + "chainNamespace": "eip155:421614", + "pushReadiness": { + "ready": false, + "chains": [ + { + "chainNamespace": "eip155:421614", + "ready": false, + "configurationReady": true, + "funding": "push", + "selectedAssets": [ + { + "token": "0x980B62Da83eFf3D4576C647993b0c1D7faf17c73", + "maxPerCall": "1000000000000000", + "maxTotal": "10000000000000000" + }, + { + "token": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "maxPerCall": "10000000", + "maxTotal": "100000000" + } + ], + "bridgeAssets": [ + { + "token": "0x980B62Da83eFf3D4576C647993b0c1D7faf17c73", + "status": "unavailable" + }, + { + "token": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "status": "unavailable" + } + ], + "issues": [ + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0x980B62Da83eFf3D4576C647993b0c1D7faf17c73", + "message": "No SDK PRC20 mapping for eip155:421614:0x980B62Da83eFf3D4576C647993b0c1D7faf17c73 on TESTNET_DONUT. Use a supported source asset or explicitly choose destination funding for assets already at the CEA." + }, + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "message": "No SDK PRC20 mapping for eip155:421614:0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d on TESTNET_DONUT. Use a supported source asset or explicitly choose destination funding for assets already at the CEA." + } + ], + "disabledCalls": [], + "excludedCalls": [], + "knownTokens": [ + "0x980B62Da83eFf3D4576C647993b0c1D7faf17c73", + "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d" + ], + "zeroBridgeLimits": [] + } + ] + }, + "destinationFactorySimulation": "passed", + "selectedAssets": [ + { + "token": "0x980B62Da83eFf3D4576C647993b0c1D7faf17c73", + "maxPerCall": "1000000000000000", + "maxTotal": "10000000000000000" + }, + { + "token": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "maxPerCall": "10000000", + "maxTotal": "100000000" + } + ], + "pushPreparation": "unavailable-in-registry" + }, + { + "category": "DEXES", + "chainNamespace": "eip155:97", + "pushReadiness": { + "ready": false, + "chains": [ + { + "chainNamespace": "eip155:97", + "ready": false, + "configurationReady": true, + "funding": "push", + "selectedAssets": [ + { + "token": "0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd", + "maxPerCall": "10000000000000000", + "maxTotal": "100000000000000000" + }, + { + "token": "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", + "maxPerCall": "10000000", + "maxTotal": "100000000" + } + ], + "bridgeAssets": [ + { + "token": "0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd", + "status": "unavailable" + }, + { + "token": "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", + "status": "unavailable" + } + ], + "issues": [ + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd", + "message": "No SDK PRC20 mapping for eip155:97:0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd on TESTNET_DONUT. Use a supported source asset or explicitly choose destination funding for assets already at the CEA." + }, + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", + "message": "No SDK PRC20 mapping for eip155:97:0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c on TESTNET_DONUT. Use a supported source asset or explicitly choose destination funding for assets already at the CEA." + } + ], + "disabledCalls": [], + "excludedCalls": [], + "knownTokens": [ + "0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd", + "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c" + ], + "zeroBridgeLimits": [] + } + ] + }, + "destinationFactorySimulation": "passed", + "selectedAssets": [ + { + "token": "0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd", + "maxPerCall": "10000000000000000", + "maxTotal": "100000000000000000" + }, + { + "token": "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", + "maxPerCall": "10000000", + "maxTotal": "100000000" + } + ], + "pushPreparation": "unavailable-in-registry" + }, + { + "category": "LENDING", + "chainNamespace": "eip155:11155111", + "pushReadiness": { + "ready": false, + "chains": [ + { + "chainNamespace": "eip155:11155111", + "ready": false, + "configurationReady": true, + "funding": "push", + "selectedAssets": [ + { + "token": "0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5", + "maxPerCall": "1000000000000000000", + "maxTotal": "10000000000000000000" + } + ], + "bridgeAssets": [ + { + "token": "0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5", + "status": "unavailable" + } + ], + "issues": [ + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5", + "message": "No SDK PRC20 mapping for eip155:11155111:0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5 on TESTNET_DONUT. Use a supported source asset or explicitly choose destination funding for assets already at the CEA." + } + ], + "disabledCalls": [], + "excludedCalls": [], + "knownTokens": [ + "0xFF34B3d4Aee8ddCd6F9AFFFB6Fe49bD371b8a357", + "0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5", + "0x94a9D9AC8a22534E3FaCa9F4e7F2E2cf85d5E4C8", + "0x29f2D40B0605204364af54EC677bD022dA425d03", + "0xC558DBdd856501FCd9aaF1E62eae57A9F0629a3c", + "0xaA8E23Fb1079EA71e0a56F48a2aA51851D8433D0", + "0x88541670E55cC00bEEFD87eB59EDd1b7C511AC9a", + "0x6d906e526a4e2Ca02097BA9d0caA3c382F52278E", + "0xc4bF5CbDaBE595361438F8c6a187bDc330539c60" + ], + "zeroBridgeLimits": [] + } + ] + }, + "destinationFactorySimulation": "passed", + "selectedAssets": [ + { + "token": "0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5", + "maxPerCall": "1000000000000000000", + "maxTotal": "10000000000000000000" + } + ], + "pushPreparation": "unavailable-in-registry" + }, + { + "category": "LENDING", + "chainNamespace": "eip155:421614", + "pushReadiness": { + "ready": false, + "chains": [ + { + "chainNamespace": "eip155:421614", + "ready": false, + "configurationReady": true, + "funding": "push", + "selectedAssets": [ + { + "token": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "maxPerCall": "10000000", + "maxTotal": "100000000" + } + ], + "bridgeAssets": [ + { + "token": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "status": "unavailable" + } + ], + "issues": [ + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "message": "No SDK PRC20 mapping for eip155:421614:0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d on TESTNET_DONUT. Use a supported source asset or explicitly choose destination funding for assets already at the CEA." + } + ], + "disabledCalls": [], + "excludedCalls": [], + "knownTokens": [ + "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "0x1dF462e2712496373A347f8ad10802a5E95f053D" + ], + "zeroBridgeLimits": [] + } + ] + }, + "destinationFactorySimulation": "passed", + "selectedAssets": [ + { + "token": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "maxPerCall": "10000000", + "maxTotal": "100000000" + } + ], + "pushPreparation": "unavailable-in-registry" + }, + { + "category": "LENDING", + "chainNamespace": "eip155:84532", + "pushReadiness": { + "ready": false, + "chains": [ + { + "chainNamespace": "eip155:84532", + "ready": false, + "configurationReady": true, + "funding": "push", + "selectedAssets": [ + { + "token": "0x810D46F9a9027E28F9B01F75E2bdde839dA61115", + "maxPerCall": "1000000000000000000", + "maxTotal": "10000000000000000000" + }, + { + "token": "0x4616975f7E6045FD9737e95bC527e9e14c727BD2", + "maxPerCall": "10000000", + "maxTotal": "100000000" + }, + { + "token": "0x663A6F02d547dFd639BF689FED298712f2FB69Fb", + "maxPerCall": "1000000000000000", + "maxTotal": "10000000000000000" + } + ], + "bridgeAssets": [ + { + "token": "0x810D46F9a9027E28F9B01F75E2bdde839dA61115", + "status": "unavailable" + }, + { + "token": "0x4616975f7E6045FD9737e95bC527e9e14c727BD2", + "status": "unavailable" + }, + { + "token": "0x663A6F02d547dFd639BF689FED298712f2FB69Fb", + "status": "unavailable" + } + ], + "issues": [ + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0x810D46F9a9027E28F9B01F75E2bdde839dA61115", + "message": "No SDK PRC20 mapping for eip155:84532:0x810D46F9a9027E28F9B01F75E2bdde839dA61115 on TESTNET_DONUT. Use a supported source asset or explicitly choose destination funding for assets already at the CEA." + }, + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0x4616975f7E6045FD9737e95bC527e9e14c727BD2", + "message": "No SDK PRC20 mapping for eip155:84532:0x4616975f7E6045FD9737e95bC527e9e14c727BD2 on TESTNET_DONUT. Use a supported source asset or explicitly choose destination funding for assets already at the CEA." + }, + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0x663A6F02d547dFd639BF689FED298712f2FB69Fb", + "message": "No SDK PRC20 mapping for eip155:84532:0x663A6F02d547dFd639BF689FED298712f2FB69Fb on TESTNET_DONUT. Use a supported source asset or explicitly choose destination funding for assets already at the CEA." + } + ], + "disabledCalls": [], + "excludedCalls": [ + { + "target": "0x876852425331a113d8E432eFFB3aC5BEf38f033a", + "selector": "redeem(uint256)", + "app": "Moonwell mUSDbC", + "reason": "SHARE_AMOUNT", + "alternative": "redeemUnderlying(uint256)" + }, + { + "target": "0x2F39a349A79492a70E152760ce7123A1933eCf28", + "selector": "redeem(uint256)", + "app": "Moonwell mWETH", + "reason": "SHARE_AMOUNT", + "alternative": "redeemUnderlying(uint256)" + } + ], + "knownTokens": [ + "0xba50Cd2A20f6DA35D788639E581bca8d0B5d4D5f", + "0x0a215D8ba66387DCA84B284D18c3B4ec3de6E54a", + "0x54114591963CF60EF3aA63bEfD6eC263D98145a4", + "0x4200000000000000000000000000000000000006", + "0xD171b9694f7A2597Ed006D41f7509aaD4B485c4B", + "0x810D46F9a9027E28F9B01F75E2bdde839dA61115", + "0x4616975f7E6045FD9737e95bC527e9e14c727BD2", + "0x663A6F02d547dFd639BF689FED298712f2FB69Fb" + ], + "zeroBridgeLimits": [] + } + ] + }, + "destinationFactorySimulation": "passed", + "selectedAssets": [ + { + "token": "0x810D46F9a9027E28F9B01F75E2bdde839dA61115", + "maxPerCall": "1000000000000000000", + "maxTotal": "10000000000000000000" + }, + { + "token": "0x4616975f7E6045FD9737e95bC527e9e14c727BD2", + "maxPerCall": "10000000", + "maxTotal": "100000000" + }, + { + "token": "0x663A6F02d547dFd639BF689FED298712f2FB69Fb", + "maxPerCall": "1000000000000000", + "maxTotal": "10000000000000000" + } + ], + "pushPreparation": "unavailable-in-registry" + }, + { + "category": "LENDING", + "chainNamespace": "eip155:97", + "pushReadiness": { + "ready": false, + "chains": [ + { + "chainNamespace": "eip155:97", + "ready": false, + "configurationReady": true, + "funding": "push", + "selectedAssets": [ + { + "token": "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", + "maxPerCall": "10000000", + "maxTotal": "100000000" + }, + { + "token": "0x16227D60f7a0e586C66B005219dfc887D13C9531", + "maxPerCall": "10000000", + "maxTotal": "100000000" + } + ], + "bridgeAssets": [ + { + "token": "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", + "status": "unavailable" + }, + { + "token": "0x16227D60f7a0e586C66B005219dfc887D13C9531", + "status": "unavailable" + } + ], + "issues": [ + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", + "message": "No SDK PRC20 mapping for eip155:97:0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c on TESTNET_DONUT. Use a supported source asset or explicitly choose destination funding for assets already at the CEA." + }, + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0x16227D60f7a0e586C66B005219dfc887D13C9531", + "message": "No SDK PRC20 mapping for eip155:97:0x16227D60f7a0e586C66B005219dfc887D13C9531 on TESTNET_DONUT. Use a supported source asset or explicitly choose destination funding for assets already at the CEA." + } + ], + "disabledCalls": [], + "excludedCalls": [ + { + "target": "0xb7526572FFE56AB9D7489838Bf2E18e3323b441A", + "selector": "redeem(uint256)", + "app": "Venus vUSDT", + "reason": "SHARE_AMOUNT", + "alternative": "redeemUnderlying(uint256)" + }, + { + "target": "0xD5C4C2e2facBEB59D0216D0595d63FcDc6F9A1a7", + "selector": "redeem(uint256)", + "app": "Venus vUSDC", + "reason": "SHARE_AMOUNT", + "alternative": "redeemUnderlying(uint256)" + } + ], + "knownTokens": [ + "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", + "0x16227D60f7a0e586C66B005219dfc887D13C9531" + ], + "zeroBridgeLimits": [] + } + ] + }, + "destinationFactorySimulation": "passed", + "selectedAssets": [ + { + "token": "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", + "maxPerCall": "10000000", + "maxTotal": "100000000" + }, + { + "token": "0x16227D60f7a0e586C66B005219dfc887D13C9531", + "maxPerCall": "10000000", + "maxTotal": "100000000" + } + ], + "pushPreparation": "unavailable-in-registry" + }, + { + "category": "STAKING", + "chainNamespace": "eip155:11155111", + "pushReadiness": { + "ready": false, + "chains": [ + { + "chainNamespace": "eip155:11155111", + "ready": false, + "configurationReady": true, + "funding": "push", + "selectedAssets": [ + { + "token": "0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9", + "maxPerCall": "1000000000000000", + "maxTotal": "10000000000000000" + } + ], + "bridgeAssets": [ + { + "token": "0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9", + "status": "unavailable" + } + ], + "issues": [ + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9", + "message": "No SDK PRC20 mapping for eip155:11155111:0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9 on TESTNET_DONUT. Use a supported source asset or explicitly choose destination funding for assets already at the CEA." + } + ], + "disabledCalls": [], + "excludedCalls": [], + "knownTokens": [ + "0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9" + ], + "zeroBridgeLimits": [] + } + ] + }, + "destinationFactorySimulation": "passed", + "selectedAssets": [ + { + "token": "0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9", + "maxPerCall": "1000000000000000", + "maxTotal": "10000000000000000" + } + ], + "pushPreparation": "unavailable-in-registry" + } + ], + "blockNumber": "24381571", + "factory": "0xFBBEB6a365178fAaA81A9789a5f64b300c37e5bc", + "verifiedERC20Mappings": [ + { + "source": "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14", + "prc20": "0x0d0dF7E8807430A81104EA84d926139816eC7586", + "status": "source-identity-verified" + }, + { + "source": "0x3e3FE7dBc6B4C189E7128855dD526361c49b40Af", + "prc20": "0xaf89E805949c628ebde3262e91dc4ab9eA12668E", + "status": "source-identity-verified" + } + ], + "counterfactualWallet": "0xED6bFE825b8d84A1E6f4F7c9067398F8985CC372" +} \ No newline at end of file diff --git a/plan/agw/research/preset-release-readiness-2026-10-18/acceptance.log b/plan/agw/research/preset-release-readiness-2026-10-18/acceptance.log new file mode 100644 index 00000000..a22cb1f0 --- /dev/null +++ b/plan/agw/research/preset-release-readiness-2026-10-18/acceptance.log @@ -0,0 +1,10 @@ +DEXES eip155:11155111: destination factory eth_call passed; Push unavailable-in-registry +DEXES eip155:84532: destination factory eth_call passed; Push unavailable-in-registry +DEXES eip155:421614: destination factory eth_call passed; Push unavailable-in-registry +DEXES eip155:97: destination factory eth_call passed; Push unavailable-in-registry +LENDING eip155:11155111: destination factory eth_call passed; Push unavailable-in-registry +LENDING eip155:421614: destination factory eth_call passed; Push unavailable-in-registry +LENDING eip155:84532: destination factory eth_call passed; Push unavailable-in-registry +LENDING eip155:97: destination factory eth_call passed; Push unavailable-in-registry +STAKING eip155:11155111: destination factory eth_call passed; Push unavailable-in-registry +Read-only report: /tmp/preset-release-acceptance.json; 9/9 passed. diff --git a/plan/agw/research/preset-release-readiness-2026-10-18/api.json b/plan/agw/research/preset-release-readiness-2026-10-18/api.json new file mode 100644 index 00000000..4837405e --- /dev/null +++ b/plan/agw/research/preset-release-readiness-2026-10-18/api.json @@ -0,0 +1,64 @@ +{ + "baseline": "b1597b91a25dbf7f691f589b4e1e154add604315", + "head": "2d16bfe0429fd680558eca1a48bf983358940698", + "compiledMatchesSource": true, + "initializeSignatureChanged": false, + "addedExports": [ + "AgenticPresets", + "ArgumentPath", + "DecodedSolanaRule", + "Pin", + "Preset", + "PresetAsset", + "PresetCallIssue", + "PresetCategory", + "PresetChainReadiness", + "PresetConfigurationIssue", + "PresetOptions", + "PresetResult", + "PresetRuleTemplate", + "ReadyPresetOptions", + "RuleInput", + "Spent", + "WalletMarker" + ], + "removedExports": [ + "AgenticNetworkConstants", + "NativeRule", + "UniversalRule" + ], + "publicTypeChanges": [ + "AGENTIC_ERROR_CODE", + "AgenticError", + "AgenticRevertError", + "AgenticErrorCode", + "AgenticTxMetadata", + "AgenticWallet", + "AllowedCall", + "AssetCap", + "CreateOptions", + "DecodedSolanaRule", + "Rule", + "RuleInput", + "Pin", + "Spent", + "WalletMarker", + "ArgumentPath", + "RulesRecord", + "Preset", + "PresetCategory", + "PresetAsset", + "PresetOptions", + "ReadyPresetOptions", + "PresetRuleTemplate", + "PresetResult", + "PresetChainReadiness", + "PresetConfigurationIssue", + "PresetCallIssue", + "AgenticPresets" + ], + "transactionMethodChanges": [], + "instanceMethodChanges": [], + "agwConstantsChanged": true, + "scope": "Summary of check-agw-api.js output; redundant full source/declaration snapshots omitted." +} diff --git a/plan/agw/research/preset-release-readiness-2026-10-18/build.log b/plan/agw/research/preset-release-readiness-2026-10-18/build.log new file mode 100644 index 00000000..8eff7773 --- /dev/null +++ b/plan/agw/research/preset-release-readiness-2026-10-18/build.log @@ -0,0 +1,11 @@ + +> nx run core:build + +Compiling TypeScript files for project "core"... +Done compiling TypeScript files for project "core". +(node:42929) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. +(Use `node --trace-warnings ...` to show where the warning was created) + + + + NX Successfully ran target build for project core diff --git a/plan/agw/research/preset-release-readiness-2026-10-18/docs.log b/plan/agw/research/preset-release-readiness-2026-10-18/docs.log new file mode 100644 index 00000000..2755478b --- /dev/null +++ b/plan/agw/research/preset-release-readiness-2026-10-18/docs.log @@ -0,0 +1 @@ +AGW guide: 6 TypeScript blocks typechecked against public exports; no examples executed. diff --git a/plan/agw/research/preset-release-readiness-2026-10-18/full-unit.log b/plan/agw/research/preset-release-readiness-2026-10-18/full-unit.log new file mode 100644 index 00000000..2e996935 --- /dev/null +++ b/plan/agw/research/preset-release-readiness-2026-10-18/full-unit.log @@ -0,0 +1,184 @@ +PASS core packages/core/src/lib/universal/account/account.spec.ts (6.588 s) + ● Console + + console.warn + [PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead. + + 207 | ): Promise { + 208 | if (!_convertOriginToExecutorWarned) { + > 209 | console.warn( + | ^ + 210 | '[PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead.' + 211 | ); + 212 | _convertOriginToExecutorWarned = true; + + at Object.convertOriginToExecutor (src/lib/universal/account/account.ts:209:13) + at Object. (src/lib/universal/account/account.spec.ts:80:52) + + console.warn + [PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead. + + 425 | ): Promise { + 426 | if (!options?._internal && !_convertExecutorToOriginWarned) { + > 427 | console.warn( + | ^ + 428 | '[PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead.' + 429 | ); + 430 | _convertExecutorToOriginWarned = true; + + at convertExecutorToOrigin (src/lib/universal/account/account.ts:427:13) + at Object. (src/lib/universal/account/account.spec.ts:106:38) + +PASS core packages/core/src/lib/universal/prc20-address.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/block-results-client.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-tx-retry.spec.ts +PASS core packages/core/src/lib/push-client/push-client.archive-fallback.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-backend.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-confirmation-gate.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/funds-only-burn-guard.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/preset-catalog.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/public-rule.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-quote.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/read-tx-spec-strings.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-timeout-clamp.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-usd-sizer.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/response-surface.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/preset-routes.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/native-multi-action.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r2-outbound-revert-flow.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/presets.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/inbound-payload.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/preset-default-policy.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/runtime-token-chain.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/send.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/preset-default-tokens.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/reads-context.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-request-recipient.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/registry.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/preset-operation-limits.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/account-status.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-executor.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/inbound-tracker-derivation.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-svm-confirmation.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/source-hash-resolution.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/svm-account.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/execute-standard-required-funds.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-tracker.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg.spec.ts +PASS core packages/core/src/lib/universal/signer/signer.spec.ts +PASS core packages/core/src/lib/utils.spec.ts + ● Console + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:973:17) + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:977:17) + + console.log + 1.23 + + at Object. (src/lib/utils.spec.ts:982:17) + +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/chain-namespace.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/response-invariant.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/scenarios.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-detector.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/multichain-hooks.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/management.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/track-transaction-guard.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/context-helpers-tracker.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/signing-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/resolver.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r1-spec-strings.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/labels.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/build-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-classification.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-idl.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/svm-rent.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/web2-compat.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-evm-r3-native-eoa.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/response-builder-push-revert.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/export.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-builder-progress-hook.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/payload-builders.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-svm-rent.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-composition.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/rescue-svm-confirmation.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-svm-r3.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-emission.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gateway-uea-account.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/cascade.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-calculator.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/terminal-suppression.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-event-hook-bridge.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r2-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-native-multicall.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/send-transaction-progress-hook.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/resolve.spec.ts +PASS core packages/core/src/lib/push-client/push-client.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-multichain.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r3-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/gate.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/public-surface.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm-rent-pc20.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-events.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/prc20-source-encoding.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-params.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/spec-builder.spec.ts +PASS core packages/core/src/lib/constants/__tests__/token-constants.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-evm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/revalidate-read.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-wire-fixture.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/result-decoder.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/address-codec.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-svm.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm-log-index.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/ucallback-codec.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/normalize.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/abi-selectors.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/__tests__/signing.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/child-inbounds.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/codec.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.chain-symbol.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/auto-detect.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg-svm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/validate.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.dynamic-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/ix-encoder.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.batch-gas.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-web2.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-types.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/registry.spec.ts +PASS core packages/core/src/lib/constants/__tests__/svm-gateway-idl.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/error-decoder.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/tracking.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/classify.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/max-pc-for-gas.spec.ts +PASS core packages/core/src/lib/formatters.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-execute-order.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/normalize-address.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/budget.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/errors.spec.ts + +Test Suites: 1 skipped, 131 passed, 131 of 132 total +Tests: 12 skipped, 2142 passed, 2154 total +Snapshots: 0 total +Time: 36.23 s, estimated 40 s +Ran all test suites. diff --git a/plan/agw/research/preset-release-readiness-2026-10-18/lint.log b/plan/agw/research/preset-release-readiness-2026-10-18/lint.log new file mode 100644 index 00000000..e69de29b diff --git a/plan/agw/research/preset-release-readiness-2026-10-18/local-types.log b/plan/agw/research/preset-release-readiness-2026-10-18/local-types.log new file mode 100644 index 00000000..e69de29b diff --git a/plan/agw/research/preset-release-readiness-2026-10-18/local.log b/plan/agw/research/preset-release-readiness-2026-10-18/local.log new file mode 100644 index 00000000..17518deb --- /dev/null +++ b/plan/agw/research/preset-release-readiness-2026-10-18/local.log @@ -0,0 +1,29 @@ +PASS core-agw-local packages/core/__agw-local__/v5-multiasset.spec.ts (9.483 s) + v6 multi-asset SDK management and execution + ✓ v6 EVM alternatives enforce both spender and MAX, and reads update losslessly (300 ms) + ✓ v6 refuses a bare alternative that bypasses a pinned function and too many initial rules (53 ms) + ✓ the shipped DEX catalog enforces tuple receiver/token/amount pins on actual v6 URP (231 ms) + ✓ a default-token DEX exactInputSingle call rejects spending above its policy cap despite edited bridge budgets (107 ms) + ✓ a default-token DEX exactOutputSingle call rejects spending above its policy cap despite edited bridge budgets (106 ms) + ✓ public DEXES destination-funded defaults create directly without rewriting returned rules (222 ms) + ✓ public LENDING destination-funded defaults create directly without rewriting returned rules (110 ms) + ✓ public STAKING destination-funded defaults create directly without rewriting returned rules (130 ms) + ✓ regenerated LENDING presets enforce new token/amount pins through atomic rules.update (353 ms) + ✓ regenerated STAKING presets enforce new token/amount pins through atomic rules.update (254 ms) + ✓ a fixture preset produces rules accepted by public create and enforced by real contracts (107 ms) + ✓ public create encodes two ordered assets; public get reconstructs source-token caps (67 ms) + ✓ a token from the wrong chain fails before deployment (12 ms) + ✓ a same-chain registry identity mismatch fails before deployment (4 ms) + ✓ both tokens execute under one rule and keep independent counters/limits (117 ms) + ✓ omitted and explicit zero totals both prohibit movement (101 ms) + ✓ empty user assets grants one zero-cap gas token and executes a call-only request (113 ms) + ✓ public update resets both counters in one batch and records five checkpoints (135 ms) + ✓ spend on the second asset after snapshot rolls back revoke/grant and checkpoint writes (144 ms) + ✓ out-of-band duplicate contract grants still make sends ambiguous (81 ms) + ✓ a legacy two-field envelope is refused by the actual v6 grant path (19 ms) + +Test Suites: 1 passed, 1 total +Tests: 21 passed, 21 total +Snapshots: 0 total +Time: 9.524 s +Ran all test suites within paths "packages/core/__agw-local__/v5-multiasset.spec.ts". diff --git a/plan/agw/research/preset-release-readiness-2026-10-18/package.log b/plan/agw/research/preset-release-readiness-2026-10-18/package.log new file mode 100644 index 00000000..8e1b97e4 --- /dev/null +++ b/plan/agw/research/preset-release-readiness-2026-10-18/package.log @@ -0,0 +1 @@ +AGW package: CJS/ESM imports, compiled declaration examples and npm contents pass. No examples executed/published. diff --git a/plan/agw/research/preset-release-readiness-2026-10-18/routes.json b/plan/agw/research/preset-release-readiness-2026-10-18/routes.json new file mode 100644 index 00000000..3d6d0600 --- /dev/null +++ b/plan/agw/research/preset-release-readiness-2026-10-18/routes.json @@ -0,0 +1,130 @@ +{ + "network": "TESTNET_DONUT", + "chainId": 42101, + "blockNumber": "24369907", + "at": "2026-10-18T05:22:00.084Z", + "readOnly": true, + "records": [ + { + "key": "pETH", + "address": "0x2971824Db68229D087931155C2b8bB820B275809", + "chain": "eip155:11155111", + "source": "0x0000000000000000000000000000000000000000", + "decimals": 18, + "sourceEncoding": "address" + }, + { + "key": "pETH_ARB", + "address": "0xc0a821a1AfEd1322c5e15f1F4586C0B8cE65400e", + "chain": "eip155:421614", + "source": "0x0000000000000000000000000000000000000000", + "decimals": 18 + }, + { + "key": "pETH_BASE", + "address": "0xc7007af2B24D4eb963fc9633B0c66e1d2D90Fc21", + "chain": "eip155:84532", + "source": "0x0000000000000000000000000000000000000000", + "decimals": 18 + }, + { + "key": "pBNB", + "address": "0x7a9082dA308f3fa005beA7dB0d203b3b86664E36", + "chain": "eip155:97", + "source": "0x0000000000000000000000000000000000000000", + "decimals": 18 + }, + { + "key": "pSOL", + "address": "0x5D525Df2bD99a6e7ec58b76aF2fd95F39874EBed", + "error": "Position `32` is out of bounds (`0 < position < 32`)." + }, + { + "key": "USDT_ETH", + "address": "0x0f97A213207703923F5f0C613C9827f7C9A0f96B", + "chain": "eip155:11155111", + "source": "0xC4230aEaFcF6b8B49a7b4e53886420f00ff71876", + "decimals": 6 + }, + { + "key": "USDC_ETH", + "address": "0x7A58048036206bB898008b5bBDA85697DB1e5d66", + "chain": "eip155:11155111", + "source": "0x97F477B7f970D47a87B42869ceeace218106152a", + "decimals": 6 + }, + { + "key": "USDT_ARB", + "address": "0xFE6E9DF2BbC9ce05D98b83B1365df6DcA9951891", + "chain": "eip155:421614", + "source": "0xE30928528f52CAEeB75fB07837e22d77D47e9c07", + "decimals": 6 + }, + { + "key": "USDC_ARB", + "address": "0x1091cCBA2FF8d2A131AE4B35e34cf3308C48572C", + "chain": "eip155:421614", + "source": "0x5dd39b0b3610F666F631a6506b7713EF83e1Ac5C", + "decimals": 6 + }, + { + "key": "USDT_SOL", + "address": "0x4f1A3D22d170a2F4Bddb37845a962322e24f4e34", + "error": "Position `32` is out of bounds (`0 < position < 32`)." + }, + { + "key": "USDC_SOL", + "address": "0x04B8F634ABC7C879763F623e0f0550a4b5c4426F", + "error": "Position `32` is out of bounds (`0 < position < 32`)." + }, + { + "key": "USDT_BSC", + "address": "0x731aF1Da5365259d27528557EE4aFBA4baC90ef2", + "chain": "eip155:97", + "source": "0xE935d9c9C24D02E61186c640cc01d713C876d40F", + "decimals": 6 + }, + { + "key": "USDC_BSC", + "address": "0x120EBf25Dad7D6a09Ad2316f23f9Be95DBb90639", + "chain": "eip155:97", + "source": "0xA8802F96cAd0d45343d9bc660B6f7d80050A660b", + "decimals": 6 + }, + { + "key": "USDT_BASE", + "address": "0x148823809B853e1db187BC09A9ac909BC42F971a", + "chain": "eip155:84532", + "source": "0x4D7646B9eE3D68F4b0F135B5cbc66B00819F6b61", + "decimals": 6 + }, + { + "key": "USDC_BASE", + "address": "0xD7C6cA1e2c0CE260BE0c0AD39C1540de460e3Be1", + "chain": "eip155:84532", + "source": "0x5c3504F0E3bA28FDc1F74234fE936518276AaBB8", + "decimals": 6 + }, + { + "key": "WETH_ETH", + "address": "0x0d0dF7E8807430A81104EA84d926139816eC7586", + "chain": "eip155:11155111", + "source": "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14", + "decimals": 18, + "sourceEncoding": "address" + }, + { + "key": "stETH_ETH", + "address": "0xaf89E805949c628ebde3262e91dc4ab9eA12668E", + "chain": "eip155:11155111", + "source": "0x3e3FE7dBc6B4C189E7128855dD526361c49b40Af", + "decimals": 18, + "sourceEncoding": "address" + }, + { + "key": "DAI_SOL", + "address": "0x5861f56A556c990358cc9cccd8B5baa3767982A8", + "error": "Position `32` is out of bounds (`0 < position < 32`)." + } + ] +} \ No newline at end of file diff --git a/plan/agw/research/preset-release-readiness-2026-10-18/types.log b/plan/agw/research/preset-release-readiness-2026-10-18/types.log new file mode 100644 index 00000000..e69de29b diff --git a/plan/agw/research/preset-release-readiness-2026-10-18/v5-build.log b/plan/agw/research/preset-release-readiness-2026-10-18/v5-build.log new file mode 100644 index 00000000..e9cb362e --- /dev/null +++ b/plan/agw/research/preset-release-readiness-2026-10-18/v5-build.log @@ -0,0 +1,11 @@ + +> nx run core:build + +Compiling TypeScript files for project "core"... +Done compiling TypeScript files for project "core". +(node:47418) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. +(Use `node --trace-warnings ...` to show where the warning was created) + + + + NX Successfully ran target build for project core diff --git a/plan/agw/research/preset-release-readiness-2026-10-18/v5-immutable.log b/plan/agw/research/preset-release-readiness-2026-10-18/v5-immutable.log new file mode 100644 index 00000000..95471b88 --- /dev/null +++ b/plan/agw/research/preset-release-readiness-2026-10-18/v5-immutable.log @@ -0,0 +1,26 @@ +➤ YN0000: · Yarn 4.2.2 +➤ YN0000: ┌ Project validation +➤ YN0057: │ @pushprotocol/common-components: Resolutions field will be ignored +➤ YN0057: │ @pushchain/ui-kit: Resolutions field will be ignored +➤ YN0000: └ Completed +➤ YN0000: ┌ Resolution step +➤ YN0000: └ Completed in 0s 346ms +➤ YN0000: ┌ Post-resolution validation +➤ YN0002: │ @pushchain/core@workspace:packages/core doesn't provide @types/node (p360d1), requested by ts-node. +➤ YN0002: │ @pushchain/core@workspace:packages/core doesn't provide typescript (p97602), requested by ts-node. +➤ YN0002: │ @pushchain/ui-kit@workspace:packages/ui-kit doesn't provide eslint (p05da2), requested by typescript-eslint. +➤ YN0002: │ @pushchain/ui-kit@workspace:packages/ui-kit doesn't provide eslint (p7d515), requested by eslint-plugin-react-refresh. +➤ YN0002: │ @pushchain/ui-kit@workspace:packages/ui-kit doesn't provide eslint (pafac7), requested by eslint-plugin-react-hooks. +➤ YN0002: │ @pushchain/ui-kit@workspace:packages/ui-kit doesn't provide typescript (pc5a0d), requested by typescript-eslint. +➤ YN0002: │ @pushprotocol/common-components@workspace:packages/shared-components doesn't provide react-is (p3a3ff), requested by styled-components. +➤ YN0086: │ Some peer dependencies are incorrectly met; run yarn explain peer-requirements for details, where is the six-letter p-prefixed code. +➤ YN0000: └ Completed +➤ YN0000: ┌ Fetch step +➤ YN0066: │ typescript@patch:typescript@npm%3A5.5.4#optional!builtin::version=5.5.4&hash=b45daf: Cannot apply hunk #11 +➤ YN0066: │ typescript@patch:typescript@npm%3A5.6.3#optional!builtin::version=5.6.3&hash=b45daf: Cannot apply hunk #11 +➤ YN0066: │ typescript@patch:typescript@npm%3A5.8.2#optional!builtin::version=5.8.2&hash=b45daf: Cannot apply hunk #1 +➤ YN0013: │ 1675 packages were added to the project (+ 221.38 MiB). +➤ YN0000: └ Completed in 55s 412ms +➤ YN0000: ┌ Link step +➤ YN0000: └ Completed in 9s 365ms +➤ YN0000: · Done with warnings in 1m 6s diff --git a/plan/agw/research/preset-release-readiness-2026-10-18/v5-package.log b/plan/agw/research/preset-release-readiness-2026-10-18/v5-package.log new file mode 100644 index 00000000..8e1b97e4 --- /dev/null +++ b/plan/agw/research/preset-release-readiness-2026-10-18/v5-package.log @@ -0,0 +1 @@ +AGW package: CJS/ESM imports, compiled declaration examples and npm contents pass. No examples executed/published. diff --git a/plan/agw/section7-presets.md b/plan/agw/section7-presets.md index 74adfa10..d7de5529 100644 --- a/plan/agw/section7-presets.md +++ b/plan/agw/section7-presets.md @@ -1,6 +1,6 @@ # Section 7 presets — current alignment -Updated October 15, 2026. [Live SDK §7](https://app.notion.com/p/pushprotocol/5-SDK-AGW-3e9188aea7f481cf8e8de324956549b9#07ce163677ef44dfae03a38ea4c16da0) and the [catalog proposal snapshot](notion/agw-presets-proposal-and-rules.md) are the sources. Work is on v4; non-plan changes are mirrored to v5. +Updated October 18, 2026. [Live SDK §7](https://app.notion.com/p/pushprotocol/5-SDK-AGW-3e9188aea7f481cf8e8de324956549b9#07ce163677ef44dfae03a38ea4c16da0) and the [catalog proposal snapshot](notion/agw-presets-proposal-and-rules.md) are the sources. Work is on v4; non-plan changes are mirrored to v5. ## Approved decisions @@ -34,3 +34,26 @@ Five additional scenarios now pass across focused runs: EigenLayer Sepolia; Base ## October 16 — operation limits and readiness supersede earlier behavior get returns additive readiness metadata; supported lending/staking calls now have token/amount restrictions. Market redemption uses underlying units. Dynamic/position-derived claims are excluded and explained. [Current implementation, API changes and live validation boundary](research/preset-configuration-2026-10-16/README.md). Earlier live runs predate these restrictions; new live attempts timed out during setup and are not accepted as passes. + + +## October 18 — SDK supplies curated tokens + +Riyanshu clarified that presets should include tokens across their networks without frontend token selection. This supersedes the earlier omitted-assets discovery flow: `get` now supplies a curated token subset per chain whenever `assets` is omitted. DEX defaults include a complete pair with generated token constraints. Explicit `assets` replaces defaults, including an empty list or a list covering only some chains. + +Spending caps retain the agreed zero default. Gas and expiry defaults are not invented. Automatic token inclusion is implemented; fully executable presets still require an agreed permission policy. Suggested 10 USDC/call, 100 USDC Push-outbound total and 7-day expiry are proposals only, not shipped defaults; native/other token caps and chain-specific gas budgets require separate values. There is no implied conversion to USD, batch aggregate cap or destination lifetime cap. + +The default subsets use existing reviewed catalog/source addresses and fit the deployed 32-call/32-pin ceilings. Mainnet remains template-only and no new funded live run is performed for this change. See the [consumer guide](../../packages/core/AGW.md) for the per-network token table and replacement semantics. + + +## October 18 — default permission policy approved and implemented + +The user authorized preset-generated limits, gas budgets and expiry. This supersedes the pending-policy note above. Omitted assets selects curated tokens with explicit caps: stablecoins 10/call and 100 cumulative Push-outbound; ETH-family 0.001/0.01; WBNB 0.01/0.1; LINK 1/10. Decimals were checked by chain/address using read-only RPC calls at recorded blocks. Omitted expiry becomes seven days from get time; the catalog gas ceiling is 20 PC. Actual sends still quote at runtime. Mainnet execution is not newly certified. + +Supplying only agent (plus an optional chain filter) now produces typed Rule[] and complete local configuration. Explicit expiry/gas and asset arrays remain authoritative; zero gas and zero asset caps are preserved. General rule authoring keeps zero defaults. No public helper or new required argument is introduced. + +Operational prerequisites remain: asset PRC20 mappings, funded source/destination accounts, protocol liquidity and live routes. Some testnet protocol mocks have no PRC20 mapping; their prior live tests used prefunded CEAs with bridge assets empty. Configuration readiness does not guarantee that those default source assets can be bridged or that an unmodified default rule can be created on every network. No unavailable mapping is fabricated or silently dropped. + + +## October 18 — release correction for funding availability + +Configuration completeness alone is no longer advertised as readiness. Ready additionally checks the SDK's verified AGW network registry, supported gateway destinations and selected source-token registry. Push mode preserves missing assets and reports them. Destination mode explicitly requests empty bridge authority with unchanged call constraints and selectedAssets review metadata. This is additive and avoids inventing PRC20 identities. Sepolia WETH/stETH mappings and EVM address-word source metadata are now supported and read-only verified. [Final release evidence](research/preset-release-readiness-2026-10-18/README.md) supersedes prior readiness descriptions. From 089a0b51bc0acedaed0302afe94cb213feb05bb1 Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Sun, 18 Oct 2026 19:03:50 +0530 Subject: [PATCH 51/68] fix(ci): repair AGW workflow context and pin v6 contracts --- .github/workflows/agw-sdk-validation.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/agw-sdk-validation.yml b/.github/workflows/agw-sdk-validation.yml index af1d14ef..9ff23dca 100644 --- a/.github/workflows/agw-sdk-validation.yml +++ b/.github/workflows/agw-sdk-validation.yml @@ -15,7 +15,6 @@ jobs: env: NX_DAEMON: 'false' AGW_REPO: ${{ github.workspace }}/.ci-contracts - AGW_LOCAL_DIR: ${{ runner.temp }}/agw-v5-build steps: - uses: actions/checkout@v5 with: @@ -23,7 +22,7 @@ jobs: - uses: actions/checkout@v5 with: repository: pushchain/push-agentic-wallets - ref: 2e61e133e641b4e0e1ddbdc9306b0903b60e4dbb + ref: ffd567d3e49b2d27c6f50ad36093274dbac3090f path: .ci-contracts persist-credentials: false - uses: actions/setup-node@v6 @@ -36,6 +35,8 @@ jobs: - run: corepack enable - run: yarn install --immutable - name: Unit, contracts, types, docs and package checks + env: + AGW_LOCAL_DIR: ${{ runner.temp }}/agw-v6-build run: node packages/core/scripts/agw-verify.js - uses: actions/upload-artifact@v4 if: always() From 5eee8bbba7e72439bc1765e5dd7756b9bf6ae1ab Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Sun, 18 Oct 2026 19:20:55 +0530 Subject: [PATCH 52/68] fix(ci): repair invalid dependency ranges for hardened installs --- .github/workflows/agw-sdk-validation.yml | 1 + yarn.lock | 95 +++++++++++++++++++++++- 2 files changed, 94 insertions(+), 2 deletions(-) diff --git a/.github/workflows/agw-sdk-validation.yml b/.github/workflows/agw-sdk-validation.yml index 9ff23dca..8db87790 100644 --- a/.github/workflows/agw-sdk-validation.yml +++ b/.github/workflows/agw-sdk-validation.yml @@ -14,6 +14,7 @@ jobs: timeout-minutes: 30 env: NX_DAEMON: 'false' + YARN_ENABLE_HARDENED_MODE: '1' AGW_REPO: ${{ github.workspace }}/.ci-contracts steps: - uses: actions/checkout@v5 diff --git a/yarn.lock b/yarn.lock index 1a09b363..50dbcabb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1464,6 +1464,13 @@ __metadata: languageName: node linkType: hard +"@babel/runtime@npm:^7.12.5": + version: 7.29.10 + resolution: "@babel/runtime@npm:7.29.10" + checksum: 10/883bb39a09f4773cf46cdd7ba0080ef6b30ff996a4ed21f8d34511ec0836122e697716533da5efc9b5016f763110b19aa07e81cec6e2036fe72cb26aad556af2 + languageName: node + linkType: hard + "@babel/runtime@npm:^7.5.5": version: 7.27.6 resolution: "@babel/runtime@npm:7.27.6" @@ -8860,7 +8867,7 @@ __metadata: languageName: node linkType: hard -"babel-plugin-macros@npm:^2.8.0, babel-plugin-macros@npm:^3.1.0": +"babel-plugin-macros@npm:^2.8.0": version: 2.8.0 resolution: "babel-plugin-macros@npm:2.8.0" dependencies: @@ -8871,6 +8878,17 @@ __metadata: languageName: node linkType: hard +"babel-plugin-macros@npm:^3.1.0": + version: 3.1.0 + resolution: "babel-plugin-macros@npm:3.1.0" + dependencies: + "@babel/runtime": "npm:^7.12.5" + cosmiconfig: "npm:^7.0.0" + resolve: "npm:^1.19.0" + checksum: 10/30be6ca45e9a124c58ca00af9a0753e5410ec0b79a737714fc4722bbbeb693e55d9258f05c437145ef4a867c2d1603e06a1c292d66c243ce1227458c8ea2ca8c + languageName: node + linkType: hard + "babel-plugin-polyfill-corejs2@npm:^0.4.10": version: 0.4.13 resolution: "babel-plugin-polyfill-corejs2@npm:0.4.13" @@ -9631,7 +9649,7 @@ __metadata: languageName: node linkType: hard -"commander@npm:^13.1.0, commander@npm:^4.0.0": +"commander@npm:^13.1.0": version: 13.1.0 resolution: "commander@npm:13.1.0" checksum: 10/d3b4b79e6be8471ddadacbb8cd441fe82154d7da7393b50e76165a9e29ccdb74fa911a186437b9a211d0fc071db6051915c94fb8ef16d77511d898e9dbabc6af @@ -9645,6 +9663,13 @@ __metadata: languageName: node linkType: hard +"commander@npm:^4.0.0": + version: 4.1.1 + resolution: "commander@npm:4.1.1" + checksum: 10/3b2dc4125f387dab73b3294dbcb0ab2a862f9c0ad748ee2b27e3544d25325b7a8cdfbcc228d103a98a716960b14478114a5206b5415bd48cdafa38797891562c + languageName: node + linkType: hard + "compare-func@npm:^2.0.0": version: 2.0.0 resolution: "compare-func@npm:2.0.0" @@ -9870,6 +9895,19 @@ __metadata: languageName: node linkType: hard +"cosmiconfig@npm:^7.0.0": + version: 7.1.0 + resolution: "cosmiconfig@npm:7.1.0" + dependencies: + "@types/parse-json": "npm:^4.0.0" + import-fresh: "npm:^3.2.1" + parse-json: "npm:^5.0.0" + path-type: "npm:^4.0.0" + yaml: "npm:^1.10.0" + checksum: 10/03600bb3870c80ed151b7b706b99a1f6d78df8f4bdad9c95485072ea13358ef294b13dd99f9e7bf4cc0b43bcd3599d40df7e648750d21c2f6817ca2cd687e071 + languageName: node + linkType: hard + "cosmiconfig@npm:^9.0.0": version: 9.0.0 resolution: "cosmiconfig@npm:9.0.0" @@ -12178,6 +12216,15 @@ __metadata: languageName: node linkType: hard +"hasown@npm:^2.0.4": + version: 2.0.4 + resolution: "hasown@npm:2.0.4" + dependencies: + function-bind: "npm:^1.1.2" + checksum: 10/13823863ae48161068b4c51606a3128451c66f14545a5169d667fe9fca168dcd38c27570c7a299e32ef844b8da3d55def7fe88602f8970d4311fb543ee88001a + languageName: node + linkType: hard + "he@npm:^1.2.0": version: 1.2.0 resolution: "he@npm:1.2.0" @@ -12541,6 +12588,15 @@ __metadata: languageName: node linkType: hard +"is-core-module@npm:^2.17.0": + version: 2.17.0 + resolution: "is-core-module@npm:2.17.0" + dependencies: + hasown: "npm:^2.0.4" + checksum: 10/0020f71b7eb525ccd684012cd1cfba235e7596e0addbc993732f7d8faff7ccd3a399e16dac7eb317b63459ea23f97efd661d6bf32584f6bf1d0a607fd8e21a6b + languageName: node + linkType: hard + "is-deflate@npm:^1.0.0": version: 1.0.0 resolution: "is-deflate@npm:1.0.0" @@ -16245,6 +16301,20 @@ __metadata: languageName: node linkType: hard +"resolve@npm:^1.19.0": + version: 1.22.13 + resolution: "resolve@npm:1.22.13" + dependencies: + es-errors: "npm:^1.3.0" + is-core-module: "npm:^2.17.0" + path-parse: "npm:^1.0.7" + supports-preserve-symlinks-flag: "npm:^1.0.0" + bin: + resolve: bin/resolve + checksum: 10/4fc4242f448c5a679921bbac6e74268ca76893d7379cb9cfaa49f40ce6b1cea884c2df901d0617c92d927375fe66a05ccbbf17bbb0262cdcd6cb196e33fa1baa + languageName: node + linkType: hard + "resolve@patch:resolve@npm%3A^1.1.7#optional!builtin, resolve@patch:resolve@npm%3A^1.12.0#optional!builtin, resolve@patch:resolve@npm%3A^1.14.2#optional!builtin, resolve@patch:resolve@npm%3A^1.20.0#optional!builtin, resolve@patch:resolve@npm%3A^1.22.8#optional!builtin, resolve@patch:resolve@npm%3A~1.22.1#optional!builtin, resolve@patch:resolve@npm%3A~1.22.2#optional!builtin": version: 1.22.10 resolution: "resolve@patch:resolve@npm%3A1.22.10#optional!builtin::version=1.22.10&hash=c3c19d" @@ -16258,6 +16328,20 @@ __metadata: languageName: node linkType: hard +"resolve@patch:resolve@npm%3A^1.19.0#optional!builtin": + version: 1.22.13 + resolution: "resolve@patch:resolve@npm%3A1.22.13#optional!builtin::version=1.22.13&hash=c3c19d" + dependencies: + es-errors: "npm:^1.3.0" + is-core-module: "npm:^2.17.0" + path-parse: "npm:^1.0.7" + supports-preserve-symlinks-flag: "npm:^1.0.0" + bin: + resolve: bin/resolve + checksum: 10/f0b8e2c897327b5edc4b277c90d19c7bd06975817183ef51f5c79367b8b8e6d637f6ca20ba6eb3ef964944157cc2eb6970fef1c2202edbe65e6e7be4f268fc7f + languageName: node + linkType: hard + "restore-cursor@npm:^3.1.0": version: 3.1.0 resolution: "restore-cursor@npm:3.1.0" @@ -18771,6 +18855,13 @@ __metadata: languageName: node linkType: hard +"yaml@npm:^1.10.0": + version: 1.10.3 + resolution: "yaml@npm:1.10.3" + checksum: 10/e2ef2feb92c708138f016c69777a0f1e45f6d3c5e7cbcda30807a98a37eda2e008bd4fa57352b043c65245a4c799d0c99d1f9b3425de40e70929e26d2ea38215 + languageName: node + linkType: hard + "yaml@npm:^1.7.2": version: 1.10.2 resolution: "yaml@npm:1.10.2" From 6108348fe573f5879cd00369d68ebb0342c04706 Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Sun, 18 Oct 2026 19:46:31 +0530 Subject: [PATCH 53/68] perf(ci): keep automatic AGW validation SDK-only --- .github/workflows/agw-sdk-validation.yml | 28 ++++++++- packages/core/scripts/agw-local/prepare.sh | 8 ++- packages/core/scripts/agw-verify.js | 70 ++++++++++++---------- 3 files changed, 73 insertions(+), 33 deletions(-) diff --git a/.github/workflows/agw-sdk-validation.yml b/.github/workflows/agw-sdk-validation.yml index 8db87790..67a23a41 100644 --- a/.github/workflows/agw-sdk-validation.yml +++ b/.github/workflows/agw-sdk-validation.yml @@ -1,8 +1,19 @@ name: AGW SDK validation (unfunded) on: pull_request: - paths: ['packages/core/**', 'tsconfig.base.json', 'yarn.lock', '.github/workflows/agw-sdk-validation.yml'] + paths: + [ + 'packages/core/**', + 'tsconfig.base.json', + 'yarn.lock', + '.github/workflows/agw-sdk-validation.yml', + ] workflow_dispatch: + inputs: + contracts: + description: 'Run contract suites and full API checks (slower)' + type: boolean + default: false permissions: contents: read concurrency: @@ -21,6 +32,7 @@ jobs: with: persist-credentials: false - uses: actions/checkout@v5 + if: github.event_name == 'workflow_dispatch' && inputs.contracts with: repository: pushchain/push-agentic-wallets ref: ffd567d3e49b2d27c6f50ad36093274dbac3090f @@ -31,17 +43,29 @@ jobs: node-version: '24.18.0' package-manager-cache: false - uses: foundry-rs/foundry-toolchain@v1 + if: github.event_name == 'workflow_dispatch' && inputs.contracts with: version: v1.5.1 - run: corepack enable + - uses: actions/cache@v4 + with: + path: .yarn/cache + key: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock') }} + restore-keys: ${{ runner.os }}-yarn- - run: yarn install --immutable - - name: Unit, contracts, types, docs and package checks + - name: SDK tests, types, build and package checks + if: github.event_name != 'workflow_dispatch' || !inputs.contracts + run: node packages/core/scripts/agw-verify.js --sdk-only + - name: Full unfunded contract and SDK checks + if: github.event_name == 'workflow_dispatch' && inputs.contracts env: AGW_LOCAL_DIR: ${{ runner.temp }}/agw-v6-build + AGW_ALLOW_COMPILER_DOWNLOAD: '1' run: node packages/core/scripts/agw-verify.js - uses: actions/upload-artifact@v4 if: always() with: name: agw-unfunded-validation path: .agw-validation/ + include-hidden-files: true if-no-files-found: ignore diff --git a/packages/core/scripts/agw-local/prepare.sh b/packages/core/scripts/agw-local/prepare.sh index 6e3d487e..2796fe8a 100755 --- a/packages/core/scripts/agw-local/prepare.sh +++ b/packages/core/scripts/agw-local/prepare.sh @@ -7,6 +7,8 @@ # so the clone's working tree, branches and index are never touched. # AGW_PIN commit to extract (default: the reviewed v6). # OUT destination directory (default: $TMPDIR/push-agw-local-). +# AGW_ALLOW_COMPILER_DOWNLOAD=1 permits Foundry to install the pinned Solidity +# compiler on a fresh CI runner. Default keeps compilation offline. # # The script extracts the pinned tree, fetches each git submodule at the exact # commit recorded in that tree, copies the harness-only contracts from @@ -44,5 +46,9 @@ fi mkdir -p "$OUT/sdk-harness" cp "$HERE"/contracts/*.sol "$OUT/sdk-harness/" -(cd "$OUT" && forge build --offline src sdk-harness lib/smartsessions/contracts/SmartSession.sol lib/openzeppelin-contracts/contracts/proxy >/dev/null) +AGW_BUILD_ARGS=(src sdk-harness lib/smartsessions/contracts/SmartSession.sol lib/openzeppelin-contracts/contracts/proxy) +if [ "${AGW_ALLOW_COMPILER_DOWNLOAD:-0}" != "1" ]; then + AGW_BUILD_ARGS=(--offline "${AGW_BUILD_ARGS[@]}") +fi +(cd "$OUT" && forge build "${AGW_BUILD_ARGS[@]}" >/dev/null) echo "$OUT" diff --git a/packages/core/scripts/agw-verify.js b/packages/core/scripts/agw-verify.js index 3ac74f72..6767f8de 100644 --- a/packages/core/scripts/agw-verify.js +++ b/packages/core/scripts/agw-verify.js @@ -3,6 +3,7 @@ const { spawnSync } = require('node:child_process'); const fs = require('node:fs'); const path = require('node:path'); const root = path.resolve(__dirname, '../../..'); +const sdkOnly = process.argv.includes('--sdk-only'); const dir = path.join(root, '.agw-validation'); fs.mkdirSync(dir, { recursive: true }); function run(name, file, args, options = {}) { @@ -16,6 +17,8 @@ function run(name, file, args, options = {}) { const out = String(result.stdout || '') + String(result.stderr || ''); fs.writeFileSync(path.join(dir, `${name}.log`), out); if (result.error || result.status !== 0) { + process.stderr.write(out); + if (result.error) process.stderr.write(String(result.error) + '\n'); throw new Error( `AGW validation failed: ${name}; see .agw-validation/${name}.log` ); @@ -28,37 +31,39 @@ run('units', node, [ '--config', 'packages/core/jest.config.ts', '--runInBand', - '--testPathPattern=agentic|outbound-(confirmation-gate|svm-confirmation)|svm-idl|evm-client.batch-gas', + '--testPathPattern=agentic|prc20-address|outbound-(confirmation-gate|svm-confirmation)|svm-idl|evm-client.batch-gas', ]); -for (const kind of ['lib', 'spec', 'agw-local']) +for (const kind of sdkOnly ? ['spec'] : ['lib', 'spec', 'agw-local']) run(`types-${kind}`, node, [ 'node_modules/typescript/bin/tsc', '-p', `packages/core/tsconfig.${kind}.json`, '--noEmit', ]); -run('docs', node, ['packages/core/scripts/check-agw-docs.js']); -const env = { - ...process.env, - OUT: process.env.AGW_LOCAL_DIR || path.join(dir, 'contracts'), -}; -run( - 'prepare-contracts', - 'bash', - ['packages/core/scripts/agw-local/prepare.sh'], - { env } -); -run( - 'local-contracts', - node, - [ - 'node_modules/jest/bin/jest.js', - '--config', - 'packages/core/jest.agw-local.config.ts', - '--runInBand', - ], - { env: { ...env, AGW_LOCAL_DIR: env.OUT } } -); +if (!sdkOnly) { + run('docs', node, ['packages/core/scripts/check-agw-docs.js']); + const env = { + ...process.env, + OUT: process.env.AGW_LOCAL_DIR || path.join(dir, 'contracts'), + }; + run( + 'prepare-contracts', + 'bash', + ['packages/core/scripts/agw-local/prepare.sh'], + { env } + ); + run( + 'local-contracts', + node, + [ + 'node_modules/jest/bin/jest.js', + '--config', + 'packages/core/jest.agw-local.config.ts', + '--runInBand', + ], + { env: { ...env, AGW_LOCAL_DIR: env.OUT } } + ); +} run( 'build', node, @@ -66,9 +71,14 @@ run( { env: { ...process.env, NX_DAEMON: 'false' } } ); run('package', node, ['packages/core/scripts/check-agw-package.js']); -run('public-api', node, [ - 'packages/core/scripts/check-agw-api.js', - '--output', - path.join(dir, 'api-comparison.json'), -]); -process.stdout.write('AGW unfunded validation completed.\n'); +if (!sdkOnly) + run('public-api', node, [ + 'packages/core/scripts/check-agw-api.js', + '--output', + path.join(dir, 'api-comparison.json'), + ]); +process.stdout.write( + sdkOnly + ? 'AGW SDK-only validation completed.\n' + : 'AGW unfunded validation completed.\n' +); From 4206fae6bf6a92e454473a03b3cb615b3dd41324 Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Sun, 18 Oct 2026 19:48:06 +0530 Subject: [PATCH 54/68] docs(agw): record CI repairs and lightweight release checks --- plan/agw/implementation-status.md | 4 ++ .../README.md | 16 ++++++++ .../all-local-contracts.log | 31 +++++++++++++++ .../ci-focused-unit.log | 38 ++++++++++++++++++ .../full-unfunded.log | 11 ++++++ .../hardened-lock-regeneration.log | 27 +++++++++++++ .../lock-audit.json | 10 +++++ .../manual-compiler-prepare.log | 1 + .../sdk-only-units.log | 39 +++++++++++++++++++ .../sdk-only-validation.log | 5 +++ .../sdk-only-workflow-lint.log | 0 .../v5-hardened-immutable.log | 22 +++++++++++ .../workflow-after.log | 0 .../workflow-before.log | 4 ++ 14 files changed, 208 insertions(+) create mode 100644 plan/agw/research/preset-release-readiness-2026-10-18/all-local-contracts.log create mode 100644 plan/agw/research/preset-release-readiness-2026-10-18/ci-focused-unit.log create mode 100644 plan/agw/research/preset-release-readiness-2026-10-18/full-unfunded.log create mode 100644 plan/agw/research/preset-release-readiness-2026-10-18/hardened-lock-regeneration.log create mode 100644 plan/agw/research/preset-release-readiness-2026-10-18/lock-audit.json create mode 100644 plan/agw/research/preset-release-readiness-2026-10-18/manual-compiler-prepare.log create mode 100644 plan/agw/research/preset-release-readiness-2026-10-18/sdk-only-units.log create mode 100644 plan/agw/research/preset-release-readiness-2026-10-18/sdk-only-validation.log create mode 100644 plan/agw/research/preset-release-readiness-2026-10-18/sdk-only-workflow-lint.log create mode 100644 plan/agw/research/preset-release-readiness-2026-10-18/v5-hardened-immutable.log create mode 100644 plan/agw/research/preset-release-readiness-2026-10-18/workflow-after.log create mode 100644 plan/agw/research/preset-release-readiness-2026-10-18/workflow-before.log diff --git a/plan/agw/implementation-status.md b/plan/agw/implementation-status.md index bddd7318..3c524e76 100644 --- a/plan/agw/implementation-status.md +++ b/plan/agw/implementation-status.md @@ -1,5 +1,9 @@ # AGW SDK implementation status +**October 18 — lighter CI requested:** PR checks now run SDK-only validation (421 focused units, spec types, build and package checks); contract checkout/Foundry/full API checks are manual opt-in. Local fast checks pass. Release branch v5 `b291b873` is pushed; package publication remains manual. **2,142 full units**, **107 local contract tests** and **9/9 read-only factory simulations** remain the release evidence. The optional fresh-run full CI preparation failure is documented, not reported as passing. + +**October 18 — final CI repairs:** invalid runner context and stale contract checkout pin are corrected; two incompatible merged dependency ranges were regenerated with Yarn hardened mode. Clean hardened immutable install passes on v5 `66dc81f8`. The full unfunded verifier passes locally, including **107 local contract tests**, in addition to **2,142 full units** and **9/9 Donut factory simulations**. [Final evidence](research/preset-release-readiness-2026-10-18/README.md). + **October 18 — alpha release readiness:** automatic token/permission defaults, route-aware readiness and explicit destination-funded grants are committed on v4 `2d16bfe0` / v5 `83f9a713`. Sepolia WETH/stETH mappings and address-word metadata are fixed. **2,142 units**, **21 local contract tests**, **9/9 read-only Donut factory simulations**, package checks and isolated v5 immutable install pass. No funded live run or publication was triggered. [Release evidence and limits](research/preset-release-readiness-2026-10-18/README.md). Earlier same-day entries are intermediate states. **October 18 — preset permission defaults:** user-approved explicit preset policy now supplies token caps, 20 PC outbound ceilings and seven-day expiries. An agent alone returns Rule[] and complete configuration; general-rule/explicit-asset zero defaults remain. **2,129 unit tests**, **18 local contract tests**, build/typechecks/package checks pass. Existing PRC20 availability still limits unmodified default-asset grants. [Preset policy evidence](research/preset-permission-policy-2026-10-18/README.md). diff --git a/plan/agw/research/preset-release-readiness-2026-10-18/README.md b/plan/agw/research/preset-release-readiness-2026-10-18/README.md index d15f3bb0..645c9898 100644 --- a/plan/agw/research/preset-release-readiness-2026-10-18/README.md +++ b/plan/agw/research/preset-release-readiness-2026-10-18/README.md @@ -36,3 +36,19 @@ No funded live E2E was repeated for this release. Previous Aave/EigenLayer/BNB l Use presets.get(category, { agent, chainNamespace, funding: 'destination' }) for prefunded destination execution. Display selectedAssets as token permissions; returned rules.assets is Push bridge authority and intentionally empty in that mode. Check readiness.ready and show issues. Use default Push mode only with registered, verified source routes. Missing routes and mainnet execution remain external availability limits, not reasons to invent registry entries. The repository read-only checker is packages/core/scripts/check-agw-preset-routes.js. It runs against built artifacts, never loads keys, and is excluded from the npm package. Publishing remains manual; select feat/agw-sdk-v5 and an alpha release. + +## CI repair and complete unfunded command + +The first pushed workflow was rejected before starting jobs: runner.temp was used at job-level env where that context is unavailable. Actionlint reproduced the exact diagnostic; moving the value to step env validates. The checkout was also still pinned to 2e61e1 while the harness defaults to deployed v6 ffd567d. Both were aligned. Workflow fix commits: v4 089a0b51 / v5 21857417. GitHub's [context availability reference](https://docs.github.com/en/actions/reference/workflows-and-actions/contexts) confirms the distinction. + +Once jobs could start, GitHub's hardened public-PR install exposed two pre-existing invalid merged lock descriptors: babel-plugin-macros ^3.1.0 resolving to 2.8.0, and commander ^4.0.0 resolving to 13.1.0. Kept the older versions for their compatible consumers, split the incompatible descriptors and regenerated through Yarn with hardened mode enabled. Yarn resolved macros 3.1.0, commander 4.1.1 and their required transitive entries. V4 5eee8bbb and v5 66dc81f8 contain the correction; hardened checking stays enabled in CI. V5 preserves its alpha.2 workspace/version-specific resolution. Clean hardened immutable install passed against the exact v5 lock. The earlier ordinary immutable-install result did not exercise public-PR hardened validation. + +The full repository agw-verify.js command also passed locally: 417 focused units, all three typechecks, docs, pinned contract preparation, **107 real local contract tests across 13 suites**, build, package and public API checks. This broadens the earlier 21-test subset. The command loads no .env, broadcasts no transactions and invokes no publish action. Full unit coverage separately remains 2,142 passed / 12 skipped. + +## User-requested lighter CI + +The user clarified that CI is lower priority and should be faster. V4 6108348f / v5 b291b873 switches PR validation to agw-verify.js --sdk-only: **421 focused units**, spec typecheck, build (including library types) and compiled package/guide checks. This command passed locally. It skips the external contract checkout, Foundry setup/compilation, full contract suites, duplicate standalone guide check and full API comparison. Full unit coverage separately remains 2,142 and all local contracts separately passed 107. + +The full unfunded path remains manual via workflow_dispatch with contracts=true. Yarn package archives are cached; hardened immutable install remains enabled. The fresh hosted full run passed installation, units, types and docs but failed at contract preparation; its hidden artifact folder was not uploaded, so the exact nested error was not available. Added failed-command output to the console, enabled upload of the explicit validation folder, and allowed downloading the pinned compiler on fresh manual CI runners. Default local preparation remains offline. The manual fresh-run path is not represented as remotely passing; local full verification passed. No funded run or publish was dispatched. + +Publishing the next alpha is based on the completed local tests, 9/9 read-only factory simulations, package checks and hardened v5 lock validation. We are not waiting on the optional heavy CI job at the user's request. Publishing remains the user's manual action from feat/agw-sdk-v5. diff --git a/plan/agw/research/preset-release-readiness-2026-10-18/all-local-contracts.log b/plan/agw/research/preset-release-readiness-2026-10-18/all-local-contracts.log new file mode 100644 index 00000000..383986cc --- /dev/null +++ b/plan/agw/research/preset-release-readiness-2026-10-18/all-local-contracts.log @@ -0,0 +1,31 @@ +PASS core-agw-local packages/core/__agw-local__/agw-local-advanced.spec.ts (8.504 s) +PASS core-agw-local packages/core/__agw-local__/svm-public.spec.ts (5.283 s) +PASS core-agw-local packages/core/__agw-local__/svm-backend.spec.ts (7.266 s) +PASS core-agw-local packages/core/__agw-local__/agw-local.spec.ts +PASS core-agw-local packages/core/__agw-local__/svm-differential.spec.ts + ● Console + + console.log + {"corpus":"svm-grant","seed":23063,"cases":107,"accepted":37,"rejected":70,"mismatches":[]} + + at Object. (__agw-local__/svm-differential.spec.ts:226:13) + + console.log + {"corpus":"svm-payload","seed":23063,"cases":88,"accepted":6,"rejected":82,"mismatches":[]} + + at Object. (__agw-local__/svm-differential.spec.ts:407:13) + +PASS core-agw-local packages/core/__agw-local__/svm-internals.spec.ts +PASS core-agw-local packages/core/__agw-local__/delayed-index.spec.ts +PASS core-agw-local packages/core/__agw-local__/native-multi-action.spec.ts +PASS core-agw-local packages/core/__agw-local__/vectors.spec.ts +PASS core-agw-local packages/core/__agw-local__/agw-local-races.spec.ts +PASS core-agw-local packages/core/__agw-local__/labels.spec.ts +PASS core-agw-local packages/core/__agw-local__/agw-local-batch.spec.ts +PASS core-agw-local packages/core/__agw-local__/v5-multiasset.spec.ts (8.595 s) + +Test Suites: 13 passed, 13 total +Tests: 107 passed, 107 total +Snapshots: 0 total +Time: 47.355 s +Ran all test suites. diff --git a/plan/agw/research/preset-release-readiness-2026-10-18/ci-focused-unit.log b/plan/agw/research/preset-release-readiness-2026-10-18/ci-focused-unit.log new file mode 100644 index 00000000..6e60d573 --- /dev/null +++ b/plan/agw/research/preset-release-readiness-2026-10-18/ci-focused-unit.log @@ -0,0 +1,38 @@ +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-confirmation-gate.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/response-surface.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/preset-default-tokens.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/preset-catalog.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/preset-default-policy.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/presets.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/preset-routes.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/preset-operation-limits.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/labels.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-svm-confirmation.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/build-payload.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/send.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/public-rule.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/management.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/runtime-token-chain.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/resolve.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-backend.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-idl.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/reads-context.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-quote.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/native-multi-action.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-wire-fixture.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/prc20-source-encoding.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/codec.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/registry.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.batch-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/ix-encoder.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/normalize-address.spec.ts + +Test Suites: 32 passed, 32 total +Tests: 417 passed, 417 total +Snapshots: 0 total +Time: 7.869 s, estimated 8 s +Ran all test suites matching /agentic|outbound-(confirmation-gate|svm-confirmation)|svm-idl|evm-client.batch-gas/i. diff --git a/plan/agw/research/preset-release-readiness-2026-10-18/full-unfunded.log b/plan/agw/research/preset-release-readiness-2026-10-18/full-unfunded.log new file mode 100644 index 00000000..baec7036 --- /dev/null +++ b/plan/agw/research/preset-release-readiness-2026-10-18/full-unfunded.log @@ -0,0 +1,11 @@ +AGW validation: units +AGW validation: types-lib +AGW validation: types-spec +AGW validation: types-agw-local +AGW validation: docs +AGW validation: prepare-contracts +AGW validation: local-contracts +AGW validation: build +AGW validation: package +AGW validation: public-api +AGW unfunded validation completed. diff --git a/plan/agw/research/preset-release-readiness-2026-10-18/hardened-lock-regeneration.log b/plan/agw/research/preset-release-readiness-2026-10-18/hardened-lock-regeneration.log new file mode 100644 index 00000000..c4f79841 --- /dev/null +++ b/plan/agw/research/preset-release-readiness-2026-10-18/hardened-lock-regeneration.log @@ -0,0 +1,27 @@ +➤ YN0000: · Yarn 4.2.2 +➤ YN0000: ┌ Project validation +➤ YN0057: │ @pushprotocol/common-components: Resolutions field will be ignored +➤ YN0057: │ @pushchain/ui-kit: Resolutions field will be ignored +➤ YN0000: └ Completed +➤ YN0000: ┌ Resolution step +➤ YN0085: │ + @babel/runtime@npm:7.29.10, babel-plugin-macros@npm:3.1.0, commander@npm:4.1.1, cosmiconfig@npm:7.1.0, hasown@npm:2.0.4, is-core-module@npm:2.17.0, and 3 more. +➤ YN0000: └ Completed in 50s 376ms +➤ YN0000: ┌ Post-resolution validation +➤ YN0002: │ @pushchain/core@workspace:packages/core [a1d04] doesn't provide @types/node (pd8231), requested by ts-node. +➤ YN0002: │ @pushchain/core@workspace:packages/core [a1d04] doesn't provide typescript (p4f093), requested by ts-node. +➤ YN0002: │ @pushchain/core@workspace:packages/core doesn't provide @types/node (p360d1), requested by ts-node. +➤ YN0002: │ @pushchain/core@workspace:packages/core doesn't provide typescript (p97602), requested by ts-node. +➤ YN0002: │ @pushchain/ui-kit@workspace:packages/ui-kit doesn't provide eslint (p05da2), requested by typescript-eslint. +➤ YN0002: │ @pushchain/ui-kit@workspace:packages/ui-kit doesn't provide eslint (p7d515), requested by eslint-plugin-react-refresh. +➤ YN0002: │ @pushchain/ui-kit@workspace:packages/ui-kit doesn't provide eslint (pafac7), requested by eslint-plugin-react-hooks. +➤ YN0002: │ @pushchain/ui-kit@workspace:packages/ui-kit doesn't provide typescript (pc5a0d), requested by typescript-eslint. +➤ YN0002: │ @pushprotocol/common-components@workspace:packages/shared-components doesn't provide react-is (p3a3ff), requested by styled-components. +➤ YN0086: │ Some peer dependencies are incorrectly met; run yarn explain peer-requirements for details, where is the six-letter p-prefixed code. +➤ YN0000: └ Completed +➤ YN0000: ┌ Fetch step +➤ YN0013: │ 9 packages were added to the project (+ 475 KiB). +➤ YN0000: └ Completed in 0s 458ms +➤ YN0000: ┌ Link step +➤ YN0073: │ Skipped due to mode=update-lockfile +➤ YN0000: └ Completed +➤ YN0000: · Done with warnings in 50s 984ms diff --git a/plan/agw/research/preset-release-readiness-2026-10-18/lock-audit.json b/plan/agw/research/preset-release-readiness-2026-10-18/lock-audit.json new file mode 100644 index 00000000..3fbc6fc7 --- /dev/null +++ b/plan/agw/research/preset-release-readiness-2026-10-18/lock-audit.json @@ -0,0 +1,10 @@ +[ + { + "descriptor": "@pushchain/core@npm:^6.0.26", + "version": "0.0.0-use.local" + }, + { + "descriptor": "commander@npm:^4.0.0", + "version": "13.1.0" + } +] \ No newline at end of file diff --git a/plan/agw/research/preset-release-readiness-2026-10-18/manual-compiler-prepare.log b/plan/agw/research/preset-release-readiness-2026-10-18/manual-compiler-prepare.log new file mode 100644 index 00000000..a347e8ba --- /dev/null +++ b/plan/agw/research/preset-release-readiness-2026-10-18/manual-compiler-prepare.log @@ -0,0 +1 @@ +/tmp/agw-preset-defaults-v6 diff --git a/plan/agw/research/preset-release-readiness-2026-10-18/sdk-only-units.log b/plan/agw/research/preset-release-readiness-2026-10-18/sdk-only-units.log new file mode 100644 index 00000000..611e28df --- /dev/null +++ b/plan/agw/research/preset-release-readiness-2026-10-18/sdk-only-units.log @@ -0,0 +1,39 @@ +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-confirmation-gate.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/send.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-svm-confirmation.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/preset-operation-limits.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/resolve.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/preset-default-policy.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/response-surface.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/preset-catalog.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/management.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-quote.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/public-rule.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/presets.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/preset-default-tokens.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/labels.spec.ts +PASS core packages/core/src/lib/universal/prc20-address.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-idl.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-backend.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/build-payload.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/runtime-token-chain.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/preset-routes.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/reads-context.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/native-multi-action.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-wire-fixture.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/prc20-source-encoding.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/codec.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.batch-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/registry.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/ix-encoder.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/normalize-address.spec.ts + +Test Suites: 33 passed, 33 total +Tests: 421 passed, 421 total +Snapshots: 0 total +Time: 6.953 s, estimated 8 s +Ran all test suites matching /agentic|prc20-address|outbound-(confirmation-gate|svm-confirmation)|svm-idl|evm-client.batch-gas/i. diff --git a/plan/agw/research/preset-release-readiness-2026-10-18/sdk-only-validation.log b/plan/agw/research/preset-release-readiness-2026-10-18/sdk-only-validation.log new file mode 100644 index 00000000..30ba6576 --- /dev/null +++ b/plan/agw/research/preset-release-readiness-2026-10-18/sdk-only-validation.log @@ -0,0 +1,5 @@ +AGW validation: units +AGW validation: types-spec +AGW validation: build +AGW validation: package +AGW SDK-only validation completed. diff --git a/plan/agw/research/preset-release-readiness-2026-10-18/sdk-only-workflow-lint.log b/plan/agw/research/preset-release-readiness-2026-10-18/sdk-only-workflow-lint.log new file mode 100644 index 00000000..e69de29b diff --git a/plan/agw/research/preset-release-readiness-2026-10-18/v5-hardened-immutable.log b/plan/agw/research/preset-release-readiness-2026-10-18/v5-hardened-immutable.log new file mode 100644 index 00000000..d07d0731 --- /dev/null +++ b/plan/agw/research/preset-release-readiness-2026-10-18/v5-hardened-immutable.log @@ -0,0 +1,22 @@ +➤ YN0000: · Yarn 4.2.2 +➤ YN0000: ┌ Project validation +➤ YN0057: │ @pushprotocol/common-components: Resolutions field will be ignored +➤ YN0057: │ @pushchain/ui-kit: Resolutions field will be ignored +➤ YN0000: └ Completed +➤ YN0000: ┌ Resolution step +➤ YN0000: └ Completed in 1m 25s +➤ YN0000: ┌ Post-resolution validation +➤ YN0002: │ @pushchain/core@workspace:packages/core doesn't provide @types/node (p360d1), requested by ts-node. +➤ YN0002: │ @pushchain/core@workspace:packages/core doesn't provide typescript (p97602), requested by ts-node. +➤ YN0002: │ @pushchain/ui-kit@workspace:packages/ui-kit doesn't provide eslint (p05da2), requested by typescript-eslint. +➤ YN0002: │ @pushchain/ui-kit@workspace:packages/ui-kit doesn't provide eslint (p7d515), requested by eslint-plugin-react-refresh. +➤ YN0002: │ @pushchain/ui-kit@workspace:packages/ui-kit doesn't provide eslint (pafac7), requested by eslint-plugin-react-hooks. +➤ YN0002: │ @pushchain/ui-kit@workspace:packages/ui-kit doesn't provide typescript (pc5a0d), requested by typescript-eslint. +➤ YN0002: │ @pushprotocol/common-components@workspace:packages/shared-components doesn't provide react-is (p3a3ff), requested by styled-components. +➤ YN0086: │ Some peer dependencies are incorrectly met; run yarn explain peer-requirements for details, where is the six-letter p-prefixed code. +➤ YN0000: └ Completed +➤ YN0000: ┌ Fetch step +➤ YN0000: └ Completed in 0s 204ms +➤ YN0000: ┌ Link step +➤ YN0000: └ Completed in 10s 84ms +➤ YN0000: · Done with warnings in 1m 35s diff --git a/plan/agw/research/preset-release-readiness-2026-10-18/workflow-after.log b/plan/agw/research/preset-release-readiness-2026-10-18/workflow-after.log new file mode 100644 index 00000000..e69de29b diff --git a/plan/agw/research/preset-release-readiness-2026-10-18/workflow-before.log b/plan/agw/research/preset-release-readiness-2026-10-18/workflow-before.log new file mode 100644 index 00000000..fe5b33bc --- /dev/null +++ b/plan/agw/research/preset-release-readiness-2026-10-18/workflow-before.log @@ -0,0 +1,4 @@ +../../../../../../tmp/agw-validation-before.yml:18:26: context "runner" is not allowed here. available contexts are "github", "inputs", "matrix", "needs", "secrets", "strategy", "vars". see https://docs.github.com/en/actions/learn-github-actions/contexts#context-availability for more details [expression] + | +18 | AGW_LOCAL_DIR: ${{ runner.temp }}/agw-v5-build + | ^~~~~~~~~~~ From a542f30346870ff9822ed32183117df47e7bd8cb Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Tue, 20 Oct 2026 15:40:28 +0530 Subject: [PATCH 55/68] fix(core): clarify agentic creation and rule errors --- packages/core/AGW.md | 22 + .../core/__agw-local__/v5-multiasset.spec.ts | 1 + .../agentic/__tests__/creation-errors.spec.ts | 206 +++++ .../agentic/__tests__/preset-catalog.spec.ts | 2 +- .../__tests__/preset-operation-limits.spec.ts | 2 +- packages/core/src/lib/agentic/codec/rules.ts | 206 ++--- .../core/src/lib/agentic/codec/universal.ts | 37 +- .../core/src/lib/agentic/error-messages.ts | 167 ++++ packages/core/src/lib/agentic/errors.ts | 88 ++ .../core/src/lib/agentic/management/common.ts | 12 + .../src/lib/agentic/management/destination.ts | 38 + .../src/lib/agentic/management/prepare.ts | 196 ++-- .../src/lib/agentic/management/svm-public.ts | 15 +- .../core/src/lib/agentic/presets/index.ts | 14 +- packages/core/src/lib/agentic/public-rule.ts | 26 +- plan/SDK-CHANGELOG.md | 21 + plan/agw/implementation-status.md | 2 + .../README.md | 43 + .../api-summary.json | 62 ++ .../build.log | 11 + .../creation-error-review-2026-10-20/docs.log | 1 + .../error-copy.json | 834 ++++++++++++++++++ .../full-unit.log | 185 ++++ .../git-checkpoint-validation.json | 68 ++ .../creation-error-review-2026-10-20/lint.log | 0 .../local-types.log | 0 .../local.log | 29 + .../package.log | 1 + .../types.log | 0 29 files changed, 2086 insertions(+), 203 deletions(-) create mode 100644 packages/core/src/lib/agentic/__tests__/creation-errors.spec.ts create mode 100644 packages/core/src/lib/agentic/error-messages.ts create mode 100644 packages/core/src/lib/agentic/management/destination.ts create mode 100644 plan/SDK-CHANGELOG.md create mode 100644 plan/agw/research/creation-error-review-2026-10-20/README.md create mode 100644 plan/agw/research/creation-error-review-2026-10-20/api-summary.json create mode 100644 plan/agw/research/creation-error-review-2026-10-20/build.log create mode 100644 plan/agw/research/creation-error-review-2026-10-20/docs.log create mode 100644 plan/agw/research/creation-error-review-2026-10-20/error-copy.json create mode 100644 plan/agw/research/creation-error-review-2026-10-20/full-unit.log create mode 100644 plan/agw/research/creation-error-review-2026-10-20/git-checkpoint-validation.json create mode 100644 plan/agw/research/creation-error-review-2026-10-20/lint.log create mode 100644 plan/agw/research/creation-error-review-2026-10-20/local-types.log create mode 100644 plan/agw/research/creation-error-review-2026-10-20/local.log create mode 100644 plan/agw/research/creation-error-review-2026-10-20/package.log create mode 100644 plan/agw/research/creation-error-review-2026-10-20/types.log diff --git a/packages/core/AGW.md b/packages/core/AGW.md index 0a8a7c60..e5a0e18b 100644 --- a/packages/core/AGW.md +++ b/packages/core/AGW.md @@ -10,6 +10,7 @@ Use an application-managed key; examples do not load secrets or execute automati import { PushChain, AgenticError, + AgenticRevertError, type Rule, } from '@pushchain/core'; import { @@ -116,6 +117,27 @@ The deployed v6 policy supports up to eight EQ/MAX pins per EVM destination call 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. +## Displaying errors in the UI + +Use `userMessage` for `AgenticError` and `AgenticRevertError`. Keep `code`, `message`, `hint`, `details`, `decodedError` and `cause` for diagnostics or application-specific translations. Unknown exceptions should get a neutral fallback instead of raw RPC/ABI text. + +```ts +function walletErrorText(error: unknown): string { + if (error instanceof AgenticError || error instanceof AgenticRevertError) { + return error.userMessage; + } + return 'The request could not be completed. Check wallet activity before trying again.'; +} +``` + +Creation and rule-preparation errors include a zero-based `details.ruleIndex` when a rule can be identified, with `assetIndex`, `callIndex` and `field` where available. The UI message uses a one-based rule number. Use these details to show the error on the relevant rule instead of only in a footer. Read/receipt failures preserve their causes and transaction hashes; do not automatically retry a submitted transaction whose outcome is unknown. + +`TOKEN_ROUTE_UNAVAILABLE` means an asset cannot be resolved for transfers from Push. It is not a token-symbol formatting request. Choose a supported source token, or regenerate the preset with `funding: 'destination'` when using assets already held by the destination account. The wallet can be created before funding; destination balances are needed before execution. Pass returned `rules` unchanged. **Do not copy `readiness.chains[].selectedAssets` back into `rules[].assets` in destination-funded mode**: selectedAssets is review metadata and doing so reintroduces unsupported bridge requirements. + +A DEX condition-limit failure reports `details.reason = 'RULE_CONSTRAINT_LIMIT'`, `actual`, `limit` and `callCount`. Conditions here are generated input checks (for example token, recipient and amount checks), rather than the number of visible function names. A stock two-token, single-router preset contains six allowed-call entries and twenty conditions. Appending the same call list again makes forty conditions. The SDK rejects this; it does not deduplicate, remove conditions or split authority automatically. Preserve per-chain rules and regenerate after edits rather than appending generated calls. + +For the review screen, show the actual network (including testnet name) and funding mode. In destination-funded mode, selectedAssets.maxTotal is not an enforced destination lifetime limit; the grant has no Push token-export budget. Label maxGasPerCall as a maximum PC gas budget, not a guaranteed fee or execution gas-unit count. + ## Solana destinations Rules use fixed-width signatures and numeric positions, without an IDL: diff --git a/packages/core/__agw-local__/v5-multiasset.spec.ts b/packages/core/__agw-local__/v5-multiasset.spec.ts index 859d1247..394301ed 100644 --- a/packages/core/__agw-local__/v5-multiasset.spec.ts +++ b/packages/core/__agw-local__/v5-multiasset.spec.ts @@ -352,6 +352,7 @@ describe('v6 multi-asset SDK management and execution', () => { }) ).rejects.toMatchObject({ decodedError: { name: 'PolicyCheckReverted(ArgPinAboveMax)' }, + userMessage: expect.stringContaining('exceeds a rule'), }); } ); diff --git a/packages/core/src/lib/agentic/__tests__/creation-errors.spec.ts b/packages/core/src/lib/agentic/__tests__/creation-errors.spec.ts new file mode 100644 index 00000000..4a80316b --- /dev/null +++ b/packages/core/src/lib/agentic/__tests__/creation-errors.spec.ts @@ -0,0 +1,206 @@ +import { AgenticNamespaceImpl } from '../agentic'; +import { + AgenticError, + AgenticRevertError, + AGENTIC_ERROR_CODE, +} from '../errors'; +import { agenticPresets } from '../presets'; +import { normalizePublicRule, publicRules } from '../public-rule'; +import { validateUniversalRuleShape } from '../codec/universal'; +import type { UniversalRule } from '../agentic.types'; +import { wrapSendError } from '../management/common'; +import { ADDR, FakeChain, registerFakeGeneration } from './fake-chain'; +import { mockRuntime } from './mock-runtime'; +import { resetAgenticGenerations } from '../deployments'; + +const chainNamespace = 'eip155:11155111' as const; +const options = { + chainNamespace, + agent: ADDR.agent, + validUntil: 2_000_000_000, +}; +beforeEach(registerFakeGeneration); +afterEach(resetAgenticGenerations); + +it.each(['LENDING', 'STAKING'] as const)( + 'public %s create gives a typed token-route error before any transaction', + async (category) => { + const cause = new Error( + 'Unable to infer origin chain or token symbol for token' + ); + const rt = mockRuntime(new FakeChain(), { + signer: ADDR.owner, + resolvePrc20: () => { + throw cause; + }, + }); + const sdk = new AgenticNamespaceImpl(rt); + const { rules } = agenticPresets.get(category, options); + let failure: unknown; + try { + await sdk.create('Test', { rules }); + } catch (error) { + failure = error; + } + expect(failure).toBeInstanceOf(AgenticError); + expect(failure).toMatchObject({ + code: 'TOKEN_ROUTE_UNAVAILABLE', + cause, + details: { + ruleIndex: 0, + assetIndex: 0, + chainNamespace, + field: 'assets[0].token', + }, + userMessage: expect.stringContaining( + 'Rule 1: This token cannot be sent from Push to Ethereum Sepolia' + ), + hint: expect.stringContaining("funding: 'destination'"), + }); + expect(rt.executeMock).not.toHaveBeenCalled(); + expect(rt.atomicMock).not.toHaveBeenCalled(); + } +); + +it('reports the complete 40-condition count for duplicated DEX entries, without dropping them', async () => { + const rt = mockRuntime(new FakeChain(), { signer: ADDR.owner }); + const sdk = new AgenticNamespaceImpl(rt); + const { rules } = agenticPresets.get('DEXES', { + ...options, + funding: 'destination', + }); + const calls = rules[0].allowedCalls; + const duplicated = { ...rules[0], allowedCalls: [...calls, ...calls] }; + await expect( + sdk.create('Test', { rules: [duplicated] }) + ).rejects.toMatchObject({ + code: 'INVALID_RULE', + details: { + reason: 'RULE_CONSTRAINT_LIMIT', + actual: 40, + limit: 32, + callCount: 12, + ruleIndex: 0, + chainNamespace, + }, + message: expect.stringContaining('40 conditions'), + userMessage: expect.stringContaining('Rule 1:'), + }); + expect(duplicated.allowedCalls).toHaveLength(12); + expect(rt.executeMock).not.toHaveBeenCalled(); +}); + +it('validates stock DEX rules independently: two 20-condition rules do not become a 40-condition rule', async () => { + const rt = mockRuntime(new FakeChain()); + for (const chain of ['eip155:11155111', 'eip155:84532'] as const) { + const { rules } = agenticPresets.get('DEXES', { + ...options, + chainNamespace: chain, + funding: 'destination', + }); + const normalized = (await normalizePublicRule( + publicRules(rules)[0], + ADDR.other, + rt + )) as UniversalRule; + expect( + normalized.allowedCalls.reduce((n, c) => n + (c.pins?.length ?? 0), 0) + ).toBe(20); + expect(() => + validateUniversalRuleShape(normalized, rt.nowSeconds()) + ).not.toThrow(); + } +}); + +it('does not misclassify a destination RPC failure as an unavailable token', async () => { + const cause = new Error('RPC timeout: internal endpoint details'); + const rt = mockRuntime(new FakeChain(), { + signer: ADDR.owner, + resolveCEA: async () => { + throw cause; + }, + }); + const sdk = new AgenticNamespaceImpl(rt); + await expect( + sdk.create('Test', { rules: agenticPresets.get('LENDING', options).rules }) + ).rejects.toMatchObject({ + code: 'RULE_READ_FAILED', + cause, + userMessage: + 'Rule 1: The wallet’s destination account could not be loaded. Try again shortly.', + details: { ruleIndex: 0, chainNamespace, stage: 'destinationAccount' }, + }); + expect(rt.executeMock).not.toHaveBeenCalled(); +}); + +it.each(Object.values(AGENTIC_ERROR_CODE))( + 'provides safe UI copy for %s while retaining diagnostic text', + (code) => { + const error = new AgenticError(code, 'raw RPC details: 0x12345678'); + expect(error.userMessage.length).toBeGreaterThan(10); + expect(error.userMessage).not.toContain('raw RPC'); + expect(error.message).toBe('raw RPC details: 0x12345678'); + } +); + +it('keeps submitted hashes and uncertainty visible instead of inviting a blind retry', () => { + const error = new AgenticError( + 'RECEIPT_UNAVAILABLE', + 'technical receipt diagnostic', + { details: { txHash: '0x1234' } } + ); + expect(error.userMessage).toContain('submitted'); + expect(error.userMessage).toContain('Check its status'); + expect(error.details).toEqual({ txHash: '0x1234' }); +}); + +it('explains the create and native action ceilings using the available structured reason', () => { + expect( + new AgenticError( + 'INVALID_RULE', + 'create accepts at most eight initial rules' + ).userMessage + ).toContain('at most eight rules'); + expect( + new AgenticError('CAPABILITY_UNAVAILABLE', 'diagnostic', { + details: { capability: 'nativeActions' }, + }).userMessage + ).toContain('at most eight functions'); +}); + +it('preserves decoded contract failures and cancellation causes with UI messages', () => { + const decodedError = { + name: 'PolicyCheckReverted(ArgPinAboveMax)', + selector: '0x12345678', + }; + const cause = new Error('provider detail'); + const error = new AgenticRevertError('technical revert', { + decodedError, + cause, + }); + expect(error.userMessage).toContain('exceeds'); + expect(error.decodedError).toEqual(decodedError); + expect(error.cause).toBe(cause); + const rejected = { code: 4001, message: 'User rejected request' }; + expect(wrapSendError(rejected)).toMatchObject({ + code: 'REQUEST_REJECTED', + cause: rejected, + userMessage: expect.stringContaining('cancelled'), + }); +}); + +it.each([ + ['OwnerSigExpired', 'approval has expired'], + ['RulesExpired', 'rule has expired'], + ['ERC20InsufficientAllowance', 'spending approval'], + ['ERC20InsufficientBalance', 'not enough funds'], + ['TooManyAllowedCallPins', 'more than 32 conditions'], +])( + 'explains %s without confusing approvals, rules and balances', + (name, text) => { + expect( + new AgenticRevertError('diagnostic', { decodedError: { name } }) + .userMessage + ).toContain(text); + } +); diff --git a/packages/core/src/lib/agentic/__tests__/preset-catalog.spec.ts b/packages/core/src/lib/agentic/__tests__/preset-catalog.spec.ts index 0adcce47..25b47921 100644 --- a/packages/core/src/lib/agentic/__tests__/preset-catalog.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/preset-catalog.spec.ts @@ -45,7 +45,7 @@ it('rejects native-token markers and oversized pin expansion', () => { ...input, assets: [...input.assets!, { token: ADDR.owner }], }) - ).toThrow(/32 pins/); + ).toThrow(/maximum is 32/); expect(() => agenticPresets.get('DEXES', { ...input, diff --git a/packages/core/src/lib/agentic/__tests__/preset-operation-limits.spec.ts b/packages/core/src/lib/agentic/__tests__/preset-operation-limits.spec.ts index 5d1a73f1..caa42aa3 100644 --- a/packages/core/src/lib/agentic/__tests__/preset-operation-limits.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/preset-operation-limits.spec.ts @@ -223,5 +223,5 @@ it('refuses an overlarge token expansion without dropping restrictions', () => { asset(getAddress('0x88541670E55cC00bEEFD87eB59EDd1b7C511AC9a')), ], }) - ).toThrow(/32 pins/); + ).toThrow(/maximum is 32/); }); diff --git a/packages/core/src/lib/agentic/codec/rules.ts b/packages/core/src/lib/agentic/codec/rules.ts index e180f269..402929d5 100644 --- a/packages/core/src/lib/agentic/codec/rules.ts +++ b/packages/core/src/lib/agentic/codec/rules.ts @@ -7,7 +7,7 @@ import { type Hex, } from 'viem'; import { AgenticCapability, requireCapability } from '../capabilities'; -import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; +import { AGENTIC_ERROR_CODE, AgenticError, ruleErrorContext } from '../errors'; import type { NativeRule, InternalRule, @@ -96,112 +96,116 @@ export function prepareRules( ); } return rules.map((rule, i) => { - if (!rule || typeof rule !== 'object') { - throw new AgenticError( - AGENTIC_ERROR_CODE.INVALID_RULE, - `rules[${i}] is not an object` - ); - } - if ( - !isAddress(rule.agent, { strict: false }) || - /^0x0{40}$/i.test(rule.agent) - ) { - throw new AgenticError( - AGENTIC_ERROR_CODE.INVALID_RULE, - `rules[${i}].agent must be a non-zero Push address` - ); - } - const agent = getAddress(rule.agent); - if (ctx.owner && agent === getAddress(ctx.owner)) { - throw new AgenticError( - AGENTIC_ERROR_CODE.AGENT_IS_OWNER, - `rules[${i}].agent is the wallet owner; the owner uses the owner door` - ); - } - const chainNamespace = ruleChain(rule, ctx.pushChainNamespace); - if ( - isUniversalRule(rule) && - rule.chainNamespace === ctx.pushChainNamespace - ) { - throw new AgenticError( - AGENTIC_ERROR_CODE.INVALID_RULE, - `rules[${i}] names the connected Push chain; omit chainNamespace for a native rule` - ); - } - if ('ref' in rule) { - throw new AgenticError( - AGENTIC_ERROR_CODE.INVALID_RULE, - 'InternalRule ref is not supported; remove it from the input' - ); - } - - if (isSolanaRule(rule)) { - requireCapability( - ctx.capabilities, - AgenticCapability.UNIVERSAL_SVM_RULES - ); - const terms = ctx.svm?.get(rule); - if (!terms || !ctx.gateway) + try { + if (!rule || typeof rule !== 'object') { throw new AgenticError( AGENTIC_ERROR_CODE.INVALID_RULE, - 'SVM rules require resolved wallet context and validated instruction layouts' + `rules[${i}] is not an object` ); - return { - rule, - agent, - chainNamespace, - svmTerms: terms, - session: buildSession({ - validator: ctx.validator, - rulesPolicy: ctx.rulesPolicy, - agent, - actions: [ - { - target: ctx.gateway, - selector: SEND_OUTBOUND_SELECTOR, - initData: encodeEnvelope( - chainNamespace, - encodeSvmTerms(terms, ctx.nowSeconds) - ), - }, - ], - }), - }; - } - if (isUniversalRule(rule)) { - return encodeUniversalRule(rule, ctx); - } - requireCapability(ctx.capabilities, AgenticCapability.NATIVE_RULES); - const actions = nativeRuleToActionTerms(rule as NativeRule, ctx).map( - (a) => a.terms - ); - const forbidden = [ - '0x0000000000000000000000000000000000000000', - '0x0000000000000000000000000000000000000001', - ...(ctx.forbiddenTargets ?? []), - ].map((a) => a.toLowerCase()); - actions.forEach((terms, j) => { - if (forbidden.includes(terms.target.toLowerCase())) { - const where = - actions.length > 1 ? `rules[${i}].actions[${j}]` : `rules[${i}]`; + } + if ( + !isAddress(rule.agent, { strict: false }) || + /^0x0{40}$/i.test(rule.agent) + ) { throw new AgenticError( AGENTIC_ERROR_CODE.INVALID_RULE, - `${where}.target ${terms.target} is a wallet-infrastructure address the contracts refuse as a native target` + `rules[${i}].agent must be a non-zero Push address` ); } - }); - // One rule, one rule ID: every action is a separate (target, selector) - // entry of the same session, each with its own stored terms. - const session = buildSession({ - validator: ctx.validator, - agent, - rulesPolicy: ctx.rulesPolicy, - actions: actions.map((terms) => ({ - target: terms.target, - selector: terms.selector, - initData: encodeEnvelope(chainNamespace, encodeNativeTerms(terms)), - })), - }); - return { rule, agent, chainNamespace, session, nativeTerms: actions }; + const agent = getAddress(rule.agent); + if (ctx.owner && agent === getAddress(ctx.owner)) { + throw new AgenticError( + AGENTIC_ERROR_CODE.AGENT_IS_OWNER, + `rules[${i}].agent is the wallet owner; the owner uses the owner door` + ); + } + const chainNamespace = ruleChain(rule, ctx.pushChainNamespace); + if ( + isUniversalRule(rule) && + rule.chainNamespace === ctx.pushChainNamespace + ) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + `rules[${i}] names the connected Push chain; omit chainNamespace for a native rule` + ); + } + if ('ref' in rule) { + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'InternalRule ref is not supported; remove it from the input' + ); + } + + if (isSolanaRule(rule)) { + requireCapability( + ctx.capabilities, + AgenticCapability.UNIVERSAL_SVM_RULES + ); + const terms = ctx.svm?.get(rule); + if (!terms || !ctx.gateway) + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'SVM rules require resolved wallet context and validated instruction layouts' + ); + return { + rule, + agent, + chainNamespace, + svmTerms: terms, + session: buildSession({ + validator: ctx.validator, + rulesPolicy: ctx.rulesPolicy, + agent, + actions: [ + { + target: ctx.gateway, + selector: SEND_OUTBOUND_SELECTOR, + initData: encodeEnvelope( + chainNamespace, + encodeSvmTerms(terms, ctx.nowSeconds) + ), + }, + ], + }), + }; + } + if (isUniversalRule(rule)) { + return encodeUniversalRule(rule, ctx); + } + requireCapability(ctx.capabilities, AgenticCapability.NATIVE_RULES); + const actions = nativeRuleToActionTerms(rule as NativeRule, ctx).map( + (a) => a.terms + ); + const forbidden = [ + '0x0000000000000000000000000000000000000000', + '0x0000000000000000000000000000000000000001', + ...(ctx.forbiddenTargets ?? []), + ].map((a) => a.toLowerCase()); + actions.forEach((terms, j) => { + if (forbidden.includes(terms.target.toLowerCase())) { + const where = + actions.length > 1 ? `rules[${i}].actions[${j}]` : `rules[${i}]`; + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + `${where}.target ${terms.target} is a wallet-infrastructure address the contracts refuse as a native target` + ); + } + }); + // One rule, one rule ID: every action is a separate (target, selector) + // entry of the same session, each with its own stored terms. + const session = buildSession({ + validator: ctx.validator, + agent, + rulesPolicy: ctx.rulesPolicy, + actions: actions.map((terms) => ({ + target: terms.target, + selector: terms.selector, + initData: encodeEnvelope(chainNamespace, encodeNativeTerms(terms)), + })), + }); + return { rule, agent, chainNamespace, session, nativeTerms: actions }; + } catch (error) { + throw ruleErrorContext(error, i, rule?.chainNamespace); + } }); } diff --git a/packages/core/src/lib/agentic/codec/universal.ts b/packages/core/src/lib/agentic/codec/universal.ts index fa6b6d6f..d91e5ff6 100644 --- a/packages/core/src/lib/agentic/codec/universal.ts +++ b/packages/core/src/lib/agentic/codec/universal.ts @@ -1,7 +1,11 @@ import { validatePins } from './pins'; import { getAddress, isAddress, type Address } from 'viem'; import { AgenticCapability, requireCapability } from '../capabilities'; -import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; +import { + AGENTIC_ERROR_CODE, + AgenticError, + ruleConstraintLimit, +} from '../errors'; import type { UniversalRule } from '../agentic.types'; import type { RuleEncodeContext, PreparedRule } from './rules'; import { argumentOffset, rawOffset } from './abi-layout'; @@ -84,11 +88,20 @@ export function validateUniversalRuleShape( try { validatePins(call.pins ?? []); } catch (error) { - throw invalid((error as Error).message); + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + (error as Error).message, + { + cause: error, + details: { + callIndex: i, + field: `allowedCalls[${i}].pins`, + chainNamespace: rule.chainNamespace, + }, + } + ); } pinCount += call.pins?.length ?? 0; - if (pinCount > 32) - throw invalid('at most 32 pins across all allowed calls'); const key = `${call.target.toLowerCase()}:${parsed.selector}`; const restricted = !!call.pins?.length || @@ -100,11 +113,27 @@ export function validateUniversalRuleShape( ); seen.set(key, restricted); }); + if (pinCount > 32) + throw ruleConstraintLimit( + pinCount, + rule.allowedCalls.length, + rule.chainNamespace + ); const tokens = new Set(); rule.assets.forEach((a, i) => { const address = typeof a.token === 'string' ? a.token : a.token?.address; if (typeof address !== 'string') throw invalid(`assets[${i}].token is missing an address`); + if (!isAddress(address, { strict: false })) + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'The selected token has an invalid address.', + { + userMessage: + 'The selected token has an invalid address. Select the token again.', + details: { assetIndex: i, field: `assets[${i}].token` }, + } + ); const key = address.toLowerCase(); if (tokens.has(key)) throw invalid(`assets[${i}] duplicates an earlier token`); diff --git a/packages/core/src/lib/agentic/error-messages.ts b/packages/core/src/lib/agentic/error-messages.ts new file mode 100644 index 00000000..88722c60 --- /dev/null +++ b/packages/core/src/lib/agentic/error-messages.ts @@ -0,0 +1,167 @@ +import type { AgenticErrorCode } from './errors'; + +/** UI copy only. Codes, original messages, hints and causes remain diagnostic data. */ +const MESSAGES: Record = { + DUPLICATE_RULE: + 'Keep one rule per agent and network. Edit the existing rule or remove the duplicate.', + AGENT_IS_OWNER: 'Choose an agent address different from the wallet owner.', + AMBIGUOUS_RULE: + 'More than one rule matches this agent and network. Keep one active matching rule before sending.', + TARGET_NOT_ON_RULE_CHAIN: + 'Choose an app on the network selected for this rule.', + ASSET_CHAIN_MISMATCH: + 'The selected token belongs to a different network. Choose a token on this rule’s network.', + TOKEN_ROUTE_UNAVAILABLE: + 'This token cannot currently be transferred from Push to the selected network. Choose a supported token or use funds already on the destination network.', + REQUEST_REJECTED: + 'The wallet request was cancelled. Check wallet activity before trying again.', + NOT_OWNER_OR_AGENT: + 'Connect the wallet owner or an agent authorized by its rules.', + WALLET_NOT_DEPLOYED: 'This agentic wallet has not been created yet.', + NOT_AGENTIC_WALLET: 'This address is not a supported agentic wallet.', + DELETE_NEEDS_TARGET: 'Choose which rules to remove.', + NO_RULES_FOR_CHAIN: 'This agent has no active rule for the selected network.', + FROM_NOT_ALLOWED: + 'The agentic wallet is the sender. Remove the custom sender selection.', + NOT_ALLOWED_IN_AGENTIC_MODE: + 'This action is unavailable while using an agentic wallet.', + INVALID_RULE: + 'Some rule settings are invalid. Review the rule and try again.', + CAPABILITY_UNAVAILABLE: + 'This feature is not available for this wallet or network yet.', + READ_ONLY: 'Connect a signing wallet to continue.', + NOT_WALLET_OWNER: 'Connect the owner wallet to change these permissions.', + RULE_NOT_FOUND: + 'This rule could not be found. Refresh the wallet’s rules and try again.', + RULE_READ_FAILED: + 'The wallet’s current state could not be loaded. Refresh and try again.', + INCONSISTENT_READ: + 'The wallet changed while it was being checked. Refresh before trying again.', + INDEX_RACE: + 'The expected wallet address changed. Refresh wallet information before trying again.', + RECEIPT_MISMATCH: + 'The transaction result needs verification. Check its status before retrying.', + RECEIPT_UNAVAILABLE: + 'The transaction was submitted, but its status could not be confirmed. Check its status before trying again.', + AGENT_GAS_INSUFFICIENT: + 'The agent needs more Push coins to pay transaction fees.', + WALLET_BALANCE_INSUFFICIENT: + 'The agentic wallet does not have enough funds for this action.', +}; + +export function agenticUserMessage( + code: AgenticErrorCode, + diagnostic: string, + details?: Readonly> +): string { + if (code === 'CAPABILITY_UNAVAILABLE') { + if (details?.['capability'] === 'nativeActions') + return 'A Push rule can allow at most eight functions. Select fewer functions.'; + if (details?.['capability'] === 'presetCalls') + return 'Choose a preset configuration with 1 to 32 allowed functions.'; + if ( + details?.['capability'] === 'presetChain' || + details?.['capability'] === 'presetCatalog' + ) + return 'This preset is unavailable for the selected network.'; + } + if (code !== 'INVALID_RULE') return MESSAGES[code]; + if (/validUntil|expiry|expired|future.*timestamp/i.test(diagnostic)) + return 'Choose an expiry date in the future.'; + if (/label.*(64|length|most)/i.test(diagnostic)) + return 'The wallet name is too long. Shorten it and try again.'; + if (/label/i.test(diagnostic)) return 'Enter a valid wallet name.'; + if (/maxGasPerCall.*positive/i.test(diagnostic)) + return 'Set a gas budget greater than zero for this rule.'; + if (/allowedCalls.*(1\.\.32|contain|array)/i.test(diagnostic)) + return 'Select between 1 and 32 allowed functions for this rule.'; + if (/rules.*(eight|8)|eight initial rules/i.test(diagnostic)) + return 'A wallet can be created with at most eight rules. Remove some rules before creating it.'; + if (/assets.*(eight|8)/i.test(diagnostic)) + return 'A rule can include at most eight tokens. Select fewer tokens.'; + if (/duplicate.*pin|pin.*duplicate/i.test(diagnostic)) + return 'The same function input has more than one condition. Keep one condition for each input.'; + if (/pins.*(eight|8)/i.test(diagnostic)) + return 'A function can have at most eight conditions. Choose a simpler function configuration.'; + if (/pins.*32|32.*pins/i.test(diagnostic)) + return 'This rule has too many conditions. Select fewer tokens or allowed functions.'; + if (/selector|function signature/i.test(diagnostic)) + return 'The selected function format is invalid. Select the function again or check its signature.'; + if (/dynamic|static|offset|argument.*range|tuple/i.test(diagnostic)) + return 'This function input cannot be constrained in that format. Choose a supported input or function.'; + if (/uint256|bigint|non-negative/i.test(diagnostic)) + return 'One of the spending limits is invalid. Review the amounts and try again.'; + if (/chainNamespace|unsupported.*chain/i.test(diagnostic)) + return 'Choose a supported network for this rule.'; + if (/address/i.test(diagnostic)) + return 'Enter a valid wallet, token or app address for this rule.'; + return MESSAGES.INVALID_RULE; +} + +export function agenticRevertUserMessage(name?: string): string { + if (!name) + return 'The transaction could not be completed. Check wallet activity before trying again.'; + if (/TooManyAllowedCallPins/.test(name)) + return 'This rule has more than 32 conditions. Select fewer tokens or allowed functions.'; + if (/TooMany.*Pins|PinRuleOutOfRange/.test(name)) + return 'This function has too many conditions. Choose a simpler rule configuration.'; + if (/TooManyActions|TooManyInitialRules|BatchSizeOutOfRange/.test(name)) + return 'Too many rules or functions are selected. Reduce the selection and try again.'; + if (/LabelTooLong/.test(name)) + return 'The wallet name is too long. Shorten it and try again.'; + if (/DuplicateAction|DuplicateAsset|DuplicateSvmPin/.test(name)) + return 'This rule contains duplicate functions, tokens or conditions. Remove the duplicate selection.'; + if ( + /SpentMismatch|SpentLengthMismatch|AssetSpentMismatch|IndexMismatch|InvalidNonce|IntentGrantNonceMismatch|IntentWalletMismatch/.test( + name + ) + ) + return 'The wallet changed while this action was being prepared. Refresh its state before trying again.'; + if (/EnforcedPause/.test(name)) + return 'This operation is temporarily paused. Try again later.'; + if (/OwnerSigExpired|SignatureExpired/.test(name)) + return 'The wallet approval has expired. Review and sign a new request.'; + if (/OutsideTimeWindow/.test(name)) + return 'This request is outside its valid time window. Refresh and approve a new request.'; + if (/InvalidExpiry/.test(name)) + return 'Choose a valid future expiry for this rule.'; + if (/Allowance|Approval/.test(name)) + return 'The token spending approval is missing or too small. Review the token approvals.'; + if ( + /RuleWithoutPin|CeaAccountsMissExpectedCEA|CeaAccountAtUnpinnedIndex/.test( + name + ) + ) + return 'The rule is missing a required wallet-recipient restriction. Review its recipient settings.'; + if (/Unsupported|WrongVmForCall|WrongModeForCall/.test(name)) + return 'This action is not supported on the selected network or wallet version.'; + if ( + /InvalidOwnerSignature|InvalidEnableSignature|InvalidSessionKeySignature|SignerNotFound/.test( + name + ) + ) + return 'The signature could not be verified. Reconnect the authorized wallet and try again.'; + if (/PCValueExceedsCap|Gas.*Cap/.test(name ?? '')) + return 'The required gas exceeds this rule’s gas budget. Review the budget before trying again.'; + if ( + /ArgPinAboveMax|AmountExceedsCap|TotalSpendCapExceeded|Value.*Cap|MaxCalls|CallLimitReached|TotalNativeAmountExceeded|TotalValueExceeded/.test( + name ?? '' + ) + ) + return 'This action exceeds a rule’s spending or usage limit. Reduce the amount or ask the owner to update the rule.'; + if (/Expired|Expiry/.test(name ?? '')) + return 'This rule has expired. Ask the owner to renew it.'; + if ( + /ArgPinMismatch|Beneficiary|NotAllowed|NotEnabled|Permission|RuleNot|RulesNot|RecipientTargetMismatch|TargetMismatch|SelectorMismatch|SvmAccountPinMismatch|SvmDataPinMismatch/.test( + name ?? '' + ) + ) + return 'This action does not match the wallet’s permissions. Check the token, recipient and allowed function.'; + if (/CallerIsNotOwner|UnauthorizedOwner|OwnerLaneRequired/.test(name ?? '')) + return 'Connect the owner wallet to make this change.'; + if (/CallerIsNotAgent/.test(name ?? '')) + return 'Connect the agent authorized by this rule.'; + if (/Insufficient|Balance/.test(name ?? '')) + return 'There are not enough funds for this action. Check the wallet balance and fees.'; + return 'The wallet contract rejected this transaction. Review the permissions and transaction details before trying again.'; +} diff --git a/packages/core/src/lib/agentic/errors.ts b/packages/core/src/lib/agentic/errors.ts index bbe55e4b..08ce712e 100644 --- a/packages/core/src/lib/agentic/errors.ts +++ b/packages/core/src/lib/agentic/errors.ts @@ -2,6 +2,7 @@ import { PushChainExecutionError, type DecodedErrorPayload, } from '../orchestrator/internals/errors'; +import { agenticUserMessage, agenticRevertUserMessage } from './error-messages'; /** * Stable AGW error codes. The first groups are specified by the AGW SDK page @@ -15,6 +16,8 @@ export const AGENTIC_ERROR_CODE = { AMBIGUOUS_RULE: 'AMBIGUOUS_RULE', TARGET_NOT_ON_RULE_CHAIN: 'TARGET_NOT_ON_RULE_CHAIN', ASSET_CHAIN_MISMATCH: 'ASSET_CHAIN_MISMATCH', + TOKEN_ROUTE_UNAVAILABLE: 'TOKEN_ROUTE_UNAVAILABLE', + REQUEST_REJECTED: 'REQUEST_REJECTED', // initialize with agenticWallet (spec 3.f) NOT_OWNER_OR_AGENT: 'NOT_OWNER_OR_AGENT', WALLET_NOT_DEPLOYED: 'WALLET_NOT_DEPLOYED', @@ -50,6 +53,8 @@ export type AgenticErrorCode = */ export class AgenticError extends Error { readonly code: AgenticErrorCode; + /** Safe end-user copy; message/cause retain technical diagnostics. */ + readonly userMessage: string; readonly hint?: string; readonly details?: Readonly>; override readonly cause?: unknown; @@ -61,11 +66,14 @@ export class AgenticError extends Error { hint?: string; details?: Record; cause?: unknown; + userMessage?: string; } = {} ) { super(message); this.name = 'AgenticError'; this.code = code; + this.userMessage = + opts.userMessage ?? agenticUserMessage(code, message, opts.details); this.hint = opts.hint; this.details = opts.details; this.cause = opts.cause; @@ -80,6 +88,7 @@ export class AgenticError extends Error { */ export class AgenticRevertError extends PushChainExecutionError { readonly agenticCode?: string; + readonly userMessage: string; constructor( message: string, @@ -97,9 +106,88 @@ export class AgenticRevertError extends PushChainExecutionError { }); this.name = 'AgenticRevertError'; this.agenticCode = opts.agenticCode; + this.userMessage = agenticRevertUserMessage( + opts.decodedError?.name ?? opts.agenticCode + ); } } +export function ruleConstraintLimit( + actual: number, + callCount: number, + chainNamespace?: string +): AgenticError { + const message = `This rule has ${actual} conditions. The maximum is 32. Remove duplicate functions or select fewer tokens or functions.`; + return new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, message, { + userMessage: message, + hint: 'Regenerate the preset after changing selections. Do not drop individual conditions or bypass the contract limit.', + details: { + reason: 'RULE_CONSTRAINT_LIMIT', + field: 'allowedCalls', + actual, + limit: 32, + callCount, + chainNamespace, + }, + }); +} + +export function ruleErrorContext( + error: unknown, + ruleIndex: number, + chainNamespace?: string +): unknown { + if (!(error instanceof AgenticError)) return error; + if (error.details?.['ruleIndex'] !== undefined) return error; + return new AgenticError(error.code, error.message, { + hint: error.hint, + userMessage: `Rule ${ruleIndex + 1}: ${error.userMessage}`, + cause: error.cause ?? error, + details: { + ...error.details, + ruleIndex, + ...(chainNamespace ? { chainNamespace } : {}), + }, + }); +} + +export function tokenRouteUnavailable( + cause: unknown, + token: string, + chainNamespace: string, + assetIndex: number +): AgenticError { + if (cause instanceof AgenticError) return cause; + const names: Record = { + 'eip155:1': 'Ethereum', + 'eip155:11155111': 'Ethereum Sepolia', + 'eip155:8453': 'Base', + 'eip155:84532': 'Base Sepolia', + 'eip155:42161': 'Arbitrum', + 'eip155:421614': 'Arbitrum Sepolia', + 'eip155:56': 'BNB Chain', + 'eip155:97': 'BNB Testnet', + }; + const network = + names[chainNamespace] ?? + (chainNamespace.startsWith('solana:') + ? 'the selected Solana network' + : 'the selected network'); + const message = `This token cannot be sent from Push to ${network}. Choose a supported token, or use destination funding for balances held on that network.`; + return new AgenticError(AGENTIC_ERROR_CODE.TOKEN_ROUTE_UNAVAILABLE, message, { + userMessage: message, + hint: "For prefunded preset destinations, use funding: 'destination' and pass the returned rules unchanged. selectedAssets is review metadata; do not copy it back into rule.assets.", + details: { + token, + chainNamespace, + assetIndex, + field: `assets[${assetIndex}].token`, + funding: 'push', + }, + cause, + }); +} + export function capabilityUnavailable( capability: string, dependency: string, diff --git a/packages/core/src/lib/agentic/management/common.ts b/packages/core/src/lib/agentic/management/common.ts index 84271b3c..1200109c 100644 --- a/packages/core/src/lib/agentic/management/common.ts +++ b/packages/core/src/lib/agentic/management/common.ts @@ -156,6 +156,18 @@ export function wrapSendError(err: unknown): unknown { cause: err, }); } + if ( + err && + typeof err === 'object' && + (('code' in err && err.code === 4001) || + ('name' in err && err.name === 'UserRejectedRequestError')) + ) { + return new AgenticError( + AGENTIC_ERROR_CODE.REQUEST_REJECTED, + 'The wallet request was cancelled.', + { cause: err } + ); + } if (decoded || err instanceof PushChainExecutionError) { const e = err as { message?: string; diff --git a/packages/core/src/lib/agentic/management/destination.ts b/packages/core/src/lib/agentic/management/destination.ts new file mode 100644 index 00000000..d1dacf63 --- /dev/null +++ b/packages/core/src/lib/agentic/management/destination.ts @@ -0,0 +1,38 @@ +import { getAddress, type Address } from 'viem'; +import type { CHAIN } from '../../constants/enums'; +import type { AgenticRuntime } from '../runtime'; +import { AgenticError, AGENTIC_ERROR_CODE } from '../errors'; + +/** Preserve read failures as read failures; never report them as bad token routes. */ +export async function resolveRuleDestination( + runtime: AgenticRuntime, + wallet: Address, + chain: CHAIN +): Promise
{ + try { + return getAddress((await runtime.resolveCEA(wallet, chain)).cea); + } catch (cause) { + if (cause instanceof AgenticError) throw cause; + const unavailable = + cause instanceof Error && + cause.message.includes('CEAFactory not available on chain'); + const message = unavailable + ? 'Agentic wallets are not available on this destination network yet. Choose a supported network.' + : 'The wallet’s destination account could not be loaded. Try again shortly.'; + throw new AgenticError( + unavailable + ? AGENTIC_ERROR_CODE.CAPABILITY_UNAVAILABLE + : AGENTIC_ERROR_CODE.RULE_READ_FAILED, + message, + { + userMessage: message, + cause, + details: { + chainNamespace: chain, + field: 'chainNamespace', + stage: 'destinationAccount', + }, + } + ); + } +} diff --git a/packages/core/src/lib/agentic/management/prepare.ts b/packages/core/src/lib/agentic/management/prepare.ts index 195841b0..df51da54 100644 --- a/packages/core/src/lib/agentic/management/prepare.ts +++ b/packages/core/src/lib/agentic/management/prepare.ts @@ -16,10 +16,16 @@ import { type AgenticGeneration, } from '../deployments'; import { AgenticCapability, requireCapability } from '../capabilities'; -import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; +import { + AGENTIC_ERROR_CODE, + AgenticError, + tokenRouteUnavailable, + ruleErrorContext, +} from '../errors'; import type { InternalRule, UniversalRule, SolanaRule } from '../agentic.types'; import type { AgenticRuntime } from '../runtime'; import { Snapshot } from '../reads/snapshot'; +import { resolveRuleDestination } from './destination'; import { PRC20_SOURCE_ABI, @@ -37,103 +43,125 @@ export async function prepareWalletRules( snap: Snapshot ) { const rules = await Promise.all( - inputs.map((rule) => - isPublicRule(rule) ? normalizePublicRule(rule, wallet, runtime) : rule - ) + inputs.map(async (rule, ruleIndex) => { + try { + return isPublicRule(rule) + ? await normalizePublicRule(rule, wallet, runtime) + : rule; + } catch (error) { + throw ruleErrorContext(error, ruleIndex, rule?.chainNamespace); + } + }) ); if (rules.length) await verifyPolicyVersion(runtime.reader, gen); const svm = new Map(); const universal = new Map(); - for (const rule of rules) { - if (rule && isSolanaRule(rule)) { - requireCapability( - gen.capabilities, - AgenticCapability.UNIVERSAL_SVM_RULES - ); - svm.set(rule, await preparePublicSvmRule(runtime, snap, wallet, rule)); - continue; - } - if (!isUniversalRule(rule)) continue; - if (rule.chainNamespace.startsWith('solana:')) + for (const [ruleIndex, rule] of rules.entries()) { + try { + if (rule && isSolanaRule(rule)) { + requireCapability( + gen.capabilities, + AgenticCapability.UNIVERSAL_SVM_RULES + ); + svm.set(rule, await preparePublicSvmRule(runtime, snap, wallet, rule)); + continue; + } + if (!isUniversalRule(rule)) continue; + if (rule.chainNamespace.startsWith('solana:')) + requireCapability( + gen.capabilities, + AgenticCapability.UNIVERSAL_SVM_RULES + ); + validateUniversalRuleShape(rule, runtime.nowSeconds()); requireCapability( gen.capabilities, - AgenticCapability.UNIVERSAL_SVM_RULES - ); - validateUniversalRuleShape(rule, runtime.nowSeconds()); - requireCapability( - gen.capabilities, - rule.chainNamespace.startsWith('solana:') - ? AgenticCapability.UNIVERSAL_SVM_RULES - : AgenticCapability.UNIVERSAL_EVM_RULES - ); - const chain = rule.chainNamespace as CHAIN; - if (CHAIN_INFO[chain]?.vm !== VM.EVM) - throw new AgenticError( - AGENTIC_ERROR_CODE.INVALID_RULE, - `unsupported EVM rule chain ${chain}` + rule.chainNamespace.startsWith('solana:') + ? AgenticCapability.UNIVERSAL_SVM_RULES + : AgenticCapability.UNIVERSAL_EVM_RULES ); - const { cea } = await runtime.resolveCEA(wallet, chain); - const assets = rule.assets.length - ? rule.assets.map((a) => ({ - token: - typeof a.token === 'string' && getAddress(a.token) === zeroAddress - ? undefined - : a.token, - maxPerCall: a.maxPerCall, - maxTotal: withDefault( - a.maxTotal, - AGENTIC_DEFAULTS.universal.assetMaxTotal - ), - })) - : [{ token: undefined, maxPerCall: BigInt(0), maxTotal: BigInt(0) }]; - const resolved = []; - for (const asset of assets) { - const token = - asset.token === undefined - ? await readGasPrc20(snap, chain) - : runtime.resolvePrc20(asset.token, chain); - if (token === zeroAddress) + const chain = rule.chainNamespace as CHAIN; + if (CHAIN_INFO[chain]?.vm !== VM.EVM) throw new AgenticError( AGENTIC_ERROR_CODE.INVALID_RULE, - `no gas PRC20 registered for ${chain}` - ); - const namespace = await snap.read( - token, - PRC20_SOURCE_ABI, - 'SOURCE_CHAIN_NAMESPACE' - ); - if (namespace !== chain) - throw new AgenticError( - AGENTIC_ERROR_CODE.ASSET_CHAIN_MISMATCH, - `PRC20 ${token} belongs to ${namespace}, not ${chain}` + `unsupported EVM rule chain ${chain}` ); - if (asset.token !== undefined) { - const expected = - typeof asset.token === 'string' - ? getAddress(asset.token) - : getAddress(asset.token.address); - if (expected === zeroAddress) { - if ((await readGasPrc20(snap, chain)) !== getAddress(token)) - throw new AgenticError( - AGENTIC_ERROR_CODE.INVALID_RULE, - 'resolved token is not the registered native gas token' - ); - } else { - const source = await readOriginToken(snap, token, chain); - if (source !== expected) - throw new AgenticError( - AGENTIC_ERROR_CODE.INVALID_RULE, - `PRC20 ${token} represents ${source}, not requested token ${expected}` + const cea = await resolveRuleDestination(runtime, wallet, chain); + const assets = rule.assets.length + ? rule.assets.map((a) => ({ + token: + typeof a.token === 'string' && getAddress(a.token) === zeroAddress + ? undefined + : a.token, + maxPerCall: a.maxPerCall, + maxTotal: withDefault( + a.maxTotal, + AGENTIC_DEFAULTS.universal.assetMaxTotal + ), + })) + : [{ token: undefined, maxPerCall: BigInt(0), maxTotal: BigInt(0) }]; + const resolved = []; + for (const [assetIndex, asset] of assets.entries()) { + let token: Address; + if (asset.token === undefined) token = await readGasPrc20(snap, chain); + else { + try { + token = runtime.resolvePrc20(asset.token, chain); + } catch (cause) { + throw tokenRouteUnavailable( + cause, + typeof asset.token === 'string' + ? asset.token + : asset.token.address, + chain, + assetIndex ); + } + } + if (token === zeroAddress) + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + `no gas PRC20 registered for ${chain}` + ); + const namespace = await snap.read( + token, + PRC20_SOURCE_ABI, + 'SOURCE_CHAIN_NAMESPACE' + ); + if (namespace !== chain) + throw new AgenticError( + AGENTIC_ERROR_CODE.ASSET_CHAIN_MISMATCH, + `PRC20 ${token} belongs to ${namespace}, not ${chain}` + ); + if (asset.token !== undefined) { + const expected = + typeof asset.token === 'string' + ? getAddress(asset.token) + : getAddress(asset.token.address); + if (expected === zeroAddress) { + if ((await readGasPrc20(snap, chain)) !== getAddress(token)) + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'resolved token is not the registered native gas token' + ); + } else { + const source = await readOriginToken(snap, token, chain); + if (source !== expected) + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + `PRC20 ${token} represents ${source}, not requested token ${expected}` + ); + } } + resolved.push({ + token: getAddress(token), + maxPerCall: asset.maxPerCall, + maxTotal: asset.maxTotal, + }); } - resolved.push({ - token: getAddress(token), - maxPerCall: asset.maxPerCall, - maxTotal: asset.maxTotal, - }); + universal.set(rule, { expectedCEA: getAddress(cea), assets: resolved }); + } catch (error) { + throw ruleErrorContext(error, ruleIndex, rule?.chainNamespace); } - universal.set(rule, { expectedCEA: getAddress(cea), assets: resolved }); } return prepareRules(rules, { owner, diff --git a/packages/core/src/lib/agentic/management/svm-public.ts b/packages/core/src/lib/agentic/management/svm-public.ts index 3fcc1409..42289b8a 100644 --- a/packages/core/src/lib/agentic/management/svm-public.ts +++ b/packages/core/src/lib/agentic/management/svm-public.ts @@ -13,6 +13,7 @@ import { deriveAgwSvmAta, svmKey } from '../codec/svm-accounts'; import { compileSvmIdlRule } from '../codec/svm-idl'; import { svmInvalid } from '../codec/svm-terms'; import { validateSvmTerms } from '../codec/svm-terms'; +import { tokenRouteUnavailable } from '../errors'; export function svmMetadata(runtime: AgenticRuntime) { return ( @@ -48,7 +49,7 @@ export async function preparePublicSvmRule( const tokenAccounts = new Map(), mints = new Set(); const sources: { key?: Hex; token: Address }[] = []; - for (const asset of requested) { + for (const [assetIndex, asset] of requested.entries()) { const source = typeof asset.token === 'string' ? asset.token : asset.token?.address; if (typeof source !== 'string') @@ -68,9 +69,15 @@ export async function preparePublicSvmRule( typeof asset.token === 'string' && key ? new PublicKey(hexToBytes(key)).toBase58() : asset.token; - const token = native - ? await readGasPrc20(snap, chain) - : runtime.resolvePrc20(sourceToken, chain); + let token: Address; + if (native) token = await readGasPrc20(snap, chain); + else { + try { + token = runtime.resolvePrc20(sourceToken, chain); + } catch (cause) { + throw tokenRouteUnavailable(cause, source, chain, assetIndex); + } + } if (caps.some((c) => c.token === getAddress(token))) throw svmInvalid('duplicate SVM asset'); caps.push({ diff --git a/packages/core/src/lib/agentic/presets/index.ts b/packages/core/src/lib/agentic/presets/index.ts index e8014551..84b7f84d 100644 --- a/packages/core/src/lib/agentic/presets/index.ts +++ b/packages/core/src/lib/agentic/presets/index.ts @@ -3,6 +3,7 @@ import { AgenticError, AGENTIC_ERROR_CODE, capabilityUnavailable, + ruleConstraintLimit, } from '../errors'; import type { RuleAsset, RuleCall, Pin } from '../agentic.types'; import type { @@ -360,10 +361,15 @@ export function buildPresetApi( 'presetCalls', 'preset must contain 1..32 allowed calls including approvals' ); - if (calls.reduce((n, c) => n + (c.pins?.length ?? 0), 0) > 32) - throw capabilityUnavailable( - 'presetPins', - 'preset expansion exceeds 32 pins; reduce the token list or split rules across wallets' + const conditionCount = calls.reduce( + (n, c) => n + (c.pins?.length ?? 0), + 0 + ); + if (conditionCount > 32) + throw ruleConstraintLimit( + conditionCount, + calls.length, + chain.chainNamespace ); const pairs = new Map(); for (const call of calls) { diff --git a/packages/core/src/lib/agentic/public-rule.ts b/packages/core/src/lib/agentic/public-rule.ts index 8dd8f9f0..abf45404 100644 --- a/packages/core/src/lib/agentic/public-rule.ts +++ b/packages/core/src/lib/agentic/public-rule.ts @@ -38,6 +38,7 @@ import { UINT256_MAX } from './codec/defaults'; import { deriveAgwSvmCea, svmKey } from './codec/svm-accounts'; import type { AgenticRuntime } from './runtime'; import { CHAIN } from '../constants/enums'; +import { resolveRuleDestination } from './management/destination'; export const WALLET = 'agentic:wallet' as const; const PUBLIC_INPUT = Symbol('AGW public rule'); @@ -115,6 +116,15 @@ export async function normalizePublicRule( const rule = input as unknown as RuleInput; if ('format' in rule && rule.format === 'decoded') return input; const r = rule as Rule; + if (!isAddress(r.agent, { strict: false }) || /^0x0{40}$/i.test(r.agent)) + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'Enter a valid agent wallet address.', + { + userMessage: 'Enter a valid agent wallet address.', + details: { field: 'agent' }, + } + ); rejectFields( r, [ @@ -196,12 +206,20 @@ export async function normalizePublicRule( throw invalid('native rules do not carry assets or maxGasPerCall'); const own = native ? wallet - : getAddress( - (await runtime.resolveCEA(wallet, r.chainNamespace as CHAIN)).cea - ); + : await resolveRuleDestination(runtime, wallet, r.chainNamespace as CHAIN); const nativeActions: NativeAction[] = []; const calls: UniversalRule['allowedCalls'] = []; - for (const call of r.allowedCalls) { + for (const [callIndex, call] of r.allowedCalls.entries()) { + if (!isAddress(call.target, { strict: false })) + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'An allowed function has an invalid app address.', + { + userMessage: + 'An allowed function has an invalid app address. Select the app again.', + details: { field: `allowedCalls[${callIndex}].target`, callIndex }, + } + ); const pins = call.pins ?? []; const wirePins: ArgPinWire[] = []; const occupied = new Set(); diff --git a/plan/SDK-CHANGELOG.md b/plan/SDK-CHANGELOG.md new file mode 100644 index 00000000..a99bbdd3 --- /dev/null +++ b/plan/SDK-CHANGELOG.md @@ -0,0 +1,21 @@ +# Agentic SDK development history + +Running history for work continued on `feat/agw-sdk-v4`, covering AGW, marketplace and job SDK delivery. This is a development record; package releases remain tracked in `packages/core/CHANGELOG.md`. + +For each meaningful checkpoint, add a dated entry with the change, decisions, validation, remaining work and relevant commit/evidence links. Keep earlier entries as history and mark superseded decisions explicitly. Distinguish implemented code, planning, local/fork checks, funded execution, Git delivery and package publication. Git history for this file records the exact commit introducing each checkpoint. + +## 2026-10-20 — AGW creation errors and UI messages + +**Implemented:** readable `userMessage` on SDK/revert errors; typed token-route and request-cancellation failures; rule/asset/call field context; complete per-rule constraint counts; destination read failures retain their classification and original causes. Updated the consumer guide and regression/contract assertions. + +**Validation:** the [creation-error review](agw/research/creation-error-review-2026-10-20/README.md) records 2,181 passing units, 12 skipped, 21 passing local v6 contract cases, build/type/package/API checks and changed-production lint. Before the Git checkpoint, all 72 tests across the three changed unit suites and the spec typecheck passed again; [exact checked-file hashes](agw/research/creation-error-review-2026-10-20/git-checkpoint-validation.json) are retained. No funded E2E or package publication was run for this change. + +**Remaining:** the DEX UI overflow trigger needs the installed SDK version and exact create payload. Stock presets have 20 conditions; duplicating generated calls reproduces 40. Do not remove permission conditions to fit the limit. + +**Git delivery:** included in the AGW error-fix commit on `feat/agw-sdk-v4`; a release-branch sync and npm publication are separate actions. + +## 2026-10-18 — starting AGW baseline + +AGW v6, bounded preset defaults, route-aware readiness and destination-funded preset grants were already implemented before this continued marketplace work. Lighter SDK-only PR checks were delivered in `6108348f`; the previous planning checkpoint is `4206fae6`. + +Recorded evidence: 2,142 full units, 107 local contract tests and 9/9 read-only factory simulations. Earlier v6 funded evidence covers 69 distinct cases across multiple runs, not one clean full invocation. Publication remained manual at that checkpoint. See [AGW status](agw/implementation-status.md) and [release-readiness evidence](agw/research/preset-release-readiness-2026-10-18/README.md). diff --git a/plan/agw/implementation-status.md b/plan/agw/implementation-status.md index 3c524e76..ef1141e3 100644 --- a/plan/agw/implementation-status.md +++ b/plan/agw/implementation-status.md @@ -1,5 +1,7 @@ # AGW SDK implementation status +**October 20 — creation error fixes:** typed token-route failures and per-rule details, actual constraint counts, UI-safe userMessage on SDK/revert errors, preserved diagnostics and clearer receipt/cancellation handling. **2,181 units**, **21 local v6 tests**, build/type/package checks pass. DEX UI overflow source remains pending the actual create payload; stock presets stay at 20 conditions. [Review and UI handoff](research/creation-error-review-2026-10-20/README.md). [Git delivery and continuing history](../SDK-CHANGELOG.md); package publication is separate. + **October 18 — lighter CI requested:** PR checks now run SDK-only validation (421 focused units, spec types, build and package checks); contract checkout/Foundry/full API checks are manual opt-in. Local fast checks pass. Release branch v5 `b291b873` is pushed; package publication remains manual. **2,142 full units**, **107 local contract tests** and **9/9 read-only factory simulations** remain the release evidence. The optional fresh-run full CI preparation failure is documented, not reported as passing. **October 18 — final CI repairs:** invalid runner context and stale contract checkout pin are corrected; two incompatible merged dependency ranges were regenerated with Yarn hardened mode. Clean hardened immutable install passes on v5 `66dc81f8`. The full unfunded verifier passes locally, including **107 local contract tests**, in addition to **2,142 full units** and **9/9 Donut factory simulations**. [Final evidence](research/preset-release-readiness-2026-10-18/README.md). diff --git a/plan/agw/research/creation-error-review-2026-10-20/README.md b/plan/agw/research/creation-error-review-2026-10-20/README.md new file mode 100644 index 00000000..992b3860 --- /dev/null +++ b/plan/agw/research/creation-error-review-2026-10-20/README.md @@ -0,0 +1,43 @@ +# Agentic creation error review — October 20, 2026 + +Scope: the three reported creation screenshots, the shared create/add/update rule preparation paths, and UI presentation of typed SDK and decoded contract failures. This report records validation of the v4 changes. Subsequent Git delivery is tracked in the [SDK development history](../../../SDK-CHANGELOG.md); package publication remains separate. + +The npm alpha tag at inspection was 6.0.27-alpha.3. Its release commit changes version metadata over the reviewed preset implementation. The actual version installed in the UI and its create payload have not yet been supplied. No UI implementation was found in this SDK's UI packages or a matching sibling checkout. + +## Findings + +| Report | Confirmed behavior | Fix / remaining action | +| --- | --- | --- | +| Lending: Unable to infer origin chain or token symbol | The stock Sepolia Aave preset selects faucet LINK (0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5). It has no matching current SDK Push transfer route. Generic resolver Error escaped shared preparation. | TOKEN_ROUTE_UNAVAILABLE now explains the limitation and funding choice, preserves the original cause and includes ruleIndex, assetIndex, token, chainNamespace and field. It does not invent a mapping or silently remove authority. | +| Staking: same resolver error | The Sepolia EigenLayer preset selects WETH 0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9. This differs from the DEX WETH 0xfff9976782d46cc05630d1f6ebab18b2324d6b14 whose Push mapping was fixed previously. | Same typed handling applies, including Solana source-token resolution. Existing typed mismatch errors keep their classification. | +| DEX: at most 32 pins | An untouched two-token, one-router preset has 6 allowed-call entries and 20 input conditions. The guard is per rule, not summed across independent chain rules. Duplicating its call list produces 12 entries / 40 conditions and reproduces the same failure class. | Error now reports full actual count, maximum 32, callCount, ruleIndex and chainNamespace. Actual UI trigger remains unconfirmed pending the exact payload. No deduplication, condition removal, auto-splitting or contract-limit change is applied. | +| Other vague validation/revert text | Technical ABI, capability and provider wording was also the only available display text in many typed failures. | Both AgenticError and AgenticRevertError now expose userMessage. All 26 SDK codes have safe copy. Common decoded contract failures are grouped; remaining names use a safe fallback while retaining decodedError/cause. | +| Destination lookup / malformed addresses | Destination lookup could leak raw RPC failures; invalid agent/app/token addresses could leak conversion details. | Destination lookup failures are typed read failures, not token-route failures. Unsupported destination factories remain capability failures. Address errors carry field context. | +| User cancellation / receipt ambiguity | A cancelled request and an unconfirmed submitted transaction need different next steps. | REQUEST_REJECTED is explicit. Receipt uncertainty keeps transaction hashes and tells the user to check status before retrying; no automatic resend is added. | + +## UI handoff + +1. Render error.userMessage for AgenticError/AgenticRevertError. Keep message, code, hint, details, decodedError and cause for diagnostics or translation. Unknown exceptions get neutral fallback text instead of raw RPC output. The consumer guide has a typechecked renderer. +2. Highlight details.ruleIndex (zero-based), and assetIndex/callIndex/field when supplied. UI copy uses one-based rule numbering. +3. For destination-funded execution, regenerate with funding: 'destination', check readiness.ready, then pass returned rules unchanged into create. selectedAssets is display metadata and must not be copied back to rule.assets. The wallet can be created before funding; balances are needed before execution. +4. For bridge-funded rules, choose genuinely supported source assets. Changing a symbol or substituting a same-symbol token does not establish a valid route. +5. For DEX edits, regenerate rather than append generated allowedCalls. Preserve separate rules for separate networks. Do not merge distinct permission alternatives merely because their function names match. +6. Show the actual network, including testnet name. In destination mode, maxTotal in selectedAssets is not an enforced destination lifetime cap; the rule grants no Push token-export budget. Label the PC field as a maximum gas budget, not an actual fee. + +## Error inventory and compatibility + +error-copy.json inventories 26 typed SDK codes and 181 ABI error names with their UI text. Common revert classes distinguish gas/spend limits, allowance versus balance, expired approval versus expired rule, authorization and oversized configurations. Infrastructure/unknown decoded names retain a neutral contract-rejection fallback. This is not a claim that every ABI error has a unique remediation or a security audit. + +The public changes are additive userMessage properties and TOKEN_ROUTE_UNAVAILABLE / REQUEST_REJECTED codes. Existing diagnostic messages generally remain; the two reported error classes now have readable message text as well. INVALID_RULE remains the condition-limit code, with details.reason RULE_CONSTRAINT_LIMIT. Raw causes and decoded revert data remain available. Message-string matching should be replaced with codes/reasons in consumers. + +## Validation + +- Full unit suite: 2,181 passed, 12 skipped; no failures. +- 39 new regression cases cover route failure before sending, exact over-limit counts, independent stock chain rules, RPC failure classification, every typed code's UI text, uncertainty/hash preservation, cancellation and distinct contract failure categories. +- Actual local v6 suite: 21 passed, including assertions that an engine-wrapped amount-limit revert retains decoded data and has a readable userMessage. +- Build, spec/local typechecks, seven guide examples, compiled CJS/ESM/package checks and source/declaration comparison pass. Changed production files have no lint errors. +- No funded E2E, contract deployment, mainnet transaction or publish action was run. + +## Required to finish the DEX diagnosis + +Obtain the installed package version and exact { label, rules } passed to agentic.create, serializing bigint values as strings. Count conditions per rule after UI reconstruction, not only in the original preset. Compare with the stock six-entry/twenty-condition result. The screenshots alone cannot establish which calls were appended/merged or whether another transformation occurred. diff --git a/plan/agw/research/creation-error-review-2026-10-20/api-summary.json b/plan/agw/research/creation-error-review-2026-10-20/api-summary.json new file mode 100644 index 00000000..b2370051 --- /dev/null +++ b/plan/agw/research/creation-error-review-2026-10-20/api-summary.json @@ -0,0 +1,62 @@ +{ + "baseline": "b1597b91a25dbf7f691f589b4e1e154add604315", + "head": "4206fae6bf6a92e454473a03b3cb615b3dd41324", + "compiledMatchesSource": true, + "initializeSignatureChanged": false, + "addedExports": [ + "AgenticPresets", + "ArgumentPath", + "DecodedSolanaRule", + "Pin", + "Preset", + "PresetAsset", + "PresetCallIssue", + "PresetCategory", + "PresetChainReadiness", + "PresetConfigurationIssue", + "PresetOptions", + "PresetResult", + "PresetRuleTemplate", + "ReadyPresetOptions", + "RuleInput", + "Spent", + "WalletMarker" + ], + "removedExports": [ + "AgenticNetworkConstants", + "NativeRule", + "UniversalRule" + ], + "publicTypeChanges": [ + "AGENTIC_ERROR_CODE", + "AgenticError", + "AgenticRevertError", + "AgenticErrorCode", + "AgenticTxMetadata", + "AgenticWallet", + "AllowedCall", + "AssetCap", + "CreateOptions", + "DecodedSolanaRule", + "Rule", + "RuleInput", + "Pin", + "Spent", + "WalletMarker", + "ArgumentPath", + "RulesRecord", + "Preset", + "PresetCategory", + "PresetAsset", + "PresetOptions", + "ReadyPresetOptions", + "PresetRuleTemplate", + "PresetResult", + "PresetChainReadiness", + "PresetConfigurationIssue", + "PresetCallIssue", + "AgenticPresets" + ], + "transactionMethodChanges": [], + "instanceMethodChanges": [] +} diff --git a/plan/agw/research/creation-error-review-2026-10-20/build.log b/plan/agw/research/creation-error-review-2026-10-20/build.log new file mode 100644 index 00000000..194ffc1a --- /dev/null +++ b/plan/agw/research/creation-error-review-2026-10-20/build.log @@ -0,0 +1,11 @@ + +> nx run core:build + +Compiling TypeScript files for project "core"... +Done compiling TypeScript files for project "core". +(node:75773) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. +(Use `node --trace-warnings ...` to show where the warning was created) + + + + NX Successfully ran target build for project core diff --git a/plan/agw/research/creation-error-review-2026-10-20/docs.log b/plan/agw/research/creation-error-review-2026-10-20/docs.log new file mode 100644 index 00000000..5996134d --- /dev/null +++ b/plan/agw/research/creation-error-review-2026-10-20/docs.log @@ -0,0 +1 @@ +AGW guide: 7 TypeScript blocks typechecked against public exports; no examples executed. diff --git a/plan/agw/research/creation-error-review-2026-10-20/error-copy.json b/plan/agw/research/creation-error-review-2026-10-20/error-copy.json new file mode 100644 index 00000000..460e3721 --- /dev/null +++ b/plan/agw/research/creation-error-review-2026-10-20/error-copy.json @@ -0,0 +1,834 @@ +{ + "sdk": [ + { + "code": "DUPLICATE_RULE", + "userMessage": "Keep one rule per agent and network. Edit the existing rule or remove the duplicate." + }, + { + "code": "AGENT_IS_OWNER", + "userMessage": "Choose an agent address different from the wallet owner." + }, + { + "code": "AMBIGUOUS_RULE", + "userMessage": "More than one rule matches this agent and network. Keep one active matching rule before sending." + }, + { + "code": "TARGET_NOT_ON_RULE_CHAIN", + "userMessage": "Choose an app on the network selected for this rule." + }, + { + "code": "ASSET_CHAIN_MISMATCH", + "userMessage": "The selected token belongs to a different network. Choose a token on this rule’s network." + }, + { + "code": "TOKEN_ROUTE_UNAVAILABLE", + "userMessage": "This token cannot currently be transferred from Push to the selected network. Choose a supported token or use funds already on the destination network." + }, + { + "code": "REQUEST_REJECTED", + "userMessage": "The wallet request was cancelled. Check wallet activity before trying again." + }, + { + "code": "NOT_OWNER_OR_AGENT", + "userMessage": "Connect the wallet owner or an agent authorized by its rules." + }, + { + "code": "WALLET_NOT_DEPLOYED", + "userMessage": "This agentic wallet has not been created yet." + }, + { + "code": "NOT_AGENTIC_WALLET", + "userMessage": "This address is not a supported agentic wallet." + }, + { + "code": "DELETE_NEEDS_TARGET", + "userMessage": "Choose which rules to remove." + }, + { + "code": "NO_RULES_FOR_CHAIN", + "userMessage": "This agent has no active rule for the selected network." + }, + { + "code": "FROM_NOT_ALLOWED", + "userMessage": "The agentic wallet is the sender. Remove the custom sender selection." + }, + { + "code": "NOT_ALLOWED_IN_AGENTIC_MODE", + "userMessage": "This action is unavailable while using an agentic wallet." + }, + { + "code": "INVALID_RULE", + "userMessage": "Some rule settings are invalid. Review the rule and try again." + }, + { + "code": "CAPABILITY_UNAVAILABLE", + "userMessage": "This feature is not available for this wallet or network yet." + }, + { + "code": "READ_ONLY", + "userMessage": "Connect a signing wallet to continue." + }, + { + "code": "NOT_WALLET_OWNER", + "userMessage": "Connect the owner wallet to change these permissions." + }, + { + "code": "RULE_NOT_FOUND", + "userMessage": "This rule could not be found. Refresh the wallet’s rules and try again." + }, + { + "code": "RULE_READ_FAILED", + "userMessage": "The wallet’s current state could not be loaded. Refresh and try again." + }, + { + "code": "INCONSISTENT_READ", + "userMessage": "The wallet changed while it was being checked. Refresh before trying again." + }, + { + "code": "INDEX_RACE", + "userMessage": "The expected wallet address changed. Refresh wallet information before trying again." + }, + { + "code": "RECEIPT_MISMATCH", + "userMessage": "The transaction result needs verification. Check its status before retrying." + }, + { + "code": "RECEIPT_UNAVAILABLE", + "userMessage": "The transaction was submitted, but its status could not be confirmed. Check its status before trying again." + }, + { + "code": "AGENT_GAS_INSUFFICIENT", + "userMessage": "The agent needs more Push coins to pay transaction fees." + }, + { + "code": "WALLET_BALANCE_INSUFFICIENT", + "userMessage": "The agentic wallet does not have enough funds for this action." + } + ], + "contracts": [ + { + "name": "AccessControlBadConfirmation", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "AccessControlEnforcedDefaultAdminDelay", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "AccessControlEnforcedDefaultAdminRules", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "AccessControlInvalidDefaultAdmin", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "AccessControlUnauthorizedAccount", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "AddressEmptyCode", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "AllowListOutOfRange", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "AlreadyCredited", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "AlreadyInitialized", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "AmbiguousRule", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "AmountExceedsCap", + "userMessage": "This action exceeds a rule’s spending or usage limit. Reduce the amount or ask the owner to update the rule." + }, + { + "name": "AmountExceedsU64", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "ArgPinAboveMax", + "userMessage": "This action exceeds a rule’s spending or usage limit. Reduce the amount or ask the owner to update the rule." + }, + { + "name": "ArgPinMismatch", + "userMessage": "This action does not match the wallet’s permissions. Check the token, recipient and allowed function." + }, + { + "name": "AssetListOutOfRange", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "AssetNotAllowed", + "userMessage": "This action does not match the wallet’s permissions. Check the token, recipient and allowed function." + }, + { + "name": "AssetSpentMismatch", + "userMessage": "The wallet changed while this action was being prepared. Refresh its state before trying again." + }, + { + "name": "AssociatedArray_OutOfBounds", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "BatchSizeOutOfRange", + "userMessage": "Too many rules or functions are selected. Reduce the selection and try again." + }, + { + "name": "CallLimitReached", + "userMessage": "This action exceeds a rule’s spending or usage limit. Reduce the amount or ask the owner to update the rule." + }, + { + "name": "CallNotAllowed", + "userMessage": "This action does not match the wallet’s permissions. Check the token, recipient and allowed function." + }, + { + "name": "CalldataTooShort", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "CalldataTooShortForAmount", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "CalldataTooShortForPin", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "CallerIsNotAgent", + "userMessage": "Connect the agent authorized by this rule." + }, + { + "name": "CallerIsNotFactory", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "CallerIsNotOwner", + "userMessage": "Connect the owner wallet to make this change." + }, + { + "name": "CallerIsNotUEModule", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "CeaAccountAtUnpinnedIndex", + "userMessage": "The rule is missing a required wallet-recipient restriction. Review its recipient settings." + }, + { + "name": "CeaAccountsMissExpectedCEA", + "userMessage": "The rule is missing a required wallet-recipient restriction. Review its recipient settings." + }, + { + "name": "ChainIdMismatch", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "ChainMismatch", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "CloneArgumentsTooLong", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "Create2EmptyBytecode", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "DiscriminatorLenOutOfRange", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "DuplicateAction", + "userMessage": "This rule contains duplicate functions, tokens or conditions. Remove the duplicate selection." + }, + { + "name": "DuplicateAsset", + "userMessage": "This rule contains duplicate functions, tokens or conditions. Remove the duplicate selection." + }, + { + "name": "DuplicateSvmPin", + "userMessage": "This rule contains duplicate functions, tokens or conditions. Remove the duplicate selection." + }, + { + "name": "ERC1967InvalidImplementation", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "ERC1967NonPayable", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "EmptyChain", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "EnforcedPause", + "userMessage": "This operation is temporarily paused. Try again later." + }, + { + "name": "EngineStillHoldsPermissions", + "userMessage": "This action does not match the wallet’s permissions. Check the token, recipient and allowed function." + }, + { + "name": "ExecutorMismatch", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "ExpectedPause", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "FailedCall", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "FailedDeployment", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "ForbiddenActionSelector", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "ForbiddenActionTarget", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "ForbiddenDispatchTarget", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "ForbiddenInnerTarget", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "ForbiddenProgramInAllowList", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "ForbiddenTargetProgram", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "ForbiddenValidationData", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "HashIndexOutOfBounds", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "HashMismatch", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "ImplementationNotSet", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "InconsistentChain", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "IndexMismatch", + "userMessage": "The wallet changed while this action was being prepared. Refresh its state before trying again." + }, + { + "name": "IndexOutOfRange", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "InsufficientBalance", + "userMessage": "There are not enough funds for this action. Check the wallet balance and fees." + }, + { + "name": "IntentExecMismatch", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "IntentGrantNonceMismatch", + "userMessage": "The wallet changed while this action was being prepared. Refresh its state before trying again." + }, + { + "name": "IntentGrantNonceNotZero", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "IntentRulesMismatch", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "IntentSessionMismatch", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "IntentWalletMismatch", + "userMessage": "The wallet changed while this action was being prepared. Refresh its state before trying again." + }, + { + "name": "InvalidActionId", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "InvalidAsset", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "InvalidCallTarget", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "InvalidCeaAccount", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "InvalidConfigField", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "InvalidData", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "InvalidEnableSignature", + "userMessage": "The signature could not be verified. Reconnect the authorized wallet and try again." + }, + { + "name": "InvalidExpiry", + "userMessage": "Choose a valid future expiry for this rule." + }, + { + "name": "InvalidISessionValidator", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "InvalidInitialization", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "InvalidMode", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "InvalidModuleAddress", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "InvalidNonce", + "userMessage": "The wallet changed while this action was being prepared. Refresh its state before trying again." + }, + { + "name": "InvalidOwnerSignature", + "userMessage": "The signature could not be verified. Reconnect the authorized wallet and try again." + }, + { + "name": "InvalidPermissionId", + "userMessage": "This action does not match the wallet’s permissions. Check the token, recipient and allowed function." + }, + { + "name": "InvalidRevertRecipient", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "InvalidSelector", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "InvalidSelfCall", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "InvalidSession", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "InvalidSessionKeySignature", + "userMessage": "The signature could not be verified. Reconnect the authorized wallet and try again." + }, + { + "name": "InvalidSvmConfigField", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "InvalidTarget", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "InvalidUserOpSender", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "LabelTooLong", + "userMessage": "The wallet name is too long. Shorten it and try again." + }, + { + "name": "MalformedBatchCalldata", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "MalformedConfig", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "MalformedInnerCalldata", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "MalformedOutboundRequest", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "MalformedSessionShape", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "MalformedSvmPayload", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "ModuleAlreadyInstalled", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "NativeAmountExceedsCap", + "userMessage": "This action exceeds a rule’s spending or usage limit. Reduce the amount or ask the owner to update the rule." + }, + { + "name": "NativeTargetIsGateway", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "NativeTargetZero", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "NoExecutionsInBatch", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "NoPoliciesSet", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "NotAWallet", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "NotInitialized", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "NotInitializing", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "OutsideTimeWindow", + "userMessage": "This request is outside its valid time window. Refresh and approve a new request." + }, + { + "name": "OwnerLaneRequired", + "userMessage": "Connect the owner wallet to make this change." + }, + { + "name": "OwnerSigExpired", + "userMessage": "The wallet approval has expired. Review and sign a new request." + }, + { + "name": "PCValueExceedsCap", + "userMessage": "The required gas exceeds this rule’s gas budget. Review the budget before trying again." + }, + { + "name": "PartlyEnabledActions", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "PartlyEnabledPolicies", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "PayloadNotMulticall", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "PaymasterValidationNotEnabled", + "userMessage": "This action does not match the wallet’s permissions. Check the token, recipient and allowed function." + }, + { + "name": "PolicyNotInitialized", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "PolicyViolation", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "ProgramListOutOfRange", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "ProgramNotAllowed", + "userMessage": "This action does not match the wallet’s permissions. Check the token, recipient and allowed function." + }, + { + "name": "RecipientMustBeEmpty", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "RecipientNotPubkey", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "RecipientTargetMismatch", + "userMessage": "This action does not match the wallet’s permissions. Check the token, recipient and allowed function." + }, + { + "name": "ReentrancyGuardReentrantCall", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "RuleWithoutPin", + "userMessage": "The rule is missing a required wallet-recipient restriction. Review its recipient settings." + }, + { + "name": "RulesExpired", + "userMessage": "This rule has expired. Ask the owner to renew it." + }, + { + "name": "RulesTypeMismatch", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "SafeCastOverflowedUintDowncast", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "SelectorMismatch", + "userMessage": "This action does not match the wallet’s permissions. Check the token, recipient and allowed function." + }, + { + "name": "SignatureExpired", + "userMessage": "The wallet approval has expired. Review and sign a new request." + }, + { + "name": "SignerNotFound", + "userMessage": "The signature could not be verified. Reconnect the authorized wallet and try again." + }, + { + "name": "SmartSessionModuleAlreadyInstalled", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "SpentLengthMismatch", + "userMessage": "The wallet changed while this action was being prepared. Refresh its state before trying again." + }, + { + "name": "SpentMismatch", + "userMessage": "The wallet changed while this action was being prepared. Refresh its state before trying again." + }, + { + "name": "SvmAccountCountBelowPin", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "SvmAccountCountMismatch", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "SvmAccountPinMismatch", + "userMessage": "This action does not match the wallet’s permissions. Check the token, recipient and allowed function." + }, + { + "name": "SvmAccountsOutOfRange", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "SvmDataCeilingExceeded", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "SvmDataFloorNotMet", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "SvmDataPinInvalid", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "SvmDataPinMismatch", + "userMessage": "This action does not match the wallet’s permissions. Check the token, recipient and allowed function." + }, + { + "name": "SvmDataRatioNotMet", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "SvmDataTooShortForPin", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "SvmInstructionNotExecute", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "SvmIxDataTooLong", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "SvmMaxAccountsOutOfRange", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "SvmPayloadEmpty", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "SvmPinIndexOutOfRange", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "SvmPinRuleOutOfRange", + "userMessage": "This function has too many conditions. Choose a simpler rule configuration." + }, + { + "name": "TargetMismatch", + "userMessage": "This action does not match the wallet’s permissions. Check the token, recipient and allowed function." + }, + { + "name": "TooManyActions", + "userMessage": "Too many rules or functions are selected. Reduce the selection and try again." + }, + { + "name": "TooManyAllowedCallPins", + "userMessage": "This rule has more than 32 conditions. Select fewer tokens or allowed functions." + }, + { + "name": "TooManyCeaAccounts", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "TooManyInitialRules", + "userMessage": "Too many rules or functions are selected. Reduce the selection and try again." + }, + { + "name": "TooManyPins", + "userMessage": "This function has too many conditions. Choose a simpler rule configuration." + }, + { + "name": "TooManySvmDataPins", + "userMessage": "This function has too many conditions. Choose a simpler rule configuration." + }, + { + "name": "TooManySvmPins", + "userMessage": "This function has too many conditions. Choose a simpler rule configuration." + }, + { + "name": "TotalNativeAmountExceeded", + "userMessage": "This action exceeds a rule’s spending or usage limit. Reduce the amount or ask the owner to update the rule." + }, + { + "name": "TotalSpendCapExceeded", + "userMessage": "This action exceeds a rule’s spending or usage limit. Reduce the amount or ask the owner to update the rule." + }, + { + "name": "TotalValueExceeded", + "userMessage": "This action exceeds a rule’s spending or usage limit. Reduce the amount or ask the owner to update the rule." + }, + { + "name": "UUPSUnauthorizedCallContext", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "UUPSUnsupportedProxiableUUID", + "userMessage": "This action is not supported on the selected network or wallet version." + }, + { + "name": "UncappedGasSwapRejected", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "UnknownPermission", + "userMessage": "This action does not match the wallet’s permissions. Check the token, recipient and allowed function." + }, + { + "name": "UnsupportedCallType", + "userMessage": "This action is not supported on the selected network or wallet version." + }, + { + "name": "UnsupportedEnvelopeVersion", + "userMessage": "This action is not supported on the selected network or wallet version." + }, + { + "name": "UnsupportedExecutionMode", + "userMessage": "This action is not supported on the selected network or wallet version." + }, + { + "name": "UnsupportedExecutionType", + "userMessage": "This action is not supported on the selected network or wallet version." + }, + { + "name": "UnsupportedModuleType", + "userMessage": "This action is not supported on the selected network or wallet version." + }, + { + "name": "UnsupportedNamespace", + "userMessage": "This action is not supported on the selected network or wallet version." + }, + { + "name": "UnsupportedPolicy", + "userMessage": "This action is not supported on the selected network or wallet version." + }, + { + "name": "UnsupportedSmartSessionMode", + "userMessage": "This action is not supported on the selected network or wallet version." + }, + { + "name": "ValidationFailed", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "ValidatorNotInstalled", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "ValueExceedsCap", + "userMessage": "This action exceeds a rule’s spending or usage limit. Reduce the amount or ask the owner to update the rule." + }, + { + "name": "ValueOnlyCalldataNotEmpty", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "ValueOnlyWithAmountRule", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "ValueOnlyWithPins", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "WrongModeForCall", + "userMessage": "This action is not supported on the selected network or wallet version." + }, + { + "name": "WrongVmForCall", + "userMessage": "This action is not supported on the selected network or wallet version." + }, + { + "name": "ZeroAddress", + "userMessage": "The wallet contract rejected this transaction. Review the permissions and transaction details before trying again." + }, + { + "name": "ZeroMaxCalls", + "userMessage": "This action exceeds a rule’s spending or usage limit. Reduce the amount or ask the owner to update the rule." + } + ] +} diff --git a/plan/agw/research/creation-error-review-2026-10-20/full-unit.log b/plan/agw/research/creation-error-review-2026-10-20/full-unit.log new file mode 100644 index 00000000..d9c5e36e --- /dev/null +++ b/plan/agw/research/creation-error-review-2026-10-20/full-unit.log @@ -0,0 +1,185 @@ +PASS core packages/core/src/lib/universal/account/account.spec.ts + ● Console + + console.warn + [PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead. + + 207 | ): Promise { + 208 | if (!_convertOriginToExecutorWarned) { + > 209 | console.warn( + | ^ + 210 | '[PushChain] convertOriginToExecutor() is deprecated. Use deriveExecutorAccount() instead.' + 211 | ); + 212 | _convertOriginToExecutorWarned = true; + + at Object.convertOriginToExecutor (src/lib/universal/account/account.ts:209:13) + at Object. (src/lib/universal/account/account.spec.ts:80:52) + + console.warn + [PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead. + + 425 | ): Promise { + 426 | if (!options?._internal && !_convertExecutorToOriginWarned) { + > 427 | console.warn( + | ^ + 428 | '[PushChain] convertExecutorToOrigin() is deprecated. Use resolveControllerAccount() instead.' + 429 | ); + 430 | _convertExecutorToOriginWarned = true; + + at convertExecutorToOrigin (src/lib/universal/account/account.ts:427:13) + at Object. (src/lib/universal/account/account.spec.ts:106:38) + +PASS core packages/core/src/lib/read-state/__tests__/block-results-client.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-tx-retry.spec.ts +PASS core packages/core/src/lib/push-client/push-client.archive-fallback.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-confirmation-gate.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-timeout-clamp.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/management.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/send.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/native-multi-action.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r2-outbound-revert-flow.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/labels.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/response-surface.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/creation-errors.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/read-tx-spec-strings.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/reads-context.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/registry.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/source-hash-resolution.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/codec.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-svm-confirmation.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/inbound-tracker-derivation.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/preset-routes.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/cascade.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gateway-uea-account.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-svm-rent.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-gas.spec.ts +PASS core packages/core/src/lib/universal/signer/signer.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/preset-default-policy.spec.ts +PASS core packages/core/src/lib/push-client/push-client.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/tx-transformer-multichain.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/send-transaction-progress-hook.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-emission.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts +PASS core packages/core/src/lib/utils.spec.ts + ● Console + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:973:17) + + console.log + 1.5 + + at Object. (src/lib/utils.spec.ts:977:17) + + console.log + 1.23 + + at Object. (src/lib/utils.spec.ts:982:17) + +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-evm-r3-native-eoa.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r3-spec-strings.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/preset-catalog.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-tracker.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/outbound-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-request-recipient.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r2-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/build-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/account-status.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/response-invariant.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/payload-builders.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-executor.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-composition.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/signing-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/export.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/presets.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.dynamic-gas.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/execute-standard-required-funds.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/push-chain-native-multicall.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/scenarios.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/rescue-svm-confirmation.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/context-helpers-tracker.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/web2-compat.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-event-hook-bridge.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm-rent-pc20.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/resolver.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/inbound-payload.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r1-error-classification.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/preset-operation-limits.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/preset-default-tokens.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/r1-spec-strings.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/cascade-builder-progress-hook.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-error-classification.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/gate.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/svm-rent.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-handlers-svm-r3.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/route-detector.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-backend.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-idl.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/public-rule.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/funds-only-burn-guard.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/chain-namespace.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/resolve.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-usd-sizer.spec.ts +PASS core packages/core/src/lib/progress-hook/__tests__/multichain-hooks.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/gas-calculator.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/track-transaction-guard.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/runtime-token-chain.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/terminal-suppression.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/response-builder-push-revert.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-types.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/public-surface.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/spec-builder.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-web2.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.batch-gas.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/svm-account.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-params.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-wire-fixture.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/revalidate-read.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-evm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/result-decoder.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/envelope-svm.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/svm-quote.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/detector-svm-log-index.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/address-codec.spec.ts +PASS core packages/core/src/lib/constants/__tests__/token-constants.spec.ts +PASS core packages/core/src/lib/agentic/__tests__/prc20-source-encoding.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/read-events.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/preflight.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/child-inbounds.spec.ts +PASS core packages/core/src/lib/vm-client/evm-client.chain-symbol.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/normalize.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/__tests__/signing.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/abi-selectors.spec.ts +PASS core packages/core/src/lib/universal/prc20-address.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/auto-detect.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/registry.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg-svm.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/ucallback-codec.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/ix-encoder.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/validate.spec.ts +PASS core packages/core/src/lib/constants/__tests__/svm-gateway-idl.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/r3-execute-order.spec.ts +PASS core packages/core/src/lib/orchestrator/svm-idl/normalize-address.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/error-decoder.spec.ts +PASS core packages/core/src/lib/universal-tx-detector/__tests__/classify.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/max-pc-for-gas.spec.ts +PASS core packages/core/src/lib/read-state/__tests__/budget.spec.ts +PASS core packages/core/src/lib/orchestrator/internals/pc20/__tests__/tracking.spec.ts +PASS core packages/core/src/lib/orchestrator/__tests__/errors.spec.ts +PASS core packages/core/src/lib/formatters.spec.ts + +Test Suites: 1 skipped, 132 passed, 132 of 133 total +Tests: 12 skipped, 2181 passed, 2193 total +Snapshots: 0 total +Time: 32.401 s +Ran all test suites. diff --git a/plan/agw/research/creation-error-review-2026-10-20/git-checkpoint-validation.json b/plan/agw/research/creation-error-review-2026-10-20/git-checkpoint-validation.json new file mode 100644 index 00000000..38c912ad --- /dev/null +++ b/plan/agw/research/creation-error-review-2026-10-20/git-checkpoint-validation.json @@ -0,0 +1,68 @@ +{ + "checked_at": "2026-10-20T10:10:06.895514+00:00", + "focused_unit_suites": 3, + "focused_tests_passed": 72, + "spec_typecheck_exit_code": 0, + "files": [ + { + "path": "packages/core/AGW.md", + "sha256": "1b5bfbacdcf80846ca7c3edec158ff785767682bdc6371e65ee18e1e57e3cd68" + }, + { + "path": "packages/core/__agw-local__/v5-multiasset.spec.ts", + "sha256": "59261313ec5d99e914097f277f4dad77232a63b9a308e7af43a9942846e92c9c" + }, + { + "path": "packages/core/src/lib/agentic/__tests__/creation-errors.spec.ts", + "sha256": "111ae710ae0b1096d4c696de648cb3e2443fcf75d8b6247fce21ec5b14f074b5" + }, + { + "path": "packages/core/src/lib/agentic/__tests__/preset-catalog.spec.ts", + "sha256": "44ce1daa12f2760e787f2b3ed6140d87b4726dac3203e70558f1cba5559a1dac" + }, + { + "path": "packages/core/src/lib/agentic/__tests__/preset-operation-limits.spec.ts", + "sha256": "357afd334f211e3383b1c82d784ef2981c0c998e10e7baca92eb931e96f39940" + }, + { + "path": "packages/core/src/lib/agentic/codec/rules.ts", + "sha256": "920a5c8b09b46ac7fc927e0f8ced69340bc1c4a7a90475e5778c057a7d852e72" + }, + { + "path": "packages/core/src/lib/agentic/codec/universal.ts", + "sha256": "5c7993e0e1d3284c61da8918ee1a657bac7c8ba3bd8d592033e89a65d7804f73" + }, + { + "path": "packages/core/src/lib/agentic/error-messages.ts", + "sha256": "378fb0343cf468c89f2e87f472c7423fcbb3dccddc4a98cdb8ed950aadc76b28" + }, + { + "path": "packages/core/src/lib/agentic/errors.ts", + "sha256": "b9b1b336f5567e12684f6f2cce7ec88ace0d627ab2788e6b06ae8b1324273246" + }, + { + "path": "packages/core/src/lib/agentic/management/common.ts", + "sha256": "8131a359d19a2c08b5720caad715eac101b1f39328e22888361f9edda45aecb5" + }, + { + "path": "packages/core/src/lib/agentic/management/destination.ts", + "sha256": "b48246902014735a92dfa0ea4d4a1bdfd552ab7016a25ccb07c19544653b3f32" + }, + { + "path": "packages/core/src/lib/agentic/management/prepare.ts", + "sha256": "aaa21c5a29fed7d5d5191a7bfc55b1e747ea16f22f1d505c9703e56738de0b1a" + }, + { + "path": "packages/core/src/lib/agentic/management/svm-public.ts", + "sha256": "fd82688de91b61f7e489751116dd1bad7f863885029624d1f3a775c844ad33b5" + }, + { + "path": "packages/core/src/lib/agentic/presets/index.ts", + "sha256": "e453fa6e8523ce70490915f643b7e00541a395b9e02e313676f3a9ceec6dbe37" + }, + { + "path": "packages/core/src/lib/agentic/public-rule.ts", + "sha256": "fb769f433f518a90fe7b904ad4d5cd36f6bf1dbad587087b2047fba9948c9125" + } + ] +} diff --git a/plan/agw/research/creation-error-review-2026-10-20/lint.log b/plan/agw/research/creation-error-review-2026-10-20/lint.log new file mode 100644 index 00000000..e69de29b diff --git a/plan/agw/research/creation-error-review-2026-10-20/local-types.log b/plan/agw/research/creation-error-review-2026-10-20/local-types.log new file mode 100644 index 00000000..e69de29b diff --git a/plan/agw/research/creation-error-review-2026-10-20/local.log b/plan/agw/research/creation-error-review-2026-10-20/local.log new file mode 100644 index 00000000..f74bf4dd --- /dev/null +++ b/plan/agw/research/creation-error-review-2026-10-20/local.log @@ -0,0 +1,29 @@ +PASS core-agw-local packages/core/__agw-local__/v5-multiasset.spec.ts (7.397 s) + v6 multi-asset SDK management and execution + ✓ v6 EVM alternatives enforce both spender and MAX, and reads update losslessly (122 ms) + ✓ v6 refuses a bare alternative that bypasses a pinned function and too many initial rules (24 ms) + ✓ the shipped DEX catalog enforces tuple receiver/token/amount pins on actual v6 URP (101 ms) + ✓ a default-token DEX exactInputSingle call rejects spending above its policy cap despite edited bridge budgets (71 ms) + ✓ a default-token DEX exactOutputSingle call rejects spending above its policy cap despite edited bridge budgets (62 ms) + ✓ public DEXES destination-funded defaults create directly without rewriting returned rules (59 ms) + ✓ public LENDING destination-funded defaults create directly without rewriting returned rules (54 ms) + ✓ public STAKING destination-funded defaults create directly without rewriting returned rules (45 ms) + ✓ regenerated LENDING presets enforce new token/amount pins through atomic rules.update (134 ms) + ✓ regenerated STAKING presets enforce new token/amount pins through atomic rules.update (208 ms) + ✓ a fixture preset produces rules accepted by public create and enforced by real contracts (80 ms) + ✓ public create encodes two ordered assets; public get reconstructs source-token caps (89 ms) + ✓ a token from the wrong chain fails before deployment (6 ms) + ✓ a same-chain registry identity mismatch fails before deployment (3 ms) + ✓ both tokens execute under one rule and keep independent counters/limits (131 ms) + ✓ omitted and explicit zero totals both prohibit movement (142 ms) + ✓ empty user assets grants one zero-cap gas token and executes a call-only request (150 ms) + ✓ public update resets both counters in one batch and records five checkpoints (168 ms) + ✓ spend on the second asset after snapshot rolls back revoke/grant and checkpoint writes (206 ms) + ✓ out-of-band duplicate contract grants still make sends ambiguous (82 ms) + ✓ a legacy two-field envelope is refused by the actual v6 grant path (11 ms) + +Test Suites: 1 passed, 1 total +Tests: 21 passed, 21 total +Snapshots: 0 total +Time: 7.43 s, estimated 9 s +Ran all test suites within paths "packages/core/__agw-local__/v5-multiasset.spec.ts". diff --git a/plan/agw/research/creation-error-review-2026-10-20/package.log b/plan/agw/research/creation-error-review-2026-10-20/package.log new file mode 100644 index 00000000..8e1b97e4 --- /dev/null +++ b/plan/agw/research/creation-error-review-2026-10-20/package.log @@ -0,0 +1 @@ +AGW package: CJS/ESM imports, compiled declaration examples and npm contents pass. No examples executed/published. diff --git a/plan/agw/research/creation-error-review-2026-10-20/types.log b/plan/agw/research/creation-error-review-2026-10-20/types.log new file mode 100644 index 00000000..e69de29b From 51487e21486f50722765e82c5cfd1374e8e22ad7 Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Tue, 20 Oct 2026 15:41:09 +0530 Subject: [PATCH 56/68] docs(marketplace): record verified baseline and SDK work history --- plan/SDK-CHANGELOG.md | 14 +- plan/marketplace/.gitattributes | 4 + plan/marketplace/README.md | 30 + plan/marketplace/SOURCES.md | 34 + .../analysis/mutability-and-payment.md | 52 + .../analysis/spec-and-contract-gaps.md | 31 + .../contracts/abi/AgenticCommerce.json | 1312 ++++++++++ .../contracts/abi/JobSpecBuilder.json | 117 + .../contracts/abi/RulesBindingHook.json | 309 +++ .../contracts/abi/UniversalMarketplace.json | 2290 +++++++++++++++++ .../abi/UniversalMarketplaceErrors.json | 411 +++ .../abi/UniversalMarketplaceRules.json | 318 +++ .../push_donut_universal_marketplace.md | 33 + .../docs/universalmarketplace/README.md | 847 ++++++ .../docs/universalmarketplace/criteria.md | 374 +++ .../docs/universalmarketplace/reference.md | 490 ++++ plan/marketplace/contracts/foundry.toml | 46 + plan/marketplace/contracts/remappings.txt | 3 + .../DeployUniversalMarketplace.s.sol | 115 + .../agentic-commerce-8183/AgenticCommerce.sol | 376 +++ .../UniversalMarketplace.sol | 603 +++++ .../UniversalMarketplaceRules.sol | 278 ++ .../hooks/BaseERC8183Hook.sol | 115 + .../hooks/RulesBindingHook.sol | 95 + .../interfaces/IAgenticCommerce.sol | 239 ++ .../interfaces/IERC8183Hook.sol | 25 + .../interfaces/IUniversalMarketplace.sol | 195 ++ .../interfaces/IUniversalMarketplaceRules.sol | 34 + .../interfaces/external/IAGW.sol | 76 + .../interfaces/external/IAGWFactory.sol | 31 + .../interfaces/external/ISmartSession.sol | 16 + .../libraries/Errors.sol | 96 + .../libraries/JobSpecBuilder.sol | 147 ++ .../libraries/JobSpecTypes.sol | 108 + .../agentic-commerce-8183/libraries/Types.sol | 199 ++ .../8183-tests/AgenticCommerce.admin.t.sol | 369 +++ .../8183-tests/AgenticCommerce.fuzz.t.sol | 86 + .../8183-tests/AgenticCommerce.hooks.t.sol | 187 ++ .../AgenticCommerce.invariants.t.sol | 305 +++ .../AgenticCommerce.lifecycle.t.sol | 660 +++++ .../test/8183-tests/BaseERC8183Hook.t.sol | 188 ++ .../test/8183-tests/Interfaces.t.sol | 36 + .../test/8183-tests/JobSpecBuilder.t.sol | 401 +++ .../test/8183-tests/KernelBase.t.sol | 94 + .../contracts/test/8183-tests/Naming.t.sol | 212 ++ .../8183-tests/RulesBindingHook.fork.t.sol | 43 + .../test/8183-tests/RulesBindingHook.t.sol | 438 ++++ .../UniversalMarketplace.conformance.t.sol | 284 ++ .../UniversalMarketplace.fork.t.sol | 317 +++ .../UniversalMarketplace.invariants.t.sol | 294 +++ .../8183-tests/UniversalMarketplace.t.sol | 2144 +++++++++++++++ .../UniversalMarketplaceRules.t.sol | 548 ++++ .../test/8183-tests/helpers/RulesFixtures.sol | 184 ++ .../test/8183-tests/helpers/TemplateParts.sol | 136 + .../test/8183-tests/helpers/V2Decoder.sol | 173 ++ .../test/8183-tests/mocks/BareHook.sol | 16 + .../test/8183-tests/mocks/ERC165Only.sol | 11 + .../test/8183-tests/mocks/MockAGW.sol | 106 + .../test/8183-tests/mocks/MockAGWFactory.sol | 65 + .../test/8183-tests/mocks/MockERC20_6.sol | 17 + .../test/8183-tests/mocks/MockPRC20Source.sol | 58 + .../8183-tests/mocks/MockSmartSession.sol | 15 + .../test/8183-tests/mocks/RecordingHook.sol | 44 + .../test/8183-tests/mocks/ReentrantHook.sol | 41 + .../test/8183-tests/mocks/RevertingHook.sol | 33 + .../8183-tests/mocks/RoutingProbeHook.sol | 93 + plan/marketplace/current-baseline.md | 58 + plan/marketplace/implementation-plan.md | 104 + .../notion/2-universal-marketplace.md | 195 ++ .../notion/3-8183-job-kernel-and-hook.md | 87 + .../notion/4-universal-evaluation.md | 145 ++ .../notion/6-sdk-universal-marketplace.md | 1162 +++++++++ plan/marketplace/notion/7-sdk-8183-job.md | 349 +++ .../notion/8-sdk-evaluation-placeholder.md | 23 + plan/marketplace/questions.md | 46 + .../research/2026-10-20/ReviewGaps.t.sol | 79 + .../research/2026-10-20/abi-manifest.json | 47 + .../2026-10-20/contract-source-manifest.json | 224 ++ .../2026-10-20/contract-test-command.json | 18 + .../2026-10-20/contract-test-summary.json | 21 + .../research/2026-10-20/contract-tests.log | 1 + .../research/2026-10-20/dependency-pins.json | 34 + .../evaluator-8059817/JobSpecTypes.sol | 116 + .../evaluator-8059817/UniversalEvaluator.sol | 801 ++++++ .../2026-10-20/evaluator-source-manifest.json | 14 + .../2026-10-20/evidence-archives.json | 13 + .../2026-10-20/final-source-recheck.json | 6 + .../2026-10-20/fork-tests-summary.json | 47 + .../research/2026-10-20/fork-tests.log | 1 + .../2026-10-20/invariant-tests-summary.json | 520 ++++ .../2026-10-20/invariant-tests.log.gz | Bin 0 -> 4466951 bytes .../research/2026-10-20/live-deployment.json | 146 ++ .../research/2026-10-20/notion-discussions.md | 42 + .../research/2026-10-20/notion-export.zip | Bin 0 -> 98001 bytes .../2026-10-20/notion-source-manifest.json | 57 + .../2026-10-20/review-gaps-summary.json | 45 + .../research/2026-10-20/review-gaps.log | 1 + .../research/2026-10-20/review-workspace.txt | 1 + .../2026-10-20/runtime-comparison.json | 140 + .../research/2026-10-20/summary.json | 18 + .../research/2026-10-20/validation.md | 58 + .../research/2026-10-20/wire-comparison.json | 50 + plan/marketplace/scripts/check-wire.cjs | 37 + plan/marketplace/scripts/compare-runtime.cjs | 52 + plan/marketplace/scripts/probe-live.cjs | 68 + 105 files changed, 21886 insertions(+), 1 deletion(-) create mode 100644 plan/marketplace/.gitattributes create mode 100644 plan/marketplace/README.md create mode 100644 plan/marketplace/SOURCES.md create mode 100644 plan/marketplace/analysis/mutability-and-payment.md create mode 100644 plan/marketplace/analysis/spec-and-contract-gaps.md create mode 100644 plan/marketplace/contracts/abi/AgenticCommerce.json create mode 100644 plan/marketplace/contracts/abi/JobSpecBuilder.json create mode 100644 plan/marketplace/contracts/abi/RulesBindingHook.json create mode 100644 plan/marketplace/contracts/abi/UniversalMarketplace.json create mode 100644 plan/marketplace/contracts/abi/UniversalMarketplaceErrors.json create mode 100644 plan/marketplace/contracts/abi/UniversalMarketplaceRules.json create mode 100644 plan/marketplace/contracts/docs/addresses/push_donut_universal_marketplace.md create mode 100644 plan/marketplace/contracts/docs/universalmarketplace/README.md create mode 100644 plan/marketplace/contracts/docs/universalmarketplace/criteria.md create mode 100644 plan/marketplace/contracts/docs/universalmarketplace/reference.md create mode 100644 plan/marketplace/contracts/foundry.toml create mode 100644 plan/marketplace/contracts/remappings.txt create mode 100644 plan/marketplace/contracts/scripts/agentic-commerce-8183/DeployUniversalMarketplace.s.sol create mode 100644 plan/marketplace/contracts/src/agentic-commerce-8183/AgenticCommerce.sol create mode 100644 plan/marketplace/contracts/src/agentic-commerce-8183/UniversalMarketplace.sol create mode 100644 plan/marketplace/contracts/src/agentic-commerce-8183/UniversalMarketplaceRules.sol create mode 100644 plan/marketplace/contracts/src/agentic-commerce-8183/hooks/BaseERC8183Hook.sol create mode 100644 plan/marketplace/contracts/src/agentic-commerce-8183/hooks/RulesBindingHook.sol create mode 100644 plan/marketplace/contracts/src/agentic-commerce-8183/interfaces/IAgenticCommerce.sol create mode 100644 plan/marketplace/contracts/src/agentic-commerce-8183/interfaces/IERC8183Hook.sol create mode 100644 plan/marketplace/contracts/src/agentic-commerce-8183/interfaces/IUniversalMarketplace.sol create mode 100644 plan/marketplace/contracts/src/agentic-commerce-8183/interfaces/IUniversalMarketplaceRules.sol create mode 100644 plan/marketplace/contracts/src/agentic-commerce-8183/interfaces/external/IAGW.sol create mode 100644 plan/marketplace/contracts/src/agentic-commerce-8183/interfaces/external/IAGWFactory.sol create mode 100644 plan/marketplace/contracts/src/agentic-commerce-8183/interfaces/external/ISmartSession.sol create mode 100644 plan/marketplace/contracts/src/agentic-commerce-8183/libraries/Errors.sol create mode 100644 plan/marketplace/contracts/src/agentic-commerce-8183/libraries/JobSpecBuilder.sol create mode 100644 plan/marketplace/contracts/src/agentic-commerce-8183/libraries/JobSpecTypes.sol create mode 100644 plan/marketplace/contracts/src/agentic-commerce-8183/libraries/Types.sol create mode 100644 plan/marketplace/contracts/test/8183-tests/AgenticCommerce.admin.t.sol create mode 100644 plan/marketplace/contracts/test/8183-tests/AgenticCommerce.fuzz.t.sol create mode 100644 plan/marketplace/contracts/test/8183-tests/AgenticCommerce.hooks.t.sol create mode 100644 plan/marketplace/contracts/test/8183-tests/AgenticCommerce.invariants.t.sol create mode 100644 plan/marketplace/contracts/test/8183-tests/AgenticCommerce.lifecycle.t.sol create mode 100644 plan/marketplace/contracts/test/8183-tests/BaseERC8183Hook.t.sol create mode 100644 plan/marketplace/contracts/test/8183-tests/Interfaces.t.sol create mode 100644 plan/marketplace/contracts/test/8183-tests/JobSpecBuilder.t.sol create mode 100644 plan/marketplace/contracts/test/8183-tests/KernelBase.t.sol create mode 100644 plan/marketplace/contracts/test/8183-tests/Naming.t.sol create mode 100644 plan/marketplace/contracts/test/8183-tests/RulesBindingHook.fork.t.sol create mode 100644 plan/marketplace/contracts/test/8183-tests/RulesBindingHook.t.sol create mode 100644 plan/marketplace/contracts/test/8183-tests/UniversalMarketplace.conformance.t.sol create mode 100644 plan/marketplace/contracts/test/8183-tests/UniversalMarketplace.fork.t.sol create mode 100644 plan/marketplace/contracts/test/8183-tests/UniversalMarketplace.invariants.t.sol create mode 100644 plan/marketplace/contracts/test/8183-tests/UniversalMarketplace.t.sol create mode 100644 plan/marketplace/contracts/test/8183-tests/UniversalMarketplaceRules.t.sol create mode 100644 plan/marketplace/contracts/test/8183-tests/helpers/RulesFixtures.sol create mode 100644 plan/marketplace/contracts/test/8183-tests/helpers/TemplateParts.sol create mode 100644 plan/marketplace/contracts/test/8183-tests/helpers/V2Decoder.sol create mode 100644 plan/marketplace/contracts/test/8183-tests/mocks/BareHook.sol create mode 100644 plan/marketplace/contracts/test/8183-tests/mocks/ERC165Only.sol create mode 100644 plan/marketplace/contracts/test/8183-tests/mocks/MockAGW.sol create mode 100644 plan/marketplace/contracts/test/8183-tests/mocks/MockAGWFactory.sol create mode 100644 plan/marketplace/contracts/test/8183-tests/mocks/MockERC20_6.sol create mode 100644 plan/marketplace/contracts/test/8183-tests/mocks/MockPRC20Source.sol create mode 100644 plan/marketplace/contracts/test/8183-tests/mocks/MockSmartSession.sol create mode 100644 plan/marketplace/contracts/test/8183-tests/mocks/RecordingHook.sol create mode 100644 plan/marketplace/contracts/test/8183-tests/mocks/ReentrantHook.sol create mode 100644 plan/marketplace/contracts/test/8183-tests/mocks/RevertingHook.sol create mode 100644 plan/marketplace/contracts/test/8183-tests/mocks/RoutingProbeHook.sol create mode 100644 plan/marketplace/current-baseline.md create mode 100644 plan/marketplace/implementation-plan.md create mode 100644 plan/marketplace/notion/2-universal-marketplace.md create mode 100644 plan/marketplace/notion/3-8183-job-kernel-and-hook.md create mode 100644 plan/marketplace/notion/4-universal-evaluation.md create mode 100644 plan/marketplace/notion/6-sdk-universal-marketplace.md create mode 100644 plan/marketplace/notion/7-sdk-8183-job.md create mode 100644 plan/marketplace/notion/8-sdk-evaluation-placeholder.md create mode 100644 plan/marketplace/questions.md create mode 100644 plan/marketplace/research/2026-10-20/ReviewGaps.t.sol create mode 100644 plan/marketplace/research/2026-10-20/abi-manifest.json create mode 100644 plan/marketplace/research/2026-10-20/contract-source-manifest.json create mode 100644 plan/marketplace/research/2026-10-20/contract-test-command.json create mode 100644 plan/marketplace/research/2026-10-20/contract-test-summary.json create mode 100644 plan/marketplace/research/2026-10-20/contract-tests.log create mode 100644 plan/marketplace/research/2026-10-20/dependency-pins.json create mode 100644 plan/marketplace/research/2026-10-20/evaluator-8059817/JobSpecTypes.sol create mode 100644 plan/marketplace/research/2026-10-20/evaluator-8059817/UniversalEvaluator.sol create mode 100644 plan/marketplace/research/2026-10-20/evaluator-source-manifest.json create mode 100644 plan/marketplace/research/2026-10-20/evidence-archives.json create mode 100644 plan/marketplace/research/2026-10-20/final-source-recheck.json create mode 100644 plan/marketplace/research/2026-10-20/fork-tests-summary.json create mode 100644 plan/marketplace/research/2026-10-20/fork-tests.log create mode 100644 plan/marketplace/research/2026-10-20/invariant-tests-summary.json create mode 100644 plan/marketplace/research/2026-10-20/invariant-tests.log.gz create mode 100644 plan/marketplace/research/2026-10-20/live-deployment.json create mode 100644 plan/marketplace/research/2026-10-20/notion-discussions.md create mode 100644 plan/marketplace/research/2026-10-20/notion-export.zip create mode 100644 plan/marketplace/research/2026-10-20/notion-source-manifest.json create mode 100644 plan/marketplace/research/2026-10-20/review-gaps-summary.json create mode 100644 plan/marketplace/research/2026-10-20/review-gaps.log create mode 100644 plan/marketplace/research/2026-10-20/review-workspace.txt create mode 100644 plan/marketplace/research/2026-10-20/runtime-comparison.json create mode 100644 plan/marketplace/research/2026-10-20/summary.json create mode 100644 plan/marketplace/research/2026-10-20/validation.md create mode 100644 plan/marketplace/research/2026-10-20/wire-comparison.json create mode 100644 plan/marketplace/scripts/check-wire.cjs create mode 100644 plan/marketplace/scripts/compare-runtime.cjs create mode 100644 plan/marketplace/scripts/probe-live.cjs diff --git a/plan/SDK-CHANGELOG.md b/plan/SDK-CHANGELOG.md index a99bbdd3..8e161655 100644 --- a/plan/SDK-CHANGELOG.md +++ b/plan/SDK-CHANGELOG.md @@ -4,6 +4,18 @@ Running history for work continued on `feat/agw-sdk-v4`, covering AGW, marketpla For each meaningful checkpoint, add a dated entry with the change, decisions, validation, remaining work and relevant commit/evidence links. Keep earlier entries as history and mark superseded decisions explicitly. Distinguish implemented code, planning, local/fork checks, funded execution, Git delivery and package publication. Git history for this file records the exact commit introducing each checkpoint. +## 2026-10-20 — marketplace research and implementation handoff + +**Planning delivered:** [plan/marketplace](marketplace/README.md) contains fresh exports of Notion pages 2/6/3/7/4/8, separately reviewed discussions, immutable contract/ABI snapshots, live Donut observations, a gap register, M4/K-12 analysis, the implementation sequence and draft team questions. This checkpoint adds no marketplace SDK runtime and sends no public-chain transactions or team comments. + +**Baseline:** deployed v2 from `sdk-iteration-v1@443b4e2dd9ca5dd9ffc8efebdfcecd619dd66c47`, AGW v6, pUSDC-only kernel and manual EOA evaluator. Work continues on `feat/agw-sdk-v4`. The latest AGW code checkpoint is `a542f303`. + +**Findings:** linked evaluator `8059817` has an incompatible JobSpec wire and enum ordinals; page 6's owner-approval array predates deployed pinned agent approvals; mutable criteria are inert; cancel frees occupancy but leaves AGW authority live; providerFee is a reference price. Recommendations and outstanding choices remain explicit in [questions](marketplace/questions.md), not silently treated as approved product changes. + +**Validation:** 248 ordinary contract tests, 2 separately run fork tests, 10 invariants at 64×64, and 4 independent review cases pass. All 5 executable runtime comparisons and all 4 CEA checks match. No funded live acceptance or automated evaluator execution is claimed. [Evidence and limits](marketplace/research/2026-10-20/validation.md). + +**Evidence handling:** the 45 MB invariant JSON log is retained losslessly as gzip with original/compressed checksums. Source exports remain byte-for-byte snapshots. Follow the implementation plan for the next SDK checkpoint and append its decisions, tests and remaining work here. + ## 2026-10-20 — AGW creation errors and UI messages **Implemented:** readable `userMessage` on SDK/revert errors; typed token-route and request-cancellation failures; rule/asset/call field context; complete per-rule constraint counts; destination read failures retain their classification and original causes. Updated the consumer guide and regression/contract assertions. @@ -12,7 +24,7 @@ For each meaningful checkpoint, add a dated entry with the change, decisions, va **Remaining:** the DEX UI overflow trigger needs the installed SDK version and exact create payload. Stock presets have 20 conditions; duplicating generated calls reproduces 40. Do not remove permission conditions to fit the limit. -**Git delivery:** included in the AGW error-fix commit on `feat/agw-sdk-v4`; a release-branch sync and npm publication are separate actions. +**Git delivery:** `a542f303` (`fix(core): clarify agentic creation and rule errors`) on `feat/agw-sdk-v4`; a release-branch sync and npm publication are separate actions. ## 2026-10-18 — starting AGW baseline diff --git a/plan/marketplace/.gitattributes b/plan/marketplace/.gitattributes new file mode 100644 index 00000000..dbf59a60 --- /dev/null +++ b/plan/marketplace/.gitattributes @@ -0,0 +1,4 @@ +# Preserve imported source and native exports byte-for-byte, including whitespace. +notion/** -whitespace +contracts/** -whitespace +research/**/*.log -whitespace diff --git a/plan/marketplace/README.md b/plan/marketplace/README.md new file mode 100644 index 00000000..8690836c --- /dev/null +++ b/plan/marketplace/README.md @@ -0,0 +1,30 @@ +# Agentic marketplace SDK planning + +Updated October 20, 2026. This folder is the research and implementation handoff for the next SDK phase. No marketplace SDK implementation or public-chain transaction was made by this review. Existing uncommitted AGW work is left intact. + +**Build against deployed UniversalMarketplace v2, pinned at `sdk-iteration-v1@443b4e2dd9ca5dd9ffc8efebdfcecd619dd66c47`.** The six supplied Notion pages were exported again through signed-in Chrome, and their visible discussion panels were reviewed. The older marketplace pages in `plan/agw/notion` remain historical. + +## Start here + +| Document | Purpose | +| --- | --- | +| [SDK development history](../SDK-CHANGELOG.md) | Running checkpoints, decisions, validation and Git delivery on feat/agw-sdk-v4 | +| [Verified baseline](current-baseline.md) | Deployment, capabilities, exact wire, and shipped versus future behavior | +| [Source inventory](SOURCES.md) | Fresh exports, immutable contract pins, comments and source priority | +| [Spec/contract gaps](analysis/spec-and-contract-gaps.md) | Concrete mismatches, ownership and effect on delivery | +| [Mutability and payment analysis](analysis/mutability-and-payment.md) | Answers to the supplied M4 / M6 / K-12 questions | +| [Implementation plan](implementation-plan.md) | SDK surfaces, module boundaries, sequence and acceptance requirements | +| [Questions to share](questions.md) | Questions for Zaryab, Harsh and the evaluator team; drafts only | +| [Validation](research/2026-10-20/validation.md) | Reproduced tests, read-only RPC checks, limits and commands | +| [Current Notion discussions](research/2026-10-20/notion-discussions.md) | Author/date/context, separate from exported page bodies | + +## Main conclusions + +- The deployed stack supports card management, one card per provider, one active marketplace job per wallet, v6 multi-asset sessions and pinned agent approvals. Opening deploys/reuses the wallet, grants rules and creates an **Open** job. It moves no funds. +- Payment is currently **pUSDC only**. The evaluator is an EOA; automated baseline, criteria replacement, verification and rating are not live capabilities. +- Page 8 retires `client.evaluation`. Plan `client.market`, `client.job`, `PushChain.utils.market`, `PushChain.utils.job`, and vocabulary under `PushChain.CONSTANTS.AGENTIC`. +- The evaluator source linked by Nilesh's October 16 comment is **wire-incompatible** with deployed marketplace v2, including different enum ordinals. Align contracts before automatic evaluation; never combine these encoders implicitly. +- The deployed card-rule struct has **no `approvals[]`**. Page 6 still describes the earlier owner-approval design. This needs an explicit SDK contract with product before those deposit fields are advertised. +- Kernel cancellation releases the marketplace slot but leaves AGW permissions enabled. Independent fork checks examine that behavior and an existing owner-batch cleanup path. + +Validation totals and evidence limitations are maintained in [validation.md](research/2026-10-20/validation.md), rather than copied into dated source snapshots. diff --git a/plan/marketplace/SOURCES.md b/plan/marketplace/SOURCES.md new file mode 100644 index 00000000..e14d6107 --- /dev/null +++ b/plan/marketplace/SOURCES.md @@ -0,0 +1,34 @@ +# Sources and refresh procedure + +## Authority and freshness + +For actual network behavior use pinned RPC evidence plus reproduced deployment source/ABIs. For intended SDK/product behavior use current Notion decisions and their dated comments; report contradictions instead of treating deployed behavior as automatic approval for a public API change. The user's pasted announcement confirms the v2 rollout and explicitly defers open/future features. Archived `plan/agw` marketplace drafts are historical. + +| Read order | Current page | Local source | +| --- | --- | --- | +| 2 | [Marketplace contract](https://app.notion.com/p/3e9188aea7f48118b90ac9b267496295) | [Export](notion/2-universal-marketplace.md) | +| 6 | [Marketplace SDK](https://app.notion.com/p/3ea188aea7f481e2961ed97129f3a4e6) | [Export](notion/6-sdk-universal-marketplace.md) | +| 3 | [Kernel and hook](https://app.notion.com/p/3e9188aea7f48188a838c3a740d8c858) | [Export](notion/3-8183-job-kernel-and-hook.md) | +| 7 | [Job SDK](https://app.notion.com/p/3ea188aea7f481e0a137f5a896723376) | [Export](notion/7-sdk-8183-job.md) | +| 4 | [Evaluation](https://app.notion.com/p/3e9188aea7f4817bb03ef4c78c883f8b) | [Export](notion/4-universal-evaluation.md) | +| 8 | [Evaluation SDK placeholder](https://app.notion.com/p/3ea188aea7f48197a3b3cfdedfa74fee) | [Export](notion/8-sdk-evaluation-placeholder.md) | + +All six were freshly downloaded on October 20 using Notion's Markdown & CSV export of the stack index with subpages. [Raw bundle](research/2026-10-20/notion-export.zip), [hashes and export entries](research/2026-10-20/notion-source-manifest.json). Raw bundle also contains the overview and AGW pages; only the six requested pages were imported here. No earlier AGW snapshots were overwritten. Original exported relative links are preserved as evidence and may point to unimported filenames; use the table above for navigation. + +Page exports **exclude comments**. Current All discussions panels on pages 2, 6, 3, 7 and 4 were separately read; page 8 exposes no Comments button in its current placeholder state. [Discussion observations](research/2026-10-20/notion-discussions.md) are paraphrases with author/date/context, not an exhaustive resolved-thread archive. No comments were posted, resolved or edited. + +## Immutable code sources + +- [Marketplace deployment branch, exact pin](https://github.com/pushchain/push-chain-core-contracts/tree/443b4e2dd9ca5dd9ffc8efebdfcecd619dd66c47). Includes [address book](contracts/docs/addresses/push_donut_universal_marketplace.md), [README](contracts/docs/universalmarketplace/README.md), [reference](contracts/docs/universalmarketplace/reference.md), [criteria guide](contracts/docs/universalmarketplace/criteria.md), sources, deployment script and tests. +- [Selected snapshot manifest](research/2026-10-20/contract-source-manifest.json): exact Git file hashes. `contracts/` is a reference subset; the test workspace is a separate full archive. Generated ABIs are in `contracts/abi` and have a separate manifest. +- [Pinned dependency revisions](research/2026-10-20/dependency-pins.json), including AGW `ffd567d`. Dependencies were archived at their actual submodule pins; the sibling repository's active branch was not checked out or changed. Dependency symlinks are omitted from the isolated archive. +- [Evaluator source linked in Nilesh's October 16 comment](https://github.com/pushchain/push-chain-core-contracts/blob/8059817591cca16c59f1cc154f475f51e1736a67/src/agentic-commerce-8183/libraries/JobSpecTypes.sol): [local types](research/2026-10-20/evaluator-8059817/JobSpecTypes.sol), [local evaluator](research/2026-10-20/evaluator-8059817/UniversalEvaluator.sol). These are comparison sources, **not** the deployed marketplace schema or proof of evaluator deployment. Page 7 also links older evaluator revision `4391181`; the later `8059817` source was read for current API differences. + +## Repeatable review + +1. Export the stack index with subpages again; retain ZIP and hashes. Match pages by stable ID. Keep comments separate. +2. Fetch `sdk-iteration-v1`; record full SHA before analysis and recheck remote head before sharing questions. Never save authenticated remote URLs in evidence. +3. Archive the exact source and pinned dependencies into an isolated workspace. Do not switch the SDK or sibling contract working trees. +4. Run unfunded unit/fuzz, explicitly scoped invariants and read-only fork tests. Preserve exit codes, skips, fork blocks and mock-versus-real scope. +5. Run the included read-only live probe and runtime comparator. Current scripts write October 20 evidence; use a new dated directory for a later review instead of overwriting this baseline. +6. Reconcile docs/code/observations in the gap register and remove questions already answered by newer evidence. Keep product choices distinct from SDK-owned implementation details. diff --git a/plan/marketplace/analysis/mutability-and-payment.md b/plan/marketplace/analysis/mutability-and-payment.md new file mode 100644 index 00000000..b99f20b3 --- /dev/null +++ b/plan/marketplace/analysis/mutability-and-payment.md @@ -0,0 +1,52 @@ +# M4 mutability and M6 / K-12 payment analysis + +October 20. This answers the questions in the user's supplied team discussion, checked against fresh Notion bodies/comments and deployment source. Recommendations below are proposals, not new product decisions. + +## M4: what the design says versus what exists + +The page-body understanding is substantially right: a provider-authorized replacement is proposed while Open, the client accepts at fund, and `origin`, `allowedMutability` and timing restrictions survive. The original page does not provide a client proposal route even though CLIENT/BOTH exists and setBudget is provider-only. + +**Current deployed v2 does none of the replacement workflow.** The builder copies the flag; the interim RulesBindingHook only processes fund's rulesId; the evaluator is an EOA. A setBudget payload does not replace the kernel's description or establish evaluator state. A non-NONE flag is not an implemented permission system. The independent review case registers BOTH, passes arbitrary replacement bytes to setBudget, observes the original description unchanged and funds successfully. + +The later evaluator source linked by Nilesh does contain a different client-fund replacement design in its type comments, but also a different wire, enum order and hook contract assumptions. It cannot resolve the deployed API by inference. Marketplace NONE=0 while that evaluator NONE=1 and BOTH=0 is a particularly dangerous ordinal mismatch. Never send bytes across those profiles on the assumption that matching enum names imply matching ABI. + +### Is it needed for the first release? + +Recommend retaining the schema field and requiring **NONE in the initial marketplace authoring flow**, pending Harsh's explicit decision. Parameterized templates already handle expected input variation. For a genuinely changed agreement, cancel the Open job, revoke its permissions, preview a new job and sign again. Do not describe cancel as revocation unless that cleanup actually happened. + +This is an SDK/product restriction unless enforced on-chain too: existing deployed contracts accept non-NONE templates. It is not a security guarantee against arbitrary direct callers. To guarantee immutable card criteria at protocol level, a compatible hook/evaluator or marketplace registration/open guard must enforce NONE. + +### The same-price front-run is real for the proposed mutable workflow + +`expectedBudget` only commits a number. If the future evaluator freezes its current standing proposal without checking what the funding client reviewed, the provider can replace criteria at the same price before fund executes. A last-moment SDK reread/simulation does not close a mempool race. + +The example's exact payout depends on the actual checks: changing only a rate threshold does not remove an independent “deposit at least 499 USDC” check if both are required. A whole replacement with weaker/removable checks can still make the attack work. The core issue is accepting an uncommitted spec, regardless of the example's arithmetic. + +### A complete later solution + +1. Give a quote/proposal a canonical identity, at minimum `keccak256(exactEncodedJobSpec)`, optionally a monotonically increasing quote revision. Keep marketplace/version/provider/client/kernel/job identity in the checked context. +2. The client reviews and authorizes **both the exact expected budget and exact expected spec hash/revision**. Do not silently refresh either when sending. The token is already immutable in the current single-token kernel; a later per-job token must be part of that accepted context too. +3. During fund, before acceptance/escrow commits, the hook compares the supplied expected hash/revision with the standing spec that will actually be frozen. Any mismatch reverts the entire transaction. Freeze those exact bytes atomically; no mutation after funding. +4. Authenticate proposals against the original allowedMutability. For CLIENT/BOTH, define an explicit authenticated client route: a dedicated proposal call, or a replacement submitted by the client in fund. Do not allow the provider to impersonate a client proposal through provider-only setBudget. Preserve origin/flag and validate complete replacement timing/structure. +5. Version the hook payload and capability. Today's RulesBindingHook **requires exactly 32 bytes**, so appending a hash to current `abi.encode(rulesId)` will revert. This requires compatible hook/evaluator delivery; it is not an SDK-only patch. A versioned payload might include rulesId, expectedSpecHash and proposal revision. Kernel signature can remain unchanged if its hooks enforce this through optParams. +6. Test same-price and changed-price front-runs, stale revisions, client/provider authorization, immutable fields, timing, rollback, replay, alternate hooks and terminal-state writes. SDK checks improve feedback; the on-chain atomic comparison supplies the protection. + +## M6 / K-12: present answer + +The requested end state is reasonable: each card chooses a token and every job's escrow/payout/refund uses that immutable token. Adding that token to createJob and the stored Job is a Push extension to the presently deployed ABI. The current kernel has one token from initialize and scalar totalEscrowed; a card label alone cannot change it. + +**The rollout has already chosen the interim path:** v2 registration/update rejects every card token except the kernel's actual pUSDC. No K-12 decision is needed to start this SDK phase. Read the deployed token and explicitly reject unsupported user input; do not follow the stale instruction that an explicit mismatching token is simply ignored. + +Do not switch marketplace addresses to an unrelated multi-token/demo kernel. KERNEL is set once, and old jobs remain associated with the old kernel. Bind ABI, hook, evaluator, token and marketplace configuration as one verified deployment profile. + +### If K-12 is approved later + +- Add token to creation and immutable per-job storage; use the job token in funding, provider/evaluator/platform payout, refunds and rescue accounting. Track escrow liabilities per token. Preserve old storage layout and define old-job migration/reads rather than reinterpreting existing slots. +- Keep a capability-specific createJob encoder. The token must be inside the createJob calldata hash authorized by OwnerIntent. Publish the new ABI/version and shared vectors together; no speculative two-format signing now. +- A curated admin allowlist is a reasonable first policy, with events and clear treatment of already-open/funded jobs when a token is delisted. Always permit settlement/refund of existing liabilities. An allowlist alone is not proof of safe ERC-20 behavior: validate exact received amounts or explicitly exclude fee-on-transfer/rebasing assets, and test reentrancy and unusual token failures. +- “PC” needs clarification: the current kernel is ERC-20-only. Native PC escrow is not accomplished by passing address(0); either choose a supported wrapped-PC ERC-20 or design payable/native accounting separately. +- Upgrade/redeploy the kernel plus compatible marketplace/hook wiring once the choice is final. Existing addresses and signed plans remain tied to their original deployment. Old signatures must fail closed on an incompatible new path. + +## Adjacent funding issue already present + +Card providerFee is a reference, not a kernel constraint. The independent test funds at three times the card's providerFee when the client supplies that exact larger expectedBudget. Therefore the page's “read current budget” convenience must not become silent price acceptance. For an initial fixed-card-price UX, fund against the **opened card version's reviewed providerFee** and reject a different current budget. For negotiation, expose an explicit reviewed quote with expectedBudget. The source makes either possible; product must choose the public behavior. diff --git a/plan/marketplace/analysis/spec-and-contract-gaps.md b/plan/marketplace/analysis/spec-and-contract-gaps.md new file mode 100644 index 00000000..e33bd97f --- /dev/null +++ b/plan/marketplace/analysis/spec-and-contract-gaps.md @@ -0,0 +1,31 @@ +# Spec, deployment and SDK gaps + +October 20, 2026. **P0** blocks automatic-evaluation integration; **P1** affects a promised behavior or safe transaction construction; **P2** is a bounded SDK design/detail. A finding is not automatically a request for a contract change. Existing deployed behavior can support a smaller explicit first release. + +| ID | Priority | Evidence / mismatch | Disposition and owner | +| --- | --- | --- | --- | +| W01 | P0 for automatic evaluation | [Deployed types](../contracts/src/agentic-commerce-8183/libraries/JobSpecTypes.sol) versus [evaluator `8059817`](../research/2026-10-20/evaluator-8059817/JobSpecTypes.sol): top-level order differs; Read gains `at`; Check becomes left/right arrays; Logic has CHECK leaves; NONE/BOTH and logic enum ordinals differ. [Controlled vectors](../research/2026-10-20/wire-comparison.json) do not cross-decode. | Zaryab + Nilesh/Aman: choose one shared package/pin and matching marketplace builder/hook/evaluator. SDK may implement deployed v2 card/open/manual-job flow now, but cannot advertise automatic evaluation. No implicit conversion of signed bytes. | +| W02 | P1 | [Page 6](../notion/6-sdk-universal-marketplace.md) still has `rules.approvals[]`, owner approval deposit steps, `skipApprovals`, and approve denial. [Deployed rules](../contracts/src/agentic-commerce-8183/libraries/Types.sol) omit approvals; [helper](../contracts/src/agentic-commerce-8183/UniversalMarketplaceRules.sol) allows pinned `approve`. | Confirm public SDK follows v2 D1. Remove or explicitly revise obsolete fields instead of serializing an old 5-field tuple or silently dropping requested approvals. Product/SDK API alignment; deployed capability already exists. | +| W03 | P1, future feature | M4 flag is stored, but interim hook does not process proposals or freeze specs. Non-NONE templates can be registered/funded. Independent review test confirms arbitrary `setBudget.optParams` is ignored. | Recommend NONE authoring policy for initial marketplace delivery, subject to Harsh's decision. No mutability promises for this deployment. Future proposals require atomic expected-spec binding at fund; [analysis](mutability-and-payment.md). | +| W04 | P1, explicitly deferred | K-12 not implemented. `_validateCard` enforces `card.paymentToken == KERNEL.paymentToken()`. Kernel createJob has no token parameter and escrow is scalar. | Ship pUSDC capability profile without waiting for K-12. Reject mismatching explicit tokens; never silently ignore a caller's token. Future upgrade needs new ABI/deployment identity. | +| W05 | P1 | Open cancellation exists as `kernel.reject`, but page 7 omits a client cancel function and explicitly removes evaluatorOnly reject. Hook never revokes rules. Review fork proves cancel frees slot, old/new permissions both remain enabled after reopen. | Harsh: decide user-facing `job.cancel` and cleanup policy. Existing AGW owner batch can atomically reject + revoke the recorded rulesId; independently passed against real v6. Contract team still owns automatic provider/evaluator-triggered cleanup. Never equate kernel terminal state with revoked authority. | +| W06 | P1 contract/spec discrepancy | Page 3 says createJob hookable on Push. [Current createJob](../contracts/src/agentic-commerce-8183/AgenticCommerce.sol) is explicitly unhooked. | Zaryab/Aman: mark as deferred or deliver core change. Does not block deployed marketplace opening, and the evaluator design says it must not depend on this hook. Do not synthesize hook events. | +| W07 | P1 | Page 7 fund prose says read current stored budget, but also says marketplace funding passes the card's providerFee. Kernel checks only `expectedBudget`; independent test funds at 3× card fee when client supplies 3×. | Preserve the user's reviewed quote. Harsh: fixed card reference fee for first release, or explicit negotiated quote acceptance? Never replace an accepted expected amount with an arbitrary freshly read one. ProviderFee is not protocol-enforced. | +| W08 | P1 | Page 6 pure `universal.read.prepare` returns `{namespace,chainId,target,selector,args,outputs}` and preserves placeholders. Existing SDK has async `universal.prepareRead(subject, opts)` returning a funded request/preflight, query envelope and resultShape; no nested `.prepare` or evaluator `outputs` compiler. | SDK-owned reusable parser/query encoder plus explicit pure authoring adapter; confirm additive API naming with Harsh. Preserve existing read/prepareRead callers. Address sentinels need metadata/zero-word lowering before ABI encoding; existing viem address encoder cannot accept them unchanged. | +| W09 | P1 | Page 7 proposes snapshot/verify/status/watch evaluator facts, but live evaluator has zero code. Linked `8059817` implements `startSnapshot`, `verifyFromSubmit` (onlyHook), `sendReads`, `retrySnapshot`, `prefundCost`, etc., not the page's generic API. | Gate all evaluator paths by verified deployment and matching ABI. Unsupported calls fail before signing; absent baseline/verdict is unavailable, not PASS. Ask for compatible delivery rather than implementing against stale names. | +| W10 | P1 | Page 6 example defaults `relay=true` for external owners; its dated decision says client submits by default and relay is later. Typed OwnerIntent authorization plus client transaction submission may require two signing interactions. Non-EVM signers may lack EIP-712. | Follow dated client-submission decision; clarify whether “one signature” means one OwnerIntent or one total wallet prompt. Do not invent a relayer endpoint or claim external-origin coverage before ERC-1271/typed-signing tests. | +| W11 | P1 | `previewIntent` only requires an existing card and builds the intent/calldata; it does not call `_checkCardAndJob`, `_checkRules` or occupancy checks. | SDK preview must perform complete block-consistent preflight and local rules matching, then revalidate the exact plan before signing/sending. Preserve stale plan errors; never silently refresh and sign different content. | +| W12 | P1 | `deposit(jobId)` must recover the opened card version and principal. Marketplace retains only current card blobs plus job/card/version/rules mappings; `JobOpened` carries principal and version. Updates can happen before a later deposit. | SDK-owned historical snapshot resolver: retain validated plan or reconstruct exact version using logs/transaction input/historical reads. Verify hashes/version; block-end card reads alone can see a later same-block update. Never deposit using the latest card's changed amounts/calls. Expose recoverable failure if history is unavailable. | +| W13 | P2 | `jobType` bytes32 cannot be inverted to a string; decoded raw selectors do not recover function names; version/rating are uint256 but SDK draft uses number. | Keep canonical hash/raw selector/word positions, use verified optional metadata labels, and use bigint or checked safe conversion. Do not invent original names/ABI. | +| W14 | P2 | Page 6 says card/template authoring pure, yet token resolution may need network/source metadata. `decodeAgentCardRules` promises destination token addresses from stored PRC20s. | Reuse verified registry where deterministic; distinguish unresolved raw tokens and cached metadata. Decide/document what pure helper accepts. No network hidden in a synchronous helper or token alias guessing. | +| W15 | P2 | Registry has count, per-provider lookup and per-ID full view, no pagination/indexer. Job counter/getJob similarly walkable. Some events omit full blobs/deliverable. | Bounded concurrency, progress, block-consistent enumeration, explicit fromJobId, event cursor/deduplication and transaction-input recovery where needed. Record practical limits without adding an invented indexer service. | +| W16 | P2 | Live helper/kernel runtimes are the 1,000-run artifacts; README size table describes larger variants. Explorer source verification is absent per repo. | Source/runtime comparison now passes. Documentation correction only; no code/deployment drift established. Retain compiler/profile provenance and full error-library ABI (40 marketplace errors). | +| W17 | Scope boundary | Current cards are EVM destination only. Read schema is EVM shaped, current evaluator EOA, recurring jobs and verified ratings remain separate. | Keep out of initial capability claims. Existing AGW Solana capability does not imply Solana marketplace cards. Presets are permission templates, not offers, pricing or job criteria. | + +## Work that can proceed + +Verified deployment/ABI registry; card reads and provider writes; v2 card-rule codecs/markers; deployed JobSpec/template codecs with contract vectors; human-readable permission/criteria descriptions; local validation; intent/session composition and stale-plan checks; kernel create/quote/fund/submit/refund/status/list/watch; explicit manual-evaluator behavior; existing-read integration design. + +## Decisions to resolve before relevant surfaces are advertised + +Public approvals/deposit shape (W02), canonical automatic-evaluation wire (W01), mutability policy (W03), expected-budget policy (W07), cancel surface/cleanup (W05), pure-read helper shape (W08), and signing/relay promise (W10). These do not require stopping all SDK work or reopening already-delivered AGW functionality. diff --git a/plan/marketplace/contracts/abi/AgenticCommerce.json b/plan/marketplace/contracts/abi/AgenticCommerce.json new file mode 100644 index 00000000..0d2d3cac --- /dev/null +++ b/plan/marketplace/contracts/abi/AgenticCommerce.json @@ -0,0 +1,1312 @@ +[ + { + "type": "constructor", + "inputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "ADMIN_ROLE", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "BPS_DENOMINATOR", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "DEFAULT_ADMIN_ROLE", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "EVALUATOR_GRACE_PERIOD", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "MIN_EXPIRY_WINDOW", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "batchDetachHook", + "inputs": [ + { + "name": "jobIds", + "type": "uint256[]", + "internalType": "uint256[]" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "claimRefund", + "inputs": [ + { + "name": "jobId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "complete", + "inputs": [ + { + "name": "jobId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "reason", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "optParams", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "createJob", + "inputs": [ + { + "name": "provider", + "type": "address", + "internalType": "address" + }, + { + "name": "evaluator", + "type": "address", + "internalType": "address" + }, + { + "name": "expiredAt", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "description", + "type": "string", + "internalType": "string" + }, + { + "name": "hook", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "jobId", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "emergencyWithdraw", + "inputs": [ + { + "name": "token", + "type": "address", + "internalType": "address" + }, + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "evaluatorFeeBP", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "fund", + "inputs": [ + { + "name": "jobId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "expectedBudget", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "optParams", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "getJob", + "inputs": [ + { + "name": "jobId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "tuple", + "internalType": "struct IAgenticCommerce.Job", + "components": [ + { + "name": "client", + "type": "address", + "internalType": "address" + }, + { + "name": "status", + "type": "uint8", + "internalType": "enum IAgenticCommerce.JobStatus" + }, + { + "name": "provider", + "type": "address", + "internalType": "address" + }, + { + "name": "expiredAt", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "evaluator", + "type": "address", + "internalType": "address" + }, + { + "name": "hook", + "type": "address", + "internalType": "address" + }, + { + "name": "budget", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "description", + "type": "string", + "internalType": "string" + } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getRoleAdmin", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "grantRole", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "hasRole", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "initialize", + "inputs": [ + { + "name": "paymentToken_", + "type": "address", + "internalType": "address" + }, + { + "name": "treasury_", + "type": "address", + "internalType": "address" + }, + { + "name": "admin_", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "jobCounter", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "pause", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "paused", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "paymentToken", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract IERC20" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "platformFeeBP", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "platformTreasury", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "reject", + "inputs": [ + { + "name": "jobId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "reason", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "optParams", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "renounceRole", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "callerConfirmation", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "revokeRole", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setBudget", + "inputs": [ + { + "name": "jobId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "optParams", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setEvaluatorFee", + "inputs": [ + { + "name": "feeBP", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setHookWhitelist", + "inputs": [ + { + "name": "hook", + "type": "address", + "internalType": "address" + }, + { + "name": "status", + "type": "bool", + "internalType": "bool" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setPlatformFee", + "inputs": [ + { + "name": "feeBP", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "treasury", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setProvider", + "inputs": [ + { + "name": "jobId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "provider", + "type": "address", + "internalType": "address" + }, + { + "name": "optParams", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "submit", + "inputs": [ + { + "name": "jobId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "deliverable", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "optParams", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "supportsInterface", + "inputs": [ + { + "name": "interfaceId", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "totalEscrowed", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "unpause", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "whitelistedHooks", + "inputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "event", + "name": "BudgetSet", + "inputs": [ + { + "name": "jobId", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "EmergencyWithdraw", + "inputs": [ + { + "name": "token", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "to", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "EvaluatorFeePaid", + "inputs": [ + { + "name": "jobId", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "evaluator", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "EvaluatorFeeUpdated", + "inputs": [ + { + "name": "feeBP", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "HookDetached", + "inputs": [ + { + "name": "jobId", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "hook", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "HookWhitelistUpdated", + "inputs": [ + { + "name": "hook", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "status", + "type": "bool", + "indexed": false, + "internalType": "bool" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Initialized", + "inputs": [ + { + "name": "version", + "type": "uint64", + "indexed": false, + "internalType": "uint64" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "JobCompleted", + "inputs": [ + { + "name": "jobId", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "evaluator", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "reason", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "JobCreated", + "inputs": [ + { + "name": "jobId", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "client", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "provider", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "evaluator", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "expiredAt", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "hook", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "JobExpired", + "inputs": [ + { + "name": "jobId", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "JobFunded", + "inputs": [ + { + "name": "jobId", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "client", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "JobRejected", + "inputs": [ + { + "name": "jobId", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "rejector", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "reason", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "JobSubmitted", + "inputs": [ + { + "name": "jobId", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "provider", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "deliverable", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Paused", + "inputs": [ + { + "name": "account", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "PaymentReleased", + "inputs": [ + { + "name": "jobId", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "provider", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "PlatformFeePaid", + "inputs": [ + { + "name": "jobId", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "treasury", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "PlatformFeeUpdated", + "inputs": [ + { + "name": "feeBP", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "treasury", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ProviderSet", + "inputs": [ + { + "name": "jobId", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "provider", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Refunded", + "inputs": [ + { + "name": "jobId", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "client", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RoleAdminChanged", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "previousAdminRole", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "newAdminRole", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RoleGranted", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RoleRevoked", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Unpaused", + "inputs": [ + { + "name": "account", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "AccessControlBadConfirmation", + "inputs": [] + }, + { + "type": "error", + "name": "AccessControlUnauthorizedAccount", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "neededRole", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "BudgetMismatch", + "inputs": [] + }, + { + "type": "error", + "name": "ClientIsProvider", + "inputs": [] + }, + { + "type": "error", + "name": "EnforcedPause", + "inputs": [] + }, + { + "type": "error", + "name": "EvaluatorIsProvider", + "inputs": [] + }, + { + "type": "error", + "name": "ExpectedPause", + "inputs": [] + }, + { + "type": "error", + "name": "ExpiryTooShort", + "inputs": [] + }, + { + "type": "error", + "name": "FeesTooHigh", + "inputs": [] + }, + { + "type": "error", + "name": "GracePeriodActive", + "inputs": [] + }, + { + "type": "error", + "name": "HookNotWhitelisted", + "inputs": [] + }, + { + "type": "error", + "name": "InsufficientUnattributedBalance", + "inputs": [ + { + "name": "requested", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "available", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "InvalidHook", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidInitialization", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidJob", + "inputs": [] + }, + { + "type": "error", + "name": "NotInitializing", + "inputs": [] + }, + { + "type": "error", + "name": "ProviderNotSet", + "inputs": [] + }, + { + "type": "error", + "name": "ReentrancyGuardReentrantCall", + "inputs": [] + }, + { + "type": "error", + "name": "SafeERC20FailedOperation", + "inputs": [ + { + "name": "token", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "Unauthorized", + "inputs": [] + }, + { + "type": "error", + "name": "WrongStatus", + "inputs": [] + }, + { + "type": "error", + "name": "ZeroAddress", + "inputs": [] + } +] diff --git a/plan/marketplace/contracts/abi/JobSpecBuilder.json b/plan/marketplace/contracts/abi/JobSpecBuilder.json new file mode 100644 index 00000000..70a5ec8c --- /dev/null +++ b/plan/marketplace/contracts/abi/JobSpecBuilder.json @@ -0,0 +1,117 @@ +[ + { + "type": "function", + "name": "build", + "inputs": [ + { + "name": "jobSpecTemplate", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "ctx", + "type": "tuple", + "internalType": "struct BuildContext", + "components": [ + { + "name": "agw", + "type": "address", + "internalType": "address" + }, + { + "name": "principal", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "executeBy", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "settleWindow", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "params", + "type": "int256[]", + "internalType": "int256[]" + }, + { + "name": "origin", + "type": "bytes32", + "internalType": "bytes32" + } + ] + } + ], + "outputs": [ + { + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], + "stateMutability": "view" + }, + { + "type": "error", + "name": "FillOutOfBounds", + "inputs": [ + { + "name": "read", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "fill", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "ParamCountMismatch", + "inputs": [ + { + "name": "expected", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "actual", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "ParamOutOfRange", + "inputs": [ + { + "name": "index", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "value", + "type": "int256", + "internalType": "int256" + } + ] + }, + { + "type": "error", + "name": "TargetOverflow", + "inputs": [ + { + "name": "check", + "type": "uint256", + "internalType": "uint256" + } + ] + } +] diff --git a/plan/marketplace/contracts/abi/RulesBindingHook.json b/plan/marketplace/contracts/abi/RulesBindingHook.json new file mode 100644 index 00000000..a4e6044a --- /dev/null +++ b/plan/marketplace/contracts/abi/RulesBindingHook.json @@ -0,0 +1,309 @@ +[ + { + "type": "constructor", + "inputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "AGW_FACTORY", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "KERNEL", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "SESSION_ENGINE", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "activeJobOf", + "inputs": [ + { + "name": "agw", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "afterAction", + "inputs": [ + { + "name": "jobId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "selector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "data", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "agwOfJob", + "inputs": [ + { + "name": "jobId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "beforeAction", + "inputs": [ + { + "name": "jobId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "selector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "data", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "initialize", + "inputs": [ + { + "name": "kernel_", + "type": "address", + "internalType": "address" + }, + { + "name": "agwFactory_", + "type": "address", + "internalType": "address" + }, + { + "name": "sessionEngine_", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "rulesOfJob", + "inputs": [ + { + "name": "jobId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "supportsInterface", + "inputs": [ + { + "name": "interfaceId", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "event", + "name": "Initialized", + "inputs": [ + { + "name": "version", + "type": "uint64", + "indexed": false, + "internalType": "uint64" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RulesBound", + "inputs": [ + { + "name": "jobId", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "agw", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "rulesId", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "AGWHasLiveJob", + "inputs": [ + { + "name": "agw", + "type": "address", + "internalType": "address" + }, + { + "name": "liveJobId", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "CallerIsNotAGW", + "inputs": [ + { + "name": "caller", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "CallerIsNotKernel", + "inputs": [ + { + "name": "caller", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "InvalidInitialization", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidOptParams", + "inputs": [ + { + "name": "length", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "NotInitializing", + "inputs": [] + }, + { + "type": "error", + "name": "RulesNotLive", + "inputs": [ + { + "name": "agw", + "type": "address", + "internalType": "address" + }, + { + "name": "rulesId", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "ZeroAddress", + "inputs": [] + } +] diff --git a/plan/marketplace/contracts/abi/UniversalMarketplace.json b/plan/marketplace/contracts/abi/UniversalMarketplace.json new file mode 100644 index 00000000..fe12eab2 --- /dev/null +++ b/plan/marketplace/contracts/abi/UniversalMarketplace.json @@ -0,0 +1,2290 @@ +[ + { + "type": "constructor", + "inputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "ADMIN_ROLE", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "AGW_FACTORY", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract IAGWFactory" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "DEFAULT_ADMIN_ROLE", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "KERNEL", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract IAgenticCommerce" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "MODE_SINGLE", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "OPENJOB_LANE", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint192", + "internalType": "uint192" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "PUSH_CHAIN_HASH", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "RULES", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract IUniversalMarketplaceRules" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "activeJobOf", + "inputs": [ + { + "name": "agw", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "agentCardCount", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "agentCardOf", + "inputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "agentCardVersion", + "inputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "agwOfJob", + "inputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "buildCreateJobCalldata", + "inputs": [ + { + "name": "cardId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "index", + "type": "uint96", + "internalType": "uint96" + }, + { + "name": "job", + "type": "tuple", + "internalType": "struct JobInputs", + "components": [ + { + "name": "principal", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "expiredAt", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "executeBy", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "params", + "type": "int256[]", + "internalType": "int256[]" + } + ] + } + ], + "outputs": [ + { + "name": "mode", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "executionCalldata", + "type": "bytes", + "internalType": "bytes" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "cardOfJob", + "inputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "cardVersionOfJob", + "inputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "ceaDeployment", + "inputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [ + { + "name": "ceaFactory", + "type": "address", + "internalType": "address" + }, + { + "name": "ceaProxyImpl", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "computeCEA", + "inputs": [ + { + "name": "agw", + "type": "address", + "internalType": "address" + }, + { + "name": "chainHash", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "disableAgentCard", + "inputs": [ + { + "name": "cardId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "evaluator", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getAgentCard", + "inputs": [ + { + "name": "cardId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "v", + "type": "tuple", + "internalType": "struct AgentCardView", + "components": [ + { + "name": "card", + "type": "tuple", + "internalType": "struct AgentCard", + "components": [ + { + "name": "provider", + "type": "address", + "internalType": "address" + }, + { + "name": "jobType", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "metadataURI", + "type": "string", + "internalType": "string" + }, + { + "name": "metadataHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "chainNamespace", + "type": "string", + "internalType": "string" + }, + { + "name": "providerFee", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "paymentToken", + "type": "address", + "internalType": "address" + }, + { + "name": "principalMin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "principalMax", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "minDuration", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "maxDuration", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "minExecuteWindow", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "settleWindow", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "active", + "type": "bool", + "internalType": "bool" + } + ] + }, + { + "name": "rules", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "jobSpecTemplate", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "version", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "verified", + "type": "bool", + "internalType": "bool" + }, + { + "name": "disabled", + "type": "bool", + "internalType": "bool" + } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getAgentRating", + "inputs": [ + { + "name": "agent", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getRoleAdmin", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "grantRole", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "hasRole", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "hook", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "initialize", + "inputs": [ + { + "name": "p", + "type": "tuple", + "internalType": "struct InitParams", + "components": [ + { + "name": "agwFactory", + "type": "address", + "internalType": "address" + }, + { + "name": "kernel", + "type": "address", + "internalType": "address" + }, + { + "name": "hook", + "type": "address", + "internalType": "address" + }, + { + "name": "evaluator", + "type": "address", + "internalType": "address" + }, + { + "name": "rules", + "type": "address", + "internalType": "address" + }, + { + "name": "admin", + "type": "address", + "internalType": "address" + } + ] + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "isAgentCardDisabled", + "inputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isAgentCardVerified", + "inputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "openJob", + "inputs": [ + { + "name": "p", + "type": "tuple", + "internalType": "struct OpenJobParams", + "components": [ + { + "name": "cardId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "cardVersion", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "job", + "type": "tuple", + "internalType": "struct JobInputs", + "components": [ + { + "name": "principal", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "expiredAt", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "executeBy", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "params", + "type": "int256[]", + "internalType": "int256[]" + } + ] + }, + { + "name": "session", + "type": "tuple", + "internalType": "struct Session", + "components": [ + { + "name": "sessionValidator", + "type": "address", + "internalType": "address" + }, + { + "name": "sessionValidatorInitData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "erc7739Policies", + "type": "tuple", + "internalType": "struct ERC7739Data", + "components": [ + { + "name": "allowedERC7739Content", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNames", + "type": "string[]", + "internalType": "string[]" + } + ] + }, + { + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "actions", + "type": "tuple[]", + "internalType": "struct ActionData[]", + "components": [ + { + "name": "actionTargetSelector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "actionTarget", + "type": "address", + "internalType": "address" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "permitERC4337Paymaster", + "type": "bool", + "internalType": "bool" + } + ] + }, + { + "name": "intent", + "type": "tuple", + "internalType": "struct OwnerIntent", + "components": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "wallet", + "type": "address", + "internalType": "address" + }, + { + "name": "executor", + "type": "address", + "internalType": "address" + }, + { + "name": "index", + "type": "uint96", + "internalType": "uint96" + }, + { + "name": "sessionHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "mode", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "execCalldataHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "nonceKey", + "type": "uint192", + "internalType": "uint192" + }, + { + "name": "nonceSeq", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "grantNonce", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "deadline", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "signerChainId", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "sig", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "label", + "type": "string", + "internalType": "string" + } + ] + } + ], + "outputs": [ + { + "name": "jobId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "agw", + "type": "address", + "internalType": "address" + }, + { + "name": "rulesId", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "pause", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "paused", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "previewIntent", + "inputs": [ + { + "name": "r", + "type": "tuple", + "internalType": "struct IntentRequest", + "components": [ + { + "name": "cardId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "index", + "type": "uint96", + "internalType": "uint96" + }, + { + "name": "job", + "type": "tuple", + "internalType": "struct JobInputs", + "components": [ + { + "name": "principal", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "expiredAt", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "executeBy", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "params", + "type": "int256[]", + "internalType": "int256[]" + } + ] + }, + { + "name": "deadline", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "signerChainId", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "s", + "type": "tuple", + "internalType": "struct Session", + "components": [ + { + "name": "sessionValidator", + "type": "address", + "internalType": "address" + }, + { + "name": "sessionValidatorInitData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "erc7739Policies", + "type": "tuple", + "internalType": "struct ERC7739Data", + "components": [ + { + "name": "allowedERC7739Content", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNames", + "type": "string[]", + "internalType": "string[]" + } + ] + }, + { + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "actions", + "type": "tuple[]", + "internalType": "struct ActionData[]", + "components": [ + { + "name": "actionTargetSelector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "actionTarget", + "type": "address", + "internalType": "address" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "permitERC4337Paymaster", + "type": "bool", + "internalType": "bool" + } + ] + } + ], + "outputs": [ + { + "name": "i", + "type": "tuple", + "internalType": "struct OwnerIntent", + "components": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "wallet", + "type": "address", + "internalType": "address" + }, + { + "name": "executor", + "type": "address", + "internalType": "address" + }, + { + "name": "index", + "type": "uint96", + "internalType": "uint96" + }, + { + "name": "sessionHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "mode", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "execCalldataHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "nonceKey", + "type": "uint192", + "internalType": "uint192" + }, + { + "name": "nonceSeq", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "grantNonce", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "deadline", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "signerChainId", + "type": "uint256", + "internalType": "uint256" + } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "registerAgentCard", + "inputs": [ + { + "name": "c", + "type": "tuple", + "internalType": "struct AgentCard", + "components": [ + { + "name": "provider", + "type": "address", + "internalType": "address" + }, + { + "name": "jobType", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "metadataURI", + "type": "string", + "internalType": "string" + }, + { + "name": "metadataHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "chainNamespace", + "type": "string", + "internalType": "string" + }, + { + "name": "providerFee", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "paymentToken", + "type": "address", + "internalType": "address" + }, + { + "name": "principalMin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "principalMax", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "minDuration", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "maxDuration", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "minExecuteWindow", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "settleWindow", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "active", + "type": "bool", + "internalType": "bool" + } + ] + }, + { + "name": "rules", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "jobSpecTemplate", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "cardId", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "renounceRole", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "callerConfirmation", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "revokeAgentCardVerification", + "inputs": [ + { + "name": "cardId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "revokeRole", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "rulesOfJob", + "inputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "setAgentCardActive", + "inputs": [ + { + "name": "cardId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "active", + "type": "bool", + "internalType": "bool" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setAgentRating", + "inputs": [ + { + "name": "agent", + "type": "address", + "internalType": "address" + }, + { + "name": "rating", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setCEADeployment", + "inputs": [ + { + "name": "chainHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "ceaFactory", + "type": "address", + "internalType": "address" + }, + { + "name": "ceaProxyImpl", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setEvaluator", + "inputs": [ + { + "name": "evaluator_", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setHook", + "inputs": [ + { + "name": "hook_", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "supportsInterface", + "inputs": [ + { + "name": "interfaceId", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "unpause", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "updateAgentCard", + "inputs": [ + { + "name": "cardId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "c", + "type": "tuple", + "internalType": "struct AgentCard", + "components": [ + { + "name": "provider", + "type": "address", + "internalType": "address" + }, + { + "name": "jobType", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "metadataURI", + "type": "string", + "internalType": "string" + }, + { + "name": "metadataHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "chainNamespace", + "type": "string", + "internalType": "string" + }, + { + "name": "providerFee", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "paymentToken", + "type": "address", + "internalType": "address" + }, + { + "name": "principalMin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "principalMax", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "minDuration", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "maxDuration", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "minExecuteWindow", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "settleWindow", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "active", + "type": "bool", + "internalType": "bool" + } + ] + }, + { + "name": "rules", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "jobSpecTemplate", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "verifyAgentCard", + "inputs": [ + { + "name": "cardId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "cardVersion", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "version", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "pure" + }, + { + "type": "event", + "name": "AgentCardDisabled", + "inputs": [ + { + "name": "cardId", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "AgentCardRegistered", + "inputs": [ + { + "name": "cardId", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "provider", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "jobType", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "chainNamespace", + "type": "string", + "indexed": false, + "internalType": "string" + }, + { + "name": "rulesHash", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + }, + { + "name": "jobSpecHash", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + }, + { + "name": "metadataHash", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + }, + { + "name": "providerFee", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "AgentCardStatusChanged", + "inputs": [ + { + "name": "cardId", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "active", + "type": "bool", + "indexed": false, + "internalType": "bool" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "AgentCardUpdated", + "inputs": [ + { + "name": "cardId", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "version", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "rulesHash", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + }, + { + "name": "jobSpecHash", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + }, + { + "name": "metadataHash", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + }, + { + "name": "providerFee", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "AgentCardVerificationRevoked", + "inputs": [ + { + "name": "cardId", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "AgentCardVerified", + "inputs": [ + { + "name": "cardId", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "version", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "AgentRatingSet", + "inputs": [ + { + "name": "agent", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "rating", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "CEADeploymentSet", + "inputs": [ + { + "name": "chainHash", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "ceaFactory", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "ceaProxyImpl", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "EvaluatorUpdated", + "inputs": [ + { + "name": "evaluator", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "HookUpdated", + "inputs": [ + { + "name": "hook", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Initialized", + "inputs": [ + { + "name": "version", + "type": "uint64", + "indexed": false, + "internalType": "uint64" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "JobOpened", + "inputs": [ + { + "name": "cardId", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "agw", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "jobId", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "rulesId", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + }, + { + "name": "principal", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "cardVersion", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Paused", + "inputs": [ + { + "name": "account", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RoleAdminChanged", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "previousAdminRole", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "newAdminRole", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RoleGranted", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RoleRevoked", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Unpaused", + "inputs": [ + { + "name": "account", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "AGWMismatch", + "inputs": [ + { + "name": "expected", + "type": "address", + "internalType": "address" + }, + { + "name": "actual", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "AccessControlBadConfirmation", + "inputs": [] + }, + { + "type": "error", + "name": "AccessControlUnauthorizedAccount", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "neededRole", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "AgentCardAlreadyRegistered", + "inputs": [ + { + "name": "provider", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "AgentCardDisabled", + "inputs": [ + { + "name": "cardId", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "AgentCardIdentityImmutable", + "inputs": [] + }, + { + "type": "error", + "name": "AgentCardInactive", + "inputs": [] + }, + { + "type": "error", + "name": "AgentCardVersionMismatch", + "inputs": [ + { + "name": "provided", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "current", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "CallerIsNotProvider", + "inputs": [] + }, + { + "type": "error", + "name": "ChainNotSupported", + "inputs": [ + { + "name": "chainHash", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "EnforcedPause", + "inputs": [] + }, + { + "type": "error", + "name": "ExecuteByOutOfRange", + "inputs": [] + }, + { + "type": "error", + "name": "ExecutorMismatch", + "inputs": [ + { + "name": "expected", + "type": "address", + "internalType": "address" + }, + { + "name": "actual", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ExpectedPause", + "inputs": [] + }, + { + "type": "error", + "name": "ExpiryOutOfRange", + "inputs": [] + }, + { + "type": "error", + "name": "HookNotWhitelisted", + "inputs": [] + }, + { + "type": "error", + "name": "IntentExecMismatch", + "inputs": [ + { + "name": "actualCalldataHash", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "IntentSessionMismatch", + "inputs": [ + { + "name": "actual", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "IntentWalletMismatch", + "inputs": [ + { + "name": "expected", + "type": "address", + "internalType": "address" + }, + { + "name": "provided", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "InvalidAgentCard", + "inputs": [ + { + "name": "reason", + "type": "string", + "internalType": "string" + } + ] + }, + { + "type": "error", + "name": "InvalidInitialization", + "inputs": [] + }, + { + "type": "error", + "name": "JobMismatch", + "inputs": [] + }, + { + "type": "error", + "name": "NotInitializing", + "inputs": [] + }, + { + "type": "error", + "name": "PrincipalOutOfRange", + "inputs": [] + }, + { + "type": "error", + "name": "ProviderIsEvaluator", + "inputs": [] + }, + { + "type": "error", + "name": "ReentrancyGuardReentrantCall", + "inputs": [] + }, + { + "type": "error", + "name": "UnexpectedJobCount", + "inputs": [ + { + "name": "before", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "afterCount", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "WalletHasActiveJob", + "inputs": [ + { + "name": "agw", + "type": "address", + "internalType": "address" + }, + { + "name": "jobId", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "WalletOwnerMismatch", + "inputs": [ + { + "name": "expected", + "type": "address", + "internalType": "address" + }, + { + "name": "actual", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ZeroAddress", + "inputs": [] + } +] diff --git a/plan/marketplace/contracts/abi/UniversalMarketplaceErrors.json b/plan/marketplace/contracts/abi/UniversalMarketplaceErrors.json new file mode 100644 index 00000000..dd526ec2 --- /dev/null +++ b/plan/marketplace/contracts/abi/UniversalMarketplaceErrors.json @@ -0,0 +1,411 @@ +[ + { + "type": "error", + "name": "AGWMismatch", + "inputs": [ + { + "name": "expected", + "type": "address", + "internalType": "address" + }, + { + "name": "actual", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ActionCount", + "inputs": [] + }, + { + "type": "error", + "name": "ActionsMismatch", + "inputs": [] + }, + { + "type": "error", + "name": "AgentCardAlreadyRegistered", + "inputs": [ + { + "name": "provider", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "AgentCardDisabled", + "inputs": [ + { + "name": "cardId", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "AgentCardIdentityImmutable", + "inputs": [] + }, + { + "type": "error", + "name": "AgentCardInactive", + "inputs": [] + }, + { + "type": "error", + "name": "AgentCardVersionMismatch", + "inputs": [ + { + "name": "provided", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "current", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "AgentMismatch", + "inputs": [] + }, + { + "type": "error", + "name": "AssetCountMismatch", + "inputs": [ + { + "name": "expected", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "actual", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "AssetMismatch", + "inputs": [ + { + "name": "index", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "CallerIsNotProvider", + "inputs": [] + }, + { + "type": "error", + "name": "ChainMismatch", + "inputs": [ + { + "name": "i", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "ChainNotSupported", + "inputs": [ + { + "name": "chainHash", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "EnvelopeVersionMismatch", + "inputs": [ + { + "name": "actual", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "ExecuteByOutOfRange", + "inputs": [] + }, + { + "type": "error", + "name": "ExecutorMismatch", + "inputs": [ + { + "name": "expected", + "type": "address", + "internalType": "address" + }, + { + "name": "actual", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ExpectedCEAMismatch", + "inputs": [ + { + "name": "expected", + "type": "address", + "internalType": "address" + }, + { + "name": "actual", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ExpiryMismatch", + "inputs": [] + }, + { + "type": "error", + "name": "ExpiryOutOfRange", + "inputs": [] + }, + { + "type": "error", + "name": "FillOutOfBounds", + "inputs": [ + { + "name": "read", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "fill", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "GasCapMismatch", + "inputs": [] + }, + { + "type": "error", + "name": "HookNotWhitelisted", + "inputs": [] + }, + { + "type": "error", + "name": "IntentExecMismatch", + "inputs": [ + { + "name": "actualCalldataHash", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "IntentSessionMismatch", + "inputs": [ + { + "name": "actual", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "IntentWalletMismatch", + "inputs": [ + { + "name": "expected", + "type": "address", + "internalType": "address" + }, + { + "name": "provided", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "InvalidAgentCard", + "inputs": [ + { + "name": "reason", + "type": "string", + "internalType": "string" + } + ] + }, + { + "type": "error", + "name": "JobMismatch", + "inputs": [] + }, + { + "type": "error", + "name": "ParamCountMismatch", + "inputs": [ + { + "name": "expected", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "actual", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "ParamOutOfRange", + "inputs": [ + { + "name": "index", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "value", + "type": "int256", + "internalType": "int256" + } + ] + }, + { + "type": "error", + "name": "PinMismatch", + "inputs": [ + { + "name": "call", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "pin", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "PolicyShape", + "inputs": [ + { + "name": "i", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "PrincipalCapMismatch", + "inputs": [] + }, + { + "type": "error", + "name": "PrincipalOutOfRange", + "inputs": [] + }, + { + "type": "error", + "name": "ProviderIsEvaluator", + "inputs": [] + }, + { + "type": "error", + "name": "TargetOverflow", + "inputs": [ + { + "name": "check", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "UnexpectedJobCount", + "inputs": [ + { + "name": "before", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "afterCount", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "WalletHasActiveJob", + "inputs": [ + { + "name": "agw", + "type": "address", + "internalType": "address" + }, + { + "name": "jobId", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "WalletOwnerMismatch", + "inputs": [ + { + "name": "expected", + "type": "address", + "internalType": "address" + }, + { + "name": "actual", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ZeroAddress", + "inputs": [] + } +] diff --git a/plan/marketplace/contracts/abi/UniversalMarketplaceRules.json b/plan/marketplace/contracts/abi/UniversalMarketplaceRules.json new file mode 100644 index 00000000..714dfff3 --- /dev/null +++ b/plan/marketplace/contracts/abi/UniversalMarketplaceRules.json @@ -0,0 +1,318 @@ +[ + { + "type": "function", + "name": "checkRulesMatchCard", + "inputs": [ + { + "name": "cardRules", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "session", + "type": "tuple", + "internalType": "struct Session", + "components": [ + { + "name": "sessionValidator", + "type": "address", + "internalType": "address" + }, + { + "name": "sessionValidatorInitData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "userOpPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "erc7739Policies", + "type": "tuple", + "internalType": "struct ERC7739Data", + "components": [ + { + "name": "allowedERC7739Content", + "type": "tuple[]", + "internalType": "struct ERC7739Context[]", + "components": [ + { + "name": "appDomainSeparator", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "contentNames", + "type": "string[]", + "internalType": "string[]" + } + ] + }, + { + "name": "erc1271Policies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "actions", + "type": "tuple[]", + "internalType": "struct ActionData[]", + "components": [ + { + "name": "actionTargetSelector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "actionTarget", + "type": "address", + "internalType": "address" + }, + { + "name": "actionPolicies", + "type": "tuple[]", + "internalType": "struct PolicyData[]", + "components": [ + { + "name": "policy", + "type": "address", + "internalType": "address" + }, + { + "name": "initData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "permitERC4337Paymaster", + "type": "bool", + "internalType": "bool" + } + ] + }, + { + "name": "ctx", + "type": "tuple", + "internalType": "struct SessionContext", + "components": [ + { + "name": "agent", + "type": "address", + "internalType": "address" + }, + { + "name": "chainHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "principal", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "expiredAt", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "expectedCEA", + "type": "address", + "internalType": "address" + } + ] + } + ], + "outputs": [], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "validateAgentCardRules", + "inputs": [ + { + "name": "rules", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "tokens", + "type": "address[]", + "internalType": "address[]" + } + ], + "stateMutability": "pure" + }, + { + "type": "error", + "name": "ActionCount", + "inputs": [] + }, + { + "type": "error", + "name": "ActionsMismatch", + "inputs": [] + }, + { + "type": "error", + "name": "AgentMismatch", + "inputs": [] + }, + { + "type": "error", + "name": "AssetCountMismatch", + "inputs": [ + { + "name": "expected", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "actual", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "AssetMismatch", + "inputs": [ + { + "name": "index", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "ChainMismatch", + "inputs": [ + { + "name": "i", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "EnvelopeVersionMismatch", + "inputs": [ + { + "name": "actual", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "ExpectedCEAMismatch", + "inputs": [ + { + "name": "expected", + "type": "address", + "internalType": "address" + }, + { + "name": "actual", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ExpiryMismatch", + "inputs": [] + }, + { + "type": "error", + "name": "GasCapMismatch", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidAgentCard", + "inputs": [ + { + "name": "reason", + "type": "string", + "internalType": "string" + } + ] + }, + { + "type": "error", + "name": "PinMismatch", + "inputs": [ + { + "name": "call", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "pin", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "PolicyShape", + "inputs": [ + { + "name": "i", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "PrincipalCapMismatch", + "inputs": [] + } +] diff --git a/plan/marketplace/contracts/docs/addresses/push_donut_universal_marketplace.md b/plan/marketplace/contracts/docs/addresses/push_donut_universal_marketplace.md new file mode 100644 index 00000000..e0702612 --- /dev/null +++ b/plan/marketplace/contracts/docs/addresses/push_donut_universal_marketplace.md @@ -0,0 +1,33 @@ +# Push Donut (Chain ID: 42101): UniversalMarketplace stack + +Deployed 2026-10-20 with `scripts/agentic-commerce-8183/DeployUniversalMarketplace.s.sol` (last tx in block 24443653). +Self-contained stack: its own 8183 kernel on pUSDC, bound to AGW v6. Fees are zero. + +## Contracts + +| Contract | Proxy | Implementation | ProxyAdmin | +|---|---|---|---| +| AgenticCommerce (kernel) | `0x977cf1AC973E9eC4332791d531507575006157Ed` | `0x1d631E9d0E0A7a7423743c3076054C784Af8FA40` | `0x5F5Ef9dBbC31d59a28626d1F913A35B5b6eA0Cb9` | +| RulesBindingHook | `0xDe7A94e510b6C571DE7880d441349689F73A32b3` | `0x58bd6951b653B5028Aa77B4904E83Df668Bcef7E` | `0xBa96c7FB588aC17aba00c7aa920E282c088B1746` | +| UniversalMarketplace | `0x9071ebE01B75123A91e88eB6ec4BF163F3fE9BF4` | `0xd683545f84698dF4341b0031C892C53384FF30be` | `0xb7D9315813fE87A13833871ce673073dd4B8c8af` | +| UniversalMarketplaceRules (not a proxy) | `0x5b98A8E0df5b918DF76cD2BE84bA7995B39dfd44` | | | +| JobSpecBuilder (linked library) | `0x2de1e3F053b0bBa0cE0C6953144534a0b055f59e` | | | + +## Roles and settings + +| Item | Value | +|---|---| +| Kernel + marketplace admin (`DEFAULT_ADMIN_ROLE`, `ADMIN_ROLE`), owner of every ProxyAdmin | `0x1afC81396f1bb36F91f74506284952b81e4bd47c` | +| Marketplace-wide evaluator (EOA, completes or rejects by hand) | `0x1afC81396f1bb36F91f74506284952b81e4bd47c` | +| Kernel payment token (pUSDC, `USDC.eth`, 6 decimals) | `0x7A58048036206bB898008b5bBDA85697DB1e5d66` | +| Kernel platform treasury | `0x2348286F118810521497ADBbF2615D1328aa1630` | +| AGW v6 factory / session engine | `0xFBBEB6a365178fAaA81A9789a5f64b300c37e5bc` / `0xf63DC0628fe1B25049FE3E3a3585Ef051CB98c1d` | + +## Supported card chains (`setCEADeployment`) + +| Chain | Namespace | CEAFactory (proxy) | CEA proxy implementation | +|---|---|---|---| +| Ethereum Sepolia | `eip155:11155111` | `0x8ED594A83301FEc545fC6c19fc12cF7111777029` | `0x0a4F7be62B56830070266be81114edB93e68DA09` | +| Base Sepolia | `eip155:84532` | `0x0A75ca7736b488Eb41675ADc3b3156BACF659F55` | `0x6c9Cfef12155bEE91ecD6d0C8f516cABA2890656` | +| Arbitrum Sepolia | `eip155:421614` | `0x88DC189275078Cf509E4Cc773F089c8ad07b7EA2` | `0x512d1B8C185a0Fd533a69f8973A3DD6513233009` | +| BSC Testnet | `eip155:97` | `0x3f1B16e0B072d472951C4563d29d3da6a3EE3Ce8` | `0x0ff5d8b7d9Ac3ee2Ad420e9b70Ed6Dc465f593e9` | diff --git a/plan/marketplace/contracts/docs/universalmarketplace/README.md b/plan/marketplace/contracts/docs/universalmarketplace/README.md new file mode 100644 index 00000000..c3c5b26f --- /dev/null +++ b/plan/marketplace/contracts/docs/universalmarketplace/README.md @@ -0,0 +1,847 @@ +# Universal Marketplace + +How the Universal Marketplace contracts work, end to end. Written for a reviewer: every guarantee is tied to the +code that enforces it, and every assumption the code makes about something else is stated. + +| Doc | Contents | +|---|---| +| **This file** | What the marketplace is, its parts, the agent card lifecycle, `openJob` step by step, the rules check, the criteria, admin powers, upgradeability, trust model, limitations, tests, reviewer checklist | +| [`reference.md`](./reference.md) | Every function, event, error, registration reason, storage slot and constant, one by one | +| [`criteria.md`](./criteria.md) | The `jobSpecTemplate` format, how a job's `JobSpec` is built from it, and two worked examples | +| [`../addresses/push_donut_universal_marketplace.md`](../addresses/push_donut_universal_marketplace.md) | The live Push Donut deployment: every proxy, implementation, ProxyAdmin, role and supported chain | + +Code as of branch `sdk-iteration-v1`, commit `7cd2d7b` (marketplace v2, PRD 12). Deployed on Push Donut on 2026-10-20 +(§12.5). + +--- + +## Contract locations + +| Contract | Path | Kind | +|---|---|---| +| **UniversalMarketplace** | [`src/agentic-commerce-8183/UniversalMarketplace.sol`](../../src/agentic-commerce-8183/UniversalMarketplace.sol) | Upgradeable (TransparentUpgradeableProxy), stateful. The only contract users and providers call. `version()` = `"2.0.0"`. | +| **UniversalMarketplaceRules** | [`src/agentic-commerce-8183/UniversalMarketplaceRules.sol`](../../src/agentic-commerce-8183/UniversalMarketplaceRules.sol) | Stateless, `pure`, not upgradeable. The rules side of a card: registration guards and rules = card at `openJob`. | +| **JobSpecBuilder** | [`src/agentic-commerce-8183/libraries/JobSpecBuilder.sol`](../../src/agentic-commerce-8183/libraries/JobSpecBuilder.sol) | External library, linked into the marketplace and called by `DELEGATECALL`. Builds each job's criteria. | +| Types | [`src/agentic-commerce-8183/libraries/Types.sol`](../../src/agentic-commerce-8183/libraries/Types.sol) | Every struct and enum of the package (file-level), and the markers `MARKER_WALLET` / `MARKER_PRINCIPAL`. | +| Errors | [`src/agentic-commerce-8183/libraries/Errors.sol`](../../src/agentic-commerce-8183/libraries/Errors.sol) | `UniversalMarketplaceErrors` (40 errors), `RulesBindingHookErrors`, `ERC8183HookErrors`. | +| JobSpecTypes | [`src/agentic-commerce-8183/libraries/JobSpecTypes.sol`](../../src/agentic-commerce-8183/libraries/JobSpecTypes.sol) | The built criteria (`JobSpec`): the wire format shared with the future UniversalHook and UniversalEvaluator. | +| IUniversalMarketplace | [`src/agentic-commerce-8183/interfaces/IUniversalMarketplace.sol`](../../src/agentic-commerce-8183/interfaces/IUniversalMarketplace.sol) | The marketplace's events and functions (banners UM_1–UM_5). | +| IUniversalMarketplaceRules | [`src/agentic-commerce-8183/interfaces/IUniversalMarketplaceRules.sol`](../../src/agentic-commerce-8183/interfaces/IUniversalMarketplaceRules.sol) | The rules helper's two functions (banner UMR_1). | +| AGW interfaces | [`interfaces/external/IAGW.sol`](../../src/agentic-commerce-8183/interfaces/external/IAGW.sol), [`IAGWFactory.sol`](../../src/agentic-commerce-8183/interfaces/external/IAGWFactory.sol), [`ISmartSession.sol`](../../src/agentic-commerce-8183/interfaces/external/ISmartSession.sol) | The SmartSession `Session` mirror and the AGW / factory / engine functions the package calls. AGW types are imported, not copied (§12.1). | + +Contracts the marketplace works with, but which are **not** part of it: + +| Contract | Where | Role | +|---|---|---| +| **AgenticCommerce** (the "kernel") | [`src/agentic-commerce-8183/AgenticCommerce.sol`](../../src/agentic-commerce-8183/AgenticCommerce.sol) | The ERC-8183 job kernel: jobs, budgets, escrow, payout. The marketplace only creates jobs on it (through the user's wallet). On Donut the marketplace uses **its own instance**, deployed with it on pUSDC (`0x977cf1AC973E9eC4332791d531507575006157Ed`), not the `marketplace_demo` kernel (§12.5). | +| **RulesBindingHook** | [`src/agentic-commerce-8183/hooks/RulesBindingHook.sol`](../../src/agentic-commerce-8183/hooks/RulesBindingHook.sol) | The interim 8183 hook every marketplace job is created with. At `fund` it binds the job to the wallet's live rules set and allows one live job per wallet. | +| **AGW + AGWFactory** | `push-agentic-wallets` repo (submodule [`lib/push-agentic-wallets`](../../lib/push-agentic-wallets)) | The user's agentic wallet (an ERC-7579 account with SmartSession) and its factory. Verifies the owner's signature. AGW v6 is deployed on Donut. | +| **UniversalRulesPolicy (URP)** | `push-agentic-wallets` repo | The SmartSession policy that enforces the agent's rules when the agent sends outbound calls through the gateway. | +| **CEAFactory** | destination chain (`src/cea/CEAFactory.sol` here) | Deploys each user's Chain Executor Account (CEA) on the destination chain. The marketplace only predicts CEA addresses. | +| UniversalHook, UniversalEvaluator (V2) | not compatible yet (§12.5) | The intended long-term hook and evaluator. Until they ship, jobs use RulesBindingHook and a Push-controlled evaluator address. | + +--- + +## 1 · What the marketplace is + +The Universal Marketplace is a registry of **agent cards** plus one entry point, **`openJob`**. + +- **An agent card** is a standing offer from one provider (an AI agent's address). Each provider has at most one + card. It covers one job type on one EVM execution chain. It says who the agent is, what it does, what it needs + permission to do there (the **rules**), and how "done" is judged (the **`jobSpecTemplate`**, the criteria + template). +- **`openJob`** is one relayed call. On a single signature from the user, it: + 1. deploys the user's agentic wallet (AGW) if needed; + 2. grants the AGW the card's rules, with the card's markers filled for this job, so the agent can act from it; + 3. creates an ERC-8183 job on the kernel, with the AGW as client, the card's provider as provider, the + marketplace's configured evaluator and hook, and **criteria built on-chain from the card**. + +What the marketplace deliberately does **not** do: + +| Not done | Where it happens instead | +|---|---| +| Move any funds | The user funds the AGW in a separate transaction. The provider prices the job with `setBudget`; the AGW funds it with `fund`. Both are kernel calls. | +| Grant token approvals as the owner | Approvals are the agent's: an `approve` is an allowed call the agent makes, with its spender and amount pinned by the card (D1, §6.3). | +| Judge whether the criteria make sense | Nobody, on-chain. The admin's **verified tag** is the review. | +| Evaluate the job | The job's evaluator (the UniversalEvaluator, once shipped). | +| Enforce the agent's rules at execution | The AGW's SmartSession engine and URP. | + +The marketplace never holds tokens or native PC. Tests `test_MS02_movesNoFunds` and the invariants +`MI02_marketplaceHoldsNothing` and `MI05_userBalanceNeverMovedByOpenJob` check this. + +--- + +## 2 · Glossary + +| Term | Meaning | +|---|---| +| **Provider / agent** | One address. It registers the card, is the 8183 job's `provider` (and fee recipient), and is the agent the rules authorise (`sessionValidatorInitData == abi.encode(provider)`). One card per provider (`agentCardOf`). | +| **User / owner** | The person opening a job. Signs one `OwnerIntent`; owns the AGW. | +| **AGW** | Agentic Wallet: the user's smart account, deployed by the AGW factory at an address derived from `(owner, index)`. The job's client. | +| **CEA** | Chain Executor Account: the AGW's account on the destination chain, at an address derived from the AGW (`computeCEA`). It is where the agent's outbound calls execute and where the criteria read balances. | +| **Agent card** | `AgentCard` (the listing) plus two blobs: `rules` and `jobSpecTemplate`. | +| **Rules** | On the card: `abi.encode(AgentCardRules)`, the assets with caps, the gas cap and the allowed calls with pins. At `openJob`: the SmartSession `Session` granted to the agent, whose one policy carries the AGW v6 envelope `abi.encode(uint16 ENVELOPE_VERSION, string chain, bytes body)` with `UniversalTerms` as body. `rulesId` is the engine's `permissionId`. | +| **Pin** | An AGW v6 `ArgPin{offset, op, value}` on an allowed call: the calldata word at `offset` must equal (`EQ`) or not exceed (`MAX`) `value`. | +| **Markers** | Two published `bytes32` constants a card may hold where a per-job value goes: `MARKER_WALLET` (the user's CEA on the card's chain, EQ pins only) and `MARKER_PRINCIPAL` (this job's principal, in pins and in the principal asset's caps). The signed session holds the filled values, never a marker (D2, D3). | +| **OwnerIntent** | The single owner-signed message (AGW type, imported). One signature authorises the wallet deploy, the rules grant and the `createJob` execution. | +| **`jobSpecTemplate`** | `abi.encode(JobSpecTemplate)`: the V2 `JobSpec` with holes. Stored on the card. Also called the criteria template. | +| **JobSpec** | The built criteria for one job: reads, checks, the `logic` tree, `allowedMutability`, `origin`, times. `abi.encode(JobSpec)` is the 8183 job's `description`. | +| **`logic`** | The job's pass logic: `Logic` steps, each combining checks and child steps with `ALL`, `ANY` or `AT_LEAST k`. Copied verbatim; its semantics are evaluator-owned. | +| **Card version** | 1 at registration, +1 per update. Bound into every job's criteria, so an intent signed against one version can't open a job on another. Recorded per job (`cardVersionOfJob`). | +| **Verified tag** | An admin label: "this card, at this version, was reviewed". A tag, not a gate. | +| **chainHash** | `keccak256` of a CAIP-2 string such as `"eip155:11155111"`. The key for chain configuration. | +| **`PUSH_CHAIN_HASH`** | `keccak256("eip155:" ‖ block.chainid)`: Push Chain itself. No card may name it. | + +--- + +## 3 · The parts and how they fit + +```mermaid +flowchart LR + Provider -- registerAgentCard / updateAgentCard --> MKT[UniversalMarketplace] + Relayer -- openJob --> MKT + MKT -- validateAgentCardRules / checkRulesMatchCard --> RULES[UniversalMarketplaceRules] + MKT -- DELEGATECALL build --> JSB[JobSpecBuilder] + JSB -. computeCEA .-> MKT + MKT -- predictWallet / deployWalletWithSig / ownerOf --> FACT[AGWFactory] + MKT -- grantRulesWithSig / executeWithSig --> AGW[User's AGW] + AGW -- createJob --> KERNEL[AgenticCommerce kernel] + MKT -- jobCounter / getJob / whitelistedHooks / paymentToken --> KERNEL + KERNEL -- beforeAction / afterAction --> HOOK[RulesBindingHook] +``` + +- **The marketplace** holds the cards and runs `openJob`. It is the `executor` named in the user's intent: the + factory and the wallet accept that intent only from it. +- **The rules helper** is pure logic, split out for the EIP-170 size limit. It validates a card's rules at + registration (R1–R17) and checks the user's session against the card at `openJob` (C1–C14). +- **JobSpecBuilder** is an external library. It turns the card's `jobSpecTemplate` plus the job's inputs into the + job's `JobSpec`. It runs in the marketplace's context, so it reads CEAs from the marketplace's own `computeCEA`. +- **The AGW** does the work that needs the owner's authority: it verifies the owner's signature, grants the rules, + and calls `createJob` itself, so the kernel records the AGW as the client. + +--- + +## 4 · The agent card + +### 4.1 What a card holds + +A card is three things stored on-chain together: + +1. **`AgentCard`**, the listing. Who: `provider`. What: `jobType`, `metadataURI` and `metadataHash` (off-chain + JSON with the name, summary, ABIs, criteria in words and param units). Where: `chainNamespace`, a full CAIP-2 + string `"eip155:"`, immutable after registration. Commercials: `providerFee` (reference price, in + `paymentToken`) and `paymentToken`. Windows: `principalMin` / `principalMax` (in the principal asset's units), + `minDuration` / `maxDuration`, `minExecuteWindow`, `settleWindow`. And an `active` switch. +2. **Rules**, `abi.encode(AgentCardRules)`: `assets` (1–8 AGW `AssetCap{token, maxPerCall, maxTotal}`, each a + PRC20 of the card's chain), `principalAsset` (an index into `assets`), `maxGasPerCall` (PC wei per outbound), + and `allowedCalls` (1–32 AGW `AllowedCall`s, with pins). See §6. +3. **`jobSpecTemplate`**, `abi.encode(JobSpecTemplate)`: see [`criteria.md`](./criteria.md). + +`getAgentCard(cardId)` returns all three, the version and both tags in one call (`AgentCardView`). + +**One card per provider.** `registerAgentCard` reverts `AgentCardAlreadyRegistered(provider)` if +`agentCardOf[msg.sender] != 0`. Disabling a card does not free the provider: a disabled provider cannot register +again (`test_MR11_onePerProvider`, invariant `MI06`). + +**`paymentToken`.** Until the kernel supports a per-job payment token (K-12, out of scope), every job is paid in +the kernel's token, so a card must name exactly `KERNEL.paymentToken()` (`InvalidAgentCard("payment token")`, +`test_MR12_paymentTokenGuard`). `providerFee` is a reference price the client funds against; the marketplace does +not enforce it (§5). + +### 4.2 What registration checks + +`registerAgentCard` checks `agentCardOf` first; then it and `updateAgentCard` run `_validateCard`, in this order. +The first failure reverts. + +| # | Check | Error | +|---|---|---| +| 1 | `jobType != 0` | `InvalidAgentCard("job type zero")` | +| 2 | `metadataURI` not empty | `InvalidAgentCard("metadata uri empty")` | +| 3 | `metadataHash != 0` | `InvalidAgentCard("metadata hash zero")` | +| 4 | `chainNamespace` starts with `"eip155:"` and is longer than 7 bytes | `InvalidAgentCard("chain namespace")` | +| 5 | the chain is not Push, and has a CEA deployment (`setCEADeployment`) | `ChainNotSupported(chainHash)` | +| 6 | `paymentToken == KERNEL.paymentToken()` | `InvalidAgentCard("payment token")` | +| 7 | the caller is not the marketplace's evaluator | `InvalidAgentCard("provider is evaluator")` | +| 8 | `principalMax != 0` and `principalMin ≤ principalMax` | `InvalidAgentCard("principal range")` | +| 9 | `1 hour ≤ minDuration ≤ maxDuration` | `InvalidAgentCard("duration range")` | +| 10 | `settleWindow != 0` | `InvalidAgentCard("settle window")` | +| 11 | `minExecuteWindow + settleWindow ≤ maxDuration` | `InvalidAgentCard("execute window")` | +| 12 | the rules pass `RULES.validateAgentCardRules` (R1–R17, §6.2) | `InvalidAgentCard(...)` from the helper | +| 13 | **every** asset's `SOURCE_CHAIN_NAMESPACE()` is a well-formed string equal to the card's chain | `InvalidAgentCard("asset")` / `InvalidAgentCard("asset chain")` | + +**The `jobSpecTemplate` is stored as given; it is not checked.** Whether the evaluator can run it is the +provider's responsibility. A malformed template fails only when a job is built from it (§7.3). + +Check 13 uses a raw `staticcall` plus an ABI-shape check, not `try/catch`: a `try` clause cannot catch the +decoding of its own return data, so a non-string answer would otherwise revert with an opaque error. A codeless +asset answers empty and fails the length check (`test_MR06_assetTeeth`, `test_MR13_everyAssetOnChain`). + +### 4.3 Lifecycle + +```mermaid +stateDiagram-v2 + [*] --> Active: registerAgentCard (version 1, unverified) + Active --> Inactive: setAgentCardActive(false) by provider + Inactive --> Active: setAgentCardActive(true) by provider + Active --> Active: updateAgentCard (version +1, tag cleared) + Inactive --> Inactive: updateAgentCard (version +1, tag cleared) + Active --> Disabled: disableAgentCard + Inactive --> Disabled: disableAgentCard + Disabled --> [*] +``` + +| Action | Who | Effect | +|---|---|---| +| `registerAgentCard` | any address without a card (becomes the provider) | Stores the card, version 1, active, unverified; `agentCardOf[provider] = cardId`. The contract writes `provider = msg.sender` and `active = true`, ignoring the caller's values. | +| `updateAgentCard` | the provider | Replaces every field except `provider`, `chainNamespace` and `active` (so `jobType`, `metadataURI`, `metadataHash`, `providerFee`, `paymentToken`, principal range, durations and windows), and both blobs. Version +1, verified tag cleared. **The chain cannot change** (`AgentCardIdentityImmutable`). Refused for a disabled card (`AgentCardDisabled`). | +| `setAgentCardActive` | the provider | Switches the card on or off. A disabled card cannot be switched back on. | +| `verifyAgentCard(cardId, cardVersion)` | admin | Sets the verified tag. `cardVersion` must be the current version (`AgentCardVersionMismatch`), so a provider who updates after review makes it revert. Refused for a disabled card; allowed for an inactive one. | +| `revokeAgentCardVerification` | admin | Clears the tag. Idempotent: emits only if there was a tag. | +| `disableAgentCard` | admin | Permanent kill switch: disabled, inactive, tag cleared. The provider cannot undo it, and keeps its `agentCardOf` entry. | + +**Updates and signed intents.** The card version is hashed into every job's `origin`, which is inside the +`createJob` calldata the owner signs. After an update, an intent signed against the old version fails at +`AgentCardVersionMismatch` (stale `p.cardVersion`) or at `IntentExecMismatch` (current version, old intent) +(`test_ML11_update_invalidatesOldIntents`). A provider therefore cannot swap the card under a user's signature. +Jobs already opened are untouched (`test_ML12_update_leavesOpenedJobsUntouched`). + +**The verified tag is a tag, not a gate.** `openJob` treats verified and unverified cards alike. The SDK shows it. + +--- + +## 5 · End-to-end flow + +```mermaid +sequenceDiagram + autonumber + actor P as Provider (agent) + actor U as User (owner) + participant SDK + participant M as UniversalMarketplace + participant F as AGWFactory + participant W as User's AGW + participant K as Kernel (AgenticCommerce) + participant H as RulesBindingHook + + P->>M: registerAgentCard(card, rules, jobSpecTemplate) + U->>SDK: pick a card, principal, times, params + SDK->>SDK: build the session: card rules, markers filled (Appendix E of PRD 12) + SDK->>M: previewIntent(request, session) + M-->>SDK: OwnerIntent (calldata hash binds the built criteria) + U->>SDK: sign the OwnerIntent once + SDK->>M: openJob(params) via a relayer + M->>F: deployWalletWithSig(intent, sig, label) [if new] + M->>W: grantRulesWithSig(session, intent, sig) + M->>W: executeWithSig(createJob calldata, intent, sig) + W->>K: createJob(provider, evaluator, expiredAt, JobSpec, hook) + Note over M,K: job is Open, budget 0. Nothing has moved. + U->>W: funding tx (SDK-built): principal, PC for gas, fee + P->>K: setBudget(jobId, card.providerFee) + W->>K: fund(jobId, card.providerFee, abi.encode(rulesId)) + K->>H: beforeAction(fund): bind job to the live rules set + P->>W: act within the rules (URP-enforced outbound calls, approvals included) + P->>K: submit; evaluator completes or rejects +``` + +1. **The provider registers a card** (§4). +2. **The user opens a job.** The SDK builds the session from the card's rules (filling the markers), calls + `previewIntent`, the user signs the returned `OwnerIntent` once, and a relayer calls `openJob`. The AGW is + deployed (if new), granted the rules, and creates the job in **Open** with budget 0. +3. **The user funds** the AGW, in one transaction built by the SDK: the principal (in the principal asset), PC + for gas and the fee. +4. **The provider prices** the job: `kernel.setBudget(jobId, card.providerFee)`. +5. **The AGW funds** the job: `kernel.fund(jobId, card.providerFee, abi.encode(rulesId))`. The kernel calls the + hook, which checks the AGW is a factory wallet, the rules set is live, and the AGW has no other live job. A + provider who prices above the card's fee cannot be funded, because the owner's `expectedBudget` is the card fee + (`BudgetMismatch`; `test_MS17_8183Continuation_feeEnforcedAtFund`). +6. **The agent executes** within the rules (including any pinned `approve`), submits, and the evaluator completes + or rejects (kernel). + +Steps 3–6 are outside the marketplace. They are shown because the marketplace's design depends on them. The fork +test `test_fork_openJob_realAGWv6` runs steps 2, 4 and 5 against the real AGW v6 on Donut. + +--- + +## 6 · The rules: rules = card + +The owner signs a SmartSession `Session` the SDK builds, which they cannot read. The marketplace proves it is +exactly the card's rules, with the card's markers filled for this job, for the card's agent, bound to this job. +Both checks live in the rules helper. + +### 6.1 The format (AGW v6) + +The card stores `AgentCardRules`: + +```solidity +struct AgentCardRules { + AssetCap[] assets; // 1..MAX_ASSETS (8) PRC20s on Push, each SOURCE_CHAIN_NAMESPACE == card chain + uint8 principalAsset; // index into assets + uint256 maxGasPerCall; // PC wei per outbound, copied to the session exactly + AllowedCall[] allowedCalls; // 1..32; pins may hold MARKER_WALLET / MARKER_PRINCIPAL +} +``` + +`AssetCap`, `AllowedCall`, `ArgPin` and `PinOp` are the AGW v6 types, imported from `@push-agw/libraries/Types.sol`. +The session's one action carries one URP policy whose `initData` is the v6 **envelope** +`abi.encode(uint16 version, string chainNamespace, bytes body)`, with `version == ENVELOPE_VERSION` (1) and +`body = abi.encode(UniversalTerms{validUntil, expectedCEA, assets, maxGasPerCall, allowedCalls})`. + +**Multi-asset.** Each asset has its own `maxPerCall` and lifetime `maxTotal`. The principal asset's caps are set +per job (D3); every other asset's caps are copied from the card. A second asset with caps `{0, 0}` may route a +request but never moves (the two-asset fixture `_rulesTwoAssets`). + +**Markers** (D2, D3). Where a card needs a per-job value it holds a marker, and the signed session holds the +value the marketplace fills in: + +| Card holds | Where | The signed session must hold | +|---|---|---| +| `MARKER_PRINCIPAL` | `assets[principalAsset].maxTotal` (as `uint256`) | `principal` | +| `MARKER_PRINCIPAL` | `assets[principalAsset].maxPerCall` | `principal` | +| a number `n` | `assets[principalAsset].maxPerCall` | `n` (a "tranche" card, `test_MS20_openJob_trancheCard`) | +| a number | any field of any other asset | the same number | +| `MARKER_WALLET` | a pin's `value` (op EQ) | `bytes32(uint256(uint160(computeCEA(agw, cardChainHash))))` | +| `MARKER_PRINCIPAL` | a pin's `value` (op EQ or MAX) | `bytes32(principal)` | +| any other `bytes32` | a pin's `value` | the same value | + +`MARKER_WALLET = keccak256("push.marketplace.marker.WALLET")` and +`MARKER_PRINCIPAL = keccak256("push.marketplace.marker.PRINCIPAL")`. Both have non-zero high 96 bits, so neither +is a clean address word (`test_naming_markers`). + +**Approvals are allowed calls** (D1). There is no owner-approval list. The agent may call ERC-20 `approve` only +with the spender pinned to a fixed address and the amount capped by a `MAX` pin (a literal or +`MARKER_PRINCIPAL`). Several entries may share one `(target, selector)` with different pins ("approve to Aave or +to Uniswap"), but only if every one of them is pinned. + +### 6.2 At registration: `validateAgentCardRules` + +Decodes `AgentCardRules` (malformed bytes revert in `abi.decode` without data), then runs R1–R17 in this order; +the first failure reverts `InvalidAgentCard(reason)`. Each rule is checked over every item before the next rule. + +| # | Check | Reason | +|---|---|---| +| R1 | `1 <= assets.length <= MAX_ASSETS` | `"asset count"` | +| R2 | `principalAsset < assets.length` | `"principal asset"` | +| R3 | every asset's `token != address(0)` | `"asset zero"` | +| R4 | no two assets share a token | `"duplicate asset"` | +| R5 | `assets[principalAsset].maxTotal == uint256(MARKER_PRINCIPAL)` | `"principal total not marker"` | +| R6 | `assets[principalAsset].maxPerCall != 0` | `"principal per-call zero"` | +| R7 | no other asset holds `MARKER_PRINCIPAL` in either cap | `"marker off principal asset"` | +| R8 | `1 <= allowedCalls.length <= 32` | `"allow-list size"` | +| R9 | `pins.length <= MAX_PINS` (8) per call, and `<= MAX_ALLOWED_CALL_PINS` (32) in total | `"too many pins"` | +| R10 | a pin holding `MARKER_WALLET` has `op == EQ` | `"wallet marker op"` | +| R11 | no two calls are byte-identical | `"duplicate call"` | +| R12 | two calls with the same `(target, selector)` are both pinned | `"unpinned duplicate"` | +| R13 | no `increaseAllowance` | `"increaseAllowance"` | +| R14 | `approve` has a pin `{4, EQ, v}`, `v` a non-zero clean address word (so never a marker) | `"approve spender not pinned"` | +| R15 | `approve` has a pin `{36, MAX, *}` | `"approve amount not capped"` | +| R16 | `transfer` binds its recipient to the user's account: beneficiary at 4, or a pin `{4, EQ, MARKER_WALLET}` | `"erc20 transfer recipient"` | +| R17 | `transferFrom` likewise at offset 36 | `"erc20 transferFrom recipient"` | + +It returns every asset's token, which the marketplace then checks against the card's chain (§4.2, check 13). The +full table is in [`reference.md`](./reference.md#universalmarketplacerules). + +### 6.3 At `openJob`: `checkRulesMatchCard` + +In order; the first mismatch reverts. + +| # | The session must… | Error | +|---|---|---| +| C1 | name the card's provider as its agent: `sessionValidatorInitData == abi.encode(provider)` | `AgentMismatch()` | +| C2 | have exactly one action | `ActionCount()` | +| C3 | with exactly one policy | `PolicyShape(0)` | +| C4 | whose `initData` starts with the word `ENVELOPE_VERSION`, read **before** any decode (0 if under 32 bytes) | `EnvelopeVersionMismatch(actual)` | +| C5 | and names the card's chain | `ChainMismatch(0)` | +| C6 | carry as many assets as the card | `AssetCountMismatch(expected, actual)` | +| C7 | with the card's tokens, in order | `AssetMismatch(i)` | +| C8 | with the principal asset's `maxTotal == principal`, and `maxPerCall == principal` (marker) or the card's number | `PrincipalCapMismatch()` | +| C9 | and every other asset's caps exactly the card's | `AssetMismatch(i)` | +| C10 | and the card's `maxGasPerCall` | `GasCapMismatch()` | +| C11 | and the card's allowed calls: same count, same target, selector, beneficiary fields, `maxValue`, pin count, and each pin's offset and op | `ActionsMismatch()` | +| C12 | with each pin's value equal to the card's, markers filled (table in §6.1) | `PinMismatch(call, pin)` | +| C13 | expiring with the job: `validUntil == expiredAt` | `ExpiryMismatch()` | +| C14 | paying only the AGW's own CEA on that chain: `expectedCEA == computeCEA(agw, chainHash)` | `ExpectedCEAMismatch(expected, actual)` | + +C4 mirrors URP: a pre-v6 two-field envelope `(string, bytes)` has first word 64 (the string's offset), so it is +named `EnvelopeVersionMismatch(64)` instead of panicking the decoder (`test_MS22_envelopeVersion_named`). C11 and +C12 share one loop, per call and then per pin. + +The session never carries a marker: C8 and C12 compare against the filled value, so a session holding the raw +marker fails (`test_MT09_match_pins`). D3 makes the principal caps exact: a per-call cap below the principal is +refused (`test_MB04_perCallMustEqualPrincipal`); the invariant `MI07` checks every granted `maxTotal` equals the +job's principal. + +What C12 and C14 protect: the `MARKER_WALLET` pins and URP's beneficiary pins bind funds the agent moves to the +user's own CEA. The marketplace derives the CEA itself (§9); the SDK derives it independently from the +destination `CEAFactory`. A disagreement fails closed before anything happens. + +Fields the helper does not compare, and why that is safe, are in §13.2. + +--- + +## 7 · The criteria: card ⊆ job + +### 7.1 Why they are built on-chain + +If the SDK or relayer supplied the job's criteria, nothing would guarantee they are the card's: a relayer could +swap in easier ones. Instead, `openJob` builds the criteria from the card's **stored** `jobSpecTemplate` and the +job's inputs. The result goes into the `createJob` calldata, which the owner's intent hashes (`execCalldataHash`). +So the owner's single signature covers the exact criteria, and the marketplace re-derives them before executing. + +### 7.2 What building does + +`JobSpecBuilder.build(jobSpecTemplate, ctx)` fills the template's holes: + +| Hole | Filled with | +|---|---| +| a `Fill` with source `CEA` in a read's args | the AGW's CEA **on that read's chain** | +| a `Fill` with source `PARAM` | one of the job's `params` (two's complement for negatives) | +| a check target `FIXED` | the template's value | +| a check target `PRINCIPAL_BPS` | `principal × bps / 10 000`, rounded down | +| a check target `PARAM` | one of the job's `params` | +| a check target `CEA` | the AGW's CEA on the check's read chain | +| `executeBy` | the job's `executeBy` | +| `failFinalAt` | `executeBy + card.settleWindow` | +| `origin` | `keccak256(abi.encode(marketplace, cardId, cardVersion, principal))` | + +`logic` (the pass-logic tree), `allowedMutability` and every other read field are copied verbatim. The full format +and two worked examples are in [`criteria.md`](./criteria.md). + +### 7.3 What building checks, and what it doesn't + +The template is **not judged**. Building checks only what building needs: + +| Check | Error | +|---|---| +| one param per template param | `ParamCountMismatch(expected, actual)` | +| each param inside its inclusive bounds | `ParamOutOfRange(index, value)` | +| each fill writes inside its read's args | `FillOutOfBounds(read, fill)` | +| `principal × bps` fits in uint256 | `TargetOverflow(check)` | +| a CEA is asked only for a chain with a CEA deployment | `ChainNotSupported(chainHash)` | + +Anything else malformed reverts on its own when a job is built (an index out of range panics, undecodable bytes +fail in `abi.decode`). A template the evaluator could not run, such as a read no check uses or an unreachable +logic step, **builds without complaint** (`test_JB08_doesNotJudgeTheTemplate`). `allowedMutability` is carried, +not enforced: nothing in this repo reads it. The verified tag is the review. + +--- + +## 8 · `openJob`, step by step + +`openJob(OpenJobParams p)` is `whenNotPaused` and `nonReentrant`. **Every check runs before the first state +change**, so a refusal leaves no wallet, no grant and no job (`test_MS13_intentSessionMismatch_noStateOnFailure`, +`test_MS22_envelopeVersion_named`). + +| Step | What | Code | Error on failure | +|---|---|---|---| +| 1 | Card exists and is active | `_checkCardAndJob` | `AgentCardInactive()` | +| 2 | `p.cardVersion` is the card's current version | `_checkCardAndJob` | `AgentCardVersionMismatch(provided, current)` | +| 3 | `principalMin ≤ principal ≤ principalMax` | `_checkJobWindows` | `PrincipalOutOfRange()` | +| 4 | `now + minDuration ≤ expiredAt ≤ now + maxDuration` | `_checkJobWindows` | `ExpiryOutOfRange()` | +| 5 | `executeBy ≥ now + minExecuteWindow` and `executeBy + settleWindow ≤ expiredAt` | `_checkJobWindows` | `ExecuteByOutOfRange()` | +| 6 | the card's provider is not the current evaluator (it may have changed since registration) | `_checkCardAndJob` | `ProviderIsEvaluator()` | +| 7 | `(agw, deployed) = AGW_FACTORY.predictWallet(intent.owner, intent.index)`; the intent names that wallet and this marketplace as executor | `_resolveWallet` | `IntentWalletMismatch(expected, provided)` · `ExecutorMismatch(expected, actual)` | +| 8 | the AGW has no active job opened here: `activeJobOf(agw) == 0` | `openJob` | `WalletHasActiveJob(agw, jobId)` | +| 9 | build the job's criteria from the card's `jobSpecTemplate` | `_buildCreateJob` → `JobSpecBuilder.build` | §7.3 errors | +| 10 | encode `createJob(provider, evaluator, expiredAt, description, hook)` as an ERC-7579 single execution: `abi.encodePacked(kernel, 0, call)` | `_buildCreateJob` | — | +| 11 | the intent's `mode`, `execCalldataHash` and `nonceKey` (`OPENJOB_LANE`) are exactly this execution, and its `sessionHash` is this session | `_bindIntent` | `IntentExecMismatch(expectedHash)` · `IntentSessionMismatch(expectedHash)` | +| 12 | the session is the card's rules with markers filled, `SessionContext{agent: provider, chainHash, principal, expiredAt, expectedCEA: computeCEA(agw, chainHash)}` (§6.3) | `_checkRules` → `RULES.checkRulesMatchCard` | C1–C14 errors | +| — | *first state change* | | | +| 13 | deploy the predicted wallet (`deployWalletWithSig`) and require it landed at the prediction; or, for an existing wallet, require the factory's `ownerOf` is the intent's owner | `_deployOrCheckOwner` | `AGWMismatch(expected, actual)` · `WalletOwnerMismatch(expected, actual)` | +| 14 | `rulesId = AGW.grantRulesWithSig(session, intent, sig)` | `openJob` | the AGW's own errors | +| 15 | `AGW.executeWithSig(MODE_SINGLE, calldata, intent, sig)`; exactly one new kernel job; its client is the AGW and its provider, hook and evaluator are the expected ones | `_createJob` | `UnexpectedJobCount(before, after)` · `JobMismatch()` | +| 16 | record `_lastJobOf`, `cardOfJob`, `agwOfJob`, `rulesOfJob`, `cardVersionOfJob`; emit `JobOpened(cardId, owner, agw, jobId, rulesId, principal, cardVersion)` | `openJob` | — | + +`openJob` makes one `createJob` execution (`MODE_SINGLE`). It does not revoke a wallet's previous rules set. + +**What one signature binds.** The owner signs one `OwnerIntent`. Through it: + +| Bound value | How | +|---|---| +| principal, `executeBy`, params, card version, the wallet (through its CEA) | inside the built `JobSpec`, inside the `createJob` calldata → `execCalldataHash` | +| `expiredAt`, provider, evaluator, hook | `createJob` arguments → `execCalldataHash` | +| the rules (assets and caps, gas cap, calls and pins, CEA, expiry) | the `Session` → `sessionHash` | +| which wallet, which executor | `wallet`, `executor` fields | +| replay | `nonceKey` / `nonceSeq` (the owner lane) and `grantNonce`, checked by the AGW | + +`test_MS12_intentExecMismatch_everyBoundInput` changes each bound input in turn and expects `IntentExecMismatch`. + +**Who checks the signature.** Not the marketplace. The factory and the wallet verify the owner's signature +themselves and accept the intent only from its `executor` (this contract). The marketplace's own checks +(steps 7 and 11) mirror the wallet's, so a mismatch fails early with a named error before any state change. + +**Previewing.** `previewIntent(request, session)` returns the exact `OwnerIntent` to sign: it predicts the wallet, +builds the same calldata `openJob` will, hashes it, and reads the wallet's live nonces (0 for a wallet not yet +deployed). `buildCreateJobCalldata` returns the execution itself. Both revert `AgentCardInactive` for an unknown +card, and both revert exactly as step 9 would on a bad template. `test_MV04_buildCreateJobCalldata` asserts that +what `openJob` executes equals this view's answer. + +**Front-running.** `openJob` can be called by anyone holding the signed parameters; the relayer has no power. A +third party who submits them first opens exactly the job the owner signed. The AGW's nonces make it one-shot. + +--- + +## 9 · Chains and CEAs + +A card's chain must be configured before any card can name it: + +- **`setCEADeployment(chainHash, ceaFactory, ceaProxyImpl)`** (admin) records the destination chain's CEA factory + and proxy implementation. A chain without one cannot carry cards (`ChainNotSupported`), and the builder cannot + ask for a CEA on it. +- **Clearing a chain.** `setCEADeployment(chainHash, 0, 0)` deletes the entry and emits + `CEADeploymentSet(chainHash, 0, 0)`. Registration and update on that chain, `computeCEA`, and `openJob` on an + existing card there then revert `ChainNotSupported(chainHash)`. Exactly one zero address reverts `ZeroAddress()` + (`test_MV11_setCEADeployment_clear`). +- **`computeCEA(agw, chainHash)`** mirrors `CEAFactory._computeCEAInternal`: an OZ minimal proxy of + `ceaProxyImpl`, salt `keccak256(abi.encode(agw))`, deployed by the CEA factory (`test_MV02_computeCEA` checks it + against the real `CEAFactory`). +- **Push itself is never a card chain** (`PUSH_CHAIN_HASH`, set at `initialize` from `block.chainid`). + +There is **no per-chain pause** any more (the `setUniversalPaused` / `isUniversalPaused` pair was removed; its +slot 14 is reserved and always zero; `test_MV14_noPerChainPause`). + +**CEA implementation rotation.** If the destination rotates its CEA proxy implementation, `computeCEA` goes stale. +An SDK reading the destination factory then signs the new CEA (in the `MARKER_WALLET` pin and `expectedCEA`), and +`openJob` refuses it, first at the wallet pin (`PinMismatch(1, 0)` in the test fixture), until the admin updates +the deployment (`test_MV03_ceaRotation_staleCaught`). Runbook: + +1. `pause()` stops registration, updates and `openJob` marketplace-wide. +2. Rotate the implementation on the destination chain. +3. `setCEADeployment(chainHash, factory, newImpl)`. +4. `unpause()`. + +An intent signed before the rotation names the old CEA in its criteria, so after step 3 it fails +`IntentExecMismatch` and must be re-signed. The CEA value is security-relevant: it is the wallet pin and expected +CEA of every rules grant on that chain (§6.3 C12, C14). A wrong entry still cannot silently redirect funds, +because the SDK derives the CEA independently and the two must agree. + +--- + +## 10 · One live job per wallet + +Two rules, at two moments, read through two views named `activeJobOf`: + +| View | Where | Returns the job id while | Used by | +|---|---|---|---| +| `UniversalMarketplace.activeJobOf(agw)` | marketplace | the last job **opened here** for the AGW is Funded, Submitted, or Open and not yet expired; else 0 | `openJob` step 8 (`WalletHasActiveJob(agw, jobId)`) | +| `RulesBindingHook.activeJobOf(agw)` | hook | the AGW's last job **bound by the hook** is Funded or Submitted; else 0 | `fund` (`AGWHasLiveJob(agw, jobId)`) | + +The difference is intended: the marketplace binds at `openJob`, so an Open, unexpired job also blocks and a user +cannot stack unfunded jobs on one wallet; the hook binds at `fund`, so it only sees funded jobs. An Open job frees +the wallet once it expires or is rejected; a Funded or Submitted job frees it once it is completed, rejected or +refunded (`test_MS14_oneLiveJob`, `test_MS21_activeJobOf`, hook `test_activeJobOf_returnsId`). + +Jobs created directly on the kernel, not through the marketplace, are invisible to the marketplace's +`activeJobOf`. The hook's rule still covers any job that names the hook. + +--- + +## 11 · Admin powers + +Roles (OpenZeppelin AccessControl): `DEFAULT_ADMIN_ROLE` manages roles; `ADMIN_ROLE` runs every admin function. +Both go to `InitParams.admin`. Upgrades are separate: they belong to the ProxyAdmin owner. + +| Function | Effect | Limits | +|---|---|---| +| `setHook(hook)` | hook of every **new** job | must be non-zero and whitelisted on the kernel; existing jobs keep theirs | +| `setEvaluator(evaluator)` | evaluator of every **new** job | non-zero; a card whose provider is the new evaluator can't open jobs (`ProviderIsEvaluator`) | +| `setCEADeployment(chainHash, factory, impl)` | enables a chain and sets its CEA derivation, or clears it with `(h, 0, 0)` | exactly one zero reverts | +| `setAgentRating(agent, rating)` | sets an agent's rating, read by `getAgentRating` | no validation; a placeholder until VerifiedRatings is wired | +| `pause()` / `unpause()` | stops or resumes `registerAgentCard`, `updateAgentCard`, `openJob` | admin functions, `setAgentCardActive` and views stay live | +| `disableAgentCard(cardId)` | permanently disables a card | cannot re-enable; the provider stays registered | +| `verifyAgentCard(cardId, cardVersion)` / `revokeAgentCardVerification(cardId)` | the verified tag | version-bound | + +The admin cannot move funds (the marketplace holds none), cannot change an opened job (the kernel fixed its +provider, evaluator, hook and description at creation), and cannot re-enable a disabled card. + +The admin **can** influence future jobs: the evaluator decides completion, and the hook gates funding. Both are +trust points of the deployment. + +--- + +## 12 · Deployment, upgradeability and build + +### 12.1 AGW dependency + +The package compiles against AGW v6 source: the submodule [`lib/push-agentic-wallets`](../../lib/push-agentic-wallets), +pinned at commit `ffd567d3e49b2d27c6f50ad36093274dbac3090f` (branch `deploy-agw`), with the remapping +`@push-agw/=lib/push-agentic-wallets/src/`. AGW v6 on Donut was deployed from that same commit. + +- Imported by name from `@push-agw/libraries/Types.sol` (a file with no imports): `OwnerIntent`, + `OWNER_LANE_FLAG`, `AssetCap`, `AllowedCall`, `ArgPin`, `PinOp`, `UniversalTerms`, `ENVELOPE_VERSION`, + `MAX_ASSETS`, `MAX_PINS`, `MAX_ALLOWED_CALL_PINS`; the fork test also imports the EIP-712 constants and + `SEND_OUTBOUND_SELECTOR`. A struct change in the AGW fails this build, not `openJob`. +- `Session` and its parts stay a mirror in `IAGW.sol` (the vendor SmartSession tree cannot be compiled here). The + fork test pins it: a wrong mirror changes the session hash and the real wallet refuses the grant. +- Donut v6 addresses are deploy-time inputs and test constants; nothing in `src/` hard-codes them. + +### 12.2 Wiring + +1. Deploy `UniversalMarketplaceRules` (no constructor arguments). +2. Deploy the `JobSpecBuilder` library and link it into `UniversalMarketplace`. Foundry links it automatically in + tests and scripts. +3. Deploy the `UniversalMarketplace` implementation; its constructor disables initializers. +4. Deploy a `TransparentUpgradeableProxy` calling `initialize(InitParams{agwFactory, kernel, hook, evaluator, + rules, admin})`. `agwFactory`, `kernel`, `rules`, `admin`, `hook` and `evaluator` must be non-zero, and the + hook must be whitelisted on the kernel. +5. `setCEADeployment` for each supported destination chain. + +Interim configuration (until the V2 UniversalHook and UniversalEvaluator ship): `hook` = RulesBindingHook, +`evaluator` = a Push-controlled address. + +### 12.3 Upgradeability + +- **The marketplace** sits behind a `TransparentUpgradeableProxy`. Its storage is append-only (slots 0–21, slot 14 + reserved, then a 27-slot gap, 22–48; see [`reference.md`](./reference.md#storage-layout)). OZ upgradeable bases + use ERC-7201 namespaced storage, so they don't occupy these slots. `test_MV09_storageLayout_bySlot` pins every + slot by position, and `test_MV10_upgrade_preservesState` upgrades through the ProxyAdmin. v1 was never + deployed, so there is no migration from it. v2 is live on Donut (§12.5): from now on every upgrade must keep + this layout. +- **The rules helper and JobSpecBuilder** are not upgradeable. A rule change is a new deployment plus a + marketplace upgrade that points at it. The helper is an `initialize`-time address (`RULES`); the library's + address is linked into the implementation's bytecode. + +### 12.4 Deploy script + +[`scripts/agentic-commerce-8183/DeployUniversalMarketplace.s.sol`](../../scripts/agentic-commerce-8183/DeployUniversalMarketplace.s.sol) +deploys the whole stack in one run and follows §12.2: + +1. `AgenticCommerce` (kernel) proxy, `initialize(pUSDC, treasury, deployer)`. +2. `RulesBindingHook` proxy, `initialize(kernel, AGW v6 factory, AGW v6 session engine)`, then + `kernel.setHookWhitelist(hook, true)`. +3. `UniversalMarketplaceRules`; the `JobSpecBuilder` library is deployed and linked by Foundry. +4. `UniversalMarketplace` proxy, `initialize` with the deployer as `admin` and as `evaluator`. +5. `setCEADeployment` for Ethereum Sepolia, Base Sepolia, Arbitrum Sepolia and BSC Testnet. + +Each proxy gets its own ProxyAdmin, owned by the deployer. Fees stay zero. Inputs come from `.env`: `DEPLOYER_KEY` +(the broadcaster) and `TREASURE_KEY` (its address becomes the kernel's platform treasury); both are accepted with or +without the `0x` prefix. The script refuses any chain other than Donut (42101). + +```bash +forge script scripts/agentic-commerce-8183/DeployUniversalMarketplace.s.sol \ + --rpc-url $PUSH_CHAIN_TESTNET_RPC_URL --broadcast --slow +``` + +### 12.5 Live deployment (Push Donut) + +Full table: [`docs/addresses/push_donut_universal_marketplace.md`](../addresses/push_donut_universal_marketplace.md). + +| Contract | Proxy | +|---|---| +| UniversalMarketplace | `0x9071ebE01B75123A91e88eB6ec4BF163F3fE9BF4` | +| AgenticCommerce (kernel, pUSDC `0x7A58048036206bB898008b5bBDA85697DB1e5d66`) | `0x977cf1AC973E9eC4332791d531507575006157Ed` | +| RulesBindingHook | `0xDe7A94e510b6C571DE7880d441349689F73A32b3` | +| UniversalMarketplaceRules (not a proxy) | `0x5b98A8E0df5b918DF76cD2BE84bA7995B39dfd44` | +| JobSpecBuilder (library) | `0x2de1e3F053b0bBa0cE0C6953144534a0b055f59e` | + +- **Its own kernel.** The stack does not use the `marketplace_demo` kernel (`0x4F9b…B1E0`) or its UniversalEvaluator + (`0x7D62…4Ce3`). That kernel is priced in eUSD, its admin is not ours, its evaluator accepts only jobs created + with its own UniversalHook, and that evaluator decodes a different `JobSpec` layout from `JobSpecTypes.sol`. +- **Evaluator is an EOA.** The deployer `0x1afC81396f1bb36F91f74506284952b81e4bd47c` completes or rejects jobs by + hand until a compatible evaluator is set with `setEvaluator` (and, if it needs its own hook, `setHook`). +- **Moving to another kernel.** `KERNEL` is set once at `initialize` and has no setter. Pointing the marketplace at + a different kernel takes a marketplace upgrade or redeploy plus a new RulesBindingHook whitelisted on that kernel. + Jobs already opened stay on the old kernel. +- Contracts are not source-verified on the explorer. + +### 12.6 Build configuration + +- solc 0.8.26, `via_ir`, EVM `shanghai`. +- **`UniversalMarketplace.sol` compiles at 1 000 optimizer runs**; every other contract uses 99 999. This is the + `compilation_restrictions` entry in `foundry.toml`. At 99 999 runs the inliner puts the marketplace over the + EIP-170 limit. +- Coverage must run with `FOUNDRY_PROFILE=coverage`, which drops that restriction. Otherwise contracts tested + from both compile jobs exist twice, and coverage keeps the hits of only one. + +| Contract | Runtime size | Margin to EIP-170 | +|---|---|---| +| UniversalMarketplace (1 000 runs) | 22,156 B | 2,420 B | +| UniversalMarketplaceRules | 9,376 B | 15,200 B | +| JobSpecBuilder | 6,352 B | 18,224 B | +| RulesBindingHook | 4,499 B | 20,077 B | + +--- + +## 13 · Trust model and security notes + +### 13.1 What the marketplace guarantees + +| Guarantee | Enforced by | Tested by | +|---|---|---| +| The rules granted are exactly the card's, markers filled, for the card's agent, bound to this job's principal, expiry and CEA | `checkRulesMatchCard` (§6.3) | `MB01`–`MB04`, `MT07`–`MT11`, `MS19`, `MS20`, `MI07`, fork test | +| The job's criteria are exactly the card's template, filled with this job's inputs | `_buildCreateJob` + intent binding (§7, §8) | `MS01`, `ML13`, `MV04`, `MC01`–`MC05` | +| The job is created by the user's own wallet, with the card's provider, the configured evaluator and hook | `_createJob` | `MS15` | +| A provider can't change a card under a user's signature | card version in `origin` | `ML11` | +| One card per provider | `agentCardOf` | `MR11`, `MI06` | +| Nothing moves through the marketplace | no transfer code; no payable function | `MS02`, `MI02`, `MI05` | +| One active job per wallet | `activeJobOf` (§10) | `MS14`, `MS21`, `MI01` | +| Every refusal happens before any state change | step order (§8) | `MS13`, `MS22` | + +### 13.2 What the marketplace relies on, or does not check + +1. **The AGW and its factory verify the owner's signature** and accept the intent only from its executor. They + also enforce deadlines, nonces and the signer chain. The marketplace's mirror checks only name the error + early. The unit suites use `MockAGW` / `MockAGWFactory`, which verify no signature; the fork test + `test_fork_openJob_realAGWv6` runs the real AGW v6 stack on Donut with a real owner signature. +2. **SmartSession and URP enforce the rules at execution.** The marketplace checks the rules' *content* at grant + time; it does not execute or watch them. +3. **Session fields the helper does not compare are pinned by the AGW.** The helper never compares the + `sessionValidator`, the policy address, the action target and selector, `userOpPolicies`, `erc7739Policies`, + `permitERC4337Paymaster` or `salt`. AGW v6 `_grantRules` refuses the grant unless: `userOpPolicies`, both + ERC-7739 lists are empty and `permitERC4337Paymaster` is false (`MalformedSessionShape`); a universal rules set + has exactly one action, targeting `UNIVERSAL_GATEWAY_PC` with `SEND_OUTBOUND_SELECTOR` (`RulesTypeMismatch`); + that action has one policy, which is URP; `sessionValidator == SESSION_VALIDATOR` and + `validateConfig(sessionValidatorInitData)` passes; and it overwrites `salt` with its grant nonce. URP then + refuses an envelope whose first word is not `ENVELOPE_VERSION`, an empty or oversized allow-list, a past or + zero `validUntil`, a zero `expectedCEA`, too many pins, and 0 or more than 8 assets, duplicates, or an asset + whose `SOURCE_CHAIN_NAMESPACE()` is not the envelope's chain. The question left open in v1 is therefore + closed: pinning these fields in the marketplace would duplicate the wallet's own checks. +4. **The criteria are not judged** (§7.3). A provider can register criteria the evaluator cannot run, or that + are trivially satisfied. The verified tag is the review, and the SDK must render every check in words before + the user signs. +5. **The asset check is a sanity check, not a security property.** The asset contract chooses its own + `SOURCE_CHAIN_NAMESPACE()` answer. What binds the assets is URP: the session's assets must equal the card's. +6. **`providerFee` is a reference price.** The marketplace never enforces it; the kernel does, at `fund`, through + the owner's `expectedBudget`. +7. **`createJob`'s `description` and `expiredAt` are not re-read after creation.** Step 15 checks the new job's + client, provider, hook and evaluator. The description and expiry are trusted to the AGW executing exactly the + signed calldata (its `execCalldataHash` check). +8. **The evaluator and hook are admin-set trust points** for new jobs (§11). +9. **`MARKER_PRINCIPAL` on a non-principal token's `approve` is not detectable.** The helper requires an + `approve`'s amount to be capped (R15) but cannot check that a `MARKER_PRINCIPAL` cap sits on the principal + token's `approve`: `IPRC20` has no source-token view, so a PRC20 cannot be mapped to its destination token. + The verified tag covers it. + +### 13.3 Reentrancy and external calls + +`openJob` is `nonReentrant` and makes its external calls only after every check: + +1. `AGW_FACTORY.deployWalletWithSig`, a factory the deployment chose; +2. `AGW.grantRulesWithSig`, `AGW.executeWithSig`, on the predicted wallet; +3. `KERNEL.jobCounter`, `KERNEL.getJob`. + +Before them, the checks read `AGW_FACTORY.predictWallet`, `KERNEL.getJob` (for `activeJobOf`) and call the pure +`RULES` helper. The wallet is the factory's deterministic deployment for the intent's owner, re-checked by +`AGWMismatch` / `WalletOwnerMismatch`. The marketplace holds no value, so a reentrant path has nothing to drain. +Registration also calls `KERNEL.paymentToken()` and each asset's `SOURCE_CHAIN_NAMESPACE()`. + +### 13.4 Known limitations of v2 + +| Limitation | Note | +|---|---| +| **EVM destinations only** | Cards name `eip155:*` chains, never Push. Solana and native (Push-side) cards are out of scope. | +| **One payment token** | Until kernel K-12, every card's `paymentToken` must be the kernel's token (pUSDC on the Donut deployment). | +| **Kernel is fixed** | `KERNEL` has no setter; changing kernels needs an upgrade or redeploy (§12.5). | +| **Interim hook and evaluator** | RulesBindingHook and a Push-controlled evaluator until the V2 UniversalHook and UniversalEvaluator ship. The `JobSpec` description and its `allowedMutability` are inert to RulesBindingHook. | +| **No revoke of a previous grant** | `openJob` on an existing wallet grants a new rules set; the previous one is not revoked by the marketplace. | +| **Rating is a placeholder** | `setAgentRating` / `getAgentRating` store an admin number until VerifiedRatings is wired. | +| **A card can be internally inconsistent** | Registration checks `minExecuteWindow + settleWindow ≤ maxDuration` only. A card whose `minDuration` is shorter than that sum simply can't open jobs at its shortest expiry (`ExecuteByOutOfRange`). | +| **Error decoding** | Each contract's ABI lists only the errors it raises itself. Decode marketplace reverts, including rules-helper and builder errors that bubble through `openJob`, with the `UniversalMarketplaceErrors` artifact, which lists all 40. | + +--- + +## 14 · Invariants + +Fuzzed by [`UniversalMarketplace.invariants.t.sol`](../../test/8183-tests/UniversalMarketplace.invariants.t.sol): +64 runs × depth 100 per invariant. The handler opens jobs through honest and misbehaving wallets, registers cards +from three providers, updates the card, cancels jobs and moves time. + +| Invariant | Property | +|---|---| +| `MI01_activeJobIsTheAgwsOwnJob` | `activeJobOf(agw)` is 0 or a job whose client is that AGW | +| `MI02_marketplaceHoldsNothing` | The marketplace's token, rules-asset and native balances are always 0 | +| `MI03_outcomesExactlyExpected` | An honest open on a free wallet always succeeds; a misbehaving wallet (two jobs, foreign client) is always refused with its own named error | +| `MI04_everyJobIsWellFormed` | Every opened job's description decodes as a `JobSpec` with the recorded `origin`, and has the configured evaluator and hook | +| `MI05_userBalanceNeverMovedByOpenJob` | The user's tokens and PC never change | +| `MI06_onePerProvider` | `agentCardOf[p]` is 0 or a card whose provider is `p`; no two cards share a provider; a second registration is always refused with `AgentCardAlreadyRegistered` | +| `MI07_principalCapEqualsPrincipal` | For every opened job, the granted rules' `assets[principalAsset].maxTotal` equals that job's principal | +| `afterInvariant` | Liveness: at least one honest open and one refused misbehaviour happened, so none of the above held vacuously | + +--- + +## 15 · Tests + +`forge test --match-path 'test/8183-tests/*' --no-match-contract 'Invariants|ForkTest'`: 247 tests, all passing. +The invariant suites and both fork tests pass too. The marketplace-related suites: + +| Suite | Tests | Covers | +|---|---|---| +| [`UniversalMarketplace.t.sol`](../../test/8183-tests/UniversalMarketplace.t.sol) | 68 | Registration (MR01–MR14), card lifecycle (ML01–ML13), `openJob` (MS01–MS22), rules = card through the marketplace (MB01–MB04), views, admin, initialize, storage layout, upgrade, CEA clearing, rating, version, no per-chain pause (MV01–MV14) | +| [`UniversalMarketplaceRules.t.sol`](../../test/8183-tests/UniversalMarketplaceRules.t.sol) | 11 | The helper directly: R1–R17 (MT01–MT06), each C1–C14 error with exact arguments (MT07–MT09), malformed input (MT10), fuzzed principal binding (MT11) | +| [`JobSpecBuilder.t.sol`](../../test/8183-tests/JobSpecBuilder.t.sol) | 12 | Fills, targets, timing and origin, params, overflow, fill bounds, unsupported chains, "does not judge", fuzz, `logic` and `allowedMutability` copied (JB12) | +| [`UniversalMarketplace.conformance.t.sol`](../../test/8183-tests/UniversalMarketplace.conformance.t.sol) | 5 | Built criteria equal the V2 design doc's examples, field by field; every built read decodes in a copy of the V2 evaluator's decoder; the `JobSpec` ABI field order (MC05) | +| [`UniversalMarketplace.invariants.t.sol`](../../test/8183-tests/UniversalMarketplace.invariants.t.sol) | 7 | §14 | +| [`UniversalMarketplace.fork.t.sol`](../../test/8183-tests/UniversalMarketplace.fork.t.sol) | 1 | `openJob` against the real AGW v6 on Donut: fresh wallet, fund through the hook, refusal while Funded, existing-wallet path, pre-v6 envelope named | +| [`Naming.t.sol`](../../test/8183-tests/Naming.t.sol) | 8 | Every function, event and error of the v2 surface pinned to literal signatures; marker values; no retired names in ABIs | +| [`RulesBindingHook.t.sol`](../../test/8183-tests/RulesBindingHook.t.sol) | 32 | The interim hook, including `activeJobOf` returning the id | +| [`RulesBindingHook.fork.t.sol`](../../test/8183-tests/RulesBindingHook.fork.t.sol) | 1 | The factory and engine interfaces against Donut v6 | + +The two fork tests skip unless `PUSH_CHAIN_TESTNET_RPC_URL` is set. Both were run against Donut at block +24310581 and passed. + +Unit fixtures use the real kernel, the real RulesBindingHook, the real rules helper and builder library, and the +real `CEAFactory`. The AGW factory and wallet are mocks: they enforce the rules the marketplace relies on +(executor, hashes, nonces), decode the policy envelope as the real wallet does, and verify no signature. +`MockAGW` has misbehaving modes (two jobs, foreign client, rewritten evaluator) to test the marketplace's +post-creation checks. Shared fixtures for card rules and the SDK's session filling are in +[`helpers/RulesFixtures.sol`](../../test/8183-tests/helpers/RulesFixtures.sol). + +**Coverage** (`FOUNDRY_PROFILE=coverage`, `--ir-minimum`, gas test excluded): + +| Contract | Lines | Statements | Branches | Functions | +|---|---|---|---|---| +| UniversalMarketplace | 97.63% (247/253) | 98.14% (317/323) | 100% (52/52) | 100% (37/37) | +| UniversalMarketplaceRules | 100% (132/132) | 100% (253/253) | 100% (39/39) | 100% (12/12) | +| JobSpecBuilder | 98.28% (57/58) | 98.80% (82/83) | 100% (12/12) | 100% (7/7) | +| RulesBindingHook | 96.43% (27/28) | 96.97% (32/33) | 100% (6/6) | 100% (6/6) | + +Every uncovered line is executed by the tests but not attributed by `--ir-minimum`: + +| File:line | Code | Executed by | +|---|---|---| +| `UniversalMarketplace.sol:98` | `_disableInitializers()` (constructor) | every test that deploys the implementation; `test_MV08_initialize` asserts its effect | +| `UniversalMarketplace.sol:107-109` | `__AccessControl_init()`, `__Pausable_init()`, `__ReentrancyGuard_init()` | every `initialize` | +| `UniversalMarketplace.sol:165`, `:170` | `_pause()`, `_unpause()` | `test_MV07_pause` | +| `RulesBindingHook.sol:40` | `_disableInitializers()` (constructor) | every hook deployment | +| `JobSpecBuilder.sol:106` | the inline `mstore` of a fill | every build with a fill; `test_JB01_fills` asserts the written words | + +**Mutation testing.** + +30 hand-written mutants, each applied to the source, run against one suite, then restored from a backup outside +`src/`. **30 killed, 0 survived.** + +| Group | Mutants | Suite | Result | +|---|---|---|---| +| Registration guards R1–R17, each check removed | 17 | `UniversalMarketplaceRules.t.sol` | 17 killed (MT02–MT06) | +| Rules = card C4, C6–C12, each check removed | 8 | `UniversalMarketplaceRules.t.sol` | 8 killed (MT08, MT09, MT11) | +| Marketplace: the `agentCardOf` check, the `paymentToken` guard, `<` → `<=` in `activeJobOf`'s Open-expiry comparison, the `delete` in `setCEADeployment`'s both-zero branch, the `cardVersionOfJob` write | 5 | `UniversalMarketplace.t.sol` | 5 killed (MR11, MR12, MS14, MV11, ML12) | + +Several mutants were killed by a wrong-error assertion rather than a missing revert, for example R2 (the decoder +panics on the out-of-range index instead of `InvalidAgentCard("principal asset")`) and C4 (a pre-v6 envelope +panics in `abi.decode` instead of `EnvelopeVersionMismatch(64)`): every negative test names its exact error. + +**Gas ceilings** (`test_MS18_gasCeilings`, mock wallet and factory, two-asset card): `registerAgentCard` +≤ 2.70 M (measured 2,564,983), `openJob` on a fresh wallet ≤ 4.45 M (4,231,625), on an existing wallet ≤ 1.89 M +(1,797,405). The v1 ceilings were 2.46 M / 3.49 M / 2.09 M. Both `openJob` figures include `MockAGW` storing the +granted policy `initData` for the tests. `registerAgentCard` is dominated by storing the two content blobs; +`openJob` by the wallet deploy and the kernel storing the description. + +--- + +## 16 · Reviewer checklist + +Where to look first: + +1. **`openJob` ordering** (§8): every check before the first state change; the intent's `execCalldataHash` + covers everything per-job. +2. **`checkRulesMatchCard` completeness** (§6.3, §13.2 item 3): the C1–C14 order, the envelope version read before + decoding, and marker filling in C8 and C12. +3. **Registration guards** (§6.2): R1–R17, especially the approve rules R14–R15 and the duplicate rules R11–R12. +4. **CEA derivation** (§9): `computeCEA` against `CEAFactory`; the rotation runbook; clearing a chain. +5. **`JobSpecBuilder`** ([`criteria.md`](./criteria.md)): the only inline assembly (`mstore` of a fill) and its + bounds check; the PRINCIPAL_BPS overflow argument; the `DELEGATECALL` context (`address(this)` is the + marketplace). +6. **`_requireAssetOnChain`**: the raw `staticcall` ABI-shape check, now run for every asset. +7. **Storage layout and upgrade safety** (§12.3, [`reference.md`](./reference.md#storage-layout)). +8. **Admin trust points** (§11): evaluator, hook, CEA deployments. +9. **The interim hook** (`RulesBindingHook`): the `fund`-time binding and its `activeJobOf`. +10. **The AGW dependency** (§12.1): the submodule commit and what is imported versus mirrored. diff --git a/plan/marketplace/contracts/docs/universalmarketplace/criteria.md b/plan/marketplace/contracts/docs/universalmarketplace/criteria.md new file mode 100644 index 00000000..46b6c41e --- /dev/null +++ b/plan/marketplace/contracts/docs/universalmarketplace/criteria.md @@ -0,0 +1,374 @@ +# Universal Marketplace — Job criteria + +How a card says what counts as "done", and how `openJob` turns that into one job's criteria. For where this fits +in the whole flow, see [`README.md`](./README.md) §7. + +- [Two formats: template and JobSpec](#two-formats-template-and-jobspec) +- [The JobSpec](#the-jobspec) +- [The template](#the-template) +- [Building a JobSpec](#building-a-jobspec) +- [Worked example: a lending card](#worked-example-a-lending-card) +- [Worked example: a swap card with a user param](#worked-example-a-swap-card-with-a-user-param) +- [What the SDK must do](#what-the-sdk-must-do) + +--- + +## Two formats: template and JobSpec + +| | Template (`JobSpecTemplate`) | Criteria (`JobSpec`) | +|---|---|---| +| Where | stored on the card as `jobSpecTemplate` (`abi.encode`d, as given) | the 8183 job's `description` (`abi.encode(JobSpec)`) | +| Written by | the provider, once per card version | `JobSpecBuilder`, once per job | +| Holds | everything that is the same for every job, plus **holes** | concrete values for this job | +| Read by | the marketplace, at `openJob` / previews | the hook (at `fund`) and the evaluator (at verify) | +| Defined in | [`libraries/Types.sol`](../../src/agentic-commerce-8183/libraries/Types.sol) | [`libraries/JobSpecTypes.sol`](../../src/agentic-commerce-8183/libraries/JobSpecTypes.sol) | + +The `JobSpec` is the format of the Universal Evaluator V2 design, plus `origin` and `allowedMutability`. +JobSpecTypes is the one definition shared by everything that writes or reads a job's criteria. Its field order is +ABI: reordering or inserting a field changes every description. + +--- + +## The JobSpec + +```solidity +struct JobSpec { // FIELD ORDER IS ABI, decided 2026-10-12 + Read[] reads; + Check[] checks; + Logic[] logic; // logic[0] is the root: the job passes if it passes + AllowedMutability allowedMutability; // copied from the template; not read in this repo + bytes32 origin; // keccak256(abi.encode(marketplace, cardId, cardVersion, principal)) + uint64 executeBy; // the provider must execute before this + uint64 failFinalAt; // a FAIL only counts from a verify started after this +} +``` + +The ABI head is seven words: three offsets (reads, checks, logic), then `allowedMutability`, `origin`, +`executeBy`, `failFinalAt` (`test_MC05_fieldOrder`). + +### Reads: what to look at + +```solidity +struct Read { + string chainNamespace; // namespace only, "eip155" + string chainId; // decimal, e.g. "11155111" + uint16 minConfirmations; // confirmations before the answer counts + address target; // the contract to call + bytes4 selector; // the view function + bytes args; // abi-encoded arguments + bytes outputs; // the function's return types, as type codes + uint8[] field; // which returned value, by ABI position +} +``` + +A read is one view call on one chain. **`chainNamespace` here is the namespace only** (`"eip155"`), with +`chainId` separate: the Read State split of the V2 design. That differs from `AgentCard.chainNamespace`, which is +the full CAIP-2 string `"eip155:"`. + +`outputs` describes the return types so the evaluator can find one value in the answer. Codes: + +| Code | Type | Code | Type | +|---|---|---|---| +| 1 `T_UINT` | `uintN` | 6 `T_BYTES` | `bytes` | +| 2 `T_INT` | `intN` | 7 `T_STRING` | `string` | +| 3 `T_BOOL` | `bool` | 8 `T_TUPLE` | tuple / struct: followed by its field count, then each field's type | +| 4 `T_ADDRESS` | `address` | 9 `T_ARRAY` | `T[]`: followed by the element type | +| 5 `T_BYTESN` | `bytesN` | 10 `T_FIXED_ARRAY` | `T[k]`: followed by `k`, then the element type | + +The top level is always a tuple of the return values. For example, `balanceOf(address) returns (uint256)` is +`[T_TUPLE, 1, T_UINT]`. + +`field` is the path to the value: at a tuple, the field index; at an array, the element index. `[0]` is the first +return value; `[0, 2]` is the first return value's third field. + +How the evaluator turns the selected value into a number (from the V2 design; a test-only copy of its decoder is +[`test/8183-tests/helpers/V2Decoder.sol`](../../test/8183-tests/helpers/V2Decoder.sol)): + +| Leaf | Value compared | +|---|---| +| uint / int | the number (a uint above `int256.max` is "can't tell") | +| bool | 0 or 1 | +| address, bytesN | the raw word (compare with `EQUAL` / `NOT_EQUAL`) | +| bytes, string | `keccak256` of the content | +| array | its length | + +### Checks: what to compare + +```solidity +struct Check { + uint8 read; // index into reads + Evaluation evaluation; + Operation operation; // EQUAL, NOT_EQUAL, GREATER_THAN, GREATER_OR_EQUAL, LESS_THAN, LESS_OR_EQUAL + int256 target; // in the contract's own units +} +``` + +| `Evaluation` | Compares | +|---|---| +| `BOOLEAN` | the value now, as a bool | +| `COMPARE` | the value now | +| `NUMBER` | the change since the baseline the hook takes at `fund` (V2 UniversalHook) | +| `PERCENTAGE` | the percentage change since that baseline | + +The ordinals are those of the v1 names (`BOOL`, `CMP`, `NUM`, `PCT` and `EQ` … `LTE`), so the encoding did not +change, only the names. + +### Logic: the pass logic + +```solidity +enum LogicKind { ALL, ANY, AT_LEAST } + +struct Logic { + LogicKind kind; + uint8[] checks; // indexes into checks + uint8[] children; // indexes into logic, each greater than this step's own index + uint8 k; // AT_LEAST only +} +``` + +`logic[0]` is the root. A step combines its checks and its child steps: `ALL` is AND, `ANY` is OR, `AT_LEAST` +needs `k` of the step's checks and children together to pass. Children always have a higher index than their +parent, so the tree has no cycles and can be evaluated from the last step to the first. A step's checks are leaves, +so there is no separate `CHECK` kind (v1's `Node` had one). + +**The marketplace never evaluates `logic`.** It copies the template's array verbatim; the semantics above are the +evaluator's, and are stated here only so a card can be read. They are evaluator-owned. + +### `allowedMutability` + +```solidity +enum AllowedMutability { NONE, CLIENT, PROVIDER, BOTH } +``` + +Who may propose a replacement JobSpec at `setBudget`. Carried, not enforced: the builder copies whatever the +template says and nothing in this repo reads it (`test_JB12_copiesLogicAndMutability`). + +### Timing + +- **`executeBy`**: the provider must have executed by then. +- **`failFinalAt = executeBy + card.settleWindow`**: a FAIL verdict only counts from a verify started after this, + so slow settlement on the destination chain is not misread as failure. + +The marketplace guarantees `executeBy ≥ now + minExecuteWindow` and `failFinalAt ≤ expiredAt` (`openJob` step 5). + +### `origin` + +`keccak256(abi.encode(marketplace, cardId, cardVersion, principal))`. The hook and evaluator ignore it. It ties +the job to the card version it was opened from, and it is what makes an intent signed against one version +unusable on another: the version is inside the signed calldata. + +--- + +## The template + +```solidity +struct JobSpecTemplate { + ReadTemplate[] reads; + CheckTemplate[] checks; + Logic[] logic; // copied verbatim + AllowedMutability allowedMutability; // copied verbatim + ParamBounds[] params; // one entry per per-job number the user supplies +} +``` + +### ReadTemplate: a Read with fills + +```solidity +struct ReadTemplate { + string chainNamespace; // "eip155" + string chainId; + uint16 minConfirmations; + address target; + bytes4 selector; + bytes args; // with placeholder words + Fill[] fills; // what to write into args per job + bytes outputs; + uint8[] field; +} + +enum FillSource { CEA, PARAM } + +struct Fill { + uint8 word; // overwrites args[32·word : 32·word + 32] + FillSource source; + uint8 param; // PARAM only: index into the job's params +} +``` + +| Fill source | Word written | +|---|---| +| `CEA` | the AGW's CEA **on this read's chain**, as a 32-byte word | +| `PARAM` | the job's `params[param]`, as a 32-byte word (two's complement for negatives) | + +A CEA fill is how criteria name "this user's account": `balanceOf(CEA)`, `ownerOf(tokenId) == CEA`, and so on. +The CEA is derived per read chain, so one template can read two chains, each with that chain's CEA. (The SDK maps +its word `WALLET` to `FillSource.CEA` / `TargetSource.CEA`.) + +### CheckTemplate: a Check with a target source + +```solidity +enum TargetSource { FIXED, PRINCIPAL_BPS, PARAM, CEA } + +struct CheckTemplate { + uint8 read; + Evaluation evaluation; + Operation operation; + TargetSource source; + int256 value; +} +``` + +| Source | `value` means | Target | +|---|---|---| +| `FIXED` | the target | `value` | +| `PRINCIPAL_BPS` | basis points of the principal | `principal × value / 10 000`, rounded down | +| `PARAM` | an index into the job's params | `params[value]` | +| `CEA` | unused | the AGW's CEA on the check's read chain, as `int256(uint160(cea))` | + +`PRINCIPAL_BPS` is how criteria scale with the job's size ("at least 99.99% of the principal arrived"). + +### ParamBounds: per-job numbers + +```solidity +struct ParamBounds { int256 min; int256 max; } // inclusive +``` + +A template may declare numbers the user picks per job (a minimum swap output, a tick range, …). The job supplies +exactly one value per entry, each inside its bounds. The values feed `PARAM` fills and `PARAM` targets. Units are +the provider's, described in the card's metadata. + +--- + +## Building a JobSpec + +[`JobSpecBuilder.build`](../../src/agentic-commerce-8183/libraries/JobSpecBuilder.sol), called at `openJob` +step 9 and by both preview views: + +1. **Decode** the `JobSpecTemplate`. Undecodable bytes revert in `abi.decode`. +2. **Params**: `params.length == template.params.length`, else `ParamCountMismatch(expected, actual)`; each + `min ≤ params[i] ≤ max`, else `ParamOutOfRange(i, value)`. +3. **CEAs**: for each read with a CEA fill, and each read a `CEA`-target check names, get + `computeCEA(agw, keccak256(namespace ":" chainId))` from the marketplace, once per read. A chain without a + CEA deployment reverts `ChainNotSupported(chainHash)`. +4. **Reads**: copy each read; copy its `args` into a fresh buffer; apply each fill. A fill must satisfy + `32·word + 32 ≤ args.length`, else `FillOutOfBounds(read, fill)`. This bound check is what makes the one + inline-assembly `mstore` safe. +5. **Checks**: copy `read`, `evaluation`, `operation`; resolve the target. For `PRINCIPAL_BPS`, if + `principal > type(uint256).max / bps`, revert `TargetOverflow(check)`. Once the product fits, the quotient is at + most `uint256.max / 10 000`, which always fits in `int256`, so the cast cannot truncate. +6. **`logic`** and **`allowedMutability`** copied verbatim. `executeBy`, `failFinalAt = executeBy + settleWindow`, + `origin`. +7. Return `abi.encode(spec)`. + +**Not checked:** whether the criteria make sense or can be run. That covers caps on the number of reads, checks +or logic steps; outputs that are not valid type codes; fields that point nowhere; reads no check uses; +unreachable steps; `allowedMutability` values; and trivially true criteria. All of these build as given +(`test_JB08_doesNotJudgeTheTemplate`). The caps `MAX_READS` (16), `MAX_CHECKS` (16) and `MAX_LOGIC` (32) in +JobSpecTypes are the evaluator's, not enforced here. An out-of-range index (a check's `read`, a fill's `param`, a +`PARAM` target) panics. Anything that reverts here makes `openJob` and both previews of that card revert. + +The result is deterministic for a given card version, job inputs and CEA configuration +(`testFuzz_JB11_deterministic`). + +--- + +## Worked example: a lending card + +"Deposit the principal into Aave v3 on Sepolia, at a supply rate of at least 4%." This is the test fixture's card +(`_lendingTemplate` and `_rules` in [`UniversalMarketplace.t.sol`](../../test/8183-tests/UniversalMarketplace.t.sol)) +and the V2 design doc's lending example. + +**Card:** `chainNamespace = "eip155:11155111"`, `settleWindow = 2 h`, `paymentToken` = the kernel's token. + +**Rules** (`_cardRules` in [`helpers/RulesFixtures.sol`](../../test/8183-tests/helpers/RulesFixtures.sol)): + +``` +assets [ {pUSDC (Sepolia PRC20), maxPerCall: MARKER_PRINCIPAL, maxTotal: MARKER_PRINCIPAL} ] +principalAsset 0 +maxGasPerCall 1e18 +allowedCalls[0] USDC.approve pins [ {4, EQ, Pool}, {36, MAX, MARKER_PRINCIPAL} ] +allowedCalls[1] Pool.supply(address,uint256,address,uint16) pins [ {68, EQ, MARKER_WALLET} ] +allowedCalls[2] USDC.transfer beneficiary at offset 4, no pins +``` + +For a 500 USDC job, the signed session holds `{pUSDC, 500e6, 500e6}`, the approve amount pin `bytes32(500e6)`, and +the supply pin the CEA word. + +**Template:** + +``` +reads[0] eip155 / 11155111, 12 confirmations + aUSDC.balanceOf(address) args = 32 zero bytes fills = [word 0 ← CEA] + outputs = [TUPLE 1, UINT] field = [0] +reads[1] eip155 / 11155111, 12 confirmations + Pool.getReserveData(address) args = abi.encode(USDC) fills = [] + outputs = [TUPLE 1, TUPLE 15, (TUPLE 1, UINT), UINT×7, ADDRESS×4, UINT×3] + field = [0, 2] (the struct's 3rd field: currentLiquidityRate) +checks[0] read 0, COMPARE, GREATER_OR_EQUAL, PRINCIPAL_BPS, 9999 "deposited ≥ 99.99% of principal" +checks[1] read 1, COMPARE, GREATER_OR_EQUAL, FIXED, 0.04e27 "rate ≥ 4% (ray)" +logic [ {ALL, checks [0, 1], children [], k 0} ] +allowedMutability NONE +params [] +``` + +**A job:** principal 500 USDC (`500e6`), `executeBy = now + 1 h`, for wallet 0 of the user. + +**Built JobSpec:** + +``` +reads[0].args = abi.encode(CEA(agw, "eip155:11155111")) +checks[0].target = 500e6 × 9999 / 10 000 = 499 950 000 +checks[1].target = 0.04e27 +logic = [ {ALL, checks [0, 1], children [], k 0} ] +allowedMutability = NONE +origin = keccak256(abi.encode(marketplace, cardId, 1, 500e6)) +executeBy = now + 1 h +failFinalAt = now + 3 h +``` + +The evaluator later passes the job if both checks pass: the CEA's aUSDC balance is at least 499.95 USDC, and +Aave's current supply rate is at least 4%. + +`test_MC01_lendingExample_equalsV2Doc` builds the same template on Ethereum (the design doc's chain) and compares +the result, field by field and byte for byte, with the V2 design doc's JobSpec written by hand in the new field +order. The fork test `test_fork_openJob_realAGWv6` decodes the description of a job opened through the real AGW +v6 and checks this `logic`, `allowedMutability` and `origin`. + +## Worked example: a swap card with a user param + +"The CEA receives at least `minOut` WETH." `minOut` is chosen by the user per job. + +``` +reads[0] eip155 / 11155111, 3 confirmations + WETH.balanceOf(address) args = 32 zero bytes fills = [word 0 ← CEA] + outputs = [TUPLE 1, UINT] field = [0] +checks[0] read 0, NUMBER, GREATER_OR_EQUAL, PARAM, 0 "balance grew by ≥ params[0]" +logic [ {ALL, checks [0], children [], k 0} ] +allowedMutability NONE +params [ {min: 1, max: 1e30} ] +``` + +A job with `params = [0.38e18]` gets `checks[0].target = 0.38e18` and the same one-step `logic` +(`test_MC02_swapExample_equalsV2Doc`). `NUMBER` compares the change since the baseline the V2 UniversalHook takes +at `fund`, so WETH the CEA already held doesn't count. (The interim RulesBindingHook takes no baseline; `NUMBER` +and `PERCENTAGE` checks need the V2 hook.) A job with `params = [0]` reverts `ParamOutOfRange(0, 0)`; one with no +params reverts `ParamCountMismatch(1, 0)`. + +Trees with child steps are built the same way. "(Aave deposited AND Aave ≥ 4%) OR (Morpho deposited AND Morpho +rate ≥ 4%)" is `logic = [ {ANY, checks [], children [1, 2]}, {ALL, checks [0, 1]}, {ALL, checks [2, 3]} ]`, and +"at least 2 of Aave, Morpho, Spark" is `[ {AT_LEAST, checks [0, 1, 2], children [], k 2} ]` +(`test_MC03_orAndAtLeastExamples`). + +--- + +## What the SDK must do + +- **Build templates from ABIs**: `outputs` and `field` from the function's ABI and the chosen return field, and + CEA fills where the CEA appears in the arguments. +- **Render every check and the `logic` tree in words before the user signs.** The template is not judged + on-chain; what the user sees is their protection, together with the verified tag. +- **Fill the card's markers into the session** exactly as README §6.1 tables them, and wrap the terms in the v6 + envelope `abi.encode(uint16 1, chain, abi.encode(UniversalTerms))`. +- **Use `previewIntent`** to get the exact intent to sign, so the signed calldata hash covers the built criteria. +- **Derive the CEA independently** from the destination `CEAFactory` for the session's `expectedCEA` and + `MARKER_WALLET` pins, and treat a disagreement with `computeCEA` as an error. diff --git a/plan/marketplace/contracts/docs/universalmarketplace/reference.md b/plan/marketplace/contracts/docs/universalmarketplace/reference.md new file mode 100644 index 00000000..ee4776e1 --- /dev/null +++ b/plan/marketplace/contracts/docs/universalmarketplace/reference.md @@ -0,0 +1,490 @@ +# Universal Marketplace — Reference + +Every function, event, error, type, constant and storage slot of the Universal Marketplace package. For how they +fit together, read [`README.md`](./README.md) first. Section numbers like "§8" refer to that file. + +- [UniversalMarketplace](#universalmarketplace) + - [Initialization](#initialization) + - [Admin functions](#admin-functions) + - [Card functions](#card-functions) + - [openJob](#openjob) + - [Views](#views) + - [Constants](#constants) + - [Storage layout](#storage-layout) +- [UniversalMarketplaceRules](#universalmarketplacerules) +- [JobSpecBuilder](#jobspecbuilder) +- [RulesBindingHook (interim hook)](#rulesbindinghook-interim-hook) +- [Types](#types) +- [Markers](#markers) +- [Events](#events) +- [Errors](#errors) + +--- + +## UniversalMarketplace + +[`src/agentic-commerce-8183/UniversalMarketplace.sol`](../../src/agentic-commerce-8183/UniversalMarketplace.sol). +Inherits OZ `Initializable`, `AccessControlUpgradeable`, `PausableUpgradeable`, `ReentrancyGuardUpgradeable` and +`IUniversalMarketplace`. Deployed behind a `TransparentUpgradeableProxy`. It has no payable function and holds +no funds. `version()` returns `"2.0.0"`. + +### Initialization + +#### `constructor()` +Calls `_disableInitializers()`, so the implementation itself can never be initialized. + +#### `initialize(InitParams calldata p)` — `initializer` + +| Step | Effect | +|---|---| +| 1 | Reverts `ZeroAddress()` if `agwFactory`, `kernel`, `rules` or `admin` is zero. | +| 2 | Initializes AccessControl, Pausable and ReentrancyGuard. | +| 3 | Stores `AGW_FACTORY`, `KERNEL`, `RULES`. | +| 4 | `PUSH_CHAIN_HASH = keccak256("eip155:" ‖ decimal(block.chainid))`. | +| 5 | `_setHook(p.hook)`: `ZeroAddress()` if zero, `HookNotWhitelisted()` unless `KERNEL.whitelistedHooks(hook)`; emits `HookUpdated`. | +| 6 | `_setEvaluator(p.evaluator)`: `ZeroAddress()` if zero; emits `EvaluatorUpdated`. | +| 7 | Grants `DEFAULT_ADMIN_ROLE` and `ADMIN_ROLE` to `p.admin`. | + +A second call reverts `InvalidInitialization()` (OZ). + +### Admin functions + +All are `onlyRole(ADMIN_ROLE)`; a non-admin caller gets `AccessControlUnauthorizedAccount(caller, ADMIN_ROLE)`. +None is pausable. + +#### `setHook(address hook)` +Sets the hook every **new** job is created with. Reverts `ZeroAddress()` or `HookNotWhitelisted()`. Emits +`HookUpdated(hook)`. Existing jobs keep the hook the kernel recorded at creation. + +#### `setEvaluator(address evaluator)` +Sets the evaluator every **new** job is created with. Reverts `ZeroAddress()`. Emits `EvaluatorUpdated(evaluator)`. +Not checked against providers: a card whose provider is now the evaluator is refused at `openJob` +(`ProviderIsEvaluator()`). + +#### `setCEADeployment(bytes32 chainHash, address ceaFactory, address ceaProxyImpl)` +Records a destination chain's CEA factory and proxy implementation, which enables the chain for cards and for +criteria reads and sets the CEA derivation (§9). + +| Arguments | Effect | +|---|---| +| both zero | `delete ceaDeployment[chainHash]`: the chain then reports `ChainNotSupported(chainHash)` everywhere | +| exactly one zero | reverts `ZeroAddress()` | +| both non-zero | sets the entry | + +Emits `CEADeploymentSet(chainHash, ceaFactory, ceaProxyImpl)` when it does not revert. Rotation runbook: +`pause()` → rotate on the destination → `setCEADeployment` → `unpause()`. + +#### `setAgentRating(address agent, uint256 rating)` +`_agentRating[agent] = rating`; emits `AgentRatingSet(agent, rating)`. No validation. A placeholder until +VerifiedRatings is wired. + +#### `pause()` / `unpause()` +OZ Pausable. While paused, `registerAgentCard`, `updateAgentCard` and `openJob` revert `EnforcedPause()`. Admin +functions, `setAgentCardActive` and every view stay live. + +#### `disableAgentCard(uint256 cardId)` +Permanently disables a card: `isAgentCardDisabled = true`, `active = false`, verified tag cleared. Reverts +`AgentCardInactive()` for an unknown card. Emits `AgentCardVerificationRevoked(cardId)` (only if it was verified), +then `AgentCardDisabled(cardId)`. Nothing re-enables it. `agentCardOf[provider]` is kept, so the provider cannot +register again. + +#### `verifyAgentCard(uint256 cardId, uint256 cardVersion)` +Sets the verified tag for the card's current version. + +| Revert | When | +|---|---| +| `AgentCardInactive()` | unknown card | +| `AgentCardDisabled(cardId)` | disabled card | +| `AgentCardVersionMismatch(cardVersion, current)` | `cardVersion` is not the current version, e.g. the card changed after review | + +Allowed for a card its provider switched off. Emits `AgentCardVerified(cardId, cardVersion)`. + +#### `revokeAgentCardVerification(uint256 cardId)` +Clears the tag. Reverts `AgentCardInactive()` for an unknown card. Idempotent: emits +`AgentCardVerificationRevoked(cardId)` only if the card was verified. + +### Card functions + +#### `registerAgentCard(AgentCard calldata c, bytes calldata rules, bytes calldata jobSpecTemplate) returns (uint256 cardId)` — `whenNotPaused` + +| Step | Effect | +|---|---| +| 1 | `AgentCardAlreadyRegistered(msg.sender)` if `agentCardOf[msg.sender] != 0`. | +| 2 | `_validateCard(c, rules)`: the 13 checks of README §4.2, in order. | +| 3 | `cardId = ++agentCardCount` (ids start at 1). | +| 4 | Stores the card, then overwrites `provider = msg.sender` and `active = true`. | +| 5 | Stores both blobs as given; `agentCardVersion = 1`; `agentCardOf[msg.sender] = cardId`. | +| 6 | Emits `AgentCardRegistered(cardId, msg.sender, jobType, chainNamespace, keccak256(rules), keccak256(jobSpecTemplate), metadataHash, providerFee)`. | + +`jobSpecTemplate` is **not** checked (§7.3). `rules` must decode as `AgentCardRules`; undecodable bytes revert +in `abi.decode` with no data. + +#### `updateAgentCard(uint256 cardId, AgentCard calldata c, bytes calldata rules, bytes calldata jobSpecTemplate)` — `whenNotPaused` + +| Step | Effect / revert | +|---|---| +| 1 | `CallerIsNotProvider()` unless the card exists and `msg.sender` is its provider. | +| 2 | `AgentCardDisabled(cardId)` if disabled. | +| 3 | `AgentCardIdentityImmutable()` if `c.chainNamespace` differs from the stored one. | +| 4 | `_validateCard(c, rules)`, as at registration. | +| 5 | Writes `jobType`, `metadataURI`, `metadataHash`, `providerFee`, `paymentToken`, `principalMin`, `principalMax`, `minDuration`, `maxDuration`, `minExecuteWindow`, `settleWindow`; replaces both blobs. `provider`, `chainNamespace` and `active` stay. | +| 6 | `version = ++agentCardVersion[cardId]`; clears the verified tag (emits `AgentCardVerificationRevoked` if there was one). | +| 7 | Emits `AgentCardUpdated(cardId, version, keccak256(rules), keccak256(jobSpecTemplate), metadataHash, providerFee)`. | + +Opened jobs are untouched (`test_ML12`). Intents signed against the previous version stop working (§4.3). + +#### `setAgentCardActive(uint256 cardId, bool active)` +Provider only (`CallerIsNotProvider()`, also for an unknown card). Switching on a disabled card reverts +`AgentCardDisabled(cardId)`; switching it off is allowed. Emits `AgentCardStatusChanged(cardId, active)`. Not +pausable. + +### openJob + +#### `openJob(OpenJobParams calldata p) returns (uint256 jobId, address agw, bytes32 rulesId)` — `whenNotPaused nonReentrant` + +Deploys the AGW if needed, grants it the card's rules and creates the job. The 16 steps, checks and errors are in +§8. Records `cardOfJob`, `agwOfJob`, `rulesOfJob`, `cardVersionOfJob` and the wallet's last job. Emits +`JobOpened(cardId, intent.owner, agw, jobId, rulesId, principal, cardVersion)`. + +`OpenJobParams`: + +| Field | Meaning | +|---|---| +| `cardId` | the card | +| `cardVersion` | the version the owner signed against; must equal the current version | +| `job` | `JobInputs{principal, expiredAt, executeBy, params}` | +| `session` | the rules (SmartSession `Session`) the owner signed, markers filled | +| `intent` | the owner-signed `OwnerIntent` (from `previewIntent`) | +| `sig` | the owner's signature over the intent | +| `label` | wallet label, used only when deploying a new wallet | + +Calls made, in order, after every check: `AGW_FACTORY.deployWalletWithSig` (new wallet) or +`AGW_FACTORY.ownerOf` (existing wallet); `AGW.grantRulesWithSig`; `KERNEL.jobCounter`; `AGW.executeWithSig`; +`KERNEL.jobCounter`; `KERNEL.getJob`. + +### Views + +| View | Returns | Notes | +|---|---|---| +| `getAgentCard(uint256 cardId)` | `AgentCardView{card, rules, jobSpecTemplate, version, verified, disabled}` | All zero for an unknown card. | +| `isAgentCardVerified(uint256 cardId)` | `bool` | Verified at the current version. | +| `isAgentCardDisabled(uint256 cardId)` | `bool` | | +| `agentCardVersion(uint256 cardId)` | `uint256` | 1 at registration, +1 per update, 0 if unknown. | +| `agentCardCount()` | `uint256` | The last card id. | +| `agentCardOf(address provider)` | `uint256` | The provider's card id; 0 for none. | +| `getAgentRating(address agent)` | `uint256` | 0 by default. | +| `activeJobOf(address agw)` | `uint256` | The AGW's last job opened here while it is Funded, Submitted, or Open with `block.timestamp < expiredAt`; else 0 (§10). | +| `cardOfJob(uint256 jobId)` / `agwOfJob` / `rulesOfJob` / `cardVersionOfJob` | card id / AGW / `rulesId` / card version | Recorded by `openJob`; zero for jobs not opened here. | +| `ceaDeployment(bytes32 chainHash)` | `(address ceaFactory, address ceaProxyImpl)` | Zero if unconfigured or cleared. | +| `computeCEA(address agw, bytes32 chainHash)` | `address` | The AGW's CEA on that chain (§9). Reverts `ChainNotSupported(chainHash)` if unconfigured. | +| `buildCreateJobCalldata(uint256 cardId, address owner, uint96 index, JobInputs job)` | `(bytes32 mode, bytes executionCalldata)` | Exactly what `openJob` executes for wallet `index` of `owner`. Reverts `AgentCardInactive()` for an unknown card, and like step 9 on a bad template or bad inputs. | +| `previewIntent(IntentRequest r, Session s)` | `OwnerIntent` | The intent to sign (§8). Nonces are read from the wallet, or 0 if not yet deployed. Reverts like `buildCreateJobCalldata`. | +| `AGW_FACTORY()`, `KERNEL()`, `RULES()` | addresses | Set once at `initialize`. | +| `PUSH_CHAIN_HASH()` | `bytes32` | `keccak256("eip155:" ‖ block.chainid)` at initialization. | +| `hook()`, `evaluator()` | addresses | Admin-settable. | +| `version()` | `string` | `"2.0.0"` (`pure`). | +| `hasRole`, `paused`, … | | OZ AccessControl and Pausable views. | + +`previewIntent` output: + +| Field | Value | +|---|---| +| `owner`, `index`, `deadline`, `signerChainId` | from the request | +| `wallet` | `AGW_FACTORY.predictWallet(owner, index)` | +| `executor` | the marketplace | +| `sessionHash` | `keccak256(abi.encode(session))` | +| `mode` | `MODE_SINGLE` (0) | +| `execCalldataHash` | `keccak256(buildCreateJobCalldata(...))` | +| `nonceKey` | `OPENJOB_LANE` | +| `nonceSeq` | `AGW.getNonce(OPENJOB_LANE)` if deployed, else 0 | +| `grantNonce` | `AGW.grantNonce()` if deployed, else 0 | + +Removed in v2: `setUniversalPaused`, `isUniversalPaused`, `isAGWFree`, the public `lastJobOf`, `expectedCEAOf`, +`startJob`, `registerCard`, `modifyAgentCard`, `setCardActive`, `adminDisableCard`, `getCard`, `isCardVerified`, +`isCardAdminDisabled`, `cardVersion`, `cardCount`, `TERMS`, `pushChainHash`, `STARTJOB_LANE`. + +### Constants + +| Constant | Value | Use | +|---|---|---| +| `ADMIN_ROLE` | `keccak256("ADMIN_ROLE")` | every admin function | +| `OPENJOB_LANE` | `OWNER_LANE_FLAG` (`1 << 191`, imported from AGW v6) | the AGW nonce lane `openJob`'s execution uses (owner lane, key 0) | +| `MODE_SINGLE` | `bytes32(0)` | ERC-7579 single call, default exec type | +| `MIN_DURATION` (internal) | `1 hours` | lower bound on a card's `minDuration` | +| `EVM_PREFIX` (internal) | `"eip155:"` | required prefix of a card's `chainNamespace` | + +### Storage layout + +Append-only from this layout. OZ upgradeable bases use ERC-7201 namespaced storage and occupy none of these +slots, so slot 0 is the marketplace's. Pinned by `test_MV09_storageLayout_bySlot`. + +| Slot | Variable | Type | +|---|---|---| +| 0 | `AGW_FACTORY` | `IAGWFactory` | +| 1 | `KERNEL` | `IAgenticCommerce` | +| 2 | `hook` | `address` | +| 3 | `evaluator` | `address` | +| 4 | `PUSH_CHAIN_HASH` | `bytes32` | +| 5 | `RULES` | `IUniversalMarketplaceRules` | +| 6 | `agentCardCount` | `uint256` | +| 7 | `_cards` | `mapping(uint256 => AgentCard)` | +| 8 | `_agentCardRules` | `mapping(uint256 => bytes)` | +| 9 | `_jobSpecTemplates` | `mapping(uint256 => bytes)` | +| 10 | `agentCardVersion` | `mapping(uint256 => uint256)` | +| 11 | `isAgentCardVerified` | `mapping(uint256 => bool)` | +| 12 | `isAgentCardDisabled` | `mapping(uint256 => bool)` | +| 13 | `ceaDeployment` | `mapping(bytes32 => CEADeployment)` | +| 14 | `__reserved14` | `uint256`, always 0 (was the per-chain pause) | +| 15 | `_lastJobOf` | `mapping(address => uint256)` | +| 16 | `cardOfJob` | `mapping(uint256 => uint256)` | +| 17 | `agwOfJob` | `mapping(uint256 => address)` | +| 18 | `rulesOfJob` | `mapping(uint256 => bytes32)` | +| 19 | `agentCardOf` | `mapping(address => uint256)` | +| 20 | `cardVersionOfJob` | `mapping(uint256 => uint256)` | +| 21 | `_agentRating` | `mapping(address => uint256)` | +| 22–48 | `__gap` | `uint256[27]` | + +--- + +## UniversalMarketplaceRules + +[`src/agentic-commerce-8183/UniversalMarketplaceRules.sol`](../../src/agentic-commerce-8183/UniversalMarketplaceRules.sol), +implementing [`IUniversalMarketplaceRules`](../../src/agentic-commerce-8183/interfaces/IUniversalMarketplaceRules.sol). +Stateless and `pure`, with no admin and no upgrade. Split out of the marketplace for EIP-170. Reverts with +`UniversalMarketplaceErrors`, so its reverts bubble through the marketplace unchanged. + +| Constant | Value | +|---|---| +| `MAX_ALLOWED_CALLS` | 32 (URP's allow-list bound; internal there, so mirrored) | +| `ERC20_TRANSFER` / `ERC20_APPROVE` / `ERC20_TRANSFER_FROM` | `IERC20.transfer/approve/transferFrom.selector` (`0xa9059cbb` / `0x095ea7b3` / `0x23b872dd`) | +| `ERC20_INCREASE_ALLOWANCE` | `bytes4(keccak256("increaseAllowance(address,uint256)"))` (`0x39509351`) | +| `MAX_ASSETS`, `MAX_PINS`, `MAX_ALLOWED_CALL_PINS`, `ENVELOPE_VERSION` | 8, 8, 32, 1 (imported from AGW v6 `Types.sol`) | +| `MARKER_WALLET`, `MARKER_PRINCIPAL` | imported from the package's `Types.sol` ([Markers](#markers)) | + +#### `validateAgentCardRules(bytes calldata rules) external pure returns (address[] memory tokens)` + +Decodes `AgentCardRules` with `abi.decode` (malformed bytes revert without data). Then runs the checks below **in +this order**, reverting `InvalidAgentCard(reason)`. Returns `tokens[i] = assets[i].token` for every asset. + +| # | Check | Reason | +|---|---|---| +| R1 | `1 <= assets.length <= MAX_ASSETS` | `"asset count"` | +| R2 | `principalAsset < assets.length` | `"principal asset"` | +| R3 | for each asset `i`: `token != address(0)` | `"asset zero"` | +| R4 | for each `i`, no `j < i` with the same token | `"duplicate asset"` | +| R5 | `assets[principalAsset].maxTotal == uint256(MARKER_PRINCIPAL)` | `"principal total not marker"` | +| R6 | `assets[principalAsset].maxPerCall != 0` (it is the marker or a fixed number > 0) | `"principal per-call zero"` | +| R7 | for each `i != principalAsset`: `maxPerCall != uint256(MARKER_PRINCIPAL)` and `maxTotal != uint256(MARKER_PRINCIPAL)` | `"marker off principal asset"` | +| R8 | `1 <= allowedCalls.length <= MAX_ALLOWED_CALLS` | `"allow-list size"` | +| R9 | for each call: `pins.length <= MAX_PINS`, and the sum over all calls `<= MAX_ALLOWED_CALL_PINS` | `"too many pins"` | +| R10 | for each pin: if `value == MARKER_WALLET` then `op == PinOp.EQ` | `"wallet marker op"` | +| R11 | for each call `i`, no `j < i` with byte-identical content (`keccak256(abi.encode(calls[i])) == keccak256(abi.encode(calls[j]))`) | `"duplicate call"` | +| R12 | for each call `i`, if some `j != i` has the same `(target, selector)`, then **both** have `pins.length > 0` (a pinless entry beside a pinned one makes the pins pointless, per the v6 docs) | `"unpinned duplicate"` | +| R13 | `selector == ERC20_INCREASE_ALLOWANCE` is refused | `"increaseAllowance"` | +| R14 | `selector == ERC20_APPROVE` requires a pin `{offset: 4, op: EQ, value: v}` where `v != 0`, `uint256(v) >> 160 == 0` (a clean address word), and `v` is not a marker | `"approve spender not pinned"` | +| R15 | `selector == ERC20_APPROVE` requires a pin `{offset: 36, op: MAX, value: w}` where `w` is `MARKER_PRINCIPAL` or any fixed value | `"approve amount not capped"` | +| R16 | `selector == ERC20_TRANSFER` requires the recipient (offset 4) pinned to the user's account: `hasBeneficiary && beneficiaryOffset == 4`, **or** a pin `{offset: 4, op: EQ, value: MARKER_WALLET}` | `"erc20 transfer recipient"` | +| R17 | `selector == ERC20_TRANSFER_FROM` likewise at offset 36 | `"erc20 transferFrom recipient"` | + +Implementation notes: each rule runs over every item before the next rule starts. R11/R12 compare across all +entries (O(n²), n ≤ 32). The required pins of R14–R17 may sit anywhere in `pins[]`; extra pins are allowed. R14's +"not a marker" holds through the clean-address-word test, because both markers have non-zero high 96 bits. +Known limit: whether a `MARKER_PRINCIPAL` pin sits on the **principal** token's `approve` is not checked (`IPRC20` +has no source-token view); the verified tag covers it. + +#### `checkRulesMatchCard(bytes calldata cardRules, Session calldata session, SessionContext calldata ctx) external pure` + +`ctx` is `SessionContext{agent, chainHash, principal, expiredAt, expectedCEA}`, filled by the marketplace from the +card, the job and `computeCEA`. Checks **in this order**; the first failure reverts: + +| # | Check | Error | +|---|---|---| +| C1 | `keccak256(session.sessionValidatorInitData) == keccak256(abi.encode(ctx.agent))` | `AgentMismatch()` | +| C2 | `session.actions.length == 1` | `ActionCount()` | +| C3 | `session.actions[0].actionPolicies.length == 1` | `PolicyShape(0)` | +| C4 | let `d = actionPolicies[0].initData`. Require `d.length >= 32` and `uint256(bytes32(d[0:32])) == ENVELOPE_VERSION`, **before any decode**. If `d.length < 32`, revert with actual `0` | `EnvelopeVersionMismatch(uint256 actual)` | +| C5 | `(, string chainNamespace, bytes body) = abi.decode(d, (uint16, string, bytes))`; `keccak256(bytes(chainNamespace)) == ctx.chainHash` | `ChainMismatch(0)` | +| C6 | `UniversalTerms t = abi.decode(body, (UniversalTerms))`; `AgentCardRules c = abi.decode(cardRules, (AgentCardRules))`; `t.assets.length == c.assets.length` | `AssetCountMismatch(c.assets.length, t.assets.length)` | +| C7 | for each `i`: `t.assets[i].token == c.assets[i].token` | `AssetMismatch(i)` | +| C8 | for `i == c.principalAsset`: `t.maxTotal == ctx.principal`; and `t.maxPerCall == ctx.principal` if `c.maxPerCall == uint256(MARKER_PRINCIPAL)`, else `t.maxPerCall == c.maxPerCall` | `PrincipalCapMismatch()` | +| C9 | for each `i != c.principalAsset`: `t.maxPerCall == c.maxPerCall && t.maxTotal == c.maxTotal` | `AssetMismatch(i)` | +| C10 | `t.maxGasPerCall == c.maxGasPerCall` | `GasCapMismatch()` | +| C11 | `t.allowedCalls.length == c.allowedCalls.length`; for each `i`: `target`, `selector`, `beneficiaryOffset`, `hasBeneficiary`, `maxValue` and `pins.length` equal; for each pin `k`: `offset` and `op` equal | `ActionsMismatch()` | +| C12 | for each pin `k` of call `i`: card `value == MARKER_WALLET` ⇒ session `value == bytes32(uint256(uint160(ctx.expectedCEA)))`; card `value == MARKER_PRINCIPAL` ⇒ session `value == bytes32(ctx.principal)`; otherwise session `value ==` card `value` | `PinMismatch(i, k)` | +| C13 | `t.validUntil == ctx.expiredAt` | `ExpiryMismatch()` | +| C14 | `t.expectedCEA == ctx.expectedCEA` | `ExpectedCEAMismatch(ctx.expectedCEA, t.expectedCEA)` | + +C11 and C12 share one loop: per call, the call fields; then per pin, offset and op, then value. Never compared: the +card's `principalAsset` (an index, not a rule), and the session's validator, policy address, action target and +selector, userOp and ERC-7739 lists, paymaster flag and salt — AGW v6 `_grantRules` pins all of them (README +§13.2). Malformed bytes after a correct version word, an undecodable body or undecodable card rules revert in +`abi.decode` without data (`test_MT10_malformedInputs`). + +--- + +## JobSpecBuilder + +[`src/agentic-commerce-8183/libraries/JobSpecBuilder.sol`](../../src/agentic-commerce-8183/libraries/JobSpecBuilder.sol). +An external library: deployed once, linked into the marketplace, called by `DELEGATECALL`. Inlined, it would put +the marketplace over the size limit. + +#### `build(bytes memory jobSpecTemplate, BuildContext memory ctx) public view returns (bytes memory)` +Returns `abi.encode(JobSpec)` for one job: the 8183 job's description. Algorithm and checks are in +[`criteria.md`](./criteria.md#building-a-jobspec). `logic` and `allowedMutability` are copied verbatim. + +`BuildContext{agw, principal, executeBy, settleWindow, params, origin}` comes from the job's inputs, the card's +`settleWindow`, and `origin = keccak256(abi.encode(marketplace, cardId, cardVersion, principal))`. + +The library reads CEAs with `IUniversalMarketplace(address(this)).computeCEA(agw, chainHash)`, with +`chainHash = keccak256(abi.encodePacked(read.chainNamespace, ":", read.chainId))`. Under `DELEGATECALL`, +`address(this)` is the marketplace proxy, so this is an external call back into the marketplace. Called directly +(not through the marketplace), a template that needs a CEA reverts, because the library would ask itself. It has +no storage. + +--- + +## RulesBindingHook (interim hook) + +[`src/agentic-commerce-8183/hooks/RulesBindingHook.sol`](../../src/agentic-commerce-8183/hooks/RulesBindingHook.sol), +on [`BaseERC8183Hook`](../../src/agentic-commerce-8183/hooks/BaseERC8183Hook.sol). Not part of the marketplace, +but every marketplace job is created with it until the V2 UniversalHook ships. Behind a +`TransparentUpgradeableProxy`; storage continues the base at slot 50. + +| Item | Behaviour | +|---|---| +| `initialize(address kernel, address agwFactory, address sessionEngine)` | All non-zero (`ERC8183HookErrors.ZeroAddress()`). Sets `KERNEL`, `AGW_FACTORY`, `SESSION_ENGINE`. | +| `beforeAction` / `afterAction` | Kernel only (`CallerIsNotKernel(caller)`). Acts only in `beforeAction(fund)`; every other action passes through. | +| `beforeAction(fund)` | In order: `fund.optParams` is exactly 32 bytes, `abi.encode(rulesId)` (`InvalidOptParams(length)`); the client is a factory AGW (`CallerIsNotAGW(caller)`); `SESSION_ENGINE.isPermissionEnabled(rulesId, client)` (`RulesNotLive(agw, rulesId)`); `activeJobOf(client) == 0` (`AGWHasLiveJob(agw, liveJobId)`). Then records the binding and the AGW's live job, and emits `RulesBound(jobId, agw, rulesId)`. | +| `rulesOfJob(uint256 jobId)` | The `rulesId` bound at `fund`, or zero. | +| `agwOfJob(uint256 jobId)` | The AGW bound at `fund`, or zero. | +| `activeJobOf(address agw)` | The AGW's last bound job while it is Funded or Submitted; else 0. Narrower than the marketplace's view (README §10). | + +Storage: 50 `AGW_FACTORY`, 51 `SESSION_ENGINE`, 52 `_bindingOf` (`mapping(uint256 => Binding{agw, rulesId})`), +53 `_liveJobOf` (`mapping(address => uint256)`), 54–103 `__gap[50]`. Because the hook runs in `beforeAction`, any +revert leaves the job Open with no escrow moved. A wallet is freed by reading the kernel's job status, so an +unhooked `claimRefund` frees it too. `optParams` stays exactly `abi.encode(rulesId)`. + +--- + +## Types + +All in [`libraries/Types.sol`](../../src/agentic-commerce-8183/libraries/Types.sol), file-level. The built +criteria (`JobSpec`, `Read`, `Check`, `Logic` and the enums) are in +[`libraries/JobSpecTypes.sol`](../../src/agentic-commerce-8183/libraries/JobSpecTypes.sol). The AGW types +(`OwnerIntent`, `AssetCap`, `AllowedCall`, `ArgPin`, `PinOp`, `UniversalTerms`) are imported from +`@push-agw/libraries/Types.sol`; the SmartSession `Session` and its parts are mirrored in +[`interfaces/external/IAGW.sol`](../../src/agentic-commerce-8183/interfaces/external/IAGW.sol). + +| Type | Fields | Notes | +|---|---|---| +| `AgentCard` | `provider`, `jobType`, `metadataURI`, `metadataHash`, `chainNamespace`, `providerFee`, `paymentToken`, `principalMin`, `principalMax`, `minDuration`, `maxDuration`, `minExecuteWindow`, `settleWindow`, `active` | `provider` and `active` are contract-written. `chainNamespace` is the full CAIP-2 string `"eip155:"`, immutable after registration. `providerFee` is in `paymentToken`, which must equal `KERNEL.paymentToken()`; principal is in the principal asset's units; durations and windows in seconds. | +| `AgentCardRules` | `assets` (`AssetCap[]`), `principalAsset` (uint8), `maxGasPerCall`, `allowedCalls` (`AllowedCall[]`) | `abi.encode`d into the card's `rules`. | +| `CEADeployment` | `ceaFactory`, `ceaProxyImpl` | Per destination chain. | +| `AgentCardView` | `card`, `rules`, `jobSpecTemplate`, `version`, `verified`, `disabled` | `getAgentCard`'s return. | +| `JobInputs` | `principal`, `expiredAt` (uint48), `executeBy` (uint48), `params` (int256[]) | Per-job inputs the owner signs. | +| `OpenJobParams` | `cardId`, `cardVersion`, `job`, `session`, `intent`, `sig`, `label` | `openJob`'s argument. | +| `IntentRequest` | `cardId`, `owner`, `index`, `job`, `deadline`, `signerChainId` | `previewIntent`'s argument. | +| `InitParams` | `agwFactory`, `kernel`, `hook`, `evaluator`, `rules`, `admin` | `initialize`'s argument. | +| `SessionContext` | `agent`, `chainHash`, `principal`, `expiredAt`, `expectedCEA` | The rules helper's per-job context. | +| `FillSource`, `Fill`, `ReadTemplate`, `TargetSource`, `CheckTemplate`, `ParamBounds`, `JobSpecTemplate`, `BuildContext` | | The criteria template; see [`criteria.md`](./criteria.md). `CheckTemplate` is `{read, evaluation, operation, source, value}`; `JobSpecTemplate` is `{reads, checks, logic, allowedMutability, params}`. | + +Deleted in v2: `Approval`, `RulesCardTerms`, `CardView`, `StartJobParams`, `EvaluationTemplate`, and the local +copies of `OwnerIntent`, `OWNER_LANE_FLAG`, `AllowedCall`, `UniversalTerms`. + +--- + +## Markers + +Published constants in [`libraries/Types.sol`](../../src/agentic-commerce-8183/libraries/Types.sol); the SDK uses +the same values. Pinned by `test_naming_markers`. + +| Constant | Value | Meaning in a card | +|---|---|---| +| `MARKER_WALLET` | `0x38beb8621ef19c2ac125b45b1ac07225511365301161eb56ac7a21aa8641cf5a` = `keccak256("push.marketplace.marker.WALLET")` | "the user's account (CEA) on the card's chain". EQ pins only (R10). | +| `MARKER_PRINCIPAL` | `0xc12ba2e9bfe16dd303c04d7f517245a6b49fd69f9d0e5c82d14be8c18ef34d52` = `keccak256("push.marketplace.marker.PRINCIPAL")` | "this job's principal". Pins (EQ or MAX) and the principal asset's caps, as `uint256`. | + +How each is filled is the table in README §6.1. Other constants: `ENVELOPE_VERSION` 1, `MAX_ASSETS` 8, `MAX_PINS` 8, +`MAX_ALLOWED_CALL_PINS` 32 (AGW `Types.sol`); `MAX_ALLOWED_CALLS` 32 (rules helper); `OPENJOB_LANE` +`OWNER_LANE_FLAG` (`1 << 191`); `version()` `"2.0.0"`. + +--- + +## Events + +Emitted by the marketplace (declared in `IUniversalMarketplace`, banner UM_1): + +| Event | Emitted by | +|---|---| +| `AgentCardRegistered(uint256 indexed cardId, address indexed provider, bytes32 indexed jobType, string chainNamespace, bytes32 rulesHash, bytes32 jobSpecHash, bytes32 metadataHash, uint256 providerFee)` | `registerAgentCard` | +| `AgentCardUpdated(uint256 indexed cardId, uint256 version, bytes32 rulesHash, bytes32 jobSpecHash, bytes32 metadataHash, uint256 providerFee)` | `updateAgentCard` | +| `AgentCardStatusChanged(uint256 indexed cardId, bool active)` | `setAgentCardActive` | +| `AgentCardDisabled(uint256 indexed cardId)` | `disableAgentCard` | +| `AgentCardVerified(uint256 indexed cardId, uint256 version)` | `verifyAgentCard` | +| `AgentCardVerificationRevoked(uint256 indexed cardId)` | `revokeAgentCardVerification`, `updateAgentCard`, `disableAgentCard` (only when a tag is cleared) | +| `AgentRatingSet(address indexed agent, uint256 rating)` | `setAgentRating` | +| `HookUpdated(address hook)` | `initialize`, `setHook` | +| `EvaluatorUpdated(address evaluator)` | `initialize`, `setEvaluator` | +| `CEADeploymentSet(bytes32 indexed chainHash, address ceaFactory, address ceaProxyImpl)` | `setCEADeployment` (both zero when clearing) | +| `JobOpened(uint256 indexed cardId, address indexed owner, address indexed agw, uint256 jobId, bytes32 rulesId, uint256 principal, uint256 cardVersion)` | `openJob` | + +`rulesHash = keccak256(rules)` and `jobSpecHash = keccak256(jobSpecTemplate)`, so an indexer can check the blobs +returned by `getAgentCard`. Removed: `UniversalChainPaused`. The hook emits +`RulesBound(uint256 indexed jobId, address indexed agw, bytes32 indexed rulesId)`. OZ emits `RoleGranted`, +`Paused`, `Unpaused`, `Initialized`. + +--- + +## Errors + +All marketplace, rules-helper and builder errors are in the `UniversalMarketplaceErrors` library +([`libraries/Errors.sol`](../../src/agentic-commerce-8183/libraries/Errors.sol)). A library error has the same +selector wherever it is raised, so a helper or builder revert bubbles through `openJob` unchanged. + +Each contract's ABI lists only the errors that contract itself raises. **Decode marketplace reverts with the +`UniversalMarketplaceErrors` artifact**, which lists all 40. + +| Error | Raised by | Status | +|---|---|---| +| `ZeroAddress()` | initialize, setters, `setCEADeployment` (one zero) | unchanged | +| `HookNotWhitelisted()` | `setHook` | unchanged | +| `AgentCardInactive()` | `openJob` step 1, `_requireCard` (unknown card in disable, verify, revoke, `buildCreateJobCalldata`, `previewIntent`) | was `CardInactive` | +| `CallerIsNotProvider()` | update, setActive (also for an unknown card) | unchanged | +| `AgentCardDisabled(uint256 cardId)` | update, setActive(on), verify | was `CardAdminDisabled` | +| `ChainNotSupported(bytes32 chainHash)` | register/update, `computeCEA` (so also `openJob` and the builder) | unchanged | +| `InvalidAgentCard(string reason)` | register/update, rules helper | was `InvalidCard` | +| `AgentCardVersionMismatch(uint256 provided, uint256 current)` | `openJob`, verify | was `CardVersionMismatch` | +| `AgentCardIdentityImmutable()` | update | was `CardIdentityImmutable` | +| `AgentCardAlreadyRegistered(address provider)` | register | **new** | +| `PrincipalOutOfRange()`, `ExpiryOutOfRange()`, `ExecuteByOutOfRange()`, `ProviderIsEvaluator()` | `openJob` | unchanged | +| `ParamCountMismatch(uint256 expected, uint256 actual)`, `ParamOutOfRange(uint256 index, int256 value)`, `TargetOverflow(uint256 check)`, `FillOutOfBounds(uint256 read, uint256 fill)` | builder | unchanged | +| `IntentWalletMismatch(address expected, address provided)`, `ExecutorMismatch(address expected, address actual)`, `IntentSessionMismatch(bytes32 actual)`, `IntentExecMismatch(bytes32 actualCalldataHash)`, `AGWMismatch(address expected, address actual)`, `WalletOwnerMismatch(address expected, address actual)` | `openJob` | unchanged | +| `WalletHasActiveJob(address agw, uint256 jobId)` | `openJob` step 8 | was `AGWBusy` | +| `AgentMismatch()`, `ActionCount()`, `PolicyShape(uint256 i)`, `ChainMismatch(uint256 i)`, `ActionsMismatch()`, `ExpiryMismatch()`, `ExpectedCEAMismatch(address expected, address actual)` | rules helper | unchanged | +| `EnvelopeVersionMismatch(uint256 actual)` | rules helper C4 | **new** | +| `AssetCountMismatch(uint256 expected, uint256 actual)` | rules helper C6 | **new** | +| `AssetMismatch(uint256 index)` | rules helper C7, C9 | **now carries the index** | +| `PrincipalCapMismatch()` | rules helper C8 | was `CapMismatch` | +| `GasCapMismatch()` | rules helper C10 | was `PCCapMismatch` | +| `PinMismatch(uint256 call, uint256 pin)` | rules helper C12 | **new** | +| `UnexpectedJobCount(uint256 before, uint256 afterCount)`, `JobMismatch()` | `openJob` step 15 | unchanged | +| ~~`ChainPaused(bytes32)`~~ | | **deleted** | + +`IntentSessionMismatch` and `IntentExecMismatch` carry the hash the marketplace expected (this session's hash, +this execution's calldata hash). + +### `InvalidAgentCard` reasons + +| Raised by | Reasons | +|---|---| +| marketplace | `"job type zero"`, `"metadata uri empty"`, `"metadata hash zero"`, `"chain namespace"`, `"payment token"` (new), `"provider is evaluator"`, `"principal range"`, `"duration range"`, `"settle window"`, `"execute window"`, `"asset"`, `"asset chain"` | +| rules helper | `"asset count"`, `"principal asset"`, `"asset zero"`, `"duplicate asset"`, `"principal total not marker"`, `"principal per-call zero"`, `"marker off principal asset"`, `"allow-list size"`, `"too many pins"`, `"wallet marker op"`, `"duplicate call"` (now identical entries only), `"unpinned duplicate"`, `"increaseAllowance"`, `"approve spender not pinned"`, `"approve amount not capped"`, `"erc20 transfer recipient"`, `"erc20 transferFrom recipient"` | +| deleted | `"erc20 approval"`, `"approval count"`, `"approval token"`, `"approval spender"`, `"approval cap"`, `"duplicate approval"` | + +### Hook errors + +Unchanged. + +| Library | Error | +|---|---| +| `RulesBindingHookErrors` | `InvalidOptParams(uint256 length)`, `CallerIsNotAGW(address caller)`, `RulesNotLive(address agw, bytes32 rulesId)`, `AGWHasLiveJob(address agw, uint256 liveJobId)` | +| `ERC8183HookErrors` | `CallerIsNotKernel(address caller)`, `ZeroAddress()` | diff --git a/plan/marketplace/contracts/foundry.toml b/plan/marketplace/contracts/foundry.toml new file mode 100644 index 00000000..1f9721f6 --- /dev/null +++ b/plan/marketplace/contracts/foundry.toml @@ -0,0 +1,46 @@ +[profile.default] +src = "src" +out = "out" +libs = ["lib"] +ffi = true +ast = true +build_info = true +extra_output = ["storageLayout"] + +# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options +# Solidity & EVM Specific Configs +solc = "0.8.26" +optimizer = true +optimizer_runs = 99999 +auto_detect_solc = false +evm_version = "shanghai" +via_ir = true +# UniversalMarketplace only: at 99 999 runs the inliner puts it over EIP-170 (26,257 B); at 1 000 runs it is +# 21,284 B. Every other contract keeps the default. +additional_compiler_profiles = [{ name = "marketplace-size", optimizer_runs = 1000 }] +compilation_restrictions = [{ paths = "src/agentic-commerce-8183/UniversalMarketplace.sol", optimizer_runs = 1000 }] + +no_match_coverage = "(PRC20V0\\.sol|testnetV0/UniversalCore\\.sol|ReceiverExample\\.sol|src/(libraries|[Ii]nterfaces|mocks)/|test/)" + +fs_permissions = [{ access = "read-write", path = "deployments/" }, { access = "read", path = "out/" }] + +# Coverage only: drop the per-file profile above. With it, a contract tested both from the marketplace's +# compile job and from its own is two artifacts, and coverage keeps the hits of only one. Run coverage with +# FOUNDRY_PROFILE=coverage; sizes are never measured under coverage. +[profile.coverage] +additional_compiler_profiles = [] +compilation_restrictions = [] + +[fmt] +ignore = ["src/**"] + +[fuzz] +runs = 1024 +max_test_rejects = 65536 +seed = '0x1' + +[profile.ci.fuzz] +runs = 4096 + +[rpc_endpoints] +push_chain_testnet = "${PUSH_CHAIN_TESTNET_RPC_URL}" \ No newline at end of file diff --git a/plan/marketplace/contracts/remappings.txt b/plan/marketplace/contracts/remappings.txt new file mode 100644 index 00000000..89c270a0 --- /dev/null +++ b/plan/marketplace/contracts/remappings.txt @@ -0,0 +1,3 @@ +@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/ +@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/ +@push-agw/=lib/push-agentic-wallets/src/ diff --git a/plan/marketplace/contracts/scripts/agentic-commerce-8183/DeployUniversalMarketplace.s.sol b/plan/marketplace/contracts/scripts/agentic-commerce-8183/DeployUniversalMarketplace.s.sol new file mode 100644 index 00000000..e31de845 --- /dev/null +++ b/plan/marketplace/contracts/scripts/agentic-commerce-8183/DeployUniversalMarketplace.s.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import {Script, console} from "forge-std/Script.sol"; +import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; + +import {AgenticCommerce} from "../../src/agentic-commerce-8183/AgenticCommerce.sol"; +import {UniversalMarketplace} from "../../src/agentic-commerce-8183/UniversalMarketplace.sol"; +import {UniversalMarketplaceRules} from "../../src/agentic-commerce-8183/UniversalMarketplaceRules.sol"; +import {RulesBindingHook} from "../../src/agentic-commerce-8183/hooks/RulesBindingHook.sol"; +import {InitParams} from "../../src/agentic-commerce-8183/libraries/Types.sol"; + +/// @title DeployUniversalMarketplace +/// @notice Deploys the self-contained UniversalMarketplace stack on Push Donut, bound to AGW v6: +/// kernel (AgenticCommerce, pUSDC) → RulesBindingHook (whitelisted) → UniversalMarketplaceRules → +/// UniversalMarketplace, then registers the CEA deployment of each supported chain. +/// @dev - The broadcaster is the kernel and marketplace admin, the owner of every ProxyAdmin, and the +/// marketplace-wide evaluator (an EOA that completes or rejects jobs by hand) until the real evaluator +/// is wired with `setEvaluator`. +/// - Fees stay zero (the kernel's default). +/// - Env: DEPLOYER_KEY (broadcaster), TREASURE_KEY (its address becomes the kernel's platform treasury). +/// - Run: forge script scripts/agentic-commerce-8183/DeployUniversalMarketplace.s.sol \ +/// --rpc-url $PUSH_CHAIN_TESTNET_RPC_URL --broadcast +contract DeployUniversalMarketplace is Script { + address internal constant PUSDC = 0x7A58048036206bB898008b5bBDA85697DB1e5d66; // USDC.eth (Sepolia) + address internal constant AGW_V6_FACTORY = 0xFBBEB6a365178fAaA81A9789a5f64b300c37e5bc; + address internal constant AGW_V6_SESSION_ENGINE = 0xf63DC0628fe1B25049FE3E3a3585Ef051CB98c1d; + uint256 internal constant DONUT_CHAIN_ID = 42101; + + struct CEAChain { + string namespace; + address ceaFactory; + address ceaProxyImpl; + } + + struct Deployed { + address kernel; + address hook; + address rules; + address marketplace; + } + + function run() external returns (Deployed memory d) { + require(block.chainid == DONUT_CHAIN_ID, "not Push Donut"); + uint256 key = _envKey("DEPLOYER_KEY"); + address me = vm.addr(key); + address treasury = vm.addr(_envKey("TREASURE_KEY")); + + vm.startBroadcast(key); + d.kernel = _proxy( + address(new AgenticCommerce()), me, abi.encodeCall(AgenticCommerce.initialize, (PUSDC, treasury, me)) + ); + d.hook = _proxy( + address(new RulesBindingHook()), + me, + abi.encodeCall(RulesBindingHook.initialize, (d.kernel, AGW_V6_FACTORY, AGW_V6_SESSION_ENGINE)) + ); + AgenticCommerce(d.kernel).setHookWhitelist(d.hook, true); + d.rules = address(new UniversalMarketplaceRules()); + + InitParams memory ip = InitParams({ + agwFactory: AGW_V6_FACTORY, kernel: d.kernel, hook: d.hook, evaluator: me, rules: d.rules, admin: me + }); + d.marketplace = + _proxy(address(new UniversalMarketplace()), me, abi.encodeCall(UniversalMarketplace.initialize, (ip))); + + CEAChain[] memory chains = _ceaChains(); + for (uint256 i; i < chains.length; ++i) { + UniversalMarketplace(d.marketplace).setCEADeployment( + keccak256(bytes(chains[i].namespace)), chains[i].ceaFactory, chains[i].ceaProxyImpl + ); + } + vm.stopBroadcast(); + + _log(d, me, treasury); + } + + /// @dev Accepts a private key with or without the 0x prefix. + function _envKey(string memory name) internal view returns (uint256) { + string memory raw = vm.envString(name); + if (bytes(raw).length == 64) raw = string.concat("0x", raw); + return vm.parseUint(raw); + } + + function _proxy(address impl, address proxyAdminOwner, bytes memory init) internal returns (address) { + return address(new TransparentUpgradeableProxy(impl, proxyAdminOwner, init)); + } + + /// @dev Live factories (gateway-testnet / core-testnet address docs); each proxy impl read from the factory's + /// `CEA_PROXY_IMPLEMENTATION()` on 2026-10-20. + function _ceaChains() internal pure returns (CEAChain[] memory c) { + c = new CEAChain[](4); + c[0] = CEAChain( + "eip155:11155111", 0x8ED594A83301FEc545fC6c19fc12cF7111777029, 0x0a4F7be62B56830070266be81114edB93e68DA09 + ); + c[1] = CEAChain( + "eip155:84532", 0x0A75ca7736b488Eb41675ADc3b3156BACF659F55, 0x6c9Cfef12155bEE91ecD6d0C8f516cABA2890656 + ); + c[2] = CEAChain( + "eip155:421614", 0x88DC189275078Cf509E4Cc773F089c8ad07b7EA2, 0x512d1B8C185a0Fd533a69f8973A3DD6513233009 + ); + c[3] = CEAChain( + "eip155:97", 0x3f1B16e0B072d472951C4563d29d3da6a3EE3Ce8, 0x0ff5d8b7d9Ac3ee2Ad420e9b70Ed6Dc465f593e9 + ); + } + + function _log(Deployed memory d, address me, address treasury) internal pure { + console.log("admin / proxy admin owner / evaluator:", me); + console.log("treasury ", treasury); + console.log("kernel ", d.kernel); + console.log("hook ", d.hook); + console.log("rules ", d.rules); + console.log("marketplace", d.marketplace); + } +} diff --git a/plan/marketplace/contracts/src/agentic-commerce-8183/AgenticCommerce.sol b/plan/marketplace/contracts/src/agentic-commerce-8183/AgenticCommerce.sol new file mode 100644 index 00000000..6ccd50cd --- /dev/null +++ b/plan/marketplace/contracts/src/agentic-commerce-8183/AgenticCommerce.sol @@ -0,0 +1,376 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import {ERC165Checker} from "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {AccessControlUpgradeable} from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; +import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol"; +import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol"; + +import {IAgenticCommerce} from "./interfaces/IAgenticCommerce.sol"; +import {IERC8183Hook} from "./interfaces/IERC8183Hook.sol"; + +/// @title AgenticCommerce +/// @notice ERC-8183 job escrow kernel for Push Chain. +/// @dev - Base shape: Virtuals `AgenticCommerceV3`, changed by K-01…K-11 (PRD Appendix A). +/// - Deployed behind `TransparentUpgradeableProxy`; upgrades go through its `ProxyAdmin`. +/// - Single payment token, assumed standard ERC-20 (no fee-on-transfer, no rebasing). +/// - Hooked functions run: checks → beforeAction → effects → transfers → events → afterAction +/// (`complete` interleaves each fee transfer with its event, per PRD §4.1.6). +contract AgenticCommerce is + Initializable, + AccessControlUpgradeable, + PausableUpgradeable, + ReentrancyGuardUpgradeable, + IAgenticCommerce +{ + using SafeERC20 for IERC20; + + /// @inheritdoc IAgenticCommerce + bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE"); + /// @inheritdoc IAgenticCommerce + uint256 public constant EVALUATOR_GRACE_PERIOD = 1 hours; + /// @inheritdoc IAgenticCommerce + uint256 public constant MIN_EXPIRY_WINDOW = 5 minutes; + /// @inheritdoc IAgenticCommerce + uint256 public constant BPS_DENOMINATOR = 10_000; + + // ───────── storage — slots 0..57, append-only (PRD §4.1.4) ───────── + + /// @inheritdoc IAgenticCommerce + IERC20 public paymentToken; + /// @inheritdoc IAgenticCommerce + uint256 public platformFeeBP; + /// @inheritdoc IAgenticCommerce + address public platformTreasury; + /// @inheritdoc IAgenticCommerce + uint256 public evaluatorFeeBP; + /// @dev Read through `getJob`. + mapping(uint256 => Job) internal jobs; + /// @inheritdoc IAgenticCommerce + uint256 public jobCounter; + /// @inheritdoc IAgenticCommerce + mapping(address => bool) public whitelistedHooks; + /// @inheritdoc IAgenticCommerce + uint256 public totalEscrowed; + uint256[50] private __gap; + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + /// @notice Initialize the proxy. + /// @dev - Grants `DEFAULT_ADMIN_ROLE` and `ADMIN_ROLE` to `admin_`. + /// - Whitelists `address(0)` so hookless jobs are allowed. + /// - Fees start at 0. + /// @param paymentToken_ The single payment token. + /// @param treasury_ Platform fee recipient. + /// @param admin_ Admin of roles, fees, hooks and pause. + function initialize(address paymentToken_, address treasury_, address admin_) external initializer { + if (paymentToken_ == address(0) || treasury_ == address(0) || admin_ == address(0)) revert ZeroAddress(); + __AccessControl_init(); + __Pausable_init(); + __ReentrancyGuard_init(); + + paymentToken = IERC20(paymentToken_); + platformTreasury = treasury_; + _grantRole(DEFAULT_ADMIN_ROLE, admin_); + _grantRole(ADMIN_ROLE, admin_); + whitelistedHooks[address(0)] = true; + } + + // ═════════════════════════════════ admin ═════════════════════════════════ + + /// @inheritdoc IAgenticCommerce + /// @dev - `claimRefund` stays callable while paused (K-05). + function pause() external onlyRole(ADMIN_ROLE) { + _pause(); + } + + /// @inheritdoc IAgenticCommerce + function unpause() external onlyRole(ADMIN_ROLE) { + _unpause(); + } + + /// @inheritdoc IAgenticCommerce + function setPlatformFee(uint256 feeBP, address treasury) external onlyRole(ADMIN_ROLE) { + if (treasury == address(0)) revert ZeroAddress(); + if (feeBP + evaluatorFeeBP > BPS_DENOMINATOR) revert FeesTooHigh(); + platformFeeBP = feeBP; + platformTreasury = treasury; + emit PlatformFeeUpdated(feeBP, treasury); + } + + /// @inheritdoc IAgenticCommerce + function setEvaluatorFee(uint256 feeBP) external onlyRole(ADMIN_ROLE) { + if (feeBP + platformFeeBP > BPS_DENOMINATOR) revert FeesTooHigh(); + evaluatorFeeBP = feeBP; + emit EvaluatorFeeUpdated(feeBP); + } + + /// @inheritdoc IAgenticCommerce + /// @dev - Affects new jobs only; an existing job keeps calling its hook. + function setHookWhitelist(address hook, bool status) external onlyRole(ADMIN_ROLE) { + if (hook == address(0)) revert ZeroAddress(); + whitelistedHooks[hook] = status; + emit HookWhitelistUpdated(hook, status); + } + + /// @inheritdoc IAgenticCommerce + /// @dev - A detached job behaves as hookless from then on. + function batchDetachHook(uint256[] calldata jobIds) external onlyRole(ADMIN_ROLE) { + uint256 n = jobCounter; + for (uint256 i; i < jobIds.length; ++i) { + uint256 jobId = jobIds[i]; + if (jobId == 0 || jobId > n) revert InvalidJob(); + address oldHook = jobs[jobId].hook; + if (oldHook == address(0)) continue; + jobs[jobId].hook = address(0); + emit HookDetached(jobId, oldHook); + } + } + + /// @inheritdoc IAgenticCommerce + /// @dev - K-02: escrow is untouchable; only `balance − totalEscrowed` of the payment token is free. + /// - D-27: ERC-20 only; no native branch. + function emergencyWithdraw(address token, address to, uint256 amount) external onlyRole(ADMIN_ROLE) whenPaused { + if (token == address(0) || to == address(0)) revert ZeroAddress(); + if (token == address(paymentToken)) { + uint256 bal = paymentToken.balanceOf(address(this)); + uint256 available = bal > totalEscrowed ? bal - totalEscrowed : 0; + if (amount > available) revert InsufficientUnattributedBalance(amount, available); + } + IERC20(token).safeTransfer(to, amount); + emit EmergencyWithdraw(token, to, amount); + } + + // ═════════════════════════════════ lifecycle ═════════════════════════════════ + + /// @inheritdoc IAgenticCommerce + /// @dev - Not hooked (K-10). + /// - Evaluator must be non-zero (K-03); `evaluator == client` is allowed. + function createJob( + address provider, + address evaluator, + uint256 expiredAt, + string calldata description, + address hook + ) external whenNotPaused nonReentrant returns (uint256 jobId) { + if (evaluator == address(0)) revert ZeroAddress(); + if (expiredAt <= block.timestamp + MIN_EXPIRY_WINDOW || expiredAt > type(uint48).max) { + revert ExpiryTooShort(); + } + if (provider == msg.sender) revert ClientIsProvider(); + if (provider != address(0) && provider == evaluator) revert EvaluatorIsProvider(); + if (!whitelistedHooks[hook]) revert HookNotWhitelisted(); + if (hook != address(0) && !ERC165Checker.supportsInterface(hook, type(IERC8183Hook).interfaceId)) { + revert InvalidHook(); + } + + jobId = ++jobCounter; + jobs[jobId] = Job({ + client: msg.sender, + status: JobStatus.Open, + provider: provider, + // forge-lint: disable-next-line(unsafe-typecast) + expiredAt: uint48(expiredAt), // safe: bounded by the type(uint48).max check above + evaluator: evaluator, + hook: hook, + budget: 0, + description: description + }); + emit JobCreated(jobId, msg.sender, provider, evaluator, expiredAt, hook); + } + + /// @inheritdoc IAgenticCommerce + /// @dev - Hooked, with `optParams` (K-04). + function setProvider(uint256 jobId, address provider, bytes calldata optParams) + external + whenNotPaused + nonReentrant + { + Job storage job = _job(jobId); + if (job.status != JobStatus.Open) revert WrongStatus(); + if (block.timestamp >= job.expiredAt) revert WrongStatus(); + if (msg.sender != job.client) revert Unauthorized(); + if (job.provider != address(0)) revert WrongStatus(); + if (provider == address(0)) revert ZeroAddress(); + if (provider == job.client) revert ClientIsProvider(); + if (provider == job.evaluator) revert EvaluatorIsProvider(); + + bytes memory data = abi.encode(msg.sender, provider, optParams); + _beforeHook(job.hook, jobId, data); + job.provider = provider; + emit ProviderSet(jobId, provider); + _afterHook(job.hook, jobId, data); + } + + /// @inheritdoc IAgenticCommerce + /// @dev - Re-callable while Open; `fund`'s `expectedBudget` guards against re-quotes. + function setBudget(uint256 jobId, uint256 amount, bytes calldata optParams) external whenNotPaused nonReentrant { + Job storage job = _job(jobId); + if (job.status != JobStatus.Open) revert WrongStatus(); + if (block.timestamp >= job.expiredAt) revert WrongStatus(); + if (msg.sender != job.provider) revert Unauthorized(); + + bytes memory data = abi.encode(msg.sender, amount, optParams); + _beforeHook(job.hook, jobId, data); + job.budget = amount; + emit BudgetSet(jobId, amount); + _afterHook(job.hook, jobId, data); + } + + /// @inheritdoc IAgenticCommerce + /// @dev - Adds `budget` to `totalEscrowed`. + /// - A zero budget moves to Funded without a transfer. + function fund(uint256 jobId, uint256 expectedBudget, bytes calldata optParams) + external + whenNotPaused + nonReentrant + { + Job storage job = _job(jobId); + if (job.status != JobStatus.Open) revert WrongStatus(); + if (msg.sender != job.client) revert Unauthorized(); + if (job.provider == address(0)) revert ProviderNotSet(); + if (block.timestamp >= job.expiredAt) revert WrongStatus(); + if (job.budget != expectedBudget) revert BudgetMismatch(); + + bytes memory data = abi.encode(msg.sender, optParams); + _beforeHook(job.hook, jobId, data); + uint256 budget = job.budget; + job.status = JobStatus.Funded; + totalEscrowed += budget; + if (budget > 0) paymentToken.safeTransferFrom(msg.sender, address(this), budget); + emit JobFunded(jobId, msg.sender, budget); + _afterHook(job.hook, jobId, data); + } + + /// @inheritdoc IAgenticCommerce + /// @dev - Funded only (K-11); no auto-complete (K-03). + function submit(uint256 jobId, bytes32 deliverable, bytes calldata optParams) external whenNotPaused nonReentrant { + Job storage job = _job(jobId); + if (job.status != JobStatus.Funded) revert WrongStatus(); + if (block.timestamp >= job.expiredAt) revert WrongStatus(); + if (msg.sender != job.provider) revert Unauthorized(); + + bytes memory data = abi.encode(msg.sender, deliverable, optParams); + _beforeHook(job.hook, jobId, data); + job.status = JobStatus.Submitted; + emit JobSubmitted(jobId, msg.sender, deliverable); + _afterHook(job.hook, jobId, data); + } + + /// @inheritdoc IAgenticCommerce + /// @dev - Allowed after `expiredAt`; races `claimRefund` once the grace window ends. + /// - Event order is normative: PlatformFeePaid → EvaluatorFeePaid → JobCompleted → PaymentReleased. + function complete(uint256 jobId, bytes32 reason, bytes calldata optParams) external whenNotPaused nonReentrant { + Job storage job = _job(jobId); + if (job.status != JobStatus.Submitted) revert WrongStatus(); + if (msg.sender != job.evaluator) revert Unauthorized(); + + bytes memory data = abi.encode(msg.sender, reason, optParams); + _beforeHook(job.hook, jobId, data); + + uint256 budget = job.budget; + job.status = JobStatus.Completed; + totalEscrowed -= budget; + + uint256 platformFee = (budget * platformFeeBP) / BPS_DENOMINATOR; + uint256 evalFee = (budget * evaluatorFeeBP) / BPS_DENOMINATOR; + uint256 net = budget - platformFee - evalFee; + address provider = job.provider; + + if (platformFee > 0) { + address treasury = platformTreasury; + paymentToken.safeTransfer(treasury, platformFee); + emit PlatformFeePaid(jobId, treasury, platformFee); + } + if (evalFee > 0) { + // msg.sender is the evaluator (checked above). + paymentToken.safeTransfer(msg.sender, evalFee); + emit EvaluatorFeePaid(jobId, msg.sender, evalFee); + } + if (net > 0) paymentToken.safeTransfer(provider, net); + emit JobCompleted(jobId, msg.sender, reason); + emit PaymentReleased(jobId, provider, net); + + _afterHook(job.hook, jobId, data); + } + + /// @inheritdoc IAgenticCommerce + /// @dev - Open: client or provider. Funded/Submitted: evaluator only. + function reject(uint256 jobId, bytes32 reason, bytes calldata optParams) external whenNotPaused nonReentrant { + Job storage job = _job(jobId); + JobStatus prev = job.status; + if (prev == JobStatus.Open) { + if (msg.sender != job.client && msg.sender != job.provider) revert Unauthorized(); + } else if (prev == JobStatus.Funded || prev == JobStatus.Submitted) { + if (msg.sender != job.evaluator) revert Unauthorized(); + } else { + revert WrongStatus(); + } + + bytes memory data = abi.encode(msg.sender, reason, optParams); + _beforeHook(job.hook, jobId, data); + job.status = JobStatus.Rejected; + if (prev != JobStatus.Open) _refund(jobId, job); + emit JobRejected(jobId, msg.sender, reason); + _afterHook(job.hook, jobId, data); + } + + /// @inheritdoc IAgenticCommerce + /// @dev - Not pausable (K-05): refunds must never be blockable. + /// - Not hooked: a broken hook cannot trap funds. + /// - Submitted jobs wait `EVALUATOR_GRACE_PERIOD` after expiry (K-06). + function claimRefund(uint256 jobId) external nonReentrant { + Job storage job = _job(jobId); + JobStatus prev = job.status; + if (prev != JobStatus.Open && prev != JobStatus.Funded && prev != JobStatus.Submitted) revert WrongStatus(); + if (prev == JobStatus.Submitted) { + if (block.timestamp < uint256(job.expiredAt) + EVALUATOR_GRACE_PERIOD) revert GracePeriodActive(); + } else if (block.timestamp < job.expiredAt) { + revert WrongStatus(); + } + + job.status = JobStatus.Expired; + if (prev != JobStatus.Open) _refund(jobId, job); + emit JobExpired(jobId); + } + + // ═════════════════════════════════ views ═════════════════════════════════ + + /// @inheritdoc IAgenticCommerce + function getJob(uint256 jobId) external view returns (Job memory) { + return jobs[jobId]; + } + + // ═════════════════════════════════ internal ═════════════════════════════════ + + /// @dev Loads a job; reverts `InvalidJob` for 0 or unknown ids. + function _job(uint256 jobId) internal view returns (Job storage) { + if (jobId == 0 || jobId > jobCounter) revert InvalidJob(); + return jobs[jobId]; + } + + /// @dev Returns a Funded/Submitted job's escrow to the client and releases it from `totalEscrowed`. + function _refund(uint256 jobId, Job storage job) internal { + uint256 budget = job.budget; + if (budget == 0) return; + totalEscrowed -= budget; + paymentToken.safeTransfer(job.client, budget); + emit Refunded(jobId, job.client, budget); + } + + /// @dev Calls `beforeAction` with the current function's selector; no-op without a hook. + function _beforeHook(address hook, uint256 jobId, bytes memory data) internal { + if (hook != address(0)) IERC8183Hook(hook).beforeAction(jobId, msg.sig, data); + } + + /// @dev Calls `afterAction` with the current function's selector; no-op without a hook. + function _afterHook(address hook, uint256 jobId, bytes memory data) internal { + if (hook != address(0)) IERC8183Hook(hook).afterAction(jobId, msg.sig, data); + } +} diff --git a/plan/marketplace/contracts/src/agentic-commerce-8183/UniversalMarketplace.sol b/plan/marketplace/contracts/src/agentic-commerce-8183/UniversalMarketplace.sol new file mode 100644 index 00000000..3440649e --- /dev/null +++ b/plan/marketplace/contracts/src/agentic-commerce-8183/UniversalMarketplace.sol @@ -0,0 +1,603 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol"; +import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {AccessControlUpgradeable} from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; +import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol"; +import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol"; + +import {OwnerIntent, OWNER_LANE_FLAG} from "@push-agw/libraries/Types.sol"; +import {IPRC20} from "../Interfaces/IPRC20.sol"; +import {IUniversalMarketplace} from "./interfaces/IUniversalMarketplace.sol"; +import {UniversalMarketplaceErrors} from "./libraries/Errors.sol"; +import { + AgentCard, + AgentCardView, + CEADeployment, + JobInputs, + OpenJobParams, + IntentRequest, + InitParams, + SessionContext, + BuildContext +} from "./libraries/Types.sol"; +import {IAgenticCommerce} from "./interfaces/IAgenticCommerce.sol"; +import {IUniversalMarketplaceRules} from "./interfaces/IUniversalMarketplaceRules.sol"; +import {JobSpecBuilder} from "./libraries/JobSpecBuilder.sol"; +import {IAGWFactory} from "./interfaces/external/IAGWFactory.sol"; +import {IAGW, Session} from "./interfaces/external/IAGW.sol"; + +/// @title UniversalMarketplace +/// @notice Agent cards, and `openJob`: one relayed call that, on one owner-signed OwnerIntent, deploys the +/// user's AGW if needed, grants it the card's rules, and creates the ERC-8183 job with the AGW as client. +/// @dev - Moves no funds. Wallet funding and 8183 `setBudget` / `fund` happen elsewhere. +/// - Never owns anything: it presents the owner's intent to the factory and wallet, which verify the +/// signature themselves and accept it only from the intent's `executor` (this contract). +/// - Rules = card: the owner signs a session they cannot read, so this contract proves it is the card's, with +/// the card's markers filled for this job. Card ⊆ job: the job's criteria are BUILT here (JobSpecBuilder) from +/// the card's stored `jobSpecTemplate`, never supplied. The template itself is not judged: whether the +/// evaluator can run it is the provider's responsibility, reviewed through the verified tag. +/// - The card's content lives on-chain. The rules side is checked by `RULES`, a stateless helper split out +/// for EIP-170. +/// - One card per provider. +/// - Deployed behind `TransparentUpgradeableProxy`. Storage is append-only from this layout. +contract UniversalMarketplace is + Initializable, + AccessControlUpgradeable, + PausableUpgradeable, + ReentrancyGuardUpgradeable, + IUniversalMarketplace +{ + bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE"); + /// @notice The owner lane `openJob` executes `createJob` on (owner lane, key 0). + uint192 public constant OPENJOB_LANE = OWNER_LANE_FLAG; + /// @notice ERC-7579 single call, default exec type: all four mode components are zero. + bytes32 public constant MODE_SINGLE = bytes32(0); + + uint32 internal constant MIN_DURATION = 1 hours; + bytes7 internal constant EVM_PREFIX = "eip155:"; + + // ───────── storage: append-only ───────── + + IAGWFactory public AGW_FACTORY; + IAgenticCommerce public KERNEL; + address public hook; + /// @notice The 8183 evaluator of every job opened here. + address public evaluator; + /// @notice keccak256("eip155:" ‖ decimal(block.chainid)): Push itself, which no card may name. + bytes32 public PUSH_CHAIN_HASH; + IUniversalMarketplaceRules public RULES; + uint256 public agentCardCount; + mapping(uint256 => AgentCard) internal _cards; + mapping(uint256 => bytes) internal _agentCardRules; + mapping(uint256 => bytes) internal _jobSpecTemplates; + /// @notice 1 at registration, +1 per update. Bound into the job's criteria (`origin`). + mapping(uint256 => uint256) public agentCardVersion; + /// @notice Verified by the admin at the CURRENT version. Cleared by every update. + mapping(uint256 => bool) public isAgentCardVerified; + /// @notice Disabled by the admin. Permanent: the provider cannot reactivate the card. + mapping(uint256 => bool) public isAgentCardDisabled; + mapping(bytes32 => CEADeployment) public ceaDeployment; + /// @dev Slot 14: the removed per-chain pause. Reserved, always zero. + uint256 private __reserved14; + /// @dev AGW → the last job opened here for it. Read through `activeJobOf`. + mapping(address => uint256) internal _lastJobOf; + mapping(uint256 => uint256) public cardOfJob; + mapping(uint256 => address) public agwOfJob; + mapping(uint256 => bytes32) public rulesOfJob; + /// @notice Provider → their card id; 0 for none. Never cleared, so a disabled provider cannot register again. + mapping(address => uint256) public agentCardOf; + mapping(uint256 => uint256) public cardVersionOfJob; + mapping(address => uint256) internal _agentRating; + uint256[27] private __gap; + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + /// @notice Initialize the proxy. + /// @param p The addresses; every one non-zero, and `p.hook` whitelisted on the kernel. + function initialize(InitParams calldata p) external initializer { + if (p.agwFactory == address(0) || p.kernel == address(0) || p.rules == address(0) || p.admin == address(0)) { + revert UniversalMarketplaceErrors.ZeroAddress(); + } + __AccessControl_init(); + __Pausable_init(); + __ReentrancyGuard_init(); + + AGW_FACTORY = IAGWFactory(p.agwFactory); + KERNEL = IAgenticCommerce(p.kernel); + RULES = IUniversalMarketplaceRules(p.rules); + PUSH_CHAIN_HASH = keccak256(abi.encodePacked("eip155:", Strings.toString(block.chainid))); + _setHook(p.hook); + _setEvaluator(p.evaluator); + _grantRole(DEFAULT_ADMIN_ROLE, p.admin); + _grantRole(ADMIN_ROLE, p.admin); + } + + // ═════════════════════════════════ admin ═════════════════════════════════ + + /// @inheritdoc IUniversalMarketplace + /// @dev Jobs keep the hook they were created with; new jobs get this one. + function setHook(address hook_) external onlyRole(ADMIN_ROLE) { + _setHook(hook_); + } + + /// @inheritdoc IUniversalMarketplace + /// @dev Not checked against providers: `openJob` refuses a card whose provider is the evaluator. + function setEvaluator(address evaluator_) external onlyRole(ADMIN_ROLE) { + _setEvaluator(evaluator_); + } + + /// @inheritdoc IUniversalMarketplace + /// @dev - The derived CEA is the `MARKER_WALLET` value and expected CEA of every rules grant on `chainHash`, and + /// the CEA the job's criteria read. The SDK derives it from the destination CEAFactory; `openJob` refuses + /// a mismatch. + /// - Both zero clears the chain: registration, update, `computeCEA` and `openJob` then revert + /// `ChainNotSupported`. Exactly one zero reverts `ZeroAddress`. + /// - Rotation runbook: `pause()` → rotate on the destination → this → `unpause()`. + function setCEADeployment(bytes32 chainHash, address ceaFactory, address ceaProxyImpl) + external + onlyRole(ADMIN_ROLE) + { + if (ceaFactory == address(0) && ceaProxyImpl == address(0)) { + delete ceaDeployment[chainHash]; + } else if (ceaFactory == address(0) || ceaProxyImpl == address(0)) { + revert UniversalMarketplaceErrors.ZeroAddress(); + } else { + ceaDeployment[chainHash] = CEADeployment({ceaFactory: ceaFactory, ceaProxyImpl: ceaProxyImpl}); + } + emit CEADeploymentSet(chainHash, ceaFactory, ceaProxyImpl); + } + + /// @inheritdoc IUniversalMarketplace + /// @dev Placeholder until VerifiedRatings is wired (page 2 M12). + function setAgentRating(address agent, uint256 rating) external onlyRole(ADMIN_ROLE) { + _agentRating[agent] = rating; + emit AgentRatingSet(agent, rating); + } + + /// @inheritdoc IUniversalMarketplace + function pause() external onlyRole(ADMIN_ROLE) { + _pause(); + } + + /// @inheritdoc IUniversalMarketplace + function unpause() external onlyRole(ADMIN_ROLE) { + _unpause(); + } + + /// @inheritdoc IUniversalMarketplace + /// @dev The per-card kill switch. Permanent, so a compromised provider cannot switch it back on. Keeps + /// `agentCardOf[provider]`: one card per provider, so a disabled provider cannot register again. + function disableAgentCard(uint256 cardId) external onlyRole(ADMIN_ROLE) { + _requireCard(cardId); + isAgentCardDisabled[cardId] = true; + _cards[cardId].active = false; + _clearVerified(cardId); + emit AgentCardDisabled(cardId); + } + + /// @inheritdoc IUniversalMarketplace + /// @dev - A tag, not a gate: `openJob` treats verified and unverified cards alike. + /// - `cardVersion` is the one the admin reviewed: an update in between makes this revert. + /// - Refused for a disabled card; allowed for one its provider switched off. + function verifyAgentCard(uint256 cardId, uint256 cardVersion) external onlyRole(ADMIN_ROLE) { + _requireCard(cardId); + if (isAgentCardDisabled[cardId]) revert UniversalMarketplaceErrors.AgentCardDisabled(cardId); + uint256 current = agentCardVersion[cardId]; + if (cardVersion != current) revert UniversalMarketplaceErrors.AgentCardVersionMismatch(cardVersion, current); + isAgentCardVerified[cardId] = true; + emit AgentCardVerified(cardId, cardVersion); + } + + /// @inheritdoc IUniversalMarketplace + function revokeAgentCardVerification(uint256 cardId) external onlyRole(ADMIN_ROLE) { + _requireCard(cardId); + _clearVerified(cardId); + } + + // ═════════════════════════════════ cards ═════════════════════════════════ + + /// @inheritdoc IUniversalMarketplace + function registerAgentCard(AgentCard calldata c, bytes calldata rules, bytes calldata jobSpecTemplate) + external + whenNotPaused + returns (uint256 cardId) + { + if (agentCardOf[msg.sender] != 0) revert UniversalMarketplaceErrors.AgentCardAlreadyRegistered(msg.sender); + _validateCard(c, rules); + + cardId = ++agentCardCount; + _cards[cardId] = c; + AgentCard storage stored = _cards[cardId]; + stored.provider = msg.sender; + stored.active = true; + _agentCardRules[cardId] = rules; + _jobSpecTemplates[cardId] = jobSpecTemplate; + agentCardVersion[cardId] = 1; + agentCardOf[msg.sender] = cardId; + + emit AgentCardRegistered( + cardId, + msg.sender, + c.jobType, + c.chainNamespace, + keccak256(rules), + keccak256(jobSpecTemplate), + c.metadataHash, + c.providerFee + ); + } + + /// @inheritdoc IUniversalMarketplace + /// @dev - Provider only; refused for a disabled card and while paused. + /// - `chainNamespace` identifies the card: another chain is another card. `provider` and `active` stay. + /// - The version is part of every job's criteria (`origin`), so an intent signed against the old + /// version fails `openJob`. Jobs already opened are untouched. + function updateAgentCard(uint256 cardId, AgentCard calldata c, bytes calldata rules, bytes calldata jobSpecTemplate) + external + whenNotPaused + { + AgentCard storage stored = _cards[cardId]; + if (stored.provider == address(0) || msg.sender != stored.provider) { + revert UniversalMarketplaceErrors.CallerIsNotProvider(); + } + if (isAgentCardDisabled[cardId]) revert UniversalMarketplaceErrors.AgentCardDisabled(cardId); + if (keccak256(bytes(c.chainNamespace)) != keccak256(bytes(stored.chainNamespace))) { + revert UniversalMarketplaceErrors.AgentCardIdentityImmutable(); + } + _validateCard(c, rules); + + stored.jobType = c.jobType; + stored.metadataURI = c.metadataURI; + stored.metadataHash = c.metadataHash; + stored.providerFee = c.providerFee; + stored.paymentToken = c.paymentToken; + stored.principalMin = c.principalMin; + stored.principalMax = c.principalMax; + stored.minDuration = c.minDuration; + stored.maxDuration = c.maxDuration; + stored.minExecuteWindow = c.minExecuteWindow; + stored.settleWindow = c.settleWindow; + _agentCardRules[cardId] = rules; + _jobSpecTemplates[cardId] = jobSpecTemplate; + + uint256 newVersion = ++agentCardVersion[cardId]; + _clearVerified(cardId); + + emit AgentCardUpdated( + cardId, newVersion, keccak256(rules), keccak256(jobSpecTemplate), c.metadataHash, c.providerFee + ); + } + + /// @inheritdoc IUniversalMarketplace + function setAgentCardActive(uint256 cardId, bool active) external { + AgentCard storage c = _cards[cardId]; + if (c.provider == address(0) || msg.sender != c.provider) { + revert UniversalMarketplaceErrors.CallerIsNotProvider(); + } + if (active && isAgentCardDisabled[cardId]) revert UniversalMarketplaceErrors.AgentCardDisabled(cardId); + c.active = active; + emit AgentCardStatusChanged(cardId, active); + } + + /// @inheritdoc IUniversalMarketplace + function getAgentCard(uint256 cardId) external view returns (AgentCardView memory v) { + v.card = _cards[cardId]; + v.rules = _agentCardRules[cardId]; + v.jobSpecTemplate = _jobSpecTemplates[cardId]; + v.version = agentCardVersion[cardId]; + v.verified = isAgentCardVerified[cardId]; + v.disabled = isAgentCardDisabled[cardId]; + } + + // ═════════════════════════════════ openJob ═════════════════════════════════ + + /// @inheritdoc IUniversalMarketplace + /// @dev Normative order, every check before the first state change: + /// 1-6 card, version, ranges, evaluator · 7 wallet · 8 no active job · 9-10 build the job · 11 bind the intent · + /// 12 rules = card · ── 13 deploy or check owner · 14 grant · 15 create, verified · 16 record. + function openJob(OpenJobParams calldata p) + external + whenNotPaused + nonReentrant + returns (uint256 jobId, address agw, bytes32 rulesId) + { + AgentCard storage c = _cards[p.cardId]; + bytes32 chainHash = _checkCardAndJob(c, p); + bool deployed; + (agw, deployed) = _resolveWallet(p); + uint256 active = activeJobOf(agw); + if (active != 0) revert UniversalMarketplaceErrors.WalletHasActiveJob(agw, active); + (bytes32 mode, bytes memory execCalldata) = _buildCreateJob(p.cardId, agw, p.job); + _bindIntent(p, mode, execCalldata); + _checkRules(c, p, agw, chainHash); + + _deployOrCheckOwner(p, agw, deployed); + rulesId = IAGW(agw).grantRulesWithSig(p.session, p.intent, p.sig); + jobId = _createJob(c, agw, mode, execCalldata, p.intent, p.sig); + + _lastJobOf[agw] = jobId; + cardOfJob[jobId] = p.cardId; + agwOfJob[jobId] = agw; + rulesOfJob[jobId] = rulesId; + cardVersionOfJob[jobId] = p.cardVersion; + emit JobOpened(p.cardId, p.intent.owner, agw, jobId, rulesId, p.job.principal, p.cardVersion); + } + + // ═════════════════════════════════ views ═════════════════════════════════ + + /// @inheritdoc IUniversalMarketplace + /// @dev Active while the last job opened here is Funded, Submitted, or Open and not yet expired. + function activeJobOf(address agw) public view returns (uint256) { + uint256 id = _lastJobOf[agw]; + if (id == 0) return 0; + IAgenticCommerce.Job memory j = KERNEL.getJob(id); + if (j.status == IAgenticCommerce.JobStatus.Funded || j.status == IAgenticCommerce.JobStatus.Submitted) { + return id; + } + if (j.status == IAgenticCommerce.JobStatus.Open && block.timestamp < j.expiredAt) return id; + return 0; + } + + /// @inheritdoc IUniversalMarketplace + /// @dev Mirrors `CEAFactory._computeCEAInternal`: an OZ minimal proxy of `ceaProxyImpl`, salt + /// `keccak256(abi.encode(pushAccount))`, deployer = the CEA factory. Stale after a destination + /// implementation rotation until `setCEADeployment`: pause first. + function computeCEA(address agw, bytes32 chainHash) public view returns (address) { + CEADeployment memory d = ceaDeployment[chainHash]; + if (d.ceaFactory == address(0)) revert UniversalMarketplaceErrors.ChainNotSupported(chainHash); + return Clones.predictDeterministicAddress(d.ceaProxyImpl, keccak256(abi.encode(agw)), d.ceaFactory); + } + + /// @inheritdoc IUniversalMarketplace + function getAgentRating(address agent) external view returns (uint256) { + return _agentRating[agent]; + } + + /// @inheritdoc IUniversalMarketplace + function version() external pure returns (string memory) { + return "2.0.0"; + } + + /// @inheritdoc IUniversalMarketplace + function buildCreateJobCalldata(uint256 cardId, address owner, uint96 index, JobInputs calldata job) + external + view + returns (bytes32 mode, bytes memory executionCalldata) + { + _requireCard(cardId); + (address agw,) = AGW_FACTORY.predictWallet(owner, index); + return _buildCreateJob(cardId, agw, job); + } + + /// @inheritdoc IUniversalMarketplace + /// @dev The SDK signs exactly what this returns. Nonces are 0 for a wallet not yet deployed. + function previewIntent(IntentRequest calldata r, Session calldata s) external view returns (OwnerIntent memory i) { + _requireCard(r.cardId); + (address wallet, bool deployed) = AGW_FACTORY.predictWallet(r.owner, r.index); + (bytes32 mode, bytes memory cd) = _buildCreateJob(r.cardId, wallet, r.job); + i.owner = r.owner; + i.wallet = wallet; + i.executor = address(this); + i.index = r.index; + i.sessionHash = keccak256(abi.encode(s)); + i.mode = mode; + i.execCalldataHash = keccak256(cd); + i.nonceKey = OPENJOB_LANE; + i.nonceSeq = deployed ? IAGW(wallet).getNonce(OPENJOB_LANE) : 0; + i.grantNonce = deployed ? IAGW(wallet).grantNonce() : 0; + i.deadline = r.deadline; + i.signerChainId = r.signerChainId; + } + + // ═════════════════════════════════ internal: config and cards ═════════════════════════════════ + + function _setHook(address hook_) internal { + if (hook_ == address(0)) revert UniversalMarketplaceErrors.ZeroAddress(); + if (!KERNEL.whitelistedHooks(hook_)) revert UniversalMarketplaceErrors.HookNotWhitelisted(); + hook = hook_; + emit HookUpdated(hook_); + } + + function _setEvaluator(address evaluator_) internal { + if (evaluator_ == address(0)) revert UniversalMarketplaceErrors.ZeroAddress(); + evaluator = evaluator_; + emit EvaluatorUpdated(evaluator_); + } + + /// @dev `AgentCardInactive` for a card that was never registered. + function _requireCard(uint256 cardId) internal view { + if (_cards[cardId].provider == address(0)) revert UniversalMarketplaceErrors.AgentCardInactive(); + } + + /// @dev Clears the verified tag, emitting only when there was one to clear. + function _clearVerified(uint256 cardId) internal { + if (!isAgentCardVerified[cardId]) return; + isAgentCardVerified[cardId] = false; + emit AgentCardVerificationRevoked(cardId); + } + + /// @dev Registration and update checks, in order. The caller is the provider. The `jobSpecTemplate` is stored + /// as given. + function _validateCard(AgentCard calldata c, bytes calldata rules) internal view { + if (c.jobType == bytes32(0)) revert UniversalMarketplaceErrors.InvalidAgentCard("job type zero"); + if (bytes(c.metadataURI).length == 0) revert UniversalMarketplaceErrors.InvalidAgentCard("metadata uri empty"); + if (c.metadataHash == bytes32(0)) revert UniversalMarketplaceErrors.InvalidAgentCard("metadata hash zero"); + bytes calldata ns = bytes(c.chainNamespace); + if (ns.length <= EVM_PREFIX.length || bytes7(ns[:7]) != EVM_PREFIX) { + revert UniversalMarketplaceErrors.InvalidAgentCard("chain namespace"); + } + bytes32 chainHash = keccak256(ns); + if (chainHash == PUSH_CHAIN_HASH || ceaDeployment[chainHash].ceaFactory == address(0)) { + revert UniversalMarketplaceErrors.ChainNotSupported(chainHash); + } + // Until the kernel's K-12, every job is paid in the kernel's token; a card may not advertise another. + if (c.paymentToken != address(KERNEL.paymentToken())) { + revert UniversalMarketplaceErrors.InvalidAgentCard("payment token"); + } + _validateWindows(c); + address[] memory tokens = RULES.validateAgentCardRules(rules); + for (uint256 i; i < tokens.length; ++i) { + _requireAssetOnChain(tokens[i], chainHash); + } + } + + /// @dev The provider is not the evaluator, and the principal and time windows are coherent. + function _validateWindows(AgentCard calldata c) internal view { + if (msg.sender == evaluator) revert UniversalMarketplaceErrors.InvalidAgentCard("provider is evaluator"); + if (c.principalMax == 0 || c.principalMin > c.principalMax) { + revert UniversalMarketplaceErrors.InvalidAgentCard("principal range"); + } + if (c.minDuration < MIN_DURATION || c.minDuration > c.maxDuration) { + revert UniversalMarketplaceErrors.InvalidAgentCard("duration range"); + } + if (c.settleWindow == 0) revert UniversalMarketplaceErrors.InvalidAgentCard("settle window"); + if (uint256(c.minExecuteWindow) + c.settleWindow > c.maxDuration) { + revert UniversalMarketplaceErrors.InvalidAgentCard("execute window"); + } + } + + /// @dev The asset is a PRC20 of the card's chain. A raw staticcall, not try/catch: a non-string answer must + /// fail as "asset", and a try clause cannot catch its own return-data decoding. A codeless asset answers + /// empty, so it fails the length check. + function _requireAssetOnChain(address asset, bytes32 chainHash) internal view { + (bool ok, bytes memory ret) = asset.staticcall(abi.encodeCall(IPRC20.SOURCE_CHAIN_NAMESPACE, ())); + if (!ok || ret.length < 64) revert UniversalMarketplaceErrors.InvalidAgentCard("asset"); + (uint256 offset, uint256 len) = abi.decode(ret, (uint256, uint256)); + if (offset != 32 || len > ret.length - 64) revert UniversalMarketplaceErrors.InvalidAgentCard("asset"); + if (keccak256(abi.decode(ret, (bytes))) != chainHash) { + revert UniversalMarketplaceErrors.InvalidAgentCard("asset chain"); + } + } + + // ═════════════════════════════════ internal: openJob ═════════════════════════════════ + + /// @dev Steps 1-6. Returns the card's chain hash. + function _checkCardAndJob(AgentCard storage c, OpenJobParams calldata p) internal view returns (bytes32) { + if (!c.active) revert UniversalMarketplaceErrors.AgentCardInactive(); + uint256 current = agentCardVersion[p.cardId]; + if (p.cardVersion != current) { + revert UniversalMarketplaceErrors.AgentCardVersionMismatch(p.cardVersion, current); + } + _checkJobWindows(c, p.job); + if (c.provider == evaluator) revert UniversalMarketplaceErrors.ProviderIsEvaluator(); + return keccak256(bytes(c.chainNamespace)); + } + + /// @dev Steps 3-5: principal, expiry and executeBy inside the card's windows. + function _checkJobWindows(AgentCard storage c, JobInputs calldata job) internal view { + if (job.principal < c.principalMin || job.principal > c.principalMax) { + revert UniversalMarketplaceErrors.PrincipalOutOfRange(); + } + uint256 expiredAt = job.expiredAt; + if (expiredAt < block.timestamp + c.minDuration || expiredAt > block.timestamp + c.maxDuration) { + revert UniversalMarketplaceErrors.ExpiryOutOfRange(); + } + uint256 executeBy = job.executeBy; + if (executeBy < block.timestamp + c.minExecuteWindow || executeBy + c.settleWindow > expiredAt) { + revert UniversalMarketplaceErrors.ExecuteByOutOfRange(); + } + } + + /// @dev Step 7: the intent names the wallet derived from its owner and index, and this executor. + function _resolveWallet(OpenJobParams calldata p) internal view returns (address agw, bool deployed) { + (agw, deployed) = AGW_FACTORY.predictWallet(p.intent.owner, p.intent.index); + if (p.intent.wallet != agw) revert UniversalMarketplaceErrors.IntentWalletMismatch(agw, p.intent.wallet); + if (p.intent.executor != address(this)) { + revert UniversalMarketplaceErrors.ExecutorMismatch(p.intent.executor, address(this)); + } + } + + /// @dev Steps 9-10: the job's criteria, built from the card's template, inside `createJob` as an ERC-7579 + /// single execution. Everything the owner signs per job (principal, times, params, card version and + /// the wallet, through its CEA) is in this calldata, so the intent's calldata hash binds all of it. + function _buildCreateJob(uint256 cardId, address agw, JobInputs calldata job) + internal + view + returns (bytes32 mode, bytes memory executionCalldata) + { + AgentCard storage c = _cards[cardId]; + bytes memory description = JobSpecBuilder.build( + _jobSpecTemplates[cardId], + BuildContext({ + agw: agw, + principal: job.principal, + executeBy: job.executeBy, + settleWindow: c.settleWindow, + params: job.params, + origin: keccak256(abi.encode(address(this), cardId, agentCardVersion[cardId], job.principal)) + }) + ); + bytes memory call = abi.encodeCall( + IAgenticCommerce.createJob, (c.provider, evaluator, uint256(job.expiredAt), string(description), hook) + ); + mode = MODE_SINGLE; + executionCalldata = abi.encodePacked(address(KERNEL), uint256(0), call); + } + + /// @dev Step 11: the intent's exec fields name exactly this createJob, on the openJob lane, and its + /// session hash is this session. The wallet re-checks both; this names the error before state moves. + function _bindIntent(OpenJobParams calldata p, bytes32 mode, bytes memory execCalldata) internal pure { + bytes32 cdHash = keccak256(execCalldata); + if (p.intent.mode != mode || p.intent.execCalldataHash != cdHash || p.intent.nonceKey != OPENJOB_LANE) { + revert UniversalMarketplaceErrors.IntentExecMismatch(cdHash); + } + bytes32 sessionHash = keccak256(abi.encode(p.session)); + if (p.intent.sessionHash != sessionHash) revert UniversalMarketplaceErrors.IntentSessionMismatch(sessionHash); + } + + /// @dev Step 12: the signed session is the card's rules with its markers filled for this job, for the card's + /// agent, bound to this job and CEA. + function _checkRules(AgentCard storage c, OpenJobParams calldata p, address agw, bytes32 chainHash) + internal + view + { + RULES.checkRulesMatchCard( + _agentCardRules[p.cardId], + p.session, + SessionContext({ + agent: c.provider, + chainHash: chainHash, + principal: p.job.principal, + expiredAt: p.job.expiredAt, + expectedCEA: computeCEA(agw, chainHash) + }) + ); + } + + /// @dev Step 13: deploy the predicted wallet, or check the factory's owner of the existing one. + function _deployOrCheckOwner(OpenJobParams calldata p, address agw, bool deployed) internal { + if (!deployed) { + address d = AGW_FACTORY.deployWalletWithSig(p.intent, p.sig, p.label); + if (d != agw) revert UniversalMarketplaceErrors.AGWMismatch(agw, d); + return; + } + address owner = AGW_FACTORY.ownerOf(agw); + if (owner != p.intent.owner) revert UniversalMarketplaceErrors.WalletOwnerMismatch(p.intent.owner, owner); + } + + /// @dev Step 15: the AGW creates the job; exactly one job appeared, with this AGW as client and the card's + /// provider, this hook and this evaluator. + function _createJob( + AgentCard storage c, + address agw, + bytes32 mode, + bytes memory execCalldata, + OwnerIntent calldata intent, + bytes calldata sig + ) internal returns (uint256 jobId) { + uint256 before = KERNEL.jobCounter(); + IAGW(agw).executeWithSig(mode, execCalldata, intent, sig); + jobId = KERNEL.jobCounter(); + if (jobId != before + 1) revert UniversalMarketplaceErrors.UnexpectedJobCount(before, jobId); + IAgenticCommerce.Job memory j = KERNEL.getJob(jobId); + if (j.client != agw || j.provider != c.provider || j.hook != hook || j.evaluator != evaluator) { + revert UniversalMarketplaceErrors.JobMismatch(); + } + } +} diff --git a/plan/marketplace/contracts/src/agentic-commerce-8183/UniversalMarketplaceRules.sol b/plan/marketplace/contracts/src/agentic-commerce-8183/UniversalMarketplaceRules.sol new file mode 100644 index 00000000..1de6d539 --- /dev/null +++ b/plan/marketplace/contracts/src/agentic-commerce-8183/UniversalMarketplaceRules.sol @@ -0,0 +1,278 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { + AssetCap, + AllowedCall, + ArgPin, + PinOp, + UniversalTerms, + ENVELOPE_VERSION, + MAX_ASSETS, + MAX_PINS, + MAX_ALLOWED_CALL_PINS +} from "@push-agw/libraries/Types.sol"; +import {UniversalMarketplaceErrors} from "./libraries/Errors.sol"; +import {AgentCardRules, SessionContext, MARKER_WALLET, MARKER_PRINCIPAL} from "./libraries/Types.sol"; +import {IUniversalMarketplaceRules} from "./interfaces/IUniversalMarketplaceRules.sol"; +import {Session} from "./interfaces/external/IAGW.sol"; + +/// @title UniversalMarketplaceRules +/// @notice The rules side of an agent card: registration guards, and rules = card at `openJob`. +/// @dev - EVM universal only. Pure logic, no storage, no admin; split out of the marketplace for EIP-170. +/// - Reverts with `UniversalMarketplaceErrors`: a revert here bubbles through the marketplace unchanged. +/// - Not upgradeable. A rule change is a new deployment plus a marketplace upgrade that points at it. +/// - Known limit: whether a `MARKER_PRINCIPAL` pin sits on the PRINCIPAL token's `approve` is not checked. +/// `IPRC20` has no source-token view, so a PRC20 cannot be mapped to its destination token. The verified tag +/// covers it. +contract UniversalMarketplaceRules is IUniversalMarketplaceRules { + /// @dev URP's allow-list bound (internal there, so mirrored): a card that could never be granted is refused. + uint256 internal constant MAX_ALLOWED_CALLS = 32; + + bytes4 internal constant ERC20_TRANSFER = IERC20.transfer.selector; + bytes4 internal constant ERC20_APPROVE = IERC20.approve.selector; + bytes4 internal constant ERC20_TRANSFER_FROM = IERC20.transferFrom.selector; + /// @dev Not on OZ 5's IERC20. + bytes4 internal constant ERC20_INCREASE_ALLOWANCE = bytes4(keccak256("increaseAllowance(address,uint256)")); + + /// @dev Calldata offsets of an ERC-20 call's first and second argument words. + uint16 internal constant ARG0 = 4; + uint16 internal constant ARG1 = 36; + + // ═════════════════════════════════ rules = card ═════════════════════════════════ + + /// @inheritdoc IUniversalMarketplaceRules + /// @dev - Order C1-C14; the first failure reverts. + /// - The session never carries a marker: C8 and C12 compare against the filled-in value. + /// - Never compared: the card's `principalAsset` (an index, not a rule), and the session's validator, + /// policy address, action target and selector, userOp and ERC-7739 lists, paymaster flag and salt. The + /// AGW pins every one of those itself at `grantRules` (v6 `_grantRules`). + function checkRulesMatchCard(bytes calldata cardRules, Session calldata session, SessionContext calldata ctx) + external + pure + { + if (keccak256(session.sessionValidatorInitData) != keccak256(abi.encode(ctx.agent))) { + revert UniversalMarketplaceErrors.AgentMismatch(); + } + if (session.actions.length != 1) revert UniversalMarketplaceErrors.ActionCount(); + if (session.actions[0].actionPolicies.length != 1) revert UniversalMarketplaceErrors.PolicyShape(0); + + UniversalTerms memory t = _decodeEnvelope(session.actions[0].actionPolicies[0].initData, ctx.chainHash); + AgentCardRules memory c = abi.decode(cardRules, (AgentCardRules)); + _matchAssets(c, t, ctx.principal); + if (t.maxGasPerCall != c.maxGasPerCall) revert UniversalMarketplaceErrors.GasCapMismatch(); + _matchCalls(c.allowedCalls, t.allowedCalls, ctx); + if (t.validUntil != ctx.expiredAt) revert UniversalMarketplaceErrors.ExpiryMismatch(); + if (t.expectedCEA != ctx.expectedCEA) { + revert UniversalMarketplaceErrors.ExpectedCEAMismatch(ctx.expectedCEA, t.expectedCEA); + } + } + + /// @dev C4-C5. The version is read from the first word BEFORE any decode, as URP does, so a pre-v6 + /// two-field envelope (first word 64, its string offset) is named instead of panicking the decoder. + function _decodeEnvelope(bytes calldata d, bytes32 chainHash) internal pure returns (UniversalTerms memory) { + uint256 version = d.length < 32 ? 0 : uint256(bytes32(d[:32])); + if (version != ENVELOPE_VERSION) revert UniversalMarketplaceErrors.EnvelopeVersionMismatch(version); + (, string memory chainNamespace, bytes memory body) = abi.decode(d, (uint16, string, bytes)); + if (keccak256(bytes(chainNamespace)) != chainHash) revert UniversalMarketplaceErrors.ChainMismatch(0); + return abi.decode(body, (UniversalTerms)); + } + + /// @dev C6-C9: same tokens in the same order; the principal asset's caps filled with the principal (D3); every + /// other asset's caps copied exactly. + function _matchAssets(AgentCardRules memory c, UniversalTerms memory t, uint256 principal) internal pure { + uint256 n = c.assets.length; + if (t.assets.length != n) revert UniversalMarketplaceErrors.AssetCountMismatch(n, t.assets.length); + for (uint256 i; i < n; ++i) { + if (t.assets[i].token != c.assets[i].token) revert UniversalMarketplaceErrors.AssetMismatch(i); + } + AssetCap memory card = c.assets[c.principalAsset]; + AssetCap memory signed = t.assets[c.principalAsset]; + uint256 perCall = card.maxPerCall == uint256(MARKER_PRINCIPAL) ? principal : card.maxPerCall; + if (signed.maxTotal != principal || signed.maxPerCall != perCall) { + revert UniversalMarketplaceErrors.PrincipalCapMismatch(); + } + for (uint256 i; i < n; ++i) { + if (i == c.principalAsset) continue; + if (t.assets[i].maxPerCall != c.assets[i].maxPerCall || t.assets[i].maxTotal != c.assets[i].maxTotal) { + revert UniversalMarketplaceErrors.AssetMismatch(i); + } + } + } + + /// @dev C11-C12, one loop: every field of every call equal, every pin's offset and op equal, then its value + /// equal with markers filled in. + function _matchCalls(AllowedCall[] memory card, AllowedCall[] memory signed, SessionContext calldata ctx) + internal + pure + { + if (signed.length != card.length) revert UniversalMarketplaceErrors.ActionsMismatch(); + bytes32 wallet = bytes32(uint256(uint160(ctx.expectedCEA))); + bytes32 principal = bytes32(ctx.principal); + for (uint256 i; i < card.length; ++i) { + AllowedCall memory a = card[i]; + AllowedCall memory b = signed[i]; + if ( + a.target != b.target || a.selector != b.selector || a.beneficiaryOffset != b.beneficiaryOffset + || a.hasBeneficiary != b.hasBeneficiary || a.maxValue != b.maxValue || a.pins.length != b.pins.length + ) revert UniversalMarketplaceErrors.ActionsMismatch(); + for (uint256 k; k < a.pins.length; ++k) { + ArgPin memory p = a.pins[k]; + ArgPin memory q = b.pins[k]; + if (p.offset != q.offset || p.op != q.op) revert UniversalMarketplaceErrors.ActionsMismatch(); + bytes32 want = p.value == MARKER_WALLET ? wallet : p.value == MARKER_PRINCIPAL ? principal : p.value; + if (q.value != want) revert UniversalMarketplaceErrors.PinMismatch(i, k); + } + } + } + + // ═════════════════════════════════ registration guards ═════════════════════════════════ + + /// @inheritdoc IUniversalMarketplaceRules + /// @dev Order R1-R17; the first failure reverts. Malformed bytes revert in the decoder, without data. + function validateAgentCardRules(bytes calldata rules) external pure returns (address[] memory tokens) { + AgentCardRules memory r = abi.decode(rules, (AgentCardRules)); + _validateAssets(r.assets, r.principalAsset); + _validateCallShape(r.allowedCalls); + _validateDuplicates(r.allowedCalls); + _validateErc20(r.allowedCalls); + tokens = new address[](r.assets.length); + for (uint256 i; i < tokens.length; ++i) { + tokens[i] = r.assets[i].token; + } + } + + /// @dev R1-R7. + function _validateAssets(AssetCap[] memory assets, uint8 principalAsset) internal pure { + uint256 n = assets.length; + if (n == 0 || n > MAX_ASSETS) revert UniversalMarketplaceErrors.InvalidAgentCard("asset count"); + if (principalAsset >= n) revert UniversalMarketplaceErrors.InvalidAgentCard("principal asset"); + for (uint256 i; i < n; ++i) { + if (assets[i].token == address(0)) revert UniversalMarketplaceErrors.InvalidAgentCard("asset zero"); + } + for (uint256 i; i < n; ++i) { + for (uint256 j; j < i; ++j) { + if (assets[j].token == assets[i].token) { + revert UniversalMarketplaceErrors.InvalidAgentCard("duplicate asset"); + } + } + } + AssetCap memory p = assets[principalAsset]; + if (p.maxTotal != uint256(MARKER_PRINCIPAL)) { + revert UniversalMarketplaceErrors.InvalidAgentCard("principal total not marker"); + } + if (p.maxPerCall == 0) revert UniversalMarketplaceErrors.InvalidAgentCard("principal per-call zero"); + for (uint256 i; i < n; ++i) { + if (i == principalAsset) continue; + if (assets[i].maxPerCall == uint256(MARKER_PRINCIPAL) || assets[i].maxTotal == uint256(MARKER_PRINCIPAL)) { + revert UniversalMarketplaceErrors.InvalidAgentCard("marker off principal asset"); + } + } + } + + /// @dev R8-R10: 1-32 calls; at most MAX_PINS pins per call and MAX_ALLOWED_CALL_PINS in all; `MARKER_WALLET` + /// only under EQ (a ceiling of an address is meaningless). + function _validateCallShape(AllowedCall[] memory calls) internal pure { + uint256 n = calls.length; + if (n == 0 || n > MAX_ALLOWED_CALLS) revert UniversalMarketplaceErrors.InvalidAgentCard("allow-list size"); + uint256 total; + for (uint256 i; i < n; ++i) { + uint256 pins = calls[i].pins.length; + total += pins; + if (pins > MAX_PINS || total > MAX_ALLOWED_CALL_PINS) { + revert UniversalMarketplaceErrors.InvalidAgentCard("too many pins"); + } + } + for (uint256 i; i < n; ++i) { + ArgPin[] memory pins = calls[i].pins; + for (uint256 k; k < pins.length; ++k) { + if (pins[k].value == MARKER_WALLET && pins[k].op != PinOp.EQ) { + revert UniversalMarketplaceErrors.InvalidAgentCard("wallet marker op"); + } + } + } + } + + /// @dev R11-R12. Several entries may share a (target, selector) — "approve to Aave or to Uniswap" — but only + /// if each is pinned: a call passes if ANY entry passes, so a pinless one beside a pinned one makes the + /// pins pointless (AGW v6 `AllowedCall` docs; URP allows it, the SDK and this helper refuse it). + function _validateDuplicates(AllowedCall[] memory calls) internal pure { + uint256 n = calls.length; + bytes32[] memory hashes = new bytes32[](n); + for (uint256 i; i < n; ++i) { + hashes[i] = keccak256(abi.encode(calls[i])); + for (uint256 j; j < i; ++j) { + if (hashes[j] == hashes[i]) revert UniversalMarketplaceErrors.InvalidAgentCard("duplicate call"); + } + } + for (uint256 i; i < n; ++i) { + for (uint256 j; j < i; ++j) { + if ( + calls[j].target == calls[i].target && calls[j].selector == calls[i].selector + && (calls[j].pins.length == 0 || calls[i].pins.length == 0) + ) revert UniversalMarketplaceErrors.InvalidAgentCard("unpinned duplicate"); + } + } + } + + /// @dev R13-R17, each over every call before the next (D1: the agent approves, but only under pins). + /// - approve: spender pinned EQ to a clean, non-zero address word (which excludes both markers: their + /// high 96 bits are non-zero), and amount capped by a MAX pin (a literal or `MARKER_PRINCIPAL`). + /// - transfer / transferFrom: recipient bound to the user's account, by the beneficiary field or by an EQ + /// `MARKER_WALLET` pin. + function _validateErc20(AllowedCall[] memory calls) internal pure { + for (uint256 i; i < calls.length; ++i) { + if (calls[i].selector == ERC20_INCREASE_ALLOWANCE) { + revert UniversalMarketplaceErrors.InvalidAgentCard("increaseAllowance"); + } + } + for (uint256 i; i < calls.length; ++i) { + if (calls[i].selector == ERC20_APPROVE && !_hasSpenderPin(calls[i].pins)) { + revert UniversalMarketplaceErrors.InvalidAgentCard("approve spender not pinned"); + } + } + for (uint256 i; i < calls.length; ++i) { + if (calls[i].selector == ERC20_APPROVE && !_hasPin(calls[i].pins, ARG1, PinOp.MAX)) { + revert UniversalMarketplaceErrors.InvalidAgentCard("approve amount not capped"); + } + } + for (uint256 i; i < calls.length; ++i) { + if (calls[i].selector == ERC20_TRANSFER && !_recipientIsWallet(calls[i], ARG0)) { + revert UniversalMarketplaceErrors.InvalidAgentCard("erc20 transfer recipient"); + } + } + for (uint256 i; i < calls.length; ++i) { + if (calls[i].selector == ERC20_TRANSFER_FROM && !_recipientIsWallet(calls[i], ARG1)) { + revert UniversalMarketplaceErrors.InvalidAgentCard("erc20 transferFrom recipient"); + } + } + } + + /// @dev Some pin is `{4, EQ, v}` with `v` a non-zero address word. + function _hasSpenderPin(ArgPin[] memory pins) internal pure returns (bool) { + for (uint256 k; k < pins.length; ++k) { + ArgPin memory p = pins[k]; + if (p.offset == ARG0 && p.op == PinOp.EQ && p.value != 0 && uint256(p.value) >> 160 == 0) return true; + } + return false; + } + + /// @dev Some pin is `{offset, op, *}`. + function _hasPin(ArgPin[] memory pins, uint16 offset, PinOp op) internal pure returns (bool) { + for (uint256 k; k < pins.length; ++k) { + if (pins[k].offset == offset && pins[k].op == op) return true; + } + return false; + } + + /// @dev The recipient word at `offset` is the user's account: the beneficiary field, or `{offset, EQ, MARKER_WALLET}`. + function _recipientIsWallet(AllowedCall memory call, uint16 offset) internal pure returns (bool) { + if (call.hasBeneficiary && call.beneficiaryOffset == offset) return true; + for (uint256 k; k < call.pins.length; ++k) { + ArgPin memory p = call.pins[k]; + if (p.offset == offset && p.op == PinOp.EQ && p.value == MARKER_WALLET) return true; + } + return false; + } +} diff --git a/plan/marketplace/contracts/src/agentic-commerce-8183/hooks/BaseERC8183Hook.sol b/plan/marketplace/contracts/src/agentic-commerce-8183/hooks/BaseERC8183Hook.sol new file mode 100644 index 00000000..ab234c9e --- /dev/null +++ b/plan/marketplace/contracts/src/agentic-commerce-8183/hooks/BaseERC8183Hook.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {ERC165Upgradeable} from "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol"; +import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; + +import {IERC8183Hook} from "../interfaces/IERC8183Hook.sol"; +import {IAgenticCommerce} from "../interfaces/IAgenticCommerce.sol"; +import {ERC8183HookErrors} from "../libraries/Errors.sol"; + +/// @title BaseERC8183Hook +/// @notice Abstract helper every hook in this repo inherits. Not part of the ERC. +/// @dev - Only the kernel may call (H-01); no router trust path. +/// - Selectors come from `IAgenticCommerce` (H-02), so a signature change fails to compile. +/// - Unknown selectors are ignored (H-03). +/// - Owns storage slots 0–49: `KERNEL` at slot 0, then a 49-slot gap. +abstract contract BaseERC8183Hook is Initializable, ERC165Upgradeable, IERC8183Hook { + /// @notice The only address allowed to call this hook. Set once, at initialization. + address public KERNEL; + uint256[49] private __gap; + + /// @dev - Reverts `CallerIsNotKernel` for any other caller. + modifier onlyKernel() { + if (msg.sender != KERNEL) revert ERC8183HookErrors.CallerIsNotKernel(msg.sender); + _; + } + + /// @notice Sets the kernel. Call once from the derived hook's initializer. + /// @param kernel_ The kernel proxy address. + function __BaseERC8183Hook_init(address kernel_) internal onlyInitializing { + __ERC165_init(); + if (kernel_ == address(0)) revert ERC8183HookErrors.ZeroAddress(); + KERNEL = kernel_; + } + + /// @inheritdoc IERC8183Hook + function beforeAction(uint256 jobId, bytes4 selector, bytes calldata data) external onlyKernel { + if (selector == IAgenticCommerce.setProvider.selector) { + (address caller, address provider, bytes memory opt) = abi.decode(data, (address, address, bytes)); + _preSetProvider(jobId, caller, provider, opt); + } else if (selector == IAgenticCommerce.setBudget.selector) { + (address caller, uint256 amount, bytes memory opt) = abi.decode(data, (address, uint256, bytes)); + _preSetBudget(jobId, caller, amount, opt); + } else if (selector == IAgenticCommerce.fund.selector) { + (address caller, bytes memory opt) = abi.decode(data, (address, bytes)); + _preFund(jobId, caller, opt); + } else if (selector == IAgenticCommerce.submit.selector) { + (address caller, bytes32 deliverable, bytes memory opt) = abi.decode(data, (address, bytes32, bytes)); + _preSubmit(jobId, caller, deliverable, opt); + } else if (selector == IAgenticCommerce.complete.selector) { + (address caller, bytes32 reason, bytes memory opt) = abi.decode(data, (address, bytes32, bytes)); + _preComplete(jobId, caller, reason, opt); + } else if (selector == IAgenticCommerce.reject.selector) { + (address caller, bytes32 reason, bytes memory opt) = abi.decode(data, (address, bytes32, bytes)); + _preReject(jobId, caller, reason, opt); + } + } + + /// @inheritdoc IERC8183Hook + function afterAction(uint256 jobId, bytes4 selector, bytes calldata data) external onlyKernel { + if (selector == IAgenticCommerce.setProvider.selector) { + (address caller, address provider, bytes memory opt) = abi.decode(data, (address, address, bytes)); + _postSetProvider(jobId, caller, provider, opt); + } else if (selector == IAgenticCommerce.setBudget.selector) { + (address caller, uint256 amount, bytes memory opt) = abi.decode(data, (address, uint256, bytes)); + _postSetBudget(jobId, caller, amount, opt); + } else if (selector == IAgenticCommerce.fund.selector) { + (address caller, bytes memory opt) = abi.decode(data, (address, bytes)); + _postFund(jobId, caller, opt); + } else if (selector == IAgenticCommerce.submit.selector) { + (address caller, bytes32 deliverable, bytes memory opt) = abi.decode(data, (address, bytes32, bytes)); + _postSubmit(jobId, caller, deliverable, opt); + } else if (selector == IAgenticCommerce.complete.selector) { + (address caller, bytes32 reason, bytes memory opt) = abi.decode(data, (address, bytes32, bytes)); + _postComplete(jobId, caller, reason, opt); + } else if (selector == IAgenticCommerce.reject.selector) { + (address caller, bytes32 reason, bytes memory opt) = abi.decode(data, (address, bytes32, bytes)); + _postReject(jobId, caller, reason, opt); + } + } + + /// @inheritdoc ERC165Upgradeable + function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165Upgradeable, IERC165) returns (bool) { + return interfaceId == type(IERC8183Hook).interfaceId || super.supportsInterface(interfaceId); + } + + // ───────── handlers — override what you need; all default to no-op ───────── + + /// @dev Before `setProvider`. + function _preSetProvider(uint256 jobId, address caller, address provider, bytes memory optParams) internal virtual {} + /// @dev After `setProvider`. + function _postSetProvider(uint256 jobId, address caller, address provider, bytes memory optParams) internal virtual {} + /// @dev Before `setBudget`. + function _preSetBudget(uint256 jobId, address caller, uint256 amount, bytes memory optParams) internal virtual {} + /// @dev After `setBudget`. + function _postSetBudget(uint256 jobId, address caller, uint256 amount, bytes memory optParams) internal virtual {} + /// @dev Before `fund`. `caller` is the job's client. + function _preFund(uint256 jobId, address caller, bytes memory optParams) internal virtual {} + /// @dev After `fund`. + function _postFund(uint256 jobId, address caller, bytes memory optParams) internal virtual {} + /// @dev Before `submit`. + function _preSubmit(uint256 jobId, address caller, bytes32 deliverable, bytes memory optParams) internal virtual {} + /// @dev After `submit`. + function _postSubmit(uint256 jobId, address caller, bytes32 deliverable, bytes memory optParams) internal virtual {} + /// @dev Before `complete`. + function _preComplete(uint256 jobId, address caller, bytes32 reason, bytes memory optParams) internal virtual {} + /// @dev After `complete`. + function _postComplete(uint256 jobId, address caller, bytes32 reason, bytes memory optParams) internal virtual {} + /// @dev Before `reject`. + function _preReject(uint256 jobId, address caller, bytes32 reason, bytes memory optParams) internal virtual {} + /// @dev After `reject`. + function _postReject(uint256 jobId, address caller, bytes32 reason, bytes memory optParams) internal virtual {} +} + diff --git a/plan/marketplace/contracts/src/agentic-commerce-8183/hooks/RulesBindingHook.sol b/plan/marketplace/contracts/src/agentic-commerce-8183/hooks/RulesBindingHook.sol new file mode 100644 index 00000000..736165f7 --- /dev/null +++ b/plan/marketplace/contracts/src/agentic-commerce-8183/hooks/RulesBindingHook.sol @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import {BaseERC8183Hook} from "./BaseERC8183Hook.sol"; +import {IAgenticCommerce} from "../interfaces/IAgenticCommerce.sol"; +import {IAGWFactory} from "../interfaces/external/IAGWFactory.sol"; +import {ISmartSession} from "../interfaces/external/ISmartSession.sol"; +import {RulesBindingHookErrors, ERC8183HookErrors} from "../libraries/Errors.sol"; + +/// @title RulesBindingHook +/// @notice Binds each job to the funding AGW's rules set and allows one live job per AGW. +/// @dev - Acts only in `beforeAction(fund)` (H-09); every other action passes through. +/// - Scope (D-25): the rule covers jobs that name this hook; hookless jobs are invisible to it. +/// - An AGW is freed by reading kernel job status (H-05), so unhooked `claimRefund` frees it too. +/// - Deployed behind `TransparentUpgradeableProxy` (D-15); storage continues the base at slot 50. +contract RulesBindingHook is BaseERC8183Hook { + /// @notice The job ↔ rules set record. `rulesId` is the AGW's rules id (the engine's `permissionId`). + struct Binding { + address agw; + bytes32 rulesId; + } + + /// @notice A job was bound to an AGW's rules set at `fund`. + event RulesBound(uint256 indexed jobId, address indexed agw, bytes32 indexed rulesId); + + // ───────── storage — slots 50..103 (base owns 0..49) ───────── + + /// @notice AGW factory, used to prove the client is an AGW. Set once, at initialization. + address public AGW_FACTORY; + /// @notice SmartSession engine, used to prove the rules set is live. Set once, at initialization. + address public SESSION_ENGINE; + /// @dev Job id → bound rules set. `rulesId` is not globally unique across wallets; always read with `agw`. + mapping(uint256 => Binding) internal _bindingOf; + /// @dev AGW → last job bound; live only while that job is Funded or Submitted. Read through `activeJobOf`. + mapping(address => uint256) internal _liveJobOf; + uint256[50] private __gap; + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + /// @notice Initialize the proxy. + /// @param kernel_ The kernel proxy. + /// @param agwFactory_ The AGW factory proxy. + /// @param sessionEngine_ The SmartSession engine. + function initialize(address kernel_, address agwFactory_, address sessionEngine_) external initializer { + if (kernel_ == address(0) || agwFactory_ == address(0) || sessionEngine_ == address(0)) { + revert ERC8183HookErrors.ZeroAddress(); + } + __BaseERC8183Hook_init(kernel_); + AGW_FACTORY = agwFactory_; + SESSION_ENGINE = sessionEngine_; + } + + /// @notice The rules set bound to `jobId` at fund, or zero. + function rulesOfJob(uint256 jobId) external view returns (bytes32) { + return _bindingOf[jobId].rulesId; + } + + /// @notice The AGW bound to `jobId` at fund, or zero. + function agwOfJob(uint256 jobId) external view returns (address) { + return _bindingOf[jobId].agw; + } + + /// @notice The AGW's live job under this hook (Funded or Submitted), or 0. + /// @dev Narrower than the marketplace's `activeJobOf`, which also counts an Open, unexpired job: this hook binds + /// at `fund`, the marketplace at `openJob`. Both are intended. + /// @param agw The wallet. + /// @return The job id, or 0 if the AGW may fund another job here. + function activeJobOf(address agw) public view returns (uint256) { + uint256 id = _liveJobOf[agw]; + if (id == 0) return 0; + IAgenticCommerce.JobStatus s = IAgenticCommerce(KERNEL).getJob(id).status; + return s == IAgenticCommerce.JobStatus.Funded || s == IAgenticCommerce.JobStatus.Submitted ? id : 0; + } + + /// @dev Checks, in order: optParams length · client is an AGW · rules set live · AGW has no live job. + /// - `caller` is the job's client — the kernel checks it before calling the hook. + /// - Runs in `beforeAction`, so any revert leaves the job Open with no escrow moved. + function _preFund(uint256 jobId, address caller, bytes memory optParams) internal override { + if (optParams.length != 32) revert RulesBindingHookErrors.InvalidOptParams(optParams.length); + bytes32 rulesId = abi.decode(optParams, (bytes32)); + if (!IAGWFactory(AGW_FACTORY).isWallet(caller)) revert RulesBindingHookErrors.CallerIsNotAGW(caller); + if (!ISmartSession(SESSION_ENGINE).isPermissionEnabled(rulesId, caller)) { + revert RulesBindingHookErrors.RulesNotLive(caller, rulesId); + } + uint256 live = activeJobOf(caller); + if (live != 0) revert RulesBindingHookErrors.AGWHasLiveJob(caller, live); + + _bindingOf[jobId] = Binding({agw: caller, rulesId: rulesId}); + _liveJobOf[caller] = jobId; + emit RulesBound(jobId, caller, rulesId); + } +} diff --git a/plan/marketplace/contracts/src/agentic-commerce-8183/interfaces/IAgenticCommerce.sol b/plan/marketplace/contracts/src/agentic-commerce-8183/interfaces/IAgenticCommerce.sol new file mode 100644 index 00000000..5354ebf9 --- /dev/null +++ b/plan/marketplace/contracts/src/agentic-commerce-8183/interfaces/IAgenticCommerce.sol @@ -0,0 +1,239 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +/// @title IAgenticCommerce +/// @notice External surface of the ERC-8183 kernel on Push Chain. +/// @dev - Events and errors are declared only here. +/// - Hooks and tests take selectors from this interface, never from signature strings. +interface IAgenticCommerce { + // ──────────────────────────────── types ──────────────────────────────── + + /// @notice Job lifecycle states. + enum JobStatus { + Open, + Funded, + Submitted, + Completed, + Rejected, + Expired + } + + /// @notice A job record. + /// @dev - `provider` may be zero until `setProvider`. + /// - `hook == address(0)` means no hook. + struct Job { + address client; + JobStatus status; + address provider; + uint48 expiredAt; + address evaluator; + address hook; + uint256 budget; + string description; + } + + // ──────────────────────────────── events ──────────────────────────────── + + /// @notice A job was created. + event JobCreated( + uint256 indexed jobId, + address indexed client, + address indexed provider, + address evaluator, + uint256 expiredAt, + address hook + ); + /// @notice A provider was assigned to an Open job. + event ProviderSet(uint256 indexed jobId, address indexed provider); + /// @notice The provider set or re-quoted the budget. + event BudgetSet(uint256 indexed jobId, uint256 amount); + /// @notice The client funded the escrow. + event JobFunded(uint256 indexed jobId, address indexed client, uint256 amount); + /// @notice The provider submitted a deliverable. + event JobSubmitted(uint256 indexed jobId, address indexed provider, bytes32 deliverable); + /// @notice The evaluator completed the job. + event JobCompleted(uint256 indexed jobId, address indexed evaluator, bytes32 reason); + /// @notice The job was rejected. + event JobRejected(uint256 indexed jobId, address indexed rejector, bytes32 reason); + /// @notice The job expired through `claimRefund`. + event JobExpired(uint256 indexed jobId); + /// @notice Net payment released to the provider. Emitted on every completion, even at 0. + event PaymentReleased(uint256 indexed jobId, address indexed provider, uint256 amount); + /// @notice Platform fee paid to the treasury. + event PlatformFeePaid(uint256 indexed jobId, address indexed treasury, uint256 amount); + /// @notice Evaluator fee paid. + event EvaluatorFeePaid(uint256 indexed jobId, address indexed evaluator, uint256 amount); + /// @notice Escrow returned to the client. + event Refunded(uint256 indexed jobId, address indexed client, uint256 amount); + /// @notice A hook's whitelist status changed. + event HookWhitelistUpdated(address indexed hook, bool status); + /// @notice An admin detached a hook from a job. + event HookDetached(uint256 indexed jobId, address indexed hook); + /// @notice Platform fee or treasury changed. + event PlatformFeeUpdated(uint256 feeBP, address indexed treasury); + /// @notice Evaluator fee changed. + event EvaluatorFeeUpdated(uint256 feeBP); + /// @notice Unattributed tokens withdrawn while paused. + event EmergencyWithdraw(address indexed token, address indexed to, uint256 amount); + + // ──────────────────────────────── errors ──────────────────────────────── + + /// @notice Job id is 0 or beyond `jobCounter`. + error InvalidJob(); + /// @notice Job is not in a status that permits the action. + error WrongStatus(); + /// @notice Caller is not the role this action requires. + error Unauthorized(); + /// @notice A required address is zero. + error ZeroAddress(); + /// @notice `expiredAt` is not beyond `now + MIN_EXPIRY_WINDOW`, or exceeds `uint48`. + error ExpiryTooShort(); + /// @notice `fund` called before a provider was set. + error ProviderNotSet(); + /// @notice Platform + evaluator fees would exceed 100%. + error FeesTooHigh(); + /// @notice Hook is not whitelisted. + error HookNotWhitelisted(); + /// @notice Hook does not advertise `IERC8183Hook` via ERC-165. + error InvalidHook(); + /// @notice `expectedBudget` differs from the stored budget. + error BudgetMismatch(); + /// @notice Evaluator and provider are the same address. + error EvaluatorIsProvider(); + /// @notice Client and provider are the same address. + error ClientIsProvider(); + /// @notice A Submitted job is still inside the evaluator grace window. + error GracePeriodActive(); + /// @notice Withdrawal would take escrowed funds. + error InsufficientUnattributedBalance(uint256 requested, uint256 available); + + // ──────────────────────────────── constants ──────────────────────────────── + + /// @notice Role for fees, hooks, pause and emergency withdrawal. + /// @return The role id. + function ADMIN_ROLE() external view returns (bytes32); + /// @notice Window after expiry in which a Submitted job cannot be refunded. + /// @return Seconds. + function EVALUATOR_GRACE_PERIOD() external view returns (uint256); + /// @notice Minimum distance between now and `expiredAt` at creation. + /// @return Seconds. + function MIN_EXPIRY_WINDOW() external view returns (uint256); + /// @notice Basis-point denominator. + /// @return The denominator. + function BPS_DENOMINATOR() external view returns (uint256); + + // ──────────────────────────────── admin ──────────────────────────────── + + /// @notice Pause every lifecycle function except `claimRefund`. + function pause() external; + /// @notice Unpause. + function unpause() external; + /// @notice Set the platform fee and treasury. + /// @param feeBP Fee in basis points. + /// @param treasury Fee recipient. + function setPlatformFee(uint256 feeBP, address treasury) external; + /// @notice Set the evaluator fee. + /// @param feeBP Fee in basis points. + function setEvaluatorFee(uint256 feeBP) external; + /// @notice Whitelist or de-whitelist a hook for new jobs. + /// @param hook Hook address. + /// @param status Whitelisted or not. + function setHookWhitelist(address hook, bool status) external; + /// @notice Detach hooks from jobs (emergency). + /// @param jobIds Jobs to detach. + function batchDetachHook(uint256[] calldata jobIds) external; + /// @notice Withdraw tokens that are not escrow, while paused. + /// @param token ERC-20 to withdraw; never zero. + /// @param to Recipient. + /// @param amount Amount. + function emergencyWithdraw(address token, address to, uint256 amount) external; + + // ──────────────────────────────── lifecycle ──────────────────────────────── + + /// @notice Create a job; the caller is the client. + /// @param provider Provider, or zero to set later. + /// @param evaluator Evaluator; never zero. + /// @param expiredAt Expiry timestamp. + /// @param description Free-text description. + /// @param hook Whitelisted hook, or zero. + /// @return jobId The new job id. + function createJob( + address provider, + address evaluator, + uint256 expiredAt, + string calldata description, + address hook + ) external returns (uint256 jobId); + + /// @notice Assign the provider of an Open job. Client only. + /// @param jobId The job. + /// @param provider The provider. + /// @param optParams Opaque hook payload. + function setProvider(uint256 jobId, address provider, bytes calldata optParams) external; + + /// @notice Set or re-quote the budget. Provider only. + /// @param jobId The job. + /// @param amount Budget in payment-token units. + /// @param optParams Opaque hook payload. + function setBudget(uint256 jobId, uint256 amount, bytes calldata optParams) external; + + /// @notice Fund the escrow. Client only. + /// @param jobId The job. + /// @param expectedBudget Must equal the stored budget. + /// @param optParams Opaque hook payload. + function fund(uint256 jobId, uint256 expectedBudget, bytes calldata optParams) external; + + /// @notice Submit a deliverable. Provider only. + /// @param jobId The job. + /// @param deliverable Deliverable hash or reference. + /// @param optParams Opaque hook payload. + function submit(uint256 jobId, bytes32 deliverable, bytes calldata optParams) external; + + /// @notice Complete and pay out. Evaluator only. + /// @param jobId The job. + /// @param reason Attestation reason. + /// @param optParams Opaque hook payload. + function complete(uint256 jobId, bytes32 reason, bytes calldata optParams) external; + + /// @notice Reject; refunds escrow if funded. + /// @param jobId The job. + /// @param reason Rejection reason. + /// @param optParams Opaque hook payload. + function reject(uint256 jobId, bytes32 reason, bytes calldata optParams) external; + + /// @notice Refund an expired job. Anyone may call. + /// @param jobId The job. + function claimRefund(uint256 jobId) external; + + // ──────────────────────────────── views ──────────────────────────────── + + /// @notice Full job record; zero struct for unknown ids. + /// @param jobId The job. + /// @return The job. + function getJob(uint256 jobId) external view returns (Job memory); + + /// @notice The single payment token. + /// @return The token. + function paymentToken() external view returns (IERC20); + /// @notice Platform fee in basis points. + /// @return Basis points. + function platformFeeBP() external view returns (uint256); + /// @notice Platform fee recipient. + /// @return The recipient. + function platformTreasury() external view returns (address); + /// @notice Evaluator fee in basis points. + /// @return Basis points. + function evaluatorFeeBP() external view returns (uint256); + /// @notice Last job id issued. + /// @return The last id issued. + function jobCounter() external view returns (uint256); + /// @notice Whether a hook may be used on new jobs. + /// @param hook Hook address. + /// @return Whether whitelisted. + function whitelistedHooks(address hook) external view returns (bool); + /// @notice Sum of budgets of Funded and Submitted jobs. + /// @return The escrowed sum. + function totalEscrowed() external view returns (uint256); +} diff --git a/plan/marketplace/contracts/src/agentic-commerce-8183/interfaces/IERC8183Hook.sol b/plan/marketplace/contracts/src/agentic-commerce-8183/interfaces/IERC8183Hook.sol new file mode 100644 index 00000000..83c31ed8 --- /dev/null +++ b/plan/marketplace/contracts/src/agentic-commerce-8183/interfaces/IERC8183Hook.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; + +/// @title IERC8183Hook +/// @notice ERC-8183 hook interface: callbacks around each hooked kernel action. +/// @dev - Same selectors as the EIP's `IACPHook` and the official `IERC8183Hook`, so the +/// ERC-165 id (`0x7ff6bc9e`) is compatible with both. +/// - `data` encoding per selector is fixed by the kernel (PRD §4.1.5). +interface IERC8183Hook is IERC165 { + /// @notice Called before the kernel applies an action. + /// @dev - May revert to block the action. + /// @param jobId The job the action targets. + /// @param selector The kernel function's selector. + /// @param data ABI-encoded action arguments, caller first. + function beforeAction(uint256 jobId, bytes4 selector, bytes calldata data) external; + + /// @notice Called after the kernel applied an action. + /// @dev - A revert rolls back the whole kernel call. + /// @param jobId The job the action targeted. + /// @param selector The kernel function's selector. + /// @param data ABI-encoded action arguments, caller first. + function afterAction(uint256 jobId, bytes4 selector, bytes calldata data) external; +} diff --git a/plan/marketplace/contracts/src/agentic-commerce-8183/interfaces/IUniversalMarketplace.sol b/plan/marketplace/contracts/src/agentic-commerce-8183/interfaces/IUniversalMarketplace.sol new file mode 100644 index 00000000..4bc56367 --- /dev/null +++ b/plan/marketplace/contracts/src/agentic-commerce-8183/interfaces/IUniversalMarketplace.sol @@ -0,0 +1,195 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import {OwnerIntent} from "@push-agw/libraries/Types.sol"; +import {Session} from "./external/IAGW.sol"; +import {IAGWFactory} from "./external/IAGWFactory.sol"; +import {IAgenticCommerce} from "./IAgenticCommerce.sol"; +import {IUniversalMarketplaceRules} from "./IUniversalMarketplaceRules.sol"; +import {AgentCard, AgentCardView, JobInputs, OpenJobParams, IntentRequest} from "../libraries/Types.sol"; + +/// @title IUniversalMarketplace +/// @notice Agent cards, and `openJob`: one relayed call that deploys the user's AGW (if needed), grants it the +/// card's rules, and creates the ERC-8183 job with the AGW as client. Moves no funds. +/// @dev Errors live in `UniversalMarketplaceErrors` (`libraries/Errors.sol`); types in `libraries/Types.sol`. +interface IUniversalMarketplace { + // ═══ UM_1: EVENTS ═══ + + /// @dev `rulesHash = keccak256(rules)`, `jobSpecHash = keccak256(jobSpecTemplate)`. + event AgentCardRegistered( + uint256 indexed cardId, + address indexed provider, + bytes32 indexed jobType, + string chainNamespace, + bytes32 rulesHash, + bytes32 jobSpecHash, + bytes32 metadataHash, + uint256 providerFee + ); + /// @notice The provider changed the card. `version` is the new version; the verified tag is cleared. + event AgentCardUpdated( + uint256 indexed cardId, + uint256 version, + bytes32 rulesHash, + bytes32 jobSpecHash, + bytes32 metadataHash, + uint256 providerFee + ); + /// @notice The provider switched the card on or off. + event AgentCardStatusChanged(uint256 indexed cardId, bool active); + /// @notice The admin disabled the card, permanently. + event AgentCardDisabled(uint256 indexed cardId); + /// @notice The admin verified the card AT `version`. Any later update clears the tag. + event AgentCardVerified(uint256 indexed cardId, uint256 version); + /// @notice The verified tag was removed: by the admin, by an update, or by `disableAgentCard`. + event AgentCardVerificationRevoked(uint256 indexed cardId); + /// @notice The admin set an agent's rating (placeholder until VerifiedRatings is wired). + event AgentRatingSet(address indexed agent, uint256 rating); + /// @notice New jobs get this hook. + event HookUpdated(address hook); + /// @notice New jobs get this evaluator. + event EvaluatorUpdated(address evaluator); + /// @notice A chain's CEA deployment was set, or cleared (both zero). + event CEADeploymentSet(bytes32 indexed chainHash, address ceaFactory, address ceaProxyImpl); + /// @notice `openJob` deployed (if needed) and granted the AGW, and created `jobId`. + event JobOpened( + uint256 indexed cardId, + address indexed owner, + address indexed agw, + uint256 jobId, + bytes32 rulesId, + uint256 principal, + uint256 cardVersion + ); + + // ═══ UM_2: ADMIN ═══ + + /// @notice Sets the hook every new job is created with. Must be whitelisted on the kernel. + function setHook(address hook) external; + + /// @notice Sets the evaluator every new job is created with. + function setEvaluator(address evaluator) external; + + /// @notice Sets a destination chain's CEA deployment; `(chainHash, 0, 0)` clears it. A chain without one cannot + /// carry cards or jobs. + function setCEADeployment(bytes32 chainHash, address ceaFactory, address ceaProxyImpl) external; + + /// @notice Sets an agent's rating. No validation; placeholder until VerifiedRatings is wired. + function setAgentRating(address agent, uint256 rating) external; + + /// @notice Pauses card registration, update and `openJob`. Admin functions stay live. + function pause() external; + + /// @notice Lifts `pause`. + function unpause() external; + + /// @notice Permanently disables a card and clears its verified tag. The provider stays registered. + function disableAgentCard(uint256 cardId) external; + + /// @notice Tags the card verified at `cardVersion`, which must be its current version. + function verifyAgentCard(uint256 cardId, uint256 cardVersion) external; + + /// @notice Clears the verified tag. Idempotent. + function revokeAgentCardVerification(uint256 cardId) external; + + // ═══ UM_3: CARDS ═══ + + /// @notice Registers the caller's one card, with its content. The caller becomes its provider. + /// @param c The card; `provider` and `active` are ignored. + /// @param rules `abi.encode(AgentCardRules)`. + /// @param jobSpecTemplate `abi.encode(JobSpecTemplate)`. + function registerAgentCard(AgentCard calldata c, bytes calldata rules, bytes calldata jobSpecTemplate) + external + returns (uint256 cardId); + + /// @notice Replaces every mutable field and both content blobs; bumps the version, clears the verified tag. + function updateAgentCard(uint256 cardId, AgentCard calldata c, bytes calldata rules, bytes calldata jobSpecTemplate) + external; + + /// @notice The provider switches the card on or off. A disabled card cannot be switched on. + function setAgentCardActive(uint256 cardId, bool active) external; + + // ═══ UM_4: JOBS ═══ + + /// @notice Deploys the AGW if needed, grants the card's rules, and creates the job. Moves no funds. + /// @return jobId The kernel job. + /// @return agw The AGW, the job's client. + /// @return rulesId The granted rules (the engine's permissionId). + function openJob(OpenJobParams calldata p) external returns (uint256 jobId, address agw, bytes32 rulesId); + + // ═══ UM_5: VIEWS ═══ + + /// @notice The card, its content, version and tags. The zero view for an unknown card. + function getAgentCard(uint256 cardId) external view returns (AgentCardView memory); + + /// @notice Whether the admin has verified the card at its current version. + function isAgentCardVerified(uint256 cardId) external view returns (bool); + + /// @notice Whether the admin has disabled the card. Permanent. + function isAgentCardDisabled(uint256 cardId) external view returns (bool); + + /// @notice 1 at registration, +1 per update, 0 for an unknown card. + function agentCardVersion(uint256 cardId) external view returns (uint256); + + /// @notice Cards registered so far; also the last card id. + function agentCardCount() external view returns (uint256); + + /// @notice The provider's card id, or 0 for none. + function agentCardOf(address provider) external view returns (uint256); + + /// @notice The agent's rating, 0 by default. + function getAgentRating(address agent) external view returns (uint256); + + /// @notice The AGW's last job opened here while it is Funded, Submitted, or Open and unexpired; else 0. + /// @dev Wider than the hook's `activeJobOf` (Funded or Submitted only): the marketplace binds at `openJob`, the + /// hook at `fund`. + function activeJobOf(address agw) external view returns (uint256); + + /// @notice The card a job was opened from. + function cardOfJob(uint256 jobId) external view returns (uint256); + + /// @notice The AGW a job was opened for. + function agwOfJob(uint256 jobId) external view returns (address); + + /// @notice The rules set granted for a job. + function rulesOfJob(uint256 jobId) external view returns (bytes32); + + /// @notice The card version a job was opened against. + function cardVersionOfJob(uint256 jobId) external view returns (uint256); + + /// @notice The AGW's CEA on `chainHash`. Reverts `ChainNotSupported` for a chain without a CEA deployment. + function computeCEA(address agw, bytes32 chainHash) external view returns (address); + + /// @notice The ERC-7579 single execution `openJob` makes the AGW run: `createJob` on the kernel. + function buildCreateJobCalldata(uint256 cardId, address owner, uint96 index, JobInputs calldata job) + external + view + returns (bytes32 mode, bytes memory executionCalldata); + + /// @notice The OwnerIntent the owner signs for `openJob`. + function previewIntent(IntentRequest calldata r, Session calldata s) external view returns (OwnerIntent memory); + + /// @notice A chain's CEA factory and proxy implementation; zero when unsupported. + function ceaDeployment(bytes32 chainHash) external view returns (address ceaFactory, address ceaProxyImpl); + + /// @notice The AGW factory. Set once, at initialization. + function AGW_FACTORY() external view returns (IAGWFactory); + + /// @notice The ERC-8183 kernel. Set once, at initialization. + function KERNEL() external view returns (IAgenticCommerce); + + /// @notice The rules-side helper (UniversalMarketplaceRules). Set once, at initialization. + function RULES() external view returns (IUniversalMarketplaceRules); + + /// @notice keccak256("eip155:" ‖ decimal(block.chainid)): Push itself, which no card may name. + function PUSH_CHAIN_HASH() external view returns (bytes32); + + /// @notice The hook new jobs get. + function hook() external view returns (address); + + /// @notice The evaluator new jobs get. + function evaluator() external view returns (address); + + /// @notice The contract's version, "2.0.0". + function version() external pure returns (string memory); +} diff --git a/plan/marketplace/contracts/src/agentic-commerce-8183/interfaces/IUniversalMarketplaceRules.sol b/plan/marketplace/contracts/src/agentic-commerce-8183/interfaces/IUniversalMarketplaceRules.sol new file mode 100644 index 00000000..e4266660 --- /dev/null +++ b/plan/marketplace/contracts/src/agentic-commerce-8183/interfaces/IUniversalMarketplaceRules.sol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import {Session} from "./external/IAGW.sol"; +import {SessionContext} from "../libraries/Types.sol"; + +/// @title IUniversalMarketplaceRules +/// @notice The rules side of an agent card: validates its `AgentCardRules` at registration, and checks the +/// owner-signed session against the card at `openJob`. EVM universal only. Reverts with +/// `UniversalMarketplaceErrors`. +interface IUniversalMarketplaceRules { + // ═══ UMR_1: RULES ═══ + + /// @notice Registration guards on a card's rules (R1-R17). Reverts `InvalidAgentCard(reason)` on the first + /// violation. + /// @dev - Assets: count, principal index, no zero, no duplicate; the principal asset's total cap is + /// `MARKER_PRINCIPAL`, its per-call cap non-zero; no marker on any other asset. + /// - Allowed calls: count, pin counts, `MARKER_WALLET` under EQ only, no identical entries, no pinless entry + /// beside a pinned one, ERC-20 approve / transfer / transferFrom pinned, no increaseAllowance. + /// @param rules `abi.encode(AgentCardRules)`. + /// @return tokens Every asset's token, for the marketplace's chain check. + function validateAgentCardRules(bytes calldata rules) external pure returns (address[] memory tokens); + + /// @notice Rules = card (C1-C14): the session grants exactly the card's rules, markers filled for this job, + /// to the card's agent, bound to this job and CEA. Reverts on the first mismatch. + /// @dev - Shape: agent, one action, one policy, envelope version, chain. + /// - Terms: assets and caps, gas cap, allowed calls and pins, expiry, expected CEA. + /// @param cardRules The card's stored `abi.encode(AgentCardRules)`. + /// @param session The owner-signed session. + /// @param ctx The job's values. + function checkRulesMatchCard(bytes calldata cardRules, Session calldata session, SessionContext calldata ctx) + external + pure; +} diff --git a/plan/marketplace/contracts/src/agentic-commerce-8183/interfaces/external/IAGW.sol b/plan/marketplace/contracts/src/agentic-commerce-8183/interfaces/external/IAGW.sol new file mode 100644 index 00000000..cff0214d --- /dev/null +++ b/plan/marketplace/contracts/src/agentic-commerce-8183/interfaces/external/IAGW.sol @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import {OwnerIntent} from "@push-agw/libraries/Types.sol"; + +/// @title IAGW — the SmartSession `Session` mirror and the Push Agentic Wallet (AGW) functions the marketplace needs. +/// @dev - Source: AGW v6, `push-agentic-wallets` commit `ffd567d` (submodule `lib/push-agentic-wallets`). +/// - The AGW's own types (`OwnerIntent`, `AllowedCall`, `UniversalTerms`, `AssetCap`, `ArgPin`, ...) are +/// IMPORTED from `@push-agw/libraries/Types.sol`, never copied: a struct change there fails this build. +/// - `Session` and its parts stay a MIRROR of the vendor SmartSession types +/// (`lib/smartsessions/contracts/DataTypes.sol` in the AGW repo, fork `7dc20e4`; field order verified +/// identical): the vendor tree pulls remappings and an EVM target this repo cannot compile. The fork test +/// (`UniversalMarketplace.fork.t.sol`) pins it — a wrong mirror changes `keccak256(abi.encode(session))`, and +/// the real wallet's `grantRulesWithSig` reverts `IntentSessionMismatch`. +/// - `Session.sessionValidator` is `ISessionValidator` upstream; a contract type is `address` in the ABI. +/// - `rulesId` is the AGW's name for the engine's `permissionId`; the two are the same value. +/// - Agent identity: the AGW's `AgentValidator` requires `sessionValidatorInitData == abi.encode(agent)`, +/// exactly 32 bytes, agent non-zero. +/// - `IAGW` below: signatures verified identical to v6 `src/interfaces/IAGW.sol`. + +// ─────────────────────────────── SmartSession ─────────────────────────────── + +struct PolicyData { + address policy; + bytes initData; +} + +struct ActionData { + bytes4 actionTargetSelector; + address actionTarget; + PolicyData[] actionPolicies; +} + +struct ERC7739Context { + bytes32 appDomainSeparator; + string[] contentNames; +} + +struct ERC7739Data { + ERC7739Context[] allowedERC7739Content; + PolicyData[] erc1271Policies; +} + +struct Session { + address sessionValidator; + bytes sessionValidatorInitData; + bytes32 salt; + PolicyData[] userOpPolicies; + ERC7739Data erc7739Policies; + ActionData[] actions; + bool permitERC4337Paymaster; +} + +// ─────────────────────────────── the wallet ─────────────────────────────── + +/// @title IAGW — the wallet functions the marketplace calls. +interface IAGW { + /// @notice `grantRules`, authorised by the owner's signed OwnerIntent. + function grantRulesWithSig(Session calldata session, OwnerIntent calldata intent, bytes calldata sig) + external + returns (bytes32 rulesId); + + /// @notice The owner door, authorised by the owner's signed OwnerIntent. + function executeWithSig( + bytes32 mode, + bytes calldata executionCalldata, + OwnerIntent calldata intent, + bytes calldata sig + ) external; + + /// @notice Next expected sequence number in a replay lane. + function getNonce(uint192 nonceKey) external view returns (uint64); + + /// @notice The grant nonce the next grant will consume. + function grantNonce() external view returns (uint64); +} diff --git a/plan/marketplace/contracts/src/agentic-commerce-8183/interfaces/external/IAGWFactory.sol b/plan/marketplace/contracts/src/agentic-commerce-8183/interfaces/external/IAGWFactory.sol new file mode 100644 index 00000000..96b9ea57 --- /dev/null +++ b/plan/marketplace/contracts/src/agentic-commerce-8183/interfaces/external/IAGWFactory.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import {OwnerIntent} from "@push-agw/libraries/Types.sol"; + +/// @title IAGWFactory +/// @notice The Push Agentic Wallet factory — the functions this repo calls. +/// @dev - Source: AGW v6, `push-agentic-wallets` commit `ffd567d`, `src/interfaces/IAGWFactory.sol`; every +/// signature below verified identical. +/// - `isWallet` is what RulesBindingHook reads; the rest is what UniversalMarketplace reads. +/// - The v6 factory proxy is a deploy-time input, never a constant. +interface IAGWFactory { + /// @notice True only for wallets this factory deployed. + /// @param account Address to test. + /// @return Whether it is an AGW. + function isWallet(address account) external view returns (bool); + + /// @notice Deploys wallet `intent.index` for `intent.owner`, on the owner's signature. + function deployWalletWithSig(OwnerIntent calldata intent, bytes calldata sig, string calldata label) + external + returns (address wallet); + + /// @notice The address wallet `index` of `owner` has, or will have. + function predictWallet(address owner, uint256 index) external view returns (address wallet, bool deployed); + + /// @notice How many wallets `owner` has; also the index the next deploy takes. + function walletCount(address owner) external view returns (uint256); + + /// @notice The owner of `wallet`, or address(0) if this factory did not deploy it. + function ownerOf(address wallet) external view returns (address); +} diff --git a/plan/marketplace/contracts/src/agentic-commerce-8183/interfaces/external/ISmartSession.sol b/plan/marketplace/contracts/src/agentic-commerce-8183/interfaces/external/ISmartSession.sol new file mode 100644 index 00000000..a71030ea --- /dev/null +++ b/plan/marketplace/contracts/src/agentic-commerce-8183/interfaces/external/ISmartSession.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +/// @title ISmartSession +/// @notice Read-only mirror of the SmartSession engine used by Push AGWs. +/// @dev - Source: the SmartSession fork `7dc20e4` vendored by AGW v6 (`push-agentic-wallets` commit `ffd567d`). +/// - `PermissionId` is a user-defined `bytes32`; the ABI is plain `bytes32`. +/// - The id comes FIRST here, unlike the engine's other views. +/// - The v6 engine address is a deploy-time input, never a constant. +interface ISmartSession { + /// @notice Whether a rules set is live on an account. + /// @param permissionId The rules set's id (the AGW's `rulesId`; the engine names it `permissionId`). + /// @param account The wallet. + /// @return Whether the permission is enabled. + function isPermissionEnabled(bytes32 permissionId, address account) external view returns (bool); +} diff --git a/plan/marketplace/contracts/src/agentic-commerce-8183/libraries/Errors.sol b/plan/marketplace/contracts/src/agentic-commerce-8183/libraries/Errors.sol new file mode 100644 index 00000000..ac8a76df --- /dev/null +++ b/plan/marketplace/contracts/src/agentic-commerce-8183/libraries/Errors.sol @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +/// @title UniversalMarketplaceErrors +/// @notice Every error the marketplace, its rules helper and JobSpecBuilder raise. +/// @dev A library error has the same selector wherever it is raised, so a helper's revert bubbles through the +/// marketplace with the selector its callers expect. +library UniversalMarketplaceErrors { + // ───────── config and cards ───────── + + error ZeroAddress(); + error HookNotWhitelisted(); + error AgentCardInactive(); + /// @dev The caller is not the card's provider (or the card does not exist). + error CallerIsNotProvider(); + error AgentCardDisabled(uint256 cardId); + error ChainNotSupported(bytes32 chainHash); + /// @dev The single registration error; every `reason` is listed in the reference (Appendix B of PRD 12). + error InvalidAgentCard(string reason); + /// @dev `provided` is not the card's `current` version (openJob, verifyAgentCard). + error AgentCardVersionMismatch(uint256 provided, uint256 current); + /// @dev `updateAgentCard` tried to change the card's execution chain. + error AgentCardIdentityImmutable(); + /// @dev One card per provider; a disabled card still counts. + error AgentCardAlreadyRegistered(address provider); + + // ───────── openJob: the job ───────── + + error PrincipalOutOfRange(); + error ExpiryOutOfRange(); + error ExecuteByOutOfRange(); + /// @dev The configured evaluator is the card's provider (the evaluator changed after registration). + error ProviderIsEvaluator(); + error ParamCountMismatch(uint256 expected, uint256 actual); + error ParamOutOfRange(uint256 index, int256 value); + /// @dev A PRINCIPAL_BPS target overflows: `principal × bps` does not fit uint256. + error TargetOverflow(uint256 check); + /// @dev The card's template writes fill `fill` of read `read` outside that read's args. + error FillOutOfBounds(uint256 read, uint256 fill); + + // ───────── openJob: wallet and intent (same shapes as the AGW's errors of the same name) ───────── + + error IntentWalletMismatch(address expected, address provided); + error ExecutorMismatch(address expected, address actual); + error IntentSessionMismatch(bytes32 actual); + error IntentExecMismatch(bytes32 actualCalldataHash); + /// @dev The wallet's last job opened here is still active (`activeJobOf`). + error WalletHasActiveJob(address agw, uint256 jobId); + error AGWMismatch(address expected, address actual); + error WalletOwnerMismatch(address expected, address actual); + + // ───────── openJob: rules = card ───────── + + error AgentMismatch(); + error ActionCount(); + error PolicyShape(uint256 i); + /// @dev The envelope's first word is not `ENVELOPE_VERSION`; 0 when the envelope is shorter than one word. + error EnvelopeVersionMismatch(uint256 actual); + error ChainMismatch(uint256 i); + error AssetCountMismatch(uint256 expected, uint256 actual); + error AssetMismatch(uint256 index); + error PrincipalCapMismatch(); + error GasCapMismatch(); + error ActionsMismatch(); + /// @dev Pin `pin` of allowed call `call` does not hold the card's value, with markers filled in. + error PinMismatch(uint256 call, uint256 pin); + error ExpiryMismatch(); + error ExpectedCEAMismatch(address expected, address actual); + + // ───────── openJob: the created job ───────── + + error UnexpectedJobCount(uint256 before, uint256 afterCount); + error JobMismatch(); +} + +/// @title RulesBindingHookErrors +/// @notice The errors of the interim job hook. +library RulesBindingHookErrors { + /// @notice `fund.optParams` is not exactly 32 bytes. + error InvalidOptParams(uint256 length); + /// @notice The funding client is not a factory-deployed AGW. + error CallerIsNotAGW(address caller); + /// @notice The rules set is not enabled on this AGW. + error RulesNotLive(address agw, bytes32 rulesId); + /// @notice The AGW already has a Funded or Submitted job under this hook. + error AGWHasLiveJob(address agw, uint256 liveJobId); +} + +/// @title ERC8183HookErrors +/// @notice The errors of BaseERC8183Hook, shared by every hook built on it. +library ERC8183HookErrors { + /// @notice Caller is not the kernel. + error CallerIsNotKernel(address caller); + /// @notice A required address is zero. + error ZeroAddress(); +} diff --git a/plan/marketplace/contracts/src/agentic-commerce-8183/libraries/JobSpecBuilder.sol b/plan/marketplace/contracts/src/agentic-commerce-8183/libraries/JobSpecBuilder.sol new file mode 100644 index 00000000..b6dcbced --- /dev/null +++ b/plan/marketplace/contracts/src/agentic-commerce-8183/libraries/JobSpecBuilder.sol @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import {IUniversalMarketplace} from "../interfaces/IUniversalMarketplace.sol"; +import {UniversalMarketplaceErrors} from "./Errors.sol"; +import {Read, Check, JobSpec} from "./JobSpecTypes.sol"; +import { + FillSource, + Fill, + ReadTemplate, + TargetSource, + CheckTemplate, + ParamBounds, + JobSpecTemplate, + BuildContext +} from "./Types.sol"; + +/// @title JobSpecBuilder +/// @notice Turns a card's `jobSpecTemplate` into one job's criteria, a `JobSpec` (the `createJob` description). +/// @dev - Builds only: it never judges a template. Whether the UniversalEvaluator can run the criteria is the +/// provider's responsibility, and the card's verified tag is the review (PRD 09 Z6). +/// - Checks only what building needs: the job's params against the template's bounds, every fill inside its +/// read's args, and a PRINCIPAL_BPS product that fits. Anything else malformed reverts on its own +/// (out-of-range index, unsupported CEA chain). +/// - External library: deployed once and linked into the marketplace, which DELEGATECALLs it. Inlined, it +/// put the marketplace over the size limit (23,821 B even at 1 optimizer run). +/// - Runs in the caller's context: the CEA comes from the caller's own `computeCEA`. +/// - `logic` and `allowedMutability` are copied verbatim; neither is judged here. +library JobSpecBuilder { + uint256 internal constant BPS = 10_000; + + /// @notice `abi.encode(JobSpec)` for one job. + /// @param jobSpecTemplate The card's `abi.encode(JobSpecTemplate)`. + /// @param ctx The job's values. + function build(bytes memory jobSpecTemplate, BuildContext memory ctx) public view returns (bytes memory) { + JobSpecTemplate memory t = abi.decode(jobSpecTemplate, (JobSpecTemplate)); + _checkParams(t.params, ctx.params); + address[] memory cea = _ceas(t, ctx.agw); + + JobSpec memory spec; + spec.executeBy = uint64(ctx.executeBy); + spec.failFinalAt = uint64(ctx.executeBy) + ctx.settleWindow; + spec.origin = ctx.origin; + spec.logic = t.logic; + spec.allowedMutability = t.allowedMutability; + spec.reads = new Read[](t.reads.length); + for (uint256 i; i < t.reads.length; ++i) { + spec.reads[i] = _buildRead(t.reads[i], i, ctx.params, cea[i]); + } + spec.checks = new Check[](t.checks.length); + for (uint256 j; j < t.checks.length; ++j) { + spec.checks[j] = _buildCheck(t.checks[j], j, ctx, cea); + } + return abi.encode(spec); + } + + /// @dev One per template param, each inside its inclusive bounds. + function _checkParams(ParamBounds[] memory bounds, int256[] memory params) private pure { + if (params.length != bounds.length) { + revert UniversalMarketplaceErrors.ParamCountMismatch(bounds.length, params.length); + } + for (uint256 i; i < params.length; ++i) { + if (params[i] < bounds[i].min || params[i] > bounds[i].max) { + revert UniversalMarketplaceErrors.ParamOutOfRange(i, params[i]); + } + } + } + + /// @dev The AGW's CEA for every read that needs one (a CEA fill, or a CEA-target check on it), else zero. + function _ceas(JobSpecTemplate memory t, address agw) private view returns (address[] memory cea) { + cea = new address[](t.reads.length); + for (uint256 i; i < t.reads.length; ++i) { + if (_hasCEAFill(t.reads[i])) cea[i] = _ceaOf(agw, t.reads[i]); + } + for (uint256 j; j < t.checks.length; ++j) { + uint8 r = t.checks[j].read; + if (t.checks[j].source == TargetSource.CEA && cea[r] == address(0)) { + cea[r] = _ceaOf(agw, t.reads[r]); + } + } + } + + function _hasCEAFill(ReadTemplate memory r) private pure returns (bool) { + for (uint256 f; f < r.fills.length; ++f) { + if (r.fills[f].source == FillSource.CEA) return true; + } + return false; + } + + /// @dev The template read, with its fills written into a fresh copy of `args`. + function _buildRead(ReadTemplate memory r, uint256 i, int256[] memory params, address cea) + private + pure + returns (Read memory) + { + bytes memory args = bytes.concat(r.args); // a copy: the template stays untouched + for (uint256 f; f < r.fills.length; ++f) { + Fill memory fill = r.fills[f]; + uint256 at = 32 * uint256(fill.word); + if (at + 32 > args.length) revert UniversalMarketplaceErrors.FillOutOfBounds(i, f); + bytes32 word = fill.source == FillSource.CEA + ? bytes32(uint256(uint160(cea))) + : bytes32(uint256(params[fill.param])); + // solhint-disable-next-line no-inline-assembly + assembly ("memory-safe") { + mstore(add(add(args, 0x20), at), word) + } + } + return Read({ + chainNamespace: r.chainNamespace, + chainId: r.chainId, + minConfirmations: r.minConfirmations, + target: r.target, + selector: r.selector, + args: args, + outputs: r.outputs, + field: r.field + }); + } + + /// @dev The check with its target resolved. + function _buildCheck(CheckTemplate memory c, uint256 j, BuildContext memory ctx, address[] memory cea) + private + pure + returns (Check memory) + { + int256 target = c.value; + if (c.source == TargetSource.PRINCIPAL_BPS) { + uint256 bps = uint256(c.value); + if (ctx.principal > type(uint256).max / bps) revert UniversalMarketplaceErrors.TargetOverflow(j); + // forge-lint: disable-next-line(unsafe-typecast) + target = int256((ctx.principal * bps) / BPS); // ≤ uint256.max / 10_000 < int256.max: cannot truncate + } else if (c.source == TargetSource.PARAM) { + target = ctx.params[uint256(c.value)]; + } else if (c.source == TargetSource.CEA) { + target = int256(uint256(uint160(cea[c.read]))); + } + return Check({read: c.read, evaluation: c.evaluation, operation: c.operation, target: target}); + } + + /// @dev The AGW's CEA on the read's chain, from the caller (the marketplace, under DELEGATECALL). The key is + /// keccak256 of the read's CAIP-2 string; an unsupported chain reverts `ChainNotSupported`. + function _ceaOf(address agw, ReadTemplate memory r) private view returns (address) { + bytes32 chainHash = keccak256(abi.encodePacked(r.chainNamespace, ":", r.chainId)); + return IUniversalMarketplace(address(this)).computeCEA(agw, chainHash); + } +} diff --git a/plan/marketplace/contracts/src/agentic-commerce-8183/libraries/JobSpecTypes.sol b/plan/marketplace/contracts/src/agentic-commerce-8183/libraries/JobSpecTypes.sol new file mode 100644 index 00000000..c19af258 --- /dev/null +++ b/plan/marketplace/contracts/src/agentic-commerce-8183/libraries/JobSpecTypes.sol @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +/// @title JobSpecTypes — the evaluation criteria of an ERC-8183 job +/// @notice One definition, shared by everything that writes or reads a job's criteria: +/// - UniversalMarketplace builds a `JobSpec` and stores `abi.encode(spec)` as the job's description; +/// - the UniversalHook decodes it at `fund` and freezes it; +/// - the UniversalEvaluator fires its reads and judges its checks and `logic`. +/// @dev - Source: `docs-internal/Universal Evaluator V2 Design`, plus `origin` (marketplace PRD decision Z7) and +/// `allowedMutability` (carried, not enforced, by the marketplace). +/// - Field order is ABI. Never reorder, never insert; a change here changes every description. + +/// @notice How a check compares. BOOLEAN / COMPARE use the value now; NUMBER / PERCENTAGE use the change since the +/// baseline. +enum Evaluation { + BOOLEAN, + COMPARE, + NUMBER, + PERCENTAGE +} + +/// @notice The comparison operator: == != > >= < <=. +enum Operation { + EQUAL, + NOT_EQUAL, + GREATER_THAN, + GREATER_OR_EQUAL, + LESS_THAN, + LESS_OR_EQUAL +} + +/// @notice How a logic step combines its checks and child steps. +enum LogicKind { + ALL, + ANY, + AT_LEAST +} + +/// @notice Who may propose a replacement JobSpec at setBudget. Carried, not enforced, by the marketplace. +enum AllowedMutability { + NONE, + CLIENT, + PROVIDER, + BOTH +} + +/// @notice One contract call on one chain, and which value in its answer to use. +struct Read { + // namespace only ("eip155"), with chainId separate — the Read State split (AGW doc D6); + // AgentCard.chainNamespace is the full CAIP-2 string + string chainNamespace; + string chainId; // e.g. "8453" + uint16 minConfirmations; // confirmations this chain needs before the answer counts + address target; // the contract to call + bytes4 selector; // the view function + bytes args; // abi-encoded arguments + bytes outputs; // the function's return types, as T_* codes + uint8[] field; // which returned value, by ABI position: [0] = 1st return value, [0, 2] = its 3rd field +} + +/// @notice One comparison on one read. +struct Check { + uint8 read; // index into reads + Evaluation evaluation; + Operation operation; + int256 target; // in the contract's own units +} + +/// @notice One logic step. `logic[0]` is the root. `checks` index into checks; `children` index into logic, +/// each greater than this step's own index. `k` is used by AT_LEAST only. +/// @dev AT_LEAST: `k` of the step's checks and children together pass. The marketplace copies the array verbatim +/// and never evaluates it: the semantics are evaluator-owned. +struct Logic { + LogicKind kind; + uint8[] checks; + uint8[] children; + uint8 k; +} + +/// @notice A job's criteria. `logic[0]` is the root: the job passes if it passes. +struct JobSpec { + Read[] reads; + Check[] checks; + Logic[] logic; + AllowedMutability allowedMutability; // copied from the card's template; not read in this repo + bytes32 origin; // keccak256(abi.encode(marketplace, cardId, cardVersion, principal)); opaque to hook and evaluator + uint64 executeBy; // the provider must execute before this + uint64 failFinalAt; // a FAIL only counts from a verify started after this +} + +// ─────────────────────────────── return-type codes (`Read.outputs`) ─────────────────────────────── + +uint8 constant T_UINT = 1; +uint8 constant T_INT = 2; +uint8 constant T_BOOL = 3; +uint8 constant T_ADDRESS = 4; +uint8 constant T_BYTESN = 5; +uint8 constant T_BYTES = 6; +uint8 constant T_STRING = 7; +uint8 constant T_TUPLE = 8; +uint8 constant T_ARRAY = 9; +uint8 constant T_FIXED_ARRAY = 10; + +// ─────────────────────────────── limits ─────────────────────────────── + +uint256 constant MAX_READS = 16; +uint256 constant MAX_CHECKS = 16; +uint256 constant MAX_LOGIC = 32; diff --git a/plan/marketplace/contracts/src/agentic-commerce-8183/libraries/Types.sol b/plan/marketplace/contracts/src/agentic-commerce-8183/libraries/Types.sol new file mode 100644 index 00000000..290dde4d --- /dev/null +++ b/plan/marketplace/contracts/src/agentic-commerce-8183/libraries/Types.sol @@ -0,0 +1,199 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import {AssetCap, AllowedCall, OwnerIntent} from "@push-agw/libraries/Types.sol"; +import {Session} from "../interfaces/external/IAGW.sol"; +import {Evaluation, Operation, Logic, AllowedMutability} from "./JobSpecTypes.sol"; + +/// @title Types — the UniversalMarketplace package's structs, enums and markers, file-level. +/// @dev - Cards, jobs and init: the marketplace (UniversalMarketplace, IUniversalMarketplace). +/// - `AgentCardRules`, `SessionContext`, the markers: the rules helper (UniversalMarketplaceRules). +/// - The criteria template: JobSpecBuilder. The built criteria (`JobSpec`) stay in JobSpecTypes.sol, the wire +/// format shared with the UniversalHook and the UniversalEvaluator. +/// - AGW types (`AssetCap`, `AllowedCall`, `OwnerIntent`, ...) are imported from AGW v6, never copied. + +// ─────────────────────────────── markers (D2, D3) ─────────────────────────────── +// +// Published constants: the SDK uses the same values. A card holds a marker; the signed session holds the value the +// marketplace fills in for this job. Both have non-zero high 96 bits, so neither is a clean address word. + +/// @dev In a card: "the user's account (CEA) on the card's chain". EQ pins only. +/// keccak256("push.marketplace.marker.WALLET"). +bytes32 constant MARKER_WALLET = 0x38beb8621ef19c2ac125b45b1ac07225511365301161eb56ac7a21aa8641cf5a; +/// @dev In a card: "this job's principal". Pins (EQ or MAX) and the principal asset's caps (as uint256). +/// keccak256("push.marketplace.marker.PRINCIPAL"). +bytes32 constant MARKER_PRINCIPAL = 0xc12ba2e9bfe16dd303c04d7f517245a6b49fd69f9d0e5c82d14be8c18ef34d52; + +// ─────────────────────────────── cards, jobs, init ─────────────────────────────── + +/// @notice One standing offer from one provider: one job type on one EVM execution chain. One card per provider. +/// @dev - `provider` and `active` are contract-written; caller values are ignored. +/// - `chainNamespace` is immutable after registration. +struct AgentCard { + address provider; // msg.sender at registration · the rules agent · 8183 provider · fee recipient + bytes32 jobType; // e.g. keccak256("LENDING_DEPOSIT") + string metadataURI; // off-chain JSON: name, summary, ABIs, criteria in words, param units + bytes32 metadataHash; // keccak256 of that JSON + string chainNamespace; // full CAIP-2 execution chain, "eip155:", never Push + uint256 providerFee; // reference price in paymentToken; the client funds against it (not enforced on-chain) + address paymentToken; // until the kernel's K-12, must equal KERNEL.paymentToken() + uint256 principalMin; // the job's size, in the principal asset's units + uint256 principalMax; + uint32 minDuration; // job expiry window, seconds from openJob + uint32 maxDuration; + uint32 minExecuteWindow; // executeBy ≥ openJob time + this + uint32 settleWindow; // failFinalAt = executeBy + this; executeBy + this ≤ expiredAt + bool active; +} + +/// @notice What the agent needs. Approvals are allowed calls under pins (D1); markers fill per job (D2, D3). +/// @dev `expectedCEA`, `validUntil` and the principal asset's caps are per job. +struct AgentCardRules { + AssetCap[] assets; // 1..MAX_ASSETS PRC20s on Push, each SOURCE_CHAIN_NAMESPACE == card chain + uint8 principalAsset; // index into assets; its maxTotal is MARKER_PRINCIPAL + uint256 maxGasPerCall; // PC wei per outbound, copied to the session exactly + AllowedCall[] allowedCalls; // 1..32; pins may hold MARKER_WALLET / MARKER_PRINCIPAL +} + +/// @notice A destination chain's CEA factory and proxy implementation, for `computeCEA`. +struct CEADeployment { + address ceaFactory; + address ceaProxyImpl; +} + +/// @notice The full card, for the SDK. One call. +struct AgentCardView { + AgentCard card; + bytes rules; // abi.encode(AgentCardRules) + bytes jobSpecTemplate; // abi.encode(JobSpecTemplate) + uint256 version; + bool verified; + bool disabled; +} + +/// @notice Per-job inputs the owner signs (inside the createJob calldata and the session). +struct JobInputs { + uint256 principal; + uint48 expiredAt; + uint48 executeBy; + int256[] params; // one per template param, within its bounds +} + +/// @notice Everything `openJob` needs. +struct OpenJobParams { + uint256 cardId; + uint256 cardVersion; // the version the owner signed against + JobInputs job; + Session session; + OwnerIntent intent; + bytes sig; + string label; // wallet label, used only when deploying +} + +/// @notice What `previewIntent` needs to build the OwnerIntent the owner signs. +struct IntentRequest { + uint256 cardId; + address owner; + uint96 index; + JobInputs job; + uint48 deadline; + uint256 signerChainId; +} + +/// @notice `initialize` arguments. Every field must be non-zero. +struct InitParams { + address agwFactory; + address kernel; + address hook; // must be whitelisted on the kernel + address evaluator; // the marketplace-wide 8183 evaluator + address rules; // UniversalMarketplaceRules + address admin; // receives DEFAULT_ADMIN_ROLE and ADMIN_ROLE +} + +// ─────────────────────────────── rules check (UniversalMarketplaceRules) ─────────────────────────────── + +/// @notice The per-job values `checkRulesMatchCard` checks the session against. +struct SessionContext { + address agent; // card.provider + bytes32 chainHash; // keccak256(bytes(card.chainNamespace)) + uint256 principal; + uint48 expiredAt; + address expectedCEA; // the AGW's CEA on the card's chain, derived by the marketplace +} + +// ─────────────────────────────── a card's criteria template ─────────────────────────────── +// +// The V2 JobSpec with holes. The card fixes everything that is the same for every job; `JobSpecBuilder.build` +// fills in the per-job values (the AGW's CEA, the principal, the user's params, the times). + +/// @notice Where a fill's 32-byte word comes from. CEA = the AGW's CEA on the READ's chain. +enum FillSource { + CEA, + PARAM +} + +/// @notice Overwrites `args[32·word : 32·word + 32]` per job. `param` is used by PARAM only. +struct Fill { + uint8 word; + FillSource source; + uint8 param; +} + +/// @notice A `Read` with fills. Copied into the JobSpec, then filled. +struct ReadTemplate { + // namespace only ("eip155"), with chainId separate — the Read State split (AGW doc D6); + // AgentCard.chainNamespace is the full CAIP-2 string + string chainNamespace; + string chainId; // e.g. "1" + uint16 minConfirmations; + address target; + bytes4 selector; + bytes args; + Fill[] fills; + bytes outputs; + uint8[] field; +} + +/// @notice Where a check's target comes from. +enum TargetSource { + FIXED, + PRINCIPAL_BPS, + PARAM, + CEA +} + +/// @notice A `Check` whose target is a source. `value`: FIXED the target · PRINCIPAL_BPS bps of principal · +/// PARAM a param index · CEA unused (the CEA of the check's read chain). +struct CheckTemplate { + uint8 read; + Evaluation evaluation; + Operation operation; + TargetSource source; + int256 value; +} + +/// @notice Inclusive bounds on one per-job number the user supplies. +struct ParamBounds { + int256 min; + int256 max; +} + +/// @notice The whole template, stored on the card as `abi.encode(JobSpecTemplate)`. `logic` and +/// `allowedMutability` are copied verbatim. +struct JobSpecTemplate { + ReadTemplate[] reads; + CheckTemplate[] checks; + Logic[] logic; + AllowedMutability allowedMutability; + ParamBounds[] params; +} + +/// @notice The per-job values `build` fills in. +struct BuildContext { + address agw; + uint256 principal; + uint48 executeBy; + uint32 settleWindow; + int256[] params; + bytes32 origin; +} diff --git a/plan/marketplace/contracts/test/8183-tests/AgenticCommerce.admin.t.sol b/plan/marketplace/contracts/test/8183-tests/AgenticCommerce.admin.t.sol new file mode 100644 index 00000000..df8ddea9 --- /dev/null +++ b/plan/marketplace/contracts/test/8183-tests/AgenticCommerce.admin.t.sol @@ -0,0 +1,369 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import {IAccessControl} from "@openzeppelin/contracts/access/IAccessControl.sol"; +import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; +import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; +import {ITransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import {ERC1967Utils} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol"; + +import {AgenticCommerce} from "../../src/agentic-commerce-8183/AgenticCommerce.sol"; +import {IAgenticCommerce} from "../../src/agentic-commerce-8183/interfaces/IAgenticCommerce.sol"; +import {KernelBase} from "./KernelBase.t.sol"; +import {MockERC20_6} from "./mocks/MockERC20_6.sol"; +import {RecordingHook} from "./mocks/RecordingHook.sol"; + +/// @notice Kernel: initialisation, upgrade, storage layout, admin functions. +contract AgenticCommerceAdminTest is KernelBase { + // ───────────── initialisation ───────────── + + function test_initialize_setsState() public view { + assertEq(address(kernel.paymentToken()), address(token)); + assertEq(kernel.platformTreasury(), treasury); + assertTrue(kernel.hasRole(kernel.DEFAULT_ADMIN_ROLE(), admin)); + assertTrue(kernel.hasRole(kernel.ADMIN_ROLE(), admin)); + assertTrue(kernel.whitelistedHooks(address(0))); + assertEq(kernel.platformFeeBP(), 0); + assertEq(kernel.evaluatorFeeBP(), 0); + assertEq(kernel.jobCounter(), 0); + assertEq(kernel.totalEscrowed(), 0); + } + + function test_constants() public view { + assertEq(kernel.ADMIN_ROLE(), keccak256("ADMIN_ROLE")); + assertEq(kernel.EVALUATOR_GRACE_PERIOD(), 1 hours); + assertEq(kernel.MIN_EXPIRY_WINDOW(), 5 minutes); + assertEq(kernel.BPS_DENOMINATOR(), 10_000); + } + + function test_initialize_revertsOnZeroToken() public { + vm.expectRevert(IAgenticCommerce.ZeroAddress.selector); + _deployKernelProxy(address(kernelImpl), address(0), treasury, admin); + } + + function test_initialize_revertsOnZeroTreasury() public { + vm.expectRevert(IAgenticCommerce.ZeroAddress.selector); + _deployKernelProxy(address(kernelImpl), address(token), address(0), admin); + } + + function test_initialize_revertsOnZeroAdmin() public { + vm.expectRevert(IAgenticCommerce.ZeroAddress.selector); + _deployKernelProxy(address(kernelImpl), address(token), treasury, address(0)); + } + + function test_initialize_secondCallReverts() public { + vm.expectRevert(Initializable.InvalidInitialization.selector); + kernel.initialize(address(token), treasury, admin); + } + + function test_initialize_onImplementationReverts() public { + vm.expectRevert(Initializable.InvalidInitialization.selector); + kernelImpl.initialize(address(token), treasury, admin); + } + + // ───────────── upgrade ───────────── + + function test_upgrade_byProxyAdminOwner_preservesState() public { + uint256 jobId = _funded(address(0), BUDGET); + AgenticCommerce newImpl = new AgenticCommerce(); + ProxyAdmin pa = ProxyAdmin(_proxyAdmin(address(kernel))); + assertEq(pa.owner(), kernelProxyAdminOwner); + + vm.prank(kernelProxyAdminOwner); + pa.upgradeAndCall(ITransparentUpgradeableProxy(address(kernel)), address(newImpl), ""); + + assertEq( + address(uint160(uint256(vm.load(address(kernel), ERC1967Utils.IMPLEMENTATION_SLOT)))), address(newImpl) + ); + assertEq(kernel.totalEscrowed(), BUDGET); + assertEq(uint8(_status(jobId)), uint8(IAgenticCommerce.JobStatus.Funded)); + assertTrue(kernel.hasRole(kernel.ADMIN_ROLE(), admin)); + assertEq(kernel.jobCounter(), 1); + } + + function test_upgrade_byStranger_reverts() public { + ProxyAdmin pa = ProxyAdmin(_proxyAdmin(address(kernel))); + address newImpl = address(new AgenticCommerce()); + vm.prank(stranger); + vm.expectRevert(abi.encodeWithSelector(Ownable.OwnableUnauthorizedAccount.selector, stranger)); + pa.upgradeAndCall(ITransparentUpgradeableProxy(address(kernel)), newImpl, ""); + } + + function test_upgrade_byAdminRoleHolder_reverts() public { + ProxyAdmin pa = ProxyAdmin(_proxyAdmin(address(kernel))); + address newImpl = address(new AgenticCommerce()); + vm.prank(admin); + vm.expectRevert(abi.encodeWithSelector(Ownable.OwnableUnauthorizedAccount.selector, admin)); + pa.upgradeAndCall(ITransparentUpgradeableProxy(address(kernel)), newImpl, ""); + } + + // ───────────── storage layout (by slot, PRD §4.1.4) ───────────── + + function test_storageLayout_bySlot() public { + vm.startPrank(admin); + kernel.setPlatformFee(123, treasury); + kernel.setEvaluatorFee(45); + vm.stopPrank(); + uint256 jobId = _funded(address(0), BUDGET); + + assertEq(address(uint160(uint256(vm.load(address(kernel), bytes32(uint256(0)))))), address(token)); + assertEq(uint256(vm.load(address(kernel), bytes32(uint256(1)))), 123); + assertEq(address(uint160(uint256(vm.load(address(kernel), bytes32(uint256(2)))))), treasury); + assertEq(uint256(vm.load(address(kernel), bytes32(uint256(3)))), 45); + assertEq(uint256(vm.load(address(kernel), bytes32(uint256(5)))), 1); + assertEq(uint256(vm.load(address(kernel), bytes32(uint256(7)))), BUDGET); + + bytes32 jobSlot = keccak256(abi.encode(jobId, uint256(4))); + uint256 expectedWord = uint256(uint160(client)) | (uint256(uint8(IAgenticCommerce.JobStatus.Funded)) << 160); + assertEq(uint256(vm.load(address(kernel), jobSlot)), expectedWord); + + bytes32 hookSlot = keccak256(abi.encode(address(0), uint256(6))); + assertEq(uint256(vm.load(address(kernel), hookSlot)), 1); + + for (uint256 i = 8; i <= 57; i++) { + assertEq(vm.load(address(kernel), bytes32(i)), bytes32(0)); + } + } + + // ───────────── access control ───────────── + + function test_admin_functions_revertForNonAdmin() public { + bytes32 role = kernel.ADMIN_ROLE(); + bytes memory err = + abi.encodeWithSelector(IAccessControl.AccessControlUnauthorizedAccount.selector, stranger, role); + + vm.startPrank(stranger); + vm.expectRevert(err); + kernel.pause(); + vm.expectRevert(err); + kernel.unpause(); + vm.expectRevert(err); + kernel.setPlatformFee(1, treasury); + vm.expectRevert(err); + kernel.setEvaluatorFee(1); + vm.expectRevert(err); + kernel.setHookWhitelist(address(1), true); + vm.expectRevert(err); + kernel.batchDetachHook(new uint256[](0)); + vm.expectRevert(err); + kernel.emergencyWithdraw(address(token), stranger, 1); + vm.stopPrank(); + } + + // ───────────── pause ───────────── + + function test_pause_blocksEveryLifecycleFunction() public { + uint256 openJob = _create(address(0)); + uint256 noProv = _createNoProvider(address(0)); + uint256 funded = _funded(address(0), BUDGET); + uint256 submitted = _submitted(address(0), BUDGET); + _pause(); + + bytes memory paused = abi.encodeWithSelector(PausableUpgradeable.EnforcedPause.selector); + vm.prank(client); + vm.expectRevert(paused); + kernel.createJob(provider, evaluator, _expiry(), "x", address(0)); + vm.prank(client); + vm.expectRevert(paused); + kernel.setProvider(noProv, provider, ""); + vm.prank(provider); + vm.expectRevert(paused); + kernel.setBudget(openJob, 1, ""); + vm.prank(client); + vm.expectRevert(paused); + kernel.fund(openJob, 0, ""); + vm.prank(provider); + vm.expectRevert(paused); + kernel.submit(funded, bytes32(0), ""); + vm.prank(evaluator); + vm.expectRevert(paused); + kernel.complete(submitted, bytes32(0), ""); + vm.prank(evaluator); + vm.expectRevert(paused); + kernel.reject(funded, bytes32(0), ""); + } + + function test_unpause_restores() public { + _pause(); + vm.prank(admin); + kernel.unpause(); + uint256 jobId = _create(address(0)); + assertEq(jobId, 1); + } + + function test_unpause_whenNotPaused_reverts() public { + vm.prank(admin); + vm.expectRevert(PausableUpgradeable.ExpectedPause.selector); + kernel.unpause(); + } + + // ───────────── fees ───────────── + + function test_setPlatformFee() public { + address t2 = makeAddr("t2"); + vm.expectEmit(address(kernel)); + emit IAgenticCommerce.PlatformFeeUpdated(500, t2); + vm.prank(admin); + kernel.setPlatformFee(500, t2); + assertEq(kernel.platformFeeBP(), 500); + assertEq(kernel.platformTreasury(), t2); + } + + function test_setPlatformFee_zeroTreasury_reverts() public { + vm.prank(admin); + vm.expectRevert(IAgenticCommerce.ZeroAddress.selector); + kernel.setPlatformFee(1, address(0)); + } + + function test_fees_exactly10000_allowed_10001_reverts() public { + vm.startPrank(admin); + kernel.setEvaluatorFee(4000); + kernel.setPlatformFee(6000, treasury); + vm.expectRevert(IAgenticCommerce.FeesTooHigh.selector); + kernel.setPlatformFee(6001, treasury); + vm.expectRevert(IAgenticCommerce.FeesTooHigh.selector); + kernel.setEvaluatorFee(4001); + vm.stopPrank(); + } + + function test_setEvaluatorFee_emits() public { + vm.expectEmit(address(kernel)); + emit IAgenticCommerce.EvaluatorFeeUpdated(250); + vm.prank(admin); + kernel.setEvaluatorFee(250); + assertEq(kernel.evaluatorFeeBP(), 250); + } + + // ───────────── hook whitelist / detach ───────────── + + function test_setHookWhitelist() public { + address h = makeAddr("h"); + vm.expectEmit(address(kernel)); + emit IAgenticCommerce.HookWhitelistUpdated(h, true); + vm.prank(admin); + kernel.setHookWhitelist(h, true); + assertTrue(kernel.whitelistedHooks(h)); + } + + function test_setHookWhitelist_zero_reverts() public { + vm.prank(admin); + vm.expectRevert(IAgenticCommerce.ZeroAddress.selector); + kernel.setHookWhitelist(address(0), true); + } + + function test_batchDetachHook_detachesAndSkips() public { + RecordingHook hook = new RecordingHook(); + vm.prank(admin); + kernel.setHookWhitelist(address(hook), true); + uint256 hooked = _create(address(hook)); + uint256 plain = _create(address(0)); + + uint256[] memory ids = new uint256[](2); + ids[0] = hooked; + ids[1] = plain; + vm.expectEmit(address(kernel)); + emit IAgenticCommerce.HookDetached(hooked, address(hook)); + vm.prank(admin); + kernel.batchDetachHook(ids); + assertEq(kernel.getJob(hooked).hook, address(0)); + + uint256 before = hook.count(); + vm.prank(provider); + kernel.setBudget(hooked, 1, ""); + assertEq(hook.count(), before, "detached job must not call the hook"); + } + + function test_batchDetachHook_empty_isNoop() public { + vm.prank(admin); + kernel.batchDetachHook(new uint256[](0)); + } + + function test_batchDetachHook_invalidIds_revert() public { + _create(address(0)); + uint256[] memory ids = new uint256[](1); + vm.startPrank(admin); + ids[0] = 0; + vm.expectRevert(IAgenticCommerce.InvalidJob.selector); + kernel.batchDetachHook(ids); + ids[0] = 2; + vm.expectRevert(IAgenticCommerce.InvalidJob.selector); + kernel.batchDetachHook(ids); + vm.stopPrank(); + } + + function test_dewhitelistedHook_stillCalledOnExistingJob() public { + RecordingHook hook = new RecordingHook(); + vm.prank(admin); + kernel.setHookWhitelist(address(hook), true); + uint256 jobId = _create(address(hook)); + vm.prank(admin); + kernel.setHookWhitelist(address(hook), false); + + vm.prank(provider); + kernel.setBudget(jobId, 1, ""); + assertEq(hook.count(), 2); + } + + // ───────────── emergencyWithdraw (K-02, D-27) ───────────── + + function test_emergencyWithdraw_notPaused_reverts() public { + vm.prank(admin); + vm.expectRevert(PausableUpgradeable.ExpectedPause.selector); + kernel.emergencyWithdraw(address(token), admin, 1); + } + + function test_emergencyWithdraw_zeroTo_reverts() public { + _pause(); + vm.prank(admin); + vm.expectRevert(IAgenticCommerce.ZeroAddress.selector); + kernel.emergencyWithdraw(address(token), address(0), 1); + } + + function test_emergencyWithdraw_zeroToken_reverts() public { + _pause(); + vm.prank(admin); + vm.expectRevert(IAgenticCommerce.ZeroAddress.selector); + kernel.emergencyWithdraw(address(0), admin, 1); + } + + function test_emergencyWithdraw_cannotTouchEscrow() public { + _funded(address(0), BUDGET); + _funded(address(0), BUDGET); + token.mint(address(kernel), 7e6); // accidental transfer + _pause(); + + vm.prank(admin); + vm.expectRevert(abi.encodeWithSelector(IAgenticCommerce.InsufficientUnattributedBalance.selector, 7e6 + 1, 7e6)); + kernel.emergencyWithdraw(address(token), admin, 7e6 + 1); + + vm.expectEmit(address(kernel)); + emit IAgenticCommerce.EmergencyWithdraw(address(token), admin, 7e6); + vm.prank(admin); + kernel.emergencyWithdraw(address(token), admin, 7e6); + assertEq(token.balanceOf(admin), 7e6); + assertEq(token.balanceOf(address(kernel)), 2 * BUDGET); + } + + function test_emergencyWithdraw_otherToken_fullyWithdrawable() public { + MockERC20_6 other = new MockERC20_6("Other", "OTH"); + other.mint(address(kernel), 5e6); + _funded(address(0), BUDGET); + _pause(); + vm.prank(admin); + kernel.emergencyWithdraw(address(other), admin, 5e6); + assertEq(other.balanceOf(admin), 5e6); + } + + function test_emergencyWithdraw_balanceBelowEscrow_availableIsZero() public { + _funded(address(0), BUDGET); + // Simulate a shortfall: move tokens out of the kernel behind its back. + vm.prank(address(kernel)); + token.transfer(stranger, 1); + _pause(); + vm.prank(admin); + vm.expectRevert(abi.encodeWithSelector(IAgenticCommerce.InsufficientUnattributedBalance.selector, 1, 0)); + kernel.emergencyWithdraw(address(token), admin, 1); + } +} diff --git a/plan/marketplace/contracts/test/8183-tests/AgenticCommerce.fuzz.t.sol b/plan/marketplace/contracts/test/8183-tests/AgenticCommerce.fuzz.t.sol new file mode 100644 index 00000000..d873688b --- /dev/null +++ b/plan/marketplace/contracts/test/8183-tests/AgenticCommerce.fuzz.t.sol @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import {IAgenticCommerce} from "../../src/agentic-commerce-8183/interfaces/IAgenticCommerce.sol"; +import {KernelBase} from "./KernelBase.t.sol"; + +/// @notice Stateless fuzz over every function that moves funds. +contract AgenticCommerceFuzzTest is KernelBase { + function testFuzz_fund_movesExactBudget(uint256 budget) public { + budget = bound(budget, 0, 2 ** 96); + token.mint(client, budget); + uint256 jobId = _budgeted(address(0), budget); + uint256 before = token.balanceOf(client); + vm.prank(client); + kernel.fund(jobId, budget, ""); + assertEq(before - token.balanceOf(client), budget); + assertEq(kernel.totalEscrowed(), budget); + assertEq(token.balanceOf(address(kernel)), budget); + } + + function testFuzz_complete_conservesBudget(uint256 budget, uint256 pBP, uint256 eBP) public { + budget = bound(budget, 0, 2 ** 96); + pBP = bound(pBP, 0, 10_000); + eBP = bound(eBP, 0, 10_000 - pBP); + token.mint(client, budget); + vm.startPrank(admin); + kernel.setPlatformFee(pBP, treasury); + kernel.setEvaluatorFee(eBP); + vm.stopPrank(); + + uint256 escrowBefore = kernel.totalEscrowed(); + uint256 jobId = _submitted(address(0), budget); + vm.prank(evaluator); + kernel.complete(jobId, bytes32(0), ""); + + uint256 paid = token.balanceOf(treasury) + token.balanceOf(evaluator) + token.balanceOf(provider); + assertEq(paid, budget); + assertEq(token.balanceOf(treasury), budget * pBP / 10_000); + assertEq(token.balanceOf(evaluator), budget * eBP / 10_000); + assertEq(kernel.totalEscrowed(), escrowBefore); + } + + function testFuzz_reject_refundsClient(uint256 budget, bool submitFirst) public { + budget = bound(budget, 0, 2 ** 96); + token.mint(client, budget); + uint256 jobId = submitFirst ? _submitted(address(0), budget) : _funded(address(0), budget); + uint256 before = token.balanceOf(client); + vm.prank(evaluator); + kernel.reject(jobId, bytes32(0), ""); + assertEq(token.balanceOf(client) - before, budget); + assertEq(kernel.totalEscrowed(), 0); + } + + function testFuzz_claimRefund_refundsClient(uint256 budget, bool submitFirst) public { + budget = bound(budget, 0, 2 ** 96); + token.mint(client, budget); + uint256 jobId = submitFirst ? _submitted(address(0), budget) : _funded(address(0), budget); + vm.warp(block.timestamp + EXPIRY_OFFSET + kernel.EVALUATOR_GRACE_PERIOD()); + uint256 before = token.balanceOf(client); + kernel.claimRefund(jobId); + assertEq(token.balanceOf(client) - before, budget); + assertEq(kernel.totalEscrowed(), 0); + } + + function testFuzz_emergencyWithdraw_bound(uint256 escrowed, uint256 extra, uint256 amount) public { + escrowed = bound(escrowed, 0, 2 ** 96); + extra = bound(extra, 0, 2 ** 96); + amount = bound(amount, 0, 2 ** 97); + token.mint(client, escrowed); + _funded(address(0), escrowed); + token.mint(address(kernel), extra); + _pause(); + + vm.prank(admin); + if (amount > extra) { + vm.expectRevert( + abi.encodeWithSelector(IAgenticCommerce.InsufficientUnattributedBalance.selector, amount, extra) + ); + kernel.emergencyWithdraw(address(token), admin, amount); + } else { + kernel.emergencyWithdraw(address(token), admin, amount); + assertEq(token.balanceOf(admin), amount); + assertGe(token.balanceOf(address(kernel)), kernel.totalEscrowed()); + } + } +} diff --git a/plan/marketplace/contracts/test/8183-tests/AgenticCommerce.hooks.t.sol b/plan/marketplace/contracts/test/8183-tests/AgenticCommerce.hooks.t.sol new file mode 100644 index 00000000..363b0d67 --- /dev/null +++ b/plan/marketplace/contracts/test/8183-tests/AgenticCommerce.hooks.t.sol @@ -0,0 +1,187 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol"; + +import {IAgenticCommerce} from "../../src/agentic-commerce-8183/interfaces/IAgenticCommerce.sol"; +import {KernelBase} from "./KernelBase.t.sol"; +import {RecordingHook} from "./mocks/RecordingHook.sol"; +import {RevertingHook} from "./mocks/RevertingHook.sol"; +import {ReentrantHook} from "./mocks/ReentrantHook.sol"; + +/// @notice Kernel ↔ hook behaviour: call order, rollback, blocking, reentrancy. +contract AgenticCommerceHooksTest is KernelBase { + RecordingHook internal rec; + RevertingHook internal rh; + ReentrantHook internal re; + + function setUp() public override { + super.setUp(); + rec = new RecordingHook(); + rh = new RevertingHook(); + re = new ReentrantHook(); + vm.startPrank(admin); + kernel.setHookWhitelist(address(rec), true); + kernel.setHookWhitelist(address(rh), true); + kernel.setHookWhitelist(address(re), true); + vm.stopPrank(); + } + + // ───────────── order: before sees pre-state, after sees post-state ───────────── + + function test_callOrder_fullLifecycle() public { + vm.prank(client); + uint256 jobId = kernel.createJob(address(0), evaluator, _expiry(), "", address(rec)); + vm.prank(client); + kernel.setProvider(jobId, provider, ""); + vm.prank(provider); + kernel.setBudget(jobId, BUDGET, ""); + vm.prank(client); + kernel.fund(jobId, BUDGET, ""); + vm.prank(provider); + kernel.submit(jobId, bytes32(0), ""); + vm.prank(evaluator); + kernel.complete(jobId, bytes32(0), ""); + + bytes4[6] memory sels = [ + IAgenticCommerce.setProvider.selector, + IAgenticCommerce.setBudget.selector, + IAgenticCommerce.fund.selector, + IAgenticCommerce.submit.selector, + IAgenticCommerce.complete.selector, + bytes4(0) + ]; + uint8[6] memory preStatus = [0, 0, 0, 1, 2, 0]; + uint8[6] memory postStatus = [0, 0, 1, 2, 3, 0]; + assertEq(rec.count(), 10); + for (uint256 i = 0; i < 5; i++) { + RecordingHook.Call memory b = rec.getCall(2 * i); + RecordingHook.Call memory a = rec.getCall(2 * i + 1); + assertTrue(b.isBefore); + assertFalse(a.isBefore); + assertEq(b.selector, sels[i]); + assertEq(a.selector, sels[i]); + assertEq(b.jobId, jobId); + assertEq(b.statusSeen, preStatus[i]); + assertEq(a.statusSeen, postStatus[i]); + } + } + + function test_reject_hookEncodingAndOrder() public { + uint256 jobId = _funded(address(rec), BUDGET); + vm.prank(evaluator); + kernel.reject(jobId, bytes32("r"), hex"77"); + RecordingHook.Call memory b = rec.getCall(4); + RecordingHook.Call memory a = rec.getCall(5); + assertEq(b.selector, IAgenticCommerce.reject.selector); + assertEq(b.data, abi.encode(evaluator, bytes32("r"), hex"77")); + assertEq(b.statusSeen, uint8(IAgenticCommerce.JobStatus.Funded)); + assertEq(a.statusSeen, uint8(IAgenticCommerce.JobStatus.Rejected)); + } + + function test_complete_hookEncoding() public { + uint256 jobId = _submitted(address(rec), BUDGET); + vm.prank(evaluator); + kernel.complete(jobId, bytes32("c"), hex"55"); + assertEq(rec.getCall(6).data, abi.encode(evaluator, bytes32("c"), hex"55")); + } + + // ───────────── afterAction revert rolls the whole call back ───────────── + + function test_afterRevert_rollsBackFund() public { + uint256 jobId = _budgeted(address(rh), BUDGET); + rh.setRevertAfter(true); + uint256 before = token.balanceOf(client); + vm.prank(client); + vm.expectRevert(RevertingHook.HookSaysNo.selector); + kernel.fund(jobId, BUDGET, ""); + assertEq(token.balanceOf(client), before); + assertEq(kernel.totalEscrowed(), 0); + assertEq(uint8(_status(jobId)), uint8(IAgenticCommerce.JobStatus.Open)); + } + + function test_afterRevert_rollsBackComplete() public { + uint256 jobId = _submitted(address(rh), BUDGET); + rh.setRevertAfter(true); + vm.prank(evaluator); + vm.expectRevert(RevertingHook.HookSaysNo.selector); + kernel.complete(jobId, bytes32(0), ""); + assertEq(token.balanceOf(provider), 0); + assertEq(kernel.totalEscrowed(), BUDGET); + } + + // ───────────── a reverting hook blocks every hooked action, not claimRefund ───────────── + + function test_revertingBefore_blocksEveryHookedAction() public { + vm.prank(client); + uint256 noProv = kernel.createJob(address(0), evaluator, _expiry(), "", address(rh)); + uint256 open = _budgeted(address(rh), BUDGET); + uint256 funded = _funded(address(rh), BUDGET); + uint256 submitted = _submitted(address(rh), BUDGET); + rh.setRevertBefore(true); + bytes4 err = RevertingHook.HookSaysNo.selector; + + vm.prank(client); + vm.expectRevert(err); + kernel.setProvider(noProv, provider, ""); + vm.prank(provider); + vm.expectRevert(err); + kernel.setBudget(open, 1, ""); + vm.prank(client); + vm.expectRevert(err); + kernel.fund(open, BUDGET, ""); + vm.prank(provider); + vm.expectRevert(err); + kernel.submit(funded, bytes32(0), ""); + vm.prank(evaluator); + vm.expectRevert(err); + kernel.complete(submitted, bytes32(0), ""); + vm.prank(evaluator); + vm.expectRevert(err); + kernel.reject(funded, bytes32(0), ""); + + vm.warp(block.timestamp + EXPIRY_OFFSET); + kernel.claimRefund(funded); + assertEq(uint8(_status(funded)), uint8(IAgenticCommerce.JobStatus.Expired)); + } + + // ───────────── reentrancy ───────────── + + function _reentryPayloads() internal view returns (bytes[] memory p) { + p = new bytes[](8); + p[0] = abi.encodeCall(IAgenticCommerce.createJob, (provider, evaluator, _expiry(), "", address(0))); + p[1] = abi.encodeCall(IAgenticCommerce.setProvider, (1, provider, "")); + p[2] = abi.encodeCall(IAgenticCommerce.setBudget, (1, 1, "")); + p[3] = abi.encodeCall(IAgenticCommerce.fund, (1, 1, "")); + p[4] = abi.encodeCall(IAgenticCommerce.submit, (1, bytes32(0), "")); + p[5] = abi.encodeCall(IAgenticCommerce.complete, (1, bytes32(0), "")); + p[6] = abi.encodeCall(IAgenticCommerce.reject, (1, bytes32(0), "")); + p[7] = abi.encodeCall(IAgenticCommerce.claimRefund, (1)); + } + + function test_reentrancy_fromBefore_blockedForEveryLifecycleCall() public { + bytes[] memory payloads = _reentryPayloads(); + for (uint256 i = 0; i < payloads.length; i++) { + uint256 jobId = _create(address(re)); + re.setInAfter(false); + re.setPayload(payloads[i]); + vm.prank(provider); + vm.expectRevert(ReentrancyGuardUpgradeable.ReentrancyGuardReentrantCall.selector); + kernel.setBudget(jobId, 1, ""); + re.setPayload(""); + } + } + + function test_reentrancy_fromAfter_blocked() public { + bytes[] memory payloads = _reentryPayloads(); + for (uint256 i = 0; i < payloads.length; i++) { + uint256 jobId = _create(address(re)); + re.setInAfter(true); + re.setPayload(payloads[i]); + vm.prank(provider); + vm.expectRevert(ReentrancyGuardUpgradeable.ReentrancyGuardReentrantCall.selector); + kernel.setBudget(jobId, 1, ""); + re.setPayload(""); + } + } +} diff --git a/plan/marketplace/contracts/test/8183-tests/AgenticCommerce.invariants.t.sol b/plan/marketplace/contracts/test/8183-tests/AgenticCommerce.invariants.t.sol new file mode 100644 index 00000000..0a7f62c5 --- /dev/null +++ b/plan/marketplace/contracts/test/8183-tests/AgenticCommerce.invariants.t.sol @@ -0,0 +1,305 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import {Test} from "forge-std/Test.sol"; + +import {AgenticCommerce} from "../../src/agentic-commerce-8183/AgenticCommerce.sol"; +import {IAgenticCommerce} from "../../src/agentic-commerce-8183/interfaces/IAgenticCommerce.sol"; +import {KernelBase} from "./KernelBase.t.sol"; +import {MockERC20_6} from "./mocks/MockERC20_6.sol"; +import {RecordingHook} from "./mocks/RecordingHook.sol"; + +/// @notice Drives the kernel with random but role-correct actions and checks every transition. +/// @dev - Kernel reverts are swallowed (fail_on_revert stays false). +/// - Violations are recorded in `violation`, never asserted here — a handler revert would be swallowed too. +contract KernelHandler is Test { + AgenticCommerce internal kernel; + MockERC20_6 internal token; + address internal admin; + address internal hook; + + address[3] internal clients; + address[3] internal providers; + address[2] internal evaluators; + + mapping(uint256 => uint8) public lastStatus; + uint256 public okFund; + uint256 public okComplete; + uint256 public okExit; // reject or claimRefund from Funded/Submitted + bool public violation; + string public violationReason; + + constructor(AgenticCommerce kernel_, MockERC20_6 token_, address admin_, address hook_) { + kernel = kernel_; + token = token_; + admin = admin_; + hook = hook_; + for (uint256 i = 0; i < 3; i++) { + clients[i] = makeAddr(string.concat("c", vm.toString(i))); + providers[i] = makeAddr(string.concat("p", vm.toString(i))); + token.mint(clients[i], 1e12); + vm.prank(clients[i]); + token.approve(address(kernel), type(uint256).max); + } + evaluators[0] = makeAddr("e0"); + evaluators[1] = makeAddr("e1"); + _seed(); + } + + /// @dev Seeds one Open-budgeted, one Funded and one Submitted job so every run has escrow to move. + function _seed() internal { + uint256 exp = block.timestamp + 30 days; + for (uint256 k = 0; k < 3; k++) { + vm.prank(clients[k]); + uint256 id = kernel.createJob(providers[k], evaluators[0], exp, "seed", address(0)); + vm.prank(providers[k]); + kernel.setBudget(id, 1e6 * (k + 1), ""); + lastStatus[id] = uint8(IAgenticCommerce.JobStatus.Open); + if (k >= 1) { + vm.prank(clients[k]); + kernel.fund(id, 1e6 * (k + 1), ""); + lastStatus[id] = uint8(IAgenticCommerce.JobStatus.Funded); + } + if (k == 2) { + vm.prank(providers[k]); + kernel.submit(id, bytes32(0), ""); + lastStatus[id] = uint8(IAgenticCommerce.JobStatus.Submitted); + } + } + } + + // ───────────── actions ───────────── + + function createJob(uint256 c, uint256 p, uint256 e, uint256 expOffset, bool withProvider, bool withHook) external { + address cl = clients[c % 3]; + address pr = withProvider ? providers[p % 3] : address(0); + address ev = evaluators[e % 2]; + expOffset = bound(expOffset, 6 minutes, 30 days); + vm.prank(cl); + try kernel.createJob(pr, ev, block.timestamp + expOffset, "", withHook ? hook : address(0)) returns ( + uint256 id + ) { + lastStatus[id] = uint8(IAgenticCommerce.JobStatus.Open); + } catch {} + } + + function setProvider(uint256 j, uint256 p) external { + (uint256 id, IAgenticCommerce.Job memory job) = _pick(j); + if (id == 0) return; + vm.prank(job.client); + try kernel.setProvider(id, providers[p % 3], "") { + _check(id); + } catch {} + } + + function setBudget(uint256 j, uint256 amount) external { + (uint256 id, IAgenticCommerce.Job memory job) = _pick(j); + if (id == 0) return; + amount = bound(amount, 0, 1e9); + vm.prank(job.provider); + try kernel.setBudget(id, amount, "") { + _check(id); + } catch {} + } + + /// @dev Probes: `wrongStatus` targets any job; `wrongActor` sends from the provider. + /// A probe that succeeds is a violation (C-01). + function fund(uint256 j, bool wrongStatus, bool wrongActor) external { + (uint256 id, IAgenticCommerce.Job memory job) = + wrongStatus ? _pick(j) : _pickStatus(j, IAgenticCommerce.JobStatus.Open); + if (id == 0) return; + bool mustRevert = wrongActor || job.status != IAgenticCommerce.JobStatus.Open; + vm.prank(wrongActor ? job.provider : job.client); + try kernel.fund(id, job.budget, "") { + if (mustRevert) _fail("fund succeeded with wrong status/actor"); + _check(id); + okFund++; + } catch {} + } + + /// @dev Probes: `wrongActor` sends from the client. + function submit(uint256 j, bool wrongStatus, bool wrongActor) external { + (uint256 id, IAgenticCommerce.Job memory job) = + wrongStatus ? _pick(j) : _pickStatus(j, IAgenticCommerce.JobStatus.Funded); + if (id == 0) return; + bool mustRevert = wrongActor || job.status != IAgenticCommerce.JobStatus.Funded; + vm.prank(wrongActor ? job.client : job.provider); + try kernel.submit(id, bytes32(0), "") { + if (mustRevert) _fail("submit succeeded with wrong status/actor"); + _check(id); + } catch {} + } + + /// @dev Probes: `wrongActor` sends from the client. + function complete(uint256 j, bool wrongStatus, bool wrongActor) external { + (uint256 id, IAgenticCommerce.Job memory job) = + wrongStatus ? _pick(j) : _pickStatus(j, IAgenticCommerce.JobStatus.Submitted); + if (id == 0) return; + bool mustRevert = wrongActor || job.status != IAgenticCommerce.JobStatus.Submitted; + vm.prank(wrongActor ? job.client : job.evaluator); + try kernel.complete(id, bytes32(0), "") { + if (mustRevert) _fail("complete succeeded with wrong status/actor"); + _check(id); + okComplete++; + } catch {} + } + + /// @dev Default: evaluator on an escrowed job, or client on any job. + /// Probe `wrongActor`: Open → evaluator; Funded/Submitted → provider. Must revert. + function reject(uint256 j, bool asEvaluator, bool wrongActor) external { + (uint256 id, IAgenticCommerce.Job memory job) = (asEvaluator && !wrongActor) ? _pickEscrowed(j) : _pick(j); + if (id == 0) return; + address actor; + if (wrongActor) actor = job.status == IAgenticCommerce.JobStatus.Open ? job.evaluator : job.provider; + else actor = asEvaluator ? job.evaluator : job.client; + uint8 before = lastStatus[id]; + vm.prank(actor); + try kernel.reject(id, bytes32(0), "") { + if (wrongActor) _fail("reject succeeded with wrong actor"); + _check(id); + if (before == 1 || before == 2) okExit++; + } catch {} + } + + function claimRefund(uint256 j) external { + (uint256 id,) = _pickEscrowed(j); + if (id == 0) return; + uint8 before = lastStatus[id]; + try kernel.claimRefund(id) { + _check(id); + if (before == 1 || before == 2) okExit++; + } catch {} + } + + function warp(uint256 secs) external { + vm.warp(block.timestamp + bound(secs, 1, 2 days)); + } + + function setFees(uint256 pBP, uint256 eBP) external { + pBP = bound(pBP, 0, 10_000); + eBP = bound(eBP, 0, 10_000 - pBP); + vm.startPrank(admin); + kernel.setEvaluatorFee(0); + kernel.setPlatformFee(pBP, makeAddr("treasury")); + kernel.setEvaluatorFee(eBP); + vm.stopPrank(); + } + + // ───────────── ghost checks ───────────── + + function _pick(uint256 j) internal view returns (uint256 id, IAgenticCommerce.Job memory job) { + uint256 n = kernel.jobCounter(); + if (n == 0) return (0, job); + id = bound(j, 1, n); + job = kernel.getJob(id); + } + + /// @dev Picks the first job at or after a random start whose status is `want`; 0 if none. + function _pickStatus(uint256 j, IAgenticCommerce.JobStatus want) + internal + view + returns (uint256 id, IAgenticCommerce.Job memory job) + { + uint256 n = kernel.jobCounter(); + if (n == 0) return (0, job); + uint256 start = bound(j, 1, n); + for (uint256 k = 0; k < n; k++) { + uint256 cand = ((start - 1 + k) % n) + 1; + IAgenticCommerce.Job memory c = kernel.getJob(cand); + if (c.status == want) return (cand, c); + } + return (0, job); + } + + /// @dev A job holding escrow (Funded, else Submitted); 0 if none. + function _pickEscrowed(uint256 j) internal view returns (uint256 id, IAgenticCommerce.Job memory job) { + (id, job) = _pickStatus(j, IAgenticCommerce.JobStatus.Funded); + if (id == 0) (id, job) = _pickStatus(j, IAgenticCommerce.JobStatus.Submitted); + } + + /// @dev Called only after a successful action: the transition must be a legal edge. + function _check(uint256 id) internal { + uint8 prev = lastStatus[id]; + uint8 next = uint8(kernel.getJob(id).status); + if (prev >= 3) { + _fail("action succeeded on a terminal job"); + } else if (!_isEdge(prev, next)) { + _fail("illegal status transition"); + } + lastStatus[id] = next; + } + + function _isEdge(uint8 a, uint8 b) internal pure returns (bool) { + // 0 Open · 1 Funded · 2 Submitted · 3 Completed · 4 Rejected · 5 Expired + if (a == 0) return b == 0 || b == 1 || b == 4 || b == 5; + if (a == 1) return b == 2 || b == 4 || b == 5; + if (a == 2) return b == 3 || b == 4 || b == 5; + return false; + } + + function _fail(string memory why) internal { + if (!violation) { + violation = true; + violationReason = why; + } + } +} + +contract AgenticCommerceInvariantsTest is KernelBase { + KernelHandler internal handler; + + function setUp() public override { + super.setUp(); + RecordingHook hook = new RecordingHook(); + vm.prank(admin); + kernel.setHookWhitelist(address(hook), true); + handler = new KernelHandler(kernel, token, admin, address(hook)); + targetContract(address(handler)); + } + + function invariant_totalEscrowedMatchesLiveBudgets() public view { + uint256 sum; + uint256 n = kernel.jobCounter(); + for (uint256 i = 1; i <= n; i++) { + IAgenticCommerce.Job memory j = kernel.getJob(i); + if (j.status == IAgenticCommerce.JobStatus.Funded || j.status == IAgenticCommerce.JobStatus.Submitted) { + sum += j.budget; + } + } + assertEq(kernel.totalEscrowed(), sum); + } + + function invariant_balanceCoversEscrow() public view { + assertGe(token.balanceOf(address(kernel)), kernel.totalEscrowed()); + } + + function invariant_onlyLegalTransitions() public view { + assertFalse(handler.violation(), handler.violationReason()); + } + + /// @dev Liveness proof for the handler: a fixed 600-step pseudo-random walk must reach + /// fund, complete and a refund path, with every invariant holding at the end. + /// Lives here, not in afterInvariant, because shrunk/replayed sequences are short by design. + function test_handlerLiveness() public { + for (uint256 i = 0; i < 600; i++) { + uint256 r = uint256(keccak256(abi.encode(i))); + uint256 a = r % 10; + if (a == 0) handler.createJob(r, r >> 8, r >> 16, r >> 24, (r >> 32) % 2 == 0, (r >> 40) % 2 == 0); + else if (a == 1) handler.setProvider(r, r >> 8); + else if (a == 2) handler.setBudget(r, r >> 8); + else if (a == 3) handler.fund(r, false, false); + else if (a == 4) handler.submit(r, false, false); + else if (a == 5) handler.complete(r, false, false); + else if (a == 6) handler.reject(r, (r >> 8) % 2 == 0, false); + else if (a == 7) handler.claimRefund(r); + else if (a == 8) handler.warp(r % 3 hours); + else handler.setFees(r, r >> 8); + } + assertGt(handler.okFund(), 0, "no successful fund"); + assertGt(handler.okComplete(), 0, "no successful complete"); + assertGt(handler.okExit(), 0, "no successful refund path"); + invariant_totalEscrowedMatchesLiveBudgets(); + invariant_balanceCoversEscrow(); + invariant_onlyLegalTransitions(); + } +} diff --git a/plan/marketplace/contracts/test/8183-tests/AgenticCommerce.lifecycle.t.sol b/plan/marketplace/contracts/test/8183-tests/AgenticCommerce.lifecycle.t.sol new file mode 100644 index 00000000..c29b803f --- /dev/null +++ b/plan/marketplace/contracts/test/8183-tests/AgenticCommerce.lifecycle.t.sol @@ -0,0 +1,660 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import {Vm} from "forge-std/Vm.sol"; + +import {IAgenticCommerce} from "../../src/agentic-commerce-8183/interfaces/IAgenticCommerce.sol"; +import {KernelBase} from "./KernelBase.t.sol"; +import {RecordingHook} from "./mocks/RecordingHook.sol"; +import {RevertingHook} from "./mocks/RevertingHook.sol"; +import {ERC165Only} from "./mocks/ERC165Only.sol"; + +/// @notice Kernel lifecycle: every function, every revert in PRD order. +contract AgenticCommerceLifecycleTest is KernelBase { + RecordingHook internal rec; + + function setUp() public override { + super.setUp(); + rec = new RecordingHook(); + vm.prank(admin); + kernel.setHookWhitelist(address(rec), true); + } + + // ═════════════════════════════ createJob ═════════════════════════════ + + function test_createJob_happy_withProviderAndHook() public { + uint256 exp = _expiry(); + vm.expectEmit(address(kernel)); + emit IAgenticCommerce.JobCreated(1, client, provider, evaluator, exp, address(rec)); + vm.prank(client); + uint256 jobId = kernel.createJob(provider, evaluator, exp, "desc", address(rec)); + + assertEq(jobId, 1); + assertEq(kernel.jobCounter(), 1); + IAgenticCommerce.Job memory j = kernel.getJob(jobId); + assertEq(j.client, client); + assertEq(j.provider, provider); + assertEq(j.evaluator, evaluator); + assertEq(j.hook, address(rec)); + assertEq(j.expiredAt, exp); + assertEq(j.budget, 0); + assertEq(j.description, "desc"); + assertEq(uint8(j.status), uint8(IAgenticCommerce.JobStatus.Open)); + assertEq(rec.count(), 0, "createJob is not hooked (K-10)"); + } + + function test_createJob_happy_noProvider_noHook_evaluatorIsClient() public { + vm.prank(client); + uint256 jobId = kernel.createJob(address(0), client, _expiry(), "", address(0)); + assertEq(kernel.getJob(jobId).provider, address(0)); + assertEq(kernel.getJob(jobId).evaluator, client); + } + + function test_createJob_zeroEvaluator_reverts() public { + vm.prank(client); + vm.expectRevert(IAgenticCommerce.ZeroAddress.selector); + kernel.createJob(provider, address(0), _expiry(), "", address(0)); + } + + /// @dev Two faults at once: the earlier check in PRD order must win (C-03). + function test_createJob_precedence() public { + vm.startPrank(client); + vm.expectRevert(IAgenticCommerce.ZeroAddress.selector); // zero evaluator AND short expiry + kernel.createJob(provider, address(0), block.timestamp, "", address(0)); + vm.expectRevert(IAgenticCommerce.ExpiryTooShort.selector); // short expiry AND client == provider + kernel.createJob(client, evaluator, block.timestamp, "", address(0)); + vm.expectRevert(IAgenticCommerce.ClientIsProvider.selector); // client == provider AND bad hook + kernel.createJob(client, evaluator, _expiry(), "", makeAddr("nope")); + vm.stopPrank(); + } + + function test_createJob_expiryBoundary() public { + uint256 exact = block.timestamp + kernel.MIN_EXPIRY_WINDOW(); + vm.startPrank(client); + vm.expectRevert(IAgenticCommerce.ExpiryTooShort.selector); + kernel.createJob(provider, evaluator, exact, "", address(0)); + kernel.createJob(provider, evaluator, exact + 1, "", address(0)); + vm.stopPrank(); + } + + function test_createJob_expiryAboveUint48_reverts() public { + vm.prank(client); + vm.expectRevert(IAgenticCommerce.ExpiryTooShort.selector); + kernel.createJob(provider, evaluator, uint256(type(uint48).max) + 1, "", address(0)); + } + + function test_createJob_clientIsProvider_reverts() public { + vm.prank(client); + vm.expectRevert(IAgenticCommerce.ClientIsProvider.selector); + kernel.createJob(client, evaluator, _expiry(), "", address(0)); + } + + function test_createJob_evaluatorIsProvider_reverts() public { + vm.prank(client); + vm.expectRevert(IAgenticCommerce.EvaluatorIsProvider.selector); + kernel.createJob(provider, provider, _expiry(), "", address(0)); + } + + function test_createJob_hookNotWhitelisted_reverts() public { + vm.prank(client); + vm.expectRevert(IAgenticCommerce.HookNotWhitelisted.selector); + kernel.createJob(provider, evaluator, _expiry(), "", makeAddr("nope")); + } + + function test_createJob_invalidHook_eoa_reverts() public { + address eoaHook = makeAddr("eoaHook"); + vm.prank(admin); + kernel.setHookWhitelist(eoaHook, true); + vm.prank(client); + vm.expectRevert(IAgenticCommerce.InvalidHook.selector); + kernel.createJob(provider, evaluator, _expiry(), "", eoaHook); + } + + function test_createJob_invalidHook_erc165Only_reverts() public { + ERC165Only h = new ERC165Only(); + vm.prank(admin); + kernel.setHookWhitelist(address(h), true); + vm.prank(client); + vm.expectRevert(IAgenticCommerce.InvalidHook.selector); + kernel.createJob(provider, evaluator, _expiry(), "", address(h)); + } + + function test_getJob_unknownIds_returnZeroStruct() public { + _create(address(0)); + IAgenticCommerce.Job memory j0 = kernel.getJob(0); + IAgenticCommerce.Job memory j2 = kernel.getJob(2); + assertEq(j0.client, address(0)); + assertEq(j2.client, address(0)); + assertEq(j2.budget, 0); + } + + // ═════════════════════════════ setProvider (K-04) ═════════════════════════════ + + function test_setProvider_happy_hookedWithEncoding() public { + uint256 jobId = _createNoProvider(address(rec)); + vm.expectEmit(address(kernel)); + emit IAgenticCommerce.ProviderSet(jobId, provider); + vm.prank(client); + kernel.setProvider(jobId, provider, hex"beef"); + + assertEq(kernel.getJob(jobId).provider, provider); + assertEq(rec.count(), 2); + bytes memory expected = abi.encode(client, provider, hex"beef"); + RecordingHook.Call memory b = rec.getCall(0); + RecordingHook.Call memory a = rec.getCall(1); + assertTrue(b.isBefore); + assertFalse(a.isBefore); + assertEq(b.selector, IAgenticCommerce.setProvider.selector); + assertEq(b.data, expected); + assertEq(a.data, expected); + } + + function test_setProvider_reverts_inOrder() public { + uint256 jobId = _createNoProvider(address(0)); + + vm.startPrank(client); + vm.expectRevert(IAgenticCommerce.InvalidJob.selector); + kernel.setProvider(0, provider, ""); + vm.expectRevert(IAgenticCommerce.InvalidJob.selector); + kernel.setProvider(99, provider, ""); + vm.stopPrank(); + + vm.prank(stranger); + vm.expectRevert(IAgenticCommerce.Unauthorized.selector); + kernel.setProvider(jobId, provider, ""); + + vm.startPrank(client); + vm.expectRevert(IAgenticCommerce.ZeroAddress.selector); + kernel.setProvider(jobId, address(0), ""); + vm.expectRevert(IAgenticCommerce.ClientIsProvider.selector); + kernel.setProvider(jobId, client, ""); + vm.expectRevert(IAgenticCommerce.EvaluatorIsProvider.selector); + kernel.setProvider(jobId, evaluator, ""); + kernel.setProvider(jobId, provider, ""); + vm.expectRevert(IAgenticCommerce.WrongStatus.selector); // provider already set + kernel.setProvider(jobId, makeAddr("p2"), ""); + vm.stopPrank(); + } + + function test_setProvider_notOpen_reverts() public { + uint256 jobId = _createNoProvider(address(0)); + vm.prank(client); + kernel.reject(jobId, bytes32(0), ""); + vm.prank(client); + vm.expectRevert(IAgenticCommerce.WrongStatus.selector); + kernel.setProvider(jobId, provider, ""); + } + + function test_setProvider_expired_reverts() public { + uint256 jobId = _createNoProvider(address(0)); + vm.warp(block.timestamp + EXPIRY_OFFSET); + vm.prank(client); + vm.expectRevert(IAgenticCommerce.WrongStatus.selector); + kernel.setProvider(jobId, provider, ""); + } + + function test_setProvider_revertingBeforeHook_blocks() public { + RevertingHook rh = new RevertingHook(); + vm.prank(admin); + kernel.setHookWhitelist(address(rh), true); + uint256 jobId = _createNoProvider(address(rh)); + rh.setRevertBefore(true); + vm.prank(client); + vm.expectRevert(RevertingHook.HookSaysNo.selector); + kernel.setProvider(jobId, provider, ""); + } + + /// @dev Two faults at once: the earlier check in PRD order must win (C-03). + function test_setProvider_precedence() public { + uint256 expired = _createNoProvider(address(0)); + vm.warp(block.timestamp + EXPIRY_OFFSET); + vm.prank(stranger); // expired AND unauthorised + vm.expectRevert(IAgenticCommerce.WrongStatus.selector); + kernel.setProvider(expired, provider, ""); + + uint256 set = _create(address(0)); // provider already set + vm.prank(client); // provider set AND zero address + vm.expectRevert(IAgenticCommerce.WrongStatus.selector); + kernel.setProvider(set, address(0), ""); + } + + // ═════════════════════════════ setBudget ═════════════════════════════ + + function test_setBudget_reQuotableWhileOpen_andEncoding() public { + uint256 jobId = _create(address(rec)); + vm.startPrank(provider); + kernel.setBudget(jobId, 5, hex"01"); + vm.expectEmit(address(kernel)); + emit IAgenticCommerce.BudgetSet(jobId, 7); + kernel.setBudget(jobId, 7, hex"02"); + vm.stopPrank(); + assertEq(kernel.getJob(jobId).budget, 7); + assertEq(rec.getCall(2).data, abi.encode(provider, uint256(7), hex"02")); + assertEq(rec.getCall(2).selector, IAgenticCommerce.setBudget.selector); + } + + function test_setBudget_reverts() public { + uint256 jobId = _create(address(0)); + vm.startPrank(provider); + vm.expectRevert(IAgenticCommerce.InvalidJob.selector); + kernel.setBudget(0, 1, ""); + vm.stopPrank(); + + vm.prank(stranger); + vm.expectRevert(IAgenticCommerce.Unauthorized.selector); + kernel.setBudget(jobId, 1, ""); + + vm.warp(block.timestamp + EXPIRY_OFFSET); + vm.prank(provider); + vm.expectRevert(IAgenticCommerce.WrongStatus.selector); + kernel.setBudget(jobId, 1, ""); + } + + function test_setBudget_afterFund_reverts() public { + uint256 jobId = _funded(address(0), BUDGET); + vm.prank(provider); + vm.expectRevert(IAgenticCommerce.WrongStatus.selector); + kernel.setBudget(jobId, 1, ""); + } + + // ═════════════════════════════ fund ═════════════════════════════ + + function test_fund_happy() public { + uint256 jobId = _budgeted(address(rec), BUDGET); + uint256 before = token.balanceOf(client); + vm.expectEmit(address(kernel)); + emit IAgenticCommerce.JobFunded(jobId, client, BUDGET); + vm.prank(client); + kernel.fund(jobId, BUDGET, hex"abcd"); + + assertEq(token.balanceOf(client), before - BUDGET); + assertEq(token.balanceOf(address(kernel)), BUDGET); + assertEq(kernel.totalEscrowed(), BUDGET); + assertEq(uint8(_status(jobId)), uint8(IAgenticCommerce.JobStatus.Funded)); + + RecordingHook.Call memory b = rec.getCall(2); + assertEq(b.selector, IAgenticCommerce.fund.selector); + assertEq(b.data, abi.encode(client, hex"abcd")); + assertEq(b.statusSeen, uint8(IAgenticCommerce.JobStatus.Open), "before sees pre-state"); + assertEq(rec.getCall(3).statusSeen, uint8(IAgenticCommerce.JobStatus.Funded), "after sees post-state"); + } + + function test_fund_zeroBudget_noTransfer() public { + uint256 jobId = _create(address(0)); + uint256 before = token.balanceOf(client); + vm.prank(client); + kernel.fund(jobId, 0, ""); + assertEq(uint8(_status(jobId)), uint8(IAgenticCommerce.JobStatus.Funded)); + assertEq(token.balanceOf(client), before); + assertEq(kernel.totalEscrowed(), 0); + } + + function test_fund_reverts_inOrder() public { + uint256 noProv = _createNoProvider(address(0)); + uint256 jobId = _budgeted(address(0), BUDGET); + + vm.startPrank(client); + vm.expectRevert(IAgenticCommerce.InvalidJob.selector); + kernel.fund(0, BUDGET, ""); + vm.stopPrank(); + + vm.prank(stranger); + vm.expectRevert(IAgenticCommerce.Unauthorized.selector); + kernel.fund(jobId, BUDGET, ""); + + vm.prank(client); + vm.expectRevert(IAgenticCommerce.ProviderNotSet.selector); + kernel.fund(noProv, 0, ""); + + vm.prank(client); + vm.expectRevert(IAgenticCommerce.BudgetMismatch.selector); + kernel.fund(jobId, BUDGET - 1, ""); + + vm.warp(block.timestamp + EXPIRY_OFFSET); + vm.prank(client); + vm.expectRevert(IAgenticCommerce.WrongStatus.selector); + kernel.fund(jobId, BUDGET, ""); + } + + /// @dev Two faults at once: the earlier check in PRD order must win (C-03). + function test_fund_precedence() public { + uint256 noProv = _createNoProvider(address(0)); + vm.prank(stranger); // unauthorised AND no provider + vm.expectRevert(IAgenticCommerce.Unauthorized.selector); + kernel.fund(noProv, 0, ""); + + vm.prank(client); // no provider AND wrong budget + vm.expectRevert(IAgenticCommerce.ProviderNotSet.selector); + kernel.fund(noProv, 1, ""); + + uint256 jobId = _budgeted(address(0), BUDGET); + vm.warp(block.timestamp + EXPIRY_OFFSET); + vm.prank(client); // expired AND wrong budget + vm.expectRevert(IAgenticCommerce.WrongStatus.selector); + kernel.fund(jobId, BUDGET - 1, ""); + } + + function test_fund_frontRunReQuote_reverts() public { + uint256 jobId = _budgeted(address(0), BUDGET); + vm.prank(provider); + kernel.setBudget(jobId, BUDGET * 100, ""); + vm.prank(client); + vm.expectRevert(IAgenticCommerce.BudgetMismatch.selector); + kernel.fund(jobId, BUDGET, ""); + } + + function test_fund_twice_reverts() public { + uint256 jobId = _funded(address(0), BUDGET); + vm.prank(client); + vm.expectRevert(IAgenticCommerce.WrongStatus.selector); + kernel.fund(jobId, BUDGET, ""); + } + + // ═════════════════════════════ submit (K-11) ═════════════════════════════ + + function test_submit_happy() public { + uint256 jobId = _funded(address(rec), BUDGET); + bytes32 d = keccak256("d"); + vm.expectEmit(address(kernel)); + emit IAgenticCommerce.JobSubmitted(jobId, provider, d); + vm.prank(provider); + kernel.submit(jobId, d, hex"09"); + assertEq(uint8(_status(jobId)), uint8(IAgenticCommerce.JobStatus.Submitted)); + assertEq(rec.getCall(4).data, abi.encode(provider, d, hex"09")); + } + + function test_submit_openJob_reverts_evenZeroBudget() public { + uint256 jobId = _create(address(0)); + vm.prank(provider); + vm.expectRevert(IAgenticCommerce.WrongStatus.selector); + kernel.submit(jobId, bytes32(0), ""); + } + + function test_submit_reverts() public { + uint256 jobId = _funded(address(0), BUDGET); + vm.prank(provider); + vm.expectRevert(IAgenticCommerce.InvalidJob.selector); + kernel.submit(0, bytes32(0), ""); + + vm.prank(stranger); + vm.expectRevert(IAgenticCommerce.Unauthorized.selector); + kernel.submit(jobId, bytes32(0), ""); + + vm.warp(block.timestamp + EXPIRY_OFFSET); + vm.prank(provider); + vm.expectRevert(IAgenticCommerce.WrongStatus.selector); + kernel.submit(jobId, bytes32(0), ""); + } + + // ═════════════════════════════ complete ═════════════════════════════ + + function test_complete_feeSplit_rounding_andEventOrder() public { + vm.startPrank(admin); + kernel.setPlatformFee(500, treasury); + kernel.setEvaluatorFee(250); + vm.stopPrank(); + uint256 budget = 1_000_003; + uint256 jobId = _submitted(address(0), budget); + + vm.expectEmit(address(kernel)); + emit IAgenticCommerce.PlatformFeePaid(jobId, treasury, 50_000); + vm.expectEmit(address(kernel)); + emit IAgenticCommerce.EvaluatorFeePaid(jobId, evaluator, 25_000); + vm.expectEmit(address(kernel)); + emit IAgenticCommerce.JobCompleted(jobId, evaluator, bytes32("ok")); + vm.expectEmit(address(kernel)); + emit IAgenticCommerce.PaymentReleased(jobId, provider, 925_003); + vm.prank(evaluator); + kernel.complete(jobId, bytes32("ok"), ""); + + assertEq(token.balanceOf(treasury), 50_000); + assertEq(token.balanceOf(evaluator), 25_000); + assertEq(token.balanceOf(provider), 925_003); + assertEq(kernel.totalEscrowed(), 0); + assertEq(uint8(_status(jobId)), uint8(IAgenticCommerce.JobStatus.Completed)); + } + + function test_complete_zeroFees_providerGetsAll() public { + uint256 jobId = _submitted(address(0), BUDGET); + vm.recordLogs(); + vm.prank(evaluator); + kernel.complete(jobId, bytes32(0), ""); + assertEq(token.balanceOf(provider), BUDGET); + assertEq(token.balanceOf(treasury), 0); + _assertNoLog(IAgenticCommerce.PlatformFeePaid.selector); + _assertNoLog(IAgenticCommerce.EvaluatorFeePaid.selector); + } + + function test_complete_fullFees_netZero_stillEmitsPaymentReleased() public { + vm.prank(admin); + kernel.setPlatformFee(10_000, treasury); + uint256 jobId = _submitted(address(0), BUDGET); + vm.expectEmit(address(kernel)); + emit IAgenticCommerce.PaymentReleased(jobId, provider, 0); + vm.prank(evaluator); + kernel.complete(jobId, bytes32(0), ""); + assertEq(token.balanceOf(treasury), BUDGET); + assertEq(token.balanceOf(provider), 0); + } + + function test_complete_zeroBudget() public { + uint256 jobId = _submitted(address(0), 0); + vm.expectEmit(address(kernel)); + emit IAgenticCommerce.PaymentReleased(jobId, provider, 0); + vm.prank(evaluator); + kernel.complete(jobId, bytes32(0), ""); + } + + function test_complete_allowedAfterExpiry() public { + uint256 jobId = _submitted(address(0), BUDGET); + vm.warp(block.timestamp + EXPIRY_OFFSET + 30 minutes); + vm.prank(evaluator); + kernel.complete(jobId, bytes32(0), ""); + assertEq(uint8(_status(jobId)), uint8(IAgenticCommerce.JobStatus.Completed)); + } + + function test_complete_reverts() public { + uint256 funded = _funded(address(0), BUDGET); + uint256 submitted = _submitted(address(0), BUDGET); + + vm.startPrank(evaluator); + vm.expectRevert(IAgenticCommerce.InvalidJob.selector); + kernel.complete(0, bytes32(0), ""); + vm.expectRevert(IAgenticCommerce.WrongStatus.selector); + kernel.complete(funded, bytes32(0), ""); + vm.stopPrank(); + + vm.prank(client); + vm.expectRevert(IAgenticCommerce.Unauthorized.selector); + kernel.complete(submitted, bytes32(0), ""); + } + + // ═════════════════════════════ reject ═════════════════════════════ + + function test_reject_open_byClient_and_byProvider() public { + uint256 a = _create(address(0)); + uint256 b = _create(address(0)); + vm.expectEmit(address(kernel)); + emit IAgenticCommerce.JobRejected(a, client, bytes32("no")); + vm.prank(client); + kernel.reject(a, bytes32("no"), ""); + vm.prank(provider); + kernel.reject(b, bytes32(0), ""); + assertEq(uint8(_status(a)), uint8(IAgenticCommerce.JobStatus.Rejected)); + assertEq(uint8(_status(b)), uint8(IAgenticCommerce.JobStatus.Rejected)); + } + + function test_reject_funded_byEvaluator_refunds() public { + uint256 jobId = _funded(address(0), BUDGET); + uint256 before = token.balanceOf(client); + vm.expectEmit(address(kernel)); + emit IAgenticCommerce.Refunded(jobId, client, BUDGET); + vm.prank(evaluator); + kernel.reject(jobId, bytes32(0), ""); + assertEq(token.balanceOf(client), before + BUDGET); + assertEq(kernel.totalEscrowed(), 0); + } + + function test_reject_submitted_byEvaluator_refunds() public { + uint256 jobId = _submitted(address(0), BUDGET); + uint256 before = token.balanceOf(client); + vm.prank(evaluator); + kernel.reject(jobId, bytes32(0), ""); + assertEq(token.balanceOf(client), before + BUDGET); + assertEq(kernel.totalEscrowed(), 0); + } + + function test_reject_fundedZeroBudget_noRefundEvent() public { + uint256 jobId = _funded(address(0), 0); + vm.recordLogs(); + vm.prank(evaluator); + kernel.reject(jobId, bytes32(0), ""); + _assertNoLog(IAgenticCommerce.Refunded.selector); + } + + function test_reject_unauthorisedPerStatus() public { + uint256 open = _create(address(0)); + uint256 funded = _funded(address(0), BUDGET); + uint256 submitted = _submitted(address(0), BUDGET); + + vm.prank(evaluator); + vm.expectRevert(IAgenticCommerce.Unauthorized.selector); + kernel.reject(open, bytes32(0), ""); + + vm.prank(client); + vm.expectRevert(IAgenticCommerce.Unauthorized.selector); + kernel.reject(funded, bytes32(0), ""); + + vm.prank(provider); + vm.expectRevert(IAgenticCommerce.Unauthorized.selector); + kernel.reject(submitted, bytes32(0), ""); + } + + function test_reject_invalidAndTerminal_revert() public { + vm.expectRevert(IAgenticCommerce.InvalidJob.selector); + kernel.reject(0, bytes32(0), ""); + + uint256 jobId = _create(address(0)); + vm.prank(client); + kernel.reject(jobId, bytes32(0), ""); + vm.prank(client); + vm.expectRevert(IAgenticCommerce.WrongStatus.selector); + kernel.reject(jobId, bytes32(0), ""); + } + + // ═════════════════════════════ claimRefund (K-05, K-06) ═════════════════════════════ + + function test_claimRefund_funded_afterExpiry() public { + uint256 jobId = _funded(address(0), BUDGET); + uint256 before = token.balanceOf(client); + vm.warp(block.timestamp + EXPIRY_OFFSET); + vm.expectEmit(address(kernel)); + emit IAgenticCommerce.Refunded(jobId, client, BUDGET); + vm.expectEmit(address(kernel)); + emit IAgenticCommerce.JobExpired(jobId); + vm.prank(stranger); + kernel.claimRefund(jobId); + assertEq(token.balanceOf(client), before + BUDGET); + assertEq(kernel.totalEscrowed(), 0); + assertEq(uint8(_status(jobId)), uint8(IAgenticCommerce.JobStatus.Expired)); + } + + function test_claimRefund_funded_beforeExpiry_reverts() public { + uint256 jobId = _funded(address(0), BUDGET); + vm.expectRevert(IAgenticCommerce.WrongStatus.selector); + kernel.claimRefund(jobId); + } + + function test_claimRefund_submitted_gracePeriod() public { + uint256 jobId = _submitted(address(0), BUDGET); + uint256 exp = kernel.getJob(jobId).expiredAt; + vm.warp(exp + kernel.EVALUATOR_GRACE_PERIOD() - 1); + vm.expectRevert(IAgenticCommerce.GracePeriodActive.selector); + kernel.claimRefund(jobId); + + vm.warp(exp + kernel.EVALUATOR_GRACE_PERIOD()); + kernel.claimRefund(jobId); + assertEq(uint8(_status(jobId)), uint8(IAgenticCommerce.JobStatus.Expired)); + assertEq(kernel.totalEscrowed(), 0); + } + + function test_claimRefund_open_afterExpiry_noTransfer() public { + uint256 jobId = _create(address(0)); + vm.warp(block.timestamp + EXPIRY_OFFSET); + vm.recordLogs(); + kernel.claimRefund(jobId); + assertEq(uint8(_status(jobId)), uint8(IAgenticCommerce.JobStatus.Expired)); + _assertNoLog(IAgenticCommerce.Refunded.selector); + } + + function test_claimRefund_fundedZeroBudget_noTransfer() public { + uint256 jobId = _funded(address(0), 0); + vm.warp(block.timestamp + EXPIRY_OFFSET); + vm.recordLogs(); + kernel.claimRefund(jobId); + _assertNoLog(IAgenticCommerce.Refunded.selector); + } + + function test_claimRefund_worksWhilePaused() public { + uint256 jobId = _funded(address(0), BUDGET); + _pause(); + vm.warp(block.timestamp + EXPIRY_OFFSET); + kernel.claimRefund(jobId); + assertEq(uint8(_status(jobId)), uint8(IAgenticCommerce.JobStatus.Expired)); + } + + function test_claimRefund_neverCallsHook_evenReverting() public { + RevertingHook rh = new RevertingHook(); + vm.prank(admin); + kernel.setHookWhitelist(address(rh), true); + uint256 jobId = _funded(address(rh), BUDGET); + rh.setRevertBefore(true); + rh.setRevertAfter(true); + vm.warp(block.timestamp + EXPIRY_OFFSET); + kernel.claimRefund(jobId); + assertEq(uint8(_status(jobId)), uint8(IAgenticCommerce.JobStatus.Expired)); + } + + function test_claimRefund_invalidAndTerminal_revert() public { + vm.expectRevert(IAgenticCommerce.InvalidJob.selector); + kernel.claimRefund(0); + uint256 jobId = _create(address(0)); + vm.prank(client); + kernel.reject(jobId, bytes32(0), ""); + vm.expectRevert(IAgenticCommerce.WrongStatus.selector); + kernel.claimRefund(jobId); + } + + function test_complete_vs_claimRefund_race_afterGrace() public { + uint256 a = _submitted(address(0), BUDGET); + vm.warp(kernel.getJob(a).expiredAt + kernel.EVALUATOR_GRACE_PERIOD()); + kernel.claimRefund(a); + vm.prank(evaluator); + vm.expectRevert(IAgenticCommerce.WrongStatus.selector); + kernel.complete(a, bytes32(0), ""); + } + + // ───────────── helpers ───────────── + + function _assertNoLog(bytes32 topic0) internal { + VmLogs memory l = _logs(); + for (uint256 i = 0; i < l.n; i++) { + assertTrue(l.topics[i] != topic0, "unexpected event"); + } + } + + struct VmLogs { + uint256 n; + bytes32[] topics; + } + + function _logs() internal returns (VmLogs memory out) { + Vm.Log[] memory entries = vm.getRecordedLogs(); + out.n = entries.length; + out.topics = new bytes32[](entries.length); + for (uint256 i = 0; i < entries.length; i++) { + out.topics[i] = entries[i].topics.length > 0 ? entries[i].topics[0] : bytes32(0); + } + } +} + diff --git a/plan/marketplace/contracts/test/8183-tests/BaseERC8183Hook.t.sol b/plan/marketplace/contracts/test/8183-tests/BaseERC8183Hook.t.sol new file mode 100644 index 00000000..e11e77eb --- /dev/null +++ b/plan/marketplace/contracts/test/8183-tests/BaseERC8183Hook.t.sol @@ -0,0 +1,188 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import {ERC8183HookErrors} from "../../src/agentic-commerce-8183/libraries/Errors.sol"; +import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; + +import {IERC8183Hook} from "../../src/agentic-commerce-8183/interfaces/IERC8183Hook.sol"; +import {KernelBase} from "./KernelBase.t.sol"; +import {RoutingProbeHook} from "./mocks/RoutingProbeHook.sol"; +import {BareHook} from "./mocks/BareHook.sol"; +import {IAgenticCommerce} from "../../src/agentic-commerce-8183/interfaces/IAgenticCommerce.sol"; + +/// @notice Phase 3 — every route decodes exactly what the real kernel encoded. +contract BaseERC8183HookTest is KernelBase { + RoutingProbeHook internal probe; + RoutingProbeHook internal probeImpl; + address internal hookProxyAdminOwner = makeAddr("hookProxyAdminOwner"); + + function setUp() public override { + super.setUp(); + probeImpl = new RoutingProbeHook(); + probe = RoutingProbeHook(_deployProbe(address(kernel))); + vm.prank(admin); + kernel.setHookWhitelist(address(probe), true); + } + + function _deployProbe(address kernel_) internal returns (address) { + return address( + new TransparentUpgradeableProxy( + address(probeImpl), hookProxyAdminOwner, abi.encodeCall(RoutingProbeHook.initialize, (kernel_)) + ) + ); + } + + function _assertRec( + uint256 i, + string memory handler, + uint256 jobId, + address caller, + address addrArg, + uint256 uintArg, + bytes32 b32Arg, + bytes memory opt + ) internal view { + RoutingProbeHook.Rec memory r = probe.rec(i); + assertEq(r.handler, handler); + assertEq(r.jobId, jobId); + assertEq(r.caller, caller); + assertEq(r.addrArg, addrArg); + assertEq(r.uintArg, uintArg); + assertEq(r.b32Arg, b32Arg); + assertEq(r.optParams, opt); + } + + // ───────────── all 12 routes, driven through the real kernel ───────────── + + function test_routes_setProvider_setBudget_fund_submit_complete() public { + vm.prank(client); + uint256 jobId = kernel.createJob(address(0), evaluator, _expiry(), "", address(probe)); + assertEq(probe.count(), 0); + + vm.prank(client); + kernel.setProvider(jobId, provider, hex"a1"); + vm.prank(provider); + kernel.setBudget(jobId, 42, hex"a2"); + token.mint(client, 42); + vm.prank(client); + kernel.fund(jobId, 42, hex"a3"); + vm.prank(provider); + kernel.submit(jobId, bytes32("deliv"), hex"a4"); + vm.prank(evaluator); + kernel.complete(jobId, bytes32("ok"), hex"a5"); + + assertEq(probe.count(), 10); + _assertRec(0, "preSetProvider", jobId, client, provider, 0, 0, hex"a1"); + _assertRec(1, "postSetProvider", jobId, client, provider, 0, 0, hex"a1"); + _assertRec(2, "preSetBudget", jobId, provider, address(0), 42, 0, hex"a2"); + _assertRec(3, "postSetBudget", jobId, provider, address(0), 42, 0, hex"a2"); + _assertRec(4, "preFund", jobId, client, address(0), 0, 0, hex"a3"); + _assertRec(5, "postFund", jobId, client, address(0), 0, 0, hex"a3"); + _assertRec(6, "preSubmit", jobId, provider, address(0), 0, bytes32("deliv"), hex"a4"); + _assertRec(7, "postSubmit", jobId, provider, address(0), 0, bytes32("deliv"), hex"a4"); + _assertRec(8, "preComplete", jobId, evaluator, address(0), 0, bytes32("ok"), hex"a5"); + _assertRec(9, "postComplete", jobId, evaluator, address(0), 0, bytes32("ok"), hex"a5"); + } + + function test_routes_reject() public { + uint256 jobId = _funded(address(probe), BUDGET); + uint256 n = probe.count(); + vm.prank(evaluator); + kernel.reject(jobId, bytes32("no"), hex"b1"); + _assertRec(n, "preReject", jobId, evaluator, address(0), 0, bytes32("no"), hex"b1"); + _assertRec(n + 1, "postReject", jobId, evaluator, address(0), 0, bytes32("no"), hex"b1"); + } + + // ───────────── caller authentication ───────────── + + function test_beforeAction_fromNonKernel_reverts() public { + vm.prank(stranger); + vm.expectRevert(abi.encodeWithSelector(ERC8183HookErrors.CallerIsNotKernel.selector, stranger)); + probe.beforeAction(1, bytes4(0), ""); + } + + function test_afterAction_fromNonKernel_reverts() public { + vm.prank(stranger); + vm.expectRevert(abi.encodeWithSelector(ERC8183HookErrors.CallerIsNotKernel.selector, stranger)); + probe.afterAction(1, bytes4(0), ""); + } + + /// @dev The kernel never sends an unknown selector, so this is the one test that pranks as the kernel. + function test_unknownSelector_isNoop() public { + vm.startPrank(address(kernel)); + probe.beforeAction(1, bytes4(0xdeadbeef), hex"00"); + probe.afterAction(1, bytes4(0xdeadbeef), hex"00"); + vm.stopPrank(); + assertEq(probe.count(), 0); + } + + // ───────────── ERC-165 ───────────── + + function test_supportsInterface() public view { + assertTrue(probe.supportsInterface(type(IERC8183Hook).interfaceId)); + assertTrue(probe.supportsInterface(type(IERC165).interfaceId)); + assertFalse(probe.supportsInterface(bytes4(0x12345678))); + } + + // ───────────── initialisation ───────────── + + function test_kernel_isSetAndAtSlot0() public view { + assertEq(probe.KERNEL(), address(kernel)); + assertEq(address(uint160(uint256(vm.load(address(probe), bytes32(uint256(0)))))), address(kernel)); + } + + function test_init_zeroKernel_reverts() public { + vm.expectRevert(ERC8183HookErrors.ZeroAddress.selector); + _deployProbe(address(0)); + } + + function test_init_twice_reverts() public { + vm.expectRevert(Initializable.InvalidInitialization.selector); + probe.initialize(address(kernel)); + } + + function test_init_onImplementation_reverts() public { + vm.expectRevert(Initializable.InvalidInitialization.selector); + probeImpl.initialize(address(kernel)); + } + + function test_baseInit_outsideInitializer_reverts() public { + vm.expectRevert(Initializable.NotInitializing.selector); + probe.initOutside(address(kernel)); + } + + // ───────────── default handlers are no-ops ───────────── + + /// @dev A hook that overrides nothing must let every hooked action through unchanged. + function test_defaultHandlers_areNoops_fullLifecycleAndReject() public { + BareHook bareImpl = new BareHook(); + address bare = address( + new TransparentUpgradeableProxy( + address(bareImpl), hookProxyAdminOwner, abi.encodeCall(BareHook.initialize, (address(kernel))) + ) + ); + vm.prank(admin); + kernel.setHookWhitelist(bare, true); + + vm.prank(client); + uint256 a = kernel.createJob(address(0), evaluator, _expiry(), "", bare); + vm.prank(client); + kernel.setProvider(a, provider, ""); + vm.prank(provider); + kernel.setBudget(a, BUDGET, ""); + vm.prank(client); + kernel.fund(a, BUDGET, ""); + vm.prank(provider); + kernel.submit(a, bytes32(0), ""); + vm.prank(evaluator); + kernel.complete(a, bytes32(0), ""); + assertEq(uint8(kernel.getJob(a).status), uint8(IAgenticCommerce.JobStatus.Completed)); + + uint256 b = _funded(bare, BUDGET); + vm.prank(evaluator); + kernel.reject(b, bytes32(0), ""); + assertEq(uint8(kernel.getJob(b).status), uint8(IAgenticCommerce.JobStatus.Rejected)); + } +} diff --git a/plan/marketplace/contracts/test/8183-tests/Interfaces.t.sol b/plan/marketplace/contracts/test/8183-tests/Interfaces.t.sol new file mode 100644 index 00000000..cfe9a6e3 --- /dev/null +++ b/plan/marketplace/contracts/test/8183-tests/Interfaces.t.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import {Test} from "forge-std/Test.sol"; +import {IERC8183Hook} from "../../src/agentic-commerce-8183/interfaces/IERC8183Hook.sol"; +import {IAgenticCommerce} from "../../src/agentic-commerce-8183/interfaces/IAgenticCommerce.sol"; + +/// @notice Phase 1 — interface ids and the hooked selectors the hook base routes on. +contract InterfacesTest is Test { + function test_hookInterfaceId_isXorOfBothSelectors() public pure { + bytes4 expected = IERC8183Hook.beforeAction.selector ^ IERC8183Hook.afterAction.selector; + assertEq(type(IERC8183Hook).interfaceId, expected); + assertEq(type(IERC8183Hook).interfaceId, bytes4(0x7ff6bc9e)); + } + + function test_hookSelectors_matchStandard() public pure { + assertEq(IERC8183Hook.beforeAction.selector, bytes4(keccak256("beforeAction(uint256,bytes4,bytes)"))); + assertEq(IERC8183Hook.afterAction.selector, bytes4(keccak256("afterAction(uint256,bytes4,bytes)"))); + } + + /// @dev Pins every hooked selector. K-04 moves setProvider to the 3-argument form. + function test_hookedKernelSelectors() public pure { + assertEq(IAgenticCommerce.setProvider.selector, bytes4(0xc9a84bb9)); + assertEq(IAgenticCommerce.setBudget.selector, bytes4(0xdd4ae9d4)); + assertEq(IAgenticCommerce.fund.selector, bytes4(0xd2e13f50)); + assertEq(IAgenticCommerce.submit.selector, bytes4(0x9e63798d)); + assertEq(IAgenticCommerce.complete.selector, bytes4(0xd75bbdf3)); + assertEq(IAgenticCommerce.reject.selector, bytes4(0x41dd26f5)); + } + + function test_createJob_keepsFiveArgumentShape() public pure { + assertEq( + IAgenticCommerce.createJob.selector, bytes4(keccak256("createJob(address,address,uint256,string,address)")) + ); + } +} diff --git a/plan/marketplace/contracts/test/8183-tests/JobSpecBuilder.t.sol b/plan/marketplace/contracts/test/8183-tests/JobSpecBuilder.t.sol new file mode 100644 index 00000000..5280ba32 --- /dev/null +++ b/plan/marketplace/contracts/test/8183-tests/JobSpecBuilder.t.sol @@ -0,0 +1,401 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import {Test} from "forge-std/Test.sol"; + +import {TemplateParts} from "./helpers/TemplateParts.sol"; +import {UniversalMarketplaceErrors} from "../../src/agentic-commerce-8183/libraries/Errors.sol"; +import {JobSpecBuilder} from "../../src/agentic-commerce-8183/libraries/JobSpecBuilder.sol"; +import { + Evaluation, + Operation, + LogicKind, + Logic, + AllowedMutability, + JobSpec, + T_TUPLE, + T_ADDRESS +} from "../../src/agentic-commerce-8183/libraries/JobSpecTypes.sol"; +import { + FillSource, + Fill, + ReadTemplate, + TargetSource, + CheckTemplate, + ParamBounds, + JobSpecTemplate, + BuildContext +} from "../../src/agentic-commerce-8183/libraries/Types.sol"; + +/// @notice TEST ONLY: calls JobSpecBuilder the way the marketplace does. Under DELEGATECALL the library asks +/// `address(this)` (this harness) for CEAs, so the harness answers `computeCEA` like a marketplace: +/// a deterministic stand-in per (agw, chain) for chains the test supports, `ChainNotSupported` otherwise. +contract JobSpecBuilderHarness { + mapping(bytes32 => bool) internal supported; + + function setSupported(bytes32 chainHash, bool on) external { + supported[chainHash] = on; + } + + function build(bytes memory jobSpecTemplate, BuildContext memory ctx) external view returns (bytes memory) { + return JobSpecBuilder.build(jobSpecTemplate, ctx); + } + + function computeCEA(address agw, bytes32 chainHash) external view returns (address) { + if (!supported[chainHash]) revert UniversalMarketplaceErrors.ChainNotSupported(chainHash); + return ceaFor(agw, chainHash); + } + + function ceaFor(address agw, bytes32 chainHash) public pure returns (address) { + return address(uint160(uint256(keccak256(abi.encode("cea", agw, chainHash))))); + } +} + +/// @notice The V2 doc's templates and build helpers, shared by the builder and conformance suites. +abstract contract BuilderFixtures is Test, TemplateParts { + JobSpecBuilderHarness internal builder; + + bytes32 internal constant ETH_HASH = keccak256("eip155:1"); + bytes32 internal constant BASE_HASH = keccak256("eip155:8453"); + + address internal AGW = makeAddr("agw"); + address internal AUSDC_ETH = makeAddr("aUSDC.eth"); + address internal AAVE_POOL_ETH = makeAddr("AavePool.eth"); + address internal USDC_ETH = makeAddr("USDC.eth"); + address internal MORPHO_VAULT = makeAddr("MorphoVault.eth"); + address internal SPARK = makeAddr("Spark.eth"); + address internal WETH_BASE = makeAddr("WETH.base"); + + function setUp() public virtual { + builder = new JobSpecBuilderHarness(); + builder.setSupported(ETH_HASH, true); + builder.setSupported(BASE_HASH, true); + } + + // ───────── the V2 doc's templates ───────── + + /// @dev "Deposit into Aave v3 on Ethereum at ≥ 4%": deposited ≥ 99.99% of principal AND rate ≥ 4% (ray). + function _lending() internal view returns (JobSpecTemplate memory t) { + t.reads = new ReadTemplate[](2); + t.reads[0] = _balanceOfCEA("1", AUSDC_ETH); + t.reads[1] = + _read("1", AAVE_POOL_ETH, GET_RESERVE_DATA, abi.encode(USDC_ETH), _noFills(), _reserveDataOut(), _f2(0, 2)); + t.checks = new CheckTemplate[](2); + t.checks[0] = _chk(0, Evaluation.COMPARE, Operation.GREATER_OR_EQUAL, TargetSource.PRINCIPAL_BPS, 9999); + t.checks[1] = _chk(1, Evaluation.COMPARE, Operation.GREATER_OR_EQUAL, TargetSource.FIXED, 0.04e27); + t.logic = _rootOf(LogicKind.ALL, _kids(0, 1)); + t.params = new ParamBounds[](0); + } + + /// @dev "The CEA receives at least minOut WETH on Base": one NUM check, `minOut` is the user's param 0. + function _swap() internal view returns (JobSpecTemplate memory t) { + t.reads = new ReadTemplate[](1); + t.reads[0] = _balanceOfCEA("8453", WETH_BASE); + t.reads[0].minConfirmations = 3; + t.checks = new CheckTemplate[](1); + t.checks[0] = _chk(0, Evaluation.NUMBER, Operation.GREATER_OR_EQUAL, TargetSource.PARAM, 0); + t.logic = _rootOf(LogicKind.ALL, _one(0)); + t.params = new ParamBounds[](1); + t.params[0] = ParamBounds({min: 1, max: 1e30}); + } + + /// @dev "Aave OR Morpho": ANY over two CMP checks. + function _either() internal view returns (JobSpecTemplate memory t) { + t.reads = new ReadTemplate[](2); + t.reads[0] = _balanceOfCEA("1", AUSDC_ETH); + t.reads[1] = _read("1", MORPHO_VAULT, MAX_WITHDRAW, new bytes(32), _ceaFill(0), _uintOut(), _f(0)); + t.checks = new CheckTemplate[](2); + t.checks[0] = _chk(0, Evaluation.COMPARE, Operation.GREATER_OR_EQUAL, TargetSource.PRINCIPAL_BPS, 9999); + t.checks[1] = _chk(1, Evaluation.COMPARE, Operation.GREATER_OR_EQUAL, TargetSource.PRINCIPAL_BPS, 9999); + t.logic = _rootOf(LogicKind.ANY, _kids(0, 1)); + t.params = new ParamBounds[](0); + } + + /// @dev "At least 2 of Aave, Morpho, Spark". + function _twoOfThree() internal view returns (JobSpecTemplate memory t) { + t.reads = new ReadTemplate[](3); + t.reads[0] = _balanceOfCEA("1", AUSDC_ETH); + t.reads[1] = _read("1", MORPHO_VAULT, MAX_WITHDRAW, new bytes(32), _ceaFill(0), _uintOut(), _f(0)); + t.reads[2] = _balanceOfCEA("1", SPARK); + t.checks = new CheckTemplate[](3); + for (uint8 i; i < 3; ++i) { + t.checks[i] = _chk(i, Evaluation.COMPARE, Operation.GREATER_OR_EQUAL, TargetSource.FIXED, 99.99e6); + } + t.logic = new Logic[](1); + t.logic[0] = _step(LogicKind.AT_LEAST, _kids3(0, 1, 2), _none(), 2); + t.params = new ParamBounds[](0); + } + + /// @dev "(Aave deposited AND Aave ≥ 4%) OR (Morpho deposited AND Morpho rate ≥ 4%)". + function _nested() internal view returns (JobSpecTemplate memory t) { + t.reads = new ReadTemplate[](4); + t.reads[0] = _balanceOfCEA("1", AUSDC_ETH); + t.reads[1] = + _read("1", AAVE_POOL_ETH, GET_RESERVE_DATA, abi.encode(USDC_ETH), _noFills(), _reserveDataOut(), _f2(0, 2)); + t.reads[2] = _read("1", MORPHO_VAULT, MAX_WITHDRAW, new bytes(32), _ceaFill(0), _uintOut(), _f(0)); + t.reads[3] = _read("1", MORPHO_VAULT, bytes4(keccak256("supplyRate()")), "", _noFills(), _uintOut(), _f(0)); + t.checks = new CheckTemplate[](4); + t.checks[0] = _chk(0, Evaluation.COMPARE, Operation.GREATER_OR_EQUAL, TargetSource.FIXED, 99.99e6); + t.checks[1] = _chk(1, Evaluation.COMPARE, Operation.GREATER_OR_EQUAL, TargetSource.FIXED, 0.04e27); + t.checks[2] = _chk(2, Evaluation.COMPARE, Operation.GREATER_OR_EQUAL, TargetSource.FIXED, 99.99e6); + t.checks[3] = _chk(3, Evaluation.COMPARE, Operation.GREATER_OR_EQUAL, TargetSource.FIXED, 0.04e18); + t.logic = new Logic[](3); + t.logic[0] = _step(LogicKind.ANY, _none(), _kids(1, 2), 0); + t.logic[1] = _step(LogicKind.ALL, _kids(0, 1), _none(), 0); + t.logic[2] = _step(LogicKind.ALL, _kids(2, 3), _none(), 0); + t.params = new ParamBounds[](0); + } + + // ───────── building ───────── + + function _ctx(uint256 principal, int256[] memory params) internal view returns (BuildContext memory) { + return BuildContext({ + agw: AGW, + principal: principal, + executeBy: 1_800_000_000, + settleWindow: 2 hours, + params: params, + origin: keccak256("origin") + }); + } + + function _build(JobSpecTemplate memory t, BuildContext memory ctx) internal view returns (JobSpec memory) { + return abi.decode(builder.build(abi.encode(t), ctx), (JobSpec)); + } + + function _noParams() internal pure returns (int256[] memory) { + return new int256[](0); + } + + function _oneParam(int256 v) internal pure returns (int256[] memory p) { + p = new int256[](1); + p[0] = v; + } +} + +/// @title JobSpecBuilder — unit suite. +contract JobSpecBuilderTest is BuilderFixtures { + /// @dev `positionManager.ownerOf(1234) == CEA` on Ethereum: a CEA-target check, and no CEA fill. + function _ownerIsCEA() internal pure returns (JobSpecTemplate memory t) { + t.reads = new ReadTemplate[](1); + t.reads[0] = _read( + "1", + address(0x9051), + bytes4(keccak256("ownerOf(uint256)")), + abi.encode(uint256(1234)), + _noFills(), + abi.encodePacked(T_TUPLE, uint8(1), T_ADDRESS), + _f(0) + ); + t.checks = new CheckTemplate[](1); + t.checks[0] = _chk(0, Evaluation.COMPARE, Operation.EQUAL, TargetSource.CEA, 0); + t.logic = _rootOf(LogicKind.ALL, _one(0)); + t.params = new ParamBounds[](0); + } + + function test_JB01_fills() public view { + // one read on Ethereum and one on Base: each gets its own chain's CEA + JobSpecTemplate memory t = _either(); + t.reads[1] = _balanceOfCEA("8453", WETH_BASE); + t.checks[1] = _chk(1, Evaluation.COMPARE, Operation.GREATER_OR_EQUAL, TargetSource.FIXED, 1); + JobSpec memory s = _build(t, _ctx(100e6, _noParams())); + assertEq(s.reads[0].args, abi.encode(builder.ceaFor(AGW, ETH_HASH)), "eth read: eth CEA"); + assertEq(s.reads[1].args, abi.encode(builder.ceaFor(AGW, BASE_HASH)), "base read: base CEA"); + assertTrue(builder.ceaFor(AGW, ETH_HASH) != builder.ceaFor(AGW, BASE_HASH)); + + // PARAM fills, positive and negative; untouched words keep their bytes + JobSpecTemplate memory p = _swap(); + p.params[0] = ParamBounds({min: type(int256).min, max: type(int256).max}); + p.reads[0].args = abi.encode(uint256(7), uint256(0), uint256(9)); + p.reads[0].fills = new Fill[](2); + p.reads[0].fills[0] = Fill({word: 1, source: FillSource.PARAM, param: 0}); + p.reads[0].fills[1] = Fill({word: 2, source: FillSource.CEA, param: 0}); + s = _build(p, _ctx(1, _oneParam(-5))); + assertEq(s.reads[0].args, abi.encode(uint256(7), int256(-5), builder.ceaFor(AGW, BASE_HASH))); + } + + function test_JB02_targets() public view { + // PRINCIPAL_BPS rounds down: 100_000_001 × 9999 / 10_000 = 99_990_000.9999 → 99_990_000 + JobSpec memory s = _build(_lending(), _ctx(100_000_001, _noParams())); + assertEq(s.checks[0].target, 99_990_000); + assertEq(s.checks[1].target, 0.04e27, "FIXED"); + s = _build(_lending(), _ctx(100e6, _noParams())); + assertEq(s.checks[0].target, 99.99e6, "exact"); + + s = _build(_swap(), _ctx(1, _oneParam(0.38e18))); + assertEq(s.checks[0].target, 0.38e18, "PARAM"); + + s = _build(_ownerIsCEA(), _ctx(1, _noParams())); + assertEq(s.checks[0].target, int256(uint256(uint160(builder.ceaFor(AGW, ETH_HASH)))), "CEA"); + assertEq(s.reads[0].args, abi.encode(uint256(1234)), "a read without fills is copied as is"); + } + + function test_JB03_timingAndOrigin() public view { + JobSpecTemplate memory t = _nested(); + JobSpec memory s = _build(t, _ctx(100e6, _noParams())); + assertEq(s.executeBy, 1_800_000_000); + assertEq(s.failFinalAt, 1_800_000_000 + 2 hours); + assertEq(s.origin, keccak256("origin")); + assertEq(keccak256(abi.encode(s.logic)), keccak256(abi.encode(t.logic)), "logic verbatim"); + assertEq(uint8(s.allowedMutability), uint8(t.allowedMutability), "mutability verbatim"); + for (uint256 i; i < t.reads.length; ++i) { + assertEq(s.reads[i].chainNamespace, t.reads[i].chainNamespace); + assertEq(s.reads[i].chainId, t.reads[i].chainId); + assertEq(s.reads[i].minConfirmations, t.reads[i].minConfirmations); + assertEq(s.reads[i].target, t.reads[i].target); + assertEq(s.reads[i].selector, t.reads[i].selector); + assertEq(s.reads[i].outputs, t.reads[i].outputs); + assertEq(keccak256(abi.encode(s.reads[i].field)), keccak256(abi.encode(t.reads[i].field))); + } + for (uint256 i; i < t.checks.length; ++i) { + assertEq(s.checks[i].read, t.checks[i].read); + assertEq(uint8(s.checks[i].evaluation), uint8(t.checks[i].evaluation)); + assertEq(uint8(s.checks[i].operation), uint8(t.checks[i].operation)); + } + } + + function test_JB04_params() public { + bytes memory swap = abi.encode(_swap()); + vm.expectRevert(abi.encodeWithSelector(UniversalMarketplaceErrors.ParamCountMismatch.selector, 1, 0)); + builder.build(swap, _ctx(1, _noParams())); + + vm.expectRevert(abi.encodeWithSelector(UniversalMarketplaceErrors.ParamOutOfRange.selector, 0, int256(0))); + builder.build(swap, _ctx(1, _oneParam(0))); + vm.expectRevert( + abi.encodeWithSelector(UniversalMarketplaceErrors.ParamOutOfRange.selector, 0, int256(1e30 + 1)) + ); + builder.build(swap, _ctx(1, _oneParam(1e30 + 1))); + builder.build(swap, _ctx(1, _oneParam(1))); // both bounds are inclusive + builder.build(swap, _ctx(1, _oneParam(1e30))); + } + + function test_JB05_targetOverflow() public { + // PRINCIPAL_BPS: the product principal × bps overflows. (Once it fits, the quotient is at most + // uint256.max / 10_000, always inside int256: this is the one overflow there is.) + JobSpecTemplate memory t = _lending(); + t.checks[0].value = 2; + bytes memory enc = abi.encode(t); + vm.expectRevert(abi.encodeWithSelector(UniversalMarketplaceErrors.TargetOverflow.selector, 0)); + builder.build(enc, _ctx(2 ** 255, _noParams())); + // the largest principal whose product fits builds + uint256 largest = type(uint256).max / 2; + JobSpec memory s = _build(t, _ctx(largest, _noParams())); + assertEq(uint256(s.checks[0].target), largest * 2 / 10_000); + } + + function test_JB06_fillOutOfBounds() public { + // a fill on the last word builds; one word further does not, whatever its source + JobSpecTemplate memory t = _swap(); + t.reads[0].args = new bytes(64); + t.reads[0].fills[0].word = 1; + _build(t, _ctx(1, _oneParam(1))); + + t.reads[0].fills[0].word = 2; + bytes memory enc = abi.encode(t); + vm.expectRevert(abi.encodeWithSelector(UniversalMarketplaceErrors.FillOutOfBounds.selector, 0, 0)); + builder.build(enc, _ctx(1, _oneParam(1))); + + t = _swap(); + t.reads[0].fills = new Fill[](2); + t.reads[0].fills[0] = Fill({word: 0, source: FillSource.CEA, param: 0}); + t.reads[0].fills[1] = Fill({word: 1, source: FillSource.PARAM, param: 0}); // args are one word long + enc = abi.encode(t); + vm.expectRevert(abi.encodeWithSelector(UniversalMarketplaceErrors.FillOutOfBounds.selector, 0, 1)); + builder.build(enc, _ctx(1, _oneParam(1))); + } + + function test_JB07_ceaOnUnsupportedChain() public { + bytes32 polygon = keccak256("eip155:137"); + JobSpecTemplate memory t = _swap(); + t.reads[0].chainId = "137"; // a CEA fill on a chain without a CEA deployment + bytes memory enc = abi.encode(t); + vm.expectRevert(abi.encodeWithSelector(UniversalMarketplaceErrors.ChainNotSupported.selector, polygon)); + builder.build(enc, _ctx(1, _oneParam(1))); + + t = _ownerIsCEA(); + t.reads[0].chainId = "137"; // a CEA target on such a chain + enc = abi.encode(t); + vm.expectRevert(abi.encodeWithSelector(UniversalMarketplaceErrors.ChainNotSupported.selector, polygon)); + builder.build(enc, _ctx(1, _noParams())); + + // no CEA anywhere: no chain is asked, so an unsupported chain is fine + t = _ownerIsCEA(); + t.reads[0].chainId = "137"; + t.checks[0] = _chk(0, Evaluation.COMPARE, Operation.EQUAL, TargetSource.FIXED, 7); + _build(t, _ctx(1, _noParams())); + } + + /// @dev The builder does not judge criteria: a template the evaluator could not run (an unread read, an + /// unreachable logic step, outputs that are not types) still builds, copied as given. + function test_JB08_doesNotJudgeTheTemplate() public view { + JobSpecTemplate memory t = _lending(); + ReadTemplate[] memory reads = new ReadTemplate[](3); + (reads[0], reads[1]) = (t.reads[0], t.reads[1]); + reads[2] = _read("1", SPARK, BALANCE_OF, "", _noFills(), hex"ff00", new uint8[](0)); + t.reads = reads; + Logic[] memory logic = new Logic[](2); + logic[0] = t.logic[0]; + logic[1] = _step(LogicKind.ALL, _one(1), _none(), 0); // reached by nobody + t.logic = logic; + JobSpec memory s = _build(t, _ctx(100e6, _noParams())); + assertEq(s.reads.length, 3); + assertEq(s.reads[2].outputs, hex"ff00"); + assertEq(s.logic.length, 2); + } + + function test_JB09_malformedTemplate_reverts() public { + // Not an abi-encoded JobSpecTemplate: the decode fails with no revert data. A bare expectRevert is the + // only possible assertion. + vm.expectRevert(); + builder.build(hex"deadbeef", _ctx(1, _noParams())); + } + + function test_JB12_copiesLogicAndMutability() public view { + JobSpecTemplate memory t = _nested(); + t.allowedMutability = AllowedMutability.PROVIDER; + JobSpec memory s = _build(t, _ctx(100e6, _noParams())); + assertEq(abi.encode(s.logic), abi.encode(t.logic), "two-level logic, byte-identical"); + assertEq(s.logic.length, 3); + assertEq(s.logic[0].children.length, 2, "root has two child steps"); + assertEq(uint8(s.allowedMutability), uint8(AllowedMutability.PROVIDER)); + } + + // ═════════════════════════════ fuzz ═════════════════════════════ + + function testFuzz_JB10_inBoundsNeverReverts(uint256 principal, int256 minOut) public view { + principal = bound(principal, 0, 2 ** 200); + minOut = bound(minOut, 1, 1e30); + JobSpec memory s = _build(_swap(), _ctx(principal, _oneParam(minOut))); + assertEq(s.checks[0].target, minOut); + _assertStructural(s); + + s = _build(_lending(), _ctx(principal, _noParams())); + assertEq(uint256(s.checks[0].target), principal * 9999 / 10_000); + _assertStructural(s); + } + + function testFuzz_JB11_deterministic(uint256 principal, bytes32 origin) public view { + principal = bound(principal, 0, 2 ** 200); + BuildContext memory ctx = _ctx(principal, _noParams()); + ctx.origin = origin; + bytes memory a = builder.build(abi.encode(_nested()), ctx); + bytes memory b = builder.build(abi.encode(_nested()), ctx); + assertEq(keccak256(a), keccak256(b)); + } + + /// @dev The structural rules the evaluator relies on, checked on the BUILT spec of a well-formed template. + function _assertStructural(JobSpec memory s) internal pure { + for (uint256 i; i < s.checks.length; ++i) { + assertLt(s.checks[i].read, s.reads.length); + } + for (uint256 i; i < s.logic.length; ++i) { + for (uint256 j; j < s.logic[i].checks.length; ++j) { + assertLt(s.logic[i].checks[j], s.checks.length); + } + for (uint256 j; j < s.logic[i].children.length; ++j) { + assertGt(s.logic[i].children[j], i); + assertLt(s.logic[i].children[j], s.logic.length); + } + } + } +} diff --git a/plan/marketplace/contracts/test/8183-tests/KernelBase.t.sol b/plan/marketplace/contracts/test/8183-tests/KernelBase.t.sol new file mode 100644 index 00000000..94afd32b --- /dev/null +++ b/plan/marketplace/contracts/test/8183-tests/KernelBase.t.sol @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import {Test} from "forge-std/Test.sol"; +import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import {ERC1967Utils} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol"; + +import {AgenticCommerce} from "../../src/agentic-commerce-8183/AgenticCommerce.sol"; +import {IAgenticCommerce} from "../../src/agentic-commerce-8183/interfaces/IAgenticCommerce.sol"; +import {MockERC20_6} from "./mocks/MockERC20_6.sol"; + +/// @notice Shared kernel fixture: token, kernel behind a Transparent proxy, actors, job helpers. +abstract contract KernelBase is Test { + AgenticCommerce internal kernel; + AgenticCommerce internal kernelImpl; + MockERC20_6 internal token; + + address internal kernelProxyAdminOwner = makeAddr("kernelProxyAdminOwner"); + address internal admin = makeAddr("admin"); + address internal treasury = makeAddr("treasury"); + address internal client = makeAddr("client"); + address internal provider = makeAddr("provider"); + address internal evaluator = makeAddr("evaluator"); + address internal stranger = makeAddr("stranger"); + + uint256 internal constant BUDGET = 100e6; + uint256 internal constant EXPIRY_OFFSET = 1 days; + + function setUp() public virtual { + vm.warp(1_700_000_000); + token = new MockERC20_6("Push USDC", "pUSDC"); + kernelImpl = new AgenticCommerce(); + kernel = AgenticCommerce(_deployKernelProxy(address(kernelImpl), address(token), treasury, admin)); + + token.mint(client, 1e15); + vm.prank(client); + token.approve(address(kernel), type(uint256).max); + } + + function _deployKernelProxy(address impl, address token_, address treasury_, address admin_) + internal + returns (address) + { + bytes memory initData = abi.encodeCall(AgenticCommerce.initialize, (token_, treasury_, admin_)); + return address(new TransparentUpgradeableProxy(impl, kernelProxyAdminOwner, initData)); + } + + function _proxyAdmin(address proxy) internal view returns (address) { + return address(uint160(uint256(vm.load(proxy, ERC1967Utils.ADMIN_SLOT)))); + } + + // ───────────── job helpers ───────────── + + function _expiry() internal view returns (uint256) { + return block.timestamp + EXPIRY_OFFSET; + } + + function _create(address hook) internal returns (uint256 jobId) { + vm.prank(client); + jobId = kernel.createJob(provider, evaluator, _expiry(), "job", hook); + } + + function _createNoProvider(address hook) internal returns (uint256 jobId) { + vm.prank(client); + jobId = kernel.createJob(address(0), evaluator, _expiry(), "job", hook); + } + + function _budgeted(address hook, uint256 amount) internal returns (uint256 jobId) { + jobId = _create(hook); + vm.prank(provider); + kernel.setBudget(jobId, amount, ""); + } + + function _funded(address hook, uint256 amount) internal returns (uint256 jobId) { + jobId = _budgeted(hook, amount); + vm.prank(client); + kernel.fund(jobId, amount, ""); + } + + function _submitted(address hook, uint256 amount) internal returns (uint256 jobId) { + jobId = _funded(hook, amount); + vm.prank(provider); + kernel.submit(jobId, keccak256("deliverable"), ""); + } + + function _status(uint256 jobId) internal view returns (IAgenticCommerce.JobStatus) { + return kernel.getJob(jobId).status; + } + + function _pause() internal { + vm.prank(admin); + kernel.pause(); + } +} diff --git a/plan/marketplace/contracts/test/8183-tests/Naming.t.sol b/plan/marketplace/contracts/test/8183-tests/Naming.t.sol new file mode 100644 index 00000000..7ed3693b --- /dev/null +++ b/plan/marketplace/contracts/test/8183-tests/Naming.t.sol @@ -0,0 +1,212 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import {Test} from "forge-std/Test.sol"; +import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; + +import {RulesBindingHook} from "../../src/agentic-commerce-8183/hooks/RulesBindingHook.sol"; +import {UniversalMarketplaceRules} from "../../src/agentic-commerce-8183/UniversalMarketplaceRules.sol"; +import {IUniversalMarketplace} from "../../src/agentic-commerce-8183/interfaces/IUniversalMarketplace.sol"; +import {IUniversalMarketplaceRules} from "../../src/agentic-commerce-8183/interfaces/IUniversalMarketplaceRules.sol"; +import { + UniversalMarketplaceErrors, + RulesBindingHookErrors, + ERC8183HookErrors +} from "../../src/agentic-commerce-8183/libraries/Errors.sol"; +import {MARKER_WALLET, MARKER_PRINCIPAL} from "../../src/agentic-commerce-8183/libraries/Types.sol"; + +/// @notice TEST ONLY: exposes the rules helper's ERC-20 selector constants. +contract RulesSelectorsHarness is UniversalMarketplaceRules { + function selectors() external pure returns (bytes4, bytes4, bytes4, bytes4) { + return (ERC20_TRANSFER, ERC20_APPROVE, ERC20_TRANSFER_FROM, ERC20_INCREASE_ALLOWANCE); + } +} + +/// @title Naming — the marketplace's v2 surface (PRD 12 §3, §6.8), pinned against LITERAL signatures. +/// @notice A rename that drifts from the PRD, or a type change that moved a selector, fails here. +contract NamingTest is Test { + // The struct tuples, spelled out: a field change moves every selector that takes one. + string internal constant AGENT_CARD = + "(address,bytes32,string,bytes32,string,uint256,address,uint256,uint256,uint32,uint32,uint32,uint32,bool)"; + string internal constant JOB_INPUTS = "(uint256,uint48,uint48,int256[])"; + string internal constant OWNER_INTENT = + "(address,address,address,uint96,bytes32,bytes32,bytes32,uint192,uint64,uint64,uint48,uint256)"; + string internal constant SESSION = + "(address,bytes,bytes32,(address,bytes)[],((bytes32,string[])[],(address,bytes)[]),(bytes4,address,(address,bytes)[])[],bool)"; + string internal constant SESSION_CONTEXT = "(address,bytes32,uint256,uint48,address)"; + + function _sel(string memory sig) internal pure returns (bytes4) { + return bytes4(keccak256(bytes(sig))); + } + + function test_naming_marketplaceFunctions() public pure { + assertEq( + IUniversalMarketplace.openJob.selector, + _sel( + string.concat( + "openJob((uint256,uint256,", JOB_INPUTS, ",", SESSION, ",", OWNER_INTENT, ",bytes,string))" + ) + ) + ); + assertEq( + IUniversalMarketplace.registerAgentCard.selector, + _sel(string.concat("registerAgentCard(", AGENT_CARD, ",bytes,bytes)")) + ); + assertEq( + IUniversalMarketplace.updateAgentCard.selector, + _sel(string.concat("updateAgentCard(uint256,", AGENT_CARD, ",bytes,bytes)")) + ); + assertEq(IUniversalMarketplace.setAgentCardActive.selector, _sel("setAgentCardActive(uint256,bool)")); + assertEq(IUniversalMarketplace.disableAgentCard.selector, _sel("disableAgentCard(uint256)")); + assertEq(IUniversalMarketplace.getAgentCard.selector, _sel("getAgentCard(uint256)")); + assertEq(IUniversalMarketplace.isAgentCardVerified.selector, _sel("isAgentCardVerified(uint256)")); + assertEq(IUniversalMarketplace.isAgentCardDisabled.selector, _sel("isAgentCardDisabled(uint256)")); + assertEq(IUniversalMarketplace.agentCardVersion.selector, _sel("agentCardVersion(uint256)")); + assertEq(IUniversalMarketplace.agentCardCount.selector, _sel("agentCardCount()")); + assertEq(IUniversalMarketplace.agentCardOf.selector, _sel("agentCardOf(address)")); + assertEq(IUniversalMarketplace.activeJobOf.selector, _sel("activeJobOf(address)")); + assertEq(IUniversalMarketplace.computeCEA.selector, _sel("computeCEA(address,bytes32)")); + assertEq(IUniversalMarketplace.cardVersionOfJob.selector, _sel("cardVersionOfJob(uint256)")); + assertEq(IUniversalMarketplace.getAgentRating.selector, _sel("getAgentRating(address)")); + assertEq(IUniversalMarketplace.setAgentRating.selector, _sel("setAgentRating(address,uint256)")); + assertEq(IUniversalMarketplace.RULES.selector, _sel("RULES()")); + assertEq(IUniversalMarketplace.PUSH_CHAIN_HASH.selector, _sel("PUSH_CHAIN_HASH()")); + assertEq(IUniversalMarketplace.version.selector, _sel("version()")); + assertEq(IUniversalMarketplace.AGW_FACTORY.selector, _sel("AGW_FACTORY()")); + assertEq(IUniversalMarketplace.KERNEL.selector, _sel("KERNEL()")); + assertEq( + IUniversalMarketplace.previewIntent.selector, + _sel( + string.concat( + "previewIntent((uint256,address,uint96,", JOB_INPUTS, ",uint48,uint256),", SESSION, ")" + ) + ) + ); + assertEq( + IUniversalMarketplaceRules.validateAgentCardRules.selector, _sel("validateAgentCardRules(bytes)") + ); + assertEq( + IUniversalMarketplaceRules.checkRulesMatchCard.selector, + _sel(string.concat("checkRulesMatchCard(bytes,", SESSION, ",", SESSION_CONTEXT, ")")) + ); + } + + function test_naming_marketplaceEvents() public pure { + assertEq( + IUniversalMarketplace.AgentCardRegistered.selector, + keccak256("AgentCardRegistered(uint256,address,bytes32,string,bytes32,bytes32,bytes32,uint256)") + ); + assertEq( + IUniversalMarketplace.AgentCardUpdated.selector, + keccak256("AgentCardUpdated(uint256,uint256,bytes32,bytes32,bytes32,uint256)") + ); + assertEq(IUniversalMarketplace.AgentCardStatusChanged.selector, keccak256("AgentCardStatusChanged(uint256,bool)")); + assertEq(IUniversalMarketplace.AgentCardDisabled.selector, keccak256("AgentCardDisabled(uint256)")); + assertEq(IUniversalMarketplace.AgentCardVerified.selector, keccak256("AgentCardVerified(uint256,uint256)")); + assertEq( + IUniversalMarketplace.AgentCardVerificationRevoked.selector, keccak256("AgentCardVerificationRevoked(uint256)") + ); + assertEq(IUniversalMarketplace.AgentRatingSet.selector, keccak256("AgentRatingSet(address,uint256)")); + assertEq(IUniversalMarketplace.HookUpdated.selector, keccak256("HookUpdated(address)")); + assertEq(IUniversalMarketplace.EvaluatorUpdated.selector, keccak256("EvaluatorUpdated(address)")); + assertEq( + IUniversalMarketplace.CEADeploymentSet.selector, keccak256("CEADeploymentSet(bytes32,address,address)") + ); + assertEq( + IUniversalMarketplace.JobOpened.selector, + keccak256("JobOpened(uint256,address,address,uint256,bytes32,uint256,uint256)") + ); + } + + function test_naming_hookTopicsAndErrors() public pure { + assertEq(RulesBindingHook.RulesBound.selector, keccak256("RulesBound(uint256,address,bytes32)")); + assertEq(RulesBindingHookErrors.RulesNotLive.selector, bytes4(keccak256("RulesNotLive(address,bytes32)"))); + assertEq(RulesBindingHookErrors.CallerIsNotAGW.selector, bytes4(keccak256("CallerIsNotAGW(address)"))); + assertEq(RulesBindingHookErrors.AGWHasLiveJob.selector, bytes4(keccak256("AGWHasLiveJob(address,uint256)"))); + assertEq(ERC8183HookErrors.CallerIsNotKernel.selector, bytes4(keccak256("CallerIsNotKernel(address)"))); + } + + function test_naming_marketplaceErrors() public pure { + assertEq(UniversalMarketplaceErrors.CallerIsNotProvider.selector, _sel("CallerIsNotProvider()")); + assertEq(UniversalMarketplaceErrors.ZeroAddress.selector, _sel("ZeroAddress()")); + assertEq(UniversalMarketplaceErrors.FillOutOfBounds.selector, _sel("FillOutOfBounds(uint256,uint256)")); + // renamed + assertEq(UniversalMarketplaceErrors.AgentCardInactive.selector, _sel("AgentCardInactive()")); + assertEq(UniversalMarketplaceErrors.AgentCardDisabled.selector, _sel("AgentCardDisabled(uint256)")); + assertEq(UniversalMarketplaceErrors.InvalidAgentCard.selector, _sel("InvalidAgentCard(string)")); + assertEq( + UniversalMarketplaceErrors.AgentCardVersionMismatch.selector, + _sel("AgentCardVersionMismatch(uint256,uint256)") + ); + assertEq(UniversalMarketplaceErrors.AgentCardIdentityImmutable.selector, _sel("AgentCardIdentityImmutable()")); + assertEq(UniversalMarketplaceErrors.WalletHasActiveJob.selector, _sel("WalletHasActiveJob(address,uint256)")); + assertEq(UniversalMarketplaceErrors.PrincipalCapMismatch.selector, _sel("PrincipalCapMismatch()")); + assertEq(UniversalMarketplaceErrors.GasCapMismatch.selector, _sel("GasCapMismatch()")); + assertEq(UniversalMarketplaceErrors.AssetMismatch.selector, _sel("AssetMismatch(uint256)")); + // new + assertEq( + UniversalMarketplaceErrors.AgentCardAlreadyRegistered.selector, _sel("AgentCardAlreadyRegistered(address)") + ); + assertEq(UniversalMarketplaceErrors.EnvelopeVersionMismatch.selector, _sel("EnvelopeVersionMismatch(uint256)")); + assertEq( + UniversalMarketplaceErrors.AssetCountMismatch.selector, _sel("AssetCountMismatch(uint256,uint256)") + ); + assertEq(UniversalMarketplaceErrors.PinMismatch.selector, _sel("PinMismatch(uint256,uint256)")); + } + + function test_naming_hookViews() public { + address kernel = makeAddr("kernel"); + address factory = makeAddr("factory"); + address engine = makeAddr("engine"); + RulesBindingHook hook = RulesBindingHook( + address( + new TransparentUpgradeableProxy( + address(new RulesBindingHook()), + makeAddr("hookAdmin"), + abi.encodeCall(RulesBindingHook.initialize, (kernel, factory, engine)) + ) + ) + ); + assertEq(hook.rulesOfJob.selector, _sel("rulesOfJob(uint256)")); + assertEq(hook.agwOfJob.selector, _sel("agwOfJob(uint256)")); + assertEq(hook.activeJobOf.selector, _sel("activeJobOf(address)")); + assertEq(hook.AGW_FACTORY.selector, _sel("AGW_FACTORY()")); + assertEq(hook.SESSION_ENGINE.selector, _sel("SESSION_ENGINE()")); + assertEq(hook.KERNEL.selector, _sel("KERNEL()")); + assertEq(hook.KERNEL(), kernel); + assertEq(hook.AGW_FACTORY(), factory); + assertEq(hook.SESSION_ENGINE(), engine); + assertEq(hook.rulesOfJob(1), bytes32(0)); + assertEq(hook.agwOfJob(1), address(0)); + } + + function test_naming_derivedErc20Selectors() public { + (bytes4 transfer, bytes4 approve, bytes4 transferFrom, bytes4 increaseAllowance) = + new RulesSelectorsHarness().selectors(); + assertEq(transfer, bytes4(0xa9059cbb)); + assertEq(approve, bytes4(0x095ea7b3)); + assertEq(transferFrom, bytes4(0x23b872dd)); + assertEq(increaseAllowance, bytes4(0x39509351)); + } + + function test_naming_markers() public pure { + assertEq(MARKER_WALLET, keccak256("push.marketplace.marker.WALLET")); + assertEq(MARKER_PRINCIPAL, keccak256("push.marketplace.marker.PRINCIPAL")); + // non-zero high 96 bits: neither marker is a clean address word, so neither can pass as a spender pin + assertGt(uint256(MARKER_WALLET) >> 160, 0); + assertGt(uint256(MARKER_PRINCIPAL) >> 160, 0); + } + + function test_naming_noMandateInABIs() public view { + string[3] memory artifacts = [ + "out/UniversalMarketplace.sol/UniversalMarketplace.json", + "out/UniversalMarketplaceRules.sol/UniversalMarketplaceRules.json", + "out/RulesBindingHook.sol/RulesBindingHook.json" + ]; + for (uint256 i; i < artifacts.length; ++i) { + string memory abiSection = vm.split(vm.readFile(artifacts[i]), '"bytecode"')[0]; + assertEq(vm.indexOf(abiSection, "andate"), type(uint256).max, artifacts[i]); + assertEq(vm.indexOf(abiSection, "permissionId"), type(uint256).max, artifacts[i]); + } + } +} diff --git a/plan/marketplace/contracts/test/8183-tests/RulesBindingHook.fork.t.sol b/plan/marketplace/contracts/test/8183-tests/RulesBindingHook.fork.t.sol new file mode 100644 index 00000000..397400e6 --- /dev/null +++ b/plan/marketplace/contracts/test/8183-tests/RulesBindingHook.fork.t.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import {Test} from "forge-std/Test.sol"; + +import {IAGWFactory} from "../../src/agentic-commerce-8183/interfaces/external/IAGWFactory.sol"; +import {ISmartSession} from "../../src/agentic-commerce-8183/interfaces/external/ISmartSession.sol"; + +/// @notice The v6 factory's owner-door deploy, which IAGWFactory does not mirror (the marketplace never calls it). +interface IAGWFactoryDeploy { + function deployWallet(string calldata label) external returns (address wallet); +} + +/// @notice Pins the AGW interfaces against the live Donut AGW v6 deployment. +/// @dev - Skips unless PUSH_CHAIN_TESTNET_RPC_URL is set (forge also reads it from `.env`); no default RPC. +/// - Forks `FORK_BLOCK` if set, else the latest block (the public Donut RPC is not archival). The block used is +/// logged. +/// - A wrong ABI reverts or decodes garbage, so passing calls pin it. The wallet is deployed on the fork, so the +/// test needs no pre-existing wallet. +contract RulesBindingHookForkTest is Test { + address internal constant FACTORY = 0xFBBEB6a365178fAaA81A9789a5f64b300c37e5bc; + address internal constant ENGINE = 0xf63DC0628fe1B25049FE3E3a3585Ef051CB98c1d; + + function test_fork_mirrorsMatchDeployedAGW() public { + string memory url = vm.envOr("PUSH_CHAIN_TESTNET_RPC_URL", string("")); + if (bytes(url).length == 0) { + vm.skip(true); + return; + } + uint256 blk = vm.envOr("FORK_BLOCK", uint256(0)); + if (blk == 0) vm.createSelectFork(url); + else vm.createSelectFork(url, blk); + emit log_named_uint("fork block", block.number); + + address eoa = makeAddr("forkWalletOwner"); + vm.prank(eoa); + address w = IAGWFactoryDeploy(FACTORY).deployWallet(""); + assertTrue(IAGWFactory(FACTORY).isWallet(w), "a freshly deployed wallet is an AGW"); + assertEq(IAGWFactory(FACTORY).ownerOf(w), eoa); + assertFalse(IAGWFactory(FACTORY).isWallet(makeAddr("nobody")), "random address is not"); + assertFalse(ISmartSession(ENGINE).isPermissionEnabled(bytes32(uint256(1)), w), "unknown id is not enabled"); + } +} diff --git a/plan/marketplace/contracts/test/8183-tests/RulesBindingHook.t.sol b/plan/marketplace/contracts/test/8183-tests/RulesBindingHook.t.sol new file mode 100644 index 00000000..8e43e242 --- /dev/null +++ b/plan/marketplace/contracts/test/8183-tests/RulesBindingHook.t.sol @@ -0,0 +1,438 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import {RulesBindingHookErrors, ERC8183HookErrors} from "../../src/agentic-commerce-8183/libraries/Errors.sol"; +import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import {ITransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {IERC20Errors} from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol"; + +import {IAgenticCommerce} from "../../src/agentic-commerce-8183/interfaces/IAgenticCommerce.sol"; +import {RulesBindingHook} from "../../src/agentic-commerce-8183/hooks/RulesBindingHook.sol"; +import {KernelBase} from "./KernelBase.t.sol"; +import {MockAGWFactory} from "./mocks/MockAGWFactory.sol"; +import {MockSmartSession} from "./mocks/MockSmartSession.sol"; +import {RecordingHook} from "./mocks/RecordingHook.sol"; + +/// @notice Phase 5 — mandate binding and one live job per AGW, driven through the real kernel. +contract RulesBindingHookTest is KernelBase { + RulesBindingHook internal hook; + RulesBindingHook internal hookImpl; + MockAGWFactory internal factory; + MockSmartSession internal engine; + address internal hookProxyAdminOwner = makeAddr("hookProxyAdminOwner"); + + /// @dev `client` from KernelBase acts as the AGW. + address internal agw; + bytes32 internal constant P = keccak256("mandate-1"); + bytes32 internal constant P2 = keccak256("mandate-2"); + + function setUp() public override { + super.setUp(); + agw = client; + factory = new MockAGWFactory(); + engine = new MockSmartSession(); + hookImpl = new RulesBindingHook(); + hook = RulesBindingHook(_deployHook(address(kernel), address(factory), address(engine))); + vm.prank(admin); + kernel.setHookWhitelist(address(hook), true); + + factory.setWallet(agw, true); + engine.setPermission(P, agw, true); + } + + function _deployHook(address k, address f, address e) internal returns (address) { + return address( + new TransparentUpgradeableProxy( + address(hookImpl), hookProxyAdminOwner, abi.encodeCall(RulesBindingHook.initialize, (k, f, e)) + ) + ); + } + + /// @dev Job by `cl`, budgeted, ready to fund. + function _open(address cl, uint256 amount) internal returns (uint256 jobId) { + vm.prank(cl); + jobId = kernel.createJob(provider, evaluator, _expiry(), "", address(hook)); + vm.prank(provider); + kernel.setBudget(jobId, amount, ""); + } + + function _bind(address cl, bytes32 pid, uint256 amount) internal returns (uint256 jobId) { + jobId = _open(cl, amount); + vm.prank(cl); + kernel.fund(jobId, amount, abi.encode(pid)); + } + + function _assertStillOpenAndUnbound(uint256 jobId, uint256 clientBalBefore) internal view { + assertEq(uint8(_status(jobId)), uint8(IAgenticCommerce.JobStatus.Open)); + assertEq(token.balanceOf(agw), clientBalBefore); + address a = hook.agwOfJob(jobId); + assertEq(a, address(0)); + } + + // ═════════════════════════ happy path ═════════════════════════ + + function test_fund_bindsRules() public { + uint256 jobId = _open(agw, BUDGET); + vm.expectEmit(address(hook)); + emit RulesBindingHook.RulesBound(jobId, agw, P); + vm.prank(agw); + kernel.fund(jobId, BUDGET, abi.encode(P)); + + (address a, bytes32 pid) = (hook.agwOfJob(jobId), hook.rulesOfJob(jobId)); + assertEq(a, agw); + assertEq(pid, P); + assertEq(hook.activeJobOf(agw), jobId); + assertEq(uint8(_status(jobId)), uint8(IAgenticCommerce.JobStatus.Funded)); + } + + function test_zeroBudgetJob_bindsNormally() public { + uint256 jobId = _bind(agw, P, 0); + assertEq(hook.activeJobOf(agw), jobId); + } + + // ═════════════════════════ check 1 · optParams length ═════════════════════════ + + function test_invalidOptParams_lengths() public { + uint256[4] memory lens = [uint256(0), 31, 33, 64]; + for (uint256 i = 0; i < lens.length; i++) { + uint256 jobId = _open(agw, BUDGET); + uint256 bal = token.balanceOf(agw); + vm.prank(agw); + vm.expectRevert(abi.encodeWithSelector(RulesBindingHookErrors.InvalidOptParams.selector, lens[i])); + kernel.fund(jobId, BUDGET, new bytes(lens[i])); + _assertStillOpenAndUnbound(jobId, bal); + } + } + + // ═════════════════════════ check 2 · client is an AGW ═════════════════════════ + + function test_notAnAGW_eoaClient() public { + address eoa = makeAddr("eoaClient"); + engine.setPermission(P, eoa, true); + uint256 jobId = _open(eoa, BUDGET); + vm.prank(eoa); + vm.expectRevert(abi.encodeWithSelector(RulesBindingHookErrors.CallerIsNotAGW.selector, eoa)); + kernel.fund(jobId, BUDGET, abi.encode(P)); + assertEq(uint8(_status(jobId)), uint8(IAgenticCommerce.JobStatus.Open)); + } + + function test_notAnAGW_contractClient() public { + address c = address(new MockSmartSession()); + uint256 jobId = _open(c, BUDGET); + uint256 bal = token.balanceOf(c); + vm.prank(c); + vm.expectRevert(abi.encodeWithSelector(RulesBindingHookErrors.CallerIsNotAGW.selector, c)); + kernel.fund(jobId, BUDGET, abi.encode(P)); + assertEq(token.balanceOf(c), bal); + assertEq(uint8(_status(jobId)), uint8(IAgenticCommerce.JobStatus.Open)); + address a = hook.agwOfJob(jobId); + assertEq(a, address(0)); + } + + // ═════════════════════════ check 3 · mandate live ═════════════════════════ + + function test_rulesNotLive_neverGranted() public { + uint256 jobId = _open(agw, BUDGET); + uint256 bal = token.balanceOf(agw); + vm.prank(agw); + vm.expectRevert(abi.encodeWithSelector(RulesBindingHookErrors.RulesNotLive.selector, agw, P2)); + kernel.fund(jobId, BUDGET, abi.encode(P2)); + _assertStillOpenAndUnbound(jobId, bal); + } + + function test_rulesNotLive_revoked() public { + engine.setPermission(P, agw, false); + uint256 jobId = _open(agw, BUDGET); + uint256 bal = token.balanceOf(agw); + vm.prank(agw); + vm.expectRevert(abi.encodeWithSelector(RulesBindingHookErrors.RulesNotLive.selector, agw, P)); + kernel.fund(jobId, BUDGET, abi.encode(P)); + _assertStillOpenAndUnbound(jobId, bal); + } + + function test_rulesOfAnotherWallet_notLiveHere() public { + address other = makeAddr("otherAGW"); + factory.setWallet(other, true); + engine.setPermission(P2, other, true); // P2 live on `other`, not on `agw` + uint256 jobId = _open(agw, BUDGET); + uint256 bal = token.balanceOf(agw); + vm.prank(agw); + vm.expectRevert(abi.encodeWithSelector(RulesBindingHookErrors.RulesNotLive.selector, agw, P2)); + kernel.fund(jobId, BUDGET, abi.encode(P2)); + _assertStillOpenAndUnbound(jobId, bal); + } + + // ═════════════════════════ check 4 · one live job per AGW ═════════════════════════ + + function test_secondJob_whileFirstFunded_reverts() public { + uint256 first = _bind(agw, P, BUDGET); + uint256 second = _open(agw, BUDGET); + uint256 bal = token.balanceOf(agw); + vm.prank(agw); + vm.expectRevert(abi.encodeWithSelector(RulesBindingHookErrors.AGWHasLiveJob.selector, agw, first)); + kernel.fund(second, BUDGET, abi.encode(P)); + _assertStillOpenAndUnbound(second, bal); + } + + function test_secondJob_whileFirstSubmitted_reverts() public { + uint256 first = _bind(agw, P, BUDGET); + vm.prank(provider); + kernel.submit(first, bytes32(0), ""); + assertEq(hook.activeJobOf(agw), first); + uint256 second = _open(agw, BUDGET); + uint256 bal = token.balanceOf(agw); + vm.prank(agw); + vm.expectRevert(abi.encodeWithSelector(RulesBindingHookErrors.AGWHasLiveJob.selector, agw, first)); + kernel.fund(second, BUDGET, abi.encode(P)); + _assertStillOpenAndUnbound(second, bal); + } + + // ═════════════════════════ freeing the AGW — every path ═════════════════════════ + + function _assertSecondJobFunds() internal { + assertEq(hook.activeJobOf(agw), 0); + uint256 second = _bind(agw, P, BUDGET); + assertEq(hook.activeJobOf(agw), second); + } + + function test_freed_afterComplete() public { + uint256 first = _bind(agw, P, BUDGET); + vm.prank(provider); + kernel.submit(first, bytes32(0), ""); + vm.prank(evaluator); + kernel.complete(first, bytes32(0), ""); + _assertSecondJobFunds(); + } + + function test_freed_afterReject() public { + uint256 first = _bind(agw, P, BUDGET); + vm.prank(evaluator); + kernel.reject(first, bytes32(0), ""); + _assertSecondJobFunds(); + } + + function test_freed_afterClaimRefund_unhooked() public { + uint256 first = _bind(agw, P, BUDGET); + vm.warp(block.timestamp + EXPIRY_OFFSET); + kernel.claimRefund(first); + _assertSecondJobFunds(); + } + + function test_freed_afterDetachThenRefund() public { + uint256 first = _bind(agw, P, BUDGET); + uint256[] memory ids = new uint256[](1); + ids[0] = first; + vm.prank(admin); + kernel.batchDetachHook(ids); + assertTrue(hook.activeJobOf(agw) != 0, "detach alone does not end the job"); + vm.warp(block.timestamp + EXPIRY_OFFSET); + kernel.claimRefund(first); + _assertSecondJobFunds(); + } + + // ═════════════════════════ isolation ═════════════════════════ + + function test_twoAGWs_eachHoldALiveJob() public { + address agw2 = makeAddr("agw2"); + factory.setWallet(agw2, true); + engine.setPermission(P2, agw2, true); + token.mint(agw2, 1e12); + vm.prank(agw2); + token.approve(address(kernel), type(uint256).max); + + uint256 a = _bind(agw, P, BUDGET); + uint256 b = _bind(agw2, P2, BUDGET); + assertEq(hook.activeJobOf(agw), a); + assertEq(hook.activeJobOf(agw2), b); + } + + function test_samePermissionId_differentAGWs_bindIndependently() public { + address agw2 = makeAddr("agw2"); + factory.setWallet(agw2, true); + engine.setPermission(P, agw2, true); // same id, different wallet + token.mint(agw2, 1e12); + vm.prank(agw2); + token.approve(address(kernel), type(uint256).max); + + uint256 a = _bind(agw, P, BUDGET); + uint256 b = _bind(agw2, P, BUDGET); + (address wa, bytes32 pa) = (hook.agwOfJob(a), hook.rulesOfJob(a)); + (address wb, bytes32 pb) = (hook.agwOfJob(b), hook.rulesOfJob(b)); + assertEq(wa, agw); + assertEq(wb, agw2); + assertEq(pa, P); + assertEq(pb, P); + } + + function test_sameRules_sequentialJobs_allowed() public { + uint256 first = _bind(agw, P, BUDGET); + vm.prank(evaluator); + kernel.reject(first, bytes32(0), ""); + uint256 second = _bind(agw, P, BUDGET); + bytes32 pid = hook.rulesOfJob(second); + assertEq(pid, P); + } + + // ═════════════════════════ caller auth ═════════════════════════ + + function test_beforeAction_directCall_reverts() public { + vm.prank(stranger); + vm.expectRevert(abi.encodeWithSelector(ERC8183HookErrors.CallerIsNotKernel.selector, stranger)); + hook.beforeAction(1, IAgenticCommerce.fund.selector, abi.encode(agw, abi.encode(P))); + } + + function test_afterAction_directCall_reverts() public { + vm.prank(stranger); + vm.expectRevert(abi.encodeWithSelector(ERC8183HookErrors.CallerIsNotKernel.selector, stranger)); + hook.afterAction(1, IAgenticCommerce.fund.selector, ""); + } + + // ═════════════════════════ no desync ═════════════════════════ + + /// @dev `_preFund` runs, then the kernel's transfer fails — the binding must roll back with it. + /// Asserted on state: a reverted call has no on-chain logs (Foundry's recorder keeps them anyway). + function test_transferFailsAfterHook_rollsBackBinding() public { + address agw3 = makeAddr("agw3-noAllowance"); + factory.setWallet(agw3, true); + engine.setPermission(P, agw3, true); + token.mint(agw3, 1e12); // funds but no approval + uint256 jobId = _open(agw3, BUDGET); + + vm.prank(agw3); + vm.expectRevert( + abi.encodeWithSelector(IERC20Errors.ERC20InsufficientAllowance.selector, address(kernel), 0, BUDGET) + ); + kernel.fund(jobId, BUDGET, abi.encode(P)); + + address a = hook.agwOfJob(jobId); + assertEq(a, address(0)); + assertEq(hook.activeJobOf(agw3), 0); + assertEq(uint8(_status(jobId)), uint8(IAgenticCommerce.JobStatus.Open)); + } + + // ═════════════════════════ initialisation ═════════════════════════ + + function test_initialize_setsState() public view { + assertEq(hook.KERNEL(), address(kernel)); + assertEq(hook.AGW_FACTORY(), address(factory)); + assertEq(hook.SESSION_ENGINE(), address(engine)); + } + + function test_initialize_zeroKernel_reverts() public { + vm.expectRevert(ERC8183HookErrors.ZeroAddress.selector); + _deployHook(address(0), address(factory), address(engine)); + } + + function test_initialize_zeroFactory_reverts() public { + vm.expectRevert(ERC8183HookErrors.ZeroAddress.selector); + _deployHook(address(kernel), address(0), address(engine)); + } + + function test_initialize_zeroEngine_reverts() public { + vm.expectRevert(ERC8183HookErrors.ZeroAddress.selector); + _deployHook(address(kernel), address(factory), address(0)); + } + + function test_initialize_twice_reverts() public { + vm.expectRevert(Initializable.InvalidInitialization.selector); + hook.initialize(address(kernel), address(factory), address(engine)); + } + + // ═════════════════════════ views ═════════════════════════ + + function test_activeJobOf_neverSeen_zero() public { + assertEq(hook.activeJobOf(makeAddr("never")), 0); + } + + function test_activeJobOf_returnsId() public { + assertEq(hook.activeJobOf(agw), 0, "before fund"); + uint256 jobId = _bind(agw, P, BUDGET); + assertEq(hook.activeJobOf(agw), jobId, "Funded"); + vm.prank(provider); + kernel.submit(jobId, bytes32(0), ""); + assertEq(hook.activeJobOf(agw), jobId, "Submitted"); + vm.prank(evaluator); + kernel.complete(jobId, bytes32(0), ""); + assertEq(hook.activeJobOf(agw), 0, "after complete"); + assertEq(hook.rulesOfJob(jobId), P, "the binding outlives the job"); + assertEq(hook.agwOfJob(jobId), agw); + } + + // ═════════════════════════ scope of the rule (D-25) ═════════════════════════ + + function test_scope_hooklessJob_fundsWhileBusy() public { + _bind(agw, P, BUDGET); + assertTrue(hook.activeJobOf(agw) != 0); + uint256 plain = _budgeted(address(0), BUDGET); // `client` == agw + vm.prank(agw); + kernel.fund(plain, BUDGET, ""); + assertEq(uint8(_status(plain)), uint8(IAgenticCommerce.JobStatus.Funded)); + } + + function test_scope_otherHookJob_doesNotTouchThisHook() public { + RecordingHook other = new RecordingHook(); + vm.prank(admin); + kernel.setHookWhitelist(address(other), true); + uint256 jobId = _budgeted(address(other), BUDGET); + vm.prank(agw); + kernel.fund(jobId, BUDGET, abi.encode(P)); + assertEq(hook.activeJobOf(agw), 0); + address a = hook.agwOfJob(jobId); + assertEq(a, address(0)); + } + + // ═════════════════════════ upgrade + layout ═════════════════════════ + + function test_upgrade_preservesBindingAndBlock() public { + uint256 first = _bind(agw, P, BUDGET); + ProxyAdmin pa = ProxyAdmin(_proxyAdmin(address(hook))); + assertEq(pa.owner(), hookProxyAdminOwner); + address newImpl = address(new RulesBindingHook()); + vm.prank(hookProxyAdminOwner); + pa.upgradeAndCall(ITransparentUpgradeableProxy(address(hook)), newImpl, ""); + + (address a, bytes32 pid) = (hook.agwOfJob(first), hook.rulesOfJob(first)); + assertEq(a, agw); + assertEq(pid, P); + assertEq(hook.activeJobOf(agw), first); + + uint256 second = _open(agw, BUDGET); + vm.prank(agw); + vm.expectRevert(abi.encodeWithSelector(RulesBindingHookErrors.AGWHasLiveJob.selector, agw, first)); + kernel.fund(second, BUDGET, abi.encode(P)); + } + + function test_upgrade_byNonOwner_reverts() public { + ProxyAdmin pa = ProxyAdmin(_proxyAdmin(address(hook))); + address impl = address(new RulesBindingHook()); + vm.prank(admin); + vm.expectRevert(abi.encodeWithSelector(Ownable.OwnableUnauthorizedAccount.selector, admin)); + pa.upgradeAndCall(ITransparentUpgradeableProxy(address(hook)), impl, ""); + } + + function test_storageLayout_bySlot() public { + uint256 jobId = _bind(agw, P, BUDGET); + address h = address(hook); + assertEq(address(uint160(uint256(vm.load(h, bytes32(uint256(0)))))), address(kernel)); + for (uint256 i = 1; i <= 49; i++) { + assertEq(vm.load(h, bytes32(i)), bytes32(0), "base gap"); + } + assertEq(address(uint160(uint256(vm.load(h, bytes32(uint256(50)))))), address(factory)); + assertEq(address(uint160(uint256(vm.load(h, bytes32(uint256(51)))))), address(engine)); + + bytes32 b = keccak256(abi.encode(jobId, uint256(52))); + assertEq(address(uint160(uint256(vm.load(h, b)))), agw); + assertEq(vm.load(h, bytes32(uint256(b) + 1)), P); + + // slots 52 / 53 unchanged: `_bindingOf` (was `rulesOf`), `_liveJobOf` (was `liveJobOf`) + bytes32 l = keccak256(abi.encode(agw, uint256(53))); + assertEq(uint256(vm.load(h, l)), jobId); + + for (uint256 i = 54; i <= 103; i++) { + assertEq(vm.load(h, bytes32(i)), bytes32(0), "hook gap"); + } + } +} diff --git a/plan/marketplace/contracts/test/8183-tests/UniversalMarketplace.conformance.t.sol b/plan/marketplace/contracts/test/8183-tests/UniversalMarketplace.conformance.t.sol new file mode 100644 index 00000000..fe4da737 --- /dev/null +++ b/plan/marketplace/contracts/test/8183-tests/UniversalMarketplace.conformance.t.sol @@ -0,0 +1,284 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import { + Evaluation, + Operation, + LogicKind, + Logic, + AllowedMutability, + Read, + Check, + JobSpec, + T_UINT, + T_ADDRESS, + T_TUPLE +} from "../../src/agentic-commerce-8183/libraries/JobSpecTypes.sol"; +import {BuilderFixtures} from "./JobSpecBuilder.t.sol"; +import {V2Decoder} from "./helpers/V2Decoder.sol"; +import {BuildContext, JobSpecTemplate} from "../../src/agentic-commerce-8183/libraries/Types.sol"; + +/// @title UniversalMarketplace — conformance with the Universal Evaluator V2 design (PRD 09 §7.5) +/// @notice What the marketplace builds must be exactly what the V2 doc's examples write by hand, and every read it +/// builds must decode in the V2 evaluator's decoder. +contract UniversalMarketplaceConformanceTest is BuilderFixtures { + V2Decoder internal decoder; + + uint64 internal executeBy; + uint64 internal failFinalAt; + + function setUp() public override { + super.setUp(); + decoder = new V2Decoder(); + executeBy = uint64(block.timestamp + 1 hours); // the doc's times + failFinalAt = uint64(block.timestamp + 2 hours); + } + + // ═════════════════════════════ the doc's specs, built by the marketplace ═════════════════════════════ + + function test_MC01_lendingExample_equalsV2Doc() public view { + JobSpec memory built = _build(_lending(), _docCtx(100e6, _noParams())); + address cea = builder.ceaFor(AGW, ETH_HASH); + + Read[] memory reads = new Read[](2); + reads[0] = _docRead("1", 12, AUSDC_ETH, BALANCE_OF, abi.encode(cea), _docUintOutputs(), _f(0)); + reads[1] = + _docRead("1", 12, AAVE_POOL_ETH, GET_RESERVE_DATA, abi.encode(USDC_ETH), _docReserveOutputs(), _f2(0, 2)); + Check[] memory checks = new Check[](2); + checks[0] = Check({read: 0, evaluation: Evaluation.COMPARE, operation: Operation.GREATER_OR_EQUAL, target: 99.99e6}); + checks[1] = Check({read: 1, evaluation: Evaluation.COMPARE, operation: Operation.GREATER_OR_EQUAL, target: 0.04e27}); + Logic[] memory logic = new Logic[](1); + logic[0] = Logic({kind: LogicKind.ALL, checks: _kids(0, 1), children: new uint8[](0), k: 0}); + + _assertSpecEq(built, _docSpec(reads, checks, logic)); + } + + function test_MC02_swapExample_equalsV2Doc() public view { + JobSpec memory built = _build(_swap(), _docCtx(0, _oneParam(0.38e18))); + address cea = builder.ceaFor(AGW, BASE_HASH); + + Read[] memory reads = new Read[](1); + reads[0] = _docRead("8453", 3, WETH_BASE, BALANCE_OF, abi.encode(cea), _docUintOutputs(), _f(0)); + Check[] memory checks = new Check[](1); + checks[0] = Check({read: 0, evaluation: Evaluation.NUMBER, operation: Operation.GREATER_OR_EQUAL, target: 0.38e18}); + Logic[] memory logic = new Logic[](1); + logic[0] = Logic({kind: LogicKind.ALL, checks: _one(0), children: new uint8[](0), k: 0}); + + _assertSpecEq(built, _docSpec(reads, checks, logic)); + } + + function test_MC03_orAndAtLeastExamples() public view { + address cea = builder.ceaFor(AGW, ETH_HASH); + + // ANY: "Aave or Morpho", spelled out in full in the doc. + JobSpec memory either = _build(_either(), _docCtx(100e6, _noParams())); + Read[] memory reads = new Read[](2); + reads[0] = _docRead("1", 12, AUSDC_ETH, BALANCE_OF, abi.encode(cea), _docUintOutputs(), _f(0)); + reads[1] = _docRead("1", 12, MORPHO_VAULT, MAX_WITHDRAW, abi.encode(cea), _docUintOutputs(), _f(0)); + Check[] memory checks = new Check[](2); + checks[0] = Check({read: 0, evaluation: Evaluation.COMPARE, operation: Operation.GREATER_OR_EQUAL, target: 99.99e6}); + checks[1] = Check({read: 1, evaluation: Evaluation.COMPARE, operation: Operation.GREATER_OR_EQUAL, target: 99.99e6}); + Logic[] memory logic = new Logic[](1); + logic[0] = Logic({kind: LogicKind.ANY, checks: _kids(0, 1), children: new uint8[](0), k: 0}); + _assertSpecEq(either, _docSpec(reads, checks, logic)); + + // Nested: the doc draws the tree only. ANY over two ALL steps: ALL(checks 0, 1) and ALL(checks 2, 3). + JobSpec memory nested = _build(_nested(), _docCtx(100e6, _noParams())); + Logic[] memory tree = new Logic[](3); + tree[0] = Logic({kind: LogicKind.ANY, checks: new uint8[](0), children: _kids(1, 2), k: 0}); + tree[1] = Logic({kind: LogicKind.ALL, checks: _kids(0, 1), children: new uint8[](0), k: 0}); + tree[2] = Logic({kind: LogicKind.ALL, checks: _kids(2, 3), children: new uint8[](0), k: 0}); + _assertLogicEq(nested.logic, tree); + + // AT_LEAST: "at least 2 of 3", each ≥ 99.99 USDC. + JobSpec memory twoOfThree = _build(_twoOfThree(), _docCtx(300e6, _noParams())); + Logic[] memory atLeast = new Logic[](1); + atLeast[0] = Logic({kind: LogicKind.AT_LEAST, checks: _kids3(0, 1, 2), children: new uint8[](0), k: 2}); + for (uint8 i; i < 3; ++i) { + assertEq(twoOfThree.checks[i].target, 99.99e6, "AT_LEAST: target"); + } + _assertLogicEq(twoOfThree.logic, atLeast); + } + + /// @dev The ABI head of a built JobSpec is: reads, checks, logic, allowedMutability, origin, executeBy, + /// failFinalAt. The three arrays are offsets; the four static fields sit in head words 3 to 6. + function test_MC05_fieldOrder() public view { + JobSpecTemplate memory t = _lending(); + t.allowedMutability = AllowedMutability.BOTH; + bytes memory built = builder.build(abi.encode(t), _docCtx(100e6, _noParams())); + JobSpec memory s = abi.decode(built, (JobSpec)); + assertEq(abi.encode(s), built, "round-trips"); + // `built` is abi.encode(spec): word 0 is the tuple's offset (32), the head starts at byte 32. + assertEq(_word(built, 0), 32, "tuple offset"); + assertEq(_word(built, 1 + 3), uint256(AllowedMutability.BOTH), "head 3: allowedMutability"); + assertEq(bytes32(_word(built, 1 + 4)), keccak256("origin"), "head 4: origin"); + assertEq(_word(built, 1 + 5), executeBy, "head 5: executeBy"); + assertEq(_word(built, 1 + 6), failFinalAt, "head 6: failFinalAt"); + assertEq(_word(built, 1 + 0), 7 * 32, "head 0: reads, the first dynamic tail right after the 7-word head"); + assertGt(_word(built, 1 + 1), _word(built, 1 + 0), "head 1: checks after reads"); + assertGt(_word(built, 1 + 2), _word(built, 1 + 1), "head 2: logic after checks"); + } + + function _word(bytes memory b, uint256 i) internal pure returns (uint256 w) { + assembly ("memory-safe") { + w := mload(add(add(b, 0x20), mul(i, 0x20))) + } + } + + // ═════════════════════════════ the reference decoder reads what the builder writes ═════════════════════════════ + + /// @dev Every read the marketplace builds for the doc's examples decodes in the V2 decoder. + function test_MC04_referenceDecoder_agrees() public view { + _assertBuiltReadsDecode(_build(_lending(), _docCtx(100e6, _noParams()))); + _assertBuiltReadsDecode(_build(_swap(), _docCtx(0, _oneParam(0.38e18)))); + _assertBuiltReadsDecode(_build(_either(), _docCtx(100e6, _noParams()))); + _assertBuiltReadsDecode(_build(_twoOfThree(), _docCtx(300e6, _noParams()))); + _assertBuiltReadsDecode(_build(_nested(), _docCtx(100e6, _noParams()))); + } + + // ═════════════════════════════ the doc's spellings ═════════════════════════════ + + /// @dev The doc's times: execute within 1 h, FAIL final 1 h later. + function _docCtx(uint256 principal, int256[] memory params) internal view returns (BuildContext memory ctx) { + ctx = _ctx(principal, params); + // forge-lint: disable-next-line(unsafe-typecast) + ctx.executeBy = uint48(executeBy); // now + 1 h + // forge-lint: disable-next-line(unsafe-typecast) + ctx.settleWindow = uint32(failFinalAt - executeBy); // 1 h + } + + function _docSpec(Read[] memory reads, Check[] memory checks, Logic[] memory logic) + internal + view + returns (JobSpec memory) + { + return JobSpec({ + reads: reads, + checks: checks, + logic: logic, + allowedMutability: AllowedMutability.NONE, + origin: keccak256("origin"), + executeBy: executeBy, + failFinalAt: failFinalAt + }); + } + + function _docRead( + string memory chainId, + uint16 confirmations, + address target, + bytes4 selector, + bytes memory args, + bytes memory outputs, + uint8[] memory field + ) internal pure returns (Read memory) { + return Read({ + chainNamespace: "eip155", + chainId: chainId, + minConfirmations: confirmations, + target: target, + selector: selector, + args: args, + outputs: outputs, + field: field + }); + } + + function _docUintOutputs() internal pure returns (bytes memory) { + return abi.encodePacked(T_TUPLE, uint8(1), T_UINT); + } + + /// @dev Line for line as the doc writes `getReserveData`'s outputs. + function _docReserveOutputs() internal pure returns (bytes memory) { + return bytes.concat( + abi.encodePacked(T_TUPLE, uint8(1)), + abi.encodePacked(T_TUPLE, uint8(15)), + abi.encodePacked(T_TUPLE, uint8(1), T_UINT), + abi.encodePacked(T_UINT), + abi.encodePacked(T_UINT), + abi.encodePacked(T_UINT, T_UINT, T_UINT), + abi.encodePacked(T_UINT, T_UINT), + abi.encodePacked(T_ADDRESS, T_ADDRESS, T_ADDRESS, T_ADDRESS), + abi.encodePacked(T_UINT, T_UINT, T_UINT) + ); + } + + /// @dev ReserveData with field k (k ≥ 1) = 1000 + k; `rate`, when non-zero, replaces currentLiquidityRate. + function _reserveAnswer(uint256 rate) internal pure returns (bytes memory res) { + res = abi.encode(uint256(1)); // configuration: a 1-field struct + for (uint256 k = 1; k < 15; ++k) { + uint256 w = k == 2 && rate != 0 ? rate : 1000 + k; + res = bytes.concat(res, bytes32(w)); + } + } + + // ═════════════════════════════ assertions ═════════════════════════════ + + /// @dev Every built read decodes in the V2 decoder, at a UINT leaf, to the value its answer holds. + function _assertBuiltReadsDecode(JobSpec memory spec) internal view { + for (uint256 i; i < spec.reads.length; ++i) { + Read memory r = spec.reads[i]; + bool isReserve = keccak256(r.outputs) == keccak256(_docReserveOutputs()); + bytes memory res = isReserve ? _reserveAnswer(0.052e27) : abi.encode(uint256(100e6 + i)); + // forge-lint: disable-next-line(unsafe-typecast) + _decodes(r.outputs, r.field, res, isReserve ? int256(0.052e27) : int256(100e6 + i)); // i < 16 + } + } + + function _decodes(bytes memory outputs, uint8[] memory field, bytes memory res, int256 value) internal view { + (bool located, uint8 leaf,) = decoder.locate(outputs, field, res); + assertTrue(located, "decoder: located"); + assertEq(leaf, T_UINT, "decoder: leaf"); + (bool ok, int256 v) = decoder.decodeAnswer(outputs, field, res); + assertTrue(ok, "decoder: ok"); + assertEq(v, value, "decoder: value"); + } + + function _assertSpecEq(JobSpec memory a, JobSpec memory b) internal pure { + assertEq(a.executeBy, b.executeBy, "executeBy"); + assertEq(a.failFinalAt, b.failFinalAt, "failFinalAt"); + assertEq(a.origin, b.origin, "origin"); + assertEq(a.reads.length, b.reads.length, "reads.length"); + for (uint256 i; i < a.reads.length; ++i) { + _assertReadEq(a.reads[i], b.reads[i]); + } + assertEq(a.checks.length, b.checks.length, "checks.length"); + for (uint256 i; i < a.checks.length; ++i) { + assertEq(a.checks[i].read, b.checks[i].read, "check.read"); + assertEq(uint8(a.checks[i].evaluation), uint8(b.checks[i].evaluation), "check.evaluation"); + assertEq(uint8(a.checks[i].operation), uint8(b.checks[i].operation), "check.operation"); + assertEq(a.checks[i].target, b.checks[i].target, "check.target"); + } + _assertLogicEq(a.logic, b.logic); + assertEq(uint8(a.allowedMutability), uint8(b.allowedMutability), "allowedMutability"); + assertEq(abi.encode(a), abi.encode(b), "description bytes"); + } + + function _assertReadEq(Read memory a, Read memory b) internal pure { + assertEq(a.chainNamespace, b.chainNamespace, "read.chainNamespace"); + assertEq(a.chainId, b.chainId, "read.chainId"); + assertEq(a.minConfirmations, b.minConfirmations, "read.minConfirmations"); + assertEq(a.target, b.target, "read.target"); + assertEq(a.selector, b.selector, "read.selector"); + assertEq(a.args, b.args, "read.args"); + assertEq(a.outputs, b.outputs, "read.outputs"); + _assertBytesEq(a.field, b.field, "read.field"); + } + + function _assertLogicEq(Logic[] memory a, Logic[] memory b) internal pure { + assertEq(a.length, b.length, "logic.length"); + for (uint256 i; i < a.length; ++i) { + assertEq(uint8(a[i].kind), uint8(b[i].kind), "logic.kind"); + assertEq(a[i].k, b[i].k, "logic.k"); + _assertBytesEq(a[i].checks, b[i].checks, "logic.checks"); + _assertBytesEq(a[i].children, b[i].children, "logic.children"); + } + } + + function _assertBytesEq(uint8[] memory a, uint8[] memory b, string memory what) internal pure { + assertEq(a.length, b.length, what); + for (uint256 i; i < a.length; ++i) { + assertEq(a[i], b[i], what); + } + } +} diff --git a/plan/marketplace/contracts/test/8183-tests/UniversalMarketplace.fork.t.sol b/plan/marketplace/contracts/test/8183-tests/UniversalMarketplace.fork.t.sol new file mode 100644 index 00000000..b2284156 --- /dev/null +++ b/plan/marketplace/contracts/test/8183-tests/UniversalMarketplace.fork.t.sol @@ -0,0 +1,317 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import {Test} from "forge-std/Test.sol"; +import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +import { + OwnerIntent, + UniversalTerms, + OWNER_INTENT_TYPEHASH, + OWNER_INTENT_DOMAIN_TYPEHASH, + OWNER_INTENT_DOMAIN_NAME_HASH, + OWNER_INTENT_DOMAIN_VERSION_HASH, + SEND_OUTBOUND_SELECTOR +} from "@push-agw/libraries/Types.sol"; +import {TemplateParts} from "./helpers/TemplateParts.sol"; +import {RulesFixtures, SessionSkeleton} from "./helpers/RulesFixtures.sol"; +import {MockERC20_6} from "./mocks/MockERC20_6.sol"; +import {AgenticCommerce} from "../../src/agentic-commerce-8183/AgenticCommerce.sol"; +import {IAgenticCommerce} from "../../src/agentic-commerce-8183/interfaces/IAgenticCommerce.sol"; +import {RulesBindingHook} from "../../src/agentic-commerce-8183/hooks/RulesBindingHook.sol"; +import {UniversalMarketplace} from "../../src/agentic-commerce-8183/UniversalMarketplace.sol"; +import {UniversalMarketplaceRules} from "../../src/agentic-commerce-8183/UniversalMarketplaceRules.sol"; +import {UniversalMarketplaceErrors} from "../../src/agentic-commerce-8183/libraries/Errors.sol"; +import {IAGWFactory} from "../../src/agentic-commerce-8183/interfaces/external/IAGWFactory.sol"; +import {ISmartSession} from "../../src/agentic-commerce-8183/interfaces/external/ISmartSession.sol"; +import {Session} from "../../src/agentic-commerce-8183/interfaces/external/IAGW.sol"; +import { + Evaluation, + Operation, + LogicKind, + AllowedMutability, + JobSpec +} from "../../src/agentic-commerce-8183/libraries/JobSpecTypes.sol"; +import { + AgentCard, + AgentCardRules, + JobInputs, + OpenJobParams, + IntentRequest, + InitParams, + ReadTemplate, + TargetSource, + CheckTemplate, + ParamBounds, + JobSpecTemplate +} from "../../src/agentic-commerce-8183/libraries/Types.sol"; + +/// @notice The wallet's owner door (AGW `execute` is `onlyOwner`; the owner here is an EOA). +interface IAGWExecute { + function execute(bytes32 mode, bytes calldata executionCalldata) external payable; +} + +/// @title UniversalMarketplace — fork suite against the REAL AGW v6 on Donut (PRD 12 §6.9). +/// @notice Proves, against the deployed factory, wallet, URP, engine and AgentValidator: the versioned envelope, +/// multi-asset caps, pins with filled markers, the `Session` mirror (via the session hash) and the imported +/// `OwnerIntent` (via the owner's signature). +/// @dev - Skips unless PUSH_CHAIN_TESTNET_RPC_URL is set (forge also reads `.env`). Forks the latest block, logged. +/// - The marketplace, its rules helper, a kernel and the hook are deployed on the fork; the AGW stack is live. +contract UniversalMarketplaceForkTest is Test, TemplateParts, RulesFixtures { + address internal constant FACTORY = 0xFBBEB6a365178fAaA81A9789a5f64b300c37e5bc; + address internal constant ENGINE = 0xf63DC0628fe1B25049FE3E3a3585Ef051CB98c1d; + address internal constant URP = 0xBA32e7A1500cb34311a31127bcD40CA52C8CFd36; + address internal constant AGENT_VALIDATOR = 0xBf08d8335c1cE41a577DB70666816027814737dD; + address internal constant GATEWAY_PC = 0x00000000000000000000000000000000000000C1; + address internal constant USDC_ETH = 0x7A58048036206bB898008b5bBDA85697DB1e5d66; // PRC20 USDC.eth (Sepolia) + address internal constant PETH = 0x2971824Db68229D087931155C2b8bB820B275809; // PRC20 pETH (Sepolia) + + string internal constant SEPOLIA_ID = "11155111"; + uint256 internal constant PRINCIPAL = 500e6; + uint256 internal constant BUDGET = 5e6; + + MockERC20_6 internal token; + AgenticCommerce internal kernel; + RulesBindingHook internal hook; + UniversalMarketplace internal mkt; + + address internal admin = makeAddr("forkAdmin"); + address internal provider = makeAddr("forkProvider"); + address internal evaluator = makeAddr("evaluator"); + address internal relayer = makeAddr("forkRelayer"); + address internal owner; + uint256 internal ownerKey; + + // made-up, non-zero Sepolia addresses: the destination calls are never executed here + address internal usdcSepolia = makeAddr("USDC.sepolia"); + address internal pool = makeAddr("aavePool.sepolia"); + address internal aUSDC = makeAddr("aUSDC.sepolia"); + + function _deploy() internal { + (owner, ownerKey) = makeAddrAndKey("forkOwner"); + token = new MockERC20_6("Push USDC", "pUSDC"); + kernel = AgenticCommerce( + address( + new TransparentUpgradeableProxy( + address(new AgenticCommerce()), + makeAddr("kernelProxyAdminOwner"), + abi.encodeCall(AgenticCommerce.initialize, (address(token), makeAddr("treasury"), admin)) + ) + ) + ); + hook = RulesBindingHook( + address( + new TransparentUpgradeableProxy( + address(new RulesBindingHook()), + makeAddr("hookAdmin"), + abi.encodeCall(RulesBindingHook.initialize, (address(kernel), FACTORY, ENGINE)) + ) + ) + ); + vm.prank(admin); + kernel.setHookWhitelist(address(hook), true); + + InitParams memory ip = InitParams({ + agwFactory: FACTORY, + kernel: address(kernel), + hook: address(hook), + evaluator: evaluator, + rules: address(new UniversalMarketplaceRules()), + admin: admin + }); + mkt = UniversalMarketplace( + address( + new TransparentUpgradeableProxy( + address(new UniversalMarketplace()), + makeAddr("mktAdmin"), + abi.encodeCall(UniversalMarketplace.initialize, (ip)) + ) + ) + ); + vm.prank(admin); + mkt.setCEADeployment(SEPOLIA_HASH, makeAddr("ceaFactory"), makeAddr("ceaProxyImpl")); + } + + function _card() internal view returns (AgentCard memory c) { + c.jobType = keccak256("LENDING_DEPOSIT"); + c.metadataURI = "ipfs://card"; + c.metadataHash = keccak256("card.json"); + c.chainNamespace = SEPOLIA; + c.providerFee = BUDGET; + c.paymentToken = address(token); + c.principalMin = 100e6; + c.principalMax = 1_000e6; + c.minDuration = 3 hours; + c.maxDuration = 30 days; + c.minExecuteWindow = 10 minutes; + c.settleWindow = 2 hours; + } + + function _rules() internal view returns (AgentCardRules memory) { + return _cardRulesTwoAssets(USDC_ETH, usdcSepolia, pool, PETH); + } + + function _lendingTemplate() internal view returns (JobSpecTemplate memory t) { + t.reads = new ReadTemplate[](2); + t.reads[0] = _balanceOfCEA(SEPOLIA_ID, aUSDC); + t.reads[1] = + _read(SEPOLIA_ID, pool, GET_RESERVE_DATA, abi.encode(usdcSepolia), _noFills(), _reserveDataOut(), _f2(0, 2)); + t.checks = new CheckTemplate[](2); + t.checks[0] = + _chk(0, Evaluation.COMPARE, Operation.GREATER_OR_EQUAL, TargetSource.PRINCIPAL_BPS, 9999); + t.checks[1] = _chk(1, Evaluation.COMPARE, Operation.GREATER_OR_EQUAL, TargetSource.FIXED, 0.04e27); + t.logic = _rootOf(LogicKind.ALL, _kids(0, 1)); + t.allowedMutability = AllowedMutability.NONE; + t.params = new ParamBounds[](0); + } + + /// @dev The real v6 values: the wallet refuses anything else (`MalformedSessionShape` / `RulesTypeMismatch`). + function _skeletonV6() internal pure returns (SessionSkeleton memory) { + return SessionSkeleton({ + validator: AGENT_VALIDATOR, actionTarget: GATEWAY_PC, actionSelector: SEND_OUTBOUND_SELECTOR, policy: URP + }); + } + + function _inputs() internal view returns (JobInputs memory j) { + j.principal = PRINCIPAL; + j.expiredAt = uint48(block.timestamp + 7 days); + j.executeBy = uint48(block.timestamp + 1 hours); + j.params = new int256[](0); + } + + function _sessionFor(address agw, JobInputs memory job) internal view returns (Session memory) { + UniversalTerms memory t = _fillTerms(_rules(), job.principal, job.expiredAt, mkt.computeCEA(agw, SEPOLIA_HASH)); + return _wrapSession(_envelope(t, SEPOLIA), provider, _skeletonV6()); + } + + function _sign(OwnerIntent memory intent) internal view returns (bytes memory) { + bytes32 domainSeparator = keccak256( + abi.encode( + OWNER_INTENT_DOMAIN_TYPEHASH, + OWNER_INTENT_DOMAIN_NAME_HASH, + OWNER_INTENT_DOMAIN_VERSION_HASH, + intent.signerChainId, + FACTORY, + bytes32(block.chainid) + ) + ); + bytes32 digest = + keccak256(abi.encodePacked("\x19\x01", domainSeparator, keccak256(abi.encode(OWNER_INTENT_TYPEHASH, intent)))); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(ownerKey, digest); + return abi.encodePacked(r, s, v); + } + + /// @dev An owner-signed openJob for wallet `index`, built the way the SDK does: session, previewIntent, sign. + function _signed(uint256 cardId, uint96 index, Session memory s, JobInputs memory job) + internal + view + returns (OpenJobParams memory p) + { + p.cardId = cardId; + p.cardVersion = mkt.agentCardVersion(cardId); + p.job = job; + p.session = s; + p.intent = mkt.previewIntent( + IntentRequest({ + cardId: cardId, + owner: owner, + index: index, + job: job, + deadline: uint48(block.timestamp + 1 hours), + signerChainId: block.chainid + }), + s + ); + p.sig = _sign(p.intent); + p.label = "fork"; + } + + function _ownerExecute(address agw, address target, bytes memory data) internal { + vm.prank(owner); + IAGWExecute(agw).execute(bytes32(0), abi.encodePacked(target, uint256(0), data)); + } + + function test_fork_openJob_realAGWv6() public { + string memory url = vm.envOr("PUSH_CHAIN_TESTNET_RPC_URL", string("")); + if (bytes(url).length == 0) { + vm.skip(true); + return; + } + vm.createSelectFork(url); + emit log_named_uint("fork block", block.number); + _deploy(); + + bytes memory rules = abi.encode(_rules()); + bytes memory template = abi.encode(_lendingTemplate()); + AgentCard memory card = _card(); + vm.prank(provider); + uint256 cardId = mkt.registerAgentCard(card, rules, template); + + // ── 1. openJob on a fresh wallet ── + uint96 index = uint96(IAGWFactory(FACTORY).walletCount(owner)); + (address agw, bool deployed) = IAGWFactory(FACTORY).predictWallet(owner, index); + assertFalse(deployed); + JobInputs memory job = _inputs(); + OpenJobParams memory p = _signed(cardId, index, _sessionFor(agw, job), job); + vm.prank(relayer); + (uint256 jobId, address opened, bytes32 rulesId) = mkt.openJob(p); + + assertEq(opened, agw); + assertTrue(IAGWFactory(FACTORY).isWallet(agw), "deployed by the real factory"); + assertTrue(ISmartSession(ENGINE).isPermissionEnabled(rulesId, agw), "rules live in the real engine"); + IAgenticCommerce.Job memory j = kernel.getJob(jobId); + assertEq(j.client, agw); + assertEq(j.provider, provider); + assertEq(j.hook, address(hook)); + assertEq(j.evaluator, evaluator); + JobSpec memory spec = abi.decode(bytes(j.description), (JobSpec)); + assertEq(abi.encode(spec.logic), abi.encode(_lendingTemplate().logic), "lending logic"); + assertEq(uint8(spec.allowedMutability), uint8(AllowedMutability.NONE)); + assertEq(spec.origin, keccak256(abi.encode(address(mkt), cardId, uint256(1), PRINCIPAL)), "origin"); + + // ── 2. fund through the hook, from the owner's own door ── + vm.prank(provider); + kernel.setBudget(jobId, BUDGET, ""); + token.mint(agw, BUDGET); + _ownerExecute(agw, address(token), abi.encodeCall(IERC20.approve, (address(kernel), BUDGET))); + _ownerExecute( + agw, address(kernel), abi.encodeCall(IAgenticCommerce.fund, (jobId, BUDGET, abi.encode(rulesId))) + ); + assertEq(uint8(kernel.getJob(jobId).status), uint8(IAgenticCommerce.JobStatus.Funded)); + assertEq(hook.rulesOfJob(jobId), rulesId); + assertEq(hook.agwOfJob(jobId), agw); + + // ── 3. a second openJob while Funded ── + JobInputs memory job2 = _inputs(); + OpenJobParams memory busy = _signed(cardId, index, _sessionFor(agw, job2), job2); + vm.prank(relayer); + vm.expectRevert(abi.encodeWithSelector(UniversalMarketplaceErrors.WalletHasActiveJob.selector, agw, jobId)); + mkt.openJob(busy); + + // ── 4. the existing-wallet path, once the job is Rejected ── + vm.prank(evaluator); + kernel.reject(jobId, bytes32(0), ""); + assertEq(mkt.activeJobOf(agw), 0); + OpenJobParams memory again = _signed(cardId, index, _sessionFor(agw, job2), job2); + assertEq(again.intent.grantNonce, 1, "the live grant nonce"); + assertEq(again.intent.nonceSeq, 1, "the live lane"); + vm.prank(relayer); + (uint256 jobId2, address same, bytes32 rulesId2) = mkt.openJob(again); + assertEq(same, agw); + assertEq(jobId2, jobId + 1); + assertTrue(ISmartSession(ENGINE).isPermissionEnabled(rulesId2, agw)); + assertTrue(rulesId2 != rulesId, "a new rules set"); + + // ── 5. a pre-v6 envelope is named by the marketplace; the AGW is never called ── + uint96 fresh = uint96(IAGWFactory(FACTORY).walletCount(owner)); + (address agw2,) = IAGWFactory(FACTORY).predictWallet(owner, fresh); + UniversalTerms memory t = _fillTerms(_rules(), PRINCIPAL, job2.expiredAt, mkt.computeCEA(agw2, SEPOLIA_HASH)); + Session memory preV6 = _wrapSession(abi.encode(SEPOLIA, abi.encode(t)), provider, _skeletonV6()); + OpenJobParams memory old = _signed(cardId, fresh, preV6, job2); + vm.prank(relayer); + vm.expectRevert(abi.encodeWithSelector(UniversalMarketplaceErrors.EnvelopeVersionMismatch.selector, 64)); + mkt.openJob(old); + assertFalse(IAGWFactory(FACTORY).isWallet(agw2), "nothing deployed"); + } +} diff --git a/plan/marketplace/contracts/test/8183-tests/UniversalMarketplace.invariants.t.sol b/plan/marketplace/contracts/test/8183-tests/UniversalMarketplace.invariants.t.sol new file mode 100644 index 00000000..f89f7d47 --- /dev/null +++ b/plan/marketplace/contracts/test/8183-tests/UniversalMarketplace.invariants.t.sol @@ -0,0 +1,294 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import {Test} from "forge-std/Test.sol"; + +import {UniversalTerms} from "@push-agw/libraries/Types.sol"; +import {MarketplaceFixtures} from "./UniversalMarketplace.t.sol"; +import {MockAGW} from "./mocks/MockAGW.sol"; +import {UniversalMarketplaceErrors} from "../../src/agentic-commerce-8183/libraries/Errors.sol"; +import {IAgenticCommerce} from "../../src/agentic-commerce-8183/interfaces/IAgenticCommerce.sol"; +import {UniversalMarketplace} from "../../src/agentic-commerce-8183/UniversalMarketplace.sol"; +import {JobSpec} from "../../src/agentic-commerce-8183/libraries/JobSpecTypes.sol"; +import { + AgentCard, + AgentCardRules, + JobInputs, + OpenJobParams +} from "../../src/agentic-commerce-8183/libraries/Types.sol"; + +/// @notice Drives openJob through honest and misbehaving wallets on a swap card (one param), card registration by +/// a small set of providers, the card's update, cancels and time. Records what every opened job must look +/// like. +contract MarketplaceHandler is MarketplaceFixtures { + uint256 public cardId; + address[] public agws; + uint256[] public jobs; + mapping(uint256 => bytes32) public expectedOrigin; + /// @notice Per opened job: the policy initData the wallet was granted, and the job's principal (MI07). + mapping(uint256 => bytes) public grantedInitData; + mapping(uint256 => uint256) public grantedPrincipal; + address[3] public providers; + uint256 public userTokenStart; + uint256 public userAssetStart; + uint256 public userEthStart; + + /// @notice Outcome counters. `opened` and `refused` are the liveness evidence (afterInvariant); the + /// "unexpected" counters must stay zero. Counters rather than vm.expectRevert: with + /// fail_on_revert = false an unmet expectation inside a handler is a discarded call. + uint256 public opened; + uint256 public refused; + uint256 public honestRefused; + uint256 public misbehaviourAccepted; + uint256 public wrongRefusal; + uint256 public duplicateCardAccepted; + uint256 public wrongRegistrationRefusal; + + constructor() { + setUp(); + cardId = _registerSwap(); + providers = [provider, provider2, makeAddr("provider3")]; + userTokenStart = token.balanceOf(user); + userAssetStart = pUSDC.balanceOf(user); + userEthStart = user.balance; + } + + function agwCount() external view returns (uint256) { + return agws.length; + } + + function jobCount() external view returns (uint256) { + return jobs.length; + } + + function marketplace() external view returns (address) { + return address(mkt); + } + + function job(uint256 jobId) external view returns (IAgenticCommerce.Job memory) { + return kernel.getJob(jobId); + } + + function balances(address who) external view returns (uint256 tokenBal, uint256 assetBal, uint256 ethBal) { + return (token.balanceOf(who), pUSDC.balanceOf(who), who.balance); + } + + function principalAssetOf(uint256 id) external view returns (uint8) { + return abi.decode(mkt.getAgentCard(id).rules, (AgentCardRules)).principalAsset; + } + + /// @param misbehave 0 honest · 1 wallet creates two jobs · 2 wallet creates the job from another address. + /// An honest open on a free wallet MUST succeed; a misbehaving one MUST fail with its named error. + function open(uint256 principalSeed, uint256 executeSeed, uint256 paramSeed, uint8 misbehave) external { + uint8 mode = misbehave % 3; + (uint96 index, address agw, bool deployed) = _freeWallet(); + JobInputs memory j = _swapInputs(int256(bound(paramSeed, 1, 1e30))); + j.principal = bound(principalSeed, 100e6, 1_000e6); + j.executeBy = uint48(bound(executeSeed, block.timestamp + 10 minutes, j.expiredAt - 2 hours)); + OpenJobParams memory p = _readyAt(cardId, index, _rules(), j); + + if (mode != 0 && !deployed) { + vm.prank(user); + factory.deployWalletWithSig(p.intent, "", ""); + deployed = true; + } + if (deployed) MockAGW(payable(agw)).setMode(MockAGW.Mode(mode)); + + uint256 before = kernel.jobCounter(); + vm.prank(relayer); + try mkt.openJob(p) returns (uint256 jobId, address, bytes32) { + if (mode == 0) { + opened++; + _record(agw, jobId, j.principal); + } else { + misbehaviourAccepted++; + } + } catch (bytes memory err) { + if (mode == 0) { + honestRefused++; + } else { + refused++; + bytes memory expected = mode == 1 + ? abi.encodeWithSelector(UniversalMarketplaceErrors.UnexpectedJobCount.selector, before, before + 2) + : abi.encodeWithSelector(UniversalMarketplaceErrors.JobMismatch.selector); + if (keccak256(err) != keccak256(expected)) wrongRefusal++; + } + } + if (deployed) MockAGW(payable(agw)).setMode(MockAGW.Mode.Honest); + } + + /// @notice One of three providers tries to register a card. A provider who already has one MUST be refused with + /// `AgentCardAlreadyRegistered`; one who has none MUST succeed. + function register(uint256 seed) external { + address who = providers[seed % providers.length]; + bool had = mkt.agentCardOf(who) != 0; + AgentCard memory c = _card(); + bytes memory r = abi.encode(_rules()); + bytes memory e = abi.encode(_lendingTemplate()); + vm.prank(who); + try mkt.registerAgentCard(c, r, e) returns (uint256) { + if (had) duplicateCardAccepted++; + } catch (bytes memory err) { + bytes memory expected = + abi.encodeWithSelector(UniversalMarketplaceErrors.AgentCardAlreadyRegistered.selector, who); + if (!had || keccak256(err) != keccak256(expected)) wrongRegistrationRefusal++; + } + } + + /// @notice The provider re-publishes the card: same content, next version. + function update() external { + AgentCard memory c = _card(); + c.jobType = keccak256("SWAP"); + bytes memory r = abi.encode(_rules()); + bytes memory e = abi.encode(_swapTemplate()); + vm.prank(provider); + mkt.updateAgentCard(cardId, c, r, e); + } + + function cancel(uint256 seed) external { + if (agws.length == 0) return; + uint256 id = mkt.activeJobOf(agws[seed % agws.length]); + if (id == 0 || kernel.getJob(id).status != IAgenticCommerce.JobStatus.Open) return; + vm.prank(provider); + kernel.reject(id, bytes32(0), ""); + } + + function warp(uint256 secs) external { + vm.warp(block.timestamp + bound(secs, 1, 10 days)); + } + + /// @dev The user's last wallet if it has no active job, else the next one. + function _freeWallet() internal view returns (uint96 index, address agw, bool deployed) { + index = uint96(factory.walletCount(user)); + (agw, deployed) = factory.predictWallet(user, index); + if (index == 0) return (index, agw, deployed); + (address last,) = factory.predictWallet(user, index - 1); + if (mkt.activeJobOf(last) == 0) return (index - 1, last, true); + } + + function _record(address agw, uint256 jobId, uint256 principal) internal { + jobs.push(jobId); + expectedOrigin[jobId] = keccak256(abi.encode(address(mkt), cardId, mkt.agentCardVersion(cardId), principal)); + grantedInitData[jobId] = MockAGW(payable(agw)).lastPolicyInitData(); + grantedPrincipal[jobId] = principal; + for (uint256 i; i < agws.length; ++i) { + if (agws[i] == agw) return; + } + agws.push(agw); + } +} + +/// @title UniversalMarketplace — invariants (PRD 12 §6.7). +/// @dev 64 runs × depth 100 per invariant (6,400 handler calls each): every call is a full openJob with criteria +/// built on-chain, so the defaults (256 × 500) take far longer. +/// forge-config: default.invariant.runs = 64 +/// forge-config: default.invariant.depth = 100 +contract UniversalMarketplaceInvariants is Test { + MarketplaceHandler internal h; + UniversalMarketplace internal mkt; + address internal user = makeAddr("userUEA"); + + function setUp() public { + h = new MarketplaceHandler(); + mkt = UniversalMarketplace(h.marketplace()); + + targetContract(address(h)); + bytes4[] memory sels = new bytes4[](5); + sels[0] = MarketplaceHandler.open.selector; + sels[1] = MarketplaceHandler.update.selector; + sels[2] = MarketplaceHandler.cancel.selector; + sels[3] = MarketplaceHandler.warp.selector; + sels[4] = MarketplaceHandler.register.selector; + targetSelector(FuzzSelector({addr: address(h), selectors: sels})); + } + + /// @notice An AGW's active job is always 0 or a job that AGW is the client of. + function invariant_MI01_activeJobIsTheAgwsOwnJob() public view { + uint256 n = h.agwCount(); + for (uint256 i; i < n; ++i) { + address agw = h.agws(i); + uint256 id = mkt.activeJobOf(agw); + if (id == 0) continue; + assertEq(h.job(id).client, agw, "activeJobOf points at a job the AGW is not client of"); + assertEq(mkt.agwOfJob(id), agw); + } + } + + /// @notice The marketplace never holds the payment token, the rules asset or PC. + function invariant_MI02_marketplaceHoldsNothing() public view { + (uint256 tokenBal, uint256 assetBal, uint256 ethBal) = h.balances(address(mkt)); + assertEq(tokenBal, 0); + assertEq(assetBal, 0); + assertEq(ethBal, 0); + } + + /// @notice An honest open on a free wallet always succeeds; a misbehaving wallet is always refused, with + /// its own named error. + function invariant_MI03_outcomesExactlyExpected() public view { + assertEq(h.honestRefused(), 0, "an honest openJob on a free wallet reverted"); + assertEq(h.misbehaviourAccepted(), 0, "a misbehaving wallet's openJob succeeded"); + assertEq(h.wrongRefusal(), 0, "a misbehaving wallet was refused with the wrong error"); + } + + /// @notice Every opened job carries well-formed criteria with the recorded origin, the configured evaluator + /// and hook, and is never Funded (only the test funds, and this handler never does). + function invariant_MI04_everyJobIsWellFormed() public view { + uint256 n = h.jobCount(); + for (uint256 i; i < n; ++i) { + uint256 id = h.jobs(i); + IAgenticCommerce.Job memory j = h.job(id); + JobSpec memory spec = abi.decode(bytes(j.description), (JobSpec)); + assertEq(spec.origin, h.expectedOrigin(id), "origin"); + assertEq(j.evaluator, mkt.evaluator(), "evaluator"); + assertEq(j.hook, mkt.hook(), "hook"); + assertTrue(j.status != IAgenticCommerce.JobStatus.Funded, "funded by nobody"); + } + } + + /// @notice openJob never moves the user's tokens or PC. + function invariant_MI05_userBalanceNeverMovedByOpenJob() public view { + (uint256 tokenBal, uint256 assetBal, uint256 ethBal) = h.balances(user); + assertEq(tokenBal, h.userTokenStart()); + assertEq(assetBal, h.userAssetStart()); + assertEq(ethBal, h.userEthStart()); + } + + /// @notice One card per provider: `agentCardOf[p]` is 0 or a card whose provider is `p`, and no two cards share + /// a provider. A second registration is always refused with its named error. + function invariant_MI06_onePerProvider() public view { + uint256 n = mkt.agentCardCount(); + for (uint256 id = 1; id <= n; ++id) { + address p = mkt.getAgentCard(id).card.provider; + assertEq(mkt.agentCardOf(p), id, "the card's provider maps back to it"); + for (uint256 other = 1; other < id; ++other) { + assertTrue(mkt.getAgentCard(other).card.provider != p, "two cards share a provider"); + } + } + for (uint256 i; i < 3; ++i) { + address p = h.providers(i); + uint256 id = mkt.agentCardOf(p); + if (id != 0) assertEq(mkt.getAgentCard(id).card.provider, p, "agentCardOf names another provider's card"); + } + assertEq(h.duplicateCardAccepted(), 0, "a provider registered a second card"); + assertEq(h.wrongRegistrationRefusal(), 0, "a registration was refused with the wrong error"); + } + + /// @notice The rules granted for every opened job cap the principal asset's lifetime total at exactly that + /// job's principal (D3). + function invariant_MI07_principalCapEqualsPrincipal() public view { + uint8 principalAsset = h.principalAssetOf(h.cardId()); + uint256 n = h.jobCount(); + for (uint256 i; i < n; ++i) { + uint256 id = h.jobs(i); + (,, bytes memory body) = abi.decode(h.grantedInitData(id), (uint16, string, bytes)); + UniversalTerms memory t = abi.decode(body, (UniversalTerms)); + assertEq(t.assets[principalAsset].maxTotal, h.grantedPrincipal(id), "maxTotal == principal"); + } + } + + /// @notice Liveness: the run reached BOTH paths, or every invariant above held vacuously. + function afterInvariant() public view { + assertGt(h.opened(), 0, "no honest openJob ever succeeded"); + assertGt(h.refused(), 0, "no misbehaving openJob was ever refused"); + } +} diff --git a/plan/marketplace/contracts/test/8183-tests/UniversalMarketplace.t.sol b/plan/marketplace/contracts/test/8183-tests/UniversalMarketplace.t.sol new file mode 100644 index 00000000..093dfdf7 --- /dev/null +++ b/plan/marketplace/contracts/test/8183-tests/UniversalMarketplace.t.sol @@ -0,0 +1,2144 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import { + TransparentUpgradeableProxy, + ITransparentUpgradeableProxy +} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; +import {ERC1967Utils} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol"; +import {IAccessControl} from "@openzeppelin/contracts/access/IAccessControl.sol"; +import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; + +import { + OwnerIntent, + OWNER_LANE_FLAG, + AssetCap, + AllowedCall, + ArgPin, + PinOp, + UniversalTerms +} from "@push-agw/libraries/Types.sol"; +import {KernelBase} from "./KernelBase.t.sol"; +import {TemplateParts} from "./helpers/TemplateParts.sol"; +import {RulesFixtures, SessionSkeleton} from "./helpers/RulesFixtures.sol"; +import {MockAGWFactory} from "./mocks/MockAGWFactory.sol"; +import {MockAGW} from "./mocks/MockAGW.sol"; +import {MockSmartSession} from "./mocks/MockSmartSession.sol"; +import {MockPRC20Source} from "./mocks/MockPRC20Source.sol"; +import {IAgenticCommerce} from "../../src/agentic-commerce-8183/interfaces/IAgenticCommerce.sol"; +import {RulesBindingHook} from "../../src/agentic-commerce-8183/hooks/RulesBindingHook.sol"; +import {UniversalMarketplace} from "../../src/agentic-commerce-8183/UniversalMarketplace.sol"; +import {UniversalMarketplaceRules} from "../../src/agentic-commerce-8183/UniversalMarketplaceRules.sol"; +import {IUniversalMarketplace} from "../../src/agentic-commerce-8183/interfaces/IUniversalMarketplace.sol"; +import {UniversalMarketplaceErrors} from "../../src/agentic-commerce-8183/libraries/Errors.sol"; +import {JobSpecBuilder} from "../../src/agentic-commerce-8183/libraries/JobSpecBuilder.sol"; +import { + Evaluation, + Operation, + LogicKind, + AllowedMutability, + JobSpec +} from "../../src/agentic-commerce-8183/libraries/JobSpecTypes.sol"; +import {Session, ActionData, PolicyData} from "../../src/agentic-commerce-8183/interfaces/external/IAGW.sol"; +import {CEAFactory} from "../../src/cea/CEAFactory.sol"; +import { + AgentCard, + AgentCardRules, + AgentCardView, + JobInputs, + OpenJobParams, + IntentRequest, + InitParams, + ReadTemplate, + TargetSource, + CheckTemplate, + ParamBounds, + JobSpecTemplate, + BuildContext, + MARKER_WALLET +} from "../../src/agentic-commerce-8183/libraries/Types.sol"; + +/// @notice TEST ONLY: runs JobSpecBuilder as the marketplace does, with CEAs from the real marketplace, so a test can +/// compute the description a job must carry. +contract MarketJobSpecBuilder { + IUniversalMarketplace internal immutable MARKET; + + constructor(IUniversalMarketplace market) { + MARKET = market; + } + + function build(bytes memory jobSpecTemplate, BuildContext memory ctx) external view returns (bytes memory) { + return JobSpecBuilder.build(jobSpecTemplate, ctx); + } + + function computeCEA(address agw, bytes32 chainHash) external view returns (address) { + return MARKET.computeCEA(agw, chainHash); + } +} + +/// @title MarketplaceFixtures — shared setup and builders for the marketplace unit and invariant suites. +/// @notice Real kernel, real RulesBindingHook, real rules helper and JobSpecBuilder library, real CEAFactory. The AGW +/// factory and wallet are mocks that enforce the rules the marketplace relies on and verify no signature; +/// `UniversalMarketplace.fork.t.sol` runs the real AGW v6 stack. +abstract contract MarketplaceFixtures is KernelBase, TemplateParts, RulesFixtures { + UniversalMarketplace internal mkt; + UniversalMarketplaceRules internal rulesHelper; + MarketJobSpecBuilder internal expectedBuilder; + RulesBindingHook internal hook; + MockAGWFactory internal factory; + MockSmartSession internal engine; + CEAFactory internal ceaFactory; + MockPRC20Source internal pUSDC; // the principal asset: pUSDC.sepolia, 6 decimals + MockPRC20Source internal pETH; // a second asset, 18 decimals + + address internal user = makeAddr("userUEA"); + address internal relayer = makeAddr("relayer"); + address internal mktAdmin = makeAddr("mktAdmin"); + address internal provider2 = makeAddr("provider2"); + address internal universalEvaluator = makeAddr("universalEvaluator"); + address internal ceaProxyImpl = makeAddr("ceaProxyImpl"); + address internal pool = makeAddr("aavePool.sepolia"); + address internal aUSDC = makeAddr("aUSDC.sepolia"); + address internal usdc = makeAddr("USDC.sepolia"); + address internal weth = makeAddr("WETH.sepolia"); + address internal gateway = makeAddr("universalGatewayPC"); + address internal urp = makeAddr("urp"); + address internal validator = makeAddr("sessionValidator"); + + string internal constant SEPOLIA_ID = "11155111"; + bytes4 internal constant SEND_OUTBOUND = + bytes4(keccak256("sendUniversalTxOutbound((bytes,address,uint256,uint256,uint256,uint256,bytes,address))")); + bytes4 internal constant WITHDRAW = bytes4(keccak256("withdraw(address,uint256,address)")); + + uint256 internal constant PRINCIPAL = 500e6; + uint256 internal constant FEE = 2e6; + + function setUp() public virtual override { + super.setUp(); + factory = new MockAGWFactory(); + engine = new MockSmartSession(); + RulesBindingHook hookImpl = new RulesBindingHook(); + hook = RulesBindingHook( + address( + new TransparentUpgradeableProxy( + address(hookImpl), + makeAddr("hookAdmin"), + abi.encodeCall(RulesBindingHook.initialize, (address(kernel), address(factory), address(engine))) + ) + ) + ); + vm.prank(admin); + kernel.setHookWhitelist(address(hook), true); + + rulesHelper = new UniversalMarketplaceRules(); + mkt = UniversalMarketplace( + address( + new TransparentUpgradeableProxy( + address(new UniversalMarketplace()), + mktAdmin, + abi.encodeCall(UniversalMarketplace.initialize, (_initParams())) + ) + ) + ); + + CEAFactory ceaImpl = new CEAFactory(); + ceaFactory = CEAFactory( + address( + new TransparentUpgradeableProxy( + address(ceaImpl), + makeAddr("ceaAdmin"), + abi.encodeCall( + CEAFactory.initialize, + (admin, admin, makeAddr("vault"), ceaProxyImpl, makeAddr("ceaImpl"), makeAddr("gateway")) + ) + ) + ) + ); + vm.prank(admin); + mkt.setCEADeployment(SEPOLIA_HASH, address(ceaFactory), ceaProxyImpl); + expectedBuilder = new MarketJobSpecBuilder(IUniversalMarketplace(address(mkt))); + + pUSDC = new MockPRC20Source("pUSDC.sepolia", SEPOLIA, 6); + pETH = new MockPRC20Source("pETH.sepolia", SEPOLIA, 18); + pUSDC.mint(user, 1e15); + token.mint(user, 1e15); + vm.deal(user, 100 ether); + } + + function _initParams() internal view returns (InitParams memory) { + return InitParams({ + agwFactory: address(factory), + kernel: address(kernel), + hook: address(hook), + evaluator: universalEvaluator, + rules: address(rulesHelper), + admin: admin + }); + } + + // ═════════════════════════════ cards ═════════════════════════════ + + /// @dev The lending card, on Sepolia, paid in the kernel's token. `minDuration` is 3 h so that a job at the + /// shortest expiry still fits `minExecuteWindow + settleWindow` (10 min + 2 h). + function _card() internal view returns (AgentCard memory c) { + c.jobType = keccak256("LENDING_DEPOSIT"); + c.metadataURI = "ipfs://card"; + c.metadataHash = keccak256("card.json"); + c.chainNamespace = SEPOLIA; + c.providerFee = FEE; + c.paymentToken = address(token); + c.principalMin = 100e6; + c.principalMax = 1_000e6; + c.minDuration = 3 hours; + c.maxDuration = 30 days; + c.minExecuteWindow = 10 minutes; + c.settleWindow = 2 hours; + } + + /// @dev PRD 12 §6.1: pUSDC (both caps the marker); approve USDC → Pool ≤ principal; supply onBehalfOf = wallet; + /// transfer to the wallet by the beneficiary field. + function _rules() internal view returns (AgentCardRules memory) { + return _cardRules(address(pUSDC), usdc, pool); + } + + /// @dev `_rules()` plus `{pETH, 0, 0}` as asset 1. + function _rulesTwoAssets() internal view returns (AgentCardRules memory) { + return _cardRulesTwoAssets(address(pUSDC), usdc, pool, address(pETH)); + } + + /// @dev The V2 doc's lending criteria on Sepolia: aUSDC.balanceOf(CEA) ≥ 99.99% of principal AND rate ≥ 4%. + function _lendingTemplate() internal view returns (JobSpecTemplate memory t) { + t.reads = new ReadTemplate[](2); + t.reads[0] = _balanceOfCEA(SEPOLIA_ID, aUSDC); + t.reads[1] = + _read(SEPOLIA_ID, pool, GET_RESERVE_DATA, abi.encode(usdc), _noFills(), _reserveDataOut(), _f2(0, 2)); + t.checks = new CheckTemplate[](2); + t.checks[0] = + _chk(0, Evaluation.COMPARE, Operation.GREATER_OR_EQUAL, TargetSource.PRINCIPAL_BPS, 9999); + t.checks[1] = _chk(1, Evaluation.COMPARE, Operation.GREATER_OR_EQUAL, TargetSource.FIXED, 0.04e27); + t.logic = _rootOf(LogicKind.ALL, _kids(0, 1)); + t.allowedMutability = AllowedMutability.NONE; + t.params = new ParamBounds[](0); + } + + /// @dev The V2 doc's swap criteria on Sepolia: the CEA's WETH grows by at least `minOut`, the job's param 0. + function _swapTemplate() internal view returns (JobSpecTemplate memory t) { + t.reads = new ReadTemplate[](1); + t.reads[0] = _balanceOfCEA(SEPOLIA_ID, weth); + t.reads[0].minConfirmations = 3; + t.checks = new CheckTemplate[](1); + t.checks[0] = _chk(0, Evaluation.NUMBER, Operation.GREATER_OR_EQUAL, TargetSource.PARAM, 0); + t.logic = _rootOf(LogicKind.ALL, _one(0)); + t.params = new ParamBounds[](1); + t.params[0] = ParamBounds({min: 1, max: 1e30}); + } + + function _registerAs(address who, AgentCard memory c, AgentCardRules memory r, JobSpecTemplate memory t) + internal + returns (uint256 id) + { + bytes memory rules = abi.encode(r); + bytes memory template = abi.encode(t); + vm.prank(who); + id = mkt.registerAgentCard(c, rules, template); + } + + function _register(AgentCard memory c, AgentCardRules memory r, JobSpecTemplate memory t) + internal + returns (uint256) + { + return _registerAs(provider, c, r, t); + } + + function _registerLending() internal returns (uint256) { + return _register(_card(), _rules(), _lendingTemplate()); + } + + function _registerSwap() internal returns (uint256) { + AgentCard memory c = _card(); + c.jobType = keccak256("SWAP"); + return _register(c, _rules(), _swapTemplate()); + } + + /// @dev The provider's lending card, registering it on first use (one card per provider). + function _lendingId() internal returns (uint256 id) { + id = mkt.agentCardOf(provider); + if (id == 0) id = _registerLending(); + } + + // ═════════════════════════════ jobs ═════════════════════════════ + + /// @dev Expires in 7 days; execute within 1 hour; no params. + function _inputs(uint256 principal) internal view returns (JobInputs memory j) { + j.principal = principal; + j.expiredAt = uint48(block.timestamp + 7 days); + j.executeBy = uint48(block.timestamp + 1 hours); + j.params = new int256[](0); + } + + function _swapInputs(int256 minOut) internal view returns (JobInputs memory j) { + j = _inputs(PRINCIPAL); + j.params = new int256[](1); + j.params[0] = minOut; + } + + /// @dev The unit-suite session skeleton: fields the marketplace never checks (the AGW pins them at grant). + function _skeleton() internal view returns (SessionSkeleton memory) { + return SessionSkeleton({ + validator: validator, actionTarget: gateway, actionSelector: SEND_OUTBOUND, policy: urp + }); + } + + /// @dev The terms an honest SDK signs for `r` and this job: markers filled, the marketplace's CEA. + function _termsFor(AgentCardRules memory r, address agw, JobInputs memory job) + internal + view + returns (UniversalTerms memory) + { + return _fillTerms(r, job.principal, job.expiredAt, mkt.computeCEA(agw, SEPOLIA_HASH)); + } + + /// @dev `t` in a v6 envelope on Sepolia, for `agent`, with the unit skeleton. + function _sessionAs(address agent, UniversalTerms memory t) internal view returns (Session memory) { + return _wrapSession(_envelope(t, SEPOLIA), agent, _skeleton()); + } + + function _sessionOf(UniversalTerms memory t) internal view returns (Session memory) { + return _sessionAs(provider, t); + } + + /// @dev PRD 12 §6.1: the session the SDK builds for card rules `r`, wallet `agw` and this job. + function _sessionFor(AgentCardRules memory r, address agw, JobInputs memory job) + internal + view + returns (Session memory) + { + return _sessionOf(_termsFor(r, agw, job)); + } + + function _params(uint256 cardId, uint96 index, JobInputs memory job, Session memory s) + internal + view + returns (OpenJobParams memory p) + { + p.cardId = cardId; + p.cardVersion = mkt.agentCardVersion(cardId); + p.job = job; + p.session = s; + p.intent = mkt.previewIntent( + IntentRequest({ + cardId: cardId, + owner: user, + index: index, + job: job, + deadline: uint48(block.timestamp + 1 hours), + signerChainId: 1 + }), + s + ); + p.sig = hex"01"; + p.label = "job"; + } + + /// @dev An honest, signed openJob for wallet `index` of the user, for the card's own agent. + function _readyAt(uint256 cardId, uint96 index, AgentCardRules memory r, JobInputs memory job) + internal + view + returns (OpenJobParams memory) + { + (address agw,) = factory.predictWallet(user, index); + address agent = mkt.getAgentCard(cardId).card.provider; + return _params(cardId, index, job, _sessionAs(agent, _termsFor(r, agw, job))); + } + + /// @dev An honest, signed openJob on the user's next (fresh) wallet. + function _ready(uint256 cardId) internal view returns (OpenJobParams memory) { + return _readyAt(cardId, uint96(factory.walletCount(user)), _rules(), _inputs(PRINCIPAL)); + } + + function _open(OpenJobParams memory p) internal returns (uint256 jobId, address agw) { + vm.prank(relayer); + (jobId, agw,) = mkt.openJob(p); + } + + function _expectOpen(OpenJobParams memory p, bytes memory err) internal { + vm.prank(relayer); + vm.expectRevert(err); + mkt.openJob(p); + } + + /// @dev The 8183 continuation outside the marketplace: the provider prices, the AGW funds with its rulesId. + function _budgetAndFund(uint256 jobId, address agw, uint256 amount) internal { + vm.prank(provider); + kernel.setBudget(jobId, amount, ""); + _fund(jobId, agw, amount); + } + + function _fund(uint256 jobId, address agw, uint256 amount) internal { + engine.setPermission(MockAGW(payable(agw)).RULES_ID(), agw, true); + token.mint(agw, amount); + vm.startPrank(agw); + token.approve(address(kernel), amount); + kernel.fund(jobId, amount, abi.encode(mkt.rulesOfJob(jobId))); + vm.stopPrank(); + } + + /// @dev The JobSpec bytes the card's template must give for this job. + function _expectedDescription( + JobSpecTemplate memory t, + uint256 cardId, + uint256 cardVersion, + address agw, + JobInputs memory job + ) internal view returns (bytes memory) { + return expectedBuilder.build( + abi.encode(t), + BuildContext({ + agw: agw, + principal: job.principal, + executeBy: job.executeBy, + settleWindow: _card().settleWindow, + params: job.params, + origin: keccak256(abi.encode(address(mkt), cardId, cardVersion, job.principal)) + }) + ); + } + + function _calldataHash(uint256 cardId, uint96 index, JobInputs memory job) internal view returns (bytes32) { + (, bytes memory cd) = mkt.buildCreateJobCalldata(cardId, user, index, job); + return keccak256(cd); + } + + /// @dev The policy terms the wallet was last granted, decoded from the v6 envelope. + function _granted(address agw) internal view returns (UniversalTerms memory) { + (,, bytes memory body) = abi.decode(MockAGW(payable(agw)).lastPolicyInitData(), (uint16, string, bytes)); + return abi.decode(body, (UniversalTerms)); + } + + /// @dev Pure on purpose: an external read here would consume a pending `vm.prank`. + function _adminRevert(address who) internal pure returns (bytes memory) { + return + abi.encodeWithSelector( + IAccessControl.AccessControlUnauthorizedAccount.selector, who, keccak256("ADMIN_ROLE") + ); + } +} + +/// @title UniversalMarketplace — unit suite (PRD 12 §6.2, §6.5). +contract UniversalMarketplaceTest is MarketplaceFixtures { + // ═════════════════════════════ MR · registration ═════════════════════════════ + + function test_MR01_registerAgentCard_storesEverythingAndEmits() public { + AgentCard memory c = _card(); + bytes memory r = abi.encode(_rules()); + bytes memory e = abi.encode(_lendingTemplate()); + vm.expectEmit(address(mkt)); + emit IUniversalMarketplace.AgentCardRegistered( + 1, provider, c.jobType, SEPOLIA, keccak256(r), keccak256(e), c.metadataHash, FEE + ); + vm.prank(provider); + uint256 id = mkt.registerAgentCard(c, r, e); + + assertEq(id, 1); + assertEq(mkt.agentCardCount(), 1); + assertEq(mkt.agentCardOf(provider), id); + AgentCardView memory v = mkt.getAgentCard(id); + assertEq(v.card.provider, provider); + assertEq(v.card.jobType, c.jobType); + assertEq(v.card.metadataURI, c.metadataURI); + assertEq(v.card.metadataHash, c.metadataHash); + assertEq(v.card.chainNamespace, SEPOLIA); + assertEq(v.card.providerFee, FEE); + assertEq(v.card.paymentToken, address(token)); + assertEq(v.card.principalMin, c.principalMin); + assertEq(v.card.principalMax, c.principalMax); + assertEq(v.card.minDuration, c.minDuration); + assertEq(v.card.maxDuration, c.maxDuration); + assertEq(v.card.minExecuteWindow, c.minExecuteWindow); + assertEq(v.card.settleWindow, c.settleWindow); + assertTrue(v.card.active); + assertEq(v.rules, r, "rules stored byte-equal"); + assertEq(v.jobSpecTemplate, e, "template stored byte-equal"); + assertEq(v.version, 1); + assertFalse(v.verified); + assertFalse(v.disabled); + assertEq(mkt.agentCardVersion(id), 1); + } + + function test_MR02_providerAndActiveAreContractWritten() public { + AgentCard memory c = _card(); + c.provider = stranger; + c.active = false; + uint256 id = _register(c, _rules(), _lendingTemplate()); + assertEq(mkt.getAgentCard(id).card.provider, provider); + assertTrue(mkt.getAgentCard(id).card.active); + assertEq(mkt.agentCardOf(stranger), 0); + } + + function _expectInvalidCard(AgentCard memory c, string memory reason) internal { + bytes memory r = abi.encode(_rules()); + bytes memory e = abi.encode(_lendingTemplate()); + vm.prank(provider); + vm.expectRevert(abi.encodeWithSelector(UniversalMarketplaceErrors.InvalidAgentCard.selector, reason)); + mkt.registerAgentCard(c, r, e); + } + + function test_MR03_eachInvalidCardField_reverts() public { + AgentCard memory c = _card(); + c.jobType = bytes32(0); + _expectInvalidCard(c, "job type zero"); + c = _card(); + c.metadataURI = ""; + _expectInvalidCard(c, "metadata uri empty"); + c = _card(); + c.metadataHash = bytes32(0); + _expectInvalidCard(c, "metadata hash zero"); + + string[5] memory badChains = + ["solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp", "eip155:", "eip155", "EIP155:11155111", ""]; + for (uint256 i; i < badChains.length; ++i) { + c = _card(); + c.chainNamespace = badChains[i]; + _expectInvalidCard(c, "chain namespace"); + } + + vm.prank(admin); + mkt.setEvaluator(provider); + _expectInvalidCard(_card(), "provider is evaluator"); + vm.prank(admin); + mkt.setEvaluator(universalEvaluator); + + c = _card(); + c.principalMin = 0; + c.principalMax = 0; + _expectInvalidCard(c, "principal range"); + c = _card(); + c.principalMin = 2; + c.principalMax = 1; + _expectInvalidCard(c, "principal range"); + c = _card(); + c.minDuration = 1 hours - 1; + _expectInvalidCard(c, "duration range"); + c = _card(); + c.minDuration = 2 days; + c.maxDuration = 1 days; + _expectInvalidCard(c, "duration range"); + c = _card(); + c.settleWindow = 0; + _expectInvalidCard(c, "settle window"); + c = _card(); + c.minExecuteWindow = 30 days - 2 hours + 1; + _expectInvalidCard(c, "execute window"); + + // every boundary passes: principal min == max, min duration 1 h, min == max duration, window == max + c = _card(); + c.principalMin = 7; + c.principalMax = 7; + c.minDuration = 1 hours; + c.minExecuteWindow = 30 days - 2 hours; + _register(c, _rules(), _lendingTemplate()); + c = _card(); + c.minDuration = 30 days; + _registerAs(provider2, c, _rules(), _lendingTemplate()); // one card per provider: a second provider + } + + function test_MR04_pushChain_refused() public { + string memory push = string.concat("eip155:", Strings.toString(block.chainid)); + bytes32 pushHash = keccak256(bytes(push)); + assertEq(mkt.PUSH_CHAIN_HASH(), pushHash); + vm.prank(admin); + mkt.setCEADeployment(pushHash, address(ceaFactory), ceaProxyImpl); // refused even with a deployment + AgentCard memory c = _card(); + c.chainNamespace = push; + bytes memory r = abi.encode(_rules()); + bytes memory e = abi.encode(_lendingTemplate()); + vm.prank(provider); + vm.expectRevert(abi.encodeWithSelector(UniversalMarketplaceErrors.ChainNotSupported.selector, pushHash)); + mkt.registerAgentCard(c, r, e); + } + + function test_MR05_unsupportedEvmChain_refused() public { + AgentCard memory c = _card(); + c.chainNamespace = "eip155:137"; + bytes memory r = abi.encode(_rules()); + bytes memory e = abi.encode(_lendingTemplate()); + vm.prank(provider); + vm.expectRevert( + abi.encodeWithSelector(UniversalMarketplaceErrors.ChainNotSupported.selector, keccak256("eip155:137")) + ); + mkt.registerAgentCard(c, r, e); + } + + function _expectInvalidRules(AgentCardRules memory r, string memory reason) internal { + bytes memory rules = abi.encode(r); + bytes memory e = abi.encode(_lendingTemplate()); + AgentCard memory c = _card(); + vm.prank(provider); + vm.expectRevert(abi.encodeWithSelector(UniversalMarketplaceErrors.InvalidAgentCard.selector, reason)); + mkt.registerAgentCard(c, rules, e); + } + + function test_MR06_assetTeeth() public { + AgentCardRules memory r = _rules(); + r.assets[0].token = makeAddr("codelessAsset"); + _expectInvalidRules(r, "asset"); + + MockPRC20Source.Answer[4] memory malformed = [ + MockPRC20Source.Answer.Reverts, + MockPRC20Source.Answer.Short, + MockPRC20Source.Answer.BadOffset, + MockPRC20Source.Answer.Overlong + ]; + for (uint256 i; i < malformed.length; ++i) { + pUSDC.setAnswer(malformed[i]); + _expectInvalidRules(_rules(), "asset"); + } + pUSDC.setAnswer(MockPRC20Source.Answer.Namespace); + pUSDC.setNamespace("eip155:1"); + _expectInvalidRules(_rules(), "asset chain"); + + pUSDC.setNamespace(SEPOLIA); + _registerLending(); + } + + function test_MR07_rulesErrorsSurface() public { + AgentCardRules memory r = _rules(); + r.allowedCalls[0].pins[1].op = PinOp.EQ; // the approve amount is no longer a ceiling + _expectInvalidRules(r, "approve amount not capped"); + } + + /// @dev The criteria template is stored as given: registration never judges it. A template that writes a fill + /// outside its args registers, and fails only when a job is built from it. + function test_MR08_criteriaNotJudgedAtRegistration() public { + JobSpecTemplate memory t = _lendingTemplate(); + ReadTemplate[] memory reads = new ReadTemplate[](3); + reads[0] = t.reads[0]; + reads[1] = t.reads[1]; + reads[2] = _balanceOfCEA(SEPOLIA_ID, weth); // read by no check + t.reads = reads; + t.reads[0].fills[0].word = 1; // args are one word long + uint256 id = _register(_card(), _rules(), t); + assertEq(mkt.getAgentCard(id).jobSpecTemplate, abi.encode(t), "stored byte-equal"); + + JobInputs memory job = _inputs(PRINCIPAL); + vm.expectRevert(abi.encodeWithSelector(UniversalMarketplaceErrors.FillOutOfBounds.selector, 0, 0)); + mkt.buildCreateJobCalldata(id, user, 0, job); // the same build openJob runs at step 9 + } + + function test_MR09_assetIndependent() public { + assertTrue(address(pETH) != address(kernel.paymentToken()), "pETH is not the kernel's payment token"); + AgentCardRules memory r = _rules(); + r.assets[0].token = address(pETH); + uint256 id = _register(_card(), r, _lendingTemplate()); + OpenJobParams memory p = _readyAt(id, 0, r, _inputs(PRINCIPAL)); + (uint256 jobId, address agw) = _open(p); + assertEq(kernel.getJob(jobId).client, agw); + assertEq(abi.decode(mkt.getAgentCard(id).rules, (AgentCardRules)).assets[0].token, address(pETH)); + } + + function test_MR10_paused() public { + vm.prank(admin); + mkt.pause(); + bytes memory r = abi.encode(_rules()); + bytes memory e = abi.encode(_lendingTemplate()); + AgentCard memory c = _card(); + vm.prank(provider); + vm.expectRevert(PausableUpgradeable.EnforcedPause.selector); + mkt.registerAgentCard(c, r, e); + } + + function test_MR11_onePerProvider() public { + uint256 id = _registerLending(); + assertEq(mkt.agentCardOf(provider), id); + + bytes memory r = abi.encode(_rules()); + bytes memory e = abi.encode(_swapTemplate()); + AgentCard memory c = _card(); + vm.prank(provider); + vm.expectRevert(abi.encodeWithSelector(UniversalMarketplaceErrors.AgentCardAlreadyRegistered.selector, provider)); + mkt.registerAgentCard(c, r, e); + + uint256 id2 = _registerAs(provider2, _card(), _rules(), _swapTemplate()); + assertEq(mkt.agentCardOf(provider2), id2); + assertEq(mkt.agentCardOf(provider), id, "unchanged"); + + vm.prank(admin); + mkt.disableAgentCard(id); + assertEq(mkt.agentCardOf(provider), id, "a disabled card still counts"); + vm.prank(provider); + vm.expectRevert(abi.encodeWithSelector(UniversalMarketplaceErrors.AgentCardAlreadyRegistered.selector, provider)); + mkt.registerAgentCard(c, r, e); + } + + function test_MR12_paymentTokenGuard() public { + address[2] memory bad = [address(pUSDC), address(0)]; + for (uint256 i; i < 2; ++i) { + AgentCard memory c = _card(); + c.paymentToken = bad[i]; + _expectInvalidCard(c, "payment token"); + } + uint256 id = _registerLending(); + assertEq(mkt.getAgentCard(id).card.paymentToken, address(kernel.paymentToken())); + + AgentCard memory u = _card(); + u.paymentToken = address(pUSDC); + _expectInvalidUpdate(id, u, abi.encode(_rules()), abi.encode(_lendingTemplate()), "payment token"); + _update(id, _card(), _rules(), _lendingTemplate()); + assertEq(mkt.agentCardVersion(id), 2); + } + + function test_MR13_everyAssetOnChain() public { + pETH.setNamespace("eip155:1"); + _expectInvalidRules(_rulesTwoAssets(), "asset chain"); + pETH.setNamespace(SEPOLIA); + + AgentCardRules memory r = _rulesTwoAssets(); + r.assets[1].token = makeAddr("codelessAsset1"); + _expectInvalidRules(r, "asset"); + + uint256 id = _register(_card(), _rulesTwoAssets(), _lendingTemplate()); + assertEq(abi.decode(mkt.getAgentCard(id).rules, (AgentCardRules)).assets.length, 2); + } + + function test_MR14_rulesErrorsSurface() public { + AgentCardRules memory r = _rules(); + r.assets = new AssetCap[](0); + _expectInvalidRules(r, "asset count"); + r = _rules(); + r.allowedCalls[1].pins[0].op = PinOp.MAX; + _expectInvalidRules(r, "wallet marker op"); + r = _rules(); + r.assets[0].maxTotal = PRINCIPAL; + _expectInvalidRules(r, "principal total not marker"); + + uint256 id = _registerLending(); + r = _rules(); + r.allowedCalls[0].selector = INCREASE_ALLOWANCE; + _expectInvalidUpdate(id, _card(), abi.encode(r), abi.encode(_lendingTemplate()), "increaseAllowance"); + } + + // ═════════════════════════════ ML · card lifecycle ═════════════════════════════ + + function test_ML01_setAgentCardActive() public { + uint256 id = _registerLending(); + vm.prank(stranger); + vm.expectRevert(UniversalMarketplaceErrors.CallerIsNotProvider.selector); + mkt.setAgentCardActive(id, false); + vm.prank(provider); + vm.expectRevert(UniversalMarketplaceErrors.CallerIsNotProvider.selector); + mkt.setAgentCardActive(999, false); + + vm.expectEmit(address(mkt)); + emit IUniversalMarketplace.AgentCardStatusChanged(id, false); + vm.prank(provider); + mkt.setAgentCardActive(id, false); + assertFalse(mkt.getAgentCard(id).card.active); + vm.prank(provider); + mkt.setAgentCardActive(id, true); + assertTrue(mkt.getAgentCard(id).card.active); + + vm.prank(admin); + mkt.disableAgentCard(id); + vm.prank(provider); + vm.expectRevert(abi.encodeWithSelector(UniversalMarketplaceErrors.AgentCardDisabled.selector, id)); + mkt.setAgentCardActive(id, true); + vm.prank(provider); + mkt.setAgentCardActive(id, false); // switching off stays allowed + } + + function test_ML02_disableAgentCard() public { + uint256 id = _registerLending(); + OpenJobParams memory p = _ready(id); + vm.prank(admin); + mkt.verifyAgentCard(id, 1); + + vm.prank(stranger); + vm.expectRevert(_adminRevert(stranger)); + mkt.disableAgentCard(id); + + vm.expectEmit(address(mkt)); + emit IUniversalMarketplace.AgentCardVerificationRevoked(id); + vm.expectEmit(address(mkt)); + emit IUniversalMarketplace.AgentCardDisabled(id); + vm.prank(admin); + mkt.disableAgentCard(id); + + AgentCardView memory v = mkt.getAgentCard(id); + assertTrue(v.disabled); + assertTrue(mkt.isAgentCardDisabled(id)); + assertFalse(v.card.active); + assertFalse(v.verified); + _expectOpen(p, abi.encodeWithSelector(UniversalMarketplaceErrors.AgentCardInactive.selector)); + + vm.prank(admin); + vm.expectRevert(UniversalMarketplaceErrors.AgentCardInactive.selector); + mkt.disableAgentCard(999); + } + + function test_ML03_verifyAgentCard() public { + uint256 id = _registerLending(); + vm.prank(stranger); + vm.expectRevert(_adminRevert(stranger)); + mkt.verifyAgentCard(id, 1); + vm.prank(admin); + vm.expectRevert(abi.encodeWithSelector(UniversalMarketplaceErrors.AgentCardVersionMismatch.selector, 2, 1)); + mkt.verifyAgentCard(id, 2); + vm.prank(admin); + vm.expectRevert(UniversalMarketplaceErrors.AgentCardInactive.selector); + mkt.verifyAgentCard(999, 1); + + vm.prank(provider); + mkt.setAgentCardActive(id, false); // a card its provider switched off can still be verified + vm.expectEmit(address(mkt)); + emit IUniversalMarketplace.AgentCardVerified(id, 1); + vm.prank(admin); + mkt.verifyAgentCard(id, 1); + assertTrue(mkt.isAgentCardVerified(id)); + assertTrue(mkt.getAgentCard(id).verified); + + uint256 disabled = _registerAs(provider2, _card(), _rules(), _lendingTemplate()); + vm.startPrank(admin); + mkt.disableAgentCard(disabled); + vm.expectRevert(abi.encodeWithSelector(UniversalMarketplaceErrors.AgentCardDisabled.selector, disabled)); + mkt.verifyAgentCard(disabled, 1); + vm.stopPrank(); + } + + function test_ML04_verify_racedByUpdate() public { + uint256 id = _registerLending(); + _update(id, _card(), _rules(), _lendingTemplate()); + vm.prank(admin); + vm.expectRevert(abi.encodeWithSelector(UniversalMarketplaceErrors.AgentCardVersionMismatch.selector, 1, 2)); + mkt.verifyAgentCard(id, 1); + vm.prank(admin); + mkt.verifyAgentCard(id, 2); + assertTrue(mkt.isAgentCardVerified(id)); + } + + function test_ML05_revokeVerification() public { + uint256 id = _registerLending(); + vm.prank(admin); + mkt.verifyAgentCard(id, 1); + vm.prank(stranger); + vm.expectRevert(_adminRevert(stranger)); + mkt.revokeAgentCardVerification(id); + + vm.expectEmit(address(mkt)); + emit IUniversalMarketplace.AgentCardVerificationRevoked(id); + vm.prank(admin); + mkt.revokeAgentCardVerification(id); + assertFalse(mkt.isAgentCardVerified(id)); + + vm.recordLogs(); + vm.prank(admin); + mkt.revokeAgentCardVerification(id); + assertEq(vm.getRecordedLogs().length, 0, "revoking an unverified card logs nothing"); + + vm.prank(admin); + vm.expectRevert(UniversalMarketplaceErrors.AgentCardInactive.selector); + mkt.revokeAgentCardVerification(999); + } + + function _update(uint256 id, AgentCard memory c, AgentCardRules memory r, JobSpecTemplate memory t) internal { + bytes memory rules = abi.encode(r); + bytes memory template = abi.encode(t); + vm.prank(provider); + mkt.updateAgentCard(id, c, rules, template); + } + + /// @dev Every mutable field changed, two assets, a fourth (withdraw) call, and the swap criteria. + function _updated() + internal + view + returns (AgentCard memory c, AgentCardRules memory r, JobSpecTemplate memory t) + { + c = _card(); + c.jobType = keccak256("SWAP"); + c.metadataURI = "ipfs://card-v2"; + c.metadataHash = keccak256("card-v2.json"); + c.providerFee = FEE * 3; + c.principalMin = 200e6; + c.principalMax = 2_000e6; + c.minDuration = 4 hours; + c.maxDuration = 10 days; + c.minExecuteWindow = 20 minutes; + c.settleWindow = 3 hours; + r = _rulesTwoAssets(); + r.maxGasPerCall = 2 ether; + r.allowedCalls = + _appendCall(r.allowedCalls, _allowed(pool, WITHDRAW, 0, false, _pins1(68, PinOp.EQ, MARKER_WALLET))); + t = _swapTemplate(); + t.allowedMutability = AllowedMutability.CLIENT; + } + + function _appendCall(AllowedCall[] memory calls, AllowedCall memory c) + internal + pure + returns (AllowedCall[] memory out) + { + out = new AllowedCall[](calls.length + 1); + for (uint256 i; i < calls.length; ++i) { + out[i] = calls[i]; + } + out[calls.length] = c; + } + + function test_ML06_update_updatesEveryMutableField() public { + uint256 id = _registerLending(); + vm.prank(provider); + mkt.setAgentCardActive(id, false); + (AgentCard memory c, AgentCardRules memory r, JobSpecTemplate memory t) = _updated(); + c.provider = stranger; // ignored + c.active = true; // ignored: the provider's switch stays off + bytes memory rules = abi.encode(r); + bytes memory template = abi.encode(t); + + vm.expectEmit(address(mkt)); + emit IUniversalMarketplace.AgentCardUpdated( + id, 2, keccak256(rules), keccak256(template), c.metadataHash, c.providerFee + ); + vm.prank(provider); + mkt.updateAgentCard(id, c, rules, template); + + AgentCardView memory v = mkt.getAgentCard(id); + assertEq(v.card.provider, provider, "provider kept"); + assertEq(v.card.chainNamespace, SEPOLIA, "chain kept"); + assertFalse(v.card.active, "active kept"); + assertEq(v.card.jobType, c.jobType); + assertEq(v.card.metadataURI, c.metadataURI); + assertEq(v.card.metadataHash, c.metadataHash); + assertEq(v.card.providerFee, c.providerFee); + assertEq(v.card.paymentToken, c.paymentToken); + assertEq(v.card.principalMin, c.principalMin); + assertEq(v.card.principalMax, c.principalMax); + assertEq(v.card.minDuration, c.minDuration); + assertEq(v.card.maxDuration, c.maxDuration); + assertEq(v.card.minExecuteWindow, c.minExecuteWindow); + assertEq(v.card.settleWindow, c.settleWindow); + assertEq(v.rules, rules); + assertEq(v.jobSpecTemplate, template); + assertEq(v.version, 2); + assertEq(mkt.agentCardCount(), 1, "no new card"); + + // and an active card stays active when the input says inactive + vm.prank(provider); + mkt.setAgentCardActive(id, true); + c.active = false; + _update(id, c, r, t); + assertTrue(mkt.getAgentCard(id).card.active); + assertEq(mkt.agentCardVersion(id), 3); + } + + function test_ML07_update_clearsVerification() public { + uint256 id = _registerLending(); + vm.prank(admin); + mkt.verifyAgentCard(id, 1); + AgentCard memory c = _card(); + bytes memory r = abi.encode(_rules()); + bytes memory e = abi.encode(_lendingTemplate()); + vm.expectEmit(address(mkt)); + emit IUniversalMarketplace.AgentCardVerificationRevoked(id); + vm.expectEmit(address(mkt)); + emit IUniversalMarketplace.AgentCardUpdated(id, 2, keccak256(r), keccak256(e), c.metadataHash, c.providerFee); + vm.prank(provider); + mkt.updateAgentCard(id, c, r, e); + assertFalse(mkt.isAgentCardVerified(id)); + } + + function test_ML08_update_access() public { + uint256 id = _registerLending(); + AgentCard memory c = _card(); + bytes memory r = abi.encode(_rules()); + bytes memory e = abi.encode(_lendingTemplate()); + + vm.prank(stranger); + vm.expectRevert(UniversalMarketplaceErrors.CallerIsNotProvider.selector); + mkt.updateAgentCard(id, c, r, e); + vm.prank(provider); + vm.expectRevert(UniversalMarketplaceErrors.CallerIsNotProvider.selector); + mkt.updateAgentCard(999, c, r, e); + + vm.prank(admin); + mkt.pause(); + vm.prank(provider); + vm.expectRevert(PausableUpgradeable.EnforcedPause.selector); + mkt.updateAgentCard(id, c, r, e); + vm.prank(admin); + mkt.unpause(); + + vm.prank(admin); + mkt.disableAgentCard(id); + vm.prank(provider); + vm.expectRevert(abi.encodeWithSelector(UniversalMarketplaceErrors.AgentCardDisabled.selector, id)); + mkt.updateAgentCard(id, c, r, e); + } + + function test_ML09_update_chainImmutable() public { + uint256 id = _registerLending(); + bytes32 baseSepolia = keccak256("eip155:84532"); + vm.prank(admin); + mkt.setCEADeployment(baseSepolia, address(ceaFactory), ceaProxyImpl); + AgentCard memory c = _card(); + c.chainNamespace = "eip155:84532"; + bytes memory r = abi.encode(_rules()); + bytes memory e = abi.encode(_lendingTemplate()); + vm.prank(provider); + vm.expectRevert(UniversalMarketplaceErrors.AgentCardIdentityImmutable.selector); + mkt.updateAgentCard(id, c, r, e); + } + + function test_ML10_update_validatesLikeRegistration() public { + uint256 id = _registerLending(); + AgentCard memory c = _card(); + c.settleWindow = 0; + _expectInvalidUpdate(id, c, abi.encode(_rules()), abi.encode(_lendingTemplate()), "settle window"); + + AgentCardRules memory r = _rules(); + r.allowedCalls[0].selector = INCREASE_ALLOWANCE; + _expectInvalidUpdate(id, _card(), abi.encode(r), abi.encode(_lendingTemplate()), "increaseAllowance"); + + assertEq(mkt.agentCardVersion(id), 1, "no failed update bumped the version"); + } + + function _expectInvalidUpdate(uint256 id, AgentCard memory c, bytes memory r, bytes memory e, string memory reason) + internal + { + vm.prank(provider); + vm.expectRevert(abi.encodeWithSelector(UniversalMarketplaceErrors.InvalidAgentCard.selector, reason)); + mkt.updateAgentCard(id, c, r, e); + } + + function test_ML11_update_invalidatesOldIntents() public { + uint256 id = _registerLending(); + OpenJobParams memory p = _ready(id); + _update(id, _card(), _rules(), _lendingTemplate()); // same content, version 2 + + _expectOpen(p, abi.encodeWithSelector(UniversalMarketplaceErrors.AgentCardVersionMismatch.selector, 1, 2)); + p.cardVersion = 2; + _expectOpen( + p, + abi.encodeWithSelector(UniversalMarketplaceErrors.IntentExecMismatch.selector, _calldataHash(id, 0, p.job)) + ); + assertEq(factory.walletCount(user), 0, "nothing deployed"); + } + + function test_ML12_update_leavesOpenedJobsUntouched() public { + uint256 id = _registerLending(); + (uint256 jobId, address agw) = _open(_ready(id)); + IAgenticCommerce.Job memory before = kernel.getJob(jobId); + + (AgentCard memory c, AgentCardRules memory r, JobSpecTemplate memory t) = _updated(); + _update(id, c, r, t); + + IAgenticCommerce.Job memory afterJob = kernel.getJob(jobId); + assertEq(afterJob.provider, before.provider); + assertEq(afterJob.evaluator, before.evaluator); + assertEq(afterJob.description, before.description); + assertEq(afterJob.hook, before.hook); + assertEq(mkt.cardOfJob(jobId), id); + assertEq(mkt.agwOfJob(jobId), agw); + assertEq(mkt.activeJobOf(agw), jobId); + assertEq(mkt.rulesOfJob(jobId), MockAGW(payable(agw)).RULES_ID()); + assertEq(mkt.cardVersionOfJob(jobId), 1, "the version the job was opened against"); + } + + function test_ML13_openJob_afterUpdate_usesNewContent() public { + uint256 id = _registerLending(); + JobSpecTemplate memory t = _lendingTemplate(); + t.checks[1].value = 0.05e27; + AgentCardRules memory r = _rules(); + r.maxGasPerCall = 2 ether; + _update(id, _card(), r, t); + + OpenJobParams memory p = _readyAt(id, 0, r, _inputs(PRINCIPAL)); + (uint256 jobId, address agw) = _open(p); + bytes memory description = bytes(kernel.getJob(jobId).description); + assertEq(description, _expectedDescription(t, id, 2, agw, p.job)); + JobSpec memory spec = abi.decode(description, (JobSpec)); + assertEq(spec.checks[1].target, 0.05e27, "the new criteria"); + assertEq(spec.origin, keccak256(abi.encode(address(mkt), id, uint256(2), PRINCIPAL)), "origin carries v2"); + assertEq(mkt.cardVersionOfJob(jobId), 2); + assertEq(_granted(agw).maxGasPerCall, 2 ether, "the new rules"); + } + + // ═════════════════════════════ MS · openJob ═════════════════════════════ + + function test_MS01_freshWallet_happyPath() public { + uint256 id = _registerLending(); + OpenJobParams memory p = _ready(id); + address agw = p.intent.wallet; + uint256 expectedJobId = kernel.jobCounter() + 1; + + vm.expectEmit(address(mkt)); + emit IUniversalMarketplace.JobOpened(id, user, agw, expectedJobId, keccak256("mock-rules"), PRINCIPAL, 1); + vm.prank(relayer); + (uint256 jobId, address got, bytes32 rulesId) = mkt.openJob(p); + + assertEq(jobId, expectedJobId); + assertEq(got, agw, "deployed at the predicted address"); + assertEq(factory.ownerOf(agw), user); + MockAGW w = MockAGW(payable(agw)); + assertEq(rulesId, w.RULES_ID()); + assertEq(w.lastSessionHash(), keccak256(abi.encode(p.session))); + assertEq(w.lastGrantIntentHash(), keccak256(abi.encode(p.intent)), "grant got the signed intent"); + assertEq(w.lastExecIntentHash(), keccak256(abi.encode(p.intent)), "exec got the same intent"); + assertEq(w.lastGrantCaller(), address(mkt)); + assertEq(w.lastExecCalldataHash(), _calldataHash(id, 0, p.job)); + + IAgenticCommerce.Job memory j = kernel.getJob(jobId); + assertEq(j.client, agw); + assertEq(j.provider, provider); + assertEq(j.evaluator, universalEvaluator); + assertEq(j.hook, address(hook)); + assertEq(j.expiredAt, p.job.expiredAt); + assertEq(j.budget, 0); + assertEq(uint8(j.status), uint8(IAgenticCommerce.JobStatus.Open)); + assertEq(bytes(j.description), _expectedDescription(_lendingTemplate(), id, 1, agw, p.job)); + + assertEq(mkt.activeJobOf(agw), jobId); + assertEq(mkt.cardOfJob(jobId), id); + assertEq(mkt.agwOfJob(jobId), agw); + assertEq(mkt.rulesOfJob(jobId), rulesId); + assertEq(mkt.cardVersionOfJob(jobId), 1); + } + + function test_MS02_movesNoFunds() public { + uint256 id = _registerLending(); + OpenJobParams memory p = _ready(id); + address agw = p.intent.wallet; + address[3] memory who = [user, agw, address(mkt)]; + uint256[3] memory tokenBefore; + uint256[3] memory assetBefore; + uint256[3] memory ethBefore; + for (uint256 i; i < 3; ++i) { + tokenBefore[i] = token.balanceOf(who[i]); + assetBefore[i] = pUSDC.balanceOf(who[i]); + ethBefore[i] = who[i].balance; + } + assertEq(token.allowance(user, address(mkt)), 0, "no allowance"); + assertEq(pUSDC.allowance(user, address(mkt)), 0, "no allowance"); + assertEq(agw.balance, 0, "no PC in the AGW"); + + _open(p); + + for (uint256 i; i < 3; ++i) { + assertEq(token.balanceOf(who[i]), tokenBefore[i], "payment token moved"); + assertEq(pUSDC.balanceOf(who[i]), assetBefore[i], "rules asset moved"); + assertEq(who[i].balance, ethBefore[i], "PC moved"); + } + assertEq(token.balanceOf(address(mkt)), 0); + assertEq(address(mkt).balance, 0); + } + + function test_MS03_existingWallet_skipsDeploy() public { + uint256 id = _registerLending(); + (uint256 job1, address agw) = _open(_ready(id)); + vm.prank(provider); + kernel.reject(job1, bytes32(0), ""); + + OpenJobParams memory p = _readyAt(id, 0, _rules(), _inputs(PRINCIPAL)); + assertEq(p.intent.grantNonce, 1, "preview reads the live grant nonce"); + assertEq(p.intent.nonceSeq, 1, "preview reads the live lane"); + (uint256 job2, address again) = _open(p); + assertEq(again, agw); + assertEq(factory.walletCount(user), 1, "no second wallet"); + assertEq(job2, job1 + 1); + assertEq(MockAGW(payable(agw)).grantNonce(), 2, "rules granted again"); + assertEq(mkt.activeJobOf(agw), job2); + } + + function test_MS04_existingWallet_wrongOwner() public { + uint256 id = _registerLending(); + (uint256 job1, address agw) = _open(_ready(id)); + vm.prank(provider); + kernel.reject(job1, bytes32(0), ""); + OpenJobParams memory p = _readyAt(id, 0, _rules(), _inputs(PRINCIPAL)); + // the factory's registry disagrees with the derivation (MockAGWFactory.ownerOf is slot 2) + vm.store(address(factory), keccak256(abi.encode(agw, uint256(2))), bytes32(uint256(uint160(stranger)))); + _expectOpen(p, abi.encodeWithSelector(UniversalMarketplaceErrors.WalletOwnerMismatch.selector, user, stranger)); + } + + function test_MS04b_factoryDeploysElsewhere_agwMismatch() public { + uint256 id = _registerLending(); + OpenJobParams memory p = _ready(id); + factory.setMisdeploy(true); + bytes32 salt = keccak256(abi.encode(keccak256(abi.encode(user, uint96(0))))); + address elsewhere = vm.computeCreate2Address( + salt, keccak256(abi.encodePacked(type(MockAGW).creationCode, abi.encode(user))), address(factory) + ); + _expectOpen( + p, abi.encodeWithSelector(UniversalMarketplaceErrors.AGWMismatch.selector, p.intent.wallet, elsewhere) + ); + } + + function test_MS05_cardInactive_unknown() public { + uint256 id = _registerLending(); + OpenJobParams memory p = _ready(id); + + vm.prank(provider); + mkt.setAgentCardActive(id, false); + _expectOpen(p, abi.encodeWithSelector(UniversalMarketplaceErrors.AgentCardInactive.selector)); + vm.prank(provider); + mkt.setAgentCardActive(id, true); + + p.cardId = 999; + _expectOpen(p, abi.encodeWithSelector(UniversalMarketplaceErrors.AgentCardInactive.selector)); + p.cardId = id; + _open(p); + } + + function test_MS06_cardVersionMismatch() public { + uint256 id = _registerLending(); + OpenJobParams memory p = _ready(id); + p.cardVersion = 2; + _expectOpen(p, abi.encodeWithSelector(UniversalMarketplaceErrors.AgentCardVersionMismatch.selector, 2, 1)); + p.cardVersion = 0; + _expectOpen(p, abi.encodeWithSelector(UniversalMarketplaceErrors.AgentCardVersionMismatch.selector, 0, 1)); + } + + function test_MS07_principalOutOfRange() public { + uint256 id = _registerLending(); + uint256[2] memory bad = [uint256(100e6 - 1), 1_000e6 + 1]; + for (uint256 i; i < 2; ++i) { + OpenJobParams memory p = _readyAt(id, uint96(factory.walletCount(user)), _rules(), _inputs(bad[i])); + _expectOpen(p, abi.encodeWithSelector(UniversalMarketplaceErrors.PrincipalOutOfRange.selector)); + } + _open(_readyAt(id, 0, _rules(), _inputs(100e6))); + _open(_readyAt(id, 1, _rules(), _inputs(1_000e6))); + } + + function _withTimes(uint256 expiredAt, uint256 executeBy) internal view returns (JobInputs memory j) { + j = _inputs(PRINCIPAL); + // forge-lint: disable-next-line(unsafe-typecast) + j.expiredAt = uint48(expiredAt); // a timestamp within 31 days of now + // forge-lint: disable-next-line(unsafe-typecast) + j.executeBy = uint48(executeBy); // a timestamp within 31 days of now + } + + function test_MS08_expiryOutOfRange() public { + uint256 id = _registerLending(); + uint256 t = block.timestamp; + JobInputs memory tooSoon = _withTimes(t + 3 hours - 1, t + 10 minutes); + JobInputs memory tooLate = _withTimes(t + 30 days + 1, t + 10 minutes); + _expectOpen( + _readyAt(id, 0, _rules(), tooSoon), + abi.encodeWithSelector(UniversalMarketplaceErrors.ExpiryOutOfRange.selector) + ); + _expectOpen( + _readyAt(id, 0, _rules(), tooLate), + abi.encodeWithSelector(UniversalMarketplaceErrors.ExpiryOutOfRange.selector) + ); + _open(_readyAt(id, 0, _rules(), _withTimes(t + 3 hours, t + 10 minutes))); + _open(_readyAt(id, 1, _rules(), _withTimes(t + 30 days, t + 10 minutes))); + } + + function test_MS09_executeByOutOfRange() public { + uint256 id = _registerLending(); + uint256 t = block.timestamp; + uint256 expiry = t + 7 days; + _expectOpen( + _readyAt(id, 0, _rules(), _withTimes(expiry, t + 10 minutes - 1)), + abi.encodeWithSelector(UniversalMarketplaceErrors.ExecuteByOutOfRange.selector) + ); + _expectOpen( + _readyAt(id, 0, _rules(), _withTimes(expiry, expiry - 2 hours + 1)), + abi.encodeWithSelector(UniversalMarketplaceErrors.ExecuteByOutOfRange.selector) + ); + _open(_readyAt(id, 0, _rules(), _withTimes(expiry, t + 10 minutes))); + _open(_readyAt(id, 1, _rules(), _withTimes(expiry, expiry - 2 hours))); + } + + function test_MS10_params() public { + uint256 id = _registerSwap(); + + OpenJobParams memory p = _readyAt(id, 0, _rules(), _swapInputs(0.5e18)); + p.job.params = new int256[](0); + _expectOpen(p, abi.encodeWithSelector(UniversalMarketplaceErrors.ParamCountMismatch.selector, 1, 0)); + p = _readyAt(id, 0, _rules(), _swapInputs(0.5e18)); + p.job.params = new int256[](2); + _expectOpen(p, abi.encodeWithSelector(UniversalMarketplaceErrors.ParamCountMismatch.selector, 1, 2)); + + p = _readyAt(id, 0, _rules(), _swapInputs(0.5e18)); + p.job.params[0] = 0; + _expectOpen(p, abi.encodeWithSelector(UniversalMarketplaceErrors.ParamOutOfRange.selector, 0, int256(0))); + p = _readyAt(id, 0, _rules(), _swapInputs(0.5e18)); + p.job.params[0] = 1e30 + 1; + _expectOpen( + p, abi.encodeWithSelector(UniversalMarketplaceErrors.ParamOutOfRange.selector, 0, int256(1e30 + 1)) + ); + + (uint256 jobA,) = _open(_readyAt(id, 0, _rules(), _swapInputs(1))); + (uint256 jobB,) = _open(_readyAt(id, 1, _rules(), _swapInputs(1e30))); + assertEq(abi.decode(bytes(kernel.getJob(jobA).description), (JobSpec)).checks[0].target, 1); + assertEq(abi.decode(bytes(kernel.getJob(jobB).description), (JobSpec)).checks[0].target, 1e30); + } + + function test_MS11_intentWalletAndExecutor() public { + uint256 id = _registerLending(); + OpenJobParams memory p = _ready(id); + address agw = p.intent.wallet; + p.intent.wallet = stranger; + _expectOpen(p, abi.encodeWithSelector(UniversalMarketplaceErrors.IntentWalletMismatch.selector, agw, stranger)); + p = _ready(id); + p.intent.executor = stranger; + _expectOpen( + p, abi.encodeWithSelector(UniversalMarketplaceErrors.ExecutorMismatch.selector, stranger, address(mkt)) + ); + } + + function _expectExecMismatch(OpenJobParams memory p, uint96 index) internal { + _expectOpen( + p, + abi.encodeWithSelector( + UniversalMarketplaceErrors.IntentExecMismatch.selector, _calldataHash(p.cardId, index, p.job) + ) + ); + } + + function test_MS12_intentExecMismatch_everyBoundInput() public { + uint256 id = _registerSwap(); + JobInputs memory job = _swapInputs(0.5e18); + + OpenJobParams memory p = _readyAt(id, 0, _rules(), job); + p.job.principal = PRINCIPAL + 1; + _expectExecMismatch(p, 0); + + p = _readyAt(id, 0, _rules(), _swapInputs(0.5e18)); + p.job.executeBy += 1; + _expectExecMismatch(p, 0); + + p = _readyAt(id, 0, _rules(), _swapInputs(0.5e18)); + p.job.expiredAt += 1; + _expectExecMismatch(p, 0); + + p = _readyAt(id, 0, _rules(), _swapInputs(0.5e18)); + p.job.params[0] += 1; + _expectExecMismatch(p, 0); + + // another wallet of the same owner: its CEA is in the criteria + p = _readyAt(id, 0, _rules(), _swapInputs(0.5e18)); + p.intent.index = 1; + (p.intent.wallet,) = factory.predictWallet(user, 1); + _expectExecMismatch(p, 1); + + p = _readyAt(id, 0, _rules(), _swapInputs(0.5e18)); + p.intent.mode = bytes32(uint256(1)); + _expectExecMismatch(p, 0); + + p = _readyAt(id, 0, _rules(), _swapInputs(0.5e18)); + p.intent.nonceKey = 0; + _expectExecMismatch(p, 0); + + p = _readyAt(id, 0, _rules(), _swapInputs(0.5e18)); + p.intent.execCalldataHash = keccak256("another call"); + _expectExecMismatch(p, 0); + } + + function test_MS13_intentSessionMismatch_noStateOnFailure() public { + uint256 id = _registerLending(); + OpenJobParams memory p = _ready(id); + p.session.salt = bytes32(uint256(1)); + uint256 jobsBefore = kernel.jobCounter(); + _expectOpen( + p, + abi.encodeWithSelector( + UniversalMarketplaceErrors.IntentSessionMismatch.selector, keccak256(abi.encode(p.session)) + ) + ); + assertEq(factory.walletCount(user), 0, "no wallet"); + assertEq(kernel.jobCounter(), jobsBefore, "no job"); + assertEq(mkt.activeJobOf(p.intent.wallet), 0); + } + + function _expectActive(uint256 id, address agw, uint256 jobId) internal { + assertEq(mkt.activeJobOf(agw), jobId); + _expectOpen( + _readyAt(id, 0, _rules(), _inputs(PRINCIPAL)), + abi.encodeWithSelector(UniversalMarketplaceErrors.WalletHasActiveJob.selector, agw, jobId) + ); + } + + function test_MS14_oneLiveJob() public { + uint256 id = _registerLending(); + + // Open → active; expired Open → free + (uint256 job1, address agw) = _open(_ready(id)); + _expectActive(id, agw, job1); + vm.warp(kernel.getJob(job1).expiredAt); + assertEq(mkt.activeJobOf(agw), 0, "free after an expired Open job"); + + // Open → Rejected → free + (uint256 job2,) = _open(_readyAt(id, 0, _rules(), _inputs(PRINCIPAL))); + vm.prank(provider); + kernel.reject(job2, bytes32(0), ""); + assertEq(mkt.activeJobOf(agw), 0, "free after Rejected"); + + // Funded → active; Submitted → active; Completed → free + (uint256 job3,) = _open(_readyAt(id, 0, _rules(), _inputs(PRINCIPAL))); + _budgetAndFund(job3, agw, FEE); + assertEq(uint8(_status(job3)), uint8(IAgenticCommerce.JobStatus.Funded)); + _expectActive(id, agw, job3); + vm.prank(provider); + kernel.submit(job3, keccak256("deliverable"), ""); + _expectActive(id, agw, job3); + vm.prank(universalEvaluator); + kernel.complete(job3, bytes32(0), ""); + assertEq(mkt.activeJobOf(agw), 0, "free after Completed"); + _open(_readyAt(id, 0, _rules(), _inputs(PRINCIPAL))); + } + + function test_MS15_jobVerification() public { + uint256 id = _registerLending(); + OpenJobParams memory p = _ready(id); + vm.prank(user); + factory.deployWalletWithSig(p.intent, "", ""); + MockAGW(payable(p.intent.wallet)).setMode(MockAGW.Mode.TwoJobs); + uint256 n = kernel.jobCounter(); + _expectOpen(p, abi.encodeWithSelector(UniversalMarketplaceErrors.UnexpectedJobCount.selector, n, n + 2)); + + MockAGW(payable(p.intent.wallet)).setMode(MockAGW.Mode.ForeignClient); + _expectOpen(p, abi.encodeWithSelector(UniversalMarketplaceErrors.JobMismatch.selector)); + + MockAGW(payable(p.intent.wallet)).setMode(MockAGW.Mode.OtherEvaluator); + _expectOpen(p, abi.encodeWithSelector(UniversalMarketplaceErrors.JobMismatch.selector)); + } + + function test_MS16_providerIsEvaluator_afterSetEvaluator() public { + uint256 id = _registerLending(); + OpenJobParams memory p = _ready(id); + vm.prank(admin); + mkt.setEvaluator(provider); + _expectOpen(p, abi.encodeWithSelector(UniversalMarketplaceErrors.ProviderIsEvaluator.selector)); + } + + function test_MS17_8183Continuation_feeEnforcedAtFund() public { + uint256 id = _registerLending(); + (uint256 jobId, address agw) = _open(_ready(id)); + uint256 fee = mkt.getAgentCard(id).card.providerFee; + + // a provider who prices above the card cannot be funded: the owner's expectedBudget is the card fee + vm.prank(provider); + kernel.setBudget(jobId, fee + 1, ""); + engine.setPermission(MockAGW(payable(agw)).RULES_ID(), agw, true); + token.mint(agw, fee + 1); + bytes memory optParams = abi.encode(mkt.rulesOfJob(jobId)); + vm.startPrank(agw); + token.approve(address(kernel), fee + 1); + vm.expectRevert(IAgenticCommerce.BudgetMismatch.selector); + kernel.fund(jobId, fee, optParams); + vm.stopPrank(); + + uint256 escrowBefore = kernel.totalEscrowed(); + _budgetAndFund(jobId, agw, fee); + assertEq(uint8(_status(jobId)), uint8(IAgenticCommerce.JobStatus.Funded)); + assertEq(kernel.totalEscrowed() - escrowBefore, fee, "the kernel escrows the card fee"); + assertEq(kernel.getJob(jobId).budget, fee); + } + + /// @dev Ceilings = measured + 5%, rounded up to 10k (PRD 12 §6.5). Measured 2026-10-16 with the mock wallet + /// and factory, two-asset card: registerAgentCard 2,564,983 · openJob fresh 4,231,625 · openJob existing + /// 1,797,405. MockAGW now stores the granted initData (`lastPolicyInitData`), which is part of both + /// openJob figures. + uint256 internal constant REGISTER_GAS_CEILING = 2_700_000; + uint256 internal constant OPEN_FRESH_GAS_CEILING = 4_450_000; + uint256 internal constant OPEN_EXISTING_GAS_CEILING = 1_890_000; + + function test_MS18_gasCeilings() public { + AgentCard memory c = _card(); + bytes memory r = abi.encode(_rulesTwoAssets()); + bytes memory e = abi.encode(_lendingTemplate()); + vm.prank(provider); + uint256 g = gasleft(); + uint256 id = mkt.registerAgentCard(c, r, e); + uint256 used = g - gasleft(); + emit log_named_uint("registerAgentCard (two-asset lending card)", used); + assertLe(used, REGISTER_GAS_CEILING, "registerAgentCard (two-asset lending card)"); + + OpenJobParams memory p = _readyAt(id, 0, _rulesTwoAssets(), _inputs(PRINCIPAL)); + vm.prank(relayer); + g = gasleft(); + (uint256 jobId,,) = mkt.openJob(p); + used = g - gasleft(); + emit log_named_uint("openJob (fresh wallet)", used); + assertLe(used, OPEN_FRESH_GAS_CEILING, "openJob (fresh wallet)"); + + vm.prank(provider); + kernel.reject(jobId, bytes32(0), ""); + p = _readyAt(id, 0, _rulesTwoAssets(), _inputs(PRINCIPAL)); + vm.prank(relayer); + g = gasleft(); + mkt.openJob(p); + used = g - gasleft(); + emit log_named_uint("openJob (existing wallet)", used); + assertLe(used, OPEN_EXISTING_GAS_CEILING, "openJob (existing wallet)"); + } + + function test_MS19_openJob_twoAssets_principalMarkers() public { + uint256 id = _register(_card(), _rulesTwoAssets(), _lendingTemplate()); + OpenJobParams memory p = _readyAt(id, 0, _rulesTwoAssets(), _inputs(PRINCIPAL)); + address agw = p.intent.wallet; + uint256 expectedJobId = kernel.jobCounter() + 1; + + vm.expectEmit(address(mkt)); + emit IUniversalMarketplace.JobOpened(id, user, agw, expectedJobId, keccak256("mock-rules"), PRINCIPAL, 1); + (uint256 jobId,) = _open(p); + + assertEq(MockAGW(payable(agw)).lastSessionHash(), keccak256(abi.encode(p.session))); + assertEq(mkt.cardVersionOfJob(jobId), 1); + UniversalTerms memory t = _granted(agw); + assertEq(t.assets.length, 2); + assertEq(t.assets[0].token, address(pUSDC)); + assertEq(t.assets[0].maxPerCall, PRINCIPAL, "principal per-call: marker filled"); + assertEq(t.assets[0].maxTotal, PRINCIPAL, "principal total: marker filled"); + assertEq(t.assets[1].token, address(pETH)); + assertEq(t.assets[1].maxPerCall, 0); + assertEq(t.assets[1].maxTotal, 0); + assertEq(t.allowedCalls[0].pins[1].value, bytes32(PRINCIPAL), "approve amount pin filled"); + assertEq(t.allowedCalls[1].pins[0].value, _word(mkt.computeCEA(agw, SEPOLIA_HASH)), "wallet pin filled"); + assertEq(t.expectedCEA, mkt.computeCEA(agw, SEPOLIA_HASH)); + } + + function test_MS20_openJob_trancheCard() public { + AgentCardRules memory r = _rules(); + r.assets[0].maxPerCall = 100e6; + uint256 id = _register(_card(), r, _lendingTemplate()); + JobInputs memory job = _inputs(PRINCIPAL); + (address agw,) = factory.predictWallet(user, 0); + + UniversalTerms memory t = _termsFor(r, agw, job); + assertEq(t.assets[0].maxPerCall, 100e6, "an SDK copies a fixed per-call cap"); + t.assets[0].maxPerCall = PRINCIPAL; + _expectOpen( + _params(id, 0, job, _sessionOf(t)), + abi.encodeWithSelector(UniversalMarketplaceErrors.PrincipalCapMismatch.selector) + ); + + (, address opened) = _open(_readyAt(id, 0, r, job)); + assertEq(_granted(opened).assets[0].maxPerCall, 100e6); + assertEq(_granted(opened).assets[0].maxTotal, PRINCIPAL); + } + + function test_MS21_activeJobOf() public { + uint256 id = _registerLending(); + OpenJobParams memory p = _ready(id); + address agw = p.intent.wallet; + assertEq(mkt.activeJobOf(agw), 0, "before"); + + (uint256 job1,) = _open(p); + assertEq(mkt.activeJobOf(agw), job1, "Open"); + _expectOpen( + _readyAt(id, 0, _rules(), _inputs(PRINCIPAL)), + abi.encodeWithSelector(UniversalMarketplaceErrors.WalletHasActiveJob.selector, agw, job1) + ); + vm.warp(kernel.getJob(job1).expiredAt - 1); + assertEq(mkt.activeJobOf(agw), job1, "Open, one second before expiry"); + vm.warp(kernel.getJob(job1).expiredAt); + assertEq(mkt.activeJobOf(agw), 0, "Open, expired"); + + (uint256 job2,) = _open(_readyAt(id, 0, _rules(), _inputs(PRINCIPAL))); + _budgetAndFund(job2, agw, FEE); + assertEq(mkt.activeJobOf(agw), job2, "Funded"); + vm.prank(provider); + kernel.submit(job2, keccak256("deliverable"), ""); + vm.prank(universalEvaluator); + kernel.complete(job2, bytes32(0), ""); + assertEq(mkt.activeJobOf(agw), 0, "Completed"); + + (uint256 job3,) = _open(_readyAt(id, 0, _rules(), _inputs(PRINCIPAL))); + vm.prank(provider); + kernel.reject(job3, bytes32(0), ""); + assertEq(mkt.activeJobOf(agw), 0, "Rejected"); + assertEq(mkt.activeJobOf(makeAddr("neverSeen")), 0); + } + + function test_MS22_envelopeVersion_named() public { + uint256 id = _registerLending(); + JobInputs memory job = _inputs(PRINCIPAL); + (address agw,) = factory.predictWallet(user, 0); + bytes memory preV6 = abi.encode(SEPOLIA, abi.encode(_termsFor(_rules(), agw, job))); // (string, bytes) + Session memory s = _wrapSession(preV6, provider, _skeleton()); + _expectOpen( + _params(id, 0, job, s), abi.encodeWithSelector(UniversalMarketplaceErrors.EnvelopeVersionMismatch.selector, 64) + ); + assertEq(factory.walletCount(user), 0, "nothing deployed"); + } + + // ═════════════════════════════ MB · rules = card, through the marketplace ═════════════════════════════ + + function _sessionCase(function(Session memory) internal view mutate, bytes memory err) internal { + uint256 id = _lendingId(); + JobInputs memory job = _inputs(PRINCIPAL); + (address agw,) = factory.predictWallet(user, 0); + Session memory s = _sessionFor(_rules(), agw, job); + mutate(s); + _expectOpen(_params(id, 0, job, s), err); + } + + function _termsCase(function(UniversalTerms memory) internal view mutate, bytes memory err) internal { + uint256 id = _lendingId(); + JobInputs memory job = _inputs(PRINCIPAL); + (address agw,) = factory.predictWallet(user, 0); + UniversalTerms memory t = _termsFor(_rules(), agw, job); + mutate(t); + _expectOpen(_params(id, 0, job, _sessionOf(t)), err); + } + + function _otherAgent(Session memory s) internal view { + s.sessionValidatorInitData = abi.encode(stranger); + } + + function _wideInitData(Session memory s) internal view { + s.sessionValidatorInitData = abi.encode(provider, provider); + } + + function _noActions(Session memory s) internal pure { + s.actions = new ActionData[](0); + } + + function _twoActions(Session memory s) internal pure { + ActionData[] memory a = new ActionData[](2); + a[0] = s.actions[0]; + a[1] = s.actions[0]; + s.actions = a; + } + + function _twoPolicies(Session memory s) internal pure { + PolicyData[] memory p = new PolicyData[](2); + p[0] = s.actions[0].actionPolicies[0]; + p[1] = s.actions[0].actionPolicies[0]; + s.actions[0].actionPolicies = p; + } + + function _otherChain(Session memory s) internal pure { + (uint16 v,, bytes memory body) = abi.decode(s.actions[0].actionPolicies[0].initData, (uint16, string, bytes)); + s.actions[0].actionPolicies[0].initData = abi.encode(v, "eip155:1", body); + } + + function test_MB01_agentMismatch() public { + _sessionCase(_otherAgent, abi.encodeWithSelector(UniversalMarketplaceErrors.AgentMismatch.selector)); + _sessionCase(_wideInitData, abi.encodeWithSelector(UniversalMarketplaceErrors.AgentMismatch.selector)); + } + + function test_MB02_shape() public { + _sessionCase(_noActions, abi.encodeWithSelector(UniversalMarketplaceErrors.ActionCount.selector)); + _sessionCase(_twoActions, abi.encodeWithSelector(UniversalMarketplaceErrors.ActionCount.selector)); + _sessionCase(_twoPolicies, abi.encodeWithSelector(UniversalMarketplaceErrors.PolicyShape.selector, 0)); + _sessionCase(_otherChain, abi.encodeWithSelector(UniversalMarketplaceErrors.ChainMismatch.selector, 0)); + } + + function _otherAsset(UniversalTerms memory t) internal view { + t.assets[0].token = address(pETH); + } + + function _gasCapUp(UniversalTerms memory t) internal pure { + t.maxGasPerCall += 1; + } + + function _extraCall(UniversalTerms memory t) internal view { + t.allowedCalls = _appendCall(t.allowedCalls, _allowed(pool, WITHDRAW, 68, true, new ArgPin[](0))); + } + + function _missingCall(UniversalTerms memory t) internal pure { + t.allowedCalls = new AllowedCall[](0); + } + + function _valueChanged(UniversalTerms memory t) internal pure { + t.allowedCalls[0].maxValue = 1; + } + + function _totalNotPrincipal(UniversalTerms memory t) internal pure { + t.assets[0].maxTotal -= 1; + } + + function _perCallOverPrincipal(UniversalTerms memory t) internal pure { + t.assets[0].maxPerCall += 1; + } + + function _validUntilMoved(UniversalTerms memory t) internal pure { + t.validUntil += 1; + } + + function _attackerCEA(UniversalTerms memory t) internal pure { + t.expectedCEA = address(0xBAD); + } + + function test_MB03_terms() public { + _termsCase(_otherAsset, abi.encodeWithSelector(UniversalMarketplaceErrors.AssetMismatch.selector, 0)); + _termsCase(_gasCapUp, abi.encodeWithSelector(UniversalMarketplaceErrors.GasCapMismatch.selector)); + _termsCase(_extraCall, abi.encodeWithSelector(UniversalMarketplaceErrors.ActionsMismatch.selector)); + _termsCase(_missingCall, abi.encodeWithSelector(UniversalMarketplaceErrors.ActionsMismatch.selector)); + _termsCase(_valueChanged, abi.encodeWithSelector(UniversalMarketplaceErrors.ActionsMismatch.selector)); + _termsCase( + _totalNotPrincipal, abi.encodeWithSelector(UniversalMarketplaceErrors.PrincipalCapMismatch.selector) + ); + _termsCase( + _perCallOverPrincipal, abi.encodeWithSelector(UniversalMarketplaceErrors.PrincipalCapMismatch.selector) + ); + _termsCase(_validUntilMoved, abi.encodeWithSelector(UniversalMarketplaceErrors.ExpiryMismatch.selector)); + (address agw,) = factory.predictWallet(user, 0); + _termsCase( + _attackerCEA, + abi.encodeWithSelector( + UniversalMarketplaceErrors.ExpectedCEAMismatch.selector, ceaFactory.computeCEA(agw), address(0xBAD) + ) + ); + + // reordered: a four-call card, the session lists two calls the other way round + (, AgentCardRules memory four,) = _updated(); + uint256 id = _lendingId(); + _update(id, _card(), four, _lendingTemplate()); + JobInputs memory job = _inputs(PRINCIPAL); + UniversalTerms memory t = _termsFor(four, agw, job); + (t.allowedCalls[1], t.allowedCalls[3]) = (t.allowedCalls[3], t.allowedCalls[1]); + _expectOpen( + _params(id, 0, job, _sessionOf(t)), + abi.encodeWithSelector(UniversalMarketplaceErrors.ActionsMismatch.selector) + ); + } + + /// @dev D3 flips the old "per-call below principal passes": the card's per-call cap is `MARKER_PRINCIPAL`, so + /// the session's must EQUAL the principal. + function test_MB04_perCallMustEqualPrincipal() public { + uint256 id = _registerLending(); + JobInputs memory job = _inputs(PRINCIPAL); + (address agw,) = factory.predictWallet(user, 0); + UniversalTerms memory t = _termsFor(_rules(), agw, job); + t.assets[0].maxPerCall = PRINCIPAL / 4; + _expectOpen( + _params(id, 0, job, _sessionOf(t)), + abi.encodeWithSelector(UniversalMarketplaceErrors.PrincipalCapMismatch.selector) + ); + t.assets[0].maxPerCall = PRINCIPAL; + _open(_params(id, 0, job, _sessionOf(t))); + } + + // ═════════════════════════════ MV · views, admin, upgrade ═════════════════════════════ + + function test_MV01_getAgentCard_fullView() public { + uint256 id = _registerLending(); + vm.prank(admin); + mkt.verifyAgentCard(id, 1); + AgentCardView memory v = mkt.getAgentCard(id); + AgentCard memory expected = _card(); + expected.provider = provider; + expected.active = true; + assertEq(abi.encode(v.card), abi.encode(expected), "card"); + assertEq(v.rules, abi.encode(_rules())); + assertEq(v.jobSpecTemplate, abi.encode(_lendingTemplate())); + assertEq(v.version, 1); + assertTrue(v.verified); + assertFalse(v.disabled); + + AgentCardView memory none = mkt.getAgentCard(999); + AgentCardView memory zero; + assertEq(abi.encode(none), abi.encode(zero), "an unknown card reads all zero"); + } + + function test_MV02_computeCEA() public { + address agw = makeAddr("anyAGW"); + assertEq(mkt.computeCEA(agw, SEPOLIA_HASH), ceaFactory.computeCEA(agw)); + (address cea,) = ceaFactory.getCEAForPushAccount(agw); + assertEq(mkt.computeCEA(agw, SEPOLIA_HASH), cea); + vm.expectRevert( + abi.encodeWithSelector(UniversalMarketplaceErrors.ChainNotSupported.selector, bytes32(uint256(1))) + ); + mkt.computeCEA(agw, bytes32(uint256(1))); + } + + /// @dev After a destination implementation rotation, the stale config is refused until updated; the runbook is + /// `pause()` → rotate → `setCEADeployment` → `unpause()`. + function test_MV03_ceaRotation_staleCaught() public { + uint256 id = _registerLending(); + OpenJobParams memory signedBefore = _ready(id); + address newImpl = makeAddr("ceaProxyImplV2"); + vm.prank(admin); + ceaFactory.setCEAProxyImplementation(newImpl); + + // not paused: an SDK reading the destination factory signs the NEW CEA, into the wallet pin and the + // expected CEA; the marketplace still derives the old one, and the pin (C12) is the first to differ + JobInputs memory job = _inputs(PRINCIPAL); + address agw = signedBefore.intent.wallet; + Session memory s = _sessionOf(_fillTerms(_rules(), PRINCIPAL, job.expiredAt, ceaFactory.computeCEA(agw))); + assertTrue(ceaFactory.computeCEA(agw) != mkt.computeCEA(agw, SEPOLIA_HASH), "stale"); + _expectOpen(_params(id, 0, job, s), abi.encodeWithSelector(UniversalMarketplaceErrors.PinMismatch.selector, 1, 0)); + + // the runbook + vm.prank(admin); + mkt.pause(); + _expectOpen(signedBefore, abi.encodeWithSelector(PausableUpgradeable.EnforcedPause.selector)); + vm.prank(admin); + mkt.setCEADeployment(SEPOLIA_HASH, address(ceaFactory), newImpl); + vm.prank(admin); + mkt.unpause(); + assertEq(mkt.computeCEA(agw, SEPOLIA_HASH), ceaFactory.computeCEA(agw), "fresh"); + // an intent signed before the rotation names the old CEA in its criteria: refused + _expectOpen( + signedBefore, + abi.encodeWithSelector(UniversalMarketplaceErrors.IntentExecMismatch.selector, _calldataHash(id, 0, job)) + ); + _open(_ready(id)); // re-signed: the criteria's CEA moved too + } + + function test_MV04_buildCreateJobCalldata() public { + uint256 id = _registerSwap(); + JobInputs memory job = _swapInputs(0.5e18); + (bytes32 mode, bytes memory cd) = mkt.buildCreateJobCalldata(id, user, 0, job); + (address agw,) = factory.predictWallet(user, 0); + assertEq(mode, bytes32(0)); + bytes memory call = abi.encodeCall( + IAgenticCommerce.createJob, + ( + provider, + universalEvaluator, + uint256(job.expiredAt), + string(_expectedDescription(_swapTemplate(), id, 1, agw, job)), + address(hook) + ) + ); + assertEq(cd, abi.encodePacked(address(kernel), uint256(0), call)); + + bytes32 base = keccak256(cd); + JobInputs memory j = _swapInputs(0.5e18); + j.principal += 1; + assertTrue(_calldataHash(id, 0, j) != base, "principal"); + j = _swapInputs(0.5e18); + j.executeBy += 1; + assertTrue(_calldataHash(id, 0, j) != base, "executeBy"); + j = _swapInputs(0.5e18); + j.expiredAt += 1; + assertTrue(_calldataHash(id, 0, j) != base, "expiredAt"); + assertTrue(_calldataHash(id, 0, _swapInputs(0.5e18 + 1)) != base, "params"); + assertTrue(_calldataHash(id, 1, job) != base, "index"); + (, bytes memory otherOwner) = mkt.buildCreateJobCalldata(id, stranger, 0, job); + assertTrue(keccak256(otherOwner) != base, "owner"); + _update(id, _card(), _rules(), _swapTemplate()); + assertTrue(_calldataHash(id, 0, job) != base, "card version"); + + // what openJob executes is exactly this view's answer + OpenJobParams memory p = _readyAt(id, 0, _rules(), job); + (, address opened) = _open(p); + assertEq(MockAGW(payable(opened)).lastExecCalldataHash(), _calldataHash(id, 0, job)); + + vm.expectRevert(UniversalMarketplaceErrors.AgentCardInactive.selector); + mkt.buildCreateJobCalldata(999, user, 0, job); + } + + function test_MV05_previewIntent_roundTrips() public { + uint256 id = _registerLending(); + OpenJobParams memory p = _ready(id); + OwnerIntent memory i = p.intent; + (address agw,) = factory.predictWallet(user, 0); + assertEq(i.owner, user); + assertEq(i.wallet, agw); + assertEq(i.executor, address(mkt)); + assertEq(i.index, 0); + assertEq(i.sessionHash, keccak256(abi.encode(p.session))); + assertEq(i.mode, bytes32(0)); + assertEq(i.execCalldataHash, _calldataHash(id, 0, p.job)); + assertEq(i.nonceKey, OWNER_LANE_FLAG); + assertEq(i.nonceSeq, 0, "fresh wallet"); + assertEq(i.grantNonce, 0, "fresh wallet"); + assertEq(i.deadline, uint48(block.timestamp + 1 hours)); + assertEq(i.signerChainId, 1); + (uint256 jobId,) = _open(p); + + vm.prank(provider); + kernel.reject(jobId, bytes32(0), ""); + OwnerIntent memory again = _readyAt(id, 0, _rules(), _inputs(PRINCIPAL)).intent; + assertEq(again.nonceSeq, 1, "deployed: the live lane"); + assertEq(again.grantNonce, 1, "deployed: the live grant nonce"); + + _expectPreviewUnknownCard(); + } + + function _expectPreviewUnknownCard() internal { + Session memory s; + IntentRequest memory r = + IntentRequest({cardId: 999, owner: user, index: 0, job: _inputs(PRINCIPAL), deadline: 0, signerChainId: 1}); + vm.expectRevert(UniversalMarketplaceErrors.AgentCardInactive.selector); + mkt.previewIntent(r, s); + } + + function test_MV06_adminSetters() public { + vm.prank(stranger); + vm.expectRevert(_adminRevert(stranger)); + mkt.setHook(address(hook)); + vm.prank(admin); + vm.expectRevert(UniversalMarketplaceErrors.ZeroAddress.selector); + mkt.setHook(address(0)); + vm.prank(admin); + vm.expectRevert(UniversalMarketplaceErrors.HookNotWhitelisted.selector); + mkt.setHook(stranger); + vm.expectEmit(address(mkt)); + emit IUniversalMarketplace.HookUpdated(address(hook)); + vm.prank(admin); + mkt.setHook(address(hook)); + + vm.prank(stranger); + vm.expectRevert(_adminRevert(stranger)); + mkt.setEvaluator(stranger); + vm.prank(admin); + vm.expectRevert(UniversalMarketplaceErrors.ZeroAddress.selector); + mkt.setEvaluator(address(0)); + address next = makeAddr("evaluatorV2"); + vm.expectEmit(address(mkt)); + emit IUniversalMarketplace.EvaluatorUpdated(next); + vm.prank(admin); + mkt.setEvaluator(next); + assertEq(mkt.evaluator(), next); + + vm.prank(stranger); + vm.expectRevert(_adminRevert(stranger)); + mkt.setCEADeployment(SEPOLIA_HASH, address(ceaFactory), ceaProxyImpl); + vm.startPrank(admin); + vm.expectRevert(UniversalMarketplaceErrors.ZeroAddress.selector); + mkt.setCEADeployment(SEPOLIA_HASH, address(0), ceaProxyImpl); + vm.expectRevert(UniversalMarketplaceErrors.ZeroAddress.selector); + mkt.setCEADeployment(SEPOLIA_HASH, address(ceaFactory), address(0)); + vm.expectEmit(address(mkt)); + emit IUniversalMarketplace.CEADeploymentSet(SEPOLIA_HASH, address(ceaFactory), ceaProxyImpl); + mkt.setCEADeployment(SEPOLIA_HASH, address(ceaFactory), ceaProxyImpl); + vm.stopPrank(); + (address f, address impl) = mkt.ceaDeployment(SEPOLIA_HASH); + assertEq(f, address(ceaFactory)); + assertEq(impl, ceaProxyImpl); + } + + function test_MV07_pause() public { + uint256 id = _registerLending(); + OpenJobParams memory p = _ready(id); + vm.prank(stranger); + vm.expectRevert(_adminRevert(stranger)); + mkt.pause(); + vm.prank(admin); + mkt.pause(); + + _expectOpen(p, abi.encodeWithSelector(PausableUpgradeable.EnforcedPause.selector)); + AgentCard memory c = _card(); + bytes memory r = abi.encode(_rules()); + bytes memory e = abi.encode(_lendingTemplate()); + vm.prank(provider2); + vm.expectRevert(PausableUpgradeable.EnforcedPause.selector); + mkt.registerAgentCard(c, r, e); + vm.prank(provider); + vm.expectRevert(PausableUpgradeable.EnforcedPause.selector); + mkt.updateAgentCard(id, c, r, e); + + vm.prank(stranger); + vm.expectRevert(_adminRevert(stranger)); + mkt.unpause(); + vm.prank(admin); + mkt.unpause(); + _open(p); + } + + function _expectInitRevert(InitParams memory ip, bytes4 err) internal { + address impl = address(new UniversalMarketplace()); + vm.expectRevert(err); + new TransparentUpgradeableProxy(impl, mktAdmin, abi.encodeCall(UniversalMarketplace.initialize, (ip))); + } + + function test_MV08_initialize() public { + bytes4 zero = UniversalMarketplaceErrors.ZeroAddress.selector; + InitParams memory ip = _initParams(); + ip.agwFactory = address(0); + _expectInitRevert(ip, zero); + ip = _initParams(); + ip.kernel = address(0); + _expectInitRevert(ip, zero); + ip = _initParams(); + ip.hook = address(0); + _expectInitRevert(ip, zero); + ip = _initParams(); + ip.evaluator = address(0); + _expectInitRevert(ip, zero); + ip = _initParams(); + ip.rules = address(0); + _expectInitRevert(ip, zero); + ip = _initParams(); + ip.admin = address(0); + _expectInitRevert(ip, zero); + ip = _initParams(); + ip.hook = stranger; + _expectInitRevert(ip, UniversalMarketplaceErrors.HookNotWhitelisted.selector); + + vm.expectRevert(Initializable.InvalidInitialization.selector); + mkt.initialize(_initParams()); + UniversalMarketplace impl = new UniversalMarketplace(); + vm.expectRevert(Initializable.InvalidInitialization.selector); + impl.initialize(_initParams()); + + assertEq(address(mkt.AGW_FACTORY()), address(factory)); + assertEq(address(mkt.KERNEL()), address(kernel)); + assertEq(mkt.hook(), address(hook)); + assertEq(mkt.evaluator(), universalEvaluator); + assertEq(address(mkt.RULES()), address(rulesHelper)); + assertTrue(mkt.hasRole(mkt.ADMIN_ROLE(), admin)); + assertTrue(mkt.hasRole(mkt.DEFAULT_ADMIN_ROLE(), admin)); + } + + /// ⚠️ NEVER-DELETE. Every slot of the layout (PRD 12 Appendix C) is pinned by position after an exercise that + /// writes every variable, so an insertion, reorder or forgotten gap decrement fails here instead of on the + /// first upgrade. Append-only: extend this test, never loosen it. + function test_MV09_storageLayout_bySlot() public { + uint256 id = _registerLending(); + uint256 id2 = _registerAs(provider2, _card(), _rules(), _lendingTemplate()); + (uint256 jobId, address agw) = _open(_ready(id)); + _update(id, _card(), _rules(), _lendingTemplate()); // version 2 + vm.startPrank(admin); + mkt.verifyAgentCard(id, 2); + mkt.disableAgentCard(id2); + mkt.setAgentRating(provider, 77); + mkt.pause(); // the old per-chain pause's slot stays unwritten by every path + mkt.unpause(); + vm.stopPrank(); + + address m = address(mkt); + assertEq(_word(m, 0), uint256(uint160(address(factory))), "0 AGW_FACTORY"); + assertEq(_word(m, 1), uint256(uint160(address(kernel))), "1 KERNEL"); + assertEq(_word(m, 2), uint256(uint160(address(hook))), "2 hook"); + assertEq(_word(m, 3), uint256(uint160(universalEvaluator)), "3 evaluator"); + assertEq(vm.load(m, bytes32(uint256(4))), mkt.PUSH_CHAIN_HASH(), "4 PUSH_CHAIN_HASH"); + assertEq(_word(m, 5), uint256(uint160(address(rulesHelper))), "5 RULES"); + assertEq(_word(m, 6), 2, "6 agentCardCount"); + + // mappings: the entry lives at keccak256(key ‖ slot); a long `bytes` stores 2·length + 1 + assertEq(_entry(m, id, 7), uint256(uint160(provider)), "7 _cards[id].provider"); + assertEq(_entry(m, id, 8), abi.encode(_rules()).length * 2 + 1, "8 _agentCardRules"); + assertEq(_entry(m, id, 9), abi.encode(_lendingTemplate()).length * 2 + 1, "9 _jobSpecTemplates"); + assertEq(_entry(m, id, 10), 2, "10 agentCardVersion"); + assertEq(_entry(m, id2, 10), 1, "10 agentCardVersion (not updated)"); + assertEq(_entry(m, id, 11), 1, "11 isAgentCardVerified"); + assertEq(_entry(m, id2, 12), 1, "12 isAgentCardDisabled"); + assertEq( + uint256(vm.load(m, keccak256(abi.encode(SEPOLIA_HASH, uint256(13))))), + uint256(uint160(address(ceaFactory))), + "13 ceaDeployment.ceaFactory" + ); + assertEq(_word(m, 14), 0, "14 __reserved14"); + assertEq(uint256(vm.load(m, keccak256(abi.encode(SEPOLIA_HASH, uint256(14))))), 0, "14 never a mapping"); + assertEq(_addrEntry(m, agw, 15), jobId, "15 _lastJobOf"); + assertEq(_entry(m, jobId, 16), id, "16 cardOfJob"); + assertEq(_entry(m, jobId, 17), uint256(uint160(agw)), "17 agwOfJob"); + assertEq( + vm.load(m, keccak256(abi.encode(jobId, uint256(18)))), MockAGW(payable(agw)).RULES_ID(), "18 rulesOfJob" + ); + assertEq(_addrEntry(m, provider, 19), id, "19 agentCardOf"); + assertEq(_addrEntry(m, provider2, 19), id2, "19 agentCardOf (second provider)"); + assertEq(_entry(m, jobId, 20), 1, "20 cardVersionOfJob"); + assertEq(_addrEntry(m, provider, 21), 77, "21 _agentRating"); + for (uint256 slot = 7; slot <= 21; ++slot) { + assertEq(_word(m, slot), 0, "a mapping's base slot (or slot 14) is never written"); + } + for (uint256 slot = 22; slot <= 49; ++slot) { + assertEq(_word(m, slot), 0, "gap (22-48) or slot 49 written"); + } + } + + function _word(address m, uint256 slot) internal view returns (uint256) { + return uint256(vm.load(m, bytes32(slot))); + } + + function _entry(address m, uint256 key, uint256 slot) internal view returns (uint256) { + return uint256(vm.load(m, keccak256(abi.encode(key, slot)))); + } + + function _addrEntry(address m, address key, uint256 slot) internal view returns (uint256) { + return uint256(vm.load(m, keccak256(abi.encode(key, slot)))); + } + + function test_MV10_upgrade_preservesState() public { + uint256 id = _registerLending(); + (uint256 jobId, address agw) = _open(_ready(id)); + _update(id, _card(), _rules(), _lendingTemplate()); + vm.prank(admin); + mkt.setAgentRating(provider, 5); + bytes memory viewBefore = abi.encode(mkt.getAgentCard(id)); + + UniversalMarketplace next = new UniversalMarketplace(); + vm.prank(mktAdmin); + ProxyAdmin(_proxyAdmin(address(mkt))) + .upgradeAndCall(ITransparentUpgradeableProxy(address(mkt)), address(next), ""); + assertEq(address(uint160(uint256(vm.load(address(mkt), ERC1967Utils.IMPLEMENTATION_SLOT)))), address(next)); + + assertEq(abi.encode(mkt.getAgentCard(id)), viewBefore, "card, blobs, version and tags intact"); + assertEq(mkt.agentCardCount(), 1); + assertEq(mkt.agentCardOf(provider), id); + assertEq(mkt.activeJobOf(agw), jobId); + assertEq(mkt.cardOfJob(jobId), id); + assertEq(mkt.agwOfJob(jobId), agw); + assertEq(mkt.rulesOfJob(jobId), MockAGW(payable(agw)).RULES_ID()); + assertEq(mkt.cardVersionOfJob(jobId), 1); + assertEq(mkt.getAgentRating(provider), 5); + assertEq(mkt.evaluator(), universalEvaluator); + _open(_ready(id)); // and it still opens jobs + } + + function test_MV11_setCEADeployment_clear() public { + uint256 id = _registerLending(); + OpenJobParams memory p = _ready(id); // signed before the chain is cleared + address agw = p.intent.wallet; + + vm.expectEmit(address(mkt)); + emit IUniversalMarketplace.CEADeploymentSet(SEPOLIA_HASH, address(0), address(0)); + vm.prank(admin); + mkt.setCEADeployment(SEPOLIA_HASH, address(0), address(0)); + (address f, address impl) = mkt.ceaDeployment(SEPOLIA_HASH); + assertEq(f, address(0)); + assertEq(impl, address(0)); + + bytes memory unsupported = + abi.encodeWithSelector(UniversalMarketplaceErrors.ChainNotSupported.selector, SEPOLIA_HASH); + vm.expectRevert(unsupported); + mkt.computeCEA(agw, SEPOLIA_HASH); + + AgentCard memory c = _card(); + bytes memory r = abi.encode(_rules()); + bytes memory e = abi.encode(_lendingTemplate()); + vm.prank(provider2); + vm.expectRevert(unsupported); + mkt.registerAgentCard(c, r, e); + + _expectOpen(p, unsupported); + + vm.startPrank(admin); + vm.expectRevert(UniversalMarketplaceErrors.ZeroAddress.selector); + mkt.setCEADeployment(SEPOLIA_HASH, address(ceaFactory), address(0)); + vm.expectRevert(UniversalMarketplaceErrors.ZeroAddress.selector); + mkt.setCEADeployment(SEPOLIA_HASH, address(0), ceaProxyImpl); + vm.stopPrank(); + } + + function test_MV12_agentRating() public { + assertEq(mkt.getAgentRating(provider), 0, "default"); + vm.expectEmit(address(mkt)); + emit IUniversalMarketplace.AgentRatingSet(provider, 42); + vm.prank(admin); + mkt.setAgentRating(provider, 42); + assertEq(mkt.getAgentRating(provider), 42); + assertEq(mkt.getAgentRating(provider2), 0, "per agent"); + + vm.prank(stranger); + vm.expectRevert(_adminRevert(stranger)); + mkt.setAgentRating(provider, 1); + assertEq(mkt.getAgentRating(provider), 42); + } + + function test_MV13_version() public view { + assertEq(mkt.version(), "2.0.0"); + assertEq(mkt.OPENJOB_LANE(), OWNER_LANE_FLAG); + assertEq(mkt.MODE_SINGLE(), bytes32(0)); + } + + function test_MV14_noPerChainPause() public view { + string memory json = vm.readFile("out/UniversalMarketplace.sol/UniversalMarketplace.json"); + string memory abiSection = vm.split(json, '"bytecode"')[0]; + assertEq(vm.indexOf(abiSection, "setUniversalPaused"), type(uint256).max, "setUniversalPaused"); + assertEq(vm.indexOf(abiSection, "isUniversalPaused"), type(uint256).max, "isUniversalPaused"); + assertEq(vm.indexOf(abiSection, "UniversalChainPaused"), type(uint256).max, "UniversalChainPaused"); + assertTrue(vm.indexOf(abiSection, "openJob") != type(uint256).max, "the artifact is the new one"); + } +} diff --git a/plan/marketplace/contracts/test/8183-tests/UniversalMarketplaceRules.t.sol b/plan/marketplace/contracts/test/8183-tests/UniversalMarketplaceRules.t.sol new file mode 100644 index 00000000..15df8025 --- /dev/null +++ b/plan/marketplace/contracts/test/8183-tests/UniversalMarketplaceRules.t.sol @@ -0,0 +1,548 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import {Test} from "forge-std/Test.sol"; + +import {AssetCap, AllowedCall, ArgPin, PinOp, UniversalTerms} from "@push-agw/libraries/Types.sol"; +import {UniversalMarketplaceRules} from "../../src/agentic-commerce-8183/UniversalMarketplaceRules.sol"; +import {UniversalMarketplaceErrors} from "../../src/agentic-commerce-8183/libraries/Errors.sol"; +import {Session, ActionData, PolicyData} from "../../src/agentic-commerce-8183/interfaces/external/IAGW.sol"; +import { + AgentCardRules, + SessionContext, + MARKER_WALLET, + MARKER_PRINCIPAL +} from "../../src/agentic-commerce-8183/libraries/Types.sol"; +import {RulesFixtures, SessionSkeleton} from "./helpers/RulesFixtures.sol"; + +/// @title UniversalMarketplaceRules — unit suite (PRD 12 §6.3). Direct calls; the marketplace suite covers the +/// same rules through `registerAgentCard` and `openJob`. +contract UniversalMarketplaceRulesTest is Test, RulesFixtures { + UniversalMarketplaceRules internal rules; + + address internal agent = makeAddr("agent"); + address internal usdcPrc20 = makeAddr("pUSDC.sepolia"); + address internal pethPrc20 = makeAddr("pETH.sepolia"); + address internal pool = makeAddr("pool"); + address internal usdc = makeAddr("USDC"); + address internal cea = makeAddr("cea"); + uint256 internal constant PRINCIPAL = 500e6; + uint48 internal constant EXPIRY = 1_800_000_000; + + function setUp() public { + rules = new UniversalMarketplaceRules(); + } + + // ───────── builders ───────── + + function _rules() internal view returns (AgentCardRules memory) { + return _cardRules(usdcPrc20, usdc, pool); + } + + function _rules2() internal view returns (AgentCardRules memory) { + return _cardRulesTwoAssets(usdcPrc20, usdc, pool, pethPrc20); + } + + function _skeleton() internal returns (SessionSkeleton memory) { + return SessionSkeleton({ + validator: makeAddr("validator"), + actionTarget: makeAddr("gateway"), + actionSelector: bytes4(0x12345678), + policy: makeAddr("urp") + }); + } + + function _terms(AgentCardRules memory r) internal view returns (UniversalTerms memory) { + return _fillTerms(r, PRINCIPAL, EXPIRY, cea); + } + + function _session(bytes memory initData) internal returns (Session memory) { + return _wrapSession(initData, agent, _skeleton()); + } + + function _sessionFor(UniversalTerms memory t) internal returns (Session memory) { + return _session(_envelope(t, SEPOLIA)); + } + + function _ctx() internal view returns (SessionContext memory) { + return SessionContext({ + agent: agent, chainHash: SEPOLIA_HASH, principal: PRINCIPAL, expiredAt: EXPIRY, expectedCEA: cea + }); + } + + function _expectInvalid(AgentCardRules memory r, string memory reason) internal { + bytes memory enc = abi.encode(r); + vm.expectRevert(abi.encodeWithSelector(UniversalMarketplaceErrors.InvalidAgentCard.selector, reason)); + rules.validateAgentCardRules(enc); + } + + function _withCalls(AllowedCall[] memory calls) internal view returns (AgentCardRules memory r) { + r = _rules(); + r.allowedCalls = calls; + } + + function _calls1(AllowedCall memory c) internal pure returns (AllowedCall[] memory calls) { + calls = new AllowedCall[](1); + calls[0] = c; + } + + function _calls2(AllowedCall memory a, AllowedCall memory b) internal pure returns (AllowedCall[] memory calls) { + calls = new AllowedCall[](2); + (calls[0], calls[1]) = (a, b); + } + + function _pins2(ArgPin memory a, ArgPin memory b) internal pure returns (ArgPin[] memory pins) { + pins = new ArgPin[](2); + (pins[0], pins[1]) = (a, b); + } + + function _noPins() internal pure returns (ArgPin[] memory) { + return new ArgPin[](0); + } + + function _approveTo(address spender, PinOp amountOp, bytes32 amount) internal view returns (AllowedCall memory) { + return + _allowed(usdc, APPROVE, 0, false, _pins2(_pin(4, PinOp.EQ, _word(spender)), _pin(36, amountOp, amount))); + } + + /// @dev `n` distinct, pinless supply calls (distinct targets). + function _manyCalls(uint256 n) internal pure returns (AllowedCall[] memory calls) { + calls = new AllowedCall[](n); + for (uint256 i; i < n; ++i) { + // forge-lint: disable-next-line(unsafe-typecast) + calls[i] = _allowed(address(uint160(0x1000 + i)), SUPPLY, 0, false, new ArgPin[](0)); // i < 64 + } + } + + function _distinctPins(uint256 n) internal pure returns (ArgPin[] memory pins) { + pins = new ArgPin[](n); + for (uint256 k; k < n; ++k) { + // forge-lint: disable-next-line(unsafe-typecast) + pins[k] = _pin(uint16(4 + 32 * k), PinOp.EQ, bytes32(k + 1)); // k < 9 + } + } + + // ═════════════════════════════ validateAgentCardRules ═════════════════════════════ + + function test_MT01_validate_returnsTokens() public view { + address[] memory one = rules.validateAgentCardRules(abi.encode(_rules())); + assertEq(one.length, 1); + assertEq(one[0], usdcPrc20); + address[] memory two = rules.validateAgentCardRules(abi.encode(_rules2())); + assertEq(two.length, 2); + assertEq(two[0], usdcPrc20); + assertEq(two[1], pethPrc20); + } + + function test_MT02_assetChecks() public { + AgentCardRules memory r = _rules(); + r.assets = new AssetCap[](0); + _expectInvalid(r, "asset count"); // R1: zero + r = _rules(); + AssetCap[] memory nine = new AssetCap[](9); + nine[0] = r.assets[0]; + for (uint256 i = 1; i < 9; ++i) { + // forge-lint: disable-next-line(unsafe-typecast) + nine[i] = AssetCap({token: address(uint160(0x2000 + i)), maxPerCall: 0, maxTotal: 0}); // i < 9 + } + r.assets = nine; + _expectInvalid(r, "asset count"); // R1: MAX_ASSETS + 1 + + r = _rules(); + r.principalAsset = 1; + _expectInvalid(r, "principal asset"); // R2 + + r = _rules2(); + r.assets[1].token = address(0); + _expectInvalid(r, "asset zero"); // R3 + + r = _rules2(); + r.assets[1].token = usdcPrc20; + _expectInvalid(r, "duplicate asset"); // R4 + + // boundary: MAX_ASSETS (8) passes + r = _rules(); + AssetCap[] memory eight = new AssetCap[](8); + for (uint256 i; i < 8; ++i) { + eight[i] = nine[i]; + } + r.assets = eight; + assertEq(rules.validateAgentCardRules(abi.encode(r)).length, 8); + } + + function test_MT03_principalMarkers() public { + AgentCardRules memory r = _rules(); + r.assets[0].maxTotal = 1000e6; + _expectInvalid(r, "principal total not marker"); // R5: a fixed total + + r = _rules(); + r.assets[0].maxPerCall = 0; + _expectInvalid(r, "principal per-call zero"); // R6 + + r = _rules2(); + r.assets[1].maxPerCall = uint256(MARKER_PRINCIPAL); + _expectInvalid(r, "marker off principal asset"); // R7: per-call + r = _rules2(); + r.assets[1].maxTotal = uint256(MARKER_PRINCIPAL); + _expectInvalid(r, "marker off principal asset"); // R7: total + + // principal on asset 1 instead: asset 0 must then carry no marker + r = _rules2(); + r.principalAsset = 1; + r.assets[1] = AssetCap({token: pethPrc20, maxPerCall: 5, maxTotal: uint256(MARKER_PRINCIPAL)}); + _expectInvalid(r, "marker off principal asset"); + r.assets[0] = AssetCap({token: usdcPrc20, maxPerCall: 0, maxTotal: 0}); + rules.validateAgentCardRules(abi.encode(r)); + + // a tranche card: a fixed per-call cap passes + r = _rules(); + r.assets[0].maxPerCall = 100; + rules.validateAgentCardRules(abi.encode(r)); + } + + function test_MT04_allowListAndPins() public { + _expectInvalid(_withCalls(new AllowedCall[](0)), "allow-list size"); // R8 + _expectInvalid(_withCalls(_manyCalls(33)), "allow-list size"); + rules.validateAgentCardRules(abi.encode(_withCalls(_manyCalls(32)))); // boundary + + AllowedCall[] memory c = _manyCalls(1); + c[0].pins = _distinctPins(9); + _expectInvalid(_withCalls(c), "too many pins"); // R9: one call over MAX_PINS + c[0].pins = _distinctPins(8); + rules.validateAgentCardRules(abi.encode(_withCalls(c))); // boundary + + c = _manyCalls(5); // 8 + 8 + 8 + 8 + 1 = 33 pins in all + for (uint256 i; i < 4; ++i) { + c[i].pins = _distinctPins(8); + } + c[4].pins = _distinctPins(1); + _expectInvalid(_withCalls(c), "too many pins"); // R9: total over MAX_ALLOWED_CALL_PINS + c[4].pins = _noPins(); + rules.validateAgentCardRules(abi.encode(_withCalls(c))); // 32 in all: boundary + + AgentCardRules memory r = _rules(); + r.allowedCalls[1].pins[0].op = PinOp.MAX; + _expectInvalid(r, "wallet marker op"); // R10 + } + + function test_MT05_duplicates() public { + AgentCardRules memory r = _rules(); + AllowedCall memory supply = r.allowedCalls[1]; + _expectInvalid(_withCalls(_calls2(supply, supply)), "duplicate call"); // R11 + + AllowedCall memory pinless = _allowed(pool, SUPPLY, 0, false, _noPins()); + _expectInvalid(_withCalls(_calls2(supply, pinless)), "unpinned duplicate"); // R12: either order + _expectInvalid(_withCalls(_calls2(pinless, supply)), "unpinned duplicate"); + AllowedCall memory pinless2 = _allowed(pool, SUPPLY, 4, true, _noPins()); + _expectInvalid(_withCalls(_calls2(pinless, pinless2)), "unpinned duplicate"); // both pinless + + // "approve to Aave or Uniswap": same (target, selector), different pins + AllowedCall memory toAave = _approveTo(pool, PinOp.MAX, MARKER_PRINCIPAL); + AllowedCall memory toUni = _approveTo(makeAddr("uniswap"), PinOp.MAX, MARKER_PRINCIPAL); + rules.validateAgentCardRules(abi.encode(_withCalls(_calls2(toAave, toUni)))); + } + + function test_MT06_erc20Rules() public { + // R13 + _expectInvalid( + _withCalls(_calls1(_allowed(usdc, INCREASE_ALLOWANCE, 4, true, _pins1(4, PinOp.EQ, _word(pool))))), + "increaseAllowance" + ); + + // R14: spender pin missing, zero, dirty high bits, or a marker + _expectInvalid( + _withCalls(_calls1(_allowed(usdc, APPROVE, 0, false, _pins1(36, PinOp.MAX, bytes32(uint256(1)))))), + "approve spender not pinned" + ); + bytes32[4] memory badSpenders = + [bytes32(0), bytes32(uint256(1) << 160 | uint160(pool)), MARKER_WALLET, MARKER_PRINCIPAL]; + for (uint256 i; i < 4; ++i) { + AllowedCall memory a = _approveTo(pool, PinOp.MAX, bytes32(uint256(1))); + a.pins[0].value = badSpenders[i]; + _expectInvalid(_withCalls(_calls1(a)), "approve spender not pinned"); + } + AllowedCall memory spenderAsMax = _approveTo(pool, PinOp.MAX, bytes32(uint256(1))); + spenderAsMax.pins[0].op = PinOp.MAX; + _expectInvalid(_withCalls(_calls1(spenderAsMax)), "approve spender not pinned"); + + // R15: amount pin missing, or under EQ + _expectInvalid( + _withCalls(_calls1(_allowed(usdc, APPROVE, 0, false, _pins1(4, PinOp.EQ, _word(pool))))), + "approve amount not capped" + ); + _expectInvalid(_withCalls(_calls1(_approveTo(pool, PinOp.EQ, bytes32(uint256(1))))), "approve amount not capped"); + + // approve passes with a MAX literal and with MAX MARKER_PRINCIPAL; required pins may sit anywhere + rules.validateAgentCardRules(abi.encode(_withCalls(_calls1(_approveTo(pool, PinOp.MAX, bytes32(uint256(7))))))); + rules.validateAgentCardRules(abi.encode(_withCalls(_calls1(_approveTo(pool, PinOp.MAX, MARKER_PRINCIPAL))))); + AllowedCall memory reordered = _approveTo(pool, PinOp.MAX, MARKER_PRINCIPAL); + (reordered.pins[0], reordered.pins[1]) = (reordered.pins[1], reordered.pins[0]); + rules.validateAgentCardRules(abi.encode(_withCalls(_calls1(reordered)))); + + // R16 / R17: refused without the recipient bound, at the right offset + _expectInvalid(_withCalls(_calls1(_allowed(usdc, TRANSFER, 4, false, _noPins()))), "erc20 transfer recipient"); + _expectInvalid(_withCalls(_calls1(_allowed(usdc, TRANSFER, 36, true, _noPins()))), "erc20 transfer recipient"); + _expectInvalid( + _withCalls(_calls1(_allowed(usdc, TRANSFER, 0, false, _pins1(36, PinOp.EQ, MARKER_WALLET)))), + "erc20 transfer recipient" + ); + _expectInvalid( + _withCalls(_calls1(_allowed(usdc, TRANSFER, 0, false, _pins1(4, PinOp.EQ, _word(cea))))), + "erc20 transfer recipient" + ); + _expectInvalid( + _withCalls(_calls1(_allowed(usdc, TRANSFER_FROM, 36, false, _noPins()))), "erc20 transferFrom recipient" + ); + _expectInvalid( + _withCalls(_calls1(_allowed(usdc, TRANSFER_FROM, 4, true, _noPins()))), "erc20 transferFrom recipient" + ); + _expectInvalid( + _withCalls(_calls1(_allowed(usdc, TRANSFER_FROM, 0, false, _pins1(4, PinOp.EQ, MARKER_WALLET)))), + "erc20 transferFrom recipient" + ); + + // pass with the beneficiary field, and with an EQ MARKER_WALLET pin + rules.validateAgentCardRules( + abi.encode( + _withCalls( + _calls2( + _allowed(usdc, TRANSFER, 4, true, _noPins()), _allowed(usdc, TRANSFER_FROM, 36, true, _noPins()) + ) + ) + ) + ); + rules.validateAgentCardRules( + abi.encode( + _withCalls( + _calls2( + _allowed(usdc, TRANSFER, 0, false, _pins1(4, PinOp.EQ, MARKER_WALLET)), + _allowed(usdc, TRANSFER_FROM, 0, false, _pins1(36, PinOp.EQ, MARKER_WALLET)) + ) + ) + ) + ); + } + + // ═════════════════════════════ checkRulesMatchCard ═════════════════════════════ + + function test_MT07_match_happy() public { + rules.checkRulesMatchCard(abi.encode(_rules()), _sessionFor(_terms(_rules())), _ctx()); + rules.checkRulesMatchCard(abi.encode(_rules2()), _sessionFor(_terms(_rules2())), _ctx()); + + AgentCardRules memory tranche = _rules2(); + tranche.assets[0].maxPerCall = 100e6; // per-call fixed + UniversalTerms memory t = _terms(tranche); + assertEq(t.assets[0].maxPerCall, 100e6, "fixed per-call is copied, not filled"); + assertEq(t.assets[0].maxTotal, PRINCIPAL); + rules.checkRulesMatchCard(abi.encode(tranche), _sessionFor(t), _ctx()); + } + + function _expectMatch(AgentCardRules memory r, Session memory s, bytes memory err) internal { + bytes memory enc = abi.encode(r); + SessionContext memory ctx = _ctx(); + vm.expectRevert(err); + rules.checkRulesMatchCard(enc, s, ctx); + } + + function _expectTerms(UniversalTerms memory t, bytes memory err) internal { + _expectMatch(_rules2(), _sessionFor(t), err); + } + + function test_MT08_match_eachError() public { + AgentCardRules memory r = _rules2(); + bytes memory actionsMismatch = abi.encodeWithSelector(UniversalMarketplaceErrors.ActionsMismatch.selector); + + // C1 + Session memory s = _sessionFor(_terms(r)); + s.sessionValidatorInitData = abi.encode(makeAddr("other")); + _expectMatch(r, s, abi.encodeWithSelector(UniversalMarketplaceErrors.AgentMismatch.selector)); + s.sessionValidatorInitData = abi.encodePacked(agent); // 20 bytes: not the 32-byte agent config + _expectMatch(r, s, abi.encodeWithSelector(UniversalMarketplaceErrors.AgentMismatch.selector)); + + // C2 + s = _sessionFor(_terms(r)); + s.actions = new ActionData[](0); + _expectMatch(r, s, abi.encodeWithSelector(UniversalMarketplaceErrors.ActionCount.selector)); + s = _sessionFor(_terms(r)); + ActionData[] memory two = new ActionData[](2); + (two[0], two[1]) = (s.actions[0], s.actions[0]); + s.actions = two; + _expectMatch(r, s, abi.encodeWithSelector(UniversalMarketplaceErrors.ActionCount.selector)); + + // C3 + s = _sessionFor(_terms(r)); + s.actions[0].actionPolicies = new PolicyData[](0); + _expectMatch(r, s, abi.encodeWithSelector(UniversalMarketplaceErrors.PolicyShape.selector, 0)); + s = _sessionFor(_terms(r)); + PolicyData[] memory twoPolicies = new PolicyData[](2); + (twoPolicies[0], twoPolicies[1]) = (s.actions[0].actionPolicies[0], s.actions[0].actionPolicies[0]); + s.actions[0].actionPolicies = twoPolicies; + _expectMatch(r, s, abi.encodeWithSelector(UniversalMarketplaceErrors.PolicyShape.selector, 0)); + + // C4: pre-v6 two-field envelope (first word = 64, the string's offset), version 2, and under one word + bytes memory body = abi.encode(_terms(r)); + _expectMatch( + r, + _session(abi.encode(SEPOLIA, body)), + abi.encodeWithSelector(UniversalMarketplaceErrors.EnvelopeVersionMismatch.selector, 64) + ); + _expectMatch( + r, + _session(abi.encode(uint16(2), SEPOLIA, body)), + abi.encodeWithSelector(UniversalMarketplaceErrors.EnvelopeVersionMismatch.selector, 2) + ); + _expectMatch( + r, _session(new bytes(31)), abi.encodeWithSelector(UniversalMarketplaceErrors.EnvelopeVersionMismatch.selector, 0) + ); + + // C5 + _expectMatch( + r, + _session(_envelope(_terms(r), "eip155:1")), + abi.encodeWithSelector(UniversalMarketplaceErrors.ChainMismatch.selector, 0) + ); + + // C6: the card has two assets; the session one + UniversalTerms memory t = _terms(_rules()); + _expectTerms(t, abi.encodeWithSelector(UniversalMarketplaceErrors.AssetCountMismatch.selector, 2, 1)); + + // C7: each index + t = _terms(r); + t.assets[0].token = usdc; + _expectTerms(t, abi.encodeWithSelector(UniversalMarketplaceErrors.AssetMismatch.selector, 0)); + t = _terms(r); + t.assets[1].token = usdc; + _expectTerms(t, abi.encodeWithSelector(UniversalMarketplaceErrors.AssetMismatch.selector, 1)); + + // C8 + t = _terms(r); + t.assets[0].maxTotal = PRINCIPAL + 1; + _expectTerms(t, abi.encodeWithSelector(UniversalMarketplaceErrors.PrincipalCapMismatch.selector)); + t = _terms(r); + t.assets[0].maxPerCall = PRINCIPAL - 1; + _expectTerms(t, abi.encodeWithSelector(UniversalMarketplaceErrors.PrincipalCapMismatch.selector)); + + // C9: each field of the non-principal asset + t = _terms(r); + t.assets[1].maxPerCall = 1; + _expectTerms(t, abi.encodeWithSelector(UniversalMarketplaceErrors.AssetMismatch.selector, 1)); + t = _terms(r); + t.assets[1].maxTotal = 1; + _expectTerms(t, abi.encodeWithSelector(UniversalMarketplaceErrors.AssetMismatch.selector, 1)); + + // C10 + t = _terms(r); + t.maxGasPerCall = 0; + _expectTerms(t, abi.encodeWithSelector(UniversalMarketplaceErrors.GasCapMismatch.selector)); + + // C11: length, then every call field, then every pin's offset and op + t = _terms(r); + AllowedCall[] memory shorter = new AllowedCall[](2); + (shorter[0], shorter[1]) = (t.allowedCalls[0], t.allowedCalls[1]); + t.allowedCalls = shorter; + _expectTerms(t, actionsMismatch); + for (uint256 f; f < 8; ++f) { + t = _terms(r); + AllowedCall memory c = t.allowedCalls[0]; + if (f == 0) c.target = pool; + if (f == 1) c.selector = TRANSFER; + if (f == 2) c.beneficiaryOffset = 4; + if (f == 3) c.hasBeneficiary = true; + if (f == 4) c.maxValue = 1; + if (f == 5) c.pins = _pins1(4, PinOp.EQ, _word(pool)); + if (f == 6) c.pins[1].offset = 68; + if (f == 7) c.pins[1].op = PinOp.EQ; + _expectTerms(t, actionsMismatch); + } + + // C13 + t = _terms(r); + t.validUntil = EXPIRY - 1; + _expectTerms(t, abi.encodeWithSelector(UniversalMarketplaceErrors.ExpiryMismatch.selector)); + + // C14 + t = _terms(r); + t.expectedCEA = address(0xBAD); + t.allowedCalls[1].pins[0].value = _word(address(0xBAD)); // keep C12 satisfied for the bad CEA + SessionContext memory ctx = _ctx(); + bytes memory enc = abi.encode(r); + Session memory bad = _sessionFor(t); + vm.expectRevert(abi.encodeWithSelector(UniversalMarketplaceErrors.PinMismatch.selector, 1, 0)); + rules.checkRulesMatchCard(enc, bad, ctx); // C12 runs before C14: the pin is checked against ctx's CEA + t.allowedCalls[1].pins[0].value = _word(cea); + bad = _sessionFor(t); + vm.expectRevert(abi.encodeWithSelector(UniversalMarketplaceErrors.ExpectedCEAMismatch.selector, cea, address(0xBAD))); + rules.checkRulesMatchCard(enc, bad, ctx); + } + + function test_MT09_match_pins() public { + AgentCardRules memory r = _rules(); + + UniversalTerms memory t = _terms(r); + t.allowedCalls[1].pins[0].value = _word(makeAddr("otherCEA")); // MARKER_WALLET, wrong CEA + _expectMatch(r, _sessionFor(t), abi.encodeWithSelector(UniversalMarketplaceErrors.PinMismatch.selector, 1, 0)); + + t = _terms(r); + t.allowedCalls[0].pins[1].value = bytes32(PRINCIPAL - 1); // MARKER_PRINCIPAL, principal − 1 + _expectMatch(r, _sessionFor(t), abi.encodeWithSelector(UniversalMarketplaceErrors.PinMismatch.selector, 0, 1)); + + t = _terms(r); + t.allowedCalls[0].pins[0].value = _word(makeAddr("otherSpender")); // a changed literal + _expectMatch(r, _sessionFor(t), abi.encodeWithSelector(UniversalMarketplaceErrors.PinMismatch.selector, 0, 0)); + + t = _terms(r); + t.allowedCalls[1].pins[0].value = MARKER_WALLET; // the raw marker, unfilled + _expectMatch(r, _sessionFor(t), abi.encodeWithSelector(UniversalMarketplaceErrors.PinMismatch.selector, 1, 0)); + t = _terms(r); + t.allowedCalls[0].pins[1].value = MARKER_PRINCIPAL; + _expectMatch(r, _sessionFor(t), abi.encodeWithSelector(UniversalMarketplaceErrors.PinMismatch.selector, 0, 1)); + } + + /// @dev Malformed bytes fail in `abi.decode`, which reverts with no data: a bare expectRevert is the only + /// way to name it. Each case is otherwise well formed, so nothing else can be what reverts. + function test_MT10_malformedInputs() public { + vm.expectRevert(); + rules.validateAgentCardRules(hex"01"); + + bytes memory enc = abi.encode(_rules()); + SessionContext memory ctx = _ctx(); + Session memory badEnvelope = _session(abi.encodePacked(uint256(1), hex"01")); // right version, then garbage + vm.expectRevert(); + rules.checkRulesMatchCard(enc, badEnvelope, ctx); + + Session memory badBody = _session(abi.encode(uint16(1), SEPOLIA, hex"01")); + vm.expectRevert(); + rules.checkRulesMatchCard(enc, badBody, ctx); + + Session memory good = _sessionFor(_terms(_rules())); + vm.expectRevert(); + rules.checkRulesMatchCard(hex"01", good, ctx); + } + + function testFuzz_MT11_principalBinding(uint256 principal) public { + principal = bound(principal, 1, 1e30); + AgentCardRules memory r = _rules2(); + bytes memory enc = abi.encode(r); + SessionContext memory ctx = _ctx(); + ctx.principal = principal; + rules.checkRulesMatchCard(enc, _sessionFor(_fillTerms(r, principal, EXPIRY, cea)), ctx); + + UniversalTerms memory t = _fillTerms(r, principal, EXPIRY, cea); + t.assets[0].maxTotal = principal + 1; + Session memory s = _sessionFor(t); + vm.expectRevert(UniversalMarketplaceErrors.PrincipalCapMismatch.selector); + rules.checkRulesMatchCard(enc, s, ctx); + + t = _fillTerms(r, principal, EXPIRY, cea); + t.assets[0].maxTotal = principal - 1; + s = _sessionFor(t); + vm.expectRevert(UniversalMarketplaceErrors.PrincipalCapMismatch.selector); + rules.checkRulesMatchCard(enc, s, ctx); + + t = _fillTerms(r, principal, EXPIRY, cea); + t.assets[0].maxPerCall = principal + 1; + s = _sessionFor(t); + vm.expectRevert(UniversalMarketplaceErrors.PrincipalCapMismatch.selector); + rules.checkRulesMatchCard(enc, s, ctx); + } +} diff --git a/plan/marketplace/contracts/test/8183-tests/helpers/RulesFixtures.sol b/plan/marketplace/contracts/test/8183-tests/helpers/RulesFixtures.sol new file mode 100644 index 00000000..8032e59e --- /dev/null +++ b/plan/marketplace/contracts/test/8183-tests/helpers/RulesFixtures.sol @@ -0,0 +1,184 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import { + AssetCap, + AllowedCall, + ArgPin, + PinOp, + UniversalTerms, + ENVELOPE_VERSION +} from "@push-agw/libraries/Types.sol"; +import { + Session, + ActionData, + PolicyData, + ERC7739Data, + ERC7739Context +} from "../../../src/agentic-commerce-8183/interfaces/external/IAGW.sol"; +import {AgentCardRules, MARKER_WALLET, MARKER_PRINCIPAL} from "../../../src/agentic-commerce-8183/libraries/Types.sol"; + +/// @notice The session fields the marketplace never checks and the AGW pins at `grantRules`. Unit suites pass test +/// values; the fork suite passes the real AGW v6 ones. +struct SessionSkeleton { + address validator; + address actionTarget; + bytes4 actionSelector; + address policy; +} + +/// @title RulesFixtures — TEST ONLY: card rules, and the session the SDK builds from them (PRD 12 §6.1, Appendix E). +/// @notice `_fillTerms` plays the SDK: it copies the card's rules into `UniversalTerms` and fills the markers for one +/// job. Everything here is pure; deep copies throughout, so editing a filled session never edits the card. +abstract contract RulesFixtures { + string internal constant SEPOLIA = "eip155:11155111"; + bytes32 internal constant SEPOLIA_HASH = keccak256("eip155:11155111"); + + bytes4 internal constant SUPPLY = bytes4(keccak256("supply(address,uint256,address,uint16)")); + bytes4 internal constant TRANSFER = 0xa9059cbb; + bytes4 internal constant APPROVE = 0x095ea7b3; + bytes4 internal constant TRANSFER_FROM = 0x23b872dd; + bytes4 internal constant INCREASE_ALLOWANCE = 0x39509351; + + // ───────── card rules ───────── + + /// @dev One asset (the principal, both caps the marker) and three calls: `approve(pool, ≤ principal)`, + /// `pool.supply(_, _, onBehalfOf = wallet, _)`, `transfer(wallet, _)` by the beneficiary field. + function _cardRules(address usdcPrc20, address usdcDest, address pool) + internal + pure + returns (AgentCardRules memory r) + { + r.assets = new AssetCap[](1); + r.assets[0] = + AssetCap({token: usdcPrc20, maxPerCall: uint256(MARKER_PRINCIPAL), maxTotal: uint256(MARKER_PRINCIPAL)}); + r.principalAsset = 0; + r.maxGasPerCall = 1e18; + r.allowedCalls = new AllowedCall[](3); + ArgPin[] memory approvePins = new ArgPin[](2); + approvePins[0] = _pin(4, PinOp.EQ, _word(pool)); + approvePins[1] = _pin(36, PinOp.MAX, MARKER_PRINCIPAL); + r.allowedCalls[0] = _allowed(usdcDest, APPROVE, 0, false, approvePins); + r.allowedCalls[1] = _allowed(pool, SUPPLY, 0, false, _pins1(68, PinOp.EQ, MARKER_WALLET)); + r.allowedCalls[2] = _allowed(usdcDest, TRANSFER, 4, true, new ArgPin[](0)); + } + + /// @dev `_cardRules` plus a second asset that may route but never moves: `{pETH, 0, 0}`. + function _cardRulesTwoAssets(address usdcPrc20, address usdcDest, address pool, address pethPrc20) + internal + pure + returns (AgentCardRules memory r) + { + r = _cardRules(usdcPrc20, usdcDest, pool); + AssetCap[] memory assets = new AssetCap[](2); + assets[0] = r.assets[0]; + assets[1] = AssetCap({token: pethPrc20, maxPerCall: 0, maxTotal: 0}); + r.assets = assets; + } + + // ───────── the SDK's session ───────── + + /// @dev Appendix E: the principal asset's caps → `principal` (per-call only if it is the marker); pins' + /// `MARKER_PRINCIPAL` → `bytes32(principal)`, `MARKER_WALLET` → the CEA word; everything else copied. + function _fillTerms(AgentCardRules memory r, uint256 principal, uint48 validUntil, address cea) + internal + pure + returns (UniversalTerms memory t) + { + t.validUntil = validUntil; + t.expectedCEA = cea; + t.maxGasPerCall = r.maxGasPerCall; + t.assets = new AssetCap[](r.assets.length); + for (uint256 i; i < r.assets.length; ++i) { + t.assets[i] = _fillAsset(r.assets[i], i == r.principalAsset, principal); + } + t.allowedCalls = new AllowedCall[](r.allowedCalls.length); + for (uint256 i; i < r.allowedCalls.length; ++i) { + t.allowedCalls[i] = _fillCall(r.allowedCalls[i], principal, cea); + } + } + + function _fillAsset(AssetCap memory a, bool isPrincipal, uint256 principal) + internal + pure + returns (AssetCap memory filled) + { + filled = AssetCap({token: a.token, maxPerCall: a.maxPerCall, maxTotal: a.maxTotal}); + if (!isPrincipal) return filled; + filled.maxTotal = principal; + if (a.maxPerCall == uint256(MARKER_PRINCIPAL)) filled.maxPerCall = principal; + } + + function _fillCall(AllowedCall memory c, uint256 principal, address cea) + internal + pure + returns (AllowedCall memory filled) + { + ArgPin[] memory pins = new ArgPin[](c.pins.length); + for (uint256 k; k < pins.length; ++k) { + pins[k] = _fillPin(c.pins[k], principal, cea); + } + filled = _allowed(c.target, c.selector, c.beneficiaryOffset, c.hasBeneficiary, pins); + filled.maxValue = c.maxValue; + } + + function _fillPin(ArgPin memory p, uint256 principal, address cea) internal pure returns (ArgPin memory) { + bytes32 v = p.value; + if (v == MARKER_WALLET) v = _word(cea); + else if (v == MARKER_PRINCIPAL) v = bytes32(principal); + return _pin(p.offset, p.op, v); + } + + /// @dev The v6 envelope: `abi.encode(uint16 version, string chain, bytes body)`. + function _envelope(UniversalTerms memory t, string memory chain) internal pure returns (bytes memory) { + return abi.encode(ENVELOPE_VERSION, chain, abi.encode(t)); + } + + /// @dev One action, one policy carrying `initData`; the agent is `abi.encode(agent)`. + function _wrapSession(bytes memory initData, address agent, SessionSkeleton memory sk) + internal + pure + returns (Session memory s) + { + s.sessionValidator = sk.validator; + s.sessionValidatorInitData = abi.encode(agent); + s.erc7739Policies = + ERC7739Data({allowedERC7739Content: new ERC7739Context[](0), erc1271Policies: new PolicyData[](0)}); + s.userOpPolicies = new PolicyData[](0); + PolicyData[] memory p = new PolicyData[](1); + p[0] = PolicyData({policy: sk.policy, initData: initData}); + s.actions = new ActionData[](1); + s.actions[0] = + ActionData({actionTargetSelector: sk.actionSelector, actionTarget: sk.actionTarget, actionPolicies: p}); + } + + // ───────── small builders ───────── + + function _word(address a) internal pure returns (bytes32) { + return bytes32(uint256(uint160(a))); + } + + function _pin(uint16 offset, PinOp op, bytes32 value) internal pure returns (ArgPin memory) { + return ArgPin({offset: offset, op: op, value: value}); + } + + function _pins1(uint16 offset, PinOp op, bytes32 value) internal pure returns (ArgPin[] memory pins) { + pins = new ArgPin[](1); + pins[0] = _pin(offset, op, value); + } + + function _allowed(address target, bytes4 selector, uint16 offset, bool hasBeneficiary, ArgPin[] memory pins) + internal + pure + returns (AllowedCall memory) + { + return AllowedCall({ + target: target, + selector: selector, + beneficiaryOffset: offset, + hasBeneficiary: hasBeneficiary, + maxValue: 0, + pins: pins + }); + } +} diff --git a/plan/marketplace/contracts/test/8183-tests/helpers/TemplateParts.sol b/plan/marketplace/contracts/test/8183-tests/helpers/TemplateParts.sol new file mode 100644 index 00000000..3c6a4248 --- /dev/null +++ b/plan/marketplace/contracts/test/8183-tests/helpers/TemplateParts.sol @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import { + Evaluation, + Operation, + LogicKind, + Logic, + T_UINT, + T_ADDRESS, + T_TUPLE +} from "../../../src/agentic-commerce-8183/libraries/JobSpecTypes.sol"; +import { + FillSource, + Fill, + ReadTemplate, + TargetSource, + CheckTemplate +} from "../../../src/agentic-commerce-8183/libraries/Types.sol"; + +/// @title TemplateParts — TEST ONLY: chain-agnostic builders for jobSpecTemplates +/// @notice Shared by the builder, conformance and marketplace suites. Every builder is pure. +abstract contract TemplateParts { + bytes4 internal constant BALANCE_OF = bytes4(keccak256("balanceOf(address)")); + bytes4 internal constant GET_RESERVE_DATA = bytes4(keccak256("getReserveData(address)")); + bytes4 internal constant MAX_WITHDRAW = bytes4(keccak256("maxWithdraw(address)")); + + // ───────── outputs and fields ───────── + + function _uintOut() internal pure returns (bytes memory) { + return abi.encodePacked(T_TUPLE, uint8(1), T_UINT); + } + + /// @dev Aave v3 `getReserveData` → one 15-field struct, the V2 doc's encoding. + function _reserveDataOut() internal pure returns (bytes memory) { + return abi.encodePacked( + abi.encodePacked(T_TUPLE, uint8(1), T_TUPLE, uint8(15), T_TUPLE, uint8(1), T_UINT), + abi.encodePacked(T_UINT, T_UINT, T_UINT, T_UINT, T_UINT, T_UINT, T_UINT), + abi.encodePacked(T_ADDRESS, T_ADDRESS, T_ADDRESS, T_ADDRESS, T_UINT, T_UINT, T_UINT) + ); + } + + function _f(uint8 a) internal pure returns (uint8[] memory f) { + f = new uint8[](1); + f[0] = a; + } + + function _f2(uint8 a, uint8 b) internal pure returns (uint8[] memory f) { + f = new uint8[](2); + f[0] = a; + f[1] = b; + } + + function _noFills() internal pure returns (Fill[] memory) { + return new Fill[](0); + } + + function _ceaFill(uint8 word) internal pure returns (Fill[] memory fills) { + fills = new Fill[](1); + fills[0] = Fill({word: word, source: FillSource.CEA, param: 0}); + } + + // ───────── reads, checks, logic ───────── + + function _read( + string memory chainId, + address target, + bytes4 selector, + bytes memory args, + Fill[] memory fills, + bytes memory outputs, + uint8[] memory field + ) internal pure returns (ReadTemplate memory) { + return ReadTemplate({ + chainNamespace: "eip155", + chainId: chainId, + minConfirmations: 12, + target: target, + selector: selector, + args: args, + fills: fills, + outputs: outputs, + field: field + }); + } + + /// @dev `token.balanceOf(CEA)` on `chainId`: args are one zero word the CEA fill overwrites. + function _balanceOfCEA(string memory chainId, address token) internal pure returns (ReadTemplate memory) { + return _read(chainId, token, BALANCE_OF, new bytes(32), _ceaFill(0), _uintOut(), _f(0)); + } + + function _chk(uint8 read, Evaluation e, Operation op, TargetSource src, int256 value) + internal + pure + returns (CheckTemplate memory) + { + return CheckTemplate({read: read, evaluation: e, operation: op, source: src, value: value}); + } + + /// @dev One logic step over `checks` and child steps `children`; `k` for AT_LEAST only. + function _step(LogicKind kind, uint8[] memory checks, uint8[] memory children, uint8 k) + internal + pure + returns (Logic memory) + { + return Logic({kind: kind, checks: checks, children: children, k: k}); + } + + /// @dev A one-step tree: `kind` over `checks`, no children. + function _rootOf(LogicKind kind, uint8[] memory checks) internal pure returns (Logic[] memory logic) { + logic = new Logic[](1); + logic[0] = _step(kind, checks, new uint8[](0), 0); + } + + function _none() internal pure returns (uint8[] memory) { + return new uint8[](0); + } + + function _one(uint8 a) internal pure returns (uint8[] memory c) { + c = new uint8[](1); + c[0] = a; + } + + function _kids(uint8 a, uint8 b) internal pure returns (uint8[] memory c) { + c = new uint8[](2); + c[0] = a; + c[1] = b; + } + + function _kids3(uint8 a, uint8 b, uint8 d) internal pure returns (uint8[] memory c) { + c = new uint8[](3); + c[0] = a; + c[1] = b; + c[2] = d; + } +} diff --git a/plan/marketplace/contracts/test/8183-tests/helpers/V2Decoder.sol b/plan/marketplace/contracts/test/8183-tests/helpers/V2Decoder.sol new file mode 100644 index 00000000..9a71b651 --- /dev/null +++ b/plan/marketplace/contracts/test/8183-tests/helpers/V2Decoder.sol @@ -0,0 +1,173 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import { + T_UINT, + T_INT, + T_BOOL, + T_ADDRESS, + T_BYTES, + T_STRING, + T_TUPLE, + T_ARRAY, + T_FIXED_ARRAY +} from "../../../src/agentic-commerce-8183/libraries/JobSpecTypes.sol"; + +/// @title V2Decoder — TEST ONLY: the evaluator's answer decoder, as written in the V2 design doc +/// @notice The reference the conformance suite holds the marketplace's templates to. +/// @dev - Source: `docs-internal/Universal Evaluator V2 Design`, "The decoder (in the evaluator)". Logic copied +/// verbatim; only the layout is `forge fmt`'s. Do not "fix" it here: a divergence is a finding. +/// - `locate` is the one addition: it exposes `_locate` so a test can compare leaf types. +// forge-lint: disable-start(unsafe-typecast) +contract V2Decoder { + /// @notice The number to compare, from answer `res`. + function decodeAnswer(bytes memory outputs, uint8[] memory field, bytes calldata res) + external + pure + returns (bool, int256) + { + (bool ok, uint8 leaf, uint256 at) = _locate(outputs, field, res); + if (!ok) return (false, 0); + + if (leaf == T_BYTES || leaf == T_STRING || leaf == T_ARRAY) { + (bool ok2, uint256 len) = _word(res, at); + if (!ok2) return (false, 0); + if (leaf == T_ARRAY) return (true, int256(len)); + if (len > res.length || at + 32 + len > res.length) return (false, 0); + return (true, int256(uint256(keccak256(res[at + 32:at + 32 + len])))); + } + + (bool ok3, uint256 w) = _word(res, at); + if (!ok3) return (false, 0); + if (leaf == T_UINT) return w > uint256(type(int256).max) ? (false, int256(0)) : (true, int256(w)); + if (leaf == T_INT) return (true, int256(w)); + if (leaf == T_BOOL) return w > 1 ? (false, int256(0)) : (true, int256(w)); + if (leaf == T_ADDRESS) return w >> 160 != 0 ? (false, int256(0)) : (true, int256(w)); + return (true, int256(w)); + } + + /// @notice `_locate`, exposed: whether the path resolves, the leaf's type code, and its offset in `res`. + function locate(bytes memory types, uint8[] memory field, bytes calldata res) + external + pure + returns (bool ok, uint8 leaf, uint256 at) + { + return _locate(types, field, res); + } + + /// @dev Walks the return types along `field` and finds where that value sits in `res`. + function _locate(bytes memory types, uint8[] memory field, bytes calldata res) + internal + pure + returns (bool ok, uint8 leaf, uint256 at) + { + uint256 t; + uint256 base; + for (uint256 i; i < field.length; ++i) { + uint8 code = uint8(types[t]); + uint256 idx = field[i]; + uint256 elem; + uint256 ptr; + + if (code == T_TUPLE) { + if (idx >= uint8(types[t + 1])) return (false, 0, 0); + uint256 c = t + 2; + uint256 head; + for (uint256 j; j < idx; ++j) { + head += _headWords(types, c); + c = _skip(types, c); + } + uint256 slot = base + 32 * head; + if (_isDynamic(types, c)) { + (ok, ptr) = _word(res, slot); + if (!ok || ptr > res.length) return (false, 0, 0); + base += ptr; + } else { + base = slot; + } + t = c; + } else if (code == T_ARRAY) { + elem = t + 1; + uint256 len; + (ok, len) = _word(res, base); + if (!ok || idx >= len) return (false, 0, 0); + uint256 start = base + 32; + if (_isDynamic(types, elem)) { + (ok, ptr) = _word(res, start + 32 * idx); + if (!ok || ptr > res.length) return (false, 0, 0); + base = start + ptr; + } else { + base = start + 32 * idx * _headWords(types, elem); + } + t = elem; + } else if (code == T_FIXED_ARRAY) { + if (idx >= uint8(types[t + 1])) return (false, 0, 0); + elem = t + 2; + if (_isDynamic(types, elem)) { + (ok, ptr) = _word(res, base + 32 * idx); + if (!ok || ptr > res.length) return (false, 0, 0); + base += ptr; + } else { + base += 32 * idx * _headWords(types, elem); + } + t = elem; + } else { + return (false, 0, 0); + } + } + return (true, uint8(types[t]), base); + } + + /// @dev bytes, string and T[] are dynamic; a struct or T[k] is dynamic if anything inside is. + function _isDynamic(bytes memory types, uint256 t) internal pure returns (bool) { + uint8 code = uint8(types[t]); + if (code == T_BYTES || code == T_STRING || code == T_ARRAY) return true; + if (code == T_FIXED_ARRAY) return _isDynamic(types, t + 2); + if (code == T_TUPLE) { + uint256 c = t + 2; + for (uint256 j; j < uint8(types[t + 1]); ++j) { + if (_isDynamic(types, c)) return true; + c = _skip(types, c); + } + } + return false; + } + + /// @dev Slots a value takes in its parent's head: 1 if dynamic (a pointer), else its full size. + function _headWords(bytes memory types, uint256 t) internal pure returns (uint256 n) { + if (_isDynamic(types, t)) return 1; + uint8 code = uint8(types[t]); + if (code == T_FIXED_ARRAY) return uint8(types[t + 1]) * _headWords(types, t + 2); + if (code == T_TUPLE) { + uint256 c = t + 2; + for (uint256 j; j < uint8(types[t + 1]); ++j) { + n += _headWords(types, c); + c = _skip(types, c); + } + return n; + } + return 1; + } + + /// @dev The position in `types` right after the type starting at `t`. + function _skip(bytes memory types, uint256 t) internal pure returns (uint256) { + uint8 code = uint8(types[t]); + if (code == T_ARRAY) return _skip(types, t + 1); + if (code == T_FIXED_ARRAY) return _skip(types, t + 2); + if (code == T_TUPLE) { + uint256 c = t + 2; + for (uint256 j; j < uint8(types[t + 1]); ++j) { + c = _skip(types, c); + } + return c; + } + return t + 1; + } + + /// @dev One 32-byte slot of the answer, or not-ok if the answer is too short. + function _word(bytes calldata b, uint256 at) internal pure returns (bool, uint256) { + if (at > b.length || b.length - at < 32) return (false, 0); + return (true, uint256(bytes32(b[at:at + 32]))); + } +} +// forge-lint: disable-end(unsafe-typecast) diff --git a/plan/marketplace/contracts/test/8183-tests/mocks/BareHook.sol b/plan/marketplace/contracts/test/8183-tests/mocks/BareHook.sol new file mode 100644 index 00000000..1197a652 --- /dev/null +++ b/plan/marketplace/contracts/test/8183-tests/mocks/BareHook.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import {BaseERC8183Hook} from "../../../src/agentic-commerce-8183/hooks/BaseERC8183Hook.sol"; + +/// @notice Overrides nothing: exercises the base's default no-op handlers. +contract BareHook is BaseERC8183Hook { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address kernel_) external initializer { + __BaseERC8183Hook_init(kernel_); + } +} diff --git a/plan/marketplace/contracts/test/8183-tests/mocks/ERC165Only.sol b/plan/marketplace/contracts/test/8183-tests/mocks/ERC165Only.sol new file mode 100644 index 00000000..b1592493 --- /dev/null +++ b/plan/marketplace/contracts/test/8183-tests/mocks/ERC165Only.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; + +/// @notice Answers ERC-165 for IERC165 only — not a valid hook. +contract ERC165Only is IERC165 { + function supportsInterface(bytes4 id) external pure returns (bool) { + return id == type(IERC165).interfaceId; + } +} diff --git a/plan/marketplace/contracts/test/8183-tests/mocks/MockAGW.sol b/plan/marketplace/contracts/test/8183-tests/mocks/MockAGW.sol new file mode 100644 index 00000000..def049d4 --- /dev/null +++ b/plan/marketplace/contracts/test/8183-tests/mocks/MockAGW.sol @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import {OwnerIntent} from "@push-agw/libraries/Types.sol"; +import {Session} from "../../../src/agentic-commerce-8183/interfaces/external/IAGW.sol"; + +/// @notice An AGW stand-in for UniversalMarketplace unit tests. OBSERVER, NOT ORACLE: it records what +/// the marketplace presented and forwards the exec calldata so the REAL kernel runs `createJob` +/// with this contract as `msg.sender`. It checks the presenter and hashes like the real wallet, +/// and verifies no signature. `mode` lets a test make it misbehave in the ways the +/// marketplace must catch. +/// @dev `grantRulesWithSig` decodes the policy envelope as `(uint16, string, bytes)` exactly as the real wallet's +/// policy does, so a session in the pre-v6 two-field format fails here the way it fails there (a decode panic). +contract MockAGW { + enum Mode { + Honest, + TwoJobs, + ForeignClient, + OtherEvaluator // rewrites createJob's evaluator argument before calling the kernel + } + + address public constant OTHER_EVALUATOR = address(0xE7A1); + + address public immutable OWNER; + Mode public mode; + uint64 public grantNonce; + mapping(uint192 => uint64) public getNonce; + + bytes32 public lastSessionHash; + bytes32 public lastGrantIntentHash; + bytes32 public lastExecIntentHash; + bytes32 public lastExecCalldataHash; + address public lastGrantCaller; + /// @notice The full policy `initData` of the last grant, for tests and the MI07 invariant to decode. + bytes public lastPolicyInitData; + + bytes32 public constant RULES_ID = keccak256("mock-rules"); + + constructor(address owner_) { + OWNER = owner_; + } + + receive() external payable {} + + function setMode(Mode m) external { + mode = m; + } + + function grantRulesWithSig(Session calldata session, OwnerIntent calldata intent, bytes calldata) + external + returns (bytes32) + { + require(msg.sender == intent.executor, "MockAGW: executor"); + require(intent.sessionHash == keccak256(abi.encode(session)), "MockAGW: session hash"); + require(intent.grantNonce == grantNonce, "MockAGW: grant nonce"); + bytes calldata initData = session.actions[0].actionPolicies[0].initData; + abi.decode(initData, (uint16, string, bytes)); + grantNonce++; + lastPolicyInitData = initData; + lastSessionHash = keccak256(abi.encode(session)); + lastGrantIntentHash = keccak256(abi.encode(intent)); + lastGrantCaller = msg.sender; + return RULES_ID; + } + + function executeWithSig(bytes32, bytes calldata cd, OwnerIntent calldata intent, bytes calldata) external { + require(msg.sender == intent.executor, "MockAGW: executor"); + require(intent.execCalldataHash == keccak256(cd), "MockAGW: exec hash"); + require(intent.nonceSeq == getNonce[intent.nonceKey], "MockAGW: nonce"); + getNonce[intent.nonceKey]++; + lastExecIntentHash = keccak256(abi.encode(intent)); + lastExecCalldataHash = keccak256(cd); + + address target = address(bytes20(cd[0:20])); + bytes memory callData = cd[52:]; + if (mode == Mode.OtherEvaluator) { + address other = OTHER_EVALUATOR; + assembly ("memory-safe") { + mstore(add(callData, 68), other) // data + 4 (selector) + 32 (provider) = the evaluator word + } + } + if (mode == Mode.ForeignClient) { + new ForeignCaller().forward(target, callData); + return; + } + _call(target, callData); + if (mode == Mode.TwoJobs) _call(target, callData); + } + + function _call(address target, bytes memory data) internal { + (bool ok, bytes memory ret) = target.call(data); + if (!ok) { + assembly { + revert(add(ret, 0x20), mload(ret)) + } + } + } +} + +/// @dev Makes the call from a different address, so the kernel's `client` is not the AGW. +contract ForeignCaller { + function forward(address target, bytes memory data) external { + (bool ok,) = target.call(data); + require(ok, "ForeignCaller"); + } +} diff --git a/plan/marketplace/contracts/test/8183-tests/mocks/MockAGWFactory.sol b/plan/marketplace/contracts/test/8183-tests/mocks/MockAGWFactory.sol new file mode 100644 index 00000000..6858fea8 --- /dev/null +++ b/plan/marketplace/contracts/test/8183-tests/mocks/MockAGWFactory.sol @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import {OwnerIntent} from "@push-agw/libraries/Types.sol"; +import {MockAGW} from "./MockAGW.sol"; + +/// @notice Answers `isWallet` from a settable map, and — for UniversalMarketplace tests — deploys +/// MockAGW clones at CREATE2 addresses it can predict, mirroring the real factory's rules that +/// the marketplace depends on: explicit index == count, `intent.wallet` == predicted, and the +/// intent presentable only by its executor. It verifies NO signature; the AGW repo's E2E suite +/// runs the real factory. +contract MockAGWFactory { + mapping(address => bool) public isWallet; + mapping(address => uint256) public walletCount; + mapping(address => address) public ownerOf; + /// @notice Misbehaviour switch: deploy at another salt, i.e. not at the address `predictWallet` gave. + bool public misdeploy; + + error IndexMismatch(uint96 expected, uint96 provided); + error IntentWalletMismatch(address expected, address provided); + error ExecutorMismatch(address expected, address actual); + + function setWallet(address account, bool status) external { + isWallet[account] = status; + } + + function setMisdeploy(bool on) external { + misdeploy = on; + } + + function predictWallet(address owner, uint256 index) public view returns (address wallet, bool deployed) { + // forge-lint: disable-next-line(unsafe-typecast) + bytes32 salt = keccak256(abi.encode(owner, uint96(index))); // the real factory's index is a uint96 + bytes32 h = keccak256( + abi.encodePacked( + bytes1(0xff), + address(this), + salt, + keccak256(abi.encodePacked(type(MockAGW).creationCode, abi.encode(owner))) + ) + ); + // forge-lint: disable-next-line(unsafe-typecast) + wallet = address(uint160(uint256(h))); // CREATE2: the address is the hash's low 160 bits + deployed = index < walletCount[owner]; + } + + function deployWalletWithSig(OwnerIntent calldata intent, bytes calldata, string calldata) + external + returns (address wallet) + { + uint96 next = uint96(walletCount[intent.owner]); + if (intent.index != next) revert IndexMismatch(next, intent.index); + (address predicted,) = predictWallet(intent.owner, intent.index); + if (intent.wallet != predicted) revert IntentWalletMismatch(predicted, intent.wallet); + if (msg.sender != intent.owner && msg.sender != intent.executor) { + revert ExecutorMismatch(intent.executor, msg.sender); + } + walletCount[intent.owner] = next + 1; + bytes32 salt = keccak256(abi.encode(intent.owner, intent.index)); + if (misdeploy) salt = keccak256(abi.encode(salt)); + wallet = address(new MockAGW{salt: salt}(intent.owner)); + isWallet[wallet] = true; + ownerOf[wallet] = intent.owner; + } +} diff --git a/plan/marketplace/contracts/test/8183-tests/mocks/MockERC20_6.sol b/plan/marketplace/contracts/test/8183-tests/mocks/MockERC20_6.sol new file mode 100644 index 00000000..5b70eed8 --- /dev/null +++ b/plan/marketplace/contracts/test/8183-tests/mocks/MockERC20_6.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; + +/// @notice 6-decimal test token with open minting. +contract MockERC20_6 is ERC20 { + constructor(string memory name_, string memory symbol_) ERC20(name_, symbol_) {} + + function decimals() public pure override returns (uint8) { + return 6; + } + + function mint(address to, uint256 amount) external { + _mint(to, amount); + } +} diff --git a/plan/marketplace/contracts/test/8183-tests/mocks/MockPRC20Source.sol b/plan/marketplace/contracts/test/8183-tests/mocks/MockPRC20Source.sol new file mode 100644 index 00000000..37b94b55 --- /dev/null +++ b/plan/marketplace/contracts/test/8183-tests/mocks/MockPRC20Source.sol @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; + +/// @notice A PRC20 stand-in: an ERC-20 whose `SOURCE_CHAIN_NAMESPACE()` the test sets. OBSERVER, NOT ORACLE: +/// the namespace and the shape of the answer are inputs; the marketplace's judgement of them is what +/// is under test. +contract MockPRC20Source is ERC20 { + /// @dev How `SOURCE_CHAIN_NAMESPACE()` answers. Namespace: a well-formed string · Reverts · Short: one + /// word · BadOffset: a string head whose offset is not 32 · Overlong: a length past the data. + enum Answer { + Namespace, + Reverts, + Short, + BadOffset, + Overlong + } + + uint8 internal immutable DECIMALS; + string internal namespace; + Answer public answer; + + constructor(string memory name_, string memory namespace_, uint8 decimals_) ERC20(name_, name_) { + namespace = namespace_; + DECIMALS = decimals_; + } + + function setNamespace(string calldata namespace_) external { + namespace = namespace_; + } + + function setAnswer(Answer a) external { + answer = a; + } + + function mint(address to, uint256 amount) external { + _mint(to, amount); + } + + function decimals() public view override returns (uint8) { + return DECIMALS; + } + + // forge-lint: disable-next-line(mixed-case-function) + function SOURCE_CHAIN_NAMESPACE() external view returns (string memory) { + Answer a = answer; + if (a == Answer.Reverts) revert("MockPRC20Source: reverts"); + if (a == Answer.Namespace) return namespace; + bytes memory raw; + if (a == Answer.Short) raw = abi.encode(uint256(7)); + if (a == Answer.BadOffset) raw = abi.encode(uint256(64), uint256(0)); + if (a == Answer.Overlong) raw = abi.encode(uint256(32), uint256(1000)); + assembly ("memory-safe") { + return(add(raw, 32), mload(raw)) + } + } +} diff --git a/plan/marketplace/contracts/test/8183-tests/mocks/MockSmartSession.sol b/plan/marketplace/contracts/test/8183-tests/mocks/MockSmartSession.sol new file mode 100644 index 00000000..53af7549 --- /dev/null +++ b/plan/marketplace/contracts/test/8183-tests/mocks/MockSmartSession.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +/// @notice Answers `isPermissionEnabled` from a settable map. +contract MockSmartSession { + mapping(bytes32 => mapping(address => bool)) internal enabled; + + function setPermission(bytes32 permissionId, address account, bool status) external { + enabled[permissionId][account] = status; + } + + function isPermissionEnabled(bytes32 permissionId, address account) external view returns (bool) { + return enabled[permissionId][account]; + } +} diff --git a/plan/marketplace/contracts/test/8183-tests/mocks/RecordingHook.sol b/plan/marketplace/contracts/test/8183-tests/mocks/RecordingHook.sol new file mode 100644 index 00000000..32bd4624 --- /dev/null +++ b/plan/marketplace/contracts/test/8183-tests/mocks/RecordingHook.sol @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; +import {IERC8183Hook} from "../../../src/agentic-commerce-8183/interfaces/IERC8183Hook.sol"; +import {IAgenticCommerce} from "../../../src/agentic-commerce-8183/interfaces/IAgenticCommerce.sol"; + +/// @notice Observer hook: records every callback and the job status the kernel shows at that moment. +contract RecordingHook is IERC8183Hook { + struct Call { + bool isBefore; + uint256 jobId; + bytes4 selector; + bytes data; + uint8 statusSeen; + } + + Call[] public calls; + + function count() external view returns (uint256) { + return calls.length; + } + + function getCall(uint256 i) external view returns (Call memory) { + return calls[i]; + } + + function beforeAction(uint256 jobId, bytes4 selector, bytes calldata data) external { + _record(true, jobId, selector, data); + } + + function afterAction(uint256 jobId, bytes4 selector, bytes calldata data) external { + _record(false, jobId, selector, data); + } + + function supportsInterface(bytes4 id) external pure returns (bool) { + return id == type(IERC8183Hook).interfaceId || id == type(IERC165).interfaceId; + } + + function _record(bool isBefore, uint256 jobId, bytes4 selector, bytes calldata data) internal { + uint8 status = uint8(IAgenticCommerce(msg.sender).getJob(jobId).status); + calls.push(Call(isBefore, jobId, selector, data, status)); + } +} diff --git a/plan/marketplace/contracts/test/8183-tests/mocks/ReentrantHook.sol b/plan/marketplace/contracts/test/8183-tests/mocks/ReentrantHook.sol new file mode 100644 index 00000000..e582ac1a --- /dev/null +++ b/plan/marketplace/contracts/test/8183-tests/mocks/ReentrantHook.sol @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; +import {IERC8183Hook} from "../../../src/agentic-commerce-8183/interfaces/IERC8183Hook.sol"; + +/// @notice Hook that calls back into the kernel with `payload` and bubbles the revert. +contract ReentrantHook is IERC8183Hook { + bytes public payload; + bool public inAfter; + + function setPayload(bytes calldata p) external { + payload = p; + } + + function setInAfter(bool v) external { + inAfter = v; + } + + function beforeAction(uint256, bytes4, bytes calldata) external { + if (!inAfter) _reenter(); + } + + function afterAction(uint256, bytes4, bytes calldata) external { + if (inAfter) _reenter(); + } + + function supportsInterface(bytes4 id) external pure returns (bool) { + return id == type(IERC8183Hook).interfaceId || id == type(IERC165).interfaceId; + } + + function _reenter() internal { + if (payload.length == 0) return; + (bool ok, bytes memory ret) = msg.sender.call(payload); + if (!ok) { + assembly { + revert(add(ret, 32), mload(ret)) + } + } + } +} diff --git a/plan/marketplace/contracts/test/8183-tests/mocks/RevertingHook.sol b/plan/marketplace/contracts/test/8183-tests/mocks/RevertingHook.sol new file mode 100644 index 00000000..471757b6 --- /dev/null +++ b/plan/marketplace/contracts/test/8183-tests/mocks/RevertingHook.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; +import {IERC8183Hook} from "../../../src/agentic-commerce-8183/interfaces/IERC8183Hook.sol"; + +/// @notice Hook that reverts `HookSaysNo` in the flagged phase. +contract RevertingHook is IERC8183Hook { + error HookSaysNo(); + + bool public revertBefore; + bool public revertAfter; + + function setRevertBefore(bool v) external { + revertBefore = v; + } + + function setRevertAfter(bool v) external { + revertAfter = v; + } + + function beforeAction(uint256, bytes4, bytes calldata) external view { + if (revertBefore) revert HookSaysNo(); + } + + function afterAction(uint256, bytes4, bytes calldata) external view { + if (revertAfter) revert HookSaysNo(); + } + + function supportsInterface(bytes4 id) external pure returns (bool) { + return id == type(IERC8183Hook).interfaceId || id == type(IERC165).interfaceId; + } +} diff --git a/plan/marketplace/contracts/test/8183-tests/mocks/RoutingProbeHook.sol b/plan/marketplace/contracts/test/8183-tests/mocks/RoutingProbeHook.sol new file mode 100644 index 00000000..4313a15c --- /dev/null +++ b/plan/marketplace/contracts/test/8183-tests/mocks/RoutingProbeHook.sol @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import {BaseERC8183Hook} from "../../../src/agentic-commerce-8183/hooks/BaseERC8183Hook.sol"; + +/// @notice Phase-3 concrete hook: records which handler ran and the arguments it decoded. +contract RoutingProbeHook is BaseERC8183Hook { + struct Rec { + string handler; + uint256 jobId; + address caller; + address addrArg; + uint256 uintArg; + bytes32 b32Arg; + bytes optParams; + } + + Rec[] internal recs; + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address kernel_) external initializer { + __BaseERC8183Hook_init(kernel_); + } + + /// @dev Calls the base init outside an initializer — must revert NotInitializing. + function initOutside(address kernel_) external { + __BaseERC8183Hook_init(kernel_); + } + + function count() external view returns (uint256) { + return recs.length; + } + + function rec(uint256 i) external view returns (Rec memory) { + return recs[i]; + } + + function _push(string memory h, uint256 id, address c, address a, uint256 u, bytes32 b, bytes memory o) internal { + recs.push(Rec(h, id, c, a, u, b, o)); + } + + function _preSetProvider(uint256 id, address c, address p, bytes memory o) internal override { + _push("preSetProvider", id, c, p, 0, 0, o); + } + + function _postSetProvider(uint256 id, address c, address p, bytes memory o) internal override { + _push("postSetProvider", id, c, p, 0, 0, o); + } + + function _preSetBudget(uint256 id, address c, uint256 amt, bytes memory o) internal override { + _push("preSetBudget", id, c, address(0), amt, 0, o); + } + + function _postSetBudget(uint256 id, address c, uint256 amt, bytes memory o) internal override { + _push("postSetBudget", id, c, address(0), amt, 0, o); + } + + function _preFund(uint256 id, address c, bytes memory o) internal override { + _push("preFund", id, c, address(0), 0, 0, o); + } + + function _postFund(uint256 id, address c, bytes memory o) internal override { + _push("postFund", id, c, address(0), 0, 0, o); + } + + function _preSubmit(uint256 id, address c, bytes32 d, bytes memory o) internal override { + _push("preSubmit", id, c, address(0), 0, d, o); + } + + function _postSubmit(uint256 id, address c, bytes32 d, bytes memory o) internal override { + _push("postSubmit", id, c, address(0), 0, d, o); + } + + function _preComplete(uint256 id, address c, bytes32 r, bytes memory o) internal override { + _push("preComplete", id, c, address(0), 0, r, o); + } + + function _postComplete(uint256 id, address c, bytes32 r, bytes memory o) internal override { + _push("postComplete", id, c, address(0), 0, r, o); + } + + function _preReject(uint256 id, address c, bytes32 r, bytes memory o) internal override { + _push("preReject", id, c, address(0), 0, r, o); + } + + function _postReject(uint256 id, address c, bytes32 r, bytes memory o) internal override { + _push("postReject", id, c, address(0), 0, r, o); + } +} diff --git a/plan/marketplace/current-baseline.md b/plan/marketplace/current-baseline.md new file mode 100644 index 00000000..482bfdb3 --- /dev/null +++ b/plan/marketplace/current-baseline.md @@ -0,0 +1,58 @@ +# Verified marketplace baseline + +Observed October 20, 2026. Deployment source: `443b4e2dd9ca5dd9ffc8efebdfcecd619dd66c47`, branch `sdk-iteration-v1` in `pushchain/push-chain-core-contracts`. AGW dependency: `ffd567d3e49b2d27c6f50ad36093274dbac3090f`, matching the existing SDK v6 adapter. + +## Live Donut deployment + +RPC `https://evm.donut.rpc.push.org/`, chain ID 42101. [Pinned observations](research/2026-10-20/live-deployment.json): block **24447347**. The address book reports deployment on October 20, final transaction block 24443653; this review independently checked current code/wiring, not every deployment transaction. + +| Component | Address | +| --- | --- | +| Marketplace | `0x9071ebE01B75123A91e88eB6ec4BF163F3fE9BF4` | +| Kernel | `0x977cf1AC973E9eC4332791d531507575006157Ed` | +| Rules hook | `0xDe7A94e510b6C571DE7880d441349689F73A32b3` | +| Rules helper | `0x5b98A8E0df5b918DF76cD2BE84bA7995B39dfd44` | +| JobSpecBuilder library | `0x2de1e3F053b0bBa0cE0C6953144534a0b055f59e` | +| Payment token, pUSDC / `USDC.eth`, 6 decimals | `0x7A58048036206bB898008b5bBDA85697DB1e5d66` | +| Current evaluator, EOA | `0x1afC81396f1bb36F91f74506284952b81e4bd47c` | +| AGW factory | `0xFBBEB6a365178fAaA81A9789a5f64b300c37e5bc` | +| SmartSession engine | `0xf63DC0628fe1B25049FE3E3a3585Ef051CB98c1d` | + +Marketplace reports `version() == "2.0.0"`. Marketplace/kernel are unpaused; the hook is whitelisted; hook/factory/engine/kernel wiring matches the supplied book. Platform and evaluator fees are zero. `MIN_EXPIRY_WINDOW = 300` seconds; `EVALUATOR_GRACE_PERIOD = 3600`. No cards or kernel jobs existed at the pinned observation. + +Supported card destinations: Ethereum Sepolia, Base Sepolia, Arbitrum Sepolia and BSC Testnet. Registered CEA factories/implementations match the book. Four independent EIP-1167/CREATE2 calculations agree with `computeCEA` for a sample predicted AGW. This checks the marketplace's registered derivation, not destination liquidity or current remote factory configuration. + +Proxy implementation/admin slots match the address book. Executable runtimes of all five marketplace-stack components match the pinned build after resolving library linking/self-address and excluding compiler metadata. The matching artifacts all use 1,000 optimizer runs. The README's larger 99,999-run helper/kernel sizes are not the live sizes; see [comparison](research/2026-10-20/runtime-comparison.json). Full bytecode including metadata is not identical, and this is not an audit. + +## Implemented contract behavior + +1. Provider `registerAgentCard` creates one integer-ID card; another registration by that provider reverts. `updateAgentCard` preserves provider, execution chain and active flag, bumps version and clears verification. Verification is a version-specific tag, not an execution gate. +2. A card combines `AgentCard`, `abi.encode(AgentCardRules)` and `abi.encode(JobSpecTemplate)`. `jobType` is a bytes32 hash, not a recoverable string. Full views and an ABI inventory are under [contracts](contracts/). +3. Rules are `assets`, `principalAsset`, `maxGasPerCall`, `allowedCalls`. PRC20 assets are on Push and report the card's destination chain. The principal asset's total is `MARKER_PRINCIPAL`; its per-call cap may be that marker or a nonzero literal. Other asset caps match byte-for-byte. +4. `approve` is allowed with a nonzero literal EQ spender pin and a MAX amount pin. `increaseAllowance` is refused. Transfer recipients must be bound to the user's destination CEA. There is **no owner-approvals array**. +5. `MARKER_WALLET = keccak256("push.marketplace.marker.WALLET")`; `MARKER_PRINCIPAL = keccak256("push.marketplace.marker.PRINCIPAL")`. Cards store markers; signed sessions store resolved addresses/amounts. Public SDK sentinels need not equal these wire values. +6. `previewIntent` and `buildCreateJobCalldata` provide exact intent/calldata. `previewIntent` alone does not perform all `openJob` eligibility checks; SDK preview must also check ranges, pause, version, wallet occupancy and session compatibility. +7. `openJob` accepts an OwnerIntent and the owner's signature, checks content and nonces, deploys/reuses AGW, grants the session, and creates the kernel job. No deposits or escrow. The intent binds card version through the built description's `origin`. `label` is deploy-only cosmetic input outside the signed intent. +8. Deposits and kernel funding are subsequent operations. Provider calls `setBudget`; client funds with `expectedBudget` and exactly 32 bytes `abi.encode(rulesId)` for the interim hook. `providerFee` on the card is a reference price; the kernel only checks the client's supplied expected budget against its current budget. +9. The interim hook proves client is an AGW, permission enabled, and no Funded/Submitted hook-bound job. It does not check agent/provider equality, expiry, criteria, baseline or verdict. Marketplace checks bind provider/expiry when opening, but manual wallet edits and plain kernel jobs require separate consideration at fund. +10. Client or provider may reject an Open job. Only evaluator may reject Funded/Submitted. Cancellation is `reject`, not a separate deployed `cancel` selector. Marketplace `activeJobOf` becomes zero for Rejected; permissions are not revoked automatically. `claimRefund` is unpausable and callable by anyone after the relevant deadline; funds go to the recorded client. + +The marketplace's occupancy includes unexpired Open jobs, unlike the hook's Funded/Submitted-only occupancy. A plain hookless job is outside that hook's accounting. The marketplace kernel is immutable configuration; moving to K-12 on another kernel requires an upgrade/redeploy and hook wiring, not an SDK address substitution. + +## Wire supported by this deployment + +`JobSpec = (reads, checks, logic, allowedMutability, origin, executeBy, failFinalAt)`. + +- `Read`: split namespace/chainId, confirmations, 20-byte target, 4-byte selector, args, output-type codes, field path. +- `Check`: one read index, Evaluation, Operation, int256 target. +- `Logic`: ALL=0 / ANY=1 / AT_LEAST=2, direct check indices and child-logic indices; root index 0. +- `AllowedMutability`: NONE=0 / CLIENT=1 / PROVIDER=2 / BOTH=3, carried without enforcement. +- Limits defined with the schema: 16 reads, 16 checks, 32 logic entries. Builder does not enforce all evaluator semantic limits. Template order: reads, checks, logic, allowedMutability, params. +- `origin = keccak256(abi.encode(marketplace, cardId, cardVersion, principal))`; plain specs use zero. +- Wire `FillSource.CEA` / `TargetSource.CEA` map to SDK `AGENTIC.WALLET` without renaming the ABI. + +## Not implemented here + +K-12 per-job tokens; createJob hooks; mutable criteria negotiation/freezing; automated snapshot/verify/retry; compatible evaluator; verified ratings; recurring jobs; Solana/Push-native cards; non-EVM evaluation reads. There is no evidence that setting the EOA evaluator to the other demo evaluator would work; the repo explicitly documents incompatible kernel/token/hook/wire assumptions. + +The latest linked evaluator source `8059817` changes not only reads/checks but top-level field order, logic nodes and enum ordinals. See [gap W01](analysis/spec-and-contract-gaps.md). Retain separate explicit wire profiles in research; do not silently translate or ship a universal decoder claiming compatibility. diff --git a/plan/marketplace/implementation-plan.md b/plan/marketplace/implementation-plan.md new file mode 100644 index 00000000..ca2fbc4d --- /dev/null +++ b/plan/marketplace/implementation-plan.md @@ -0,0 +1,104 @@ +# Marketplace and job SDK implementation plan + +Planning only, October 20, 2026. Start from existing `feat/agw-sdk-v4` without disturbing its uncommitted AGW error improvements. Keep marketplace delivery separate from AGW release history. This is a proposed implementation sequence; product decisions still open are listed in [questions](questions.md). + +## First delivery boundary + +Target verified Donut marketplace v2 and its own pUSDC kernel, AGW v6 and interim rules hook. Support the four configured EVM testnets. Deliver card discovery/provider management, permission/spec authoring, preview/open, explicit deposits, and the kernel lifecycle with manual evaluator status. Do not advertise mutable criteria, automated verification, K-12, recurring jobs, verified ratings, mainnet or non-EVM cards. + +No `client.evaluation`, `compileCard`, `market.compile`, `start`, `publish`, hash card IDs, public address dump under `CONSTANTS.MARKET`, admin SDK or generic prepare namespace. These were superseded. Public vocabulary goes under `AGENTIC`; helpers go under `PushChain.utils.job` / `PushChain.utils.market`, not under CONSTANTS. + +## Public surface to implement + +| Surface | Target behavior | +| --- | --- | +| `client.market.cards/card` | Count/ID walk or per-provider lookup; full decoded card/version/tags/rating; bounded concurrent reads | +| `client.market.preview` | Exact card-version snapshot, independent CEA match, session + intent + kernel calldata + JobSpec + readable permissions/criteria; no signing/broadcast | +| `client.market.openJob` | Revalidate same plan, authorize exact OwnerIntent, client-submit by dated decision, validate JobOpened and actual wallet/job/rules association, return `{jobId,wallet,rulesId,tx}` | +| `client.market.deposit` | Separate recorded steps with receipts/recovery; exact opened-card snapshot; fee/PC/principal funding only after revised approval design is agreed | +| `client.market.job/activeJob` | Marketplace mappings and occupancy, distinct from kernel/evaluator facts | +| `client.market.agent.register/update/setActive/card` | One provider card, on-chain integer IDs, new version clears verification, immutable provider/chain | +| `client.job.create/setBudget/fund/submit/claimRefund` | Current kernel ABI, correct client/provider identity, exact reviewed expectedBudget, rulesId optParams only with compatible hook | +| `client.job.status/list/watch` | Kernel + hook reads, stable event-derived deliverable where absent in storage, unavailable evaluator facts represented honestly; stop callback and cursor/deduplication | +| `client.job.cancel` | Proposed addition to resolve the decided client-cancel capability; owner atomic reject+revoke for marketplace AGWs if approved; plain clients reject Open jobs directly | +| `client.job.verify` | Deferred/gated until a compatible contract exposes an agreed retry entry point; fail before signing on current EOA deployment | +| `utils.job` | buildJobSpec, buildJobSpecTemplate, encode/decode/describe/previewJobSpec; pure except explicit paid preview | +| `utils.market` | validate/encode/decodeAgentCardRules using deployed 4-field shape, v6 pins and published markers | +| `AGENTIC` | Preserve WALLET/PRESETS; add PRINCIPAL and JOB EVALUATION/OPERATION/LOGIC/ALLOWED_MUTABILITY vocabulary. Per-chain JOB.ADDRESS is the page 7 exception to internal deployment constants; confirm EOA evaluator representation. No public encoder-context or limit dumps. | + +Every write follows existing UniversalTxResponse and progress-hook conventions. Reads and previews are available in read-only mode where no paid reads are requested. MarketError / JobError / JobSpecError need additive typed codes and decoded causes; do not force new codes into the current closed AgenticErrorCode union with casts. + +## Module shape and reuse + +Proposed new directories: `packages/core/src/lib/market`, `job`, and `job-spec`. Keep wire encoders, on-chain reads, transaction composition and public authoring normalization separate. Add namespace integration in `push-chain/push-chain.ts`, helper exposure in `utils.ts`, and exports in the package entry points. Do not duplicate the whole orchestrator or AGW backend. + +| Existing source | Reuse / qualification | +| --- | --- | +| `agentic/contracts/{donut-v6,v6}.ts`, `deployments.ts`, ABI snapshots | Same AGW generation and verified reader; add an internal marketplace deployment profile with kernel/hook/token/evaluator capabilities and source pins | +| `agentic/codec/{session,universal,abi-layout,pins,ids}.ts` | SessionWire, canonical envelope, static tuple/fixed-array paths, v6 EQ/MAX pins and hashes. Card markers need a separate unresolved representation; publicRule normalization resolves wallet values too early for stored templates. | +| `agentic/runtime.ts`, `context.ts`, `reads/*`, `management/common.ts` | Signer Push identity versus execution wallet, snapshot reads, transaction/error/progress conventions. Add typed signing narrowly; external ERC-1271/home-chain semantics need independent acceptance. | +| `agentic/response.ts`, core transaction response/tracker | Preserve signer origin, actual sender, hashes, wait/replay and decoded errors. Do not claim relayer is owner or AGW is provider. | +| `universal/signer/*`, `universal.signTypedData` | Existing EIP-712 facility; capability-check signer before prompting. Factory domain includes signer home chain, factory address and Push-chain salt. Do not rebuild a generic EIP-712 domain from guesses. | +| `orchestrator/cea-utils.ts`, PRC20 metadata/source helpers, registry | Independent CEA derivation and exact source-token identity. PRC20 on Push and destination token address are distinct. Missing route stays explicit. | +| `read-state/read-params.ts`, query encoders/result shapes, `prepareRead` | Reuse logical parsing/ABI data; existing async prepared request is not the pure JobSpec read shape. Add the agreed adapter without replacing read/prepareRead or hiding fee/height preflight inside pure builders. | +| Existing AGW E2E runner/local harness conventions | New opt-in marketplace group, actual receipt/event evidence, separate unfunded/fork/funded reports; default runner selection remains intentional | + +## Phase 1 — freeze profiles, types and ABI bindings + +Import verified ABIs including all 40 errors from the error library (marketplace ABI alone omits helper errors). Register only the supplied deployment; fail unsupported networks before signatures. Pin exact JobSpec/Template tuple definitions and enum ordinals for deployed v2. Keep the linked evaluator schema as a distinct comparison profile, not an automatic decoder fallback. Canonical public types retain bigint IDs/hashes and lossless selector/word positions; optional metadata supplies names without inventing them. + +Acceptance: imports/declarations, selector/event/error vectors, deployment wiring/capability checks, no legacy names accidentally exported, unsupported signer/network failures before signature. + +## Phase 2 — card rules and JobSpec authoring + +Implement deployed AgentCardRules including principal marker caps, fixed/nonprincipal caps, WALLET/PRINCIPAL pins, approved spender literals and amount maximums. Preserve ordered assets/calls/pins exactly. Validate duplicate/overlapping alternatives and contract ceilings. Keep intended on-chain behavior and SDK validation differences explicit. + +Implement output-layout type codes from ABI (including nested tuples/arrays), field paths, signed targets, tree validation/flattening with higher child indices, template fills and bounded params. ABI encode/decode must be canonical. Decode known card templates/jobs contextually; the convenience decoder must validate shape and canonical re-encoding and reject ambiguous/unsupported inputs. ABI bytes are not a self-describing version tag. + +Add the pure logical-read preparation form agreed for W08. Preserve placeholder location/ABI metadata so an address sentinel can become a zero word plus a fill record; never pass the sentinel directly to viem's address encoder or infer holes from all zero-valued arguments. Pure encoding accepts verified deterministic token data; network-dependent resolution stays explicit. + +Describe exact permissions, alternatives, amount units, gas, expiry and every criteria check. Do not turn a preview with missing baseline into a successful NUMBER/PERCENTAGE result. Preview using universal reads incurs explicit fees; reuse the supported request client path. Defer optional free-RPC fallback until semantics are agreed. Keep EVM-only evaluation read claims for this wire. + +Acceptance: Solidity↔TypeScript vectors from the pinned builder/decoder, encode→decode→encode equality, template fill/PRINCIPAL_BPS rounding, deeply nested logic/ABI returns, bounds/overflow/negative targets, no unresolved placeholders in complete specs, named errors, descriptive output faithful to OR/AT_LEAST behavior. Cross-profile payloads must fail closed. + +## Phase 3 — card reads/provider writes + +Implement all discovery and provider methods, using agentCardOf for provider lookup and count/getAgentCard for enumeration. Keep consistent block reads, bounded concurrency and cancellation for large walks. Preserve disabled/inactive distinctions, version and verification resets. Registration/update validate locally and simulate actual contract behavior before sending. Reject unsupported payment tokens explicitly. + +Metadata is untrusted optional display content: hash-check fetched bytes, retain raw jobType/selector, and do not change permissions from metadata. No indexer or hosting service is implied by publishing a metadata URI. + +Acceptance: real local contracts for registration, duplicate provider, update immutability, stale versions, inactive/disabled and verified tags, correct event-derived IDs, read-only client behavior and unknown ID/provider results. + +## Phase 4 — preview, intent, signing and opening + +Take one card/config snapshot. Derive the connected **owner's** wallet index even when another execution context is present. Obtain destination CEA independently and compare computeCEA. Resolve markers into a v6 session, preserving all constraints and matching actual helper checks. Read nonces/lane/deadline, obtain previewIntent and buildCreateJobCalldata, and independently verify sessionHash/execCalldataHash/origin. Check all openJob eligibility conditions, not just previewIntent success. + +Before signing, re-read current version, configuration, ownership, wallet slot/occupancy and nonces. If any signed content changes, return STALE_PLAN for user review; never silently produce a new plan. Label is outside the signed intent and must be described as cosmetic. Validate signer typed-data support/home-chain identity, EOA and ERC-1271 flows. Use the dated client-submission default; relay remains a future transport until an actual service is supplied. + +After receipt, verify emitted wallet, card version, principal, rules ID, job ID and actual kernel/AGW association. Preserve submitted hash if receipt lookup fails. No duplicate opening on retry; recover by receipt/events. OwnerIntent authorization is one signature, while submitting a transaction can require another signing interaction; document the verified UX. + +Acceptance: fresh/existing wallet, index race, parallel plans, stale card/config/nonces, signature replay, tampered calldata/spec/session/CEA, native owner and external EVM UEA, unsupported signer, user rejection, receipt failure/recovery. Fork tests must use real AGW signatures, not only MockAGW. + +## Phase 5 — kernel lifecycle and historical deposits + +Create plain jobs through the connected ordinary account or AGW owner door. Provider calls go through provider identity. Fund composes token allowance plus exact-budget funding atomically for AGW, with no sequential fallback disguised as atomic success. The interim hook expects exactly rulesId; no speculative specHash payload. Keep allowance/funding distinction from the wallet's automatic **gateway** approval. + +Market deposits must use the **opened version** and original principal, recovered from the validated plan or verified historical source/events/transaction input. Do not use today's mutated card. Separate principal, fee and PC assets, combine repeated token requirements correctly, quote gas and routes explicitly, and report partial progress/hashes so resuming does not pay every step again. Revise obsolete approval fields before implementing them. “Any account can transfer funds” does not grant it owner authority for wallet operations. + +Implement status/list/watch with kernel state, hook binding and explicitly unavailable evaluator state on today's deployment. Recover deliverable from JobSubmitted where kernel storage lacks it. Deduplicate logs, cleanly unsubscribe, resume from a cursor, and re-read status after gaps. Refund goes to recorded client even if a third party triggers claimRefund. Never pausable by an SDK convenience guard when the kernel allows it. + +If approved, client cancel on an AGW uses one owner batch: reject Open job + revoke that job's rulesId. Fork evidence shows existing v6 permits this. Check current permission/status and protect against races; handle already-revoked permissions without revoking unrelated grants. Provider/evaluator rejection cannot claim owner cleanup it lacks authority to perform. Existing grants after earlier jobs can cause AMBIGUOUS_RULE; reopening must not silently pick or widen one. + +Acceptance: fixed reviewed budget versus re-quote, same/different fee/principal token, zero budgets (kernel allows free jobs), insufficiency/allowance, hook payload shape, plain/AGW identity, cancel cleanup/rollback, card update between open/deposit, interrupted deposit resumption, refund while paused, grace boundaries, terminal events/replay, existing overlapping grants. + +## Phase 6 — evaluation delivery after alignment + +Require a compatible deployed hook/evaluator and a single canonical wire before adding baselines, prefund, automatic submit→verify and retry. Bind job context to kernel/chain/evaluator configuration. Shared Solidity/SDK vectors must cover enum values as well as field order. If mutability is approved, fund must atomically commit expectedSpecHash/revision and budget. Current 32-byte interim payload cannot provide that. + +Tests include attested reads, exact baseline/end heights, UNKNOWN/INCONCLUSIVE, percentage zero denominator, owner checkpoints, duplicate/late callbacks, retries, fee shortfalls and settlement/refunds. Do not infer automatic behavior from a zero-code EOA evaluator or an unrelated demo stack. + +## Delivery and validation order + +Suggested PR sequence: (1) profile/types/codecs + authoring helpers, (2) card/provider namespace, (3) preview/open + signing/receipts, (4) job lifecycle and agreed deposit/cancel behavior, (5) documentation/examples/package validation, (6) automatic evaluation only after compatible contract delivery. Independent layers may progress while the specific product questions are resolved. + +Run focused meaningful unit vectors and pinned real-contract tests per phase; then build/typechecks, consumer examples and CJS/ESM declaration/API checks. Add funded Donut execution only for the completed public path, as a separate opt-in acceptance stage. The research tests in this folder establish current contract behavior; they are not passing tests for SDK features that have not been written. diff --git a/plan/marketplace/notion/2-universal-marketplace.md b/plan/marketplace/notion/2-universal-marketplace.md new file mode 100644 index 00000000..cd42f682 --- /dev/null +++ b/plan/marketplace/notion/2-universal-marketplace.md @@ -0,0 +1,195 @@ +# 2. Universal Marketplace + + + +# 0. Before anything else: the marketplace breaks when the AGW redeploys + +**What happens.** The AGW is moving to multi-asset rules (`assets: AssetCap[]`, `maxGasPerCall`; [1. AGW Contract Changes (nomenclature standard + change set)](1%20AGW%20Contract%20Changes%20(nomenclature%20standard%20+%20ch%203e9188aea7f4813aa31fc95ceb4e684d.md) section 4c). The marketplace still carries the old single-asset shape in two places: the card's rule terms (`RulesCardTerms { asset, maxPCPerCall, ... }`) and a hand-copied mirror of the AGW's `UniversalTerms` in `interfaces/external/IAGW.sol`. Its rules check compares the signed session field by field against that shape. + +**What breaks.** The day the new AGW is on Donut, every `openJob` fails at `grantRulesWithSig`: the session the marketplace accepted is not one the wallet will store. + +**Fix.** Item 1 in section 4 and the diff in 4b, shipped in the same window as the AGW. The rules helper is not upgradeable, so this is a redeploy of the helper plus a marketplace upgrade pointing at it. Same rule as page 1 section 0: import the AGW's types from its package instead of copying them, so the next struct change fails the build and not `openJob`. + +# 1. What the marketplace is, in one paragraph + +An agent lists what it will do, under which rules, judged how (an agent card: listing, rules, job spec template). A user picks a card, sees it in words, signs once; `openJob` deploys the user's agentic wallet if needed, grants it exactly the card's rules bound to this job, and creates the 8183 job with the wallet as client and the criteria built from the card's template. The marketplace moves no funds and holds none: the user deposits into the wallet from any chain, the provider prices with `setBudget`, the wallet funds with `fund`, the agent acts within the rules, the evaluator rules ([3. 8183 (job kernel and hook)](3%208183%20(job%20kernel%20and%20hook)%203e9188aea7f48188a838c3a740d8c858.md), [4. Universal Evaluation](4%20Universal%20Evaluation%203e9188aea7f4817bb03ef4c78c883f8b.md)). Phase 2 (users post, agents bid) is a separate proposal: [Proposal: Open Jobs and Budget Proposals for ERC-8183](https://app.notion.com/p/Proposal-Open-Jobs-and-Budget-Proposals-for-ERC-8183-3f4188aea7f481cdad84fdd7a446ab7b?pvs=21). + +# 2. Decisions + +| # | Decision | Outcome | +| --- | --- | --- | +| M1 | Scope of the one call | **Deploy or reuse the wallet, grant the rules, create the job. Nothing else.** No funds move, no approvals run, no escrow is touched. Funding is a plain transfer to the wallet from any chain, later. The job is Open with budget 0 when the call returns. (2026-10-01, matches the build.) | +| M2 | One signature | **The AGW's `OwnerIntent`**, signed once under the factory's EIP-712 domain with the signer's home chain id, presentable only by the marketplace (`intent.executor`). The factory and the wallet verify the owner; the marketplace mirrors the checks for early named errors. Works for a Push EOA owner too. Replaces the three WithSig variants once planned on page 1. | +| M3 | Criteria | **Built on-chain from the card's stored template** (`JobSpecBuilder`), so a relayer or SDK cannot swap in easier criteria, and the result sits inside the `createJob` calldata the owner signs. `reads` (what to look at), `checks` (how to compare), `logic` (how checks combine; was `nodes`). The template is stored as given and not judged; the verified tag is the review; the SDK renders every check in words before the signature. | +| M4 | Criteria mutability | **`AllowedMutability allowedMutability` on `JobSpec` and on the template** (NONE, CLIENT, PROVIDER, BOTH; named `Mutability mutability` until 2026-10-12). `PROVIDER` means a whole replacement spec may be proposed at `setBudget`; the evaluator refuses changes to `origin` and to `allowedMutability` itself; the client accepts by funding. Shared wire format with the evaluator; lands in both repos together. (2026-10-06, 2026-10-07) | +| M5 | Rules on the card | **Multi-asset.** `AgentCardRules { assets[], principalAsset, maxGasPerCall, allowedCalls, approvals }`. The rules check binds the principal asset's total to the job's principal and compares every other cap byte for byte. Follows the AGW decision of 2026-10-05. | +| M6 | Payment token | **`Card.paymentToken`, inherited by the job.** Requires the kernel to take the token at `createJob` (K-12 on [3. 8183 (job kernel and hook)](3%208183%20(job%20kernel%20and%20hook)%203e9188aea7f48188a838c3a740d8c858.md)); until then cards are priced in the kernel's one token. (2026-10-09) | +| M7 | Approvals | **The owner's, never the agent's.** The card lists the ERC-20 allowances the job needs on the execution chain; the helper rejects `approve` and `increaseAllowance` in any agent allow-list (the universal rulebook pins only the receiving address, not the spender). The owner makes them through the wallet's owner door, a cross-chain call that must land before the agent's first call; the SDK bundles them into the deposit. Nothing on-chain verifies they ran. v1. | +| M8 | Destination account check | **Keep, as `computeCEA`.** The signed rule names the account on the destination chain that must receive what the agent deposits and that the criteria read. The marketplace derives that address itself (fixed formula over the wallet address plus the chain's CEA factory and proxy implementation, registered by the admin) and refuses a rule naming anyone else's. Later this check may move into URP at grant time, covering every grant; URP is over the size limit now. The rule field stays `expectedCEA`. | +| M9 | Session fields the marketplace does not compare | **No marketplace code.** Validator, policy address, action target and selector, and the extra policy lists are pinned by the AGW at `grantRules`, which runs before any marketplace state write. One line in the repo doc closes the team's open question. | +| M10 | Per-chain pause | **Removed.** It only gated `openJob` for one destination during a CEA rotation, which already fails closed (`ExpectedCEAMismatch`). The marketplace owns no per-chain switch; `pause()` and `unpause()` are its only pause. `setCEADeployment(chainHash, 0, 0)` may clear a chain to `ChainNotSupported`. | +| M11 | Hook and evaluator | **Separate contracts.** The rules hook maps job to wallet rules and exists only on Push; the evaluator is directly callable so a developer with their own hook or no AGW can use it. (2026-10-06) | +| M12 | Provider identity and rating | **Open registration, no stake, `getAgentRating(agent)` placeholder** returning the admin's dummy value until `VerifiedRatings.sol` is wired. No registration fee exists in the code; the kernel's `platformFee` at `complete` is the only fee. | +| M13 | The noun | **`AgentCard`, full word everywhere in code.** The stack already says "agent card"; A2A's Agent Card is the same family of object (ours carries rules and criteria and is on-chain), one doc line states the difference. `Listing` rejected. `cardId` stays as the short id. | + +# 3. Rename map (current to proposed) + +| Area | Today | Proposed | +| --- | --- | --- | +| Inherited names (SmartSession, AGW) | `Session`, `session`, `SessionContext`, `OwnerIntent`, `IntentSessionMismatch`, `UniversalTerms` | unchanged: the AGW's own ABI says `grantRules(Session session)`, so the marketplace says `session` too | +| Entry point | `startJob`, `StartJobParams`, `JobStarted` | `openJob`, `OpenJobParams`, `JobOpened` (the job is Open, not started; start is `fund`) | +| Helper contract | `UniversalMarketplaceTerms`, `TERMS()`, `InitParams.terms` | `UniversalMarketplaceRules`, `RULES()`, `InitParams.rules` | +| Card rules | `RulesCardTerms`, `rulesTerms`, `_rulesTerms`, `validateRulesTerms`, `verifySession` | `AgentCardRules`, `rules`, `_agentCardRules`, `validateAgentCardRules`, `checkRulesMatchCard` | +| Criteria | `evaluation`, `_evaluations`, `evaluationHash`, `EvaluationTemplate` | `jobSpecTemplate`, `_jobSpecTemplates`, `jobSpecHash`, `JobSpecTemplate` (prose: "criteria"; one noun with the evaluator's `JobSpec`, decided 2026-10-12) | +| Card functions | `registerCard`, `modifyAgentCard`, `setCardActive`, `adminDisableCard`, `verifyAgentCard`, `revokeAgentCardVerification`, `getCard` | `registerAgentCard`, `updateAgentCard`, `setAgentCardActive`, `disableAgentCard`, `verifyAgentCard`, `revokeAgentCardVerification`, `getAgentCard` | +| Card views and types | `isCardVerified`, `isCardAdminDisabled`, `cardVersion`, `cardCount`, `CardView` | `isAgentCardVerified`, `isAgentCardDisabled`, `agentCardVersion`, `agentCardCount`, `AgentCardView` | +| Card events | `CardRegistered`, `CardModified`, `CardStatusChanged`, `CardDisabledByAdmin`, `CardVerified`, `CardVerificationRevoked` | `AgentCardRegistered`, `AgentCardUpdated`, `AgentCardStatusChanged`, `AgentCardDisabled`, `AgentCardVerified`, `AgentCardVerificationRevoked` | +| Card errors | `CardInactive`, `CardAdminDisabled`, `CardVersionMismatch`, `InvalidCard(reason)`, `CardIdentityImmutable` | `AgentCardInactive`, `AgentCardDisabled`, `AgentCardVersionMismatch`, `InvalidAgentCard(reason)`, `AgentCardIdentityImmutable` | +| Fee | `fee` | `providerFee` (the kernel's `platformFee` is the other fee) | +| Live job | `isAGWFree(agw) returns (bool)`, `lastJobOf(agw)`, `AGWBusy(agw, jobId)` | `activeJobOf(agw) returns (uint256 jobId)`, `WalletHasActiveJob(agw, jobId)` | +| Destination account | `expectedCEAOf(agw, chainHash)` | `computeCEA(agw, chainHash)` (mirrors core's `computeUEA`; the rule field stays `expectedCEA`) | +| Per-chain pause | `setUniversalPaused`, `isUniversalPaused`, `UniversalChainPaused`, `ChainPaused` error | removed (M10) | +| Rules check errors | `PCCapMismatch`, `CapMismatch` | `GasCapMismatch`, `PrincipalCapMismatch` | +| Set-once wiring | `pushChainHash()` | `PUSH_CHAIN_HASH()` (URP has the same lowercase name; align on its next redeploy) | +| Hook views | `rulesOf(jobId)` returning `{agw, rulesId}`, `isAGWBusy`, `liveJobOf` | `rulesOfJob(jobId)`, `agwOfJob(jobId)`, `activeJobOf(agw)`: one spelling with the marketplace | +| Criteria tree | `Node`, `NodeKind`, `nodes`, `MAX_NODES` | `Logic`, `LogicKind`, `logic`, `MAX_LOGIC` | +| Chain field | `AgentCard.chainNamespace` full CAIP-2; `Read.chainNamespace` namespace only with `chainId` beside it | unchanged; rule written once: a single field naming a chain is the full CAIP-2 string, the split form appears only where `chainId` sits beside it | +| Layout | `docs/universalmarketplace/README.md`, unnumbered tests, hand-copied AGW mirrors in `interfaces/external/` | deferred; AGW types imported, not copied (section 0) | + +# 4. Structural changes that ride along with the rename + +1. **Multi-asset card rules** (M5). `AgentCardRules { AssetCap[] assets; uint8 principalAsset; uint256 maxGasPerCall; AllowedCall[] allowedCalls; Approval[] approvals; }`. `checkRulesMatchCard` applies total equals principal to `assets[principalAsset]` and byte-equal caps to the rest. Replace the `UniversalTerms` mirror with the AGW's new struct in the same change. Blocks the AGW redeploy (section 0). +2. **Mutability on the criteria** (M4). `AllowedMutability allowedMutability` on `JobSpec` and `JobSpecTemplate`, copied by the builder. Field order decided 2026-10-12: `reads, checks, logic, allowedMutability, origin, executeBy, failFinalAt`; the template is the first four fields plus `params`, so `JobSpecBuilder` copies four and appends `origin` and timing. Supersedes both this repo's order and the Trust Layer page's. Implementation lands in `JobSpecTypes.sol` with the evaluator team. +3. **`Card.paymentToken`** (M6), after K-12 lands on the kernel. `providerFee` is read in it. +4. **`activeJobOf`** replaces `isAGWFree` and `lastJobOf`; the hook adopts the same view and the marketplace's two job views. +5. **Per-chain pause removed** (M10). Storage slot 14 becomes a reserved gap entry. +6. **`getAgentRating(agent)`** placeholder (M12). **`version()`** added. **`PUSH_CHAIN_HASH()`** uppercase. +7. **Admin surface stays out of the SDK**: `verifyAgentCard`, `disableAgentCard`, `setCEADeployment`, `setHook`, `setEvaluator`, `pause`, `unpause`. + +# 4b. Contract surface, as a diff + +Read `+` as added, `-` as removed, `~` as changed in place, `=` as unchanged. Names are the post-rename names. Storage is append-only; renames are labels only. + +**UniversalMarketplace** + +```diff +// cards +~ registerAgentCard(AgentCard c, bytes rules, bytes jobSpecTemplate) returns (uint256 cardId) // was registerCard(c, rulesTerms, evaluation); reverts AgentCardAlreadyRegistered(provider) on a second card (decided 2026-10-12) +~ updateAgentCard(uint256 cardId, AgentCard c, bytes rules, bytes jobSpecTemplate) // was modifyAgentCard +~ setAgentCardActive(uint256 cardId, bool active) // was setCardActive +~ disableAgentCard(uint256 cardId) // was adminDisableCard; admin += verifyAgentCard(uint256 cardId, uint256 version), revokeAgentCardVerification(uint256 cardId) // admin +~ getAgentCard(uint256 cardId) view returns (AgentCardView) // was getCard +~ isAgentCardVerified, isAgentCardDisabled, agentCardVersion, agentCardCount // was isCardVerified, isCardAdminDisabled, cardVersion, cardCount ++ getAgentRating(address agent) view returns (uint256) // placeholder; TAP or VerifiedRatings later + +// jobs +~ openJob(OpenJobParams p) returns (uint256 jobId, address agw, bytes32 rulesId) // was startJob(StartJobParams) +~ activeJobOf(address agw) view returns (uint256 jobId) // replaces isAGWFree and lastJobOf; 0 = free += cardOfJob, agwOfJob, rulesOfJob +~ computeCEA(address agw, bytes32 chainHash) view returns (address) // was expectedCEAOf += buildCreateJobCalldata(uint256 cardId, address owner, uint96 index, JobInputs job) view returns (bytes32 mode, bytes executionCalldata) += previewIntent(IntentRequest r, Session s) view returns (OwnerIntent) + +// admin += setHook, setEvaluator, setCEADeployment, pause, unpause +~ setCEADeployment(chainHash, 0, 0) allowed: clears the chain to ChainNotSupported +- setUniversalPaused(bytes32 chainHash, bool paused), isUniversalPaused(bytes32) + +// views (wiring) += AGW_FACTORY(), KERNEL(), hook(), evaluator() +~ RULES() returns (IUniversalMarketplaceRules) // was TERMS() +~ PUSH_CHAIN_HASH() returns (bytes32) // was pushChainHash() ++ version() returns (string) + +// events +~ AgentCardRegistered(cardId, provider, jobType, chainNamespace, rulesHash, jobSpecHash, metadataHash, providerFee) +~ AgentCardUpdated(cardId, version, rulesHash, jobSpecHash, metadataHash, providerFee) +~ AgentCardStatusChanged, AgentCardDisabled, AgentCardVerified, AgentCardVerificationRevoked +~ JobOpened(cardId, owner, agw, jobId, rulesId, principal, cardVersion) // was JobStarted += HookUpdated, EvaluatorUpdated, CEADeploymentSet +- UniversalChainPaused + +// storage (slots never move) += 0 AGW_FACTORY, 1 KERNEL, 2 hook, 3 evaluator, 4 PUSH_CHAIN_HASH, 5 RULES, 6 agentCardCount, 7 _cards, 8 _agentCardRules, 9 _jobSpecTemplates, += 10 agentCardVersion, 11 isAgentCardVerified, 12 isAgentCardDisabled, 13 ceaDeployment, 15 activeJobOf (was lastJobOf), 16 cardOfJob, 17 agwOfJob, 18 rulesOfJob +~ 14 reserved (was isUniversalPaused) ++ _agentRating appended after the gap start; __gap shrinks by one +``` + +**Types** (`libraries/Types.sol`) + +```diff +~ struct AgentCard { address provider; bytes32 jobType; string metadataURI; bytes32 metadataHash; string chainNamespace; +~ uint256 providerFee; address paymentToken; // was fee; paymentToken NEW with K-12 +~ uint256 principalMin; uint256 principalMax; uint32 minDuration; uint32 maxDuration; uint32 minExecuteWindow; uint32 settleWindow; bool active; } +- struct RulesCardTerms { address asset; uint256 maxPCPerCall; AllowedCall[] allowedCalls; Approval[] approvals; } ++ struct AgentCardRules { AssetCap[] assets; uint8 principalAsset; uint256 maxGasPerCall; AllowedCall[] allowedCalls; Approval[] approvals; } ++ struct AssetCap { address token; uint256 maxPerCall; uint256 maxTotal; } // imported from the AGW package, not copied += struct Approval { address token; address spender; bool capIsPrincipal; uint256 cap; } +~ struct OpenJobParams { uint256 cardId; uint256 cardVersion; JobInputs job; Session session; OwnerIntent intent; bytes sig; string label; } // was StartJobParams +~ struct AgentCardView { AgentCard card; bytes rules; bytes jobSpecTemplate; uint256 version; bool verified; bool disabled; } // was CardView +~ struct JobSpecTemplate { ReadTemplate[] reads; CheckTemplate[] checks; Logic[] logic; AllowedMutability allowedMutability; ParamBounds[] params; } // was EvaluationTemplate with nodes; CriteriaTemplate in the morning draft; first four fields match JobSpec += JobInputs, IntentRequest, InitParams (field terms -> rules), SessionContext, Fill, ReadTemplate, CheckTemplate, ParamBounds +``` + +**JobSpecTypes** (shared wire format with the hook and the evaluator) + +```diff +~ enum Evaluation { BOOLEAN, COMPARE, NUMBER, PERCENTAGE } // was EvalType { BOOL, CMP, NUM, PCT }; SDK constant names (2026-10-12) +~ enum Operation { EQUAL, NOT_EQUAL, GREATER_THAN, GREATER_OR_EQUAL, LESS_THAN, LESS_OR_EQUAL } // was Op +~ enum LogicKind { ALL, ANY, AT_LEAST } // was NodeKind; CHECK leaf dropped (PROPOSED) ++ enum AllowedMutability { NONE, CLIENT, PROVIDER, BOTH } +~ struct Check { uint8 read; Evaluation evaluation; Operation operation; int256 target; } +~ struct Logic { LogicKind kind; uint8[] checks; uint8[] children; uint8 k; } // was Node; no leaf nodes +~ struct JobSpec { Read[] reads; Check[] checks; Logic[] logic; AllowedMutability allowedMutability; bytes32 origin; uint64 executeBy; uint64 failFinalAt; } +~ // order decided 2026-10-12: content, then allowedMutability and origin, then timing (section 4, item 2) +~ MAX_LOGIC = 32 // was MAX_NODES += Read, T_* codes, MAX_READS, MAX_CHECKS +``` + +**UniversalMarketplaceRules** (was UniversalMarketplaceTerms) + +```diff +~ validateAgentCardRules(bytes rules) pure returns (address[] tokens) // was validateRulesTerms returning one asset +~ checks: 1..MAX_ASSETS assets, principalAsset in range, no duplicate token, 1..32 allowed calls, no duplicate (target, selector), +~ no approve or increaseAllowance, transfer and transferFrom pin their recipient, at most 8 approvals, approval shape, no duplicate (token, spender) +~ checkRulesMatchCard(bytes cardRules, Session session, SessionContext ctx) pure // was verifySession +~ checks, in order: agent == provider; one action; one policy; envelope chain == card chain; +~ assets[] equal to the card's with assets[principalAsset].maxTotal == principal and maxPerCall <= principal; +~ maxGasPerCall equal; allowedCalls byte-equal; validUntil == expiredAt; expectedCEA == computeCEA(agw, chainHash) +~ errors: AssetMismatch, GasCapMismatch (was PCCapMismatch), ActionsMismatch, PrincipalCapMismatch (was CapMismatch), ExpiryMismatch, ExpectedCEAMismatch += MAX_ALLOWED_CALLS = 32, MAX_APPROVALS = 8; + MAX_ASSETS = 8 (imported from the AGW) +``` + +**RulesBindingHook** (interim; extended by the evaluator track) + +```diff += beforeAction(fund): optParams == abi.encode(rulesId); client is a factory AGW; rules live on the engine; no live job; records the binding; emits RulesBound ++ afterAction(setBudget): decode the optional JobSpec proposal; check allowedMutability against the caller; hand to the evaluator or revert ++ afterAction(fund): freeze the standing JobSpec; trigger the baseline (prefunded by the client) ++ afterAction(submit): evaluator.verify(jobId) +~ rulesOfJob(jobId) view returns (bytes32), agwOfJob(jobId) view returns (address) // was rulesOf(jobId) returning a struct +~ activeJobOf(agw) view returns (uint256) // was isAGWBusy and liveJobOf +- the binder role (rules expire by validUntil); recomputing a criteria hash (criteria are built on-chain); refusing submit before the baseline (the evaluator returns inconclusive) +``` + +**Not in this change set** (belongs elsewhere, listed so nobody looks for it here): the kernel's per-job payment token (K-12, [3. 8183 (job kernel and hook)](3%208183%20(job%20kernel%20and%20hook)%203e9188aea7f48188a838c3a740d8c858.md)), the evaluator, Solana and native (Push-side) cards, the `EvaluatorGateway` for jobs on other chains. + +# 5. Open for review on this page + +1. Client-side cancellation of an Open unfunded job. Decided 2026-10-12: enforced at the contract level, the client can cancel on the kernel. What is still open is the AGW side: on cancel the hook must release the wallet's rules so the wallet is not blocked until `expiredAt`. Research tagged on [3. 8183 (job kernel and hook)](3%208183%20(job%20kernel%20and%20hook)%203e9188aea7f48188a838c3a740d8c858.md) (open item 2). +2. One card per provider. Decided 2026-10-12: enforced on-chain, `registerAgentCard` reverts `AgentCardAlreadyRegistered(provider)`; a provider changes its offer through `updateAgentCard`. `agent.card()` on page 6 reads the one card. +3. `JobSpec` field order and `origin`: decided 2026-10-12 (section 4, item 2); pending implementation in `JobSpecTypes.sol`. +4. Recurring jobs (a 7 or 15 day job renewing until cancelled) against the one-live-job rule: a renewal is a new job that must start the moment the old one completes, or the rule needs a successor slot. Research, with the fee design (tagged 2026-10-12). +5. Size: 21.3 KB today with 3.3 KB to the EIP-170 limit; multi-asset rules add code, another split may be needed. +6. Anything in the rename map or the diff that should stay as is. \ No newline at end of file diff --git a/plan/marketplace/notion/3-8183-job-kernel-and-hook.md b/plan/marketplace/notion/3-8183-job-kernel-and-hook.md new file mode 100644 index 00000000..3395c9e1 --- /dev/null +++ b/plan/marketplace/notion/3-8183-job-kernel-and-hook.md @@ -0,0 +1,87 @@ +# 3. 8183 (job kernel and hook) + + + +# 1. What exists (verified in source, 2026-10-07) + +**Kernel `AgenticCommerce.sol`.** Base V3 shape with the K-01 to K-11 changes. + +- Transparent proxy. One `paymentToken` set at `initialize` (changes with K-12, section 4). `platformFee` and `evaluatorFee` in bps, start at 0; `platformFee` goes to the treasury at `complete`, the evaluator fee to whoever calls `complete`. +- Hookable: `setProvider`, `setBudget`, `fund`, `submit`, `complete`, `reject`, each with `beforeAction` and `afterAction` and an `optParams` payload. `createJob` is hookable on the Push kernel (decided 2026-10-12, reverses K-10 for this kernel only; kernels on other chains are not expected to hook it, so the design must not depend on it). Not hookable: `claimRefund`. +- `createJob(provider, evaluator, expiredAt, description, hook)`: evaluator non-zero, hook whitelisted and ERC-165 checked, provider may be zero (bid mode) or set. The job is Open with budget 0. +- `setBudget(jobId, amount, optParams)`: provider only, re-callable while Open. `fund(jobId, expectedBudget, optParams)`: client only, provider must be set, `expectedBudget` must equal the stored budget, pulls `paymentToken`, status Funded. `submit(jobId, deliverable, optParams)`: provider, Funded only, `deliverable` is `bytes32`. `complete` and `reject`: evaluator only. `claimRefund`: client, after expiry plus a 1-hour grace for Submitted jobs, never pausable. + +**Hook `RulesBindingHook.sol`** (was `MandateBindingHook`). Acts only in `beforeAction(fund)`: `optParams` must be exactly `abi.encode(rulesId)`; the client must be a factory AGW; the rules must be live on the session engine; the AGW must have no Funded or Submitted job under this hook. Then records the binding and emits `RulesBound(jobId, agw, rulesId)`. Every other action passes through. Views `rulesOf(jobId)` and `liveJobOf(agw)` (renamed below). + +# 2. The lifecycle, as decided + +| Kernel call | Who | What Push does there | Status | +| --- | --- | --- | --- | +| `createJob` | client (the AGW through `openJob`, or any address directly) | `evaluator` = `UniversalEvaluator` on Push (or the `EvaluatorGateway` on another chain, phase 2); `description` = `abi.encode(JobSpec)`; `hook` = the rules hook. Hookable on the Push kernel (2026-10-12): the hook may learn the job at creation; on other chains it is not, so the evaluator still only depends on `setBudget` and `fund`. K-12 adds `paymentToken` here. | DECIDED | +| `setBudget` | provider | Prices the job in the job's token. `optParams` may carry a replacement `JobSpec`; the hook's `afterAction(setBudget)` checks `allowedMutability` against the caller and the evaluator stores the proposal, or the call reverts. A proposal is not an agreement. | DECIDED (2026-10-06); hook and evaluator code pending | +| `fund` | client | The client's acceptance. `beforeAction(fund)`: bind job to rules (section 1). `afterAction(fund)`: freeze the standing `JobSpec`, take the baseline (one before read per NUM or PCT check, pinned to the height at `fund`), paid from the client's prefund (`quoteSnapshot(description)` returns the amount). No further `setBudget` once Funded. | DECIDED (2026-10-06); snapshot owned by hook plus evaluator | +| `submit` | provider | `afterAction(submit)` calls `verify(jobId)` on the evaluator: checkpoint first (any owner-side change after the baseline completes in the agent's favour), after reads by validator quorum, logic tree, settle. A separate provider-callable retry exists for partial read failures. | DECIDED (2026-10-06) | +| `complete` / `reject` | evaluator | PASS calls `complete`; FAIL after `failFinalAt` calls `reject`; an early FAIL or an inconclusive round sends nothing and `verify` can run again. `reason` is a hash of the job and the round. Verified rating written in the same transaction (draft). | DECIDED | +| `claimRefund` | client | Untouched. The evaluator never holds funds and never blocks the kernel; `failFinalAt` sits well before `expiredAt`. | unchanged | + +Started is an evaluator fact, not a kernel state: the job has started when the baseline is recorded. The hook and the evaluator are separate contracts (DECIDED 2026-10-06, option A): the hook maps job to wallet rules and exists only on Push; the evaluator is directly callable so a developer with their own hook, or no AGW at all, can use it, and other chains' kernels whitelist their own hooks. + +# 3. Criteria: the shared wire format + +`JobSpec` is defined once (`JobSpecTypes.sol` in the marketplace repo) and read by the marketplace (writes it), the hook (freezes it) and the evaluator (judges it). Field order is ABI; a change here changes every description. + +```solidity +enum Evaluation { BOOLEAN, COMPARE, NUMBER, PERCENTAGE } // was EvalType { BOOL, CMP, NUM, PCT } (renamed 2026-10-12) +enum Operation { EQUAL, NOT_EQUAL, GREATER_THAN, GREATER_OR_EQUAL, LESS_THAN, LESS_OR_EQUAL } // was Op +enum LogicKind { ALL, ANY, AT_LEAST } // was NodeKind; CHECK leaf dropped (PROPOSED 2026-10-12) +enum AllowedMutability { NONE, CLIENT, PROVIDER, BOTH } // was Mutability; who may propose a replacement spec at setBudget + +struct Read { string chainNamespace; string chainId; uint16 minConfirmations; address target; bytes4 selector; bytes args; bytes outputs; uint8[] field; } +struct Check { uint8 read; Evaluation evaluation; Operation operation; int256 target; } +struct Logic { LogicKind kind; uint8[] checks; uint8[] children; uint8 k; } // was Node; operators list checks and child operators directly; logic[0] is the root + +struct JobSpec { + Read[] reads; // what to look at + Check[] checks; // how to compare each value; NUM and PCT need the baseline + Logic[] logic; // how the checks combine; was nodes + AllowedMutability allowedMutability; // who may propose a replacement spec at setBudget + bytes32 origin; // marketplace jobs: keccak256(marketplace, cardId, cardVersion, principal); zero otherwise + uint64 executeBy; + uint64 failFinalAt; +} +``` + +`PROVIDER` means the provider may propose a whole replacement spec; the evaluator refuses a proposal that changes `origin` or `allowedMutability` itself; timing stays inside the job's `expiredAt`; the client accepts by funding. Field order decided 2026-10-12: content first, then `allowedMutability` and `origin`, then timing ([4. Universal Evaluation](4%20Universal%20Evaluation%203e9188aea7f4817bb03ef4c78c883f8b.md), section 0); the evaluator team implements it in `JobSpecTypes.sol`. + +# 4. Kernel change the stack needs: K-12, payment token per job + +ERC-8183 carries no token on any call: `createJob`, `setBudget` and `fund` are token-less, and the token is an implementation constant of this kernel. The card wants to name its payment token and the job to inherit it. DECIDED (2026-10-09): `createJob` takes `paymentToken`; escrow is tracked per token; `fund` pulls and `complete` pays the job's token; `setBudget` keeps its one role, the price in that token. The token sits inside the `createJob` calldata the owner signs at `openJob`, so nobody can swap it afterwards. Two consequences to record in the interface: `createJob` is not hooked on other chains' kernels, so a hook reads the token from the job struct at `setBudget` or `fund`; and the argument is a Push extension, marked as such so a Base or BNB integration does not expect it. Until it lands, cards are priced in the kernel's one token. + +# 5. Hook changes + +- Renames: `rulesOf(jobId)` becomes `rulesOfJob(jobId)` and `agwOfJob(jobId)`; `isAGWBusy` and `liveJobOf` become `activeJobOf(agw) returns (uint256)`; one spelling with the marketplace. +- New: `afterAction(setBudget)` mutability check and proposal hand-off; `afterAction(fund)` freeze and baseline; `afterAction(submit)` verify. The interim hook is being extended into this (owner: the evaluator track, building on the existing hook). +- Dropped from the earlier plan: the binder role (rules expire by `validUntil`, caps bound the gap); the hook recomputing a criteria hash (the marketplace builds criteria on-chain, so there is nothing to recompute); the hook refusing `submit` before the baseline (the evaluator returns inconclusive instead and `verify` runs again). +- Still to check in the hook for non-marketplace jobs: the rules' `validUntil` is at or after the job's `expiredAt`, and the rules' agent equals the job's provider. The marketplace already enforces both at `openJob`; a plain job that names the hook gets them here or not at all. + +# 6. Fits the standard + +Push implements the Evaluator role in ERC-8183. The kernel ABI is Base V3's with the K changes; K-12 is the first change to a standard function's signature and is marked as a Push extension. Everything the hook and evaluator do runs through the standard's own hook points and evaluator role. The open-jobs and budget-proposals extension is a separate proposal: [Proposal: Open Jobs and Budget Proposals for ERC-8183](https://app.notion.com/p/Proposal-Open-Jobs-and-Budget-Proposals-for-ERC-8183-3f4188aea7f481cdad84fdd7a446ab7b?pvs=21). + +# 7. Open + +1. `createJob` hookability. Decided 2026-10-12: hookable on the Push kernel (reverses K-10 here), not assumed for kernels on other chains. The evaluator therefore still learns a job at `setBudget` or `fund`, and the Push hook may use the `createJob` hook for bookkeeping only. +2. Client cancel of an Open unfunded job. Decided 2026-10-12: yes, at the kernel. Open: the hook (or a narrow stop role) must release the AGW's rules on cancel so the wallet is not blocked until `expiredAt`. Research tagged. +3. `JobSpec` field order and `origin`: decided 2026-10-12 (section 3); pending implementation in `JobSpecTypes.sol`. +4. Fee design: the kernel's `platformFee` exists; who pays reads (client prefund at `fund` for the baseline, the submitter for after reads, as drafted) and whether external-chain evaluators are charged differently. Research, after AGW (tagged 2026-10-12). +5. Recurring jobs: a 7 or 15 day job that renews until cancelled, because a year of fees cannot be escrowed for "4% as long as the principal stays". Research; interacts with the one-live-job rule (tagged 2026-10-12). +6. Phase 2: jobs on other chains name an `EvaluatorGateway` on their chain; snapshot and verify travel to Push through the universal gateway, the verdict comes back TSS-signed. Planning doc pending; must not block the V2 evaluator build (tagged 2026-10-12). \ No newline at end of file diff --git a/plan/marketplace/notion/4-universal-evaluation.md b/plan/marketplace/notion/4-universal-evaluation.md new file mode 100644 index 00000000..c2ad7def --- /dev/null +++ b/plan/marketplace/notion/4-universal-evaluation.md @@ -0,0 +1,145 @@ +# 4. Universal Evaluation + + + +# 0. Settle first: one `JobSpec`, three repos + +`JobSpec` is written by the marketplace, frozen by the hook and judged by the evaluator, and it is the 8183 job's `description` byte for byte. Three places define it today and they do not agree: the marketplace repo (`JobSpecTypes.sol`: `executeBy, failFinalAt, reads, checks, nodes, origin`, no mutability), the Trust Layer page (`executeBy, failFinalAt, mutability, reads, checks, logic`, no `origin`), and the evaluator build in progress. Field order is ABI; two orders means two incompatible descriptions on day one. Decided 2026-10-12, the one order both repos implement: + +```solidity +enum Evaluation { BOOLEAN, COMPARE, NUMBER, PERCENTAGE } // was EvalType { BOOL, CMP, NUM, PCT }; renamed 2026-10-12 to match the SDK constants +enum Operation { EQUAL, NOT_EQUAL, GREATER_THAN, GREATER_OR_EQUAL, LESS_THAN, LESS_OR_EQUAL } // was Op +enum LogicKind { ALL, ANY, AT_LEAST } // CHECK leaf dropped (PROPOSED 2026-10-12): operators reference checks directly +enum AllowedMutability { NONE, CLIENT, PROVIDER, BOTH } // was Mutability + +struct Read { string chainNamespace; string chainId; uint16 minConfirmations; address target; bytes4 selector; bytes args; bytes outputs; uint8[] field; } +struct Check { uint8 read; Evaluation evaluation; Operation operation; int256 target; } +struct Logic { LogicKind kind; uint8[] checks; uint8[] children; uint8 k; } // checks: indices into checks[]; children: indices into logic[]; logic[0] is the root; no leaf nodes + +struct JobSpec { + Read[] reads; // what to look at + Check[] checks; // how to compare each value + Logic[] logic; // how the checks combine; logic[0] is the root + AllowedMutability allowedMutability; // who may propose a replacement spec at setBudget + bytes32 origin; // marketplace jobs: keccak256(marketplace, cardId, cardVersion, principal); zero for plain jobs + uint64 executeBy; // the provider should have acted by this time + uint64 failFinalAt; // after this a FAIL is final; must sit well before the kernel's expiredAt +} + +struct JobSpecTemplate { // the marketplace's stored form: the first four fields of JobSpec, plus param bounds + ReadTemplate[] reads; + CheckTemplate[] checks; + Logic[] logic; + AllowedMutability allowedMutability; + ParamBounds[] params; +} +``` + +Order decided 2026-10-12 (Harsh): content first (`reads`, `checks`, `logic`), then who may change it and where it came from (`allowedMutability`, `origin`), then timing (`executeBy`, `failFinalAt`). The template is the first four fields plus `params`, so `JobSpecBuilder` copies four fields and appends `origin` and the timing the job supplies. `origin` is kept, zero when unused: the marketplace needs it to tie a job to the card version the user signed. The evaluator ignores it except to refuse a proposal that changes it. The Trust Layer page's order is superseded; this one goes to the evaluator team as the order to implement. A `Check` compares a read against a constant target; read-against-read comparisons are out of scope (the marketplace resolves `principalBps` targets to constants at `openJob`). Vocabulary (2026-10-12): the enum and field names above are the SDK's constant names (`PushChain.CONSTANTS.AGENTIC.JOB.EVALUATION`, `OPERATION`, `LOGIC`, `ALLOWED_MUTABILITY`), one vocabulary from contract to SDK; `Logic` drops the `CHECK` leaf kind so an operator lists its checks and its child operators directly, which roughly halves node count (PROPOSED, for the evaluator team). The `Read` struct is EVM-shaped today (`address target`, `bytes4 selector`); since the evaluator only compares attested answers, any source universal read serves (Solana, web2) works once `Read` can carry the universal read envelope. Tracked as open item 3. + +# 1. In one paragraph + +The evaluator is deliberately dumb. It does not know what a yield job or a swap is. It knows how to fire a read on a chain at an agreed height, decode one value out of the answer using the `outputs` layout and the `field` path, compare that value (or its change since a snapshot) to a target, and combine the results through a small tree. Reads are attested by the universal validators by quorum, so the evaluator only ever does arithmetic on answers a quorum agreed on. The kernel's own lifecycle drives it: `fund` freezes the criteria and takes the snapshot, `submit` triggers the verdict, `complete` or `reject` settle. `claimRefund` after expiry always works, whatever the evaluator is doing. + +# 2. Decisions + +| # | Decision | Outcome | +| --- | --- | --- | +| E1 | Criteria format | **The V2 `JobSpec`** (reads, checks, logic) replaces the 2026-09-28 `Criteria { conditions[] }` draft. Generic through `outputs` and `field`: the evaluator reads a nested struct value without knowing the contract's interface. A read that cannot be decoded resolves to UNKNOWN, never reverts. | +| E2 | Comparison families | **Four `Evaluation`s**: BOOLEAN (`after == target`), COMPARE (`after op target`), NUMBER (`(after - before) op target`), PERCENTAGE (`(after - before) * 10000 / before op target`). NUMBER and PERCENTAGE need the snapshot; BOOLEAN and COMPARE look at the end state only. Named BOOL, CMP, NUM, PCT until 2026-10-12. The four families from the first draft (true or false, greater or less, percentage, absolute) map onto these one to one. | +| E3 | Pass logic | **A tree**, `logic[]`: ALL, ANY, AT_LEAST k, each listing the checks and the child operators it combines (the CHECK leaf kind was dropped 2026-10-12, PROPOSED). Children always have a higher index than their parent, so evaluation runs leaves up and cannot loop. No NOT: flip the operator on the check instead. Renamed from `nodes` to `logic` (2026-10-07). | +| E4 | Mutability | **`AllowedMutability` on the spec**: NONE, CLIENT, PROVIDER, BOTH. A proposal travels as a replacement `JobSpec` in `setBudget`'s `optParams`; the hook checks the flag against the caller; the evaluator stores it as the standing proposal; the client accepts by funding or does not fund. A proposal may not change `origin` or `allowedMutability`. `PROVIDER` means the whole spec. (2026-10-06, 2026-10-07) | +| E5 | Hook and evaluator | **Separate contracts.** The hook is the kernel-facing adapter (and on Push also the AGW rules binder); the evaluator is directly callable so a kernel with its own hook, or a party calling by hand, can use it. 8183 lets a kernel whitelist several hooks; merging would have limited that. (2026-10-06) | +| E6 | When the job starts | **At `fund`.** The hook's `afterAction(fund)` freezes the standing spec and takes the baseline: one before read per NUM or PCT check, pinned to the height at `fund`, so the baseline is the state before the agent touched anything. "Started" is the baseline being recorded; it is an evaluator fact, not a kernel state. | +| E7 | Who pays the reads | **Client prefunds the snapshot; the submitter pays the verify reads.** `quoteSnapshot(description)` returns the amount up front. On Push the AGW prefunds in the funding transaction. A spec with only BOOL and CMP checks has no snapshot and no prepay. (2026-10-06) | +| E8 | When the verdict runs | **At `submit`**, from the hook's `afterAction(submit)` calling `verify`. Wrapped in a try so a failed call never blocks `submit`; anyone can call `verify` again. A provider-callable retry exists for rounds where a read failed. The old "provider calls submit and then calls verify" is gone. | +| E9 | Verdicts | **PASS calls `complete`. FAIL after `failFinalAt` calls `reject`. FAIL before `failFinalAt` and INCONCLUSIVE send nothing** and `verify` can run again. `reason` is a hash of the job id and the round, so a verdict traces back to its reads. The three-consecutive-blocks rule from the first draft is dropped; a spec that fears a one-block spike adds a second read a few blocks later and joins them with ALL. | +| E10 | Checkpoint rule | **Checkpoint first.** Before any after read, the evaluator asks the AGW whether the owner changed anything after the baseline. If so, the job completes in the agent's favour (verdict `CLIENT_INTERFERED`), no reads. Unchanged from the first draft. | +| E11 | Verified ratings | **Written by the evaluator in the same transaction as `complete` or `reject`** (draft): rail, chain, job reference, 8004 agent id, provider, client, evaluator, verdict, reason, fee, settled at. Keyed by rail, chain and job so a job counts once. Where the record lives is open on [Proposal: Verified Ratings on ERC-8004 (In draft)](https://app.notion.com/p/Proposal-Verified-Ratings-on-ERC-8004-In-draft-3f4188aea7f4817480cfe762d6d833a6?pvs=21). | +| E12 | Jobs on other chains | **Phase 2: `EvaluatorGateway` per chain.** A job on Base or Arbitrum names the gateway as its evaluator and keeps its own kernel; `snapshot` and `verify` travel to Push through the universal gateway and the verdict comes back TSS-signed to the evaluator's account there, which alone may call `complete` or `reject` through the gateway. Three ways to trigger it: the kernel's own hook (from `EvaluationHookBase`), Push's hook whitelisted on the kernel, or any party calling `snapshot` and `verify` by hand (the default, needs nothing from the kernel operator). Planning doc pending; must not block v1. | +| E13 | Scope of v1 | **Deterministic lane only.** Validator-attested reads plus on-chain comparison. No committee, no staking, no commit-reveal, no judging of quality. Say so externally. Solana reads limited to what Read State serves today; prompt-based reads are the future path. | + +# 3. Rename map (2026-09-28 draft to the V2 design) + +| Area | Draft (09-28) | V2 (now) | +| --- | --- | --- | +| The criteria object | `Criteria { version, minDuration, conditions[] }` | `JobSpec { reads[], checks[], logic[], allowedMutability, origin, executeBy, failFinalAt }` | +| One condition | `Condition { read, sample, cmp }`, each condition owning its read | split into `Read` (fired once, may feed several checks), `Check` (one comparison) and `Logic` (how checks combine) | +| Read | `{ chainNamespace (full), queryType, target (bytes), callData, word, resultType }` | `{ chainNamespace (namespace only), chainId, minConfirmations, target (address), selector, args, outputs, field }`; `outputs` and `field` replace `word` and `resultType` | +| Sampling | `Sample { END, START_AND_END, PERIODIC }` | implied by `Evaluation`: NUMBER and PERCENTAGE snapshot at `fund`, BOOLEAN and COMPARE do not. PERIODIC dropped, not reserved | +| Comparison | `Compare { op (incl. IS_TRUE, IS_FALSE), basis (ABSOLUTE, DELTA, PCT, REF), value, ref, period, minPassBps }` | `Check { read, evaluation, operation, target }`; IS_TRUE and IS_FALSE become BOOLEAN with EQUAL; REF (compare two reads) is out of scope, see section 0 | +| Combining | all conditions must hold | `logic[]` tree: ALL, ANY, AT_LEAST k, operators listing checks and children directly | +| Timing | `minDuration` blocks early submit | `executeBy` and `failFinalAt` on the spec; the card's `minDuration`, `maxDuration`, `minExecuteWindow` and `settleWindow` bound them at `openJob` | +| Start | START reads at `fund`, `PreRecorded(jobId)` when the last lands | snapshot at `fund` by the hook, baseline recorded; same meaning, new names | +| Verdict trigger | END reads at `submit`, verdict in the last callback | `verify(jobId)` from `afterAction(submit)`, re-callable; verdicts PASS, FAIL, INCONCLUSIVE | +| Retry | `refireStart(jobId, condition)` by anyone | a provider-callable retry for failed reads; name follows the contract | +| Push-local and web2 reads | `push` namespace (direct staticcall, no fee), `web2` | push-local is a direct `staticcall`; web2 undefined, future planning (open item 3) | +| Where registered criteria live | evaluator or hook, open | the evaluator stores the spec and the standing proposal; the hook holds nothing of the criteria (storage doc owned by the evaluator track) | +| SDK namespace | `client.evaluation` (page 8) | none; job-side reads live in `client.job` ([7. SDK: 8183 Job](7%20SDK%208183%20Job%203ea188aea7f481e0a137f5a896723376.md)), `JobSpec` helpers (`buildJobSpec`, `encodeJobSpec`, ...) in `PushChain.utils.job` ([6. SDK: Universal Marketplace](6%20SDK%20Universal%20Marketplace%203ea188aea7f481e2961ed97129f3a4e6.md), section 3) | + +# 4. Structural pieces + +1. **Wire format.** `JobSpecTypes.sol` defined once and imported by the marketplace, the hook and the evaluator; never copied. Limits: `MAX_READS 16`, `MAX_CHECKS 16`, `MAX_LOGIC 32`, enforced by the evaluator, not the builder. +2. **Hook touchpoints.** `afterAction(setBudget)`: mutability check, proposal hand-off. `afterAction(fund)`: freeze, snapshot. `afterAction(submit)`: `verify` in a try. On Push the same hook also binds the AGW's rules in `beforeAction(fund)` ([3. 8183 (job kernel and hook)](3%208183%20(job%20kernel%20and%20hook)%203e9188aea7f48188a838c3a740d8c858.md)). `createJob` is hookable on the Push kernel only (2026-10-12) and the evaluator never depends on it. +3. **Snapshot.** One before read per NUM or PCT check, all pinned to the height at `fund`. Prefunded by the client; `quoteSnapshot` prices it. If the snapshot never completes, the job cannot pass a NUM or PCT check and expires into `claimRefund`. +4. **Verify round.** Checkpoint first; after reads by quorum; decode each read through `outputs` and `field`; each check resolves to PASS, FAIL or UNKNOWN; the tree combines them; settle or wait. Paid by the caller with `msg.value`. +5. **Settlement.** `complete` or `reject` with a reason hash; the verified rating written in the same transaction (draft). Late or duplicate verdicts are skipped, never reverted. +6. **Other chains (phase 2).** `EvaluatorGateway` per chain, `EvaluationHookBase` template for kernels that run their own hook, Push's hook as a one-time whitelist, or manual `snapshot` and `verify`. Job key on Push is (chain, kernel, jobId), never a bare jobId. + +# 4b. Contract surface, as a sketch (PROPOSED; follows the V2 build) + +Read `+` as new. Names follow the V2 design and the Plugging page; the build may move them. + +**UniversalEvaluator** (Push) + +```diff +// lifecycle, called by the hook (or by any party on a remote chain through the gateway) ++ propose(address kernel, uint256 jobId, address caller, bytes spec) // afterAction(setBudget): checks allowedMutability vs caller; stores the standing proposal; refuses origin or allowedMutability changes ++ snapshot(address kernel, uint256 jobId) payable // afterAction(fund): freezes the standing spec; fires before reads for NUM and PCT; prefund in msg.value or via prefund() ++ verify(address kernel, uint256 jobId) payable // afterAction(submit) or anyone: checkpoint, after reads, logic tree, settle or wait ++ prefund(address kernel, uint256 jobId) payable // client prepays the snapshot before fund ++ quoteSnapshot(bytes description) view returns (uint256) // what the snapshot will cost + +// views ++ specOf(address kernel, uint256 jobId) view returns (JobSpec) // frozen spec, or the standing proposal while Open ++ statusOf(address kernel, uint256 jobId) view returns (EvaluationStatus) // baseline height, before values, last round, verdict ++ version() view returns (string) + +// events ++ JobSpecProposed(kernel, jobId, by, specHash) // CriteriaProposed in the morning draft; one noun with the struct (2026-10-12) ++ JobSpecFrozen(kernel, jobId, specHash) ++ BaselineRecorded(kernel, jobId, height) ++ VerifyRound(kernel, jobId, round, result) // PASS | FAIL | INCONCLUSIVE ++ Settled(kernel, jobId, verdict, reason) // PASS | FAIL | CLIENT_INTERFERED +``` + +**EvaluationHookBase** (template for kernels on any chain) + +```diff ++ afterAction(jobId, sel, data): fund => GATEWAY.snapshot(msg.sender, jobId); submit => try GATEWAY.verify(msg.sender, jobId) {} catch {}; then _afterAction (yours) +``` + +**EvaluatorGateway** (every other chain, phase 2) + +```diff ++ snapshot(kernel, jobId) payable, verify(kernel, jobId) payable, prefund(kernel, jobId) payable // forward to Push through the universal gateway ++ settle(kernel, jobId, pass, reason) // only from the evaluator's execution account on this chain; calls complete or reject; late or duplicate skipped +``` + +# 5. Open + +1. `JobSpec` field order and `origin`: decided 2026-10-12 (section 0). Remaining step is the evaluator team implementing it in `JobSpecTypes.sol`; both repos import from there. +2. Who may call the retry, and its name on the contract (tagged 2026-10-12). +3. Push-local, non-EVM and web2 reads. Decided 2026-10-12: a read whose chain is Push itself is a direct `staticcall` by the evaluator, no universal read round trip. For every other source the evaluator compares attested answers and needs no new path; what is missing is a `Read` struct that can carry the universal read envelope for Solana and web2 (EVM-shaped today). Future planning, not v1 (tagged 2026-10-12). +4. Fees beyond reads: whether the evaluator takes a fee and how external-chain settlement is funded. Research, with the fee design (tagged 2026-10-12). +5. Recurring jobs and renewal, with the one-live-job rule on the wallet (tagged 2026-10-12). +6. Where the verified rating record lives (8004 Validation Registry or a Push contract). Parked; to be addressed later (2026-10-12). \ No newline at end of file diff --git a/plan/marketplace/notion/6-sdk-universal-marketplace.md b/plan/marketplace/notion/6-sdk-universal-marketplace.md new file mode 100644 index 00000000..d4fffa40 --- /dev/null +++ b/plan/marketplace/notion/6-sdk-universal-marketplace.md @@ -0,0 +1,1162 @@ +# 6. SDK: Universal Marketplace + + + +# List of changes + +New + +- `client.market` + - user side + - `cards` + - `card` + - `preview` + - `openJob` + - `deposit` + - `job` + - `activeJob` + - provider side, `client.market.agent` + - `register` + - `update` + - `setActive` + - `card` +- `MarketError`, progress family `MARKET-TX-1xx` +- `PushChain.utils.job` (moved here from page 8, 2026-10-12) + - `buildJobSpec` + - `buildJobSpecTemplate` + - `encodeJobSpec` + - `decodeJobSpec` + - `describeJobSpec` + - `previewJobSpec` +- `PushChain.utils.market` + - `validateAgentCardRules` + - `encodeAgentCardRules` + - `decodeAgentCardRules` +- `PushChain.CONSTANTS.AGENTIC.PRINCIPAL` and `PushChain.CONSTANTS.AGENTIC.JOB.*` (vocabulary), `JobSpecError` +- `client.universal.read.prepare` (core change; the read input to the builders) + +Removed from this page on 2026-10-12 + +- `PushChain.CONSTANTS.MARKET` (addresses stay inside the SDK, page 5 decision); `PushChain.CONSTANTS.JOB_SPEC` limits; the `'PRINCIPAL'` and `'CEA'` string markers (now `AGENTIC.PRINCIPAL` and `AGENTIC.WALLET`); `beneficiary` on allowed calls (now `pins`, page 5 6.a) + +Removed from the earlier draft of this page + +- `start` funding anything; `prepare.start`; `compile`; `publish`, `mine`, `retire`; `fee.tokens[]`; off-chain signed cards and hash ids + +Not in the SDK + +- admin calls: `verifyAgentCard`, `disableAgentCard`, `setCEADeployment`, `setHook`, `setEvaluator`, `pause` + +Two sides, one namespace. The user side is everything the person starting a job does: browse, preview, sign once, deposit. The provider side (`client.market.agent`) is everything the agent's operator does: register the card, update it, switch it on and off. A card id is an on-chain integer; a card version is on-chain and bumps on every update. + +# 1. User side, by example + +### 1.a List agent cards - `client.market.cards` + +Lists cards. The contract has no list view, so the SDK walks `agentCardCount` and `getAgentCard` and filters locally; an indexer replaces the walk later without changing the call. + +```tsx +// Function +const res = await client.market.cards({ options? }) + +// Usage and Params +const { cards } = await client.market.cards(); // every card +const { cards } = await client.market.cards({ chain: CHAIN.ETHEREUM_SEPOLIA }); // cards acting on one chain +const { cards } = await client.market.cards({ provider: '0xAgentOnPush', active: true }); +// options.provider Address, optional only cards registered by this Push address +// options.chain CHAIN, optional only cards whose execution chain is this one +// options.active boolean, optional only cards switched on; default all + +// Returns +// { cards: AgentCardSummary[] } +{ + cards: [ + { + cardId: 7n, + provider: '0xAgentOnPush', + jobType: 'LENDING_DEPOSIT', + chain: 'eip155:11155111', + providerFee: 5000000n, + paymentToken: '0xUSDC...', + principalMin: 100000000n, + principalMax: 50000000000n, + version: 2, + active: true, + verified: true, + rating: 0, + }, + ] +} +``` + +### 1.b Read one card - `client.market.card` + +The card in full, decoded: the listing, the rules the agent needs, the job spec template, version and tags. `getAgentCard` plus `getAgentRating`. + +```tsx +// Function +const card = await client.market.card(cardId) + +// Usage and Params +const card = await client.market.card(7n); // one card +// cardId bigint, required the card's on-chain id + +// Returns +// { cardId, provider, jobType, metadataURI, metadataHash, chain, providerFee, paymentToken, principalMin, principalMax, minDuration, maxDuration, minExecuteWindow, settleWindow, active, version, verified, disabled, rating, rules, jobSpecTemplate } +{ + cardId: 7n, + provider: '0xAgentOnPush', + jobType: 'LENDING_DEPOSIT', + metadataURI: 'ipfs://...', + metadataHash: '0x...', + chain: 'eip155:11155111', + providerFee: 5000000n, + paymentToken: '0xUSDC...', + principalMin: 100000000n, + principalMax: 50000000000n, + minDuration: 86400, + maxDuration: 7776000, + minExecuteWindow: 3600, + settleWindow: 7200, + active: true, + version: 2, + verified: true, + disabled: false, + rating: 0, + rules: { // AgentCardRules, decoded + assets: [ + { + token: MOVEABLE.TOKEN.ETHEREUM_SEPOLIA.USDC, + maxPerCall: PushChain.CONSTANTS.AGENTIC.PRINCIPAL, + maxTotal: PushChain.CONSTANTS.AGENTIC.PRINCIPAL, + }, + ], + maxGasPerCall: 1000000000000000000n, + allowedCalls: [ + { + target: aavePool, + selector: 'supply(address,uint256,address,uint16)', + pins: [ + { arg: 2, expected: PushChain.CONSTANTS.AGENTIC.WALLET }, + ], + }, + ], + principalAsset: 0, + approvals: [ + { + token: usdcSepolia, + spender: aavePool, + capIsPrincipal: true, + }, + ], + }, + jobSpecTemplate: { // JobSpecTemplate, decoded + reads: [...], + checks: [...], + logic: { ... }, + allowedMutability: 'NONE', + params: [], + }, +} +``` + +`rules.assets[].maxPerCall` and `maxTotal` read `PushChain.CONSTANTS.AGENTIC.PRINCIPAL` for the principal asset because the contract binds them to the job's principal at `openJob`; every other cap is a number. `PushChain.CONSTANTS.AGENTIC.WALLET` in a pin means the user's wallet on the card's chain (its CEA), filled the same way. + +### 1.c Preview a job before signing - `client.market.preview` + +Builds and validates everything the user's one signature will cover, and sends nothing. Bad inputs throw here (principal out of range, stale card version, wallet busy), before any signature. The returned plan is what `openJob` signs, and the readable preview is what the UI shows. + +```tsx +// Function +const plan = await client.market.preview(cardId, { options }) + +// Usage and Params +const plan = await client.market.preview(7n, { + principal: parseUnits('500', 6), // in the card's principal asset + expiredAt: now + 7 * 86400, // inside the card's duration window + executeBy: now + 3600, // at or after now + minExecuteWindow; executeBy + settleWindow <= expiredAt + params: [], // one per template param, inside its bounds +}); +// cardId bigint, required the card +// options.principal bigint, required the job's size, in the card's principal asset +// options.expiredAt number, required job expiry, unix seconds +// options.executeBy number, required the provider must have executed by this +// options.params bigint[], optional per-job numbers the template declares; default none +// options.walletIndex number, optional reuse a derived wallet slot; default the owner's next unused index + +// Returns +// { cardId, cardVersion, wallet, walletDeployed, session, intent, calldata, jobSpec, deposit, preview } +{ + cardId: 7n, + cardVersion: 2, + wallet: '0x2Fd9...', // predictWallet(owner, index) + walletDeployed: false, + session: { ... }, // the rules for this job, as the AGW will store them; sessionHash is in the intent + intent: { // what the owner signs; from previewIntent + owner: '0xFd6C...', + wallet: '0x2Fd9...', + executor: '0xMarketplace', + index: 0, + sessionHash: '0x...', + mode: '0x00...', + execCalldataHash: '0x...', + nonceKey: 0n, + nonceSeq: 0n, + grantNonce: 0n, + deadline: 1767225600, + signerChainId: 11155111n, + }, + calldata: '0x...', // the exact createJob execution, from buildCreateJobCalldata + jobSpec: { + spec: { // JobSpec, built from the card's template + reads: [...], + checks: [...], + logic: { ... }, + allowedMutability: 'NONE', + origin: '0x...', + executeBy: 1766630400, + failFinalAt: 1766637600, + }, + bytes: '0x...', + }, + deposit: { // what deposit() will move, for display + principal: { + token: MOVEABLE.TOKEN.ETHEREUM_SEPOLIA.USDC, + amount: 500000000n, + }, + providerFee: { + token: '0xUSDC...', + amount: 5000000n, + }, + pc: 1000000000000000000n, + approvals: [ + { + token: usdcSepolia, + spender: aavePool, + amount: 500000000n, + }, + ], + }, + preview: { // in words, for the signing screen + mayDo: [ + 'On Ethereum Sepolia: call Aave Pool supply(...); the receiving account is always your own account there', + ], + mayMove: [ + 'Up to 500 USDC in total, 500 per call; up to 1 PC per outbound for fees', + ], + judgedBy: [ + 'aUSDC balance of your account is at least 499.95 USDC', + 'Aave USDC supply rate is at least 4%', + ], + until: '2026-10-19 12:00 UTC', + }, +} +``` + +The SDK derives the user's destination account itself with the account utilities and compares it to the contract's `computeCEA`; a disagreement throws `CEA_MISMATCH` before signing. Approvals are listed because the owner, not the agent, must make them (page 2, section 3). + +### 1.d Open the job with one signature - `client.market.openJob` + +Signs the `OwnerIntent` and submits `openJob`. Behind the signature: the wallet is deployed if new, the rules are granted, the kernel job is created in Open with the wallet as client. Nothing is funded. + +```tsx +// Function +const res = await client.market.openJob(plan, { options? }) + +// Usage and Params +const res = await client.market.openJob(plan, { progressHook: (p) => console.log(p.id, p.message) }); // MARKET-TX-1xx +// plan JobPlan, required from preview; the SDK re-reads the wallet's nonces and refuses a stale plan +// options.progressHook function, optional progress events; default none +// options.relay boolean, optional submit through the Push relayer; default true for an external owner, false for a Push EOA, which submits itself + +// Returns +// { jobId, wallet, rulesId, tx } +{ + jobId: 42n, + wallet: '0x2Fd9...', + rulesId: '0x9c1e...', + tx: { // UniversalTxResponse of the openJob transaction + hash: '0xb527...', + origin: 'eip155:11155111:0x31dC...', // the owner's key, CAIP-10 + from: '0xRelayerOrOwner', + blockNumber: 1290n, + wait + } +} +``` + +The signature is EIP-712 under the factory's domain with `signerChainId` set to the owner's home chain, so MetaMask signs it on the chain it is connected to. Anyone may submit the signed parameters; a front-runner starts exactly the job the owner signed, and the wallet's nonces make it one-shot. A Push EOA owner signs the same way and the SDK submits from that EOA. + +### 1.e Deposit into the wallet - `client.market.deposit` + +The funding step, separate from `openJob` by decision: moves the principal, the provider fee and PC into the wallet from the connected signer (any chain, the normal `sendTransaction` with `funds`), then makes the card's approvals from the wallet's account on the destination chain through the owner door. Reports each step, because an external owner may sign more than once. + +```tsx +// Function +const res = await client.market.deposit(jobId, { options? }) + +// Usage and Params +const res = await client.market.deposit(42n, { progressHook: (p) => console.log(p.id, p.message) }); +const res = await client.market.deposit(42n, { skipApprovals: true }); // funds only; approvals made elsewhere +// jobId bigint, required the job opened on this card +// options.progressHook function, optional progress events, MARKET-TX-11x; default none +// options.skipApprovals boolean, optional move funds and PC only; default false + +// Returns +// { txs } +{ + txs: [ + { + step: 'PRINCIPAL', + tx: { hash: '0x...', wait }, // UniversalTxResponse + }, + { + step: 'PROVIDER_FEE', + tx: { hash: '0x...', wait }, + }, + { + step: 'PC', + tx: { hash: '0x...', wait }, + }, + { + step: 'APPROVAL', // owner door, cross-chain + token: usdcSepolia, + spender: aavePool, + tx: { hash: '0x...', wait }, + }, + ] +} +``` + +Funding can come from any account, not only the owner's: anyone can send tokens and PC to the wallet address. `deposit` is the convenience that knows the card's amounts and makes the approvals, which only the owner can do. After the provider prices the job, funding the kernel escrow is `client.job.fund(jobId)` on [7. SDK: 8183 Job](7%20SDK%208183%20Job%203ea188aea7f481e0a137f5a896723376.md). + +### 1.f Read what the marketplace recorded for a job - `client.market.job` + +```tsx +// Function +const res = await client.market.job(jobId) + +// Usage and Params +const { cardId, wallet, rulesId } = await client.market.job(42n); +// jobId bigint, required a job opened through the marketplace + +// Returns +// { cardId, cardVersion, wallet, rulesId } +{ + cardId: 7n, + cardVersion: 2, + wallet: '0x2Fd9...', + rulesId: '0x9c1e...', +} +``` + +Zero values for a job not opened here. The job's own state (status, budget, provider) is `client.job.status(jobId)`. + +### 1.g Read a wallet's live job - `client.market.activeJob` + +```tsx +// Function +const res = await client.market.activeJob(wallet) + +// Usage and Params +const { jobId } = await client.market.activeJob('0x2Fd9...'); // 0n when the wallet is free +// wallet Address, required an AGW + +// Returns +// { jobId } +{ + jobId: 42n +} +``` + +A wallet is busy while its last marketplace job is Funded, Submitted, or Open and not yet expired. `preview` and `openJob` throw `WALLET_HAS_ACTIVE_JOB` for a busy wallet. + +# 2. Provider side, by example + +The provider is the agent's operator. The connected signer's Push address becomes the card's `provider`, the 8183 provider, and the agent every rule names. One card per provider is enforced on-chain (open item 1). + +### 2.a Register a card - `client.market.agent.register` + +Encodes the rules (tokens resolved to PRC20s, selector strings to `bytes4`, pins to the argument offsets the contract checks) and the job spec template, then calls `registerAgentCard`. `rules` is the AGW's `Rule` ([5. SDK: AGW](5%20SDK%20AGW%203e9188aea7f481cf8e8de324956549b9.md), 6.a and 6.h) with the per-job fields left out: `agent` is the card's provider, `chainNamespace` is the card's `chain`, `validUntil` is the job's `expiredAt`; the marketplace fills those at `openJob`. Argument restrictions are `pins` on each allowed call, exactly as on the wallet, with `PushChain.CONSTANTS.AGENTIC.WALLET` standing for the user's wallet. Two fields are the marketplace's own: `principalAsset` says which asset is the principal, and `approvals` are the owner's token approvals on the execution chain, not rules on the wallet. + +```tsx +// Function +const res = await client.market.agent.register(card, { options }) + +// Usage and Params +const res = await client.market.agent.register({ + jobType: 'LENDING_DEPOSIT', + metadataURI: 'ipfs://...', + metadataHash: '0x...', + chain: CHAIN.ETHEREUM_SEPOLIA, // the chain the agent acts on + providerFee: parseUnits('5', 6), + paymentToken: USDC_PUSH, + principalMin: parseUnits('100', 6), + principalMax: parseUnits('50000', 6), + minDuration: 86400, + maxDuration: 90 * 86400, + minExecuteWindow: 3600, + settleWindow: 7200, +}, { + rules: { + assets: [ + { + token: MOVEABLE.TOKEN.ETHEREUM_SEPOLIA.USDC, + maxPerCall: PushChain.CONSTANTS.AGENTIC.PRINCIPAL, // bound to the job's principal at openJob + maxTotal: PushChain.CONSTANTS.AGENTIC.PRINCIPAL, + }, + ], + maxGasPerCall: parseUnits('1', 18), // PC (wei) per outbound, as on the AGW rule + allowedCalls: [ + { + target: aavePool, + selector: 'supply(address,uint256,address,uint16)', + pins: [ + { arg: 2, expected: PushChain.CONSTANTS.AGENTIC.WALLET }, // onBehalfOf must be the user's wallet (its CEA on Sepolia) + ], + }, + ], + principalAsset: 0, // marketplace field: which asset is the principal + approvals: [ // marketplace field: the owner's approvals on the execution chain + { + token: usdcSepolia, + spender: aavePool, + capIsPrincipal: true, + }, + ], + }, + jobSpecTemplate, // JobSpecTemplate; built with PushChain.utils.job.buildJobSpecTemplate (3.b) + progressHook: (p) => console.log(p.id, p.message), +}); +// card AgentCardInput, required the listing; provider and active are set by the contract +// options.rules AgentCardRules, required what the agent needs the owner to grant +// options.jobSpecTemplate JobSpecTemplate, required the evaluator's JobSpec with holes +// options.progressHook function, optional progress events, MARKET-TX-12x; default none + +// Returns +// { cardId, version, tx } +{ + cardId: 7n, + version: 1, + tx: { // UniversalTxResponse + hash: '0x...', + origin: 'eip155:11155111:0x31dC...', + from: '0xAgentOnPush', + blockNumber: 1300n, + wait + } +} +``` + +Registration checks run on-chain (job type, metadata, chain configured, principal and duration ranges, allow-list size and shape, no `approve` in the allow-list, approvals well formed, assets on the card's chain). The template is stored as given and not judged. + +### 2.b Update a card - `client.market.agent.update` + +Replaces every field except `provider`, `chain` and `active`, and both blobs. Version bumps, the verified tag clears, jobs already opened keep the version they were signed against. + +```tsx +// Function +const res = await client.market.agent.update(cardId, card, { options }) + +// Usage and Params +const res = await client.market.agent.update(7n, card, { rules, jobSpecTemplate, progressHook }); +// cardId bigint, required the provider's card +// card, options as in register + +// Returns +// { cardId, version, tx } +``` + +### 2.c Switch a card on or off - `client.market.agent.setActive` + +Off stops new jobs on the card; on resumes. Live jobs are untouched. Reversible, unlike the admin's `disableAgentCard`. + +```tsx +// Function +const tx = await client.market.agent.setActive(cardId, active, { options? }) + +// Usage and Params +const tx = await client.market.agent.setActive(7n, false); // pause the card +// cardId bigint, required the provider's card +// active boolean, required on or off +// options.progressHook function, optional default none + +// Returns +// { hash, origin, from, to, blockNumber, wait() } +``` + +### 2.d Read the provider's card - `client.market.agent.card` + +```tsx +// Function +const card = await client.market.agent.card() + +// Usage and Params +const card = await client.market.agent.card(); // the connected signer's card, or undefined +// no params + +// Returns +// same shape as 1.b +``` + +# 3. Authoring helpers, by example + +Pure functions, no network except `previewJobSpec`. A provider uses them to write a card; a client creating a plain 8183 job uses the same helpers to write a `JobSpec` with no placeholders and passes the bytes to `client.job.create` ([7. SDK: 8183 Job](7%20SDK%208183%20Job%203ea188aea7f481e0a137f5a896723376.md)). The format they produce is the `JobSpec` on [4. Universal Evaluation](4%20Universal%20Evaluation%203e9188aea7f4817bb03ef4c78c883f8b.md), section 0. Two authors, one format: a card carries a `JobSpecTemplate`, a `JobSpec` with placeholders for the user's wallet, the user's params and the principal and no timing, filled on-chain at `openJob`; a plain job carries a `JobSpec` directly. Both go on-chain as `abi.encode(...)`. + +Reads are universal reads that have not been sent yet. `client.universal.read.prepare` takes exactly the options `client.universal.read` takes, sends nothing, and returns the read as data; `client.universal.read(read)` accepts the same object, so what the author previews and what the validators fetch at verification is one description. The two things only the evaluator needs, `field` (which value to take out of the return) and `minConfirmations`, are given beside the prepared read in the builder, not to `prepare`. The evaluator never fetches anything itself; it compares attested answers, so any source universal read serves (EVM, Solana, web2) works the day the `Read` struct can describe it. Vocabulary comes from `PushChain.CONSTANTS.AGENTIC` (4.d); strings are accepted too. All PROPOSED (2026-10-12). + +### 3.a Build a spec for a plain job - `PushChain.utils.job.buildJobSpec` + +A complete `JobSpec` with no placeholders, for a client creating a job directly on the kernel. Validates the logic tree, the evaluator's limits (16 reads, 16 checks, 32 logic nodes) and that `failFinalAt` sits inside the expiry you pass. + +```tsx +// Function +const spec = PushChain.utils.job.buildJobSpec({ options }) + +// Usage and Params +const { JOB, WALLET } = PushChain.CONSTANTS.AGENTIC; +const deposited = client.universal.read.prepare({ // exactly what client.universal.read takes; nothing is sent + chain: CHAIN.ETHEREUM_SEPOLIA, + target: aUSDC, + abi: erc20Abi, + functionName: 'balanceOf', + args: [userWallet], +}); +const rate = client.universal.read.prepare({ + chain: CHAIN.ETHEREUM_SEPOLIA, + target: aavePool, + abi: aavePoolAbi, + functionName: 'getReserveData', + args: [USDC], +}); + +const spec = PushChain.utils.job.buildJobSpec({ + reads: [ + { + read: deposited, + minConfirmations: 12, + }, + { + read: rate, + field: [0, 2], // currentLiquidityRate inside the returned struct; default [0] + }, + ], + checks: [ + { + read: 0, + evaluation: JOB.EVALUATION.COMPARE, + operation: JOB.OPERATION.GREATER_OR_EQUAL, + target: 499950000n, // deposited at least 499.95 USDC + }, + { + read: 1, + evaluation: JOB.EVALUATION.COMPARE, + operation: JOB.OPERATION.GREATER_OR_EQUAL, + target: 4n * 10n ** 25n, // rate at least 4%, in ray + }, + ], + logic: JOB.LOGIC.ALL, // shorthand: all checks; or a tree, see 3.b + allowedMutability: JOB.ALLOWED_MUTABILITY.NONE, + executeBy: now + 3600, + failFinalAt: now + 3 * 3600, + expiredAt: now + 7 * 86400, // for the failFinalAt check only; not stored +}); +// options.reads (PreparedRead | ReadInput)[], required 1..16; a bare prepared read, or { read, field?, minConfirmations? }; no placeholders +// options.checks Check[], required 1..16; { read, evaluation, operation, target } +// options.logic LOGIC.ALL | LOGIC.ANY | LogicTree, required +// options.allowedMutability ALLOWED_MUTABILITY.*, required who may propose a replacement spec at setBudget +// options.executeBy number, required unix seconds +// options.failFinalAt number, required unix seconds; after this a FAIL is final +// options.expiredAt number, optional warns FAIL_WINDOW_THIN if failFinalAt is close to it + +// Returns +// { reads, checks, logic, allowedMutability, origin, executeBy, failFinalAt } +{ + reads: [ + { + chainNamespace: 'eip155', + chainId: '11155111', + minConfirmations: 12, + target: '0xaUSDC...', + selector: '0x70a08231', + args: '0x000...userWallet', + outputs: '0x0801...', // type codes derived from the ABI + field: [0], + }, + { ... }, + ], + checks: [ + { + read: 0, + evaluation: 'COMPARE', + operation: 'GREATER_OR_EQUAL', + target: 499950000n, + }, + { + read: 1, + evaluation: 'COMPARE', + operation: 'GREATER_OR_EQUAL', + target: 40000000000000000000000000n, + }, + ], + logic: { + kind: 'ALL', + of: [0, 1], + }, + allowedMutability: 'NONE', + origin: '0x00...00', // zero for a plain job + executeBy: 1766630400, + failFinalAt: 1766637600, +} +``` + +### 3.b Build a card template - `PushChain.utils.job.buildJobSpecTemplate` + +The same, with placeholders and no timing (the job supplies `executeBy` and `failFinalAt`). A read argument may be `WALLET` (the user's wallet on that chain, its CEA off Push) or `{ param: i }` (a user-chosen number); a check target may be `PRINCIPAL`, `{ principalBps: n }` or `{ param: i }`; each param declares bounds. Placeholders travel through `prepare` as ordinary argument values and the builder records where they sit, so `prepare` stays a plain universal read. This is what `client.market.agent.register` (2.a) takes as `jobSpecTemplate`. The marketplace stores it as given and fills the placeholders on-chain at `openJob`. + +```tsx +// Function +const template = PushChain.utils.job.buildJobSpecTemplate({ options }) + +// Usage and Params +const { JOB, WALLET, PRINCIPAL } = PushChain.CONSTANTS.AGENTIC; +const deposited = client.universal.read.prepare({ + chain: CHAIN.ETHEREUM_SEPOLIA, + target: aUSDC, + abi: erc20Abi, + functionName: 'balanceOf', + args: [WALLET], // placeholder: the user's wallet on Sepolia, filled at openJob +}); +const rate = client.universal.read.prepare({ + chain: CHAIN.ETHEREUM_SEPOLIA, + target: aavePool, + abi: aavePoolAbi, + functionName: 'getReserveData', + args: [USDC], +}); + +const template = PushChain.utils.job.buildJobSpecTemplate({ + reads: [ + { + read: deposited, + minConfirmations: 12, + }, + { + read: rate, + field: [0, 2], + }, + ], + checks: [ + { + read: 0, + evaluation: JOB.EVALUATION.COMPARE, + operation: JOB.OPERATION.GREATER_OR_EQUAL, + target: { principalBps: 9999n }, // deposited at least 99.99% of the principal + }, + { + read: 1, + evaluation: JOB.EVALUATION.COMPARE, + operation: JOB.OPERATION.GREATER_OR_EQUAL, + target: 4n * 10n ** 25n, + }, + ], + logic: { // a tree: entries are check indices or sub-trees + kind: JOB.LOGIC.ANY, + of: [ + { + kind: JOB.LOGIC.ALL, + of: [0, 1], + }, + { + kind: JOB.LOGIC.AT_LEAST, + k: 1, + of: [0], + }, + ], + }, + allowedMutability: JOB.ALLOWED_MUTABILITY.NONE, + params: [], // e.g. [{ min: 1n, max: 10n ** 30n }] for a user-chosen minOut +}); +// options.reads (PreparedRead | ReadInput)[], required args may carry WALLET or { param: i }; the builder records where +// options.checks CheckTemplate[], required target: bigint | PRINCIPAL | { principalBps } | { param } +// options.logic LOGIC.ALL | LOGIC.ANY | LogicTree, required +// options.allowedMutability ALLOWED_MUTABILITY.*, required +// options.params { min, max }[], optional one per user-supplied number, at most 8; default none + +// Returns +// { reads, checks, logic, allowedMutability, params } +{ + reads: [ + { + chainNamespace: 'eip155', + chainId: '11155111', + minConfirmations: 12, + target: '0xaUSDC...', + selector: '0x70a08231', + args: '0x00...00', // 32 zero bytes where the wallet goes + outputs: '0x0801...', + field: [0], + fills: [ + { + word: 0, + source: 'WALLET', // the placeholder, filled on-chain + }, + ], + }, + { ... }, + ], + checks: [ + { + read: 0, + evaluation: 'COMPARE', + operation: 'GREATER_OR_EQUAL', + target: { principalBps: 9999n }, + }, + { + read: 1, + evaluation: 'COMPARE', + operation: 'GREATER_OR_EQUAL', + target: 40000000000000000000000000n, + }, + ], + logic: { + kind: 'ANY', + of: [ + { + kind: 'ALL', + of: [0, 1], + }, + { + kind: 'AT_LEAST', + k: 1, + of: [0], + }, + ], + }, + allowedMutability: 'NONE', + params: [], +} +``` + +### 3.c Encode a spec - `PushChain.utils.job.encodeJobSpec` + +The bytes `client.job.create` takes as `jobSpec`, and the bytes `registerAgentCard` stores as the template. The logic tree is flattened to the contract's node list here and re-nested by the decoder, so the SDK never shows a leaf node. + +```tsx +// Function +const bytes = PushChain.utils.job.encodeJobSpec(spec) + +// Usage and Params +const jobSpec = PushChain.utils.job.encodeJobSpec(spec); // pass as client.job.create's jobSpec +const template = PushChain.utils.job.encodeJobSpec(templateSpec); // what register sends as jobSpecTemplate +// spec JobSpec | JobSpecTemplate, required abi.encode of either + +// Returns +// +``` + +### 3.d Decode a spec - `PushChain.utils.job.decodeJobSpec` + +From a job's `description` or a card's stored template back to a typed object; the decoder tells `JobSpec` from `JobSpecTemplate` by shape. + +```tsx +// Function +const spec = PushChain.utils.job.decodeJobSpec(bytes) + +// Usage and Params +const spec = PushChain.utils.job.decodeJobSpec(job.description); +const template = PushChain.utils.job.decodeJobSpec(card.jobSpecTemplateBytes); +// bytes Hex, required abi.encode of a JobSpec or a JobSpecTemplate + +// Returns +// +``` + +### 3.e Say the spec in words - `PushChain.utils.job.describeJobSpec` + +What `client.market.preview` shows on the signing screen, and what a card page renders. Pure; uses the ABI names captured by `prepare` when present, falls back to selector and address when describing a spec read from chain. + +```tsx +// Function +const lines = PushChain.utils.job.describeJobSpec(spec, { options? }) + +// Usage and Params +const lines = PushChain.utils.job.describeJobSpec(spec, { principal: 500000000n, decimals: { [aUSDC]: 6 } }); +// spec JobSpec | JobSpecTemplate, required +// options.principal bigint, optional resolves PRINCIPAL and principalBps targets into amounts +// options.decimals Record, optional formats token amounts + +// Returns +// { checks: string[], logic: string, timing: string } +{ + checks: [ + 'aUSDC balance of your wallet on Ethereum Sepolia is at least 499.95 USDC', + 'Aave USDC supply rate is at least 4%', + ], + logic: 'All of the above', + timing: 'Executed by 2026-10-13 13:00 UTC; a fail is final after 15:00 UTC', // empty on a template +} +``` + +### 3.f Dry-run the reads - `PushChain.utils.job.previewJobSpec` + +Sends each read through `client.universal.read` now and runs the tree, so an author sees what the evaluator would see today. Not a verdict and not attested: a sanity check before registering a card or creating a job. + +```tsx +// Function +const result = await PushChain.utils.job.previewJobSpec(spec, { options }) + +// Usage and Params +const result = await PushChain.utils.job.previewJobSpec(spec, { client, wallet: userWallet, principal: 500000000n }); +// spec JobSpec | JobSpecTemplate, required +// options.client PushChainClient, required the reads go through client.universal.read (open item 5) +// options.wallet Address, required for a template fills WALLET +// options.principal bigint, required for a template resolves PRINCIPAL and principalBps +// options.params bigint[], optional fills { param: i } + +// Returns +// { reads, checks, pass } +{ + reads: [ + { + value: '0x...', + decoded: 499960000n, + }, + { + value: '0x...', + decoded: 41200000000000000000000000n, + }, + ], + checks: [ + { + pass: true, + value: 499960000n, + }, + { + pass: true, + value: 41200000000000000000000000n, + }, + ], + pass: true, +} +``` + +### 3.g Check card rules - `PushChain.utils.market.validateAgentCardRules` + +`AgentCardRules` is plain data, so there is no builder: the provider writes the object and this applies the contract's checks locally (1..8 assets, `principalAsset` in range, no duplicate token, 1..32 allowed calls, no `approve` or `increaseAllowance`, transfer-like calls pin their recipient, at most 8 approvals). `register` and `update` call it before signing; exported for card pages. + +```tsx +// Function +PushChain.utils.market.validateAgentCardRules(rules) + +// Usage and Params +PushChain.utils.market.validateAgentCardRules(rules); // throws MarketError on the first failing check +// rules AgentCardRules, required as in 2.a + +// Returns +// +``` + +### 3.h Encode card rules - `PushChain.utils.market.encodeAgentCardRules` + +The bytes `registerAgentCard` stores. Tokens resolve to PRC20s, selector strings to `bytes4`, pins to the argument offsets the contract checks, `PRINCIPAL` caps to the marker the contract binds at `openJob`. Same encoding the AGW uses for a rule, so a card's rules and the rule the wallet stores never disagree. + +```tsx +// Function +const bytes = PushChain.utils.market.encodeAgentCardRules(rules, { options }) + +// Usage and Params +const bytes = PushChain.utils.market.encodeAgentCardRules(rules, { chain: CHAIN.ETHEREUM_SEPOLIA }); +// rules AgentCardRules, required as in 2.a +// options.chain CHAIN, required the card's execution chain; needed to resolve tokens and offsets + +// Returns +// +``` + +### 3.i Decode card rules - `PushChain.utils.market.decodeAgentCardRules` + +Back from the stored bytes to the object `register` took, tokens as the other chain's addresses again. What `card` uses to fill `rules`. + +```tsx +// Function +const rules = PushChain.utils.market.decodeAgentCardRules(bytes, { options }) + +// Usage and Params +const rules = PushChain.utils.market.decodeAgentCardRules(card.rulesBytes, { chain: card.chain }); +// bytes Hex, required as stored by registerAgentCard +// options.chain CHAIN, required the card's execution chain + +// Returns +// +``` + +# 4. Types + +### 4.a Namespace + +```tsx +interface MarketNamespace { + cards(opts?: { provider?: Address; chain?: CHAIN; active?: boolean }): Promise<{ cards: AgentCardSummary[] }>; + card(cardId: bigint): Promise; + preview(cardId: bigint, opts: PreviewOptions): Promise; + openJob(plan: JobPlan, opts?: { progressHook?: ProgressHook; relay?: boolean }): Promise<{ jobId: bigint; wallet: Address; rulesId: Hex; tx: UniversalTxResponse }>; + deposit(jobId: bigint, opts?: { progressHook?: ProgressHook; skipApprovals?: boolean }): Promise<{ txs: DepositStep[] }>; + job(jobId: bigint): Promise<{ cardId: bigint; cardVersion: number; wallet: Address; rulesId: Hex }>; + activeJob(wallet: Address): Promise<{ jobId: bigint }>; + agent: { + register(card: AgentCardInput, opts: { rules: AgentCardRules; jobSpecTemplate: JobSpecTemplate; progressHook?: ProgressHook }): Promise<{ cardId: bigint; version: number; tx: UniversalTxResponse }>; + update(cardId: bigint, card: AgentCardInput, opts: { rules: AgentCardRules; jobSpecTemplate: JobSpecTemplate; progressHook?: ProgressHook }): Promise<{ cardId: bigint; version: number; tx: UniversalTxResponse }>; + setActive(cardId: bigint, active: boolean, opts?: { progressHook?: ProgressHook }): Promise; + card(): Promise; + }; +} +``` + +### 4.b Cards and rules + +```tsx +interface AgentCardInput { + jobType: string; // stored as bytes32 (keccak of the string) + metadataURI: string; + metadataHash: Hex; + chain: CHAIN; // the execution chain; stored as the full CAIP-2 string; immutable after registration + providerFee: bigint; + paymentToken: Address; // lands with K-12 on the kernel + principalMin: bigint; + principalMax: bigint; + minDuration: number; + maxDuration: number; + minExecuteWindow: number; + settleWindow: number; +} + +interface AgentCard extends AgentCardInput { + cardId: bigint; + provider: Address; + active: boolean; + version: number; + verified: boolean; + disabled: boolean; + rating: number; + rules: AgentCardRules; + jobSpecTemplate: JobSpecTemplate; +} + +interface AgentCardSummary { + cardId: bigint; + provider: Address; + jobType: string; + chain: string; + providerFee: bigint; + paymentToken: Address; + principalMin: bigint; + principalMax: bigint; + version: number; + active: boolean; + verified: boolean; + rating: number; +} + +interface AgentCardRules { // the AGW Rule (page 5, 6.h) minus agent, chainNamespace, validUntil; plus two marketplace fields + assets: AssetCapInput[]; // 1..8; PRINCIPAL only on assets[principalAsset] + maxGasPerCall: bigint; // PC (wei) per outbound + allowedCalls: AllowedCall[]; // 1..32, with pins, imported from page 5; no approve or increaseAllowance + principalAsset: number; // marketplace: index into assets + approvals: ApprovalInput[]; // marketplace: the owner's, on the execution chain +} + +interface AssetCapInput { + token: MoveableToken | Address; // the other chain's token address or the native marker; the SDK resolves to the PRC20 + maxPerCall: bigint | PrincipalMarker; // PushChain.CONSTANTS.AGENTIC.PRINCIPAL + maxTotal?: bigint | PrincipalMarker; +} + +interface ApprovalInput { + token: Address; // on the execution chain + spender: Address; + capIsPrincipal: boolean; + cap?: bigint; // required when capIsPrincipal is false +} +``` + +### 4.c Plan and deposit + +```tsx +interface PreviewOptions { + principal: bigint; + expiredAt: number; + executeBy: number; + params?: bigint[]; + walletIndex?: number; +} + +interface JobPlan { + cardId: bigint; + cardVersion: number; + wallet: Address; + walletDeployed: boolean; + session: Session; // the rules for this job, as the AGW stores them + intent: OwnerIntent; // what the owner signs; from previewIntent + calldata: Hex; // the createJob execution; from buildCreateJobCalldata + jobSpec: { + spec: JobSpec; + bytes: Hex; + }; + deposit: { + principal: Funds; + providerFee: Funds; + pc: bigint; + approvals: { token: Address; spender: Address; amount: bigint }[]; + }; + preview: { + mayDo: string[]; + mayMove: string[]; + judgedBy: string[]; + until: string; + }; +} + +interface DepositStep { + step: 'PRINCIPAL' | 'PROVIDER_FEE' | 'PC' | 'APPROVAL'; + token?: Address; + spender?: Address; + tx: UniversalTxResponse; +} +``` + +`JobSpecTemplate` and `JobSpec` are the evaluator's wire format ([3. 8183 (job kernel and hook)](3%208183%20(job%20kernel%20and%20hook)%203e9188aea7f48188a838c3a740d8c858.md)); helpers to build and read them are in section 3 (`buildJobSpecTemplate`, `encodeJobSpec`, `decodeJobSpec`). + +### 4.d Constants - `PushChain.CONSTANTS.AGENTIC` additions + +Vocabulary for the spec and the two placeholders. `WALLET` already exists on page 5 (6.a); `PRINCIPAL` is new; the `JOB` members are new. No contract addresses here (page 5 decided addresses stay inside the SDK; the per-chain `JOB.ADDRESS` table is on page 7 because phase 2 needs the gateway address per chain). No limits here; the SDK enforces them and names the limit in the error. + +```tsx +PushChain.CONSTANTS.AGENTIC.WALLET // the user's wallet on the rule's or read's chain; pins, read args, check targets +PushChain.CONSTANTS.AGENTIC.PRINCIPAL // the job's principal; asset caps and check targets at 100% +PushChain.CONSTANTS.AGENTIC.JOB.EVALUATION.BOOLEAN | COMPARE | NUMBER | PERCENTAGE +PushChain.CONSTANTS.AGENTIC.JOB.OPERATION.EQUAL | NOT_EQUAL | GREATER_THAN | GREATER_OR_EQUAL | LESS_THAN | LESS_OR_EQUAL +PushChain.CONSTANTS.AGENTIC.JOB.LOGIC.ALL | ANY | AT_LEAST +PushChain.CONSTANTS.AGENTIC.JOB.ALLOWED_MUTABILITY.NONE | CLIENT | PROVIDER | BOTH +// enumerable, like PRESETS; the string each resolves to is the TypeScript literal type +``` + +### 4.e Errors and progress + +```tsx +class MarketError extends AgenticError {} // decoded from UniversalMarketplaceErrors, plus SDK-side checks + +// codes (contract) AGENT_CARD_INACTIVE, AGENT_CARD_VERSION_MISMATCH, PRINCIPAL_OUT_OF_RANGE, EXPIRY_OUT_OF_RANGE, EXECUTE_BY_OUT_OF_RANGE, +// PROVIDER_IS_EVALUATOR, PARAM_COUNT_MISMATCH, PARAM_OUT_OF_RANGE, WALLET_HAS_ACTIVE_JOB, +// AGENT_MISMATCH, ASSET_MISMATCH, GAS_CAP_MISMATCH, ACTIONS_MISMATCH, PRINCIPAL_CAP_MISMATCH, EXPIRY_MISMATCH, EXPECTED_CEA_MISMATCH +// codes (SDK) CEA_MISMATCH (SDK derivation disagrees with computeCEA), STALE_PLAN (nonces moved since preview), NOT_CARD_PROVIDER + +// progress events, MARKET-TX (PROPOSED) +// MARKET-TX-101 plan built { cardId, wallet } +// MARKET-TX-102 intent signed +// MARKET-TX-103 openJob submitted { relayed } +// MARKET-TX-104 job opened { jobId, wallet, rulesId } +// MARKET-TX-111 deposit step sent { step, token? } +// MARKET-TX-121 card registered or updated { cardId, version } +// MARKET-TX-199-01 done +// MARKET-TX-199-02 failed { code, decodedError } +``` + +### 4.f Authoring helper types - `PushChain.utils.job`, `PushChain.utils.market` + +```tsx +namespace PushChain.utils.market { + validateAgentCardRules(rules: AgentCardRules): void; + encodeAgentCardRules(rules: AgentCardRules, opts: { chain: CHAIN }): Hex; + decodeAgentCardRules(bytes: Hex, opts: { chain: CHAIN }): AgentCardRules; +} + +namespace PushChain.utils.job { + buildJobSpec(opts: BuildJobSpecOptions): JobSpec; + buildJobSpecTemplate(opts: BuildJobSpecTemplateOptions): JobSpecTemplate; + encodeJobSpec(spec: JobSpec | JobSpecTemplate): Hex; + decodeJobSpec(bytes: Hex): JobSpec | JobSpecTemplate; + describeJobSpec(spec: JobSpec | JobSpecTemplate, opts?: { principal?: bigint; decimals?: Record }): { checks: string[]; logic: string; timing: string }; + previewJobSpec(spec: JobSpec | JobSpecTemplate, opts: { client: PushChainClient; wallet?: Address; principal?: bigint; params?: bigint[] }): Promise; +} + +// client.universal.read.prepare: exactly the options of client.universal.read (chain, target, abi | idl, functionName, args), returns a PreparedRead without sending (core change, universal read change list item 6) +interface PreparedRead { chainNamespace: string; chainId: string; target: Address; selector: Hex; args: Hex; outputs: Hex } // what read() would send, as data +interface ReadInput { // what the builders take; a bare PreparedRead means field [0] and the chain's default confirmations + read: PreparedRead; + field?: number[]; // path to the value in the return; default [0] + minConfirmations?: number; // default per chain +} + +// vocabulary; the string forms are what the constants resolve to +type Evaluation = 'BOOLEAN' | 'COMPARE' | 'NUMBER' | 'PERCENTAGE'; +type Operation = 'EQUAL' | 'NOT_EQUAL' | 'GREATER_THAN' | 'GREATER_OR_EQUAL' | 'LESS_THAN' | 'LESS_OR_EQUAL'; +type LogicKind = 'ALL' | 'ANY' | 'AT_LEAST'; +type AllowedMutability = 'NONE' | 'CLIENT' | 'PROVIDER' | 'BOTH'; +type WalletMarker = typeof PushChain.CONSTANTS.AGENTIC.WALLET; // the user's wallet on the read's chain (page 5, 6.a) +type PrincipalMarker = typeof PushChain.CONSTANTS.AGENTIC.PRINCIPAL; // the job's principal + +// mirrors JobSpecTypes.sol (page 4, section 0); field order is ABI +interface Read { + chainNamespace: string; // 'eip155' (namespace only; chainId beside it) + chainId: string; + minConfirmations: number; + target: Address; + selector: Hex; + args: Hex; + outputs: Hex; // type codes + field: number[]; + fills?: Fill[]; // template reads only +} +interface Fill { word: number; source: 'WALLET' | 'PARAM'; param?: number } +interface Check { read: number; evaluation: Evaluation; operation: Operation; target: bigint } +interface CheckTemplate { read: number; evaluation: Evaluation; operation: Operation; target: bigint | PrincipalMarker | { principalBps: bigint } | { param: number } } +interface LogicTree { kind: LogicKind; of: (number | LogicTree)[]; k?: number } // k only with AT_LEAST; a bare index is a check + +interface JobSpec { + reads: Read[]; + checks: Check[]; + logic: LogicTree; + allowedMutability: AllowedMutability; + origin: Hex; + executeBy: number; + failFinalAt: number; +} +interface JobSpecTemplate { // the first four fields of JobSpec, plus params + reads: Read[]; + checks: CheckTemplate[]; + logic: LogicTree; + allowedMutability: AllowedMutability; + params: { min: bigint; max: bigint }[]; +} + +interface PreviewResult { + reads: { value: Hex; decoded: unknown }[]; + checks: { pass: boolean; value: unknown }[]; + pass: boolean; +} + +class JobSpecError extends AgenticError { index?: number } +// codes TOO_MANY_READS, TOO_MANY_CHECKS, TOO_MANY_LOGIC, TOO_MANY_PARAMS (the limit is in the message), BAD_TREE (dangling index, empty of, k out of range), +// UNFILLED_PLACEHOLDER (a template passed where a JobSpec is needed), FAIL_WINDOW_THIN +``` + +# 5. Open for review + +1. One card per provider. Decided 2026-10-12: enforced on-chain (`registerAgentCard` reverts `AgentCardAlreadyRegistered`), so `agent.card()` reads the one card and `agent.register` surfaces that revert as `MarketError` `CARD_EXISTS`. +2. Relayer for `openJob`. Decided 2026-10-12: the client submits in the default path; a relayed path can be added later without changing the signed intent. Not a v1 question. +3. Authoring helpers. Decided 2026-10-12: all of them live on this page (section 3), `PushChain.utils.job` for the spec and `PushChain.utils.market` for the rules, so the card author builds both halves of a card in one place. `client.evaluation` (page 8) is not kept as a namespace; its reads fold into `client.job`. +4. `cards` walks ids until an indexer exists; fine for a demo, not for a thousand cards. Definitions of what the contract exposes versus what needs an indexer requested (tagged 2026-10-12). +5. `previewJobSpec` through `client.universal.read` costs read fees and is faithful to what validators will see; a free `eth_call` fallback (`{ via: 'rpc' }`) is approximate and needs per-chain RPCs. Proposed: universal by default, rpc opt-in. +6. Non-EVM and web2 reads: `prepare` accepts whatever `client.universal.read` accepts (`idl` for Solana, the web2 destination), and the evaluator compares attested answers from any source. The gap is the on-chain `Read` struct, which is EVM-shaped today; tracked on page 4 (section 0, open item 3). +7. Whether `buildJobSpecTemplate` should derive a first draft of the `AgentCardRules` from the same reads (chains, contracts and selectors are all in there), or the author writes them separately (3.g to 3.i). +8. `client.universal.read.prepare` is a core change (universal read change list, item 6): same options as `read`, returns the read as data. Until it ships the builders cannot take reads. \ No newline at end of file diff --git a/plan/marketplace/notion/7-sdk-8183-job.md b/plan/marketplace/notion/7-sdk-8183-job.md new file mode 100644 index 00000000..3c5651df --- /dev/null +++ b/plan/marketplace/notion/7-sdk-8183-job.md @@ -0,0 +1,349 @@ +# 7. SDK: 8183 Job + + + +# List of changes + +New + +- `client.job` + - client side + - `create` + - `fund` + - `status` + - `list` + - `watch` + - `claimRefund` + - provider side + - `setBudget` + - `submit` + - `verify` +- `PushChain.CONSTANTS.AGENTIC.JOB.ADDRESS[chain]` (was `CONSTANTS.JOB[chain]`; kept because phase 2 puts an `EvaluatorGateway` on every chain) +- `JobError`, progress family `JOB-TX-1xx` + +Removed from the earlier draft of this page + +- `prepare.create` and `prepare.fund` (no prepare anywhere in the agentic SDK) +- `fund`'s token argument (the token is fixed at `createJob` with K-12 and read from the job) +- `evaluatorOnly.complete / reject` (DECIDED 2026-10-12: out; the evaluator contract calls them, a plain job calls the kernel raw) +- `client.evaluation` as a namespace (page 8): its job-side reads (`status`, `verdict`, `waitForStart`, `watch`) fold into `client.job.status` and `client.job.watch`; its criteria helpers become `PushChain.utils.job.*` (`buildJobSpec`, `encodeJobSpec`, `decodeJobSpec`, `describeJobSpec`, `previewJobSpec`), documented on [6. SDK: Universal Marketplace](6%20SDK%20Universal%20Marketplace%203ea188aea7f481e2961ed97129f3a4e6.md), section 3 + +Two sides. The client is whoever created the job: in marketplace jobs the AGW, acting through its owner (`PushChain.initialize(ownerSigner, { agenticWallet })`), so every client write below is a normal `sendTransaction` to the kernel through the owner door. The provider is an ordinary signer with no wallet and no rules, talking to the kernel directly. + +# 1. Client side, by example + +### 1.a Create a job without the marketplace - `client.job.create` + +A plain 8183 job: the connected account is the client. From an owner in `agenticWallet` mode the AGW is the client; from any other signer, that signer is. Marketplace jobs do not use this; `client.market.openJob` creates them from the card's job spec template. + +```tsx +// Function +const res = await client.job.create({ options }) + +// Usage and Params +const res = await client.job.create({ + provider: '0xAgentOnPush', // the agent; zero for bid mode + evaluator: PushChain.CONSTANTS.AGENTIC.JOB.ADDRESS[CHAIN.PUSH_TESTNET_DONUT].EVALUATOR, + hook: PushChain.CONSTANTS.AGENTIC.JOB.ADDRESS[CHAIN.PUSH_TESTNET_DONUT].HOOK, + expiredAt: now + 7 * 86400, + paymentToken: USDC_PUSH, // K-12; fixed here, read everywhere after + jobSpec: jobSpecBytes, // encodeJobSpec(spec); the description on the kernel + progressHook: (p) => console.log(p.id, p.message), +}); +// options.provider Address, required the 8183 provider; for an AGW client it must equal the agent of a live rule on that wallet +// options.evaluator Address, required UniversalEvaluator on Push, or the EvaluatorGateway on another chain (phase 2) +// options.hook Address, required a hook whitelisted on the kernel; zero for none +// options.expiredAt number, required unix seconds; at least the kernel's minimum window ahead +// options.paymentToken Address, required the job's token (K-12); until K-12 lands the kernel's one token is implied and this is ignored +// options.jobSpec Hex, optional encodeJobSpec(spec); omit for a job with no evaluation (description then free text) +// options.description string, optional only when jobSpec is absent +// options.progressHook function, optional progress events, JOB-TX-101; default none + +// Returns +// { jobId, tx } +{ + jobId: 43n, + tx: { // UniversalTxResponse + hash: '0x...', + origin: 'eip155:11155111:0x31dC...', + from: '0xWalletOrSigner', + blockNumber: 1400n, + wait + } +} +``` + +### 1.b Fund the escrow - `client.job.fund` + +The client's acceptance. Call after the provider's `setBudget`. The SDK reads the stored budget as `expectedBudget` (the kernel refuses a mismatch), reads the job's token, and for an AGW client passes `abi.encode(rulesId)` so the rules hook binds job to rules. If the criteria have NUM or PCT checks it also attaches the baseline prefund (`quoteSnapshot`) in PC. + +```tsx +// Function +const tx = await client.job.fund(jobId, { options? }) + +// Usage and Params +const tx = await client.job.fund(42n, { rulesId: '0x9c1e...' }); // AGW client: binds the rules +const tx = await client.job.fund(43n); // plain client, no hook payload +const tx = await client.job.fund(42n, { rulesId, progressHook: (p) => console.log(p.id) }); +// jobId bigint, required the job +// options.rulesId Hex, required for an AGW client with the rules hook the rule this job runs under +// options.progressHook function, optional progress events, JOB-TX-102; default none + +// Returns +// { hash, origin, from, to, blockNumber, wait() } +``` + +Before sending, the SDK checks the budget is set (`BUDGET_NOT_SET`), the token balance and allowance of the client (`INSUFFICIENT_FUNDS`), and for an AGW client that the wallet is free (`WALLET_HAS_ACTIVE_JOB`). Marketplace jobs: `client.market.deposit` moves the funds into the wallet first ([6. SDK: Universal Marketplace](6%20SDK%20Universal%20Marketplace%203ea188aea7f481e2961ed97129f3a4e6.md)). + +### 1.c Read a job - `client.job.status` + +The kernel record plus the evaluator's view of it, in one read. + +```tsx +// Function +const job = await client.job.status(jobId) + +// Usage and Params +const job = await client.job.status(42n); +// jobId bigint, required + +// Returns +// { jobId, status, client, provider, evaluator, hook, expiredAt, budget, paymentToken, deliverable?, jobSpec?, rulesId?, evaluation } +{ + jobId: 42n, + status: 'Funded', // Open | Funded | Submitted | Completed | Rejected | Expired + client: '0x2Fd9...', + provider: '0xAgentOnPush', + evaluator: '0xEval...', + hook: '0xHook...', + expiredAt: 1767225600, + budget: 5000000n, + paymentToken: '0xUSDC...', + deliverable: undefined, // bytes32 after submit + jobSpec: { + spec: { ... }, // decoded JobSpec + bytes: '0x...', + frozen: true, // frozen once Funded; the standing proposal while Open + }, + rulesId: '0x9c1e...', // from the rules hook, AGW clients only + evaluation: { + baselineAt: 1290n, // block of the baseline; undefined before fund or for BOOL/CMP-only specs + before: [499950000n, undefined], // per read, where taken + after: undefined, + verdict: undefined, // 'PASS' | 'FAIL' | 'CLIENT_INTERFERED' once settled + reason: undefined, + lastVerifyAt: undefined, + } +} +``` + +### 1.d List jobs - `client.job.list` + +```tsx +// Function +const res = await client.job.list({ options? }) + +// Usage and Params +const { jobs } = await client.job.list({ provider: client.universal.account, status: 'Funded' }); // my jobs as provider +const { jobs } = await client.job.list({ client: '0x2Fd9...' }); // one wallet's jobs +// options.client Address, optional +// options.provider Address, optional +// options.status JobStatus, optional +// options.fromJobId bigint, optional walk from here; default 1 + +// Returns +// { jobs: Job[] } +``` + +Walks `jobCounter` and `jobs(id)` until an indexer exists. + +### 1.e Watch a job - `client.job.watch` + +One stream for the reader, two sources underneath: kernel events (`BudgetSet`, `JobFunded`, `JobSubmitted`, `JobCompleted`, `JobRejected`) and evaluator events (proposal stored, baseline recorded, verify round, verdict). + +```tsx +// Function +const stop = client.job.watch(jobId, callback) + +// Usage and Params +const stop = client.job.watch(42n, (e) => console.log(e.kind, e.txHash)); +stop(); +// jobId bigint, required +// callback (e: JobEvent) => void, required + +// Returns +// stop() +// JobEvent.kind: 'BudgetSet' | 'JobSpecProposed' | 'Funded' | 'BaselineRecorded' | 'Submitted' | 'VerifyRound' | 'Completed' | 'Rejected' | 'Refunded' +``` + +### 1.f Claim a refund - `client.job.claimRefund` + +After `expiredAt` (plus the 1-hour grace for a Submitted job). Never pausable on the kernel. + +```tsx +// Function +const tx = await client.job.claimRefund(jobId, { options? }) + +// Usage and Params +const tx = await client.job.claimRefund(42n); +// jobId bigint, required +// options.progressHook function, optional + +// Returns +// +``` + +# 2. Provider side, by example + +### 2.a Price the job, optionally propose a new spec - `client.job.setBudget` + +Sets the budget in the job's token. For a marketplace job the budget must equal the card's `providerFee`, because the client's `fund` passes that as `expectedBudget`. When the job's `allowedMutability` allows the provider, `jobSpec` carries a replacement `JobSpec` in `optParams`; the hook checks the flag and the evaluator stores the proposal. The client sees it in `status.jobSpec` and accepts by funding, or does not fund. + +```tsx +// Function +const tx = await client.job.setBudget(jobId, amount, { options? }) + +// Usage and Params +const tx = await client.job.setBudget(42n, parseUnits('5', 6)); // price only +const tx = await client.job.setBudget(42n, parseUnits('5', 6), { jobSpec: newSpecBytes }); // price plus a counter-proposal +// jobId bigint, required +// amount bigint, required in the job's paymentToken +// options.jobSpec Hex, optional encodeJobSpec(spec); refused by the hook unless allowedMutability allows PROVIDER or BOTH +// options.progressHook function, optional + +// Returns +// +``` + +Before sending, the SDK checks the job is Open and not expired, the caller is the provider, and if `jobSpec` is given that `allowedMutability` permits it (`JOB_SPEC_NOT_MUTABLE`) and that `origin` and `allowedMutability` are unchanged (`PROPOSAL_CHANGES_FIXED_FIELDS`). + +### 2.b Submit the work - `client.job.submit` + +Funded only, before `expiredAt`. The hook's `afterAction(submit)` calls the evaluator's `verify`, so the verdict follows without another call; the submitter pays the after reads. + +```tsx +// Function +const tx = await client.job.submit(jobId, { options }) + +// Usage and Params +const tx = await client.job.submit(42n, { deliverable: 'ipfs://...' }); // string is hashed to bytes32 +const tx = await client.job.submit(42n, { deliverable: '0x7a0f...' }); // a bytes32 as is +// jobId bigint, required +// options.deliverable Hex | string, required bytes32 on the kernel: a hash, or a string the SDK hashes +// options.progressHook function, optional progress events, JOB-TX-103; default none + +// Returns +// +``` + +### 2.c Run or retry the verdict - `client.job.verify` + +Normally not needed: `submit` triggers it. Call when a verify round was inconclusive (a read failed or the job is before `failFinalAt` and failing) and the provider wants another round. Caller pays the reads. PROPOSED name; follows the evaluator's function once it lands. + +```tsx +// Function +const tx = await client.job.verify(jobId, { options? }) + +// Usage and Params +const tx = await client.job.verify(42n); +// jobId bigint, required +// options.progressHook function, optional + +// Returns +// +``` + +# 3. Types + +```tsx +interface JobNamespace { + create(opts: CreateJobOptions): Promise<{ jobId: bigint; tx: UniversalTxResponse }>; + fund(jobId: bigint, opts?: { rulesId?: Hex; progressHook?: ProgressHook }): Promise; + status(jobId: bigint): Promise; + list(opts?: { client?: Address; provider?: Address; status?: JobStatus; fromJobId?: bigint }): Promise<{ jobs: Job[] }>; + watch(jobId: bigint, cb: (e: JobEvent) => void): () => void; + claimRefund(jobId: bigint, opts?: { progressHook?: ProgressHook }): Promise; + setBudget(jobId: bigint, amount: bigint, opts?: { jobSpec?: Hex; progressHook?: ProgressHook }): Promise; + submit(jobId: bigint, opts: { deliverable: Hex | string; progressHook?: ProgressHook }): Promise; + verify(jobId: bigint, opts?: { progressHook?: ProgressHook }): Promise; +} + +interface CreateJobOptions { + provider: Address; + evaluator: Address; + hook: Address; + expiredAt: number; + paymentToken: Address; + jobSpec?: Hex; + description?: string; + progressHook?: ProgressHook; +} + +type JobStatus = 'Open' | 'Funded' | 'Submitted' | 'Completed' | 'Rejected' | 'Expired'; + +interface Job { + jobId: bigint; + status: JobStatus; + client: Address; + provider: Address; + evaluator: Address; + hook: Address; + expiredAt: number; + budget: bigint; + paymentToken: Address; + deliverable?: Hex; + jobSpec?: { + spec: JobSpec; + bytes: Hex; + frozen: boolean; + }; + rulesId?: Hex; + evaluation: { + baselineAt?: bigint; + before?: (bigint | undefined)[]; + after?: (bigint | undefined)[]; + verdict?: 'PASS' | 'FAIL' | 'CLIENT_INTERFERED'; + reason?: Hex; + lastVerifyAt?: bigint; + }; +} + +interface JobEvent { + jobId: bigint; + kind: 'BudgetSet' | 'JobSpecProposed' | 'Funded' | 'BaselineRecorded' | 'Submitted' | 'VerifyRound' | 'Completed' | 'Rejected' | 'Refunded'; + txHash: Hex; + blockNumber: bigint; + data?: unknown; +} + +// JobSpec: the evaluator's wire format (page 3, section 3). Helpers to build, encode, decode and preview it are +// PushChain.utils.job.* (page 6, section 3: buildJobSpec, encodeJobSpec, decodeJobSpec, describeJobSpec, previewJobSpec); this namespace carries bytes. + +PushChain.CONSTANTS.AGENTIC.JOB.ADDRESS[CHAIN.PUSH_TESTNET_DONUT] = { // per chain: other chains get their kernel and EvaluatorGateway here in phase 2 + KERNEL, + HOOK, + EVALUATOR, // UniversalEvaluator on Push; the EvaluatorGateway on every other chain +}; +// the kernel's grace window is read from the kernel, not a constant (page 5 rule: limits stay inside the SDK) + +class JobError extends AgenticError {} +// codes BUDGET_NOT_SET, BUDGET_MISMATCH, INSUFFICIENT_FUNDS, WALLET_HAS_ACTIVE_JOB, NOT_PROVIDER, NOT_CLIENT, WRONG_STATUS, EXPIRED, +// JOB_SPEC_NOT_MUTABLE, PROPOSAL_CHANGES_FIXED_FIELDS, RULES_NOT_LIVE, TOKEN_MISMATCH (until K-12: the kernel is single-token) +// progress events, JOB-TX (PROPOSED): 101 created, 102 funded { rulesId }, 103 submitted, 104 budget set { proposal }, 105 verify requested, 199-01 done, 199-02 failed +``` + +# 4. Open for review + +1. `create` from a plain EOA client: allowed, agreed 2026-10-12. Keeps the namespace honest to the standard; the rules hook simply does not bind. +2. `verify` naming and who may call it follow the evaluator contract; the V2 design has a provider-callable retry (tagged 2026-10-12). +3. `list` and `watch` walk the kernel until an indexer exists; agreed 2026-10-12, the indexer comes later. +4. `JobSpec` helpers (`PushChain.utils.job.buildJobSpec`, `encodeJobSpec`, `decodeJobSpec`, `describeJobSpec`, `previewJobSpec`) live on [6. SDK: Universal Marketplace](6%20SDK%20Universal%20Marketplace%203ea188aea7f481e2961ed97129f3a4e6.md), section 3, next to the card they are first used for; this page only carries the encoded bytes. Their open items (preview cost, Solana reads, hole marker) are tracked there. \ No newline at end of file diff --git a/plan/marketplace/notion/8-sdk-evaluation-placeholder.md b/plan/marketplace/notion/8-sdk-evaluation-placeholder.md new file mode 100644 index 00000000..7322cf7a --- /dev/null +++ b/plan/marketplace/notion/8-sdk-evaluation-placeholder.md @@ -0,0 +1,23 @@ +# 8. SDK: Evaluation (retired, placeholder) + + + +# What moved where + +- `client.evaluation.status / verdict / waitForStart / watch` are `client.job.status` and `client.job.watch` (page 7) +- `client.evaluation.refireStart` is `client.job.verify` (page 7) +- `PushChain.utils.job.buildJobSpec`, `buildJobSpecTemplate`, `encodeJobSpec`, `decodeJobSpec`, `describeJobSpec`, `previewJobSpec`, `PushChain.CONSTANTS.JOB_SPEC`, `JobSpecError` (page 6, 3.a to 3.f and 4.f) +- `PushChain.utils.market.validateAgentCardRules`, `encodeAgentCardRules`, `decodeAgentCardRules` (page 6, 3.g to 3.i) + +# If an evaluation SDK is needed later + +Candidates, none committed: a read-only `client.evaluator` for validators and operators (pending rounds, read receipts, verdict history), a verdict explorer over `Settled` and `VerifyRound` events, and a committee client for the probabilistic lane once that lane exists. Each would be designed against a shipped contract, not ahead of it. \ No newline at end of file diff --git a/plan/marketplace/questions.md b/plan/marketplace/questions.md new file mode 100644 index 00000000..21293248 --- /dev/null +++ b/plan/marketplace/questions.md @@ -0,0 +1,46 @@ +# Questions to share — drafts, not posted + +Prepared October 20 after fresh Notion discussions, pinned source review, unfunded tests and Donut read-only checks. Lead with the concrete mismatch and proposal; do not resend historical questions already answered below. + +## Zaryab, with Nilesh / Aman: canonical wire before automatic evaluation + +**Which exact shared JobSpec package/commit should the SDK target for the next compatible marketplace + hook + evaluator deployment?** Deployed marketplace v2 `443b4e2` uses `(reads,checks,logic,allowedMutability,origin,executeBy,failFinalAt)`, direct check indices, and NONE=0. Nilesh's [October 16 linked source](https://github.com/pushchain/push-chain-core-contracts/blob/8059817591cca16c59f1cc154f475f51e1736a67/src/agentic-commerce-8183/libraries/JobSpecTypes.sol) uses timing first, PRE/POST reads, left/right sums, CHECK leaves, and NONE=1/BOTH=0. Controlled vectors are incompatible. Proposal: build the current v2/manual-evaluator SDK profile now; coordinate one shared schema and deployment change before automated evaluation, without an SDK-only translation of signed bytes. + +## Harsh + Zaryab: public approvals and deposit shape + +**Should the SDK now follow deployed v2 D1 and remove `rules.approvals[]`, `skipApprovals`, and owner-approval deposit steps from page 6?** V2 permits agent `approve` with a pinned nonzero spender and capped amount and has no approvals array. Page 6 still rejects approve and exposes the old fields. Proposal: retain pinned approvals as allowedCalls and make deposit about principal/fee/PC, with explicit execution prerequisites. This confirms the public contract rather than asking for a feature already delivered. + +## Harsh: M4 in the first release + +**Can marketplace authoring require `allowedMutability: NONE` for the initial release, leaving other enum values representable but unsupported until the proposal/acceptance protocol is delivered?** Current hook ignores replacements; non-NONE flags are accepted but inert. A future mutable flow needs the client's exact expectedSpecHash/revision checked atomically at fund alongside budget. SDK rereads cannot close the same-price front-run. If mutability is required now, define the authenticated CLIENT/BOTH route and versioned fund payload with the evaluator team first. + +## Harsh + Zaryab: cancel surface and permission cleanup + +**Add `client.job.cancel` for an Open job, and should the AGW owner path atomically reject + revoke that job's permission?** The kernel already permits client reject; the SDK draft omits the method after removing evaluatorOnly.reject. Real-v6 fork proof shows cancel alone frees the marketplace slot but old permissions remain enabled after a new job opens. A single existing owner batch rejects and revokes successfully, with no new AGW role. Provider/evaluator-driven automatic cleanup remains a separate contract design; confirm that boundary and the expected behavior for terminal jobs. + +## Harsh: accepted price + +**For the first marketplace release, is funding fixed to the opened card version's reviewed providerFee, or may a user explicitly accept a different provider quote?** Page 7 alternates between passing the card price and reading the latest stored budget. Contract test proves a job can fund at 3× card fee if the client supplies that expectedBudget. Proposal: never silently adopt the latest price; fixed-price flow uses the opened version, negotiation requires an explicit reviewed quote/expected amount. + +## Harsh: pure read-authoring interface + +**Confirm an additive pure `client.universal.read.prepare` authoring API alongside existing async `universal.prepareRead(subject, options)`, or choose an adapter over that existing surface.** Current prepareRead produces paid-request/preflight data and does network reads; the page needs synchronous logical reads with output-layout codes and preserved WALLET/PARAM metadata. These are different representations. Proposal: share parsing/ABI encoding while retaining existing read APIs and introducing a distinct typed authoring representation. + +## Zaryab / Aman: smaller delivery discrepancies + +- Page 3 calls createJob hookable on Push, while the deployed kernel has no createJob hooks. Is this intentionally deferred? It need not block current marketplace SDK work; label it accurately. +- Confirm the eventual compatible evaluator delivery/ABI instead of wrapping a guessed `verify`: linked code uses hook-only verifyFromSubmit and public sendReads/retrySnapshot; the live marketplace evaluator is an EOA. Capability gating can ship now. + +## Wording to confirm during UX acceptance + +Page 6's dated decision chooses client submission and defers relay, while an example still defaults external users to relay=true. Follow the dated decision. Verify the native/EVM-owner signing UX and distinguish “one OwnerIntent authorization” from “one total wallet prompt”: self-submitting the transaction may require another signature. No relayer service is identified by these docs. + +## Already answered — do not block SDK work on these again + +- **K-12/payment token:** v2 intentionally ships with kernel pUSDC only; registration rejects other tokens. Future per-job tokens are a separately versioned kernel extension, not a prerequisite to implement v2. +- **Page 8:** no client.evaluation namespace in v1. Helpers are utils.job/utils.market; job-side reads belong to client.job. +- **Card enumeration:** agentCardCount + getAgentCard and agentCardOf exist; SDK can walk IDs with bounded reads. No list/indexer service is required for the demo. +- **Card identity/versioning:** on-chain integer ID, one card per provider, update increments version and clears verification; old hash-ID/signed-document proposals are superseded. +- **Opening funds:** openJob moves none; deposits and escrow funding are separate. +- **Markers:** contract FillSource.CEA/TargetSource.CEA stay named that way; public SDK uses WALLET. Marker wire hashes are published. +- **Recurring jobs/fees/ratings:** future research or placeholders; do not invent a renewal flow, rating service or fee policy. diff --git a/plan/marketplace/research/2026-10-20/ReviewGaps.t.sol b/plan/marketplace/research/2026-10-20/ReviewGaps.t.sol new file mode 100644 index 00000000..bb1a6ef1 --- /dev/null +++ b/plan/marketplace/research/2026-10-20/ReviewGaps.t.sol @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +// Copied into the isolated pinned repository's test/8183-tests for execution. +import {MarketplaceFixtures} from "./UniversalMarketplace.t.sol"; +import {UniversalMarketplaceForkTest, IAGWExecute} from "./UniversalMarketplace.fork.t.sol"; +import {IAgenticCommerce} from "../../src/agentic-commerce-8183/interfaces/IAgenticCommerce.sol"; +import {IAGWFactory} from "../../src/agentic-commerce-8183/interfaces/external/IAGWFactory.sol"; +import {ISmartSession} from "../../src/agentic-commerce-8183/interfaces/external/ISmartSession.sol"; +import {JobInputs, OpenJobParams, JobSpecTemplate} from "../../src/agentic-commerce-8183/libraries/Types.sol"; +import {JobSpec, AllowedMutability} from "../../src/agentic-commerce-8183/libraries/JobSpecTypes.sol"; + +contract ReviewLocalGaps is MarketplaceFixtures { + function test_review_nonNoneIsAcceptedButReplacementPayloadIsInert() public { + JobSpecTemplate memory t = _lendingTemplate(); + t.allowedMutability = AllowedMutability.BOTH; + uint256 id = _register(_card(), _rules(), t); + (uint256 jobId, address agw) = _open(_ready(id)); + string memory original = kernel.getJob(jobId).description; + assertEq(uint8(abi.decode(bytes(original), (JobSpec)).allowedMutability), uint8(AllowedMutability.BOTH)); + vm.prank(provider); + kernel.setBudget(jobId, FEE, hex"deadbeef"); + assertEq(kernel.getJob(jobId).description, original, "interim hook ignores replacement bytes"); + _fund(jobId, agw, FEE); + assertEq(uint8(kernel.getJob(jobId).status), uint8(IAgenticCommerce.JobStatus.Funded)); + } + + function test_review_cardFeeIsReferenceAndFundOnlyChecksAcceptedBudget() public { + uint256 id = _registerLending(); + (uint256 jobId, address agw) = _open(_ready(id)); + uint256 differentFee = mkt.getAgentCard(id).card.providerFee * 3; + _budgetAndFund(jobId, agw, differentFee); + assertEq(kernel.getJob(jobId).budget, differentFee); + assertEq(uint8(kernel.getJob(jobId).status), uint8(IAgenticCommerce.JobStatus.Funded)); + } +} + +contract ReviewRealAgwCancellation is UniversalMarketplaceForkTest { + struct Execution { address target; uint256 value; bytes callData; } + + function _reviewOpen() internal returns (uint256 cardId, uint96 index, uint256 jobId, address agw, bytes32 rulesId) { + vm.createSelectFork("https://evm.donut.rpc.push.org/", 24447347); + _deploy(); + vm.prank(provider); + cardId = mkt.registerAgentCard(_card(), abi.encode(_rules()), abi.encode(_lendingTemplate())); + index = uint96(IAGWFactory(FACTORY).walletCount(owner)); + (agw,) = IAGWFactory(FACTORY).predictWallet(owner, index); + JobInputs memory job = _inputs(); + OpenJobParams memory p = _signed(cardId, index, _sessionFor(agw, job), job); + vm.prank(relayer); + (jobId,,rulesId) = mkt.openJob(p); + } + + function test_review_cancelFreesWalletButOldAndNewGrantsBothRemainLive() public { + (uint256 cardId, uint96 index, uint256 jobId, address agw, bytes32 oldId) = _reviewOpen(); + _ownerExecute(agw, address(kernel), abi.encodeCall(IAgenticCommerce.reject, (jobId, bytes32(0), bytes("")))); + assertEq(mkt.activeJobOf(agw), 0, "cancel frees marketplace slot"); + assertTrue(ISmartSession(ENGINE).isPermissionEnabled(oldId, agw), "cancel does not revoke authority"); + JobInputs memory job = _inputs(); + OpenJobParams memory again = _signed(cardId, index, _sessionFor(agw, job), job); + vm.prank(relayer); + (,,bytes32 newId) = mkt.openJob(again); + assertTrue(newId != oldId); + assertTrue(ISmartSession(ENGINE).isPermissionEnabled(oldId, agw)); + assertTrue(ISmartSession(ENGINE).isPermissionEnabled(newId, agw)); + } + + function test_review_ownerCanAtomicallyCancelAndRevokeWithoutNewAgwRole() public { + (,,uint256 jobId, address agw, bytes32 rulesId) = _reviewOpen(); + Execution[] memory calls = new Execution[](2); + calls[0] = Execution(address(kernel), 0, abi.encodeCall(IAgenticCommerce.reject, (jobId, bytes32(0), bytes("")))); + calls[1] = Execution(agw, 0, abi.encodeWithSignature("revokeRules(bytes32)", rulesId)); + vm.prank(owner); + IAGWExecute(agw).execute(bytes32(bytes1(0x01)), abi.encode(calls)); + assertEq(uint8(kernel.getJob(jobId).status), uint8(IAgenticCommerce.JobStatus.Rejected)); + assertEq(mkt.activeJobOf(agw), 0); + assertFalse(ISmartSession(ENGINE).isPermissionEnabled(rulesId, agw)); + } +} diff --git a/plan/marketplace/research/2026-10-20/abi-manifest.json b/plan/marketplace/research/2026-10-20/abi-manifest.json new file mode 100644 index 00000000..3a7b41c6 --- /dev/null +++ b/plan/marketplace/research/2026-10-20/abi-manifest.json @@ -0,0 +1,47 @@ +{ + "source_commit": "443b4e2dd9ca5dd9ffc8efebdfcecd619dd66c47", + "files": [ + { + "file": "contracts/abi/AgenticCommerce.json", + "sha256": "6d6e09266fab0bc4c2e6a54933e53446c9dd207ea22a90071852428e9146992e", + "functions": 36, + "events": 23, + "errors": 22 + }, + { + "file": "contracts/abi/JobSpecBuilder.json", + "sha256": "0069a5e52d7000e17b5730cfdabe49bd2989c38adfed6b95f1a74d5f632a975a", + "functions": 1, + "events": 0, + "errors": 4 + }, + { + "file": "contracts/abi/RulesBindingHook.json", + "sha256": "cab42ebf25c34b63b4e51270b91a95740d7de7826c89cae5ff08a36fb3ff8b77", + "functions": 10, + "events": 2, + "errors": 8 + }, + { + "file": "contracts/abi/UniversalMarketplace.json", + "sha256": "06b639855612125c71f99b51aa69fbaa1b6bbb5d989505cfb4417fd6bfc20859", + "functions": 48, + "events": 17, + "errors": 30 + }, + { + "file": "contracts/abi/UniversalMarketplaceErrors.json", + "sha256": "48e821171747d9f22f1a3ef45525fb8bd02540a79976428700b088afcfdc090f", + "functions": 0, + "events": 0, + "errors": 40 + }, + { + "file": "contracts/abi/UniversalMarketplaceRules.json", + "sha256": "d72c043567ef1d3165493271dc93d3b8b9263000016946391a27991abe78996e", + "functions": 2, + "events": 0, + "errors": 14 + } + ] +} diff --git a/plan/marketplace/research/2026-10-20/contract-source-manifest.json b/plan/marketplace/research/2026-10-20/contract-source-manifest.json new file mode 100644 index 00000000..fa54946e --- /dev/null +++ b/plan/marketplace/research/2026-10-20/contract-source-manifest.json @@ -0,0 +1,224 @@ +{ + "repository": "https://github.com/pushchain/push-chain-core-contracts", + "branch": "sdk-iteration-v1", + "sha": "443b4e2dd9ca5dd9ffc8efebdfcecd619dd66c47", + "fetched_at": "2026-10-20T09:43:33.190042+00:00", + "files": [ + { + "path": "docs/addresses/push_donut_universal_marketplace.md", + "sha256": "71bd3676843ca4ef8f3c252cd7e6b9461affbcacf8ce885c805e07cd5f2c23e4" + }, + { + "path": "docs/universalmarketplace/README.md", + "sha256": "7caa8efcfd608c026f56f28e1b873a23b39acaf967223990074d3c03fec5ede5" + }, + { + "path": "docs/universalmarketplace/criteria.md", + "sha256": "ff66b0e63b1bfb81eafa3cd540c1db7ca0b7eabadd5830f11c4dcfc14df945ad" + }, + { + "path": "docs/universalmarketplace/reference.md", + "sha256": "bac4e09b0f13490b8f786266efc3118d65a7a7c6328cf3fc4a577239bdc1b33f" + }, + { + "path": "foundry.toml", + "sha256": "4343577dc84f7db108cfcd64736af12b2d848b206496b3e7d15fc5c352db807d" + }, + { + "path": "remappings.txt", + "sha256": "33b31e373f063571d30483b3ffc6e53bd19703071b50847c7fd2ac4d55087544" + }, + { + "path": "scripts/agentic-commerce-8183/DeployUniversalMarketplace.s.sol", + "sha256": "89f17de70d673f739417d9d73d25689437311943732f386c59e6fab6c7314b7d" + }, + { + "path": "src/agentic-commerce-8183/AgenticCommerce.sol", + "sha256": "bfc39d710ed8f3daf118ba8fcb5a83422797a241f99a788b7b920392e822a99f" + }, + { + "path": "src/agentic-commerce-8183/UniversalMarketplace.sol", + "sha256": "5acafe41338b5734b9df2cc295a88deebbeddb39e473e6583cdcf5a12f23b439" + }, + { + "path": "src/agentic-commerce-8183/UniversalMarketplaceRules.sol", + "sha256": "b8818e2d8b232f5913876ce32c67b630a0fc9cabf9c2dd5cc68ff16d2d1b7a82" + }, + { + "path": "src/agentic-commerce-8183/hooks/BaseERC8183Hook.sol", + "sha256": "3dd2af20677ceb71561a999bb564c25a6d9396a19c50da99706afcaf3d174c24" + }, + { + "path": "src/agentic-commerce-8183/hooks/RulesBindingHook.sol", + "sha256": "24fff91d14d3e1bafce79f71f7f58a2dc35de98019e04bd1099cfbb4021da077" + }, + { + "path": "src/agentic-commerce-8183/interfaces/IAgenticCommerce.sol", + "sha256": "a90d1bc5518e8ef190e250d7523f2268dacce1b380493699377063a096d8fd14" + }, + { + "path": "src/agentic-commerce-8183/interfaces/IERC8183Hook.sol", + "sha256": "d344ead446fbb7c10502843ae22ba87743ca0acd8befc84f328a97b62545d70e" + }, + { + "path": "src/agentic-commerce-8183/interfaces/IUniversalMarketplace.sol", + "sha256": "5ad7c860ecf19209b7dfde30af3d3693d5ba27ae815f965c61de66656844262a" + }, + { + "path": "src/agentic-commerce-8183/interfaces/IUniversalMarketplaceRules.sol", + "sha256": "8b15e1962bb136cc70b558c154dc5d3056cedc636cd4d803cd083b6c244c02ff" + }, + { + "path": "src/agentic-commerce-8183/interfaces/external/IAGW.sol", + "sha256": "17a06215afc2136aa795cce81acca5a3743eed404afc8a89c44f8171501912af" + }, + { + "path": "src/agentic-commerce-8183/interfaces/external/IAGWFactory.sol", + "sha256": "20ae9164904171ba01f6fa866bcbb089a721af20014243ebd8c1457aea87bb12" + }, + { + "path": "src/agentic-commerce-8183/interfaces/external/ISmartSession.sol", + "sha256": "c4d749382733544eccc7b53fdec6e505ef587eaac3331e6193cf534fa359c62a" + }, + { + "path": "src/agentic-commerce-8183/libraries/Errors.sol", + "sha256": "bfc0e60e6af1a0cb06d7ae2f2e5125ef74a4a0ffdde2544419b9e98604d7f6ac" + }, + { + "path": "src/agentic-commerce-8183/libraries/JobSpecBuilder.sol", + "sha256": "2b637585a6218d5474c5a5ba3f554a8830622745e48a2c5bc7fda12844ba8359" + }, + { + "path": "src/agentic-commerce-8183/libraries/JobSpecTypes.sol", + "sha256": "cdd81b07709c662f577007b557b31b7e97ffa54f8c6785b66361ced6024f895c" + }, + { + "path": "src/agentic-commerce-8183/libraries/Types.sol", + "sha256": "59896b8fce2ef03a37b372617122a56f1447da92f58fc47c18a3da37ffab4d44" + }, + { + "path": "test/8183-tests/AgenticCommerce.admin.t.sol", + "sha256": "bb1b729b5b643e7e3e5a7a5102def4729be55fb6e29606ae670c4de7532b2fee" + }, + { + "path": "test/8183-tests/AgenticCommerce.fuzz.t.sol", + "sha256": "cec05ba373a3a4a394d4a5a112c318e1257c0f22aef3bdf842425147874cb420" + }, + { + "path": "test/8183-tests/AgenticCommerce.hooks.t.sol", + "sha256": "f4e3085b009e9b04da9627f7526a510db7dd4e0dbd73d8cda835fbb0d993182d" + }, + { + "path": "test/8183-tests/AgenticCommerce.invariants.t.sol", + "sha256": "87cf5279ada6cbcc17c3e06356e501e2c39801906d78d2d48bc3fb24454fd997" + }, + { + "path": "test/8183-tests/AgenticCommerce.lifecycle.t.sol", + "sha256": "16c70160e1b055391a02444f8f3e1f98daa04e290735f63cd6c6d2912e0fc5c7" + }, + { + "path": "test/8183-tests/BaseERC8183Hook.t.sol", + "sha256": "ea2cf4e3ecfb9b6561573a64821edce7912c37fa9cc5dc48afb37c2e3827f9d3" + }, + { + "path": "test/8183-tests/Interfaces.t.sol", + "sha256": "07224a4daa067466dbbed7fac2da3f8854f0f92a29bd123a425d3ab4adcf4515" + }, + { + "path": "test/8183-tests/JobSpecBuilder.t.sol", + "sha256": "60ba8bcc5a90f48b59654253851dee204c0137d0501444f6a4f00e91639674ba" + }, + { + "path": "test/8183-tests/KernelBase.t.sol", + "sha256": "fb120cc4dcbfa227321d87daa4b68185381fd43889bdd55b3f01137af450dca0" + }, + { + "path": "test/8183-tests/Naming.t.sol", + "sha256": "313a49b0a083039110ca2553779fa29a4511f5b98100bf29cedce0b83e209d8b" + }, + { + "path": "test/8183-tests/RulesBindingHook.fork.t.sol", + "sha256": "1140f2394d433450c0324677d4c824597e56e5387c61ccb2a95ae34d2756f3f9" + }, + { + "path": "test/8183-tests/RulesBindingHook.t.sol", + "sha256": "779e99ee165549cb70b3b91031ea2b6a843d4b1f8d98a865894548e10e939955" + }, + { + "path": "test/8183-tests/UniversalMarketplace.conformance.t.sol", + "sha256": "e7dba1f27b2483d028fd2cb7ab2552e1f5ce79828901b369b5bc06b2ee929d55" + }, + { + "path": "test/8183-tests/UniversalMarketplace.fork.t.sol", + "sha256": "e302e56f7c82cadbcc6ca22c530bb43060517e71e453d427d2351ff01ef0e21a" + }, + { + "path": "test/8183-tests/UniversalMarketplace.invariants.t.sol", + "sha256": "fb6381e003b9b412d927cf85ac4185cabf4479643b121380839c422bafb23bf8" + }, + { + "path": "test/8183-tests/UniversalMarketplace.t.sol", + "sha256": "e10d6668b579a400ada8d877b1e7fb50aa0799151948baff8d1b07f7f5cefa9e" + }, + { + "path": "test/8183-tests/UniversalMarketplaceRules.t.sol", + "sha256": "82bd14c04f4aa949a131299369dd2c819dfe85014fa9b3aa9833529073698835" + }, + { + "path": "test/8183-tests/helpers/RulesFixtures.sol", + "sha256": "36de1516702919e007e8255f1556406a043ca70e25d7e801442e925a68d33f50" + }, + { + "path": "test/8183-tests/helpers/TemplateParts.sol", + "sha256": "17fddc29d8c5bfe2a4554fe61351064eae21adddc0d01693a42e30c29f8fce05" + }, + { + "path": "test/8183-tests/helpers/V2Decoder.sol", + "sha256": "2224cde7ef9a92ee061760a29de7ec89ccbdac22d49e0467022e118efd6bada5" + }, + { + "path": "test/8183-tests/mocks/BareHook.sol", + "sha256": "cf3dba5de2318fbf040c0bfd340ea62a98b4fd3e2db8c4e1c4192ff4baae46d9" + }, + { + "path": "test/8183-tests/mocks/ERC165Only.sol", + "sha256": "813dcc2fac5b4bcb796fdbe8fbc4183345e49e90f6da92c970fa38f81ed0d37f" + }, + { + "path": "test/8183-tests/mocks/MockAGW.sol", + "sha256": "fc6bea534ae3f3e5f0560a452d26a77b43311168918615c85030ad7371981847" + }, + { + "path": "test/8183-tests/mocks/MockAGWFactory.sol", + "sha256": "5d7b3b537d0169c0647aab2646d18bb608c9311b08dcb10c93c31c1dc9e268d2" + }, + { + "path": "test/8183-tests/mocks/MockERC20_6.sol", + "sha256": "d66d5e7c147613ab9986420f66d28a468e73aa3c55891ef4653d31771050d43e" + }, + { + "path": "test/8183-tests/mocks/MockPRC20Source.sol", + "sha256": "bddf0460fd38c7fe485a77cd6b99695b9f2eec74edb163b6a555b161244d8197" + }, + { + "path": "test/8183-tests/mocks/MockSmartSession.sol", + "sha256": "5d1a6be41784938f5117a72f9a19fbaa5a4579410355a022d11a01ca59db8975" + }, + { + "path": "test/8183-tests/mocks/RecordingHook.sol", + "sha256": "2fa999d4319a35b4b18566d824a74103f892d7a5bc6ec480414e75181b568267" + }, + { + "path": "test/8183-tests/mocks/ReentrantHook.sol", + "sha256": "034d63401a510ba6ab1e8186430e4e71bd32a6d8d6c9550ea461a71bb257a8b6" + }, + { + "path": "test/8183-tests/mocks/RevertingHook.sol", + "sha256": "cab340c8d79ba30578ef3f66c6117333c39b34f67298f896262d26a4c61ba784" + }, + { + "path": "test/8183-tests/mocks/RoutingProbeHook.sol", + "sha256": "180c1f409b903013976c0e6222bb21bde2dd523189e4114a4dd8e833efb9414f" + } + ] +} diff --git a/plan/marketplace/research/2026-10-20/contract-test-command.json b/plan/marketplace/research/2026-10-20/contract-test-command.json new file mode 100644 index 00000000..2cd54329 --- /dev/null +++ b/plan/marketplace/research/2026-10-20/contract-test-command.json @@ -0,0 +1,18 @@ +{ + "args": [ + "forge", + "test", + "--root", + "/var/folders/4_/d47r2_4s1wb3x2dvmt2ghp800000gp/T/marketplace-review-443b4e2-_ib864pr", + "--match-path", + "test/8183-tests/*.t.sol", + "--no-match-test", + "invariant_", + "--offline", + "--json" + ], + "exit_code": 0, + "seconds": 45.76, + "log": "contract-tests.log", + "scope": "All 8183 test files, invariant functions excluded; fork files are reviewed separately for gated execution." +} diff --git a/plan/marketplace/research/2026-10-20/contract-test-summary.json b/plan/marketplace/research/2026-10-20/contract-test-summary.json new file mode 100644 index 00000000..63e5486a --- /dev/null +++ b/plan/marketplace/research/2026-10-20/contract-test-summary.json @@ -0,0 +1,21 @@ +{ + "counts": { + "Success": 248, + "Skipped": 2 + }, + "suites": 15, + "nonpassing": [ + { + "suite": "test/8183-tests/RulesBindingHook.fork.t.sol:RulesBindingHookForkTest", + "test": "test_fork_mirrorsMatchDeployedAGW()", + "status": "Skipped", + "reason": null + }, + { + "suite": "test/8183-tests/UniversalMarketplace.fork.t.sol:UniversalMarketplaceForkTest", + "test": "test_fork_openJob_realAGWv6()", + "status": "Skipped", + "reason": null + } + ] +} diff --git a/plan/marketplace/research/2026-10-20/contract-tests.log b/plan/marketplace/research/2026-10-20/contract-tests.log new file mode 100644 index 00000000..11c5efcf --- /dev/null +++ b/plan/marketplace/research/2026-10-20/contract-tests.log @@ -0,0 +1 @@ +{"test/8183-tests/AgenticCommerce.admin.t.sol:AgenticCommerceAdminTest":{"duration":"16ms 730µs 209ns","test_results":{"test_admin_functions_revertForNonAdmin()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":53361}},"traces":[],"labeled_addresses":{"0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin"},"duration":"58µs 875ns","breakpoints":{},"gas_snapshots":{}},"test_batchDetachHook_detachesAndSkips()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":1165609}},"traces":[],"labeled_addresses":{"0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin"},"duration":"512µs 208ns","breakpoints":{},"gas_snapshots":{}},"test_batchDetachHook_empty_isNoop()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":20896}},"traces":[],"labeled_addresses":{"0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin"},"duration":"11µs 666ns","breakpoints":{},"gas_snapshots":{}},"test_batchDetachHook_invalidIds_revert()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":158355}},"traces":[],"labeled_addresses":{"0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin"},"duration":"26µs 417ns","breakpoints":{},"gas_snapshots":{}},"test_constants()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":19031}},"traces":[],"labeled_addresses":{"0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin"},"duration":"15µs 708ns","breakpoints":{},"gas_snapshots":{}},"test_dewhitelistedHook_stillCalledOnExistingJob()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":1386723}},"traces":[],"labeled_addresses":{"0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin"},"duration":"160µs 958ns","breakpoints":{},"gas_snapshots":{}},"test_emergencyWithdraw_balanceBelowEscrow_availableIsZero()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":300767}},"traces":[],"labeled_addresses":{"0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin"},"duration":"57µs 166ns","breakpoints":{},"gas_snapshots":{}},"test_emergencyWithdraw_cannotTouchEscrow()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":454393}},"traces":[],"labeled_addresses":{"0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin"},"duration":"4ms 927µs 666ns","breakpoints":{},"gas_snapshots":{}},"test_emergencyWithdraw_notPaused_reverts()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":23671}},"traces":[],"labeled_addresses":{"0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin"},"duration":"16µs 542ns","breakpoints":{},"gas_snapshots":{}},"test_emergencyWithdraw_otherToken_fullyWithdrawable()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":939832}},"traces":[],"labeled_addresses":{"0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin"},"duration":"1ms 16µs 959ns","breakpoints":{},"gas_snapshots":{}},"test_emergencyWithdraw_zeroTo_reverts()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":46786}},"traces":[],"labeled_addresses":{"0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin"},"duration":"18µs 666ns","breakpoints":{},"gas_snapshots":{}},"test_emergencyWithdraw_zeroToken_reverts()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":44848}},"traces":[],"labeled_addresses":{"0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin"},"duration":"14µs 709ns","breakpoints":{},"gas_snapshots":{}},"test_fees_exactly10000_allowed_10001_reverts()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":76289}},"traces":[],"labeled_addresses":{"0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin"},"duration":"22µs 83ns","breakpoints":{},"gas_snapshots":{}},"test_initialize_onImplementationReverts()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":18423}},"traces":[],"labeled_addresses":{"0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin"},"duration":"8µs 459ns","breakpoints":{},"gas_snapshots":{}},"test_initialize_revertsOnZeroAdmin()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":96196}},"traces":[],"labeled_addresses":{"0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin"},"duration":"23µs 167ns","breakpoints":{},"gas_snapshots":{}},"test_initialize_revertsOnZeroToken()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":96474}},"traces":[],"labeled_addresses":{"0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin"},"duration":"52µs 709ns","breakpoints":{},"gas_snapshots":{}},"test_initialize_revertsOnZeroTreasury()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":96613}},"traces":[],"labeled_addresses":{"0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin"},"duration":"39µs","breakpoints":{},"gas_snapshots":{}},"test_initialize_secondCallReverts()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":22754}},"traces":[],"labeled_addresses":{"0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin"},"duration":"20µs 250ns","breakpoints":{},"gas_snapshots":{}},"test_initialize_setsState()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":55988}},"traces":[],"labeled_addresses":{"0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin"},"duration":"85µs 917ns","breakpoints":{},"gas_snapshots":{}},"test_pause_blocksEveryLifecycleFunction()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":631845}},"traces":[],"labeled_addresses":{"0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin"},"duration":"254µs 375ns","breakpoints":{},"gas_snapshots":{}},"test_setEvaluatorFee_emits()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":46469}},"traces":[],"labeled_addresses":{"0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin"},"duration":"32µs 833ns","breakpoints":{},"gas_snapshots":{}},"test_setHookWhitelist()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":47302}},"traces":[],"labeled_addresses":{"0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xfedf0985f0dd1922cf3d60e35e5348a6fb37c922":"h"},"duration":"117µs 750ns","breakpoints":{},"gas_snapshots":{}},"test_setHookWhitelist_zero_reverts()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":19483}},"traces":[],"labeled_addresses":{"0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin"},"duration":"27µs 708ns","breakpoints":{},"gas_snapshots":{}},"test_setPlatformFee()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":57469}},"traces":[],"labeled_addresses":{"0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x6a8548f54c723e46f27892911e8c1badf15a21a5":"t2"},"duration":"125µs 375ns","breakpoints":{},"gas_snapshots":{}},"test_setPlatformFee_zeroTreasury_reverts()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":19055}},"traces":[],"labeled_addresses":{"0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin"},"duration":"23µs","breakpoints":{},"gas_snapshots":{}},"test_storageLayout_bySlot()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":352521}},"traces":[],"labeled_addresses":{"0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin"},"duration":"271µs 125ns","breakpoints":{},"gas_snapshots":{}},"test_unpause_restores()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":158007}},"traces":[],"labeled_addresses":{"0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin"},"duration":"53µs 125ns","breakpoints":{},"gas_snapshots":{}},"test_unpause_whenNotPaused_reverts()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":20466}},"traces":[],"labeled_addresses":{"0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin"},"duration":"19µs 667ns","breakpoints":{},"gas_snapshots":{}},"test_upgrade_byAdminRoleHolder_reverts()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":2933561}},"traces":[],"labeled_addresses":{"0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin"},"duration":"107µs 166ns","breakpoints":{},"gas_snapshots":{}},"test_upgrade_byProxyAdminOwner_preservesState()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":3189641}},"traces":[],"labeled_addresses":{"0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin"},"duration":"216µs 541ns","breakpoints":{},"gas_snapshots":{}},"test_upgrade_byStranger_reverts()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":2933671}},"traces":[],"labeled_addresses":{"0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin"},"duration":"99µs 84ns","breakpoints":{},"gas_snapshots":{}}},"warnings":[]},"test/8183-tests/AgenticCommerce.fuzz.t.sol:AgenticCommerceFuzzTest":{"duration":"192ms 520µs 750ns","test_results":{"testFuzz_claimRefund_refundsClient(uint256,bool)":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Fuzz":{"first_case":{"calldata":"0xaab49aa000000000000000000000000000214feb2caf420de2e7d1a5d26675eab6a0e2bb0000000000000000000000000000000000000000000000000000000000000001","gas":255492,"stipend":21560},"runs":1024,"mean_gas":230121,"median_gas":233499,"failed_corpus_replays":0}},"traces":[],"labeled_addresses":{"0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider"},"duration":"99ms 746µs 542ns","breakpoints":{},"gas_snapshots":{}},"testFuzz_complete_conservesBudget(uint256,uint256,uint256)":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Fuzz":{"first_case":{"calldata":"0x9b3a61fc00000000000000000000000000214feb2caf420de2e7d1a5d26675eab6a0e2bb0000000000000000000000000000000260818b01e8252083ddd4ceb18d829d9b000000000000000000000000000000000000000003dd4aa62561b3c84436274e","gas":398421,"stipend":22024},"runs":1024,"mean_gas":369538,"median_gas":375964,"failed_corpus_replays":0}},"traces":[],"labeled_addresses":{"0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider"},"duration":"181ms 275µs 708ns","breakpoints":{},"gas_snapshots":{}},"testFuzz_emergencyWithdraw_bound(uint256,uint256,uint256)":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Fuzz":{"first_case":{"calldata":"0x514c2e5500000000000000000000000000214feb2caf420de2e7d1a5d26675eab6a0e2bb0000000000000000000000000000000260818b01e8252083ddd4ceb18d829d9b000000000000000000000000000000000000000003dd4aa62561b3c84436274e","gas":339581,"stipend":22024},"runs":1024,"mean_gas":300070,"median_gas":287302,"failed_corpus_replays":0}},"traces":[],"labeled_addresses":{"0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider"},"duration":"151ms 242µs","breakpoints":{},"gas_snapshots":{}},"testFuzz_fund_movesExactBudget(uint256)":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Fuzz":{"first_case":{"calldata":"0x4e4a534e00000000000000000000000000214feb2caf420de2e7d1a5d26675eab6a0e2bb","gas":276113,"stipend":21420},"runs":1024,"mean_gas":253195,"median_gas":254260,"failed_corpus_replays":0}},"traces":[],"labeled_addresses":{"0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider"},"duration":"67ms 263µs 333ns","breakpoints":{},"gas_snapshots":{}},"testFuzz_reject_refundsClient(uint256,bool)":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Fuzz":{"first_case":{"calldata":"0xc88cc79700000000000000000000000000214feb2caf420de2e7d1a5d26675eab6a0e2bb0000000000000000000000000000000000000000000000000000000000000001","gas":256228,"stipend":21560},"runs":1024,"mean_gas":230877,"median_gas":234235,"failed_corpus_replays":0}},"traces":[],"labeled_addresses":{"0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider"},"duration":"83ms 468µs 250ns","breakpoints":{},"gas_snapshots":{}}},"warnings":[]},"test/8183-tests/AgenticCommerce.hooks.t.sol:AgenticCommerceHooksTest":{"duration":"4ms 212µs 917ns","test_results":{"test_afterRevert_rollsBackComplete()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":354434}},"traces":[],"labeled_addresses":{"0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner"},"duration":"188µs 42ns","breakpoints":{},"gas_snapshots":{}},"test_afterRevert_rollsBackFund()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":310037}},"traces":[],"labeled_addresses":{"0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner"},"duration":"136µs 125ns","breakpoints":{},"gas_snapshots":{}},"test_callOrder_fullLifecycle()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":1884232}},"traces":[],"labeled_addresses":{"0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner"},"duration":"554µs 583ns","breakpoints":{},"gas_snapshots":{}},"test_complete_hookEncoding()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":1692302}},"traces":[],"labeled_addresses":{"0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner"},"duration":"189µs 375ns","breakpoints":{},"gas_snapshots":{}},"test_reentrancy_fromAfter_blocked()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":1710353}},"traces":[],"labeled_addresses":{"0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner"},"duration":"466µs","breakpoints":{},"gas_snapshots":{}},"test_reentrancy_fromBefore_blockedForEveryLifecycleCall()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":1546641}},"traces":[],"labeled_addresses":{"0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner"},"duration":"307µs 958ns","breakpoints":{},"gas_snapshots":{}},"test_reject_hookEncodingAndOrder()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":1309279}},"traces":[],"labeled_addresses":{"0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner"},"duration":"247µs 41ns","breakpoints":{},"gas_snapshots":{}},"test_revertingBefore_blocksEveryHookedAction()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":788011}},"traces":[],"labeled_addresses":{"0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner"},"duration":"346µs","breakpoints":{},"gas_snapshots":{}}},"warnings":[]},"test/8183-tests/AgenticCommerce.invariants.t.sol:AgenticCommerceInvariantsTest":{"duration":"106ms 126µs 84ns","test_results":{"test_handlerLiveness()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":62258443}},"traces":[["Deployment",{"arena":[{"parent":null,"children":[],"idx":0,"trace":{"depth":0,"success":true,"caller":"0x1f95d37f27ea0dea9c252fc09d5a6eaa97647353","address":"0x5f65cd7d792e9746ef82929d60de9a1c526f93a5","maybe_precompile":false,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CREATE","value":"0x0","data":"0x608080604052346019576118d0908161001e823930815050f35b5f80fdfe60806040526004361015610011575f80fd5b5f3560e01c6319317cc514610024575f80fd5b60407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261102c5760043567ffffffffffffffff811161102c573660238201121561102c5780600401359061007a826114b3565b916100886040519384611472565b8083526020830191366024838301011161102c57815f926024602093018537840101526024359067ffffffffffffffff821161102c5760c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc833603011261102c576040519160c0830183811067ffffffffffffffff821117610f8957604052806004013573ffffffffffffffffffffffffffffffffffffffff8116810361102c57835260248101356020840152604481013565ffffffffffff8116810361102c576040840152606481013563ffffffff8116810361102c576060840152608481013567ffffffffffffffff811161102c5781013660238201121561102c57600481013590610196826114ed565b916101a46040519384611472565b808352602060048185019260051b840101019136831161102c57602401905b82821061140d57505050608084015260a4013560a0830152825183019060208483031261102c57519167ffffffffffffffff831161102c5760a084840183031261102c57604051936102148561141d565b6020848201015167ffffffffffffffff811161102c57602090858301010160208401601f8201121561102c57805161024b816114ed565b916102596040519384611472565b81835260208084019260051b8201019060208701821161102c5760208101925b8284106111b6575050505085526040848201015167ffffffffffffffff811161102c57602090858301010160208401601f8201121561102c5780516102bd816114ed565b916102cb6040519384611472565b818352602060a081850193028201019060208701821161102c57602001915b81831061113c575050506020860152606084820101519067ffffffffffffffff821161102c5760208401603f828701840101121561102c5760208286830101015191610335836114ed565b926103436040519485611472565b808452602084016020870160208360051b81868c8901010101011161102c576040848901840101905b6040858a018501600585901b010182106110305750505050604086019182526080858201015194600486101561102c576060870195865260a081830101519067ffffffffffffffff821161102c5760209201010160208401601f8201121561102c578051906103da826114ed565b946103e86040519687611472565b82865260208087019360061b8301019160208201831161102c57602001925b828410610fe4575050505082608086015260808201519384518451808203610fb65750505f5b85518110156104bc576104408187611688565b5161044b8287611688565b515113801561049b575b6104615760010161042d565b61046b8187611688565b51907f4b1b3452000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b506104a68187611688565b5160206104b38388611688565b51015112610455565b508573ffffffffffffffffffffffffffffffffffffffff845116815151927fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061051d610507866114ed565b956105156040519788611472565b8087526114ed565b013660208601375f5b8351805182101561058f579061054761054182600194611688565b51611723565b610552575b01610526565b610567610560828751611688565b5185611766565b73ffffffffffffffffffffffffffffffffffffffff6105868389611688565b9116905261054c565b5050945f5b60208401518051821015610654579060ff6105b182600194611688565b515116600360606105c68460208a0151611688565b5101516105d281611642565b6105db81611642565b148061062c575b6105ee575b5001610594565b73ffffffffffffffffffffffffffffffffffffffff61062261061b610614848a51611688565b5188611766565b9289611688565b91169052886105e7565b5073ffffffffffffffffffffffffffffffffffffffff61064c8289611688565b5116156105e2565b858386898b6040519160e0830183811067ffffffffffffffff821117610f89576040526060835260606020840152606060408401525f60608401525f60808401525f60a08401525f60c084015265ffffffffffff60408601511660a084015265ffffffffffff60408601511663ffffffff6060870151160167ffffffffffffffff81116108f05767ffffffffffffffff9096949395961660c086015260a086015160808601525160408501525161070a81611642565b61071381611642565b60608401528051517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061075e610748836114ed565b926107566040519485611472565b8084526114ed565b015f5b818110610f6857505083525f915b815180518410156109df578361078491611688565b519360808601519573ffffffffffffffffffffffffffffffffffffffff6107ab8685611688565b5116936107b661164c565b5060a0870151936108086020604051876107d98299518092858086019101611505565b810103017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101875286611472565b5f5b60c0890151805182101561091d578161082291611688565b518051909190600581901b611fe016602081019081106108f0578851106108c0576020830151926002841015610893578c600194155f146108755750506020611fe08a925b60051b16890101520161080a565b61088c611fe09160ff604060209501511690611688565b5192610867565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b50887fb2159785000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5050975094809294506109d4919660019481519160208101519161ffff60408301511673ffffffffffffffffffffffffffffffffffffffff6060840151167fffffffff000000000000000000000000000000000000000000000000000000006080850151169161010060e0860151950151956040519761099c89611455565b8852602088015260408701526060860152608085015260a084015260c083015260e08201528551906109ce8383611688565b52611688565b50019190929361076f565b848383886020830151517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0610a16610748836114ed565b015f5b818110610f5157505060208501525f5b60208401518051821015610c0c5781610a4191611688565b5190610a4b6116c9565b5060808201908151916060840160018151610a6581611642565b610a6e81611642565b03610b8d57509091505160208401518115610b6057817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0410610b345760208401518181029181830414901517156108f0576127109004905b60ff835116926040602082015191610ade83611642565b015190600682101561089357602094600194610b2b93859360405193610b0385611439565b8452610b0e81611642565b8884015260408301526060820152858a0151906109ce8383611688565b50019050610a29565b507fc7764ffa000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b60028151610b9a81611642565b610ba381611642565b03610bc35750610bbc9192506080850151905190611688565b5190610ac7565b6003915051610bd181611642565b610bda81611642565b03610ac757905073ffffffffffffffffffffffffffffffffffffffff610c0460ff84511686611688565b511690610ac7565b85604051602080820152610120810182519060e06040840152815180915261014083019060206101408260051b8601019301915f905b828210610e4d57505050506020830151907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0838203016060840152602080835192838152019201905f5b818110610dfb575050506040830151907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0838203016080840152815180825260208201906020808260051b8501019401925f905b828210610d7157610d6d87610d59818967ffffffffffffffff60c08e6060810151610d0a81611642565b60a08601526080810151828601528260a08201511660e0860152015116610100830152037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282611472565b604051918291602083526020830190611526565b0390f35b90919293947fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082820301855285519081516003811015610893576001928260209392849352606060ff81610de7610dd58787015160808988015260808701906116ed565b604087015186820360408801526116ed565b940151169101529701950193920190610ce0565b909192835160ff81511682526020810151610e1581611642565b602083015260408101519060068210156108935782606060809260209460406001970152015160608201520194019101919091610c8c565b90919293602080610f43837ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec08a6001960301865288519060e0610f32610f20610eb4610ea486516101008752610100870190611526565b888701518682038a880152611526565b61ffff604087015116604086015273ffffffffffffffffffffffffffffffffffffffff60608701511660608601527fffffffff00000000000000000000000000000000000000000000000000000000608087015116608086015260a086015185820360a0870152611526565b60c085015184820360c0860152611526565b9201519060e08184039101526116ed565b960192019201909291610c42565b602090610f5c6116c9565b82828601015201610a19565b602090610f78979694959761164c565b828286010152019593929495610761565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7fc5019299000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b60406020858403011261102c5760405190604082019082821067ffffffffffffffff831117610f89576040926020928452865181528287015183820152815201930192610407565b5f80fd5b815167ffffffffffffffff811161102c576080868b01860182018a037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0011261102c576040519160208281888e61108688611439565b8b010101010151600381101561102c5783526060878c0187018301015167ffffffffffffffff811161102c57826020888e6110d48f846060978f92828787828c9401960101010101016115dd565b838901528b0101010101519067ffffffffffffffff821161102c5760209361112a608086958f8f8897918e61111b8f93948b808097019188828888880101010101016115dd565b604089015201010101016115cf565b6060820152815201920191905061036c565b60a06020848903011261102c57604051906111568261141d565b61115f846115cf565b82526020840151600481101561102c5760208301526040840151600681101561102c576040830152606084015190600482101561102c5782602092606060a0950152608086015160808201528152019201916102ea565b835167ffffffffffffffff811161102c578201610120818a031261102c5760405191610120830183811067ffffffffffffffff821117610f8957604052602082015167ffffffffffffffff811161102c57611219906020808d0191850101611569565b8352604082015167ffffffffffffffff811161102c57611241906020808d0191850101611569565b6020840152606082015161ffff8116810361102c576040840152611267608083016115ae565b606084015260a08201517fffffffff000000000000000000000000000000000000000000000000000000008116810361102c57608084015260c082015167ffffffffffffffff811161102c576112c5906020808d0191850101611569565b60a084015260e082015167ffffffffffffffff811161102c5760209083010160208b01601f8201121561102c5780518b6112fe826114ed565b9261130c6040519485611472565b828452602080606081870195028301019201821161102c57602001915b8d8284106113a2575050505060c084015261010082015167ffffffffffffffff811161102c57611361906020808d0191850101611569565b60e08401526101208201519267ffffffffffffffff841161102c5761139160209493858095818f019201016115dd565b610100820152815201930192610279565b60208460609203011261102c57604051906060820182811067ffffffffffffffff821117610f89576040526113d6846115cf565b8252602084015190600282101561102c57826020928360609501526113fd604087016115cf565b6040820152815201920191611329565b81358152602091820191016101c3565b60a0810190811067ffffffffffffffff821117610f8957604052565b6080810190811067ffffffffffffffff821117610f8957604052565b610100810190811067ffffffffffffffff821117610f8957604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117610f8957604052565b67ffffffffffffffff8111610f8957601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b67ffffffffffffffff8111610f895760051b60200190565b5f5b8381106115165750505f910152565b8181015183820152602001611507565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f60209361156281518092818752878088019101611505565b0116010190565b81601f8201121561102c5760208151910190611584816114b3565b926115926040519485611472565b8184528183011161102c576115ab916020840190611505565b90565b519073ffffffffffffffffffffffffffffffffffffffff8216820361102c57565b519060ff8216820361102c57565b9080601f8301121561102c5781516115f4816114ed565b926116026040519485611472565b81845260208085019260051b82010192831161102c57602001905b82821061162a5750505090565b60208091611637846115cf565b81520191019061161d565b6004111561089357565b6040519061165982611455565b606060e0838281528260208201525f60408201525f838201525f60808201528260a08201528260c08201520152565b805182101561169c5760209160051b010190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b604051906116d682611439565b5f6060838281528260208201528260408201520152565b90602080835192838152019201905f5b81811061170a5750505090565b825160ff168452602093840193909201916001016116fd565b5f5b60c0820151805182101561175f5761173f82602092611688565b5101516002811015610893571561175857600101611725565b5050600190565b5050505f90565b9060206117f760018284519401516040519384918161178e8185019889815193849201611505565b83017f3a00000000000000000000000000000000000000000000000000000000000000838201526117c88251809385602185019101611505565b010103017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282611472565b51902073ffffffffffffffffffffffffffffffffffffffff604051927ff432b52e0000000000000000000000000000000000000000000000000000000084521660048301526024820152602081604481305afa90811561188f575f9161185b575090565b90506020813d602011611887575b8161187660209383611472565b8101031261102c576115ab906115ae565b3d9150611869565b6040513d5f823e3d90fdfea2646970667358221220f4075903b067136f6fb2d484a54ab0ac59336245b2c21b39476a6650c10a60bc64736f6c634300081a0033","output":"0x60806040526004361015610011575f80fd5b5f3560e01c6319317cc514610024575f80fd5b60407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261102c5760043567ffffffffffffffff811161102c573660238201121561102c5780600401359061007a826114b3565b916100886040519384611472565b8083526020830191366024838301011161102c57815f926024602093018537840101526024359067ffffffffffffffff821161102c5760c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc833603011261102c576040519160c0830183811067ffffffffffffffff821117610f8957604052806004013573ffffffffffffffffffffffffffffffffffffffff8116810361102c57835260248101356020840152604481013565ffffffffffff8116810361102c576040840152606481013563ffffffff8116810361102c576060840152608481013567ffffffffffffffff811161102c5781013660238201121561102c57600481013590610196826114ed565b916101a46040519384611472565b808352602060048185019260051b840101019136831161102c57602401905b82821061140d57505050608084015260a4013560a0830152825183019060208483031261102c57519167ffffffffffffffff831161102c5760a084840183031261102c57604051936102148561141d565b6020848201015167ffffffffffffffff811161102c57602090858301010160208401601f8201121561102c57805161024b816114ed565b916102596040519384611472565b81835260208084019260051b8201019060208701821161102c5760208101925b8284106111b6575050505085526040848201015167ffffffffffffffff811161102c57602090858301010160208401601f8201121561102c5780516102bd816114ed565b916102cb6040519384611472565b818352602060a081850193028201019060208701821161102c57602001915b81831061113c575050506020860152606084820101519067ffffffffffffffff821161102c5760208401603f828701840101121561102c5760208286830101015191610335836114ed565b926103436040519485611472565b808452602084016020870160208360051b81868c8901010101011161102c576040848901840101905b6040858a018501600585901b010182106110305750505050604086019182526080858201015194600486101561102c576060870195865260a081830101519067ffffffffffffffff821161102c5760209201010160208401601f8201121561102c578051906103da826114ed565b946103e86040519687611472565b82865260208087019360061b8301019160208201831161102c57602001925b828410610fe4575050505082608086015260808201519384518451808203610fb65750505f5b85518110156104bc576104408187611688565b5161044b8287611688565b515113801561049b575b6104615760010161042d565b61046b8187611688565b51907f4b1b3452000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b506104a68187611688565b5160206104b38388611688565b51015112610455565b508573ffffffffffffffffffffffffffffffffffffffff845116815151927fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061051d610507866114ed565b956105156040519788611472565b8087526114ed565b013660208601375f5b8351805182101561058f579061054761054182600194611688565b51611723565b610552575b01610526565b610567610560828751611688565b5185611766565b73ffffffffffffffffffffffffffffffffffffffff6105868389611688565b9116905261054c565b5050945f5b60208401518051821015610654579060ff6105b182600194611688565b515116600360606105c68460208a0151611688565b5101516105d281611642565b6105db81611642565b148061062c575b6105ee575b5001610594565b73ffffffffffffffffffffffffffffffffffffffff61062261061b610614848a51611688565b5188611766565b9289611688565b91169052886105e7565b5073ffffffffffffffffffffffffffffffffffffffff61064c8289611688565b5116156105e2565b858386898b6040519160e0830183811067ffffffffffffffff821117610f89576040526060835260606020840152606060408401525f60608401525f60808401525f60a08401525f60c084015265ffffffffffff60408601511660a084015265ffffffffffff60408601511663ffffffff6060870151160167ffffffffffffffff81116108f05767ffffffffffffffff9096949395961660c086015260a086015160808601525160408501525161070a81611642565b61071381611642565b60608401528051517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061075e610748836114ed565b926107566040519485611472565b8084526114ed565b015f5b818110610f6857505083525f915b815180518410156109df578361078491611688565b519360808601519573ffffffffffffffffffffffffffffffffffffffff6107ab8685611688565b5116936107b661164c565b5060a0870151936108086020604051876107d98299518092858086019101611505565b810103017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101875286611472565b5f5b60c0890151805182101561091d578161082291611688565b518051909190600581901b611fe016602081019081106108f0578851106108c0576020830151926002841015610893578c600194155f146108755750506020611fe08a925b60051b16890101520161080a565b61088c611fe09160ff604060209501511690611688565b5192610867565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b50887fb2159785000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5050975094809294506109d4919660019481519160208101519161ffff60408301511673ffffffffffffffffffffffffffffffffffffffff6060840151167fffffffff000000000000000000000000000000000000000000000000000000006080850151169161010060e0860151950151956040519761099c89611455565b8852602088015260408701526060860152608085015260a084015260c083015260e08201528551906109ce8383611688565b52611688565b50019190929361076f565b848383886020830151517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0610a16610748836114ed565b015f5b818110610f5157505060208501525f5b60208401518051821015610c0c5781610a4191611688565b5190610a4b6116c9565b5060808201908151916060840160018151610a6581611642565b610a6e81611642565b03610b8d57509091505160208401518115610b6057817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0410610b345760208401518181029181830414901517156108f0576127109004905b60ff835116926040602082015191610ade83611642565b015190600682101561089357602094600194610b2b93859360405193610b0385611439565b8452610b0e81611642565b8884015260408301526060820152858a0151906109ce8383611688565b50019050610a29565b507fc7764ffa000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b60028151610b9a81611642565b610ba381611642565b03610bc35750610bbc9192506080850151905190611688565b5190610ac7565b6003915051610bd181611642565b610bda81611642565b03610ac757905073ffffffffffffffffffffffffffffffffffffffff610c0460ff84511686611688565b511690610ac7565b85604051602080820152610120810182519060e06040840152815180915261014083019060206101408260051b8601019301915f905b828210610e4d57505050506020830151907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0838203016060840152602080835192838152019201905f5b818110610dfb575050506040830151907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0838203016080840152815180825260208201906020808260051b8501019401925f905b828210610d7157610d6d87610d59818967ffffffffffffffff60c08e6060810151610d0a81611642565b60a08601526080810151828601528260a08201511660e0860152015116610100830152037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282611472565b604051918291602083526020830190611526565b0390f35b90919293947fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082820301855285519081516003811015610893576001928260209392849352606060ff81610de7610dd58787015160808988015260808701906116ed565b604087015186820360408801526116ed565b940151169101529701950193920190610ce0565b909192835160ff81511682526020810151610e1581611642565b602083015260408101519060068210156108935782606060809260209460406001970152015160608201520194019101919091610c8c565b90919293602080610f43837ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec08a6001960301865288519060e0610f32610f20610eb4610ea486516101008752610100870190611526565b888701518682038a880152611526565b61ffff604087015116604086015273ffffffffffffffffffffffffffffffffffffffff60608701511660608601527fffffffff00000000000000000000000000000000000000000000000000000000608087015116608086015260a086015185820360a0870152611526565b60c085015184820360c0860152611526565b9201519060e08184039101526116ed565b960192019201909291610c42565b602090610f5c6116c9565b82828601015201610a19565b602090610f78979694959761164c565b828286010152019593929495610761565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7fc5019299000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b60406020858403011261102c5760405190604082019082821067ffffffffffffffff831117610f89576040926020928452865181528287015183820152815201930192610407565b5f80fd5b815167ffffffffffffffff811161102c576080868b01860182018a037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0011261102c576040519160208281888e61108688611439565b8b010101010151600381101561102c5783526060878c0187018301015167ffffffffffffffff811161102c57826020888e6110d48f846060978f92828787828c9401960101010101016115dd565b838901528b0101010101519067ffffffffffffffff821161102c5760209361112a608086958f8f8897918e61111b8f93948b808097019188828888880101010101016115dd565b604089015201010101016115cf565b6060820152815201920191905061036c565b60a06020848903011261102c57604051906111568261141d565b61115f846115cf565b82526020840151600481101561102c5760208301526040840151600681101561102c576040830152606084015190600482101561102c5782602092606060a0950152608086015160808201528152019201916102ea565b835167ffffffffffffffff811161102c578201610120818a031261102c5760405191610120830183811067ffffffffffffffff821117610f8957604052602082015167ffffffffffffffff811161102c57611219906020808d0191850101611569565b8352604082015167ffffffffffffffff811161102c57611241906020808d0191850101611569565b6020840152606082015161ffff8116810361102c576040840152611267608083016115ae565b606084015260a08201517fffffffff000000000000000000000000000000000000000000000000000000008116810361102c57608084015260c082015167ffffffffffffffff811161102c576112c5906020808d0191850101611569565b60a084015260e082015167ffffffffffffffff811161102c5760209083010160208b01601f8201121561102c5780518b6112fe826114ed565b9261130c6040519485611472565b828452602080606081870195028301019201821161102c57602001915b8d8284106113a2575050505060c084015261010082015167ffffffffffffffff811161102c57611361906020808d0191850101611569565b60e08401526101208201519267ffffffffffffffff841161102c5761139160209493858095818f019201016115dd565b610100820152815201930192610279565b60208460609203011261102c57604051906060820182811067ffffffffffffffff821117610f89576040526113d6846115cf565b8252602084015190600282101561102c57826020928360609501526113fd604087016115cf565b6040820152815201920191611329565b81358152602091820191016101c3565b60a0810190811067ffffffffffffffff821117610f8957604052565b6080810190811067ffffffffffffffff821117610f8957604052565b610100810190811067ffffffffffffffff821117610f8957604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117610f8957604052565b67ffffffffffffffff8111610f8957601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b67ffffffffffffffff8111610f895760051b60200190565b5f5b8381106115165750505f910152565b8181015183820152602001611507565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f60209361156281518092818752878088019101611505565b0116010190565b81601f8201121561102c5760208151910190611584816114b3565b926115926040519485611472565b8184528183011161102c576115ab916020840190611505565b90565b519073ffffffffffffffffffffffffffffffffffffffff8216820361102c57565b519060ff8216820361102c57565b9080601f8301121561102c5781516115f4816114ed565b926116026040519485611472565b81845260208085019260051b82010192831161102c57602001905b82821061162a5750505090565b60208091611637846115cf565b81520191019061161d565b6004111561089357565b6040519061165982611455565b606060e0838281528260208201525f60408201525f838201525f60808201528260a08201528260c08201520152565b805182101561169c5760209160051b010190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b604051906116d682611439565b5f6060838281528260208201528260408201520152565b90602080835192838152019201905f5b81811061170a5750505090565b825160ff168452602093840193909201916001016116fd565b5f5b60c0820151805182101561175f5761173f82602092611688565b5101516002811015610893571561175857600101611725565b5050600190565b5050505f90565b9060206117f760018284519401516040519384918161178e8185019889815193849201611505565b83017f3a00000000000000000000000000000000000000000000000000000000000000838201526117c88251809385602185019101611505565b010103017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282611472565b51902073ffffffffffffffffffffffffffffffffffffffff604051927ff432b52e0000000000000000000000000000000000000000000000000000000084521660048301526024820152602081604481305afa90811561188f575f9161185b575090565b90506020813d602011611887575b8161187660209383611472565b8101031261102c576115ab906115ae565b3d9150611869565b6040513d5f823e3d90fdfea2646970667358221220f4075903b067136f6fb2d484a54ab0ac59336245b2c21b39476a6650c10a60bc64736f6c634300081a0033","gas_used":1271740,"gas_limit":1073591220,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]}]}],["Deployment",{"arena":[{"parent":null,"children":[1,2,3,4,5,6,7,8,9,10,11,12,13,14],"idx":0,"trace":{"depth":0,"success":true,"caller":"0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38","address":"0x7fa9385be102ac3eac297483dd6233d62b3e1496","maybe_precompile":false,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CREATE","value":"0x0","data":"0x6080604052346109e4575f600160ff19600c541617600c55600160ff19601f541617601f55604051610032604082610a2a565b60158152602081017f6b65726e656c50726f787941646d696e4f776e65720000000000000000000000815260405160208101906100896020828651610078818789610a61565b81010301601f198101835282610a2a565b5190206040519063ffa1864960e01b825260048201526020816024815f8051602061e7318339815191525afa9081156109d9575f916109e8575b505f8051602061e7318339815191523b156109e45761011960645f9260405194859384926318caf8e360e31b845260018060a01b0316978860048501526040602485015251809281604486015285850190610a61565b601f01601f19168101030181835f8051602061e7318339815191525af180156109d9576109c4575b5060018060a01b03196022541617602255604051610160604082610a2a565b6005815281602082016430b236b4b760d91b8152604051602081019061018f6020828751610078818789610a61565b5190206040519063ffa1864960e01b825260048201526020816024815f8051602061e7318339815191525afa908115610802578391610982575b505f8051602061e7318339815191523b156107bc5761021f6064849260405194859384926318caf8e360e31b845260018060a01b0316988960048501526040602485015251809281604486015285850190610a61565b601f01601f19168101030181835f8051602061e7318339815191525af180156107b15761096d575b505060018060a01b03196023541617602355604051610267604082610a2a565b60088152816020820167747265617375727960c01b815260405160208101906102996020828751610078818789610a61565b5190206040519063ffa1864960e01b825260048201526020816024815f8051602061e7318339815191525afa90811561080257839161092b575b505f8051602061e7318339815191523b156107bc576103296064849260405194859384926318caf8e360e31b845260018060a01b0316988960048501526040602485015251809281604486015285850190610a61565b601f01601f19168101030181835f8051602061e7318339815191525af180156107b157610916575b505060018060a01b03196024541617602455604051610371604082610a2a565b6006815281602082016518db1a595b9d60d21b815260405160208101906103a16020828751610078818789610a61565b5190206040519063ffa1864960e01b825260048201526020816024815f8051602061e7318339815191525afa9081156108025783916108d4575b505f8051602061e7318339815191523b156107bc576104316064849260405194859384926318caf8e360e31b845260018060a01b0316988960048501526040602485015251809281604486015285850190610a61565b601f01601f19168101030181835f8051602061e7318339815191525af180156107b1576108bf575b505060018060a01b03196025541617602555604051610479604082610a2a565b60088152816020820167383937bb34b232b960c11b815260405160208101906104ab6020828751610078818789610a61565b5190206040519063ffa1864960e01b825260048201526020816024815f8051602061e7318339815191525afa90811561080257839161087d575b505f8051602061e7318339815191523b156107bc5761053b6064849260405194859384926318caf8e360e31b845260018060a01b0316988960048501526040602485015251809281604486015285850190610a61565b601f01601f19168101030181835f8051602061e7318339815191525af180156107b157610868575b505060018060a01b03196026541617602655604051610583604082610a2a565b6009815281602082016832bb30b63ab0ba37b960b91b815260405160208101906105b66020828751610078818789610a61565b5190206040519063ffa1864960e01b825260048201526020816024815f8051602061e7318339815191525afa908115610802578391610826575b505f8051602061e7318339815191523b156107bc576106466064849260405194859384926318caf8e360e31b845260018060a01b0316988960048501526040602485015251809281604486015285850190610a61565b601f01601f19168101030181835f8051602061e7318339815191525af180156107b15761080d575b505060018060a01b031960275416176027556040519061068f604083610a2a565b60088252602082016739ba3930b733b2b960c11b815260405160208101906106c06020828751610078818789610a61565b5190206040519063ffa1864960e01b825260048201526020816024815f8051602061e7318339815191525afa9081156108025783916107c0575b505f8051602061e7318339815191523b156107bc576107506064849260405194859384926318caf8e360e31b845260018060a01b0316988960048501526040602485015251809281604486015285850190610a61565b601f01601f19168101030181835f8051602061e7318339815191525af180156107b157610799575b602880546001600160a01b0319168417905560405161dcae9081610a838239f35b6107a4828092610a2a565b6107ae5780610778565b80fd5b6040513d84823e3d90fd5b8280fd5b90506020813d6020116107fa575b816107db60209383610a2a565b810103126107bc57516001600160a01b03811681036107bc575f6106fa565b3d91506107ce565b6040513d85823e3d90fd5b8161081791610a2a565b61082257815f61066e565b5080fd5b90506020813d602011610860575b8161084160209383610a2a565b810103126107bc57516001600160a01b03811681036107bc575f6105f0565b3d9150610834565b8161087291610a2a565b61082257815f610563565b90506020813d6020116108b7575b8161089860209383610a2a565b810103126107bc57516001600160a01b03811681036107bc575f6104e5565b3d915061088b565b816108c991610a2a565b61082257815f610459565b90506020813d60201161090e575b816108ef60209383610a2a565b810103126107bc57516001600160a01b03811681036107bc575f6103db565b3d91506108e2565b8161092091610a2a565b61082257815f610351565b90506020813d602011610965575b8161094660209383610a2a565b810103126107bc57516001600160a01b03811681036107bc575f6102d3565b3d9150610939565b8161097791610a2a565b61082257815f610247565b90506020813d6020116109bc575b8161099d60209383610a2a565b810103126107bc57516001600160a01b03811681036107bc575f6101c9565b3d9150610990565b6109d19192505f90610a2a565b5f905f610141565b6040513d5f823e3d90fd5b5f80fd5b90506020813d602011610a22575b81610a0360209383610a2a565b810103126109e457516001600160a01b03811681036109e4575f6100c3565b3d91506109f6565b601f909101601f19168101906001600160401b03821190821017610a4d57604052565b634e487b7160e01b5f52604160045260245ffd5b5f5b838110610a725750505f910152565b8181015183820152602001610a6356fe6080806040526004361015610012575f80fd5b5f905f3560e01c9081630a9254e414611355575080631ed7831c146112ac5780632ade3880146110805780633e5e3c2314610fd75780633f7286f414610f2e57806347853bb914610ef75780634d657a1e14610ec057806366d9a9a014610d6557806385226c8114610cbd578063916a17c614610be8578063b0464fdc14610b13578063b5508aa914610a6b578063ba414fa614610a28578063c5c988ca1461020f578063d87d4feb146101d5578063e20c9f711461011c5763fa7626d4146100d9575f80fd5b3461011957807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261011957602060ff601f54166040519015158152f35b80fd5b503461011957807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101195760405180916020601554928381520191601582527f55f448fdea98c4d29eb340757ef0a66cd03dbb9538908a6a81d96026b71ec475915b8181106101a9576101a58561019981870382611ea7565b60405191829182611c35565b0390f35b825473ffffffffffffffffffffffffffffffffffffffff16845260209093019260019283019201610182565b503461011957807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101195761020c61273e565b80f35b503461011957807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261011957805b61025881106104b0575073ffffffffffffffffffffffffffffffffffffffff602954166040517f7f974c6f000000000000000000000000000000000000000000000000000000008152602081600481855afa9081156104a5578391610473575b506102e36040918251906102b48483611ea7565b601282527f6e6f207375636365737366756c2066756e6400000000000000000000000000006020830152612ad4565b80517f05e3769c000000000000000000000000000000000000000000000000000000008152602081600481865afa908115610469578491610436575b506004926103646020928451906103368683611ea7565b601682527f6e6f207375636365737366756c20636f6d706c6574650000000000000000000085830152612ad4565b8251938480927f59e136190000000000000000000000000000000000000000000000000000000082525afa801561042c5783906103f4575b6103dc92506103ad82519283611ea7565b601982527f6e6f207375636365737366756c20726566756e642070617468000000000000006020830152612ad4565b6103e461273e565b6103ec61221d565b61020c61208e565b506020823d602011610424575b8161040e60209383611ea7565b81010312610420576103dc915161039c565b5f80fd5b3d9150610401565b81513d85823e3d90fd5b90506020813d602011610461575b8161045160209383611ea7565b810103126104205751600461031f565b3d9150610444565b82513d86823e3d90fd5b90506020813d60201161049d575b8161048e60209383611ea7565b8101031261042057515f6102a0565b3d9150610481565b6040513d85823e3d90fd5b816040516020810190838252602081526104cb604082611ea7565b519020600a8106806105a3575073ffffffffffffffffffffffffffffffffffffffff6029541690813b1561059f57600160c484928360405195869485937f8253f2d90000000000000000000000000000000000000000000000000000000085528060048601528060081c60248601528060101c60448601528060181c6064860152818160201c1615608486015260281c161560a48401525af180156105945761057b575b50506001905b01610240565b8161058591611ea7565b61059057815f61056f565b5080fd5b6040513d84823e3d90fd5b8280fd5b60018103610638575073ffffffffffffffffffffffffffffffffffffffff6029541690813b1561059f5782916044839260405194859384927f725cc2e100000000000000000000000000000000000000000000000000000000845280600485015260081c60248401525af1801561059457610623575b5050600190610575565b8161062d91611ea7565b61059057815f610619565b600281036106b7575073ffffffffffffffffffffffffffffffffffffffff6029541690813b1561059f5782916044839260405194859384927f9675dc1700000000000000000000000000000000000000000000000000000000845280600485015260081c60248401525af1801561059457610623575050600190610575565b60038103610739575073ffffffffffffffffffffffffffffffffffffffff6029541690813b1561059f5782916064839260405194859384927f81ede1bb00000000000000000000000000000000000000000000000000000000845260048401528160248401528160448401525af1801561059457610623575050600190610575565b600481036107bb575073ffffffffffffffffffffffffffffffffffffffff6029541690813b1561059f5782916064839260405194859384927fd130382500000000000000000000000000000000000000000000000000000000845260048401528160248401528160448401525af1801561059457610623575050600190610575565b6005810361083d575073ffffffffffffffffffffffffffffffffffffffff6029541690813b1561059f5782916064839260405194859384927ffd61a25600000000000000000000000000000000000000000000000000000000845260048401528160248401528160448401525af1801561059457610623575050600190610575565b600681036108c5575073ffffffffffffffffffffffffffffffffffffffff6029541690813b1561059f576001606484928360405195869485937f531c7faa00000000000000000000000000000000000000000000000000000000855280600486015260081c161560248401528160448401525af1801561059457610623575050600190610575565b6007810361093b575073ffffffffffffffffffffffffffffffffffffffff6029541690813b1561059f5782916024839260405194859384927f5b7baf6400000000000000000000000000000000000000000000000000000000845260048401525af1801561059457610623575050600190610575565b6008036109b25773ffffffffffffffffffffffffffffffffffffffff6029541690813b1561059f57612a30602484928360405195869485937fe5d6bf020000000000000000000000000000000000000000000000000000000085520660048401525af1801561059457610623575050600190610575565b73ffffffffffffffffffffffffffffffffffffffff6029541690813b1561059f5782916044839260405194859384927f0b78f9c000000000000000000000000000000000000000000000000000000000845280600485015260081c60248401525af1801561059457610623575050600190610575565b503461011957807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610119576020610a61612644565b6040519015158152f35b503461011957807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261011957601954610aa681611ee8565b91610ab46040519384611ea7565b818352601981527f944998273e477b495144fb8794c914197f3ccb46be2900f4698fd0ef743c9695602084015b838310610af657604051806101a58782611d3d565b600160208192610b0585611f00565b815201920192019190610ae1565b503461011957807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261011957601c54610b4e81611ee8565b91610b5c6040519384611ea7565b818352601c81527f0e4562a10381dec21b205ed72637e6b1b523bdd0e4d4d50af5cd23dd4500a211602084015b838310610b9e57604051806101a58782611dba565b60026020600192604051610bb181611e5e565b73ffffffffffffffffffffffffffffffffffffffff8654168152610bd68587016123a0565b83820152815201920192019190610b89565b503461011957807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261011957601d54610c2381611ee8565b91610c316040519384611ea7565b818352601d81527f6d4407e7be21f808e6509aa9fa9143369579dd7d760fe20a2c09680fc146134f602084015b838310610c7357604051806101a58782611dba565b60026020600192604051610c8681611e5e565b73ffffffffffffffffffffffffffffffffffffffff8654168152610cab8587016123a0565b83820152815201920192019190610c5e565b503461011957807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261011957601a54610cf881611ee8565b91610d066040519384611ea7565b818352601a81527f057c384a7d1c54f3a1b2e5e67b2617b8224fdfd1ea7234eea573a6ff665ff63e602084015b838310610d4857604051806101a58782611d3d565b600160208192610d5785611f00565b815201920192019190610d33565b503461011957807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261011957601b54610da081611ee8565b610dad6040519182611ea7565b818152601b83526020810191837f3ad8aa4f87544323a9d1e5dd902f40c356527a7955687113db5f9a85ad579dc1845b838310610e8557868587604051928392602084019060208552518091526040840160408260051b8601019392905b828210610e1a57505050500390f35b91936020610e75827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0600195979984950301865288519083610e658351604084526040840190611ca5565b9201519084818403910152611ce8565b9601920192018594939192610e0b565b60026020600192604051610e9881611e5e565b610ea186611f00565b8152610eae8587016123a0565b83820152815201920192019190610ddd565b503461011957807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101195761020c61221d565b503461011957807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101195761020c61208e565b503461011957807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101195760405180916020601754928381520191601782527fc624b66cc0138b8fabc209247f72d758e1cf3343756d543badbf24212bed8c15915b818110610fab576101a58561019981870382611ea7565b825473ffffffffffffffffffffffffffffffffffffffff16845260209093019260019283019201610f94565b503461011957807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101195760405180916020601854928381520191601882527fb13d2d76d1f4b7be834882e410b3e3a8afaf69f83600ae24db354391d2378d2e915b818110611054576101a58561019981870382611ea7565b825473ffffffffffffffffffffffffffffffffffffffff1684526020909301926001928301920161103d565b503461011957807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261011957601e546110bb81611ee8565b6110c86040519182611ea7565b818152601e83526020810191837f50bb669a95c7b50b7e8a6f09454034b2b14cf2b85c730dca9a539ca82cb6e350845b8383106112165786858760405192839260208401906020855251809152604084019160408260051b8601019392815b8383106111345786860387f35b9193957fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc09086929496030183528551906020604082019273ffffffffffffffffffffffffffffffffffffffff81511683520151916040602083015282518091526060820190602060608260051b850101940192855b8281106111cd57505050505060208060019297019301930190928695949293611127565b9091929394602080611209837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa087600196030189528951611ca5565b97019501939291016111a9565b60405161122281611e5e565b73ffffffffffffffffffffffffffffffffffffffff835416815260018301805461124b81611ee8565b916112596040519384611ea7565b8183528a526020808b20908b9084015b83821061128f5750505050600192826020928360029501528152019201920191906110f8565b60016020819261129e86611f00565b815201930191019091611269565b503461011957807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101195760405180916020601654928381520191601682527fd833147d7dc355ba459fc788f669e58cfaf9dc25ddcd0702e87d69c7b5124289915b818110611329576101a58561019981870382611ea7565b825473ffffffffffffffffffffffffffffffffffffffff16845260209093019260019283019201611312565b905034610420575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261042057737109709ecfa91a80626ff3989d68f67f5b1dd12d3b15610420577fe5d6bf02000000000000000000000000000000000000000000000000000000008152636553f10060048201525f8160248183737109709ecfa91a80626ff3989d68f67f5b1dd12d5af18015611c2a57611c17575b50604051610e1e8082019082821067ffffffffffffffff831117611b5d5760c091839161be71833960408152600960408201527f5075736820555344430000000000000000000000000000000000000000000000606082015260806020820152600560808201527f705553444300000000000000000000000000000000000000000000000000000060a082015203019082f08015611af95773ffffffffffffffffffffffffffffffffffffffff167fffffffffffffffffffffffff0000000000000000000000000000000000000000602154161760215560405161389f8082019082821067ffffffffffffffff831117611b5d579082916139918339039082f08015611af95773ffffffffffffffffffffffffffffffffffffffff16807fffffffffffffffffffffffff0000000000000000000000000000000000000000602054161760205573ffffffffffffffffffffffffffffffffffffffff6021541673ffffffffffffffffffffffffffffffffffffffff6024541673ffffffffffffffffffffffffffffffffffffffff6023541690604051927fc0c53b8b000000000000000000000000000000000000000000000000000000006020850152602484015260448301526064820152606481526115cf608482611ea7565b73ffffffffffffffffffffffffffffffffffffffff602254169160405192610e54918285019285841067ffffffffffffffff851117611bea579285949260609261162c95612b3d8839825260208201528160408201520190611ca5565b039082f08015611af9577fffffffffffffffffffffff0000000000000000000000000000000000000000ff74ffffffffffffffffffffffffffffffffffffffff00601f549260081b16911617601f558073ffffffffffffffffffffffffffffffffffffffff6021541673ffffffffffffffffffffffffffffffffffffffff60255416813b15611be65782916044839260405194859384927f40c10f19000000000000000000000000000000000000000000000000000000008452600484015266038d7ea4c6800060248401525af1801561059457611bd1575b5073ffffffffffffffffffffffffffffffffffffffff60255416737109709ecfa91a80626ff3989d68f67f5b1dd12d3b15611bce57604051907fca669fa70000000000000000000000000000000000000000000000000000000082526004820152818160248183737109709ecfa91a80626ff3989d68f67f5b1dd12d5af1801561059457611bb9575b50602073ffffffffffffffffffffffffffffffffffffffff60215416604473ffffffffffffffffffffffffffffffffffffffff601f5460081c1660405194859384927f095ea7b300000000000000000000000000000000000000000000000000000000845260048401527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60248401525af1801561059457611b8a575b50604051610fea8082019082821067ffffffffffffffff831117611b5d5790829161cc8f8339039082f08015611af9578173ffffffffffffffffffffffffffffffffffffffff60235416737109709ecfa91a80626ff3989d68f67f5b1dd12d3b1561059057604051907fca669fa70000000000000000000000000000000000000000000000000000000082526004820152818160248183737109709ecfa91a80626ff3989d68f67f5b1dd12d5af1801561059457611b48575b5073ffffffffffffffffffffffffffffffffffffffff80601f5460081c16921691803b15610590578180916044604051809481937fce79eb60000000000000000000000000000000000000000000000000000000008352886004840152600160248401525af1801561059457611b33575b505073ffffffffffffffffffffffffffffffffffffffff601f5460081c1673ffffffffffffffffffffffffffffffffffffffff602154169173ffffffffffffffffffffffffffffffffffffffff6023541660405193614c41938486019486861067ffffffffffffffff871117611b06579160809593918795936172308739845260208401526040830152606082015203019082f08015611af95773ffffffffffffffffffffffffffffffffffffffff16807fffffffffffffffffffffffff0000000000000000000000000000000000000000602954161760295560175468010000000000000000811015611acc576001810180601755811015611a9f577fc624b66cc0138b8fabc209247f72d758e1cf3343756d543badbf24212bed8c1501907fffffffffffffffffffffffff000000000000000000000000000000000000000082541617905580f35b6024837f4e487b710000000000000000000000000000000000000000000000000000000081526032600452fd5b6024837f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b50604051903d90823e3d90fd5b6024887f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b81611b3d91611ea7565b61059057815f611955565b81611b5291611ea7565b61059057815f6118e4565b6024847f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b611bab9060203d602011611bb2575b611ba38183611ea7565b810190612003565b505f61182b565b503d611b99565b81611bc391611ea7565b61011957805f61178e565b50fd5b81611bdb91611ea7565b61011957805f611705565b5050fd5b6024877f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b611c2391505f90611ea7565b5f806113f5565b6040513d5f823e3d90fd5b60206040818301928281528451809452019201905f5b818110611c585750505090565b825173ffffffffffffffffffffffffffffffffffffffff16845260209384019390920191600101611c4b565b5f5b838110611c955750505f910152565b8181015183820152602001611c86565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602093611ce181518092818752878088019101611c84565b0116010190565b90602080835192838152019201905f5b818110611d055750505090565b82517fffffffff0000000000000000000000000000000000000000000000000000000016845260209384019390920191600101611cf8565b602081016020825282518091526040820191602060408360051b8301019401925f915b838310611d6f57505050505090565b9091929394602080611dab837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc086600196030187528951611ca5565b97019301930191939290611d60565b602081016020825282518091526040820191602060408360051b8301019401925f915b838310611dec57505050505090565b9091929394602080611e4f837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc086600196030187526040838b5173ffffffffffffffffffffffffffffffffffffffff815116845201519181858201520190611ce8565b97019301930191939290611ddd565b6040810190811067ffffffffffffffff821117611e7a57604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117611e7a57604052565b67ffffffffffffffff8111611e7a5760051b60200190565b90604051915f8154908160011c9260018316928315611ff9575b602085108414611fcc578487528693908115611f8c5750600114611f48575b50611f4692500383611ea7565b565b90505f9291925260205f20905f915b818310611f70575050906020611f46928201015f611f39565b6020919350806001915483858901015201910190918492611f57565b60209350611f469592507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091501682840152151560051b8201015f611f39565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b93607f1693611f1a565b90816020910312610420575180151581036104205790565b81601f8201121561042057805167ffffffffffffffff8111611e7a576040519261206d601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200185611ea7565b818452602082840101116104205761208b9160208085019101611c84565b90565b73ffffffffffffffffffffffffffffffffffffffff60295416604051907fe662e387000000000000000000000000000000000000000000000000000000008252602082600481845afa908115611c2a576004925f926121fa575b505f90604051938480927f087320b20000000000000000000000000000000000000000000000000000000082525afa918215611c2a575f926121ba575b50737109709ecfa91a80626ff3989d68f67f5b1dd12d3b156104205761218a915f9160405193849283927f7ba0480900000000000000000000000000000000000000000000000000000000845215156004840152604060248401526044830190611ca5565b0381737109709ecfa91a80626ff3989d68f67f5b1dd12d5afa8015611c2a576121b05750565b5f611f4691611ea7565b9091503d805f833e6121cc8183611ea7565b810160208282031261042057815167ffffffffffffffff8111610420576121f3920161201b565b905f612125565b5f9192506122169060203d602011611bb257611ba38183611ea7565b91906120e8565b73ffffffffffffffffffffffffffffffffffffffff602154602082601f5460081c16916024604051809581937f70a08231000000000000000000000000000000000000000000000000000000008352866004840152165afa918215611c2a575f9261236b575b506020600491604051928380927ff91682310000000000000000000000000000000000000000000000000000000082525afa908115611c2a575f91612339575b50737109709ecfa91a80626ff3989d68f67f5b1dd12d3b1561042057604051917fa8d4d1d9000000000000000000000000000000000000000000000000000000008352600483015260248201525f81604481737109709ecfa91a80626ff3989d68f67f5b1dd12d5afa8015611c2a576121b05750565b90506020813d602011612363575b8161235460209383611ea7565b8101031261042057515f6122c3565b3d9150612347565b9091506020813d602011612398575b8161238760209383611ea7565b810103126104205751906020612283565b3d915061237a565b90604051918281549182825260208201905f5260205f20925f905b8060078301106125b757611f46945491818110612581575b81811061254b575b818110612515575b8181106124df575b8181106124a9575b818110612473575b81811061243e575b10612411575b500383611ea7565b7fffffffff000000000000000000000000000000000000000000000000000000001681526020015f612409565b9260206001917fffffffff0000000000000000000000000000000000000000000000000000000085831b168152019301612403565b9260206001917fffffffff000000000000000000000000000000000000000000000000000000008560401b1681520193016123fb565b9260206001917fffffffff000000000000000000000000000000000000000000000000000000008560601b1681520193016123f3565b9260206001917fffffffff000000000000000000000000000000000000000000000000000000008560801b1681520193016123eb565b9260206001917fffffffff000000000000000000000000000000000000000000000000000000008560a01b1681520193016123e3565b9260206001917fffffffff000000000000000000000000000000000000000000000000000000008560c01b1681520193016123db565b9260206001917fffffffff000000000000000000000000000000000000000000000000000000008560e01b1681520193016123d3565b9160089193506101006001917fffffffff000000000000000000000000000000000000000000000000000000008754818160e01b168352818160c01b166020840152818160a01b166040840152818160801b166060840152818160601b166080840152818160401b1660a0840152818160201b1660c08401521660e08201520194019201859293916123bb565b60085460ff1680156126535790565b506040517f667f9d70000000000000000000000000000000000000000000000000000000008152737109709ecfa91a80626ff3989d68f67f5b1dd12d60048201527f6661696c656400000000000000000000000000000000000000000000000000006024820152602081604481737109709ecfa91a80626ff3989d68f67f5b1dd12d5afa908115611c2a575f916126eb575b50151590565b90506020813d602011612715575b8161270660209383611ea7565b8101031261042057515f6126e5565b3d91506126f9565b519073ffffffffffffffffffffffffffffffffffffffff8216820361042057565b5f73ffffffffffffffffffffffffffffffffffffffff601f5460081c166040517f50355d76000000000000000000000000000000000000000000000000000000008152602081600481855afa908115611c2a575f91612aa2575b5060015b81811115612890575050906020600492604051938480927ff91682310000000000000000000000000000000000000000000000000000000082525afa918215611c2a575f9261285c575b50737109709ecfa91a80626ff3989d68f67f5b1dd12d3b1561042057604051917f98296c54000000000000000000000000000000000000000000000000000000008352600483015260248201525f81604481737109709ecfa91a80626ff3989d68f67f5b1dd12d5afa8015611c2a576121b05750565b9091506020813d602011612888575b8161287860209383611ea7565b810103126104205751905f6127e6565b3d915061286b565b6040517fbf22c4570000000000000000000000000000000000000000000000000000000081528160048201525f81602481875afa908115611c2a575f916129aa575b50602081018051600681101561297d57600114908115612968575b50612950575b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146129235760010161279c565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b60c0909491940151810180911161292357925f6128f3565b905051600681101561297d576002145f6128ed565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b90503d805f833e6129bb8183611ea7565b8101906020818303126104205780519067ffffffffffffffff82116104205701610100818303126104205760405191610100830183811067ffffffffffffffff821117611e7a57604052612a0e8261271d565b835260208201516006811015610420576020840152612a2f6040830161271d565b6040840152606082015165ffffffffffff81168103610420576060840152612a596080830161271d565b6080840152612a6a60a0830161271d565b60a084015260c082015160c084015260e082015167ffffffffffffffff811161042057612a97920161201b565b60e08201525f6128d2565b90506020813d602011612acc575b81612abd60209383611ea7565b8101031261042057515f612798565b3d9150612ab0565b737109709ecfa91a80626ff3989d68f67f5b1dd12d3b156104205761218a915f9160405193849283927fd9a3c4d20000000000000000000000000000000000000000000000000000000084526004840152846024840152606060448401526064830190611ca556fe60a0604052610e548038038061001481610281565b928339810160608282031261027d5761002c826102a6565b610038602084016102a6565b604084015190936001600160401b03821161027d570182601f8201121561027d5780519061006d610068836102ba565b610281565b938285526020838301011161027d575f5b82811061026857505060205f9184010152803b15610248577f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0383169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a2815115610231575f8083602061013095519101845af43d15610229573d91610121610068846102ba565b9283523d5f602085013e6102d5565b505b6040519061064f8083016001600160401b038111848210176102155760209284926107e584396001600160a01b031681520301905ff0801561020a5760018060a01b0316806080525f80516020610e34833981519152547f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6040805160018060a01b0384168152846020820152a181156101f7576001600160a01b031916175f80516020610e34833981519152556040516104b1908161033482396080518160070152f35b633173bdd160e11b5f525f60045260245ffd5b6040513d5f823e3d90fd5b634e487b7160e01b5f52604160045260245ffd5b6060916102d5565b505034156101325763b398979f60e01b5f5260045ffd5b634c9c8ce360e01b5f9081526001600160a01b0391909116600452602490fd5b8060208092840101518282880101520161007e565b5f80fd5b6040519190601f01601f191682016001600160401b0381118382101761021557604052565b51906001600160a01b038216820361027d57565b6001600160401b03811161021557601f01601f191660200190565b906102f957508051156102ea57805190602001fd5b63d6bda27560e01b5f5260045ffd5b8151158061032a575b61030a575090565b639996b31560e01b5f9081526001600160a01b0391909116600452602490fd5b50803b1561030256fe6080604052337f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16036100bd575f357fffffffff00000000000000000000000000000000000000000000000000000000167f4f1ef28600000000000000000000000000000000000000000000000000000000146100b3577fd2b576ec000000000000000000000000000000000000000000000000000000005f5260045ffd5b6100bb6101c1565b005b5f8073ffffffffffffffffffffffffffffffffffffffff7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5416368280378136915af43d5f803e1561010d573d5ff35b3d5ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f604051930116820182811067ffffffffffffffff82111761018257604052565b610111565b67ffffffffffffffff811161018257601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b366004116102745760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102745760043573ffffffffffffffffffffffffffffffffffffffff8116809103610274576024359067ffffffffffffffff821161027457366023830112156102745781600401359061024961024483610187565b61013e565b918083523660248286010111610274576020815f92602461027297018387013784010152610278565b565b5f80fd5b90813b156103675773ffffffffffffffffffffffffffffffffffffffff8216807fffffffffffffffffffffffff00000000000000000000000000000000000000007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5416177f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a280511561033657610333916103a9565b50565b50503461033f57565b7fb398979f000000000000000000000000000000000000000000000000000000005f5260045ffd5b73ffffffffffffffffffffffffffffffffffffffff827f4c9c8ce3000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b5f806103db93602081519101845af43d156103de573d916103cc61024484610187565b9283523d5f602085013e6103e2565b90565b6060915b9061041f57508051156103f757805190602001fd5b7fd6bda275000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580610472575b610430575090565b73ffffffffffffffffffffffffffffffffffffffff907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561042856fea2646970667358221220481cacafffcdffc0448fe9cfe96f8149f61f2083b69e100dc149c658ac2528fd64736f6c634300081a003360803460b857601f61064f38819003918201601f19168301916001600160401b0383118484101760bc5780849260209460405283398101031260b857516001600160a01b0381169081900360b857801560a5575f80546001600160a01b031981168317825560405192916001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a361057e90816100d18239f35b631e4fbdf760e01b5f525f60045260245ffd5b5f80fd5b634e487b7160e01b5f52604160045260245ffdfe60806040526004361015610011575f80fd5b5f803560e01c8063715018a6146103c45780638da5cb5b146103745780639623609d146101cb578063ad3cb1cc146101485763f2fde38b14610051575f80fd5b346101455760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101455760043573ffffffffffffffffffffffffffffffffffffffff8116809103610141576100a96104fc565b80156101155773ffffffffffffffffffffffffffffffffffffffff8254827fffffffffffffffffffffffff00000000000000000000000000000000000000008216178455167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b6024827f1e4fbdf700000000000000000000000000000000000000000000000000000000815280600452fd5b5080fd5b80fd5b503461014557807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261014557506101c760405161018960408261045e565b600581527f352e302e30000000000000000000000000000000000000000000000000000000602082015260405191829160208352602083019061049f565b0390f35b5060607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103435760043573ffffffffffffffffffffffffffffffffffffffff81168091036103435760243573ffffffffffffffffffffffffffffffffffffffff81168091036103435760443567ffffffffffffffff8111610343573660238201121561034357806004013567ffffffffffffffff8111610347576040519161029f601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0166020018461045e565b818352366024838301011161034357815f9260246020930183860137830101526102c76104fc565b823b1561034357610316925f926040518095819482937f4f1ef286000000000000000000000000000000000000000000000000000000008452600484015260406024840152604483019061049f565b039134905af180156103385761032a575080f35b61033691505f9061045e565b005b6040513d5f823e3d90fd5b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b34610343575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261034357602073ffffffffffffffffffffffffffffffffffffffff5f5416604051908152f35b34610343575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610343576103fa6104fc565b5f73ffffffffffffffffffffffffffffffffffffffff81547fffffffffffffffffffffffff000000000000000000000000000000000000000081168355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761034757604052565b91908251928382525f5b8481106104e75750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f845f6020809697860101520116010190565b806020809284010151828286010152016104a9565b73ffffffffffffffffffffffffffffffffffffffff5f5416330361051c57565b7f118cdaa7000000000000000000000000000000000000000000000000000000005f523360045260245ffdfea2646970667358221220bf8617a09a791c192cb0d344676f2dcbe88d7a55549a679b2ee10beaae67e98364736f6c634300081a0033b53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61036080806040523460d0577ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460ff8160401c1660c1576002600160401b03196001600160401b03821601605c575b6040516137ca90816100d58239f35b6001600160401b0319166001600160401b039081177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005581527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a15f80604d565b63f92ee8a960e01b5f5260045ffd5b5f80fdfe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a714612aed57508063248a9ca314612a7d5780632f0e31f414612a425780632f2ff15d146129c75780632f8e6a2d1461298d5780633013ce291461293d57806336568abe146128b55780633f4ba83a146127e55780634152881214611fe557806341dd26f514611e1f5780634c4911c414611cba57806350355d7614611c7f5780635b7baf6414611a955780635c975abb14611a365780636d3b96c3146119ce57806375b238fc146119765780637ab03cf21461193c5780638456cb591461186957806384f15090146117ea57806391d14854146117565780639e63798d1461162b578063a217fddf146115f3578063b4d884f6146114fd578063bf22c45714611269578063c0c53b8b14610ecc578063c9a84bb914610c84578063ce79eb6014610bb6578063d2e13f501461096a578063d547741f146108e8578063d75bbdf31461067d578063dd4ae9d4146104b0578063e138818c1461045f578063e1a4521814610425578063e63ea40814610222578063f9168231146101e75763ff96092a146101a8575f80fd5b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e3576020600154604051908152f35b5f80fd5b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e3576020600754604051908152f35b346101e35760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357610259612bcc565b610261612ba9565b73ffffffffffffffffffffffffffffffffffffffff60443592610282612e1e565b61028a613662565b169081158015610407575b6103df5773ffffffffffffffffffffffffffffffffffffffff5f5416808314610309575b50602073ffffffffffffffffffffffffffffffffffffffff826102fe867ff24ef89f38eadc1bde50701ad6e4d6d11a2dc24f7cf834a486991f38833285049587613605565b6040519586521693a3005b6020602491604051928380927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa9081156103d4575f916103a2575b506007548082111561039a5761036391612dfe565b808411156102b957837f9529d841000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b50505f610363565b90506020813d6020116103cc575b816103bd60209383612cf9565b810103126101e357518461034e565b3d91506103b0565b6040513d5f823e3d90fd5b7fd92e233d000000000000000000000000000000000000000000000000000000005f5260045ffd5b5073ffffffffffffffffffffffffffffffffffffffff811615610295565b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e35760206040516127108152f35b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357602073ffffffffffffffffffffffffffffffffffffffff60025416604051908152f35b346101e3576104be36612c1d565b9290916104c9613331565b6104d1613384565b6104da826133fb565b60ff815460a01c1660068110156106505761062857600181015465ffffffffffff8160a01c164210156106285773ffffffffffffffffffffffffffffffffffffffff16330361060057827f869e2577b006bf47ee981cf6fec2e25583548081c14b98deab587f77b5068038602073ffffffffffffffffffffffffffffffffffffffff946105b46105da996105886040519a8b9233878501528560408501526060808501526080840191612d8b565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081018a5289612cf9565b80600460038701966105ca8b888b8b541661345f565b0155604051908152a2541661357c565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055005b7f82b42900000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f8e78f0cb000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b346101e35761068b36612c1d565b919290610696613331565b61069e613384565b6106a7826133fb565b9360ff855460a01c166006811015610650576002036106285773ffffffffffffffffffffffffffffffffffffffff6002860154163303610600576107fd837f21d71db5be59bb9fa133895586b7404307dd33fb93b16db09dc6f1d9d7d231b060206105da9861076473ffffffffffffffffffffffffffffffffffffffff976107386040519b8c928a33888601612dc9565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081018b528a612cf9565b60038101956107778a868a8a541661345f565b6004820154740300000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff8454161783556107c581600754612dfe565b6007558860016127106107d9825485612e0b565b049889936107f86127106107ef60035484612e0b565b04958692612dfe565b612dfe565b9401541696806108a3575b5080610863575b5081610850575b604051908152847f0fd54bd364fa9e67f17b091aefe930932c09fe7651cf5ad02c71a418f3341444843393a3604051908152a3541661357c565b61085e82878a5f5416613605565b610816565b61087181338b5f5416613605565b604051908152857f253dd534010ac976fa263caa123bae79b9c50292adf7ce67bdc5ec309f784e61853393a38b61080f565b867f0e61cfd0ee655641b3ed0a1dd373ec3cacf4c090de1f33708e3a4091f4947662868c60025416936108db818f87905f5416613605565b604051908152a38c610808565b346101e35760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357610968600435610925612ba9565b9061096361095e825f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602052600160405f20015490565b612ea6565b613229565b005b346101e35761097836612c1d565b61098493919293613331565b61098c613384565b610995826133fb565b93845460ff8160a01c166006811015610650576106285773ffffffffffffffffffffffffffffffffffffffff16330361060057600185015473ffffffffffffffffffffffffffffffffffffffff811615610b8e5760a01c65ffffffffffff16421015610628576004850190815403610b66576105da94610a6f73ffffffffffffffffffffffffffffffffffffffff93610a436040519788923360208501526040808501526060840191612d8b565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101875286612cf9565b6003810191610a8286868686541661345f565b5490740100000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff825416179055610acd81600754612ccf565b60075580610b0a575b604051908152837fe3fbcc1ea1bdc559ec7f0347efde7655e58b5f45a30b0e4470a583c3ef5496b360203393a3541661357c565b610b61835f5416604051907f23b872dd00000000000000000000000000000000000000000000000000000000602083015233602483015230604483015283606483015260648252610b5c608483612cf9565b61370d565b610ad6565b7f99b0fc87000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fa9456d43000000000000000000000000000000000000000000000000000000005f5260045ffd5b346101e35760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357610bed612bcc565b602435908115158092036101e35773ffffffffffffffffffffffffffffffffffffffff90610c19612e1e565b169081156103df5760207f7ee54953080e392a475a25b6acacb85417ca4e1953293c90934233ca1361251091835f526006825260405f207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0081541660ff8316179055604051908152a2005b346101e35760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357600435610cbe612ba9565b60443567ffffffffffffffff81116101e357610cde903690600401612bef565b929091610ce9613331565b610cf1613384565b610cfa826133fb565b90815460ff8160a01c1660068110156106505761062857600183019182549165ffffffffffff8360a01c164210156106285773ffffffffffffffffffffffffffffffffffffffff16918233036106005773ffffffffffffffffffffffffffffffffffffffff166106285773ffffffffffffffffffffffffffffffffffffffff169081156103df578114610ea45773ffffffffffffffffffffffffffffffffffffffff6002840154168114610e7c57600373ffffffffffffffffffffffffffffffffffffffff93610e186105da98610dec604051998a923360208501528760408501526060808501526080840191612d8b565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101895288612cf9565b0191610e2886868686541661345f565b817fffffffffffffffffffffffff0000000000000000000000000000000000000000825416179055837f9a87df076ea1725aba8ba29d32517ce37c9597d88cbf16ec6707892cc330ab695f80a3541661357c565b7fc7b4e9eb000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f332ff0f9000000000000000000000000000000000000000000000000000000005f5260045ffd5b346101e35760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357610f03612bcc565b610f0b612ba9565b60443573ffffffffffffffffffffffffffffffffffffffff81168082036101e3577ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460ff8160401c16159467ffffffffffffffff821680159081611261575b6001149081611257575b15908161124e575b5061122657818660017fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000073ffffffffffffffffffffffffffffffffffffffff9516177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00556111d1575b50169081159081156111b2575b81156111a9575b506103df576110bd9273ffffffffffffffffffffffffffffffffffffffff916110216136b6565b6110296136b6565b6110316136b6565b6110396136b6565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00557fffffffffffffffffffffffff00000000000000000000000000000000000000005f5416175f55167fffffffffffffffffffffffff000000000000000000000000000000000000000060025416176002556110b781612f2c565b50613013565b505f805260066020527f54cdd369e4e8a8515e52ca72ec816c2101831ad1f18bf44102ed171459c9b4f880547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905561111657005b7fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054167ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a1005b90501585610ffa565b73ffffffffffffffffffffffffffffffffffffffff8516159150610ff3565b7fffffffffffffffffffffffffffffffffffffffffffffff0000000000000000001668010000000000000001177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005586610fe6565b7ff92ee8a9000000000000000000000000000000000000000000000000000000005f5260045ffd5b90501587610f7d565b303b159150610f75565b879150610f6b565b346101e35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357606060e06040516112a881612cdc565b5f81525f60208201525f60408201525f838201525f60808201525f60a08201525f60c082015201526004355f52600460205260405f20604051906112eb82612cdc565b60ff815473ffffffffffffffffffffffffffffffffffffffff8116845260a01c169060208301916006811015610650578252600181015491604084019173ffffffffffffffffffffffffffffffffffffffff8416835265ffffffffffff606086019460a01c16845273ffffffffffffffffffffffffffffffffffffffff600282015416936080860194855273ffffffffffffffffffffffffffffffffffffffff60038301541660a08701908152600560048401549360c08901948552019360405194855f8254926113bb84612d3a565b80845293600181169081156114bd5750600114611479575b506113e092500386612cf9565b60e0880194855273ffffffffffffffffffffffffffffffffffffffff6040519860208a525116602089015251600681101561065057879665ffffffffffff73ffffffffffffffffffffffffffffffffffffffff948561147599819560408d0152511660608b015251166080890152511660a0870152511660c08501525160e08401525161010080840152610120830190612c72565b0390f35b90505f9291925260205f20905f915b8183106114a15750509060206113e0928201018b6113d3565b6020919350806001915483858c01015201910190918792611488565b602093506113e09592507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091501682840152151560051b8201018b6113d3565b346101e35760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e35760043573ffffffffffffffffffffffffffffffffffffffff61154c612ba9565b611554612e1e565b169081156103df5761271061156b60035483612ccf565b116115cb576020817ff0c09f5238364083d828870e877edaebb364d9f19f4093fdbf24e486bbdca48492600155837fffffffffffffffffffffffff00000000000000000000000000000000000000006002541617600255604051908152a2005b7fc9034e18000000000000000000000000000000000000000000000000000000005f5260045ffd5b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e35760206040515f8152f35b346101e35761163936612c1d565b919290611644613331565b61164c613384565b611655826133fb565b60ff815460a01c1660068110156106505760010361062857600181015465ffffffffffff8160a01c164210156106285773ffffffffffffffffffffffffffffffffffffffff163303610600576105da946116d273ffffffffffffffffffffffffffffffffffffffff93610a43604051978892853360208601612dc9565b60038201916116e586868686541661345f565b740200000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff825416179055604051908152837f80c17db79857f338a6a6df68a6883ecc0ce78e2202fe61ed979733573f40538e60203393a3541661357c565b346101e35760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e35761178d612ba9565b6004355f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205273ffffffffffffffffffffffffffffffffffffffff60405f2091165f52602052602060ff60405f2054166040519015158152f35b346101e35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357600435611824612e1e565b61271061183360015483612ccf565b116115cb576020817f24fe03678743d8fe5f3d39d760da9fc7a5f3feea46847d91688ba8ef9e400d1492600355604051908152a1005b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e35761189f612e1e565b6118a7613331565b60017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff007fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005416177fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586020604051338152a1005b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357602060405161012c8152f35b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e35760206040517fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c217758152f35b346101e35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e35773ffffffffffffffffffffffffffffffffffffffff611a1a612bcc565b165f526006602052602060ff60405f2054166040519015158152f35b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357602060ff7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330054166040519015158152f35b346101e35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357600435611acf613384565b611ad8816133fb565b60ff815460a01c166006811015908161065057801515918280611c72575b8181611c61575b506106285761065057600203611c225765ffffffffffff600183015460a01c16610e108101809111611bf5574210611bcd575b740500000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff835416178255611bbd575b507f97237956f8810192811e2c3f273fd02c5d6295206fdd9c62e6fe2bfc19ba92325f80a260017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055005b611bc79082613505565b81611b72565b7f478f84e7000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b65ffffffffffff600183015460a01c16421015611b30577f8e78f0cb000000000000000000000000000000000000000000000000000000005f5260045ffd5b905061065057600282141581611afd565b50505f6001821415611af6565b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e3576020600554604051908152f35b346101e35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e35760043567ffffffffffffffff81116101e357366023820112156101e357806004013567ffffffffffffffff81116101e3573660248260051b840101116101e357611d31612e1e565b600554915f5b828110156109685760248160051b830101359081158015611e16575b611dee57816001925f52600460205273ffffffffffffffffffffffffffffffffffffffff600360405f20015416908115611de757805f526004602052600360405f20017fffffffffffffffffffffffff000000000000000000000000000000000000000081541690557fcde6a24b3e1e5d23bc4d45609905c64b3516b23478ba2f7fdada3ab2bae3812d5f80a35b01611d37565b5050611de1565b7f71c8f460000000000000000000000000000000000000000000000000000000005f5260045ffd5b50848211611d53565b346101e357611e2d36612c1d565b919290611e38613331565b611e40613384565b611e49826133fb565b9384549060ff8260a01c169260068410159283610650578415948515611f97575073ffffffffffffffffffffffffffffffffffffffff1633141580611f73575b61060057611ea6905b610a43604051978892853360208601612dc9565b6003860191611ecd868673ffffffffffffffffffffffffffffffffffffffff86541661345f565b740400000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff885416178755610650576105da9573ffffffffffffffffffffffffffffffffffffffff9315611f63575b50604051908152837fae7362b1af91f4492868987b9c73990d780060811551b58728fbe96fd1bab27560203393a3541661357c565b611f6d9085613505565b86611f2e565b5073ffffffffffffffffffffffffffffffffffffffff600188015416331415611e89565b5f94506001811491508115611fd7575b50156106285773ffffffffffffffffffffffffffffffffffffffff600288015416330361060057611ea690611e92565b93505060025f931488611fa7565b346101e35760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e35761201c612bcc565b612024612ba9565b60443560643567ffffffffffffffff81116101e357612047903690600401612bef565b9390926084359273ffffffffffffffffffffffffffffffffffffffff8416918285036101e35773ffffffffffffffffffffffffffffffffffffffff9061208b613331565b612093613384565b169283156103df5761012c4201804211611bf55782118015906127d6575b6127ae5773ffffffffffffffffffffffffffffffffffffffff1693338514610ea457841515806127a5575b610e7c57825f52600660205260ff60405f2054161561277d5782151590816125a4575b5061257c576005547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114611bf557600101948560055560405161214281612cdc565b33815287602082015f81526040830193888552606084019165ffffffffffff87168352608085019089825260a086019289845267ffffffffffffffff60c08801965f88521161254f578d906040519e8f6121c460207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8501160182612cf9565b5236828201116101e357818f5f936020938483013701015260e086019c8d528b5f52600460205273ffffffffffffffffffffffffffffffffffffffff8060405f20975116167fffffffffffffffffffffffff0000000000000000000000000000000000000000875416178655519060068210156106505760059673ffffffffffffffffffffffffffffffffffffffff9485937fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff74ff00000000000000000000000000000000000000008a549260a01b169116178855838060018a01935116167fffffffffffffffffffffffff0000000000000000000000000000000000000000835416178255517fffffffffffff000000000000ffffffffffffffffffffffffffffffffffffffff79ffffffffffff000000000000000000000000000000000000000083549260a01b1691161790555116826002860191167fffffffffffffffffffffffff0000000000000000000000000000000000000000825416179055511673ffffffffffffffffffffffffffffffffffffffff6003840191167fffffffffffffffffffffffff000000000000000000000000000000000000000082541617905551600482015501955195865167ffffffffffffffff811161254f576123ac8254612d3a565b601f811161250a575b50806020988990601f831160011461246d575f92612462575b50507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c19161790555b604051928352858301526040820152827fb0f0239bfdd96453e24733e18bfc24b70d8fadf123dd977473518dd577ee79b960603393a460017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055604051908152f35b0151905089806123ce565b5f858152828120937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016905b8181106124f357509084600195949392106124bc575b505050811b019055612400565b01517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c191690558980806124af565b92938c600181928786015181550195019301612499565b825f5260205f20601f830160051c81019160208410612545575b601f0160051c01905b81811061253a57506123b5565b5f815560010161252d565b9091508190612524565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f9c9d8823000000000000000000000000000000000000000000000000000000005f5260045ffd5b905060205f604051828101907f01ffc9a70000000000000000000000000000000000000000000000000000000082527f01ffc9a700000000000000000000000000000000000000000000000000000000602482015260248152612608604482612cf9565b519084617530fa903d5f519083612771575b5082612767575b50816126ce575b81612636575b5015876120ff565b602091505f90604051838101907f01ffc9a70000000000000000000000000000000000000000000000000000000082527f7ff6bc9e0000000000000000000000000000000000000000000000000000000060248201526024815261269b604482612cf9565b5191617530fa5f513d826126c2575b50816126b8575b508761262e565b90501515876126b1565b602011159150886126aa565b905060205f604051828101907f01ffc9a70000000000000000000000000000000000000000000000000000000082527fffffffff00000000000000000000000000000000000000000000000000000000602482015260248152612732604482612cf9565b519084617530fa5f513d8261275b575b5081612751575b501590612628565b9050151588612749565b60201115915089612742565b1515915088612621565b6020111592508961261a565b7fa04b28ec000000000000000000000000000000000000000000000000000000005f5260045ffd5b508385146120dc565b7ff7a0748c000000000000000000000000000000000000000000000000000000005f5260045ffd5b5065ffffffffffff82116120b1565b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e35761281b612e1e565b612823613662565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff007fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330054167fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6020604051338152a1005b346101e35760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e3576128ec612ba9565b3373ffffffffffffffffffffffffffffffffffffffff8216036129155761096890600435613229565b7f6697b232000000000000000000000000000000000000000000000000000000005f5260045ffd5b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357602073ffffffffffffffffffffffffffffffffffffffff5f5416604051908152f35b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e3576020604051610e108152f35b346101e35760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357610968600435612a04612ba9565b90612a3d61095e825f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602052600160405f20015490565b613117565b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e3576020600354604051908152f35b346101e35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e3576020612ae56004355f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602052600160405f20015490565b604051908152f35b346101e35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357600435907fffffffff0000000000000000000000000000000000000000000000000000000082168092036101e357817f7965db0b0000000000000000000000000000000000000000000000000000000060209314908115612b7f575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483612b78565b6024359073ffffffffffffffffffffffffffffffffffffffff821682036101e357565b6004359073ffffffffffffffffffffffffffffffffffffffff821682036101e357565b9181601f840112156101e35782359167ffffffffffffffff83116101e357602083818601950101116101e357565b60607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8201126101e35760043591602435916044359067ffffffffffffffff82116101e357612c6e91600401612bef565b9091565b91908251928382525f5b848110612cba5750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f845f6020809697860101520116010190565b80602080928401015182828601015201612c7c565b91908201809211611bf557565b610100810190811067ffffffffffffffff82111761254f57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761254f57604052565b90600182811c92168015612d81575b6020831014612d5457565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b91607f1691612d49565b601f82602094937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe093818652868601375f8582860101520116010190565b612dfb949273ffffffffffffffffffffffffffffffffffffffff60609316825260208201528160408201520191612d8b565b90565b91908203918211611bf557565b81810292918115918404141715611bf557565b335f9081527fb16e88c42fd4e48df2dd6a2eabd6bc9aec654ec170056b470819f8892cc6431c602052604090205460ff1615612e5657565b7fe2517d3f000000000000000000000000000000000000000000000000000000005f52336004527fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177560245260445ffd5b805f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260405f2073ffffffffffffffffffffffffffffffffffffffff33165f5260205260ff60405f20541615612efd5750565b7fe2517d3f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b73ffffffffffffffffffffffffffffffffffffffff81165f9081527fb7db2dd08fcb62d0c9e08c51941cae53c267786a0b75803fb7960902fc8ef97d602052604090205460ff1661300e5773ffffffffffffffffffffffffffffffffffffffff165f8181527fb7db2dd08fcb62d0c9e08c51941cae53c267786a0b75803fb7960902fc8ef97d6020526040812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790553391907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d8180a4600190565b505f90565b73ffffffffffffffffffffffffffffffffffffffff81165f9081527fb16e88c42fd4e48df2dd6a2eabd6bc9aec654ec170056b470819f8892cc6431c602052604090205460ff1661300e5773ffffffffffffffffffffffffffffffffffffffff165f8181527fb16e88c42fd4e48df2dd6a2eabd6bc9aec654ec170056b470819f8892cc6431c6020526040812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790553391907fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9080a4600190565b805f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260ff60405f205416155f1461322357805f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260405f2060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082541617905573ffffffffffffffffffffffffffffffffffffffff339216907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d5f80a4600190565b50505f90565b805f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260ff60405f2054165f1461322357805f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260405f207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00815416905573ffffffffffffffffffffffffffffffffffffffff339216907ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b5f80a4600190565b60ff7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300541661335c57565b7fd93c0665000000000000000000000000000000000000000000000000000000005f5260045ffd5b60027f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0054146133d35760027f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b7f3ee5aeb5000000000000000000000000000000000000000000000000000000005f5260045ffd5b80158015613416575b611dee575f52600460205260405f2090565b506005548111613404565b7fffffffff00000000000000000000000000000000000000000000000000000000612dfb949360609383521660208201528160408201520190612c72565b73ffffffffffffffffffffffffffffffffffffffff16918261348057505050565b823b156101e3576134e8925f92836040518096819582947fdc08fb1d0000000000000000000000000000000000000000000000000000000084527fffffffff000000000000000000000000000000000000000000000000000000008535169060048501613421565b03925af180156103d4576134f95750565b5f61350391612cf9565b565b600482015491821561357757602073ffffffffffffffffffffffffffffffffffffffff7f7ca5472b7ea78c2c0141c5a12ee6d170cf4ce8ed06be3d22c8252ddfc7a6a2c49261355686600754612dfe565b60075561356b86835f54168484541690613605565b541693604051908152a3565b505050565b73ffffffffffffffffffffffffffffffffffffffff16918261359d57505050565b823b156101e3576134e8925f92836040518096819582947fa3fe47830000000000000000000000000000000000000000000000000000000084527fffffffff000000000000000000000000000000000000000000000000000000008535169060048501613421565b6135039273ffffffffffffffffffffffffffffffffffffffff604051937fa9059cbb000000000000000000000000000000000000000000000000000000006020860152166024840152604483015260448252610b5c606483612cf9565b60ff7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330054161561368e57565b7f8dfc202b000000000000000000000000000000000000000000000000000000005f5260045ffd5b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c16156136e557565b7fd7e6bcf8000000000000000000000000000000000000000000000000000000005f5260045ffd5b905f602091828151910182855af1156103d4575f513d61378b575073ffffffffffffffffffffffffffffffffffffffff81163b155b6137495750565b73ffffffffffffffffffffffffffffffffffffffff907f5274afe7000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b6001141561374256fea26469706673582212206c80219f5022a102b78e2b3cea53bc36a61bd9d0874a3d24319381fbeaeb022a64736f6c634300081a0033608080604052346104ca57608081614c41803803809161001f8285610d0a565b8339810103126104ca578051906001600160a01b03821682036104ca5760208101516001600160a01b038116908190036104ca57600161006d606061006660408601610d41565b9401610d41565b938160ff19600c541617600c55601f54906101008360a81b039060081b1690828060a81b0319161717601f5560018060a01b0319602054161760205560018060a01b031660018060a01b0319602154161760215560018060a01b031660018060a01b031960225416176022555f5b60038110156105d35760405163348051d760e11b8152600481018290525f816024815f80516020614c218339815191525afa9081156104d6575f916105b9575b50604051906101566021836020810193606360f81b85526101458151809260208686019101610d79565b81010301601f198101845283610d0a565b60405160208101906101826020828651610171818789610d79565b81010301601f198101835282610d0a565b519020916040519263ffa1864960e01b845260048401526020836024815f80516020614c218339815191525afa9283156104d6575f9361057e575b505f80516020614c218339815191523b156104ca5761021260645f9260405194859384926318caf8e360e31b845260018060a01b03891660048501526040602485015251809281604486015285850190610d79565b601f01601f19168101030181835f80516020614c218339815191525af180156104d65761056e575b506023820180546001600160a01b0319166001600160a01b0390921691909117815560405163348051d760e11b8152600481018390525f816024815f80516020614c218339815191525afa9081156104d6575f9161054c575b50604051906102bd6021836020810193600760fc1b85526101458151809260208686019101610d79565b60405160208101906102d86020828651610171818789610d79565b519020916040519263ffa1864960e01b845260048401526020836024815f80516020614c218339815191525afa9283156104d6575f93610511575b505f80516020614c218339815191523b156104ca5761036860645f9260405194859384926318caf8e360e31b845260018060a01b03891660048501526040602485015251809281604486015285850190610d79565b601f01601f19168101030181835f80516020614c218339815191525af180156104d657610501575b506026830180546001600160a01b0319166001600160a01b0392831617905560205482549082169116813b156104ca575f916044839260405194859384926340c10f1960e01b8452600484015264e8d4a5100060248401525af180156104d6576104f1575b50546001600160a01b03165f80516020614c218339815191523b156104ca576040519063ca669fa760e01b825260048201525f81602481835f80516020614c218339815191525af180156104d6576104e1575b5060208054601f5460405163095ea7b360e01b81526001600160a01b0360089290921c821660048201525f1960248201529291839160449183915f91165af180156104d65761049b575b506001016100db565b6020813d82116104ce575b816104b360209383610d0a565b810103126104ca5751801515036104ca575f610492565b5f80fd5b3d91506104a6565b6040513d5f823e3d90fd5b5f6104eb91610d0a565b5f610448565b5f6104fb91610d0a565b5f6103f5565b5f61050b91610d0a565b5f610390565b9092506020813d8211610544575b8161052c60209383610d0a565b810103126104ca5761053d90610d41565b915f610313565b3d915061051f565b61056891503d805f833e6105608183610d0a565b810190610d9a565b5f610293565b5f61057891610d0a565b5f61023a565b9092506020813d82116105b1575b8161059960209383610d0a565b810103126104ca576105aa90610d41565b915f6101bd565b3d915061058c565b6105cd91503d805f833e6105608183610d0a565b5f61011b565b604080516105e18282610d0a565b600281526020810161065360f41b8152825160208101906106028284610d55565b60028152610611602282610d0a565b51902083519063ffa1864960e01b825260048201526020816024815f80516020614c218339815191525afa908115610c4f575f91610cd0575b505f80516020614c218339815191523b156104ca5761069e60645f92865194859384926318caf8e360e31b845260018060a01b03169788600485015289602485015251809281604486015285850190610d79565b601f01601f19168101030181835f80516020614c218339815191525af18015610ab157610cc0575b50602980546001600160a01b03191691909117905580516106e78282610d0a565b600281526020810161653160f01b8152825160208101906107088284610d55565b60028152610717602282610d0a565b51902083519063ffa1864960e01b825260048201526020816024815f80516020614c218339815191525afa908115610c4f575f91610c86575b505f80516020614c218339815191523b156104ca576107a460645f92865194859384926318caf8e360e31b845260018060a01b03169788600485015289602485015251809281604486015285850190610d79565b601f01601f19168101030181835f80516020614c218339815191525af18015610ab157610c76575b5060018060a01b0319602a541617602a5562278d00420190814211610bf857905f915b6003831015610c69576023830180549093906001600160a01b03165f80516020614c218339815191523b156104ca5782519063ca669fa760e01b825260048201525f81602481835f80516020614c218339815191525af18015610ab157610c59575b5060018060a01b03601f5460081c16938160260190602060018060a01b0383541660e460018060a01b0360295416915f88519a8b9485936320a9440960e11b8552600485015260248401528a604484015260a06064840152600460a4840152631cd9595960e21b60c48401528160848401525af1958615610c4f575f96610c1c575b5081545f91906001600160a01b03165f80516020614c218339815191523b156104ca5785519063ca669fa760e01b825260048201525f81602481835f80516020614c218339815191525af18015610bd457610c0c575b50601f54600185019060081c6001600160a01b0316818611610bf85781620f42400291620f4240830403610bf857803b156104ca578651633752ba7560e21b8152600481018a905260248101839052606060448201525f6064820181905290918290608490829084905af18015610bee57610bde575b50875f52602b602052855f2060ff1981541690556001851015610adf575b5050600283146109d4575b505060010192506107ef565b610acb57546001600160a01b03165f80516020614c218339815191523b156104ca5782519063ca669fa760e01b825260048201525f81602481835f80516020614c218339815191525af18015610ab157610abb575b50601f5460081c6001600160a01b031693843b156104ca575f80956084855180988193639e63798d60e01b8352866004840152816024840152606060448401528160648401525af1948515610ab1576001939495610aa1575b505f52602b602052825f20600260ff19825416179055839291856109c8565b5f610aab91610d0a565b85610a82565b83513d5f823e3d90fd5b5f610ac591610d0a565b84610a29565b634e487b7160e01b5f52603260045260245ffd5b90545f92506001600160a01b03165f80516020614c218339815191523b156104ca5785519063ca669fa760e01b825260048201525f81602481835f80516020614c218339815191525af18015610bd457610bc4575b50601f5460081c6001600160a01b0316803b156104ca578551630d2e13f560e41b8152600481018990526024810192909252606060448301525f60648301819052908290608490829084905af18015610bba57610baa575b50855f52602b602052835f20600160ff1982541617905586806109bd565b5f610bb491610d0a565b86610b8c565b85513d5f823e3d90fd5b5f610bce91610d0a565b87610b34565b86513d5f823e3d90fd5b5f610be891610d0a565b8861099f565b87513d5f823e3d90fd5b634e487b7160e01b5f52601160045260245ffd5b5f610c1691610d0a565b87610929565b9095506020813d8211610c47575b81610c3760209383610d0a565b810103126104ca575194866108d3565b3d9150610c2a565b84513d5f823e3d90fd5b5f610c6391610d0a565b84610851565b51613e169081610e0b8239f35b5f610c8091610d0a565b826107cc565b90506020813d602011610cb8575b81610ca160209383610d0a565b810103126104ca57610cb290610d41565b84610750565b3d9150610c94565b5f610cca91610d0a565b826106c6565b90506020813d602011610d02575b81610ceb60209383610d0a565b810103126104ca57610cfc90610d41565b8461064a565b3d9150610cde565b601f909101601f19168101906001600160401b03821190821017610d2d57604052565b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b03821682036104ca57565b5f5b60028110610d6957505060025f910152565b8181015183820152602001610d57565b5f5b838110610d8a5750505f910152565b8181015183820152602001610d7b565b6020818303126104ca578051906001600160401b0382116104ca570181601f820112156104ca5780516001600160401b038111610d2d5760405192610de9601f8301601f191660200185610d0a565b818452602082840101116104ca57610e079160208085019101610d79565b9056fe6080806040526004361015610012575f80fd5b5f905f3560e01c90816305e3769c1461191c57508063087320b2146118025780630b78f9c0146111ce5780631ed7831c146111255780632ade388014610f685780633e5e3c2314610ebf5780633f7286f414610e16578063531c7faa14610dfe57806359e1361914610dc25780635b7baf6414610d8757806366d9a9a014610c2c578063725cc2e114610c145780637f974c6f14610bd857806381ede1bb14610bc05780638253f2d91461080d57806385226c811461075d578063916a17c6146106885780639675dc1714610670578063b0464fdc1461059b578063b5508aa9146104eb578063b5c0922c146104a0578063ba414fa61461045d578063d130382514610445578063e20c9f711461038c578063e5d6bf02146101f1578063e662e387146101b0578063fa7626d41461016f5763fd61a25614610152575f80fd5b3461016c5761016961016336611c67565b91612d94565b80f35b80fd5b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c57602060ff601f54166040519015158152f35b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c57602060ff602f54166040519015158152f35b503461016c5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c57806102336202a3006001600435613b7d565b6102fb604091838084516102478682611a0b565b600c81527f426f756e6420726573756c740000000000000000000000000000000000000000602082015285516102e4816102b260208201947fb60e72cc0000000000000000000000000000000000000000000000000000000086528a60248401526064830190611b2b565b876044830152037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282611a0b565b51906a636f6e736f6c652e6c6f675afa50426128c2565b90737109709ecfa91a80626ff3989d68f67f5b1dd12d3b15610388578051917fe5d6bf020000000000000000000000000000000000000000000000000000000083526004830152828260248183737109709ecfa91a80626ff3989d68f67f5b1dd12d5af190811561037f575061036e5750f35b8161037891611a0b565b61016c5780f35b513d84823e3d90fd5b5050fd5b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c5760405180916020601554928381520191601582527f55f448fdea98c4d29eb340757ef0a66cd03dbb9538908a6a81d96026b71ec475915b818110610419576104158561040981870382611a0b565b60405191829182611ba2565b0390f35b825473ffffffffffffffffffffffffffffffffffffffff168452602090930192600192830192016103f2565b503461016c5761016961045736611c67565b91612b77565b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c576020610496612a9e565b6040519015158152f35b503461016c5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c5760ff60406020926004358152602b8452205416604051908152f35b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c5760195461052681611db7565b916105346040519384611a0b565b818352601981527f944998273e477b495144fb8794c914197f3ccb46be2900f4698fd0ef743c9695602084015b83831061057e576040516020808252819061041590820188611bf1565b60016020819261058d85611a4c565b815201920192019190610561565b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c57601c546105d681611db7565b916105e46040519384611a0b565b818352601c81527f0e4562a10381dec21b205ed72637e6b1b523bdd0e4d4d50af5cd23dd4500a211602084015b83831061062657604051806104158782611d06565b60026020600192604051610639816119a5565b73ffffffffffffffffffffffffffffffffffffffff865416815261065e8587016121fe565b83820152815201920192019190610611565b503461016c5761016961068236611b6e565b906128cf565b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c57601d546106c381611db7565b916106d16040519384611a0b565b818352601d81527f6d4407e7be21f808e6509aa9fa9143369579dd7d760fe20a2c09680fc146134f602084015b83831061071357604051806104158782611d06565b60026020600192604051610726816119a5565b73ffffffffffffffffffffffffffffffffffffffff865416815261074b8587016121fe565b838201528152019201920191906106fe565b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c57601a5461079881611db7565b916107a66040519384611a0b565b818352601a81527f057c384a7d1c54f3a1b2e5e67b2617b8224fdfd1ea7234eea573a6ff665ff63e602084015b8383106107f0576040516020808252819061041590820188611bf1565b6001602081926107ff85611a4c565b8152019201920191906107d3565b503461016c5760c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c576084358015158103610bbc5760a4358015158103610bb8576003600435066003811015610b85576023015473ffffffffffffffffffffffffffffffffffffffff169115610bb2576003602435066003811015610b85576026015473ffffffffffffffffffffffffffffffffffffffff165b6001604435166002811015610b585773ffffffffffffffffffffffffffffffffffffffff85916029015416926108ec62278d00610168606435613b7d565b9060409583808861096b61099d82516109058482611a0b565b600c81527f426f756e6420726573756c7400000000000000000000000000000000000000006020820152835192839160208301957fb60e72cc00000000000000000000000000000000000000000000000000000000875260248401526064830190611b2b565b896044830152037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282611a0b565b51906a636f6e736f6c652e6c6f675afa50737109709ecfa91a80626ff3989d68f67f5b1dd12d3b15610b4a578651907fca669fa70000000000000000000000000000000000000000000000000000000082526004820152838160248183737109709ecfa91a80626ff3989d68f67f5b1dd12d5af18015610b4e57610b2e575b509273ffffffffffffffffffffffffffffffffffffffff9260c49284602096610a4d82601f5460081c1693426128c2565b9015610b27578160225416905b8a51998a9889977f415288120000000000000000000000000000000000000000000000000000000089521660048801526024870152604486015260a060648601528360a48601521660848401525af1839181610aef575b50610aba578280f35b8252602b60205281207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0081541690555f808280f35b9091506020813d602011610b1f575b81610b0b60209383611a0b565b81010312610b1b5751905f610ab1565b5f80fd5b3d9150610afe565b8390610a5a565b92610b3d818096939495611a0b565b610b4a579291905f610a1c565b8380fd5b87513d86823e3d90fd5b6024857f4e487b710000000000000000000000000000000000000000000000000000000081526032600452fd5b6024847f4e487b710000000000000000000000000000000000000000000000000000000081526032600452fd5b826108ae565b8280fd5b5080fd5b503461016c57610169610bd236611c67565b91612678565b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c576020602c54604051908152f35b503461016c57610169610c2636611b6e565b906124d9565b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c57601b54610c6781611db7565b610c746040519182611a0b565b818152601b83526020810191837f3ad8aa4f87544323a9d1e5dd902f40c356527a7955687113db5f9a85ad579dc1845b838310610d4c57868587604051928392602084019060208552518091526040840160408260051b8601019392905b828210610ce157505050500390f35b91936020610d3c827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0600195979984950301865288519083610d2c8351604084526040840190611b2b565b9201519084818403910152611cb1565b9601920192018594939192610cd2565b60026020600192604051610d5f816119a5565b610d6886611a4c565b8152610d758587016121fe565b83820152815201920192019190610ca4565b503461016c5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c57610169600435612106565b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c576020602e54604051908152f35b503461016c57610169610e1036611c67565b91611dfc565b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c5760405180916020601754928381520191601782527fc624b66cc0138b8fabc209247f72d758e1cf3343756d543badbf24212bed8c15915b818110610e93576104158561040981870382611a0b565b825473ffffffffffffffffffffffffffffffffffffffff16845260209093019260019283019201610e7c565b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c5760405180916020601854928381520191601882527fb13d2d76d1f4b7be834882e410b3e3a8afaf69f83600ae24db354391d2378d2e915b818110610f3c576104158561040981870382611a0b565b825473ffffffffffffffffffffffffffffffffffffffff16845260209093019260019283019201610f25565b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c57601e54610fa381611db7565b610fb06040519182611a0b565b818152601e83526020810191837f50bb669a95c7b50b7e8a6f09454034b2b14cf2b85c730dca9a539ca82cb6e350845b83831061108f57868587604051928392602084019060208552518091526040840160408260051b8601019392905b82821061101d57505050500390f35b9193602061107f827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc060019597998495030186526040838a5173ffffffffffffffffffffffffffffffffffffffff815116845201519181858201520190611bf1565b960192019201859493919261100e565b60405161109b816119a5565b73ffffffffffffffffffffffffffffffffffffffff83541681526001830180546110c481611db7565b916110d26040519384611a0b565b8183528a526020808b20908b9084015b838210611108575050505060019282602092836002950152815201920192019190610fe0565b60016020819261111786611a4c565b8152019301910190916110e2565b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c5760405180916020601654928381520191601682527fd833147d7dc355ba459fc788f669e58cfaf9dc25ddcd0702e87d69c7b5124289915b8181106111a2576104158561040981870382611a0b565b825473ffffffffffffffffffffffffffffffffffffffff1684526020909301926001928301920161118b565b5034610b1b575f906111ec6127106111e536611b6e565b9490613b7d565b916040905f8083516111fe8582611a0b565b600c81527f426f756e6420726573756c7400000000000000000000000000000000000000006020820152845161129b8161126960208201947fb60e72cc0000000000000000000000000000000000000000000000000000000086528960248401526064830190611b2b565b8a6044830152037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282611a0b565b51906a636f6e736f6c652e6c6f675afa50836127100361271081116117d5575f6112c492613b7d565b5f8083516112d28582611a0b565b600c81527f426f756e6420726573756c7400000000000000000000000000000000000000006020820152845161133d816102b260208201947fb60e72cc0000000000000000000000000000000000000000000000000000000086528960248401526064830190611b2b565b51906a636f6e736f6c652e6c6f675afa5073ffffffffffffffffffffffffffffffffffffffff60215416737109709ecfa91a80626ff3989d68f67f5b1dd12d3b15610b1b578251907f06447d5600000000000000000000000000000000000000000000000000000000825260048201525f8160248183737109709ecfa91a80626ff3989d68f67f5b1dd12d5af180156117cb576117b6575b5073ffffffffffffffffffffffffffffffffffffffff601f5460081c16803b15610b4a5783809160248551809481937f84f150900000000000000000000000000000000000000000000000000000000083528160048401525af1801561171e579084916117a1575b505073ffffffffffffffffffffffffffffffffffffffff601f5460081c168251946114688487611a0b565b600886527f747265617375727900000000000000000000000000000000000000000000000060208701528351855b6008811061178c5750958686602881990152600881526114b7602882611a0b565b602081519101208551907fffa186490000000000000000000000000000000000000000000000000000000082526004820152602081602481737109709ecfa91a80626ff3989d68f67f5b1dd12d5afa908115611744578791611752575b50737109709ecfa91a80626ff3989d68f67f5b1dd12d3b1561174e578673ffffffffffffffffffffffffffffffffffffffff61158c92885193849283927fc657c71800000000000000000000000000000000000000000000000000000000845216958660048401528a60248401526044830190611b2b565b038183737109709ecfa91a80626ff3989d68f67f5b1dd12d5af180156117445790879161172f575b5050823b1561172b576044869283875195869485937fb4d884f6000000000000000000000000000000000000000000000000000000008552600485015260248401525af1801561171e57908491611709575b505073ffffffffffffffffffffffffffffffffffffffff601f5460081c1690813b1561170457839160248392855194859384927f84f1509000000000000000000000000000000000000000000000000000000000845260048401525af180156116f8579083916116e3575b5050737109709ecfa91a80626ff3989d68f67f5b1dd12d3b156116e0578051907f90c5013b000000000000000000000000000000000000000000000000000000008252828260048183737109709ecfa91a80626ff3989d68f67f5b1dd12d5af190811561037f575061036e5750f35b50fd5b816116ed91611a0b565b6116e057815f611671565b505051903d90823e3d90fd5b505050fd5b8161171391611a0b565b61038857825f611606565b50505051903d90823e3d90fd5b8580fd5b8161173991611a0b565b61172b57855f6115b4565b86513d89823e3d90fd5b8680fd5b90506020813d602011611784575b8161176d60209383611a0b565b8101031261174e5761177e906130cc565b5f611514565b3d9150611760565b80602080928a01015182828501015201611496565b816117ab91611a0b565b610bb857825f61143d565b6117c39193505f90611a0b565b5f915f6113d5565b83513d5f823e3d90fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b34610b1b575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610b1b576040515f60305461184081611954565b80845290600181169081156118da575060011461187c575b6104158361186881850382611a0b565b604051918291602083526020830190611b2b565b60305f9081527f6ff97a59c90d62cc7236ba3a37cd85351bf564556780cf8c1157a220f31f0cbb939250905b8082106118c057509091508101602001611868611858565b9192600181602092548385880101520191019092916118a8565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660208086019190915291151560051b840190910191506118689050611858565b34610b1b575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610b1b57602090602d548152f35b90600182811c9216801561199b575b602083101461196e57565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b91607f1691611963565b6040810190811067ffffffffffffffff8211176119c157604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b610100810190811067ffffffffffffffff8211176119c157604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176119c157604052565b9060405191825f825492611a5f84611954565b8084529360018116908115611aca5750600114611a86575b50611a8492500383611a0b565b565b90505f9291925260205f20905f915b818310611aae575050906020611a84928201015f611a77565b6020919350806001915483858901015201910190918492611a95565b60209350611a849592507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091501682840152151560051b8201015f611a77565b5f5b838110611b1b5750505f910152565b8181015183820152602001611b0c565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602093611b6781518092818752878088019101611b0a565b0116010190565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6040910112610b1b576004359060243590565b60206040818301928281528451809452019201905f5b818110611bc55750505090565b825173ffffffffffffffffffffffffffffffffffffffff16845260209384019390920191600101611bb8565b9080602083519182815201916020808360051b8301019401925f915b838310611c1c57505050505090565b9091929394602080611c58837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe086600196030187528951611b2b565b97019301930191939290611c0d565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6060910112610b1b57600435906024358015158103610b1b57906044358015158103610b1b5790565b90602080835192838152019201905f5b818110611cce5750505090565b82517fffffffff0000000000000000000000000000000000000000000000000000000016845260209384019390920191600101611cc1565b602081016020825282518091526040820191602060408360051b8301019401925f915b838310611d3857505050505090565b9091929394602080611d9b837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc086600196030187526040838b5173ffffffffffffffffffffffffffffffffffffffff815116845201519181858201520190611cb1565b97019301930191939290611d29565b919082039182116117d557565b67ffffffffffffffff81116119c15760051b60200190565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146117d55760010190565b90919082806120fd575b5f93156120ec57611e15613090565b50611e1f8261387b565b9281156120d7575b5091905b82156120d05783156120a1575060208101519060068210156120745773ffffffffffffffffffffffffffffffffffffffff9161206a5760800151165b925b815f52602b60205260ff60405f20541693737109709ecfa91a80626ff3989d68f67f5b1dd12d3b15610b1b5773ffffffffffffffffffffffffffffffffffffffff604051917fca669fa70000000000000000000000000000000000000000000000000000000083521660048201525f8160248183737109709ecfa91a80626ff3989d68f67f5b1dd12d5af1801561205f5761204c575b5073ffffffffffffffffffffffffffffffffffffffff601f5460081c16803b15610bbc57818080926084604051809581937f41dd26f5000000000000000000000000000000000000000000000000000000008352896004840152816024840152606060448401528160648401525af19182612037575b5050611f82575b50505050565b611f9192611fca575b50613550565b60018114908115611fbf575b50611fac575b5f808080611f7c565b611fb7602e54611dcf565b602e55611fa3565b60029150145f611f9d565b50612031604051611fdc606082611a0b565b602181527f72656a6563742073756363656564656420776974682077726f6e67206163746f60208201527f7200000000000000000000000000000000000000000000000000000000000000604082015261333e565b5f611f8b565b8161204191611a0b565b610bbc57815f611f75565b61205891505f90611a0b565b5f80611eff565b6040513d5f823e3d90fd5b6040015116611e67565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b73ffffffffffffffffffffffffffffffffffffffff9190156120c95760800151165b92611e69565b51166120c3565b5050505050565b90506120e49192506139fc565b91905f611e27565b906120f690613225565b9091611e2b565b82159350611e06565b61210e613090565b506121188161387b565b509081156121ed575b5080156121ea57805f52602b60205260ff60405f2054169073ffffffffffffffffffffffffffffffffffffffff601f5460081c16803b15610b1b575f80916024604051809481937f5b7baf640000000000000000000000000000000000000000000000000000000083528760048401525af190816121da575b506121a3575050565b6121ac90613550565b600181149081156121cf575b506121bf57565b6121ca602e54611dcf565b602e55565b60029150145f6121b8565b5f6121e491611a0b565b5f61219a565b50565b6121f791506139fc565b505f612121565b90604051918281549182825260208201905f5260205f20925f905b80600783011061241557611a849454918181106123df575b8181106123a9575b818110612373575b81811061233d575b818110612307575b8181106122d1575b81811061229c575b1061226f575b500383611a0b565b7fffffffff000000000000000000000000000000000000000000000000000000001681526020015f612267565b9260206001917fffffffff0000000000000000000000000000000000000000000000000000000085831b168152019301612261565b9260206001917fffffffff000000000000000000000000000000000000000000000000000000008560401b168152019301612259565b9260206001917fffffffff000000000000000000000000000000000000000000000000000000008560601b168152019301612251565b9260206001917fffffffff000000000000000000000000000000000000000000000000000000008560801b168152019301612249565b9260206001917fffffffff000000000000000000000000000000000000000000000000000000008560a01b168152019301612241565b9260206001917fffffffff000000000000000000000000000000000000000000000000000000008560c01b168152019301612239565b9260206001917fffffffff000000000000000000000000000000000000000000000000000000008560e01b168152019301612231565b9160089193506101006001917fffffffff000000000000000000000000000000000000000000000000000000008754818160e01b168352818160c01b166020840152818160a01b166040840152818160801b166060840152818160601b166080840152818160401b1660a0840152818160201b1660c08401521660e0820152019401920185929391612219565b81156124ac570690565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b6124e290613225565b90915f918315611f7c575173ffffffffffffffffffffffffffffffffffffffff16737109709ecfa91a80626ff3989d68f67f5b1dd12d3b15610b1b57604051907fca669fa700000000000000000000000000000000000000000000000000000000825260048201525f8160248183737109709ecfa91a80626ff3989d68f67f5b1dd12d5af1801561205f57612663575b50600373ffffffffffffffffffffffffffffffffffffffff601f5460081c1691066003811015612636576026015473ffffffffffffffffffffffffffffffffffffffff16813b15610bb85782916084839260405195869384927fc9a84bb90000000000000000000000000000000000000000000000000000000084528960048501526024840152606060448401528160648401525af19182612621575b50506126185750565b611a8490613550565b61262c828092611a0b565b61016c578061260f565b6024837f4e487b710000000000000000000000000000000000000000000000000000000081526032600452fd5b6126709192505f90611a0b565b5f905f612572565b5f91156128b15761268890613225565b9190915b8215611f7c57838015612899575b1561287c5773ffffffffffffffffffffffffffffffffffffffff6040820151165b737109709ecfa91a80626ff3989d68f67f5b1dd12d3b15610b1b5773ffffffffffffffffffffffffffffffffffffffff604051917fca669fa70000000000000000000000000000000000000000000000000000000083521660048201525f8160248183737109709ecfa91a80626ff3989d68f67f5b1dd12d5af1801561205f57612867575b5060c073ffffffffffffffffffffffffffffffffffffffff601f5460081c16910151813b15610bb8576040517fd2e13f50000000000000000000000000000000000000000000000000000000008152600481018590526024810191909152606060448201525f606482015290829081908390608490829084905af19182612852575b50506127cd57505050565b6127db926127eb5750613550565b6127e6602c54611dcf565b602c55565b506120316040516127fd606082611a0b565b602681527f66756e642073756363656564656420776974682077726f6e672073746174757360208201527f2f6163746f720000000000000000000000000000000000000000000000000000604082015261333e565b8161285c91611a0b565b610bbc57815f6127c2565b6128749192505f90611a0b565b5f905f612740565b73ffffffffffffffffffffffffffffffffffffffff8151166126bb565b9350602081015160068110156120745715159361269a565b6128ba906136e4565b91909161268c565b919082018092116117d557565b6128d890613225565b5f929192918315611f7c57633b9aca005f6128f292613b7d565b73ffffffffffffffffffffffffffffffffffffffff604080935f8083516129198582611a0b565b600c81527f426f756e6420726573756c740000000000000000000000000000000000000000602082015284516129848161126960208201947fb60e72cc0000000000000000000000000000000000000000000000000000000086528960248401526064830190611b2b565b51906a636f6e736f6c652e6c6f675afa50015116737109709ecfa91a80626ff3989d68f67f5b1dd12d3b15610b1b578251907fca669fa700000000000000000000000000000000000000000000000000000000825260048201525f8160248183737109709ecfa91a80626ff3989d68f67f5b1dd12d5af180156117cb57612a89575b5073ffffffffffffffffffffffffffffffffffffffff601f5460081c1691823b15610b4a57517fdd4ae9d4000000000000000000000000000000000000000000000000000000008152600481018590526024810191909152606060448201525f6064820152919081908390608490829084905af191826126215750506126185750565b612a969193505f90611a0b565b5f915f612a06565b60085460ff168015612aad5790565b506040517f667f9d70000000000000000000000000000000000000000000000000000000008152737109709ecfa91a80626ff3989d68f67f5b1dd12d60048201527f6661696c656400000000000000000000000000000000000000000000000000006024820152602081604481737109709ecfa91a80626ff3989d68f67f5b1dd12d5afa90811561205f575f91612b45575b50151590565b90506020813d602011612b6f575b81612b6060209383611a0b565b81010312610b1b57515f612b3f565b3d9150612b53565b5f9115612d8357612b8790613225565b9190915b8215611f7c57838015612d65575b73ffffffffffffffffffffffffffffffffffffffff919015612d5b5751165b737109709ecfa91a80626ff3989d68f67f5b1dd12d3b15610b1b5773ffffffffffffffffffffffffffffffffffffffff604051917fca669fa70000000000000000000000000000000000000000000000000000000083521660048201525f8160248183737109709ecfa91a80626ff3989d68f67f5b1dd12d5af1801561205f57612d48575b5073ffffffffffffffffffffffffffffffffffffffff601f5460081c16803b15610bbc57818080926084604051809581937f9e63798d000000000000000000000000000000000000000000000000000000008352896004840152816024840152606060448401528160648401525af19182612d33575b5050612cbe57505050565b611a8492612ccc5750613550565b50612031604051612cde606082611a0b565b602881527f7375626d69742073756363656564656420776974682077726f6e67207374617460208201527f75732f6163746f72000000000000000000000000000000000000000000000000604082015261333e565b81612d3d91611a0b565b610bbc57815f612cb3565b612d5491505f90611a0b565b5f80612c3d565b6040015116612bb8565b93506020810151906006821015612074576001919091141593612b99565b612d8c9061387b565b919091612b8b565b5f9115612fb057612da490613225565b9190915b8215611f7c57838015612f92575b73ffffffffffffffffffffffffffffffffffffffff919015612f885751165b737109709ecfa91a80626ff3989d68f67f5b1dd12d3b15610b1b5773ffffffffffffffffffffffffffffffffffffffff604051917fca669fa70000000000000000000000000000000000000000000000000000000083521660048201525f8160248183737109709ecfa91a80626ff3989d68f67f5b1dd12d5af1801561205f57612f75575b5073ffffffffffffffffffffffffffffffffffffffff601f5460081c16803b15610bbc57818080926084604051809581937fd75bbdf3000000000000000000000000000000000000000000000000000000008352896004840152816024840152606060448401528160648401525af19182612f60575b5050612edb57505050565b612ee992612ef95750613550565b612ef4602d54611dcf565b602d55565b50612031604051612f0b606082611a0b565b602a81527f636f6d706c6574652073756363656564656420776974682077726f6e6720737460208201527f617475732f6163746f7200000000000000000000000000000000000000000000604082015261333e565b81612f6a91611a0b565b610bbc57815f612ed0565b612f8191505f90611a0b565b5f80612e5a565b6080015116612dd5565b93506020810151906006821015612074576002919091141593612db6565b612fb9906139fc565b919091612da8565b906001612fcd92613b7d565b905f80604051612fde604082611a0b565b600c81527f426f756e6420726573756c740000000000000000000000000000000000000000602082015260405161307d8161304b60208201947fb60e72cc000000000000000000000000000000000000000000000000000000008652604060248401526064830190611b2b565b886044830152037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282611a0b565b51906a636f6e736f6c652e6c6f675afa50565b6040519061309d826119ee565b606060e0835f81525f60208201525f60408201525f838201525f60808201525f60a08201525f60c08201520152565b519073ffffffffffffffffffffffffffffffffffffffff82168203610b1b57565b602081830312610b1b5780519067ffffffffffffffff8211610b1b57019061010082820312610b1b5760405191613123836119ee565b61312c816130cc565b835260208101516006811015610b1b57602084015261314d604082016130cc565b6040840152606081015165ffffffffffff81168103610b1b576060840152613177608082016130cc565b608084015261318860a082016130cc565b60a084015260c081015160c084015260e08101519067ffffffffffffffff8211610b1b570181601f82011215610b1b57805167ffffffffffffffff81116119c157604051926131ff601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200185611a0b565b81845260208284010111610b1b5761321d9160208085019101611b0a565b60e082015290565b9061322e613090565b73ffffffffffffffffffffffffffffffffffffffff601f5460081c1692604051917f50355d76000000000000000000000000000000000000000000000000000000008352602083600481885afa92831561205f575f9361330a575b508215613301575061329e6024925f92612fc1565b93604051928380927fbf22c4570000000000000000000000000000000000000000000000000000000082528760048301525afa90811561205f575f916132e2575090565b6132fe91503d805f833e6132f68183611a0b565b8101906130ed565b90565b935050505f9190565b9092506020813d602011613336575b8161332660209383611a0b565b81010312610b1b5751915f613289565b3d9150613319565b90602f5460ff81161561335057509050565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117602f55815167ffffffffffffffff81116119c157613394603054611954565b601f81116134af575b50602092601f82116001146133f657928192935f926133eb575b50507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c191617603055565b015190505f806133b7565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082169360305f527f6ff97a59c90d62cc7236ba3a37cd85351bf564556780cf8c1157a220f31f0cbb915f5b8681106134975750836001959610613460575b505050811b01603055565b01517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c191690555f8080613455565b91926020600181928685015181550194019201613442565b60305f52601f820160051c7f6ff97a59c90d62cc7236ba3a37cd85351bf564556780cf8c1157a220f31f0cbb019060208310613528575b601f0160051c7f6ff97a59c90d62cc7236ba3a37cd85351bf564556780cf8c1157a220f31f0cbb01905b81811061351d575061339d565b5f8155600101613510565b7f6ff97a59c90d62cc7236ba3a37cd85351bf564556780cf8c1157a220f31f0cbb91506134e6565b805f52602b60205260ff60405f2054169060245f73ffffffffffffffffffffffffffffffffffffffff601f5460081c16604051928380927fbf22c4570000000000000000000000000000000000000000000000000000000082528660048301525afa801561205f576020915f916136ca575b5001519160068310156120745782600382106136785750506136406040516135eb606082611a0b565b602281527f616374696f6e20737563636565646564206f6e2061207465726d696e616c206a60208201527f6f62000000000000000000000000000000000000000000000000000000000000604082015261333e565b5f52602b60205260ff60405f2091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055565b61368191613d55565b613640576136c5604051613696604082611a0b565b601981527f696c6c6567616c20737461747573207472616e736974696f6e00000000000000602082015261333e565b613640565b6136de91503d805f833e6132f68183611a0b565b5f6135c2565b906136ed613090565b9173ffffffffffffffffffffffffffffffffffffffff601f5460081c1690604051907f50355d76000000000000000000000000000000000000000000000000000000008252602082600481865afa91821561205f575f92613847575b50811561383f578161375a91612fc1565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101908111915f5b8181106137945750505050505f9190565b836117d5576137ac826137a783866128c2565b6124a2565b600181018091116117d557604051907fbf22c4570000000000000000000000000000000000000000000000000000000082528060048301525f826024818a5afa91821561205f575f92613823575b50602082015160068110156120745715613818575050600101613783565b975095945050505050565b6138389192503d805f833e6132f68183611a0b565b905f6137fa565b5050505f9190565b9091506020813d602011613873575b8161386360209383611a0b565b81010312610b1b5751905f613749565b3d9150613856565b90613884613090565b9173ffffffffffffffffffffffffffffffffffffffff601f5460081c1690604051907f50355d76000000000000000000000000000000000000000000000000000000008252602082600481865afa91821561205f575f926139c8575b50811561383f57816138f191612fc1565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101908111915f5b81811061392b5750505050505f9190565b836117d55761393e826137a783866128c2565b600181018091116117d557604051907fbf22c4570000000000000000000000000000000000000000000000000000000082528060048301525f826024818a5afa91821561205f575f926139ac575b50602082015160068110156120745760011461381857505060010161391a565b6139c19192503d805f833e6132f68183611a0b565b905f61398c565b9091506020813d6020116139f4575b816139e460209383611a0b565b81010312610b1b5751905f6138e0565b3d91506139d7565b90613a05613090565b9173ffffffffffffffffffffffffffffffffffffffff601f5460081c1690604051907f50355d76000000000000000000000000000000000000000000000000000000008252602082600481865afa91821561205f575f92613b49575b50811561383f5781613a7291612fc1565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101908111915f5b818110613aac5750505050505f9190565b836117d557613abf826137a783866128c2565b600181018091116117d557604051907fbf22c4570000000000000000000000000000000000000000000000000000000082528060048301525f826024818a5afa91821561205f575f92613b2d575b506020820151600681101561207457600214613818575050600101613a9b565b613b429192503d805f833e6132f68183611a0b565b905f613b0d565b9091506020813d602011613b75575b81613b6560209383611a0b565b81010312610b1b5751905f613a61565b3d9150613b58565b5f90838311613cd15782811091821580613cc7575b613cbf57613ba08486611daa565b92600184018094116117d557600383111580613cb6575b613ca7577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc83101580613c9d575b613c8c5785831115613c44575050906137a784613c0193611daa565b908115613c3f57613c1292506128c2565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81019081116117d55790565b505090565b959492919095613c545750505050565b839495506137a790613c669394611daa565b908115613c3f57613c779250611daa565b600181018091116117d557905f808080611f7c565b505090506132fe9291501990611daa565b5082198411613be5565b50509190506132fe92506128c2565b50828411613bb7565b509250505090565b5084821115613b92565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603e60248201527f5374645574696c7320626f756e642875696e743235362c75696e743235362c7560448201527f696e74323536293a204d6178206973206c657373207468616e206d696e2e00006064820152fd5b60ff168015613db75760018114613d9e57600214613d7257505f90565b60ff1660038114908115613d93575b8115613d8b575090565b600591501490565b600481149150613d81565b5060ff1660028114908115613d93578115613d8b575090565b5060ff168015908115613dd5575b8115613d93578115613d8b575090565b600181149150613dc556fea264697066735822122087a51d10e0458fb317219be7eb23f08edb70a540fa5ddaaf1fe23542f4215bae64736f6c634300081a00330000000000000000000000007109709ecfa91a80626ff3989d68f67f5b1dd12d60806040523461031057610e1e8038038061001981610314565b9283398101906040818303126103105780516001600160401b0381116103105782610045918301610339565b60208201519092906001600160401b038111610310576100659201610339565b81516001600160401b03811161022357600354600181811c91168015610306575b602082101461020557601f81116102a3575b50602092601f821160011461024257928192935f92610237575b50508160011b915f199060031b1c1916176003555b80516001600160401b03811161022357600454600181811c91168015610219575b602082101461020557601f81116101a2575b50602091601f8211600114610142579181925f92610137575b50508160011b915f199060031b1c1916176004555b604051610a7b90816103a38239f35b015190505f80610113565b601f1982169260045f52805f20915f5b85811061018a57508360019510610172575b505050811b01600455610128565b01515f1960f88460031b161c191690555f8080610164565b91926020600181928685015181550194019201610152565b60045f527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b601f830160051c810191602084106101fb575b601f0160051c01905b8181106101f057506100fa565b5f81556001016101e3565b90915081906101da565b634e487b7160e01b5f52602260045260245ffd5b90607f16906100e8565b634e487b7160e01b5f52604160045260245ffd5b015190505f806100b2565b601f1982169360035f52805f20915f5b86811061028b5750836001959610610273575b505050811b016003556100c7565b01515f1960f88460031b161c191690555f8080610265565b91926020600181928685015181550194019201610252565b60035f527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b601f830160051c810191602084106102fc575b601f0160051c01905b8181106102f15750610098565b5f81556001016102e4565b90915081906102db565b90607f1690610086565b5f80fd5b6040519190601f01601f191682016001600160401b0381118382101761022357604052565b81601f82011215610310578051906001600160401b03821161022357610368601f8301601f1916602001610314565b9282845260208383010111610310575f5b82811061038d57505060205f918301015290565b8060208092840101518282870101520161037956fe6080806040526004361015610012575f80fd5b5f3560e01c90816306fdde031461077257508063095ea7b3146106c557806318160ddd1461068a57806323b872dd146104f6578063313ce567146104bd57806340c10f19146103be57806370a082311461035c57806395d89b4114610169578063a9059cbb1461011a5763dd62ed3e1461008a575f80fd5b346101165760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610116576100c1610909565b73ffffffffffffffffffffffffffffffffffffffff6100de61092c565b91165f52600160205273ffffffffffffffffffffffffffffffffffffffff60405f2091165f52602052602060405f2054604051908152f35b5f80fd5b346101165760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101165761015e610154610909565b602435903361094f565b602060405160018152f35b34610116575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610116576040515f600454908160011c60018316928315610352575b6020821084146103255781855284939081156102c5575060011461024b575b5003601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01681019067ffffffffffffffff82118183101761021e5761021a829182604052826108a3565b0390f35b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b60045f90815291507f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b5b8183106102a957505081016020017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06101ce565b6020919350806001915483858801015201910190918392610275565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660208581019190915291151560051b840190910191507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090506101ce565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b90607f16906101af565b346101165760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101165773ffffffffffffffffffffffffffffffffffffffff6103a8610909565b165f525f602052602060405f2054604051908152f35b346101165760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610116576103f5610909565b73ffffffffffffffffffffffffffffffffffffffff16602435811561049157600254908082018092116104645760207fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef915f9360025584845283825260408420818154019055604051908152a3005b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b7fec442f05000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b34610116575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261011657602060405160068152f35b346101165760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101165761052d610909565b61053561092c565b6044359073ffffffffffffffffffffffffffffffffffffffff831692835f52600160205260405f2073ffffffffffffffffffffffffffffffffffffffff33165f5260205260405f20547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81106105b1575b5061015e935061094f565b83811061065657841561062a5733156105fe5761015e945f52600160205260405f2073ffffffffffffffffffffffffffffffffffffffff33165f526020528360405f2091039055846105a6565b7f94280d62000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b7fe602df05000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b83907ffb8f41b2000000000000000000000000000000000000000000000000000000005f523360045260245260445260645ffd5b34610116575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610116576020600254604051908152f35b346101165760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610116576106fc610909565b60243590331561062a5773ffffffffffffffffffffffffffffffffffffffff169081156105fe57335f52600160205260405f20825f526020528060405f20556040519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a3602060405160018152f35b34610116575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610116575f600354908160011c60018316928315610899575b6020821084146103255781855284939081156102c5575060011461081f575003601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01681019067ffffffffffffffff82118183101761021e5761021a829182604052826108a3565b60035f90815291507fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b5b81831061087d57505081016020017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06101ce565b6020919350806001915483858801015201910190918392610849565b90607f16906107b5565b919091602081528251928360208301525f5b8481106108f35750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f845f6040809697860101520116010190565b80602080928401015160408286010152016108b5565b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361011657565b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361011657565b73ffffffffffffffffffffffffffffffffffffffff16908115610a195773ffffffffffffffffffffffffffffffffffffffff1691821561049157815f525f60205260405f20548181106109e757817fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92602092855f525f84520360405f2055845f525f825260405f20818154019055604051908152a3565b827fe450d38c000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b7f96c6fd1e000000000000000000000000000000000000000000000000000000005f525f60045260245ffdfea26469706673582212207d4081a323998c8d20751316ef809be0cc398b922c8a680eea7ed1d1bc08e9bf64736f6c634300081a003360808060405234601557610fd0908161001a8239f35b5f80fdfe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a714610b915750806306661abd14610b575780633a32058114610a1d578063a3fe4783146105eb578063d183ce14146105295763dc08fb1d1461005e575f80fd5b346103cb5761006c36610cb1565b9092916040517fbf22c4570000000000000000000000000000000000000000000000000000000081528360048201525f81602481335afa801561051e575f906103fc575b6020915001519260068410156103cf57604051926100cd84610e07565b60018452602084019182527fffffffff00000000000000000000000000000000000000000000000000000000604085019316835261010a81610f60565b956101186040519788610e40565b81875236828201116103cb57815f92602092838a0137870101526060830194855260ff60808401941684525f54680100000000000000008110156103725780600161016592015f55610d51565b93909361039f5751151560ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00855416911617835551600183015560028201905160e01c7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000082541617905560038101925192835167ffffffffffffffff8111610372576101f28254610db6565b601f811161032d575b506020601f8211600114610287579080600494939260ff96975f9261027c575b50507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c19161790555b019151167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008254161790555f80f35b015190505f8061021b565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0821695835f52815f20965f5b8181106103155750966001928492600497969560ff999a106102de575b505050811b01905561024d565b01517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c191690555f80806102d1565b838301518955600190980197602093840193016102b4565b825f5260205f20601f830160051c81019160208410610368575b601f0160051c01905b81811061035d57506101fb565b5f8155600101610350565b9091508190610347565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b503d805f833e61040c8183610e40565b8101906020818303126103cb5780519067ffffffffffffffff82116103cb5701610100818303126103cb576040519061044482610e23565b61044d81610f3f565b8252602081015160068110156103cb57602083015261046e60408201610f3f565b6040830152606081015165ffffffffffff811681036103cb57606083015261049860808201610f3f565b60808301526104a960a08201610f3f565b60a083015260c081015160c083015260e08101519067ffffffffffffffff82116103cb57019180601f840112156103cb578251926104e684610f60565b916104f46040519384610e40565b848352602085830101116103cb5760209361051491858085019101610c4d565b60e08201526100b0565b6040513d5f823e3d90fd5b346103cb5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103cb576004355f548110156103cb5761056d90610d51565b5060ff8154166001820154916105e1600282015460e01b917fffffffff0000000000000000000000000000000000000000000000000000000060ff60046105b660038501610e81565b930154169360405196879615158752602087015216604085015260a0606085015260a0840190610c6e565b9060808301520390f35b346103cb576105f936610cb1565b9092916040517fbf22c4570000000000000000000000000000000000000000000000000000000081528360048201525f81602481335afa801561051e575f906108fb575b6020915001519260068410156103cf576040519261065a84610e07565b5f8452602084019182527fffffffff00000000000000000000000000000000000000000000000000000000604085019316835261069681610f60565b956106a46040519788610e40565b81875236828201116103cb57815f92602092838a0137870101526060830194855260ff60808401941684525f5468010000000000000000811015610372578060016106f192015f55610d51565b93909361039f5751151560ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00855416911617835551600183015560028201905160e01c7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000082541617905560038101925192835167ffffffffffffffff81116103725761077e8254610db6565b601f81116108b6575b506020601f8211600114610811579080600494939260ff96975f926108065750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c1916179055019151167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008254161790555f80f35b01519050878061021b565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0821695835f52815f20965f5b81811061089e5750966001928492600497969560ff999a1061086757505050811b01905561024d565b01517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c191690558780806102d1565b8383015189556001909801976020938401930161083e565b825f5260205f20601f830160051c810191602084106108f1575b601f0160051c01905b8181106108e65750610787565b5f81556001016108d9565b90915081906108d0565b503d805f833e61090b8183610e40565b8101906020818303126103cb5780519067ffffffffffffffff82116103cb5701610100818303126103cb576040519061094382610e23565b61094c81610f3f565b8252602081015160068110156103cb57602083015261096d60408201610f3f565b6040830152606081015165ffffffffffff811681036103cb57606083015261099760808201610f3f565b60808301526109a860a08201610f3f565b60a083015260c081015160c083015260e08101519067ffffffffffffffff82116103cb57019180601f840112156103cb578251926109e584610f60565b916109f36040519384610e40565b848352602085830101116103cb57602093610a1391858085019101610c4d565b60e082015261063d565b346103cb5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103cb575f6080604051610a5b81610e07565b8281528260208201528260408201526060808201520152610a7d600435610d51565b50604051610a8a81610e07565b60ff825416151581526001820154916020820192835260ff610b4b600283015460e01b927fffffffff0000000000000000000000000000000000000000000000000000000060408601941684527fffffffff00000000000000000000000000000000000000000000000000000000836004610b0760038501610e81565b93606089019485520154169460808701958652604051978897602089525115156020890152516040880152511660608601525160a0608086015260c0850190610c6e565b91511660a08301520390f35b346103cb575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103cb5760205f54604051908152f35b346103cb5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103cb57600435907fffffffff0000000000000000000000000000000000000000000000000000000082168092036103cb57817f7ff6bc9e0000000000000000000000000000000000000000000000000000000060209314908115610c23575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483610c1c565b5f5b838110610c5e5750505f910152565b8181015183820152602001610c4f565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602093610caa81518092818752878088019101610c4d565b0116010190565b9060607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8301126103cb57600435916024357fffffffff00000000000000000000000000000000000000000000000000000000811681036103cb579160443567ffffffffffffffff81116103cb57826023820112156103cb5780600401359267ffffffffffffffff84116103cb57602484830101116103cb576024019190565b5f54811015610d89575f8080526005919091027f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5630191565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b90600182811c92168015610dfd575b6020831014610dd057565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b91607f1691610dc5565b60a0810190811067ffffffffffffffff82111761037257604052565b610100810190811067ffffffffffffffff82111761037257604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761037257604052565b9060405191825f825492610e9484610db6565b8084529360018116908115610eff5750600114610ebb575b50610eb992500383610e40565b565b90505f9291925260205f20905f915b818310610ee3575050906020610eb9928201015f610eac565b6020919350806001915483858901015201910190918492610eca565b60209350610eb99592507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091501682840152151560051b8201015f610eac565b519073ffffffffffffffffffffffffffffffffffffffff821682036103cb57565b67ffffffffffffffff811161037257601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0166020019056fea2646970667358221220af75d4a17c0b6da6a3609fe1e4338988c321fe2d51d15dda0930b8f2e25388aa64736f6c634300081a0033a2646970667358221220f16bdcf0e1bc42cc06e2748da5fb883ec4927ec1a6fcacf0ab8a4e3b5625b20f64736f6c634300081a00330000000000000000000000007109709ecfa91a80626ff3989d68f67f5b1dd12d","output":"0x6080806040526004361015610012575f80fd5b5f905f3560e01c9081630a9254e414611355575080631ed7831c146112ac5780632ade3880146110805780633e5e3c2314610fd75780633f7286f414610f2e57806347853bb914610ef75780634d657a1e14610ec057806366d9a9a014610d6557806385226c8114610cbd578063916a17c614610be8578063b0464fdc14610b13578063b5508aa914610a6b578063ba414fa614610a28578063c5c988ca1461020f578063d87d4feb146101d5578063e20c9f711461011c5763fa7626d4146100d9575f80fd5b3461011957807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261011957602060ff601f54166040519015158152f35b80fd5b503461011957807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101195760405180916020601554928381520191601582527f55f448fdea98c4d29eb340757ef0a66cd03dbb9538908a6a81d96026b71ec475915b8181106101a9576101a58561019981870382611ea7565b60405191829182611c35565b0390f35b825473ffffffffffffffffffffffffffffffffffffffff16845260209093019260019283019201610182565b503461011957807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101195761020c61273e565b80f35b503461011957807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261011957805b61025881106104b0575073ffffffffffffffffffffffffffffffffffffffff602954166040517f7f974c6f000000000000000000000000000000000000000000000000000000008152602081600481855afa9081156104a5578391610473575b506102e36040918251906102b48483611ea7565b601282527f6e6f207375636365737366756c2066756e6400000000000000000000000000006020830152612ad4565b80517f05e3769c000000000000000000000000000000000000000000000000000000008152602081600481865afa908115610469578491610436575b506004926103646020928451906103368683611ea7565b601682527f6e6f207375636365737366756c20636f6d706c6574650000000000000000000085830152612ad4565b8251938480927f59e136190000000000000000000000000000000000000000000000000000000082525afa801561042c5783906103f4575b6103dc92506103ad82519283611ea7565b601982527f6e6f207375636365737366756c20726566756e642070617468000000000000006020830152612ad4565b6103e461273e565b6103ec61221d565b61020c61208e565b506020823d602011610424575b8161040e60209383611ea7565b81010312610420576103dc915161039c565b5f80fd5b3d9150610401565b81513d85823e3d90fd5b90506020813d602011610461575b8161045160209383611ea7565b810103126104205751600461031f565b3d9150610444565b82513d86823e3d90fd5b90506020813d60201161049d575b8161048e60209383611ea7565b8101031261042057515f6102a0565b3d9150610481565b6040513d85823e3d90fd5b816040516020810190838252602081526104cb604082611ea7565b519020600a8106806105a3575073ffffffffffffffffffffffffffffffffffffffff6029541690813b1561059f57600160c484928360405195869485937f8253f2d90000000000000000000000000000000000000000000000000000000085528060048601528060081c60248601528060101c60448601528060181c6064860152818160201c1615608486015260281c161560a48401525af180156105945761057b575b50506001905b01610240565b8161058591611ea7565b61059057815f61056f565b5080fd5b6040513d84823e3d90fd5b8280fd5b60018103610638575073ffffffffffffffffffffffffffffffffffffffff6029541690813b1561059f5782916044839260405194859384927f725cc2e100000000000000000000000000000000000000000000000000000000845280600485015260081c60248401525af1801561059457610623575b5050600190610575565b8161062d91611ea7565b61059057815f610619565b600281036106b7575073ffffffffffffffffffffffffffffffffffffffff6029541690813b1561059f5782916044839260405194859384927f9675dc1700000000000000000000000000000000000000000000000000000000845280600485015260081c60248401525af1801561059457610623575050600190610575565b60038103610739575073ffffffffffffffffffffffffffffffffffffffff6029541690813b1561059f5782916064839260405194859384927f81ede1bb00000000000000000000000000000000000000000000000000000000845260048401528160248401528160448401525af1801561059457610623575050600190610575565b600481036107bb575073ffffffffffffffffffffffffffffffffffffffff6029541690813b1561059f5782916064839260405194859384927fd130382500000000000000000000000000000000000000000000000000000000845260048401528160248401528160448401525af1801561059457610623575050600190610575565b6005810361083d575073ffffffffffffffffffffffffffffffffffffffff6029541690813b1561059f5782916064839260405194859384927ffd61a25600000000000000000000000000000000000000000000000000000000845260048401528160248401528160448401525af1801561059457610623575050600190610575565b600681036108c5575073ffffffffffffffffffffffffffffffffffffffff6029541690813b1561059f576001606484928360405195869485937f531c7faa00000000000000000000000000000000000000000000000000000000855280600486015260081c161560248401528160448401525af1801561059457610623575050600190610575565b6007810361093b575073ffffffffffffffffffffffffffffffffffffffff6029541690813b1561059f5782916024839260405194859384927f5b7baf6400000000000000000000000000000000000000000000000000000000845260048401525af1801561059457610623575050600190610575565b6008036109b25773ffffffffffffffffffffffffffffffffffffffff6029541690813b1561059f57612a30602484928360405195869485937fe5d6bf020000000000000000000000000000000000000000000000000000000085520660048401525af1801561059457610623575050600190610575565b73ffffffffffffffffffffffffffffffffffffffff6029541690813b1561059f5782916044839260405194859384927f0b78f9c000000000000000000000000000000000000000000000000000000000845280600485015260081c60248401525af1801561059457610623575050600190610575565b503461011957807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610119576020610a61612644565b6040519015158152f35b503461011957807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261011957601954610aa681611ee8565b91610ab46040519384611ea7565b818352601981527f944998273e477b495144fb8794c914197f3ccb46be2900f4698fd0ef743c9695602084015b838310610af657604051806101a58782611d3d565b600160208192610b0585611f00565b815201920192019190610ae1565b503461011957807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261011957601c54610b4e81611ee8565b91610b5c6040519384611ea7565b818352601c81527f0e4562a10381dec21b205ed72637e6b1b523bdd0e4d4d50af5cd23dd4500a211602084015b838310610b9e57604051806101a58782611dba565b60026020600192604051610bb181611e5e565b73ffffffffffffffffffffffffffffffffffffffff8654168152610bd68587016123a0565b83820152815201920192019190610b89565b503461011957807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261011957601d54610c2381611ee8565b91610c316040519384611ea7565b818352601d81527f6d4407e7be21f808e6509aa9fa9143369579dd7d760fe20a2c09680fc146134f602084015b838310610c7357604051806101a58782611dba565b60026020600192604051610c8681611e5e565b73ffffffffffffffffffffffffffffffffffffffff8654168152610cab8587016123a0565b83820152815201920192019190610c5e565b503461011957807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261011957601a54610cf881611ee8565b91610d066040519384611ea7565b818352601a81527f057c384a7d1c54f3a1b2e5e67b2617b8224fdfd1ea7234eea573a6ff665ff63e602084015b838310610d4857604051806101a58782611d3d565b600160208192610d5785611f00565b815201920192019190610d33565b503461011957807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261011957601b54610da081611ee8565b610dad6040519182611ea7565b818152601b83526020810191837f3ad8aa4f87544323a9d1e5dd902f40c356527a7955687113db5f9a85ad579dc1845b838310610e8557868587604051928392602084019060208552518091526040840160408260051b8601019392905b828210610e1a57505050500390f35b91936020610e75827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0600195979984950301865288519083610e658351604084526040840190611ca5565b9201519084818403910152611ce8565b9601920192018594939192610e0b565b60026020600192604051610e9881611e5e565b610ea186611f00565b8152610eae8587016123a0565b83820152815201920192019190610ddd565b503461011957807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101195761020c61221d565b503461011957807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101195761020c61208e565b503461011957807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101195760405180916020601754928381520191601782527fc624b66cc0138b8fabc209247f72d758e1cf3343756d543badbf24212bed8c15915b818110610fab576101a58561019981870382611ea7565b825473ffffffffffffffffffffffffffffffffffffffff16845260209093019260019283019201610f94565b503461011957807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101195760405180916020601854928381520191601882527fb13d2d76d1f4b7be834882e410b3e3a8afaf69f83600ae24db354391d2378d2e915b818110611054576101a58561019981870382611ea7565b825473ffffffffffffffffffffffffffffffffffffffff1684526020909301926001928301920161103d565b503461011957807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261011957601e546110bb81611ee8565b6110c86040519182611ea7565b818152601e83526020810191837f50bb669a95c7b50b7e8a6f09454034b2b14cf2b85c730dca9a539ca82cb6e350845b8383106112165786858760405192839260208401906020855251809152604084019160408260051b8601019392815b8383106111345786860387f35b9193957fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc09086929496030183528551906020604082019273ffffffffffffffffffffffffffffffffffffffff81511683520151916040602083015282518091526060820190602060608260051b850101940192855b8281106111cd57505050505060208060019297019301930190928695949293611127565b9091929394602080611209837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa087600196030189528951611ca5565b97019501939291016111a9565b60405161122281611e5e565b73ffffffffffffffffffffffffffffffffffffffff835416815260018301805461124b81611ee8565b916112596040519384611ea7565b8183528a526020808b20908b9084015b83821061128f5750505050600192826020928360029501528152019201920191906110f8565b60016020819261129e86611f00565b815201930191019091611269565b503461011957807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101195760405180916020601654928381520191601682527fd833147d7dc355ba459fc788f669e58cfaf9dc25ddcd0702e87d69c7b5124289915b818110611329576101a58561019981870382611ea7565b825473ffffffffffffffffffffffffffffffffffffffff16845260209093019260019283019201611312565b905034610420575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261042057737109709ecfa91a80626ff3989d68f67f5b1dd12d3b15610420577fe5d6bf02000000000000000000000000000000000000000000000000000000008152636553f10060048201525f8160248183737109709ecfa91a80626ff3989d68f67f5b1dd12d5af18015611c2a57611c17575b50604051610e1e8082019082821067ffffffffffffffff831117611b5d5760c091839161be71833960408152600960408201527f5075736820555344430000000000000000000000000000000000000000000000606082015260806020820152600560808201527f705553444300000000000000000000000000000000000000000000000000000060a082015203019082f08015611af95773ffffffffffffffffffffffffffffffffffffffff167fffffffffffffffffffffffff0000000000000000000000000000000000000000602154161760215560405161389f8082019082821067ffffffffffffffff831117611b5d579082916139918339039082f08015611af95773ffffffffffffffffffffffffffffffffffffffff16807fffffffffffffffffffffffff0000000000000000000000000000000000000000602054161760205573ffffffffffffffffffffffffffffffffffffffff6021541673ffffffffffffffffffffffffffffffffffffffff6024541673ffffffffffffffffffffffffffffffffffffffff6023541690604051927fc0c53b8b000000000000000000000000000000000000000000000000000000006020850152602484015260448301526064820152606481526115cf608482611ea7565b73ffffffffffffffffffffffffffffffffffffffff602254169160405192610e54918285019285841067ffffffffffffffff851117611bea579285949260609261162c95612b3d8839825260208201528160408201520190611ca5565b039082f08015611af9577fffffffffffffffffffffff0000000000000000000000000000000000000000ff74ffffffffffffffffffffffffffffffffffffffff00601f549260081b16911617601f558073ffffffffffffffffffffffffffffffffffffffff6021541673ffffffffffffffffffffffffffffffffffffffff60255416813b15611be65782916044839260405194859384927f40c10f19000000000000000000000000000000000000000000000000000000008452600484015266038d7ea4c6800060248401525af1801561059457611bd1575b5073ffffffffffffffffffffffffffffffffffffffff60255416737109709ecfa91a80626ff3989d68f67f5b1dd12d3b15611bce57604051907fca669fa70000000000000000000000000000000000000000000000000000000082526004820152818160248183737109709ecfa91a80626ff3989d68f67f5b1dd12d5af1801561059457611bb9575b50602073ffffffffffffffffffffffffffffffffffffffff60215416604473ffffffffffffffffffffffffffffffffffffffff601f5460081c1660405194859384927f095ea7b300000000000000000000000000000000000000000000000000000000845260048401527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60248401525af1801561059457611b8a575b50604051610fea8082019082821067ffffffffffffffff831117611b5d5790829161cc8f8339039082f08015611af9578173ffffffffffffffffffffffffffffffffffffffff60235416737109709ecfa91a80626ff3989d68f67f5b1dd12d3b1561059057604051907fca669fa70000000000000000000000000000000000000000000000000000000082526004820152818160248183737109709ecfa91a80626ff3989d68f67f5b1dd12d5af1801561059457611b48575b5073ffffffffffffffffffffffffffffffffffffffff80601f5460081c16921691803b15610590578180916044604051809481937fce79eb60000000000000000000000000000000000000000000000000000000008352886004840152600160248401525af1801561059457611b33575b505073ffffffffffffffffffffffffffffffffffffffff601f5460081c1673ffffffffffffffffffffffffffffffffffffffff602154169173ffffffffffffffffffffffffffffffffffffffff6023541660405193614c41938486019486861067ffffffffffffffff871117611b06579160809593918795936172308739845260208401526040830152606082015203019082f08015611af95773ffffffffffffffffffffffffffffffffffffffff16807fffffffffffffffffffffffff0000000000000000000000000000000000000000602954161760295560175468010000000000000000811015611acc576001810180601755811015611a9f577fc624b66cc0138b8fabc209247f72d758e1cf3343756d543badbf24212bed8c1501907fffffffffffffffffffffffff000000000000000000000000000000000000000082541617905580f35b6024837f4e487b710000000000000000000000000000000000000000000000000000000081526032600452fd5b6024837f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b50604051903d90823e3d90fd5b6024887f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b81611b3d91611ea7565b61059057815f611955565b81611b5291611ea7565b61059057815f6118e4565b6024847f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b611bab9060203d602011611bb2575b611ba38183611ea7565b810190612003565b505f61182b565b503d611b99565b81611bc391611ea7565b61011957805f61178e565b50fd5b81611bdb91611ea7565b61011957805f611705565b5050fd5b6024877f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b611c2391505f90611ea7565b5f806113f5565b6040513d5f823e3d90fd5b60206040818301928281528451809452019201905f5b818110611c585750505090565b825173ffffffffffffffffffffffffffffffffffffffff16845260209384019390920191600101611c4b565b5f5b838110611c955750505f910152565b8181015183820152602001611c86565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602093611ce181518092818752878088019101611c84565b0116010190565b90602080835192838152019201905f5b818110611d055750505090565b82517fffffffff0000000000000000000000000000000000000000000000000000000016845260209384019390920191600101611cf8565b602081016020825282518091526040820191602060408360051b8301019401925f915b838310611d6f57505050505090565b9091929394602080611dab837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc086600196030187528951611ca5565b97019301930191939290611d60565b602081016020825282518091526040820191602060408360051b8301019401925f915b838310611dec57505050505090565b9091929394602080611e4f837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc086600196030187526040838b5173ffffffffffffffffffffffffffffffffffffffff815116845201519181858201520190611ce8565b97019301930191939290611ddd565b6040810190811067ffffffffffffffff821117611e7a57604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117611e7a57604052565b67ffffffffffffffff8111611e7a5760051b60200190565b90604051915f8154908160011c9260018316928315611ff9575b602085108414611fcc578487528693908115611f8c5750600114611f48575b50611f4692500383611ea7565b565b90505f9291925260205f20905f915b818310611f70575050906020611f46928201015f611f39565b6020919350806001915483858901015201910190918492611f57565b60209350611f469592507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091501682840152151560051b8201015f611f39565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b93607f1693611f1a565b90816020910312610420575180151581036104205790565b81601f8201121561042057805167ffffffffffffffff8111611e7a576040519261206d601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200185611ea7565b818452602082840101116104205761208b9160208085019101611c84565b90565b73ffffffffffffffffffffffffffffffffffffffff60295416604051907fe662e387000000000000000000000000000000000000000000000000000000008252602082600481845afa908115611c2a576004925f926121fa575b505f90604051938480927f087320b20000000000000000000000000000000000000000000000000000000082525afa918215611c2a575f926121ba575b50737109709ecfa91a80626ff3989d68f67f5b1dd12d3b156104205761218a915f9160405193849283927f7ba0480900000000000000000000000000000000000000000000000000000000845215156004840152604060248401526044830190611ca5565b0381737109709ecfa91a80626ff3989d68f67f5b1dd12d5afa8015611c2a576121b05750565b5f611f4691611ea7565b9091503d805f833e6121cc8183611ea7565b810160208282031261042057815167ffffffffffffffff8111610420576121f3920161201b565b905f612125565b5f9192506122169060203d602011611bb257611ba38183611ea7565b91906120e8565b73ffffffffffffffffffffffffffffffffffffffff602154602082601f5460081c16916024604051809581937f70a08231000000000000000000000000000000000000000000000000000000008352866004840152165afa918215611c2a575f9261236b575b506020600491604051928380927ff91682310000000000000000000000000000000000000000000000000000000082525afa908115611c2a575f91612339575b50737109709ecfa91a80626ff3989d68f67f5b1dd12d3b1561042057604051917fa8d4d1d9000000000000000000000000000000000000000000000000000000008352600483015260248201525f81604481737109709ecfa91a80626ff3989d68f67f5b1dd12d5afa8015611c2a576121b05750565b90506020813d602011612363575b8161235460209383611ea7565b8101031261042057515f6122c3565b3d9150612347565b9091506020813d602011612398575b8161238760209383611ea7565b810103126104205751906020612283565b3d915061237a565b90604051918281549182825260208201905f5260205f20925f905b8060078301106125b757611f46945491818110612581575b81811061254b575b818110612515575b8181106124df575b8181106124a9575b818110612473575b81811061243e575b10612411575b500383611ea7565b7fffffffff000000000000000000000000000000000000000000000000000000001681526020015f612409565b9260206001917fffffffff0000000000000000000000000000000000000000000000000000000085831b168152019301612403565b9260206001917fffffffff000000000000000000000000000000000000000000000000000000008560401b1681520193016123fb565b9260206001917fffffffff000000000000000000000000000000000000000000000000000000008560601b1681520193016123f3565b9260206001917fffffffff000000000000000000000000000000000000000000000000000000008560801b1681520193016123eb565b9260206001917fffffffff000000000000000000000000000000000000000000000000000000008560a01b1681520193016123e3565b9260206001917fffffffff000000000000000000000000000000000000000000000000000000008560c01b1681520193016123db565b9260206001917fffffffff000000000000000000000000000000000000000000000000000000008560e01b1681520193016123d3565b9160089193506101006001917fffffffff000000000000000000000000000000000000000000000000000000008754818160e01b168352818160c01b166020840152818160a01b166040840152818160801b166060840152818160601b166080840152818160401b1660a0840152818160201b1660c08401521660e08201520194019201859293916123bb565b60085460ff1680156126535790565b506040517f667f9d70000000000000000000000000000000000000000000000000000000008152737109709ecfa91a80626ff3989d68f67f5b1dd12d60048201527f6661696c656400000000000000000000000000000000000000000000000000006024820152602081604481737109709ecfa91a80626ff3989d68f67f5b1dd12d5afa908115611c2a575f916126eb575b50151590565b90506020813d602011612715575b8161270660209383611ea7565b8101031261042057515f6126e5565b3d91506126f9565b519073ffffffffffffffffffffffffffffffffffffffff8216820361042057565b5f73ffffffffffffffffffffffffffffffffffffffff601f5460081c166040517f50355d76000000000000000000000000000000000000000000000000000000008152602081600481855afa908115611c2a575f91612aa2575b5060015b81811115612890575050906020600492604051938480927ff91682310000000000000000000000000000000000000000000000000000000082525afa918215611c2a575f9261285c575b50737109709ecfa91a80626ff3989d68f67f5b1dd12d3b1561042057604051917f98296c54000000000000000000000000000000000000000000000000000000008352600483015260248201525f81604481737109709ecfa91a80626ff3989d68f67f5b1dd12d5afa8015611c2a576121b05750565b9091506020813d602011612888575b8161287860209383611ea7565b810103126104205751905f6127e6565b3d915061286b565b6040517fbf22c4570000000000000000000000000000000000000000000000000000000081528160048201525f81602481875afa908115611c2a575f916129aa575b50602081018051600681101561297d57600114908115612968575b50612950575b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146129235760010161279c565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b60c0909491940151810180911161292357925f6128f3565b905051600681101561297d576002145f6128ed565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b90503d805f833e6129bb8183611ea7565b8101906020818303126104205780519067ffffffffffffffff82116104205701610100818303126104205760405191610100830183811067ffffffffffffffff821117611e7a57604052612a0e8261271d565b835260208201516006811015610420576020840152612a2f6040830161271d565b6040840152606082015165ffffffffffff81168103610420576060840152612a596080830161271d565b6080840152612a6a60a0830161271d565b60a084015260c082015160c084015260e082015167ffffffffffffffff811161042057612a97920161201b565b60e08201525f6128d2565b90506020813d602011612acc575b81612abd60209383611ea7565b8101031261042057515f612798565b3d9150612ab0565b737109709ecfa91a80626ff3989d68f67f5b1dd12d3b156104205761218a915f9160405193849283927fd9a3c4d20000000000000000000000000000000000000000000000000000000084526004840152846024840152606060448401526064830190611ca556fe60a0604052610e548038038061001481610281565b928339810160608282031261027d5761002c826102a6565b610038602084016102a6565b604084015190936001600160401b03821161027d570182601f8201121561027d5780519061006d610068836102ba565b610281565b938285526020838301011161027d575f5b82811061026857505060205f9184010152803b15610248577f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0383169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a2815115610231575f8083602061013095519101845af43d15610229573d91610121610068846102ba565b9283523d5f602085013e6102d5565b505b6040519061064f8083016001600160401b038111848210176102155760209284926107e584396001600160a01b031681520301905ff0801561020a5760018060a01b0316806080525f80516020610e34833981519152547f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6040805160018060a01b0384168152846020820152a181156101f7576001600160a01b031916175f80516020610e34833981519152556040516104b1908161033482396080518160070152f35b633173bdd160e11b5f525f60045260245ffd5b6040513d5f823e3d90fd5b634e487b7160e01b5f52604160045260245ffd5b6060916102d5565b505034156101325763b398979f60e01b5f5260045ffd5b634c9c8ce360e01b5f9081526001600160a01b0391909116600452602490fd5b8060208092840101518282880101520161007e565b5f80fd5b6040519190601f01601f191682016001600160401b0381118382101761021557604052565b51906001600160a01b038216820361027d57565b6001600160401b03811161021557601f01601f191660200190565b906102f957508051156102ea57805190602001fd5b63d6bda27560e01b5f5260045ffd5b8151158061032a575b61030a575090565b639996b31560e01b5f9081526001600160a01b0391909116600452602490fd5b50803b1561030256fe6080604052337f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16036100bd575f357fffffffff00000000000000000000000000000000000000000000000000000000167f4f1ef28600000000000000000000000000000000000000000000000000000000146100b3577fd2b576ec000000000000000000000000000000000000000000000000000000005f5260045ffd5b6100bb6101c1565b005b5f8073ffffffffffffffffffffffffffffffffffffffff7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5416368280378136915af43d5f803e1561010d573d5ff35b3d5ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f604051930116820182811067ffffffffffffffff82111761018257604052565b610111565b67ffffffffffffffff811161018257601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b366004116102745760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102745760043573ffffffffffffffffffffffffffffffffffffffff8116809103610274576024359067ffffffffffffffff821161027457366023830112156102745781600401359061024961024483610187565b61013e565b918083523660248286010111610274576020815f92602461027297018387013784010152610278565b565b5f80fd5b90813b156103675773ffffffffffffffffffffffffffffffffffffffff8216807fffffffffffffffffffffffff00000000000000000000000000000000000000007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5416177f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a280511561033657610333916103a9565b50565b50503461033f57565b7fb398979f000000000000000000000000000000000000000000000000000000005f5260045ffd5b73ffffffffffffffffffffffffffffffffffffffff827f4c9c8ce3000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b5f806103db93602081519101845af43d156103de573d916103cc61024484610187565b9283523d5f602085013e6103e2565b90565b6060915b9061041f57508051156103f757805190602001fd5b7fd6bda275000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580610472575b610430575090565b73ffffffffffffffffffffffffffffffffffffffff907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561042856fea2646970667358221220481cacafffcdffc0448fe9cfe96f8149f61f2083b69e100dc149c658ac2528fd64736f6c634300081a003360803460b857601f61064f38819003918201601f19168301916001600160401b0383118484101760bc5780849260209460405283398101031260b857516001600160a01b0381169081900360b857801560a5575f80546001600160a01b031981168317825560405192916001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a361057e90816100d18239f35b631e4fbdf760e01b5f525f60045260245ffd5b5f80fd5b634e487b7160e01b5f52604160045260245ffdfe60806040526004361015610011575f80fd5b5f803560e01c8063715018a6146103c45780638da5cb5b146103745780639623609d146101cb578063ad3cb1cc146101485763f2fde38b14610051575f80fd5b346101455760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101455760043573ffffffffffffffffffffffffffffffffffffffff8116809103610141576100a96104fc565b80156101155773ffffffffffffffffffffffffffffffffffffffff8254827fffffffffffffffffffffffff00000000000000000000000000000000000000008216178455167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b6024827f1e4fbdf700000000000000000000000000000000000000000000000000000000815280600452fd5b5080fd5b80fd5b503461014557807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261014557506101c760405161018960408261045e565b600581527f352e302e30000000000000000000000000000000000000000000000000000000602082015260405191829160208352602083019061049f565b0390f35b5060607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103435760043573ffffffffffffffffffffffffffffffffffffffff81168091036103435760243573ffffffffffffffffffffffffffffffffffffffff81168091036103435760443567ffffffffffffffff8111610343573660238201121561034357806004013567ffffffffffffffff8111610347576040519161029f601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0166020018461045e565b818352366024838301011161034357815f9260246020930183860137830101526102c76104fc565b823b1561034357610316925f926040518095819482937f4f1ef286000000000000000000000000000000000000000000000000000000008452600484015260406024840152604483019061049f565b039134905af180156103385761032a575080f35b61033691505f9061045e565b005b6040513d5f823e3d90fd5b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b34610343575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261034357602073ffffffffffffffffffffffffffffffffffffffff5f5416604051908152f35b34610343575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610343576103fa6104fc565b5f73ffffffffffffffffffffffffffffffffffffffff81547fffffffffffffffffffffffff000000000000000000000000000000000000000081168355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761034757604052565b91908251928382525f5b8481106104e75750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f845f6020809697860101520116010190565b806020809284010151828286010152016104a9565b73ffffffffffffffffffffffffffffffffffffffff5f5416330361051c57565b7f118cdaa7000000000000000000000000000000000000000000000000000000005f523360045260245ffdfea2646970667358221220bf8617a09a791c192cb0d344676f2dcbe88d7a55549a679b2ee10beaae67e98364736f6c634300081a0033b53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61036080806040523460d0577ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460ff8160401c1660c1576002600160401b03196001600160401b03821601605c575b6040516137ca90816100d58239f35b6001600160401b0319166001600160401b039081177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005581527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a15f80604d565b63f92ee8a960e01b5f5260045ffd5b5f80fdfe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a714612aed57508063248a9ca314612a7d5780632f0e31f414612a425780632f2ff15d146129c75780632f8e6a2d1461298d5780633013ce291461293d57806336568abe146128b55780633f4ba83a146127e55780634152881214611fe557806341dd26f514611e1f5780634c4911c414611cba57806350355d7614611c7f5780635b7baf6414611a955780635c975abb14611a365780636d3b96c3146119ce57806375b238fc146119765780637ab03cf21461193c5780638456cb591461186957806384f15090146117ea57806391d14854146117565780639e63798d1461162b578063a217fddf146115f3578063b4d884f6146114fd578063bf22c45714611269578063c0c53b8b14610ecc578063c9a84bb914610c84578063ce79eb6014610bb6578063d2e13f501461096a578063d547741f146108e8578063d75bbdf31461067d578063dd4ae9d4146104b0578063e138818c1461045f578063e1a4521814610425578063e63ea40814610222578063f9168231146101e75763ff96092a146101a8575f80fd5b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e3576020600154604051908152f35b5f80fd5b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e3576020600754604051908152f35b346101e35760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357610259612bcc565b610261612ba9565b73ffffffffffffffffffffffffffffffffffffffff60443592610282612e1e565b61028a613662565b169081158015610407575b6103df5773ffffffffffffffffffffffffffffffffffffffff5f5416808314610309575b50602073ffffffffffffffffffffffffffffffffffffffff826102fe867ff24ef89f38eadc1bde50701ad6e4d6d11a2dc24f7cf834a486991f38833285049587613605565b6040519586521693a3005b6020602491604051928380927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa9081156103d4575f916103a2575b506007548082111561039a5761036391612dfe565b808411156102b957837f9529d841000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b50505f610363565b90506020813d6020116103cc575b816103bd60209383612cf9565b810103126101e357518461034e565b3d91506103b0565b6040513d5f823e3d90fd5b7fd92e233d000000000000000000000000000000000000000000000000000000005f5260045ffd5b5073ffffffffffffffffffffffffffffffffffffffff811615610295565b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e35760206040516127108152f35b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357602073ffffffffffffffffffffffffffffffffffffffff60025416604051908152f35b346101e3576104be36612c1d565b9290916104c9613331565b6104d1613384565b6104da826133fb565b60ff815460a01c1660068110156106505761062857600181015465ffffffffffff8160a01c164210156106285773ffffffffffffffffffffffffffffffffffffffff16330361060057827f869e2577b006bf47ee981cf6fec2e25583548081c14b98deab587f77b5068038602073ffffffffffffffffffffffffffffffffffffffff946105b46105da996105886040519a8b9233878501528560408501526060808501526080840191612d8b565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081018a5289612cf9565b80600460038701966105ca8b888b8b541661345f565b0155604051908152a2541661357c565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055005b7f82b42900000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f8e78f0cb000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b346101e35761068b36612c1d565b919290610696613331565b61069e613384565b6106a7826133fb565b9360ff855460a01c166006811015610650576002036106285773ffffffffffffffffffffffffffffffffffffffff6002860154163303610600576107fd837f21d71db5be59bb9fa133895586b7404307dd33fb93b16db09dc6f1d9d7d231b060206105da9861076473ffffffffffffffffffffffffffffffffffffffff976107386040519b8c928a33888601612dc9565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081018b528a612cf9565b60038101956107778a868a8a541661345f565b6004820154740300000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff8454161783556107c581600754612dfe565b6007558860016127106107d9825485612e0b565b049889936107f86127106107ef60035484612e0b565b04958692612dfe565b612dfe565b9401541696806108a3575b5080610863575b5081610850575b604051908152847f0fd54bd364fa9e67f17b091aefe930932c09fe7651cf5ad02c71a418f3341444843393a3604051908152a3541661357c565b61085e82878a5f5416613605565b610816565b61087181338b5f5416613605565b604051908152857f253dd534010ac976fa263caa123bae79b9c50292adf7ce67bdc5ec309f784e61853393a38b61080f565b867f0e61cfd0ee655641b3ed0a1dd373ec3cacf4c090de1f33708e3a4091f4947662868c60025416936108db818f87905f5416613605565b604051908152a38c610808565b346101e35760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357610968600435610925612ba9565b9061096361095e825f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602052600160405f20015490565b612ea6565b613229565b005b346101e35761097836612c1d565b61098493919293613331565b61098c613384565b610995826133fb565b93845460ff8160a01c166006811015610650576106285773ffffffffffffffffffffffffffffffffffffffff16330361060057600185015473ffffffffffffffffffffffffffffffffffffffff811615610b8e5760a01c65ffffffffffff16421015610628576004850190815403610b66576105da94610a6f73ffffffffffffffffffffffffffffffffffffffff93610a436040519788923360208501526040808501526060840191612d8b565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101875286612cf9565b6003810191610a8286868686541661345f565b5490740100000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff825416179055610acd81600754612ccf565b60075580610b0a575b604051908152837fe3fbcc1ea1bdc559ec7f0347efde7655e58b5f45a30b0e4470a583c3ef5496b360203393a3541661357c565b610b61835f5416604051907f23b872dd00000000000000000000000000000000000000000000000000000000602083015233602483015230604483015283606483015260648252610b5c608483612cf9565b61370d565b610ad6565b7f99b0fc87000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fa9456d43000000000000000000000000000000000000000000000000000000005f5260045ffd5b346101e35760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357610bed612bcc565b602435908115158092036101e35773ffffffffffffffffffffffffffffffffffffffff90610c19612e1e565b169081156103df5760207f7ee54953080e392a475a25b6acacb85417ca4e1953293c90934233ca1361251091835f526006825260405f207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0081541660ff8316179055604051908152a2005b346101e35760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357600435610cbe612ba9565b60443567ffffffffffffffff81116101e357610cde903690600401612bef565b929091610ce9613331565b610cf1613384565b610cfa826133fb565b90815460ff8160a01c1660068110156106505761062857600183019182549165ffffffffffff8360a01c164210156106285773ffffffffffffffffffffffffffffffffffffffff16918233036106005773ffffffffffffffffffffffffffffffffffffffff166106285773ffffffffffffffffffffffffffffffffffffffff169081156103df578114610ea45773ffffffffffffffffffffffffffffffffffffffff6002840154168114610e7c57600373ffffffffffffffffffffffffffffffffffffffff93610e186105da98610dec604051998a923360208501528760408501526060808501526080840191612d8b565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101895288612cf9565b0191610e2886868686541661345f565b817fffffffffffffffffffffffff0000000000000000000000000000000000000000825416179055837f9a87df076ea1725aba8ba29d32517ce37c9597d88cbf16ec6707892cc330ab695f80a3541661357c565b7fc7b4e9eb000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f332ff0f9000000000000000000000000000000000000000000000000000000005f5260045ffd5b346101e35760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357610f03612bcc565b610f0b612ba9565b60443573ffffffffffffffffffffffffffffffffffffffff81168082036101e3577ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460ff8160401c16159467ffffffffffffffff821680159081611261575b6001149081611257575b15908161124e575b5061122657818660017fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000073ffffffffffffffffffffffffffffffffffffffff9516177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00556111d1575b50169081159081156111b2575b81156111a9575b506103df576110bd9273ffffffffffffffffffffffffffffffffffffffff916110216136b6565b6110296136b6565b6110316136b6565b6110396136b6565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00557fffffffffffffffffffffffff00000000000000000000000000000000000000005f5416175f55167fffffffffffffffffffffffff000000000000000000000000000000000000000060025416176002556110b781612f2c565b50613013565b505f805260066020527f54cdd369e4e8a8515e52ca72ec816c2101831ad1f18bf44102ed171459c9b4f880547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905561111657005b7fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054167ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a1005b90501585610ffa565b73ffffffffffffffffffffffffffffffffffffffff8516159150610ff3565b7fffffffffffffffffffffffffffffffffffffffffffffff0000000000000000001668010000000000000001177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005586610fe6565b7ff92ee8a9000000000000000000000000000000000000000000000000000000005f5260045ffd5b90501587610f7d565b303b159150610f75565b879150610f6b565b346101e35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357606060e06040516112a881612cdc565b5f81525f60208201525f60408201525f838201525f60808201525f60a08201525f60c082015201526004355f52600460205260405f20604051906112eb82612cdc565b60ff815473ffffffffffffffffffffffffffffffffffffffff8116845260a01c169060208301916006811015610650578252600181015491604084019173ffffffffffffffffffffffffffffffffffffffff8416835265ffffffffffff606086019460a01c16845273ffffffffffffffffffffffffffffffffffffffff600282015416936080860194855273ffffffffffffffffffffffffffffffffffffffff60038301541660a08701908152600560048401549360c08901948552019360405194855f8254926113bb84612d3a565b80845293600181169081156114bd5750600114611479575b506113e092500386612cf9565b60e0880194855273ffffffffffffffffffffffffffffffffffffffff6040519860208a525116602089015251600681101561065057879665ffffffffffff73ffffffffffffffffffffffffffffffffffffffff948561147599819560408d0152511660608b015251166080890152511660a0870152511660c08501525160e08401525161010080840152610120830190612c72565b0390f35b90505f9291925260205f20905f915b8183106114a15750509060206113e0928201018b6113d3565b6020919350806001915483858c01015201910190918792611488565b602093506113e09592507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091501682840152151560051b8201018b6113d3565b346101e35760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e35760043573ffffffffffffffffffffffffffffffffffffffff61154c612ba9565b611554612e1e565b169081156103df5761271061156b60035483612ccf565b116115cb576020817ff0c09f5238364083d828870e877edaebb364d9f19f4093fdbf24e486bbdca48492600155837fffffffffffffffffffffffff00000000000000000000000000000000000000006002541617600255604051908152a2005b7fc9034e18000000000000000000000000000000000000000000000000000000005f5260045ffd5b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e35760206040515f8152f35b346101e35761163936612c1d565b919290611644613331565b61164c613384565b611655826133fb565b60ff815460a01c1660068110156106505760010361062857600181015465ffffffffffff8160a01c164210156106285773ffffffffffffffffffffffffffffffffffffffff163303610600576105da946116d273ffffffffffffffffffffffffffffffffffffffff93610a43604051978892853360208601612dc9565b60038201916116e586868686541661345f565b740200000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff825416179055604051908152837f80c17db79857f338a6a6df68a6883ecc0ce78e2202fe61ed979733573f40538e60203393a3541661357c565b346101e35760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e35761178d612ba9565b6004355f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205273ffffffffffffffffffffffffffffffffffffffff60405f2091165f52602052602060ff60405f2054166040519015158152f35b346101e35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357600435611824612e1e565b61271061183360015483612ccf565b116115cb576020817f24fe03678743d8fe5f3d39d760da9fc7a5f3feea46847d91688ba8ef9e400d1492600355604051908152a1005b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e35761189f612e1e565b6118a7613331565b60017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff007fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005416177fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586020604051338152a1005b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357602060405161012c8152f35b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e35760206040517fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c217758152f35b346101e35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e35773ffffffffffffffffffffffffffffffffffffffff611a1a612bcc565b165f526006602052602060ff60405f2054166040519015158152f35b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357602060ff7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330054166040519015158152f35b346101e35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357600435611acf613384565b611ad8816133fb565b60ff815460a01c166006811015908161065057801515918280611c72575b8181611c61575b506106285761065057600203611c225765ffffffffffff600183015460a01c16610e108101809111611bf5574210611bcd575b740500000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff835416178255611bbd575b507f97237956f8810192811e2c3f273fd02c5d6295206fdd9c62e6fe2bfc19ba92325f80a260017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055005b611bc79082613505565b81611b72565b7f478f84e7000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b65ffffffffffff600183015460a01c16421015611b30577f8e78f0cb000000000000000000000000000000000000000000000000000000005f5260045ffd5b905061065057600282141581611afd565b50505f6001821415611af6565b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e3576020600554604051908152f35b346101e35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e35760043567ffffffffffffffff81116101e357366023820112156101e357806004013567ffffffffffffffff81116101e3573660248260051b840101116101e357611d31612e1e565b600554915f5b828110156109685760248160051b830101359081158015611e16575b611dee57816001925f52600460205273ffffffffffffffffffffffffffffffffffffffff600360405f20015416908115611de757805f526004602052600360405f20017fffffffffffffffffffffffff000000000000000000000000000000000000000081541690557fcde6a24b3e1e5d23bc4d45609905c64b3516b23478ba2f7fdada3ab2bae3812d5f80a35b01611d37565b5050611de1565b7f71c8f460000000000000000000000000000000000000000000000000000000005f5260045ffd5b50848211611d53565b346101e357611e2d36612c1d565b919290611e38613331565b611e40613384565b611e49826133fb565b9384549060ff8260a01c169260068410159283610650578415948515611f97575073ffffffffffffffffffffffffffffffffffffffff1633141580611f73575b61060057611ea6905b610a43604051978892853360208601612dc9565b6003860191611ecd868673ffffffffffffffffffffffffffffffffffffffff86541661345f565b740400000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff885416178755610650576105da9573ffffffffffffffffffffffffffffffffffffffff9315611f63575b50604051908152837fae7362b1af91f4492868987b9c73990d780060811551b58728fbe96fd1bab27560203393a3541661357c565b611f6d9085613505565b86611f2e565b5073ffffffffffffffffffffffffffffffffffffffff600188015416331415611e89565b5f94506001811491508115611fd7575b50156106285773ffffffffffffffffffffffffffffffffffffffff600288015416330361060057611ea690611e92565b93505060025f931488611fa7565b346101e35760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e35761201c612bcc565b612024612ba9565b60443560643567ffffffffffffffff81116101e357612047903690600401612bef565b9390926084359273ffffffffffffffffffffffffffffffffffffffff8416918285036101e35773ffffffffffffffffffffffffffffffffffffffff9061208b613331565b612093613384565b169283156103df5761012c4201804211611bf55782118015906127d6575b6127ae5773ffffffffffffffffffffffffffffffffffffffff1693338514610ea457841515806127a5575b610e7c57825f52600660205260ff60405f2054161561277d5782151590816125a4575b5061257c576005547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114611bf557600101948560055560405161214281612cdc565b33815287602082015f81526040830193888552606084019165ffffffffffff87168352608085019089825260a086019289845267ffffffffffffffff60c08801965f88521161254f578d906040519e8f6121c460207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8501160182612cf9565b5236828201116101e357818f5f936020938483013701015260e086019c8d528b5f52600460205273ffffffffffffffffffffffffffffffffffffffff8060405f20975116167fffffffffffffffffffffffff0000000000000000000000000000000000000000875416178655519060068210156106505760059673ffffffffffffffffffffffffffffffffffffffff9485937fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff74ff00000000000000000000000000000000000000008a549260a01b169116178855838060018a01935116167fffffffffffffffffffffffff0000000000000000000000000000000000000000835416178255517fffffffffffff000000000000ffffffffffffffffffffffffffffffffffffffff79ffffffffffff000000000000000000000000000000000000000083549260a01b1691161790555116826002860191167fffffffffffffffffffffffff0000000000000000000000000000000000000000825416179055511673ffffffffffffffffffffffffffffffffffffffff6003840191167fffffffffffffffffffffffff000000000000000000000000000000000000000082541617905551600482015501955195865167ffffffffffffffff811161254f576123ac8254612d3a565b601f811161250a575b50806020988990601f831160011461246d575f92612462575b50507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c19161790555b604051928352858301526040820152827fb0f0239bfdd96453e24733e18bfc24b70d8fadf123dd977473518dd577ee79b960603393a460017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055604051908152f35b0151905089806123ce565b5f858152828120937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016905b8181106124f357509084600195949392106124bc575b505050811b019055612400565b01517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c191690558980806124af565b92938c600181928786015181550195019301612499565b825f5260205f20601f830160051c81019160208410612545575b601f0160051c01905b81811061253a57506123b5565b5f815560010161252d565b9091508190612524565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f9c9d8823000000000000000000000000000000000000000000000000000000005f5260045ffd5b905060205f604051828101907f01ffc9a70000000000000000000000000000000000000000000000000000000082527f01ffc9a700000000000000000000000000000000000000000000000000000000602482015260248152612608604482612cf9565b519084617530fa903d5f519083612771575b5082612767575b50816126ce575b81612636575b5015876120ff565b602091505f90604051838101907f01ffc9a70000000000000000000000000000000000000000000000000000000082527f7ff6bc9e0000000000000000000000000000000000000000000000000000000060248201526024815261269b604482612cf9565b5191617530fa5f513d826126c2575b50816126b8575b508761262e565b90501515876126b1565b602011159150886126aa565b905060205f604051828101907f01ffc9a70000000000000000000000000000000000000000000000000000000082527fffffffff00000000000000000000000000000000000000000000000000000000602482015260248152612732604482612cf9565b519084617530fa5f513d8261275b575b5081612751575b501590612628565b9050151588612749565b60201115915089612742565b1515915088612621565b6020111592508961261a565b7fa04b28ec000000000000000000000000000000000000000000000000000000005f5260045ffd5b508385146120dc565b7ff7a0748c000000000000000000000000000000000000000000000000000000005f5260045ffd5b5065ffffffffffff82116120b1565b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e35761281b612e1e565b612823613662565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff007fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330054167fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6020604051338152a1005b346101e35760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e3576128ec612ba9565b3373ffffffffffffffffffffffffffffffffffffffff8216036129155761096890600435613229565b7f6697b232000000000000000000000000000000000000000000000000000000005f5260045ffd5b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357602073ffffffffffffffffffffffffffffffffffffffff5f5416604051908152f35b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e3576020604051610e108152f35b346101e35760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357610968600435612a04612ba9565b90612a3d61095e825f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602052600160405f20015490565b613117565b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e3576020600354604051908152f35b346101e35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e3576020612ae56004355f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602052600160405f20015490565b604051908152f35b346101e35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357600435907fffffffff0000000000000000000000000000000000000000000000000000000082168092036101e357817f7965db0b0000000000000000000000000000000000000000000000000000000060209314908115612b7f575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483612b78565b6024359073ffffffffffffffffffffffffffffffffffffffff821682036101e357565b6004359073ffffffffffffffffffffffffffffffffffffffff821682036101e357565b9181601f840112156101e35782359167ffffffffffffffff83116101e357602083818601950101116101e357565b60607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8201126101e35760043591602435916044359067ffffffffffffffff82116101e357612c6e91600401612bef565b9091565b91908251928382525f5b848110612cba5750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f845f6020809697860101520116010190565b80602080928401015182828601015201612c7c565b91908201809211611bf557565b610100810190811067ffffffffffffffff82111761254f57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761254f57604052565b90600182811c92168015612d81575b6020831014612d5457565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b91607f1691612d49565b601f82602094937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe093818652868601375f8582860101520116010190565b612dfb949273ffffffffffffffffffffffffffffffffffffffff60609316825260208201528160408201520191612d8b565b90565b91908203918211611bf557565b81810292918115918404141715611bf557565b335f9081527fb16e88c42fd4e48df2dd6a2eabd6bc9aec654ec170056b470819f8892cc6431c602052604090205460ff1615612e5657565b7fe2517d3f000000000000000000000000000000000000000000000000000000005f52336004527fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177560245260445ffd5b805f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260405f2073ffffffffffffffffffffffffffffffffffffffff33165f5260205260ff60405f20541615612efd5750565b7fe2517d3f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b73ffffffffffffffffffffffffffffffffffffffff81165f9081527fb7db2dd08fcb62d0c9e08c51941cae53c267786a0b75803fb7960902fc8ef97d602052604090205460ff1661300e5773ffffffffffffffffffffffffffffffffffffffff165f8181527fb7db2dd08fcb62d0c9e08c51941cae53c267786a0b75803fb7960902fc8ef97d6020526040812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790553391907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d8180a4600190565b505f90565b73ffffffffffffffffffffffffffffffffffffffff81165f9081527fb16e88c42fd4e48df2dd6a2eabd6bc9aec654ec170056b470819f8892cc6431c602052604090205460ff1661300e5773ffffffffffffffffffffffffffffffffffffffff165f8181527fb16e88c42fd4e48df2dd6a2eabd6bc9aec654ec170056b470819f8892cc6431c6020526040812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790553391907fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9080a4600190565b805f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260ff60405f205416155f1461322357805f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260405f2060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082541617905573ffffffffffffffffffffffffffffffffffffffff339216907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d5f80a4600190565b50505f90565b805f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260ff60405f2054165f1461322357805f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260405f207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00815416905573ffffffffffffffffffffffffffffffffffffffff339216907ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b5f80a4600190565b60ff7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300541661335c57565b7fd93c0665000000000000000000000000000000000000000000000000000000005f5260045ffd5b60027f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0054146133d35760027f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b7f3ee5aeb5000000000000000000000000000000000000000000000000000000005f5260045ffd5b80158015613416575b611dee575f52600460205260405f2090565b506005548111613404565b7fffffffff00000000000000000000000000000000000000000000000000000000612dfb949360609383521660208201528160408201520190612c72565b73ffffffffffffffffffffffffffffffffffffffff16918261348057505050565b823b156101e3576134e8925f92836040518096819582947fdc08fb1d0000000000000000000000000000000000000000000000000000000084527fffffffff000000000000000000000000000000000000000000000000000000008535169060048501613421565b03925af180156103d4576134f95750565b5f61350391612cf9565b565b600482015491821561357757602073ffffffffffffffffffffffffffffffffffffffff7f7ca5472b7ea78c2c0141c5a12ee6d170cf4ce8ed06be3d22c8252ddfc7a6a2c49261355686600754612dfe565b60075561356b86835f54168484541690613605565b541693604051908152a3565b505050565b73ffffffffffffffffffffffffffffffffffffffff16918261359d57505050565b823b156101e3576134e8925f92836040518096819582947fa3fe47830000000000000000000000000000000000000000000000000000000084527fffffffff000000000000000000000000000000000000000000000000000000008535169060048501613421565b6135039273ffffffffffffffffffffffffffffffffffffffff604051937fa9059cbb000000000000000000000000000000000000000000000000000000006020860152166024840152604483015260448252610b5c606483612cf9565b60ff7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330054161561368e57565b7f8dfc202b000000000000000000000000000000000000000000000000000000005f5260045ffd5b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c16156136e557565b7fd7e6bcf8000000000000000000000000000000000000000000000000000000005f5260045ffd5b905f602091828151910182855af1156103d4575f513d61378b575073ffffffffffffffffffffffffffffffffffffffff81163b155b6137495750565b73ffffffffffffffffffffffffffffffffffffffff907f5274afe7000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b6001141561374256fea26469706673582212206c80219f5022a102b78e2b3cea53bc36a61bd9d0874a3d24319381fbeaeb022a64736f6c634300081a0033608080604052346104ca57608081614c41803803809161001f8285610d0a565b8339810103126104ca578051906001600160a01b03821682036104ca5760208101516001600160a01b038116908190036104ca57600161006d606061006660408601610d41565b9401610d41565b938160ff19600c541617600c55601f54906101008360a81b039060081b1690828060a81b0319161717601f5560018060a01b0319602054161760205560018060a01b031660018060a01b0319602154161760215560018060a01b031660018060a01b031960225416176022555f5b60038110156105d35760405163348051d760e11b8152600481018290525f816024815f80516020614c218339815191525afa9081156104d6575f916105b9575b50604051906101566021836020810193606360f81b85526101458151809260208686019101610d79565b81010301601f198101845283610d0a565b60405160208101906101826020828651610171818789610d79565b81010301601f198101835282610d0a565b519020916040519263ffa1864960e01b845260048401526020836024815f80516020614c218339815191525afa9283156104d6575f9361057e575b505f80516020614c218339815191523b156104ca5761021260645f9260405194859384926318caf8e360e31b845260018060a01b03891660048501526040602485015251809281604486015285850190610d79565b601f01601f19168101030181835f80516020614c218339815191525af180156104d65761056e575b506023820180546001600160a01b0319166001600160a01b0390921691909117815560405163348051d760e11b8152600481018390525f816024815f80516020614c218339815191525afa9081156104d6575f9161054c575b50604051906102bd6021836020810193600760fc1b85526101458151809260208686019101610d79565b60405160208101906102d86020828651610171818789610d79565b519020916040519263ffa1864960e01b845260048401526020836024815f80516020614c218339815191525afa9283156104d6575f93610511575b505f80516020614c218339815191523b156104ca5761036860645f9260405194859384926318caf8e360e31b845260018060a01b03891660048501526040602485015251809281604486015285850190610d79565b601f01601f19168101030181835f80516020614c218339815191525af180156104d657610501575b506026830180546001600160a01b0319166001600160a01b0392831617905560205482549082169116813b156104ca575f916044839260405194859384926340c10f1960e01b8452600484015264e8d4a5100060248401525af180156104d6576104f1575b50546001600160a01b03165f80516020614c218339815191523b156104ca576040519063ca669fa760e01b825260048201525f81602481835f80516020614c218339815191525af180156104d6576104e1575b5060208054601f5460405163095ea7b360e01b81526001600160a01b0360089290921c821660048201525f1960248201529291839160449183915f91165af180156104d65761049b575b506001016100db565b6020813d82116104ce575b816104b360209383610d0a565b810103126104ca5751801515036104ca575f610492565b5f80fd5b3d91506104a6565b6040513d5f823e3d90fd5b5f6104eb91610d0a565b5f610448565b5f6104fb91610d0a565b5f6103f5565b5f61050b91610d0a565b5f610390565b9092506020813d8211610544575b8161052c60209383610d0a565b810103126104ca5761053d90610d41565b915f610313565b3d915061051f565b61056891503d805f833e6105608183610d0a565b810190610d9a565b5f610293565b5f61057891610d0a565b5f61023a565b9092506020813d82116105b1575b8161059960209383610d0a565b810103126104ca576105aa90610d41565b915f6101bd565b3d915061058c565b6105cd91503d805f833e6105608183610d0a565b5f61011b565b604080516105e18282610d0a565b600281526020810161065360f41b8152825160208101906106028284610d55565b60028152610611602282610d0a565b51902083519063ffa1864960e01b825260048201526020816024815f80516020614c218339815191525afa908115610c4f575f91610cd0575b505f80516020614c218339815191523b156104ca5761069e60645f92865194859384926318caf8e360e31b845260018060a01b03169788600485015289602485015251809281604486015285850190610d79565b601f01601f19168101030181835f80516020614c218339815191525af18015610ab157610cc0575b50602980546001600160a01b03191691909117905580516106e78282610d0a565b600281526020810161653160f01b8152825160208101906107088284610d55565b60028152610717602282610d0a565b51902083519063ffa1864960e01b825260048201526020816024815f80516020614c218339815191525afa908115610c4f575f91610c86575b505f80516020614c218339815191523b156104ca576107a460645f92865194859384926318caf8e360e31b845260018060a01b03169788600485015289602485015251809281604486015285850190610d79565b601f01601f19168101030181835f80516020614c218339815191525af18015610ab157610c76575b5060018060a01b0319602a541617602a5562278d00420190814211610bf857905f915b6003831015610c69576023830180549093906001600160a01b03165f80516020614c218339815191523b156104ca5782519063ca669fa760e01b825260048201525f81602481835f80516020614c218339815191525af18015610ab157610c59575b5060018060a01b03601f5460081c16938160260190602060018060a01b0383541660e460018060a01b0360295416915f88519a8b9485936320a9440960e11b8552600485015260248401528a604484015260a06064840152600460a4840152631cd9595960e21b60c48401528160848401525af1958615610c4f575f96610c1c575b5081545f91906001600160a01b03165f80516020614c218339815191523b156104ca5785519063ca669fa760e01b825260048201525f81602481835f80516020614c218339815191525af18015610bd457610c0c575b50601f54600185019060081c6001600160a01b0316818611610bf85781620f42400291620f4240830403610bf857803b156104ca578651633752ba7560e21b8152600481018a905260248101839052606060448201525f6064820181905290918290608490829084905af18015610bee57610bde575b50875f52602b602052855f2060ff1981541690556001851015610adf575b5050600283146109d4575b505060010192506107ef565b610acb57546001600160a01b03165f80516020614c218339815191523b156104ca5782519063ca669fa760e01b825260048201525f81602481835f80516020614c218339815191525af18015610ab157610abb575b50601f5460081c6001600160a01b031693843b156104ca575f80956084855180988193639e63798d60e01b8352866004840152816024840152606060448401528160648401525af1948515610ab1576001939495610aa1575b505f52602b602052825f20600260ff19825416179055839291856109c8565b5f610aab91610d0a565b85610a82565b83513d5f823e3d90fd5b5f610ac591610d0a565b84610a29565b634e487b7160e01b5f52603260045260245ffd5b90545f92506001600160a01b03165f80516020614c218339815191523b156104ca5785519063ca669fa760e01b825260048201525f81602481835f80516020614c218339815191525af18015610bd457610bc4575b50601f5460081c6001600160a01b0316803b156104ca578551630d2e13f560e41b8152600481018990526024810192909252606060448301525f60648301819052908290608490829084905af18015610bba57610baa575b50855f52602b602052835f20600160ff1982541617905586806109bd565b5f610bb491610d0a565b86610b8c565b85513d5f823e3d90fd5b5f610bce91610d0a565b87610b34565b86513d5f823e3d90fd5b5f610be891610d0a565b8861099f565b87513d5f823e3d90fd5b634e487b7160e01b5f52601160045260245ffd5b5f610c1691610d0a565b87610929565b9095506020813d8211610c47575b81610c3760209383610d0a565b810103126104ca575194866108d3565b3d9150610c2a565b84513d5f823e3d90fd5b5f610c6391610d0a565b84610851565b51613e169081610e0b8239f35b5f610c8091610d0a565b826107cc565b90506020813d602011610cb8575b81610ca160209383610d0a565b810103126104ca57610cb290610d41565b84610750565b3d9150610c94565b5f610cca91610d0a565b826106c6565b90506020813d602011610d02575b81610ceb60209383610d0a565b810103126104ca57610cfc90610d41565b8461064a565b3d9150610cde565b601f909101601f19168101906001600160401b03821190821017610d2d57604052565b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b03821682036104ca57565b5f5b60028110610d6957505060025f910152565b8181015183820152602001610d57565b5f5b838110610d8a5750505f910152565b8181015183820152602001610d7b565b6020818303126104ca578051906001600160401b0382116104ca570181601f820112156104ca5780516001600160401b038111610d2d5760405192610de9601f8301601f191660200185610d0a565b818452602082840101116104ca57610e079160208085019101610d79565b9056fe6080806040526004361015610012575f80fd5b5f905f3560e01c90816305e3769c1461191c57508063087320b2146118025780630b78f9c0146111ce5780631ed7831c146111255780632ade388014610f685780633e5e3c2314610ebf5780633f7286f414610e16578063531c7faa14610dfe57806359e1361914610dc25780635b7baf6414610d8757806366d9a9a014610c2c578063725cc2e114610c145780637f974c6f14610bd857806381ede1bb14610bc05780638253f2d91461080d57806385226c811461075d578063916a17c6146106885780639675dc1714610670578063b0464fdc1461059b578063b5508aa9146104eb578063b5c0922c146104a0578063ba414fa61461045d578063d130382514610445578063e20c9f711461038c578063e5d6bf02146101f1578063e662e387146101b0578063fa7626d41461016f5763fd61a25614610152575f80fd5b3461016c5761016961016336611c67565b91612d94565b80f35b80fd5b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c57602060ff601f54166040519015158152f35b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c57602060ff602f54166040519015158152f35b503461016c5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c57806102336202a3006001600435613b7d565b6102fb604091838084516102478682611a0b565b600c81527f426f756e6420726573756c740000000000000000000000000000000000000000602082015285516102e4816102b260208201947fb60e72cc0000000000000000000000000000000000000000000000000000000086528a60248401526064830190611b2b565b876044830152037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282611a0b565b51906a636f6e736f6c652e6c6f675afa50426128c2565b90737109709ecfa91a80626ff3989d68f67f5b1dd12d3b15610388578051917fe5d6bf020000000000000000000000000000000000000000000000000000000083526004830152828260248183737109709ecfa91a80626ff3989d68f67f5b1dd12d5af190811561037f575061036e5750f35b8161037891611a0b565b61016c5780f35b513d84823e3d90fd5b5050fd5b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c5760405180916020601554928381520191601582527f55f448fdea98c4d29eb340757ef0a66cd03dbb9538908a6a81d96026b71ec475915b818110610419576104158561040981870382611a0b565b60405191829182611ba2565b0390f35b825473ffffffffffffffffffffffffffffffffffffffff168452602090930192600192830192016103f2565b503461016c5761016961045736611c67565b91612b77565b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c576020610496612a9e565b6040519015158152f35b503461016c5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c5760ff60406020926004358152602b8452205416604051908152f35b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c5760195461052681611db7565b916105346040519384611a0b565b818352601981527f944998273e477b495144fb8794c914197f3ccb46be2900f4698fd0ef743c9695602084015b83831061057e576040516020808252819061041590820188611bf1565b60016020819261058d85611a4c565b815201920192019190610561565b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c57601c546105d681611db7565b916105e46040519384611a0b565b818352601c81527f0e4562a10381dec21b205ed72637e6b1b523bdd0e4d4d50af5cd23dd4500a211602084015b83831061062657604051806104158782611d06565b60026020600192604051610639816119a5565b73ffffffffffffffffffffffffffffffffffffffff865416815261065e8587016121fe565b83820152815201920192019190610611565b503461016c5761016961068236611b6e565b906128cf565b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c57601d546106c381611db7565b916106d16040519384611a0b565b818352601d81527f6d4407e7be21f808e6509aa9fa9143369579dd7d760fe20a2c09680fc146134f602084015b83831061071357604051806104158782611d06565b60026020600192604051610726816119a5565b73ffffffffffffffffffffffffffffffffffffffff865416815261074b8587016121fe565b838201528152019201920191906106fe565b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c57601a5461079881611db7565b916107a66040519384611a0b565b818352601a81527f057c384a7d1c54f3a1b2e5e67b2617b8224fdfd1ea7234eea573a6ff665ff63e602084015b8383106107f0576040516020808252819061041590820188611bf1565b6001602081926107ff85611a4c565b8152019201920191906107d3565b503461016c5760c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c576084358015158103610bbc5760a4358015158103610bb8576003600435066003811015610b85576023015473ffffffffffffffffffffffffffffffffffffffff169115610bb2576003602435066003811015610b85576026015473ffffffffffffffffffffffffffffffffffffffff165b6001604435166002811015610b585773ffffffffffffffffffffffffffffffffffffffff85916029015416926108ec62278d00610168606435613b7d565b9060409583808861096b61099d82516109058482611a0b565b600c81527f426f756e6420726573756c7400000000000000000000000000000000000000006020820152835192839160208301957fb60e72cc00000000000000000000000000000000000000000000000000000000875260248401526064830190611b2b565b896044830152037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282611a0b565b51906a636f6e736f6c652e6c6f675afa50737109709ecfa91a80626ff3989d68f67f5b1dd12d3b15610b4a578651907fca669fa70000000000000000000000000000000000000000000000000000000082526004820152838160248183737109709ecfa91a80626ff3989d68f67f5b1dd12d5af18015610b4e57610b2e575b509273ffffffffffffffffffffffffffffffffffffffff9260c49284602096610a4d82601f5460081c1693426128c2565b9015610b27578160225416905b8a51998a9889977f415288120000000000000000000000000000000000000000000000000000000089521660048801526024870152604486015260a060648601528360a48601521660848401525af1839181610aef575b50610aba578280f35b8252602b60205281207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0081541690555f808280f35b9091506020813d602011610b1f575b81610b0b60209383611a0b565b81010312610b1b5751905f610ab1565b5f80fd5b3d9150610afe565b8390610a5a565b92610b3d818096939495611a0b565b610b4a579291905f610a1c565b8380fd5b87513d86823e3d90fd5b6024857f4e487b710000000000000000000000000000000000000000000000000000000081526032600452fd5b6024847f4e487b710000000000000000000000000000000000000000000000000000000081526032600452fd5b826108ae565b8280fd5b5080fd5b503461016c57610169610bd236611c67565b91612678565b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c576020602c54604051908152f35b503461016c57610169610c2636611b6e565b906124d9565b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c57601b54610c6781611db7565b610c746040519182611a0b565b818152601b83526020810191837f3ad8aa4f87544323a9d1e5dd902f40c356527a7955687113db5f9a85ad579dc1845b838310610d4c57868587604051928392602084019060208552518091526040840160408260051b8601019392905b828210610ce157505050500390f35b91936020610d3c827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0600195979984950301865288519083610d2c8351604084526040840190611b2b565b9201519084818403910152611cb1565b9601920192018594939192610cd2565b60026020600192604051610d5f816119a5565b610d6886611a4c565b8152610d758587016121fe565b83820152815201920192019190610ca4565b503461016c5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c57610169600435612106565b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c576020602e54604051908152f35b503461016c57610169610e1036611c67565b91611dfc565b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c5760405180916020601754928381520191601782527fc624b66cc0138b8fabc209247f72d758e1cf3343756d543badbf24212bed8c15915b818110610e93576104158561040981870382611a0b565b825473ffffffffffffffffffffffffffffffffffffffff16845260209093019260019283019201610e7c565b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c5760405180916020601854928381520191601882527fb13d2d76d1f4b7be834882e410b3e3a8afaf69f83600ae24db354391d2378d2e915b818110610f3c576104158561040981870382611a0b565b825473ffffffffffffffffffffffffffffffffffffffff16845260209093019260019283019201610f25565b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c57601e54610fa381611db7565b610fb06040519182611a0b565b818152601e83526020810191837f50bb669a95c7b50b7e8a6f09454034b2b14cf2b85c730dca9a539ca82cb6e350845b83831061108f57868587604051928392602084019060208552518091526040840160408260051b8601019392905b82821061101d57505050500390f35b9193602061107f827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc060019597998495030186526040838a5173ffffffffffffffffffffffffffffffffffffffff815116845201519181858201520190611bf1565b960192019201859493919261100e565b60405161109b816119a5565b73ffffffffffffffffffffffffffffffffffffffff83541681526001830180546110c481611db7565b916110d26040519384611a0b565b8183528a526020808b20908b9084015b838210611108575050505060019282602092836002950152815201920192019190610fe0565b60016020819261111786611a4c565b8152019301910190916110e2565b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c5760405180916020601654928381520191601682527fd833147d7dc355ba459fc788f669e58cfaf9dc25ddcd0702e87d69c7b5124289915b8181106111a2576104158561040981870382611a0b565b825473ffffffffffffffffffffffffffffffffffffffff1684526020909301926001928301920161118b565b5034610b1b575f906111ec6127106111e536611b6e565b9490613b7d565b916040905f8083516111fe8582611a0b565b600c81527f426f756e6420726573756c7400000000000000000000000000000000000000006020820152845161129b8161126960208201947fb60e72cc0000000000000000000000000000000000000000000000000000000086528960248401526064830190611b2b565b8a6044830152037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282611a0b565b51906a636f6e736f6c652e6c6f675afa50836127100361271081116117d5575f6112c492613b7d565b5f8083516112d28582611a0b565b600c81527f426f756e6420726573756c7400000000000000000000000000000000000000006020820152845161133d816102b260208201947fb60e72cc0000000000000000000000000000000000000000000000000000000086528960248401526064830190611b2b565b51906a636f6e736f6c652e6c6f675afa5073ffffffffffffffffffffffffffffffffffffffff60215416737109709ecfa91a80626ff3989d68f67f5b1dd12d3b15610b1b578251907f06447d5600000000000000000000000000000000000000000000000000000000825260048201525f8160248183737109709ecfa91a80626ff3989d68f67f5b1dd12d5af180156117cb576117b6575b5073ffffffffffffffffffffffffffffffffffffffff601f5460081c16803b15610b4a5783809160248551809481937f84f150900000000000000000000000000000000000000000000000000000000083528160048401525af1801561171e579084916117a1575b505073ffffffffffffffffffffffffffffffffffffffff601f5460081c168251946114688487611a0b565b600886527f747265617375727900000000000000000000000000000000000000000000000060208701528351855b6008811061178c5750958686602881990152600881526114b7602882611a0b565b602081519101208551907fffa186490000000000000000000000000000000000000000000000000000000082526004820152602081602481737109709ecfa91a80626ff3989d68f67f5b1dd12d5afa908115611744578791611752575b50737109709ecfa91a80626ff3989d68f67f5b1dd12d3b1561174e578673ffffffffffffffffffffffffffffffffffffffff61158c92885193849283927fc657c71800000000000000000000000000000000000000000000000000000000845216958660048401528a60248401526044830190611b2b565b038183737109709ecfa91a80626ff3989d68f67f5b1dd12d5af180156117445790879161172f575b5050823b1561172b576044869283875195869485937fb4d884f6000000000000000000000000000000000000000000000000000000008552600485015260248401525af1801561171e57908491611709575b505073ffffffffffffffffffffffffffffffffffffffff601f5460081c1690813b1561170457839160248392855194859384927f84f1509000000000000000000000000000000000000000000000000000000000845260048401525af180156116f8579083916116e3575b5050737109709ecfa91a80626ff3989d68f67f5b1dd12d3b156116e0578051907f90c5013b000000000000000000000000000000000000000000000000000000008252828260048183737109709ecfa91a80626ff3989d68f67f5b1dd12d5af190811561037f575061036e5750f35b50fd5b816116ed91611a0b565b6116e057815f611671565b505051903d90823e3d90fd5b505050fd5b8161171391611a0b565b61038857825f611606565b50505051903d90823e3d90fd5b8580fd5b8161173991611a0b565b61172b57855f6115b4565b86513d89823e3d90fd5b8680fd5b90506020813d602011611784575b8161176d60209383611a0b565b8101031261174e5761177e906130cc565b5f611514565b3d9150611760565b80602080928a01015182828501015201611496565b816117ab91611a0b565b610bb857825f61143d565b6117c39193505f90611a0b565b5f915f6113d5565b83513d5f823e3d90fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b34610b1b575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610b1b576040515f60305461184081611954565b80845290600181169081156118da575060011461187c575b6104158361186881850382611a0b565b604051918291602083526020830190611b2b565b60305f9081527f6ff97a59c90d62cc7236ba3a37cd85351bf564556780cf8c1157a220f31f0cbb939250905b8082106118c057509091508101602001611868611858565b9192600181602092548385880101520191019092916118a8565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660208086019190915291151560051b840190910191506118689050611858565b34610b1b575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610b1b57602090602d548152f35b90600182811c9216801561199b575b602083101461196e57565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b91607f1691611963565b6040810190811067ffffffffffffffff8211176119c157604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b610100810190811067ffffffffffffffff8211176119c157604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176119c157604052565b9060405191825f825492611a5f84611954565b8084529360018116908115611aca5750600114611a86575b50611a8492500383611a0b565b565b90505f9291925260205f20905f915b818310611aae575050906020611a84928201015f611a77565b6020919350806001915483858901015201910190918492611a95565b60209350611a849592507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091501682840152151560051b8201015f611a77565b5f5b838110611b1b5750505f910152565b8181015183820152602001611b0c565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602093611b6781518092818752878088019101611b0a565b0116010190565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6040910112610b1b576004359060243590565b60206040818301928281528451809452019201905f5b818110611bc55750505090565b825173ffffffffffffffffffffffffffffffffffffffff16845260209384019390920191600101611bb8565b9080602083519182815201916020808360051b8301019401925f915b838310611c1c57505050505090565b9091929394602080611c58837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe086600196030187528951611b2b565b97019301930191939290611c0d565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6060910112610b1b57600435906024358015158103610b1b57906044358015158103610b1b5790565b90602080835192838152019201905f5b818110611cce5750505090565b82517fffffffff0000000000000000000000000000000000000000000000000000000016845260209384019390920191600101611cc1565b602081016020825282518091526040820191602060408360051b8301019401925f915b838310611d3857505050505090565b9091929394602080611d9b837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc086600196030187526040838b5173ffffffffffffffffffffffffffffffffffffffff815116845201519181858201520190611cb1565b97019301930191939290611d29565b919082039182116117d557565b67ffffffffffffffff81116119c15760051b60200190565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146117d55760010190565b90919082806120fd575b5f93156120ec57611e15613090565b50611e1f8261387b565b9281156120d7575b5091905b82156120d05783156120a1575060208101519060068210156120745773ffffffffffffffffffffffffffffffffffffffff9161206a5760800151165b925b815f52602b60205260ff60405f20541693737109709ecfa91a80626ff3989d68f67f5b1dd12d3b15610b1b5773ffffffffffffffffffffffffffffffffffffffff604051917fca669fa70000000000000000000000000000000000000000000000000000000083521660048201525f8160248183737109709ecfa91a80626ff3989d68f67f5b1dd12d5af1801561205f5761204c575b5073ffffffffffffffffffffffffffffffffffffffff601f5460081c16803b15610bbc57818080926084604051809581937f41dd26f5000000000000000000000000000000000000000000000000000000008352896004840152816024840152606060448401528160648401525af19182612037575b5050611f82575b50505050565b611f9192611fca575b50613550565b60018114908115611fbf575b50611fac575b5f808080611f7c565b611fb7602e54611dcf565b602e55611fa3565b60029150145f611f9d565b50612031604051611fdc606082611a0b565b602181527f72656a6563742073756363656564656420776974682077726f6e67206163746f60208201527f7200000000000000000000000000000000000000000000000000000000000000604082015261333e565b5f611f8b565b8161204191611a0b565b610bbc57815f611f75565b61205891505f90611a0b565b5f80611eff565b6040513d5f823e3d90fd5b6040015116611e67565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b73ffffffffffffffffffffffffffffffffffffffff9190156120c95760800151165b92611e69565b51166120c3565b5050505050565b90506120e49192506139fc565b91905f611e27565b906120f690613225565b9091611e2b565b82159350611e06565b61210e613090565b506121188161387b565b509081156121ed575b5080156121ea57805f52602b60205260ff60405f2054169073ffffffffffffffffffffffffffffffffffffffff601f5460081c16803b15610b1b575f80916024604051809481937f5b7baf640000000000000000000000000000000000000000000000000000000083528760048401525af190816121da575b506121a3575050565b6121ac90613550565b600181149081156121cf575b506121bf57565b6121ca602e54611dcf565b602e55565b60029150145f6121b8565b5f6121e491611a0b565b5f61219a565b50565b6121f791506139fc565b505f612121565b90604051918281549182825260208201905f5260205f20925f905b80600783011061241557611a849454918181106123df575b8181106123a9575b818110612373575b81811061233d575b818110612307575b8181106122d1575b81811061229c575b1061226f575b500383611a0b565b7fffffffff000000000000000000000000000000000000000000000000000000001681526020015f612267565b9260206001917fffffffff0000000000000000000000000000000000000000000000000000000085831b168152019301612261565b9260206001917fffffffff000000000000000000000000000000000000000000000000000000008560401b168152019301612259565b9260206001917fffffffff000000000000000000000000000000000000000000000000000000008560601b168152019301612251565b9260206001917fffffffff000000000000000000000000000000000000000000000000000000008560801b168152019301612249565b9260206001917fffffffff000000000000000000000000000000000000000000000000000000008560a01b168152019301612241565b9260206001917fffffffff000000000000000000000000000000000000000000000000000000008560c01b168152019301612239565b9260206001917fffffffff000000000000000000000000000000000000000000000000000000008560e01b168152019301612231565b9160089193506101006001917fffffffff000000000000000000000000000000000000000000000000000000008754818160e01b168352818160c01b166020840152818160a01b166040840152818160801b166060840152818160601b166080840152818160401b1660a0840152818160201b1660c08401521660e0820152019401920185929391612219565b81156124ac570690565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b6124e290613225565b90915f918315611f7c575173ffffffffffffffffffffffffffffffffffffffff16737109709ecfa91a80626ff3989d68f67f5b1dd12d3b15610b1b57604051907fca669fa700000000000000000000000000000000000000000000000000000000825260048201525f8160248183737109709ecfa91a80626ff3989d68f67f5b1dd12d5af1801561205f57612663575b50600373ffffffffffffffffffffffffffffffffffffffff601f5460081c1691066003811015612636576026015473ffffffffffffffffffffffffffffffffffffffff16813b15610bb85782916084839260405195869384927fc9a84bb90000000000000000000000000000000000000000000000000000000084528960048501526024840152606060448401528160648401525af19182612621575b50506126185750565b611a8490613550565b61262c828092611a0b565b61016c578061260f565b6024837f4e487b710000000000000000000000000000000000000000000000000000000081526032600452fd5b6126709192505f90611a0b565b5f905f612572565b5f91156128b15761268890613225565b9190915b8215611f7c57838015612899575b1561287c5773ffffffffffffffffffffffffffffffffffffffff6040820151165b737109709ecfa91a80626ff3989d68f67f5b1dd12d3b15610b1b5773ffffffffffffffffffffffffffffffffffffffff604051917fca669fa70000000000000000000000000000000000000000000000000000000083521660048201525f8160248183737109709ecfa91a80626ff3989d68f67f5b1dd12d5af1801561205f57612867575b5060c073ffffffffffffffffffffffffffffffffffffffff601f5460081c16910151813b15610bb8576040517fd2e13f50000000000000000000000000000000000000000000000000000000008152600481018590526024810191909152606060448201525f606482015290829081908390608490829084905af19182612852575b50506127cd57505050565b6127db926127eb5750613550565b6127e6602c54611dcf565b602c55565b506120316040516127fd606082611a0b565b602681527f66756e642073756363656564656420776974682077726f6e672073746174757360208201527f2f6163746f720000000000000000000000000000000000000000000000000000604082015261333e565b8161285c91611a0b565b610bbc57815f6127c2565b6128749192505f90611a0b565b5f905f612740565b73ffffffffffffffffffffffffffffffffffffffff8151166126bb565b9350602081015160068110156120745715159361269a565b6128ba906136e4565b91909161268c565b919082018092116117d557565b6128d890613225565b5f929192918315611f7c57633b9aca005f6128f292613b7d565b73ffffffffffffffffffffffffffffffffffffffff604080935f8083516129198582611a0b565b600c81527f426f756e6420726573756c740000000000000000000000000000000000000000602082015284516129848161126960208201947fb60e72cc0000000000000000000000000000000000000000000000000000000086528960248401526064830190611b2b565b51906a636f6e736f6c652e6c6f675afa50015116737109709ecfa91a80626ff3989d68f67f5b1dd12d3b15610b1b578251907fca669fa700000000000000000000000000000000000000000000000000000000825260048201525f8160248183737109709ecfa91a80626ff3989d68f67f5b1dd12d5af180156117cb57612a89575b5073ffffffffffffffffffffffffffffffffffffffff601f5460081c1691823b15610b4a57517fdd4ae9d4000000000000000000000000000000000000000000000000000000008152600481018590526024810191909152606060448201525f6064820152919081908390608490829084905af191826126215750506126185750565b612a969193505f90611a0b565b5f915f612a06565b60085460ff168015612aad5790565b506040517f667f9d70000000000000000000000000000000000000000000000000000000008152737109709ecfa91a80626ff3989d68f67f5b1dd12d60048201527f6661696c656400000000000000000000000000000000000000000000000000006024820152602081604481737109709ecfa91a80626ff3989d68f67f5b1dd12d5afa90811561205f575f91612b45575b50151590565b90506020813d602011612b6f575b81612b6060209383611a0b565b81010312610b1b57515f612b3f565b3d9150612b53565b5f9115612d8357612b8790613225565b9190915b8215611f7c57838015612d65575b73ffffffffffffffffffffffffffffffffffffffff919015612d5b5751165b737109709ecfa91a80626ff3989d68f67f5b1dd12d3b15610b1b5773ffffffffffffffffffffffffffffffffffffffff604051917fca669fa70000000000000000000000000000000000000000000000000000000083521660048201525f8160248183737109709ecfa91a80626ff3989d68f67f5b1dd12d5af1801561205f57612d48575b5073ffffffffffffffffffffffffffffffffffffffff601f5460081c16803b15610bbc57818080926084604051809581937f9e63798d000000000000000000000000000000000000000000000000000000008352896004840152816024840152606060448401528160648401525af19182612d33575b5050612cbe57505050565b611a8492612ccc5750613550565b50612031604051612cde606082611a0b565b602881527f7375626d69742073756363656564656420776974682077726f6e67207374617460208201527f75732f6163746f72000000000000000000000000000000000000000000000000604082015261333e565b81612d3d91611a0b565b610bbc57815f612cb3565b612d5491505f90611a0b565b5f80612c3d565b6040015116612bb8565b93506020810151906006821015612074576001919091141593612b99565b612d8c9061387b565b919091612b8b565b5f9115612fb057612da490613225565b9190915b8215611f7c57838015612f92575b73ffffffffffffffffffffffffffffffffffffffff919015612f885751165b737109709ecfa91a80626ff3989d68f67f5b1dd12d3b15610b1b5773ffffffffffffffffffffffffffffffffffffffff604051917fca669fa70000000000000000000000000000000000000000000000000000000083521660048201525f8160248183737109709ecfa91a80626ff3989d68f67f5b1dd12d5af1801561205f57612f75575b5073ffffffffffffffffffffffffffffffffffffffff601f5460081c16803b15610bbc57818080926084604051809581937fd75bbdf3000000000000000000000000000000000000000000000000000000008352896004840152816024840152606060448401528160648401525af19182612f60575b5050612edb57505050565b612ee992612ef95750613550565b612ef4602d54611dcf565b602d55565b50612031604051612f0b606082611a0b565b602a81527f636f6d706c6574652073756363656564656420776974682077726f6e6720737460208201527f617475732f6163746f7200000000000000000000000000000000000000000000604082015261333e565b81612f6a91611a0b565b610bbc57815f612ed0565b612f8191505f90611a0b565b5f80612e5a565b6080015116612dd5565b93506020810151906006821015612074576002919091141593612db6565b612fb9906139fc565b919091612da8565b906001612fcd92613b7d565b905f80604051612fde604082611a0b565b600c81527f426f756e6420726573756c740000000000000000000000000000000000000000602082015260405161307d8161304b60208201947fb60e72cc000000000000000000000000000000000000000000000000000000008652604060248401526064830190611b2b565b886044830152037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282611a0b565b51906a636f6e736f6c652e6c6f675afa50565b6040519061309d826119ee565b606060e0835f81525f60208201525f60408201525f838201525f60808201525f60a08201525f60c08201520152565b519073ffffffffffffffffffffffffffffffffffffffff82168203610b1b57565b602081830312610b1b5780519067ffffffffffffffff8211610b1b57019061010082820312610b1b5760405191613123836119ee565b61312c816130cc565b835260208101516006811015610b1b57602084015261314d604082016130cc565b6040840152606081015165ffffffffffff81168103610b1b576060840152613177608082016130cc565b608084015261318860a082016130cc565b60a084015260c081015160c084015260e08101519067ffffffffffffffff8211610b1b570181601f82011215610b1b57805167ffffffffffffffff81116119c157604051926131ff601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200185611a0b565b81845260208284010111610b1b5761321d9160208085019101611b0a565b60e082015290565b9061322e613090565b73ffffffffffffffffffffffffffffffffffffffff601f5460081c1692604051917f50355d76000000000000000000000000000000000000000000000000000000008352602083600481885afa92831561205f575f9361330a575b508215613301575061329e6024925f92612fc1565b93604051928380927fbf22c4570000000000000000000000000000000000000000000000000000000082528760048301525afa90811561205f575f916132e2575090565b6132fe91503d805f833e6132f68183611a0b565b8101906130ed565b90565b935050505f9190565b9092506020813d602011613336575b8161332660209383611a0b565b81010312610b1b5751915f613289565b3d9150613319565b90602f5460ff81161561335057509050565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117602f55815167ffffffffffffffff81116119c157613394603054611954565b601f81116134af575b50602092601f82116001146133f657928192935f926133eb575b50507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c191617603055565b015190505f806133b7565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082169360305f527f6ff97a59c90d62cc7236ba3a37cd85351bf564556780cf8c1157a220f31f0cbb915f5b8681106134975750836001959610613460575b505050811b01603055565b01517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c191690555f8080613455565b91926020600181928685015181550194019201613442565b60305f52601f820160051c7f6ff97a59c90d62cc7236ba3a37cd85351bf564556780cf8c1157a220f31f0cbb019060208310613528575b601f0160051c7f6ff97a59c90d62cc7236ba3a37cd85351bf564556780cf8c1157a220f31f0cbb01905b81811061351d575061339d565b5f8155600101613510565b7f6ff97a59c90d62cc7236ba3a37cd85351bf564556780cf8c1157a220f31f0cbb91506134e6565b805f52602b60205260ff60405f2054169060245f73ffffffffffffffffffffffffffffffffffffffff601f5460081c16604051928380927fbf22c4570000000000000000000000000000000000000000000000000000000082528660048301525afa801561205f576020915f916136ca575b5001519160068310156120745782600382106136785750506136406040516135eb606082611a0b565b602281527f616374696f6e20737563636565646564206f6e2061207465726d696e616c206a60208201527f6f62000000000000000000000000000000000000000000000000000000000000604082015261333e565b5f52602b60205260ff60405f2091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055565b61368191613d55565b613640576136c5604051613696604082611a0b565b601981527f696c6c6567616c20737461747573207472616e736974696f6e00000000000000602082015261333e565b613640565b6136de91503d805f833e6132f68183611a0b565b5f6135c2565b906136ed613090565b9173ffffffffffffffffffffffffffffffffffffffff601f5460081c1690604051907f50355d76000000000000000000000000000000000000000000000000000000008252602082600481865afa91821561205f575f92613847575b50811561383f578161375a91612fc1565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101908111915f5b8181106137945750505050505f9190565b836117d5576137ac826137a783866128c2565b6124a2565b600181018091116117d557604051907fbf22c4570000000000000000000000000000000000000000000000000000000082528060048301525f826024818a5afa91821561205f575f92613823575b50602082015160068110156120745715613818575050600101613783565b975095945050505050565b6138389192503d805f833e6132f68183611a0b565b905f6137fa565b5050505f9190565b9091506020813d602011613873575b8161386360209383611a0b565b81010312610b1b5751905f613749565b3d9150613856565b90613884613090565b9173ffffffffffffffffffffffffffffffffffffffff601f5460081c1690604051907f50355d76000000000000000000000000000000000000000000000000000000008252602082600481865afa91821561205f575f926139c8575b50811561383f57816138f191612fc1565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101908111915f5b81811061392b5750505050505f9190565b836117d55761393e826137a783866128c2565b600181018091116117d557604051907fbf22c4570000000000000000000000000000000000000000000000000000000082528060048301525f826024818a5afa91821561205f575f926139ac575b50602082015160068110156120745760011461381857505060010161391a565b6139c19192503d805f833e6132f68183611a0b565b905f61398c565b9091506020813d6020116139f4575b816139e460209383611a0b565b81010312610b1b5751905f6138e0565b3d91506139d7565b90613a05613090565b9173ffffffffffffffffffffffffffffffffffffffff601f5460081c1690604051907f50355d76000000000000000000000000000000000000000000000000000000008252602082600481865afa91821561205f575f92613b49575b50811561383f5781613a7291612fc1565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101908111915f5b818110613aac5750505050505f9190565b836117d557613abf826137a783866128c2565b600181018091116117d557604051907fbf22c4570000000000000000000000000000000000000000000000000000000082528060048301525f826024818a5afa91821561205f575f92613b2d575b506020820151600681101561207457600214613818575050600101613a9b565b613b429192503d805f833e6132f68183611a0b565b905f613b0d565b9091506020813d602011613b75575b81613b6560209383611a0b565b81010312610b1b5751905f613a61565b3d9150613b58565b5f90838311613cd15782811091821580613cc7575b613cbf57613ba08486611daa565b92600184018094116117d557600383111580613cb6575b613ca7577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc83101580613c9d575b613c8c5785831115613c44575050906137a784613c0193611daa565b908115613c3f57613c1292506128c2565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81019081116117d55790565b505090565b959492919095613c545750505050565b839495506137a790613c669394611daa565b908115613c3f57613c779250611daa565b600181018091116117d557905f808080611f7c565b505090506132fe9291501990611daa565b5082198411613be5565b50509190506132fe92506128c2565b50828411613bb7565b509250505090565b5084821115613b92565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603e60248201527f5374645574696c7320626f756e642875696e743235362c75696e743235362c7560448201527f696e74323536293a204d6178206973206c657373207468616e206d696e2e00006064820152fd5b60ff168015613db75760018114613d9e57600214613d7257505f90565b60ff1660038114908115613d93575b8115613d8b575090565b600591501490565b600481149150613d81565b5060ff1660028114908115613d93578115613d8b575090565b5060ff168015908115613dd5575b8115613d93578115613d8b575090565b600181149150613dc556fea264697066735822122087a51d10e0458fb317219be7eb23f08edb70a540fa5ddaaf1fe23542f4215bae64736f6c634300081a00330000000000000000000000007109709ecfa91a80626ff3989d68f67f5b1dd12d60806040523461031057610e1e8038038061001981610314565b9283398101906040818303126103105780516001600160401b0381116103105782610045918301610339565b60208201519092906001600160401b038111610310576100659201610339565b81516001600160401b03811161022357600354600181811c91168015610306575b602082101461020557601f81116102a3575b50602092601f821160011461024257928192935f92610237575b50508160011b915f199060031b1c1916176003555b80516001600160401b03811161022357600454600181811c91168015610219575b602082101461020557601f81116101a2575b50602091601f8211600114610142579181925f92610137575b50508160011b915f199060031b1c1916176004555b604051610a7b90816103a38239f35b015190505f80610113565b601f1982169260045f52805f20915f5b85811061018a57508360019510610172575b505050811b01600455610128565b01515f1960f88460031b161c191690555f8080610164565b91926020600181928685015181550194019201610152565b60045f527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b601f830160051c810191602084106101fb575b601f0160051c01905b8181106101f057506100fa565b5f81556001016101e3565b90915081906101da565b634e487b7160e01b5f52602260045260245ffd5b90607f16906100e8565b634e487b7160e01b5f52604160045260245ffd5b015190505f806100b2565b601f1982169360035f52805f20915f5b86811061028b5750836001959610610273575b505050811b016003556100c7565b01515f1960f88460031b161c191690555f8080610265565b91926020600181928685015181550194019201610252565b60035f527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b601f830160051c810191602084106102fc575b601f0160051c01905b8181106102f15750610098565b5f81556001016102e4565b90915081906102db565b90607f1690610086565b5f80fd5b6040519190601f01601f191682016001600160401b0381118382101761022357604052565b81601f82011215610310578051906001600160401b03821161022357610368601f8301601f1916602001610314565b9282845260208383010111610310575f5b82811061038d57505060205f918301015290565b8060208092840101518282870101520161037956fe6080806040526004361015610012575f80fd5b5f3560e01c90816306fdde031461077257508063095ea7b3146106c557806318160ddd1461068a57806323b872dd146104f6578063313ce567146104bd57806340c10f19146103be57806370a082311461035c57806395d89b4114610169578063a9059cbb1461011a5763dd62ed3e1461008a575f80fd5b346101165760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610116576100c1610909565b73ffffffffffffffffffffffffffffffffffffffff6100de61092c565b91165f52600160205273ffffffffffffffffffffffffffffffffffffffff60405f2091165f52602052602060405f2054604051908152f35b5f80fd5b346101165760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101165761015e610154610909565b602435903361094f565b602060405160018152f35b34610116575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610116576040515f600454908160011c60018316928315610352575b6020821084146103255781855284939081156102c5575060011461024b575b5003601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01681019067ffffffffffffffff82118183101761021e5761021a829182604052826108a3565b0390f35b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b60045f90815291507f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b5b8183106102a957505081016020017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06101ce565b6020919350806001915483858801015201910190918392610275565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660208581019190915291151560051b840190910191507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090506101ce565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b90607f16906101af565b346101165760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101165773ffffffffffffffffffffffffffffffffffffffff6103a8610909565b165f525f602052602060405f2054604051908152f35b346101165760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610116576103f5610909565b73ffffffffffffffffffffffffffffffffffffffff16602435811561049157600254908082018092116104645760207fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef915f9360025584845283825260408420818154019055604051908152a3005b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b7fec442f05000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b34610116575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261011657602060405160068152f35b346101165760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101165761052d610909565b61053561092c565b6044359073ffffffffffffffffffffffffffffffffffffffff831692835f52600160205260405f2073ffffffffffffffffffffffffffffffffffffffff33165f5260205260405f20547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81106105b1575b5061015e935061094f565b83811061065657841561062a5733156105fe5761015e945f52600160205260405f2073ffffffffffffffffffffffffffffffffffffffff33165f526020528360405f2091039055846105a6565b7f94280d62000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b7fe602df05000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b83907ffb8f41b2000000000000000000000000000000000000000000000000000000005f523360045260245260445260645ffd5b34610116575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610116576020600254604051908152f35b346101165760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610116576106fc610909565b60243590331561062a5773ffffffffffffffffffffffffffffffffffffffff169081156105fe57335f52600160205260405f20825f526020528060405f20556040519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a3602060405160018152f35b34610116575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610116575f600354908160011c60018316928315610899575b6020821084146103255781855284939081156102c5575060011461081f575003601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01681019067ffffffffffffffff82118183101761021e5761021a829182604052826108a3565b60035f90815291507fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b5b81831061087d57505081016020017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06101ce565b6020919350806001915483858801015201910190918392610849565b90607f16906107b5565b919091602081528251928360208301525f5b8481106108f35750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f845f6040809697860101520116010190565b80602080928401015160408286010152016108b5565b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361011657565b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361011657565b73ffffffffffffffffffffffffffffffffffffffff16908115610a195773ffffffffffffffffffffffffffffffffffffffff1691821561049157815f525f60205260405f20548181106109e757817fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92602092855f525f84520360405f2055845f525f825260405f20818154019055604051908152a3565b827fe450d38c000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b7f96c6fd1e000000000000000000000000000000000000000000000000000000005f525f60045260245ffdfea26469706673582212207d4081a323998c8d20751316ef809be0cc398b922c8a680eea7ed1d1bc08e9bf64736f6c634300081a003360808060405234601557610fd0908161001a8239f35b5f80fdfe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a714610b915750806306661abd14610b575780633a32058114610a1d578063a3fe4783146105eb578063d183ce14146105295763dc08fb1d1461005e575f80fd5b346103cb5761006c36610cb1565b9092916040517fbf22c4570000000000000000000000000000000000000000000000000000000081528360048201525f81602481335afa801561051e575f906103fc575b6020915001519260068410156103cf57604051926100cd84610e07565b60018452602084019182527fffffffff00000000000000000000000000000000000000000000000000000000604085019316835261010a81610f60565b956101186040519788610e40565b81875236828201116103cb57815f92602092838a0137870101526060830194855260ff60808401941684525f54680100000000000000008110156103725780600161016592015f55610d51565b93909361039f5751151560ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00855416911617835551600183015560028201905160e01c7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000082541617905560038101925192835167ffffffffffffffff8111610372576101f28254610db6565b601f811161032d575b506020601f8211600114610287579080600494939260ff96975f9261027c575b50507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c19161790555b019151167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008254161790555f80f35b015190505f8061021b565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0821695835f52815f20965f5b8181106103155750966001928492600497969560ff999a106102de575b505050811b01905561024d565b01517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c191690555f80806102d1565b838301518955600190980197602093840193016102b4565b825f5260205f20601f830160051c81019160208410610368575b601f0160051c01905b81811061035d57506101fb565b5f8155600101610350565b9091508190610347565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b503d805f833e61040c8183610e40565b8101906020818303126103cb5780519067ffffffffffffffff82116103cb5701610100818303126103cb576040519061044482610e23565b61044d81610f3f565b8252602081015160068110156103cb57602083015261046e60408201610f3f565b6040830152606081015165ffffffffffff811681036103cb57606083015261049860808201610f3f565b60808301526104a960a08201610f3f565b60a083015260c081015160c083015260e08101519067ffffffffffffffff82116103cb57019180601f840112156103cb578251926104e684610f60565b916104f46040519384610e40565b848352602085830101116103cb5760209361051491858085019101610c4d565b60e08201526100b0565b6040513d5f823e3d90fd5b346103cb5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103cb576004355f548110156103cb5761056d90610d51565b5060ff8154166001820154916105e1600282015460e01b917fffffffff0000000000000000000000000000000000000000000000000000000060ff60046105b660038501610e81565b930154169360405196879615158752602087015216604085015260a0606085015260a0840190610c6e565b9060808301520390f35b346103cb576105f936610cb1565b9092916040517fbf22c4570000000000000000000000000000000000000000000000000000000081528360048201525f81602481335afa801561051e575f906108fb575b6020915001519260068410156103cf576040519261065a84610e07565b5f8452602084019182527fffffffff00000000000000000000000000000000000000000000000000000000604085019316835261069681610f60565b956106a46040519788610e40565b81875236828201116103cb57815f92602092838a0137870101526060830194855260ff60808401941684525f5468010000000000000000811015610372578060016106f192015f55610d51565b93909361039f5751151560ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00855416911617835551600183015560028201905160e01c7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000082541617905560038101925192835167ffffffffffffffff81116103725761077e8254610db6565b601f81116108b6575b506020601f8211600114610811579080600494939260ff96975f926108065750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c1916179055019151167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008254161790555f80f35b01519050878061021b565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0821695835f52815f20965f5b81811061089e5750966001928492600497969560ff999a1061086757505050811b01905561024d565b01517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c191690558780806102d1565b8383015189556001909801976020938401930161083e565b825f5260205f20601f830160051c810191602084106108f1575b601f0160051c01905b8181106108e65750610787565b5f81556001016108d9565b90915081906108d0565b503d805f833e61090b8183610e40565b8101906020818303126103cb5780519067ffffffffffffffff82116103cb5701610100818303126103cb576040519061094382610e23565b61094c81610f3f565b8252602081015160068110156103cb57602083015261096d60408201610f3f565b6040830152606081015165ffffffffffff811681036103cb57606083015261099760808201610f3f565b60808301526109a860a08201610f3f565b60a083015260c081015160c083015260e08101519067ffffffffffffffff82116103cb57019180601f840112156103cb578251926109e584610f60565b916109f36040519384610e40565b848352602085830101116103cb57602093610a1391858085019101610c4d565b60e082015261063d565b346103cb5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103cb575f6080604051610a5b81610e07565b8281528260208201528260408201526060808201520152610a7d600435610d51565b50604051610a8a81610e07565b60ff825416151581526001820154916020820192835260ff610b4b600283015460e01b927fffffffff0000000000000000000000000000000000000000000000000000000060408601941684527fffffffff00000000000000000000000000000000000000000000000000000000836004610b0760038501610e81565b93606089019485520154169460808701958652604051978897602089525115156020890152516040880152511660608601525160a0608086015260c0850190610c6e565b91511660a08301520390f35b346103cb575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103cb5760205f54604051908152f35b346103cb5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103cb57600435907fffffffff0000000000000000000000000000000000000000000000000000000082168092036103cb57817f7ff6bc9e0000000000000000000000000000000000000000000000000000000060209314908115610c23575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483610c1c565b5f5b838110610c5e5750505f910152565b8181015183820152602001610c4f565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602093610caa81518092818752878088019101610c4d565b0116010190565b9060607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8301126103cb57600435916024357fffffffff00000000000000000000000000000000000000000000000000000000811681036103cb579160443567ffffffffffffffff81116103cb57826023820112156103cb5780600401359267ffffffffffffffff84116103cb57602484830101116103cb576024019190565b5f54811015610d89575f8080526005919091027f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5630191565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b90600182811c92168015610dfd575b6020831014610dd057565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b91607f1691610dc5565b60a0810190811067ffffffffffffffff82111761037257604052565b610100810190811067ffffffffffffffff82111761037257604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761037257604052565b9060405191825f825492610e9484610db6565b8084529360018116908115610eff5750600114610ebb575b50610eb992500383610e40565b565b90505f9291925260205f20905f915b818310610ee3575050906020610eb9928201015f610eac565b6020919350806001915483858901015201910190918492610eca565b60209350610eb99592507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091501682840152151560051b8201015f610eac565b519073ffffffffffffffffffffffffffffffffffffffff821682036103cb57565b67ffffffffffffffff811161037257601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0166020019056fea2646970667358221220af75d4a17c0b6da6a3609fe1e4338988c321fe2d51d15dda0930b8f2e25388aa64736f6c634300081a0033a2646970667358221220f16bdcf0e1bc42cc06e2748da5fb883ec4927ec1a6fcacf0ab8a4e3b5625b20f64736f6c634300081a0033","gas_used":11529646,"gas_limit":1072816766,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[{"Call":0},{"Call":1},{"Call":2},{"Call":3},{"Call":4},{"Call":5},{"Call":6},{"Call":7},{"Call":8},{"Call":9},{"Call":10},{"Call":11},{"Call":12},{"Call":13}]},{"parent":0,"children":[],"idx":1,"trace":{"depth":1,"success":true,"caller":"0x7fa9385be102ac3eac297483dd6233d62b3e1496","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"STATICCALL","value":"0x0","data":"0xffa186494faf2c8c453a4f5f1ae5b7803c26fd198403e6bb0a7505c9a6ba577b0b499018","output":"0x000000000000000000000000d49279c8fc3454d7328eb8777274812e84b658df","gas_used":0,"gas_limit":1056007269,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":0,"children":[],"idx":2,"trace":{"depth":1,"success":true,"caller":"0x7fa9385be102ac3eac297483dd6233d62b3e1496","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0xc657c718000000000000000000000000d49279c8fc3454d7328eb8777274812e84b658df000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000156b65726e656c50726f787941646d696e4f776e65720000000000000000000000","output":"0x","gas_used":0,"gas_limit":1056006414,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":0,"children":[],"idx":3,"trace":{"depth":1,"success":true,"caller":"0x7fa9385be102ac3eac297483dd6233d62b3e1496","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"STATICCALL","value":"0x0","data":"0xffa18649f23ec0bb4210edd5cba85afd05127efcd2fc6a781bfed49188da1081670b22d8","output":"0x000000000000000000000000aa10a84ce7d9ae517a52c6d5ca153b369af99ecf","gas_used":0,"gas_limit":1055983779,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":0,"children":[],"idx":4,"trace":{"depth":1,"success":true,"caller":"0x7fa9385be102ac3eac297483dd6233d62b3e1496","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0xc657c718000000000000000000000000aa10a84ce7d9ae517a52c6d5ca153b369af99ecf0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000561646d696e000000000000000000000000000000000000000000000000000000","output":"0x","gas_used":0,"gas_limit":1055982922,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":0,"children":[],"idx":5,"trace":{"depth":1,"success":true,"caller":"0x7fa9385be102ac3eac297483dd6233d62b3e1496","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"STATICCALL","value":"0x0","data":"0xffa18649cbd818ad4dd6f1ff9338c2bb62480241424dd9a65f9f3284101a01cd099ad8ac","output":"0x000000000000000000000000f43bca55e8091977223fa5b776e23528d205dca8","gas_used":0,"gas_limit":1055960281,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":0,"children":[],"idx":6,"trace":{"depth":1,"success":true,"caller":"0x7fa9385be102ac3eac297483dd6233d62b3e1496","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0xc657c718000000000000000000000000f43bca55e8091977223fa5b776e23528d205dca8000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000087472656173757279000000000000000000000000000000000000000000000000","output":"0x","gas_used":0,"gas_limit":1055959423,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":0,"children":[],"idx":7,"trace":{"depth":1,"success":true,"caller":"0x7fa9385be102ac3eac297483dd6233d62b3e1496","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"STATICCALL","value":"0x0","data":"0xffa18649971ee2c8925badb60ae2abac1a4faf0aa9b739dd57ac1b3b7a1e150be855cde3","output":"0x000000000000000000000000d5e069bc58dedb2a3a348995ee753eef0274004f","gas_used":0,"gas_limit":1055936782,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":0,"children":[],"idx":8,"trace":{"depth":1,"success":true,"caller":"0x7fa9385be102ac3eac297483dd6233d62b3e1496","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0xc657c718000000000000000000000000d5e069bc58dedb2a3a348995ee753eef0274004f00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000006636c69656e740000000000000000000000000000000000000000000000000000","output":"0x","gas_used":0,"gas_limit":1055935925,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":0,"children":[],"idx":9,"trace":{"depth":1,"success":true,"caller":"0x7fa9385be102ac3eac297483dd6233d62b3e1496","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"STATICCALL","value":"0x0","data":"0xffa1864991c78f343fa4753a18a7ecaff5a0d85cfa864839d839601256f8f00300358578","output":"0x0000000000000000000000009b78803558f9ea56f4f0a966322c8dd9b2fbebc0","gas_used":0,"gas_limit":1055913284,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":0,"children":[],"idx":10,"trace":{"depth":1,"success":true,"caller":"0x7fa9385be102ac3eac297483dd6233d62b3e1496","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0xc657c7180000000000000000000000009b78803558f9ea56f4f0a966322c8dd9b2fbebc00000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000870726f7669646572000000000000000000000000000000000000000000000000","output":"0x","gas_used":0,"gas_limit":1055912426,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":0,"children":[],"idx":11,"trace":{"depth":1,"success":true,"caller":"0x7fa9385be102ac3eac297483dd6233d62b3e1496","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"STATICCALL","value":"0x0","data":"0xffa186495f59b69ac1b426b06924d9159f4ac3f122f00f5da4f2b64b38efe5044cf34820","output":"0x000000000000000000000000ca5453e74f0ccc802add48a547cd965512ffd45d","gas_used":0,"gas_limit":1055889785,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":0,"children":[],"idx":12,"trace":{"depth":1,"success":true,"caller":"0x7fa9385be102ac3eac297483dd6233d62b3e1496","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0xc657c718000000000000000000000000ca5453e74f0ccc802add48a547cd965512ffd45d000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000096576616c7561746f720000000000000000000000000000000000000000000000","output":"0x","gas_used":0,"gas_limit":1055888928,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":0,"children":[],"idx":13,"trace":{"depth":1,"success":true,"caller":"0x7fa9385be102ac3eac297483dd6233d62b3e1496","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"STATICCALL","value":"0x0","data":"0xffa18649f62b197572cd131d4624c9caeaa7711aecad967ea466e508eb9cbb0683247a0c","output":"0x00000000000000000000000049052147f5d97a723debdf07680fffadad29a5dc","gas_used":0,"gas_limit":1055866286,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":0,"children":[],"idx":14,"trace":{"depth":1,"success":true,"caller":"0x7fa9385be102ac3eac297483dd6233d62b3e1496","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0xc657c71800000000000000000000000049052147f5d97a723debdf07680fffadad29a5dc00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000008737472616e676572000000000000000000000000000000000000000000000000","output":"0x","gas_used":0,"gas_limit":1055865429,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]}]}],["Setup",{"arena":[{"parent":null,"children":[1,2,3,4,7,8,9,10,11,12,14],"idx":0,"trace":{"depth":0,"success":true,"caller":"0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38","address":"0x7fa9385be102ac3eac297483dd6233d62b3e1496","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0x0a9254e4","output":"0x","gas_used":9629462,"gas_limit":1073720760,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[{"Call":0},{"Call":1},{"Call":2},{"Call":3},{"Call":4},{"Call":5},{"Call":6},{"Call":7},{"Call":8},{"Call":9},{"Call":10}]},{"parent":0,"children":[],"idx":1,"trace":{"depth":1,"success":true,"caller":"0x7fa9385be102ac3eac297483dd6233d62b3e1496","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0xe5d6bf02000000000000000000000000000000000000000000000000000000006553f100","output":"0x","gas_used":0,"gas_limit":1056941014,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":0,"children":[],"idx":2,"trace":{"depth":1,"success":true,"caller":"0x7fa9385be102ac3eac297483dd6233d62b3e1496","address":"0x5615deb798bb3e4dfa0139dfa1b3d433cc23b72f","maybe_precompile":false,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CREATE","value":"0x0","data":"0x60806040523461031057610e1e8038038061001981610314565b9283398101906040818303126103105780516001600160401b0381116103105782610045918301610339565b60208201519092906001600160401b038111610310576100659201610339565b81516001600160401b03811161022357600354600181811c91168015610306575b602082101461020557601f81116102a3575b50602092601f821160011461024257928192935f92610237575b50508160011b915f199060031b1c1916176003555b80516001600160401b03811161022357600454600181811c91168015610219575b602082101461020557601f81116101a2575b50602091601f8211600114610142579181925f92610137575b50508160011b915f199060031b1c1916176004555b604051610a7b90816103a38239f35b015190505f80610113565b601f1982169260045f52805f20915f5b85811061018a57508360019510610172575b505050811b01600455610128565b01515f1960f88460031b161c191690555f8080610164565b91926020600181928685015181550194019201610152565b60045f527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b601f830160051c810191602084106101fb575b601f0160051c01905b8181106101f057506100fa565b5f81556001016101e3565b90915081906101da565b634e487b7160e01b5f52602260045260245ffd5b90607f16906100e8565b634e487b7160e01b5f52604160045260245ffd5b015190505f806100b2565b601f1982169360035f52805f20915f5b86811061028b5750836001959610610273575b505050811b016003556100c7565b01515f1960f88460031b161c191690555f8080610265565b91926020600181928685015181550194019201610252565b60035f527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b601f830160051c810191602084106102fc575b601f0160051c01905b8181106102f15750610098565b5f81556001016102e4565b90915081906102db565b90607f1690610086565b5f80fd5b6040519190601f01601f191682016001600160401b0381118382101761022357604052565b81601f82011215610310578051906001600160401b03821161022357610368601f8301601f1916602001610314565b9282845260208383010111610310575f5b82811061038d57505060205f918301015290565b8060208092840101518282870101520161037956fe6080806040526004361015610012575f80fd5b5f3560e01c90816306fdde031461077257508063095ea7b3146106c557806318160ddd1461068a57806323b872dd146104f6578063313ce567146104bd57806340c10f19146103be57806370a082311461035c57806395d89b4114610169578063a9059cbb1461011a5763dd62ed3e1461008a575f80fd5b346101165760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610116576100c1610909565b73ffffffffffffffffffffffffffffffffffffffff6100de61092c565b91165f52600160205273ffffffffffffffffffffffffffffffffffffffff60405f2091165f52602052602060405f2054604051908152f35b5f80fd5b346101165760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101165761015e610154610909565b602435903361094f565b602060405160018152f35b34610116575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610116576040515f600454908160011c60018316928315610352575b6020821084146103255781855284939081156102c5575060011461024b575b5003601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01681019067ffffffffffffffff82118183101761021e5761021a829182604052826108a3565b0390f35b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b60045f90815291507f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b5b8183106102a957505081016020017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06101ce565b6020919350806001915483858801015201910190918392610275565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660208581019190915291151560051b840190910191507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090506101ce565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b90607f16906101af565b346101165760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101165773ffffffffffffffffffffffffffffffffffffffff6103a8610909565b165f525f602052602060405f2054604051908152f35b346101165760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610116576103f5610909565b73ffffffffffffffffffffffffffffffffffffffff16602435811561049157600254908082018092116104645760207fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef915f9360025584845283825260408420818154019055604051908152a3005b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b7fec442f05000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b34610116575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261011657602060405160068152f35b346101165760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101165761052d610909565b61053561092c565b6044359073ffffffffffffffffffffffffffffffffffffffff831692835f52600160205260405f2073ffffffffffffffffffffffffffffffffffffffff33165f5260205260405f20547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81106105b1575b5061015e935061094f565b83811061065657841561062a5733156105fe5761015e945f52600160205260405f2073ffffffffffffffffffffffffffffffffffffffff33165f526020528360405f2091039055846105a6565b7f94280d62000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b7fe602df05000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b83907ffb8f41b2000000000000000000000000000000000000000000000000000000005f523360045260245260445260645ffd5b34610116575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610116576020600254604051908152f35b346101165760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610116576106fc610909565b60243590331561062a5773ffffffffffffffffffffffffffffffffffffffff169081156105fe57335f52600160205260405f20825f526020528060405f20556040519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a3602060405160018152f35b34610116575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610116575f600354908160011c60018316928315610899575b6020821084146103255781855284939081156102c5575060011461081f575003601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01681019067ffffffffffffffff82118183101761021e5761021a829182604052826108a3565b60035f90815291507fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b5b81831061087d57505081016020017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06101ce565b6020919350806001915483858801015201910190918392610849565b90607f16906107b5565b919091602081528251928360208301525f5b8481106108f35750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f845f6040809697860101520116010190565b80602080928401015160408286010152016108b5565b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361011657565b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361011657565b73ffffffffffffffffffffffffffffffffffffffff16908115610a195773ffffffffffffffffffffffffffffffffffffffff1691821561049157815f525f60205260405f20548181106109e757817fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92602092855f525f84520360405f2055845f525f825260405f20818154019055604051908152a3565b827fe450d38c000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b7f96c6fd1e000000000000000000000000000000000000000000000000000000005f525f60045260245ffdfea26469706673582212207d4081a323998c8d20751316ef809be0cc398b922c8a680eea7ed1d1bc08e9bf64736f6c634300081a0033000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000009507573682055534443000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000057055534443000000000000000000000000000000000000000000000000000000","output":"0x6080806040526004361015610012575f80fd5b5f3560e01c90816306fdde031461077257508063095ea7b3146106c557806318160ddd1461068a57806323b872dd146104f6578063313ce567146104bd57806340c10f19146103be57806370a082311461035c57806395d89b4114610169578063a9059cbb1461011a5763dd62ed3e1461008a575f80fd5b346101165760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610116576100c1610909565b73ffffffffffffffffffffffffffffffffffffffff6100de61092c565b91165f52600160205273ffffffffffffffffffffffffffffffffffffffff60405f2091165f52602052602060405f2054604051908152f35b5f80fd5b346101165760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101165761015e610154610909565b602435903361094f565b602060405160018152f35b34610116575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610116576040515f600454908160011c60018316928315610352575b6020821084146103255781855284939081156102c5575060011461024b575b5003601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01681019067ffffffffffffffff82118183101761021e5761021a829182604052826108a3565b0390f35b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b60045f90815291507f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b5b8183106102a957505081016020017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06101ce565b6020919350806001915483858801015201910190918392610275565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660208581019190915291151560051b840190910191507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090506101ce565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b90607f16906101af565b346101165760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101165773ffffffffffffffffffffffffffffffffffffffff6103a8610909565b165f525f602052602060405f2054604051908152f35b346101165760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610116576103f5610909565b73ffffffffffffffffffffffffffffffffffffffff16602435811561049157600254908082018092116104645760207fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef915f9360025584845283825260408420818154019055604051908152a3005b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b7fec442f05000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b34610116575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261011657602060405160068152f35b346101165760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101165761052d610909565b61053561092c565b6044359073ffffffffffffffffffffffffffffffffffffffff831692835f52600160205260405f2073ffffffffffffffffffffffffffffffffffffffff33165f5260205260405f20547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81106105b1575b5061015e935061094f565b83811061065657841561062a5733156105fe5761015e945f52600160205260405f2073ffffffffffffffffffffffffffffffffffffffff33165f526020528360405f2091039055846105a6565b7f94280d62000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b7fe602df05000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b83907ffb8f41b2000000000000000000000000000000000000000000000000000000005f523360045260245260445260645ffd5b34610116575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610116576020600254604051908152f35b346101165760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610116576106fc610909565b60243590331561062a5773ffffffffffffffffffffffffffffffffffffffff169081156105fe57335f52600160205260405f20825f526020528060405f20556040519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a3602060405160018152f35b34610116575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610116575f600354908160011c60018316928315610899575b6020821084146103255781855284939081156102c5575060011461081f575003601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01681019067ffffffffffffffff82118183101761021e5761021a829182604052826108a3565b60035f90815291507fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b5b81831061087d57505081016020017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06101ce565b6020919350806001915483858801015201910190918392610849565b90607f16906107b5565b919091602081528251928360208301525f5b8481106108f35750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f845f6040809697860101520116010190565b80602080928401015160408286010152016108b5565b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361011657565b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361011657565b73ffffffffffffffffffffffffffffffffffffffff16908115610a195773ffffffffffffffffffffffffffffffffffffffff1691821561049157815f525f60205260405f20548181106109e757817fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92602092855f525f84520360405f2055845f525f825260405f20818154019055604051908152a3565b827fe450d38c000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b7f96c6fd1e000000000000000000000000000000000000000000000000000000005f525f60045260245ffdfea26469706673582212207d4081a323998c8d20751316ef809be0cc398b922c8a680eea7ed1d1bc08e9bf64736f6c634300081a0033","gas_used":583112,"gas_limit":1056908255,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":0,"children":[],"idx":3,"trace":{"depth":1,"success":true,"caller":"0x7fa9385be102ac3eac297483dd6233d62b3e1496","address":"0x2e234dae75c793f67a35089c9d99245e1c58470b","maybe_precompile":false,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CREATE","value":"0x0","data":"0x6080806040523460d0577ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460ff8160401c1660c1576002600160401b03196001600160401b03821601605c575b6040516137ca90816100d58239f35b6001600160401b0319166001600160401b039081177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005581527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a15f80604d565b63f92ee8a960e01b5f5260045ffd5b5f80fdfe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a714612aed57508063248a9ca314612a7d5780632f0e31f414612a425780632f2ff15d146129c75780632f8e6a2d1461298d5780633013ce291461293d57806336568abe146128b55780633f4ba83a146127e55780634152881214611fe557806341dd26f514611e1f5780634c4911c414611cba57806350355d7614611c7f5780635b7baf6414611a955780635c975abb14611a365780636d3b96c3146119ce57806375b238fc146119765780637ab03cf21461193c5780638456cb591461186957806384f15090146117ea57806391d14854146117565780639e63798d1461162b578063a217fddf146115f3578063b4d884f6146114fd578063bf22c45714611269578063c0c53b8b14610ecc578063c9a84bb914610c84578063ce79eb6014610bb6578063d2e13f501461096a578063d547741f146108e8578063d75bbdf31461067d578063dd4ae9d4146104b0578063e138818c1461045f578063e1a4521814610425578063e63ea40814610222578063f9168231146101e75763ff96092a146101a8575f80fd5b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e3576020600154604051908152f35b5f80fd5b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e3576020600754604051908152f35b346101e35760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357610259612bcc565b610261612ba9565b73ffffffffffffffffffffffffffffffffffffffff60443592610282612e1e565b61028a613662565b169081158015610407575b6103df5773ffffffffffffffffffffffffffffffffffffffff5f5416808314610309575b50602073ffffffffffffffffffffffffffffffffffffffff826102fe867ff24ef89f38eadc1bde50701ad6e4d6d11a2dc24f7cf834a486991f38833285049587613605565b6040519586521693a3005b6020602491604051928380927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa9081156103d4575f916103a2575b506007548082111561039a5761036391612dfe565b808411156102b957837f9529d841000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b50505f610363565b90506020813d6020116103cc575b816103bd60209383612cf9565b810103126101e357518461034e565b3d91506103b0565b6040513d5f823e3d90fd5b7fd92e233d000000000000000000000000000000000000000000000000000000005f5260045ffd5b5073ffffffffffffffffffffffffffffffffffffffff811615610295565b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e35760206040516127108152f35b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357602073ffffffffffffffffffffffffffffffffffffffff60025416604051908152f35b346101e3576104be36612c1d565b9290916104c9613331565b6104d1613384565b6104da826133fb565b60ff815460a01c1660068110156106505761062857600181015465ffffffffffff8160a01c164210156106285773ffffffffffffffffffffffffffffffffffffffff16330361060057827f869e2577b006bf47ee981cf6fec2e25583548081c14b98deab587f77b5068038602073ffffffffffffffffffffffffffffffffffffffff946105b46105da996105886040519a8b9233878501528560408501526060808501526080840191612d8b565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081018a5289612cf9565b80600460038701966105ca8b888b8b541661345f565b0155604051908152a2541661357c565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055005b7f82b42900000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f8e78f0cb000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b346101e35761068b36612c1d565b919290610696613331565b61069e613384565b6106a7826133fb565b9360ff855460a01c166006811015610650576002036106285773ffffffffffffffffffffffffffffffffffffffff6002860154163303610600576107fd837f21d71db5be59bb9fa133895586b7404307dd33fb93b16db09dc6f1d9d7d231b060206105da9861076473ffffffffffffffffffffffffffffffffffffffff976107386040519b8c928a33888601612dc9565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081018b528a612cf9565b60038101956107778a868a8a541661345f565b6004820154740300000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff8454161783556107c581600754612dfe565b6007558860016127106107d9825485612e0b565b049889936107f86127106107ef60035484612e0b565b04958692612dfe565b612dfe565b9401541696806108a3575b5080610863575b5081610850575b604051908152847f0fd54bd364fa9e67f17b091aefe930932c09fe7651cf5ad02c71a418f3341444843393a3604051908152a3541661357c565b61085e82878a5f5416613605565b610816565b61087181338b5f5416613605565b604051908152857f253dd534010ac976fa263caa123bae79b9c50292adf7ce67bdc5ec309f784e61853393a38b61080f565b867f0e61cfd0ee655641b3ed0a1dd373ec3cacf4c090de1f33708e3a4091f4947662868c60025416936108db818f87905f5416613605565b604051908152a38c610808565b346101e35760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357610968600435610925612ba9565b9061096361095e825f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602052600160405f20015490565b612ea6565b613229565b005b346101e35761097836612c1d565b61098493919293613331565b61098c613384565b610995826133fb565b93845460ff8160a01c166006811015610650576106285773ffffffffffffffffffffffffffffffffffffffff16330361060057600185015473ffffffffffffffffffffffffffffffffffffffff811615610b8e5760a01c65ffffffffffff16421015610628576004850190815403610b66576105da94610a6f73ffffffffffffffffffffffffffffffffffffffff93610a436040519788923360208501526040808501526060840191612d8b565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101875286612cf9565b6003810191610a8286868686541661345f565b5490740100000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff825416179055610acd81600754612ccf565b60075580610b0a575b604051908152837fe3fbcc1ea1bdc559ec7f0347efde7655e58b5f45a30b0e4470a583c3ef5496b360203393a3541661357c565b610b61835f5416604051907f23b872dd00000000000000000000000000000000000000000000000000000000602083015233602483015230604483015283606483015260648252610b5c608483612cf9565b61370d565b610ad6565b7f99b0fc87000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fa9456d43000000000000000000000000000000000000000000000000000000005f5260045ffd5b346101e35760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357610bed612bcc565b602435908115158092036101e35773ffffffffffffffffffffffffffffffffffffffff90610c19612e1e565b169081156103df5760207f7ee54953080e392a475a25b6acacb85417ca4e1953293c90934233ca1361251091835f526006825260405f207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0081541660ff8316179055604051908152a2005b346101e35760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357600435610cbe612ba9565b60443567ffffffffffffffff81116101e357610cde903690600401612bef565b929091610ce9613331565b610cf1613384565b610cfa826133fb565b90815460ff8160a01c1660068110156106505761062857600183019182549165ffffffffffff8360a01c164210156106285773ffffffffffffffffffffffffffffffffffffffff16918233036106005773ffffffffffffffffffffffffffffffffffffffff166106285773ffffffffffffffffffffffffffffffffffffffff169081156103df578114610ea45773ffffffffffffffffffffffffffffffffffffffff6002840154168114610e7c57600373ffffffffffffffffffffffffffffffffffffffff93610e186105da98610dec604051998a923360208501528760408501526060808501526080840191612d8b565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101895288612cf9565b0191610e2886868686541661345f565b817fffffffffffffffffffffffff0000000000000000000000000000000000000000825416179055837f9a87df076ea1725aba8ba29d32517ce37c9597d88cbf16ec6707892cc330ab695f80a3541661357c565b7fc7b4e9eb000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f332ff0f9000000000000000000000000000000000000000000000000000000005f5260045ffd5b346101e35760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357610f03612bcc565b610f0b612ba9565b60443573ffffffffffffffffffffffffffffffffffffffff81168082036101e3577ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460ff8160401c16159467ffffffffffffffff821680159081611261575b6001149081611257575b15908161124e575b5061122657818660017fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000073ffffffffffffffffffffffffffffffffffffffff9516177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00556111d1575b50169081159081156111b2575b81156111a9575b506103df576110bd9273ffffffffffffffffffffffffffffffffffffffff916110216136b6565b6110296136b6565b6110316136b6565b6110396136b6565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00557fffffffffffffffffffffffff00000000000000000000000000000000000000005f5416175f55167fffffffffffffffffffffffff000000000000000000000000000000000000000060025416176002556110b781612f2c565b50613013565b505f805260066020527f54cdd369e4e8a8515e52ca72ec816c2101831ad1f18bf44102ed171459c9b4f880547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905561111657005b7fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054167ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a1005b90501585610ffa565b73ffffffffffffffffffffffffffffffffffffffff8516159150610ff3565b7fffffffffffffffffffffffffffffffffffffffffffffff0000000000000000001668010000000000000001177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005586610fe6565b7ff92ee8a9000000000000000000000000000000000000000000000000000000005f5260045ffd5b90501587610f7d565b303b159150610f75565b879150610f6b565b346101e35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357606060e06040516112a881612cdc565b5f81525f60208201525f60408201525f838201525f60808201525f60a08201525f60c082015201526004355f52600460205260405f20604051906112eb82612cdc565b60ff815473ffffffffffffffffffffffffffffffffffffffff8116845260a01c169060208301916006811015610650578252600181015491604084019173ffffffffffffffffffffffffffffffffffffffff8416835265ffffffffffff606086019460a01c16845273ffffffffffffffffffffffffffffffffffffffff600282015416936080860194855273ffffffffffffffffffffffffffffffffffffffff60038301541660a08701908152600560048401549360c08901948552019360405194855f8254926113bb84612d3a565b80845293600181169081156114bd5750600114611479575b506113e092500386612cf9565b60e0880194855273ffffffffffffffffffffffffffffffffffffffff6040519860208a525116602089015251600681101561065057879665ffffffffffff73ffffffffffffffffffffffffffffffffffffffff948561147599819560408d0152511660608b015251166080890152511660a0870152511660c08501525160e08401525161010080840152610120830190612c72565b0390f35b90505f9291925260205f20905f915b8183106114a15750509060206113e0928201018b6113d3565b6020919350806001915483858c01015201910190918792611488565b602093506113e09592507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091501682840152151560051b8201018b6113d3565b346101e35760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e35760043573ffffffffffffffffffffffffffffffffffffffff61154c612ba9565b611554612e1e565b169081156103df5761271061156b60035483612ccf565b116115cb576020817ff0c09f5238364083d828870e877edaebb364d9f19f4093fdbf24e486bbdca48492600155837fffffffffffffffffffffffff00000000000000000000000000000000000000006002541617600255604051908152a2005b7fc9034e18000000000000000000000000000000000000000000000000000000005f5260045ffd5b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e35760206040515f8152f35b346101e35761163936612c1d565b919290611644613331565b61164c613384565b611655826133fb565b60ff815460a01c1660068110156106505760010361062857600181015465ffffffffffff8160a01c164210156106285773ffffffffffffffffffffffffffffffffffffffff163303610600576105da946116d273ffffffffffffffffffffffffffffffffffffffff93610a43604051978892853360208601612dc9565b60038201916116e586868686541661345f565b740200000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff825416179055604051908152837f80c17db79857f338a6a6df68a6883ecc0ce78e2202fe61ed979733573f40538e60203393a3541661357c565b346101e35760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e35761178d612ba9565b6004355f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205273ffffffffffffffffffffffffffffffffffffffff60405f2091165f52602052602060ff60405f2054166040519015158152f35b346101e35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357600435611824612e1e565b61271061183360015483612ccf565b116115cb576020817f24fe03678743d8fe5f3d39d760da9fc7a5f3feea46847d91688ba8ef9e400d1492600355604051908152a1005b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e35761189f612e1e565b6118a7613331565b60017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff007fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005416177fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586020604051338152a1005b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357602060405161012c8152f35b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e35760206040517fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c217758152f35b346101e35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e35773ffffffffffffffffffffffffffffffffffffffff611a1a612bcc565b165f526006602052602060ff60405f2054166040519015158152f35b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357602060ff7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330054166040519015158152f35b346101e35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357600435611acf613384565b611ad8816133fb565b60ff815460a01c166006811015908161065057801515918280611c72575b8181611c61575b506106285761065057600203611c225765ffffffffffff600183015460a01c16610e108101809111611bf5574210611bcd575b740500000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff835416178255611bbd575b507f97237956f8810192811e2c3f273fd02c5d6295206fdd9c62e6fe2bfc19ba92325f80a260017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055005b611bc79082613505565b81611b72565b7f478f84e7000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b65ffffffffffff600183015460a01c16421015611b30577f8e78f0cb000000000000000000000000000000000000000000000000000000005f5260045ffd5b905061065057600282141581611afd565b50505f6001821415611af6565b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e3576020600554604051908152f35b346101e35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e35760043567ffffffffffffffff81116101e357366023820112156101e357806004013567ffffffffffffffff81116101e3573660248260051b840101116101e357611d31612e1e565b600554915f5b828110156109685760248160051b830101359081158015611e16575b611dee57816001925f52600460205273ffffffffffffffffffffffffffffffffffffffff600360405f20015416908115611de757805f526004602052600360405f20017fffffffffffffffffffffffff000000000000000000000000000000000000000081541690557fcde6a24b3e1e5d23bc4d45609905c64b3516b23478ba2f7fdada3ab2bae3812d5f80a35b01611d37565b5050611de1565b7f71c8f460000000000000000000000000000000000000000000000000000000005f5260045ffd5b50848211611d53565b346101e357611e2d36612c1d565b919290611e38613331565b611e40613384565b611e49826133fb565b9384549060ff8260a01c169260068410159283610650578415948515611f97575073ffffffffffffffffffffffffffffffffffffffff1633141580611f73575b61060057611ea6905b610a43604051978892853360208601612dc9565b6003860191611ecd868673ffffffffffffffffffffffffffffffffffffffff86541661345f565b740400000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff885416178755610650576105da9573ffffffffffffffffffffffffffffffffffffffff9315611f63575b50604051908152837fae7362b1af91f4492868987b9c73990d780060811551b58728fbe96fd1bab27560203393a3541661357c565b611f6d9085613505565b86611f2e565b5073ffffffffffffffffffffffffffffffffffffffff600188015416331415611e89565b5f94506001811491508115611fd7575b50156106285773ffffffffffffffffffffffffffffffffffffffff600288015416330361060057611ea690611e92565b93505060025f931488611fa7565b346101e35760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e35761201c612bcc565b612024612ba9565b60443560643567ffffffffffffffff81116101e357612047903690600401612bef565b9390926084359273ffffffffffffffffffffffffffffffffffffffff8416918285036101e35773ffffffffffffffffffffffffffffffffffffffff9061208b613331565b612093613384565b169283156103df5761012c4201804211611bf55782118015906127d6575b6127ae5773ffffffffffffffffffffffffffffffffffffffff1693338514610ea457841515806127a5575b610e7c57825f52600660205260ff60405f2054161561277d5782151590816125a4575b5061257c576005547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114611bf557600101948560055560405161214281612cdc565b33815287602082015f81526040830193888552606084019165ffffffffffff87168352608085019089825260a086019289845267ffffffffffffffff60c08801965f88521161254f578d906040519e8f6121c460207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8501160182612cf9565b5236828201116101e357818f5f936020938483013701015260e086019c8d528b5f52600460205273ffffffffffffffffffffffffffffffffffffffff8060405f20975116167fffffffffffffffffffffffff0000000000000000000000000000000000000000875416178655519060068210156106505760059673ffffffffffffffffffffffffffffffffffffffff9485937fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff74ff00000000000000000000000000000000000000008a549260a01b169116178855838060018a01935116167fffffffffffffffffffffffff0000000000000000000000000000000000000000835416178255517fffffffffffff000000000000ffffffffffffffffffffffffffffffffffffffff79ffffffffffff000000000000000000000000000000000000000083549260a01b1691161790555116826002860191167fffffffffffffffffffffffff0000000000000000000000000000000000000000825416179055511673ffffffffffffffffffffffffffffffffffffffff6003840191167fffffffffffffffffffffffff000000000000000000000000000000000000000082541617905551600482015501955195865167ffffffffffffffff811161254f576123ac8254612d3a565b601f811161250a575b50806020988990601f831160011461246d575f92612462575b50507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c19161790555b604051928352858301526040820152827fb0f0239bfdd96453e24733e18bfc24b70d8fadf123dd977473518dd577ee79b960603393a460017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055604051908152f35b0151905089806123ce565b5f858152828120937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016905b8181106124f357509084600195949392106124bc575b505050811b019055612400565b01517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c191690558980806124af565b92938c600181928786015181550195019301612499565b825f5260205f20601f830160051c81019160208410612545575b601f0160051c01905b81811061253a57506123b5565b5f815560010161252d565b9091508190612524565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f9c9d8823000000000000000000000000000000000000000000000000000000005f5260045ffd5b905060205f604051828101907f01ffc9a70000000000000000000000000000000000000000000000000000000082527f01ffc9a700000000000000000000000000000000000000000000000000000000602482015260248152612608604482612cf9565b519084617530fa903d5f519083612771575b5082612767575b50816126ce575b81612636575b5015876120ff565b602091505f90604051838101907f01ffc9a70000000000000000000000000000000000000000000000000000000082527f7ff6bc9e0000000000000000000000000000000000000000000000000000000060248201526024815261269b604482612cf9565b5191617530fa5f513d826126c2575b50816126b8575b508761262e565b90501515876126b1565b602011159150886126aa565b905060205f604051828101907f01ffc9a70000000000000000000000000000000000000000000000000000000082527fffffffff00000000000000000000000000000000000000000000000000000000602482015260248152612732604482612cf9565b519084617530fa5f513d8261275b575b5081612751575b501590612628565b9050151588612749565b60201115915089612742565b1515915088612621565b6020111592508961261a565b7fa04b28ec000000000000000000000000000000000000000000000000000000005f5260045ffd5b508385146120dc565b7ff7a0748c000000000000000000000000000000000000000000000000000000005f5260045ffd5b5065ffffffffffff82116120b1565b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e35761281b612e1e565b612823613662565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff007fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330054167fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6020604051338152a1005b346101e35760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e3576128ec612ba9565b3373ffffffffffffffffffffffffffffffffffffffff8216036129155761096890600435613229565b7f6697b232000000000000000000000000000000000000000000000000000000005f5260045ffd5b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357602073ffffffffffffffffffffffffffffffffffffffff5f5416604051908152f35b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e3576020604051610e108152f35b346101e35760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357610968600435612a04612ba9565b90612a3d61095e825f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602052600160405f20015490565b613117565b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e3576020600354604051908152f35b346101e35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e3576020612ae56004355f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602052600160405f20015490565b604051908152f35b346101e35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357600435907fffffffff0000000000000000000000000000000000000000000000000000000082168092036101e357817f7965db0b0000000000000000000000000000000000000000000000000000000060209314908115612b7f575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483612b78565b6024359073ffffffffffffffffffffffffffffffffffffffff821682036101e357565b6004359073ffffffffffffffffffffffffffffffffffffffff821682036101e357565b9181601f840112156101e35782359167ffffffffffffffff83116101e357602083818601950101116101e357565b60607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8201126101e35760043591602435916044359067ffffffffffffffff82116101e357612c6e91600401612bef565b9091565b91908251928382525f5b848110612cba5750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f845f6020809697860101520116010190565b80602080928401015182828601015201612c7c565b91908201809211611bf557565b610100810190811067ffffffffffffffff82111761254f57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761254f57604052565b90600182811c92168015612d81575b6020831014612d5457565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b91607f1691612d49565b601f82602094937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe093818652868601375f8582860101520116010190565b612dfb949273ffffffffffffffffffffffffffffffffffffffff60609316825260208201528160408201520191612d8b565b90565b91908203918211611bf557565b81810292918115918404141715611bf557565b335f9081527fb16e88c42fd4e48df2dd6a2eabd6bc9aec654ec170056b470819f8892cc6431c602052604090205460ff1615612e5657565b7fe2517d3f000000000000000000000000000000000000000000000000000000005f52336004527fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177560245260445ffd5b805f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260405f2073ffffffffffffffffffffffffffffffffffffffff33165f5260205260ff60405f20541615612efd5750565b7fe2517d3f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b73ffffffffffffffffffffffffffffffffffffffff81165f9081527fb7db2dd08fcb62d0c9e08c51941cae53c267786a0b75803fb7960902fc8ef97d602052604090205460ff1661300e5773ffffffffffffffffffffffffffffffffffffffff165f8181527fb7db2dd08fcb62d0c9e08c51941cae53c267786a0b75803fb7960902fc8ef97d6020526040812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790553391907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d8180a4600190565b505f90565b73ffffffffffffffffffffffffffffffffffffffff81165f9081527fb16e88c42fd4e48df2dd6a2eabd6bc9aec654ec170056b470819f8892cc6431c602052604090205460ff1661300e5773ffffffffffffffffffffffffffffffffffffffff165f8181527fb16e88c42fd4e48df2dd6a2eabd6bc9aec654ec170056b470819f8892cc6431c6020526040812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790553391907fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9080a4600190565b805f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260ff60405f205416155f1461322357805f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260405f2060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082541617905573ffffffffffffffffffffffffffffffffffffffff339216907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d5f80a4600190565b50505f90565b805f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260ff60405f2054165f1461322357805f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260405f207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00815416905573ffffffffffffffffffffffffffffffffffffffff339216907ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b5f80a4600190565b60ff7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300541661335c57565b7fd93c0665000000000000000000000000000000000000000000000000000000005f5260045ffd5b60027f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0054146133d35760027f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b7f3ee5aeb5000000000000000000000000000000000000000000000000000000005f5260045ffd5b80158015613416575b611dee575f52600460205260405f2090565b506005548111613404565b7fffffffff00000000000000000000000000000000000000000000000000000000612dfb949360609383521660208201528160408201520190612c72565b73ffffffffffffffffffffffffffffffffffffffff16918261348057505050565b823b156101e3576134e8925f92836040518096819582947fdc08fb1d0000000000000000000000000000000000000000000000000000000084527fffffffff000000000000000000000000000000000000000000000000000000008535169060048501613421565b03925af180156103d4576134f95750565b5f61350391612cf9565b565b600482015491821561357757602073ffffffffffffffffffffffffffffffffffffffff7f7ca5472b7ea78c2c0141c5a12ee6d170cf4ce8ed06be3d22c8252ddfc7a6a2c49261355686600754612dfe565b60075561356b86835f54168484541690613605565b541693604051908152a3565b505050565b73ffffffffffffffffffffffffffffffffffffffff16918261359d57505050565b823b156101e3576134e8925f92836040518096819582947fa3fe47830000000000000000000000000000000000000000000000000000000084527fffffffff000000000000000000000000000000000000000000000000000000008535169060048501613421565b6135039273ffffffffffffffffffffffffffffffffffffffff604051937fa9059cbb000000000000000000000000000000000000000000000000000000006020860152166024840152604483015260448252610b5c606483612cf9565b60ff7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330054161561368e57565b7f8dfc202b000000000000000000000000000000000000000000000000000000005f5260045ffd5b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c16156136e557565b7fd7e6bcf8000000000000000000000000000000000000000000000000000000005f5260045ffd5b905f602091828151910182855af1156103d4575f513d61378b575073ffffffffffffffffffffffffffffffffffffffff81163b155b6137495750565b73ffffffffffffffffffffffffffffffffffffffff907f5274afe7000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b6001141561374256fea26469706673582212206c80219f5022a102b78e2b3cea53bc36a61bd9d0874a3d24319381fbeaeb022a64736f6c634300081a0033","output":"0x6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a714612aed57508063248a9ca314612a7d5780632f0e31f414612a425780632f2ff15d146129c75780632f8e6a2d1461298d5780633013ce291461293d57806336568abe146128b55780633f4ba83a146127e55780634152881214611fe557806341dd26f514611e1f5780634c4911c414611cba57806350355d7614611c7f5780635b7baf6414611a955780635c975abb14611a365780636d3b96c3146119ce57806375b238fc146119765780637ab03cf21461193c5780638456cb591461186957806384f15090146117ea57806391d14854146117565780639e63798d1461162b578063a217fddf146115f3578063b4d884f6146114fd578063bf22c45714611269578063c0c53b8b14610ecc578063c9a84bb914610c84578063ce79eb6014610bb6578063d2e13f501461096a578063d547741f146108e8578063d75bbdf31461067d578063dd4ae9d4146104b0578063e138818c1461045f578063e1a4521814610425578063e63ea40814610222578063f9168231146101e75763ff96092a146101a8575f80fd5b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e3576020600154604051908152f35b5f80fd5b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e3576020600754604051908152f35b346101e35760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357610259612bcc565b610261612ba9565b73ffffffffffffffffffffffffffffffffffffffff60443592610282612e1e565b61028a613662565b169081158015610407575b6103df5773ffffffffffffffffffffffffffffffffffffffff5f5416808314610309575b50602073ffffffffffffffffffffffffffffffffffffffff826102fe867ff24ef89f38eadc1bde50701ad6e4d6d11a2dc24f7cf834a486991f38833285049587613605565b6040519586521693a3005b6020602491604051928380927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa9081156103d4575f916103a2575b506007548082111561039a5761036391612dfe565b808411156102b957837f9529d841000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b50505f610363565b90506020813d6020116103cc575b816103bd60209383612cf9565b810103126101e357518461034e565b3d91506103b0565b6040513d5f823e3d90fd5b7fd92e233d000000000000000000000000000000000000000000000000000000005f5260045ffd5b5073ffffffffffffffffffffffffffffffffffffffff811615610295565b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e35760206040516127108152f35b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357602073ffffffffffffffffffffffffffffffffffffffff60025416604051908152f35b346101e3576104be36612c1d565b9290916104c9613331565b6104d1613384565b6104da826133fb565b60ff815460a01c1660068110156106505761062857600181015465ffffffffffff8160a01c164210156106285773ffffffffffffffffffffffffffffffffffffffff16330361060057827f869e2577b006bf47ee981cf6fec2e25583548081c14b98deab587f77b5068038602073ffffffffffffffffffffffffffffffffffffffff946105b46105da996105886040519a8b9233878501528560408501526060808501526080840191612d8b565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081018a5289612cf9565b80600460038701966105ca8b888b8b541661345f565b0155604051908152a2541661357c565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055005b7f82b42900000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f8e78f0cb000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b346101e35761068b36612c1d565b919290610696613331565b61069e613384565b6106a7826133fb565b9360ff855460a01c166006811015610650576002036106285773ffffffffffffffffffffffffffffffffffffffff6002860154163303610600576107fd837f21d71db5be59bb9fa133895586b7404307dd33fb93b16db09dc6f1d9d7d231b060206105da9861076473ffffffffffffffffffffffffffffffffffffffff976107386040519b8c928a33888601612dc9565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081018b528a612cf9565b60038101956107778a868a8a541661345f565b6004820154740300000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff8454161783556107c581600754612dfe565b6007558860016127106107d9825485612e0b565b049889936107f86127106107ef60035484612e0b565b04958692612dfe565b612dfe565b9401541696806108a3575b5080610863575b5081610850575b604051908152847f0fd54bd364fa9e67f17b091aefe930932c09fe7651cf5ad02c71a418f3341444843393a3604051908152a3541661357c565b61085e82878a5f5416613605565b610816565b61087181338b5f5416613605565b604051908152857f253dd534010ac976fa263caa123bae79b9c50292adf7ce67bdc5ec309f784e61853393a38b61080f565b867f0e61cfd0ee655641b3ed0a1dd373ec3cacf4c090de1f33708e3a4091f4947662868c60025416936108db818f87905f5416613605565b604051908152a38c610808565b346101e35760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357610968600435610925612ba9565b9061096361095e825f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602052600160405f20015490565b612ea6565b613229565b005b346101e35761097836612c1d565b61098493919293613331565b61098c613384565b610995826133fb565b93845460ff8160a01c166006811015610650576106285773ffffffffffffffffffffffffffffffffffffffff16330361060057600185015473ffffffffffffffffffffffffffffffffffffffff811615610b8e5760a01c65ffffffffffff16421015610628576004850190815403610b66576105da94610a6f73ffffffffffffffffffffffffffffffffffffffff93610a436040519788923360208501526040808501526060840191612d8b565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101875286612cf9565b6003810191610a8286868686541661345f565b5490740100000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff825416179055610acd81600754612ccf565b60075580610b0a575b604051908152837fe3fbcc1ea1bdc559ec7f0347efde7655e58b5f45a30b0e4470a583c3ef5496b360203393a3541661357c565b610b61835f5416604051907f23b872dd00000000000000000000000000000000000000000000000000000000602083015233602483015230604483015283606483015260648252610b5c608483612cf9565b61370d565b610ad6565b7f99b0fc87000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fa9456d43000000000000000000000000000000000000000000000000000000005f5260045ffd5b346101e35760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357610bed612bcc565b602435908115158092036101e35773ffffffffffffffffffffffffffffffffffffffff90610c19612e1e565b169081156103df5760207f7ee54953080e392a475a25b6acacb85417ca4e1953293c90934233ca1361251091835f526006825260405f207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0081541660ff8316179055604051908152a2005b346101e35760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357600435610cbe612ba9565b60443567ffffffffffffffff81116101e357610cde903690600401612bef565b929091610ce9613331565b610cf1613384565b610cfa826133fb565b90815460ff8160a01c1660068110156106505761062857600183019182549165ffffffffffff8360a01c164210156106285773ffffffffffffffffffffffffffffffffffffffff16918233036106005773ffffffffffffffffffffffffffffffffffffffff166106285773ffffffffffffffffffffffffffffffffffffffff169081156103df578114610ea45773ffffffffffffffffffffffffffffffffffffffff6002840154168114610e7c57600373ffffffffffffffffffffffffffffffffffffffff93610e186105da98610dec604051998a923360208501528760408501526060808501526080840191612d8b565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101895288612cf9565b0191610e2886868686541661345f565b817fffffffffffffffffffffffff0000000000000000000000000000000000000000825416179055837f9a87df076ea1725aba8ba29d32517ce37c9597d88cbf16ec6707892cc330ab695f80a3541661357c565b7fc7b4e9eb000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f332ff0f9000000000000000000000000000000000000000000000000000000005f5260045ffd5b346101e35760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357610f03612bcc565b610f0b612ba9565b60443573ffffffffffffffffffffffffffffffffffffffff81168082036101e3577ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460ff8160401c16159467ffffffffffffffff821680159081611261575b6001149081611257575b15908161124e575b5061122657818660017fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000073ffffffffffffffffffffffffffffffffffffffff9516177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00556111d1575b50169081159081156111b2575b81156111a9575b506103df576110bd9273ffffffffffffffffffffffffffffffffffffffff916110216136b6565b6110296136b6565b6110316136b6565b6110396136b6565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00557fffffffffffffffffffffffff00000000000000000000000000000000000000005f5416175f55167fffffffffffffffffffffffff000000000000000000000000000000000000000060025416176002556110b781612f2c565b50613013565b505f805260066020527f54cdd369e4e8a8515e52ca72ec816c2101831ad1f18bf44102ed171459c9b4f880547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905561111657005b7fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054167ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a1005b90501585610ffa565b73ffffffffffffffffffffffffffffffffffffffff8516159150610ff3565b7fffffffffffffffffffffffffffffffffffffffffffffff0000000000000000001668010000000000000001177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005586610fe6565b7ff92ee8a9000000000000000000000000000000000000000000000000000000005f5260045ffd5b90501587610f7d565b303b159150610f75565b879150610f6b565b346101e35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357606060e06040516112a881612cdc565b5f81525f60208201525f60408201525f838201525f60808201525f60a08201525f60c082015201526004355f52600460205260405f20604051906112eb82612cdc565b60ff815473ffffffffffffffffffffffffffffffffffffffff8116845260a01c169060208301916006811015610650578252600181015491604084019173ffffffffffffffffffffffffffffffffffffffff8416835265ffffffffffff606086019460a01c16845273ffffffffffffffffffffffffffffffffffffffff600282015416936080860194855273ffffffffffffffffffffffffffffffffffffffff60038301541660a08701908152600560048401549360c08901948552019360405194855f8254926113bb84612d3a565b80845293600181169081156114bd5750600114611479575b506113e092500386612cf9565b60e0880194855273ffffffffffffffffffffffffffffffffffffffff6040519860208a525116602089015251600681101561065057879665ffffffffffff73ffffffffffffffffffffffffffffffffffffffff948561147599819560408d0152511660608b015251166080890152511660a0870152511660c08501525160e08401525161010080840152610120830190612c72565b0390f35b90505f9291925260205f20905f915b8183106114a15750509060206113e0928201018b6113d3565b6020919350806001915483858c01015201910190918792611488565b602093506113e09592507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091501682840152151560051b8201018b6113d3565b346101e35760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e35760043573ffffffffffffffffffffffffffffffffffffffff61154c612ba9565b611554612e1e565b169081156103df5761271061156b60035483612ccf565b116115cb576020817ff0c09f5238364083d828870e877edaebb364d9f19f4093fdbf24e486bbdca48492600155837fffffffffffffffffffffffff00000000000000000000000000000000000000006002541617600255604051908152a2005b7fc9034e18000000000000000000000000000000000000000000000000000000005f5260045ffd5b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e35760206040515f8152f35b346101e35761163936612c1d565b919290611644613331565b61164c613384565b611655826133fb565b60ff815460a01c1660068110156106505760010361062857600181015465ffffffffffff8160a01c164210156106285773ffffffffffffffffffffffffffffffffffffffff163303610600576105da946116d273ffffffffffffffffffffffffffffffffffffffff93610a43604051978892853360208601612dc9565b60038201916116e586868686541661345f565b740200000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff825416179055604051908152837f80c17db79857f338a6a6df68a6883ecc0ce78e2202fe61ed979733573f40538e60203393a3541661357c565b346101e35760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e35761178d612ba9565b6004355f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205273ffffffffffffffffffffffffffffffffffffffff60405f2091165f52602052602060ff60405f2054166040519015158152f35b346101e35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357600435611824612e1e565b61271061183360015483612ccf565b116115cb576020817f24fe03678743d8fe5f3d39d760da9fc7a5f3feea46847d91688ba8ef9e400d1492600355604051908152a1005b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e35761189f612e1e565b6118a7613331565b60017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff007fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005416177fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586020604051338152a1005b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357602060405161012c8152f35b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e35760206040517fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c217758152f35b346101e35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e35773ffffffffffffffffffffffffffffffffffffffff611a1a612bcc565b165f526006602052602060ff60405f2054166040519015158152f35b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357602060ff7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330054166040519015158152f35b346101e35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357600435611acf613384565b611ad8816133fb565b60ff815460a01c166006811015908161065057801515918280611c72575b8181611c61575b506106285761065057600203611c225765ffffffffffff600183015460a01c16610e108101809111611bf5574210611bcd575b740500000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff835416178255611bbd575b507f97237956f8810192811e2c3f273fd02c5d6295206fdd9c62e6fe2bfc19ba92325f80a260017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055005b611bc79082613505565b81611b72565b7f478f84e7000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b65ffffffffffff600183015460a01c16421015611b30577f8e78f0cb000000000000000000000000000000000000000000000000000000005f5260045ffd5b905061065057600282141581611afd565b50505f6001821415611af6565b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e3576020600554604051908152f35b346101e35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e35760043567ffffffffffffffff81116101e357366023820112156101e357806004013567ffffffffffffffff81116101e3573660248260051b840101116101e357611d31612e1e565b600554915f5b828110156109685760248160051b830101359081158015611e16575b611dee57816001925f52600460205273ffffffffffffffffffffffffffffffffffffffff600360405f20015416908115611de757805f526004602052600360405f20017fffffffffffffffffffffffff000000000000000000000000000000000000000081541690557fcde6a24b3e1e5d23bc4d45609905c64b3516b23478ba2f7fdada3ab2bae3812d5f80a35b01611d37565b5050611de1565b7f71c8f460000000000000000000000000000000000000000000000000000000005f5260045ffd5b50848211611d53565b346101e357611e2d36612c1d565b919290611e38613331565b611e40613384565b611e49826133fb565b9384549060ff8260a01c169260068410159283610650578415948515611f97575073ffffffffffffffffffffffffffffffffffffffff1633141580611f73575b61060057611ea6905b610a43604051978892853360208601612dc9565b6003860191611ecd868673ffffffffffffffffffffffffffffffffffffffff86541661345f565b740400000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff885416178755610650576105da9573ffffffffffffffffffffffffffffffffffffffff9315611f63575b50604051908152837fae7362b1af91f4492868987b9c73990d780060811551b58728fbe96fd1bab27560203393a3541661357c565b611f6d9085613505565b86611f2e565b5073ffffffffffffffffffffffffffffffffffffffff600188015416331415611e89565b5f94506001811491508115611fd7575b50156106285773ffffffffffffffffffffffffffffffffffffffff600288015416330361060057611ea690611e92565b93505060025f931488611fa7565b346101e35760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e35761201c612bcc565b612024612ba9565b60443560643567ffffffffffffffff81116101e357612047903690600401612bef565b9390926084359273ffffffffffffffffffffffffffffffffffffffff8416918285036101e35773ffffffffffffffffffffffffffffffffffffffff9061208b613331565b612093613384565b169283156103df5761012c4201804211611bf55782118015906127d6575b6127ae5773ffffffffffffffffffffffffffffffffffffffff1693338514610ea457841515806127a5575b610e7c57825f52600660205260ff60405f2054161561277d5782151590816125a4575b5061257c576005547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114611bf557600101948560055560405161214281612cdc565b33815287602082015f81526040830193888552606084019165ffffffffffff87168352608085019089825260a086019289845267ffffffffffffffff60c08801965f88521161254f578d906040519e8f6121c460207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8501160182612cf9565b5236828201116101e357818f5f936020938483013701015260e086019c8d528b5f52600460205273ffffffffffffffffffffffffffffffffffffffff8060405f20975116167fffffffffffffffffffffffff0000000000000000000000000000000000000000875416178655519060068210156106505760059673ffffffffffffffffffffffffffffffffffffffff9485937fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff74ff00000000000000000000000000000000000000008a549260a01b169116178855838060018a01935116167fffffffffffffffffffffffff0000000000000000000000000000000000000000835416178255517fffffffffffff000000000000ffffffffffffffffffffffffffffffffffffffff79ffffffffffff000000000000000000000000000000000000000083549260a01b1691161790555116826002860191167fffffffffffffffffffffffff0000000000000000000000000000000000000000825416179055511673ffffffffffffffffffffffffffffffffffffffff6003840191167fffffffffffffffffffffffff000000000000000000000000000000000000000082541617905551600482015501955195865167ffffffffffffffff811161254f576123ac8254612d3a565b601f811161250a575b50806020988990601f831160011461246d575f92612462575b50507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c19161790555b604051928352858301526040820152827fb0f0239bfdd96453e24733e18bfc24b70d8fadf123dd977473518dd577ee79b960603393a460017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055604051908152f35b0151905089806123ce565b5f858152828120937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016905b8181106124f357509084600195949392106124bc575b505050811b019055612400565b01517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c191690558980806124af565b92938c600181928786015181550195019301612499565b825f5260205f20601f830160051c81019160208410612545575b601f0160051c01905b81811061253a57506123b5565b5f815560010161252d565b9091508190612524565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f9c9d8823000000000000000000000000000000000000000000000000000000005f5260045ffd5b905060205f604051828101907f01ffc9a70000000000000000000000000000000000000000000000000000000082527f01ffc9a700000000000000000000000000000000000000000000000000000000602482015260248152612608604482612cf9565b519084617530fa903d5f519083612771575b5082612767575b50816126ce575b81612636575b5015876120ff565b602091505f90604051838101907f01ffc9a70000000000000000000000000000000000000000000000000000000082527f7ff6bc9e0000000000000000000000000000000000000000000000000000000060248201526024815261269b604482612cf9565b5191617530fa5f513d826126c2575b50816126b8575b508761262e565b90501515876126b1565b602011159150886126aa565b905060205f604051828101907f01ffc9a70000000000000000000000000000000000000000000000000000000082527fffffffff00000000000000000000000000000000000000000000000000000000602482015260248152612732604482612cf9565b519084617530fa5f513d8261275b575b5081612751575b501590612628565b9050151588612749565b60201115915089612742565b1515915088612621565b6020111592508961261a565b7fa04b28ec000000000000000000000000000000000000000000000000000000005f5260045ffd5b508385146120dc565b7ff7a0748c000000000000000000000000000000000000000000000000000000005f5260045ffd5b5065ffffffffffff82116120b1565b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e35761281b612e1e565b612823613662565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff007fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330054167fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6020604051338152a1005b346101e35760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e3576128ec612ba9565b3373ffffffffffffffffffffffffffffffffffffffff8216036129155761096890600435613229565b7f6697b232000000000000000000000000000000000000000000000000000000005f5260045ffd5b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357602073ffffffffffffffffffffffffffffffffffffffff5f5416604051908152f35b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e3576020604051610e108152f35b346101e35760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357610968600435612a04612ba9565b90612a3d61095e825f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602052600160405f20015490565b613117565b346101e3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e3576020600354604051908152f35b346101e35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e3576020612ae56004355f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602052600160405f20015490565b604051908152f35b346101e35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e357600435907fffffffff0000000000000000000000000000000000000000000000000000000082168092036101e357817f7965db0b0000000000000000000000000000000000000000000000000000000060209314908115612b7f575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483612b78565b6024359073ffffffffffffffffffffffffffffffffffffffff821682036101e357565b6004359073ffffffffffffffffffffffffffffffffffffffff821682036101e357565b9181601f840112156101e35782359167ffffffffffffffff83116101e357602083818601950101116101e357565b60607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8201126101e35760043591602435916044359067ffffffffffffffff82116101e357612c6e91600401612bef565b9091565b91908251928382525f5b848110612cba5750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f845f6020809697860101520116010190565b80602080928401015182828601015201612c7c565b91908201809211611bf557565b610100810190811067ffffffffffffffff82111761254f57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761254f57604052565b90600182811c92168015612d81575b6020831014612d5457565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b91607f1691612d49565b601f82602094937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe093818652868601375f8582860101520116010190565b612dfb949273ffffffffffffffffffffffffffffffffffffffff60609316825260208201528160408201520191612d8b565b90565b91908203918211611bf557565b81810292918115918404141715611bf557565b335f9081527fb16e88c42fd4e48df2dd6a2eabd6bc9aec654ec170056b470819f8892cc6431c602052604090205460ff1615612e5657565b7fe2517d3f000000000000000000000000000000000000000000000000000000005f52336004527fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177560245260445ffd5b805f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260405f2073ffffffffffffffffffffffffffffffffffffffff33165f5260205260ff60405f20541615612efd5750565b7fe2517d3f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b73ffffffffffffffffffffffffffffffffffffffff81165f9081527fb7db2dd08fcb62d0c9e08c51941cae53c267786a0b75803fb7960902fc8ef97d602052604090205460ff1661300e5773ffffffffffffffffffffffffffffffffffffffff165f8181527fb7db2dd08fcb62d0c9e08c51941cae53c267786a0b75803fb7960902fc8ef97d6020526040812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790553391907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d8180a4600190565b505f90565b73ffffffffffffffffffffffffffffffffffffffff81165f9081527fb16e88c42fd4e48df2dd6a2eabd6bc9aec654ec170056b470819f8892cc6431c602052604090205460ff1661300e5773ffffffffffffffffffffffffffffffffffffffff165f8181527fb16e88c42fd4e48df2dd6a2eabd6bc9aec654ec170056b470819f8892cc6431c6020526040812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790553391907fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9080a4600190565b805f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260ff60405f205416155f1461322357805f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260405f2060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082541617905573ffffffffffffffffffffffffffffffffffffffff339216907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d5f80a4600190565b50505f90565b805f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260ff60405f2054165f1461322357805f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260405f207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00815416905573ffffffffffffffffffffffffffffffffffffffff339216907ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b5f80a4600190565b60ff7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300541661335c57565b7fd93c0665000000000000000000000000000000000000000000000000000000005f5260045ffd5b60027f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0054146133d35760027f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b7f3ee5aeb5000000000000000000000000000000000000000000000000000000005f5260045ffd5b80158015613416575b611dee575f52600460205260405f2090565b506005548111613404565b7fffffffff00000000000000000000000000000000000000000000000000000000612dfb949360609383521660208201528160408201520190612c72565b73ffffffffffffffffffffffffffffffffffffffff16918261348057505050565b823b156101e3576134e8925f92836040518096819582947fdc08fb1d0000000000000000000000000000000000000000000000000000000084527fffffffff000000000000000000000000000000000000000000000000000000008535169060048501613421565b03925af180156103d4576134f95750565b5f61350391612cf9565b565b600482015491821561357757602073ffffffffffffffffffffffffffffffffffffffff7f7ca5472b7ea78c2c0141c5a12ee6d170cf4ce8ed06be3d22c8252ddfc7a6a2c49261355686600754612dfe565b60075561356b86835f54168484541690613605565b541693604051908152a3565b505050565b73ffffffffffffffffffffffffffffffffffffffff16918261359d57505050565b823b156101e3576134e8925f92836040518096819582947fa3fe47830000000000000000000000000000000000000000000000000000000084527fffffffff000000000000000000000000000000000000000000000000000000008535169060048501613421565b6135039273ffffffffffffffffffffffffffffffffffffffff604051937fa9059cbb000000000000000000000000000000000000000000000000000000006020860152166024840152604483015260448252610b5c606483612cf9565b60ff7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330054161561368e57565b7f8dfc202b000000000000000000000000000000000000000000000000000000005f5260045ffd5b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c16156136e557565b7fd7e6bcf8000000000000000000000000000000000000000000000000000000005f5260045ffd5b905f602091828151910182855af1156103d4575f513d61378b575073ffffffffffffffffffffffffffffffffffffffff81163b155b6137495750565b73ffffffffffffffffffffffffffffffffffffffff907f5274afe7000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b6001141561374256fea26469706673582212206c80219f5022a102b78e2b3cea53bc36a61bd9d0874a3d24319381fbeaeb022a64736f6c634300081a0033","gas_used":2882818,"gas_limit":1056277291,"status":"Return","steps":[],"decoded":null},"logs":[{"raw_log":{"topics":["0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2"],"data":"0x000000000000000000000000000000000000000000000000ffffffffffffffff"},"decoded":null,"position":0,"index":0}],"ordering":[{"Log":0}]},{"parent":0,"children":[5,6],"idx":4,"trace":{"depth":1,"success":true,"caller":"0x7fa9385be102ac3eac297483dd6233d62b3e1496","address":"0xf62849f9a0b5bf2913b396098f7c7019b51a820a","maybe_precompile":false,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CREATE","value":"0x0","data":"0x60a0604052610e548038038061001481610281565b928339810160608282031261027d5761002c826102a6565b610038602084016102a6565b604084015190936001600160401b03821161027d570182601f8201121561027d5780519061006d610068836102ba565b610281565b938285526020838301011161027d575f5b82811061026857505060205f9184010152803b15610248577f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0383169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a2815115610231575f8083602061013095519101845af43d15610229573d91610121610068846102ba565b9283523d5f602085013e6102d5565b505b6040519061064f8083016001600160401b038111848210176102155760209284926107e584396001600160a01b031681520301905ff0801561020a5760018060a01b0316806080525f80516020610e34833981519152547f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6040805160018060a01b0384168152846020820152a181156101f7576001600160a01b031916175f80516020610e34833981519152556040516104b1908161033482396080518160070152f35b633173bdd160e11b5f525f60045260245ffd5b6040513d5f823e3d90fd5b634e487b7160e01b5f52604160045260245ffd5b6060916102d5565b505034156101325763b398979f60e01b5f5260045ffd5b634c9c8ce360e01b5f9081526001600160a01b0391909116600452602490fd5b8060208092840101518282880101520161007e565b5f80fd5b6040519190601f01601f191682016001600160401b0381118382101761021557604052565b51906001600160a01b038216820361027d57565b6001600160401b03811161021557601f01601f191660200190565b906102f957508051156102ea57805190602001fd5b63d6bda27560e01b5f5260045ffd5b8151158061032a575b61030a575090565b639996b31560e01b5f9081526001600160a01b0391909116600452602490fd5b50803b1561030256fe6080604052337f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16036100bd575f357fffffffff00000000000000000000000000000000000000000000000000000000167f4f1ef28600000000000000000000000000000000000000000000000000000000146100b3577fd2b576ec000000000000000000000000000000000000000000000000000000005f5260045ffd5b6100bb6101c1565b005b5f8073ffffffffffffffffffffffffffffffffffffffff7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5416368280378136915af43d5f803e1561010d573d5ff35b3d5ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f604051930116820182811067ffffffffffffffff82111761018257604052565b610111565b67ffffffffffffffff811161018257601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b366004116102745760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102745760043573ffffffffffffffffffffffffffffffffffffffff8116809103610274576024359067ffffffffffffffff821161027457366023830112156102745781600401359061024961024483610187565b61013e565b918083523660248286010111610274576020815f92602461027297018387013784010152610278565b565b5f80fd5b90813b156103675773ffffffffffffffffffffffffffffffffffffffff8216807fffffffffffffffffffffffff00000000000000000000000000000000000000007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5416177f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a280511561033657610333916103a9565b50565b50503461033f57565b7fb398979f000000000000000000000000000000000000000000000000000000005f5260045ffd5b73ffffffffffffffffffffffffffffffffffffffff827f4c9c8ce3000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b5f806103db93602081519101845af43d156103de573d916103cc61024484610187565b9283523d5f602085013e6103e2565b90565b6060915b9061041f57508051156103f757805190602001fd5b7fd6bda275000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580610472575b610430575090565b73ffffffffffffffffffffffffffffffffffffffff907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561042856fea2646970667358221220481cacafffcdffc0448fe9cfe96f8149f61f2083b69e100dc149c658ac2528fd64736f6c634300081a003360803460b857601f61064f38819003918201601f19168301916001600160401b0383118484101760bc5780849260209460405283398101031260b857516001600160a01b0381169081900360b857801560a5575f80546001600160a01b031981168317825560405192916001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a361057e90816100d18239f35b631e4fbdf760e01b5f525f60045260245ffd5b5f80fd5b634e487b7160e01b5f52604160045260245ffdfe60806040526004361015610011575f80fd5b5f803560e01c8063715018a6146103c45780638da5cb5b146103745780639623609d146101cb578063ad3cb1cc146101485763f2fde38b14610051575f80fd5b346101455760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101455760043573ffffffffffffffffffffffffffffffffffffffff8116809103610141576100a96104fc565b80156101155773ffffffffffffffffffffffffffffffffffffffff8254827fffffffffffffffffffffffff00000000000000000000000000000000000000008216178455167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b6024827f1e4fbdf700000000000000000000000000000000000000000000000000000000815280600452fd5b5080fd5b80fd5b503461014557807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261014557506101c760405161018960408261045e565b600581527f352e302e30000000000000000000000000000000000000000000000000000000602082015260405191829160208352602083019061049f565b0390f35b5060607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103435760043573ffffffffffffffffffffffffffffffffffffffff81168091036103435760243573ffffffffffffffffffffffffffffffffffffffff81168091036103435760443567ffffffffffffffff8111610343573660238201121561034357806004013567ffffffffffffffff8111610347576040519161029f601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0166020018461045e565b818352366024838301011161034357815f9260246020930183860137830101526102c76104fc565b823b1561034357610316925f926040518095819482937f4f1ef286000000000000000000000000000000000000000000000000000000008452600484015260406024840152604483019061049f565b039134905af180156103385761032a575080f35b61033691505f9061045e565b005b6040513d5f823e3d90fd5b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b34610343575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261034357602073ffffffffffffffffffffffffffffffffffffffff5f5416604051908152f35b34610343575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610343576103fa6104fc565b5f73ffffffffffffffffffffffffffffffffffffffff81547fffffffffffffffffffffffff000000000000000000000000000000000000000081168355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761034757604052565b91908251928382525f5b8481106104e75750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f845f6020809697860101520116010190565b806020809284010151828286010152016104a9565b73ffffffffffffffffffffffffffffffffffffffff5f5416330361051c57565b7f118cdaa7000000000000000000000000000000000000000000000000000000005f523360045260245ffdfea2646970667358221220bf8617a09a791c192cb0d344676f2dcbe88d7a55549a679b2ee10beaae67e98364736f6c634300081a0033b53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61030000000000000000000000002e234dae75c793f67a35089c9d99245e1c58470b000000000000000000000000d49279c8fc3454d7328eb8777274812e84b658df00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000064c0c53b8b0000000000000000000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f000000000000000000000000f43bca55e8091977223fa5b776e23528d205dca8000000000000000000000000aa10a84ce7d9ae517a52c6d5ca153b369af99ecf00000000000000000000000000000000000000000000000000000000","output":"0x6080604052337f0000000000000000000000004f81992fce2e1846dd528ec0102e6ee1f61ed3e273ffffffffffffffffffffffffffffffffffffffff16036100bd575f357fffffffff00000000000000000000000000000000000000000000000000000000167f4f1ef28600000000000000000000000000000000000000000000000000000000146100b3577fd2b576ec000000000000000000000000000000000000000000000000000000005f5260045ffd5b6100bb6101c1565b005b5f8073ffffffffffffffffffffffffffffffffffffffff7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5416368280378136915af43d5f803e1561010d573d5ff35b3d5ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f604051930116820182811067ffffffffffffffff82111761018257604052565b610111565b67ffffffffffffffff811161018257601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b366004116102745760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102745760043573ffffffffffffffffffffffffffffffffffffffff8116809103610274576024359067ffffffffffffffff821161027457366023830112156102745781600401359061024961024483610187565b61013e565b918083523660248286010111610274576020815f92602461027297018387013784010152610278565b565b5f80fd5b90813b156103675773ffffffffffffffffffffffffffffffffffffffff8216807fffffffffffffffffffffffff00000000000000000000000000000000000000007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5416177f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a280511561033657610333916103a9565b50565b50503461033f57565b7fb398979f000000000000000000000000000000000000000000000000000000005f5260045ffd5b73ffffffffffffffffffffffffffffffffffffffff827f4c9c8ce3000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b5f806103db93602081519101845af43d156103de573d916103cc61024484610187565b9283523d5f602085013e6103e2565b90565b6060915b9061041f57508051156103f757805190602001fd5b7fd6bda275000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580610472575b610430575090565b73ffffffffffffffffffffffffffffffffffffffff907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561042856fea2646970667358221220481cacafffcdffc0448fe9cfe96f8149f61f2083b69e100dc149c658ac2528fd64736f6c634300081a0033","gas_used":789149,"gas_limit":1053378589,"status":"Return","steps":[],"decoded":null},"logs":[{"raw_log":{"topics":["0xbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b","0x0000000000000000000000002e234dae75c793f67a35089c9d99245e1c58470b"],"data":"0x"},"decoded":null,"position":0,"index":1},{"raw_log":{"topics":["0x7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f"],"data":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000004f81992fce2e1846dd528ec0102e6ee1f61ed3e2"},"decoded":null,"position":2,"index":6}],"ordering":[{"Log":0},{"Call":0},{"Call":1},{"Log":1}]},{"parent":4,"children":[],"idx":5,"trace":{"depth":2,"success":true,"caller":"0xf62849f9a0b5bf2913b396098f7c7019b51a820a","address":"0x2e234dae75c793f67a35089c9d99245e1c58470b","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"DELEGATECALL","value":"0x0","data":"0xc0c53b8b0000000000000000000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f000000000000000000000000f43bca55e8091977223fa5b776e23528d205dca8000000000000000000000000aa10a84ce7d9ae517a52c6d5ca153b369af99ecf","output":"0x","gas_used":162348,"gas_limit":1036895255,"status":"Stop","steps":[],"decoded":null},"logs":[{"raw_log":{"topics":["0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d","0x0000000000000000000000000000000000000000000000000000000000000000","0x000000000000000000000000aa10a84ce7d9ae517a52c6d5ca153b369af99ecf","0x0000000000000000000000007fa9385be102ac3eac297483dd6233d62b3e1496"],"data":"0x"},"decoded":null,"position":0,"index":2},{"raw_log":{"topics":["0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d","0xa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775","0x000000000000000000000000aa10a84ce7d9ae517a52c6d5ca153b369af99ecf","0x0000000000000000000000007fa9385be102ac3eac297483dd6233d62b3e1496"],"data":"0x"},"decoded":null,"position":0,"index":3},{"raw_log":{"topics":["0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2"],"data":"0x0000000000000000000000000000000000000000000000000000000000000001"},"decoded":null,"position":0,"index":4}],"ordering":[{"Log":0},{"Log":1},{"Log":2}]},{"parent":4,"children":[],"idx":6,"trace":{"depth":2,"success":true,"caller":"0xf62849f9a0b5bf2913b396098f7c7019b51a820a","address":"0x4f81992fce2e1846dd528ec0102e6ee1f61ed3e2","maybe_precompile":false,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CREATE","value":"0x0","data":"0x60803460b857601f61064f38819003918201601f19168301916001600160401b0383118484101760bc5780849260209460405283398101031260b857516001600160a01b0381169081900360b857801560a5575f80546001600160a01b031981168317825560405192916001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a361057e90816100d18239f35b631e4fbdf760e01b5f525f60045260245ffd5b5f80fd5b634e487b7160e01b5f52604160045260245ffdfe60806040526004361015610011575f80fd5b5f803560e01c8063715018a6146103c45780638da5cb5b146103745780639623609d146101cb578063ad3cb1cc146101485763f2fde38b14610051575f80fd5b346101455760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101455760043573ffffffffffffffffffffffffffffffffffffffff8116809103610141576100a96104fc565b80156101155773ffffffffffffffffffffffffffffffffffffffff8254827fffffffffffffffffffffffff00000000000000000000000000000000000000008216178455167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b6024827f1e4fbdf700000000000000000000000000000000000000000000000000000000815280600452fd5b5080fd5b80fd5b503461014557807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261014557506101c760405161018960408261045e565b600581527f352e302e30000000000000000000000000000000000000000000000000000000602082015260405191829160208352602083019061049f565b0390f35b5060607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103435760043573ffffffffffffffffffffffffffffffffffffffff81168091036103435760243573ffffffffffffffffffffffffffffffffffffffff81168091036103435760443567ffffffffffffffff8111610343573660238201121561034357806004013567ffffffffffffffff8111610347576040519161029f601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0166020018461045e565b818352366024838301011161034357815f9260246020930183860137830101526102c76104fc565b823b1561034357610316925f926040518095819482937f4f1ef286000000000000000000000000000000000000000000000000000000008452600484015260406024840152604483019061049f565b039134905af180156103385761032a575080f35b61033691505f9061045e565b005b6040513d5f823e3d90fd5b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b34610343575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261034357602073ffffffffffffffffffffffffffffffffffffffff5f5416604051908152f35b34610343575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610343576103fa6104fc565b5f73ffffffffffffffffffffffffffffffffffffffff81547fffffffffffffffffffffffff000000000000000000000000000000000000000081168355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761034757604052565b91908251928382525f5b8481106104e75750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f845f6020809697860101520116010190565b806020809284010151828286010152016104a9565b73ffffffffffffffffffffffffffffffffffffffff5f5416330361051c57565b7f118cdaa7000000000000000000000000000000000000000000000000000000005f523360045260245ffdfea2646970667358221220bf8617a09a791c192cb0d344676f2dcbe88d7a55549a679b2ee10beaae67e98364736f6c634300081a0033000000000000000000000000d49279c8fc3454d7328eb8777274812e84b658df","output":"0x60806040526004361015610011575f80fd5b5f803560e01c8063715018a6146103c45780638da5cb5b146103745780639623609d146101cb578063ad3cb1cc146101485763f2fde38b14610051575f80fd5b346101455760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101455760043573ffffffffffffffffffffffffffffffffffffffff8116809103610141576100a96104fc565b80156101155773ffffffffffffffffffffffffffffffffffffffff8254827fffffffffffffffffffffffff00000000000000000000000000000000000000008216178455167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b6024827f1e4fbdf700000000000000000000000000000000000000000000000000000000815280600452fd5b5080fd5b80fd5b503461014557807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261014557506101c760405161018960408261045e565b600581527f352e302e30000000000000000000000000000000000000000000000000000000602082015260405191829160208352602083019061049f565b0390f35b5060607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103435760043573ffffffffffffffffffffffffffffffffffffffff81168091036103435760243573ffffffffffffffffffffffffffffffffffffffff81168091036103435760443567ffffffffffffffff8111610343573660238201121561034357806004013567ffffffffffffffff8111610347576040519161029f601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0166020018461045e565b818352366024838301011161034357815f9260246020930183860137830101526102c76104fc565b823b1561034357610316925f926040518095819482937f4f1ef286000000000000000000000000000000000000000000000000000000008452600484015260406024840152604483019061049f565b039134905af180156103385761032a575080f35b61033691505f9061045e565b005b6040513d5f823e3d90fd5b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b34610343575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261034357602073ffffffffffffffffffffffffffffffffffffffff5f5416604051908152f35b34610343575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610343576103fa6104fc565b5f73ffffffffffffffffffffffffffffffffffffffff81547fffffffffffffffffffffffff000000000000000000000000000000000000000081168355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761034757604052565b91908251928382525f5b8481106104e75750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f845f6020809697860101520116010190565b806020809284010151828286010152016104a9565b73ffffffffffffffffffffffffffffffffffffffff5f5416330361051c57565b7f118cdaa7000000000000000000000000000000000000000000000000000000005f523360045260245ffdfea2646970667358221220bf8617a09a791c192cb0d344676f2dcbe88d7a55549a679b2ee10beaae67e98364736f6c634300081a0033","gas_used":305418,"gas_limit":1036703183,"status":"Return","steps":[],"decoded":null},"logs":[{"raw_log":{"topics":["0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0","0x0000000000000000000000000000000000000000000000000000000000000000","0x000000000000000000000000d49279c8fc3454d7328eb8777274812e84b658df"],"data":"0x"},"decoded":null,"position":0,"index":5}],"ordering":[{"Log":0}]},{"parent":0,"children":[],"idx":7,"trace":{"depth":1,"success":true,"caller":"0x7fa9385be102ac3eac297483dd6233d62b3e1496","address":"0x5615deb798bb3e4dfa0139dfa1b3d433cc23b72f","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0x40c10f19000000000000000000000000d5e069bc58dedb2a3a348995ee753eef0274004f00000000000000000000000000000000000000000000000000038d7ea4c68000","output":"0x","gas_used":46438,"gas_limit":1052594323,"status":"Stop","steps":[],"decoded":null},"logs":[{"raw_log":{"topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x0000000000000000000000000000000000000000000000000000000000000000","0x000000000000000000000000d5e069bc58dedb2a3a348995ee753eef0274004f"],"data":"0x00000000000000000000000000000000000000000000000000038d7ea4c68000"},"decoded":null,"position":0,"index":7}],"ordering":[{"Log":0}]},{"parent":0,"children":[],"idx":8,"trace":{"depth":1,"success":true,"caller":"0x7fa9385be102ac3eac297483dd6233d62b3e1496","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0xca669fa7000000000000000000000000d5e069bc58dedb2a3a348995ee753eef0274004f","output":"0x","gas_used":0,"gas_limit":1052548082,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":0,"children":[],"idx":9,"trace":{"depth":1,"success":true,"caller":"0x7fa9385be102ac3eac297483dd6233d62b3e1496","address":"0x5615deb798bb3e4dfa0139dfa1b3d433cc23b72f","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0x095ea7b3000000000000000000000000f62849f9a0b5bf2913b396098f7c7019b51a820affffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff","output":"0x0000000000000000000000000000000000000000000000000000000000000001","gas_used":24298,"gas_limit":1052547543,"status":"Return","steps":[],"decoded":null},"logs":[{"raw_log":{"topics":["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925","0x000000000000000000000000d5e069bc58dedb2a3a348995ee753eef0274004f","0x000000000000000000000000f62849f9a0b5bf2913b396098f7c7019b51a820a"],"data":"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"},"decoded":null,"position":0,"index":8}],"ordering":[{"Log":0}]},{"parent":0,"children":[],"idx":10,"trace":{"depth":1,"success":true,"caller":"0x7fa9385be102ac3eac297483dd6233d62b3e1496","address":"0x5991a2df15a8f6a256d3ec51e99254cd3fb576a9","maybe_precompile":false,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CREATE","value":"0x0","data":"0x60808060405234601557610fd0908161001a8239f35b5f80fdfe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a714610b915750806306661abd14610b575780633a32058114610a1d578063a3fe4783146105eb578063d183ce14146105295763dc08fb1d1461005e575f80fd5b346103cb5761006c36610cb1565b9092916040517fbf22c4570000000000000000000000000000000000000000000000000000000081528360048201525f81602481335afa801561051e575f906103fc575b6020915001519260068410156103cf57604051926100cd84610e07565b60018452602084019182527fffffffff00000000000000000000000000000000000000000000000000000000604085019316835261010a81610f60565b956101186040519788610e40565b81875236828201116103cb57815f92602092838a0137870101526060830194855260ff60808401941684525f54680100000000000000008110156103725780600161016592015f55610d51565b93909361039f5751151560ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00855416911617835551600183015560028201905160e01c7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000082541617905560038101925192835167ffffffffffffffff8111610372576101f28254610db6565b601f811161032d575b506020601f8211600114610287579080600494939260ff96975f9261027c575b50507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c19161790555b019151167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008254161790555f80f35b015190505f8061021b565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0821695835f52815f20965f5b8181106103155750966001928492600497969560ff999a106102de575b505050811b01905561024d565b01517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c191690555f80806102d1565b838301518955600190980197602093840193016102b4565b825f5260205f20601f830160051c81019160208410610368575b601f0160051c01905b81811061035d57506101fb565b5f8155600101610350565b9091508190610347565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b503d805f833e61040c8183610e40565b8101906020818303126103cb5780519067ffffffffffffffff82116103cb5701610100818303126103cb576040519061044482610e23565b61044d81610f3f565b8252602081015160068110156103cb57602083015261046e60408201610f3f565b6040830152606081015165ffffffffffff811681036103cb57606083015261049860808201610f3f565b60808301526104a960a08201610f3f565b60a083015260c081015160c083015260e08101519067ffffffffffffffff82116103cb57019180601f840112156103cb578251926104e684610f60565b916104f46040519384610e40565b848352602085830101116103cb5760209361051491858085019101610c4d565b60e08201526100b0565b6040513d5f823e3d90fd5b346103cb5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103cb576004355f548110156103cb5761056d90610d51565b5060ff8154166001820154916105e1600282015460e01b917fffffffff0000000000000000000000000000000000000000000000000000000060ff60046105b660038501610e81565b930154169360405196879615158752602087015216604085015260a0606085015260a0840190610c6e565b9060808301520390f35b346103cb576105f936610cb1565b9092916040517fbf22c4570000000000000000000000000000000000000000000000000000000081528360048201525f81602481335afa801561051e575f906108fb575b6020915001519260068410156103cf576040519261065a84610e07565b5f8452602084019182527fffffffff00000000000000000000000000000000000000000000000000000000604085019316835261069681610f60565b956106a46040519788610e40565b81875236828201116103cb57815f92602092838a0137870101526060830194855260ff60808401941684525f5468010000000000000000811015610372578060016106f192015f55610d51565b93909361039f5751151560ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00855416911617835551600183015560028201905160e01c7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000082541617905560038101925192835167ffffffffffffffff81116103725761077e8254610db6565b601f81116108b6575b506020601f8211600114610811579080600494939260ff96975f926108065750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c1916179055019151167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008254161790555f80f35b01519050878061021b565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0821695835f52815f20965f5b81811061089e5750966001928492600497969560ff999a1061086757505050811b01905561024d565b01517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c191690558780806102d1565b8383015189556001909801976020938401930161083e565b825f5260205f20601f830160051c810191602084106108f1575b601f0160051c01905b8181106108e65750610787565b5f81556001016108d9565b90915081906108d0565b503d805f833e61090b8183610e40565b8101906020818303126103cb5780519067ffffffffffffffff82116103cb5701610100818303126103cb576040519061094382610e23565b61094c81610f3f565b8252602081015160068110156103cb57602083015261096d60408201610f3f565b6040830152606081015165ffffffffffff811681036103cb57606083015261099760808201610f3f565b60808301526109a860a08201610f3f565b60a083015260c081015160c083015260e08101519067ffffffffffffffff82116103cb57019180601f840112156103cb578251926109e584610f60565b916109f36040519384610e40565b848352602085830101116103cb57602093610a1391858085019101610c4d565b60e082015261063d565b346103cb5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103cb575f6080604051610a5b81610e07565b8281528260208201528260408201526060808201520152610a7d600435610d51565b50604051610a8a81610e07565b60ff825416151581526001820154916020820192835260ff610b4b600283015460e01b927fffffffff0000000000000000000000000000000000000000000000000000000060408601941684527fffffffff00000000000000000000000000000000000000000000000000000000836004610b0760038501610e81565b93606089019485520154169460808701958652604051978897602089525115156020890152516040880152511660608601525160a0608086015260c0850190610c6e565b91511660a08301520390f35b346103cb575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103cb5760205f54604051908152f35b346103cb5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103cb57600435907fffffffff0000000000000000000000000000000000000000000000000000000082168092036103cb57817f7ff6bc9e0000000000000000000000000000000000000000000000000000000060209314908115610c23575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483610c1c565b5f5b838110610c5e5750505f910152565b8181015183820152602001610c4f565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602093610caa81518092818752878088019101610c4d565b0116010190565b9060607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8301126103cb57600435916024357fffffffff00000000000000000000000000000000000000000000000000000000811681036103cb579160443567ffffffffffffffff81116103cb57826023820112156103cb5780600401359267ffffffffffffffff84116103cb57602484830101116103cb576024019190565b5f54811015610d89575f8080526005919091027f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5630191565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b90600182811c92168015610dfd575b6020831014610dd057565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b91607f1691610dc5565b60a0810190811067ffffffffffffffff82111761037257604052565b610100810190811067ffffffffffffffff82111761037257604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761037257604052565b9060405191825f825492610e9484610db6565b8084529360018116908115610eff5750600114610ebb575b50610eb992500383610e40565b565b90505f9291925260205f20905f915b818310610ee3575050906020610eb9928201015f610eac565b6020919350806001915483858901015201910190918492610eca565b60209350610eb99592507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091501682840152151560051b8201015f610eac565b519073ffffffffffffffffffffffffffffffffffffffff821682036103cb57565b67ffffffffffffffff811161037257601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0166020019056fea2646970667358221220af75d4a17c0b6da6a3609fe1e4338988c321fe2d51d15dda0930b8f2e25388aa64736f6c634300081a0033","output":"0x6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a714610b915750806306661abd14610b575780633a32058114610a1d578063a3fe4783146105eb578063d183ce14146105295763dc08fb1d1461005e575f80fd5b346103cb5761006c36610cb1565b9092916040517fbf22c4570000000000000000000000000000000000000000000000000000000081528360048201525f81602481335afa801561051e575f906103fc575b6020915001519260068410156103cf57604051926100cd84610e07565b60018452602084019182527fffffffff00000000000000000000000000000000000000000000000000000000604085019316835261010a81610f60565b956101186040519788610e40565b81875236828201116103cb57815f92602092838a0137870101526060830194855260ff60808401941684525f54680100000000000000008110156103725780600161016592015f55610d51565b93909361039f5751151560ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00855416911617835551600183015560028201905160e01c7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000082541617905560038101925192835167ffffffffffffffff8111610372576101f28254610db6565b601f811161032d575b506020601f8211600114610287579080600494939260ff96975f9261027c575b50507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c19161790555b019151167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008254161790555f80f35b015190505f8061021b565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0821695835f52815f20965f5b8181106103155750966001928492600497969560ff999a106102de575b505050811b01905561024d565b01517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c191690555f80806102d1565b838301518955600190980197602093840193016102b4565b825f5260205f20601f830160051c81019160208410610368575b601f0160051c01905b81811061035d57506101fb565b5f8155600101610350565b9091508190610347565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b503d805f833e61040c8183610e40565b8101906020818303126103cb5780519067ffffffffffffffff82116103cb5701610100818303126103cb576040519061044482610e23565b61044d81610f3f565b8252602081015160068110156103cb57602083015261046e60408201610f3f565b6040830152606081015165ffffffffffff811681036103cb57606083015261049860808201610f3f565b60808301526104a960a08201610f3f565b60a083015260c081015160c083015260e08101519067ffffffffffffffff82116103cb57019180601f840112156103cb578251926104e684610f60565b916104f46040519384610e40565b848352602085830101116103cb5760209361051491858085019101610c4d565b60e08201526100b0565b6040513d5f823e3d90fd5b346103cb5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103cb576004355f548110156103cb5761056d90610d51565b5060ff8154166001820154916105e1600282015460e01b917fffffffff0000000000000000000000000000000000000000000000000000000060ff60046105b660038501610e81565b930154169360405196879615158752602087015216604085015260a0606085015260a0840190610c6e565b9060808301520390f35b346103cb576105f936610cb1565b9092916040517fbf22c4570000000000000000000000000000000000000000000000000000000081528360048201525f81602481335afa801561051e575f906108fb575b6020915001519260068410156103cf576040519261065a84610e07565b5f8452602084019182527fffffffff00000000000000000000000000000000000000000000000000000000604085019316835261069681610f60565b956106a46040519788610e40565b81875236828201116103cb57815f92602092838a0137870101526060830194855260ff60808401941684525f5468010000000000000000811015610372578060016106f192015f55610d51565b93909361039f5751151560ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00855416911617835551600183015560028201905160e01c7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000082541617905560038101925192835167ffffffffffffffff81116103725761077e8254610db6565b601f81116108b6575b506020601f8211600114610811579080600494939260ff96975f926108065750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c1916179055019151167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008254161790555f80f35b01519050878061021b565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0821695835f52815f20965f5b81811061089e5750966001928492600497969560ff999a1061086757505050811b01905561024d565b01517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c191690558780806102d1565b8383015189556001909801976020938401930161083e565b825f5260205f20601f830160051c810191602084106108f1575b601f0160051c01905b8181106108e65750610787565b5f81556001016108d9565b90915081906108d0565b503d805f833e61090b8183610e40565b8101906020818303126103cb5780519067ffffffffffffffff82116103cb5701610100818303126103cb576040519061094382610e23565b61094c81610f3f565b8252602081015160068110156103cb57602083015261096d60408201610f3f565b6040830152606081015165ffffffffffff811681036103cb57606083015261099760808201610f3f565b60808301526109a860a08201610f3f565b60a083015260c081015160c083015260e08101519067ffffffffffffffff82116103cb57019180601f840112156103cb578251926109e584610f60565b916109f36040519384610e40565b848352602085830101116103cb57602093610a1391858085019101610c4d565b60e082015261063d565b346103cb5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103cb575f6080604051610a5b81610e07565b8281528260208201528260408201526060808201520152610a7d600435610d51565b50604051610a8a81610e07565b60ff825416151581526001820154916020820192835260ff610b4b600283015460e01b927fffffffff0000000000000000000000000000000000000000000000000000000060408601941684527fffffffff00000000000000000000000000000000000000000000000000000000836004610b0760038501610e81565b93606089019485520154169460808701958652604051978897602089525115156020890152516040880152511660608601525160a0608086015260c0850190610c6e565b91511660a08301520390f35b346103cb575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103cb5760205f54604051908152f35b346103cb5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103cb57600435907fffffffff0000000000000000000000000000000000000000000000000000000082168092036103cb57817f7ff6bc9e0000000000000000000000000000000000000000000000000000000060209314908115610c23575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483610c1c565b5f5b838110610c5e5750505f910152565b8181015183820152602001610c4f565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602093610caa81518092818752878088019101610c4d565b0116010190565b9060607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8301126103cb57600435916024357fffffffff00000000000000000000000000000000000000000000000000000000811681036103cb579160443567ffffffffffffffff81116103cb57826023820112156103cb5780600401359267ffffffffffffffff84116103cb57602484830101116103cb576024019190565b5f54811015610d89575f8080526005919091027f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5630191565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b90600182811c92168015610dfd575b6020831014610dd057565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b91607f1691610dc5565b60a0810190811067ffffffffffffffff82111761037257604052565b610100810190811067ffffffffffffffff82111761037257604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761037257604052565b9060405191825f825492610e9484610db6565b8084529360018116908115610eff5750600114610ebb575b50610eb992500383610e40565b565b90505f9291925260205f20905f915b818310610ee3575050906020610eb9928201015f610eac565b6020919350806001915483858901015201910190918492610eca565b60209350610eb99592507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091501682840152151560051b8201015f610eac565b519073ffffffffffffffffffffffffffffffffffffffff821682036103cb57565b67ffffffffffffffff811161037257601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0166020019056fea2646970667358221220af75d4a17c0b6da6a3609fe1e4338988c321fe2d51d15dda0930b8f2e25388aa64736f6c634300081a0033","gas_used":810452,"gas_limit":1052491147,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":0,"children":[],"idx":11,"trace":{"depth":1,"success":true,"caller":"0x7fa9385be102ac3eac297483dd6233d62b3e1496","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0xca669fa7000000000000000000000000aa10a84ce7d9ae517a52c6d5ca153b369af99ecf","output":"0x","gas_used":0,"gas_limit":1051692964,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":0,"children":[13],"idx":12,"trace":{"depth":1,"success":true,"caller":"0x7fa9385be102ac3eac297483dd6233d62b3e1496","address":"0xf62849f9a0b5bf2913b396098f7c7019b51a820a","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0xce79eb600000000000000000000000005991a2df15a8f6a256d3ec51e99254cd3fb576a90000000000000000000000000000000000000000000000000000000000000001","output":"0x","gas_used":24966,"gas_limit":1051692397,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[{"Call":0}]},{"parent":12,"children":[],"idx":13,"trace":{"depth":2,"success":true,"caller":"0xf62849f9a0b5bf2913b396098f7c7019b51a820a","address":"0x2e234dae75c793f67a35089c9d99245e1c58470b","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"DELEGATECALL","value":"0x0","data":"0xce79eb600000000000000000000000005991a2df15a8f6a256d3ec51e99254cd3fb576a90000000000000000000000000000000000000000000000000000000000000001","output":"0x","gas_used":24646,"gas_limit":1035259418,"status":"Stop","steps":[],"decoded":null},"logs":[{"raw_log":{"topics":["0x7ee54953080e392a475a25b6acacb85417ca4e1953293c90934233ca13612510","0x0000000000000000000000005991a2df15a8f6a256d3ec51e99254cd3fb576a9"],"data":"0x0000000000000000000000000000000000000000000000000000000000000001"},"decoded":null,"position":0,"index":9}],"ordering":[{"Log":0}]},{"parent":0,"children":[15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,49,50,52,53,55,56,58,59,62,63,65,66,68,69,72,73],"idx":14,"trace":{"depth":1,"success":true,"caller":"0x7fa9385be102ac3eac297483dd6233d62b3e1496","address":"0xc7183455a4c133ae270771860664b6b7ec320bb1","maybe_precompile":false,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CREATE","value":"0x0","data":"0x608080604052346104ca57608081614c41803803809161001f8285610d0a565b8339810103126104ca578051906001600160a01b03821682036104ca5760208101516001600160a01b038116908190036104ca57600161006d606061006660408601610d41565b9401610d41565b938160ff19600c541617600c55601f54906101008360a81b039060081b1690828060a81b0319161717601f5560018060a01b0319602054161760205560018060a01b031660018060a01b0319602154161760215560018060a01b031660018060a01b031960225416176022555f5b60038110156105d35760405163348051d760e11b8152600481018290525f816024815f80516020614c218339815191525afa9081156104d6575f916105b9575b50604051906101566021836020810193606360f81b85526101458151809260208686019101610d79565b81010301601f198101845283610d0a565b60405160208101906101826020828651610171818789610d79565b81010301601f198101835282610d0a565b519020916040519263ffa1864960e01b845260048401526020836024815f80516020614c218339815191525afa9283156104d6575f9361057e575b505f80516020614c218339815191523b156104ca5761021260645f9260405194859384926318caf8e360e31b845260018060a01b03891660048501526040602485015251809281604486015285850190610d79565b601f01601f19168101030181835f80516020614c218339815191525af180156104d65761056e575b506023820180546001600160a01b0319166001600160a01b0390921691909117815560405163348051d760e11b8152600481018390525f816024815f80516020614c218339815191525afa9081156104d6575f9161054c575b50604051906102bd6021836020810193600760fc1b85526101458151809260208686019101610d79565b60405160208101906102d86020828651610171818789610d79565b519020916040519263ffa1864960e01b845260048401526020836024815f80516020614c218339815191525afa9283156104d6575f93610511575b505f80516020614c218339815191523b156104ca5761036860645f9260405194859384926318caf8e360e31b845260018060a01b03891660048501526040602485015251809281604486015285850190610d79565b601f01601f19168101030181835f80516020614c218339815191525af180156104d657610501575b506026830180546001600160a01b0319166001600160a01b0392831617905560205482549082169116813b156104ca575f916044839260405194859384926340c10f1960e01b8452600484015264e8d4a5100060248401525af180156104d6576104f1575b50546001600160a01b03165f80516020614c218339815191523b156104ca576040519063ca669fa760e01b825260048201525f81602481835f80516020614c218339815191525af180156104d6576104e1575b5060208054601f5460405163095ea7b360e01b81526001600160a01b0360089290921c821660048201525f1960248201529291839160449183915f91165af180156104d65761049b575b506001016100db565b6020813d82116104ce575b816104b360209383610d0a565b810103126104ca5751801515036104ca575f610492565b5f80fd5b3d91506104a6565b6040513d5f823e3d90fd5b5f6104eb91610d0a565b5f610448565b5f6104fb91610d0a565b5f6103f5565b5f61050b91610d0a565b5f610390565b9092506020813d8211610544575b8161052c60209383610d0a565b810103126104ca5761053d90610d41565b915f610313565b3d915061051f565b61056891503d805f833e6105608183610d0a565b810190610d9a565b5f610293565b5f61057891610d0a565b5f61023a565b9092506020813d82116105b1575b8161059960209383610d0a565b810103126104ca576105aa90610d41565b915f6101bd565b3d915061058c565b6105cd91503d805f833e6105608183610d0a565b5f61011b565b604080516105e18282610d0a565b600281526020810161065360f41b8152825160208101906106028284610d55565b60028152610611602282610d0a565b51902083519063ffa1864960e01b825260048201526020816024815f80516020614c218339815191525afa908115610c4f575f91610cd0575b505f80516020614c218339815191523b156104ca5761069e60645f92865194859384926318caf8e360e31b845260018060a01b03169788600485015289602485015251809281604486015285850190610d79565b601f01601f19168101030181835f80516020614c218339815191525af18015610ab157610cc0575b50602980546001600160a01b03191691909117905580516106e78282610d0a565b600281526020810161653160f01b8152825160208101906107088284610d55565b60028152610717602282610d0a565b51902083519063ffa1864960e01b825260048201526020816024815f80516020614c218339815191525afa908115610c4f575f91610c86575b505f80516020614c218339815191523b156104ca576107a460645f92865194859384926318caf8e360e31b845260018060a01b03169788600485015289602485015251809281604486015285850190610d79565b601f01601f19168101030181835f80516020614c218339815191525af18015610ab157610c76575b5060018060a01b0319602a541617602a5562278d00420190814211610bf857905f915b6003831015610c69576023830180549093906001600160a01b03165f80516020614c218339815191523b156104ca5782519063ca669fa760e01b825260048201525f81602481835f80516020614c218339815191525af18015610ab157610c59575b5060018060a01b03601f5460081c16938160260190602060018060a01b0383541660e460018060a01b0360295416915f88519a8b9485936320a9440960e11b8552600485015260248401528a604484015260a06064840152600460a4840152631cd9595960e21b60c48401528160848401525af1958615610c4f575f96610c1c575b5081545f91906001600160a01b03165f80516020614c218339815191523b156104ca5785519063ca669fa760e01b825260048201525f81602481835f80516020614c218339815191525af18015610bd457610c0c575b50601f54600185019060081c6001600160a01b0316818611610bf85781620f42400291620f4240830403610bf857803b156104ca578651633752ba7560e21b8152600481018a905260248101839052606060448201525f6064820181905290918290608490829084905af18015610bee57610bde575b50875f52602b602052855f2060ff1981541690556001851015610adf575b5050600283146109d4575b505060010192506107ef565b610acb57546001600160a01b03165f80516020614c218339815191523b156104ca5782519063ca669fa760e01b825260048201525f81602481835f80516020614c218339815191525af18015610ab157610abb575b50601f5460081c6001600160a01b031693843b156104ca575f80956084855180988193639e63798d60e01b8352866004840152816024840152606060448401528160648401525af1948515610ab1576001939495610aa1575b505f52602b602052825f20600260ff19825416179055839291856109c8565b5f610aab91610d0a565b85610a82565b83513d5f823e3d90fd5b5f610ac591610d0a565b84610a29565b634e487b7160e01b5f52603260045260245ffd5b90545f92506001600160a01b03165f80516020614c218339815191523b156104ca5785519063ca669fa760e01b825260048201525f81602481835f80516020614c218339815191525af18015610bd457610bc4575b50601f5460081c6001600160a01b0316803b156104ca578551630d2e13f560e41b8152600481018990526024810192909252606060448301525f60648301819052908290608490829084905af18015610bba57610baa575b50855f52602b602052835f20600160ff1982541617905586806109bd565b5f610bb491610d0a565b86610b8c565b85513d5f823e3d90fd5b5f610bce91610d0a565b87610b34565b86513d5f823e3d90fd5b5f610be891610d0a565b8861099f565b87513d5f823e3d90fd5b634e487b7160e01b5f52601160045260245ffd5b5f610c1691610d0a565b87610929565b9095506020813d8211610c47575b81610c3760209383610d0a565b810103126104ca575194866108d3565b3d9150610c2a565b84513d5f823e3d90fd5b5f610c6391610d0a565b84610851565b51613e169081610e0b8239f35b5f610c8091610d0a565b826107cc565b90506020813d602011610cb8575b81610ca160209383610d0a565b810103126104ca57610cb290610d41565b84610750565b3d9150610c94565b5f610cca91610d0a565b826106c6565b90506020813d602011610d02575b81610ceb60209383610d0a565b810103126104ca57610cfc90610d41565b8461064a565b3d9150610cde565b601f909101601f19168101906001600160401b03821190821017610d2d57604052565b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b03821682036104ca57565b5f5b60028110610d6957505060025f910152565b8181015183820152602001610d57565b5f5b838110610d8a5750505f910152565b8181015183820152602001610d7b565b6020818303126104ca578051906001600160401b0382116104ca570181601f820112156104ca5780516001600160401b038111610d2d5760405192610de9601f8301601f191660200185610d0a565b818452602082840101116104ca57610e079160208085019101610d79565b9056fe6080806040526004361015610012575f80fd5b5f905f3560e01c90816305e3769c1461191c57508063087320b2146118025780630b78f9c0146111ce5780631ed7831c146111255780632ade388014610f685780633e5e3c2314610ebf5780633f7286f414610e16578063531c7faa14610dfe57806359e1361914610dc25780635b7baf6414610d8757806366d9a9a014610c2c578063725cc2e114610c145780637f974c6f14610bd857806381ede1bb14610bc05780638253f2d91461080d57806385226c811461075d578063916a17c6146106885780639675dc1714610670578063b0464fdc1461059b578063b5508aa9146104eb578063b5c0922c146104a0578063ba414fa61461045d578063d130382514610445578063e20c9f711461038c578063e5d6bf02146101f1578063e662e387146101b0578063fa7626d41461016f5763fd61a25614610152575f80fd5b3461016c5761016961016336611c67565b91612d94565b80f35b80fd5b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c57602060ff601f54166040519015158152f35b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c57602060ff602f54166040519015158152f35b503461016c5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c57806102336202a3006001600435613b7d565b6102fb604091838084516102478682611a0b565b600c81527f426f756e6420726573756c740000000000000000000000000000000000000000602082015285516102e4816102b260208201947fb60e72cc0000000000000000000000000000000000000000000000000000000086528a60248401526064830190611b2b565b876044830152037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282611a0b565b51906a636f6e736f6c652e6c6f675afa50426128c2565b90737109709ecfa91a80626ff3989d68f67f5b1dd12d3b15610388578051917fe5d6bf020000000000000000000000000000000000000000000000000000000083526004830152828260248183737109709ecfa91a80626ff3989d68f67f5b1dd12d5af190811561037f575061036e5750f35b8161037891611a0b565b61016c5780f35b513d84823e3d90fd5b5050fd5b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c5760405180916020601554928381520191601582527f55f448fdea98c4d29eb340757ef0a66cd03dbb9538908a6a81d96026b71ec475915b818110610419576104158561040981870382611a0b565b60405191829182611ba2565b0390f35b825473ffffffffffffffffffffffffffffffffffffffff168452602090930192600192830192016103f2565b503461016c5761016961045736611c67565b91612b77565b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c576020610496612a9e565b6040519015158152f35b503461016c5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c5760ff60406020926004358152602b8452205416604051908152f35b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c5760195461052681611db7565b916105346040519384611a0b565b818352601981527f944998273e477b495144fb8794c914197f3ccb46be2900f4698fd0ef743c9695602084015b83831061057e576040516020808252819061041590820188611bf1565b60016020819261058d85611a4c565b815201920192019190610561565b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c57601c546105d681611db7565b916105e46040519384611a0b565b818352601c81527f0e4562a10381dec21b205ed72637e6b1b523bdd0e4d4d50af5cd23dd4500a211602084015b83831061062657604051806104158782611d06565b60026020600192604051610639816119a5565b73ffffffffffffffffffffffffffffffffffffffff865416815261065e8587016121fe565b83820152815201920192019190610611565b503461016c5761016961068236611b6e565b906128cf565b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c57601d546106c381611db7565b916106d16040519384611a0b565b818352601d81527f6d4407e7be21f808e6509aa9fa9143369579dd7d760fe20a2c09680fc146134f602084015b83831061071357604051806104158782611d06565b60026020600192604051610726816119a5565b73ffffffffffffffffffffffffffffffffffffffff865416815261074b8587016121fe565b838201528152019201920191906106fe565b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c57601a5461079881611db7565b916107a66040519384611a0b565b818352601a81527f057c384a7d1c54f3a1b2e5e67b2617b8224fdfd1ea7234eea573a6ff665ff63e602084015b8383106107f0576040516020808252819061041590820188611bf1565b6001602081926107ff85611a4c565b8152019201920191906107d3565b503461016c5760c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c576084358015158103610bbc5760a4358015158103610bb8576003600435066003811015610b85576023015473ffffffffffffffffffffffffffffffffffffffff169115610bb2576003602435066003811015610b85576026015473ffffffffffffffffffffffffffffffffffffffff165b6001604435166002811015610b585773ffffffffffffffffffffffffffffffffffffffff85916029015416926108ec62278d00610168606435613b7d565b9060409583808861096b61099d82516109058482611a0b565b600c81527f426f756e6420726573756c7400000000000000000000000000000000000000006020820152835192839160208301957fb60e72cc00000000000000000000000000000000000000000000000000000000875260248401526064830190611b2b565b896044830152037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282611a0b565b51906a636f6e736f6c652e6c6f675afa50737109709ecfa91a80626ff3989d68f67f5b1dd12d3b15610b4a578651907fca669fa70000000000000000000000000000000000000000000000000000000082526004820152838160248183737109709ecfa91a80626ff3989d68f67f5b1dd12d5af18015610b4e57610b2e575b509273ffffffffffffffffffffffffffffffffffffffff9260c49284602096610a4d82601f5460081c1693426128c2565b9015610b27578160225416905b8a51998a9889977f415288120000000000000000000000000000000000000000000000000000000089521660048801526024870152604486015260a060648601528360a48601521660848401525af1839181610aef575b50610aba578280f35b8252602b60205281207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0081541690555f808280f35b9091506020813d602011610b1f575b81610b0b60209383611a0b565b81010312610b1b5751905f610ab1565b5f80fd5b3d9150610afe565b8390610a5a565b92610b3d818096939495611a0b565b610b4a579291905f610a1c565b8380fd5b87513d86823e3d90fd5b6024857f4e487b710000000000000000000000000000000000000000000000000000000081526032600452fd5b6024847f4e487b710000000000000000000000000000000000000000000000000000000081526032600452fd5b826108ae565b8280fd5b5080fd5b503461016c57610169610bd236611c67565b91612678565b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c576020602c54604051908152f35b503461016c57610169610c2636611b6e565b906124d9565b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c57601b54610c6781611db7565b610c746040519182611a0b565b818152601b83526020810191837f3ad8aa4f87544323a9d1e5dd902f40c356527a7955687113db5f9a85ad579dc1845b838310610d4c57868587604051928392602084019060208552518091526040840160408260051b8601019392905b828210610ce157505050500390f35b91936020610d3c827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0600195979984950301865288519083610d2c8351604084526040840190611b2b565b9201519084818403910152611cb1565b9601920192018594939192610cd2565b60026020600192604051610d5f816119a5565b610d6886611a4c565b8152610d758587016121fe565b83820152815201920192019190610ca4565b503461016c5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c57610169600435612106565b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c576020602e54604051908152f35b503461016c57610169610e1036611c67565b91611dfc565b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c5760405180916020601754928381520191601782527fc624b66cc0138b8fabc209247f72d758e1cf3343756d543badbf24212bed8c15915b818110610e93576104158561040981870382611a0b565b825473ffffffffffffffffffffffffffffffffffffffff16845260209093019260019283019201610e7c565b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c5760405180916020601854928381520191601882527fb13d2d76d1f4b7be834882e410b3e3a8afaf69f83600ae24db354391d2378d2e915b818110610f3c576104158561040981870382611a0b565b825473ffffffffffffffffffffffffffffffffffffffff16845260209093019260019283019201610f25565b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c57601e54610fa381611db7565b610fb06040519182611a0b565b818152601e83526020810191837f50bb669a95c7b50b7e8a6f09454034b2b14cf2b85c730dca9a539ca82cb6e350845b83831061108f57868587604051928392602084019060208552518091526040840160408260051b8601019392905b82821061101d57505050500390f35b9193602061107f827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc060019597998495030186526040838a5173ffffffffffffffffffffffffffffffffffffffff815116845201519181858201520190611bf1565b960192019201859493919261100e565b60405161109b816119a5565b73ffffffffffffffffffffffffffffffffffffffff83541681526001830180546110c481611db7565b916110d26040519384611a0b565b8183528a526020808b20908b9084015b838210611108575050505060019282602092836002950152815201920192019190610fe0565b60016020819261111786611a4c565b8152019301910190916110e2565b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c5760405180916020601654928381520191601682527fd833147d7dc355ba459fc788f669e58cfaf9dc25ddcd0702e87d69c7b5124289915b8181106111a2576104158561040981870382611a0b565b825473ffffffffffffffffffffffffffffffffffffffff1684526020909301926001928301920161118b565b5034610b1b575f906111ec6127106111e536611b6e565b9490613b7d565b916040905f8083516111fe8582611a0b565b600c81527f426f756e6420726573756c7400000000000000000000000000000000000000006020820152845161129b8161126960208201947fb60e72cc0000000000000000000000000000000000000000000000000000000086528960248401526064830190611b2b565b8a6044830152037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282611a0b565b51906a636f6e736f6c652e6c6f675afa50836127100361271081116117d5575f6112c492613b7d565b5f8083516112d28582611a0b565b600c81527f426f756e6420726573756c7400000000000000000000000000000000000000006020820152845161133d816102b260208201947fb60e72cc0000000000000000000000000000000000000000000000000000000086528960248401526064830190611b2b565b51906a636f6e736f6c652e6c6f675afa5073ffffffffffffffffffffffffffffffffffffffff60215416737109709ecfa91a80626ff3989d68f67f5b1dd12d3b15610b1b578251907f06447d5600000000000000000000000000000000000000000000000000000000825260048201525f8160248183737109709ecfa91a80626ff3989d68f67f5b1dd12d5af180156117cb576117b6575b5073ffffffffffffffffffffffffffffffffffffffff601f5460081c16803b15610b4a5783809160248551809481937f84f150900000000000000000000000000000000000000000000000000000000083528160048401525af1801561171e579084916117a1575b505073ffffffffffffffffffffffffffffffffffffffff601f5460081c168251946114688487611a0b565b600886527f747265617375727900000000000000000000000000000000000000000000000060208701528351855b6008811061178c5750958686602881990152600881526114b7602882611a0b565b602081519101208551907fffa186490000000000000000000000000000000000000000000000000000000082526004820152602081602481737109709ecfa91a80626ff3989d68f67f5b1dd12d5afa908115611744578791611752575b50737109709ecfa91a80626ff3989d68f67f5b1dd12d3b1561174e578673ffffffffffffffffffffffffffffffffffffffff61158c92885193849283927fc657c71800000000000000000000000000000000000000000000000000000000845216958660048401528a60248401526044830190611b2b565b038183737109709ecfa91a80626ff3989d68f67f5b1dd12d5af180156117445790879161172f575b5050823b1561172b576044869283875195869485937fb4d884f6000000000000000000000000000000000000000000000000000000008552600485015260248401525af1801561171e57908491611709575b505073ffffffffffffffffffffffffffffffffffffffff601f5460081c1690813b1561170457839160248392855194859384927f84f1509000000000000000000000000000000000000000000000000000000000845260048401525af180156116f8579083916116e3575b5050737109709ecfa91a80626ff3989d68f67f5b1dd12d3b156116e0578051907f90c5013b000000000000000000000000000000000000000000000000000000008252828260048183737109709ecfa91a80626ff3989d68f67f5b1dd12d5af190811561037f575061036e5750f35b50fd5b816116ed91611a0b565b6116e057815f611671565b505051903d90823e3d90fd5b505050fd5b8161171391611a0b565b61038857825f611606565b50505051903d90823e3d90fd5b8580fd5b8161173991611a0b565b61172b57855f6115b4565b86513d89823e3d90fd5b8680fd5b90506020813d602011611784575b8161176d60209383611a0b565b8101031261174e5761177e906130cc565b5f611514565b3d9150611760565b80602080928a01015182828501015201611496565b816117ab91611a0b565b610bb857825f61143d565b6117c39193505f90611a0b565b5f915f6113d5565b83513d5f823e3d90fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b34610b1b575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610b1b576040515f60305461184081611954565b80845290600181169081156118da575060011461187c575b6104158361186881850382611a0b565b604051918291602083526020830190611b2b565b60305f9081527f6ff97a59c90d62cc7236ba3a37cd85351bf564556780cf8c1157a220f31f0cbb939250905b8082106118c057509091508101602001611868611858565b9192600181602092548385880101520191019092916118a8565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660208086019190915291151560051b840190910191506118689050611858565b34610b1b575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610b1b57602090602d548152f35b90600182811c9216801561199b575b602083101461196e57565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b91607f1691611963565b6040810190811067ffffffffffffffff8211176119c157604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b610100810190811067ffffffffffffffff8211176119c157604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176119c157604052565b9060405191825f825492611a5f84611954565b8084529360018116908115611aca5750600114611a86575b50611a8492500383611a0b565b565b90505f9291925260205f20905f915b818310611aae575050906020611a84928201015f611a77565b6020919350806001915483858901015201910190918492611a95565b60209350611a849592507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091501682840152151560051b8201015f611a77565b5f5b838110611b1b5750505f910152565b8181015183820152602001611b0c565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602093611b6781518092818752878088019101611b0a565b0116010190565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6040910112610b1b576004359060243590565b60206040818301928281528451809452019201905f5b818110611bc55750505090565b825173ffffffffffffffffffffffffffffffffffffffff16845260209384019390920191600101611bb8565b9080602083519182815201916020808360051b8301019401925f915b838310611c1c57505050505090565b9091929394602080611c58837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe086600196030187528951611b2b565b97019301930191939290611c0d565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6060910112610b1b57600435906024358015158103610b1b57906044358015158103610b1b5790565b90602080835192838152019201905f5b818110611cce5750505090565b82517fffffffff0000000000000000000000000000000000000000000000000000000016845260209384019390920191600101611cc1565b602081016020825282518091526040820191602060408360051b8301019401925f915b838310611d3857505050505090565b9091929394602080611d9b837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc086600196030187526040838b5173ffffffffffffffffffffffffffffffffffffffff815116845201519181858201520190611cb1565b97019301930191939290611d29565b919082039182116117d557565b67ffffffffffffffff81116119c15760051b60200190565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146117d55760010190565b90919082806120fd575b5f93156120ec57611e15613090565b50611e1f8261387b565b9281156120d7575b5091905b82156120d05783156120a1575060208101519060068210156120745773ffffffffffffffffffffffffffffffffffffffff9161206a5760800151165b925b815f52602b60205260ff60405f20541693737109709ecfa91a80626ff3989d68f67f5b1dd12d3b15610b1b5773ffffffffffffffffffffffffffffffffffffffff604051917fca669fa70000000000000000000000000000000000000000000000000000000083521660048201525f8160248183737109709ecfa91a80626ff3989d68f67f5b1dd12d5af1801561205f5761204c575b5073ffffffffffffffffffffffffffffffffffffffff601f5460081c16803b15610bbc57818080926084604051809581937f41dd26f5000000000000000000000000000000000000000000000000000000008352896004840152816024840152606060448401528160648401525af19182612037575b5050611f82575b50505050565b611f9192611fca575b50613550565b60018114908115611fbf575b50611fac575b5f808080611f7c565b611fb7602e54611dcf565b602e55611fa3565b60029150145f611f9d565b50612031604051611fdc606082611a0b565b602181527f72656a6563742073756363656564656420776974682077726f6e67206163746f60208201527f7200000000000000000000000000000000000000000000000000000000000000604082015261333e565b5f611f8b565b8161204191611a0b565b610bbc57815f611f75565b61205891505f90611a0b565b5f80611eff565b6040513d5f823e3d90fd5b6040015116611e67565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b73ffffffffffffffffffffffffffffffffffffffff9190156120c95760800151165b92611e69565b51166120c3565b5050505050565b90506120e49192506139fc565b91905f611e27565b906120f690613225565b9091611e2b565b82159350611e06565b61210e613090565b506121188161387b565b509081156121ed575b5080156121ea57805f52602b60205260ff60405f2054169073ffffffffffffffffffffffffffffffffffffffff601f5460081c16803b15610b1b575f80916024604051809481937f5b7baf640000000000000000000000000000000000000000000000000000000083528760048401525af190816121da575b506121a3575050565b6121ac90613550565b600181149081156121cf575b506121bf57565b6121ca602e54611dcf565b602e55565b60029150145f6121b8565b5f6121e491611a0b565b5f61219a565b50565b6121f791506139fc565b505f612121565b90604051918281549182825260208201905f5260205f20925f905b80600783011061241557611a849454918181106123df575b8181106123a9575b818110612373575b81811061233d575b818110612307575b8181106122d1575b81811061229c575b1061226f575b500383611a0b565b7fffffffff000000000000000000000000000000000000000000000000000000001681526020015f612267565b9260206001917fffffffff0000000000000000000000000000000000000000000000000000000085831b168152019301612261565b9260206001917fffffffff000000000000000000000000000000000000000000000000000000008560401b168152019301612259565b9260206001917fffffffff000000000000000000000000000000000000000000000000000000008560601b168152019301612251565b9260206001917fffffffff000000000000000000000000000000000000000000000000000000008560801b168152019301612249565b9260206001917fffffffff000000000000000000000000000000000000000000000000000000008560a01b168152019301612241565b9260206001917fffffffff000000000000000000000000000000000000000000000000000000008560c01b168152019301612239565b9260206001917fffffffff000000000000000000000000000000000000000000000000000000008560e01b168152019301612231565b9160089193506101006001917fffffffff000000000000000000000000000000000000000000000000000000008754818160e01b168352818160c01b166020840152818160a01b166040840152818160801b166060840152818160601b166080840152818160401b1660a0840152818160201b1660c08401521660e0820152019401920185929391612219565b81156124ac570690565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b6124e290613225565b90915f918315611f7c575173ffffffffffffffffffffffffffffffffffffffff16737109709ecfa91a80626ff3989d68f67f5b1dd12d3b15610b1b57604051907fca669fa700000000000000000000000000000000000000000000000000000000825260048201525f8160248183737109709ecfa91a80626ff3989d68f67f5b1dd12d5af1801561205f57612663575b50600373ffffffffffffffffffffffffffffffffffffffff601f5460081c1691066003811015612636576026015473ffffffffffffffffffffffffffffffffffffffff16813b15610bb85782916084839260405195869384927fc9a84bb90000000000000000000000000000000000000000000000000000000084528960048501526024840152606060448401528160648401525af19182612621575b50506126185750565b611a8490613550565b61262c828092611a0b565b61016c578061260f565b6024837f4e487b710000000000000000000000000000000000000000000000000000000081526032600452fd5b6126709192505f90611a0b565b5f905f612572565b5f91156128b15761268890613225565b9190915b8215611f7c57838015612899575b1561287c5773ffffffffffffffffffffffffffffffffffffffff6040820151165b737109709ecfa91a80626ff3989d68f67f5b1dd12d3b15610b1b5773ffffffffffffffffffffffffffffffffffffffff604051917fca669fa70000000000000000000000000000000000000000000000000000000083521660048201525f8160248183737109709ecfa91a80626ff3989d68f67f5b1dd12d5af1801561205f57612867575b5060c073ffffffffffffffffffffffffffffffffffffffff601f5460081c16910151813b15610bb8576040517fd2e13f50000000000000000000000000000000000000000000000000000000008152600481018590526024810191909152606060448201525f606482015290829081908390608490829084905af19182612852575b50506127cd57505050565b6127db926127eb5750613550565b6127e6602c54611dcf565b602c55565b506120316040516127fd606082611a0b565b602681527f66756e642073756363656564656420776974682077726f6e672073746174757360208201527f2f6163746f720000000000000000000000000000000000000000000000000000604082015261333e565b8161285c91611a0b565b610bbc57815f6127c2565b6128749192505f90611a0b565b5f905f612740565b73ffffffffffffffffffffffffffffffffffffffff8151166126bb565b9350602081015160068110156120745715159361269a565b6128ba906136e4565b91909161268c565b919082018092116117d557565b6128d890613225565b5f929192918315611f7c57633b9aca005f6128f292613b7d565b73ffffffffffffffffffffffffffffffffffffffff604080935f8083516129198582611a0b565b600c81527f426f756e6420726573756c740000000000000000000000000000000000000000602082015284516129848161126960208201947fb60e72cc0000000000000000000000000000000000000000000000000000000086528960248401526064830190611b2b565b51906a636f6e736f6c652e6c6f675afa50015116737109709ecfa91a80626ff3989d68f67f5b1dd12d3b15610b1b578251907fca669fa700000000000000000000000000000000000000000000000000000000825260048201525f8160248183737109709ecfa91a80626ff3989d68f67f5b1dd12d5af180156117cb57612a89575b5073ffffffffffffffffffffffffffffffffffffffff601f5460081c1691823b15610b4a57517fdd4ae9d4000000000000000000000000000000000000000000000000000000008152600481018590526024810191909152606060448201525f6064820152919081908390608490829084905af191826126215750506126185750565b612a969193505f90611a0b565b5f915f612a06565b60085460ff168015612aad5790565b506040517f667f9d70000000000000000000000000000000000000000000000000000000008152737109709ecfa91a80626ff3989d68f67f5b1dd12d60048201527f6661696c656400000000000000000000000000000000000000000000000000006024820152602081604481737109709ecfa91a80626ff3989d68f67f5b1dd12d5afa90811561205f575f91612b45575b50151590565b90506020813d602011612b6f575b81612b6060209383611a0b565b81010312610b1b57515f612b3f565b3d9150612b53565b5f9115612d8357612b8790613225565b9190915b8215611f7c57838015612d65575b73ffffffffffffffffffffffffffffffffffffffff919015612d5b5751165b737109709ecfa91a80626ff3989d68f67f5b1dd12d3b15610b1b5773ffffffffffffffffffffffffffffffffffffffff604051917fca669fa70000000000000000000000000000000000000000000000000000000083521660048201525f8160248183737109709ecfa91a80626ff3989d68f67f5b1dd12d5af1801561205f57612d48575b5073ffffffffffffffffffffffffffffffffffffffff601f5460081c16803b15610bbc57818080926084604051809581937f9e63798d000000000000000000000000000000000000000000000000000000008352896004840152816024840152606060448401528160648401525af19182612d33575b5050612cbe57505050565b611a8492612ccc5750613550565b50612031604051612cde606082611a0b565b602881527f7375626d69742073756363656564656420776974682077726f6e67207374617460208201527f75732f6163746f72000000000000000000000000000000000000000000000000604082015261333e565b81612d3d91611a0b565b610bbc57815f612cb3565b612d5491505f90611a0b565b5f80612c3d565b6040015116612bb8565b93506020810151906006821015612074576001919091141593612b99565b612d8c9061387b565b919091612b8b565b5f9115612fb057612da490613225565b9190915b8215611f7c57838015612f92575b73ffffffffffffffffffffffffffffffffffffffff919015612f885751165b737109709ecfa91a80626ff3989d68f67f5b1dd12d3b15610b1b5773ffffffffffffffffffffffffffffffffffffffff604051917fca669fa70000000000000000000000000000000000000000000000000000000083521660048201525f8160248183737109709ecfa91a80626ff3989d68f67f5b1dd12d5af1801561205f57612f75575b5073ffffffffffffffffffffffffffffffffffffffff601f5460081c16803b15610bbc57818080926084604051809581937fd75bbdf3000000000000000000000000000000000000000000000000000000008352896004840152816024840152606060448401528160648401525af19182612f60575b5050612edb57505050565b612ee992612ef95750613550565b612ef4602d54611dcf565b602d55565b50612031604051612f0b606082611a0b565b602a81527f636f6d706c6574652073756363656564656420776974682077726f6e6720737460208201527f617475732f6163746f7200000000000000000000000000000000000000000000604082015261333e565b81612f6a91611a0b565b610bbc57815f612ed0565b612f8191505f90611a0b565b5f80612e5a565b6080015116612dd5565b93506020810151906006821015612074576002919091141593612db6565b612fb9906139fc565b919091612da8565b906001612fcd92613b7d565b905f80604051612fde604082611a0b565b600c81527f426f756e6420726573756c740000000000000000000000000000000000000000602082015260405161307d8161304b60208201947fb60e72cc000000000000000000000000000000000000000000000000000000008652604060248401526064830190611b2b565b886044830152037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282611a0b565b51906a636f6e736f6c652e6c6f675afa50565b6040519061309d826119ee565b606060e0835f81525f60208201525f60408201525f838201525f60808201525f60a08201525f60c08201520152565b519073ffffffffffffffffffffffffffffffffffffffff82168203610b1b57565b602081830312610b1b5780519067ffffffffffffffff8211610b1b57019061010082820312610b1b5760405191613123836119ee565b61312c816130cc565b835260208101516006811015610b1b57602084015261314d604082016130cc565b6040840152606081015165ffffffffffff81168103610b1b576060840152613177608082016130cc565b608084015261318860a082016130cc565b60a084015260c081015160c084015260e08101519067ffffffffffffffff8211610b1b570181601f82011215610b1b57805167ffffffffffffffff81116119c157604051926131ff601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200185611a0b565b81845260208284010111610b1b5761321d9160208085019101611b0a565b60e082015290565b9061322e613090565b73ffffffffffffffffffffffffffffffffffffffff601f5460081c1692604051917f50355d76000000000000000000000000000000000000000000000000000000008352602083600481885afa92831561205f575f9361330a575b508215613301575061329e6024925f92612fc1565b93604051928380927fbf22c4570000000000000000000000000000000000000000000000000000000082528760048301525afa90811561205f575f916132e2575090565b6132fe91503d805f833e6132f68183611a0b565b8101906130ed565b90565b935050505f9190565b9092506020813d602011613336575b8161332660209383611a0b565b81010312610b1b5751915f613289565b3d9150613319565b90602f5460ff81161561335057509050565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117602f55815167ffffffffffffffff81116119c157613394603054611954565b601f81116134af575b50602092601f82116001146133f657928192935f926133eb575b50507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c191617603055565b015190505f806133b7565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082169360305f527f6ff97a59c90d62cc7236ba3a37cd85351bf564556780cf8c1157a220f31f0cbb915f5b8681106134975750836001959610613460575b505050811b01603055565b01517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c191690555f8080613455565b91926020600181928685015181550194019201613442565b60305f52601f820160051c7f6ff97a59c90d62cc7236ba3a37cd85351bf564556780cf8c1157a220f31f0cbb019060208310613528575b601f0160051c7f6ff97a59c90d62cc7236ba3a37cd85351bf564556780cf8c1157a220f31f0cbb01905b81811061351d575061339d565b5f8155600101613510565b7f6ff97a59c90d62cc7236ba3a37cd85351bf564556780cf8c1157a220f31f0cbb91506134e6565b805f52602b60205260ff60405f2054169060245f73ffffffffffffffffffffffffffffffffffffffff601f5460081c16604051928380927fbf22c4570000000000000000000000000000000000000000000000000000000082528660048301525afa801561205f576020915f916136ca575b5001519160068310156120745782600382106136785750506136406040516135eb606082611a0b565b602281527f616374696f6e20737563636565646564206f6e2061207465726d696e616c206a60208201527f6f62000000000000000000000000000000000000000000000000000000000000604082015261333e565b5f52602b60205260ff60405f2091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055565b61368191613d55565b613640576136c5604051613696604082611a0b565b601981527f696c6c6567616c20737461747573207472616e736974696f6e00000000000000602082015261333e565b613640565b6136de91503d805f833e6132f68183611a0b565b5f6135c2565b906136ed613090565b9173ffffffffffffffffffffffffffffffffffffffff601f5460081c1690604051907f50355d76000000000000000000000000000000000000000000000000000000008252602082600481865afa91821561205f575f92613847575b50811561383f578161375a91612fc1565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101908111915f5b8181106137945750505050505f9190565b836117d5576137ac826137a783866128c2565b6124a2565b600181018091116117d557604051907fbf22c4570000000000000000000000000000000000000000000000000000000082528060048301525f826024818a5afa91821561205f575f92613823575b50602082015160068110156120745715613818575050600101613783565b975095945050505050565b6138389192503d805f833e6132f68183611a0b565b905f6137fa565b5050505f9190565b9091506020813d602011613873575b8161386360209383611a0b565b81010312610b1b5751905f613749565b3d9150613856565b90613884613090565b9173ffffffffffffffffffffffffffffffffffffffff601f5460081c1690604051907f50355d76000000000000000000000000000000000000000000000000000000008252602082600481865afa91821561205f575f926139c8575b50811561383f57816138f191612fc1565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101908111915f5b81811061392b5750505050505f9190565b836117d55761393e826137a783866128c2565b600181018091116117d557604051907fbf22c4570000000000000000000000000000000000000000000000000000000082528060048301525f826024818a5afa91821561205f575f926139ac575b50602082015160068110156120745760011461381857505060010161391a565b6139c19192503d805f833e6132f68183611a0b565b905f61398c565b9091506020813d6020116139f4575b816139e460209383611a0b565b81010312610b1b5751905f6138e0565b3d91506139d7565b90613a05613090565b9173ffffffffffffffffffffffffffffffffffffffff601f5460081c1690604051907f50355d76000000000000000000000000000000000000000000000000000000008252602082600481865afa91821561205f575f92613b49575b50811561383f5781613a7291612fc1565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101908111915f5b818110613aac5750505050505f9190565b836117d557613abf826137a783866128c2565b600181018091116117d557604051907fbf22c4570000000000000000000000000000000000000000000000000000000082528060048301525f826024818a5afa91821561205f575f92613b2d575b506020820151600681101561207457600214613818575050600101613a9b565b613b429192503d805f833e6132f68183611a0b565b905f613b0d565b9091506020813d602011613b75575b81613b6560209383611a0b565b81010312610b1b5751905f613a61565b3d9150613b58565b5f90838311613cd15782811091821580613cc7575b613cbf57613ba08486611daa565b92600184018094116117d557600383111580613cb6575b613ca7577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc83101580613c9d575b613c8c5785831115613c44575050906137a784613c0193611daa565b908115613c3f57613c1292506128c2565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81019081116117d55790565b505090565b959492919095613c545750505050565b839495506137a790613c669394611daa565b908115613c3f57613c779250611daa565b600181018091116117d557905f808080611f7c565b505090506132fe9291501990611daa565b5082198411613be5565b50509190506132fe92506128c2565b50828411613bb7565b509250505090565b5084821115613b92565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603e60248201527f5374645574696c7320626f756e642875696e743235362c75696e743235362c7560448201527f696e74323536293a204d6178206973206c657373207468616e206d696e2e00006064820152fd5b60ff168015613db75760018114613d9e57600214613d7257505f90565b60ff1660038114908115613d93575b8115613d8b575090565b600591501490565b600481149150613d81565b5060ff1660028114908115613d93578115613d8b575090565b5060ff168015908115613dd5575b8115613d93578115613d8b575090565b600181149150613dc556fea264697066735822122087a51d10e0458fb317219be7eb23f08edb70a540fa5ddaaf1fe23542f4215bae64736f6c634300081a00330000000000000000000000007109709ecfa91a80626ff3989d68f67f5b1dd12d000000000000000000000000f62849f9a0b5bf2913b396098f7c7019b51a820a0000000000000000000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f000000000000000000000000aa10a84ce7d9ae517a52c6d5ca153b369af99ecf0000000000000000000000005991a2df15a8f6a256d3ec51e99254cd3fb576a9","output":"0x6080806040526004361015610012575f80fd5b5f905f3560e01c90816305e3769c1461191c57508063087320b2146118025780630b78f9c0146111ce5780631ed7831c146111255780632ade388014610f685780633e5e3c2314610ebf5780633f7286f414610e16578063531c7faa14610dfe57806359e1361914610dc25780635b7baf6414610d8757806366d9a9a014610c2c578063725cc2e114610c145780637f974c6f14610bd857806381ede1bb14610bc05780638253f2d91461080d57806385226c811461075d578063916a17c6146106885780639675dc1714610670578063b0464fdc1461059b578063b5508aa9146104eb578063b5c0922c146104a0578063ba414fa61461045d578063d130382514610445578063e20c9f711461038c578063e5d6bf02146101f1578063e662e387146101b0578063fa7626d41461016f5763fd61a25614610152575f80fd5b3461016c5761016961016336611c67565b91612d94565b80f35b80fd5b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c57602060ff601f54166040519015158152f35b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c57602060ff602f54166040519015158152f35b503461016c5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c57806102336202a3006001600435613b7d565b6102fb604091838084516102478682611a0b565b600c81527f426f756e6420726573756c740000000000000000000000000000000000000000602082015285516102e4816102b260208201947fb60e72cc0000000000000000000000000000000000000000000000000000000086528a60248401526064830190611b2b565b876044830152037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282611a0b565b51906a636f6e736f6c652e6c6f675afa50426128c2565b90737109709ecfa91a80626ff3989d68f67f5b1dd12d3b15610388578051917fe5d6bf020000000000000000000000000000000000000000000000000000000083526004830152828260248183737109709ecfa91a80626ff3989d68f67f5b1dd12d5af190811561037f575061036e5750f35b8161037891611a0b565b61016c5780f35b513d84823e3d90fd5b5050fd5b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c5760405180916020601554928381520191601582527f55f448fdea98c4d29eb340757ef0a66cd03dbb9538908a6a81d96026b71ec475915b818110610419576104158561040981870382611a0b565b60405191829182611ba2565b0390f35b825473ffffffffffffffffffffffffffffffffffffffff168452602090930192600192830192016103f2565b503461016c5761016961045736611c67565b91612b77565b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c576020610496612a9e565b6040519015158152f35b503461016c5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c5760ff60406020926004358152602b8452205416604051908152f35b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c5760195461052681611db7565b916105346040519384611a0b565b818352601981527f944998273e477b495144fb8794c914197f3ccb46be2900f4698fd0ef743c9695602084015b83831061057e576040516020808252819061041590820188611bf1565b60016020819261058d85611a4c565b815201920192019190610561565b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c57601c546105d681611db7565b916105e46040519384611a0b565b818352601c81527f0e4562a10381dec21b205ed72637e6b1b523bdd0e4d4d50af5cd23dd4500a211602084015b83831061062657604051806104158782611d06565b60026020600192604051610639816119a5565b73ffffffffffffffffffffffffffffffffffffffff865416815261065e8587016121fe565b83820152815201920192019190610611565b503461016c5761016961068236611b6e565b906128cf565b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c57601d546106c381611db7565b916106d16040519384611a0b565b818352601d81527f6d4407e7be21f808e6509aa9fa9143369579dd7d760fe20a2c09680fc146134f602084015b83831061071357604051806104158782611d06565b60026020600192604051610726816119a5565b73ffffffffffffffffffffffffffffffffffffffff865416815261074b8587016121fe565b838201528152019201920191906106fe565b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c57601a5461079881611db7565b916107a66040519384611a0b565b818352601a81527f057c384a7d1c54f3a1b2e5e67b2617b8224fdfd1ea7234eea573a6ff665ff63e602084015b8383106107f0576040516020808252819061041590820188611bf1565b6001602081926107ff85611a4c565b8152019201920191906107d3565b503461016c5760c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c576084358015158103610bbc5760a4358015158103610bb8576003600435066003811015610b85576023015473ffffffffffffffffffffffffffffffffffffffff169115610bb2576003602435066003811015610b85576026015473ffffffffffffffffffffffffffffffffffffffff165b6001604435166002811015610b585773ffffffffffffffffffffffffffffffffffffffff85916029015416926108ec62278d00610168606435613b7d565b9060409583808861096b61099d82516109058482611a0b565b600c81527f426f756e6420726573756c7400000000000000000000000000000000000000006020820152835192839160208301957fb60e72cc00000000000000000000000000000000000000000000000000000000875260248401526064830190611b2b565b896044830152037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282611a0b565b51906a636f6e736f6c652e6c6f675afa50737109709ecfa91a80626ff3989d68f67f5b1dd12d3b15610b4a578651907fca669fa70000000000000000000000000000000000000000000000000000000082526004820152838160248183737109709ecfa91a80626ff3989d68f67f5b1dd12d5af18015610b4e57610b2e575b509273ffffffffffffffffffffffffffffffffffffffff9260c49284602096610a4d82601f5460081c1693426128c2565b9015610b27578160225416905b8a51998a9889977f415288120000000000000000000000000000000000000000000000000000000089521660048801526024870152604486015260a060648601528360a48601521660848401525af1839181610aef575b50610aba578280f35b8252602b60205281207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0081541690555f808280f35b9091506020813d602011610b1f575b81610b0b60209383611a0b565b81010312610b1b5751905f610ab1565b5f80fd5b3d9150610afe565b8390610a5a565b92610b3d818096939495611a0b565b610b4a579291905f610a1c565b8380fd5b87513d86823e3d90fd5b6024857f4e487b710000000000000000000000000000000000000000000000000000000081526032600452fd5b6024847f4e487b710000000000000000000000000000000000000000000000000000000081526032600452fd5b826108ae565b8280fd5b5080fd5b503461016c57610169610bd236611c67565b91612678565b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c576020602c54604051908152f35b503461016c57610169610c2636611b6e565b906124d9565b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c57601b54610c6781611db7565b610c746040519182611a0b565b818152601b83526020810191837f3ad8aa4f87544323a9d1e5dd902f40c356527a7955687113db5f9a85ad579dc1845b838310610d4c57868587604051928392602084019060208552518091526040840160408260051b8601019392905b828210610ce157505050500390f35b91936020610d3c827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0600195979984950301865288519083610d2c8351604084526040840190611b2b565b9201519084818403910152611cb1565b9601920192018594939192610cd2565b60026020600192604051610d5f816119a5565b610d6886611a4c565b8152610d758587016121fe565b83820152815201920192019190610ca4565b503461016c5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c57610169600435612106565b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c576020602e54604051908152f35b503461016c57610169610e1036611c67565b91611dfc565b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c5760405180916020601754928381520191601782527fc624b66cc0138b8fabc209247f72d758e1cf3343756d543badbf24212bed8c15915b818110610e93576104158561040981870382611a0b565b825473ffffffffffffffffffffffffffffffffffffffff16845260209093019260019283019201610e7c565b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c5760405180916020601854928381520191601882527fb13d2d76d1f4b7be834882e410b3e3a8afaf69f83600ae24db354391d2378d2e915b818110610f3c576104158561040981870382611a0b565b825473ffffffffffffffffffffffffffffffffffffffff16845260209093019260019283019201610f25565b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c57601e54610fa381611db7565b610fb06040519182611a0b565b818152601e83526020810191837f50bb669a95c7b50b7e8a6f09454034b2b14cf2b85c730dca9a539ca82cb6e350845b83831061108f57868587604051928392602084019060208552518091526040840160408260051b8601019392905b82821061101d57505050500390f35b9193602061107f827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc060019597998495030186526040838a5173ffffffffffffffffffffffffffffffffffffffff815116845201519181858201520190611bf1565b960192019201859493919261100e565b60405161109b816119a5565b73ffffffffffffffffffffffffffffffffffffffff83541681526001830180546110c481611db7565b916110d26040519384611a0b565b8183528a526020808b20908b9084015b838210611108575050505060019282602092836002950152815201920192019190610fe0565b60016020819261111786611a4c565b8152019301910190916110e2565b503461016c57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016c5760405180916020601654928381520191601682527fd833147d7dc355ba459fc788f669e58cfaf9dc25ddcd0702e87d69c7b5124289915b8181106111a2576104158561040981870382611a0b565b825473ffffffffffffffffffffffffffffffffffffffff1684526020909301926001928301920161118b565b5034610b1b575f906111ec6127106111e536611b6e565b9490613b7d565b916040905f8083516111fe8582611a0b565b600c81527f426f756e6420726573756c7400000000000000000000000000000000000000006020820152845161129b8161126960208201947fb60e72cc0000000000000000000000000000000000000000000000000000000086528960248401526064830190611b2b565b8a6044830152037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282611a0b565b51906a636f6e736f6c652e6c6f675afa50836127100361271081116117d5575f6112c492613b7d565b5f8083516112d28582611a0b565b600c81527f426f756e6420726573756c7400000000000000000000000000000000000000006020820152845161133d816102b260208201947fb60e72cc0000000000000000000000000000000000000000000000000000000086528960248401526064830190611b2b565b51906a636f6e736f6c652e6c6f675afa5073ffffffffffffffffffffffffffffffffffffffff60215416737109709ecfa91a80626ff3989d68f67f5b1dd12d3b15610b1b578251907f06447d5600000000000000000000000000000000000000000000000000000000825260048201525f8160248183737109709ecfa91a80626ff3989d68f67f5b1dd12d5af180156117cb576117b6575b5073ffffffffffffffffffffffffffffffffffffffff601f5460081c16803b15610b4a5783809160248551809481937f84f150900000000000000000000000000000000000000000000000000000000083528160048401525af1801561171e579084916117a1575b505073ffffffffffffffffffffffffffffffffffffffff601f5460081c168251946114688487611a0b565b600886527f747265617375727900000000000000000000000000000000000000000000000060208701528351855b6008811061178c5750958686602881990152600881526114b7602882611a0b565b602081519101208551907fffa186490000000000000000000000000000000000000000000000000000000082526004820152602081602481737109709ecfa91a80626ff3989d68f67f5b1dd12d5afa908115611744578791611752575b50737109709ecfa91a80626ff3989d68f67f5b1dd12d3b1561174e578673ffffffffffffffffffffffffffffffffffffffff61158c92885193849283927fc657c71800000000000000000000000000000000000000000000000000000000845216958660048401528a60248401526044830190611b2b565b038183737109709ecfa91a80626ff3989d68f67f5b1dd12d5af180156117445790879161172f575b5050823b1561172b576044869283875195869485937fb4d884f6000000000000000000000000000000000000000000000000000000008552600485015260248401525af1801561171e57908491611709575b505073ffffffffffffffffffffffffffffffffffffffff601f5460081c1690813b1561170457839160248392855194859384927f84f1509000000000000000000000000000000000000000000000000000000000845260048401525af180156116f8579083916116e3575b5050737109709ecfa91a80626ff3989d68f67f5b1dd12d3b156116e0578051907f90c5013b000000000000000000000000000000000000000000000000000000008252828260048183737109709ecfa91a80626ff3989d68f67f5b1dd12d5af190811561037f575061036e5750f35b50fd5b816116ed91611a0b565b6116e057815f611671565b505051903d90823e3d90fd5b505050fd5b8161171391611a0b565b61038857825f611606565b50505051903d90823e3d90fd5b8580fd5b8161173991611a0b565b61172b57855f6115b4565b86513d89823e3d90fd5b8680fd5b90506020813d602011611784575b8161176d60209383611a0b565b8101031261174e5761177e906130cc565b5f611514565b3d9150611760565b80602080928a01015182828501015201611496565b816117ab91611a0b565b610bb857825f61143d565b6117c39193505f90611a0b565b5f915f6113d5565b83513d5f823e3d90fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b34610b1b575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610b1b576040515f60305461184081611954565b80845290600181169081156118da575060011461187c575b6104158361186881850382611a0b565b604051918291602083526020830190611b2b565b60305f9081527f6ff97a59c90d62cc7236ba3a37cd85351bf564556780cf8c1157a220f31f0cbb939250905b8082106118c057509091508101602001611868611858565b9192600181602092548385880101520191019092916118a8565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660208086019190915291151560051b840190910191506118689050611858565b34610b1b575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610b1b57602090602d548152f35b90600182811c9216801561199b575b602083101461196e57565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b91607f1691611963565b6040810190811067ffffffffffffffff8211176119c157604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b610100810190811067ffffffffffffffff8211176119c157604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176119c157604052565b9060405191825f825492611a5f84611954565b8084529360018116908115611aca5750600114611a86575b50611a8492500383611a0b565b565b90505f9291925260205f20905f915b818310611aae575050906020611a84928201015f611a77565b6020919350806001915483858901015201910190918492611a95565b60209350611a849592507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091501682840152151560051b8201015f611a77565b5f5b838110611b1b5750505f910152565b8181015183820152602001611b0c565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602093611b6781518092818752878088019101611b0a565b0116010190565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6040910112610b1b576004359060243590565b60206040818301928281528451809452019201905f5b818110611bc55750505090565b825173ffffffffffffffffffffffffffffffffffffffff16845260209384019390920191600101611bb8565b9080602083519182815201916020808360051b8301019401925f915b838310611c1c57505050505090565b9091929394602080611c58837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe086600196030187528951611b2b565b97019301930191939290611c0d565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6060910112610b1b57600435906024358015158103610b1b57906044358015158103610b1b5790565b90602080835192838152019201905f5b818110611cce5750505090565b82517fffffffff0000000000000000000000000000000000000000000000000000000016845260209384019390920191600101611cc1565b602081016020825282518091526040820191602060408360051b8301019401925f915b838310611d3857505050505090565b9091929394602080611d9b837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc086600196030187526040838b5173ffffffffffffffffffffffffffffffffffffffff815116845201519181858201520190611cb1565b97019301930191939290611d29565b919082039182116117d557565b67ffffffffffffffff81116119c15760051b60200190565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146117d55760010190565b90919082806120fd575b5f93156120ec57611e15613090565b50611e1f8261387b565b9281156120d7575b5091905b82156120d05783156120a1575060208101519060068210156120745773ffffffffffffffffffffffffffffffffffffffff9161206a5760800151165b925b815f52602b60205260ff60405f20541693737109709ecfa91a80626ff3989d68f67f5b1dd12d3b15610b1b5773ffffffffffffffffffffffffffffffffffffffff604051917fca669fa70000000000000000000000000000000000000000000000000000000083521660048201525f8160248183737109709ecfa91a80626ff3989d68f67f5b1dd12d5af1801561205f5761204c575b5073ffffffffffffffffffffffffffffffffffffffff601f5460081c16803b15610bbc57818080926084604051809581937f41dd26f5000000000000000000000000000000000000000000000000000000008352896004840152816024840152606060448401528160648401525af19182612037575b5050611f82575b50505050565b611f9192611fca575b50613550565b60018114908115611fbf575b50611fac575b5f808080611f7c565b611fb7602e54611dcf565b602e55611fa3565b60029150145f611f9d565b50612031604051611fdc606082611a0b565b602181527f72656a6563742073756363656564656420776974682077726f6e67206163746f60208201527f7200000000000000000000000000000000000000000000000000000000000000604082015261333e565b5f611f8b565b8161204191611a0b565b610bbc57815f611f75565b61205891505f90611a0b565b5f80611eff565b6040513d5f823e3d90fd5b6040015116611e67565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b73ffffffffffffffffffffffffffffffffffffffff9190156120c95760800151165b92611e69565b51166120c3565b5050505050565b90506120e49192506139fc565b91905f611e27565b906120f690613225565b9091611e2b565b82159350611e06565b61210e613090565b506121188161387b565b509081156121ed575b5080156121ea57805f52602b60205260ff60405f2054169073ffffffffffffffffffffffffffffffffffffffff601f5460081c16803b15610b1b575f80916024604051809481937f5b7baf640000000000000000000000000000000000000000000000000000000083528760048401525af190816121da575b506121a3575050565b6121ac90613550565b600181149081156121cf575b506121bf57565b6121ca602e54611dcf565b602e55565b60029150145f6121b8565b5f6121e491611a0b565b5f61219a565b50565b6121f791506139fc565b505f612121565b90604051918281549182825260208201905f5260205f20925f905b80600783011061241557611a849454918181106123df575b8181106123a9575b818110612373575b81811061233d575b818110612307575b8181106122d1575b81811061229c575b1061226f575b500383611a0b565b7fffffffff000000000000000000000000000000000000000000000000000000001681526020015f612267565b9260206001917fffffffff0000000000000000000000000000000000000000000000000000000085831b168152019301612261565b9260206001917fffffffff000000000000000000000000000000000000000000000000000000008560401b168152019301612259565b9260206001917fffffffff000000000000000000000000000000000000000000000000000000008560601b168152019301612251565b9260206001917fffffffff000000000000000000000000000000000000000000000000000000008560801b168152019301612249565b9260206001917fffffffff000000000000000000000000000000000000000000000000000000008560a01b168152019301612241565b9260206001917fffffffff000000000000000000000000000000000000000000000000000000008560c01b168152019301612239565b9260206001917fffffffff000000000000000000000000000000000000000000000000000000008560e01b168152019301612231565b9160089193506101006001917fffffffff000000000000000000000000000000000000000000000000000000008754818160e01b168352818160c01b166020840152818160a01b166040840152818160801b166060840152818160601b166080840152818160401b1660a0840152818160201b1660c08401521660e0820152019401920185929391612219565b81156124ac570690565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b6124e290613225565b90915f918315611f7c575173ffffffffffffffffffffffffffffffffffffffff16737109709ecfa91a80626ff3989d68f67f5b1dd12d3b15610b1b57604051907fca669fa700000000000000000000000000000000000000000000000000000000825260048201525f8160248183737109709ecfa91a80626ff3989d68f67f5b1dd12d5af1801561205f57612663575b50600373ffffffffffffffffffffffffffffffffffffffff601f5460081c1691066003811015612636576026015473ffffffffffffffffffffffffffffffffffffffff16813b15610bb85782916084839260405195869384927fc9a84bb90000000000000000000000000000000000000000000000000000000084528960048501526024840152606060448401528160648401525af19182612621575b50506126185750565b611a8490613550565b61262c828092611a0b565b61016c578061260f565b6024837f4e487b710000000000000000000000000000000000000000000000000000000081526032600452fd5b6126709192505f90611a0b565b5f905f612572565b5f91156128b15761268890613225565b9190915b8215611f7c57838015612899575b1561287c5773ffffffffffffffffffffffffffffffffffffffff6040820151165b737109709ecfa91a80626ff3989d68f67f5b1dd12d3b15610b1b5773ffffffffffffffffffffffffffffffffffffffff604051917fca669fa70000000000000000000000000000000000000000000000000000000083521660048201525f8160248183737109709ecfa91a80626ff3989d68f67f5b1dd12d5af1801561205f57612867575b5060c073ffffffffffffffffffffffffffffffffffffffff601f5460081c16910151813b15610bb8576040517fd2e13f50000000000000000000000000000000000000000000000000000000008152600481018590526024810191909152606060448201525f606482015290829081908390608490829084905af19182612852575b50506127cd57505050565b6127db926127eb5750613550565b6127e6602c54611dcf565b602c55565b506120316040516127fd606082611a0b565b602681527f66756e642073756363656564656420776974682077726f6e672073746174757360208201527f2f6163746f720000000000000000000000000000000000000000000000000000604082015261333e565b8161285c91611a0b565b610bbc57815f6127c2565b6128749192505f90611a0b565b5f905f612740565b73ffffffffffffffffffffffffffffffffffffffff8151166126bb565b9350602081015160068110156120745715159361269a565b6128ba906136e4565b91909161268c565b919082018092116117d557565b6128d890613225565b5f929192918315611f7c57633b9aca005f6128f292613b7d565b73ffffffffffffffffffffffffffffffffffffffff604080935f8083516129198582611a0b565b600c81527f426f756e6420726573756c740000000000000000000000000000000000000000602082015284516129848161126960208201947fb60e72cc0000000000000000000000000000000000000000000000000000000086528960248401526064830190611b2b565b51906a636f6e736f6c652e6c6f675afa50015116737109709ecfa91a80626ff3989d68f67f5b1dd12d3b15610b1b578251907fca669fa700000000000000000000000000000000000000000000000000000000825260048201525f8160248183737109709ecfa91a80626ff3989d68f67f5b1dd12d5af180156117cb57612a89575b5073ffffffffffffffffffffffffffffffffffffffff601f5460081c1691823b15610b4a57517fdd4ae9d4000000000000000000000000000000000000000000000000000000008152600481018590526024810191909152606060448201525f6064820152919081908390608490829084905af191826126215750506126185750565b612a969193505f90611a0b565b5f915f612a06565b60085460ff168015612aad5790565b506040517f667f9d70000000000000000000000000000000000000000000000000000000008152737109709ecfa91a80626ff3989d68f67f5b1dd12d60048201527f6661696c656400000000000000000000000000000000000000000000000000006024820152602081604481737109709ecfa91a80626ff3989d68f67f5b1dd12d5afa90811561205f575f91612b45575b50151590565b90506020813d602011612b6f575b81612b6060209383611a0b565b81010312610b1b57515f612b3f565b3d9150612b53565b5f9115612d8357612b8790613225565b9190915b8215611f7c57838015612d65575b73ffffffffffffffffffffffffffffffffffffffff919015612d5b5751165b737109709ecfa91a80626ff3989d68f67f5b1dd12d3b15610b1b5773ffffffffffffffffffffffffffffffffffffffff604051917fca669fa70000000000000000000000000000000000000000000000000000000083521660048201525f8160248183737109709ecfa91a80626ff3989d68f67f5b1dd12d5af1801561205f57612d48575b5073ffffffffffffffffffffffffffffffffffffffff601f5460081c16803b15610bbc57818080926084604051809581937f9e63798d000000000000000000000000000000000000000000000000000000008352896004840152816024840152606060448401528160648401525af19182612d33575b5050612cbe57505050565b611a8492612ccc5750613550565b50612031604051612cde606082611a0b565b602881527f7375626d69742073756363656564656420776974682077726f6e67207374617460208201527f75732f6163746f72000000000000000000000000000000000000000000000000604082015261333e565b81612d3d91611a0b565b610bbc57815f612cb3565b612d5491505f90611a0b565b5f80612c3d565b6040015116612bb8565b93506020810151906006821015612074576001919091141593612b99565b612d8c9061387b565b919091612b8b565b5f9115612fb057612da490613225565b9190915b8215611f7c57838015612f92575b73ffffffffffffffffffffffffffffffffffffffff919015612f885751165b737109709ecfa91a80626ff3989d68f67f5b1dd12d3b15610b1b5773ffffffffffffffffffffffffffffffffffffffff604051917fca669fa70000000000000000000000000000000000000000000000000000000083521660048201525f8160248183737109709ecfa91a80626ff3989d68f67f5b1dd12d5af1801561205f57612f75575b5073ffffffffffffffffffffffffffffffffffffffff601f5460081c16803b15610bbc57818080926084604051809581937fd75bbdf3000000000000000000000000000000000000000000000000000000008352896004840152816024840152606060448401528160648401525af19182612f60575b5050612edb57505050565b612ee992612ef95750613550565b612ef4602d54611dcf565b602d55565b50612031604051612f0b606082611a0b565b602a81527f636f6d706c6574652073756363656564656420776974682077726f6e6720737460208201527f617475732f6163746f7200000000000000000000000000000000000000000000604082015261333e565b81612f6a91611a0b565b610bbc57815f612ed0565b612f8191505f90611a0b565b5f80612e5a565b6080015116612dd5565b93506020810151906006821015612074576002919091141593612db6565b612fb9906139fc565b919091612da8565b906001612fcd92613b7d565b905f80604051612fde604082611a0b565b600c81527f426f756e6420726573756c740000000000000000000000000000000000000000602082015260405161307d8161304b60208201947fb60e72cc000000000000000000000000000000000000000000000000000000008652604060248401526064830190611b2b565b886044830152037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282611a0b565b51906a636f6e736f6c652e6c6f675afa50565b6040519061309d826119ee565b606060e0835f81525f60208201525f60408201525f838201525f60808201525f60a08201525f60c08201520152565b519073ffffffffffffffffffffffffffffffffffffffff82168203610b1b57565b602081830312610b1b5780519067ffffffffffffffff8211610b1b57019061010082820312610b1b5760405191613123836119ee565b61312c816130cc565b835260208101516006811015610b1b57602084015261314d604082016130cc565b6040840152606081015165ffffffffffff81168103610b1b576060840152613177608082016130cc565b608084015261318860a082016130cc565b60a084015260c081015160c084015260e08101519067ffffffffffffffff8211610b1b570181601f82011215610b1b57805167ffffffffffffffff81116119c157604051926131ff601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200185611a0b565b81845260208284010111610b1b5761321d9160208085019101611b0a565b60e082015290565b9061322e613090565b73ffffffffffffffffffffffffffffffffffffffff601f5460081c1692604051917f50355d76000000000000000000000000000000000000000000000000000000008352602083600481885afa92831561205f575f9361330a575b508215613301575061329e6024925f92612fc1565b93604051928380927fbf22c4570000000000000000000000000000000000000000000000000000000082528760048301525afa90811561205f575f916132e2575090565b6132fe91503d805f833e6132f68183611a0b565b8101906130ed565b90565b935050505f9190565b9092506020813d602011613336575b8161332660209383611a0b565b81010312610b1b5751915f613289565b3d9150613319565b90602f5460ff81161561335057509050565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117602f55815167ffffffffffffffff81116119c157613394603054611954565b601f81116134af575b50602092601f82116001146133f657928192935f926133eb575b50507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c191617603055565b015190505f806133b7565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082169360305f527f6ff97a59c90d62cc7236ba3a37cd85351bf564556780cf8c1157a220f31f0cbb915f5b8681106134975750836001959610613460575b505050811b01603055565b01517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c191690555f8080613455565b91926020600181928685015181550194019201613442565b60305f52601f820160051c7f6ff97a59c90d62cc7236ba3a37cd85351bf564556780cf8c1157a220f31f0cbb019060208310613528575b601f0160051c7f6ff97a59c90d62cc7236ba3a37cd85351bf564556780cf8c1157a220f31f0cbb01905b81811061351d575061339d565b5f8155600101613510565b7f6ff97a59c90d62cc7236ba3a37cd85351bf564556780cf8c1157a220f31f0cbb91506134e6565b805f52602b60205260ff60405f2054169060245f73ffffffffffffffffffffffffffffffffffffffff601f5460081c16604051928380927fbf22c4570000000000000000000000000000000000000000000000000000000082528660048301525afa801561205f576020915f916136ca575b5001519160068310156120745782600382106136785750506136406040516135eb606082611a0b565b602281527f616374696f6e20737563636565646564206f6e2061207465726d696e616c206a60208201527f6f62000000000000000000000000000000000000000000000000000000000000604082015261333e565b5f52602b60205260ff60405f2091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055565b61368191613d55565b613640576136c5604051613696604082611a0b565b601981527f696c6c6567616c20737461747573207472616e736974696f6e00000000000000602082015261333e565b613640565b6136de91503d805f833e6132f68183611a0b565b5f6135c2565b906136ed613090565b9173ffffffffffffffffffffffffffffffffffffffff601f5460081c1690604051907f50355d76000000000000000000000000000000000000000000000000000000008252602082600481865afa91821561205f575f92613847575b50811561383f578161375a91612fc1565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101908111915f5b8181106137945750505050505f9190565b836117d5576137ac826137a783866128c2565b6124a2565b600181018091116117d557604051907fbf22c4570000000000000000000000000000000000000000000000000000000082528060048301525f826024818a5afa91821561205f575f92613823575b50602082015160068110156120745715613818575050600101613783565b975095945050505050565b6138389192503d805f833e6132f68183611a0b565b905f6137fa565b5050505f9190565b9091506020813d602011613873575b8161386360209383611a0b565b81010312610b1b5751905f613749565b3d9150613856565b90613884613090565b9173ffffffffffffffffffffffffffffffffffffffff601f5460081c1690604051907f50355d76000000000000000000000000000000000000000000000000000000008252602082600481865afa91821561205f575f926139c8575b50811561383f57816138f191612fc1565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101908111915f5b81811061392b5750505050505f9190565b836117d55761393e826137a783866128c2565b600181018091116117d557604051907fbf22c4570000000000000000000000000000000000000000000000000000000082528060048301525f826024818a5afa91821561205f575f926139ac575b50602082015160068110156120745760011461381857505060010161391a565b6139c19192503d805f833e6132f68183611a0b565b905f61398c565b9091506020813d6020116139f4575b816139e460209383611a0b565b81010312610b1b5751905f6138e0565b3d91506139d7565b90613a05613090565b9173ffffffffffffffffffffffffffffffffffffffff601f5460081c1690604051907f50355d76000000000000000000000000000000000000000000000000000000008252602082600481865afa91821561205f575f92613b49575b50811561383f5781613a7291612fc1565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101908111915f5b818110613aac5750505050505f9190565b836117d557613abf826137a783866128c2565b600181018091116117d557604051907fbf22c4570000000000000000000000000000000000000000000000000000000082528060048301525f826024818a5afa91821561205f575f92613b2d575b506020820151600681101561207457600214613818575050600101613a9b565b613b429192503d805f833e6132f68183611a0b565b905f613b0d565b9091506020813d602011613b75575b81613b6560209383611a0b565b81010312610b1b5751905f613a61565b3d9150613b58565b5f90838311613cd15782811091821580613cc7575b613cbf57613ba08486611daa565b92600184018094116117d557600383111580613cb6575b613ca7577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc83101580613c9d575b613c8c5785831115613c44575050906137a784613c0193611daa565b908115613c3f57613c1292506128c2565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81019081116117d55790565b505090565b959492919095613c545750505050565b839495506137a790613c669394611daa565b908115613c3f57613c779250611daa565b600181018091116117d557905f808080611f7c565b505090506132fe9291501990611daa565b5082198411613be5565b50509190506132fe92506128c2565b50828411613bb7565b509250505090565b5084821115613b92565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603e60248201527f5374645574696c7320626f756e642875696e743235362c75696e743235362c7560448201527f696e74323536293a204d6178206973206c657373207468616e206d696e2e00006064820152fd5b60ff168015613db75760018114613d9e57600214613d7257505f90565b60ff1660038114908115613d93575b8115613d8b575090565b600591501490565b600481149150613d81565b5060ff1660028114908115613d93578115613d8b575090565b5060ff168015908115613dd5575b8115613d93578115613d8b575090565b600181149150613dc556fea264697066735822122087a51d10e0458fb317219be7eb23f08edb70a540fa5ddaaf1fe23542f4215bae64736f6c634300081a0033","gas_used":4166661,"gas_limit":1051631826,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[{"Call":0},{"Call":1},{"Call":2},{"Call":3},{"Call":4},{"Call":5},{"Call":6},{"Call":7},{"Call":8},{"Call":9},{"Call":10},{"Call":11},{"Call":12},{"Call":13},{"Call":14},{"Call":15},{"Call":16},{"Call":17},{"Call":18},{"Call":19},{"Call":20},{"Call":21},{"Call":22},{"Call":23},{"Call":24},{"Call":25},{"Call":26},{"Call":27},{"Call":28},{"Call":29},{"Call":30},{"Call":31},{"Call":32},{"Call":33},{"Call":34},{"Call":35},{"Call":36},{"Call":37},{"Call":38},{"Call":39},{"Call":40},{"Call":41},{"Call":42},{"Call":43},{"Call":44},{"Call":45},{"Call":46},{"Call":47},{"Call":48}]},{"parent":14,"children":[],"idx":15,"trace":{"depth":2,"success":true,"caller":"0xc7183455a4c133ae270771860664b6b7ec320bb1","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"STATICCALL","value":"0x0","data":"0x6900a3ae0000000000000000000000000000000000000000000000000000000000000000","output":"0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000013000000000000000000000000000000000000000000000000000000000000000","gas_used":0,"gas_limit":1035090386,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":14,"children":[],"idx":16,"trace":{"depth":2,"success":true,"caller":"0xc7183455a4c133ae270771860664b6b7ec320bb1","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"STATICCALL","value":"0x0","data":"0xffa186498c4bdc5e5384c0751b1d106538f8c3789e521a3acd36826accbcfd96d5cd97b8","output":"0x000000000000000000000000e1fc4143851d3e84a40af3aac51afe019c98cda6","gas_used":0,"gas_limit":1035088799,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":14,"children":[],"idx":17,"trace":{"depth":2,"success":true,"caller":"0xc7183455a4c133ae270771860664b6b7ec320bb1","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0xc657c718000000000000000000000000e1fc4143851d3e84a40af3aac51afe019c98cda6000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000026330000000000000000000000000000000000000000000000000000000000000","output":"0x","gas_used":0,"gas_limit":1035087910,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":14,"children":[],"idx":18,"trace":{"depth":2,"success":true,"caller":"0xc7183455a4c133ae270771860664b6b7ec320bb1","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"STATICCALL","value":"0x0","data":"0x6900a3ae0000000000000000000000000000000000000000000000000000000000000000","output":"0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000013000000000000000000000000000000000000000000000000000000000000000","gas_used":0,"gas_limit":1035065743,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":14,"children":[],"idx":19,"trace":{"depth":2,"success":true,"caller":"0xc7183455a4c133ae270771860664b6b7ec320bb1","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"STATICCALL","value":"0x0","data":"0xffa18649fe1703dbe8a9115ed486af41105cac12e260e614269d85a2a0effad6af6dbdc6","output":"0x000000000000000000000000e5b9bc45c8125d133fe66fe9459486e3d5792d39","gas_used":0,"gas_limit":1035064164,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":14,"children":[],"idx":20,"trace":{"depth":2,"success":true,"caller":"0xc7183455a4c133ae270771860664b6b7ec320bb1","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0xc657c718000000000000000000000000e5b9bc45c8125d133fe66fe9459486e3d5792d39000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000027030000000000000000000000000000000000000000000000000000000000000","output":"0x","gas_used":0,"gas_limit":1035063275,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":14,"children":[],"idx":21,"trace":{"depth":2,"success":true,"caller":"0xc7183455a4c133ae270771860664b6b7ec320bb1","address":"0x5615deb798bb3e4dfa0139dfa1b3d433cc23b72f","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0x40c10f19000000000000000000000000e1fc4143851d3e84a40af3aac51afe019c98cda6000000000000000000000000000000000000000000000000000000e8d4a51000","output":"0x","gas_used":24538,"gas_limit":1035040790,"status":"Stop","steps":[],"decoded":null},"logs":[{"raw_log":{"topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x0000000000000000000000000000000000000000000000000000000000000000","0x000000000000000000000000e1fc4143851d3e84a40af3aac51afe019c98cda6"],"data":"0x000000000000000000000000000000000000000000000000000000e8d4a51000"},"decoded":null,"position":0,"index":10}],"ordering":[{"Log":0}]},{"parent":14,"children":[],"idx":22,"trace":{"depth":2,"success":true,"caller":"0xc7183455a4c133ae270771860664b6b7ec320bb1","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0xca669fa7000000000000000000000000e1fc4143851d3e84a40af3aac51afe019c98cda6","output":"0x","gas_used":0,"gas_limit":1035016029,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":14,"children":[],"idx":23,"trace":{"depth":2,"success":true,"caller":"0xc7183455a4c133ae270771860664b6b7ec320bb1","address":"0x5615deb798bb3e4dfa0139dfa1b3d433cc23b72f","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0x095ea7b3000000000000000000000000f62849f9a0b5bf2913b396098f7c7019b51a820affffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff","output":"0x0000000000000000000000000000000000000000000000000000000000000001","gas_used":24298,"gas_limit":1035015449,"status":"Return","steps":[],"decoded":null},"logs":[{"raw_log":{"topics":["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925","0x000000000000000000000000e1fc4143851d3e84a40af3aac51afe019c98cda6","0x000000000000000000000000f62849f9a0b5bf2913b396098f7c7019b51a820a"],"data":"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"},"decoded":null,"position":0,"index":11}],"ordering":[{"Log":0}]},{"parent":14,"children":[],"idx":24,"trace":{"depth":2,"success":true,"caller":"0xc7183455a4c133ae270771860664b6b7ec320bb1","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"STATICCALL","value":"0x0","data":"0x6900a3ae0000000000000000000000000000000000000000000000000000000000000001","output":"0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000013100000000000000000000000000000000000000000000000000000000000000","gas_used":0,"gas_limit":1034991060,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":14,"children":[],"idx":25,"trace":{"depth":2,"success":true,"caller":"0xc7183455a4c133ae270771860664b6b7ec320bb1","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"STATICCALL","value":"0x0","data":"0xffa186497c1b16802b304761acd81e033c1db5a9721da4b32959e4a8361983cfacacbbec","output":"0x000000000000000000000000a53e365bb7183eb60b1263706c686848492fb679","gas_used":0,"gas_limit":1034989477,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":14,"children":[],"idx":26,"trace":{"depth":2,"success":true,"caller":"0xc7183455a4c133ae270771860664b6b7ec320bb1","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0xc657c718000000000000000000000000a53e365bb7183eb60b1263706c686848492fb679000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000026331000000000000000000000000000000000000000000000000000000000000","output":"0x","gas_used":0,"gas_limit":1034988589,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":14,"children":[],"idx":27,"trace":{"depth":2,"success":true,"caller":"0xc7183455a4c133ae270771860664b6b7ec320bb1","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"STATICCALL","value":"0x0","data":"0x6900a3ae0000000000000000000000000000000000000000000000000000000000000001","output":"0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000013100000000000000000000000000000000000000000000000000000000000000","gas_used":0,"gas_limit":1034966422,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":14,"children":[],"idx":28,"trace":{"depth":2,"success":true,"caller":"0xc7183455a4c133ae270771860664b6b7ec320bb1","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"STATICCALL","value":"0x0","data":"0xffa18649260e065801cba6ca065f28640c3d94ef235f67db5431448aae1a51af7214efaf","output":"0x000000000000000000000000ab80885935d10ffc2f477636e1c5cdef234e22c3","gas_used":0,"gas_limit":1034964842,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":14,"children":[],"idx":29,"trace":{"depth":2,"success":true,"caller":"0xc7183455a4c133ae270771860664b6b7ec320bb1","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0xc657c718000000000000000000000000ab80885935d10ffc2f477636e1c5cdef234e22c3000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000027031000000000000000000000000000000000000000000000000000000000000","output":"0x","gas_used":0,"gas_limit":1034963953,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":14,"children":[],"idx":30,"trace":{"depth":2,"success":true,"caller":"0xc7183455a4c133ae270771860664b6b7ec320bb1","address":"0x5615deb798bb3e4dfa0139dfa1b3d433cc23b72f","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0x40c10f19000000000000000000000000a53e365bb7183eb60b1263706c686848492fb679000000000000000000000000000000000000000000000000000000e8d4a51000","output":"0x","gas_used":24538,"gas_limit":1034941468,"status":"Stop","steps":[],"decoded":null},"logs":[{"raw_log":{"topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x0000000000000000000000000000000000000000000000000000000000000000","0x000000000000000000000000a53e365bb7183eb60b1263706c686848492fb679"],"data":"0x000000000000000000000000000000000000000000000000000000e8d4a51000"},"decoded":null,"position":0,"index":12}],"ordering":[{"Log":0}]},{"parent":14,"children":[],"idx":31,"trace":{"depth":2,"success":true,"caller":"0xc7183455a4c133ae270771860664b6b7ec320bb1","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0xca669fa7000000000000000000000000a53e365bb7183eb60b1263706c686848492fb679","output":"0x","gas_used":0,"gas_limit":1034916707,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":14,"children":[],"idx":32,"trace":{"depth":2,"success":true,"caller":"0xc7183455a4c133ae270771860664b6b7ec320bb1","address":"0x5615deb798bb3e4dfa0139dfa1b3d433cc23b72f","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0x095ea7b3000000000000000000000000f62849f9a0b5bf2913b396098f7c7019b51a820affffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff","output":"0x0000000000000000000000000000000000000000000000000000000000000001","gas_used":24298,"gas_limit":1034916127,"status":"Return","steps":[],"decoded":null},"logs":[{"raw_log":{"topics":["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925","0x000000000000000000000000a53e365bb7183eb60b1263706c686848492fb679","0x000000000000000000000000f62849f9a0b5bf2913b396098f7c7019b51a820a"],"data":"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"},"decoded":null,"position":0,"index":13}],"ordering":[{"Log":0}]},{"parent":14,"children":[],"idx":33,"trace":{"depth":2,"success":true,"caller":"0xc7183455a4c133ae270771860664b6b7ec320bb1","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"STATICCALL","value":"0x0","data":"0x6900a3ae0000000000000000000000000000000000000000000000000000000000000002","output":"0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000013200000000000000000000000000000000000000000000000000000000000000","gas_used":0,"gas_limit":1034891739,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":14,"children":[],"idx":34,"trace":{"depth":2,"success":true,"caller":"0xc7183455a4c133ae270771860664b6b7ec320bb1","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"STATICCALL","value":"0x0","data":"0xffa186499e8eac5ebc9e5f692bb261b0b9d9d23399741ae01a7ae6bb2ef3f10d89ba4738","output":"0x0000000000000000000000000af2f93fd50ab3f4302013624311ec7a84bc9135","gas_used":0,"gas_limit":1034890155,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":14,"children":[],"idx":35,"trace":{"depth":2,"success":true,"caller":"0xc7183455a4c133ae270771860664b6b7ec320bb1","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0xc657c7180000000000000000000000000af2f93fd50ab3f4302013624311ec7a84bc9135000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000026332000000000000000000000000000000000000000000000000000000000000","output":"0x","gas_used":0,"gas_limit":1034889266,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":14,"children":[],"idx":36,"trace":{"depth":2,"success":true,"caller":"0xc7183455a4c133ae270771860664b6b7ec320bb1","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"STATICCALL","value":"0x0","data":"0x6900a3ae0000000000000000000000000000000000000000000000000000000000000002","output":"0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000013200000000000000000000000000000000000000000000000000000000000000","gas_used":0,"gas_limit":1034867099,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":14,"children":[],"idx":37,"trace":{"depth":2,"success":true,"caller":"0xc7183455a4c133ae270771860664b6b7ec320bb1","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"STATICCALL","value":"0x0","data":"0xffa18649c30a3ae685bfcb917dceb41e4afed5342f332572d5b3a8212679077685c494cb","output":"0x000000000000000000000000b19d78033b9efc052db6ba0b93728c9cc54f4074","gas_used":0,"gas_limit":1034865519,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":14,"children":[],"idx":38,"trace":{"depth":2,"success":true,"caller":"0xc7183455a4c133ae270771860664b6b7ec320bb1","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0xc657c718000000000000000000000000b19d78033b9efc052db6ba0b93728c9cc54f4074000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000027032000000000000000000000000000000000000000000000000000000000000","output":"0x","gas_used":0,"gas_limit":1034864630,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":14,"children":[],"idx":39,"trace":{"depth":2,"success":true,"caller":"0xc7183455a4c133ae270771860664b6b7ec320bb1","address":"0x5615deb798bb3e4dfa0139dfa1b3d433cc23b72f","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0x40c10f190000000000000000000000000af2f93fd50ab3f4302013624311ec7a84bc9135000000000000000000000000000000000000000000000000000000e8d4a51000","output":"0x","gas_used":24538,"gas_limit":1034842145,"status":"Stop","steps":[],"decoded":null},"logs":[{"raw_log":{"topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000af2f93fd50ab3f4302013624311ec7a84bc9135"],"data":"0x000000000000000000000000000000000000000000000000000000e8d4a51000"},"decoded":null,"position":0,"index":14}],"ordering":[{"Log":0}]},{"parent":14,"children":[],"idx":40,"trace":{"depth":2,"success":true,"caller":"0xc7183455a4c133ae270771860664b6b7ec320bb1","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0xca669fa70000000000000000000000000af2f93fd50ab3f4302013624311ec7a84bc9135","output":"0x","gas_used":0,"gas_limit":1034817384,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":14,"children":[],"idx":41,"trace":{"depth":2,"success":true,"caller":"0xc7183455a4c133ae270771860664b6b7ec320bb1","address":"0x5615deb798bb3e4dfa0139dfa1b3d433cc23b72f","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0x095ea7b3000000000000000000000000f62849f9a0b5bf2913b396098f7c7019b51a820affffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff","output":"0x0000000000000000000000000000000000000000000000000000000000000001","gas_used":24298,"gas_limit":1034816804,"status":"Return","steps":[],"decoded":null},"logs":[{"raw_log":{"topics":["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925","0x0000000000000000000000000af2f93fd50ab3f4302013624311ec7a84bc9135","0x000000000000000000000000f62849f9a0b5bf2913b396098f7c7019b51a820a"],"data":"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"},"decoded":null,"position":0,"index":15}],"ordering":[{"Log":0}]},{"parent":14,"children":[],"idx":42,"trace":{"depth":2,"success":true,"caller":"0xc7183455a4c133ae270771860664b6b7ec320bb1","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"STATICCALL","value":"0x0","data":"0xffa18649675fdbf9a75d0f12df3d9e7c0dbb3db24e1465ae91a68cf8f50b978edb12e29f","output":"0x000000000000000000000000de12da0783dcb1d543cf885d6eff9e8ead554d58","gas_used":0,"gas_limit":1034791944,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":14,"children":[],"idx":43,"trace":{"depth":2,"success":true,"caller":"0xc7183455a4c133ae270771860664b6b7ec320bb1","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0xc657c718000000000000000000000000de12da0783dcb1d543cf885d6eff9e8ead554d58000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000026530000000000000000000000000000000000000000000000000000000000000","output":"0x","gas_used":0,"gas_limit":1034791057,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":14,"children":[],"idx":44,"trace":{"depth":2,"success":true,"caller":"0xc7183455a4c133ae270771860664b6b7ec320bb1","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"STATICCALL","value":"0x0","data":"0xffa1864910720887749b54d617210b7ff686e35a4534ab64e191c2deb6f34ddbed595541","output":"0x000000000000000000000000456742e80e2d5a6f1db7e244e3763914d3fbd619","gas_used":0,"gas_limit":1034768453,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":14,"children":[],"idx":45,"trace":{"depth":2,"success":true,"caller":"0xc7183455a4c133ae270771860664b6b7ec320bb1","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0xc657c718000000000000000000000000456742e80e2d5a6f1db7e244e3763914d3fbd619000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000026531000000000000000000000000000000000000000000000000000000000000","output":"0x","gas_used":0,"gas_limit":1034767566,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":14,"children":[],"idx":46,"trace":{"depth":2,"success":true,"caller":"0xc7183455a4c133ae270771860664b6b7ec320bb1","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0xca669fa7000000000000000000000000e1fc4143851d3e84a40af3aac51afe019c98cda6","output":"0x","gas_used":0,"gas_limit":1034745089,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":14,"children":[48],"idx":47,"trace":{"depth":2,"success":true,"caller":"0xc7183455a4c133ae270771860664b6b7ec320bb1","address":"0xf62849f9a0b5bf2913b396098f7c7019b51a820a","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0x41528812000000000000000000000000e5b9bc45c8125d133fe66fe9459486e3d5792d39000000000000000000000000de12da0783dcb1d543cf885d6eff9e8ead554d5800000000000000000000000000000000000000000000000000000000657b7e0000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000047365656400000000000000000000000000000000000000000000000000000000","output":"0x0000000000000000000000000000000000000000000000000000000000000001","gas_used":123170,"gas_limit":1034744293,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[{"Call":0}]},{"parent":47,"children":[],"idx":48,"trace":{"depth":3,"success":true,"caller":"0xf62849f9a0b5bf2913b396098f7c7019b51a820a","address":"0x2e234dae75c793f67a35089c9d99245e1c58470b","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"DELEGATECALL","value":"0x0","data":"0x41528812000000000000000000000000e5b9bc45c8125d133fe66fe9459486e3d5792d39000000000000000000000000de12da0783dcb1d543cf885d6eff9e8ead554d5800000000000000000000000000000000000000000000000000000000657b7e0000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000047365656400000000000000000000000000000000000000000000000000000000","output":"0x0000000000000000000000000000000000000000000000000000000000000001","gas_used":122817,"gas_limit":1018576099,"status":"Return","steps":[],"decoded":null},"logs":[{"raw_log":{"topics":["0xb0f0239bfdd96453e24733e18bfc24b70d8fadf123dd977473518dd577ee79b9","0x0000000000000000000000000000000000000000000000000000000000000001","0x000000000000000000000000e1fc4143851d3e84a40af3aac51afe019c98cda6","0x000000000000000000000000e5b9bc45c8125d133fe66fe9459486e3d5792d39"],"data":"0x000000000000000000000000de12da0783dcb1d543cf885d6eff9e8ead554d5800000000000000000000000000000000000000000000000000000000657b7e000000000000000000000000000000000000000000000000000000000000000000"},"decoded":null,"position":0,"index":16}],"ordering":[{"Log":0}]},{"parent":14,"children":[],"idx":49,"trace":{"depth":2,"success":true,"caller":"0xc7183455a4c133ae270771860664b6b7ec320bb1","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0xca669fa7000000000000000000000000e5b9bc45c8125d133fe66fe9459486e3d5792d39","output":"0x","gas_used":0,"gas_limit":1034622349,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":14,"children":[51],"idx":50,"trace":{"depth":2,"success":true,"caller":"0xc7183455a4c133ae270771860664b6b7ec320bb1","address":"0xf62849f9a0b5bf2913b396098f7c7019b51a820a","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0xdd4ae9d4000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000f424000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000","output":"0x","gas_used":24492,"gas_limit":1034621654,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[{"Call":0}]},{"parent":50,"children":[],"idx":51,"trace":{"depth":3,"success":true,"caller":"0xf62849f9a0b5bf2913b396098f7c7019b51a820a","address":"0x2e234dae75c793f67a35089c9d99245e1c58470b","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"DELEGATECALL","value":"0x0","data":"0xdd4ae9d4000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000f424000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000","output":"0x","gas_used":24160,"gas_limit":1018455394,"status":"Stop","steps":[],"decoded":null},"logs":[{"raw_log":{"topics":["0x869e2577b006bf47ee981cf6fec2e25583548081c14b98deab587f77b5068038","0x0000000000000000000000000000000000000000000000000000000000000001"],"data":"0x00000000000000000000000000000000000000000000000000000000000f4240"},"decoded":null,"position":0,"index":17}],"ordering":[{"Log":0}]},{"parent":14,"children":[],"idx":52,"trace":{"depth":2,"success":true,"caller":"0xc7183455a4c133ae270771860664b6b7ec320bb1","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0xca669fa7000000000000000000000000a53e365bb7183eb60b1263706c686848492fb679","output":"0x","gas_used":0,"gas_limit":1034594569,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":14,"children":[54],"idx":53,"trace":{"depth":2,"success":true,"caller":"0xc7183455a4c133ae270771860664b6b7ec320bb1","address":"0xf62849f9a0b5bf2913b396098f7c7019b51a820a","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0x41528812000000000000000000000000ab80885935d10ffc2f477636e1c5cdef234e22c3000000000000000000000000de12da0783dcb1d543cf885d6eff9e8ead554d5800000000000000000000000000000000000000000000000000000000657b7e0000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000047365656400000000000000000000000000000000000000000000000000000000","output":"0x0000000000000000000000000000000000000000000000000000000000000002","gas_used":99270,"gas_limit":1034593780,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[{"Call":0}]},{"parent":53,"children":[],"idx":54,"trace":{"depth":3,"success":true,"caller":"0xf62849f9a0b5bf2913b396098f7c7019b51a820a","address":"0x2e234dae75c793f67a35089c9d99245e1c58470b","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"DELEGATECALL","value":"0x0","data":"0x41528812000000000000000000000000ab80885935d10ffc2f477636e1c5cdef234e22c3000000000000000000000000de12da0783dcb1d543cf885d6eff9e8ead554d5800000000000000000000000000000000000000000000000000000000657b7e0000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000047365656400000000000000000000000000000000000000000000000000000000","output":"0x0000000000000000000000000000000000000000000000000000000000000002","gas_used":98917,"gas_limit":1018427938,"status":"Return","steps":[],"decoded":null},"logs":[{"raw_log":{"topics":["0xb0f0239bfdd96453e24733e18bfc24b70d8fadf123dd977473518dd577ee79b9","0x0000000000000000000000000000000000000000000000000000000000000002","0x000000000000000000000000a53e365bb7183eb60b1263706c686848492fb679","0x000000000000000000000000ab80885935d10ffc2f477636e1c5cdef234e22c3"],"data":"0x000000000000000000000000de12da0783dcb1d543cf885d6eff9e8ead554d5800000000000000000000000000000000000000000000000000000000657b7e000000000000000000000000000000000000000000000000000000000000000000"},"decoded":null,"position":0,"index":18}],"ordering":[{"Log":0}]},{"parent":14,"children":[],"idx":55,"trace":{"depth":2,"success":true,"caller":"0xc7183455a4c133ae270771860664b6b7ec320bb1","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0xca669fa7000000000000000000000000ab80885935d10ffc2f477636e1c5cdef234e22c3","output":"0x","gas_used":0,"gas_limit":1034495362,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":14,"children":[57],"idx":56,"trace":{"depth":2,"success":true,"caller":"0xc7183455a4c133ae270771860664b6b7ec320bb1","address":"0xf62849f9a0b5bf2913b396098f7c7019b51a820a","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0xdd4ae9d4000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000001e848000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000","output":"0x","gas_used":24492,"gas_limit":1034494667,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[{"Call":0}]},{"parent":56,"children":[],"idx":57,"trace":{"depth":3,"success":true,"caller":"0xf62849f9a0b5bf2913b396098f7c7019b51a820a","address":"0x2e234dae75c793f67a35089c9d99245e1c58470b","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"DELEGATECALL","value":"0x0","data":"0xdd4ae9d4000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000001e848000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000","output":"0x","gas_used":24160,"gas_limit":1018330391,"status":"Stop","steps":[],"decoded":null},"logs":[{"raw_log":{"topics":["0x869e2577b006bf47ee981cf6fec2e25583548081c14b98deab587f77b5068038","0x0000000000000000000000000000000000000000000000000000000000000002"],"data":"0x00000000000000000000000000000000000000000000000000000000001e8480"},"decoded":null,"position":0,"index":19}],"ordering":[{"Log":0}]},{"parent":14,"children":[],"idx":58,"trace":{"depth":2,"success":true,"caller":"0xc7183455a4c133ae270771860664b6b7ec320bb1","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0xca669fa7000000000000000000000000a53e365bb7183eb60b1263706c686848492fb679","output":"0x","gas_used":0,"gas_limit":1034467672,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":14,"children":[60],"idx":59,"trace":{"depth":2,"success":true,"caller":"0xc7183455a4c133ae270771860664b6b7ec320bb1","address":"0xf62849f9a0b5bf2913b396098f7c7019b51a820a","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0xd2e13f50000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000001e848000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000","output":"0x","gas_used":52994,"gas_limit":1034467051,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[{"Call":0}]},{"parent":59,"children":[61],"idx":60,"trace":{"depth":3,"success":true,"caller":"0xf62849f9a0b5bf2913b396098f7c7019b51a820a","address":"0x2e234dae75c793f67a35089c9d99245e1c58470b","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"DELEGATECALL","value":"0x0","data":"0xd2e13f50000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000001e848000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000","output":"0x","gas_used":52662,"gas_limit":1018303207,"status":"Stop","steps":[],"decoded":null},"logs":[{"raw_log":{"topics":["0xe3fbcc1ea1bdc559ec7f0347efde7655e58b5f45a30b0e4470a583c3ef5496b3","0x0000000000000000000000000000000000000000000000000000000000000002","0x000000000000000000000000a53e365bb7183eb60b1263706c686848492fb679"],"data":"0x00000000000000000000000000000000000000000000000000000000001e8480"},"decoded":null,"position":1,"index":21}],"ordering":[{"Call":0},{"Log":0}]},{"parent":60,"children":[],"idx":61,"trace":{"depth":4,"success":true,"caller":"0xf62849f9a0b5bf2913b396098f7c7019b51a820a","address":"0x5615deb798bb3e4dfa0139dfa1b3d433cc23b72f","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0x23b872dd000000000000000000000000a53e365bb7183eb60b1263706c686848492fb679000000000000000000000000f62849f9a0b5bf2913b396098f7c7019b51a820a00000000000000000000000000000000000000000000000000000000001e8480","output":"0x0000000000000000000000000000000000000000000000000000000000000001","gas_used":25012,"gas_limit":1002367111,"status":"Return","steps":[],"decoded":null},"logs":[{"raw_log":{"topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x000000000000000000000000a53e365bb7183eb60b1263706c686848492fb679","0x000000000000000000000000f62849f9a0b5bf2913b396098f7c7019b51a820a"],"data":"0x00000000000000000000000000000000000000000000000000000000001e8480"},"decoded":null,"position":0,"index":20}],"ordering":[{"Log":0}]},{"parent":14,"children":[],"idx":62,"trace":{"depth":2,"success":true,"caller":"0xc7183455a4c133ae270771860664b6b7ec320bb1","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0xca669fa70000000000000000000000000af2f93fd50ab3f4302013624311ec7a84bc9135","output":"0x","gas_used":0,"gas_limit":1034394291,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":14,"children":[64],"idx":63,"trace":{"depth":2,"success":true,"caller":"0xc7183455a4c133ae270771860664b6b7ec320bb1","address":"0xf62849f9a0b5bf2913b396098f7c7019b51a820a","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0x41528812000000000000000000000000b19d78033b9efc052db6ba0b93728c9cc54f4074000000000000000000000000de12da0783dcb1d543cf885d6eff9e8ead554d5800000000000000000000000000000000000000000000000000000000657b7e0000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000047365656400000000000000000000000000000000000000000000000000000000","output":"0x0000000000000000000000000000000000000000000000000000000000000003","gas_used":99270,"gas_limit":1034393501,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[{"Call":0}]},{"parent":63,"children":[],"idx":64,"trace":{"depth":3,"success":true,"caller":"0xf62849f9a0b5bf2913b396098f7c7019b51a820a","address":"0x2e234dae75c793f67a35089c9d99245e1c58470b","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"DELEGATECALL","value":"0x0","data":"0x41528812000000000000000000000000b19d78033b9efc052db6ba0b93728c9cc54f4074000000000000000000000000de12da0783dcb1d543cf885d6eff9e8ead554d5800000000000000000000000000000000000000000000000000000000657b7e0000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000047365656400000000000000000000000000000000000000000000000000000000","output":"0x0000000000000000000000000000000000000000000000000000000000000003","gas_used":98917,"gas_limit":1018230788,"status":"Return","steps":[],"decoded":null},"logs":[{"raw_log":{"topics":["0xb0f0239bfdd96453e24733e18bfc24b70d8fadf123dd977473518dd577ee79b9","0x0000000000000000000000000000000000000000000000000000000000000003","0x0000000000000000000000000af2f93fd50ab3f4302013624311ec7a84bc9135","0x000000000000000000000000b19d78033b9efc052db6ba0b93728c9cc54f4074"],"data":"0x000000000000000000000000de12da0783dcb1d543cf885d6eff9e8ead554d5800000000000000000000000000000000000000000000000000000000657b7e000000000000000000000000000000000000000000000000000000000000000000"},"decoded":null,"position":0,"index":22}],"ordering":[{"Log":0}]},{"parent":14,"children":[],"idx":65,"trace":{"depth":2,"success":true,"caller":"0xc7183455a4c133ae270771860664b6b7ec320bb1","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0xca669fa7000000000000000000000000b19d78033b9efc052db6ba0b93728c9cc54f4074","output":"0x","gas_used":0,"gas_limit":1034295083,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":14,"children":[67],"idx":66,"trace":{"depth":2,"success":true,"caller":"0xc7183455a4c133ae270771860664b6b7ec320bb1","address":"0xf62849f9a0b5bf2913b396098f7c7019b51a820a","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0xdd4ae9d4000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000002dc6c000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000","output":"0x","gas_used":24492,"gas_limit":1034294388,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[{"Call":0}]},{"parent":66,"children":[],"idx":67,"trace":{"depth":3,"success":true,"caller":"0xf62849f9a0b5bf2913b396098f7c7019b51a820a","address":"0x2e234dae75c793f67a35089c9d99245e1c58470b","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"DELEGATECALL","value":"0x0","data":"0xdd4ae9d4000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000002dc6c000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000","output":"0x","gas_used":24160,"gas_limit":1018133241,"status":"Stop","steps":[],"decoded":null},"logs":[{"raw_log":{"topics":["0x869e2577b006bf47ee981cf6fec2e25583548081c14b98deab587f77b5068038","0x0000000000000000000000000000000000000000000000000000000000000003"],"data":"0x00000000000000000000000000000000000000000000000000000000002dc6c0"},"decoded":null,"position":0,"index":23}],"ordering":[{"Log":0}]},{"parent":14,"children":[],"idx":68,"trace":{"depth":2,"success":true,"caller":"0xc7183455a4c133ae270771860664b6b7ec320bb1","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0xca669fa70000000000000000000000000af2f93fd50ab3f4302013624311ec7a84bc9135","output":"0x","gas_used":0,"gas_limit":1034267393,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":14,"children":[70],"idx":69,"trace":{"depth":2,"success":true,"caller":"0xc7183455a4c133ae270771860664b6b7ec320bb1","address":"0xf62849f9a0b5bf2913b396098f7c7019b51a820a","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0xd2e13f50000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000002dc6c000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000","output":"0x","gas_used":9194,"gas_limit":1034266772,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[{"Call":0}]},{"parent":69,"children":[71],"idx":70,"trace":{"depth":3,"success":true,"caller":"0xf62849f9a0b5bf2913b396098f7c7019b51a820a","address":"0x2e234dae75c793f67a35089c9d99245e1c58470b","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"DELEGATECALL","value":"0x0","data":"0xd2e13f50000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000002dc6c000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000","output":"0x","gas_used":8862,"gas_limit":1018106057,"status":"Stop","steps":[],"decoded":null},"logs":[{"raw_log":{"topics":["0xe3fbcc1ea1bdc559ec7f0347efde7655e58b5f45a30b0e4470a583c3ef5496b3","0x0000000000000000000000000000000000000000000000000000000000000003","0x0000000000000000000000000af2f93fd50ab3f4302013624311ec7a84bc9135"],"data":"0x00000000000000000000000000000000000000000000000000000000002dc6c0"},"decoded":null,"position":1,"index":25}],"ordering":[{"Call":0},{"Log":0}]},{"parent":70,"children":[],"idx":71,"trace":{"depth":4,"success":true,"caller":"0xf62849f9a0b5bf2913b396098f7c7019b51a820a","address":"0x5615deb798bb3e4dfa0139dfa1b3d433cc23b72f","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0x23b872dd0000000000000000000000000af2f93fd50ab3f4302013624311ec7a84bc9135000000000000000000000000f62849f9a0b5bf2913b396098f7c7019b51a820a00000000000000000000000000000000000000000000000000000000002dc6c0","output":"0x0000000000000000000000000000000000000000000000000000000000000001","gas_used":3112,"gas_limit":1002194600,"status":"Return","steps":[],"decoded":null},"logs":[{"raw_log":{"topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x0000000000000000000000000af2f93fd50ab3f4302013624311ec7a84bc9135","0x000000000000000000000000f62849f9a0b5bf2913b396098f7c7019b51a820a"],"data":"0x00000000000000000000000000000000000000000000000000000000002dc6c0"},"decoded":null,"position":0,"index":24}],"ordering":[{"Log":0}]},{"parent":14,"children":[],"idx":72,"trace":{"depth":2,"success":true,"caller":"0xc7183455a4c133ae270771860664b6b7ec320bb1","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0xca669fa7000000000000000000000000b19d78033b9efc052db6ba0b93728c9cc54f4074","output":"0x","gas_used":0,"gas_limit":1034237187,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[]},{"parent":14,"children":[74],"idx":73,"trace":{"depth":2,"success":true,"caller":"0xc7183455a4c133ae270771860664b6b7ec320bb1","address":"0xf62849f9a0b5bf2913b396098f7c7019b51a820a","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0x9e63798d0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000","output":"0x","gas_used":4909,"gas_limit":1034236581,"status":"Return","steps":[],"decoded":null},"logs":[],"ordering":[{"Call":0}]},{"parent":73,"children":[],"idx":74,"trace":{"depth":3,"success":true,"caller":"0xf62849f9a0b5bf2913b396098f7c7019b51a820a","address":"0x2e234dae75c793f67a35089c9d99245e1c58470b","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"DELEGATECALL","value":"0x0","data":"0x9e63798d0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000","output":"0x","gas_used":4577,"gas_limit":1018076338,"status":"Stop","steps":[],"decoded":null},"logs":[{"raw_log":{"topics":["0x80c17db79857f338a6a6df68a6883ecc0ce78e2202fe61ed979733573f40538e","0x0000000000000000000000000000000000000000000000000000000000000003","0x000000000000000000000000b19d78033b9efc052db6ba0b93728c9cc54f4074"],"data":"0x0000000000000000000000000000000000000000000000000000000000000000"},"decoded":null,"position":0,"index":26}],"ordering":[{"Log":0}]}]}]],"labeled_addresses":{"0xa53e365bb7183eb60b1263706c686848492fb679":"c1","0xe1fc4143851d3e84a40af3aac51afe019c98cda6":"c0","0x0af2f93fd50ab3f4302013624311ec7a84bc9135":"c2","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xb19d78033b9efc052db6ba0b93728c9cc54f4074":"p2","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xab80885935d10ffc2f477636e1c5cdef234e22c3":"p1","0x456742e80e2d5a6f1db7e244e3763914d3fbd619":"e1","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xe5b9bc45c8125d133fe66fe9459486e3d5792d39":"p0","0xde12da0783dcb1d543cf885d6eff9e8ead554d58":"e0"},"duration":"93ms 320µs 583ns","breakpoints":{},"gas_snapshots":{}}},"warnings":[]},"test/8183-tests/AgenticCommerce.lifecycle.t.sol:AgenticCommerceLifecycleTest":{"duration":"62ms 456µs 167ns","test_results":{"test_claimRefund_fundedZeroBudget_noTransfer()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":169546}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"423µs 958ns","breakpoints":{},"gas_snapshots":{}},"test_claimRefund_funded_afterExpiry()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":224589}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"5ms 231µs 834ns","breakpoints":{},"gas_snapshots":{}},"test_claimRefund_funded_beforeExpiry_reverts()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":243361}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"45µs 417ns","breakpoints":{},"gas_snapshots":{}},"test_claimRefund_invalidAndTerminal_revert()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":169156}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"30µs 291ns","breakpoints":{},"gas_snapshots":{}},"test_claimRefund_neverCallsHook_evenReverting()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":515068}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"81µs 708ns","breakpoints":{},"gas_snapshots":{}},"test_claimRefund_open_afterExpiry_noTransfer()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":160461}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"1ms 835µs 916ns","breakpoints":{},"gas_snapshots":{}},"test_claimRefund_submitted_gracePeriod()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":231164}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"81µs 708ns","breakpoints":{},"gas_snapshots":{}},"test_claimRefund_worksWhilePaused()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":237789}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"57µs 125ns","breakpoints":{},"gas_snapshots":{}},"test_complete_allowedAfterExpiry()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":248113}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"56µs 750ns","breakpoints":{},"gas_snapshots":{}},"test_complete_feeSplit_rounding_andEventOrder()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":376962}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"621µs 875ns","breakpoints":{},"gas_snapshots":{}},"test_complete_fullFees_netZero_stillEmitsPaymentReleased()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":285866}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"554µs 125ns","breakpoints":{},"gas_snapshots":{}},"test_complete_reverts()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":400767}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"78µs 667ns","breakpoints":{},"gas_snapshots":{}},"test_complete_vs_claimRefund_race_afterGrace()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":223853}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"141µs 83ns","breakpoints":{},"gas_snapshots":{}},"test_complete_zeroBudget()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":183447}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"1ms 264µs 541ns","breakpoints":{},"gas_snapshots":{}},"test_complete_zeroFees_providerGetsAll()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":263434}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"170µs 417ns","breakpoints":{},"gas_snapshots":{}},"test_createJob_clientIsProvider_reverts()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":26953}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"28µs 667ns","breakpoints":{},"gas_snapshots":{}},"test_createJob_evaluatorIsProvider_reverts()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":26444}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"34µs 750ns","breakpoints":{},"gas_snapshots":{}},"test_createJob_expiryAboveUint48_reverts()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":28680}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"25µs","breakpoints":{},"gas_snapshots":{}},"test_createJob_expiryBoundary()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":138537}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"56µs 83ns","breakpoints":{},"gas_snapshots":{}},"test_createJob_happy_noProvider_noHook_evaluatorIsClient()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":132398}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"66µs 292ns","breakpoints":{},"gas_snapshots":{}},"test_createJob_happy_withProviderAndHook()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":191953}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"113µs 625ns","breakpoints":{},"gas_snapshots":{}},"test_createJob_hookNotWhitelisted_reverts()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":32568}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x74c4af92ba5855927c5586e51823c4f2ebd01cda":"nope","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"117µs","breakpoints":{},"gas_snapshots":{}},"test_createJob_invalidHook_eoa_reverts()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":63221}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xb50df9574b97e843927dddf6c100824641a688b1":"eoaHook","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"127µs 41ns","breakpoints":{},"gas_snapshots":{}},"test_createJob_invalidHook_erc165Only_reverts()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":137299}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"55µs 791ns","breakpoints":{},"gas_snapshots":{}},"test_createJob_precedence()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":58801}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x74c4af92ba5855927c5586e51823c4f2ebd01cda":"nope","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"127µs 709ns","breakpoints":{},"gas_snapshots":{}},"test_createJob_zeroEvaluator_reverts()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":26600}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"45µs 792ns","breakpoints":{},"gas_snapshots":{}},"test_fund_frontRunReQuote_reverts()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":185217}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"177µs 500ns","breakpoints":{},"gas_snapshots":{}},"test_fund_happy()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":1003255}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"1ms 443µs 208ns","breakpoints":{},"gas_snapshots":{}},"test_fund_precedence()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":296207}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"55µs 42ns","breakpoints":{},"gas_snapshots":{}},"test_fund_reverts_inOrder()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":308311}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"58µs","breakpoints":{},"gas_snapshots":{}},"test_fund_twice_reverts()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":243951}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"34µs 500ns","breakpoints":{},"gas_snapshots":{}},"test_fund_zeroBudget_noTransfer()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":172739}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"40µs 42ns","breakpoints":{},"gas_snapshots":{}},"test_getJob_unknownIds_returnZeroStruct()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":181447}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"33µs 625ns","breakpoints":{},"gas_snapshots":{}},"test_reject_fundedZeroBudget_noRefundEvent()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":171860}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"45µs 625ns","breakpoints":{},"gas_snapshots":{}},"test_reject_funded_byEvaluator_refunds()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":216232}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"565µs 208ns","breakpoints":{},"gas_snapshots":{}},"test_reject_invalidAndTerminal_revert()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":172773}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"29µs 291ns","breakpoints":{},"gas_snapshots":{}},"test_reject_open_byClient_and_byProvider()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":271538}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"51µs 417ns","breakpoints":{},"gas_snapshots":{}},"test_reject_submitted_byEvaluator_refunds()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":220407}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"54µs 667ns","breakpoints":{},"gas_snapshots":{}},"test_reject_unauthorisedPerStatus()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":500641}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"82µs 458ns","breakpoints":{},"gas_snapshots":{}},"test_setBudget_afterFund_reverts()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":245108}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"34µs 333ns","breakpoints":{},"gas_snapshots":{}},"test_setBudget_reQuotableWhileOpen_andEncoding()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":1042170}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"119µs 666ns","breakpoints":{},"gas_snapshots":{}},"test_setBudget_reverts()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":170164}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"34µs 709ns","breakpoints":{},"gas_snapshots":{}},"test_setProvider_expired_reverts()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":153570}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"20µs 500ns","breakpoints":{},"gas_snapshots":{}},"test_setProvider_happy_hookedWithEncoding()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":623342}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"91µs 84ns","breakpoints":{},"gas_snapshots":{}},"test_setProvider_notOpen_reverts()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":159117}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"27µs 750ns","breakpoints":{},"gas_snapshots":{}},"test_setProvider_precedence()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":264045}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"34µs 542ns","breakpoints":{},"gas_snapshots":{}},"test_setProvider_revertingBeforeHook_blocks()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":452789}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"39µs 459ns","breakpoints":{},"gas_snapshots":{}},"test_setProvider_reverts_inOrder()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":201058}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xb19d78033b9efc052db6ba0b93728c9cc54f4074":"p2","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"76µs 83ns","breakpoints":{},"gas_snapshots":{}},"test_submit_happy()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":1347518}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"149µs 125ns","breakpoints":{},"gas_snapshots":{}},"test_submit_openJob_reverts_evenZeroBudget()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":152838}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"21µs 375ns","breakpoints":{},"gas_snapshots":{}},"test_submit_reverts()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":259564}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"46µs 84ns","breakpoints":{},"gas_snapshots":{}}},"warnings":[]},"test/8183-tests/BaseERC8183Hook.t.sol:BaseERC8183HookTest":{"duration":"9ms 878µs 875ns","test_results":{"test_afterAction_fromNonKernel_reverts()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":19217}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xf5da897cb27ecd131cf70e9611ef85fec8533356":"hookProxyAdminOwner"},"duration":"48µs 83ns","breakpoints":{},"gas_snapshots":{}},"test_baseInit_outsideInitializer_reverts()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":17650}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xf5da897cb27ecd131cf70e9611ef85fec8533356":"hookProxyAdminOwner"},"duration":"21µs 250ns","breakpoints":{},"gas_snapshots":{}},"test_beforeAction_fromNonKernel_reverts()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":18796}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xf5da897cb27ecd131cf70e9611ef85fec8533356":"hookProxyAdminOwner"},"duration":"22µs 125ns","breakpoints":{},"gas_snapshots":{}},"test_defaultHandlers_areNoops_fullLifecycleAndReject()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":1690404}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xf5da897cb27ecd131cf70e9611ef85fec8533356":"hookProxyAdminOwner"},"duration":"477µs 792ns","breakpoints":{},"gas_snapshots":{}},"test_init_onImplementation_reverts()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":13064}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xf5da897cb27ecd131cf70e9611ef85fec8533356":"hookProxyAdminOwner"},"duration":"16µs 667ns","breakpoints":{},"gas_snapshots":{}},"test_init_twice_reverts()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":17853}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xf5da897cb27ecd131cf70e9611ef85fec8533356":"hookProxyAdminOwner"},"duration":"16µs 959ns","breakpoints":{},"gas_snapshots":{}},"test_init_zeroKernel_reverts()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":91399}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xf5da897cb27ecd131cf70e9611ef85fec8533356":"hookProxyAdminOwner"},"duration":"40µs 458ns","breakpoints":{},"gas_snapshots":{}},"test_kernel_isSetAndAtSlot0()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":18508}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xf5da897cb27ecd131cf70e9611ef85fec8533356":"hookProxyAdminOwner"},"duration":"541µs 250ns","breakpoints":{},"gas_snapshots":{}},"test_routes_reject()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":879008}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xf5da897cb27ecd131cf70e9611ef85fec8533356":"hookProxyAdminOwner"},"duration":"308µs 375ns","breakpoints":{},"gas_snapshots":{}},"test_routes_setProvider_setBudget_fund_submit_complete()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":1545489}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xf5da897cb27ecd131cf70e9611ef85fec8533356":"hookProxyAdminOwner"},"duration":"428µs 917ns","breakpoints":{},"gas_snapshots":{}},"test_supportsInterface()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":16235}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xf5da897cb27ecd131cf70e9611ef85fec8533356":"hookProxyAdminOwner"},"duration":"37µs 292ns","breakpoints":{},"gas_snapshots":{}},"test_unknownSelector_isNoop()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":23541}},"traces":[],"labeled_addresses":{"0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xf5da897cb27ecd131cf70e9611ef85fec8533356":"hookProxyAdminOwner"},"duration":"15µs 667ns","breakpoints":{},"gas_snapshots":{}}},"warnings":[]},"test/8183-tests/Interfaces.t.sol:InterfacesTest":{"duration":"87µs 584ns","test_results":{"test_createJob_keepsFiveArgumentShape()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":3183}},"traces":[],"labeled_addresses":{},"duration":"5µs 292ns","breakpoints":{},"gas_snapshots":{}},"test_hookInterfaceId_isXorOfBothSelectors()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":3795}},"traces":[],"labeled_addresses":{},"duration":"4µs 958ns","breakpoints":{},"gas_snapshots":{}},"test_hookSelectors_matchStandard()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":3672}},"traces":[],"labeled_addresses":{},"duration":"4µs 416ns","breakpoints":{},"gas_snapshots":{}},"test_hookedKernelSelectors()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":5326}},"traces":[],"labeled_addresses":{},"duration":"7µs 584ns","breakpoints":{},"gas_snapshots":{}}},"warnings":[]},"test/8183-tests/JobSpecBuilder.t.sol:JobSpecBuilderTest":{"duration":"791ms 238µs 625ns","test_results":{"testFuzz_JB10_inBoundsNeverReverts(uint256,int256)":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Fuzz":{"first_case":{"calldata":"0x9c16db6d00000000000000000000000000214feb2caf420de2e7d1a5d26675eab6a0e2bb0000000000000000000000000000000060818b01e8252083ddd4ceb18d829d9b","gas":209179,"stipend":21740},"runs":1024,"mean_gas":187406,"median_gas":187514,"failed_corpus_replays":0}},"traces":[],"labeled_addresses":{"0xbbe819a3dd1113e30925014563ca18e9ea942501":"MorphoVault.eth","0x41bffff0ebab0ff77c37421d0f3f19f48a04cb1f":"USDC.eth","0xd00966eaf28611743d149d346a1b20f6e0eb4196":"AavePool.eth","0x0df093b0529a686c0f0a153ad18e2672215fbc51":"WETH.base","0x914d024d703c0df6f9a32b21c95b3b2de71f8467":"Spark.eth","0x33474942344753f636e5af8c437d1d00eb01c6c2":"agw","0x913733dc3761d3e66534494f701a1a664861a9a7":"aUSDC.eth"},"duration":"783ms 566µs 834ns","breakpoints":{},"gas_snapshots":{}},"testFuzz_JB11_deterministic(uint256,bytes32)":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Fuzz":{"first_case":{"calldata":"0x2f337cc700000000000000000000000000214feb2caf420de2e7d1a5d26675eab6a0e2bb53c47eae3aec9bb18301b8c98eb4d12f4ec8a60096f7902e97f25d5ecd4e7660","gas":350111,"stipend":21920},"runs":1024,"mean_gas":328267,"median_gas":328191,"failed_corpus_replays":0}},"traces":[],"labeled_addresses":{"0xbbe819a3dd1113e30925014563ca18e9ea942501":"MorphoVault.eth","0x41bffff0ebab0ff77c37421d0f3f19f48a04cb1f":"USDC.eth","0xd00966eaf28611743d149d346a1b20f6e0eb4196":"AavePool.eth","0x0df093b0529a686c0f0a153ad18e2672215fbc51":"WETH.base","0x914d024d703c0df6f9a32b21c95b3b2de71f8467":"Spark.eth","0x33474942344753f636e5af8c437d1d00eb01c6c2":"agw","0x913733dc3761d3e66534494f701a1a664861a9a7":"aUSDC.eth"},"duration":"500ms 341µs 42ns","breakpoints":{},"gas_snapshots":{}},"test_JB01_fills()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":193400}},"traces":[],"labeled_addresses":{"0xbbe819a3dd1113e30925014563ca18e9ea942501":"MorphoVault.eth","0x41bffff0ebab0ff77c37421d0f3f19f48a04cb1f":"USDC.eth","0xd00966eaf28611743d149d346a1b20f6e0eb4196":"AavePool.eth","0x0df093b0529a686c0f0a153ad18e2672215fbc51":"WETH.base","0x914d024d703c0df6f9a32b21c95b3b2de71f8467":"Spark.eth","0x33474942344753f636e5af8c437d1d00eb01c6c2":"agw","0x913733dc3761d3e66534494f701a1a664861a9a7":"aUSDC.eth"},"duration":"303µs 375ns","breakpoints":{},"gas_snapshots":{}},"test_JB02_targets()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":331784}},"traces":[],"labeled_addresses":{"0xbbe819a3dd1113e30925014563ca18e9ea942501":"MorphoVault.eth","0x41bffff0ebab0ff77c37421d0f3f19f48a04cb1f":"USDC.eth","0xd00966eaf28611743d149d346a1b20f6e0eb4196":"AavePool.eth","0x0df093b0529a686c0f0a153ad18e2672215fbc51":"WETH.base","0x914d024d703c0df6f9a32b21c95b3b2de71f8467":"Spark.eth","0x33474942344753f636e5af8c437d1d00eb01c6c2":"agw","0x913733dc3761d3e66534494f701a1a664861a9a7":"aUSDC.eth"},"duration":"540µs 292ns","breakpoints":{},"gas_snapshots":{}},"test_JB03_timingAndOrigin()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":236220}},"traces":[],"labeled_addresses":{"0xbbe819a3dd1113e30925014563ca18e9ea942501":"MorphoVault.eth","0x41bffff0ebab0ff77c37421d0f3f19f48a04cb1f":"USDC.eth","0xd00966eaf28611743d149d346a1b20f6e0eb4196":"AavePool.eth","0x0df093b0529a686c0f0a153ad18e2672215fbc51":"WETH.base","0x914d024d703c0df6f9a32b21c95b3b2de71f8467":"Spark.eth","0x33474942344753f636e5af8c437d1d00eb01c6c2":"agw","0x913733dc3761d3e66534494f701a1a664861a9a7":"aUSDC.eth"},"duration":"766µs 875ns","breakpoints":{},"gas_snapshots":{}},"test_JB04_params()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":194249}},"traces":[],"labeled_addresses":{"0xbbe819a3dd1113e30925014563ca18e9ea942501":"MorphoVault.eth","0x41bffff0ebab0ff77c37421d0f3f19f48a04cb1f":"USDC.eth","0xd00966eaf28611743d149d346a1b20f6e0eb4196":"AavePool.eth","0x0df093b0529a686c0f0a153ad18e2672215fbc51":"WETH.base","0x914d024d703c0df6f9a32b21c95b3b2de71f8467":"Spark.eth","0x33474942344753f636e5af8c437d1d00eb01c6c2":"agw","0x913733dc3761d3e66534494f701a1a664861a9a7":"aUSDC.eth"},"duration":"738µs 208ns","breakpoints":{},"gas_snapshots":{}},"test_JB05_targetOverflow()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":161301}},"traces":[],"labeled_addresses":{"0xbbe819a3dd1113e30925014563ca18e9ea942501":"MorphoVault.eth","0x41bffff0ebab0ff77c37421d0f3f19f48a04cb1f":"USDC.eth","0xd00966eaf28611743d149d346a1b20f6e0eb4196":"AavePool.eth","0x0df093b0529a686c0f0a153ad18e2672215fbc51":"WETH.base","0x914d024d703c0df6f9a32b21c95b3b2de71f8467":"Spark.eth","0x33474942344753f636e5af8c437d1d00eb01c6c2":"agw","0x913733dc3761d3e66534494f701a1a664861a9a7":"aUSDC.eth"},"duration":"531µs 750ns","breakpoints":{},"gas_snapshots":{}},"test_JB06_fillOutOfBounds()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":153674}},"traces":[],"labeled_addresses":{"0xbbe819a3dd1113e30925014563ca18e9ea942501":"MorphoVault.eth","0x41bffff0ebab0ff77c37421d0f3f19f48a04cb1f":"USDC.eth","0xd00966eaf28611743d149d346a1b20f6e0eb4196":"AavePool.eth","0x0df093b0529a686c0f0a153ad18e2672215fbc51":"WETH.base","0x914d024d703c0df6f9a32b21c95b3b2de71f8467":"Spark.eth","0x33474942344753f636e5af8c437d1d00eb01c6c2":"agw","0x913733dc3761d3e66534494f701a1a664861a9a7":"aUSDC.eth"},"duration":"399µs","breakpoints":{},"gas_snapshots":{}},"test_JB07_ceaOnUnsupportedChain()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":147535}},"traces":[],"labeled_addresses":{"0xbbe819a3dd1113e30925014563ca18e9ea942501":"MorphoVault.eth","0x41bffff0ebab0ff77c37421d0f3f19f48a04cb1f":"USDC.eth","0xd00966eaf28611743d149d346a1b20f6e0eb4196":"AavePool.eth","0x0df093b0529a686c0f0a153ad18e2672215fbc51":"WETH.base","0x914d024d703c0df6f9a32b21c95b3b2de71f8467":"Spark.eth","0x33474942344753f636e5af8c437d1d00eb01c6c2":"agw","0x913733dc3761d3e66534494f701a1a664861a9a7":"aUSDC.eth"},"duration":"217µs 42ns","breakpoints":{},"gas_snapshots":{}},"test_JB08_doesNotJudgeTheTemplate()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":144987}},"traces":[],"labeled_addresses":{"0xbbe819a3dd1113e30925014563ca18e9ea942501":"MorphoVault.eth","0x41bffff0ebab0ff77c37421d0f3f19f48a04cb1f":"USDC.eth","0xd00966eaf28611743d149d346a1b20f6e0eb4196":"AavePool.eth","0x0df093b0529a686c0f0a153ad18e2672215fbc51":"WETH.base","0x914d024d703c0df6f9a32b21c95b3b2de71f8467":"Spark.eth","0x33474942344753f636e5af8c437d1d00eb01c6c2":"agw","0x913733dc3761d3e66534494f701a1a664861a9a7":"aUSDC.eth"},"duration":"200µs 209ns","breakpoints":{},"gas_snapshots":{}},"test_JB09_malformedTemplate_reverts()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":19054}},"traces":[],"labeled_addresses":{"0xbbe819a3dd1113e30925014563ca18e9ea942501":"MorphoVault.eth","0x41bffff0ebab0ff77c37421d0f3f19f48a04cb1f":"USDC.eth","0xd00966eaf28611743d149d346a1b20f6e0eb4196":"AavePool.eth","0x0df093b0529a686c0f0a153ad18e2672215fbc51":"WETH.base","0x914d024d703c0df6f9a32b21c95b3b2de71f8467":"Spark.eth","0x33474942344753f636e5af8c437d1d00eb01c6c2":"agw","0x913733dc3761d3e66534494f701a1a664861a9a7":"aUSDC.eth"},"duration":"19µs 500ns","breakpoints":{},"gas_snapshots":{}},"test_JB12_copiesLogicAndMutability()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":203167}},"traces":[],"labeled_addresses":{"0xbbe819a3dd1113e30925014563ca18e9ea942501":"MorphoVault.eth","0x41bffff0ebab0ff77c37421d0f3f19f48a04cb1f":"USDC.eth","0xd00966eaf28611743d149d346a1b20f6e0eb4196":"AavePool.eth","0x0df093b0529a686c0f0a153ad18e2672215fbc51":"WETH.base","0x914d024d703c0df6f9a32b21c95b3b2de71f8467":"Spark.eth","0x33474942344753f636e5af8c437d1d00eb01c6c2":"agw","0x913733dc3761d3e66534494f701a1a664861a9a7":"aUSDC.eth"},"duration":"627µs 416ns","breakpoints":{},"gas_snapshots":{}}},"warnings":[]},"test/8183-tests/Naming.t.sol:NamingTest":{"duration":"38ms 562µs 375ns","test_results":{"test_naming_derivedErc20Selectors()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":1960001}},"traces":[],"labeled_addresses":{},"duration":"2ms 389µs 541ns","breakpoints":{},"gas_snapshots":{}},"test_naming_hookTopicsAndErrors()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":5183}},"traces":[],"labeled_addresses":{},"duration":"13µs 917ns","breakpoints":{},"gas_snapshots":{}},"test_naming_hookViews()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":1733116}},"traces":[],"labeled_addresses":{"0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x3cdc6b6e442f4a0caa38245fa4fea787d7514bb4":"engine","0x8176041fcc3e7da62bc98139fe56d18cba211fd5":"kernel","0xf3cdfc0454c731c119fc247420fc3e0f4d3a3670":"factory"},"duration":"1ms 246µs 584ns","breakpoints":{},"gas_snapshots":{}},"test_naming_markers()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":4414}},"traces":[],"labeled_addresses":{},"duration":"151µs 542ns","breakpoints":{},"gas_snapshots":{}},"test_naming_marketplaceErrors()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":13118}},"traces":[],"labeled_addresses":{},"duration":"23µs 542ns","breakpoints":{},"gas_snapshots":{}},"test_naming_marketplaceEvents()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":7765}},"traces":[],"labeled_addresses":{},"duration":"10µs 375ns","breakpoints":{},"gas_snapshots":{}},"test_naming_marketplaceFunctions()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":22696}},"traces":[],"labeled_addresses":{},"duration":"36µs 42ns","breakpoints":{},"gas_snapshots":{}},"test_naming_noMandateInABIs()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":71005049}},"traces":[],"labeled_addresses":{},"duration":"31ms 24µs 916ns","breakpoints":{},"gas_snapshots":{}}},"warnings":[]},"test/8183-tests/RulesBindingHook.fork.t.sol:RulesBindingHookForkTest":{"duration":"6ms 23µs 708ns","test_results":{"test_fork_mirrorsMatchDeployedAGW()":{"status":"Skipped","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":0}},"traces":[],"labeled_addresses":{},"duration":"2ms 701µs 875ns","breakpoints":{},"gas_snapshots":{}}},"warnings":[]},"test/8183-tests/RulesBindingHook.t.sol:RulesBindingHookTest":{"duration":"192ms 532µs 500ns","test_results":{"test_activeJobOf_neverSeen_zero()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":17748}},"traces":[],"labeled_addresses":{"0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x9c64e4efa500d7a55b8327003a3f5693a07ca800":"never","0xf5da897cb27ecd131cf70e9611ef85fec8533356":"hookProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner"},"duration":"42µs 458ns","breakpoints":{},"gas_snapshots":{}},"test_activeJobOf_returnsId()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":387603}},"traces":[],"labeled_addresses":{"0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf5da897cb27ecd131cf70e9611ef85fec8533356":"hookProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner"},"duration":"152µs 750ns","breakpoints":{},"gas_snapshots":{}},"test_afterAction_directCall_reverts()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":18763}},"traces":[],"labeled_addresses":{"0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf5da897cb27ecd131cf70e9611ef85fec8533356":"hookProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner"},"duration":"12µs 167ns","breakpoints":{},"gas_snapshots":{}},"test_beforeAction_directCall_reverts()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":22774}},"traces":[],"labeled_addresses":{"0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf5da897cb27ecd131cf70e9611ef85fec8533356":"hookProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner"},"duration":"13µs 42ns","breakpoints":{},"gas_snapshots":{}},"test_freed_afterClaimRefund_unhooked()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":572825}},"traces":[],"labeled_addresses":{"0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf5da897cb27ecd131cf70e9611ef85fec8533356":"hookProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner"},"duration":"235µs 916ns","breakpoints":{},"gas_snapshots":{}},"test_freed_afterComplete()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":617121}},"traces":[],"labeled_addresses":{"0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf5da897cb27ecd131cf70e9611ef85fec8533356":"hookProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner"},"duration":"190µs 333ns","breakpoints":{},"gas_snapshots":{}},"test_freed_afterDetachThenRefund()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":567946}},"traces":[],"labeled_addresses":{"0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf5da897cb27ecd131cf70e9611ef85fec8533356":"hookProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner"},"duration":"162µs 667ns","breakpoints":{},"gas_snapshots":{}},"test_freed_afterReject()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":579218}},"traces":[],"labeled_addresses":{"0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf5da897cb27ecd131cf70e9611ef85fec8533356":"hookProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner"},"duration":"156µs 917ns","breakpoints":{},"gas_snapshots":{}},"test_fund_bindsRules()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":362643}},"traces":[],"labeled_addresses":{"0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf5da897cb27ecd131cf70e9611ef85fec8533356":"hookProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner"},"duration":"103µs 500ns","breakpoints":{},"gas_snapshots":{}},"test_initialize_setsState()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":29227}},"traces":[],"labeled_addresses":{"0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf5da897cb27ecd131cf70e9611ef85fec8533356":"hookProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner"},"duration":"29µs 459ns","breakpoints":{},"gas_snapshots":{}},"test_initialize_twice_reverts()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":22733}},"traces":[],"labeled_addresses":{"0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf5da897cb27ecd131cf70e9611ef85fec8533356":"hookProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner"},"duration":"11µs 458ns","breakpoints":{},"gas_snapshots":{}},"test_initialize_zeroEngine_reverts()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":95895}},"traces":[],"labeled_addresses":{"0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf5da897cb27ecd131cf70e9611ef85fec8533356":"hookProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner"},"duration":"27µs 625ns","breakpoints":{},"gas_snapshots":{}},"test_initialize_zeroFactory_reverts()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":96227}},"traces":[],"labeled_addresses":{"0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf5da897cb27ecd131cf70e9611ef85fec8533356":"hookProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner"},"duration":"18µs 875ns","breakpoints":{},"gas_snapshots":{}},"test_initialize_zeroKernel_reverts()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":96135}},"traces":[],"labeled_addresses":{"0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf5da897cb27ecd131cf70e9611ef85fec8533356":"hookProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner"},"duration":"18µs 417ns","breakpoints":{},"gas_snapshots":{}},"test_invalidOptParams_lengths()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":690627}},"traces":[],"labeled_addresses":{"0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf5da897cb27ecd131cf70e9611ef85fec8533356":"hookProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner"},"duration":"255µs 500ns","breakpoints":{},"gas_snapshots":{}},"test_notAnAGW_contractClient()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":341433}},"traces":[],"labeled_addresses":{"0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf5da897cb27ecd131cf70e9611ef85fec8533356":"hookProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner"},"duration":"141µs 167ns","breakpoints":{},"gas_snapshots":{}},"test_notAnAGW_eoaClient()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":241551}},"traces":[],"labeled_addresses":{"0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf5da897cb27ecd131cf70e9611ef85fec8533356":"hookProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xc593195b6b4f26174151fded0b8079566f791aac":"eoaClient","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner"},"duration":"125µs 833ns","breakpoints":{},"gas_snapshots":{}},"test_rulesNotLive_neverGranted()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":235059}},"traces":[],"labeled_addresses":{"0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf5da897cb27ecd131cf70e9611ef85fec8533356":"hookProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner"},"duration":"159µs 708ns","breakpoints":{},"gas_snapshots":{}},"test_rulesNotLive_revoked()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":236290}},"traces":[],"labeled_addresses":{"0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf5da897cb27ecd131cf70e9611ef85fec8533356":"hookProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner"},"duration":"154µs 417ns","breakpoints":{},"gas_snapshots":{}},"test_rulesOfAnotherWallet_notLiveHere()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":287307}},"traces":[],"labeled_addresses":{"0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf5da897cb27ecd131cf70e9611ef85fec8533356":"hookProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x4dad47a4ad9ac11e30d045132b59f708835ff35b":"otherAGW"},"duration":"248µs 625ns","breakpoints":{},"gas_snapshots":{}},"test_samePermissionId_differentAGWs_bindIndependently()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":682538}},"traces":[],"labeled_addresses":{"0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf5da897cb27ecd131cf70e9611ef85fec8533356":"hookProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd10a536aa09b514997d5617f55b79a9962ec8384":"agw2","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner"},"duration":"378µs 417ns","breakpoints":{},"gas_snapshots":{}},"test_sameRules_sequentialJobs_allowed()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":568190}},"traces":[],"labeled_addresses":{"0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf5da897cb27ecd131cf70e9611ef85fec8533356":"hookProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner"},"duration":"288µs 625ns","breakpoints":{},"gas_snapshots":{}},"test_scope_hooklessJob_fundsWhileBusy()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":498652}},"traces":[],"labeled_addresses":{"0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf5da897cb27ecd131cf70e9611ef85fec8533356":"hookProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner"},"duration":"112µs 83ns","breakpoints":{},"gas_snapshots":{}},"test_scope_otherHookJob_doesNotTouchThisHook()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":1859421}},"traces":[],"labeled_addresses":{"0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf5da897cb27ecd131cf70e9611ef85fec8533356":"hookProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner"},"duration":"273µs 375ns","breakpoints":{},"gas_snapshots":{}},"test_secondJob_whileFirstFunded_reverts()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":511778}},"traces":[],"labeled_addresses":{"0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf5da897cb27ecd131cf70e9611ef85fec8533356":"hookProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner"},"duration":"227µs 416ns","breakpoints":{},"gas_snapshots":{}},"test_secondJob_whileFirstSubmitted_reverts()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":529573}},"traces":[],"labeled_addresses":{"0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf5da897cb27ecd131cf70e9611ef85fec8533356":"hookProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner"},"duration":"345µs 84ns","breakpoints":{},"gas_snapshots":{}},"test_storageLayout_bySlot()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":487324}},"traces":[],"labeled_addresses":{"0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf5da897cb27ecd131cf70e9611ef85fec8533356":"hookProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner"},"duration":"324µs 875ns","breakpoints":{},"gas_snapshots":{}},"test_transferFailsAfterHook_rollsBackBinding()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":406252}},"traces":[],"labeled_addresses":{"0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xc3c6ad6c2acbfd173dc55f5c2014b8a4feb6217e":"agw3-noAllowance","0xf5da897cb27ecd131cf70e9611ef85fec8533356":"hookProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner"},"duration":"137µs 917ns","breakpoints":{},"gas_snapshots":{}},"test_twoAGWs_eachHoldALiveJob()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":688988}},"traces":[],"labeled_addresses":{"0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf5da897cb27ecd131cf70e9611ef85fec8533356":"hookProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd10a536aa09b514997d5617f55b79a9962ec8384":"agw2","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner"},"duration":"354µs 625ns","breakpoints":{},"gas_snapshots":{}},"test_upgrade_byNonOwner_reverts()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":971931}},"traces":[],"labeled_addresses":{"0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf5da897cb27ecd131cf70e9611ef85fec8533356":"hookProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner"},"duration":"104µs 416ns","breakpoints":{},"gas_snapshots":{}},"test_upgrade_preservesBindingAndBlock()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":1480699}},"traces":[],"labeled_addresses":{"0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf5da897cb27ecd131cf70e9611ef85fec8533356":"hookProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner"},"duration":"181µs 333ns","breakpoints":{},"gas_snapshots":{}},"test_zeroBudgetJob_bindsNormally()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":275568}},"traces":[],"labeled_addresses":{"0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0xf5da897cb27ecd131cf70e9611ef85fec8533356":"hookProxyAdminOwner","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner"},"duration":"94µs 41ns","breakpoints":{},"gas_snapshots":{}}},"warnings":[]},"test/8183-tests/UniversalMarketplace.conformance.t.sol:UniversalMarketplaceConformanceTest":{"duration":"10ms 810µs 208ns","test_results":{"test_MC01_lendingExample_equalsV2Doc()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":191300}},"traces":[],"labeled_addresses":{"0xd00966eaf28611743d149d346a1b20f6e0eb4196":"AavePool.eth","0x33474942344753f636e5af8c437d1d00eb01c6c2":"agw","0x913733dc3761d3e66534494f701a1a664861a9a7":"aUSDC.eth","0x914d024d703c0df6f9a32b21c95b3b2de71f8467":"Spark.eth","0x0df093b0529a686c0f0a153ad18e2672215fbc51":"WETH.base","0xbbe819a3dd1113e30925014563ca18e9ea942501":"MorphoVault.eth","0x41bffff0ebab0ff77c37421d0f3f19f48a04cb1f":"USDC.eth"},"duration":"636µs 625ns","breakpoints":{},"gas_snapshots":{}},"test_MC02_swapExample_equalsV2Doc()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":127513}},"traces":[],"labeled_addresses":{"0xd00966eaf28611743d149d346a1b20f6e0eb4196":"AavePool.eth","0x33474942344753f636e5af8c437d1d00eb01c6c2":"agw","0x913733dc3761d3e66534494f701a1a664861a9a7":"aUSDC.eth","0x914d024d703c0df6f9a32b21c95b3b2de71f8467":"Spark.eth","0x0df093b0529a686c0f0a153ad18e2672215fbc51":"WETH.base","0xbbe819a3dd1113e30925014563ca18e9ea942501":"MorphoVault.eth","0x41bffff0ebab0ff77c37421d0f3f19f48a04cb1f":"USDC.eth"},"duration":"197µs 208ns","breakpoints":{},"gas_snapshots":{}},"test_MC03_orAndAtLeastExamples()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":531999}},"traces":[],"labeled_addresses":{"0xd00966eaf28611743d149d346a1b20f6e0eb4196":"AavePool.eth","0x33474942344753f636e5af8c437d1d00eb01c6c2":"agw","0x913733dc3761d3e66534494f701a1a664861a9a7":"aUSDC.eth","0x914d024d703c0df6f9a32b21c95b3b2de71f8467":"Spark.eth","0x0df093b0529a686c0f0a153ad18e2672215fbc51":"WETH.base","0xbbe819a3dd1113e30925014563ca18e9ea942501":"MorphoVault.eth","0x41bffff0ebab0ff77c37421d0f3f19f48a04cb1f":"USDC.eth"},"duration":"896µs 83ns","breakpoints":{},"gas_snapshots":{}},"test_MC04_referenceDecoder_agrees()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":884396}},"traces":[],"labeled_addresses":{"0xd00966eaf28611743d149d346a1b20f6e0eb4196":"AavePool.eth","0x33474942344753f636e5af8c437d1d00eb01c6c2":"agw","0x913733dc3761d3e66534494f701a1a664861a9a7":"aUSDC.eth","0x914d024d703c0df6f9a32b21c95b3b2de71f8467":"Spark.eth","0x0df093b0529a686c0f0a153ad18e2672215fbc51":"WETH.base","0xbbe819a3dd1113e30925014563ca18e9ea942501":"MorphoVault.eth","0x41bffff0ebab0ff77c37421d0f3f19f48a04cb1f":"USDC.eth"},"duration":"1ms 586µs 167ns","breakpoints":{},"gas_snapshots":{}},"test_MC05_fieldOrder()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":137247}},"traces":[],"labeled_addresses":{"0xd00966eaf28611743d149d346a1b20f6e0eb4196":"AavePool.eth","0x33474942344753f636e5af8c437d1d00eb01c6c2":"agw","0x913733dc3761d3e66534494f701a1a664861a9a7":"aUSDC.eth","0x914d024d703c0df6f9a32b21c95b3b2de71f8467":"Spark.eth","0x0df093b0529a686c0f0a153ad18e2672215fbc51":"WETH.base","0xbbe819a3dd1113e30925014563ca18e9ea942501":"MorphoVault.eth","0x41bffff0ebab0ff77c37421d0f3f19f48a04cb1f":"USDC.eth"},"duration":"194µs 583ns","breakpoints":{},"gas_snapshots":{}}},"warnings":[]},"test/8183-tests/UniversalMarketplace.fork.t.sol:UniversalMarketplaceForkTest":{"duration":"839µs 916ns","test_results":{"test_fork_openJob_realAGWv6()":{"status":"Skipped","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":0}},"traces":[],"labeled_addresses":{"0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0x540da3418be99da0614998034fcb817e9d8a0644":"forkAdmin","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x238ec72e0743bd4c21497d4157854dd3a1dd2f0d":"forkRelayer","0x22aa0d0bcc922d549618bd1ef8253cc8dee5a3cc":"forkProvider"},"duration":"10µs 791ns","breakpoints":{},"gas_snapshots":{}}},"warnings":[]},"test/8183-tests/UniversalMarketplace.t.sol:UniversalMarketplaceTest":{"duration":"50ms 687µs 750ns","test_results":{"test_MB01_agentMismatch()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":3187475}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"1ms 134µs 834ns","breakpoints":{},"gas_snapshots":{}},"test_MB02_shape()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":3804741}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"2ms 62µs 958ns","breakpoints":{},"gas_snapshots":{}},"test_MB03_terms()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":6080412}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"10ms 415µs 667ns","breakpoints":{},"gas_snapshots":{}},"test_MB04_perCallMustEqualPrincipal()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":7216863}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"1ms 323µs 958ns","breakpoints":{},"gas_snapshots":{}},"test_ML01_setAgentCardActive()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":2735675}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"344µs 292ns","breakpoints":{},"gas_snapshots":{}},"test_ML02_disableAgentCard()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":2940853}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"626µs 542ns","breakpoints":{},"gas_snapshots":{}},"test_ML03_verifyAgentCard()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":5217626}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"1ms 869µs 333ns","breakpoints":{},"gas_snapshots":{}},"test_ML04_verify_racedByUpdate()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":2712867}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"799µs 958ns","breakpoints":{},"gas_snapshots":{}},"test_ML05_revokeVerification()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":2607531}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"496µs 667ns","breakpoints":{},"gas_snapshots":{}},"test_ML06_update_updatesEveryMutableField()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":2694633}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"1ms 535µs 334ns","breakpoints":{},"gas_snapshots":{}},"test_ML07_update_clearsVerification()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":2692771}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"930µs 916ns","breakpoints":{},"gas_snapshots":{}},"test_ML08_update_access()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":2696245}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"1ms 227µs 500ns","breakpoints":{},"gas_snapshots":{}},"test_ML09_update_chainImmutable()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":2671877}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"929µs","breakpoints":{},"gas_snapshots":{}},"test_ML10_update_validatesLikeRegistration()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":2686095}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"493µs 750ns","breakpoints":{},"gas_snapshots":{}},"test_ML11_update_invalidatesOldIntents()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":3151497}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"1ms 15µs 625ns","breakpoints":{},"gas_snapshots":{}},"test_ML12_update_leavesOpenedJobsUntouched()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":7005782}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"1ms 288µs 125ns","breakpoints":{},"gas_snapshots":{}},"test_ML13_openJob_afterUpdate_usesNewContent()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":7273277}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"1ms 340µs 791ns","breakpoints":{},"gas_snapshots":{}},"test_MR01_registerAgentCard_storesEverythingAndEmits()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":2668135}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"309µs 750ns","breakpoints":{},"gas_snapshots":{}},"test_MR02_providerAndActiveAreContractWritten()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":2686013}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"307µs 417ns","breakpoints":{},"gas_snapshots":{}},"test_MR03_eachInvalidCardField_reverts()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":6026036}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"4ms 308µs 708ns","breakpoints":{},"gas_snapshots":{}},"test_MR04_pushChain_refused()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":133192}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"220µs 750ns","breakpoints":{},"gas_snapshots":{}},"test_MR05_unsupportedEvmChain_refused()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":76069}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"182µs 750ns","breakpoints":{},"gas_snapshots":{}},"test_MR06_assetTeeth()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":3180147}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xf286838c4411fb1f95258c7c4af513b7dcb8a03f":"codelessAsset","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"2ms 89µs 167ns","breakpoints":{},"gas_snapshots":{}},"test_MR07_rulesErrorsSurface()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":112309}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"264µs 41ns","breakpoints":{},"gas_snapshots":{}},"test_MR08_criteriaNotJudgedAtRegistration()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":3212964}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"1ms 23µs 791ns","breakpoints":{},"gas_snapshots":{}},"test_MR09_assetIndependent()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":7099876}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"1ms 61µs 84ns","breakpoints":{},"gas_snapshots":{}},"test_MR10_paused()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":95515}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"86µs 125ns","breakpoints":{},"gas_snapshots":{}},"test_MR11_onePerProvider()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":4628637}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"430µs 42ns","breakpoints":{},"gas_snapshots":{}},"test_MR12_paymentTokenGuard()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":2922156}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"631µs 875ns","breakpoints":{},"gas_snapshots":{}},"test_MR13_everyAssetOnChain()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":2906776}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0xe45bd004b7672615dc2c835bab76232ecc41f6f2":"codelessAsset1","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"555µs 83ns","breakpoints":{},"gas_snapshots":{}},"test_MR14_rulesErrorsSurface()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":2888090}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"562µs 375ns","breakpoints":{},"gas_snapshots":{}},"test_MS01_freshWallet_happyPath()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":7327047}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"1ms 959µs 917ns","breakpoints":{},"gas_snapshots":{}},"test_MS02_movesNoFunds()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":7070726}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"1ms 864µs 834ns","breakpoints":{},"gas_snapshots":{}},"test_MS03_existingWallet_skipsDeploy()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":9077923}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"1ms 771µs 333ns","breakpoints":{},"gas_snapshots":{}},"test_MS04_existingWallet_wrongOwner()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":7427839}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"1ms 619µs 334ns","breakpoints":{},"gas_snapshots":{}},"test_MS04b_factoryDeploysElsewhere_agwMismatch()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":4309613}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"1ms 811µs 459ns","breakpoints":{},"gas_snapshots":{}},"test_MS05_cardInactive_unknown()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":7054591}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"3ms 368µs 167ns","breakpoints":{},"gas_snapshots":{}},"test_MS06_cardVersionMismatch()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":2847572}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"557µs 834ns","breakpoints":{},"gas_snapshots":{}},"test_MS07_principalOutOfRange()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":11845553}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"7ms 438µs 709ns","breakpoints":{},"gas_snapshots":{}},"test_MS08_expiryOutOfRange()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":11844962}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"6ms 336µs 708ns","breakpoints":{},"gas_snapshots":{}},"test_MS09_executeByOutOfRange()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":11845880}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"4ms 726µs 333ns","breakpoints":{},"gas_snapshots":{}},"test_MS10_params()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":10721615}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"3ms 165µs 208ns","breakpoints":{},"gas_snapshots":{}},"test_MS11_intentWalletAndExecutor()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":3115903}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"2ms 559µs 667ns","breakpoints":{},"gas_snapshots":{}},"test_MS12_intentExecMismatch_everyBoundInput()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":5005868}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"6ms 338µs 291ns","breakpoints":{},"gas_snapshots":{}},"test_MS13_intentSessionMismatch_noStateOnFailure()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":2952976}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"725µs 500ns","breakpoints":{},"gas_snapshots":{}},"test_MS14_oneLiveJob()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":14440082}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"4ms 846µs 750ns","breakpoints":{},"gas_snapshots":{}},"test_MS15_jobVerification()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":14008060}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"4ms 183µs 458ns","breakpoints":{},"gas_snapshots":{}},"test_MS16_providerIsEvaluator_afterSetEvaluator()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":2844607}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"547µs 625ns","breakpoints":{},"gas_snapshots":{}},"test_MS17_8183Continuation_feeEnforcedAtFund()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":7400238}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"2ms 835µs 167ns","breakpoints":{},"gas_snapshots":{}},"test_MS18_gasCeilings()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":9126893}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"1ms 768µs 125ns","breakpoints":{},"gas_snapshots":{}},"test_MS19_openJob_twoAssets_principalMarkers()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":7149268}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"1ms 867µs 958ns","breakpoints":{},"gas_snapshots":{}},"test_MS20_openJob_trancheCard()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":7366287}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"2ms 359µs","breakpoints":{},"gas_snapshots":{}},"test_MS21_activeJobOf()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":11840509}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x1159dbc912518f64b56b88f2659e854296e8d2b2":"neverSeen","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"4ms 733µs 750ns","breakpoints":{},"gas_snapshots":{}},"test_MS22_envelopeVersion_named()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":2889688}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"1ms 626µs 542ns","breakpoints":{},"gas_snapshots":{}},"test_MV01_getAgentCard_fullView()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":2758254}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"688µs 834ns","breakpoints":{},"gas_snapshots":{}},"test_MV02_computeCEA()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":54010}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0xd92f78e25c59ea89e560d580f0bf875b9aacdc01":"anyAGW","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"65µs 917ns","breakpoints":{},"gas_snapshots":{}},"test_MV03_ceaRotation_staleCaught()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":7805098}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x2256a349222d618181d0fd035e2949095230f6eb":"ceaProxyImplV2","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"4ms 710µs 375ns","breakpoints":{},"gas_snapshots":{}},"test_MV04_buildCreateJobCalldata()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":6829964}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"8ms 949µs 666ns","breakpoints":{},"gas_snapshots":{}},"test_MV05_previewIntent_roundTrips()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":7398628}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"3ms 414µs 833ns","breakpoints":{},"gas_snapshots":{}},"test_MV06_adminSetters()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":136323}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x933ef277ef1da53ebdaca202a0cffc3e399aeab2":"evaluatorV2","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"111µs 250ns","breakpoints":{},"gas_snapshots":{}},"test_MV07_pause()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":7107418}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"1ms 86µs","breakpoints":{},"gas_snapshots":{}},"test_MV08_initialize()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":37019622}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"817µs 958ns","breakpoints":{},"gas_snapshots":{}},"test_MV09_storageLayout_bySlot()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":9852365}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"1ms 539µs 375ns","breakpoints":{},"gas_snapshots":{}},"test_MV10_upgrade_preservesState()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":16222142}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"2ms 230µs 83ns","breakpoints":{},"gas_snapshots":{}},"test_MV11_setCEADeployment_clear()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":2963606}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"721µs 208ns","breakpoints":{},"gas_snapshots":{}},"test_MV12_agentRating()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":67110}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"37µs 167ns","breakpoints":{},"gas_snapshots":{}},"test_MV13_version()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":19934}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"20µs 667ns","breakpoints":{},"gas_snapshots":{}},"test_MV14_noPerChainPause()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":28893490}},"traces":[],"labeled_addresses":{"0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2"},"duration":"11ms 571µs 291ns","breakpoints":{},"gas_snapshots":{}}},"warnings":[]},"test/8183-tests/UniversalMarketplaceRules.t.sol:UniversalMarketplaceRulesTest":{"duration":"706ms 948µs 542ns","test_results":{"testFuzz_MT11_principalBinding(uint256)":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Fuzz":{"first_case":{"calldata":"0xbcd8cd2b00000000000000000000000000214feb2caf420de2e7d1a5d26675eab6a0e2bb","gas":279212,"stipend":21420},"runs":1024,"mean_gas":257643,"median_gas":257556,"failed_corpus_replays":0}},"traces":[],"labeled_addresses":{"0xb941317fab7e0feb9d890585be19a8c9923d50b5":"cea","0xd7375ad69845c24062465f67bfdeb04dfe871b22":"pool","0x5fa59300b772d54451e6921c4a0db8fd3ddad8ce":"agent","0x8ae775926accb6f39f230a90d051e80ed3fe31ee":"pUSDC.sepolia","0xf151080efb137c79dfe753cf74605c3df046d681":"pETH.sepolia","0x85f1a0ec1abb81e37317103d10d8877d35328693":"USDC"},"duration":"705ms 989µs 667ns","breakpoints":{},"gas_snapshots":{}},"test_MT01_validate_returnsTokens()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":84743}},"traces":[],"labeled_addresses":{"0xb941317fab7e0feb9d890585be19a8c9923d50b5":"cea","0xd7375ad69845c24062465f67bfdeb04dfe871b22":"pool","0x5fa59300b772d54451e6921c4a0db8fd3ddad8ce":"agent","0x8ae775926accb6f39f230a90d051e80ed3fe31ee":"pUSDC.sepolia","0xf151080efb137c79dfe753cf74605c3df046d681":"pETH.sepolia","0x85f1a0ec1abb81e37317103d10d8877d35328693":"USDC"},"duration":"288µs","breakpoints":{},"gas_snapshots":{}},"test_MT02_assetChecks()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":207081}},"traces":[],"labeled_addresses":{"0xb941317fab7e0feb9d890585be19a8c9923d50b5":"cea","0xd7375ad69845c24062465f67bfdeb04dfe871b22":"pool","0x5fa59300b772d54451e6921c4a0db8fd3ddad8ce":"agent","0x8ae775926accb6f39f230a90d051e80ed3fe31ee":"pUSDC.sepolia","0xf151080efb137c79dfe753cf74605c3df046d681":"pETH.sepolia","0x85f1a0ec1abb81e37317103d10d8877d35328693":"USDC"},"duration":"447µs 500ns","breakpoints":{},"gas_snapshots":{}},"test_MT03_principalMarkers()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":205678}},"traces":[],"labeled_addresses":{"0xb941317fab7e0feb9d890585be19a8c9923d50b5":"cea","0xd7375ad69845c24062465f67bfdeb04dfe871b22":"pool","0x5fa59300b772d54451e6921c4a0db8fd3ddad8ce":"agent","0x8ae775926accb6f39f230a90d051e80ed3fe31ee":"pUSDC.sepolia","0xf151080efb137c79dfe753cf74605c3df046d681":"pETH.sepolia","0x85f1a0ec1abb81e37317103d10d8877d35328693":"USDC"},"duration":"291µs 834ns","breakpoints":{},"gas_snapshots":{}},"test_MT04_allowListAndPins()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":871036}},"traces":[],"labeled_addresses":{"0xb941317fab7e0feb9d890585be19a8c9923d50b5":"cea","0xd7375ad69845c24062465f67bfdeb04dfe871b22":"pool","0x5fa59300b772d54451e6921c4a0db8fd3ddad8ce":"agent","0x8ae775926accb6f39f230a90d051e80ed3fe31ee":"pUSDC.sepolia","0xf151080efb137c79dfe753cf74605c3df046d681":"pETH.sepolia","0x85f1a0ec1abb81e37317103d10d8877d35328693":"USDC"},"duration":"1ms 140µs 875ns","breakpoints":{},"gas_snapshots":{}},"test_MT05_duplicates()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":162199}},"traces":[],"labeled_addresses":{"0xb941317fab7e0feb9d890585be19a8c9923d50b5":"cea","0xd7375ad69845c24062465f67bfdeb04dfe871b22":"pool","0x5fa59300b772d54451e6921c4a0db8fd3ddad8ce":"agent","0x8ae775926accb6f39f230a90d051e80ed3fe31ee":"pUSDC.sepolia","0xf151080efb137c79dfe753cf74605c3df046d681":"pETH.sepolia","0xe03eaf47d03484b6a07f6db1c9340590b20b4630":"uniswap","0x85f1a0ec1abb81e37317103d10d8877d35328693":"USDC"},"duration":"257µs 250ns","breakpoints":{},"gas_snapshots":{}},"test_MT06_erc20Rules()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":626218}},"traces":[],"labeled_addresses":{"0xb941317fab7e0feb9d890585be19a8c9923d50b5":"cea","0xd7375ad69845c24062465f67bfdeb04dfe871b22":"pool","0x5fa59300b772d54451e6921c4a0db8fd3ddad8ce":"agent","0x8ae775926accb6f39f230a90d051e80ed3fe31ee":"pUSDC.sepolia","0xf151080efb137c79dfe753cf74605c3df046d681":"pETH.sepolia","0x85f1a0ec1abb81e37317103d10d8877d35328693":"USDC"},"duration":"777µs 750ns","breakpoints":{},"gas_snapshots":{}},"test_MT07_match_happy()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":244096}},"traces":[],"labeled_addresses":{"0xb941317fab7e0feb9d890585be19a8c9923d50b5":"cea","0xd7375ad69845c24062465f67bfdeb04dfe871b22":"pool","0x5fa59300b772d54451e6921c4a0db8fd3ddad8ce":"agent","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0x8ae775926accb6f39f230a90d051e80ed3fe31ee":"pUSDC.sepolia","0xf151080efb137c79dfe753cf74605c3df046d681":"pETH.sepolia","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0x9d5c72ad9b728cae519e74da03ef7eb140332ee3":"validator","0x85f1a0ec1abb81e37317103d10d8877d35328693":"USDC"},"duration":"589µs 958ns","breakpoints":{},"gas_snapshots":{}},"test_MT08_match_eachError()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":2039826}},"traces":[],"labeled_addresses":{"0xb941317fab7e0feb9d890585be19a8c9923d50b5":"cea","0xd7375ad69845c24062465f67bfdeb04dfe871b22":"pool","0x5fa59300b772d54451e6921c4a0db8fd3ddad8ce":"agent","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0x8ae775926accb6f39f230a90d051e80ed3fe31ee":"pUSDC.sepolia","0xf151080efb137c79dfe753cf74605c3df046d681":"pETH.sepolia","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0x748960e2d176d9033d500d7aa997cc2c444f57bc":"other","0x9d5c72ad9b728cae519e74da03ef7eb140332ee3":"validator","0x85f1a0ec1abb81e37317103d10d8877d35328693":"USDC"},"duration":"4ms 725µs 333ns","breakpoints":{},"gas_snapshots":{}},"test_MT09_match_pins()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":320012}},"traces":[],"labeled_addresses":{"0xb941317fab7e0feb9d890585be19a8c9923d50b5":"cea","0xd7375ad69845c24062465f67bfdeb04dfe871b22":"pool","0x85b44980ad19a3456427949b7b8fb0cfde32aced":"otherCEA","0x5fa59300b772d54451e6921c4a0db8fd3ddad8ce":"agent","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0x8ae775926accb6f39f230a90d051e80ed3fe31ee":"pUSDC.sepolia","0xf151080efb137c79dfe753cf74605c3df046d681":"pETH.sepolia","0x82d23435a5bd3da279a0666c44580817cbb0b58f":"otherSpender","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0x9d5c72ad9b728cae519e74da03ef7eb140332ee3":"validator","0x85f1a0ec1abb81e37317103d10d8877d35328693":"USDC"},"duration":"879µs 83ns","breakpoints":{},"gas_snapshots":{}},"test_MT10_malformedInputs()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":116987}},"traces":[],"labeled_addresses":{"0xb941317fab7e0feb9d890585be19a8c9923d50b5":"cea","0xd7375ad69845c24062465f67bfdeb04dfe871b22":"pool","0x5fa59300b772d54451e6921c4a0db8fd3ddad8ce":"agent","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0x8ae775926accb6f39f230a90d051e80ed3fe31ee":"pUSDC.sepolia","0xf151080efb137c79dfe753cf74605c3df046d681":"pETH.sepolia","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0x9d5c72ad9b728cae519e74da03ef7eb140332ee3":"validator","0x85f1a0ec1abb81e37317103d10d8877d35328693":"USDC"},"duration":"366µs 125ns","breakpoints":{},"gas_snapshots":{}}},"warnings":[]}} diff --git a/plan/marketplace/research/2026-10-20/dependency-pins.json b/plan/marketplace/research/2026-10-20/dependency-pins.json new file mode 100644 index 00000000..17f16769 --- /dev/null +++ b/plan/marketplace/research/2026-10-20/dependency-pins.json @@ -0,0 +1,34 @@ +[ + { + "path": "lib/forge-std", + "sha": "3b20d60d14b343ee4f908cb8079495c07f5e8981", + "archived": true, + "skipped_links": [] + }, + { + "path": "lib/openzeppelin-contracts", + "sha": "e4f70216d759d8e6a64144a9e1f7bbeed78e7079", + "archived": true, + "skipped_links": [] + }, + { + "path": "lib/openzeppelin-contracts-upgradeable", + "sha": "0ed1f55fa6a2e50c062985f7a3cbc79f4029d85d", + "archived": true, + "skipped_links": [] + }, + { + "path": "lib/openzeppelin-foundry-upgrades", + "sha": "cbce1e00305e943aa1661d43f41e5ac72c662b07", + "archived": true, + "skipped_links": [] + }, + { + "path": "lib/push-agentic-wallets", + "sha": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "archived": true, + "skipped_links": [ + "lib/push-chain-core-contracts" + ] + } +] diff --git a/plan/marketplace/research/2026-10-20/evaluator-8059817/JobSpecTypes.sol b/plan/marketplace/research/2026-10-20/evaluator-8059817/JobSpecTypes.sol new file mode 100644 index 00000000..10ea0911 --- /dev/null +++ b/plan/marketplace/research/2026-10-20/evaluator-8059817/JobSpecTypes.sol @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +/// @title JobSpecTypes — the evaluation criteria of an ERC-8183 job +/// @notice One definition, shared by everything that writes or reads a job's criteria: +/// - UniversalMarketplace builds a `JobSpec` and stores `abi.encode(spec)` as the job's description; +/// - the UniversalHook decodes it at `fund` and freezes it; +/// - the UniversalEvaluator fires its reads and judges its checks and logic. +/// @dev - Source: `docs-internal/Universal Evaluator V2 Design`, plus `origin` (marketplace PRD decision Z7). +/// - Field order is ABI. Never reorder, never insert; a change here changes every description. + +/// @notice How a check compares. BOOLEAN / COMPARE: the `left` side against `target` · NUMBER / PERCENTAGE: `left` against `right`. +enum Evaluation { + BOOLEAN, + COMPARE, + NUMBER, + PERCENTAGE +} + +/// @notice The comparison operator: == != > >= < <=. +enum Operation { + EQUAL, + NOT_EQUAL, + GREATER_THAN, + GREATER_OR_EQUAL, + LESS_THAN, + LESS_OR_EQUAL +} + +/// @notice One step of the pass logic. CHECK: one check · ALL / ANY / AT_LEAST: combine children. +enum LogicKind { + CHECK, + ALL, + ANY, + AT_LEAST +} + +/// @notice Who may replace a job's criteria before it is funded: the provider in `setBudget`, the client in `fund`. +/// @dev - The flag is always the one in the `createJob` description; a replacement must carry the same flag. +/// - `BOTH` is the zero value, so a spec that never sets the flag can be replaced by either side. +enum AllowedMutability { + BOTH, + NONE, + CLIENT, + PROVIDER +} + +/// @notice When a read is taken: after the provider's execution (at `submit`) or before it (at `fund`). +enum ReadAt { + POST_EXECUTION, + PRE_EXECUTION +} + +/// @notice One contract call on one chain, at one moment, and which value in its answer to use. +struct Read { + // namespace only ("eip155"), with chainId separate — the Read State split (AGW doc D6); + // AgentCard.chainNamespace is the full CAIP-2 string + string chainNamespace; + string chainId; // e.g. "8453" + uint16 minConfirmations; // confirmations this chain needs before the answer counts + address target; // the contract to call + bytes4 selector; // the view function + bytes args; // abi-encoded arguments + bytes outputs; // the function's return types, as T_* codes + uint8[] field; // which returned value, by ABI position: [0] = 1st return value, [0, 2] = its 3rd field + ReadAt at; // read at the block recorded at `fund` (PRE) or fixed at `submit` (POST) +} + +/// @notice One comparison. Each side is the sum of its reads. BOOLEAN `left == target` · COMPARE `Σleft op target` · +/// NUMBER `(Σleft - Σright) op target` · PERCENTAGE `(Σleft - Σright) / Σright op target`, in basis points. +struct Check { + uint8[] left; // indexes into reads, increasing · BOOLEAN: exactly one + uint8[] right; // indexes into reads, increasing, none in `left` · NUMBER / PERCENTAGE: at least one · BOOLEAN / COMPARE: none + Evaluation evaluation; + Operation operation; + int256 target; // in the contract's own units +} + +/// @notice One step of the pass logic. Children always have a higher index than their parent. +struct Logic { + LogicKind kind; + uint8 check; // CHECK only: index into checks + uint8[] children; // ALL / ANY / AT_LEAST: indexes into logic, each greater than this entry's own + uint8 k; // AT_LEAST only: how many children must pass +} + +/// @notice A job's criteria. `logic[0]` is the root: the job passes if it passes. +struct JobSpec { + uint64 executeBy; // the provider must execute before this + uint64 failFinalAt; // a FAIL only counts from a verify started after this + Read[] reads; + Check[] checks; + Logic[] logic; + AllowedMutability allowedMutability; // who may replace these criteria before `fund`; marketplace jobs are NONE + bytes32 origin; // keccak256(abi.encode(marketplace, cardId, cardVersion, principal)); opaque to hook and evaluator +} + +// ─────────────────────────────── return-type codes (`Read.outputs`) ─────────────────────────────── + +uint8 constant T_UINT = 1; +uint8 constant T_INT = 2; +uint8 constant T_BOOL = 3; +uint8 constant T_ADDRESS = 4; +uint8 constant T_BYTESN = 5; +uint8 constant T_BYTES = 6; +uint8 constant T_STRING = 7; +uint8 constant T_TUPLE = 8; +uint8 constant T_ARRAY = 9; +uint8 constant T_FIXED_ARRAY = 10; + +// ─────────────────────────────── limits ─────────────────────────────── + +uint256 constant MAX_READS = 32; +uint256 constant MAX_CHECKS = 16; +uint256 constant MAX_LOGIC = 32; +uint256 constant MAX_TERMS = 64; // read indexes across every check's sides; bounds a callback's work diff --git a/plan/marketplace/research/2026-10-20/evaluator-8059817/UniversalEvaluator.sol b/plan/marketplace/research/2026-10-20/evaluator-8059817/UniversalEvaluator.sol new file mode 100644 index 00000000..d465dc66 --- /dev/null +++ b/plan/marketplace/research/2026-10-20/evaluator-8059817/UniversalEvaluator.sol @@ -0,0 +1,801 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; + +import {IAgenticCommerce} from "../interfaces/IAgenticCommerce.sol"; +import {IUniversalEvaluator} from "../interfaces/IUniversalEvaluator.sol"; +import {IUniversalCallback} from "../../interfaces/IUniversalCallback.sol"; +import {RequestStatus, MAX_CALLBACK_GAS_LIMIT} from "../../libraries/ReadTypes.sol"; +import {JobSpec, Read, Check, ReadAt} from "../libraries/JobSpecTypes.sol"; +import { + Answer, + Verdict, + OwnerCheck, + PackedCheck, + ReadPlan, + ReadConfig, + MAX_RESULT_LENGTH, + MAX_DESCRIPTION_LENGTH, + IAGWCheckpoints, + IUniversalCoreHeights, + IReadStateDomains +} from "./EvaluationTypes.sol"; +import {JobSpecLib} from "./JobSpecLib.sol"; +import {EvmReadLib, FireParams} from "./EvmReadLib.sol"; +import {UniversalEvaluatorErrors, JobSpecErrors} from "../libraries/Errors.sol"; + +/// @title UniversalEvaluator +/// @notice One evaluator for every job. It holds each job's spec, prepaid PC, PRE_EXECUTION snapshot and evaluation: +/// - inside `fund`, the UniversalHook hands it the final spec (`startSnapshot`): it is checked, frozen, every +/// read's fresh tracked height is recorded, and every PRE_EXECUTION read is read there (the snapshot); +/// - inside `submit`, the hook calls `verifyFromSubmit`: the end block of every POST_EXECUTION read is fixed at +/// its fresh tracked height, which must be above the one recorded at `fund`, then each is sent at its block; +/// - the callback that delivers the last answer works out the verdict and applies it: PASS completes, +/// FAIL rejects. +/// @dev - The end blocks are recorded before the reads are sent, and sending runs in its own guarded call, so a +/// failure to send (PC short, Read State paused) never loses them; the provider sends later (`sendReads`) at +/// the same blocks. +/// - Every tracked height used (at `fund` and at `submit`) must be at most `MAX_HEIGHT_AGE` old. +/// - The end blocks are fixed only inside `submit`: the hook calls `verifyFromSubmit` without try/catch, so if +/// they can't be fixed (a stale or unmoved height, too little gas) `submit` reverts and is sent again later. +/// - An unreadable answer counts as answered, PRE or POST: the checks that need it stay UNKNOWN and the rest may +/// still decide the root. Once the evaluation starts, an unreadable PRE read is sent again with the POST reads. +/// - Retries re-read the same blocks; there is no attempt limit. Only the provider spends PC on reads after +/// `submit` (`sendReads`), and only while the job is Submitted and undecided; snapshot retries +/// (`retrySnapshot`, until the evaluation starts) are the client's or the provider's. +/// - A job with no verdict ends through the kernel: after `expiredAt + EVALUATOR_GRACE_PERIOD` anyone may call +/// `claimRefund`, which refunds the client and frees the wallet. +/// - Answers longer than `MAX_RESULT_LENGTH` are unreadable. Read State itself does not cap answers yet. +/// - The verdict is applied as soon as the root is decided: the three-valued logic is monotone, so once the +/// root is PASS or FAIL no later answer can change it, and reads still out don't hold up payment. +/// - The kernel `reason` commits to the spec and to every read's evidence (`evidenceOf`) in index order, zero +/// for a read not answered when the root was decided, so it can be re-derived from events. +/// - `JobSpec.executeBy` and `JobSpec.failFinalAt` are not used: a FAIL at fixed blocks is final. +/// - `JobSpecLib.validate` runs in a linked library (DELEGATECALL; its address is fixed in this bytecode at +/// deployment, and it is stateless). Everything else, `EvmReadLib` included, is compiled in. +/// - Not upgradeable, with no admin: how this evaluator judges a frozen spec can't change. A rule change is a new +/// evaluator for new jobs; every job settles through the evaluator recorded in it at `createJob`. The kernel +/// and the hook stay trust points: both are upgradeable, and the kernel admin can detach a job's hook. +contract UniversalEvaluator is IUniversalEvaluator, ReentrancyGuard { + using SafeERC20 for IERC20; + + /// @notice What the evaluator keeps per job once its spec is frozen. + struct JobCache { + address client; + uint8 logicCount; // entries in the packed logic + bool frozen; + bool checkpointOk; // the wallet's counter could be read at `fund` + uint64 checkpointAtFund; + bytes32 specHash; // keccak256 of the exact frozen spec bytes + uint256[2] readChecks; // per read i, a 16-bit mask of the checks that use it: word i / 16, bits 16·(i % 16) + } + + /// @notice The PRE_EXECUTION snapshot of a job. + struct Snapshot { + uint8 needed; // PRE_EXECUTION reads + uint32 pre; // bit i: read i is PRE_EXECUTION + uint32 answered; // bit i: PRE read i answered, usable or not; never cleared + } + + /// @notice The evaluation of a submitted job. + struct Evaluation { + bool endFixed; // the end blocks are recorded + bool started; // the POST reads were sent + uint8 reads; + uint8 pending; // reads still waiting for an answer + bool done; // a verdict was worked out from the current answers + Verdict verdict; + bool applied; // the kernel accepted the verdict + OwnerCheck ownerCheck; // recorded only + uint32 checkRes; // each check's result, 2 bits per check (JobSpecLib) + uint32 answered; // bit i: read i answered since it was last sent; PRE reads start answered by the snapshot + } + + /// @notice Which read of which job a Read State request answers. + struct RequestRef { + uint256 jobId; + uint8 read; + bool snapshot; + } + + // ───────── events ───────── + + event Prefunded(uint256 indexed jobId, address indexed from, uint256 amount); + event SpecFrozenHere(uint256 indexed jobId, bytes32 specHash, OwnerCheck checkpointRead, uint64 checkpointAtFund); + event SnapshotRequested(uint256 indexed jobId, uint8 indexed read, uint256 requestId, uint64 height); + event SnapshotAnswered(uint256 indexed jobId, uint8 indexed read, uint256 requestId, bool ok, int256 value); + event SnapshotReady(uint256 indexed jobId); + event EndBlocksFixed(uint256 indexed jobId); + event ReadsSent(uint256 indexed jobId, uint256 reads, uint256 paid); + event ReadsNotSent(uint256 indexed jobId, bytes reason); + event ReadAnswered( + uint256 indexed jobId, uint8 indexed read, uint256 requestId, uint64 height, bool ok, int256 value + ); + event Verified(uint256 indexed jobId, Verdict verdict, OwnerCheck ownerCheck, bytes32 reason); + event SettleFailed(uint256 indexed jobId, bytes reason); + event PrepaidRefunded(uint256 indexed jobId, address indexed to, uint256 amount); + event FeesSwept(address indexed to, uint256 amount); + + /// @notice Gas for one decode, run as a capped self-call so a bad answer can't consume the callback. + uint256 internal constant DECODE_GAS = 200_000; + /// @notice Gas for reading the AGW's checkpoint counter. + uint256 internal constant CHECKPOINT_GAS = 30_000; + + // ───────── configuration, written once in the constructor ───────── + // Plain storage rather than `immutable`: Solidity copies an immutable into the bytecode at every use, which + // costs about 1.5 KB here, against EIP-170. Nothing writes these after the constructor (no setter, and the + // contract is not upgradeable), so they are as fixed as immutables. + + IAgenticCommerce public KERNEL; + address public HOOK; + IUniversalCallback public READ_STATE; + IUniversalCoreHeights public UNIVERSAL_CORE; + /// @notice Receives the evaluator's share of job fees, if the kernel admin sets one. + address public FEE_RECIPIENT; + /// @notice See `ReadConfig`. + uint64 public READ_TTL; + uint64 public CALLBACK_GAS_LIMIT; + uint64 public SNAPSHOT_CALLBACK_GAS_LIMIT; + uint256 public BUDGET_MULTIPLIER; + uint256 public MAX_HEIGHT_AGE; + uint16 public MAX_CONFIRMATIONS; + + // ───────── storage ───────── + + /// @notice Unspent PC prepaid for a job's reads (snapshot and evaluation). + mapping(uint256 => uint256) public prepaidOf; + /// @dev The job's spec, when it is not the createJob description: a replacement before `fund`, the frozen spec + /// after. Empty means the description (the hook never stores an empty one; freezing the description clears it). + mapping(uint256 => bytes) internal _replacement; + mapping(uint256 => JobCache) internal _cache; + mapping(uint256 => ReadPlan[]) internal _plans; + mapping(uint256 => PackedCheck[]) internal _checks; + mapping(uint256 => uint256[]) internal _packedLogic; // JobSpecLib.packLogic + mapping(uint256 => Snapshot) internal _snapshots; + mapping(uint256 => uint256[8]) internal _fundHeights; // every read's tracked height at fund, 4 uint64 per word + mapping(uint256 => Evaluation) internal _evals; + // Per read, PRE or POST alike: a PRE read's snapshot, a POST read's latest answer. + mapping(uint256 => mapping(uint256 => Answer)) internal _answers; // jobId => read => value + mapping(uint256 => mapping(uint256 => uint256)) internal _request; // jobId => read => current request + mapping(uint256 => mapping(uint256 => bytes32)) internal _leaf; // jobId => read => evidence of its answer + mapping(uint256 => uint256[8]) internal _endHeights; // POST reads only, 4 uint64 per word + mapping(uint256 => RequestRef) internal _requests; + + /// @dev `HOOK` is fixed here, for good: every later hook change must be an upgrade of that same proxy, since a + /// hook deployed at another address can't call this evaluator. The hook needs this address at its + /// `initialize`, so the two are deployed together: predict this address, deploy the hook proxy with it, then + /// deploy this (`scripts/agentic-commerce-8183`). + constructor( + address kernel_, + address hook_, + address readState_, + address universalCore_, + address feeRecipient_, + ReadConfig memory config_ + ) { + if ( + kernel_ == address(0) || hook_ == address(0) || readState_ == address(0) || universalCore_ == address(0) + || feeRecipient_ == address(0) + ) revert UniversalEvaluatorErrors.ZeroValue(); + if ( + config_.readTtl == 0 || config_.callbackGasLimit == 0 || config_.callbackGasLimit > MAX_CALLBACK_GAS_LIMIT + || config_.snapshotCallbackGasLimit == 0 || config_.snapshotCallbackGasLimit > MAX_CALLBACK_GAS_LIMIT + || config_.budgetMultiplier == 0 || config_.maxHeightAge == 0 || config_.maxConfirmations == 0 + ) revert UniversalEvaluatorErrors.ZeroValue(); + KERNEL = IAgenticCommerce(kernel_); + HOOK = hook_; + READ_STATE = IUniversalCallback(readState_); + UNIVERSAL_CORE = IUniversalCoreHeights(universalCore_); + FEE_RECIPIENT = feeRecipient_; + READ_TTL = config_.readTtl; + CALLBACK_GAS_LIMIT = config_.callbackGasLimit; + SNAPSHOT_CALLBACK_GAS_LIMIT = config_.snapshotCallbackGasLimit; + BUDGET_MULTIPLIER = config_.budgetMultiplier; + MAX_HEIGHT_AGE = config_.maxHeightAge; + MAX_CONFIRMATIONS = config_.maxConfirmations; + } + + modifier onlyHook() { + _requireHook(); + _; + } + + /// @dev The modifier's check as one function, so it isn't copied into each hook-facing function. + function _requireHook() private view { + if (msg.sender != HOOK) revert UniversalEvaluatorErrors.CallerIsNotHook(msg.sender); + } + + // ═════════════════════════════════ hook-facing (IUniversalEvaluator) ═════════════════════════════════ + + /// @inheritdoc IUniversalEvaluator + function setSpec(uint256 jobId, bytes calldata spec) external onlyHook { + if (_cache[jobId].frozen) revert UniversalEvaluatorErrors.SpecFrozen(jobId); + if (spec.length > MAX_DESCRIPTION_LENGTH) revert JobSpecErrors.SpecTooLong(spec.length); + _replacement[jobId] = spec; // the hook emits SpecReplaced + } + + /// @inheritdoc IUniversalEvaluator + function currentSpec(uint256 jobId) external view returns (bytes memory) { + return _replacement[jobId]; + } + + /// @inheritdoc IUniversalEvaluator + /// @dev Inside `afterAction(fund)`: a revert here reverts the funding. Checks the spec, freezes it, records the + /// wallet's checkpoint (the AGW ticks it before each owner call, so this includes the funding call) and + /// sends the snapshot reads from the job's prepaid PC. + function startSnapshot(uint256 jobId, bytes calldata spec) external onlyHook { + IAgenticCommerce.Job memory job = KERNEL.getJob(jobId); + if (job.evaluator != address(this) || job.hook != HOOK) revert UniversalEvaluatorErrors.NotOurJob(jobId); + if (job.status != IAgenticCommerce.JobStatus.Funded) revert UniversalEvaluatorErrors.WrongStatus(jobId); + JobCache storage c = _cache[jobId]; + if (c.frozen) revert UniversalEvaluatorErrors.SpecFrozen(jobId); + if (spec.length > MAX_DESCRIPTION_LENGTH) revert JobSpecErrors.SpecTooLong(spec.length); + + JobSpec memory s = _decodeSpec(spec); // reverts if `spec` is not an encoded JobSpec + JobSpecLib.validate(s, MAX_CONFIRMATIONS); // reverts with the JobSpecErrors reason + + bytes32 specHash = keccak256(spec); + if (specHash == keccak256(bytes(job.description))) delete _replacement[jobId]; + else _replacement[jobId] = spec; // the frozen bytes, whoever replaced them + + (bool cpOk, uint64 cp) = _readCheckpoint(job.client); + c.client = job.client; + c.frozen = true; + c.checkpointOk = cpOk; + c.checkpointAtFund = cp; + c.specHash = specHash; + _cacheSpec(jobId, s); + emit SpecFrozenHere(jobId, specHash, cpOk ? OwnerCheck.CLEAN : OwnerCheck.UNKNOWN, cp); + + Snapshot storage sn = _snapshots[jobId]; + for (uint256 i; i < s.reads.length; ++i) { + Read memory r = s.reads[i]; + // Preflight only: Read State's admin can still block the domain after `fund`. + if (IReadStateDomains(address(READ_STATE)).isDomainBlocked(r.chainNamespace, r.chainId)) { + revert UniversalEvaluatorErrors.ReadDomainBlocked(i); + } + uint64 h = EvmReadLib.latestHeight(UNIVERSAL_CORE, r, MAX_HEIGHT_AGE); + _setHeight(_fundHeights[jobId], i, h); // a PRE read's block; a POST read's end block must be above it + if (r.at == ReadAt.PRE_EXECUTION) { + // forge-lint: disable-next-line(unsafe-typecast) + sn.pre |= uint32(1 << i); // safe: i < MAX_READS (32) + ++sn.needed; // answers come in later transactions, so counting as we fire is safe + _fireSnapshot(jobId, i, r, h); + } + } + if (sn.needed == 0) emit SnapshotReady(jobId); + } + + /// @inheritdoc IUniversalEvaluator + /// @dev Inside `afterAction(submit)`, called without try/catch: if the end blocks can't be fixed, `submit` reverts. + /// Fixes every read's end block first, then tries to send the reads in a separate guarded call, so a failure + /// to send (PC short, snapshot not ready, Read State paused) keeps the blocks and `submit` still succeeds. + function verifyFromSubmit(uint256 jobId) external onlyHook { + IAgenticCommerce.Job memory job = KERNEL.getJob(jobId); + if (job.status != IAgenticCommerce.JobStatus.Submitted) revert UniversalEvaluatorErrors.WrongStatus(jobId); + if (!_cache[jobId].frozen) revert UniversalEvaluatorErrors.WrongStatus(jobId); + JobSpec memory s = _frozenSpec(jobId, job.description); + _fixEndBlocks(jobId, s); + try this.sendFromSubmit(jobId) {} + catch (bytes memory err) { + emit ReadsNotSent(jobId, err); + } + } + + /// @notice The second half of `verifyFromSubmit`, as its own call so a failure doesn't undo the fixed blocks. + function sendFromSubmit(uint256 jobId) external { + if (msg.sender != address(this)) revert UniversalEvaluatorErrors.CallerIsNotSelf(msg.sender); + IAgenticCommerce.Job memory job = KERNEL.getJob(jobId); + _start(jobId, _frozenSpec(jobId, job.description)); + } + + // ═════════════════════════════════ PC ═════════════════════════════════ + + /// @notice Prepays PC for a job's reads, snapshot and evaluation. The AGW calls it in the funding batch. + /// @dev Anyone may add PC; whatever is unspent goes back to the job's client through `claimPrepaid`. + function prefund(uint256 jobId) external payable { + if (jobId == 0 || jobId > KERNEL.jobCounter()) revert UniversalEvaluatorErrors.UnknownJob(jobId); + _addPrepaid(jobId); + } + + /// @notice What the job's reads cost at current fees, for the spec as it stands (replacement or description). + /// Prepay at least the sum, with headroom: fees and the base fee can move, and retries cost again. + function prefundCost(uint256 jobId) external view returns (uint256 snapshot, uint256 evaluation) { + bytes memory spec = _replacement[jobId]; + if (spec.length == 0) spec = bytes(KERNEL.getJob(jobId).description); + JobSpec memory s = _decodeSpec(spec); + for (uint256 i; i < s.reads.length; ++i) { + bool pre = s.reads[i].at == ReadAt.PRE_EXECUTION; + uint256 p = EvmReadLib.price( + READ_STATE, s.reads[i], pre ? SNAPSHOT_CALLBACK_GAS_LIMIT : CALLBACK_GAS_LIMIT, BUDGET_MULTIPLIER + ); + if (pre) snapshot += p; + else evaluation += p; + } + } + + /// @notice Sends the job's unspent PC to its client once the job is over (Completed, Rejected, Expired), or + /// still Open past its expiry. + function claimPrepaid(uint256 jobId) external nonReentrant { + IAgenticCommerce.Job memory job = KERNEL.getJob(jobId); + if (job.client == address(0)) revert UniversalEvaluatorErrors.UnknownJob(jobId); + IAgenticCommerce.JobStatus st = job.status; + if ( + st == IAgenticCommerce.JobStatus.Funded || st == IAgenticCommerce.JobStatus.Submitted + || (st == IAgenticCommerce.JobStatus.Open && block.timestamp < job.expiredAt) + ) revert UniversalEvaluatorErrors.JobStillLive(jobId); + uint256 amount = prepaidOf[jobId]; + prepaidOf[jobId] = 0; + if (amount == 0) return; + (bool ok,) = job.client.call{value: amount}(""); + if (!ok) revert UniversalEvaluatorErrors.RefundFailed(job.client, amount); + emit PrepaidRefunded(jobId, job.client, amount); + } + + // ═════════════════════════════════ provider / client recovery ═════════════════════════════════ + + /// @notice Sends the job's reads for evaluation: POST reads at the blocks fixed at `submit`, PRE reads again at + /// their `fund` blocks. Provider only, and only while the job is Submitted: once it has ended, its PC is + /// the client's to claim. `msg.value` is added to the job's PC. + /// - If they did not go out inside `submit` (PC short, snapshot not ready, Read State paused): every POST + /// read, and every PRE read with no usable value. + /// - Once sent: every read with no usable answer that is not in flight (an error answer, an undecodable + /// or oversized one, an expired request, a failed callback). There is no attempt limit. + /// @dev Never fixes the blocks, so the provider can't choose when the job is measured. + function sendReads(uint256 jobId) external payable nonReentrant { + IAgenticCommerce.Job memory job = KERNEL.getJob(jobId); + if (msg.sender != job.provider) revert UniversalEvaluatorErrors.CallerIsNotProvider(msg.sender); + if (job.status != IAgenticCommerce.JobStatus.Submitted) revert UniversalEvaluatorErrors.WrongStatus(jobId); + Evaluation storage e = _evals[jobId]; + if (!e.endFixed) revert UniversalEvaluatorErrors.EndBlocksNotFixed(jobId); + if (e.done && e.verdict != Verdict.INCONCLUSIVE) revert UniversalEvaluatorErrors.NothingToSend(jobId); + _addPrepaid(jobId); + JobSpec memory s = _frozenSpec(jobId, job.description); + if (e.started) _sendMissing(jobId, s); + else _start(jobId, s); + } + + /// @notice Sends again, at the same blocks, every PRE read never answered and not in flight (an expired request, a + /// failed callback). The job's client or provider only, until the evaluation starts; after that, `sendReads`. + /// @dev Never takes back an answer, usable or not, so neither side can hold `ready` back; the evaluation itself + /// re-reads an unreadable PRE answer. + function retrySnapshot(uint256 jobId) external payable nonReentrant { + IAgenticCommerce.Job memory job = KERNEL.getJob(jobId); + if (msg.sender != job.client && msg.sender != job.provider) { + revert UniversalEvaluatorErrors.CallerIsNotClientOrProvider(msg.sender); + } + if (!_cache[jobId].frozen || _evals[jobId].started) revert UniversalEvaluatorErrors.NothingToSend(jobId); + if (job.status != IAgenticCommerce.JobStatus.Funded && job.status != IAgenticCommerce.JobStatus.Submitted) { + revert UniversalEvaluatorErrors.WrongStatus(jobId); + } + _addPrepaid(jobId); + JobSpec memory s = _frozenSpec(jobId, job.description); + Snapshot storage sn = _snapshots[jobId]; + uint256 sent; + for (uint256 i; i < s.reads.length; ++i) { + if ((sn.pre >> i) & 1 == 0 || (sn.answered >> i) & 1 == 1) continue; // never take back an answer + if (READ_STATE.statusOf(_request[jobId][i]) == RequestStatus.PENDING) continue; + _fireSnapshot(jobId, i, s.reads[i], _height(_fundHeights[jobId], i)); + ++sent; + } + if (sent == 0) revert UniversalEvaluatorErrors.NothingToSend(jobId); + } + + /// @notice Applies a PASS or FAIL verdict the kernel refused inside the callback, e.g. while it was paused. + function settle(uint256 jobId) external nonReentrant { + Evaluation storage e = _evals[jobId]; + if (!e.done || e.applied || (e.verdict != Verdict.PASS && e.verdict != Verdict.FAIL)) { + revert UniversalEvaluatorErrors.NothingToSettle(jobId); + } + (bool ok, bytes memory err) = _apply(jobId, e.verdict, _reason(jobId, e.verdict, e.ownerCheck)); + if (!ok) { + assembly ("memory-safe") { + revert(add(err, 32), mload(err)) // the kernel's own revert + } + } + } + + /// @notice Sends the evaluator's share of job fees (paid by the kernel on `complete`) to `FEE_RECIPIENT`. + function sweepFees() external { + IERC20 token = KERNEL.paymentToken(); + uint256 amount = token.balanceOf(address(this)); + if (amount == 0) return; + token.safeTransfer(FEE_RECIPIENT, amount); + emit FeesSwept(FEE_RECIPIENT, amount); + } + + // ═════════════════════════════════ callback ═════════════════════════════════ + + /// @notice Read State delivers one answer, to a snapshot or an evaluation request. An evaluation answer that + /// decides the root applies the verdict. + /// @dev Never reverts for a known request: bad or oversized answers become "can't tell", and a kernel revert is + /// caught. An answer to a superseded request is ignored. + function onUniversalData(uint256 requestId, bytes calldata result) external { + if (msg.sender != address(READ_STATE)) revert UniversalEvaluatorErrors.CallerIsNotReadState(msg.sender); + RequestRef memory q = _requests[requestId]; + if (q.jobId == 0) return; + delete _requests[requestId]; + if (q.snapshot) _onSnapshot(q.jobId, q.read, requestId, result); + else _onAnswer(q.jobId, q.read, requestId, result); + } + + /// @dev Usable or not, the answer completes this read's part of the snapshot. + function _onSnapshot(uint256 jobId, uint8 read, uint256 requestId, bytes calldata result) internal { + Snapshot storage sn = _snapshots[jobId]; + if (_request[jobId][read] != requestId || (sn.answered >> read) & 1 == 1) return; + (bool ok, int256 value) = _record(jobId, read, requestId, _height(_fundHeights[jobId], read), result); + sn.answered |= uint32(1) << read; + emit SnapshotAnswered(jobId, read, requestId, ok, value); + if (sn.answered == sn.pre) emit SnapshotReady(jobId); + } + + function _onAnswer(uint256 jobId, uint8 read, uint256 requestId, bytes calldata result) internal { + if (_request[jobId][read] != requestId) return; // superseded by a retry + Evaluation storage e = _evals[jobId]; + if (e.done || (e.answered >> read) & 1 == 1) return; + + uint64 height = _blockOf(jobId, read); + (bool ok, int256 value) = _record(jobId, read, requestId, height, result); + e.answered |= uint32(1) << read; + emit ReadAnswered(jobId, read, requestId, height, ok, value); + + // Judge now every check that uses this read; one still missing a usable value stays UNKNOWN (0). + if (ok) e.checkRes = _judgeRead(jobId, read, e.checkRes); + --e.pending; + + // The logic is monotone: once the root is PASS or FAIL no later answer can change it, so apply it now. + // An unreadable answer changes no check, so only a usable one can decide the root. + if (ok || e.pending == 0) { + Verdict v = JobSpecLib.verdictPacked(_packedLogic[jobId], _cache[jobId].logicCount, e.checkRes); + if (v != Verdict.INCONCLUSIVE || e.pending == 0) _finish(jobId, v); + } + } + + // ═════════════════════════════════ views ═════════════════════════════════ + + /// @notice The number to compare, from one answer. Pure; the evaluator calls it on itself with a gas cap. + function decodeAnswer(bytes calldata outputs, uint8[] calldata field, bytes calldata res) + external + pure + returns (bool, int256) + { + return EvmReadLib.decode(outputs, field, res); + } + + function evaluationOf(uint256 jobId) external view returns (Evaluation memory) { + return _evals[jobId]; + } + + /// @notice keccak256 of the frozen spec; zero until `fund` freezes it. + function specHashOf(uint256 jobId) external view returns (bytes32) { + return _cache[jobId].specHash; + } + + /// @notice True once the spec is frozen and every PRE_EXECUTION read is answered, usable or not (`answerOf`). + function ready(uint256 jobId) public view returns (bool) { + Snapshot storage sn = _snapshots[jobId]; + return _cache[jobId].frozen && sn.answered == sn.pre; + } + + /// @notice A read's value: a PRE read's snapshot, a POST read's latest answer. + function answerOf(uint256 jobId, uint256 read) external view returns (bool ok, int256 value) { + Answer memory a = _answers[jobId][read]; + return (a.ok, a.value); + } + + /// @notice The read's tracked height recorded at `fund`; a PRE_EXECUTION read is read at this block. + function fundHeightOf(uint256 jobId, uint256 read) external view returns (uint64) { + return _height(_fundHeights[jobId], read); + } + + function endHeightOf(uint256 jobId, uint256 read) external view returns (uint64) { + return _height(_endHeights[jobId], read); + } + + function requestOf(uint256 jobId, uint256 read) external view returns (uint256) { + return _request[jobId][read]; + } + + /// @notice The evidence of one read's latest answer: keccak256(read, request, block, raw answer hash, ok, value). + function evidenceOf(uint256 jobId, uint256 read) external view returns (bytes32) { + return _leaf[jobId][read]; + } + + // ═════════════════════════════════ internal ═════════════════════════════════ + + /// @dev Specs are checked by `JobSpecLib.validate` when frozen, so decoding a frozen spec never fails. + function _decodeSpec(bytes memory spec) internal pure returns (JobSpec memory) { + return abi.decode(spec, (JobSpec)); + } + + /// @dev The frozen spec: the stored replacement, or the createJob description. + function _frozenSpec(uint256 jobId, string memory description) internal view returns (JobSpec memory) { + bytes memory spec = _replacement[jobId]; + return _decodeSpec(spec.length == 0 ? bytes(description) : spec); + } + + /// @dev Decode plans, checks, which checks each read feeds, and the packed tree, so callbacks never decode. + function _cacheSpec(uint256 jobId, JobSpec memory s) internal { + ReadPlan[] storage plans = _plans[jobId]; + for (uint256 i; i < s.reads.length; ++i) { + plans.push(); + ReadPlan storage p = plans[i]; + p.outputs = s.reads[i].outputs; + p.field = s.reads[i].field; + } + JobCache storage c = _cache[jobId]; + PackedCheck[] storage checks = _checks[jobId]; + for (uint256 i; i < s.checks.length; ++i) { + Check memory chk = s.checks[i]; + uint32 left = JobSpecLib.packSide(chk.left); + uint32 right = JobSpecLib.packSide(chk.right); + checks.push( + PackedCheck({ + left: left, right: right, evaluation: chk.evaluation, operation: chk.operation, target: chk.target + }) + ); + uint256 reads = left | right; + for (uint256 r; reads != 0; ++r) { + if (reads & 1 != 0) _markCheck(c, r, i); + reads >>= 1; + } + } + _packedLogic[jobId] = JobSpecLib.packLogic(s.logic); + // forge-lint: disable-next-line(unsafe-typecast) + c.logicCount = uint8(s.logic.length); // safe: JobSpecLib caps logic at MAX_LOGIC (32) + } + + function _markCheck(JobCache storage c, uint256 read, uint256 check) internal { + c.readChecks[read / 16] |= uint256(1) << (16 * (read % 16) + check); + } + + /// @dev Each POST read's end block is its fresh tracked height, strictly above the one recorded at `fund`. + /// - A floor, not a proof of work: a height that has not moved since `fund` can't include the provider's + /// work, but one that has moved may still be below the block the work landed in. The provider (SDK) must + /// submit only once each tracked height covers that block; a too-early `submit` reads pre-work state. + /// - Applies to every POST read's chain, including one the provider did not act on, so `submit` waits until + /// each tracked height has moved on and is fresh. An intended liveness requirement. + function _fixEndBlocks(uint256 jobId, JobSpec memory s) internal { + Evaluation storage e = _evals[jobId]; + if (e.endFixed) return; + uint256[8] storage heights = _endHeights[jobId]; + uint256[8] storage atFund = _fundHeights[jobId]; + uint32 pre = _snapshots[jobId].pre; + for (uint256 i; i < s.reads.length; ++i) { + if ((pre >> i) & 1 == 1) continue; // a PRE read has no end block + uint64 h = EvmReadLib.latestHeight(UNIVERSAL_CORE, s.reads[i], MAX_HEIGHT_AGE); + uint64 f = _height(atFund, i); + if (h <= f) revert UniversalEvaluatorErrors.EndHeightNotAfterFund(jobId, i, f, h); + _setHeight(heights, i, h); + } + e.endFixed = true; + emit EndBlocksFixed(jobId); + } + + /// @dev Starts the evaluation: judges the checks on PRE values alone, then sends every POST read at its end block + /// and every unreadable PRE read again at its `fund` block. Needs every PRE read answered. + function _start(uint256 jobId, JobSpec memory s) internal { + if (!ready(jobId)) revert UniversalEvaluatorErrors.SnapshotNotReady(jobId); + Evaluation storage e = _evals[jobId]; + Snapshot storage sn = _snapshots[jobId]; + e.started = true; + // forge-lint: disable-next-line(unsafe-typecast) + e.reads = uint8(s.reads.length); // safe: JobSpecLib caps reads at MAX_READS (32) + // forge-lint: disable-next-line(unsafe-typecast) + e.pending = uint8(s.reads.length - sn.needed); // the POST reads; safe: as above + e.answered = sn.pre; + uint32 res; + for (uint256 i; i < s.checks.length; ++i) { + res = _judge(jobId, i, _checks[jobId][i], res); // a check needing a POST value stays UNKNOWN + } + e.checkRes = res; + _sendMissing(jobId, s); + } + + /// @dev Sends, at its block, every read with no usable answer that is not in flight, and reopens the verdict. On + /// the first send that is every POST read and every unreadable PRE read. + function _sendMissing(uint256 jobId, JobSpec memory s) internal { + Evaluation storage e = _evals[jobId]; + uint256 sent; + uint256 paid; + for (uint256 i; i < e.reads; ++i) { + bool answered = (e.answered >> i) & 1 == 1; + if (answered && _answers[jobId][i].ok) continue; + uint256 req = _request[jobId][i]; + if (req != 0 && READ_STATE.statusOf(req) == RequestStatus.PENDING) continue; + if (answered) { + // forge-lint: disable-next-line(unsafe-typecast) + e.answered = uint32(uint256(e.answered) & ~(uint256(1) << i)); // safe: clears one bit of a uint32 + ++e.pending; // it had been counted as answered + } + paid += _fireRead(jobId, i, s.reads[i]); + ++sent; + } + if (sent == 0) revert UniversalEvaluatorErrors.NothingToSend(jobId); + e.done = false; + e.verdict = Verdict.NONE; + emit ReadsSent(jobId, sent, paid); + } + + function _fireRead(uint256 jobId, uint256 read, Read memory r) internal returns (uint256 value) { + value = _spend(jobId, EvmReadLib.price(READ_STATE, r, CALLBACK_GAS_LIMIT, BUDGET_MULTIPLIER)); + uint256 requestId = _fire(r, _blockOf(jobId, read), value, CALLBACK_GAS_LIMIT, READ_TTL, jobId); + _request[jobId][read] = requestId; + // forge-lint: disable-next-line(unsafe-typecast) + _requests[requestId] = RequestRef({jobId: jobId, read: uint8(read), snapshot: false}); // safe: read < 32 + } + + function _fireSnapshot(uint256 jobId, uint256 read, Read memory r, uint64 height) internal { + uint256 value = _spend(jobId, EvmReadLib.price(READ_STATE, r, SNAPSHOT_CALLBACK_GAS_LIMIT, BUDGET_MULTIPLIER)); + uint256 requestId = _fire(r, height, value, SNAPSHOT_CALLBACK_GAS_LIMIT, READ_TTL, jobId); + _request[jobId][read] = requestId; + // forge-lint: disable-next-line(unsafe-typecast) + _requests[requestId] = RequestRef({jobId: jobId, read: uint8(read), snapshot: true}); // safe: read < 32 + // forge-lint: disable-next-line(unsafe-typecast) + emit SnapshotRequested(jobId, uint8(read), requestId, height); // safe: as above + } + + function _fire(Read memory r, uint64 height, uint256 value, uint64 gasLimit, uint64 ttl, uint256 jobId) + internal + returns (uint256) + { + address client = _cache[jobId].client; + return EvmReadLib.fire( + READ_STATE, + r, + FireParams({ + owner: client, + height: height, + value: value, + ttl: ttl, + revertRecipient: client, // unspent callback budget goes back to the client + callbackSelector: this.onUniversalData.selector, + callbackGasLimit: gasLimit + }) + ); + } + + function _spend(uint256 jobId, uint256 value) internal returns (uint256) { + uint256 available = prepaidOf[jobId]; + if (available < value) revert UniversalEvaluatorErrors.PrepaidTooLow(value, available); + prepaidOf[jobId] = available - value; + return value; + } + + function _addPrepaid(uint256 jobId) internal { + if (msg.value == 0) return; + prepaidOf[jobId] += msg.value; + emit Prefunded(jobId, msg.sender, msg.value); + } + + /// @dev Stores a read's answer, usable or not, and its evidence. + function _record(uint256 jobId, uint8 read, uint256 requestId, uint64 height, bytes calldata result) + internal + returns (bool ok, int256 value) + { + bytes32 resultHash; + (ok, value, resultHash) = _decodeResult(jobId, read, result); + _answers[jobId][read] = Answer({ok: ok, value: value}); + _leaf[jobId][read] = keccak256(abi.encode(read, requestId, height, resultHash, ok, value)); + } + + /// @dev The block a read is read at: a PRE read's recorded at `fund`, a POST read's fixed at `submit`. + function _blockOf(uint256 jobId, uint256 read) internal view returns (uint64) { + bool pre = (_snapshots[jobId].pre >> read) & 1 == 1; + return _height(pre ? _fundHeights[jobId] : _endHeights[jobId], read); + } + + /// @dev Caps, then decodes. Oversized answers are unreadable and are not hashed (the hash would copy them). + function _decodeResult(uint256 jobId, uint256 read, bytes calldata result) + internal + view + returns (bool ok, int256 value, bytes32 resultHash) + { + if (result.length > MAX_RESULT_LENGTH) return (false, 0, bytes32(0)); + resultHash = keccak256(result); + ReadPlan storage plan = _plans[jobId][read]; + try this.decodeAnswer{gas: DECODE_GAS}(plan.outputs, plan.field, result) returns (bool k, int256 v) { + (ok, value) = (k, v); + } catch {} + } + + /// @dev Judges every check that uses `read`. + function _judgeRead(uint256 jobId, uint256 read, uint32 checkRes) internal view returns (uint32) { + uint256 mask = (_cache[jobId].readChecks[read / 16] >> (16 * (read % 16))) & type(uint16).max; + for (uint256 i; mask != 0; ++i) { + if (mask & 1 != 0) checkRes = _judge(jobId, i, _checks[jobId][i], checkRes); + mask >>= 1; + } + return checkRes; + } + + /// @dev Sets check `i`'s result from the values in so far; a missing or unreadable one leaves it UNKNOWN. + function _judge(uint256 jobId, uint256 i, PackedCheck memory chk, uint32 checkRes) internal view returns (uint32) { + Answer memory b; + if (chk.right != 0) b = _sum(jobId, chk.right); + return JobSpecLib.setCheck( + checkRes, i, JobSpecLib.checkResult(chk.evaluation, chk.operation, chk.target, _sum(jobId, chk.left), b) + ); + } + + /// @dev The sum of the reads in `mask`: not ok if any is missing or unreadable, or the sum overflows. + function _sum(uint256 jobId, uint256 mask) internal view returns (Answer memory total) { + total.ok = true; + for (uint256 r; mask != 0; ++r) { + if (mask & 1 != 0) { + Answer storage v = _answers[jobId][r]; + if (!v.ok) return Answer({ok: false, value: 0}); + (total.ok, total.value) = JobSpecLib.add(total.value, v.value); + if (!total.ok) return total; + } + mask >>= 1; + } + } + + /// @dev Records the verdict `v` (worked out from the per-check results), then tries to apply PASS or FAIL on the + /// kernel. + function _finish(uint256 jobId, Verdict v) internal { + Evaluation storage e = _evals[jobId]; + e.done = true; + e.verdict = v; + OwnerCheck oc = _ownerCheck(jobId); + e.ownerCheck = oc; + bytes32 reason = _reason(jobId, v, oc); + emit Verified(jobId, v, oc, reason); + + if (v == Verdict.INCONCLUSIVE) return; // the provider retries; otherwise the job ends through the kernel + (bool ok, bytes memory err) = _apply(jobId, v, reason); + if (!ok) emit SettleFailed(jobId, err); // anyone can `settle` later + } + + /// @dev PASS completes the job, FAIL rejects it. Returns the kernel's revert data if it refused. + function _apply(uint256 jobId, Verdict v, bytes32 reason) internal returns (bool ok, bytes memory err) { + bytes4 action = v == Verdict.PASS ? IAgenticCommerce.complete.selector : IAgenticCommerce.reject.selector; + (ok, err) = address(KERNEL).call(abi.encodeWithSelector(action, jobId, reason, bytes(""))); + if (ok) _evals[jobId].applied = true; // the kernel emits JobCompleted / JobRejected + } + + /// @dev Recorded, not acted on. UNKNOWN when either read of the wallet's counter failed. + function _ownerCheck(uint256 jobId) internal view returns (OwnerCheck) { + JobCache storage c = _cache[jobId]; + if (!c.checkpointOk) return OwnerCheck.UNKNOWN; + (bool ok, uint64 nowCount) = _readCheckpoint(c.client); + if (!ok) return OwnerCheck.UNKNOWN; + return nowCount == c.checkpointAtFund ? OwnerCheck.CLEAN : OwnerCheck.TOUCHED; + } + + /// @dev A raw, gas-capped staticcall, so a wallet without the counter is "unknown" instead of a revert. + function _readCheckpoint(address wallet) internal view returns (bool, uint64) { + (bool ok, bytes memory ret) = + wallet.staticcall{gas: CHECKPOINT_GAS}(abi.encodeCall(IAGWCheckpoints.checkpointCount, ())); + if (!ok || ret.length < 32) return (false, 0); + uint256 v = abi.decode(ret, (uint256)); + if (v > type(uint64).max) return (false, 0); + // forge-lint: disable-next-line(unsafe-typecast) + return (true, uint64(v)); // safe: checked on the line above + } + + /// @dev The kernel `reason`: the job, the exact frozen spec, every read's evidence in index order, the verdict + /// and the owner check. Independent of the order answers arrived in. + function _reason(uint256 jobId, Verdict v, OwnerCheck oc) internal view returns (bytes32) { + uint256 n = _evals[jobId].reads; + bytes32[] memory leaves = new bytes32[](n); + for (uint256 i; i < n; ++i) { + leaves[i] = _leaf[jobId][i]; + } + return keccak256(abi.encode(jobId, _cache[jobId].specHash, leaves, v, oc)); + } + + function _setHeight(uint256[8] storage heights, uint256 read, uint64 h) internal { + uint256 shift = 64 * (read % 4); + heights[read / 4] = (heights[read / 4] & ~(uint256(type(uint64).max) << shift)) | (uint256(h) << shift); + } + + function _height(uint256[8] storage heights, uint256 read) internal view returns (uint64) { + // forge-lint: disable-next-line(unsafe-typecast) + return uint64(heights[read / 4] >> (64 * (read % 4))); // safe: masked to 64 bits by the cast + } +} diff --git a/plan/marketplace/research/2026-10-20/evaluator-source-manifest.json b/plan/marketplace/research/2026-10-20/evaluator-source-manifest.json new file mode 100644 index 00000000..c086882c --- /dev/null +++ b/plan/marketplace/research/2026-10-20/evaluator-source-manifest.json @@ -0,0 +1,14 @@ +{ + "source_commit": "8059817591cca16c59f1cc154f475f51e1736a67", + "authority": "comparison source linked in Nilesh Oct16 comment; not a deployed v2 dependency", + "files": [ + { + "file": "research/2026-10-20/evaluator-8059817/JobSpecTypes.sol", + "sha256": "dad44d25e1793c5c9303eb1d38b27de61472ba8aa749b487cd7e5b3039c3d363" + }, + { + "file": "research/2026-10-20/evaluator-8059817/UniversalEvaluator.sol", + "sha256": "efb2f1a4045e3be2101c92ba47e192adafa0478a86897d80a5041505e0a3e98a" + } + ] +} diff --git a/plan/marketplace/research/2026-10-20/evidence-archives.json b/plan/marketplace/research/2026-10-20/evidence-archives.json new file mode 100644 index 00000000..a1fe86a4 --- /dev/null +++ b/plan/marketplace/research/2026-10-20/evidence-archives.json @@ -0,0 +1,13 @@ +{ + "archives": [ + { + "file": "invariant-tests.log.gz", + "compression": "gzip", + "uncompressed_name": "invariant-tests.log", + "uncompressed_bytes": 45180847, + "uncompressed_sha256": "8352680abe26d8fdbda1c12c5dd003a84b2d91c0320bf9ca4e6471f4b6ca5cdc", + "compressed_bytes": 4466951, + "sha256": "dec8bc21a83014b1d5479796ce621ef4f419c3f304be14db82542d0feae2b6b5" + } + ] +} diff --git a/plan/marketplace/research/2026-10-20/final-source-recheck.json b/plan/marketplace/research/2026-10-20/final-source-recheck.json new file mode 100644 index 00000000..16f18860 --- /dev/null +++ b/plan/marketplace/research/2026-10-20/final-source-recheck.json @@ -0,0 +1,6 @@ +{ + "checked_at": "2026-10-20T10:03:15.266171+00:00", + "branch": "sdk-iteration-v1", + "head": "443b4e2dd9ca5dd9ffc8efebdfcecd619dd66c47", + "matches_reviewed_pin": true +} diff --git a/plan/marketplace/research/2026-10-20/fork-tests-summary.json b/plan/marketplace/research/2026-10-20/fork-tests-summary.json new file mode 100644 index 00000000..d07ced50 --- /dev/null +++ b/plan/marketplace/research/2026-10-20/fork-tests-summary.json @@ -0,0 +1,47 @@ +{ + "args": [ + "forge", + "test", + "--root", + "/var/folders/4_/d47r2_4s1wb3x2dvmt2ghp800000gp/T/marketplace-review-443b4e2-_ib864pr", + "--match-path", + "test/8183-tests/*.fork.t.sol", + "--offline", + "--json" + ], + "environment": { + "PUSH_CHAIN_TESTNET_RPC_URL": "https://evm.donut.rpc.push.org/", + "FORK_BLOCK": "24447347" + }, + "exit_code": 0, + "seconds": 41.36, + "counts": { + "Success": 2 + }, + "tests": [ + { + "suite": "test/8183-tests/RulesBindingHook.fork.t.sol:RulesBindingHookForkTest", + "test": "test_fork_mirrorsMatchDeployedAGW()", + "status": "Success", + "reason": null, + "decoded_logs": [], + "kind": { + "Unit": { + "gas": 193974 + } + } + }, + { + "suite": "test/8183-tests/UniversalMarketplace.fork.t.sol:UniversalMarketplaceForkTest", + "test": "test_fork_openJob_realAGWv6()", + "status": "Success", + "reason": null, + "decoded_logs": [], + "kind": { + "Unit": { + "gas": 21035856 + } + } + } + ] +} diff --git a/plan/marketplace/research/2026-10-20/fork-tests.log b/plan/marketplace/research/2026-10-20/fork-tests.log new file mode 100644 index 00000000..c4aaa2b2 --- /dev/null +++ b/plan/marketplace/research/2026-10-20/fork-tests.log @@ -0,0 +1 @@ +{"test/8183-tests/RulesBindingHook.fork.t.sol:RulesBindingHookForkTest":{"duration":"5s 674ms 840µs 667ns","test_results":{"test_fork_mirrorsMatchDeployedAGW()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":193974}},"traces":[],"labeled_addresses":{"0x95906919abef897340abe05fec8c78d9c0658cec":"forkWalletOwner","0x3bd52ac93106ecf372507350a717905f93b74d5a":"nobody"},"duration":"5s 671ms 69µs 41ns","breakpoints":{},"gas_snapshots":{}}},"warnings":[]},"test/8183-tests/UniversalMarketplace.fork.t.sol:UniversalMarketplaceForkTest":{"duration":"39s 650ms 455µs 333ns","test_results":{"test_fork_openJob_realAGWv6()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":21035856}},"traces":[],"labeled_addresses":{"0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0x540da3418be99da0614998034fcb817e9d8a0644":"forkAdmin","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0x238ec72e0743bd4c21497d4157854dd3a1dd2f0d":"forkRelayer","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0x0bd7513c1db25948b7a05301ec3698f379f4af13":"ceaFactory","0x22aa0d0bcc922d549618bd1ef8253cc8dee5a3cc":"forkProvider","0x15773a5a32018dc9fb19262d7d5f422eadd5d3e9":"forkOwner"},"duration":"39s 645ms 384µs 625ns","breakpoints":{},"gas_snapshots":{}}},"warnings":[]}} diff --git a/plan/marketplace/research/2026-10-20/invariant-tests-summary.json b/plan/marketplace/research/2026-10-20/invariant-tests-summary.json new file mode 100644 index 00000000..e28b5c72 --- /dev/null +++ b/plan/marketplace/research/2026-10-20/invariant-tests-summary.json @@ -0,0 +1,520 @@ +{ + "args": [ + "forge", + "test", + "--root", + "/var/folders/4_/d47r2_4s1wb3x2dvmt2ghp800000gp/T/marketplace-review-443b4e2-_ib864pr", + "--match-path", + "test/8183-tests/*.t.sol", + "--match-test", + "invariant_", + "--offline", + "--json" + ], + "environment": { + "FOUNDRY_INVARIANT_RUNS": "64", + "FOUNDRY_INVARIANT_DEPTH": "64" + }, + "exit_code": 0, + "seconds": 51.29, + "counts": { + "Success": 10 + }, + "tests": [ + { + "suite": "test/8183-tests/AgenticCommerce.invariants.t.sol:AgenticCommerceInvariantsTest", + "test": "invariant_balanceCoversEscrow()", + "status": "Success", + "reason": null, + "decoded_logs": [], + "kind": { + "Invariant": { + "runs": 64, + "calls": 4096, + "reverts": 0, + "metrics": { + "test/8183-tests/AgenticCommerce.invariants.t.sol:KernelHandler.setBudget": { + "calls": 430, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/AgenticCommerce.invariants.t.sol:KernelHandler.setFees": { + "calls": 422, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/AgenticCommerce.invariants.t.sol:KernelHandler.complete": { + "calls": 381, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/AgenticCommerce.invariants.t.sol:KernelHandler.reject": { + "calls": 424, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/AgenticCommerce.invariants.t.sol:KernelHandler.setProvider": { + "calls": 398, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/AgenticCommerce.invariants.t.sol:KernelHandler.fund": { + "calls": 422, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/AgenticCommerce.invariants.t.sol:KernelHandler.submit": { + "calls": 398, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/AgenticCommerce.invariants.t.sol:KernelHandler.createJob": { + "calls": 403, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/AgenticCommerce.invariants.t.sol:KernelHandler.warp": { + "calls": 395, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/AgenticCommerce.invariants.t.sol:KernelHandler.claimRefund": { + "calls": 423, + "reverts": 0, + "discards": 0 + } + }, + "failed_corpus_replays": 0 + } + } + }, + { + "suite": "test/8183-tests/AgenticCommerce.invariants.t.sol:AgenticCommerceInvariantsTest", + "test": "invariant_onlyLegalTransitions()", + "status": "Success", + "reason": null, + "decoded_logs": [], + "kind": { + "Invariant": { + "runs": 64, + "calls": 4096, + "reverts": 0, + "metrics": { + "test/8183-tests/AgenticCommerce.invariants.t.sol:KernelHandler.warp": { + "calls": 395, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/AgenticCommerce.invariants.t.sol:KernelHandler.setProvider": { + "calls": 398, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/AgenticCommerce.invariants.t.sol:KernelHandler.setFees": { + "calls": 422, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/AgenticCommerce.invariants.t.sol:KernelHandler.submit": { + "calls": 398, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/AgenticCommerce.invariants.t.sol:KernelHandler.reject": { + "calls": 424, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/AgenticCommerce.invariants.t.sol:KernelHandler.fund": { + "calls": 422, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/AgenticCommerce.invariants.t.sol:KernelHandler.setBudget": { + "calls": 430, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/AgenticCommerce.invariants.t.sol:KernelHandler.createJob": { + "calls": 403, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/AgenticCommerce.invariants.t.sol:KernelHandler.claimRefund": { + "calls": 423, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/AgenticCommerce.invariants.t.sol:KernelHandler.complete": { + "calls": 381, + "reverts": 0, + "discards": 0 + } + }, + "failed_corpus_replays": 0 + } + } + }, + { + "suite": "test/8183-tests/AgenticCommerce.invariants.t.sol:AgenticCommerceInvariantsTest", + "test": "invariant_totalEscrowedMatchesLiveBudgets()", + "status": "Success", + "reason": null, + "decoded_logs": [], + "kind": { + "Invariant": { + "runs": 64, + "calls": 4096, + "reverts": 0, + "metrics": { + "test/8183-tests/AgenticCommerce.invariants.t.sol:KernelHandler.claimRefund": { + "calls": 423, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/AgenticCommerce.invariants.t.sol:KernelHandler.submit": { + "calls": 398, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/AgenticCommerce.invariants.t.sol:KernelHandler.reject": { + "calls": 424, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/AgenticCommerce.invariants.t.sol:KernelHandler.warp": { + "calls": 395, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/AgenticCommerce.invariants.t.sol:KernelHandler.createJob": { + "calls": 403, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/AgenticCommerce.invariants.t.sol:KernelHandler.fund": { + "calls": 422, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/AgenticCommerce.invariants.t.sol:KernelHandler.setProvider": { + "calls": 398, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/AgenticCommerce.invariants.t.sol:KernelHandler.setFees": { + "calls": 422, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/AgenticCommerce.invariants.t.sol:KernelHandler.complete": { + "calls": 381, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/AgenticCommerce.invariants.t.sol:KernelHandler.setBudget": { + "calls": 430, + "reverts": 0, + "discards": 0 + } + }, + "failed_corpus_replays": 0 + } + } + }, + { + "suite": "test/8183-tests/UniversalMarketplace.invariants.t.sol:UniversalMarketplaceInvariants", + "test": "invariant_MI01_activeJobIsTheAgwsOwnJob()", + "status": "Success", + "reason": null, + "decoded_logs": [], + "kind": { + "Invariant": { + "runs": 64, + "calls": 6400, + "reverts": 0, + "metrics": { + "test/8183-tests/UniversalMarketplace.invariants.t.sol:MarketplaceHandler.update": { + "calls": 1322, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/UniversalMarketplace.invariants.t.sol:MarketplaceHandler.open": { + "calls": 1290, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/UniversalMarketplace.invariants.t.sol:MarketplaceHandler.warp": { + "calls": 1246, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/UniversalMarketplace.invariants.t.sol:MarketplaceHandler.cancel": { + "calls": 1294, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/UniversalMarketplace.invariants.t.sol:MarketplaceHandler.register": { + "calls": 1248, + "reverts": 0, + "discards": 0 + } + }, + "failed_corpus_replays": 0 + } + } + }, + { + "suite": "test/8183-tests/UniversalMarketplace.invariants.t.sol:UniversalMarketplaceInvariants", + "test": "invariant_MI02_marketplaceHoldsNothing()", + "status": "Success", + "reason": null, + "decoded_logs": [], + "kind": { + "Invariant": { + "runs": 64, + "calls": 6400, + "reverts": 0, + "metrics": { + "test/8183-tests/UniversalMarketplace.invariants.t.sol:MarketplaceHandler.cancel": { + "calls": 1294, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/UniversalMarketplace.invariants.t.sol:MarketplaceHandler.warp": { + "calls": 1246, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/UniversalMarketplace.invariants.t.sol:MarketplaceHandler.register": { + "calls": 1248, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/UniversalMarketplace.invariants.t.sol:MarketplaceHandler.update": { + "calls": 1322, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/UniversalMarketplace.invariants.t.sol:MarketplaceHandler.open": { + "calls": 1290, + "reverts": 0, + "discards": 0 + } + }, + "failed_corpus_replays": 0 + } + } + }, + { + "suite": "test/8183-tests/UniversalMarketplace.invariants.t.sol:UniversalMarketplaceInvariants", + "test": "invariant_MI03_outcomesExactlyExpected()", + "status": "Success", + "reason": null, + "decoded_logs": [], + "kind": { + "Invariant": { + "runs": 64, + "calls": 6400, + "reverts": 0, + "metrics": { + "test/8183-tests/UniversalMarketplace.invariants.t.sol:MarketplaceHandler.cancel": { + "calls": 1294, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/UniversalMarketplace.invariants.t.sol:MarketplaceHandler.register": { + "calls": 1248, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/UniversalMarketplace.invariants.t.sol:MarketplaceHandler.warp": { + "calls": 1246, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/UniversalMarketplace.invariants.t.sol:MarketplaceHandler.update": { + "calls": 1322, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/UniversalMarketplace.invariants.t.sol:MarketplaceHandler.open": { + "calls": 1290, + "reverts": 0, + "discards": 0 + } + }, + "failed_corpus_replays": 0 + } + } + }, + { + "suite": "test/8183-tests/UniversalMarketplace.invariants.t.sol:UniversalMarketplaceInvariants", + "test": "invariant_MI04_everyJobIsWellFormed()", + "status": "Success", + "reason": null, + "decoded_logs": [], + "kind": { + "Invariant": { + "runs": 64, + "calls": 6400, + "reverts": 0, + "metrics": { + "test/8183-tests/UniversalMarketplace.invariants.t.sol:MarketplaceHandler.register": { + "calls": 1248, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/UniversalMarketplace.invariants.t.sol:MarketplaceHandler.update": { + "calls": 1322, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/UniversalMarketplace.invariants.t.sol:MarketplaceHandler.warp": { + "calls": 1246, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/UniversalMarketplace.invariants.t.sol:MarketplaceHandler.open": { + "calls": 1290, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/UniversalMarketplace.invariants.t.sol:MarketplaceHandler.cancel": { + "calls": 1294, + "reverts": 0, + "discards": 0 + } + }, + "failed_corpus_replays": 0 + } + } + }, + { + "suite": "test/8183-tests/UniversalMarketplace.invariants.t.sol:UniversalMarketplaceInvariants", + "test": "invariant_MI05_userBalanceNeverMovedByOpenJob()", + "status": "Success", + "reason": null, + "decoded_logs": [], + "kind": { + "Invariant": { + "runs": 64, + "calls": 6400, + "reverts": 0, + "metrics": { + "test/8183-tests/UniversalMarketplace.invariants.t.sol:MarketplaceHandler.open": { + "calls": 1290, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/UniversalMarketplace.invariants.t.sol:MarketplaceHandler.register": { + "calls": 1248, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/UniversalMarketplace.invariants.t.sol:MarketplaceHandler.update": { + "calls": 1322, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/UniversalMarketplace.invariants.t.sol:MarketplaceHandler.warp": { + "calls": 1246, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/UniversalMarketplace.invariants.t.sol:MarketplaceHandler.cancel": { + "calls": 1294, + "reverts": 0, + "discards": 0 + } + }, + "failed_corpus_replays": 0 + } + } + }, + { + "suite": "test/8183-tests/UniversalMarketplace.invariants.t.sol:UniversalMarketplaceInvariants", + "test": "invariant_MI06_onePerProvider()", + "status": "Success", + "reason": null, + "decoded_logs": [], + "kind": { + "Invariant": { + "runs": 64, + "calls": 6400, + "reverts": 0, + "metrics": { + "test/8183-tests/UniversalMarketplace.invariants.t.sol:MarketplaceHandler.register": { + "calls": 1248, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/UniversalMarketplace.invariants.t.sol:MarketplaceHandler.cancel": { + "calls": 1294, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/UniversalMarketplace.invariants.t.sol:MarketplaceHandler.open": { + "calls": 1290, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/UniversalMarketplace.invariants.t.sol:MarketplaceHandler.update": { + "calls": 1322, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/UniversalMarketplace.invariants.t.sol:MarketplaceHandler.warp": { + "calls": 1246, + "reverts": 0, + "discards": 0 + } + }, + "failed_corpus_replays": 0 + } + } + }, + { + "suite": "test/8183-tests/UniversalMarketplace.invariants.t.sol:UniversalMarketplaceInvariants", + "test": "invariant_MI07_principalCapEqualsPrincipal()", + "status": "Success", + "reason": null, + "decoded_logs": [], + "kind": { + "Invariant": { + "runs": 64, + "calls": 6400, + "reverts": 0, + "metrics": { + "test/8183-tests/UniversalMarketplace.invariants.t.sol:MarketplaceHandler.warp": { + "calls": 1246, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/UniversalMarketplace.invariants.t.sol:MarketplaceHandler.cancel": { + "calls": 1294, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/UniversalMarketplace.invariants.t.sol:MarketplaceHandler.update": { + "calls": 1322, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/UniversalMarketplace.invariants.t.sol:MarketplaceHandler.open": { + "calls": 1290, + "reverts": 0, + "discards": 0 + }, + "test/8183-tests/UniversalMarketplace.invariants.t.sol:MarketplaceHandler.register": { + "calls": 1248, + "reverts": 0, + "discards": 0 + } + }, + "failed_corpus_replays": 0 + } + } + } + ] +} diff --git a/plan/marketplace/research/2026-10-20/invariant-tests.log.gz b/plan/marketplace/research/2026-10-20/invariant-tests.log.gz new file mode 100644 index 0000000000000000000000000000000000000000..959c6b4b2465ea8604b08f767ef22ea5b6d59cc2 GIT binary patch literal 4466951 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

Y(2h&r+$N%kRRR50{O}mR@PC1h7s#9RU+YO*bob z7|9>VRF&ygJ%1^ zRc47ls40aM*0&-%z1EI-6gbtga_0+watVcxw(9X)1VtrPV%IE3k;vT3JY2tD zRzN}DQnhGvS!`t0i*+pPCtk-87Fkx`Rz_=LK7ii|Hd!flI1S z-+{?tj;n}A=WOwGr0(_R??anfoDl_?J#bbHjH6`=K&U-F)_fRT*XG7 z5i@=9zwI70>#|;=yXs{C9VP;2KLW6!BTYr>z1b4jCsuv>2=+=T{Mymgev)2hp3T>L zUQl1FF4rV%1Z&HP-t*On#+E!0MR|G!R6rC(C%E!R;6fT$bADOQ z<@#g)_8*8P=hdrWBjY%xt88ER#DpufsU=sCE9SW3bahyrJlV9o|#MFYP&vk%vZ9;Fp4l1T76sSNixB7f6s7%%) zOtnJdeT+)2-Fb<+v2mn!{*)r`!jNA%VG2?7MbU(ziegnY143C0EoirGc$+V?A}3M- zr$x?pNE8P3jD48AnqP=LWrkwT<@4uWa9@V7MKORYj+40-^FW3@k@K6B?DS2*(nxQ2 zJ~hI)&tc-1;8NdM`@}L3a3-}8d)V�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 JBU{7r|nEgpy*C1yGpL`Fc(H_M$8~7 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

$0@5o~EC5nLrkLT+s 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�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

~j-B3*r9P8b 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�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

DpZ9gd$&mr;otr><;h$H`aS1;4uoc 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

Et-i#<%JwGvN?L#_&pqcI}})#619S&(>hmE6cf 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%0A+5#P1zH?szEkc>{e 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

LHImm5C{ovs6qbEyPlLhDRT$ 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

{i5Tv4~j^IhW86i0{TzfpYky zvh~9JIV~s6XBIqBt1HU^qui6=gyt?o_nyd(0ei{9DnV>@r|MSNR@hOv@`mARj=K+1 z_Ftf!N!>{I$#Ckzc|MHs@K-Z|{%!av7;d49)5nk58XNK(5?f-3(|$*BH#LB*SRDh{ zFI%?{u}qET$(R6WjttYuZn=k#RgPYMvO_<>a9^r zCOVE3XD4x1k|hbmZR%JVt(kG`)X6pccRs%d%)$2EyyLl!A1fuS6@bpwf2jXPG{83_ z@POKQtZ>J&%H$+xtb*lLjRJK$$I)N}Ym2@Fq(L&JAkh&lovmr;_5kxUyB-We1_RhF zqhQ^0|5(9>xmp;JNq?RB4A>`n$@#rR`Y*X_H*lmUd9Cfa~>0XD~K*>gZJu8j5A+Q#-iWNo{X`K273J&Z=3xf+&H;}bJ zBs)o~ukkBFUod}=Q4S53@#g)P;{WgLWz>OJJNYj<=W9)<`A1D?>e7f+yU%iDPJ=Tm z8GWOplRDZ+LMS}3OZ~_b6CPtcc1~X^O2@t=iuB~W_zUIdD2i$7XB=pYmdo)l@wX#7 z{~Gg=xYX=vo)zydNCLxWkvVZtA6|X*MIYQ>>^-Bi$_36UdOWNAlM3UA5kNhx9-Q7> zlN0%@Hp=jM%!uI{nF(>>PFls)dp)$AJa3nBj6$YB}q5gp}KhKKa zpjQ|1wo{edHHQfoBVpYW++!q*DL>^J#?hwIH~4hP1{987@x#XBli#a`CdK^BQLbRN zK%~li?8V^vqHJ*zwm`fTHncLwIB_l**-C_tWvd%b$AG*vuC~wuQZWRq=@=1T)-bl7 zvO+d7_-)2K3p;DW9(kSko}8c6D7L{@#$YFN%@ekM#8*`V(=~sX-i4g}_xSLmCQS4* zzY&Anu+)ez;t%-u!Y8?8(k!`X-p*J|CR=uXs#4p2Fq&3J164!x1q3m*zt z`L>Luf96HLZW1)$j0iAaGyK}v$=ytN5hqc)!%HFa#U40VKjsl%x>`*ZPQoWOW6^Ub zzFK+~JeGYYj!`O+Fq^g>#Q2NT|0gJ!?dUe=|PF*bUyL}StUdub~Z9HWzz&(NevqvRvP4zg*cC-f) zfM+W{YIqd`+ z>cg+sji3f-<>Vc)B{_EocYd@Jb3l1_7bFAKSiH@yT<=2LnKCKw)@2&oz5J%TDeHb# z4YsN3V+A5VAi5~>-_gXMt}d`%_tllR5As)T&ZG<`pm=>{txYMFxUSN^+R_+@r-rI& zOKc&e`xtJd+OfO+4JR-ds#_ct?9R5;gp~u3;Yiio9oV=&gy{2D;8@!X+@CN2s7H-` zq|ol|@55{O=xgMPE#G`I<@n8aC(h2|tUg0Xo`9b70D?(@&D7zZ7D0{BzSn?4T{Y0d zKw;K4J1o0{W!8`;Xv@JMG<<9g`FOHaDE?qf{}G?YM`QZ6H@_d#zxqwSF)wHZuJiKm z_+H{0--{dM&8^7b@xN)&de>uR^Q$Lm=9B()HppkO%!Xiw|1&f5-m%mY8cJiUNp2BteptI3#wdaWG(&GbS1k1$;-i7RTUr&Womu!KZb&oa3trU_;MEP2FEU_}BSvNA}<^arbZvQAE~3rFKF zc8_|xR#csJ@5yWC)QlX%H)!RIc;`zvkl2)KFnxF8&m;c_O0ep-;{UY9ncoEMK0$BW zi$|DxW*WB`9asrhZ5MCSV@)GGet(@T? zNpaz?+*ghG-8be`pii(a6&zt`3Lv|vA##)C`%m)PtUQb3eIK{N-M8Ym*>!e*vbVwl z0Ct{A9Fw5R4~s3!nZh`NUE*SFr#SK?!%}v$Iv=mF+;$ywB0Nrb3I_`At!MBbib*-m z1t|7t1+F5k+EImNZOM*O=RAdT{*AuoxC!=8A{S2B0a^d1HRtxVNggaXo!pAqhzsTs zzcs&Eqy4lxpxYprktWb0kRk+Jqwu^D!f)2-k6O~!mhc*dR@C3L4e%tpxoaT8gE&v2H;MMk7_M$2JE?Gc$tz$5-Tr zrnqmgKRU{Ae5*(3SO3k5yt5rZ8@AJSaMt!uICS12;%~f^V;iew0dJC=t4~ls$n<>0 zY`sQofO+fwx>k?#67GUi0A~SVDe#y1`C63i7yv%II0cxM8n-Ksr5*1&mr9c7Py(Q(Tn+O}2;x zG-}fzF1o?oS5Vw^vjvlZ%s`xk0jsHl36(dK;k+|2qSYH~h@uVpV;Dir_LfG@TjjW} zUy6*<1p$EkT#1Wp>(YU0P{NrZ(DZ z8{z#q(Z71~VN$O2;6AWH^o&9W z?v|~*NuhwoTm@`dHB(ckdvlu}5M%+Ms?uBw9W-f+{M5%U@b8h%EC+W_EL!{}@-)s) zFkClK?xuHS;(vRZHNTHIShy4wT{24NczeznrSVFzL6YOz+`dtT`yIs{1^Y1Tki~@~ z5v`SpvYn%hICNUWnY>?P=B{uLJ)xE;`;YM+l9O??I8&Wg6`3P&^4SqW?e*%k+vMWV z+i4u4WX|Bz+en6U1COtOKtv2|UO=PQo=JE;( z+laMiPh+&_n7nT*XOCWg&t43wdyb~mKG#cK`X{J%>8a!D^U)pouy6+0*-ya@8MYE7 zyH&lBP8%T{IXB-*W!G>SVP2uS5F0ye>@ab48-@rMT;1H+QFt4)~vPoE6RmDDxZEkNnpDYn=mbl|k)#{OhjZ+Vg z+=dM1VdW{>f)C5c9{d7xUrCKFUQxnKi*a-Q-oXwHgb=>r3`8nl?0ueyCyZ-au4ECX zHiBp{l&{ux@H*a;)F=Mi zTzcZFJGaPgys}Izy};U6eJId}bH(akFy<;(u;ewaNwC-q*}KT6oNLHh%7nbKCv(oR)+c_Q zSG@dY_g&8&-uI}pK7N1y?d4gqJmxH74HvE-L7I?zVE7PT8qr_qFJ*3Oer&fq*C0W# zcF-XSWj*=^dkHxj?|#wk@ry8uai-^*|FRmN;XT8^%3`&b@};#d_F))cyBY1{m!3?r51GktQY+K(9e3o8rrO~E&1gkn~A&tyQL=ct(nlGR(@<(U(!CCiMjMt5X=l*sqB}LQQ!SM_U3$-HN*TFku0`!aDe%_^N+R)4;GD6 z)R$I1c)WP5X8sIX^lD=-%HG3P>@GVfXn-;vpPSZ;pcKK~kP^|8+W z;Qd8RDE^xX$M)a@zFPFm1~JB=Gn2PfxRoZx1%53Sl0vj~h`YuO%cz`fU=U??_W{gn zu6wS@x0NipP{$eccZ=j~XDgT0lv$3vwaU4AX(ei|A==5oLU!ghStz8}Hj1T+>Cx<| zU!GvHnM_Y-4k#-2HM2J5xzO{f!z!Keim?Ze)k!uBUn}x*Z`D%Nbp8%K#XD*;tezG; z_9sj7k>3da=XRfjx?;GtIueq}84#3&CHgf_^_{hV&(CK1$xj*RtrMr}LZ0ON=lVRnQ&VdO!FZ!q$|(U`#o_4d_BP~SaeaKc})M|1Ws z(TN5pp9y>XqUni$x{hKePuRz!Sl!D}?0R~XTC2+_wpnxMN28ctjUq+sM-bG+979-F zbl-IhZ%474B%|1kdNzve3F1*~+p|%`9KwLGO_ypZU*EeOeaWxJovW?kUnwr*-tBL& z0r7&}((o${Dk;Xo3CRQd+4I_^{mn?9#0Zvm` zN1W8;9B2N&!~VKviz}kEk=hFTJ3^Q&QhfG268t3<{FO z3h>S$=xJ09k2Q@9eSgIlk(6FeH@Fwkj~nO%i6pjttqnY^X_DH|w0a!{@$owDQSLmR ze76Se?f!1L_k}MOe~;SVc_d%?XYm)HA-fpwH7*R;OLaLF$nHPK-Oi{AUa^k2U-Qne zC^5%tM)_ptuxDnEllOS9U3f4W?q2HsyZFG5$h>g#YJA`?oSzOxW7fOV^l|LG!-->| z%$U6~RvC*R@h-!^$v?i`aZj9)BzP|hoRe(Rr=6v>J?|_l^=aT6I$JMNQJZwt2WZYT zF57))Xl4J5jDFY$tizzL{0sCaF^SIz?-6Y~Fged+G4ZIqswc|@bG;w4x-hg`_K_eT zMIr_VrG$}PWS#6eIGeB0Pl>qV?6^hxBR5|7dz_E`$w)DU{^UEKIDQ+%AFe2q>6p)M zej(|$lcWngcao3MU`{onc}dS7;fM3-gt-`L>7#y>B##j{icev`1kIC}sl?2+PhPF6 zCPy|~&lF*Jl#7Yc1avYIMBHlDEhARUQ)=cYDXZGd2czPUi}keqVni?aXv9Mg9!oey z(zKI;`BcX{<1jT>SR!@}Wor2eQ}Lg$#=HHi8}4_o0@3C}9WMU{Ys^xdJWhpeRFZa< zd@Qt={_e}6wP#WLyU~Ru>k?CErf+7>{T^K^UH{p7zU(2;guUMGvJCEXkgntQ9Um9= z+m`!r!I7wWjaR|Q{AL`&+q{a6My1UY;}u5vPZ;g|wk4P=VPzhsExyd$iy2wZX*c5O zoGvLn(SSX&*nOk{dt^<&(}3~2ll*r*{yC%I?mYiNZrpX29(zNz$lXJ4$OA0AiZXWb z7e1FQKg%ur8T$PTX#BTXMSmIBujN~c2kN(DB6UCw%kil0YuwFv+N&COYqa!Q<4&;J zlYRVy`e`bZbgJI=VMXR?Dg5~PA6AvS{_Z!m;U3=oB$6}lyYiI2uA6v_HFJcXtLdyW zv1XRe=<#QWXlCKOV7Vu^^qDoq~5pP5OpQf%6Z@4yo74dejBi<^v zBdW7h0YG&ABYJwN1F)mcADRFEhD4`*2@0_@S3eoXjb8Z4j-1|EOUkg8P8BL1vBT=9 zT>&dzuh`*(rByg~^xHW-Fdbo9+4pDwFvYerwgaxz1=|tLxMDlj{E<(v9STDP2ew1< z5gxG}%xdut+i|YxwAXL?6x-ontn_UC!%ELPi|)@>dV06gV|#(^(Bwzq@k*gj)C8=M za*xpgL)o5D9dPB8|FNPvM9%#H)ge3U21%iE*p~K%Ylg)c&!NC1J>xmBS_)}O5DQ zI<35$`cZTKUe%96CfHZ?u=pAO)aYC*mM&woo%68pz3#<(KdGy8Jbgi@-+gxi zW2)MEMNkm8kUWX449;UzmDzXr@7RvN!{IxrVbR|)7j#B1R?aR<{)atw>Sn`o|hM$MK z#;Bel%em?kytnRhF&Dcve!?XEp(eHEETzoQz zO;zC?{i9!#xkas@Q)$MVEkBsmX5GSoGUs($`T35%E;%=BCpYDvjPk5K_M=hm;X2Ct zew4dO`zZIVJR9XY{<%>e{U@V5;=Z1rjwLcn-{)8dQ6Hx9Zn9#)r(l#+Jiq&tyfUO z;wQp^l^wy^lA9Udu$?61`}*6-J-S{aYwsKVam<=p1BUdA9ww;VwF<6x5DI2kn^IQ; zgY!8Qmy9>C&^m1KmU|&bXjDy0t@|xAL(yiNaIqxad(7#+R>_gs{v@|u-{rQ`h{4(# z(2*Pn#}yOj_-%0Agz7Org|2(fC^w+&hdf}U=qhExq94P>I%3Ft72ifzt5>aUj1U6_ zldonox((6rRm?WSs};uIlvwC0h$gu@yzSeld^Kji3c|=ECjei?9A&r$N;<6J#`*Yo z=P4f_tLsuudx8TOQNk>d?rL!}bGk8{t7qbx&(e=|WMIsqEk$NT^qWm80^(o9J2i2d zpnHr(f)>heK^%iFm`a4ur~MhjJbQ-jQWvS|u27XFMilv-DP++_&TtQpJ)2efw(O$zDokjlOZ$faspv^#fv&FHcoL3b2R>w9u zUcn%f=r7j&1?y<9cIgyyC&KC4k$G|UXn+o_WA5L~LBRKh_N*^=J>ix|vAAZY9V$z3 zmXB|?jWH75B*Z7D*iQ1_v~8E&E~%^JMy4HCO8b32u)N1^_Vs%#oV-}l@3-&avlX-C zY5zR$Pj4R1oj+wyoT|r-^O+6W$~lK(KZD+!I>aD@THtd2KW1bcPs4oOM*l|2BHCsq z&@jjPzkjN~e=26T_vKm7Yn4ll^!Yq%pT-Dg#x33XeJxy}UV3+a_{jxKIvb-`$%dZS z$lFnldyJme))qFjxWmnfpl2G723G&C%>EP8sqs!|M<6i6-0xOQFIG?+0*e+E~@m6HAO+j zKhNjiZK=u0%Q#zRT*sbcr9!U!_$?NLXxNsY8UI{$W^;l+h<9@XYd>yRx%n+yl-?dC zH+$NS-{Y5ueS}t&^7AuuYM-pIfc#;L6{ZS~2O zvAhB?K;Qi8rQH>3zCVk-@TmSqQ~2c6LQwftTc775YtdXg^4ZDtqqEig_H2FC%6op! zZ?u?K&u`nCZgAX>=P%Zbz`7cx{=S+T$5QwlC7BU>oi?Cyv)y1ch?nNK?;+HpC5<`u zy^eyPynyCr4AfO)xrxKl{S2R%+^=6O7|JF(Q<_Qd{y!-q&CAF zdP+f-O|%L zV!&L-5Up@wf+OB0#3f=}kMEm^fTSe)YEIrDc%#*9i6y^q$|;#siKV_<9V9OUN24+6 zM7-uwjZE104{p5uH<9(t^SgihzNbAb=F&sBR<{Geu)hEI{e2T}+*jmX)vncxa>!EA zZjpf?uyysMg5bsbRfeXD=ijWxBW;=fF3ur0Y)R-PD!KVRHi8($z`ENaAxm7nd(^kR zM%38lfM$tDet{DF&p4u1ZvU+mbL%xZBd}y=zT|nNd*qy_44fT+Rm+W04ra~UIF0On2F~oAt?D?}?(u|2q|*zw$=w=0o+-GS%QNG0hc`3cx89NW zx7LRoA<7MU$EYbI{Y-ueOG!76_j5-Rgf-@lsS76=*eR1;0U-)YHOkOIzf0s9UYs3loZ}CPKg_OSCV=dV3vc_84 zHS}m~>bAtLV~p8@c3o7h82AKD)zqyFupDX+|No6?Vp*C07t{QVt(&=(g|8c$(Ci>) zZk50=rI_Iwc;l-{;;d+m$6WYctSH1+`@kZAk*^vV2bkcJBga{l4iW*jm?0FJWHdU7 z)Y{U6sg6fS%{IWlF^0;|RaJTc-Dw>}FY~F7d9|kCa*-#*ATeY(vy*AuhRw^Udz-R@ zbxTj^PWl$S&oIW0uOi4EuY%l0A0W*pnDu#H?IR9}EH@>+h%Gy~x16sg3@b-xh3TYA z92=Hd22sOT?U1XmJw|KHsa*|QIHu&Ba^KRq$JG~Si#(ys=hjl-yr}$yA~uq#Rl_5s zWiISjqlJHYB+(ngS3CAgCy9@%J(k}4;ME5kN@DcQ*$}Maw;@{`Uxf`@(%@*i(Q>sz z_loNLT-{|ZI-CV&7=D7DIDuh7;MR@DOjDkWfnyQ|F*6=O4Sk8xYhA@2G(^+P7Aajl zJb7Uxm}cbYs1BwOPRg)0^>SWLir5STqYP@riAhrX^j^d*7R zg6)o9;5soD&c5h%z8m)^Z$-v#!lvmwqluF*lRXe7F(W)>r`uyh+u|RgdftvPmS>F_ zIVUz4TYNwJb|UgJmQk&CDHo9Xc%-Y=2yPr=hj|Ne*Z`u!pbG~{g)o5-PfmyNC9Ei| z_-W^LWuL7pOPp@V;f?4@!Q)N~ZIJ#*nuqC`{-x_3d8&z(Z5@$(8j%$>aQGla8-;^G zELc$Oj9}fCwF1%}6cg2{`q0d$`gE<>3qvij`NmhXhwZxj=BDN@XQQJ&_oQAoNNdbv zNAx}{LBou)v;M+oYwmR`AMJhdiaXx_ zYa8mN4Y=a9YCFTRM*gx3TgKcwuX{uF$)A7kWG%sSKtlFXMB=cN^Cq-k;1l^n9fQ5JCgshgP+%3*(1#2 z3G(mnBV>IPKk(zOAWtFR8Mp=uRug!*)6tzy?)*~BI&r2}SfbYc*4ws5t&1-YQERMw zw??hYfyCYlRUy8MTB~nHts{8?xqk6Y6<^BD-DB3ELM}1u+~Voe>AQORt_sR}%V-Z# zyc;b{;U}ff>GYX0CD_N@_+OBNp)xA_Z(LdJMq)hfbM;!TQLYB^I-aBnUTa4`0_dbg zrOcjTs6AgzVw3ob&nV=@`di`CMqp_cgK!lBHFvVJJf!MqO&3E-M;$2iF2A(6`Y*$ zs?`$Cdpk5*vc1xCJ3X@B-)EWc==gII&bw&kv(!WpG?ZVn#IE|IR5|(|;iD)j=)a|bql|SxzPj?>BAN=mMZH&KZn2SX$?VJ_KY}&%AT638!l#dp>L}<5b zRFd}qz#5uawvxrgW8ah!E<{!b(Jsg}p#eM0#N z=SFjI7P#uWilK+lQ-=MAC>dD(14Cd@!|I7(xD``i*MXAITg8YMG=NVql&61w4(czu zhgdsyuEUUSwb^d2MNZIR(-^@Fi@((#e4hU z{p@-1Kk*Zlu+_3p56(P93si;4n-(72t$|@EBO@7G(iY|#iv>1NDGjm=!r@tafn^?J zfCHC|hASRKdySevWZ8n5)aar{W{Le9gk>c111hO!{F#i5!bZJRZX6b?i(Y(dI4htP z-duhC9`W>IO-A+TfwTh6S3yo*kI# z-c_fX0?;?=5BYtd5AKGKYhzx^udI1q*=k+Ij8DB{%%WPkKsm?o2a!kQ>h`P07vZ~y z90(}NLaU%ZSp||iVY+o5Agl{CHX8>&8z8dbgYg|y!VN}G`>eCYI_AB3Vb0hpGk3RD zrqFeF$dFTSU&c*{UE6;@_L4kl*B;|gubv(K<0`(B2hs04o}!@dRxk0zBMvFN_ULE* zwb-8HwT+~ppJ_HzTl$WEaHnVe`jk|^KPByUhm9o`?PY%u3ePiAZxb|Z5{-Z78`hSq z>ws>7cA0vNgkUUBFTB@#B##g;oABa{YHnjSB3^@KN46zIYeWt0wFtE(-x#MC_CA9XF_Qv=AJvKiNWOj zOiN^>0qnLmDkz=huQvRzSGaz^!e7Val?nYClP9Jed$5jIl0U}WNlcQxcyMv_24nW> zh_-W-9W-Xp!-_Wg&*Stu_WU4mBWNKk%^zdh9D8QIW9Dy|)w`VDt9LQK@2$S~x5zQE zq%#-PHF}KF}^#2&aXxYKFNds$-1+I zD|~?kQMQ+FVnJYl(qk(>MMA+V^hqyritHoS0AC}ac%MGULa`^Byt~<%zBT76Iu^HX zbL^WQ79Amv~>&g%p1{Lj~id9ywYua8*3{IspvLMO3~#pl+C zw6xtsiP6jKV(7r>H2u=XFA&lKJ_2;)4u7apaO@n11vJz zMl)@AWDiSQ1N+IC<{Fxr1(98CfH{_YMU1RR4*ZZ)v>|U_=x5mSsh@%N|3}D2);wSK zQ*l3wYoL<1o{A?&B#1eM;Kw*zB8MDIxH7F6w`s(^fR+fR6b4S~W_^7+pHDS7c*rxP z;VUl)rVG;vNo=fb```LNKnZJ6{rf(Uvo{0j9{yL}42725x4aojEWT*Rug}L*G(<(@ zG!Al`O{GkE0AXM{HCWaDPdVB8$T&nQ{E5$cw1&e7 zu+LiA{$O>$yD)|+Z=;+pVv)d4%)I%v3~+j8s5|y{w{{feB|OfUTu09Ca;&1)d=08* zM#W=@_!7G~=eBa(ix_S>^ZW^Bb+6@H<75o2EqFK`&lhJH*uNlqoSDZ&TId|>C zt&7AfzPk*^cta1K>1i{Ka^wpvWEe%PAq_gHe`MVw_ED}kpaLgXG}=|!G?XS7sDQtk z3G{EnPqRLe*SlXG3nx`!kkP)s<9@*z3K1n4Rf3_O8yqi?fWyrb6K40R285Er6uIkQ zk;Wb7JRJVN-e4PhR%VS1M>%sE8K+J3Fve=Ot#?{QrHRjUNw5{xIi$-dniT^1&iT_#jA>C;o9Dz%eX(zw(r(dbpzY0{p!>inV z_5pMvFsYykn5Cvb)FQhko>jTzYLKxc<4E=vL)CqNxq_@IlIx0k%i-lJ)p9O4?p{4B z4brF+uWfN=Wrf3<3kNG4&74ofUCEi=^BI(%O~2pV3s$+EzpZTOJpC3=53-eITg_&_ z$ArTkMCwy!=9_@}F{G@E}@&*oE&emQkob_ctGYRrIehy6G>4_@bg5V~ZWEYzqi zGc$E4M~3)UA_efwmiNr?Wa{Sq*Vfxaw_UyGT*Y*)QAyQ6y0*+_u*e>&_9-=Z3`!!- zZY~IUYG6YR&~J3xkjy7ml!>6lbZ4se0hCGDX908&1NVc_gh!1U`$(Z3I1hY2`_N@? zcCTd*TrdnP>mjiOoR~b<)?u|Lu%$}`8x&5O-c8S7k0va_h}_IJSupi0c`Ff0I1<|5 zATetl#XA40b(jnAu62J$6~F3TNK_Lq!%FLzj0QHew=KbB=%C=&CTs(yCt?=bfYsb} zg;BRi))x#6|BK$CM)yJQ{)&{l_AYLp`o37}{5dWNWEa&Xe%H4Le%L3`im6w#HVxf_ zqnY^i2iEAh=(6_EWvAZ}wIvgUn`6AzkOx;~6CMvG>@dN6suS}rcX3v1A$_*uCr#S! ztT2nD8R-@mL)A#hwkIAI_sAWBd;nHJslT&x<$PM#^T*k6TjBg`_zSD6!@uLP7W1Qr z|D6xzGrtMSe^@5t;8?omU0$Rww{QD9!t;3V@ytK(z?*0OS!Ufl^Uo-=Wz5;q*D6Sj z5qgJO-ulZGwLA%ry?<>*aYP*Yqt-F|b399PJPTPjNGGCo+x;yE*4uu(?ghQY9VizZ z#Tk3mYn60#!iO}aO4FH0!s;=vP zQcRoss#qillSrgJN%<ypa##`Pk2UocRrD)`HumW(9VzE9CoES6^RpDrYg}_qa zz=3^+jzY)K1tOw>bvD)j^CxJTCJLkOua$vzT(-ZR&Huz)at1KR6TOs@1^(7#d9C8HNvD6Y_b~cnH zgOwmsNG&(ef4tA2U_N1cB|@5YmXS3HmpN&yIxh$ne5rg#6%geGk4vNTB^XIHv>l=K z1jE>p(e(NmL`l6e3cc&9pH6JN-j^^aNfN?B9_U`aBDxp-PKb3eOyr1e3H!|6@F`l> zf|aGwvzxb#5riaSGZJWM zjUb-p{B406v*FpJ5A(P6TD2ymjwEXe*L@G2N+asIJR^9|oyQZX723fwRWil}SAn9t ztz?^d2>Uljm2vS~l)N88zk(GPk+Y91y-L@)(iqqM?6{~{n5owy#$O`iz8bU(x_bt4S>J8lRK0QZc&YZ80 zU(vk#KK5QIobY5Z?T+)8uobS{ENL(KX!$fk`bH|pdPhS_qGvT%eZacqvz9bTRlRM+ zefMq1EI-r4u3nXIA+j%=_a!2GzwZf=ooHGQnnrxruHVcW$U!nX@m^ONpQbriBXWYO zMI(|{qPn;kr^B;vd0(AY>Cl@|U-}*|w}u*0F%pClM7R`NsHT(*lmxt^<)%UE_7wxz zqR+rRt5y+Bts$7Qwe3T^TuD3=^qYxL3oq;lwO>PSU1d?JTBL;_elI%urZfq3`pD9# z%mecjbQO#$;j5{mS!x*7RyAW>%7KsSLP3X4zgPFGpycM7`c+XoCTH>$8A_LZ2`x#F zx`lkr%ac4TI2Pd&>C~@ZFdWINE-Y7_Wi8XTuVp&_?EU5P{!s_e?pP8{iHF)DV#HqD zz7M6+rTyXk4ZY@Xub*+-xAR=|N`o{bxZ4AHy*Vx~5{d&y0Dd$Jn0+pKALQBxZhQFD zxpj{4y=(tr)SUA!!$yB^#!qM$hA9pE3@?Pu`HEH~ERzFAn@KGzyylCYHi`7#N zB(A1%*+<(`WY#g>?8SXp<7eMwe6KcdktAtX?$&) zwPHz*8vT%5_2}9Y&HI1Miv|wfaV@MEICKUP>AFPm*voMuCyW?GVle zM)6*omN`SoiRxY^`s~6!OM8`!Ax&Z;eL$>NlrLYbxVot`Ofoh~SdKFmaejvkfxk+! zGz!viiK959_Be*ap2xF&;C1ROm(dLU6eE;HWU2LiRSCnGju)KMVFANRSs(=BGz5~| zS=w&{J=D0zTt}q&ZkbhYZPZwSGVG%n)nbL}h@SVAX{Edl?aPtIM_c)ko88+-K8*<) zu`FDd1NYP#xdPNaBUer)qb;fC|}< z9t`e4TqEC|j>MO&+7?bEd;Wj)c!}j}&zQj?% zWVfWyX$5p=;|-a2i^n|cai^0$VW)n`vczY#vQGEDuv5{U@m-zMn|sX{?j_XPSEt3z zQ{U4Sng0!4k#;`%j8@&xk?&qm)uI+=m8_duE)uzXujArI<@G14@Z<~hj@nVU5o-N$ z+(3{a{>3RYP8#-DNQzexpd8MM;dW`#g=B>BA8{8kDM8P`|)}0c@%q`p#MRxNk111$A>#YB2se1GJ$rX`IEI{R9rs= z`y4{s)K;#ZjlD!Xg)@Xq> z2;*%fkGd9s7D5x$`d zT(vdoE+Kn0WMwN=|75mt&BTEsZS4HDSCPlMr)GRg+q6Np@yYq|N#;@Gf|28?X2`ft z@~>of8&=q0k6tY^ueOV~D$H1Nd$n>fZzf+(j%wzX!g)J{ZNcKhxB)AHyQ~ zSjo&SmCS%`?p9D*(@fS+`kgD|rMyQbzF$RLJF08wE!hoaBc3A}dovKn?kg&H6c`Lj z9r`QV8?Emel(Ot+#r$kMy9s9oSxQnWfuZU9ptYP-Cw05;XzV;5z#$gY+r`{ z;$Q9i>M9;HXER##k6QHU@Jd8lvyNq@f*!d5!`?mY(DWYE`WYw3A|3`kNxBPJSKz&o z?JWJ>pY6Q6i2mR3$RBJ@^L_XI=u)kjl_2_cwh3}Zf6 zaZBxDj%*lJ8*Q)J80B@8Z|7Q8pT73og{xrC9C`)vgN^T_p7^$HdNWq$0?g2CuD~&- zoCD%l1t}&75#J#&a8|8jqp3+YDhKHqMFrI2G zpBl}wru&fA4z14`JfLfEv;((xYmfJ@Y>3}m2MpT#=9BvRBwKEYr(d5jqmJ)Im!&)2 z=(6+8H@fV;GW-0KRr$qke~w-VdmIYx;ZYg;5c9!ruvSw2dQ;TYJjllU(gV!T5?%)g z(CA-wMMOr*Cf$&KH--MvXHB0q)mOn!e1a;%07QETRqoKSg>IWj>SVzNrnK0>ZI1Mp z?6Vtt`MFKcSnpSl%*dCbGt%d6R&eDw4zb6xH5J(MXr{i!6;wA_9&MWaRPEXjRlKWg z0i~*^Jzk#Yf-P4Y@gRR|1r7^RV7yrg5pw6}T(d9on-E!5Xn-ytOz&{B>ZZ_mu!y{vP?9>_LWfILh6Iwr}pCU;#dp1{!SHr4zzx z-(IiA(2&J~C(2Le@bF|~$!$KV$CCnWy5{FLSF#2!7T4c7CphZuBoUz8_P{07TP}e+ z0qsk7JB>LZwrtKVllS@~9sx~6wi{$ZJJ!#88WTM}m$?{S;pyBg``Yr`6HB$NfTV{k+l&0$P(okP4rv0uB!Y@-`v^1W9*D$Sxzu-6w4 zTRzM^%)DLaS<_u{L$n;d%r4e@AsLhHiCA5ERzH`=_tIF^z#HmOf;?h<8L?exM$mX! zr%j?AX{J+%pcM!`o{;)NwH9ecynUprM0ugK1~lH#$D3%pNz1TN4C$Z;aaw&xac?>f zi$tvDc1MU2U49wex|+%5_d9~-qcqp5)2F@Y*bj2pJCk~ON3!jI-IJYymsJrRcUvTzhgR03 zi`4Pl>U%{@|H38mhI+c`aO~;onW$6?uxu3dN&wkZs~Kf@jJU-bf{iK%R(fjdF+iQN z(92;&kJ&{lGsW1h+=hNn90d+LCH6ZBnc6Mw_1zXR>XfMk#}RtlJeS+Bm~P3^Z>h_+ zeP6>aSL@She_u3X=Wkh$UqW2o?AJE~PmS}viSrCmFC+P~%Lmf#o+P5%t;TOi3--0N z;IYiNhQAShsqieU349BmNDKEhBVWiqnQ@-ELW&jN7>#)&`*;tl;i@>T=&NI~UWDnv4`IDnv$lJU z{!HA?!K04A7WbzJVzjxEbYDE7v5CUS?!*;JP={FWt{(@GL%LK+5j=~er@Dm~>)bcW zK=5MjyGR~ils-V(So|a`FI}=e0wP*Y@9jHVi5A16qfQo`Zgs}-RFGU)X2owVjA}r9 z2E1Q`hnV>;<4$?#@{XIzt@kxzah9u2BN}bsA$%HPBS&wm-R3FJapD{+*&|q$7`89k zRhiCjmJe#w>{nun!C!lh%E+ClA@sJ{za=^Il*U_q87qzc0OH8NKc=Mmno8l`OjT4x z-OBW#bl(Yn$6rkCs1akd!)MaaYck&1NS2|DEBxk1l@`vslZX+}QR#pZH<{UnF>7jj zwk9x5Fsc!@Gb}OePZ@HObXcMBH+(Bpd5veek$;a++|bGxo$M86#z+XEaicX_dW)mN zF$GMIMjr}JCyj2zD096Nqx(9|=vhp#g|~Co5Olcf9K5bgi)nLyj{VqUb)Kx${mi1P z_T97W?;&3&_gb>0k7E8>DS`hLtSw0QXfqtX#?~^`Wyyo9yn1fYAbRx?Nq@yQbdlFj zo72-8VS+Xowh>_+coz5yTt!0N8dDIS}MI=JR#=b3BgJ)+sNzHTsNj- zI5=rkL&{*yl6W@zFYxf~&ubC!siJ447Dch6xI^vg-@spTow<`YwmrH7`>!@?Gi}@^ zRR)Bi-Sd_;FN^i^;>-XhIZ zq*gTh_~yGXM*>83&mQ%4cBBqH>eCDZCgtH`DXR_R4KZd04i7QvytsIm6NYg% zjQTq)Q_@fc$i|!wdlF!)1i>cspPkwgV!;h#LtN%NZGpo65hGv|8j4!I*lD@ zd|ao;X{!B;bEX#!j`-4uf^2|g9?kDWj6$O8JrV_9CwzI`KK#$B1@rUjji(Op>L>?`UW!*q-!WacC5s>ZrD`ssa|4o* zSVPD7xM5p2j9Wm`gI#mFv0b1D`qW{nCR@p~LgxkOH5bmFb9%w7uSVJ@t(lz*4u{;aig5AJPC_Zi_KZ?>eIHknXQ zhTUV6FKGi&peDq*vk6w&fP!B9Rzcu3G0Ot0Qeh5lZuc4CcW(lIr?!$x*aC41Xi6fI zo50d;ZUZ$2rny=ZK@`q4B`d4R&gayMfsv=r-=v^XM2E69#gs);PK7KG6d(RXgbUTs zl5quSDZw=5O;jU&tr{k-2JxKbK6x6(6^rf%L2DuXkN6d%(`ae>{_TKTzL+V7V`EoiQ^Kvt&AnRz`E z%gs1v)#IEg8=veyy^W+tMGQq2jgw_a0eAC}AjG2XHX)1-{m3TNV@tLdb2r9d9>$=k z!tv`d5Ng02gS?DE(iq4}(?=k`Faned_NW?fYd;xv(&J?0)t$C3DfK{m=r*p7Lx@;G zoY_eBDm!AdLt5=se9fyHYn8E#lfu<;(KSPQSqtb>rhea9tfVu0B=NywWjU{DTC93x z_pq37pMApuv?;d@G%93ZNyk)u(Z;mmMQkcmbpLNAC14FUyUm%cRo_6(+KPC_obhblk6xDFDvlFHwM+6rh;`P(p>{rN(Lz4_?4w6I;kpHPDMU zXeegnS4nTsS&ZpIIBRDx?gy6MzM}xu@*4_(7Yz!C;f4ZKH5Uqio((N$U)kV3mLhIA z)*?f6&NXC+iw9+%8aF&&ExeC&)93uGvcTbV+NH}CAC2BZ)TH`M=}=hbW3L6DN8(jp zBew0A%npsU*p9lvNzzw$l0NZ8ICEMlRdAfC70lT%=rh6@?>D|~Lg-mqIBlhHeiMim zJs(SN!K;2%>ycwc1ydbk!f4g=v5d%4;GCIG=ZpzMHA;0q!&K#~(UuTFLgG^atpJ1+ z0}~VT*7Lk7qA%-GoT^24^cdpL2c(vAue0!V%v+_5N+oXVJR*mn-?baIn6riFIU|0> zGJS>c@}>S_adPCXb?r54PMUK=^N?lse2*h0NU3+oCgZ(5v&V3)49xo4GkL~Iugsd2 z)jfKOWh=x~ni)T`nM1~pWUMgW_Z-`>>|~bcZuLKu@rFi#JedCVLtCe8O0p|*-rC3v z`aH|air+g!d!*GsyOT8EUE;BVqxe`OoSEKla)v05HI8~B{Z27*hse_`2a?SmDR_9t zw{qolnsKh3KGZ#3-e9Acwo~XG;?irpqc^)i`TD$TIj0}}drYlJgB*v8er>XxVXZkn ziv*9#11oHpoLb~oRR-Pz=cL*&5**a;P*RFkZ3(9aC8$NC;}!$H*l6q%;fPpiwV_df0**YcC^X+O6af9i}+Xw5!18Id96FPz`1 zSMME_)QwdO!X8HBUofO@!)!;ec{#N|rwA&1}U!*A7@Lz{Zkw71JSZEWn_Z z94){-(o%K%FFpOj4%>ex`>%D#(2lx4ZZ9m zE3taE68AAYS&6mF@5dnGK8CBEI}v(wTw@;@q2UWw;#ao%J_7q>=l1382*_Ua!d8#P zjnB4vxqWWwwruG>RJYi+fedV_KA{0wJ<(0i7VzM2ETHz;0xIq-pt9XrKrP$AWB!^A zynf9BD$B5d+BE|BogLG*cXmu`x*b!xa%aah{%Xh6_1l(gX}2F(vSr5y+SgIsdNNK{ z+GzKcjGliPm7nkY8Eg^w+?t)Yhqc`9t=XIVkNPt-RSSJZ1)4BwSZmBTRG>||P=Pk` zYRztG$gE_op^C5qnp{>5WB$y^|GAkD~{IrDci^eYR9{ z;9q(mST=a+fe60qtj`{ZT{^n=K+szb9te|v>VYuZ^gw(KdH&#i@U~;Y9efXNpr{>u z4{jSM^_ypl%F z@4OeTw~#P_ZR_`9H0RZ)A<61+@@de{KEz=Oe;m_|fK3tKRcJ`KXHM%w<*_%z=2 zS8B#s@oTRapGHdljZcGGx}q?Q_8k)>wcmZsXG}3rq*l+t+g1;rl5VG8%j5BEm z##w*&`!ykaZg)WPvJ=Tm*>pzo`Wk{5zeC+q@f)NgyysenOZY<_uJ=!yVfERslaw{| zl}UfAHbp*Bs#<^1Ll6PlFVQxt?U`32$4XP?K;{)3YX?`l9>Vd83ZsMRd_{8s%YLJ3 z>>gX=8%!R|dN7-R^(TFvIG^oqXY zbFOZ8a`;YLFMK*gZ~q_gihd^9bL4{e=3A1zkK52bUdr`)m+OCOIk}PReQCcg*Zb_h z=)nx??>v}6eComERsYO`Iq!WyCJ!-PkjVquAif=K74}TOFC&hlnztg3e_R)5*O+LW z7j219Tnr%&q0NLTJw}f4<_tBg4a5{5U6)5k_N0iWM+(Br>AS3R)<&*duf;qoaSR+N zlr6)KPQ{rXjGUw!`~8-Egl)SeDqv)e50o?|de+rld(NNR>zLw*gID)fJ1_CKbu?l~ zvyR4Sg~m6UpUrK3Rc_<=$Mb1T)*;n=AqRVj*uvgF<+G|{Dxpn#rBVhK5sK1q zXn@oWiWHiZrKfaCCyK&o5+HBwGt63$MWXrnj)F5r45=EoR&hgU0V1y{z5&0c)YQ$y zR$Oecz$uf10!?76AbZyu3KMXb4{h((z}X=zQz5DRcM5TfiRO96rUcBBGp zM(b3AG$jDnt8VildAQFtI9O%dbPEx`>+`Vh6fHY7e?Pr_?L>NrZDE46N9FgrMcP2*(y(Ev4VP zfyifC;fm2^RGi*)0x`IU!$CmNdJ%?L@!M4PG(8D8H zmB_IC-HLAdh-73OGVtW0r4nTO!x0ye0g{dUo}x>*E++peZ<9HwsrRD$wOU{ zOWja8bOQF10hRcwG>`;q6ula#85P(_dPZpo5fc+^yr~sO%Oj>ZC$3dnM{E?2$HR68 zEk1|uW9g21p4=xy^S$W<*WD>$_}lWvvL)<@vR1wG4JDgq+PAGwJGw;gkEQ7n-4kNgJ`}O{VaxCP z5DB|u&b%bJ4Pc(RX>FGP2Z2jr4MC`asD zs-x~O>=}7}Betza7O`TRO~<0)Du{xxNwiYCpXC+bV62}WiAg%^ip4E0$Na!QpuV(H zQv{g+gxd;DqY0%pftZm6-nwnk>JSl~C4pQ3l&;`#l{Fi0dz{nsI&D4QHZ{VQ!VG>H zJZrdPv}YeaNGWdh;S(m-MNb-gGYX1f;z%k*h>Ja^HssG{hU)`YIG*6xZ)@%6OC|W1 z?Z`-WMk5JdO0^MxMbRf>uf@5nbLV(iFKgHiqcL#ufVf$W_aHi1X-wM!2qhU#G#P=* z=DdNRP=P2!1IY)L3qeDT&TyXEfrhi7sKbG}Pynw6p=YQnc9bi!fRNS>vJb8n3~=CK zD4tdNe~+^=?X%f^eO~oiC8(={Nb^&zp7DbwpT6UXZlJ58mD`Z65anL$TY%~o%(_O< zF5y1;hUn6SkcbF`h@6e93U|RWSCinX!tZnsqM$j#;(@6{e-k0`Oq;4lp~M_532?9Z ze8dCQ6D?LC^ewS49u?7K)c28fF0=W33cGBE3?K~Aj%_nmdd{hhIk?lDhB2owQ=lAx zw2iZc=#$Pxm|wrl8_t#Y`a0W4r(;Gz>Cv2w=)O3Y?`CvAt+6zbmZkpmv>p-YeJ08C zN4D6*S&c&L9oL|WxnG+-`i3(|H0dY|1?Op@NV+Ei9fBf>f0=UO{>JSQm8$2eGI#TL zbK1Hs&(qeWFUc3=w>qBdE|$Z&F4s5Jw!f*g_iy5gfk>~x9N#i(mEF9>D>>idrTXM8 zTmi3?!#g}%m%q+WSIY?Og6N|tqWlLqX%Q0xsQV9OKl!_TQ;89iy7T-ydnZZ^-Pgc1 zVcK|(#{|beND(dk2l!c3`NYqF!Cd%RK-1TWpXq%^dO`aHcOoYGsJ`oPcWF;oaPRRc zLHkhC9>XgOKZE_MzRtzI#?NxDg~Zg~=VzgX3qK1<-}5uomf2h83M)FmjP?2y_dIOn zTPr{N4iEbVKZ}f^LHj>`vi}eKEX1SkaPTpmI8Ed#yZk2OzrfFY&BwRsl^Q^Aw;*RD zg7Z)4fa4#B9YO7Ogh0D(W`lMbp=v_a9xMnF57$;=El2CbrN-Jo7#*?k{Y{?U1hjQ{ z6Ga|xomUa>jWx|(PEo3iUYyn{#mb>!v$^EZ_bM^2bw@TOKgjW|2X1l`)0RT&I*RSQ zCdF6= z4gG+nP}Lnt9N7jZ0jshy0|Y4u{%z zL(if}Ww%nKTt3+gK!J{W77lwMWwGawoZhk#wm-jR6XK)2y-6C0!pd%p5=!%tj#iP> z^n%8GrnHXCJv@}`XWsYH%5Be-Mv;Vsk6pt`UE@us{dIcNI3?*_@qx2vs{T#&j;g0< z6unR`X04nlS2N`fjy!0MDern(0u@WRid2aeeYD$1B5f<>!f(Lye|S0$%8j#Thg@=M zvh*FvnWOlq?y1nD+6mQ|j9;sG(j|!VdY`x_+Q|AEq$}^_80k}0X09@Uwe9p+|Cvck z>o3t_$(Zo)8-j^mPhs>k@;bqZ+V*v#RnnwgC|bW88Rs~+YCk!B&a)=%)};`17qkz! z0^Mola`NtbGuPclm~;JXZz9Gr=h*ss*pGQ2*Nfaf;a60{%*w~Jx~N^tDYAU56?nGo z&3+ZG2=;;PDUJd97 z15?MyGPIboeLHC8Xt%bj63TDcu1I=n0p!DE%RLQE> z6hd>rVZBY4u`BKE*H)}vt5nxh_F1IWrMfofxx3LQn%QNWrnfI@6m{DU z9HgmHJ^Si?k#}zoJLhVj_1Ng07MSrSBki!3|51NE|=m9hG>IQnN-FC2%?b_S(|p`Ul}j|3dF8Mb%w1y7l#6C4Q@4i&$ldJfxPnN~0aD|rQ? z5Gq$1wgPA+Aon<3uO0~$;J@OLz|xxUJQA{Jd4Dh~8_!C0*I8-iJ*`n3N0;+FOh*YI zAVB{uXk<#K2s2>|>@n4h$hi8-Cyzw~f|sxf5uqx9AYYIW^Xa^#S}4GEf?K^}L!uhK zQcE$~aYVoB9YOt2PgjvPu%KbV4qqxv5C0lhT<#TuZAWX77(&7savJ5|wA9xP6z8X@ zLJQ`|$WgC(NY$hPm9(Phz;!&?_6p0YWRA#n`$`7eYewUmOKV>2FCfLk{=zF2<+7DV zsMgZE>~1~I0%shIy>Hh`s(M{5dtb5l;ie>+_E937(0(IL0}P)Dl{Mi6BS zn*>e+);d2QlW%h5yzZKrR9It&^Hs+iU^}E*n%>{=XpeHwZ`%$LExwfuTO{Z96U%cS znx8*m-ELxo!@l=~dFLd{sXN?_?~IL>0x4Ep&YnRG^qB@_%s_|H3I%?4)_#@T5Irf1ppECo1RC_-v$oDhF zAU5Qv;%Ma@;jH5L(O4xRF6wi&TN)?xa+8ko3DxV`hJ50%(%3Ri*Y~qPu1+@9jygc` zAF^Yx9q0+x3iTht3X-;*YRcmXx&BY+IjVt+&Eb689QF)W+Mlgrf)KrxbDXRkIB|pP zdr-QY)<4t;Z>@6Ae8Wb!ShW>h>9Gy`yOUfC>u8+=IhF0oXmtzLklk3ij8%6V^I zH5W0)7JhlMsHuxZjcS0Y&7bWgOp7qL(}n}2C_eOP(A|vIH1rH*oz#H20?n^IHDuo;5G_tPA$AXX#qhYt^)6&*}qjvM1i;-|!|^^v;`- z*rhjE!Hfb{L@_IlTHcImg*>FVF)vJ=p$L7AisLn`h1XDrv4+jzD8~Fxsm1j33G?Mf zmR+Zmoele83p7Dd@;*YT(69wy^rhtUfeDU zw%-_exQsmT$Ty&C7@{k(nGG~NAp8(i1zB*@Ri^;t&|D;UKB$n&lug3~M2VSCp{RNq zIfB3a*~r_k+8(4Ta7Qx#0oy|fb;rrQ8$0D;uR44}ztF0~d!WC7arN;}qEMc-{$lmn zZi1B?D@bNPw3}SwR^o_3v$KEZ;OV`|ECE6s_5g}&kwvbOixvTszZLR2)h!?9)|VWw zGXSk^B}erXMSx6Uc#(%)6!R7Fxxl&h2VDZT)`(HTNVkao5B7?1jEcwj=!mf^9HruW z6r3BLlMx}Xc>1~aJNf%H*MFy{w9C*E#lcY2wfjnp%AO$vTi2)NzptqsqJj?5NbxBe z35dMMW_bN+j^n7}e82x$=EjUm3+*@e?a_d~e~PX;&=E?VpZEEO-iBtH(}+%C9WljT zxtV5%&`BmQwRFFDiUpFnZc|pt<)i!^c*Y!}bSO3mxMw@aE;+j{T^DhQSAc8&A&N;* z;Qxlzi{<9ckPt?+8I5PeHtEZFirL3gKJovNw}SREqt(s+mlu+932uLj`zU@w7T>P1 zO)}NfTb+C%Sr*2@;`e?M|2-wk6vFX6@l!8YC4WyT_2Ta-HGk~ysXaqVY#>O1zG<_E zW!-#*b#5SfS_AxVQ=2roDInYIwJ15oWOW33S9x=l5OWUxp4$G>-&5^&@9&{}GK1?w z-W}JyJ9K(Xe{RcI>6cgcyF13u^YOb&f54%r_oA zMb%7QjjIXtr{I@L2#08wpeQci#~GoQ5jE-Qr9xXG*(Gomi6_-H9+Xz9zVzto>Cr{R z7krB#x@$nWXG=*_;kBiN*LcOj$8WT@y00y;`F*CkEV)=9kmEjjxvDHTUe@N?*@Lzt zgvW0ETx!XEE}grJbnbXJ6=0@tz!zV#wsuR##+H46bHv4J0~|3eVuE`q8ThSG6}8cb zI}bEXSi_Ta-pcl8(s|3~x1{rnN9^OQ3t;r}wWPi7Cd6&|fv4;-avP@Q;3>OEq0fG= z_&hQ-bII!P0+Dx_EqcQ*Gd)NC+nyssZ*aGsBeHnW?$uxL91*Jh$G#szOS)jkPwOh3 zv4p>SN%C9qsBEccztxU`7C64F^N-akJ^i=j0l*#x+F@i#542;@li2%3kr~P(3N8B< zWav>CssFxS?XetFgBRKOnzQ}`zgK$X8x%=1cu|jl#Otc~;EwvKa9uxb{PZ`7|c%nq`!@Crc04i0z#?oYq}jr zXe#u*p@$Y@&!_+Kcmj4TK$aOfE+)fvftG&FHWk+%nKoiZVYVY%auwpBfc6M8#Pp%7 z5B@|SBgY0KH>E>(Ow2#~C|~T+7dmYY=UGW}R?s&<*_+KK55mo_WjY>C+c__^YeYR% zwnD=_%4n|7j`8lC$03Gw2V;ku`+hIod2TxAa)Waz)6%dOkX~k*;XY=4>%$hkXAV}Z za-1?|kAOr%79*r$hk$AyuN&n{9I_Xb=oPs?tTk};cf=6Iq(6(!QqD(~6!5dFA$L^X7(>AFbfe>ackhvB`$U*Nc{lyw52KNc zjQlZ;Amt&I#0M(zGIMluYbPrCj0(JNI~7cC_;={ZJ9BMmjXqHxhTbE+?xRnXM{8B+ zckGdHZn-0RI^WDO#^n%;@}*vH?XK5pwpYK{UiEkFx~2 zOZ9=yT=yhn!G{kl%*Zu+EwnqUE+UIh9tlF_=kX8N_XC##z!|B$#g;@XUnWXPakG!^xy6>S-Sd z=*!TxK*6Nn`%k0_3>+1?&Jj?HszCnc+sGbEgc!H4j_n&zA407^Xx|;%*T?oNNPAlo z>ig}7WBcaVKEfSYbn<_@{WPsApG0F|Rc%>W24MfeN+D79tgC``hHiI=y6h0ucSx}l z?SG8!XE|_|A`Lm8uGcTVsj%?#Ogpk~$*=L0bq|t?bP4RR3YUC^wDEH50;s(T<-$*Vw2YzXet-YSCP)x?~D6!)b2)cVpj0x>T;HzIw2HH zIjOLhgyf{6KEe-yXX5qbJ!sj{9U?hZk$SDF86^9x*xQC{gK?2l>OA<%RB_W%9>vsn zo_%9Ix*EO5-GcVAs-`ING^&zu1XOR0q!p}O z+->Lmi7;yO?KO1wnls%`M3yzQA}x~lX%6c4Y7Q#TLHuMEN}bx&jC(%%!@Eaa&ehTf zUrqOiAAB=am(}hc#l5dvRhHS%Q+Dv_`&(bP9-dwDc+>OhPkJBoXT2}xsrUS*uw5y$ z$03*zhk$g#bTw?-J;(H6#5*SQC)IgYk6%X%K`rq+PxhRuuRrI$`CR_ibKj|9bZ+BV z3;SB1iS$0~!wu)Iy~Dn%ygE1jWfJ z=EAF$KntZu&H6!|A?y`?x>s8tvLwVO{_H`A$7gp;CQVTzi}eYvI1?7z?ew>*vn76+ zuVJ$%*~9dF)7|>BL|KBEH>^Q>7UhyX2zMkutU+rVVYvef-KWbPX?k<>>}{Uc>PH!` zWYx0A%#z(gvrw0OqN*cJj}zkg&ihuPU|pXmW%Vx;l82W1h);mCBF(@jFjt!E=bc@$ zB31V;>x;j9i4ubYJ|9oOZp)%x_;|3)E>)iJs%>+W{zX-iWz2&vN%k^5BARNlaoiNw z-6ZdevfHdOX0enZDGmy~D3~RME)+b4*}H{6=xbdqE$fJskqCR%D{C#%*RXG4Obebz zr&y~cqChJVkM*&*MV?>uZ@_o;vO-q8RLC;CqD`!JwvN(|t$$P{>+tSRtJUdVtq$uF z$W3=zl$>LB;XlXdJ~{9l#=7_FIgjg1awtcC9bzgEv2Ciywy~^_`vGS`S3|p%W`o-3 zGMm=9`+~;z6pr6RI(~Qg_}$dwcP)?ME%`BlX-$h*P4aby02X+<{+lBUd7x z5@{_n+K!$SpFD|ke0{ct&z^O6&wlvcaPw^W@V)8o*$>~FZ=TH`zPH{z+q17w1CFCA zuN2Sic&@!RThnyb%h9v_q~xoqUp0rTp-ki;oU z7Nu+&X$q55>sK852XY8!Nk2&;CRW}*oF)A}1C%3>K(&8rRrFuKjPpQ@@|>AHBM494 z#Se0(aa^EgQr*L&RAE*>?T(_LXVjMb2%$q_30sP2m5J-g*j%GMzN^Q89kRdExQ0do zIi#jlqRR8BI-jcZsiEQ6A!W|i2%}Yw9CvMO96FI&?uwae+1=b_mb+4;`norFx#g}* z{RuaBh1F9%vf*j2x()a!-+nOL4eKzPi;vWZMGyYOH>jPWRiLvTLr}~Oh1eSk8KZV^ z)ZJwI-;Q|Nq=ytI5YGW6h+gehJ6o;aD~hsb$-y9E@jt4m`FZ5n9^Z#=2AaeIj`n*< z=X>4G;o15|hSE(;Ap)}VnUAtf6i=Q|?bSrEfS1ZoJfS2RxOVWiYA=TwT~Bs z{ir5BuL~ZdQbCk$swwZ{5906q%oKCu{Q3J>!;!V9JyqBiBf5wr#3j1un|XCKe?9kc z#wFwYVWwb$L!)Hz{n%DBrFXOQk#*M0WuCs9A2?$D@hGtP%gha3WAgXi!}0lF-#gE% z62*`DE-!sQBa!`C&wrnGoDN|#CJ!0(m^0clfIr+hT&w-NbL;pVf}T<)>WovT2xN2V zr|bQ6yN6QEIF{W*{3|s3a_^OxG*%<~oh;q2%y_FqAL#XYK{phrYc}Ms!~4t84kC|e z2l!;yU%2ig{(_Mmma=}v{^w7XaJs3guH}j(j}!kbyBAu8 zyL_+6*a}gOxRkp4#8G~BoISg*)+si{Xt62nHnYL(fH=};V$!1w+n||1nujqm9$G?s z7UuCDr~=>r*VMpP8rp}FDI%t?Py}I^EIm9?gzA}`;#iw~J%#Fl8Ukb4DmD6~pD2NU z|CAc~IAMHY&;8Tipa$j2g&M+v8a&n9!K??3pbHo;oW+GERIf6)(1b3B_ORln;VN(c zZJN;SAD{{7)?d+tny7#9&acyi_WnW>Y{!I~$|e(N*&CePSP*=>o*uo|+wd7-k7SR6 zNjwra>&zupvI|L>e47aEcIU!W1J=kqr-BDVz@a_JXFXxbT}X$Ni49yh_>$suQc z0m^RFe%lcFKr0L}%JRZ5Oe$~rg`qmX|9yTTz4-@d!QvSIh8FBL`Gxxizp$ZQ_(eR> zL;yP2K&o&$ZDLD69Wa*dDp_DS`-v(#`rv30?x8%N_}`}r8UF#QaJX83Llr_iatJ>; zgg}$|x7D{C!cm>C|2~Hh110>wN(rDUNEi{MRYM>3@JCg8M7^0S@pd?x5A+ z4q6?!1BP?nafcHn0B2BeQiv^g-f%r9Le6g~0VLIbgAzpe2Ph%B@Hdp8TWyb&peH5h z10_U6`TF3TaGTwdTC5Q_=R_>(?Ku&v{1?s%-3Bhjf0Y&zV!QnfEkyH33ue-SInYAd z#4RnHCCHOjA@3!~#0bwXCCF66zaT;CX4OAH4G6{mN7SI>payNfAvJ8&})rs3-0+Q{u<-_GUGE>^ln`*!~C(?-ny z0Bw}$|B5!kL=e*c8?;f%#l9`Yfi@7C7%Mkol{3V!$*Phjg5MBNxX0$5Xrzh@|7h~i zKHMXbe~AA+jTre4&`3>x#y?b;H1ZwowAL&CD71!{y=kpBSjF!`70{*E*6-3Ihbu)6 z@7C`!t>2|nO4I%NzhV7G6s~`OVp>*zL@{Lxk8*09a%x=VRCL4N%BiQ5=9ym7g^Nh& z?7Nc&?rHzTNmIQ0@6!Yx_J2hawmi~AnlzCPG=T*}KcNW^Di3t_Bbor2_AO0FT766P%!Ct(K;v1g;41tSAzzskS-ff$byz?MMo>p_vf$l zp-g(GxgfOKKcTtgEdBxdQ1!3qBPTy4kNkDX1CvcIk_Tm_V_^&=47fkPkurL2Jz~Ng zq>PzO-&>RzY|hvJ5h)|ve}Ou5`z!lL*8Y)ul*v8HfqNM3Z@I@wXVDRDJ4*YouZ^snH7nYTOn=E(5SWFf16Fsym@>?iB7`5-dDXc85bFq| z_oOv@#F)bLvPnrkQ}j&$}eo zB}4-q<~?GT%yKfRr3WDRo75@FU_FL-Q-g$O`!b_cC^7iMjB2WG;Rr(*+AKMih}h3D zc%VCp@;dMErp@p6srDv?Z2}=Yb{VVQvcbcBwyFOxdiLY~}oScg-`L)&sA`tGh@pG;e z_sCe9Va8w^JrL2>bqx{P!!C8e?}2Ur4_<&G=@J(ch@%?&m2=W zufNO@R7NC$*Bqhz4#&c*!mszQwfL@o^_TirUHW?eLPFYl)xWtu@xlIc_EUlc2QryW zi`V+R>e1Evec$b#=Jrm`dgn*!h?Jf2>(mVe9y;eM3!?zn4gUE@$qb= zI(TUR!&)FK)%De<8X?DOTxQHC;$GPU%^RvTnBaiZ^Q60;pyHF$Pvx)48S|{8h>(Bu z#7I@2);~X=$pg*v`D7N(>r9zc)n50dkl#9uQ%;wYqi*W!oX>5!z2VI1cQ`Zl`|JG! zZMDAc->T1z_>yH-wh}Q1+i0t2COmQPf&V&d(}|96AbMS?eFw@FkHg9phlA>#ig=(u z<`*mNXo}BOX-L%35_R}!ALz;=q7D3u(gXg>HDVbLIuB_Ot3{fCXbWR>Axx~NxMybe zF(pBnlO0b0zZtFx6Zo6utj@&Wu>OqVJ=bil!jFn%QLei!`YZO{!spW9<9r3EJ07n% zLzRY>D^%tFa3%Fja=b#wCZ=OqjTO>#PUeEU;rBRX5#|>-Wc(#f5!T@AyC;Uaop;aq zbe}t=c==H@p4`+X(#vQ(Sz>$_jVDVA_tAL&ak(Z1_m9anRmb0#Yuv48Yn;aMaF+O6 z`{Ox76xKP|f?3;6lysqj8uPmhQCYFl+kZbpR44T>_^_J(tN7d`)gD1JB-w%DcE{U5 z6UF>LeTvaua{b`|;&`eVMU}5K&|-ZTqb(a{f&JHGv~?_h?TO&}t1oE)Uie4(8#-?O zC^b@*CgDn_276j-v)9^j&K>-ccbOT$xy`$^RsylX|An>of9+YIJjpj}jd-hnwAMDC z*4l#hloeK;UbWW1vM=>4Otcw4F)v)Vq0hR3X(D3eIX3vDXmv@#swWF>f4>Qg7jo|j z@JCMoVi8fbC6JYWB!9L4A8M%4Obt~<(kV#SV7`7vh({X(;*oX>vb?2e<+M_w!JgZ8 zBpTmn17$6JsVNtYC@osU4i=37MUwX#E0@<$qybe@RgeucChS(3RYTeEuHK|s^j-Iv zz8h6Kj(G0G3teDtXi6PH_)beoD5AtYN_vU)fLkc>B=#;OX)6BpFN zaYmT$oe`n5i#J|o@hMjs`t5pVkrher7O_b5&FDu|k3$a1pY}1a*Yn{1=i@KC<&7~! z&H7!PzMIo`cltiw%HKu>Ko4SC%SD(RQz+GJAels%3MwDdk~1Y$37T=%ULlOSGg`x8 z<3aeKeC4{>2=|yR6pk)2TfELmCeVgr%(;dwZzYsqGulH^y2fw~yvvp=oTjzdh%Sv( zw9CbdS&3fb#mHi#ll`VHl?D(xX z8zy>`Ep*l(S{jFkGA>bsS+cd%kaZPp%Vn!kU~S?8J@*yw*+L+cbG6JyAy0lP1KYIo zNwUW3@W_?aZf8}lZF?Joi?4f2d3m3|*yC14oE~cdSRq0TMDef*uB&v=r9jOh+)9vr zxkaw+6ByZWpQclYh|$F;ZVtxVHS5eB|pKkqSx1EtuDQpM&rphre&?QKpB z<9HZRY{A|}InLRURNrNv8Lktw)Q6aHkB)i^Tvnbe6dg&e$VkAGa_nw$l%Z04?ap+}*2KLqQ8r|60mJv()8 z%T6tP#U1Vle*ZQ&R+r1}>2+U2L{Nl&q4(!RA@Vha7~Lr(ZicEq2p)aQ53~|7pl4kf zGiZgflV8({Z?OOC7LYeXM?gQ%Sclr!O{Oe7R<6K^U8@OIxWXt?_DM<5a2%mirPFH0 z&Vg21i;P2jptb1C?P}79yyiLUt4V7KV&;~F_TOGhce|Emu4PR1Oot2o^?6h=cZs^A zWaE{#_x{LV(u^C#RmOX(nk&*<5HpH;)_4e9cMnfAkQ#Oxh^;=(SrX+sXP`aXn78dZ zXETaq@dKac%ihkHp7WIq)mbMR+w6Edv?o;$Rv>mqZ zo_Z8ZB2E^>#Ju9c2j#V-|H2gWC&nOLM}hemcQyf)3hrOa6)?v9OldCFOMa*l3*~gJ zO}nv%+OJWZ5BWduXTehi5fQl(q^9~~a%~w-tOIX(@?Os!IQYP3?S&6;6!0y#Bt+Wn z6v=|uIJ=Q+ijt&Hc%z4$g2<7qjj{?>?<-u5h!W!}*IGmLbKoJ@bs*~`{?-ECuah}i zMbx&n+Zpb7gz(?!1yhC-2iyxc$PfuCs!bLKpftNECS+`BN`X@4GoDV$1>89f=E$GPhmL zdAE;~0_%(i+}&_jLw|^8%gu?~7tw9pSuD?Mrjebizu>1>_tRZ=Xwl+shhF$@G5)(0 zlFU-YmEIXwURJzhYAD;G%`9?kKsl&MJ8wV>OJ*WR=UtO9FIW8Rd3NM^-Z>spUZ2D9 zH;A!6vKZfDw@nNr%KfgjCS~34?``h(+~u_QE{qyyfvRdT-;=9F@T>@~G>vtJ zMV}elM{xDZke_au@11hFmTs8Vv*9BYd+per|8+Yj*M#XK;fkwvjzmry++JVKTD^>9 z*4e?jXrkBq6id~UK7($jk;K(2I1hnps4XjN5bk`my|3G>Bx-skQN50e`OBc_C~w!t z%~7eF^)c(Hy8hZL<*253f4ORobqjY2qKa<1S52B0vQeparQ~BD){(0|a(tsRT;Xn~ z3aUf7@YR3R&t*iJb^1hZRGra8b>SlM7{3CP3A%NJ)rFPT1_P9o(mngh3|V*gOs%bP z-B|KVSs{o=|O6tlzSr(bYXv(6Yo=`pbgH^ceCGh(AgsGc5KXWiuRP6z_ zqr>rNX6I33xvNwm*PNvx3ulfvr0lskGA?1{{E2dvUaX6no;?ch>Gt%OeWG&# z+FsvI`UJgI@TZI4?Nu*SnP}A*PL1y~D=G(`-9Q{vy;MO5yid@p*z~B^g}uOfUHC6m z?1CePYRY1bO>?vw203=>UbU-Ndm#y2gYrJkQLLkC`D9Qvt+E!rjZQ?RD=-qe^QkXf zg_P=#rmyzJSC+P^4_Lo+)Ku&;)1{UP$7Zv=$@XY=F>2RqrOINt#GOVO|50}uJCLiJ zDz#`uFUMKb7-y=VjFaARQ|+B9kn2M)F6<{BEnXQ zjx$?G&g}9pSxNS2P|nK6U1xIT9E+%Sn_(j>k~XPQ?ambXOwwsCxpp;uk8FSG9Mc=U z?*=;G(Mq6(Wn{<#KF@e^48ny6uHIF-IC7gX?u4abC?LJFb-;(U#?o zZ*YsIKoTNX*s>=I@X&wCYgRRHbNy*dk?zLIQz7=XM@ypX(uOUSDsx(@;)zSc!Be?yRn3imt&rLNDP8=~N$5(|)IHZ>;gjyT{JTsdJX9 zIM30jpFQ+w)B>6MmtEmjeR}K&SjRv+fb-#DZByB+N+8F6n5liGaCZ7wo;Z*kqX&5#Z_`u9#-6OcT>B?obI;k-MSv`#$#i8hA($-(jD(si~r+tcZ&LW zxAv#D*M7(9k9V8;;_gu8-MMHR#pEt$qHTB{-ruLL_szG5^5X5j9OpQs#s7Sn2cJ$O z+qM^T>}7a;;+xwOf68K^Zf|5X%-39hiJ)}6egbWehbLrt_e4CsL%TOmsO>0gM$_Is zq1*8ZI5=NFA$jDtHI8Fyv&J#ytBo4RyX^cO$z2Ji)L8>L27T;x)^Bcf_llqN*M?vo`%>DMBM|?=@eHUnz3FvM&vV`Meu6itey!J8ALqJ>`qqX0N64$6h=Crq|Y`=U%6}_nM-Af2Y@` zrDLyyI`%rh@jnXVp6MDox%axJU+Xn8Fx7T?Ag@ER%{#SSLiD;K={K~1iZSjw~uLMdL}38 z4X&v%a$DL7qa7<}JK?i-*b>~^iK87t#o>11XYDw>wBtuRoViKu_|Mv5J(b(Rlu2%9 zoAV>pXYHhQe)4Fi?(>sBYbP)BBSmiqnwb3&pS9C^bO+KzkK$FxWhhIsx2hYr8j$<& zu14IO>DNM(af~BDMnnEXapC}G;Q))*1<0a}DE@0y80YRtcg_OiT6*nA!kQg-Zh7PU)R}8RyIzN$ud(JkkG@;Aw{yih z*mosHbn{AG$J2VQa+=W>BR)1zEKE@MZ-$dX?^nZ;6P%XM`H(Ao>@)gUF?_Dm1=tFlmuksN0j97?sPceZjv+j3yxVVn-`Kuzbh@seZf zXI{^#HLui4&)6TgkABS~m$&q+&OMEt4^S3=&k`6Oe&RDdD*$tbW~_=B{(g!Fas%rP z5n?IM<>aY{g8}9n^Iw771fOR(YuYgl2|@URBmR-I^)Q=?B41<%UPU(B5CTpO$~T+! zbTxte3uKK~C5UAGYBs*+tof?$_rfUPPpN!W=6+Qn{zKvx3cR1M29auM+(OB=U#$g^ z#xh?;%^a_y$PF8duWqoy{pto%eY1SE_II0(&}+ULdJDlS<;L4&>thSC`dC%rtEI0o&|H$9lISLQTWxV$BLr-T@Fx9g zstI&FzBkr>Z^Jra&d{vGCWdz5TJlc0LNp>I$v=H}YQD>kczN_TaE^pj`!A~J!Xb_| z#Rn7rLeC%a7mTAGxeDhtkt5!VJ^ZD)aD}7b!-!%8R*ii|OVr44h10|1 zZ}S@6hqyuGJ@EmRhw;xDwdV#4l4o*7r=fF{-|6%`zxVmm4(G3!`BrMdj$HBRc9fry z9pCZQ<&L6-`SCL=e!sfSs}witn`q)k|LLun+jrR8{-a98oiyAE6=aQ`auvv6H`;2oagP|*sTF{b*&KlJ1ukt+stL=3kh zVxZL+`O9hFTgHY!31YOy`X&6q+UrS9WF49*JWs4H0kiaqmZO)kggPsBgV@-!JedyrN&k{z7d7}^C@vS9YB;h_lch~nR&(NmFNfzy-%iVqHt%7 zJ+CF8+Rpt ze=1**W$^Cpe14Km2}Tev?`pE!mljjt@EUz$f@-*XRWbUVR>V;@g*i$**xdF4@z)-U^-?hN(zjGN|80WSqG2D6eNwturX|-yUCq7#~pR*C*skEOO z)T&=vwd|e!I2U5JN^(t?RWAOvp6`3-9Tah!FlE@&NSBwo7ccvwq2f zs67i}wG;EzuUP{ORlsA3eAoa!(EFuGDgs9>s*MV$Xa&G|J2lgFk9^Kc=v;llOWtsz{DY^Z$PVVi zmXT|BwQPQ&C*`|6k&)^~BS^_2RnsYxx3aIxazcnh^(8TIDf!yIqV8})-p@r)B}Jqo)be&(S^Q0^*IKaJ+)L~E z*Qi&*PiePt|1M&Cx0hF4FZOb{YTViC9R`|>pcwVgQO0-4VbNtfe!<}IJ1d+`X{?aM*%g|YT6iGVgA}9Jv!agZ42&x6z86o zG7&$u=A3xdtnx-@MGz0F=o(0^lSc_<>7AFK9^{vV%(2!Xkw;oVm!ZdT;HDOjpsS%>pYkAexBL;xLbyN z)2W1%Oap$3_26`hMOIrtLs!iR;s*%HfeH4(OHBK;EvA6=aA1?<8;KdA74S?B?y5VA z;n6jAL2EYi7qepsTSh}(`0T_E#yz;B><%qEb_5~9ys{kyTq48=uRP)Frj9~HRv(&w ztoIGd0ojc3{igTG9QE6Q(1hp60i7x3j?T1GO<3@l5Mb`b{@3UIKd$GMKGTst>G$>} zUZ6$$A}`p!W$}BXX*f_5WOFE=vc;-PE_$h#dX!v1Q%@}&&R0C0b7-B4_jNbtO(rbhYmV zMnQ%CLx%{Vd!0wzy@rtDb`-nuoEn)LAI*k*I~UfZ!(1Rgv>;UST)0(l2$Hd@=#=o? z#)iDbFmFMcIKH1KN0GE>Xf`ayc#ViS;2w!axUm*+)u4%syc{K;c9@kD!UHwgjcZ2b z&}(Uc5bNhjiT2_$>&*0gmOEs;J)`KjQp7)O6C+L=IfzszZH%%FhTk6UFnZ4n+H2Dc zbnJO8e|4qJiUO))xl=*pzMEK%YM*Qa@M@zhIy?q#oZAm^Fm z8rui<-g?lp+(L1zVYp+q%iF$~?%Ra+*q5bCnDye&(gW9RM_ye#Vx+zGTqT@EOsM&q z6t+Z~j+LRf(ly%cjD|bcTzt_QEWha?3z&n?UNI|M{rr?Z_(lB1FXDF@FFR#6=W-SZ zrxse;GLn?>&8y;Vs4_RL4T2GZo~5@`wx*1dSQ0s8dE*zMf}d~wBH#0SurmFvSqPU| z2>UE-h=2k*U6IXfp!)?4+N7$$=Qmw7u=bXkiw!rLNL87#X^Ut(MQI<3s&}&xx4)YO z&d~n?1%_`*Y_wP4Idk4ECs_`Y8`Fq(F)8yByoruz#pkdwD_WBPJ00N6{|2n0hv9Otrn;n&fNwuPw1xL2>Z{Ae$UmmCMo3ccny;EJQKV$||}cpu{bQ&bzpl`t>H znmky2tG>$S2F%-Tkl9+&r-dwNtSI*(9hjjI%myZowU&D>kMC%tSbEq9fd zcNMkbY%ekFBjbExW=j#G zrqnAx?WIQA2R>SBb~EeXNIV|l=d(P_GUeS4V;SSb>>Z zOVom~)6QY5s@`r%YEjRciLkidKs$lzVJ($163dX{{YE?hsf#yqdI%MTyzH8zpEv&^ z!oi%Z|Cl>nvQ*nZ*(mwP*$b!HE@iq)#wQf6=Et`_z{{^-zA&C*9E+ zaPHGp&pk&F8iUXom)JY1ju`il!Vdp!4r?ib1Q_~v&m^;Cc@CNJz~8b4u_lJyiR&=R z*(miHL66C^KI7~k)vDK$gQTdk4$rIcJ?1Sg{-8^C0QTphQsdJ;TkHdr|2FLd*4Xe+ zsqua8f`3<~@uW9dycj9g9-*Qw`7~Uu{%q94D=uvTDteXQVD1E27?_UvkkQJZYYev+2ZVdEXuWv^yMI z6VH}iWA_cXT}ma9Fi6_h%X8JLC;RY=JzeLXu8$|6{oZLJF}DBgEU|h|OaaQhI!n&y z#cf3O>FlQ5ZXNfEz&G2ElRVXR7c2dp^L>s^H?d-H)|Kv?`H4ik18aEZ``@CGGHIlE z&ppCk{-j3*OA>#hN9;MUPS%WSZvi8&Y{^RDDcW+~?UFHW)~M*9&fk+dD!dLmr$lRp z#CD3taehgisY`yX$FDZ9#g(X=<}C|f9D6C3B-|N}07d*l#&NQwTgtNL&z}7T?Aymk zU5VPjZ#fn5_T#rLRf>N`ymvSici%e*De(RhruvatfT#JIA_S|A92n+cSRn%0#>yDL>4l&`kO2?>g%e(S8+6Zxk*4t zBp@I?LXQ5C{PRWv5+qYNFw02-O2>&R5>Rx7um2B8KsxpRgA!0|`5#F@I{NAP0lq?< z@iAh8eP+<1m@b$?$}{D}0A%b#jqVp*!VCn7g>w9$97Z>sl;aP(l2A?xk*~j^970o3 zFX-kXT^RLP&~kr8St zc>6+fvXM?Qo@;GDNKW~Ji4s@8{^UA2w5US;fxLtx&cxetn0ergnB6K@;UhA4UB&eeek3ZxOpS(J#(=0Y$D{5RBsR zh2R+tbO29Acy+|T`G<5+hz?3rU(!K|`wKcK|C$bbJ<~x*zovuj4ILmx%0UO)jSeFb-$?l{A^Sjx&uzkZ|103kz-{d`--la*`P5C&~vk8}5?s zPTom8z2ORHm{C0Smwpz^dBfH=OeVcs@;{Iqp&k9Py;=C7c<#dR3c3;e0aN`opNHDpz?Z=*ORp2}j)7PaKbY^XtO z{Zv^{#c=L@>2G?Uu?4Q#h8oA`z2A?T&Z?WwdcWIK?{VhxcCJCGnm_d(@oirB9yvhP z-23#6-lK1O^d2pZpY(oUIE>yWv~84g?=@4-*LAZ%)QRVDCjDld$noO-t_HeZYM|>< zJ{!@tts}~mg9WoE^8?_YA?=~iXF`qW( zH}h%2u{(|bjJ{2<5A%s6z0Rj$q>K;d6O`1)dg_=>GW+&L{P*nJHuBtz;02@Bsf#)H zZQzxSS*-QVEK&>p%qvazUp%1(?#Osz@9(kww4nJ=45h@*r)zxXh^eReOv(ZsIjQ`M zw$`Gzua`XP*}zGKF=wPp7DBPJ@bG(N9!7LoktMnAU{ahVFh1i6E}u2mD2#r5{~hM! zxz$E_G1hKhAWx2`zQCW1pW#n_jW>yX>Y1|d%|K|fb~ncr@=LVZg6C=&0f`uNMn~2% zM_IHkd(;(9k>@(B`NgVhdIBSgDkBl%UwwLh&O43v9LFyA1GN~b%V=gq@AwQ{J;&3$ zJ74A3(`w?XGtzbL;;_v^+K1f>R-|2oP`^0dQ~TFE_eNgKEI|rL02c5|7(yNRhEn)2+-Y34>6Ox{B<2vFy zNnJm$MwAn3Xxt+ijRgreZrv`3>iH>y+N}OcsUo<&ij_@SVxc(7m~ssBh(-r~$Dg2k zGatu=W=9=d#T5$k@S?r67;4HoT-WA`K_VF|>^mIxOpf0tTPC-lul=}JR`jfoWF^?} zo^xm5c{#^IiHH`M##zsqGln?io%*dB&rhmS23IuhJID*bVET_O<=oO!)(_9E=5-wR zv9;&-_D*wZaqNq6jbd-d=VjIj3sTmw%nFH<7GMm=Z}3ZEnL9{TzA@h6dZuWyZD0Aql;Rp|Q1wWGYbF$)d^k%-L9IK~r7e zeSW5FN$CORS(A)yQ{4t))VZ~DPi$(4uUSK#xSM7mA$hE0leP{AjnN$@w3<>8M$N%F zR;r4|co@44-jW{EVO>j&aJ-e0g41>PMJiKcUUYomwR7L#XxJvt@mzxrxyR({!qrTU z^%=NA^}lZYme`u?Bz}z%NjRPhu5Ra66D;`r4h>kA927-!H#0g(s%) zxWjC1#q_-G9agznWh)k2+F@ovYb;@Nd2b=_xvB0edK=ue`xU|eS^o@;@Bzh~Ab&%7P=gpXV=qQiZhw2Zz|W)^ok^@k;xq;6cPxNYpmD{tbfTpwwyp;XM# z+{WMsh`hi&$g^$G@#rG%A6Mht!5h}5vKa3VzvBCbXXU8scbv+D*DkW)RiEKAXF1Q) za~|{k&6^lZAfLi@tB=d}ezKRYPQ{BbixI{z4J*K7FAIdPfOgj05i3 z(zPC%t&9YD!qgt^BA=@5;3y9kiy>k1KIgqP#^FeMqE?!-j7cMYSN#-?`h5D(n?+O4 zc0KV|-G#VpGl|a-InTd1LtdkbLx1a`xgrIuI$UDu{-8k6XKTc2OWnWH_YP{mYkkA3 zH*^lt@{(#t1+c3g%unZo?o<+qKZRp8<~7zM=64uh&-;abS{3>ksDM0zD|bN%CGyn2 z)VtR;Ln{fdG*d3Dd!ZIDrbbLbC4Mq$<7>uFrMlX!86Xu zrM8-!ldi`ZDTjX3mlPHH%(+bqEiCp)r2JmDTjfigRvx$1COtSLpYG2s?(Wv2m6-n$ z_V8njcBQVIx~^1CHKu7+&=eC$>Hd3FcyC@@j_#3uInI!*?z)LeRU+tTP8j^aATW zVtW4~dO%{T=Sj(EF(WqsaVOT?0O!<86n*>67`zkL|7VeSG6L=F?!Jn|TjemRzHRpG zY;ixHVRNElcjyOR`z6oq##QwiHHVsm1H~5qrRZLc@l~Pde(o^Z#>@S>W;i2f!{Xt#qC+7O4m%V`k&j>?*P;ih(Q zQ@>-u0@%|NEghfhRcco)RVU%Q$G^f~F~;W-vvj34IsMf$kHUDWv=xlMJZ$Vzmv+HU zpd4qc4$hc%_zCoJ^}vsei$`tIQ5#dL_Zn~Cd#d4Seby|VqZ-BxlEn>q2Jw5UIJVAJ zrBo<9v+y1a9EgP5s~LTVd{b7{6VKKdCX%;SWBK)2>Sn~Soe{%keqzcpZD+)mrT(en zs-;;SGCF0<-L4VU=v__%tY%BNOzRwATshwp-bIh;$LO(Dhl%@EV>U*czmhT3m;=-) zah6VVfOFF&Le?`MW?XYZxjF3{%jmA~mm||`%7Tl(&cx<9n@_P#FZi;JQ(zx4ceHo0 zxH#3(T%YdiJdT)`AaNx$fAD0V7={kiLB>UVA6Ej;xFnjxSl1&0hAj5<-gAr^@S6R! zv*09uAKzo8T8;Ev-UWS^Pt zu9Pj2H=oLrhbQ!Nj56_%!ryIwDMvPzBM&)=c4x4w1xTbybSeCYS) zU}S3`i^?fBo30-kf$nrqx!u!`y@)&Jq`ke_k0G5R3()^eu_e3RSG%We5{(jg|Kg`y zKjLzOSBLEspNLmDYEn2}$Yw;exlm8>lb&l)aTJ)>?JDKKe!axpqS>BCk!QVXmRoQn zEW0E^J>>HSOB1s#>pg1j$tLNdu3Yz^$O^h>xPIAMy8^CSzn^*Wy^VS@-`|Ic>~L#bB+?vf1;aAxV%?5?h@Lt@ z|SkVHZDxP}0-+pTt@NpXmHw zaX8HD^ZzNr2<@P0-5W{oXPU=rLc3yRW-r5xA)IpJ;*&aCfM>MtDm&TQWQJVA2>GxV zb)wW+yZ-!C9MWJa1>{JZUG{nLv%Y(4X6$v7DIUbRN4}GJx8fU`a2k;sE*_dZqkfK0 z*In$=Ue^|mJ;o6e7PYWt_N%Qxb3jfG0mhwGdMRzgfL**P4fR z)kC}LWxIl0o7kpr#H;BTm2e`~t5Y;gZWHmITOrJt*BHZ6)dulBm0+e2XU%n>-*b6I z4YzKx?)%7+r#BYurzec8*yGGj5_xh|iD6HhE6R>`Bm)($*-?AvqZT+ThP`)m78cs! zWP`+t21o~-RhYFrAzmU-v&09c1J?zTd;r0X=LlfIi5}Gjt<-I>^aSArVLy+$5DxbB zQE6bzJx6rle&=@ZzRihcfjx>rYBt1yP%$$dqtp?wQuRT6;At6oQj*_kmkI`FdMKnt zy`+aev1Pxch|=tl@gOx3u!_LB*2SDPu0ZkSylvKeG;f64&+}$4^Cq<}wx86xkh*=( zbG;cm=320pD*4KI|86C+{{g8+v%LhpL-93FFgKonbA`t+(JQCi;h}XF6$99(vR+ z`_XgZhtJiYJtxxk&z@92e)5OC6{+_7&y^qd)coj4!u8+LVT;tL!;jj~d7#29`3W=f z{uW7dmf2;mxa*n89I>e30z#PpXAt9wP1z z&ybt<9@Q~N%+T-@O-m58uiWH`R_f16jq(}uH29tt)JK{Zj7K=m=CD+#VhWKJVkwB? zeMs`0m8jglEoZYl30Fy=HltSIsH!?^;Yxocj)=8kGkRR4$K111^{!{i2@jNmbhA(n zabc<@IpSD3V(>&yVbarH>}z@oEVs1hTAHtHgVYB98dmF7TB_U#6^z-*k94=&w)EN` zeeP=X**{nMs**YIbzQHtRJu|W?*+ZuHOmN8G1Sexs#OAbRn1fQ=PFlAZB4~i0!^4M z4rmE&Q21H!tM|Q*%3q+V#mCBDn6cOVK6aSxEtiG>>}BJI~V4p$zM!i`78){p`ugmwXn@vAiEk4h6kgfccPBPOdvFZeqhZ#yIc7raTO8BO_4gJ##=&*b^QZ@B zT5bXw-!L=aC1xn|+tslDys98+ZWS0Tun%Zx zmyF4mwdA}FdBoFs+XYPw`zw96QLOav$vxI94Gp8ZoLo-#LeP)`r6?dA&j!G-(Or_wH_X*js%yngP4H z=>fVRS-=i(!vo}<@}E>P~x_RN)PfiY76VT-ukHF3FPJVQn`MuCfMgw)B8N_9J8+AYz?FS58sw| zMlV)_d6(Z$zOCghx7-!Y;oUml6_&e__&@J=rRl9c@LPDUMAkgZD<8}@s0I|>wa%|u z^*oX9pV3Aa$-#Grt3a|Je8}#BLi_`T%u%DI;TW?u=e0gxEhm|TssGjPo|RnLYQS|F zPj#GEj|gdhiZOXqBq^2h*COTTf(UNV7MTY!Bu0r#q}2Fs`}w<3=kLm#zK8D4-)lI3 zFBGBApR=6G>ckn(n#p2gpFRxYl!3jN*^G)*`AO^a31y;iR2HTu-6v1tJl~&<^|NQg z)3YDGH$6NXK74O^diKNj)`w^PhwtrA&rVy0N~ouEq=b6iPDBr1(z7*7x|JS1JN9xC zY$LwvPFIs$4X3L?uBOvfCs)hqs*$Thm1IF6AzzX;tf{q+#Q|;>L->P;oW7fHrC%-Bz;<|g+Ey&IR{W|FW7r8 zGCW!RiW+Cyy+(+PIIOm#Ni%nQuYPUkJ-9V{PQtu?id#9^gzHib^T{U6{FSYKKC4-O zUhGe_md}<_PoUOctUjLvw>8IinZ9Q6zoi1P)%es0rLH!L8O`By@KncSP{SdaTymeY zWFMLHEW5M(1?xTglohusbl{cLd0#W3Ki)yPv?tFjqG)|(gNJ9;@-A~&86=WhPb6K= zOIv)j(;_W&JMF-6?u&~Z7(Vr5Ux);*B@@D}+1gH!dpWZVz3`bl_t~;#>NNgsYJKXM z?JPD#&aqfCz@@u_St6W#iI(MZi4Qib9hYZQR^2VD z{@F^GVjlb~lzllWJU?E`3qn2Tp=YhvJk~2i-n9hrBss^`XXF! zJM?wjrMNP>;=if@LyVK76(s2f>Q)T)=XIa+7tY-zB z6b)A-%8D31DQJ`x^+dm66rbO=OjVFXbD1^M{ncYMP|#-Pk-Fs@9Vdpr^RkBwb-%ELWY&{si9%Zt)PwDm|TY)qd@P zTy&FN?imktNuE5w7$W#{CoJePXoF+{ZNAnDc9&W7O|C8pnD2 zBO8GIAj;f+9btaHC!FpHkN2e0J!y$lzxo|fUqI_1o#t%mYj_IeX;VZEIPL+|_}t>p zD?zed`He04us`G5u*^3qw88zbw#uchjr&$zo0Da}8>yMb8Q(AMko~}e_TA-=?U3E1 zlO3{)hC@7wPS{J_D@v2>d*I6;osQH6- zN(4@Aevbc_#4`U>t0;x5jhb!fn8nOdZ(KF`2^I3jvAkqMnfJLcc~+S>3wC7oq-~HL zKXLUT^wlF(Aw1mLKkG3O4I}C#;~r%jknupV(|p~H%vry0BvU!oD))%h(O}(^7BAyR zBclqx;qZXG9-CgO_TeZI)lza@Nsi_0P2L5BBKcz11aSYF6 zIc8w%U(djsy+pD5epmK9H=903H~=-Uf4$lx5>kl-q@cBr1axN~&ai7(NDKD<4feaRq zt3lhv9d97CNL?BtAF>^owZUUNo8(UkP79)&TtP)}ndcV$S272qyLu zHl-4jNRv+aMI+;UrL*LY8Nw%uyW)DmwSL9*3TBJAfzfuHCV{(SG`~{~L$e8Z0 z*B9Hx6~LbA0}Ixw#=X~e_TK6N(b@dYoe$<9UvqQ~?Z_vxT2`nQ3QS=8W54BdeZg`i}n=>>d9N zu5Ax9jduaNKl!pbT205TC>wuOSMgUXlg|{ybBO$}Imv4tref z#~nu=ynHjKZ|?Lh+-578`&@~Ci!u+Gnx)j zK0uN}d3+}m87V$kKKHRIXdaa`v3dY&NVEgb=!uT2t1gu*5u=$kNB=@|OoSVK({?#C zNO+g<7}V@WWb+x@6yK6gn8HLC!8@MQTcuvdu>_9e37A%POuDC>E77FY1}w5v|4S(WCzebSwh9h#|RlRA6u*F@rZ70tx!&$}wr4&!r2ZWzS|Q$$IKeWK10KfzzD)+0MC z#8jwPID0V)K8IH^m?mDBqyC^>NkfkD7Z`3zvI@&5Ut(c~Bd$N)w z^nDnnQKECKI|2W$^ex%tx9HRm1ED#;iax~|IwD)SSA1#-Hnrj!A|do9oW?WaFlW~J z;Vtr1i({FM<{51@aTciLcJpsr8>@ipfLadiQTT-`QNW0(o~O7FUK<)MR=DAo zlxUrHSO^kY0-{)OF{VqrFFdxqR4+rGd_><6-8jX1SLGZN_D4{klcfreLSHhPaX0n< z7&{08jC>wKi<3Wl@;|9L&q=V%xGzlSSOr0>25U@XNUq zt;xC&idnREw`l9B9QKNoKZuXKaXw3@Rxs+Mqouy7|Ed_!xlHXoHuqhoYX;vEzmIMST z5mfFNwb8M_Uh0AtKj$lt_{WpJH{{?PRRAVqi`mT%ngD1+-?4@-axm6lsi3?dug$r( zT$&BFMOA|p0<>MtNtiS9`e$I z1XzsaHtqDQ3Z*@?dXdxYT~13U4P*M0=yQK9hr+@vk}(pIX4xvyDdk62GHU$J{kEgqteo;u(i%v5AccXl%aH_G1S+kPN`&- zJIa1_OMNYhZ^U>jZmG7>5q6gFSjvO@E+S;B#Vzl0e+ zdU5233>hjQz8>~?bCE5~u0?fZtVx#d>~B^_RT^psPbRAQK>mR(Y{y9}83lyN;-y#I zyVxk|>zJKeZ&DX~_vksDv^0C?-q6X+a})g1w-Li+koS|kHQT~^X&48?E2@vD^!nUs zF7Vuw`<2{J*$;Cb&?Ay0ZZ4EQa_!xegA?%BTz=(^6p3T{lx#n|h9GC!2>ctS&!HbO zTJ#wbd{7V0Ahbme9T+7j&^DO*@O|Q3A}3#d%fQc-YrxInXW;SJG6wEi{1g$$ONS2E z8a~B7GsecmwvKEPT7eq#Y6BYfj{AOH_d3h%Sz5@Xo!;@e^MSulsQkQ3@rli@XbsZ} zP`7@u87x&uLoFks8a}iBKdL0*m9CFS>oup6#zB$c0Z!Sc3QH2fG+{>`}0|OAJO}> z@}<`I6h9B|t%yHWbT}+!67hw$-g2eB5g|!hiKUvAa#~rcMz`z5LQ2s&bhSNVXf10r za*T0zX~z|L7Q1EF{bG&1YH`lbXxV)e`)@dGaEM@!^3TIHGp|{eNduilAZLVg4M+Ti zDj!O%T0-9H;WU4=dx=Lxsv17z6q(VEXX|A@a}17Ovw(wYYOMzg^U2(z(6=-qv1e3` zjU>g`iJ6<`=ua4rN7kraB4gGp(1Rj-D-SY`9+8t+|5WOfqJGo+eqOa}Yx~JRIPAT` zL-ebx>I09%kqjcO?I4G`*ELmXoU11WHHkxB*i*nfkL(6oF{Um)?02eoB6VKz9vbIv zmX$_o*@52OIisUK-EsVP%#0^*ufF zx4nMK-}d&*-}W93+`1co+p9!IldMFuv|s#RPjT%lhJ%y%`w=faEclUfLoapQ&iQUk zM<{uEyg!m(@ArPJ5$`kVb)a(eMMvpcXWu~970OYbo3l@e4 zMZ2OHHLG1K~zjViVlXt_aWwyi?n?|N>&`__{c+^a}-B2W0?pm<{( zZtox(qAK3EvVrX9G>DhLc3s;l#!F!J(uy%Go6QZ#%2(4Y?V`f*n=~Gad1O0hjZn2| zjgCsDYv2=QcZ_QR4Q0Z$;3!@#GwzNV&y)i=F)Tb{Sm3X1Nc7A8R<1X}8n~`JtPRQT ziZF`|4w})paB|^F#5`!5ACUg2UN}p1yJEXMJXqKsmDF-4*JWAb34!WOIYslixJQuH zVgF@k%&uc4aNX=+3f=BgYS!w$?FEC-ZFA`1wx(5|yG=ENWWCSWvD5pp)MpY4|2R{M zW{peX8pbEe(D7|={qPOpF~n76l(m>Io~51#wn%ZTRN(;n9_`keR0T#$C}n=%Q4ntV z;?Ecg?g3qrFkM#)P}cD%5eqL^Ak37pg6z_c8c$nSb4|6|@#~0oxYi-Yox$;3{C3HX zmz;@gWDisBB}yja41npF=gOiNX}0km7%yyle4tW$rP6_{^#y(w^PQ8W|7i7S?G?@p zqloUr)kj>CGKl^l9FgwjIRxRq5rpK!3^NZP9&b%yI|l5Z!ghN`%g8ySnZW;S4X}U0 zH!bK@bj~C>XRHM+{Fnc`^8lJ(MR77f=7*B;(>I_o-R&AAo%G{MN_Yw@1*aaI8_i&1 z%FinyUiJvKOZdl(cm%(5&G*Z^{QkT`Un$6$cn-#dsJ5C<27H_Cw8B_9CE^w2FZ8!z zHQB){emCML?($~0K6*fw{fa26XB<8yxiYVOC-THg?5Dt3c*Maiw@ufm4i3pja$RBM z$4$1xGbuAlx7=sozBk@cx{GvMl4wLOqO0tk1s>};1EePUmpnEKF~tUkfMoo#RBbtK zS7I;Lk&s5cXCw8@aquXUS(N#K8r;Nj);xzRPd!jt;1tOBla08ddJQ1{DV6*Uh3h|% z?EX+jo4maw#+)xyxfpn9KXfuaRY?lde5%0v+F<6L5dODb_Z?0kVCCRqpFFkrsXU}+st~FT3_#HDJ-L$rGGQ4>*-tP z>6`s>`rcyj<37&gKc4sHoK6kT>0*K#{zIRzUJ>X+Y40%8RH+80I@HZ$N#JNP3dw>T zT#M=^Y$$(%hLb?T$4J1f?FB{$Gzzz(EdnGvOD6OJ?2+=T;5UW!B#^VRZeSC7#M%F| z@OFE~B5*@TqWoOq?eJz?JJJa(tusYVjsLplTqM64k_X>7!~ zEt=wo1kQD3Z`l*ncHGm}fm!A1fpB3nJ8hk-4G2sXx1&!Zy9}!wjVZR3vUe=WonY3s z05sYuYNj9`ce;v{uNv0%$}H7`hO)zi$3xz`OZ8LU{YZ{qWi~p!g2b}GA;I%9+O#Ys zf^HjZq*`r-;!8j_H5By%v{gJ%&Bj-^##eKI!$;*tS9K_SwKQ8dT`OOu+97r~djsW) zpU3(K^Zl0ZGJIZLPhP(M<;kn|&K8VF{DM6WqDQJ`o=z`}#EBMnF1TT8bGvkJYF!fPw*b{At2aD}T zd5-c2Mh%CE`SC%r#%K=z&xo!&tZvNZLz0{$nlFx`zfg)v^&?7=`^<;;IlS+cWJ&jk zB)3?&Qk5AdN$&O2`GoGJG-6+31l(0lr4v%-pK$qx#CNiY(OVB`k0O0Y)(a%-*`sC$ z*~`WrnYCM!)B(g6xD`P*^kmI8+5TRiI%DzS8&)(vu8ewFaoAXE)g!VDQa_{Rlb?1F ze%}epedp(;UZr}8oG0Ap-)T84+2O3Bo&Ske?|E_1){zxQ`6IfGI)J~^=gW2`0FfJX)d+Uc{Odd}(XM}F1| zd(#rh4yvCYR8b`L8_@R7x6bVh4R(;G=Gxp5aumb6)=#mqIV;r^CG6? zd)##1w@@{PyY&tm*QAmos*PRs8g(upKRilyARcNHLjuh?qz&zjrGr|PcaRGd#wa+D z%k36=>K&FTwE#^;kk>cg!a)5V)*?ijP-sEf5ss;2NTg~z{I+BCB&cNuI3kcu24x@v zJA$r(o@Pr9!So%p6=QM@&@awa7d$D#v#gpcnyxaX&JP|5?6qRdwQ;(cvY9D|`6-88 zo;_Rkoyde})&GO>$VpnULqen(11`P8Kw!;*GZ{rOrq~K* zPn8U6HedH551L(dt9Qp&Z5vk&uo_RYBTSbXS5ptg$W=td!K)YoP&RvNfoATE6EnR+DqrFj(pp2LgUp`)ws&ovUC;qE?>nWmby}ZVX)GNQI(yq!rgpz zi(A3x#U=s+QRSk_7Q#CutefUFlgYKxlR6{@O7Qh^Plr zIM0JMZCpjl%Ve$8rdE;7b;Al{+%tnYcXSo@ZOn=17h^?OVh5tzTif}nmwPwY612@D z#=3%hRZwF|lJ8mOtioQfo5=T6)rGF+lH9gYe^o&*6kY8xcgzF8tGUS7ngJFA8-cFI zO=c3c)adliSN*sbCJiKInn~rYysb4?dTumgATxOzv(Fx){;$VI({bHQ}^^9JiFf>OpaFoSE zT_PC}t5J=3NL)>p_d22e7_)h)w=}A`7)KS4K_c@eH#DvM*5<_$2+8Ne=ENujWF2^c zlmHU=HZl)Dpr}XY0mv=(l6k=`=gm>gFl_2zZ)|v5~e()Pic^OZwh;|RyrD$e~pss~& zcd>U+KF9v%f{d9B@LYKBW(}OpdM_??1%kJMeV23uu{;IX2`F;H zTXvK%k)y#3!~H-Q>W{n%z34hK{eP+|_pBceD)v}gaiL<($eolPw^Ff3{bHeF zAHqt-nd+%0|CWxGVqg9vbrR+R#$dTKonkay$jDcXZc(?*Z{24QZT6ypk}^;Tdr8v$dm>GQpa4*>U)Lp>@m3>bn@KmL~rGKz$kSo_^s|u z^^SQVPH(n1P&R?gL9wmyhPpeL5Y<3ewKl5MZNZ4z-DMX+=>^KG<1C}qjV^*jz9-5$ zc|9iRNu{2+^U3?5RNL#`!mg1O=FZ>f~m04I+!t;Maz)~jn3H0xGk zL@>98;AUN=qB*V!AoWL|_YK4?B>O-EvBY_osBEx+ZtdNO`phu`cPq zGiStAj85qv@kGNsku#%J+O~x!>Yf*#h*Sw1;l_jDoau0e)T(>YxKDlV73kH1bhJ0* zJV>P&&gemF*;IE9v=fk&s_lr0faz*@%+Y?n@ty4Ubg?x9_W<=h!hZNY_6n_(=r~pl zyFQMJvY7^2f?(D_ZwgocS=LCKq6X!s>e#B9^QQKi;@?Oyh|B^FH)sE*y^r`)-rAyj zOQeugkwFY)d$e)&L*vsRN=yy>sH!`3Y*6HP5T0TAy@l=3EwFlru`KYa0$h4SYf!Ak zb=a8}7)-_ZZ3pXBL5M*vMY))gTTds@L{1=-P>fk6nxQ%#6Q5(1VlN!-l@(&}=z>@& zhwb65w{6T}2{31t@IMsAr5iXpPP$Kt>cl$>aF~^MB68QtI~8j_pYu+RW=M?eaMptC zr&XHTxV}N_E>Y#VSM< z;Yg_!7NBe)Q`FXlPoiCZb3OO%ulS9%W(UzS|2@BXY3oCfh}G7&?d`VT9=+gc;YEM% zxzQd@{^vYGrM-A%dg=plrB`)f_XZ2 z=iH-x)b62gjiSG~$IQ3kn$!6qG8=OR8m=FxfUrty2*5uj%afe!;~S zDVg0xvmYKAHPs8N+xCcC#D!1T0$aKM9?sW&Z^7)|QIr14JBs^Cvd7~-yqSN)J!KAX z_tijhfu%UgF=o&Ce{p_SR~^*6kZgif+L0KlzEQ0PqdCv~CpqM2yte~KWMBeXKgM=O zyIOL#`d&!l(IeY^SbHCMzvIkauGBf>u=HIb8u-j?4bHPx_&tg;NrmHUjd;#6&eK}= zRJWQ@P{pESNA@vR2z|VlVxm||Em8wS@?QLmJaSxbh|q$l9j=BnDvwfjE@!OmIk45q zPCtt`obxzhPH{d^9jEv?K`z5koXO?)Z9{|$WzSk@XZ)fU<8YkoO?lar56bzgnX^M5 z)*>Q6*?D%a7V$(q1*QseSZ14dlWbGY_uh_gX};^2$?<8!jO$UV23zRg_G}B*8yI=X;n8RNEWN;*HPaXzM(%Ydc!uP)F ziWofgO+Oi;#Myu2Ejz4c8YH(*tY&D_9e5Ro=YX-QS@VKz+MYG9=rH{Bm-erVRV%5g zW7{G|%78+Y3Us&a0sf|BLF5DpHl}WjGMLlfTaGy*ejf-u%G=amS+zc~zTm)4kq&Zl z{;eJO!o`uVX*3e}iSB9CsK`T@l#3OP>_88(9OkVRMVp@1$PD2VW{(_a@}5r^w|8hB zP7nt?V(+lOn$0aD(tidSw7`YEchD1(i#eq6 zcc2%R%26u)bvr<|AgIPvJ1%nX)__t5j1wp}stsYn5vQ*qG-l0vbkV!M0duY1Aqadi zJ{`Qu+HcI(5?KIeYyDnifmCC0IVr3yTf1u(OGkjr?F*21f*J1#l#9AM;NTiYjh-n3 zXExAHwlF)eBfdqO*VE3~?XX3R9WgY%@9&Ctquuwvp_pIpOSiexS>iUrD*E~?5$gs^ zc3gW1W0G-K2USL;UsUuKYl4^9pp%zd`-WDLn`FpR@_aMeFVu<(2V&UnqoZ5_czeXR z0A>3hod;HY#AFFTt&96iQR5cp0`zrF75}vErrI47bI_~mTQC{Kx3IScTA}G-?*{gg z&Kp`I4QE^aWvm2^ma8vmgn1APBnCxR)9*w1mFrOn1*RGq9naWuN{2Tt#w$J0Alz$(a_;%mCwg2C;ZRqL;**3@1Zr0*- zN4~V2M)O5FR z$?8F5_1H0v=Z-aWm)zZtICT4ju67sA%!9t2E)-xv?^V z)Iq_dbzacNwPQSQ9@n;15PK6VmY!n8c#Y{T^}y>QU3rIjbLjtqE?sFF+I=A>rPx0Ol7Ce$c{CgiYY{GupeVO*C>^|IA$*wjHlw=)N zdB;qqDRYS+=r!7!Kue`KP4ejD+2{VwhkKUBM~x8R70A`FuHQFmguqtU zuWE##U+=j_2+V5!q(%t#iF#E{9W_EIg7j^L5R}@alGwF2h<&IH;<&HHa*P3^L)|Na z=$g4U4ANXZDuRq!AkgM^tp%d1#O{8Gwg>B5b4wt<{GD%;$1gejhBK{?yiKVV%eC!J z*G|=w9oO2>O-qfrh4*V(dmX)1n8k#dIdlze4t;pP@Co>)j)-gB>a3Kkv8I~HScznl z><@2_|d<~5=Rh=iZ1=x8!plrOH~--96qvu z_Zm(X@Lv0oRr#0J@4vBq`?lrYRe_zm?P!lf-la=S)>Tm49GrN@x#D{&#dUAv)@&-h zbhoK!OZm$7{l^6{zt zzw1Z4+9!DtdguJ#BQL_B0pY*Qi|~5?hAq+l%$8_qWF$fT6F=W=TtBpTu6VP3%E*L7 zw8UVdr!Iox);9I4N}_0e7&b)^*V5qbhkxUG&QR4C@gXX`#;w1>$>mj@Ue?d<&6GRF zwcJkDU6AqflTKh4%LXHaQw@gf&vxAdx1Q(rVGXp5NlU)_8}v@zQAQW4&3Lh)pxp8W zN{s=b;NPIs7`?fr0u%aj7Msez4pr(C+?~ZPFsmed7rW=F4Mp+{NYxVSOEKaigX0Qn z!hbNvjUGQ|lbWjxjcXBis+WmRizFo)pheFT)dO{-ss!6D2J+O34ZGBB$BaUgU4F3B z2i!?v)T?-^F0sbH3;Oe=GS;y!sBK_oUM4JY!mfAP>Bt_PahJ6N#TgD}toM>Fg<^Wy8p^^2#0u|v)fnoE6{%1)*%QUQ2WNFXA_cJmsl>{X{R^~^fpHCbtJksF z1?79768+wnd_@&t-^SnZ=n(^XUO9vvU1Krs_CI4O?p%E}1K0jP#ZoTo6+tm*O{Kj; zKbt~zB~^?!gk1u1QZ*rhVq4S}eNqS+5jqUvRK|H*FnXm=8SZUWc1ATU}BzP|B?Ybg=7>fi#Ynupz4K}q3;g1ll(cb?DR%S+ci(XLq z{=#m}qqV*J(zn0D?^Yv9!@x#cqcooLD8}AmuOE9EOiUL<$Z3HaQlm(T=p{I+Pu--% zB|82&M-<=H@>(ZrVzv%lB$>>Zt;tT*)_^ho@Ph+dsc`sj`p22w=d6sWqk8MLSXj^x zNwc|2l)qUJTM5|;duhv%s}Ma3gmK3*vREWfcqCjC7Vj$CvlRvO;aa?l2KGydshSF^ z1I$R#ruP86Qz0xxPra$Ib=wRUxAMSzFs2ob=t>zLCLuD)Ghzw;3Ws$Vx$>wzFb6sC zDn?ey3Fjlsx~=b474zDEv8u)H-65{;f3&KyVy|*lFyaF?O0L_l>=Ru7OouxzuzXrD z1Hu_I;LkWM(H(|G39kjIt{P>wzv8vn&%em19l5mF+aBl15Iabod-^k9($4-Es@=ym z9k3=F?C%w~4*ds++Q6vHPtrP4HzPaPL%({clK?V;EBo)_EAMp@*zZeoRY3oLQ72(* z1?Cq0vp`?YRlV=Nm96X>%)ARYt8o1H9TDZX(n0LDm~^UZj1lCv__|KQ|2i7352^k? zG~7?oaB)|>M#RPHRRa+hq}^@XO6BVVVHQp=&bX zaK38d9qrfHDr1Aa96|GCJ;P26;0(%A%86}>ZL|yhwJCBR@D#Y=1p_?^maKQ6&^Jb- zHHfapSHq@KEZj5g$GxSO9W9#ZXWWW^zyRI`{x0HKA#x92wK59e7`ipZNV}WbACQ5| zSRpv_d&AR=FpJZ;nnBfUigA5okog5VETBX3+oIhcP=v!+3oJ$oYru6s_Gku*aH+oT za&@fGiY=^q6O3gz`?GD0QAYX}@7Ths2bnW0?5==g@YN_(vXzZW)1L3$HiR=OjLO>w zel&E-b;YxTg%AY;82NANj85FVjG_TGq_lI-P`{I_9vBa=JV?m-0dY8GX#wb>k;8#; zh=m?@2bzpGov#|IjJN~8Ld-cvwl)2N3>-B@3f8Mfh_3$=qz&~LO|>FzL>+HP8Pv7dml;o^n9S_IX>wHN{60Vy!yEf%!WmH zs5fo+*@nlo4+rN1$Z-WkZV;(^MyTxFVKsytdkYJ1m`yBwznui9y3-$9%@2nNf`ur?;^>sKsQWKS2j` z0~eKYn_>0Ozbdw$&3z4bq|+T%xb=lIptJXKA6xal;5p{<)X17+50d`{_ag=fO#85g zfkYx0=Mwj)M|H0Uehqu>pu2%wzPlHBG3dNM@pq|5++N?G!+NI3{o(%%J`iKj*E;9Q z{vIW0%q~Yb@*AX1?1~SB6$_AG+3}t0QJ*TUiKOQqB|X72iLTJU8hM~@r|24u8{$Px z2C5mxwaB?5+WN-y;*Ap*7tb8nw@2ZRD_sAe8v(!IL~+-Iff~qt39kyosh~?rMghS3F zyRaG9U&*F{2a07xIRafUyEwOGph=~`-y|nZr^u~##^oAWa2&CQ8C94U5+|}0W|hQL z5KWZo2P?#S%9$!H(3L>wRvD%0#y*2RQ)UzAi67hs5oI;+!>ccu{jO+AB!2|u<=R@? zq~c=OD-rP*r#U(v`P7X!>3fD-rWmrN9^y-GCH@fdf*@y0mSf4d<}Le0hR1pGsevBV z5I-mFi0mshHZ|gtyws`@@gDzWwC04lvm?&YhAtx<*JvgOkHfxEmVqjzQ;*9!W8`}` zoCAt037S!QH)?FB@%*NBet|dVQ8koNY?Rb{7Vpre*mh9%IDD6smIaZsQ9@dAdM|O**Ro{No|I@iyYk1L5T)Ud%(#OK<2@674089mi zW%LW~Jnef`h$i_nSI@Xti{`OEU8mWt6Jzi8tD6{k@AqmTj>WB{1+}jbuj9{kV(P`X zfAfF%jxN5^r)){$TF5v3`#a2m-skVXI>B>i#Gx>%^)gD#kV&w(j^>P|rTSCdBxf5w z=~og7M^KP7vQ@W8BZB!k_7KV;r`oMgw4{4Chz zAob~IN$g1u6R8VDnpMtn>$sT5Un8F7bk%EJ=TD^!;d+RAYfuJCRptjIE#!6M3>+uA zs^>Va@pou1~%P8gD(jE z351nxZ^^=hY`&G|Lf>Pt71c+~-=a5e1C2iU*Ku|$3ZYmTET50?PB?Fz!g$t>`L6a{ z-RziuT!8|dNA2dEY4O(>%y3oyv8C~RMb~q<7QzG znrHx@yk}{-u|IW4c_c%q5v$6mnv61c=b41|Kyn^xt66NMlqF$4mAxP9qS;?a-#3j9 zJzHwkPnMbeE4}2WD1e`>mQaLV*9~)am?GZKQ+UTeUghD3Vh+?L;=Ow6D`wGG*pkXz z=oK;vTNPjpYB?j5*idFoyZ5yrfVQNKUSG9=zwRWhnt{R*X`bxD%OcGew1@sr#9Ac) zABr;qt~@YJu<8vgEZ%8*;EY&LQDgy8t4XR=DlY9N*{?SQSi55u?ja#RczMLXlE~t1 zNY?=UF(k$o4dS^m9Ib^#rAEXQ`5mHW8`8^}V;mMLLqpFedLum9csC%A1ZQ4q zH!KCe7j9!~gd#&H9|*zmV^jq`A^q^R&tygP` zLWW(?2}ud)obsJfnhB@zhGo3wKGwvPp|OCINk!1;&C-iG!7l?p^0ft^*}Uhp*TZ~kPdIO zi~sjj4NmJuGquq>+~rBCR~4_gB?D=OPYJy}+#!2G_9CyX?t~>2p5C#&!bahDx#L~0 z@4URzAz?+(YizkXur1L-(&PB6+N#@&r7HmGwTrVZ-bj9iW1qxu>h zX4X{6tU(<-Op)a>)#r?=*Hp(S9Z`KFEBb4MV$Lz5d9B~-y zYuaQqAW7$(<7rGKmD?yBM*L*LUeyNMN+flr9`|TL)Q0^EGTOdvyR%_4xi>g0Tiku_ zn`tR#SDmeSuOR*uT@A3@WaecH$7)?m1WbzU7TLt+N#8{Eb-? zi=tugzF2k9Lv1J<>iAXLOtKYnn|T6&x}9NzX5yGT>zwVd-C%*q({J1I+pvCkwo)F} zN_ryh?8C=OnnxWvH!C37S^tP5{Sm_lXP7cV&N3Kb@6bL*y--`N`Mg2P1Y04D8eV^r zq1%E<<4C&(3gNslwAaymhd)?XSxqdqhIL4Za+-X`H73;Y%;-53$2U&+1?R_djZUY z8neX}7SD5LI1@OZ<}AILGjEw@*y80meg`eET+M><*T|Aya9&9|B$FTYkt`03TFUiz zP?{=vAZf}7G3&wKMmXru*ZvX(iX{I>6ex~^-9DoY9%)I^FFW)>L4t}44S1%3z_>DF zmG=);`P1=I#Mq1R2Gd@QS5@`R@dl&5HQpfc4>;cT^>|r}z+8#wtFHbxzVeX`P5wbY z{DXHt;S23vqak&*Oo1vL4;}6Q9t8N$eUYEniT}8@@Rg0=wcWw%iJ+l%EP*{JVX5Uy zD5#kA2G^4sXa}4JH*(?_ox?2|a^dt#T7D_Z=em6E$7i;EFW=1Rn>&3Ar*G->ZN6*4 zdB}pyxp?cjzm~AJ3ZwT?6oI8o8FN_e(x~|Z!mP*^=<5tHBMIdNu{4U*%@Pms8q~>I zz8NC zN>$!b9nSIFCcjzyZ)DXIQokAYM{LD_n_?RL4Did9sctCmIi5@8kMncbUA4>DZ{pd)(uqU*L} zm9ptGnSKkBO2neiaZ|*nhnHgFPQS9^8`W8FsGYLtAN&>Nj`oZkk)CR*6UtWojon^T zR97G=$9lngx6@|d70U#U?E3j+*Y|Qy!wirr5iM`+`r%`{zMgh{zu5KlwCnR#yVQ^& zJ_rtP&wEu|} z|Lc1O(t5Zet*?9`o%zB8^+%?D#rqmFmE)srJE31tu+S&h&K{C&@Z-5)8im^A%-8pJD@3`{7!yZ**jrzn6Jz`%R7Pb{Qxasrgg@oC5T;dUi{4>LV(SmaR9R!XRrvqEKngO0^C5SnxOU1&I5HDf z3&1C~Xq$VP*&|)hn>Q)su<7c{&8!uPbc6&r{zOD{nFcVm^(~jx@BPVRo{cmdoJkkA2 zzBy?Lb4h*_(|XFaGcKfauAOm3|EIZj+m=6%G@g;t{}E3A=h3e;cV6wwZ0gsT161v7 z&6CxLHn{A~C%gedq9ln1O-_Wjg3lEIR6wi0B~}TG)d`UzJ;GcRkeM|!9)J(IVnA^0 z7KEw{6HyWLWK+3k;N;sDOSPf2oORCzP8R50c1JWfBB77jAs>@riD^`~O6qMaw;_!> zjB^%q(q_Cp<7x)G9i!Pco>5>(FLK!*D>mvs7&Yu;P-H}B!oC0-qNrGxhJR#eQBt`w zNp9DeCoS9>rQYzerdtrpi06uE9ELhKAr}a*Euj!MOzWl{@kNL_wHtwbq}b*`ev1loZ&=P z*|;gnjiJxE3?vz>bDg=~cbhW$;}NbWo9Ko;9-FE%2np~ehE*fZh>&bgmZZFfG#2xOu|* z&vYCkb%lAYt-?B6cWRXD4>{3Fa-!u9@_O;rYgY8Q14Xk_^vR#0B3t*DsK|q|mDn1t zG|Z^Q6gR;BaKQvi6EPIzu6*o}Q#<9{4%bFDQb&iZ*_<0rREg0fV?Oj>vYOzHyP_J_T|_AETVDh z>?sNvI_5_{ds%vKawh}QD-R3C;V>U0YBq%Jg>egO8z5`GYs0GJ`J`kw6hl$wBi9d4 z286&IztY)X(1G;jj&bKbx@6l2%C?V^1D`2UfMZ>jy{g@)qil_h2M!+UHnI~yC>Z^s zNTydkq7oKIRF^5GA6fPi8^y6k;euo$+4hoAuh=tn^pWNcG0@{t->^s2)f^GyXiz*f6T*tY2h1 zATkGn@IBPx_7{%k1iNF}p{L&<55(;t8R__W#A77IsO0m6+`6Lr&hTkB_p0z=;OA

mQF!vBwT>cnw0Y$cVb8uDoqjg5#W#&DCfoj6Ql4s+09HjHIW5~<@X z`hg?i_3-SDsw{jhjceyqNi9(|s>nU#dv!Brg}9gOJmOvWH;7*!;{lP20jI}(RZ%X? zF@-Y~!A%1L4b$Aertu)OSt~_F9Xl>#jRK5P->y$e21S{ECd~N5TGCGVBhrCiMB}d5Kon~al0O^{z~cJ0iNrflF>)&02hxIk zM%+Nv(=$2?n)akhfJCyGRulV5O)EAJdm`>RpFmTHh=!}+%>FqdS`_?|xnhhhw0u8S zaKv=s3bt+TuTNL7KCj^2npb!Q1*eh_ZgAe3T|H)RR>j}eBMJ{-ONAzc`!Xp+Vbx-a zZ-mcT9jlWhYL4{`l=)y@@H|tlk~f*8oGYpdEaGlVb$-#O5=(ZBxUt~6Kud^iOq!%+ zpZybMJjjt8VX38-2E~QqEJzL;X|a1_Y+U)a9kh?KRm|cIKih#=z6>A>qHZ{>32GOM zNgSD4=&|HDwP}xA&hXn^dRkmal1bq!`^kJ#a_TYG@Y1H6QL8wF7CZF7$4lR107a4uHdJr^A6u_ z?8)q_SK5(S z33@U|-R$eVWjUXpvnH?|TK^uGO73?}Va8YxlEv{P_aQQxqDGWReBL(1{Yln#x@Mm- zaI92z3j5?mgo8dsIDoXt{#Sh<>sZWjlB(`j zl`63Wml4DMowgR_!8~d{PbWrtV?<5hvioT^%4s&}J*{z8rg)bH1tM{~jWJo#ex8%` z*eyNQjCoEiX$nyJqQ@Z3T9j(Jb;lSIv$uOX^){}(&2i3IT6^Hj(E}IW^?+kw(f*u0 zNs3%Cp|M0bd!cPU^}?Ufg;=um*cZ~7F$-sBsS_o_0}BbHPwzz{J-3K;QQ1UA;Oj)49t#m;ISmsWFCA6P!W(<;R==&)#~-$&O?3SbO(h zSlDn0odd^-4d)$9VKL!v`oY$ywI7&8&Xzl4UZbu)VtrA>DR3U#UAgU2cRt##8dB_E z)MbhwGUTn~`bTx1$RdiKJs`rv&PlQGWalKrHnDSRJ>#$t#GOWmktGK7lfUVWSb^i& z;%e>|SB?o!yX9VBRfa~8hS*Wz;AkuI62}#;7y;jKK=fy??K{{_9yS;(Wc*@TQqO%h_Bju z)4wY>V*LN1t7>)Gy-Rzs3cnQ_>u# zBzpW&$Z4DURSm&xxrz;G&wdx1z#7j8vV+v?`ssU6;?jf*W__Os^sF7;BahND$`i)> z2lsw@A5h^YD9*6b9LrACfG2`^;(TDlRGe6{tlRp1SjEYI1XnU@&|IZMQx>Ub4Ck!n z3Gszs6$6e1#y`VfgGhfA*N;b~Iqb(EJ^IJo9=rHyN$X66Y?i6c$?@BnM&Ioq+$mV4 zd!ViGEJg&W(VQ~|bGYu$zsKhuUI4W5 z^KN_TnuVXWfp!g=QOWE}`aGkedHSs1Wr+=b@-(BFEGWn&h_)TZ zLQzCK*6G43IC|J}UeNX*_YqGfy*>97-(=ssDXU}O;;v3yQ&@7Txn&#?#q?Y9m!j2` z(0kCBJnPTWf1@>&b}?Qo(}_mD%hWiYf8b>k_feXCGLG)3*e_7i6X@#r$%V(9Huz=B z6crvgj+fC2lAksajI0?_G_FvXwUSp1rX+b9l&irQKkP$@`jEk&-oB^H+X=S;hKqb9 zYmD~Gst=nUV=ZiAi|C@o&z$ZHGSsmDSG&CC^|x|kQ^Z++1O5~#0ixo%zFY#*anJ` zE$o?{kqmirOdV)R;Jt)b3rD>zZMfr_%lL5Cay7$3M{6>AYm?o~RqEnl8JAMlq zkT56s19{1kykwUi!l*J~R0bMhqDT%-@OD>tdt|afp zQ{{5KtR_`s;Cvt2kNkA*X_-6N6Mp3#gw=0LMLT+3I0js6@xWHWGjt*{UHX+2XL7lv zcJz@0$J*MhXO$Rk>%B#D;d$nfF1D192&?1n)emrgrr5Do z=V#n}CMd~5-o9foJLNG-7W2XJ%Dh(QwK}iWd9BN}zp>)=(e6Fk5JB&7+VjWv-l~v2JjX$dDE^SChmw*Ie7V5&A=TWoL1Az#AYO*pWfh~u3GD*x6BS2bz#=E-j3D3F4l#L!a?sw`l&vd14UL0OajD#o3>bcU2 zAGBjJGvr1)eb*=2>Dy)gMr8p*MRF)lg{z$52`w|nS;b=&m%h{6_&S}MPG};YXhLR- ztApVD`Jn+irURx@q6W)c^Pq;~ZH#I4wIzn-1fs#+Nc`!-Oa4Fh-UG{ZUC9!i61*7> z?EHuD!+}ne$xNMF)$3Qku5(iqMZyNc?AS3mhHxuOC?A2X(6fg?R<1qQOBMavp5m0` zBYbUjE*>4J`)ZHglf5#S`lvG4(T2y~70N%fQ%QdM8C$2qs-%1H_BgQ(X3JZ>rtJwA zZUcVK;G9%$Ss}+e%J$Z_wZ3iF7N6HABb|hg=Hd$@)-MN# zaNa#})0kyxvYwr9S^k#Kd0}pLe>0yX4p&Izz5B+S{0fm2o* zZS(Ayv4{5mYMqjLg^sv`?(Sc8$DQhVoi*?`YwB}j;drP6#gaV;cElNu+BhXuLhsMe zM_IRdL%e$0AA|DDsVY{BL(GC8KR|XrL4I&+a+5mBbJJ~J>&A}~U2j(FRr(N$o|$h> zJDbLjWeHMsknEAwo+YQk%ZVv6^@7-VQb+zyQ}gfd!hIpDxSvLtq;tf%W^V&X2BDUzOo!J z$~_BCXzem|?}_Y~u$LUH62w*ys&0jCg&l<}Z(6SAxcMMu|3%7~G@W#x0;evV=hNB% ze{~z_-;ST6!gko43m+N z$Ymn!ZR*qX9*P;I_E1|cc+k4hGy##Ti>R*5l(K0pII9nt=r~fGoy1v5jwBGbX<%iv zZs)#J7uWFL`TQO*2kN_d$7>xwR!TTl06JIyq5fOZ0N;$j18U>3!X3*hTe6(78kSeH z8r1EQW`_}MJ%t*P2FccnL`Sf6R5#G=3Fc?>cB@k`7b)>YfY$!M@?wy(uh^N&vIl=gEK1`ePfcBI@(A=C_J%;`jICl zJjQrzoW4|)j(tfK=_z;d7s}7k6w@@%IM5DSF2}>f-;U_~Ys^RDQmdzBRlK_(2`ryQ z_QXNGd-c&5y>oxD_l(XeA33Y&@vI6@DvTpW0QIo8b9!@4PUN#vl;QK35yLeyGvdO% zw2G_u25v<~hB}y&m?cXEuC=h|3>}%L=}nQnuQ=8=93#b<@??&&3fPBkS(k~tsQF?m z9I#C^Hkf1yLPg?9++wNt;a46Tjsym+;zUzEwm&fDmsRl_^y(_!cB+zl%wfXCNLcp_ z_gKkdDo?qFakQ!Q4L)760fnPi{IF^N6t=3NSu;O#k}H@kkf<^rdoj4aC|jI_Ef6n- zi@mNf&YTNIwi2OZ+3JSVF(NOGZ$0*iR16VoIwr)Ib&Rd&qLEDuep@il!mZk{dtN8L zr<7+kid_tiG1%E&^MqZP=~dOhe9a%GcOfVLJwAM|36sLgZ^R%sEH&bb_yhjE@<}e4 zG>2TY;8rZAkS)7DHK}cX3#e(WQ@^k_9XI0>KBj786#_-g4{@L2Ypct)ut!fc{U za~u)H^Me`s*^lOeSHgwofpOj!Km z*Q>)Vbn3wZzuPCNZMD49*2Yuj0^AeXKf71rHdK$3Y)7{v0eH63qo#L806Q>#{cQGM zAdpx7#W}+O=3&F@gUQj~_?QM)l#>>qbxmv~tRZ*pi&P zojX6dg*l+Sy9<(mYAoJnS03*|+nF*c@786W>Rx`+-IR5|ss_8<%)SDV9}ry>>Vy21n=`3^2`FA)S!+v5Wv;8Vt+qVp?x~?_+7erc`96l5sCMjTf5Qn3 zhN?=lf!*0v%UC%88IE)-!-I_*Voaf^3dfqVaDT=CpqVX=nPb1Vzjv?Uqpy)GwtVx= zl;gMFojE&;v-&I{c_MnwBM2r9Hq(H6dIB}VgwY}jb=^S^1BKbR;<4-wmRUoZAXTD8 zX!uke`FM&{DE?qf|A|lIqcQ#3o8OP=U;QTEm>0AHkMr{1_+HW*-;1B*&27lw@jug| z<6V!H&99!Ml~4ND*&v_AVKxLa{J&;q{`btw*<18{M!>`b{lGVCdTt?iQ(PP+L{%La zn$cBn!Bpyc^cH6iZd3zp25Tq5@1m~P8F}m5b06dkNR%he&@I^9zt`M8jtgO4r{M09 zvvu^{4~eufjhyox6dz=J1(gTp#$kLk;j!{3rCcomLmrB}HBUgGA|hGdBhNf zDbYXpd#vvmM?; z`*y4S#N34It)6(vINnM5;88GOq{XYD)v;oeo1WuiTQ%;TQO#SkF%)`GC-_N>r8_?( zG5U6Y2L2jJs&H;5s3C+VqrVUJKp4H?W+8+F{5MIJsdBClo=?v{<`L#gC2>tH4YVpT z6_$|5`dKE|!Zg7QfF+OE39LvEV$l}KnEqgOFV@NBb>V2-#qQBh*NSed?mcTQNCclH{K27 ze8I(eRqQ>M#T(2PUolvik#Fn*HP=Hyu%@B6qF{=OBz&8~CXlY6P=9mOkemK~&oGFYW zI3zB{c8VuYGAw1ks`K#*D}B>J7sBI&r|_WQ-g*ZAQB2AkE~#Bc3y*628`4(K)rW~2#p z2&9M+*C;%1#`v2x`lFWgV@r6ALMz&D+VRJhoW}$eI+%56OAa#(XbpS{sBigSv_zvR zE^HmE%G8eCq%+?&L2vuZIjX6&HJ#WY|6;D^X@s#KII5WH3GYRP{3ks-_ltF5#;hUd zF1OOTpSM!`hgO3A4=u&g+gP_CM{AHOHej2hrEZ|L&bM*-d2$`O*n61}{4KQ#0U)Sn>Ucy~) z3g9dtECv3uKVPd-;VT}baX^MF6yUkQ|Db0r>v}ynexq$!&#*cihgFmQN4vqC#sT{c zCjdMFS3Tmn5}xP?K#m3XN0|RgD!yw8Ny&^m6RdRD9WnnmCq*c*4~?NW!iw;pjl}bo zAYx}?s^Gx9RMjW6Yoex{dP6Mt9H9C)n+?*YMGJO$$sw3ATgG~z4e4n7#tu#TZlKr# zBX{Bmwau@vq|8waj2rekM5NO*Siq>a=_UvgIK_3H&}4^5K&zDjaWO3BzJlUrx~rHB zWGCVzELcqgOsJx4f%DG7h_+yzC5krak7Wck+gk=XZ?)&TemOBp7X$$Eb7f-YCnm2s zHYQl+{R?aZp-Y-=AVz;7!e+o&CDe+=c0(&!RUEZo7i%nCQ)JODrZD3Fx0MmgSN?xn zH+J)9wP5)ktw{Sk)^XJ_?0g7spKz#5%j~q*y0p@kLTz-{Hp2T$rhm=i!=_q^(7(M# zD^|+9snPnp7Rg@cfZpQO#g^1(94l<9xp1rq;NG!8^o&Xet}0I6q)|X)t^&5K*`=w| zy`?V?2(kcBRcWq;4w|$>e(L=f`1j0bmV>(|RwMorc^YRYSgso=chfrx@xMLIn%_no zEL@6;9x_VTcn8iIrSZzJL9*xC+@Vv2`whjN1pBb+kfj4hB3dg8WxGZhap<&$3wgih z%3a|e20|@S_8;RtBqw8UaiKb`Ix$D!;NE~XGH3AVeP+wKf%{s^ zcFoEw4hw$PogKB_BJY5^Z{A_J*7CC8jyAX|HnG*ea(M-XZN=Jir!m@cOy0MZvq!JL zXD8a=H^U3e|uy6*r)lb0A=MQMP zv^+B#tHA+Pr$6j5d1$ys=EJHb?s+(p{HeDnLE*&O5f!K2*3B+&2fN&fU9K6ad0t0H zrVJdAD^mu(FOjz@asMNZ=_XB5*zztDRfWTKOz{ZhrJ>AEu0lf*fA$m_#@FEhvNYhH z)*W+3k-1+warHpDYP&mbBqe_0b~-8>j6aIfV@7@yJu8Vu**4-T4L9 zzLFYUyrP7e7USmpy@wqd2_byL8HiNA*!!{&PZ-y9T*)FWZ3NL^C|{i)$bWDiExaBI zM!`?lAFFt{JATo0)V>&H*_^quj?Pg-bC3jvezeYd#I|DKT1N&81nM4p2e0EjNqyqK?WHHa`E!e$;+17n9TnET z9#expTpCvYf-%>nfhBKnO@hT{$=*di<-^5jzOwZ`0naOOKH}OKMqRk2#B2!-eZdkS63G7(RrTM)Vi@OWT{8AL^Fp8YBqT4%#K5tjEw{FCjqjbjX+Xws1zZD;iHIteT1@j2nb@gox7UUKn2wIbXLD*}v` zlNCYNLO4dW4_1Ud*-ZXoGsSl{Q=YrcRF>CZWgxIVXL&6JwRYJa(-JI{TW|%)Ck;RsG4zRFx{@zyM!J=_W=F-Xsj~9>C%AY}tUMu#Z zY^^QG2XY16o28P&5545G|!K7e)2kH9tgR4tMVwVy$Mw@A)* zw)RCYndQk_tG#cRR-)z_lUp1tWM`_yLLt3&Ni0=Nk7iH(;R&|b#q@OMfTChwD{E7p z3q5Zp9;Gv0v2N$FI>~0?Yeime)f`1l*YD6%yrCxJ(bIy*{$feq^Bdv+{N|I;R}7bG zGb5Rt1wlzzqF?h=-&qUz{9>1%{G?%VRHW6T{oBHCBJBDUKO+o4#DcdNNyM;iga6GK z2@CKxzIu(VK8#n#N=CuL!7@rjnp^De)82Pup7ow|ydH<>$lV_GuQuB+MxtD>QEI~* zU>p%6%${&3j64|d4MzSIjTvmv;9iXc^*vAqC;XL0vS@+A>nINL zgnc}U&A%MQVU|a!_jVY?zH09LXcY6SQKV@7jDnh2V+iYt?z@iR?I;eLWfX_i&qk3w zK|G3GJsU;LA&dyy^tsjg^}RdLm;7qnx!M~3mD6F|hx-jSAYHIq27YBgCB;}cA$edw z2VT3hzZvP18Nu>yAJb@2+eTfHzTJ1IyUN>mkJO%w_e7*87>%~3h-qWr9&eDsFUNc4 z<)@s;y|<6|EWa4<_UU-Lfa^c>SL1#&-jm|Mv)H@wu5BA{!BufY0Z%$~ci_Ku9?w1U zzt48UDsCqx_&eW;t`U0#7QmAapwQq?XPRLxF$*) zsjaZRBgVxd#b?hm-d&9q;LLe_-uoKBoEpiU#^$h&K|zvO0p2+UJ&mg2zNV3(@2~hG zlG2CM4emwsqXK;(lf-tfwSk8l~Duc(9?>3;l-QO+uzVOB3?@{|Z zkK`-=EdByCWS`Q##)ScUsV=7@+5P9Z+Zk2CE7lYDYuOkUCFXd|C|~Rx?#%3Q@*Z!s z3wK7t%}c#~mmc^LnHO$dO%MEq>(kC?%zAfTK8}rdICCtN8M75*m9YpC?=t+G{Nw75 zd*X~F!Fy5QoMf9h?JQ&5d1pDPPXpi3*?N(R#^$R&Kyzkr*={?-X!mDi^us=29R_vf zU!XsUNqj|k_h{RW$$1uwNqg;8vsf;e>wTZq14FxG9|`hNWMXj8S{T_y*2$iOv-ukR zl!z0x?ejV8FC?8hNxH~$C;1p1=F}jX zm-PG@e>k6Bn2V8?KAA^J@)&WW_!Ra_&^(!$O6*$u8Fe(mtu%6T}M)ZP@Mm+T7v4m43FFPsPPj$RA4%2XjC1Tgm zw$-0775@oqyxG5|<9-J#5N$rx;mU8Y#w^9j<5by3C28l#$3lDQ@4g&bdk(d~8(mnk zE-`gx`DWJKZ_%YX%%832%N_zvI2d)8WpJN^bRD3QO8gM`syN@*BfUN0v z8Zdr$lK+0BKW7x&o##Kujl0g$V{fPyxqs*ld4PpiQN}L)!snvOv)sa;q2IrN#($et z^p|n{TE3-tpnf|hQU}zs98dbb#@&jiy{d6{jFw(&+zD2Dv5$XHKTXG)Pu1H#tjN49 zg&#lv!>V%E-~FaG+{3${L~_=BSDw<>brbioW{%KvHJ#&395YK-^!PJGG_!DCu-uE= zdaLX8`6v*w{dN3bQzfn2h_@yGPuJIoH(Z;)ig^3i5pP}k9@RNi0YG&ABYOH!2Vg^; zKQjOS4T(3cIbw%*mR8}|F>mK| z$8^MHW#6L#z!XzwYzJIv2W&^O^NQ^_=8t@W?a&w^*s&dwkMM}?U{;HF*p72er>%a| zr`V40Vx<=s9#(qUSag53((}8Op85-Hhao=-k5`Ukp(bF3)O(B$7|QO9>VPY!{Es85 zL*(2KP#vlNkp zNPXH%U6xmsSeI1zL}uSrV%<*ysp<0M2?sgNeITwLUY+M^Q>T@8Q$K3W->dpj$OQYU z9u`02UyaVSV(DRw)Hx3e-|Jtz_mjFh`_m8T^t*2_(I?$FZ%jAWt_TX^7Lq5imBD$8 zx-t6>|DF2&ciep^EgtlD%mrQ1iz8>3BmadGRI_f#Fo$=CQ@$H}YB>`dzO%=ARq3hk zh-5_b{mR$&WCV~QjJ?KirJJkA^blugL+Y|z`&i4Kb%vj(zs9JZA|>?v$>*nN63hg~<}9sQ$UletBmpi^na zyQ@E#)$aU(0cFjrI`Z@FeLdvdu$|m>crwbX_Sla`dBp1|oBL57HgBUmRDCweZT`Da zp5rH@Jkz$GpN=ImOW)^MN91*N(b%G(A91+i+H`6f`2WdS&=zt@bIejpf({_FrEjiYu=t5^V0A-q_Uu>2H*6=# z_`d#jagQFak+t`Y{&;3hZ4pEI)l3_88AeAx1_%W^oy&RXiNX02tIsxASZD*bcrT-p zBQ)u5q}IJE%uu9U7cQ1;#z-aK*DBdF+n?mNo4ee08ZlT~6FO2N;kZ)f96truZEOMa zQ|Nl&jB*Rgek>D4imp;7Ec!8gYBR;cSMhChwFTX~VuTndn0&R^Ib2MZuVS_tUTrY` zwx&u~K{UzL8Qf5_@zqrLDhQ*1oB(_kbCls4DCw|afW+*?AfZ)r%I4o*9#*mvWcFOwwi{CCGf`X zBBLmH%&ebtd|GqIgxGKisNeHk631t}=lFzI_QiAuEpR)>Czd)R4ft7G?Oj_7B3rDP ze`;&m+nVBHQFzgAGsmIbrcKVVpA@xLWlBX${H~}Ydje~1;s<}~vr!Zu7oUyTfx$AMF1<$X zL^xdsGB2(kP0*oDD&w0u2>9OEpY`RgC*1NR7T3zOLuCoh^7+lSF-9WTjQHf7`bqxV zt~S~2v%X4hWZLny_TT3N%X^%1uixX~7{ZqsJQ!%@J9G>;O zR=LzjU(a*yX^dcH+|r%j*TOaGrFZ8?SX{uQvoU&=Z0L23yd8DF$C_nrsi@H6jyETQ zS+xMZp?}|0^YENwEN3e90X1Z1FKG72Wl*cg$dGyNd_lg$t^{QVo4}nu(|tcV|5&fo zXyf{y{BEsljOSbPbGDj z)#WXOYaBlc>oap|pRBNm{9y+x%rL_Gi*{Jd?qEads}=Ud@`}U&ee&Q|-|v-MRg@A)~u(PCabzin^6!EryHzgRN@ z>uS{Y`)X<&OW|{rWJVfo*?`)wc7xF%UYg&&hfs@-H0Ct6ItpR&0@|A~&{vJ+CJsyY zQ{?ScPAiWV&bvKCMfs{^w!W%Wy3LqNjw9UXtCDXawHe;vD|j8f$6;*u{RSg)w6tGg zMAm&&$@dhElPLU^Ay3APu^}qs8!5NGZJ9Mioib}SOV4bG0ec-ow8Di6j(D38mxysa zzHcD{vX^GU(w61#;v90zmV`M(B~{pBBZxtath*f~WKBo!9`$Xj5j8hCU|8ajU!cbDGmfYu zx4){@-g-^W2rSu|FL@s69y#YJ182ivEz3`$^z`iqD6FHLA-p`Zs+G_xBc<;MSPOReVz8EWiz8W=hpTCrlu`+xU02;2 z20lSkwN2FtmO~ry|J|4-mX-OxnC53}-OQ~leBIE5?j|vF>kNh|#SD*8PMx~MEfr-y z%*t15Syu-pBxJtI75?CADM;wf_eS3&9typ|XeH+Z40*0@ZcbMmU&VYezS{ICRqj>t zT&$s;QzG`J0V1jE&9B0)gN(9(phEVL1(dZ>o>*|QMc^)0T+5rEi6dONR zH|Yg*rw&v=2W||UN?pk`0dhu{?JzvcjR!-gt)5(xHHY~FOqK2=!DOX{8%-)$( zyIHnyY%L|1q4K%MEmZHSJfW`Vwp!u5X#9jKHj-`4z$2t(K5kc&gMWD>(Hp~82lmTk ziI3|omOjSh)dw3&V)Wg+7@g*~AzK_@g$-NtAza&8`>QA7SMNoAukY`|&l#~%gR4NT3Y=Jn^zqkNw>8~VsKnDpBR?~d*MY)b zJ1p!n4f4#C3}-tGYQe(A-oQkGc>t5tBPO^7kVR;MwFp`hoC<~Vo{=D3$ytSOw9DJN z{9h|~MXfdRm3Bi4h!?BR(5&1g9EO~awD8Kf3$cl-j^iFI)HrC`e4xIcL- zGIkR-&6E{QTzr}Afv}kw;VC=a?IYR`{t>F@?HOZv)|ioVLc!SL``NdXke9K}=8Vs! zg4D+&UH49K>?rgvT_4C(O{{Fk5hDBCEyDq=EskzJ9=%~*-M zdtbcb-uj>Zme=O}y5#s6M=s2YhrxryPwfWPTZI3{M{nz~4einfT=7Qtjp5iJf7yjC zW9^;Sy`lQ#&%gJwmf$%cAxEtuaqKaQpJYY39fJu6huC41Bk3r28`mG+pUobj{(;;g zws1oCjz?zYW$E*2@wji>{l2A`&Po1zlK--UpVwX4BFy3m3h(bDWPK7p@Z+u^Pa)qK zxdsbX6L`4O)16-K{8G$1bEZ~2M6JWEx9u3UuAx3et+DRiF=}0RB(|zlh4?ONt-l$y zPUH#X`o%X@d?`0~i&=vTd5Bq;o=%@m-?h_sO;FaVpglzKZnQ9kpOil5(`U+*U>|em ze?bn$#;EMSab@)ziSfA4^=r9Cxf;mpc#6i9UF#;Xz%Xs(AyoF&W2((`|AInIHzS*!O5AfS}ozc)vnQ!?UkR~>52XR zp~!qE&!4k!-X$lWr6!7?p~5js?5aOXm81V5d=y0mLtNDup!a`ANu@&#T`h0m9Ly6w zDp;;-o7ZQ~15bhdQOV1Ho&486`l;S~OTM8qeCRDXy!Fr0_%FV(vrn!W{n{t@${+W< zryCFG4}SOBHpbs{%*7&>cFu}qHf>>5ZKW<2%14V`BDCrnm8Gig)N43Hkbf=gTnWrR zimQ+EypRP`WH;hC7MpmKEZ&d2NsluDPZ;LlTjJ=A|MX167E5$~!;6X4e8GqvQBsrv z9IoxYpOydWd}qz#5uax5xrgW8ah!E>{!b_Nsb1#peM0#N=SKH%7Wfv1PI1IIa)JGa zC>dD(6GLFh!0Jh0xK&$W*MX8Sdc%kpG=NVql&61w4(cyv#MB0MZorVL*4=PMnFvPp zD8z8ok%pn=8A1DSqjuz-bFM01j8D59vG#a^QG~&Obm?|3c5!#|$^3mLIg{omQueyy zm3=2uUdS=@#XMpv6r+Cdkfc=rN7L?;CZ=xd4BEOyytfbD&ruHkCw`(9wp#Y-!I_6> zfu=Ee)4_v>voH*G79?ZK#=%@;vA_;0rA3xOI6T{^u*_46aNv^BaK(d|U{DiCEL$*> z8eP=LEU|rqu#8N8KrQu*Ka-J3*r*Sc8>hqSq8Hy9&I)LSH&W znocv-V^pQD74g!qdH3f2vp4@j?yo)NWF4qE=23os*7kJMcKfvLSHBI%Q}EqNEQvTx z)w7rZ5)P^VY92W@UGh*3cgzUR*HKMxXt=`Pus}1|vlCO@haOZ@0QyG#A-@mw!Qb$4 zDdx5O%9`hut&gji@u^pgS<*)?P|h*@LF5s+y2H`qi}2lD4n!1Xu{Y44oCe9AG2OaM z5Y`nMTdaqlO%U1e!G-}Up@Pvfp_t;Zj``?8m@`yk=I(x!DRkZMGUU|TmvIwf*ACy0 zz2rdJb-*~(t7oV1xQg%OK?>WBrzq&V)k}Qwh(n66J^ICbEw<-*Z6hh@XPV8@mcFAO z-04}rJ|*?Z5RB!S1Ml?~ z$s@#z5?-8H+{OalKb@QFm=N;yclHSUo!uV&|HgbT20Uhg*2L1ow)l6nMBhQW4^>?D zbsCWNGlS(*VzRDj5VEs(<3K8dvQymfHr8%a8D)T)7;P!fv_wW4z;5fafznz3YQz6} zg`4*){B=xT+c>TjUll&)0{2vpy`Zk5s|@biKPuC$UL2ls;x~HKklzX)2-f#-!k;v!LMV z+M>bK(FErovLO9*eLVIvpY4N?#}E4H-t<#Yfz!GP7Mbg_+dc!bhh^2lezLavj%H>> zWLKYHj^)r0BO8zdKbD+aEb0sWjH;aa8EOB2gnVSp^JPCZ_p|yADtRBd269A#n9~S; zOw(s_$iakb+pG1;AnpaUL@=c=aN3j$?dg0z)!^VE&ya?%ydan^OeZ9jMEL ztS9~7`#{d#45WMbpYmpCwB)|!&Cp`;B{zS4KAxf>Iw7aYLo~$yH5wu@$K~()vDb44 zSN&cO-7#xA7s>;O6Vs`|st$k3$u@h&AyVNleAc5i9A|`m)~ou1)dBCq7^b|9a=M5` z0zWbH=GQX7>6x)@*xSw8(Uh0)IAd}hIlJq=ieB?I=vEjNk0Ihq?Bbl;%5g7ZxaG|A zCz#c(mTyaoF|_&gOxBBLO?NCtGv!}1n&GcFk8W}9x&yZ^60d~e3moGeJ$QCxWjp1_ zS6Ij}idaJ$bkOj~x<~AzTyH=}POj**tBUO?O)yXae{~z_-;SSFeWGACzd9C9YQi96 z!g$C1f-@8oN;0YhLp`@RULXOdUneHa?o$m2C55eW*Ulo1JIn_-{C~Z{6nj=yjSNpY za|RiwZ3-~PdbMo~T1B;s&!0UuYp<`kbHyP47~?P2Y_fZM?4c$X^If}}wl!&6-P)F{ z)IJmcQ}Po3bLd05(>^!?mnqXueicr?(yxCNseVV$WrPwU=tN*rK@%`bO@pXKc1=91 zN-fPIV@bi096iNm#sqT(SyLp}74??g%T=4>TyWgIW>p%bQ72y8>g|yg4r?y#tZ+1Q zArp5cXL_$^P<}T3UilZSavOhJRp>nZ7Ecedl@-^la^GXZVGknpsW9_RMEw}9E~XOvu^XNnlIgz z-_*1DRHHwfI=%Rv-9UF{K)Azx?3@R$^FIh(q81A^YRk+_9qXPU{*_1pJhPWAGd$a- zLipNxTj;i{_nfPk9&1!mHIQK(vl$#@4^{h=8ax&y5ob47ggkYyp(f}zrYj`#NeyKp zXfeavW^sf_pU*yY*_$I6*#j30!;$rnSOQK=p2yZ< zwI{HpYXTb-PMR_7C}59fEW(J~%q}}H^&5FB5lT2S+TS2CTbtGS@Tzr~3-GRWe@7L+ z>RrrK6R*HZ8<>m+Hgs@3!(^DK;ny~*3Dc7>3vI$`9;U&lJ0$Ci7KZ;t?@*)rpm%>o z%3XVx)Th2L);fQV3j*0ib&22g?SUWmNwi|=)vQfJ_uyzIe*K9xdM>)G+jZIHcSLQ; zCgJ9ouQlY!RoR5cLkl}hw4dt4yvu!B62iDtuyzT|P#qTH=9K{uTHRS7MJTARI{)4wmzrGg*#G>Vo zNFByP8B;ADa(9X;DZ%6aL7)#CoW<1fWQJhE{GkvqB!-CD-6c<5@jjAHiPIT4VY<<^Y zMZuB{Zd3z`m5U|8?;=NO_EDT;jA?sm&f5g~PD`Z?hjcSlmDUZ~ZXN8iWJ}Q<_7@s0 z@MQ&6EaZg#4lr?IZLyE$dK&{wH4tjUr{1A6VDS`9HK09uftsovOB7`@BiKZsBC0>W zU*BnB3(BHio5$z>dEG@MRx?>+b!{}7hC6m{nQfR9y*gr8gFfgBSdlh1u z4W5}biI=%ptU9lV75q^7jw&GP2R<%~!I$JT)zA*a){`7_OJ*naGiW7AWfXeXqkXz@ z<4If6T1lE17TRL>iUZlb=zC(U%V}ed5Kq`={)SK4vJPBX79+c@R%Q^=$jwOHJ)p81 zuJNOgyXVBygSi=ZcoMm;-f;_Tzh__adfRt=$&0hr?4Q;0;9gr5e;s$)($T_!*%FrY z#%!s2-Iy)aCx{Jh=b_RCRt1&XWlBviH5Z8sJDSBpDJ+0AqA%9pHs;hCcwRfz$*^5= z(bTG7e&?0_cP8`xqd%2R+lBcp3Sr zi`Uli=shyq%4&JpVr1hGmSn@#B9A?m+Nj7*i8XZ08@^8G{9ZMA>+_p=JK|6?$0oRv zE!WGHPfvL{x0a$DX3q;UfCx*ieg2EUwT0yu%)R_>v{<6bEW7h8FFx3pT+cK@6pf*} z*&Lm~xN%G?mw`Al)(Y@gqm-%`xs8>TT5W^WK&E$RIDB$gcM($95ML*vm551o_LNgi z1^;&#m8<^Th&vKlTpdSh@RTl~yDFWzo@`iBKIc?&0t+{TdfM8r6>7|e=ZHRxUzJ+5 zE)`*tb)D6KP0(= z6&F#muPnVm*SXRd0A@g$zt{Z~UQ{g1B(;d~o6Nkgj(C%p=M>gG=mubCw;p@Upms(V z2J9WMvOzBPk&8w~S@>=7=x4f-yEe~N>nPVPTNCzW<{mCaTzeinY~U##N5>j+T~0zqMTT0qd4;wWLX_l4l!kdz?#W`I{y77*+Wd zBl|(}zGP&V`<^kf)0(zxO(Van*f(1ZG0@# z-dC4dI<;oim%iuA9ciS}od%@@87@^#!}Z=^C4uaiZCcQ}<3Ipgjt!*euqLCcH6_>U ztRM2_YLb~?-)s!E@Iqmz{TXxXQ5V%_W||0+_e$6|wJTuLXVyk_Tb!q0t01a`uNGmm zw9u`Ty>VMOh12?>HN3%_lNhdI)HxXl9)z4sU4yg_Tu(^sFfa`zoNfMYW_<7 zjN7(d$3iL%(um-0PZafLTwW#?2SxyXGzyq~uA~k6*am*~imCI{8R2{P{3pHUoOhin z{d?1YV!PP^r^>dUDA3Y_w7f-q2VvSS-iL0qR?4$Y&nRUjS zy|@pne8!z2gmZfoVoqt}a=eD-mLN)1^vsDHC=wPHz+TJ6wW_2{uB zmiPY}7Yhe!)r%{oGOA;kGv*Q>} zdmhjB#n)+@KJ;eUr-)EinYGsURV5sAIzI56E)N)1$^s=2har*X&f5N5?4d3^&2_{z zFP>TR)<=yMDAV4XRV`K-Vf4JOOsn-{*M5vNKKshg((K+p@+l^0VOh8?2kxmOas^iV zhFrPKIP&%8zr>}<-l2W2HEZb5yB1yfQ>15Q!=aXVt#^CV0xD#`TCk)8NsV@QI+9%S zrXD1biW3YFP=1U0bBu?%de8BxSCR(PF7z%Ds4b@12HWpnv?Z?!Cc7tvPAgb|nsT*ORNv%kSXZYSMN1pTR-*;xAg#Ccw(72wQA(I{ zRVsD3k;61e-qy`ljiov*l|@wR%R4euMZ^VPO%wst(dzD*;TxL3Ra>(a4LO>nD|>C^ zFIU$!mlun)^V_#lMIP&(y7gD7n-6lXzd~Gp>9%TIFmpWB3|aSS{+9f1%L|+QIjZHh ztMegRl{PH7fAn&&Y^GRF%Vx_hh4XgB^oS>qp6~4|te|3gn>SK5wDd_RjgcU0Ffdh#3UNis(>_hurAEiZcorD|i= zkG*_5)_TP9v)?^P6>M3+s6cz-;HTaCZ{;ie1aO{07QQXRqn8PCh<)abMat75V9BRk2O_SL3=r((cE2vi8pZYZAR26H8D&7tDfKt^{!OQblu;;3h z42rj2;B;UL%r`TkQWJU3HTyEZ37J(@%exiX`q(%&mo0w!e#-X;TfJ*~TDF2a-bxAF3Fu$C+i5Hb@yYJ` zWQtyYBqQJvnf(Th*pBVCv zs>ABBBlyzk1XAL4!*fXK+q38}KX6|lpUP>B7}h~?hH`y0&+C8Uq>Kd`l1cNA6fT6Zy^m>AIQQ5x~ke=2qoY#i-qNkxn0;5CK zy9~2KXM|%ark25zf&9+Uo+NlTttb}@O9!V;QaY7%8$)O0Xx9C-M#-a@{3fG`YJ_bx znx(Mv1?l`v%xQq=>+IzJ4A$<>^6PGQ-|gXK$UY+jG2RgwOND)9KPGxWxOTc=H-lPp z!xnNTmId@mnCwr)>dIU7bA5g<_0=rCAwdapkL^Q`{b9{0>Mz^0Ma}b?krkq729n?j zsV!7%kwzr?r|YUvUMS50^*2d>3-z~Hoho5S*LqNw*$;$!vw3+W^60laLM?RpL+_5W zSwefiBWV2_X=i{{8*rC;+@A4mi2Gs)Wl~AulkWICkQHMvwE!Gg6R5@_auc}~xWMyHL!zsb+qL-O4wnu40 z-xo%K!%oR^Coxlp!}DafWkj9wYQcUac{Yz_T^`d~JbhP0x0QVjyWAXqUH127w|0JQ zc72ob;mz^*W{|0QdvD=9L$u3CzZCsI`#q9G>$Z;k3vI!_))pd``L^(HhHnP^7Ul## zrBAel`d-X#7TOg(|P{C{K#-5sMpo8FSE5VP^G&7#b_h(V?~2E9_Ik^k|Hs;BZp!7Dk!t zoj5D=w4rA)!4}@mSwqlZu{n5Nr&XKJ`8oDu$Lc)uQp=e|SN*%+a=eFPo!n~8o<73- z&E6CLSFyFA!&9H(iZ#yJs4h!eQsvd}4i>F6{cCsmwMDFi!un2O{d&gv z8X0@ac3Qqp&aaaU8p`?Fu9fXt+pe{BO{2?{YB)8@jN&#p=g&Q8TMx#i2gK#9QWM=# z`jDSXIKJ=nj7Ifc$`H@-N6)yB;5ifn03dK`l!=b#~2|? z9zyZ&zrfXT#dCTxy^C#jq*dF`q*uSD_LWiHCUtna%MF zJbdN%R%QHEw_BwaL)cN=q5c@(z;D{vawl(mdvpi3-&A^Lsr*c;3E^68&|nSzoNFt zB9$z8fo|uLkU_#Sj`#ac|3>;35%kEYty5h7BTx)v7Q)WANF$Z$DVAe=+q*DF0#x6R8|Sx<%k8>PKUqW{XjNsvY4L$D^XrD&y{LHQqc)9riZq z610cpd55TB}h%?O6+uO*&Ym6t!bCL*JPl;c`J9qwHZY@@)@r#X*>+}RmwSRHU?7@N~ zxwKGlNKeRrAtr+)yc3PVa!q9PAqvKb^OnW`i7l|5ThKrPqpZZgL94yklG>GYZ%cZE zl6IkJ?U1w1)w1yl9`*uD;-L6FxXKxo`Irx?upGme@`^=4vqryT0jEfeKjzH z31Vq?%_qWEZ8rX%*jU|aOZ}uR1&sND@XjG(ZN@;XM4;P!xSKB?KJ14(qCyvbkFk^o z4>HLcNy-_t#)p~y>ID0BRsY0dugTWf_5_O9$#WF6;y#ykmt@9 zm}LhBdXII0!s~L=9cE>~82UEvGs5rQ1oF<*UV5sDBn3Q5Ba@rL(r%%G83V&Syvv{p zw^54M!?h4wncYFp%ja)0@K9uj@}uO^)HK1QrjQgL{>exeYT-#PbXZFThN)FGoQ`8y z7`Tzt^DOsGrXj9aNgM>dh4lYPUNJk3)lT-WAm>+9aN~ub-=`DG(X9x(-oB^oR|gi7 zSXFlUUPPy5l%{(1417ZH*&Kh5()-D8jNwWPmMblgm#J}Po@8Q$4d-kG=SAiI~xgxee^7N9L{Ra=KXoX1IqH04-Zq&OWm#e5^&>NUVbnA(Ct95DyWQ?bNuD z`Q{+|I5&M8pQA2tI-Pdy^2m=yZ=uy>WTb5BZ1Zu{g3lxMDz6cr9S@lu7HhGcZG(%Z zZ|*dGl8bQW%-)A$oT*nV*%0)Z;f#-!ue+2aOACjscg}AD)k5;IY)#R~Rclv{6%|Yk z%n4(St z;G8rSk>Fr{r(R0-rWPC;#5rSa(=@#=u4DO!N;RLEVGq&WiRw`$yZAP^t`u?@(^+|9 zw~d&rBxc8O$bb(|CJmv_C4IRD^H1B94krWo zU_JQZ@^Tl1=lHGGTwLR4s z{OhUh%iPgQTm0rw#|S>|+Ihz-dMUlvtR!u#bE`F4mcHJKk|hO^BeSl?4_IH>xc zGSl?&X?3~dy-#;gnC)5YX+O7_f9lFl=-oax4VfYI7tU`Z)q7VZb?422VGq&x4;)(0 z&vcIZfc$k{b(`AXnTqZuB%BDMp(u<||m ze_hssKX7sP|61|?>Zkr+ZXxbPdQM1L3${R>li7z%>}rJaXN>>Wwqw;Pc`_qMV4uG9 z5`(aM^ssUSck{5?ar6?~?VBZ;vDQRPTONd;%y%5avdcd55}W5K3&w zW?(n$g$>BtjotL>0Z;M91L~i9K-HZGRL?sPsAnH|Za?#ZkDqx!bzdG(e?$Pk^JDt? z&X4Jx_%U_pcYaJ4AN`ni{MwVPef@(cTMIwXK9A})l5z3UX1~v5j{ME4{CpSBV2{A( z-t1PN%w@gzX4mka#xpEc3w^Z;EOFGZ)!1%Ufpz6!6g5eR3u2t>JyL1EK~^ZY6L5WR50onjARv8bJ551}rW`f6v3j=9xB3O5l6 z++B|m39s`_M8f%T6OjOOT&@PNd5W;fnIQMVa;>okiD_7U7rhAbgn|idRqjPJ=VMGm zlh@%A)1aMw!eOa+kHb>DMpQ!&TXIih8pK6X}oK%w#=~-kF7q$G)jqYVjA?M zM;3+5GxyA^m1AWobD;4IuDOFNVuvtZ(I7gQ&R297uC%L+nG?MD9{QUmr2 zGs}8xKkxMyJMMvL-KG5m`Ektg-6`c_e1584VvcU~r!hy@^Z&&h&r`OUbc zFZ2K6mT%&gpXdvypKLs+ONWu#Na0i)DO_qJz1=rYqoVKRTp0CE58v0;iE`piVrx8q^_0J-h z+r3Yi$x|*5%;X7u5WhxSr9IQ{$Bg4><{cTwKdy_jTTIl?2WyE~TpTeDq0fX@dd`gT z<_tBg4a6%x2hm4Y_N2;Akb>}X`mDz`YAe@GYB6t>I2I2S>XvC|r{YWxW=^t`<9>&I zgwGBKRKUs{Uo2@xN!Hcf^Fq8nPdLSq2XE|86uBUuwmKT?Df|R~egbOHY_HM0 z=i->#VUsTw$#3>gg2Y|JGO%~nrGZtt46>frTkGHsqYW)AUx7AmsRk&k3MwU2A{^98{cJe7Az1?W~AQqbiR!OU9zgV06rBbIKj05-35w>fS*izH2F3!KL6l zfhe{hokPv7gH8>*0S>w`p%>cc)*2Glz)wxLJ$6vGd&ELL?=VWlVO~ziB(@HapY#Wow33M;j&8b8uv z%UI5bXd&ZVj?qFB(j{6b`a28;XRu=ueT)-@Q-;&R)}o6=LnOq82X+QC1{O~%cEEWU z8k{lKgX~kqwgOKEk#A~kNip{3bi#@M`N7+Q`!JGy_B;^Ye*~qRUIO99rN0|9vwAODZ zDW?`n%360qNrB)|TU^NMXe&q=I0-e|PmkWDzt$uTj3C@s00T#GjZtP>MVS{t6+S#i ztzTQ$KqYR&u5a@#->yV!!v1z{<&(&MI@r}Jj&GqKv_D#>Uca=wS?-*C>}PzQ_Aj|U z8QqjQn{n;qQFeR<-pgayLxrs${oM$&4B!}$DXY>iBe54_WzHE+8SQ^J2iQK5n^u`K zio$-OF4Ln7kc>t`fmr`{4r`?Ea8r+o9+}@hgX@$BJU6;Qm)ZEc);|{$33KoTt{0|w zH9uCs`s;ax`j|zF6ds1mwZs|ZNHQRIF6r1f;CO|6kbPMp|BTJ#Pn;{RT6Qv6}R?;TeVjrIdq5MI4-1!+_S;a~C5x~)vEimovNgTN!|{;U(VGpNtuT^gIz6W^EYaI?|XXTGaXq3 zy9f28hgu@xVm;I{uBr(a8L#apdZ=A!=EbOo^%NM*n%wCuwZ1)`r7(?hmVReckEd_j zPT%Ygr|(16@;KLd{N-^!oYSd4vypw814cTMpTU6%SwZauH5r<3yaheD6*Ww#sDFZm zlR(4wAew5QC6X87sh0=6J2kCJ#AqA*z7lb5?<*1GyY4Fy=PjeJ5-S91KE<~Hksu^Mm);`XXPZBnJRGYL#jo`;ClZE5KAgJLGF~2@Yj&Z6T?<(w;Th#%U^30OD z@UI-*yQ~zG+D9uz?lT|W=UyQv>7EDVBwhUgIf*#-xcW}HMNiQ4oQ==ppY%cFJ9)(D zt-H2I8Fr-WQ4NTNo#!0s!yZ{&s@z}7Jrcy_Vp4_q&agg_VgIl8)R9TmuPRadCwDXB zu(7h*c~;3Y7&l%kB|8W|PhyXrlI0SXRdw$PS<>g4&xvX0KiFG)Isk`8C$SLlI#mzcLz$`N7mZ>p5rXzuhno-fNe zw3g6tq{V|)(_k#(*HBzf<97~ZPHZZGU{DQX)lnmdW=ej&VGKeE+8rW&JkS2b4! z)A3c?*Hr_ehI5u+xYW9uMkq$E zHp#rg@O@n8VXGzCLRUwTTquXSQPPALg3Y;D-*oRLOix$i z%ExjIMqf8-FLYMg;4x*fN9ManpFUr$v6dP5UYCWB&NtX{h4ZE~TBvk2bl5_nS-z@e zbYMw>`Y;#21r}PHM)=pI4RC&bgkwhysIz7*scpU}}G-Y82T-j>9yE1ZTG?(r2 zHh3ybd}3>aGEw;|yw||?VWuOQAsC!d5PC(L@{qnw@=e;69ZxueiM6$|DUv6ZuJ%mx zcNos*_jCVUUfSCy#Ag`Vc8?d}>*(u)DTTvhc@xnk2A_4l&B$Xs0qc!$w~>et^9aD_ z9HdS?V-6ORLJG?-;%_+E_}oPACEJr!&uZgTxLRr)cS)!u7&m4DL7hhFP1im=2F6Mc z!}ZX$2FcNko3Vi!?TSkQ4tuyeS!>{QLR|p+nzcLR*?Fw5iQEE`c|dJ2RCAlX0*Pv} z#<_AYf35u@(>|lL7=>EUiMTkMC^JYHFYr(od|X5hB+`bM4K%a9Hwf)&O!W)*D|djh zfE8XaWzgh~u9a`1l*H#m`C9B9IPm@@(6aHroZ00F0VvVTCN=4B#Te!_-h4W1t+SnD z8t2&bm2)HO^j3>U2Q4(h+WsBSo>zA^p~TR~p8NA|Z;FNy_07(FEfvmtPnoCoz}n4r zpaly1S1P9(sn}&fZGgv@waYD92qvl(HF3PNOkDgjs9B*zDWY4cu%Z94XmVV+$&CFZ z`E{-zrq^%X!s%}JpCf&uFXO2d(eDAf6x~b_%(YObi(`NR(q@>W;R^GKc);M2cId_* zrNTCzaKFb&^Ndh=@Y_*-bRo=Ps~M?4Twd08Nia^DlQ7;*D#cyUg+{(lb@L#@9QK;|O*m^E-V>seeF3KVYx`!4A?5K;s?0aZ?T%R~(mB^rz{+z$&weJQE{;x{JH ze(RIy{}1w3Wfgl@PODf;RcB&pIjmxj_Qhcpdn_TauVQp)!AkTm*RfI@%fDTngcwJ_ zqC2ls%r6NU<*Ly=V)AeuK7(pAi?&#!1x}F~9VpN$_6|xYv;_`D%pL44Ox<&j9nOxr zu*kS76LFk9Mhj>}dYAQ4G07qocuOMY30QCGaV=KpT-nzmXtlrmqy48TfNuwqZE za6=3`XuAE}bBB09Y%5ly=IC2uJ`bTo;JT6PbmIDmDRJE)!%P{VHjob%=hrl@37zk^W=w7bojkXiDoh8?_&}{o!FO$TH3ss(J6-MQU~IxN2gA0(8`^X* zAgY6{YHd_$*n$jX(`6UI=!KQn)>%fg8y#jF%@m12=4qdxCB(+c)k}}Mt$U{1#u~&2 zjJZ*E*K0|d#7Y@LrE#_w^vv`gYm0p}*Be;Yy+p9SeS&dxdZ>h;@)p3ff%Y`8YZTF9 zO?ZvLdV)tz3P!@>%3HOxjCC@b2F7{$BTsTKVqv3Q?omz@a)%N3)=Bckem=kBuxH7a z-0mOwp>>!kq1T@Bl(nTKiJ-a6uMyb$D7rVgMc|DN&tdX8{Rwl$|B%lk8M% z`Ft)r8O?zE925IaZMC0TK~%@^B6TmU4bOjjnt91*tkpfyXGI@c_erGG-b&r-j@l_$ z8Zy5*m9q>^@t0OpMo;X%*F_SeMs_QSlfJ=j93(9HI!cOtsu)08M&nBb3$K{mEi7qJ zb!=?e=h#zf6;7zpLR1lsl-6JZN)4G%TNgQre);M~9`#%D##%E$wanj_H&1~--Peod7|wTM zHjfBu)GpK@KYvBCUEZDB9vy_OsPd`LytSC+Hdg68@$RnYVy-~P`2!PB=CAdB{yZ+< zkK^}W@*zC#Kh_;EuK{DkkKZqCUo+1P_1ls!5XRI=?k}QPt>7Rhv&E_)d1>%`=qd>L z;m~x2<8gS?N;Cs&ayJyMZ~_%*KlEfehrY8`M0}Z18_$uZTRjp0d$1Yz$Qk zo$!$N&&(6+YC7Ce4u7|;y1B$`{p#D5J!i|=8k6b)uU72d-W%CZUOLuc@}|{i{iqSK zez?5B950cR|N2}w4ebOPDCuQen)ZSe|&N z-;hTRp97;b^q*^CZm<=XB=4UMK4h{3`a!e}Lxrk^capIGdE8wF(2m$qF3` zGn$_DgWAHmmj$c%3PWM$n!Y!45n%&eM)&FwPt;Nnsu^oz(`R@LWbS*X=^^F*h{gZL`@~u`}gu?hFn{>2qOlps|#C z7kJ*yGG1~xv_8KRHBdOj+7&K{byR8VH$I(_q@YE0EWXL{f z|4p=P_nK+Y+&=M|p--13aK zp8@`xk_D9$G}xF1ruAbL!O?Tf$k`P^=~3RM@yx6BiT4FNc0xMH$@yJB@Mqk_?>Qho z(KXnMqRmK0WQNEIGb7_nUdsvN=77h;3F1IT%mMqW+uY&%UNY#Q1uo1nz)namV(v}? z+d7R2syQYwu$-_L8KBR8peK7)YfJv0t>y5!A9f>+B}!tDCf$R6>stVc5(kK|TtFLy zlfr>9Fx@md8H@|V6jxg#m^8DF-g>Z;*c?`l*q@&R%N7*XnA*Te9>W?i%0O_!ijArw zK{yNxj0-G)mS=R)yHP>7Ht!rP)na_wWtFu*7_9@c0M6F-Gh_iX4HcJ@im>L|a2@6h z4!(ipFGVL9@sYr|Xw!iN*U)Q>Oc^+{Vcld4qXRqQM{DzX+BsWyU&O}i9e%qjUiB6k zIlr-D{{I(>AMD*$h&>MyXe{jbggD=}j71fbQ$Z6?$>R|!rOkwGqx zVVXszp@~sd--F4Zz9AhyScPVUISlM2ohy1H4QE?^6DvWzC5$jYW!aDC$nWki=Cyo6zop6i$|{X-m+e~nFi zxo=+j{~vkEoBxcbeEYSd3MInou1>K9INbW-JQ5zfoo9yL2!}pr5HV98JjXKA_7MRI z>yRrkX>>?SW;bz}pDp!A`}G(}K3JGh6O#Gi_lNuMavb>?Jd-_eRt$O&8R+(0Ifq zL+>l|qUB+Bh`ZJ3BXT1jH2N6hNeW|*=|kjP7_4^B2S>mhNn=C#_biPa`mWI-i8%5& zm(_pO*=a{%Yf?ypgcS`Q)L&vj{gJL7L|2akaXgP)Lywxf`<0|lBB`T4#=X$yc=UT) z9s|E&ch8!BL13b(x=ciZI4Z1^LDJyko|Gl`Nfy(n1`18RgL)b{Y$J^y2Fa`9MfAG zuQ6t(qU<_o0mi?eN!K+E&wZjNr=E{-957P#V;m=Z5Iuz_yC>08%XI`2eat_8^l6|b>xhBgnO*OodaI-dVGc)@DkK`TxZ7x`wdk?lVxYK3 zW%rFRWcN|jbFn<{TIX5gq?sRB$uN=6hxIVs#-?RqTJx&FCrs#WwVLY=ke`j~%Zav* zMNN)AVAlH6&eS^7!nB~j3~_$`gljo_4x;!{CE^Ng%=`xb|6}hxuw2KLEzv2# zo8f>k^B=+w2NI+xlbNcz_1EjZ{Z6GQii8b>-8+*XH9lhaRrWc;1K|}s-nF#73bkQ> z6G%^8bbC^ZY7QSJ)}a!L+_J*(_l)~b`QDW6VdJd7>)gT$lFg*;^;vkJaD(=VFSv;_ zft+G_g$U$~+!S_{;HlsE9PWIfoGUsdUv!@%mS7fTHu6isI>aeUmc5V2MFu*SwGV{Xh&qs&S+If(^&dernh^r478Xe-h^LO@vqmg5; zFsk_zhDK}?wW^vbc|DdgNSW&|GFzbV+6dnt-pv@>3zGj^rcGE+_BCIht~oI>0<5_k zjzxIpcIE5SHT?+b9Ok#?mOy{`UTl;5FE#u|c+K~^O>PgJ8kcJaYBXCo7|GF1Z;SxF z$bL<8ucNmLtC+AdhpwT|q0i_S{sKO!BjZ}Pnr2;)ZZ1z9E0J!J{SnQPT7K?)B)MErwL^PR=2p{hN9t^{7p@P0v0gx>mN?ORYKLO!{Ek zvC%)Dy*MA zzrW-A_HE0(6XU`*&>x4gOP83et6;b}IPr{g#rIT->)yt#*;IPzZd1{g^3M1DB6>3@ zwjnl;wRd=Q@MD2(DCz~O<)(#1|x)P zvReGvuRBo#c?Q^be3=6+ebPI3+EesS-cd%EkoAKPMKRy>E0h`oO2I#aQe*Vyj<+AI ze(ar?*r7^&g1fW$1@*gsTCXc7;&m7G}+}FKYhTRBoz`flP~GR3Owh(3;Hw93n3$(=LM||tjx=VB~IA& zPCFerqBHNZ3mX?0OdaVu%)sDtY6B!&D5jUKp)OoNt?;f_jj66-a}iCGktpXqIIHWC zDVUX+xw7Q{0xM)NvA{~4Q@H|Wg>T-$$_ zOS#Nf1jC>;l}3ejHihO&s+eyGy9D&4YC;6Vwx})oq%7Qz_#(=Tim4W{-Om^1P`iHT z6Gbca+iymnzcM%z$}DaHJkP+yfRxht1P#%t&P0bgVJKuoaKV5*bU5op-84 zg7O)vL7Vx+){`L$NANa7`8>M+$Zq&(bielI_oMsQ9rukHA{5hQhW?#ho8IhNPxwHf z?0LWJJLbPIGyk1=IjR?5&&WXFtl_IQm~fIC zR#5g5qS~A@Il9f;Y<<&U7bC2+>zjc#yI2zZF6!+%BVWu#0;RR>2!jndI79dnqBZ*a zzu;wNgtzDgmG2vVYwoS>-Iu<73%^^&W7fJmHZ{#z2$GcJD<2d$<Q{AwCO#7>{JL#(Nk|KY~414xPBRkl`zPjN_03E@V@wfcSN1g$y}6-|L#7+^T{kbw=^kBKK<5OD$IJje>xx&B)Fc(ax&i&T3@J-2x$)f@Uems<51` z@6qtpP1*~xG?o!NUrmCcsvD@Gy)oKvK)gpn@HGm~Oh-tthB5xG$iS|IM+{)FwbR7) zg>4HOIA1mK5$)I5Dt&{!9KrHsJHzf6z!{9CloR_B+k7sx*QUsAz*FD>FBsO7V99z1 z27O~RT7&3nd^Kz;#lkJqe%@Pp8R*f(IOA6Q4F>Qw@plo=3XyyGs+C@V#Lx}&6uzp) z4Ki?XP$e5LmwFH&3_Ii|6vXw3LVf^{tZ9_Pt z!l=A`;zvWHTvt3gNQ5XDz$kxHXLRD`r56oWLrO!q$@Q35JqRA2dC-va4dO6zmoqYO z^^F1!j6*EzVK}g4yy<+^5HsQcd4-sBjBIQA1sOPM$`q{Eh!9=>N02tuZ8p`4v=McD zK-!4p1wN2AqH=qsNkDw(Tci#BO{5J*=*w-#!o5@!p(g?4T#ZsMyQ2>W;tQVqFCnz` zllPJl8Zgh3IJp$Lkanb0P(n|i_2qlLe*X_)Y!HHOU3>RBlko2Mfqu{VNl#EZ^j^iQ z@1KFyum}(J;u(H_hR3oG2j>ImaRpRvP^o)HsO;g84I#(gLWf5-I35O^JmV2x&CL@x z=+3hSBjtKGEnqIqmVBulR?xyDS@O*I42mO30mNniMFE5Z^Ww~m(9W5}7L~-V*KeBS z2{UHzyvkUSWN94N2%C9++Vb2vGq+3?LOa!9tPlb$E+-tr&XGYvq_zFX`-kshZh|fl z(Yl%UPJ1Z3EO~fJ+mP@Gpa>^wB6uys3IvrxTVpL!tbt+_Elfht0hA?N=HYEg2F1gI zhJz5)5hr`aWoAw)f~)1&#^91@^|-4`BA;TU>LJFCRYpomZWH zXT>{#bpV~K0dST!iK)8cX5|599S{1qobTxExWm%PNc#2vNemk9JJvH!%ZxZyoZjZ_ zpcRv8{Rujlo4BY{+YGaR{#LR7Y~R;#M>^eMMOt4Z0|t99_pw*+jm$BZU(KpHjv)Cz zNIw#QAhZu}7-%GdaV~j(da`@n$ZObh$GV%y<-Jab^*9<@Umf!Ck>za>*AC5ncI*BLS?6>f#( z+n_yXr6v3w{8u$*7^D3YDfvfwS;aXTx7)9Af9PO)qnV3Q!}FlC3onmf`I58?`1+^N-iI@16)5K z9BArbM4Om7Ht?F7m^t)DMTj{hXDs1^^N7b;W0(T^I_;uUaPF{XwXojVr9;uHbA3g_vsbz}2=L#ubx${=gcv$3>+b zT-yP1Y@KI1kM86O%sR7=*DkdwG=|mlIaZt5Bdj;9M|O**Rp0*7{?oZxYk1O5oV%Li z(#FE`2@^tC0K5tc>*yEUdD{1?(3<4GnLXo?Et>m&cb!JJ?ihOy-?|+m@AX~{B(eA@ zX+iBPB zxsK+FrG@>eZc?)if9Yo$31?7{HnLT>Xd{C8Irk9iAt&zEyS1a}DPiK^j_p~i?%Kp{ zh|`L@$uy_$kNPaw<)HQHdrj<44->5mRhm`La%;a>#$Pj@<#g36uk)u`hDbd`y)~!< zr7GhCnik5sc?QlCUDb0QS8{^Hgt*0oG%oj*C2!Hs&8MX!I~LCWb9GxAibG zR(6?=C(wLH=x)XY_7R82;idz6`k_CR_bTB})nq*Ntg zKGnT%dC}}2wC@Lt4sZm*cdUSUrvOQC1TBU}Eu3+XGj`ddeaTh+0irtx|D$Zj$}_fBiN4=;Q+>IDU+(z$c`iu@>r~O*@yKXY6K1K|)QC z(BcRS7eBe9pU>@TOk#mAk9x?B3ve=-_ zftWUEZ!>Z=evaxrI?T?glG%bfWSAn)WvcfTRnJ!)qjW^|o=IzM`HA0Uwk0j{bTfDR zoIGIK4a;c12y#UKMNjLx!|k%eH}p!;E;s8g*SyQEad`TWr0^>4$Os?q@xAT&ZQJwF zc19@4TaMWy7aU0#>ucJiH=s%9oa3oaC6$L>IL!FTguSW_J}Z&dnR*=2f~pPs6?C+* zZNu5HncN#3mMspS`(|2-*;Qw29u?G|qN@Rs+YA`v!}i?sz*vyB+aOd6+et!bJ94h{ zdCMC~T4yQG`3IvW9!0~^eevpIgxXLw)bXvhnRF|ZHv0(x=5~e+nn_{~wmIA3yFr4< z(|6nQ-SmEV_EH|+O8P|{9K%N@&4Y)|?F>kE=Re|1f5h;?5vGcevkpesJG76{F4R_Q zK5x)7!CnZXX4Ic_=(b?eII^x`g>c;%`s--C!x!dNW)sQQkcX63PLscJjtO->p)`z-gWdUxw6-9qWg3G%@R_Oq@Jf{h0OOVFzG4S`Ha=2&y3U zVV!K?rwa-YYM~U3oqHoA5ln$!1wtm$aO%@OaFZ{+pHQ;#-1jdz_vphbSOfwdCR zS6%&IV&$_Mn&N|g#s?qcgiow{jgHjSGX_&c;CVkrLsN!hdPx80!&r;>jz%#=%mY zx(@T^dN=!bJg=0~^W6D)D>o!Y<|c0We(lkkHIu`s9(Tq0%YIx-a&3ur&}X}5IX2zJwp41vaY$3Z(l!UncZo}(0CzMn9Ha|;2a%sw`25( z*?s;tUw<3o%isFtw`E;b-VqPy{BD!)EdFm+)e};`nf~SJ$K1bjyxvP#FsvDeCu7VA zwWP{X*>X3}N!X4Z+EnmNEUICD`$pVL=xwA~W$zlHSXT=_8l8WVC*=n@ ziLc`WWJ!DwYmn?j_d3?Vp6Uvs^hK=U6_UC^>P&iuF;AXBxUgnB^w_5{fkzZW^7hZ# z97bu|vkKvF%))~8nQx=DWkzcaGdw{nVxxZpdCf7G#~z-NvmfM~;X=r_Tm??KO}2&Y z@h-)va9rDlcwbv0?L^mYAWPXEGuh)7q?L$ApYx_jPR}UCjywI#i*HnCyP!}+pZxk>?rB&7QYEA1rC&dM z?AO=3U*9i&eZBkj`KnzwWC(dRIq~be)r(EmrMr0d*GLp1`36RvTu5iRaI^X&uYSe*8Y`9Kt#3PFTu`vk z_tkHT?9iT&KeH0S~*Hn8;rR_%2xx5Y2OM$bm?ev^dTU<9eD|H z{SFKNC5b(VE8-{PQP^91%7#I|Euqz#22y&75QAo(Y2Sb}P8D-+ntPO}*}Rg<6Ayc` z#v1jBAA07(kT)}2y_wkKJ;SjqUgtnLb%*zB48nFe=H(0Xz#dvF^I&l`z#Nn3mfzXR z$!8i)p0y!}@BZXl%P)MUqi%~ z^(P+E#^dz4hZLTrf8rshr9$r`coM>+G@j_Jlvxw-BaPXOG_DNn-C0=2Tf@x>fjp ze?ST{Q}Us7q`Y>jNH{7JRu8}@zGxhP!x#Mx%ZO|71)~SgzBthx|Ep;1QkP2k=6^>% zI%*X^Se=A|kN?)R=1XEp{Td;dRlJWL^XIil1~iZ3nGsH})?tWzFxG7yRzi!dpsHI{ z+>EaUhEcf~l`ZHl$R4I??C4@We*ufm`TAr$yxn8 zLlfWSPw^9^WI~a-XZB7H--;A7C0e9>EsodPx64sLZDyQ{SYiC?Y=UO}CivCw??Y1p{o@u;iO8-kZ z{hw#Q(%5-5meJJDF$ak4Y^{^kh&H(F%{#mSLZT#%23<~sw}QVbO1u&l*$Ht)dW5+s zpfhWDcmO%%iUGy3TTrSp3`9lHlTGEGL6UDT5ovD=@!H@;+YYRb5Y)UZJ<4AS_ocdUJy1C>kODP z5`N($zT_F35SQ~$OXa1ufAdM-WYRxqmRdh*mOqY9yLT;oUjrj7+KQ0&_dN>h-aYtb z-3_X+e(=ghu5co+Y}^#p#?arnOe7iPxz5b@-S&|Is{)3m!Z}@fr0|_}po?v_7aMV@ zp~Vb~uxG>%$^&FyY;E(Sx&fzYF>p39YRYmNf0EnDeyAfK^y-Vc(?rN_@wjhaSH$d9 zI#-W$*gewGxc!9npV>G@c!hbctwNry$JHp;Z)&2I)I`f26!qe(*Q)4w2dZYL?31sd zB3t)OROGp`mG~O2YnV}sDQ|$|;erX4cEnK7yYjI^PR}Xl=P)<25gr}#W^>Ir>RX7* zLbjht1!sJ}Ykl%kH>|`%9jIbRYc=;1Y=SWN6C4lyfwLao(9%3{jw(<=<4wIRv3ZAl z=!m*wg%J<|C+ID?R}6Vqd=f*J|3) z}6@a$(k&t7lks z{5~n!4aHEF`K?LJst3}~ zo_`+q+%RHu)=#P(5Sar(_-?qk{Y9cV!S2}o(0kkci4_L53g4aKx+jm?ZF#&DCfog_?R z33IH&Y#7U$G*ZV^^b<$I>lxXdtSo#j&1>gVNiA75s>nU_b9H;p3P~^7c_h2=zd_>q zm=B0j3?x17tBQJIjwzg15!^H}(6G$?{TdIlHfyDbi^;mmB}*_u$t9oniW%ay&lnY5fcLzF<21gG)80tKgq^jv4JSp9yEVA96-eN zZ4-@mqGIG!xD8|l`HZ-Ms;7H&7If_iOMqmum{t?VN=+*^Pk$orIiJ8%h=_)(;LQF# zB3cyuk$uJ(TWI-w%;3!F!WnGazP~=5!FoS~kKVk(GblKfgm8o7*6bQFdoe5iVLqbB z0QOX9Lbxyc3Q@>fO!A_=PM;1B3oqWL?YEj}4nRdTG!< zxMRRNtZ-bxS5fBypKa{PjM7_ZaVvtWw~S*pUuTK8jD2_b_m15BJvs!EWvekGZ^GZB zqn8y%xGG7_bM%>YBwm7^%)y&|y|*mq^L^C>K8NPN$A!uL(NfrREC|Ws_$9X?GMb`B zlt}!&ZHW7mtnGBo-ecfcVRqzaczeQz$tMiHm?Gnt#8G_ST8-t`u7 zmjwkP@pBtvvZDVyCuy-;TC5rKoSvj9LFG-0L7TOx)$-FFV@T|+9qH8CxVAROeazC@ z0$+|6xbUh4oCAyg=j=&SWX6QX8sXjwZS$!W{)8^Xnx)6Kkj;!$ID@rL)CdnOB+x#+ z7mf7%MC46fo_Nd6I`b$F?v)5)tRs(r{_Tq0**Y#y%~gHi`TWUKDUU&i#X9{tIu}QF zvSvMiy_Pe+H#ulxni!OvJ-J%!a)-Y4SfC~jg3Gu1CpNSbL(a-#intb!XZ~_lMr1#! z(fwNdoZfHM0}rfyj9*yTa0!D0$B7N+9SmVH;XCbMZ`9fjtRiR6oiWc*S8uVtDB~0) z5ALqqhVafu+f~CA`wd>E2r5I~O0Hkxc_NP}M)qJ49)3>Bg(p8JA-0L1Q|mns3qjne zcbHjXz&`m-Ys3p2&mLFv=yBzo@H8y90$CXvWygGp`-+gn*;}poq)%1Y+Rk`l7g@5b zqc|#Ny3tnt&dh(84e^863Nj2$Zv^~}si8;434Ev5jFTe|1m5(?)AzXl8henuq;VIW zJf7*t{S(a#KjO1zy=dQ68ZrL=9!=%86GrSm)pq^Mw)4#4DQ4E3D)?MZIaR`N@ab$3 zQ|g<%_xHG;n0b_zUY;=CKe+eP`(PDrg5nG_&AIHv2D~GfC$0xZOvN2bmTg-o9mzmQl6vKVkKF#c!8YY^#=^7`?pG>88fv`2qi+hdnFEm@t3kj*mj zoE+bs*XXMqggXUUx+mHSk77iS8qGChFosLZ_Lj???c+Q3i#wBgh4g*2myk>78Hj>; zUMWuSjbGz)&nN);`1yDBcfaHM)L;Bks;VWXY$TJOaGfsLv0uH#WI~}6uV4~^Z6%UHc20)IVR)ij*9I9 zGd+Q=j(@puThj*LY?-pc1LyHFT0!!=PXse-rWTDe6n3uU6@w{Bod(rvFvbtZ5TZVG z@VmE}p;kzZkdbO^ zC#%HCDoI%P1S?^iC`Pt$WOmPF$eZKUfu023OL(<#*4y%C$;hYH@+q|R4@WImGd*-P zC$q(t`&afDPA-6Ww%f-=4vmho>x1?`4uA|C8{z%Ya{%vH;=m_ z&*~i`y8uxVFhXR{`;&P{SQ30eU$Uex*`+z@4$8 z@0w5YeIJCSmP}t~lK0|?xm+)^No)*U??d~Mf1P_;#t!y`Uu6ej_1jX>k6ssv0oPhQ zuvPF3-4U5C?MjL(x!l4Xebm6Q^}4SVzsNyFtBlt-YVh&AE)09wvDHbC#mvqr1N}<= zsifSnvX><#^)^Xw3CSM5O=-i*&0Wf=i%es_H@okpGW@Ou#^>BTtH$s!-&-^nnP+a- z#g_7sVRhWS#sMCGQ|z3p^Kab#o1ml$dHadS>{Q1nRm_LPEBm#wU#t7Ix?k&Z?K@t) zKA-!TZHSj2EEte|N;oI2LT8&NmL6+=$V%%aIy7fGBv$##g@41?obznSJY_5C? z5|2ZTlYFNfp`{!xJg1p)fTVA$jiqm%ngl(OwN~`F*_Ol1a>RO1KV>sv&V$~Vd0g2x zB}8WF-FEObQ1tGu~-@Muy*>;r?u0!%lJ)Z0YfA?RHwo$XLv%($Z=Ki zoW-T>^ftaur>2uN5l?GEMvK`&aQytV03ELbUZu1eEKAK}H5_kaOsn^v7}gVL4Gtsu zr;98Z97DL3B~*{VR_NJ7AS>6N`BFu{wx>8H`3PTIofAh#cwg=6Jvo@c)JM!*os+230C*4O>o#Pj-Oq?6#$Tzp}K`sLsd&W9&%7&9$R*0b|1%HQ-k&zzgX-^?e8 z!xa*F@4oRSzsg7oPco8b_BEwI=sGi!c$TGhY@cVxh&{CbXX}*k6*|HWy1Re!jyu)z zJZs=@*3`$2!tuZZ#gaWp?uauSwQ)*VLhsMeM_IRfL%e$0AA|DDsZFdFhdB$9`2n)~ zN#+N)CRgE69=mSyS~q@_=z6zWuhNII=o$Iuw6kgaSe77E2gx2;?OAFnyquUKQ!g1C zPk7|-G&TSJF5DNgiraY=A2JB@O?mWOdV-LoN&j+Ee;K?WM~d%(tWlIfG;=22=9uID z^FE^=5Z{fb0@d&dv-N`fIV~r{XBIrs=qt(rXSrv|6PmjW-FqTC2J9sVs|0haJF#0~ zTVY4x${Uv19Csh2?7v7glctgGQ{dEv^L$tv;IC#Q{oC+UwA@0UrjH-1H5B3-5?W$R z(|$*BH#GpYIg=vTFRHtTSSCja?L4XD0K=pw1acV&dz;!Yt%YKG*;?3YE_l$oUNt2m zZ!V&`GE&N>*5IsOD$#MIxH^fek{n4OZc|5Qv}VV#QzzE&-|_q&at_pY>yGC-eq>5m z8Gz30Kh%FK8sM7|c*xp#WVmBlWlNSbR>ShDR)e}-(r7S(wWY8{gh8^~hCoNKbW}6Y z?E&Uz@jY5h8H`}Jj176u!y|(YW3_NbCjE8BGhmA%#j-7p<5JtZ&LM zw-=-73?b89@0_zk=m$HF0j#R6r|t?Y;ABb-&Gb5~0wo*u^`Z^dhQL}dI#n21gmLN$ z6dc%#4h9#dZXjxbNOqD|U&B{~zF_?zXE`)j#wvs_#sA;g%cujdcJg0z&exhy3y+%6 z)TJ?3?Y_#9F%8bBWb}UwzX2!g5FRfzs-oUNc5TOp{Bxb2nfonA!HA5@% zG`%UZ_Z7$5hBZ>0sZM5%Rlq)U)4ELLMa>smVaaWxvB4rs5GoQ+;uZ_zho5z9I1(7N ziUUpgSpR^SUnb)>=+&Ee+leK2tzp8&NV)DA?y*wERGwlD<7gB04L)6}0R^L1{IKcx z6n56otQns<$rY>?NW{#?UJT|JWs8$?3&cy|V%z2zXRZY!TZyt`+3JSVF(NLFuPwHS zPz(_{9TVo4HH@w2q7h9Dep|54!cA`2qplO*Q_3@rVi!Z@9PDhbb;2%;^olhwU+ahI zU5LqlpC5j3!lW?k8!^ZYOO5a%{*eE^@kuU~G)pa7a5END$d;X-s&Lz{7|WAA%$rwi z##8(E=#6wi@KC_YciUL{XJ6FoX2}Me5dp?)hF@DZv70Gh#7mU!@KVTpu?G&;kA2K9 zU9BbuC*c#$SoGY9ua=$#k7eJ9=PZ>(Ih!cc97ja){9uHB_M^EVb%J^#R2X8koS7}o zx4jC0bci&bvMwM8GuKsTw~k?=EPd_DfW_Z`y*k{?PF*bUyM2=C&gGrGnGcxFY)Q@Cft{b+%sHUCyGtemaV*|eSFU%V?M#)F zck40_buYi^ZmPPUtidihIB*L`&r^+Em0&6!ld1Qf5YthFhn zGV?0!t1XXlcxs4ETVe|_-^XwhamViVH=Mv=sH!w7*qu$)jLZRuaHMPL9&FqYV+uuW zaI7f{_h$?Mno(09IktQI`|uh*`Wl(B<(qG&8o&AO%+*<3)n_S_C!*&(f?(2MGj+J9 zB~T+w=ry8H*A4VAP?(J?9%*-wW({G2REZW-!-r~!$5Vu%_=7S1M|>I|jp^6k{C-UT z>Nokuyr31h&da~!dr5D6FMg0Ww<3ba|E5LjU60J>S5MNcC;jVekk4Y74aph)&&UmtY=m^vs6M z%Gl(F=lIyp#(f~Fd24orLJ#T$KZ$ec&d*4keS16ue~lnjI5z{-5XvT_zZX6b&R%e% zP=*8iHwnvBIrD?()3et)!hB&8*VNKLs}f6LDHB;gtK^zFO)vvs$z$#WG7^MXv_&wc zKUm!pb#i)LI2w1cd-T(_qU+?nC$E{;Gja^ypp`SyoiE|Y#HLz<>AMqu9{E2|f>p1! z@TWD-_$FxgN%pq8c!a5EwsDJ5zF@sK-VNh?$&2%<*!x@-Z?IZ?#$aKNH|=Hr>oWI0 zuJ9QhI0G??7UJGj~BZ!8-OG|7AYiiOi(_4rIdB>f%j$GMYyJAcQ`ULAz!x4t20HTXp0yoK_|D>+X$+I}#_i-!y zeJg%jUFY^E2PY^1VCU(~F$rRRSZrCY6vh$k5*K4T#giu)ma?Dhe7wR++jY>H;c?2R z@Sxz{dItZYn3Ok6K(R+Fa1|Nd4i=WRC3}`S*D0LqZ_KsEO>+Mva^VFXko9j`bADf& zd4)sGv8Io-u9PsR1>u|o!BA& zVy?$&gs~qus#xj???r|DCp|m&i*;enSwqZSZl!ZSZ>9DRtpxoaT8h-$$Xk%3H3$_O zu+7oa%#3LM@fE4i6b}vdM@JcsZw;9G)qk@h?`#LqhTXIsymS2%44row@i$(|p~h-i zz?-Dz>XR%WM0&pFY`xCd0Q1)Wb*&!fCENw40L}uYrNCeI=WA6MzTzT{10rOh0M7;f z2R*AVK69I)ST0>Be+)nh(a!V?`6kYmC95yn3y72mal zq-4gO306Anj+pLEq_7xO2)7*x|Kz3lBgaxaqg9%lXEpXmh7||N6vjouw z{jr=u&Gwc-%vs{--acVr zre$>6D=)3IrBEB)wTZ0D@J!m!|H-Puv|E%FYy`{o^nxt6B| zx7y&U*u+-~hVSn&)-2B4yx!T#+*HeTlqPiTfXMOm}IL!d`co zh!qakF~uVgmxd}onT3WT{_H6=aVI& z&64&!RK0rSVB^%oBc~9-JgzuJDu%d>?13*Z_myyT@rn{;T8x|X_a1g=qzvI3%s_Eny6EYM!3&Vsnt$eb`|+`7XrtDJBgCRo!om{ErPe#X$(_KVMc?^S01 zIl>-I{f9?330fo?KcSj0AsHUkdE_%NGa{ip#f2um1J}2jWBuT_Y`-cu)XysDGU4uW z#0<0I2pxp#w`p%~Q;(54OKMr+%w>`y{MN~bcAPBqS5fOdYTgqjLNitGhIt=8Q0~pb zOvo#HBIg`yede$8ikIK)zU#Te`yO>R$M5gIy*w*zk2QU&i`BkuUs~&8 zAI1T;n>8VQ>A7^OQWiZ|(kl=QJAY-2h#lt7vXoaVf1l7M$dBJIQZ+UwQZ*K-(Z>h@ zOFAVp5n7LG3)`3E+%6p)wV<14z2NVMdDaWo&?d{a)R)I%XXXXiEj8P3&4f|&t&B23 zD9TPrZmqJz-y`9`X0=pff9k=LU6VqF-loTUc?XufoJ2NrRT}2=83XE2@83U(NF#i0 z?GdUM)~kc&{b=2g4%VnHK*yeCv{LKS#yKpOS$njf85h}hwSE?iAWT7sJH{A1(WDg{ z?LhSLIteQ0`kZjV_z{V3FSYoeS`qGr6#+)e$%>$BA*>PY#fq>eo5^2nrufcg%Hyz^ z%Jdq{3Ix{YEU%@Y4o?JH`KeufN&9SO#?sSKa%SL4WxtG!`tIj(H|M*o8OF~@WU=J~ z11!v)f3#I_uxOl;xwP`Zu1oS*NVL;dut2gfi0_!JSqI<1EutBTTB-eY9CBX zb^FsfMcMxsqJuNFO{L5y+e%;aqqY^9mw0>2guNn^HkOuNPn z%V;~>z#z)p?gNdlv$ppbb&}13*NV8@syd3A z&flS@c+Z-QtEUBz{fUx%)HlNa`Q0a>uQ^<*j*MV(76c{b68##d`p#Ow=NCKuce<7WHJgC4whab!rWqi zpZ2~P^Q`xzRPpjZ%BQ0mczA!t5#UgfkC1e1nmHMPmjVG`LqI zL46NY!3lq*p6uDbL?;@Yd^Ya!i)Lp2({&U(dBQ#(#p+*a&CmAgL16D1nq$zjxO_wQp&G&tEEtgUd_QU(B=+b0f>7Z0 z_MXpfXXn|C{xHl(Nait5YGRHv{@-DLU8}`4LD~qn!v2mJCyErGJGh=#kDdjBpx;3G0F+`O6|@C)as z1JRiE?mT@QJMM7iSSTZAE6!C$5+vSb_&52-)gAW4Igd$E+?0?T&pUh)0nL!9i<5WEWW{dk)U#YxGkht~fh>k^YE{7ylmTV}CM2Orbyd z&L@uFM)8Mhs$@Fmv)f-tI(3qCk>^h8F&fON!E9dA^GE#Qe0o7HMp*h}9wo_R#Es%p z*e}WE$&6HD=h`Q)R@D&Jc zQok6{OMW!wLk}KHI7RZblcN1p$2;d?8fI7`bPa9m_7kMyKjj+l_OEHU-@yt*n-6uk z@|#>^mg3}b+So=VY3IntLVM}&z8qS64z<4e2Jp`I? zFzT+#;JyawI&RMg|s_1iHK9#G42Jn4Im zyBSY=#c{VrORpSvlB+$@$3Ngt({alu_O=fhnWv@jrAYbr89c`Sw=LYa9(n`C${y@>-G64P-gq<_`fD5t=ovVCI3&; z*N8V<8^4Np`_~a~UD^@VSy%utJO43zdf@@sv(6up|NoYWPWuuRVsEd0GK?F&@RJ=i zy^~AIvX)K^6_2^Y`rxjB6>rwu;RB^rFm}w_IX!YZ;lk%q^d0^?wd3!2_)cnE^mnWUozaUG zv&)hHLP=J$u81&)cZXBG8+&TG5*xm=D_>Q5>N_GCQGL7OwLKXDLM>p7 z47Cd{%e9YNIjYX^^YGUg)w9fUW_^P9)?Ka~9%_76W0Yt5%gxF-k)fw*2HmjMfM%mv zcd2H0HlHnpeGZ#XPv)@cD!8M6^lLJ8%?;bh zO@}9=Jh{hyG|D|*N7>wua<_RO<*v48qg=;7H_D^`WRyqR*Yne{L}cmv8taI-t}Yr| z6!ar@S6m%V4Fmr_ISblCE@|{pwvwO&i0o;`Fbzw@#s(+qM>W<>5ozTYYSB@Dnic7A za%g5RVrlCR{5-v0K?#eWC=YDgGdNrJv*H`JlT>_Pe><^9*K1_$eWO2~QB!Ngkp5z1=nq?0qaxfdfq3Bq+fb3{cp(NogSX_#07@8~Wvijt3+^>d6*YwnN`D=q=`dz?$c z_>A`$pYX~yk?x=c?!fp&sx#7npS9KAwY6Yoi#6j=wzzBjP_I3V$ii6 zq$)009zfGhU;`AWz5uCLVV~9PwnBi0!@Z-2`wkF#Ox_Du`!?A2lZgc{I zG=Y=Y=M7FrL<=RvTHa}&`5&=P##Ymu3ibPSG8jE_5l$LVEx-SCT1z{M{DI$u$@!9P z2GW}?4wXw;v&dB)YGS;CK_<~(D7Z`L5-dt-an zm%E;D%ad4Kv(gTgB{<8+H`~TJ62WH7PtK{G$c9lveu_w~T?9;e*v z_c%Ctk<#zC@8Po*tK@0_Jnv6$0nVL2RZpDQ6p_6IBtZSqU`kvHtI$8t$Kp)$M(G)^o0M;Ygp)bM9%3U{>7Ho!{5OHR`2z z=SP@Wz@)Qr_A1%X^BQ?Ow&NaarnRM_LW?`zoCs!e0enOMzG3t5Tw^R}D)j+1WJWKj zcEvK-Hj$Ab^W6D@c!y0%mK|&Yclu2C{p9>(y;7r%>wogQxvnvuZ_ST?yR#r#Oc_PD zaF9Kn9_6CW-&j)=Wc>4d{@s?En7o{4%ZTgPb7U%H=ErZL7$nQK{H*wA)*0m`{~+DX z4Xpj7u5$BRwkW+lNp1GD9lwV!5BmtMD9`M-U@C3XTL{-UeiY_s#?(GpVG;4e7Awqf zhV>Wiu$bLqL+Ps(_QdjvgaCc>tCx0HtmXbJ4uYfl8%^PpQwx*IuiE-N7g>vD?#O2+ z*N@It``feiRV(lDIls|jUOm5UZ@$UnemsAXGXi-vw)%TEHIAk5IZ84k^*U`p?Pt5e zXb>;WZ{I^%i;gtr)OQ|*FmVCx%^2vb#&Q#frTZ!J_Nu0pM+@iOE>TgwDwVCTxJvgK zbIEap`+QaEErgrlO@0NhqxX3j`+dL35m_zmS2-f{K4S7cMdKt2e?`cXG2`42mGO;K zTVMCenxamXHM^x}_KX309YeIj1qqIDn=mgC<9dAG%m~O@qObPk4T3j1!ujYrxt{asu`ZrPGBOH@*YJvM?l zh>>--MM7?A_3lyMc8;jA%K^g@kNg5#3_rt&TCx4rw%J>+$vFc{cIHc*N4iJOd8)wK zbFil6CsBI(_Jb^}RnAbpJfo_W##s(_t=l+_?0yE$>K#>0nrruX!ege>3$)4I8a|#W zc{i75rsa-cXS{E{qwH_34>dwm8}trQQ%3rk{1lXunjht7EkBl@CzQlGS%|X|99ETG zwo{f)GytR(y5RpN zeumb~*vf*}4NYin5Hh#UV3<M_aay>wo=j!UlaK-UetQX^}Rrj*Vy-J>o9O}6i%e6OkUfr^9TkU)m`Ge?c zwPhU4rU*R)Y2F!Tlt6Ac#XpN_`@x90>#8>-362Qb)t&9Uq@KzGX zS+$800d`m+6q{5udWqD!tw&oukB**gfPYhpm7lAt^a8rmI*4AzQy=qc&C!=lo{*x% zkm1bEws9L&kWmjV7Z2-}p3uGYErw8Fj6Gk)BzwFHavObsG@D@7mwC01G$gXzwDcmi z;^E%yd^KZOIe8~YCtc#$u*?dG8oug=T!rm1T4PM@YT3fETPeA8mCrq{Ve@X2Cv5Y% zb=%;)sQiRYY$RK&fk#NoeB7@l2mkU&qBn-GcI=nQ5+B!lEWP)^s}DAm#ORxMF*?m} zL$o-)3LAFIgQMxz$kh(r+jQsWnl5wE;ViJj@)OL=6BrHzZdE*HhU#Q29Fs7Jh4TUQ zFqas;F;(nAOEArBkR}4uq})#Y*>ZHeW3h#gb$dRq{{15$&&@h+n-I^}Tky z3qNPfjq1z-H5oXOhxGB+$lIE37%K7f(TLAX;B}y|Zw(f983u7?N`|u?2DKn@u{SVL zU>?9EwTK070b~)HU^Rl)1gAowx@QDPS8`V28}0PAPXE`eUHQqZ2j5~bsbc_evl00q zuzGl)Kr%=-Z`%*CFZrq=|6%o5BH_en8O`Ld{?18YE5#gyi z-5n#^7XJwGd3(;WJZsE|IiX-|@%`-ENr=n1jp~fgWdo^?N4jo}(v4&4FmEvp7eQ25 zbm1VV5Ec;P$>}k^gpAUfpLSkX?%BF>gz1JD-k4n}`MA?U8>Byy=3#rGf9ZNhoN7X4 zTSugvMr6$zIDC+zjl#ho7A&ZCR&w2zwF1%}6cgQveQ4HGeY#fM1)-MEeABDh!**SM zbHlmI)##|tJ>lyHX^nO4n7t26&@!Uz3!2;-_|<_!i;6@zLA5wxM3yfGghUwj&%H#4o#`Wz49^ANX-skf)IEjLgA;YyuB=db-ogonMMsXRg$W zOVm2tdfV2h^%k~=s5SE5tx@ak$i!9~u@K)yt@Ssf)`>iU%wK%N;!Cx;d(0YC$R%c7 zS~`6?eOFK4Rmrke1??eG z2a6VLPZ+g4)TVG>H_Y1mf}Z~$n7eP-Dxc5YU*Gn?WcXzPn@3VItVOyF2uL zho-ZknBBhmznSMWttvP<(^abgTtK70r95wSXtZQ|<>z*KV!wYVGT+Jb=Pa0a$;oHo zM3HQ$uvUp(^+#bj`XA*-QB*L*$;JS^|9h5HS~zsIyn$;lPx(>7GOul(pScb^1@=cJ zFaLG&U;F5%dhadyhR*Pzw`6(ipQZ6%d}C*yTs8W&PwtgJ?s-pl9MB*9?zL@5c5BZd1M(pAI=ad+~`{Cy_5lIAB;_PXMgeJ4|1$T9TAJmyp= z&icVal2!p6O@~jKkh-liXzLd7-adFgds+NX{6sBiwd~V_GY_)`s>b3?2M_Mf!Z2*3 zAQ)RV4(1xk0vo857EuP_@T`49h3K5hHeZ^Q8ve76!yA`Y|ZQA`I3htPjp?m1Rn za#t01Ob^a)eKW11;R=7l0?lC04lH%=x)Y}W^o{yMejn(Azro{DjBELoHP0(sudA5z zQ?EH@Nv~L-Tx0ly$RlEPht=bY>AQy3j2D*k$gfd@$XOF<&*&WgUZ_M{Zz+)6>O(;EVi+@K;^bMqYSH)$&4Fl4CWUzcnOx9Hm zLUy!f97ttQc8crX#;w^@dg-7hMqA1=Es-+~V7IkVLFwH7YQz6}g`4*){B=xT+t{x$ zc|yu@2kLkw`D5*!#3b2^2Ny?gFlMihXgf#QL1P9zY%|vUd7NIyo*yJ`0xg84`D09* zW6z9t%=itHy~~@Oy^HaEZ}q*uMUDw2ow1;<(PNY**9?v$nrvq@`H>%2kc+TZoBd!9 zT0ZZy(eC|ZZ=>pWel^PAlREgHtUE_}g)eeJwCme9b3tH$@?$GM&4hwin3G=QHQ7h3 z0lvEQ?dewbptFi*G98#1Vj(Zs)7AvZSxJy%ndWU+5mGbhl)9} z0Wt7n$;ri{zR=I8%Bi1`_WwtjkF0sV?5E~_ZoYv^-g@2wIU+&KX-s}h!)J2H!Gvqu zHtUtaycf_C!IZ+lX;m)Nr}Oz#gM)`W%QSrD1;KJ*Iw1*-wWZBu`+I^bOx!<4sCO&6g^;3r1j{8|M# zJu}ul_jb2-G}R?M&X`PofmcHJ1&;BC9z5H#vW;rwH(1CpipU`i zI%s%A-6Ql-<{QwFiz^!Ks$v^T6AVbb@70tq<$JTYN*pK3rTDeNY99VpVc!+e0l|JNH#v1es+WO%BXGl)2CQ-Cqn zvu(Z8D%zU({MlnO_xg-GZy4n7z5m6UP4;MyT{yWI@7mq8txDUry=}<~_nG*gl9%|O zLm$$e_Q4UjOqF)>t8n_2e*LRR{2f7;9!iLy6M;zuO~5KO4Wbs&HSw$}Td5WiOA3x; zZz)#O2be2}nj*EXsJ9$muB|$*1;^cMCet8|I^o)G-ma){$hmN!!qLoyOxTrN={=u8 z_1W}$c?;;mv5m9J=>kM4vP{F zvUB#%wdcXKfdP>3wCO$021|?s_w2KKk8|jX^m3d|KlhTHb(>#tzBE^U!)NoUM!%do zt@s1oKsQD}xXb-GFb`hWe^7Rbnkdw$Ei*E8+>Q$IuS5#qnXT-V;n`Ld!q?W@%x=4S z&zZ$^<)|b!kZv5K87#7g*gl1W$D$gEkoo*LLt1N0ly6oUDriZT(jnC@*gA%Zdq z`z(SEV&Q%en((MmQy)3DBhLe$&pve7n>`rW1D70z74?u%0!~PtYwM8h32f;tfei{L zP4BiButzhJFd{ay%MMKaO5RFLB^(*;Z;+U^j?MY-s&!Zk@UC@#&nkY^yO@a+ufR&{ zSd0cXbZ{-hWSFSo*EXsF)040YZNO^oroyN@1nY|yhW|zHP^0^xcYn>4yY?=rPkmpk zb^bgr2xJ%W62I%)13v7NXvNg4S(}FL!O=|k`U5$7F1oBcblK^5L~Y3?!R8pRHRQpp zY=YyV1sx{ZPjzD66n6ssCbQF#edWT-#`pXryJPD7ze{Dr^L>&5~*D?EZJj-xA3sE;n zC!%%R!z~8Z+kU+61--=|SuQw=Gxlo8*US01^#1q{yj}YBy(l1(mOp0da4wWF8%q0I zjS@L?QS|>>brapqs%PiW_c4i#)&B@4(cjPW^yWPGgqs1gPxUI_eb;&y<1HVagGaps zwP=)cFavOqB3WMqNemW<>2Nf`L?9J7NZ?qZq0lf4fvD_Yo}G6f{0UlSsK%)KD>Kl6 z%l6NX=D#tPTmj7aM6X71AZ*O=)tUwiHaAmT1T8kI4S{x|+q})zHw{)4EZN}tWGsnqTeZe~-ZHiNcX1N$u5Qgnm;g+>c}xq&JcazcLx zm^g8(vGwX&?Hx=t5Nh40)}S+B@f1xQ&>p=&Rc#F^in19IY$8w*)gRxl@36h93osQU zDrgbt@80x?_7W_Xnra5!vGtZ=bT-r_lh>e9Xsb7{e`2g)U_Qh4Dugr}JR@roE_1QS zI5h#jZAo(_X+l`2 z6WuFzME9ca39&Ax9XUcgVW0UMK1It~u(B*hcI&n=f{;dRM#Am^mEADMk3#I86HX7- zX58hI$aVD&TVVe^`;zC|zT-=tn6>8ktfmL|+N${LxYJ&a78YbnSkgPPrE1%bY^grU z*x+_9Oc%%sD%@pC4KJLFgoPc=M4=QEKpN2(>u(=(Y7IQEo_I2BlUg)28O-mzvLDa= zGu%_U2Y+`$0j8@53NT&)iGlaK>?T7hY{a-Sq#k2{*dFvucfw`lr%qg3$D{X%Y%8nf zWs4DwLr{_pvqi2w7H(8Tr$i1N^9HZeIe)Mw?|ptVZ)+ZE=GX)?*)m_Qe0qw@xwjPM zFneAQ0Yp%0?ekv*<`$M;F!u7h(PD`zv+T~ZJn>*(Vm;FcQ8b2lvpG6}apRa~Edya@ z%oX5~qm)>T+>Xjht+qipkm=nS4xb$6U6d(o2(J^fl?X|7w3O493jS{ym8`pK~fXfrXnvJ+1ZE3N=>4b3`A;ZxgOsmx>_Cy2iZkNmgk_ zJC{cU@41V3!fJ)*;F+o! z`zg4nNX#T$#Q05S+*e1qNsMy}>mGCiu(NB6EoM+VqYEAO4p`YB7hBIoBcd$)ws`b2 z-N;>=$K*Q7+g_~+`!aJ6CnByrj~!xWO76mn{A!1bc}`OZVJzfKN%q zxWBeXe%~Vdh;QIV_SwBR?kf4D|AxjrO5cSkobY6^?2hY~@F~pPtZ6UB?D;gp^^L0> z`HrTRM8CDn`hdLUJC`(RRq|}ZZI5H>EPu1a9-}J1LS$bg?@L5>x$hYwJFRIu*EHh0 zihZ+lAScb}#0Rf5{+hC~FZFMW@f+fz@aISon) zB3!C1b=O*jl?1Y5)L}vEjvW)&a;zXdyEPeIttq*-jqO9cTum|)?3*2-7G5X_wLe2{ zU3F1yMy81%d9MV0Q@a8-eP(S`*NJ%wwhCsI@YNz{mKJ)ob;}r+dg7yo)G(kU_gc9M zMsDpzuBtAWoF#S?D5CokT9Tc-g?ugQi$1J47vUk(Nv=O&I8szyd1jquE7OmkRXYFe z{q5oXlLycrSQ5jiC)^=w=3d;s54FPg!5PUGj7{<9SdO^q!Gd0o+#?gd3l*o z95@5;qfx->b0uxiYa964Gp5c@=M3Mw=RfH+*Szbr(Z4tSC$x)pn+3I08*w$#T5)u| z`+@sp?=i2Ka}DykT7I=kH0AkUSBd!pgA2XscsuQ8Tot{E=K6_oE!Xaxq^>1uDS1jpKvmKgQj~-iMdH>IGu^_<(*TSobL+22YPBe0rs2+9VdzC&YS1{qn_( zn;V{C(y>v)3S6;><2!W-{8p2vQIUm95+yiuP+duq*Gfz`feu3Tmu@p|)L;?iXA&_36iHFW4* zjjsGD(le{!P)oe>-QKi-i0o$zrgR{wQSVMil1tufizHHUfB^!^Z&81a@i12JIX?AD z(qP$zJ|qIQ#Z+5i`~4Gb$&&@9%LRHz7Zh%UT7TMaSdc0I6Q|HTX*gn`DPKi_akw*v+e1br_QTW3FwaJt z_tP}mmZmj<=r1v)L(g5LUo`eA{Z6MYK56GIf>9>@D7YE7pMS3{&+5n%jDM&#k#oUu zes~}xBBN(66Id6P|MGtJiuqHp%?YgG=pSV|;!a%cuU$J7D}Rq?g&EJnnfOCIt9%g8 z3UA_B;Tq4ih!#ahY>-dsu*s3(_3T%GpEMW(&Gx?%OCJ+vOcAya zttLkc4Q{t=>knb|Fv$3_xguAEL&RiXV8=r>oXEqjvD4KG$ zZm7P=)iAFP)r*!k^qr#x<{-_twK{oMN-rf0xhhN@uIDgJlD9Rpv$1SW3$uu-ZF)z# z+A!mSuO^BB>S%TIjPMOjVAj@bMMI8e>dIal`O9tdn#&VK+WGxkVUb7PQ#b!A+wOxL z^RE!+U%F0?3r3D7&X9SZ=5NXGHodUPpQBoCzd9bGRcX&9_m5r%Ke(eu51l`Ci-+2i5+h`Bao|FS3bQ_b;LXPGXivy5VCdY(b(^(EFngBm%ZPV(ud z8)Ky49S4h&q557+DiCCMLSt!EOz@<&vTeHKc@E2gR$D z#H&muJV@dfQ4;xL|1z`}|FuzO*KnV?n$cr?)MHGCXCl*_36_;fcGdz+fA{o5(|geB zXPg|5co_6cvR%l#0`JZ2XOVY*w)5^X`o9s8Klz;Y_uaQcv|6__LCAIX335f_tOGv$ zf%pqSP_u9L|HB@BKQFu2QKkg$A2O$F@Z*IP}@r>IxiUKYQmx-g~(7 zQ6BfzUE7gpcv={P@l<2|)LGUw!-s3_^z@yB2W$<_cHpPo`s3p(AL8%k0h9KA`Ahrw zOZME7On>~1n>@Y`wk+N8#+KdRd}GTVGjohTd6i%6_UG9P>BvLDJv^DQPdOj_2JbcT z*SltR%Y%H(FC)PGTf*xA1sdbap{dMB*<>5?_pZ^u^tYwIE%B@1UwncZ!T>~n2r+lq zJd*e(in(~OK`1SLa9=b1Oa9r7qx}5L$XM@>5t&&pMQ3EJ+s@$1c^vAW5Ha3$_J9)WspQM^Sg_}6BN-HLy})Tf3d}b%p;8rj&YXRj--O7j zs^-IrtgY`Do6{CQeLv*;#a3^co|bLq_+AJB&RdT?#BV27y37RV^7qK+`K#h@5Wu+WfX*o6_zJFE^T&m!&Wd_qfGGqJxSo$(zj>PGCy!% zAfL)Vots6!gduO)ta`i2<@kOZSy#VrDZa_Rc+=rIrBm04Z6-O0 zVg(p#J4UYuSQi`nmjc4m+L`CIXM54p&?14+A@(lA=+GI{F%?70;K@LKXJ}87d^fGA z77M9^QzI#zO1h1qbLME)?X*V8qnZ3JqX}w+Z8VytFzW^B{7sB$fZ5mC$^RMT?#}Y- zW)I)(ax!F}5rG)*h@4A>ePur;dO(;vU2->rnsdVzawe1o^kZ;F7mZ;qdL2W&Lb+du z#q4vKeTvd5$x8F+6BK^&wAItt!^rz}oGsmzH$=;^%jhEC3+b5bPegX*o&8*&-%EWp z6K_be1i8odp~rq%Gm84lHf>Skyk=yDD4KyJ`GnLK;##B;iT>%jDpVIrb3pw~(%(Y; zEmo(Ea!BWTP?y;cl=o)y^ho61Zg+&5+2s$tTW7O``hG{y`Zv!e-Q6zb z(Peq?1stW7(QlqYo1zNBKz$f|j{3|sDKR1F(L)TDca&wWI(ylRf#V>jy|b@g-jVG4 zU-zV};AK{n;BKqp>$J)wyU3i+E!it-k1srA-cU<7o6ap=BNLst0NX}cuLO`yT+OJ% zW5z9V2o7Qn?DVTma)4xIVU)uu$=O9OGv(N>(uTe-oCOX$CCicSUqt+1Iek&HC$dyf3@C^S5f}Hz_Y~j_aF2rsn;<583;wmX5RvBF!oL~5>F`^a6Zn)q(H8DGBVXt~m2sY#A;qg-^v1o> zePV>!2t7LZyJL^wd;gj4gXcPVh*4%}ks0QEvM2R{{>j;{`jrlG@9naW-fm%&Va9WA zpMTN5i4CiEl(EO(+qb{}{z%-8!BZQ7J?_skh|%Xt+I@?J#-v604?1$6P!* z;&sOUbkJN_XT?t;O*SAt1K!WUlbm_cad&;_;T<>3t@j+UILh6YnTjynsjw|ts!EdETW!6sgl;qhQ-_l%pO8xDz&6&n{ z07+z!AG@addX>Vxl~`0&-`XBSk=O}-#&28~)QH*J88aCeHJR@mq{~pn6@H47rG@M6 zG-3n@DjlrEO;`3|?3~(>y$QS~7}W@$Gd(dJPnmj>4#?2>jo1n?ukk1kitiDM8+sXY z(84e?dqN0}8_m(uTI?0}DPegu#!zrLsdxV$dvDTX%Z{W6{+G9o1?Qo5f}lkMT1nao zLV-@wONmZpC30w}A?Uxi4J4g(_cKJ?xcROcm9Hx9Iey&f9E?UAKkG5dT<^r_woW5@ z787jY?VL3P9d0@Yuj{VGusJ`D{WxNE9$Bf|nMGIat7qBYL%vS#wPZ^l#r*B11pZgB zwjkX@n_>4g?t7-XEV*-)XU|O95$jF7o_ob9!21tc1Y&POd+_`~7)j?2_%& zZJnH7*D`1*=WAR`<60iqa=#|gWJ)!hGG#__AB?f<2=W*~J&k~{oJGh@c5Gvak2xIQ zx3rO|zDugja{N{s=XI#m2E`7_u@ZaIS9}S6eqIUDY!-(k2<_D`$WH1#yU{Bd@ZN4T zNqOB9W2x$j{(MhGebLjGlHD^Y52eWCeB|##qa@h^IhZ!{Nj=Ln+Hj1JCJSM+?>~vF zopEtTFbo)EKmLa@@y*7JHb*Nv$d4o(_XmoiwhB%aOw3p{+=^IAlF zs_0RvMN#Z1?od1XH}IESNABc}ZIAB2{;Q4JOdGdJl>uRB_x$8OvaIE?nY+E;PUDBa zbl(XUA!$ADZ-@TWLVp9sPCse=@P51{qpdOFv#&yGS>NpqDTczR-oIp zq{yI#GLHA#LVrE|#Rz&t)Rw__`w<8RZ57;sw@5P;sTIvWzVR;1kpNNMvqycN9jQZ$ z`ZQe%(=4aL|JPmvCaU=!uKJM~r&*(ypK3>#j`1jHwo<)&+vaat64Tx$S%UUZYj5)U zDUuN0$$Teylk#w}l+}juh8Qyghll8OUR=D(3Bx!WM*Z!UDQTzzhq^r;=ZK4xYz&5sDhHuITh10REVnZP@XA}}$?~y3@I^oOf{muW) zS};GaUU=&8u7+|j>7{s;^c~Z5TeA4kU#jLJ8aE&ri8XYLkL$K|!?*<`J=i&?8`}kn zK;A|&GEjzRBt<-4L7y3j78uWW&gWf10htyMK=_~rMliux+C%d3 zuvN46Uk5f8x6)Esq$P(wKVaU`d92Oo2$cwAyEk|9$-;-@FmqIBkKf~1$|-UhqZ4m+ zW%g1q4|8FTrTlpr?vJ&0?!mon={_SoI#n61G5`0-BPDU_up3GezgLyCpMHP;pkAYAF#u(&f43fq`R+=^f z`H2yrTyR9ycw5`asFUs|Bd_kTbxEl^+C#H(H5@|33gXO0vRBz2qaD(0ui|T7-B_!P zWtu2AkdH%(hp*gPOG!8MkirZ5C6Gd!TcY$GUGX?51)jIkx3& zTy3Ya>Wl3Z0oXqi&o5d$|BRpYW<39C{YBRx4jU)!g!B4$d!?eB-?P0^d3{3xnkb;* ze!Wcra1MWp0@R=Y%@lwVDjY90R*QJ>0uGzFhaA-odhrGg#fxWmWnGF>wdjT( zL;QI`YAN?R3tz{)Rm!MT;0jTqb;_nByCUbU^~|96v%IYMzB9B%T6MHLN%P$# z9xFJCk2S)P>HQ*Sh~ijduP4&(6g_u{Jk7Er*&LCA%R9c5E2q;8A&Cg*zsv7P(cGf%m{U zsWyxR2lYFYl%iEz!l}VHXRK`+c59OQM#V@iw@w6k-_DS-GHF zBuyIso8E7rvTTgn#SdX0v>krVk$TD*CVt}X*2+CvD^33GzE=1>9~_m@2;wakH0pWx z_Via3JUVSz_M}WGg^W!k0%%C$;Fbrv9BLbZ(J>4n;6uwKA(XvyU#`LY**=BoWFQ-? zCHtW6xP8%pzzHYW_pYi((SWK@eQ&!#6N>N_b|beR>hn$I6hcb<3{~Dm*uTX^Op0vX&WUt|qt2gwFyvn+PM zDLCk=#i>p?WS=#NnPitl^z)>@cG}y9X7uo!My@u$xCgw`B$lMxw0e#7~#TJ_#uN!?gAA?#r^{slwp z@tMwEAK<^nilRgQaipSq4hbiR%b>@}`kfs9-m1N;6kvjNft?SUnbirVt=cS0%D5IV zzk3p{giVC%f#HC1YD$(q>dkD$KCT@wS%8ft>nf&0+*p7?D_JeTEz(jo`!7BH#17kj zC;P97vc(@5f7pL@v;WG6_FwKH?nP?Hg(zEWL2D{72vBs#C3HjvRq~ z`qWAc%<5`kWe@JKuB1oA6r1hods0xcNS2~Ht?7~X9KUFvw+IdEueOe0Dfi1 zwEHVNrZvruDP6gCOj*p6~OT8F}M@82*bN_CN&x)C0k?!BY=J@J(lZ z?14C>qk9hoy=C!0nEaz22(t|j#OILb7w?0&4GV7ZJ-Cjdw)h_0)=}y=y=QM2Tg?S` zRAtU>^E32)7z(`yb=ec-3F28DquIy`Fp;Dft&Z z4QlC%!qD4yOpw%m^EIC_#XymoJqIsaT|6btPC>a6E1TlVxx~Jk7NJn_jwGNl?OC7G)Pn&M_Ij)nG)%BG@f3r44K2fS#f6+q_ z0oqT|HfldIuX>J^rp$rNE7;c#t~5P_;}sP~2h;hA<^q=edezt?w#M%;c`)n2Y_{g) zqs$I>JuF8N*~e|e4W99oL!_nM)J=Gyci^iA3mb0dcpUBaOFRza!`QxRI zj)A2i&eA^TkkMLrJ_&C!$+RA0Z_)usDL+2?fq%eRjC#N5FyHfzS^nL-7KD=8jr?0% z4cKp3S(anVy4RoVxC_#{3C9WYX`kb(Q_6V%_*6al98E0`eU7HYfAcx6T=fw@KhArs zU;N!TmHZC(XuU0=O!W0epN2oArhk~<(r)SSTS6zwna8awFIKvVXf=@3a4;2Q#Rj=fMo(T@NO& z`g*!i;mGv+G~zg_c{Aep+jVgcjfuv2(Uu6s#Sr2U+Dw?z zW8@fb&QQbJKuqz`HF>mWPl{+-q#(SUzRNmht>?P6TFj#oN5_Fe*)kmHRGjI-$Vqx< zzu&Zvux&R*1@z4Ej*_NC%euO2&-rtE4O1L(@aoZO<0byKjz$b=)Y0gza0_;A0VQbG z*J#~iGK}po_=^VqqAvU;skHEyn0x)H2(lw;UwVBvBUZ9sggFfE*B_VExdwDYk*jP! z9N6;I7mk)7oVyW?8cB9(2y^lQe}Q&M4~@GU&nes6HKZfFhq88@*h`)_d*|CqQ5IKm5P z>M2wNlMC4Z6Db9b(hSrd;hCCsifZ%8?3hZj=K@c-w8^Y0rj~u8J}ewW{yXc#+8C?J zzEw*JsJZG?V1H@VYMQA19C07)ebimx9tzUZ5sze?+B2=bpF#Z0F8$ehuH0w$u+K@& zeKxoCRk@AtAJ4lrS-Vv8i5%=HVhel!D4$goQweR_E0r>^h)|SZpJCR5EE3JncNCm4Vo24v?G-nK79jGP;&)ZaWJm5NyNo+1`y2Bl@+bquipR|6r+Zn6{*sBcFqux7MQHAqteaJ}j_ zACiar+ztn;+&8_42wc#+6n78Z*>=!Vvjv4D!j`%n>2Dvu{Y(1mKmYx&wfy!^20iuO z8NT+%Km3nB{Oz}Y0&x@hzt?d2uYXH_`}<#i`={UjQ~lfD|MI8b@JjtNT==j5?c=vn z^S>5s=1+hB;~)R`$8Uf9*MDih{Oeyz{mUQz^e^!3fBp9F(;xr%+dql_{n0Yw0!;^Vjc-~aH(0^j)QKa~FoH+}r}x4)!ZfBUEZ1uy#Z-~KyY`s?3wu78EM z{OvD)ukakSSN{Ut6aUl045JIIVpLAnHDwh+TO$9J*6?RTA69fQgjC>N*a$xM<^sWE z|0DgsTm9!h{{=?lsvqOptG8|DWKsEdZ)H%KurOb0*hZ&0@)|Q83+?#Kv0e7m)&7= z>jZ87>)-$O=fD4rU-967a3p6N;cVQpuRx1JZ4xL}C78=S1aFkeIqYE}J8_~nkWPS? zd-)yo_6BLGeF2N6oIDoL3eLm>D>@KHtE)DP9sah@Ad= zh#LO;_^-eHXK3KhzX5?GeJA3soz!_TCu)};AX0Ub7gv%O&qy9t+T;LY-!2s#JKL^7 z!1Gt zho}0`ALhe;xDWpkJ|a-ShXguMA5wov^C9hrbRW`x$nYWKhY}x3ekk>!^oKGZ%6=&K zq5OvmA1Z!m@uB61h9>m~hyvPvX!oK0hYlY)ei-p#ci>}3th1v)_vIc0kh%MhtnS*Y`FO0#Rsr^uRgr~@aDtY4-b9zA3l5p`4QAdFdxBw z1or_OD8R+|5yeN8AJKnA7#R*t{DVaWP)}^Bn~!0G8$jzs-0lef$W0eevvXEh=5fCz z?mhkSuk{~G-T&!7{Ja11A0E>;L(v`K?plk$i8yHl-Y|fl$PB>dI7V>#Meh9AMg~|PHV^GotaZSPH-ni7?fTre6%dYF1=UA)35yMyY)m*zFiRe*{KBTQ53h7|H>dJcd$4c36eX&*n&plG~m1RlsUt!2n*4;A#EsyjgC zxu|w*WxE-~839`(zsaz{oXZXdN~+?3U`1{QV_I1U3F-$!;9^-W{c@xYHjT%L|CT(0 z(lNZ$T#QH<{J`NItt1f9PAg{*_n{GLSuJ6MJc?8}gB4y8cXNZ;DY4JQphpDO?}dyB zs?8V~mzK~BnBbm;DmtX#&!h&75X3c26c&cF71L)ZBJ4~Ny@w}?;2x5LWH#7!dg!xs zP(zR$M5B72^dm~(-`}N%Hcl8HCW16-&|jbi<;sN`!a@z+8-f*+96HTaA zL}a1~U6%In#6Ymg@cYw*-hTm_Ko9*-q6y^&O_(pxg!cYI6BKme;HH9TXwhz=il93p&yL--^v9KtU&;a2k^P(-*;gwOs=5xum0YYhXXFof6t{uJT#FF+B&{Ve$b z<4PWI2dz4H&}!ihA>GRlCrSX$px~qsTW-AJdQOC#Us6KA(sRE8C6I0C_ojr1kcU5m z67*j8hm@cPCFq3`VoGnF6K=CxQj;~}=A4K{y*wvkmA}F{q4!jN0a{3|{w!LE<{>SZ zK?`P~g|vxVS~yFPC#^!>OOUC=ml9;cfW+Tlg47sZ^7~T*R{s7;)Sw3dh_+vl8n$ga zOAS)ZRN*D)6JBFLqr#|Z&@G(0(KP&(Yi#wRf2O#+1Mb-~o?*W`og5|Meos2d;V0>z zx|TZVT> zm-ew(6Y>x7`_qV#zW|NY^wao<3WG+zqMg=yQ}G*pc9S2$@(2bcRjX#x-XpG6b4Jfw*2R6O@K`Mk|r?3 z=9i!ex%~n(A<^ddb7(@ShcvMbn%EYaP?%736RmU7TtMrp7>-VfL{zNHz#BbcL*l>D zVrGZ%SNc#Uz0zEyvhkPDTyhq_0DY+Xv*;ryKO~R*dC5a+l`oQqrZrT8f-T_w{6flT z-~l>EwMZFyNEy0Og~miWrGFVIBimnrIn~Q{%l|&;pLoB2p{FB5``9-n z@yQ-BrU<^eQ&JY$>J8&QamPo7Gk~X~!zA}W1<4WEw?o1OPS@&Bam4y=Mr;|xdJpjSqq()H&p4M>z;68Ts4ZXn&pl!d*C>Jw#yNP(#%93M=9@ZoV z4|IpMiA@I*yq{?VcVNgs(cYNCG}oc6|8{f7i6+{-+v~c~>Np0izU6fC0KaU!SlgMa zp+ThhnoM?qBfSTIqt%%r5b0lWx4YBu^xpLmlUzT~nR0S2?#Z`a%hqdo(8iB*rFcZf z(hSRersxh)y7b@#m^oH4haUCa04OL5X5pV5S`I;0BPFWyCzzj`zS(%@m~!{}(;Pu% z1Ymg15z6;)EQDnEeE;@6zUp87rv6ozKHon|;C$M@u|DyE{pakb1PKmgGMgr^_0>-a z%&WZeQ^K~)_kPMKW)5(Y##RnM?|54pYv2=$G^UVV<(H(f_wy?Fyy*LDWK^vCOCDJj zGUoC)tKy3?S=xt8#=Jrm`dc5Lgo}I;BIbu^wEExiaV}2IIU>wY`uX_qY(z>)X#Yc4 zz?tgW>Z?F4+?S#VHrR#c4bquRaKPzt(%k@*ymR`g{5d&eoOKit@{67r=_tC<);~W! zlX1Oees(eo=XIt`s%o$MQphiz#wn-E$x%1;dCupyyuaYg>3cXc_WSew18ucF@87J? z_4tx$R<=ULW()$!(w<3NNJ9}QzdRt$_#1O8+D*p}uHg5KJaX1DG@X;V;BNRn4q1fx1`Zj&NmGP1`26mPh*EUgJ?GPX z?3Ci=ThVxOQ=3Rnqw!>k@l`aQELi;DE*kG2F4v^selfYG>iGR~jl1=1_0u>mXNkYH zKb|v0VV#352*cq-Nf#=pF~7R0e#?fPfM=O(F+2%0X*1|Iz_Zv#yf z^Z)cIMqAktXA1`q$5V|cs(ht^J=Rw-+H$8Xu-`pKTgURVJrM-K{G0|9*6jH?G!Qqx zN{z_<;OWw+!JgK-mz}}Fdd@9=$-B%9;N0fbS}Q?NzQ4d)`=9MupghSJYb~|-S!-?c zX|1h8fQ=NBowe4$vM=>4G$_?3fsu6Pnhm|_tR#&Y{*=eq;FF@&B?+sZEV%9c@Eny3 zx%UM4)e{gv2FCU>$jUz?f9?N2)KH^23KB-rDM;5~zJ3~&A z@Y5dQQmJ?+LR3HKzdFhKJPQun1lAO39?{DRAsoC{Bh-rH+!sM7jsb&MoB*IiswUj+MQ&N?n z8E5T59FxWwt>LioAbe21a-D31N6Z!qN0*o_UgsneXhSjPT*H>P5=yWc?I9^$W4Jot z_?|1ArnT6JE{#;Q%f*Z2LImDXqEb8P$yJzGH*a+Ez)NF|1q;CytS~XfJ3!y?@4+WW zw1dK;8!V#^Sz6vvJgpPop%ELqlJB~XYkG?*Cn4IZ_4k5c(AKTJ59Iv9cbTIQ04V!y z_1YDX6+~OV4!<5f$`(3n5G{?vLm8JS!YtWZYRI~ZeamI55o;O90zLN?@7Y42LJ4Y` zjY6LMR62xyTMEmW-dRjq+)9trV=VxSsEG#NuEQp{ z?AfAAftnTRU)?-^u5z(af?uC`f!G&bFc(O8e&0cV@NTAR@0q5ZqVg4X{(Qs~w%y>o zC{=831A26Z`4_dRI~Rz{h$1lB+bG8|J5*fG9WxVSFHO;9#~%0SsJFmn<;g;!SQlGb zR7Z<}qa)$j>bNL`fup>S@967p*lXYhuzAy8LyrZ6U%igqr(h?V3(MT%GpHf1vx?oM zHypEz*Xmt=Xk~&fGac|r!RH*8fx&yQtitD39-nfFduQ^|J1&zmu2Jj0;FZnX^)9q1 z^yY_Peee`rF;PyNv6))F=9Mv>Rwz69Ij#5|_J7?1@@D7==;v7~3v;~5l!aHyT8!AWc;q`- zVU#KRq$FrKj?k&nX*FZxKr^jHDpI`CT6E@iHEBd%^PIKSq_qSwb4x<|FR!J$T}w08 zG9ujZN{18uwRu!AH;KA%oCIFkkKV8RC5^a2TxGnss<9%i1u>$i!=M3`8x4S9InhAe z>%%!qqFm>!mjk}e*@z;U{J^LAvbXc4$9yHjIBCvK^JVjeK9g%9NG@sS5G~PB@rhJVq#wLzz5|)xW)fqiun^`5YD5(e2hDrfJ#^<+1MK9 z`5Dq&s+auGRtktIr)h24^)=Lfj^ccf|MPklJe6n_)Q1d8lcu6vQ_FB-ExhHC_j>HW z&IdMYFMNQbfN!}aA<}NANES(jR5yxuRbA32ywN46AaW$@PFV%B_Z6;2M2T@+Y6C68 z3V6tM9mqO~zwH6<*S(zDF%R2*JHri+5dMo^Fl9JV7MegmHW!?4ea@{VKj@lmoTF5D z)7fITeWsz&=SdD}yK|C&v1r<(Q%N+s#&w2S(so`4dD>N3yRXty^(-+>@^7{%|2lV^ zKtarl+DfEZHO{+nJA#n1G4fPyFgSEAZ|#(Z?cD?zqn73^knTkDPNh%Oa zh1#^Em}bHM!8})6xR@HBXE?JY)v}h2qirL&dS%E@H_i7!xfEkheda!NA0e;unB`%& ziQO6?+eo7f|pY5iuaeRW^h}xQV-YH~S`APKU=f_p5h)F{#FVb$WXE zdwKtk>u$QP`t?zctVQ_|HMRa9Hd@(#OVe-e^jn^O>m%o1YL5Y=nWv(VSdzERKkfs{ z%V@Ks%wczC&5q}Yd}z~s=I~q-*O>k66L(6xd>A#L%YkLJ&+&P%@yjZyEBDB<$Q(vf z77g`;3xm#9;ii|s>*FI#09-($zunyUnS-gKY7ej-9mZ!+IqU5bouRQ3#Nca>vJJHK z`bSaG^0e!JAVLFyH-7hsEUm;(!e`goyV*lC%ZW=yHxLTv93Eb@k=eOwEO(VEn(vx*j!?Q=>JmUw&&;SCcy0e3X5}8ZzYPFlyY8YhSsW=Ykn;O+# zNCMZOy!UgI%5L(>plX_BEqoiDh)P#rBy{JazL?tjqILRgUwmb0oB9AhHNU}-s4ull zI5wN@O}0g|(|QP+X;mi6CGIrR_*dPj??AiL6Kc|mo{qDqK2EIC_{MVm)6!x zFXX1?c^HM1@A_ec>;2f(`}0lj5qqBB!7Q^dc;lI++DwroNxf32gZg72_ZqT|dKk~5q9OIDI28kDoLao3q#ImaTZ z!)CaX6-k>^@h^H+Th9V(exYlGk?k*yV|t^H-9YC%S_xFQjC5I`-xr%aKr(=eewKE- zZp3BmLyVX)f!2B&wYV+Y-Z(4yJdZ-ZEdqnex5Js}Xs(c<&`!aT+Hqp%p+TVLBJ3*1 zU-W*~H6&T7miY{XL&9=wG?VP8W=%m`v_#BraFeD$5+WDdwkHbk(0|HnRyA*9{b@{* z?#9YfA-1(gOQLJihAp_F7Hx6bVnogG!`mSR+Or&+yH+S!pK4d!SzhH)_R*mPNm9=- z?&jCIEtbuG{?H}nen%aVF)$u8taW1aN7D&7<%+C5CrMJaNCX|sp=||<1d0P=CDNU^ zvzm@6ng;6#y@d2UI+vWL{Z855@J;dVp>t`Sr7F&I6jisJupW(CAXEReE8MJ4_Z0Rj_q|H5a^-v;lo+W2CbUy#s%lI3Z^Q4a)>m7TQ<)uk_ijyNk=r5353M zR8aVP-?w>+lxTJ(W7VR0&o+%t5q{|2P0t_>h$sm*8a`EH%kX6DjrM(}j+MgMX=8cB zfxK}yE2YGKjl9*ljM|hSfNIINlc9j7Q?_eZTccp=cXoL$j%{ zY@tf2tEFH2?PPyEe0WKm&p`f+)F~#*2-!#X?!}306W$J6E>a;|r*KZt(%Y@L{q9{I z7IV7W&Ufp&+>OV^@C;w>-lSXaR+InZa(9Y)y<7WJ+jGBT_3PcHKDj$od3P>yadI=A ziFU{H@cuq^y>GldlqYXTtNhZ}H2I$|^Wf8IWZU*+j=c=ePkeKG;tyFY)a`|ghWVQF zFAm zNrRNH2CJo4+4(DyyAn*PnyuQtiFW+(cU8aHK*xQ4k0As#*O zZ>dorto|7H1Y z{7)J_6~|m=vGTucUhqF@Sn9a%bvXE6cHhVUkVP%Mwj8m_JwQF3&un=-e@; zElFpqm3 z%h79Jzpd9nnzh$nuD#ymi(Y%bJ?=H<@^P=Z2H3as+KX-Nbr{_kQ}plm^xEuc?R8LVuk#E4qcH9NT(sj8OoDO1*7hZp)Ch3P!(bumY; zH~Ve9mL;scP8@f>YcrPOe@1PIZ$tKO^uP;)K2K_SUK7W@3q60 z;MPv;?GP#sw-euM$LXmZ-`nBLO=`!#*ADBc+zzHpay#3YAF1AJC(ZMddpq@*pZs1s zd72+7T079h=#O}>oxMeOAWgI=UWHtSvLsupdgoRHav$E+hES?oQE{~8s>xjWLGv%ol4yTyt@8@@!o{@xndn0yAmV1d8Mx7*;}r18qpU$ zJ~mJ+Oi=f4hLb`cSHqMOoTkrt$rWDvj6PP37J;o57@ubJ@75=$)!8T4eYhNT(%UiO zpd9*Lt-rgwc>ocS=YchxHl~|7z|Us->@F*Dw3+mr%iLz~rp>!&vz#-HnPM>(8gtto z)5HC$OjKed#~B8PQtj!Td%2-)*|G32P6v0Ort{i($+7h#ujka7S8Aqb?2kJ}Kj)Fl zTY6UKp2o%pD2u;k33LxX@tKwtfH^}WRz-AwKg9#Nj`fBJu@vWW^3=n@0P~IcuRv~s z&oi7g?U;syAbi0d|H#>Tm`z2IFERtKBAaap0jCD#o6UNIPE%Zux5Q?W)BLaUeFjiWLOus;^4h%5O`t^+Balu@)s=jWY37kWXdafSu!2L{Q|b z!01#CJ73-Uy%ieGirWpk^+E3*`25Zz_M73WMpPSW<^IC9ZCA4`Aqj35JtlP3iXBZT zlCR>3=&DUQ1)u0Du#0we522l#l|yy{$uDJCA9LR}EAdI6#`^qQ}R)1gY1EhX=3L@Yh^*Sm=UfYh za`IKtW~XG>SUGdgwylk#D$K3(lCP@P-)f87c0$0G2yfD^rkX&<<9lOm_wHCH%o&<> z*u>B-Tua_5SBOT0B>AW9PR)1O9xspH2F{U?>i9*qTsXwBrubmuU+DQm{(^DTJy+q} zCUV5P7AY44NKLpN-A3b8zNQ>l<=D;97o19uRBM;*0;| zn8+hDV2(olRvLEObSkJ8f6th8 z(1>ZMhEv9twtQ+7Q+umbN9-5V=dP}M4v`h zKD2?D7cSZ6G1Boqw;uk|T)4tf@S#UB0;|S8qa~_mxWeh-@wah}?nB(5{+{>%m51@q z8MWsI3zBDYMyH{3l;7#}IKPki(+=manDJI>!S-D7=nj;ho*m!t)#ZVrh57L#EB?5; zjjI$l>UXh=ANpTw&D_4j-uB1cUF|rm0^Kbghjmbh8L@x+RMj}N_&Y_>g*^*gspXqq zzM18lUB0=wzQw>4mMBY5kMy}mapbcPJfXfOsb}s<>M3EaPm{488o9(aeRI8?O4W{jym@ee)tN92kD4H3f~h!|)!M*ecz_m;6CP=e^K zv3?1Eu=aYA16hY=3eOX(OTa9>qGj)8ETN8y-5@r$?6{+kZb2x&L53i-x&;#=6zo4* z2I#jmFmEY7*uzm*lS{xBe`xQ%jUr+C=(fzIe$K;kJmj9?R3Ai;W3`ibr;nWZj$gFujqJM$SYmRW*tLn5niKD zOi&GXuPR2r(~3CCrZB6-lifw)={f4HS4(~+@P}NlS)eRwQr^l^i?VBI z`IccIc(?p3n>Wv=%O!id)my<+!!Q-;OXjpa-@`f6b;+5=ac@0CS|UUx&lASHTOqsu zN5+9GkMep3)jESR|K%|^+t-XVO}jgg1<1@?k>);(dLM%O>B;{(^chWiBcRvYV%9Ba zeLe1z%%AX^D~BBoW7N5Fa+I7ajqamJ`yep=2iH(!@ITpGpt-@CmsXtKBIdW8JxxG& z!&@donPX1cC=X8)+$+e_geGh~=csmnk_dU?>XfZRcej{_g(vhK#?k}GJ0v^fj@BIm zVe*pk%m77_o`jMxw3n|urp_p_Ckr-kp7_}E`8XQ^o=V55L9P0!Rm@tyYx%x+-a!$!5tAii%I~Zhon0y{kq4k}?uW#7JL{J$h}yCsW;-!o{hT$xPz5}e z$h!^T4ZUBAq#|(CqV`?^6|Dd`kDQ-~cOYT0lq3;JNO6FEkk zORGSW)Pnn^xuwRJk{`8bK(^GXfXZB8Lp4Q3b481?SR^zS^;9?11iHS=y8X#dj5 zpFr5z9pZ;0cDPj){_f7BWx)zVPkYg5=lyez-*c|-e5#PtP@+C{&JAnFCJQ4WiVY~o zFC4OS1YD7aoT70*#@@Z9*Z1hp(0iE8>8!S z>)0YRU*Q&8eAwLyZK~x2D@KMQp0aV=&|CI3qwTTV4Mm#KIk=%cN^HBPzlpF>={_Y^ z+ZptF+hoJFcrZ4W+U(Fw=RNX1FQIew2`_oUiSiFTEk$-PAGY*dyQ^jM6Fn(k?TL(3 zHyS}oCaIcEnY@)_U8WO4EY+7p$EDU*epiU>J4GHnOOo*{cca@*lG z#S@Hb81sHEf+{H@9if(Y(8}a*QmqC9ytCN%DMDtNi=ypiE{f4_%|$*qfWU-#l_YAT zrDovo@S0jYLOfPDKsIEfrNC_kmQSP|ju53wF(84Gx_6zy61Is8F(+W#*(OBSiB3CvCvbiUH$SK+6@a74;nc?C;x#yl*&p$`K5`IdDjr)5M+nc?- z>Uy!4!&T$XR`1Z!Yy`!qhlVnKNDh-O+wcoIhi`EvQtXV1$W{=nTZezCJs_FM27aDH z#GB<>M8o>6yRLt-Ycv#4L#?Kb(G|w8Ez+aWP2INO?niO%c_{<&Q;W8a*g{FO)#PZo z`iHh0wc2tH?=xj61hS#18K<~oFRqr5%edib73nWp0Be`}y3K-Z^T+tf_P1*~V^1^S z?(A8x9noWJ*v>#F^d5J#9Ev^cVe36?b2B{gVt0(GKJ8ATfTviO>eXnu{Rb9~n_cKG zm8PCbeWU+p3&#nC>qqPxeYe;i_6)-7b0^z}x!5(_#rAPRjdNy3zaZ4O2NsZZ_8v>jsFXaB zm{CgG_c-Ohx4jF8s(o9Bj&pXAv2!*(FoAH=jb|;kX1(6M?@x5z>OOf2>HW(R6Utf= zfz{4Z0xBzSNeShU5?nEu*x)x%0AXW<>MSVcDPo;ijO7LTjHP%uWyM|<2nJaI>582K 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%0APfe8nzd71Qk|Pidr?8T3iOCP9 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 z%0A+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­O0X%x&AJST;_x75P(ttxb1io52>(w7m_U_*pY+aQZ9o;+Ft#sDU6Rv4n zJJ)El2~%3MM?bc%UA(U+_s;Z~KH56hMmZU57u{cU)?*GP1wW$4R*)71Dj01Sy*~^k z1k(*H6s9vuD7DbQDE9{7=O&wy8tzy*hN*X1k z+E>M#)9sQ=lbBML#CTHdWvd_49CPwR$JFde z;?d(W!*)e?ho8p6CFMn3tTV&#JM2ju_V6f4U_oPib})PxG{)sc89-y4q#iWJKR)X)eMHygaRIG5pamY{9uu8$nbri0W+$gNq?YdE07?#i5$lpMrX$CWtJ<$quRv?e( z$K?j!@M_e|THrXt?&V^E&W{$_S!#>|=Ft}4oRQi6l}W;G?~k{aU!W{#`aU;jFB^{L zx{2>^c7*kPGI#e%-2gUQ#e&OVK5lfo zaM;hVHb#TdaGZycoQ@uTKud zP51(b{x(~h{@Zav+{TEaH4cZ9<;8fKiIc^Ut(6UTSKK6O-=hU5dK@u69t(j1(N+_% z4Dii;aa9j>=w2bKqnZVdS5ih2o}hTW0nawV}g;tJeIGC%dSJtqAP@ z5+y^!lUAUtsQCll$B=4f=KVymNbyUg29IvmdT>+=DZQim_PzWsfBVTR+G!`-bwXIr zb`&cGU8$DU&->MdGJecNBa-w64$0Ax1@%?9bTnUORk}=eDkk#}cVml%=otKIRcY$K z0bYKIMs&uXSJ-yOSKr)skkZQ>q3B7qL_D#2k!LyW!tg*07X>I_OAzBGwlzAMVdP*0`R z=-td0;;EfcbGiMG5{eA8URy9ii`~=sN{QK)!;tQF|8(XXw>_K7PQT*C%|ZV(=-Z)7 z)VTR%avfg^aM|~Vlgi^e!w`U)uw4#^7YN;Fpi6Z3zi#z^ri>9E)$e|FiTQ1AvRy{c zBq&J+=}gWo^o)#IQ*n-b1pktLD++`+`x^kcT_FpWY&ODbCl3og~s zvYE+F?+BH$6QrgDxeRmq4rb`s?;R_36YFyXPzYv{1=LbNro1{UmXW6XZ{^Htm${aQ zZaNpi#hxN#!F9*ln zYqL2O9}agL_ITZX+x*IAbBrHX{Av zo*u)@FuWp;QT!}*Y!Xm!>&qwXk%N&pA*QkM?oEM`VJqPKdjIxtA@I&$UGE=7 z4g*zF`6W|+Vl0&O9^1TpsdsLdp6=8NEIYxKZGbtMH^|W#WnfE{(9sKA3UtC*F!08W z3L5L*9W!<6&Ge~)VO?ZTHAY&f=;5zR%nQIWtGx++eJ9e5i45?{&nLRnQ$#hJnqn*u zS#@ULZKE14q4@-HfdM_O zg%DG_2e5`emMq76z}_*R2I zGIzr0kGGGa@=RuUdgF43R3Cl$DDriYUg5CXJe_GWNn|NA*<1SeHQwAlKz*C~y=3VS zpq`KeVU;$+)40ZGM{fzV#sk#5za!pmw5s15yfr-QEt%%=K)T^bD{3LQVRX$$*$OO^ zLxNYv(C`Xj+OR7V_i&{kP=E0_%OS;C* zP_1bB>?lc$idreO@flyH{avR>!(5T-X7}*)PD#>L1^JvDmW%UJLlTLFJCS??O25I< zgT5tsTE6&1#Sw?G3B#vn7fh$gdbrGALK%`amW^#WTMD;Lp6ywyYuGg≷e; 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

eeSC$ka%xG6r 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

n%JtwH4T!v(522>eG9X=r;xgw7O+K{Hh8 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� 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
    )AGO?R&J*}VQRM^G677@l*4@;w|2 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�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 $~eQi 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

    3At(?8SJ4X)ngBs`|(A2BZFIyg}k0 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

    v4aEeexv3L7y@lK-=W_t3Hr*EY>&)tGiXDNiM-d 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�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%0D>j0b>%EGV7oln8sb&%jomqqK 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�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⋘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%0ABELSkNQ6bLvinde z&?AjhGK+vXj#Ey9vvF5av(dEC<9t$;3LQ7`XqAz^^qwxgk%d@d^%5*|42M`I!?56H;y%0iu8 z3<;Q5cV4!)qALa4nbu1h%U32pu%aNBy-*{r3O){ut=C5fSkAz2 zqLquL`|}L|ZQIYlwB%IZ+1e1PTT`1k_#avaKn?|eyiBSi4DDUtcAr*vPcD0H(ws#gEoLKu>eJ$Ls<|xtC_>x}q2yLJ$=IPkP z_kMW!EF*a%>|r%?ep=YO<{QUjqlPbWsr;I#&e2cLed`bKz74Muo*3T2xq%c5NMn!Fa1{TBP-sg9t;Q=MRTRr(@{K96c2 znKX&UM;EC=aPcJEDb7=4LskUKJ-F(@MXo=%NWuTXMP8M@L&$}D1~$jrT6n&~D^nTA z*`5=$@Em4Y@~VjQeRG+oK2$Gs3>+Que?^jlsC4CuEV!3?D3BF|lkQH$>0L*zIAmVJ zCCVhTmXhfWFX_NM26~#5=KD8kX@NE(A5dqJMDC!GAq*|{%$Ek8L8=05nyG~1aVObu z;lTzHDA8IYc(%^5-nAvYP`CkVLo~*g)ChY0=1-a68Dj+HTcTyt3z^{xiph)|MWz}W zbBxQV(nJPKL`{qps$v--gzwKa+imt`^^j0H%)l#oKhQSC3e9q(8z{#jRi_t;opYn< zE6Wxe#S3?VYXjBk$7_QO#q)=215^Fvnr*tJcv|0BWjN`!YLUY|rF^}Yo~+`X2wkm} zIy7_K*)~EAabHKm!jbPRPZkC5R+8E8529}U)-r;`zu#K&2FCwbePi_5n_y-$WYGsD z2c_As9rqM|7ycIh489+J9v?fmcVkG|8D?@IC zGhuHptTzQw+gj*REgh`{xoSuW=P*z$kPt3>yc1hnG+OR&LNlSj|J#(q)rL?11b|5{5Amg#kLIsl9lWXP5@fnv2o{R{0ixu#O?vI(9pk>LN`N*G% z@9Gy->$e1sJY;>i=ExW57)9ubew9j7lO7Q*Mjp%+6y>eS1gbKTz@f_w8A7jnlU1&I zB(Bg|-HgzQknuGV{5nEy^;?LOGta{2F6p4dleT+hc2i)bIFcfU|9pCyg7-(%?rubq zMp?OOsukY!^cn0KDen)Q^x1bM=-+sle8^JM5Zm{MwLSZ z-21W=L`9tc958&0{8`_g6y>WSTsl2JHGH2SmB@OltVq@L_Vr+&*pK5ugLwk$Zbb!u z=T8}(bY(|F_R;J!>%oPJ={80oV}_UHsP~c{-r?#%EHZtSk>-&I0R>K-m<0V;}@-|2|xE9p>I*% zi&0jSk*Aw{dAz@TS=>Wff61`)hDkZHZ%b(v%u94`Es@c>^!&`vtICae(q1!U!(J($ zoSPS8BVK8_z220Yqx|LAG2)^-#Q62^`B%HoH;DjWGX|;mJKh|hpml&;dXJBaPzh<| zYY(~f+aFNI3#b}DHJo$a((yO>KZ?DKpg+0vkZe)|339VI<1Exufy^P5k>As=2eHQ$ zlZSe26F;$UmK%u|gRA{@s${yc8h7tRc|DpHCDcHbkVvo?yg-~lZB`^cO27AC26#eXIM1`&T@x_+X9rzVMG?@bpP!V>VfQaKd<>G*}D~bBKEIj4-BNm zFYx~%dw9R&P`TFX%+IU}q7!{0i)IzilM4i(Cm2n@)UTl8j7kT%a^L07x8LAhdvbx>3>)00O;~Jbd?n{I4!3)`Bm8){hHVLA;nymR}#=C3ReFpI*& zFMYf_|A|j@qR{KN&gVoS3tUYZ4E5?b(BC&(54Kx5(b*->)uTyY7{>m?>|MyK4EMM$ zigXtVZK;PAxGK_ARW_Hgf9X$=u{^qHSvR^K8l)+lv%Z6g;B%=|yq7%R4XJOP|9VC- z^|2k@;BRP8BX2+z&1FZl-LT?9q&sW;Y*44MCzFzsY}$^1|kjO#@cTaf)y%@@c~sbq0>jBy20+6Ug=~P_Y5JW^8Eizd&P}3$xz%03u5hK$)QN`B zi}3@NyjCZql}w)_)o~r{4v81V`PaZ7jz+CcK$e%1lA?A!7|8N+ddTuxdC2l|;s>(4 zR?gNX|68?J^=#$6(61{n!^@4W(%?x0M?|VsrJ9;Z^l|Qk_sEBu7P7;1f&JLN?b)9& zNY$2ViGhl^?J>ykLHS^i{AYT*`59*%Q@i8|qVWVRWf*}B;umDe776-i9jf1m0k!w8 z8RLQsbr8dPw4l2k8@B{L+uWQO#_u=U8>)IUT#r?W{H1x#OtCU}cZo2(FJz}EC!*H+ z6avV-p+kvvk?y%m3C`}h8jHxj5MaIw0KWcY5SQ(WYRNTJYIs{}$Vzl|S=j(@ayeW` zrZ7t-{^ZBA@B|YcTG;)ojP7f_`lswTu{zmf>e8}n=PHMZPN(Y7hy9B z5%kPbeb^TvPd<2whPKr6II8Mx{xhnAiT*vRlAo1>K7&QM>oGc<5Wx_#^;+LI?sVSm zkAl94T7A30_M7eb+mY;T3Gij#oIbKWP!ruRC-AT)caT_+1>ZiIGxfRG!>kId+imnP zs|r3R^>k#o{LS{nAK4yD-vA#D5M|%>I^GM-osEwC1UBZj zULnthq9>sWg%v9yYViD}4{8sVYq6J59k>An)d*wPVc>x?xFKoy7DU-te(d%WF|U*b zZFEul8rC@#+B@Vd|5uyh$Fhw4a|Z54m$m#v4vqXp=?n6)tjg92W-WaWfbA^@ec8JB z2iqHLGB55M^(_`LsIyov|IPM>Aa{^)nJCdh5>y!(uNNQwJD+1^3NWP-pr z^~4MFS&!|i`+{11Jobg?h>xe9j=%;773%_m=|Ecy6 z`_H?cScKWlxObeGJL;W-)=c|E&3^5L>dX*bRq>WtIKn!+`cRmKrR+5#{7vnlA(1!S zSDd}Hz0+J;yja{D8BE4!9rP4;F~mcG*n*Yl4xUA*tQ*F|cyPpcc@PigIQKOVxlQ&S z2RqRXx|!eoF#Qbkv2DLN*_8)(eZxy2`o&eQGlP^g%2%0T@e{hTAyJgHor4*}p`ruA z)AXUi_a2tun_I?X4Y|Re9ZD+)QAJQuTZ=}c1m#(X9XkWhPYrq8P}%uKn+%fkM;)zi z`WJ#W_uOI<7PzOk_D4Chnb!o)m$IAuw<6;(;+WWhHL!R*+UU2vJUPHSN(1S>{6T!Y ze*|KRLFr!EfIp>T zv+m3)vM3BX`N$(^`v~_oHa1lv{l#%h9VQ?LB;_II@7q3XxWSQo zw(*wVd5KfS7qto8IgH#7Y5xkD_V7sdHoeL<9Aop}pe@npleMxVs&aYuiF4MjWlwcN ziJrf^vpxE9NuA(2o^BUnsI6;vT>xqu08Q#&a}$l)_2FcGg`n)!d)a86mP_tHEUxV5~QH>}2v28-c_rz(yl zd>l}}-J^Q2dqqY_xAGFF@t^0`;yFxPJ@nmO){5fy0lOFYX!nSSHm|=MNUH8v z*E&_4o!K*LYFrrbxaDP`N|f!2A-zUwzz6q|;VygGx*pI4kazc*_)3xBIMUDZ_E zF;m10udkk0D^0DVUxc8&oPa_afW}`VZ5E5qfLdxOy-Hy;DC~$n-`YN z7?!|Mw83i4jiqB{s923--AK|Q94J=$AOhC`pnLh}8%O0@xgeOo=$^zQ-D}v77yKr} z8{$2^V-)7P${P}qL}93y-IIs}=WB7jvv=P$D534@kUBptO8b`S%c94%Upk(x-&WG8 z5C6@NDV4CiEkpsUu`zF=B=!zjeq$0z_ZMV@=i2u^P1$JZjul4ngc$})R-Vvojb_LEK#UI#nlNObGM*H@@U!EjDUn>a_032U6QNg1j2qV?Vc~X zvSu5M`@iG8gWq@$^&faIsqZ)5%l?h`LLcxR+9TfM{R{7n{l*(t zc$JIP(PP%Lc5Kr*k)tumdH1VlL7)Vlr18S;Q&N=$Y0IdplW-*mlCaAD(+jRMm1Jt| zoBq|k)0;b&+35}^Jwwrpi^EydLHBqE;?d{*r`0u;=G7+&hTOzpBEfy!Q;YTNk3X6& zt*i_koeU>(wLy#EgQ~Fb_<~4SwVNk>1^(v~!g;?4CcJ9R>A7@Vzg!wFHOULacKU!$ zE|igR3+vUYq&vz$iG8eBJC^B!rS9KXhD*kc1&SW^p1|Mr9-roPLtWe5_uD{L)h2_t z>gNu_wbicYYHJ+U3@0b?1cRKW9UdZ~<)M6n$pZZMNBq{MXhk|c(<>fE8|KAqf<#iZ zl)A#%RJ4_w^%^Z#Qznb1qI-H}(5d7S?%?`W@3gGxw58 z>*mP5^AV|KDk;mG*urSe)Ej9xiVO#0BEF+dvxWhPJB=DcdH)Qk+++XCJpSR;i;wwp zeXc`W8mPOe<*whgqD6m=+?;9_JvT&~*Mw&5;r#AwyHTACu1cuTTBE`-0Yl~`s@Hg` z8jFn;*Nh?HJ#T!Y^=N~@El?7e{LJHf(=W*R3~Lh{5o!LFdp_-t@O`)DjBpjuF8%nd zY|op4_x>^B1AucDHYU^#|#Yq0nAf9$Ps9J$inMEdG_B?+!o zJMs>qfLJAU?G7s*`QE(ax+?py^ysX;v1YS#)${4=RkQ6<%%>};A*WOiey{Su?+Fx*?!AuNV-=WD zEwR2=nFGaKB(KdI4rydTsDcP~!uME>%tIGn9xSGS>xFV4*@J4c);FlX>iiO$9PL6Z zsvT_IcDNgN@UvGwWt&Eclbw?fFPpU_oSdME3Y)v*ki@*yD)wk|XuY`=NuKtMg@_<1 zE`$bdNk2_!yvxY*IL=5`b*L_=w|MVS5O#9l`i^@VN5eZ@Ks^`D9Dl?%7+sRMwGgy8 z7l)y}+;4sE>Ir7%ZC<^ZEfTLD0E5wP$|VbM?H6Sxqi)5jid9G!3~A<-M4~^$>H1ub zS`94r(+ZHc#P1~SdGed^1;5<17S~(3Wt`dK+}^=@naN7|j)a-?mWVaAkthvrESl$Q z2!diqFdbDA{|T=9(L7k1=Cu6jS+a&VG|$w)C)+N|)27wBL`bZg>nP{-iEcs>-l$vu ze*0#zgG%yumOvNNkdOJbjcgay`A6eTyERyi8#t!>2LpqTg0J5B4DEb{;h%!fkP~K`(C3kht)0xw}s(*JmaH`a!?eVXI zuTISdw=;3PAzR3Uum(nW9(79S7R}sHMH|w zqHL%L@>(&qFq91Ij$^A|P<^)A#!zNXpv$HrWw3LbR!W~axaPjL?^29^k- zPiI_WIb{xm{&HP_G36KbCKM=m8a8zsK zd%IR%m;avdDUCyJNUTvIb#xdS)sh@65*??(!Q3?`c!M=pvj$%`ZoY*hb=OjVeIq#s z0-@eIg~r2u*Z)F+B$y$T+v-%+IpU!#5Snd5iQ5PmzO+jD(0?<0KWsUYodCnP*_Jb; zal1e$;f&5bpN_?-vlgEjXCHUwUmA5=p~l!!?YO8Fcv>Givq4p}t7gJZ7N%hJHCDzi zD!`MDo;x1X_9Hs4)cUk;8ZC1v^`~^5Av3bDG6PRd^*pn~?Qf}vIr95&BNNBzHbXi+ zWBZH|oi76!<^#`&vi=x8>PN#TGy9Xt??){@(bV$+b`cl_!yOy5_a}*+y^b!s6Wsq4 ze1PS~q7(`?0JvDMLkT zz(S1bmI!?9(N)yG$4E2fiALRI2JQGXm|bpkiBQ*edZ+GqFq$$QB}fDIz`138t>vwF zQPiQp+RjI`*EDi?<^JQ_is#D0e7?3&!#_V*c3U!511B~z4f_*Cq zt0SJ8f`b1i6#^!MrLDuvYje8b(BZaLS)rO(E^Fmy!Q-u2%t->_u+ zXZoYM4ZJ7{Gr;mCgG%nB6)YD%+uh=^IVEnlA(Z`0Ypx!tKpDSQ|0osnG?7jQFBTIS zm!RZff39Tgw!4b0>h^J~T5d5Rg_f0y!ff?_l%AJ{z^J|eJh%A1JC>&(|! z{3;cG@4I(oS8=$@p1yN`F$`D2+F2|g zZI-s#;p^xGX(GLc>pqj3n5kAo$NWUvYZ7J>n0rtr_SJQ`Q2#y@e9!IW(RxclBv8j7 z3?)n|N8}heLa+b9>?CK&9TDEuFNROSe}X0sUxSQdkN1fcH_SOV{OZ|Nbe=W4P9cxt zSFjjRghr8*V|#)h!Kfn2dU>5bi1xUKy67blu7vZrhAMLll-B;Hg13Y6f}gCLG?6H$kpy z-grwrBWCfd0QPyRNt=Le9+Pxy-Sco7pXwDfhM|CqlP~^kX@6UsW_qE$xBMY@cp?sZ zLMavF0Qn6%j|@`MYrC|eK+^%OR4iX9LZIP~ARRz?8uva@ZvK>Z%RLZBdt)q~Bcv57 zyJcW$X(&+ln9*(-YyH9XE%-E9I?H6bO{l-*%G(7?{NJXW4zuDTN3N?iC) zVVPK*Ki*z){S141%{4~izrHf$L0E@nfysDaooS01VXIXEI+aYg z>RUM)7(_2K>`T`l)ocxrXaaE)~SKhSB-D0C$0{P5|^_ zSh2WbO#b@>)fICAaXQ8POPVun0{`Q}Uw%DMh2Zdo{}#m?@obA9)r`XEi-QOK4Ewq9g#SUHC@5_TzK5d+-$+ky*rp+65rSuV)9py zs*;+N6%1k2#0Pc>`z*OWqOkzAiS`Ru-|3C$_^+Ib1&98c&yLA?QLQNCl-4}wXO70Lo)5q3Bx45=vDiXP*TT}7ql0$69?%ZBJ)tK?Ob;^_e*xb zF|Pk&`sxLX%(gtz`R!asY?NvoU1i}vVwj2*deQs3(1kJ-;aSPG&}k~FmZtiq<#iJ~ z<7aHMmMDiaz>5xQVNv&-XJ|EapJ%j8k}NEg05>-F#4Uk5!bR{qaQ_?2QYxaSc)I)V zYb(W*V0B?8<1~k7PoWENOjtM!aR1tGavk}--*n0a>^E&$1N%+HhQNLk{{XPx1UNrn zzlnd~VZVt#G@}#a-}jr8Votf5eD1eI@SG4m&-wPBRVdk^zdX|Vllrb{lkLXH=S8JR z%kWI}U=G*a){-)Y{Ak3Ecnq<{C`dY}5lOm7%?4!H)w`&-}34 zq!LUp5pgJT@tv`LxK7e3efS7>!6+W!dc&+8(oX46H*cNDe}(vP;-B(9wXDcnlyORr zp0NBC;_>xgNgp#n`Y6m_;^u#ss`@5nWIm1`#F7^`78R!As`lY{>4Qy&i#asr4omVW z^FjMLg<2eL7t#b++t^09EfhSo&HXzZ{_O@cOHpeS^e5X~d82mS!)A!W2PcyAUONQk zc+FF7@wF&^Ow7gZbX}+~;NJN>xKTp8z?x>=Gxd9|4_!yT7=q8AE3Q8CdL8q#c>Bs% zS4_EKFhE>w{;Bgsf5-xLe+$;T_x^Hea(J(H-Y^zP80iX(Aw8YFQmFc~2c_yfKTTtn zTk^OEMSqsQ;Gj9Nug>JJ4fo>ouFlmqYTkSE3B4(sq#2s%+E;q;5k8O*pDXlal&mWJ zsBtTa_>5s^LfOz*(n!97hvh?sz@+TdXHgNqkoq`CpLFTTY#d4w~fM{|}{%_H@A+^#*@YM>GRfvXL6%)soiteq6!$MUieR;-IpVe*{->%QldFk??t?NR9M)U4OLSHauHvd7_~ zaOAaUD)$VqDZf!y_r|M?EqeK1*Pu$QWW4bx@Xh4C8%m;5{S1vtRuB!nUALeEtzr-j z{}af2AbQuiIfpeB3Qxi|Fb43cl@F1xU-A(0{S2&NHqf0TrcZmvCE-(^BJv*rr4}?h zk1fuxT@>2J6pvO!Lq?1NEny?HP%FRAcU*~BCN9Ztz29IbZ!0hc22s)2?6_-0B&_<2 zpD)#mS@q|_&mIgjm5IKE{!WtB!e9v;168r#NeWxe{{i&=j`a{G>C12E@hQbn07vv? zQ!w`nA`}c?j@UZ;-&x-EBg>QgLR=)lFxgds>+qpj^1V(=RD${;waj?td${M9Bx3Sx zG6Q1W+BbpuBxDbpNuAeyVQa0ef$A?1TWGBQbunr6iT-0+JESZ!u2uro2ObEn=fEBN zT1UZg(H~-GGVdldqp4|@N6k?wQ-o|87&5vqZ$Zc{k3(VxrIpWZttdy7YWX z>xjr9AX-9{vm~EW+x}$u#Ll2k6sXDO@3mz``T#}O8of*4JNts82 z?x`ECTiBUk)k;gyvQ(<57u@L1uPfn?LIjEodFnO7e-Zwwb~w%)Y~M|Ne%o0La|gwlT; zp7D#7!4@ue)6?7HL&_eUfa1VX9<(|*6=Q&eWRAX8;nCl^RSY8KfH+8GpOo3%RY(|) zBQ53U$bGpEB&wQ;O?KW2E~vwMl0e`sHDUTwA}G1Msdf2+bt{0d5M|Hh=f=FuiPi{4 zj~W7Ur2FY=^a^qdJR>7E<;0YYva|Qz5RDVa&E^Crn;hV zpVv^b7L9)QC8Is`B|nAhws*>`v@Cr2>g7a#!AWk+16PwRXwZQFX!Z?3vFo!0>3fyZ zGE=`b+G+zY@{n#&;R*B;lFq_ z!`H_^XEKI~_c!J;zJv_P?b>X@H0CFIDAa#ClM$I+@=00$)|s55>3FLc+az?NEe{C; z3nD%-jtcr`XELmL`bOAtv7_`52iF}_+-Hp6OF~}N_OshaX^IvROBVB0W%qh#NUxEO z-`y8p-Clr`-?jm{-ZMNJu0Y)oTD8~9X5)>)9CMNYp;a$6a2RLjPRRVOT%DF!nIE!Q z*yQ65poR^2Kd|c{>;zc0hgRk0QJ!_x@KK&PgxHMUg;{*loJwwyDhBRI z)iP4{-p!i!w1{>8En<+*lF3&AQ`k;})Y7UU@(&{|8oo>WW(wSW)*e_9!b`S#@!=vtyY*INa*A16#I zs|3nG!369|IWaPnQ$@_ogO%urlO`8N{mxOHv~L&sRmB+ErKZg***CR1HH_4^4SHwR z0`z=x416uM#V$gL?Put|S={z^Lg45t2RvuVeQX}Ee3$sr+sgg0XY zs+rzHpYqOX?yKTRho1J1R>kh4tAljWf}ncYaeHSeBrN6Gt{A2-%#5==FEv_WC(JP^ znJ%v}DPNu#wqt*4g$0_oEJ-L2yOzyrrp#(46L^Ikm+-`rd7=4uF6f*#z^jyXO|A>D z3-6;P!-PQ8M}(o`f(#WBACe@p*LvfkZHX<7Soh#(FD0iuXP#KRv23>ZWI1FuWIkjm z&?5w5XScav;AERPo*AKw{{GSLGoKnYjXcK}Gx3D*Y3c9yDrc=cjXT*LJD&r2j53*z zWT>;!6LPLkH@frbgW9Ao^W-}5o?0v&fz_-!ZiO8C1im#X~WMirBI8G^OTvK>3`#-TN-7F zce>-qfo;=2J3PNbWq2qyHbZb;Dq+9W3`y6ah)-?k%4&ja-CyfT$w`|@Ftjayk-f7IUN?uuEe^PB3 zb|<>pj4?hRgwNq`cjmR8TUN~QiPww&yeVu~TcldJn3y0Ag|2;D|3&PFFR&_w?j6Ni zBid+Noci-&Xz{KO1gkSl8o2k|dzuf6vri*hBdq@Czc3m;1= z_c?m7V0i<2->Ab&+v7Q{gp2~+rB7Uig#t&HTru}~2#Wn#f3(obEPL+^8I5I;go28; z-_JIT%Th?LSCeRt=zU1&8^%^0(JQLE>$-~_4iKNdFH5`Zxr>cX+y&vexliAdJ^oKT zZz?DNy^>td>-Ep*R#)<%kj%>HCbVgOX8KY*veqP$Ek1(Mwx80NW%2q5ICrApJ^6?p z@$TjbCHi-{+viT!T1;jHMP|gXNON}~Vwu3H0?kvJ-2-50mhthMn7RYNQV9g8f(G79+thlFJS({Bi8t{EcsTQTwtnFK zYJxx&0RVl%3~nkp@A&L-65g0>p+G9Au4Fh)L6&bpqdwj0(im=*5dl*=pW>TKQ&xrB zuSGJ*a&gSY3$YrjB61r&MG{MdTMO)Zuvw~B_mMG{4yrpe7EFB=P1#DI#0SQ~WZ%^l zC3%%jqpa`WzALOn57nt(D^+J9gk$ti|K^kK#`$|yal;ugx?F%RiSflbo`R5Uo`+m~ z-ajqv#7bQmU}*XxQDeh0RKt1P_%REQVxZ2se`PB4|`Z342Kbl_P`!AN6%+Q4s z8#*>+@>61gz~$246m2f2)k)e*zx0GL2>o}?}Fmplhlhw1;qff1gEGPgP`!VagM2am|Tr zDF!Ep(bV=nLJlE8tFTL8J@Y$?toZW7f9kv(#LlHg^&1>HX+E3!~^{UO=3`@tpCTs~Z z=h}Y_!2UFiCMVMsau5)EXNe|z)W7RF-TSlXbL)SK zTA*k&rZl@7H_**pt}&u5LQ+Lmpdts}u`KUmaz>DVoLB44lzLnKqc5AXD#?V(Q6@MD{q@CngNhPYa!%5r5F3rKu0wX5tro z6K}V=BJa=7kS_du01no5x}2iW%vL36igEqss`VSmho=N~mG8b%00n#KI-hNa0Y;`A zTOr)|%H&i^@f=GJj*7D-ya1h`4&8;mWP^@%pF8g-6bu8li9r|CFl|s3`%?kCA#IJv z&qfC&eXBrOf}Nc^)R!##DgpQdbyOs}w?E|XT??Kf* zbNsDp+a6Ud>)cQ6p+F$N!7dHRZ`k8Z#RBph z9?#^YY%f9;k$%#UBcPl;r@Qr2T7q*A?W{BPimQUef8QtZ8SX_*LJBWm2An!6$63#9zN%ZO8D4^pNbq0sXxu0nCnLF6Wwy+ znpAsHK_S{MYnnaR?()X6+CbsVY~+H@T|py%AYbB_1+p=CQe8b~Ht|GQW?Bxb5U7`?Vo=JP zfx$Ws7^EVW?5hs^hjLX^4ZgP;vB=_Kww+hNXm=h6X9Id*Mpo!pLBM1en4*rX)K}hr z99a=_Av_X9^1!(tHMz^qJoUd!{&~-4r!O9MB5|2)5%tCYiP7NlK(GToT4dSnWOCDe zsl1a<_#E{ja@bPf_*Y~gvJJ4SbBTd#T-PF_&hqI(#r5v0K&z+ha>R}64czKZl^&4U zmQ5UEQ~yEZS#Ho#&mP6L&Kwia>RGq(pY5vq;vG8B=}Ar+D)Puyx1F9Z8)crU1*9kI z+#x=g)`VkDh9+-*tGfVjB4rk*fQ?2=@{PX`f-@X3Fd{^ahzAODp{>{)!=Msr^ZmU>ly8HHELai4^ zZ-unq54;TcWBoA|4_I|Z6sv{7_O|JcJ+_CiGQ+>3HuXGn3$3+{HPXgKKsk{w|JQMA z`~5NwXlXDN1;cEm{Djf8RZbnIw<7eJ@Id+J6nw``)$h19-K0$RRGH!JuGhmZ;4ohl zhkwScK^YH`Hb)v zU)z*A9F!`Z{@jA&4Fi;Gzr0)1&bB+zW;MU&U(?(_L2JLCfSjRkzFi@m!_aw_;p{7j z95{qp!Hz64XvgIgfMpGome2C5`Y9Q*lb(l9&RX=L%WPXkC21Z*49f$XnaZlnDAOZ!PFCZ_QohPxI%WytOs< zxLJuT{!keSQEQ- zw$^C`X{e!FAB+J_vhPhkL&Su?o}qoU63EKx7r2U%0pit0MYsfc`G#_WTG-)V)vPN$ zwbG>IJACK8cVYBmI-L}10B!VhY&CEUm#d9i&+-C%>x4P{0C$S9-(W_^UlT;eU+c!m|k5K6nv@#GM%p|EZYQBfobs<%%iq zPIQn2){|`tG*di#PYG1Ai(K3Qck}`O=-#xrblJA#p+VS=)^<#L12<_ds77&Fyn{B) zSZkm*4Jx~aje^9a-A}mPxegAdYNOVk=1^)#gzzre(;`BDceo3lIsfwF9m5MD$9gOw z%UuH!3ukRkXa;oiT!oPZSyZu~RNfSH54;eNM6Z6pULWzNl7&Ebc79NYzoQx~&x=s?(nuN4L{FYJ`qXPQVfM=anN}9iT z)#L_L7wa#k{kG+i-temk2tA$VoHt8<@j+J6*&Fej2{o~KDN3ozM|RUirej(~B6s?% zpXi8}$#)}W+n*=im$#=!Qk!|IL?>*311s6s@(M+R2Y#+6Ifsnv9^;Q%3+K5bQHYD4 zHQ32#c-pjEX@#b`c5joPEgycYJ%rt8+^*$}&9AlRp8uwoer@p*2)l;s9yR8nDTY2w zIJ%sf$6Z?yH{P>3%#6hjD40```*Yu4s&-0wiiTU@-u*PdK3plUj$x2m8`_j$8klCT z>#N~qNW?YQNw&hmYiYH@>fII8K!1p9exUJfu*C5@xVVWZ7pk_Ro2Yy+TehN}q8nhi zgSp7LcNdO>iOoN9%C?v{87aVR%v+uI1Y)_iTNMp&ZhN@HI4j~Ey#LhIa;9*8=FH(V zddSP(_i7_WepJ5S6{e-1mcBlIQ`Ps-{$zeEAeli+^*X37je2)!RWlfl57~uDrIKBN~3GNPb-k2e3L#T4n zv^tH(w(nNmQQ!L6lSlH*e8|WO4)cXPWu46s3fpy47#_u9>>*;E`mg9L;rBgj41qzz zRf9$xNqLamh2#WC?tF3`BzG~{&s&MGaev9(>QI==iJY(=6LkRzfzj8y+Ux$KO3{zJ zY(3K=L=~Wu@Ix1l&3VfzewtJ__nGi=w*r)`W=NSZ5ofw8?K@yJO6&X1x6UQdrQB$N zm!9Ih;mTi8m8rAQJc@B+3uyLa0OF#&^tP{Gi{Pl|O`0FO=I%h9+9B9~FyGSWR`VT& zrO$hn^z3zyjF_{Ejd-pzB3g+&s=X^Hygrll@YS*6#|1{og=>N1#_DgqR>56Ft0*7j zQoG)F-zWya;PTe^H_C`lVvo|Ry$p98$ZJc}Z-QK&yW_Pwe4Jtwn!<%2GQ}mUf1yo4 zv@3@=%c|W(sjcSy&b-W>xpm^nFKQp6Dg9;!@9er~^+&RddxvmSP*1&*;7QW0M3oze z2X5e#k(fxL-lj7rd2sR6xlh!TyPD?OVD_VNf+LN9zh#j6#o3gi1?zbY*uW8vodsfz zz~P#=W9Ku6WXI0KYZV#jSNMbp2|^pZNQ`$Vj6i zXW+G13jwNOx1)1GvcUD0PzG}^FWUeuIMUc>vwpOR2wz~T1@UY8jqcm@QPLs7=V);* z!RM?qf=+_zko+DJk(*+U$l*KJ@A|Z}Gr{M@u1qt6Q|=-+&X9uFP@C~55zW8+;Fs!Tb@x0+r{`JRcr5! zM>oN>U{z|9F-2r8nCx=l6-H_M%Q9$xpNJs9fM>pwPXl(3$eSk>_4620G9}A|BUCn{ zX!WKeelWg!0$RjJyuqCnov z6t8!}$HdELJh;DQHFe_MhUAOddnj(=2B(or;KMYNacLuLq5|^=VEvMXD#s6#QZ+G% zLBX&Pq2WxSz~z~@Wd6xNG74RTb zfRNY(3kkeA{32tyZAAUm6>^Y1mI6DKfO5LWKci1;&X$*(k`E{ERNAdF{!Py$Eh7M@ zGUl^F^oXH)P}``C`>{x5OOf3hU-sUm#F1{%Pu!G*0y5;(3qy2q25#lt6VJa*Zo~}6 z*We0v9zBd#8{g}#546aK*jmKG%Iz^vt#P7r$Xcul;P)^WUCXFPTQhbvz^-Txj;P^X zsJ0%o*G%^88P1v7-2o2`ApakGZy6NF!nRvO2oOBM-JJkI!{F{7BzS^ra0#x#2~M!! zZowtEySux)+YG14-p}*e{_3kbRqwy^r)im?hN_vN`|5SA``z(X*qy;Yw zUjlIt9~@tV)erne27~Z(u?0J{O%|nVwnHMjD1c$rb1&??KiQ!u(VQ!{3=_YjdU2k6 zz&%>|EBnFajFuTZstLuOqVRq)GvMe2DPD?1I(so2cPr_CxLp z@!dq3lU(o(*^YzKdxfYyY^>_hhg$k(c)zYRWve(M3%pYtAu=(dK?Ew=Q1Gx(>v2RI z-oG6m0(LVmL)MBTiV~+bpkq3qzi+74S4gVe;>*3&4UUXTt)|R+Tc0$IzF#Oen`vZ+ zIj^LWO}m$pD!D9iqOYcq^i%|$kOsK3@We>OP3#p3)cxjfVOoo-^KBhC#=+=?9^>X8 zdy|N*z%Ic*W@>WbtE0wFw``5VO4cljj{s|-B?^Rcdi8hh_g@@6(~EpPwh?XyDFX0! zRj_68i@SIcYy7kA9?B^l9Sij zBUP?RNBl2e32_@d2TE`9-IX^xQ)8}#+k_-(+S6cqAmHdfG3zF$=5G`I1-OGIPkax$ z+%mLrb-N0~5AoS(jFYhUipxwomIe~UBlOj0%A2;y?I}lCB>+isE#5{#fH*@sc@MbD#?ARp_hMjZPKO_Z8P1aRW0Bp>phddstB2v_-`V zY$3pjKw^`B3PX@0qBIpFNF;#ZVgX!a6zHW?s4MQKgY(j@&7p)e{EX8pp&3%nw zDn?$!mw|=li_Y(Ff`E5JsJ0F@#Q4Ts+z%!bM{Ryu<V9{wS)!Cy!Z^C z%4pT_bkAz4j4%0`E%>9J<11C%4V8|qRqI!Y7u>Q{L)7^>VzRSi0XyqlCpk!wjHXyu z{g5@KCsP6o$fp}?mz%F5MArEagFX9uTim>CNjlb_YPgz~+_t|@Ea(vO$y+hg7xX^ z-KA3pSkL)oY}bx&P%L>GtyuZ-`NHbA?Lqp=82rXZR&;%S z41IX9Fw~L(jf*rM$XpC-aldwUGgYF6{SrbIP9+4h&|1 zSGmPVr_vxi6)q^9)3nJ74GZd90i|WRCA&WM*w+U|cZ#b(~vAn+X zzcV1U13vRUy})Ol^c?ui`}6{z`5?kWewe7gKJ!7^z-Rt-pWr6s)y}FXt(0aSty}49Y0hS!tk}u{&?O*Qpdh3B+ zp$IUjH(8crYbm~5TL=s!`NF@cE4sHWaxA}jS_@Nb6I&==pl?Kw<8e2Fz-QI${&d|l zL!t-x3%6R@w+CicWO4v|;hhap#nOK|Rm+>u3yxLrd6pN}qHFhtAtmxvM<#X!9FnA6 zZu+;zEk<$Kkg+it*5rzKBPEttME%*~v=hK#)k^RRiM#6=AW3QPT=GLoY;w2&U4cVu z(~uIwk%@6wH-wGh;em%)aM+QtwFL~;Mb4#7<8KQaTcYrf;%@>!hZyY^m3jxI4Tho# zIuNFK{2wM!k7NG4il)5C#5iHPTFR1sApQ+OO0*@bbjD)67=DQ)(<6WQN=1OijvQX^ z1s6u#;Mjd}j5^iV)G7=nPG*BHrT%-zk7npoQX258sbk?`GeodA$DKqv#0>X*Gb_Qy z;zS&FMshbWJtEHIj5q#n&f`Xrbp80sMW1ApFhjFKE#OinsWmYfN=!g>nMsFKOnxdJ zaFh%=p;1{k0)5JjH6dy>_Frk18sJZ|2@WBr@+mpDz^WVYuj^i(drJxBQcc+Ebw!xu zcWSd3Qez*)QWmIwd@887lZKXqOwvJPS}658Xpftz4$MMcGkd;lpe0)Y6FbeDRayD0 zi;={XcnyJ+zCFB)p2QU0d9Uuo6s{PIhqPHwY;#o@aTI0`#NsM>mbQS#Jrc};jz$z(O*#)jR*%?*eH51A|4?2AN*AN zCXGiA9_-2UmImh+5gE;=j@!-VLQyoe94`VnGb-o${-E@~qfsE4{{02hk6%j__r~@=HaWpx1B1^V!>&v$i@f!R&bHk#j|FL3=SEQ5??XH}mz{UQm9iHJ5{4gM}F7OmV z(!2U_cJweKtL_G>r_M$!$S~5cR#G+3Q-Mv>jK{AQsN&N%BgKNWf*!}AG+E&A0DL#9 z?Ivx*lz^1&$5pBHvr)%48Wq3y^5-!wuUndM-+uY(I@&0Su=^DOlOWsNNm zT`!F^;`*{Q;tO$Zs3uB+^MpCY)ojutD-8?HR6rJF{{N;{nZ=tElvvyz>tXtr$HOu`9(rqH_6CgUnkEYtW!Q%XMeOdctKA?$>W>!*(JCw_i7?QH~Wt8q4`^1q(y{q8#KU0Mzp)cU5i z-&EXU7RE+0ZXWveafqfy+wVKNCy)IJRT>*=32#LBcD7xtxtXFqywUe#?dFrIj+E6Q z$zqDV%%{_-eIpUt)Z+K^I9O!b=M|%e6!?);)JHlyMqtNPL#wGjSRS)q$s$2Hw-RQlc!Xxc%_w)j8g=Km4(vY z;Noj=`cqxR5Jt_H-iEBNd zV6KR02eigZW64liGFZd9(EmSI(puH9anMs;?pGdwKj3bsvse4IQ9ozsBi@s7RTTro zYP#ulyrq~UD_ZpB621ni+;(K>==7eZxypwiS0bHg&1d0ZtWJ-VMM}HE+@7=IW%cWu zi(6)sQF1=YqZLp0hi2r@@YIJ1q=!h98g>QLEx4a$wvIl$B6#`X+CsU8LumnbFjR?i zpJELZJM{ajOG}sijTV=YAY-b^YbPmKpBO~X$abQfwXv_0FTN?n4p>YQ5)XaakVyD# zx*kJ(({9UM7Zj#z6rilS@UJ@z>=o{6s#X4v`O4UskMg2E$e3O+jS61|Q=v3g-A=*P zKfH5wg2d*uQ-Y@9tHyAobgb7w)S6eAo zlpDBA$o==TI5q`P-h6!u+A~iofXOOTCXIElyj|~o5j*_-m?^=aZ7;36>AE=l z9E#8K{g&U200L^g@klB1whdD&a4`zYH49$T)(0Yk zVc1*r1CuLl@BS>jtrGuvQbW9`zr4}yQfA2B6|sA-{_}ZPB3FM42xqnM@_jykSjE%W z13Zc#2O{OIW6w%w+}(&N*XAxb>w2arPy}^Y0J)pESLxyN4^L2v-IBqx^$-n}M(5_^ zbLRhI(?(_6%cACK`C-JDr1sm4ZL{K^tcyezs&aMuL!I^vN?qwf;QKVz`6nBV4pSiD zg2^TRlX)$Vm_8Mr2aZ9Ch77CzjNYi>%mN<}196yB+L$NsT_!Ck{-C}s03=}a{J2MY z37&XICRNY6!$BWl^Xk)c^u>WD{-D=z7k1s^@<0;)x9%|5sZ>SAdUqx62TUo;O&bbW zjv;aI>P6KJb#M?PToe`;WvsSJc{3eVCOYG6ApvxA4gCiXXhy4Otmwg5<_h6>#-+qG ze8ZBq_#eKx)%dk!8=BkOoQX9%EqEN|JapL^Tb~u6mJz|-5wu<{nV^F=`At$ScFzaIz z7PBYvzXoyyzb$|D?|~dKs<3gfv|%y`!9}n~`~85Au#$IST-$2wTWrOR6rR~1-63W? zVKtDw{&Ut<%_ zPZtU40=6Xl@Al=07{zSMo;)Ur1r1(m7?jJYuDta$?bjH+CD)OSM1OL5joyNm|LQ%C z<$x(L0nG42;Mh=4oq48g9qHR9U53Y&jP0Z_XdRjIYH5+HI8~cjU(BQ`yq8Dj356No z+;WHA&g==lpMN7+)6#X5X0n6J&8#*DGB5C(S*kAacGMHZuzXKUC8N&JH_UB8GnMRW z;*IgAE-dTSb`N-G_^DpNriMV63!ec5_e@jz>2s$=7zFRkwf)|t^Pme&ybZAJ82mU^RyiUQysF$(dc=#w(eV8s!fwd9*PCw&CaE_s*_dh^ zjTHlYni>WKURx2JYaq%mNgVZc>%PU$NMVA|H~pxlz*lpmWoYzC>b_27v^Jn*RSpWC zI&nZ~*nl3#_CDe|jqN?EoPf!f&B1VitF}af89v~c%zI#Wv&%yu+xt>uweNxAsDYdj z>dXDYuvAp|Ly7cV8CE49qEPcYHSNihS7qqOa;7zfSlsP5No4xU`%jf+RWt0=pHjuQJ{4}mYgKo6{wAHSWzE#Q{sI6kMWpvMTox#x0Cl}jcw9drCVS_*S> zYoGAEX$rK=vK1Ih9$Q3J_^gl@7VhNGX&Nz2w&ynP&%F)7jd zk$CuOQ>vPUF#RJ&hOyz{>n1_5Dvm=7(&;aM*gp+^c%Mb;FrY+4>sPAv;!iN;?MsFb z!qs_Y;4wv};v*eyUPt)I@|oyO_g6V2Dim`mnNZx8ETost)#BKlU2+$^Pkpy9osrqUg`*SXa7tUpF45L1ea-@R2N6N-)t`3+PWU~iNPn`a z(t1z4AVX5S-A|-;OMZVPPTF4|OIfwyfEgM_CuC9n&tSIKckA#lQGQD% zq|q}YA@>9@Q4AL(&$-qjNg8TUm0H@&@+qn6?W+9!|4gK&{GSskA*oPzvgG(Gtct0R zqzD9x6V!qdaF6}a=i%G2MY=T~Lm6p(Pmek}(B6~SF=sklkln~{CbSTJ3dmC7kj7$I zpgkJ!lHWDE*m|fHXolS0AKfrNVR7m;Lv;6BT<79z8GawiZ$bXc*)CryL^|6YG5cZQ zp$-NoY|WQNff3gr%;z<6GX>bc70Xge8-WS81J+>L;gwC>4@XAyKU?C*JH9Lj=L+Sl zPcC;^Kcd<;d|9;LZLhBSvRIUeGvQLyeL}_wyPMGL(0=!= zqzzuv@A+rFSOgDZH!cF%TMd5^B9nAAJNO&uKd<714%eWSfh-|gwGP)UgYvI^^tc-- zEXr?*c*-dhuTpx0!?5394~bIQSMeWgs!Ey0ThM4*>UI|rEvj^{I7yA_s?}~Rn zcg~&HBbffokv$P*%c^V9)|dddo{gqD4DhWjr#j#nhE#l;q@PvB>{{PlPlBeY4(8k& z4MAZ{|Hy*3g}4g@Q+mncUA4L|2`6elkinqlQfV7009Uc-YX z^*kTWl>v}KYlvq{#8gSWt`vlw!G$skNB?`U23038Y<95}-t%0(AtAlxz@aTM<+v`5 z4OHT0L!CEvw<9Y*P)q`3PGNT&vhvJF0>Cn*FBq&~DNy;>Fxf{xu)?7iKE@D`UYVQ< z5Cy6e(j>ehJ02eoOS`+p z6l0xU={$>}?EB60em=@HT6d!zgd>liqQg$BsTZ-qc7h!28Q2KI{BVL>Y|k>a4$N2O zSC@F=cLYmq>LK9_Sq8ou+e6Io!<-8I=F7hcqfxb|BQ_Ke~-sPDS zICG3<4HsUFb`ECM-4&4*awSFID7i$#(<-c(;&D~C1Va9%^$EFyk<1%2?wI*1HO-tn zS;lN@OnzkKCYWD1)N4C?F+B%KF8HzpZ*p~|Ks29007Vb)B)UDQXmm&mG9V&=v{BU6@E zI)5}pZSG%>g0)?QwbN?7@@-^a-7$oN93!c$;f{X)t=#>cm6*KxnKikndqdKI!_+;! zvY2pE>AIxmR4W~=I0C+nGIFeP2f`)1asXKPW0KE^1SSJziAJ9ApXUd27~) zwospUaY}A*L1OQ8V|sHqiE2bHokrQrO0HM>?-JNU#uxUO#vW2Ez1*IR(moIxpf!7u z+{gXM(;Ho>HHq4en5Rw2Sdq5W@cNGUA(S^_jW=s{nqQYa8GR4SO>*Wzb{&7OQpTj0 zWl!(umkwM(Wy_GlCEu8I85c;WEHxwwBUGM;9X+!a&Sb3GR7tM~mHLB>@Iyv`ii6+~ zH!ezd=jQ18%s5=C`DDF$_+z^NZfeDxE6FeGThaZ%LpHzYuz4ay$L=|@LP|cw-0N|@ zt?jwE4{1CJ38n(HfFgBRbk`o+Fi#}gyTH0cCdv%eY&!q_E%76kJe3$agn+E6Tk_9~r!~r&SQGTiwZ6;F^+dEv`Rb|rc^v#Y)~OA)a2zEngyczb z6QIyc+x9MyQk1I!IIU!@wg>L3w%5rQfA*nAh?NKbT4REB1cwUFit`GddPe-3^%!KK z#(IR~#5&j_>#Ot1&9DJ}r6J$m#r26-g7dt5f)`I;rtFSFQXM(CsDY9v_m-f_>GCr1 z`jl?i(UU^}8oTo3r zp4AzprjdIoGVfq*ZjCqfM!!ar5!XB&8$S9BjuRAtANk-%&OHo8^*San6q&{8xm;1r z`QR`MtQvYX;-eZrk)ZRZ}_?M#zH1v6j4(u5n2DU3MaQ6tzis!8fzpQSn| zCD4S2XTwBDotzA61rhQPB^N$eMum}G!HEjXRmk-ANs}c8oQo4nt7cMx%v1`lS&mBj z3lH2r<0I|+9HpqHeYZQY-;rUf4nSffbN_hbbIg zvITi~0X7qgQaNI?R9eR0C-WfKcOt%*O=nt3TUA&HBFBE1vEus9`EqD0U?np4r_p%! z#FXOoJVFy+?m{I?I9Ib6zP-E2wfeDT%y!N14^}7Hi*@2@C^tfGCvi)XCII#%(I3pj z+!ZV?=(>Q#M7FYtUWFd^yK$UaUQ%H?Pl0;af#iFugaf`E|AxJT;>--Y-MC%La6n~A z*+7$v>am=wYaY_1`tOuXi-@-a!ElFamA{rKGnhX2v79q7B_!^X4+?@`;J$zca7J|>))mT5e z(^vN>cv9U5PzGa(Ugp@Fk$|Z{VjIFOes-c+H6wm=XQs@~@z!ZnJW9iz@&WIc5D~NQ z5AM8zk5oT5|IR;Jl87ez;oWr7Vq;zb5;=)EuA#Z=l6P0RWSd=3@_5jm zhP!5iyoU&pC;2!?J!_S=xL6p>->Zuf6CSaWHDy1req(nN=OT6?u#fvAw0}Fgd zlhScjl`k^tO)Z|s)`#G5MECP!Z{p6r!-?7PMr*!jxhaGGy?cRkU?rZFr<<6=eS$p? zqjE`(s<~<0zD$t={!%bWowLk5+pKI<0z*FE3XPmlWP~_dkcVjuA;%_j_j{fb-=%pv z_=8_%`OVk{sx%g3Tp2)N-7R9*eZHNAHROgTG_;YHfS%S1OP zNUp!nKd3EOyK}iz^0>2|PyTXa4hWtgOe{^M{BZ^I4ufRg45{E7nkmwDP0cFiJ`&;+ z++*%~6Bo^G-%1vv_T>4OJ${XN9c$Lo&6^wXmW&6kz{<}>6E3<161PqD3O8i+%Y2=k zY@fFA&OcVT*#<)9z`-%qo^pY8fN5lB`MA$IPOC>d_d1c_D4C05DQcsWV&p{Kdim)# zs*Vdz-O9gj!!v(pNFhm+=69!P^5|Y^4tA;uLd1@z_+&%l%3KfeRis8yHoH(DF%rnl zV`M^&e)Uj) zgK=*#U(dkLB-tQoCbx5VC#CeOnkl7x^-l}}mv{|u;n#y@gp<9GJCo)=cs(*k0F&vx zy6p6e*&_Z9#_3tj+!hY&`u>s!)VD#N&hSWQWs+K2o7YSCn_tAr(S^H9ID{E(F?`(} zML&=Kz8)dtL!<^Hj~JtH9+!44RX6^QubuJM&b`FxL%Hi+gew`cMLRErzsiQs7}rZP zS+YGAsT*F)T_NK0yHr!|F&R128R1F|oKI8Y7CSV~?2_{1*tsDY_W$95?I!m+OhjB{Ib$2mFb4V2dC(T1IpXK! z;gU`9`BwrK(~oa5Hn#1~0gI`nllSpMve9_SZ?^}^>XIzo5O;}Ax^k&_!|CORV#K?C z6;&!(7GW2Tlnv*YP6-*Cc2^p{PbM71;;$98qbqFh)#o8nQSL7a#_`ZIzem1Kr^N7J z9KmLk)WOmyKNB4I@pfRilIGFZ|HQoo-RGD-1cD9>{`sVvvHf}_-P&%c6e82y1VJ)y zkp(BR$c<1k!#N(Y3V_7WuZqJR%u1O{z#8~^VB^r#RUQ*9`x_@q1x9e$&H47k&2Enl zH-4X6JBY?`^>q;x?3H}6uyqu=;->n`9QNUyeL!JqKS$v=NI2o!@;>Lu5zM^5YC31I z(zI~@U6JL733T4Ok*p~R`pdk0gpGwJnb%nKJJh0J8wbHVx(NBb66{=RKCGv*4`GN7 z%omXNV6C{0Nq*rwDPf8ZDW3lHgRAj{=-;Q5w!dnAGmXuRJ~qNkDmbAC4UZ{X0|HYJ z9}P{&`|KZhn8f-aW$o_+MN-`J84ID{PN9i(jKrJ%~ z7rOfuZkcQl*0618{6teN7*_y`2YPoV%`H)K-T6mfsx>aTUIniASDe(C-ovcr18E~+ z(A4O=qAA^B#?^-pWY4Oo=+ejzSs4hDDI@Rl|FM@I8oa-;O{OK<(MVZGA6vKUiSj6v zAJfY-opDJ0<(W61+LM9ByTrUAxWB7@Xx6aJzt2R!(rMy z+0D@p#nxc#$mq?V`2Mt}Bg$`&bT4e{R4VP(HtCnjY=(x`^OL#LdG0-X@@8Z$5c-#>98=tnNvv(YeJj~mS zR+NjB*0o`26vHy5=%^&K<5OgVLDWHpG#mRYV{tzevGSGD$1KT*E5u=%>Qt20rpQFv zGzz%BQNJ&W8YLKp4jJSR-~vnQxMH01Buc;KzZ<4IRg(1D9FkO8@Ha+AwdVi^z@}J) z!4(cqZ_S1r2X8Vpn>mC|pJ5|K(CoO_{k?dq2kfPB#DogNXPf_<3kcpHdubLnX*jo3 zG&7-eG(1&bi)x2a0{#krp6`I7`J;kbn-PI~vkELyDO3m6r@9w|1U=!=hT19MpAYq1 z4-N1*CM2m|OvBBC_iO8i0K>&J46z0Kg;v_zIx!78JyRjB5{WxJXwIUPkj757RhJD~CXMwuo$m5S9vR*i zgKjhg*e*VNp=VN#*NN+!sI9O@e|E_iv9Fs$avrF{cPDzD;4Lr6R#{82JU#dAhx7?W zcHNID38v)~QLTzQZW+T?;w6r-TaF40B00!$p4%HA1amwmry^L7{`}!*J2HIzP`=Uo z{W*Nm=}FSx9^M9mu-THEkFnGj*Y4L`4)SGa1Lv%C7I_I zzJj^TvqCoB^t6uAh|>!nA9+_xMD1O~E zFy(Uki(KL1%Q!hzZz><Vs?XlIP@^J2b3}`EM(acZ0)$;)1snY%Gcu_hmk@Je^RrjDfHDPQ)* z49Pia`uV-cF~|QMy8_SU1jni1M4kHE2O}ETD}S+Ib84<0WmHi`m=5qK`|S-70(d^b)~B=|{li=z zBkjJTZaYmHCHjTizN2JHw#!dbLb%wjCmht>{uBY4rGQXvkrvn38wRE8cdBVn7$xK^wE)ixE$230|Z;dD2j zHzl$7rr4Dl$aJw<>q$S`{XpH|ly zWHPv=gSy?$1Ya+>=!=b@>JjIsf@lp_)fU+6DVZW+VyY8uW|FfkBUe%oQ zTiVf_`@@O?NBSRkw*DH$iC2+ViWw}7O>D5T?v?y>v6bL8_4wo(jZx*?w-~-OQc>+r zGjZH{8xX!Y--1&U5Tvzz;!(wPRX}p$S#&pnGnSt_JINGmPDNfH9Ma25Pf$Gu!kkRZ zVl2!?d{G<_@*uH<zoHZY#B7BOu_I^pGY4 z4^`BLd~#9WdpDqK&656Bu~@?O3$+j(>41fO+ixPyQNdZ~X#X?LVtQ@?dajemuYpUr*}l zIHrDoM$u9hV~y6w|yvs|D68Zj0@VMu8_ba)E#T=>N3%l@pphM#M%2?pM)3 z0Uju!wZH!5teUY_qLooi+}uB`P-|&uOH!{2$voxj8z_8Nye?3bbQj}exhD)$n35`s zju=|2AIwZ2e|4M}rsxS@cE-OHqBxDp6riE81`RQ0A` zIRNT}62YSC3B&q0O7}sad^fDOA!oFfbBFezIyS*St#X~_wWk*~aa2}yh7L2-V?;jK z`SjIViC+N5Vm^&b#7u~gR~Gfh;_@xhnd&PzD;-e&z@4p06DkvTAZ3;!%YPOFRu*RF zXe;MfUEZb!wX5FC39F8Vhm#okoV4A{=nMB!b!GySJVg)a&}*gvcyf9P4K6Lz6yZ>U6JP za&fxbcB)dRGH3m4F1HkqoVkt*7X9gJVGAujXINR4COy9+l+Qqug)i65!R-aPV}pzu zDnH+~F;vDg6b|4e6@k+VL8nJDbQ&ThvcRw!&%l~o5q>je$c(h>uMF#M)r%QU*yJUr zCqNT(KZhny%`pr9TxXHM@o<( z;3>Ek#PW~4u21RE`QqiYEyuUXb*xW#;a3DrUXu{ltB);hcY$q+EFg0MknB@avWEX&BfwulbvcNS0Bnz_3 zGs$wQ3y>_p!`%KNSx$AYKD8!8pKzeTH3B3HvI{`6B)~S3^?n55Z@dt6-y*vEVk#~b zr10v1ibvEL5?^L79;l$eoi2@otY(`%iSqK^;k}9q$VXVV$&dZ(Xi}(Yp;45L`N0}J$sw?j?gxSaQ zGz|J#_dCeZ_cFc`cvvQPaMPsM)u+H(Hlag#D&Q98rac>0b$wK5QW57;451W)Vtv1j z9`&AE+x~{Trt;67w>VsC#(fn5_xi+dIzR&g_>vbdrK9?bD#JX;q58uD^DygECYFI- z;pVE6{Av)Xy@Y(K<9Xq;sjt23Tc=uF$Aezr_m4PAfT_<`9u?!GR^Rqtrap1*K!jp9 zn;)$}pF-9fI2T8c?0ETn!x}L4rG&_jjBiJW2i!P#~EU-#|Lxa2=}**{GpDy_3&E&XPTcll4auH6vm&3KaisU4A&)^P|&SHjssRrMT5fGJ(U|pU#|(l`-C-faL${JvkXyPOnGQ>oP&h zaRLe^|4V3kL?rZN5IN_~=C2R|Jr^}|T9;~DG|~u~+oPY9wPk*j&hhN`zns2gUQlaa zRR}teGVW_=ew9vI4`BqZKw@Wq?YwTSqFr#j%;NZ*IW3L4VYMmp{i>g)A7lQw zMU>-N7Yz)S9rRB1TY4xioOv$rg>EaycN18tpGQW*cVZGc&W|q4E1?r7!CC}ieitb8 zwCsN0VC9V5to;$K73)VBJN_Bn{0rthhp{sHTnt*s{Epl$=%S4L!%IGF5LPMIvT|x{ zB`n^lt7WKplsLi=KsdkWt`q+D;1VSY$f+8_(<+H?{~y$5SWVzs_}|T2RN2`wsadqS zhcox~?!4r@*PO3%4`;G1E%ftWkB2JNsO*E@61coaJE?U!_Czu??m_HBZ{W-)3XnmS zdcqChnLjECWC(0CnYZJk4HB<>aW}RF`C8e#jMQU`*9{bJ2j1D?bt}QO8sP%P+Z4Ss zb2d=RI^RB|{}bwty7tZLV+e3s_!t757RGv~=-C=UI)F!Fk!XLj)w$nd4Fi7u`3mJq zv77P(eizqX5`4mE_q}a<ae-8C+LA0O1&xR_|iX28O@V&_KUC5YdzV=?ss>?eg7`t%BXX@4zh$yX`QY2 z{HmO(-?S=3OY21sg<6rG;8Z!VX8~!bDoO>n*TqKGX^sLzPP{@v1OK5njEzz|NUHJ^ z|JZZ-O&=E3F!C%FO880b+vUQ3{qIbo@07XJyD1VM9c4?(!_(5% zpnZuqs^X2fXXs%rB}L_|>l`iu6uJO2>k>W;tN>(+c;inNuP_%zfPGr$5Pt#yMSy); zzgmZ<&;{71&d@(`6ooFpK0W^${Z5N31H4WdShA5D2eL$I@W)PzO1=P$QwHrtDcUa3 zaSnECleWp&fBMG*J>&YW{#!oAU6!6nS^|1oj;qeXS8Q{KouB(crFW=!zw%rKG432D zibe0C39AE740*|H=$t80N63IV%tGI^v?DpVtSl~AdlidmC6^<^s~Gc5brI$R(w_%0 zPXU9N@z;Ps%+e~ui(Ku#;?kulu#@*8=J{YVHmnsB;PMRXqZL{ zQcwvT3q$SRwL~@FFjpk-f|9Mq=7=a2Z)l18>}_FW;aYXIVf0CNA&GcWTpSq09LG}g zt;`HV0b$a>;xw-Y4yl;e({iY(fx|ha=cg~>un_-V8)G6~f?|_Mox;&7|5wzTJ*rjy zVbdp9jrOgt;%;lju|M;TL7H(12F#P79Q%mg?)<}RL>pgZtWQ1 zEPF?m^J?oq+ObU1Cv5n;^ZS3dV;c|gsxtiqkOVHr;q!2esd-*}RklKgr=1qf$HU_h zWiGBN`K$+1?(}y%7W8V9^D|%}6vT5_LihgLLWquO8+6cfUnnAYXOi+?FvOBGeX}2oquW67qV<6po&P#6;Ip;H^*U@0zJEo=_Xz-(=rRP_bE8F)BL&v26?^-zU z!vi&LzZHm<2mhHg+DGykAk?;pW__-{rRm9men(P2*C}~2Jm1~ zI{*(3atH8W((^7fIPw`sZ=g9FQ}zcz)P8>H2|m3rnJo=TYA?u3rgo~|^U_w;^TUZk z{?$Hv#rpVH`>cRk^jg>zNm_G9n3K_r!LX?O)03s3Trw09-YElo#+u1iVFKf{K2iv& z`@`vJ$57y6DD9GaZxhDdmNopxHCokh<*o)!#31G;P)6QR!pRE2B5oYiuCzR=184E~ zZUs;KMq10IhZQ_P6Tezu>fuABK=s3iT7fHvdxofUy2xYZlMPe=5Jc+ct^O3oqULsW zO0-AwvhDnnWI3iG-dI&yg$V%tWO{z0%@6&&~#yP5Fkc zpEf7*4alrw8Y1RcZO7$OvB}Q;l+tIG zc-4`Z0({{Es9_G+1mFGWTB6E@Bd>`-k$}uTm9TL;$Rm=uLS~KHHOT{ape-CgB68GWhA))2* z3g@eiipC_fQdT;OOz%ksnVyp_?THVU5fn3BEfTwmSh2bBLsGJQ%H~2|MNd(M#tM|c9rM6etB!il!d$yN*Wis}_o+@Rf$xt%>As2i6Jt7I* zw`J&Aq?pr-%f5}gyFOapGqe879pgrVo=!}{7b?AbPO(R&dUDUbJ9kwD^}M!{LOrY! zIdv*sPN|+d^OQ0;jPRErJ&p<0t+$A8B`;K2^inOy{ht$v9Y@|DEsWmeWrweSA z57=oesTtDce4%D;+Y8r&4M%vJce3&C(u5WusJYfkT0dyxOJAeR@&(W}{hr4Z%b=%J zoPCPVCn>{cEAf_Z!U%_Jh&VvpaB?p~XB=8QXIiHqw2f zR8sy=ETZ{q?6}U24vM}PL-?W+9ywT5L_F{g*t@#H;O^@0Ptxud!c0O69V?jYP`wgo z$dK+#(TDPv(I~ ztdglc6V6|U*mjeGxBW9}5BOC={E02*$ZW7@mLlc^wSxlBX7QP9HpYBDI4qB#5 zF1dl0q&NmgdKeo@P9Bq<5(r@mZp=zxFUWYsC7Y3FTU?8%YGa??X|+{{*Yu)nRn2%>ph__T*f9Y_SdhQ2R{stL}RNtq$w&DCc#M<)v3< zNq69dd-wLQ%qxTzf-?IaH>tK*=6H~4k>&r#BK|M4i1r0q8UlMC^Hyr_-0Gj21-&#C zDODekwPI_(xk|2lYe)^`$H*VJp}C#l%na&+I1-?isO}Ht{1b{;M+Kh(YG!+2aITTE zUsx)raaR7Koi+09A-(CQ|4TO8IMpDcZpRBZWK`38HhU{fZRZ4^?Ez)bJH_hx{dTV)O<}7u=_6Wy&^XSgyBlBV~+d|(u(mW?|L_Ud7~fE zqctVds0YkW%I37>zkk`tF4Fr#*Ce&%GEpN|IT=@JMNQ-RP7AuCmMAUaI`}X?>-ajj z%)ElI_Q@(u92+45m1XIR-m3MPQ)c6@IArWJ>7%n4y4anXM;D)*c;^RFw-!wL&Kdi~s`o1WDxI*;w-Bf>^{2%JxGOEq*>lQ7v#Y&+- zi@Q4o3KTC;thl?oyGvTMIK|!Fo#O6=;7)Lt;6am{{@(v9W88D@IA@&mez+gVv$NUR zNf-}nuC?}DYqDDVKz^B`&>Dgt*)q~>Cng^Y+D@hYYH`RuJfq*btCES-O%N_CkId-a z&`EqI7HbXYnnA{eYpt))@ibfKVb*E%ndWbMFpxzFMz`}4Tg(AI)QnZ>w69DJ*t8s{ z#0&p2u6Q;bIPvjYT(D|7(2;S-@~N2cw#BfNxQ5De+r2+cF*irU@K3j{sMdw!8*+sJkLZnsR735E$8~TLoE)GSie@g+Rwx4Fhn*eGMEmP?Traf%JDRCyLO>l{IIT-6i>uGzHQ{q@(+cwls z#6iP<)cP?B6WPH%)IlPP&>dX((J75;rZN6iz5fgIEiryOin((HyPnl~+ze4ak#FT|`>%xWeHwxzv_ULubYpeLa)XIaP|yL7E7`syx2+o?km&}ciwANjM7_`!n&OG{ zM?j2J#+~hKQn*dnscydd@Lh6;-qGrc;C-d@amv`NkW0QFjzs~#bB5>6{qxcIBbhKZ z-q1!_)JLyX%$xRmX_aHs7Llr|h9Qb0DFL#u0*hyT#jOf~gczU$oI|2D`0L2KCf$idBw ze_`Ivs+kUF`q`^TI#HK(+jEi0WHmE zAQ4IP&qf*f{*JawJ3!$6mil_qcO#T?SW$_@GzuLPYT zNbGG}2wYgb${4&h?-JN0>lcloEz^-FhQa$Fa{b7+hSDn^;mU*5P?IvFtGBShrV4J*E3>YwF z`QCBFxoR9$Y4)IVl~lgk3hoX#@bIXKZGsh4vN%85`#Cq~X`)hW&lBb*{YDk(r5M@H@0H)g;nJtVkgAc)IM;2?>Dm7LZJ6_pyFXQu>R~b zghF@UaRwZnCF0Fgx?R72S7nhgA$AI+&!lwcoZ2dYOR7I&T8RD;is+#I2`nd@%-r$w z&u@0^9`nzC$>I>vuP7r@4rx}M<wi-buBUut+V#VFUJ45B4=H zE5k0rr)VdfxM-8!%BT5k)DcfwQ%{IVg+k9Nz4ZB+$qrT^CG&I$Em!A%kJT3MbFq(CJ*y~1v zBIuu#B8xb@z*hIv>^UV6n79akm;w0#TkJr_q&-FGd zNz{(uW(E$2<4?8k0p4`#xy@3j^p{Kl%7pvMZfuhSEhoQ3%%iP(*3+k9tx!BS$A*(y zFv#v%vIPH6{dbj={i!3W4-YD{K^LbWnxANiE;xDcZjCul?)D zUOf*vWLS3GLU~~~$aaxg+oNQ2VKB4((>)=tlEaRa)6KBQt+OF2pwD8WJj9rTFLa@P zFvoXMqG_C6LeGVx9u}{iGddd(Nu1(IlbNsXV=NO84XtCbqIOz_>Wb1IF(12zuVfKd z1&872uy=%(_=bX6e+j zJuIYFd{C{@VACqE*`;ziu|0{Fb(ZWv?sm=OU9TGI&Y*XC8=Ymha&~bHkXuN#u%C1* z7!fVL`(5eKA*p^-Z2j;oH1Q)V;=M?Ft%F?4!FZ{l?cfQqs-}Z$;lXSTH2HSKoiuEz@c_zlcP_YbrH5GAibO$zS@KVHSnt?NplATP_w7 zP_OKSE@!V!mCKXy@_niwn$tsK>ox6;2S=i&?`5XSMt&@GIQ>^%6Y4lV@t(Eo7q!m| z_-|D+E5~X-tl^C4`OX~RR&KN4{#VW+)MY4sok{R>R>t-S?|z1Fj0aXaf}n{_f#4%sR_X7pT8y7G;>w?YPG0k1W_Z=!wFMcAuEv*h`f@91>P zf40AMa!d**8oEN^yhM1mETUf61p52)<9BG!z*5U+emsk=A{cxn9r6DT8_{xXczPq~ zlHape5IKvUW+uz@kp6a>Fje`*oG#-B?F$ai?h8g5UkuN!<}NsQ5Oxe`M^KJ^S#cc= zQrf$p=p(}l6K1X_iX_8E3-|dHpvsI&?s?*f9<~)!mjG9n z4Zj>tPk$f|x`Zd79>!o#V+H`NOjXzO;xENN-Zg0bUtuFMD7}lbQfm5j-+7ou>c(qe}{?&$4Z4rLO2p#5k4Ty<%^p-A$w$qa$7+6<%3d4u7npIidK}+Kci)7g+0ox#5zdQ~(e@ z19|H$Y#o8gknlp!SZgltMiN5-v#s~9st$!0E(|r`8lbv4gJ5{eEIv(V-qTf`e`-sA z_)j{X>;+V&%S3p1i>`0}FE-9Xfj7>|F%^FhfD5A+roP@b8zvTLz}b~Jj%wn!!J4QP z?{nhx7#Oda8&;>%iL&LY`+p6DX026AsL8aVdXVLAd~Sv!2mhm%n!xv8-TivLC%n`P zo}J{VT`pm4%>Onn)X40XH@uE3^Ro0Dd15meX)>Imu(ma}WDWE1=_a)OWl1|U)+eeC zPGP9I7Ag;RuMWQ16{fqcxxai~Av1vY&bswkfB8e*;aS6jMAwPI_MaZ2@KhxhT>2Iv zS`Wi|-!^uC0;%nL{pOjGSL&LsDw_auLsJvXA4&bSWX0%V?3 zm*$@*B(u)%VH>tK|E7IQ|JwZ%Wdmbj^YE`&ijCJ`gOU6jL{r+++Rp`XYqy)}!}3}w zOG?S+xZH!i5^vfC6Po(5?3OIxZ8}l|3HA*0iBE7;mI#pFD6;~4R-;>)U251dLi){A zFm5;*jX(m)flF|fBKyBsiUlEbjx{q;Pezh@S@8kBc?IN~l?CJhqsFmXO~gd48LRrp z@@SW(aREWiaRHX7@~t(W*x1|Fuq8gS-Q%-Kzon_?K0~0s_=wo{g9d~40bej_LK>P> z>^ZCQoS>Q2_=`N6W=oUufAEmEKZH$Efcx>%b_~T!rQ%w~o`8KTk7wY8kBZQdoRLXt zlo@x@lBW6pU~um=SjRoD+Z|t-6GwqL`2S5n{HJ@C^zP_#Skx27`v zf?)Ka_j^xPBGiGRQ33VzjJYy9y<+Tx5L&*I~j5RutW`7esUlU9tnUz%m*59{01XOzF! z5{+PA*$+CZddXL((R7k1h;uZezrkEIf2mA_?yB*D{0O+x`Nho!)kX?bU|E#3_!j z?>aa@I>HhcRYQN)0dL-_vCNIe><9!_j;d(ZPfJ?Jx?m)hKS>*TR^M}-8;o=I?{{G( zYCLt!dvLlvOv^J#=xhrQM=g*p2~EEga}348UPVKdDuFbiNZU`S&P_bNpXa8=js6;C z{cRG_n2|-NfKbm=F3b7y;fKw&hz*HQc$%AtP0}KA`0{4nvz|5r&7zM@4dg@6+mTyO z=#Lr#GtKow$*MHLKg=m>LWgyf&PU+>9+g;tI_NW4cJhkw5;smH3sq)^nk$n7eYi{E^p<7m@t&sf zqXuH|4g)o?b~Z3p0BBnEUVAnRi-BOe^7f1N;MT8aXp-)+7JpO!b}AKx*MvaPF98yh zG^F}R1*t4H)-JLf4oyHib=)uKobzFtUk|Q+3|jAay+jHO&3Z-y5??dDQOB)d*3_!0 z`_G9pO|48#ENR17L)P)5w+=MgW@L>_kzOB{RRxI9O9l!ieYMC#s<_zu>4iT|F&ev- zM0R{hn2tu@V#rJI@BqCvbTFx5Qcn~NWxrt9%kx~hPv(S{V%kqRQxL8T+}(m?GikV;(^GWuGZ0nC z8%UY2#ywc5jrjgpY;0~`nc?^!<&4gpAHpV*>kH7#uL)0@F!qh@$Ma{KT8bTP<0)1= zq}u3!T17; z3HKlzN|XCvo{4r%7}uThxkKzjt!&Z#K2s_L!AvH{-zb3YcWOtQNc*0M61I!0A?(nG zM+JRcfmUX3*QbMfD*pwuj+nOI#xZYBL*r0^8c`&TaCJT=b@%Z)Vj?0vj@%Eo>!M0? z=DmotwQ2}uQHgm2Q&$$RnYoQ3MmBM^=J_G9W*vbs!tKoGN)KX5H=X@Ysht%XDrI5B z@J6B>5=oNjk#g_qFMrM>T3R$BIx5Dyu|NKNN5%Uxb@R3anq=0&M*NYCwTH_aO8#Ot z@Y%xB9=7sX3l@ouD*+@MFsPQ-#3u&eQxk8}`{O4WPzd}HETWU8BNM$#@sW+rmd*Yy zijVcoQ~$j1FLB;MFBO?JJ3r^JR|p_azHfFaljxM$8fu&49rte%KNLg`C9eFE>D9po z#hrJqsr(9Rrf#R%e15`8{yPFA@z87vLSlm;8{6UctA4w{ExXB|=Qgw|mvVvp2u|6ZWv{a6tyx74{x{ zh*|fCaX~yD%UmfnOx`wf1Bd7798_dj3-<6ynl)89R#QkXBvCqxq?X7%-QQHY6ecqg zgT5m8-;Y6?%1suGCFgjpzb5FF=qJ8tz0HBs083N%(xP*zci(G${jMrQ;X1(8zxQ#@ zw!~;hvVvBbrK$hjr}Jv)Qu3-RiA|sT~R9)%EQslDo6jc0H-!Wk=k6It>m;tGnsv(owK{&8LCBkl5GG zt>yRok$1~!Q*FS{jI8Ckg|~yh@x6XWBAf;&Eh6_&auSQy&Aoj_BQB4(=LVdj;(fP* zdWNNbR#93nT_8glAE_b4joVZvm<{9e?!O;SDw`O0L6b9Vif8%sqn3WfG?w+#kCxEM zS4dM5UMQ`V-NbHsnsbYnyJ-&|eWxf7!6pfjZ_vb%q$Zjl5p|2WA@mZKn2G0~7WKc+-k8Mp%4j+DfQ_$SkG_$P^i zwcT@IKj1$Yz4IP98pZB89(qV-$Pd{z$ll)30ME(|VYEF#e~pfVk&t@Qijy)AISwiJ zIU)>+*GZP@-&<6qH5JlSC&hqU+`#W26{Tq&X7P9G0(%&LC0b5Ic4*h5b0fLWMGOuY zN>0!vpXj0{=-rrVbky4BIGzE~-_8^28YP2DY|%b^!)4q-%tFT{dC`t(rwa{s5xVkJ z=Yam?9J?(ibF+t`T09NxLRv`#KZLY?^My*n2=DgoyRMjyMW_X)c2j*G7u->Bl2 zFe_^1)O|7gF^ZV@?-TbUic7@BaZ#d|NV9<|BY2||0+jJ5BDG6sT+R68an1+YGe1O~ zW)~$J{))|4D>hI`?u$nFzem%jU(Su*q66uG&wE6%nv_L)+3uVf@Nf-rt@*Y3q92kW zijEc$_vP*>xbrq7efnP8M08zkcP1+I#zxONA2hsn)u*)L8-CQ|7Zuu zWp#kPSg?cDEFBnCH_ZL8M-6R#?XFfai#OJ>TB23;cBM1mHH%iQt|-BWetxSWX~N*5 zLVW!%`ElydZ4R}0$H7>D>3z-2B(=ch1piwoXX=n6-IT0Vs$mz^MZ8ib(_0is%N^8 z=DQ&2oWJdu8ko1em%HTNyM4L99HU9XXu{TF4@b+=v~7@J)!yBQCDvHm1sT(}0LuN% zo~0@ox9-B7C$rL;+QFngdNKr3Gw*5>l^vxavqjgmjeH0*hqjrCZW+y&TA>DAJC?+{ zsxmkQ{C)sGS!;YH*DGPX?(E!Gzou$s`)03?TL;Gg=&)xrZX!Zcnwf8eW1r*2RD3l)BC#gwQH(w;KCkM~rpe@E+Y?Z5Tw(h9jq+F>=hKSqGeqcXH zYp&u8JmKZbI(gE#-Q!l+sc!}H;n#S8K)Vfw`3Z=CCR|r;W1zRM5;d`pjEh{cKPL|n z(1w;buz_sRlUtp5K9%B(QWGUPl1@y)x9MhejKg4(=gw5-L0fIFy0$=38?`Yb>a}F{ zR8p_^h!VrnQ5rr816mS)&%V_6!TsekRKEA5quFYXqApr>=ff;fRa~~pJDaVm*Kee> zA>GmR>PQ)=4?Qbpy7ZKk(KCyrjLjo+bkR6Ujs>L5?~_wh9+juI08l+{rF(K*!S%pF zbaNZJ>cbo-d5*dH)FR%mjC0f<`RIo$eH>W$RE$q)j5!`%GCL16Kj+<$zVlTTI8(+k zj}>t9@f5M{m6A)@6tnIXczjov9NTe5(|Li;c%ON605N6RMt77CKJNf>>M-{yK*6#E zCMlFN9dQ1Ugm>k|Rzx$vRrUJMW4=X8`r}jmBbce<^+rW)zx6yNxgYYq*G-yv{5EoR zwQxv`n6@e_$b8sBFpMp>5_G5*@&`2}5tB9LWyl<0q3fAF_wJp3kv3|d3cUsyD@8(i z`bCmrRgg26C!7#iHbj+BUO)bRbPnePW_cX!%msNjI=8X?X7}4amMx(i?witUz&D*rRg_eki*~=|>K^x`HBqhei)N^crkNFW}o;Kt)>~lpRoa zk2Ie#v)B^Kmq^ZEjV8KpMDxVE4&tl^I&p|g#>utx)Y3n6=b5elkK z83Um9XTx9E2nJurA4|cc+`zW*x~WZi0a-Uu$B$uOxACWIHqW!fCCY6hWg3GfmeE-> zbYu!E%8k)=lutMDpt9n-HZY9zw4LC7FZG(B{(FK~@3D(xKkpmUQ#fVW6~%t84*LQ8 zU_jv{FBH_zdv_?F#WF>Vt$C}xv~ZB+y!C6q3kLxb4Pvx3k)4;#3H^c8&0a1J(B4i!UGl>$}0gcKuSdCDUy7`3aDmK=0?d{6Ft_Q z^7Xg@PIW%*viYEH_1IYLX68$LT?#%@L(Q?lBoskQO|z;xgp20M{}O*C)%adiLs!fe zLuEXKP{P08nsUxq23_PO>QZa_=jLT68(jszO&DKNe_5ht{6K6?UAUo?O@@`YigfFt z2IaJXh_Yfll$_zD<&|N&6C{rEp}_a|{=qNepQo=NC`=ynvrE*|G{2+=naGIV=*(pS z0VIN3zNRv2`+K~>v>#VSaMQXq6YMyo@Y1?h#Vip6W7s|+qzdD(&X9n^1orJYfGxdH;__8e|;4E6lU@0 zRcFZ|RAYImU-Becs_W~Fu)DyR=o7UU*embNVu5gKXOB>k z_7igLfe6zl^N%|MsVU#K`x(nBXUv>`s+LI`x+=yl*}0a94+*)P9VwOU%UBdPXn_&GN*2C@fhm(fYk)qV7* z|IWGm5`I0Sc(V=I3%*#_1Q}ATaxoVxm3OP91a7aGH^R?-cFOi zl&kxeRJ0}S=mI`r%Ngu^^XgG}**jNvTo8^OaO2k!_mA=0wXTC=jn1iF!I7oqB{>{T z?!@RdG^DcsV$6*S85{vGjlfnOzt1H*urC8NDt0UUNrw$9;f3s`t zjx6xQxsc@dHc4&9<~C_U`AYeZt;)tP)zh-?E-`iAG%Rl^6Mo2m2ZoMackBOzX+yJtUrUkiZCMU%zpe#5=1F}#&~SNUwQkENCh?P2a?UEB znG}sPY1CzyyY6*nNXP^cPw zdEvha49EjAPkJXO%8MII*6_XCuD?;pShd0DV;;U2;Z0`6AMP`Vk+QLA6@@5Z-}KYx zMc>x>8~qy=!T4@sZ{7%BJp|uFvWbPg+@KrfSCaJ)Bf9|i$7(_0&=B71Z)Owe+SaRx z)iTs5=Yum&wVgQxUxgfb%mt*J(|I6!Y__RPIvfTXH450EZ~wh{ux({&P>P|0j3?|k zxoZIMln6T@I2QJQd|p^xKP{gQ(~aVqT^69y$!?cpX^BlUaa}c58gVr7?kA(TOQSRk z+*o31nD{X6(N%>pUHBhpMDTxxM&d00{b*FJLM+WR*<$=z6?4CF(rx6Z&s*EGK-V+C z#lUaz;j+^BLDvfLE<)~I9|B3TQ;0RigE*%*@CTQVid?} zX>S+e*S+c5TI%QKtIm(aO&t*IoM91ZlYe_kbgLm~5JpA^1NVLJTR2JO$v zSDMzOGUMCF4s57kuiJlaXHucRF4Ja05M;^xTkm6<=alJh22^kh++ji{gL_K~vAK~wV3dVEjniYT+am7^r>l^*s zdm2gq`up`f>1F9Y{TPvNntU~wXB#ilI{9jkR1^o_*Ebh+_$k#A0qzHA!KB8weULK$ z{f{zZL)vx7b0y)h`F575n`nb5g~!q1i-RR-vNIPT<~?&H*OwlsBSUR4w;%R|sY|Kl zb^P;y8vSbSwzXT)b9o<~)K%1m(y*HRZRL9oUheq!wAHbyZ?)$t7G2Ae;wvqGKK^{` z9yvjTZd>W+k_EFIOs&wnrHRL=oYS!gaYAjpaY{Hvz>5=C&o#l^`7QCOhDrpp9Lq0- zK-1s|lDzj^=m$6i89YFeub~_#YsN5lA4p&aQ7?$Z2%J>op|IG-aI*H{fPbzoqORB{2Cr&^;V<`PFD{sY;lZ5sCSz#KkA%dR%)y$dOD^hBKk2A1 z>v>v>f2f2)G3$bPSyL)2XJS}Wo_D;LgtJ_&KKPdHE8RCvyCHkEit;US-eghEs|w<- z6CkX{$&!8(lVi~i9qIQmO!Nb1$%pfJn`KdhwEG_m2UhgxKqoQ`<+4>=pCTIh#yT~b zennDAm09Ukybknm3=sO@Fo}*u$_z@D!l+y8;kwLB=S=K4R|7)(yA@bgG; z#6BDFhlxj^b;+-m-Rq^rcJw>J924O&%Oe^!U#DPgPUbL{LL>y+h{Xv>4{a50!u+YS z1KC%j(atQd3GVjP(`aMP+vCVFrMnlWZezlM8{b$2r8a-}os0j}N;a*8%pGZ#&1X50 z`COn`2g@Qw&QOpijABbRT7qR<-haDhOhdTG{2)rmo1Lqc#`NQ}26Sj298ujs{OVWi zei^0~gBJ+;h^@6-{m*5JDC9cX-_|KGE? z-sNukUC;Y(Ku>Mhmy(mJ-Rj}X#N%F$|H(Pr--EgPXicppD)SmjDA}L-&xY5;(SJ}? ziu7FOAla$E-2bBfBwEZrsQ<Ch1REr|79%)|dh*Wgm26tA|EFNHGQ!eIwtus)m%Z$?IeCNeJf@F8%Lan2I zHS8U+U)6lROz1#%ViO3G{)|TR%#8~1WBEM-(JVN(!!^Yu%$rIR`NX$oB!O~Sb@+Ly z;9_rZj5exHdfW1|9Jf`5HK5>O3vM-T25inxc1)vH4KjSBZU*3qx}%7H%tmP^{A_BN zHVPhb+fIMh@HdN>SSoP(H*A*Yy@{1043_7+f?wc0Aw(tpE^gON;s-mta|c8839n7U z$%wT*H>PK@W`zgLr<8F{<_C)7PP^JFf7y1KJ|gF2nLg622zz##J{B*NjofD26`4L( zqbA7>F2|i_`$#nb&M#9)KJsE8Y^+90QjfiUvVe_U*8xh(5eouNa6tl)^J_Oeg3Td&gmkE8p&G!e!ENw zR}{{vLjnfGMX*Mv%`;lh1(X-v1XY(Wt1}u-(p1ELWQz9=ld?S=jr$M@t*C$1O7I$i z<-JPTW#_9-r@?}B%!zwv^1O+xoP7M^DZx5yzLXi)_e*(a=6s_-^71ca<+sQ0DsCW4 z8)tDGYo|8I@(G7_qpAa6#-l9mz$3|sKIDd3(dA(LlZH&mqu!Yn(eHSAp5?5*2uhsG zB;_2Y;Pa`+L9sC?0!Bu*+VchseDjArvQ>YJk$UO9VPiYBi}V~1g$OUq*#ZTi%apPHOtNW9$44Y1ER zF$Q#aAT(rI1uDf84hif4(K(lb{K#dP(Ml4{bxWe1Yk7I~7Nx^R9}+ZwYk%yNC+!M- zJyy>Y^;XrDqEI%WLEJ)CZcyyFVaKvUt*WT>Qg~t^xMiCsgE>nUm#h)iyiyH(%C^au zQ6TGTiyJ3v*4)yryJv<$u2dQ)TEn&#-zgRsfLTlJQD_rOP9~zC4wyi zFgG+Yuy>8v`f0@Vm5d>?iM^93m8c_H-34i)?k0A|uSwsmtl^5f2)tS)I6<`{%b^)Ps%;lTWoQ+Ex=UOVZ7wqpbUrpHxB)J0re5j zHL5Kdg6fge{sMM$`gDN^~!)lpUq!t&<1`RZ_~hU zV;C*`MGx?$aTjrs3)kE11Z*VlNvjVLqe9NoFT7VegD^*`9i3^63`ic?!G&b8kjseh z`9;EGFXjYMGps)to>ie{0V%WFaFvw_neq)4LGY;nlZ|WUJjq;|K@9>}858}NFl(B4 z5}DZsG@?!z<@1(2Tx5mPKE1xh^Gvs*he(6Ss9Q0Ekr@=r(u(WaP@Mp;Y3|v#E%uhM zcZ`W8}f0Dyh$7NhGSq_b*+gPb2~yi81m_2o^ZQWmXIr|B+c?;+Y7T^T?6F zP$3%f0F5#>NAm6!$gP)6h`+K?DGccNNK%r)+_zo8F!1hsThuz^JChx-GADz4TsBGL zCDCc0rQ{WQem?I()Uk-e6NXip*7RpSqQ`sgG!857RaCi{CVyX|lm&^IK+rI~lGiE$ z&L>~_kJ+NLIG^s~^LiBU!co$2K6#8gX%2z36^5jRu2EttB3J6Y9}k5(WFVVPtv~_F zHM$R{2G!p_lWH_*fGA=;ViME@;AVL!&f09eR<&V$_-H8nmL$^K;f$&buj~tW=Stcq z(9=*_HP@W<&Cdej)_K>QNy)x@bDRW3&CXC?{iHGC%r`6;^#K^WM_*W@$0lu}dW5{w zU%K+Q)F{M7ByUCfi5B$WYV!kcvDGVTjJvMb+a&t+L^TxWc)rVfnA(umvHV(Oa4xP0 zygZkJ%xAfit>VcX`HHNA)5F+Y=WA0fFN9(G**0`g2%yFzVqY#;MagR0J0;I_eBD;$?uJnR&#(#VooUV%xtUL+Hn0BI{gOI@8K7Ezfcd}ml-}ZGsl@@ zmP;aVZFsY_d1U_9N4~?Dz7+LNV)p`KiTW0~ZeoJyRI6t*g26+K;goSTNu6yMge1ejX-r z?XV~r*UwI28+cV@=hdV^us^E_up6F0p<0K_MBDmuLFEq#zbrwcngrNw!VO2RWknoj z{P}06qy5K)G?Kwvd+8l`zgE4Iw6jt>n3{#&uzFap4!vsdB~9`$*6*4E_zQ*mop=)^ zHb1uwv*?`V_bpRy39UxbH@h8H3#AQTjw&p!8%V_M4|B9Wf3W!jUGcQXd-QHtjZ(jd ztJP(f!@%GL@o+7ia&dQWg_1%pf$&at=-4wtd?iio)uJdP?JLtYqwd>pZ^L|W^*)wL z#Fw*IU@orHRO`8a{gEA2y_o$n`BzV@cU$0=f@<=2P>c-F+2>K=lqWypn3GLAYfYQf zOs0V(tR_;cTO30Rao)lv;)B*uO^h~xuoDvy5juUlgjgD53up#d&v~!!rg}g+?e|#R zw*!MO>^|e4HPzpBe0cURUg^Ot6rQ8JIVLt(cZhJkLP--+X^D8STo$iC04WIYYA{S^ z|AFQ6K6$OzMC+Wj9aGFmLZ9u&JbN!x{FfIL{hpS+B()2hBfDf`n@@cf(iWQgc?O?H zG>3x|bET_l2*ma^?`mtPop`v!*@=v0lTdu6SBC^*ULM&}64h3(T`3OgO0w67~2irt}^l-x9d~y_kU)#b9icL zaU;HC_!DJuw9Se4T!NeF?;EYf<)!J0Wn(cT49K=SVbWIT8^V=+d9t2*gU8G_;!bi4 zT?&PUV!UDdbG!X`q8E{rr8GvYU)}A`F4NQFws>5d)3#!cW^b$2tZn`)CO*j%tc&-M z%6#%{VPxUzRSoE?%ucU+($zoS+ciGNY-V8F6pJ1)9&ghe zbN-y2tcSxFnp77^`J>6?2rz;c)mg$n+rHocOx(wx}CqJ zJIM}dB?&d7UQ9Nq`a-rcOq-PL(Bs&TpBJ+m26koYsFf~P&=B*2$Um%^va=ZfyAw5D^I&bHf@9W2~MS(LUXlvez*MrgH;7Q zRrd-96dizh8y3)9ZZN1JQ8JtcjS)_uZ{#J>%z<<37Azt(e7t<`eC)$YiLaFunQk}l z*Qd}QeFe9A`RayfYMN_cjg-X@&vAa|Ru3W#gJ)Nn$IR$!d>Q0&q;);G=_40F_{jV++SEe24y9dmprRiCG8iE zUk&bhKat>oyQLE8s{-n@q$%q-j}cWqZKaLP6*^i~Lf0=vbuoo^i!P zpRQ|1=zQw4Qg{=m^ZkjTygjw2gX(vr*)SKW9fF&?%Y;BtB8)h8f@e?0|fetlQYy~TzCWA>Oy zFJOub)GN&fjswTno@CKp$wD7yQWSj2z+RtpZ~U$zma~5fH!s`^tyQsMZB=m^=5wA; z*2TB>!gRO7n6!oW#WJGZ54SBLgw3ONBP|uD^?1w8)`R{M(dE$sLIwbD=(Eq3DOtt< zicP=YI&ekT%8rB;H=aG0Cn8x}7NqIuFP9#8l_E4y2vLN8#fOJS>SLySOKu2;iHrRh8wzrsyj!leg+5Zi*ZS+dyDj{L*=Gfw>=>++dZGjIHSJ?)B5(?If}rQyBJ zND(tZ!Odf-1qXQ$S5*>uHG8BS0K&h*ML1&?0JMpq(`f#c!j)Zj6W{&XFMAaYQnzyL ztaItZ{1_2x5~#DjTMStlehc7aF=<#>hN?cN4hLneD$6`rd9{*`8~{a*-LB0un$&+t zCKG{Mfq$S}Jf4BP^G1b!lD2B3MfI>vS*DGM1Qp-*#o?L>N6=;^h_5)bo@(>D6%$GA=X1dQCL8v zC>aNQ&ASBAP8O_vxoFJ z#uywFPb6(Qoh*5;KdE`VCxWy`e$Zm&^BFgA-EQMGD4zr}w!%&b-%s|Lhb%uoNx-NV zPEUkCtmt%3t;AThn9Ck>`Ml2;UbgbPWRJJx1`QjJkC(P|)ec$+FYU?SWf4`hwDC6= zC+*T<>9;@l+-@_HRjxc{?dx*Bd~89RRIL7^mSR`*$~A^5U_N9>nN2At-lXMY;7Q0# z?|QS@{b6$UNg!w4z6D)Z6j`lF4Z&;D-uA=F!s1@%4;_1V?hs`?v_^=HgkP7(mzmN0 z8S~@d!#RarnA>hiH@2BSY~r$X!pP15c)Rn_#U*-MMRU*A?-Dn-*oOy^gPGQekO$JlVd&QmX?qRd%W^UL*>T5|*qEko&E4=cs8k6EX>%O1d?E7kGk&=tJM z?CYe_AI&@76V)0)j-WYK+7o_@+taFyaWYEZXWl+mod&UQRCO!%R^KTnp7n{gbO6=64>DLmNNrj;dPshcxun)be-8Rh<7)7Xb1^Uo>SE8}6&VDdn&2>{B(){TflU zAyfNwV<{0nNE5=oIzE@yUFBHCu3bXQpKZbvk}Z(cIpdc+ftsy*x6@09C)9F20JQ#QDmFGU-tyB7T=KJwl@NAcvw&}k0UX_u^ zmK*aG&AoE(v8{mxe{Ko$O3IpDwfzSSnjqKDxbJ47CaE9`IWyYSzD|HBHuU?>0{YW` zxEh*4??ur|0~;bM1pb|>u`F~(P-ombWXI0MKbhrsMwd!ZX$oud0k02YxN)AiDx&ZB z^pbIU5csIg1u1F~eKg-VJTH7+(Zm-NyGND@9?aD3Hfvct3FBnNuWl4S+9&!=K!VJZ zO$K`ObOamVuQ-q(lfim#?dlM+Y`@bHZTL0a+-*FKHOJs8NEqm#zI;wjQrtb=x6!Np zv-bGBcfrY;+a#2w_JxoVc(YN*s&3-WUaJ*s{TSjgvD;}>Gh+T8CJ%ang>*`WJ_^O{T?HiNBa^n5&JC zOf0u5d*bJ8fk_NGe0nO=2LAD!TU!@md?MnmPS(K8>TsWhuG@DBT>-pDSG5q=lFY<# zTL&!clo0RY2wr{y&UYsl$B;EswiM)(;em`E0U~e(9AGAKWbQm#AO55`zq(IrQpy8k zL_wXke-ez}8@iA3fO-XRy}S0pLVFk9H22cXOna2C7MPEygo5i6oYa1TVW(OXDH^Zt zyo&gOY`4!+W7g%^Z@2k1 z=CkE8$f%-~?N^QgmXpbHlOk#7UB~Ot-(*ucbVv}+kO#SRp40VD9f#-Uv*|rNZ6;-w z?SF(n|B`4IBKw^!@rjYZnGbn3O#!L6_9MR0>6T3C)LaVUJUC9GJ^DNO;a8f&uhMki z_?-5h5?%8Oa6&Pp=_UlJGw-%S3vlQl>sm9khy8Ss*#$UcyD%v}Cs`;>=3US|+hISR zFm>kVySq5~zsxm2yz3S`$^Un+tas3!tC;Dq`C}X#rKqW%HJ;47CO=d#+r@LCKfnrP zunb8)doF~+l>0Rj44~9IVPd+gnL<{N1#i8R9?Z<6>@PRsVnE7oq`$?4JMT#2l&wnagi{Q zzSAVnoaK_0xDZ{aZ9Fy+;V#Z)^-iPF+rgufg%NSVA+4aEi_jis)aa0D znNjavcrt0Mco#v15?TUuAdJz4&>e9Kv**n$lx9yEdi=polx9~{Vu9HV9w@9-W*6zZ z)v|RBS<&%cN3U61$aE*`f2Cuaq#svyowD6UTQ3VDZoenY*sQ-ds7v(NSTPruub3>P z{x4h~(l!4MKVlNw0-#gOp(!HG!7an=`8qi0TCM zMmppCr2UeUf;NZY*?;!gyKL8%bkCrjOu6B7ME)GZ!u_F0cnGXDjPCLpzWw5zlpdP; z#T%VC6!(;{Wg0FZ^Fx5|tFPpn)Q+4;smAE;8~Sw-{A#xdh|^Fz3)9gfEb8AyMzI*; zl1v9Yz5ps!T7HB&*Gj`pZLRQq!S+agN;Y98p|+wL+unp_jwROz4wR~~0As#_EO$5M zHI>GJSZn6a+iUv9f#xlGsg0xbTMAp&$Jq86U=?KJ2zX^T;(w|jc!*C#@f`8(aeGlv zyV3C+>A0?m?K9-B^zQjY1|O0ek~iW&Ewi={wC5HRb6mXapfH21dxG{1Wv=4_Hr;5c zfszt>9f{gkQq2Cn3Nk}*i$&waas7=S@6r!UF$rksR?{)Eve?UoRFNLC9zccU*-S1~ zWMmmrLHFEJkzy`JuVDAP%2&6{vy^kt>RR5T^@!0DJ7V(r1c^{Eu=2}{Mr1n2X^I_D z!m(~Fcn2^2{zu5*3BEvL0_hzI3ZE@(RMou5)JT>JGlTWDJK7{Jw}9f*E9RLJIt%FS zZDXiNpSsHv2#VF`1*;-p&UrzmW5iQrEJwu+Sv4^-!y{1%_BG*n z&W4Ap&2Ko<*OOklcApea0FwzsB>>ulBtt2TpRgR?-N zr!H2I&(9GTiVDDm{72xLxmckt!K+z^2vQs*mvNy5lJ(=CLMXq>e*l3g9sB9R1d4`6 zJCVji<8CffeyDAslX(-HB+lKgDWL+sag5|NjLOz+sEO}4 zDSW>kbw2%WfH_U^^^FZ}()9tHUv_<5pV|T%=tA}8wE!(aNc>a6m){M1pNkkIiA0b> zJ&)4Y30n{P30p5fdqT?E_Kg=^KAX{p9=UdP1(pVYs~CeKJ$CDy-H?%K6*YCSQ8jkm zrv#nB&pLGbUR5?I=QJMZG$KSe*VEKTNKSGZ1a|{DB}LIw$bN+NTrMM8j0;_!+kCkE zOec2*eM6dZ>u6gNtx(U&Hd9L`U(LWcvuXvzhp2)x$w0{dP)nvVmst$az$kMjOokMP z;>{UYvR7?HOj!%2GGNrA+Lq4PYzqhXEOy(D0&A-*hGyJ4@CLXEz~ zVnpR1As-r=Z=o#~#Jnb)c=P^ji{OSR1V|UVqVFc>Kks?!!+Py7L+bwZCjIlSbwOI( zJ%nw4TXZ9T0>zn>!k*L>Hgh%M?DNK+d=RnlQ1cqIAX$2=MmRK`1Fzthsbm(ed`^Rz zL?&7Cn%8S%!&O~0gXwv;!9BY}MWmHx4chXuMQqf{(>D$eLCLr*?2%=hsjd|jfthsO zXc|9HHd`k4B=*VYLz$!UBo^-OWGr+4h0EPB+533~{95bWKb3zKT)}cE{o|u`?~X9- zqW>#wbFn1;vSI>qVti#`eX$_)2c#5MzVl>p!q5ZwrB4{h#`oVJmz1|o)L2OT!@kjNz^En-Ca2#Pf~*pr zpoapM32Pn8{wqMu@8{->deGkNwf1ARH3vvgSD#O7m2@9U4q$mL*)n1zV-OhroC$i= z>vUz>j0yyfBGp-1_d{RZuvt=+eMvINK&|e~v1fteqDn)ebg7V7Uv^2c*ZHQD=t#^x zk?$e%VUIt*F%o{Sxk!99BaB&jXMazo-Z?+Ze>2kmj=35$)60`zb$*dfcK z-J&g&+M7NJ7aUnp!33vf66SjTHaQi%JVp12cQ1e486F&pj1*r{H8cPAW^!w+d}77- zH%gu1vNe-dwBB`o3+e3j#d9j!W{sEI2kl{mAqkqVhO(`Xx^K5qUcOH6w;n=+DhjIE z;zaqaGd=S)S^Y0{&sT)hWfJ7_Sl}eeGZUYrQ%5&6D4z1oEcm@iUb!Kyn#n`I3``l1 zR_xC-y7Owy#g?!VaVSPDNc~$CIT1_x7n)};4GQziKqro{4TU)qjXHa`6fKv@6@~=G zmVPoA@YnOrcsZpift2NdMNZNM<{$}d#0~}+Btf`)=PLVYjxo%VO1=9FIjXMgCy3)?O9^Tf%`AM*hGdLRNn<2la zNTO^-73I&fLrxIi_#?E6R2Be9iZ(bQs>QQy@a1H23K7{uKh4{bEmq7S+tMxg$ILQj z$ns5!8E=Yk**^-t}7}NY0kH_&p)dB(x(Kb-7b{jdx&27I`yH?s| z{5NH+-Z5}Pb}BmCWqgL0_-v%349ZnsL3BK)VHAhwzd6bb$;UfH(2)w37NE55;2Jol zTCmSE-H@rGm0)Taz~DZq`I@;nGyODJ-en%abm`9c8r5uSK#y2qaf_O7X>dE*I(WkG z9EA)&`FlNiTQT~i(Lq_$e-fk5nJuJJMwO@-D@I~8n2PgJr7GsB*}F?lZ6Luyxe3)g zi}-V~lrNox7!Am3R-PWV>pRc z6c<|DWpiQ2U21{yMoiB9U%w^2VkouZfqvHtKV+hMx7&oOn6Gi-?u_)FNgq;kHn`XL zBk(jVai{yEDZM81mev5{4jVUyJ({q$*8rmdszi~2i~lSl{fDlU_cWFw$MID+*$=6# z3#j3c76fWI{@M$u;YjwIs z-9e9R*LfrVQ%uLF#QjailF;)XpXhIuY+w9elG$tdR9Q2ygiNbk*hsMz%0MUJ2=fI| zG6D7cXt96k`DOHKKY+5+M+ENw7!=*c1N(mgwcz2clozRzB^Cm%RsR1ub_xG)>2T{T z2~Rm3Ef;nzM=<_|WwcB?CA*pSKHD!9SXr`9LOYW9?yUG^(WP5?ZruurB|Hl6V}0G< zNr0#BQY~4tWF%*awHerb+mq*&wxYTpQ7Qc z>@Tlyz3T?y$*8ZUrd6>;tnTvrm0R~gEobFdGn8-XqpJ=}AG|dL*Rx5fmW>`@s%IYP zTP+W?p}&w8`vGhuRRRGJqVt%Bi^4(RlA|n~<*bRYICV2{Am`Ovm z)IH2v$v(wL_@4qZow64I{kKr1q8Oj&;A>MVy_pRjy|N#Ln1+IE2pd$UWnZwBiVHjp zoJiq!L%}%n`H10nf#PhY57Y11fT;V&hNp1vwWGWy#~0hi4?-0IpqlmWk@zFM{Np?i zAlVQ_$opo>4%pJ?c4!3c2lib#Dn3ekl$dhhcziZ}+*I>`@76F3Unmz7d_lUoJqgyJ z976uC>x)1XT3@W)J`p?RfvQWa)iGCwkcNgpON5WFD*tr((j-8sEZ;q*Osnq(w|~+{ z5#->^vVl69Bwq;yBqL?+-GG6{G$85{@J?ji0i-5@5DhL+s;xcpmsHz zmTREEH;p$SI79nOj#>>!%9H>P;jQ#epIAm!3|!^=<_o`nLV=JYUrD*4ORc7RLZ7Qm zPzLC^1rnBR;8}t#vq)>#(dyB;U9HgjCl3}m4-;K8759P|K(hg!2>*7ua{icHlqPv@0I=0?o2l~@&kYlTwCCyY$r)PIUs>c1g?H^-1sM!uCSi`PLU_cZ^B0mIIA_{aNzGfS`13aC+uS`v!9(= z`RH&+2yfB2?I}jyYdI0Ar94#88nrrK-czz(&;VcK`Tct0Jo4LgA@XscnTZY{;JE1e z@t!@8$!}0ZUA^#vjBW9D#q60dq$AfbNGt(JsSz^#w_VR~` zk=C77-~UeitYIpkXDp^y@6kQE9ZHVlntQSE-}TN=(k-(kOqFh=avZt%f$lp(@o%g% z{&;EZLkk)^W_)Fb8?khAqH%|heRupaLWuseLf-KQDCy_WN;U#&bcu<-ReIlZ%_M;S zMVRl@=mlck8dbu!KCB)lUUM-36@J#Uc#Y*fgk)3U!0X$R-k=TKJ6f2{@ zp~az&tIgs(0(ENAh_`#R`T|KW)rQ;VwwK%M&UwOu0MEe3*RHR>0rz8@I|3i0zE1Z0 z2|g3=I-QnAsk_+5Lzo^?6@Givv2rAy1OYTzFA1oA4Y73YyEkBGRi+D%OQ@bHF`eT$a?)l}(zLFLywTHHK zz`YeDKmhw%$6HX4c}JIRN1@4r*F0_cOU=|bt1F3x$dxb_I;0r7F&MYsVV2B0O}O@H zr(c!?ex7Q!p^0nfvOO~Ga4gbywHQ3B;0&r47(BDhab9vt@6Fl?B zVe+OWe0;tN@WT~pi8B1FZP&l}crjv-Lmyt&={=3GmVxA&Y4Pc*T1GYkQH)s@!*71aw)fLa^&vO-CCKDnI~@Zzr9{D`DxC*Pa~_s2BuH#Q zP~Ab_Ob*3ly4*<+HGKhDwC)9|*CorOAaT0fhdmvGkIKobVynyMNc|+{>yew!kvjAr zHy$o*_;M;4nj=u*f&-OC|F1M>?~RLaJlN%^8sP`!8d&UF&OxBh91KuA4*V@fhhKAo zqA8r{a(5-1i1jLZFkFtKMhoS0jdFzrA62XSx@Vt;&@{5fhC zcdjOIvi6ZMeT|IC%`Z_0CM{g|a%`she+O2ePJDHLjAt#gT=&cNGg%mnUNuuSlQdHm zu4~PY;Fhj)ScISWYNqOn(OAbyn=G8G0Xy+kcnFm{dAjEBOEmm*8S4KG`3_EBo2Mti zqL)vX2boa(+j}EGp~^2(Ck&SUwa%l?_9M!MLd$(h51Oq_J2I5C4T_z$EOSH%!?G^A z)K3P~7pyjEf)WxB=Z!;h#hG!LvZ7&$WC7bVxIKe6Py%a)tEwi|AksBNo-NYO-)cch z#e27r3h0N>$hiGZ(b+ZMJD5H)__dLy?3)R4vBpDS#(iWHTp)`?tnysCDFJO#8>&(7 zCp=ngeZ%)BtMW_WG}d?-No+-@Z)gpivOXPHLIM=BcF{=3NAO}{>O@nE#8b)o%cW}< zUoD*Jk}~&0G$G4!REOt(;GLkLd^HZw*Q|dm;DV#@z?krR3xy+z%GmrG|Bg!DOZVx3 zh^cpcQpG5#Z+0O^c!IClYMMpe7UGj%oY&{|W~m?z((xujNXo}-(Ny1Rn7Znkps0U8 zhyh921I!4J@vRnmz=ZZs_hQM>TuT|~2RH(@!=EzpaC+{+ zc?4YCSekeF@>jw$NY3~I*Q(Hu|7AW1{B%%C<%$gHDqD&}0p%%N8%1^7Jxol1Nv~*I zP0Nl(&g*9BCcpO%=kCgl|I;;eEZK<19dJw3_3o2Y|9`TcJEK(Z>91{GOX?jik+p{K z(~+=}(O}Q$wM!($J0$|2LDk_$;w22=(Y0w~4TNoI$5KS^F6Ovvd}zt|U_aIju}z@Rf5 ziP%RSEhgTOVv(7pW~Cpv0>e$JzadH~sSRPtxsKcKlNF)zV`NZ%?=|APisv&d_&cSU zQyZ-stQvRUZZBHXC3N?7BXHa~?KIn64oYCsc>shZHE?-&VR8-<<*g^|@&p_#;uE0s zQ%tMMpra;bp>|OV_{gP%~dw-svTQVLN z&D5)bqeE-|Rz9$VOL&PHStVdMaTB(X`{g12^kA4ctCZ^^(?fmYnzmMlc%?FB*acE- zvM;bsC*{OXdgOUbQQt6%K2(7pjCb_z`%ob^YX|FO5vvtvyJ_4E4c@LIJ!r)J|H?4S z&-{a7UY;ixSoDp>*bKeY{eei5g7U+q#qGh8XFLQIMeAFo1B=F5RP=XRxIaCJ8G${B zQ>-ODa^iF01B{zj(W|+4xJqTNHwHTa+D?tPO~T`{G1d0gbBd~_?5#$^ zv}awxd8HFUklzgcnL0z}2k0GjPhjYJe-8o+%Co)~bgvQRuAwRi)}GhQ&tCRbtEzTe zrFyl1f2bQxo-}__WI%7JY=ND>l4a{#g+Pl#pwSf26IIG>?9T%c&|w6~t^!ja&p@9M z?dPOFn}>oi_2Eha9T99t$he6JIx1f(dK!AHECEmQ|G=6G z;@{BSC(gX||1~={*Q8TJ5t8HYdmn0|23_|#gpV-6N*{W>WIoK3a&dOLl%0{em6Dwi z^K^a*<8)0mV7a5e12qfiDdH^{U#%4o^lZ>mg$Ii&u+jPZPr9sX?d(UWNmQ4g+L4+gz%d&Pc)efdInKGn0 zsA)#+H#IfYD(BB{OEYAX5{=5vHd#t$V0HhS%#OQzdbcC{x=%8PtGZ$`wj>cW7)*yR zX8Wxi9GcE1A0yah-e{xabXSralH)9Le?n3zce3nIO3h>3q}G3=GSm@x(2n8<&_Ph) z^~0lbYY_4`p}@5Sy9=x)~ia)IY?L_vTfYCaJ)M3rvv762u9OQ@#4$A?+5 zeg7k~Ca-|V*IOk(AO{k+B9WPhmCJXxd;aRWyHp-8WNa^0xWpt*T!MrpEK0V1@0%3H z?HbFlBX;062v_|5cbek_KW|@(M&D`hxAvyXq~(vVR)DK)HG|hN!}lBYF5X4PnEU^{ z3i$53)0FHhPz=(FJUZ3sWBBB&4p7>>dpZ*EGI*N+SFeAR1zS=9=0|>+(Rg%mY6UBp zhc_q_3G%p84EhfH-73JeqwaQ{15fh?7!JSQWPbNi_65V?XxTe&^51MK+$5q9AX3%+ ze)k&qvcy3NNIudf6SBzn6(9ts7V_2oHSvyXWx#k)yVFJOK*4rmFhzA@un6;ppV zeBW=fl@}7~Ah5WPxbh0tCJ1p0*5(5?8W67hPNGKib_)kI2SJ^p-8(s8)g@8u0tWz& z&VVbM4}W5TW4^)K9g|ZWdwx~1WwzgZf%|MGdbbN#cAi54-)&BafN|*ROALp5;DLx< z{_Mn4un7!q`g{G^EYhb-xbg!9;R?6~;wAvD#RIDzco5SYK+oZy)8K-1i3}&X%x3Z! zaP0~|MaGsLmiea(tO&FSJPQO1449S$j1qrCGLMrfJxMM&Mv-AA#$u}|yVC3@-QKC8 z)Rb0$Zc~Qk_F7~!#^``;MK7uk>B7`02=@)!QDf6gGeod;7K2x4DJ#v|m{4#9Y&T^C z-XPidmSQ|!%^G7|UXM1)0nb$LR*=)KR*ytYE@xyIf=N|yziw8YaVkdH0~A}0bn}&j z>Ax)GD1v?Bg0S_Q+?(zVJ^gYbFWAQRtO5Tdk=2BxYFb89StcDiyD_SrMC`2k%vk34 zim@P>O$+}NZKCFjlF?(sj3@_mBn(kj{(fCu2b0ld#t zXb(U=MGgsWLjzCU^3ds>?7X ziy^+?Y_|#|$d6xLdq{k}#yRxgBgJ_)W1Z#eEerT`J$HxOd}pY665}UMKyq5;77M~d zIBp#9`4`}h=wqVm<5c%F+xO!-6oTawVDDS3xb&si_eA&~+T}3pp9MM64CYE9axw9? zx3%ZGXaHAza(5ZuzSA@*TRU}sW$bK5)nrknM^q-pDX^Ae1D$%`FCzM=`M9xsxwie( zF=s0P5GJcH{<%QOX_=1Bjq5)y-w>of^A!{}G&gF1Uxg>xHSEakBH3$GRox)dj|R-I*NBv>e!SJGkMp}S@(c+ zpE3ab`|aktC9V*LhX36Yu45zpZ%V#ixgcdd=vpf&T5xJuvNtTBSVC#iVcb2i_Ab$? zScV?YB$!Xd3QVO3%9w@(ybrp*AJ3Of3x(ujaFlAuqB)w!2`Vc+?FscBGYo~8ar4^; zmB<*&9#|<>;9HA%@vt1jgL;b~9u3c|$a)7tXkL@Xe8&*q5qsL10>BEeYtNz(|G-HiljyCS8k{d&VxNQu8!T>KS95awu&nco@;zorK>l+TThj@d6nkP;X9=1ps%xzkt_v z+TyiLfz0&M@Ntv<@t}Kch-|{zZAe9$=%tD&4;{Rt_+{%T-cO@vTd>`a?W?g@rFB4@ zfhdQsW~5unlK{pIfi zBo`lsFJm!YgL)!}bW`A+CVr&DYz5fFrq#U5Un~nODwt-vm(l^;H4D`uzcyfcJadr(&NM3@BX?*pH7X0l?Lq?J(8{(SbzQN8-oZsqcFlV^0H- z&&$x=81iw^=ErRpz_s`NFx$7(SIzgi4QUQ=>?vby-z7qHNUXFJ5$^#)n^&QUy`KP*8svwIH@`TOH5{yotN z(Cj)keBvGIX1)vI%Mk!l;QfUWFh@KE;D5h)yl)Z!z&PydR+YWpSNXo40{`Q$Z3~G2 z)-NS~de2K;^MD(0rY&8&=?{bM%4%Qx=k28opU++KLdUlonR9Y2AI+XD9=ATB9Dp~| z#Qwv_h|T>D-)9z-WbQ5;$-B#&13*Ps04vpqKR3fP8S~T%o+uq<*Xb9 zMA@Iflyd`W_blMyU=%@Bwf*Id_1uWvC_GEv?&7n$iZq^q-y**EM1Y6JgI!TSKn9aw zQiHv)ILd(#2pwsF=sx*^6a)sQk&wAi4%OUpzOEDt&ZQ^ z3c(QesLR!N#0ye^uAl4HgY%yrdIU83?u1N|b0$pGAty&#=c1H0UVyFlp_c0l>@Sp5`dpK|1PIhZ@J z^j1hWOs~F!R3fOp3a0towdcBKA67OpXAEb9u%I+$OnWxZw30{1+=i_5F)lfR?xWP_ zqP!|u1maiUK?Ayv82o%{dqYTIb|9lgs#y^*SSnYVvWC(ksn*mUf{+PRk^y|79er1=8U?C7Ah^mhJF7OLlUh>ON+$4D*()%lC57nYD-P3yA~RE>w!1BIrnj%;QM{ zs?y!K6(|WRbXO?>q`6|kKD<1U)?Wk!!WU(yTe=KSu<;RxB1Pbbp;wL|0u$(Ak8o4( zu#SawB${k~$wh2drt_Wo0+WIn1(lg_Ig@I^1!2P8qtM3d1s(JGuI_d6YsxvxmYo`yExr;^t{rT>yqIOWdUkzfo>w9O~?csaAGazO2- zvX;m%YS!H_*(Lr-hgCrWCH-o`y}N|@eCcHz3}euhlr8Mv zUh&ifOZ6F)=?L+&ex9JHbJ*Axe_Qt&v@3Q!OMK9aJKKBv;Hr+%ltq6?D z(W73K9Q;<{x*?;~jE_CUfUJxe2d|^tnzUD@0b&Mc_!T5LI@u)dWGbQ#Wsg$SD9>03 zm{^M3GB`f0IkzK72=g3wca~e8^QTw&STPdnhEM`&nmBT$oHA4j`X_=7l64x-ADwbR zJy%A6WU&-twjRjiBF#ryQF&1jlXRL2Ya@3*sasi=u7Ss(pd0wH2&SrG4^D+XV#T2o z5VDzdNxmoicsi5kd6J^^D^O-;&O8%hX=Svxo&6yrSPCllJZV&tr$)bd=(RKf_0;H8-L!X>Fx0J<(UNO|sj$WrUd%gl#``!o+t)_{&(1s5A&iy|VU+^5? zyH!*kW&;QvP%7z6cI0$?!0Gfq^Eiz`Wm_IF{rqL6hP%ckbAij-A^l0LL1#3kB`?#w zSBTA@X?ZQO=tOJ?t+jE(eHjXhbu_&DfMX zC+_0S(s3M$)#n44g%#u$3H%TpRS9rnBu{kuk$gzXUD_}#*CQI}IySnsg)}+O%T9Ps zv>rCn7H6pxTBZtYi{iqOnG5N!sfp;NvYF{E`&r-W_rhN8M2!uW_G8qu`Nq_QUEhL= ze(-iy{F+<6l8RySN%<8oq=s3>e~g4W#+pBEuG>UDokf;pq#6A%BzfnM@Ka+k;+=mm zb(xFRo5+P*A{nN(GBA-{LqLqpxN*4rOHXLUo}}}PILV$BePNRM-d(XsPCZKa&RMax z`Iw0ai|&{F>OkVvY~>;!@DBo)WIYMhDe$w16eIl}VzQSdadi=1OSt|(njZb5pZmlB zYdu59$gk~}}S zC&_NX-G96Wb;>5fK~o9KLa|(dE3xy>)@ZmKLv8*P**FN(hL-~w#e;GihkmREyP!&k ze;%J!jYtPJUAjVwnlJk_Q3~%cmCp20DII17x+~{t1^%7uTt@PAvYfqK<>r3(%!$^| zqX?m$Ux0i3~5 zH!9**q2xto_a%Y5AGh@sB^uhHclYb%XA{PTyG?hRd$vZ}q z)*is@)0x%u^#|s*=Qg6r#Q-YXZKO2v_J+ZtT($5sikuKJ(loP*x+v>Feu zi>IG$g~OM0l&tjt?&&O%9}sd+a>3scrzh?MuMse~Nz6(p%`Oj~VvAt+9ZFF9xHR27 z;oaEDCnN%tXJUDv>Z@RPaA1gXemos|um?%UO-;X9+LSfe4I&QAXBruv-^4Pv%5iOU ztA)eiI(}RP4$?-w{d$+7o%-TEH10Em#A~^>AMJX6hgavo&ceCc9#eDM)bEl%!9l6E zxooq3v|kbac*S3cLQnP?Pp$_N>bB~#(G!{PW>P~GV5nU%Dcr0#bkVx3mJ3DiZp2Hr zNoZ>udYM1UV^0#s_>GG-Ch25DwnM6f=rH=wJ!mECmKeXb13Gl#t1=N@k|E07iNtrC z*EsMj!iAH`n8@sg;gm*~29G_B^n|l>sLWKpkrR_UAq_G*C&fDcCXa9G0Uii8Aorej zWpmAC9ilpsRu5z>0)kbrn!o+Oj83~5^Jq3rJPe;EW;3Nyx3&&=;?%`G@_L!*hYYM2 zx`^h^vjxNLS)Sd&4w@TFX0ar(r_6t~Xk3OUu|D!}AnzRafg!2;e(hX$Do{`9!@&E9 zf7yp7NBYa?wOQ2vl=4}{DPvcomec2eLPbq(d_vvAC+ zb`h`?-oX`>RGQRM9~9=c5<*s*I~EED3hv?rd1h1|yn`ZAi>DIko7Jchr<-C0prpO`6K^7Ou$4-z(i(t;U{ zU!#LbND95EjcdX5{I32|Y9s)^PP$OS|GYo(;=X16xKkGR9>IUOfHY(8b)zAP1)Y+F z5QjL%FD*Tf<#K4fUoh5Ho_#kQ^usw+hEz+f)?tDNQ}%d39}r;BhO(tS1Rr@%$`gO2 zoj0T>wKO_uSsv{}6dot!rphE@Has;HhE-cX#s2HVXgRNgJm(~A*dA{JHB&s?dce&# z|4=d{u15NuZ1hX5^Lps-T^b=AIKC|U(#)dF_Oq8j`Uq7E*voN$QrAye*jN*n0@Jl} z_ZLJ~MPX_ue1za3xSFYvsy|fZnmh%+RGRn4gl+Mve;0LX|-vBBcUjH!7s(U+;wo)706#;u^K-ue}Ktsl3UJ_qQU?)dBg_PleDL? z&*L3cjqWrfC=3hXc#|^O)0L6Bxho!5=Buot)EWnAwRV##u16Q$j4j)1*}kvf{(loj zHnsdVk&%?L5vIgrif0d&y)yQ?{;s;0Jx^2;_vpIm06B-?QB3=32PV6g4V8y+hl&S4 zy7~mkzoMUUxkoTU97Q{`&(p88a$|yvlGXpVk@xAiya!YaiH|vaMCfX4~$^xQljfV(3M@FlYH^ zRqW~MJ{{&_k1t%h%+MsvS21be)YS%tNQV4)jzD1drukw5Vg9lkBaC7^65M8pt-?SCR}(gz8-q}_b7Y#?j8v9MiaL?UhZGZKZFQY2K)SONVPJw?<6BKbP9p7RVpbd<(1M zRx^kQKO}a@wyplkMeO3G!qEu_B1>G&1;=SMb63XQsty-Ql018<6J%eQG_K~{)tdz( z2W7o`@8>4>MZ;}_vpvM}u3x~F4Z6^a;?B-H4GRuA-i~zi*F`{11&D3B`2$(N1Cyi! zDd_}s;?H$2yD9XCO)<0BKIOPX{XCq5l)g1Rh+n3i!Rp@SrCtyQP5MS!p>egw$YeRG zc-CrY)@tZGL-jh(^)oIDZ{dw-;x|WRUNRaT`P+6zHjWf~++^ntSt6fS@dY!wctXQS zlr4hWe{t@u(o56x7Yt;!=SYus59>#1H2sPK;RZ$*> zigUS?yC4bYoerD@MC)~!wwSXNgza3GQ6QCwp@WxHxynXR; z=&wnnU?t$(WH^55d93HeTQp5&?(`%?^=9iq=P`G?CoV0xbzyIb4%SmVnSHTi#ql3K zX!pyJ2mK8302+FZ+Tfn=C@SO0$tM3&Ft1`%j0SaO6HA#}s@^(N9h&U8>|f-ks;-xT z5S4J7HjA)oIPLvYcRRyN%Rm)AjCG0!gJZ%ZZ%&PMhHbM2lWI2CQo_bWSU-xa91Wo z@IsK19a6I0zHWO`yKouc-KyX^IEY|Y{F|DXvvSnt@f7cOksNkK8aec z^!9@Bv&i|JHx}rcRmD(tpI&8;W;lX~w~d-)Iav(J*8>qv0L{Pg&3+;uq=&>Mn2!df}+LONi6S%-csJ6pD}u zS(RHWh73Z7@^d(Sv}k;Rx1}3$0~{8W)?ZZH}jyp--7%L3(*Om)B%DlukS z+4s5XG@FULGaTFp2)-Z6&EZqNUVCqsM;c+C>m-#7mn;QB@CPrHyPHB&UK6iPM>u$b zwnL4(h)%IFTcB7xngohJ2}q{RMW_xU$vDT9&nE+j<60U~EmyRtWRro`*2!*puRnP^ zV0F%Jfj%0h$Mq3rw&mu0``9J}$#U6eR(y7vrYqVGX43uLvUBtlCY=4Qw(ANBXh|VB zdW!TNQ!bhb22I$@aZGK&6qH+6pbZ_zk)lCRQn`f2#J1C0VXVEZhagR5B1BCTT(IOS zOL8DH*=eK|Bmv~Xr3@O!rbiR_qQxC>d@JEfeV(}bqcHk90fMQ=Uzf%ay_YzVE+P}p z7F!soe6P*7n7HCbO$sDicpWf7zzHU-Yz<}IWp+3_jN|mZ$4L7{Og-c3Q6aH6z@=db z&22HHWNe#VdRcGGtoZR(Lxw`8X1`g-q>7vCpk83yxN2K4jI;K;hrir<`6s+>+85EF_L z*M1ql!Ik|l>K%64S6BM?%Iw*NBHhodRPSnLzP&Msf{Mo)nw)>~2u?KGPSd$L$z!K4 z8osGk-CAjEnk=gpI0s!-qFhy~*)j5@Y3wxiG{|O+62uf#5PDXCJvYrcHt>TSzHaDt zvD94$JF2)-ggZ#Vb7A6uq^{h4scZf(Lv zA@77uMo~>=$1%EKnM-T8lC9xS(+YePGuMo<{Q0Kdvyg&)qofm$QK*56;=WHVSh!*= zKdt8OZe*kK7{;OlSXDgjHdkIrt2PMPM;8dM0e41Tjd^MvORVXhSHDJt@5<;+Ulx*w zj@0yD_9K{cuAd5M5RPH|_K1B7!l*{g&IO|)3ZB3it#gzqlf;~aSRF_$=N|6hX>a*O zx|mS66kY}<$6cqZREdHuYWG49-!pO}3hOxdP|a^8LGmZ;+7lRujniejQE8Ykx^g^_ zhIG@Q3<}CeXiUW*<-Zw$qRHGQ+(&tL`Zmp$hA)HGJEU2|?Kb%eHn8eE2x$xRfif~wo zBy($^yX4YRq;4n2u?hVhab+Ws-f` zvW@-5S}6`VeOt$H{D;kiv_Wb^3I+U#8WgeR*PXshBdg8?G%7{LH-|{aFaz?!HEGl! zz-V7f54{lE_hWl+0fcbIptnQ3b3Ij+}{2lxlaKtjLt?6ULTEust_D4T{2^x<%aO z3Fa+Qp3gxMu8j5!BfJ%ky7BI6m|2Re;~(#qB@T0F=GG&4$oK=>EnZX;&`SO7_>iU6 zNMr$1cDR^@fk6uRak~ny$Lb}W&;>t9F9byI87mx`jzgksYAqb$zQ#^FJUn-D>Mq!L%UVH<=+u|25<4mL>FFjrUZoUua#Iwi38Mmx z%xF$yXlrqg^&9`_oY(`Xg>~wevzYkFr??OahbVQlhx=`>hx(7K?|@Dg%MH#thUN9N z0!uB8cATLDu(yjm5P`2Bwm@@`JMo{hiDrmAsS4c@)FuO5Ez#8w*t^MllKae~lAi@G z_37I~xg+_k5}Ek70II!D-HAVft{Zr-C(!Lve(NWHa7u@)qVKjjGHW*;&TxA0&eattdoWBk3-nlC^f-C+dh?39(}^}Dkl`21FKH3t9b0OD zj$phd=|WlY5{z43kuhr0y4c9unygbsP$&1!86A%5mBA+=!*=OLc!~5e(djwC}oFM0(W_ z`9?X36Ra(<<8G*y*>PZg;Tmu9MK;8qx<%qG#& zshoXBRt5UX=Q_@mIzK7K+yV-+k}qaL^cx{GEHHFX6&(Y(9lvT>jnQ*xrw8be?K{4N zxCm4}wlwRYTV<=eb5`(Pjbe3Ms^`(xra`ju3cjHzv#IMeo}hyer2p8PgvL-zt2F}= zOce9K(^2Lt=M8^zrnSws@Qf|(CK!1`Y79kfqNQ(e>T1S-CwJ6Q)u2cTy>Z>bsrxaTyG)#uWlh!ge*j59w!h@u%ZJ<`-&1OS*xyrohLl)9 zkOFn%oqiZT4D}oMN&%0={E+x~jPd)a37}?JNB~)h^fm zo;cb}uy@CG?+$T~)t@_xoL=xUDsrr?+ALq21tUzeb(6Js*s;&WwCx4zM^|t$ zQ_A<3vdMI^lr$CIwv_N5_eLl1FG`JlZ*||>=5{UjrXty7fk29T)5}%YVo|e~wYhfm zppD}4q8F5wjbn%3DV@8Mbnf^x6(FX-;EOL=Te~D#v4_TVpSVZ3H%fS(cV81q5Nd7sXxSdS?vY*Bl6-S8ZJ~QkvSUFA^vqwN8A&U`W zu`@nCzHgK-vCCdig0+lm-eM(1gYgn<)P?0z0xy#%c~Kpo1?s)Hlw9zSj_Vv{eR zSKKz!{80WQMUJTK_On{nsP+4v|Ja-7!De0h{sCZ-=i_TKcN0t=uv#TNZx@s|ofSn2s?-*@u`&D_n9R)&JuLa4w7dzbY zwJVqO4rX{IldrwM<#sEINj^HXqByiq+Ii&JJ`q-*yj%U?H&!EiY+5F(qM zHsKu+on%E-X!2|@Gab?P34B?+nLB&45pf+~Ty?#USlAU@T#zxG^q7PgQAm zHImYjL-whCnrvvV^Ltg{dT19uLGhjz!!nKt4UUDw6=8gWL(Tf!6s8wAXPXLFDGeOI zVAo%JEaqp$G>CV#6p#_^hPaxkPODT&^kVHhN!f1DW(aEFOq!yewv~Xs3{wjfO#0j( zn2F+;Rk4E+V2i4N{^se*9#e!EkFWOQ8&DrYtsfZQ?Z?;q@heDsOB3q(@xy+6vmYPJ z9a(hpKRte0ttyX1V*qw6va$@o{(~7qqU>2$fTwWp)d^9j6QcSF0iin_cIRU`aF!ws zIiHR&Yl$bFK72x^9oe_!`)JC12FXJryT$ZY>o$hhHALmcEv%si2Noq1vbN=vH~pB~ z>u$c7z!;mkcG0LZ4T=Ue@g{3!i48Tc>!PGW}dh5jA;2ubG2vW_~>M6tq{jVIe_j~TV2 z)`7yx2b6;_ayH9JWtj~V-Slf4_1c4XXkd2d&AlF& z)B@YfaFeh>Z+J#?)rez*vq9OlPOx7p3 z;!K!qx2wNZ9WC(_yoSx5WDnExO*iY$6lDow-mnI3S(H=uAl#9rhNIgUVY*`p!@e`$ zkUTYYYOQSCmnWV6sr*d=da)gGq@hq!&`^(g12b5m}N)Kc&36ChNiF>}+o zJ0I=AzePf=pP;Pb7fa~g!Son>~{bWWrEJ67p$H{qMtJn)iaFViEUrR-720b|8` z%&b-vy~eY#5_Xvs2Zde~%#uPE3UXogZebzxE`3uTla_Tv%1A7GhQ2?slfH(13u9W4 zA01+?ricQqM3-fT^vfeMe9^xF-?s+ql*BrG~ z&G^RsNmTbsVbQ5+Z+Gv$_Dr3!ACbrUM%jAsY;V~}`+zxSC;GFG?vtaQ!`OF(zO=XZ zndDH8{@TS9&_WsSC@C&eRAa-W*xvo$>Sth;*l z!S{xXXUl`{O;^u8_}+Z+Y<}>)_3GK4eT5n@pIhdpH^=c7ZKrY_O>_6DF|&)N!EC2@+9MJbzBn!-w{^;;DB19AvwN#Bw} zOssrkI2O^Zm%8VTf(nr4YAuTRzWsk%NjG#opm%yl%X z(JDudyEZlsok&f0#Y~;aF77hZU5Waaxr@8pbXTVNgp0ev?5Q5v@C2)F1K!KG4?w$N zzd3XAks2}S!H@U`wNtbU#OpBx#av*By}*#MY6qEFu;!KH^z=JaTM{@546(PDboe@LZ+y>&B-~_BEVh3b7zN^L&(TZnsI* zUab`@;HB~rPbf(SuI;?7+KV+C`y&yB+Q(Ccea;3Ll~gb)6-3#ln({7wApXv;nPP76 zpRbQK99fInW6wLg_C6#Daf&W_GOv!{*K;4Y7RLZT%oI$(G)flF$F`bPdN&&#nW1J* zaC$aBaK!o}E3o*>nj1RDK}qBm)UX+Zfp%Eox$p~uA1gO)%8_xM7XLU@8LVS`--%z`5Nv@M_q`u9e48Eadx3! zpXavkLd>JSrw=jtAlautHh*a_Vu#1v*XuBf@>Gb{!{W5?kO zPd@s0wl?blZ5Ar>n>rohe9NG4eyois6~#=+jg@wAJnB09_DXyIU|uKwTQ)DWdaQqN z-F)IGKReEz-FE8`n_{$Bly-|*06HL!bV#iDD8t&fI*{gJjEuXH(4K{PygRJG_kT4u zu$6|+p=6AR={*=hHB6=%zP|@`-C;xETDD4!Iq6%Nz`s9=4Sk)kzOd!~=_jy3xpKmW zu)_vVJ$EqcL1WPcj2F)0gcGWF8JuuJm)&^Sano>@w{MLTx_t*Y0n_>_oKS1kKX~W+ zaYB24!U?ux!cAq73AF45IJYQj-@(3P1J8OHJ|mow>`^d@SK`(94 zmAmx9P@ms#PcNi5-vKUIT;tc^f?Za6;hvxuHnbDHh&!AJfCmdm6;7u`ED5j!*0P)> z3k+vJU`4M!I7WnfD9Rk%qsL$88rx0RP3IC?J;BERMTo7rk-wx1zKZWo~oG66f;Y9D(;*t3va)}&H z7~!)&VnndJ(cqrqs7K2;#|Wpt1B?jntK?=_ zOYXGc%qK$5cQFAZ)$aonMEDLcA-eE2n4nv2H!(r4n4ou<5V6YF1AM|Qc1dcoMqKcT zSkzrU5v%+j_=IkwF2y&+g@m=;z6KYfxrqyA#Rap&g|vuETsTUQ2dzS0OOS~xJijSH zrW(En2~sz!z5{H)Qv6?p4LS~N(Dn(bVOf@=)F9Q26<&fq;Q=ES#0ZcoLBmiNnub49 zjisLS&lGp>fO}d-9`?=gq&EK@;7JZ&q<`vK*19A58T~Wov;LWP)MJsML>qtt<+zk8 ztHn6djMl59PPmcV$-bS-Zd~kikM`~S?QtXK?*KPS^k0P=VXYvf{S&xR%E`Vh#SS;H zGBI{;#4cx8!zQarnh1Wwdcr+6?|>s!oajfByYb;3iS$E!dmJ(HJHU~ezKnjTu;R!w z+G(w4`cY^PF?-WmZLo{q2`gYqZ(F}hj~uQPIlNiF%WC~D9aEa_*S`%#0?*J!cabJZKLfyoPWyOhQhZ72b zeif~A&|Ii0UF2@ifEChZ|jBLLL?9lD2 z>>pYCo7AJM)T8XEhtd9$dK`2X9nm%p|6%_kuh`;&ma*055l%J_X`H{Ovq&I9--XVy zH2WRkh817rKhet;#Rod>1C-=HPYsq@6 z(mw2KBP(aliZ&zDUve!7%)-(EyE|Y^8D>gRg*H_I^YEShBrp{l-+0c!3i22Rs%K9U zH@4iA%Us(!>|$Gm-6}vi2Z791;jrv6lSV+p=z z@EoBd2|8+qPOn@iYp8xyuDdZm@%a2GuNu!E);hxIJ!#DrF{UuRY{jH3veipi_{2x9 z`T$QyXBAdWr1NCCmqes^YRYizG1Mb!))~(4U+ZTG81P~(+oiHH>qQk z!F~+!q6Y~>`vg&Hloc)&Y}@;aaJTad;Y7}ji=p>S82 zU>*AYFBf+laH7NAp7)J*hiU)@aY^a0YlO(4Da&}(*APj0D843>VT7I=rPo+}6Q&46 z`d3_??zDP(ujYu|CEib&a&j)V z)?LhDM1A)R6N-Y_(a$L2=(Ixh8;#*l(p}BX#v{d)&Fgnl1eLLpz}pm|d=ACJtit!t zueEq@e)W^)S6zDl{6a$9dTV~`{=^&hpQE1=Bsh@CY?{2*XFnwnuX4{%3CA*D`zfQC zDZoJ*J7z_#y;~lT#(H0uoiv8oL5qA!8hbpig89WbUu#Ci{(Q+Tt3t+HZf8|IDU+qP z%4AF{RH47?ZBDq8F9Oy7(lTGuaaxh(91*4`gFoKnjnoGZ?SI${WX8I_`_v<3-;K)* zcw*fvyTf@yody#yIK6VZGY1uqa6gsbCugj@jv_+7Q;w0UKJ0(K&67tp&)b|?IIlBh zQdN6CmqI?pjZ;o1&QTZje#+;T-0o23^f{Cn=l%Zqfwo%Tp5Ls`jrfuYDocr&gKf0c zYbHEV?@|AC?M)|oeFM?^N^K`l&h?Ydys+GqbNL3Cf)8^#t&n;hr#ozgf=e zO#BV|&nP}~&DJXX=tvgjeA=Qv*WR1xTpDzouK;$({S{}Z)6jH%sq@GERSE#ay z>9wrJ4r$_(x!`H|JPKKa`2-3XKS@)BJ$V1=iJ>mX({tqR>q#kIJ`{~77qy7=W;C8G zG2V;DlO=`gXuRKDu1UdtXL3!|@$=;xcj?(0+&J!diNCZz9y3H?pMx!!we3VnCoHHj z-^&n{6+69s`wUT?)c4@SYWl0%ACl*(eL_o5yJDSiag5!Tnd?!~uBW7v*p0xcI%)NL`wQD;*o`VXw{BYsWda z^GjZ3W&q_j_x4%|tPTD>?6v=D&jRI1-q~xcxB5kUZS!HTEoe_!Vb|$dYYi;>(#*nI zZN{%PFI=~wuYCj4S`j0!YlBaUc9$fqda&U3_nW}=Lasdle(wpuT13=s31sCD$zSci zLk%^WRYO&gbPCcnn64iy#G{P?>ydT~vb@A-<+M_w!I@jON;JOF0m@qXQd2G(tF&kh zCs;HpD3ZL_*txuhA`PgLs)B5oF=4mLtQyLOSN$f@F5mkJ_{A?UyD0a`vJ*Gr|bH=nViKHC-xhP7@m8h|UUU(8<}Wc}XX zjJoC-@|)F$)x6M;;qc_RQRSvg_2cs9`MMR;I9ClEJ(jzMX!dj}cFlqPX18Fb#YbVb z)HBRj{|>9peu9}M4bPl3JRueLNR$D6S35}M2~rD|V7nc+^#yQ}&(SPRPig8{^3DB4 zQ6Bs*T79RUtW)X{o-(3BO`fnt>q$2jwzIC7LZILfP&h`wB$@lRf1-mwO3e1-5ITc*?15>C||iwHo`4t3x%Uo z%ogu+k_oh-7;~;+$x8_(*o^j&l+H0+quyo96}V|FHlj--7435IBDoNOc9f`813kG4 z6YJuQP9A7!tg$Su0&kAhPVo*fH~f2}lWVktk`=h$u0s`{%@YqDHS|F)z;fJ`eAjio zrk9v<5^HzM{$3Caw#u*gK9KVZ-?jE5m#FM-HC@?qr^Hsj6`^6GN7+JW4WgxS$dqx5 zB0$O3QbX2Nv?Z6NMuEMF3(VYCyk`l4s+_9{8ihRhsf^mDolcT9R)?EZNo{sk<=V21 zF{t=_wv?CG`HMYnWyI;R7JwZh#Hc797Qua$cDfX(SyZb(RQ?8 zTl>BHHvHq>+w@k(X{V?LzMVgBF@>W_u@|L^#Vvr3T&1;-xz;d_yA{P2>}8bW3LQ!P zT{g&YpP;Ef#2WYLXtqFQ<-tPHYsv3MRNII_^*&F&I;z_W>x*uzZ<}i~>@{$8?QqT5 z6h#Lv8FLQx+aOS75}h)l^lu!YWhtNlDOf995@Ehuw^w0?oJG~B~i{W1MS(yyewy!tx+VCANT+-dkHVS z!YdiBljiIMFPl&JnQX_;5VuZIqrRz{#@=DlwujTZ57Fl^c37U}dK60{4i?13wBm*j z%4_+Y>N|HX+ z8{Op;M2=)_lvOZ$U*T%RDlx8duQjZG4m9Mv4`iLh-&(-?buxRah+39*3E^Ik5dMo^ zFlIPWb~wR(;^14iX`*gVBl%s&cQ~z{PMYo=JVG3{&$Uy+zMs_G54`jJ+gwR>yr!<6 z8s)9&cX>EfS-WTPsd|=}Ciyp8lz*MuIC+kBew#bchYiP2p6c-gsOhOFHcK|i$#$mW zYfQjI?I(J5h6;8Ho$zBPQRHRhPrb>#uV7HbfC2X%iBlbA9=n?3X&;;d`-}%X-Edb! ze~4$x&4Jn%(QVvWOwVh^k&UXqK~J&or#qd{qQ%t-J<;7_{IeL6%+$q|-Wg|FR=i|v zD9dilEOKmsIjBiHZ$Jx6X005ZH%-F4x#LIAvm?**M)45yIt<6(L5%Z}#rPJxZDLfS z-0qrtQr7MMKIUf6ow&VsVe~i))K!Zy$B9TQ!9FP=E_E<7z77l&c*7*+0)zmptJBn%UeKV=QCwGfrs0i*fjeUkihm7qjID2KtPdCAP z!(8sA8&>Pt@DYlwckD+0x}B4I!t|AJ$5p$oM6Nctt-qYLdRocaX9xSDiQey1OkGbp z1l@)siMv;D9s>1Hn|9VUmX6Uj{};dAUDsU6s1nA2YA2>#x02 zj%td}m#b#qw{XKC>gc9>*QC`#HagYLn7p6EymHl7j&F2^JKSwpL47DEy84~^xr``l zpFWWrb!RkDov29M$FBfpf^HpQcVVZs!2l(tbkBY=L)P6qQ}bxtH*ztr_~2a z)hs@hv~v8Grr+G*w>-cY5XkRMhPOj-$i)45fPx++MfR z*a>2#YqzouwDkI;RnhWv>OT;nq2qUu`>B=qqWbJwdpCP%W;t<}(G7^gIft7UZO!c5 zYb;ltD&(BAG-Tn-5r>pL7e~e=teihluF@O(qE^oyh4*xO`kQkiz5rv-Zzp|%-YWRh z$?x{oEL2&mRbx0czR%26Igob)a!~hD1rzW-!K`A_qhA-!0{eC0ztph{SPb=)#U7hx zZ#4{ZoYbvrSMT;h61WECeehB2qiUHmsG4S33*SZ@QRxbVgzmgG7w$qz{YTS#=i)0% z+cXF4Upjg!cA4qa%Y$Os4vRvXxBaMHrJB<^_-A$F6w4yiHS=3l( zs*kLb-f_|GojQ=~-7MsyW;i6X^=doK!w5I#(bVJcruT@J=l8H>V}**r4(V?}OSRr- zS8``j>JV(02W+yaSod${6RaN$`I;jBdtXnowKNlYXDA&#MpQ&ND$#Lf3(1*X{v|8P z77fZ-*?8(quAE~L)n+qnWJS^@RqEZDLWd-AbIHA{>3d}ROQ)FL=mj_4&P|?rQ?$C{>U$P1@V#Wko>uJ@(U-dlhl$Cs*Ti@dzfq@u`Jkb%Xkf6{> z!Ij#TW9LYEJ8anl z26&i1(YiTl{#};>f(u7!tle}RSL96IW`ZiP_jPN zuehVU%Bvi!LkW_ko^9RTuX7dY*ZurqNX!@gmE#yGts{{wLhm!u_cJF+Quas$9n7X} z1&RcUYmJpicjC$FI;Q9vtfT5B+##L%Luxwjl_!I-8!ls4f#F0y)DYo`Igq( z&)bL;!j8mLu|bXQ+0^T{l)AU{Yrh=qkDCuKi6al>&xoC3vW$>@v<)v#WSj7^*>VvJ z**e8ta#bEy+;MkPo5h^&w)5S(?(Rmmv3iD2cQ4ZI?^cul<8*h5dVja}hq32*$LjZY zoBGDxp~@@1XdA`kPCU^z<&P{EXzT1Y_#j133o0pLN!EW)1ZC=B$%Q+pO#IS+ka{F8f)R zx|>~+_3c^9#(m4LXYK4dYdAWeHtSmBZq{iRrvl&o9sNaCn+E^7nm6^&?ek9RGv*xy zy|*y++h!i^e&*%Q`H_ne`zPw1^CMH;@984$oF5sx@B11$i6(j#DUSFHmS3YljSnFW7zPzUeMckwBvfZ9_u^W9a`t#^JNaMR%7qve# zKqT+XTGVoT))c$kXC39I&06@fpLN({NXd8PFVU*LIqNExZPqn^)~rSIdm30ud+Y>= zCik*m)%Vs{bGp4gzpby@&s$&T^y~Vn*-Mi(+@Zgsu*7;j>*BUqFaFbJUDyh`%{uLQ zK&|P{taG{z>!vpj-lY1pS!cb6brXB;*o?h1>m}ai0WIWh)~DplvyO5nxnq+4JUf(a z@60*`b9>gYY_s8TXtew9zYwObOS*N2?q&bpXw){FhLS<4dkvrZg$-tcqX(MPz3b5{JEk$ca*ZD+6jVGUZZ@{7^(j{L&@ zz^-f<_RMS2jkR@%yWzZ6SxS$%`^enGnPc-5*cPvreirDvXE-{KQ*3r{^| zo_b0)j*VbnmgK0@%jcumvZ?o@*fy$Pp|8jQ;tyXD(CWtCKE{>RGr3m1!96ubF4H(+ zjAP|GPIzn_wgmTa;uwdj;_x`}v2mQ9#_?ku&fKJN{A1&=p3383$|R4otniWQv2oH2 zpFGB?8+`I(ztpX(>aSPggHCzIP${zscWtUoq8R5zQ&yIJmzlIHqN=$!FDP!qMLW> zyq?x`mD3u1G2&wb#li%2{bt}4db=8?oZvKl&bwUU{hZOqiqRr)v;x%594(31Zv{f#!HT^U-Nnnqj{xf ze8%~>ZS`{=xxB<@b)0GJbbzw>dzQfP@DrWsSpk?cw8pB4;qRw-AUA5gVTD+Vb2)hG zfiVEQG5;0NO)x)0sAUoh7b@mDBmpB)71p>FQ7GE zl^~M!tJ(OPv*xS1-wUgNze?q+GWV+r>pvtOp}_n3Y7nWG#v_z$`_)>o(pcuJsF~wc z6uIGG@zn)(xL;jBs&AIB7T>R0%n%1;qpR3Kkgocww5|NM6#E=hDiwQC($y#vUj_M8 z<^{+(Ud0NEd=&_t%AxVqW!zg~(5!gep!*zj^FZetuh=h!uNqNpsFmjn$F^V1wuB^j zT=baGRVx~rP$XZ)7133jatc1tRUjArY73#J4t0&36t6m0Vv32^rcf8et6qSp4728| zp^p%(Qf|CWw!XFytB+L`zFPVo1I{JsDcN4)!2K$`Yr*7ix;k(tfef#J^x;)eT7O$w za>zb4zM4B67E}vc$$V9ING=w*Zc4NlsKfWGF{`EUZi?(XmMn;3EjhkwI`(C~IG1=8 zBCEdhIoE=roP1Su=#&fxD`%eBvh-C{g}HTJ@>SL6TWxVmqYBs(%bWD8sV30z_}*Ci zy$$<>IYUr~Lk#1>wd9?0g>Xbjl7IT?)O?p6@$%?x;2a65wqI1wg~K}56dz3V3q5~G zUoeh(^@Af{I}oHDkwWv)?79i!$28}8IRqK8e-FpcycM10~ywE{ z>$wIZ`m|={!x&ie!X?{1Mmk>S*2CWf3s*P_K8z?vAk{c$v_y>zSKuBVe_OB7eONbW zyeHnM%ER@~xoXcvEl7ssT%CsaD8JL`m49#W(+=TR%=%Uu!H!(<=(Z|9BRjs=SC?BA zEzFN!v*Nd_%X*dKMtu`aeCSUf&0N02Ue3o|T^)5;1-e^C9o7{?%o_XGrmn`J$KNT6 zE*x3lO6|Vs-8ZxQW_RD*+}~oYDJ)Tzpc(1ojN+QlzSa{Ody+;*AJ1*OI?wTRRbO5; z)73D+R$szaU&2=NO5#E*F{hO*AxDaP?Q&iqJB?W=3ezOT@re{;-K&|bR6&?*=DWD+ z4_En*Ba;{IDt>?0j*0}HUqyNr&N~mZ!&4k8T46KBR3GSvUg<~Vjsd+QhTAG)pw$@Z z%i-Kxt_^__#2AhBOZW?WuP3=y)*(nCKe4(5%+f1bj#e{gz#KxW-x6RS*DwJPT zhM;P7yP6Q8;QY}tK)B%aMPQO$k;IPw#57+n5LT_O2g#tq%jwRg1H*ppJDO2#+y5_ot{H>Lv+4>J@EI z3wg#X*{x%UEy8Q`i3#fA?p4L;ciIt0*%W3k@nm{Z@yv6;G}SNkG{;>Yi#$}SHvh^`QISSEqRsbv~MazB$OdWk4;>H zj}FvIG;bJu^hwz@^nA;(R`BlmS2i!6xyvbgy7yZ_u3;F9^eJ=N9`E6t>AK6A#&s_v zLt0{qN`@20yjvlM|3}8Pt~|=?8C2^G%KX!7?zXSF(lnj!Ko%e~Q$>P(So?hlo~I}O z>#EOaIvWAK-WIcNLF*fFpJe`o-(1=3Xc(i;os*;FTxoP4MLGw8@jtj;MF#(qV+4W? z_Pn&>@D?$@<>+Ywyj#6xB9uAiq_1-GG{L=sJWXiA)^m>P@F$6oC#p`_I&^oBdDzi} zal%-70C|UGXFSn*)IgZLWDFU=NYax~5{B{ena0$)O6)+JOhi#z$OPoJ}u+tpY569Z!R#o`BIggeFD-1pDMaP}T`5eFJ*x&ikA*ol1 zdKaHttsRRjTnSMufH{6gAqPdk9l1#_PQ1~*2YqsT{YABj66u^Cq={~)bci5nfy(v_h5i`7W+6x$V{*(+MZxh zjD83fd7}UV6XsQtsEwAIfxg3QYVla&u>u2Gkc^fBw-wkvks7cNrAsj&fs(p+hF}TH zM1`0Vuk1)h~v)qelwSMcN>mTeIy$YzIQPaZJ71m#Sq({e_x-7w6ui`lK zQr3!}TJ(Ly5lWh^Cfmr>-?ZhZy)9?+K2wH5ARCIB>lBaLi+fARY2EO&iu5;H0PB$Y zhRuR)^V|B#_SZD=*aHOIl|2iNBYJEN+Zl*Mx7g5fC|YP?88hs#Sv~QhIj*Tbole4l zH)~z0d#mN~Z&)}kPN6$>ntD^}TjzhYa2%>|eZ;;&J}&G;2uW zy`l3~_f9UP+tU&g%32Z&s~x2TR8}6663QkexMDD|!7rcy!odjDSy0SV#6GbY%M17! zOYy*EMXL$~gDe1bMWX-$ZQ5B%z+~TNqy$jfY5-qk!__#zXl~<2Tv{G^1k0&%S(={=M@4Bw1;k+=Mb3Vhlr2BAY@8f0} z@=d1_QZfzbDfWZYDHd660S#R>BZwYgNe)b~4_;#0r)@C>?1uw~Bwt9(SXu#ja&Twe zQ4Ei+u~W5Xv;JbX8p4*VAy0I6tsRVKaI3OAwCva`2vN-|+pB;}Eb+lRPxWEe=O|+54SQ z9CWXfG(`?{i!AQiewDpWn{d7z{$M2kxRax0IP!Hr!jLAViEOdVTCG-lu2*&*S#BeD zD>-3$AiE;YSE{|85691Dci!n*QJcIu+meTchO;(N5>>eT{ui~S7N%GrE+U5RT= zbhVuYu7V2lhY3-I?ir4FdJR>I+p5@&=hVp5cnBKuE-b7`J6Iq+v>;S6EZnR&1j)6l zh)eixV?)|vn6@BJ?B7qAqexmb1PzNZULzt7s7Im|F02KdHE5zDZ?2NL9cJZ(a08p{ z!abvM=)E*Ri1jO{M0;^r`^@xwmaEEmTSn1-r-**oCPth#QV^*Q+8AXU48J|xVf2<6 zwDqPL)v?!W`Mo=B-q>lU+X?HPDNkX&zlZf&ty)G*zsy-fq$7c+Nwin!i^& z=@Q4NWX`3eD->BXAinbE(F=)U0(x|0$CuuvR#S|Q9lA1UFH@BGMD+A1dae>e z5ff_OCxuOsrekL)u5^xeJ66M8_guWw8Z4jmkOj=aXRnx*tv=4BcYYCn@{9OQ#>-Bb z#krgXmQxEYEg4bD_~updHdL9L)&`3af}W+9RFJYkEdiy2>#gHC21H&NWVN=sK)1-_&Jd$~!G3Nil0LH!yv~ z1mgTC+C?UnPnXB^O(6SM-z1RuM}sNjwtg)9nwbmHm6zKm87$y7-V! zJwC@dT(9BWPeztqeq7qf1>wBLU5DJGq$nr5g`6UVd;RVCTb?o^&$uYbx{Q%Qv%LW% z8I`*={#koN?a@huon=@XdUVB>$D;-ZxTd@G>#?&CKy4vQkBM!~J>9w!?N`{L#$AfW zU3S*8*4$gVC)^w8A8Z=wb5Ox?B%<@0=Ibi9( zXmdmQmn;dA^xw7NC!|7mk_z1>Clr{3G#)e@*lW8aV`Ixcga*PxwIPF07)w^Rlw5=t zs$wtXh%$u)5jn&QsjwvXWl~`Y@6>@%FFD9{SUNBnG@Ac1~qVlN2sIwLXH6d>KX%9Wp9`Mm>)zsPtr^n+_{d|^(S*ASOVKmn`QLSPW zGMwh#0|=h-z99FEEUywph#Rd&nc7>gv2llm)fi*mnP)lo6b`!%#KLZrAGFdZ$KT#F z_=cEd#wPYu{glmkyb^~zCAkNa9dHJ%LtpAuhonr5{fwEDsm(X)N=y69ApbhXZLQ!}hv6?^# z9&i=-iSZ-a@(QY_;rpLQv8gq0+Jk?DU^#>+cK}N2(58g=BdKTHEqVQP-EwSE5Et;lKFOp=b7B%Rw43|ej7?yl$dJw~l)mBr0jk9=}*S907m z8N-^4h_)ur{mD<74DEv2#av%QH26KWmd)!YsED+|mbaRpr#j84y7bJPWJPPheojX{cOOBh6qe37#NJVNMBiL+4gOmU_EH21(AD?yBsFDu z4w-SQzoiw{nizH`?!(x5WAD!hdQ4pVGp_TaUiGr)APMTM!*Er$`ndSXA9TnL!1-Ks zYP>pUlYM~l-&Xs8R@z;3YJ59)!M@d{ai=$FIn`na?%1IbcwE?MnK|WcaEHcc^82)s zYy2Bi2Sw4|h@qHwd*rD*Std{o9gR}-RS(cDUu|?~9GtduSutnHbEPg^D^|TlzvQGt zSkgQVXVZ0`<@t2j-RUrFP25{{m2L}AyAV^ab;?-}*p0z#bGk`>%lwB>x-d&an$ zqoSSIe-C2o@H*_AJzCQRwo??2^9y2+UH#X*{i+>XTnW1gZn4wFah75VojL;x5JWHf zI(C+HO&DIJ6`O_6nHk;Vi@3F^K zn2@(`Ko!&WZFHUP_NyMr+wD|ar)R@8ITVJeVju1QpS|}$lU-HTM5lx|!$E-NKZF+! zgiK~-nYH`8ulw$MR%I$Bgb9MMfBYNH8FKnZoHNf|k;krp741Kfg-osfCJT-Fx@z!M z9L-*C5>OHe2uP2Rqkkm-ypeze$rKLEa*}}3aiWR@6kXx#|3eaxPW}I&1Qc8TM-q^Z zetLd@uMlT^jF@1b8FVP73#O3rOgS+C8T(M9`vsRU13_Y;96u#rz>&{Wh5y17UfMm^Rzf2NzU%g`6Nc)8FG^j*5SQAc8Hz=e)1N|NUa=aS*PQVv?U z|CDlMgqjN8zL1=3q?3&2S{o3OQ@&uL#MQ4qxlRr(s!)F*FX4zY@wOah9ylW=xuW!Z zE7M7i+Z7v&aUBS;<6qK;+O`vYs2YDwALR{wuoryLM7hyNQGZPzJVN+e#BNRWi?d!p zkt-Jjqd0sact!&qz>^VP9r17eAsrN=gA&!3bWq~{f)2{RrUPHkbP&?7>0o<92Z)h! z(7|@2gH4scrUM!w{B>670QZ&$-KZLj!`Xf%O(w46OydwF95?gAf}03m6EmiqB*yuP z@G5Ygw1rlnX24YyRI;1j=@=wizc;BZ9cr!=8t*P`u)63TuxsK>ve+r`Gx)< z@luXFFVLqAv_@LNN6*@~Xmp!2iq0c#8b!cL-HOp)G}N;1p0OxD(0G_T2aH=bt@uE? zQqzmah+-#*b{l;TSFfW%v=$Gi1R}Oz_VS0^Cyl!9ilcvyZ<2d{&L%Ry(+@fJ3TMzN zp1~H58APwHmmCK|`EwM-c%MCYT5qgLj>y007mW13aGA4uo-^k?5bV!p>~H4mJ5*<< zKiBFf&d786aNRuG^vu8Y#*O`L_L{!(YyGeFxY(CEfb{IUXh$F)B#^#(Xn$log=WJB zQg$~D@#WQNtOt6M`$yfS*+Qj zmOPmaHHfXBDhsL@&b=@FP46?dz%|=YpJlg=MjnKRLp^O*Yf9)rR-t_+WM+PAyhyv2W`mg4!{ z#^f*N)5iQ}K211wr}3ZBw+Z%PK9Qu?`814_@xgq8lKNOr9kWSh-@b_do_*U!o|_T8 zVAMKwG3UMwys|NiwZ54}YQdj*rRn~QC)B_l8Bgr}J+_|~G#`qgl-T)njn5o0^%S2; zS)d~)m4DIJTJ-kyl1DuoIH@q^jC9FDD0UVeevizv*sFw z(U0%H!<;;~+9)r^+U*PE$??<|_>=K7{K>EJCb3UFQ}(?X2u;@R=D0$BiB?IvZdW}sYM}Rl;3@qDBv@-Ug*+Q{VTehvv8wLuj-`D<*wh*=ht*6=xWBN z2Rg#c5uDXaCWCl}ITPLAbIG5mknuNhW-(@!vZUV6v;XD(e>2Zj{rB@sdX*8RC9M6! z`^0y9LeevCTt|E-sq5#}h;l*=je8`cu^{2bt=k1rJwIhoo7G<_RRp(Jv9c*kEEGo> zQ;uOC(dfYM_!D$*=Hs}~?5KmQxI$qbUbL4MLrqzS>)Ko~NF-y0eTT!I$?^MS%j6dH zwIBD&ik|h6tOOh0bM6d0FXvb&5zzwEIO{oc#t?_RQ@>T?`AJpE;EKk52YCS)O#iW^ zoLhRz`r*0NypH2Ow)Xtq-f2!Pj(st%QS9ybyv#abLCPAISs`)K0*vAK4Sq>1a|fx) zH|CpU7r9ft8auWnb3S^emfj}0=J=YH+K|gVAinP74qmfRYZ>oPmo}-!=)9Y`5a;UH zq>86{N$`pA(-EWy|E(=?UJ#*UT1IvsbVSzAeP8=O`ij{_n)KAL@8(61h~HRBi%NEB z-z=Z05`~RYZIvntBH|%pdGKtEHxeIA#$0o{q3LBmKIV19Jx;3a=2PW~Q&q#1M~zq+ z0ZO1!>5($h;L~>P6-7CVOcKVv(nRw-^Chq!I}wf~{W9*o%(xagB%v2EG`7}|Oa)3i zSv2{cIU5TtXsQdm&(D-CDLueEYm%{Ts@p(}I=6Q2iA@dhHEXC7chd|cB#(7$($?Xi zF}lNqR#Pg%s5v;tN>$Mq4`a8%The1XtZS(ej<-@$aJufkNM&lwi;fSxcJ3P-4cp{7 zo@>w{_n2H=xSGkaJ_A>%{@1PF5?hm<#IG?T3CDB6)$QDhoUV4=rQ<}luuTX}U%T`A z(Qi@s`{g&L@Wd1zcbKiMn4Y)2!zwqcY{gm!Xdl!`f;+Zg-+kr$W;dA1EY9$m!!<7%8cc*ELM7UTWlSA5^_tQ=MSj#GK? z+C>(;>N9-iEa!Q8&SSoxJR{$CQ1qs_mIU>}mL8w@IQvtM4B$Qy?GO(CI1iIVtd3_! zG^TJ;&d#=sG9k!S+#>G3ww@y7755S&Ip!kF+R|gxrwUt7m1nfPX=FH`B;b8*i}ujw zIe%KP*JdT*(`uv(UwF=Uw*7@KrM|e{1_JbnYi)UBt|dLP%TBT4H;cfHw_blEzdi0X zczeqSCFeT^2yy1or%A!O+$nf`<94emkDAhr2Nx2{peB*RC&T-vs{pZ6_a=!u?n zEFT;gBbT)eOWrxGR9afXd2v@sbF|GE8pP>gvd~X@(f6&K&unj@YKSa#Br_|@UnoM} zr!Q1N?ilL zsry&@-a+kmt#5eshR#7+UQ+F-0Cv@b`RRPnok}9{r*N#syvBOO{0`&mdB4z4t3p2m z6_7`8mPe|QOc@AV@)%|f_2K&PMHMTDU%?N`>LW?uso|WQv4Wu4l?5+ z*_mSy##3D)c*Z%o)K-&o()Bna<_f`USPdPOz&Sr4@gY)JSiD1X5G=1_BRpxENS6y3`)zADxm=N0?N zsFlbqhgmyd?0deSI0GZ5Q4A&T^E96v`yAgJ%d&^{$WbDSq_^ic*lZ6ozTohfkI;c8 zhR_?%9G=jG4y@iqcQ}w<%MAtS&US(y0DF3(rQ>tGO6{tp>Lh&k_*eKV#`s)fmafz$r@wmUQ5a8^ zwu14OhmBq8(k|Eul;e!m!5PyIKY>239{7=Q@u)32YGX?EUgPb1Pc=NP&zi+^RKu7- zvbZ77Abw93$JV*3lnRAs7T$w_1CelhHKXs4Z_28A;@KL*MDo^ZEWbWW-HaHvGh*1x zPfS^+?Tpy6)IU{RwKS_kMyHIq+clyZy~{~})ocluX`KU%E9ZN{yXZ0f7(KS?Fmc~% z%*JT*S2BhgbAUP}&eCZPaBjLp$a?0(jB8FPH>Z7L8Qm5Ba%7rKS#a^!nb(hOm#}V@qB(8+!51#B3!_a{`$he5_<4WKemqc?I>v}}M zkj0+fdyY{9UbCNe7M$eo<9n=BtC60|yP)s#iTaNi&g74A&g3i7+mxjAD|AG=XR!`r zyACGn8EdGD=LUpBdzUSbD&Mbo7DYasxfaPIu%{N@km9wyhj+ci7Q9EyP7dd`5#tLZ zcImth)xD42fv3&Km9i!B=2Lm{@PvMjQ6?Tz_`B^d<;ccza zYWK8FqEQ0xU;LEoM_g|3>ad;S6Y&a1O$x^g*^G!b7wRc~(sL~;jso+#U8Nk@ua}rx zG~3fC@~l_Qatn@xWtT*#hkV{(X=1izy+_SG*(6=mmFpf9SwR;K*DqUZSHM;4*VB8Q zgR@W1Vdnp0!9U-5v4r!kcpZ0gjX_*$TBL`X7N@;uANJm)w^2{#`};7F9d3<_M4Dr* zU|2?7tlO~<(NiaA+dn4)nO!Ih6XjiPv>}8lSgi}sjd{So%@Qn6d zWhYyk%#ceMAs_alPLw)p*Pow?LmEt_fE;PF%RVoD)^~5sjJ<9$#e+Ea$agaDR(wMf zP9svo#Y2;4)X(whx{F=f>)OJx$2elbq87Hyew8=4Y}7#Zh53F})dQm{LXP7Zw;eV* zrkONo2InTqUG@b!a1UyFL?|ANC^WdX^e{7@yJ{$YziKCNG?5Ot;^n%W2=m}TJzAZdT3X@Y*&zL6WjEScr_iP5>CW=b&7_`Z6e-tD})*I8e>?h+91BC z63i6htho;KdoHi2;nq#oeIHr!^v0t7^n{TWdz{%xB2SJgG3;q`McL7gWT3(|J8JKI z)B-&d0O^3U3bU3c#7hKfmiWMQ;JQGP4hyautzaS&4xG-DrTl*lsW=dsy>JhJS`(n zO7c7HQo-O%4~4X-m-Nslw(OS_QJOt69;7A$RuMSYx|p-Z6)3)(x6PW5=8bUsdEV@0 z-lW#W_LEu{Qn&AUt~X=HTnpAxC0`lu->pRUKOog;wwIuHD8A+i=Ef6nuJ9Np8pb>+ z+85}Bg}$@Cw^fcp-#90R*4!{E_^1p){i(bU@jCaV)j6}=s!9`)0@oRM2+i}l8v8b? zNyBw@><@k$U#IiPc|<>;>Vq<$dQ{GETQ9@5B5l#TP)DZ78$^su z_)!}=4^)^XKVe4R-y&(wGP~>*cRe$iBNjD${9K!kW1+4(adJZ+o_?iET=>Pt5U0Lu z8B;wh7;A52h1UE1Z20mVXkt12?TOjV{t@TzA-*~>f5Z9Tp0eGjgY!Q`PKmD%vpQTC z%mS|UNwrYSL&V+T8FKU9qdMk@85*9VX$gY%m76@#O8r@>Q9fgy2H(?y`bhJF@d(G+ z9F_`IOd+yDECo@#4@sW05|!Jx_^Fy`WdSW*LDhhPs(owMqc5s(A|k zT;*!1t*O{bpb68(0WF~o3O@^e^}g3p`3p3)_*nT1GxnO_#}2c7oY#k3a<&ZsJ#>^% zIG!pyj&l^7t(gcG>X93$qp}(IGz~d+jf=s^c8rVhpvD4WSP%adtLZ=dOrJhPsw17;?WG)yJJPjFGykk2*zeMOjNkGpu9MdWsc*=24G%=UEy$ zlwqB8u^Nc~@Kp_Ex@W{+U!R>74bWOC@onOR!Ye!b?!;zj4~{{5G|aj-$4rQQi({I( z{@!B8IJho)9`)dii~Vbf7-jU2bZa9mcVs)Pg6kb+^5!~wTj#Z5aeuk1#wvi!mc=@E z_~n>(KiikcOV|C#+Je_0qem6qSupeq3kF#z#8U2^u1{4Wy)hg88)gQ)#0+JAyBhYN zR~019tpbAu_5ls;k}>(RmYlaCk9az7yP%0-f2Gehij^KdxyO3t;p4chm4g3)4~@ry zfBi>DCEACFWhJhh};Z>V{&MDCxnD&BV=G0|u&hyyp zuu<@yw-#j(t}r_7mvA>rBcuaQYD62TTm2jOB>jqWr%Ashi`wchK?+9d96O5JIr~Yb z-mIAZKdLo{mKdtGc&|8@!kJo6>q}OwL9tC8mF)35=Mc}@aCjxJS4e{MfV@-wlS+m>tDI9ayaOH>_=tdz8Ks@_?v(R_p``s?xBBtf z!}Zo*ojfkuHL^N=$(z$eHh9r0A$sJ_KCt08@UFz05A3J}c&=)xzdj)-C&@LN^*F;0 zn!b6%o_t*ITcFyP`R~Tj#sNa#s@n=l!lUz10VP3(u9vnrC_CgV_ev zfTFwB`8BJaC-VI>+UO!V`0j8ONcMvd**#E*f1r>#YP2*QW47kJ*5|9`B$F`pzuMii zk}F#cxGv+Vj`QjfA?;5wCXb3FrBeP{r2JeE!429X^FW5gC~=9D8sBX{e>dvmJuP_NsG=;2Fxwq{AU z(xYd`UQU8-#8=(vYLctrbT!D;bh_%~YB^msa&>4N64^6!UN`G{6Xphv)Yk9#l|YoP zXWOAnPiwXCCyONK z0E+Ded+$YtC#zpk<4n8P2$2zo)pj&#=5FuRukE}Cw`R{tnAcBnD<_+9U8-R|*@T(D zvenOLHS5od{fXA{*;48W)cT9n=ab;J=J+nt*DU_GR3Nq*pZcKG)kZO+IeZSD>X-~_ zI3$xx?sJyxBXgc*cb30ky=R}Y;#P$YyplTaYbNx^J1Cd-nG@T^+iWezKY zL~`qiq|13}i;s3%q=jy$9XQT?aj^r#r+(}Uk-)WNLbx?s+X-?nXO^KCK9lD@TeeJ{ z#=lLiPaU(J#fHc^7HbALkKrsQ$V`tB_-V;Dmk|`y#g3hwrXMCtgp)7PvRp3l!DhAN z@@&egyJgisTj^5FgP(=6FGr z%bJ+=tbmiE;fh3A5yK}1jk2Pi=r@ew^V^oG3X*6pvu3)#dW;4N+RQvsw|t}H#PD}s z_K>0Omzd+rT{EwH$ohJfI;NyCeN~61cl5a4d{u|-^YxxNokKOYBV)U72}9wJ$# zr&F%luRV~99ehEcMBNixXbN+~>VEKLu~#gz1lupdmEOX*f1>wwo^-k=Es^S1za#1kXdR@}oGpC~Pk}sbil_m{ zJ%AdYTl{$?NVY4#u_Yh&XM7u$`9_5{xF6P5xzx3B->PeKvdniQHPblb`=uSSA9&Ed zyZo^ovYT|WLw3<{h$qnrdx?8RX_9^1zQ@8|NI?s>Cu_&csB%w8Wt#WX_9o8z6j$;( zE9MzBf6z{ez^Tp8@&A%o=AUX6rEs-Tvke`ym^tc=t0q68Lf$x*mux8WJ{Km>D)VN+ zj?A944YK1Wu0DjmdZa3ZhgZqih2*9w>I2ue*^s>-UXhD#u#o9S@iI%^#x>Uc^1C_z9!|ff%ddv>^)8X3b0iqE|1grIKN$%=9|=#+#RWO;v$`{6$-Cu_-;HG#!yU zm?fxMS8#mV5?TH@+grqD1G8mIy5d;b19|(5|A_^>M*e}|7l}2&Ty8$ z;M4*c)BW}OV!OBk*i(IA!CKY0_u9_hTYbilJbG^>3x8rq()`0A>wAfWgRKNh-!8j! zeh$m$Q(m4K)}dE8VVDVi?6OQf$NE%{b8KTg&#{v#fB|#1@bfM+?TpKuarf> z@!x{I9`eTb;&a`8S1WQ@Kit(~GAtu9uEYAV;L-(`b{>^kFp}l7I`X*q-m>8HQbmz)R1^Uo z)y{Ws%lh8$mQ28da)Grm<3|s#pF!u-d1aEdf{$v=lH?u`jH=TZDoBf zEFOjfHD~tC8?*L}@2`(?2HtJcQH$cVH_#n7aV?LmFzGc2R^01iPC1{CC%+$Y_G5kL z=W^U(kE{K-K@4GnH&oXV3kbNIb8inRxwqSB2VPeD25%qu5}IC<(Do)H&iO z_>0wgWQT>A3iS$SFGj)V@QP)LgIZ=p=A;=f(V@;=XOwpr#fKiUR3z(-`UXu$TZN_- z({yf6R+5Ci55qJ{bdGf=;NO+LCA<6+0+rlu{%vbx6>uF;%b`6Azi?%0GL%uh#y!#V6c@s4 zL!-qCH{6mEtf6h3OotAc)mqjcE+Y^?O!0b9=N=FA;(t zL|S7(`g5c;SrAI1YxzJ#USpWabQKSnoDZkZHTs|Krlw~+Y1ObrDG+{ zYNNrDfFLD;${nLNIu_VVUC`p^eB}}Uc+&TV9Gs&Hz+`MOyV*e#0Bz_y*6>9R#u_XY zlo#Z+IoFm;v!S-A3J?S$v1DWRvW2c(?pt)A_kwnkdv2hT#nyB8)N|zt|^v3853dNSFI6J*ShFX7Ah^I+=NHf?xVJVweo_ev-FlTUaj*<6wA2 z_3@NmpF7P3o_lh?lKUz9Va@}3M3ThKh0;f^y_<4y0v?;oue^~WaZI0*?T6P8cJU=w#cCaqXY%o22&rtPn=8S>UlXSqE~3z@XjJ3e!SQPra8OOH^nOhY4 zmPRD@jHFfbJHCC3FGm|8nsJg%$fyyP-JiALB`P|auVyGN}W>FZ+hR)t9ET| zKlulTy;pdMew9^y;Bh#TL8P@Eu6@ODa1wt%;-!ZLKT>Y! zrHIsy40BQOR@-e4^}*aV?;sOt=;t#j9n;-7({tasVfWg+~kv{Iv~ zOk&|5XG+nmaVcEG_(T~xzU{3az9Bq@xT=h@7W2ik)bqd=DUOvY96;Zr-CC2Xz-S4j z%q-I2Ivyor;ROqXnKD+8UD{FOY3pjPsdhVl9nlWgI>fj$ zIG&5&F4^&tGm(w#VamNk$z+@XFdg$;S@a^!Hr@l{g>8=yRBEqOI*_%#z|Ug7bF%aw ztsbqt!kJ+d(Ve*Zh)Yri(I12((!D%~ApAFikbIb7<^jaxtto8Bfc;b0ZqH~LIcGEz z_@Au-_D}ex1-**SnIz|owV;Ln^8fBUfaX_GoD7ipp=A8@4QNbvy9P-o{kW16p2AAO zsR!pqGnkn2^Gb-9J%a5L{xKsS!S7u2{W34VKd;bN3UVf%gE1kht>%*f-)1|lFjh{9 zcm??j{cTuHcJPYdjrfVXyxFaf9*||fB8uu6hfhha%q!oCJn<6yDKHiuad69R(>1Dt zL-LVaR~Y$mlP&Q~%8b%2_ZhhFjdzspBHflG8j*|WDtl*v$9m2Hsfqq2kBvf1v4J5V z8NV!5TaMe6*o$=}q*3qLNIi2LJj!GiWqzOrH*uUb&*92b50n--1@ir5Bd(}k1Bic0 zC4WQV`VS<#Ka|lXZ!d{4=L=OX2430^os3UalEO5fD)4?eSO191+|~?swVchrdBb{M z@SE7z48u|E&mBl#CppwQJLOQ2VuZHcLEA6nP%F`>YT~MCIZM$tv!12a*ZWxt%P42* z-^}WI`qp{+X1|=iw;24mkMsDC=Y2V+Q^Rw*nBa#0&?l@{1o}|gJIpjys)4Bvb@Nyf zI9iNCvLFZ7qPhti%AcU&B#`hi5^!sKfzbht!mVhF0Ljjh3B3S&r2H!QO<_F=@eZ+koWFV{gih-M6aU2oBiyrgLxFI1-eN-Fv zL>uD4V*62^qx^wU!y#gRe2}a$n#2DyqU#Q;8*}-PBA=gp~OwT)rXkoh)MX)ybMUV|WS+h;Hzt^YESbX?~6^)N8qh3}VHr878h%AHD z&uIDNryYdfcfxYt`FW{Vsa_)I3HSMTS`JHgIIC#qf1=fUUL3S_WW~{bCXMW?me8h9 zjy1jG04BnY`v$LL^n$TI6mI$kepiDQ7;F{F5qYAVb{{0&W^e04s}pCmhkd5cvA4CJfm z-H7PCh$;CVH=Xw_RE^;5hh<7FKvNOq_06|1P``(@2$3cfT2OX`W9k?ZsoD;|?HD}?YMB9! z2xOB%8OXqnplhI~*^)yreFtsDm|O$&i*wZlPm1s?tLBQPt4yi$gGT~;tr&A{oNlIU zX3AlH%3+sh&z5~BG9g;^|6n|Fl2$DF?Kjx#QI~Esu9nMKT+!v+^^PHPC2k(^WsUB= zX&|l+OpoGZn~@4Ls%W+#F~$$bT-o#vOa5d*Wd6qz;tLtktTN(|5NXDMOYblcSaaY^ zMp29@wu0GHC4-vH*S*MtW>?+n-SJi1##IBX#*^#_)1}7M)I%|H6%ldpDuw{m4&nh_ z&AVI;h)%b4zUo9$g=yPLvW2ep()p?*-!`1kcr{fut}?bPUB$i2SFwntuGC)`tn^`2 zW#_AKH(%Z2R`$U6x}4-{g)LXMjjwvSH#FEnp<2GGWp;ohL44RrS_XAjdKL>1THU$7 zcFY4J>VXu_^I%OISCR5ESu3@vRb+GBu)-Mk%wWzPU4?xcbK?2MSP_=kf#~+ucE0N6 z-p#cHZS#n+t{`6()L4?_dzLw?uovtm@;y~`p{uzhw{6s4RnQAXS9{DI^8oN_E;6=e zfW^Q@psR6{nM5r$I=%B%KkkJ|14)@?Qh6(HYt5CO8;uyqOx^~q!onxkM(k$CRd}y~ z?L$|ytPo62F9^p&l5&@^?PQy@ny=PO`pgd7Dx1RB(8_bxXR3cVt?BAG_r1HG^WSVC z-di}He2|d&I@nJhQL-9|h@Wzhbc~f2x@)0n4V)~OSSLU|qZcR) z&5;ZoW${p#NCw1eR3jb|SCi$vPN+Y|Y+mXujcP8&QN?4B$h^r7O)I~(d9egS^7*hi zF$w`$2VNj0fCRpc%mWZ8>XCT>a*MrW9x$!5o?~iTGYw!a-r!%OffhPpZTlO`-c#%d z0Z$^ea|P;;_NGV}pj6y<=6kMi-h0Zt)Cb0HwjDK4Of#?(#ewF0$JqK%#xA$0AsEDw z>U)4x`(}2q%cHE#618_J2d0>vcWdq;eJZl;s}*{#vZ<*U@u(Va>l=T zXxk;hJXwoSno=+Hj5EAeI3}z?q*~5=9Y}%{L0zyO-a^reGjtXCS1^K4!Qq#-l;D3G ztt8BM^^zy$*L5vMeox!9Aj2NsV0ktj9k5-HF|z@l3-8^mfwNif#f7dw@HVjTl8zvj zrvN(vMNW9jjuIwvG?-zy9|%MJkyioOZ%iQlZZEw5PgUif_2WUs9&0NuRIC}flhWf> zD)y*fEL7}6SgANuJ@w?@(y>zP%YUR!!d$=@EO(|;jHU}2`Kr+^>bCi<`wXJZUNlfr z1}Y6(bRa;h*cu3-&=)uq+op1>Vb?9U*x>Bgq(TuUDllRLlJ^a*1r&QI z(JGknIZh|~?y>VqxFX)^JlSAzeNCnHgdLhvChWWr+;Jz5##3b8axcQVn&mC?6JbkW zhHxMsO;r1+u7R!9@r@!Rw?!x9otRwQ@o;flvzTKJ5;G|Dz??EDXM4{U&M{L}-g^w5 zkP#XjTA;Z(opuW=5 zDAR)o>@C_b3Me39F9wT!6b(vf0hxQt70Vi#(m+7!n9EsxuP~lHCf9>bo_n3>ty~Wn zr7i`()xD|SF)zgF&GrV$CXhKOwiVt`cLx)q8tAIlMwPlP7*V^s>>?<=KzVhXWwg4{ zMUcq%L|G@V#{@m8)Dw3;d7nJ=!bjp3#0CtX5i4iNwZu&@Hyr*gmGTI=ErPyc#Q$#QX{)qGJ&Z!F69<8J=#$T*?7hS zMs9rKd$ER<@8OkZ7)cCgYTob{7c&{Gv`KC0KBUv!< zJ!dK4;q-Tm6^haYy(6O*Cmayxf>M63S*LhC6rqL)Y=P`y2U4 zuQnmpCH;5ijJS%?Dg7g!XqYE*X0%G%w(vyV^THF6Dq$nsco3X39nO$ibuSwCsn5Lv zy;_it_J*7XsT9K*J!mbP>dt|70+Ld-9WfCwT@8;p+Rrz>lii*!wr1cSpuR`g55LD= zp_LLH$Eso1$5Bx>(?ClQ%o^xT;p#uj8fjD1p!`%FTUB%3)Lv8k8z}~nS)k$O?BBHa z5r4{CTXb)U6p|`3h@otcHm-hXd>TZFsevC=b%%}(iu?}3Gc3Qiusym3R_`#D1zuHv zOK)fminX{7JJSM#sTjZQV7)2`G03GT7gKWU=>(d{34{`gF{?x~RL5iDbF5PAg~PqF zLJS^V5G&=dJ-qd{jX5j<=FAfQhoZQ214qY6_bE}GcxM3)v+_WrAX?_X=Ql5HeFze<+WNM=-S*p~ z7d$Pz=?ENT3V7PNb-9JxWQ{E5%z9zl)L zh3Z-`Psi?@d$f<*J@l zo&DY~xY!~kv%6^a!y}`ndSP|j9&wAf@CjRBE7#w{`MU2dnB6;S(qDN;abHRHc-)6K z^KZDP%mMDc8b~g%6h}G6>^c80&hP4~gPIqTO^`}E5<}HDs?}gL=b8T`hy0B9cHoE% zOhD_$*v@EIOU_o`3rReBWV;V*?*s35oY~8jI%gb~zDq;{pP8+}dDaTQM^PrJaD1&1 z&pF0!FPri~ zIe#^CcId-eLUcO5f1zKwbaQU}4wXU_MY zHHQh0N#eN>M|6$gV{|gg;5ADXJteiSG}pR<|CyOt%~n&IOQZ%o!SH*T*a3`oEtQ}U zXBoH{B0EXl3X1lDvpV9sqBCIiTroxoweA>=dzXw9sZ2&ytf+p^?cE>feUDLz*o*2G zX$-%=)9=I{3Y*!AJ=7ld1k{k=mD|YrApWZ|#u347nD5*$g)V{wg-}p%Ol)wuWfON7DA>VbCPK z9l9cX@2jqe!BgM#lOal+{WspS!)m5Ma{I(;hBn=SS8;d_7^|8!FW9E-S@Vhx!%u%{ z|GHSUlBznkEn=h$C`741ciSG|Z%P(KPLN<@>c%L8IsLumm?Pr%fzYG8P5qTs>l5n> z4(t@^ASdVF+JP@z9Qm3?BY~gjo<@y|JcLQPSmDSH^bpHo-da(#>1mD35I$k{$Z;m` z`Gj$Mhvwk~alj+?4*RRw+#(|VXOKY)T-bXDJt4V>xjPAT>(qA;%`t(2`Gmdj0DZOt zz1Xu_TeAPmp2PRH>_$dX!KAev6d{mreGR}-Vh0wM5f}_nLO>bV-EMR;=of}1-s~1Z zrP;UMY72G;dSR&?rP5!w17r(=YD~4`BKK|$C}qGnfnuZD5GEXP`WixG*1Sg-z3Uq= z*XkXDz!&4w!K(E)ZX>Ls zug?;(Zm?v>wTCb!8FzJ1WmNh_MQ^btc!>=3SRt*CGyhV4E& z$`ydOM|=xVw*S$2V8usFmH^bcxX%OO3-Mz`jSSN2eCk6P-JC2)Wx(X*W+KsQanXV=zGre7b`fV z2&5H^Pka}l!PtBUog|~3CRB3mx*3_NoJGLD;V*6bJpM`f_pym@_sv`T|1H~wu6~eh zb3E;4ElzjjOUro_Qd`a=8b{U#&J4W~4t>rbN_wr*XmmdtLd`FYmV z@A~WNNnSL}s40^9_WW}HQ;s9ILDr;(fz@ua9a?I}ZXoKw>5D0!z$D>194wo$K;Byc z(P3|;6w`Re9#H?E%Dxnx~AO)^;gk&j0B1AV~OA-(Z}E(CHffl zlSCh5JaOTe)ZKHQxw7bC`Ct#2BW`Rc|DL(AL)$ePBr%ShFv-=E%uYKBdy_(vNLZ2J zLHtEccl(yC9z<4;9piZJSVMQo-TjDDC*jo5uYNDoIqr6E%X8po?Cx38FBq6;HeGg% z1OYJ-I-Y^kbD-%c^6iiy@1$|sQ#`ETJZA%5QH?d;rDOQZvnBGzkye`s}cbGSa{x9g#m8PNH z7jklHdG+IflB(~1obZA76k2vKyr)zd4L$J`@BLuGBN@cM_ff+p?5EwAX^+b8!+n+P zYSTbT)?t-*%w(E!2kv_I1Yr(G-i4Eb6!+*2wH7Vb(+7%sRCZqvf+x&g&t$Gr=UL*U zmG3T45B!kBbnR2h!n9`U1Dp(u>r3`N>NVrTlbuab> zRbk|&kj%vz<8yejg>tOu;C#`2j#z?Gl-bCWAyYOGE?Kf{eI(3z`?AlAG>kggE6kKn zvo&M>3F->=;yMPZ&ww(J8Bwr;4E4tQ?)6huImI>MKX`gZpi;F5$;NnD2SKP6l!miE$i4a!K%F~W~tqpbH`&ul= z7%)22y&{ONnQOx!&DEnK$fyMZZEn|EAi7HI?uTf5u)a071oF$@`8Ij{lEZH})B4EU zlxneD+wOGjR6W^otqt9@)Rx1NH)p-@a9M^Kaaq^9sy__z{ax8{4;UTkc&I*ty$|_BiBSy2NB%1;x$5iD#TEzNb=L z_cm_LrqWAyn~JuSuWa9Myf-`fHbm#K_6d)UES@`Q31p{XEeCC}BLW}m%jdWmYyL~W z!`wulH}*67A1yiH1f-64XEO^WDbvLwo0n zH`}L-Oh`ma3?_Q&A}DTcQ@^Stiq?l=Qv`7>4eoyUH?HRlRecd3qS9;J`Wu{FUe)Pk z{p{XMxno?*?PT2r89zVi1a`4(FhV%hV95S#*FA9Sd2S!pK+Bl4mm@pCq*xysPE7ICL~nfSCwQlbG`^ej<5P&cYdu-#%HPp#OnOWk(N zC^XsS2RnVhofJmBil^!lYy7*QKVK?i9qWSH24?1E!V)L!dZ(R^?9mx_Svydi;b6vk zAE`RCqw_hn9XMMkrkAauEL=dW@UB;lp{`hw3RROmQOtXAR@Wm^5G#;MtSs5TKnocd z*Pyq09h+THz6UDN?|sQvQ~~yF{2h-TF_7n#L)g(Z7UORJGnV4c)mJlc?f+9O<+5H8 z6ob}O+AH+4DO6Wd#dt&5B_JnN6CxoR z{jYnp-o-g5YYg0#2jS`W7pp-&+4FvxJLZ33W&U^8<;Y%qzal#VXYIaPg8?VGVFqO{ zA*#(elcU=_mc(ru^kRgSc6~F@XBSI?=c3-OEAof2NFcPfi7?n;Q>zgE2+<2jFF>@D{Cv6sQbbU}oi7Puibij;_6 zf}{G>O-fv%(E7#$&A^W>_lx17~>B=IG~jZhySL3oY{TO%9uK; zw_b~d1^tjTo4Z8$n+36zkgc$nwhXxn(W5{ZcPt}|Me>A4!Zl&>uChH_Q9vKA#k*)= zzm%A&sh~Q*j1+Bp55PMW!cz3qn+jXE&0ujW56lN+TH%PUl;L3#BBMMbmf){&Scj1- zkJm>ZI zqv86H>iYA1zA-E;6u}(O~tP1Wd?8f4@KnSKFSqic$ zkhAqY8os(oe}R|Avd7L>lVGUo24ZM$jP@H4?~xFEje;}N5fZFnjK3=~uq)w?0Svl! z8o0i&Z9xL(t0vyjevPd%HrUG%G+)*;?8E@hpe&`F*p}EvyU<^oBKHALfg4^h(34=v zdIt)9V>DWW=xTg5Y%0aVJ=1>NTYA~iqKSUSt@sBF;BDaVBAyi@_wZFKqX3SfTT_g* zyQ%#F8MurUf+N2-Jk1ERIE||rRL!Os*Ea^4U!cPRIwZd>+Wi4VIE=NxVx+JJT=!#- zW}pa{>gz67#|o|3!m2mHScbDd+twImq;K(#Ev$NwIm5#43OEK|jY1_`*{C$_`QB|q zIHSU-ynWzDL#JF<16E7C^P z@rJY!$qIZRZA9f}rb$42=SQRs{g+4^jL?_c#KOH~6rm*n_*{*WFFVnPL-G`3BHuz= zzj-eap#kGOsV0{q6VgOV1tIkGU0;6J>+k;vV}lTM>pHskk%Ujr2YR04lU|^7=$XZ< zpWDD}ScHdq(}tgIcuf0na6W(>S3u+jk-BGu%HADTL&&kW(4ol&$HNXM&wj^ObK}Gf zy7Q{ROu61o3m8kYC0}X>3R>z&mOLUpgJMro!20SSC;)Tdx;P^uv~wh}MIo{4^_M1b z!i?EFt}<36X&T2h!e$=dwmf#uh%Hlv&`vcdD}(@x7f)pD$3aMlM1Rw!x3shd*#`?gQSh!6tOKRUN^f&UtCy{tEkJf{0G zcG9y21kUz$U_uXH9Oa`?)$n7EP|G%4I(skou~qL2o?|XgjjTEL zAo*W#KVpEuv=3_-NF;)BE^&W)RQGz|*Rbafx*N#lyL*urgU~e%7zd`E6uJ}M$u>kp%9pAYg^{LXDNP6y3(i1$B=nDO- zkq7E_imuVPAzsvEpqgP^i<~Q>t#3>(-Z*h_@yvmJd*lvf1YUpfe@moJO5_aBJV_^TRM7^D3YDfvPwS;aXwaBPqgIJ~&W&hz{Q!}FlC3ncGf`I58?`1+^N-iI{ z1Drn~HPF;i5p7`R*uXS3FmvdQiV$;%&sf3-=NXS9$1nx7b=pOy;Mif!W=-r{=GqO( z2+u;h9Spj!RTffMt1KiZbp-7<=o>XEKWQ#)=Ab#Ai=F=M+kX>t=*%u>I4lSwaY^mC zbu_oSh-2qmsD$FvA7VH^+xhDK{+Sx$!~Wsl9x}U-XRJ?m#n822NO{o#?HO1 z!`5scv0Pk(aL9RN7d8X?E7>&gK(UM{N1zL47w47?G^rH$o8+YF6uH&TxLhL(jw9AE zqYCpv;zX9htdf`tqKQ)dV1-yuIa8$tx)KQ8Dx*~0*k`b3%5361@q^nSqO9h9c=aW- z-xW=Xq6hpSuLww1t#2-Rl5aevhax59w zyk)=0@HkICHPE9P;^(9tk$t7crbc{{ms&L<-s8WF)|@bRcEmZ_&}D?<8qMV3ao9J? zGEk*->Ty|TjC}8gb3kz=K{HD4Mvd(>p5L_2FYx9(s)jO(jgorL;vL!)+YZVehp%;3 z{N!<@?rylWkD3P6_$Wf{;{V{QJZsyok-{qO3XXPAh^ZD2Ty5K7UNN}m7gd9%UsU?R zxgEgA)^(=y=!vhus&n=6+9fxI=CFD`$7(av!}?J5$ZpZJ>f3Mne>yj74KMnMYgcnz z`dD~9VL=EBfT^IcjDEqLr+u#q(IkK7>KXTH(LDC2>omJ{V(i_1brU1+{ay{kvAC7A zp!OBwb^N(bOuZQQZ~h;?ql>TfDO-}b7V=I1{tk1X_xby;PVn3raVU&xy^InwWD+c{ zqd8+~ss2J%n<|sdnoV?I>y`3>@5jd)2F_K5-x7 z(Bd8<&FS|eKMQs_NPYTQ5_^)vMCwA3W|gztIxgn%*NA61UG-Ym`BN!FxE`Y38kB)j zmH7cl3whl*1ILN3>N$=pIYDAV++so+m;1^Rw`lR6i5T5F=SvbAJ30%2v_Te2`An{TDL(DztuMfDN$x9E-AK%-Cob)4ObLMT=S%jYA! z6V4l_FrKwzzN`xt19?1}D#Huo?CZo*Vc_yJfker9wY8D$QWl5M% zW$(wjX!aM<_f6wN&z4&ClVxWAN-y~-3gBm}B^068b;Fz;ril0R6yEWVS9$oMm;-f* zc(0!Nidpm(wxlu_dWB5FRs~ptTF%HMHk4V@?tN_tpe<>m*H>-euRBSrW}t9HnkT#P zvPkmphV*jg7>9+*(9rXV-Uv@N z-VKPeV(!c~kYN{eLQ(=cr+jCWX2NN_VHvNvk2Nu6Xe^*|8SD2(igjaggc+q) z!b$OnRe^pqM#P|6yr>~dB;KHs2YwhBqx&no4LHv@0}AIej<2?NYXjycp6hlm5=ot@$30pQwPC-4jJ9vv z?rhjh?hOvh7I&ZfW?G8bRcCA7D~LZuR|71!8BoS|+jGx5`hv9Gc0#qVoj8QHd(M@< zZ+Rn5>nz1Ne`D6fqG;H=FIHXjP#emII)2qQlWc|DW}X0`ZfDq_nKt(1qglAee=`|z=n=23^v%?e0%)<5D%f5h;?8K#VovkXSqJG75cFVt3R zK5x)6!Bz;PhS#5D=(b?eIMS|xLO5>>?R7NY;SbhTRuhY@VI5MUoF<=fjR|!;GkOli z@r@IH!TGUVqZ2JDI6jIJfzvz_z6^;O6YGa!G%@O^44gcnevEqXumi9kEr*OT1XYmw zFi$pc>w*G=QYd+2$KJ?T2&TYOfslzbocgp6+^84eQvF)frd2A}RhsLfB`1Ja%n@P| zj2bDGadW-oZSXgz#%ytg#q*pQ&IHbRJHL|1^oL7<# z$>c|UB#Q&1mU8_al%`4^NSZQ2%zE&*5e_=^wZBAxBFX;|1&ZTfx6f#UM_Q8f%MN`| zkf7p11DZxQ=m%6Lr43+2Lb+bU*zX?;y-RJd}SkeZFlf` zB4}tGOJEO5SZeta3Myv3!S$pD+5zXmjhr|}=Wt7gTsZxbmS4*9xh|jk@tJMk%QtiS z=1$+j>03H|o9|k19u}v%@5cC!_DVUm=g#e|wIR_nH*m}6wYxTJMh&NW+!e=@{kWFo+T!h??{OhaN-og;-%OqZEN_bokwl*`vzt zzt&TRG+`gF4c$6pS?{5&%~k{j<;`AdkL+Lw5n`fBQ(q5oic?z|4R(bq}Z|l z+mzJlD#~m~d5z*}WyL$UH`-vdRHC=RDe5!*3RfZ|)p1W>o~+}^iN?d%`?$W?T_*2h zIyUO@9(TIOJl+#d_qfM<(&?Tc_s|ulXr!3w*(8Yxv=fflb#uk$jA2|b$Bs$#GOa_p z&Z~Gy#aGD|i!wcv{Jn~HHKL(DJ=^}a?#VB#@#ZsY{I}XvpS1aIcK&6ZlyAf&zV{E1 zCh>u`}9Ptc3l=-)tAbByJ&ho$6f2RTQ$5b`Z&fm3XgZDG6Lr5F{C zbK4N_YfB`Z=(_D#rEL04rr(0360zuW+!XQY;iZ_k)32=fMs?O3YNssv2Y*Gmqdg-> zq^FwdgtAqCW4G57)fGs}v0m`r?X=l<#WH~-yM8{|^}XEFFaxAYM9W*de)!m~ucuw# zFLr%B?fQJxE;VEbc{Mq)>$}y8P1>cqSoc>?6e9TsMy-9c?)zU@_x-fAcSWePEj(KH z{U2KQ{jjVb?SEp$|N5SRv>vWV>nmSKXTI=2{gJ6(@xI1P<@jjZPUsgDEc8kJrpONM z3F~K8!rf4M|E67b^frIlTX*j57Ktl7^)^#)!(z4GDR0@6y>5pMM1M6_PX*dX>mHn0 zDTQ8o?tKSc6ZA{qkNXz#wg>3tUYgoq&K;I~H6WPwtsq2~jwVMR0+zQUDwd}lriTWe3zFle_Wv|7`EOD`T`kjyjf8{o#NV(d+GcaECPJFYzNut(Kcqdu`i zk60M8W`?UZ6GuEF9Lr*L4ir;&Sikn2upN$d`Ga*}3$2xPut*KC#$>tWceZk}nTC^P zZ5PCMf3mIRH#XC~Zij_)v8)BQ@}8~9cz??C{K_BNi`~~VjM1~xf?SU|HYyUXK7SsS zb!6=EH1?i2e=)tou4s^%=RWx?VOQm@8-yDp zKf#hr$TDYS@38Q#NTcRe1nt!VJ>x#Ck^5(a#(|{>?<|Jj$r4T62bY6mZ*!o6!XDfs zg3DSHu-v#Rx;Qx6bF&V_1Em`xf55a=TXYQ(bAz8}w%Jo=U9 z&Z~WyP5l~kfU2FXd9oVO2A940gf~D)lqAuh$%*h*@VTPIDq*oYAyTAAn2Q23vxde4 z@F7)bh~`El^f5c+V=^o;jp|lO zy^ZBIq)~@)&SFm5jJIc8&0x1g1MiEiZGNwAhtsqeIGY$XWjT#MiS1-N)DaJQwM9KiBBZx?+_&#DVrG`k)gm3H zMLHTcPgwt%j$@>*Ft4>$SZC`_jdJ}VCt68PwA?{nFTQ%siXL~MXm*M|`7=~x>;4iI zc~G_zTf>!x8MT<=2G}1im|$rlhJxIcj~#Mqr<~j2+Q>%g=#Vv=bH-8LLR=Qo{Y)yj z;`6Sx?ha+VeBV39{R0jJ-nf%apD|Vpn}GmdRct)4(p*K>W-C) zfCxB2Z?TmTqTo{|+aw-c#JT)A6ZQNK!u##(8wS4G={-0esc&m-tcSG&zk7G*nUZ1t zBEN~~#u}!~T#=`MCUPM2KKo?yV=lYYoPrjR7o}sJPWkL6W1Ypm{Q95ew4=r6>zsC} zyln}Q5wVdyMIl4S{K#i7OYcqYWI%f5VZk^Y=7U7dhOoUbZeeW$WX*SNSam#~lhg#hJ!qJ>ycT79<^c&=XxE&-T9Y2qFjHDQqe4db7S5)5_KJDgS z6+R67TupU%F(xP^lymk?^=Lr&|FKS;IF5#`q!Lv_K5e405%I(rZgRF0he^y~4m!++ zv8+iVb(}>%a3s7Qp50NEg|DS??R+Y!C8|ahxo3Q@ZpN$-_mZ7QybJ#Z@#|weAaXI_ z^ti7o%7ro7EMrT3Oo>U2tNEXv-Vqd9g#pYp8#69N|XbKV0a21@{KSxB1f

    zjIo85@5c&`m@Ztww$1(Z=?d286}(&X3a_BxR1(4s&Resq$L!6j_}h9!;Q?%^(1dVb zCWR=hT1@ec@Hwkvb&^EQv7Ui4AIuA$XUbLbCXNQuFZxts$&L{>7F-u- z39*eyleFx!f1->BIg%qRwbas}xKNx0$zdZcc5jT0E8n(*_EENqS-jzAI}pp40c1hc z4Tm*B?P4*BBU1}KmK>)x?QzQ)e!ELgiwj9IDSTx=nNLbiJ;oYd+H^B&701`H4)ROc zch~BplV44r6CqZmaK~@sS)jitW1^*8>I+%m1_tf3SamH|zi-&Zy_W{#gFAMh!wSb0 z{1kQG;k%7JnZ5KDTHK1@>Miq_&7W6^w~T#v*!Pau{OKJ6&a%~*v2Mcey`vWjBV3iF z#yR>*I}$5FPv)qbeZ99V=ks&c1hzx#-{Vrr{jMp@7z;wOIG*G_L`GB8h!Tm<+lIJ5 z$=XiW>@xst;rx zi#bkG)!nL6C6?eaV%Wda)`C2kN6qKy#7J+9s0mzlKg~ut%?7=vHO|Tu@3NpkByP7c zCM(*{bCMprrN^2vI%0V-eg7^GQ?QZ2Xc7(-(Ac2B3?#)Lx0e#yZv!&_AWvS*_#JYOd-7%jb7mr8ov17VY%==v?gC$(rQ=wptGV z-l#zn)4-tQ=*d-Mmpk;M#R4U9U|hb{UsXdpRmfSZm?Eyl{mfs^%81oZYIHwlKd1Lw zb*lqw@BRx58!n-9;5f12yn`t$Cj3o5*c!F=1GC84a%aqI)YV6%4sLm5vMA5ScM0nUaDHfjWoP^jWc22El92SDO)95g=#DISC zH@y)na6DUF&E4Y4G2v;q+zYJA&?q|Qk7{2Lk~mwdHJ|jUO0~8#p4f$#EOZq2iji)# zmH%et|F#<92fh`oFf^66x{-+%QzNL zxS(`On&Xs2k3R}IZBxIhA($;!u_5i*?_v{J;~7DAka}G|eGf`pnsC9a?-PNZwZnVl zQCdcM!g&AS-cRoXD%=Fc8CIHO*{K@vL@-aB4~&?K6HAtLTfYyhIQfs@N=6Nut8{3} zBK3^noV7e5z7VWpz_GyiXZULn>5t<2@u)P1{TQT2|Crlj7e6g&or#dmGSxXbemm3X zyB&l(1*>!qv=yGkh#)nZbH-o}m!8d@%bo4xJN278lX{2ree{=*OQ;P*!8}un6MWH`iipQLU04N24_nR)+WzA{;>o19=bqx5?3*`bb?jT*)ro5gOD;9Hj3c6$ zeoOvRw7L>{4;qta{aN~Nw1(0y#*1Y-(a3k18prbwylmn=O0!SK(H#~01!{T%T^&EU z@R-vEzigSJ!UMGWgTm_jGwX z;WofFx+1avpZM2sLju6%sR`!$? zoh1K`o|7ydD|wqTr^u1n)3#XWC~pOy2^phjkGEiDrc541N2nE&BV;5S+Xm+)%gsJG?K5|K~6`faIbN3RRVfNL!t*eZC2PDG|l zzmnoiF1OTP*UG$B=e0Vob-DI8R=hsiy+<1&=v@{> z51xz7)e${5uD*KG4UC$HC+FNV&Igasf6>zgy`Ql^vOIZc1JjH2q6!|jBr*M?dd5fh zrf=L^KEC(kHecX23|VuP>O}Td;?XCBCEFCsC!=B`McV0j_{J6sJxCrRLu#DuMXnQk zEApl7xT`IlREMn0m2))K4Gt0+(t_q{lDOuYYdbeWe+aLv?dE2|##0a&3TF{FH{Un% z6r{ZUx>DZyu5awa8K{THI{QVMIA%zNa6&nK0);Zp=KdteX-dvy5&#>NQaG z_3W=>4mZ-iFslKNbApdSNA>PIoFu7(IdzGPJQN?uJp}|!)u9= z@I+ZXS6cCdb}VLw+-Rro`b0Z@yUgFHEMTZe4&|wEl`}k{W#%}mc&y^mcX}INr&H4j zO~eyT$ZTENACOl)qtf9x*qEy_ruEhZGWd?|xxTeixAx zUPL5~=xYjr&~-#4@hVI1*j#7Fh&{CbNAHx>D|Cb%^mPBIJML7={fEYHMFRX{ z25wOs_X>B+t8B?~#%dt1YBh-4CG8Dnu(lMoh%iWY+YsmoNJljT!`?ytEWSsJA%hY0 zmVLvz=iy$#hOt^WB9lIy@eJ4|ddc~{c=|87YY&x9 zm5hEd$x9t=1R)fh*rk5t2?>v5JSL_u6{TZa5_x*clmCVCb2Rxh%_|JFMapG=nAqDf zI{)hP5x>+JX&DvoE|CP5&mw!mpgyenXp26uzu0<4XO)kfRdheA!ix&y7$bmkSUoVk zxh5y#St-i!xo5<1jm(U3;a+;h)q4Z?Vnc*FSd*9~O9iggaO4cF$kX(u$ktb!Ya3Qi zai%<()mH)g&<*V}krg#xbcH3hiRK2AEP<(rKZ$!R6+isQW5bz1r&Zihm5=ooi1}qy z{06yt6KgwF$z5}pkQgb}J;Oa#vY5(CtYMsODt&{kOE#cj^okue9pA#N8k#lZGbg!% z*#e0w^RX3!>x;6+NwEcDrEsxrV~#WDf|0I7(Xp&`!|50im&Vr?TSO>^h&3G(#+Nnp zt>>Z$Hs~W{FhRQM6*=Awa?yetzL-L~?D$rtw*88+JgSFz^RAllkp4YdBV7~I5)B~ZyP({lT+2VYgSpXzMr2S>p z1+2l$dDYpibC@VfU%Rpc@%JB7ha1tUiw6F*Pg0$=ywmLCDRTktiEN)eDsdaC$4R=Q zJ0byiwbEVEJ4XOJP=5Vh?Z1dX9{CsN3ZH=6V z7XLr?-UG{ZUC9!i61*7>?EHuD!+}ne$xNMF)$3Qku5(iqMZyNc?AUQYQat)hSWCoI zs;DTTY6=%SVtnEuD-iSF=|0R91CeNjkKLY`m+`yg4mp;fVQ{`ItQ#{kst>tK=Jy@T3b>ob6urvwdFZ?PYqSmme@kf_c7c= zwPQE?8%|&_R8^V{?9Q%Q#>xT6aHLxq9&FqYV+uu8IM$Sf`!far&1`AR9Q(cfy?YHG zeT`hP<(qG&9KZGM%-LC-)n^IG6VY=XK`?2snFid`6Q~g;j22O->kfJtD9pwck7akT z%o@@JsS+(h!>8)V$5W(2@dso2Pkb65jp^6k{C-UT>Nokuyr30$oR|N`_mbZDUi>6) zZbJr-|CtsY?|Q6ke)S}+eA2(p2Kg)wvmuz_|1~r7zh_>~-lFF-0wyNt2fkU;a|^kf z;^HVFs_MYdjIMeMrc&3Vw>W!nqZ(*4SUU-R7j?bP$Xnl@`ygjPqC9biZo%gMz2^3D zTnO_z1$U2}t)uULNTiKv}TIz7DlS=f3B1D}l9&Q@LF!q3` zB!nrBtM|3=GeTT((sMOz9)FyQ9aFV_YZd=C`4tbnRMMsz(ONGCA@3&RQ{b;6Z7<}N zdBIrEBZeqUiT=Ugb3G->Q<`5@lTJKKKU&$?u{KQp%gTPXn!U633GV{2KP?6*kEvPl zndbqS?eHGjw_EKe<|bTk^~6iY@lMJIkAeXsEnW?+juo5S^c)}Cs&Vg(YTlZSq0oam z!B1i=-T4`b(YO0E@YhIEg>y4O4Iwlc{e7qh!srDz3n3ifze%c0m2-XYe0ugVk1$^< ziEC$3JguJ9E*SiO{ZDq`a<`S)hsw=*%o znR{S2!94bj|7AVhiOi(_POOBh)y13iSknm4pM{db-x-NM2eH{6;F^5FRHyg$D)q)-(8zVp8640g5eJfvd>q zzE@#6wq!%8bDqLE|HfQ%+ywh4kqa;EfUJMhn)BP*Bo7vxPX375NC(U#ertcTM#pJ& zK(|3KBTb+~AVrM0M&Wrg#^0>bAGM?(Tf%D;TG4*fjz6~KJSM2n!K_1Da+qO2Yv5Br zearu%B^pg}Ve42`rgrQmo%yZ_dfQ*lQB9?->BJ8C7jr#NBaHpPQN>hGcrPmCKk3=I zU#tr=W(_%axs}fSyp`HNv=a1xXepN7#<~SLT7y)v0oxos&CHDEpRY)Trg-SEKL*Nh zd}~1H*Z9qfyt5rZ8+OZf@Xn1-ICS12;%~f^Q_Z7g0dJC=t4~ls$n<>0Y`sQofO+fx zx>on|67GUi0A~SVDe#y5`C63JiVC@I*%daxAz%!u(fK@m)(uN@m=dV5P(Ei21)cDMEpLXbim( zR)qg-B%Zef5jzu81qbG(sy?Az6E)@38)CWV0M)+lBTCmGY4#AAsGS&laNJry0 zc4*Rf1H~2?xf4gIZGMF%WsYKC+_2XnBAuSW0!F<}H$jlVDX!~;CObp|TCEI-i(xVM z6%;qqUBzS|I}s;g!D<>{LKS5ToOc#Rv<2%dQM5sSEF-Ad-ZIE}t3B8C%ZX9CAOMh` zD-$z6F?r3gF~KtLUtk*uUD9j=G5QM;HUq{gp;j!m8(PV#;;03?SYzp$B8zr0g%SV1 zt&CW{^8eeqv70}u1oA(4-ymQ}4gPzh^$P9Nayz8u6FN(>Oc9a@|0=o8D1~ z|Ltkk{5IlX;ZjuekWsqEJ8;e@jaP;Zl0Dbv4xK98Zz%30*oRezEFCx!(OOw3+cnCF zL#H)d$on-{?h5xX5Ne6C{}}HfIT?G43)N}Wi8%rnpB*98UawB478i$6r*TM_ za?ME1^Ex^*W#E8ZnKJNwiM&;b`yX*kH))c>mUo$`Djcq3ibo(X4P}0E6&i~8v!~E7 zz77YFr2+S}?wB)*3??dS!ZOQ9E{N-{l|gB6OaPvuRU{8M#hSa(cJ$JLP(u z@Es`nB~+Iu7P`w_4c`)yO~T@8I*n;v_gmZfWJzeVqz#9vj~+SLIBoaHDP%B@N1h@T zLp+S^&M&a`mDK3s6(!8H7&qtdJ?zj(2;m#fK&0};-j{`V!nmg6N)~BpBZvk=`Re>Y z{)6*q;q_233Vyo&SjEHL@yn*d?8_^9f@<1ce*wf^KYp^O?~Ffw(h_yy{!)cpuG5;Z zZU&*;42^2`lzoLBCHkeGgCsEYqjlCJwiN@{Ix<)wQ1{q7cpdLa>J$HMFFoTrq(y;m$jJYliEO~=#5-c`L_Ac@%mlliBrKEtFKEBAx0_}C_EXaF} zl@r#CTetgVm6IBW3D$HAW|nEcj~M#ee(~9Fy~^xAN7|#M|M18rVT(lLCp7aVCc`~D zk9-DZMI@A`xX|Kv;QUszuOIxD?N{Zd`dJ2DCf;3+m?0{T*g+_NoAzd1dW_^*Qp*Y> zmr087TUR}_{bZrPiaOq-);(b{G*k9&Soh%r<=!ln33+8N=A3=4FZ?>Mc=^rdyIwnd zY*A;k|Nj2l%d=8_%vr=5E?hr?G$H@M@FBc3qQB5z+TPUsP`5nSAVIKp&@KsOJ%$c@ z2{{_?elgtsi#V(Gc9d5BvKpV^J>$g6Vr|s=rL`{hVVq#QSrgKio=c}Hq3Ai2UV&iP z>Q}~y++qGKOL?{O_X%x+{P_Jrs>bd_s>UKY`WPW#NvC8cLLX7pP`@PSHtFD~1;ae+ z1%E%yvtF=bY zN_{LFXSY~Z?$LH;Tx8qT`Z;g}Ap{|A9AofAlaAbIJEM=+Nmx0L&j}ZfACdU>l8gVT z72#f35n!~OtO&Xm!ZD(Kup;cqX7U%CDZaCr^4x8vvb+W>1A+B9%WEm9-4lUUe(G0W z(l(o!x%6}t%nV#pYi&V3u*0e&PYSpLynn#=yXny&dQkS#+ z4tp1gRB*-4=X#dCVZk3Uy7I@<^RCZi-t`>6BeU_aRAJ&i{~BxczRv#O{Y6YD{#yvg z_TU4)TJ+2YG3Tx`lebm4l@`VYek~S~MznQIo5l^xsGe0EBCQ_n-xhuoVb`bl8DRh-7QDqs zB8F`n{BOocSb(?j)oX0^VZ1t4G71(BmQf4M!d@GAo< zDaOJH$pia2@Y<#Q%}Afj2$pyIm`01*HtLG>?Y=|ZRo=#Xr1oUICn7z;XtXs&OdI?5 zc!LyvIo>lbKjlR3y?wlA`Nep*PsiH@T>qiJ8uy#=o)ib3#omo~ZQFPYu8JcHc+#P} z1OKh_c?=e(b-az0XaES;l@xEAERwELXGzfoe|7kgPN#^z^x^&qf! z4b3s=Sv-70_Mw_m9auOZ*ZIEZI!Nr#`2$0N+uD0RyPaKUH~Pa6kC4nGPHJ(EGymUi ze_gZ1HBs6~ZH4U}F)kJr6N7`+!pJVN zPWBv}&DZFsL|k!p{6YF7H(vaEoR9sgVa(|zTGQE|wF^`w3=q8EHL;-M#xC7dF8*-6oUs^gt; zn1(AX5xa)At^S0m_)l2l&HgnV_d8gDX!D^CSAK&vW+_e{r^+@eNjpbA7TQaH_vO&q zbEy5@=)#h9iK#QoH?!t`i!Rk+{%k#8_7G^o!Kk||gZmt$>$rW#$A$fN^?qD%Bw9Jf zt6*e)GY;`>UWKAj>FdOJg;D+!M!URi3Fb;TnTKVIA7<{wj2zEtKhx=)t~o!^fCIAF zeWU>gWKF-*fbqMN{P!dMIiuk2JpVy%+;x^7dqcIz{X=ia11!9XGIr?~J{MJ<X4mvgQUeF88vb?Iqx}?GwXeQO_wK6ILK-419A26>O5DQI<35$`cZ5C zUe%96CfHZ?u=pAOYILp@OAlkD&Usk)UjO2~pVZaapMF56-+g6=9BqN&dSH89@|if-CRAUhd4tUQkUi0$6EHRGyFXLHAeLeS=pX%> z%q{8!ok}y_UH!qVcIOWaC~IETk)Lnx>mlcc?c}b*lTlu^$9^=*BVI?@+>i3Gc^l=S z>a$U9^WTl~96uT5nYQ)(bS#ls`aZ`xBCo59#uf$rh{F}vrc=|v|4+_>wvbDjW0qPH zbO4z>&77uVirB1hqJETP-4zwB{6a1|>Q5^p9Zn9-)r(l#x}85yAFrT<#ZQC-s~du| zXTLJOVLM62_w~1nd-QmXti5ma$1`hcix|?cX4_{({v@~E+~u~@h{4*L(2)`e$CWbY z_$jzFoYJ>5&HC4I_qDijK;D(xwucpFRK^O((1mLTfqYT$TNryGuIUgVIJmuqKbzRD7 z&v4)(N|+_mT`g{APPdkG^=vxkvy6QmSs1hAYLyug{YFVeK>Uk%rxs2VbdPzEpq27l z5XWFDrV=6aX?w=B&z@n1)J5uMXjEm15k-DyD_L}jGu-22&sLQ_Rf5#IUKml4P4tws z)ig{jfj4#+8AZWkX8oMw)0#Ub#D+^i{hsHNI6mV&$0xk9FQz+af!jGgvD6u9z|Y!h z@7h`r*<#K7Q(M#C))W_u!i#pBIS%bMZE}wNq^PwjQz}~GcSRl96Ig2#KloFhjiUIt z_-w=u6t)43#*zeEJUZ6B=F!QNdl~JgRf|E_cFcncZ}5`y>sR$0>-lXWy^yB|>mI>b z8!?7BvWpo`r3pWdwc3_!FX-Zh?GDGXHM!FX2+{;jVxKFVj>r~DjJ3SeKJ!0fo{Vj# zI~CgZ^JFl39m$M7WtjO3Bmb-HUsI+7Kh5E98u(|O|>{)!61|9FV_79 z>u9TX={0gE!s$AYd2#hG=FP8NC?R)ra#VmQ+KhOI!dVq81 zPuUZv>T&aYW`nkJ&Y{@Opf{%uG0316csTzbGcxw4VZLsse-mX9sg(&d?Y{o+pBnC; zirMYs@T}*x%B4p7dY*GnV+1SXmhSw%7Oqh*y*od`;sPd}jnS)QL$7P(?Wp@b)+}pF zMTHi3yg3ofss->3{rjexhvyt)Ia8?*s39|ZL9<6LgIYyKhRk#43-TRyB`7=C1n%^i z?)%C4$9knk8`uBjcWYf^Jl~oh|8}c_Xc01sZs8z%Iz7rooxicBD9HHd`TV;rwK#bh zXUmN1*mJB@$dwppR3L&FZhFWH#e~Mle)^yZ`q>s_9VI4%Xa)8zdYfnpP5tpWQ9fK4?9?4h7s0Zw8LU{2OCOXt*|GSS0o1Ln_s=O zyJ9Q%XK@f7)!%3epPX6s(|lnrlZsJGp*zw%XsGt*=^n&(Had7W3-)ZF}<# zj{EWa#hMXVSEIJyS5xCy3ZJ7SGty|w2GoAF8;l0=(){*4gj#f@F{iQBQ3#6{(B6!J zzG^Htaag*aB5$v9T6wf^-t8eO%2y?`^;NCXZN^-39N|7+m3#}S&F}_a!RzQf4r9CT zHyDwlrTq#cvhJfwzNcuMMB%Rtc`{~<4N)22NV)ZG%d9Etlv%S`dS*im*y|Xg6)sG0 z#M^|pM2ze4eG3tgwM1X-$r}W3bcQXl91fgvTIN(@sqa+>*z(Ta&rF9qf?e^x;~iytYkSBMqTHZ& zjG8ji&*Z1Dl(hUPKU?{+{5-KFwpE2VE8$^P*=4(A>0+a&-d8Vp61mSX_apHznk2Xi z&V;C3fmsRq;^dLP@YV2{e5myPUEXNbi4*X@;*G8vDSb!4TCl?xgSE6<9Lc&oTusBI zlu7{Yy6V<2@Cll#ZK_VN9NLKg@5VH-tjzz#G(ThOW^QHS>xL$DH;I{BXE01DW_XNp z>eMA}sVMtlR=!%xx;ii+A@fzP@CR2*K|*)FH~J>=Q0NUtD>)xv$a8gbbGqXAD&~vv z)uuFcf{c1_xp-K&^n~H1Z!v@d zW9<1Vg6#1s$Zhli(rkiRU)I$z)0D_^*V2pBi-&vb`D(_na`H}?PKLy>VVM;WHGI`g zxeD83_RgHz&9a4KYbm)5mCrqHp?X*433WZU)e7fD<0n+Hk!))Q9w9CBal4uv{L3SW z-Wa|*uwN!id|Yp_^f4x{KG;waqwn6u=rq3#+2Z&rY}lG7N7Jp5s{^`M_2B24A#*X{ zEU?q^6U@R1Oa}tDDIPOJc`_D`Nf^Y!cmO@kB}Q*d6MN7SO*31hbanUS#hGE6k)xw| zm_j%ytC~J}#H_*^EKS!itx9lgn~qT;SWqKnlc$>{BUp0T)FM07{_Y!}fLwp{RS1fe z?qM`vD~rXFWEExduX-ceUp*1OdN1mGeSa5z&WMc~Tm@=X;KVwlkH5yct?8yhC7wPS z`I(8l4ixs9F~Kc>EJ72kMbMhyR4A19j0EXQ z&MJJPUEbE^|5~{#KbiI5dn_gm3;%&g+Q z8*+Ffx>E4C%R-x^Ka%EQN1=b|`aqs)Vr2kZK%~Drjz~F;$PqQL`yfRdg@ZvXSWxY( zVBHRD1*APFCVEiyp_Nbd=~{6YhFW6tO|NDT+jaTPP0d}-Mn`?_Nxg26)|khR=zUm% zmKkMN{e{og-0N08+WX=a_tyXPx4bs**CoftIC5cDJPaNrerh+U-Xi=rK6+b^ZD^M^ z;EFf8Zw$u<`O7YB8Efyn?hVx^fBwCfwFJ)r2{~#NiDQpZ{3I*N?HEirIK&R497#vH z+qnMl{%rOL^$+A0v4s=5cRVsHFH4_Ki^qN2?)NRlbWZZ$ll+$*{JieU7GV}oPK==a*vEnKQNGA!;3Ny=}*+bq)0)YK?X8j#2Bn zBe7MbD#UkDYyHirbs|q7*Dt=Q;!C-?Tg)0%$V1G!^mO`k`mUY6Yl5;?1??eBdSDs!?r_KAB$*UYc?PQ%b^MM_f&eFQswVbo3Rp^?oOW?4)U6X3lVH$-O*9br zF?uZ{G#JYmK=qs*YmyDnvEhslDH;P;E$AnP@TzIE;1R_KsurJ{_6vQ`pY(y==l}k; zI4kIeHHA3`thO`~a+(m)y}^7e&=gzurh$Gm1E#x!MGLkkj9Q+mD%{r{QF~v|^Zysj z-8XEN&*$#1Z~NZd{aIW8UodyyusA-SyT88eTXRR=aK&=9?Q#|LDZV!9rp2KjX#3mF zt46okmqBp9{t=@^zR(TbM5TrA?$|I)M0+)oKan zt#*x;Y_I&>PEYLj4@KrXdH$S*^Da60EHzOC4Hb@AVpsi9svP|f;iD)j7~-nN0KNY^ zN-7;{=xTWb=U|@jQNeOu+q^z=9(W4uk4j$t>*T-o(NFc>Tk;K^;X`l9;jMp`#((jR zoqcl6=+{2ESN^!?J>7UffAG84wlV&uV=fl4v~yM@vuO*fYAbcIP(E7h5}{Sss4P`= zr(VMug8XY?=SpDqQCxkL=Y=eoBD)dCvDn0;WbuCFO?sROc)~CT-x5b}{HJFkwpgO` z8(vJT<_kvbh?1fV;BamC{jB^~=R0c_kN7le&pkZ%j^nJ8^M5+APxUf)?-R;LI5)b7 zv%t47bc!R!kqhiUM9IMNpBMs523Ai3!>!s1yAG6u(Hlm*paFb>p*;Qbb5MUVBc?X6 za|4D{weE&9%0w`#Mu!bnvD9<197=~)pVMv9-}IKt%#R?&AT`EpS}4Pa)0e9C+k4XF^}^5v$m(3w%ey| zzxr)Bo`UaIVoAhls-DFRkZ?%-SM$iR>5_+PxMN0ezK&{oL&FvRh6S3zo}HNLKJ=iP z0?;?=5BYtd5B`RaOEItISJphQY<*nCj8DB{%#uEGfpU)F4k-?2^EZ<3B?qLb<9T(!knQRGk5o+Orh(3 zmm#O#zKoj?yLR|~>?H@%t^>xQUOhX7$5nhM4^r56JVim@tzP1bM;uao?a?phYq34g zYa2;HKhtcMw)7qS;7-r_^(m=;e@Z%ahm9o`?Zf^c6kcGYo)R={7L9-78#a!s>ws>7 zcA0*RgkUVs9C)v{NFE_xlEHuhW3EpBXHl5|edJgOHuQ8wXMul%3*+x3PAc$|wWW#Ar)-rX@1c z0CroS4V2FMR~!D$rDqK+gZmO$scR)BqqsTJh(V|gE4!(N835d z4jMD)Vbxgk=W%)+dw!6(3A7NF=8rLLjy*HqG4nU9>RsM!)w`JA_g3HgTjZEn(wPhD z8a+m7az$|L(PX=#$&dAMg}DfGwb>8$pyl&EoBiHT_BN`1=T{>HpX9;+WZgN!6~4fN zXgBINu^=!&`LUIsBB9_F=A;*SP4*FMfUl8IyicEFq1Y2m-reHuP~H26jzu+GNkf_G zK*GV>Ec7L!A#W%0m75ZC0#yvg%rq5C#eAzB4fR<+NgLy;AD+13_8zYD<}P#YDVE?z z(#!q+d^Wt10E$ zN>d4)Hzox)odpF?*A@+?jwU$&kOk?d>*KMX`D`DAJbutm_oknM3Y^wWu*h7W-S!!f zJuIsZ_LH^UcQi9ABD?wob1a937}p-Uo8_W+2_e|CBdFqb2t(Z-y3&FS+^a^YIi7(Fr+C9-<-s zuh9^RIWB+SkG-Bdxa#+M=#E*_xlkTJoS04xR(1GOPPW-I4v`9f;jO!`^Pzj;6eX#~G9B$k|=@RrH##LAS!FcnlF= zVi)J!R*riS!!2i?Kf$bSwR~GzjG@h^XR=;2Yr11GnkoO9(F}jZd31|&*B!WZk$5Ex zU*H(;=)toiE88hYzQRI=QN$Y3po4}-);(e$<$41;a&kqdT~%yHX@Y?Y_^aDU|91Se z>JtUC`PH#-QWFLl6UIC47o4G(P?Aw480xvj@d61r{W>vWcAsiMC@E}}yLJ|7++jYz z;s5Imrr5KxYGioInKQ^ZZBu|T)~jt}&?>53eE#gQS$loOoht_U#~6RHW|Q69V-GdC znD5%%w5>_o>ejYorS_TlpOTmOpFIxJ;RL@~d$Am45xJNcB5{E+do>K_>!} z3YvgfY8pf>vTNd5RcdJ#8A}R|;}3s1Hv8lW9K}0o&Q1T617;UQCnta>R9&- z@vlS*;F-N_nc>+s6~fon+d{Wpz2{uT^jM>ks(}pSn9blId#Ku{)Znowi8#BtBIK!q z4K+c(F=xm#1e2~@;tTToA}Es!RN?Zx8&iPofn|uV!r;x(7!y@#{~l z(R0yd-LA_nzawf(HVHS!e61l*uF57n9$MI8qWx4S=3Va7s@OvMY{O56wB1!<7D+Sm zEiQ(tk&{AhyR@qKD_mpE9&qh zJof&x6~z&8=#M^**`MQChT~btxpkchAA2-ho;)$~l+;I7qQrUj#`E7Kj;eG{Hn*DR7X$u|Y$j zVHg5Y*}*(J??CtywaiqVS@(~Xfp%WDe>j2e8Ahj~E}6Url|oxx z!TyP{fr0sq+p7@MZ1BviNxaO(V%2#?tl)>rcT@pUKk#u`48A0%sfKnSww~meTQWPT zpFt~0Dx=W59_`bO8&BGj)=JXEu+SE}R~*RhMc)%+T}~Twgm}U}^EZ6TmUZCDvKZNI zwK9W{Ms7yp?g5qEaE%{@+&w3r9?Z?S!;{E$^^RL$`#t-T*W141OJ1C{X8){~2lv{l z`0KdSmW~z<%$BgEH)c!K>&9%UK0$17I}epEuqvq3E>miHskum8*wHK&N?`${5q+`# zwlSyH!1LOvPKNE0i>6iu^E1>FUk`j8{Nn;QcPURUs8NVmwwz z-NyjAJ?NS4#LLJ}UA(rANAHo@R#wZ)79$&nup}F<7J2Nk)J8>iO01z{-tcug=l80~ zTc6*|+YyJFIX1zSY`I>pe0s{uxwRDKFneB*0Yq48?ekv*t}QITVD9C2qs0-Bsz#^<=}6@;RrH6Ii$z)YH~} ztx#h&JV*3l{HoNdb*TuGtm|C&J;^G~Xy@{X;5~N{Pgt$+96VDsb6jv0D7xEg_L--& ze+pC?7e8gq`yt5{thk7heP!tly3UoxxbCO$qGDktsYQ(6WafQ!#GAxCr?BopHvl`k z_1I$uwKKXfVDEsH4RW!MTr@Ju!f%U5KhurewRx^uN4ajvl@ShswuB~4nDJlk;F<6Jt+ z-z>4msLHPx*$f$0!hezM@zPilPsWq#<^gUnhNF$Z*G${ zH5py4DY;%}{g5wLlgtGBW@D&@7Yak|&zM_}x~MiY(?pQGSHixjT>+auvo@;R;yeXg z1yLn@wFsM~g5 zYKP{kM~^MBy#Lp@SdietYvI-6p>xPcCmO}mR<0AdAY%0CUHP^R&OM(SS)Wv86z}!r zFlMMZQQgZze}}Y>(q1KFX_J^ppOEVn^~)DCZf@!fla7rVR^W_99N(ow;J2DQjfyN> zk|@EM9mjCm^LVx|zE0cpp*PDuMTD}-thK(cD&d&Z@qy=bdBCtz7AS!@42d*%*7oOO z4|U;bt|P8_@ywdHK5DE$nfBhSYO%@)qvw5PTCE?u_G6^+*;js+X7~P)PccCY%ffXz za8DhPE3n!(P$B!(f+ZbD zYP7r4k>rv$^&p8|rOV?4~&dyY@Nk~Elhp?8TuZ86O@*na<_EqPTi**z(A zTEV*W`DU4m$74I|ai^0#;Wzt`b&1bvWnJ!l;isZI^Se5yH}|?9+)J#ruTG1bU;WNj zWcjyjMcVloGdkLSfnxWHsus<(Rmr-k<)Tr_OC6W6Dz88D3U6|O-Z6xQ8>!Zx_8S&t z%KzdNS|<%hEHvR&6c~qF#c;dJsKkDFIvLj4X!CZOM%&Y}CXoFlrnKw12k94$y-L5+ zsf$nA>K4H$lYSK3ircThk1fw?#|g$i6JPg=GTk!t!6Ke6l`+> zYdHExnU1^@SNm(z4#mpf;#pzEvv4N<5YH+f#IwSicviT^vow3RIG#06@htSMem|l` z(GeTuQ`&8EtnhmFE5J`W41s3*Ux}rUfEiPyT8LJwMhgw@ux#s3sp?^{;!AZ!u1XCN zlYN05W8|v%D`0&V^j*tUsf1!{1Pz_5u_$EGl&h_x`X*Pyx;oV;TG}wS8Z9sfX}ztt zRd=O~Qo@w0QmMm@9HvR~wr;j+EY)eLETURp-jSgyA};u9q6nalR(H<~-_QiE+M2Cs z$k8la*=r+zxw@{oyjY~2-@cV9@>uuOt-ng$e2{bf72^6!w^ieUnd7Nu$huGSx8!$Q zUfAT%Q7yM!oe$Bfv|-8pqnCqaGsSXRHd}5foVP2cM?87-d~aW21ICliyHJk~x~WHxo&0nNhv7z#u4f*{|$x z^ieD*<2lZX`Pq1O6VD8am?P>HEn&XSjJPX;K$S=pwPqr|xP;KKgVm2-lPNRT?s7ID zJ3#OCrN#;)YeGg~qH6=})}VVXDcaCNN~m>Eyh=&D%4Fh$r1~OCB46xZhW6sWHp=W8 z?lWgIdW?^HjOp-9WSTSKvNFl8T!7{8UVdnL4_f`qljD&OgMLZ23wc-Iy_x+i^6t-e z-W{U<8xi@F&uM$#eLF;}bz3C}xz0X8&S+eDz`H*Xe<2KN_Rao(*u(F~24vi!b}=Ix zR@Fu?RU5N@?B(0B)+3gm{q8}kV9NqV1=c6*fcu!8ZqI}XJeZyaESfvoe#M8aOb1k?`xa3Bhm15s2Gf=8tbRdvaT6E zTx+MNZ#8(p)?l;)Kke2ZA7A+pe>V>Z+WX}%?c*=mb4xP)@i%VO@qMsm>5ezH?Dpmx zTXvtBef-I*{9?C1M=zuuhk|=}RmMJHKKKpZYpP%Gy4frb@-e@R0P}B&uLBflj4y|- zGBah9ZOGrdPXE&1mj1R>Uj_f-6Vwm~Ao@e7a)-?`iEpBqiw7Ho(!mezTc&@>KU+D< z&(Dm^_5K)i$HuX_Z1L0gQ@%gg>Rr>* zvdtXd3n9RH>#>LU?cz$8nE+k>p81^oL5^%V%H4)%-`qoB0X~x!8*JaT6XI&GuV-Uf z$m+l+%D-&s$uB2sZrd;I`lUjjuKT;smArumkL!2N2}ZqLGy>Gyo=6GvR!ZPbK>yO+ zPGd=kPj=TQQ}p^H83B*T>^Eq{c5I*TX-xF^T<2nTg=gnpd3x@#o=)o`GA4oKckC;_ z5d_v^1A&HAoUq{+`zfC{%PXSwj?Rn|q}>D?6zoz5V`_^*F_>VXVUb}MW;E}(I-ER< zw5#(8Ep5$I9afJW!Iw@akP@#OoMR zHyKS-BW$D5EQOUXNat^2P6I?=XD9z>uy%KrUw6CvZVx9z_8A$7@s7w?D(ox!G0_9U zwbKQ=8Pu8^wvaQiETA8Q5nVKfx#;5<;uXSv?H04oVf86Ws|1zi(I+VN#Zzskv4@fO z$8olFSFXsGV-KT?^+^f5uV(QL2}+QAY#(~;4{JtIf7zxjYM$4O ztPn*rkOWUiZJ}C=G$PSIT~~$jLTL`Dze)OAsK3SPR0%`6)`PmtejwbN&C4T^N59<> zYN5*?dUu@7659J6LF?a0I|HoRfVg65DzW?K%lofoK6(zjes`$37GC>!a^SLE^ zMQ!ng2jmU4wAyrT=`k`fs1{(agnA`{Y^v3aIy@q7v4-HJ%7KG^RRseiD+{9>P6=ig zz08EMJxUw;zAy?Lc1o5ziJ3Yao+rC4BkGh_3-%+)vw1A*@|f1*>ANDjt?X;q<>vV7 zvcE68wexGU>zkAhZ;r<|gG|ladkg0oqFqM%rRWFR?~x>0w{_%SXbb+ewh*z*w}pQ* zd^6y;FemUSeWESg*Nl9j`!wcx<_alZ{h~MSjqVd8%tjc|!QTUW1mFA5bRRs|$wQ1X zLyOEX=aW6D5A;t)yXsdu#J#u6K6<;QnhaMw=l1y*?OWWiYGWCD{Jnkq`|pp$?HD|@ z5!mDY3_*-OSJLi#BsMnHnc1DBLQm#|^%na$fgU1SB_VhYnw}94FV?xAlz|Y{w(l}U zd{O%VZQ~FpVSVW#>mwnf_c^6w;~&#Am?!Ie3DZ z7ae!ghaTQ>Q@QoNMl6ofimA<2@AX zz8eOJT!>Lhb6t}@Sf9^rsdN3|M zATDQ>n&^(whx}Z^@qMRfG^+1XhIo!Ydd77g20eqYgL<2ZS?nXf1podx6H0s*yCw+F z8^6$<%x8Y1cRJv`-{_#_tw@Zgsw?*AEmh-9OW$gCue3bWBKPx=KW`Q#=@ux#tUI36 zN1etx#t2#R5Q=~Q1+I=Op3{@*U2L->t=fJjz4|q^&t%U0AlXkTKR(h!`uh(+jn1OI`vZ$7p z!ImY-Y>r>x;VZwlD&w!Z-72*h!j9q&^~d-Ie$&R5J9*>VqdTzurqVM@Io`unKN|BiTa5Bk?FhFx9uxf~}S?7X$W0oMD#U-bM~yV?0TolSI&ZO8gSux%2;WYq2_wUu=9_rzcpd z{flE}4;CEBrGHqkpNIixO!-Iucvxh>u&o zb;rB~q&@g!PB%UmRs_m6(ve|hL}pUN;}z_gjnM+}eES+9OD+L+a}V9XDMcMcJ2GX`QM0^RPz-F)%zVL#jv z6}s?yjHNsvrxBfaYb$e<)TfK7W&ehax+aA0?NjrU@oBg{1iKPe!^>3r}*P!&)jZ zOs%TnbR5INz>TDyXSr`O4ROUv;vncPr2kLyirHzbcCvp3IlrQU8!rU?KAljGZbjJj z_C004IJ#`d8~ABJCgY1vGSbPw0W!q*}Xg_+~zp3 z0Bvcrf<=V_tk_&e?AE#2qsr5yf#Lt^N&(T}Td2X+IpPE}t9G61^7@L$lyMJqPI6yo zed9OPlk`~0*?9Dw>R}&zr%1s56Fk2XJpYkD>q9*MW&YK&Aa)-o?S$+6FMp+>oZqXz z(nNc+0xYcn;r;q}1;9D{qZMGb6<~PZ9Cd-y>9lK?M}9PV3#}$2BV|)(n~$Rwd>*M+d5!q&c*yLq zSc~m!8(cJfbEoN(T!b@c_C6HjOub^shM><3XMC)D-K8X1S~zUIbAA)37Lt!;Yl=p$ zTDx+rs9AIqtx6^@ycbGVn5&29c}Dz^%k&k)%a7WN z#mP~&j$^CYaZ8^EQ#nD)~%3J zY0LQ0)15MYG;@XVzGrO1VJEXjcWeKlj<+lVl)?1hxU6-`rX;^2=dG>GpwF|sy!zf5 zDoCrvcBg5)MdR^`QG9F>ZkgV1a)t=UnpZs$xl^s&A&NBX#bmQ11yAqzRj!;Z8_reM zhq+&uH{2+0?kn_;ap^VR(VJah;&{GmIj0}vd%Rk44KfZF{5uerj{ZI`Ib zMv!m0pwZ5|_ou(B;IY=0=Sa$drI5LaR00c0?b32*mqTkKF*}As27GujX$XBT>B}{k zf7+&WI2p(X>&ZW87jIv7pm4%T_T5>Hs2Wfes_#BGSz-~cX*ym1)aIMYDa4felT~?# zu>VMkxT5b)(S7#s;_M<-Xhqm3>ob|d%&P-a&NN?#9)2L@KJ*rpDA2*3iCvH6 zCTKROn>96KHE_@kk3(HrYOz^RGs!QB?B~V)?zH#9X7u!&M<%l0o%5cVI{xh`FQ@jG z?4HZ1?WxA#Ur%jc7N_Wbs(LdHxDUa}GN^MEXDdF$E+S8N-18h6&e6Y;CEii1u zH{DCaxq$JVMTMTKN+W{60pry5ren6%)$X6y4mfy#ohR=qrbFC#fWay`dw>OLX~h3a zzkcC|mG8;_>#`R7fs4EU*NXpFKlT4|3vn;fb3)2mum$p*%symdS0j`^WBj+a9ji{s zlNmVz`}C!k7=+cMhm|9^n}^koqnFrj-z>?DwI*WP@*wmNMXTKIwXc~rNNjEk2x`+X*J1l zRj}sFZm4OS^*@L}gqt~wVxzx{KsdWaAj(|~3M1dwIdl3Z0wWIq81ij@HfpG1w5eQee2*l5r=TFgx=!FaJ6nhAZMeP)O2z9a4S36sD z%&ituxQR&M?s|+!c%5$|63&mChyQ-n><1i2TMYmGffOvCEC=tYnx6ii^N zaxbDeA7dJtybhO`2JP$<4ok&*9G2oWq8fVGl6xA{Al_huZ%kgsmn)Ok<q`9p-)&zhOGUdmig>sd%cx_5Rmxd42Zlq-8C8Wm|toYl>o` zRJH!W4nYR!ctG2jxo2Lj94kwi1C3{J%^h43JB0Cy2GPNEzM{K;b-z_LcE{Gl34;ft zo?P{#m6&x4xa(m$x@s}kiW|J)DTho;(~YX4vJ>R0!@`F3ipQ~GKHzbfAMVB$!IrM7 zRqt}hun(*aahCQqhm7VT@=17;NoMWVchL?&OZj{6H~s_8Vzl$YhWXArj{5IhRuF1x zH~R088n9oOS=M9wd9T0NaSu%EF6}4Ck7JJSPAM1T^HcQ_b9AFWjXAoW|1aivma5O> z`F`GG{o-%)RPsB*v-$SKGO^|xV;XVSn*Ou6rLSd=TS6l_ZYdhk&W!HO7Pky0Y;jAE zyvg#*Z^kWsng18Jd=t0)L|;JtWaB|yI*imt3a8pg;Zhsv?Y?;$6@4e?!l-w8_`bGY z#B^xA{XY;D{Yq?tQ{co^p9$CQs;t_%+%p?U{Z*W*kQ|@5ng*ab29;)rnw zeI~rpb7qV;XQ*LqAYSn~h(5ZqCslTW6oi-4XFax2Te)shi+QWWv3Q_Rw@f=b6=!-d zbCR7L_dDz(e0DgX0#@euVo5Vfvaar)7vlAK!YPhCcw>L6$dY(lM z6HtR@dyVEj7suQVn|!e#U(ADiDW;s{OKz+FR0iDRba_ zSmXx#4>xXkY73(!i05uYqh``wgkerUkuUIEvP1I>+wY8D&vj%Yyg@x4-}-N}=#U!u zk#hh>1B8n;R(Y^aL5LWHx)E;{9iEt17hSY(vgn?lu{i6ma1&&Eyv0pa948Ix8mTYP)Zel9QY#n|PO4ZE_OfCCCeONe%;y3HV z`kaSrQL3dRv|MfJu)nO4nkHsm5%z_>mS{#&SMH3mNBfj24=ZF402K-(fH~gB_FTW1J|QGMpB+7F{eFA|WVgC5h1@wMtJXj#2MLg2DGlFXDUejaRqMs3vmzOjUCehFqGZh# zPPQ_gWc?!p8Ztw0BukKC6>KkHzuKK~LYN%RRCbhJDb+}V8vIzU_7voV&}r?Wa3aMzUCrD-Srz2>QK47pv)Ms^j!8Q&*F@alytNTVVM|B8>+ zZPgA1Bc|COvqj&-9(|XV;GSnIm^{nS`AGG?BXU=49!@^Hq;}Pksl+BPnp3}F;v%W2 z{$AzfJ1bm&L9_d!j<(76!rb{Fq#4VuR^6ZNR3$A;@^;|;a;|&>}olizft3R z-_r}9>Bu73J*X!=)Dj67>!Fr$RZY0acx^w?L+wH{FGfAAr@&~|lES)4(Z$^e}Uoo*ieZ1B6v>9%Im1J8hk79Tu2E*BJC6y9~38UI^Pu znZtt3o?z5!fHgW4Vl9Zz!3oC&VjcDJf(0;0+=Ky-yT13R)qky8^2w)`)X}RJwdXPs zB$%Frb?~g9I#|i?t&$iI>@ElR&{HF8ue5`*vt;bm9S%Y{eT)ZPvX($ zqmx%nVa%Z1dn*V8>1{W6rFNi_NyM?o)pyD*dV-$kYK=<^EFcksvM?lPb)2hV_XI`+v2kj!de4 zRf*a^xtke>jg{5Tvr3-9xba#k*+KYu5_|NNESIpXs(Vk!l0N^=%3;k8NA&^AvDV;& zwRf!adqKv$dJ_5+%08!bZd_J29`-+wb#yjENS zbEntwd|A$+wSqCww;%^#f*^0f`99CWA4MK^#HTz)rIzhhWA8YsHw{ z0{s<|o{SDbE|k*r6ZQsfyKst9Fd8VR0c4jxyf5VOuAwqS=Gwxb~|B zAwC97`JD&x7h@TP?{Jx;l#FLOIlpk|w+mY|h2{ zrh7MGdb%1{K9*}R`npkjp|jEkk12~iGT%M=^!aLywamcxx-5KjzQL9&oHwP>LZz#r z!xjq7@>MOP14|OrhuN5EeT_pbu+Z8x!oMzUfb$b=Hy#IT`nrlMFLS*C(3Pn?>o91bDGNK`%2w;$ zm61E6xonrW!Bb)46I&yciON^uy#}@qGabnc!QhO7&@0lEhxBcdZ_=*pc)}S>tgV$z zkvyq%wP%{Y!*DjgpZo9f(%wEHKEu$qd%OT&M_(UIDI6Zln}{wk_^k77Mjqn{SZ{>8 zjYNc)M*u$OAa&{)bFi2cQdoWwf5XAX=O%hD*`B0&RvV|n)l%cQOF|{VxG@t5>NHAk zy7u8QFjjgPu7|EQNRDRQj1AOiS6m8k*u&k)S_7vO>H^r;tlc5c&SQN|b9Z<+p8$Pk^^O+!8{9mP+gz;`tDei(UH1d6_n+F;8 zaE0lqIyw-$pkrnOG8fs$tbwyx&*H*Rpm-bDcS*;AkRsR#sB*$vCTf@{(O`t(epndl zOHl<7zcGRKTc1S#e~`B-tJu48TE$wbIulFFVHJC{FAl5NV+nzM6{AB7R-%8oj+NqA z{_W}{#5e*L-Fcm2eo4qESB>rwlZWf@8C08Dw8a`NaEjFEK!H}VcThs1EpRAe?qF|W z>YjV-aCX#%MaET`h~w-rT0kSxyR46jNfxQVTM{u(z*Nt4K6W2#fiR%s-X37Ayfqbwy zzov0zIMAO{rYbohxcyGaL~+TT?u8LYy<~gK_7~>55(+U;j3%nZ>&u*M8_O^8H5_b0 z-igV@iHD1;-3A9I^Z>;}W9djR&gRG#&N0(eo+AbiV#=3}NzR~8>NG8w6b`HRSd03^ z1wVY=;lvMzj1@2|Q@&f8335iPH6D6TxW?+kUB^~?SeYJFV2}0Oz$Al3Gz+NxtrV1sy@V-uD+ z7`6@G(58a{Q5|emYokiT7GxlsF1rXuFRZ+_&N7R>}}6jkCR=XQua9TkNB`-oUc%C4%+s6O5zNLnQ>2w*aOM zw5Nexqlgx3!fOoH6FhQKFcKD5-m0Z#tdrR^FwV;#d6Ih(3mffnk8+}rJB+xuPLeP7 z^Z6ZzJxjjicK^sHXZZ6onNE1m7RnQCC`a;O;(M<39v@DBhtHxJb@YymR-8yc%1nys zK>~8lNs-kMK`f9z%&0@n_~VKF>XeSq^>8B@DX%FZdl>!iEE#bYBkrW%$izc^I;z87 z4>D1Ye2|Hhe>T&D46?|FF>7mj6pj1T=Rx`NpdHPQk_T5Q!WlhSEm+OQfpr3!QnLeg z6h@jQ*U;X`o$O}1_?kg_2se%TOFW0{8k#AwajaT?ea_bn@;Ciuq}F`F89dqs=$%t* z)Al zYaf(nn0{|zdkjo8b%^R6*pjKS`aV|@!JmOs}-zeZoH-}C+Sx>X2o!3 zQ_{R?}#2WT#@w=X2S~Xa?NpnAmq}tNqjpqB@2bse55ded%u7CFt?r3FEBes7Pa>uE zR_a!F)K0c|=g7cA*CO`74s`^6uRB=pbxGl}~-6R1G@p(oQh^hI_ZVGeT371Wy~Yi`BwHf^k< z=1P9v^oUUfRr3pLoj}ZgUT1%g3qEp86wPsX6x37~xz&2-^-rGmD0^UAWh*A#Aq8M` z(}R}$t>`H3t5zhYzM`4mk)ARJxcgcly}%NVa`o9$UKCiU>$AGrpyr8YgZ~?QMdZQt zl#QNYW2jo_gonI;W}aAA)8USC_`7Y@%_U~*SKqGeIa|)wm{bpVwPN@7-pGFP(yt{QqLzYC%~%_oW~=k_@aZtJ zb^nyMckLs&J~h$wJb8E-z2#RWd$lT8W7YJ9=Q5hPZWn@&xuFqno6XLOohff~XK+AD zp9_NnjiuDP!1HdF@sh)#J#aWgoL3A6JXEaWr+>ubaD4X%cHb>35nIvRK^w!*uk1VV zhr(vI;t#dEKS5Jva!OI6NF2#ul@Uh-x4}%?jwy5zG^iK{9upNV_YB>fh}oaLVsI66 zl4}POkx|$frAYRJ^ZmgFgwqR*G_W+&x3%4OaW|H**Eks*N%bzmphDX&T zqzo8DsX%l44DjESEU28I!NxQ&tskohj-F#i&aMbbkMcH+XI`yOyf4_X6VgFW&hPqx zKjS8T&jIm?uEAauZALmGGel0985w8tT22@@2Rt555C<}14%lDa<__QYl0gS8aAA%C zc0zIyb9WNh)@e*o%`t(2<%GS+0DblYJ=wEbTk`*GEr-wjup4PCQ4)hR=^pf3-vUUK zI6#Eu0@@&)6b_7m>88=iU|blcxY`=Qq?vW})`OkI=CE?a{`?$RwxFoS)CNxS7}kJM z27(h-Y*ZBq!eLloTwnpTJfn-=jS9lGdFNoM7UR<{tE~OOXdRFRaJIIeAq$vksJNU| zgf-WO>o8|<@C_t?DLTQ3j|9d=n+_znhF)W2%D|Zo>n2+m9oP{+TASC?&e^*AA~s&{ z@Y`MSs<+6<`HdCx$9?IlJDnx2cCrQDo+aYlV9k!+j^09y7HF=wMeKEG=pDQXUa&!@ zD7W?7%1u0eCxAe}R?le{~*Mi4l`00Ie==Goi-0 zN^qix403r4(=0L#O^mAg9!v)H4e00HqpX*k>Rn^+0zEn&>@ zY*{%Mc-1zxLtRWWxe>pGrTC2J_T3CFEdtjH;uBvXG=x2FTPMh(hwB?xC?mQA;Ux@v z^jyb$=^x^l{A+CD%YF0G|NqES-u!1g<=d|vRVWcwcXf&_z~R;p=aKN>?L0H|MmY32 zgNT{(;5n9=wvPx%SchDRNuxtrGP{Y({A{T|+ONk*^1;H4nvl#7zdzi6m*dFKAa7Df zV703j2~4}O6;vHKeTgu!1-K3eOEngjcP*eg%wBr2rJ7m>oKmKXj~rRb(ehoMJ4J0v zyf>n5X}X}kg~lT`8G2ut7cCF7L)@)KACVjRpwY(|Pf{3jOdlfW!eF&~J~#sANE#c; zzh`Oe(07dvNyL%Ixvc)H&Q3cDTa!W(B&=xgp#BmI>W_5wAi8=Sh~s(W8hX^+-LE8d z5=kBXG46#n$D`ld@)-CHyL;C33jz~O)ny_Q#8F|T43aLlXkpFuNP07_ZrDO_CYS{0 zZ${d?3ac*q=kaS8Q_S4(2MHbUs<9iZALBUTgXk$d**%G# zTCO9I81H@K!6O~Szm8GECLE{TmuZj6?qmM(qfY}hSw{@?&g^;z)mtS!2y-~HR3Xuz z#ob0jtwoRZ76ZjSD!XrlA-j*Fo{Qyq*E-J{C(Zo8N`{GiKCFl7Ha0B_)0$TWK4C(4 ztJPe0fc$J+Urw}jENXJ}0khVhcBa;u7N!OLWr*|hCtSZ znf$2nk;AXC&k-I7ui)`+rEgiN9s8R=dg`M4lU!7@`!F#Nm008sD-3_ny#IvvCbWl* zEB|hA3mZr_lj`fUaA)BL?Gs;c6K4WB#qtUn$eFn*Y%IY`zwtTT`9c{hx+Gt8pEH&q ziZUDdrEneMlqJjFN32B#JN{Xl585!=WY0KLKF!vQ`8TX9*otc(h_4ZKAhS@g!VL8y z`tEP;;L0VR{dz;7;!5_CjiH}OF7P)bz z!&c`Cjf!gZVTDGA{O~nk^iR4xYoU; zl^3MD%S*>fq?=^FM{^{XpL<}R_W-O85aYGw@dxDMO`j=3cI~rXJ;vT*NCod?4EgHc z(i^EqeO24^>_eh!rLJCT%@JqP2m8j2{`u@}(sgW+nY+HsH}iMs4G51zZ-y>whG=CY z!_~1riS98E{mFP;(Y@@wT79(cbgz+nyXkB}7Uil*-(uOr>RYTC!U=B#M-YpOE`99{ z7wwF-s_flI-Vzw47ET`U(Z-%t`AzTlcYNQz*E|MQT&NTMaVWcViOISKhMR*E&p227 zNTs;pZLHmBz)HbiiO@q%MNt)~l+2LFl9RVfhpdRtyvAzQ;GN=M2hjEipu;Kdn$hv-)A> zn{{v2QhV54yt|;|=R2Fg9y}Y&5U$B;@n^s8Vh!XOVBhg&4z%=1Z?)5&vUl>1GP;DU zAABf^>rKC6sWG4w{2P`UqpREBzE|~Q@5JH`Rq7Moor7P%{I>GX-7_Am6&d2DI9Dq& z#?9YXD}rB(CM6c2#mEv>ASC>kMXm<&TP)_OBRA|m;*?QnvdcGq`hYu0G9(s~FX`P1 zJmcSm{h8;5m=VwOg4PCR=4Ij%C+>QuosJyQS$Ek(H7+oi2A1nE6NAsGPmpY(m{Dp+ zUATZ+;oWE&p{}92h^EO*gn19n>b4^VvoZ@SOa3pgLKerh#S&hz+XKt@VkP=}EcwbR zz_E?*$>`6j8b12}j7?lO=* zp3!2)LbhGU7849x@d%d4m~!mAQza6W&r}`S%qO;96{2tiZxPDp(fud8;iJ+0+MC~x z?q7G@H)e=fOb;{k-|X7-X4iV+2Lc^GtQhHk-J;`NoO5!-z+Gh!o_^n$4T{O0_sh0p z{x{6b|DJi-vlm~_$VB3->6|#mqT-4ijMZOq|1VU@u z5e6I9;0)nQh}LND|ALj75#FK~RK9Q6t$DPzcVGJUE&OgZqcjX`v^7fOK9Ay5taCZ`oRr~DvpFQn-ze6m5DBz&jPfQuNfD3R}0$U~wxC%m-sy;fSu3 z;b9UYque8w;ID94hnXu+Rm`~>>5f-1vr?{g0*}>tx~iDh{)bg9c65ihzW>sy%8EV9 zRl$f4*eJPff3i=IZ-@8G1s7O8Etmn}j2ZAXPD^yhb!3VAfK*qFGTXO!E%x&p8MQN) z7JJ*{elo-klIKWY^Cb=T$0W1YbikTyu)kN_I`khPY6GJ(-%0C8-HhyD5B=(x+@gOL=*zjP$MCIeWo$6>F5s-f@!tm`%5SBE*ljWC zRM!|I$ZhenYMB3xXt+M4`hRG+pQ7R7u6T}!i`Ahh6~p(sCMdV6V39hb_-c`Rwd$o7EB8i0K-FesXNyQ@Rd8oD zR?6K1A((<>Dafio&er#6`06J81zsAo2)rzzcb$meDh-3vmkT#-nd!|W1eCJ!F4gF1|4Myn8ZO6jBWE7z#0r*^v zk}tcX4+p9jJnO%N(AIC>OGIeEI8Um{rO1S|Bc*~6dit&}zw7n)e+XlP5OnK0y4R6} zch3iUp5v3ApmgXxi&x*bf!VMK5A~uAzqjEr?Zd(O0CHRbksCzno)Id0IIM<{V{f5D zlMRlC0VmIR#8-3k#0|Rhs=-XT-c1V_OS2_kY6l8h>PVJ6BR+#-Pf`H389-0~=D>Av zW<+S`NMegZV%O_0P2z+Zvv*!)tVq%{j%$R?Jil#u?wlE0rV62*YEV`P0T#&#=diP9 zkPvBYKjQx3x0sut3q;gz=DkxN$}USBp3*iXJOaqWiINCj%Rqr3QfOjMNUl(gcmn^OGyHg?2_5CYOa zI=6Cx{~B<;tT&82ru#8=(z68w&h~a-LQh{D<)dMYr8(vZwQR#Rj{FP!BFVtsIQjw9 zK75O7PU7XmXU}=n={YOb3CsiNoDG1hw24pE6*n^vFzR^F-*UdAx8n{=CnL$%|C1Or zJa)`yoSGTcSaEurtAkohCi)X}FgI~gDYqF`|NN_B``Ny);f{2=!wR>)a0YbtUhZS7 z-W#4{E>F#@Irbp=KX5-{fWWj5YZyo*f^jZ!e|lE;y5ZNb=MK7?$mPR5$%{ef{fWOz zJ>vHK{v6gbMeYy(8GIndps#hGEBkkppgFr7;mB{0IL(z-A>Up8aKp~nhaDkjBAl|MYQ#e>B$>+TwFYJVBa3OLm7eBpZwnv zsgn|UL&NI`nUo6mLgH;upR>{v{tfYMpN@+6@ZHSPnG_g{2yL~5ZX>nGsA7XyrWIxX;lHM4Mhi;rkW~c% z(K+7Bgu;|uK5_>*e?V%WsiPv=#LTgQX=-BT&>IyY<`AE;gb&U$9%qhW3TW%Ji%h|> z!gps(UcHBCehq{P!=Uk|S;?r+pI6vF@>h=EFHN>0!!@u2Rb|KGLpYDpU;j?#r zII0dNqBxA5ds&CA**;^rxCY^r^T;l2CiYjdY2txm8BvZv7tAisEtzOiDeyPRNz*BE ztDSMVW)>VrtYJnK=7q!^SqigCVk(FxO7(*kVm;+dl@{nqAatvYQgvgW!N`=^#ChTe zw?RZ%&HM1`OJ=_-ni9z$L3z2h*0xh|G3=Fy_>0pV9glqKfj8;L47W@%WJ^87r`$^X zA>;)?&Xz34l5x#j_KQr9^UkLxdQ?OFoHP*GS88l(#3y;GRU_g({$;f0gt@ab&e4W0 zBb?W0CMS=>zEPHeDy378%Q|D^dpDc|iYp14QF=9MY^U-3rgeUSH|JS3lu>My)O!~1 z(5BdSP)3}-*1h5k>IEt*z+`%C{% z=Vq}yFSzrx?^Pk1_8xw9 zJ4W8?y&8yPaVu#-?JLCV_;cMc^?jTRkuhZg84c35XvE^+O2oAqo|cI zad5}>tXFq^;y%Qw#oa`j)9*)q7VL76`t-ddb|;64)P*9=DrdQMT+HLI5zlhE>b0)( zr&5M+Jw&}VC~(7li%M zoZX5-C{_l`=Oerm&KsvNp0#7Xt36jYJLVr(paADl!<;kiZfD=T((XFVeYa}S?qFBB z?Ji&Bvvzr17_*YsSR{*z`pR?MEbKuO4d9daEG;+or%ox4WC%55RT)*2QRW_bCZRo$ zoQK+K78@yLNtjP%@7ua)_7BqcgT{xREw$<=%glaDFZnGB;Ag8P6rtC3!<-$ah}ZKJ zUh$7-dHA8219gdbuio_)v*;^qNo6kd44H(j3a|#XoRLXvD0@x2*R>&lwxo?-pS6L% z4w6>QMB#`uPj=yDk>(59L;ojYtrCC_#Tfxto|qY35@U-7@!S}W*21DvGh&MT4pFlW>FLZd z4hxl`q30955uR+k8xUv5N-l4LGcUCVECoLbx3M)sk)e|hgy8rwssf*oe)?Kygf{K9 z^gLrXGYS$)f`k@FSh)Dj9pikiS8IwwhF#DJNeSqj@|{td38(RfWxVEbtcfW@V*!=R zSbsKBtQ(6X%qX=IPKrmY3iP8fA_mpsMGaXZ@g|kr@Wa3u-S6-=;5_3DD4fqY-vW~2 zaW(B|96H!T6VsaNfoRr3afTQn9o}dc|L>_9oYswIYNL0!%ac^EDqe9*CejR_5_-G2 zL-vB~MP6Io2}>y4y<>ZZjl%D8$Ge{2d3mSDH8+OsCwK3Bi^sz64#&ISKe6y2~~1a%&u(KEx@!iaRpG zhkJbQdw$#ZeDs|WO7fOt_E-y!IE?i*Z892=q;t;kG^Ucu!zdg^{A9vj)dt&2Bz2}9 zN3Ud`K9E#(cC;Wo*W4T5rT2gR)6eR+uc_w@r5;JzJABxe$sG~A*@`U;^>cPVf zz<#tGGR6>8LF&Ui*}$y}3J^-6`#sUVuyWy{1j8RIaPE zuZxzP0A4Xih)FPNq*TVu^^&*2-<+DW#T6FMb7nXbIG^S$y_hp^nP%AH}(xI>YDGC%x{Vtv=6&D)tOap;&W#%f64_5ip@lwRtlko=Ao{U#j^~3Q7qkc5rAn^}4 z-u8aHtVLk1MD$fx{}*5R%!Vfapr8K1M?c{c?OvlHb+t@^Djg3U?SBUW{&QdC=XK&g zZY{jC5j?j$c)cTNXdO#n4@y{S`4S2$X1&4nq$b({=fTaKI7a7iONLxH{gRen%JR7` zpZoEdZQsi`bNc2^-@@rzI(^&UwctEtLFQb%_1s@eSX+hB`zVUQQl^YKtafSE`~hKB zWDE3l2AGkA@`6|zMe1gWhjJ}@J|CKlCjynUnEOK5GRRb}fMp;=Dv zlqu}_Ut(x>ik2yz!d*}*NG*Zm&*(8Yxv=fflb^D6# zGlp@&96Kh_%d`&ZIDl((x+j0I#+%Qq@jq%)ebVNu z+4(2yr2HTz@wI<|G>H#<4HBK`Ui%u@QeA8&+f;R$*X8~qJrHOE*Udss@&c93&~3nAZf z7C6N=*%r3PyA-3sac&#peQk-P6J57~Rmygs$?mrxsYERL95+RLdU`2#-05dle4{$+ z4YgAi{f)n(Jfb}#N2I5k>V&dY|6;e-6x9_-%CTPX-tBI)?}}vtM|S;uvg>=fr(p(2 zm57#?cKz_NU0?5ZeZScC^={Yat9Gd&L&&SiiCy2VR&3HP-Nm}UdZG}?H!y1Lt##l3 z!Mg8vOM6#@I@`jnb>Dx{y6>lD{b>IaEB^a?CenJiBCW4{A)Wcc4fRK+e#QG5GnM15 zZ9Ab~P_WQ<>NiDpXir!_vl8xx(&LAA+1cCtwzuxw+bt4Txa)1E-iF0$Jt%M4lf7=h z2BLp8R!;@mN9!J(St*5HdhUIIt_k`j@W-)*yo~_89HprZ=G>1cBF zAz*nsvJxWw4h#Ph#~xHG;wSS_*jjsvhC#b6q1BoOTzc^kgJhm*-vBpG6=QFjd*rCu zyyD6e4|`UPHR=;P^o)feYi77wGjYUwgkxE(&Vgd;4(rz#gza#w%NN#xEwonF!6G%l z8k6Og-`UE^W*SbGwIPV_{$yLrFKnixZij_)v8)BQ@}8~9cz??K`ISGk7rXZ}jM1~Z z1-Tw`Y*Zv%ef~Tv>&V#SY3x05#)& z)&OUFEef`jM5-+rNnE{%Xsa@=1+1p}JSy#J^w{<~dhESE;ZON3glW~;qIX!5*!qJp zRo0kp75?uJNI_Sel`7+FHmkDdpY@PkDQ&5m}Ru9!tIho!1mSWEf#4 z1@k0k_45c#e3w7@Pp~8tvdlfQcUt&Xq*3!Mg7#{G-s3*3k^A=ujRQ*&-dPO4lO>us zCYOU_Z*!o6!X6wE!DX!pSZ-VuT^t#IGF3GQAT2Hxl#)WjwwKJ~he>K-`+w$j; z#(Sjnzl78OdGssIomXR-P5m5mfU2FXd9oVO2A92ghc`e-lqAuh$%*h*@VTPIDq*oY zAyTAAn2Q23vxde4@F7)bh~`El z^f^1^V=^o;&FWT3y^Q5Hq)~@?&SFm59&gXMn!#?zXts@K6d2NzT=v_Fjrt3thJ6f* zjOa|*7hppa73Y&KeqkfN#2K3qm-A0c=B2iOvq|4X(mzO+T0csbKlV?%cRhTc10z+m6(Q~K zdlcy2J=kU44XUtyu*ycxa3ZU0+!W=;(C1txk_^_l&Rp-i?K1;f1x!tabGr0M?mO#1 z7TansHX^B^#tcN*GvWv30lY7^w)s)rfYY=XIGY$XWjT#MiS1-N)DaJQwME@YBBZx? z+_$eYV)iVZt3^8O7U^i*e!}|CbQ~jfg?X*5!a7@z)F{_)a-x;wM9UrI_2R47tmt_M zie{(ildqv7TlY;=pl~||)WejPp=6-@r5axb@lWBvg{=`iert!1<6FR?IojLv1jV& zBh4LRpvT+V-Cp*{Bd1Ca91nUm?E5j?)T5de)Hlord$%g+^}~CulR9IY>F=Lfc?$J) zvlwMm52T+x{ygrnVN}goKgo7LWDW%3yQ#(PFC5JYcE@gq-u(u7B5nuCNXO4J9wRA6 zCEriTtt+bU44;O1tO_3{ey*mvyBHG`63RJaQ#~3G{(r4gCyt|GE2%`)kWZUvY(_jW zhMS!2#94L=F0iJ+JeNrlMFIfnzHF+ zjrL3pMHS&5_Bx#Ch+mGB$tw~to7HAo6;pP(9?^6W69b4CG>CGVBhrDNMB}d5Kon~a zl0O^{z~cJ0iNrfmF>)&02hxIkM%+Nv(>*#1n)akhfJCyGRulV5O)EA}dm`>RpFmTH zh=!}+%>F$hS`_?|eZ?4CX!(Au;Ed_Q6>QtSzdl{TdcT5?*1W> ztzs5$_}LD`@?`*75Ou?8O;AHDCUItJp~sTr)OLH^a)v+LrFV-9Nir$Cv!CowN=`k- z8eZCTd(Z6li?LH?$tV-b#zl~>s{zVxRE#*>Q$O1PoXrINZYq|Qd zVHZa)4aNs|44}gb#})h(bsq5D#-7Y5y@eLHBDi|XJZAItD)E-F?+*Lk5u3kzhk&ze zHD;`v@OSU%g~A9|C8>FiKGTlGO3;%z>SkZ>Ez9|QpEZH)(E9hdRC0gR6!sVkLb5oX zI1Mmfy} zy{9$K$`tRipg<&Uw=pIw+Rt;69=oN-nlaC*B~1Y;Z+Z;UtVOAoTX&2hvG;bQQ*Yzi z+Z^{fOKT5&IeOs2s~&I+EZU#5CrObjCN!1^_g-k5PrdLbbRm{3J@$okX3WAFEOnwp zcwixc^y$4wq~{i~ZtBwFZEe;WM{(3%iNMA>))COZrP#e%$EDR=)d!Z(pR`JG3_2{@ z>Ce%**t3&0%K>b)oc_I8gC?elLCMjRtHv&O=v#{gO5(t{e5-$|hIXouvsN)hT#Lsu ze>p27RzIoH{hIxp-fz`I9a#J5zp$|35;_Nt6C2Jun8IShclyEBsI?!MMb4HxW1gd~ z-eP@G#3^td++Dd1sXHHSR}Crl8+Dl?hzxlvxqhk66In#jvj;?Y*f}W{p6r~2*d}&P zt@k)A1aYU)VPuH`{p35n5i4*!TU^bf#g${i)3DqNtjf?RI_68YuLwz;t<{=O`c$P_ z+Zj*n!b=u9ilbtr8*Sz9to(PYA%5Un!3smu8Udd%H1vo#f#38RadO0gz?(j4efRsX zz6Xg*8h75wqfI~VTQo21h|k)3(Z4GjMkQs2bAzsCioQ_>u#BzpW&$Z4DUQw_mvxrz;G&whwaV2x)4*+J@c{q{X5 zacRN@v%c>L^sF5|MjoYQlqZb$5AOZ+KA^%)P@G|CxZj_SnTw zOIl|lWV1|lPLAKsH2P`>;ZDIS-4ktvXE7p3jpm#&n8T%Kd(Y+0_VJzi#hppLLi#@X zOUNbE2BKh|Da8rC@oRkU=>FvI!_$K?}O<5iL z7I$^xn!=Jx%`M}ID5l?%zZ9*mgx-V39>SJ!vdRa}X#=!YLv>*BD+|x35uqXV=I|!@amWp=t zx^N7**5ZM!f@kQC$aLvfQk==#`WIpzL(1IyA&9o*XCIzhKKdu zqPg%qb4wRn%14CNarf#6czmYVxmM?A-2O~Zl7+ne#A0^JW0WlBgX5L`TG_AF{aW3x zb-DH(D_)=NK1LfN=v@{>51xz7)fqiDuReRyO^lkGC-=E$oDUwMf78nVso4kb>qowA3PVzls_=86NveOqnJee;wgs701q(c)%X4l~LT^F96K&4f7* za%1LsW!;nznPqg_QLllbulN2s_V95g9>#!E)DuNU9}@HV-FiyxU8nuDV6A%@o1l`C z-b-y&I)`|q-E+j9P$2#)GKyr++U~rx%^oqS$;y}nwjAEcBr#8n0BQXh@9J?+c+NGZ zZ1l)+zq>wjPgnZEi^FS)k?=%WJy%-sgLW)thCI+tANoW)eY?!xtSn%tNDk$xaFsJW zp=IVct9Y*B(sz0rU#C;k2~ETkO~`CTVhyF zAQ~J-;!hV|GT4W3%S$L9fwj=Hg+M6Rp6jKGd~HvDO0p5Y);cGSj?{g%tM%ll45mJ+ z47Td3Mp?`uI9MgAZ7nW%9%8cWS;`3E}ZAX+5n%Ljr6zSw`jSCK1~}xW@{+K zHzc&gn5O=Y>~2Z`YI7z<&|g${557$H654rE#{r5-PYC2P5cW2;VOk5t^s=?E)m-qP zb-ii|MBZFPab={GO|8LMy=0=}OmTJ+XC*n}K-{N}mC>3V$4;GC!+*!~dx$wu-_1Lo zbo^K;VXXjkuKq*gw;}<)nSqC>jmHXi%&Tn4a>i;PuWB`j+a-+#Ggw;+TSOQnyKM+` z1f-*yfng6&Ka20tV#r_wy=81z_dGmSuwkqgj>x1>XFLP8iC%JkFP{EO?%GYI<7Iw0 zYmMbid2)L(o6Zn2-Sy77I)r|(;}`%{Z9R2YfPj-JH8j)funL51l-G+km>UALV05Z5 zvk2qV6$m)67adG4EZsoV0^#h$t-gk@2xGzgL5^~0K*lPBFZuu9>B}esuX^%dWX{); zPz#Te(3GVyR_#8^kueR%jKTclj}hl#x%qw}vmAMs1gk(OEU?h;90`7E+04C=$GkGALo`-`n-bXNJu zSw)X$Rd`Zi9AgAf4yy;IH`nAuJS#;RK93nOTq84MT)3BBarNH7z1R?;4%Q@Q$x?x9 zH5@rZEAlkGDYEqy=h}wVQ=BPJX7yFTK6F#NOk_pP7hPeAZKAosBuii_;!olpOT`aA z^Vo1E&}kJ1s`9b^0WrVKir*ktZ(?nyD!FS86A~lEx@Wk@N)}UjiZzV0O{H(Jb;$-4 zj9#(BrsG@KtA=LH_{>SJV75S_%6x3a;QFGhaZ+r7SSeg=+nnRfxnQI#QFJV8-EcZa z#HI1I#TF5YA!1F(gz;q!ee1bsL=%H&3+7q4SsV7q>%{kz@~lR&i=lE1cDC0%VHZYv zRW&eQ^M~nOh{=B+AAZz?Nnz$UqLUj)jqoD=5dXgMNiLZ*OD1$U85P$zQb+{Rwx@h2c`y|!9mUr6w zc*T#0p=#EGLUaj;f>765h9VowkRQpdvAkX}ZbA|z|!yc~>Do1-C zuTRg=oaDu>!?r*mjlyb%FM}Q&&+RwWm*j@jI6Bra#l|}`@3devlPh_(Q+Pv zF=^15I^5F|h!H0A8j-2%267k(%*GXuWp}X58o~sr5-o;?57iKlr$~k359ahAv1xoX zr(b*X`#Jrq-Q*kVf?D9ZF8_}0CB3n|_(9g(iU=P6nI5foJytfqT9Rfy>0eiaY!=IE zNX+nm&C2}utjpP2^n67?#RU1lS8H0XAvaT8>?K6CIZ!mC+q?x;sp;No94)xM8R#=; zI|-hPdb_U3Tic%dAZI|lJaL3(LFfLxcc8RE@2veL_@3+EjggE`A=W5tI|F{%KOx1kW zDtSxuY6VB3) zC>sY>yUBl{>}S;MowZMJ7YO}nB0zae&5F+~4~T4s_t3uGYdfW5iDT)`Z6uDqJ=(yh5u^&&W`Gz%(PZ>_ zsRzQ*3vLvOaDac4RGBL0`r!H0_L@hSFO|eK^)wJwVk#^}BI{?FTr;K#Rsb}4jGe%W z1R)k}5sc{%TK7bqoK_e1#$EIt{ghU8optZYYUcIy9K$cD<&1P^OE@C2Dc4}y?!=x) z_7CJ>)vGQ1iN+b<1ob|N-gXy@FpbPM?lJNg%=gB-VV*B>ab6XBAIstmW{XcBEUfXS zz3hKo=KeC8R}s{F9%vYaW5GuXv1#(Ih;OEQqMpVj%8!b;m^ z&>7)zil^`(;NDsW{~@20H(Y>X_f{Yk8QqR5ENf5pD0R+LIOpG(YmS@5{)y+p3pyan z-$ZkMr%ke8!Rh4Jn2of=JmRnRH#FK$)B(c=#*8q54g)D-L>h(mMvT9q(I54stvz8H zgQ#`P~P&t=!r&ET+ljZm8m0klg@lsC3@Rm&QVRJ zt?9%L`4?+FPBV<-z*)sqPk1j1`i-^Cm zQVum%%>v#eIai-V0U^@!HD>E|#0IFh{;#xpoR@GHoC3HC7?uK`?9XXcDtyI-8wW(l zLI$1-{0AeeS#Q^a<2TZl^&D1*^Dt}D|7bUu(>&m~;RJvdkm@m>E8&Tb0m!l7{s`lr z;)?HjLR>QA&IBzTc1O(r&Pfpp>_cPdjX)9pvzd6_6O7mym@3#YFIBYx{Te7Kr&ckR zdvp-}tIY;s)1n2vyyOr}A2nk=(28(0en*EUc{h-6fg^Wf4_h5yK}i|C7??L4b%+S3 zXRv@#tHTXoByfuBZ9tbDMgm%`46uuCG4~Y&H`CmP$v}2soP-6fse=ktlr3=HS(wop ztg{5s2IH|DLCyM>LCjn2xvpPM9Hk2k0P(ppA@dWG*XTPEEaUzK)`8F@%{mZAe_@18 zhq+296^rhMTC&=3)`Fd=v2;z5Mmv$h2>;)19I<@G|F_$YZvLzmEZ?IQNuO&SR~^HF zhw!$Ar7|s}(_ZV+N?!`~(Ovrp?=PADnu&)^wGv@`M~zmjlzCI5^?5Clqs{@n#jA@h zsn2n&u&Kt3W5odOBQ}WI*yzAj#mSpAGHA?Iz@Ak*C3U*Dv}plB6acC!&9%@$l6Hts zeLR7mM?Rw*+_ktFv6o0|oSk5~ZlK&v?Q)DmU?alD7*WE?#% zRHs!Z#t58vb`+uZnmV1DSR6*3<{?Su47T1zwwxPy&|0>0RbF9Oa9ekJ)O?G)1Ma?g zhv8bwQ-fP|a8+z#t$*h7N))ygZO@(NXwNZu-&f8ay*|%Y461vMs?@&LOI`XWQSCBP z&(-IXKk{MW3~+Ot5;tU7OO)(Z{f0X!ig4uId?%G%<7I}KLd`~K?69%pjH^@VB3$C? z=FU!n+h8O=nxX`(lAJquUs>mC;*%UXdn%9Vt!I6HiIz*#GP9!^EKzm(!x58(hHGR# zP%UB4!;$1qqeTu1C)N>BaT@Km>*aOP%bn=unjDcbTXv9MUoQBM_H{GC#Qr4SD?8QfN574kwVg0grS$V$R4jn5d`;^DHB|AhO47 z#oEk#mw&vAqVsedRhzAtp0@!)PHPsPQ?A7Uzk#4%!shb8LU*~T?rTD@Ng%GOQy+T&35YLSDDQxA)rLIm@;;uNVE;xe-bzQEj9QlpD0N|0&MZ_dAa*rAak zgl{kd5y}@wUuMJ;`ZXO_vPe@J!Duk#ug-VGKRC}8UJnJm;HT@4RXp4szHBOtzC67r zD5f3t7l7@x^_xBYX8ih1i`Rw6OBHgtPHV!t85HGaXjZeQ>?^b=(UX33;=nMD+E|X* zDF&`JM6kd>-F0;EI^L5sCjM+MBk|Rrd*l>TmQ7pVfcAAC8sysY+4woJp^MG3@m#V?^vQf99o3t^9jJoghE{zHrspoN(1x zBu5`T1kCA_tVC!%sx53^;&VH9aMXito{fTkALiL8SVEgswk5wj7CR#^KyRtperqL+ znr~&42|`hJN@8o39sV8(2R5sv9Q)Gy~1EVGqbpE}N=vCQ0~{mi)VwyXBDU<6?ZLfkRN zphc5bY_tQ>$Ll1hoNGJbg7G69-(GU@Kh+}K3oQbamXj7i*Fso5+KU!pPdbyo=uGjQ z&XmWYGnHvIm>CEx&snCWpbkp}YWb;MZAtrTX2#OfQDSD`N@cr@%=&KUaX06?&VwYyVEx6IQ2bjcj_tt)eAVa~4PuN#W+rQ^U@OfS7kFAUB#qJ5 zG3^pJkkNM5fq|8|-3BnP`5w3?pW2G#LLFz&-!+o6o~?b+lV^Fd)@twTrI#qV#^fdj z3+b6^qEN`FT@p>cpD`uN85* zRdwVwozJ1Ac#oQltEB~x{fUx% z`ANcJuSnfi{kMkSc-ZyHe?~C?5ewd;ClTGY75*DBQY^q*|LWDZ`Y>M&D;Wg~2TLyz zVQz7}Pe;REdx&(5J}M&PLVvYp99k_?Qf3s$sED*ZXeTZQQ!JD zJ$;AmP&bwL`R=JcneTy-o}e_^Ek#Tl`}TYT7k)Y4BTqZ!K@~CVsf1Gakk3&NZGM; zjw-@hkn_?WYYKm(_`EOrvQ`|MpY7Fxz}7WX$6#b}`GxdDHKaPQU_j3E{m69?-=Fgf zLV?@+dp^6Joo6@N!!RBpna4P(i8;>re~12c%@)@LX(P22_IJcMQKb0nd4{{Iu>zbq z)91ad0o19U+-YtWItBqrd1DQCsdo2w- z&@^#v=vuwbg4lRHkEnE>PrloL^mc!@-21{7i_fF^t_E~%aBxIk`y~KqMd#Ns` zBkBETzuP&gf+^M$_G{S@7RBdy%_yJf9PW(lak3uowF?hK!`(`~|CS!`5g8Y5UQG}9 zh4b5iXv}hVo;HphcQ~^zlo7KP$0}nHB;IBCne5~04twGpNrLwx!#VLbbJ|(Pxbx0( zQlAEXp|kbE6^+eTd4Sf;AldFa!)W*C$moZCz%mTV%D;&IBqZ_a;XS-ei9*G}>=8my_oXkL=@NBrS>dOzME{W#Jj8tML?UPlj>WPuf+B10=9{FPCXaYJJDMZ{EmMs8dK%Bo5R?O3S<|t{W z+sp@};*g8>q<%4@m-uLmhaNnaaEj!qCq?_IjCYR1G+bec&^5HJ+fR^+{}gMy>%XSq zeg`cObv~5g%5P$gnTwOfX=5FgxSb;#3+<)9+j5BZ97=yTvan=bV(QGa&CIpmy-Qm+ zf7YHadk7@qVANff!F>+Wb>6;X!xvJO)hUsmqLimd0fAL(>XZ#h4afCHk~eIx+~L`}bwfbq8z|MxxpIiuk2 zJpVy%+;x>6M?VR72<4NDwxSRg8S2gZdZ|Swhoy2NS^zjesr|G!mQ}wnFD>6?_;m7TNSXJ)&+;3{b zJ-qvgCuiPw#VLJVH}RNj#t1!E(^*$y%`BbXV(n73ievu+|O zbct%|U%X~moZ~q(sHEq34y=|!(%z)BJ)VQAC|E z!Y4fYt`h5U5=c##CoL>|n#Vv`JxrbFYEvi5yQv>F*Y8#RC`5vNRS%2X_@`#)TCsGQ zBX!Qh!uR?Y@BO5%&e8f3oqqT0#rvcy=Z)#=>NSFbu!W>0)-pJcQCCLa;m@fZpW|UW zsd16tF&A`tFILPhNA?RPQO&v{!W`ZmPWf(ZspU*;_|2~Ms?t;25%GxX+ZC_v$qXPu z7+a0uN;6lB>EdUoUFx!2$GDXv>kPjSfAvv4i!A4=Pw?Kl^OeIwjcqkXd8SWpX2uB* zJ!LcKhPei`8qK;(Hp8>^Y$@z(*nE1jhD}$&9sQ$Sld(meM5oeTqfp`2XZANDH~7(MQ=zf&n11ry0XEOc5I!oTwk=ST{vQ zE5DG7j`GvYNQaX{bM+$Tw(h{s)9V%Fu=tJQz_vYtvt>UszF|8_#`pEvi9NbrBW>>+ z6i0}GfXP>j9o@xb`6_0c;nfQBZ@0A3RbWkWbp+Sd zsC+dQz6#7JASM7`#T;e020}W}aN~S@yz`WgkJWW4r#-`gi&4VNk?v}7Gjh7MoU3Qk zn$OY?I41L<$81`8krb}I< zX1YdEmJm_oIlGZYmpH>cK8|cw=~E?0t?L;hD!hqWNqbGh#2k1>cad3?c+9MyV|-e3 zhlE&>1k~?wE(zl^-eY{iE89f6gC4j8;}c7rkp%p#ulBC51tVLm8Gq_)I{KR8L{WIr zZ!`MRZ&L^7*bnkrt1_gbCH_{_ik`qyo7lmh+H4g0$HitNdZ3^Upf{E{*u>GX?lq21 zrrgVDKdo8}vbJL!RCt4zoL@hy=UC5g6YhmLJy`b$&f17R#GYNua4HRWIBuJ*$+m(f zUfAw%EL)Qsoq)hi;3W2WgVPbwLJ6^!ciLz6N6eG4)ikF<{eGSddXHR$lLkb~@3&60 zw4=x$_)Qp`FVSYey;xs)}ET-Bi_#w#df;{C_j+SJ0dU65e<-` zO)CAHISBaP*q)8$ZY13EBpTPuv_oMD&hqiizHy91uo>f%b8094Z=2eAx6k^@xe;l{ zZ(I9)KCryUDfjw44o+Sy>G#|B@Y#x4^0a@RkEgc)=gyz9Cr;Jl#`(+!Y2}4Mmd-(FOk5G&9T>TbQrEOXZ;Trpo!u-yd z+9xe6B7WGSg&B^p{-Pchvs-j1ebvIAXkL*Jpl_afsdvR%?$6>NII6#q6h1k%FsS@0 ztg;r^A~GIU|o%^{=S+T`%?HE zC7zLbojRcQv)`aJh?VBI@1dwgM-p@DdmV)^aRKek9O$dWa^r`k`^oe6DyNla3)kH) zUQxa(nXRvCmF_F%l4B3|`KshwNNt8U@fA!*@8dA``+gH6vTE9|VnpVBRLS?`jT0~Y z6(LXNjAKJo#y3)Kecdx_iaKT1?3$k0BL?hs4p9piBsjut!nj2A>+yXvA|Pw=zS@&D z2;S%nYhpPpm~vXyRD7xLsDt=rWN$Pkoru+3s*wr${(+6RKa*JAJiq(5?|VAJ&0aCmH45uMstNK46&RkzHVm;b$08E4IJdHhXI|IY(g0 z&U}gUNcYG&PZ>CS4A#{A#7j@Veh`JV@)?SkXH>P)ILg7Uc^jvh-Os?8y`!p0lXj05 z9wVJzpiS=D@X@Bk-CWvC%N@Z^f8TmX+22|pa)c;1=pCY_%=9zRvXvS4q2ALp|4GIrpZ{ zt6TPMtDUc6{UEwpZP`kYJe?rznl@_fo$p0FM7}!AfE90iHH)7WweeIoz85PB@zp-C z2w>u?R^|Z~cq@thtlC8J06WYOicK;ay?AQf)}yVSXGhOIz~7W&<#u(IQNVCo2iD7Y z>SJE5Ir_3m3n_{Z8P4o%8}~s4nf2gu@j$oKLiaMZ7(#(L_IwqC?C~n_ZL|T>YJyr{ z=G8vZ5YKYcGK$oShkLj4)r@ZC_X?`1`#qm|xuv;GNO}9p_b{O8KJGX1PtVM^jzz)kTm>DN995CFfc+L#v z$yhihVG;|+1L$EcK6+!S=!2GEnpq>ItA`~ojtt9;7#-Ea62eKjso|5ym{p*`QuP*w zRSAx5)6h!<1l3bEdALzB21`zzT6l*#-hE>ekn4}O3W;K+dpMe}mWg6XyoxgUXT1^a zua<~ky%*)ZcDxI}XN-;NTm@=Y;KVwlk56OW)^t;$5>FqE_{;=e2Lk)nfUwIjh%-|% zob52F1q&B@0}BP}0W4CBnBW$G7oiGPBS=kfDiq3lMu2oBXBEEDPHXG5f6d&LpR9WD zEf$kHIsi8tu^t3w4-aH$M#G_RDo*{Dfos8b#~+YRtb?;J1ykS12%8xZp0d;3F{5p_K z+Y9}r>m6~b36*V~k#d@mHEQ6nL5egA2ZLy^Alg}pbz5i!xIG9ax>NO`nNRg8t+)$9 zEus0QSF4Bpx;%4JbC>p##g_-^^Xh`hTu2a25_%}XUTh~6+OCONpjcz-_u|fQ@3tGn9JFiDW^~szS#^;&OXd+=Ig-MiImy&aL*YNIN|cV27#O|Nw#OCZ-TzNz9% zxw*T~8brv&XI)x4eLMYDPrp@(vQ`E4A@X;lhAH@@^gW-xQ>Fylm>d5EJ{T)UW&aH; ztKD#n$9=9}^EJxVKwQTYH^FP|7)Jz|bTc_;I6b!tEG_DeWzd_$9gB-(Qb6Guv|5z$ z8yX1$oWN-_v2CV+ru4~a7l%UGI)O3?3N7eF9Rojl+e!}=<}wBlJx9ZuWF2H|IO9W# z#=unz@`<5%)wFBy7{v#o7N48;3uDlqjDg zDc0sq1^H+MOm_#37IaUTwLH|Oa9=l!+WUf>|6j0n-_TV)U%S7)?R#tYXKDSvVC}x4 zaeTgZe|_7x){d;X2wj_sY-p^u%`mP-MN6=kHlC z?~;@6QWHg@p~9Lac9kEc%F%x)K8n18A*5 zV|=DzE*7D*b5PZ+h#Y|bs!}4R?*`H9pDoT`RSkALHWh>m}vm(RA3P38~vUgSu`J>+OT}vzNvG#4Tz;t7V%WoOu{6P&FoRI%v2% z3)8TTf?#afI9O{e7T7?fw1_eYhiB~@kaQ!lz zB3{}x@7~;g_U2#k{kf-{(199#to-}4zNeeM+oyfM+HKgMg6~$MNyK3`J&NhT;Sl<7 z%RR@cOYW-Tj_JYqt#77PR9xXR5NHN{c3`S|*PUt#z}RR!WcPtF_!~Sf#kiJVp?Rik zy;3p9r(R>sl3uYuImhq^o=3#$4y(l%!*>rp5RsL|RzZGp8aQ{xbn7yJS#QwUVm&-I zfMvrM8#;)D3TDrQVv55$=Dh_$&QO(+yW7fB=(<06$Z51M{U(I29lq~-$$_NnfPSb~ zZKv=^#drK5g?-197xW$V5?(yUA;s4g{bIi6+w)A@2nza{WHY6u@5l#ta@Ma;N&Wj% z(y6=HSVGZW_6J4b1&-8H5)GS0;@|OxjpOP%AX}hbrXM{a=*u$;?)C1;qlgzJxHzM@ z9R<97x;EE2p~%FduF_2#&4L_yS&+}cQL;2t-SX)&oQB-GZxg4bmu6p@I@?$c76M1EC@_ce(dF^kx=jobCQd^ zCjE#dz}JybyicFULa`;9th>eAuA2814U4L~lDaa(0f&RPSr|)1Mcxj?D>o(P1fm$s znW-w44fCyzXsFM|Nzxcs{qTehcZ_hJH+PwHPh$yw#J$|_&u1g}+eg0NuPNgzk#evc zXZk=r|8x4VZ|K7^eWVT4PuH5;=p;623#IiD+?G<_YN;xr@y4X!hO;2x>8(bCsiO(b zKSV+LDSbSSGoST?koynD>E4V}q5_9?12i(%Mzd`ML=VfVf&OG|^9|L^4I{hS0Cg;f ziZQYQG4Nx_$;G0+FwUsTX`GSv|3{IJEP1{hr{-~PzJW;IdfoyVB7x0m41P?*XEMma zf@|A0>y^Q{7myM`l|sj9RW8)0>-kiIgGQc38osiEV7f4!kc7tC)PL3n0zz0z`ro&K zoUIuM_wb*xW@yypzGcnOqVXj+etkZkydgRvrpbdh#Q)VBB0k4y@B6XU^9Zi`y&QVP ztm#}R4Z zP)x|ls1gi~+~Rxz2ONH$n6SD}B_QM!c9Xjf6lvUHKEUDs>kX#ZvNCIAc*>bGh&XLi zfH~H)Z@m*0ZB1Jpuq!#! zd$vLO+4Q{fFHq%n{I*S@@$_3bJ&0CTT(!!54+)1Yh%~0c$Ttz?W4Mybx6p;2?M|Y@ zqNE1dIeO{G*^C8&*oE! zemQko@dvtrZj69%7yEHw9=y)~py(1cQK(T`W@PHP9U0E2co zA_$YP&mzbm7VZb82~CZf`pB^zaUR${+t6ii_F!ZWTw)kj)I&lEI3aniy~Aoxpi6HF zbWk{HdbhoRKAN!zBVseV>_FA8WUa(d!jVz`298x3- zLLOX|O>jK4pu% z^Upi*rp-U|teZCf9A&o5IcxexN2xJF@6gLze@RhGOL*-4YZS#EaTt$Y=j_k^EW`dR zMBN~ni0HP5TMVqX<9Iy^dW%1zTyPer@70j4m*a8i{qY}oyNv65UO+5b{urslu~5cr z$n9?>O01cStpC@do5*ffJv)cKk4a>#{zov0{(hdPH|M!0+zeQK%2)aByVkoHZ~3qs zJjxv?MI)bs6@Y^ji}gj|#Grwg4o4F#1eO8^4je0V6gq}35S1OQv-1v^KS9e3)fjbu ztqgSFvi-BO`ESf6X8?0N(W_Y;2pcnewWa~V=4OhEAjL+tA<#~Ao448era_AWk`1nJ z1_Ub?OM>SjdufhY9KH8pTdB_51oBQzrFMsKGn*>48Pwex=x526q8sclR9fK24Mee! z6WTjK#fe*utykA-@1UvyQ|msp27>{Or)a7H?a>NU)z+{?Q8pujP6Q&N`s4fc9ky3> z0hVG!1w8`!-J2d!UjkyOsb-KJTW=X=XG2*sc?}|kwt55oC&mg2<}+-sLP)d0GqNV( zG8c{NlsG@?LcTf$uYKMc2YlsC`l@#(7PV>(;XX6`jRFk zX+l`26WuFzME9cK39&Ax9XUcQVV~I>K1It~u(B+AcI&n=f{;dRM#Am^k=<~OABEUG zC!8M4&A5vvk?ZOmw!r>8+mh$ozGF+Cn6>8kuBHX|+N=0$ztf(M78YbnAn6_1QnhVI zwp5=)Y;Zr9N*7oaRBD$gHN4bZBrNP`CJLpX0Md-Upuc_2sW;GGJ=MvuO>)uHtYCg; zmHl|_pW&X;J^0)S1(>cLD8P6HI0oMDvYQoBVI#)1Lh3OGi0wgbx)UxVw>oic9nan) zvaL|d%N`>dhoB@It`@nDSZbppIwjW7F>mlXo%2W4S!saEfxH4nU$;j zTnRf8QCuB+YVedUAiFA^xt?s8Tt4SiasmxEgLqo&uLWw%hG&mH%-<%pYF#RVB@!QR z({-*i#&tgh7ZnRLNiAahB{S};Bitm$IR&~0*#PwH+G2|t#LnnKhrI(@Ht@yPbJ2(> z3(pphcBUJ?Yx9`3j`Fr=Yr?+FJi>{HYtM6sn3)p0up7{gr()b++atek;eAwZ;D-0veKhXM`DFZt<~_>TrBXQI$zs|a=PzL^T)A1(UW(cC zX@vBRRF3tIrj$g_TCVzlb<6i!(j-+$+lKod$CO$ArindzRepuYzHr``i0pFTGemZx zX*+2e@m)o~*=ryt&FI8OU1@xp=G@H4391&2NLq#J;$oZ*&%Wn`Q1#cGfNAYf)e1Va2fs50OrC{Q<*~yz0tx)mhdu z{rFj?^WWaz9^OCe0Qv(7q{<2sdQ<7dViDD{FV9{w|%?Lg;W}(8NuD2 z$m`8!uPKIC!^+^cbzu+dozAQyJ)vjP)oKE zXCti{N5{J#YM<;QW{NrIAg|Q&D=N_x=YORV^M?v9^rqwOw40GGPP7ASVNc&*$>;Mf z<4E4iB2kmZulMTb$R9pxCAb%@++eXrs)5ASR37%x_AD~%9B=mGKCJQ?4}=iT?NJzW zdW#I(D%A{CN1tA|-Td12N}*Ci)^r-**!EhnBuCADXs&wn*b~e9f6j{q4lcMBUQHZ2 zhlq3{Q9SMCJdq1Vj6S_9-}b?|=W8SMNmWMiUSF0uL&=HiUKaWs(lJX%m5eD(Vj_J) ztXGsTU#z&fsWVJ6HcD85GZt}vrwoC=YO*vc(r}5R1ZR#ohSQ$Mvwh-q+Nzh)O#Kui zlvQS_^?g+d$C!=}IH%JBhLy5F2*hbfB)PM+KPGyp3r}+$k>xf}Ml-9$ zDkF%V_mye2ejM75BaP3t@-sKPw~u@p6EtI4xGo3osWoy1sC|!IxvV(i_2$3$rAgnR zeXcc2=rFn(UHOxzXJ*5plz6Rod(#6dWIuZ_xdU;HdUrY!U-D*KIFX726c7-8i~6&V zhp~Fk{;5}-2GcI|!4ar0rrHYI@1N*Po)t_EOA4J!y~AMlLUPT*9op{>&=8^96cG7Zh%UT7NojAjp*eiBo8vH0-g^6tAK{IovCT+k;0X zw!_oOFwaJt_tP}mmZmm==r1v)L(W~eUo`g0{Z6MYwzStRf>|c{D7fjjpP$#BXLZC0 z#y{km$hqJ+K0FW-kma9?;#cmNK zbgsst5Jgk2)(yosxf=XvsYu; zoR-QWs1xA>3%;7j1E{0b%`?I`bb+h3W-AhMG*edg+Q=uj&1)`C6lv%8U!{sX z);)FeQ`vSK)YzdFlwIh|$XOVjfVLaQ%T z{WB<$6Y33f^&4G4pb!nR7p;Me=DSv#?Y$1GafsL1|4ZSwHD_u8dde5t;aY z6>;sTu3_|KH`If8j%Mu5L>yaIR39iX7?e8oSGG6$C>oUU>}SRNY&^ROX9ii!8uf~r zFkfdx-04A}N~DT8I3a!_^=1!6M~>--|YW~J^X%dfX6Mhi#f7kR&DfBwK40*QNEpP-DCOLa}Qhv zdlt|uP@mZNKI%yv+h#ZCb#1^5-4+@gV_I~-KeSDHFx5U#QpK-H}?}IK&cf8SM_c!0@vd79C^G{ag7rXs=^g=q~P;d{= z%Gjrv4}OF9n(EiPW_HbkY|Jk`!2B%Xb$|ek{^ihAW~6M=4f%K1=r4V?^x0B<75u~} zs38nMw1-gT4x2|3+e9%J3pOyN#SZRkroUvL-Pp^|ZAQj=fAq-Ad?`93W8L-&t{lgq zj(E0V5?dbKu5WP#)lIjjHcdHIMH`}ucbzSuRP|Ki<#{gHa*lMo0U+h z3P0zXeVN~c$f~O5LyN4f?--j?7eD(gaGHQ#}VSM6DwU-0%ZAn zwco2@_93@B3d8O znQ;KO8=!-NUg}^@Z869O6A&5}8Fpbr^A4-SNn0dcolj`#Yo_Y3x*rjI>2v}qvAW?o zr1b4sw5$)@7s#e^nj?vAE@8-8HnZMtVmZFwN0!y^dx~$eFWz)m zPU+M&qMJz!qG$nz`i|b~0oujJ_N9REw06dM?a^M;8fqjkJ5;^PFgkR`a7@L}GI%nO z-5L6mB;HLc%EiLc!Ko3KP9@#?&^dB6>vp11vS=p1^Jsz^VI7TDDa?F9I)4*m8esHw zcJe=iwY#%C-RxnzT~3DVGa?Y<9g${L<LKLk)l6XSu3)Nbr8HxTWT@}g; zr8S`OCK+#`@fNGoMlqz59@J&^1I4}BJS`Hrx7!_|W_0<(=+@ONp}yY{ME^$m8Gvd7 z?oyAt)ZOh;o?Ye#U%*jXEBeh-Xj7Cy7-$TG&rzQ_CnY8XJ$mrL@{Y1xtIl5bVqibW zY47aR%R7>7|LdL<3SL%43GTKkzD})7qKnM=+>*VbcK^adb z>XiVpsa7+}@ECE6H3SD$4(#;QCNV%lS?J|(N@8}=%1kk~E4QKF3rB&&PRVj7AybE? zJ=tv;qfVJxa2!e6=DFOa#dIs4ek&r|%D#qOZq}#E@xJWl&flt?zofjpIj(O8o|^af z7S1z7y^Q2bkq@*#JV`{iThG6c7W`{zA!3hhAW9`Tql`U1Z{I%u{h7F(gQq$ITil;T5TnhNr27^LjZHO1b|
    )a2@K!|GJcbPoCD1CsmvG_??UV6y-NQh{;dvD*_ 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

    3At(?8SJ4sV~N>cJ+_r4MzRbc!R`0 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∋NCi1+wJ*A(#+CR^~2rEG7 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

    dtCWh|BoN0a{w5)*@X_357bC8c$bC78c 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 ERMcxFJLpFaED&N;pP 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�ZfLDy%plz06Tq3VqVJk_@_ikIrIt)zN0Qg# ziMd=aqe*NGT<=5ck+04@Eqw=T!mqM}u=;JO=tr-M#DHTh9@r|lhwg|>mv$w^m0WJ& zjy`JO*m~V(ieKcQqFKiC8#VZNo)?C_?AYog$YN&al!5n3{;8zgu(FpWCB1EuwsD>rv3r!F#$`QGflmdfzE78sv%^Q;=f!+3AeTx6cPoflimM~2mL_8JFxyr$SW zR_ANneoatPg}nX5V|J=zlq%*!;+6ea*^kxzSly3xIrbedUZ3}U%r->OyDW$v+!vdx zGka_veRidr7&SLn?tRZVAN+>?O-mQ_e#ZXDa^+zS>`|mAEO>k;$?2c$86TaSesFI2 z_}q{0`2@FN>YA%oC%U(ih&~}K*``=OnT(B;X{X~68(Tc|pm~T6sj;^gy-x70D3&&G zRa@Gr4qcg2gwX+K{J~qj=5%T=SJuc;hDGHJb18i7X*RARm9Eh&zp5}sO3^c zI{X@YTC1^1Kgg1OPmEh^L${u1ZWgzx_&rw>vkr{Mip`ZzLE>?!agy(pBeayGh5Ix! z4v_S1wXyWgQ8ETa%z4loGxsaori92WZ?_$M4U~Pox7Trm zk1O#o2b{8=C^P!dn9tAFQ)}-!?YjkA-OIZPDk<5$bgxSL5Wi{noN*^J5PuaNMXG0Q zcV6zz5i#LpWlREFj_72PoF_(rwEm2D^|&TH*BVnbdgQ#{-JZFhSNb7}!()k=@HDe} zt~BDu+_6|0@-TP$(5Jc6w@d#`W&uMaIaH^@EN8ewOV4pt@f^ja?esK0PP?X)IT25D zLVAnYL9qY)v;ZB?1D>Tc8!SuBV>TR5V@#{}o*32>Xbuh|`KOC485~2nl_gYODD_!PH00V5<#}Z&#@P&<-W_>F3-!6(*DJ z;_Y!_8;qKFzNY;S7i@)bDlXjhrgM35{EM+^4fjlO@5V;6rN-x z&FpJRfzWkkB=IOq?btrfjuCrk{m<4Z;VX269dvj87T41I3a( zNbZO;9JO&uSVHgj&_`Lfdqcc>`aTBbnNyosEe>-QB=ZAg_mj*IZcVPjqda!q=CyA8 zDADz9wO*wUWzjS8&1q#*|FJAVs1A}nGTXD%RCw7jMW$XdHlFav-)U<8{aLs!WEQvc zEIwoq=9_Zwx%31fNt6ENr2aB^L5>vP16iXegJ|STyv;Gk_2+#?KOjCEcLl296K3lL z`Ey!MhW9MEqtREC1I}{Kk|#7*8M^mGb_`fc4rU4FR(E2z!nVSS!kITLvpMcQNLhc8 zY9>u1-KW5=3;X%7Ho&K5BmHgoEn04&Pt(Vb)fx)%4GAqVrfI*UxSJY)+MG!d>=)JD zLoAb{gm&)Kae!gc69TymguP8|nASouy=*OPH5c4yU9XxFkvA7nT^T85Q)_TmFO}%n zQ(T?IRY{H{5Vxr#Gg`CbSg8|h`0sdr4>Jyyf?s#b%#UD9aKgSDlwMT9}J+lD|#Fm+Tj@Y(~+&*FQum@*i_ZW$Z$ zo`**U8^&tkj7<7;#xr1_=%wcO66wFxuH7&lFa5(+Ypid|mD`KnbcT@Wu4m5CA@qYC z#{g#4)>C%{CU7#PhGu#lR)La@`g+j@YeQfz7@aEgEW$W-1qu$VMF*V=LpKn$KqNa! ztFPfJ!n z8moYH=%#g<$cvgUw!)IzM16xrmLOClp2RH{#t%R1*sv!sXcY&V^0EE_F~3a4Z_ukZ z@wO97?pniylaX@WGn`|kim5!s8phrx>KnYfR09e|ulQlp@h$AEp;+j$#)>l-o1 z4O5NqBL0y7zVS{jl{8B&T5vNKQ^=N`->PuiuNcddJt&RF!^iLaLK z1-E72iRUbpL^+!%(;P=casOb1e)gleAa#OzB2*Y+w49kO&bPe^fOLp7p0X|=2Q$}I zXSeoYqAY#w%7Dq=e?2?g%uZb_@Vj-A>dxhz_BNg>7vP-8{@H_x+Ylco*^chW1mMw1 zkDA^&1K5G_>qoW!Ll3QvlLBrsBS(rCwWKKQSLWK3Qki*`_Su%lI6O7PrY*6B znD1k_iMV5T`x|y(FjQ3<73|KYYDVS&L^#s5bPqOeh%tqtHrUpbh4V880L`eWj~v^* z{e5^1AAOC?*z(OMQ;pwzcIN6VuIjUt$rI6Y9zif^u$elX(-No=CiEInsOtuL7%0rf z6_2z#NVA48L8?THso_I4#N#Q#Q2ark{v$q(kNWg$Pk!I0fAyPuV_eV*T*u|#@x7!s zz862pn_CgVxb1tbI`j*O9S}bw1{+}? zhPK1Bb$R}V-wD&dcq~+cqi3^N67&rEnao4R>mebJjcg&Htqva&0Di0 z6nao6_)eTlcfLpB?AzlWcr}7l;n)mNLnxb!J}-PAoW0;ip$rH3HwnvBIrD?()4kU^ z!hB&8*VNKLvl2^TDHB;gtK^zFO)vsr$z$#WG7^MXv_&wcKUm!pb#i)LI2w1cd-T(} zqU+?nC$E{;Gja^Spp`SyoiE|Y#HLz<>AMqu9{E2|f>p1!@TWP>_$FxgN%pq8c!cTA zY~vQAe8GBeJRAD?k{9PyvG=(w-e9%(jKRVfZ`#ZH*JZAMoZ&NeFyB(*shAsgslPY# zyaR~=_S^;C1nby${FixmCo+@XcOVn4Ru^y5Bc~DWKQl`TuQL*T4q~&zQZBHOrb-^Z=+_pSJCb)DPq9Gsv4fSso^ z$0UgPVX#^YIKTZP!6(hQ}$N!h?c)>lyrqVp85P0mUAz zz*%H;J6KrOmh4&TT&HlZzcJSuH_82z$b}blK-Rx$&iQ?Ak_QWRC%@)wq$TGOf3?4v zqy02H;I%<8BTS&fM2Z-3j>7#$jK7(qKWa%^Tf%b`T2X(~jz6~K+$X5e!Kg!9au}gQ zYv5Zzearu%B^pg}LF+QO6{6^cdp3~~E zA0{XLk5+>@^#i^)>;P~Fob{N`m2gML1msw7eT4B(NyT?9At{-0WrCFst0U%rXQv1S z)}b-*Pw?HZ^lr&ckSdvs9!tIY;s)1n2tyyOr}A2lN% zXhk?0zoSEwz8fgEz?nO-hpmpUprnjm4D=hmb%+S3XOO_C)!_yR64=G{HlWE4GXbqu z2E;|TSo;c!n`v&tVjw#(Pr`!L)WL)*$`;t~Ec9p%)>(pRgZHtVLCyA-LCjn2nb$8T z&e8<|fcRXQkogJ8YxErnmT~_A+d$}&W*dmJzc9n5LtiD-ip6$AD_L#WYr#&`SURT2 zqMb-#g#T|h&RD+U|J!XxH-E+j%jalC+ULsSs$)3t5Z>NlVWwqt+AA-uw53oR-L;MI z{F3RfnRwX5l?d;5aI_**<_$;db1ssD=YXE#)y0<7=R8(eRAc6`VgmP(8$|cmXv0;- z$&)k+XslJhmQ_17bvn1S=>b6$0AiJ9E_BeO9pY0TSK#N7&nO3XcifElOXO}`onVC;eOBJPLlgDdC1a&k%-pH z%(9)mjCtrZhYNYX#;jf8Hw=`uMAd(s?;$lAM~e&bwCcndffLV;GSptrPNyaohf$|~ zNK!e2cW)zGt_?iqTDEgkUSU}9z3%L&`4o8uoPF~Q!(7YLf?I8HRcvCbf7bF!7Pb{@ z&z<^cuQ7SwR<0hsUe8_(;yp)GY9H%`m;OmsyS%Aq_W9(GdRW*4+i6K20zFsW+OCqSlDsq)hP@SE_roxWhcRHFj5~)Sprr`%^f_ito=3d zNsgL5mB) zm)FHEcVd@o&eS~5qZKIwJLHO#fzM0itxEj<5&LwPCMoQ7mx);6a2``U0&!`m@{?I; zDB{naLc{rW*nun!_)WJX=ZqqQiAYUYW*Mmkku_#3ax?Q;{_!lz&eL&JZMI^1-UcW+ zty#EExfTcf28w z5zOO?Q>0>uOV1wo0&`snM;Fg1L8isHIsfiqg+|H{zQGJcC|`X0GBchquIZS`B28@s zv%yflI^Plh;M`kyJQR$ApN>DWc(^-!*;E*Pc}7oAO*{A(K)d z7;>4XH6d>XWw{yZ)$FPI3O!16r5~LnFuX@?tVirK297mEu)sv!_3hwsye8?L__Mvd ziLd_LBByv}*|hZy=DzMjgFaj;vVTFJ>r%mzH#jH3VzXrLBA#-ou^3%S3Rvmmi_9$0 zUZ>82xYx*>Fh|_F!!N6xa2zI>(>0h;hW&oV(AUHwPJ(~It_iPfhNHl&z zHD5w9JgW1^XJBSTLV1b{O?(HgZ#BpK!C%>aRc@%CRnTR^-Q|cGX2lUY2-R=X+T5ld zBXyS4vcj3mBt`hClMn6KS?E(y>p5zk6DC44Rquv*9^O#S&B9E`GkYTE9CLlI-BGA`(H2jO50=2B67Gee*|el{sG}baA`z;p-WvwY7ukXfwuZTr$(7yB>{u-&W)=}Y&eU6r!v zxsqOiVA%O9V?^vQf0m^@Tlx2dHbH*;eUYlMIgzTdNR2*52w2i78Hvz(R9o1-Bl~MYCe@wCJ05@Daox>cKCZF99XQD zYV1#M@MP7bkl}69vNXpQc#B{ z0x!P}8y9lI$Gj=@Jv+NBDevi?WKklA)?@Z=h%keuh8#hZ82Cnn3p;jOB><`{w z%n8N6h4R=Qe85+Wp3xx2ICN(6whFe=%yEIM#X{1UZ5`9DalT`CvUCxzFu01nrlpMVz7{%sU`}AytPYWsbYCFd+L`v z*kUKr(-{Mb$i8OPrra0ayqdU5XFOuvfn#-&&4Sm8xZJ8biki;r&{Mo;O~%#Jg4_N? zNj~Zu;eUSjN$6`1m#QNpn4AScNx4M7#;Lxu7V!SXPCxlc!{Vq&-B$azhTlZk^(lTv zIRFs}Z!waHVcQD-jTk8x;B9>M8e4tnuZB!U!NSJUOGKDkeBY;U-;8`BlF&+Zuk#Y3cXwev=!J zF1cFvKVl138d0;&Up1ZWZInyU|2Fts3Oua>I>)VX<9lk@|RNni$r~0J72WEPL z(P+06v25(y{S8w1Wq*%6{geZ-_m2J^3KkaW9aQ=t(s^4$=dr%yB6nod-TiyFx z@~SwZfIA(!JMix|)_srs@1ve_755#J^PG>pRrW`!j-`E65!Qn2m-ZM__!}kWeX*Cd z;@tdfuO0;UuAw;wZx)wd$Uam<*ntHDa_;X(t%Jn=oL>+M+}_^v-tFw%yU`zp`3T88 z=1EP=amN2U?5}IJxF$#&;a1q65#vOW;=Sh??yg1#ICGw#_r3-&r+RXyzFFomC`b}3 zz%z$rPorvh%xOgE`)hs?N$F*GgL5(aQGq^?Nn*R#+Q7q{CaDcgtJhu-AFt;(DxLe2 z&o-dF-JdPzzVOB3^{D-wd-9ck7Owye*{5``abdt-*yVI2yZ;<_J7-n!jP->5T6Tm* zi8)>?$|pL9J0p9XyvI9t;elwld#U%|(gQvsflRemfA2S?|u%$FbuMXO4w3 zVz%O3Wh6o3RfeC*Kd$buC(fB9crFT@lWa4mm1T@OuPi70H1G@Utrw|iY`*FPG-d{; z?Y=UMc7M){epm;r!=SGGi|kKA5}y&?BieT4WL1=gEBSAch zOb8BI3nIJ7I$3kDH(#Tl5^=@R@r(3FY`pmQI3N3y5n>Ac$#*_+{56U{TvH{}F`nK2 zLei;|q>DUuQjgJKObur9lAb@}569CBaxucvC-W#t9wTlPpThT&Y@WJm$5rf+7B{T^M~y7{y9d|5-F2?wL@stoRHkgomq9Um9I zx7+Uf1$&~FHC_ch^P7H%Z|f=)^-7yN#;Y9VKjmnbw=Kb12`A$)ZSiH~UW~}PPy3Nh z`}CIc6Ad^Zirq&Va6r`bI}I3rJIR0F)1NB}?)LK^)W%&$>G5rdi`+lF4S9eCS5f*d z{le#>%Cp+SpJl&)Ashc~RncGi^=tK(;(_{Yp9l}AWjUVoJ;&XQr@i91Tcf2{jyuWK zp6KHr@TcjxBHsRW#9Nnk zM0FMx0L;#R%${C&0QRi&N96y%Wunu%1clh!tDg+xMlbwiM@{eKlCrF&6GO#g?yx?% zD`3W(HFx+xX%&ne^L9*+oQ^oH?E7p0FvZk4w*!vUCATBlan0>m>qkDx?a&w^IC49r z9^o;!gHbKs<#wDoop%1FPjfrMiwnzABFT5-2OJN_w=F^ig zY`O~W=pX%>j4kRUJC#Pfx$Os|+MHhyQ0BO*6`${T*QMr$?c}DzlU|9BKXW-nrC>kj-py&gdc zi{B^@Y}+$9TlTZ!8Qrbfcs19fX1%&gI=qDj!XSkAg4?hzY<)u|^q=fszh$xN$u` zo_VUrM|NGRY0t3XVwNyVq&qHdMozbuYxQhe>sk6Sk1X_Aa@!^&BKnOIMnL>TxKlGv z6LgQUNYIVyTQHBoY*$TpGgpat&0 z_(ZBR(tw|})!wzWU}lRo<4d~$8P9@BFEH;=~>|&U-d!E9V-DeGhuG>kxtrYJtoC|5%Z6+zsn>8~sgGMWkjW z(6Gn+zrSm^zbjU^_vK#CxypqjecsQxr!j(AaZ6`@Uklf$m)`9kVPXN3&c@lRWJAwm z9I_mjHH&2QPF^zq`&;sV;6KG0W<fvRc}&azy5N#N>O5#z_?ZijXIL#uEuSu+Lo}c~O=RJMH&0gLRj#YJJFs#r2{rkR&H|{g?j5~ZhK zKghyb@-ci-0Id_jcJZ3t*K%3mH;p3i?cXPRCTFwY| z#{1SY%Kp^)P$NXOLGKVXrKg|CPeCcE`B8q>@?-gVLP@NXg*Yq0VO7~>J7wuaqo=pu zyyTO}d4{nc35U@n$*bT>h>aPTm1JL>Jn|R38s3u^ruXmSMyp1cfd3Y5^rjKgw+G~c z?YvDHn>L#UB0%+Hpt`!5HpsCubwgHwy?eYJ=F-@eE`F}CZ&(OLVTUqeB zp$W|mLgv;P3{#33u2D{%n#3&?RX>c4k8Wii?O2eI`6x5|!O>C>(4EhXzDhh4-Ug$U zTo2IYzPh?GTycC9>&5tJ)xB(Tu9EvAhkCBXa_vo>N4M{vbM9ZP`kYI-MZ* zHEq<|JD-bqhSvULv(_>(N%vy`yIv;BQK?@_lucw}97a9YinVsgHTI=IF~NcSuoU$gpQ;+qexX zNUsN%i-&njcj#W;Erw8_k3Ap7BzrsxavObsG@4-6mwB|0G$gXzw7f-X#lyMV`Dn(l za`H})PP)XgVVV^XHGI?!ISR{Tw8og))v|?Sw^DNHDxcrDhRwT8?y$}K)@_6RqVgR! zv5{=825uoO^Kn0#9Q@^;L~jfq?f70MOMG1KvGm>t&pudC5~FY4#ppCY4bkHGC@k15 z500i=BS$;D-ljX>*K`?+4ts$emhWI@p1^P*aI4}zGgK#IVVi_bESwLZhq=V)jj3V} zT7qe2iYfoGUCCaBPqfq9I{ja>cI79d9(;?%q>cf=%|_&d!0O?F0?laH z^i9RC-!e!oSnl`(&J*ik?@PgyyMBN2R7C8i+%!{WG;!i(vIoLuMuey8ba(ViS`_QbX`gE?i3qmcS`KDK+hwZvtbHlmI)##|t zJ>lyHX^nO4n7t2E&@!UzqMSF<}bcs@uk|_J!TCmW(z%&Ebm0K{6?z@(flj>i7+v1Oay7w3*m8Q@~RCWVee$ zp>CbPm;{3sY@&{dAH8j*hYEce1E`*(AtzY}9UJ!ekfJeg)PjCuC|@=07CdJ0fvUy( zrv1V@=uh5(p6CDmv^X}<4Yw4==rG$-Pl#zkK=%ggu|QL-&6^7P(Fj=X4i+ugp3rM~ zs7>LzZkViFm~UtRX!iPzdr4IWA|rm{XZ~v->^77AG^Ok?OS6<-f+cowH|U6 z^eH~pw_S@vKhXZ!j;ltu+m}J|e*I&P7WqQ=>?WcXzB^;jVItVOyEF8DhNiutnBBhm zznSMWtt!|#(^adbJa2Vqv}Akb=XQExzket)-pTX#ESPu6$#>yIk!+~2R*7BpM`1bo zALU0;R4~NJ#sF{s_bjQjaOi4z0@q-k@}q)fUfVpsa~*gJ?2k%b{&n)Nee_ek_m+G^ zXZX-tvOM+A()cgFv9nLE8vWWQ_sSpl{7rWp&>vj)+BU{(8rEVFN;_9YGMcuas@Aei z6v{`7T_UvV8kHqhcY15sLlA#099RjAK8mxC>bwvIQ)D;haZEJvC{?^4d6OPT0`Abw z;#=bAjsJ8{#1>0*e$N*ZtND^6wq{9D1#q~w`+ijZt^J)fi^u#lYtL_Zemjn{4zB-c zgg({EIJ{3NA7S5U9`*uXL)R(x7<(?T{xC}hrvJbYSTZns5*Tiq-C)&$lF(blh!-?~ zcQBNvf4&duFQ&&-JHA|pE>*R;?u;@KjOtzp;iw@DL(L05O>bGP5EMcI^>A8 z>kdW{1_RQi*)h?@-N`5O_mSjEnx9D7>x@_SolJQl$Iut^m{XxR>jyVUngy^m9X@G7 z>bB0Hty{!<`{4cTW${1p9krmYw5v-S<9c}fvBTrwK2`5-13)C3aC7ObR37d0YF?7v`IMkYU?7Cz(8WMmRF>V>&+ zIAj;S_||Y#Kr6gC`uaKI=|xUP{pf+XoIN?6M%vb>N}Ds{rC;;z$?a!P{)OD1Ys$$y zP@|7ket*{XbklbGwCz{F4aZaP*-9*lILxL;F&!ivLjP^K=U8>gT~%B$JvhJh&9sV! zD}06tn!%nOSnA$&Cr$x)H+moP`@lQ+8$2$>xRzg;^E|WlI*U0!^_pXr^oj+_HHJTk zJR(+iSUtX&zI(`lh@vdE3i^}NAh|P^TbBXCdV|Im>*2BiA{)Ng&_N|s(0e8nQylV` z_Z9>>LsdrZZmUe8Hz9QG@cr0J4y0WNj6=P;cM6ZQ_)Z?Au&;QEg1(!* zgcpx_Nb$8tznHJZ_B_vR1O@#}vzgk`cl3ihJ?q!Ir2hRb>C|0rETL#G>w~iJ0%z(e z$%f6M@$Y!U#xc7N=oV;~>BmS2#`4U9d%Z{UDC0#5F3u=!M*(l2j?J}CDD(Aq_6U5= z?uh<>W4tE<9-}~OLg`^!{5x8rZy?>fDlYqN7?AcOgXL3VvaV_nvZFQQKq`Z>Q(X5p zZq26BO9wSE+ESiriJWNwtF4U+O6T@h8~)cb+`OORuVeDs#(s^-6H<;lP{%9DA8YR< zCdpphxHx))F?)SP+d0Y(8Z+o&o3ZB4{q#Ea{2*}?Xdx`kA7k1aduF_2#&4MHUEb{M zU5xL0tMC0Sa!e@cj0JU#9-}n5W^f$QWILnDkNmiTT!gjS><4?$@_C(&cJC*98&$va zt5F7@)WQE`-Z{!Ee31*HUEjW$3j!UKA6xlpCKNovob)2E$v$EY@O35>uhZwbQ0$2& z?{4w7tLA-0$D-=4q^`_xAmQL?7TzVIA#Vrbm75ZC0#yw9%v2T2hV@oQHq>YDN!l2* zet5!$JKk{aH+PkDPjd-=B)#14_h%#c+ef|MuV=jqe4u8n5f2#6k*RRjCU+U6UYnHy$ywE^Z>4i$4`17hIEl9P)?ec?T$ zDyR31wEjQJd}Ph@<$G#=&&@Yb$y?7`AV(yKIgQDWY4}VIIT&zl+h)BonD+u&BA8Mb zIIYTs`gA;>YH)CqXPJhtydYREOgki@u{QO;^?`sA){_4BeIRFV2Esl3ue=!=ExB)b zGqhNI$&Fv{kEdvePKasp5DoEvjfP0far*my?Dag7tA4MC9yx0|7pen@1Iwwwst$ju z$u>vDAwuEL{H#Z7IF1PGtZnKKRtG!_W0>+Zs_7yW3H-*$n_sH{r+db_=icttj;6YV z#}Sj`h}pdzv*C0=kl#-B8FCRAtm%x2 zXr}yYL^HgK>*yxtu3NBm5qKqZUtk+==)to+E8D0>euIe&y@(vrpo4}-)ICBUWxfF& zxwxXysw%djG{Haxd}=n*--h2NKT$BdUmb~)svyXi(BEOd;0VQpl8l&O=*=zm7f8V2 z=Z*=Z`&0u$NntlR>p+pl73KqM{=Z&eiajfnBg0e8oI%8Cn*#K)o^9)$X3^Hf=g%IS zxz=agdBY%o@BJ^#c-QWxZB^Q~?QKg|xX;A@l)S|M9Qu&%v=5HJWvaB3 ztHS9j{raj%{2f7;9!iLy6M;zuO~5KO4Wbs&HF2*hTd5WiOA7X6Zz)#O2be2}nj*EX zsJ9$muB|$*1;^EECetAGI^o)G-ma){$hmN!!qLcuOxTrN={@g3_1Sd2@-I;3cKo(Y zq4V@xI6a6~R$R5peGdtTJ&5#9g^_O}>c?;-mv5m9JzJeL4~r5GvUB#%_05B60|Ox6 zY14b04VD-O?%8MO9{bQ0>E+m+e(ohX>o&jQd}*%yhR^0xjegm6TJZ>}#|Dfy=HBqQhTV`bHxE&SZUx^gJJzLo;!?Ud_gs;uFnca5vo->Q-%27#dAl*1d zGgxE~v3&{$k3~tu)y*5GJT#A{#KQR?G~rgG zrap3PN1g}XpMB`EHhVC#1}-@aE9xPk1e}mO*VZB16WG#Q0vi-|n%-?MV2@@bVMJ_Z zmmQe;mAsXhN;opw-ykt-9h>vvRqL=8;9cwfo>lzn?P4ZQyaF?=V=)@o(809~gJGhE zt8G*Rh9_Ya+JM>IO@&@}2-X)ZbpMODLyhi(xBF|R-1Y5}`qcNuTIbL6fToWUF&j$zTa6Mqb5ZpFT6GiM z&8lbn(DyNkjMe`LCeh#b^Ymsv_k^1PqfhlJ-+k747UL}+o`Xld1GQ+Bb1(w1ks?`N z1W61Qi0QC3!9XAtI7r}Fp`p+)41uWZV4R(IAp8khW~j!f`ztfhfy?&K_U6CQms|nN z`9!aJaUg8W@YR|I6E-(fTm&sPsttj5qT9U9);A4S6inIR`es0}a|I`a+`xe%wG63pt^`15BK_)!2GGO_9}!l8$2Ux5-xMG$U3hG6?|d7BL+nM zfX8Jq_>!C^4(&i_J;^b)WOl-zK{H91QRrEZ_UVp|Cv8b{CTT)gs1w~Qc0~80-wClU zryV&$JYk>t8$LzLTClP#Mt1AAF@lgrY(~QF0hQe_$B#nno)b(xb=+w$M+*zGB~0lZ*;2J_N48X-WNdId7p4nj1r_cx zrG^*IMZ&_4W};9E3Ly39i}|#SAhrkH)17b``K}Y!)^YDWBHPMrdD&t_;}Dc&!)%f3 z8w)ooqEjM=j(LOE>6|}UllOOiGj3}hYUbDkGubjiu`D`7_>imT&D4ertfbXTP_ z^T~!O<#SFYC$MlcsHe65TA{{jc#h~p|82rm>rxRUS=X5NJ;^N1XycH;HjhVcvso0Csk5vBeB(XLO;%+5syY=e|SCOvznXk$-I&g8aM4+y~@ekzgmPFTDW_>{3 z@|{bXv?{r`;kL&yb(X(bVvkXkUm>zDlJ_MdyPWq7k)7tWopT!TUB$lHIgpcPbmD_o z8n324H#2jB*rE|hs}L_P=IL z7~=_JP=FdQkWt~|5OvX$w_&nlh&_Wbtn{K*684=jmc z)D!LyHFGa+pNCrMa{n3qO~Uyr{28}xyY_`J4N{NbYEKmP=DfU2C=Q$f_)#xl^|_KZ z=(P=e?-^6)yK{!`-Tj}uHP^iBw9((2_b0TAcAEvYR2y+M(pqtJJo|zBWPf9xG3OfO zb+-I!mT1cJzs?f#2L=~<((!a!%{VVka|g!4p1!}*&*xdjk-nEjqb7@A@9gI&A3nNE za4+t1gT)$&1BuyG9@f$JEHmqzZ}#FmWciE-LI~IPD9ky%MTTvaI78LZrq}mwe!cfP zLxn@ubb7zB?Od^>N6mIuv61;nETed?FH4`H=0v=gg+7OL^wPnSF||o7q)&+Tiu&b?5jQtH!=z)Qh84JC z5&L)Q5csPmPop9Wmn2GX=E!3>t$EzrCtjzmdU=~^pJIlx%B;1%XO(b_>G*(iIz3>> zlm$v4c0(e~owfZj(L-H$TI+~&UOcnrt&bWRDAVyalPy*mLG-+5rq%lK)qb35eD;-} zrP;lInajew9Jr>|%oUjJd*;ez#1XGI|0OO>_71Ictyx2dx2w^WKSg?GH5_V* zSH9bu77&sBY{8TcBsJ>Y?nrXUn{AOqDh@C}K>01|&oLgx>OIG&UP&4(yU>S3pthK5 zD=fc%qAhtcm>ixI+O1&T`Fu0Y#pAK>^|;c>p76VU$hyR5Tv?ZMU-+r$%>0h$^yXam zgL4VB_SJ52bJg!`MV5clR-~1WF{9P?3lzIo#9B1c&XRS*<)Tr_3y({f%Cp#&CPcsKkDF+8O5FX!E|CM%&V~CJ_B4 zrgZ4Ji}Z`eUZvk@*Tp;SyhYH2m!8jk)^rX%je)&APGL$UJrcvhJ4EF6hH#Iwo=@vQJBo)xa~EY036 zj%STiJPUoR-;Zcfbi@YvmJXX78D7tR1-PU^7ihNsm00?iFk_0ag=jT7TBvioWm|s; ztA|0xm(3M9DjXsv`vNP*$WifE!2B%eyOyKEgkrY{8alJFC`8eeqjf{|O^$|nbf{jm zw4v`DEieXYKCRWsyHa{7VaQQo>To@WVUj$pnVpSgb6S{1RBh8c($$6;7ko5P1W-q- zn`eY?XacjgW-A(UG*egh+Q=uj&0{W46lv%8Uxh^;c~9N^RJPp*Ip(Jj=OaAd&FEDvVYl=`l;sltG!H@(_TigG(Gnq^!gI(pFxeBP$zkJ(~U7w@Qj1S%*&o; z&h3~U$)`+aVPP@@v3YnwX-q45Kk0X7#w+#6Ong6zICjKq7(Mw7^&pv}8GAF4#Fi1& z2MP=(rB3^m{f$0~1!X+PS+PDF_in+EL(_B6>SvrBk9Zh#CD|_I zU4iFj_Or;dKU;Zs8U5dg$e(;p`}6MGAzH25nIPmi`vke7an=DJ{y@A!5Y+6O_5ZMj z-}ep3xP`lzGaDvrqZii3tRLUkF*w3E%koO+$e3Zv|b=P(z8lD!$ zVBFPMKXsOM&G6w|JKcTf-~n5MvmN+uxBmF}%7^&7aloX#UtVb+uVl|H$@Ir-+~o0n zux06tH@58l|%>9eKJmiSfh6YrpgFaXgXLd+dDk0ic{VlEzR5K4<5 z+}BKh$v?Ysl%MYz8SDKqA~WlyXpf9_+ZkLrk3${#Y{Mk>Ji6W9Vg}Vsx2HZ$*;U0F zBF4MU9#CREm3(>b3-(-XB!l9u7dS0Qf%#@6RH`D+nX@nRlMq=|)qGfywe=libK2sk z--rCZ*y>Hw-LlOb-wPqYe(UiK@z;r!E+YZD{5|qH`GXwUa8$bu_r5uYk_C8AnrN`? z&`t=eeS19`(?V7Yo+w{g(~~O)Yi|3Mc3!E_r|bUib0u%!;&J`XKEYXU7mWb*wkJ}; zyp;e*G9+sT zbiPD&ZWjF#hP-97>g^_%0R-L#@wETj%jjihuc={APW znWI^^(;Ov_X7am?Ca4j%(P)&ytQVyHH!-FGW?yF~|1-$lo#pCg58v&wGi09;ff&z- zoJ)o8%6?4rfG~Hucd?0+J|_Aa=#9X+2=6dDN3s(E6t-% zQ252uR!@BoJ@40kwscnB5G}_py^DM=q+_x_5!sb@_H%uHF1@RnctesU$Zu>P-q5<62-L42Vv&$deZXL}M>iZQz^WR821I*fhtJLEvb$6?jdza*hJt(|@L@`_~N|GFk+1}~$c1b15% zU#C?j*+u5OZ^>Fwdwk&`^M+cw*>rB{8ky+C1=u#qdL@8t;%Y`69y4x{LvRptV5h4# z$pMm?g;5TtBxe`B%#>rhN*nsUa27bMlq_cwGIdz)C#x-E)+x^xe2*me=Dysf$8;;6 zek-Ee%DRSCZq}>I@x1Kj%HOJ;zofi8Ij&CznVR?K7OpcyyNvWp(GRpgB1trFx1N8Y zE%?{kLPVNx3x6~G(&1Vd6Zn=s(H8DGBVXt~m2sY#A;qg-yp4OK`@{&N5qfm+x#Jtb z@BTC02lsXI5Tne{A~Vc+XHV(_{gbm@^(!6X-rHp#z1_kl!;I(LKL4V96B}0TC}WS; z+qc($zb9_{;Hizk9`|P%#OQM+?Y>1qV^fWh-AO96WKOx>Vjm~aLqw~j44y^PGveVz zp8G)+2vP0pE>px8wGYrXmN*IPOAl2a2@x&#=jynsjw|tu!C$3DW!6sgl;qwV-_l%pO7Gian zv2$ui_9pP0U{oW#&-BD_JZ0)hIv_*iH)1QqyvDseD85H1Zs=vqK?}pod=o-w+-QuJ z*5X^?J0&cS#uy5AC%xUwQD(jqXJwrB>{%?Zg{O1X5Hwh94j$KG)$VhCp8Ij+>OAvO z%brC?{kv;9-b1lYZnb7lALaaw))N1#*jmuxsn2l68po)_%TlLQd3D`lK?wVZroU>N zw#e(N-Q{YFxe^Nbox;3&#PK>a_EhaOeVtriClxeQ^R*u<`?0zotMiyfmnm^LRjQ2Q zHaO?cZ&3F)=$AJjEN7Lf=#KIZ`MHGS^G^4u#P3qNc#c21$8{V!-Gg!m^*$1#*hhQ` zzJ47EB|eKo6NLNqU+7NeGr!S09q`_7v}k!V661+=#s0jds=sOJTg~p3mWNv8u|M+n z-J&Gj0wtJr>rTDuG}dvBkR=bH`1fDr)iL8a-I<=nHao(q9edKNtEqh^bL9ugeqw<@ zT+%=+gikAu?^$1D#|KN0W4){g>{jENL4bKlHWdEX1o~zP)6&@OArj(Fkq~5h*=Aj@ zW!{*M>EL8hO)Y~hOOn|fzrf8`uD2@VRn6{9ErxPOafSLdzJb5gzSmCP`1a@wY`@v) zo@L{E5;GvY+Pyrv&n%NVHg~u7WjB8M%Z!~M35m3PJ{{WA8~sg~JN@GBNA%+(9qpVG zzQ!uF)&0X*h1;>pE&3I;MHH!I$qRHlmXsMJDC2m(Z}d0PU(BFKL~Who^dEs@Afpft zyhZA%On0#ynzM~{I5?Am~7T_nDwJFPP4@*KXFI6 ziSekYw@SZz+7@r_q?WZ!x&*Bux!)4?Go&GWQu$8$Ce`60mDPs%hL|%0n}?b_FCpL6 zgkhcyqyA3Mly<}bIatzROA;)#gtZv3CgKRAwE8x3@H)qnQDEK(x%iHnc|E*RqUvJ(->hLT`_M$KH2fxsEGYZVBEj2X_BUm@ohdI!T$SSJQK*yZTq9D2jv)gt>8JZwE&Kc`YD; z@V*+D!343iyXNCzs}}8lPi!o1wWWH{mK?_XKzK*zu{NV4RwB^tKHSYG4?tM%58R4O1TT@9{CbW}b_t@lX%Ag9g zggkdP!7Ljv(5uf46kZdHtS~DL#?Y32pAmldCXjb3*Hl9eBq`ug5}DitmUeR)%orHv zW=#ZDxU`h4Y^FG0Qm+Pjo<4t*f`=kIlx-=dBD!)a6oI7p@UMt;p&FiKT!poiV3H~U~7`k<)7@#{ViYrxhA zdFg|sK9HAY^g#Zg2dEe9s2XqEI2m=)^JL`N-F#hA>dE#nd|ZQv5V?XlvyuE&c4D+c zTK!dg&8r)4m9fl|!qssxG(&b-4;WLXcHeodq%%8`_~5a!oY%B@tOl}sdQ7;@zGDH} zRC)%B3I$lwF*RScF}->by9y1%|JkGjqQMrIoyooV4rW%aGUn;^9UfE0JdG;i)lgZK2F*R=lP%hN<}%pXMd&g z`ep@aS^*Eyw=kSkKfZA4o<`sY%DjY8@Hj8}l0uGzlLy4+`U7X=Tv7o$4IzwX- z(}i@_&LHjwrry3=0jifbD*#?JS3nFmD?l}KSpm?pY31xQ8{EfQ#ErySbci9jrVeq5 zplqkcjm%ez?Bm?@ZG2W;;BY$a+U3fRMsK0jq{c|;P}%0=s0E)#;#FQFKHD#u9U5z~ z9c_b?rmyZaeUgiC=JZ;dV4SHHEZGqB8R3lgnXj7=MwS*1Tdkbm1ggcz$I>}?HLhws zbF8Rfs$)(VtwuhU5k(3dGc(pXbHY%KQa#Qv)%a?(HAK*m_*6hI05QeDz{HYAo>xQm zWnHUNt?I!ZL-P5+)Kc$l7QT*otCUfx#BH5Nlo0g2cGDMg_V7Gs#IIbYuNYo_)Ltx3 zjHQ{Wh;XcN))N_bikUk^k!CrWY<8sJ;T^xqmD6d%xsLUr z?$_lFH;U=|3cX`odd+wAW)~>mo_8(h^kaOFS1YbT#^GXIn>=S&YmUz%!M*Yz3OgpJ zR+*bBAba4PR2h-rV19?1QnV^392&$qV{OyWtxcw4`G-t3pP69~(cOXSQ3XBuHn^@7 zav0NDd0@9lnk@bgqu;Q~iZQB-KXD(79e&P{dMOzedE)No%011Mrug=pEBst`iOOsQ z@sKvk%|``n<3ML36UWd2i|Zz`t{Q|eDvcLO-m}pq7~z3-i&^N;qeV%}qAjka8b-3rZB|;70i>TQD6o z8`RB;=sqhr=$gf$P9+pyG^m;6mqhmSqi=zgkN)fU{xz{xVF>qKmf%7tf)GazcUrxOGr35Tmd^ywr@)Kd#`p^DZl{h3OgSxGpiE}TeC&h zRB$d}e0vhEhAcw!AaKAqHMK||bvC)$=h^{_2iREhu3|dGjRzR4lA{NBAT8DK|I)8t z_+iKQH#&aV3kcnN5Q2vbZ-`ciTof=PO z@1|Y$k(XFKdx=LMp1j1` zmG^xRaqq*`&z*?9Ij-18W@z|W$s>>;Vt{#sg}fJ)q*w11kHS2h_3;JeHsNz}wF}pt4R6s9h1j z@BEmyzw={SGyIs+)jL0?@mD{lZol?qOPl}T$(Dm3XrD)M8_76%X`|g|GJ5`IR(`&V zXRt@$b8mLZ4|AFCz1i9Qr|}F;)k0sb0!Y&DjfRiI6}tO9N1)tlYZ)LF?}Llt2K zJaU;e#Qd34{DB$${cKI)-A5+~X0dIv20F|xJ&q9w)|Lq!`gYbRTITjVhGoty)hd{C zrZ?2Ij`ANwAl%KI`C+5Ki$EB?MIh2$3<@LP=Q%U-CIYd=Fa8{X2>xXRf^~zJ5s2W2 z&H5aH*tMhk2n4<55P>k|uMr57w+O_~nCB1C2X6-#+#&YhCX3o3_Tchlsn5C>Z1@oTG>m_|ze zO-zHHbY)?f&v(2a>G>npeC8AbLu!p2ynX5+QZoD$lq=!NYYsF~j}ehHtEWIK!)WKi zffm?=8PM>;3mB`HaWWu3zvt%nx^Ci(pG<)v9+n zWY`DRhB!<6oI^%);rS%I$t2Ty>-*3SKuh_1?>GJf&SKR4V#9pr9jpG^rxk>n+Kv9( zMh)06%q;7%^|;qx?6?clx(WLU^5dA}yHm<||9q;RVveTO$C#t3@qc5EN2&TG&-e2l z>lc5Ur;^{{p61&U%fy^-jA{5?Yx>XPmNut7ZV8R#xaH7@c4l;|wz#EJZi`!5Vu*1FeI~rp zV`PjsXQ*LqAYSp&4SjTGPl{*;QV?EFpJm%dZRWa-TFhG|j>!Xsx@FkesW{VvnUi$q zxZkpm@Y!xb1WiZUi2l)ceB|9{BxBX7p`CLOb!W-1%`qqD&MTgYLSIz+# z4G=C`X<@-S1tFpk>PEa-ba-N3oi|>;$)bBcV{z7B;U>uTc#E6J%Kk5I;=jR7z!6@- zQcs~FnOrCagh;J$lonX+5q{H(PElo_OvhA`UMl>;r7VkTm|FIO`mk^i`ES;TwJ|nR z{HT@^&~nwO!v4}~)HG53jJOZ>9(5PEg@UYfERRg1BDT^~#G=Yzbo8!ch!vy~C_y&MT0tScYbjd6 zDd9YUDApjIU5=%KP7S*O4!YK%7t+R33KG`9PgT{`S5UUA$3i{tFiON>o({+)whoY= z^c6CRP$RTo3Z2r5qpWyEhnb1KTp#QxghkR%F+qGLp%RbLM7lnriHK0Dj8ozYD>=;? zKcmH(v7DD^A>&-uXrXf96fGS3I}8SAuwxRv_Z@{(gwsOjB$Gx%#QA~;b_6p97EejK z!FlKkoH5#h>=Q|s1WyK$uW~LyF!ttf!VUlP#oL1W(35>*ea~P9R{U2MYD~4| z1SIqL_9s-a?HnZ(rc#d4=$WD)k;PR75Y60dBk%BN5o_y(qD_0cFe3t+cPusI@V zmECmE?5ftXi&VuQf>>BMA2uz`zk)W0cvJQRaD2 zg_q}u`D<+osKlk|`E9)A+a1vwx4)fR`4HI;i(M^z`xg2^+SNL>@}=d?a_8V-Kh_-*{utxe0(`D=Ek@@X2xK6plbE7JBnYF)b{e3c#FbALG zdSQZB^R)ujU(YMl$23}`@GxYqCC(s2k^#AMNyo+k$1CK6tkVklXKW^a;#@K5RKHI2 zH~hQ&i>EzFTJ>PZ>-ygN-1XuWzt+H{_``nRJFXxa?F&~BUOjOINmK;k-@`|1wrYn1 zBPQ7&vqj(C9(^Az!9CAbFnN}t^PcK`d*rUzJe+)XjoMXHrV^X{(46WG6BkKE@%Jh( z-&x`E3!2>*b+k>kC+5xvA!LA->^EYaI?|XXU zGYwe;y9f24hiW3>Vm(wduBr?!GG5ycdZ?ag=E3gYK?)yBCzdY{CIUVYgjch}2Fw&m<3NV2w6`SPSBFFoWX)v5sn@su^Mm);`W7pTuqUs8nH#8o`feCJV=dK~TdXqJDjltZ}Lx?>g8mx2gjy z<(VaQ;$JzscUmbbl#f=*xKDj}pLvCxqV(kYGqQjvr5$d z$=u91Y^*4Do>lS;`i<90j2(oZJF!Rik>%p1Rdw$PnbPOqSvjoP;iz7)9CHm`ti83; z?+F?6>PhHRNc)`9xp7+Ac-a3y*3sGcB}u1H(&0?}3O%sz67{x9IU-E{O_g%()tz3) z^QAe5RudYIw0O{J3XFyS8j9;NerG`D_#zw#22n6p?Im((hG3h|GWP6>gp0N{*tjaB z=+SI!q7^S=0{!7uvjg=IGadrwkA;l>#?-*9iXCAD(lwBt&FSn~Xbq+b1A-p@V?{<@ zY;lSIRRk!4NeGLzVHG}6JABs>^#f*^0*MIACW0{#K^#HTz)sUCI;UC(YelJ89JGtM zs<|o{SDY@Ak*upuDdSBWn^Aq`JvKOz1zinU7@(jJ_Y48zefoSg`<%MtdrcgCbhf~jOPn_)(L$xGuEG{_ zMe|iTMhBK8s1Lm`)A}3-pJ1Vtt_J`5Xak&|XuI(^XjSJ`TzQe}4X845x1xkW43=94 zOK4n$ed}Z3@x|O>*4Pz;E%>S(_hwT=K&mXNV~|G6GRP5Z4_8WxW6TQd1)Ya}pX+D? ztdU@H=B%=$MrK=SKDO-GyBgEzTU8)pU?VU-F^`c%E7cp>kC}KC1`Raj!45dH)oL}V z#mZs1>1+2j>ZhZ;IxF$E7FwP=vyb>q@LOFgfr+^TPvzG z@}$Dqo+cmckSzCM^zI6S5|5nW>NS;pIpJjN5S-UxTA z5fNe@0r(u~^_9WG_+Bg-?mKw)h0xAj0v>rfEhn8xQ zxi*V|u~c0%)m14$auj8{FQ7)7WP*dk9_|iWD>$7{7r?$oX_h=Yi}f{;TVP}!P#YB0 z+-9#ppqi|{&)myjYrn{}&nPWMp(b=9PR=IE3>u6Vc&HD2oJS5M(uSA~G_t@TORP55AHo)W4+~pcA1m(qyni$?$%1?e7)T~gVq@i00x1s;B zXtJNV$&CFZ`E{%xCg*R>#OZGLA0vH3U&d3*qu&E|DY}_Fm}@R~<68p*q;%I?!4+l$ z@qoc4Y0!<|Qig5Z;eLyi<{6=K@!L^;bRx`Q$q}hQOq|ws3NTJu2hVl60{Q=D-LAE+ zSKt~9wA0+E`Z4(sxPCC!MBP^O!1fA?uS7=~=x`>60RPK0lQ7<8REj&H3)T2Oz z@ujE&h+iK-`^^v0{~zS7j#X?;I;>(jsyY)(%d(0s+84_zwpc=7U&ZLqf|Y1ru45rM zmVdiC2{DdJMYy{P&C#kVU3!Ea^8&IHyuN9O~XbT*Qm^)aD z>$1k`E1Vs9Vv%uG2I4roMhj>}Y8~q%W0FNk@RmT#6R_UGbuDJ-T-w(nXtlrmqy z48TfNuwoCZa6=3mXuAH~bBB09Y%5ly=IC2sK950%z;z?%>BRLBL*TkYikUJ%Z6F^k z&aWz584mR45UEOzb7sGDWTKd04)?-{qh7MTW%~PkXSkrjI-XNhI3365qtB_f|#+3k<{Edk23%wLa@X2w3oFxt3T&~S8<=FUh8(J2x(}u~87#M&Doi`h_&}{oz;~rr(Hio<8<};hU~IxN z2gA0&8%j4YAfke;s4Xeq-9+QT=!KP6=2=Fw>kVcb_27v?=CM!E5@KWJ>ZPl0 zYo2slpWW~QV{Vk*^;(i9K2wHJDxB>FJyW&%TzqZC)B=`uO&+Xo8(9)(L1zMK{<{ z7-=54hWbYCMAO5`*9_8QaMOst#B<25p_v*sjuz9e&-uD;{7rwUQENWo46e2TdgsJk z`IwZz`MfcUUV{IQ7UMy*!-K2Q-+A6g@+s!J*xmyvbi(S7XPo2E_-o|GnHKoU_iNh# zVL+b0%-RR#8K&QA*d7fNO$}mM;8h8vbVhHGFUd66nHmI4LHxFX`6>x(nJX(P%W3q> ztywXg*%TzN8Rm{0EBv6vo+R9p7h=k2Ob1(h4={ z&IA%>m7OWbgX|P+`Ft)r8O?zE925HvZPlMzK~%@^By~@$4bQ(l%>2k_%-KBXvqK-6 z_l-!YzLmP!tlBA98e@KANJkkQ{4cGhh@RMeuMbI#8riKR4)O-Ou}E0*b)?{H7v6!i z^vb3T7G6@ZYFN^s>S$l0jlPCZGMrGYI4?XLDW$*!r0gQ0woY;q{qotg*z&jJjn=Az zY8k&TZytSpx!Z%UFZX)cZ?{qKu*jnCM{cBz<~HU>8O$Rp)56Hd#hlXZ8s+Tn_xQXq zP&D+Q-Peod7|wTMHdh2SY8RrBpFbnnF7M85k2b|FZ|nD8@*!OJAL|a7*MKqN>-SUJm&`Lm{nq3QgfTTE_ZLyDdf*^C zv&9NG^3ve>&{Yuf&7kQD$78dqB(ECQijIuHmG{gZ1A79 zS43`HPg%+CHioK+PPpX#GxNl}8kRfK@^{&)n~#{SoqapA=WID!ty4YV*^1rUdn5bF zOUF7)+_d^AuNo2ShtnI(@se@!pPy?8Poj>x5@`*{xVL%h20rMj!KmTUVPt{hy56_< z5+;hZR2VZqEKj`CZpb5p&w){l^ErZ`a5P%@xszsxbK0Y0uamY5zluKdAD}tD@*f}+ zXOr?h=fQw*utJ-_jHai4P+K_nGGP_p!B7~vrti&Mc-TOv(LH;_1GN-{YQ);uG+ULQ zhfjx*&HJaYy=x!I`Kb&|&yt6i(OY&_vKO;*HC9cZcrGQG>vkgem>U}Lwo&b@*pc!! zcLoQf^f@s&&{&Ro7kJ+F)LwEplnaN0$9ctIz@=gpKm8*fhxOeb*nPLCL~KPdi#CRz zU)guV9}1gU4}YlM{RxsPlT(TkMdC>QiikKOxD94nS4^Svph0=x@R-POxkl(_N6db& z8H1~slbkDXIJ(!kOT-_~~D#obuKp5tV2B;~sZgCy;3w-w=Y zTWv)IPyH}XhU|m--$cuHubBkR?GvvV`gFNQ_!>DNIjPw4f^AywEiZ3``m_J*7b9VyR)}eJ!%`t(2<%B-T0D1HSJ?vR2HTi$Gmc!?|>_!?(l*AxSss;Vl z76%f=HxOYlfi?&yg#lxro33O~7#D^q&N_QAX?kw8RHr+!Im{ffKR*YSEhwr!l!lYs znpR+xf#8G{>qSO_a2OUC7gzu#c5l2jErW0^))-i-N!hT=Dy@GoS_`rO&erlXWC1e` zB@=`2u;xlL73K^MzJ}y4Nd_447QnbD-GBs_&})oLDLAuX-9!ze13ThJYx8{C8J%}u z#K!CGe!DAP^%fa9zp-NexGzmMhqJ`wO18k;vt)QTShJ(Iqqh*F1(NG+5qljPdW$!~ z4s6gN$}Me0ugFC+WG#7nGx{%xfe-T^NJiM)tv8e_0B@)2FR-%hug(KKV#MSLK&y+} zOsH|L5*#QZgIpd>6^%?o9iytYIu${ELppx23RQExDcDOgX7olX&bIs}R)Ts<7;`*Z zX3hm()rIX)<3kUo`EOw}NdX+pi5(C>gBo;t*Sa!>umo(cr<`d1mO1aOiUe z5i{k%b2Kw;uLww3hg^wCqC%l&sbj{FSrCRGGh zo2-$*v?`rJ)q&HO2osBg>u|7SrD1vJ1gb-?sV1GW%BjIArRwmJBTG42zSDCjsBMAw zhLObr3w4<;!!G(c@9U45Szr=$2BVFAMUEMdt@m#rvu9~~~m81?s zQhU3`z0l^k`n@%ef!(mXM@>H=Fi~ZhIwC;~6;_HM>0b!l9U&EMU=7wD)w8N`PZ>*B%T_w@i!kDfh&%hjHe_S+n^5q)lq2+#MHT?PZ zB~~olVa0fk=`DrV7&B8*b{(_;<6qFE^O}a|KIqAz#x;%uMykBVaoh*dQ+Tp@h@NV$ zBM=zxedEC+9mKwlQNt!|hus%xkB;5P{Nt-n12tJg4D?3rdI!~8B|QjpIO3>6B0-D0 zjfQHC9_uXzihFeIzUJE4eH8VaEYG{vdDJ**<{MTr4CM1+JxrFiX<3-oJS*@GCUi4f z&2?_+ zQH@^?u0x!%pxOI~wa8${Kec($hS4T_;!OE8Thqtiu&!V$&V3-hM%01SM8OVbs29<9 zdvga@F8S=&8v+$qvK`qN@=1z~)e6S7qYVDtGr!lAk;R1#?}@7rF{Pv8;$B@w7U3x0 z0=>bxe^{ZD+MM^i5L{vt&opB=h-lBEgO(aInk~*)4c3O&pm+taT|fo%qK2Momtc(4 z=#g>PO7t~>l}b2Gis<9nXTBH1J!<2#LLe`HYe|R@@ zY%fgyZ!2xWdeX1!^~n+gGb6y7yQ#4V&&=m~eX@ifF`dKwmRJMmFW-x8a{osTzZ!MT zx4cbm51ksPYddQ+TR0fWkyU19fL>(3q`8;gYJpiyn3+S@(C5%*^b3ChpTv&1mbHYL z7bL5RQ^yLVn?$=ub4D&d_dq}Q0IUuWSpD99i?z5ad#@=E`1@B}G`Rw1+ z8>vTiR@=1fL!xUb&t6K&5ogi|>&A`#`Rr}dwQZ4^yT0@{^SAT{gvZjGCexfDTG_~O zwe}~_J?he*h}Q+(%igQmM{N%Gs&Q{sl`Y65OjhArEPGgei#0&1V*X2g9p5owr5p-)BF7$-?yzfwnh~faz}q0$}X9F(58UlX5hqA#w6Q9 zN~T%ubJZcW)Jzs$r}WPE{UUnPDYh|e9!&0MUHv8N6s($R9nB1X4e8Ri4_yyE&EC1X*<65mq5jVxLT9Hzw z|Grug{Ca3o!vfS8S)vMrg#XgW)j)oW$vm}k!|o$a8HFmEc;lycxRXYP#6k=6NAz#N)i6wSk#=k+{T(yWU76Jx6rrU3#g;1qM^YaviE;@Hx~DlFcR6Qm&{A zCr~S_X+das_34vSQ%QG6+wJ`1WIe&7zQiW;B@XwjMnJy|ALp98Q#1dtbE__TXS!9Yc{p~E&gsXQ5p(1+KSS+ z&!ae0D>NKsP(GX(AvX`))EbADh*5%p-oMil7j*o6jwrsXMz$DOE7>?(r!5jxWX{%6 z5g9dqhZukO!oXT7aQJ8W>&)(BR>o$dT5U&VPRj77(d+}|uNKBuVz$Col2>@tX{Xq| zVI6sRBoBNfvtpnMDc^fhz#cBi8n0l#Bp-?@U^>8vB&k|+AUg%pQnb*jaJlKKu(*{4 z;e(h~IHC(>c&LEPDEEvd_$?gPZsy8U6?3jey75)atdw(|z|1hgb_hyjS z_dlA|F=J1;Dv0=ijS@@#lYfF@JG@^`yujnHg)_h%IRm~XX=&YY9a)k-pw$&6RQ{H% z#ddxpqju)fVr!ezLhw%esZD3aBJ8d0TH#0lv z-M+f1lK?t`N&Rp5%4?kjj{DMBCH+`SFxLcQi}6`lU&a*KyR9jwo?+yT!%>Cfzjb7k zghtug6T7VkaiZT_=rnEw;maIFjFf7x(9Wy8f?@yv*e)vG2WE@-_Un-Ekr;fH zfHTt&6Rcv6zcVwiN$$!447PTdyuPq)K?CQj%3s-jl`f-iu$MhpzHDdcjRQD>u@qup zUt*olh4$*;xea&|8zj5v$Kyc)sOtb%!csgN^W?KXi8 z$#3(z->?X~ITxXTU^j;Aesr%Ui*PEo^l^30(8?_=S{)qAaP~)CE3=HW?62IyqPa0< zsbMZbVbospW0mBTUF*so@68$Mj1sf*w#gq2jWSK}=wKnl!2yi&H#BA^u6FdI!fFVi zkJ{w2&#M*$56?Vk$nl187;Bd^GjOq$0uIbWJk~=uV98k3_^P7Hh#lk=a?UZct!gJ` zU@r+NSk4h4y8cg?HpDHOYGvB+(qEW1Jb8h4rVTI5mTBUU-}#nlLw=KKgBki_-MDa1 z8Aa$x06ACu$d}#NhaJ@mp7mdxtLrCg2O`uV&Xa0#334HAOsSxR9zM&{_j3LIA8~9D zgKk-S_Zmrf_j^abXMEBFONZRDc;)>wFdG)>p?B06i{&$_*-Yi%6B- z4OT;lzE#)Ykrj@I4ku5)@~fG7;yT%Q)?lPeYpOcL(&S)MX|RHpI+7_)#HSM+Npc`I z9ViMQ9JnsdM1(d*5^Gcvn_R!C11HR!z4Iz_MUthlUn6ej`6-o@Yyh04JYuRQnVETjsN+umPRBc1-S5zJ zGLnA%|0M?v_Z{;Yr)5SpR*cMZcF>B6wEhM=n3=q&l-mrmfBaUk|7_dWa7Q@Yp@+0S zNd^q|p6+9>-W!>tPQRL2a~wgke~^A806}Q)-Z0Qe2FLlp{mEI~>qcI~p4->mWG?UK zAuk4l_Xqht>JiuH`=eXWlySfNzrzp29Q37ZW2OJj5;RAb5sv(ZQ73lg2f~U4D6jPV z%=M@bmDYx)XKppU!Dr%4qJK-2fwCUZH4-<(Lrn&%8OF89xgy&7#_;gQjTaZs9N4#e z?odSH^@smkkUAkyG}OID$b^u%6$5XB_M9Fq;qTzTqH={X+CRP!L#xp{Z`naI`;iH$ zHy^7qo8C7f;o@qhZfB0Wj zBC`brv+JsZ0nr%V%f!MIOx$w^IDcT&KofgKw8@#H9j~d$nL}?B#F#^JMiW0ckGP*X zhQXn)Q!hFNV}~WXHL-1xYc~WnWET4Epwn%wvJl)_Wg(bRM^OJ@eWOKXw>1~C+SeS9 zMW=ta{NG>>jq2kJhY4XOu2DN~?aiew;@ml>RYLgm8w}@XJ72usKbwVkvw!%zo6Ihh z8SAf`;A{BXyEg1q2Lr7*#Lm5}!&Y^hST3$XIQ2a83#-Zf6?B+8I;Q6VIdAVj593$2+qYCpv{KhPWStULsWD}+O!2-FSVx&q7bj1<7RYa}2 za?GGd%5361@m<;=qpak8c#b7=+!bAk6px_1TwO}tR&i1smGJnDk&KQrbK>{N2?kc@A2Qv z)*LW*cH$hhYomwr8ja+Xao9G>G7u>>YH?aejAHMKb3kz>!7>W3dX3MiJicKaUy#jl zRt;qq8!_rVkLXYq>^n%^&sghL@ss-znz``O-dY+|<0FmLKH?vIl}9aii7Tw&u3)r- zKu$Hk^J?n`vT^KPzBL<1-s`>UNMi9*!ou2@NY?S+W#iQIzW?z5@EvW$O7F5INot|ow6E__ zJA0qKerpDwJ2MWsS*@2@Vx~@l#dRcSEG^ZaN*+1e@RxkjNEksu+DI;D(MAU6=iEc6 zha76R-mM)$PjQn6x96u;-L;9^;HMRLgEXh__xvo_<)HP+drj<44;xw+sx+&fW!8SN zj6Wlu$LT89y3U_!8AIwJ>#af^D3mciplPA3n`huW(M37pxPlo>OvqbIOylFewBQys z-m@`A*T(sh#6}MzqrA($n%rEEnAxQovJ7O|T!jxv{Rs;z>Q;k>0m-(eYFz6+>4N4X z=5Ns(^JJqB_8DilvJeh0gXZ%Q-U;W85r}7PnD45O)y?+t#~DZv*KSD8s{52WXzwHk+yl(Hn$r@HrTT{Qg%?fYW!VPs3J_Q^7`-?B@7%L4e>Y>gEm z*LlO79bOTy$H~2tA5VGsE~%Y$iDa+b>=m`xE9^;SDfGll!d?ZKgOZNSB-*8|rrqn> z5U{q!Gg^6i27cQ~TUC>V!_zqFMV5IQFL)ltKap#d2z&@<1X6i&nqbu%m{`11H^&*V zmQZ94S*uB_6~Zsi4P(Dv7+`hBEZki~zKQaT_(~v;w<22u>_-=vThxunjbgMG7L}Ta zDT+II$v&jVkz*bfDnmoR5A;U(W#!#~JUe>i@&-8bLcMS)*q-USx>QUEcP&>)=E4n7P%@gj>e1_RErla!=I_Btp$F~9J z8D~J@c>4Jk&=mKpVPoTvPVbhOlvEEyvK5LW#0=^1M!m#;57pqLtTa-Y-eFF^q9cHVk64`>o zZn4FVu^_2)CsqsHNJ2>6V=VMJ$4rveXu>)FVAO_3QE_yCcy%#CttcC6|5oZqx)n;B z?F0aGJHiHyBr!YNoOSozV1dcQcX|14dOs|CDR*xr{la&S;bSGuy$+q(Dj?~t{t+Yn zk;4Z^m@-0+Iv8>9&^|`HP--dpyg|%vK6$hw9V!g*upucPsHUzpc1 zn^yXmQspD^)V`3eT%$`FyzInngJU^OibfPB(`$s4dIL#yR%aEF}as3cR6H!NL z^5l)xkEjO=I{@2Jql<_kD1)gF^JE=AeXszb7E00Bxi=yff=TczN6bVLPJP-3X4VTZ zp}e=WX_nG?mbQ73BPW1o%n)M|^cq(x^XA%-x51x`n4`rN7LQ}5I1@M?#w@%TGpl*c zu*b_Xeg{3UT+M>{*T|Eea9l|{B$pqxkvtB}TFUizP@76|GHH$;V%CGb^l+|2TiPQF z6lwmqEKrPt&7Z9e?r936U3%Jsg9*wnYrygvaLg++XSshc%b)g_5MvMhb*et}R}}HX z{yHUo)L%F757^)OzQ1fmV6KF>MHc&)SozF`rud+p@xg1H@WHy5=tx~XQ(#K_-A4QW zhXMZcSmft*;y-?xd*>r~_B&X)F=$BXlj8`ATWa|d3o2&4!Sx^}+X3gn&73%9=P*l# zoI89ImT%JXcUk^!``_&QUOuVACv*7Z4xhr|)Ap`~=OGSe&LvvU?bXD!m6*McPz0JX zWz_Dq3$x}AD6>Piz*wh)5ecX-3{T_Gx>@5PS%Wq?TfDHz*xn5fdGVa7wpM0ZYBoBW zj}VBD6#h#i$6Sx76VJNhYaA^2sq1jvTx(|k_UEN^c%C^vZ>up|N{4Sg9;&rUV?LFpjkGj3b9quu=_k_beZrnpxctzui z*&>^yF@bf$h+VVI*fwH_3uf%tKrhogg!8zLDCvk*vd1EAkxBkshIKX3P@kS{->rM{ z2XDOk%p3osXNpgr`D%3jWu25CU=m-)2gs86Al5L@iRN{zfj!j)MCprI!z(6rg{3p; z8A?4ogLq+8-u2kWn820Aki7jfH-}l;HdG<}jVLTwpYb+Yn`X3DafK&ng|GB)M_zNp z^61@Da`b~75iZ1h%UR%rZPL}{>s^9b;W)Pq`Mz=>?L?N`u}aw%Guh%6q?HVhKI5iH zPR}UC#ykDw#aE)S-B223(ci=?(v|HQB_jQ*ibgD3zTEu!d{r+sWQch+nBmtqs~4NBOLOw> zuaPKZ@^#Ewd+Xh|fAH?x&C}ilvCdX^>)p3s^zPf~S>K=ki5LIwbdwGxEWV}Db z?fi-#`isr`5k~av=0Ps|7%Sn4SD*i$m32nn{h{wIaK?!~^gTWIU5%Qzh-Y}~F)q_% z4EpFq{H~D+x%f-#+WzXFJfuqG_TV9{JWii`Na0!XCmvFarfu_>Kk<;l$q8}>x00{{01rXV#XA4*5UwNpmIo|&+E06y_W;{fcw=xVFfs;>!E-6DKewj>xvVZ0YQp}Qbjn3^tP$kjy{lyvWfr@TG1h_s4( zi$}f#o!5jOQp_+DoO-~levZ(@ciBVy1WPiZ$lQ><)5EtijjAUE?b!pp;Xbq)_iqS| zol6nknH0a1H5%Wil!Ie08!$m(4|b2_vRXMTH!hM)29EYvwE^`&$coG#Fllk6^cwat7&60V!nS}IB2=siGd?n{s8P8xjNGm{PI5?V)Oy`xO*c0@BbFm z*9O`XriEa~%nyc*z&ZnBM%*ua#3!7wa(+4gI(B*Yk_sPuB&lezsZRfBPV*? zK~XQhdd`ZTcc5x^K%ab#6$r~2KL+vPINJ=sH6Kn!E_Y)is?NYNI z-cZ9larP|G!Nwa}T4M7C>!Bm-jvf^Ok#K_Eq6;%b!C#SllX!HIh`AxKLwBnT+3(6F*M0RH0`qzV^_2d(P*eIIV>QOyeK8S}y3%?d{S@Lp|3 zow2Oi`(Ldxh1!}mqKwMU^t0j5{e}&rYR>W@+X0z5kc9817Pmb~G&8t6Hb3+hH;9vQ z+l`EL{Cnatf?!ti?S#xtPo|>8at0<7yj3cxIW?mQHp`2$9+{$FN{98<0^uiCI=d(xxZiIZmi8x2o<&O zxQI0h5T%~azZ@A9X^S&q#vj(oHpndzvXQ0#dj1?Ep2~(Q7@s+>Z=D|+g}QUD9M7xl z2JW47kU7(oO*iIf%hV855$>|r;Y3INa$K1_BM!4!b);EQY18YGO&2*aU=f1_kq%=- zHt+))cjX2mtUYM{a5#X7YdH^%cd}x{khl$G1=)zafueu7ET9_l#(M@Q-XW#@s^7=Y0kzrVD4V=52p{I)mkY2Cv?{#4|W} zDv99+$F1r$V)kNI>}5XukOAzeki>AGwiP0^aHVe=|C4m+i-dlL?0d#KQpy3V#zqQ%^$a%;g`GQ=5ZlS zCb)P0lkJxyryj9}r)QcCwTk^~SO@u0_w7=Abn=TW=0uED!Cm>=cogWrsAHn1eAE}x zAPp4yXR+#9EVgHCVsEKJ|KN@e>#)Fa1z&j?JABr@1=UlluKJt?uii3_QGLBiyk_pZ z-M_bE^S9^_NS0iD#JUN8kB**J81bqEG0)K_>u7ihT2Oo4?DM^8IiK&dCh$2l|IIIz z+^?3xhOr&eumWtZkTxB;Pb&VkBRTe z#$1a}zaIA|?vn?EgFGM{K-=W_tK6A&H0C&ss_t5(GOz@v9>f0Kd@U%0xz~K2ZXD^A z88t!5_QPnT!)VZZYUQlV5nUcE5P_dtnUfX$=P`^Ho2A8)InU`yk^m}iS`6B(My-~g zZkR)2Yi$pQ*7~)z(QjiG))v^bx4^hpEno~R`k$jEO_3`mRMrT$R!AKWt*{4nA=WG{ zwuNkF%);rcb)rVNb0LBDY38A98Q+^VXndF)l#HHSE%tGTy!BY1CJutj*7B!n zXom_pYZX)EwYZ-7%US8M`bqKT*W%~!el0F_VD&YAp<%-X3=ZrkHk@}bgh{#Yw1d4- zYdbKDoIQ6+J+rRfa(xlv6eJJsu2}o1JMVQ96<6#x>N0sy8DdVce5uY8c|@}1TUFR(v)T-DX%%9!xbHMat*GE_pxe5v*o zF^RLcTJlLB%Ba?M$o zI}QZi^vTn=xc?e^7`UW<7oFUnY5V;X)eAr3)3aW*?<|d&|9^|7a@&a`_FuJK{<7^n zb9joW6;lPD(*aX8Dja+|TU06a4etFtFDRXoYCk10;*UyB&Eiir1f%9EHe@~9K70Zz zo)L71QLpQ_??H`A5-*sxZDXKk>+p&^3QI2!9Pc08`{{kK3iDubhM8t8J5>YT7|a9b z10$#6#wE+Pt?kn*PVpnS648R@DjkxtNG)?XM>&2mVj)lC;K=FAd05+DZX=#d zGT*lp-=tr>DT;mH;;s%{Q+VW3^OLbhgz485FGa5_vG<@ed8bz z+w$gt$fwrwDYWztM=cgLJ#;iDv&EYGm$n$>5vMmf(5c;?+HGldV^z~-w@@$UYEPmZ zS3AY|1v4N8$}&G{BmAvZ*If~3_Kq6609g_+LZpxTlk1SMB=~~9q)A`WOADb_kvJ+H z^)L_;1aod^uVT!=-S88@oxY&&nosg=AGjr#OrB?w_u`>)xm;$GsxffB5A8?(b!=f7 zJJ=I;l^w*@uTw!kdRZg}T&sTPR>3oLV`MtDD+tcyGE42~JqM1h*KMWPMGgvDWxT#o zgZIaEq1elgtqy}(Ol>t~pkKj0O3I9xy(}rIw_)^_nC#)(5Heb|HNZ<$YUH? z%)7)(+qJY^E8DfQU2Egocf5FQKKF_?MAExB7(I9_vMCciHm^SY(oBw;n_q5Y&paR8 zL;I$s3wu9vf5h?2-5S`UNDo!;_(=oPKdWbabZ_{G#;!;-Lr4W9X0)M|;uh2EP@>(mL*HO()f^D|6)>iFJeBK!#K& zxtb)-x#Zf;mDnHLleb-6JlJ>&fi`$g!hSfyWfwGvfxzTTEb}IIn5OZNcz@NS^CDQNzfBnYekQn zuF*}DBj$VBDVvFN9`we@$_k`tKW6DPNjQic}nfrAmFHszxOGLuc%4)IDjPGklV`j)@?X)frYp3PY z_|3`!ii+e=o(fkv!xMUp9A_2JSzOvqZ{zE9YMQYo{9#Ru(c!l9;S|8$+Mllp`Vm_v+^nR#czevS4SI=Ny{7F6CvF3N z&h`8|>kiv9yPix4>oYgTHaI7RnO4YpN7~+6w$_*J+T`>4WTeC3qdED)i1o|BAsly4 zTvuvZnyhEXTb94+bDo%+-QUb7iNO`(dGEgQCci=?xd%kjL|+pGLY9e0;#nTKW7|9% zX6&K;KU*h8y+T9WL3j7hy5mOFIL{jRn>F>mv2a}KK(SH*p`0spv7tDe9Zr<@+$Ja^;YXzWV^&jfL9va}A5xAf>t`+WBR_PSS87pCV6)i#C zPN7#A!BT_E9%+zt&Pa3wOGi`%-R@w1CfmG5$e;(irDv>r?yePVn5%^mne^9@&wzcR zr<~tYr2mw=c2nti86VDCV|{b{GQSv2qllUAeCM1UVn5h;3}98|7Me-0fP+fKRn!dx{j;`L$Z^!`Wn9?^ab+=8Rbx684KsW z6#su`FQX2;+R1;>IbUl+)m=5AsY@eP?LNzqISr1iWb};+cGS^E62id~yVQ?7FyS%A zW8?ItqIB#_qDW7=i@#8Qj-;5Tdg4G^v|Nsd4SzeL^UpD#5to`hO|#fNi4zUZC%i@j%bR$0$kMc1>+JyaM+i~#CkW#{zfnw-dIB`Cw^ni0b_G9%)`?PwKO z?{(aYj0|-!Cq9lW6}VR1o-?#EPt%(`dtY&^wOb>_k@95LSOx4uGp)-&UetK96&7q0 zjSVJQf>0UpByRDj_+e)r8;%49t$asQ-j_cx=BHWl8}#ZtyzNvacg0lb z#grbohHx;6*N!Wtnr7*tc zImVH5!N^u3bSzula5{SArLm>@>XC}UV@=0^__B(z^_V2GiNS9Z=2@6o8+Om@#P_81 zRHN8G(1zKB2I-!q@&Ba>#y zMRR7xViMW1^HUkM?N^TFSv}0ESJjNC_HWS}Y24sL0W06+zVuJO$k&Yn4LBnL%-0OR z)@E`y6JErQDBbR*81uy*I9NaWiZ5NQCIctoL(N$9+znqXJqsSoz7xwRl|YzHlxc<| zqIiBVLqGe`j2n4^axzpXs%SZpEymU@3xITp&>yQVU=3!@tBz(J!$2r~X;O#9-+sM1 z%tWUy7Wmyh31zG09kw>Cvq3ukWly~bgc5yGi>2AuppH+iRENWkY$Pb7viu89h@u#Z` ztk-RICGkQ2%FUUSzyus#-?7%Fl!{zeXa;ZlKz+oBa(ZFc_*L z^a6Hg6(wTj0Ax6lB{d5+uJb;)Br+UpLc{$L1AwZR(0cUs-u~XbhF4!BS8Vy_n<>X{ zzB_Vu7H9QoLh^X@oO=*V5^Sah_tXGtgmSHT6zZ~q9tH}tGRb1u9W1kkG(jSHjnMEe zD)RB9QK9&QG5se#jgQ9kYj1u(rhoODd}ChF3S8&qzwy0E3A%=Pq z{tWyzl2qZ`bWlSGO-6q&^*|WCV0t2i1N=9PDpToLA3PqOz2*_dQzdapEp@aiF%_1O z$nq(ZYhs#U2EdX>>;zUMa6UoUSX+jI_N}r9Pktt6x>_S;6I8lyg=KBYhEnG| zg=7AWI_J0z?B9r7*uf6S`ZujPyRA*~V8Q8RSIkCOFpv1H{>>U~ht&by2EmLpfd+vT z-s2jD=XLLYvqpc^lDf8p*C@22{H7g$Y{_vR)Ds4?Cwu`@*>wXwv><5l2rh3AAQ6c|H&yM|KU6?Uz$hpg{ zH0I~6l=jj}(Ep*OSb7`l7DTTVQpGxKv$r%e-K&4TA_bb_uEPFkD8uos4xwM|H!Jea zb^vYIOxwX4(>~$Qd54I<@ltltSIYw4G;*#!K>;Dt^BJ@C8nFT9t^Mm--Oo$73r+!? z1%#!*U;5{3byWEBi!^q~kc9#~Cin+>R-(-3gX1^ambMJ5!*Q53>3_5v)L|U3-*5uJ z6L8fdo-5#qjsRqzaDTY|ucYF;mXMT;xHG{@huz`he{)i}1p81adLyg|``Ji5w*(P8 z9a9Ax=B0|-pfna(sv!j78tqX zo6Dttg(ao8q+r~z*UlrIp27k~wRF=#kiaP}bB87yL;`9l6o`waG4~Y|H&so>WFXxU zC!xV=YG6Vop%a{U8b-7@Z8TA|L4PzOsM+39$ayO**Y%5mQMw=ike@3OGe0qT^|mp= zGVh;b8wg#}Yy&a+3lTOA#wwszJZv|#l10W*b9%DI(ltRA?PLlg{(qerv3%zL*Lh<% zf2sw`_eeq7=UT^Adbjf-ynVt_nU>jU&vj`>TN1U=oZATRPm%tuCLcD{N`(IHHCnM! z=1q;(=UOCtodbG{6(?I#9&xO&srtmRB7l3x2GKJz9k?Qy@g|7^8gmt}WkpX-o$gI_ zdO(l`fT~J!Ep*VN4f0d(zreqHJhB|zJu$1{FBwnc>;%nq1IOL;jzs)#k6H8Eh=YYo zQPCx%bdI;p5@r7}-ecrs>@7}Ir&R{#2%LO&giw3EI*piI97-I`APPiJrVni*0Vjopyk5! z%xtU%3#v|j*kkh0aE;8%swM7uIFjt4w;W(Cc$lamw~Fn;X0;x1oF~Q<|kL7p@=_w3Kiq)Z~$2va8L7& zIitv6prR%$v((518GB3@tj)}K+3Q_|&Xc|usd7>+<_=0utr~tOO!XbU14Tc%Y+}bk zcd?3QOF*(oSX@Ph*0rg2YdfDT0d1DB;ZWu3k%Ns>c8{Du26Mmi6bbMAGO|0rz}#1( zMi;NB!Ay&BbN=4K4)uf(zTpf+Dqrk_;wYrwi0gmP0fs?k#R z6?&BDm$o;Oz|fCUS&!IO3|ypN?aS6B z=)I5*Qv80?=@CVm@}@;?w1v2 z)Hn>Vri)WOb^U$B(AV~hjdtr*WdAwR9!>p+M>Y($NHl(2QD0&*+_Uq@XP{<8LRg9m zO@0T?Z&myH!Ef1q6{d@yWza?9-Q|cGqT+}hgz~p(Z|14Tj66$fSz_ceNfCbQtcSLr zEc90r>pf!L<0eBhW$(IqA3kv08%JeAUfGj5XJ6|Rzs@Uu{ATlA&mG>jsI%ICfB)_2 zSs`C@7O{p4*N-4g$X*ye1~1LfU+6EXZ)$#sTb^r>AXqzSmxN=YlZIio(TswtEL?LLk}KyO>hx< z8?N{A4oq=5iFD+wG{o~M1?o_1-#>{+BYbV`5vv#GtApl!wQfiUtCSZYeT!qXLT%H= z*)5itd$gSyC)swkein`(gdq5hV+@|C!pe=dGx}H=1}o?K9CzaQ84_Qga`8X4BFqab z0*sb}6+zdWTO-C{lReo?{+-Pf`))I(={1-c2&~U(UQ15wo(Qz^Lp}SFw%Lr# zr6>Ks%)phxewi`qo1e$robO}JFn>lMi!JUPU~caGy{&@>i^eIaQ!6hXFCMFzKZ6#% z6zoOWTAPp$Y*}^WN#Qr|ETwPTqS|1gwocVh@}JHrLjRwb<`L%vnqT~;)a7iyW$z-9 z3a;4xtY_&P7X0SDNq;;&@A^#UU5)-bG8+#|;X3Z~ud!C|>+BESU&MsszZ2ouEgDiJGeqW^%BQohc>@#ptyO!&1fcX!g`EPtZwErl%tZ6cziL zS)1dz(DS1FDxL9)Ham~iK{gM*R^;Ut#Zc6A{ti9G8*0+8o)$dzCrk34-w6M+n@>WX zFB(1#dBuh+*3T z|8(yO3-C6+dXBAL#;al_Bd6hDX~`qaE%x`Z_f@H<-jj}3eH%J*)vNwhdiljjq!Ttu zY6aRD` z#YUd6k4LfCm!sI!^eEL@mQk#;=FX2sF}@l_iq>~OP!n?uVO`OE=P|q;#irvJ#ir%c zD6%JrN3n{hQN$cVkFZS}OU_^4yA6HGug0CLt>IrWEaTqHZ?FO3gxyl`D+MYk#=;57 z1N+(W+NJ%?NT0|EmUsJ@MvL0k@{IKDzC&3>+{U|w@-W^Vk)B{Q>Kr_#jeUE(K?=Vd z?;fY0vLpB2KHfe3V!X?z<82(Se^+0P`^|WFiUaqg@5VcqZM+AriX#em(xJNp|DF4K z?vek!mjhODJ24sOyq~S(e5CAHI!6U@EsXP0?{fd4+4AF&>VxF z`Q;n34@DocVJm2?RhY|ZTc3~(mTYHaZx6$+LMt>OM5rVqnq$cM$^Z)Jk*Ew5U z5~abO4deGOnvwO|fov#euKkVdQk@9YCTjjG|krjeoV zulOR8(#z=v_agdHfIbjOVw>06z-3L7)P|;&^C%1-ujL-4#^cF%E70EV?;iKQ@WtZq zQTscNnBzI4e6n+xBeTcB zd%V>y+!+lwFZK3axbPz~FWkHuF8qb_)6QtjdUu>Yj*WLXax9b?vjt<7u?Q0HGW?tT zPXmz2r0&u7!WkaXf8={(Qf$j7KK zrwY-$q~~}4!}+v>xfp5bgStwRYs8J>Q`oP8=84QyqUYKtuU3(hBb%*fiZEQ|Vq`P{ zos0w#H;Q%3fEDwkoHUc*Srs4`q z#I7NA$vB!F>+WdECC^O3)CVU+)b(N1q$g1HiA%)_+BmzjGpBkMVBdpMlaImQPK*ddGEM;fq0 z*7Q3K7{5Enf7`;JGYam`^B?5KooDIV8>&TaFTEiT@ZeP(V;6qma}nt&xA14^_b;IF z-)0s4Wn90OZ#g_rza5iN2UN2h5Awdo-HfNbs&ThQOV2g#23C8rkAF}Pvvfv}KSM+_3+D;T zJ-My7x?Z1;0wLR9$Nwc&(z=a!Yx4h8d5(C)wf?J!w|yP)mZ|Phouvu@qVuol>7@?9 zhC078|Njk%PWuuRVyn-7GK?F&@RRL1y|b2-W-Xm6R9vyca<5$hD_*VG;hm**aO|kJ zbGlPp};lLj*gvW8@=Tu^r56@ebQ@tm(AX zZ~7G5;a;rtWZY$?r;SDTXDdCvTj`;`z;-C|qwsh|-zI7TR!F|b=zyVYj;Ic}a>)N! zQ5{3h{Q%W5cGeA&LMAVk_W5&$#SzaT!6ZH6Ij~v^X?t^}ZFmlfzOStTuI6c{lZ==KQ^?AB9Y? zuj*m(Gyc`+oGX?tVGW4go{N*i@q&V9^j&pN};-JWAqPsnnv`ULMSn_SsF z)cCB*EYI|pnVE4zh90sRWW`(qnvJT>DVyPGK5KB>99A11=CH~#ct`)}*JN%{Gtj9t z2Cv({UT+Ci2rLm;UcY zxwoH;au3^jejH0=mcGxi_Q>mMywXWPKYTOElx{><@c+SR&=z6}z4eq+fDRzDr|Ml* zOcCoDPSlTbtgE1+m0!q3NBwDLq{GP}xq1;xTeI`$$@L0KSo}mdu)HBSYqT@t8@AKP z_&)!3a*wXp$lCixe=M`67LOtQth)9xH6^`m4TOU3#>CiU$KZVO*+%U&EVKq&yr!1P z5gKGwqt?Ah%upmu9b7C?wH8vmuT`>Vwm;;ytGnEG8ZlT~9XgUc;kZKN96tfqwJ#3y zQ|P+mjB*XizE2%Simp;7Ec!8QC_VVZSMhChwK!R;V1yVbn0z(q-i!~LuVS_tUM(>G zI)_YGK{So4-I*qO;j1C>RS-rFIRW@8<|xB8P|{%ySI)=BI}iEzSY4NL+9Mpeh!SRr zbXSX;nbWoATs#6LgQhNYG6AEr?@K8B>W6 z`m{Zx>!)X^HtHf()g-F2#E3F}r!!e}fiv9wwP&+RpGa=hx}F%(A)DwaVXJ8vSORbC zE@Ko29y7{kj!&)bm=Fst0r7jDOXB$S_Z*+_$~u|upao{<_{36Yqyay*Ro}HWA+klQ z{-?Hvy{*Ad7KIn>R=q9lR;6=}eW$3kNPSea#P5<=*%Mf68-DOdpN*jS`0&{bJ8-ZK zU^JE_*yPdC<~5H_q})rdKdo8}y0&2+RCt3OIlp#R&(W6OHl!Ew^kCg1IBPw|5L+}p z!l~5Z$3ACWg02Z&ys+KjSk@|5IsrkNz)5UlhSL$*LW!}KciLzEN6eGaMO7nQ`F@@Z zMvsh#lLl1F??0W^(#9gc^EV+lf1u4kdb7nLVoEEDT$C;*$150QBl?SVf5AH1s$E)% z+=+0yHe_C$J?fxCtB~3^a}e;ozCQKkt|#2`Ff6W_X@|-ZoaOzSZDWjt(-HB>G1P2)Mc z@Lg&>3urNK1I2C6qWheA{4oU*6z<_6ZdTTrtgIWqJDmg}3-yYITZUD^u?(|2r?)IF6aL}Bjacd^L0D@O_W8XW+u>P5Bh&@H9WV9+3jO#>vgSi zsgXY0bMB>&U}oIXoqsQdYm`f$&W|v$fJtWK=vC68=QXl+)Z-p&rnaS`LXA5Q)vt+Av1bGvn!TCt->Qi=C$($@eaF^C_C5$?)07R`_B2ta-~Kc z*MH}^N!RGlx8~c=?o|*ihK!7w-ZB)QpBcl9AxvCA`!EOkDzQBHVd;MI zyuHh5<=Mh@w~JSluS#a?yIQ6Din-+2!+pLg`4&=};fweRrlYUpF!uX?5+kx|+V5gS z=6zJj_vDQeFZ>lDPv(qcLsZ5$Qf__QGi!=EW!CJPp4lS?>~#)N3l}6f!fnF1MD*+N zeKR5;Yw^C?lQjt5=nQLOIV_lRTGmv2sb5hC@yp2GXiPd0tGQGo6ZHK98*hImvAlVH z_fOyVa)i}hMhMrMIwBa>_y2snU-%n$ihQctwOUaQUMkWpA`nE@u3l6SyjZ{LW~k!% zUsmIhzD#=;=a5_0B+TNKRAKjxU<_hp*=^yFHLcb?8rxnYYTNmMVU9<3ff~d2Frrp$ ze^sk}w3?hFuw-Yx#d)NAYJTFSr(Zva!dm$Z#mh6QTIn3+VAs5j)6DK? z;LP4p&7?`YM+^5zr#EPmyEc5ZDRDQKHq&xPu+!hS-ck0qwp)%6Z|poec3~1DO?IHGI`=auv46);nWr zH_IB1t)=8LR6dWmh3Z|E7V2!b)e7fD;})vuNVYWtO-Rpt+^;4Fe|aX+8pBryj>}~6 zkL%r+KE}q>2OCO!^xeA{o#wY8S{z@64O{cZ-gIl^>VV-@J-A&nWGx1q1$MLCf|+pw zn*)a16wjHVJQ)keBurxAcmTbbi;v!zCiFQz0i(7_eMvRW;VF}@+tZMVg zW6UbhU}?IB&8h^)w(0040)iSTo4mQLWDJ&^I<@c)b-eq*CLq`EwhD=2rF%GZfkm|P>H9HMto)huLFU- zb|CDs8N`_>8P0Z?)PjYJy@7=S^#B&BM@(=Fz>81?YZ0U-I28)zJtIK6lCuimXs5Mx z+P`M*%6C>h_#TT%108_XMyv;c*~1$$G^63rHw~x0X5d<|-SG#c6YJpYOTm<?2gq+jETNSz<=a2?cYD?`PXiLR`kWHD`P- z6}Ubg>AH6cH;!q*y2Z4)2&}@Q2?s%iFo6(HPLKX2tSGIywKHA0S9IkF(+x4aF}hOX zai@m1k^D%KhaH9f()EEj)r88n&PX}U$Qm_p*dRq3g@ZvfSP<>3#JVlC0^A-16FsQ< z(9Ea$lvdmYp_b5m)4SEfeqEkp$UwHs7#5&n&LYwOyFcIg9BywQC}I5vo1c0tRS zd*}UVs6P4Y-@VWhv;!P+)G8duu3r2k6y=T>OgK1152GAON4eWbe|Ud3hllzbe2dV+ zDY|#uk(H;W&!@$G-?ry{OFo?w|M$fIWe2~myRv(j#S#?0zKb0(+-n`aW_ipuC*CP^JRjNY#9tN| z3FP|44^@0AH+T10g9y3!tV>U)Z>Qhd>9;0P)~cXBME-8nFa@8KzUR|-%9LOmbLYRn z2V>)??B8K!^#_h|-{<;0U!ztU!rzf`i zha&5pJb%xEd6%4gmzpRN4Hecbv8((jRgV6f;-knb7~-tP0HgnXlvG-3=xTWb=U|@V zqk`qSwt0T%Jn$6Q9+kZO>*Qa1w^My>E%^(X;X`Z5^44E-h_6HPoy7Vk&ar29%h3&Sk7CHCIm-5r(1VErRsnM(v0@=Ui337@rP4V(of@k%z$mcjCD31EULz1Wfj;6yVO-S9=8Ps))SZ{CE&rufp6St@Zt(I+iaOPpO zK+~AK>7e1^EKEb)3WBj^<6y0^SYQW{(jv+r9G-1dAoG+W9Jr)3T;oAZFenKm<}H{> zjV5YDme_y6u#8N0KrQu*KjV=}(5RQnjhn;jq8Hm5t_nzn4_Dv6M=ZTqlTqI-5SP1W zO{Xo@)vMAcMZC3ZKE1hr@6A8p`*Tk@p#!yzZROve^*ufG-M;Mm)o#Q76nwW5O(Jfl z>aCao91fxXY92W@UGh*3cgzUR*HKMxsJOysAkYl@?1riCLl3Gc0Ar)^klhEy;2-d~ z6ysX{3C%NQ>y?T*KJ^-7mh_4R$~lJL@H`?`cUUdH7`}V(frzXu_6G8k)4;hirdyW{ zn01BD7VF`$4OljOv0;Ens9^R?D5f~9V?KHiCP`Sv{1HiCkFCfQ7B>2KtN zCpqiKr=SBOf_uGt z@+jg(2`Qd?KV6&aoKWQJ&-4-aoZaF5|BLmW2zZPFtqG-vb@9KE5`72mK2&kp z*UbR8-!f=EB_`{d1}3}pZX9rB5O#_i-p1N(Dx(Y#6QeEVm6XVl2C&=u)`SlulU_#_YhJ9OtLuJBDPh<2m?Wh@9xP`>x_ z(?}?Ig*nMZUXy;r65#ttDBh>9W1-j*P1fDw?NHtOhK5BoTuDQj%>jplw^m^0H1P6`0iZpy@1;KP-Iw1*-wX6SL z8wdztJ?VeF4diUiK)8qhE^CHHP42I(8Co>H+QkC-)`3*`aC4b!PXs}8@)$u>vEAwuEL_^i7&9JdJjtXK65tpnbLK1_KV z<#Z8>1b$=W%|FWkr#55TV{dnDM^j$HeZ}NDVs_Vqir(Wj=vFu?9$my2-^Dq%mHl3X zaLbwJFJe~rTD~n!#L(u`D_$>>HQg~0&6IzSXogR59^J&;bqlsG03pn8B=ZOic`%(fzPGPIub)ZP&4)XyH{~vEK#g>&> zBg0e9oI%8Cn*z+So_!mGsHk?a`Lo4l?)B++uIS_+WBf*&P4?)IU21YM-nDz^Ta&)k zy>H1%?K81IB`^Lzhc=`q>4QCRnKJFC@LZ8_Y2d+_TT_JusEI<2(lR4c$9iOl|B0sn+U#Y| z49~Wy5dMtbW^~)tdd^i$*BX^n4P+R{Xa)=Kp=zH}gU2E#;_T*%Ax|B2s14*B(-ngG zq=q~Zq?qAtGa-U73HvO93}WGaV4Bd>*3#H=>_?mjw$C4v>ke6V z+8t3^vPrNxw)Yb9##Pw_$3qJ`OthcM#JtOWniX3}o^ANekhD81%pzz;evFHuYNVvw z6Ap{NV}~H#?4+De>w11W8%|ZuzlKj(T^;^z_gc(%3;$O(l+WxY$p3*%wgY47ns<5O zzT7|c`v}kDy+@nB-hmHo{+ee!wE62Ovt`a%(>FRwjS+f>Uf%jcidtI2WA9%^QS1?i z@#uBVe(ldP?9W2f4U&n7Zbx{;!1{6=??*vz@kf*k&f@gF8nX3rJTARI{sV89as8ba z5Q~=IBXu|y%9x7W{!yaDnz_jOe=NF*>}J)gbLj6eiHz0%2qw|*&-3)fdF}}}16H5% zRsQx}>s^eud{_?datBJ$$md`M;2_0feGxb@Xdq_5(F6;DrNDs$#|9mRj-d-gWe4l* zyaVP>&@!9qjJm&820C!r{@L05SIi}60CPOiyII^2HfHn9nhpe;yD2V$6dP4Vpq=Qd zx7qrxL5l*C4Q^Bef|ZLU!E=$lG{-D%V~oxA(ww&mrP!i^9)bMs&4{Qk0kO2yGRTg7^bE68QI#m>f*m%;HG$~0F!a|$qUU4A07yV9%bvf7Z%---RTGoP4Of%e*| zPKNE0i>77;^Czq9$7}xz_mu9z=T0cVboD?1#w)-v@P3!wtdI&DF|HL-k2yeW4{Fn$ za2dJPiEHb4_U_2GLM?B5jA$H!l5DtIzQVV zyfIWao4ph0H;!rMG7x6QqyUdKN~wyG+fiAm*EUEEWO{do!zYJ%7exvi!t2CnB|=i& zddjJ$g8y4)n*`p8h zSEW|1OGS`mUFW**NvJfVp35_W_dIz#fm)#*JX1AeTyPaAy4!2EnWuDo3se~wzh%w) zA;}f2xQLv6X6X&O&XvZv?x*0QVqqq!MU1~>#(i~!o5VP$K=&XUfS%oY>@kDb8C@8# zcRAhLH=EM z?hW}@IM`b}TDs@42KeMujQeXx?lIU5>RUfc!`Cdz!q$+9KaNpxLWtQJ*Vt22~j}X}x z&ifXTUG95@$WAnECru;1tLQg-4dkR5o%pCLjZf2@n;AJl)uItet598BjML%S_q?wz zt90tktS|kHmpjr(r8^Bm2_jsonuhDW0VM(N*xF`6>W%{g*m7*ZJ%=?JO|2=pUbp%o zUalsd3Hr^BPzx^Rx303NHe05JAbzg|eN(#vI(=qoRJVzF3c3nLmGIRfXqFa6 zRflDaOFi*XL+a?zk$bIN1tqtQB3IQAOwJMqG8B=02`$Oax`li#>We(AI2Pd+=_J>0 z7>?vsSDvfRvX<$$?`1mw?*0At{#ggmA6OEbQ7>wTs2O|l_&$_Mm-eUkH%ZN3sh{!K zx9eO;r9qkz-0g|H-W->g3B`dU06&@q%syAr2fg-z+nzpkZk;21pW1&hYR-ArsnXwv z@e|rbe~f}!vW++!Y0Wq~-hHcmvX7W4=A47PQp=C1L{psql}gMnD!9;_jRupV_CQ^2kxmgas{Y;k6gK| zIO6r@-}t3T-=Tf3HB0C)x)xpem8WNB!=aRTt#|v-11e-cdoZ~JagFwLIuc*(F7&|>s4u432HWqS=u4gzOb$y5omN11K0lDTSUmQ# z9(OwF6MokZS(f;$R@UX-H+CwzGk;a*^xcj11~*emxtox0f4UbhHlndGD3 zrr&;kUVEO^5hoabk!vF7g5&t`KuAPJ&sZkVE-ZiYevXRkr(mBGXv5Lpc{<`wT=lPA zIutE`_h*Ia&%%}Xg+Hr&;Li$Q__M;*pQYKl#r~}Afd{`$U9<#d`pK;jul?d zb_IB(!xU)N|CMO^7%*dsR148+)@Y&09hP^nsT*O6yM}(m{&J7ik3c%y+#YHL7H#tZPr~Wqm;18RjJhB zMh=@v^0sdFYAn@hsVt&epVpC~Dn?xJ)kGdZ9j)%35x$`dT(vb@k&vUAva;7kKDj!t zxja#%o!@_zD)LzO)Xh(&?l#D6ehP7Z(rwnbVB~nJ88YwF{43errWH2%vscUQSGSwD zD($i4{%+-9-b}unmd&193g_+g=@CvIweRh_SV42I9uL1qjI|;Cmo2HEN{&A|%XB%N zW#miK^9(|(FID|BD3KHDB%f}&Ge!#Daa1w$a;BMcKc+?UWhJw)R5Am$d00VdO&eK1 z>36P-SK1Mo`1LB{+EHD@=*e!VH{v;(u{RTOY*|r#puk{I>eOG^-sq!fP{y;L74x(4 z>?WKUWHD>hD{8`goe^=T2Z1V)D(cOK@x>*Ch6AjA^qNfBa_uf>1H1#|USDdgFta9P z3`}%wfZiH(&m~10T1W|{4)Rwi@mHBlc#u?IM2Y8%?aR<#{A;7EuHi9rHls)Xs7Id; zuSBLb6D%u}?92t2_U>tiruU%M&p0_A@i6E~(p|{90`JXiXOVY*w)37M`v1Zsf3i94 z?|bftNVRUS1R>YiCde6$GY|N%2jUZgpk}|=|F=E-_1plDTWS|`WW%i5=%s37*7s3< zIoEo`^1bJ7Tm^d;&@0eh*!Vu`N!)6+)p^}IFhf^Ehhxly0K{)PP!fiUt5ljxp~I%p zvDb(RhdvwIT!BOEd+)r(y@w|o<#Auzr5*8xr=?;ro@y+gI?J+V_>k64t?xB>K-b`C z2X5`r9v|P?5P!A~7_|4pC++=7w%ig=zdz$<9p9TSOLu&s%kFP}&}EO6Ip&|N%5Qf2 z>*$4a#G&9Go|UmrF(3Q}?={u0cirro2ich4dVu*^!s`G58vV|nGx9mvgBS-G}wMfCxq2r->=5hkkx`G%1^fR;>nFA zxBW>wpHyhmb-%Z{k~MI#xc<#K!BKA)i2&uc7hJ-8$t7?npnd6Sr!gnQmff{w@?L+$ zBcO@Qc7sM}$M*G}#zc?LWiCcncy;cTm**bK=|mTiV-kpe$3F8LfniNF5a>w71si^% zpYnM#ts+_<(V1}rZnuFB3VNx7Ikm+g8%#iGSY+6REt;>eI-Imc($)EdmcC}H4y(rz z!Iw@akP@pKo;34$CQ>x<+&}i9r-Cz);`Od%b~nQQ5u}5T4e~IIlh0i&{gC1ZIb-cNs>9 z&KQoV7+MBT2C_Rtf0D$zX+^nMSUNa$;?k+4M;|&zj%M9YG)flD!zRphmGg!Mj%hTN+w%g@o$UY+iG2Rh5mI}wpc1*N@aP4%7-3)534Qt4m zP!`aR!4X|Fhq>r=4)F@bejOUK&tZ-!O0Og;&7)0F>Win^PIC`4@7H;@bXTs3mSdOM z#dIaH@vw2!1^5~B{Le1#%+vwKSETMh9 zBZ&Tu^fLg}2Hd3{cd2{Yr98XL5B>m0X|3otPob(PgD}t-HaFSvnR12_Iih3o0Y^v3aGCW4yVhzEKDhCdFs!9xyP!@VQoRXMbv@%nS?aFQF_rg)& zuv49-=Xt?X;qSZKfihQ8`;YlL8tt0!%YbKLP2gMlL|S;R z8Tm%`X^ivC6;izV!D!qUvQLb#8ev2Sp9hWze)pfrK6tK^g&28;7M@|wCwo#K$e$eT zs^7^F&(wf*5VCB;EH& zXl$x8vO95wp3EuMTlC`ua)?Nk6v4AddPXd~Sm%DD41}omeV57Oi_!;38;hTW<)vHJ zM?yr)-Fy3$t;DKn(J>c`j#!;>JOd;bmRa#zNV6Icp8;R5!HbxAk#To<==P3>%B{~e zVsVy-Ei)Qz;vsw*VWVenhp+o7&vD`$D=87IMorrn?W#uSH_HbjTlOn4#o(`!qcU?R zMoQ8)`?oY_p3-~p2jA3z)#_{T1(zNb>Sw^0>UHEQ2|DB?T8@A!)wf*LVLJAEb_ zdQIj#HPFab?PGTpLUn0EyhYHtnU=&(_7r$N5-DA zou;jm^XnvohH}34Yh}OI_G@ik(`YiK8cvNeqqq;w`SS?cK7w%>0bx0-)I@faG33`A zj_*6Q(Wt&l8Dcs9sEzA73~Ga72lc)ZTd{Y134VTE2_-g*LlT7c#t&pC^O@b~D;eWck-Pu2LMr(a5T@1#7GB9HTtzwa6)$ri}LtXog&Ri?3yV}vYO2*tkt zCa#Vvo>R;8F4ox*R_!>G-aSqIGnq3#i1$+!2*f1~RE6+m#_@C27di1k6J%d6%K^LA zxJD3QT#^li|22WWS;Dk5w%$A;?&JxP1BZv2bzVY#$_c|b8%F(|mMQJ10_4V=4ttVdt0m0E zfIShnu$A7v^c=j8@g#mu96{?%{Fm^~1OJzMi`8lTMC0Q+J;74#Uz{_$XmG@rW)vL4 z6Y?jF$si8zL}IX96B%uY5@W=9%VPh;9@x%3XuyGySK?=oYA?E^b|pRQlHMSvol&%Q z$XVxV*>MGzy}+C}D1Hx8IY(vQ^FbAsWB8+dP&gfB6$ORFT~SEvct)b&>x3_Fw-5hs z)q?qX^M$7l?-G=QMK8sxr0+P_5^g{;5^LxfA2)65j&Tb}dhlybH?|8D zfxL}mWT1@5NQ!v8f`2q9JA!2RDK&V6@+kLp3FBU!=hg+jUXZ#+=QZA9x7@hd2 zE3=n^d00qmEag9!;r?1{=N>%UmYy@hQ>(t0R;n(jC&TXXCH7K56c`0@?tFn&cA%j5 zSO*BaE;rp_RR+wVZ`*T5_|uz!-=iavGZi))!l7fTHA^CAT}<+Aw;Yo&TJ%mm7g)%sjT)Yz81}cwaR(M zN#W|a=$awDY)j}hNQh+u17HV*H8*u|Qt9G61wEBw0l;a-goaC`?^$WYH-bjv>oQ=Ef zR1bTzogx7HcjEb##PhHCSs%vpU)Enu4dSqI(oVRp|Fl;c%K5$8D^0Wy6kv%01o!J> z3V?I?TNGe+3b0H8D51jfGV<_<2e06;$y;jKY@iocXec-2SH)K7EXH&poON&*_XA7s zzoG!MwJ#_DUNk8nrw0l!!`&zVdN#G3V`WqLSc-VySc?oHoNLMuHxJ5wYCQ0Kv+zF7 zP2cBdl?6_x(;;21_-OPNq9!9VWm9LJkG&Rr9;tVEjo5ZvGCM5RVms>w7fIhdN&3VW z;mp~3ABy8ly<*OWL7y4U_*nV6OG&b{aN2t3{3Z}BBp=Jx6pdW9cIH@7!PLN*FxE&u zmQzhDoHHkM&X_P%qtwb7W(Hr)zNZWl5}yia1t6ptn3&wEH zIksWh$t=-5>VGKXO^pC~F#Q{+wociUWLM<8wV4_8d6t(~e|LsTq}4>b(=^{A@p#2i ze5?`fnciRI3{f0wp7liJPBn9f$kVJRlFbn*czVZ=a^-B<<6MP4%rjj+V57M0pwK78 zrT2J8U+e-C$Ln3oIsNG0V`@bjtb?de}t z@R+pa*^{!M6f!oEN}wUBgIgZxa;R-2M#pf7fDbK`gwVIieYpnncl(r_6fnuIQ&z^jQ5T zKf7=hq6qtfK9gBiUM@z0*}a%%sP-g7y%J=GZe?Wyg{ z#1uVFRd2=;_aSkzjOjWfHY78AYE(f9?w3!_aztrnA=v z_^c(4k)LtHyyLBu6F;rcEDl*cAl)Om=5t^0S2w)Yyp-?OC$DQdisqWR(>b@ughBE z4_rL#zgFzO`lbDsdx(3H+6gIZi7k+JGTV>|U5%prImUnQ+gf!>TIR?R*r#u;#K5fX z7FPD)?iN-%Rx7dHf0>*aYfZ$o=Rx?5@s4Addf7)-V)NQcEMs_OCAOh`JqDGJG2HFk zh0vSx8vDoy4d1X5zq8fL2>dHMckEw|fb2zYZ1q^&_-d=y^>a(NXG`~~x<#!M8Q2Yb zK?Cx3M>oA%z*Bs%fcn=KQ1xU1)!UN=)Uypdx9{1&$M-Ctx=#zJUn79OvSa$~D?6rl zV#m~>KiM%|yxTGD_^~Bh`}zw@wibM#V;$9_C*xwJ&Hh-)9Ql`7`T5D8!4`qft=X-< zSj+ls&932J>d&xLE%Y4~Si-1bt+72&fpz6Z1=i`iHG3;lW+iJ4RfJX0q$Szmh~4(aIG z13_;&c_3W-tp~!@-2?GGuHDDLi;2aChB3 z5?<#AkA(B%!6O0cxLggO^AtgoGePbJa;>ok@o8B7Yi!9fe`G zADAGieepG4F~vZUT0I9}wtDiEh@FCRB|>|Tfu{P|BT{Dd6zFA=el8eji7g0xBJP%> zU!IDXXH7ZL2gVsoa8DR#Ja6c^`7Xwp?)4WKXWCDUGkN#dYeM+k;e_PncO)<4%N5D% zdkA9u4)aXKUmzXfJ@-0XDxT_aef_kXR-fZKNm)~0+39c9rpPBsRqJnh2qHkoCECVp zN9NVcv9gpo(0B#s+QAjkLpWa1V018@uV^k{*>6^jJz{I(29pP~o?P{#m6&x4xa(m# zx@s}kiW|J)DThc)n;TU{WjElf4htLBYdnq(+btf4@!=kH5$x%#TJ=>98IFOaAXYS&VkO=`eruj#d8MrWS;f+JpQ%qz3FCtSrm1 z{k+%T?6@1!x=Y6i@@=2vSErPV@%5>C@j1HDU-}$f&;Ri`p1JBPetw+ySiktMaVq&8 z;njM3LYbKBjXsTdNKOATzooC`@LNJB*>5Ql(SeNa&F;4hChUGokGRS5QfIUuli>m%>CXM z$mA)P8!~x98^n*Jt2c@BvKGwPT%#|XKm)XNiF8R634`WLfJAM=v18P!N^H=W53_BkFf2q zL~%C|E8K!Vw}28f>ua>`xj4pl z*!hbE{$g(YrI>Q!FS*V7QyFAO)V}Qb-Hcetei7y{xL(~Y}b*F@I}<)`qqCoiw>cY@0bHH8^BzwvC4yX z3QWXcs2kyC(cy`CbH}S8Dn}8#{gQi~6Krp$~ z959jI;V5lD?HQgK&6aFxEN;V8lC5=kB9y9|8JJr3jry=~5XHZ&59@Otu0^Sql2CKC zrNjQRMrxXv?HX~P{BzV@;vOo}(h-kjKebm{{XB#Con897^<25n;botTS^MlB>#K4b ze?Oj2YqCzM<{LTKOT-rT{#8D!>246(bTpTZ^0`-6WU;p*L{?GsZfBw(^{;&W0ztsQB znJQoB(BR&{)jj#L5Ca?GDS(!&Rgwjx3d+%gBp*G(tbv5Zpj)$ib!N;Uc)8Vm@Kr6o zA?PIV08v1$zxTo|^sP^Cm@1=h+(K{D8#X$k&NRO2%=CsC*uaUe*6r|-+0AX9ug(fa z&{^vv*Mf#smAoGlhq0ckGwG704{%@%i^n%!&04B6S&;i$&E(4OClOCWU6)mYv1(+!_s^YPUzJ#)?XR1~)xqrA<-UO-eKzUm}%2#%~) zQY?(=p(G;-RyB$1u=3zQt z?Xt!ov=oitRCLwIy&2wBP39HSlXhTV1OrD4@z_2qT9t}=Zeh;bo6JK6Vb^V)Yh`yW zGg&=ITX1|c?tYfBRXp9h)Y@uMsH7r^ZDnHg3-y6M9YWzz5T+SlZKIZwB3zuNvv^@K{<;iC!T-5DUj(0WDu-+adP?A}WaP!<+*c*IiPhoOO(3a%?kx zu9rf1df}+Uho=k(VZa0O==R4_tU;7xl3`g#FTf(FT$!7l^Tv7!(hO=4nrh5))gr{- z4XI9@%T&@8o8`E?fB;kVRo&hIjX3wJE`{rE)+;k`#J~YJCa#L;U4hYE3=%$SO#2h4 zftnqu&~v;9j$^Tq<{6Rh+0O;rFcdFwpCDwp2a7)DY|>nW&InbcvyzuWBWfsD5J4@A zv{i%1V8=DO4=ZTQ_h4)fFpP&cp$u)y<1e$KqCPAutbOu317n`s)BK@+2Yq(?Td4)c zF+p_CAhR=T09VkR5_>+`LPS@SMjevu7R%MTU$uA@G^=0Q<)tnp*TauF-7v@vh(O>6<%!^QUi83zB`?)FWOcN50#5rrB$q%*&b- z^oSpQJFc#Myj``ASKV?oEpuxh=hi;XE#uZZjHrW=xZ6l-YT2_MM`KD79Ynahu5ffB z?M;chSkNh5bL(BxM#<3`gfzu1}rq(i7 z7`Hn%rWLNpkwb`ecG~x#eqn22$C6M?5BST5yI)U!z%xbu6Wf6gLl3N;z05rgi2#G& z9b#9UD44VEW<3CG5~Xyj(cKMVx8k)*QSOPzDN>g>x<61T4br?k^)!WA&WP(tR)VU&V7A&FLuNvtb~>2Gh(rejnYK5h23UJaq*Pf z$knB+x}FlJ(;?XH+9!U_HRct1M=d?7uN#?Tu56n#)h)7wcoiCig^7EDrDQZ-FGRGJoisfe8Ib+wjN3iGZKpHF4kNA|RjLcN}!?2`yB-`=(H z{^3ewLR*UP0Hv4Yvm)d#3>TF%5FX?CJny1oeQ~d&F9R*b+^hMt(s#PjUTSl4J>-@r zT5kje)@NRkz_@Q`iKm5|#6y1iqgN=svh6z%nqnKA-9q)RCk`J;nz(~N0tZ1WqYzBC zee%78)h@|nQ2N?s*C9XFFQGRl;(=5!8N zw*viouoMm-{h{od1R*f-D1#$e23NgR_J(_|l+5xuN9fFo39h&>J?85@&N1&=?@@Nj zj~N}^v&M3&dH2MFg2(fOHg7ICMi%#3vBz=c>jtWI17-eqsEEc*{%R=3gQ5^N?)yPS zH23U*I%=M!C^+Y$&v4zq6h}a+z%y{0HZ89yT0C*C!=x9E$fN85sTZdSD?Dk5k4lVJ z!*A5H1)7@*EqHZ#i(20z^_5UwQxqGM2KkG4zPk~W{bjH0^|J9^MHRC(m1J3~5O;|s zN^Rlll<`D&Z-mu&<_U9$vGf4)j>OD+>K)DA2_+Y21}KvBBtunKK!~~Vn8AEX&W4NM zGOGNYDyIBSs(n82XMAZa*fC;)T&=vHKVNP6Q?!HweD+{OZ#Na=56QC4QLo%b0|>U8-R4)$dsY(7O2;EAd|MN1t2)ZQ6EC6D^sQz-Z3FTzo%{t+L&FgJt~UeSDj}j}!7E2kM?uQ| z#yQ9Dv2eIn_LdF}W3h4q*yWrv-#h0HFPiQW*I1RC6f*7T!VxMtm0xfQ;eJxt@rhnP zqd&&dl}tzS39q%Tw4YQSH}5xCrmcgHlbY)$4|oNd&&H;(E<;zgS2(0B2&y0tmZW<| zjSe=~?3xGqTr%+ARGo?Cr<V-wWhT{B(x$mhI- z&eb=(6&1d7)Ol;0nR{r)jvzXHX4=MmfL0!~2b6H&a?=TxkIdPwIJ+F^C{YEj zNh`Aoqx>gTX}kZNB6Op<=olG%nTzi1M|05*4xkV^&lJky?xPtDV)Ub9hyjRn6^?me zqrJmz9hOg(4UQ0Fdv_i^m|8!~U?-f7$%U8`um1rDQDKMm+fH5oV%JdY0io)lqg2vTk6-nS zw(?x_2y@9FM{(_W?-PM#R$k;W^s-t_j+RG!Y0EKZTh0;%hWUSqY$$sL&Doc`CFC}4 zc$%uEZdjlsj4Aa^o5if5Gsn+0eJq`^ml+68_AD%Q=*ilOb_TApkT@6 zGi}OPSBdN^>+U29Xy}hKErYD!LUcgC#qIG&=Bv@}$o5Ybj)z@HJm7PwZ}0!r!eK=2 z`vdz%vw|+tCqBa~-eIXGIA}U+4>bbjP&E@w1i)HDb5^FM!zXm~Z@!GOwfysX2vNoy zr^WWLXTUd?!o~LCZg!1uvwfKJJ;5E;T900#mllxo?7fzlQ7L&NFpHO(i)Gs`y78*Tj%LqyZ`&K4cZ6@ALU#MH#DuaIRz6BsDFKz0kEDct zNC}}kPzy$^pa3Ee!w4P}^O7+f#$jD^IK6t09g_`)0l}bQDG#+#0D*PeT}se8kDo{h zm?rqClz`#Y-;oluW*f~nB---h^(nMIM&H-Rn9tUyd?wLi1*G3gwAw`TxkRf4wd4ny zm^)|J&2jyBo-5CDYxjBX)H|ShcYvh1fWcO;b`v{WeHGNr8hwkKP znM5_#&n--8QoGC+%QmZ?i4Ri0%vj(1kQGyUvKPdY-OfiA z+$YAOk&J^(b$ZS{P`rC3V*!+zJona-DNFNYDZbWYxfez--sjPBjWf?0!jXsMc5k}= za5nUpbKzY%%?0v9?`Ku1u<8wo_PLxAQEY62q(HVdJ#pn$ipYkfMZ!PAsIDU-4!B2| z70{7?-8E?9B5y~@rybViOz8zRdC&lfni$_7ue3d*hU~?C*36nUi&w0+!S=u? z6!8zgF?|^3Alh8CG0HNVetWpX*}an7)Yr=X=CogH-(6|p>T{!3q@8EL~rc(obml^cEX7$CSYcm zF}+Ckh@}`Ezh`EJBirx7^=Y0$zVtF)d&zUPM-Rd?8`}qt-bSo3u}~aq81&|O+I-L# zH)e&o$i6JwlbU)9T6#1F((9{7jI=k$)hKZmwR79|q_8E@bgm4=m9EilYuqVe7|u0U z-?RqnA9~1A=+i6a^)@~~rB8m5c=LvbFTO8E3Sqqo<}H{2~|___bf;XMPV>rhhaG={5`Ln1u?$D-1Vuy}1gyU$UT0 zngM*i+F^mUZ)FR4BdC-zjO*3HWMqw*8mXJ{Gz*f!{Ey5+a^IBL(hnsz+AEH7-_E<` ziXQ?`mKp8ha+VtJh~Tl~Z-yW0HG}jTV6->A1`ha-^_sEx0#yZ)&n3gz38G;I3BQC* zW#>T*bk$VgbDIG*qeZKFE4g@^8>k1ZhGG4a=2_6H^N;E^94YXbUXwTXtk>{+Q@L|E zwD&RPG5&7ab9uKC z%&Rn)R^}4J?e@8p-L;&hsF=LemU4V;IVfp+t(hITj~q*@3+J1EXSGhu|E{9=6k${{nOv@sjFZ4)br0yjzIfv-x*Dd{8+b{3&OR~{o>Q5Mqnykwh8MN9PK$0;{tnoj!Hw=kRBI@k=sFQ-x6-OSA znJ2(A-=$x@T4L0B)+$+gT;AfYgZbwX%B)daVczA>8M0xyC%tSbEq9fdca`O?w#Kke zq*E`eF)PSVjh`YSuMr|RcNiDU@;~}OMf&g7y^#JjOM)c*i#GfNsW9B6!f?n59Xg?1 z1Puq)+SlTI-dap)1L0x#)IccAy&2zo>nbWU5~7)+Orb$UPWeG9?1;bq4@reReNzWQ zz2qX-K`Ud36%FVv>bo5G3tsX&PPF|-hTX01<}a=8-}TSlqVlj$Hh2$$no_U)w1|lI zJs+(#+g>YnBHW{dCGs%Kly^IfWkejaF#=y>Oc9OmjIrbCnRnzDrSie6QKlxC&4h#X z);aghJjtYe%=5hAIY4!;5#sF`Ce{mL7j2Y1cQi?#UaGr3TfmgE{Utl|YN=@4q-KTgFO0gV5 zoI4?U{KTh&tNyjTe!K2DwkWBG_z!*HazDw|7@CoK9L2SeIBsQ;blf88ypCY7dyRuv zefxKeTCt|7m%X0(*pCw@yxCD7VQtXi1x|%_gv&7 z&enI%)(_5xyZI-5f?4{DK8?LkW9icf0`qLl?DGXZCiC^Re+Nz+`w}_-0Or;B z5p#`;Kj@MjVARYF_;Q~u_5sR&+wB9^*qKlDdG3N|ZlDteKo8ticIO5+tk^|Q3o9qX zC>uEA(!tBzEpG!gub<`jS)=#(H|7q8qP>wqG4J+zrk-S(gw&KRO3_yjLt;H}=G5V= zE+?&=vTDteCsaC=IV>nZc;c?MF;AMO<7_(dS>AVtKkW|3*2J@A*VwHBw@axc5(Y{8 zdU>uQIP%APy6tk~ARq|syr$lRp#CD3#aehgisY`xs z$FG*LNQtxYyk+5wb1&tRgge6#pom|{I8K&yOIg2p{6rQqt@)cQB=&di6X#5tu$7wxltco;k`4N&^3NLy zD2W85TRBNU={QkE0*bEi^?xG?NT>1NC;`Qu{~-xTN56Z1um-Y!6*0j+Gw4uE7fd1L znQ~$PGWMZG_X{pzCW6F5Iet=3P$$aqhh0f1Cn18d@vkX|&{Wh5y17UfMorn`1G<^J z41Ix%mkZrM-=&)ybtJY1TgA%tFbWr|jI`HjG2O<5M4(b~^K#Y`w4(g2#sw#g?2Q)(X*GU~J+FKrU zqh>G;r~XQsB*{>+!2}7%?RjCr?Fe5xW=uIrjQc0b2Q?LU$#5s{B%a=g&K~x7>M#8) znDd6MRZJ$mTk=1U9HAZkvE;bzlH>L#I=B93b#Aj&p$JpH$~wGV-}c%J&u5LkSr0%W z!D8(xxcVF1p}5huZ6GQ2QChc%o@{};S+#+9>^97b##pkEx^^a1Gjuggx!Q(qFlLUy zS&)l%YTdQ@@K&2Y=1uGO^S0x1`chc06Wq@)^aqKTa^!h|K2^{fX$2oWYu}>Ly3;5+ zkF@C&0juH(M-&aU?7Npb<6mn$%$)^JW3O-qt>PK%;g~`6>Uzm>Ae28xQH=N5bEoyz zW?=0QjefyM|Aot(wey@g@3Abyk7n#|=IlFEXLo}DC zyZI|9ZyAc?O)v1Lp3vH?;<{CdK9g1Tbrh$>Q^7NiIMvLPsi;BJvBq>-6~nprWxVNq z#uf}C7nJYxe#=Mihxx4cn?3a&XD-)r?tS;C-Xp%v>)s;=z={{xTKY!s(YHN&kCw(y zdOtB7X73Z)Hp;p8nki?gmgbjg?F*&>h&u5+&ZOUr6FDA;fv;nNt)_}~GNMvG8&R$6 zh%)71fi8NcC!PC;V~VDn$297D3<~20^BwoaE;n!S->9W{ez!6Ci}|!MznM=Hj@@be zXY_4?eV9)q>2*F0BV~LrpP-~ZVRKr{CfWP;Mf~^Pw>tCOjNk>M)~Sm*_if^p%~@>i z%`8$2{>&@Q@LxQkCho|5VjJ(V{j{L@Pz7j_+K-ZF zZ9h1vs192qnE|zM3lG0X=3zva6#|2( z;S_nU!{(sx()y^NF`rQwFFfCeHPfTNpqX1&K(@3smsS)4 zM)}PTi2^=T>xC{|)4!t2eHL!C=~dflbGhp`^!YX23A&o`>4A?{L~PIey=8Wn0&G9vg^*P@I;_Ei=;57@amHGa3X%lNeA9phs;#?hzRhy|^5_}^3bOb5F zzpW?E3nFw(%gFANjx<+6T>C%!irGb)^wh9z=0%T)-&jhEN_J`AET5?og^i_7Tzf=C z%7o>?voYUDd@vbv&FO}wm;Lyd*A4fe{)gv6K2@Grt7f}ID20sVPa{AHRO%R0MjCvo z*IrSSv&bZ2?ki0+&of^F`>_+@NYXF!-ph<@kwX%C5kqHd4aroXw39`X@7ZT#p#@E~ zsJHzyWlKsAFwdG~Y@1r0h*9U(&ONcIBfe(i3dw#y<2X|9c znH=jgaE0oB-TE!DHQ7o08Y7Z$JQrN8=T_u&wd*dOC$fcYLTLKho!5_klgjni-Ybul%Hj%@3evZOQh(zzt`V*KO9#) z*RHd`xXx6(uLbtLpd)&TC3FY>-m^Y==EZ)x=6VqwZu6vN^p&z_ai>#%Sb|CF#+8bz zb3a~r6JO=}NOKLPVvgoECO<&r1?EAXZG((cz^g6-#0xgM^(S$ zRGz$ckp-{%44*m6d7hs0nC~ag%=euXT@}}opkCNA;u9Zdf69>oJa$Aogu_41!z2-_ z^O+fqDV&tEvn``c2yzv-i2JXvrwDn)y~Ie)xd@XM_EDcIY&}(;(ekF5;e3*Sx3w+W zL)CNsv|z7so^LYe)kqh<@SN{##|vLddvU!_1n3jjs<|@Pk{;P*r&#fuMc~GDwBN{Y zk9!T?-t$4p`HlfXoO$+Xr(j*~6gf{+*Q(?Z8L@jaeA06^pjrneJkfP+gqp_B1;{~%o=J} zijeo|3sulNO88CQ4H zjrd*lQ#9)H=|gW8O+DN7#9wt6;O|Rb6IY`S(svi}=u6i&(oe#QGNhJOhj@8(&u^zF1hw+WPUFfGb zp`VEg$RoIN7lcqEPyI{1dtI|^*upj`7uLN{iM-)B&0{P*yqCAcOgAxvU&)H z`!cGQI#tC439Eykm(r$x?Ab*rt4)nH?HLxVQ>K2(B&erMf;{hQieka?UX_vJ$Jld_ z85ha!IR;@qH6(&(o|8*$H905Uho9k5+G$FLhdZ+)|tL z;E;T}KexEKTZ>j={!7@xk1^Vnx^n8aQaRO_rddH#OdvJSbIm50iO59ff3UvhLZPr+Mk^J9N!zuvWNA|Q6h?@x92z5Y!5TO;P9A_ z(1CUgp*Ng4JfR64SiOtxa3H;w8w${&5xfLi*k1QxEPWWW?f7tF%^JC4PgQU4HK%*c zGg1=iq3eBf&XnFykA3ZhcVZOXy81|mGotvwIg%&ZNq;(?aL38;qMF2v{w7Xn>%j?a zh|}KXGzfl2Wlg_f-?CBjX9iJObYF8~)C*ixte}%tdjL#)z=}K*K`m1Li zh4ECW7L30kcJM{Utr8&j(H8gJiws^MvU)-0Z* z8s-d=#SM7|@q4N`w$4?fR46>N@E!~th=kj#8GVO*Q&zPT&(;_wl520V{Q4|)d&IEa zBZkfXi7CtUjS*Xx`lpJkmS%Ox=#(*cyGB%_H#rHgnl0fnt#g2J<$OYO4C1a>L2dGoxES=^6=VnNRtY<#VxaNd%bJ{nS(OuzRj!d&D3oiaT6V-Dz zpJJO{@TJaEV4E>_w0E(%IMvZypC0Qx&X|`VaV0c=@Z{Jr3>~P0jEnd_t^}TONi>JK zu15q6S?uY(=NL8MHQQ-t!Abr;zQ;Ouiz$?UIy!g^p;q zEY@Lc*TG~xV+}R&+<xV|52i;R{_l#pN;*L3KZ*TTvNT40`t0Gr5xC= zmzY~L+tVoWUay+v790u7E{RYN`Mkl>#B9rYkD7b3NxG;T*F7k*f-V}aU$)k+fUDN8 zr}sJsXP=(K%>TuLf4=i#3Flq$I_~5egSgbRNDnnFPJ7Qj?7f}dW<8nj@54lPxHT>k zX^ypmX&H5~)ngx`r%uqg`PzP0AIAM$+4v=JA@)u2`Ab%dp1~?sDSdlR8^~ z_h{c$cCxL@47r36@?k6LM5%l2`twt9N`t8skRxq&+2_U2`tGfnvDZzeco63v`A+8D zif`z`X+&zccxdt-^>ci>?qZj=wzhEWF^-t9sD&-F-{cK08#R%AVZL8g^}wi#kmG#D z)x$=|G?OOH;M_#H%f3Jd9zpFM5sC*R3JtC=J^c)2bo!uoKU z?}u63sB#Sao7L-ft$AoyJ+!M{wkycBiEa8uyqbv`;eVbYG^v0t7?g=9+_B^wbM4lW~V%XE>in6mE$v}l` zcGlkcs0Gf7VecKCg@txF*&wl^0n!0y6=p3@h?fY|Eb)Qqz;%HnA3$*9IRaR4qGxqM zD|H(zJwbRu*w3RbgoAy3R2rCb&k-HC-?<&UuR5_TutzaS&4xG;D)vmrD0Kv^RDBR1 zcv?oDl;n5XrGmkk9tvquFX>_I*s@tdfZu0ZkSyj5#Hnm5Aj z=XtZ2d6QZf^(VD1q;B8yTvub~TnpAxBVQTs-&!L3ACPJ^+e^?p6kqcMbK?m(S9lB) z4P%}Z?F;n6Lf={6tBs@3E9b<}nj1z1pOqn~KaKYxUgy5_w$CiLs?v@~f$I!Bgywl& zjjhgV(r{fJ`-9)c*XcZR9?=h|`k>6Go|Q9P9c9{9q%C?E>c|v%V~E}?%S`C+VJcbQ z#xfXHKG%NsoJiY0ds6-Q$shJsq}uO4SAN`6^P?vT*MCEY zEmETnKWangi3+piC+v~;w@8|^%r1MyUC&JBh(%2wKi8(?Sg5N`oZQrhcfZmlF8pF+ zh`YXQ8B;wh7;A52g+9jpZ20mV=wdnj?TIf5Z9Tp0dNJgY!Q`PKmD% zvpU=m%mS|UNwrYSL&V+T8FKr*M|I2@Gc-L#yCn$PS8nHtR_f16jq*L_Y4SZSsE;%+ z7>{tA&0(of#S|hd#8ME&`;g?hSE6!TUCw5C60VX!ZDy^)Sygqfg)9A)I3m`D&FpcJ z9&^u5)w`Z4Cp=IN(#=9S#D%GrBY)*RWcz z(o*F{s9?@cex$q2_NCYU=<`ss&;Gg6SCh&3f9mhF}&DQJ)7V423sH3tO_cTp8c8!a{$aaj2@u0>6VOS6UD^}D0@H2h- z5UI*eUB}<@AD_+^s&Kc~N)_wXfnv!0?o=OlpJ9yDRb$pEax2POBAQ_xlh#wL05p$! z&O6W2)S(RPq>I%+{D-e=*~vMbD$2oN=*#EfJ%P{*i8Nq~(rmr&VyhqwKu7?Y(XLwP|sGxvSBbry-obDY1L;k|6w);7EiRQqx7Zfw6 zE@N|^$7ZLEg7>_&D1&f?(cOLtce6A?I`B@7XajYte*>SSUvcg<>9=H2Tm2;zE6$~Grqfm+?B-tdA}>|-s%Ith386S z&9l7n!EA$SK+#?6{F+tI6Z!rbZFG?w{BXDmB>TaK>>en@KTya%YP2*QW47kJ*5|9` zB$F`pzuMhj)GEq1x z3)7SClP7VW@6X2e*|Xv4*$>~F9-a*!zPCI*`{8@r!?XUw_l~D$cUy)^sHbzJgnHdh zL=Rumdux_-D?NL5?ByibMts$st|qw}PFI6mO{c3)u9nkPBUh)!A(1^(=XHBsZ^GQb zk=phhzY>Vj?QA=g>}9bo&3tu7nEEfQb2v9nJbZqMH(0fEcX$@4pIB~$cbB=^SbuAg z^l7aY{$!El96+(XVDG)i@MQHXYMyEL8X+>`u-cAxnz`G1^=mut!L8YI687t-xRsMl zxGmK%pKQX+U)k#Cv)b#=i~Wh#^4U`A3Do+F)#sDow&wUQGuABrw^Sgu8lT3b)YV3@ zM|1cbJk>Fo)Nn{9m)z$p*+=F)%kC_H!Fum~%8FYRI`B&Bysw$iAMc=C`jclCQMA6Y z!Nap^d6zk?3=+w$cO+fTOIv)jyG2^)cDDn^eP3Mc!0>4t`$8meEtwE*&DM5;+{>9| z=!MVZxzCm@Q>XFQUF%cFY-h0{a*oBC0nTGM%Ly{ma|C|3WSh$f3hH9V&Q7}@CQF2q zFVV7GF7d%;wd3+^%Bs6%)jwP5Qp|&&g|aVarDvJXJu}`R8pQM3gZOdcOa8)_JXc7` zj4VVk$zmZRPAS!-g}w;a+fIEQcPXxnZunOfV2E+&D0w33O9m*>@L@6KJK35}-;?YM zxhKz@XtvHLSt+~kYm|lNxa{FCV@{H&P6YSxfsf4m|G9epx{L81!cjlhSa%os7w(F2 zZRt3J)u}T5q_Zq*V%D<)PKu5z5@kgUpAs9L5C5_!zb!d7=kK4^xb=W>%@0rs%)M7s} zmV67_#NibQ46gZ3$Bz>4NM7e?+~#QaSxqbS;QRBdHW+9fc+rK+mZ%x zZ0YNG3gq3Uh#GL*0;uu1$Ddb%WV`YkTk>Il# zGmSI8U)mwZfd}n}%OBezhe;O<(ON2)@2xV3-QV`?UaI!tC=u0Ca$QM|7L{<89pOcSr+2>ThgCrt2z4#i;1h(hY5mo*aQ|{R-v`I`T&<)7z_V8PvM9y!> zMQlMIw#<}`^oi~J18Ma#1HBwGP{-FZ@MbSj?7rWWJ0WtO~+Ypna_cXR$doPJN2Uk&H$T_Q#IkzmaJ!$^|;WF+`} zBs@767v#9l>cW&4*V9A>3&_==?c$C%5L%=z9gz>&4$Ru%F`g>Q-0CRIA7^3xnqX#iQ=xfUT|$(alL}6@%~1p zqUKkMU};RwaF)N|)B+jP{q_1{ySM__Q+;5;TGhGt+U~u#`iviW^xjGq{*E0<^ACrt zA0-kFwh}CTyX?~ab67r~^772I4!yz&!%XmFmu2cX)~9-$V;kdnj-6Bi44AWppEsFl zXI$ot+g~HAo@e@w{}${W{|&CyhndE^fZd;b*&MB=V=cl~;cjl@ z_`&AJksonwWqmFz9)<%oXYZRgX6+l_-yY=*yxXRu7R70ApgV5IwLG%Iq}L!=aj%Ox z<$OM#{C>vS&-L9um*Wn5Tph<9M;^Ru_+a_m$Eu)tR?@`k0jwd>4m_hLIiRV=`6R$t-s?Y|E&mFm8 z6dOztB_WO-b&mK6{$jPB*$KBCkkAqk#e$15UE+P=vE`+D8S>;K`iAJnDb~9h z=a{fRg8G~+Rd^KolF`h&ssG2=K@ec%^ALL6`LiegliKGw36>f6h3OotAc)mqjcE+Y zjeAx&b9=N=FA;(tL|S7(`g5c;Sr+;E)v_eoXx~78BbXxmg85k$IGv5^`GAc+wym8c17MhO5J@Eh{KBZ3Bqbci$UB#+#Vw4r~ohHr8( z)?jI%ydba5x%FJS4XsC2fFKZwB^xtK4MVv+YILCYf_9Qe?x2#zKJxI?bLer^Th(5? z2D${uCyGagmE4|l`02N!niPLqRi?OIQ!IZnCc?bSRjk0opL8>H?SbAvCFGNIAuAuY zl!dE)D@mU6(v1XIjO8}%;a3$(yJ_`7PP5N)TDoW$hfj$C5N>;g}>{qwd*P{4FjJM*JT3;=}bCL0mDFdaV^EZ?KQS)EmBs2x0+sOAIt2WqJ2 zNh=uzgvsKiSKPbUDeCK-ou}TUA@=Uob2@2h_O895lbPox_^od%hRGoBCwc2=3+ts} z91O3hKA+P2bCcs#a@ zfx8wzMFjHFVZgPHPqEL8u`#i&Gn<4~pvAn~fR?@EdB5&^o#pl{Eo9P8pYgf#iN8;% z{Jcx?iE4MWhQkWb>UgjjY*k1@D=VTJKC}M6swCl+q0dO`J*Se!L6PABPT9K(OA^7f zde@b??H$D!yzbo$51g=@u-gC+yMg^tSHC#}Za8iCiMjAY-ABu^`97jh??)8Fn-O(C zAK#ef{aN`uqW5RzOReuNejeW25Pz!Za9YYF;tOrP<&pYUgd}MtmTFeYX=SMz-PD_f zl%jL!YQM$M+SX|07~}5Jjw|wPcFUp1gEjV1i*x>nmYr4Xzu~mOA%Z>1KR4IRam}(! z8t5znIU`(aIN~o<`A}-r67tpvm-(aJOFSY{)$k>!$czp=TOal_$Kd!q3pl8*_Ij`| zpUf=^eM>76`-rNsk)#-VVCJS{^cRfBGi%gtkuiG~=t+^Imm3*JugFQPe=2oKQNI~u zURUk0wR!OmE_<)=5dA8v`o!aKB!ft66Xa0$x~3|PbN9rcCUMFOGX>1^$Znw(W9s6~ zey55jQs))#p>a;Ltu#{01bTP-$X3*?#L=70zP)0rp8Z=p@0cVl$eW0F#Eo}M`#86= zbe`MO$|~{eGu`vI**@iOv)}W#Il_rs_r%|3lgMb2m1vgcga7L;u6@UFa1wvN;-!}b zKT>Y!Lmjtkz8ljKN}e9?kL1_;yB}-C`>c8$Xx+io=M}ebmD^8`Ka89rP`OU3YOY`r zM*M&HrnF#)N_>Oim?zP=Py2(3T;*7q#yE#%Rc=Ap2%)y^`hgCDu_fnhyM;ERSDT75 z(=S*6bp1f`Mp*~{rbP94>REr1dyIS7uQlMTh_m(m^jC0bFAuBX+;7J;bD}6axC1mO z7<=`|-fvn7y*7-O!0M$9V_2%q9mvWz(=F|y!tt9l z9*cQole0#s+O$STCDS$Vi83AIT0ldYa4k5BSIdmMbH+2}03H|?9x*KN*S;kBZGS5_ zx?l}Ft~{&_$?l3Uiwq8$(YSDO;Y!3jXq#`4{-|C!OLSAQT^=4RY>!H6yOZm(?D2#^ z^`=~+`COb4WOdko*%>o+Yy_^G9ZaE{KBaE09(5KBLbu(ahufOod>%Hn43hOcV#hA; z$5Nk3Ed1+CDVjAdg=-k^C_~4$z4gmCgvSt9l~LAWzIc{;9@rwqu~LNt=zFxacc}`D zmQc$4envrf$``-KP;fWsl7#8HQ-HFLM~PT?!2)5Xj1^?JcGP;>x|UmN!>(Ufw8LW^ zV%!-V&&6+-?0CtU$VT=svd#dQj^kX}^dikR-V@`6ZI3rpY9Fa|A#44BpT&IV zV(C9yJzIN)Gs7sNleqedOHu~WAA}>)y*!5?{C9$oyqRI<0mS32DQw4p{ZrU(&uAGr zXEYP|->m`mPxz(m zSUDx)7344UZ^vq~i&y+@#CP1~&2GK*fNc8}QB<UE3uUG_b=}45HOS~Q4jB7`_0%{Fx@jrA{(pBkQce(nkYh|jDg!hmR z0RjDX32HmeR0lAt+&mC2Y-XpebFBk`sp2O3G_uRE%F&o& zdnt2ZN$v!*Rs+!Jps1OGeB9|KQoia~*DJGB4;spZ36H0|_bk;P^6p1+{4TT6=@lfF z1r7S>vZ-B(jGzEhi}-?__#9a!-~Vk+N&Os zWsv$AEuZ|fgYf$#EceOJOT9|<5;;$}&wr=ouw;j`igx}xT7AxogSO7BINHyok^R&X z+7!yUrq4KliLm4Tf!8s5!FM>FK~9G&@hjx>bC+zLg{Dxxx}N5Dk{!al#ijxV z@-_5sM08%nl>CTQ=UGG3816O(Y+RE{j;J;cHCoiUfc$VP*@1YdO$-S%=a4Ge8_NK- zDo>CL6vikxkjrfiBaH#elzM=sBFO92_pngEm$e9yCKOswCc-fd42e{I!fz9!CqXSU zz!8CLGAIKX*b#IM^fX&?2xd&sR*cClK)*OwUGSs`&$4N*Xu8XkI^TFCu-A$)*VgG~ zN;QWZ<_|gS;n}NY--%3!R{bxGM^4g)CBJ=zy&iQLM&oL^jKvjQ&O=WOnJck+#FsUC zjIM#W1~5H}lkG+-%&4N-g2Wg11>#bAh71Z znT(go8Z?dz%mR^v%_gy~Z2Y8s&!xr&H5cojnc+5qu@ zuI4FM1ESN_!B?F~sxWP}BwOg}D1)y$@@>NjjaO4s>ndZ*(pB8Md=-mW>PG#A!Ac)i zRd&7#ck|U6Yng%Xbven^23xMw%2&PI8#-*E&@5loGCM$$AU;fzmOp2Y%$)+YDY zu6aO2J&?kA9<1r>DpFo1Yo#`=iEOSrRv6=+8O*t(tFUilPCUODE5Z^x5Z&y3@>MVQ zR@W1>%_GLTf_zm_V@Z-9S>~+4Ua(cs7d z7a3bOz+zw{(A8LFCQ(a`PEWq-*S#=lASu&KDsSa&y}L4Urx630$=je+Sop-+h^=;A zh4&iRK6Ew93c=)zf^a+}DGwRjB-^Cbe6?lLXC`c`YzkjPE6-J*Y5wN4rmO4R_wMnW z|Hl^Ma|`E_Hxe>mM_V5(DI6Y0JvtTfyHt65t`&;bOqLtrZX+Hc@+tzeFqu&gSB)Q$ z(rgOLF5<_t_QmHWS}$3jOzF%6dDhg}?~+hRFmB8Qj5>|do5pBSbc~fAhU=kg4VnwIPBr>WG%)Jpe%r61$x|K7Ca)}LH{jFDclFMb4=@drUA^w8~kfD&_XAy?ccHN z-NlX&@FY?@SD^lAZ;FHgO2zZee9slGdrz5{`oP-FcAy4|X$JN{aiBS$7+W98+T|8C z1cNxT{N3@+GI3>P5o#G_sIhFdRV_fMD14XK;s+qSBll1VLa%3?SPAO zjQ{4PZI=Y|WGzBzO1;o4&hTF0n6L(sYB}?DAqi3hb-{Xg8$~P5&{gDL!3aJDhhM5G z!T&0)B+Pg7k|*W&buC7IPxY`M!yc}%JXJ>rY!_tAY=Gy&d#g2YHtShj7zzY$1N$!N z2x55(uoF<^gtttTFp;Cd48#3E80t%21z^81f%IEnc>nLJ%H8Y7i;6wgR@|sqGjb=T z$L&^W)iDKr_<2&__)T&Y%Ks zN!T-_xAaVlh%Q)8T4YQ`%zeVPCa3`kWaU(@RCvU|yNHO9A6xF`6jWfu1|;trS_>%l zP@+{Z<8z%(^xb3Um2gG8(|NMN;`*9K>j^tFrA*j)A-MBS9*w8SyzO3ubv4^tj!%Rw zff>Sqd^AzbRb2yHYwH_DNY+g!I~@B`F#Zx&Wy)_$GJ)UHqVdpsLK>@2ckR9Q zK$#vyU~kceQ9uC+vluM)Q8Xx_1!V4;8ty~Wn zr7i`(wb|7em>1%7wWEWw31kk6ZG$(o>0m-s2VK?LsM4?nBWkD1E`rhvl-Jf-MynfL z1c`hm$~t*HCg@3{p1AADd*`7SJ`!sX8!&uEtehp+5;wuzaQIsq- zl@cAts%6*5QBgM2LQ4?L8t6^o>Ob2WX;ajq{L~yq=!eFqL6kT&@UyD!(y>92pCCNL@_P&0V_0DI4r5v1RRy?o zMQc!O#SPe*78p#!_-zO4)j)_rE=9SRl3PzF(1DylD4`g$N;E@tJPv%0U5b6+aIdTo zi$@p4N;z#0Z@q164oiSJvxNVlC@$T=(Q(mzN>mr#S%Aaryc3bTcHXI2^ZA^2ax_C? zWQVI3WIxq{@cBosd%fe$vzL|UYKV$5T5si9k%!iO;wiPaT(`PiI<0njXLBl79-QJY zwWjO|$8zm;;lwDB-E!ijZ(=t#4okL1+-MIc|9u{z(q6nWBaMZ{qup_hvbN8AqGUK3w^ao#Qj#>8@TV2L_H`!G~s^24F(>Jeetv=Yr| z&`Lwr3MWv3{=-P7b7+g~I>H*{mMe%iNoa2Q?+$6KqvT3<-t-)!3Zmv0Xq|$X|4e6p z_X}>eNXhIjn*H#|sHt99tMwMQhzp;v1-5bhJ)E!Sy#=%TjGFWx&!k?oklTZ6+&@V=H$-Sb)DBleT9rpBJC`%o zW)5t1vWK6=8_s!LF{d~msE$+ooFJEBD9*v)Vk7K>k9s7j?8Mdn$lb%HQ)(`-^+m=z-ZS}2?}wR zfr}xslhm!CXdgJMBd#kt19s09W0X+qj?uWMWTZ%CGOA)l^?RP){ej+h8Y5Cmj$@FHq7z(@fu%c7O7_F^7HhlfjWx?>r2eq_85VHttJ5G4eZf$65v$)H~tmbls)L8X~> z^wxu&Krbwnqg49mc7SX_P>rb#T;wsV0i_HWCs1ru6=A{=r>`S4X3I0W=-sHmT$^_Y z0$+?zC$F;hA7*QdEP%7M{aa*#RAX^DDXcBqhU*qfM}W-j3y^n$86OFhi#8o_a1EnI z&y;~P8|Wrmm>t*=|3sUQr=7F)v_-5Pu{6Ga-xcphJLh*O=8yZ*Rd+c{TqUfcpU)Dp zZm?v>wTCb!8FzJ1WmWn`MQ^hvc!>?Vc)7LjXcc*q3|UG(-i-DOwWGp;7&d)$lq&#l zkN6g#Z2znCz>1HUECHx>ai1w_+~Qn-zOJd_pVq@PJ25c_y{f(klRvSivPlAgy40 z;=2e9#^yWeBpK~Ap^|Gi%*ssVECT)wf9dt}_$TGx$0okrH*f9#PuVtf^@D7i^J#a~ z;&f-ew46sF_3b>Oab$hs%+MR*(B}-Ir1xsQ%ag+qkU)omKZyou$?T?@pI1%&S%2L< z$(x25HAON%J-^+5m*dE7kTt1eV704uKug`&3Zf32zL@d}OcJic!BUL{@~#C$huKRn zwp3HgfK$qJv5{AlBT*AybV7Ygyf>n5X}X}k6^+M8koZ292rd$R4DME9-wSn)XS=uMIq*m9?p4w+7?^0PE)yd`Kum;= zXW(?XMGG|7BgxH3-LQq=OfU(~-wd2ySD?D+U;D3NPBC-CZyY+{)m72rW>;y#wR3A_ z0;z+7N$b3zk88(x-aM|lRSoPX%u;`fhYfhHT2N9~BC$>I zh->ah_t#z0b3COhgAC6MI~ZH~|&yn^Sum40NQb{ua4?x~CJFLF`M zX~V=kR6>#4C=8!R8ef&c8NGAm-*LU$+<>#0RNtS4l9hz|bMyold~?1<;a6Bzg^`;= zG7r`mpTnIklw(B~=Zo%h#1f36%toFJnX-X!$&zL3BVo?lmwn!(VbsZ9VWxbVtr_!g zP*<=Qk7J4^74D#V!5r`jS|VtCaS(RJ2;sV#Emg-{LUM{Gy~ilmw#rRIuiOK{$Twh=7| zUI}y;5W%AAX_h`UC?h?`2tRs_wkFV0DNd6-`gr!a@A+`A()g+o0=xpb8rJpuhZ-TU z)%B|yA?Vk;uMq;Xnm?%#f_aTstd*tXd$@W__#$qMO9-eu%aQ>)UcqAisRix5?v|9Dc)@)@R zc9(0H>dB64ZRoD0#@xpHHLbml-YU#u!pt1HhBk+>ykGbPd{bw{weIbxl&rC)n#fp* zWRvVqZ;s^h^9bzg5rEbKY`nHS{t&r%Gv@4X#;n(fakQ3@adqby@-@CCH`0i@Th%hy zhD6s&U8B^RJS>o`0!cVn49tlu^oU>@6OhAwM`h_VskY9CLcd(6{# zGG147FI%tH7_Gb9YvkT;I%|+cxoXn4Q1-A=5KD$|!W)Srh($%0zV?O(>5Qc+jBySh zS-?jN7Yq1k0sT4Q7jkViU zMj5WEXiNFY_Wj0tGs(9hI*+w?cywg(oTMd?orbj>w8gFne5@~@V>Q- z=X2^4I9n)Yl-f}iE+AHTH=4#!SFA{ds>w_g^B$bl?Ti$}3ZxP%OZG3&LKem~=&fGI zZa0+gg-Y~yU-BcW0Q)w+$D>yaf4FN~pfx|$?BM!I+G>QS6XS4{LNP!v|TTC!*#bdBU#*|~{ohp%_d?r?EPkdtQ zqdMBWM^t^7-T!1ad^EdXd-Kn;`_~=!jTIsk(`|+RH@i0duxmZx1A&YmmXGv*-J|_3 z&N6vF!s?M1l zUG-QJw`kJgUi%c$SN?^Y{H!@x${qcraGDAwL$uOE9EOiT}mkcS0sNsS^UqL<*TKJ_Fe zZqf1gIimQkp7%Og2WIQiMUu&k*_!Nu+8Qv%AAWE^D-90+s(+o?ea*@^bX0G>77Gjd zA!#z#Qbn zt5{hn7o3l9)NOsYs+iaQhgB_h4u`nD|D#ov6?>Jdf)O9EQF5z)vQKdRGaa6Bf#uVN z84#|R0bk>^M0Xe#CA=1-x@MHA-{Q5{&u?VZu3TE|?TE+85C=$}GkwjMG}#|RwfnfH z1J-1N{k`MXq5l9;8yJ=OPFhFmW@HC@>Q^^)5Lk=& zU~bVr3-sk&({uV>YMB*g-UXahIR3{(MEP0G;$roxg@_B%ZmqR6zP=D<;q(H%P&>YA1zA-E;6uoza<+a%!&j^H z7kFtbGY-C*1VdGK5JN|2wBLYukA&cB6r7okkYEjC{5>KAyAqx;fI-(z3)dI6ElA*e z)x>ACUt^n$4fb*b&6o8Idtd-(P?l0oY)kB`UFfe(k^6wBz!P3D(34=vdIt)9XEa)a z=xTg5RFz`ko@u}CEu&1dXriC77Jq{QTo?W>;#nbb4_~!13g8&Jcg0A%Rm~e@;IdW- zj{MQ_G$YL7w611QHM?S5-xy?mfes7kko>l2=M9Q*SZjgBNMQ}Q?#GN~p$M1e+mx$o zg?4OVHM(Fd!`Yv0?~F1sYJA2PRwKxqVPSU#9D}b$p^{oEm8QMkTPwmD6-MP93qKk< z<%Z(f!9s|F0gU`N4Mr#KUPjS@8d93vGt}?ost3lyD-RNKzCj#LSy}+P=;Ux<9Acq| z=|Ge5X7E)*l@TZKE5w{*WLq;Hkb$G7NWu2#5u)q=3DSnTji%a>HlmJCNE?x?z$em1 zRPM+$35f4}i?pG?iL}88eYqc4xDOdcXh{G**P`Uh9_Yg%d5STSZ=vtsyqAd3fN`Ew zlS`2a=|D;aA@uTHKm4xu-~S_w4MNau`{>?B65c%@=y{G$dV$iRk1Sq&-v(yGB0SWa zHvG|s$FvUz=L5)b1w?KTsYgbr?CG!?LXM+{0Zn!|9wwYT^BG^wtrIus!K(%{<;E~Q zU@T2dzO(@pwAGO;c}08%#h#>q_0>U80Or7TaaKg=;7DSNLgLW-FJ0n<8MAj?Wvocj zG|p>;&Ah(VymrotEmMWiPBkbigaC`=gmXC9Gf0TEcARnl@LSAX&;=rDH|yS|4`r7n z4o_(t5*`6u54(E0mVp8-R(ChnVu>{njG~1_2s(hUgk&CmOvxaBSkQ0~f;i%2uei*W zlZxPKIo2^a>jMNUl(gcZn^OFHod;q>2m$FIom;uUe;v49))ga<>3)oz^lSlvv%Q~~ z(90J``Dj!%{G21yvJKZb@^A2qBm=v0^aH4U_!ifl#LI`zp7UzZb5^VqmUh%Ma=l~p^A1ZVBgxnQuf(9?v12~t(#)vFiqmzi4r(!(=ugnW+`>hr z+-6w)>#vIKXUD#VJJRJ2E8O~lGoZ8g;XbzN{lIg~!&573jy*{J58RI!ATaII8U_-H zV4O?bpI+6yZum9qxs&b|a`|*G@?y|=f8p;^kGQ|SKZpHHk^95{Gx$J^LEqXjSN88H zL2Gt7!jaz~bz*mXAgow`{K~HHT#x!vX-yA(~CDAxVU)cz`i|mhcW`Mzxcl`QYR(yhKBbMGAR}Ag~Z#SK4+yT{2TnM zI#(E@{SzA@v^sm@mR&e=luSr_*g&Zs875ujSchE^v0HU9%w>YMUyh3R@ZHSPnG_g{ z2yL~5ZX>nGsA7XyrWIxX;lHM3Mhi;rlvM=*(K+7Bgu;|uK63{+e?V%Wsk0*5!pyOO zX=-8S&>IyY<`AE;gb&U$9#@WG3TW%Jn@qv6!=6Eh9{T=mx6LaXylrtO_gps(UcHBOir@Dx1=R8me#i!rI zaDKM))%*Q(Xoxrahkv`t>_VQgKRpy*!)NdMa8?~mL~$59_qGmOw`0X}aSg&H=aF65 zEbOmj)4~JAGNK%TE|^`MTe8rkQs8frlcrPTRtMv9tt>c>Si_7e%nOMJvJ_^O#8ePX zlk>I8clD$|E2$zbF;PZqMx{SEyt~oh1U}ngs=dZ3JS~U z54iKR?^Pk1YPY)Rr;$T$7_JIsmR=bwLdg6GbNLt$0xWt5mDlVEWj%^6Eu^`}-PXB$50 zR}u+FP>?iIo7eXGJxDRn@aW|3X^!u5g1-l%i zK7B8V-N|7hb)iVJ%UNz87xVbXh-W!n^Cm8josA|X2#4eGZ1B<>Jd78LFi8) ztZYY57AB$TAKKa*ib~_58SQ#vzkMK@7Z=Aw-)`9u1_FCQS zoPS(_0-Q%pbIr87oqh98yBjq3!>UcYgI(q7UB1X??ee-XW+kt&NEQwCmDjjg*n=(_ zz$fq7TJG#mT~Z#&5NgG$GO8w{%sul=LVF-N54F`SHd4xxFrUiaw{_9%AEfUmjSoFr zYS&M;nf;bt@>>+Z&sIw)LhtK_IXg@d@8>DJ;~%f`@Ix^t>Jsr@edsG@(^uG%%3SCb zG6`E1U=3QiB9quqj+%DwYeN8SNgJcRY6E|rB(0i-!Vzhn?8eI?%@?$X{!heOB>*3a zGXk!>Fio)P4J<6)X-D9USWi)80a2?-s#Pj(?Izi;PYAGfVixWxA>Vj;#J`fr;%!LR z0R1r}#ug3YxiK8Ag+--S#1#1*qGlV?%b8;w7AiwS&nJ2#JlT0SAkL1JT;2p{Ug}R+ z3Vs%Dqjo}(p_31U;P^4B0-un6`C4d%HXXI}JYzRA3KB|!gce6wxcJST<9w}GYl=dK zT`&kq3Fw^iol%+zm+^*eyykhVi77*40hNcb{@X~gZY+*4qtr?`DIT#Z(2vH57*vZF zHDrmzTU2tx4+CR#|Ae;z=NV@};e5vR7LXLrtLZ@F(7~RXnATJeM6(u(GsFn#@J74& ze=pVGwC*%hmEPeVo}_wJ@e#LVAJ2jw9y;qda2V-Kt`PItOCfpuWw>)%ZQCpV48C znktz!sFQ~&vRtNipHcOi>KLUXs-G)q?LEKLcUgT&8$Ye)Zl99{OuK0r?H56g=wGz7 z?mOIWJG`P*igvl#ce&{pP{X06lNP)!~k4$B^=&!d{2 zVs_2hmS+R;r|4#Y<#q$g__QOBJkb}VZJmT_VFz&tZD-DnzSmrd(>hCW&i^oLVo@~g z-50AadZ-O$L!G~Bn@P4pZgZRfpl)Z_pqV)4WSz60wi_%kdHJnwzb)&BXDj7tt)wU7 zWFJ0O(md>b+2s26IhHJ>+VnP4k~QOoO3GIZZC zX&h3nmDR*zYgmVrD5uM3Tw_8V&y1c!aeV89-*A2`*XTq`3XYGW zMBp^fgfBy4#)0)iF`5{4R2EL2P(MaJc-R5hkDf!u7=k89eV8X3xOG7RLMfEIv1@N+ zECf^FsX)j?8cu!M2X561aH;*QY11l|$5lGkMN3Wqub3mmBp5YPD&yvQ$=l#>POaJE z3X9h{Gn@&WFLRdO%$c`LGi>ql9KVAWSgvNl_-kZIFF3Cx9g@k9`bZWBMlI#~J19++ zypS|ygqZc6cylpddlTjRri^Kww;%waW8@ zRsM9m6fyQ^py+%XoZkYmAI-WY(|9cSNKlep`UMK$J*1}IVg4cEjuMY$btz!x7K?z$eUqV5} ztT(ux)IvMpJh+t;$LJhx%a99~U()tV**>@J^Ef}V?R)!XF5lecTey5nmv6_rHk^kn z$ef$Ep8IPFYpXDNA4L&Z%9Jsu)h?}?KOoGCY=OSc05g(MUJy&8NZl;)5U)XU+G;iiT91?nj}-o;nPaR+l!;ee@!b!W;*xc^ZmxH0d}n*5T-tNj z_V(J4=$Tu%<;S&WZPu(BPVKxat|!NNEy=ab+d<#$9_hS$I`&`4FVGHO$J6gAu3y9L z)8TmfsCtC@3q@UXCf`9nWn0~)$IyHsR+!5uMc^8pez$Y>sIvQdHa|Wa;@fBa_H5ay z$~&sVxqhqio5lZDRy`s0n`K{KcFf~9$MjyphGES(JQ;mPC?z%a%9guzPEt*39KXvh z)u+#&y-fwr#G*QmcT}pqgw{q{Rkp4Xn&t9NnZlm`Er#Zx*tP%rA*s_pn< ziVtpYwZUkqL~n~zw0rs$u0%+x>z=Va+18T>8V_F|>-uJQId~V-u~E18xXV4}_MULL z$KBqOF82hvhpsS1BgGt^O_G>EJK>03cdXbkV;C3Av11awOzV&y=T*F<;;UqfML9f^ z{Jn{GwW6UuJ=?xp_v8=Oc=MSx{-4@ZpS1aIcK*vcDgO|Y_})K2n#2db28m8|?|lty zscyhZ-}oBdA*mZIok?vN^P&yHg*Ek*V_*6No>2_R+P`vh7^UrqDumA%g$4APZ@sl; zd20<xYl+`uecz`^~Pe54%2JwOb7t zLS9Wy?D}rEVv~019<2MjCkl~#1Ebd7TKD}Qto#13v=2q7vpw8e_x%^G`+iy0&-OpD z;{SZlLRt@xNb5UaNLRjaL;aDdU-7=iOyziM+fL{g6fE?E`c07?Iuh2;Y=pa^^!!J= z?CNd)vA6Ep+Zu^0-1Rn7Z^LG_o|L!j$zC^M1JS=4tEU3(qje9?tdzniBabmb*983% z_~Wc0*BPLfvvgHq&K;I~H6WOdS`ea3N0Xxu0n6Kwl@RH7TKJbZ_M}=7|1uwit+khE z7_{3GTCM58r8f^TNamUL4RGVsF!rXqXO5c9JFdL&uvgVsqdu`iuUHteW`;*=CXV=s za4ehEIZ#a9Y5kg$upQ2I`NBG|h1SYCSfmD6W3t@xJA1jnn zdRjO)%UWP7@70=&_osZEU-?6OvHN+3F?#l}Ah&aljf#Y;&!1Oi9T|JPjC~}|II)+p zm)B!AQu7w$8Gf`Fw`DN~d2~hm?w$#~*-QK0{~ljiNR6uFg@v^9Jbi8jM{+dn1^n(=iF0zc@8sKbiMZuPmNVP2^iK`b8Z8gTVfYnr= zN2R@t9;@%8$9~o){3XAIFs%k#^iE3>TYoU7${I7Q!vFmNDab6&huo3k+9@O9%uLuV z0H4^RaRN?T^fxpk&czpu9z6TvLU;VXipDN^sT6PicjTipSMdYtBouu7+tMB{i7EBF zhhSy#K3mLR=OP)9JkB;FoL+sv6!~DRs{<&Z$6ip>Z7NpdTY+g*E=FYwnhUarrI{+H z+Czp(Dfd=*%G*PY$eMiiSn?g{yr$?O!w54em=`gtpGRooyZps}f+d-dWgd~e%fh!K zjha^xw2v0(Bksc*x&MgJII$GroyG7wS)z$^aXC2lssj}i_TY>NE^AG|a^tG#;^1h{ z-8v8tl8?& zJZK4XNq!a6ddamjE~IO&opD9~Pjl^R&7VgaACc1kBb@%vqhD$6yqeo=>erY9RPAif zlhueexb4k5ya7U@B#8!1PK39D&lM$B35(SUks>|9TojO*H8dW854mDMa2ytdstgm+ z5cH&~JTh?dT4QN8l%BI5*}%yHz02;5=0+s+H9O>EGAuEz>Q+g;jpa6^QHOQTVour- zZ_l`z!Pav$wepMtLwb?Rep|6oe__1*_U0VK;rA0~Q$|Sj6Yo4@l zYm|D!%bIRMEF+#PqH!$Bk5(J#Pg)v+mz5WUjl?no#*Bnt*oYtEj7^B!`KKlGQro}T zq;DeWpCn7IpC!wG_D{Q?diZk=j8xH9gtUL`QJ{PGWS4a}sKWZmDjPY&iLA1*D$0$a z&$%ol8LV@ix!!j_W(Kqhn3@LXbQzJ{ch-R{R@*2xBB`Oq3`96G;s@mkyf5}%{cLW+ zX<7`NO^lkdoyMQUcCsDnj0b(RMcqjvq_=q7x9>Azjx3!=i*z_F($To%g!P~4I7aFU z^IBVlb+(?VQLf+QL@UXOmOIGn#aAD*qSqZLnq8t#zJ`iy-8WH@7iBB4H9XQVqZU)# z0Qf^^pn}GmM%jGx4(p*K>W-C)fCxB2Z?TOLqTo{| z+aw-c#JT)66ZQHI!uuWj8y3FWxU-;LSU|6 z>Fh7)K>BgVxa%I>vh4$9+egWP&lD-Zu`b(Q)o#^Mw#LR22M=`{*$E&NtbS1>)2kj) z35zqT%ak(CEPIKK;#i~bfMg=s_L5Pr*fVwZk>(CD(Bp0GZZCV}nNy`Fjt9M(_UAF& z)T3Gz)GOwL{j@6R^}~CulR9J7jGv#{c?$KlT8uJkC(_Rme;$w6FskOPUt~KVG6#b2 z-PGdt4;;-2cE@3dKKurGA#MlBNXO4B9wRA6B|lEcIuzA+hELNxSA`D?KUY)TU5p6| z3FVww)rba!|6l9WiQ{P4N-9w`F7*RH3M+M;Syk$cwn=8l*Z;$E`zh{c%CWO$eT=3&LgS{EaEh#Ilt*si6uKm+}Lnkpe4jMCQZ_^&;E`w zZsbUgu+&mZgW^JQ79@v_wAk4h8&|&7llD=zidnqjS33~PmjPr!)D4$4K~1rk#FeRq z9!ri>JM3}W8UA#aJ}fRI$)xa;{p5I3a_TYG@S#n2M6KfZ2G&7-Df>>XK05i;;d3Iy zsuZ5_+jth}Uz9P?QZDs{EN}yZ_F1gDmYbgyyEsSbFh00r0v$FuuHdJr^Mvm)Bq^i4BrAaKo z!-!%39<~jB5WqWw90k`%dO zLT8Ea=!LfV(hGk<7h=iMV_!&T#w?u4QYT7;Cl(S&pWcf^dTkNwrfx0X)@EIC6ld*~ z2yAR%9RdAYian}zJhYmd`oQw}FRfA>gASW^`tRsm?Aghh5u>>;Vy;c20_gCp#x0wuzln>mv>eLELF{7+GRKKlx5?#0ng*7FY9Z zapjosG%fc6t1@(oj`>pUD?$=yYqjQ+J~gS8hS>Yz;AkwI631$;7y;je)#=&--E;@%{%Yp*`}ZOEt)rW#8+*->E9za zV*LNZo63DBjM)FG@A{X0=as`#%jMkQh$hh{}~sQPDyi~lIZbA zA*WaMry7FUauplWp8XV?z#h*CvV+v?`t5sA;?jf*X8kx2=vg~_jyy`+C@&cAAKd%t zeL#g(P@G|CxZj_Snr&OIl|lWV1|lPR`%1H2Q7_;ZDIS-3x7n zXE7p3jpm#&n8U4SN6+QX{_&mq&7DcTL;61ZOUNbE2BKhIDa8rC@q2vk3ZK&e3O0irmW6=i@Q2;O<~EU=9Y0p6w`0XUy4>&LhnIi z@=<@5{#&h~w2Sd#nNBqFU8c_Q{0lFexR288lW}xM!+wF9obTmK!#fOKkGUAMQqvGvUhE@mllo?))rRwk`S?4Hk1)m8Sqi4^zU}dIE9z{o}6_O)lBpcfal{lf2gn3Uu33Z_u*}|UL zBa$Ik$JBwA1l~({wQ$ti_GXF5r{3}@w2cpEEjP0)bhIX`$Ck%e4j<$-PH$nLQ@2uE;BU$H*=~lmzq;+3Wt~IwZ^q zz927Il9%k(Ll{*ijLJYGOcV)%IXARd(Pt2D@Co3~*wA*(C;71t!j?;>A6Jt1;-zxA z-d2;UF>t;Q?MHq(kF?Dl>|{d;2C-#GClMwDbD0_TkYsG z2adJZgHrs)2Nh8n(>F@+@k$qlt?bzAB*~|aa_WJnalJQt?4>gOAqB?QwRv`l;c2~VG!Hz_+|or&`HZkS@810Y&(9RQ*6R9< zJDv$jvXJY)Sj;YYjFQECa=da}E625VTx-X*A=kcR#T%>L=V(I&y~~2=!E;evThU|d z>Z>Q+!l=1<@|b(Z`QQ=yA9}i>_cQiKmM2eb;P4{7sDj5WNlgE$p7GJW=^ySbAK&|N zn=f!1maMr;bs~E!@#qu6lI@D+lU1>iBJFfMePf%29wZNuAvMnSCf5nR75UO8?rKXX z)hR1;Q>orjH_0eC)9zM>* z!x(UidZNhaQ)0fpTQ8}7=yaSGtaWc=6I4>td#SBP=Max{c#gOe3dCPUMv?4UJDiuc z*&`-3Ss9bSmeV_#B<6_`Ag#aRT|Ms!&$-5wjUGAf_t0nV=}JF&ad<5;5}qh)vU>5p^12*37IXf z4ubRNmj>vV4wy=b8Z2|olN!#qF{ahemKc^3hz6&T_|uJ-O!gt%@)F8NU@i1&ArQ*7 z*LtZUU)zhHl5B+Uwa$g3BXwWxZaq0GgQ<@ygY7yzj;>Jtp`A+d)3330Dy&Mno3+P@ zZZKOu>NOoLJYXAeJJ09eqwH|BIqgD1*xNi1+u)p3ZfPO=9p!jyJ9^)aYYWfolbKF} zNAq9{Bh)Vkhj2bEanqQkX|kN1Z&Ci1&3VP#oc3luNgPs0JpEaI@eMH;NNI8?H zlk8LA)P?hWS{vX~w~_vK{1z?u(5GeN$7~IS_=bd*7}L_jD$cg6Jc*tpQiUv%qX>o+H%2z){Ukq5V^XD;>t`Zo7RG}ddoz|nd0mu z&PsB`fw)ftE2DKg&z-ukhX0P|_Y`xWzMFTv==ix(!d?OBTK$K{Z$$$9VFsR}Hl8co zF|V>E%NeVIyqeV@ZkIGW%wX#&)QB)hwpIi>0@6|4z_2H%pT&=8F=Q};-ZCrJJrBUALV03CQvk2of6bLx57adG4EZs!Z0^#h$t-gk@ z2xGzgL5_0hK*lPBFZus}(w9*N-u2|a$eiybp&p(kp(RUWtlE8+BV!s|QOW2Rlf2Z? zMi4^5iQVc)UXbuO#^b>BrJ{6fOCnECx%0nJevT%erg?>dwn@3{4-z?5rD_KnCCDt&`HkH1?)+HNIFnYxfo6c|Hs2Z9z<1;6@g4qIzD)X@w zgX@d3#!0aSVx@4g*EPqPbHPYgqUc!Gy5V$;h)d&Jk3Aw3L&Tbn3FFH;`qp#Nh$aTl z7R}((Ngk6~FUDd$+m_JPKLQMYq`0%qPObRQ%5uMyX zYJ?Z@hxqr(C%I(OY`JK`EniF_U3PtIQrmvVSYFk`ym?p6cuD^rt&uJW9tvpruFh?I z_D#NSmT17`5n#M#c-p#!-AwT!Uc7Xtl|t5wEpR|T_BpToMMb<@D__DO0-E$?*n@sha!_e8eOo|U)_)#D`H(VdY1yjtm5 z(z`|gJ5YZ8Z1%s1KwkM5*9-$#ha+AeRF3|0ygofcbCNf^4%-5OIQkwr4=rwy6wfvj zmJ%_QDk@5-nu5iSF+Oq23dH<(x(_qOfF)YNW4Bl2W&ACm0b(Ick%X6NV8mgu(zJ-|Y zeYlBg#~%7OoWP){sx%wuon5tzl>-prNVhUP=(r)q6pE^FtSJlkXLJCX+0vLf_Iv&N zv>HC!8o6T2H{VP-e(T+tv$Hs>&r&2$M9X;u#-u@K8gNffAV!!lT12LW!nqZ;TlXgdj>i@H9p$d9%?_d(8pczNOs-Ga{j zd&%u%zYykiO58nSwvK+WqCkkJG_VX?NR%Qu?g2(J>inEzmxL8qr`xb6t9L>d&MRtU=gN~ z+0H#i{(|}5csI=RLtLC!#oouVc!SyE%LfZ%1oPMr{Fl|b6P`)qomdH1s|Rb+b4?>We^!(fK4--H97Jb_tz6(B$!Wu{ zJg7$O?us!L=o`?bh9eAB0Yn$I1a6YU_?NskCvCC6@8e$h`(FGuyUrag2PY^1py%n# zJ_)M)u<5d#DU35X#4pBriYH4lkg{LZ`Iy2=KV;Aq;cd$?q{6X^VNpU+r&b zbX=$dh7F7vVFDcnQpAWf3hm7pe?z1H)RVsVglQCd(SFm9KlbE0Cn(UtszYCLm|;L~ z;9Ed>%m1P$8dY&Y>sVE$&e%;l^IenZZU1nNYAS6_Cw9ocSnGM2VH^j}DyDkEdr=_& zmyun^#j-HRtRdzu_tLq4@1^!ny#)CmdWxmDv2FlHK)Js`j@BSlY`{K8Pb)K{`Ohg* zp(-9a?2myw9N!u+^lSWvBJXqukcQpT9lUen6AYc7BI0kXlvB-Jvw$~A&ebPTK#27G z7_;?0VguA$|5sW)&r7%qP61p63`>De_TOn$DtyI_8wW(lLI$1-{0AdzS=Yyd<2TZl z^&D1*^RQ~t|I=_PoZv=|)pUuSUo?yhz#8kn7d8w*T=+{I^IrWCI+;f2F-)uGrn-(qTx3>l zj0Ch=8DJN~V(u#lZl=46$v}2uoP-6fX@CkLCjn2 zxvpPM9Hk2k0P(ppA@dWG*Bl2DEaUzK)`8F@%{mZAe_@2pfVoO26^rhMTC%D*Yr!tm zSh}W2qg_a0g#T|VM=U?$|J!v-N?!`~ z(LMGN-d{5PH46`$Y9+$>&Kj*)Df6aA>+4!1XPpCji&qc2q`tB|CwC;(JdnroqhB<&EN`g{UE&wNEWxNET*v6o0| zoSk5~ZlK&v?$t${Ll&<*>oHI)Em0^Qq&$YQjrwaE+6nB!?hgF9x zZ5WBDt*j{9HOm->PBdJ|`ZZVX3Xd>Q)DmU?alD7*WSl)NRHs!Z#t2+^b`+uZo;sac zSR6)O<{?Su47T29wwxPy(pt7_Ro-D(a9ekJ)Ow4&1Ma?ghv8bwOM}~Wa8+z#t$*e6 zN))ygZO>ii=*Thoxv!i(`uIFsF{ti2s#3>VZ*}QkM77IEJy)Mk{>+DkGr+BJO5BiT zEm5*t^$*-hQG_Gs<~ynE8XsnuDb!R#V~33$S6rP!7vUCHw{~_C+y*20(G(?MmE_#P z`^r9F3!mi7*;9EgZ$0btTeMtSmYD<9V2i5LAC8zTG+ZO|iE0UZ9*!h`87*>9II+%% zipyy0p_jK!FL$DsYmU^s($S8TffMqGl!5O{WUWd({)lsWaFY~{yvsyY;gF8WAAz_u zl=;b3XvpKwmO{hvbvS{{4S1yWj5#CEV4|WX%(IN-g2*1T4Qn&=UH@%~Gk*W3 z#p}Z3r3$%Rr!`^S42p6yG^^QD_7z%`=t(~ZabOrn>nukc6a&{fB3NLc?mjwr9q&mR z6Mwc3Bk|2&d*l>TmQ8h3pnW~226?zNto{Xau1f<=-XKka#%4+1MLgxwVlldu6fo1r z7ojYWUYE>*xYt-YVXe4zr(IS#sd1Qqrdu$xO#A(ap|9;1pZzha%=UAHJzDY)&ukL3 zNK}48Ghae7JhSu2W?+^_LV5BFEqn*gZ#5_V;IFK|DmT@?Wzc29-DQs%M#T|22<30n z-mFWGkvvQ4S>ecK;v)RkRS)evS?E(y`#oyi6Ba@rC6ke?s^WTpE#I=##cLH9yoX&NXll ztQ~Z6LZQddVJ{&@3;iz93BVvd7D=%eg<=+$P1o`>*jjP7)gsa9PIr``!U{0rGB|;xj)lk30 z=ML`Rs0YKm8U_D8&8tzcgtn?|OMZDQc12!*-qN!D)=C()-pVKwgre+}#MUZ1{XG&6 zY*tG-_LmX7*fl9+7;SpKmv>;v+eu_IXQg30pD`c~jq&}Hh$O=I+8&{LVZJ&@-p|?% z$zYxG0(2Z%W-IlvbevOTS-D5Yneo8e9<`qhBM3tf;(;*+Et<4rqn(I8UME52+}jBc z7(c@C?L#j9r&@%2qeXzya?v8_S_r#Gd($H9MQ8F4I#c{fXUg-`naZ*ntPBK}=Pc7w zP^TpVwfxi{ZAr&!X2#OfQDSD`N@Kf>%=%&HaX06?&POxwen|Bqt}Y9C`WG#;(={cN0tncoQi^M_4BKgMvWHZy|BSzweDOZ01;>N{-#+b?$6$uANXdqrB^_1_kL<6+kq z{~5&qL@aoVot~dxi8Y5n zS9IUw9Ny02uvuntSp8}i*%HLF*ww39#2mtiVVgd;TED(`2ilU~%{y0H!%sPF^FG{f zVgu4c?3RJ242Y!Y3#UjP*w2A!m-aVD`ecq^`Dq{1Y*F7vU7o(vcBs3`$9#{}Ud;Ez zNKa52ZA}r=#=bq@z=hw=_sq*qIT3sBobOqFG2iXe`E~*6KlFF=ely>b{J^u=yZNr| zm~V-zVvhozbZG9tzjf~C9@*b#yTmFUCnm=^pJ%I_kCYut=cppA1vxM6xu)8y$my zB)$T?b4v6yiiRgmBSPO_JmFi_wn?27K_iL^mm=fclKF)0wiRg(!Iom4tuFCrz7e8SHIges)8xj6ZUI4 z5EjMf_?S_?&^g={+2dk8K57@9h=zxi`uHt9;Uh9G+`5{c@C(i9_PCLM3dbeUJeiS7?4o_L zYBjwuvRQj355qHG%p6TXCnJT3JHxVN!isrXuN)=qbYJ;kR2*{Cp42a9^dUYPbIll` z*J?WZO6-}X%X|D;L^PvtKE!e_Z0n=0*XOf9k?rsO|C%ak-Fmz&*?+oz^mxOy`74jN zfA8_urJr7%tqK4}=RZeJZ*>5UsPkv!|G!0|)4l|O*xN@t8TyUh*vZbE-c?J=vXo90 zDxPD9^;x?DDBkR`!zW6sVCM&S9oL#pNByQxV>`kdN-r)vQF=L0bpMUg^G}qX`kUAeLv|FN zuN=pUng9x^_c1!4D7$M^2VA-2f9z2m!sq@WszY|xO(cabQEmN;j~N!%cn%FJ={24M ztEG^%wPM~hdsjaSkzn7|!{RpntJ!(1Sh~%Ty5?cwd;OdDeo|NGY<-JP zzx(yU`=lG^jp^pvV*~|Z3rS0?WpEy&Zj8RepHn|S$J2Jw;wHaiF6i=J?3i7S>=#O+ znsq~jIlMbu^4-`{%bD2lo89YGrI)rN;t|dFN4&NdGk^$TY&C`}-8@=MH$OugQkUg% zjJ2FuXZU^kM<3Oz$a1dw1n+GJUpXz**j8thXZqw;W}NWQOE!b&ab*7qh%- zkNwjukN7yt=6;rk&BrVcRbS0=oB!P`&+#v_JkvqXFXs}GrSEgBBjUQcXlzk1jyPO# zZ8|j#{C{#5q=j749JADtU;v2hY34K?Q^aP46ZNAU>#nG12Pvru3p64 z)}8oydcT4k7Qay(SUn;*d-f~i8@7{Vd_O+But)c6r0soUJf2ZgTSS+BHPc32hSAZF z0ZhS8=W-r;qI15)>az_N2yMU??`2dngeKjM)Vf!N5sH-Sg2j@}7^&p@S|w*@`-|Lm zbC=srGX}IZVIU<^99PPm9A&r$ zLORfJ=X`v;^OBE`)paSSJ;Q;EQNqlT?rL!}a=Nvgt7p@m&oWLrvM^`K)ha6@@{N*; zfcS}Ur&gRM$R2a!pq27lFpj}gOeMn5r=yK&U$tR|)J5uMXcT1$5k;P}l{C7<8Se3U zWUES_DnV*puNYC`P1H&{Y8ocyzz4dE%%a3&X8juD)0#UZ#D*lGevflW7@zST;}c%l z7t$T{z?~SMSn7-<;8%UMcYQ4w*<#K7Q(x2B*Ay3u!kd1ZIktYAHaW+BlGj?5DHSd8 zx1x6R1eV&w4*t?+qsTulHXG3c1#JMmvBbd^j*fNjada}}UPk+A)nbsf9pj+F8@%NF z`c*y0dVZU5FU0A=x<_!|%yfX~M&?R@;*81x>uL-QifaCU-gkft$cd>~n?F z5z#^kv6gq*XZA*T&aWW`neH&7nBXpdU^hLXbfza6A8>GcwNBFkiRR z-$YqNYGndVd(!`XtKq&?%x)iBTd!-COO5o^o^vmK1S{i~?)<(Ku2C+%J3qq00w$S_ zqgP3XUf0OlQO|pmf6ExJa3zBT{+>`?{LV#p|(g@f$r^voA^ z{sv8vlkv~%`FCAvVe)dEEhDbu$gxr(SAP5!ib1lh%dd=ot~#T<#2=))wE@~s>XC1L zOBbcLC&|rTy5sloYn%};M zq81%V%xN5T6vDyKP=r(p0{^7tvp+}?soHv@>R)feOIgWSTUCzd$_Mx zCEr47GyD)=!F2R<9L90qZ(>AtP5WJp$hwaz`Chzn;)Q=i$dfta*btTRjg(v8j?9{( zE}1olre}_b0sA9N{)$Tq64Q_`VepkhOSU?Zp}dZ*+z=u^cu`IW21{zSN(n zgZO1+Z!{*Ih}B%GkqP?#iH&zWlUUxozWcZDdpW{tA4Uk*nmQvG_V@pOyg&FG4~o32 z+O=CzPF^a~Eg}#^)~;Su5PYzH)oG~W`8TWaNMDw{i*v{=YZ7MjN~&=9Mlc33vh22T z$eMQR9*ym&5j77!V3^~PU7*JBZx~TKw!f;?-datr5m>S_-{L&dJ#x-d2F?+KwKPBR z($lXWL}BfGhT`QJRjqW6a6`?CZ$vYNY_=jhK^5=RBcmrg67ah{QqB{CYF`?|9qOCp>;F1 zvfyZf;Ij9ACwJF}~XLC{^xN(k|9e&#hR_y=m)e&A!(*_$t;9qN~l8T7u;1 z1Zmgw+1eOczvo^?Eg< zTRC|rNGC)5*g$3lSPfrwQ?A1Hn7uQmcC)PE*jh?1L*?s;Td3YuX`!xmTdi0?Z$KG;y=qwn6u=rq3#(c<_jY}lG7 zd(*9vs{@8t_272RkhK_a7T9UI1+(G=rUQoC6wjHVJQ)keBurxAcmO@kgOA>rCiFR08i!;MABSuH_u!L|@RyBR{7_$mASemY3T9x3~HXXf0Ku{xPlc$>{W3c4X zsfBl_^W8T#0lEHctB@#Gx`(6rT3INT#H%Qif7Kh&{?QWgtM{V3*Uxw1_l&VogR4NT z3Y=Jn^!aJ5+nR1FRO0EQ5ucgB>p)5~?hzV{1 zcoC{#ErQepr$V8;X9P%Ba#rCR?XtEm``5}{`Il7>zQ(K-kQP@RXhI&Kd2SeT3?H zdycWZO3a8kp(@*_zeb`<(c*9YQM6Dr$2Bjqw9d(^;b zgA{2L4hGR+LA0|H>$cGfaC;C;^q}fPE1&99T5%5uwS?xI-mM*1N3n!B8hj`G}# zdfmXSF^?Ui_kjd0Bg(G&3!l;4`(8fl`(hRM*8l6XOq=&~$^J3+T$tq#gNDRT?FQ9b zgn#3+wRP`9d*}mFywUwYI5vo1_JEeL_Rjm!P<`^(zk8u2Xa_jts8u+Q-M#opD9W8N zm~e229!5Emj&iq={_y^6P7n1z@GU|Mr|91CjI8|sWA96PB}tO={!5+v;QP`yg5W^_ zPZVzg(eQQHP)&EEs#>BjnEx(Y++)d%T;9v9S0gBg>{pqQ5#gJ;xvif~O`lJT^L<;6 z_bvH!cKqKG{~tT}a^021!#pfO?)H5YSs#WS_M^@|Ux_)>1}; z$jaBO5@<^IoOZqol&u3Olc3OoPSh~)qt%?6D=?Sdf#}&Q)+B2nW5XHmf>#QzYLHJ9 z#jA!zgU2X75ViQ+)K3_Lyk`v5o_)ME-!sUDIk?^%P+MpLF--{QUSU2KNQ$LeRX{%K z4%6L1qXpd)W-WG+1@7yLQF~92^Zx%y&iEhy^-H7|O=P_Dj3tgg{sI>6W9ZL)o!QLI+ zA(uNOoefDX`qlrRaZXdKf|E0xO0^W{Emnz^bgy_>PY-POcWJD5u>3s^%)4O5_fZpN zL_@i4me{HMII0}|p!g{A3OYZlF~H~_kCFXoIc?lfvRLlA$>tyl?+K8n;wd0vQuIe0h5aZEIE zKeBl5vL>Cc1iYcCjctj&H}>8$5qmtm^Gm$g(3($T#I{jVlmYBc`+dABA9cR7WN{v! zruBY=`_ZwVwR8SYCG@G9`f7bb{s`wrwQv^L;+hP;dEa7!{fAL9K>i(FU_k-(1W??v z&amr1NNBa7#|t{ZCm8b6hu?$pi)ucUhJ$M`rJ_{Rj1tO&Qr!|E994v2D6xBxK1|CM zap#Q5!X{})cRuOw&EyoJl2QoPW&c*+$%hPIgVmV)CYe7dN9}8gfqv z#uk-wB6+}vnD1&f#mX?9cL-26mlG1P*52BnxNgyz9!Axp2Q6sX%@(YG#M6v_Q zQP2239vKE2^`>%TH&|Wt#I}a30#f0@)$8pHOE1=Bl;;+Rle=e4rylawt5PRLT(xT+ zwOrrU@;mtc+*4-If#|Jo`S*Q&4+nkM7yEu{w_$$@wk?Jx;k(MRC)I$%A@pC4E&3u; zY@*yshHza zPh-r2++u-pj^P_TkBHUnwiaIu-(C5DM^@%*0r|;D;M@_@ty2ePouRWyTX?Jk%Z4x7 zH4q5}%${;dC4+U$TXh3DLlj2tu3Mf$*X_zfcB8%OHz9Ow_k7<=bR=Cn^g~^HcW~!a ze8dleTXsBoL2pqn;l*PdlD}@zPwHvDJprH3jHd9)9j(l(=XTAHBl zcWqARgd$(xr;otrXjbq4GuC?|;4uocB$OW3#h)W3+6vsgiDaV9T>-c65j3CVgEmD1 zlkK%C16&z|on)HTK35%5OAW+CuT#1tC32(z?6%qq2%Y&+9sb=Eu5MHKb)US{zMcBy z2`R^{sN;qBkJd*VlXx#4T_zkmqmsLykF2?sgl=mL<91}`9V?mvIkCB_4MsTd&WIesf=k;+1auMcgvmNYA z%IAI7>#?2erdR#Qu0|1jBM<&9bZ028@JcL*G%Y_f76c|Jp7-+JNGNDR?c^dWNk3u< z@OmT^@6*e%P;7}N>u$2TiE3>@!=h*=g(g%tz~P`Z4P)`B$m@=Hj>w0bCfxEF_z#>+{?WGd{zU0d(HQIH)T8}QVy15Pamk~ z-%lU<27PFzkB~wAG_{&cC$S3IrP{hPIfR%?Dk7lqMg?cO(IDW-T)e{6(E#Tkq9DDM zKF-G(_xgd0?G58JH^w=l0=qUHG%{0r)wMfB4~wFL{-kxa71hj)kzKWeIu>2Q7+HrH z_&&v8d=gI>rx$5APEY&)uEvm-+!usMmrkD=R0202)8scY6& zD2#gnDG^jDbetApT)DWO7bQ4&$)!lcYgQ0U7p4=E&{(VZu{ID8!fKEoZv)v|GZ60K zM_Dr@YI4uAX2_xO1=HVsKJL6BG9aeOnK#5f>J1q_$7%0-v(3fx=F>93>7BkT zvA2u1BPlQ8e8t9f#O%&168xNR`z=l!YyZ>Ux-;S;QLBAcMMd z)ICBU<$43sb8q_*Av0zZJjD`b17Gc6BVAR0e{Ka_tuO3$Bn4$jPV@ z42@jld;tgScAl89x)&uNY}6?6f!)FiN4MAyW#D&GXCh$zHa3SIw7d(tGOJ+$+& zV!EwSN!37_GK^-h;XPFCbJXC`$cZ?+Ib+CE1s$q`e50yBFrQG6CxR5ytS-uV5GG-t zd5}Rg+z(6>Ue!xzJ^H%FdEoomhCcRYb875?lNg3A>LH;7?2tUSy~AoxpiAcfIw+hp zt?8CPAB|Xq5wV#~G@$AivQ}a!VUMVP1IH|-XJg&9-eE4lt=>HzReWu9K2lA*1eDe= z84Yx3XKIASP+r2*+KUd$6EF*{12s2QVAc(S^?41`e`Rzi(cLk+M4*-x}K)KI{c=#gwaAnug)Q(Mo3(2zuzbTS-XN6e=&4`C_F;tC|bbG>KvFF$!h&MYa=ia)W zZ_b7jne(sV6ING;zx})x^SOopmJQ`Ty9x4tAd|jgES=_Eo^W68pLjgNb8UBh=fgYj z;GGZitb=zx9A&ndbJp~g^rOZIwIMgHzLTOhZ^C2m!zhY9;xHb$owJAiS&IExh`K>C z5z%dPhZtBl$8miW)QVlBTyPer?^Thlm*a7%eg7R=ALDwS7Z8ht`Pa5TX}U@36mz`j67p=0O*5z)Xp8*7016SPbhl~MP%m4Q}V zw(mQeA2FAl0nG74*JiOJY)rRBs|o}gt4hX$6zfGspdD|r)lu6jL5l*Cb*5znf|c

    _v!6=QV(d8dR_nnAdkEK;cob+-!oSK=3=5D~?L?aL!`n#;Wsz zP{B8q@2CQzJj3JC=zIxAQVnfKXg$F&wq!J;eg;v}sEk5wo$IFyHs0tx)>JZh+zr4&)#q^TGj?DOQUDE{60sQxy9Y#e#Wj8eV)yKDdN4QR zD4t|o7q_qlmgm`)JX?E?EqP+rs`a~=7TnWb`FH!BmUJ|?LAC^vUXU$C%?q-nxF=$R z`?;xffmK0A?J^;{9W@sT3)`!SLOD~IVy8re6&m2A0Q?)Y{QmviYU z@?o~TAOgrhsnwUCa9mq>Ji*w@w`Pku>R4s7U*(Ahdll=MW{A8oR5zQw6X-YgVdgRr zX2zrdi#1BAiji4RS*h3BjT*?*c7($xx_K8x3M<0v#Aqc#QtdUwkVC@%+sw+T{9Fh- z5>Z?Ydus5MP9VDq8M&UUn_ND|kYWH0H-dOt%DV+>%!X%=KFnVpwQ5aB14-6YuKOMa zl}6Nac}DP_BabIgE4&BKRLK|@Tm_2mwvuh;A*|mVRmR0{QSyEW;|f+>M9x05^cr2~ zN@HC2bKs(4VWv@w7=MY3`)UX`iE&PW?m;#HJ-bw2eFU-78`og(fR+t>v9_2bBFe(E z$)cU`;J? zg;b3Mp#%{wMGno>T7Z&(cl6RVNZr0+09*70xM$NUqNz0mQ*+OE;^j)>nV{b+2({4Q zK&X8ia_d$Wm8wTt2;%o*pl?c(K&Ou^jmk1HPeE6~s1m-K2AZXYQRSu?<5Et1R2M2b zbjH1UTm>b!v^1`YHZVDpZ^%%F>`Q1#de$xEYhIqn!-8WG&LW-0^)n1d@~R8VRcBet zwEb$IDZE_Sp7YoT}FugT~0 zE@epGi$kI&jbAR+&yhde^%iHYyyXCk)l&^5uBLLfkMgC+tbM%MmHV*Dr(Y35IJZY& z%;_OAY%NqXRIGiv{_bkG@7_}As3EHwjj!jWRxHU;vmcVH9-a3@^ZuXnqJe`CTnj5E z4xK?nx*<_q?BzU>6Gn_)yel5|!I;ZyGw745jN-jEZRQLmC#rjy=(7v!EUi^CrZkC( z^Z~J6QNFyg;_9HzFv-{`VL8rN#QB{v1pX??(kMv7C63~ZTH_dYdmhjBiPx!%+>B=G zrx>9uB1^5et4bKgbUed3ofa^xlm$W{PD3Ecou&Og(L;^9nCpl%KPPwU+t^neQ4&mK(fKwP67osPtptjZfsBzy-21ccut z9`^AtR`1?Fb&b0`)}|U10ltkG{lN!DO|h&}jv9XX62x4~xfg*5ghmeZnsK zAWZ}U(Py;P{T%u31ywET zVX2aJP|HOkmmhUp+^oEQ$tt|?1!|)W6mEoCzc_9n$PmBBDKt+S_E<=YR}r8bE)~P| z%A*3?;pt?UXQPhGY3g+iQ=35a7azhZ=We*4SNfFu?M_{M(^9txW|`z8XQtnNe%|&x ziZxEqKaguO&IQBq;f|1ql$^0lpj~MGWbGUk*H6Jd2hfJSJ?H6&J8`OiEz;r8@)v)W zoBk|Zi3j{y=?;IEyW!7rr~WL-)-CpD^_@QpZL81sXpwhByYVfoIyqK&-P;x5kqT2F zS^pP9)5m}rl}5D?DQ1lpn%t&Y*YBgMhr)_4*`#rG)DTh8CfG4*TpjibpwEQ1>v45d zLebfSgwEAi1fpn;t0klOHmIKHX$xj1;_Mtzu@!nWpyrm=?*4mCW3xk{Phg)e1^$TFClIzjI~0 zRMyDE+pCCcM|BOoCA*>Q#B(HLZwBJnV@2hP0)s)RQ-5W9qxD0BQkMO!n4gVjH{r}6 zi`hoKq9)AO84-7S5U3KVpx$(hFHX)C9ALJs=AcrKxtbUi@D7lBZOT5w%qkZ#Fwv9- zdaIK)rr@{}~?noy}=!@3ZiY?xIW?Wo!q<@qRY&b4el zz3sU(u7W*t=oKgzY|o@y+g8qKn%yOY*-Z(nNgfUd#O4*a%5 zd%VA9Lww&lV9?$>pVa41vgMX|`uQ_v*6}^lW$BI^y6n>OfiAnQ%sT&MRlc&@FGnwg zH4X*$@T`ozi}~Odtd&&1-c+?{9%N&_>H+3w39kbLX!I|;Dk39glWxern@WG_v!>6Q z>Z{-0HQsFDtGAE!>~;xbz;E=rnIqx+Y;$7*=I9*`T3omvEI);GBaO_&PZSK zQo)tuIK&#y)>UB3qgnJVuArJ_y=c=Mr|Qs#sN!8?3n*1R9r5x!7i_u8#Dn~y6*z2= z0^`9-h)@PU=bC+yTS8=2QR1pamf9AK&8ds;e(&S=jjmoLy)Ej<{ypa$oVON7h`&y( z^sy2k%O4}3lRe0g4oA7$@a}_qC|H2cq=^PwSLuYX+Vl0*m>RO!;ED2+C0uy2v*fls zsppddZMx=hn=4rZHx}3DoD&@Nb|Mj=+;)LWsGD2@cLLg%j&>SzLVUA1eKUEl@8S{g zipX|@LTJbO@}9;-kNagVMpw9W?xl<89?R)O7oKAhh=2P!^BaL-O*9bbNX7+gcA}s1 zc{8mdQm)aNz5}=Gpo4;5YG6)vQpg4a5E>R4Hm-Yh3#-G7cae0pKcPooBUOi$ZH?dy zyAwzZs~es}LLQz)oArVF9NAQMbHtH77-dM>49I+e^4v7qB@|i9X4cz5EXVWv$g=uz zPq8I^rKQz!N~f+Gy4i?999n>)zN7cLgLaYGzT^;|R?j%ECEAPLh8hXX4pr|`j1CRcZU9i5$`4iJ9rOmaJic!grWR*l(4H^<~huSQgwMVsKLFCKE)%{|P#-OjV7yJAMP9KD%c ztoK4PCfgISy7E%}T<+VYv8stTG@=A~#QJQ+c0)6Q#>+Zw5`9lIgF*zYKp63a)EBC? zNHgN?MY>9q7fNeD;|*iHiN>3>44Gm`Cq0Oh)pr#4rsK3o#8wY?gqYFgXQSJ$W^(2B zjv)G1qn{3_*5NL-xJ%8^F6G%}e((ewrENvOc?xAg8HA3;(D@v-k#kafK+vNzA1v=E z&9&=m*27tSJYsHa(n zeNVTZiAJ>mYo@4I0?4LX%_zfT#4Xkk>{L0h(NlTE01e7QFNYB$W*4o@6l1&PHuQVq zC~(**aokDB)Nb>>vD+d>oierHIKp^0&t;w#)0`~*mWFIQ_BHHswS79R?L{+pelB|c z65^(1zikj<{zmwv!LzU?@GaaU zEgaX3ydwJ)#(CxnDOS8=H0Flv<2|f~Yu>=;h9iRC?R~Njp6g^GMxG%D&rti5J%~Hx zPmXq#*JOxeYnMK^c8_W@T=AUyXRq{cV#A6BW$gTUee?O}&&1&zT+|WR;(jTD7;Ua3 z-B(X&Y@#xxDYcxWZXp_I&0&g za_e!8Se)gi(~L%&cnJ4K*vQ%2X7h5&bDTKGN{$FtC8q6*c2%MCo8^NRHT#vAV({0I zqcU?RS_tFa?B9}{c}nALzRs0Ke*kf0;2(>mdYww)-a=JWMay;Zp$y*%e#c)-8>kU; zw9{wO(Q7i>>?F%j#ua|^vq}r+-ATj<7^rkWiCGr5VJtPZJzEo)CK%NS-!m;S>`$3; zl5|+1@fp4qs=UUt+{wR3C~jzFj82XUGjk+_(3okBHoe7B;g|xZN23n~r;|oEW0bkx ziP2-7mgrebu!Yt+YX~|#bPitEuEk<=z8w3p#_C+MQjar>uG(AAvcHFXo!o25mOhI4 z>$L{{SFpAq-9?+>^fmTgs4h#HT;W@?Ldc7#=1&!lTlQ~y-t%n#!IR0RTYNgY)oyqIx(T=iv~_@D{0 zub1V3MQhwf5MW%Ac8UL0j=pKav{X8uc|y$26M~gq^33biTsNj+I5=rkQ_5h?l6W@z zFYxdk&ubC!sj8PsEsA1CafjNie*=FhZONTHusWKo8?Um?HtA zx@V92c6Ou=BkI#kDNM7R3jeiP1175NJzVvpFix{ZFF)0eFcafZ&}^l4)LQljZxWlm zO|k^-q4B0hG#v5YH3>+R})_HO9C?^c#Y#8--TBf9-3Xq*S z9rh%^RtuPm0eixC*HbMwJqOogJc*wZN071)|0T4!;{S4Qu{w>NXnb6!$7!nli*u$o z8XWPZ83l*%g!~C(GKj;QAu(vKiHtVH5o5%8%ftSOJwf3|wpuVhuWoqi@UDS!u+dBLD(O3B=(c3>qrX(mMGS60G7@X(7#}xn>xOX) zNP4i_oNjzCPz3Tel97QjJR>RM@e2CPf@p#9d@GHRCg&-NK#=br`=Qo;uosYN0Re

    N{W9DyYwg^FW82bkMtCUM)>KlK3H4;yJvRB8GKc~# zAeax=)BPj`2!w-ViLi&H=SBy@hr5XEoM9xpI;DQT5&xc)8UtBr#t7saMu2j`8dc+M8z-YqdY+8Dx{Iw#NN_l^9QQ!yB#*V{ z8+KFKNsb*k8|SuD+4Pz16am=Z63;J2JpUFy>&|%oll2!{rNw3u4_?4w6MHC8bnLz4nxIG_O4%oznh&!(2Mu5563OA!YgYa>Gp&NXF- zGY`sgY8>!-xDIF^7eC)O0^GICFYs7c^O=gG2 zT5NmW;6&0_N0L7AML2VMtxa&8sTIuGFz7SF8SgV+HzABHEu6MmIll=+i;<6|bMR_h z)q3VwQNdKlm@rz6d@Li16gX#Q&^cqmP>oVO&M?*ZYP2;(kdXLPKq~+t#lXbGl1H9b zL-b``t5dD&fgVHrd56?ek98Klj(Mw;QK`gXok!#l^t*P`7ISLhxttNd#WKBy@baeq zVsUcht!>+D)|@owhL$PItoa^$Opw}+kWFU0BeTbFtqjciS~Gd(Nw3T{D{FZ46w6kK zskCJL$ZmESKa#P+c;9nu!)7P5M0cqFp^P^*0_4H;ub}eH6YWmYd=H7o3XbAqjd02IzL7ITajbFH6B&1knL9+DW;u~;)=0r!8}G`M(`kuw z9rU4&>GA*@#q^azj}Vux;~m}D1)N2=B5hp9ylje#z=5bze7zaT9p${4aPZRZPU=LO{QY`hfFn}8DS5jy93pu3VPyg za9t_HFs8F|hi;KHY5aG3zk$k%F{+D)un)!#Kh2T4${9BN#2u}byR=rC{M&P_@OxP~ zDx(p^Lo8_2^N#K5w<>r{+Oq6P*`O3MHjxORA&He+uIO^8Z3ITgFo=K;Zzc($_Q`#@ z2J>6{6gDRV*x|eKnc-8Ta$?|q89}xkLQ4(m4VmGr zGmKc@U2Zst`u8H!)OK%mx$V6dcaZDllJ99fw;6xx6ra$Vb#4kGL&ztb-)dCvot4y$ zRU3pojK)91(7Jr4v)2dsud$-)P##ArI_8jYa<~F|oNUkJ@W)o|u2O&r))jU>Xl7O? zn6_q%tf}By!2I?kTn$--=7HgWa%yUkKI&|8wU=uLY%IXWl64i+Ar36Spq1<`z$4O9 z4f`)WeZ>wtekc2{iE_jr7{A(o^|1fSi}qjcA?`(bj|)+b*n;t%$Tnm`SEDF@j`3gm zwyiof-pr9BuurdAiGf+2TUgnHyI5Ft+ggeB^2_ARSZl(EB@e=O#yj?I>ScFXiPdE* z@fgD;E8M+fcV{($pk zjaqZ8v1-(uv*uWAC6!~ zb)AP)V~3*UY#x}m?SL)Tz%7;5Q4eD9%o4d-|0>;C89BP0K0cDi{HQ1tFSSUWBMem;)IYQhBvx(A%TB>kH8EKwYy@=E` zOHO7pD@C`MTaTEmmnRjg1KUkK|70vH_(CHE^Qf~3INxg#z!YL433J~9@{iw~r=obT z1!+Gc!}yT<^d1E3tnHV;QQl`Y7`%v7fhVirfa-HzOPhzb8npLU8TG(|S`zy0E4^E*IjAT{v$nW~aA?41W0Gg^{I+3IpJ@7%_ctg0-TX zKA8BUwLX$Fm{i|eR&aAgB|k&ug0`Gv`Wd&c(ujZ`11sJUR8SF%%TD%p)jV=zbxQIz z!89vOv%>$pgy*Yrz`EcIb8+FDdNCmQQ7|Xwf=Y>xG?ZlTBOHcNH&KSMXK+1jw;~+K zt$acDrPu#Bu&;M_kq6IQxQgq#0&W%Avxz;r5CBmd@*~RL;6RuwuG#^z_Zq~Ni_)p4 z*QynX@r>7TAwMmf2=4;r=1*xP0EBtZpB4q5sm=^8)eL56*xDU!o;K!t znhZGg$4nKYl~tT=gIoROps|+ZgF;$FH$GZ1^r4X~hagPeLu8Bc%#;w!4sbm-^;O2) z;eGR!nLP(A!b?HSzMSa_l~%`5dw5y|hm=PPMC|I2#9f^u9|T^xmzrBy9(DH0`7)(VV*GN_W-DfdlU;?4?U~KeCN` z4&%aAjh!nodWw~7Z?rTAWeDW>7wjyQ{9fqnp6RaQG3EI+?Bz@0Su9D~b!v(6Jn0fl3Hrs+`@KWNbVw6iRWC7eO`C;V_PG<&9Rk^UAl*_VssSHj$O4M zK*uhI&uD_lyzX3RmT)h=w9eBf55`n42BO5UwCT7p@O7dsd>iy-=^hS}n8J)!5xkzi z^wSkgbDT3xWI_&1!JNVDXeIYpT*H|xi*@YCO5V=D39{D`i8D~BV4@e?)>1Sw+ieRm z?iBwR?Fr^vW2-t-Pv7ewkp5e{YF!h1wr%|bo0h(hMkezo-o@pf|5$FDgK-E2y0+R5 z|GOq*c`p1HoeS%c)-!_Z7gSQ7hF+md>=?rO{r@b&idleK#$HR)aEm1SFykvpc$QxW zOKD&%F*ctgJQ(Z}-Of}YSs7WEJS)(Vy%&`h1C{z+z*MUOc>dx^L8jxlg5xjF8{zx7UnuPkaw3Ar$bbsD9VIVe9#LdAZy6d%b^o>WR|x{ZiaW)$@CU z^M2bX^^?sN@O#yG|0sP?s3BZ>Rj4JLdY!8w{P#LnOE~b#WSg!sm-+tEtoheu#c{DN z^VfEvW~1qh{i5SP;{0uiPOHU=&ALmb>qm)BkHw1J`osS#a?JhD5JIMF(EFR;POHFt z>Lc#$pIrXrulEP15WCJZzv?eY<(Gw0J3U2vS2L;$8v8Iiy-(|F zyv{lw&=%rPI7AyQtw$z*;VnUo->e%jU*gEKfM;3}gPTUgDhd^II6bh~e-rAv^*tqD zi5m=l-k`P*D+0bBn`wH0-1TGK4Yd=6m&b|Q%b@Mu7Zzk?UskR~k8s{96eL6r88bEmEN|dr?j2+?Vv+A8`wnwCKwAJYEwU4rT?&M> zByX5`C81(HXeJA{5aAp#Eptyo=`fmSVvzTUxN+2UoTr?xZdRl?8Qx?Z63YPUw}irr zM)?p|n2Vv_9r^5|t=9bPwT;UXe|VqBB0o7HgOme3^P%QcwaZdVyfA_QOwIJ2vmA zSdQzxpq=3+{0sk-h5{{qLF^8>N-y?mHy>~euVi1P(Z6dc+-1iQ_d8_6LgJRtz-2&|yQn-~J{p|CEe^rtm6m78r#->Q zA;E4TV%xW_nAxpF*eb*6{0OOjUzH%c9*kvUwRIZW8%$8PxtYN5qm08F*<$G1L>SJww`%nC~f7>@0f)gi=K!>ELn#5#;H#rMr`ZZH*LyLO=&} zKuaj~b!&x%Pe35P>u%sd*DsCIdR@R(4I1*r27ONIs1zakm3u1z{!E9=y0pTy=f1M!eg-2@cX)wBS{RUgjuM0bn5b zypp(oB}ClHe_oH+(m*Zge`X@Ws1ip}^_m8uJ~>Fw4#2~p5U|4xe>ZGK(+AVOFYZ^c zEk5nS(XyMvNWOldT=#tO&Y5PqD*m2UCK3@W$uQ9M+Z@fUSO@9y!x4pt3E*AX!bmwS z$-1RvNOI*cm6D+Z9obc}G?5(`-CIhOQ!mx;iL_LD?b-2X(o0rDLjzhe1Zm}Heve`U z1WU{<$hmw9HkA;I`$H%jg{h+0hNscgm1E$4Ok^%0=P7ZXdby%Eittx_6#G_paaX3g z#T4ILY2Lw+hu&_@d@p-w9w@HJRcNh5brKf{&j>1tg^6NX3?6^xT&ilTQjfweMBgn^ z3Q-4K43uO{<%6&jq@l^*c6@_54tb@FE%1Kv$*E1=mVg#WGx7v0^w%)}kh0(MY%oEF zHxi01F^tRv;i0h>&IjFz1ngZ%vvozLz)ixJ$uu9IT0gLdXdCw}hSMs;5eG@ekdYPr zjWr59nghhU{TlLD$ZB)2Or&SsSwpZw1QJ+wk1-*bF8KYl>EacTJ5GC=??XCHJE34m ztGOfiaaWDEKuN(LVN{WNd<=+5XC}trBGS#)|7RR>gIrV(L_LBjny3-%Jm*?TfJk9L zuO2zdkQj>eE{$3%yj0EHq3y(&K!kyPzZhd@0My8@pV)82{LujJ7IKz&didrLYB^Kj zznfQYs-$)?UB!%g!3T5-*3z|+LD46P#>mMZc?&!90Oe4_9tJF7-fLGT^E+Ueouii zO>9>Y;yp+ypDDLGnz9RQWKS`@&44DsREF(uCO%8rE-k|VjU{{9W>BY>H0HAxILNu?UTt>ZZa>%w79^Nf5TCQ^6y zUn+0@%ih@Kal-vnyMwg8fy-CM3SSRjf@CJLek+)LrArxo5lDr^o95ROoxzAhMaTu8 zJNx?u!?r(`Ej0oCaVgeP~E={_3iS=feXNl0=fSFk{^J3bML<*TAH3u z3gUSGwKcj`eZSoi{B@k~Wwe~SAXXLYgE!{KNZ1>tUi*L9cbGPX1I!F)AN_So>KMnU z7#~m;IaaW~Dfk{-Im8nNyPs%T3xsHoSk7%{wsWc@IW zU}`Oh^k&rcNg5jI{NK|p_Axn;zGl}B!lzRsVz9{kktaTCYmkX=IrrngS8+>v34u!& z^Qvb4qH0N}JDHlY|?>2m79_yjUxXy?EXT;&{COH;+UWwoFxgW z1Zvs-GjF+{t~hClQZV{Kl`lD#;HuYNksd6HOcRJncBm+%j%~s>8C_JcnJsxmouqw( zO^Ye(W(xnEb17PCk^(t#C3%@S6gb2&qE8w%iPx*a2eu(QF@nt?m1}vf0 zcVzzj*CUE)l$6tcmN@$LhjL|;QTZ4_Aohpr=AFiU;@keDX0J|k!+l)|y}CEFJk~pI z{b~)4$@UU$XN1oqA4q%=7#`Sqkc1p}$q`K%T35fuyh<l|;Srzmvl|^El7PH{)hc1OWV=y-H7z{vIM+l;dmdYA zU1`C3LkS1ECT8I*ck_I|Rzy*5m4K@3R&7s7wtdH^ZIo2zb4kBT;kMadzE=8v93bdoO3DdJ0Dj_zoEs=nH_>`@! z0+6K%1X%x2a>zk@LC}hH7FhqBXwRJx{2<55PpC;e& zY@&OaT#*qJc5I_|Sf>`xa$Yj&hGmxg?|8rVk|Ji@3!h%GP`CY3I5FgOI<~W{T9>%J z?ukQa`LJ4H^)FKvS;(DvXSTjUq9`)VN~rz^*_Bh}%8uxQWnh!Pi_HjR6_6VvXn4#~ zGD@e3W>6L{(03)q?U43JI_}-jcb(UvIO>7cpo=cSSGV(3)UP-%aHH-hQ`f27T!xR$ zWSn`QloYX_u9^;n4zDXW2P*)DVg1;KXNF{#xY^yBV%3ATtW;7CpMDI>07d&zy;$GJp zW|Zf~fWO)|f5h+jNC~7+OX3!_4ibY-1C7fOO?85rP>u*xqo)<>%)XSy>V|rkxlQ{h7}& zOL6|@a;T=;y76Q`{WCMuy5&%nHwq(|GOjQBR;5LsTb!LT6Mc?phq@pdvxGZY-g}P7 zRC8~b8w}cG+d}TFqBiTU<=!plZn=^5MMv(%!BRltii@jx_d$-cdDmaR-NC6sGtNO{ z0PS~U0w;akrN-7u(b7}2=%G6M2sY7o`hG39bhSSn0Op7s*qhfPcMrXcEnXRLyeS$~ zM<)Z<|BFzy$N(5(%Fc7x?Zt3O6qa$&cf~ky){cLm>zJ11lbxAxUGt42M695mWM~ee zeHV$u>&2c~HqJ2Q09n5Tlk?6ZDt>zei|OwFA4ozM*c#Y6hwPiG=G0(oWhR|2Hw#R$?^-9H+RN?U*S5wn_d)fhmA6>4v_^ zjt!{Xn55n$R`SjAl24f&4Q}!~EW>5x3uy?#wg3#$UL8rAfW@aCFA9Yy6ifaqAT?C; zC#7m0qlm^1$bvh_X$dPvuWB{sY6mq2^nCyY54FM1H3j(w=<2AV7n@FK(UU9@f6jMP zu}wI!)bgaIaC)?*>63;9GcJB(zv#AQmSLlpbB1nk+!=dWuk?(BtrpXQ#ee#1cx%ZE z+%NEA=>yW$swU;-0ngHN!pVDh0a|}ZsmLYM#x)7Zhgv``Y@1-1+#xrxxA5JFdEiOo zWyAuon5#v`1)az&x@{Ng;9TZd#UZ`X)rZ?E1WlTa=>mbMcb4Y#wTXgr#d84aE+uujVV&r^i3Bz;#(RW$^lY~j6_oCNkt`5MSHX+x5|X;oFC+7Ew^OoBTGj{1J5j- zI15->DhT3Rw<@_K(yCUS91V9WJXawS6U|6g#RSz$mWq)}b;b2D%RAL|*ZJ2=RmV%g zX|@5i!}UUpTyzGU%xk6VSXvZ+$Lk~uE`|o!IIRGJ;@)&2Xi|l=kAm|hl`Q1fp%+(= zxbKiMW}8kWL3b`mGX@g7$XCCi)%y3{u#u{BsuGn*8-o9$BmeW31#Og%-`6RnZgwerfV$U2-6wpUckUKbeurC=58s-21s89XS58SW?&97rV`AOS?W_bt4QkQ ziU6DXk*F!dOmrgl!wtF`kb*|O?r#*0cg$frBcw-V>#VL z2PqzzVIBFq1{%d;>6gQb0mLtjvBNARZIdRYF$YXh^TcY&-E1O!^_0sXY&ZW|DCJ53 z21Ifd6iF_%&Fvasu5~lA8lPEQ=SD9knf0gHFhtz?0B2(B)y%~kI2v&(UL__dS{wbXruYQ6bY~8q98sl&ER|*Y6F$tm8 zWR!*(E`F=Lt0`osBs!_jssDiIj{H`O-nLskE2lf0Vocz2bg`Z&=ZenT&+s-!w%%4u zqw_j;kW`aU4N|>i7R-1$bSA6A_?Kaa{Sb+T?U4uRlEz(BT!v|_e+EiH!%!y^m;022 z*`b~b>8&;V$p4so5BrGBEeJN(G;kOQXE>1uz&iY%Yif0{Q5b=8Kw6))Cl3YrGSQSs zyD}7GebJRt-glEvBPR^y%QEn27*uRTH=Zo>KQ3Ss4pNmjksD?U7)sXP4p`q1e0Quv zlRpSn<(5nvozoB9^?d-DobgTdADr_B0df#Zq+oW!-Oi5lmak?s6&gyc@u1=t@=!zl zuofFyZl^;poWiG^(=9gowMy?Gp8ZU-E^N=%;vBIIi5Xu@tw%SF{C%PFL(bg@gOo)u6uj$iUD+1>jDWi0O?!fJ;Pv+A|Vonn^`?a2yR| zHAw~?k#2S~3SK8j(g6Nm*(!-b_FV7{U-prD5=t^ z{3+_S7Eq-rG@VY=^dB{4rr>uQZ4C2#XK*xP>XQmhFO&?ZUpNp9XwlHcn3T2O6xpgP zxJalTNc<62Mu9nTZljqWV_y10x!!|jBg<0nQN5f>HDtDXEGEgt{p=oC=@m=IdsZ|h z7_(JYw|PDrAa~}*XrR$SLjjiHA5?iOFp|?}vr%Ass9HS&TA=Z_d+K_{Q|dC1chbr< zvd=jqIEdf>`!snoR(pP)BQM_na<{vIe8+I6&9R$Kp?ds@z~I)ZeC@c<0tzp>mc~>t zL|MO}s{(YkMNwfoTYJGQxK$7{Jmf1ldIZbsUW`$mqLjonYgr4okEBONXSZJLc#Laf z*LOd!>F~-E2a2vR3hJXj#y>*Y9k;H9*Y-jwh*kPUIrjlLBru-zA}yp2x$CR2vz1W5 zGPMI<@#0>TD9CEENK<%o3L+}>fBIs-n6Iv3fZ*L|GDyFnGpoU#u;zHKWUqDK(VG;1 zj{tl|qGnE>ocCFLgwD7g$#-FGUBH{B|46*#OZS*h7NqXvk_@@)UtI6Kewx>Qyj||e zF|9;j@_AEyH#9lI)1b$`;#@-!r=pak#d%)-GT(^O2HC|<*|uCIK=>Chtc6V1DAilc zq8a2ZQPMZP*sBkF0=wSpiH>X-C-tlMW6#V@>k4Wl6=IAPTw9dkXLq8Z9Oot(&EUb@ z3F^iw!R)gA4gy~Kh!JAq@0qIaeEVO2gmC^Y_#|NRY^D1TSbLbkI*#x_TJb;K$rc&h z%V;#Ao;MTu)M5nBxm5LiHgsagJXrgMH1!7dwtoL>Wy+K$JFtXlnIp96 zxUa8A$tuG9kIvKU&LCwxzT+Oz%y7?so$;A?-wJ&vxGgYQ2Aj3B$Z$z;p6JwEuOPZR zRGv9YzM7MP7mupA7p&-?O}(c^f72fB05QQ9!LEIEN4c#dOsFO`60JJc%FaY$|(t|yNP-gqBx_%&JcX?tVr z%I57Y(HiFXE%uvfqJ7r&j8Li)+V)&NCSZWcvH`L`Yu+MeUv1d(GwLmN1}~+Iuahto zR=OKoS!dVXS~dAVh2}aXunJu^58@*%-kCNxUo)9tnJ6U<(D@_isN~BwewbRa#`qZF zqw0t(JVP$e1(*Xci+zKfAqhwrj4$lMI6%mXPPmI-5>Q_+v<{$4Z%&(id)W$HLoidk zZR{*;tJR-N$Ca}?a%wwH1K;!+iq{4abI={Jrb301Qj5CUQ-)T-B*lI2X<79bnaDZO zb!{c0io(KZ=$tic^d45v@nEyQ6wjP7@jhC>AS>r;S)de7nXJR)iyvh1tk?8Hau?75 zs)zoGR3{-OLe0l=NUO$mRfA%&6RZTT4_$p!yMjLl&<2G#)_(t4WFt4c-?T`V1V_0fKM%ws1Z=aDD z-xBbCAfzOYdB*PA{3TrvuG6ZL05+b)%jf`+gr}B^$n#c9M}hF!!p6ICctT-MY^!y1 zhD6-vWqn4zOe&?}F&7bkx%yq8jbqZo0tO1R*`PBwS{wsvKtgG z@<$PXlM0>^{GT&fkWddJt;6zKkmQ0>Wij_Zs^7^}w?D2x8z2EoVe|I!S_`mA%=%e^ z^}5E=DTBew5y*yQu6CVlbl^^O%UDE9Mb_#b$;)M zEa=Pdh~3LJV7G{j`*i+}3LT(`^ahJ3>5BHI;QxdX8o_z?WSTrY*RiwJv<4G+fLniQ zYNA`7j^!tV-sX)Pd8DLkir_YRr9xeT$apOAt3yuc;_$xYUO>uDY^r{^4nkdYZqBPV zMPx~Y(vmUI6@CcCxgfTqcX7F$Ash+_o(1o~B-w1c5S;9ikV}DB>TH^A7pg`1VT_Ul zm08N5|3km_y02J2{fXf=a9}(OtK!r}wJODI+9XQduu*O{EIDf)AGw>3RPa?NXee)N zz_<838)WgRQUCMl@b#Z&AC(AEwZ8XWGYmq4CxR{#DQN;&gu99cayO`R*HRR?)(+|thTT{Se=5ainixa^dCzNlIW)Uy#{3(#n zu``VEtArwqgeU-!Moh2(fMauClv<`F^P%nc&ohAorzG{~nD^uR(I+_1i#xPNA~lq1 zW);&^6?HaXF|44G~&O6=#%(0vX>^CM_;bMHWGpN+m2BFP=%^E<1$>-~-pm z(Mg+MsIn_D=ibNYS%`<)CtL6|jVF1(^^h%m)wS(lKseZb%!@h#TX`77ryttJCLK{*Ax+Qz<>$^(VT%lYwwQ;tzsBy+!A{Ok)=gW0!5lnB&PkPonlrH-}S3 z&gNFF9?Vm`V^_N=C;imbe_chnjEo8<>D;1$SYU$Dy+Feo^^;c5gv|I31Gv8QJg}@D zl!a7g`Rvxzj}^w!v~~jyy!BlbHuGD3HHoHXd+C)OvpmEGK6)G;Cwzqc^xL-EUWo3h zOq45lv3kSK;YCRU9HS`tfV9zB@OwW%s;mXhmKQ*F*b@|20Fko%b~ASW@;awKa|-gR zJSJEIpL6T2H&Bc@yz8WUwpMn8Bx3}VUEJnz{G=}lN8}@W`xbUz zFqHdI+zK|$DojGk%enfu3@f9j_!Xz4y&A=1-Myk@J9QD7xT&y1MvZl1lQCw;nDYb$ zThm%>!qju?Kw`|WCd7Hk&2@i`QzYMd&?iPC%~{=02VYmrm4;TlX9FpG0<{w(V<~IH zi89#u^D?s}!4#e*u70@uA30YEr-QHI=p(rPUgM-^Op^2t(*^@gumGnMT3t%`T(fiV zh^G>Bqzf}!%Y6cj9c$`?Gqc?c8iaWYcKaPOF#e(U@jhpk$6C14K^&t(o`w*|s*?ln ztt_t~`r#Xj2E@BWdPR0*dW~6YANU_?H-@O5_p!G%@zBeh^p4Q=&3zIa%s z5@klVTF!?CWL<$@ixZo7J}?i9$DKzZM1Q8-OMnA?;g7W3;^j<*>w8g4c{c6{fodTC zAcYwjEKkZ^e~gPqZw|*6tSPW1j`lcR1yh=KRcaD38 z*fq4@3?-v-91{wwmWA29=4Y{AM93nnqQk(Kt6yAuf^EdP0w|8~E7V3%lhlYQK~U|N zc}2|RaGpLBF8K?VN3&F8YT>^0))?f2^8wG)Pa5)y6FB``5Aopex6GXxr}P68&^dxi%k<}je2o9^$Te(jykBD7i^Z>Kl&JT13W$w z+K3!!4VZR_#}tF1L+ws65;t=r(;hFXtgxE3b;LBDaf?@+bnZazQHSUq-deTQud}h2 z&V?h@Q}3HO$7;e}Xu&*%PCQ=2eKm}BLg2!l6TSlZZ(_NUOVq~oslvfdC7ErMR9ZDZ zxzr-=H*+wWZZs!YZZOBL1znc78Lf&zRO8g}0&pN$M7E8@QC zDf|nE(Z9yGfK0H6%m6ew>_lrgs&v!l8I|vRb`}ly?0LG4C-f^BitXW9k0yR0ykC)K z6m$XStW}43bgrU1ZwD-)0PJm+6B1nWzeW07&$cYZ6KFdVaJPV2-ZMx+Pq1bBQd1V39dM0`nw2&<76N?`Uh z(>8q`?6PuLM*kjO|AO_PI6|sD^-&j^=u(L3pg$VyfMfRMo&Rw^+|bvoNoqmoYPWLe z%b9XWvJoSzBH+C$*-ZujjfPC`gwO5m0}Y8GfHSmU8BJ-07LP3 zlY};-wxiZbfa#Usi7dAOw$5(fgZGu+dDQ7GcmAgvz3o)5#aFB$701~jfT>I+ST`?M zC9eY&b{Myx9+az`@)%GrL+phc9QuZ$2Vv!6P!>`;V$H{SgwH4>uGIGX$aJ-7tGA-t1rLb2Dv7->^lJJhUY2cP zvM=R@k?S$5f_gE2dNWyL`huaki*2O0dfaBkEdi|u3@2fjj4*+ zR6=yEKAlQWz`k00!(L~lzBr5IU`0X*S;@E>|5hGkbD8F+f)xP?;IlO`4d$?erru^b zU*^^PmmxzZV9`YBhPZ~tzRoVW&lziYN%#0#p9*-%dpw>u49Ha6k3*f4Vk~%yEgF<@ zes_qWY*8Vxf~QUP=TB0*fa%(yc5MC^KpUOVGl1py+y_$qlk>gN+s*WepT=lTp}NIU zU40fwqH#?uNx)ER><^@+L_>l=v_a$1pMGcs&*Im(>WcS9^(NcgQ!g z7kOpSB~VjRiKPtiEh^-cf)Le^2^qEG*-p?&Xd}(taQdX(d@$ng2wciet-bo+bQ(GF z%TTLK+0KacWXFi7j+*5mm7&f@XjL}gRus}}p{h&OYOywY)H4=37l9D6eUe?DgXV7@ z7C2M?H3O(NKGWU>PP#e#P!R-OI7J-=p+mD9>axW=k`Ay2qB6L*r`%(iwuBBdOE# zSU}f5MFNCfpMlSt~#lq6}3gpswRKo3Fz317X8 zN{H7U9#OVww!X~*Ka7)!G-9t-w!=l1$xa8(O8fU#-Q))@Hsrr-D}ibPf4)3fgYMB<(!0q5BYe(;vNA&WKR%2>1bklipK5!2-yWW}`9ElVU+>TC znm;hTUwK$x-%{7R-(NTM%xKGa_?XUDMHI|Tc_%mf5) z&HZpuAHaoHhHrErdj0eHF_-a-G1@O>zPo?W`|Z{&sC40Y<^m1@KD>W9l#7bXO1_#K zxiIEBcCrJfS}Gv>L?x_Q99?rTwb!T_;}0(!X~1H(O1M)6Kw1QgH0}VfS(WFt0u%ee z_K~~k`?3!g^;zrp{)+9nyl`AQ8(DkdRC__=T<-m5;=v_1ec8%T{q>^taj5lroBDWh zjfiz?r|0!{TfC(AsrLGAmg)8(m!^JlE%3F`^S;pY1?Oz~9!~RW(b(Ar4UNc1UP30k zTu6yG2*&<1HU`iC{RR}mvjcM)PdywHeXU?WlZ~-ERF+# zVL;(ziZz7(?Mm zB}A1OkdtWHLV3TVxXA11L=c-2rHgw%+K{9vPm6f#37)le!p+DCKol{Sjo3&u8lK|b z$3qLM2SK9{=6Fx;%2ch=MU6_fW(!Bjtk?6H>}UBoBBEaExcWpQL+@GPj37GVGzNRf z0N^U^eHe-pKsS|+JJhhgBppN@Z!39s$8l5mLxnqn*n>T|5a5&-n31Op?V|nNGH(gR zy`I~ccztx=45|AQE?V0K=~ zYDPIw7?xh)2RQKrqMP8rmzwvpgbAO(B$T0WHr#3_1_pQO{!=EDwAKsNgF`@eLKl9e z9EjRUoa6&lvaH@nxM=6Wond!lqW^Mhjorp$z&=A5MF1!I;pgl)b9QT!y>LhBaUFM@ zC1uX5cW62^#PFI7T75cmROs^Ach78c@{6}+kT;I!l3}c!t<6A=T7Vfc(&tqc^z3^C z?P#U-MbY>Hk>OmD+$JAfB8pmJxkEXn(&3I@}Y;Z_}ZD~u&<$-k09$X81_ zj=%4-YXY!DR(&z0x3jq!OFO#J(*e$gxhbAO8j}8O5jtWxdD`QW^iaPrYt6 zz(YfTMR8xfqCeRrSW`Gx+KPc-387NO@GY%mE|3=G91%oVaGEk(sXLU;iFh}ZlzkwI z3^c-jA9_CWDnH=*NuNu!#-|{v%<+OXo(l zgb#K9JKE$Lr4ObFE*4A2O#`f0Oi32g=7hCPz50a@20^?W7sJZFx9Mrj5j*Mc1VNe- zWB(y!+goK=e^MSXFK#1UE~rn89mf&a6uk)zJ6Y?-37gIH7SqD(nRp`#s?R$5C zp4~Vv$k3bJyK3}1_NNMdwl0RObnVsD^6n~s9)=Os)S-f9Z&o41*WCI7@Zzn=-^~kZ zbiI$2(F6QU>D?w9$Y^+qyycW_Hck(X(Fmx7Ilm(&I5)Lr6O#ui4E-(K^+u$@c0z>& z#pcL+-}GFUi=fJBtx#6QDLAbRj{ksB9QC%C{iGw(QtUO&ya7DLPrrcWLw7n?Zl%;7 z{l{|lPBOeqd~-o-xOhr^q4173<{9(NR6OdLbkTSo5A52zksNncc~9B>8~6|-n0rFy zsho?`UAgp|boxVtf(8*6?#SXnvfv}~b&MdgK8Vz#+U#qvpE>z@wve5tLpE7W|r zibn2)Gxsi0M6NP?rHBzl7e-8^mwwlq2d0lzKBY z#<1ZQC|tFWpL`Y3GEIAA7+}09=YqURqq;$#tYytsgsfmD zBOZ5e=<#BP}vg0VMff#wx#1nO82?hc({9DZtF-Bn=uW)R7trDI z9L8ye^sO1wr;m>I zFSm4h-G>vc-Y+Q(+qZ{W--BO#-V?bG7yP$$x{9M@A=>}n3va4W%qk+0gSvy+EHt8Z z@v|Y)f!Uvnx6FGzj6r^V`W8ZvKdZFmyQzI)?n}QP^ag02HgU~_;|nIjhE^(V`iHdj z`Lw149VIf6Nvz53*sLizo#D^tVj+_K1uwJ$t8p&Dz>qR$dQ)0kxBOPC`d*)lr<*i+ z>K2quY%7A(bZDvJ!kjMw&vJ7WS; m_h2U|CIw4hhR^gm-`8K-ifKU-xw3WKi}En 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

    ZoWGw`LZ#TiK3b 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 z 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 z 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 literal 0 HcmV?d00001 diff --git a/plan/marketplace/research/2026-10-20/live-deployment.json b/plan/marketplace/research/2026-10-20/live-deployment.json new file mode 100644 index 00000000..978c2910 --- /dev/null +++ b/plan/marketplace/research/2026-10-20/live-deployment.json @@ -0,0 +1,146 @@ +{ + "observedAt": "2026-10-20T09:47:56.301Z", + "rpc": "https://evm.donut.rpc.push.org/", + "chainId": 42101, + "blockNumber": "24447347", + "addresses": { + "marketplace": "0x9071ebE01B75123A91e88eB6ec4BF163F3fE9BF4", + "kernel": "0x977cf1AC973E9eC4332791d531507575006157Ed", + "hook": "0xDe7A94e510b6C571DE7880d441349689F73A32b3", + "rules": "0x5b98A8E0df5b918DF76cD2BE84bA7995B39dfd44", + "builder": "0x2de1e3F053b0bBa0cE0C6953144534a0b055f59e", + "factory": "0xFBBEB6a365178fAaA81A9789a5f64b300c37e5bc", + "engine": "0xf63DC0628fe1B25049FE3E3a3585Ef051CB98c1d", + "pUSDC": "0x7A58048036206bB898008b5bBDA85697DB1e5d66", + "evaluator": "0x1afC81396f1bb36F91f74506284952b81e4bd47c" + }, + "components": { + "marketplace": { + "address": "0x9071ebE01B75123A91e88eB6ec4BF163F3fE9BF4", + "codeBytes": 1033, + "codeHash": "0xec110641b71085ab23f3614eca15d149d9cc83dfecbeeea076e140e6c7882b0e", + "implementation": "0xd683545f84698df4341b0031c892c53384ff30be", + "proxyAdmin": "0xb7d9315813fe87a13833871ce673073dd4b8c8af", + "implementationCodeBytes": 22156, + "implementationCodeHash": "0xabad53926791b8ea4089b86e2d7eb11397e6ede4f91deefd123a0369e2839ce3" + }, + "kernel": { + "address": "0x977cf1AC973E9eC4332791d531507575006157Ed", + "codeBytes": 1033, + "codeHash": "0xbc67b4b15b395df23ca79660448955f993ee75c2e9e4650e0c4c6d2f30ce3e89", + "implementation": "0x1d631e9d0e0a7a7423743c3076054c784af8fa40", + "proxyAdmin": "0x5f5ef9dbbc31d59a28626d1f913a35b5b6ea0cb9", + "implementationCodeBytes": 10930, + "implementationCodeHash": "0x97f198ec46563a5906240f99aa9eeaf76d547bb0c79475486dc233bce5d4c1bc" + }, + "pUSDC": { + "address": "0x7A58048036206bB898008b5bBDA85697DB1e5d66", + "codeBytes": 1201, + "codeHash": "0xed2764096d54cbdeccb8952d602675293f894e03faa9ad78e8d135f15cc16ac3" + }, + "factory": { + "address": "0xFBBEB6a365178fAaA81A9789a5f64b300c37e5bc", + "codeBytes": 141, + "codeHash": "0x58e6a6553bb3565097e3d3a08dd1e72e339f004ecca9285b569286d8f459c43c" + }, + "rules": { + "address": "0x5b98A8E0df5b918DF76cD2BE84bA7995B39dfd44", + "codeBytes": 7832, + "codeHash": "0x75daf3f6953e873ad056184e9c491487e96882bd3548beca9d4b5700c9c79c1a" + }, + "engine": { + "address": "0xf63DC0628fe1B25049FE3E3a3585Ef051CB98c1d", + "codeBytes": 22581, + "codeHash": "0x5fa747bb1b2fb6635dbc22608f86a18a743d6ed9b3f394abf812ee3d4199bdde" + }, + "evaluator": { + "address": "0x1afC81396f1bb36F91f74506284952b81e4bd47c", + "codeBytes": 0, + "codeHash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470" + }, + "builder": { + "address": "0x2de1e3F053b0bBa0cE0C6953144534a0b055f59e", + "codeBytes": 5597, + "codeHash": "0x9f4d23c0b4a3ace3e37841c331fa9b0d639c6684cd94b6e8a03093c3f2fb4de0" + }, + "hook": { + "address": "0xDe7A94e510b6C571DE7880d441349689F73A32b3", + "codeBytes": 1033, + "codeHash": "0x610391ddca2489a14762aaa988da87e8a0dc2398bccfc1cdab75146024bd3611", + "implementation": "0x58bd6951b653b5028aa77b4904e83df668bcef7e", + "proxyAdmin": "0xba96c7fb588ac17aba00c7aa920e282c088b1746", + "implementationCodeBytes": 3477, + "implementationCodeHash": "0x73d02a69e7fb974656b028d41d140d967ae9efa7564af5f49707b43f1445ed12" + } + }, + "getters": { + "marketplace.RULES": "0x5b98A8E0df5b918DF76cD2BE84bA7995B39dfd44", + "marketplace.PUSH_CHAIN_HASH": "0x3d6bc1f1d3fb03065860265a8e93840b586e57075d956cd41b4319d040be87f9", + "marketplace.AGW_FACTORY": "0xFBBEB6a365178fAaA81A9789a5f64b300c37e5bc", + "marketplace.OPENJOB_LANE": "3138550867693340381917894711603833208051177722232017256448", + "marketplace.KERNEL": "0x977cf1AC973E9eC4332791d531507575006157Ed", + "marketplace.evaluator": "0x1afC81396f1bb36F91f74506284952b81e4bd47c", + "marketplace.agentCardCount": "0", + "marketplace.hook": "0xDe7A94e510b6C571DE7880d441349689F73A32b3", + "marketplace.version": "2.0.0", + "marketplace.paused": false, + "kernel.paymentToken": "0x7A58048036206bB898008b5bBDA85697DB1e5d66", + "kernel.platformFeeBP": "0", + "hook.SESSION_ENGINE": "0xf63DC0628fe1B25049FE3E3a3585Ef051CB98c1d", + "hook.KERNEL": "0x977cf1AC973E9eC4332791d531507575006157Ed", + "kernel.MIN_EXPIRY_WINDOW": "300", + "kernel.evaluatorFeeBP": "0", + "hook.AGW_FACTORY": "0xFBBEB6a365178fAaA81A9789a5f64b300c37e5bc", + "kernel.jobCounter": "0", + "kernel.paused": false, + "pUSDC.symbol": "USDC.eth", + "kernel.EVALUATOR_GRACE_PERIOD": "3600", + "pUSDC.decimals": 6, + "kernel.whitelistedHooks": true + }, + "chains": [ + { + "chain": "eip155:11155111", + "chainHash": "0xafa90c317deacd3d68f330a30f96e4fa7736e35e8d1426b2e1b2c04bce1c2fb7", + "factory": "0x8ED594A83301FEc545fC6c19fc12cF7111777029", + "implementation": "0x0a4F7be62B56830070266be81114edB93e68DA09", + "cea": "0x33996E73ee53988B4c446457e5f497e9a4B87B0D", + "independentCEA": "0x33996E73ee53988B4c446457e5f497e9a4B87B0D", + "matches": true + }, + { + "chain": "eip155:84532", + "chainHash": "0x8a9a9c58b754a98f1ff302a7ead652cfd23eb36a5791767b5d185067dd9481c2", + "factory": "0x0A75ca7736b488Eb41675ADc3b3156BACF659F55", + "implementation": "0x6c9Cfef12155bEE91ecD6d0C8f516cABA2890656", + "cea": "0xf1981b90F0207135B396F698F33119FaED32e5cF", + "independentCEA": "0xf1981b90F0207135B396F698F33119FaED32e5cF", + "matches": true + }, + { + "chain": "eip155:421614", + "chainHash": "0xf0b5e5225193cfd0cd1b399b5597eb35e33f77deb76267030dc6d28cf2a8d16b", + "factory": "0x88DC189275078Cf509E4Cc773F089c8ad07b7EA2", + "implementation": "0x512d1B8C185a0Fd533a69f8973A3DD6513233009", + "cea": "0xcE8377D906a057fEBBF5c898729B2D31644AFAf2", + "independentCEA": "0xcE8377D906a057fEBBF5c898729B2D31644AFAf2", + "matches": true + }, + { + "chain": "eip155:97", + "chainHash": "0x42a13880db2f2fe1c95fc8d04876a774745355a97dfe8f3397694d11f135eccf", + "factory": "0x3f1B16e0B072d472951C4563d29d3da6a3EE3Ce8", + "implementation": "0x0ff5d8b7d9Ac3ee2Ad420e9b70Ed6Dc465f593e9", + "cea": "0x3223037344F37C1bf32a0d6b13035d55d88F39C7", + "independentCEA": "0x3223037344F37C1bf32a0d6b13035d55d88F39C7", + "matches": true + } + ], + "errors": [], + "sampleWallet": { + "owner": "0x1111111111111111111111111111111111111111", + "index": 0, + "wallet": "0xa932F2f3903379FEcAe7936559543862D4C3AbBa", + "deployed": false + } +} diff --git a/plan/marketplace/research/2026-10-20/notion-discussions.md b/plan/marketplace/research/2026-10-20/notion-discussions.md new file mode 100644 index 00000000..06d693b1 --- /dev/null +++ b/plan/marketplace/research/2026-10-20/notion-discussions.md @@ -0,0 +1,42 @@ +# Notion discussion observations — October 20 + +Read from signed-in Chrome's current **All discussions** panels. These notes are paraphrases, separate from the body-only Markdown export. Dates below are the displayed dates. This is not a full export of resolved/hidden history. No team replies or page edits were made. + +## Page 2 — Universal Marketplace + +- **Zaryab, Oct 16**, attached to M7 owner approvals: AGW v6 can EQ-pin the spender and MAX-cap approve amounts; its change doc explicitly uses an Aave allowance example. Asks Harsh to reconsider the old approval restriction. No resolution is visible in this discussion panel. The newly deployed branch independently implements pinned agent approvals, so page 6's public API still needs alignment. +- **Harsh, Oct 12**, recurring-jobs open item: asks Aman/Zaryab how 7/15-day renewals interact with one-live-job-per-wallet, including a successor slot. **Aman, Oct 13**: ERC-8183 has no renewal concept; renewal must create another job, with sequencing a product/AGW choice. +- **Aman, Oct 13**, Open cancellation: confirms client can reject an Open unfunded kernel job. Does not establish AGW permission cleanup. + +## Page 6 — Marketplace SDK + +- **Harsh, Oct 12**, card enumeration: asks Zaryab to distinguish on-chain count/ID-range/provider lookup from indexer needs and practical scale. No visible answer in that thread. Source now supplies agentCardCount/getAgentCard/agentCardOf; initial enumeration is SDK-owned work. + +## Page 3 — Kernel and hook + +- **Harsh, Oct 12**, fees: assigns client baseline prefund/provider verification costs and platform/external-chain fee research to Aman. **Aman, Oct 15**: client prepays snapshots; provider pays verification; suggests zero kernel platform fee when neither sponsorship nor triggers are supplied, with any additional fee potentially in marketplace. This is a recommendation, not evidence of an implemented marketplace fee. Live kernel fees are zero. +- **Harsh, Oct 12**, renewals: asks Aman/Zaryab to research per-period escrow and occupancy. **Aman, Oct 15**: says initial research will begin. No delivered renewal protocol is established. +- **Harsh, Oct 12**, phase 2: requests EvaluatorGateway planning. **Aman, Oct 13**: says a proposal has already been presented/agreed and no theoretical blockers found; links `3f0188aea7f480169cdcc33375f564a5`. That linked phase-2 proposal was not part of this v1 contract review, and no gateway deployment is inferred. +- **Harsh, Oct 12**, cancellation: asks for hook/narrow-role cleanup so cancellation also releases wallet rules. **Aman, Oct 13**: reject is hookable; direct hook→AGW authority appears missing. Independent review now distinguishes occupancy from permission and proves an owner-batch cleanup path on current v6. Automatic cleanup by a hook still needs its own authority design. + +## Page 7 — Job SDK + +- **Harsh, Oct 12**, verify/retry: asks whether anyone or only provider can rerun verification and for exact function name. **Aman, Oct 15**: refers to Nilesh, notes verifyFromSubmit is currently onlyHook in evaluator revision `4391181a143616bfe16c49be163b663c82cfe58f`, and says ideally anyone may call the retry. +- Later linked evaluator revision `8059817` was read directly: verifyFromSubmit remains onlyHook; public sendReads/retrySnapshot are separate operations. Do not equate a retry desire with a public verifyFromSubmit capability. Live v2 uses neither contract; evaluator is an EOA. + +## Page 4 — Evaluation + +- **Nilesh, Oct 16**, attached to the shared Solidity format: links [JobSpecTypes at `8059817591cca16c59f1cc154f475f51e1736a67`](https://github.com/pushchain/push-chain-core-contracts/blob/8059817591cca16c59f1cc154f475f51e1736a67/src/agentic-commerce-8183/libraries/JobSpecTypes.sol#L48-L77). Adds Read.at (POST/PRE); baseline is explicit in PRE reads; Check.left/right are arrays whose values are summed; MAX_READS grows to 32. Rationale includes protocol totals and cross-chain comparisons. The actual linked file also changes top-level order, Logic/CHECK representation and enum ordinals, beyond what this comment lists. [Comparison](wire-comparison.json). +- **Harsh, Oct 12**, shared wire: says content-first order with origin must be the one imported definition. Also asks Aman/Nilesh to use direct check references rather than CHECK leaf nodes, with common Evaluation/Operation/AllowedMutability vocabulary. Those body decisions are not implemented by the later linked evaluator profile. +- **Harsh, Oct 12**, verify retry: asks for authorization/name; **Aman, Oct 15** says Nilesh can verify the name and anyone can trigger. Current code distinguishes hook trigger and public retries. +- **Harsh, Oct 12**, source kinds: Push-local reads should use direct staticcall; evaluator web2 path is not defined and is future scope. **Aman, Oct 15** acknowledges. +- **Harsh, Oct 12**, fees: asks about evaluator fees/external settlement. **Aman, Oct 15** says current design has the provider pay evaluator invocation via hook or directly, reflected in profitable provider quotes. This remains distinct from client baseline prefunding. +- **Harsh, Oct 12**, recurring jobs: asks what each renewal needs (fresh baseline/spec/rearmed spec). No visible resolved design in this panel. + +## Page 8 — retired placeholder + +Current title is “SDK: Evaluation (retired, placeholder)”, edited Oct 12. The body explicitly retires client.evaluation, moves authoring helpers to utils.job/market and job-side state to client.job. No Comments toolbar button was exposed in this page's current UI. No absence-of-all-historical-comments claim is made. + +## Supplied team message + +The user supplied M4/K-12 concerns plus Zaryab's subsequent v2 deployment notice. Treat that as session evidence of intended rollout: current pUSDC-only kernel, EOA evaluator, four EVM testnets, SDK branch sdk-iteration-v1. The proposed NONE-only scope, token allowlist, CLIENT route and fund spec-hash commitment were questions/proposals in that discussion, not settled implementations. They are analyzed in [M4/M6](../../analysis/mutability-and-payment.md). diff --git a/plan/marketplace/research/2026-10-20/notion-export.zip b/plan/marketplace/research/2026-10-20/notion-export.zip new file mode 100644 index 0000000000000000000000000000000000000000..519da4efb9fc74c68f092a712f57e74aa25a5990 GIT binary patch literal 98001 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�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 literal 0 HcmV?d00001 diff --git a/plan/marketplace/research/2026-10-20/notion-source-manifest.json b/plan/marketplace/research/2026-10-20/notion-source-manifest.json new file mode 100644 index 00000000..e7a0b055 --- /dev/null +++ b/plan/marketplace/research/2026-10-20/notion-source-manifest.json @@ -0,0 +1,57 @@ +{ + "exported_at": "2026-10-20T09:44:55.670557+00:00", + "method": "signed-in Chrome UI, Markdown & CSV, stack index with subpages", + "archive": "notion-export.zip", + "archive_sha256": "14778ebb329966c82950c6ffad8e0a6324ea041221b58e426b3a9de4b6a66fb4", + "comments_included": false, + "pages": [ + { + "page_id": "3e9188aea7f48118b90ac9b267496295", + "url": "https://app.notion.com/p/3e9188aea7f48118b90ac9b267496295", + "local_file": "notion/2-universal-marketplace.md", + "export_entry": "Private & Shared/AGW + UniversalMarketplace + 8183 + UniversalEvalu/2 Universal Marketplace 3e9188aea7f48118b90ac9b267496295.md", + "sha256": "a4313308d8a7ae836dc32c6202b37892a34ea683b9600d18481e6ec858808c64", + "bytes": 23371 + }, + { + "page_id": "3ea188aea7f481e2961ed97129f3a4e6", + "url": "https://app.notion.com/p/3ea188aea7f481e2961ed97129f3a4e6", + "local_file": "notion/6-sdk-universal-marketplace.md", + "export_entry": "Private & Shared/AGW + UniversalMarketplace + 8183 + UniversalEvalu/6 SDK Universal Marketplace 3ea188aea7f481e2961ed97129f3a4e6.md", + "sha256": "2fa9093f077601b16f5a0410def51df5f0dd2c7324d96402fa3b9dddd2d4ef91", + "bytes": 48935 + }, + { + "page_id": "3e9188aea7f48188a838c3a740d8c858", + "url": "https://app.notion.com/p/3e9188aea7f48188a838c3a740d8c858", + "local_file": "notion/3-8183-job-kernel-and-hook.md", + "export_entry": "Private & Shared/AGW + UniversalMarketplace + 8183 + UniversalEvalu/3 8183 (job kernel and hook) 3e9188aea7f48188a838c3a740d8c858.md", + "sha256": "0e9100c1eba4ff3e163f15ef1725a00f044fec19be95a744aed064be0037b030", + "bytes": 11616 + }, + { + "page_id": "3ea188aea7f481e0a137f5a896723376", + "url": "https://app.notion.com/p/3ea188aea7f481e0a137f5a896723376", + "local_file": "notion/7-sdk-8183-job.md", + "export_entry": "Private & Shared/AGW + UniversalMarketplace + 8183 + UniversalEvalu/7 SDK 8183 Job 3ea188aea7f481e0a137f5a896723376.md", + "sha256": "bfb79eadeaba235da9b9bde28ef598ca5163a2caf489e4cee313c2166a433080", + "bytes": 16646 + }, + { + "page_id": "3e9188aea7f4817bb03ef4c78c883f8b", + "url": "https://app.notion.com/p/3e9188aea7f4817bb03ef4c78c883f8b", + "local_file": "notion/4-universal-evaluation.md", + "export_entry": "Private & Shared/AGW + UniversalMarketplace + 8183 + UniversalEvalu/4 Universal Evaluation 3e9188aea7f4817bb03ef4c78c883f8b.md", + "sha256": "2271987bba0cbfd9e5a3790168437c4820cc81b815043f37060e5294658fb3f4", + "bytes": 19325 + }, + { + "page_id": "3ea188aea7f48197a3b3cfdedfa74fee", + "url": "https://app.notion.com/p/3ea188aea7f48197a3b3cfdedfa74fee", + "local_file": "notion/8-sdk-evaluation-placeholder.md", + "export_entry": "Private & Shared/AGW + UniversalMarketplace + 8183 + UniversalEvalu/8 SDK Evaluation (retired, placeholder) 3ea188aea7f48197a3b3cfdedfa74fee.md", + "sha256": "5a1acc551814a9b05868fc9b3d3dacfb8cbdf26414e9bac240ffbf970e2d1b0c", + "bytes": 2301 + } + ] +} diff --git a/plan/marketplace/research/2026-10-20/review-gaps-summary.json b/plan/marketplace/research/2026-10-20/review-gaps-summary.json new file mode 100644 index 00000000..f08411d7 --- /dev/null +++ b/plan/marketplace/research/2026-10-20/review-gaps-summary.json @@ -0,0 +1,45 @@ +{ + "args": [ + "forge", + "test", + "--root", + "/var/folders/4_/d47r2_4s1wb3x2dvmt2ghp800000gp/T/marketplace-review-443b4e2-_ib864pr", + "--match-path", + "test/8183-tests/ReviewGaps.t.sol", + "--match-test", + "test_review_", + "--offline", + "--json" + ], + "exit_code": 0, + "seconds": 70.58, + "counts": { + "Success": 4 + }, + "tests": [ + { + "suite": "test/8183-tests/ReviewGaps.t.sol:ReviewLocalGaps", + "test": "test_review_cardFeeIsReferenceAndFundOnlyChecksAcceptedBudget()", + "status": "Success", + "reason": null + }, + { + "suite": "test/8183-tests/ReviewGaps.t.sol:ReviewLocalGaps", + "test": "test_review_nonNoneIsAcceptedButReplacementPayloadIsInert()", + "status": "Success", + "reason": null + }, + { + "suite": "test/8183-tests/ReviewGaps.t.sol:ReviewRealAgwCancellation", + "test": "test_review_cancelFreesWalletButOldAndNewGrantsBothRemainLive()", + "status": "Success", + "reason": null + }, + { + "suite": "test/8183-tests/ReviewGaps.t.sol:ReviewRealAgwCancellation", + "test": "test_review_ownerCanAtomicallyCancelAndRevokeWithoutNewAgwRole()", + "status": "Success", + "reason": null + } + ] +} diff --git a/plan/marketplace/research/2026-10-20/review-gaps.log b/plan/marketplace/research/2026-10-20/review-gaps.log new file mode 100644 index 00000000..fe140dab --- /dev/null +++ b/plan/marketplace/research/2026-10-20/review-gaps.log @@ -0,0 +1 @@ +{"test/8183-tests/ReviewGaps.t.sol:ReviewLocalGaps":{"duration":"9ms 591µs 125ns","test_results":{"test_review_cardFeeIsReferenceAndFundOnlyChecksAcceptedBudget()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":7340929}},"traces":[],"labeled_addresses":{"0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin"},"duration":"1ms 345µs 292ns","breakpoints":{},"gas_snapshots":{}},"test_review_nonNoneIsAcceptedButReplacementPayloadIsInert()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":7378198}},"traces":[],"labeled_addresses":{"0xbe57cdad49a1d68545d529fca9298a841621eb6c":"vault","0x952c59c00bc7e96202b1ae82aa80f887422cc8f8":"userUEA","0xd5e069bc58dedb2a3a348995ee753eef0274004f":"client","0x31af8d96c3d532c6ab33c1e5b77366cd4de4c44a":"sessionValidator","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0x2d1e3d67e9cc5f95f17143108ad330c1fa324669":"gateway","0x1a7126be3438aca07d6d8ff452bfbbf1915fa2f0":"universalEvaluator","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0x011f44c68a9877b052c5de168e499e05573f8db8":"relayer","0xdad018fdf469e68cd5cb63da97a057bb880f947e":"universalGatewayPC","0xc6df7efa69bbc88b352644eb471f353aa45506eb":"urp","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0x49052147f5d97a723debdf07680fffadad29a5dc":"stranger","0x6481431770cb268b1b5085a2c4d1a9f32d802b59":"ceaAdmin","0xa7c25dd02068ddc53ebab008955d97ca81247cef":"provider2","0xaa10a84ce7d9ae517a52c6d5ca153b369af99ecf":"admin","0x9b78803558f9ea56f4f0a966322c8dd9b2fbebc0":"provider","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x6118a5fc63087cb6297bb2b107b22b1b734ff9e9":"WETH.sepolia","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0xaee40976dd07664e7e8bfa60dbb16685177036d3":"ceaImpl","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin"},"duration":"1ms 610µs 458ns","breakpoints":{},"gas_snapshots":{}}},"warnings":[]},"test/8183-tests/ReviewGaps.t.sol:ReviewRealAgwCancellation":{"duration":"36s 126ms 821µs 750ns","test_results":{"test_review_cancelFreesWalletButOldAndNewGrantsBothRemainLive()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":20306518}},"traces":[],"labeled_addresses":{"0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0x15773a5a32018dc9fb19262d7d5f422eadd5d3e9":"forkOwner","0x238ec72e0743bd4c21497d4157854dd3a1dd2f0d":"forkRelayer","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x0bd7513c1db25948b7a05301ec3698f379f4af13":"ceaFactory","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x22aa0d0bcc922d549618bd1ef8253cc8dee5a3cc":"forkProvider","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x540da3418be99da0614998034fcb817e9d8a0644":"forkAdmin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"36s 120ms 520µs 792ns","breakpoints":{},"gas_snapshots":{}},"test_review_ownerCanAtomicallyCancelAndRevokeWithoutNewAgwRole()":{"status":"Success","reason":null,"counterexample":null,"logs":[],"decoded_logs":[],"kind":{"Unit":{"gas":17388935}},"traces":[],"labeled_addresses":{"0xca5453e74f0ccc802add48a547cd965512ffd45d":"evaluator","0x15773a5a32018dc9fb19262d7d5f422eadd5d3e9":"forkOwner","0x238ec72e0743bd4c21497d4157854dd3a1dd2f0d":"forkRelayer","0x919d35e718c04fbc3bd9b098899520515cfdb314":"USDC.sepolia","0x1be57ea2ee4ae3a8330fd2fd90a4cf841b8dc4a5":"aavePool.sepolia","0x0bd7513c1db25948b7a05301ec3698f379f4af13":"ceaFactory","0xf93f5348654f103940e6572fa5e7122c2343845d":"mktAdmin","0xa081e81b06ed97291a863d20895b1842ecadb456":"hookAdmin","0x22aa0d0bcc922d549618bd1ef8253cc8dee5a3cc":"forkProvider","0xe0842c7973a357d001a707bee27e8773f7a8c39a":"ceaProxyImpl","0xd49279c8fc3454d7328eb8777274812e84b658df":"kernelProxyAdminOwner","0xd3776133024ed4410f2977b65e042ab9ede78944":"aUSDC.sepolia","0x540da3418be99da0614998034fcb817e9d8a0644":"forkAdmin","0xf43bca55e8091977223fa5b776e23528d205dca8":"treasury"},"duration":"26s 979ms 895µs 417ns","breakpoints":{},"gas_snapshots":{}}},"warnings":[]}} diff --git a/plan/marketplace/research/2026-10-20/review-workspace.txt b/plan/marketplace/research/2026-10-20/review-workspace.txt new file mode 100644 index 00000000..f1d48567 --- /dev/null +++ b/plan/marketplace/research/2026-10-20/review-workspace.txt @@ -0,0 +1 @@ +/var/folders/4_/d47r2_4s1wb3x2dvmt2ghp800000gp/T/marketplace-review-443b4e2-_ib864pr diff --git a/plan/marketplace/research/2026-10-20/runtime-comparison.json b/plan/marketplace/research/2026-10-20/runtime-comparison.json new file mode 100644 index 00000000..1a3d1382 --- /dev/null +++ b/plan/marketplace/research/2026-10-20/runtime-comparison.json @@ -0,0 +1,140 @@ +{ + "blockNumber": "24447347", + "sourceCommit": "443b4e2dd9ca5dd9ffc8efebdfcecd619dd66c47", + "results": [ + { + "artifact": "UniversalMarketplace.json", + "component": "marketplace", + "address": "0xd683545f84698df4341b0031c892c53384ff30be", + "optimizerRuns": 1000, + "sourceBytes": 22156, + "liveBytes": 22156, + "exactMatch": false, + "executableMatchExcludingMetadata": true, + "builderLinkResolved": true, + "librarySelfAddressNormalized": false, + "executableHash": "0xa427de90878b45e09c78f4ff2dfb9158aa3d737349777960b7247e799ec1ba38", + "expectedExecutableHash": "0xa427de90878b45e09c78f4ff2dfb9158aa3d737349777960b7247e799ec1ba38", + "candidateProfiles": [ + { + "artifact": "UniversalMarketplace.json", + "optimizerRuns": 1000, + "sourceBytes": 22156, + "executableMatchExcludingMetadata": true + } + ] + }, + { + "artifact": "AgenticCommerce.marketplace-size.json", + "component": "kernel", + "address": "0x1d631e9d0e0a7a7423743c3076054c784af8fa40", + "optimizerRuns": 1000, + "sourceBytes": 10930, + "liveBytes": 10930, + "exactMatch": false, + "executableMatchExcludingMetadata": true, + "builderLinkResolved": false, + "librarySelfAddressNormalized": false, + "executableHash": "0x718bd7e85b020816b8893dbb594a58677754c3caad687b4ba3862711daf4e84e", + "expectedExecutableHash": "0x718bd7e85b020816b8893dbb594a58677754c3caad687b4ba3862711daf4e84e", + "candidateProfiles": [ + { + "artifact": "AgenticCommerce.json", + "optimizerRuns": 99999, + "sourceBytes": 14282, + "executableMatchExcludingMetadata": false + }, + { + "artifact": "AgenticCommerce.marketplace-size.json", + "optimizerRuns": 1000, + "sourceBytes": 10930, + "executableMatchExcludingMetadata": true + } + ] + }, + { + "artifact": "RulesBindingHook.marketplace-size.json", + "component": "hook", + "address": "0x58bd6951b653b5028aa77b4904e83df668bcef7e", + "optimizerRuns": 1000, + "sourceBytes": 3477, + "liveBytes": 3477, + "exactMatch": false, + "executableMatchExcludingMetadata": true, + "builderLinkResolved": false, + "librarySelfAddressNormalized": false, + "executableHash": "0x655c3c92cb2c58404bec34fb1480174312de73f6acaa3770d41ac62ff57ba204", + "expectedExecutableHash": "0x655c3c92cb2c58404bec34fb1480174312de73f6acaa3770d41ac62ff57ba204", + "candidateProfiles": [ + { + "artifact": "RulesBindingHook.json", + "optimizerRuns": 99999, + "sourceBytes": 4499, + "executableMatchExcludingMetadata": false + }, + { + "artifact": "RulesBindingHook.marketplace-size.json", + "optimizerRuns": 1000, + "sourceBytes": 3477, + "executableMatchExcludingMetadata": true + } + ] + }, + { + "artifact": "UniversalMarketplaceRules.marketplace-size.json", + "component": "rules", + "address": "0x5b98A8E0df5b918DF76cD2BE84bA7995B39dfd44", + "optimizerRuns": 1000, + "sourceBytes": 7832, + "liveBytes": 7832, + "exactMatch": false, + "executableMatchExcludingMetadata": true, + "builderLinkResolved": false, + "librarySelfAddressNormalized": false, + "executableHash": "0xfbb751181bf0aa2e3ab5273277d689fca1531126a6390c29450d3b394e9be18e", + "expectedExecutableHash": "0xfbb751181bf0aa2e3ab5273277d689fca1531126a6390c29450d3b394e9be18e", + "candidateProfiles": [ + { + "artifact": "UniversalMarketplaceRules.json", + "optimizerRuns": 99999, + "sourceBytes": 9376, + "executableMatchExcludingMetadata": false + }, + { + "artifact": "UniversalMarketplaceRules.marketplace-size.json", + "optimizerRuns": 1000, + "sourceBytes": 7832, + "executableMatchExcludingMetadata": true + } + ] + }, + { + "artifact": "JobSpecBuilder.marketplace-size.json", + "component": "builder", + "address": "0x2de1e3F053b0bBa0cE0C6953144534a0b055f59e", + "optimizerRuns": 1000, + "sourceBytes": 5597, + "liveBytes": 5597, + "exactMatch": false, + "executableMatchExcludingMetadata": true, + "builderLinkResolved": false, + "librarySelfAddressNormalized": false, + "executableHash": "0x85280ca6b74a0b851f8524c435d2c6e5a60fe6e16e924e7c98b59361650d061b", + "expectedExecutableHash": "0x85280ca6b74a0b851f8524c435d2c6e5a60fe6e16e924e7c98b59361650d061b", + "candidateProfiles": [ + { + "artifact": "JobSpecBuilder.json", + "optimizerRuns": 99999, + "sourceBytes": 6352, + "executableMatchExcludingMetadata": false + }, + { + "artifact": "JobSpecBuilder.marketplace-size.json", + "optimizerRuns": 1000, + "sourceBytes": 5597, + "executableMatchExcludingMetadata": true + } + ] + } + ] +} diff --git a/plan/marketplace/research/2026-10-20/summary.json b/plan/marketplace/research/2026-10-20/summary.json new file mode 100644 index 00000000..1b246d1c --- /dev/null +++ b/plan/marketplace/research/2026-10-20/summary.json @@ -0,0 +1,18 @@ +{ + "ordinary_contract_tests": { + "Success": 248, + "Skipped": 2 + }, + "fork_tests": { + "Success": 2 + }, + "bounded_invariants": { + "Success": 10 + }, + "independent_review_cases": { + "Success": 4 + }, + "runtime_matches": 5, + "cea_matches": 4, + "fresh_notion_pages": 6 +} diff --git a/plan/marketplace/research/2026-10-20/validation.md b/plan/marketplace/research/2026-10-20/validation.md new file mode 100644 index 00000000..9306fd2c --- /dev/null +++ b/plan/marketplace/research/2026-10-20/validation.md @@ -0,0 +1,58 @@ +# Validation and limitations — October 20 + +Source pin `443b4e2dd9ca5dd9ffc8efebdfcecd619dd66c47`, source branch sdk-iteration-v1. Remote head was rechecked after the review and remained at that SHA. Full source was archived into an isolated temporary workspace, with all five dependencies at their actual submodule SHAs. No .env file exists in that workspace. SDK production files and sibling working-tree checkouts were not modified by this research. + +## Results + +| Check | Result / evidence | +| --- | --- | +| Fresh Notion download | 6/6 requested page bodies imported from a new stack-index export; ZIP, entries, SHA-256 and timestamp retained in [manifest](notion-source-manifest.json). Visible discussions reviewed separately. | +| Ordinary contract unit/fuzz suite | **248 passed, 0 failed, 2 fork tests skipped** without RPC env. [Summary](contract-test-summary.json), [command/exit](contract-test-command.json), [raw JSON log](contract-tests.log). Source fuzz setting 1,024 runs. Invariant functions excluded from this invocation. | +| Upstream fork suite | **2 passed, 0 skipped/failed**, separately with public Donut RPC. [Summary/commands](fork-tests-summary.json), [log](fork-tests.log). Real AGW v6; marketplace/kernel/hook created on fork. Hook test honors FORK_BLOCK=24447347. The marketplace test selects latest internally; its emitted block is not retained in this quiet JSON artifact, so no exact block is claimed for that case. | +| Kernel/marketplace invariants | **10 passed**, separately at **64 runs × depth 64**, 4,096 handler calls per invariant. [Summary and per-test metrics](invariant-tests-summary.json), [compressed raw log](invariant-tests.log.gz). This is a bounded review configuration, not the repository's full CI invariant budget. | +| Independent review cases | **4 passed**, two local real-kernel/mock-wallet cases and two real-AGW fork cases pinned to 24447347. [Source](ReviewGaps.t.sol), [summary](review-gaps-summary.json), [log](review-gaps.log). Findings below. | +| Live state/code/wiring | Block **24447347**, chain 42101, version 2.0.0, correct factory/kernel/hook/rules/engine/evaluator/token wiring, whitelist true, fees zero, EOA evaluator code empty, 0 cards / 0 jobs. [RPC observations](live-deployment.json). | +| CEA computation | **4/4** supported chain configurations match address book and independent EIP-1167/CREATE2 calculation for a predicted AGW. Checks registered derivation, not destination protocol execution. | +| Runtime/source parity | **5/5** stack component executable runtimes match pinned build after metadata exclusion and explicit library link/self-address resolution. [Profile-by-profile comparison](runtime-comparison.json). All matching artifacts use 1,000 optimizer runs. Full bytecode including metadata differs. | +| Wire comparison | Controlled old/new nonempty JobSpec vectors each roundtrip canonically in their own profile and fail the other decoder. [Vectors/results](wire-comparison.json). Also samples template/spec decoding separately. Does not prove every hostile/ambiguous payload is rejected. | +| ABI collection | Marketplace, kernel, hook, helper, library and complete 40-error library ABIs extracted from pinned build under [contracts/abi](../../contracts/abi). | + +The passes above are separate invocations, not one single full-suite result. Research work did not rerun the SDK's full AGW unit suite; October 18 AGW counts in plan/agw remain earlier evidence. + +## Independent review findings + +1. A BOTH template can register/open/fund today, but arbitrary setBudget replacement bytes are ignored by the interim hook and kernel description stays unchanged. Stored flags are not implemented mutability. +2. Card providerFee is not a protocol-enforced fixed price: funding at three times that reference succeeds when the client accepts that exact budget. +3. Client reject of an Open job frees marketplace occupancy. Old permission remains enabled; opening another job for the same wallet/provider creates a second enabled permission. +4. One owner batch calling kernel.reject and wallet.revokeRules atomically cancels and disables that job's grant on existing real AGW v6. No new AGW stop role is required for this **owner-authorized SDK path**. It does not prove hook/provider-triggered cleanup or external UEA wallet UX. + +The two local cases use the pinned suite's mock AGW signatures; they are not owner-signature proofs. The two cancellation fork cases use the actual factory/wallet/engine and signed OwnerIntent. All fork writes are ephemeral local EVM state, never public transactions. + +## Commands + +Workspace location is captured in review-workspace.txt; source dependencies are pinned in dependency-pins.json. Test records retain exact absolute invocation roots and exit codes. For a fresh run, archive the same Git SHA plus pinned dependencies first; contracts/ is a selected reference snapshot, not a standalone full build tree. + +```sh +forge test --root "$review_root" --match-path 'test/8183-tests/*.t.sol' --no-match-test invariant_ --offline --json +PUSH_CHAIN_TESTNET_RPC_URL=https://evm.donut.rpc.push.org/ FORK_BLOCK=24447347 \ + forge test --root "$review_root" --match-path 'test/8183-tests/*.fork.t.sol' --offline --json +FOUNDRY_INVARIANT_RUNS=64 FOUNDRY_INVARIANT_DEPTH=64 \ + forge test --root "$review_root" --match-path 'test/8183-tests/*.t.sol' --match-test invariant_ --offline --json +# Copy ReviewGaps.t.sol into that workspace's test/8183-tests before this command: +forge test --root "$review_root" --match-path test/8183-tests/ReviewGaps.t.sol --match-test test_review_ --offline --json +node plan/marketplace/scripts/probe-live.cjs +node plan/marketplace/scripts/compare-runtime.cjs +node plan/marketplace/scripts/check-wire.cjs +``` + +RPC scripts use the existing installed viem package, load no keys and have no send/broadcast calls. Runtime comparison uses the saved block and generated artifacts. These scripts currently write this dated evidence directory; select another output directory before a later baseline refresh. + +## Corrections made during verification + +- Initial dependency extraction refused an archived outward symlink. Dependencies were re-extracted at the correct pins with links omitted; final tests use that corrected workspace. +- First standalone RPC probe used predictWallet's index as uint96 because IntentRequest.index is uint96. Factory ABI actually takes uint256; corrected against the pinned interface before the successful probe. Initial failure was a probe ABI mistake, not a contract failure. +- First runtime comparison selected the default 99,999-run dependency artifacts. The live deployments use the 1,000-run variants emitted by the marketplace build profile. Comparison now records both candidates and the matching profile; no unexplained runtime mismatch remains. + +## Not established by this review + +No funded live transaction, card registration, open/fund/execute/settle roundtrip, destination liquidity check, public deployment or publication occurred. No automatic evaluator, baseline, mutable agreement, recurring job or rating was exercised. There were no live registry cards/jobs at the observation to inspect. No full security audit, exhaustive mutation run, all-mainnet claim, complete explorer source verification or user-wallet signing-prompt count is implied. diff --git a/plan/marketplace/research/2026-10-20/wire-comparison.json b/plan/marketplace/research/2026-10-20/wire-comparison.json new file mode 100644 index 00000000..cc957882 --- /dev/null +++ b/plan/marketplace/research/2026-10-20/wire-comparison.json @@ -0,0 +1,50 @@ +{ + "marketplaceSource": "443b4e2dd9ca5dd9ffc8efebdfcecd619dd66c47", + "evaluatorSource": "8059817591cca16c59f1cc154f475f51e1736a67", + "schemaChanges": [ + "JobSpec top-level field order", + "Read.at appended", + "Check.read replaced by left/right arrays", + "Logic checks[] replaced by CHECK leaf structure", + "AllowedMutability.NONE ordinal 0 -> 1; BOTH 3 -> 0", + "Logic ALL ordinal 0 -> 1; ANY 1 -> 2; AT_LEAST 2 -> 3", + "MAX_READS 16 -> 32" + ], + "oldRoundtrip": { + "decoded": true, + "canonicalRoundtrip": true + }, + "newRoundtrip": { + "decoded": true, + "canonicalRoundtrip": true + }, + "oldDecodedAsNew": { + "decoded": false, + "error": "Position `1344` is out of bounds (`0 < position < 1344`)." + }, + "newDecodedAsOld": { + "decoded": false, + "error": "Position `1800000032` is out of bounds (`0 < position < 1472`)." + }, + "deployedJobDecodedAsTemplate": { + "decoded": false, + "error": "Position `1375` is out of bounds (`0 < position < 1344`)." + }, + "templateDecodedAsDeployedJob": { + "decoded": false, + "error": "Number \"3.618509717477737e+75\" is not in safe 8-bit unsigned integer range (0 to 255)" + }, + "old": { + "bytes": "0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006b49d200000000000000000000000000000000000000000000000000000000006b49ee200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000111111111111111111111111111111111111111170a0823100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000066569703135350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000831313135353131310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060800010101000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000001dbe22c0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "hash": "0xd87e5ea5bad8aa297d039a9624f341c16b12c905421e50ec41a8c790785f612f" + }, + "modern": { + "bytes": "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000006b49d200000000000000000000000000000000000000000000000000000000006b49ee2000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000000000000000000000000000000004c0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000111111111111111111111111111111111111111170a082310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000066569703135350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000831313135353131310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060800010101000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000001dbe22c00000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "hash": "0xdb0a5d96f5989b91ceb5552c46d93d31bf24cdb81119d903967fbe5bf82154b9" + }, + "template": { + "bytes": "0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000003600000000000000000000000000000000000000000000000000000000000000420000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005400000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000111111111111111111111111111111111111111170a082310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002400000000000000000000000000000000000000000000000000000000000000006656970313535000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000083131313535313131000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000608000101010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001dbe22c0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "hash": "0xfa711861a92dacf51b35a04f50038d7a5fe9cb13029b3dc90faa8cbb8b85667f" + }, + "scope": "Controlled nonempty ABI vectors, not a proof that every malformed/cross-profile payload is rejected. No evaluator deployment or settlement is tested." +} diff --git a/plan/marketplace/scripts/check-wire.cjs b/plan/marketplace/scripts/check-wire.cjs new file mode 100644 index 00000000..d20a6cef --- /dev/null +++ b/plan/marketplace/scripts/check-wire.cjs @@ -0,0 +1,37 @@ +// Research vectors only: contrasts deployed marketplace wire with the evaluator comment's source. +const fs = require('node:fs'); +const path = require('node:path'); +const { parseAbiParameters, encodeAbiParameters, decodeAbiParameters, keccak256 } = require('viem'); +const oldType = parseAbiParameters('((string,string,uint16,address,bytes4,bytes,bytes,uint8[])[],(uint8,uint8,uint8,int256)[],(uint8,uint8[],uint8[],uint8)[],uint8,bytes32,uint64,uint64)'); +const newType = parseAbiParameters('(uint64,uint64,(string,string,uint16,address,bytes4,bytes,bytes,uint8[],uint8)[],(uint8[],uint8[],uint8,uint8,int256)[],(uint8,uint8,uint8[],uint8)[],uint8,bytes32)'); +const templateType = parseAbiParameters('((string,string,uint16,address,bytes4,bytes,(uint8,uint8,uint8)[],bytes,uint8[])[],(uint8,uint8,uint8,uint8,int256)[],(uint8,uint8[],uint8[],uint8)[],uint8,(int256,int256)[])'); +const zeroHash = '0x' + '00'.repeat(32); +const read = ['eip155','11155111',12,'0x1111111111111111111111111111111111111111','0x70a08231','0x'+'00'.repeat(32),'0x080001010100',[0]]; +const old = [[read],[[0,1,3,499_000_000n]],[[0,[0],[],0]],0,zeroHash,1_800_000_000n,1_800_007_200n]; +// New evaluator NONE=1 and CHECK=0, ALL=1. These are different ordinal mappings. +const modern = [1_800_000_000n,1_800_007_200n,[[...read,0]],[[[0],[],1,3,499_000_000n]],[[0,0,[],0]],1,zeroHash]; +const oldBytes = encodeAbiParameters(oldType,[old]); +const newBytes = encodeAbiParameters(newType,[modern]); +const template = [[[...read.slice(0,6),[],...read.slice(6)]],[[0,1,3,0,499_000_000n]],[[0,[0],[],0]],0,[]]; +const templateBytes = encodeAbiParameters(templateType,[template]); +function attempt(bytes, schema) { + try { + const decoded = decodeAbiParameters(schema, bytes); + return { decoded: true, canonicalRoundtrip: encodeAbiParameters(schema, decoded).toLowerCase() === bytes.toLowerCase() }; + } catch (error) { return { decoded: false, error: error.shortMessage || error.message }; } +} +const report = { + marketplaceSource: '443b4e2dd9ca5dd9ffc8efebdfcecd619dd66c47', + evaluatorSource: '8059817591cca16c59f1cc154f475f51e1736a67', + schemaChanges: ['JobSpec top-level field order', 'Read.at appended', 'Check.read replaced by left/right arrays', 'Logic checks[] replaced by CHECK leaf structure', 'AllowedMutability.NONE ordinal 0 -> 1; BOTH 3 -> 0', 'Logic ALL ordinal 0 -> 1; ANY 1 -> 2; AT_LEAST 2 -> 3', 'MAX_READS 16 -> 32'], + oldRoundtrip: attempt(oldBytes,oldType), newRoundtrip: attempt(newBytes,newType), + oldDecodedAsNew: attempt(oldBytes,newType), newDecodedAsOld: attempt(newBytes,oldType), + deployedJobDecodedAsTemplate: attempt(oldBytes,templateType), templateDecodedAsDeployedJob: attempt(templateBytes,oldType), + old: { bytes: oldBytes, hash: keccak256(oldBytes) }, modern: { bytes: newBytes, hash: keccak256(newBytes) }, + template: { bytes: templateBytes, hash: keccak256(templateBytes) }, + scope: 'Controlled nonempty ABI vectors, not a proof that every malformed/cross-profile payload is rejected. No evaluator deployment or settlement is tested.' +}; +const out = path.resolve(__dirname,'../research/2026-10-20/wire-comparison.json'); +fs.writeFileSync(out,JSON.stringify(report,null,2)+'\n'); +console.log(JSON.stringify(Object.fromEntries(Object.entries(report).filter(([key])=>!['old','modern','template'].includes(key))),null,2)); +if (!report.oldRoundtrip.canonicalRoundtrip || !report.newRoundtrip.canonicalRoundtrip) process.exitCode=1; diff --git a/plan/marketplace/scripts/compare-runtime.cjs b/plan/marketplace/scripts/compare-runtime.cjs new file mode 100644 index 00000000..922701f7 --- /dev/null +++ b/plan/marketplace/scripts/compare-runtime.cjs @@ -0,0 +1,52 @@ +// Compares the pinned build to live code using the block from probe-live.cjs. +const fs = require('node:fs'); +const path = require('node:path'); +const { createPublicClient, http, keccak256 } = require('viem'); +const ROOT = path.resolve(__dirname, '..'); +const EVIDENCE = path.join(ROOT, 'research/2026-10-20'); +const workspace = fs.readFileSync(path.join(EVIDENCE, 'review-workspace.txt'), 'utf8').trim(); +const live = JSON.parse(fs.readFileSync(path.join(EVIDENCE, 'live-deployment.json'), 'utf8')); +const names = { marketplace: 'UniversalMarketplace', kernel: 'AgenticCommerce', hook: 'RulesBindingHook', rules: 'UniversalMarketplaceRules', builder: 'JobSpecBuilder' }; +function stripMetadata(code) { + const bytes = (code.length - 2) / 2; + const length = Number.parseInt(code.slice(-4), 16); + if (length > 0 && length + 2 < bytes) return code.slice(0, -(length + 2) * 2); + return code; +} +async function main() { + const client = createPublicClient({ transport: http(live.rpc) }); + const results = []; + for (const [key, name] of Object.entries(names)) { + const folder = path.join(workspace, 'out', `${name}.sol`); + const candidates = fs.readdirSync(folder).filter(file => file.startsWith(name + '.') && file.endsWith('.json')); + const comparisons = []; + for (const file of candidates) { + const artifact = JSON.parse(fs.readFileSync(path.join(folder, file), 'utf8')); + const address = live.components[key].implementation || live.addresses[key]; + let expected = artifact.deployedBytecode.object; + for (const refs of Object.values(artifact.deployedBytecode.linkReferences || {})) { + for (const entries of Object.values(refs)) { + for (const ref of entries) { + const start = 2 + ref.start * 2; + expected = expected.slice(0, start) + live.addresses.builder.slice(2) + expected.slice(start + ref.length * 2); + } + } + } + const actual = await client.getCode({ address, blockNumber: BigInt(live.blockNumber) }); + // Solidity's deployed library runtime substitutes its own address for PUSH20 0. + let selfAddressNormalized = false; + if (key === 'builder' && expected.startsWith('0x730000000000000000000000000000000000000000')) { + expected = '0x73' + address.slice(2) + expected.slice(44); + selfAddressNormalized = true; + } + const a = stripMetadata(actual).toLowerCase(); + const e = stripMetadata(expected).toLowerCase(); + comparisons.push({ artifact: file, component: key, address, optimizerRuns: artifact.metadata.settings.optimizer.runs, sourceBytes: (expected.length - 2) / 2, liveBytes: (actual.length - 2) / 2, exactMatch: actual.toLowerCase() === expected.toLowerCase(), executableMatchExcludingMetadata: a === e, builderLinkResolved: key === 'marketplace', librarySelfAddressNormalized: selfAddressNormalized, executableHash: keccak256(a), expectedExecutableHash: keccak256(e) }); + } + const selected = comparisons.find(item => item.executableMatchExcludingMetadata) || comparisons[0]; + results.push({ ...selected, candidateProfiles: comparisons.map(({artifact, optimizerRuns, sourceBytes, executableMatchExcludingMetadata}) => ({artifact, optimizerRuns, sourceBytes, executableMatchExcludingMetadata})) }); + } + fs.writeFileSync(path.join(EVIDENCE, 'runtime-comparison.json'), JSON.stringify({ blockNumber: live.blockNumber, sourceCommit: '443b4e2dd9ca5dd9ffc8efebdfcecd619dd66c47', results }, null, 2) + '\n'); + console.log(JSON.stringify(results.map(({ component, sourceBytes, liveBytes, exactMatch, executableMatchExcludingMetadata }) => ({ component, sourceBytes, liveBytes, exactMatch, executableMatchExcludingMetadata })), null, 2)); +} +main().catch(error => { console.error(error); process.exitCode = 1; }); diff --git a/plan/marketplace/scripts/probe-live.cjs b/plan/marketplace/scripts/probe-live.cjs new file mode 100644 index 00000000..15d2051b --- /dev/null +++ b/plan/marketplace/scripts/probe-live.cjs @@ -0,0 +1,68 @@ +// Read-only Donut deployment probe. Never loads keys or broadcasts transactions. +const fs = require('node:fs'); +const path = require('node:path'); +const { + createPublicClient, http, parseAbi, keccak256, encodeAbiParameters, + parseAbiParameters, getCreate2Address, +} = require('viem'); + +const ROOT = path.resolve(__dirname, '..'); +const OUT = path.join(ROOT, 'research/2026-10-20/live-deployment.json'); +const addresses = { + marketplace: '0x9071ebE01B75123A91e88eB6ec4BF163F3fE9BF4', + kernel: '0x977cf1AC973E9eC4332791d531507575006157Ed', + hook: '0xDe7A94e510b6C571DE7880d441349689F73A32b3', + rules: '0x5b98A8E0df5b918DF76cD2BE84bA7995B39dfd44', + builder: '0x2de1e3F053b0bBa0cE0C6953144534a0b055f59e', + factory: '0xFBBEB6a365178fAaA81A9789a5f64b300c37e5bc', + engine: '0xf63DC0628fe1B25049FE3E3a3585Ef051CB98c1d', + pUSDC: '0x7A58048036206bB898008b5bBDA85697DB1e5d66', + evaluator: '0x1afC81396f1bb36F91f74506284952b81e4bd47c', +}; +const implementationSlot = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc'; +const adminSlot = '0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103'; +const getters = { + marketplace: ['version() view returns (string)', 'AGW_FACTORY() view returns (address)', 'KERNEL() view returns (address)', 'RULES() view returns (address)', 'hook() view returns (address)', 'evaluator() view returns (address)', 'PUSH_CHAIN_HASH() view returns (bytes32)', 'agentCardCount() view returns (uint256)', 'OPENJOB_LANE() view returns (uint192)', 'paused() view returns (bool)'], + kernel: ['paymentToken() view returns (address)', 'jobCounter() view returns (uint256)', 'platformFeeBP() view returns (uint256)', 'evaluatorFeeBP() view returns (uint256)', 'EVALUATOR_GRACE_PERIOD() view returns (uint256)', 'MIN_EXPIRY_WINDOW() view returns (uint256)', 'paused() view returns (bool)'], + hook: ['KERNEL() view returns (address)', 'AGW_FACTORY() view returns (address)', 'SESSION_ENGINE() view returns (address)'], + pUSDC: ['symbol() view returns (string)', 'decimals() view returns (uint8)'], +}; +async function main() { + const client = createPublicClient({ transport: http('https://evm.donut.rpc.push.org/', { timeout: 20000, retryCount: 2 }) }); + const blockNumber = await client.getBlockNumber(); + const report = { observedAt: new Date().toISOString(), rpc: 'https://evm.donut.rpc.push.org/', chainId: await client.getChainId(), blockNumber, addresses, components: {}, getters: {}, chains: [], errors: [] }; + await Promise.all(Object.entries(addresses).map(async ([name, address]) => { + try { + const code = (await client.getCode({ address, blockNumber })) || '0x'; + report.components[name] = { address, codeBytes: (code.length - 2) / 2, codeHash: keccak256(code) }; + if (['marketplace', 'kernel', 'hook'].includes(name)) { + const [impl, admin] = await Promise.all([implementationSlot, adminSlot].map(slot => client.getStorageAt({ address, slot, blockNumber }))); + report.components[name].implementation = '0x' + impl.slice(-40); + report.components[name].proxyAdmin = '0x' + admin.slice(-40); + const implCode = (await client.getCode({ address: report.components[name].implementation, blockNumber })) || '0x'; + report.components[name].implementationCodeBytes = (implCode.length - 2) / 2; + report.components[name].implementationCodeHash = keccak256(implCode); + } + } catch (error) { report.errors.push({ stage: 'code', name, message: error.shortMessage || error.message }); } + })); + await Promise.all(Object.entries(getters).flatMap(([name, signatures]) => signatures.map(async signature => { + const fn = signature.slice(0, signature.indexOf('(')); + try { report.getters[`${name}.${fn}`] = await client.readContract({ address: addresses[name], abi: parseAbi(['function ' + signature]), functionName: fn, blockNumber }); } + catch (error) { report.errors.push({ stage: 'getter', name, fn, message: error.shortMessage || error.message }); } + }))); + report.getters['kernel.whitelistedHooks'] = await client.readContract({ address: addresses.kernel, abi: parseAbi(['function whitelistedHooks(address) view returns (bool)']), functionName: 'whitelistedHooks', args: [addresses.hook], blockNumber }); + const owner = '0x1111111111111111111111111111111111111111'; + const [wallet, deployed] = await client.readContract({ address: addresses.factory, abi: parseAbi(['function predictWallet(address,uint256) view returns (address,bool)']), functionName: 'predictWallet', args: [owner, 0n], blockNumber }); + report.sampleWallet = { owner, index: 0, wallet, deployed }; + for (const chain of ['eip155:11155111', 'eip155:84532', 'eip155:421614', 'eip155:97']) { + const chainHash = keccak256(Buffer.from(chain)); + const [factory, implementation] = await client.readContract({ address: addresses.marketplace, abi: parseAbi(['function ceaDeployment(bytes32) view returns (address,address)']), functionName: 'ceaDeployment', args: [chainHash], blockNumber }); + const cea = await client.readContract({ address: addresses.marketplace, abi: parseAbi(['function computeCEA(address,bytes32) view returns (address)']), functionName: 'computeCEA', args: [wallet, chainHash], blockNumber }); + const init = `0x3d602d80600a3d3981f3363d3d373d3d3d363d73${implementation.slice(2)}5af43d82803e903d91602b57fd5bf3`; + const independentCEA = getCreate2Address({ from: factory, salt: keccak256(encodeAbiParameters(parseAbiParameters('address'), [wallet])), bytecodeHash: keccak256(init) }); + report.chains.push({ chain, chainHash, factory, implementation, cea, independentCEA, matches: cea.toLowerCase() === independentCEA.toLowerCase() }); + } + fs.writeFileSync(OUT, JSON.stringify(report, (_, value) => typeof value === 'bigint' ? value.toString() : value, 2) + '\n'); + console.log(JSON.stringify({ file: OUT, blockNumber: blockNumber.toString(), version: report.getters['marketplace.version'], cards: String(report.getters['marketplace.agentCardCount']), jobs: String(report.getters['kernel.jobCounter']), errors: report.errors, ceaChecks: report.chains.map(x => ({ chain: x.chain, matches: x.matches })) }, null, 2)); +} +main().catch(error => { console.error(error); process.exitCode = 1; }); From fbd0e032940e523b18bb0d6f8fd80b23beae1c67 Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Tue, 20 Oct 2026 16:51:39 +0530 Subject: [PATCH 57/68] feat(core): add marketplace v2 and job SDK primitives --- packages/core/MARKETPLACE.md | 148 + packages/core/__e2e__/ci/suite.ts | 6 +- .../__e2e__/marketplace/lifecycle.spec.ts | 131 + .../__e2e__/marketplace/readiness.spec.ts | 55 + .../core/__market-local__/marketplace.spec.ts | 402 + packages/core/__market-local__/setup.ts | 42 + .../core/jest.marketplace-local.config.ts | 15 + packages/core/package.json | 1 + packages/core/scripts/check-agw-api.js | 3 + packages/core/scripts/check-agw-docs.js | 7 +- packages/core/scripts/check-agw-package.js | 10 +- .../__tests__/response-surface.spec.ts | 2 + packages/core/src/lib/agentic/constants.ts | 15 +- .../core/src/lib/agentic/contracts/reader.ts | 2 + packages/core/src/lib/agentic/errors.ts | 13 +- packages/core/src/lib/index.ts | 40 + .../src/lib/job-spec/__tests__/codec.spec.ts | 190 + packages/core/src/lib/job-spec/codec.ts | 452 + packages/core/src/lib/job-spec/constants.ts | 32 + packages/core/src/lib/job-spec/helpers.ts | 157 + packages/core/src/lib/job-spec/index.ts | 34 + packages/core/src/lib/job-spec/read.ts | 273 + packages/core/src/lib/job-spec/schema.ts | 66 + packages/core/src/lib/job-spec/types.ts | 111 + packages/core/src/lib/job/job.ts | 685 + packages/core/src/lib/job/types.ts | 98 + .../lib/market/__tests__/kernel-wire.spec.ts | 55 + .../lib/market/__tests__/namespace.spec.ts | 123 + .../src/lib/market/__tests__/rules.spec.ts | 115 + .../lib/market/contracts/AgenticCommerce.ts | 1313 ++ .../lib/market/contracts/RulesBindingHook.ts | 310 + .../market/contracts/UniversalMarketplace.ts | 2291 +++ .../contracts/UniversalMarketplaceErrors.ts | 412 + .../contracts/UniversalMarketplaceRules.ts | 319 + packages/core/src/lib/market/deployment.ts | 26 + packages/core/src/lib/market/errors.ts | 89 + packages/core/src/lib/market/index.ts | 8 + packages/core/src/lib/market/kernel-wire.ts | 73 + packages/core/src/lib/market/market.ts | 794 + packages/core/src/lib/market/rules.ts | 417 + packages/core/src/lib/market/runtime.ts | 232 + packages/core/src/lib/market/types.ts | 144 + .../core/src/lib/push-chain/push-chain.ts | 24 +- packages/core/src/lib/utils.ts | 4 + packages/core/tsconfig.marketplace-local.json | 5 + plan/SDK-CHANGELOG.md | 10 + plan/marketplace/README.md | 3 +- plan/marketplace/current-baseline.md | 2 + plan/marketplace/implementation-plan.md | 2 + plan/marketplace/implementation-status.md | 50 + plan/marketplace/questions.md | 2 + .../sdk-implementation-2026-10-20/README.md | 42 + .../api-comparison.json | 13167 ++++++++++++++++ .../cea-routing.json | 85 + .../checked-files.json | 185 + .../fork-results.json | 1 + .../live-evidence.json | 41 + .../live-results.json | 17 + .../post-live-state.json | 11 + .../readonly-results.json | 1 + .../unit-results.json | 1 + .../validation-summary.json | 30 + 62 files changed, 23379 insertions(+), 15 deletions(-) create mode 100644 packages/core/MARKETPLACE.md create mode 100644 packages/core/__e2e__/marketplace/lifecycle.spec.ts create mode 100644 packages/core/__e2e__/marketplace/readiness.spec.ts create mode 100644 packages/core/__market-local__/marketplace.spec.ts create mode 100644 packages/core/__market-local__/setup.ts create mode 100644 packages/core/jest.marketplace-local.config.ts create mode 100644 packages/core/src/lib/job-spec/__tests__/codec.spec.ts create mode 100644 packages/core/src/lib/job-spec/codec.ts create mode 100644 packages/core/src/lib/job-spec/constants.ts create mode 100644 packages/core/src/lib/job-spec/helpers.ts create mode 100644 packages/core/src/lib/job-spec/index.ts create mode 100644 packages/core/src/lib/job-spec/read.ts create mode 100644 packages/core/src/lib/job-spec/schema.ts create mode 100644 packages/core/src/lib/job-spec/types.ts create mode 100644 packages/core/src/lib/job/job.ts create mode 100644 packages/core/src/lib/job/types.ts create mode 100644 packages/core/src/lib/market/__tests__/kernel-wire.spec.ts create mode 100644 packages/core/src/lib/market/__tests__/namespace.spec.ts create mode 100644 packages/core/src/lib/market/__tests__/rules.spec.ts create mode 100644 packages/core/src/lib/market/contracts/AgenticCommerce.ts create mode 100644 packages/core/src/lib/market/contracts/RulesBindingHook.ts create mode 100644 packages/core/src/lib/market/contracts/UniversalMarketplace.ts create mode 100644 packages/core/src/lib/market/contracts/UniversalMarketplaceErrors.ts create mode 100644 packages/core/src/lib/market/contracts/UniversalMarketplaceRules.ts create mode 100644 packages/core/src/lib/market/deployment.ts create mode 100644 packages/core/src/lib/market/errors.ts create mode 100644 packages/core/src/lib/market/index.ts create mode 100644 packages/core/src/lib/market/kernel-wire.ts create mode 100644 packages/core/src/lib/market/market.ts create mode 100644 packages/core/src/lib/market/rules.ts create mode 100644 packages/core/src/lib/market/runtime.ts create mode 100644 packages/core/src/lib/market/types.ts create mode 100644 packages/core/tsconfig.marketplace-local.json create mode 100644 plan/marketplace/implementation-status.md create mode 100644 plan/marketplace/research/sdk-implementation-2026-10-20/README.md create mode 100644 plan/marketplace/research/sdk-implementation-2026-10-20/api-comparison.json create mode 100644 plan/marketplace/research/sdk-implementation-2026-10-20/cea-routing.json create mode 100644 plan/marketplace/research/sdk-implementation-2026-10-20/checked-files.json create mode 100644 plan/marketplace/research/sdk-implementation-2026-10-20/fork-results.json create mode 100644 plan/marketplace/research/sdk-implementation-2026-10-20/live-evidence.json create mode 100644 plan/marketplace/research/sdk-implementation-2026-10-20/live-results.json create mode 100644 plan/marketplace/research/sdk-implementation-2026-10-20/post-live-state.json create mode 100644 plan/marketplace/research/sdk-implementation-2026-10-20/readonly-results.json create mode 100644 plan/marketplace/research/sdk-implementation-2026-10-20/unit-results.json create mode 100644 plan/marketplace/research/sdk-implementation-2026-10-20/validation-summary.json diff --git a/packages/core/MARKETPLACE.md b/packages/core/MARKETPLACE.md new file mode 100644 index 00000000..4e0225fc --- /dev/null +++ b/packages/core/MARKETPLACE.md @@ -0,0 +1,148 @@ +# Agentic marketplace and jobs + +This SDK checkpoint targets UniversalMarketplace v2 on Push Donut, its pUSDC kernel and AGW v6. It implements card management, JobSpec authoring, preview/open for native owners without delegation, and the kernel lifecycle. The evaluator is currently an EOA: there is no automatic verification, baseline or rating claim. + +`PushChain.initialize` now exposes `client.market` and `client.job`. Helpers are `PushChain.utils.market` and `PushChain.utils.job`; vocabulary is under `PushChain.CONSTANTS.AGENTIC`. There is no separate `client.evaluation` namespace. Read-only clients can discover cards and jobs. + +## Author a card + +Use verified application/token addresses and raw token units. The following helper returns permissions and a criteria template; it does not sign or send anything. + +```ts +import { PushChain, MarketError, type AgentCardInput, type AgentCardRules } from '@pushchain/core'; +import { parseAbi, type Address } from 'viem'; + +function authorCard(app: Address, token: Address, receiptToken: Address) { + const { WALLET, PRINCIPAL, JOB } = PushChain.CONSTANTS.AGENTIC; + const read = PushChain.utils.job.prepareRead({ + chain: PushChain.CONSTANTS.CHAIN.BNB_TESTNET, + target: receiptToken, + abi: parseAbi(['function balanceOf(address) view returns (uint256)']), + functionName: 'balanceOf', + args: [WALLET], + }); + const jobSpecTemplate = PushChain.utils.job.buildJobSpecTemplate({ + reads: [read], + checks: [{ read: 0, evaluation: JOB.EVALUATION.COMPARE, operation: JOB.OPERATION.GREATER_OR_EQUAL, target: { principalBps: 9990n } }], + logic: JOB.LOGIC.ALL, + allowedMutability: JOB.ALLOWED_MUTABILITY.NONE, + }); + const rules: AgentCardRules = { + assets: [{ token, maxPerCall: PRINCIPAL, maxTotal: PRINCIPAL }], + principalAsset: 0, + maxGasPerCall: 10n ** 18n, + allowedCalls: [ + { target: token, selector: 'approve(address,uint256)', pins: [{ arg: 0, expected: app }, { arg: 1, max: PRINCIPAL }] }, + { target: app, selector: 'supply(address,uint256,address,uint16)', pins: [{ arg: 0, expected: token }, { arg: 1, max: PRINCIPAL }, { arg: 2, expected: WALLET }] }, + ], + }; + PushChain.utils.market.validateAgentCardRules(rules); + return { rules, jobSpecTemplate }; +} +``` + +`client.universal.read.prepare(options)` is the same pure authoring helper. Existing async `universal.prepareRead(subject, options)` remains the paid-request preparation API. They produce different representations. WALLET/PARAM holes retain explicit positions; a literal zero is never guessed to be a placeholder. Dynamic-layout placeholders are refused. + +Cards name one execution chain and one provider. Destination tokens resolve to verified Push PRC20 routes on that chain. An explicit `{ prc20: address }` is available for already-known Push tokens and is returned by lossless rule decoding. No route or same-symbol alias is invented. Structural validation alone does not establish deployment or liquidity readiness. + +Approvals are **allowed calls with spender/amount pins** in v2. There is no separate `approvals[]` field or automatic owner-approval deposit step. Principal caps meter outbound tokens from Push; they are not a destination-lifetime trading budget. Spec comparisons use raw units; the receipt token must have the units expected by the criterion. + +## Register, preview and open + +```ts +async function registerOffer( + provider: PushChain, + listing: AgentCardInput, + app: Address, + token: Address, + receiptToken: Address, +) { + const authored = authorCard(app, token, receiptToken); + return provider.market.agent.register(listing, authored); +} + +async function openReviewedJob(owner: PushChain, cardId: bigint) { + const now = Math.floor(Date.now() / 1000); + const plan = await owner.market.preview(cardId, { + principal: 100_000_000n, + executeBy: now + 3600, + expiredAt: now + 86400, + }); + // Render every mayDo/mayMove/judgedBy entry and the logic before signing. + return owner.market.openJob(plan, { + progressHook: event => console.log(event.id, event.message), + }); +} +``` + +Opening deploys/reuses the AGW, grants the card's exact resolved permissions and creates an Open job. It moves no principal or fee. The plan is revalidated before signing; changed card versions, nonces, occupancy or plan content require a new preview. OwnerIntent authorization uses the factory EIP-712 domain. Client submission can require a second wallet interaction; no relay is supplied in this checkpoint. + +Opening currently requires a Push-native owner with no contract/delegation code. External/contract/delegated owner signing returns `CAPABILITY_UNAVAILABLE` before prompting. Provider writes use the connected signer's ordinary Push identity, including when the instance also has an AGW execution context. + +**Current destination readiness:** BSC Testnet has passing live open/cancel coverage. Sepolia, Base Sepolia and Arbitrum Sepolia have different CEA factories in the marketplace configuration and current SDK routing table; preview returns `CEA_MISMATCH`. The SDK does not substitute the marketplace's account for an independently derived account. Align the deployment/routing configuration before opening on those chains. + +Card IDs, versions, ratings and job IDs are bigint. `jobType` reads are the canonical bytes32 hash, not a guessed original name. `cards` walks IDs with bounded concurrency; summaries remain readable even if an unverified provider stored a malformed template. Full `card` decoding/preview rejects unsupported content. `agent.card`, `agent.update` and `agent.setActive` manage the provider's one card. Preserve raw `rulesBytes`/`jobSpecTemplateBytes` for archival rather than serializing away unknown wire metadata. + +## Fund and track the kernel lifecycle + +```ts +async function priceAndFund(provider: PushChain, owner: PushChain, jobId: bigint) { + // First fund the AGW with the payment token, principal and PC appropriate to the job. + await (await provider.job.setBudget(jobId, 5_000_000n)).wait(); + // Explicitly pass the price the client reviewed; never silently accept a re-quote. + return owner.job.fund(jobId, { expectedBudget: 5_000_000n }); +} + +async function trackJob(client: PushChain, provider: PushChain, jobId: bigint) { + const stop = client.job.watch(jobId, event => console.log(event.kind)); + const job = await client.job.status(jobId); + await (await provider.job.submit(jobId, { deliverable: 'ipfs://deliverable' })).wait(); + stop(); + return job; +} +``` + +The kernel currently accepts pUSDC (`USDC.eth`, 6 decimals) only; explicit mismatching payment tokens are rejected. A card's providerFee is a reference price. For an unchanged marketplace card version, omitted expectedBudget uses that reference; plain jobs or changed card versions need an explicit reviewed amount. A zero-price job is valid. + +For AGW clients, fund verifies ownership, rule/provider identity and expiry, then batches any necessary ERC20 allowance change and escrow funding through the owner door. This allowance is distinct from the AGW's automatic gateway allowance. Plain-client allowance/fund batching requires a supported atomic signer transport; the SDK does not silently fall back to sequential acceptance. + +`status` reads the kernel and hook, retains binary description bytes, decodes supported v2 JobSpecs, and recovers deliverable from submission logs. `evaluation.available` is false for this manual/unverified evaluator profile; frozen/baseline/verdict data is not fabricated. Plain text descriptions may have no decoded JobSpec. `list` can filter client/provider/status; `watch` polls bounded event ranges, reports read errors, supports a starting block and returns a stop function. It is not an indexer or a reorg-finality service. + +```ts +async function stopOpenJob(owner: PushChain, jobId: bigint) { + // For marketplace AGWs, one owner batch rejects the Open job and revokes its recorded grant. + return owner.job.cancel(jobId); +} + +function marketplaceErrorText(error: unknown): string { + return error instanceof MarketError ? error.userMessage : 'Check transaction activity before retrying.'; +} +``` + +Cancellation is client-side Open-job rejection. A plain job has no marketplace grant to infer. Other terminal paths do not imply AGW permission revocation. `claimRefund` respects expiry/grace and remains available while the kernel is paused; a third party may trigger it, with funds returned to the recorded client. + +Plain jobs can use `job.create` with provider/evaluator/hook/expiry/paymentToken plus either binary jobSpec or text description. The kernel's Solidity string slot can carry binary JobSpec bytes; the SDK preserves them and retains the original createJob selector. + +## Explicit placeholders + +- `market.deposit`: historical-card deposit/resumption policy remains pending. Fund the wallet explicitly; do not recompute an old job from the current card version. +- `job.verify`, baseline/prefund/retry integration: no compatible automatic evaluator is configured. A different linked evaluator source has a different wire and enum values. +- Replacement JobSpecs, non-NONE marketplace criteria, recurring jobs, relay and external/delegated OwnerIntent signing are unavailable. +- `utils.job.previewJobSpec`: paid read/callback and fee behavior remains gated. Pure build/encode/decode/describe helpers work without a network. + +Unsupported paths throw before signing/sending. They do not return successful dummy results. Keep message, code, details and cause for diagnostics. + +## E2E validation + +From the repository root: + +```sh +# Real deployed stack on an isolated Anvil fork; no private keys or public-chain writes. +node node_modules/jest/bin/jest.js --config packages/core/jest.marketplace-local.config.ts --runInBand +# Read-only live Donut acceptance. +node node_modules/ts-node/dist/bin.js --compiler-options '{"module":"commonjs"}' packages/core/__e2e__/ci/run.ts --group marketplace +# Explicit funded smoke, using packages/core/.env: fresh provider/card/owner/wallet, then cancel/revoke/deactivate. +node node_modules/ts-node/dist/bin.js --compiler-options '{"module":"commonjs"}' packages/core/__e2e__/ci/run.ts --group marketplace-live +``` + +Marketplace groups stay out of the runner's default `all`. Live smoke spends bounded PC for gas/test wallets and does not move principal or escrow tokens. Nonzero escrow, allowance, payout, manual completion and pause/refund are tested separately on the local fork. No destination protocol execution or automated verdict is implied by those results. diff --git a/packages/core/__e2e__/ci/suite.ts b/packages/core/__e2e__/ci/suite.ts index 56dd7c9a..adb23978 100644 --- a/packages/core/__e2e__/ci/suite.ts +++ b/packages/core/__e2e__/ci/suite.ts @@ -39,6 +39,8 @@ export const GROUPS = [ 'agw-svm-replay', 'agw-presets', 'agw-presets-expanded', + 'marketplace', + 'marketplace-live', ] as const; export type Group = (typeof GROUPS)[number]; @@ -169,6 +171,8 @@ const F = { } as const; export const SCENARIOS: Scenario[] = [ + { id: 'marketplace-native-lifecycle', group: 'marketplace-live', file: '__e2e__/marketplace/lifecycle.spec.ts', grep: 'marketplace live 1\\. native provider registration', needs: { masterPC: '0.5' }, env: { MARKETPLACE_LIVE_E2E: '1', AGW_E2E_AGENT_PC: '0.1' }, note: 'Fresh provider/card/wallet only; no principal export or fee escrow. Cancels and revokes its own permission.' }, + { id: 'marketplace-readonly-bindings', group: 'marketplace', file: '__e2e__/marketplace/readiness.spec.ts', grep: 'marketplace deployed v2 read-only', needs: {}, note: 'Unfunded public SDK card/job enumeration and capability gates; no signing keys.' }, { id: 'agw-svm-replay-positive', group: 'agw-svm-replay', @@ -1210,7 +1214,7 @@ export function scenariosFor(group: string | undefined): Scenario[] { if (!group || group === 'all') { // AGW stays opt-in: scenarios create/fund fresh wallets and consume testnet funds. return SCENARIOS.filter( - (s) => s.group !== 'known-fail' && !s.group.startsWith('agw') + (s) => s.group !== 'known-fail' && !s.group.startsWith('agw') && !s.group.startsWith('marketplace') ); } if (!(GROUPS as readonly string[]).includes(group)) { diff --git a/packages/core/__e2e__/marketplace/lifecycle.spec.ts b/packages/core/__e2e__/marketplace/lifecycle.spec.ts new file mode 100644 index 00000000..90742f12 --- /dev/null +++ b/packages/core/__e2e__/marketplace/lifecycle.spec.ts @@ -0,0 +1,131 @@ +/** Opt-in funded Donut smoke. Only PC gas/fresh provider funding moves; principal and escrow stay zero. */ +import { parseAbi, parseEther, type Address } from 'viem'; +import { generatePrivateKey } from 'viem/accounts'; +import { PushChain } from '../../src'; +import { CHAIN } from '../../src/lib/constants/enums'; +import { setupAgw, evmClient, type AgwFixture } from '../agw/_fixture'; +import { DONUT_MARKETPLACE as D } from '../../src/lib/market/deployment'; +const d = + process.env['MARKETPLACE_LIVE_E2E'] === '1' ? describe : describe.skip; +d('marketplace live', () => { + let f: AgwFixture; + let provider: PushChain; + let owner: PushChain; + let cardId: bigint | undefined; + let opened: + | { jobId: bigint; wallet: Address; rulesId: `0x${string}` } + | undefined; + beforeAll(async () => { + f = await setupAgw(); + provider = await evmClient( + f.agentKey, + CHAIN.PUSH_TESTNET_DONUT, + f.manifest.network + ); + const ownerKey = generatePrivateKey(); + owner = await evmClient(ownerKey, CHAIN.PUSH_TESTNET_DONUT, f.manifest.network); + await f.fundPC(owner.universal.account as Address, parseEther('0.1')); + }, 300000); + afterAll(async () => { + // Best-effort cleanup after failures, restricted to this run's own fresh card and wallet. + if (opened && (await owner.job.status(opened.jobId)).status === 'Open') + await (await owner.job.cancel(opened.jobId)).wait(); + if (cardId && (await provider.market.card(cardId)).active) + await (await provider.market.agent.setActive(cardId, false)).wait(); + f?.teardown(); + }); + it('1. native provider registration, reviewed open and atomic cancel/revoke on BSC Testnet', async () => { + const target = PushChain.CONSTANTS.MOVEABLE.TOKEN.BNB_TESTNET.USDT + .address as Address; + const read = PushChain.utils.job.prepareRead({ + chain: CHAIN.BNB_TESTNET, + target, + abi: parseAbi(['function balanceOf(address) view returns (uint256)']), + functionName: 'balanceOf', + args: [PushChain.CONSTANTS.AGENTIC.WALLET], + }); + const template = PushChain.utils.job.buildJobSpecTemplate({ + reads: [read], + checks: [ + { + read: 0, + evaluation: 'COMPARE', + operation: 'GREATER_OR_EQUAL', + target: BigInt(0), + }, + ], + logic: 'ALL', + }); + const registered = await provider.market.agent.register( + { + jobType: 'SDK_MARKETPLACE_SMOKE', + metadataURI: 'https://example.invalid/push-sdk-test', + metadataHash: ('0x' + '34'.repeat(32)) as `0x${string}`, + chain: CHAIN.BNB_TESTNET, + providerFee: BigInt(0), + paymentToken: D.paymentToken, + principalMin: BigInt(1), + principalMax: BigInt(1), + minDuration: 3600, + maxDuration: 86400, + minExecuteWindow: 0, + settleWindow: 60, + }, + { + rules: { + assets: [ + { + token: { prc20: '0x731aF1Da5365259d27528557EE4aFBA4baC90ef2' }, + maxPerCall: PushChain.CONSTANTS.AGENTIC.PRINCIPAL, + maxTotal: PushChain.CONSTANTS.AGENTIC.PRINCIPAL, + }, + ], + principalAsset: 0, + maxGasPerCall: BigInt(0), + allowedCalls: [ + { + target, + selector: 'balanceOf(address)', + pins: [{ arg: 0, expected: PushChain.CONSTANTS.AGENTIC.WALLET }], + }, + ], + }, + jobSpecTemplate: template, + } + ); + cardId = registered.cardId; + f.evidence('marketplace-register', { cardId, txHash: registered.tx.hash }); + const now = Number((await f.push.getBlock()).timestamp); + const plan = await owner.market.preview(cardId, { + principal: BigInt(1), + executeBy: now + 600, + expiredAt: now + 7200, + label: 'marketplace-e2e', + }); + const result = await owner.market.openJob(plan); + opened = result; + f.evidence('marketplace-open', { + jobId: result.jobId, + wallet: result.wallet, + rulesId: result.rulesId, + txHash: result.tx.hash, + }); + const status = await owner.job.status(opened.jobId); + expect(status.status).toBe('Open'); + expect(status.description).toBe(plan.jobSpec.bytes); + const cancelled = await owner.job.cancel(opened.jobId); + await cancelled.wait(); + expect((await owner.job.status(opened.jobId)).status).toBe('Rejected'); + await expect( + owner.agentic.wallet(opened.wallet).rules.get(opened.rulesId) + ).rejects.toMatchObject({ code: 'RULE_NOT_FOUND' }); + await (await provider.market.agent.setActive(cardId, false)).wait(); + expect((await provider.market.card(cardId)).active).toBe(false); + f.evidence('marketplace-cancel-cleanup', { + cardId, + wallet: opened.wallet, + jobId: opened.jobId, + txHash: cancelled.hash, + }); + }); +}); diff --git a/packages/core/__e2e__/marketplace/readiness.spec.ts b/packages/core/__e2e__/marketplace/readiness.spec.ts new file mode 100644 index 00000000..8876d34b --- /dev/null +++ b/packages/core/__e2e__/marketplace/readiness.spec.ts @@ -0,0 +1,55 @@ +/** Unfunded deployment acceptance. No keys, signatures or transaction broadcasts. */ +import { PushChain } from '../../src'; +import { CHAIN, PUSH_NETWORK } from '../../src/lib/constants/enums'; +import { createPublicClient, http } from 'viem'; +import { DONUT_MARKETPLACE as D } from '../../src/lib/market/deployment'; +import { MARKETPLACE_ABI } from '../../src/lib/market/contracts/UniversalMarketplace'; +import { JOB_KERNEL_ABI } from '../../src/lib/market/contracts/AgenticCommerce'; +describe('marketplace deployed v2 read-only', () => { + let sdk: PushChain; + beforeAll(async () => { + sdk = await PushChain.initialize( + { + chain: CHAIN.PUSH_TESTNET_DONUT, + address: '0x1111111111111111111111111111111111111111', + }, + { network: PUSH_NETWORK.TESTNET_DONUT } + ); + }); + it('enumerates registry and jobs through public SDK bindings and confirms the deployment/token', async () => { + const rpc = createPublicClient({ + transport: http('https://evm.donut.rpc.push.org/'), + }); + const [cards, jobs, version, count, token] = await Promise.all([ + sdk.market.cards(), + sdk.job.list(), + rpc.readContract({ + address: D.marketplace, + abi: MARKETPLACE_ABI, + functionName: 'version', + }), + rpc.readContract({ + address: D.marketplace, + abi: MARKETPLACE_ABI, + functionName: 'agentCardCount', + }), + rpc.readContract({ + address: D.kernel, + abi: JOB_KERNEL_ABI, + functionName: 'paymentToken', + }), + ]); + expect(version).toBe('2.0.0'); + expect(token.toLowerCase()).toBe(D.paymentToken.toLowerCase()); + expect(BigInt(cards.cards.length)).toBe(count); + expect(Array.isArray(jobs.jobs)).toBe(true); + }); + it('returns explicit placeholders for unavailable verification and deposit orchestration', async () => { + await expect(sdk.job.verify(BigInt(1))).rejects.toMatchObject({ + code: 'CAPABILITY_UNAVAILABLE', + }); + await expect(sdk.market.deposit(BigInt(1))).rejects.toMatchObject({ + code: 'CAPABILITY_UNAVAILABLE', + }); + }); +}); diff --git a/packages/core/__market-local__/marketplace.spec.ts b/packages/core/__market-local__/marketplace.spec.ts new file mode 100644 index 00000000..40810c43 --- /dev/null +++ b/packages/core/__market-local__/marketplace.spec.ts @@ -0,0 +1,402 @@ +/** Public SDK → real deployed v2/AGW v6 on an isolated Anvil Donut fork. No keys or writes to public RPC. */ +import { spawn, type ChildProcess } from 'node:child_process'; +import { createServer } from 'node:net'; +import { + createPublicClient, + createWalletClient, + defineChain, + encodeFunctionData, + erc20Abi, + keccak256, + http, + parseAbi, + stringToHex, + zeroAddress, + zeroHash, + type Address, + type PublicClient, +} from 'viem'; +import { mnemonicToAccount } from 'viem/accounts'; +import { PushChain } from '../src'; +import { CHAIN, PUSH_NETWORK, LIBRARY } from '../src/lib/constants/enums'; +import { DONUT_MARKETPLACE as D } from '../src/lib/market/deployment'; +import { JOB_KERNEL_ABI } from '../src/lib/market/contracts/AgenticCommerce'; +import { currentGeneration } from '../src/lib/agentic/deployments'; +import type { AgentCardRules } from '../src/lib/market/rules'; +import type { JobSpecTemplate } from '../src/lib/job-spec/types'; + +let node: ChildProcess; +let rpc: string; +let push: PublicClient; +let owner: PushChain; +let provider: PushChain; +let cardId: bigint; +let opened: { jobId: bigint; wallet: Address; rulesId: `0x${string}` }; +let template: JobSpecTemplate; +let rules: AgentCardRules; +let stopWatch: (() => void) | undefined; +const accounts = [0, 1].map((addressIndex) => + mnemonicToAccount( + 'test test test test test test test test test test test junk', + { addressIndex } + ) +); +const token = '0x731aF1Da5365259d27528557EE4aFBA4baC90ef2'; +const tokenOnSepolia = '0xE935d9c9C24D02E61186c640cc01d713C876d40F'; +beforeAll(async () => { + const port = await new Promise((resolve) => { + const server = createServer(); + server.listen(0, '127.0.0.1', () => { + const p = (server.address() as { port: number }).port; + server.close(() => resolve(p)); + }); + }); + rpc = `http://127.0.0.1:${port}`; + node = spawn( + 'anvil', + [ + '--host', + '127.0.0.1', + '--port', + String(port), + '--chain-id', + '42101', + '--fork-url', + process.env['MARKET_FORK_RPC'] ?? 'https://evm.donut.rpc.push.org/', + '--fork-block-number', + '24447347', + '--timeout', + '120000', + '--retries', + '2', + '--silent', + ], + { stdio: ['ignore', 'ignore', 'pipe'] } + ); + let logs = ''; + node.stderr?.on('data', (c) => { + logs += String(c); + }); + const chain = defineChain({ + id: 42101, + name: 'Local marketplace fork', + nativeCurrency: { name: 'PC', symbol: 'PC', decimals: 18 }, + rpcUrls: { default: { http: [rpc] } }, + }); + push = createPublicClient({ + chain, + transport: http(rpc, { timeout: 120000, retryCount: 0 }), + pollingInterval: 25, + }) as PublicClient; + let ready = false; + for (let i = 0; i < 150; i++) { + if (node.exitCode !== null) throw new Error(`Anvil stopped: ${logs}`); + try { + await push.getBlockNumber(); + ready = true; + break; + } catch { + await new Promise((r) => setTimeout(r, 200)); + } + } + if (!ready) throw new Error(`Anvil did not start: ${logs}`); + await push.request({ + method: 'evm_setNextBlockTimestamp' as never, + params: [Math.floor(Date.now() / 1000)] as never, + }); + const clients = await Promise.all( + accounts.map(async (account) => { + const wallet = createWalletClient({ + account, + chain, + transport: http(rpc, { timeout: 120000 }), + pollingInterval: 25, + }); + const signer = await PushChain.utils.signer.toUniversalFromKeypair( + wallet, + { chain: CHAIN.PUSH_TESTNET_DONUT, library: LIBRARY.ETHEREUM_VIEM } + ); + return PushChain.initialize(signer, { + network: PUSH_NETWORK.TESTNET_DONUT, + rpcUrls: { [CHAIN.PUSH_TESTNET_DONUT]: [rpc] }, + }); + }) + ); + [owner, provider] = clients; + const read = PushChain.utils.job.prepareRead({ + chain: CHAIN.BNB_TESTNET, + target: tokenOnSepolia, + abi: parseAbi(['function balanceOf(address) view returns (uint256)']), + functionName: 'balanceOf', + args: ['agentic:wallet'], + }); + template = PushChain.utils.job.buildJobSpecTemplate({ + reads: [read], + checks: [ + { + read: 0, + evaluation: 'COMPARE', + operation: 'GREATER_OR_EQUAL', + target: BigInt(0), + }, + ], + logic: 'ALL', + }); + rules = { + assets: [ + { + token: { prc20: token }, + maxPerCall: PushChain.CONSTANTS.AGENTIC.PRINCIPAL, + maxTotal: PushChain.CONSTANTS.AGENTIC.PRINCIPAL, + }, + ], + principalAsset: 0, + maxGasPerCall: BigInt(0), + allowedCalls: [ + { + target: tokenOnSepolia, + selector: 'balanceOf(address)', + pins: [{ arg: 0, expected: PushChain.CONSTANTS.AGENTIC.WALLET }], + }, + ], + }; +}, 180000); +afterAll(async () => { + stopWatch?.(); + node?.kill('SIGTERM'); +}); + +it('registers and discovers a real v2 provider card through the public namespace', async () => { + const response = await provider.market.agent.register( + { + jobType: 'SDK_FORK_TEST', + metadataURI: 'https://example.invalid/sdk-marketplace-test', + metadataHash: ('0x' + '12'.repeat(32)) as `0x${string}`, + chain: CHAIN.BNB_TESTNET, + providerFee: BigInt(5000000), + paymentToken: D.paymentToken, + principalMin: BigInt(1), + principalMax: BigInt(100), + minDuration: 3600, + maxDuration: 90 * 86400, + minExecuteWindow: 0, + settleWindow: 60, + }, + { rules, jobSpecTemplate: template } + ); + cardId = response.cardId; + expect(response.version).toBe(BigInt(1)); + expect(cardId).toBeGreaterThan(BigInt(0)); + const card = await owner.market.card(cardId); + expect(card.provider).toBe(accounts[1].address); + expect(card.jobSpecTemplate.allowedMutability).toBe('NONE'); + expect( + (await owner.market.cards({ provider: accounts[1].address })).cards[0] + .cardId + ).toBe(cardId); + expect((await provider.market.agent.card())?.cardId).toBe(cardId); +}); +it('previews and signs the exact on-chain JobSpec, opens on real AGW v6, and preserves binary bytes', async () => { + const now = Number((await push.getBlock()).timestamp); + const plan = await owner.market.preview(cardId, { + principal: BigInt(10), + executeBy: now + 600, + expiredAt: now + 7200, + }); + const response = await owner.market.openJob(plan); + opened = response; + expect((await owner.market.activeJob(opened.wallet)).jobId).toBe( + opened.jobId + ); + const status = await owner.job.status(opened.jobId); + expect(status.description).toBe(plan.jobSpec.bytes); + expect(status.jobSpec?.spec.origin).toBe(plan.jobSpec.spec.origin); + expect(status.evaluation.available).toBe(false); +}); +it('updates a decoded card without losing rule constraints or template wire bytes', async () => { + const before = await provider.market.card(cardId); + const updated = await provider.market.agent.update( + cardId, + { ...before, metadataURI: 'https://example.invalid/updated-sdk-test' }, + { rules: before.rules, jobSpecTemplate: before.jobSpecTemplate } + ); + expect(updated.version).toBe(BigInt(2)); + const after = await owner.market.card(cardId); + expect(after.rulesBytes).toBe(before.rulesBytes); + expect(after.jobSpecTemplateBytes).toBe(before.jobSpecTemplateBytes); + expect(after.verified).toBe(false); +}); +it('funds through the real rules hook and submits as the provider; manual evaluator completes locally', async () => { + const events: string[] = []; + stopWatch = owner.job.watch(opened.jobId, (e) => events.push(e.kind), { + fromBlock: (await push.getBlockNumber({ cacheTime: 0 })) + BigInt(1), + pollIntervalMs: 25, + }); + await (await provider.job.setBudget(opened.jobId, BigInt(6000000))).wait(); + await expect(owner.job.fund(opened.jobId)).rejects.toMatchObject({ + code: 'EXPECTED_BUDGET_REQUIRED', + }); + await expect( + owner.job.fund(opened.jobId, { expectedBudget: BigInt(5000000) }) + ).rejects.toMatchObject({ code: 'BUDGET_MISMATCH' }); + await (await provider.job.setBudget(opened.jobId, BigInt(5000000))).wait(); + await expect( + owner.job.fund(opened.jobId, { expectedBudget: BigInt(5000000) }) + ).rejects.toMatchObject({ code: 'INSUFFICIENT_FUNDS' }); + // Borrow existing pUSDC on this local fork only; no mint/transfer is sent to public Donut. + const source = '0x0A16CBa65FfCAa4C2282b27b027Ab4A2fE46E0Bf'; + await push.request({ + method: 'anvil_impersonateAccount' as never, + params: [source] as never, + }); + const funder = createWalletClient({ + account: source, + chain: push.chain, + transport: http(rpc), + }); + const fundingHash = await funder.writeContract({ + chain: push.chain, + address: D.paymentToken, + abi: erc20Abi, + functionName: 'transfer', + args: [opened.wallet, BigInt(5000000)], + }); + await push.waitForTransactionReceipt({ hash: fundingHash }); + const before = await push.readContract({ + address: D.paymentToken, + abi: erc20Abi, + functionName: 'balanceOf', + args: [accounts[1].address], + }); + await ( + await owner.job.fund(opened.jobId, { expectedBudget: BigInt(5000000) }) + ).wait(); + expect((await owner.job.status(opened.jobId)).status).toBe('Funded'); + await ( + await provider.job.submit(opened.jobId, { deliverable: 'fork-only proof' }) + ).wait(); + const submitted = await owner.job.status(opened.jobId); + expect(submitted.status).toBe('Submitted'); + expect(submitted.deliverable).toBe(keccak256(stringToHex('fork-only proof'))); + await push.request({ + method: 'anvil_impersonateAccount' as never, + params: [D.evaluator] as never, + }); + await push.request({ + method: 'anvil_setBalance' as never, + params: [D.evaluator, '0x8ac7230489e80000'] as never, + }); + const evaluator = createWalletClient({ + account: D.evaluator, + chain: push.chain, + transport: http(rpc), + }); + const hash = await evaluator.sendTransaction({ + chain: push.chain, + to: D.kernel, + data: encodeFunctionData({ + abi: JOB_KERNEL_ABI, + functionName: 'complete', + args: [opened.jobId, zeroHash, '0x'], + }), + }); + await push.waitForTransactionReceipt({ hash }); + expect((await owner.job.status(opened.jobId)).status).toBe('Completed'); + const after = await push.readContract({ + address: D.paymentToken, + abi: erc20Abi, + functionName: 'balanceOf', + args: [accounts[1].address], + }); + expect(after - before).toBe(BigInt(5000000)); + await new Promise((resolve) => setTimeout(resolve, 300)); + stopWatch(); + stopWatch = undefined; + expect(events).toEqual( + expect.arrayContaining(['BudgetSet', 'Funded', 'Submitted', 'Completed']) + ); + expect(events).not.toContain('Error'); + await expect(owner.job.verify(opened.jobId)).rejects.toMatchObject({ + code: 'CAPABILITY_UNAVAILABLE', + }); +}); +it('creates a plain job and allows third-party refund while the kernel is paused', async () => { + const expiredAt = Number((await push.getBlock()).timestamp) + 600; + const plain = await owner.job.create({ + provider: accounts[1].address, + evaluator: D.evaluator, + hook: zeroAddress, + expiredAt, + paymentToken: D.paymentToken, + description: 'plain SDK fork job', + }); + await ( + await owner.job.fund(plain.jobId, { expectedBudget: BigInt(0) }) + ).wait(); + await push.request({ + method: 'anvil_impersonateAccount' as never, + params: [D.evaluator] as never, + }); + await push.request({ + method: 'anvil_setBalance' as never, + params: [D.evaluator, '0x8ac7230489e80000'] as never, + }); + const admin = createWalletClient({ + account: D.evaluator, + chain: push.chain, + transport: http(rpc), + }); + const pauseHash = await admin.writeContract({ + chain: push.chain, + address: D.kernel, + abi: JOB_KERNEL_ABI, + functionName: 'pause', + }); + await push.waitForTransactionReceipt({ hash: pauseHash }); + await push.request({ + method: 'evm_setNextBlockTimestamp' as never, + params: [expiredAt + 1] as never, + }); + await push.request({ method: 'evm_mine' as never, params: [] as never }); + await (await provider.job.claimRefund(plain.jobId)).wait(); + expect((await owner.job.status(plain.jobId)).status).toBe('Expired'); + const unpauseHash = await admin.writeContract({ + chain: push.chain, + address: D.kernel, + abi: JOB_KERNEL_ABI, + functionName: 'unpause', + }); + await push.waitForTransactionReceipt({ hash: unpauseHash }); + expect( + (await owner.job.list({ provider: accounts[1].address })).jobs.some( + (j) => j.jobId === plain.jobId + ) + ).toBe(true); +}); +it('rejects a tampered plan before signing and atomically cancels a second job with permission revocation', async () => { + const now = Number((await push.getBlock()).timestamp); + const plan = await owner.market.preview(cardId, { + principal: BigInt(10), + executeBy: now + 600, + expiredAt: now + 7200, + }); + await expect( + owner.market.openJob({ + ...plan, + preview: { ...plan.preview, mayDo: ['tampered'] }, + }) + ).rejects.toMatchObject({ code: 'STALE_PLAN' }); + const second = await owner.market.openJob(plan); + await (await owner.job.cancel(second.jobId)).wait(); + expect((await owner.job.status(second.jobId)).status).toBe('Rejected'); + expect((await owner.market.activeJob(second.wallet)).jobId).toBe(BigInt(0)); + const gen = currentGeneration(PUSH_NETWORK.TESTNET_DONUT); + expect( + await push.readContract({ + address: gen.addresses.sessionEngine, + abi: gen.contracts.abis.engine, + functionName: 'isPermissionEnabled', + args: [second.rulesId, second.wallet], + }) + ).toBe(false); +}); diff --git a/packages/core/__market-local__/setup.ts b/packages/core/__market-local__/setup.ts new file mode 100644 index 00000000..3855681f --- /dev/null +++ b/packages/core/__market-local__/setup.ts @@ -0,0 +1,42 @@ +/** Real viem RPC/actions, with local-fork timeouts and polling instead of production defaults. */ +jest.mock('viem', () => { + const actual = jest.requireActual('viem'); + return { + ...actual, + createPublicClient: (options: { + pollingInterval?: number; + [key: string]: unknown; + }) => + actual.createPublicClient({ + ...options, + pollingInterval: options.pollingInterval ?? 25, + }), + http: (url?: string, options?: Record) => + actual.http(url, { + ...(url?.startsWith('http://127.0.0.1:') ? { timeout: 120000 } : {}), + ...options, + }), + createWalletClient: (options: { + chain?: { rpcUrls?: { default?: { http?: string[] } } }; + [key: string]: unknown; + }) => { + const client = actual.createWalletClient(options); + const url = options.chain?.rpcUrls?.default?.http?.[0]; + if (url?.startsWith('http://127.0.0.1:')) { + const send = client.sendTransaction; + const local = actual.createPublicClient({ + transport: actual.http(url, { timeout: 120000 }), + }); + client.sendTransaction = async (params: unknown) => { + const hash = await send(params); + // Anvil may return the hash before its receipt is indexed, then forward a + // premature receipt query to the public fork RPC. Mine confirmation blocks locally before + // handing the real hash to SDK receipt polling. No result is mocked. + await local.request({ method: 'anvil_mine', params: ['0x4'] }); + return hash; + }; + } + return client; + }, + }; +}); diff --git a/packages/core/jest.marketplace-local.config.ts b/packages/core/jest.marketplace-local.config.ts new file mode 100644 index 00000000..36c35c62 --- /dev/null +++ b/packages/core/jest.marketplace-local.config.ts @@ -0,0 +1,15 @@ +export default { + displayName: 'marketplace-local', + preset: '../../jest.preset.js', + testEnvironment: 'node', + setupFilesAfterEnv: ['/__market-local__/setup.ts'], + transform: { + '^.+\\.[tj]s$': [ + 'ts-jest', + { tsconfig: '/tsconfig.marketplace-local.json' }, + ], + }, + moduleFileExtensions: ['ts', 'js'], + testTimeout: 180000, + testMatch: ['/__market-local__/**/*.spec.ts'], +}; diff --git a/packages/core/package.json b/packages/core/package.json index 7572d206..1f4eba06 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -73,6 +73,7 @@ "src/**/*.json", "README.md", "AGW.md", + "MARKETPLACE.md", "CHANGELOG.md" ], "devDependencies": { diff --git a/packages/core/scripts/check-agw-api.js b/packages/core/scripts/check-agw-api.js index 4aa6c929..ff2c461f 100644 --- a/packages/core/scripts/check-agw-api.js +++ b/packages/core/scripts/check-agw-api.js @@ -169,6 +169,9 @@ function snapshot(entry) { (context) => { const visit = (node) => { node = ts.visitEachChild(node, visit, context); + // Source property keys can use single quotes while declarations emit + // double quotes. Canonicalize syntax without changing the literal value. + if (ts.isStringLiteral(node)) return ts.factory.createStringLiteral(node.text); if (ts.isUnionTypeNode(node) || ts.isIntersectionTypeNode(node)) { const types = [...node.types].sort((a, b) => printer diff --git a/packages/core/scripts/check-agw-docs.js b/packages/core/scripts/check-agw-docs.js index ec10c4b1..af27c104 100644 --- a/packages/core/scripts/check-agw-docs.js +++ b/packages/core/scripts/check-agw-docs.js @@ -4,11 +4,12 @@ const path = require('node:path'); const ts = require('typescript'); const root = path.resolve(__dirname, '../../..'); -const guide = path.join(root, 'packages/core/AGW.md'); +const guide = path.join(root, process.argv[2] || 'packages/core/AGW.md'); +const guideName = path.basename(guide, '.md'); const blocks = [ ...fs.readFileSync(guide, 'utf8').matchAll(/```ts\n([\s\S]*?)```/g), ].map((m) => m[1]); -if (!blocks.length) throw new Error('No AGW TypeScript examples found'); +if (!blocks.length) throw new Error(`No ${guideName} TypeScript examples found`); const cache = path.join(root, 'node_modules/.cache'); fs.mkdirSync(cache, { recursive: true }); const dir = fs.mkdtempSync(path.join(cache, 'agw-docs-')); @@ -42,7 +43,7 @@ try { process.exitCode = 1; } else { process.stdout.write( - `AGW guide: ${blocks.length} TypeScript blocks typechecked against public exports; no examples executed.\n` + `${guideName} guide: ${blocks.length} TypeScript blocks typechecked against public exports; no examples executed.\n` ); } } finally { diff --git a/packages/core/scripts/check-agw-package.js b/packages/core/scripts/check-agw-package.js index 7384461d..453042a3 100644 --- a/packages/core/scripts/check-agw-package.js +++ b/packages/core/scripts/check-agw-package.js @@ -22,10 +22,13 @@ async function main() { }) ); assert(pack.files.some((f) => f.path === 'AGW.md')); + assert(pack.files.some((f) => f.path === 'MARKETPLACE.md')); + assert.equal(typeof cjs.PushChain.utils.job.buildJobSpec, 'function'); + assert.equal(typeof cjs.PushChain.utils.market.encodeAgentCardRules, 'function'); assert(!pack.files.some((f) => /(^|\/)\.env($|\.)/.test(f.path))); assert( !pack.files.some((f) => - /(^|\/)(plan|__e2e__|__agw-local__|scripts)(\/|$)/.test(f.path) + /(^|\/)(plan|__e2e__|__agw-local__|__market-local__|scripts)(\/|$)/.test(f.path) ) ); const preset = cjs.PushChain.utils.agentic.presets.get('LENDING', { @@ -53,6 +56,9 @@ async function main() { try { const file = path.join(tmp, 'consumer.ts'); fs.writeFileSync(file, source); + const marketFile = path.join(tmp, 'market-consumer.ts'); + const marketGuide = fs.readFileSync(path.join(built, 'MARKETPLACE.md'), 'utf8'); + fs.writeFileSync(marketFile, [...marketGuide.matchAll(/```ts\n([\s\S]*?)```/g)].map(m => m[1]).join('\n\n')); const config = ts.readConfigFile( path.join(root, 'packages/core/tsconfig.lib.json'), ts.sys.readFile @@ -68,7 +74,7 @@ async function main() { paths: { '@pushchain/core': [path.join(built, 'src/index.d.ts')] }, }; const diagnostics = ts.getPreEmitDiagnostics( - ts.createProgram([file], options) + ts.createProgram([file, marketFile], options) ); if (diagnostics.length) throw new Error( diff --git a/packages/core/src/lib/agentic/__tests__/response-surface.spec.ts b/packages/core/src/lib/agentic/__tests__/response-surface.spec.ts index 3dac9d67..19d26627 100644 --- a/packages/core/src/lib/agentic/__tests__/response-surface.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/response-surface.spec.ts @@ -228,7 +228,9 @@ describe('public surface', () => { it('exposes the wallet marker and preset API, keeping deployment wiring and codecs internal', () => { expect(CONSTANTS.AGENTIC.WALLET).toBe('agentic:wallet'); expect(Object.keys(CONSTANTS.AGENTIC).sort()).toEqual([ + 'JOB', 'PRESETS', + 'PRINCIPAL', 'WALLET', ]); expect(Object.isFrozen(CONSTANTS.AGENTIC)).toBe(true); diff --git a/packages/core/src/lib/agentic/constants.ts b/packages/core/src/lib/agentic/constants.ts index 943b896c..b5e798de 100644 --- a/packages/core/src/lib/agentic/constants.ts +++ b/packages/core/src/lib/agentic/constants.ts @@ -1,6 +1,19 @@ -/** Public section-7 discovery constants; deployment wiring stays internal. */ +import { JOB_VOCABULARY, PRINCIPAL } from '../job-spec/constants'; +import { DONUT_MARKETPLACE } from '../market/deployment'; +/** Public vocabulary. JOB.ADDRESS is the explicit per-chain job integration surface. */ export const AGENTIC = Object.freeze({ WALLET: 'agentic:wallet' as const, + PRINCIPAL, + JOB: Object.freeze({ + ...JOB_VOCABULARY, + ADDRESS: Object.freeze({ + 'eip155:42101': Object.freeze({ + KERNEL: DONUT_MARKETPLACE.kernel, + HOOK: DONUT_MARKETPLACE.hook, + EVALUATOR: DONUT_MARKETPLACE.evaluator, + }), + }), + }), PRESETS: Object.freeze({ CATEGORY: Object.freeze({ DEXES: 'DEXES' as const, diff --git a/packages/core/src/lib/agentic/contracts/reader.ts b/packages/core/src/lib/agentic/contracts/reader.ts index 7b978068..2515cd8e 100644 --- a/packages/core/src/lib/agentic/contracts/reader.ts +++ b/packages/core/src/lib/agentic/contracts/reader.ts @@ -14,6 +14,7 @@ export interface ChainReader { blockNumber?: bigint; }): Promise; getBlockNumber(): Promise; + getBlock?(args: { blockNumber: bigint }): Promise<{ timestamp: bigint }>; getCode(args: { address: Address; blockNumber?: bigint }): Promise; getBalance(args: { address: Address; blockNumber?: bigint }): Promise; getLogs(args: { @@ -33,6 +34,7 @@ export function chainReaderFromPublicClient(client: PublicClient): ChainReader { readContract: (args) => client.readContract(args as Parameters[0]), getBlockNumber: () => client.getBlockNumber({ cacheTime: 0 }), + getBlock: (args) => client.getBlock(args), getCode: (args) => client.getCode(args), getBalance: (args) => client.getBalance(args), getLogs: (args) => diff --git a/packages/core/src/lib/agentic/errors.ts b/packages/core/src/lib/agentic/errors.ts index 08ce712e..5aac4033 100644 --- a/packages/core/src/lib/agentic/errors.ts +++ b/packages/core/src/lib/agentic/errors.ts @@ -51,8 +51,10 @@ export type AgenticErrorCode = * eligibility or a read that cannot be trusted. Nothing was signed or sent * except receipt errors, which retain the submitted transaction hash. */ -export class AgenticError extends Error { - readonly code: AgenticErrorCode; +export class AgenticError< + Code extends string = AgenticErrorCode +> extends Error { + readonly code: Code; /** Safe end-user copy; message/cause retain technical diagnostics. */ readonly userMessage: string; readonly hint?: string; @@ -60,7 +62,7 @@ export class AgenticError extends Error { override readonly cause?: unknown; constructor( - code: AgenticErrorCode, + code: Code, message: string, opts: { hint?: string; @@ -73,7 +75,10 @@ export class AgenticError extends Error { this.name = 'AgenticError'; this.code = code; this.userMessage = - opts.userMessage ?? agenticUserMessage(code, message, opts.details); + opts.userMessage ?? + (Object.prototype.hasOwnProperty.call(AGENTIC_ERROR_CODE, code) + ? agenticUserMessage(code as AgenticErrorCode, message, opts.details) + : message); this.hint = opts.hint; this.details = opts.details; this.cause = opts.cause; diff --git a/packages/core/src/lib/index.ts b/packages/core/src/lib/index.ts index 1783b439..b40c9a86 100644 --- a/packages/core/src/lib/index.ts +++ b/packages/core/src/lib/index.ts @@ -1,4 +1,44 @@ import { PushChain } from './push-chain/push-chain'; +export { MarketError, JobError, JobSpecError } from './market'; +export type { + AgentCardRules, + MarketAssetToken, + MarketPin, + AgentCard, + AgentCardInput, + AgentCardSummary, + MarketNamespace, + MarketPreviewOptions, + JobPlan, + OwnerIntent, +} from './market'; +export type { + JobNamespace, + Job, + JobStatus, + JobEvent, + CreateJobOptions, + FundJobOptions, +} from './job/types'; +export type { + JobSpec, + JobSpecTemplate, + JobRead, + PreparedJobRead, + JobReadInput, + JobCheck, + JobCheckTemplate, + LogicTree, + Evaluation, + Operation, + LogicKind, + AllowedMutability, + PrincipalMarker, + PrepareJobReadOptions, + BuildJobSpecOptions, + BuildJobSpecTemplateOptions, + JobSpecPreview, +} from './job-spec'; export { CHAIN } from './constants/enums'; export type { ConversionQuote } from './constants/tokens'; export type { diff --git a/packages/core/src/lib/job-spec/__tests__/codec.spec.ts b/packages/core/src/lib/job-spec/__tests__/codec.spec.ts new file mode 100644 index 00000000..aac64c3d --- /dev/null +++ b/packages/core/src/lib/job-spec/__tests__/codec.spec.ts @@ -0,0 +1,190 @@ +import { + decodeAbiParameters, + encodeAbiParameters, + parseAbi, + parseAbiParameters, + zeroAddress, + zeroHash, +} from 'viem'; +import { + buildJobSpec, + buildJobSpecTemplate, + decodeJobSpec, + encodeJobSpec, +} from '../codec'; +import { prepareJobRead } from '../read'; +import { PRINCIPAL } from '../constants'; +import { JOB_SPEC_PARAM } from '../schema'; +import { resolveJobSpec, specOrigin } from '../helpers'; +import type { LogicTree } from '../types'; +const address = '0x1111111111111111111111111111111111111111'; +const abi = parseAbi(['function balanceOf(address) view returns (uint256)']); +const read = () => + prepareJobRead({ + chain: 'eip155:11155111', + target: address, + abi, + functionName: 'balanceOf', + args: [address], + }); +const check = { + read: 0, + evaluation: 'COMPARE' as const, + operation: 'GREATER_OR_EQUAL' as const, + target: BigInt(9), +}; +const spec = () => + buildJobSpec({ + reads: [read()], + checks: [check], + logic: 'ALL', + executeBy: 1800000000, + failFinalAt: 1800003600, + }); + +it('prepares exact selectors, binary output codes and literal zero arguments without inventing holes', () => { + const p = prepareJobRead({ + chain: 'eip155:11155111', + target: address, + abi, + functionName: 'balanceOf', + args: [zeroAddress], + }); + expect(p.selector).toBe('0x70a08231'); + expect(p.outputs).toBe('0x080101'); + expect(p.fills).toBeUndefined(); +}); +it('preserves WALLET/PARAM positions and resolves them independently of literal zeros', () => { + const r = prepareJobRead({ + chain: 'eip155:11155111', + target: address, + abi: parseAbi([ + 'function quote(address,uint256,uint256) view returns (uint256)', + ]), + functionName: 'quote', + args: ['agentic:wallet', { param: 0 }, BigInt(0)], + }); + expect(r.fills).toEqual([ + { word: 0, source: 'WALLET' }, + { word: 1, source: 'PARAM', param: 0 }, + ]); + const t = buildJobSpecTemplate({ + reads: [r], + checks: [{ ...check, target: PRINCIPAL }], + logic: 'ALL', + params: [{ min: BigInt(1), max: BigInt(20) }], + }); + const resolved = resolveJobSpec(t, { + principal: BigInt(50), + params: [BigInt(7)], + accounts: { 'eip155:11155111': address }, + origin: zeroHash, + executeBy: 1800000000, + settleWindow: 3600, + }); + expect( + decodeAbiParameters( + parseAbiParameters('address,uint256,uint256'), + resolved.reads[0].args + ) + ).toEqual([address, BigInt(7), BigInt(0)]); + expect(resolved.checks[0].target).toBe(BigInt(50)); + expect(t.reads[0].args).not.toBe(resolved.reads[0].args); +}); +it('encodes the deployed field and enum order and roundtrips a complete spec canonically', () => { + const bytes = encodeJobSpec(spec()); + const w = decodeAbiParameters([JOB_SPEC_PARAM], bytes)[0]; + expect(w.allowedMutability).toBe(0); + expect(w.logic[0].kind).toBe(0); + expect(w.origin).toBe(zeroHash); + expect(w.executeBy).toBe(BigInt(1800000000)); + expect(encodeJobSpec(decodeJobSpec(bytes))).toBe(bytes); +}); +it('roundtrips templates including principal-BPS targets and bounds', () => { + const t = buildJobSpecTemplate({ + reads: [read()], + checks: [{ ...check, target: { principalBps: BigInt(9999) } }], + logic: { kind: 'AT_LEAST', k: 1, of: [0] }, + }); + const bytes = encodeJobSpec(t); + expect(encodeJobSpec(decodeJobSpec(bytes, { format: 'template' }))).toBe( + bytes + ); +}); +it('keeps a valid non-DFS topological logic order when decoding unchanged signed bytes', () => { + const w = decodeAbiParameters([JOB_SPEC_PARAM], encodeJobSpec(spec()))[0]; + const bytes = encodeAbiParameters( + [JOB_SPEC_PARAM], + [ + { + ...w, + logic: [ + { kind: 0, checks: [], children: [2, 1], k: 0 }, + { kind: 1, checks: [0], children: [], k: 0 }, + { kind: 0, checks: [0], children: [], k: 0 }, + ], + }, + ] + ); + expect(encodeJobSpec(decodeJobSpec(bytes))).toBe(bytes); +}); +it('rejects cycles, invalid indexes and unsupported template holes before encoding', () => { + const tree: LogicTree = { kind: 'ALL', of: [] }; + tree.of.push(tree); + expect(() => + buildJobSpec({ + reads: [read()], + checks: [check], + logic: tree, + executeBy: 1, + failFinalAt: 2, + }) + ).toThrow(/cyclic/); + expect(() => + buildJobSpec({ + reads: [read()], + checks: [{ ...check, read: 2 }], + logic: 'ALL', + executeBy: 1, + failFinalAt: 2, + }) + ).toThrow(/index/); + expect(() => + prepareJobRead({ + chain: 'eip155:1', + target: address, + abi: parseAbi(['function x(address[]) view returns (uint256)']), + functionName: 'x', + args: [['agentic:wallet']], + }) + ).toThrow(); +}); +it('rejects malformed enums, trailing bytes, foreign wire and filled format ambiguity', () => { + const bytes = encodeJobSpec(spec()); + const w = decodeAbiParameters([JOB_SPEC_PARAM], bytes)[0]; + expect(() => decodeJobSpec((bytes + '00') as `0x${string}`)).toThrow( + /canonical/ + ); + expect(() => + decodeJobSpec( + encodeAbiParameters([JOB_SPEC_PARAM], [{ ...w, allowedMutability: 9 }]) + ) + ).toThrow(); + const foreign = encodeAbiParameters( + parseAbiParameters('(uint64,uint64,bytes[],bytes[],bytes[],uint8,bytes32)'), + [[BigInt(1), BigInt(2), [], [], [], 1, zeroHash]] + ); + expect(() => decodeJobSpec(foreign)).toThrow(); +}); +it('binds origin to marketplace, integer card version and principal with ABI words', () => { + const expected = + '0x' + + address.slice(2).padStart(64, '0') + + [BigInt(1), BigInt(2), BigInt(3)] + .map((n) => n.toString(16).padStart(64, '0')) + .join(''); + const { keccak256 } = jest.requireActual('viem'); + expect(specOrigin(address, BigInt(1), BigInt(2), BigInt(3))).toBe( + keccak256(expected) + ); +}); diff --git a/packages/core/src/lib/job-spec/codec.ts b/packages/core/src/lib/job-spec/codec.ts new file mode 100644 index 00000000..95f6d21a --- /dev/null +++ b/packages/core/src/lib/job-spec/codec.ts @@ -0,0 +1,452 @@ +import { + decodeAbiParameters, + encodeAbiParameters, + isHex, + zeroHash, + type AbiParameter, + type Hex, +} from 'viem'; +import { JobSpecError } from '../market/errors'; +import { + EVALUATIONS, + OPERATIONS, + LOGIC_KINDS, + MUTABILITIES, + PRINCIPAL, +} from './constants'; +import { JOB_SPEC_PARAM, JOB_TEMPLATE_PARAM } from './schema'; +import { validateJobRead } from './read'; +import type { + BuildJobSpecOptions, + BuildJobSpecTemplateOptions, + JobCheckTemplate, + JobRead, + JobReadInput, + JobSpec, + JobSpecTemplate, + LogicTree, +} from './types'; + +interface LogicWire { + kind: number; + checks: readonly number[]; + children: readonly number[]; + k: number; +} +interface CheckWire { + read: number; + evaluation: number; + operation: number; + target: bigint; +} +interface TemplateCheckWire { + read: number; + evaluation: number; + operation: number; + source: number; + value: bigint; +} +interface ReadWire extends Omit { + fills?: { word: number; source: number; param: number }[]; +} +interface SpecWire { + reads: ReadWire[]; + checks: CheckWire[]; + logic: LogicWire[]; + allowedMutability: number; + origin: Hex; + executeBy: bigint; + failFinalAt: bigint; +} +interface TemplateWire { + reads: ReadWire[]; + checks: TemplateCheckWire[]; + logic: LogicWire[]; + allowedMutability: number; + params: { min: bigint; max: bigint }[]; +} +const originalLogic = new WeakMap< + LogicTree, + { fingerprint: string; wire: LogicWire[] } +>(); +const fail = (message: string, code = 'INVALID_JOB_SPEC'): never => { + throw new JobSpecError(code, message); +}; +const fingerprint = (x: unknown): string => + JSON.stringify(x, (_, v) => (typeof v === 'bigint' ? v.toString() : v)); +export function int256(value: bigint, what = 'Target'): bigint { + if ( + typeof value !== 'bigint' || + value < -(BigInt(1) << BigInt(255)) || + value >= BigInt(1) << BigInt(255) + ) + fail(`${what} must fit int256.`); + return value; +} +function count( + values: readonly unknown[], + max: number, + what: string, + min = 1 +): void { + if (!Array.isArray(values) || values.length < min || values.length > max) + fail( + `${what} must contain ${min}..${max} entries.`, + `TOO_MANY_${what.toUpperCase()}` + ); +} +function timestamp(n: number): void { + if (!Number.isSafeInteger(n) || n < 0) + fail('Timestamps must be nonnegative safe integers.'); +} +function enumIndex(values: T[], value: T, name: string): number { + const i = values.indexOf(value); + if (i < 0) fail(`Unknown ${name}.`); + return i; +} +export function flattenLogic(tree: LogicTree, checkCount: number): LogicWire[] { + const nodes: LogicWire[] = []; + const active = new Set(); + function visit(t: LogicTree): number { + if (!t || active.has(t) || nodes.length >= 32) + fail('Logic is cyclic or exceeds 32 operators.', 'BAD_TREE'); + active.add(t); + const index = nodes.length; + const kind = enumIndex(LOGIC_KINDS, t.kind, 'logic kind'); + if (!Array.isArray(t.of) || !t.of.length || t.of.length > 255) + fail('Logic operators need 1..255 operands.', 'BAD_TREE'); + const k = t.kind === 'AT_LEAST' ? t.k ?? 0 : 0; + if ( + !Number.isInteger(k) || + (t.kind === 'AT_LEAST' && (k < 1 || k > t.of.length)) || + (t.kind !== 'AT_LEAST' && t.k !== undefined && t.k !== 0) + ) + fail('Invalid AT_LEAST threshold.', 'BAD_TREE'); + const n: LogicWire = { kind, checks: [], children: [], k: k }; + nodes.push(n); + for (const item of t.of) { + if (typeof item === 'number') { + if ( + !Number.isInteger(item) || + item < 0 || + item >= checkCount || + n.checks.includes(item) + ) + fail('Dangling or duplicated check index.', 'BAD_TREE'); + (n.checks as number[]).push(item); + } else (n.children as number[]).push(visit(item)); + } + active.delete(t); + return index; + } + visit(tree); + const saved = originalLogic.get(tree); + return saved?.fingerprint === fingerprint(tree) ? saved.wire : nodes; +} +function nestLogic(nodes: LogicWire[], checkCount: number): LogicTree { + count(nodes, 32, 'logic'); + const reached = new Set(); + let expanded = 0; + function visit(index: number, depth: number): LogicTree { + if (++expanded > 512 || depth > 32) + fail('Stored logic is too large to describe as a tree.', 'BAD_TREE'); + const n = nodes[index]; + if (!n || !LOGIC_KINDS[n.kind]) + fail('Unknown stored logic kind.', 'BAD_TREE'); + reached.add(index); + if ( + n.checks.some((i) => !Number.isInteger(i) || i < 0 || i >= checkCount) || + new Set(n.checks).size !== n.checks.length + ) + fail('Invalid stored check reference.', 'BAD_TREE'); + if ( + n.children.some((i) => i <= index || i >= nodes.length) || + new Set(n.children).size !== n.children.length + ) + fail('Invalid stored child reference.', 'BAD_TREE'); + const t: LogicTree = { + kind: LOGIC_KINDS[n.kind], + of: [...n.checks, ...n.children.map((i) => visit(i, depth + 1))], + ...(n.kind === 2 ? { k: n.k } : {}), + }; + if (n.kind !== 2 && n.k !== 0) + fail('Unexpected threshold on stored logic.', 'BAD_TREE'); + return t; + } + const tree = visit(0, 0); + if (reached.size !== nodes.length) + fail('Stored logic has unreachable operators.', 'BAD_TREE'); + // Preserve an unchanged, valid topological order instead of rewriting signed bytes. + originalLogic.set(tree, { fingerprint: fingerprint(tree), wire: nodes }); + flattenLogic(tree, checkCount); + return tree; +} +function normalizeReads(values: BuildJobSpecOptions['reads']): JobRead[] { + count(values, 16, 'reads'); + return values.map((input) => { + const wrapper = input as JobReadInput; + const source = 'read' in input ? wrapper.read : input; + const read: JobRead = { + ...source, + field: [...(wrapper.field ?? [0])], + minConfirmations: wrapper.minConfirmations ?? 1, + ...(source.fills ? { fills: source.fills.map((f) => ({ ...f })) } : {}), + }; + return read; + }); +} +function validate(spec: JobSpec | JobSpecTemplate): void { + count(spec.reads, 16, 'reads'); + count(spec.checks, 16, 'checks'); + enumIndex(MUTABILITIES, spec.allowedMutability, 'allowedMutability'); + const template = 'params' in spec; + if (template) { + count(spec.params, 16, 'params', 0); + for (const p of spec.params) + if (int256(p.min) > int256(p.max)) + fail('Parameter minimum exceeds its maximum.'); + } else { + timestamp(spec.executeBy); + timestamp(spec.failFinalAt); + if ( + spec.failFinalAt <= spec.executeBy || + !/^0x[\da-f]{64}$/i.test(spec.origin) + ) + fail('Invalid JobSpec timing or origin.'); + } + for (const r of spec.reads) { + validateJobRead(r); + if ( + !Number.isInteger(r.minConfirmations) || + r.minConfirmations < 1 || + r.minConfirmations > 65535 + ) + fail('Read confirmations must be 1..65535.'); + const words = new Set(); + for (const f of r.fills ?? []) { + if (!template) + fail( + 'A complete JobSpec cannot contain placeholders.', + 'UNFILLED_PLACEHOLDER' + ); + if ( + !Number.isInteger(f.word) || + f.word < 0 || + f.word > 255 || + f.word * 32 + 32 > (r.args.length - 2) / 2 || + words.has(f.word) + ) + fail('Invalid or duplicate fill word.'); + words.add(f.word); + if (!['WALLET', 'PARAM'].includes(f.source)) fail('Unknown fill source.'); + if ( + f.source === 'PARAM' && + (!Number.isInteger(f.param) || + (f.param ?? -1) < 0 || + (f.param ?? -1) >= (spec as JobSpecTemplate).params.length) + ) + fail('Fill parameter is out of range.'); + } + } + for (const c of spec.checks) { + if (!Number.isInteger(c.read) || c.read < 0 || c.read >= spec.reads.length) + fail('Check read index is out of range.'); + enumIndex(EVALUATIONS, c.evaluation, 'evaluation'); + enumIndex(OPERATIONS, c.operation, 'operation'); + if (c.evaluation === 'BOOLEAN' && c.operation !== 'EQUAL') + fail('BOOLEAN checks use EQUAL.'); + if (typeof c.target === 'bigint') int256(c.target); + else if (!template) + fail( + 'Complete JobSpec targets must be resolved integers.', + 'UNFILLED_PLACEHOLDER' + ); + else targetWire(c.target, (spec as JobSpecTemplate).params.length); + } + flattenLogic(spec.logic, spec.checks.length); +} +function targetWire( + target: JobCheckTemplate['target'], + params: number +): { source: number; value: bigint } { + if (typeof target === 'bigint') return { source: 0, value: int256(target) }; + if (target === PRINCIPAL) return { source: 1, value: BigInt(10000) }; + if (target === 'agentic:wallet') return { source: 3, value: BigInt(0) }; + if (target && typeof target === 'object' && 'principalBps' in target) { + if (int256(target.principalBps) <= BigInt(0)) + fail('principalBps must be positive.'); + return { source: 1, value: target.principalBps }; + } + if ( + target && + typeof target === 'object' && + 'param' in target && + Number.isInteger(target.param) && + target.param >= 0 && + target.param < params + ) + return { source: 2, value: BigInt(target.param) }; + return fail('Unknown or out-of-range template target.'); +} +export function buildJobSpec(options: BuildJobSpecOptions): JobSpec { + const spec: JobSpec = { + reads: normalizeReads(options.reads), + checks: options.checks.map((c) => ({ ...c })), + logic: + typeof options.logic === 'string' + ? { kind: options.logic, of: options.checks.map((_, i) => i) } + : options.logic, + allowedMutability: options.allowedMutability ?? 'NONE', + origin: options.origin ?? zeroHash, + executeBy: options.executeBy, + failFinalAt: options.failFinalAt, + }; + validate(spec); + if (options.expiredAt !== undefined) { + timestamp(options.expiredAt); + if (options.failFinalAt >= options.expiredAt) + fail('failFinalAt must precede job expiry.', 'FAIL_WINDOW_THIN'); + } + return spec; +} +export function buildJobSpecTemplate( + options: BuildJobSpecTemplateOptions +): JobSpecTemplate { + const t: JobSpecTemplate = { + reads: normalizeReads(options.reads), + checks: options.checks.map((c) => ({ ...c })), + logic: + typeof options.logic === 'string' + ? { kind: options.logic, of: options.checks.map((_, i) => i) } + : options.logic, + allowedMutability: options.allowedMutability ?? 'NONE', + params: (options.params ?? []).map((p) => ({ ...p })), + }; + validate(t); + return t; +} +export function encodeJobSpec(spec: JobSpec | JobSpecTemplate): Hex { + validate(spec); + const base = { + reads: spec.reads.map(({ fills, ...r }) => + 'params' in spec + ? { + ...r, + fills: (fills ?? []).map((f) => ({ + word: f.word, + source: f.source === 'WALLET' ? 0 : 1, + param: f.param ?? 0, + })), + } + : r + ), + logic: flattenLogic(spec.logic, spec.checks.length), + allowedMutability: MUTABILITIES.indexOf(spec.allowedMutability), + }; + const checks = spec.checks.map((c) => ({ + read: c.read, + evaluation: EVALUATIONS.indexOf(c.evaluation), + operation: OPERATIONS.indexOf(c.operation), + ...('params' in spec + ? targetWire(c.target, spec.params.length) + : { target: c.target }), + })); + const value = + 'params' in spec + ? { ...base, checks, params: spec.params } + : { + ...base, + checks, + origin: spec.origin, + executeBy: BigInt(spec.executeBy), + failFinalAt: BigInt(spec.failFinalAt), + }; + return encodeAbiParameters( + [('params' in spec ? JOB_TEMPLATE_PARAM : JOB_SPEC_PARAM) as AbiParameter], + [value] + ); +} +/** Known callers pass the format; inference requires one canonical validated decode. */ +export function decodeJobSpec( + bytes: Hex, + options?: { format?: 'spec' | 'template' } +): JobSpec | JobSpecTemplate { + if (!isHex(bytes) || bytes.length > 524290) + fail('Invalid or oversized JobSpec encoding.'); + const valid: (JobSpec | JobSpecTemplate)[] = []; + for (const template of options?.format + ? [options.format === 'template'] + : [false, true]) { + try { + const w = decodeAbiParameters( + [(template ? JOB_TEMPLATE_PARAM : JOB_SPEC_PARAM) as AbiParameter], + bytes + )[0] as SpecWire & TemplateWire; + const reads: JobRead[] = w.reads.map(({ fills: rawFills, ...r }) => ({ + ...r, + ...(template + ? { + fills: (rawFills ?? []).map((f) => { + if (f.source > 1 || (f.source === 0 && f.param !== 0)) + fail('Invalid stored fill.'); + return { + word: f.word, + source: + f.source === 0 ? ('WALLET' as const) : ('PARAM' as const), + ...(f.source === 1 ? { param: f.param } : {}), + }; + }), + } + : {}), + })); + const checks = w.checks.map((c) => { + const common = { + read: c.read, + evaluation: EVALUATIONS[c.evaluation], + operation: OPERATIONS[c.operation], + }; + if (!template) return { ...common, target: c.target }; + const t = c as unknown as TemplateCheckWire; + const target = + t.source === 0 + ? t.value + : t.source === 1 + ? t.value === BigInt(10000) + ? PRINCIPAL + : { principalBps: t.value } + : t.source === 2 + ? { param: Number(t.value) } + : t.source === 3 && t.value === BigInt(0) + ? ('agentic:wallet' as const) + : fail('Unknown template target.'); + return { ...common, target }; + }); + const common = { + reads, + checks, + logic: nestLogic(w.logic, checks.length), + allowedMutability: MUTABILITIES[w.allowedMutability], + }; + const spec = ( + template + ? { ...common, params: w.params } + : { + ...common, + origin: w.origin, + executeBy: Number(w.executeBy), + failFinalAt: Number(w.failFinalAt), + } + ) as JobSpec | JobSpecTemplate; + if (encodeJobSpec(spec).toLowerCase() === bytes.toLowerCase()) + valid.push(spec); + } catch { + /* Wrong shape, unsupported wire, malformed enums or noncanonical bytes. */ + } + } + if (valid.length !== 1) + fail( + 'The bytes do not identify one supported canonical deployed-v2 JobSpec format.', + 'UNSUPPORTED_JOB_SPEC' + ); + return valid[0]; +} diff --git a/packages/core/src/lib/job-spec/constants.ts b/packages/core/src/lib/job-spec/constants.ts new file mode 100644 index 00000000..fe6b4c16 --- /dev/null +++ b/packages/core/src/lib/job-spec/constants.ts @@ -0,0 +1,32 @@ +export const JOB_VOCABULARY = Object.freeze({ + EVALUATION: Object.freeze({ + BOOLEAN: 'BOOLEAN', + COMPARE: 'COMPARE', + NUMBER: 'NUMBER', + PERCENTAGE: 'PERCENTAGE', + } as const), + OPERATION: Object.freeze({ + EQUAL: 'EQUAL', + NOT_EQUAL: 'NOT_EQUAL', + GREATER_THAN: 'GREATER_THAN', + GREATER_OR_EQUAL: 'GREATER_OR_EQUAL', + LESS_THAN: 'LESS_THAN', + LESS_OR_EQUAL: 'LESS_OR_EQUAL', + } as const), + LOGIC: Object.freeze({ + ALL: 'ALL', + ANY: 'ANY', + AT_LEAST: 'AT_LEAST', + } as const), + ALLOWED_MUTABILITY: Object.freeze({ + NONE: 'NONE', + CLIENT: 'CLIENT', + PROVIDER: 'PROVIDER', + BOTH: 'BOTH', + } as const), +}); +export const PRINCIPAL = 'agentic:principal' as const; +export const EVALUATIONS = Object.values(JOB_VOCABULARY.EVALUATION); +export const OPERATIONS = Object.values(JOB_VOCABULARY.OPERATION); +export const LOGIC_KINDS = Object.values(JOB_VOCABULARY.LOGIC); +export const MUTABILITIES = Object.values(JOB_VOCABULARY.ALLOWED_MUTABILITY); diff --git a/packages/core/src/lib/job-spec/helpers.ts b/packages/core/src/lib/job-spec/helpers.ts new file mode 100644 index 00000000..5ef1259f --- /dev/null +++ b/packages/core/src/lib/job-spec/helpers.ts @@ -0,0 +1,157 @@ +import { getAddress, keccak256, toHex, type Address, type Hex } from 'viem'; +import { encodeJobSpec, int256 } from './codec'; +import { PRINCIPAL } from './constants'; +import { JobSpecError } from '../market/errors'; +import type { JobSpec, JobSpecTemplate, LogicTree } from './types'; +export function resolveJobSpec( + template: JobSpecTemplate, + ctx: { + principal: bigint; + params: bigint[]; + accounts: Record; + origin: Hex; + executeBy: number; + settleWindow: number; + } +): JobSpec { + encodeJobSpec(template); + if ( + ctx.params.length !== template.params.length || + ctx.params.some( + (n, i) => int256(n) < template.params[i].min || n > template.params[i].max + ) + ) + throw new JobSpecError( + 'PARAM_OUT_OF_RANGE', + 'The job parameters do not match the template bounds.' + ); + const account = (read: number): Address => { + const r = template.reads[read]; + const a = ctx.accounts[`${r.chainNamespace}:${r.chainId}`]; + if (!a) + throw new JobSpecError( + 'UNFILLED_PLACEHOLDER', + 'Resolve the wallet account on every read chain.' + ); + return getAddress(a); + }; + const reads = template.reads.map((r, i) => { + let args = r.args; + for (const f of r.fills ?? []) { + const value = + f.source === 'WALLET' + ? BigInt(account(i)) + : BigInt.asUintN(256, ctx.params[f.param ?? 0]); + const at = 2 + f.word * 64; + args = (args.slice(0, at) + + toHex(value, { size: 32 }).slice(2) + + args.slice(at + 64)) as Hex; + } + const read = { ...r }; + delete read.fills; + return { ...read, args }; + }); + const checks = template.checks.map((c) => { + const t = c.target; + const target = + typeof t === 'bigint' + ? t + : t === PRINCIPAL + ? ctx.principal + : t === 'agentic:wallet' + ? BigInt(account(c.read)) + : 'param' in t + ? ctx.params[t.param] + : (() => { + const product = ctx.principal * t.principalBps; + if (product >= BigInt(1) << BigInt(256)) + throw new JobSpecError( + 'TARGET_OVERFLOW', + 'The principal-based target overflows uint256.' + ); + return product / BigInt(10000); + })(); + return { ...c, target: int256(target) }; + }); + const spec = { + reads, + checks, + logic: template.logic, + allowedMutability: template.allowedMutability, + origin: ctx.origin, + executeBy: ctx.executeBy, + failFinalAt: ctx.executeBy + ctx.settleWindow, + }; + encodeJobSpec(spec); + return spec; +} +const words = { + EQUAL: 'equals', + NOT_EQUAL: 'does not equal', + GREATER_THAN: 'is greater than', + GREATER_OR_EQUAL: 'is at least', + LESS_THAN: 'is less than', + LESS_OR_EQUAL: 'is at most', +}; +export function describeJobSpec( + spec: JobSpec | JobSpecTemplate, + options?: { principal?: bigint; decimals?: Record } +): { checks: string[]; logic: string; timing: string } { + encodeJobSpec(spec); + function logic(t: LogicTree): string { + return `${ + t.kind === 'ALL' ? 'All' : t.kind === 'ANY' ? 'Any' : `At least ${t.k}` + } of (${t.of + .map((x) => (typeof x === 'number' ? `check ${x + 1}` : logic(x))) + .join(', ')})`; + } + return { + checks: spec.checks.map((c) => { + const r = spec.reads[c.read]; + const t = c.target; + const target = + typeof t === 'bigint' + ? t.toString() + : t === PRINCIPAL + ? options?.principal?.toString() ?? 'principal' + : t === 'agentic:wallet' + ? 'the wallet on this chain' + : 'param' in t + ? `parameter ${t.param + 1}` + : options?.principal !== undefined + ? ((options.principal * t.principalBps) / BigInt(10000)).toString() + : `${t.principalBps} basis points of principal`; + return `Read ${c.read + 1}: ${r.target} ${r.selector} on ${ + r.chainNamespace + }:${r.chainId}, field [${r.field.join(',')}], ${c.evaluation} ${ + words[c.operation] + } ${target}${c.evaluation === 'PERCENTAGE' ? ' bps' : ' (raw units)'}.`; + }), + logic: logic(spec.logic), + timing: + 'executeBy' in spec + ? `Execute by ${new Date( + spec.executeBy * 1000 + ).toISOString()}; failure is final after ${new Date( + spec.failFinalAt * 1000 + ).toISOString()}.` + : '', + }; +} +export function specOrigin( + marketplace: Address, + cardId: bigint, + version: bigint, + principal: bigint +): Hex { + // Imported here to keep the public helpers independent of client state. + return keccak256( + ('0x' + + [ + marketplace.slice(2).padStart(64, '0'), + ...[cardId, version, principal].map((n) => + toHex(n, { size: 32 }).slice(2) + ), + ].join('')) as Hex + ); +} diff --git a/packages/core/src/lib/job-spec/index.ts b/packages/core/src/lib/job-spec/index.ts new file mode 100644 index 00000000..cd0e1ab1 --- /dev/null +++ b/packages/core/src/lib/job-spec/index.ts @@ -0,0 +1,34 @@ +import { + buildJobSpec, + buildJobSpecTemplate, + encodeJobSpec, + decodeJobSpec, +} from './codec'; +import { describeJobSpec } from './helpers'; +import { prepareJobRead } from './read'; +import { unavailable } from '../market/errors'; +import type { + JobSpec, + JobSpecTemplate, + JobSpecPreview, + PreviewJobSpecOptions, +} from './types'; +export const jobSpecUtils = Object.freeze({ + buildJobSpec, + buildJobSpecTemplate, + encodeJobSpec, + decodeJobSpec, + describeJobSpec, + prepareRead: prepareJobRead, + async previewJobSpec( + _spec: JobSpec | JobSpecTemplate, + _options: PreviewJobSpecOptions + ): Promise { + void _spec; + void _options; + return unavailable( + 'Paid JobSpec preview pending the raw-read fee and callback adapter' + ); + }, +}); +export type * from './types'; diff --git a/packages/core/src/lib/job-spec/read.ts b/packages/core/src/lib/job-spec/read.ts new file mode 100644 index 00000000..eeb48ff2 --- /dev/null +++ b/packages/core/src/lib/job-spec/read.ts @@ -0,0 +1,273 @@ +import { + encodeAbiParameters, + getAddress, + isAddress, + isHex, + toFunctionSelector, + zeroAddress, + type AbiFunction, + type AbiParameter, + type Hex, +} from 'viem'; +import { argumentLocation } from '../agentic/codec/abi-layout'; +import { JobSpecError } from '../market/errors'; +import type { JobFill, PrepareJobReadOptions, PreparedJobRead } from './types'; + +export function outputTypes(params: readonly AbiParameter[]): Hex { + function type(p: AbiParameter, depth: number): number[] { + if (depth > 16) + throw new JobSpecError('INVALID_READ', 'Output type nesting exceeds 16.'); + const a = /^(.*)\[(\d*)\]$/.exec(p.type); + if (a) { + const base = { ...p, type: a[1] } as AbiParameter; + if (!a[2]) return [9, ...type(base, depth + 1)]; + const n = Number(a[2]); + if (n < 1 || n > 255) + throw new JobSpecError( + 'INVALID_READ', + 'Fixed output arrays must contain 1..255 elements.' + ); + return [10, n, ...type(base, depth + 1)]; + } + if (p.type === 'tuple') + return tuple( + (p as { components: readonly AbiParameter[] }).components, + depth + 1 + ); + if (/^uint(\d+)?$/.test(p.type)) return [1]; + if (/^int(\d+)?$/.test(p.type)) return [2]; + if (p.type === 'bool') return [3]; + if (p.type === 'address') return [4]; + if (/^bytes([1-9]|[12]\d|3[0-2])$/.test(p.type)) return [5]; + if (p.type === 'bytes') return [6]; + if (p.type === 'string') return [7]; + throw new JobSpecError('INVALID_READ', `Unsupported ABI output ${p.type}.`); + } + function tuple(items: readonly AbiParameter[], depth: number): number[] { + if (items.length < 1 || items.length > 255) + throw new JobSpecError( + 'INVALID_READ', + 'An output tuple needs 1..255 fields.' + ); + return [8, items.length, ...items.flatMap((p) => type(p, depth))]; + } + return ('0x' + + tuple(params, 0) + .map((x) => x.toString(16).padStart(2, '0')) + .join('')) as Hex; +} + +/** Pure ABI preparation, independent of read fees, RPCs and the request preflight. */ +export function prepareJobRead( + options: PrepareJobReadOptions +): PreparedJobRead { + try { + if (!/^eip155:[1-9]\d*$/.test(options.chain)) + throw new JobSpecError( + 'CHAIN_UNSUPPORTED', + 'JobSpec reads currently support EVM chain identifiers only.' + ); + const candidates = options.abi.filter( + (x): x is AbiFunction => + x.type === 'function' && + x.name === options.functionName && + x.inputs.length === (options.args?.length ?? 0) + ); + if (candidates.length !== 1) + throw new JobSpecError( + 'INVALID_READ', + 'Select one exact function ABI for this read, including overloaded functions.' + ); + const fn = candidates[0]; + if (!['view', 'pure'].includes(fn.stateMutability)) + throw new JobSpecError( + 'INVALID_READ', + 'A JobSpec read must use a view or pure function.' + ); + const fills: JobFill[] = []; + const lower = ( + p: AbiParameter, + value: unknown, + indices: number[], + depth: number + ): unknown => { + if (depth > 16) + throw new JobSpecError( + 'INVALID_READ', + 'Read arguments are nested too deeply.' + ); + const marker = value === 'agentic:wallet'; + const param = + value && typeof value === 'object' && 'param' in value + ? (value as { param: unknown }).param + : undefined; + if (marker || param !== undefined) { + if (marker && p.type !== 'address') + throw new JobSpecError( + 'INVALID_READ', + 'WALLET read arguments must be addresses.' + ); + if (!marker && !/^u?int(\d+)?$/.test(p.type)) + throw new JobSpecError( + 'INVALID_READ', + 'PARAM read arguments must be static integers.' + ); + if ( + !marker && + (!Number.isInteger(param) || Number(param) < 0 || Number(param) > 255) + ) + throw new JobSpecError( + 'INVALID_READ', + 'Invalid template parameter index.' + ); + const word = + (argumentLocation(fn.inputs, indices, 'Read placeholder').offset - + 4) / + 32; + if (word > 255) + throw new JobSpecError( + 'INVALID_READ', + 'Read placeholder is outside the uint8 word range.' + ); + fills.push({ + word, + source: marker ? 'WALLET' : 'PARAM', + ...(!marker ? { param: Number(param) } : {}), + }); + return marker ? zeroAddress : BigInt(0); + } + const a = /^(.*)\[(\d*)\]$/.exec(p.type); + if (a) { + if (!Array.isArray(value)) + throw new JobSpecError( + 'INVALID_READ', + 'Array argument must be an array.' + ); + return value.map((v, i) => + lower( + { ...p, type: a[1] } as AbiParameter, + v, + [...indices, i], + depth + 1 + ) + ); + } + if (p.type === 'tuple') { + const fields = (p as { components: readonly AbiParameter[] }) + .components; + return fields.map((field, i) => + lower( + field, + Array.isArray(value) + ? value[i] + : (value as Record)?.[field.name ?? ''], + [...indices, i], + depth + 1 + ) + ); + } + return value; + }; + const values = fn.inputs.map((p, i) => lower(p, options.args?.[i], [i], 0)); + const [chainNamespace, chainId] = options.chain.split(':'); + return { + chainNamespace, + chainId, + target: getAddress(options.target), + selector: toFunctionSelector(fn), + args: encodeAbiParameters(fn.inputs, values), + outputs: outputTypes(fn.outputs), + ...(fills.length ? { fills } : {}), + }; + } catch (cause) { + if (cause instanceof JobSpecError) throw cause; + throw new JobSpecError( + 'INVALID_READ', + 'The read arguments or ABI are invalid.', + undefined, + cause + ); + } +} + +export interface OutputNode { + code: number; + children: OutputNode[]; + size?: number; +} +export function parseOutputs(outputs: Hex): OutputNode { + if (!isHex(outputs) || outputs.length > 8194) + throw new JobSpecError('INVALID_READ', 'Invalid output type layout.'); + const bytes = + outputs + .slice(2) + .match(/../g) + ?.map((x) => parseInt(x, 16)) ?? []; + let pos = 0; + function read(depth: number): OutputNode { + if (depth > 16 || pos >= bytes.length) + throw new JobSpecError('INVALID_READ', 'Invalid output type layout.'); + const code = bytes[pos++]; + const n: OutputNode = { code, children: [] }; + if (code === 8 || code === 10) { + n.size = bytes[pos++]; + if (!n.size) + throw new JobSpecError( + 'INVALID_READ', + 'An output tuple/array cannot be empty.' + ); + if (code === 8) + for (let i = 0; i < n.size; i++) n.children.push(read(depth + 1)); + else n.children.push(read(depth + 1)); + } else if (code === 9) n.children.push(read(depth + 1)); + else if (code < 1 || code > 7) + throw new JobSpecError('INVALID_READ', 'Unknown output type code.'); + return n; + } + const root = read(0); + if (root.code !== 8 || pos !== bytes.length) + throw new JobSpecError( + 'INVALID_READ', + 'Outputs must encode exactly one root tuple.' + ); + return root; +} +export function validateJobRead( + r: PreparedJobRead & { field?: number[]; minConfirmations?: number } +): void { + if ( + r.chainNamespace !== 'eip155' || + !/^[1-9]\d*$/.test(r.chainId) || + !isAddress(r.target) || + !/^0x[\da-f]{8}$/i.test(r.selector) || + !isHex(r.args) || + r.args.length % 2 + ) + throw new JobSpecError('INVALID_READ', 'Invalid EVM JobSpec read.'); + let node = parseOutputs(r.outputs); + const field = r.field ?? [0]; + if (field.length < 1 || field.length > 16) + throw new JobSpecError( + 'INVALID_READ', + 'Output field path must have 1..16 indexes.' + ); + for (const i of field) { + if ( + !Number.isInteger(i) || + i < 0 || + i > 255 || + ![8, 9, 10].includes(node.code) || + (node.code !== 9 && i >= (node.size ?? 0)) + ) + throw new JobSpecError( + 'INVALID_READ', + 'Output field path does not resolve.' + ); + node = node.children[node.code === 8 ? i : 0]; + } + if ([8, 10].includes(node.code)) + throw new JobSpecError( + 'INVALID_READ', + 'Choose a scalar or dynamic-length output field.' + ); +} diff --git a/packages/core/src/lib/job-spec/schema.ts b/packages/core/src/lib/job-spec/schema.ts new file mode 100644 index 00000000..93b7e794 --- /dev/null +++ b/packages/core/src/lib/job-spec/schema.ts @@ -0,0 +1,66 @@ +export const READ_FIELDS = [ + { name: 'chainNamespace', type: 'string' }, + { name: 'chainId', type: 'string' }, + { name: 'minConfirmations', type: 'uint16' }, + { name: 'target', type: 'address' }, + { name: 'selector', type: 'bytes4' }, + { name: 'args', type: 'bytes' }, + { name: 'outputs', type: 'bytes' }, + { name: 'field', type: 'uint8[]' }, +] as const; +export const FILL_FIELDS = [ + { name: 'word', type: 'uint8' }, + { name: 'source', type: 'uint8' }, + { name: 'param', type: 'uint8' }, +] as const; +export const TEMPLATE_READ_FIELDS = [ + ...READ_FIELDS.slice(0, 6), + { name: 'fills', type: 'tuple[]', components: FILL_FIELDS }, + ...READ_FIELDS.slice(6), +] as const; +export const CHECK_FIELDS = [ + { name: 'read', type: 'uint8' }, + { name: 'evaluation', type: 'uint8' }, + { name: 'operation', type: 'uint8' }, + { name: 'target', type: 'int256' }, +] as const; +export const TEMPLATE_CHECK_FIELDS = [ + ...CHECK_FIELDS.slice(0, 3), + { name: 'source', type: 'uint8' }, + { name: 'value', type: 'int256' }, +] as const; +export const LOGIC_FIELDS = [ + { name: 'kind', type: 'uint8' }, + { name: 'checks', type: 'uint8[]' }, + { name: 'children', type: 'uint8[]' }, + { name: 'k', type: 'uint8' }, +] as const; +export const JOB_SPEC_PARAM = { + type: 'tuple', + components: [ + { name: 'reads', type: 'tuple[]', components: READ_FIELDS }, + { name: 'checks', type: 'tuple[]', components: CHECK_FIELDS }, + { name: 'logic', type: 'tuple[]', components: LOGIC_FIELDS }, + { name: 'allowedMutability', type: 'uint8' }, + { name: 'origin', type: 'bytes32' }, + { name: 'executeBy', type: 'uint64' }, + { name: 'failFinalAt', type: 'uint64' }, + ], +} as const; +export const JOB_TEMPLATE_PARAM = { + type: 'tuple', + components: [ + { name: 'reads', type: 'tuple[]', components: TEMPLATE_READ_FIELDS }, + { name: 'checks', type: 'tuple[]', components: TEMPLATE_CHECK_FIELDS }, + { name: 'logic', type: 'tuple[]', components: LOGIC_FIELDS }, + { name: 'allowedMutability', type: 'uint8' }, + { + name: 'params', + type: 'tuple[]', + components: [ + { name: 'min', type: 'int256' }, + { name: 'max', type: 'int256' }, + ], + }, + ], +} as const; diff --git a/packages/core/src/lib/job-spec/types.ts b/packages/core/src/lib/job-spec/types.ts new file mode 100644 index 00000000..055d25d2 --- /dev/null +++ b/packages/core/src/lib/job-spec/types.ts @@ -0,0 +1,111 @@ +import type { Abi, Address, Hex } from 'viem'; +import type { ArgumentPath, WalletMarker } from '../agentic/agentic.types'; +import type { JOB_VOCABULARY, PRINCIPAL } from './constants'; +import type { PushChain } from '../push-chain/push-chain'; +export type Evaluation = + (typeof JOB_VOCABULARY.EVALUATION)[keyof typeof JOB_VOCABULARY.EVALUATION]; +export type Operation = + (typeof JOB_VOCABULARY.OPERATION)[keyof typeof JOB_VOCABULARY.OPERATION]; +export type LogicKind = + (typeof JOB_VOCABULARY.LOGIC)[keyof typeof JOB_VOCABULARY.LOGIC]; +export type AllowedMutability = + (typeof JOB_VOCABULARY.ALLOWED_MUTABILITY)[keyof typeof JOB_VOCABULARY.ALLOWED_MUTABILITY]; +export type PrincipalMarker = typeof PRINCIPAL; +export interface JobFill { + word: number; + source: 'WALLET' | 'PARAM'; + param?: number; +} +export interface PreparedJobRead { + chainNamespace: string; + chainId: string; + target: Address; + selector: Hex; + args: Hex; + outputs: Hex; + /** Placeholder positions are explicit; zero argument values are never treated as holes. */ + fills?: JobFill[]; +} +export interface JobRead extends PreparedJobRead { + minConfirmations: number; + field: number[]; +} +export interface PrepareJobReadOptions { + chain: string; + target: Address; + abi: Abi; + functionName: string; + args?: readonly unknown[]; +} +export interface JobReadInput { + read: PreparedJobRead; + minConfirmations?: number; + field?: number[]; +} +export interface JobCheck { + read: number; + evaluation: Evaluation; + operation: Operation; + target: bigint; +} +export interface JobCheckTemplate extends Omit { + target: + | bigint + | PrincipalMarker + | WalletMarker + | { principalBps: bigint } + | { param: number }; +} +export interface LogicTree { + kind: LogicKind; + of: (number | LogicTree)[]; + k?: number; +} +export interface JobSpec { + reads: JobRead[]; + checks: JobCheck[]; + logic: LogicTree; + allowedMutability: AllowedMutability; + origin: Hex; + executeBy: number; + failFinalAt: number; +} +export interface JobSpecTemplate { + reads: JobRead[]; + checks: JobCheckTemplate[]; + logic: LogicTree; + allowedMutability: AllowedMutability; + params: { min: bigint; max: bigint }[]; +} +export interface BuildJobSpecOptions { + reads: (PreparedJobRead | JobReadInput)[]; + checks: JobCheck[]; + logic: 'ALL' | 'ANY' | LogicTree; + allowedMutability?: AllowedMutability; + executeBy: number; + failFinalAt: number; + expiredAt?: number; + origin?: Hex; +} +export interface BuildJobSpecTemplateOptions + extends Omit< + BuildJobSpecOptions, + 'checks' | 'executeBy' | 'failFinalAt' | 'expiredAt' | 'origin' + > { + checks: JobCheckTemplate[]; + params?: { min: bigint; max: bigint }[]; +} +export interface PreviewJobSpecOptions { + client: Pick; + wallet?: Address; + principal?: bigint; + params?: bigint[]; + /** Required for cross-chain template holes: an AGW address is not its destination account. */ + accounts?: Record; +} +export interface JobSpecPreview { + reads: { value: Hex; decoded: bigint }[]; + checks: { pass: boolean | null; value: bigint }[]; + pass: boolean | null; +} +export type JobArgumentPath = ArgumentPath; diff --git a/packages/core/src/lib/job/job.ts b/packages/core/src/lib/job/job.ts new file mode 100644 index 00000000..6b14a9d7 --- /dev/null +++ b/packages/core/src/lib/job/job.ts @@ -0,0 +1,685 @@ +import { + decodeEventLog, + encodeAbiParameters, + encodeFunctionData, + erc20Abi, + getAbiItem, + getAddress, + keccak256, + stringToHex, + zeroAddress, + zeroHash, + type Address, + type Hex, +} from 'viem'; +import { JOB_KERNEL_ABI as ABI } from '../market/contracts/AgenticCommerce'; +import { RULES_HOOK_ABI } from '../market/contracts/RulesBindingHook'; +import { MARKETPLACE_ABI } from '../market/contracts/UniversalMarketplace'; +import { KERNEL_READ_ABI, encodeCreateJob } from '../market/kernel-wire'; +import { + deployment, + eventArgs, + ownerBatch, + snapshot, + write, + type MarketSnapshot, + type StackRuntime, +} from '../market/runtime'; +import { JobError, unavailable } from '../market/errors'; +import { currentGeneration } from '../agentic/deployments'; +import { getRule } from '../agentic/reads/rules'; +import { Snapshot, scanLogs } from '../agentic/reads/snapshot'; +import { decodeJobSpec } from '../job-spec/codec'; +import type { JobSpec } from '../job-spec/types'; +import type { Call } from '../agentic/contracts/v6'; +import type { + CreateJobOptions, + FundJobOptions, + Job, + JobEvent, + JobNamespace, + JobStatus, + JobWriteOptions, +} from './types'; + +const STATES: JobStatus[] = [ + 'Open', + 'Funded', + 'Submitted', + 'Completed', + 'Rejected', + 'Expired', +]; +interface KernelJob { + client: Address; + status: number; + provider: Address; + expiredAt: number; + evaluator: Address; + hook: Address; + budget: bigint; + description: Hex; +} +function validId(jobId: bigint): void { + if (typeof jobId !== 'bigint' || jobId < BigInt(1)) + throw new JobError('INVALID_JOB_ID', 'Job IDs are positive bigint values.'); +} +function amount(n: bigint): void { + if (typeof n !== 'bigint' || n < BigInt(0) || n >= BigInt(1) << BigInt(256)) + throw new JobError('INVALID_AMOUNT', 'The amount must fit uint256.'); +} + +export class JobNamespaceImpl implements JobNamespace { + constructor(private readonly rt: StackRuntime) {} + private async raw(jobId: bigint, s: MarketSnapshot): Promise { + validId(jobId); + const j = await s.read( + deployment(this.rt).kernel, + KERNEL_READ_ABI, + 'getJob', + [jobId] + ); + if (getAddress(j.client) === zeroAddress || !STATES[j.status]) + throw new JobError('JOB_NOT_FOUND', 'This job does not exist.'); + return j; + } + private async jobAt(jobId: bigint, s: MarketSnapshot): Promise { + const d = deployment(this.rt); + const j = await this.raw(jobId, s); + const paymentToken = await s.read

    (d.kernel, ABI, 'paymentToken'); + let spec: JobSpec | undefined; + let decodeError: string | undefined; + if (j.description !== '0x') { + try { + spec = decodeJobSpec(j.description, { format: 'spec' }) as JobSpec; + } catch (e) { + decodeError = (e as Error).message; + } + } + const rulesId = + getAddress(j.hook) === getAddress(d.hook) + ? await s.read(d.hook, RULES_HOOK_ABI, 'rulesOfJob', [jobId]) + : undefined; + let deliverable: Hex | undefined; + if (j.status >= 2) { + const logs = await scanLogs( + this.rt.agw.reader, + { + address: d.kernel, + event: getAbiItem({ abi: ABI, name: 'JobSubmitted' }), + args: { jobId }, + }, + this.rt.jobBlocks?.get(jobId) ?? d.startBlock, + s.blockNumber + ); + if (logs.length > 1) + throw new JobError( + 'INCONSISTENT_READ', + 'The job has multiple submission events.' + ); + if (logs.length === 1) { + const event = decodeEventLog({ + abi: ABI, + eventName: 'JobSubmitted', + data: logs[0].data, + topics: logs[0].topics, + }); + deliverable = event.args.deliverable; + } + } + return { + ...j, + jobId, + status: STATES[j.status], + paymentToken, + ...(deliverable ? { deliverable } : {}), + ...(rulesId && rulesId !== zeroHash ? { rulesId } : {}), + ...(spec ? { jobSpec: { spec, bytes: j.description } } : {}), + ...(decodeError ? { jobSpecDecodeError: decodeError } : {}), + evaluation: { + available: false, + reason: + getAddress(j.evaluator) === getAddress(d.evaluator) + ? 'MANUAL_EVALUATOR' + : 'UNVERIFIED_EVALUATOR', + }, + }; + } + async status(jobId: bigint): Promise { + return this.jobAt(jobId, await snapshot(this.rt)); + } + async list( + options: { + client?: Address; + provider?: Address; + status?: JobStatus; + fromJobId?: bigint; + } = {} + ): Promise<{ jobs: Job[] }> { + const s = await snapshot(this.rt); + const count = await s.read( + deployment(this.rt).kernel, + ABI, + 'jobCounter' + ); + const from = options.fromJobId ?? BigInt(1); + validId(from); + const jobs: Job[] = []; + for (let i = from; i <= count; i += BigInt(8)) { + const rows = await Promise.all( + Array.from( + { + length: Number( + count - i + BigInt(1) > BigInt(8) + ? BigInt(8) + : count - i + BigInt(1) + ), + }, + (_, n) => this.jobAt(i + BigInt(n), s) + ) + ); + jobs.push( + ...rows.filter( + (j) => + (!options.client || + getAddress(options.client) === getAddress(j.client)) && + (!options.provider || + getAddress(options.provider) === getAddress(j.provider)) && + (!options.status || options.status === j.status) + ) + ); + } + return { jobs }; + } + async create(options: CreateJobOptions) { + const d = deployment(this.rt); + const s = await snapshot(this.rt); + const token = await s.read
    (d.kernel, ABI, 'paymentToken'); + if (getAddress(options.paymentToken) !== getAddress(token)) + throw new JobError( + 'TOKEN_MISMATCH', + 'The job token must equal this kernel’s payment token.' + ); + if (options.jobSpec) { + const spec = decodeJobSpec(options.jobSpec, { + format: 'spec', + }) as JobSpec; + if (spec.allowedMutability !== 'NONE') + unavailable('Mutable job criteria'); + if (spec.origin !== zeroHash) + throw new JobError( + 'INVALID_JOB_SPEC', + 'A plain job must have a zero marketplace origin.' + ); + if (spec.failFinalAt >= options.expiredAt) + throw new JobError( + 'INVALID_JOB_SPEC', + 'The failure deadline must precede expiry.' + ); + } + const min = await s.read(d.kernel, ABI, 'MIN_EXPIRY_WINDOW'); + if ( + !Number.isSafeInteger(options.expiredAt) || + options.expiredAt <= s.timestamp + Number(min) || + options.expiredAt >= 2 ** 48 + ) + throw new JobError( + 'EXPIRY_TOO_SHORT', + 'Choose a future expiry beyond the kernel minimum window.' + ); + const call = { + target: d.kernel, + value: BigInt(0), + data: encodeCreateJob( + getAddress(options.provider), + getAddress(options.evaluator), + options.expiredAt, + options, + getAddress(options.hook) + ), + }; + const wallet = this.rt.wallet(); + const tx = wallet + ? await ownerBatch(this.rt, wallet, [call], options.progressHook) + : await write(this.rt, call, options.progressHook, 'JOB', true); + const e = await eventArgs(this.rt, tx, d.kernel, ABI, 'JobCreated'); + if (getAddress(e['client'] as Address) !== getAddress(this.rt.account())) + throw new JobError( + 'RECEIPT_MISMATCH', + 'The created job has a different client.', + { txHash: tx.hash } + ); + return { jobId: e['jobId'] as bigint, tx }; + } + private provider(j: KernelJob): void { + if (getAddress(j.provider) !== getAddress(this.rt.agw.signerPushAccount())) + throw new JobError('NOT_PROVIDER', 'Connect this job’s provider.'); + } + private open(j: KernelJob, now: number): void { + if (j.status !== 0 || j.expiredAt <= now) + throw new JobError('WRONG_STATUS', 'The job must be Open and unexpired.'); + } + async setBudget( + jobId: bigint, + budget: bigint, + options: JobWriteOptions & { jobSpec?: Hex } = {} + ) { + if (options.jobSpec !== undefined) + unavailable('Replacement JobSpec proposals'); + amount(budget); + const s = await snapshot(this.rt); + const j = await this.raw(jobId, s); + this.provider(j); + this.open(j, s.timestamp); + const d = deployment(this.rt); + return write( + this.rt, + { + target: d.kernel, + value: BigInt(0), + data: encodeFunctionData({ + abi: ABI, + functionName: 'setBudget', + args: [jobId, budget, '0x'], + }), + }, + options.progressHook, + 'JOB', + true + ); + } + async fund(jobId: bigint, options: FundJobOptions = {}) { + const rt = this.rt; + const d = deployment(rt); + const s = await snapshot(rt); + const j = await this.raw(jobId, s); + this.open(j, s.timestamp); + const gen = currentGeneration(rt.agw.network); + const isWallet = await s.read( + gen.addresses.factory, + gen.contracts.abis.factory, + 'isWallet', + [j.client] + ); + if (isWallet) { + const owner = await s.read
    ( + j.client, + gen.contracts.abis.wallet, + 'owner' + ); + if (getAddress(owner) !== getAddress(rt.agw.signerPushAccount())) + throw new JobError('NOT_CLIENT', 'Connect the job wallet’s owner.'); + } else if (getAddress(j.client) !== getAddress(rt.agw.signerPushAccount())) + throw new JobError('NOT_CLIENT', 'Connect this job’s client.'); + let expected = options.expectedBudget; + const cardId = await s.read( + d.marketplace, + MARKETPLACE_ABI, + 'cardOfJob', + [jobId] + ); + let rulesId = options.rulesId; + if (cardId) { + const [version, view, recordedRules] = await Promise.all([ + s.read(d.marketplace, MARKETPLACE_ABI, 'cardVersionOfJob', [ + jobId, + ]), + s.read<{ version: bigint; card: { providerFee: bigint } }>( + d.marketplace, + MARKETPLACE_ABI, + 'getAgentCard', + [cardId] + ), + s.read(d.marketplace, MARKETPLACE_ABI, 'rulesOfJob', [jobId]), + ]); + if (rulesId && rulesId !== recordedRules) + throw new JobError( + 'RULES_MISMATCH', + 'Use the permission recorded when this job was opened.' + ); + rulesId = recordedRules; + if (expected === undefined && version === view.version) + expected = view.card.providerFee; + } + if (expected === undefined) + throw new JobError( + 'EXPECTED_BUDGET_REQUIRED', + 'Pass the exact budget you reviewed; this SDK does not silently accept the latest provider quote.' + ); + amount(expected); + if (expected !== j.budget) + throw new JobError( + 'BUDGET_MISMATCH', + 'The provider’s current price differs from the budget you reviewed.', + { expectedBudget: expected, currentBudget: j.budget } + ); + let optParams: Hex = '0x'; + if (getAddress(j.hook) === getAddress(d.hook)) { + if (!isWallet || !rulesId || !/^0x[\da-f]{64}$/i.test(rulesId)) + throw new JobError( + 'RULES_REQUIRED', + 'This rules hook needs an AGW client and its rulesId.' + ); + const record = await getRule( + new Snapshot(rt.agw.reader, s.blockNumber), + gen, + j.client, + rulesId, + rt.agw.pushChainNamespace + ); + if ( + getAddress(record.agent) !== getAddress(j.provider) || + record.validUntil < j.expiredAt + ) + throw new JobError( + 'RULES_MISMATCH', + 'The live rule must authorize this provider through the job expiry.' + ); + if ( + await s.read(d.hook, RULES_HOOK_ABI, 'activeJobOf', [j.client]) + ) + throw new JobError( + 'WALLET_HAS_ACTIVE_JOB', + 'This wallet already has a funded job under the rules hook.' + ); + optParams = encodeAbiParameters([{ type: 'bytes32' }], [rulesId]); + } else if (rulesId) + throw new JobError( + 'HOOK_MISMATCH', + 'A rulesId payload is supported only for the verified rules hook.' + ); + const token = await s.read
    (d.kernel, ABI, 'paymentToken'); + const calls: Call[] = []; + if (expected > BigInt(0)) { + const [balance, allowance] = await Promise.all([ + s.read(token, erc20Abi, 'balanceOf', [j.client]), + s.read(token, erc20Abi, 'allowance', [j.client, d.kernel]), + ]); + if (balance < expected) + throw new JobError( + 'INSUFFICIENT_FUNDS', + 'The job client lacks the payment tokens required for escrow.' + ); + if (allowance < expected) { + if (allowance > BigInt(0)) + calls.push({ + target: token, + value: BigInt(0), + data: encodeFunctionData({ + abi: erc20Abi, + functionName: 'approve', + args: [d.kernel, BigInt(0)], + }), + }); + calls.push({ + target: token, + value: BigInt(0), + data: encodeFunctionData({ + abi: erc20Abi, + functionName: 'approve', + args: [d.kernel, expected], + }), + }); + } + } + calls.push({ + target: d.kernel, + value: BigInt(0), + data: encodeFunctionData({ + abi: ABI, + functionName: 'fund', + args: [jobId, expected, optParams], + }), + }); + if (isWallet) return ownerBatch(rt, j.client, calls, options.progressHook); + if (calls.length === 1) + return write(rt, calls[0], options.progressHook, 'JOB', true); + if (rt.agw.isReadOnly) + throw new JobError('READ_ONLY', 'Connect a signer to fund escrow.'); + // No sequential fallback: allowance and acceptance must belong to one atomic batch. + return rt.agw.executeAtomicBatch( + { + to: d.kernel, + value: BigInt(0), + data: calls.map((c) => ({ + to: c.target, + value: c.value, + data: c.data, + })), + }, + { progressHook: options.progressHook } + ); + } + async submit( + jobId: bigint, + options: JobWriteOptions & { deliverable: Hex | string } + ) { + const s = await snapshot(this.rt); + const j = await this.raw(jobId, s); + this.provider(j); + if (j.status !== 1 || j.expiredAt <= s.timestamp) + throw new JobError( + 'WRONG_STATUS', + 'Only an unexpired Funded job can be submitted.' + ); + const deliverable = /^0x[\da-f]{64}$/i.test(options.deliverable) + ? (options.deliverable as Hex) + : keccak256(stringToHex(options.deliverable)); + return write( + this.rt, + { + target: deployment(this.rt).kernel, + value: BigInt(0), + data: encodeFunctionData({ + abi: ABI, + functionName: 'submit', + args: [jobId, deliverable, '0x'], + }), + }, + options.progressHook, + 'JOB', + true + ); + } + async cancel(jobId: bigint, options: JobWriteOptions = {}) { + const rt = this.rt; + const d = deployment(rt); + const s = await snapshot(rt); + const j = await this.raw(jobId, s); + if (j.status !== 0) + throw new JobError( + 'WRONG_STATUS', + 'Only an Open job can be cancelled by its client.' + ); + const gen = currentGeneration(rt.agw.network); + const isWallet = await s.read( + gen.addresses.factory, + gen.contracts.abis.factory, + 'isWallet', + [j.client] + ); + const calls: Call[] = [ + { + target: d.kernel, + value: BigInt(0), + data: encodeFunctionData({ + abi: ABI, + functionName: 'reject', + args: [jobId, zeroHash, '0x'], + }), + }, + ]; + if (isWallet) { + const wallet = await s.read
    ( + d.marketplace, + MARKETPLACE_ABI, + 'agwOfJob', + [jobId] + ); + const rulesId = await s.read( + d.marketplace, + MARKETPLACE_ABI, + 'rulesOfJob', + [jobId] + ); + if ( + getAddress(wallet) === getAddress(j.client) && + rulesId !== zeroHash && + (await s.read( + gen.addresses.sessionEngine, + gen.contracts.abis.engine, + 'isPermissionEnabled', + [rulesId, j.client] + )) + ) + calls.push({ + target: j.client, + value: BigInt(0), + data: gen.contracts.encodeRevokeRules(rulesId), + }); + return ownerBatch(rt, j.client, calls, options.progressHook); + } + if (getAddress(j.client) !== getAddress(rt.agw.signerPushAccount())) + throw new JobError( + 'NOT_CLIENT', + 'Only the client can use this cancellation method.' + ); + return write(rt, calls[0], options.progressHook, 'JOB', true); + } + async claimRefund(jobId: bigint, options: JobWriteOptions = {}) { + const s = await snapshot(this.rt); + const j = await this.raw(jobId, s); + const d = deployment(this.rt); + if (![0, 1, 2].includes(j.status)) + throw new JobError('WRONG_STATUS', 'This job is already terminal.'); + const grace = + j.status === 2 + ? Number(await s.read(d.kernel, ABI, 'EVALUATOR_GRACE_PERIOD')) + : 0; + if (s.timestamp < j.expiredAt + grace) + throw new JobError( + 'REFUND_NOT_READY', + 'The expiry or evaluator grace window has not elapsed.' + ); + return write( + this.rt, + { + target: d.kernel, + value: BigInt(0), + data: encodeFunctionData({ + abi: ABI, + functionName: 'claimRefund', + args: [jobId], + }), + }, + options.progressHook, + 'JOB', + true + ); + } + async verify(_jobId: bigint, _options?: JobWriteOptions): Promise { + void _jobId; + void _options; + return unavailable( + 'Automatic job verification; the configured evaluator is manual' + ); + } + watch( + jobId: bigint, + callback: (event: JobEvent) => void, + options: { fromBlock?: bigint; pollIntervalMs?: number } = {} + ): () => void { + validId(jobId); + const d = deployment(this.rt); + let stopped = false; + let timer: ReturnType | undefined; + let cursor = options.fromBlock; + const interval = options.pollIntervalMs ?? 3000; + if ( + !Number.isSafeInteger(interval) || + interval < 25 || + (cursor !== undefined && cursor < BigInt(0)) + ) + throw new JobError( + 'INVALID_WATCH_OPTIONS', + 'Use a nonnegative block and a polling interval of at least 25ms.' + ); + const names = [ + 'JobCreated', + 'BudgetSet', + 'JobFunded', + 'JobSubmitted', + 'JobCompleted', + 'JobRejected', + 'JobExpired', + 'Refunded', + ] as const; + const kinds = [ + 'Created', + 'BudgetSet', + 'Funded', + 'Submitted', + 'Completed', + 'Rejected', + 'Expired', + 'Refunded', + ]; + const poll = async () => { + try { + const head = await this.rt.agw.reader.getBlockNumber(); + if (stopped) return; + if (cursor === undefined) cursor = head; + const end = cursor + BigInt(999) < head ? cursor + BigInt(999) : head; + if (cursor <= end) { + const groups = await Promise.all( + names.map((name) => + this.rt.agw.reader.getLogs({ + address: d.kernel, + event: getAbiItem({ abi: ABI, name }), + args: { jobId }, + fromBlock: cursor ?? head, + toBlock: end, + }) + ) + ); + const logs = groups + .flat() + .sort( + (a, b) => + Number( + (a.blockNumber ?? BigInt(0)) - (b.blockNumber ?? BigInt(0)) + ) || (a.logIndex ?? 0) - (b.logIndex ?? 0) + ); + for (const log of logs) { + if (stopped) return; + const e = decodeEventLog({ + abi: ABI, + data: log.data, + topics: log.topics, + }); + callback({ + jobId, + kind: kinds[names.indexOf(e.eventName as (typeof names)[number])], + txHash: log.transactionHash ?? undefined, + blockNumber: log.blockNumber ?? undefined, + data: e.args, + }); + } + cursor = end + BigInt(1); + } + } catch (error) { + if (!stopped) callback({ jobId, kind: 'Error', error }); + } finally { + if (!stopped) + timer = setTimeout(() => { + void poll(); + }, interval); + } + }; + void poll(); + return () => { + stopped = true; + if (timer) clearTimeout(timer); + }; + } +} diff --git a/packages/core/src/lib/job/types.ts b/packages/core/src/lib/job/types.ts new file mode 100644 index 00000000..25c6e6ad --- /dev/null +++ b/packages/core/src/lib/job/types.ts @@ -0,0 +1,98 @@ +import type { Address, Hex } from 'viem'; +import type { UniversalTxResponse } from '../orchestrator/orchestrator.types'; +import type { JobSpec } from '../job-spec/types'; +import type { StackProgressHook } from '../market/runtime'; +export type JobStatus = + | 'Open' + | 'Funded' + | 'Submitted' + | 'Completed' + | 'Rejected' + | 'Expired'; +export interface CreateJobOptions { + provider: Address; + evaluator: Address; + hook: Address; + expiredAt: number; + paymentToken: Address; + jobSpec?: Hex; + description?: string; + progressHook?: StackProgressHook; +} +export interface Job { + jobId: bigint; + client: Address; + provider: Address; + evaluator: Address; + hook: Address; + status: JobStatus; + expiredAt: number; + budget: bigint; + paymentToken: Address; + /** Raw Solidity string bytes, which may contain a binary JobSpec rather than UTF-8. */ + description: Hex; + deliverable?: Hex; + rulesId?: Hex; + jobSpec?: { + spec: JobSpec; + bytes: Hex; + /** Unavailable without a compatible evaluator. */ frozen?: boolean; + }; + jobSpecDecodeError?: string; + evaluation: { + available: false; + reason: 'MANUAL_EVALUATOR' | 'UNVERIFIED_EVALUATOR'; + }; +} +export interface JobWriteOptions { + progressHook?: StackProgressHook; +} +export interface FundJobOptions extends JobWriteOptions { + rulesId?: Hex; + /** The price the client reviewed. Required for plain jobs or an updated card version. */ + expectedBudget?: bigint; +} +export interface JobEvent { + jobId: bigint; + kind: string; + txHash?: Hex; + blockNumber?: bigint; + data?: unknown; + error?: unknown; +} +export interface JobNamespace { + create( + options: CreateJobOptions + ): Promise<{ jobId: bigint; tx: UniversalTxResponse }>; + setBudget( + jobId: bigint, + amount: bigint, + options?: JobWriteOptions & { jobSpec?: Hex } + ): Promise; + fund(jobId: bigint, options?: FundJobOptions): Promise; + submit( + jobId: bigint, + options: JobWriteOptions & { deliverable: Hex | string } + ): Promise; + cancel( + jobId: bigint, + options?: JobWriteOptions + ): Promise; + claimRefund( + jobId: bigint, + options?: JobWriteOptions + ): Promise; + verify(jobId: bigint, options?: JobWriteOptions): Promise; + status(jobId: bigint): Promise; + list(options?: { + client?: Address; + provider?: Address; + status?: JobStatus; + fromJobId?: bigint; + }): Promise<{ jobs: Job[] }>; + watch( + jobId: bigint, + callback: (event: JobEvent) => void, + options?: { fromBlock?: bigint; pollIntervalMs?: number } + ): () => void; +} diff --git a/packages/core/src/lib/market/__tests__/kernel-wire.spec.ts b/packages/core/src/lib/market/__tests__/kernel-wire.spec.ts new file mode 100644 index 00000000..8f1a1fc3 --- /dev/null +++ b/packages/core/src/lib/market/__tests__/kernel-wire.spec.ts @@ -0,0 +1,55 @@ +import { + decodeAbiParameters, + getAbiItem, + toFunctionSelector, + zeroAddress, +} from 'viem'; +import { JOB_KERNEL_ABI } from '../contracts/AgenticCommerce'; +import { decodeCreateJob, encodeCreateJob } from '../kernel-wire'; +it('preserves arbitrary binary JobSpec bytes in the Solidity string slot with its original selector', () => { + const bytes = '0xff00c0af8081'; + const data = encodeCreateJob( + zeroAddress, + zeroAddress, + 1900000000, + { jobSpec: bytes }, + zeroAddress + ); + expect(data.slice(0, 10)).toBe( + toFunctionSelector(getAbiItem({ abi: JOB_KERNEL_ABI, name: 'createJob' })) + ); + expect(decodeCreateJob(data).description).toBe(bytes); + const decoded = decodeAbiParameters( + [ + { type: 'address' }, + { type: 'address' }, + { type: 'uint256' }, + { type: 'bytes' }, + { type: 'address' }, + ], + ('0x' + data.slice(10)) as `0x${string}` + ); + expect(decoded[3]).toBe(bytes); +}); +it('supports plain UTF-8 descriptions but refuses conflicting carriers', () => { + expect( + decodeCreateJob( + encodeCreateJob( + zeroAddress, + zeroAddress, + 1, + { description: 'plain job' }, + zeroAddress + ) + ).description + ).toBe('0x706c61696e206a6f62'); + expect(() => + encodeCreateJob( + zeroAddress, + zeroAddress, + 1, + { jobSpec: '0x00', description: 'x' }, + zeroAddress + ) + ).toThrow(); +}); diff --git a/packages/core/src/lib/market/__tests__/namespace.spec.ts b/packages/core/src/lib/market/__tests__/namespace.spec.ts new file mode 100644 index 00000000..c2ccbda4 --- /dev/null +++ b/packages/core/src/lib/market/__tests__/namespace.spec.ts @@ -0,0 +1,123 @@ +import { zeroAddress, zeroHash, type Address } from 'viem'; +import { MarketNamespaceImpl } from '../market'; +import { JobNamespaceImpl } from '../../job/job'; +import { mockRuntime } from '../../agentic/__tests__/mock-runtime'; +import { FakeChain } from '../../agentic/__tests__/fake-chain'; +import type { StackRuntime } from '../runtime'; +const owner = '0x1111111111111111111111111111111111111111'; +const provider = '0x2222222222222222222222222222222222222222'; +function runtime(signer: Address = owner) { + const base = mockRuntime(new FakeChain(), { signer }); + const read = jest.fn(async (args: { functionName: string }) => { + switch (args.functionName) { + case 'getJob': + return { + client: owner, + provider, + hook: zeroAddress, + evaluator: provider, + status: 0, + expiredAt: 2000000000, + budget: BigInt(5), + description: '0x', + }; + case 'agentCardCount': + return BigInt(1); + case 'getAgentCard': + return { + card: { + provider, + chainNamespace: 'eip155:11155111', + jobType: zeroHash, + metadataURI: 'invalid template example', + metadataHash: zeroHash, + active: true, + providerFee: BigInt(5), + }, + version: BigInt(1), + verified: false, + disabled: false, + rules: '0xdead', + jobSpecTemplate: '0xdead', + }; + case 'getAgentRating': + return BigInt(0); + case 'cardOfJob': + return BigInt(0); + case 'isWallet': + return false; + default: + throw new Error(`unexpected read ${args.functionName}`); + } + }); + const rt: StackRuntime = { + agw: { + ...base, + reader: { + ...base.reader, + readContract: read, + getBlockNumber: async () => BigInt(10), + }, + }, + account: () => owner as Address, + wallet: () => undefined, + signTypedData: jest.fn(), + send: jest.fn(), + }; + return { rt, read, execute: base.executeMock }; +} +it('a provider’s malformed unverified template cannot break registry summary enumeration', async () => { + const { rt } = runtime(); + const market = new MarketNamespaceImpl(rt); + expect((await market.cards()).cards[0]).toMatchObject({ + provider, + cardId: BigInt(1), + verified: false, + }); + await expect(market.card(BigInt(1))).rejects.toMatchObject({ + code: 'INVALID_AGENT_CARD_RULES', + }); +}); +it('lets a provider deactivate a malformed card without decoding its broken template', async () => { + const { rt, execute } = runtime(provider); + await new MarketNamespaceImpl(rt).agent.setActive(BigInt(1), false); + expect(execute).toHaveBeenCalledTimes(1); +}); +it('delivers the correct terminal family to the per-call hook once when waiting repeatedly', async () => { + const { rt } = runtime(provider); + const events: string[] = []; + const tx = await new JobNamespaceImpl(rt).setBudget(BigInt(1), BigInt(5), { + progressHook: (e) => events.push(e.id), + }); + await tx.wait(); + await tx.wait(); + expect(events.filter((id) => id === 'JOB-TX-199-01')).toHaveLength(1); + expect(events).not.toContain('MARKET-TX-199-01'); +}); +it('plain jobs require an explicitly reviewed budget rather than silently adopting a re-quote', async () => { + const { rt, execute } = runtime(); + const job = new JobNamespaceImpl(rt); + await expect(job.fund(BigInt(1))).rejects.toMatchObject({ + code: 'EXPECTED_BUDGET_REQUIRED', + }); + await expect( + job.fund(BigInt(1), { expectedBudget: BigInt(4) }) + ).rejects.toMatchObject({ code: 'BUDGET_MISMATCH' }); + expect(execute).not.toHaveBeenCalled(); +}); +it('placeholder methods and replacement proposals fail before any reads or signatures', async () => { + const { rt, read } = runtime(); + const job = new JobNamespaceImpl(rt); + const market = new MarketNamespaceImpl(rt); + await expect(job.verify(BigInt(1))).rejects.toMatchObject({ + code: 'CAPABILITY_UNAVAILABLE', + }); + await expect( + job.setBudget(BigInt(1), BigInt(5), { jobSpec: '0x00' }) + ).rejects.toMatchObject({ code: 'CAPABILITY_UNAVAILABLE' }); + await expect(market.deposit(BigInt(1))).rejects.toMatchObject({ + code: 'CAPABILITY_UNAVAILABLE', + }); + expect(read).not.toHaveBeenCalled(); + expect(rt.signTypedData).not.toHaveBeenCalled(); +}); diff --git a/packages/core/src/lib/market/__tests__/rules.spec.ts b/packages/core/src/lib/market/__tests__/rules.spec.ts new file mode 100644 index 00000000..6510768a --- /dev/null +++ b/packages/core/src/lib/market/__tests__/rules.spec.ts @@ -0,0 +1,115 @@ +import { decodeAbiParameters, encodeAbiParameters } from 'viem'; +import { PRINCIPAL } from '../../job-spec/constants'; +import { PUSH_NETWORK } from '../../constants/enums'; +import { SYNTHETIC_PUSH_ERC20 } from '../../constants/chain'; +import { + CARD_RULES_PARAM, + MARKER_PRINCIPAL, + decodeAgentCardRules, + encodeAgentCardRules, + validateAgentCardRules, + type AgentCardRules, +} from '../rules'; +const token = '0x1111111111111111111111111111111111111111'; +const spender = '0x2222222222222222222222222222222222222222'; +const options = { chain: 'eip155:11155111' }; +function rules(): AgentCardRules { + return { + assets: [ + { token: { prc20: token }, maxPerCall: PRINCIPAL, maxTotal: PRINCIPAL }, + ], + principalAsset: 0, + maxGasPerCall: BigInt(1), + allowedCalls: [ + { + target: token, + selector: 'approve(address,uint256)', + pins: [ + { arg: 0, expected: spender }, + { arg: 1, max: PRINCIPAL }, + ], + }, + { + target: token, + selector: 'transfer(address,uint256)', + pins: [ + { arg: 0, expected: 'agentic:wallet' }, + { arg: 1, max: PRINCIPAL }, + ], + }, + ], + }; +} +it('encodes v2’s four-field rules, accepts pinned approvals and fills published markers', () => { + const r = rules(); + validateAgentCardRules(r); + const bytes = encodeAgentCardRules(r, options); + const w = decodeAbiParameters([CARD_RULES_PARAM], bytes)[0]; + expect(w.assets[0].maxTotal).toBe(BigInt(MARKER_PRINCIPAL)); + expect(w.allowedCalls[0].pins[1].value).toBe(MARKER_PRINCIPAL); + expect(encodeAgentCardRules(decodeAgentCardRules(bytes), options)).toBe( + bytes + ); +}); +it('retains legacy beneficiary fields during an unchanged decode/encode', () => { + const w = decodeAbiParameters( + [CARD_RULES_PARAM], + encodeAgentCardRules(rules(), options) + )[0]; + const bytes = encodeAbiParameters( + [CARD_RULES_PARAM], + [ + { + ...w, + allowedCalls: [ + { + ...w.allowedCalls[1], + hasBeneficiary: true, + beneficiaryOffset: 4, + pins: [], + }, + ], + }, + ] + ); + expect(encodeAgentCardRules(decodeAgentCardRules(bytes), options)).toBe( + bytes + ); +}); +it('uses the explicit execution chain for native-token objects shared by several networks', () => { + const r = rules(); + r.assets[0].token = { + symbol: 'ETH', + decimals: 18, + mechanism: 'native', + address: '0x0000000000000000000000000000000000000000', + }; + const w = decodeAbiParameters( + [CARD_RULES_PARAM], + encodeAgentCardRules(r, options) + )[0]; + expect(w.assets[0].token.toLowerCase()).toBe( + SYNTHETIC_PUSH_ERC20[PUSH_NETWORK.TESTNET_DONUT].pETH.toLowerCase() + ); +}); +it.each(['spender', 'amount', 'recipient', 'increaseAllowance', 'oldArray'])( + 'refuses unsupported approval or transfer authority: %s', + (which) => { + const r = rules(); + if (which === 'spender') r.allowedCalls[0].pins!.shift(); + if (which === 'amount') r.allowedCalls[0].pins!.pop(); + if (which === 'recipient') r.allowedCalls[1].pins!.shift(); + if (which === 'increaseAllowance') + r.allowedCalls[0].selector = 'increaseAllowance(address,uint256)'; + if (which === 'oldArray') Object.assign(r, { approvals: [] }); + expect(() => encodeAgentCardRules(r, options)).toThrow(); + } +); +it('does not silently drop duplicate alternatives or caps off the principal asset', () => { + const r = rules(); + r.allowedCalls.push(r.allowedCalls[0]); + expect(() => encodeAgentCardRules(r, options)).toThrow(/Duplicate/); + r.allowedCalls.pop(); + r.assets.push({ token: { prc20: spender }, maxPerCall: PRINCIPAL }); + expect(() => encodeAgentCardRules(r, options)).toThrow(/principal asset/); +}); diff --git a/packages/core/src/lib/market/contracts/AgenticCommerce.ts b/packages/core/src/lib/market/contracts/AgenticCommerce.ts new file mode 100644 index 00000000..261909e6 --- /dev/null +++ b/packages/core/src/lib/market/contracts/AgenticCommerce.ts @@ -0,0 +1,1313 @@ +// Generated from sdk-iteration-v1@443b4e2; Donut marketplace v2. +export const JOB_KERNEL_ABI = [ + { + type: 'constructor', + inputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + name: 'ADMIN_ROLE', + inputs: [], + outputs: [ + { + name: '', + type: 'bytes32', + internalType: 'bytes32', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'BPS_DENOMINATOR', + inputs: [], + outputs: [ + { + name: '', + type: 'uint256', + internalType: 'uint256', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'DEFAULT_ADMIN_ROLE', + inputs: [], + outputs: [ + { + name: '', + type: 'bytes32', + internalType: 'bytes32', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'EVALUATOR_GRACE_PERIOD', + inputs: [], + outputs: [ + { + name: '', + type: 'uint256', + internalType: 'uint256', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'MIN_EXPIRY_WINDOW', + inputs: [], + outputs: [ + { + name: '', + type: 'uint256', + internalType: 'uint256', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'batchDetachHook', + inputs: [ + { + name: 'jobIds', + type: 'uint256[]', + internalType: 'uint256[]', + }, + ], + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + name: 'claimRefund', + inputs: [ + { + name: 'jobId', + type: 'uint256', + internalType: 'uint256', + }, + ], + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + name: 'complete', + inputs: [ + { + name: 'jobId', + type: 'uint256', + internalType: 'uint256', + }, + { + name: 'reason', + type: 'bytes32', + internalType: 'bytes32', + }, + { + name: 'optParams', + type: 'bytes', + internalType: 'bytes', + }, + ], + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + name: 'createJob', + inputs: [ + { + name: 'provider', + type: 'address', + internalType: 'address', + }, + { + name: 'evaluator', + type: 'address', + internalType: 'address', + }, + { + name: 'expiredAt', + type: 'uint256', + internalType: 'uint256', + }, + { + name: 'description', + type: 'string', + internalType: 'string', + }, + { + name: 'hook', + type: 'address', + internalType: 'address', + }, + ], + outputs: [ + { + name: 'jobId', + type: 'uint256', + internalType: 'uint256', + }, + ], + stateMutability: 'nonpayable', + }, + { + type: 'function', + name: 'emergencyWithdraw', + inputs: [ + { + name: 'token', + type: 'address', + internalType: 'address', + }, + { + name: 'to', + type: 'address', + internalType: 'address', + }, + { + name: 'amount', + type: 'uint256', + internalType: 'uint256', + }, + ], + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + name: 'evaluatorFeeBP', + inputs: [], + outputs: [ + { + name: '', + type: 'uint256', + internalType: 'uint256', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'fund', + inputs: [ + { + name: 'jobId', + type: 'uint256', + internalType: 'uint256', + }, + { + name: 'expectedBudget', + type: 'uint256', + internalType: 'uint256', + }, + { + name: 'optParams', + type: 'bytes', + internalType: 'bytes', + }, + ], + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + name: 'getJob', + inputs: [ + { + name: 'jobId', + type: 'uint256', + internalType: 'uint256', + }, + ], + outputs: [ + { + name: '', + type: 'tuple', + internalType: 'struct IAgenticCommerce.Job', + components: [ + { + name: 'client', + type: 'address', + internalType: 'address', + }, + { + name: 'status', + type: 'uint8', + internalType: 'enum IAgenticCommerce.JobStatus', + }, + { + name: 'provider', + type: 'address', + internalType: 'address', + }, + { + name: 'expiredAt', + type: 'uint48', + internalType: 'uint48', + }, + { + name: 'evaluator', + type: 'address', + internalType: 'address', + }, + { + name: 'hook', + type: 'address', + internalType: 'address', + }, + { + name: 'budget', + type: 'uint256', + internalType: 'uint256', + }, + { + name: 'description', + type: 'string', + internalType: 'string', + }, + ], + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'getRoleAdmin', + inputs: [ + { + name: 'role', + type: 'bytes32', + internalType: 'bytes32', + }, + ], + outputs: [ + { + name: '', + type: 'bytes32', + internalType: 'bytes32', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'grantRole', + inputs: [ + { + name: 'role', + type: 'bytes32', + internalType: 'bytes32', + }, + { + name: 'account', + type: 'address', + internalType: 'address', + }, + ], + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + name: 'hasRole', + inputs: [ + { + name: 'role', + type: 'bytes32', + internalType: 'bytes32', + }, + { + name: 'account', + type: 'address', + internalType: 'address', + }, + ], + outputs: [ + { + name: '', + type: 'bool', + internalType: 'bool', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'initialize', + inputs: [ + { + name: 'paymentToken_', + type: 'address', + internalType: 'address', + }, + { + name: 'treasury_', + type: 'address', + internalType: 'address', + }, + { + name: 'admin_', + type: 'address', + internalType: 'address', + }, + ], + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + name: 'jobCounter', + inputs: [], + outputs: [ + { + name: '', + type: 'uint256', + internalType: 'uint256', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'pause', + inputs: [], + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + name: 'paused', + inputs: [], + outputs: [ + { + name: '', + type: 'bool', + internalType: 'bool', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'paymentToken', + inputs: [], + outputs: [ + { + name: '', + type: 'address', + internalType: 'contract IERC20', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'platformFeeBP', + inputs: [], + outputs: [ + { + name: '', + type: 'uint256', + internalType: 'uint256', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'platformTreasury', + inputs: [], + outputs: [ + { + name: '', + type: 'address', + internalType: 'address', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'reject', + inputs: [ + { + name: 'jobId', + type: 'uint256', + internalType: 'uint256', + }, + { + name: 'reason', + type: 'bytes32', + internalType: 'bytes32', + }, + { + name: 'optParams', + type: 'bytes', + internalType: 'bytes', + }, + ], + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + name: 'renounceRole', + inputs: [ + { + name: 'role', + type: 'bytes32', + internalType: 'bytes32', + }, + { + name: 'callerConfirmation', + type: 'address', + internalType: 'address', + }, + ], + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + name: 'revokeRole', + inputs: [ + { + name: 'role', + type: 'bytes32', + internalType: 'bytes32', + }, + { + name: 'account', + type: 'address', + internalType: 'address', + }, + ], + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + name: 'setBudget', + inputs: [ + { + name: 'jobId', + type: 'uint256', + internalType: 'uint256', + }, + { + name: 'amount', + type: 'uint256', + internalType: 'uint256', + }, + { + name: 'optParams', + type: 'bytes', + internalType: 'bytes', + }, + ], + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + name: 'setEvaluatorFee', + inputs: [ + { + name: 'feeBP', + type: 'uint256', + internalType: 'uint256', + }, + ], + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + name: 'setHookWhitelist', + inputs: [ + { + name: 'hook', + type: 'address', + internalType: 'address', + }, + { + name: 'status', + type: 'bool', + internalType: 'bool', + }, + ], + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + name: 'setPlatformFee', + inputs: [ + { + name: 'feeBP', + type: 'uint256', + internalType: 'uint256', + }, + { + name: 'treasury', + type: 'address', + internalType: 'address', + }, + ], + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + name: 'setProvider', + inputs: [ + { + name: 'jobId', + type: 'uint256', + internalType: 'uint256', + }, + { + name: 'provider', + type: 'address', + internalType: 'address', + }, + { + name: 'optParams', + type: 'bytes', + internalType: 'bytes', + }, + ], + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + name: 'submit', + inputs: [ + { + name: 'jobId', + type: 'uint256', + internalType: 'uint256', + }, + { + name: 'deliverable', + type: 'bytes32', + internalType: 'bytes32', + }, + { + name: 'optParams', + type: 'bytes', + internalType: 'bytes', + }, + ], + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + name: 'supportsInterface', + inputs: [ + { + name: 'interfaceId', + type: 'bytes4', + internalType: 'bytes4', + }, + ], + outputs: [ + { + name: '', + type: 'bool', + internalType: 'bool', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'totalEscrowed', + inputs: [], + outputs: [ + { + name: '', + type: 'uint256', + internalType: 'uint256', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'unpause', + inputs: [], + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + name: 'whitelistedHooks', + inputs: [ + { + name: '', + type: 'address', + internalType: 'address', + }, + ], + outputs: [ + { + name: '', + type: 'bool', + internalType: 'bool', + }, + ], + stateMutability: 'view', + }, + { + type: 'event', + name: 'BudgetSet', + inputs: [ + { + name: 'jobId', + type: 'uint256', + indexed: true, + internalType: 'uint256', + }, + { + name: 'amount', + type: 'uint256', + indexed: false, + internalType: 'uint256', + }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'EmergencyWithdraw', + inputs: [ + { + name: 'token', + type: 'address', + indexed: true, + internalType: 'address', + }, + { + name: 'to', + type: 'address', + indexed: true, + internalType: 'address', + }, + { + name: 'amount', + type: 'uint256', + indexed: false, + internalType: 'uint256', + }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'EvaluatorFeePaid', + inputs: [ + { + name: 'jobId', + type: 'uint256', + indexed: true, + internalType: 'uint256', + }, + { + name: 'evaluator', + type: 'address', + indexed: true, + internalType: 'address', + }, + { + name: 'amount', + type: 'uint256', + indexed: false, + internalType: 'uint256', + }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'EvaluatorFeeUpdated', + inputs: [ + { + name: 'feeBP', + type: 'uint256', + indexed: false, + internalType: 'uint256', + }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'HookDetached', + inputs: [ + { + name: 'jobId', + type: 'uint256', + indexed: true, + internalType: 'uint256', + }, + { + name: 'hook', + type: 'address', + indexed: true, + internalType: 'address', + }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'HookWhitelistUpdated', + inputs: [ + { + name: 'hook', + type: 'address', + indexed: true, + internalType: 'address', + }, + { + name: 'status', + type: 'bool', + indexed: false, + internalType: 'bool', + }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'Initialized', + inputs: [ + { + name: 'version', + type: 'uint64', + indexed: false, + internalType: 'uint64', + }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'JobCompleted', + inputs: [ + { + name: 'jobId', + type: 'uint256', + indexed: true, + internalType: 'uint256', + }, + { + name: 'evaluator', + type: 'address', + indexed: true, + internalType: 'address', + }, + { + name: 'reason', + type: 'bytes32', + indexed: false, + internalType: 'bytes32', + }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'JobCreated', + inputs: [ + { + name: 'jobId', + type: 'uint256', + indexed: true, + internalType: 'uint256', + }, + { + name: 'client', + type: 'address', + indexed: true, + internalType: 'address', + }, + { + name: 'provider', + type: 'address', + indexed: true, + internalType: 'address', + }, + { + name: 'evaluator', + type: 'address', + indexed: false, + internalType: 'address', + }, + { + name: 'expiredAt', + type: 'uint256', + indexed: false, + internalType: 'uint256', + }, + { + name: 'hook', + type: 'address', + indexed: false, + internalType: 'address', + }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'JobExpired', + inputs: [ + { + name: 'jobId', + type: 'uint256', + indexed: true, + internalType: 'uint256', + }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'JobFunded', + inputs: [ + { + name: 'jobId', + type: 'uint256', + indexed: true, + internalType: 'uint256', + }, + { + name: 'client', + type: 'address', + indexed: true, + internalType: 'address', + }, + { + name: 'amount', + type: 'uint256', + indexed: false, + internalType: 'uint256', + }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'JobRejected', + inputs: [ + { + name: 'jobId', + type: 'uint256', + indexed: true, + internalType: 'uint256', + }, + { + name: 'rejector', + type: 'address', + indexed: true, + internalType: 'address', + }, + { + name: 'reason', + type: 'bytes32', + indexed: false, + internalType: 'bytes32', + }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'JobSubmitted', + inputs: [ + { + name: 'jobId', + type: 'uint256', + indexed: true, + internalType: 'uint256', + }, + { + name: 'provider', + type: 'address', + indexed: true, + internalType: 'address', + }, + { + name: 'deliverable', + type: 'bytes32', + indexed: false, + internalType: 'bytes32', + }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'Paused', + inputs: [ + { + name: 'account', + type: 'address', + indexed: false, + internalType: 'address', + }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'PaymentReleased', + inputs: [ + { + name: 'jobId', + type: 'uint256', + indexed: true, + internalType: 'uint256', + }, + { + name: 'provider', + type: 'address', + indexed: true, + internalType: 'address', + }, + { + name: 'amount', + type: 'uint256', + indexed: false, + internalType: 'uint256', + }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'PlatformFeePaid', + inputs: [ + { + name: 'jobId', + type: 'uint256', + indexed: true, + internalType: 'uint256', + }, + { + name: 'treasury', + type: 'address', + indexed: true, + internalType: 'address', + }, + { + name: 'amount', + type: 'uint256', + indexed: false, + internalType: 'uint256', + }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'PlatformFeeUpdated', + inputs: [ + { + name: 'feeBP', + type: 'uint256', + indexed: false, + internalType: 'uint256', + }, + { + name: 'treasury', + type: 'address', + indexed: true, + internalType: 'address', + }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'ProviderSet', + inputs: [ + { + name: 'jobId', + type: 'uint256', + indexed: true, + internalType: 'uint256', + }, + { + name: 'provider', + type: 'address', + indexed: true, + internalType: 'address', + }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'Refunded', + inputs: [ + { + name: 'jobId', + type: 'uint256', + indexed: true, + internalType: 'uint256', + }, + { + name: 'client', + type: 'address', + indexed: true, + internalType: 'address', + }, + { + name: 'amount', + type: 'uint256', + indexed: false, + internalType: 'uint256', + }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'RoleAdminChanged', + inputs: [ + { + name: 'role', + type: 'bytes32', + indexed: true, + internalType: 'bytes32', + }, + { + name: 'previousAdminRole', + type: 'bytes32', + indexed: true, + internalType: 'bytes32', + }, + { + name: 'newAdminRole', + type: 'bytes32', + indexed: true, + internalType: 'bytes32', + }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'RoleGranted', + inputs: [ + { + name: 'role', + type: 'bytes32', + indexed: true, + internalType: 'bytes32', + }, + { + name: 'account', + type: 'address', + indexed: true, + internalType: 'address', + }, + { + name: 'sender', + type: 'address', + indexed: true, + internalType: 'address', + }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'RoleRevoked', + inputs: [ + { + name: 'role', + type: 'bytes32', + indexed: true, + internalType: 'bytes32', + }, + { + name: 'account', + type: 'address', + indexed: true, + internalType: 'address', + }, + { + name: 'sender', + type: 'address', + indexed: true, + internalType: 'address', + }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'Unpaused', + inputs: [ + { + name: 'account', + type: 'address', + indexed: false, + internalType: 'address', + }, + ], + anonymous: false, + }, + { + type: 'error', + name: 'AccessControlBadConfirmation', + inputs: [], + }, + { + type: 'error', + name: 'AccessControlUnauthorizedAccount', + inputs: [ + { + name: 'account', + type: 'address', + internalType: 'address', + }, + { + name: 'neededRole', + type: 'bytes32', + internalType: 'bytes32', + }, + ], + }, + { + type: 'error', + name: 'BudgetMismatch', + inputs: [], + }, + { + type: 'error', + name: 'ClientIsProvider', + inputs: [], + }, + { + type: 'error', + name: 'EnforcedPause', + inputs: [], + }, + { + type: 'error', + name: 'EvaluatorIsProvider', + inputs: [], + }, + { + type: 'error', + name: 'ExpectedPause', + inputs: [], + }, + { + type: 'error', + name: 'ExpiryTooShort', + inputs: [], + }, + { + type: 'error', + name: 'FeesTooHigh', + inputs: [], + }, + { + type: 'error', + name: 'GracePeriodActive', + inputs: [], + }, + { + type: 'error', + name: 'HookNotWhitelisted', + inputs: [], + }, + { + type: 'error', + name: 'InsufficientUnattributedBalance', + inputs: [ + { + name: 'requested', + type: 'uint256', + internalType: 'uint256', + }, + { + name: 'available', + type: 'uint256', + internalType: 'uint256', + }, + ], + }, + { + type: 'error', + name: 'InvalidHook', + inputs: [], + }, + { + type: 'error', + name: 'InvalidInitialization', + inputs: [], + }, + { + type: 'error', + name: 'InvalidJob', + inputs: [], + }, + { + type: 'error', + name: 'NotInitializing', + inputs: [], + }, + { + type: 'error', + name: 'ProviderNotSet', + inputs: [], + }, + { + type: 'error', + name: 'ReentrancyGuardReentrantCall', + inputs: [], + }, + { + type: 'error', + name: 'SafeERC20FailedOperation', + inputs: [ + { + name: 'token', + type: 'address', + internalType: 'address', + }, + ], + }, + { + type: 'error', + name: 'Unauthorized', + inputs: [], + }, + { + type: 'error', + name: 'WrongStatus', + inputs: [], + }, + { + type: 'error', + name: 'ZeroAddress', + inputs: [], + }, +] as const; diff --git a/packages/core/src/lib/market/contracts/RulesBindingHook.ts b/packages/core/src/lib/market/contracts/RulesBindingHook.ts new file mode 100644 index 00000000..6a8fc5d8 --- /dev/null +++ b/packages/core/src/lib/market/contracts/RulesBindingHook.ts @@ -0,0 +1,310 @@ +// Generated from sdk-iteration-v1@443b4e2; Donut marketplace v2. +export const RULES_HOOK_ABI = [ + { + type: 'constructor', + inputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + name: 'AGW_FACTORY', + inputs: [], + outputs: [ + { + name: '', + type: 'address', + internalType: 'address', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'KERNEL', + inputs: [], + outputs: [ + { + name: '', + type: 'address', + internalType: 'address', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'SESSION_ENGINE', + inputs: [], + outputs: [ + { + name: '', + type: 'address', + internalType: 'address', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'activeJobOf', + inputs: [ + { + name: 'agw', + type: 'address', + internalType: 'address', + }, + ], + outputs: [ + { + name: '', + type: 'uint256', + internalType: 'uint256', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'afterAction', + inputs: [ + { + name: 'jobId', + type: 'uint256', + internalType: 'uint256', + }, + { + name: 'selector', + type: 'bytes4', + internalType: 'bytes4', + }, + { + name: 'data', + type: 'bytes', + internalType: 'bytes', + }, + ], + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + name: 'agwOfJob', + inputs: [ + { + name: 'jobId', + type: 'uint256', + internalType: 'uint256', + }, + ], + outputs: [ + { + name: '', + type: 'address', + internalType: 'address', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'beforeAction', + inputs: [ + { + name: 'jobId', + type: 'uint256', + internalType: 'uint256', + }, + { + name: 'selector', + type: 'bytes4', + internalType: 'bytes4', + }, + { + name: 'data', + type: 'bytes', + internalType: 'bytes', + }, + ], + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + name: 'initialize', + inputs: [ + { + name: 'kernel_', + type: 'address', + internalType: 'address', + }, + { + name: 'agwFactory_', + type: 'address', + internalType: 'address', + }, + { + name: 'sessionEngine_', + type: 'address', + internalType: 'address', + }, + ], + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + name: 'rulesOfJob', + inputs: [ + { + name: 'jobId', + type: 'uint256', + internalType: 'uint256', + }, + ], + outputs: [ + { + name: '', + type: 'bytes32', + internalType: 'bytes32', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'supportsInterface', + inputs: [ + { + name: 'interfaceId', + type: 'bytes4', + internalType: 'bytes4', + }, + ], + outputs: [ + { + name: '', + type: 'bool', + internalType: 'bool', + }, + ], + stateMutability: 'view', + }, + { + type: 'event', + name: 'Initialized', + inputs: [ + { + name: 'version', + type: 'uint64', + indexed: false, + internalType: 'uint64', + }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'RulesBound', + inputs: [ + { + name: 'jobId', + type: 'uint256', + indexed: true, + internalType: 'uint256', + }, + { + name: 'agw', + type: 'address', + indexed: true, + internalType: 'address', + }, + { + name: 'rulesId', + type: 'bytes32', + indexed: true, + internalType: 'bytes32', + }, + ], + anonymous: false, + }, + { + type: 'error', + name: 'AGWHasLiveJob', + inputs: [ + { + name: 'agw', + type: 'address', + internalType: 'address', + }, + { + name: 'liveJobId', + type: 'uint256', + internalType: 'uint256', + }, + ], + }, + { + type: 'error', + name: 'CallerIsNotAGW', + inputs: [ + { + name: 'caller', + type: 'address', + internalType: 'address', + }, + ], + }, + { + type: 'error', + name: 'CallerIsNotKernel', + inputs: [ + { + name: 'caller', + type: 'address', + internalType: 'address', + }, + ], + }, + { + type: 'error', + name: 'InvalidInitialization', + inputs: [], + }, + { + type: 'error', + name: 'InvalidOptParams', + inputs: [ + { + name: 'length', + type: 'uint256', + internalType: 'uint256', + }, + ], + }, + { + type: 'error', + name: 'NotInitializing', + inputs: [], + }, + { + type: 'error', + name: 'RulesNotLive', + inputs: [ + { + name: 'agw', + type: 'address', + internalType: 'address', + }, + { + name: 'rulesId', + type: 'bytes32', + internalType: 'bytes32', + }, + ], + }, + { + type: 'error', + name: 'ZeroAddress', + inputs: [], + }, +] as const; diff --git a/packages/core/src/lib/market/contracts/UniversalMarketplace.ts b/packages/core/src/lib/market/contracts/UniversalMarketplace.ts new file mode 100644 index 00000000..6cb8b3a3 --- /dev/null +++ b/packages/core/src/lib/market/contracts/UniversalMarketplace.ts @@ -0,0 +1,2291 @@ +// Generated from sdk-iteration-v1@443b4e2; Donut marketplace v2. +export const MARKETPLACE_ABI = [ + { + type: 'constructor', + inputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + name: 'ADMIN_ROLE', + inputs: [], + outputs: [ + { + name: '', + type: 'bytes32', + internalType: 'bytes32', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'AGW_FACTORY', + inputs: [], + outputs: [ + { + name: '', + type: 'address', + internalType: 'contract IAGWFactory', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'DEFAULT_ADMIN_ROLE', + inputs: [], + outputs: [ + { + name: '', + type: 'bytes32', + internalType: 'bytes32', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'KERNEL', + inputs: [], + outputs: [ + { + name: '', + type: 'address', + internalType: 'contract IAgenticCommerce', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'MODE_SINGLE', + inputs: [], + outputs: [ + { + name: '', + type: 'bytes32', + internalType: 'bytes32', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'OPENJOB_LANE', + inputs: [], + outputs: [ + { + name: '', + type: 'uint192', + internalType: 'uint192', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'PUSH_CHAIN_HASH', + inputs: [], + outputs: [ + { + name: '', + type: 'bytes32', + internalType: 'bytes32', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'RULES', + inputs: [], + outputs: [ + { + name: '', + type: 'address', + internalType: 'contract IUniversalMarketplaceRules', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'activeJobOf', + inputs: [ + { + name: 'agw', + type: 'address', + internalType: 'address', + }, + ], + outputs: [ + { + name: '', + type: 'uint256', + internalType: 'uint256', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'agentCardCount', + inputs: [], + outputs: [ + { + name: '', + type: 'uint256', + internalType: 'uint256', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'agentCardOf', + inputs: [ + { + name: '', + type: 'address', + internalType: 'address', + }, + ], + outputs: [ + { + name: '', + type: 'uint256', + internalType: 'uint256', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'agentCardVersion', + inputs: [ + { + name: '', + type: 'uint256', + internalType: 'uint256', + }, + ], + outputs: [ + { + name: '', + type: 'uint256', + internalType: 'uint256', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'agwOfJob', + inputs: [ + { + name: '', + type: 'uint256', + internalType: 'uint256', + }, + ], + outputs: [ + { + name: '', + type: 'address', + internalType: 'address', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'buildCreateJobCalldata', + inputs: [ + { + name: 'cardId', + type: 'uint256', + internalType: 'uint256', + }, + { + name: 'owner', + type: 'address', + internalType: 'address', + }, + { + name: 'index', + type: 'uint96', + internalType: 'uint96', + }, + { + name: 'job', + type: 'tuple', + internalType: 'struct JobInputs', + components: [ + { + name: 'principal', + type: 'uint256', + internalType: 'uint256', + }, + { + name: 'expiredAt', + type: 'uint48', + internalType: 'uint48', + }, + { + name: 'executeBy', + type: 'uint48', + internalType: 'uint48', + }, + { + name: 'params', + type: 'int256[]', + internalType: 'int256[]', + }, + ], + }, + ], + outputs: [ + { + name: 'mode', + type: 'bytes32', + internalType: 'bytes32', + }, + { + name: 'executionCalldata', + type: 'bytes', + internalType: 'bytes', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'cardOfJob', + inputs: [ + { + name: '', + type: 'uint256', + internalType: 'uint256', + }, + ], + outputs: [ + { + name: '', + type: 'uint256', + internalType: 'uint256', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'cardVersionOfJob', + inputs: [ + { + name: '', + type: 'uint256', + internalType: 'uint256', + }, + ], + outputs: [ + { + name: '', + type: 'uint256', + internalType: 'uint256', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'ceaDeployment', + inputs: [ + { + name: '', + type: 'bytes32', + internalType: 'bytes32', + }, + ], + outputs: [ + { + name: 'ceaFactory', + type: 'address', + internalType: 'address', + }, + { + name: 'ceaProxyImpl', + type: 'address', + internalType: 'address', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'computeCEA', + inputs: [ + { + name: 'agw', + type: 'address', + internalType: 'address', + }, + { + name: 'chainHash', + type: 'bytes32', + internalType: 'bytes32', + }, + ], + outputs: [ + { + name: '', + type: 'address', + internalType: 'address', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'disableAgentCard', + inputs: [ + { + name: 'cardId', + type: 'uint256', + internalType: 'uint256', + }, + ], + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + name: 'evaluator', + inputs: [], + outputs: [ + { + name: '', + type: 'address', + internalType: 'address', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'getAgentCard', + inputs: [ + { + name: 'cardId', + type: 'uint256', + internalType: 'uint256', + }, + ], + outputs: [ + { + name: 'v', + type: 'tuple', + internalType: 'struct AgentCardView', + components: [ + { + name: 'card', + type: 'tuple', + internalType: 'struct AgentCard', + components: [ + { + name: 'provider', + type: 'address', + internalType: 'address', + }, + { + name: 'jobType', + type: 'bytes32', + internalType: 'bytes32', + }, + { + name: 'metadataURI', + type: 'string', + internalType: 'string', + }, + { + name: 'metadataHash', + type: 'bytes32', + internalType: 'bytes32', + }, + { + name: 'chainNamespace', + type: 'string', + internalType: 'string', + }, + { + name: 'providerFee', + type: 'uint256', + internalType: 'uint256', + }, + { + name: 'paymentToken', + type: 'address', + internalType: 'address', + }, + { + name: 'principalMin', + type: 'uint256', + internalType: 'uint256', + }, + { + name: 'principalMax', + type: 'uint256', + internalType: 'uint256', + }, + { + name: 'minDuration', + type: 'uint32', + internalType: 'uint32', + }, + { + name: 'maxDuration', + type: 'uint32', + internalType: 'uint32', + }, + { + name: 'minExecuteWindow', + type: 'uint32', + internalType: 'uint32', + }, + { + name: 'settleWindow', + type: 'uint32', + internalType: 'uint32', + }, + { + name: 'active', + type: 'bool', + internalType: 'bool', + }, + ], + }, + { + name: 'rules', + type: 'bytes', + internalType: 'bytes', + }, + { + name: 'jobSpecTemplate', + type: 'bytes', + internalType: 'bytes', + }, + { + name: 'version', + type: 'uint256', + internalType: 'uint256', + }, + { + name: 'verified', + type: 'bool', + internalType: 'bool', + }, + { + name: 'disabled', + type: 'bool', + internalType: 'bool', + }, + ], + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'getAgentRating', + inputs: [ + { + name: 'agent', + type: 'address', + internalType: 'address', + }, + ], + outputs: [ + { + name: '', + type: 'uint256', + internalType: 'uint256', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'getRoleAdmin', + inputs: [ + { + name: 'role', + type: 'bytes32', + internalType: 'bytes32', + }, + ], + outputs: [ + { + name: '', + type: 'bytes32', + internalType: 'bytes32', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'grantRole', + inputs: [ + { + name: 'role', + type: 'bytes32', + internalType: 'bytes32', + }, + { + name: 'account', + type: 'address', + internalType: 'address', + }, + ], + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + name: 'hasRole', + inputs: [ + { + name: 'role', + type: 'bytes32', + internalType: 'bytes32', + }, + { + name: 'account', + type: 'address', + internalType: 'address', + }, + ], + outputs: [ + { + name: '', + type: 'bool', + internalType: 'bool', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'hook', + inputs: [], + outputs: [ + { + name: '', + type: 'address', + internalType: 'address', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'initialize', + inputs: [ + { + name: 'p', + type: 'tuple', + internalType: 'struct InitParams', + components: [ + { + name: 'agwFactory', + type: 'address', + internalType: 'address', + }, + { + name: 'kernel', + type: 'address', + internalType: 'address', + }, + { + name: 'hook', + type: 'address', + internalType: 'address', + }, + { + name: 'evaluator', + type: 'address', + internalType: 'address', + }, + { + name: 'rules', + type: 'address', + internalType: 'address', + }, + { + name: 'admin', + type: 'address', + internalType: 'address', + }, + ], + }, + ], + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + name: 'isAgentCardDisabled', + inputs: [ + { + name: '', + type: 'uint256', + internalType: 'uint256', + }, + ], + outputs: [ + { + name: '', + type: 'bool', + internalType: 'bool', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'isAgentCardVerified', + inputs: [ + { + name: '', + type: 'uint256', + internalType: 'uint256', + }, + ], + outputs: [ + { + name: '', + type: 'bool', + internalType: 'bool', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'openJob', + inputs: [ + { + name: 'p', + type: 'tuple', + internalType: 'struct OpenJobParams', + components: [ + { + name: 'cardId', + type: 'uint256', + internalType: 'uint256', + }, + { + name: 'cardVersion', + type: 'uint256', + internalType: 'uint256', + }, + { + name: 'job', + type: 'tuple', + internalType: 'struct JobInputs', + components: [ + { + name: 'principal', + type: 'uint256', + internalType: 'uint256', + }, + { + name: 'expiredAt', + type: 'uint48', + internalType: 'uint48', + }, + { + name: 'executeBy', + type: 'uint48', + internalType: 'uint48', + }, + { + name: 'params', + type: 'int256[]', + internalType: 'int256[]', + }, + ], + }, + { + name: 'session', + type: 'tuple', + internalType: 'struct Session', + components: [ + { + name: 'sessionValidator', + type: 'address', + internalType: 'address', + }, + { + name: 'sessionValidatorInitData', + type: 'bytes', + internalType: 'bytes', + }, + { + name: 'salt', + type: 'bytes32', + internalType: 'bytes32', + }, + { + name: 'userOpPolicies', + type: 'tuple[]', + internalType: 'struct PolicyData[]', + components: [ + { + name: 'policy', + type: 'address', + internalType: 'address', + }, + { + name: 'initData', + type: 'bytes', + internalType: 'bytes', + }, + ], + }, + { + name: 'erc7739Policies', + type: 'tuple', + internalType: 'struct ERC7739Data', + components: [ + { + name: 'allowedERC7739Content', + type: 'tuple[]', + internalType: 'struct ERC7739Context[]', + components: [ + { + name: 'appDomainSeparator', + type: 'bytes32', + internalType: 'bytes32', + }, + { + name: 'contentNames', + type: 'string[]', + internalType: 'string[]', + }, + ], + }, + { + name: 'erc1271Policies', + type: 'tuple[]', + internalType: 'struct PolicyData[]', + components: [ + { + name: 'policy', + type: 'address', + internalType: 'address', + }, + { + name: 'initData', + type: 'bytes', + internalType: 'bytes', + }, + ], + }, + ], + }, + { + name: 'actions', + type: 'tuple[]', + internalType: 'struct ActionData[]', + components: [ + { + name: 'actionTargetSelector', + type: 'bytes4', + internalType: 'bytes4', + }, + { + name: 'actionTarget', + type: 'address', + internalType: 'address', + }, + { + name: 'actionPolicies', + type: 'tuple[]', + internalType: 'struct PolicyData[]', + components: [ + { + name: 'policy', + type: 'address', + internalType: 'address', + }, + { + name: 'initData', + type: 'bytes', + internalType: 'bytes', + }, + ], + }, + ], + }, + { + name: 'permitERC4337Paymaster', + type: 'bool', + internalType: 'bool', + }, + ], + }, + { + name: 'intent', + type: 'tuple', + internalType: 'struct OwnerIntent', + components: [ + { + name: 'owner', + type: 'address', + internalType: 'address', + }, + { + name: 'wallet', + type: 'address', + internalType: 'address', + }, + { + name: 'executor', + type: 'address', + internalType: 'address', + }, + { + name: 'index', + type: 'uint96', + internalType: 'uint96', + }, + { + name: 'sessionHash', + type: 'bytes32', + internalType: 'bytes32', + }, + { + name: 'mode', + type: 'bytes32', + internalType: 'bytes32', + }, + { + name: 'execCalldataHash', + type: 'bytes32', + internalType: 'bytes32', + }, + { + name: 'nonceKey', + type: 'uint192', + internalType: 'uint192', + }, + { + name: 'nonceSeq', + type: 'uint64', + internalType: 'uint64', + }, + { + name: 'grantNonce', + type: 'uint64', + internalType: 'uint64', + }, + { + name: 'deadline', + type: 'uint48', + internalType: 'uint48', + }, + { + name: 'signerChainId', + type: 'uint256', + internalType: 'uint256', + }, + ], + }, + { + name: 'sig', + type: 'bytes', + internalType: 'bytes', + }, + { + name: 'label', + type: 'string', + internalType: 'string', + }, + ], + }, + ], + outputs: [ + { + name: 'jobId', + type: 'uint256', + internalType: 'uint256', + }, + { + name: 'agw', + type: 'address', + internalType: 'address', + }, + { + name: 'rulesId', + type: 'bytes32', + internalType: 'bytes32', + }, + ], + stateMutability: 'nonpayable', + }, + { + type: 'function', + name: 'pause', + inputs: [], + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + name: 'paused', + inputs: [], + outputs: [ + { + name: '', + type: 'bool', + internalType: 'bool', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'previewIntent', + inputs: [ + { + name: 'r', + type: 'tuple', + internalType: 'struct IntentRequest', + components: [ + { + name: 'cardId', + type: 'uint256', + internalType: 'uint256', + }, + { + name: 'owner', + type: 'address', + internalType: 'address', + }, + { + name: 'index', + type: 'uint96', + internalType: 'uint96', + }, + { + name: 'job', + type: 'tuple', + internalType: 'struct JobInputs', + components: [ + { + name: 'principal', + type: 'uint256', + internalType: 'uint256', + }, + { + name: 'expiredAt', + type: 'uint48', + internalType: 'uint48', + }, + { + name: 'executeBy', + type: 'uint48', + internalType: 'uint48', + }, + { + name: 'params', + type: 'int256[]', + internalType: 'int256[]', + }, + ], + }, + { + name: 'deadline', + type: 'uint48', + internalType: 'uint48', + }, + { + name: 'signerChainId', + type: 'uint256', + internalType: 'uint256', + }, + ], + }, + { + name: 's', + type: 'tuple', + internalType: 'struct Session', + components: [ + { + name: 'sessionValidator', + type: 'address', + internalType: 'address', + }, + { + name: 'sessionValidatorInitData', + type: 'bytes', + internalType: 'bytes', + }, + { + name: 'salt', + type: 'bytes32', + internalType: 'bytes32', + }, + { + name: 'userOpPolicies', + type: 'tuple[]', + internalType: 'struct PolicyData[]', + components: [ + { + name: 'policy', + type: 'address', + internalType: 'address', + }, + { + name: 'initData', + type: 'bytes', + internalType: 'bytes', + }, + ], + }, + { + name: 'erc7739Policies', + type: 'tuple', + internalType: 'struct ERC7739Data', + components: [ + { + name: 'allowedERC7739Content', + type: 'tuple[]', + internalType: 'struct ERC7739Context[]', + components: [ + { + name: 'appDomainSeparator', + type: 'bytes32', + internalType: 'bytes32', + }, + { + name: 'contentNames', + type: 'string[]', + internalType: 'string[]', + }, + ], + }, + { + name: 'erc1271Policies', + type: 'tuple[]', + internalType: 'struct PolicyData[]', + components: [ + { + name: 'policy', + type: 'address', + internalType: 'address', + }, + { + name: 'initData', + type: 'bytes', + internalType: 'bytes', + }, + ], + }, + ], + }, + { + name: 'actions', + type: 'tuple[]', + internalType: 'struct ActionData[]', + components: [ + { + name: 'actionTargetSelector', + type: 'bytes4', + internalType: 'bytes4', + }, + { + name: 'actionTarget', + type: 'address', + internalType: 'address', + }, + { + name: 'actionPolicies', + type: 'tuple[]', + internalType: 'struct PolicyData[]', + components: [ + { + name: 'policy', + type: 'address', + internalType: 'address', + }, + { + name: 'initData', + type: 'bytes', + internalType: 'bytes', + }, + ], + }, + ], + }, + { + name: 'permitERC4337Paymaster', + type: 'bool', + internalType: 'bool', + }, + ], + }, + ], + outputs: [ + { + name: 'i', + type: 'tuple', + internalType: 'struct OwnerIntent', + components: [ + { + name: 'owner', + type: 'address', + internalType: 'address', + }, + { + name: 'wallet', + type: 'address', + internalType: 'address', + }, + { + name: 'executor', + type: 'address', + internalType: 'address', + }, + { + name: 'index', + type: 'uint96', + internalType: 'uint96', + }, + { + name: 'sessionHash', + type: 'bytes32', + internalType: 'bytes32', + }, + { + name: 'mode', + type: 'bytes32', + internalType: 'bytes32', + }, + { + name: 'execCalldataHash', + type: 'bytes32', + internalType: 'bytes32', + }, + { + name: 'nonceKey', + type: 'uint192', + internalType: 'uint192', + }, + { + name: 'nonceSeq', + type: 'uint64', + internalType: 'uint64', + }, + { + name: 'grantNonce', + type: 'uint64', + internalType: 'uint64', + }, + { + name: 'deadline', + type: 'uint48', + internalType: 'uint48', + }, + { + name: 'signerChainId', + type: 'uint256', + internalType: 'uint256', + }, + ], + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'registerAgentCard', + inputs: [ + { + name: 'c', + type: 'tuple', + internalType: 'struct AgentCard', + components: [ + { + name: 'provider', + type: 'address', + internalType: 'address', + }, + { + name: 'jobType', + type: 'bytes32', + internalType: 'bytes32', + }, + { + name: 'metadataURI', + type: 'string', + internalType: 'string', + }, + { + name: 'metadataHash', + type: 'bytes32', + internalType: 'bytes32', + }, + { + name: 'chainNamespace', + type: 'string', + internalType: 'string', + }, + { + name: 'providerFee', + type: 'uint256', + internalType: 'uint256', + }, + { + name: 'paymentToken', + type: 'address', + internalType: 'address', + }, + { + name: 'principalMin', + type: 'uint256', + internalType: 'uint256', + }, + { + name: 'principalMax', + type: 'uint256', + internalType: 'uint256', + }, + { + name: 'minDuration', + type: 'uint32', + internalType: 'uint32', + }, + { + name: 'maxDuration', + type: 'uint32', + internalType: 'uint32', + }, + { + name: 'minExecuteWindow', + type: 'uint32', + internalType: 'uint32', + }, + { + name: 'settleWindow', + type: 'uint32', + internalType: 'uint32', + }, + { + name: 'active', + type: 'bool', + internalType: 'bool', + }, + ], + }, + { + name: 'rules', + type: 'bytes', + internalType: 'bytes', + }, + { + name: 'jobSpecTemplate', + type: 'bytes', + internalType: 'bytes', + }, + ], + outputs: [ + { + name: 'cardId', + type: 'uint256', + internalType: 'uint256', + }, + ], + stateMutability: 'nonpayable', + }, + { + type: 'function', + name: 'renounceRole', + inputs: [ + { + name: 'role', + type: 'bytes32', + internalType: 'bytes32', + }, + { + name: 'callerConfirmation', + type: 'address', + internalType: 'address', + }, + ], + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + name: 'revokeAgentCardVerification', + inputs: [ + { + name: 'cardId', + type: 'uint256', + internalType: 'uint256', + }, + ], + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + name: 'revokeRole', + inputs: [ + { + name: 'role', + type: 'bytes32', + internalType: 'bytes32', + }, + { + name: 'account', + type: 'address', + internalType: 'address', + }, + ], + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + name: 'rulesOfJob', + inputs: [ + { + name: '', + type: 'uint256', + internalType: 'uint256', + }, + ], + outputs: [ + { + name: '', + type: 'bytes32', + internalType: 'bytes32', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'setAgentCardActive', + inputs: [ + { + name: 'cardId', + type: 'uint256', + internalType: 'uint256', + }, + { + name: 'active', + type: 'bool', + internalType: 'bool', + }, + ], + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + name: 'setAgentRating', + inputs: [ + { + name: 'agent', + type: 'address', + internalType: 'address', + }, + { + name: 'rating', + type: 'uint256', + internalType: 'uint256', + }, + ], + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + name: 'setCEADeployment', + inputs: [ + { + name: 'chainHash', + type: 'bytes32', + internalType: 'bytes32', + }, + { + name: 'ceaFactory', + type: 'address', + internalType: 'address', + }, + { + name: 'ceaProxyImpl', + type: 'address', + internalType: 'address', + }, + ], + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + name: 'setEvaluator', + inputs: [ + { + name: 'evaluator_', + type: 'address', + internalType: 'address', + }, + ], + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + name: 'setHook', + inputs: [ + { + name: 'hook_', + type: 'address', + internalType: 'address', + }, + ], + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + name: 'supportsInterface', + inputs: [ + { + name: 'interfaceId', + type: 'bytes4', + internalType: 'bytes4', + }, + ], + outputs: [ + { + name: '', + type: 'bool', + internalType: 'bool', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'unpause', + inputs: [], + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + name: 'updateAgentCard', + inputs: [ + { + name: 'cardId', + type: 'uint256', + internalType: 'uint256', + }, + { + name: 'c', + type: 'tuple', + internalType: 'struct AgentCard', + components: [ + { + name: 'provider', + type: 'address', + internalType: 'address', + }, + { + name: 'jobType', + type: 'bytes32', + internalType: 'bytes32', + }, + { + name: 'metadataURI', + type: 'string', + internalType: 'string', + }, + { + name: 'metadataHash', + type: 'bytes32', + internalType: 'bytes32', + }, + { + name: 'chainNamespace', + type: 'string', + internalType: 'string', + }, + { + name: 'providerFee', + type: 'uint256', + internalType: 'uint256', + }, + { + name: 'paymentToken', + type: 'address', + internalType: 'address', + }, + { + name: 'principalMin', + type: 'uint256', + internalType: 'uint256', + }, + { + name: 'principalMax', + type: 'uint256', + internalType: 'uint256', + }, + { + name: 'minDuration', + type: 'uint32', + internalType: 'uint32', + }, + { + name: 'maxDuration', + type: 'uint32', + internalType: 'uint32', + }, + { + name: 'minExecuteWindow', + type: 'uint32', + internalType: 'uint32', + }, + { + name: 'settleWindow', + type: 'uint32', + internalType: 'uint32', + }, + { + name: 'active', + type: 'bool', + internalType: 'bool', + }, + ], + }, + { + name: 'rules', + type: 'bytes', + internalType: 'bytes', + }, + { + name: 'jobSpecTemplate', + type: 'bytes', + internalType: 'bytes', + }, + ], + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + name: 'verifyAgentCard', + inputs: [ + { + name: 'cardId', + type: 'uint256', + internalType: 'uint256', + }, + { + name: 'cardVersion', + type: 'uint256', + internalType: 'uint256', + }, + ], + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + name: 'version', + inputs: [], + outputs: [ + { + name: '', + type: 'string', + internalType: 'string', + }, + ], + stateMutability: 'pure', + }, + { + type: 'event', + name: 'AgentCardDisabled', + inputs: [ + { + name: 'cardId', + type: 'uint256', + indexed: true, + internalType: 'uint256', + }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'AgentCardRegistered', + inputs: [ + { + name: 'cardId', + type: 'uint256', + indexed: true, + internalType: 'uint256', + }, + { + name: 'provider', + type: 'address', + indexed: true, + internalType: 'address', + }, + { + name: 'jobType', + type: 'bytes32', + indexed: true, + internalType: 'bytes32', + }, + { + name: 'chainNamespace', + type: 'string', + indexed: false, + internalType: 'string', + }, + { + name: 'rulesHash', + type: 'bytes32', + indexed: false, + internalType: 'bytes32', + }, + { + name: 'jobSpecHash', + type: 'bytes32', + indexed: false, + internalType: 'bytes32', + }, + { + name: 'metadataHash', + type: 'bytes32', + indexed: false, + internalType: 'bytes32', + }, + { + name: 'providerFee', + type: 'uint256', + indexed: false, + internalType: 'uint256', + }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'AgentCardStatusChanged', + inputs: [ + { + name: 'cardId', + type: 'uint256', + indexed: true, + internalType: 'uint256', + }, + { + name: 'active', + type: 'bool', + indexed: false, + internalType: 'bool', + }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'AgentCardUpdated', + inputs: [ + { + name: 'cardId', + type: 'uint256', + indexed: true, + internalType: 'uint256', + }, + { + name: 'version', + type: 'uint256', + indexed: false, + internalType: 'uint256', + }, + { + name: 'rulesHash', + type: 'bytes32', + indexed: false, + internalType: 'bytes32', + }, + { + name: 'jobSpecHash', + type: 'bytes32', + indexed: false, + internalType: 'bytes32', + }, + { + name: 'metadataHash', + type: 'bytes32', + indexed: false, + internalType: 'bytes32', + }, + { + name: 'providerFee', + type: 'uint256', + indexed: false, + internalType: 'uint256', + }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'AgentCardVerificationRevoked', + inputs: [ + { + name: 'cardId', + type: 'uint256', + indexed: true, + internalType: 'uint256', + }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'AgentCardVerified', + inputs: [ + { + name: 'cardId', + type: 'uint256', + indexed: true, + internalType: 'uint256', + }, + { + name: 'version', + type: 'uint256', + indexed: false, + internalType: 'uint256', + }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'AgentRatingSet', + inputs: [ + { + name: 'agent', + type: 'address', + indexed: true, + internalType: 'address', + }, + { + name: 'rating', + type: 'uint256', + indexed: false, + internalType: 'uint256', + }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'CEADeploymentSet', + inputs: [ + { + name: 'chainHash', + type: 'bytes32', + indexed: true, + internalType: 'bytes32', + }, + { + name: 'ceaFactory', + type: 'address', + indexed: false, + internalType: 'address', + }, + { + name: 'ceaProxyImpl', + type: 'address', + indexed: false, + internalType: 'address', + }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'EvaluatorUpdated', + inputs: [ + { + name: 'evaluator', + type: 'address', + indexed: false, + internalType: 'address', + }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'HookUpdated', + inputs: [ + { + name: 'hook', + type: 'address', + indexed: false, + internalType: 'address', + }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'Initialized', + inputs: [ + { + name: 'version', + type: 'uint64', + indexed: false, + internalType: 'uint64', + }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'JobOpened', + inputs: [ + { + name: 'cardId', + type: 'uint256', + indexed: true, + internalType: 'uint256', + }, + { + name: 'owner', + type: 'address', + indexed: true, + internalType: 'address', + }, + { + name: 'agw', + type: 'address', + indexed: true, + internalType: 'address', + }, + { + name: 'jobId', + type: 'uint256', + indexed: false, + internalType: 'uint256', + }, + { + name: 'rulesId', + type: 'bytes32', + indexed: false, + internalType: 'bytes32', + }, + { + name: 'principal', + type: 'uint256', + indexed: false, + internalType: 'uint256', + }, + { + name: 'cardVersion', + type: 'uint256', + indexed: false, + internalType: 'uint256', + }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'Paused', + inputs: [ + { + name: 'account', + type: 'address', + indexed: false, + internalType: 'address', + }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'RoleAdminChanged', + inputs: [ + { + name: 'role', + type: 'bytes32', + indexed: true, + internalType: 'bytes32', + }, + { + name: 'previousAdminRole', + type: 'bytes32', + indexed: true, + internalType: 'bytes32', + }, + { + name: 'newAdminRole', + type: 'bytes32', + indexed: true, + internalType: 'bytes32', + }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'RoleGranted', + inputs: [ + { + name: 'role', + type: 'bytes32', + indexed: true, + internalType: 'bytes32', + }, + { + name: 'account', + type: 'address', + indexed: true, + internalType: 'address', + }, + { + name: 'sender', + type: 'address', + indexed: true, + internalType: 'address', + }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'RoleRevoked', + inputs: [ + { + name: 'role', + type: 'bytes32', + indexed: true, + internalType: 'bytes32', + }, + { + name: 'account', + type: 'address', + indexed: true, + internalType: 'address', + }, + { + name: 'sender', + type: 'address', + indexed: true, + internalType: 'address', + }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'Unpaused', + inputs: [ + { + name: 'account', + type: 'address', + indexed: false, + internalType: 'address', + }, + ], + anonymous: false, + }, + { + type: 'error', + name: 'AGWMismatch', + inputs: [ + { + name: 'expected', + type: 'address', + internalType: 'address', + }, + { + name: 'actual', + type: 'address', + internalType: 'address', + }, + ], + }, + { + type: 'error', + name: 'AccessControlBadConfirmation', + inputs: [], + }, + { + type: 'error', + name: 'AccessControlUnauthorizedAccount', + inputs: [ + { + name: 'account', + type: 'address', + internalType: 'address', + }, + { + name: 'neededRole', + type: 'bytes32', + internalType: 'bytes32', + }, + ], + }, + { + type: 'error', + name: 'AgentCardAlreadyRegistered', + inputs: [ + { + name: 'provider', + type: 'address', + internalType: 'address', + }, + ], + }, + { + type: 'error', + name: 'AgentCardDisabled', + inputs: [ + { + name: 'cardId', + type: 'uint256', + internalType: 'uint256', + }, + ], + }, + { + type: 'error', + name: 'AgentCardIdentityImmutable', + inputs: [], + }, + { + type: 'error', + name: 'AgentCardInactive', + inputs: [], + }, + { + type: 'error', + name: 'AgentCardVersionMismatch', + inputs: [ + { + name: 'provided', + type: 'uint256', + internalType: 'uint256', + }, + { + name: 'current', + type: 'uint256', + internalType: 'uint256', + }, + ], + }, + { + type: 'error', + name: 'CallerIsNotProvider', + inputs: [], + }, + { + type: 'error', + name: 'ChainNotSupported', + inputs: [ + { + name: 'chainHash', + type: 'bytes32', + internalType: 'bytes32', + }, + ], + }, + { + type: 'error', + name: 'EnforcedPause', + inputs: [], + }, + { + type: 'error', + name: 'ExecuteByOutOfRange', + inputs: [], + }, + { + type: 'error', + name: 'ExecutorMismatch', + inputs: [ + { + name: 'expected', + type: 'address', + internalType: 'address', + }, + { + name: 'actual', + type: 'address', + internalType: 'address', + }, + ], + }, + { + type: 'error', + name: 'ExpectedPause', + inputs: [], + }, + { + type: 'error', + name: 'ExpiryOutOfRange', + inputs: [], + }, + { + type: 'error', + name: 'HookNotWhitelisted', + inputs: [], + }, + { + type: 'error', + name: 'IntentExecMismatch', + inputs: [ + { + name: 'actualCalldataHash', + type: 'bytes32', + internalType: 'bytes32', + }, + ], + }, + { + type: 'error', + name: 'IntentSessionMismatch', + inputs: [ + { + name: 'actual', + type: 'bytes32', + internalType: 'bytes32', + }, + ], + }, + { + type: 'error', + name: 'IntentWalletMismatch', + inputs: [ + { + name: 'expected', + type: 'address', + internalType: 'address', + }, + { + name: 'provided', + type: 'address', + internalType: 'address', + }, + ], + }, + { + type: 'error', + name: 'InvalidAgentCard', + inputs: [ + { + name: 'reason', + type: 'string', + internalType: 'string', + }, + ], + }, + { + type: 'error', + name: 'InvalidInitialization', + inputs: [], + }, + { + type: 'error', + name: 'JobMismatch', + inputs: [], + }, + { + type: 'error', + name: 'NotInitializing', + inputs: [], + }, + { + type: 'error', + name: 'PrincipalOutOfRange', + inputs: [], + }, + { + type: 'error', + name: 'ProviderIsEvaluator', + inputs: [], + }, + { + type: 'error', + name: 'ReentrancyGuardReentrantCall', + inputs: [], + }, + { + type: 'error', + name: 'UnexpectedJobCount', + inputs: [ + { + name: 'before', + type: 'uint256', + internalType: 'uint256', + }, + { + name: 'afterCount', + type: 'uint256', + internalType: 'uint256', + }, + ], + }, + { + type: 'error', + name: 'WalletHasActiveJob', + inputs: [ + { + name: 'agw', + type: 'address', + internalType: 'address', + }, + { + name: 'jobId', + type: 'uint256', + internalType: 'uint256', + }, + ], + }, + { + type: 'error', + name: 'WalletOwnerMismatch', + inputs: [ + { + name: 'expected', + type: 'address', + internalType: 'address', + }, + { + name: 'actual', + type: 'address', + internalType: 'address', + }, + ], + }, + { + type: 'error', + name: 'ZeroAddress', + inputs: [], + }, +] as const; diff --git a/packages/core/src/lib/market/contracts/UniversalMarketplaceErrors.ts b/packages/core/src/lib/market/contracts/UniversalMarketplaceErrors.ts new file mode 100644 index 00000000..0d302d29 --- /dev/null +++ b/packages/core/src/lib/market/contracts/UniversalMarketplaceErrors.ts @@ -0,0 +1,412 @@ +// Generated from sdk-iteration-v1@443b4e2; Donut marketplace v2. +export const MARKET_ERRORS_ABI = [ + { + type: 'error', + name: 'AGWMismatch', + inputs: [ + { + name: 'expected', + type: 'address', + internalType: 'address', + }, + { + name: 'actual', + type: 'address', + internalType: 'address', + }, + ], + }, + { + type: 'error', + name: 'ActionCount', + inputs: [], + }, + { + type: 'error', + name: 'ActionsMismatch', + inputs: [], + }, + { + type: 'error', + name: 'AgentCardAlreadyRegistered', + inputs: [ + { + name: 'provider', + type: 'address', + internalType: 'address', + }, + ], + }, + { + type: 'error', + name: 'AgentCardDisabled', + inputs: [ + { + name: 'cardId', + type: 'uint256', + internalType: 'uint256', + }, + ], + }, + { + type: 'error', + name: 'AgentCardIdentityImmutable', + inputs: [], + }, + { + type: 'error', + name: 'AgentCardInactive', + inputs: [], + }, + { + type: 'error', + name: 'AgentCardVersionMismatch', + inputs: [ + { + name: 'provided', + type: 'uint256', + internalType: 'uint256', + }, + { + name: 'current', + type: 'uint256', + internalType: 'uint256', + }, + ], + }, + { + type: 'error', + name: 'AgentMismatch', + inputs: [], + }, + { + type: 'error', + name: 'AssetCountMismatch', + inputs: [ + { + name: 'expected', + type: 'uint256', + internalType: 'uint256', + }, + { + name: 'actual', + type: 'uint256', + internalType: 'uint256', + }, + ], + }, + { + type: 'error', + name: 'AssetMismatch', + inputs: [ + { + name: 'index', + type: 'uint256', + internalType: 'uint256', + }, + ], + }, + { + type: 'error', + name: 'CallerIsNotProvider', + inputs: [], + }, + { + type: 'error', + name: 'ChainMismatch', + inputs: [ + { + name: 'i', + type: 'uint256', + internalType: 'uint256', + }, + ], + }, + { + type: 'error', + name: 'ChainNotSupported', + inputs: [ + { + name: 'chainHash', + type: 'bytes32', + internalType: 'bytes32', + }, + ], + }, + { + type: 'error', + name: 'EnvelopeVersionMismatch', + inputs: [ + { + name: 'actual', + type: 'uint256', + internalType: 'uint256', + }, + ], + }, + { + type: 'error', + name: 'ExecuteByOutOfRange', + inputs: [], + }, + { + type: 'error', + name: 'ExecutorMismatch', + inputs: [ + { + name: 'expected', + type: 'address', + internalType: 'address', + }, + { + name: 'actual', + type: 'address', + internalType: 'address', + }, + ], + }, + { + type: 'error', + name: 'ExpectedCEAMismatch', + inputs: [ + { + name: 'expected', + type: 'address', + internalType: 'address', + }, + { + name: 'actual', + type: 'address', + internalType: 'address', + }, + ], + }, + { + type: 'error', + name: 'ExpiryMismatch', + inputs: [], + }, + { + type: 'error', + name: 'ExpiryOutOfRange', + inputs: [], + }, + { + type: 'error', + name: 'FillOutOfBounds', + inputs: [ + { + name: 'read', + type: 'uint256', + internalType: 'uint256', + }, + { + name: 'fill', + type: 'uint256', + internalType: 'uint256', + }, + ], + }, + { + type: 'error', + name: 'GasCapMismatch', + inputs: [], + }, + { + type: 'error', + name: 'HookNotWhitelisted', + inputs: [], + }, + { + type: 'error', + name: 'IntentExecMismatch', + inputs: [ + { + name: 'actualCalldataHash', + type: 'bytes32', + internalType: 'bytes32', + }, + ], + }, + { + type: 'error', + name: 'IntentSessionMismatch', + inputs: [ + { + name: 'actual', + type: 'bytes32', + internalType: 'bytes32', + }, + ], + }, + { + type: 'error', + name: 'IntentWalletMismatch', + inputs: [ + { + name: 'expected', + type: 'address', + internalType: 'address', + }, + { + name: 'provided', + type: 'address', + internalType: 'address', + }, + ], + }, + { + type: 'error', + name: 'InvalidAgentCard', + inputs: [ + { + name: 'reason', + type: 'string', + internalType: 'string', + }, + ], + }, + { + type: 'error', + name: 'JobMismatch', + inputs: [], + }, + { + type: 'error', + name: 'ParamCountMismatch', + inputs: [ + { + name: 'expected', + type: 'uint256', + internalType: 'uint256', + }, + { + name: 'actual', + type: 'uint256', + internalType: 'uint256', + }, + ], + }, + { + type: 'error', + name: 'ParamOutOfRange', + inputs: [ + { + name: 'index', + type: 'uint256', + internalType: 'uint256', + }, + { + name: 'value', + type: 'int256', + internalType: 'int256', + }, + ], + }, + { + type: 'error', + name: 'PinMismatch', + inputs: [ + { + name: 'call', + type: 'uint256', + internalType: 'uint256', + }, + { + name: 'pin', + type: 'uint256', + internalType: 'uint256', + }, + ], + }, + { + type: 'error', + name: 'PolicyShape', + inputs: [ + { + name: 'i', + type: 'uint256', + internalType: 'uint256', + }, + ], + }, + { + type: 'error', + name: 'PrincipalCapMismatch', + inputs: [], + }, + { + type: 'error', + name: 'PrincipalOutOfRange', + inputs: [], + }, + { + type: 'error', + name: 'ProviderIsEvaluator', + inputs: [], + }, + { + type: 'error', + name: 'TargetOverflow', + inputs: [ + { + name: 'check', + type: 'uint256', + internalType: 'uint256', + }, + ], + }, + { + type: 'error', + name: 'UnexpectedJobCount', + inputs: [ + { + name: 'before', + type: 'uint256', + internalType: 'uint256', + }, + { + name: 'afterCount', + type: 'uint256', + internalType: 'uint256', + }, + ], + }, + { + type: 'error', + name: 'WalletHasActiveJob', + inputs: [ + { + name: 'agw', + type: 'address', + internalType: 'address', + }, + { + name: 'jobId', + type: 'uint256', + internalType: 'uint256', + }, + ], + }, + { + type: 'error', + name: 'WalletOwnerMismatch', + inputs: [ + { + name: 'expected', + type: 'address', + internalType: 'address', + }, + { + name: 'actual', + type: 'address', + internalType: 'address', + }, + ], + }, + { + type: 'error', + name: 'ZeroAddress', + inputs: [], + }, +] as const; diff --git a/packages/core/src/lib/market/contracts/UniversalMarketplaceRules.ts b/packages/core/src/lib/market/contracts/UniversalMarketplaceRules.ts new file mode 100644 index 00000000..e8a669bd --- /dev/null +++ b/packages/core/src/lib/market/contracts/UniversalMarketplaceRules.ts @@ -0,0 +1,319 @@ +// Generated from sdk-iteration-v1@443b4e2; Donut marketplace v2. +export const MARKET_RULES_ABI = [ + { + type: 'function', + name: 'checkRulesMatchCard', + inputs: [ + { + name: 'cardRules', + type: 'bytes', + internalType: 'bytes', + }, + { + name: 'session', + type: 'tuple', + internalType: 'struct Session', + components: [ + { + name: 'sessionValidator', + type: 'address', + internalType: 'address', + }, + { + name: 'sessionValidatorInitData', + type: 'bytes', + internalType: 'bytes', + }, + { + name: 'salt', + type: 'bytes32', + internalType: 'bytes32', + }, + { + name: 'userOpPolicies', + type: 'tuple[]', + internalType: 'struct PolicyData[]', + components: [ + { + name: 'policy', + type: 'address', + internalType: 'address', + }, + { + name: 'initData', + type: 'bytes', + internalType: 'bytes', + }, + ], + }, + { + name: 'erc7739Policies', + type: 'tuple', + internalType: 'struct ERC7739Data', + components: [ + { + name: 'allowedERC7739Content', + type: 'tuple[]', + internalType: 'struct ERC7739Context[]', + components: [ + { + name: 'appDomainSeparator', + type: 'bytes32', + internalType: 'bytes32', + }, + { + name: 'contentNames', + type: 'string[]', + internalType: 'string[]', + }, + ], + }, + { + name: 'erc1271Policies', + type: 'tuple[]', + internalType: 'struct PolicyData[]', + components: [ + { + name: 'policy', + type: 'address', + internalType: 'address', + }, + { + name: 'initData', + type: 'bytes', + internalType: 'bytes', + }, + ], + }, + ], + }, + { + name: 'actions', + type: 'tuple[]', + internalType: 'struct ActionData[]', + components: [ + { + name: 'actionTargetSelector', + type: 'bytes4', + internalType: 'bytes4', + }, + { + name: 'actionTarget', + type: 'address', + internalType: 'address', + }, + { + name: 'actionPolicies', + type: 'tuple[]', + internalType: 'struct PolicyData[]', + components: [ + { + name: 'policy', + type: 'address', + internalType: 'address', + }, + { + name: 'initData', + type: 'bytes', + internalType: 'bytes', + }, + ], + }, + ], + }, + { + name: 'permitERC4337Paymaster', + type: 'bool', + internalType: 'bool', + }, + ], + }, + { + name: 'ctx', + type: 'tuple', + internalType: 'struct SessionContext', + components: [ + { + name: 'agent', + type: 'address', + internalType: 'address', + }, + { + name: 'chainHash', + type: 'bytes32', + internalType: 'bytes32', + }, + { + name: 'principal', + type: 'uint256', + internalType: 'uint256', + }, + { + name: 'expiredAt', + type: 'uint48', + internalType: 'uint48', + }, + { + name: 'expectedCEA', + type: 'address', + internalType: 'address', + }, + ], + }, + ], + outputs: [], + stateMutability: 'pure', + }, + { + type: 'function', + name: 'validateAgentCardRules', + inputs: [ + { + name: 'rules', + type: 'bytes', + internalType: 'bytes', + }, + ], + outputs: [ + { + name: 'tokens', + type: 'address[]', + internalType: 'address[]', + }, + ], + stateMutability: 'pure', + }, + { + type: 'error', + name: 'ActionCount', + inputs: [], + }, + { + type: 'error', + name: 'ActionsMismatch', + inputs: [], + }, + { + type: 'error', + name: 'AgentMismatch', + inputs: [], + }, + { + type: 'error', + name: 'AssetCountMismatch', + inputs: [ + { + name: 'expected', + type: 'uint256', + internalType: 'uint256', + }, + { + name: 'actual', + type: 'uint256', + internalType: 'uint256', + }, + ], + }, + { + type: 'error', + name: 'AssetMismatch', + inputs: [ + { + name: 'index', + type: 'uint256', + internalType: 'uint256', + }, + ], + }, + { + type: 'error', + name: 'ChainMismatch', + inputs: [ + { + name: 'i', + type: 'uint256', + internalType: 'uint256', + }, + ], + }, + { + type: 'error', + name: 'EnvelopeVersionMismatch', + inputs: [ + { + name: 'actual', + type: 'uint256', + internalType: 'uint256', + }, + ], + }, + { + type: 'error', + name: 'ExpectedCEAMismatch', + inputs: [ + { + name: 'expected', + type: 'address', + internalType: 'address', + }, + { + name: 'actual', + type: 'address', + internalType: 'address', + }, + ], + }, + { + type: 'error', + name: 'ExpiryMismatch', + inputs: [], + }, + { + type: 'error', + name: 'GasCapMismatch', + inputs: [], + }, + { + type: 'error', + name: 'InvalidAgentCard', + inputs: [ + { + name: 'reason', + type: 'string', + internalType: 'string', + }, + ], + }, + { + type: 'error', + name: 'PinMismatch', + inputs: [ + { + name: 'call', + type: 'uint256', + internalType: 'uint256', + }, + { + name: 'pin', + type: 'uint256', + internalType: 'uint256', + }, + ], + }, + { + type: 'error', + name: 'PolicyShape', + inputs: [ + { + name: 'i', + type: 'uint256', + internalType: 'uint256', + }, + ], + }, + { + type: 'error', + name: 'PrincipalCapMismatch', + inputs: [], + }, +] as const; diff --git a/packages/core/src/lib/market/deployment.ts b/packages/core/src/lib/market/deployment.ts new file mode 100644 index 00000000..3c96131f --- /dev/null +++ b/packages/core/src/lib/market/deployment.ts @@ -0,0 +1,26 @@ +import { PUSH_NETWORK } from '../constants/enums'; +import { unavailable } from './errors'; +export const DONUT_MARKETPLACE = Object.freeze({ + sourceCommit: '443b4e2dd9ca5dd9ffc8efebdfcecd619dd66c47', + version: '2.0.0', + startBlock: BigInt(24443653), + marketplace: '0x9071ebE01B75123A91e88eB6ec4BF163F3fE9BF4', + kernel: '0x977cf1AC973E9eC4332791d531507575006157Ed', + hook: '0xDe7A94e510b6C571DE7880d441349689F73A32b3', + rules: '0x5b98A8E0df5b918DF76cD2BE84bA7995B39dfd44', + evaluator: '0x1afC81396f1bb36F91f74506284952b81e4bd47c', + paymentToken: '0x7A58048036206bB898008b5bBDA85697DB1e5d66', +} as const); +export type MarketDeployment = Omit< + typeof DONUT_MARKETPLACE, + 'marketplace' | 'kernel' | 'hook' | 'rules' | 'evaluator' | 'paymentToken' +> & + Record< + 'marketplace' | 'kernel' | 'hook' | 'rules' | 'evaluator' | 'paymentToken', + `0x${string}` + >; +export function marketplaceDeployment(network: PUSH_NETWORK): MarketDeployment { + if (network !== PUSH_NETWORK.TESTNET_DONUT) + unavailable('Marketplace on this Push network'); + return DONUT_MARKETPLACE; +} diff --git a/packages/core/src/lib/market/errors.ts b/packages/core/src/lib/market/errors.ts new file mode 100644 index 00000000..3afe513e --- /dev/null +++ b/packages/core/src/lib/market/errors.ts @@ -0,0 +1,89 @@ +import { decodeErrorResult, type Hex } from 'viem'; +import { AgenticError } from '../agentic/errors'; +import { MARKET_ERRORS_ABI } from './contracts/UniversalMarketplaceErrors'; +import { JOB_KERNEL_ABI } from './contracts/AgenticCommerce'; +import { RULES_HOOK_ABI } from './contracts/RulesBindingHook'; + +export class MarketError extends AgenticError { + constructor( + code: string, + message: string, + details?: Record, + cause?: unknown + ) { + super(code, message, { userMessage: message, details, cause }); + this.name = 'MarketError'; + } +} +export class JobError extends MarketError { + constructor( + code: string, + message: string, + details?: Record, + cause?: unknown + ) { + super(code, message, details, cause); + this.name = 'JobError'; + } +} +export class JobSpecError extends MarketError { + constructor( + code: string, + message: string, + details?: Record, + cause?: unknown + ) { + super(code, message, details, cause); + this.name = 'JobSpecError'; + } +} +export function unavailable(feature: string): never { + throw new MarketError( + 'CAPABILITY_UNAVAILABLE', + `${feature} is not available in the deployed marketplace v2 stack.`, + { feature } + ); +} +/** Inspect provider error chains without parsing human-readable revert messages. */ +export function stackError(error: unknown): unknown { + if (error instanceof AgenticError) return error; + const seen = new Set(); + function visit(value: unknown, depth: number): MarketError | undefined { + if (!value || typeof value !== 'object' || seen.has(value) || depth > 8) + return; + seen.add(value); + const o = value as Record; + if (o['code'] === 4001 || o['name'] === 'UserRejectedRequestError') + return new MarketError( + 'REQUEST_REJECTED', + 'The wallet request was cancelled.', + undefined, + error + ); + if (typeof o['data'] === 'string' && /^0x[0-9a-f]+$/i.test(o['data'])) { + try { + const decoded = decodeErrorResult({ + abi: [...MARKET_ERRORS_ABI, ...JOB_KERNEL_ABI, ...RULES_HOOK_ABI], + data: o['data'] as Hex, + }); + const code = decoded.errorName + .replace(/([a-z0-9])([A-Z])/g, '$1_$2') + .toUpperCase(); + return new MarketError( + code, + `The contract rejected the request: ${decoded.errorName}.`, + { decodedError: decoded }, + error + ); + } catch { + /* This value is not a known stack revert; retain the provider cause. */ + } + } + for (const key of ['cause', 'error', 'data']) { + const found = visit(o[key], depth + 1); + if (found) return found; + } + return; + } + return visit(error, 0) ?? error; +} diff --git a/packages/core/src/lib/market/index.ts b/packages/core/src/lib/market/index.ts new file mode 100644 index 00000000..aeba7a97 --- /dev/null +++ b/packages/core/src/lib/market/index.ts @@ -0,0 +1,8 @@ +export { MarketError, JobError, JobSpecError } from './errors'; +export type * from './types'; +export type { AgentCardRules, MarketAssetToken, MarketPin } from './rules'; +export { + validateAgentCardRules, + encodeAgentCardRules, + decodeAgentCardRules, +} from './rules'; diff --git a/packages/core/src/lib/market/kernel-wire.ts b/packages/core/src/lib/market/kernel-wire.ts new file mode 100644 index 00000000..65494e0c --- /dev/null +++ b/packages/core/src/lib/market/kernel-wire.ts @@ -0,0 +1,73 @@ +import { + decodeAbiParameters, + encodeAbiParameters, + getAbiItem, + stringToHex, + toFunctionSelector, + type Abi, + type AbiParameter, + type Address, + type Hex, +} from 'viem'; +import { JOB_KERNEL_ABI } from './contracts/AgenticCommerce'; +import { JobError } from './errors'; +const create = getAbiItem({ abi: JOB_KERNEL_ABI, name: 'createJob' }); +export const CREATE_JOB_SELECTOR = toFunctionSelector(create); +const inputs = create.inputs.map((p) => + p.name === 'description' ? { ...p, type: 'bytes' } : p +) as readonly AbiParameter[]; +/** Solidity string(description) carries arbitrary ABI bytes, not UTF-8 text. */ +export const KERNEL_READ_ABI: Abi = JOB_KERNEL_ABI.map((item) => + item.type === 'function' && item.name === 'getJob' + ? { + ...item, + outputs: item.outputs.map((p) => ({ + ...p, + components: p.components.map((c) => + c.name === 'description' ? { ...c, type: 'bytes' as const } : c + ), + })), + } + : item +); +export function encodeCreateJob( + provider: Address, + evaluator: Address, + expiredAt: number, + payload: { jobSpec?: Hex; description?: string }, + hook: Address +): Hex { + if (payload.jobSpec && payload.description !== undefined) + throw new JobError('INVALID_JOB', 'Use jobSpec or description, not both.'); + const bytes = payload.jobSpec ?? stringToHex(payload.description ?? ''); + return (CREATE_JOB_SELECTOR + + encodeAbiParameters(inputs, [ + provider, + evaluator, + BigInt(expiredAt), + bytes, + hook, + ]).slice(2)) as Hex; +} +export function decodeCreateJob(data: Hex): { + provider: Address; + evaluator: Address; + expiredAt: bigint; + description: Hex; + hook: Address; +} { + if (data.slice(0, 10).toLowerCase() !== CREATE_JOB_SELECTOR) + throw new JobError( + 'INVALID_JOB', + 'Expected the deployed kernel createJob selector.' + ); + const [provider, evaluator, expiredAt, description, hook] = + decodeAbiParameters(inputs, ('0x' + data.slice(10)) as Hex) as [ + Address, + Address, + bigint, + Hex, + Address + ]; + return { provider, evaluator, expiredAt, description, hook }; +} diff --git a/packages/core/src/lib/market/market.ts b/packages/core/src/lib/market/market.ts new file mode 100644 index 00000000..212438d8 --- /dev/null +++ b/packages/core/src/lib/market/market.ts @@ -0,0 +1,794 @@ +import { + encodeFunctionData, + getAddress, + keccak256, + stringToHex, + toHex, + zeroAddress, + type Address, + type Hex, +} from 'viem'; +import { MARKETPLACE_ABI as ABI } from './contracts/UniversalMarketplace'; +import { JOB_KERNEL_ABI } from './contracts/AgenticCommerce'; +import { MARKET_RULES_ABI } from './contracts/UniversalMarketplaceRules'; +import { currentGeneration } from '../agentic/deployments'; +import { + buildSession, + encodeEnvelope, + encodeSession, +} from '../agentic/codec/session'; +import { encodeUniversalTerms } from '../agentic/codec/universal-terms'; +import { assertLabel } from '../agentic/management/label'; +import { decodeJobSpec, encodeJobSpec } from '../job-spec/codec'; +import { + resolveJobSpec, + describeJobSpec, + specOrigin, +} from '../job-spec/helpers'; +import type { JobSpecTemplate } from '../job-spec/types'; +import { + decodeAgentCardRules, + decodeCardRulesWire, + encodeAgentCardRules, + fillCardRules, +} from './rules'; +import { decodeCreateJob } from './kernel-wire'; +import { + deployment, + eventArgs, + progress, + snapshot, + write, + type MarketSnapshot, + type StackRuntime, +} from './runtime'; +import { MarketError, unavailable } from './errors'; +import type { + AgentCard, + AgentCardInput, + AgentCardSummary, + JobPlan, + MarketJobInputs, + MarketNamespace, + MarketPreviewOptions, + MarketWriteOptions, + OwnerIntent, +} from './types'; +import type { CHAIN } from '../constants/enums'; + +interface WireCard extends Omit { + provider: Address; + chainNamespace: string; + active: boolean; +} +interface WireView { + card: WireCard; + rules: Hex; + jobSpecTemplate: Hex; + version: bigint; + verified: boolean; + disabled: boolean; +} +const fp = (x: unknown): string => + JSON.stringify(x, (_, v) => (typeof v === 'bigint' ? v.toString() : v)); +const ownerIntentFields = [ + ['owner', 'address'], + ['wallet', 'address'], + ['executor', 'address'], + ['index', 'uint96'], + ['sessionHash', 'bytes32'], + ['mode', 'bytes32'], + ['execCalldataHash', 'bytes32'], + ['nonceKey', 'uint192'], + ['nonceSeq', 'uint64'], + ['grantNonce', 'uint64'], + ['deadline', 'uint48'], + ['signerChainId', 'uint256'], +].map(([name, type]) => ({ name, type })); +function id(n: bigint): void { + if (typeof n !== 'bigint' || n < BigInt(1)) + throw new MarketError( + 'INVALID_CARD_ID', + 'Card IDs are positive bigint values.' + ); +} + +export class MarketNamespaceImpl implements MarketNamespace { + constructor(private readonly rt: StackRuntime) {} + private async viewAt(cardId: bigint, s: MarketSnapshot): Promise { + id(cardId); + const d = deployment(this.rt); + const v = await s.read(d.marketplace, ABI, 'getAgentCard', [ + cardId, + ]); + if (getAddress(v.card.provider) === zeroAddress) + throw new MarketError( + 'CARD_NOT_FOUND', + 'This agent card does not exist.' + ); + return v; + } + private async summaryAt( + cardId: bigint, + s: MarketSnapshot, + view?: WireView + ): Promise { + const v = view ?? (await this.viewAt(cardId, s)); + const d = deployment(this.rt); + const { chainNamespace, ...card } = v.card; + return { + ...card, + cardId, + chain: chainNamespace, + version: v.version, + verified: v.verified, + disabled: v.disabled, + rating: await s.read(d.marketplace, ABI, 'getAgentRating', [ + v.card.provider, + ]), + }; + } + private async cardAt(cardId: bigint, s: MarketSnapshot): Promise { + const v = await this.viewAt(cardId, s); + return { + ...(await this.summaryAt(cardId, s, v)), + rules: decodeAgentCardRules(v.rules), + jobSpecTemplate: decodeJobSpec(v.jobSpecTemplate, { + format: 'template', + }) as JobSpecTemplate, + rulesBytes: v.rules, + jobSpecTemplateBytes: v.jobSpecTemplate, + }; + } + async card(cardId: bigint): Promise { + return this.cardAt(cardId, await snapshot(this.rt)); + } + async cards( + options: { provider?: Address; chain?: string; active?: boolean } = {} + ): Promise<{ cards: AgentCardSummary[] }> { + const s = await snapshot(this.rt); + const d = deployment(this.rt); + const count = options.provider + ? await s.read(d.marketplace, ABI, 'agentCardOf', [ + getAddress(options.provider), + ]) + : await s.read(d.marketplace, ABI, 'agentCardCount'); + const cards: AgentCardSummary[] = []; + // Bounded requests. An indexer can replace the walk without changing the public result. + for ( + let start = options.provider ? count : BigInt(1); + start > BigInt(0) && start <= count; + + ) { + const batch = options.provider + ? [start] + : Array.from( + { + length: Number( + count - start + BigInt(1) > BigInt(8) + ? BigInt(8) + : count - start + BigInt(1) + ), + }, + (_, i) => start + BigInt(i) + ); + const rows = await Promise.all(batch.map((n) => this.summaryAt(n, s))); + for (const card of rows) + if ( + (!options.chain || card.chain === options.chain) && + (options.active === undefined || card.active === options.active) + ) { + cards.push(card); + } + if (options.provider) break; + start += BigInt(batch.length); + } + return { cards }; + } + async job(jobId: bigint): Promise<{ + cardId: bigint; + cardVersion: bigint; + wallet: Address; + rulesId: Hex; + }> { + const s = await snapshot(this.rt); + const d = deployment(this.rt); + const [cardId, cardVersion, wallet, rulesId] = await Promise.all([ + s.read(d.marketplace, ABI, 'cardOfJob', [jobId]), + s.read(d.marketplace, ABI, 'cardVersionOfJob', [jobId]), + s.read
    (d.marketplace, ABI, 'agwOfJob', [jobId]), + s.read(d.marketplace, ABI, 'rulesOfJob', [jobId]), + ]); + return { cardId, cardVersion, wallet, rulesId }; + } + async activeJob(wallet: Address): Promise<{ jobId: bigint }> { + const d = deployment(this.rt); + return { + jobId: await ( + await snapshot(this.rt) + ).read(d.marketplace, ABI, 'activeJobOf', [getAddress(wallet)]), + }; + } + + async preview( + cardId: bigint, + options: MarketPreviewOptions + ): Promise { + const rt = this.rt; + const d = deployment(rt); + const s = await snapshot(rt); + const card = await this.cardAt(cardId, s); + const gen = currentGeneration(rt.agw.network); + const now = s.timestamp; + if (card.disabled || !card.active) + throw new MarketError( + 'AGENT_CARD_INACTIVE', + 'This agent card is inactive or disabled.' + ); + if (card.jobSpecTemplate.allowedMutability !== 'NONE') + unavailable('Mutable marketplace criteria'); + const [ + factory, + kernel, + paused, + evaluator, + hook, + rulesHelper, + kernelPaused, + ] = await Promise.all([ + s.read
    (d.marketplace, ABI, 'AGW_FACTORY'), + s.read
    (d.marketplace, ABI, 'KERNEL'), + s.read(d.marketplace, ABI, 'paused'), + s.read
    (d.marketplace, ABI, 'evaluator'), + s.read
    (d.marketplace, ABI, 'hook'), + s.read
    (d.marketplace, ABI, 'RULES'), + s.read(d.kernel, JOB_KERNEL_ABI, 'paused'), + ]); + if ( + getAddress(factory) !== getAddress(gen.addresses.factory) || + getAddress(kernel) !== getAddress(d.kernel) || + getAddress(hook) !== getAddress(d.hook) || + getAddress(rulesHelper) !== getAddress(d.rules) || + getAddress(evaluator) !== getAddress(d.evaluator) + ) + throw new MarketError( + 'CAPABILITY_UNAVAILABLE', + 'The marketplace deployment wiring has changed.' + ); + if (paused || kernelPaused) + throw new MarketError('PAUSED', 'The marketplace or kernel is paused.'); + if (getAddress(card.provider) === getAddress(evaluator)) + throw new MarketError( + 'PROVIDER_IS_EVALUATOR', + 'The provider cannot be the evaluator.' + ); + const job: MarketJobInputs = { + principal: options.principal, + expiredAt: options.expiredAt, + executeBy: options.executeBy, + params: options.params ?? [], + }; + if ( + typeof job.principal !== 'bigint' || + job.principal < card.principalMin || + job.principal > card.principalMax + ) + throw new MarketError( + 'PRINCIPAL_OUT_OF_RANGE', + 'The principal is outside this card’s range.' + ); + if ( + !Number.isSafeInteger(job.expiredAt) || + job.expiredAt < now + card.minDuration || + job.expiredAt > now + card.maxDuration || + job.expiredAt >= 2 ** 48 + ) + throw new MarketError( + 'EXPIRY_OUT_OF_RANGE', + 'Choose an expiry inside the card’s duration window.' + ); + if ( + !Number.isSafeInteger(job.executeBy) || + job.executeBy < now + card.minExecuteWindow || + job.executeBy + card.settleWindow > job.expiredAt + ) + throw new MarketError( + 'EXECUTE_BY_OUT_OF_RANGE', + 'Choose an execution deadline that leaves the settlement window.' + ); + const owner = getAddress(rt.agw.signerPushAccount()); + if (owner === getAddress(card.provider)) + throw new MarketError( + 'CLIENT_IS_PROVIDER', + 'The wallet owner and provider must be different.' + ); + if ( + options.walletIndex !== undefined && + (!Number.isSafeInteger(options.walletIndex) || options.walletIndex < 0) + ) + throw new MarketError( + 'INVALID_WALLET_INDEX', + 'The wallet index must be a nonnegative safe integer.' + ); + const index = + options.walletIndex === undefined + ? await s.read( + factory, + gen.contracts.abis.factory, + 'walletCount', + [owner] + ) + : BigInt(options.walletIndex); + const [wallet, deployed] = await s.read<[Address, boolean]>( + factory, + gen.contracts.abis.factory, + 'predictWallet', + [owner, index] + ); + if ( + deployed && + getAddress( + await s.read
    (factory, gen.contracts.abis.factory, 'ownerOf', [ + wallet, + ]) + ) !== owner + ) + throw new MarketError( + 'NOT_OWNER', + 'The connected account does not own this wallet.' + ); + if ( + (await s.read(d.marketplace, ABI, 'activeJobOf', [wallet])) !== + BigInt(0) + ) + throw new MarketError( + 'WALLET_HAS_ACTIVE_JOB', + 'This wallet already has an active marketplace job.' + ); + const accounts: Record = {}; + const chains = new Set([ + card.chain, + ...card.jobSpecTemplate.reads + .filter( + (r, i) => + r.fills?.some((f) => f.source === 'WALLET') || + card.jobSpecTemplate.checks.some( + (c) => c.read === i && c.target === 'agentic:wallet' + ) + ) + .map((r) => `${r.chainNamespace}:${r.chainId}`), + ]); + for (const chain of chains) { + const [independent, onchain] = await Promise.all([ + rt.agw.resolveCEA(wallet, chain as CHAIN), + s.read
    (d.marketplace, ABI, 'computeCEA', [ + wallet, + keccak256(stringToHex(chain)), + ]), + ]); + if (getAddress(independent.cea) !== getAddress(onchain)) + throw new MarketError( + 'CEA_MISMATCH', + 'The independently derived destination wallet differs from the marketplace.', + { chain, wallet, expectedCEA: onchain, derivedCEA: independent.cea } + ); + accounts[chain] = getAddress(onchain); + } + const rules = decodeCardRulesWire(card.rulesBytes); + const terms = fillCardRules( + rules, + job.principal, + accounts[card.chain], + job.expiredAt + ); + const session = buildSession({ + validator: gen.addresses.sessionValidator, + agent: card.provider, + rulesPolicy: gen.addresses.rulesPolicy, + actions: [ + { + target: gen.addresses.gateway, + selector: '0x77b86bec', + initData: encodeEnvelope(card.chain, encodeUniversalTerms(terms)), + }, + ], + }); + const rawChain = rt.agw.signerOrigin().chain; + if (!/^eip155:[1-9]\d*$/.test(rawChain)) + unavailable('Non-EVM OwnerIntent signing'); + const deadline = options.deadline ?? Math.min(now + 3600, job.expiredAt); + if ( + !Number.isSafeInteger(deadline) || + deadline <= now || + deadline >= 2 ** 48 + ) + throw new MarketError( + 'INVALID_DEADLINE', + 'The intent deadline must be a future uint48 timestamp.' + ); + const request = { + cardId, + owner, + index, + job, + deadline, + signerChainId: BigInt(rawChain.split(':')[1]), + }; + const [intent, [mode, calldata]] = await Promise.all([ + s.read(d.marketplace, ABI, 'previewIntent', [ + request, + session, + ]), + s.read<[Hex, Hex]>(d.marketplace, ABI, 'buildCreateJobCalldata', [ + cardId, + owner, + index, + job, + ]), + ]); + const spec = resolveJobSpec(card.jobSpecTemplate, { + principal: job.principal, + params: job.params, + accounts, + origin: specOrigin(d.marketplace, cardId, card.version, job.principal), + executeBy: job.executeBy, + settleWindow: card.settleWindow, + }); + if ( + getAddress(intent.owner) !== owner || + intent.index !== index || + intent.deadline !== deadline || + intent.signerChainId !== request.signerChainId + ) + throw new MarketError( + 'INTENT_MISMATCH', + 'The preview intent names a different owner, wallet index, chain or deadline.' + ); + const bytes = encodeJobSpec(spec); + const packedTarget = getAddress(('0x' + calldata.slice(2, 42)) as Address); + const kernelCall = decodeCreateJob(('0x' + calldata.slice(106)) as Hex); + if ( + packedTarget !== getAddress(d.kernel) || + BigInt('0x' + calldata.slice(42, 106)) !== BigInt(0) || + kernelCall.description !== bytes || + getAddress(kernelCall.provider) !== getAddress(card.provider) || + getAddress(kernelCall.evaluator) !== getAddress(evaluator) || + getAddress(kernelCall.hook) !== getAddress(hook) || + kernelCall.expiredAt !== BigInt(job.expiredAt) || + intent.execCalldataHash !== keccak256(calldata) || + intent.sessionHash !== keccak256(encodeSession(session)) || + intent.mode !== mode || + getAddress(intent.wallet) !== getAddress(wallet) || + getAddress(intent.executor) !== getAddress(d.marketplace) + ) + throw new MarketError( + 'INTENT_MISMATCH', + 'The marketplace preview disagrees with the independently built job or permissions.' + ); + await s.read(d.rules, MARKET_RULES_ABI, 'checkRulesMatchCard', [ + card.rulesBytes, + session, + { + agent: card.provider, + chainHash: keccak256(stringToHex(card.chain)), + principal: job.principal, + expiredAt: job.expiredAt, + expectedCEA: accounts[card.chain], + }, + ]); + const label = options.label ?? 'Agent job'; + assertLabel(label); + const description = describeJobSpec(spec); + return { + cardId, + cardVersion: card.version, + wallet: getAddress(wallet), + walletDeployed: deployed, + session, + intent, + calldata, + jobSpec: { spec, bytes }, + job, + label, + deposit: { + principal: { + prc20: terms.assets[rules.principalAsset].token, + amount: job.principal, + }, + providerFee: { token: card.paymentToken, amount: card.providerFee }, + pc: card.rules.maxGasPerCall, + }, + preview: { + mayDo: terms.allowedCalls.map( + (c) => + `${card.chain}: ${c.target} ${c.selector}; ${c.pins.length} argument conditions; max value ${c.maxValue}.` + ), + mayMove: terms.assets.map( + (a) => + `${a.token}: up to ${a.maxPerCall} per outbound, ${a.maxTotal} total; gas budget ${terms.maxGasPerCall} PC wei.` + ), + judgedBy: [...description.checks, description.logic], + until: new Date(job.expiredAt * 1000).toISOString(), + }, + }; + } + async openJob( + plan: JobPlan, + options: MarketWriteOptions & { relay?: boolean } = {} + ) { + if (options.relay) unavailable('Marketplace relaying'); + if (!this.rt.agw.signerIsPushNative()) + unavailable( + 'External-owner marketplace signatures pending ERC-1271 acceptance' + ); + if (this.rt.agw.isReadOnly) + throw new MarketError( + 'READ_ONLY', + 'Connect a signing wallet to open a job.' + ); + const ownerCode = await this.rt.agw.reader.getCode({ + address: this.rt.agw.signerPushAccount(), + }); + if (ownerCode && ownerCode !== '0x') + unavailable( + 'Delegated or contract-owner intent signing pending ERC-1271 acceptance' + ); + const fresh = await this.preview(plan.cardId, { + ...plan.job, + walletIndex: Number(plan.intent.index), + deadline: plan.intent.deadline, + label: plan.label, + }); + if (fp(fresh) !== fp(plan)) + throw new MarketError( + 'STALE_PLAN', + 'The plan changed. Preview and review it again before signing.' + ); + const d = deployment(this.rt); + const gen = currentGeneration(this.rt.agw.network); + progress(this.rt, options.progressHook, 'MARKET-TX-101', 'Plan verified', { + cardId: plan.cardId, + wallet: plan.wallet, + }); + const sig = (await this.rt.signTypedData({ + domain: { + name: 'AGWFactory', + version: '1', + chainId: Number(plan.intent.signerChainId), + verifyingContract: gen.addresses.factory, + salt: toHex(BigInt(this.rt.agw.pushChainNamespace.split(':')[1]), { + size: 32, + }), + }, + types: { OwnerIntent: ownerIntentFields }, + primaryType: 'OwnerIntent', + message: { ...plan.intent }, + })) as Hex; + progress( + this.rt, + options.progressHook, + 'MARKET-TX-102', + 'Owner intent signed' + ); + const tx = await write( + this.rt, + { + target: d.marketplace, + value: BigInt(0), + data: encodeFunctionData({ + abi: ABI, + functionName: 'openJob', + args: [ + { + cardId: plan.cardId, + cardVersion: plan.cardVersion, + job: plan.job, + session: plan.session, + intent: plan.intent, + sig, + label: plan.label, + }, + ], + }), + }, + options.progressHook, + 'MARKET', + true + ); + const e = await eventArgs(this.rt, tx, d.marketplace, ABI, 'JobOpened'); + if ( + e['cardId'] !== plan.cardId || + e['cardVersion'] !== plan.cardVersion || + getAddress(e['agw'] as Address) !== plan.wallet || + e['principal'] !== plan.job.principal || + getAddress(e['owner'] as Address) !== plan.intent.owner + ) + throw new MarketError( + 'RECEIPT_MISMATCH', + 'The opened job does not match the signed plan.', + { txHash: tx.hash } + ); + return { + jobId: e['jobId'] as bigint, + wallet: getAddress(e['agw'] as Address), + rulesId: e['rulesId'] as Hex, + tx, + }; + } + async deposit(_jobId: bigint, _options?: MarketWriteOptions): Promise { + void _jobId; + void _options; + throw new MarketError( + 'CAPABILITY_UNAVAILABLE', + 'Automatic deposits are not implemented yet. Fund the AGW explicitly, then call client.job.fund.', + { feature: 'market.deposit' } + ); + } + readonly agent = { + card: async (): Promise => { + const d = deployment(this.rt); + const s = await snapshot(this.rt); + const n = await s.read(d.marketplace, ABI, 'agentCardOf', [ + this.rt.agw.signerPushAccount(), + ]); + return n ? this.cardAt(n, s) : undefined; + }, + register: async ( + card: AgentCardInput, + options: Parameters[1] + ) => this.cardWrite(undefined, card, options), + update: async ( + cardId: bigint, + card: AgentCardInput, + options: Parameters[2] + ) => this.cardWrite(cardId, card, options), + setActive: async ( + cardId: bigint, + active: boolean, + options: MarketWriteOptions = {} + ) => { + const card = await this.summaryAt(cardId, await snapshot(this.rt)); + this.assertProvider(card); + const d = deployment(this.rt); + return write( + this.rt, + { + target: d.marketplace, + value: BigInt(0), + data: encodeFunctionData({ + abi: ABI, + functionName: 'setAgentCardActive', + args: [cardId, active], + }), + }, + options.progressHook, + 'MARKET', + true + ); + }, + }; + private assertProvider(card: Pick): void { + if ( + getAddress(card.provider) !== getAddress(this.rt.agw.signerPushAccount()) + ) + throw new MarketError( + 'NOT_CARD_PROVIDER', + 'Connect the provider that registered this card.' + ); + } + private async cardWrite( + cardId: bigint | undefined, + card: AgentCardInput, + options: Parameters[1] + ) { + const d = deployment(this.rt); + const s = await snapshot(this.rt); + if ( + !card.jobType || + !/^eip155:[1-9]\d*$/.test(card.chain) || + !card.metadataURI || + !/^0x[\da-f]{64}$/i.test(card.metadataHash) || + /^0x0{64}$/i.test(card.metadataHash) + ) + throw new MarketError( + 'INVALID_AGENT_CARD', + 'Supply a job type, EVM execution chain, metadata URI and nonzero metadata hash.' + ); + for (const v of [card.providerFee, card.principalMin, card.principalMax]) + if ( + typeof v !== 'bigint' || + v < BigInt(0) || + v >= BigInt(1) << BigInt(256) + ) + throw new MarketError( + 'INVALID_AGENT_CARD', + 'Card amounts must fit uint256.' + ); + if ( + card.principalMax === BigInt(0) || + card.principalMin > card.principalMax || + [ + card.minDuration, + card.maxDuration, + card.minExecuteWindow, + card.settleWindow, + ].some((n) => !Number.isInteger(n) || n < 0 || n > 0xffffffff) || + card.minDuration < 3600 || + card.minDuration > card.maxDuration || + card.settleWindow < 1 || + card.minExecuteWindow + card.settleWindow > card.maxDuration + ) + throw new MarketError( + 'INVALID_AGENT_CARD', + 'The principal or duration ranges are invalid.' + ); + if (cardId !== undefined) { + const current = await this.summaryAt(cardId, s); + this.assertProvider(current); + if (current.chain !== card.chain) + throw new MarketError( + 'CARD_IDENTITY_IMMUTABLE', + 'An existing card cannot change its execution chain.' + ); + } + if (options.jobSpecTemplate.allowedMutability !== 'NONE') + unavailable('Mutable marketplace criteria'); + const token = await s.read
    ( + d.kernel, + JOB_KERNEL_ABI, + 'paymentToken' + ); + if (getAddress(card.paymentToken) !== getAddress(token)) + throw new MarketError( + 'TOKEN_MISMATCH', + 'This deployment accepts only the kernel payment token.' + ); + const rules = encodeAgentCardRules(options.rules, { + chain: card.chain, + network: this.rt.agw.network, + }); + const template = encodeJobSpec(options.jobSpecTemplate); + const { chain, ...input } = card; + const jobType = /^0x[\da-f]{64}$/i.test(card.jobType) + ? (card.jobType as Hex) + : keccak256(stringToHex(card.jobType)); + const c = { + ...input, + jobType, + chainNamespace: chain, + provider: this.rt.agw.signerPushAccount(), + active: true, + }; + const data = + cardId === undefined + ? encodeFunctionData({ + abi: ABI, + functionName: 'registerAgentCard', + args: [c, rules, template], + }) + : encodeFunctionData({ + abi: ABI, + functionName: 'updateAgentCard', + args: [cardId, c, rules, template], + }); + const tx = await write( + this.rt, + { target: d.marketplace, value: BigInt(0), data }, + options.progressHook, + 'MARKET', + true + ); + const e = await eventArgs( + this.rt, + tx, + d.marketplace, + ABI, + cardId === undefined ? 'AgentCardRegistered' : 'AgentCardUpdated' + ); + return { + cardId: e['cardId'] as bigint, + version: cardId === undefined ? BigInt(1) : (e['version'] as bigint), + tx, + }; + } +} diff --git a/packages/core/src/lib/market/rules.ts b/packages/core/src/lib/market/rules.ts new file mode 100644 index 00000000..8f0ae939 --- /dev/null +++ b/packages/core/src/lib/market/rules.ts @@ -0,0 +1,417 @@ +import { + decodeAbiParameters, + encodeAbiParameters, + getAddress, + isAddress, + keccak256, + stringToHex, + toHex, + type Address, + type Hex, +} from 'viem'; +import type { MoveableToken } from '../constants/tokens'; +import { CHAIN, PUSH_NETWORK } from '../constants/enums'; +import { getPRC20Address } from '../universal/prc20-address'; +import { argumentLocation, encodeArgWord } from '../agentic/codec/abi-layout'; +import { parseSelector } from '../agentic/codec/selectors'; +import { validatePins } from '../agentic/codec/pins'; +import { + UNIVERSAL_TERMS_PARAM, + type AssetCapWire, + type AllowedCallWire, + type UniversalTermsWire, +} from '../agentic/codec/universal-terms'; +import type { + ArgumentPath, + WalletMarker, + Selector, +} from '../agentic/agentic.types'; +import type { PrincipalMarker } from '../job-spec/types'; +import { PRINCIPAL } from '../job-spec/constants'; +import { MarketError } from './errors'; + +export type MarketAssetToken = MoveableToken | string | { prc20: Address }; +export type MarketPin = + | { + arg: ArgumentPath; + expected: + | Hex + | Address + | bigint + | boolean + | WalletMarker + | PrincipalMarker; + max?: never; + } + | { arg: ArgumentPath; max: bigint | PrincipalMarker; expected?: never }; +export interface AgentCardRules { + assets: { + token: MarketAssetToken; + maxPerCall: bigint | PrincipalMarker; + maxTotal?: bigint | PrincipalMarker; + }[]; + principalAsset: number; + maxGasPerCall: bigint; + allowedCalls: { + target: Address; + selector: string; + pins?: MarketPin[]; + maxValue?: bigint; + }[]; +} +export interface CardRulesWire { + assets: readonly AssetCapWire[]; + principalAsset: number; + maxGasPerCall: bigint; + allowedCalls: readonly AllowedCallWire[]; +} +export const MARKER_WALLET = keccak256( + stringToHex('push.marketplace.marker.WALLET') +); +export const MARKER_PRINCIPAL = keccak256( + stringToHex('push.marketplace.marker.PRINCIPAL') +); +const PRINCIPAL_WORD = BigInt(MARKER_PRINCIPAL); +const decodedRules = new WeakMap< + AgentCardRules, + { fingerprint: string; wire: CardRulesWire } +>(); +const fingerprint = (r: AgentCardRules) => + JSON.stringify(r, (_, v) => (typeof v === 'bigint' ? v.toString() : v)); +const fields = UNIVERSAL_TERMS_PARAM.components; +export const CARD_RULES_PARAM = { + type: 'tuple', + components: [ + fields[2], + { name: 'principalAsset', type: 'uint8' }, + fields[3], + fields[4], + ], +} as const; +const bad = (message: string): never => { + throw new MarketError('INVALID_AGENT_CARD_RULES', message); +}; +function cap(n: bigint | PrincipalMarker | undefined): bigint { + const v = n === PRINCIPAL ? PRINCIPAL_WORD : n ?? BigInt(0); + if (typeof v !== 'bigint' || v < BigInt(0) || v >= BigInt(1) << BigInt(256)) + bad('Spending caps must fit uint256.'); + return v; +} +function toWire( + input: AgentCardRules, + options?: { chain?: string; network?: PUSH_NETWORK; structural?: boolean } +): CardRulesWire { + if ( + !input || + !Array.isArray(input.assets) || + !Array.isArray(input.allowedCalls) + ) + bad('Card rules need assets and allowedCalls arrays.'); + const saved = decodedRules.get(input); + if (saved?.fingerprint === fingerprint(input)) return saved.wire; + if ('approvals' in input) + bad( + 'V2 approvals belong in allowedCalls with spender and amount pins; remove the retired approvals array.' + ); + if ( + input.assets.some( + (a) => + typeof a.token === 'object' && + 'prc20' in a.token && + /^0x0{40}$/i.test(a.token.prc20) + ) + ) + bad('An explicit PRC20 reference cannot be zero.'); + const assets = input.assets.map((a) => ({ + token: + typeof a.token === 'object' && 'prc20' in a.token + ? getAddress(a.token.prc20) + : (() => { + if (options?.structural) + return getAddress( + typeof a.token === 'string' ? a.token : a.token.address + ); + if (!options?.chain) + return bad( + 'Encoding destination tokens needs the card chain, or an explicit { prc20 } reference.' + ); + try { + return getPRC20Address( + { + chain: options.chain as CHAIN, + address: + typeof a.token === 'string' ? a.token : a.token.address, + }, + { network: options.network ?? PUSH_NETWORK.TESTNET_DONUT } + ).address as Address; + } catch (cause) { + throw new MarketError( + 'TOKEN_ROUTE_UNAVAILABLE', + 'This card token has no verified Push route for the selected chain.', + { chain: options.chain, token: a.token }, + cause + ); + } + })(), + maxPerCall: cap(a.maxPerCall), + maxTotal: cap(a.maxTotal), + })); + const allowedCalls: AllowedCallWire[] = input.allowedCalls.map((call) => { + const parsed = parseSelector(call.selector as Selector); + if (parsed.valueOnly) + bad( + 'Marketplace cards support EVM function calls, not Push value-only rules.' + ); + const pins = (call.pins ?? []).map((p) => { + const location = parsed.inputs + ? argumentLocation(parsed.inputs, p.arg, 'Card pin') + : { + offset: + typeof p.arg === 'number' && Number.isInteger(p.arg) && p.arg >= 0 + ? 4 + p.arg * 32 + : bad( + 'Raw selector pins need a nonnegative integer word index.' + ), + param: { type: 'uint256' } as const, + }; + const max = 'max' in p && p.max !== undefined; + const value = 'max' in p && p.max !== undefined ? p.max : p.expected; + if (value === undefined) return bad('A card pin needs expected or max.'); + if (value === 'agentic:wallet' && max) + bad('WALLET is supported only in equality pins.'); + const encoded = + value === 'agentic:wallet' + ? MARKER_WALLET + : value === PRINCIPAL + ? MARKER_PRINCIPAL + : max + ? toHex(cap(value as bigint), { size: 32 }) + : encodeArgWord(location.param, value, 'Card pin'); + return { + offset: location.offset, + op: max ? (1 as const) : (0 as const), + value: encoded, + }; + }); + return { + target: getAddress(call.target), + selector: parsed.selector, + beneficiaryOffset: 0, + hasBeneficiary: false, + maxValue: cap(call.maxValue), + pins, + }; + }); + const wire = { + assets, + principalAsset: input.principalAsset, + maxGasPerCall: cap(input.maxGasPerCall), + allowedCalls, + }; + validateWire(wire, !!options?.structural); + return wire; +} +function validateWire(r: CardRulesWire, structural = false): void { + if (!Array.isArray(r.assets) || r.assets.length < 1 || r.assets.length > 8) + bad('Cards need 1..8 assets.'); + if ( + !Number.isInteger(r.principalAsset) || + r.principalAsset < 0 || + r.principalAsset >= r.assets.length + ) + bad('principalAsset is outside the asset list.'); + const tokens = new Set(); + r.assets.forEach((a, i) => { + if ( + !isAddress(a.token) || + (!structural && /^0x0{40}$/i.test(a.token)) || + tokens.has(a.token.toLowerCase()) + ) + bad('Assets need distinct nonzero PRC20 addresses.'); + tokens.add(a.token.toLowerCase()); + cap(a.maxPerCall); + cap(a.maxTotal); + if (i === r.principalAsset) { + if (a.maxTotal !== PRINCIPAL_WORD || a.maxPerCall === BigInt(0)) + bad( + 'The principal total must be PRINCIPAL and its per-call cap must be positive or PRINCIPAL.' + ); + } else if (a.maxPerCall === PRINCIPAL_WORD || a.maxTotal === PRINCIPAL_WORD) + bad('PRINCIPAL asset-cap markers belong only on the principal asset.'); + }); + cap(r.maxGasPerCall); + if ( + !Array.isArray(r.allowedCalls) || + r.allowedCalls.length < 1 || + r.allowedCalls.length > 32 + ) + bad('Cards need 1..32 allowed calls.'); + if (r.allowedCalls.reduce((n, c) => n + c.pins.length, 0) > 32) + bad('A card rule supports at most 32 conditions.'); + const entries = new Set(); + const pairs = new Map(); + for (const c of r.allowedCalls) { + if ( + !isAddress(c.target) || + /^0x0{40}$/i.test(c.target) || + !/^0x[\da-f]{8}$/i.test(c.selector) + ) + bad('An allowed app or selector is invalid.'); + cap(c.maxValue); + try { + validatePins(c.pins); + } catch (cause) { + throw new MarketError( + 'INVALID_AGENT_CARD_RULES', + 'An allowed call has invalid argument conditions.', + undefined, + cause + ); + } + if ( + c.hasBeneficiary && + (c.beneficiaryOffset < 4 || (c.beneficiaryOffset - 4) % 32 !== 0) + ) + bad('Invalid recipient offset.'); + for (const p of c.pins) + if (p.value === MARKER_WALLET && p.op !== 0) + bad('WALLET pins must use equality.'); + const encoded = encodeAbiParameters([{ ...fields[4], type: 'tuple' }], [c]); + if (entries.has(encoded)) bad('Duplicate allowed call.'); + entries.add(encoded); + const key = `${c.target.toLowerCase()}:${c.selector.toLowerCase()}`; + if (pairs.has(key) && (!pairs.get(key) || !c.pins.length)) + bad('An unpinned alternative would bypass the pinned call.'); + pairs.set(key, c.pins.length > 0); + const pin = (offset: number, op: number) => + c.pins.find((p) => p.offset === offset && p.op === op); + const recipient = (offset: number) => + (c.hasBeneficiary && c.beneficiaryOffset === offset) || + pin(offset, 0)?.value === MARKER_WALLET; + if (c.selector === '0x39509351') + bad('increaseAllowance is not supported in cards.'); + if (c.selector === '0x095ea7b3') { + const spender = pin(4, 0)?.value; + if ( + !spender || + BigInt(spender) === BigInt(0) || + BigInt(spender) >> BigInt(160) !== BigInt(0) + ) + bad('approve needs an EQ pin to a nonzero literal spender.'); + if (!pin(36, 1)) bad('approve needs a MAX amount pin.'); + } + if (c.selector === '0xa9059cbb' && !recipient(4)) + bad('transfer must pin its recipient to WALLET.'); + if (c.selector === '0x23b872dd' && !recipient(36)) + bad('transferFrom must pin its recipient to WALLET.'); + } +} +export function validateAgentCardRules(rules: AgentCardRules): void { + toWire(rules, { structural: true }); +} +export function encodeAgentCardRules( + rules: AgentCardRules, + options: { chain: string; network?: PUSH_NETWORK } +): Hex { + return encodeAbiParameters([CARD_RULES_PARAM], [toWire(rules, options)]); +} +export function decodeCardRulesWire(bytes: Hex): CardRulesWire { + try { + const wire = decodeAbiParameters( + [CARD_RULES_PARAM], + bytes + )[0] as unknown as CardRulesWire; + validateWire(wire); + if ( + encodeAbiParameters([CARD_RULES_PARAM], [wire]).toLowerCase() !== + bytes.toLowerCase() + ) + bad('Noncanonical card rules.'); + return wire; + } catch (cause) { + if (cause instanceof MarketError) throw cause; + throw new MarketError( + 'INVALID_AGENT_CARD_RULES', + 'Unsupported or malformed v2 card-rule encoding.', + undefined, + cause + ); + } +} +export function decodeAgentCardRules( + bytes: Hex, + _options?: { chain?: string } +): AgentCardRules { + void _options; + const r = decodeCardRulesWire(bytes); + // Explicit PRC20 references make unknown/custom registry tokens lossless and unambiguous. + const result: AgentCardRules = { + ...r, + assets: r.assets.map((a) => ({ + token: { prc20: a.token }, + maxPerCall: a.maxPerCall === PRINCIPAL_WORD ? PRINCIPAL : a.maxPerCall, + maxTotal: a.maxTotal === PRINCIPAL_WORD ? PRINCIPAL : a.maxTotal, + })), + allowedCalls: r.allowedCalls.map((c) => ({ + target: c.target, + selector: c.selector, + maxValue: c.maxValue, + pins: [ + ...c.pins.map((p) => { + const value = + p.value === MARKER_WALLET + ? ('agentic:wallet' as const) + : p.value === MARKER_PRINCIPAL + ? PRINCIPAL + : p.value; + return p.op === 1 + ? { + arg: (p.offset - 4) / 32, + max: value === PRINCIPAL ? PRINCIPAL : BigInt(p.value), + } + : { arg: (p.offset - 4) / 32, expected: value }; + }), + ...(c.hasBeneficiary + ? [ + { + arg: (c.beneficiaryOffset - 4) / 32, + expected: 'agentic:wallet' as const, + }, + ] + : []), + ], + })), + }; + decodedRules.set(result, { fingerprint: fingerprint(result), wire: r }); + return result; +} +export function fillCardRules( + r: CardRulesWire, + principal: bigint, + wallet: Address, + expiredAt: number +): UniversalTermsWire { + const walletWord = toHex(BigInt(wallet), { size: 32 }); + return { + validUntil: expiredAt, + expectedCEA: wallet, + assets: r.assets.map((a, i) => ({ + ...a, + maxPerCall: a.maxPerCall === PRINCIPAL_WORD ? principal : a.maxPerCall, + maxTotal: i === r.principalAsset ? principal : a.maxTotal, + })), + maxGasPerCall: r.maxGasPerCall, + allowedCalls: r.allowedCalls.map((c) => ({ + ...c, + pins: c.pins.map((p) => ({ + ...p, + value: + p.value === MARKER_WALLET + ? walletWord + : p.value === MARKER_PRINCIPAL + ? toHex(principal, { size: 32 }) + : p.value, + })), + })), + }; +} diff --git a/packages/core/src/lib/market/runtime.ts b/packages/core/src/lib/market/runtime.ts new file mode 100644 index 00000000..33f52f17 --- /dev/null +++ b/packages/core/src/lib/market/runtime.ts @@ -0,0 +1,232 @@ +import { + decodeEventLog, + getAddress, + type Abi, + type Address, + type Log, + type TypedData, + type TypedDataDomain, +} from 'viem'; +import type { AgenticRuntime } from '../agentic/runtime'; +import { confirmedLogs } from '../agentic/management/common'; +import { currentGeneration } from '../agentic/deployments'; +import type { Call } from '../agentic/contracts/v6'; +import type { + ExecuteParams, + TransactionExecutionOptions, + UniversalExecuteParams, + UniversalTxResponse, +} from '../orchestrator/orchestrator.types'; +import type { ProgressEvent } from '../progress-hook/progress-hook.types'; +import { MarketError, stackError } from './errors'; +import { marketplaceDeployment, type MarketDeployment } from './deployment'; + +export type StackProgressHook = (event: ProgressEvent) => void; +export interface StackRuntime { + agw: AgenticRuntime; + account(): Address; + wallet(): Address | undefined; + send( + params: ExecuteParams | UniversalExecuteParams, + options?: TransactionExecutionOptions + ): Promise; + signTypedData(data: { + domain: TypedDataDomain; + types: TypedData; + primaryType: string; + message: Record; + }): Promise; + /** Internal fixture override; never a public initialization option. */ + deployment?: MarketDeployment; + /** Receipt-confirmed creation blocks accelerate bounded event recovery. */ + jobBlocks?: Map; +} +export function deployment(rt: StackRuntime): MarketDeployment { + return rt.deployment ?? marketplaceDeployment(rt.agw.network); +} +export interface MarketSnapshot { + blockNumber: bigint; + timestamp: number; + read( + address: Address, + abi: Abi, + name: string, + args?: readonly unknown[] + ): Promise; +} +export async function snapshot(rt: StackRuntime): Promise { + const blockNumber = await rt.agw.reader.getBlockNumber(); + const timestamp = rt.agw.reader.getBlock + ? Number((await rt.agw.reader.getBlock({ blockNumber })).timestamp) + : rt.agw.nowSeconds(); + return { + blockNumber, + timestamp, + read: async ( + address: Address, + abi: Abi, + name: string, + args: readonly unknown[] = [] + ) => { + try { + return (await rt.agw.reader.readContract({ + address, + abi, + functionName: name, + args, + blockNumber, + })) as T; + } catch (cause) { + throw new MarketError( + 'READ_FAILED', + `Could not load ${name} at block ${blockNumber}.`, + { address, functionName: name, blockNumber }, + cause + ); + } + }, + }; +} +export function progress( + rt: StackRuntime, + hook: StackProgressHook | undefined, + id: string, + message: string, + response: object = {} +): void { + rt.agw.emit( + { + id, + title: message, + message, + level: id.endsWith('199-02') ? 'ERROR' : 'INFO', + response, + timestamp: new Date().toISOString(), + }, + hook + ); +} +export async function write( + rt: StackRuntime, + call: Call, + hook: StackProgressHook | undefined, + family: 'MARKET' | 'JOB', + signer = false +): Promise { + if (rt.agw.isReadOnly) + throw new MarketError('READ_ONLY', 'Connect a signing wallet to continue.'); + progress(rt, hook, `${family}-TX-103`, 'Submitting transaction'); + try { + const tx = await (signer + ? rt.agw.execute( + { to: call.target, value: call.value, data: call.data }, + { progressHook: hook } + ) + : rt.send( + { to: call.target, value: call.value, data: call.data }, + { progressHook: hook } + )); + const originalWait = tx.wait.bind(tx); + let terminalReported = false; + const wait: typeof tx.wait = async (...args) => { + try { + const receipt = await originalWait(...args); + if (!terminalReported) { + terminalReported = true; + progress( + rt, + hook, + `${family}-TX-199-${receipt.status === 1 ? '01' : '02'}`, + receipt.status === 1 + ? 'Transaction confirmed' + : 'Transaction reverted', + { txHash: tx.hash } + ); + } + return receipt; + } catch (error) { + progress( + rt, + hook, + `${family}-TX-199-02`, + 'Transaction confirmation unavailable', + { txHash: tx.hash } + ); + throw error; + } + }; + return { ...tx, wait }; + } catch (error) { + const wrapped = stackError(error); + progress(rt, hook, `${family}-TX-199-02`, 'Transaction failed', { + error: wrapped, + }); + throw wrapped; + } +} +export async function ownerBatch( + rt: StackRuntime, + wallet: Address, + calls: Call[], + hook?: StackProgressHook +): Promise { + const gen = currentGeneration(rt.agw.network); + const s = await snapshot(rt); + const owner = getAddress( + await s.read
    (wallet, gen.contracts.abis.wallet, 'owner') + ); + if (owner !== getAddress(rt.agw.signerPushAccount())) + throw new MarketError('NOT_CLIENT', 'Connect the owner of the job wallet.'); + return write( + rt, + { + target: wallet, + value: BigInt(0), + data: gen.contracts.encodeExecute(calls), + }, + hook, + 'JOB', + true + ); +} +export async function eventArgs( + rt: StackRuntime, + tx: UniversalTxResponse, + address: Address, + abi: Abi, + name: string +): Promise> { + const result = await confirmedLogs(rt.agw, tx); + const found: Record[] = []; + for (const log of result.logs as Log[]) { + if (log.address.toLowerCase() !== address.toLowerCase()) continue; + try { + const e = decodeEventLog({ + abi, + eventName: name, + data: log.data, + topics: log.topics, + strict: true, + }); + if (e.eventName === name) { + found.push(e.args as unknown as Record); + const args = e.args as unknown as Record; + if ( + (name === 'JobCreated' || name === 'JobOpened') && + typeof args['jobId'] === 'bigint' && + log.blockNumber !== null + ) + rt.jobBlocks?.set(args['jobId'], log.blockNumber); + } + } catch { + /* Other contract events are expected in a receipt. */ + } + } + if (found.length !== 1) + throw new MarketError( + 'RECEIPT_MISMATCH', + `The submitted transaction did not produce one ${name} event.`, + { txHash: tx.hash } + ); + return found[0]; +} diff --git a/packages/core/src/lib/market/types.ts b/packages/core/src/lib/market/types.ts new file mode 100644 index 00000000..b430a347 --- /dev/null +++ b/packages/core/src/lib/market/types.ts @@ -0,0 +1,144 @@ +import type { Address, Hex } from 'viem'; +import type { AgentCardRules } from './rules'; +import type { JobSpec, JobSpecTemplate } from '../job-spec/types'; +import type { SessionWire } from '../agentic/codec/session'; +import type { StackProgressHook } from './runtime'; +import type { UniversalTxResponse } from '../orchestrator/orchestrator.types'; + +export interface AgentCardInput { + /** A name is hashed on write; reads retain the canonical bytes32 jobType. */ + jobType: string; + metadataURI: string; + metadataHash: Hex; + chain: string; + providerFee: bigint; + paymentToken: Address; + principalMin: bigint; + principalMax: bigint; + minDuration: number; + maxDuration: number; + minExecuteWindow: number; + settleWindow: number; +} +export interface AgentCard extends AgentCardInput { + cardId: bigint; + provider: Address; + active: boolean; + version: bigint; + verified: boolean; + disabled: boolean; + rating: bigint; + rules: AgentCardRules; + jobSpecTemplate: JobSpecTemplate; + /** Canonical on-chain bytes retained for exact matching and unknown token metadata. */ + rulesBytes: Hex; + jobSpecTemplateBytes: Hex; +} +export type AgentCardSummary = Omit< + AgentCard, + 'rules' | 'jobSpecTemplate' | 'rulesBytes' | 'jobSpecTemplateBytes' +>; +export interface MarketJobInputs { + principal: bigint; + expiredAt: number; + executeBy: number; + params: bigint[]; +} +export interface OwnerIntent { + owner: Address; + wallet: Address; + executor: Address; + index: bigint; + sessionHash: Hex; + mode: Hex; + execCalldataHash: Hex; + nonceKey: bigint; + nonceSeq: bigint; + grantNonce: bigint; + deadline: number; + signerChainId: bigint; +} +export interface JobPlan { + cardId: bigint; + cardVersion: bigint; + wallet: Address; + walletDeployed: boolean; + session: SessionWire; + intent: OwnerIntent; + calldata: Hex; + jobSpec: { spec: JobSpec; bytes: Hex }; + job: MarketJobInputs; + label: string; + /** Reference deposit amounts; no principal or fee is moved by openJob. */ + deposit: { + principal: { prc20: Address; amount: bigint }; + providerFee: { token: Address; amount: bigint }; + pc: bigint; + }; + preview: { + mayDo: string[]; + mayMove: string[]; + judgedBy: string[]; + until: string; + }; +} +export interface MarketPreviewOptions extends Omit { + params?: bigint[]; + walletIndex?: number; + deadline?: number; + label?: string; +} +export interface MarketWriteOptions { + progressHook?: StackProgressHook; +} +export interface MarketNamespace { + cards(options?: { + provider?: Address; + chain?: string; + active?: boolean; + }): Promise<{ cards: AgentCardSummary[] }>; + card(cardId: bigint): Promise; + preview(cardId: bigint, options: MarketPreviewOptions): Promise; + openJob( + plan: JobPlan, + options?: MarketWriteOptions & { relay?: boolean } + ): Promise<{ + jobId: bigint; + wallet: Address; + rulesId: Hex; + tx: UniversalTxResponse; + }>; + deposit(jobId: bigint, options?: MarketWriteOptions): Promise; + job( + jobId: bigint + ): Promise<{ + cardId: bigint; + cardVersion: bigint; + wallet: Address; + rulesId: Hex; + }>; + activeJob(wallet: Address): Promise<{ jobId: bigint }>; + agent: { + register( + card: AgentCardInput, + options: MarketWriteOptions & { + rules: AgentCardRules; + jobSpecTemplate: JobSpecTemplate; + } + ): Promise<{ cardId: bigint; version: bigint; tx: UniversalTxResponse }>; + update( + cardId: bigint, + card: AgentCardInput, + options: MarketWriteOptions & { + rules: AgentCardRules; + jobSpecTemplate: JobSpecTemplate; + } + ): Promise<{ cardId: bigint; version: bigint; tx: UniversalTxResponse }>; + setActive( + cardId: bigint, + active: boolean, + options?: MarketWriteOptions + ): Promise; + card(): Promise; + }; +} diff --git a/packages/core/src/lib/push-chain/push-chain.ts b/packages/core/src/lib/push-chain/push-chain.ts index 5939f461..cf5f3b87 100644 --- a/packages/core/src/lib/push-chain/push-chain.ts +++ b/packages/core/src/lib/push-chain/push-chain.ts @@ -55,6 +55,12 @@ import { notAllowedInAgenticMode } from '../agentic/execution/guards'; import { adaptTrackedResponse } from '../agentic/response'; import { createAgenticRuntime, type AgenticRuntime } from '../agentic/runtime'; import type { AgenticNamespace } from '../agentic/agentic.types'; +import { MarketNamespaceImpl } from '../market/market'; +import { JobNamespaceImpl } from '../job/job'; +import type { MarketNamespace } from '../market/types'; +import type { JobNamespace } from '../job/types'; +import type { StackRuntime } from '../market/runtime'; +import { prepareJobRead } from '../job-spec/read'; /** Options accepted by `PushChain.initialize` / `reinitialize`. */ export interface PushChainInitializeOptions { @@ -194,7 +200,7 @@ export class PushChain { * Defaults to the canonical registry on Donut. For your own application receiver, * pass callback.target, gasLimit, abi and functionName, plus an optional args mapper. */ - read: (subject: string, options: O & ValidateReadCall) => Promise>>; + read: ((subject: string, options: O & ValidateReadCall) => Promise>>) & { prepare: typeof prepareJobRead }; /** * Build a validated `ReadSpec` for `subject` on `options.chain`: preflight (oracle * height, protocol fee, gas price), envelope encoding, budget sizing, expiry math. @@ -288,6 +294,8 @@ export class PushChain { * handles. Ownership is the connected signer's Push identity. */ agentic: AgenticNamespace; + market: MarketNamespace; + job: JobNamespace; /** @internal AGW execution context when initialized with `agenticWallet`. */ private agenticContext?: AgenticExecutionContext; @@ -330,6 +338,16 @@ export class PushChain { this.agenticRuntime = createAgenticRuntime(orchestrator, isReadMode); this.agentic = new AgenticNamespaceImpl(this.agenticRuntime); + const stackRuntime: StackRuntime = { + agw: this.agenticRuntime, + jobBlocks: new Map(), + account: () => this.universal.account as `0x${string}`, + wallet: () => this.agenticContext?.wallet, + send: (params, options) => this.universal.sendTransaction(params, options), + signTypedData: (data) => this.universal.signTypedData(data), + }; + this.market = new MarketNamespaceImpl(stackRuntime); + this.job = new JobNamespaceImpl(stackRuntime); // eslint-disable-next-line @typescript-eslint/no-this-alias -- getters below need the instance const self = this; @@ -411,14 +429,14 @@ export class PushChain { return orchestrator.rescueFunds.bind(orchestrator)(params); }, // Only read()/executeReads() send transactions; prepare/simulate/track remain read-only. - read: async (subject: string, options: O) => { + read: Object.assign(async (subject: string, options: O) => { const params = await resolveReadSpecParams(subject, withReadRefund(options), orchestrator.getNetwork(), orchestrator.getRpcUrls()); assertRequestEntrypoint(params.callback, 'read'); if (this.isReadMode) throw new Error('Read only mode cannot call read function'); const prepared = await orchestrator.prepareRead(params, options.progressHook); const { reads: [response] } = await executePreparedReads(readDeps(), [prepared] as const, options); return response as UniversalReadResponse>; - }, + }, { prepare: prepareJobRead }), prepareRead: async (subject: string, options: O & ValidateReadCall) => { const params = await resolveReadSpecParams(subject, withReadRefund(options), orchestrator.getNetwork(), orchestrator.getRpcUrls()); return orchestrator.prepareRead(params) as Promise>>; diff --git a/packages/core/src/lib/utils.ts b/packages/core/src/lib/utils.ts index ca82e7ba..2707d1d7 100644 --- a/packages/core/src/lib/utils.ts +++ b/packages/core/src/lib/utils.ts @@ -1,4 +1,6 @@ import { agenticPresets } from './agentic/presets'; +import { jobSpecUtils } from './job-spec'; +import { validateAgentCardRules, encodeAgentCardRules, decodeAgentCardRules } from './market/rules'; import { convertOriginToExecutor, fromChainAgnostic, @@ -874,6 +876,8 @@ export class Utils { /** Pure preset discovery/templates; internal encoders and identifiers stay private. */ static readonly agentic = Object.freeze({ presets: agenticPresets }); + static readonly job = jobSpecUtils; + static readonly market = Object.freeze({ validateAgentCardRules, encodeAgentCardRules, decodeAgentCardRules }); /** * Internal: resolves a CHAIN enum from either a CHAIN value or a PushChain client instance. diff --git a/packages/core/tsconfig.marketplace-local.json b/packages/core/tsconfig.marketplace-local.json new file mode 100644 index 00000000..023b9ecd --- /dev/null +++ b/packages/core/tsconfig.marketplace-local.json @@ -0,0 +1,5 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { "module": "commonjs", "types": ["jest", "node"] }, + "include": ["__market-local__/**/*.ts", "src/**/*.d.ts"] +} diff --git a/plan/SDK-CHANGELOG.md b/plan/SDK-CHANGELOG.md index 8e161655..9dc751d7 100644 --- a/plan/SDK-CHANGELOG.md +++ b/plan/SDK-CHANGELOG.md @@ -4,6 +4,16 @@ Running history for work continued on `feat/agw-sdk-v4`, covering AGW, marketpla For each meaningful checkpoint, add a dated entry with the change, decisions, validation, remaining work and relevant commit/evidence links. Keep earlier entries as history and mark superseded decisions explicitly. Distinguish implemented code, planning, local/fork checks, funded execution, Git delivery and package publication. Git history for this file records the exact commit introducing each checkpoint. +## 2026-10-20 — first marketplace SDK implementation + +**Implemented:** client.market discovery/provider management, exact preview and native plain-EOA open; client.job create/pricing/funding/submit/status/list/watch/cancel/refund; deployed v2 JobSpec/template/card-rule codecs, marker resolution and authoring helpers; additive universal.read.prepare; constants/types/errors and a [consumer guide](../packages/core/MARKETPLACE.md). Binary kernel description bytes survive encoding and reads. Default E2E selection stays unchanged. + +**Validation:** 2,205 units pass (12 existing skips); six real-stack SDK fork E2Es pass, including nonzero pUSDC escrow/payout and paused refunds; two read-only live cases and one funded register/open/cancel/revoke/deactivate smoke pass. Build/typechecks, new-production lint, source/built API equality and compiled guide/package checks pass. [Details](marketplace/research/sdk-implementation-2026-10-20/README.md). + +**New findings:** three destination CEA factory tables disagree, so preview fails closed there; BSC Testnet matches and passes live. The shared test master is delegated, so the passing live path uses a fresh native owner. Current open signing explicitly gates delegated/contract/external owners. An initial live attempt registered/deactivated card 1 without opening; the later fresh-owner run opened/cancelled job 1 and deactivated card 2. + +**Placeholders:** historical deposit orchestration, paid read preview, compatible automatic evaluation/retry, mutable criteria, relayer, external/delegated signing, recurring jobs and ratings. No successful dummy responses or deployment substitutions were added. No package or contract was published/deployed. Continue on feat/agw-sdk-v4; [status and next requirements](marketplace/implementation-status.md). + ## 2026-10-20 — marketplace research and implementation handoff **Planning delivered:** [plan/marketplace](marketplace/README.md) contains fresh exports of Notion pages 2/6/3/7/4/8, separately reviewed discussions, immutable contract/ABI snapshots, live Donut observations, a gap register, M4/K-12 analysis, the implementation sequence and draft team questions. This checkpoint adds no marketplace SDK runtime and sends no public-chain transactions or team comments. diff --git a/plan/marketplace/README.md b/plan/marketplace/README.md index 8690836c..d872fe45 100644 --- a/plan/marketplace/README.md +++ b/plan/marketplace/README.md @@ -1,6 +1,6 @@ # Agentic marketplace SDK planning -Updated October 20, 2026. This folder is the research and implementation handoff for the next SDK phase. No marketplace SDK implementation or public-chain transaction was made by this review. Existing uncommitted AGW work is left intact. +Updated October 20, 2026. **Actual SDK implementation has started:** see [current implementation and acceptance](implementation-status.md). The initial contract-only research below is preserved as history; its planning-only statements predate the SDK and live smoke checkpoint. No package was published. **Build against deployed UniversalMarketplace v2, pinned at `sdk-iteration-v1@443b4e2dd9ca5dd9ffc8efebdfcecd619dd66c47`.** The six supplied Notion pages were exported again through signed-in Chrome, and their visible discussion panels were reviewed. The older marketplace pages in `plan/agw/notion` remain historical. @@ -9,6 +9,7 @@ Updated October 20, 2026. This folder is the research and implementation handoff | Document | Purpose | | --- | --- | | [SDK development history](../SDK-CHANGELOG.md) | Running checkpoints, decisions, validation and Git delivery on feat/agw-sdk-v4 | +| [Implementation status](implementation-status.md) | Implemented SDK methods, explicit placeholders, current CEA mismatch and passing local/live coverage | | [Verified baseline](current-baseline.md) | Deployment, capabilities, exact wire, and shipped versus future behavior | | [Source inventory](SOURCES.md) | Fresh exports, immutable contract pins, comments and source priority | | [Spec/contract gaps](analysis/spec-and-contract-gaps.md) | Concrete mismatches, ownership and effect on delivery | diff --git a/plan/marketplace/current-baseline.md b/plan/marketplace/current-baseline.md index 482bfdb3..dac8a70b 100644 --- a/plan/marketplace/current-baseline.md +++ b/plan/marketplace/current-baseline.md @@ -1,5 +1,7 @@ # Verified marketplace baseline +This records the contract/research baseline. SDK implementation and later live acceptance are tracked in [implementation status](implementation-status.md), including a newly verified SDK-versus-marketplace CEA factory mismatch on three chains. + Observed October 20, 2026. Deployment source: `443b4e2dd9ca5dd9ffc8efebdfcecd619dd66c47`, branch `sdk-iteration-v1` in `pushchain/push-chain-core-contracts`. AGW dependency: `ffd567d3e49b2d27c6f50ad36093274dbac3090f`, matching the existing SDK v6 adapter. ## Live Donut deployment diff --git a/plan/marketplace/implementation-plan.md b/plan/marketplace/implementation-plan.md index ca2fbc4d..b30ff288 100644 --- a/plan/marketplace/implementation-plan.md +++ b/plan/marketplace/implementation-plan.md @@ -1,5 +1,7 @@ # Marketplace and job SDK implementation plan +**Implementation is underway:** see [current status](implementation-status.md). The dated plan below records the original handoff; the referenced AGW fixes were subsequently committed as a542f303. + Planning only, October 20, 2026. Start from existing `feat/agw-sdk-v4` without disturbing its uncommitted AGW error improvements. Keep marketplace delivery separate from AGW release history. This is a proposed implementation sequence; product decisions still open are listed in [questions](questions.md). ## First delivery boundary diff --git a/plan/marketplace/implementation-status.md b/plan/marketplace/implementation-status.md new file mode 100644 index 00000000..ea7bad5b --- /dev/null +++ b/plan/marketplace/implementation-status.md @@ -0,0 +1,50 @@ +# Marketplace SDK implementation status + +October 20, 2026 — first implementation checkpoint on `feat/agw-sdk-v4`. This supersedes the planning-only statements in the original research package. No package was published. + +## Implemented + +- `client.market`: card discovery/reads; provider register/update/setActive/card; independently checked CEA and JobSpec preview; native plain-EOA OwnerIntent signing/open; job mappings and active-wallet reads. +- `client.job`: plain create; provider pricing; explicit-budget acceptance, balances/allowances and atomic AGW funding; submit; status/list/watch; client cancel with recorded marketplace permission revocation; expiry/grace refunds, including while paused. +- `PushChain.utils.job`: pure EVM read authoring, complete/template builders, canonical v2 codecs and descriptions. `client.universal.read.prepare` exposes the same pure authoring adapter; existing async prepareRead is unchanged. +- `PushChain.utils.market`: deployed four-field card rules, principal/wallet markers and pinned approvals. Destination-token resolution always uses the explicit card chain, including same-address native-token objects. Decoded unknown PRC20s remain explicit references. Unchanged legacy wire metadata is preserved; archive raw bytes for persistence. +- `AGENTIC.PRINCIPAL` and `AGENTIC.JOB` vocabulary/address table; public types/errors; source and compiled consumer guide checks. The API checker now canonicalizes equivalent string-literal quote syntax in emitted property names. + +Binary JobSpec data in the kernel's Solidity string is handled as raw bytes while retaining the original createJob selector. Card versions, rules, origin and calldata are independently compared before signing. Plain jobs and historical card versions require an explicitly reviewed budget; the SDK does not silently adopt a re-quote. + +Registry summaries do not decode an unverified provider's template. A malformed template therefore cannot break listing or prevent its provider from deactivating/updating the card. Full decoding/preview still refuses unsupported content. + +## Current placeholders and delivery limits + +| Surface | Current behavior / next requirement | +| --- | --- | +| market.deposit | Explicit CAPABILITY_UNAVAILABLE. Historical-card snapshot/resumption and deposit policy remain a later SDK increment. Fund the AGW explicitly. | +| Automatic evaluator / job.verify | Explicit capability error. Current evaluator is manual; the linked evaluator has a different ABI/wire. No baseline, frozen-spec or verdict data is invented. | +| Paid previewJobSpec | Explicit capability error pending the fee/callback/raw-read adapter. Pure authoring/description works. | +| Replacement criteria / non-NONE cards | Refused before writes. Expected-spec-hash acceptance must be delivered with compatible contracts before mutable negotiation. | +| External and contract/delegated owners | openJob is gated before signing. The actual test master has EIP-7702 code and follows the contract-signature branch; a fresh plain native owner passes live. ERC-1271 / UEA-specific signing needs its own acceptance. | +| Relayer, recurring jobs, ratings, non-EVM cards/evaluation | No successful placeholder or invented service. Remain outside this checkpoint. | + +`job.cancel` revokes only the permission recorded for that marketplace job, using the current owner's existing AGW authority. Provider/evaluator terminal actions do not acquire owner cleanup authority. Plain jobs have no marketplace permission to infer. Funded job completion/payout is tested with manual evaluator action only on an isolated fork. + +## Destination rollout mismatch + +**BSC Testnet has passing live open/cancel coverage.** Preview fails closed with CEA_MISMATCH for the other three configured destinations: + +| Chain | SDK factory | Marketplace factory | +| --- | --- | --- | +| Sepolia | `0x5E191fbBe22F8866C5e4250557664fCE760e8870` | `0x8ED594A83301FEc545fC6c19fc12cF7111777029` | +| Base Sepolia | `0x7e8CeeDA043ED1460540616103dD57581a66C856` | `0x0A75ca7736b488Eb41675ADc3b3156BACF659F55` | +| Arbitrum Sepolia | `0x65572FFa81c230360a8a53C1682C7f0Ee321E5E7` | `0x88DC189275078Cf509E4Cc773F089c8ad07b7EA2` | +| BSC Testnet | `0x3f1B16e0B072d472951C4563d29d3da6a3EE3Ce8` | same | + +Both old/new factories in the first three chains answer and name the same gateway, but derive different accounts. The queried lower-case gateway ceaFactory getter reverted, so this review does not infer which deployment the live routing stack should use. [Read-only evidence](research/sdk-implementation-2026-10-20/cea-routing.json). Align the canonical route/marketplace configuration with Zaryab; do not change global SDK factories solely to make this guard pass. + +## Acceptance + +- **2,205 unit tests pass**, 12 existing skips; 24 new unit cases. +- **6 public-SDK fork E2Es pass**: real v2/v6 registration, open/signature/wire, decoded update, paid pUSDC allowance/escrow/payout, re-quote/insufficiency/version-drift checks, events/deliverable, plain creation, refund while paused and cancel/revoke. No public token transfer was used for that escrow test. +- **2 live read-only cases pass** and **1 funded live smoke passes**. The funded smoke creates only fresh provider/card/owner/wallet state, opens/cancels/revokes, and deactivates its card. It moves PC for gas/test-wallet setup, not principal/escrow tokens. +- Build, library/spec/local typechecks, compiled imports/declarations/package checks and source-versus-built API comparison pass; the new production modules lint without warnings. The consumer guide's four TS blocks typecheck. + +[Validation details and limits](research/sdk-implementation-2026-10-20/README.md). E2E groups `marketplace` and `marketplace-live` are opt-in; default all selection is unchanged. Future checkpoints should append to the [running changelog](../SDK-CHANGELOG.md). diff --git a/plan/marketplace/questions.md b/plan/marketplace/questions.md index 21293248..4c0b350b 100644 --- a/plan/marketplace/questions.md +++ b/plan/marketplace/questions.md @@ -1,5 +1,7 @@ # Questions to share — drafts, not posted +**Implementation update:** the user authorized implementation with explicit placeholders. Approval handling now follows deployed v2; client cancel/revoke, explicit expected-budget acceptance and additive pure read authoring are implemented/tested. Historical proposals below remain useful context. The immediate rollout question is CEA configuration: SDK and marketplace factories differ on Sepolia/Base Sepolia/Arbitrum Sepolia, while BSC matches and passes live. [Addresses and read-only evidence](implementation-status.md#destination-rollout-mismatch). Which route/deployment manifest is canonical, and which configuration should be aligned? Global routing constants were not changed to bypass the guard. External/delegated signatures and evaluator integration remain explicitly gated. + Prepared October 20 after fresh Notion discussions, pinned source review, unfunded tests and Donut read-only checks. Lead with the concrete mismatch and proposal; do not resend historical questions already answered below. ## Zaryab, with Nilesh / Aman: canonical wire before automatic evaluation diff --git a/plan/marketplace/research/sdk-implementation-2026-10-20/README.md b/plan/marketplace/research/sdk-implementation-2026-10-20/README.md new file mode 100644 index 00000000..4ef384a5 --- /dev/null +++ b/plan/marketplace/research/sdk-implementation-2026-10-20/README.md @@ -0,0 +1,42 @@ +# SDK implementation acceptance — October 20 + +Implementation targets `sdk-iteration-v1@443b4e2`, AGW `ffd567d`, and the deployed v2 stack. This is separate from the earlier contract-only review in research/2026-10-20. Consumer documentation: [MARKETPLACE.md](../../../../packages/core/MARKETPLACE.md). + +## Evidence + +| Check | Result | +| --- | --- | +| Full units | [unit-results.json](unit-results.json): 2,205 passed, 12 existing skips, no failures | +| Fork E2Es | [fork-results.json](fork-results.json): 6 passed against real deployed v2/v6 on Anvil fork block 24447347 | +| Live smoke | [live-results.json](live-results.json), [transactions](live-evidence.json): runner exited 0; one matching test passed, none failed/pending | +| CEA routing | [cea-routing.json](cea-routing.json): three factory/account mismatches; BSC Testnet matches | +| API | [api-comparison.json](api-comparison.json): compiled public surface matches source. Recorded baseline changes include earlier AGW work; this is not an assertion that every listed delta was introduced by this checkpoint. | + +Fork writes and evaluator/admin impersonation occur **only on localhost**. The paid case transfers existing pUSDC from a fork-impersonated holder to the test AGW, approves/pulls actual pUSDC into the real kernel, and checks the provider payout. It does not mint or transfer those tokens on public Donut. The live test has zero provider fee and no principal deposit/export or escrow transfer. + +The local fixture uses actual viem actions/contracts, short polling, longer local RPC timeouts and explicit Anvil confirmation mining. No successful SDK/contract result is mocked. This avoids premature receipt queries falling through to the fork provider. Native sender confirmation timing can still make the run take around two minutes. + +## Live scope and cleanup + +Card 1 registered in the initial attempt; opening failed at gas estimation with the shared master, whose code is EIP-7702 delegation. That card was deactivated. No job was opened by that attempt. The SDK now gates delegated/contract owners before signing rather than applying an untested plain-EOA signature path. + +The passing attempt used a new native owner and provider, registered card 2, opened job 1 on wallet `0xAc1A9778518AbaAE12367f7932C30c114d4940AE`, cancelled it and revoked its grant, then deactivated card 2. Public transaction hashes are in live-evidence.json. No signing keys or unbroadcast authorization payloads are retained here. + +The existing CI reporter sampled `results.success` as false in its onRunComplete callback despite one passed test, zero failures and runner exit 0. The raw live report is retained unchanged. Assess this run using its test status/counts and actual runner exit; the discrepancy is recorded rather than silently rewriting evidence. It is not a claim of one clean full marketplace suite invocation across local/live groups. + +## Commands + +```sh +node node_modules/jest/bin/jest.js --config packages/core/jest.config.ts --runInBand --silent +node node_modules/jest/bin/jest.js --config packages/core/jest.marketplace-local.config.ts --runInBand +node node_modules/ts-node/dist/bin.js --compiler-options '{"module":"commonjs"}' packages/core/__e2e__/ci/run.ts --group marketplace +node node_modules/ts-node/dist/bin.js --compiler-options '{"module":"commonjs"}' packages/core/__e2e__/ci/run.ts --group marketplace-live +node packages/core/scripts/check-agw-docs.js packages/core/MARKETPLACE.md +NX_DAEMON=false node node_modules/nx/bin/nx.js run core:build --skip-nx-cache +node packages/core/scripts/check-agw-package.js +node packages/core/scripts/check-agw-api.js --output /tmp/marketplace-api.json +``` + +Earlier selected test attempts exposed the old constant-key assertion, the three-chain CEA mismatch, local receipt timing and the test's card-version/implicit-price assumption. They were corrected or explicitly gated. The final unit/fork result files contain the final passing runs, not a claim that every earlier attempt passed. + +No package publication, contract deployment, mainnet transaction, automated evaluator execution or destination protocol transaction was performed. Existing full AGW contract harness counts remain their earlier evidence; this checkpoint's real-contract coverage is the six SDK fork E2Es plus the live smoke. diff --git a/plan/marketplace/research/sdk-implementation-2026-10-20/api-comparison.json b/plan/marketplace/research/sdk-implementation-2026-10-20/api-comparison.json new file mode 100644 index 00000000..df1175b1 --- /dev/null +++ b/plan/marketplace/research/sdk-implementation-2026-10-20/api-comparison.json @@ -0,0 +1,13167 @@ +{ + "baseline": "b1597b91a25dbf7f691f589b4e1e154add604315", + "head": "51487e21486f50722765e82c5cfd1374e8e22ad7", + "compiledMatchesSource": true, + "initializeSignatureChanged": false, + "addedExports": [ + "AgentCard", + "AgentCardInput", + "AgentCardRules", + "AgentCardSummary", + "AgenticPresets", + "AllowedMutability", + "ArgumentPath", + "BuildJobSpecOptions", + "BuildJobSpecTemplateOptions", + "CreateJobOptions", + "DecodedSolanaRule", + "Evaluation", + "FundJobOptions", + "Job", + "JobCheck", + "JobCheckTemplate", + "JobError", + "JobEvent", + "JobNamespace", + "JobPlan", + "JobRead", + "JobReadInput", + "JobSpec", + "JobSpecError", + "JobSpecPreview", + "JobSpecTemplate", + "JobStatus", + "LogicKind", + "LogicTree", + "MarketAssetToken", + "MarketError", + "MarketNamespace", + "MarketPin", + "MarketPreviewOptions", + "Operation", + "OwnerIntent", + "Pin", + "PrepareJobReadOptions", + "PreparedJobRead", + "Preset", + "PresetAsset", + "PresetCallIssue", + "PresetCategory", + "PresetChainReadiness", + "PresetConfigurationIssue", + "PresetOptions", + "PresetResult", + "PresetRuleTemplate", + "PrincipalMarker", + "ReadyPresetOptions", + "RuleInput", + "Spent", + "WalletMarker" + ], + "removedExports": [ + "AgenticNetworkConstants", + "NativeRule", + "UniversalRule" + ], + "changedAgwTypes": [ + "AgenticWallet", + "AgenticError", + "AgenticRevertError", + "AGENTIC_ERROR_CODE", + "Rule", + "RuleInput", + "Pin", + "Spent", + "NativeRule", + "AssetCap", + "AllowedCall", + "UniversalRule", + "RulesRecord", + "CreateOptions", + "AgenticTxMetadata" + ], + "publicTypeChanges": [ + "MarketError", + "JobError", + "JobSpecError", + "AgentCardRules", + "MarketAssetToken", + "MarketPin", + "AgentCard", + "AgentCardInput", + "AgentCardSummary", + "MarketNamespace", + "MarketPreviewOptions", + "JobPlan", + "OwnerIntent", + "JobNamespace", + "Job", + "JobStatus", + "JobEvent", + "CreateJobOptions", + "FundJobOptions", + "JobSpec", + "JobSpecTemplate", + "JobRead", + "PreparedJobRead", + "JobReadInput", + "JobCheck", + "JobCheckTemplate", + "LogicTree", + "Evaluation", + "Operation", + "LogicKind", + "AllowedMutability", + "PrincipalMarker", + "PrepareJobReadOptions", + "BuildJobSpecOptions", + "BuildJobSpecTemplateOptions", + "JobSpecPreview", + "AGENTIC_ERROR_CODE", + "AgenticError", + "AgenticRevertError", + "AgenticErrorCode", + "AgenticTxMetadata", + "AgenticWallet", + "AllowedCall", + "AssetCap", + "CreateOptions", + "DecodedSolanaRule", + "Rule", + "RuleInput", + "Pin", + "Spent", + "WalletMarker", + "ArgumentPath", + "RulesRecord", + "PushChain", + "Preset", + "PresetCategory", + "PresetAsset", + "PresetOptions", + "ReadyPresetOptions", + "PresetRuleTemplate", + "PresetResult", + "PresetChainReadiness", + "PresetConfigurationIssue", + "PresetCallIssue", + "AgenticPresets" + ], + "transactionMethodChanges": [ + "read" + ], + "instanceMethodChanges": [ + "job", + "market", + "universal" + ], + "agwConstantsChanged": true, + "before": { + "exports": [ + "AGENTIC_ERROR_CODE", + "AccountRole", + "AccountStatus", + "AccountType", + "AgenticAddress", + "AgenticDoor", + "AgenticError", + "AgenticErrorCode", + "AgenticHex", + "AgenticNamespace", + "AgenticNetworkConstants", + "AgenticProgressHook", + "AgenticRevertError", + "AgenticTxMetadata", + "AgenticWallet", + "AllowedCall", + "AssetCap", + "BatchReadResponse", + "BuildReadSpecParams", + "CHAIN", + "CONTRACT_REQUEST_STATUS", + "CascadeCompletionResult", + "CascadeHopInfo", + "CascadeProgressEvent", + "CascadeTrackOptions", + "CascadedTxResponse", + "ChainSource", + "ChainTarget", + "Checkpoint", + "CheckpointKind", + "ConversionQuote", + "CreateOptions", + "CreateResult", + "DEFAULT_MAX_PC_FOR_GAS_BUFFER_BPS", + "DecodedErrorPayload", + "DecodedReadResult", + "DerivedExecutorAccount", + "EncodedReadQuery", + "EvmReadQuery", + "ForeignChainNamespace", + "FulfilOutcome", + "FundsToken", + "InsufficientPC20BalanceError", + "InvalidPC20AddressError", + "InvalidPC20MetadataError", + "InvalidReadQueryError", + "InvalidReadSpecError", + "MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT", + "MaxPCForGasCapFromNativeValueInput", + "MaxPCForGasCapInput", + "MaxPCForGasCapQuote", + "MultiChainTxResponse", + "NativeRule", + "OutboundTxDetails", + "PC20AddressResult", + "PC20AmbiguousAddressError", + "PC20Error", + "PC20ExpectedButPRC20Error", + "PC20ExportRevertedError", + "PC20FactoryMismatchError", + "PC20RegistryEntry", + "PC20RegistryMismatchError", + "PC20TokenChainMismatchError", + "PC20TokenReference", + "PC20UnknownChainNamespaceError", + "PC20UnsafeEmptyPayloadError", + "PC20WrapperNotRegisteredError", + "PC20WrapperPredictionUnavailableError", + "ParsedReadRequest", + "PreparedRead", + "PreparedUniversalTx", + "PushChain", + "PushChainBatchExecutionError", + "PushChainExecutionError", + "PushChainInitializeOptions", + "READ_ERROR_CODE", + "READ_OUTCOME", + "READ_STATUS", + "ReadCallback", + "ReadCallbackOptions", + "ReadChain", + "ReadDecodeError", + "ReadDestination", + "ReadExecuteOptions", + "ReadFees", + "ReadHeightUnavailableError", + "ReadLifecycleOptions", + "ReadNotFoundError", + "ReadOptions", + "ReadPreflight", + "ReadPrepareOptions", + "ReadQuery", + "ReadQueryOptions", + "ReadRef", + "ReadRegistryUnavailableError", + "ReadResponseTuple", + "ReadResultShape", + "ReadSpec", + "ReadSpecTuple", + "ReadSpecViolation", + "ReadStateError", + "ReadTimeoutError", + "ReadTrackOptions", + "ReadValue", + "ReadWeb2Options", + "ReceiptLike", + "RescueFundsParams", + "ResolvedAccount", + "ResolvedControllerAccounts", + "ResolvedDestination", + "Rule", + "RulesRecord", + "Selector", + "SignAuthorizationParams", + "SignedAuthorization", + "SimulateReadResult", + "SvmExecutePayloadFields", + "SvmGatewayAccountMeta", + "SvmReadQuery", + "TERMINAL_READ_STATUSES", + "TransactionRoute", + "TransactionRouteType", + "UEAStatus", + "UNIVERSAL_CALLBACK_EVM", + "UNIVERSAL_READ_REGISTRY_EVM", + "UNIVERSAL_READ_STATUS", + "UniversalAccount", + "UniversalExecuteParams", + "UniversalOutboundTxRequest", + "UniversalReadResponse", + "UniversalRule", + "UniversalSigner", + "UniversalSignerSkeleton", + "UniversalTo", + "UnsupportedPC20DestinationError", + "UnsupportedReadDestinationError", + "ValidateReadCall", + "WaitForOutboundOptions", + "WalletInfo", + "WalletSummary", + "Web2Extract", + "Web2ReadQuery", + "Web2ValueType", + "buildErc20WithdrawalMulticall", + "buildMigrationPayload", + "buildReadSpecFromPreflight", + "chainSupportsCEA", + "chainSupportsOutbound", + "decodeReadResult", + "detectRoute", + "encodeReadQuery", + "encodeSvmExecutePayload", + "getAllCEAAddresses", + "getCEAAddress", + "getCEAFactoryAddress", + "getPushAccountForCEA", + "inferResultShape", + "isCEA", + "isChainTarget", + "isPC20Reference", + "isSvmChain", + "isValidSolanaHexAddress", + "parseFulfilOutcome", + "parseReadRequestsFromReceipt", + "parseUEAVersion", + "quoteMaxPCForGasCap", + "quoteMaxPCForGasCapFromNativeValue", + "resolveDestination", + "sizeCallbackBudget", + "toCallData", + "toReadQuery", + "toRequestIdHex", + "validateReadSpec" + ], + "agw": { + "AgenticNamespace": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace", + "members": { + "create": { + "optional": false, + "readonly": false, + "type": "(label: string, options: import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions) => Promise" + }, + "derive": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n index?: number;\n}) => Promise<{\n address: `0x${string}`;\n deployed: boolean;\n index: number;\n}>" + }, + "list": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n wallets: import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary[];\n}>" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "(address: `0x${string}`) => import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet" + } + } + }, + "AgenticWallet": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "checkpoints": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n sinceBlock?: bigint;\n}) => Promise<{\n checkpoints: import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint[];\n}>" + }, + "info": { + "optional": false, + "readonly": false, + "type": "() => Promise" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n owner: `0x${string}`;\n}>" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "{\n add(rules: import(\"sdk/src/lib/agentic/agentic.types\").Rule[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise<{\n rulesIds: `0x${string}`[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n get(rulesId: `0x${string}`): Promise;\n list(): Promise<{\n rules: import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord[];\n }>;\n revoke(rulesIds: `0x${string}`[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n revoke(params: {\n all: true;\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n update(params: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n rules: {\n rule: import(\"sdk/src/lib/agentic/agentic.types\").Rule;\n rulesId: `0x${string}`;\n }[];\n }): Promise<{\n rules: {\n replaced: `0x${string}`;\n rulesId: `0x${string}`;\n }[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n}" + }, + "setLabel": { + "optional": false, + "readonly": false, + "type": "(label: string, opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n}) => Promise" + } + } + }, + "AgenticError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"CREATE_PARTIAL\" | \"DUPLICATE_RULE\" | \"FROM_NOT_ALLOWED\" | \"GATEWAY_ALLOWANCE_INSUFFICIENT\" | \"GENERATION_UNSUPPORTED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"REVOKE_NEEDS_TARGET\" | \"RULE_LIMIT_EXCEEDED\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"" + }, + "details": { + "optional": true, + "readonly": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "AgenticRevertError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticRevertError", + "members": { + "agenticCode": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + } + } + }, + "AGENTIC_ERROR_CODE": { + "type": "{\n readonly AGENT_GAS_INSUFFICIENT: \"AGENT_GAS_INSUFFICIENT\";\n readonly AGENT_IS_OWNER: \"AGENT_IS_OWNER\";\n readonly ASSET_CHAIN_MISMATCH: \"ASSET_CHAIN_MISMATCH\";\n readonly CAPABILITY_UNAVAILABLE: \"CAPABILITY_UNAVAILABLE\";\n readonly CREATE_PARTIAL: \"CREATE_PARTIAL\";\n readonly DUPLICATE_RULE: \"DUPLICATE_RULE\";\n readonly FROM_NOT_ALLOWED: \"FROM_NOT_ALLOWED\";\n readonly GATEWAY_ALLOWANCE_INSUFFICIENT: \"GATEWAY_ALLOWANCE_INSUFFICIENT\";\n readonly GENERATION_UNSUPPORTED: \"GENERATION_UNSUPPORTED\";\n readonly INCONSISTENT_READ: \"INCONSISTENT_READ\";\n readonly INDEX_RACE: \"INDEX_RACE\";\n readonly INVALID_RULE: \"INVALID_RULE\";\n readonly NO_RULES_FOR_CHAIN: \"NO_RULES_FOR_CHAIN\";\n readonly NOT_AGENTIC_WALLET: \"NOT_AGENTIC_WALLET\";\n readonly NOT_ALLOWED_IN_AGENTIC_MODE: \"NOT_ALLOWED_IN_AGENTIC_MODE\";\n readonly NOT_OWNER_OR_AGENT: \"NOT_OWNER_OR_AGENT\";\n readonly NOT_WALLET_OWNER: \"NOT_WALLET_OWNER\";\n readonly READ_ONLY: \"READ_ONLY\";\n readonly RECEIPT_MISMATCH: \"RECEIPT_MISMATCH\";\n readonly RECEIPT_UNAVAILABLE: \"RECEIPT_UNAVAILABLE\";\n readonly REVOKE_NEEDS_TARGET: \"REVOKE_NEEDS_TARGET\";\n readonly RULE_LIMIT_EXCEEDED: \"RULE_LIMIT_EXCEEDED\";\n readonly RULE_NOT_FOUND: \"RULE_NOT_FOUND\";\n readonly RULE_READ_FAILED: \"RULE_READ_FAILED\";\n readonly TARGET_NOT_ON_RULE_CHAIN: \"TARGET_NOT_ON_RULE_CHAIN\";\n readonly WALLET_BALANCE_INSUFFICIENT: \"WALLET_BALANCE_INSUFFICIENT\";\n readonly WALLET_NOT_DEPLOYED: \"WALLET_NOT_DEPLOYED\";\n}", + "members": { + "AGENT_GAS_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\"" + }, + "AGENT_IS_OWNER": { + "optional": false, + "readonly": true, + "type": "\"AGENT_IS_OWNER\"" + }, + "ASSET_CHAIN_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"ASSET_CHAIN_MISMATCH\"" + }, + "CAPABILITY_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"CAPABILITY_UNAVAILABLE\"" + }, + "CREATE_PARTIAL": { + "optional": false, + "readonly": true, + "type": "\"CREATE_PARTIAL\"" + }, + "DUPLICATE_RULE": { + "optional": false, + "readonly": true, + "type": "\"DUPLICATE_RULE\"" + }, + "FROM_NOT_ALLOWED": { + "optional": false, + "readonly": true, + "type": "\"FROM_NOT_ALLOWED\"" + }, + "GATEWAY_ALLOWANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"GATEWAY_ALLOWANCE_INSUFFICIENT\"" + }, + "GENERATION_UNSUPPORTED": { + "optional": false, + "readonly": true, + "type": "\"GENERATION_UNSUPPORTED\"" + }, + "INCONSISTENT_READ": { + "optional": false, + "readonly": true, + "type": "\"INCONSISTENT_READ\"" + }, + "INDEX_RACE": { + "optional": false, + "readonly": true, + "type": "\"INDEX_RACE\"" + }, + "INVALID_RULE": { + "optional": false, + "readonly": true, + "type": "\"INVALID_RULE\"" + }, + "NO_RULES_FOR_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"NO_RULES_FOR_CHAIN\"" + }, + "NOT_AGENTIC_WALLET": { + "optional": false, + "readonly": true, + "type": "\"NOT_AGENTIC_WALLET\"" + }, + "NOT_ALLOWED_IN_AGENTIC_MODE": { + "optional": false, + "readonly": true, + "type": "\"NOT_ALLOWED_IN_AGENTIC_MODE\"" + }, + "NOT_OWNER_OR_AGENT": { + "optional": false, + "readonly": true, + "type": "\"NOT_OWNER_OR_AGENT\"" + }, + "NOT_WALLET_OWNER": { + "optional": false, + "readonly": true, + "type": "\"NOT_WALLET_OWNER\"" + }, + "READ_ONLY": { + "optional": false, + "readonly": true, + "type": "\"READ_ONLY\"" + }, + "RECEIPT_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_MISMATCH\"" + }, + "RECEIPT_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_UNAVAILABLE\"" + }, + "REVOKE_NEEDS_TARGET": { + "optional": false, + "readonly": true, + "type": "\"REVOKE_NEEDS_TARGET\"" + }, + "RULE_LIMIT_EXCEEDED": { + "optional": false, + "readonly": true, + "type": "\"RULE_LIMIT_EXCEEDED\"" + }, + "RULE_NOT_FOUND": { + "optional": false, + "readonly": true, + "type": "\"RULE_NOT_FOUND\"" + }, + "RULE_READ_FAILED": { + "optional": false, + "readonly": true, + "type": "\"RULE_READ_FAILED\"" + }, + "TARGET_NOT_ON_RULE_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"TARGET_NOT_ON_RULE_CHAIN\"" + }, + "WALLET_BALANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"WALLET_BALANCE_INSUFFICIENT\"" + }, + "WALLET_NOT_DEPLOYED": { + "optional": false, + "readonly": true, + "type": "\"WALLET_NOT_DEPLOYED\"" + } + } + }, + "Rule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule | import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "NativeRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "amount": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AmountLimit | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "maxCalls": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValuePerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxValueTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "pins": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ArgPin[] | undefined" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "AssetCap": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap", + "members": { + "maxPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/constants/tokens\").MoveableToken" + } + } + }, + "AllowedCall": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall", + "members": { + "beneficiary": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValue": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "`${string}(${string})` | `0x${string}`" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "UniversalRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall[]" + }, + "assets": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap[]" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "`eip155:${string}` | `solana:${string}`" + }, + "maxGasPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "RulesRecord": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "enabled": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "ref": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "rule": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule | import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule" + }, + "rulesId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "CreateOptions": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions", + "members": { + "progressHook": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook | undefined" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Rule[]" + } + } + }, + "CreateResult": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateResult", + "members": { + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "rulesIds": { + "optional": false, + "readonly": false, + "type": "`0x${string}`[]" + }, + "tx": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticTxMetadata": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticTxMetadata", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destinationAccount": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "destinationCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "door": { + "optional": false, + "readonly": false, + "type": "\"agent\" | \"owner\"" + }, + "nativeCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "rawData": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rawTo": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesId": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + } + }, + "publicSurface": { + "CHAIN": { + "type": "typeof import(\"sdk/src/lib/constants/enums\").CHAIN", + "members": { + "ARBITRUM_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA" + }, + "BASE_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA" + }, + "BNB_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET" + }, + "ETHEREUM_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET" + }, + "ETHEREUM_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA" + }, + "PUSH_LOCALNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET" + }, + "PUSH_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET" + }, + "PUSH_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET" + }, + "PUSH_TESTNET_DONUT": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET" + }, + "SOLANA_DEVNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET" + }, + "SOLANA_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET" + }, + "SOLANA_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET" + }, + "WEB2": { + "optional": false, + "readonly": false, + "type": "\"web2\"" + } + } + }, + "ConversionQuote": { + "type": "import(\"sdk/src/lib/constants/tokens\").ConversionQuote", + "members": { + "amountIn": { + "optional": false, + "readonly": false, + "type": "string" + }, + "amountOut": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rate": { + "optional": false, + "readonly": false, + "type": "number" + }, + "route": { + "optional": true, + "readonly": false, + "type": "string[] | undefined" + }, + "timestamp": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "UniversalSigner": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalSigner", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "signAndSendTransaction": { + "optional": false, + "readonly": false, + "type": "(unsignedTx: Uint8Array) => Promise" + }, + "signAuthorization": { + "optional": true, + "readonly": false, + "type": "((params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise) | undefined" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": true, + "readonly": false, + "type": "(({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise) | undefined" + } + } + }, + "UniversalAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "UniversalSignerSkeleton": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "signAndSendTransaction": { + "optional": false, + "readonly": false, + "type": "(unsignedTx: Uint8Array) => Promise" + }, + "signAuthorization": { + "optional": true, + "readonly": false, + "type": "((params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise) | undefined" + }, + "signerId": { + "optional": false, + "readonly": false, + "type": "string" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": true, + "readonly": false, + "type": "(({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise) | undefined" + } + } + }, + "SignAuthorizationParams": { + "type": "{\n chainId?: number;\n contractAddress: `0x${string}`;\n executor?: \"self\";\n nonce?: number;\n}", + "members": { + "chainId": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "contractAddress": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "executor": { + "optional": true, + "readonly": false, + "type": "\"self\" | undefined" + }, + "nonce": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "SignedAuthorization": { + "type": "{\n address: `0x${string}`;\n chainId: number;\n nonce: number;\n r: `0x${string}`;\n s: `0x${string}`;\n v?: bigint;\n yParity: number;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainId": { + "optional": false, + "readonly": false, + "type": "number" + }, + "nonce": { + "optional": false, + "readonly": false, + "type": "number" + }, + "r": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "s": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "v": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "yParity": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "DerivedExecutorAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").DerivedExecutorAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean | null" + } + } + }, + "ResolvedAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainName": { + "optional": false, + "readonly": false, + "type": "string" + }, + "exists": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "role": { + "optional": true, + "readonly": false, + "type": "\"controller\" | undefined" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"cea\" | \"uea\" | \"uoa\"" + } + } + }, + "ResolvedControllerAccounts": { + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedControllerAccounts", + "members": { + "accounts": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedAccount[]" + } + } + }, + "AccountType": { + "type": "\"cea\" | \"uea\" | \"uoa\"", + "members": {} + }, + "AccountRole": { + "type": "\"controller\"", + "members": {} + }, + "PC20TokenReference": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "FundsToken": { + "type": "import(\"sdk/src/lib/constants/tokens\").MoveableToken | import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20TokenReference", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "PC20RegistryEntry": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "chainName": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "PC20AddressResult": { + "type": "{\n address: `0x${string}`;\n decimals: number;\n name: string;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n registry: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20RegistryEntry[];\n symbol: string;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "decimals": { + "optional": false, + "readonly": false, + "type": "number" + }, + "name": { + "optional": false, + "readonly": false, + "type": "string" + }, + "network": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "registry": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20RegistryEntry[]" + }, + "symbol": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "isPC20Reference": { + "type": "(token: import(\"sdk/src/lib/orchestrator/orchestrator.types\").FundsToken | undefined) => token is import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20TokenReference", + "members": {} + }, + "PC20Error": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20Error", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidPC20AddressError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InvalidPC20AddressError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20TokenChainMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20TokenChainMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20WrapperNotRegisteredError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20WrapperNotRegisteredError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20RegistryMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20RegistryMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20FactoryMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20FactoryMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidPC20MetadataError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InvalidPC20MetadataError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20ExpectedButPRC20Error": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20ExpectedButPRC20Error", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20AmbiguousAddressError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20AmbiguousAddressError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "candidates": { + "optional": false, + "readonly": true, + "type": "{\n chain: string;\n pushAddress: string;\n}[]" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "UnsupportedPC20DestinationError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").UnsupportedPC20DestinationError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InsufficientPC20BalanceError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InsufficientPC20BalanceError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20UnknownChainNamespaceError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20UnknownChainNamespaceError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20WrapperPredictionUnavailableError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20WrapperPredictionUnavailableError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20ExportRevertedError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20ExportRevertedError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "lockedAmount": { + "optional": true, + "readonly": true, + "type": "bigint | undefined" + }, + "outboundTxId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "revertRecipient": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20UnsafeEmptyPayloadError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20UnsafeEmptyPayloadError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ChainTarget": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "ChainSource": { + "type": "{\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "UniversalTo": { + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget", + "members": {} + }, + "TransactionRouteType": { + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"", + "members": {} + }, + "UniversalExecuteParams": { + "type": "{\n from?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainSource;\n migration?: boolean;\n to: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTo;\n} & Omit", + "members": { + "_minimumDepositUsd": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "_requiredFundsOverride": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "_skipFeeLocking": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "_ueaStatus": { + "optional": true, + "readonly": false, + "type": "{\n balance: bigint;\n isDeployed: boolean;\n nonce: bigint;\n} | undefined" + }, + "data": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiCall[] | undefined" + }, + "deadline": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "feeLockTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "from": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainSource | undefined" + }, + "funds": { + "optional": true, + "readonly": false, + "type": "{\n amount: bigint;\n token?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").FundsToken;\n} | undefined" + }, + "gasLimit": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFeePerGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxPCForGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxPriorityFeePerGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "migration": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "nonce": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "options": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions | undefined" + }, + "payGasWith": { + "optional": true, + "readonly": false, + "type": "{\n minAmountOut?: bigint | string;\n slippageBps?: number;\n token?: import(\"sdk/src/lib/constants/tokens\").PayableToken;\n} | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "to": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget" + }, + "value": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "UniversalOutboundTxRequest": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalOutboundTxRequest", + "members": { + "amount": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gasPrice": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxPCForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "payload": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "recipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "revertRecipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "PreparedUniversalTx": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx", + "members": { + "_hop": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").HopDescriptor" + }, + "deadline": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "estimatedGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gatewayRequest": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalOutboundTxRequest | import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxRequest" + }, + "nonce": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "payload": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + } + } + }, + "CascadedTxResponse": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadedTxResponse", + "members": { + "finalTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hopCount": { + "optional": false, + "readonly": false, + "type": "number" + }, + "hops": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo[]" + }, + "initialTxHash": { + "optional": false, + "readonly": false, + "type": "string" + }, + "initialTxResponse": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions) => Promise" + }, + "waitForAll": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions) => Promise" + } + } + }, + "CascadeHopInfo": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo", + "members": { + "executionChain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "expectedSubTxId": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hopIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "outboundDetails": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").OutboundTxDetails | undefined" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + }, + "status": { + "optional": false, + "readonly": false, + "type": "\"confirmed\" | \"failed\" | \"pending\" | \"submitted\"" + }, + "txHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "CascadeTrackOptions": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions", + "members": { + "eventHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeProgressEvent) => void) | undefined" + }, + "timeout": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "CascadeProgressEvent": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeProgressEvent", + "members": { + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "elapsed": { + "optional": false, + "readonly": false, + "type": "number" + }, + "hopIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + }, + "status": { + "optional": false, + "readonly": false, + "type": "\"confirmed\" | \"failed\" | \"found\" | \"polling\" | \"timeout\" | \"waiting\"" + }, + "txHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "CascadeCompletionResult": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeCompletionResult", + "members": { + "failedAt": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "finalTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "finalTxResponse": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadedTxResponse | undefined" + }, + "hops": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo[]" + }, + "success": { + "optional": false, + "readonly": false, + "type": "boolean" + } + } + }, + "MultiChainTxResponse": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiChainTxResponse", + "members": { + "chains": { + "optional": false, + "readonly": false, + "type": "{\n blockNumber: bigint;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n hash: string;\n status: \"confirmed\" | \"failed\" | \"pending\";\n}[]" + }, + "transactions": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse[]" + } + } + }, + "OutboundTxDetails": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").OutboundTxDetails", + "members": { + "amount": { + "optional": false, + "readonly": false, + "type": "string" + }, + "assetAddr": { + "optional": false, + "readonly": false, + "type": "string" + }, + "destinationChain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "explorerUrl": { + "optional": false, + "readonly": false, + "type": "string" + }, + "externalTxHash": { + "optional": false, + "readonly": false, + "type": "string" + }, + "recipient": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "WaitForOutboundOptions": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").WaitForOutboundOptions", + "members": { + "_expectedDestinationChain": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "_outboundIndex": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "_resolvedSubTxId": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "initialWaitMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: {\n elapsed: number;\n status: \"failed\" | \"found\" | \"polling\" | \"timeout\" | \"waiting\";\n}) => void) | undefined" + }, + "timeout": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "SvmGatewayAccountMeta": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmGatewayAccountMeta", + "members": { + "isWritable": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "pubkey": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "SvmExecutePayloadFields": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmExecutePayloadFields", + "members": { + "accounts": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmGatewayAccountMeta[]" + }, + "instructionId": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "ixData": { + "optional": false, + "readonly": false, + "type": "Uint8Array" + }, + "targetProgram": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AccountStatus": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus", + "members": { + "mode": { + "optional": false, + "readonly": false, + "type": "\"read-only\" | \"signer\"" + }, + "uea": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UEAStatus" + } + } + }, + "UEAStatus": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UEAStatus", + "members": { + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "loaded": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "minRequiredVersion": { + "optional": false, + "readonly": false, + "type": "string" + }, + "requiresUpgrade": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "version": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "RescueFundsParams": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").RescueFundsParams", + "members": { + "prc20": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "universalTxId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "parseUEAVersion": { + "type": "(version: string) => number", + "members": {} + }, + "TransactionRoute": { + "type": "typeof import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute", + "members": { + "CEA_TO_CEA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.CEA_TO_CEA" + }, + "CEA_TO_PUSH": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.CEA_TO_PUSH" + }, + "UOA_TO_CEA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.UOA_TO_CEA" + }, + "UOA_TO_PUSH": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.UOA_TO_PUSH" + } + } + }, + "detectRoute": { + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams) => import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute", + "members": {} + }, + "isChainTarget": { + "type": "(to: unknown) => to is import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget", + "members": {} + }, + "DEFAULT_MAX_PC_FOR_GAS_BUFFER_BPS": { + "type": "1000", + "members": {} + }, + "MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT": { + "type": "10000", + "members": {} + }, + "quoteMaxPCForGasCap": { + "type": "(input: import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapInput) => import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": {} + }, + "quoteMaxPCForGasCapFromNativeValue": { + "type": "(input: import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapFromNativeValueInput) => import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": {} + }, + "MaxPCForGasCapInput": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapInput", + "members": { + "bufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "gasLegNativePc": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "MaxPCForGasCapFromNativeValueInput": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapFromNativeValueInput", + "members": { + "bufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "nativeValueForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "MaxPCForGasCapQuote": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": { + "bufferBps": { + "optional": false, + "readonly": false, + "type": "number" + }, + "gasLegNativePc": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxPCForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "nativeValueForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "getCEAAddress": { + "type": "(ueaAddress: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise", + "members": {} + }, + "getPushAccountForCEA": { + "type": "(ceaAddress: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise<`0x${string}`>", + "members": {} + }, + "isCEA": { + "type": "(address: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise", + "members": {} + }, + "chainSupportsCEA": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "chainSupportsOutbound": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "getCEAFactoryAddress": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => `0x${string}` | undefined", + "members": {} + }, + "getAllCEAAddresses": { + "type": "(ueaAddress: `0x${string}`, rpcUrls?: Partial>) => Promise", + "members": {} + }, + "encodeSvmExecutePayload": { + "type": "(fields: import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmExecutePayloadFields) => `0x${string}`", + "members": {} + }, + "isSvmChain": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "isValidSolanaHexAddress": { + "type": "(address: string) => boolean", + "members": {} + }, + "buildMigrationPayload": { + "type": "() => `0x${string}`", + "members": {} + }, + "buildErc20WithdrawalMulticall": { + "type": "(tokenAddress: `0x${string}`, recipientAddress: `0x${string}`, amount: bigint) => import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiCall[]", + "members": {} + }, + "ReadChain": { + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain", + "members": {} + }, + "ReadDestination": { + "type": "{\n chain: import(\"sdk/src/lib/read-state/read-state.types\").ReadChain;\n} | {\n chainId: string;\n chainNamespace: string;\n}", + "members": {} + }, + "ResolvedDestination": { + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}", + "members": { + "caip2": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainId": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "namespace": { + "optional": false, + "readonly": false, + "type": "\"eip155\" | \"solana\" | \"web2\"" + } + } + }, + "ReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").SvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery", + "members": { + "type": { + "optional": false, + "readonly": false, + "type": "\"accountBalance\" | \"contractCall\" | \"http\" | \"lamportBalance\" | \"rawAccountData\" | \"splTokenAccount\" | \"storageSlot\"" + } + } + }, + "EvmReadQuery": { + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n target: `0x${string}`;\n type: \"contractCall\";\n} | {\n callData: `0x${string}`;\n target: `0x${string}`;\n type: \"contractCall\";\n} | {\n slot: `0x${string}` | bigint;\n target: `0x${string}`;\n type: \"storageSlot\";\n} | {\n target: `0x${string}`;\n type: \"accountBalance\";\n}", + "members": { + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"accountBalance\" | \"contractCall\" | \"storageSlot\"" + } + } + }, + "SvmReadQuery": { + "type": "{\n account: string | Uint8Array;\n accountName?: string;\n idl?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n type: \"rawAccountData\";\n} | {\n account: string | Uint8Array;\n type: \"lamportBalance\";\n} | {\n account: string | Uint8Array;\n type: \"splTokenAccount\";\n}", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "string | Uint8Array" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"lamportBalance\" | \"rawAccountData\" | \"splTokenAccount\"" + } + } + }, + "Web2ReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery", + "members": { + "body": { + "optional": true, + "readonly": false, + "type": "string | Uint8Array | undefined" + }, + "extract": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[]" + }, + "headers": { + "optional": true, + "readonly": false, + "type": "Record | undefined" + }, + "method": { + "optional": true, + "readonly": false, + "type": "\"GET\" | \"POST\" | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"http\"" + }, + "url": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "Web2Extract": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract", + "members": { + "decimals": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "path": { + "optional": false, + "readonly": false, + "type": "string" + }, + "valueType": { + "optional": false, + "readonly": false, + "type": "\"bool\" | \"bytes\" | \"int256\" | \"string\" | \"uint256\"" + } + } + }, + "Web2ValueType": { + "type": "\"bool\" | \"bytes\" | \"int256\" | \"string\" | \"uint256\"", + "members": {} + }, + "EncodedReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery", + "members": { + "blockRef": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "encoded": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "namespace": { + "optional": false, + "readonly": false, + "type": "\"eip155\" | \"solana\" | \"web2\"" + }, + "ownerBytes": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "queryType": { + "optional": false, + "readonly": false, + "type": "number" + }, + "resultShape": { + "optional": false, + "readonly": false, + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}" + }, + "warnings": { + "optional": false, + "readonly": false, + "type": "string[]" + } + } + }, + "ReadResultShape": { + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"bytes32\" | \"evmCall\" | \"raw\" | \"svmAccount\" | \"uint256\" | \"web2\"" + } + } + }, + "DecodedReadResult": { + "type": "{\n accountName: string;\n kind: \"svmAccount\";\n value: unknown;\n} | {\n kind: \"bytes32\";\n value: `0x${string}`;\n} | {\n kind: \"evmCall\";\n value: unknown;\n} | {\n kind: \"raw\";\n value: `0x${string}`;\n} | {\n kind: \"uint256\";\n value: bigint;\n} | {\n kind: \"web2\";\n values: readonly unknown[];\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"bytes32\" | \"evmCall\" | \"raw\" | \"svmAccount\" | \"uint256\" | \"web2\"" + } + } + }, + "ReadPreflight": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight", + "members": { + "destination": { + "optional": false, + "readonly": false, + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}" + }, + "fetchedAt": { + "optional": false, + "readonly": false, + "type": "number" + }, + "observedChainHeight": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pushBlockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pushGasPrice": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "universalCallback": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "universalCore": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ReadSpec": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "{\n chainId: string;\n chainNamespace: string;\n owner: `0x${string}`;\n}" + }, + "blockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "expiryPushChainHeight": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "minConfirmations": { + "optional": false, + "readonly": false, + "type": "number" + }, + "query": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "revertRecipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ReadSpecTuple": { + "type": "readonly [\n readonly [\n string,\n string,\n `0x${string}`\n ],\n `0x${string}`,\n number,\n bigint,\n bigint,\n bigint,\n `0x${string}`\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "readonly [\n string,\n string,\n `0x${string}`\n]" + }, + "1": { + "optional": false, + "readonly": true, + "type": "`0x${string}`" + }, + "2": { + "optional": false, + "readonly": true, + "type": "number" + }, + "3": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "4": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "5": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "6": { + "optional": false, + "readonly": true, + "type": "`0x${string}`" + }, + "length": { + "optional": false, + "readonly": true, + "type": "7" + } + } + }, + "BuildReadSpecParams": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").BuildReadSpecParams", + "members": { + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "budgetBuffer": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback | undefined" + }, + "callbackBudget": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "destination": { + "optional": false, + "readonly": false, + "type": "{\n chain: import(\"sdk/src/lib/read-state/read-state.types\").ReadChain;\n} | {\n chainId: string;\n chainNamespace: string;\n}" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "expiryPushChainHeight": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFeeBufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "owner": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "query": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").SvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "PreparedRead": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead", + "members": { + "__@preparedReadValue": { + "optional": true, + "readonly": true, + "type": "T | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback | undefined" + }, + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "encodedQuery": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery" + }, + "encodedSpec": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "fees": { + "optional": false, + "readonly": false, + "type": "{\n callbackBudget: bigint;\n protocolFee: bigint;\n total: bigint;\n}" + }, + "preflight": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "queryKey": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "resultShape": { + "optional": false, + "readonly": false, + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}" + }, + "spec": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec" + }, + "specTuple": { + "optional": false, + "readonly": false, + "type": "readonly [\n readonly [\n string,\n string,\n `0x${string}`\n ],\n `0x${string}`,\n number,\n bigint,\n bigint,\n bigint,\n `0x${string}`\n]" + }, + "value": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "warnings": { + "optional": false, + "readonly": false, + "type": "string[]" + } + } + }, + "ReadCallback": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "((spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpecTuple, callbackGasLimit: bigint) => readonly unknown[]) | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "gasLimit": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "target": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "SimulateReadResult": { + "type": "{\n args?: readonly unknown[];\n error: string;\n errorName?: string;\n ok: false;\n} | {\n ok: true;\n}", + "members": { + "ok": { + "optional": false, + "readonly": false, + "type": "boolean" + } + } + }, + "ParsedReadRequest": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ParsedReadRequest", + "members": { + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackTarget": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "logIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "originalFunder": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "requestId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "requestIdUint": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "spec": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec" + }, + "totalPaid": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "FulfilOutcome": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").FulfilOutcome", + "members": { + "burned": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "delivered": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "expired": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "failReason": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "gasReported": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refunded": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refundFailed": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "ReceiptLike": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike", + "members": { + "logs": { + "optional": false, + "readonly": false, + "type": "readonly {\n address: string;\n data: string;\n logIndex?: number | string;\n topics: readonly string[];\n}[]" + } + } + }, + "ReadRef": { + "type": "{\n requestId: `0x${string}` | bigint;\n} | {\n txHash: `0x${string}`;\n}", + "members": {} + }, + "ReadLifecycleOptions": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadLifecycleOptions", + "members": { + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "resultShape": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadFees": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadFees", + "members": { + "burned": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "paid": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "refunded": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refundFailed": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + } + } + }, + "UniversalReadResponse": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse", + "members": { + "callbackDelivered": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "callbackFailReason": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "decoded": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").DecodedReadResult | undefined" + }, + "decodeError": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destination": { + "optional": false, + "readonly": false, + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}" + }, + "errorMsg": { + "optional": false, + "readonly": false, + "type": "string" + }, + "explorerUrl": { + "optional": false, + "readonly": false, + "type": "string" + }, + "fees": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadFees" + }, + "isTerminal": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "outcome": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME" + }, + "pcTx": { + "optional": false, + "readonly": false, + "type": "readonly {\n blockHeight: number;\n errorMsg: string;\n status: string;\n txHash: `0x${string}`;\n}[]" + }, + "raw": { + "optional": false, + "readonly": false, + "type": "{\n errorCode: import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n resultData: `0x${string}`;\n status: import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n} | null" + }, + "refresh": { + "optional": false, + "readonly": false, + "type": "() => Promise>" + }, + "request": { + "optional": false, + "readonly": false, + "type": "{\n callbackGasLimit: bigint;\n callbackTarget: `0x${string}`;\n createdAtHeight: bigint;\n logIndex: number;\n originalFunder: `0x${string}`;\n refundTo: `0x${string}`;\n spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec;\n}" + }, + "requestId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "requestIdUint": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "status": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "value": { + "optional": true, + "readonly": false, + "type": "T | undefined" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/read-state/read-state.types\").ReadLifecycleOptions) => Promise>" + } + } + }, + "ReadResponseTuple": { + "type": "{\n -readonly [K in keyof R]: import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse ? T : unknown>;\n}", + "members": {} + }, + "BatchReadResponse": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").BatchReadResponse", + "members": { + "atomic": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "count": { + "optional": false, + "readonly": false, + "type": "number" + }, + "reads": { + "optional": false, + "readonly": false, + "type": "{\n -readonly [K in keyof R]: import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse ? T : unknown>;\n}" + }, + "transactionHashes": { + "optional": true, + "readonly": false, + "type": "readonly `0x${string}`[] | undefined" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: Omit) => Promise>" + } + } + }, + "ReadOptions": { + "type": "((import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">)) & {\n callback?: (Pick & Required>) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n };\n}", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "advanced": { + "optional": true, + "readonly": false, + "type": "{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n} | undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "({\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} & {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n}) | ({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick & Pick & Required>) | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadPrepareOptions": { + "type": "((((({\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\">) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n}) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">)) & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n}) | ((({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n}) | ({\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\">)) & {\n blockNumber?: never;\n minConfirmations?: never;\n})) & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n}) & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "advanced": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadQueryOptions": { + "type": "({\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\">) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n}) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n}) | ({\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\">)", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadCallbackOptions": { + "type": "{\n callback?: ({\n gasLimit?: bigint;\n target: `0x${string}`;\n } & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n };\n}", + "members": { + "callback": { + "optional": true, + "readonly": false, + "type": "({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} | undefined" + } + } + }, + "ReadValue": { + "type": "O extends {\n abi: infer A extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: infer F extends string;\n} ? number extends A[\"length\"] ? unknown : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, O extends {\n args: infer Args extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n} ? Args : readonly [\n] extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> ? import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> & readonly [\n] : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>> extends infer Selected ? Selected extends {\n outputs: readonly unknown[];\n type: \"function\";\n} & import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiFunction ? {\n [key in keyof {\n [key in keyof import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"]]: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterToPrimitiveType, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"][key], import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterKind>;\n }]: {\n [key in keyof import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"]]: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterToPrimitiveType, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"][key], import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterKind>;\n }[key];\n} extends infer types ? types extends readonly [\n] ? void : types extends readonly [\n infer type\n] ? type : types : never : never : never : O extends {\n web2: {\n extract: infer E extends readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n };\n} ? {\n readonly [K in keyof E]: {\n bool: boolean;\n bytes: `0x${string}`;\n int256: bigint;\n string: string;\n uint256: bigint;\n }[E[K][\"valueType\"]];\n} : O extends {\n storageSlot: unknown;\n} ? `0x${string}` : O extends {\n idl: infer I extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} ? string extends Extract, string> ? unknown : (O extends {\n functionName: infer N extends string;\n} ? N : undefined) extends string ? import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/index\").IdlAccounts[{\n [K in Extract, string>]: Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : K> extends Lowercase<(O extends {\n functionName: infer N extends string;\n } ? N : undefined) & string extends `${infer H}_${infer T}` ? `${H}${Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : (O extends {\n functionName: infer N extends string;\n } ? N : undefined) & string> ? K : never;\n}[Extract, string>]] : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/index\").IdlAccounts[Extract, string>] : bigint", + "members": {} + }, + "ValidateReadCall": { + "type": "O extends {\n abi: infer A extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: infer F extends string;\n} ? (readonly [\n] extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> ? {\n args?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n} : {\n args: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n}) & {\n functionName: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionName;\n} : O extends {\n functionName: infer N extends string;\n idl: infer I extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} ? string extends Extract, string> ? unknown : [\n {\n [K in Extract, string>]: Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : K> extends Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : N> ? K : never;\n }[Extract, string>]\n] extends [\n never\n] ? {\n functionName: Extract, string>;\n} : unknown : unknown", + "members": {} + }, + "ReadWeb2Options": { + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options", + "members": { + "body": { + "optional": true, + "readonly": false, + "type": "string | Uint8Array | undefined" + }, + "extract": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[]" + }, + "headers": { + "optional": true, + "readonly": false, + "type": "Record | undefined" + }, + "method": { + "optional": true, + "readonly": false, + "type": "\"GET\" | \"POST\" | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadTrackOptions": { + "type": "{\n advanced?: Omit, \"enforceGasCheck\">;\n resultShape?: import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape;\n}", + "members": { + "advanced": { + "optional": true, + "readonly": false, + "type": "Omit<{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n}, \"enforceGasCheck\"> | undefined" + }, + "resultShape": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape | undefined" + } + } + }, + "ReadExecuteOptions": { + "type": "{\n advanced?: {\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n } | undefined;\n progressHook?: ((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined;\n waitForCompletion?: boolean | undefined;\n}", + "members": { + "advanced": { + "optional": true, + "readonly": false, + "type": "{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n} | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + } + } + }, + "UNIVERSAL_READ_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS", + "members": { + "ABORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.ABORTED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.EXPIRED" + }, + "FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.FAILED" + }, + "FULFILLED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.FULFILLED" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.PENDING" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.UNSPECIFIED" + }, + "VOTING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.VOTING" + } + } + }, + "READ_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS", + "members": { + "ERROR": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.ERROR" + }, + "SUCCESS": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.SUCCESS" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.UNSPECIFIED" + } + } + }, + "READ_ERROR_CODE": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE", + "members": { + "INVALID_QUERY": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.INVALID_QUERY" + }, + "INVALID_RESULT": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.INVALID_RESULT" + }, + "NOT_FOUND": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.NOT_FOUND" + }, + "REJECTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.REJECTED" + }, + "REVERTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.REVERTED" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.UNSPECIFIED" + }, + "UNSUPPORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.UNSUPPORTED" + } + } + }, + "READ_OUTCOME": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME", + "members": { + "ABORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.ABORTED" + }, + "CALLBACK_FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.CALLBACK_FAILED" + }, + "DECODE_FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.DECODE_FAILED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.EXPIRED" + }, + "FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.FAILED" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.PENDING" + }, + "SOURCE_ERROR": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.SOURCE_ERROR" + }, + "SUCCESS": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.SUCCESS" + }, + "UNKNOWN": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.UNKNOWN" + } + } + }, + "CONTRACT_REQUEST_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS", + "members": { + "EXECUTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.EXECUTED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.EXPIRED" + }, + "NONE": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.NONE" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.PENDING" + }, + "SETTLED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.SETTLED" + } + } + }, + "TERMINAL_READ_STATUSES": { + "type": "ReadonlySet", + "members": {} + }, + "ReadStateError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadStateError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidReadQueryError": { + "type": "import(\"sdk/src/lib/read-state/errors\").InvalidReadQueryError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidReadSpecError": { + "type": "import(\"sdk/src/lib/read-state/errors\").InvalidReadSpecError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "violations": { + "optional": false, + "readonly": true, + "type": "readonly import(\"sdk/src/lib/read-state/errors\").ReadSpecViolation[]" + } + } + }, + "ReadHeightUnavailableError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadHeightUnavailableError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "UnsupportedReadDestinationError": { + "type": "import(\"sdk/src/lib/read-state/errors\").UnsupportedReadDestinationError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadDecodeError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadDecodeError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadTimeoutError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadTimeoutError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "lastStatus": { + "optional": false, + "readonly": true, + "type": "number" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadNotFoundError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadNotFoundError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadRegistryUnavailableError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadRegistryUnavailableError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadSpecViolation": { + "type": "\"CALLBACK_GAS_LIMIT_EXCEEDED\" | \"DOMAIN_BLOCKED\" | \"EMPTY_QUERY\" | \"EXCESSIVE_FEE\" | \"INSUFFICIENT_CALLBACK_BUDGET\" | \"INSUFFICIENT_FEE\" | \"INVALID_ACCOUNT_ID\" | \"INVALID_BLOCK_NUMBER\" | \"INVALID_EXPIRY_HEIGHT\" | \"INVALID_MIN_CONFIRMATIONS\" | \"SVM_OWNER_NOT_32_BYTES\" | \"ZERO_CALLBACK_BUDGET\" | \"ZERO_CALLBACK_GAS_LIMIT\" | \"ZERO_REVERT_RECIPIENT\"", + "members": {} + }, + "resolveDestination": { + "type": "(dest: import(\"sdk/src/lib/read-state/read-state.types\").ReadDestination) => import(\"sdk/src/lib/read-state/read-state.types\").ResolvedDestination", + "members": {} + }, + "encodeReadQuery": { + "type": "(destination: import(\"sdk/src/lib/read-state/read-state.types\").ReadDestination, query: import(\"sdk/src/lib/read-state/read-state.types\").ReadQuery, options?: {\n blockNumber?: bigint;\n minSlot?: bigint;\n}) => import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery", + "members": {} + }, + "decodeReadResult": { + "type": "(resultData: `0x${string}`, shape: import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape) => import(\"sdk/src/lib/read-state/read-state.types\").DecodedReadResult", + "members": {} + }, + "parseReadRequestsFromReceipt": { + "type": "(receipt: import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike, universalCallback: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").ParsedReadRequest[]", + "members": {} + }, + "parseFulfilOutcome": { + "type": "(receipt: import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike, universalCallback: `0x${string}`, requestId: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").FulfilOutcome", + "members": {} + }, + "buildReadSpecFromPreflight": { + "type": "(preflight: import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight, params: import(\"sdk/src/lib/read-state/read-state.types\").BuildReadSpecParams, defaults?: {\n refundTo?: `0x${string}`;\n}) => import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead", + "members": {} + }, + "validateReadSpec": { + "type": "(input: import(\"sdk/src/lib/read-state/validate\").ValidateReadSpecInput) => {\n ok: false;\n violations: import(\"sdk/src/lib/read-state/errors\").ReadSpecViolation[];\n} | {\n ok: true;\n}", + "members": {} + }, + "toCallData": { + "type": "(prepared: import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead, target: {\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: (spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpecTuple, callbackGasLimit: bigint) => readonly unknown[];\n functionName: string;\n}) => {\n data: `0x${string}`;\n value: bigint;\n}", + "members": {} + }, + "sizeCallbackBudget": { + "type": "(callbackGasLimit: bigint, pushGasPrice: bigint, buffer?: number) => bigint", + "members": {} + }, + "inferResultShape": { + "type": "(namespace: string, query: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape", + "members": {} + }, + "toRequestIdHex": { + "type": "(id: `0x${string}` | bigint) => `0x${string}`", + "members": {} + }, + "toReadQuery": { + "type": "(subject: string, o: ReadOptionsInput, resolvedTokenProgram?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@solana/web3.js/lib/index\").PublicKey) => import(\"sdk/src/lib/read-state/read-state.types\").ReadQuery", + "members": {} + }, + "UNIVERSAL_CALLBACK_EVM": { + "type": "readonly [\n {\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"requestExternalReadSelf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"estimateFee\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"statusOf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"enum RequestStatus\";\n readonly name: \"\";\n readonly type: \"uint8\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"isFulfilled\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getPendingRead\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly internalType: \"struct PendingRead\";\n readonly name: \"\";\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"totalEscrowed\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"blockedDomains\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly indexed: false;\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"readSpec\";\n readonly type: \"tuple\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"totalPaid\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"protocolFee\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ReadRequested\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"ReadFulfilled\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"reason\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"CallbackFailed\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"gasReported\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"burned\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"CallbackGasReported\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundSent\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundFailed\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RequestExpired\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"vaultPC\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ProtocolFeeDistributed\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidAccountId\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"EmptyQuery\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidMinConfirmations\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"DomainBlocked\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidBlockNumber\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidExpiryHeight\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroRevertRecipient\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroCallbackGasLimit\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint64\";\n readonly name: \"provided\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"max\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"CallbackGasLimitExceeded\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"required\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"InsufficientFee\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ExcessiveFee\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"actual\";\n readonly type: \"uint8\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"expected\";\n readonly type: \"uint8\";\n }\n ];\n readonly name: \"InvalidRequestStatus\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ContractIsPaused\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"CallerIsNotUCallbackModule\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n }\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"requestExternalReadSelf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n}" + }, + "1": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"estimateFee\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "2": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"statusOf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"enum RequestStatus\";\n readonly name: \"\";\n readonly type: \"uint8\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "3": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"isFulfilled\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "4": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getPendingRead\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly internalType: \"struct PendingRead\";\n readonly name: \"\";\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "5": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"totalEscrowed\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "6": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"blockedDomains\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "7": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly indexed: false;\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"readSpec\";\n readonly type: \"tuple\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"totalPaid\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"protocolFee\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ReadRequested\";\n readonly type: \"event\";\n}" + }, + "8": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"ReadFulfilled\";\n readonly type: \"event\";\n}" + }, + "9": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"reason\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"CallbackFailed\";\n readonly type: \"event\";\n}" + }, + "10": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"gasReported\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"burned\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"CallbackGasReported\";\n readonly type: \"event\";\n}" + }, + "11": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundSent\";\n readonly type: \"event\";\n}" + }, + "12": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundFailed\";\n readonly type: \"event\";\n}" + }, + "13": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RequestExpired\";\n readonly type: \"event\";\n}" + }, + "14": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"vaultPC\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ProtocolFeeDistributed\";\n readonly type: \"event\";\n}" + }, + "15": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidAccountId\";\n readonly type: \"error\";\n}" + }, + "16": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"EmptyQuery\";\n readonly type: \"error\";\n}" + }, + "17": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidMinConfirmations\";\n readonly type: \"error\";\n}" + }, + "18": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"DomainBlocked\";\n readonly type: \"error\";\n}" + }, + "19": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidBlockNumber\";\n readonly type: \"error\";\n}" + }, + "20": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidExpiryHeight\";\n readonly type: \"error\";\n}" + }, + "21": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroRevertRecipient\";\n readonly type: \"error\";\n}" + }, + "22": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroCallbackGasLimit\";\n readonly type: \"error\";\n}" + }, + "23": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint64\";\n readonly name: \"provided\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"max\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"CallbackGasLimitExceeded\";\n readonly type: \"error\";\n}" + }, + "24": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"required\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"InsufficientFee\";\n readonly type: \"error\";\n}" + }, + "25": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ExcessiveFee\";\n readonly type: \"error\";\n}" + }, + "26": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"actual\";\n readonly type: \"uint8\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"expected\";\n readonly type: \"uint8\";\n }\n ];\n readonly name: \"InvalidRequestStatus\";\n readonly type: \"error\";\n}" + }, + "27": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ContractIsPaused\";\n readonly type: \"error\";\n}" + }, + "28": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"CallerIsNotUCallbackModule\";\n readonly type: \"error\";\n}" + }, + "29": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n}" + }, + "length": { + "optional": false, + "readonly": true, + "type": "30" + } + } + }, + "UNIVERSAL_READ_REGISTRY_EVM": { + "type": "readonly [\n {\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n },\n {\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"read\";\n readonly outputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"universalCallback_\";\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"constructor\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"initialize\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getLocalContext\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"hasResult\";\n readonly outputs: readonly [\n {\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"onUniversalData\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"queryKeyOf\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes32\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"readerOf\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"requestOrderOf\";\n readonly outputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"universalCallback\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"resultByRequestId\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"latestResult\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"version\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"Initialized\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadRequested\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadStored\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidInitialization\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"NotInitializing\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroAddressInit\";\n readonly type: \"error\";\n }\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n },\n {\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"read\";\n readonly outputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n}" + }, + "1": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"universalCallback_\";\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"constructor\";\n}" + }, + "2": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"initialize\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n}" + }, + "3": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getLocalContext\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "4": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"hasResult\";\n readonly outputs: readonly [\n {\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "5": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"onUniversalData\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n}" + }, + "6": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"queryKeyOf\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes32\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "7": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"readerOf\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "8": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"requestOrderOf\";\n readonly outputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "9": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"universalCallback\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "10": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"resultByRequestId\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "11": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"latestResult\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "12": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"version\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"Initialized\";\n readonly type: \"event\";\n}" + }, + "13": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadRequested\";\n readonly type: \"event\";\n}" + }, + "14": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadStored\";\n readonly type: \"event\";\n}" + }, + "15": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidInitialization\";\n readonly type: \"error\";\n}" + }, + "16": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"NotInitializing\";\n readonly type: \"error\";\n}" + }, + "17": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n}" + }, + "18": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroAddressInit\";\n readonly type: \"error\";\n}" + }, + "length": { + "optional": false, + "readonly": true, + "type": "19" + } + } + }, + "PushChainExecutionError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").PushChainExecutionError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PushChainBatchExecutionError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").PushChainBatchExecutionError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": false, + "readonly": true, + "type": "`0x${string}`[]" + } + } + }, + "DecodedErrorPayload": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload", + "members": { + "decoded": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "name": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "selector": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "PushChainInitializeOptions": { + "type": "import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions", + "members": { + "agenticWallet": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "blockExplorers": { + "optional": true, + "readonly": false, + "type": "Partial> | undefined" + }, + "network": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "printTraces": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "rpcUrls": { + "optional": true, + "readonly": false, + "type": "Partial> | undefined" + } + } + }, + "AGENTIC_ERROR_CODE": { + "type": "{\n readonly AGENT_GAS_INSUFFICIENT: \"AGENT_GAS_INSUFFICIENT\";\n readonly AGENT_IS_OWNER: \"AGENT_IS_OWNER\";\n readonly ASSET_CHAIN_MISMATCH: \"ASSET_CHAIN_MISMATCH\";\n readonly CAPABILITY_UNAVAILABLE: \"CAPABILITY_UNAVAILABLE\";\n readonly CREATE_PARTIAL: \"CREATE_PARTIAL\";\n readonly DUPLICATE_RULE: \"DUPLICATE_RULE\";\n readonly FROM_NOT_ALLOWED: \"FROM_NOT_ALLOWED\";\n readonly GATEWAY_ALLOWANCE_INSUFFICIENT: \"GATEWAY_ALLOWANCE_INSUFFICIENT\";\n readonly GENERATION_UNSUPPORTED: \"GENERATION_UNSUPPORTED\";\n readonly INCONSISTENT_READ: \"INCONSISTENT_READ\";\n readonly INDEX_RACE: \"INDEX_RACE\";\n readonly INVALID_RULE: \"INVALID_RULE\";\n readonly NO_RULES_FOR_CHAIN: \"NO_RULES_FOR_CHAIN\";\n readonly NOT_AGENTIC_WALLET: \"NOT_AGENTIC_WALLET\";\n readonly NOT_ALLOWED_IN_AGENTIC_MODE: \"NOT_ALLOWED_IN_AGENTIC_MODE\";\n readonly NOT_OWNER_OR_AGENT: \"NOT_OWNER_OR_AGENT\";\n readonly NOT_WALLET_OWNER: \"NOT_WALLET_OWNER\";\n readonly READ_ONLY: \"READ_ONLY\";\n readonly RECEIPT_MISMATCH: \"RECEIPT_MISMATCH\";\n readonly RECEIPT_UNAVAILABLE: \"RECEIPT_UNAVAILABLE\";\n readonly REVOKE_NEEDS_TARGET: \"REVOKE_NEEDS_TARGET\";\n readonly RULE_LIMIT_EXCEEDED: \"RULE_LIMIT_EXCEEDED\";\n readonly RULE_NOT_FOUND: \"RULE_NOT_FOUND\";\n readonly RULE_READ_FAILED: \"RULE_READ_FAILED\";\n readonly TARGET_NOT_ON_RULE_CHAIN: \"TARGET_NOT_ON_RULE_CHAIN\";\n readonly WALLET_BALANCE_INSUFFICIENT: \"WALLET_BALANCE_INSUFFICIENT\";\n readonly WALLET_NOT_DEPLOYED: \"WALLET_NOT_DEPLOYED\";\n}", + "members": { + "AGENT_GAS_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\"" + }, + "AGENT_IS_OWNER": { + "optional": false, + "readonly": true, + "type": "\"AGENT_IS_OWNER\"" + }, + "ASSET_CHAIN_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"ASSET_CHAIN_MISMATCH\"" + }, + "CAPABILITY_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"CAPABILITY_UNAVAILABLE\"" + }, + "CREATE_PARTIAL": { + "optional": false, + "readonly": true, + "type": "\"CREATE_PARTIAL\"" + }, + "DUPLICATE_RULE": { + "optional": false, + "readonly": true, + "type": "\"DUPLICATE_RULE\"" + }, + "FROM_NOT_ALLOWED": { + "optional": false, + "readonly": true, + "type": "\"FROM_NOT_ALLOWED\"" + }, + "GATEWAY_ALLOWANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"GATEWAY_ALLOWANCE_INSUFFICIENT\"" + }, + "GENERATION_UNSUPPORTED": { + "optional": false, + "readonly": true, + "type": "\"GENERATION_UNSUPPORTED\"" + }, + "INCONSISTENT_READ": { + "optional": false, + "readonly": true, + "type": "\"INCONSISTENT_READ\"" + }, + "INDEX_RACE": { + "optional": false, + "readonly": true, + "type": "\"INDEX_RACE\"" + }, + "INVALID_RULE": { + "optional": false, + "readonly": true, + "type": "\"INVALID_RULE\"" + }, + "NO_RULES_FOR_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"NO_RULES_FOR_CHAIN\"" + }, + "NOT_AGENTIC_WALLET": { + "optional": false, + "readonly": true, + "type": "\"NOT_AGENTIC_WALLET\"" + }, + "NOT_ALLOWED_IN_AGENTIC_MODE": { + "optional": false, + "readonly": true, + "type": "\"NOT_ALLOWED_IN_AGENTIC_MODE\"" + }, + "NOT_OWNER_OR_AGENT": { + "optional": false, + "readonly": true, + "type": "\"NOT_OWNER_OR_AGENT\"" + }, + "NOT_WALLET_OWNER": { + "optional": false, + "readonly": true, + "type": "\"NOT_WALLET_OWNER\"" + }, + "READ_ONLY": { + "optional": false, + "readonly": true, + "type": "\"READ_ONLY\"" + }, + "RECEIPT_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_MISMATCH\"" + }, + "RECEIPT_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_UNAVAILABLE\"" + }, + "REVOKE_NEEDS_TARGET": { + "optional": false, + "readonly": true, + "type": "\"REVOKE_NEEDS_TARGET\"" + }, + "RULE_LIMIT_EXCEEDED": { + "optional": false, + "readonly": true, + "type": "\"RULE_LIMIT_EXCEEDED\"" + }, + "RULE_NOT_FOUND": { + "optional": false, + "readonly": true, + "type": "\"RULE_NOT_FOUND\"" + }, + "RULE_READ_FAILED": { + "optional": false, + "readonly": true, + "type": "\"RULE_READ_FAILED\"" + }, + "TARGET_NOT_ON_RULE_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"TARGET_NOT_ON_RULE_CHAIN\"" + }, + "WALLET_BALANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"WALLET_BALANCE_INSUFFICIENT\"" + }, + "WALLET_NOT_DEPLOYED": { + "optional": false, + "readonly": true, + "type": "\"WALLET_NOT_DEPLOYED\"" + } + } + }, + "AgenticError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"CREATE_PARTIAL\" | \"DUPLICATE_RULE\" | \"FROM_NOT_ALLOWED\" | \"GATEWAY_ALLOWANCE_INSUFFICIENT\" | \"GENERATION_UNSUPPORTED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"REVOKE_NEEDS_TARGET\" | \"RULE_LIMIT_EXCEEDED\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"" + }, + "details": { + "optional": true, + "readonly": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "AgenticRevertError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticRevertError", + "members": { + "agenticCode": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + } + } + }, + "AgenticAddress": { + "type": "`0x${string}`", + "members": {} + }, + "AgenticDoor": { + "type": "\"agent\" | \"owner\"", + "members": {} + }, + "AgenticErrorCode": { + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"CREATE_PARTIAL\" | \"DUPLICATE_RULE\" | \"FROM_NOT_ALLOWED\" | \"GATEWAY_ALLOWANCE_INSUFFICIENT\" | \"GENERATION_UNSUPPORTED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"REVOKE_NEEDS_TARGET\" | \"RULE_LIMIT_EXCEEDED\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"", + "members": {} + }, + "AgenticHex": { + "type": "`0x${string}`", + "members": {} + }, + "AgenticNamespace": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace", + "members": { + "create": { + "optional": false, + "readonly": false, + "type": "(label: string, options: import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions) => Promise" + }, + "derive": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n index?: number;\n}) => Promise<{\n address: `0x${string}`;\n deployed: boolean;\n index: number;\n}>" + }, + "list": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n wallets: import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary[];\n}>" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "(address: `0x${string}`) => import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet" + } + } + }, + "AgenticNetworkConstants": { + "type": "import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants", + "members": { + "ENVELOPE_VERSION": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "FACTORY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "MAX_ALLOWED_CALLS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "MAX_PINS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "RULES_POLICY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticProgressHook": { + "type": "(event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void", + "members": {} + }, + "AgenticTxMetadata": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticTxMetadata", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destinationAccount": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "destinationCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "door": { + "optional": false, + "readonly": false, + "type": "\"agent\" | \"owner\"" + }, + "nativeCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "rawData": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rawTo": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesId": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticWallet": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "checkpoints": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n sinceBlock?: bigint;\n}) => Promise<{\n checkpoints: import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint[];\n}>" + }, + "info": { + "optional": false, + "readonly": false, + "type": "() => Promise" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n owner: `0x${string}`;\n}>" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "{\n add(rules: import(\"sdk/src/lib/agentic/agentic.types\").Rule[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise<{\n rulesIds: `0x${string}`[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n get(rulesId: `0x${string}`): Promise;\n list(): Promise<{\n rules: import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord[];\n }>;\n revoke(rulesIds: `0x${string}`[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n revoke(params: {\n all: true;\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n update(params: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n rules: {\n rule: import(\"sdk/src/lib/agentic/agentic.types\").Rule;\n rulesId: `0x${string}`;\n }[];\n }): Promise<{\n rules: {\n replaced: `0x${string}`;\n rulesId: `0x${string}`;\n }[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n}" + }, + "setLabel": { + "optional": false, + "readonly": false, + "type": "(label: string, opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n}) => Promise" + } + } + }, + "AllowedCall": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall", + "members": { + "beneficiary": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValue": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "`${string}(${string})` | `0x${string}`" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AssetCap": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap", + "members": { + "maxPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/constants/tokens\").MoveableToken" + } + } + }, + "Checkpoint": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint", + "members": { + "blockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "kind": { + "optional": false, + "readonly": false, + "type": "\"OWNER_ACTION\" | \"RULES_GRANTED\" | \"RULES_REVOKED\"" + }, + "ref": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "seq": { + "optional": false, + "readonly": false, + "type": "number" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "CheckpointKind": { + "type": "\"OWNER_ACTION\" | \"RULES_GRANTED\" | \"RULES_REVOKED\"", + "members": {} + }, + "CreateOptions": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions", + "members": { + "progressHook": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook | undefined" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Rule[]" + } + } + }, + "CreateResult": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateResult", + "members": { + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "rulesIds": { + "optional": false, + "readonly": false, + "type": "`0x${string}`[]" + }, + "tx": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ForeignChainNamespace": { + "type": "`eip155:${string}` | `solana:${string}`", + "members": {} + }, + "NativeRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "amount": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AmountLimit | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "maxCalls": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValuePerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxValueTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "pins": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ArgPin[] | undefined" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Rule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule | import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "RulesRecord": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "enabled": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "ref": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "rule": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule | import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule" + }, + "rulesId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Selector": { + "type": "`${string}(${string})` | `0x${string}`", + "members": {} + }, + "UniversalRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall[]" + }, + "assets": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap[]" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "`eip155:${string}` | `solana:${string}`" + }, + "maxGasPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "WalletInfo": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").WalletInfo", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "label": { + "optional": false, + "readonly": false, + "type": "string" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "rulesCount": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "WalletSummary": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "label": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesCount": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "PushChain": { + "type": "import(\"sdk/src/lib/push-chain/push-chain\").PushChain", + "members": { + "accountStatus": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus" + }, + "accountStatusReady": { + "optional": false, + "readonly": false, + "type": "Promise" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace" + }, + "explorer": { + "optional": false, + "readonly": false, + "type": "{\n getTransactionUrl: (txHash: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n listAllUrls: () => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n listUrls: (options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n}" + }, + "funds": { + "optional": false, + "readonly": false, + "type": "{\n getConversionQuote: (amountIn: bigint, options: {\n from: import(\"sdk/src/lib/constants/tokens\").PayableToken | undefined;\n to: import(\"sdk/src/lib/constants/tokens\").MoveableToken | undefined;\n }) => Promise;\n}" + }, + "getAccountStatus": { + "optional": false, + "readonly": false, + "type": "(options?: {\n forceRefresh?: boolean;\n}) => Promise" + }, + "isReadMode": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "moveable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").MoveableTokenAccessor;\n}" + }, + "payable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").PayableTokenAccessor;\n}" + }, + "reinitialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "universal": { + "optional": false, + "readonly": false, + "type": "{\n readonly account: `0x${string}`;\n executeReads: (reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>;\n executeTransactions: (txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise;\n migrateCEA: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"migrateCEA\"];\n readonly origin: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n prepareRead: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n prepareTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"prepareTransaction\"];\n read: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n rescueFunds: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"rescueFunds\"];\n sendTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"execute\"];\n signMessage: (data: Uint8Array) => Promise;\n signTypedData: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n trackRead: {\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n };\n trackTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"trackTransaction\"];\n}" + }, + "upgradeAccount": { + "optional": false, + "readonly": false, + "type": "(options?: {\n progressHook?: (progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n}) => Promise" + } + } + } + }, + "pushChainStatic": { + "CONSTANTS": { + "optional": false, + "readonly": false, + "type": "{\n AGENTIC: Readonly>>;\n CHAIN: typeof import(\"sdk/src/lib/constants/enums\").CHAIN;\n LIBRARY: typeof import(\"sdk/src/lib/constants/enums\").LIBRARY;\n MOVEABLE: {\n TOKEN: import(\"sdk/src/lib/constants/tokens\").MoveableTokenConstantsMap;\n };\n PAYABLE: {\n TOKEN: import(\"sdk/src/lib/constants/tokens\").PayableTokenConstantsMap;\n };\n PUSH_NETWORK: typeof import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n READ: {\n readonly CALLBACK_BUDGET_BUFFER: 3;\n readonly CHAIN: {\n readonly WEB2: \"web2\";\n } & Readonly<{\n readonly ARBITRUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA;\n readonly BASE_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA;\n readonly BNB_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET;\n readonly ETHEREUM_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET;\n readonly ETHEREUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA;\n readonly PUSH_LOCALNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET;\n readonly PUSH_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET;\n readonly PUSH_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly PUSH_TESTNET_DONUT: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly SOLANA_DEVNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET;\n readonly SOLANA_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET;\n readonly SOLANA_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n readonly WEB2: \"web2\";\n }>;\n readonly DEFAULT_EXPIRY_BLOCKS: 300n;\n readonly ERROR_CODE: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n readonly MAX_CALLBACK_GAS_LIMIT: 1000000n;\n readonly MIN_CONFIRMATIONS_FLOOR: 1;\n readonly NAMESPACE: {\n readonly EVM: \"eip155\";\n readonly SVM: \"solana\";\n readonly WEB2: \"web2\";\n };\n readonly OUTCOME: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME;\n readonly REGISTRY_CALLBACK_GAS: 500000n;\n readonly RESULT_STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n readonly STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS;\n readonly UNIVERSAL_CALLBACK_ADDRESSES: Record;\n readonly UNIVERSAL_CORE_ADDRESSES: Record;\n readonly UNIVERSAL_READ_REGISTRY_ADDRESS: {\n readonly TESTNET_DONUT: \"0x00000000000000000000000000000000000000b2\";\n };\n readonly WEB2: \"web2\";\n readonly WEB2_DEFAULT_TIMEOUT_MS: 5000;\n readonly WEB2_MAX_EXTRACT_ENTRIES: 16;\n };\n}" + }, + "initialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "utils": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/utils\").Utils" + } + }, + "pushChainInstance": { + "accountStatus": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus" + }, + "accountStatusReady": { + "optional": false, + "readonly": false, + "type": "Promise" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace" + }, + "explorer": { + "optional": false, + "readonly": false, + "type": "{\n getTransactionUrl: (txHash: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n listAllUrls: () => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n listUrls: (options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n}" + }, + "funds": { + "optional": false, + "readonly": false, + "type": "{\n getConversionQuote: (amountIn: bigint, options: {\n from: import(\"sdk/src/lib/constants/tokens\").PayableToken | undefined;\n to: import(\"sdk/src/lib/constants/tokens\").MoveableToken | undefined;\n }) => Promise;\n}" + }, + "getAccountStatus": { + "optional": false, + "readonly": false, + "type": "(options?: {\n forceRefresh?: boolean;\n}) => Promise" + }, + "isReadMode": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "moveable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").MoveableTokenAccessor;\n}" + }, + "payable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").PayableTokenAccessor;\n}" + }, + "reinitialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "universal": { + "optional": false, + "readonly": false, + "type": "{\n readonly account: `0x${string}`;\n executeReads: (reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>;\n executeTransactions: (txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise;\n migrateCEA: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"migrateCEA\"];\n readonly origin: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n prepareRead: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n prepareTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"prepareTransaction\"];\n read: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n rescueFunds: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"rescueFunds\"];\n sendTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"execute\"];\n signMessage: (data: Uint8Array) => Promise;\n signTypedData: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n trackRead: {\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n };\n trackTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"trackTransaction\"];\n}" + }, + "upgradeAccount": { + "optional": false, + "readonly": false, + "type": "(options?: {\n progressHook?: (progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n}) => Promise" + } + }, + "transactionMethods": { + "account": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "executeReads": { + "optional": false, + "readonly": false, + "type": "(reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>" + }, + "executeTransactions": { + "optional": false, + "readonly": false, + "type": "(txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise" + }, + "migrateCEA": { + "optional": false, + "readonly": false, + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => Promise" + }, + "origin": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "prepareRead": { + "optional": false, + "readonly": false, + "type": "(subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>" + }, + "prepareTransaction": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions) => Promise" + }, + "read": { + "optional": false, + "readonly": false, + "type": "(subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>" + }, + "rescueFunds": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").RescueFundsParams) => Promise" + }, + "sendTransaction": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").ExecuteParams | import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions) => Promise" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": false, + "readonly": false, + "type": "({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise" + }, + "trackRead": { + "optional": false, + "readonly": false, + "type": "{\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n}" + }, + "trackTransaction": { + "optional": false, + "readonly": false, + "type": "(txHash: string, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TrackTransactionOptions) => Promise" + } + }, + "utilityMethods": { + "account": { + "optional": false, + "readonly": false, + "type": "{\n convertExecutorToOriginAccount: (ueaAddress: `0x${string}`, options?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n }) => Promise;\n convertOriginToExecutor: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n onlyCompute?: boolean;\n }) => Promise;\n deriveExecutorAccount: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n skipNetworkCheck?: boolean;\n }) => Promise;\n fromChainAgnostic: (caip: string) => import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n resolveControllerAccount: (address: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n skipNetworkCheck?: boolean;\n }) => Promise;\n toChainAgnostic: (address: string, options: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n toUniversal: (address: string, options: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n}" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "{\n actionId: (target: `0x${string}`, selector: \"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector) => `0x${string}`;\n configId: (wallet: `0x${string}`, rulesId: `0x${string}`, actionId: `0x${string}`) => `0x${string}`;\n decodeRules: (bytes: `0x${string}`, ctx?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n pushChainNamespace?: string;\n }) => import(\"sdk/src/lib/agentic/agentic.types\").Rule;\n}" + }, + "chains": { + "optional": false, + "readonly": false, + "type": "{\n getChainName: (chainNamespace: string) => string | undefined;\n getChainNamespace: (chainName: string) => string | undefined;\n getSupportedChains: (network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK) => {\n chains: import(\"sdk/src/lib/constants/enums\").CHAIN[];\n };\n getSupportedChainsByName: (network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK) => {\n chains: string[];\n };\n}" + }, + "conversion": { + "optional": false, + "readonly": false, + "type": "{\n slippageToMinAmount(amount: string, options: {\n slippageBps: number;\n }): string;\n}" + }, + "helpers": { + "optional": false, + "readonly": false, + "type": "{\n encodeTxData({ abi, idl, functionName, args, }: {\n abi?: any;\n args?: any[];\n functionName: string;\n idl?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n }): `0x${string}`;\n formatUnits(value: bigint | string, decimalsOrOptions: {\n decimals: number;\n precision?: number;\n } | number): string;\n getChainName: (chainName: string) => string | undefined;\n parseUnits(value: string, exponent: {\n decimals: number;\n } | number): bigint;\n}" + }, + "signer": { + "optional": false, + "readonly": false, + "type": "{\n construct: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options: {\n signAndSendTransaction: (unsignedTx: Uint8Array) => Promise;\n signAuthorization?: (params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise;\n signMessage: (data: Uint8Array) => Promise;\n signTypedData?: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n }) => import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton;\n toUniversal: (signer: import(\"sdk/src/lib/universal/universal.types\").EthersV5SignerType | import(\"sdk/src/lib/universal/universal.types\").EthersV6SignerType | import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton | import(\"sdk/src/lib/universal/universal.types\").ViemSignerType) => Promise;\n toUniversalFromKeypair: (clientOrAccount: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@solana/web3.js/lib/index\").Keypair | import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").WalletClient | import(\"sdk/src/lib/universal/universal.types\").EthersV6SignerType, { chain, library }: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n library: import(\"sdk/src/lib/constants/enums\").LIBRARY;\n }) => Promise;\n}" + }, + "svm": { + "optional": false, + "readonly": false, + "type": "{\n getRegisteredIdls: () => Array<{\n address: `0x${string}`;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n }>;\n registerIdl: (idl: unknown) => void;\n}" + }, + "tokens": { + "optional": false, + "readonly": false, + "type": "{\n getMoveableTokens(chainOrClient?: import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/push-chain/push-chain\").PushChain): {\n tokens: Array<{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n decimals: number;\n mechanism: \"approve\" | \"native\" | \"permit2\";\n prc20Address?: `0x${string}`;\n sourceChain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n symbol: string;\n }>;\n };\n getPayableTokens(chainOrClient?: import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/push-chain/push-chain\").PushChain): {\n tokens: Array<{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n decimals: number;\n mechanism: \"approve\" | \"native\" | \"permit2\";\n symbol: string;\n }>;\n };\n getPC20Address(address: string, options: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n rpcUrls?: Partial>;\n strict?: boolean;\n }): Promise;\n getPRC20Address(token: {\n address: string;\n chain: string;\n } | import(\"sdk/src/lib/constants/tokens\").MoveableToken, options?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n }): {\n address: `0x${string}`;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n decimals: number;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n symbol: string;\n };\n}" + } + }, + "initialize": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise", + "agwConstants": { + "ENVELOPE_VERSION": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "FACTORY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "MAX_ALLOWED_CALLS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "MAX_PINS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "RULES_POLICY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + }, + "constants": { + "AGENTIC": { + "optional": false, + "readonly": false, + "type": "{\n readonly LOCALNET?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n readonly MAINNET?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n readonly TESTNET?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n readonly TESTNET_DONUT?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n}" + }, + "CHAIN": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "LIBRARY": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").LIBRARY" + }, + "MOVEABLE": { + "optional": false, + "readonly": false, + "type": "{\n TOKEN: import(\"sdk/src/lib/constants/tokens\").MoveableTokenConstantsMap;\n}" + }, + "PAYABLE": { + "optional": false, + "readonly": false, + "type": "{\n TOKEN: import(\"sdk/src/lib/constants/tokens\").PayableTokenConstantsMap;\n}" + }, + "PUSH_NETWORK": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "READ": { + "optional": false, + "readonly": false, + "type": "{\n readonly CALLBACK_BUDGET_BUFFER: 3;\n readonly CHAIN: {\n readonly WEB2: \"web2\";\n } & Readonly<{\n readonly ARBITRUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA;\n readonly BASE_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA;\n readonly BNB_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET;\n readonly ETHEREUM_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET;\n readonly ETHEREUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA;\n readonly PUSH_LOCALNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET;\n readonly PUSH_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET;\n readonly PUSH_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly PUSH_TESTNET_DONUT: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly SOLANA_DEVNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET;\n readonly SOLANA_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET;\n readonly SOLANA_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n readonly WEB2: \"web2\";\n }>;\n readonly DEFAULT_EXPIRY_BLOCKS: 300n;\n readonly ERROR_CODE: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n readonly MAX_CALLBACK_GAS_LIMIT: 1000000n;\n readonly MIN_CONFIRMATIONS_FLOOR: 1;\n readonly NAMESPACE: {\n readonly EVM: \"eip155\";\n readonly SVM: \"solana\";\n readonly WEB2: \"web2\";\n };\n readonly OUTCOME: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME;\n readonly REGISTRY_CALLBACK_GAS: 500000n;\n readonly RESULT_STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n readonly STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS;\n readonly UNIVERSAL_CALLBACK_ADDRESSES: Record;\n readonly UNIVERSAL_CORE_ADDRESSES: Record;\n readonly UNIVERSAL_READ_REGISTRY_ADDRESS: {\n readonly TESTNET_DONUT: \"0x00000000000000000000000000000000000000b2\";\n };\n readonly WEB2: \"web2\";\n readonly WEB2_DEFAULT_TIMEOUT_MS: 5000;\n readonly WEB2_MAX_EXTRACT_ENTRIES: 16;\n}" + } + } + }, + "after": { + "exports": [ + "AGENTIC_ERROR_CODE", + "AccountRole", + "AccountStatus", + "AccountType", + "AgentCard", + "AgentCardInput", + "AgentCardRules", + "AgentCardSummary", + "AgenticAddress", + "AgenticDoor", + "AgenticError", + "AgenticErrorCode", + "AgenticHex", + "AgenticNamespace", + "AgenticPresets", + "AgenticProgressHook", + "AgenticRevertError", + "AgenticTxMetadata", + "AgenticWallet", + "AllowedCall", + "AllowedMutability", + "ArgumentPath", + "AssetCap", + "BatchReadResponse", + "BuildJobSpecOptions", + "BuildJobSpecTemplateOptions", + "BuildReadSpecParams", + "CHAIN", + "CONTRACT_REQUEST_STATUS", + "CascadeCompletionResult", + "CascadeHopInfo", + "CascadeProgressEvent", + "CascadeTrackOptions", + "CascadedTxResponse", + "ChainSource", + "ChainTarget", + "Checkpoint", + "CheckpointKind", + "ConversionQuote", + "CreateJobOptions", + "CreateOptions", + "CreateResult", + "DEFAULT_MAX_PC_FOR_GAS_BUFFER_BPS", + "DecodedErrorPayload", + "DecodedReadResult", + "DecodedSolanaRule", + "DerivedExecutorAccount", + "EncodedReadQuery", + "Evaluation", + "EvmReadQuery", + "ForeignChainNamespace", + "FulfilOutcome", + "FundJobOptions", + "FundsToken", + "InsufficientPC20BalanceError", + "InvalidPC20AddressError", + "InvalidPC20MetadataError", + "InvalidReadQueryError", + "InvalidReadSpecError", + "Job", + "JobCheck", + "JobCheckTemplate", + "JobError", + "JobEvent", + "JobNamespace", + "JobPlan", + "JobRead", + "JobReadInput", + "JobSpec", + "JobSpecError", + "JobSpecPreview", + "JobSpecTemplate", + "JobStatus", + "LogicKind", + "LogicTree", + "MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT", + "MarketAssetToken", + "MarketError", + "MarketNamespace", + "MarketPin", + "MarketPreviewOptions", + "MaxPCForGasCapFromNativeValueInput", + "MaxPCForGasCapInput", + "MaxPCForGasCapQuote", + "MultiChainTxResponse", + "Operation", + "OutboundTxDetails", + "OwnerIntent", + "PC20AddressResult", + "PC20AmbiguousAddressError", + "PC20Error", + "PC20ExpectedButPRC20Error", + "PC20ExportRevertedError", + "PC20FactoryMismatchError", + "PC20RegistryEntry", + "PC20RegistryMismatchError", + "PC20TokenChainMismatchError", + "PC20TokenReference", + "PC20UnknownChainNamespaceError", + "PC20UnsafeEmptyPayloadError", + "PC20WrapperNotRegisteredError", + "PC20WrapperPredictionUnavailableError", + "ParsedReadRequest", + "Pin", + "PrepareJobReadOptions", + "PreparedJobRead", + "PreparedRead", + "PreparedUniversalTx", + "Preset", + "PresetAsset", + "PresetCallIssue", + "PresetCategory", + "PresetChainReadiness", + "PresetConfigurationIssue", + "PresetOptions", + "PresetResult", + "PresetRuleTemplate", + "PrincipalMarker", + "PushChain", + "PushChainBatchExecutionError", + "PushChainExecutionError", + "PushChainInitializeOptions", + "READ_ERROR_CODE", + "READ_OUTCOME", + "READ_STATUS", + "ReadCallback", + "ReadCallbackOptions", + "ReadChain", + "ReadDecodeError", + "ReadDestination", + "ReadExecuteOptions", + "ReadFees", + "ReadHeightUnavailableError", + "ReadLifecycleOptions", + "ReadNotFoundError", + "ReadOptions", + "ReadPreflight", + "ReadPrepareOptions", + "ReadQuery", + "ReadQueryOptions", + "ReadRef", + "ReadRegistryUnavailableError", + "ReadResponseTuple", + "ReadResultShape", + "ReadSpec", + "ReadSpecTuple", + "ReadSpecViolation", + "ReadStateError", + "ReadTimeoutError", + "ReadTrackOptions", + "ReadValue", + "ReadWeb2Options", + "ReadyPresetOptions", + "ReceiptLike", + "RescueFundsParams", + "ResolvedAccount", + "ResolvedControllerAccounts", + "ResolvedDestination", + "Rule", + "RuleInput", + "RulesRecord", + "Selector", + "SignAuthorizationParams", + "SignedAuthorization", + "SimulateReadResult", + "Spent", + "SvmExecutePayloadFields", + "SvmGatewayAccountMeta", + "SvmReadQuery", + "TERMINAL_READ_STATUSES", + "TransactionRoute", + "TransactionRouteType", + "UEAStatus", + "UNIVERSAL_CALLBACK_EVM", + "UNIVERSAL_READ_REGISTRY_EVM", + "UNIVERSAL_READ_STATUS", + "UniversalAccount", + "UniversalExecuteParams", + "UniversalOutboundTxRequest", + "UniversalReadResponse", + "UniversalSigner", + "UniversalSignerSkeleton", + "UniversalTo", + "UnsupportedPC20DestinationError", + "UnsupportedReadDestinationError", + "ValidateReadCall", + "WaitForOutboundOptions", + "WalletInfo", + "WalletMarker", + "WalletSummary", + "Web2Extract", + "Web2ReadQuery", + "Web2ValueType", + "buildErc20WithdrawalMulticall", + "buildMigrationPayload", + "buildReadSpecFromPreflight", + "chainSupportsCEA", + "chainSupportsOutbound", + "decodeReadResult", + "detectRoute", + "encodeReadQuery", + "encodeSvmExecutePayload", + "getAllCEAAddresses", + "getCEAAddress", + "getCEAFactoryAddress", + "getPushAccountForCEA", + "inferResultShape", + "isCEA", + "isChainTarget", + "isPC20Reference", + "isSvmChain", + "isValidSolanaHexAddress", + "parseFulfilOutcome", + "parseReadRequestsFromReceipt", + "parseUEAVersion", + "quoteMaxPCForGasCap", + "quoteMaxPCForGasCapFromNativeValue", + "resolveDestination", + "sizeCallbackBudget", + "toCallData", + "toReadQuery", + "toRequestIdHex", + "validateReadSpec" + ], + "agw": { + "AgenticNamespace": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace", + "members": { + "create": { + "optional": false, + "readonly": false, + "type": "(label: string, options: import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions) => Promise" + }, + "derive": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n index?: number;\n}) => Promise<{\n address: `0x${string}`;\n deployed: boolean;\n index: number;\n}>" + }, + "list": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n wallets: import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary[];\n}>" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "(address: `0x${string}`) => import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet" + } + } + }, + "AgenticWallet": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "checkpoints": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n sinceBlock?: bigint;\n}) => Promise<{\n checkpoints: import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint[];\n}>" + }, + "info": { + "optional": false, + "readonly": false, + "type": "() => Promise" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n owner: `0x${string}`;\n}>" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "{\n add(rules: import(\"sdk/src/lib/agentic/agentic.types\").RuleInput[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise<{\n rulesIds: `0x${string}`[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n delete(rulesIds: `0x${string}`[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n delete(params: {\n all: true;\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n get(rulesId: `0x${string}`): Promise;\n list(): Promise<{\n rules: import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord[];\n }>;\n update(params: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n rules: {\n rule: import(\"sdk/src/lib/agentic/agentic.types\").RuleInput;\n rulesId: `0x${string}`;\n }[];\n }): Promise<{\n rules: {\n replaced: `0x${string}`;\n rulesId: `0x${string}`;\n }[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n}" + }, + "setLabel": { + "optional": false, + "readonly": false, + "type": "(label: string, opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n}) => Promise" + } + } + }, + "AgenticError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "Code" + }, + "details": { + "optional": true, + "readonly": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "userMessage": { + "optional": false, + "readonly": true, + "type": "string" + } + } + }, + "AgenticRevertError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticRevertError", + "members": { + "agenticCode": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "userMessage": { + "optional": false, + "readonly": true, + "type": "string" + } + } + }, + "AGENTIC_ERROR_CODE": { + "type": "{\n readonly AGENT_GAS_INSUFFICIENT: \"AGENT_GAS_INSUFFICIENT\";\n readonly AGENT_IS_OWNER: \"AGENT_IS_OWNER\";\n readonly AMBIGUOUS_RULE: \"AMBIGUOUS_RULE\";\n readonly ASSET_CHAIN_MISMATCH: \"ASSET_CHAIN_MISMATCH\";\n readonly CAPABILITY_UNAVAILABLE: \"CAPABILITY_UNAVAILABLE\";\n readonly DELETE_NEEDS_TARGET: \"DELETE_NEEDS_TARGET\";\n readonly DUPLICATE_RULE: \"DUPLICATE_RULE\";\n readonly FROM_NOT_ALLOWED: \"FROM_NOT_ALLOWED\";\n readonly INCONSISTENT_READ: \"INCONSISTENT_READ\";\n readonly INDEX_RACE: \"INDEX_RACE\";\n readonly INVALID_RULE: \"INVALID_RULE\";\n readonly NO_RULES_FOR_CHAIN: \"NO_RULES_FOR_CHAIN\";\n readonly NOT_AGENTIC_WALLET: \"NOT_AGENTIC_WALLET\";\n readonly NOT_ALLOWED_IN_AGENTIC_MODE: \"NOT_ALLOWED_IN_AGENTIC_MODE\";\n readonly NOT_OWNER_OR_AGENT: \"NOT_OWNER_OR_AGENT\";\n readonly NOT_WALLET_OWNER: \"NOT_WALLET_OWNER\";\n readonly READ_ONLY: \"READ_ONLY\";\n readonly RECEIPT_MISMATCH: \"RECEIPT_MISMATCH\";\n readonly RECEIPT_UNAVAILABLE: \"RECEIPT_UNAVAILABLE\";\n readonly REQUEST_REJECTED: \"REQUEST_REJECTED\";\n readonly RULE_NOT_FOUND: \"RULE_NOT_FOUND\";\n readonly RULE_READ_FAILED: \"RULE_READ_FAILED\";\n readonly TARGET_NOT_ON_RULE_CHAIN: \"TARGET_NOT_ON_RULE_CHAIN\";\n readonly TOKEN_ROUTE_UNAVAILABLE: \"TOKEN_ROUTE_UNAVAILABLE\";\n readonly WALLET_BALANCE_INSUFFICIENT: \"WALLET_BALANCE_INSUFFICIENT\";\n readonly WALLET_NOT_DEPLOYED: \"WALLET_NOT_DEPLOYED\";\n}", + "members": { + "AGENT_GAS_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\"" + }, + "AGENT_IS_OWNER": { + "optional": false, + "readonly": true, + "type": "\"AGENT_IS_OWNER\"" + }, + "AMBIGUOUS_RULE": { + "optional": false, + "readonly": true, + "type": "\"AMBIGUOUS_RULE\"" + }, + "ASSET_CHAIN_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"ASSET_CHAIN_MISMATCH\"" + }, + "CAPABILITY_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"CAPABILITY_UNAVAILABLE\"" + }, + "DELETE_NEEDS_TARGET": { + "optional": false, + "readonly": true, + "type": "\"DELETE_NEEDS_TARGET\"" + }, + "DUPLICATE_RULE": { + "optional": false, + "readonly": true, + "type": "\"DUPLICATE_RULE\"" + }, + "FROM_NOT_ALLOWED": { + "optional": false, + "readonly": true, + "type": "\"FROM_NOT_ALLOWED\"" + }, + "INCONSISTENT_READ": { + "optional": false, + "readonly": true, + "type": "\"INCONSISTENT_READ\"" + }, + "INDEX_RACE": { + "optional": false, + "readonly": true, + "type": "\"INDEX_RACE\"" + }, + "INVALID_RULE": { + "optional": false, + "readonly": true, + "type": "\"INVALID_RULE\"" + }, + "NO_RULES_FOR_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"NO_RULES_FOR_CHAIN\"" + }, + "NOT_AGENTIC_WALLET": { + "optional": false, + "readonly": true, + "type": "\"NOT_AGENTIC_WALLET\"" + }, + "NOT_ALLOWED_IN_AGENTIC_MODE": { + "optional": false, + "readonly": true, + "type": "\"NOT_ALLOWED_IN_AGENTIC_MODE\"" + }, + "NOT_OWNER_OR_AGENT": { + "optional": false, + "readonly": true, + "type": "\"NOT_OWNER_OR_AGENT\"" + }, + "NOT_WALLET_OWNER": { + "optional": false, + "readonly": true, + "type": "\"NOT_WALLET_OWNER\"" + }, + "READ_ONLY": { + "optional": false, + "readonly": true, + "type": "\"READ_ONLY\"" + }, + "RECEIPT_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_MISMATCH\"" + }, + "RECEIPT_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_UNAVAILABLE\"" + }, + "REQUEST_REJECTED": { + "optional": false, + "readonly": true, + "type": "\"REQUEST_REJECTED\"" + }, + "RULE_NOT_FOUND": { + "optional": false, + "readonly": true, + "type": "\"RULE_NOT_FOUND\"" + }, + "RULE_READ_FAILED": { + "optional": false, + "readonly": true, + "type": "\"RULE_READ_FAILED\"" + }, + "TARGET_NOT_ON_RULE_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"TARGET_NOT_ON_RULE_CHAIN\"" + }, + "TOKEN_ROUTE_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"TOKEN_ROUTE_UNAVAILABLE\"" + }, + "WALLET_BALANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"WALLET_BALANCE_INSUFFICIENT\"" + }, + "WALLET_NOT_DEPLOYED": { + "optional": false, + "readonly": true, + "type": "\"WALLET_NOT_DEPLOYED\"" + } + } + }, + "Rule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Rule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleCall[]" + }, + "assets": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset[] | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "maxGasPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "RuleInput": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").DecodedSolanaRule | import(\"sdk/src/lib/agentic/agentic.types\").Rule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "assets": { + "optional": true, + "readonly": false, + "type": "{\n maxPerCall: bigint;\n maxTotal: bigint;\n token: string;\n}[] | import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset[] | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "maxGasPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Pin": { + "type": "{\n account: number;\n arg?: never;\n expected: \"agentic:wallet\" | string;\n max?: never;\n token?: import(\"sdk/src/lib/constants/tokens\").MoveableToken | string;\n} | {\n account?: never;\n arg: import(\"sdk/src/lib/agentic/agentic.types\").ArgumentPath;\n expected: \"agentic:wallet\" | `0x${string}` | `0x${string}` | bigint;\n max?: never;\n} | {\n account?: never;\n arg: import(\"sdk/src/lib/agentic/agentic.types\").ArgumentPath;\n expected?: never;\n max: bigint;\n}", + "members": { + "account": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "arg": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ArgumentPath | undefined" + }, + "expected": { + "optional": true, + "readonly": false, + "type": "bigint | string | undefined" + }, + "max": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "Spent": { + "type": "{\n actions: {\n amountSpent: bigint;\n callsUsed: number;\n selector: \"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector;\n target: `0x${string}`;\n valueSpent: bigint;\n }[];\n kind: \"native\";\n} | {\n amountSpent: bigint;\n callsUsed: number;\n kind: \"native\";\n valueSpent: bigint;\n} | {\n assets: {\n spent: bigint;\n token: string;\n }[];\n kind: \"universal\";\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"native\" | \"universal\"" + } + } + }, + "AssetCap": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset", + "members": { + "maxPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/tokens\").MoveableToken | string" + } + } + }, + "AllowedCall": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleCall", + "members": { + "app": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "label": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "maxValue": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "pins": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Pin[] | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector" + }, + "target": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "RulesRecord": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "enabled": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "rule": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").DecodedSolanaRule | import(\"sdk/src/lib/agentic/agentic.types\").Rule" + }, + "rulesId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "spent": { + "optional": false, + "readonly": false, + "type": "{\n actions: {\n amountSpent: bigint;\n callsUsed: number;\n selector: \"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector;\n target: `0x${string}`;\n valueSpent: bigint;\n }[];\n kind: \"native\";\n} | {\n amountSpent: bigint;\n callsUsed: number;\n kind: \"native\";\n valueSpent: bigint;\n} | {\n assets: {\n spent: bigint;\n token: string;\n }[];\n kind: \"universal\";\n}" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "CreateOptions": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions", + "members": { + "progressHook": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook | undefined" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleInput[]" + } + } + }, + "CreateResult": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateResult", + "members": { + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "rulesIds": { + "optional": false, + "readonly": false, + "type": "`0x${string}`[]" + }, + "tx": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticTxMetadata": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticTxMetadata", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destinationAccount": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "destinationCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "destinationInstruction": { + "optional": true, + "readonly": false, + "type": "{\n accounts: readonly {\n isWritable: boolean;\n pubkey: `0x${string}`;\n }[];\n data: `0x${string}`;\n program: `0x${string}`;\n} | undefined" + }, + "destinationTransfer": { + "optional": true, + "readonly": false, + "type": "{\n amount: bigint;\n recipient: `0x${string}`;\n token: `0x${string}`;\n} | undefined" + }, + "door": { + "optional": false, + "readonly": false, + "type": "\"agent\" | \"owner\"" + }, + "nativeCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "rawData": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rawTo": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesId": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + } + }, + "publicSurface": { + "MarketError": { + "type": "import(\"sdk/src/lib/market/errors\").MarketError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "details": { + "optional": true, + "readonly": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "userMessage": { + "optional": false, + "readonly": true, + "type": "string" + } + } + }, + "JobError": { + "type": "import(\"sdk/src/lib/market/errors\").JobError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "details": { + "optional": true, + "readonly": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "userMessage": { + "optional": false, + "readonly": true, + "type": "string" + } + } + }, + "JobSpecError": { + "type": "import(\"sdk/src/lib/market/errors\").JobSpecError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "details": { + "optional": true, + "readonly": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "userMessage": { + "optional": false, + "readonly": true, + "type": "string" + } + } + }, + "AgentCardRules": { + "type": "import(\"sdk/src/lib/market/rules\").AgentCardRules", + "members": { + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "{\n maxValue?: bigint;\n pins?: import(\"sdk/src/lib/market/rules\").MarketPin[];\n selector: string;\n target: `0x${string}`;\n}[]" + }, + "assets": { + "optional": false, + "readonly": false, + "type": "{\n maxPerCall: \"agentic:principal\" | bigint;\n maxTotal?: \"agentic:principal\" | bigint;\n token: import(\"sdk/src/lib/market/rules\").MarketAssetToken;\n}[]" + }, + "maxGasPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "principalAsset": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "MarketAssetToken": { + "type": "{\n prc20: `0x${string}`;\n} | import(\"sdk/src/lib/constants/tokens\").MoveableToken | string", + "members": {} + }, + "MarketPin": { + "type": "{\n arg: import(\"sdk/src/lib/agentic/agentic.types\").ArgumentPath;\n expected: \"agentic:principal\" | \"agentic:wallet\" | `0x${string}` | `0x${string}` | bigint | boolean;\n max?: never;\n} | {\n arg: import(\"sdk/src/lib/agentic/agentic.types\").ArgumentPath;\n expected?: never;\n max: \"agentic:principal\" | bigint;\n}", + "members": { + "arg": { + "optional": false, + "readonly": false, + "type": "number | readonly number[]" + }, + "expected": { + "optional": true, + "readonly": false, + "type": "\"agentic:principal\" | \"agentic:wallet\" | `0x${string}` | bigint | boolean | undefined" + }, + "max": { + "optional": true, + "readonly": false, + "type": "\"agentic:principal\" | bigint | undefined" + } + } + }, + "AgentCard": { + "type": "import(\"sdk/src/lib/market/types\").AgentCard", + "members": { + "active": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "cardId": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "string" + }, + "disabled": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "jobSpecTemplate": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/job-spec/types\").JobSpecTemplate" + }, + "jobSpecTemplateBytes": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "jobType": { + "optional": false, + "readonly": false, + "type": "string" + }, + "maxDuration": { + "optional": false, + "readonly": false, + "type": "number" + }, + "metadataHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "metadataURI": { + "optional": false, + "readonly": false, + "type": "string" + }, + "minDuration": { + "optional": false, + "readonly": false, + "type": "number" + }, + "minExecuteWindow": { + "optional": false, + "readonly": false, + "type": "number" + }, + "paymentToken": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "principalMax": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "principalMin": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "provider": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "providerFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "rating": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/market/rules\").AgentCardRules" + }, + "rulesBytes": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "settleWindow": { + "optional": false, + "readonly": false, + "type": "number" + }, + "verified": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "version": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "AgentCardInput": { + "type": "import(\"sdk/src/lib/market/types\").AgentCardInput", + "members": { + "chain": { + "optional": false, + "readonly": false, + "type": "string" + }, + "jobType": { + "optional": false, + "readonly": false, + "type": "string" + }, + "maxDuration": { + "optional": false, + "readonly": false, + "type": "number" + }, + "metadataHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "metadataURI": { + "optional": false, + "readonly": false, + "type": "string" + }, + "minDuration": { + "optional": false, + "readonly": false, + "type": "number" + }, + "minExecuteWindow": { + "optional": false, + "readonly": false, + "type": "number" + }, + "paymentToken": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "principalMax": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "principalMin": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "providerFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "settleWindow": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "AgentCardSummary": { + "type": "{\n active: boolean;\n cardId: bigint;\n chain: string;\n disabled: boolean;\n jobType: string;\n maxDuration: number;\n metadataHash: `0x${string}`;\n metadataURI: string;\n minDuration: number;\n minExecuteWindow: number;\n paymentToken: `0x${string}`;\n principalMax: bigint;\n principalMin: bigint;\n provider: `0x${string}`;\n providerFee: bigint;\n rating: bigint;\n settleWindow: number;\n verified: boolean;\n version: bigint;\n}", + "members": { + "active": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "cardId": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "string" + }, + "disabled": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "jobType": { + "optional": false, + "readonly": false, + "type": "string" + }, + "maxDuration": { + "optional": false, + "readonly": false, + "type": "number" + }, + "metadataHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "metadataURI": { + "optional": false, + "readonly": false, + "type": "string" + }, + "minDuration": { + "optional": false, + "readonly": false, + "type": "number" + }, + "minExecuteWindow": { + "optional": false, + "readonly": false, + "type": "number" + }, + "paymentToken": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "principalMax": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "principalMin": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "provider": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "providerFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "rating": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "settleWindow": { + "optional": false, + "readonly": false, + "type": "number" + }, + "verified": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "version": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "MarketNamespace": { + "type": "import(\"sdk/src/lib/market/types\").MarketNamespace", + "members": { + "activeJob": { + "optional": false, + "readonly": false, + "type": "(wallet: `0x${string}`) => Promise<{\n jobId: bigint;\n}>" + }, + "agent": { + "optional": false, + "readonly": false, + "type": "{\n card(): Promise;\n register(card: import(\"sdk/src/lib/market/types\").AgentCardInput, options: {\n jobSpecTemplate: import(\"sdk/src/lib/job-spec/types\").JobSpecTemplate;\n rules: import(\"sdk/src/lib/market/rules\").AgentCardRules;\n } & import(\"sdk/src/lib/market/types\").MarketWriteOptions): Promise<{\n cardId: bigint;\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n version: bigint;\n }>;\n setActive(cardId: bigint, active: boolean, options?: import(\"sdk/src/lib/market/types\").MarketWriteOptions): Promise;\n update(cardId: bigint, card: import(\"sdk/src/lib/market/types\").AgentCardInput, options: {\n jobSpecTemplate: import(\"sdk/src/lib/job-spec/types\").JobSpecTemplate;\n rules: import(\"sdk/src/lib/market/rules\").AgentCardRules;\n } & import(\"sdk/src/lib/market/types\").MarketWriteOptions): Promise<{\n cardId: bigint;\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n version: bigint;\n }>;\n}" + }, + "card": { + "optional": false, + "readonly": false, + "type": "(cardId: bigint) => Promise" + }, + "cards": { + "optional": false, + "readonly": false, + "type": "(options?: {\n active?: boolean;\n chain?: string;\n provider?: `0x${string}`;\n}) => Promise<{\n cards: import(\"sdk/src/lib/market/types\").AgentCardSummary[];\n}>" + }, + "deposit": { + "optional": false, + "readonly": false, + "type": "(jobId: bigint, options?: import(\"sdk/src/lib/market/types\").MarketWriteOptions) => Promise" + }, + "job": { + "optional": false, + "readonly": false, + "type": "(jobId: bigint) => Promise<{\n cardId: bigint;\n cardVersion: bigint;\n rulesId: `0x${string}`;\n wallet: `0x${string}`;\n}>" + }, + "openJob": { + "optional": false, + "readonly": false, + "type": "(plan: import(\"sdk/src/lib/market/types\").JobPlan, options?: {\n relay?: boolean;\n} & import(\"sdk/src/lib/market/types\").MarketWriteOptions) => Promise<{\n jobId: bigint;\n rulesId: `0x${string}`;\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n wallet: `0x${string}`;\n}>" + }, + "preview": { + "optional": false, + "readonly": false, + "type": "(cardId: bigint, options: import(\"sdk/src/lib/market/types\").MarketPreviewOptions) => Promise" + } + } + }, + "MarketPreviewOptions": { + "type": "import(\"sdk/src/lib/market/types\").MarketPreviewOptions", + "members": { + "deadline": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "executeBy": { + "optional": false, + "readonly": false, + "type": "number" + }, + "expiredAt": { + "optional": false, + "readonly": false, + "type": "number" + }, + "label": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "params": { + "optional": true, + "readonly": false, + "type": "bigint[] | undefined" + }, + "principal": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "walletIndex": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "JobPlan": { + "type": "import(\"sdk/src/lib/market/types\").JobPlan", + "members": { + "calldata": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "cardId": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "cardVersion": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "deposit": { + "optional": false, + "readonly": false, + "type": "{\n pc: bigint;\n principal: {\n amount: bigint;\n prc20: `0x${string}`;\n };\n providerFee: {\n amount: bigint;\n token: `0x${string}`;\n };\n}" + }, + "intent": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/market/types\").OwnerIntent" + }, + "job": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/market/types\").MarketJobInputs" + }, + "jobSpec": { + "optional": false, + "readonly": false, + "type": "{\n bytes: `0x${string}`;\n spec: import(\"sdk/src/lib/job-spec/types\").JobSpec;\n}" + }, + "label": { + "optional": false, + "readonly": false, + "type": "string" + }, + "preview": { + "optional": false, + "readonly": false, + "type": "{\n judgedBy: string[];\n mayDo: string[];\n mayMove: string[];\n until: string;\n}" + }, + "session": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/codec/session\").SessionWire" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "walletDeployed": { + "optional": false, + "readonly": false, + "type": "boolean" + } + } + }, + "OwnerIntent": { + "type": "import(\"sdk/src/lib/market/types\").OwnerIntent", + "members": { + "deadline": { + "optional": false, + "readonly": false, + "type": "number" + }, + "execCalldataHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "executor": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "grantNonce": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "index": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "mode": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "nonceKey": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "nonceSeq": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "sessionHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "signerChainId": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "JobNamespace": { + "type": "import(\"sdk/src/lib/job/types\").JobNamespace", + "members": { + "cancel": { + "optional": false, + "readonly": false, + "type": "(jobId: bigint, options?: import(\"sdk/src/lib/job/types\").JobWriteOptions) => Promise" + }, + "claimRefund": { + "optional": false, + "readonly": false, + "type": "(jobId: bigint, options?: import(\"sdk/src/lib/job/types\").JobWriteOptions) => Promise" + }, + "create": { + "optional": false, + "readonly": false, + "type": "(options: import(\"sdk/src/lib/job/types\").CreateJobOptions) => Promise<{\n jobId: bigint;\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n}>" + }, + "fund": { + "optional": false, + "readonly": false, + "type": "(jobId: bigint, options?: import(\"sdk/src/lib/job/types\").FundJobOptions) => Promise" + }, + "list": { + "optional": false, + "readonly": false, + "type": "(options?: {\n client?: `0x${string}`;\n fromJobId?: bigint;\n provider?: `0x${string}`;\n status?: import(\"sdk/src/lib/job/types\").JobStatus;\n}) => Promise<{\n jobs: import(\"sdk/src/lib/job/types\").Job[];\n}>" + }, + "setBudget": { + "optional": false, + "readonly": false, + "type": "(jobId: bigint, amount: bigint, options?: {\n jobSpec?: `0x${string}`;\n} & import(\"sdk/src/lib/job/types\").JobWriteOptions) => Promise" + }, + "status": { + "optional": false, + "readonly": false, + "type": "(jobId: bigint) => Promise" + }, + "submit": { + "optional": false, + "readonly": false, + "type": "(jobId: bigint, options: {\n deliverable: `0x${string}` | string;\n} & import(\"sdk/src/lib/job/types\").JobWriteOptions) => Promise" + }, + "verify": { + "optional": false, + "readonly": false, + "type": "(jobId: bigint, options?: import(\"sdk/src/lib/job/types\").JobWriteOptions) => Promise" + }, + "watch": { + "optional": false, + "readonly": false, + "type": "(jobId: bigint, callback: (event: import(\"sdk/src/lib/job/types\").JobEvent) => void, options?: {\n fromBlock?: bigint;\n pollIntervalMs?: number;\n}) => () => void" + } + } + }, + "Job": { + "type": "import(\"sdk/src/lib/job/types\").Job", + "members": { + "budget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "client": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deliverable": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "description": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "evaluation": { + "optional": false, + "readonly": false, + "type": "{\n available: false;\n reason: \"MANUAL_EVALUATOR\" | \"UNVERIFIED_EVALUATOR\";\n}" + }, + "evaluator": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "expiredAt": { + "optional": false, + "readonly": false, + "type": "number" + }, + "hook": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "jobId": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "jobSpec": { + "optional": true, + "readonly": false, + "type": "{\n bytes: `0x${string}`;\n frozen?: boolean;\n spec: import(\"sdk/src/lib/job-spec/types\").JobSpec;\n} | undefined" + }, + "jobSpecDecodeError": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "paymentToken": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "provider": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "rulesId": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "status": { + "optional": false, + "readonly": false, + "type": "\"Completed\" | \"Expired\" | \"Funded\" | \"Open\" | \"Rejected\" | \"Submitted\"" + } + } + }, + "JobStatus": { + "type": "\"Completed\" | \"Expired\" | \"Funded\" | \"Open\" | \"Rejected\" | \"Submitted\"", + "members": {} + }, + "JobEvent": { + "type": "import(\"sdk/src/lib/job/types\").JobEvent", + "members": { + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "data": { + "optional": true, + "readonly": false, + "type": "unknown" + }, + "error": { + "optional": true, + "readonly": false, + "type": "unknown" + }, + "jobId": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "kind": { + "optional": false, + "readonly": false, + "type": "string" + }, + "txHash": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "CreateJobOptions": { + "type": "import(\"sdk/src/lib/job/types\").CreateJobOptions", + "members": { + "description": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "evaluator": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "expiredAt": { + "optional": false, + "readonly": false, + "type": "number" + }, + "hook": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "jobSpec": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "paymentToken": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/market/runtime\").StackProgressHook | undefined" + }, + "provider": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "FundJobOptions": { + "type": "import(\"sdk/src/lib/job/types\").FundJobOptions", + "members": { + "expectedBudget": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/market/runtime\").StackProgressHook | undefined" + }, + "rulesId": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "JobSpec": { + "type": "import(\"sdk/src/lib/job-spec/types\").JobSpec", + "members": { + "allowedMutability": { + "optional": false, + "readonly": false, + "type": "\"BOTH\" | \"CLIENT\" | \"NONE\" | \"PROVIDER\"" + }, + "checks": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/job-spec/types\").JobCheck[]" + }, + "executeBy": { + "optional": false, + "readonly": false, + "type": "number" + }, + "failFinalAt": { + "optional": false, + "readonly": false, + "type": "number" + }, + "logic": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/job-spec/types\").LogicTree" + }, + "origin": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "reads": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/job-spec/types\").JobRead[]" + } + } + }, + "JobSpecTemplate": { + "type": "import(\"sdk/src/lib/job-spec/types\").JobSpecTemplate", + "members": { + "allowedMutability": { + "optional": false, + "readonly": false, + "type": "\"BOTH\" | \"CLIENT\" | \"NONE\" | \"PROVIDER\"" + }, + "checks": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/job-spec/types\").JobCheckTemplate[]" + }, + "logic": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/job-spec/types\").LogicTree" + }, + "params": { + "optional": false, + "readonly": false, + "type": "{\n max: bigint;\n min: bigint;\n}[]" + }, + "reads": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/job-spec/types\").JobRead[]" + } + } + }, + "JobRead": { + "type": "import(\"sdk/src/lib/job-spec/types\").JobRead", + "members": { + "args": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainId": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "field": { + "optional": false, + "readonly": false, + "type": "number[]" + }, + "fills": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/job-spec/types\").JobFill[] | undefined" + }, + "minConfirmations": { + "optional": false, + "readonly": false, + "type": "number" + }, + "outputs": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "PreparedJobRead": { + "type": "import(\"sdk/src/lib/job-spec/types\").PreparedJobRead", + "members": { + "args": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainId": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "fills": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/job-spec/types\").JobFill[] | undefined" + }, + "outputs": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "JobReadInput": { + "type": "import(\"sdk/src/lib/job-spec/types\").JobReadInput", + "members": { + "field": { + "optional": true, + "readonly": false, + "type": "number[] | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "read": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/job-spec/types\").PreparedJobRead" + } + } + }, + "JobCheck": { + "type": "import(\"sdk/src/lib/job-spec/types\").JobCheck", + "members": { + "evaluation": { + "optional": false, + "readonly": false, + "type": "\"BOOLEAN\" | \"COMPARE\" | \"NUMBER\" | \"PERCENTAGE\"" + }, + "operation": { + "optional": false, + "readonly": false, + "type": "\"EQUAL\" | \"GREATER_OR_EQUAL\" | \"GREATER_THAN\" | \"LESS_OR_EQUAL\" | \"LESS_THAN\" | \"NOT_EQUAL\"" + }, + "read": { + "optional": false, + "readonly": false, + "type": "number" + }, + "target": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "JobCheckTemplate": { + "type": "import(\"sdk/src/lib/job-spec/types\").JobCheckTemplate", + "members": { + "evaluation": { + "optional": false, + "readonly": false, + "type": "\"BOOLEAN\" | \"COMPARE\" | \"NUMBER\" | \"PERCENTAGE\"" + }, + "operation": { + "optional": false, + "readonly": false, + "type": "\"EQUAL\" | \"GREATER_OR_EQUAL\" | \"GREATER_THAN\" | \"LESS_OR_EQUAL\" | \"LESS_THAN\" | \"NOT_EQUAL\"" + }, + "read": { + "optional": false, + "readonly": false, + "type": "number" + }, + "target": { + "optional": false, + "readonly": false, + "type": "\"agentic:principal\" | \"agentic:wallet\" | {\n param: number;\n} | {\n principalBps: bigint;\n} | bigint" + } + } + }, + "LogicTree": { + "type": "import(\"sdk/src/lib/job-spec/types\").LogicTree", + "members": { + "k": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "kind": { + "optional": false, + "readonly": false, + "type": "\"ALL\" | \"ANY\" | \"AT_LEAST\"" + }, + "of": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/job-spec/types\").LogicTree | number)[]" + } + } + }, + "Evaluation": { + "type": "\"BOOLEAN\" | \"COMPARE\" | \"NUMBER\" | \"PERCENTAGE\"", + "members": {} + }, + "Operation": { + "type": "\"EQUAL\" | \"GREATER_OR_EQUAL\" | \"GREATER_THAN\" | \"LESS_OR_EQUAL\" | \"LESS_THAN\" | \"NOT_EQUAL\"", + "members": {} + }, + "LogicKind": { + "type": "\"ALL\" | \"ANY\" | \"AT_LEAST\"", + "members": {} + }, + "AllowedMutability": { + "type": "\"BOTH\" | \"CLIENT\" | \"NONE\" | \"PROVIDER\"", + "members": {} + }, + "PrincipalMarker": { + "type": "\"agentic:principal\"", + "members": {} + }, + "PrepareJobReadOptions": { + "type": "import(\"sdk/src/lib/job-spec/types\").PrepareJobReadOptions", + "members": { + "abi": { + "optional": false, + "readonly": false, + "type": "readonly (import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/abitype/dist/types/abi\").AbiConstructor | import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/abitype/dist/types/abi\").AbiError | import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/abitype/dist/types/abi\").AbiFallback | import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/abitype/dist/types/abi\").AbiReceive | import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiEvent | import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiFunction)[]" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "string" + }, + "functionName": { + "optional": false, + "readonly": false, + "type": "string" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "BuildJobSpecOptions": { + "type": "import(\"sdk/src/lib/job-spec/types\").BuildJobSpecOptions", + "members": { + "allowedMutability": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/job-spec/types\").AllowedMutability | undefined" + }, + "checks": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/job-spec/types\").JobCheck[]" + }, + "executeBy": { + "optional": false, + "readonly": false, + "type": "number" + }, + "expiredAt": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "failFinalAt": { + "optional": false, + "readonly": false, + "type": "number" + }, + "logic": { + "optional": false, + "readonly": false, + "type": "\"ALL\" | \"ANY\" | import(\"sdk/src/lib/job-spec/types\").LogicTree" + }, + "origin": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "reads": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/job-spec/types\").JobReadInput | import(\"sdk/src/lib/job-spec/types\").PreparedJobRead)[]" + } + } + }, + "BuildJobSpecTemplateOptions": { + "type": "import(\"sdk/src/lib/job-spec/types\").BuildJobSpecTemplateOptions", + "members": { + "allowedMutability": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/job-spec/types\").AllowedMutability | undefined" + }, + "checks": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/job-spec/types\").JobCheckTemplate[]" + }, + "logic": { + "optional": false, + "readonly": false, + "type": "\"ALL\" | \"ANY\" | import(\"sdk/src/lib/job-spec/types\").LogicTree" + }, + "params": { + "optional": true, + "readonly": false, + "type": "{\n max: bigint;\n min: bigint;\n}[] | undefined" + }, + "reads": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/job-spec/types\").JobReadInput | import(\"sdk/src/lib/job-spec/types\").PreparedJobRead)[]" + } + } + }, + "JobSpecPreview": { + "type": "import(\"sdk/src/lib/job-spec/types\").JobSpecPreview", + "members": { + "checks": { + "optional": false, + "readonly": false, + "type": "{\n pass: boolean | null;\n value: bigint;\n}[]" + }, + "pass": { + "optional": false, + "readonly": false, + "type": "boolean | null" + }, + "reads": { + "optional": false, + "readonly": false, + "type": "{\n decoded: bigint;\n value: `0x${string}`;\n}[]" + } + } + }, + "CHAIN": { + "type": "typeof import(\"sdk/src/lib/constants/enums\").CHAIN", + "members": { + "ARBITRUM_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA" + }, + "BASE_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA" + }, + "BNB_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET" + }, + "ETHEREUM_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET" + }, + "ETHEREUM_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA" + }, + "PUSH_LOCALNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET" + }, + "PUSH_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET" + }, + "PUSH_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET" + }, + "PUSH_TESTNET_DONUT": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET" + }, + "SOLANA_DEVNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET" + }, + "SOLANA_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET" + }, + "SOLANA_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET" + }, + "WEB2": { + "optional": false, + "readonly": false, + "type": "\"web2\"" + } + } + }, + "ConversionQuote": { + "type": "import(\"sdk/src/lib/constants/tokens\").ConversionQuote", + "members": { + "amountIn": { + "optional": false, + "readonly": false, + "type": "string" + }, + "amountOut": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rate": { + "optional": false, + "readonly": false, + "type": "number" + }, + "route": { + "optional": true, + "readonly": false, + "type": "string[] | undefined" + }, + "timestamp": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "UniversalSigner": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalSigner", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "signAndSendTransaction": { + "optional": false, + "readonly": false, + "type": "(unsignedTx: Uint8Array) => Promise" + }, + "signAuthorization": { + "optional": true, + "readonly": false, + "type": "((params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise) | undefined" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": true, + "readonly": false, + "type": "(({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise) | undefined" + } + } + }, + "UniversalAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "UniversalSignerSkeleton": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "signAndSendTransaction": { + "optional": false, + "readonly": false, + "type": "(unsignedTx: Uint8Array) => Promise" + }, + "signAuthorization": { + "optional": true, + "readonly": false, + "type": "((params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise) | undefined" + }, + "signerId": { + "optional": false, + "readonly": false, + "type": "string" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": true, + "readonly": false, + "type": "(({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise) | undefined" + } + } + }, + "SignAuthorizationParams": { + "type": "{\n chainId?: number;\n contractAddress: `0x${string}`;\n executor?: \"self\";\n nonce?: number;\n}", + "members": { + "chainId": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "contractAddress": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "executor": { + "optional": true, + "readonly": false, + "type": "\"self\" | undefined" + }, + "nonce": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "SignedAuthorization": { + "type": "{\n address: `0x${string}`;\n chainId: number;\n nonce: number;\n r: `0x${string}`;\n s: `0x${string}`;\n v?: bigint;\n yParity: number;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainId": { + "optional": false, + "readonly": false, + "type": "number" + }, + "nonce": { + "optional": false, + "readonly": false, + "type": "number" + }, + "r": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "s": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "v": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "yParity": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "DerivedExecutorAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").DerivedExecutorAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean | null" + } + } + }, + "ResolvedAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainName": { + "optional": false, + "readonly": false, + "type": "string" + }, + "exists": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "role": { + "optional": true, + "readonly": false, + "type": "\"controller\" | undefined" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"cea\" | \"uea\" | \"uoa\"" + } + } + }, + "ResolvedControllerAccounts": { + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedControllerAccounts", + "members": { + "accounts": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedAccount[]" + } + } + }, + "AccountType": { + "type": "\"cea\" | \"uea\" | \"uoa\"", + "members": {} + }, + "AccountRole": { + "type": "\"controller\"", + "members": {} + }, + "PC20TokenReference": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "FundsToken": { + "type": "import(\"sdk/src/lib/constants/tokens\").MoveableToken | import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20TokenReference", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "PC20RegistryEntry": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "chainName": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "PC20AddressResult": { + "type": "{\n address: `0x${string}`;\n decimals: number;\n name: string;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n registry: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20RegistryEntry[];\n symbol: string;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "decimals": { + "optional": false, + "readonly": false, + "type": "number" + }, + "name": { + "optional": false, + "readonly": false, + "type": "string" + }, + "network": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "registry": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20RegistryEntry[]" + }, + "symbol": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "isPC20Reference": { + "type": "(token: import(\"sdk/src/lib/orchestrator/orchestrator.types\").FundsToken | undefined) => token is import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20TokenReference", + "members": {} + }, + "PC20Error": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20Error", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidPC20AddressError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InvalidPC20AddressError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20TokenChainMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20TokenChainMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20WrapperNotRegisteredError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20WrapperNotRegisteredError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20RegistryMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20RegistryMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20FactoryMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20FactoryMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidPC20MetadataError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InvalidPC20MetadataError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20ExpectedButPRC20Error": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20ExpectedButPRC20Error", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20AmbiguousAddressError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20AmbiguousAddressError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "candidates": { + "optional": false, + "readonly": true, + "type": "{\n chain: string;\n pushAddress: string;\n}[]" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "UnsupportedPC20DestinationError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").UnsupportedPC20DestinationError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InsufficientPC20BalanceError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InsufficientPC20BalanceError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20UnknownChainNamespaceError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20UnknownChainNamespaceError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20WrapperPredictionUnavailableError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20WrapperPredictionUnavailableError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20ExportRevertedError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20ExportRevertedError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "lockedAmount": { + "optional": true, + "readonly": true, + "type": "bigint | undefined" + }, + "outboundTxId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "revertRecipient": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20UnsafeEmptyPayloadError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20UnsafeEmptyPayloadError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ChainTarget": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "ChainSource": { + "type": "{\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "UniversalTo": { + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget", + "members": {} + }, + "TransactionRouteType": { + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"", + "members": {} + }, + "UniversalExecuteParams": { + "type": "{\n from?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainSource;\n migration?: boolean;\n to: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTo;\n} & Omit", + "members": { + "_minimumDepositUsd": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "_requiredFundsOverride": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "_skipFeeLocking": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "_ueaStatus": { + "optional": true, + "readonly": false, + "type": "{\n balance: bigint;\n isDeployed: boolean;\n nonce: bigint;\n} | undefined" + }, + "data": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiCall[] | undefined" + }, + "deadline": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "feeLockTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "from": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainSource | undefined" + }, + "funds": { + "optional": true, + "readonly": false, + "type": "{\n amount: bigint;\n token?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").FundsToken;\n} | undefined" + }, + "gasLimit": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFeePerGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxPCForGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxPriorityFeePerGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "migration": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "nonce": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "options": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions | undefined" + }, + "payGasWith": { + "optional": true, + "readonly": false, + "type": "{\n minAmountOut?: bigint | string;\n slippageBps?: number;\n token?: import(\"sdk/src/lib/constants/tokens\").PayableToken;\n} | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "to": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget" + }, + "value": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "UniversalOutboundTxRequest": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalOutboundTxRequest", + "members": { + "amount": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gasPrice": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxPCForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "payload": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "recipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "revertRecipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "PreparedUniversalTx": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx", + "members": { + "_hop": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").HopDescriptor" + }, + "deadline": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "estimatedGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gatewayRequest": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalOutboundTxRequest | import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxRequest" + }, + "nonce": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "payload": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + } + } + }, + "CascadedTxResponse": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadedTxResponse", + "members": { + "finalTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hopCount": { + "optional": false, + "readonly": false, + "type": "number" + }, + "hops": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo[]" + }, + "initialTxHash": { + "optional": false, + "readonly": false, + "type": "string" + }, + "initialTxResponse": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions) => Promise" + }, + "waitForAll": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions) => Promise" + } + } + }, + "CascadeHopInfo": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo", + "members": { + "executionChain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "expectedSubTxId": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hopIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "outboundDetails": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").OutboundTxDetails | undefined" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + }, + "status": { + "optional": false, + "readonly": false, + "type": "\"confirmed\" | \"failed\" | \"pending\" | \"submitted\"" + }, + "txHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "CascadeTrackOptions": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions", + "members": { + "eventHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeProgressEvent) => void) | undefined" + }, + "timeout": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "CascadeProgressEvent": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeProgressEvent", + "members": { + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "elapsed": { + "optional": false, + "readonly": false, + "type": "number" + }, + "hopIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + }, + "status": { + "optional": false, + "readonly": false, + "type": "\"confirmed\" | \"failed\" | \"found\" | \"polling\" | \"timeout\" | \"waiting\"" + }, + "txHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "CascadeCompletionResult": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeCompletionResult", + "members": { + "failedAt": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "finalTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "finalTxResponse": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadedTxResponse | undefined" + }, + "hops": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo[]" + }, + "success": { + "optional": false, + "readonly": false, + "type": "boolean" + } + } + }, + "MultiChainTxResponse": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiChainTxResponse", + "members": { + "chains": { + "optional": false, + "readonly": false, + "type": "{\n blockNumber: bigint;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n hash: string;\n status: \"confirmed\" | \"failed\" | \"pending\";\n}[]" + }, + "transactions": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse[]" + } + } + }, + "OutboundTxDetails": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").OutboundTxDetails", + "members": { + "amount": { + "optional": false, + "readonly": false, + "type": "string" + }, + "assetAddr": { + "optional": false, + "readonly": false, + "type": "string" + }, + "destinationChain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "explorerUrl": { + "optional": false, + "readonly": false, + "type": "string" + }, + "externalTxHash": { + "optional": false, + "readonly": false, + "type": "string" + }, + "recipient": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "WaitForOutboundOptions": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").WaitForOutboundOptions", + "members": { + "_expectedDestinationChain": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "_outboundIndex": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "_resolvedSubTxId": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "initialWaitMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: {\n elapsed: number;\n status: \"failed\" | \"found\" | \"polling\" | \"timeout\" | \"waiting\";\n}) => void) | undefined" + }, + "timeout": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "SvmGatewayAccountMeta": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmGatewayAccountMeta", + "members": { + "isWritable": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "pubkey": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "SvmExecutePayloadFields": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmExecutePayloadFields", + "members": { + "accounts": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmGatewayAccountMeta[]" + }, + "instructionId": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "ixData": { + "optional": false, + "readonly": false, + "type": "Uint8Array" + }, + "targetProgram": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AccountStatus": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus", + "members": { + "mode": { + "optional": false, + "readonly": false, + "type": "\"read-only\" | \"signer\"" + }, + "uea": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UEAStatus" + } + } + }, + "UEAStatus": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UEAStatus", + "members": { + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "loaded": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "minRequiredVersion": { + "optional": false, + "readonly": false, + "type": "string" + }, + "requiresUpgrade": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "version": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "RescueFundsParams": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").RescueFundsParams", + "members": { + "prc20": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "universalTxId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "parseUEAVersion": { + "type": "(version: string) => number", + "members": {} + }, + "TransactionRoute": { + "type": "typeof import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute", + "members": { + "CEA_TO_CEA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.CEA_TO_CEA" + }, + "CEA_TO_PUSH": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.CEA_TO_PUSH" + }, + "UOA_TO_CEA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.UOA_TO_CEA" + }, + "UOA_TO_PUSH": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.UOA_TO_PUSH" + } + } + }, + "detectRoute": { + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams) => import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute", + "members": {} + }, + "isChainTarget": { + "type": "(to: unknown) => to is import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget", + "members": {} + }, + "DEFAULT_MAX_PC_FOR_GAS_BUFFER_BPS": { + "type": "1000", + "members": {} + }, + "MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT": { + "type": "10000", + "members": {} + }, + "quoteMaxPCForGasCap": { + "type": "(input: import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapInput) => import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": {} + }, + "quoteMaxPCForGasCapFromNativeValue": { + "type": "(input: import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapFromNativeValueInput) => import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": {} + }, + "MaxPCForGasCapInput": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapInput", + "members": { + "bufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "gasLegNativePc": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "MaxPCForGasCapFromNativeValueInput": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapFromNativeValueInput", + "members": { + "bufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "nativeValueForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "MaxPCForGasCapQuote": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": { + "bufferBps": { + "optional": false, + "readonly": false, + "type": "number" + }, + "gasLegNativePc": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxPCForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "nativeValueForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "getCEAAddress": { + "type": "(ueaAddress: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise", + "members": {} + }, + "getPushAccountForCEA": { + "type": "(ceaAddress: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise<`0x${string}`>", + "members": {} + }, + "isCEA": { + "type": "(address: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise", + "members": {} + }, + "chainSupportsCEA": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "chainSupportsOutbound": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "getCEAFactoryAddress": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => `0x${string}` | undefined", + "members": {} + }, + "getAllCEAAddresses": { + "type": "(ueaAddress: `0x${string}`, rpcUrls?: Partial>) => Promise", + "members": {} + }, + "encodeSvmExecutePayload": { + "type": "(fields: import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmExecutePayloadFields) => `0x${string}`", + "members": {} + }, + "isSvmChain": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "isValidSolanaHexAddress": { + "type": "(address: string) => boolean", + "members": {} + }, + "buildMigrationPayload": { + "type": "() => `0x${string}`", + "members": {} + }, + "buildErc20WithdrawalMulticall": { + "type": "(tokenAddress: `0x${string}`, recipientAddress: `0x${string}`, amount: bigint) => import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiCall[]", + "members": {} + }, + "ReadChain": { + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain", + "members": {} + }, + "ReadDestination": { + "type": "{\n chain: import(\"sdk/src/lib/read-state/read-state.types\").ReadChain;\n} | {\n chainId: string;\n chainNamespace: string;\n}", + "members": {} + }, + "ResolvedDestination": { + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}", + "members": { + "caip2": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainId": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "namespace": { + "optional": false, + "readonly": false, + "type": "\"eip155\" | \"solana\" | \"web2\"" + } + } + }, + "ReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").SvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery", + "members": { + "type": { + "optional": false, + "readonly": false, + "type": "\"accountBalance\" | \"contractCall\" | \"http\" | \"lamportBalance\" | \"rawAccountData\" | \"splTokenAccount\" | \"storageSlot\"" + } + } + }, + "EvmReadQuery": { + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n target: `0x${string}`;\n type: \"contractCall\";\n} | {\n callData: `0x${string}`;\n target: `0x${string}`;\n type: \"contractCall\";\n} | {\n slot: `0x${string}` | bigint;\n target: `0x${string}`;\n type: \"storageSlot\";\n} | {\n target: `0x${string}`;\n type: \"accountBalance\";\n}", + "members": { + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"accountBalance\" | \"contractCall\" | \"storageSlot\"" + } + } + }, + "SvmReadQuery": { + "type": "{\n account: string | Uint8Array;\n accountName?: string;\n idl?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n type: \"rawAccountData\";\n} | {\n account: string | Uint8Array;\n type: \"lamportBalance\";\n} | {\n account: string | Uint8Array;\n type: \"splTokenAccount\";\n}", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "string | Uint8Array" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"lamportBalance\" | \"rawAccountData\" | \"splTokenAccount\"" + } + } + }, + "Web2ReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery", + "members": { + "body": { + "optional": true, + "readonly": false, + "type": "string | Uint8Array | undefined" + }, + "extract": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[]" + }, + "headers": { + "optional": true, + "readonly": false, + "type": "Record | undefined" + }, + "method": { + "optional": true, + "readonly": false, + "type": "\"GET\" | \"POST\" | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"http\"" + }, + "url": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "Web2Extract": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract", + "members": { + "decimals": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "path": { + "optional": false, + "readonly": false, + "type": "string" + }, + "valueType": { + "optional": false, + "readonly": false, + "type": "\"bool\" | \"bytes\" | \"int256\" | \"string\" | \"uint256\"" + } + } + }, + "Web2ValueType": { + "type": "\"bool\" | \"bytes\" | \"int256\" | \"string\" | \"uint256\"", + "members": {} + }, + "EncodedReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery", + "members": { + "blockRef": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "encoded": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "namespace": { + "optional": false, + "readonly": false, + "type": "\"eip155\" | \"solana\" | \"web2\"" + }, + "ownerBytes": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "queryType": { + "optional": false, + "readonly": false, + "type": "number" + }, + "resultShape": { + "optional": false, + "readonly": false, + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}" + }, + "warnings": { + "optional": false, + "readonly": false, + "type": "string[]" + } + } + }, + "ReadResultShape": { + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"bytes32\" | \"evmCall\" | \"raw\" | \"svmAccount\" | \"uint256\" | \"web2\"" + } + } + }, + "DecodedReadResult": { + "type": "{\n accountName: string;\n kind: \"svmAccount\";\n value: unknown;\n} | {\n kind: \"bytes32\";\n value: `0x${string}`;\n} | {\n kind: \"evmCall\";\n value: unknown;\n} | {\n kind: \"raw\";\n value: `0x${string}`;\n} | {\n kind: \"uint256\";\n value: bigint;\n} | {\n kind: \"web2\";\n values: readonly unknown[];\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"bytes32\" | \"evmCall\" | \"raw\" | \"svmAccount\" | \"uint256\" | \"web2\"" + } + } + }, + "ReadPreflight": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight", + "members": { + "destination": { + "optional": false, + "readonly": false, + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}" + }, + "fetchedAt": { + "optional": false, + "readonly": false, + "type": "number" + }, + "observedChainHeight": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pushBlockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pushGasPrice": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "universalCallback": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "universalCore": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ReadSpec": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "{\n chainId: string;\n chainNamespace: string;\n owner: `0x${string}`;\n}" + }, + "blockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "expiryPushChainHeight": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "minConfirmations": { + "optional": false, + "readonly": false, + "type": "number" + }, + "query": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "revertRecipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ReadSpecTuple": { + "type": "readonly [\n readonly [\n string,\n string,\n `0x${string}`\n ],\n `0x${string}`,\n number,\n bigint,\n bigint,\n bigint,\n `0x${string}`\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "readonly [\n string,\n string,\n `0x${string}`\n]" + }, + "1": { + "optional": false, + "readonly": true, + "type": "`0x${string}`" + }, + "2": { + "optional": false, + "readonly": true, + "type": "number" + }, + "3": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "4": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "5": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "6": { + "optional": false, + "readonly": true, + "type": "`0x${string}`" + }, + "length": { + "optional": false, + "readonly": true, + "type": "7" + } + } + }, + "BuildReadSpecParams": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").BuildReadSpecParams", + "members": { + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "budgetBuffer": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback | undefined" + }, + "callbackBudget": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "destination": { + "optional": false, + "readonly": false, + "type": "{\n chain: import(\"sdk/src/lib/read-state/read-state.types\").ReadChain;\n} | {\n chainId: string;\n chainNamespace: string;\n}" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "expiryPushChainHeight": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFeeBufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "owner": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "query": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").SvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "PreparedRead": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead", + "members": { + "__@preparedReadValue": { + "optional": true, + "readonly": true, + "type": "T | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback | undefined" + }, + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "encodedQuery": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery" + }, + "encodedSpec": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "fees": { + "optional": false, + "readonly": false, + "type": "{\n callbackBudget: bigint;\n protocolFee: bigint;\n total: bigint;\n}" + }, + "preflight": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "queryKey": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "resultShape": { + "optional": false, + "readonly": false, + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}" + }, + "spec": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec" + }, + "specTuple": { + "optional": false, + "readonly": false, + "type": "readonly [\n readonly [\n string,\n string,\n `0x${string}`\n ],\n `0x${string}`,\n number,\n bigint,\n bigint,\n bigint,\n `0x${string}`\n]" + }, + "value": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "warnings": { + "optional": false, + "readonly": false, + "type": "string[]" + } + } + }, + "ReadCallback": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "((spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpecTuple, callbackGasLimit: bigint) => readonly unknown[]) | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "gasLimit": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "target": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "SimulateReadResult": { + "type": "{\n args?: readonly unknown[];\n error: string;\n errorName?: string;\n ok: false;\n} | {\n ok: true;\n}", + "members": { + "ok": { + "optional": false, + "readonly": false, + "type": "boolean" + } + } + }, + "ParsedReadRequest": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ParsedReadRequest", + "members": { + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackTarget": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "logIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "originalFunder": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "requestId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "requestIdUint": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "spec": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec" + }, + "totalPaid": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "FulfilOutcome": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").FulfilOutcome", + "members": { + "burned": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "delivered": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "expired": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "failReason": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "gasReported": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refunded": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refundFailed": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "ReceiptLike": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike", + "members": { + "logs": { + "optional": false, + "readonly": false, + "type": "readonly {\n address: string;\n data: string;\n logIndex?: number | string;\n topics: readonly string[];\n}[]" + } + } + }, + "ReadRef": { + "type": "{\n requestId: `0x${string}` | bigint;\n} | {\n txHash: `0x${string}`;\n}", + "members": {} + }, + "ReadLifecycleOptions": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadLifecycleOptions", + "members": { + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "resultShape": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadFees": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadFees", + "members": { + "burned": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "paid": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "refunded": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refundFailed": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + } + } + }, + "UniversalReadResponse": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse", + "members": { + "callbackDelivered": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "callbackFailReason": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "decoded": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").DecodedReadResult | undefined" + }, + "decodeError": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destination": { + "optional": false, + "readonly": false, + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}" + }, + "errorMsg": { + "optional": false, + "readonly": false, + "type": "string" + }, + "explorerUrl": { + "optional": false, + "readonly": false, + "type": "string" + }, + "fees": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadFees" + }, + "isTerminal": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "outcome": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME" + }, + "pcTx": { + "optional": false, + "readonly": false, + "type": "readonly {\n blockHeight: number;\n errorMsg: string;\n status: string;\n txHash: `0x${string}`;\n}[]" + }, + "raw": { + "optional": false, + "readonly": false, + "type": "{\n errorCode: import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n resultData: `0x${string}`;\n status: import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n} | null" + }, + "refresh": { + "optional": false, + "readonly": false, + "type": "() => Promise>" + }, + "request": { + "optional": false, + "readonly": false, + "type": "{\n callbackGasLimit: bigint;\n callbackTarget: `0x${string}`;\n createdAtHeight: bigint;\n logIndex: number;\n originalFunder: `0x${string}`;\n refundTo: `0x${string}`;\n spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec;\n}" + }, + "requestId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "requestIdUint": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "status": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "value": { + "optional": true, + "readonly": false, + "type": "T | undefined" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/read-state/read-state.types\").ReadLifecycleOptions) => Promise>" + } + } + }, + "ReadResponseTuple": { + "type": "{\n -readonly [K in keyof R]: import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse ? T : unknown>;\n}", + "members": {} + }, + "BatchReadResponse": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").BatchReadResponse", + "members": { + "atomic": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "count": { + "optional": false, + "readonly": false, + "type": "number" + }, + "reads": { + "optional": false, + "readonly": false, + "type": "{\n -readonly [K in keyof R]: import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse ? T : unknown>;\n}" + }, + "transactionHashes": { + "optional": true, + "readonly": false, + "type": "readonly `0x${string}`[] | undefined" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: Omit) => Promise>" + } + } + }, + "ReadOptions": { + "type": "((import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">)) & {\n callback?: (Pick & Required>) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n };\n}", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "advanced": { + "optional": true, + "readonly": false, + "type": "{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n} | undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "({\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} & {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n}) | ({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick & Pick & Required>) | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadPrepareOptions": { + "type": "((((({\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\">) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n}) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">)) & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n}) | ((({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n}) | ({\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\">)) & {\n blockNumber?: never;\n minConfirmations?: never;\n})) & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n}) & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "advanced": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadQueryOptions": { + "type": "({\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\">) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n}) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n}) | ({\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\">)", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadCallbackOptions": { + "type": "{\n callback?: ({\n gasLimit?: bigint;\n target: `0x${string}`;\n } & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n };\n}", + "members": { + "callback": { + "optional": true, + "readonly": false, + "type": "({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} | undefined" + } + } + }, + "ReadValue": { + "type": "O extends {\n abi: infer A extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: infer F extends string;\n} ? number extends A[\"length\"] ? unknown : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, O extends {\n args: infer Args extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n} ? Args : readonly [\n] extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> ? import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> & readonly [\n] : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>> extends infer Selected ? Selected extends {\n outputs: readonly unknown[];\n type: \"function\";\n} & import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiFunction ? {\n [key in keyof {\n [key in keyof import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"]]: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterToPrimitiveType, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"][key], import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterKind>;\n }]: {\n [key in keyof import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"]]: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterToPrimitiveType, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"][key], import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterKind>;\n }[key];\n} extends infer types ? types extends readonly [\n] ? void : types extends readonly [\n infer type\n] ? type : types : never : never : never : O extends {\n web2: {\n extract: infer E extends readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n };\n} ? {\n readonly [K in keyof E]: {\n bool: boolean;\n bytes: `0x${string}`;\n int256: bigint;\n string: string;\n uint256: bigint;\n }[E[K][\"valueType\"]];\n} : O extends {\n storageSlot: unknown;\n} ? `0x${string}` : O extends {\n idl: infer I extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} ? string extends Extract, string> ? unknown : (O extends {\n functionName: infer N extends string;\n} ? N : undefined) extends string ? import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/index\").IdlAccounts[{\n [K in Extract, string>]: Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : K> extends Lowercase<(O extends {\n functionName: infer N extends string;\n } ? N : undefined) & string extends `${infer H}_${infer T}` ? `${H}${Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : (O extends {\n functionName: infer N extends string;\n } ? N : undefined) & string> ? K : never;\n}[Extract, string>]] : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/index\").IdlAccounts[Extract, string>] : bigint", + "members": {} + }, + "ValidateReadCall": { + "type": "O extends {\n abi: infer A extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: infer F extends string;\n} ? (readonly [\n] extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> ? {\n args?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n} : {\n args: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n}) & {\n functionName: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionName;\n} : O extends {\n functionName: infer N extends string;\n idl: infer I extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} ? string extends Extract, string> ? unknown : [\n {\n [K in Extract, string>]: Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : K> extends Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : N> ? K : never;\n }[Extract, string>]\n] extends [\n never\n] ? {\n functionName: Extract, string>;\n} : unknown : unknown", + "members": {} + }, + "ReadWeb2Options": { + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options", + "members": { + "body": { + "optional": true, + "readonly": false, + "type": "string | Uint8Array | undefined" + }, + "extract": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[]" + }, + "headers": { + "optional": true, + "readonly": false, + "type": "Record | undefined" + }, + "method": { + "optional": true, + "readonly": false, + "type": "\"GET\" | \"POST\" | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadTrackOptions": { + "type": "{\n advanced?: Omit, \"enforceGasCheck\">;\n resultShape?: import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape;\n}", + "members": { + "advanced": { + "optional": true, + "readonly": false, + "type": "Omit<{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n}, \"enforceGasCheck\"> | undefined" + }, + "resultShape": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape | undefined" + } + } + }, + "ReadExecuteOptions": { + "type": "{\n advanced?: {\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n } | undefined;\n progressHook?: ((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined;\n waitForCompletion?: boolean | undefined;\n}", + "members": { + "advanced": { + "optional": true, + "readonly": false, + "type": "{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n} | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + } + } + }, + "UNIVERSAL_READ_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS", + "members": { + "ABORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.ABORTED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.EXPIRED" + }, + "FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.FAILED" + }, + "FULFILLED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.FULFILLED" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.PENDING" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.UNSPECIFIED" + }, + "VOTING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.VOTING" + } + } + }, + "READ_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS", + "members": { + "ERROR": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.ERROR" + }, + "SUCCESS": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.SUCCESS" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.UNSPECIFIED" + } + } + }, + "READ_ERROR_CODE": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE", + "members": { + "INVALID_QUERY": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.INVALID_QUERY" + }, + "INVALID_RESULT": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.INVALID_RESULT" + }, + "NOT_FOUND": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.NOT_FOUND" + }, + "REJECTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.REJECTED" + }, + "REVERTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.REVERTED" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.UNSPECIFIED" + }, + "UNSUPPORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.UNSUPPORTED" + } + } + }, + "READ_OUTCOME": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME", + "members": { + "ABORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.ABORTED" + }, + "CALLBACK_FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.CALLBACK_FAILED" + }, + "DECODE_FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.DECODE_FAILED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.EXPIRED" + }, + "FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.FAILED" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.PENDING" + }, + "SOURCE_ERROR": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.SOURCE_ERROR" + }, + "SUCCESS": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.SUCCESS" + }, + "UNKNOWN": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.UNKNOWN" + } + } + }, + "CONTRACT_REQUEST_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS", + "members": { + "EXECUTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.EXECUTED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.EXPIRED" + }, + "NONE": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.NONE" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.PENDING" + }, + "SETTLED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.SETTLED" + } + } + }, + "TERMINAL_READ_STATUSES": { + "type": "ReadonlySet", + "members": {} + }, + "ReadStateError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadStateError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidReadQueryError": { + "type": "import(\"sdk/src/lib/read-state/errors\").InvalidReadQueryError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidReadSpecError": { + "type": "import(\"sdk/src/lib/read-state/errors\").InvalidReadSpecError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "violations": { + "optional": false, + "readonly": true, + "type": "readonly import(\"sdk/src/lib/read-state/errors\").ReadSpecViolation[]" + } + } + }, + "ReadHeightUnavailableError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadHeightUnavailableError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "UnsupportedReadDestinationError": { + "type": "import(\"sdk/src/lib/read-state/errors\").UnsupportedReadDestinationError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadDecodeError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadDecodeError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadTimeoutError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadTimeoutError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "lastStatus": { + "optional": false, + "readonly": true, + "type": "number" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadNotFoundError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadNotFoundError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadRegistryUnavailableError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadRegistryUnavailableError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadSpecViolation": { + "type": "\"CALLBACK_GAS_LIMIT_EXCEEDED\" | \"DOMAIN_BLOCKED\" | \"EMPTY_QUERY\" | \"EXCESSIVE_FEE\" | \"INSUFFICIENT_CALLBACK_BUDGET\" | \"INSUFFICIENT_FEE\" | \"INVALID_ACCOUNT_ID\" | \"INVALID_BLOCK_NUMBER\" | \"INVALID_EXPIRY_HEIGHT\" | \"INVALID_MIN_CONFIRMATIONS\" | \"SVM_OWNER_NOT_32_BYTES\" | \"ZERO_CALLBACK_BUDGET\" | \"ZERO_CALLBACK_GAS_LIMIT\" | \"ZERO_REVERT_RECIPIENT\"", + "members": {} + }, + "resolveDestination": { + "type": "(dest: import(\"sdk/src/lib/read-state/read-state.types\").ReadDestination) => import(\"sdk/src/lib/read-state/read-state.types\").ResolvedDestination", + "members": {} + }, + "encodeReadQuery": { + "type": "(destination: import(\"sdk/src/lib/read-state/read-state.types\").ReadDestination, query: import(\"sdk/src/lib/read-state/read-state.types\").ReadQuery, options?: {\n blockNumber?: bigint;\n minSlot?: bigint;\n}) => import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery", + "members": {} + }, + "decodeReadResult": { + "type": "(resultData: `0x${string}`, shape: import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape) => import(\"sdk/src/lib/read-state/read-state.types\").DecodedReadResult", + "members": {} + }, + "parseReadRequestsFromReceipt": { + "type": "(receipt: import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike, universalCallback: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").ParsedReadRequest[]", + "members": {} + }, + "parseFulfilOutcome": { + "type": "(receipt: import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike, universalCallback: `0x${string}`, requestId: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").FulfilOutcome", + "members": {} + }, + "buildReadSpecFromPreflight": { + "type": "(preflight: import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight, params: import(\"sdk/src/lib/read-state/read-state.types\").BuildReadSpecParams, defaults?: {\n refundTo?: `0x${string}`;\n}) => import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead", + "members": {} + }, + "validateReadSpec": { + "type": "(input: import(\"sdk/src/lib/read-state/validate\").ValidateReadSpecInput) => {\n ok: false;\n violations: import(\"sdk/src/lib/read-state/errors\").ReadSpecViolation[];\n} | {\n ok: true;\n}", + "members": {} + }, + "toCallData": { + "type": "(prepared: import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead, target: {\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: (spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpecTuple, callbackGasLimit: bigint) => readonly unknown[];\n functionName: string;\n}) => {\n data: `0x${string}`;\n value: bigint;\n}", + "members": {} + }, + "sizeCallbackBudget": { + "type": "(callbackGasLimit: bigint, pushGasPrice: bigint, buffer?: number) => bigint", + "members": {} + }, + "inferResultShape": { + "type": "(namespace: string, query: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape", + "members": {} + }, + "toRequestIdHex": { + "type": "(id: `0x${string}` | bigint) => `0x${string}`", + "members": {} + }, + "toReadQuery": { + "type": "(subject: string, o: ReadOptionsInput, resolvedTokenProgram?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@solana/web3.js/lib/index\").PublicKey) => import(\"sdk/src/lib/read-state/read-state.types\").ReadQuery", + "members": {} + }, + "UNIVERSAL_CALLBACK_EVM": { + "type": "readonly [\n {\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"requestExternalReadSelf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"estimateFee\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"statusOf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"enum RequestStatus\";\n readonly name: \"\";\n readonly type: \"uint8\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"isFulfilled\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getPendingRead\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly internalType: \"struct PendingRead\";\n readonly name: \"\";\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"totalEscrowed\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"blockedDomains\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly indexed: false;\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"readSpec\";\n readonly type: \"tuple\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"totalPaid\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"protocolFee\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ReadRequested\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"ReadFulfilled\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"reason\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"CallbackFailed\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"gasReported\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"burned\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"CallbackGasReported\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundSent\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundFailed\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RequestExpired\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"vaultPC\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ProtocolFeeDistributed\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidAccountId\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"EmptyQuery\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidMinConfirmations\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"DomainBlocked\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidBlockNumber\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidExpiryHeight\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroRevertRecipient\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroCallbackGasLimit\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint64\";\n readonly name: \"provided\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"max\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"CallbackGasLimitExceeded\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"required\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"InsufficientFee\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ExcessiveFee\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"actual\";\n readonly type: \"uint8\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"expected\";\n readonly type: \"uint8\";\n }\n ];\n readonly name: \"InvalidRequestStatus\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ContractIsPaused\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"CallerIsNotUCallbackModule\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n }\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"requestExternalReadSelf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n}" + }, + "1": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"estimateFee\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "2": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"statusOf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"enum RequestStatus\";\n readonly name: \"\";\n readonly type: \"uint8\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "3": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"isFulfilled\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "4": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getPendingRead\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly internalType: \"struct PendingRead\";\n readonly name: \"\";\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "5": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"totalEscrowed\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "6": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"blockedDomains\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "7": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly indexed: false;\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"readSpec\";\n readonly type: \"tuple\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"totalPaid\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"protocolFee\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ReadRequested\";\n readonly type: \"event\";\n}" + }, + "8": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"ReadFulfilled\";\n readonly type: \"event\";\n}" + }, + "9": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"reason\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"CallbackFailed\";\n readonly type: \"event\";\n}" + }, + "10": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"gasReported\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"burned\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"CallbackGasReported\";\n readonly type: \"event\";\n}" + }, + "11": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundSent\";\n readonly type: \"event\";\n}" + }, + "12": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundFailed\";\n readonly type: \"event\";\n}" + }, + "13": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RequestExpired\";\n readonly type: \"event\";\n}" + }, + "14": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"vaultPC\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ProtocolFeeDistributed\";\n readonly type: \"event\";\n}" + }, + "15": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidAccountId\";\n readonly type: \"error\";\n}" + }, + "16": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"EmptyQuery\";\n readonly type: \"error\";\n}" + }, + "17": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidMinConfirmations\";\n readonly type: \"error\";\n}" + }, + "18": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"DomainBlocked\";\n readonly type: \"error\";\n}" + }, + "19": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidBlockNumber\";\n readonly type: \"error\";\n}" + }, + "20": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidExpiryHeight\";\n readonly type: \"error\";\n}" + }, + "21": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroRevertRecipient\";\n readonly type: \"error\";\n}" + }, + "22": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroCallbackGasLimit\";\n readonly type: \"error\";\n}" + }, + "23": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint64\";\n readonly name: \"provided\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"max\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"CallbackGasLimitExceeded\";\n readonly type: \"error\";\n}" + }, + "24": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"required\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"InsufficientFee\";\n readonly type: \"error\";\n}" + }, + "25": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ExcessiveFee\";\n readonly type: \"error\";\n}" + }, + "26": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"actual\";\n readonly type: \"uint8\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"expected\";\n readonly type: \"uint8\";\n }\n ];\n readonly name: \"InvalidRequestStatus\";\n readonly type: \"error\";\n}" + }, + "27": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ContractIsPaused\";\n readonly type: \"error\";\n}" + }, + "28": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"CallerIsNotUCallbackModule\";\n readonly type: \"error\";\n}" + }, + "29": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n}" + }, + "length": { + "optional": false, + "readonly": true, + "type": "30" + } + } + }, + "UNIVERSAL_READ_REGISTRY_EVM": { + "type": "readonly [\n {\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n },\n {\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"read\";\n readonly outputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"universalCallback_\";\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"constructor\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"initialize\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getLocalContext\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"hasResult\";\n readonly outputs: readonly [\n {\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"onUniversalData\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"queryKeyOf\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes32\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"readerOf\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"requestOrderOf\";\n readonly outputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"universalCallback\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"resultByRequestId\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"latestResult\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"version\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"Initialized\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadRequested\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadStored\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidInitialization\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"NotInitializing\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroAddressInit\";\n readonly type: \"error\";\n }\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n },\n {\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"read\";\n readonly outputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n}" + }, + "1": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"universalCallback_\";\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"constructor\";\n}" + }, + "2": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"initialize\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n}" + }, + "3": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getLocalContext\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "4": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"hasResult\";\n readonly outputs: readonly [\n {\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "5": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"onUniversalData\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n}" + }, + "6": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"queryKeyOf\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes32\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "7": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"readerOf\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "8": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"requestOrderOf\";\n readonly outputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "9": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"universalCallback\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "10": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"resultByRequestId\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "11": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"latestResult\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "12": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"version\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"Initialized\";\n readonly type: \"event\";\n}" + }, + "13": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadRequested\";\n readonly type: \"event\";\n}" + }, + "14": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadStored\";\n readonly type: \"event\";\n}" + }, + "15": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidInitialization\";\n readonly type: \"error\";\n}" + }, + "16": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"NotInitializing\";\n readonly type: \"error\";\n}" + }, + "17": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n}" + }, + "18": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroAddressInit\";\n readonly type: \"error\";\n}" + }, + "length": { + "optional": false, + "readonly": true, + "type": "19" + } + } + }, + "PushChainExecutionError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").PushChainExecutionError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PushChainBatchExecutionError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").PushChainBatchExecutionError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": false, + "readonly": true, + "type": "`0x${string}`[]" + } + } + }, + "DecodedErrorPayload": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload", + "members": { + "decoded": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "name": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "selector": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "PushChainInitializeOptions": { + "type": "import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions", + "members": { + "agenticWallet": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "blockExplorers": { + "optional": true, + "readonly": false, + "type": "Partial> | undefined" + }, + "network": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "printTraces": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "rpcUrls": { + "optional": true, + "readonly": false, + "type": "Partial> | undefined" + } + } + }, + "AGENTIC_ERROR_CODE": { + "type": "{\n readonly AGENT_GAS_INSUFFICIENT: \"AGENT_GAS_INSUFFICIENT\";\n readonly AGENT_IS_OWNER: \"AGENT_IS_OWNER\";\n readonly AMBIGUOUS_RULE: \"AMBIGUOUS_RULE\";\n readonly ASSET_CHAIN_MISMATCH: \"ASSET_CHAIN_MISMATCH\";\n readonly CAPABILITY_UNAVAILABLE: \"CAPABILITY_UNAVAILABLE\";\n readonly DELETE_NEEDS_TARGET: \"DELETE_NEEDS_TARGET\";\n readonly DUPLICATE_RULE: \"DUPLICATE_RULE\";\n readonly FROM_NOT_ALLOWED: \"FROM_NOT_ALLOWED\";\n readonly INCONSISTENT_READ: \"INCONSISTENT_READ\";\n readonly INDEX_RACE: \"INDEX_RACE\";\n readonly INVALID_RULE: \"INVALID_RULE\";\n readonly NO_RULES_FOR_CHAIN: \"NO_RULES_FOR_CHAIN\";\n readonly NOT_AGENTIC_WALLET: \"NOT_AGENTIC_WALLET\";\n readonly NOT_ALLOWED_IN_AGENTIC_MODE: \"NOT_ALLOWED_IN_AGENTIC_MODE\";\n readonly NOT_OWNER_OR_AGENT: \"NOT_OWNER_OR_AGENT\";\n readonly NOT_WALLET_OWNER: \"NOT_WALLET_OWNER\";\n readonly READ_ONLY: \"READ_ONLY\";\n readonly RECEIPT_MISMATCH: \"RECEIPT_MISMATCH\";\n readonly RECEIPT_UNAVAILABLE: \"RECEIPT_UNAVAILABLE\";\n readonly REQUEST_REJECTED: \"REQUEST_REJECTED\";\n readonly RULE_NOT_FOUND: \"RULE_NOT_FOUND\";\n readonly RULE_READ_FAILED: \"RULE_READ_FAILED\";\n readonly TARGET_NOT_ON_RULE_CHAIN: \"TARGET_NOT_ON_RULE_CHAIN\";\n readonly TOKEN_ROUTE_UNAVAILABLE: \"TOKEN_ROUTE_UNAVAILABLE\";\n readonly WALLET_BALANCE_INSUFFICIENT: \"WALLET_BALANCE_INSUFFICIENT\";\n readonly WALLET_NOT_DEPLOYED: \"WALLET_NOT_DEPLOYED\";\n}", + "members": { + "AGENT_GAS_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\"" + }, + "AGENT_IS_OWNER": { + "optional": false, + "readonly": true, + "type": "\"AGENT_IS_OWNER\"" + }, + "AMBIGUOUS_RULE": { + "optional": false, + "readonly": true, + "type": "\"AMBIGUOUS_RULE\"" + }, + "ASSET_CHAIN_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"ASSET_CHAIN_MISMATCH\"" + }, + "CAPABILITY_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"CAPABILITY_UNAVAILABLE\"" + }, + "DELETE_NEEDS_TARGET": { + "optional": false, + "readonly": true, + "type": "\"DELETE_NEEDS_TARGET\"" + }, + "DUPLICATE_RULE": { + "optional": false, + "readonly": true, + "type": "\"DUPLICATE_RULE\"" + }, + "FROM_NOT_ALLOWED": { + "optional": false, + "readonly": true, + "type": "\"FROM_NOT_ALLOWED\"" + }, + "INCONSISTENT_READ": { + "optional": false, + "readonly": true, + "type": "\"INCONSISTENT_READ\"" + }, + "INDEX_RACE": { + "optional": false, + "readonly": true, + "type": "\"INDEX_RACE\"" + }, + "INVALID_RULE": { + "optional": false, + "readonly": true, + "type": "\"INVALID_RULE\"" + }, + "NO_RULES_FOR_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"NO_RULES_FOR_CHAIN\"" + }, + "NOT_AGENTIC_WALLET": { + "optional": false, + "readonly": true, + "type": "\"NOT_AGENTIC_WALLET\"" + }, + "NOT_ALLOWED_IN_AGENTIC_MODE": { + "optional": false, + "readonly": true, + "type": "\"NOT_ALLOWED_IN_AGENTIC_MODE\"" + }, + "NOT_OWNER_OR_AGENT": { + "optional": false, + "readonly": true, + "type": "\"NOT_OWNER_OR_AGENT\"" + }, + "NOT_WALLET_OWNER": { + "optional": false, + "readonly": true, + "type": "\"NOT_WALLET_OWNER\"" + }, + "READ_ONLY": { + "optional": false, + "readonly": true, + "type": "\"READ_ONLY\"" + }, + "RECEIPT_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_MISMATCH\"" + }, + "RECEIPT_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_UNAVAILABLE\"" + }, + "REQUEST_REJECTED": { + "optional": false, + "readonly": true, + "type": "\"REQUEST_REJECTED\"" + }, + "RULE_NOT_FOUND": { + "optional": false, + "readonly": true, + "type": "\"RULE_NOT_FOUND\"" + }, + "RULE_READ_FAILED": { + "optional": false, + "readonly": true, + "type": "\"RULE_READ_FAILED\"" + }, + "TARGET_NOT_ON_RULE_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"TARGET_NOT_ON_RULE_CHAIN\"" + }, + "TOKEN_ROUTE_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"TOKEN_ROUTE_UNAVAILABLE\"" + }, + "WALLET_BALANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"WALLET_BALANCE_INSUFFICIENT\"" + }, + "WALLET_NOT_DEPLOYED": { + "optional": false, + "readonly": true, + "type": "\"WALLET_NOT_DEPLOYED\"" + } + } + }, + "AgenticError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "Code" + }, + "details": { + "optional": true, + "readonly": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "userMessage": { + "optional": false, + "readonly": true, + "type": "string" + } + } + }, + "AgenticRevertError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticRevertError", + "members": { + "agenticCode": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "userMessage": { + "optional": false, + "readonly": true, + "type": "string" + } + } + }, + "AgenticAddress": { + "type": "`0x${string}`", + "members": {} + }, + "AgenticDoor": { + "type": "\"agent\" | \"owner\"", + "members": {} + }, + "AgenticErrorCode": { + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"AMBIGUOUS_RULE\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"DELETE_NEEDS_TARGET\" | \"DUPLICATE_RULE\" | \"FROM_NOT_ALLOWED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"REQUEST_REJECTED\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"TOKEN_ROUTE_UNAVAILABLE\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"", + "members": {} + }, + "AgenticHex": { + "type": "`0x${string}`", + "members": {} + }, + "AgenticNamespace": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace", + "members": { + "create": { + "optional": false, + "readonly": false, + "type": "(label: string, options: import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions) => Promise" + }, + "derive": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n index?: number;\n}) => Promise<{\n address: `0x${string}`;\n deployed: boolean;\n index: number;\n}>" + }, + "list": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n wallets: import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary[];\n}>" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "(address: `0x${string}`) => import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet" + } + } + }, + "AgenticProgressHook": { + "type": "(event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void", + "members": {} + }, + "AgenticTxMetadata": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticTxMetadata", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destinationAccount": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "destinationCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "destinationInstruction": { + "optional": true, + "readonly": false, + "type": "{\n accounts: readonly {\n isWritable: boolean;\n pubkey: `0x${string}`;\n }[];\n data: `0x${string}`;\n program: `0x${string}`;\n} | undefined" + }, + "destinationTransfer": { + "optional": true, + "readonly": false, + "type": "{\n amount: bigint;\n recipient: `0x${string}`;\n token: `0x${string}`;\n} | undefined" + }, + "door": { + "optional": false, + "readonly": false, + "type": "\"agent\" | \"owner\"" + }, + "nativeCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "rawData": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rawTo": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesId": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticWallet": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "checkpoints": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n sinceBlock?: bigint;\n}) => Promise<{\n checkpoints: import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint[];\n}>" + }, + "info": { + "optional": false, + "readonly": false, + "type": "() => Promise" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n owner: `0x${string}`;\n}>" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "{\n add(rules: import(\"sdk/src/lib/agentic/agentic.types\").RuleInput[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise<{\n rulesIds: `0x${string}`[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n delete(rulesIds: `0x${string}`[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n delete(params: {\n all: true;\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n get(rulesId: `0x${string}`): Promise;\n list(): Promise<{\n rules: import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord[];\n }>;\n update(params: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n rules: {\n rule: import(\"sdk/src/lib/agentic/agentic.types\").RuleInput;\n rulesId: `0x${string}`;\n }[];\n }): Promise<{\n rules: {\n replaced: `0x${string}`;\n rulesId: `0x${string}`;\n }[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n}" + }, + "setLabel": { + "optional": false, + "readonly": false, + "type": "(label: string, opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n}) => Promise" + } + } + }, + "AllowedCall": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleCall", + "members": { + "app": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "label": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "maxValue": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "pins": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Pin[] | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector" + }, + "target": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "AssetCap": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset", + "members": { + "maxPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/tokens\").MoveableToken | string" + } + } + }, + "Checkpoint": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint", + "members": { + "blockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "kind": { + "optional": false, + "readonly": false, + "type": "\"OWNER_ACTION\" | \"RULES_GRANTED\" | \"RULES_REVOKED\"" + }, + "ref": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "seq": { + "optional": false, + "readonly": false, + "type": "number" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "CheckpointKind": { + "type": "\"OWNER_ACTION\" | \"RULES_GRANTED\" | \"RULES_REVOKED\"", + "members": {} + }, + "CreateOptions": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions", + "members": { + "progressHook": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook | undefined" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleInput[]" + } + } + }, + "CreateResult": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateResult", + "members": { + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "rulesIds": { + "optional": false, + "readonly": false, + "type": "`0x${string}`[]" + }, + "tx": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ForeignChainNamespace": { + "type": "`eip155:${string}` | `solana:${string}`", + "members": {} + }, + "DecodedSolanaRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").DecodedSolanaRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "assets": { + "optional": false, + "readonly": false, + "type": "{\n maxPerCall: bigint;\n maxTotal: bigint;\n token: string;\n}[]" + }, + "ceaAccounts": { + "optional": false, + "readonly": false, + "type": "readonly `0x${string}`[]" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "`solana:${string}`" + }, + "dataPins": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/agentic/codec/svm-terms\").SvmDataPinWire[]" + }, + "expectedCEA": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "format": { + "optional": false, + "readonly": false, + "type": "\"decoded\"" + }, + "gatewayProgram": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "maxGasPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pins": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/agentic/codec/svm-terms\").SvmAccountPinWire[]" + }, + "programs": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/agentic/codec/svm-terms\").AllowedProgramWire[]" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Rule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Rule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleCall[]" + }, + "assets": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset[] | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "maxGasPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "RuleInput": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").DecodedSolanaRule | import(\"sdk/src/lib/agentic/agentic.types\").Rule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "assets": { + "optional": true, + "readonly": false, + "type": "{\n maxPerCall: bigint;\n maxTotal: bigint;\n token: string;\n}[] | import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset[] | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "maxGasPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Pin": { + "type": "{\n account: number;\n arg?: never;\n expected: \"agentic:wallet\" | string;\n max?: never;\n token?: import(\"sdk/src/lib/constants/tokens\").MoveableToken | string;\n} | {\n account?: never;\n arg: import(\"sdk/src/lib/agentic/agentic.types\").ArgumentPath;\n expected: \"agentic:wallet\" | `0x${string}` | `0x${string}` | bigint;\n max?: never;\n} | {\n account?: never;\n arg: import(\"sdk/src/lib/agentic/agentic.types\").ArgumentPath;\n expected?: never;\n max: bigint;\n}", + "members": { + "account": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "arg": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ArgumentPath | undefined" + }, + "expected": { + "optional": true, + "readonly": false, + "type": "bigint | string | undefined" + }, + "max": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "Spent": { + "type": "{\n actions: {\n amountSpent: bigint;\n callsUsed: number;\n selector: \"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector;\n target: `0x${string}`;\n valueSpent: bigint;\n }[];\n kind: \"native\";\n} | {\n amountSpent: bigint;\n callsUsed: number;\n kind: \"native\";\n valueSpent: bigint;\n} | {\n assets: {\n spent: bigint;\n token: string;\n }[];\n kind: \"universal\";\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"native\" | \"universal\"" + } + } + }, + "WalletMarker": { + "type": "\"agentic:wallet\"", + "members": {} + }, + "ArgumentPath": { + "type": "number | readonly number[]", + "members": {} + }, + "RulesRecord": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "enabled": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "rule": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").DecodedSolanaRule | import(\"sdk/src/lib/agentic/agentic.types\").Rule" + }, + "rulesId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "spent": { + "optional": false, + "readonly": false, + "type": "{\n actions: {\n amountSpent: bigint;\n callsUsed: number;\n selector: \"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector;\n target: `0x${string}`;\n valueSpent: bigint;\n }[];\n kind: \"native\";\n} | {\n amountSpent: bigint;\n callsUsed: number;\n kind: \"native\";\n valueSpent: bigint;\n} | {\n assets: {\n spent: bigint;\n token: string;\n }[];\n kind: \"universal\";\n}" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Selector": { + "type": "`${string}(${string})` | `0x${string}`", + "members": {} + }, + "WalletInfo": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").WalletInfo", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "label": { + "optional": false, + "readonly": false, + "type": "string" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "rulesCount": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "WalletSummary": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "label": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesCount": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "PushChain": { + "type": "import(\"sdk/src/lib/push-chain/push-chain\").PushChain", + "members": { + "accountStatus": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus" + }, + "accountStatusReady": { + "optional": false, + "readonly": false, + "type": "Promise" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace" + }, + "explorer": { + "optional": false, + "readonly": false, + "type": "{\n getTransactionUrl: (txHash: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n listAllUrls: () => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n listUrls: (options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n}" + }, + "funds": { + "optional": false, + "readonly": false, + "type": "{\n getConversionQuote: (amountIn: bigint, options: {\n from: import(\"sdk/src/lib/constants/tokens\").PayableToken | undefined;\n to: import(\"sdk/src/lib/constants/tokens\").MoveableToken | undefined;\n }) => Promise;\n}" + }, + "getAccountStatus": { + "optional": false, + "readonly": false, + "type": "(options?: {\n forceRefresh?: boolean;\n}) => Promise" + }, + "isReadMode": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "job": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/job/types\").JobNamespace" + }, + "market": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/market/types\").MarketNamespace" + }, + "moveable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").MoveableTokenAccessor;\n}" + }, + "payable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").PayableTokenAccessor;\n}" + }, + "reinitialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "universal": { + "optional": false, + "readonly": false, + "type": "{\n readonly account: `0x${string}`;\n executeReads: (reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>;\n executeTransactions: (txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise;\n migrateCEA: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"migrateCEA\"];\n readonly origin: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n prepareRead: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n prepareTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"prepareTransaction\"];\n read: ((subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>) & {\n prepare: (options: import(\"sdk/src/lib/job-spec/types\").PrepareJobReadOptions) => import(\"sdk/src/lib/job-spec/types\").PreparedJobRead;\n };\n rescueFunds: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"rescueFunds\"];\n sendTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"execute\"];\n signMessage: (data: Uint8Array) => Promise;\n signTypedData: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n trackRead: {\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n };\n trackTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"trackTransaction\"];\n}" + }, + "upgradeAccount": { + "optional": false, + "readonly": false, + "type": "(options?: {\n progressHook?: (progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n}) => Promise" + } + } + }, + "Preset": { + "type": "import(\"sdk/src/lib/agentic/presets/types\").Preset", + "members": { + "chains": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace[]" + }, + "constant": { + "optional": false, + "readonly": false, + "type": "\"DEXES\" | \"LENDING\" | \"PREDICTION\" | \"STAKING\"" + }, + "name": { + "optional": false, + "readonly": false, + "type": "string" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"CATEGORY\"" + } + } + }, + "PresetCategory": { + "type": "\"DEXES\" | \"LENDING\" | \"PREDICTION\" | \"STAKING\"", + "members": {} + }, + "PresetAsset": { + "type": "import(\"sdk/src/lib/agentic/presets/types\").PresetAsset", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "maxPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/tokens\").MoveableToken | string" + } + } + }, + "PresetOptions": { + "type": "import(\"sdk/src/lib/agentic/presets/types\").PresetOptions", + "members": { + "agent": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "assets": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/presets/types\").PresetAsset[] | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "funding": { + "optional": true, + "readonly": false, + "type": "\"destination\" | \"push\" | undefined" + }, + "maxGasPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "network": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK | undefined" + }, + "validUntil": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadyPresetOptions": { + "type": "import(\"sdk/src/lib/agentic/presets/types\").ReadyPresetOptions", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "assets": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/presets/types\").PresetAsset[] | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "funding": { + "optional": true, + "readonly": false, + "type": "\"destination\" | \"push\" | undefined" + }, + "maxGasPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "network": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK | undefined" + }, + "validUntil": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "PresetRuleTemplate": { + "type": "{\n agent?: `0x${string}`;\n validUntil?: number;\n} & Omit", + "members": { + "agent": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleCall[]" + }, + "assets": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset[] | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "maxGasPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "validUntil": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "PresetResult": { + "type": "import(\"sdk/src/lib/agentic/presets/types\").PresetResult", + "members": { + "readiness": { + "optional": false, + "readonly": false, + "type": "{\n chains: import(\"sdk/src/lib/agentic/presets/types\").PresetChainReadiness[];\n ready: boolean;\n}" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "T[]" + } + } + }, + "PresetChainReadiness": { + "type": "import(\"sdk/src/lib/agentic/presets/types\").PresetChainReadiness", + "members": { + "bridgeAssets": { + "optional": false, + "readonly": false, + "type": "{\n prc20?: `0x${string}`;\n status: \"registered\" | \"unavailable\";\n token: string;\n}[]" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "`eip155:${string}` | `solana:${string}`" + }, + "configurationReady": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "disabledCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/presets/types\").PresetCallIssue[]" + }, + "excludedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/presets/types\").PresetCallIssue[]" + }, + "funding": { + "optional": false, + "readonly": false, + "type": "\"destination\" | \"push\"" + }, + "issues": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/presets/types\").PresetConfigurationIssue[]" + }, + "knownTokens": { + "optional": false, + "readonly": false, + "type": "string[]" + }, + "ready": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "selectedAssets": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset[]" + }, + "zeroBridgeLimits": { + "optional": false, + "readonly": false, + "type": "string[]" + } + } + }, + "PresetConfigurationIssue": { + "type": "import(\"sdk/src/lib/agentic/presets/types\").PresetConfigurationIssue", + "members": { + "code": { + "optional": false, + "readonly": false, + "type": "\"AGENT_REQUIRED\" | \"AGW_NETWORK_UNAVAILABLE\" | \"ASSETS_REQUIRED\" | \"BRIDGE_ASSET_UNAVAILABLE\" | \"DESTINATION_UNAVAILABLE\" | \"EXPIRY_REQUIRED\" | \"GAS_BUDGET_REQUIRED\" | \"NO_ENABLED_OPERATION\" | \"TOKEN_PAIR_REQUIRED\"" + }, + "message": { + "optional": false, + "readonly": false, + "type": "string" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "PresetCallIssue": { + "type": "import(\"sdk/src/lib/agentic/presets/types\").PresetCallIssue", + "members": { + "alternative": { + "optional": true, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector | undefined" + }, + "app": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "reason": { + "optional": false, + "readonly": false, + "type": "\"DYNAMIC_AMOUNT\" | \"POSITION_AMOUNT\" | \"SHARE_AMOUNT\" | \"TOKEN_REQUIRED\" | \"UNSELECTED_TOKEN\" | \"ZERO_CAP\"" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector" + }, + "target": { + "optional": false, + "readonly": false, + "type": "string" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "AgenticPresets": { + "type": "import(\"sdk/src/lib/agentic/presets/types\").AgenticPresets", + "members": { + "get": { + "optional": false, + "readonly": false, + "type": "{\n (preset: import(\"sdk/src/lib/agentic/presets/types\").PresetCategory, options: import(\"sdk/src/lib/agentic/presets/types\").ReadyPresetOptions): import(\"sdk/src/lib/agentic/presets/types\").PresetResult;\n (preset: import(\"sdk/src/lib/agentic/presets/types\").PresetCategory, options?: import(\"sdk/src/lib/agentic/presets/types\").PresetOptions): import(\"sdk/src/lib/agentic/presets/types\").PresetResult;\n}" + }, + "list": { + "optional": false, + "readonly": false, + "type": "(options?: {\n type?: \"CATEGORY\";\n}) => {\n presets: import(\"sdk/src/lib/agentic/presets/types\").Preset[];\n}" + } + } + } + }, + "pushChainStatic": { + "CONSTANTS": { + "optional": false, + "readonly": false, + "type": "{\n AGENTIC: Readonly<{\n JOB: Readonly<{\n ADDRESS: Readonly<{\n \"eip155:42101\": Readonly<{\n EVALUATOR: \"0x1afC81396f1bb36F91f74506284952b81e4bd47c\";\n HOOK: \"0xDe7A94e510b6C571DE7880d441349689F73A32b3\";\n KERNEL: \"0x977cf1AC973E9eC4332791d531507575006157Ed\";\n }>;\n }>;\n ALLOWED_MUTABILITY: Readonly<{\n readonly BOTH: \"BOTH\";\n readonly CLIENT: \"CLIENT\";\n readonly NONE: \"NONE\";\n readonly PROVIDER: \"PROVIDER\";\n }>;\n EVALUATION: Readonly<{\n readonly BOOLEAN: \"BOOLEAN\";\n readonly COMPARE: \"COMPARE\";\n readonly NUMBER: \"NUMBER\";\n readonly PERCENTAGE: \"PERCENTAGE\";\n }>;\n LOGIC: Readonly<{\n readonly ALL: \"ALL\";\n readonly ANY: \"ANY\";\n readonly AT_LEAST: \"AT_LEAST\";\n }>;\n OPERATION: Readonly<{\n readonly EQUAL: \"EQUAL\";\n readonly GREATER_OR_EQUAL: \"GREATER_OR_EQUAL\";\n readonly GREATER_THAN: \"GREATER_THAN\";\n readonly LESS_OR_EQUAL: \"LESS_OR_EQUAL\";\n readonly LESS_THAN: \"LESS_THAN\";\n readonly NOT_EQUAL: \"NOT_EQUAL\";\n }>;\n }>;\n PRESETS: Readonly<{\n CATEGORY: Readonly<{\n DEXES: \"DEXES\";\n LENDING: \"LENDING\";\n PREDICTION: \"PREDICTION\";\n STAKING: \"STAKING\";\n }>;\n }>;\n PRINCIPAL: \"agentic:principal\";\n WALLET: \"agentic:wallet\";\n }>;\n CHAIN: typeof import(\"sdk/src/lib/constants/enums\").CHAIN;\n LIBRARY: typeof import(\"sdk/src/lib/constants/enums\").LIBRARY;\n MOVEABLE: {\n TOKEN: import(\"sdk/src/lib/constants/tokens\").MoveableTokenConstantsMap;\n };\n PAYABLE: {\n TOKEN: import(\"sdk/src/lib/constants/tokens\").PayableTokenConstantsMap;\n };\n PUSH_NETWORK: typeof import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n READ: {\n readonly CALLBACK_BUDGET_BUFFER: 3;\n readonly CHAIN: {\n readonly WEB2: \"web2\";\n } & Readonly<{\n readonly ARBITRUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA;\n readonly BASE_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA;\n readonly BNB_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET;\n readonly ETHEREUM_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET;\n readonly ETHEREUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA;\n readonly PUSH_LOCALNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET;\n readonly PUSH_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET;\n readonly PUSH_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly PUSH_TESTNET_DONUT: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly SOLANA_DEVNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET;\n readonly SOLANA_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET;\n readonly SOLANA_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n readonly WEB2: \"web2\";\n }>;\n readonly DEFAULT_EXPIRY_BLOCKS: 300n;\n readonly ERROR_CODE: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n readonly MAX_CALLBACK_GAS_LIMIT: 1000000n;\n readonly MIN_CONFIRMATIONS_FLOOR: 1;\n readonly NAMESPACE: {\n readonly EVM: \"eip155\";\n readonly SVM: \"solana\";\n readonly WEB2: \"web2\";\n };\n readonly OUTCOME: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME;\n readonly REGISTRY_CALLBACK_GAS: 500000n;\n readonly RESULT_STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n readonly STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS;\n readonly UNIVERSAL_CALLBACK_ADDRESSES: Record;\n readonly UNIVERSAL_CORE_ADDRESSES: Record;\n readonly UNIVERSAL_READ_REGISTRY_ADDRESS: {\n readonly TESTNET_DONUT: \"0x00000000000000000000000000000000000000b2\";\n };\n readonly WEB2: \"web2\";\n readonly WEB2_DEFAULT_TIMEOUT_MS: 5000;\n readonly WEB2_MAX_EXTRACT_ENTRIES: 16;\n };\n}" + }, + "initialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "utils": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/utils\").Utils" + } + }, + "pushChainInstance": { + "accountStatus": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus" + }, + "accountStatusReady": { + "optional": false, + "readonly": false, + "type": "Promise" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace" + }, + "explorer": { + "optional": false, + "readonly": false, + "type": "{\n getTransactionUrl: (txHash: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n listAllUrls: () => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n listUrls: (options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n}" + }, + "funds": { + "optional": false, + "readonly": false, + "type": "{\n getConversionQuote: (amountIn: bigint, options: {\n from: import(\"sdk/src/lib/constants/tokens\").PayableToken | undefined;\n to: import(\"sdk/src/lib/constants/tokens\").MoveableToken | undefined;\n }) => Promise;\n}" + }, + "getAccountStatus": { + "optional": false, + "readonly": false, + "type": "(options?: {\n forceRefresh?: boolean;\n}) => Promise" + }, + "isReadMode": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "job": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/job/types\").JobNamespace" + }, + "market": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/market/types\").MarketNamespace" + }, + "moveable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").MoveableTokenAccessor;\n}" + }, + "payable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").PayableTokenAccessor;\n}" + }, + "reinitialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "universal": { + "optional": false, + "readonly": false, + "type": "{\n readonly account: `0x${string}`;\n executeReads: (reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>;\n executeTransactions: (txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise;\n migrateCEA: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"migrateCEA\"];\n readonly origin: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n prepareRead: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n prepareTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"prepareTransaction\"];\n read: ((subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>) & {\n prepare: (options: import(\"sdk/src/lib/job-spec/types\").PrepareJobReadOptions) => import(\"sdk/src/lib/job-spec/types\").PreparedJobRead;\n };\n rescueFunds: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"rescueFunds\"];\n sendTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"execute\"];\n signMessage: (data: Uint8Array) => Promise;\n signTypedData: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n trackRead: {\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n };\n trackTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"trackTransaction\"];\n}" + }, + "upgradeAccount": { + "optional": false, + "readonly": false, + "type": "(options?: {\n progressHook?: (progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n}) => Promise" + } + }, + "transactionMethods": { + "account": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "executeReads": { + "optional": false, + "readonly": false, + "type": "(reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>" + }, + "executeTransactions": { + "optional": false, + "readonly": false, + "type": "(txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise" + }, + "migrateCEA": { + "optional": false, + "readonly": false, + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => Promise" + }, + "origin": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "prepareRead": { + "optional": false, + "readonly": false, + "type": "(subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>" + }, + "prepareTransaction": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions) => Promise" + }, + "read": { + "optional": false, + "readonly": false, + "type": "((subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>) & {\n prepare: (options: import(\"sdk/src/lib/job-spec/types\").PrepareJobReadOptions) => import(\"sdk/src/lib/job-spec/types\").PreparedJobRead;\n}" + }, + "rescueFunds": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").RescueFundsParams) => Promise" + }, + "sendTransaction": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").ExecuteParams | import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions) => Promise" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": false, + "readonly": false, + "type": "({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise" + }, + "trackRead": { + "optional": false, + "readonly": false, + "type": "{\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n}" + }, + "trackTransaction": { + "optional": false, + "readonly": false, + "type": "(txHash: string, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TrackTransactionOptions) => Promise" + } + }, + "utilityMethods": { + "account": { + "optional": false, + "readonly": false, + "type": "{\n convertExecutorToOriginAccount: (ueaAddress: `0x${string}`, options?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n }) => Promise;\n convertOriginToExecutor: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n onlyCompute?: boolean;\n }) => Promise;\n deriveExecutorAccount: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n skipNetworkCheck?: boolean;\n }) => Promise;\n fromChainAgnostic: (caip: string) => import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n resolveControllerAccount: (address: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n skipNetworkCheck?: boolean;\n }) => Promise;\n toChainAgnostic: (address: string, options: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n toUniversal: (address: string, options: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n}" + }, + "agentic": { + "optional": false, + "readonly": true, + "type": "{\n readonly presets: import(\"sdk/src/lib/agentic/presets/types\").AgenticPresets;\n}" + }, + "chains": { + "optional": false, + "readonly": false, + "type": "{\n getChainName: (chainNamespace: string) => string | undefined;\n getChainNamespace: (chainName: string) => string | undefined;\n getSupportedChains: (network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK) => {\n chains: import(\"sdk/src/lib/constants/enums\").CHAIN[];\n };\n getSupportedChainsByName: (network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK) => {\n chains: string[];\n };\n}" + }, + "conversion": { + "optional": false, + "readonly": false, + "type": "{\n slippageToMinAmount(amount: string, options: {\n slippageBps: number;\n }): string;\n}" + }, + "helpers": { + "optional": false, + "readonly": false, + "type": "{\n encodeTxData({ abi, idl, functionName, args, }: {\n abi?: any;\n args?: any[];\n functionName: string;\n idl?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n }): `0x${string}`;\n formatUnits(value: bigint | string, decimalsOrOptions: {\n decimals: number;\n precision?: number;\n } | number): string;\n getChainName: (chainName: string) => string | undefined;\n parseUnits(value: string, exponent: {\n decimals: number;\n } | number): bigint;\n}" + }, + "job": { + "optional": false, + "readonly": true, + "type": "{\n readonly buildJobSpec: (options: import(\"sdk/src/lib/job-spec/types\").BuildJobSpecOptions) => import(\"sdk/src/lib/job-spec/types\").JobSpec;\n readonly buildJobSpecTemplate: (options: import(\"sdk/src/lib/job-spec/types\").BuildJobSpecTemplateOptions) => import(\"sdk/src/lib/job-spec/types\").JobSpecTemplate;\n readonly decodeJobSpec: (bytes: `0x${string}`, options?: {\n format?: \"spec\" | \"template\";\n }) => import(\"sdk/src/lib/job-spec/types\").JobSpec | import(\"sdk/src/lib/job-spec/types\").JobSpecTemplate;\n readonly describeJobSpec: (spec: import(\"sdk/src/lib/job-spec/types\").JobSpec | import(\"sdk/src/lib/job-spec/types\").JobSpecTemplate, options?: {\n decimals?: Record<`0x${string}`, number>;\n principal?: bigint;\n }) => {\n checks: string[];\n logic: string;\n timing: string;\n };\n readonly encodeJobSpec: (spec: import(\"sdk/src/lib/job-spec/types\").JobSpec | import(\"sdk/src/lib/job-spec/types\").JobSpecTemplate) => `0x${string}`;\n readonly prepareRead: (options: import(\"sdk/src/lib/job-spec/types\").PrepareJobReadOptions) => import(\"sdk/src/lib/job-spec/types\").PreparedJobRead;\n readonly previewJobSpec: (_spec: import(\"sdk/src/lib/job-spec/types\").JobSpec | import(\"sdk/src/lib/job-spec/types\").JobSpecTemplate, _options: import(\"sdk/src/lib/job-spec/types\").PreviewJobSpecOptions) => Promise;\n}" + }, + "market": { + "optional": false, + "readonly": true, + "type": "{\n readonly decodeAgentCardRules: (bytes: `0x${string}`, _options?: {\n chain?: string;\n }) => import(\"sdk/src/lib/market/rules\").AgentCardRules;\n readonly encodeAgentCardRules: (rules: import(\"sdk/src/lib/market/rules\").AgentCardRules, options: {\n chain: string;\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n }) => `0x${string}`;\n readonly validateAgentCardRules: (rules: import(\"sdk/src/lib/market/rules\").AgentCardRules) => void;\n}" + }, + "signer": { + "optional": false, + "readonly": false, + "type": "{\n construct: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options: {\n signAndSendTransaction: (unsignedTx: Uint8Array) => Promise;\n signAuthorization?: (params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise;\n signMessage: (data: Uint8Array) => Promise;\n signTypedData?: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n }) => import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton;\n toUniversal: (signer: import(\"sdk/src/lib/universal/universal.types\").EthersV5SignerType | import(\"sdk/src/lib/universal/universal.types\").EthersV6SignerType | import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton | import(\"sdk/src/lib/universal/universal.types\").ViemSignerType) => Promise;\n toUniversalFromKeypair: (clientOrAccount: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@solana/web3.js/lib/index\").Keypair | import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").WalletClient | import(\"sdk/src/lib/universal/universal.types\").EthersV6SignerType, { chain, library }: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n library: import(\"sdk/src/lib/constants/enums\").LIBRARY;\n }) => Promise;\n}" + }, + "svm": { + "optional": false, + "readonly": false, + "type": "{\n getRegisteredIdls: () => Array<{\n address: `0x${string}`;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n }>;\n registerIdl: (idl: unknown) => void;\n}" + }, + "tokens": { + "optional": false, + "readonly": false, + "type": "{\n getMoveableTokens(chainOrClient?: import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/push-chain/push-chain\").PushChain): {\n tokens: Array<{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n decimals: number;\n mechanism: \"approve\" | \"native\" | \"permit2\";\n prc20Address?: `0x${string}`;\n sourceChain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n symbol: string;\n }>;\n };\n getPayableTokens(chainOrClient?: import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/push-chain/push-chain\").PushChain): {\n tokens: Array<{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n decimals: number;\n mechanism: \"approve\" | \"native\" | \"permit2\";\n symbol: string;\n }>;\n };\n getPC20Address(address: string, options: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n rpcUrls?: Partial>;\n strict?: boolean;\n }): Promise;\n getPRC20Address: (token: {\n address: string;\n chain: string;\n } | import(\"sdk/src/lib/constants/tokens\").MoveableToken, options?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n }) => {\n address: `0x${string}`;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n decimals: number;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n symbol: string;\n };\n}" + } + }, + "initialize": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise", + "agwConstants": { + "JOB": { + "optional": false, + "readonly": true, + "type": "{\n readonly ADDRESS: Readonly<{\n \"eip155:42101\": Readonly<{\n EVALUATOR: \"0x1afC81396f1bb36F91f74506284952b81e4bd47c\";\n HOOK: \"0xDe7A94e510b6C571DE7880d441349689F73A32b3\";\n KERNEL: \"0x977cf1AC973E9eC4332791d531507575006157Ed\";\n }>;\n }>;\n readonly ALLOWED_MUTABILITY: Readonly<{\n readonly BOTH: \"BOTH\";\n readonly CLIENT: \"CLIENT\";\n readonly NONE: \"NONE\";\n readonly PROVIDER: \"PROVIDER\";\n }>;\n readonly EVALUATION: Readonly<{\n readonly BOOLEAN: \"BOOLEAN\";\n readonly COMPARE: \"COMPARE\";\n readonly NUMBER: \"NUMBER\";\n readonly PERCENTAGE: \"PERCENTAGE\";\n }>;\n readonly LOGIC: Readonly<{\n readonly ALL: \"ALL\";\n readonly ANY: \"ANY\";\n readonly AT_LEAST: \"AT_LEAST\";\n }>;\n readonly OPERATION: Readonly<{\n readonly EQUAL: \"EQUAL\";\n readonly GREATER_OR_EQUAL: \"GREATER_OR_EQUAL\";\n readonly GREATER_THAN: \"GREATER_THAN\";\n readonly LESS_OR_EQUAL: \"LESS_OR_EQUAL\";\n readonly LESS_THAN: \"LESS_THAN\";\n readonly NOT_EQUAL: \"NOT_EQUAL\";\n }>;\n}" + }, + "PRESETS": { + "optional": false, + "readonly": true, + "type": "{\n readonly CATEGORY: Readonly<{\n DEXES: \"DEXES\";\n LENDING: \"LENDING\";\n PREDICTION: \"PREDICTION\";\n STAKING: \"STAKING\";\n }>;\n}" + }, + "PRINCIPAL": { + "optional": false, + "readonly": true, + "type": "\"agentic:principal\"" + }, + "WALLET": { + "optional": false, + "readonly": true, + "type": "\"agentic:wallet\"" + } + }, + "constants": { + "AGENTIC": { + "optional": false, + "readonly": false, + "type": "{\n readonly JOB: Readonly<{\n ADDRESS: Readonly<{\n \"eip155:42101\": Readonly<{\n EVALUATOR: \"0x1afC81396f1bb36F91f74506284952b81e4bd47c\";\n HOOK: \"0xDe7A94e510b6C571DE7880d441349689F73A32b3\";\n KERNEL: \"0x977cf1AC973E9eC4332791d531507575006157Ed\";\n }>;\n }>;\n ALLOWED_MUTABILITY: Readonly<{\n readonly BOTH: \"BOTH\";\n readonly CLIENT: \"CLIENT\";\n readonly NONE: \"NONE\";\n readonly PROVIDER: \"PROVIDER\";\n }>;\n EVALUATION: Readonly<{\n readonly BOOLEAN: \"BOOLEAN\";\n readonly COMPARE: \"COMPARE\";\n readonly NUMBER: \"NUMBER\";\n readonly PERCENTAGE: \"PERCENTAGE\";\n }>;\n LOGIC: Readonly<{\n readonly ALL: \"ALL\";\n readonly ANY: \"ANY\";\n readonly AT_LEAST: \"AT_LEAST\";\n }>;\n OPERATION: Readonly<{\n readonly EQUAL: \"EQUAL\";\n readonly GREATER_OR_EQUAL: \"GREATER_OR_EQUAL\";\n readonly GREATER_THAN: \"GREATER_THAN\";\n readonly LESS_OR_EQUAL: \"LESS_OR_EQUAL\";\n readonly LESS_THAN: \"LESS_THAN\";\n readonly NOT_EQUAL: \"NOT_EQUAL\";\n }>;\n }>;\n readonly PRESETS: Readonly<{\n CATEGORY: Readonly<{\n DEXES: \"DEXES\";\n LENDING: \"LENDING\";\n PREDICTION: \"PREDICTION\";\n STAKING: \"STAKING\";\n }>;\n }>;\n readonly PRINCIPAL: \"agentic:principal\";\n readonly WALLET: \"agentic:wallet\";\n}" + }, + "CHAIN": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "LIBRARY": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").LIBRARY" + }, + "MOVEABLE": { + "optional": false, + "readonly": false, + "type": "{\n TOKEN: import(\"sdk/src/lib/constants/tokens\").MoveableTokenConstantsMap;\n}" + }, + "PAYABLE": { + "optional": false, + "readonly": false, + "type": "{\n TOKEN: import(\"sdk/src/lib/constants/tokens\").PayableTokenConstantsMap;\n}" + }, + "PUSH_NETWORK": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "READ": { + "optional": false, + "readonly": false, + "type": "{\n readonly CALLBACK_BUDGET_BUFFER: 3;\n readonly CHAIN: {\n readonly WEB2: \"web2\";\n } & Readonly<{\n readonly ARBITRUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA;\n readonly BASE_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA;\n readonly BNB_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET;\n readonly ETHEREUM_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET;\n readonly ETHEREUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA;\n readonly PUSH_LOCALNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET;\n readonly PUSH_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET;\n readonly PUSH_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly PUSH_TESTNET_DONUT: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly SOLANA_DEVNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET;\n readonly SOLANA_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET;\n readonly SOLANA_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n readonly WEB2: \"web2\";\n }>;\n readonly DEFAULT_EXPIRY_BLOCKS: 300n;\n readonly ERROR_CODE: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n readonly MAX_CALLBACK_GAS_LIMIT: 1000000n;\n readonly MIN_CONFIRMATIONS_FLOOR: 1;\n readonly NAMESPACE: {\n readonly EVM: \"eip155\";\n readonly SVM: \"solana\";\n readonly WEB2: \"web2\";\n };\n readonly OUTCOME: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME;\n readonly REGISTRY_CALLBACK_GAS: 500000n;\n readonly RESULT_STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n readonly STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS;\n readonly UNIVERSAL_CALLBACK_ADDRESSES: Record;\n readonly UNIVERSAL_CORE_ADDRESSES: Record;\n readonly UNIVERSAL_READ_REGISTRY_ADDRESS: {\n readonly TESTNET_DONUT: \"0x00000000000000000000000000000000000000b2\";\n };\n readonly WEB2: \"web2\";\n readonly WEB2_DEFAULT_TIMEOUT_MS: 5000;\n readonly WEB2_MAX_EXTRACT_ENTRIES: 16;\n}" + } + } + }, + "scope": "All root exports and declared public members, PushChain static/instance members, universal transaction methods, utility groups, readonly/optional markers and constants. Behavior/default/deployment changes need the written session review." +} diff --git a/plan/marketplace/research/sdk-implementation-2026-10-20/cea-routing.json b/plan/marketplace/research/sdk-implementation-2026-10-20/cea-routing.json new file mode 100644 index 00000000..9df788bc --- /dev/null +++ b/plan/marketplace/research/sdk-implementation-2026-10-20/cea-routing.json @@ -0,0 +1,85 @@ +{ + "at": "2026-10-20T10:42:17.933Z", + "rows": [ + { + "chain": "eip155:11155111", + "sdkFactory": "0x5E191fbBe22F8866C5e4250557664fCE760e8870", + "marketplaceFactory": "0x8ED594A83301FEc545fC6c19fc12cF7111777029", + "sdkGateway": "0x05bD7a3D18324c1F7e216f7fBF2b15985aE5281A", + "marketFactoryCEA": [ + "0x33996E73ee53988B4c446457e5f497e9a4B87B0D", + false + ], + "marketFactoryImpl": "0x0a4F7be62B56830070266be81114edB93e68DA09", + "gatewayFactory": { + "error": "The contract function \"ceaFactory\" reverted." + }, + "marketFactoryGateway": "0x05bD7a3D18324c1F7e216f7fBF2b15985aE5281A", + "sdkCEA": [ + "0x0ec3c8720D66929edec8Ff23Dfa47B888d9aC111", + false + ], + "sdkFactoryGateway": "0x05bD7a3D18324c1F7e216f7fBF2b15985aE5281A" + }, + { + "chain": "eip155:84532", + "sdkFactory": "0x7e8CeeDA043ED1460540616103dD57581a66C856", + "marketplaceFactory": "0x0A75ca7736b488Eb41675ADc3b3156BACF659F55", + "sdkGateway": "0xFD4fef1F43aFEc8b5bcdEEc47f35a1431479aC16", + "marketFactoryImpl": "0x6c9Cfef12155bEE91ecD6d0C8f516cABA2890656", + "marketFactoryGateway": "0xFD4fef1F43aFEc8b5bcdEEc47f35a1431479aC16", + "marketFactoryCEA": [ + "0xf1981b90F0207135B396F698F33119FaED32e5cF", + false + ], + "gatewayFactory": { + "error": "The contract function \"ceaFactory\" reverted." + }, + "sdkCEA": [ + "0x6437D6B60D2Ba2a76e0f791d84286020c2e93cBC", + false + ], + "sdkFactoryGateway": "0xFD4fef1F43aFEc8b5bcdEEc47f35a1431479aC16" + }, + { + "chain": "eip155:421614", + "sdkFactory": "0x65572FFa81c230360a8a53C1682C7f0Ee321E5E7", + "marketplaceFactory": "0x88DC189275078Cf509E4Cc773F089c8ad07b7EA2", + "sdkGateway": "0x2cd870e0166Ba458dEC615168Fd659AacD795f34", + "sdkCEA": [ + "0xC9bCC1c420Fb0Ef862ba2f7082a8449641cAad1f", + false + ], + "gatewayFactory": { + "error": "The contract function \"ceaFactory\" reverted." + }, + "marketFactoryCEA": [ + "0xcE8377D906a057fEBBF5c898729B2D31644AFAf2", + false + ], + "marketFactoryImpl": "0x512d1B8C185a0Fd533a69f8973A3DD6513233009", + "sdkFactoryGateway": "0x2cd870e0166Ba458dEC615168Fd659AacD795f34", + "marketFactoryGateway": "0x2cd870e0166Ba458dEC615168Fd659AacD795f34" + }, + { + "chain": "eip155:97", + "sdkFactory": "0x3f1B16e0B072d472951C4563d29d3da6a3EE3Ce8", + "marketplaceFactory": "0x3f1B16e0B072d472951C4563d29d3da6a3EE3Ce8", + "sdkGateway": "0x44aFFC61983F4348DdddB886349eb992C061EaC0", + "sdkCEA": [ + "0x3223037344F37C1bf32a0d6b13035d55d88F39C7", + false + ], + "marketFactoryGateway": "0x44aFFC61983F4348DdddB886349eb992C061EaC0", + "sdkFactoryGateway": "0x44aFFC61983F4348DdddB886349eb992C061EaC0", + "marketFactoryCEA": [ + "0x3223037344F37C1bf32a0d6b13035d55d88F39C7", + false + ], + "marketFactoryImpl": "0x0ff5d8b7d9Ac3ee2Ad420e9b70Ed6Dc465f593e9", + "gatewayFactory": { + "error": "The contract function \"ceaFactory\" reverted with the following reason:\nexecution reverted: 0x" + } + } + ] +} diff --git a/plan/marketplace/research/sdk-implementation-2026-10-20/checked-files.json b/plan/marketplace/research/sdk-implementation-2026-10-20/checked-files.json new file mode 100644 index 00000000..b8fecf75 --- /dev/null +++ b/plan/marketplace/research/sdk-implementation-2026-10-20/checked-files.json @@ -0,0 +1,185 @@ +{ + "at": "2026-10-20T11:20:11.358467+00:00", + "files": [ + { + "path": "packages/core/MARKETPLACE.md", + "sha256": "1212a00942feb179bb1e39522d9cca7857c90a19f2f9340ff0ba8329b0b3aa17" + }, + { + "path": "packages/core/__e2e__/ci/suite.ts", + "sha256": "277331424ea7d5d64b451873154843a8fce3d9ae3cb125b3d7bd7aedfc3479b2" + }, + { + "path": "packages/core/__e2e__/marketplace/lifecycle.spec.ts", + "sha256": "de5aba539b7779b97354b28b75afcbac9636aec83c37ee7c73a23bcb6df385b1" + }, + { + "path": "packages/core/__e2e__/marketplace/readiness.spec.ts", + "sha256": "a72d3c427602ecc9089c5a8823168986bf6ce978ccc201aebfd3096d03e7e287" + }, + { + "path": "packages/core/__market-local__/marketplace.spec.ts", + "sha256": "9fe8110fd9bef6ef21229f15c2551015fe5f0042c9b1f01170480b29b5eef62c" + }, + { + "path": "packages/core/__market-local__/setup.ts", + "sha256": "49013def98fb026fc408430fce66273c1d33a45ae5f66a95a68ad5240e0ef46f" + }, + { + "path": "packages/core/jest.marketplace-local.config.ts", + "sha256": "6344b13077e277d591f0bad4e94a9722527c7a5b5a9fd3539fdb4ed5b69165cc" + }, + { + "path": "packages/core/package.json", + "sha256": "f8204973c67d237e630e52c0efe5c742060b787cc095d26d4881a17d5cbf991c" + }, + { + "path": "packages/core/scripts/check-agw-api.js", + "sha256": "b376215aadf2d81b5c1528ef4b2d060af7638fcee52323010299bb169c5c1fc8" + }, + { + "path": "packages/core/scripts/check-agw-docs.js", + "sha256": "caeba5794c27f616f0744b1748f7a73c641af70a0a9bfb9ab11bb8bb50929a4c" + }, + { + "path": "packages/core/scripts/check-agw-package.js", + "sha256": "ee4d68213993c3b4a494cb067ece5e8d28a785d9a3092942d2b9adc46465169b" + }, + { + "path": "packages/core/src/lib/agentic/__tests__/response-surface.spec.ts", + "sha256": "147bc7400eaae3a7221a16035c3a722be7ac8154034257578de3aadb40bc6b80" + }, + { + "path": "packages/core/src/lib/agentic/constants.ts", + "sha256": "b5f57def2edbc5d1c22eeded1e8ab32197f8875ac8e630ed9f4085132747ca7d" + }, + { + "path": "packages/core/src/lib/agentic/contracts/reader.ts", + "sha256": "2c90f098fe374aaf2a92e54fb50e1fbbbe3bd5a138a85f34c56fb6999a178bd9" + }, + { + "path": "packages/core/src/lib/agentic/errors.ts", + "sha256": "97dfee6107e27f6dad66e0d58e996ff1225df131f018d3efa1f98ad1f075c7b1" + }, + { + "path": "packages/core/src/lib/index.ts", + "sha256": "f92d4899691d98d30243f2e8fd86eef62c10b995322a2a92a3fb3691996a25ea" + }, + { + "path": "packages/core/src/lib/job-spec/__tests__/codec.spec.ts", + "sha256": "26c64f27223a35fc716a3f64618901423397cbbcf69c6ff639e69bb92d0e12db" + }, + { + "path": "packages/core/src/lib/job-spec/codec.ts", + "sha256": "ee27c032038b7f4f38093531c5fa97e7655c1c77857c000a72390a448de2533c" + }, + { + "path": "packages/core/src/lib/job-spec/constants.ts", + "sha256": "f5c14e73d8c9ef664ca48b5f489ed406fd6367f7df61cd882aa92a528210b153" + }, + { + "path": "packages/core/src/lib/job-spec/helpers.ts", + "sha256": "5d2ec2b0cc1d746cba5006cfbe0a13c73629821c975860431a831759d51e3690" + }, + { + "path": "packages/core/src/lib/job-spec/index.ts", + "sha256": "910ca188c273fc7d4d8c564d7c1d279b3f2860af7c04942864f78eeeec4219c9" + }, + { + "path": "packages/core/src/lib/job-spec/read.ts", + "sha256": "a572900f9b316e443ffdedfc83fd043f0d944f4e431d29dc8781ea38de79a8a4" + }, + { + "path": "packages/core/src/lib/job-spec/schema.ts", + "sha256": "7f780d3b826a7acf56b43cd80ce7870d182ddc04be3a8bc5205bc095869dfbe8" + }, + { + "path": "packages/core/src/lib/job-spec/types.ts", + "sha256": "0fcaeab75d76124854e0f84ba4bc0daf8512db091b261d6cdb059be6889161a3" + }, + { + "path": "packages/core/src/lib/job/job.ts", + "sha256": "1e63af2e7eb55f2a7bea1efceab089d5778dcbbb7a70aa042ab923f0a6b20032" + }, + { + "path": "packages/core/src/lib/job/types.ts", + "sha256": "85659e00c3a0b4565b813b599d3a05d6f9efb981225162636a6ca010da9c99d9" + }, + { + "path": "packages/core/src/lib/market/__tests__/kernel-wire.spec.ts", + "sha256": "6753167bfe07aef7398c6d72f95103b78b58e945691b9da8ab850c3eeb3a04d5" + }, + { + "path": "packages/core/src/lib/market/__tests__/namespace.spec.ts", + "sha256": "f9d24545c8b1b8e9451f4952678dd65c06cf7905b1f33d0405e4e6a2b41b6b7e" + }, + { + "path": "packages/core/src/lib/market/__tests__/rules.spec.ts", + "sha256": "0eb697c4cd7e9bed6d2bf39a2b4ebe54da169d66598aa7cfc9bef386288467f5" + }, + { + "path": "packages/core/src/lib/market/contracts/AgenticCommerce.ts", + "sha256": "d77269e520a2878b5e1343e127c021d953ec2f14e1352648b6bb402f6bdb5535" + }, + { + "path": "packages/core/src/lib/market/contracts/RulesBindingHook.ts", + "sha256": "794798248d9100b7bbd4da39bd21ae0a24faec843d74df0d62e6cb66d1b62e87" + }, + { + "path": "packages/core/src/lib/market/contracts/UniversalMarketplace.ts", + "sha256": "90c2675ba46778994606da25a8d5264700c009a44837b634ef07f81070116b4d" + }, + { + "path": "packages/core/src/lib/market/contracts/UniversalMarketplaceErrors.ts", + "sha256": "09436a0f219d49077eb66899dcd047649b897ead6fa72332fa54111c1c4de477" + }, + { + "path": "packages/core/src/lib/market/contracts/UniversalMarketplaceRules.ts", + "sha256": "f3218839eeb9ac1b911c42d38ab2d8461d7ce253d06fe797c40fdc0d556b9b69" + }, + { + "path": "packages/core/src/lib/market/deployment.ts", + "sha256": "aeec7a7a45453d510f3f3a545b89bd76b4fa900c30cfd939845dc7a82e44bbc3" + }, + { + "path": "packages/core/src/lib/market/errors.ts", + "sha256": "f2199e6a618d416a862aef6e4b8950fe6804071b1d8bace8249ce9b41e25a52a" + }, + { + "path": "packages/core/src/lib/market/index.ts", + "sha256": "b219661de10456cb2510f061440747fc2dc97c0bc84103617a1aeaeae651ca2b" + }, + { + "path": "packages/core/src/lib/market/kernel-wire.ts", + "sha256": "a10226752326ebdbf76a3b01720217ed0dbf0efe27e6a62049df1774e10ef6b4" + }, + { + "path": "packages/core/src/lib/market/market.ts", + "sha256": "a72581409445c285aad217ee4e74d9f231f59da90dbb133959ec69d1b5cd8b84" + }, + { + "path": "packages/core/src/lib/market/rules.ts", + "sha256": "7aefbf7480a48d04caa8b3255282cd51886807d6082ce600daaba0aa85a5549f" + }, + { + "path": "packages/core/src/lib/market/runtime.ts", + "sha256": "c03cf0ae352e7432652647a86ad87596a6af5ddeef4da39d232ec1384251350e" + }, + { + "path": "packages/core/src/lib/market/types.ts", + "sha256": "28a7ed37d8cc787471b2271b052962c0dee2ef86050891f6252940931049ee82" + }, + { + "path": "packages/core/src/lib/push-chain/push-chain.ts", + "sha256": "be53f83582055abab1d3df1156b4e9521209db9bba8bed0fafe1036d5841cc0a" + }, + { + "path": "packages/core/src/lib/utils.ts", + "sha256": "34d7d956be03e5bbd82130088a15f2601e609b7ef5484b9a899f90dfeb13f659" + }, + { + "path": "packages/core/tsconfig.marketplace-local.json", + "sha256": "632b093629b7a442a93e2189973c2484b25fecc162bf622f1ca896070b155391" + } + ] +} diff --git a/plan/marketplace/research/sdk-implementation-2026-10-20/fork-results.json b/plan/marketplace/research/sdk-implementation-2026-10-20/fork-results.json new file mode 100644 index 00000000..f2830a22 --- /dev/null +++ b/plan/marketplace/research/sdk-implementation-2026-10-20/fork-results.json @@ -0,0 +1 @@ +{"numFailedTestSuites":0,"numFailedTests":0,"numPassedTestSuites":1,"numPassedTests":6,"numPendingTestSuites":0,"numPendingTests":0,"numRuntimeErrorTestSuites":0,"numTodoTests":0,"numTotalTestSuites":1,"numTotalTests":6,"openHandles":[],"snapshot":{"added":0,"didUpdate":false,"failure":false,"filesAdded":0,"filesRemoved":0,"filesRemovedList":[],"filesUnmatched":0,"filesUpdated":0,"matched":0,"total":0,"unchecked":0,"uncheckedKeysByFile":[],"unmatched":0,"updated":0},"startTime":1792494853973,"success":true,"testResults":[{"assertionResults":[{"ancestorTitles":[],"duration":34158,"failureDetails":[],"failureMessages":[],"fullName":"registers and discovers a real v2 provider card through the public namespace","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"registers and discovers a real v2 provider card through the public namespace"},{"ancestorTitles":[],"duration":33849,"failureDetails":[],"failureMessages":[],"fullName":"previews and signs the exact on-chain JobSpec, opens on real AGW v6, and preserves binary bytes","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"previews and signs the exact on-chain JobSpec, opens on real AGW v6, and preserves binary bytes"},{"ancestorTitles":[],"duration":38,"failureDetails":[],"failureMessages":[],"fullName":"updates a decoded card without losing rule constraints or template wire bytes","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"updates a decoded card without losing rule constraints or template wire bytes"},{"ancestorTitles":[],"duration":7647,"failureDetails":[],"failureMessages":[],"fullName":"funds through the real rules hook and submits as the provider; manual evaluator completes locally","invocations":1,"location":null,"numPassingAsserts":11,"retryReasons":[],"status":"passed","title":"funds through the real rules hook and submits as the provider; manual evaluator completes locally"},{"ancestorTitles":[],"duration":3119,"failureDetails":[],"failureMessages":[],"fullName":"creates a plain job and allows third-party refund while the kernel is paused","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"creates a plain job and allows third-party refund while the kernel is paused"},{"ancestorTitles":[],"duration":34188,"failureDetails":[],"failureMessages":[],"fullName":"rejects a tampered plan before signing and atomically cancels a second job with permission revocation","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"rejects a tampered plan before signing and atomically cancels a second job with permission revocation"}],"endTime":1792494974170,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__market-local__/marketplace.spec.ts","startTime":1792494853998,"status":"passed","summary":""}],"wasInterrupted":false} diff --git a/plan/marketplace/research/sdk-implementation-2026-10-20/live-evidence.json b/plan/marketplace/research/sdk-implementation-2026-10-20/live-evidence.json new file mode 100644 index 00000000..e197a909 --- /dev/null +++ b/plan/marketplace/research/sdk-implementation-2026-10-20/live-evidence.json @@ -0,0 +1,41 @@ +{ + "marketplaceSource": "443b4e2dd9ca5dd9ffc8efebdfcecd619dd66c47", + "attempts": [ + { + "name": "marketplace-register", + "at": "2026-10-20T10:51:09.364Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "cardId": "1", + "txHash": "0x160f9367778751c4a72adfdb99dca1b9ef2f572e86b1841b4353b457b4ae838b" + }, + { + "name": "marketplace-register", + "at": "2026-10-20T10:53:14.353Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "cardId": "2", + "txHash": "0xfca44fa6a7e1d1d36a07771b04dd3f753a51dac0d72b3594ee1fca3d223dd674" + }, + { + "name": "marketplace-open", + "at": "2026-10-20T10:53:34.470Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "jobId": "1", + "wallet": "0xAc1A9778518AbaAE12367f7932C30c114d4940AE", + "rulesId": "0x13bfdc44a54323df70f44481a6882fb2bc805fbf9d61611799ca3a3d585a1f49", + "txHash": "0x6fd25c6cc4c7f8283863bd404cdb7689f3e481341166493ebbcb716d3f5ac67c" + }, + { + "name": "marketplace-cancel-cleanup", + "at": "2026-10-20T10:53:54.879Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "cardId": "2", + "wallet": "0xAc1A9778518AbaAE12367f7932C30c114d4940AE", + "jobId": "1", + "txHash": "0x185ba491236cc85ee7a369781e7fda93fa172e49f7ade56e8ee2d16a5781ba92" + } + ] +} diff --git a/plan/marketplace/research/sdk-implementation-2026-10-20/live-results.json b/plan/marketplace/research/sdk-implementation-2026-10-20/live-results.json new file mode 100644 index 00000000..e02b42ae --- /dev/null +++ b/plan/marketplace/research/sdk-implementation-2026-10-20/live-results.json @@ -0,0 +1,17 @@ +{ + "completedAt": "2026-10-20T10:53:57.903Z", + "numTotalTests": 1, + "numPassedTests": 1, + "numFailedTests": 0, + "numPendingTests": 0, + "success": false, + "tests": [ + { + "file": "marketplace/lifecycle.spec.ts", + "fullName": "marketplace live 1. native provider registration, reviewed open and atomic cancel/revoke on BSC Testnet", + "status": "passed", + "duration": 48852, + "error": null + } + ] +} diff --git a/plan/marketplace/research/sdk-implementation-2026-10-20/post-live-state.json b/plan/marketplace/research/sdk-implementation-2026-10-20/post-live-state.json new file mode 100644 index 00000000..28be8a98 --- /dev/null +++ b/plan/marketplace/research/sdk-implementation-2026-10-20/post-live-state.json @@ -0,0 +1,11 @@ +{ + "observedAt": "2026-10-20T11:18:53.682Z", + "blockNumber": "24449590", + "card1Active": false, + "card2Active": false, + "jobId": "1", + "jobStatus": 4, + "jobBudget": "0", + "wallet": "0xAc1A9778518AbaAE12367f7932C30c114d4940AE", + "permissionEnabled": false +} diff --git a/plan/marketplace/research/sdk-implementation-2026-10-20/readonly-results.json b/plan/marketplace/research/sdk-implementation-2026-10-20/readonly-results.json new file mode 100644 index 00000000..ddbf9e72 --- /dev/null +++ b/plan/marketplace/research/sdk-implementation-2026-10-20/readonly-results.json @@ -0,0 +1 @@ +{"numFailedTestSuites":0,"numFailedTests":0,"numPassedTestSuites":1,"numPassedTests":2,"numPendingTestSuites":0,"numPendingTests":0,"numRuntimeErrorTestSuites":0,"numTodoTests":0,"numTotalTestSuites":1,"numTotalTests":2,"openHandles":[],"snapshot":{"added":0,"didUpdate":false,"failure":false,"filesAdded":0,"filesRemoved":0,"filesRemovedList":[],"filesUnmatched":0,"filesUpdated":0,"matched":0,"total":0,"unchecked":0,"uncheckedKeysByFile":[],"unmatched":0,"updated":0},"startTime":1792494947872,"success":true,"testResults":[{"assertionResults":[{"ancestorTitles":["marketplace deployed v2 read-only"],"duration":5386,"failureDetails":[],"failureMessages":[],"fullName":"marketplace deployed v2 read-only enumerates registry and jobs through public SDK bindings and confirms the deployment/token","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"enumerates registry and jobs through public SDK bindings and confirms the deployment/token"},{"ancestorTitles":["marketplace deployed v2 read-only"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"marketplace deployed v2 read-only returns explicit placeholders for unavailable verification and deposit orchestration","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"returns explicit placeholders for unavailable verification and deposit orchestration"}],"endTime":1792494956765,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__e2e__/marketplace/readiness.spec.ts","startTime":1792494947888,"status":"passed","summary":""}],"wasInterrupted":false} diff --git a/plan/marketplace/research/sdk-implementation-2026-10-20/unit-results.json b/plan/marketplace/research/sdk-implementation-2026-10-20/unit-results.json new file mode 100644 index 00000000..bfbb52a2 --- /dev/null +++ b/plan/marketplace/research/sdk-implementation-2026-10-20/unit-results.json @@ -0,0 +1 @@ +{"numFailedTestSuites":0,"numFailedTests":0,"numPassedTestSuites":136,"numPassedTests":2205,"numPendingTestSuites":1,"numPendingTests":12,"numRuntimeErrorTestSuites":0,"numTodoTests":0,"numTotalTestSuites":137,"numTotalTests":2217,"openHandles":[],"snapshot":{"added":0,"didUpdate":false,"failure":false,"filesAdded":0,"filesRemoved":0,"filesRemovedList":[],"filesUnmatched":0,"filesUpdated":0,"matched":0,"total":0,"unchecked":0,"uncheckedKeysByFile":[],"unmatched":0,"updated":0},"startTime":1792494853253,"success":true,"testResults":[{"assertionResults":[{"ancestorTitles":["detectUniversalTx (live)"],"duration":null,"failureDetails":[],"failureMessages":[],"fullName":"detectUniversalTx (live) user-supplied BSC Testnet hash decodes into a known kind","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"pending","title":"user-supplied BSC Testnet hash decodes into a known kind"},{"ancestorTitles":["detectUniversalTx (live)"],"duration":null,"failureDetails":[],"failureMessages":[],"fullName":"detectUniversalTx (live) Sepolia FUNDS R3 success decodes as OUTBOUND_FINALIZED with subTxId + universalTxId","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"pending","title":"Sepolia FUNDS R3 success decodes as OUTBOUND_FINALIZED with subTxId + universalTxId"},{"ancestorTitles":["detectUniversalTx (live)"],"duration":null,"failureDetails":[],"failureMessages":[],"fullName":"detectUniversalTx (live) Stage 2 — Sepolia detection resolves child inbound → follow-up Push Chain tx","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"pending","title":"Stage 2 — Sepolia detection resolves child inbound → follow-up Push Chain tx"},{"ancestorTitles":["detectUniversalTx (live)"],"duration":null,"failureDetails":[],"failureMessages":[],"fullName":"detectUniversalTx (live) Stage 3 — full cascade from Push root → Sepolia → follow-up Push tx","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"pending","title":"Stage 3 — full cascade from Push root → Sepolia → follow-up Push tx"},{"ancestorTitles":["detectUniversalTx (live)"],"duration":null,"failureDetails":[],"failureMessages":[],"fullName":"detectUniversalTx (live) Stage 4a — detectUniversalTxAuto resolves Push root without explicit chain","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"pending","title":"Stage 4a — detectUniversalTxAuto resolves Push root without explicit chain"},{"ancestorTitles":["detectUniversalTx (live)"],"duration":null,"failureDetails":[],"failureMessages":[],"fullName":"detectUniversalTx (live) Stage 4a — detectUniversalTxAuto resolves Sepolia finalize without explicit chain","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"pending","title":"Stage 4a — detectUniversalTxAuto resolves Sepolia finalize without explicit chain"},{"ancestorTitles":["detectUniversalTx (live)"],"duration":null,"failureDetails":[],"failureMessages":[],"fullName":"detectUniversalTx (live) Stage 5 — advanced fan-out cascade (2 BSC outbounds + CEA follow-up → Solana leg)","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"pending","title":"Stage 5 — advanced fan-out cascade (2 BSC outbounds + CEA follow-up → Solana leg)"},{"ancestorTitles":["detectUniversalTx (live)"],"duration":null,"failureDetails":[],"failureMessages":[],"fullName":"detectUniversalTx (live) Stage 6 — Push fan-out to Solana: delivered + reverted legs with separate pc-refunds","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"pending","title":"Stage 6 — Push fan-out to Solana: delivered + reverted legs with separate pc-refunds"},{"ancestorTitles":["detectUniversalTx (live)"],"duration":null,"failureDetails":[],"failureMessages":[],"fullName":"detectUniversalTx (live) Stage 7 — mixed-destination fan-out cascade across ≥3 chains","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"pending","title":"Stage 7 — mixed-destination fan-out cascade across ≥3 chains"},{"ancestorTitles":["detectUniversalTx (live)"],"duration":null,"failureDetails":[],"failureMessages":[],"fullName":"detectUniversalTx (live) SVM R3 source signature decodes via the SVM branch","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"pending","title":"SVM R3 source signature decodes via the SVM branch"}],"coverage":{},"endTime":1792494888309,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/universal-tx-detector/__tests__/detector.live.spec.ts","startTime":1792494888309,"status":"skipped","summary":""},{"assertionResults":[{"ancestorTitles":["Universal Account Utilities","toChainAgnostic()"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"Universal Account Utilities toChainAgnostic() converts an address and chain to a CAIP-10 string for EVM","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"converts an address and chain to a CAIP-10 string for EVM"},{"ancestorTitles":["Universal Account Utilities","toChainAgnostic()"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Universal Account Utilities toChainAgnostic() converts an address and chain to a CAIP-10 string for Solana","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"converts an address and chain to a CAIP-10 string for Solana"},{"ancestorTitles":["Universal Account Utilities","fromChainAgnostic()"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Universal Account Utilities fromChainAgnostic() converts a CAIP-10 string to a UniversalAccount (EVM)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"converts a CAIP-10 string to a UniversalAccount (EVM)"},{"ancestorTitles":["Universal Account Utilities","fromChainAgnostic()"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Universal Account Utilities fromChainAgnostic() converts a CAIP-10 string to a UniversalAccount (Solana)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"converts a CAIP-10 string to a UniversalAccount (Solana)"},{"ancestorTitles":["Universal Account Utilities","fromChainAgnostic()"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"Universal Account Utilities fromChainAgnostic() throws an error if the CAIP string is unsupported","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"throws an error if the CAIP string is unsupported"},{"ancestorTitles":["Universal Account Utilities","convertOriginToExecutor() - Not Mocked"],"duration":1567,"failureDetails":[],"failureMessages":[],"fullName":"Universal Account Utilities convertOriginToExecutor() - Not Mocked should return same address and pushChainClient.universal.account","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should return same address and pushChainClient.universal.account"},{"ancestorTitles":["Universal Account Utilities","convertExecutorToOrigin()"],"duration":328,"failureDetails":[],"failureMessages":[],"fullName":"Universal Account Utilities convertExecutorToOrigin() Solana: should return valid origin data for a UEA address","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"Solana: should return valid origin data for a UEA address"},{"ancestorTitles":["Universal Account Utilities","convertExecutorToOrigin()"],"duration":317,"failureDetails":[],"failureMessages":[],"fullName":"Universal Account Utilities convertExecutorToOrigin() Ethereum: should return valid origin data for a UEA address","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"Ethereum: should return valid origin data for a UEA address"},{"ancestorTitles":["Universal Account Utilities","convertOriginToExecutor() - Direct Tests"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"Universal Account Utilities convertOriginToExecutor() - Direct Tests should return same address for Push Chain with onlyCompute=true","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should return same address for Push Chain with onlyCompute=true"},{"ancestorTitles":["Universal Account Utilities","convertOriginToExecutor() - Direct Tests"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Universal Account Utilities convertOriginToExecutor() - Direct Tests should return address without deployed status for Push Chain with onlyCompute=false","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should return address without deployed status for Push Chain with onlyCompute=false"},{"ancestorTitles":["Universal Account Utilities","convertOriginToExecutor() - Direct Tests"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Universal Account Utilities convertOriginToExecutor() - Direct Tests should return address without deployed status for Push Chain with default options","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should return address without deployed status for Push Chain with default options"},{"ancestorTitles":["Universal Account Utilities","convertOriginToExecutor() - Direct Tests"],"duration":689,"failureDetails":[],"failureMessages":[],"fullName":"Universal Account Utilities convertOriginToExecutor() - Direct Tests should compute and cache address for EVM chain","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"should compute and cache address for EVM chain"},{"ancestorTitles":["Universal Account Utilities","convertOriginToExecutor() - with options.chain"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Universal Account Utilities convertOriginToExecutor() - with options.chain should return same address for Push Chain input when options.chain is Push","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should return same address for Push Chain input when options.chain is Push"},{"ancestorTitles":["Universal Account Utilities","convertOriginToExecutor() - with options.chain"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Universal Account Utilities convertOriginToExecutor() - with options.chain should default to UEA behavior when no chain is provided","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should default to UEA behavior when no chain is provided"},{"ancestorTitles":["Universal Account Utilities","toUniversal()"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Universal Account Utilities toUniversal() returns a checksummed address for EVM chains","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"returns a checksummed address for EVM chains"},{"ancestorTitles":["Universal Account Utilities","toUniversal()"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Universal Account Utilities toUniversal() returns the address as-is for non-EVM chains","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"returns the address as-is for non-EVM chains"},{"ancestorTitles":["Universal Account Utilities","toUniversal()"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"Universal Account Utilities toUniversal() throws an error on invalid EVM address format","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"throws an error on invalid EVM address format"},{"ancestorTitles":["Universal Account Utilities","toUniversal()"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Universal Account Utilities toUniversal() works with different EVM chains","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"works with different EVM chains"},{"ancestorTitles":["Universal Account Utilities","toUniversal()"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Universal Account Utilities toUniversal() works with different Solana chains","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"works with different Solana chains"},{"ancestorTitles":["Universal Account Utilities","deriveExecutorAccount()"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Universal Account Utilities deriveExecutorAccount() is accessible on PushChain.utils.account","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"is accessible on PushChain.utils.account"},{"ancestorTitles":["Universal Account Utilities","deriveExecutorAccount()"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"Universal Account Utilities deriveExecutorAccount() returns same address for Push Chain input with skipNetworkCheck","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"returns same address for Push Chain input with skipNetworkCheck"},{"ancestorTitles":["Universal Account Utilities","deriveExecutorAccount()"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Universal Account Utilities deriveExecutorAccount() returns deployed as null when skipNetworkCheck is true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"returns deployed as null when skipNetworkCheck is true"},{"ancestorTitles":["Universal Account Utilities","resolveControllerAccount()"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Universal Account Utilities resolveControllerAccount() is accessible on PushChain.utils.account","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"is accessible on PushChain.utils.account"}],"endTime":1792494861516,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/universal/account/account.spec.ts","startTime":1792494857994,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["EndBlock RPC transport"],"duration":15,"failureDetails":[],"failureMessages":[],"fullName":"EndBlock RPC transport retains finalize_block_events without passing through a lossy decoder","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"retains finalize_block_events without passing through a lossy decoder"},{"ancestorTitles":["EndBlock RPC transport"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"EndBlock RPC transport retains end_block_events without passing through a lossy decoder","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"retains end_block_events without passing through a lossy decoder"},{"ancestorTitles":["EndBlock RPC transport"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"EndBlock RPC transport prefers CometBFT finalize events when legacy events also exist","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"prefers CometBFT finalize events when legacy events also exist"},{"ancestorTitles":["EndBlock RPC transport"],"duration":204,"failureDetails":[],"failureMessages":[],"fullName":"EndBlock RPC transport retries a transient HTTP failure without treating it as an empty successful block","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"retries a transient HTTP failure without treating it as an empty successful block"},{"ancestorTitles":["EndBlock RPC transport"],"duration":831,"failureDetails":[],"failureMessages":[],"fullName":"EndBlock RPC transport surfaces a pruned-height JSON-RPC error for the tracker to classify as unknown","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"surfaces a pruned-height JSON-RPC error for the tracker to classify as unknown"},{"ancestorTitles":["EndBlock RPC transport"],"duration":411,"failureDetails":[],"failureMessages":[],"fullName":"EndBlock RPC transport a height the prune node dropped (HTTP 500 + JSON-RPC error) is served by the archive, without transient backoff","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"a height the prune node dropped (HTTP 500 + JSON-RPC error) is served by the archive, without transient backoff"}],"endTime":1792494863082,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/read-state/__tests__/block-results-client.spec.ts","startTime":1792494861519,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["sendUniversalTx — InvalidEVMSignature retry"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"sendUniversalTx — InvalidEVMSignature retry retries once with fresh signature when first broadcast fails with 0xc7dbd31d","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"retries once with fresh signature when first broadcast fails with 0xc7dbd31d"},{"ancestorTitles":["sendUniversalTx — InvalidEVMSignature retry"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"sendUniversalTx — InvalidEVMSignature retry does not retry when resignFn is undefined even if selector matches","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"does not retry when resignFn is undefined even if selector matches"},{"ancestorTitles":["sendUniversalTx — InvalidEVMSignature retry"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"sendUniversalTx — InvalidEVMSignature retry does not retry when revert selector is different (e.g. InsufficientBalance)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"does not retry when revert selector is different (e.g. InsufficientBalance)"},{"ancestorTitles":["sendUniversalTx — InvalidEVMSignature retry"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"sendUniversalTx — InvalidEVMSignature retry gives up after MAX_SIG_RETRIES and throws the last rawLog","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"gives up after MAX_SIG_RETRIES and throws the last rawLog"},{"ancestorTitles":["sendUniversalTx — InvalidEVMSignature retry"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"sendUniversalTx — InvalidEVMSignature retry does not retry on first-attempt success","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"does not retry on first-attempt success"},{"ancestorTitles":["sendUniversalTx — InvalidEVMSignature retry"],"duration":1003,"failureDetails":[],"failureMessages":[],"fullName":"sendUniversalTx — InvalidEVMSignature retry retries Push transaction lookup after receipt when RPC indexing lags","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"retries Push transaction lookup after receipt when RPC indexing lags"},{"ancestorTitles":["sendUniversalTx — decoder on broadcast-failed path"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"sendUniversalTx — decoder on broadcast-failed path throws a compact InsufficientBalance message + decodedError on 0xf4d678b8","invocations":1,"location":null,"numPassingAsserts":10,"retryReasons":[],"status":"passed","title":"throws a compact InsufficientBalance message + decodedError on 0xf4d678b8"},{"ancestorTitles":["sendUniversalTx — decoder on broadcast-failed path"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"sendUniversalTx — decoder on broadcast-failed path logs unknown selectors at INFO and still throws PushChainExecutionError without decodedError","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"logs unknown selectors at INFO and still throws PushChainExecutionError without decodedError"}],"endTime":1792494864303,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/push-chain-tx-retry.spec.ts","startTime":1792494863085,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["PushClient archive fallback — searchCosmosByQuery"],"duration":14,"failureDetails":[],"failureMessages":[],"fullName":"PushClient archive fallback — searchCosmosByQuery re-queries archive when prune returns empty, and returns the archive hit","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"re-queries archive when prune returns empty, and returns the archive hit"},{"ancestorTitles":["PushClient archive fallback — searchCosmosByQuery"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PushClient archive fallback — searchCosmosByQuery does NOT touch archive when prune already has a result","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"does NOT touch archive when prune already has a result"},{"ancestorTitles":["PushClient archive fallback — searchCosmosByQuery"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"PushClient archive fallback — searchCosmosByQuery chain without an archive endpoint never consults archive (inert)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"chain without an archive endpoint never consults archive (inert)"},{"ancestorTitles":["PushClient archive fallback — getCosmosTx"],"duration":405,"failureDetails":[],"failureMessages":[],"fullName":"PushClient archive fallback — getCosmosTx falls back to archive when prune has no indexed tx (op throws on empty)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"falls back to archive when prune has no indexed tx (op throws on empty)"},{"ancestorTitles":["PushClient archive fallback — getCosmosTx"],"duration":413,"failureDetails":[],"failureMessages":[],"fullName":"PushClient archive fallback — getCosmosTx chain without an archive endpoint throws when prune has no indexed tx","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"chain without an archive endpoint throws when prune has no indexed tx"},{"ancestorTitles":["PushClient archive fallback — getTransactionReceiptWithArchiveFallback"],"duration":7,"failureDetails":[],"failureMessages":[],"fullName":"PushClient archive fallback — getTransactionReceiptWithArchiveFallback builds the prune probe without transport retries","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"builds the prune probe without transport retries"},{"ancestorTitles":["PushClient archive fallback — getTransactionReceiptWithArchiveFallback"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"PushClient archive fallback — getTransactionReceiptWithArchiveFallback races the no-retry prune probe against the archive: a pruned receipt costs one archive round trip","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"races the no-retry prune probe against the archive: a pruned receipt costs one archive round trip"},{"ancestorTitles":["PushClient archive fallback — getTransactionReceiptWithArchiveFallback"],"duration":24,"failureDetails":[],"failureMessages":[],"fullName":"PushClient archive fallback — getTransactionReceiptWithArchiveFallback a fresh receipt the archive has not indexed yet comes from the prune node","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"a fresh receipt the archive has not indexed yet comes from the prune node"},{"ancestorTitles":["PushClient archive fallback — getTransactionReceiptWithArchiveFallback"],"duration":24,"failureDetails":[],"failureMessages":[],"fullName":"PushClient archive fallback — getTransactionReceiptWithArchiveFallback rejects with the prune error when neither has it","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects with the prune error when neither has it"},{"ancestorTitles":["PushClient archive fallback — getTransactionReceiptWithArchiveFallback"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"PushClient archive fallback — getTransactionReceiptWithArchiveFallback without an archive endpoint it is the plain shared-client call (retries intact)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"without an archive endpoint it is the plain shared-client call (retries intact)"}],"endTime":1792494865297,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/push-client/push-client.archive-fallback.spec.ts","startTime":1792494864306,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["waitForOutboundTx OBSERVED gate"],"duration":308,"failureDetails":[],"failureMessages":[],"fullName":"waitForOutboundTx OBSERVED gate does NOT return FOUND when outboundStatus is UNSPECIFIED even if txHash is set","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"does NOT return FOUND when outboundStatus is UNSPECIFIED even if txHash is set"},{"ancestorTitles":["waitForOutboundTx OBSERVED gate"],"duration":309,"failureDetails":[],"failureMessages":[],"fullName":"waitForOutboundTx OBSERVED gate does NOT return FOUND when outboundStatus is PENDING even if txHash is set","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"does NOT return FOUND when outboundStatus is PENDING even if txHash is set"},{"ancestorTitles":["waitForOutboundTx OBSERVED gate"],"duration":25,"failureDetails":[],"failureMessages":[],"fullName":"waitForOutboundTx OBSERVED gate returns FOUND once outboundStatus transitions to OBSERVED","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"returns FOUND once outboundStatus transitions to OBSERVED"},{"ancestorTitles":["waitForOutboundTx OBSERVED gate"],"duration":25,"failureDetails":[],"failureMessages":[],"fullName":"waitForOutboundTx OBSERVED gate throws OutboundFailedError when outboundStatus transitions to REVERTED (existing behavior preserved)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"throws OutboundFailedError when outboundStatus transitions to REVERTED (existing behavior preserved)"},{"ancestorTitles":["waitForOutboundTx OBSERVED gate"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"waitForOutboundTx OBSERVED gate throws OutboundFailedError when a child pcTx fails before outbound emission","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"throws OutboundFailedError when a child pcTx fails before outbound emission"},{"ancestorTitles":["waitForOutboundTx OBSERVED gate"],"duration":8,"failureDetails":[],"failureMessages":[],"fullName":"waitForOutboundTx OBSERVED gate normalizes Push Chain native balance errors from child pcTx before outbound emission","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"normalizes Push Chain native balance errors from child pcTx before outbound emission"},{"ancestorTitles":["waitForOutboundTx OBSERVED gate"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"waitForOutboundTx OBSERVED gate multi-outbound: picks the OBSERVED entry even when an UNSPECIFIED entry with txHash appears first in the array","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"multi-outbound: picks the OBSERVED entry even when an UNSPECIFIED entry with txHash appears first in the array"},{"ancestorTitles":["waitForOutboundTx OBSERVED gate"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"waitForOutboundTx OBSERVED gate multi-outbound same-chain: _outboundIndex selects the later matching destination entry","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"multi-outbound same-chain: _outboundIndex selects the later matching destination entry"},{"ancestorTitles":["waitForOutboundTx OBSERVED gate"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"waitForOutboundTx OBSERVED gate waitForAllOutboundTxsV2 maps same-chain outbounds to hops by ordinal","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"waitForAllOutboundTxsV2 maps same-chain outbounds to hops by ordinal"}],"endTime":1792494866156,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/outbound-confirmation-gate.spec.ts","startTime":1792494865304,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["Helpers Utils Namespace","getChainName"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace getChainName should get chain name","invocations":1,"location":null,"numPassingAsserts":11,"retryReasons":[],"status":"passed","title":"should get chain name"},{"ancestorTitles":["Helpers Utils Namespace","getChainName"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace getChainName should handle chain values directly","invocations":1,"location":null,"numPassingAsserts":10,"retryReasons":[],"status":"passed","title":"should handle chain values directly"},{"ancestorTitles":["Helpers Utils Namespace","getChainName"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace getChainName should return undefined for invalid chain values","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"should return undefined for invalid chain values"},{"ancestorTitles":["Helpers Utils Namespace","getChainName"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace getChainName should handle case sensitivity correctly (returns undefined)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should handle case sensitivity correctly (returns undefined)"},{"ancestorTitles":["Helpers Utils Namespace","getChainName"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace getChainName should handle whitespace correctly (returns undefined)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should handle whitespace correctly (returns undefined)"},{"ancestorTitles":["Helpers Utils Namespace","getChainNamespace"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace getChainNamespace should get chain namespace from enum key name","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"should get chain namespace from enum key name"},{"ancestorTitles":["Helpers Utils Namespace","getChainNamespace"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace getChainNamespace should return input unchanged when already a namespace","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"should return input unchanged when already a namespace"},{"ancestorTitles":["Helpers Utils Namespace","getChainNamespace"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace getChainNamespace should return undefined for unsupported names","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should return undefined for unsupported names"},{"ancestorTitles":["Helpers Utils Namespace","getSupportedChains"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace getSupportedChains should return supported chains for TESTNET","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return supported chains for TESTNET"},{"ancestorTitles":["Helpers Utils Namespace","getSupportedChains"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace getSupportedChains should return supported chains for TESTNET_DONUT","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return supported chains for TESTNET_DONUT"},{"ancestorTitles":["Helpers Utils Namespace","getSupportedChains"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace getSupportedChains should return supported chains for LOCALNET","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return supported chains for LOCALNET"},{"ancestorTitles":["Helpers Utils Namespace","getSupportedChains"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace getSupportedChains should return empty list for MAINNET","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return empty list for MAINNET"},{"ancestorTitles":["Helpers Utils Namespace","getSupportedChainsByName"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace getSupportedChainsByName should return supported chain names for TESTNET","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return supported chain names for TESTNET"},{"ancestorTitles":["Helpers Utils Namespace","getSupportedChainsByName"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace getSupportedChainsByName should return supported chain names for TESTNET_DONUT","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return supported chain names for TESTNET_DONUT"},{"ancestorTitles":["Helpers Utils Namespace","getSupportedChainsByName"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace getSupportedChainsByName should return supported chain names for LOCALNET","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return supported chain names for LOCALNET"},{"ancestorTitles":["Helpers Utils Namespace","getSupportedChainsByName"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace getSupportedChainsByName should return empty list for MAINNET","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return empty list for MAINNET"},{"ancestorTitles":["Helpers Utils Namespace","encodeTxData"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace encodeTxData should encode function data correctly","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should encode function data correctly"},{"ancestorTitles":["Helpers Utils Namespace","encodeTxData"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace encodeTxData should encode function data with arguments","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should encode function data with arguments"},{"ancestorTitles":["Helpers Utils Namespace","encodeTxData"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace encodeTxData should throw error for invalid ABI","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should throw error for invalid ABI"},{"ancestorTitles":["Helpers Utils Namespace","encodeTxData"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace encodeTxData should throw error for invalid arguments","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should throw error for invalid arguments"},{"ancestorTitles":["Helpers Utils Namespace","encodeTxData"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace encodeTxData should throw error for non-existent function","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should throw error for non-existent function"},{"ancestorTitles":["Helpers Utils Namespace","encodeTxData"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace encodeTxData should handle empty args array","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should handle empty args array"},{"ancestorTitles":["Helpers Utils Namespace","encodeTxData","Anchor IDL input (Solana)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace encodeTxData Anchor IDL input (Solana) produces discriminator + Borsh-encoded args for receive_sol amount=0","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"produces discriminator + Borsh-encoded args for receive_sol amount=0"},{"ancestorTitles":["Helpers Utils Namespace","encodeTxData","Anchor IDL input (Solana)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace encodeTxData Anchor IDL input (Solana) accepts camelCase function name","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"accepts camelCase function name"},{"ancestorTitles":["Helpers Utils Namespace","encodeTxData","Anchor IDL input (Solana)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace encodeTxData Anchor IDL input (Solana) throws when args is not an array on IDL path","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"throws when args is not an array on IDL path"},{"ancestorTitles":["Helpers Utils Namespace","encodeTxData","Anchor IDL input (Solana)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace encodeTxData Anchor IDL input (Solana) throws when instruction is not in IDL","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"throws when instruction is not in IDL"},{"ancestorTitles":["Helpers Utils Namespace","encodeTxData","Anchor IDL input (Solana)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace encodeTxData Anchor IDL input (Solana) auto-registers the IDL in PushChain.utils.svm under idl.address","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"auto-registers the IDL in PushChain.utils.svm under idl.address"},{"ancestorTitles":["Helpers Utils Namespace","encodeTxData","Anchor IDL input (Solana)","explicit 'idl' param"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace encodeTxData Anchor IDL input (Solana) explicit 'idl' param produces identical bytes to passing the IDL as abi","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"produces identical bytes to passing the IDL as abi"},{"ancestorTitles":["Helpers Utils Namespace","encodeTxData","Anchor IDL input (Solana)","explicit 'idl' param"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace encodeTxData Anchor IDL input (Solana) explicit 'idl' param auto-registers the IDL when passed via the idl param","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"auto-registers the IDL when passed via the idl param"},{"ancestorTitles":["Helpers Utils Namespace","encodeTxData","param validation"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace encodeTxData param validation throws when both 'abi' and 'idl' are provided","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"throws when both 'abi' and 'idl' are provided"},{"ancestorTitles":["Helpers Utils Namespace","encodeTxData","param validation"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace encodeTxData param validation throws when neither 'abi' nor 'idl' is provided","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"throws when neither 'abi' nor 'idl' is provided"},{"ancestorTitles":["Helpers Utils Namespace","parseUnits"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace parseUnits should parse integer values correctly","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should parse integer values correctly"},{"ancestorTitles":["Helpers Utils Namespace","parseUnits"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace parseUnits should parse decimal values correctly","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should parse decimal values correctly"},{"ancestorTitles":["Helpers Utils Namespace","parseUnits"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace parseUnits should handle zero values","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should handle zero values"},{"ancestorTitles":["Helpers Utils Namespace","parseUnits"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace parseUnits should handle negative values","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should handle negative values"},{"ancestorTitles":["Helpers Utils Namespace","parseUnits"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace parseUnits should handle values without decimals","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should handle values without decimals"},{"ancestorTitles":["Helpers Utils Namespace","parseUnits"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace parseUnits should handle values with leading/trailing whitespace","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should handle values with leading/trailing whitespace"},{"ancestorTitles":["Helpers Utils Namespace","parseUnits"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace parseUnits should handle values starting with decimal point","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should handle values starting with decimal point"},{"ancestorTitles":["Helpers Utils Namespace","parseUnits"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace parseUnits should handle exact decimal place matches","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should handle exact decimal place matches"},{"ancestorTitles":["Helpers Utils Namespace","parseUnits"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace parseUnits should throw error for invalid value types","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should throw error for invalid value types"},{"ancestorTitles":["Helpers Utils Namespace","parseUnits"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace parseUnits should throw error for invalid exponent types","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"should throw error for invalid exponent types"},{"ancestorTitles":["Helpers Utils Namespace","parseUnits"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace parseUnits should throw error for empty or invalid value strings","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"should throw error for empty or invalid value strings"},{"ancestorTitles":["Helpers Utils Namespace","parseUnits"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace parseUnits should throw error when decimal places exceed exponent","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should throw error when decimal places exceed exponent"},{"ancestorTitles":["Helpers Utils Namespace","parseUnits"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace parseUnits should handle large numbers","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should handle large numbers"},{"ancestorTitles":["Helpers Utils Namespace","parseUnits"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace parseUnits should handle common token decimal scenarios","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"should handle common token decimal scenarios"},{"ancestorTitles":["Helpers Utils Namespace","parseUnits"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace parseUnits should handle object-based exponent input","invocations":1,"location":null,"numPassingAsserts":21,"retryReasons":[],"status":"passed","title":"should handle object-based exponent input"},{"ancestorTitles":["Helpers Utils Namespace","parseUnits"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace parseUnits should throw error for invalid object-based exponent types","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"should throw error for invalid object-based exponent types"},{"ancestorTitles":["Helpers Utils Namespace","parseUnits"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace parseUnits should throw error when decimal places exceed exponent with object format","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should throw error when decimal places exceed exponent with object format"},{"ancestorTitles":["Helpers Utils Namespace","parseUnits"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace parseUnits should produce same results for number and object-based exponent formats","invocations":1,"location":null,"numPassingAsserts":21,"retryReasons":[],"status":"passed","title":"should produce same results for number and object-based exponent formats"},{"ancestorTitles":["Helpers Utils Namespace","formatUnits","EVM-style usage (number decimals)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace formatUnits EVM-style usage (number decimals) should format bigint values correctly","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"should format bigint values correctly"},{"ancestorTitles":["Helpers Utils Namespace","formatUnits","EVM-style usage (number decimals)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace formatUnits EVM-style usage (number decimals) should format string values correctly","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"should format string values correctly"},{"ancestorTitles":["Helpers Utils Namespace","formatUnits","EVM-style usage (number decimals)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace formatUnits EVM-style usage (number decimals) should handle different decimal scenarios","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should handle different decimal scenarios"},{"ancestorTitles":["Helpers Utils Namespace","formatUnits","Push-style usage (options object)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace formatUnits Push-style usage (options object) should format with decimals option","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"should format with decimals option"},{"ancestorTitles":["Helpers Utils Namespace","formatUnits","Push-style usage (options object)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace formatUnits Push-style usage (options object) should format with precision option","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"should format with precision option"},{"ancestorTitles":["Helpers Utils Namespace","formatUnits","Push-style usage (options object)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace formatUnits Push-style usage (options object) should handle edge cases with precision","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should handle edge cases with precision"},{"ancestorTitles":["Helpers Utils Namespace","formatUnits","Common token scenarios"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace formatUnits Common token scenarios should handle ETH scenarios","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should handle ETH scenarios"},{"ancestorTitles":["Helpers Utils Namespace","formatUnits","Common token scenarios"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace formatUnits Common token scenarios should handle USDC scenarios","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should handle USDC scenarios"},{"ancestorTitles":["Helpers Utils Namespace","formatUnits","Common token scenarios"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace formatUnits Common token scenarios should handle BTC scenarios","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should handle BTC scenarios"},{"ancestorTitles":["Helpers Utils Namespace","formatUnits","Error handling and validation"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace formatUnits Error handling and validation should throw error for invalid value types","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"should throw error for invalid value types"},{"ancestorTitles":["Helpers Utils Namespace","formatUnits","Error handling and validation"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace formatUnits Error handling and validation should throw error for invalid decimals parameter","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"should throw error for invalid decimals parameter"},{"ancestorTitles":["Helpers Utils Namespace","formatUnits","Error handling and validation"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace formatUnits Error handling and validation should throw error for invalid decimals values","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should throw error for invalid decimals values"},{"ancestorTitles":["Helpers Utils Namespace","formatUnits","Error handling and validation"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace formatUnits Error handling and validation should throw error for invalid precision values","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should throw error for invalid precision values"},{"ancestorTitles":["Helpers Utils Namespace","formatUnits","Error handling and validation"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace formatUnits Error handling and validation should throw error for invalid string values","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should throw error for invalid string values"},{"ancestorTitles":["Helpers Utils Namespace","formatUnits","Edge cases"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace formatUnits Edge cases should handle very large numbers","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should handle very large numbers"},{"ancestorTitles":["Helpers Utils Namespace","formatUnits","Edge cases"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace formatUnits Edge cases should handle very small numbers","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should handle very small numbers"},{"ancestorTitles":["Helpers Utils Namespace","formatUnits","Edge cases"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace formatUnits Edge cases should handle zero with different decimals","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should handle zero with different decimals"},{"ancestorTitles":["Helpers Utils Namespace","formatUnits","Edge cases"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace formatUnits Edge cases should handle negative numbers","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should handle negative numbers"},{"ancestorTitles":["Helpers Utils Namespace","formatUnits","Consistency between EVM-style and Push-style"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace formatUnits Consistency between EVM-style and Push-style should produce same results for number and object-based formats","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"should produce same results for number and object-based formats"},{"ancestorTitles":["Helpers Utils Namespace","formatUnits","Consistency between EVM-style and Push-style"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace formatUnits Consistency between EVM-style and Push-style should handle bigint and string inputs consistently","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"should handle bigint and string inputs consistently"},{"ancestorTitles":["Helpers Utils Namespace","slippageToMinAmount","basic functionality"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace slippageToMinAmount basic functionality should calculate minimum amount out with 1% slippage","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should calculate minimum amount out with 1% slippage"},{"ancestorTitles":["Helpers Utils Namespace","slippageToMinAmount","basic functionality"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace slippageToMinAmount basic functionality should calculate minimum amount out with 1% slippage for large amounts","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should calculate minimum amount out with 1% slippage for large amounts"},{"ancestorTitles":["Helpers Utils Namespace","slippageToMinAmount","basic functionality"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace slippageToMinAmount basic functionality should calculate minimum amount out with 0.5% slippage","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should calculate minimum amount out with 0.5% slippage"},{"ancestorTitles":["Helpers Utils Namespace","slippageToMinAmount","basic functionality"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace slippageToMinAmount basic functionality should calculate minimum amount out with 2% slippage","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should calculate minimum amount out with 2% slippage"},{"ancestorTitles":["Helpers Utils Namespace","slippageToMinAmount","basic functionality"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace slippageToMinAmount basic functionality should handle zero slippage","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should handle zero slippage"},{"ancestorTitles":["Helpers Utils Namespace","slippageToMinAmount","basic functionality"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace slippageToMinAmount basic functionality should handle maximum slippage (100%)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should handle maximum slippage (100%)"},{"ancestorTitles":["Helpers Utils Namespace","slippageToMinAmount","edge cases"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace slippageToMinAmount edge cases should handle very small amounts","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should handle very small amounts"},{"ancestorTitles":["Helpers Utils Namespace","slippageToMinAmount","edge cases"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace slippageToMinAmount edge cases should handle very large amounts","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should handle very large amounts"},{"ancestorTitles":["Helpers Utils Namespace","slippageToMinAmount","edge cases"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace slippageToMinAmount edge cases should handle fractional slippage calculations correctly","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should handle fractional slippage calculations correctly"},{"ancestorTitles":["Helpers Utils Namespace","slippageToMinAmount","different slippage rates"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace slippageToMinAmount different slippage rates should handle 0.1% slippage (10 bps)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should handle 0.1% slippage (10 bps)"},{"ancestorTitles":["Helpers Utils Namespace","slippageToMinAmount","different slippage rates"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace slippageToMinAmount different slippage rates should handle 0.25% slippage (25 bps)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should handle 0.25% slippage (25 bps)"},{"ancestorTitles":["Helpers Utils Namespace","slippageToMinAmount","different slippage rates"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace slippageToMinAmount different slippage rates should handle 5% slippage (500 bps)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should handle 5% slippage (500 bps)"},{"ancestorTitles":["Helpers Utils Namespace","slippageToMinAmount","different slippage rates"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace slippageToMinAmount different slippage rates should handle 10% slippage (1000 bps)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should handle 10% slippage (1000 bps)"},{"ancestorTitles":["Helpers Utils Namespace","slippageToMinAmount","different slippage rates"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace slippageToMinAmount different slippage rates should handle 50% slippage (5000 bps)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should handle 50% slippage (5000 bps)"},{"ancestorTitles":["Helpers Utils Namespace","slippageToMinAmount","error handling"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace slippageToMinAmount error handling should throw error for non-string amount","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should throw error for non-string amount"},{"ancestorTitles":["Helpers Utils Namespace","slippageToMinAmount","error handling"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace slippageToMinAmount error handling should throw error for non-number slippageBps","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should throw error for non-number slippageBps"},{"ancestorTitles":["Helpers Utils Namespace","slippageToMinAmount","error handling"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace slippageToMinAmount error handling should throw error for non-integer slippageBps","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should throw error for non-integer slippageBps"},{"ancestorTitles":["Helpers Utils Namespace","slippageToMinAmount","error handling"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace slippageToMinAmount error handling should throw error for negative slippageBps","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should throw error for negative slippageBps"},{"ancestorTitles":["Helpers Utils Namespace","slippageToMinAmount","error handling"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace slippageToMinAmount error handling should throw error for slippageBps exceeding 10000","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should throw error for slippageBps exceeding 10000"},{"ancestorTitles":["Helpers Utils Namespace","slippageToMinAmount","error handling"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace slippageToMinAmount error handling should throw error for empty amount string","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should throw error for empty amount string"},{"ancestorTitles":["Helpers Utils Namespace","slippageToMinAmount","error handling"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace slippageToMinAmount error handling should throw error for whitespace-only amount string","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should throw error for whitespace-only amount string"},{"ancestorTitles":["Helpers Utils Namespace","slippageToMinAmount","error handling"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace slippageToMinAmount error handling should throw error for invalid amount format","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should throw error for invalid amount format"},{"ancestorTitles":["Helpers Utils Namespace","slippageToMinAmount","real-world scenarios"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace slippageToMinAmount real-world scenarios should work with USDC amounts (6 decimals)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should work with USDC amounts (6 decimals)"},{"ancestorTitles":["Helpers Utils Namespace","slippageToMinAmount","real-world scenarios"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace slippageToMinAmount real-world scenarios should work with ETH amounts (18 decimals)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should work with ETH amounts (18 decimals)"},{"ancestorTitles":["Helpers Utils Namespace","slippageToMinAmount","real-world scenarios"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace slippageToMinAmount real-world scenarios should work with small token amounts","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should work with small token amounts"},{"ancestorTitles":["Helpers Utils Namespace","Tokens Utils"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace Tokens Utils should list all moveable tokens across all chains","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"should list all moveable tokens across all chains"},{"ancestorTitles":["Helpers Utils Namespace","Tokens Utils"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace Tokens Utils should list moveable tokens for a specific chain (Ethereum Sepolia)","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"should list moveable tokens for a specific chain (Ethereum Sepolia)"},{"ancestorTitles":["Helpers Utils Namespace","Tokens Utils"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace Tokens Utils should list moveable tokens for a specific chain (Arbitrum Sepolia)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"should list moveable tokens for a specific chain (Arbitrum Sepolia)"},{"ancestorTitles":["Helpers Utils Namespace","Tokens Utils"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace Tokens Utils should list moveable tokens for a specific chain (Base Sepolia)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"should list moveable tokens for a specific chain (Base Sepolia)"},{"ancestorTitles":["Helpers Utils Namespace","Tokens Utils"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace Tokens Utils should list moveable tokens for Push Chain (PRC-20 synthetics)","invocations":1,"location":null,"numPassingAsserts":68,"retryReasons":[],"status":"passed","title":"should list moveable tokens for Push Chain (PRC-20 synthetics)"},{"ancestorTitles":["Helpers Utils Namespace","Tokens Utils"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace Tokens Utils should include Push Chain PRC-20s in the all-chains moveable list","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should include Push Chain PRC-20s in the all-chains moveable list"},{"ancestorTitles":["Helpers Utils Namespace","Tokens Utils"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace Tokens Utils should return Push Chain PRC-20s via MOVEABLE_TOKENS registry lookup","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should return Push Chain PRC-20s via MOVEABLE_TOKENS registry lookup"},{"ancestorTitles":["Helpers Utils Namespace","Tokens Utils"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace Tokens Utils should list all payable tokens across all chains","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"should list all payable tokens across all chains"},{"ancestorTitles":["Helpers Utils Namespace","Tokens Utils"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace Tokens Utils should list payable tokens for a specific chain (Solana Devnet)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"should list payable tokens for a specific chain (Solana Devnet)"},{"ancestorTitles":["Helpers Utils Namespace","Tokens Utils"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace Tokens Utils should list payable tokens for a specific chain (Arbitrum Sepolia)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"should list payable tokens for a specific chain (Arbitrum Sepolia)"},{"ancestorTitles":["Helpers Utils Namespace","Tokens Utils"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace Tokens Utils should list payable tokens for a specific chain (Base Sepolia)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"should list payable tokens for a specific chain (Base Sepolia)"},{"ancestorTitles":["Helpers Utils Namespace","Tokens Utils"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace Tokens Utils should resolve chain via client instance for moveable tokens","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should resolve chain via client instance for moveable tokens"},{"ancestorTitles":["Helpers Utils Namespace","Tokens Utils"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace Tokens Utils should get PRC20 address from a MoveableToken","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"should get PRC20 address from a MoveableToken"},{"ancestorTitles":["Helpers Utils Namespace","Tokens Utils"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace Tokens Utils should get PRC20 address from a { chain, address } token input","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"should get PRC20 address from a { chain, address } token input"},{"ancestorTitles":["Helpers Utils Namespace","Tokens Utils"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"Helpers Utils Namespace Tokens Utils should throw when the PRC20 address is unresolved on the target network","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should throw when the PRC20 address is unresolved on the target network"}],"endTime":1792494866908,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/utils.spec.ts","startTime":1792494866160,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["response identity"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"response identity live adaptation keeps origin/hash/raw and records the wrapped call","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"live adaptation keeps origin/hash/raw and records the wrapped call"},{"ancestorTitles":["response identity"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"response identity replay: a tracked execute on a registered wallet is re-presented as the wallet’s call","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"replay: a tracked execute on a registered wallet is re-presented as the wallet’s call"},{"ancestorTitles":["response identity"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"response identity replay: an outbound through the gateway restores the destination call and route","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"replay: an outbound through the gateway restores the destination call and route"},{"ancestorTitles":["response identity"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"response identity replay: anything not provably an AGW call is left untouched","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"replay: anything not provably an AGW call is left untouched"},{"ancestorTitles":["revert decoding"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"revert decoding decodes AGW errors with arguments","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"decodes AGW errors with arguments"},{"ancestorTitles":["revert decoding"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"revert decoding names a truncated PolicyCheckReverted by its inner selector","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"names a truncated PolicyCheckReverted by its inner selector"},{"ancestorTitles":["revert decoding"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"revert decoding finds revert data through error causes and viem-style messages","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"finds revert data through error causes and viem-style messages"},{"ancestorTitles":["revert decoding"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"revert decoding decodes viem simulation errors whose full revert lives in raw","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"decodes viem simulation errors whose full revert lives in raw"},{"ancestorTitles":["public surface"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"public surface exports the AGW errors, and the base execution error for instanceof checks","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"exports the AGW errors, and the base execution error for instanceof checks"},{"ancestorTitles":["public surface"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"public surface exposes the wallet marker and preset API, keeping deployment wiring and codecs internal","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"exposes the wallet marker and preset API, keeping deployment wiring and codecs internal"}],"endTime":1792494867522,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/response-surface.spec.ts","startTime":1792494866911,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["waitForOutboundTx initial-wait clamp"],"duration":103,"failureDetails":[],"failureMessages":[],"fullName":"waitForOutboundTx initial-wait clamp throws OutboundTimeoutError within the clamped budget (100ms)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"throws OutboundTimeoutError within the clamped budget (100ms)"},{"ancestorTitles":["waitForOutboundTx initial-wait clamp"],"duration":202,"failureDetails":[],"failureMessages":[],"fullName":"waitForOutboundTx initial-wait clamp throws with elapsedMs matching the override (not the default)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"throws with elapsedMs matching the override (not the default)"}],"endTime":1792494867956,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/outbound-timeout-clamp.spec.ts","startTime":1792494867525,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"a provider’s malformed unverified template cannot break registry summary enumeration","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"a provider’s malformed unverified template cannot break registry summary enumeration"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"lets a provider deactivate a malformed card without decoding its broken template","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"lets a provider deactivate a malformed card without decoding its broken template"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"delivers the correct terminal family to the per-call hook once when waiting repeatedly","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"delivers the correct terminal family to the per-call hook once when waiting repeatedly"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"plain jobs require an explicitly reviewed budget rather than silently adopting a re-quote","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"plain jobs require an explicitly reviewed budget rather than silently adopting a re-quote"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"placeholder methods and replacement proposals fail before any reads or signatures","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"placeholder methods and replacement proposals fail before any reads or signatures"}],"endTime":1792494868248,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/market/__tests__/namespace.spec.ts","startTime":1792494867959,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["R2 outbound REVERTED → 299-02 + externalStatus=failed (full-chain)"],"duration":25,"failureDetails":[],"failureMessages":[],"fullName":"R2 outbound REVERTED → 299-02 + externalStatus=failed (full-chain) cosmos REVERTED transition drives OutboundFailedError → 299-02 + failed receipt","invocations":1,"location":null,"numPassingAsserts":10,"retryReasons":[],"status":"passed","title":"cosmos REVERTED transition drives OutboundFailedError → 299-02 + failed receipt"},{"ancestorTitles":["R2 outbound REVERTED → 299-02 + externalStatus=failed (full-chain)"],"duration":222,"failureDetails":[],"failureMessages":[],"fullName":"R2 outbound REVERTED → 299-02 + externalStatus=failed (full-chain) cosmos timeout (UNSPECIFIED forever) drives OutboundTimeoutError → 299-03 + timeout receipt","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"cosmos timeout (UNSPECIFIED forever) drives OutboundTimeoutError → 299-03 + timeout receipt"}],"endTime":1792494868620,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/r2-outbound-revert-flow.spec.ts","startTime":1792494868253,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["buildPayloadForRoute — SVM Route 3"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"buildPayloadForRoute — SVM Route 3 keeps native SOL drains payload-only on Push while ixData carries the drain amount","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"keeps native SOL drains payload-only on Push while ixData carries the drain amount"},{"ancestorTitles":["buildPayloadForRoute — SVM Route 3"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"buildPayloadForRoute — SVM Route 3 keeps SPL drains payload-only on Push while ixData carries the drain amount","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"keeps SPL drains payload-only on Push while ixData carries the drain amount"},{"ancestorTitles":["buildPayloadForRoute — SVM Route 3"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"buildPayloadForRoute — SVM Route 3 wraps array data in an inbound UniversalPayload carrying a Push multicall","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"wraps array data in an inbound UniversalPayload carrying a Push multicall"},{"ancestorTitles":["buildPayloadForRoute — SVM Route 3"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"buildPayloadForRoute — SVM Route 3 wraps single calldata in an inbound UniversalPayload instead of sending raw calldata","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"wraps single calldata in an inbound UniversalPayload instead of sending raw calldata"},{"ancestorTitles":["buildPayloadForRoute — SVM Route 3"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"buildPayloadForRoute — SVM Route 3 uses the PC20 CEA-burn instruction and always embeds a forwarding payload","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"uses the PC20 CEA-burn instruction and always embeds a forwarding payload"},{"ancestorTitles":["outbound fee-locking skip decision"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"outbound fee-locking skip decision requires deployed UEA balance to cover native gas value plus reserve","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"requires deployed UEA balance to cover native gas value plus reserve"}],"endTime":1792494868950,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/route-handlers-svm-r3.spec.ts","startTime":1792494868623,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"reports unmapped source tokens without silently changing the default Push grant","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"reports unmapped source tokens without silently changing the default Push grant"},{"ancestorTitles":[],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"supports the explicit destination-funded grant with preserved token/amount pins and review metadata","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"supports the explicit destination-funded grant with preserved token/amount pins and review metadata"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"an explicitly selected mapped source token can be ready for Push funding","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"an explicitly selected mapped source token can be ready for Push funding"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"never treats a mainnet template or undeployed Push generation as executable","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"never treats a mainnet template or undeployed Push generation as executable"},{"ancestorTitles":[],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"supports the TESTNET alias, rejects invalid modes and preserves empty selections","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"supports the TESTNET alias, rejects invalid modes and preserves empty selections"}],"endTime":1792494869205,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/preset-routes.spec.ts","startTime":1792494868953,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":[],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"encodes v2’s four-field rules, accepts pinned approvals and fills published markers","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"encodes v2’s four-field rules, accepts pinned approvals and fills published markers"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"retains legacy beneficiary fields during an unchanged decode/encode","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"retains legacy beneficiary fields during an unchanged decode/encode"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"uses the explicit execution chain for native-token objects shared by several networks","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"uses the explicit execution chain for native-token objects shared by several networks"},{"ancestorTitles":[],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"refuses unsupported approval or transfer authority: spender","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"refuses unsupported approval or transfer authority: spender"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"refuses unsupported approval or transfer authority: amount","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"refuses unsupported approval or transfer authority: amount"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"refuses unsupported approval or transfer authority: recipient","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"refuses unsupported approval or transfer authority: recipient"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"refuses unsupported approval or transfer authority: increaseAllowance","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"refuses unsupported approval or transfer authority: increaseAllowance"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"refuses unsupported approval or transfer authority: oldArray","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"refuses unsupported approval or transfer authority: oldArray"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"does not silently drop duplicate alternatives or caps off the principal asset","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"does not silently drop duplicate alternatives or caps off the principal asset"}],"endTime":1792494869263,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/market/__tests__/rules.spec.ts","startTime":1792494869210,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["resolveUniversalTxFromSourceHash"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveUniversalTxFromSourceHash resolves universalTxId → record → first pcTx hash + sender","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"resolves universalTxId → record → first pcTx hash + sender"},{"ancestorTitles":["resolveUniversalTxFromSourceHash"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"resolveUniversalTxFromSourceHash throws an actionable error when the detector resolves no universalTxId","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"throws an actionable error when the detector resolves no universalTxId"},{"ancestorTitles":["resolveUniversalTxFromSourceHash"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveUniversalTxFromSourceHash throws when no universal record exists on Push Chain yet","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"throws when no universal record exists on Push Chain yet"},{"ancestorTitles":["resolveUniversalTxFromSourceHash"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveUniversalTxFromSourceHash throws when the record has no Push pcTx recorded yet","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"throws when the record has no Push pcTx recorded yet"}],"endTime":1792494869473,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/source-hash-resolution.spec.ts","startTime":1792494869266,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":[],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"confirms pending Cosmos signature EyFYDWDhksPYpRk3DLzeW4izQagJZte6bKCQFagLYBdtJyaEyjbQpAWCbqDhHVymzjPJ4vdeHG1HHQp1qi6FhZD through Solana RPC","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"confirms pending Cosmos signature EyFYDWDhksPYpRk3DLzeW4izQagJZte6bKCQFagLYBdtJyaEyjbQpAWCbqDhHVymzjPJ4vdeHG1HHQp1qi6FhZD through Solana RPC"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"confirms pending Cosmos signature 0x0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c through Solana RPC","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"confirms pending Cosmos signature 0x0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c through Solana RPC"},{"ancestorTitles":[],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"waits through processed status before finalization","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"waits through processed status before finalization"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"reports a confirmed signature error as failure, preserving the hash","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"reports a confirmed signature error as failure, preserving the hash"},{"ancestorTitles":[],"duration":21,"failureDetails":[],"failureMessages":[],"fullName":"keeps wrong-cluster pending until timeout","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"keeps wrong-cluster pending until timeout"},{"ancestorTitles":[],"duration":20,"failureDetails":[],"failureMessages":[],"fullName":"keeps missing pending until timeout","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"keeps missing pending until timeout"},{"ancestorTitles":[],"duration":20,"failureDetails":[],"failureMessages":[],"fullName":"keeps processed-error pending until timeout","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"keeps processed-error pending until timeout"},{"ancestorTitles":[],"duration":21,"failureDetails":[],"failureMessages":[],"fullName":"keeps rpc-error pending until timeout","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"keeps rpc-error pending until timeout"},{"ancestorTitles":[],"duration":21,"failureDetails":[],"failureMessages":[],"fullName":"keeps malformed-hash pending until timeout","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"keeps malformed-hash pending until timeout"},{"ancestorTitles":[],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"keeps an authoritative Cosmos revert ahead of the RPC tiebreaker","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"keeps an authoritative Cosmos revert ahead of the RPC tiebreaker"}],"endTime":1792494869710,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/outbound-svm-confirmation.spec.ts","startTime":1792494869475,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":[],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"public LENDING create gives a typed token-route error before any transaction","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"public LENDING create gives a typed token-route error before any transaction"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"public STAKING create gives a typed token-route error before any transaction","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"public STAKING create gives a typed token-route error before any transaction"},{"ancestorTitles":[],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"reports the complete 40-condition count for duplicated DEX entries, without dropping them","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"reports the complete 40-condition count for duplicated DEX entries, without dropping them"},{"ancestorTitles":[],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"validates stock DEX rules independently: two 20-condition rules do not become a 40-condition rule","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"validates stock DEX rules independently: two 20-condition rules do not become a 40-condition rule"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"does not misclassify a destination RPC failure as an unavailable token","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"does not misclassify a destination RPC failure as an unavailable token"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"provides safe UI copy for DUPLICATE_RULE while retaining diagnostic text","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"provides safe UI copy for DUPLICATE_RULE while retaining diagnostic text"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"provides safe UI copy for AGENT_IS_OWNER while retaining diagnostic text","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"provides safe UI copy for AGENT_IS_OWNER while retaining diagnostic text"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"provides safe UI copy for AMBIGUOUS_RULE while retaining diagnostic text","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"provides safe UI copy for AMBIGUOUS_RULE while retaining diagnostic text"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"provides safe UI copy for TARGET_NOT_ON_RULE_CHAIN while retaining diagnostic text","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"provides safe UI copy for TARGET_NOT_ON_RULE_CHAIN while retaining diagnostic text"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"provides safe UI copy for ASSET_CHAIN_MISMATCH while retaining diagnostic text","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"provides safe UI copy for ASSET_CHAIN_MISMATCH while retaining diagnostic text"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"provides safe UI copy for TOKEN_ROUTE_UNAVAILABLE while retaining diagnostic text","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"provides safe UI copy for TOKEN_ROUTE_UNAVAILABLE while retaining diagnostic text"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"provides safe UI copy for REQUEST_REJECTED while retaining diagnostic text","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"provides safe UI copy for REQUEST_REJECTED while retaining diagnostic text"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"provides safe UI copy for NOT_OWNER_OR_AGENT while retaining diagnostic text","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"provides safe UI copy for NOT_OWNER_OR_AGENT while retaining diagnostic text"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"provides safe UI copy for WALLET_NOT_DEPLOYED while retaining diagnostic text","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"provides safe UI copy for WALLET_NOT_DEPLOYED while retaining diagnostic text"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"provides safe UI copy for NOT_AGENTIC_WALLET while retaining diagnostic text","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"provides safe UI copy for NOT_AGENTIC_WALLET while retaining diagnostic text"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"provides safe UI copy for DELETE_NEEDS_TARGET while retaining diagnostic text","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"provides safe UI copy for DELETE_NEEDS_TARGET while retaining diagnostic text"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"provides safe UI copy for NO_RULES_FOR_CHAIN while retaining diagnostic text","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"provides safe UI copy for NO_RULES_FOR_CHAIN while retaining diagnostic text"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"provides safe UI copy for FROM_NOT_ALLOWED while retaining diagnostic text","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"provides safe UI copy for FROM_NOT_ALLOWED while retaining diagnostic text"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"provides safe UI copy for NOT_ALLOWED_IN_AGENTIC_MODE while retaining diagnostic text","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"provides safe UI copy for NOT_ALLOWED_IN_AGENTIC_MODE while retaining diagnostic text"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"provides safe UI copy for INVALID_RULE while retaining diagnostic text","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"provides safe UI copy for INVALID_RULE while retaining diagnostic text"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"provides safe UI copy for CAPABILITY_UNAVAILABLE while retaining diagnostic text","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"provides safe UI copy for CAPABILITY_UNAVAILABLE while retaining diagnostic text"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"provides safe UI copy for READ_ONLY while retaining diagnostic text","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"provides safe UI copy for READ_ONLY while retaining diagnostic text"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"provides safe UI copy for NOT_WALLET_OWNER while retaining diagnostic text","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"provides safe UI copy for NOT_WALLET_OWNER while retaining diagnostic text"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"provides safe UI copy for RULE_NOT_FOUND while retaining diagnostic text","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"provides safe UI copy for RULE_NOT_FOUND while retaining diagnostic text"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"provides safe UI copy for RULE_READ_FAILED while retaining diagnostic text","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"provides safe UI copy for RULE_READ_FAILED while retaining diagnostic text"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"provides safe UI copy for INCONSISTENT_READ while retaining diagnostic text","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"provides safe UI copy for INCONSISTENT_READ while retaining diagnostic text"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"provides safe UI copy for INDEX_RACE while retaining diagnostic text","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"provides safe UI copy for INDEX_RACE while retaining diagnostic text"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"provides safe UI copy for RECEIPT_MISMATCH while retaining diagnostic text","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"provides safe UI copy for RECEIPT_MISMATCH while retaining diagnostic text"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"provides safe UI copy for RECEIPT_UNAVAILABLE while retaining diagnostic text","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"provides safe UI copy for RECEIPT_UNAVAILABLE while retaining diagnostic text"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"provides safe UI copy for AGENT_GAS_INSUFFICIENT while retaining diagnostic text","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"provides safe UI copy for AGENT_GAS_INSUFFICIENT while retaining diagnostic text"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"provides safe UI copy for WALLET_BALANCE_INSUFFICIENT while retaining diagnostic text","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"provides safe UI copy for WALLET_BALANCE_INSUFFICIENT while retaining diagnostic text"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"keeps submitted hashes and uncertainty visible instead of inviting a blind retry","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"keeps submitted hashes and uncertainty visible instead of inviting a blind retry"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"explains the create and native action ceilings using the available structured reason","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"explains the create and native action ceilings using the available structured reason"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"preserves decoded contract failures and cancellation causes with UI messages","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"preserves decoded contract failures and cancellation causes with UI messages"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"explains OwnerSigExpired without confusing approvals, rules and balances","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"explains OwnerSigExpired without confusing approvals, rules and balances"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"explains RulesExpired without confusing approvals, rules and balances","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"explains RulesExpired without confusing approvals, rules and balances"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"explains ERC20InsufficientAllowance without confusing approvals, rules and balances","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"explains ERC20InsufficientAllowance without confusing approvals, rules and balances"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"explains ERC20InsufficientBalance without confusing approvals, rules and balances","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"explains ERC20InsufficientBalance without confusing approvals, rules and balances"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"explains TooManyAllowedCallPins without confusing approvals, rules and balances","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"explains TooManyAllowedCallPins without confusing approvals, rules and balances"}],"endTime":1792494870032,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/creation-errors.spec.ts","startTime":1792494869711,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["findChildUtxIdFromExternalTx — detector-first derivation"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"findChildUtxIdFromExternalTx — detector-first derivation happy path: detector returns a UniversalTx resolution, utxId is returned with derivedFrom=detector","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"happy path: detector returns a UniversalTx resolution, utxId is returned with derivedFrom=detector"},{"ancestorTitles":["findChildUtxIdFromExternalTx — detector-first derivation"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"findChildUtxIdFromExternalTx — detector-first derivation prefers UniversalTx resolution over RevertUniversalTx when both are present","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"prefers UniversalTx resolution over RevertUniversalTx when both are present"},{"ancestorTitles":["findChildUtxIdFromExternalTx — detector-first derivation"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"findChildUtxIdFromExternalTx — detector-first derivation detector returns empty resolutions → falls through to cosmos search (which also empty) → utxId=null","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"detector returns empty resolutions → falls through to cosmos search (which also empty) → utxId=null"},{"ancestorTitles":["findChildUtxIdFromExternalTx — detector-first derivation"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"findChildUtxIdFromExternalTx — detector-first derivation detector throws → cosmos fallback finds a hit → utxId returned with derivedFrom=cosmos-fallback","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"detector throws → cosmos fallback finds a hit → utxId returned with derivedFrom=cosmos-fallback"},{"ancestorTitles":["findChildUtxIdFromExternalTx — detector-first derivation"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"findChildUtxIdFromExternalTx — detector-first derivation no sourceChain provided: skips detector entirely, uses cosmos fallback only","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"no sourceChain provided: skips detector entirely, uses cosmos fallback only"},{"ancestorTitles":["findChildUtxIdFromExternalTx — detector-first derivation"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"findChildUtxIdFromExternalTx — detector-first derivation both detector and cosmos fail → returns {utxId:null, error}","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"both detector and cosmos fail → returns {utxId:null, error}"},{"ancestorTitles":["findChildUtxIdFromExternalTx — detector-first derivation"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"findChildUtxIdFromExternalTx — detector-first derivation normalizes Push Chain native balance errors from failed inbound pcTx","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"normalizes Push Chain native balance errors from failed inbound pcTx"},{"ancestorTitles":["findChildUtxIdFromExternalTx — detector-first derivation"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"findChildUtxIdFromExternalTx — detector-first derivation fails fast when inbound pcTx is failed before universalStatus becomes terminal","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"fails fast when inbound pcTx is failed before universalStatus becomes terminal"}],"endTime":1792494870266,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/inbound-tracker-derivation.spec.ts","startTime":1792494870035,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["UniversalSigner utilities","createUniversalSigner"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"UniversalSigner utilities createUniversalSigner should return a signer with provided methods and account","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"should return a signer with provided methods and account"},{"ancestorTitles":["UniversalSigner utilities","toUniversalFromKeypair - viem"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"UniversalSigner utilities toUniversalFromKeypair - viem wraps WalletClient correctly","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"wraps WalletClient correctly"},{"ancestorTitles":["UniversalSigner utilities","toUniversalFromKeypair - viem"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"UniversalSigner utilities toUniversalFromKeypair - viem rejects invalid account","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects invalid account"},{"ancestorTitles":["UniversalSigner utilities","toUniversalFromKeypair - EIP-7702 capability gating (viem)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"UniversalSigner utilities toUniversalFromKeypair - EIP-7702 capability gating (viem) exposes signAuthorization for a local account","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"exposes signAuthorization for a local account"},{"ancestorTitles":["UniversalSigner utilities","toUniversalFromKeypair - EIP-7702 capability gating (viem)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"UniversalSigner utilities toUniversalFromKeypair - EIP-7702 capability gating (viem) omits signAuthorization for a JSON-RPC account","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"omits signAuthorization for a JSON-RPC account"},{"ancestorTitles":["UniversalSigner utilities","toUniversalFromKeypair - ethers v6"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"UniversalSigner utilities toUniversalFromKeypair - ethers v6 wraps ethers.Wallet correctly","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"wraps ethers.Wallet correctly"},{"ancestorTitles":["UniversalSigner utilities","toUniversalFromKeypair - ethers v6"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"UniversalSigner utilities toUniversalFromKeypair - ethers v6 throws if no provider","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"throws if no provider"},{"ancestorTitles":["UniversalSigner utilities","toUniversalFromKeypair - solana"],"duration":21,"failureDetails":[],"failureMessages":[],"fullName":"UniversalSigner utilities toUniversalFromKeypair - solana wraps Solana Keypair correctly","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"wraps Solana Keypair correctly"},{"ancestorTitles":["UniversalSigner utilities","toUniversalFromKeypair - solana"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"UniversalSigner utilities toUniversalFromKeypair - solana throws on wrong chain","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"throws on wrong chain"},{"ancestorTitles":["UniversalSigner utilities","toUniversal"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"UniversalSigner utilities toUniversal preserves skeleton methods","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"preserves skeleton methods"},{"ancestorTitles":["UniversalSigner utilities","construct"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"UniversalSigner utilities construct should create a UniversalSignerSkeleton with required parameters","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"should create a UniversalSignerSkeleton with required parameters"},{"ancestorTitles":["UniversalSigner utilities","construct"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"UniversalSigner utilities construct should include signTypedData when provided","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should include signTypedData when provided"},{"ancestorTitles":["UniversalSigner utilities","construct"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"UniversalSigner utilities construct should include signAuthorization when provided","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should include signAuthorization when provided"},{"ancestorTitles":["UniversalSigner utilities","construct"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"UniversalSigner utilities construct should throw error when signTypedData is provided for Solana chain","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should throw error when signTypedData is provided for Solana chain"},{"ancestorTitles":["UniversalSigner utilities","construct"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"UniversalSigner utilities construct should work with Solana chain when signTypedData is not provided","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"should work with Solana chain when signTypedData is not provided"},{"ancestorTitles":["UniversalSigner utilities","construct"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"UniversalSigner utilities construct should throw when signAuthorization is provided for a Solana chain","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should throw when signAuthorization is provided for a Solana chain"},{"ancestorTitles":["UniversalSigner utilities","construct + toUniversal two-step process"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"UniversalSigner utilities construct + toUniversal two-step process should create a UniversalSigner through construct + toUniversal","invocations":1,"location":null,"numPassingAsserts":16,"retryReasons":[],"status":"passed","title":"should create a UniversalSigner through construct + toUniversal"},{"ancestorTitles":["UniversalSigner utilities","construct + toUniversal two-step process"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"UniversalSigner utilities construct + toUniversal two-step process should work without signTypedData for Solana chain","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"should work without signTypedData for Solana chain"}],"endTime":1792494870460,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/universal/signer/signer.spec.ts","startTime":1792494870270,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["Route 1 spec strings (101–199)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 1 spec strings (101–199) 101 — Origin Chain Detected","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"101 — Origin Chain Detected"},{"ancestorTitles":["Route 1 spec strings (101–199)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 1 spec strings (101–199) 102-01 — Estimating Gas","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"102-01 — Estimating Gas"},{"ancestorTitles":["Route 1 spec strings (101–199)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"Route 1 spec strings (101–199) 103-03-04 — Prepaid Deposit Estimated","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"103-03-04 — Prepaid Deposit Estimated"},{"ancestorTitles":["Route 1 spec strings (101–199)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 1 spec strings (101–199) 103-01 — Resolving Universal Execution Account","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"103-01 — Resolving Universal Execution Account"},{"ancestorTitles":["Route 1 spec strings (101–199)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 1 spec strings (101–199) 103-02 — Universal Execution Account Resolved","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"103-02 — Universal Execution Account Resolved"},{"ancestorTitles":["Route 1 spec strings (101–199)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 1 spec strings (101–199) 104-01 — Awaiting Transaction","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"104-01 — Awaiting Transaction"},{"ancestorTitles":["Route 1 spec strings (101–199)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 1 spec strings (101–199) 104-02 — Awaiting Signature","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"104-02 — Awaiting Signature"},{"ancestorTitles":["Route 1 spec strings (101–199)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 1 spec strings (101–199) 104-03 — Verification Success","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"104-03 — Verification Success"},{"ancestorTitles":["Route 1 spec strings (101–199)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 1 spec strings (101–199) 104-04 — Verification Declined (user decline)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"104-04 — Verification Declined (user decline)"},{"ancestorTitles":["Route 1 spec strings (101–199)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"Route 1 spec strings (101–199) 104-04 — Signature Failed (non-decline error)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"104-04 — Signature Failed (non-decline error)"},{"ancestorTitles":["Route 1 spec strings (101–199)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 1 spec strings (101–199) 105-01 — Gas Funding In Progress","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"105-01 — Gas Funding In Progress"},{"ancestorTitles":["Route 1 spec strings (101–199)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 1 spec strings (101–199) 105-02 — Gas Funding Confirmed","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"105-02 — Gas Funding Confirmed"},{"ancestorTitles":["Route 1 spec strings (101–199)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"Route 1 spec strings (101–199) 106-01 — Preparing Funds Transfer","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"106-01 — Preparing Funds Transfer"},{"ancestorTitles":["Route 1 spec strings (101–199)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 1 spec strings (101–199) 106-02 — Funds Lock Submitted","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"106-02 — Funds Lock Submitted"},{"ancestorTitles":["Route 1 spec strings (101–199)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"Route 1 spec strings (101–199) 106-03 — Awaiting Confirmations","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"106-03 — Awaiting Confirmations"},{"ancestorTitles":["Route 1 spec strings (101–199)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 1 spec strings (101–199) 106-03-01 — Confirmation intermediate (INFO)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"106-03-01 — Confirmation intermediate (INFO)"},{"ancestorTitles":["Route 1 spec strings (101–199)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 1 spec strings (101–199) 106-03-02 — Confirmation terminal (SUCCESS)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"106-03-02 — Confirmation terminal (SUCCESS)"},{"ancestorTitles":["Route 1 spec strings (101–199)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 1 spec strings (101–199) 106-04 — Funds Confirmed","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"106-04 — Funds Confirmed"},{"ancestorTitles":["Route 1 spec strings (101–199)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 1 spec strings (101–199) 106-05 — Syncing with Push Chain","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"106-05 — Syncing with Push Chain"},{"ancestorTitles":["Route 1 spec strings (101–199)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 1 spec strings (101–199) 106-06 — Funds Credited on Push Chain","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"106-06 — Funds Credited on Push Chain"},{"ancestorTitles":["Route 1 spec strings (101–199)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 1 spec strings (101–199) 107 — Broadcasting to Push Chain","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"107 — Broadcasting to Push Chain"},{"ancestorTitles":["Route 1 spec strings (101–199)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 1 spec strings (101–199) 199-01 — Push Chain Tx Success","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"199-01 — Push Chain Tx Success"},{"ancestorTitles":["Route 1 spec strings (101–199)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 1 spec strings (101–199) 199-02 — Push Chain Tx Failed","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"199-02 — Push Chain Tx Failed"},{"ancestorTitles":["Route 1 spec strings (101–199)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 1 spec strings (101–199) 199-03 — Syncing State with Push Chain Timeout","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"199-03 — Syncing State with Push Chain Timeout"},{"ancestorTitles":["Route 1 spec strings (101–199)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"Route 1 spec strings (101–199) 199-99 — Intermediate Push Chain Tx Completed","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"199-99 — Intermediate Push Chain Tx Completed"}],"endTime":1792494870588,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/progress-hook/__tests__/r1-spec-strings.spec.ts","startTime":1792494870462,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["sendPushTx native multicall routing"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"sendPushTx native multicall routing uses the atomic EIP-7702 route for a constructed signer","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"uses the atomic EIP-7702 route for a constructed signer"},{"ancestorTitles":["sendPushTx native multicall routing"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"sendPushTx native multicall routing estimates gas per operation in the sequential fallback","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"estimates gas per operation in the sequential fallback"},{"ancestorTitles":["sendPushTx native multicall routing"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"sendPushTx native multicall routing a revert in the sequential fallback carries the hashes already mined on the error","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"a revert in the sequential fallback carries the hashes already mined on the error"},{"ancestorTitles":["sendPushTx native multicall routing"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"sendPushTx native multicall routing falls back when authorization is unsupported before broadcast","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"falls back when authorization is unsupported before broadcast"},{"ancestorTitles":["sendPushTx native multicall routing"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"sendPushTx native multicall routing transforms a direct Push transaction only after its receipt succeeds","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"transforms a direct Push transaction only after its receipt succeeds"},{"ancestorTitles":["sendPushTx native multicall routing"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"sendPushTx native multicall routing rejects a reverted direct Push receipt before indexing or transforming it","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"rejects a reverted direct Push receipt before indexing or transforming it"},{"ancestorTitles":["atomic-only native batches (AGW sender-preserving arrays)"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"atomic-only native batches (AGW sender-preserving arrays) rejects missing signer capability without sending any sequential call","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"rejects missing signer capability without sending any sequential call"},{"ancestorTitles":["atomic-only native batches (AGW sender-preserving arrays)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"atomic-only native batches (AGW sender-preserving arrays) refuses a missing executor before authorization or broadcast","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"refuses a missing executor before authorization or broadcast"},{"ancestorTitles":["atomic-only native batches (AGW sender-preserving arrays)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"atomic-only native batches (AGW sender-preserving arrays) does not fall back when authorization is exposed but unsupported at runtime","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"does not fall back when authorization is exposed but unsupported at runtime"},{"ancestorTitles":["atomic-only native batches (AGW sender-preserving arrays)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"atomic-only native batches (AGW sender-preserving arrays) uses the atomic transport when signer and executor are available","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"uses the atomic transport when signer and executor are available"}],"endTime":1792494870764,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/push-chain-native-multicall.spec.ts","startTime":1792494870590,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["executeReads app-contract path"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"executeReads app-contract path retains all sequential hashes for a missing request mismatch","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"retains all sequential hashes for a missing request mismatch"},{"ancestorTitles":["executeReads app-contract path"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"executeReads app-contract path retains all sequential hashes for a extra request mismatch","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"retains all sequential hashes for a extra request mismatch"},{"ancestorTitles":["executeReads app-contract path"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"executeReads app-contract path announces a stale prepared read (READ-TX-102-04) before revalidating it","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"announces a stale prepared read (READ-TX-102-04) before revalidating it"},{"ancestorTitles":["executeReads app-contract path"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"executeReads app-contract path a fresh prepared read is not announced stale","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"a fresh prepared read is not announced stale"},{"ancestorTitles":["executeReads app-contract path"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"executeReads app-contract path empty batches perform no execution or tracking","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"empty batches perform no execution or tracking"},{"ancestorTitles":["executeReads app-contract path"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"executeReads app-contract path maps identical prepared reads to distinct requests in log order","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"maps identical prepared reads to distinct requests in log order"},{"ancestorTitles":["executeReads app-contract path"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"executeReads app-contract path rejects a matching spec with a different callbackTarget","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects a matching spec with a different callbackTarget"},{"ancestorTitles":["executeReads app-contract path"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"executeReads app-contract path rejects a matching spec with a different callbackGasLimit","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects a matching spec with a different callbackGasLimit"},{"ancestorTitles":["executeReads app-contract path","partial batches through the real native execution layers"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"executeReads app-contract path partial batches through the real native execution layers retains recovery metadata after send failure","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"retains recovery metadata after send failure"},{"ancestorTitles":["executeReads app-contract path","partial batches through the real native execution layers"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"executeReads app-contract path partial batches through the real native execution layers retains recovery metadata after decline failure","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"retains recovery metadata after decline failure"},{"ancestorTitles":["executeReads app-contract path","partial batches through the real native execution layers"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"executeReads app-contract path partial batches through the real native execution layers retains recovery metadata after nonce-refresh failure","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"retains recovery metadata after nonce-refresh failure"},{"ancestorTitles":["executeReads app-contract path","partial batches through the real native execution layers"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"executeReads app-contract path partial batches through the real native execution layers retains recovery metadata after receipt failure","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"retains recovery metadata after receipt failure"},{"ancestorTitles":["executeReads app-contract path","partial batches through the real native execution layers"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"executeReads app-contract path partial batches through the real native execution layers retains recovery metadata after first-receipt failure","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"retains recovery metadata after first-receipt failure"},{"ancestorTitles":["executeReads app-contract path","partial batches through the real native execution layers"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"executeReads app-contract path partial batches through the real native execution layers retains recovery metadata after revert failure","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"retains recovery metadata after revert failure"},{"ancestorTitles":["executeReads app-contract path","partial batches through the real native execution layers"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"executeReads app-contract path partial batches through the real native execution layers retains recovery metadata after index failure","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"retains recovery metadata after index failure"},{"ancestorTitles":["executeReads app-contract path","partial batches through the real native execution layers"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"executeReads app-contract path partial batches through the real native execution layers retains recovery metadata after response failure","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"retains recovery metadata after response failure"},{"ancestorTitles":["executeReads app-contract path"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"executeReads app-contract path supports explicit request argument mapping","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"supports explicit request argument mapping"},{"ancestorTitles":["executeReads app-contract path"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"executeReads app-contract path passes an IDL result shape through batch execution and waiting","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"passes an IDL result shape through batch execution and waiting"},{"ancestorTitles":["executeReads app-contract path"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"executeReads app-contract path encodes the app entrypoint, forwards escrow and preserves each decode shape and input order","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"encodes the app entrypoint, forwards escrow and preserves each decode shape and input order"},{"ancestorTitles":["executeReads app-contract path"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"executeReads app-contract path waitForCompletion=false returns resumable snapshots without polling","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"waitForCompletion=false returns resumable snapshots without polling"},{"ancestorTitles":["executeReads app-contract path"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"executeReads app-contract path collects every hash after sequential wallet fallback","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"collects every hash after sequential wallet fallback"},{"ancestorTitles":["executeReads app-contract path"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"executeReads app-contract path validates the entire batch before broadcasting","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"validates the entire batch before broadcasting"},{"ancestorTitles":["executeReads app-contract path"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"executeReads app-contract path rejects missing or extra request logs with the transaction hash for recovery","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"rejects missing or extra request logs with the transaction hash for recovery"},{"ancestorTitles":["executeReads app-contract path"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"executeReads app-contract path a non-atomic batch that fails midway surfaces the hashes already mined","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"a non-atomic batch that fails midway surfaces the hashes already mined"},{"ancestorTitles":["executeReads app-contract path"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"executeReads app-contract path assertRequestEntrypoint rejects a malformed entrypoint without any network","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"assertRequestEntrypoint rejects a malformed entrypoint without any network"},{"ancestorTitles":["executeReads app-contract path"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"executeReads app-contract path does not track a reverted request transaction","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"does not track a reverted request transaction"},{"ancestorTitles":["executeReads app-contract path"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"executeReads app-contract path preserves callback failure responses and propagates read timeouts","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"preserves callback failure responses and propagates read timeouts"},{"ancestorTitles":["execution validation and observable progress"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"execution validation and observable progress emits the OG balance event and enforces the read-value check when requested","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"emits the OG balance event and enforces the read-value check when requested"},{"ancestorTitles":["execution validation and observable progress"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"execution validation and observable progress does not broadcast any read when a later prepared request is invalid","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"does not broadcast any read when a later prepared request is invalid"},{"ancestorTitles":["execution validation and observable progress"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"execution validation and observable progress deduplicates shared hooks and emits batch success only after completion","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"deduplicates shared hooks and emits batch success only after completion"},{"ancestorTitles":["execution validation and observable progress"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"execution validation and observable progress emits confirmed events but no completion for no-wait requests","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"emits confirmed events but no completion for no-wait requests"},{"ancestorTitles":["execution validation and observable progress"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"execution validation and observable progress reports callback failure as batch failure while resolving terminal results","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"reports callback failure as batch failure while resolving terminal results"}],"endTime":1792494870937,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/read-state/__tests__/read-executor.spec.ts","startTime":1792494870779,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["agentic.create"],"duration":5,"failureDetails":[],"failureMessages":[],"fullName":"agentic.create validates first, then sends deploy + grants in input order and returns receipt IDs","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"validates first, then sends deploy + grants in input order and returns receipt IDs"},{"ancestorTitles":["agentic.create"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"agentic.create a bare wallet is one deployWallet call, no funding","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"a bare wallet is one deployWallet call, no funding"},{"ancestorTitles":["agentic.create"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"agentic.create invalid input never reaches the signer","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"invalid input never reaches the signer"},{"ancestorTitles":["agentic.create"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"agentic.create refuses a changed URP version before grant signing","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"refuses a changed URP version before grant signing"},{"ancestorTitles":["agentic.create"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"agentic.create a different wallet in the receipt is RECEIPT_MISMATCH, not a safe-to-retry race","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"a different wallet in the receipt is RECEIPT_MISMATCH, not a safe-to-retry race"},{"ancestorTitles":["agentic.create"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"agentic.create IDs that differ from the input order are a RECEIPT_MISMATCH, not a silent reorder","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"IDs that differ from the input order are a RECEIPT_MISMATCH, not a silent reorder"},{"ancestorTitles":["agentic.create"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"agentic.create creation never uses the batch transport or a sequential fallback","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"creation never uses the batch transport or a sequential fallback"},{"ancestorTitles":["agentic.create"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"agentic.create a receipt that cannot be read after submission keeps the hash and reports unknown state","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"a receipt that cannot be read after submission keeps the hash and reports unknown state"},{"ancestorTitles":["agentic.create"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"agentic.create the deploy is index-bound: a raced slot reverts and is reported as INDEX_RACE with nothing committed","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"the deploy is index-bound: a raced slot reverts and is reported as INDEX_RACE with nothing committed"},{"ancestorTitles":["agentic.create"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"agentic.create a later rename alone does not establish a competing creation","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"a later rename alone does not establish a competing creation"},{"ancestorTitles":["agentic.create"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"agentic.create a slot that is already deployed is refused before signing","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"a slot that is already deployed is refused before signing"},{"ancestorTitles":["rules.add / rules.delete"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"rules.add / rules.delete add: owner-only, duplicate agent/chain refused before signing","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"add: owner-only, duplicate agent/chain refused before signing"},{"ancestorTitles":["rules.add / rules.delete"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"rules.add / rules.delete add: several rules are one atomic owner execute batch (one signature on any signer)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"add: several rules are one atomic owner execute batch (one signature on any signer)"},{"ancestorTitles":["rules.add / rules.delete"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"rules.add / rules.delete revoke: bare and empty are refused; unknown IDs fail before signing; several IDs are one atomic owner execute","invocations":1,"location":null,"numPassingAsserts":10,"retryReasons":[],"status":"passed","title":"revoke: bare and empty are refused; unknown IDs fail before signing; several IDs are one atomic owner execute"},{"ancestorTitles":["rules.update — one owner batch: assert → revoke → grant"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"rules.update — one owner batch: assert → revoke → grant builds exactly one execute(batch) with the observed spend asserted per pair","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"builds exactly one execute(batch) with the observed spend asserted per pair"},{"ancestorTitles":["rules.update — one owner batch: assert → revoke → grant"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"rules.update — one owner batch: assert → revoke → grant universal replacement asserts every asset in stored order before revoke/grant","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"universal replacement asserts every asset in stored order before revoke/grant"},{"ancestorTitles":["rules.update — one owner batch: assert → revoke → grant"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"rules.update — one owner batch: assert → revoke → grant replacement may name another live agent, but may not repeat an old ID","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"replacement may name another live agent, but may not repeat an old ID"}],"endTime":1792494871320,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/management.spec.ts","startTime":1792494870941,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["Orchestrator.createCascadedBuilder — per-call progressHook"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Orchestrator.createCascadedBuilder — per-call progressHook does NOT wrap ctx.progressHook when no per-call hook is provided","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"does NOT wrap ctx.progressHook when no per-call hook is provided"},{"ancestorTitles":["Orchestrator.createCascadedBuilder — per-call progressHook"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Orchestrator.createCascadedBuilder — per-call progressHook passes the per-call hook as defaultEventHook (4th arg) to the cascade builder","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"passes the per-call hook as defaultEventHook (4th arg) to the cascade builder"},{"ancestorTitles":["Orchestrator.createCascadedBuilder — per-call progressHook"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Orchestrator.createCascadedBuilder — per-call progressHook passes cascade-level enforceGasCheck to the cascade builder","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"passes cascade-level enforceGasCheck to the cascade builder"},{"ancestorTitles":["Orchestrator.createCascadedBuilder — per-call progressHook"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"Orchestrator.createCascadedBuilder — per-call progressHook wraps ctx.progressHook to fan events to BOTH init-time and per-call hooks during send()","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"wraps ctx.progressHook to fan events to BOTH init-time and per-call hooks during send()"},{"ancestorTitles":["Orchestrator.createCascadedBuilder — per-call progressHook"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Orchestrator.createCascadedBuilder — per-call progressHook dedups when the per-call hook IS the init-time hook (same reference fires once)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"dedups when the per-call hook IS the init-time hook (same reference fires once)"},{"ancestorTitles":["Orchestrator.createCascadedBuilder — per-call progressHook"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Orchestrator.createCascadedBuilder — per-call progressHook delivers events to the per-call hook even when no init-time hook is configured","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"delivers events to the per-call hook even when no init-time hook is configured"},{"ancestorTitles":["Orchestrator.createCascadedBuilder — per-call progressHook"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Orchestrator.createCascadedBuilder — per-call progressHook restores ctx.progressHook after send() resolves","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"restores ctx.progressHook after send() resolves"},{"ancestorTitles":["Orchestrator.createCascadedBuilder — per-call progressHook"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"Orchestrator.createCascadedBuilder — per-call progressHook restores ctx.progressHook even when send() rejects","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"restores ctx.progressHook even when send() rejects"},{"ancestorTitles":["Orchestrator.createCascadedBuilder — per-call progressHook"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"Orchestrator.createCascadedBuilder — per-call progressHook isolates per-call hooks across two sequential cascade calls","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"isolates per-call hooks across two sequential cascade calls"}],"endTime":1792494871453,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/cascade-builder-progress-hook.spec.ts","startTime":1792494871323,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["v5 internal SVM wire codec"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"v5 internal SVM wire codec round-trips ordered per-token caps and all four data-pin modes","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"round-trips ordered per-token caps and all four data-pin modes"},{"ancestorTitles":["v5 internal SVM wire codec"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"v5 internal SVM wire codec rejects expired before encoding","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects expired before encoding"},{"ancestorTitles":["v5 internal SVM wire codec"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"v5 internal SVM wire codec rejects zero CEA before encoding","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects zero CEA before encoding"},{"ancestorTitles":["v5 internal SVM wire codec"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"v5 internal SVM wire codec rejects empty assets before encoding","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects empty assets before encoding"},{"ancestorTitles":["v5 internal SVM wire codec"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"v5 internal SVM wire codec rejects duplicate tokens before encoding","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects duplicate tokens before encoding"},{"ancestorTitles":["v5 internal SVM wire codec"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"v5 internal SVM wire codec rejects system program before encoding","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects system program before encoding"},{"ancestorTitles":["v5 internal SVM wire codec"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"v5 internal SVM wire codec rejects ambiguous prefixes before encoding","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects ambiguous prefixes before encoding"},{"ancestorTitles":["v5 internal SVM wire codec"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"v5 internal SVM wire codec rejects missing pin before encoding","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects missing pin before encoding"},{"ancestorTitles":["v5 internal SVM wire codec"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"v5 internal SVM wire codec rejects duplicate pin before encoding","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects duplicate pin before encoding"},{"ancestorTitles":["v5 internal SVM wire codec"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"v5 internal SVM wire codec rejects CEA absent before encoding","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects CEA absent before encoding"},{"ancestorTitles":["v5 internal SVM wire codec"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"v5 internal SVM wire codec rejects fixed count outside bound before encoding","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects fixed count outside bound before encoding"},{"ancestorTitles":["v5 internal SVM wire codec"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"v5 internal SVM wire codec refuses misleading integer/raw alignment and zero ratio denominators","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"refuses misleading integer/raw alignment and zero ratio denominators"},{"ancestorTitles":["wallet-scoped SVM value accounts"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"wallet-scoped SVM value accounts derives the exact PDA from wallet20 and the selected gateway","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"derives the exact PDA from wallet20 and the selected gateway"},{"ancestorTitles":["wallet-scoped SVM value accounts"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"wallet-scoped SVM value accounts resolved token caps cannot omit their corresponding protected ATAs","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"resolved token caps cannot omit their corresponding protected ATAs"},{"ancestorTitles":["wallet-scoped SVM value accounts"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"wallet-scoped SVM value accounts includes input/output ATAs, deduplicates, and separates Token-2022 accounts","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"includes input/output ATAs, deduplicates, and separates Token-2022 accounts"},{"ancestorTitles":["S12–S18 payload checks"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"S12–S18 payload checks matches the existing node encoder and parses every byte including writable flags","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"matches the existing node encoder and parses every byte including writable flags"},{"ancestorTitles":["S12–S18 payload checks"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"S12–S18 payload checks rejects trailing data with the corresponding contract error","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects trailing data with the corresponding contract error"},{"ancestorTitles":["S12–S18 payload checks"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"S12–S18 payload checks rejects truncated with the corresponding contract error","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects truncated with the corresponding contract error"},{"ancestorTitles":["S12–S18 payload checks"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"S12–S18 payload checks rejects oversized count with the corresponding contract error","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects oversized count with the corresponding contract error"},{"ancestorTitles":["S12–S18 payload checks"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"S12–S18 payload checks pins prevent key substitution and protected-account aliasing","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"pins prevent key substitution and protected-account aliasing"},{"ancestorTitles":["S12–S18 payload checks"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"S12–S18 payload checks enforces little-endian floors/ceilings, from-end offsets, ratios and exact byte pins","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"enforces little-endian floors/ceilings, from-end offsets, ratios and exact byte pins"},{"ancestorTitles":["internal SVM outbound action"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"internal SVM outbound action uses the program recipient, wallet refund and quoted PC while preserving the exact payload","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"uses the program recipient, wallet refund and quoted PC while preserving the exact payload"},{"ancestorTitles":["internal SVM outbound action"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"internal SVM outbound action rejects caps, zero gas and unknown assets before signing","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"rejects caps, zero gas and unknown assets before signing"}],"endTime":1792494871746,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts","startTime":1792494871457,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["Route 2 spec strings (201–299)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 2 spec strings (201–299) 201 — {ChainName} Detected","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"201 — {ChainName} Detected"},{"ancestorTitles":["Route 2 spec strings (201–299)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 2 spec strings (201–299) 202-01 — Estimating {ChainName} Chain Gas","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"202-01 — Estimating {ChainName} Chain Gas"},{"ancestorTitles":["Route 2 spec strings (201–299)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 2 spec strings (201–299) 202-02 — {ChainName} Chain Gas Estimated","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"202-02 — {ChainName} Chain Gas Estimated"},{"ancestorTitles":["Route 2 spec strings (201–299)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 2 spec strings (201–299) 203-01 — Resolving {ChainName} Execution Account","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"203-01 — Resolving {ChainName} Execution Account"},{"ancestorTitles":["Route 2 spec strings (201–299)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"Route 2 spec strings (201–299) 203-02 — {ChainName} Execution Account Resolved","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"203-02 — {ChainName} Execution Account Resolved"},{"ancestorTitles":["Route 2 spec strings (201–299)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 2 spec strings (201–299) 204-01 — Awaiting Signature","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"204-01 — Awaiting Signature"},{"ancestorTitles":["Route 2 spec strings (201–299)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 2 spec strings (201–299) 204-02 — Signature Received","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"204-02 — Signature Received"},{"ancestorTitles":["Route 2 spec strings (201–299)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 2 spec strings (201–299) 204-03 — Verification Success","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"204-03 — Verification Success"},{"ancestorTitles":["Route 2 spec strings (201–299)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 2 spec strings (201–299) 204-04 — Verification Declined (genuine user decline)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"204-04 — Verification Declined (genuine user decline)"},{"ancestorTitles":["Route 2 spec strings (201–299)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 2 spec strings (201–299) 207 — Broadcasting from Push Chain → {ChainName}","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"207 — Broadcasting from Push Chain → {ChainName}"},{"ancestorTitles":["Route 2 spec strings (201–299)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 2 spec strings (201–299) 209-01 — Awaiting Push Chain Relay","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"209-01 — Awaiting Push Chain Relay"},{"ancestorTitles":["Route 2 spec strings (201–299)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 2 spec strings (201–299) 209-02 — Syncing State with {ChainName}","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"209-02 — Syncing State with {ChainName}"},{"ancestorTitles":["Route 2 spec strings (201–299)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 2 spec strings (201–299) 299-01 — {ChainName} Tx Success","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"299-01 — {ChainName} Tx Success"},{"ancestorTitles":["Route 2 spec strings (201–299)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 2 spec strings (201–299) 299-02 — {ChainName} Tx Failed","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"299-02 — {ChainName} Tx Failed"},{"ancestorTitles":["Route 2 spec strings (201–299)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 2 spec strings (201–299) 299-03 — Syncing State with {ChainName} Timeout","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"299-03 — Syncing State with {ChainName} Timeout"},{"ancestorTitles":["Route 2 spec strings (201–299)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 2 spec strings (201–299) 299-99 — Intermediate {ChainName} Tx Completed","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"299-99 — Intermediate {ChainName} Tx Completed"}],"endTime":1792494871934,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/progress-hook/__tests__/r2-spec-strings.spec.ts","startTime":1792494871751,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["gateway request recipient"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"gateway request recipient names the UEA for a PC20 burn so the native gas leg can be credited","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"names the UEA for a PC20 burn so the native gas leg can be credited"},{"ancestorTitles":["gateway request recipient"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"gateway request recipient keeps the zero sentinel for a non-PC20 transfer","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"keeps the zero sentinel for a non-PC20 transfer"},{"ancestorTitles":["gateway request recipient"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"gateway request recipient keeps the zero sentinel for a PC20 export (no burn leg on the source)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"keeps the zero sentinel for a PC20 export (no burn leg on the source)"}],"endTime":1792494872064,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/pc20-request-recipient.spec.ts","startTime":1792494871939,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["route-detector","isChainTarget"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"route-detector isChainTarget should return true for valid ChainTarget object","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return true for valid ChainTarget object"},{"ancestorTitles":["route-detector","isChainTarget"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"route-detector isChainTarget should return false for simple string address","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return false for simple string address"},{"ancestorTitles":["route-detector","isChainTarget"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"route-detector isChainTarget should return false for null/undefined","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should return false for null/undefined"},{"ancestorTitles":["route-detector","isChainTarget"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"route-detector isChainTarget should return false for object without chain property","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return false for object without chain property"},{"ancestorTitles":["route-detector","isPushChain"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"route-detector isPushChain should return true for Push Chain testnet","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return true for Push Chain testnet"},{"ancestorTitles":["route-detector","isPushChain"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"route-detector isPushChain should return true for Push Chain mainnet","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return true for Push Chain mainnet"},{"ancestorTitles":["route-detector","isPushChain"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"route-detector isPushChain should return true for Push Chain localnet","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return true for Push Chain localnet"},{"ancestorTitles":["route-detector","isPushChain"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"route-detector isPushChain should return false for external EVM chains","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should return false for external EVM chains"},{"ancestorTitles":["route-detector","isPushChain"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"route-detector isPushChain should return false for Solana","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return false for Solana"},{"ancestorTitles":["route-detector","isSupportedExternalChain"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"route-detector isSupportedExternalChain should return true for supported EVM chains","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"should return true for supported EVM chains"},{"ancestorTitles":["route-detector","isSupportedExternalChain"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"route-detector isSupportedExternalChain should return false for Push Chain","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return false for Push Chain"},{"ancestorTitles":["route-detector","isSupportedExternalChain"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"route-detector isSupportedExternalChain should return true for Solana","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return true for Solana"},{"ancestorTitles":["route-detector","detectRoute","Route 1: UOA_TO_PUSH"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"route-detector detectRoute Route 1: UOA_TO_PUSH should detect simple string address as UOA_TO_PUSH","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should detect simple string address as UOA_TO_PUSH"},{"ancestorTitles":["route-detector","detectRoute","Route 1: UOA_TO_PUSH"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"route-detector detectRoute Route 1: UOA_TO_PUSH should detect ChainTarget with Push Chain as UOA_TO_PUSH","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should detect ChainTarget with Push Chain as UOA_TO_PUSH"},{"ancestorTitles":["route-detector","detectRoute","Route 2: UOA_TO_CEA"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"route-detector detectRoute Route 2: UOA_TO_CEA should detect ChainTarget with external chain as UOA_TO_CEA","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should detect ChainTarget with external chain as UOA_TO_CEA"},{"ancestorTitles":["route-detector","detectRoute","Route 2: UOA_TO_CEA"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"route-detector detectRoute Route 2: UOA_TO_CEA should detect with Ethereum Sepolia","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should detect with Ethereum Sepolia"},{"ancestorTitles":["route-detector","detectRoute","Route 3: CEA_TO_PUSH"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"route-detector detectRoute Route 3: CEA_TO_PUSH should detect from.chain with Push target as CEA_TO_PUSH","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should detect from.chain with Push target as CEA_TO_PUSH"},{"ancestorTitles":["route-detector","detectRoute","Route 4: CEA_TO_CEA"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"route-detector detectRoute Route 4: CEA_TO_CEA should detect from.chain with external target as CEA_TO_CEA","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should detect from.chain with external target as CEA_TO_CEA"},{"ancestorTitles":["route-detector","validateRouteParams"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"route-detector validateRouteParams should pass for valid UOA_TO_PUSH params","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should pass for valid UOA_TO_PUSH params"},{"ancestorTitles":["route-detector","validateRouteParams"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"route-detector validateRouteParams should pass for valid UOA_TO_CEA params","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should pass for valid UOA_TO_CEA params"},{"ancestorTitles":["route-detector","validateRouteParams"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"route-detector validateRouteParams should throw for invalid to address","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should throw for invalid to address"},{"ancestorTitles":["route-detector","validateRouteParams"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"route-detector validateRouteParams should throw for ChainTarget with invalid address","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should throw for ChainTarget with invalid address"},{"ancestorTitles":["route-detector","validateRouteParams"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"route-detector validateRouteParams rejects CHAIN.WEB2 at the transaction runtime boundary","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects CHAIN.WEB2 at the transaction runtime boundary"},{"ancestorTitles":["route-detector","C-5: Enhanced unsupported token validation","Route 2 (UOA_TO_CEA) token validation"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"route-detector C-5: Enhanced unsupported token validation Route 2 (UOA_TO_CEA) token validation should throw with clientChain in error message for unsupported token","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"should throw with clientChain in error message for unsupported token"},{"ancestorTitles":["route-detector","C-5: Enhanced unsupported token validation","Route 2 (UOA_TO_CEA) token validation"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"route-detector C-5: Enhanced unsupported token validation Route 2 (UOA_TO_CEA) token validation should pass for USDT on Ethereum Sepolia (compatible token)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should pass for USDT on Ethereum Sepolia (compatible token)"},{"ancestorTitles":["route-detector","C-5: Enhanced unsupported token validation","Route 2 (UOA_TO_CEA) token validation"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"route-detector C-5: Enhanced unsupported token validation Route 2 (UOA_TO_CEA) token validation should throw for Push PRC-20 whose sourceChain does not match destination","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should throw for Push PRC-20 whose sourceChain does not match destination"},{"ancestorTitles":["route-detector","C-5: Enhanced unsupported token validation","Route 2 (UOA_TO_CEA) token validation"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"route-detector C-5: Enhanced unsupported token validation Route 2 (UOA_TO_CEA) token validation should pass for Push PRC-20 whose sourceChain matches destination","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should pass for Push PRC-20 whose sourceChain matches destination"},{"ancestorTitles":["route-detector","C-5: Enhanced unsupported token validation","Route 2 (UOA_TO_CEA) token validation"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"route-detector C-5: Enhanced unsupported token validation Route 2 (UOA_TO_CEA) token validation should pass for Push PRC-20 USDT variant matching destination","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should pass for Push PRC-20 USDT variant matching destination"},{"ancestorTitles":["route-detector","C-5: Enhanced unsupported token validation","Route 2 (UOA_TO_CEA) token validation"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"route-detector C-5: Enhanced unsupported token validation Route 2 (UOA_TO_CEA) token validation should show \"unknown\" clientChain when context is omitted","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should show \"unknown\" clientChain when context is omitted"},{"ancestorTitles":["route-detector","C-5: Enhanced unsupported token validation","Route 3 (CEA_TO_PUSH) token validation"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"route-detector C-5: Enhanced unsupported token validation Route 3 (CEA_TO_PUSH) token validation should throw for incompatible token on source chain","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"should throw for incompatible token on source chain"},{"ancestorTitles":["route-detector","C-5: Enhanced unsupported token validation","Route 3 (CEA_TO_PUSH) token validation"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"route-detector C-5: Enhanced unsupported token validation Route 3 (CEA_TO_PUSH) token validation should pass for compatible token on source chain","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should pass for compatible token on source chain"},{"ancestorTitles":["route-detector","C-5: Enhanced unsupported token validation","Route 3 (CEA_TO_PUSH) token validation"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"route-detector C-5: Enhanced unsupported token validation Route 3 (CEA_TO_PUSH) token validation should pass for Push PRC-20 whose sourceChain matches from.chain","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should pass for Push PRC-20 whose sourceChain matches from.chain"},{"ancestorTitles":["route-detector","C-5: Enhanced unsupported token validation","Route 3 (CEA_TO_PUSH) token validation"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"route-detector C-5: Enhanced unsupported token validation Route 3 (CEA_TO_PUSH) token validation should throw for Push PRC-20 whose sourceChain does not match from.chain","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should throw for Push PRC-20 whose sourceChain does not match from.chain"},{"ancestorTitles":["route-detector","C-5: Enhanced unsupported token validation","Route 3 (CEA_TO_PUSH) token validation"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"route-detector C-5: Enhanced unsupported token validation Route 3 (CEA_TO_PUSH) token validation should throw for ETH on Solana source chain","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should throw for ETH on Solana source chain"},{"ancestorTitles":["route-detector","C-5: Enhanced unsupported token validation","error message format"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"route-detector C-5: Enhanced unsupported token validation error message format should include token label with chain prefix when token is found in registry","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should include token label with chain prefix when token is found in registry"},{"ancestorTitles":["route-detector","chainEnumToName"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"route-detector chainEnumToName should return friendly name for known chains","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should return friendly name for known chains"},{"ancestorTitles":["route-detector","chainEnumToName"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"route-detector chainEnumToName should return the raw value for unknown chains","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return the raw value for unknown chains"},{"ancestorTitles":["route-detector","findTokenChain"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"route-detector findTokenChain should find USDT on Ethereum Sepolia by address match","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should find USDT on Ethereum Sepolia by address match"},{"ancestorTitles":["route-detector","findTokenChain"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"route-detector findTokenChain should return undefined for unknown token","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return undefined for unknown token"}],"endTime":1792494872199,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/route-detector.spec.ts","startTime":1792494872067,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["dispatchCascadeProgressEvent"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"dispatchCascadeProgressEvent no-op when both channels are undefined","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"no-op when both channels are undefined"},{"ancestorTitles":["dispatchCascadeProgressEvent"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"dispatchCascadeProgressEvent delivers to the explicit eventHook only when ctx.progressHook is unset","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"delivers to the explicit eventHook only when ctx.progressHook is unset"},{"ancestorTitles":["dispatchCascadeProgressEvent"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"dispatchCascadeProgressEvent bridges to ctx.progressHook when no explicit eventHook is supplied (THE redeem-flow fix)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"bridges to ctx.progressHook when no explicit eventHook is supplied (THE redeem-flow fix)"},{"ancestorTitles":["dispatchCascadeProgressEvent"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"dispatchCascadeProgressEvent fans out to both channels when they are different references","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"fans out to both channels when they are different references"},{"ancestorTitles":["dispatchCascadeProgressEvent"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"dispatchCascadeProgressEvent dedups when both channels reference the SAME function","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"dedups when both channels reference the SAME function"},{"ancestorTitles":["dispatchCascadeProgressEvent"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"dispatchCascadeProgressEvent drops events with empty id (pickWaitHooks no-op sentinel)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"drops events with empty id (pickWaitHooks no-op sentinel)"},{"ancestorTitles":["dispatchCascadeProgressEvent"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"dispatchCascadeProgressEvent preserves the ProgressEvent shape (no field reshaping)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"preserves the ProgressEvent shape (no field reshaping)"},{"ancestorTitles":["dispatchCascadeProgressEvent"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"dispatchCascadeProgressEvent handles cascade-failure markers (999-02) the same way as success","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"handles cascade-failure markers (999-02) the same way as success"},{"ancestorTitles":["dispatchCascadeProgressEvent"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"dispatchCascadeProgressEvent delivers a multi-event sequence in order across the bridge","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"delivers a multi-event sequence in order across the bridge"}],"endTime":1792494872327,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/cascade-event-hook-bridge.spec.ts","startTime":1792494872201,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"resolves explicit native ETH on eip155:11155111 to the same burn token as omitted native funds","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"resolves explicit native ETH on eip155:11155111 to the same burn token as omitted native funds"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolves explicit native ETH on eip155:84532 to the same burn token as omitted native funds","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"resolves explicit native ETH on eip155:84532 to the same burn token as omitted native funds"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolves explicit native ETH on eip155:421614 to the same burn token as omitted native funds","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"resolves explicit native ETH on eip155:421614 to the same burn token as omitted native funds"},{"ancestorTitles":[],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"does not infer a token from a different destination chain","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"does not infer a token from a different destination chain"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"preserves a matching explicit Push PRC20 reference and rejects a different destination","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"preserves a matching explicit Push PRC20 reference and rejects a different destination"}],"endTime":1792494872633,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/runtime-token-chain.spec.ts","startTime":1792494872330,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["Outbound/inbound error classification","Typed error shapes"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"Outbound/inbound error classification Typed error shapes OutboundTimeoutError carries code + timings","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"OutboundTimeoutError carries code + timings"},{"ancestorTitles":["Outbound/inbound error classification","Typed error shapes"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Outbound/inbound error classification Typed error shapes OutboundFailedError carries code + destination chain","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"OutboundFailedError carries code + destination chain"},{"ancestorTitles":["Outbound/inbound error classification","Typed error shapes"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Outbound/inbound error classification Typed error shapes InboundTimeoutError carries correlation key + elapsed","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"InboundTimeoutError carries correlation key + elapsed"},{"ancestorTitles":["Outbound/inbound error classification","R2 emit + receipt mutation (replicates response-builder.wait()) "],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Outbound/inbound error classification R2 emit + receipt mutation (replicates response-builder.wait()) Timeout → SEND-TX-299-03 + externalStatus=timeout","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"Timeout → SEND-TX-299-03 + externalStatus=timeout"},{"ancestorTitles":["Outbound/inbound error classification","R2 emit + receipt mutation (replicates response-builder.wait()) "],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"Outbound/inbound error classification R2 emit + receipt mutation (replicates response-builder.wait()) Failure (terminal) → SEND-TX-299-02 + externalStatus=failed","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"Failure (terminal) → SEND-TX-299-02 + externalStatus=failed"},{"ancestorTitles":["Outbound/inbound error classification","R2 emit + receipt mutation (replicates response-builder.wait()) "],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Outbound/inbound error classification R2 emit + receipt mutation (replicates response-builder.wait()) Failure (per-outbound REVERTED) → SEND-TX-299-02 with target chain in error","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"Failure (per-outbound REVERTED) → SEND-TX-299-02 with target chain in error"},{"ancestorTitles":["Outbound/inbound error classification","R2 emit + receipt mutation (replicates response-builder.wait()) "],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Outbound/inbound error classification R2 emit + receipt mutation (replicates response-builder.wait()) Classifier must NOT misclassify an OutboundFailedError whose message happens to start with \"Timeout\"","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"Classifier must NOT misclassify an OutboundFailedError whose message happens to start with \"Timeout\""},{"ancestorTitles":["Outbound/inbound error classification","Receipt externalStatus semantics"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Outbound/inbound error classification Receipt externalStatus semantics R2 outbound success → externalStatus=success + externalTxHash populated","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"R2 outbound success → externalStatus=success + externalTxHash populated"},{"ancestorTitles":["Outbound/inbound error classification","Receipt externalStatus semantics"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Outbound/inbound error classification Receipt externalStatus semantics R3 payload-only: outbound success is the terminal milestone — externalStatus stays \"success\"","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"R3 payload-only: outbound success is the terminal milestone — externalStatus stays \"success\""},{"ancestorTitles":["Outbound/inbound error classification","Receipt externalStatus semantics"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Outbound/inbound error classification Receipt externalStatus semantics R2 live failure path: partial receipt carries externalError + undefined externalTxHash","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"R2 live failure path: partial receipt carries externalError + undefined externalTxHash"},{"ancestorTitles":["Outbound/inbound error classification","Receipt externalStatus semantics"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Outbound/inbound error classification Receipt externalStatus semantics trackTransaction-style reconstruction of terminal failure → 299-02 + failed annotation","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"trackTransaction-style reconstruction of terminal failure → 299-02 + failed annotation"},{"ancestorTitles":["Outbound/inbound error classification","wait hook hash metadata"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Outbound/inbound error classification wait hook hash metadata R2 awaiting/polling events carry the root Push tx hash as pushTxHash","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"R2 awaiting/polling events carry the root Push tx hash as pushTxHash"},{"ancestorTitles":["Outbound/inbound error classification","wait hook hash metadata"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"Outbound/inbound error classification wait hook hash metadata R3 wait events carry pushTxHash without replacing txHash successes","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"R3 wait events carry pushTxHash without replacing txHash successes"},{"ancestorTitles":["Outbound/inbound error classification","R3 inbound emit + receipt mutation"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Outbound/inbound error classification R3 inbound emit + receipt mutation InboundTimeoutError → 399-03 + timeout annotation","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"InboundTimeoutError → 399-03 + timeout annotation"},{"ancestorTitles":["Outbound/inbound error classification","R3 inbound emit + receipt mutation"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Outbound/inbound error classification R3 inbound emit + receipt mutation Generic inbound Error → 399-02 + failed annotation","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"Generic inbound Error → 399-02 + failed annotation"},{"ancestorTitles":["Outbound/inbound error classification","204-04 Verification Declined heuristic"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Outbound/inbound error classification 204-04 Verification Declined heuristic classifies EIP-1193 4001 as user decline (generic title/message)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"classifies EIP-1193 4001 as user decline (generic title/message)"},{"ancestorTitles":["Outbound/inbound error classification","204-04 Verification Declined heuristic"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Outbound/inbound error classification 204-04 Verification Declined heuristic classifies UserRejectedRequestError as user decline","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"classifies UserRejectedRequestError as user decline"},{"ancestorTitles":["Outbound/inbound error classification","204-04 Verification Declined heuristic"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Outbound/inbound error classification 204-04 Verification Declined heuristic non-decline errors keep the original error message and flip title","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"non-decline errors keep the original error message and flip title"},{"ancestorTitles":["Outbound/inbound error classification","204-04 Verification Declined heuristic"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Outbound/inbound error classification 204-04 Verification Declined heuristic no-arg invocation classifies as user decline (self-consistent event)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"no-arg invocation classifies as user decline (self-consistent event)"},{"ancestorTitles":["Outbound/inbound error classification","204-04 Verification Declined heuristic"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Outbound/inbound error classification 204-04 Verification Declined heuristic classifies \"declined by user\" message as user decline","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"classifies \"declined by user\" message as user decline"},{"ancestorTitles":["Outbound/inbound error classification","204-04 Verification Declined heuristic"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Outbound/inbound error classification 204-04 Verification Declined heuristic classifies ACTION_REJECTED (ethers) as user decline","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"classifies ACTION_REJECTED (ethers) as user decline"}],"endTime":1792494872771,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/outbound-error-classification.spec.ts","startTime":1792494872639,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["v5 wallet labels"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"v5 wallet labels allows empty, 64 ASCII bytes and sixteen four-byte emoji without altering the label","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"allows empty, 64 ASCII bytes and sixteen four-byte emoji without altering the label"},{"ancestorTitles":["v5 wallet labels"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"v5 wallet labels refuses non-strings and overlong UTF-8 labels before a create reads or signs","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"refuses non-strings and overlong UTF-8 labels before a create reads or signs"},{"ancestorTitles":["v5 wallet labels"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"v5 wallet labels encodes a direct reset and forwards the per-call progress hook","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"encodes a direct reset and forwards the per-call progress hook"},{"ancestorTitles":["v5 wallet labels"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"v5 wallet labels refuses non-owner and read-only renames before signing","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"refuses non-owner and read-only renames before signing"},{"ancestorTitles":["v5 wallet labels"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"v5 wallet labels uses a direct label call for an external owner identity","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"uses a direct label call for an external owner identity"},{"ancestorTitles":["v5 wallet labels"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"v5 wallet labels maps the new contract length error and emits a failed operation hook","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"maps the new contract length error and emits a failed operation hook"}],"endTime":1792494873080,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/labels.spec.ts","startTime":1792494872775,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["READ.CHAIN"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"READ.CHAIN is an enumerable superset of CHAIN with WEB2 = \"web2\"","invocations":1,"location":null,"numPassingAsserts":15,"retryReasons":[],"status":"passed","title":"is an enumerable superset of CHAIN with WEB2 = \"web2\""},{"ancestorTitles":["READ.CHAIN"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"READ.CHAIN CHAIN itself still enumerates only blockchains","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"CHAIN itself still enumerates only blockchains"},{"ancestorTitles":["READ.CHAIN.WEB2"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"READ.CHAIN.WEB2 normalizes to the unchanged wire identity","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"normalizes to the unchanged wire identity"},{"ancestorTitles":["READ.CHAIN.WEB2"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"READ.CHAIN.WEB2 builds an http query and spec params","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"builds an http query and spec params"},{"ancestorTitles":["READ.CHAIN.WEB2"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"READ.CHAIN.WEB2 is rejected by transaction routing","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"is rejected by transaction routing"},{"ancestorTitles":["deprecated CHAIN.WEB2"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"deprecated CHAIN.WEB2 normalizes to the unchanged wire identity","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"normalizes to the unchanged wire identity"},{"ancestorTitles":["deprecated CHAIN.WEB2"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"deprecated CHAIN.WEB2 builds an http query and spec params","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"builds an http query and spec params"},{"ancestorTitles":["deprecated CHAIN.WEB2"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"deprecated CHAIN.WEB2 is rejected by transaction routing","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"is rejected by transaction routing"},{"ancestorTitles":["legacy literal"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"legacy literal normalizes to the unchanged wire identity","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"normalizes to the unchanged wire identity"},{"ancestorTitles":["legacy literal"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"legacy literal builds an http query and spec params","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"builds an http query and spec params"},{"ancestorTitles":["legacy literal"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"legacy literal is rejected by transaction routing","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"is rejected by transaction routing"},{"ancestorTitles":["type-level separation"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"type-level separation compiles","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"compiles"}],"endTime":1792494873336,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/read-state/__tests__/web2-compat.spec.ts","startTime":1792494873085,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["READ-TX spec strings"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"READ-TX spec strings READ-TX-101","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"READ-TX-101"},{"ancestorTitles":["READ-TX spec strings"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"READ-TX spec strings READ-TX-102-01","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"READ-TX-102-01"},{"ancestorTitles":["READ-TX spec strings"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"READ-TX spec strings READ-TX-102-02","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"READ-TX-102-02"},{"ancestorTitles":["READ-TX spec strings"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"READ-TX spec strings READ-TX-102-03","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"READ-TX-102-03"},{"ancestorTitles":["READ-TX spec strings"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"READ-TX spec strings READ-TX-102-04","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"READ-TX-102-04"},{"ancestorTitles":["READ-TX spec strings"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"READ-TX spec strings READ-TX-102-05","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"READ-TX-102-05"},{"ancestorTitles":["READ-TX spec strings"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"READ-TX spec strings READ-TX-103-01","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"READ-TX-103-01"},{"ancestorTitles":["READ-TX spec strings"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"READ-TX spec strings READ-TX-103-01","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"READ-TX-103-01"},{"ancestorTitles":["READ-TX spec strings"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"READ-TX spec strings READ-TX-103-02","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"READ-TX-103-02"},{"ancestorTitles":["READ-TX spec strings"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"READ-TX spec strings READ-TX-103-03","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"READ-TX-103-03"},{"ancestorTitles":["READ-TX spec strings"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"READ-TX spec strings READ-TX-104-01","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"READ-TX-104-01"},{"ancestorTitles":["READ-TX spec strings"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"READ-TX spec strings READ-TX-104-02","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"READ-TX-104-02"},{"ancestorTitles":["READ-TX spec strings"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"READ-TX spec strings READ-TX-104-03","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"READ-TX-104-03"},{"ancestorTitles":["READ-TX spec strings"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"READ-TX spec strings READ-TX-104-03","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"READ-TX-104-03"},{"ancestorTitles":["READ-TX spec strings"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"READ-TX spec strings READ-TX-104-04","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"READ-TX-104-04"},{"ancestorTitles":["READ-TX spec strings"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"READ-TX spec strings READ-TX-104-05","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"READ-TX-104-05"},{"ancestorTitles":["READ-TX spec strings"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"READ-TX spec strings READ-TX-105-01","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"READ-TX-105-01"},{"ancestorTitles":["READ-TX spec strings"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"READ-TX spec strings READ-TX-105-02","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"READ-TX-105-02"},{"ancestorTitles":["READ-TX spec strings"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"READ-TX spec strings READ-TX-105-03","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"READ-TX-105-03"},{"ancestorTitles":["READ-TX spec strings"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"READ-TX spec strings READ-TX-105-04","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"READ-TX-105-04"},{"ancestorTitles":["READ-TX spec strings"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"READ-TX spec strings READ-TX-106-01","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"READ-TX-106-01"},{"ancestorTitles":["READ-TX spec strings"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"READ-TX spec strings READ-TX-106-02","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"READ-TX-106-02"},{"ancestorTitles":["READ-TX spec strings"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"READ-TX spec strings READ-TX-106-03","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"READ-TX-106-03"},{"ancestorTitles":["READ-TX spec strings"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"READ-TX spec strings READ-TX-106-04","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"READ-TX-106-04"},{"ancestorTitles":["READ-TX spec strings"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"READ-TX spec strings READ-TX-106-05","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"READ-TX-106-05"},{"ancestorTitles":["READ-TX spec strings"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"READ-TX spec strings READ-TX-106-06","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"READ-TX-106-06"},{"ancestorTitles":["READ-TX spec strings"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"READ-TX spec strings READ-TX-199-01","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"READ-TX-199-01"},{"ancestorTitles":["READ-TX spec strings"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"READ-TX spec strings READ-TX-199-02","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"READ-TX-199-02"},{"ancestorTitles":["READ-TX spec strings"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"READ-TX spec strings READ-TX-199-03","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"READ-TX-199-03"},{"ancestorTitles":["READ-TX spec strings"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"READ-TX spec strings READ-TX-199-99","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"READ-TX-199-99"},{"ancestorTitles":["READ-TX spec strings"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"READ-TX spec strings READ-TX-001","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"READ-TX-001"},{"ancestorTitles":["READ-TX spec strings"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"READ-TX spec strings READ-TX-002-01","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"READ-TX-002-01"},{"ancestorTitles":["READ-TX spec strings"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"READ-TX spec strings READ-TX-002-99-99","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"READ-TX-002-99-99"},{"ancestorTitles":["READ-TX spec strings"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"READ-TX spec strings READ-TX-999-01","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"READ-TX-999-01"},{"ancestorTitles":["READ-TX spec strings"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"READ-TX spec strings READ-TX-999-02","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"READ-TX-999-02"},{"ancestorTitles":["READ-TX spec strings"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"READ-TX spec strings READ-TX-999-03","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"READ-TX-999-03"},{"ancestorTitles":["READ-TX spec strings"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"READ-TX spec strings every READ_TX id in the enum has a hook, and none leaks a bigint into response","invocations":1,"location":null,"numPassingAsserts":71,"retryReasons":[],"status":"passed","title":"every READ_TX id in the enum has a hook, and none leaks a bigint into response"},{"ancestorTitles":["READ-TX spec strings"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"READ-TX spec strings serializes nested contract-call and web2 results without mutating them","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"serializes nested contract-call and web2 results without mutating them"},{"ancestorTitles":["READ-TX spec strings"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"READ-TX spec strings 199-01 with a non-delivered callback says so in the message","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"199-01 with a non-delivered callback says so in the message"}],"endTime":1792494873523,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/progress-hook/__tests__/read-tx-spec-strings.spec.ts","startTime":1792494873339,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["trackRead — terminal records straight from the node"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"trackRead — terminal records straight from the node FULFILLED + delivered: value decoded, fees from the fulfil and settle receipts","invocations":1,"location":null,"numPassingAsserts":22,"retryReasons":[],"status":"passed","title":"FULFILLED + delivered: value decoded, fees from the fulfil and settle receipts"},{"ancestorTitles":["trackRead — terminal records straight from the node"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"trackRead — terminal records straight from the node FULFILLED but the callback reverted: callbackDelivered=false, no value (I4)","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"FULFILLED but the callback reverted: callbackDelivered=false, no value (I4)"},{"ancestorTitles":["trackRead — terminal records straight from the node"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"trackRead — terminal records straight from the node FULFILLED with an ERROR result: raw carries the code, value undefined, delivered still parsed","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"FULFILLED with an ERROR result: raw carries the code, value undefined, delivered still parsed"},{"ancestorTitles":["trackRead — terminal records straight from the node"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"trackRead — terminal records straight from the node EXPIRED: never fetches a receipt; the refund is confirmed from the EndBlock tx_log events","invocations":1,"location":null,"numPassingAsserts":9,"retryReasons":[],"status":"passed","title":"EXPIRED: never fetches a receipt; the refund is confirmed from the EndBlock tx_log events"},{"ancestorTitles":["trackRead — terminal records straight from the node"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"trackRead — terminal records straight from the node EXPIRED: when the block results are unavailable the refund stays unknown, never guessed","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"EXPIRED: when the block results are unavailable the refund stays unknown, never guessed"},{"ancestorTitles":["trackRead — terminal records straight from the node"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"trackRead — terminal records straight from the node EXPIRED: scans unique attempt heights newest first when newer logs are empty","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"EXPIRED: scans unique attempt heights newest first when newer logs are empty"},{"ancestorTitles":["trackRead — terminal records straight from the node"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"trackRead — terminal records straight from the node EXPIRED: scans unique attempt heights newest first when newer logs are unavailable","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"EXPIRED: scans unique attempt heights newest first when newer logs are unavailable"},{"ancestorTitles":["trackRead — terminal records straight from the node"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"trackRead — terminal records straight from the node EXPIRED: ignores unrelated malformed logs without hiding valid refund logs","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"EXPIRED: ignores unrelated malformed logs without hiding valid refund logs"},{"ancestorTitles":["trackRead — terminal records straight from the node"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"trackRead — terminal records straight from the node EXPIRED: does not confirm refunds from wrong-mode logs","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"EXPIRED: does not confirm refunds from wrong-mode logs"},{"ancestorTitles":["trackRead — terminal records straight from the node"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"trackRead — terminal records straight from the node EXPIRED: does not confirm refunds from wrong-address logs","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"EXPIRED: does not confirm refunds from wrong-address logs"},{"ancestorTitles":["trackRead — terminal records straight from the node"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"trackRead — terminal records straight from the node EXPIRED: does not confirm refunds from wrong-request logs","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"EXPIRED: does not confirm refunds from wrong-request logs"},{"ancestorTitles":["trackRead — terminal records straight from the node"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"trackRead — terminal records straight from the node EXPIRED: does not confirm refunds from expiry-only logs","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"EXPIRED: does not confirm refunds from expiry-only logs"},{"ancestorTitles":["trackRead — terminal records straight from the node"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"trackRead — terminal records straight from the node EXPIRED: a RefundFailed log reports refundFailed=true and no amount","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"EXPIRED: a RefundFailed log reports refundFailed=true and no amount"},{"ancestorTitles":["trackRead — terminal records straight from the node"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"trackRead — terminal records straight from the node SVM and web2 records infer their result shape from the envelope","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"SVM and web2 records infer their result shape from the envelope"},{"ancestorTitles":["trackRead — terminal records straight from the node"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"trackRead — terminal records straight from the node resultShape option overrides inference (a contract call carries no ABI on chain)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"resultShape option overrides inference (a contract call carries no ABI on chain)"},{"ancestorTitles":["trackRead — terminal records straight from the node"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"trackRead — terminal records straight from the node retains IDL decoding across request lookup, wait and refresh; bad layouts report decodeError","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"retains IDL decoding across request lookup, wait and refresh; bad layouts report decodeError"},{"ancestorTitles":["trackRead — terminal records straight from the node"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"trackRead — terminal records straight from the node by txHash resolves to an array; requestId accepts bigint","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"by txHash resolves to an array; requestId accepts bigint"},{"ancestorTitles":["trackRead — terminal records straight from the node"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"trackRead — terminal records straight from the node toRequestIdHex normalises","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"toRequestIdHex normalises"},{"ancestorTitles":["trackRead — lookup retry"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"trackRead — lookup retry retries a not-yet-ingested record, then throws ReadNotFoundError","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"retries a not-yet-ingested record, then throws ReadNotFoundError"},{"ancestorTitles":["trackRead — lookup retry"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"trackRead — lookup retry a terminal record answers in one lookup, announcing the lookup and the find","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"a terminal record answers in one lookup, announcing the lookup and the find"},{"ancestorTitles":["trackRead — lookup retry"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"trackRead — lookup retry a txHash lookup announces the tx and every record found","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"a txHash lookup announces the tx and every record found"},{"ancestorTitles":["trackRead — lookup retry"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"trackRead — lookup retry finds a record that appears on the second poll","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"finds a record that appears on the second poll"},{"ancestorTitles":["wait()"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"wait() recomputes remaining lifetime on each wait and keeps the expiry observation margin","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"recomputes remaining lifetime on each wait and keeps the expiry observation margin"},{"ancestorTitles":["wait()"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"wait() explicit timeouts never wait on the head lookup, including values above the default ceiling","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"explicit timeouts never wait on the head lookup, including values above the default ceiling"},{"ancestorTitles":["wait()"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"wait() announces READ-TX-105-04 once when the request is near expiry, from one head lookup","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"announces READ-TX-105-04 once when the request is near expiry, from one head lookup"},{"ancestorTitles":["wait()"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"wait() does not warn while expiry is far away","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"does not warn while expiry is far away"},{"ancestorTitles":["wait()"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"wait() terminal snapshots need no head lookup","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"terminal snapshots need no head lookup"},{"ancestorTitles":["wait()"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"wait() bounds stalled height lookups and propagates failed lookups","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"bounds stalled height lookups and propagates failed lookups"},{"ancestorTitles":["wait()"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"wait() a missing snapshot respects the shared timeout and retains the last status","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"a missing snapshot respects the shared timeout and retains the last status"},{"ancestorTitles":["wait()"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"wait() a stalled RPC cannot exceed the wait deadline","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"a stalled RPC cannot exceed the wait deadline"},{"ancestorTitles":["wait()"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"wait() recovers from a missing snapshot without resetting the deadline","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"recovers from a missing snapshot without resetting the deadline"},{"ancestorTitles":["wait()"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"wait() PENDING → VOTING → FULFILLED resolves with the terminal snapshot and hooks in order","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"PENDING → VOTING → FULFILLED resolves with the terminal snapshot and hooks in order"},{"ancestorTitles":["wait()"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"wait() wait({ resultShape }) re-decodes even an already-terminal record (the ABI is not on chain)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"wait({ resultShape }) re-decodes even an already-terminal record (the ABI is not on chain)"},{"ancestorTitles":["wait()"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"wait() already terminal: resolves at once without polling","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"already terminal: resolves at once without polling"},{"ancestorTitles":["wait()"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"wait() reverted callback emits 106-03 instead of 106-02","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"reverted callback emits 106-03 instead of 106-02"},{"ancestorTitles":["wait()"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"wait() 199-02 names the outcome of a FULFILLED read that did not work","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"199-02 names the outcome of a FULFILLED read that did not work"},{"ancestorTitles":["wait()"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"wait() a successful read ends on 199-01 and exposes requestIdUint","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"a successful read ends on 199-01 and exposes requestIdUint"},{"ancestorTitles":["wait()"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"wait() an expired read announces its confirmed refund before 199-02","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"an expired read announces its confirmed refund before 199-02"},{"ancestorTitles":["wait()"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"wait() EXPIRED is a status, not a throw — 199-02 emitted","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"EXPIRED is a status, not a throw — 199-02 emitted"},{"ancestorTitles":["wait()"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"wait() FAILED is a status, not a throw — 199-02 emitted","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"FAILED is a status, not a throw — 199-02 emitted"},{"ancestorTitles":["wait()"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"wait() ABORTED is a status, not a throw — 199-02 emitted","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"ABORTED is a status, not a throw — 199-02 emitted"},{"ancestorTitles":["wait()"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"wait() timeout throws ReadTimeoutError with the last status and emits 199-03","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"timeout throws ReadTimeoutError with the last status and emits 199-03"},{"ancestorTitles":["wait()"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"wait() default timeout is remaining blocks plus 10 seconds, capped","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"default timeout is remaining blocks plus 10 seconds, capped"},{"ancestorTitles":["wait()"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"wait() polling interval floors at 500 ms","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"polling interval floors at 500 ms"},{"ancestorTitles":["wait()"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"wait() refresh() re-reads by requestId and returns a new snapshot","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"refresh() re-reads by requestId and returns a new snapshot"},{"ancestorTitles":["through the orchestrator: READ-TX hooks are not R1-suppressed"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"through the orchestrator: READ-TX hooks are not R1-suppressed a non-R1 currentRoute still receives every READ-TX event","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"a non-R1 currentRoute still receives every READ-TX event"},{"ancestorTitles":["deriveReadOutcome — one field that means \"it worked\""],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"deriveReadOutcome — one field that means \"it worked\" PENDING","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"PENDING"},{"ancestorTitles":["deriveReadOutcome — one field that means \"it worked\""],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"deriveReadOutcome — one field that means \"it worked\" VOTING","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"VOTING"},{"ancestorTitles":["deriveReadOutcome — one field that means \"it worked\""],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"deriveReadOutcome — one field that means \"it worked\" EXPIRED","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"EXPIRED"},{"ancestorTitles":["deriveReadOutcome — one field that means \"it worked\""],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"deriveReadOutcome — one field that means \"it worked\" FAILED","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"FAILED"},{"ancestorTitles":["deriveReadOutcome — one field that means \"it worked\""],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"deriveReadOutcome — one field that means \"it worked\" ABORTED","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"ABORTED"},{"ancestorTitles":["deriveReadOutcome — one field that means \"it worked\""],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"deriveReadOutcome — one field that means \"it worked\" source error beats callback failure","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"source error beats callback failure"},{"ancestorTitles":["deriveReadOutcome — one field that means \"it worked\""],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"deriveReadOutcome — one field that means \"it worked\" source error, delivered","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"source error, delivered"},{"ancestorTitles":["deriveReadOutcome — one field that means \"it worked\""],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"deriveReadOutcome — one field that means \"it worked\" callback reverted","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"callback reverted"},{"ancestorTitles":["deriveReadOutcome — one field that means \"it worked\""],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"deriveReadOutcome — one field that means \"it worked\" receipt unavailable","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"receipt unavailable"},{"ancestorTitles":["deriveReadOutcome — one field that means \"it worked\""],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"deriveReadOutcome — one field that means \"it worked\" decode failed","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"decode failed"},{"ancestorTitles":["deriveReadOutcome — one field that means \"it worked\""],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"deriveReadOutcome — one field that means \"it worked\" success","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"success"},{"ancestorTitles":["deriveReadOutcome — one field that means \"it worked\""],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"deriveReadOutcome — one field that means \"it worked\" no result on a FULFILLED record","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"no result on a FULFILLED record"}],"endTime":1792494873697,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/read-state/__tests__/read-tracker.spec.ts","startTime":1792494873527,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["isPC20Reference"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"isPC20Reference accepts a { chain, address } reference","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"accepts a { chain, address } reference"},{"ancestorTitles":["isPC20Reference"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"isPC20Reference rejects a MoveableToken","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects a MoveableToken"},{"ancestorTitles":["isPC20Reference"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"isPC20Reference rejects undefined","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects undefined"},{"ancestorTitles":["isPC20Reference"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"isPC20Reference does not misclassify a MoveableToken that also carries a chain","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"does not misclassify a MoveableToken that also carries a chain"},{"ancestorTitles":["PC20 gate"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PC20 gate passes a legacy MoveableToken through unchanged","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"passes a legacy MoveableToken through unchanged"},{"ancestorTitles":["PC20 gate"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PC20 gate passes native funds (no token) through unchanged","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"passes native funds (no token) through unchanged"},{"ancestorTitles":["PC20 gate"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"PC20 gate refuses to let an unresolved PC20 reference reach a legacy builder","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"refuses to let an unresolved PC20 reference reach a legacy builder"},{"ancestorTitles":["PC20 import payload safety"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PC20 import payload safety recognizes only resolved imports with a positive wrapper amount","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"recognizes only resolved imports with a positive wrapper amount"},{"ancestorTitles":["PC20 import payload safety"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PC20 import payload safety fails closed before a resolved wrapper burn can carry an empty payload","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"fails closed before a resolved wrapper burn can carry an empty payload"},{"ancestorTitles":["PC20 import payload safety"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PC20 import payload safety allows the same import once a real forwarding payload exists","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"allows the same import once a real forwarding payload exists"},{"ancestorTitles":["route validation with PC20 funds"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"route validation with PC20 funds accepts an unresolved PC20 reference (pre-gate, e.g. prepareTransaction)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"accepts an unresolved PC20 reference (pre-gate, e.g. prepareTransaction)"},{"ancestorTitles":["route validation with PC20 funds"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"route validation with PC20 funds accepts the gate-resolved internal form (_pc20 present)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"accepts the gate-resolved internal form (_pc20 present)"},{"ancestorTitles":["route validation with PC20 funds"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"route validation with PC20 funds still rejects an unregistered MoveableToken","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"still rejects an unregistered MoveableToken"}],"endTime":1792494873824,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/pc20/__tests__/gate.spec.ts","startTime":1792494873698,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"expands both token directions and exact-input/output with wallet and amount pins","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"expands both token directions and exact-input/output with wallet and amount pins"},{"ancestorTitles":[],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"rejects native-token markers and oversized pin expansion","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"rejects native-token markers and oversized pin expansion"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"defaults omitted caps to zero without introducing an unlimited approval","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"defaults omitted caps to zero without introducing an unlimited approval"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"scopes money-market approvals to their actual underlying token","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"scopes money-market approvals to their actual underlying token"},{"ancestorTitles":[],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"normalizes every DEX call on eip155:1 to the exact ABI bytes","invocations":1,"location":null,"numPassingAsserts":16,"retryReasons":[],"status":"passed","title":"normalizes every DEX call on eip155:1 to the exact ABI bytes"},{"ancestorTitles":[],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"normalizes every DEX call on eip155:8453 to the exact ABI bytes","invocations":1,"location":null,"numPassingAsserts":16,"retryReasons":[],"status":"passed","title":"normalizes every DEX call on eip155:8453 to the exact ABI bytes"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"normalizes every DEX call on eip155:42161 to the exact ABI bytes","invocations":1,"location":null,"numPassingAsserts":16,"retryReasons":[],"status":"passed","title":"normalizes every DEX call on eip155:42161 to the exact ABI bytes"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"normalizes every DEX call on eip155:56 to the exact ABI bytes","invocations":1,"location":null,"numPassingAsserts":16,"retryReasons":[],"status":"passed","title":"normalizes every DEX call on eip155:56 to the exact ABI bytes"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"normalizes every DEX call on eip155:11155111 to the exact ABI bytes","invocations":1,"location":null,"numPassingAsserts":16,"retryReasons":[],"status":"passed","title":"normalizes every DEX call on eip155:11155111 to the exact ABI bytes"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"normalizes every DEX call on eip155:84532 to the exact ABI bytes","invocations":1,"location":null,"numPassingAsserts":16,"retryReasons":[],"status":"passed","title":"normalizes every DEX call on eip155:84532 to the exact ABI bytes"},{"ancestorTitles":[],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"normalizes every DEX call on eip155:421614 to the exact ABI bytes","invocations":1,"location":null,"numPassingAsserts":16,"retryReasons":[],"status":"passed","title":"normalizes every DEX call on eip155:421614 to the exact ABI bytes"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"normalizes every DEX call on eip155:97 to the exact ABI bytes","invocations":1,"location":null,"numPassingAsserts":16,"retryReasons":[],"status":"passed","title":"normalizes every DEX call on eip155:97 to the exact ABI bytes"},{"ancestorTitles":[],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"supports tuple/fixed-array positions but never descends into dynamic storage","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"supports tuple/fixed-array positions but never descends into dynamic storage"},{"ancestorTitles":[],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"tuple-authored pins re-encode using the raw-selector word indexes returned by reads","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"tuple-authored pins re-encode using the raw-selector word indexes returned by reads"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"mutating a returned tuple path cannot change a later preset","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"mutating a returned tuple path cannot change a later preset"},{"ancestorTitles":[],"duration":6,"failureDetails":[],"failureMessages":[],"fullName":"includes a curated capped token pair and exact pair pins on every DEX chain","invocations":1,"location":null,"numPassingAsserts":179,"retryReasons":[],"status":"passed","title":"includes a curated capped token pair and exact pair pins on every DEX chain"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"keeps single-token swaps disabled and generates approvals only for the supplied asset","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"keeps single-token swaps disabled and generates approvals only for the supplied asset"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"keeps chains without supplied assets discoverable and regenerates complete pairs without disabled alternatives","invocations":1,"location":null,"numPassingAsserts":26,"retryReasons":[],"status":"passed","title":"keeps chains without supplied assets discoverable and regenerates complete pairs without disabled alternatives"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"mainnet eip155:1 templates preserve one rule per chain, selectors and wallet pins","invocations":1,"location":null,"numPassingAsserts":12,"retryReasons":[],"status":"passed","title":"mainnet eip155:1 templates preserve one rule per chain, selectors and wallet pins"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"mainnet eip155:8453 templates preserve one rule per chain, selectors and wallet pins","invocations":1,"location":null,"numPassingAsserts":12,"retryReasons":[],"status":"passed","title":"mainnet eip155:8453 templates preserve one rule per chain, selectors and wallet pins"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"mainnet eip155:42161 templates preserve one rule per chain, selectors and wallet pins","invocations":1,"location":null,"numPassingAsserts":12,"retryReasons":[],"status":"passed","title":"mainnet eip155:42161 templates preserve one rule per chain, selectors and wallet pins"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"mainnet eip155:56 templates preserve one rule per chain, selectors and wallet pins","invocations":1,"location":null,"numPassingAsserts":12,"retryReasons":[],"status":"passed","title":"mainnet eip155:56 templates preserve one rule per chain, selectors and wallet pins"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"mainnet Lido uses the selected token units and excludes unbounded withdrawal/claim methods","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"mainnet Lido uses the selected token units and excludes unbounded withdrawal/claim methods"}],"endTime":1792494874176,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/preset-catalog.spec.ts","startTime":1792494873828,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-101 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-101 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-102-01 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-102-01 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-103-01 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-103-01 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-103-02 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-103-02 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-103-03 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-103-03 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-103-03-01 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-103-03-01 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-103-03-02 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-103-03-02 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-103-03-03 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-103-03-03 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-103-03-04 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-103-03-04 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-104-01 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-104-01 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-104-02 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-104-02 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-104-03 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-104-03 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-104-04 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-104-04 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-105-01 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-105-01 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-105-02 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-105-02 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-106-01 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-106-01 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-106-02 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-106-02 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-106-03 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-106-03 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-106-03-01 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-106-03-01 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-106-03-02 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-106-03-02 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-106-04 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-106-04 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-106-05 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-106-05 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-106-06 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-106-06 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-107 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-107 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-199-01 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-199-01 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-199-02 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-199-02 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-199-03 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-199-03 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-199-99 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-199-99 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-201 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-201 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-202-01 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-202-01 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-202-02 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-202-02 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-203-01 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-203-01 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-203-02 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-203-02 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-203-03 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-203-03 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-203-04 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-203-04 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-203-05 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-203-05 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-204-01 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-204-01 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-204-02 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-204-02 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-204-03 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-204-03 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-204-04 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-204-04 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-207 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-207 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-209-01 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-209-01 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-209-02 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-209-02 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-299-01 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-299-01 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-299-02 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-299-02 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-299-03 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-299-03 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-299-99 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-299-99 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-301 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-301 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-302-01 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-302-01 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-302-02 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-302-02 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-303-03-01 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-303-03-01 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-303-03-02 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-303-03-02 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-303-03-03 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-303-03-03 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-303-01 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-303-01 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-303-02 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-303-02 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-303-04 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-303-04 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-303-05 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-303-05 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-303-06 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-303-06 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-304-01 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-304-01 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-304-02 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-304-02 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-304-03 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-304-03 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-304-04 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-304-04 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-307 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-307 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-309-01 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-309-01 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-309-02 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-309-02 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-309-03 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-309-03 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-310-01 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-310-01 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-310-02 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-310-02 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-399-01 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-399-01 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-399-02 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-399-02 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-399-03 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-399-03 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-399-99 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-399-99 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-001 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-001 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-002-01 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-002-01 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-002-99-99 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-002-99-99 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-003-03 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-003-03 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-003-04 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-003-04 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-003-05 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-003-05 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-999-01 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-999-01 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-999-02 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-999-02 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants SEND-TX-999-03 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SEND-TX-999-03 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants UEA-MIG-01 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"UEA-MIG-01 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants UEA-MIG-02 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"UEA-MIG-02 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants UEA-MIG-03 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"UEA-MIG-03 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants UEA-MIG-9901 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"UEA-MIG-9901 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants UEA-MIG-9902 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"UEA-MIG-9902 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants UEA-MIG-9903 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"UEA-MIG-9903 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants READ-TX-101 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"READ-TX-101 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants READ-TX-102-01 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"READ-TX-102-01 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants READ-TX-102-02 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"READ-TX-102-02 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants READ-TX-102-03 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"READ-TX-102-03 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants READ-TX-102-04 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"READ-TX-102-04 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants READ-TX-102-05 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"READ-TX-102-05 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants READ-TX-103-01 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"READ-TX-103-01 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants READ-TX-103-02 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"READ-TX-103-02 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants READ-TX-103-03 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"READ-TX-103-03 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants READ-TX-104-01 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"READ-TX-104-01 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants READ-TX-104-02 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"READ-TX-104-02 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants READ-TX-104-03 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"READ-TX-104-03 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants READ-TX-104-04 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"READ-TX-104-04 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants READ-TX-104-05 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"READ-TX-104-05 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants READ-TX-105-01 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"READ-TX-105-01 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants READ-TX-105-02 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"READ-TX-105-02 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants READ-TX-105-03 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"READ-TX-105-03 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants READ-TX-105-04 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"READ-TX-105-04 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants READ-TX-106-01 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"READ-TX-106-01 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants READ-TX-106-02 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"READ-TX-106-02 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants READ-TX-106-03 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"READ-TX-106-03 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants READ-TX-106-04 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"READ-TX-106-04 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants READ-TX-106-05 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"READ-TX-106-05 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants READ-TX-106-06 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"READ-TX-106-06 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants READ-TX-199-01 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"READ-TX-199-01 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants READ-TX-199-02 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"READ-TX-199-02 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants READ-TX-199-03 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"READ-TX-199-03 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants READ-TX-199-99 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"READ-TX-199-99 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants READ-TX-001 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"READ-TX-001 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants READ-TX-002-01 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"READ-TX-002-01 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants READ-TX-002-99-99 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"READ-TX-002-99-99 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants READ-TX-999-01 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"READ-TX-999-01 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants READ-TX-999-02 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"READ-TX-999-02 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants READ-TX-999-03 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"READ-TX-999-03 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants AGENTIC-TX-101 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"AGENTIC-TX-101 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants AGENTIC-TX-102 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"AGENTIC-TX-102 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants AGENTIC-TX-104 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"AGENTIC-TX-104 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants AGENTIC-TX-105 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"AGENTIC-TX-105 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants AGENTIC-TX-106 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"AGENTIC-TX-106 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants AGENTIC-TX-107 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"AGENTIC-TX-107 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants AGENTIC-TX-199-01 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"AGENTIC-TX-199-01 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants AGENTIC-TX-199-02 returns response of type object | null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"AGENTIC-TX-199-02 returns response of type object | null"},{"ancestorTitles":["progress-hook response invariants"],"duration":33,"failureDetails":[],"failureMessages":[],"fullName":"progress-hook response invariants every hook event carries an id, title, message, level, timestamp","invocations":1,"location":null,"numPassingAsserts":774,"retryReasons":[],"status":"passed","title":"every hook event carries an id, title, message, level, timestamp"}],"endTime":1792494874397,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/progress-hook/__tests__/response-invariant.spec.ts","startTime":1792494874179,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["guards fail before the signer is ever invoked"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"guards fail before the signer is ever invoked from (Routes 3/4)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"from (Routes 3/4)"},{"ancestorTitles":["guards fail before the signer is ever invoked"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"guards fail before the signer is ever invoked payGasWith","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"payGasWith"},{"ancestorTitles":["guards fail before the signer is ever invoked"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"guards fail before the signer is ever invoked migration","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"migration"},{"ancestorTitles":["guards fail before the signer is ever invoked"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"guards fail before the signer is ever invoked funds on a Push send","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"funds on a Push send"},{"ancestorTitles":["guards fail before the signer is ever invoked"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"guards fail before the signer is ever invoked read-only clients never sign","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"read-only clients never sign"},{"ancestorTitles":["guards fail before the signer is ever invoked"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"guards fail before the signer is ever invoked agent native arrays require an atomic sender-preserving transport (Push EOA=true)","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"agent native arrays require an atomic sender-preserving transport (Push EOA=true)"},{"ancestorTitles":["guards fail before the signer is ever invoked"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"guards fail before the signer is ever invoked agent native arrays require an atomic sender-preserving transport (Push EOA=false)","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"agent native arrays require an atomic sender-preserving transport (Push EOA=false)"},{"ancestorTitles":["guards fail before the signer is ever invoked"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"guards fail before the signer is ever invoked empty native arrays fail before any transport is called","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"empty native arrays fail before any transport is called"},{"ancestorTitles":["guards fail before the signer is ever invoked"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"guards fail before the signer is ever invoked NO_RULES_FOR_CHAIN and AMBIGUOUS_RULE are pre-signature","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"NO_RULES_FOR_CHAIN and AMBIGUOUS_RULE are pre-signature"},{"ancestorTitles":["guards fail before the signer is ever invoked"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"guards fail before the signer is ever invoked an external agent whose deployed UEA cannot pay Push gas fails loudly; an undeployed UEA takes the first-use path","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"an external agent whose deployed UEA cannot pay Push gas fails loudly; an undeployed UEA takes the first-use path"},{"ancestorTitles":["explicit Push destinations"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"explicit Push destinations a ChainTarget on the connected Push chain is a native send, same as a bare address","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"a ChainTarget on the connected Push chain is a native send, same as a bare address"},{"ancestorTitles":["explicit Push destinations"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"explicit Push destinations the owner door treats it the same way","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"the owner door treats it the same way"},{"ancestorTitles":["explicit Push destinations"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"explicit Push destinations another Push network is refused, not routed outbound","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"another Push network is refused, not routed outbound"},{"ancestorTitles":["native wrapping and logical identity"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"native wrapping and logical identity agent door: executeAsAgent(selected rule, exact call); response shows the wallet as from","invocations":1,"location":null,"numPassingAsserts":9,"retryReasons":[],"status":"passed","title":"agent door: executeAsAgent(selected rule, exact call); response shows the wallet as from"},{"ancestorTitles":["native wrapping and logical identity"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"native wrapping and logical identity owner door: arrays become one atomic execute(batch)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"owner door: arrays become one atomic execute(batch)"},{"ancestorTitles":["native wrapping and logical identity"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"native wrapping and logical identity wallet waits report the wallet on the receipt too","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"wallet waits report the wallet on the receipt too"},{"ancestorTitles":["native wrapping and logical identity"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"native wrapping and logical identity an on-chain policy revert becomes AgenticRevertError with the decoded gate and 199-02","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"an on-chain policy revert becomes AgenticRevertError with the decoded gate and 199-02"},{"ancestorTitles":["EVM outbound composition from the wallet"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"EVM outbound composition from the wallet destination gas: deployed=false explicit=undefined quotes 2000000n","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"destination gas: deployed=false explicit=undefined quotes 2000000n"},{"ancestorTitles":["EVM outbound composition from the wallet"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"EVM outbound composition from the wallet destination gas: deployed=true explicit=undefined quotes 0n","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"destination gas: deployed=true explicit=undefined quotes 0n"},{"ancestorTitles":["EVM outbound composition from the wallet"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"EVM outbound composition from the wallet destination gas: deployed=false explicit=123456n quotes 123456n","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"destination gas: deployed=false explicit=123456n quotes 123456n"},{"ancestorTitles":["EVM outbound composition from the wallet"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"EVM outbound composition from the wallet destination gas: deployed=true explicit=123456n quotes 123456n","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"destination gas: deployed=true explicit=123456n quotes 123456n"},{"ancestorTitles":["EVM outbound composition from the wallet"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"EVM outbound composition from the wallet destination gas: deployed=false explicit=0n quotes 0n","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"destination gas: deployed=false explicit=0n quotes 0n"},{"ancestorTitles":["EVM outbound composition from the wallet"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"EVM outbound composition from the wallet builds the policy-compatible request: empty recipient, wallet refund, nonzero gas cap, multicall payload, CEA of the wallet","invocations":1,"location":null,"numPassingAsserts":10,"retryReasons":[],"status":"passed","title":"builds the policy-compatible request: empty recipient, wallet refund, nonzero gas cap, multicall payload, CEA of the wallet"},{"ancestorTitles":["EVM outbound composition from the wallet"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"EVM outbound composition from the wallet agent sends without a standing allowance; the wallet handles approval","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"agent sends without a standing allowance; the wallet handles approval"},{"ancestorTitles":["EVM outbound composition from the wallet"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"EVM outbound composition from the wallet wallet funding is checked locally; rule PC limits are enforced by the contract","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"wallet funding is checked locally; rule PC limits are enforced by the contract"},{"ancestorTitles":["EVM outbound composition from the wallet"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"EVM outbound composition from the wallet a committed destination account that no longer matches derivation is drift, not a send","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"a committed destination account that no longer matches derivation is drift, not a send"},{"ancestorTitles":["EVM outbound composition from the wallet"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"EVM outbound composition from the wallet a zero gas quote is refused (URP rejects an uncapped gas swap)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"a zero gas quote is refused (URP rejects an uncapped gas swap)"},{"ancestorTitles":["EVM outbound composition from the wallet"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"EVM outbound composition from the wallet SVM destinations reject EVM-width program addresses","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SVM destinations reject EVM-width program addresses"},{"ancestorTitles":["EVM outbound composition from the wallet"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"EVM outbound composition from the wallet owner door never writes an allowance: it sends only the outbound and consumes the existing allowance","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"owner door never writes an allowance: it sends only the outbound and consumes the existing allowance"},{"ancestorTitles":["EVM outbound composition from the wallet"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"EVM outbound composition from the wallet owner sends without a standing allowance","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"owner sends without a standing allowance"},{"ancestorTitles":["EVM outbound composition from the wallet"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"EVM outbound composition from the wallet an existing unlimited allowance is consumed as-is","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"an existing unlimited allowance is consumed as-is"},{"ancestorTitles":["EVM outbound composition from the wallet"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"EVM outbound composition from the wallet a transfer-only ERC-20 outbound instructs a transfer to the requested recipient","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"a transfer-only ERC-20 outbound instructs a transfer to the requested recipient"},{"ancestorTitles":["EVM outbound composition from the wallet"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"EVM outbound composition from the wallet a value-only outbound burns the native PRC20 for that value and forwards it to the recipient","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"a value-only outbound burns the native PRC20 for that value and forwards it to the recipient"},{"ancestorTitles":["EVM outbound composition from the wallet"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"EVM outbound composition from the wallet an outbound with no destination call (parking in the CEA) is refused before signing","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"an outbound with no destination call (parking in the CEA) is refused before signing"},{"ancestorTitles":["EVM outbound composition from the wallet"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"EVM outbound composition from the wallet an agent value-only destination call is refused before signing (the policy admits only allow-listed calls)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"an agent value-only destination call is refused before signing (the policy admits only allow-listed calls)"},{"ancestorTitles":["EVM outbound composition from the wallet"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"EVM outbound composition from the wallet more than 10 destination calls are refused","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"more than 10 destination calls are refused"}],"endTime":1792494874791,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/send.spec.ts","startTime":1792494874404,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["canonical outbound response on send and replay"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"canonical outbound response on send and replay explicit ERC20 transfer preserves its token target and calldata","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"explicit ERC20 transfer preserves its token target and calldata"},{"ancestorTitles":["canonical outbound response on send and replay"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"canonical outbound response on send and replay funds-only transfer describes the actual generated token call","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"funds-only transfer describes the actual generated token call"},{"ancestorTitles":["canonical outbound response on send and replay"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"canonical outbound response on send and replay funds plus app call keeps the generated transfer and app call in order","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"funds plus app call keeps the generated transfer and app call in order"},{"ancestorTitles":["canonical outbound response on send and replay"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"canonical outbound response on send and replay explicit call array retains all calls without guessing a primary action","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"explicit call array retains all calls without guessing a primary action"},{"ancestorTitles":["canonical outbound response on send and replay"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"canonical outbound response on send and replay native transfer preserves the actual destination value","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"native transfer preserves the actual destination value"},{"ancestorTitles":["outbound replay wait on the owner door"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"outbound replay wait on the owner door handles an early Push-only route with a success Push receipt","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"handles an early Push-only route with a success Push receipt"},{"ancestorTitles":["outbound replay wait on the owner door"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"outbound replay wait on the owner door handles an early Push-only route with a reverted Push receipt","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"handles an early Push-only route with a reverted Push receipt"},{"ancestorTitles":["outbound replay wait on the agent door"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"outbound replay wait on the agent door handles an early Push-only route with a success Push receipt","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"handles an early Push-only route with a success Push receipt"},{"ancestorTitles":["outbound replay wait on the agent door"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"outbound replay wait on the agent door handles an early Push-only route with a reverted Push receipt","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"handles an early Push-only route with a reverted Push receipt"}],"endTime":1792494875098,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/outbound-response.spec.ts","startTime":1792494874793,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["canonical registry integration"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"canonical registry integration rejects entrypoint fields without a custom target and rejects the removed nesting","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"rejects entrypoint fields without a custom target and rejects the removed nesting"},{"ancestorTitles":["canonical registry integration"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"canonical registry integration encodes the deployed three-argument entrypoint with default gas, key and unchanged refund","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"encodes the deployed three-argument entrypoint with default gas, key and unchanged refund"},{"ancestorTitles":["canonical registry integration"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"canonical registry integration keeps keys stable across pinning, payment and callback options","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"keeps keys stable across pinning, payment and callback options"},{"ancestorTitles":["canonical registry integration"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"canonical registry integration separates query identity but treats ERC20 shorthand and explicit balanceOf equivalently","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"separates query identity but treats ERC20 shorthand and explicit balanceOf equivalently"},{"ancestorTitles":["canonical registry integration"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"canonical registry integration includes Solana account, mint and token program in identity","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"includes Solana account, mint and token program in identity"},{"ancestorTitles":["canonical registry integration"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"canonical registry integration canonicalizes Web2 headers and excludes timeout while retaining extraction identity","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"canonicalizes Web2 headers and excludes timeout while retaining extraction identity"},{"ancestorTitles":["canonical registry integration"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"canonical registry integration does not assume this deployment exists on other networks; custom receivers still work","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"does not assume this deployment exists on other networks; custom receivers still work"},{"ancestorTitles":["canonical registry integration"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"canonical registry integration executes a prepared registry request through the existing batch tracker","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"executes a prepared registry request through the existing batch tracker"},{"ancestorTitles":["canonical registry integration"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"canonical registry integration exposes the supplied ABI lookup shapes without inventing consensus status","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"exposes the supplied ABI lookup shapes without inventing consensus status"}],"endTime":1792494875235,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/read-state/__tests__/registry.spec.ts","startTime":1792494875101,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["computeExecutionHash"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"computeExecutionHash returns a 32-byte keccak hash (0x + 64 hex chars)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"returns a 32-byte keccak hash (0x + 64 hex chars)"},{"ancestorTitles":["computeExecutionHash"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"computeExecutionHash is deterministic for the same inputs","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"is deterministic for the same inputs"},{"ancestorTitles":["computeExecutionHash"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"computeExecutionHash changes when the payload nonce differs","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"changes when the payload nonce differs"},{"ancestorTitles":["computeExecutionHash"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"computeExecutionHash changes when the payload value differs","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"changes when the payload value differs"},{"ancestorTitles":["computeExecutionHash"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"computeExecutionHash changes when verifyingContract differs","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"changes when verifyingContract differs"},{"ancestorTitles":["computeExecutionHash"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"computeExecutionHash changes when version differs","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"changes when version differs"},{"ancestorTitles":["computeExecutionHash"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"computeExecutionHash defaults version to \"0.1.0\" when omitted","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"defaults version to \"0.1.0\" when omitted"},{"ancestorTitles":["computeExecutionHash"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"computeExecutionHash produces a different hash for SVM vs EVM chains (different domain separator)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"produces a different hash for SVM vs EVM chains (different domain separator)"},{"ancestorTitles":["computeExecutionHash"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"computeExecutionHash uses the correct EIP-712 domain type string for EVM","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"uses the correct EIP-712 domain type string for EVM"},{"ancestorTitles":["computeExecutionHash"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"computeExecutionHash uses SVM domain type string for SVM chains","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"uses SVM domain type string for SVM chains"},{"ancestorTitles":["computeExecutionHash"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"computeExecutionHash handles zero-value payload fields","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"handles zero-value payload fields"},{"ancestorTitles":["computeExecutionHash"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"computeExecutionHash handles empty data (0x)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"handles empty data (0x)"},{"ancestorTitles":["computeExecutionHash"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"computeExecutionHash changes when payload data differs","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"changes when payload data differs"},{"ancestorTitles":["computeExecutionHash"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"computeExecutionHash changes when vType differs","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"changes when vType differs"},{"ancestorTitles":["computeMigrationHash"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"computeMigrationHash returns a 32-byte keccak hash","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"returns a 32-byte keccak hash"},{"ancestorTitles":["computeMigrationHash"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"computeMigrationHash is deterministic for the same inputs","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"is deterministic for the same inputs"},{"ancestorTitles":["computeMigrationHash"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"computeMigrationHash changes when nonce differs","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"changes when nonce differs"},{"ancestorTitles":["computeMigrationHash"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"computeMigrationHash changes when deadline differs","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"changes when deadline differs"},{"ancestorTitles":["computeMigrationHash"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"computeMigrationHash changes when migrationContractAddress differs","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"changes when migrationContractAddress differs"},{"ancestorTitles":["computeMigrationHash"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"computeMigrationHash changes when verifyingContract differs","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"changes when verifyingContract differs"},{"ancestorTitles":["computeMigrationHash"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"computeMigrationHash defaults version to \"0.1.0\" when omitted","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"defaults version to \"0.1.0\" when omitted"},{"ancestorTitles":["computeMigrationHash"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"computeMigrationHash changes when version differs","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"changes when version differs"},{"ancestorTitles":["computeMigrationHash"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"computeMigrationHash produces different hashes for SVM vs EVM chains","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"produces different hashes for SVM vs EVM chains"},{"ancestorTitles":["computeMigrationHash"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"computeMigrationHash handles zero nonce and deadline","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"handles zero nonce and deadline"},{"ancestorTitles":["signUniversalPayload","EVM path"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"signUniversalPayload EVM path calls signTypedData with correct domain, types, and message","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"calls signTypedData with correct domain, types, and message"},{"ancestorTitles":["signUniversalPayload","EVM path"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"signUniversalPayload EVM path uses custom version when provided","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"uses custom version when provided"},{"ancestorTitles":["signUniversalPayload","EVM path"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"signUniversalPayload EVM path defaults version to \"0.1.0\" when not provided","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"defaults version to \"0.1.0\" when not provided"},{"ancestorTitles":["signUniversalPayload","EVM path"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"signUniversalPayload EVM path returns the signature bytes from signTypedData","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"returns the signature bytes from signTypedData"},{"ancestorTitles":["signUniversalPayload","EVM path"],"duration":10,"failureDetails":[],"failureMessages":[],"fullName":"signUniversalPayload EVM path throws if signTypedData is not defined","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"throws if signTypedData is not defined"},{"ancestorTitles":["signUniversalPayload","SVM path"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"signUniversalPayload SVM path calls signMessage (not signTypedData) for SVM chains","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"calls signMessage (not signTypedData) for SVM chains"},{"ancestorTitles":["signUniversalPayload","SVM path"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"signUniversalPayload SVM path returns the signature bytes from signMessage","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"returns the signature bytes from signMessage"},{"ancestorTitles":["signUniversalPayload","SVM path"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"signUniversalPayload SVM path passes the execution digest as bytes to signMessage","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"passes the execution digest as bytes to signMessage"},{"ancestorTitles":["signMigrationPayload","EVM path"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"signMigrationPayload EVM path calls signTypedData with correct domain and MigrationPayload types","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"calls signTypedData with correct domain and MigrationPayload types"},{"ancestorTitles":["signMigrationPayload","EVM path"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"signMigrationPayload EVM path returns the signature bytes","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"returns the signature bytes"},{"ancestorTitles":["signMigrationPayload","EVM path"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"signMigrationPayload EVM path throws if signTypedData is not defined","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"throws if signTypedData is not defined"},{"ancestorTitles":["signMigrationPayload","SVM path"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"signMigrationPayload SVM path calls signMessage for SVM chains","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"calls signMessage for SVM chains"},{"ancestorTitles":["signMigrationPayload","SVM path"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"signMigrationPayload SVM path returns the signature bytes from signMessage","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"returns the signature bytes from signMessage"},{"ancestorTitles":["signMigrationPayload","SVM path"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"signMigrationPayload SVM path passes the migration digest as bytes to signMessage","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"passes the migration digest as bytes to signMessage"},{"ancestorTitles":["encodeUniversalPayload"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"encodeUniversalPayload encodes and round-trips a standard payload","invocations":1,"location":null,"numPassingAsserts":10,"retryReasons":[],"status":"passed","title":"encodes and round-trips a standard payload"},{"ancestorTitles":["encodeUniversalPayload"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"encodeUniversalPayload encodes zero-value fields correctly","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"encodes zero-value fields correctly"},{"ancestorTitles":["encodeUniversalPayload"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"encodeUniversalPayload preserves large BigInt values","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"preserves large BigInt values"},{"ancestorTitles":["encodeUniversalPayload"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"encodeUniversalPayload returns a hex string starting with 0x","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"returns a hex string starting with 0x"},{"ancestorTitles":["encodeUniversalPayloadSvm"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"encodeUniversalPayloadSvm returns a Buffer","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"returns a Buffer"},{"ancestorTitles":["encodeUniversalPayloadSvm"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"encodeUniversalPayloadSvm starts with 20 address bytes","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"starts with 20 address bytes"},{"ancestorTitles":["encodeUniversalPayloadSvm"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"encodeUniversalPayloadSvm encodes value as little-endian u64 at offset 20","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"encodes value as little-endian u64 at offset 20"},{"ancestorTitles":["encodeUniversalPayloadSvm"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"encodeUniversalPayloadSvm encodes data with a 4-byte LE length prefix","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"encodes data with a 4-byte LE length prefix"},{"ancestorTitles":["encodeUniversalPayloadSvm"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"encodeUniversalPayloadSvm encodes empty data (0x) with zero length","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"encodes empty data (0x) with zero length"},{"ancestorTitles":["encodeUniversalPayloadSvm"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"encodeUniversalPayloadSvm encodes gasLimit, maxFeePerGas, maxPriorityFeePerGas, nonce as u64 LE","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"encodes gasLimit, maxFeePerGas, maxPriorityFeePerGas, nonce as u64 LE"},{"ancestorTitles":["encodeUniversalPayloadSvm"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"encodeUniversalPayloadSvm encodes deadline as i64 LE (signed)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"encodes deadline as i64 LE (signed)"},{"ancestorTitles":["encodeUniversalPayloadSvm"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"encodeUniversalPayloadSvm does not require Buffer BigInt write methods (browser polyfill compatibility)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"does not require Buffer BigInt write methods (browser polyfill compatibility)"},{"ancestorTitles":["encodeUniversalPayloadSvm"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"encodeUniversalPayloadSvm encodes vType as a single byte at the end","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"encodes vType as a single byte at the end"},{"ancestorTitles":["encodeUniversalPayloadSvm"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"encodeUniversalPayloadSvm total length for empty-data payload is 73 bytes","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"total length for empty-data payload is 73 bytes"},{"ancestorTitles":["encodeUniversalPayloadSvm","u64 bounds"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"encodeUniversalPayloadSvm u64 bounds passes at u64 max","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"passes at u64 max"},{"ancestorTitles":["encodeUniversalPayloadSvm","u64 bounds"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"encodeUniversalPayloadSvm u64 bounds throws on u64 max + 1","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"throws on u64 max + 1"},{"ancestorTitles":["buildUniversalTxRequest"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"buildUniversalTxRequest returns a well-formed UniversalTxRequest","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"returns a well-formed UniversalTxRequest"},{"ancestorTitles":["buildUniversalTxRequest"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildUniversalTxRequest sets revertInstruction.fundRecipient to the signer address","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"sets revertInstruction.fundRecipient to the signer address"},{"ancestorTitles":["buildUniversalTxRequest"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildUniversalTxRequest handles zero amount","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"handles zero amount"},{"ancestorTitles":["buildUniversalTxRequest"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildUniversalTxRequest preserves the payload as-is without modification","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"preserves the payload as-is without modification"},{"ancestorTitles":["buildUniversalTxRequest"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildUniversalTxRequest works with zeroAddress as token","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"works with zeroAddress as token"},{"ancestorTitles":["buildUniversalTxRequest"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"buildUniversalTxRequest works with zeroAddress as recipient","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"works with zeroAddress as recipient"},{"ancestorTitles":["buildMulticallPayloadData"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildMulticallPayloadData starts with the UEA_MULTICALL selector (first 4 bytes of keccak)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"starts with the UEA_MULTICALL selector (first 4 bytes of keccak)"},{"ancestorTitles":["buildMulticallPayloadData"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"buildMulticallPayloadData encodes a single multicall entry that can be decoded","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"encodes a single multicall entry that can be decoded"},{"ancestorTitles":["buildMulticallPayloadData"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildMulticallPayloadData encodes multiple multicall entries","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"encodes multiple multicall entries"},{"ancestorTitles":["buildMulticallPayloadData"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"buildMulticallPayloadData checksums addresses via getAddress","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"checksums addresses via getAddress"},{"ancestorTitles":["buildMulticallPayloadData"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"buildMulticallPayloadData throws for unsupported chains","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"throws for unsupported chains"},{"ancestorTitles":["buildMulticallPayloadData"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildMulticallPayloadData works for Arbitrum Sepolia chain","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"works for Arbitrum Sepolia chain"},{"ancestorTitles":["buildMulticallPayloadData"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildMulticallPayloadData works for Base Sepolia chain","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"works for Base Sepolia chain"},{"ancestorTitles":["buildMulticallPayloadData"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildMulticallPayloadData works for BNB Testnet chain","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"works for BNB Testnet chain"},{"ancestorTitles":["buildMulticallPayloadData"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"buildMulticallPayloadData works for Solana Devnet chain","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"works for Solana Devnet chain"},{"ancestorTitles":["buildMulticallPayloadData"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildMulticallPayloadData handles zero-value calls with empty data","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"handles zero-value calls with empty data"}],"endTime":1792494875439,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/signing-payload.spec.ts","startTime":1792494875238,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["tx-transformer","transformToUniversalTxReceipt"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"tx-transformer transformToUniversalTxReceipt should map viem TransactionReceipt fields to UniversalTxReceipt","invocations":1,"location":null,"numPassingAsserts":13,"retryReasons":[],"status":"passed","title":"should map viem TransactionReceipt fields to UniversalTxReceipt"},{"ancestorTitles":["tx-transformer","transformToUniversalTxReceipt"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"tx-transformer transformToUniversalTxReceipt should set status=0 for reverted receipt","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should set status=0 for reverted receipt"},{"ancestorTitles":["tx-transformer","transformToUniversalTxReceipt"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"tx-transformer transformToUniversalTxReceipt should use contractAddress from receipt when present","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should use contractAddress from receipt when present"},{"ancestorTitles":["tx-transformer","transformToUniversalTxReceipt"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"tx-transformer transformToUniversalTxReceipt should fallback to BigInt(0) when gasPrice is undefined","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should fallback to BigInt(0) when gasPrice is undefined"},{"ancestorTitles":["tx-transformer","transformToUniversalTxReceipt"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"tx-transformer transformToUniversalTxReceipt should use raw from originalTxResponse when present","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should use raw from originalTxResponse when present"},{"ancestorTitles":["tx-transformer","transformToUniversalTxReceipt"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"tx-transformer transformToUniversalTxReceipt should construct fallback raw when originalTxResponse.raw is undefined","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should construct fallback raw when originalTxResponse.raw is undefined"},{"ancestorTitles":["tx-transformer","transformToUniversalTxReceipt"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"tx-transformer transformToUniversalTxReceipt should pass through logs from receipt","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should pass through logs from receipt"},{"ancestorTitles":["tx-transformer","transformToUniversalTxReceipt"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"tx-transformer transformToUniversalTxReceipt should default logsBloom to 0x when receipt has no logsBloom","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should default logsBloom to 0x when receipt has no logsBloom"},{"ancestorTitles":["tx-transformer","reconstructProgressEvents"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"tx-transformer reconstructProgressEvents should always include SEND_TX_101, SEND_TX_102_01, SEND_TX_103_03_04","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should always include SEND_TX_101, SEND_TX_102_01, SEND_TX_103_03_04"},{"ancestorTitles":["tx-transformer","reconstructProgressEvents"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"tx-transformer reconstructProgressEvents should always end with a final event (success or error)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should always end with a final event (success or error)"},{"ancestorTitles":["tx-transformer","reconstructProgressEvents"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"tx-transformer reconstructProgressEvents should include UEA resolution events for non-Push origins","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should include UEA resolution events for non-Push origins"},{"ancestorTitles":["tx-transformer","reconstructProgressEvents"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"tx-transformer reconstructProgressEvents should NOT include UEA resolution events for Push Chain origins","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should NOT include UEA resolution events for Push Chain origins"},{"ancestorTitles":["tx-transformer","reconstructProgressEvents"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"tx-transformer reconstructProgressEvents should NOT include sub-path-specific events in R1 reconstruction","invocations":1,"location":null,"numPassingAsserts":11,"retryReasons":[],"status":"passed","title":"should NOT include sub-path-specific events in R1 reconstruction"},{"ancestorTitles":["tx-transformer","reconstructProgressEvents"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"tx-transformer reconstructProgressEvents should include broadcasting event (SEND_TX_107)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should include broadcasting event (SEND_TX_107)"},{"ancestorTitles":["tx-transformer","reconstructProgressEvents"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"tx-transformer reconstructProgressEvents should emit error event for OUTBOUND_FAILED status","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should emit error event for OUTBOUND_FAILED status"},{"ancestorTitles":["tx-transformer","reconstructProgressEvents"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"tx-transformer reconstructProgressEvents should emit error event when pcTx status is FAILED","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should emit error event when pcTx status is FAILED"},{"ancestorTitles":["tx-transformer","reconstructProgressEvents"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"tx-transformer reconstructProgressEvents should emit success event for successful transactions","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should emit success event for successful transactions"},{"ancestorTitles":["tx-transformer","reconstructProgressEvents"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"tx-transformer reconstructProgressEvents should parse origin with only namespace (no address part)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should parse origin with only namespace (no address part)"},{"ancestorTitles":["tx-transformer","reconstructProgressEvents"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"tx-transformer reconstructProgressEvents should handle FAILED pcTx with empty errorMsg","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should handle FAILED pcTx with empty errorMsg"},{"ancestorTitles":["tx-transformer","reconstructProgressEvents"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"tx-transformer reconstructProgressEvents should emit success when universalTxData is undefined","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should emit success when universalTxData is undefined"},{"ancestorTitles":["tx-transformer","reconstructProgressEvents"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"tx-transformer reconstructProgressEvents R2 reconstruction: pcTx.FAILED emits 299-02 terminal","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"R2 reconstruction: pcTx.FAILED emits 299-02 terminal"},{"ancestorTitles":["tx-transformer","reconstructProgressEvents"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"tx-transformer reconstructProgressEvents R2 reconstruction: universalStatus=OUTBOUND_FAILED without pcFailed does not emit terminal failure","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"R2 reconstruction: universalStatus=OUTBOUND_FAILED without pcFailed does not emit terminal failure"},{"ancestorTitles":["tx-transformer","reconstructProgressEvents"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"tx-transformer reconstructProgressEvents R3 reconstruction: pcTx.FAILED emits 399-02 terminal with phase=push","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"R3 reconstruction: pcTx.FAILED emits 399-02 terminal with phase=push"},{"ancestorTitles":["tx-transformer","reconstructProgressEvents"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"tx-transformer reconstructProgressEvents R3 reconstruction: universalStatus=OUTBOUND_FAILED without pcFailed does not emit terminal failure","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"R3 reconstruction: universalStatus=OUTBOUND_FAILED without pcFailed does not emit terminal failure"},{"ancestorTitles":["tx-transformer","detectRouteFromUniversalTxData"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"tx-transformer detectRouteFromUniversalTxData should return undefined for undefined input","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return undefined for undefined input"},{"ancestorTitles":["tx-transformer","detectRouteFromUniversalTxData"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"tx-transformer detectRouteFromUniversalTxData should return UOA_TO_PUSH when no outbound and no inbound","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return UOA_TO_PUSH when no outbound and no inbound"},{"ancestorTitles":["tx-transformer","detectRouteFromUniversalTxData"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"tx-transformer detectRouteFromUniversalTxData should return UOA_TO_CEA when outbound present but no inbound","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return UOA_TO_CEA when outbound present but no inbound"},{"ancestorTitles":["tx-transformer","detectRouteFromUniversalTxData"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"tx-transformer detectRouteFromUniversalTxData should return CEA_TO_CEA when both outbound and inbound present","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return CEA_TO_CEA when both outbound and inbound present"},{"ancestorTitles":["tx-transformer","detectRouteFromUniversalTxData"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"tx-transformer detectRouteFromUniversalTxData should return CEA_TO_PUSH when inbound present but no outbound","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return CEA_TO_PUSH when inbound present but no outbound"},{"ancestorTitles":["tx-transformer","detectRouteFromUniversalTxData"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"tx-transformer detectRouteFromUniversalTxData should detect outbound route from status alone (OUTBOUND_PENDING, empty outboundTx)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should detect outbound route from status alone (OUTBOUND_PENDING, empty outboundTx)"},{"ancestorTitles":["tx-transformer","detectRouteFromUniversalTxData"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"tx-transformer detectRouteFromUniversalTxData should detect outbound route from OUTBOUND_SUCCESS status","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should detect outbound route from OUTBOUND_SUCCESS status"},{"ancestorTitles":["tx-transformer","detectRouteFromUniversalTxData"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"tx-transformer detectRouteFromUniversalTxData should detect outbound route from OUTBOUND_FAILED status","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should detect outbound route from OUTBOUND_FAILED status"},{"ancestorTitles":["tx-transformer","detectRouteFromUniversalTxData"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"tx-transformer detectRouteFromUniversalTxData should return CEA_TO_CEA when OUTBOUND_PENDING status and inbound present","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return CEA_TO_CEA when OUTBOUND_PENDING status and inbound present"},{"ancestorTitles":["gas-calculator","ensureErc20Allowance"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"gas-calculator ensureErc20Allowance should return immediately if existing allowance >= required","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should return immediately if existing allowance >= required"},{"ancestorTitles":["gas-calculator","ensureErc20Allowance"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"gas-calculator ensureErc20Allowance should return immediately if existing allowance equals required","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return immediately if existing allowance equals required"},{"ancestorTitles":["gas-calculator","ensureErc20Allowance"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"gas-calculator ensureErc20Allowance should set new allowance when current is zero","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should set new allowance when current is zero"},{"ancestorTitles":["gas-calculator","ensureErc20Allowance"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"gas-calculator ensureErc20Allowance should reset then set allowance when current is non-zero but insufficient","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should reset then set allowance when current is non-zero but insufficient"},{"ancestorTitles":["gas-calculator","ensureErc20Allowance"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"gas-calculator ensureErc20Allowance should wait for confirmations after each write","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should wait for confirmations after each write"},{"ancestorTitles":["gas-calculator","ensureErc20Allowance"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"gas-calculator ensureErc20Allowance should not throw when verification read fails","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should not throw when verification read fails"},{"ancestorTitles":["gas-calculator","calculateNativeAmountForDeposit"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"gas-calculator calculateNativeAmountForDeposit should calculate native amount based on deficit and price","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should calculate native amount based on deficit and price"},{"ancestorTitles":["gas-calculator","calculateNativeAmountForDeposit"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"gas-calculator calculateNativeAmountForDeposit should use $1 minimum deposit when deficit is zero","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should use $1 minimum deposit when deficit is zero"},{"ancestorTitles":["gas-calculator","calculateNativeAmountForDeposit"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"gas-calculator calculateNativeAmountForDeposit should throw if deposit exceeds $1000","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should throw if deposit exceeds $1000"},{"ancestorTitles":["gas-calculator","calculateNativeAmountForDeposit"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"gas-calculator calculateNativeAmountForDeposit should clamp deposit up to $1 minimum","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should clamp deposit up to $1 minimum"},{"ancestorTitles":["gas-calculator","calculateNativeAmountForDeposit"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"gas-calculator calculateNativeAmountForDeposit should fire progress hooks","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should fire progress hooks"},{"ancestorTitles":["gas-calculator","calculateGasAmountFromAmountOutMinETH"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"gas-calculator calculateGasAmountFromAmountOutMinETH should return amountOutMinETH directly when gasToken is WETH","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should return amountOutMinETH directly when gasToken is WETH"},{"ancestorTitles":["gas-calculator","calculateGasAmountFromAmountOutMinETH"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"gas-calculator calculateGasAmountFromAmountOutMinETH should return amountOutMinETH for WETH regardless of case","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return amountOutMinETH for WETH regardless of case"},{"ancestorTitles":["gas-calculator","calculateGasAmountFromAmountOutMinETH"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"gas-calculator calculateGasAmountFromAmountOutMinETH should accept string amountOutMinETH","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should accept string amountOutMinETH"},{"ancestorTitles":["gas-calculator","calculateGasAmountFromAmountOutMinETH"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"gas-calculator calculateGasAmountFromAmountOutMinETH should call quoteExactOutputFn and add 1% slippage for non-WETH tokens","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should call quoteExactOutputFn and add 1% slippage for non-WETH tokens"},{"ancestorTitles":["gas-calculator","calculateGasAmountFromAmountOutMinETH"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"gas-calculator calculateGasAmountFromAmountOutMinETH should throw for unsupported chain","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should throw for unsupported chain"},{"ancestorTitles":["gas-calculator","calculateGasAmountFromAmountOutMinETH"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"gas-calculator calculateGasAmountFromAmountOutMinETH should throw when WETH is not configured for chain","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should throw when WETH is not configured for chain"},{"ancestorTitles":["gas-calculator","calculateGasAmountFromAmountOutMinETH"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"gas-calculator calculateGasAmountFromAmountOutMinETH should throw when from/to tokens are not found in registry","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should throw when from/to tokens are not found in registry"},{"ancestorTitles":["gas-calculator","calculateGasAmountFromAmountOutMinETH"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"gas-calculator calculateGasAmountFromAmountOutMinETH should work for Arbitrum Sepolia","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should work for Arbitrum Sepolia"},{"ancestorTitles":["gas-calculator","calculateGasAmountFromAmountOutMinETH"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"gas-calculator calculateGasAmountFromAmountOutMinETH should work for Base Sepolia","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should work for Base Sepolia"},{"ancestorTitles":["gas-calculator","calculateGasAmountFromAmountOutMinETH"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"gas-calculator calculateGasAmountFromAmountOutMinETH should handle zero amountOutMinETH","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should handle zero amountOutMinETH"}],"endTime":1792494875627,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/tx-transformer-gas.spec.ts","startTime":1792494875451,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["R3 error classification","SEND_TX_304_04 builder"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"R3 error classification SEND_TX_304_04 builder emits decline copy for a real wallet rejection","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"emits decline copy for a real wallet rejection"},{"ancestorTitles":["R3 error classification","SEND_TX_304_04 builder"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"R3 error classification SEND_TX_304_04 builder emits signature-failed copy for a generic sign-time error","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"emits signature-failed copy for a generic sign-time error"},{"ancestorTitles":["R3 error classification","SEND_TX_304_04 builder"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"R3 error classification SEND_TX_304_04 builder treats undefined errorMessage as a decline","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"treats undefined errorMessage as a decline"},{"ancestorTitles":["R3 error classification","SEND_TX_304_04 builder"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"R3 error classification SEND_TX_304_04 builder classifies ethers ACTION_REJECTED as a decline","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"classifies ethers ACTION_REJECTED as a decline"},{"ancestorTitles":["R3 error classification","SEND_TX_304_04 builder"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"R3 error classification SEND_TX_304_04 builder classifies EIP-1193 4001 code as a decline","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"classifies EIP-1193 4001 code as a decline"},{"ancestorTitles":["R3 error classification","SEND_TX_304_04 builder"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"R3 error classification SEND_TX_304_04 builder classifies RPC timeout during signing as signature-failed (not decline)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"classifies RPC timeout during signing as signature-failed (not decline)"},{"ancestorTitles":["R3 error classification","104_04 / 204_04 / 304_04 parity (shared classifier)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"R3 error classification 104_04 / 204_04 / 304_04 parity (shared classifier) emits identical title + message across all three routes for: UserRejectedRequestError: The user rejected the request.","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"emits identical title + message across all three routes for: UserRejectedRequestError: The user rejected the request."},{"ancestorTitles":["R3 error classification","104_04 / 204_04 / 304_04 parity (shared classifier)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"R3 error classification 104_04 / 204_04 / 304_04 parity (shared classifier) emits identical title + message across all three routes for: user rejected transaction [ACTION_REJECTED]","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"emits identical title + message across all three routes for: user rejected transaction [ACTION_REJECTED]"},{"ancestorTitles":["R3 error classification","104_04 / 204_04 / 304_04 parity (shared classifier)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"R3 error classification 104_04 / 204_04 / 304_04 parity (shared classifier) emits identical title + message across all three routes for: insufficient funds for intrinsic transaction cost","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"emits identical title + message across all three routes for: insufficient funds for intrinsic transaction cost"},{"ancestorTitles":["R3 error classification","104_04 / 204_04 / 304_04 parity (shared classifier)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"R3 error classification 104_04 / 204_04 / 304_04 parity (shared classifier) emits identical title + message across all three routes for: something went wrong","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"emits identical title + message across all three routes for: something went wrong"},{"ancestorTitles":["R3 error classification","104_04 / 204_04 / 304_04 parity (shared classifier)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"R3 error classification 104_04 / 204_04 / 304_04 parity (shared classifier) emits identical title + message across all three routes for: undefined","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"emits identical title + message across all three routes for: undefined"}],"endTime":1792494875763,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/r3-error-classification.spec.ts","startTime":1792494875632,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["context","printLog"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"context printLog should log when printTraces is true","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should log when printTraces is true"},{"ancestorTitles":["context","printLog"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"context printLog should NOT log when printTraces is false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should NOT log when printTraces is false"},{"ancestorTitles":["context","printLog"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"context printLog should handle empty message","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should handle empty message"},{"ancestorTitles":["context","fireProgressHook"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"context fireProgressHook should call progressHook callback when provided","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"should call progressHook callback when provided"},{"ancestorTitles":["context","fireProgressHook"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"context fireProgressHook should NOT call progressHook when callback is undefined","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should NOT call progressHook when callback is undefined"},{"ancestorTitles":["context","fireProgressHook"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"context fireProgressHook should also print the message via printLog when printTraces is true","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should also print the message via printLog when printTraces is true"},{"ancestorTitles":["context","fireProgressHook"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"context fireProgressHook should forward extra arguments to the hook factory","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should forward extra arguments to the hook factory"},{"ancestorTitles":["context","OrchestratorContext interface"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"context OrchestratorContext interface should accept the minimal mock shape without errors","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"should accept the minimal mock shape without errors"},{"ancestorTitles":["context","OrchestratorContext interface"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"context OrchestratorContext interface should allow mutable caches to be set","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should allow mutable caches to be set"},{"ancestorTitles":["helpers","isPushChain"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"helpers isPushChain should return true for PUSH_MAINNET","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return true for PUSH_MAINNET"},{"ancestorTitles":["helpers","isPushChain"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"helpers isPushChain should return true for PUSH_TESTNET_DONUT","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return true for PUSH_TESTNET_DONUT"},{"ancestorTitles":["helpers","isPushChain"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"helpers isPushChain should return true for PUSH_LOCALNET","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return true for PUSH_LOCALNET"},{"ancestorTitles":["helpers","isPushChain"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"helpers isPushChain should return false for EVM external chains","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"should return false for EVM external chains"},{"ancestorTitles":["helpers","isPushChain"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"helpers isPushChain should return false for SVM chains","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should return false for SVM chains"},{"ancestorTitles":["helpers","getPushChainForNetwork"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"helpers getPushChainForNetwork should return PUSH_MAINNET for MAINNET","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return PUSH_MAINNET for MAINNET"},{"ancestorTitles":["helpers","getPushChainForNetwork"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"helpers getPushChainForNetwork should return PUSH_TESTNET_DONUT for TESTNET_DONUT","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return PUSH_TESTNET_DONUT for TESTNET_DONUT"},{"ancestorTitles":["helpers","getPushChainForNetwork"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"helpers getPushChainForNetwork should return PUSH_TESTNET_DONUT for TESTNET","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return PUSH_TESTNET_DONUT for TESTNET"},{"ancestorTitles":["helpers","getPushChainForNetwork"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"helpers getPushChainForNetwork should return PUSH_LOCALNET for LOCALNET","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return PUSH_LOCALNET for LOCALNET"},{"ancestorTitles":["helpers","getChainNamespace"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"helpers getChainNamespace should return correct CAIP-2 namespace for Ethereum Sepolia","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return correct CAIP-2 namespace for Ethereum Sepolia"},{"ancestorTitles":["helpers","getChainNamespace"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"helpers getChainNamespace should return correct CAIP-2 namespace for Solana Devnet","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return correct CAIP-2 namespace for Solana Devnet"},{"ancestorTitles":["helpers","getChainNamespace"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"helpers getChainNamespace should return correct namespace for Push Testnet Donut","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return correct namespace for Push Testnet Donut"},{"ancestorTitles":["helpers","getChainNamespace"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"helpers getChainNamespace should return correct namespace for BNB Testnet","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return correct namespace for BNB Testnet"},{"ancestorTitles":["helpers","getChainNamespace"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"helpers getChainNamespace should match VM_NAMESPACE prefix for every chain","invocations":1,"location":null,"numPassingAsserts":12,"retryReasons":[],"status":"passed","title":"should match VM_NAMESPACE prefix for every chain"},{"ancestorTitles":["helpers","chainFromNamespace"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"helpers chainFromNamespace should resolve Ethereum Sepolia from its CAIP-2 namespace","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should resolve Ethereum Sepolia from its CAIP-2 namespace"},{"ancestorTitles":["helpers","chainFromNamespace"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"helpers chainFromNamespace should resolve Solana Devnet from its namespace","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should resolve Solana Devnet from its namespace"},{"ancestorTitles":["helpers","chainFromNamespace"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"helpers chainFromNamespace should resolve Push Testnet Donut","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should resolve Push Testnet Donut"},{"ancestorTitles":["helpers","chainFromNamespace"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"helpers chainFromNamespace should return null for unknown namespace","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return null for unknown namespace"},{"ancestorTitles":["helpers","chainFromNamespace"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"helpers chainFromNamespace should return null for empty string","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return null for empty string"},{"ancestorTitles":["helpers","chainFromNamespace"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"helpers chainFromNamespace should be the inverse of getChainNamespace","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should be the inverse of getChainNamespace"},{"ancestorTitles":["helpers","getNativePRC20ForChain"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"helpers getNativePRC20ForChain should return pETH for Ethereum Sepolia","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return pETH for Ethereum Sepolia"},{"ancestorTitles":["helpers","getNativePRC20ForChain"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"helpers getNativePRC20ForChain should return pETH for Ethereum Mainnet","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return pETH for Ethereum Mainnet"},{"ancestorTitles":["helpers","getNativePRC20ForChain"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"helpers getNativePRC20ForChain should return pETH_ARB for Arbitrum Sepolia","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return pETH_ARB for Arbitrum Sepolia"},{"ancestorTitles":["helpers","getNativePRC20ForChain"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"helpers getNativePRC20ForChain should return pETH_BASE for Base Sepolia","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return pETH_BASE for Base Sepolia"},{"ancestorTitles":["helpers","getNativePRC20ForChain"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"helpers getNativePRC20ForChain should return pBNB for BNB Testnet","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return pBNB for BNB Testnet"},{"ancestorTitles":["helpers","getNativePRC20ForChain"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"helpers getNativePRC20ForChain should return pSOL for Solana Devnet","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return pSOL for Solana Devnet"},{"ancestorTitles":["helpers","getNativePRC20ForChain"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"helpers getNativePRC20ForChain should return pSOL for Solana Testnet","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return pSOL for Solana Testnet"},{"ancestorTitles":["helpers","getNativePRC20ForChain"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"helpers getNativePRC20ForChain should return pSOL for Solana Mainnet","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return pSOL for Solana Mainnet"},{"ancestorTitles":["helpers","getNativePRC20ForChain"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"helpers getNativePRC20ForChain should throw for Push Chain chains","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should throw for Push Chain chains"},{"ancestorTitles":["helpers","getNativePRC20ForChain"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"helpers getNativePRC20ForChain should throw for Push Localnet","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should throw for Push Localnet"},{"ancestorTitles":["helpers","getUniversalGatewayPCAddress"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"helpers getUniversalGatewayPCAddress should return the fixed precompile address","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return the fixed precompile address"},{"ancestorTitles":["helpers","getUniversalGatewayPCAddress"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"helpers getUniversalGatewayPCAddress should be 0x-prefixed","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should be 0x-prefixed"},{"ancestorTitles":["helpers","validateMainnetConnection"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"helpers validateMainnetConnection should throw when Ethereum Mainnet is used with non-mainnet Push Chain","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should throw when Ethereum Mainnet is used with non-mainnet Push Chain"},{"ancestorTitles":["helpers","validateMainnetConnection"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"helpers validateMainnetConnection should throw when Solana Mainnet is used with non-mainnet Push Chain","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should throw when Solana Mainnet is used with non-mainnet Push Chain"},{"ancestorTitles":["helpers","validateMainnetConnection"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"helpers validateMainnetConnection should NOT throw for Ethereum Mainnet with Push Mainnet chainId","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should NOT throw for Ethereum Mainnet with Push Mainnet chainId"},{"ancestorTitles":["helpers","validateMainnetConnection"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"helpers validateMainnetConnection should NOT throw for non-mainnet chains regardless of Push chainId","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should NOT throw for non-mainnet chains regardless of Push chainId"},{"ancestorTitles":["helpers","bigintReplacer"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"helpers bigintReplacer should convert bigint to string","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should convert bigint to string"},{"ancestorTitles":["helpers","bigintReplacer"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"helpers bigintReplacer should convert BigInt(0) to \"0\"","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should convert BigInt(0) to \"0\""},{"ancestorTitles":["helpers","bigintReplacer"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"helpers bigintReplacer should pass through strings unchanged","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should pass through strings unchanged"},{"ancestorTitles":["helpers","bigintReplacer"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"helpers bigintReplacer should pass through numbers unchanged","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should pass through numbers unchanged"},{"ancestorTitles":["helpers","bigintReplacer"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"helpers bigintReplacer should pass through null unchanged","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should pass through null unchanged"},{"ancestorTitles":["helpers","bigintReplacer"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"helpers bigintReplacer should pass through objects unchanged","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should pass through objects unchanged"},{"ancestorTitles":["helpers","bigintReplacer"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"helpers bigintReplacer should work as a JSON.stringify replacer","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should work as a JSON.stringify replacer"},{"ancestorTitles":["helpers","toExecuteParams"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"helpers toExecuteParams should extract address from string `to`","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should extract address from string `to`"},{"ancestorTitles":["helpers","toExecuteParams"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"helpers toExecuteParams should extract address from ChainTarget `to`","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should extract address from ChainTarget `to`"},{"ancestorTitles":["helpers","toExecuteParams"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"helpers toExecuteParams should forward value, data, funds, gasLimit, and deadline","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"should forward value, data, funds, gasLimit, and deadline"},{"ancestorTitles":["helpers","toExecuteParams"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"helpers toExecuteParams should forward feeLockTxHash when present","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should forward feeLockTxHash when present"},{"ancestorTitles":["helpers","toExecuteParams"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"helpers toExecuteParams should leave optional fields as undefined when not provided","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"should leave optional fields as undefined when not provided"},{"ancestorTitles":["helpers","toExecuteParams"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"helpers toExecuteParams should forward funds parameter","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should forward funds parameter"},{"ancestorTitles":["helpers","toExecuteParams"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"helpers toExecuteParams should NOT include `from` or `svmExecute` in the result","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should NOT include `from` or `svmExecute` in the result"},{"ancestorTitles":["helpers","SUPPORTED_GATEWAY_CHAINS"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"helpers SUPPORTED_GATEWAY_CHAINS should be an array","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should be an array"},{"ancestorTitles":["helpers","SUPPORTED_GATEWAY_CHAINS"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"helpers SUPPORTED_GATEWAY_CHAINS should contain known chains","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"should contain known chains"},{"ancestorTitles":["helpers","SUPPORTED_GATEWAY_CHAINS"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"helpers SUPPORTED_GATEWAY_CHAINS should NOT contain Push Chain variants","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should NOT contain Push Chain variants"},{"ancestorTitles":["outbound-tracker","computeUniversalTxId"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"outbound-tracker computeUniversalTxId should return a 0x-prefixed keccak256 hash","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should return a 0x-prefixed keccak256 hash"},{"ancestorTitles":["outbound-tracker","computeUniversalTxId"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"outbound-tracker computeUniversalTxId should produce deterministic output for same inputs","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should produce deterministic output for same inputs"},{"ancestorTitles":["outbound-tracker","computeUniversalTxId"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"outbound-tracker computeUniversalTxId should produce different output for different tx hashes","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should produce different output for different tx hashes"},{"ancestorTitles":["outbound-tracker","computeUniversalTxId"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"outbound-tracker computeUniversalTxId should produce different output for different networks","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should produce different output for different networks"},{"ancestorTitles":["outbound-tracker","computeUniversalTxId"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"outbound-tracker computeUniversalTxId should incorporate the push chain chainId in the hash input","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should incorporate the push chain chainId in the hash input"},{"ancestorTitles":["outbound-tracker","computeUniversalTxId"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"outbound-tracker computeUniversalTxId should handle empty tx hash","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should handle empty tx hash"},{"ancestorTitles":["outbound-tracker","extractAllUniversalSubTxIds"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"outbound-tracker extractAllUniversalSubTxIds should return sub-tx IDs from outbound_created events","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return sub-tx IDs from outbound_created events"},{"ancestorTitles":["outbound-tracker","extractAllUniversalSubTxIds"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"outbound-tracker extractAllUniversalSubTxIds should prefix values that lack 0x","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should prefix values that lack 0x"},{"ancestorTitles":["outbound-tracker","extractAllUniversalSubTxIds"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"outbound-tracker extractAllUniversalSubTxIds should collect multiple sub-tx IDs from multiple events","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should collect multiple sub-tx IDs from multiple events"},{"ancestorTitles":["outbound-tracker","extractAllUniversalSubTxIds"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"outbound-tracker extractAllUniversalSubTxIds should ignore events that are not outbound_created","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should ignore events that are not outbound_created"},{"ancestorTitles":["outbound-tracker","extractAllUniversalSubTxIds"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"outbound-tracker extractAllUniversalSubTxIds should skip outbound_created events without utx_id attribute","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should skip outbound_created events without utx_id attribute"},{"ancestorTitles":["outbound-tracker","extractAllUniversalSubTxIds"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"outbound-tracker extractAllUniversalSubTxIds should return empty array when Cosmos tx has no events","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return empty array when Cosmos tx has no events"},{"ancestorTitles":["outbound-tracker","extractAllUniversalSubTxIds"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"outbound-tracker extractAllUniversalSubTxIds should return empty array when Cosmos tx is null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return empty array when Cosmos tx is null"},{"ancestorTitles":["outbound-tracker","extractAllUniversalSubTxIds"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"outbound-tracker extractAllUniversalSubTxIds should return empty array when getCosmosTx throws","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return empty array when getCosmosTx throws"},{"ancestorTitles":["outbound-tracker","extractAllUniversalSubTxIds"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"outbound-tracker extractAllUniversalSubTxIds should skip utx_id attributes with empty value","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should skip utx_id attributes with empty value"},{"ancestorTitles":["outbound-tracker","extractAllUniversalSubTxIds"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"outbound-tracker extractAllUniversalSubTxIds should return empty array when events array is empty","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return empty array when events array is empty"},{"ancestorTitles":["outbound-tracker","extractUniversalSubTxIdFromTx"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"outbound-tracker extractUniversalSubTxIdFromTx should return the first sub-tx ID","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return the first sub-tx ID"},{"ancestorTitles":["outbound-tracker","extractUniversalSubTxIdFromTx"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"outbound-tracker extractUniversalSubTxIdFromTx should return null when no sub-tx IDs are found","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return null when no sub-tx IDs are found"},{"ancestorTitles":["outbound-tracker","extractUniversalSubTxIdFromTx"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"outbound-tracker extractUniversalSubTxIdFromTx should return null when getCosmosTx throws","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return null when getCosmosTx throws"}],"endTime":1792494875908,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/context-helpers-tracker.spec.ts","startTime":1792494875766,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["classifyIntoSegments"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"classifyIntoSegments should return empty array for empty hops","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return empty array for empty hops"},{"ancestorTitles":["classifyIntoSegments"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"classifyIntoSegments should create single PUSH_EXECUTION segment for one Route 1 hop","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"should create single PUSH_EXECUTION segment for one Route 1 hop"},{"ancestorTitles":["classifyIntoSegments"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"classifyIntoSegments should merge consecutive Route 1 hops into single PUSH_EXECUTION segment","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"should merge consecutive Route 1 hops into single PUSH_EXECUTION segment"},{"ancestorTitles":["classifyIntoSegments"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"classifyIntoSegments should create single OUTBOUND_TO_CEA segment for one Route 2 hop","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"should create single OUTBOUND_TO_CEA segment for one Route 2 hop"},{"ancestorTitles":["classifyIntoSegments"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"classifyIntoSegments should merge consecutive Route 2 hops to same chain","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"should merge consecutive Route 2 hops to same chain"},{"ancestorTitles":["classifyIntoSegments"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"classifyIntoSegments should NOT merge Route 2 hops targeting different chains","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"should NOT merge Route 2 hops targeting different chains"},{"ancestorTitles":["classifyIntoSegments"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"classifyIntoSegments should create INBOUND_FROM_CEA segment for Route 3 hop","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should create INBOUND_FROM_CEA segment for Route 3 hop"},{"ancestorTitles":["classifyIntoSegments"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"classifyIntoSegments should merge consecutive Route 3 hops from the same source chain into one INBOUND_FROM_CEA segment","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"should merge consecutive Route 3 hops from the same source chain into one INBOUND_FROM_CEA segment"},{"ancestorTitles":["classifyIntoSegments"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"classifyIntoSegments should NOT merge Route 3 hops from different source chains","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"should NOT merge Route 3 hops from different source chains"},{"ancestorTitles":["classifyIntoSegments"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"classifyIntoSegments should handle mixed routes: Route 1 -> Route 2 -> Route 3","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"should handle mixed routes: Route 1 -> Route 2 -> Route 3"},{"ancestorTitles":["classifyIntoSegments"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"classifyIntoSegments should keep gasLimit as max across merged hops","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should keep gasLimit as max across merged hops"},{"ancestorTitles":["classifyIntoSegments"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"classifyIntoSegments should sum non-zero maxPCForGas caps across merged outbound hops","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should sum non-zero maxPCForGas caps across merged outbound hops"},{"ancestorTitles":["classifyIntoSegments"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"classifyIntoSegments should keep merged outbound cap uncapped when any hop is uncapped","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should keep merged outbound cap uncapped when any hop is uncapped"},{"ancestorTitles":["classifyIntoSegments"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"classifyIntoSegments should retain quoted gasPrice on outbound segments","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should retain quoted gasPrice on outbound segments"},{"ancestorTitles":["classifyIntoSegments"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"classifyIntoSegments should keep the highest gasPrice across merged outbound hops","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should keep the highest gasPrice across merged outbound hops"},{"ancestorTitles":["composeCascadeDetailed"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"composeCascadeDetailed keeps the quoted gasPrice on immediate outbound requests","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"keeps the quoted gasPrice on immediate outbound requests"},{"ancestorTitles":["composeCascadeDetailed"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"composeCascadeDetailed uses live gas price resolution for Route 3 source-chain outbounds","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"uses live gas price resolution for Route 3 source-chain outbounds"},{"ancestorTitles":["composeCascadeDetailed"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"composeCascadeDetailed uses pool-quoted native value for SVM Route 3 inbound cascade outbounds","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"uses pool-quoted native value for SVM Route 3 inbound cascade outbounds"},{"ancestorTitles":["composeCascadeDetailed"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"composeCascadeDetailed uses pool-quoted native value for EVM cascade outbounds instead of flat balance split","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"uses pool-quoted native value for EVM cascade outbounds instead of flat balance split"},{"ancestorTitles":["composeCascadeDetailed"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"composeCascadeDetailed uses the live EVM pool quote for Route 3 wrapper gas instead of the flat split","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"uses the live EVM pool quote for Route 3 wrapper gas instead of the flat split"},{"ancestorTitles":["composeCascadeDetailed"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"composeCascadeDetailed always forwards a funds-only EVM PC20 import inside the inbound payload","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"always forwards a funds-only EVM PC20 import inside the inbound payload"},{"ancestorTitles":["composeCascadeDetailed"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"composeCascadeDetailed always forwards a funds-only SVM PC20 import with the dedicated burn instruction","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"always forwards a funds-only SVM PC20 import with the dedicated burn instruction"},{"ancestorTitles":["composeCascadeDetailed"],"duration":6,"failureDetails":[],"failureMessages":[],"fullName":"composeCascadeDetailed rejects oversized SVM Route 3 cascade payloads before broadcast","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects oversized SVM Route 3 cascade payloads before broadcast"}],"endTime":1792494876057,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/cascade-composition.spec.ts","startTime":1792494875911,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":[],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"an agent alone produces typed, locally complete DEXES rules on all catalog chains","invocations":1,"location":null,"numPassingAsserts":34,"retryReasons":[],"status":"passed","title":"an agent alone produces typed, locally complete DEXES rules on all catalog chains"},{"ancestorTitles":[],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"an agent alone produces typed, locally complete LENDING rules on all catalog chains","invocations":1,"location":null,"numPassingAsserts":34,"retryReasons":[],"status":"passed","title":"an agent alone produces typed, locally complete LENDING rules on all catalog chains"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"an agent alone produces typed, locally complete STAKING rules on all catalog chains","invocations":1,"location":null,"numPassingAsserts":10,"retryReasons":[],"status":"passed","title":"an agent alone produces typed, locally complete STAKING rules on all catalog chains"},{"ancestorTitles":[],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"generates one expiry seven days from this get call, refreshing on the next call","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"generates one expiry seven days from this get call, refreshing on the next call"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"uses verified raw-unit limits for stablecoins with different decimals","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"uses verified raw-unit limits for stablecoins with different decimals"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"uses token quantities for native, wrapped-native and LINK defaults","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"uses token quantities for native, wrapped-native and LINK defaults"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"preserves explicit expiry and gas, including a zero gas ceiling","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"preserves explicit expiry and gas, including a zero gas ceiling"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"never invents caps for explicit assets, even when their address is a default","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"never invents caps for explicit assets, even when their address is a default"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"does not grant the default tokens on a different chain when assets is explicit","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"does not grant the default tokens on a different chain when assets is explicit"},{"ancestorTitles":[],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"refuses unreviewed default tokens instead of inferring permissions from symbols","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"refuses unreviewed default tokens instead of inferring permissions from symbols"}],"endTime":1792494876424,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/preset-default-policy.spec.ts","startTime":1792494876059,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":[],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"ships verified mainnet and testnet templates and keeps prediction empty","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"ships verified mainnet and testnet templates and keeps prediction empty"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"groups apps on a chain into one editable template with default expiry and omitted identity","invocations":1,"location":null,"numPassingAsserts":9,"retryReasons":[],"status":"passed","title":"groups apps on a chain into one editable template with default expiry and omitted identity"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"returns ready Rule types with identity and expiry; routes assets and defaults missing caps to zero","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"returns ready Rule types with identity and expiry; routes assets and defaults missing caps to zero"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"does not type an incomplete template as a ready rule","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"does not type an incomplete template as a ready rule"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"adds only spender-pinned and amount-bounded ERC20 approvals; native assets have none","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"adds only spender-pinned and amount-bounded ERC20 approvals; native assets have none"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"does not mutate caller assets, returned records, or the bundled catalog","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"does not mutate caller assets, returned records, or the bundled catalog"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"rejects malformed or mismatched options before returning templates (case 0)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects malformed or mismatched options before returning templates (case 0)"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"rejects malformed or mismatched options before returning templates (case 1)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects malformed or mismatched options before returning templates (case 1)"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"rejects malformed or mismatched options before returning templates (case 2)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects malformed or mismatched options before returning templates (case 2)"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"rejects malformed or mismatched options before returning templates (case 3)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects malformed or mismatched options before returning templates (case 3)"},{"ancestorTitles":[],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"rejects malformed or mismatched options before returning templates (case 4)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects malformed or mismatched options before returning templates (case 4)"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"rejects malformed or mismatched options before returning templates (case 5)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects malformed or mismatched options before returning templates (case 5)"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"rejects malformed or mismatched options before returning templates (case 6)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects malformed or mismatched options before returning templates (case 6)"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"rejects malformed or mismatched options before returning templates (case 7)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects malformed or mismatched options before returning templates (case 7)"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"rejects malformed or mismatched options before returning templates (case 8)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects malformed or mismatched options before returning templates (case 8)"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"rejects unknown presets, unsupported list types and unsupported chain filters","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"rejects unknown presets, unsupported list types and unsupported chain filters"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"produces separate pinned alternatives for multiple spenders","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"produces separate pinned alternatives for multiple spenders"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"enforces the 32-call ceiling including generated approvals","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"enforces the 32-call ceiling including generated approvals"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"requires full signatures and rejects duplicate function entries","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"requires full signatures and rejects duplicate function entries"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"compiles preset spender and amount pins with the deployed v6 policy","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"compiles preset spender and amount pins with the deployed v6 policy"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"keeps OR alternatives EVM-only: repeated Solana instructions are refused","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"keeps OR alternatives EVM-only: repeated Solana instructions are refused"}],"endTime":1792494876707,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/presets.spec.ts","startTime":1792494876426,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["resolveWrapperToSource"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveWrapperToSource resolves a registered wrapper to its Push source","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"resolves a registered wrapper to its Push source"},{"ancestorTitles":["resolveWrapperToSource"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"resolveWrapperToSource rejects an unknown wrapper","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects an unknown wrapper"},{"ancestorTitles":["resolveWrapperToSource"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveWrapperToSource rejects when forward and reverse registry lookups disagree","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects when forward and reverse registry lookups disagree"},{"ancestorTitles":["resolveWrapperToSource"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveWrapperToSource rejects a wrapper that is not registered on the supplied chain","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects a wrapper that is not registered on the supplied chain"},{"ancestorTitles":["resolveWrapperToSource"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"resolveWrapperToSource caches positive results and does not re-read","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"caches positive results and does not re-read"},{"ancestorTitles":["resolveWrapperToSource"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveWrapperToSource can bypass a positive cache entry for prepared-transaction revalidation","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"can bypass a positive cache entry for prepared-transaction revalidation"},{"ancestorTitles":["resolveWrapperToSource"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"resolveWrapperToSource does not cache negative results","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"does not cache negative results"},{"ancestorTitles":["resolveWrapperToSource"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"resolveWrapperToSource stays within the cold round-trip budget","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"stays within the cold round-trip budget"},{"ancestorTitles":["resolveWrapperToSource"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveWrapperToSource stays within the warm round-trip budget","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"stays within the warm round-trip budget"},{"ancestorTitles":["readPushPC20Metadata"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"readPushPC20Metadata accepts a plain ERC-20 with standard metadata and no custom PC20 method","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"accepts a plain ERC-20 with standard metadata and no custom PC20 method"},{"ancestorTitles":["readPushPC20Metadata"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"readPushPC20Metadata rejects a token whose name() metadata read fails","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects a token whose name() metadata read fails"},{"ancestorTitles":["readPushPC20Metadata"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"readPushPC20Metadata rejects a token whose symbol() metadata read fails","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects a token whose symbol() metadata read fails"},{"ancestorTitles":["readPushPC20Metadata"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"readPushPC20Metadata rejects a token whose decimals() metadata read fails","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects a token whose decimals() metadata read fails"},{"ancestorTitles":["readPushPC20Metadata"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"readPushPC20Metadata rejects a token with no ERC-20 metadata surface","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects a token with no ERC-20 metadata surface"},{"ancestorTitles":["readPushPC20Metadata"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"readPushPC20Metadata rejects a metadata-compatible synthetic PRC20 with a distinct error","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"rejects a metadata-compatible synthetic PRC20 with a distinct error"},{"ancestorTitles":["readPushPC20Metadata"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"readPushPC20Metadata rejects empty name or symbol","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects empty name or symbol"},{"ancestorTitles":["readPushPC20Metadata"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"readPushPC20Metadata rejects decimals outside the uint8 range","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects decimals outside the uint8 range"},{"ancestorTitles":["readPushPC20Metadata"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"readPushPC20Metadata rejects an address with no deployed bytecode","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects an address with no deployed bytecode"},{"ancestorTitles":["listPC20Deployments"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"listPC20Deployments returns only confirmed deployments","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"returns only confirmed deployments"},{"ancestorTitles":["listPC20Deployments"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"listPC20Deployments issues exactly one batched round trip regardless of chain count","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"issues exactly one batched round trip regardless of chain count"},{"ancestorTitles":["listPC20Deployments"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"listPC20Deployments returns an empty list rather than throwing for a never-exported token","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"returns an empty list rather than throwing for a never-exported token"},{"ancestorTitles":["discoverPC20Chain"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"discoverPC20Chain short-circuits on a Push-native address without probing the registry","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"short-circuits on a Push-native address without probing the registry"},{"ancestorTitles":["discoverPC20Chain"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"discoverPC20Chain finds the chain a wrapper is registered on","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"finds the chain a wrapper is registered on"},{"ancestorTitles":["discoverPC20Chain"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"discoverPC20Chain returns null when no chain claims the address","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"returns null when no chain claims the address"},{"ancestorTitles":["discoverPC20Chain"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"discoverPC20Chain accepts the same address on several chains when they agree","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"accepts the same address on several chains when they agree"},{"ancestorTitles":["discoverPC20Chain"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"discoverPC20Chain throws rather than guessing when chains disagree on the source","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"throws rather than guessing when chains disagree on the source"},{"ancestorTitles":["discoverPC20Chain"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"discoverPC20Chain narrows by address format so a hex address never probes SVM chains","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"narrows by address format so a hex address never probes SVM chains"},{"ancestorTitles":["resolvePC20Token"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolvePC20Token resolves an external wrapper as an import","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"resolves an external wrapper as an import"},{"ancestorTitles":["resolvePC20Token"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolvePC20Token resolves a Push-native token as an export","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"resolves a Push-native token as an export"},{"ancestorTitles":["resolvePC20Token"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolvePC20Token never infers identity from symbol","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"never infers identity from symbol"}],"endTime":1792494876853,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/pc20/__tests__/resolver.spec.ts","startTime":1792494876709,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["SVM metadata and resolved instruction backend"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"SVM metadata and resolved instruction backend validates explicit wire accounts for dataless instructions","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"validates explicit wire accounts for dataless instructions"},{"ancestorTitles":["SVM metadata and resolved instruction backend"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"SVM metadata and resolved instruction backend validates explicit wire accounts for non-anchor instructions","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"validates explicit wire accounts for non-anchor instructions"},{"ancestorTitles":["SVM metadata and resolved instruction backend"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"SVM metadata and resolved instruction backend validates explicit wire accounts for wrong-account instructions","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"validates explicit wire accounts for wrong-account instructions"},{"ancestorTitles":["SVM metadata and resolved instruction backend"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"SVM metadata and resolved instruction backend resolves output mint Token-2022 ownership, rejecting a wrong supplied program: false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"resolves output mint Token-2022 ownership, rejecting a wrong supplied program: false"},{"ancestorTitles":["SVM metadata and resolved instruction backend"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"SVM metadata and resolved instruction backend resolves output mint Token-2022 ownership, rejecting a wrong supplied program: true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"resolves output mint Token-2022 ownership, rejecting a wrong supplied program: true"},{"ancestorTitles":["SVM metadata and resolved instruction backend"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"SVM metadata and resolved instruction backend reads initialized mint owner TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA length 82","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"reads initialized mint owner TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA length 82"},{"ancestorTitles":["SVM metadata and resolved instruction backend"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"SVM metadata and resolved instruction backend reads initialized mint owner TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb length 82","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"reads initialized mint owner TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb length 82"},{"ancestorTitles":["SVM metadata and resolved instruction backend"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"SVM metadata and resolved instruction backend reads initialized mint owner TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb length 166","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"reads initialized mint owner TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb length 166"},{"ancestorTitles":["SVM metadata and resolved instruction backend"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"SVM metadata and resolved instruction backend rejects wrong cluster RPCs and falls back to the configured correct cluster","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"rejects wrong cluster RPCs and falls back to the configured correct cluster"},{"ancestorTitles":["SVM metadata and resolved instruction backend"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"SVM metadata and resolved instruction backend rejects missing as a mint","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects missing as a mint"},{"ancestorTitles":["SVM metadata and resolved instruction backend"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"SVM metadata and resolved instruction backend rejects executable as a mint","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects executable as a mint"},{"ancestorTitles":["SVM metadata and resolved instruction backend"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"SVM metadata and resolved instruction backend rejects token-account as a mint","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects token-account as a mint"},{"ancestorTitles":["SVM metadata and resolved instruction backend"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"SVM metadata and resolved instruction backend rejects uninitialized as a mint","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects uninitialized as a mint"},{"ancestorTitles":["SVM metadata and resolved instruction backend"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"SVM metadata and resolved instruction backend rejects wrong-owner as a mint","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects wrong-owner as a mint"},{"ancestorTitles":["SVM metadata and resolved instruction backend"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"SVM metadata and resolved instruction backend requires a configured gateway/RPC, rather than choosing a devnet default","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"requires a configured gateway/RPC, rather than choosing a devnet default"},{"ancestorTitles":["SVM metadata and resolved instruction backend"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"SVM metadata and resolved instruction backend pins all PRC20 reads and rejects a source-chain mismatch","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"pins all PRC20 reads and rejects a source-chain mismatch"},{"ancestorTitles":["SVM metadata and resolved instruction backend"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"SVM metadata and resolved instruction backend rejects registry and mint substitution","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"rejects registry and mint substitution"},{"ancestorTitles":["SVM metadata and resolved instruction backend"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"SVM metadata and resolved instruction backend derives the wallet authority for IDL accounts, not the signer/default gateway authority","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"derives the wallet authority for IDL accounts, not the signer/default gateway authority"}],"endTime":1792494877140,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/svm-backend.spec.ts","startTime":1792494876856,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["scenario S-A — INBOUND_FROM_EOA — Sepolia EOA sends FUNDS"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"scenario S-A — INBOUND_FROM_EOA — Sepolia EOA sends FUNDS classify() picks the expected primary kind","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"classify() picks the expected primary kind"},{"ancestorTitles":["scenario S-A — INBOUND_FROM_EOA — Sepolia EOA sends FUNDS"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"scenario S-A — INBOUND_FROM_EOA — Sepolia EOA sends FUNDS classifyAll() yields the expected per-log kinds","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"classifyAll() yields the expected per-log kinds"},{"ancestorTitles":["scenario S-A — INBOUND_FROM_EOA — Sepolia EOA sends FUNDS"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"scenario S-A — INBOUND_FROM_EOA — Sepolia EOA sends FUNDS classify() decodes expected identifiers","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"classify() decodes expected identifiers"},{"ancestorTitles":["scenario S-C — INBOUND_FROM_CEA — Sepolia CEA round-trip"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"scenario S-C — INBOUND_FROM_CEA — Sepolia CEA round-trip classify() picks the expected primary kind","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"classify() picks the expected primary kind"},{"ancestorTitles":["scenario S-C — INBOUND_FROM_CEA — Sepolia CEA round-trip"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"scenario S-C — INBOUND_FROM_CEA — Sepolia CEA round-trip classifyAll() yields the expected per-log kinds","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"classifyAll() yields the expected per-log kinds"},{"ancestorTitles":["scenario S-C — INBOUND_FROM_CEA — Sepolia CEA round-trip"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"scenario S-C — INBOUND_FROM_CEA — Sepolia CEA round-trip classify() decodes expected identifiers","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"classify() decodes expected identifiers"},{"ancestorTitles":["scenario S-D — OUTBOUND_INITIATED — Push root with one OBSERVED outbound to BSC"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"scenario S-D — OUTBOUND_INITIATED — Push root with one OBSERVED outbound to BSC classify() picks the expected primary kind","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"classify() picks the expected primary kind"},{"ancestorTitles":["scenario S-D — OUTBOUND_INITIATED — Push root with one OBSERVED outbound to BSC"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"scenario S-D — OUTBOUND_INITIATED — Push root with one OBSERVED outbound to BSC classifyAll() yields the expected per-log kinds","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"classifyAll() yields the expected per-log kinds"},{"ancestorTitles":["scenario S-D — OUTBOUND_INITIATED — Push root with one OBSERVED outbound to BSC"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"scenario S-D — OUTBOUND_INITIATED — Push root with one OBSERVED outbound to BSC classify() decodes expected identifiers","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"classify() decodes expected identifiers"},{"ancestorTitles":["scenario S-E — OUTBOUND_FINALIZED — Sepolia Vault finalize"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"scenario S-E — OUTBOUND_FINALIZED — Sepolia Vault finalize classify() picks the expected primary kind","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"classify() picks the expected primary kind"},{"ancestorTitles":["scenario S-E — OUTBOUND_FINALIZED — Sepolia Vault finalize"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"scenario S-E — OUTBOUND_FINALIZED — Sepolia Vault finalize classifyAll() yields the expected per-log kinds","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"classifyAll() yields the expected per-log kinds"},{"ancestorTitles":["scenario S-E — OUTBOUND_FINALIZED — Sepolia Vault finalize"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"scenario S-E — OUTBOUND_FINALIZED — Sepolia Vault finalize classify() decodes expected identifiers","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"classify() decodes expected identifiers"},{"ancestorTitles":["scenario S-F — OUTBOUND_REVERTED — BSC Vault emitted UniversalTxReverted"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"scenario S-F — OUTBOUND_REVERTED — BSC Vault emitted UniversalTxReverted classify() picks the expected primary kind","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"classify() picks the expected primary kind"},{"ancestorTitles":["scenario S-F — OUTBOUND_REVERTED — BSC Vault emitted UniversalTxReverted"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"scenario S-F — OUTBOUND_REVERTED — BSC Vault emitted UniversalTxReverted classifyAll() yields the expected per-log kinds","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"classifyAll() yields the expected per-log kinds"},{"ancestorTitles":["scenario S-F — OUTBOUND_REVERTED — BSC Vault emitted UniversalTxReverted"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"scenario S-F — OUTBOUND_REVERTED — BSC Vault emitted UniversalTxReverted classify() decodes expected identifiers","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"classify() decodes expected identifiers"},{"ancestorTitles":["scenario S-G — INBOUND_REVERTED — Sepolia RevertUniversalTx"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"scenario S-G — INBOUND_REVERTED — Sepolia RevertUniversalTx classify() picks the expected primary kind","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"classify() picks the expected primary kind"},{"ancestorTitles":["scenario S-G — INBOUND_REVERTED — Sepolia RevertUniversalTx"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"scenario S-G — INBOUND_REVERTED — Sepolia RevertUniversalTx classifyAll() yields the expected per-log kinds","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"classifyAll() yields the expected per-log kinds"},{"ancestorTitles":["scenario S-G — INBOUND_REVERTED — Sepolia RevertUniversalTx"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"scenario S-G — INBOUND_REVERTED — Sepolia RevertUniversalTx classify() decodes expected identifiers","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"classify() decodes expected identifiers"},{"ancestorTitles":["scenario S-H — EXECUTED_ON_DEST — Destination payload executed"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"scenario S-H — EXECUTED_ON_DEST — Destination payload executed classify() picks the expected primary kind","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"classify() picks the expected primary kind"},{"ancestorTitles":["scenario S-H — EXECUTED_ON_DEST — Destination payload executed"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"scenario S-H — EXECUTED_ON_DEST — Destination payload executed classifyAll() yields the expected per-log kinds","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"classifyAll() yields the expected per-log kinds"},{"ancestorTitles":["scenario S-H — EXECUTED_ON_DEST — Destination payload executed"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"scenario S-H — EXECUTED_ON_DEST — Destination payload executed classify() decodes expected identifiers","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"classify() decodes expected identifiers"},{"ancestorTitles":["scenario S-I — RESCUED_FUNDS — Vault-side FundsRescued"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"scenario S-I — RESCUED_FUNDS — Vault-side FundsRescued classify() picks the expected primary kind","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"classify() picks the expected primary kind"},{"ancestorTitles":["scenario S-I — RESCUED_FUNDS — Vault-side FundsRescued"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"scenario S-I — RESCUED_FUNDS — Vault-side FundsRescued classifyAll() yields the expected per-log kinds","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"classifyAll() yields the expected per-log kinds"},{"ancestorTitles":["scenario S-I — RESCUED_FUNDS — Vault-side FundsRescued"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"scenario S-I — RESCUED_FUNDS — Vault-side FundsRescued classify() decodes expected identifiers","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"classify() decodes expected identifiers"},{"ancestorTitles":["scenario S-J — UNKNOWN — receipt with no universal-tx events"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"scenario S-J — UNKNOWN — receipt with no universal-tx events classify() picks the expected primary kind","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"classify() picks the expected primary kind"},{"ancestorTitles":["scenario S-J — UNKNOWN — receipt with no universal-tx events"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"scenario S-J — UNKNOWN — receipt with no universal-tx events classifyAll() yields the expected per-log kinds","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"classifyAll() yields the expected per-log kinds"},{"ancestorTitles":["scenario S-K — PENDING outbound — Push root, outbound not yet observed"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"scenario S-K — PENDING outbound — Push root, outbound not yet observed classify() picks the expected primary kind","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"classify() picks the expected primary kind"},{"ancestorTitles":["scenario S-L — UNKNOWN + no utx record — cascade root resolves with zero children"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"scenario S-L — UNKNOWN + no utx record — cascade root resolves with zero children classify() picks the expected primary kind","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"classify() picks the expected primary kind"},{"ancestorTitles":["scenario S-L — UNKNOWN + no utx record — cascade root resolves with zero children"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"scenario S-L — UNKNOWN + no utx record — cascade root resolves with zero children classifyAll() yields the expected per-log kinds","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"classifyAll() yields the expected per-log kinds"},{"ancestorTitles":["scenario S-M — Mixed-destination fan-out — BSC + Sepolia + Solana"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"scenario S-M — Mixed-destination fan-out — BSC + Sepolia + Solana classify() picks the expected primary kind","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"classify() picks the expected primary kind"},{"ancestorTitles":["scenario S-N — Fan-out delivered + reverted — dual pc-refund/pc-revert edges"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"scenario S-N — Fan-out delivered + reverted — dual pc-refund/pc-revert edges classify() picks the expected primary kind","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"classify() picks the expected primary kind"},{"ancestorTitles":["scenario S-O — SVM CEA payload-only self-call — GasAndPayload"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"scenario S-O — SVM CEA payload-only self-call — GasAndPayload classify() picks the expected primary kind","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"classify() picks the expected primary kind"},{"ancestorTitles":["scenario S-O — SVM CEA payload-only self-call — GasAndPayload"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"scenario S-O — SVM CEA payload-only self-call — GasAndPayload classifyAll() yields the expected per-log kinds","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"classifyAll() yields the expected per-log kinds"},{"ancestorTitles":["scenario S-O — SVM CEA payload-only self-call — GasAndPayload"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"scenario S-O — SVM CEA payload-only self-call — GasAndPayload classify() decodes expected identifiers","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"classify() decodes expected identifiers"},{"ancestorTitles":["cascade scenario S-D — OUTBOUND_INITIATED — Push root with one OBSERVED outbound to BSC"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"cascade scenario S-D — OUTBOUND_INITIATED — Push root with one OBSERVED outbound to BSC walker resolves expected shape","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"walker resolves expected shape"},{"ancestorTitles":["cascade scenario S-K — PENDING outbound — Push root, outbound not yet observed"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"cascade scenario S-K — PENDING outbound — Push root, outbound not yet observed walker resolves expected shape","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"walker resolves expected shape"},{"ancestorTitles":["cascade scenario S-L — UNKNOWN + no utx record — cascade root resolves with zero children"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"cascade scenario S-L — UNKNOWN + no utx record — cascade root resolves with zero children walker resolves expected shape","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"walker resolves expected shape"},{"ancestorTitles":["cascade scenario S-M — Mixed-destination fan-out — BSC + Sepolia + Solana"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"cascade scenario S-M — Mixed-destination fan-out — BSC + Sepolia + Solana walker resolves expected shape","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"walker resolves expected shape"},{"ancestorTitles":["cascade scenario S-N — Fan-out delivered + reverted — dual pc-refund/pc-revert edges"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"cascade scenario S-N — Fan-out delivered + reverted — dual pc-refund/pc-revert edges walker resolves expected shape","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"walker resolves expected shape"}],"endTime":1792494877376,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/universal-tx-detector/__tests__/scenarios.spec.ts","startTime":1792494877146,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["svm-rent — derivations"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"svm-rent — derivations deriveSvmCeaPda is deterministic for a given EVM address","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"deriveSvmCeaPda is deterministic for a given EVM address"},{"ancestorTitles":["svm-rent — derivations"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"svm-rent — derivations deriveAtaPubkey matches the standard SPL ATA derivation","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"deriveAtaPubkey matches the standard SPL ATA derivation"},{"ancestorTitles":["getSvmFinalizeGasBudget"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"getSvmFinalizeGasBudget returns base finalize budget for native SOL / payload-only SVM outbounds","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"returns base finalize budget for native SOL / payload-only SVM outbounds"},{"ancestorTitles":["getSvmFinalizeGasBudget"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"getSvmFinalizeGasBudget includes CEA ATA rent when an SPL outbound ATA does not exist yet","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"includes CEA ATA rent when an SPL outbound ATA does not exist yet"},{"ancestorTitles":["getSvmFinalizeGasBudget"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"getSvmFinalizeGasBudget does not include CEA ATA rent when the SPL outbound ATA already exists","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"does not include CEA ATA rent when the SPL outbound ATA already exists"},{"ancestorTitles":["getSvmFinalizeGasBudget"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"getSvmFinalizeGasBudget falls back to protocol rent constants on RPC failure","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"falls back to protocol rent constants on RPC failure"},{"ancestorTitles":["getSvmFinalizeGasBudget"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"getSvmFinalizeGasBudget rounds required gas fee up to the next whole gasLimit unit","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rounds required gas fee up to the next whole gasLimit unit"},{"ancestorTitles":["maybeBumpForCeaAtaRent"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"maybeBumpForCeaAtaRent returns input unchanged when burnAmount is 0 (native SOL outbound)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"returns input unchanged when burnAmount is 0 (native SOL outbound)"},{"ancestorTitles":["maybeBumpForCeaAtaRent"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"maybeBumpForCeaAtaRent returns input unchanged when splMintBase58 is undefined","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"returns input unchanged when splMintBase58 is undefined"},{"ancestorTitles":["maybeBumpForCeaAtaRent"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"maybeBumpForCeaAtaRent bumps effectiveGasLimit by CEA_ATA_RENT_LAMPORTS_BUMP when ATA does not exist","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"bumps effectiveGasLimit by CEA_ATA_RENT_LAMPORTS_BUMP when ATA does not exist"},{"ancestorTitles":["maybeBumpForCeaAtaRent"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"maybeBumpForCeaAtaRent does not bump when ATA already exists with non-empty data","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"does not bump when ATA already exists with non-empty data"},{"ancestorTitles":["maybeBumpForCeaAtaRent"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"maybeBumpForCeaAtaRent returns input unchanged on RPC failure (logs warning, does not throw)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"returns input unchanged on RPC failure (logs warning, does not throw)"},{"ancestorTitles":["maybeBumpForCeaAtaRent"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"maybeBumpForCeaAtaRent falls back to CHAIN_INFO defaultRPC when ctx.rpcUrls is empty","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"falls back to CHAIN_INFO defaultRPC when ctx.rpcUrls is empty"},{"ancestorTitles":["maybeBumpForCeaAtaRent"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"maybeBumpForCeaAtaRent CEA_ATA_RENT_LAMPORTS_BUMP equals 3_090_840 (gateway finalize budget with ATA)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"CEA_ATA_RENT_LAMPORTS_BUMP equals 3_090_840 (gateway finalize budget with ATA)"}],"endTime":1792494877511,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/svm-rent.spec.ts","startTime":1792494877380,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["buildPayloadForRoute — EVM Route 3 native Push EOA"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"buildPayloadForRoute — EVM Route 3 native Push EOA uses the supplied native-EOA nonce without probing delegated code","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"uses the supplied native-EOA nonce without probing delegated code"},{"ancestorTitles":["floorR3NativeValueForGas"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"floorR3NativeValueForGas raises the USD-sized value to the live buffered pool requirement","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"raises the USD-sized value to the live buffered pool requirement"},{"ancestorTitles":["floorR3NativeValueForGas"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"floorR3NativeValueForGas preserves a larger category value and includes native protocol fees","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"preserves a larger category value and includes native protocol fees"}],"endTime":1792494877645,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/route-handlers-evm-r3-native-eoa.spec.ts","startTime":1792494877513,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["toGatewayRequestV1"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toGatewayRequestV1 should flatten revertInstruction to revertRecipient","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should flatten revertInstruction to revertRecipient"},{"ancestorTitles":["toGatewayRequestV1"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"toGatewayRequestV1 should preserve recipient, token, amount, payload, signatureData","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"should preserve recipient, token, amount, payload, signatureData"},{"ancestorTitles":["toGatewayRequestV1"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toGatewayRequestV1 should produce exactly 6 keys in the V1 output","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should produce exactly 6 keys in the V1 output"},{"ancestorTitles":["toGatewayRequestV1"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toGatewayRequestV1 should handle zero amount","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should handle zero amount"},{"ancestorTitles":["toGatewayRequestV1"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toGatewayRequestV1 should handle empty payload","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should handle empty payload"},{"ancestorTitles":["toGatewayTokenRequestV1"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toGatewayTokenRequestV1 should flatten revertInstruction to revertRecipient","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should flatten revertInstruction to revertRecipient"},{"ancestorTitles":["toGatewayTokenRequestV1"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toGatewayTokenRequestV1 should preserve all token-specific fields","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"should preserve all token-specific fields"},{"ancestorTitles":["toGatewayTokenRequestV1"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toGatewayTokenRequestV1 should preserve base fields","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"should preserve base fields"},{"ancestorTitles":["toGatewayTokenRequestV1"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toGatewayTokenRequestV1 should produce exactly 10 keys in the V1 output","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should produce exactly 10 keys in the V1 output"},{"ancestorTitles":["toGatewayTokenRequestV1"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toGatewayTokenRequestV1 should handle zero gasAmount and amountOutMinETH","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should handle zero gasAmount and amountOutMinETH"},{"ancestorTitles":["computeUEAOffchain"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"computeUEAOffchain should return a 0x-prefixed address for EVM signer","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should return a 0x-prefixed address for EVM signer"},{"ancestorTitles":["computeUEAOffchain"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"computeUEAOffchain should produce deterministic output for same inputs","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should produce deterministic output for same inputs"},{"ancestorTitles":["computeUEAOffchain"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"computeUEAOffchain should produce different addresses for different signer addresses","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should produce different addresses for different signer addresses"},{"ancestorTitles":["computeUEAOffchain"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"computeUEAOffchain should produce different addresses for different chains","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should produce different addresses for different chains"},{"ancestorTitles":["computeUEAOffchain"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"computeUEAOffchain should return the raw signer address for Push Chain","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return the raw signer address for Push Chain"},{"ancestorTitles":["computeUEAOffchain"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"computeUEAOffchain should use the UEA_PROXY for the current pushNetwork in minimal proxy code","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should use the UEA_PROXY for the current pushNetwork in minimal proxy code"},{"ancestorTitles":["getUeaNonceForExecution"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"getUeaNonceForExecution should not probe EIP-7702 delegation code for a native Push EOA","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should not probe EIP-7702 delegation code for a native Push EOA"},{"ancestorTitles":["getUeaNonceForExecution"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"getUeaNonceForExecution should return 0 when UEA is not deployed (no code)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return 0 when UEA is not deployed (no code)"},{"ancestorTitles":["getUeaNonceForExecution"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"getUeaNonceForExecution should query nonce from contract when UEA is deployed","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should query nonce from contract when UEA is deployed"},{"ancestorTitles":["getUeaNonceForExecution"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"getUeaNonceForExecution should call getCode with the computed UEA address","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should call getCode with the computed UEA address"},{"ancestorTitles":["getUeaNonceForExecution"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"getUeaNonceForExecution should call readContract with nonce function when deployed","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should call readContract with nonce function when deployed"},{"ancestorTitles":["getUeaStatusAndNonce"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"getUeaStatusAndNonce should classify an EIP-7702 delegated native Push account as an EOA","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should classify an EIP-7702 delegated native Push account as an EOA"},{"ancestorTitles":["getUeaStatusAndNonce"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"getUeaStatusAndNonce should return deployed=false, nonce=0 when no code exists","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should return deployed=false, nonce=0 when no code exists"},{"ancestorTitles":["getUeaStatusAndNonce"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"getUeaStatusAndNonce should return deployed=true with on-chain nonce when code exists","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should return deployed=true with on-chain nonce when code exists"},{"ancestorTitles":["getUeaStatusAndNonce"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"getUeaStatusAndNonce should not call readContract when UEA is not deployed","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should not call readContract when UEA is not deployed"},{"ancestorTitles":["getUEANonce"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"getUEANonce should use no UEA nonce for a native Push EOA","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should use no UEA nonce for a native Push EOA"},{"ancestorTitles":["getAccountStatus"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"getAccountStatus should skip UEA lifecycle checks for an EIP-7702 native Push EOA","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"should skip UEA lifecycle checks for an EIP-7702 native Push EOA"},{"ancestorTitles":["getAccountStatus"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"getAccountStatus should return cached status on second call","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"should return cached status on second call"},{"ancestorTitles":["getAccountStatus"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"getAccountStatus should bypass cache when forceRefresh is true","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should bypass cache when forceRefresh is true"},{"ancestorTitles":["getAccountStatus"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"getAccountStatus should set mode to signer","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should set mode to signer"},{"ancestorTitles":["getAccountStatus"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"getAccountStatus should return deployed=false with empty versions when UEA not deployed","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"should return deployed=false with empty versions when UEA not deployed"},{"ancestorTitles":["getAccountStatus"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"getAccountStatus should fetch versions when UEA is deployed","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"should fetch versions when UEA is deployed"},{"ancestorTitles":["getAccountStatus"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"getAccountStatus should set requiresUpgrade=false when versions match","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should set requiresUpgrade=false when versions match"},{"ancestorTitles":["getAccountStatus"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"getAccountStatus should persist status to ctx.accountStatusCache","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should persist status to ctx.accountStatusCache"},{"ancestorTitles":["fetchLatestUEAVersion"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"fetchLatestUEAVersion should call readContract with UEA_VERSION and keccak256 of VM string","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should call readContract with UEA_VERSION and keccak256 of VM string"},{"ancestorTitles":["fetchLatestUEAVersion"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"fetchLatestUEAVersion should return empty string when readContract throws","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return empty string when readContract throws"},{"ancestorTitles":["fetchLatestUEAVersion"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"fetchLatestUEAVersion should return empty string when factory address is 0xTBD","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should return empty string when factory address is 0xTBD"},{"ancestorTitles":["fetchLatestUEAVersion"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"fetchLatestUEAVersion should work for SVM vm type","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should work for SVM vm type"},{"ancestorTitles":["migrateCEA"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"migrateCEA should throw \"Cannot migrate CEA on Push Chain\" for Push Chain","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should throw \"Cannot migrate CEA on Push Chain\" for Push Chain"},{"ancestorTitles":["migrateCEA"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"migrateCEA should throw \"Cannot migrate CEA on Push Chain\" for Push Localnet","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should throw \"Cannot migrate CEA on Push Chain\" for Push Localnet"},{"ancestorTitles":["migrateCEA"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"migrateCEA should throw when chain does not support CEA","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should throw when chain does not support CEA"},{"ancestorTitles":["migrateCEA"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"migrateCEA should throw when CEA is not deployed on the target chain","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should throw when CEA is not deployed on the target chain"},{"ancestorTitles":["migrateCEA"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"migrateCEA should call executeFn with cea address and migration flag when valid","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should call executeFn with cea address and migration flag when valid"},{"ancestorTitles":["migrateCEA"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"migrateCEA should call getCEAAddress with computed UEA and chain","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should call getCEAAddress with computed UEA and chain"}],"endTime":1792494877787,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/gateway-uea-account.spec.ts","startTime":1792494877648,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["PC20 export payload"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"PC20 export payload starts with exactly the PC20 selector","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"starts with exactly the PC20 selector"},{"ancestorTitles":["PC20 export payload"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"PC20 export payload encodes the metadata tuple exactly","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"encodes the metadata tuple exactly"},{"ancestorTitles":["PC20 export payload"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PC20 export payload appends destination user data verbatim after the metadata","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"appends destination user data verbatim after the metadata"},{"ancestorTitles":["PC20 export payload"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PC20 export payload produces an identical payload when user data is empty or omitted","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"produces an identical payload when user data is empty or omitted"},{"ancestorTitles":["PC20 export payload"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"PC20 export payload rejects an unsupported destination chain","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects an unsupported destination chain"},{"ancestorTitles":["PC20 metadata factory limits"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PC20 metadata factory limits accepts metadata at the limit","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"accepts metadata at the limit"},{"ancestorTitles":["PC20 metadata factory limits"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PC20 metadata factory limits rejects an over-long name","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects an over-long name"},{"ancestorTitles":["PC20 metadata factory limits"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"PC20 metadata factory limits rejects an over-long symbol","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects an over-long symbol"},{"ancestorTitles":["PC20 metadata factory limits"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PC20 metadata factory limits measures bytes, not characters","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"measures bytes, not characters"},{"ancestorTitles":["PC20 metadata factory limits"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PC20 metadata factory limits rejects empty name or symbol","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"rejects empty name or symbol"},{"ancestorTitles":["PC20 metadata factory limits"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PC20 metadata factory limits pins the limits to the reference PC20Factory constants","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"pins the limits to the reference PC20Factory constants"},{"ancestorTitles":["PC20 export gas quote"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"PC20 export gas quote re-quotes and returns a destination gas limit that includes wrapper deployment","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"re-quotes and returns a destination gas limit that includes wrapper deployment"},{"ancestorTitles":["PC20 export gas quote"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PC20 export gas quote leaves Solana requoting to the rent and compute-budget path","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"leaves Solana requoting to the rent and compute-budget path"}],"endTime":1792494878045,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/pc20/__tests__/export.spec.ts","startTime":1792494877789,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["traceUniversalTxCascade"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"traceUniversalTxCascade builds cascade: Push root → (outbound → Sepolia → child-inbound → follow-up) + (pc-refund → Push refund)","invocations":1,"location":null,"numPassingAsserts":11,"retryReasons":[],"status":"passed","title":"builds cascade: Push root → (outbound → Sepolia → child-inbound → follow-up) + (pc-refund → Push refund)"},{"ancestorTitles":["traceUniversalTxCascade"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"traceUniversalTxCascade flattenCascade returns nodes depth-first","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"flattenCascade returns nodes depth-first"},{"ancestorTitles":["traceUniversalTxCascade"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"traceUniversalTxCascade respects maxDepth","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"respects maxDepth"},{"ancestorTitles":["traceUniversalTxCascade"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"traceUniversalTxCascade cycle-safe: revisiting a node does not recurse","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"cycle-safe: revisiting a node does not recurse"},{"ancestorTitles":["traceUniversalTxCascade"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"traceUniversalTxCascade onNode callback fires per resolved node","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"onNode callback fires per resolved node"}],"endTime":1792494878184,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/universal-tx-detector/__tests__/cascade.spec.ts","startTime":1792494878048,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["rescueFunds","universalTxId validation"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"rescueFunds universalTxId validation should reject empty string","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should reject empty string"},{"ancestorTitles":["rescueFunds","universalTxId validation"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"rescueFunds universalTxId validation should reject id without 0x prefix","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should reject id without 0x prefix"},{"ancestorTitles":["rescueFunds","universalTxId validation"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"rescueFunds universalTxId validation should reject id that is too short (< 66 chars)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should reject id that is too short (< 66 chars)"},{"ancestorTitles":["rescueFunds","universalTxId validation"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"rescueFunds universalTxId validation should reject id that is too long (> 66 chars)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should reject id that is too long (> 66 chars)"},{"ancestorTitles":["rescueFunds","universalTxId validation"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"rescueFunds universalTxId validation should reject id with non-hex characters","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should reject id with non-hex characters"},{"ancestorTitles":["rescueFunds","universalTxId validation"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"rescueFunds universalTxId validation should reject undefined/null universalTxId","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should reject undefined/null universalTxId"},{"ancestorTitles":["rescueFunds","prc20 validation"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"rescueFunds prc20 validation should reject zero address prc20","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should reject zero address prc20"},{"ancestorTitles":["rescueFunds","prc20 validation"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"rescueFunds prc20 validation should reject empty/undefined prc20","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should reject empty/undefined prc20"},{"ancestorTitles":["rescueFunds","gas fee query failure"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"rescueFunds gas fee query failure should propagate queryRescueGasFee errors","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should propagate queryRescueGasFee errors"},{"ancestorTitles":["rescueFunds","nativeValueForGas balance capping"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"rescueFunds nativeValueForGas balance capping should cap at EVM_NATIVE_VALUE_TARGET when balance > target + reserve","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should cap at EVM_NATIVE_VALUE_TARGET when balance > target + reserve"},{"ancestorTitles":["rescueFunds","nativeValueForGas balance capping"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"rescueFunds nativeValueForGas balance capping should use balance - reserve when balance <= target + reserve but > reserve","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should use balance - reserve when balance <= target + reserve but > reserve"},{"ancestorTitles":["rescueFunds","nativeValueForGas balance capping"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"rescueFunds nativeValueForGas balance capping should fall back to nativeValueForGas when balance <= reserve","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should fall back to nativeValueForGas when balance <= reserve"},{"ancestorTitles":["rescueFunds","ExecuteParams construction"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"rescueFunds ExecuteParams construction should call executeFn with correctly structured params","invocations":1,"location":null,"numPassingAsserts":10,"retryReasons":[],"status":"passed","title":"should call executeFn with correctly structured params"},{"ancestorTitles":["rescueFunds","ExecuteParams construction"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"rescueFunds ExecuteParams construction should set isDeployed=false and nonce=0 when UEA has no code","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should set isDeployed=false and nonce=0 when UEA has no code"},{"ancestorTitles":["rescueFunds","ExecuteParams construction"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"rescueFunds ExecuteParams construction should return the result of executeFn","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return the result of executeFn"},{"ancestorTitles":["buildSvmUniversalTxRequest"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildSvmUniversalTxRequest should convert hex payload (0x-prefixed) to Buffer","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"should convert hex payload (0x-prefixed) to Buffer"},{"ancestorTitles":["buildSvmUniversalTxRequest"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildSvmUniversalTxRequest should handle empty hex payload (0x)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should handle empty hex payload (0x)"},{"ancestorTitles":["buildSvmUniversalTxRequest"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildSvmUniversalTxRequest should handle odd-length hex payload by zero-padding","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"should handle odd-length hex payload by zero-padding"},{"ancestorTitles":["buildSvmUniversalTxRequest"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildSvmUniversalTxRequest should convert Uint8Array payload to Buffer","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should convert Uint8Array payload to Buffer"},{"ancestorTitles":["buildSvmUniversalTxRequest"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"buildSvmUniversalTxRequest should handle hex signatureData","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should handle hex signatureData"},{"ancestorTitles":["buildSvmUniversalTxRequest"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"buildSvmUniversalTxRequest should produce empty signatureData buffer when undefined","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should produce empty signatureData buffer when undefined"},{"ancestorTitles":["buildSvmUniversalTxRequest"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildSvmUniversalTxRequest should handle empty hex signatureData (0x)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should handle empty hex signatureData (0x)"},{"ancestorTitles":["buildSvmUniversalTxRequest"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildSvmUniversalTxRequest should handle Uint8Array signatureData","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should handle Uint8Array signatureData"},{"ancestorTitles":["buildSvmUniversalTxRequest"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildSvmUniversalTxRequest should pass through recipient, token, amount, revertRecipient","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"should pass through recipient, token, amount, revertRecipient"},{"ancestorTitles":["buildSvmUniversalTxRequestFromReq"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildSvmUniversalTxRequestFromReq should extract first 20 bytes of recipient as number array","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should extract first 20 bytes of recipient as number array"},{"ancestorTitles":["buildSvmUniversalTxRequestFromReq"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildSvmUniversalTxRequestFromReq should map zero address token to PublicKey.default","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should map zero address token to PublicKey.default"},{"ancestorTitles":["buildSvmUniversalTxRequestFromReq"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildSvmUniversalTxRequestFromReq should convert 0x-prefixed token to a 32-byte PublicKey (zero-padded at left)","invocations":1,"location":null,"numPassingAsserts":13,"retryReasons":[],"status":"passed","title":"should convert 0x-prefixed token to a 32-byte PublicKey (zero-padded at left)"},{"ancestorTitles":["buildSvmUniversalTxRequestFromReq"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"buildSvmUniversalTxRequestFromReq should throw for non-0x, non-special token format","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should throw for non-0x, non-special token format"},{"ancestorTitles":["buildSvmUniversalTxRequestFromReq"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildSvmUniversalTxRequestFromReq should use signatureDataOverride when provided","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should use signatureDataOverride when provided"},{"ancestorTitles":["getSvmGatewayLogIndexFromTx"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"getSvmGatewayLogIndexFromTx should return 0 when no logs exist","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"should return 0 when no logs exist"},{"ancestorTitles":["getSvmGatewayLogIndexFromTx"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"getSvmGatewayLogIndexFromTx should return 0 when no matching discriminator found","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return 0 when no matching discriminator found"},{"ancestorTitles":["getSvmGatewayLogIndexFromTx"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"getSvmGatewayLogIndexFromTx should return index of first match when only one match exists","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return index of first match when only one match exists"},{"ancestorTitles":["getSvmGatewayLogIndexFromTx"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"getSvmGatewayLogIndexFromTx should return index of second match when two matches exist","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return index of second match when two matches exist"},{"ancestorTitles":["getSvmGatewayLogIndexFromTx"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"getSvmGatewayLogIndexFromTx should ignore log lines without \"Program data: \" prefix","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should ignore log lines without \"Program data: \" prefix"},{"ancestorTitles":["getSvmGatewayLogIndexFromTx"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"getSvmGatewayLogIndexFromTx should skip entries with invalid base64","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should skip entries with invalid base64"},{"ancestorTitles":["getSvmGatewayLogIndexFromTx"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"getSvmGatewayLogIndexFromTx should skip entries where decoded data is less than 8 bytes","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should skip entries where decoded data is less than 8 bytes"},{"ancestorTitles":["waitForLockerFeeConfirmation"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"waitForLockerFeeConfirmation should dispatch to EVM path (construct EvmClient) for EVM chain","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should dispatch to EVM path (construct EvmClient) for EVM chain"},{"ancestorTitles":["waitForLockerFeeConfirmation"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"waitForLockerFeeConfirmation should dispatch to SVM path (construct SvmClient) for SVM chain","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should dispatch to SVM path (construct SvmClient) for SVM chain"},{"ancestorTitles":["waitForLockerFeeConfirmation"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"waitForLockerFeeConfirmation should use custom rpcUrls from context over defaults","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should use custom rpcUrls from context over defaults"},{"ancestorTitles":["waitForLockerFeeConfirmation"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"waitForLockerFeeConfirmation should throw for unsupported VM type","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should throw for unsupported VM type"},{"ancestorTitles":["waitForEvmConfirmationsWithCountdown"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"waitForEvmConfirmationsWithCountdown should return immediately when confirmations <= 0","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should return immediately when confirmations <= 0"},{"ancestorTitles":["waitForSvmConfirmationsWithCountdown"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"waitForSvmConfirmationsWithCountdown should return immediately when confirmations <= 0","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should return immediately when confirmations <= 0"}],"endTime":1792494878328,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/rescue-svm-confirmation.spec.ts","startTime":1792494878188,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["SVM relayable payload size guard"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"SVM relayable payload size guard reports hex payload byte length","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"reports hex payload byte length"},{"ancestorTitles":["SVM relayable payload size guard"],"duration":6,"failureDetails":[],"failureMessages":[],"fullName":"SVM relayable payload size guard throws a clear error when instruction payload exceeds the safe limit","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"throws a clear error when instruction payload exceeds the safe limit"},{"ancestorTitles":["buildExecuteMulticall"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildExecuteMulticall should not emit a native value self-call when funds park PC on the UEA","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should not emit a native value self-call when funds park PC on the UEA"},{"ancestorTitles":["buildExecuteMulticall"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildExecuteMulticall should treat 0x as empty data when parking value + funds on the UEA","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should treat 0x as empty data when parking value + funds on the UEA"},{"ancestorTitles":["buildExecuteMulticall"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildExecuteMulticall should allow Route 3 inbound payloads to carry a self value seed","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should allow Route 3 inbound payloads to carry a self value seed"},{"ancestorTitles":["buildExecuteMulticall"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildExecuteMulticall should keep native value transfers for non-self recipients","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should keep native value transfers for non-self recipients"},{"ancestorTitles":["buildExecuteMulticall"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"buildExecuteMulticall should treat an empty multicall array as empty data for ERC-20 funds forwarding","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"should treat an empty multicall array as empty data for ERC-20 funds forwarding"},{"ancestorTitles":["buildCeaMulticallPayload"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildCeaMulticallPayload should return 0x for empty array","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return 0x for empty array"},{"ancestorTitles":["buildCeaMulticallPayload"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildCeaMulticallPayload should include UEA_MULTICALL_SELECTOR prefix","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should include UEA_MULTICALL_SELECTOR prefix"},{"ancestorTitles":["buildCeaMulticallPayload"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildCeaMulticallPayload should encode a single multicall entry","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"should encode a single multicall entry"},{"ancestorTitles":["buildCeaMulticallPayload"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildCeaMulticallPayload should encode multiple multicall entries","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should encode multiple multicall entries"},{"ancestorTitles":["buildOutboundRequest"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"buildOutboundRequest should build correct UniversalOutboundTxRequest struct","invocations":1,"location":null,"numPassingAsserts":9,"retryReasons":[],"status":"passed","title":"should build correct UniversalOutboundTxRequest struct"},{"ancestorTitles":["buildOutboundRequest"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildOutboundRequest should allow custom maxPCForGas cap","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should allow custom maxPCForGas cap"},{"ancestorTitles":["buildOutboundRequest"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildOutboundRequest should allow custom outbound gasPrice override","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should allow custom outbound gasPrice override"},{"ancestorTitles":["buildOutboundRequest"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildOutboundRequest should handle zero address token","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should handle zero address token"},{"ancestorTitles":["buildOutboundRequest"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildOutboundRequest should reject empty CEA payloads unless recipient parks funds","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should reject empty CEA payloads unless recipient parks funds"},{"ancestorTitles":["buildOutboundRequest"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildOutboundRequest should allow empty CEA payloads with zero recipient","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should allow empty CEA payloads with zero recipient"},{"ancestorTitles":["buildErc20Transfer"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildErc20Transfer should encode ERC20 transfer call","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"should encode ERC20 transfer call"},{"ancestorTitles":["buildOutboundApprovalAndCall"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"buildOutboundApprovalAndCall should produce burn approval + outbound call with pre-computed native value","invocations":1,"location":null,"numPassingAsserts":11,"retryReasons":[],"status":"passed","title":"should produce burn approval + outbound call with pre-computed native value"},{"ancestorTitles":["buildOutboundApprovalAndCall"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildOutboundApprovalAndCall should skip burn approval when zero address token","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should skip burn approval when zero address token"},{"ancestorTitles":["buildOutboundApprovalAndCall"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildOutboundApprovalAndCall should skip burn approval when burnAmount is zero","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should skip burn approval when burnAmount is zero"},{"ancestorTitles":["buildOutboundApprovalAndCall"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildOutboundApprovalAndCall should fallback to 5x gasFee when nativeValueForGas not provided","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should fallback to 5x gasFee when nativeValueForGas not provided"},{"ancestorTitles":["buildOutboundApprovalAndCall"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"buildOutboundApprovalAndCall no bridge-swap entries → plain approve-zero + approve + outbound emission","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"no bridge-swap entries → plain approve-zero + approve + outbound emission"},{"ancestorTitles":["MIGRATION_SELECTOR"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"MIGRATION_SELECTOR should equal bytes4(keccak256(\"UEA_MIGRATION\"))","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should equal bytes4(keccak256(\"UEA_MIGRATION\"))"},{"ancestorTitles":["MIGRATION_SELECTOR"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"MIGRATION_SELECTOR should be exactly 10 hex characters (4 bytes)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should be exactly 10 hex characters (4 bytes)"},{"ancestorTitles":["buildMigrationPayload"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildMigrationPayload should return the MIGRATION_SELECTOR value","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return the MIGRATION_SELECTOR value"},{"ancestorTitles":["buildMigrationPayload"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildMigrationPayload should return 0xcac656d6","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return 0xcac656d6"},{"ancestorTitles":["buildMigrationPayload"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildMigrationPayload should return exactly 4 bytes (10 hex chars)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should return exactly 4 bytes (10 hex chars)"},{"ancestorTitles":["buildErc20WithdrawalMulticall"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildErc20WithdrawalMulticall should return a single-element MultiCall array","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return a single-element MultiCall array"},{"ancestorTitles":["buildErc20WithdrawalMulticall"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildErc20WithdrawalMulticall should target the token address","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should target the token address"},{"ancestorTitles":["buildErc20WithdrawalMulticall"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildErc20WithdrawalMulticall should have value 0","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should have value 0"},{"ancestorTitles":["buildErc20WithdrawalMulticall"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildErc20WithdrawalMulticall should encode an ERC20 transfer call","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should encode an ERC20 transfer call"},{"ancestorTitles":["buildErc20WithdrawalMulticall"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildErc20WithdrawalMulticall should produce output matching buildErc20Transfer wrapped in array","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should produce output matching buildErc20Transfer wrapped in array"},{"ancestorTitles":["buildSendUniversalTxToUEA"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"buildSendUniversalTxToUEA should encode sendUniversalTxToUEA function call on CEA_EVM ABI","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should encode sendUniversalTxToUEA function call on CEA_EVM ABI"},{"ancestorTitles":["buildSendUniversalTxToUEA"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildSendUniversalTxToUEA should return ERC20 MultiCall with to = ceaAddress and value = 0","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should return ERC20 MultiCall with to = ceaAddress and value = 0"},{"ancestorTitles":["buildSendUniversalTxToUEA"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildSendUniversalTxToUEA should encode correct args (token, amount, payload, revertRecipient)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"should encode correct args (token, amount, payload, revertRecipient)"},{"ancestorTitles":["buildSendUniversalTxToUEA"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildSendUniversalTxToUEA should work with native token (ZERO_ADDRESS) without forwarding call value","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"should work with native token (ZERO_ADDRESS) without forwarding call value"},{"ancestorTitles":["buildSendUniversalTxToUEA"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildSendUniversalTxToUEA should work with empty payload","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"should work with empty payload"},{"ancestorTitles":["isSvmChain"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"isSvmChain should return true for Solana chains","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should return true for Solana chains"},{"ancestorTitles":["isSvmChain"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"isSvmChain should return false for EVM chains","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return false for EVM chains"},{"ancestorTitles":["isValidSolanaHexAddress"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"isValidSolanaHexAddress should accept 32-byte hex addresses","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should accept 32-byte hex addresses"},{"ancestorTitles":["isValidSolanaHexAddress"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"isValidSolanaHexAddress should reject 20-byte EVM addresses","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should reject 20-byte EVM addresses"},{"ancestorTitles":["isValidSolanaHexAddress"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"isValidSolanaHexAddress should reject addresses without 0x prefix","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should reject addresses without 0x prefix"},{"ancestorTitles":["encodeSvmExecutePayload"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"encodeSvmExecutePayload should encode a payload with no accounts","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should encode a payload with no accounts"},{"ancestorTitles":["encodeSvmExecutePayload"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"encodeSvmExecutePayload should encode a payload with accounts","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should encode a payload with accounts"},{"ancestorTitles":["findTokenChain"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"findTokenChain should find the chain for a chain-specific registered token","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should find the chain for a chain-specific registered token"},{"ancestorTitles":["findTokenChain"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"findTokenChain should return undefined for an unregistered token","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return undefined for an unregistered token"},{"ancestorTitles":["validateRouteParams — unsupported token"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"validateRouteParams — unsupported token should throw RouteValidationError when token symbol is not available on target chain","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should throw RouteValidationError when token symbol is not available on target chain"},{"ancestorTitles":["validateRouteParams — unsupported token"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"validateRouteParams — unsupported token should include token symbol and destination in error message","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should include token symbol and destination in error message"},{"ancestorTitles":["validateRouteParams — unsupported token"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"validateRouteParams — unsupported token should NOT throw when token symbol exists on target chain","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should NOT throw when token symbol exists on target chain"},{"ancestorTitles":["validateRouteParams — unsupported token"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"validateRouteParams — unsupported token should NOT throw when target is Push Chain","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should NOT throw when target is Push Chain"},{"ancestorTitles":["encodeSvmCeaToUeaPayload"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"encodeSvmCeaToUeaPayload should encode SOL drain (no token mint, no extra payload)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should encode SOL drain (no token mint, no extra payload)"},{"ancestorTitles":["encodeSvmCeaToUeaPayload"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"encodeSvmCeaToUeaPayload should encode SPL drain (with token mint)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should encode SPL drain (with token mint)"},{"ancestorTitles":["encodeSvmCeaToUeaPayload"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"encodeSvmCeaToUeaPayload should encode with extraPayload","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should encode with extraPayload"},{"ancestorTitles":["encodeSvmCeaToUeaPayload"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"encodeSvmCeaToUeaPayload should produce different output with vs without extraPayload","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should produce different output with vs without extraPayload"},{"ancestorTitles":["encodeSvmCeaToUeaPayload"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"encodeSvmCeaToUeaPayload should produce same output for empty extraPayload and no extraPayload","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should produce same output for empty extraPayload and no extraPayload"}],"endTime":1792494878471,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/payload-builders.spec.ts","startTime":1792494878330,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":[],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"DEXES includes destination tokens independently on every supported network within policy limits","invocations":1,"location":null,"numPassingAsserts":43,"retryReasons":[],"status":"passed","title":"DEXES includes destination tokens independently on every supported network within policy limits"},{"ancestorTitles":[],"duration":5,"failureDetails":[],"failureMessages":[],"fullName":"LENDING includes destination tokens independently on every supported network within policy limits","invocations":1,"location":null,"numPassingAsserts":43,"retryReasons":[],"status":"passed","title":"LENDING includes destination tokens independently on every supported network within policy limits"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"STAKING includes destination tokens independently on every supported network within policy limits","invocations":1,"location":null,"numPassingAsserts":13,"retryReasons":[],"status":"passed","title":"STAKING includes destination tokens independently on every supported network within policy limits"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"selects protocol-specific testnet tokens rather than reusing the DEX pair for lending","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"selects protocol-specific testnet tokens rather than reusing the DEX pair for lending"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"preserves an explicit empty list instead of silently repopulating tokens","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"preserves an explicit empty list instead of silently repopulating tokens"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"an explicit selection replaces defaults on all chains without filling other networks","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"an explicit selection replaces defaults on all chains without filling other networks"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"regenerates token constraints and approvals from returned default assets with supplied caps","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"regenerates token constraints and approvals from returned default assets with supplied caps"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"isolates defaults from returned assets, caller mutations and input catalog mutations","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"isolates defaults from returned assets, caller mutations and input catalog mutations"}],"endTime":1792494878815,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/preset-default-tokens.spec.ts","startTime":1792494878474,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["runPreflight"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"runPreflight emits 203_03 INFO and returns ok when balance is sufficient","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"emits 203_03 INFO and returns ok when balance is sufficient"},{"ancestorTitles":["runPreflight"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"runPreflight defaults to warning-only and proceeds on native shortfall","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"defaults to warning-only and proceeds on native shortfall"},{"ancestorTitles":["runPreflight"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"runPreflight emits 203_03 WARNING + 203_04 ERROR and throws when enforceGasCheck=true","invocations":1,"location":null,"numPassingAsserts":9,"retryReasons":[],"status":"passed","title":"emits 203_03 WARNING + 203_04 ERROR and throws when enforceGasCheck=true"},{"ancestorTitles":["runPreflight"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"runPreflight error carries structured fields (required, available, shortfall, pathTag)","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"error carries structured fields (required, available, shortfall, pathTag)"},{"ancestorTitles":["runPreflight"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"runPreflight PRC-20 burn-balance shortfall throws with reason=PRC20","invocations":1,"location":null,"numPassingAsserts":10,"retryReasons":[],"status":"passed","title":"PRC-20 burn-balance shortfall throws with reason=PRC20"},{"ancestorTitles":["runPreflight"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"runPreflight skips PRC-20 check when burnToken/burnAmount/prc20Balance are undefined (native value transfer)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"skips PRC-20 check when burnToken/burnAmount/prc20Balance are undefined (native value transfer)"},{"ancestorTitles":["runPreflight"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"runPreflight PRC-20 sufficient + native sufficient → 203_03 INFO twice, no throw","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"PRC-20 sufficient + native sufficient → 203_03 INFO twice, no throw"},{"ancestorTitles":["runPreflight"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"runPreflight InsufficientUEABalanceError auto-populates decodedError for terminal hook payload","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"InsufficientUEABalanceError auto-populates decodedError for terminal hook payload"},{"ancestorTitles":["runPreflight"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"runPreflight PRC-20 InsufficientUEABalanceError decodedError hint is PRC-20-flavoured","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"PRC-20 InsufficientUEABalanceError decodedError hint is PRC-20-flavoured"},{"ancestorTitles":["runPreflight"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"runPreflight InsufficientUEABalanceError is also instanceof PushChainExecutionError (for legacy catch handlers)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"InsufficientUEABalanceError is also instanceof PushChainExecutionError (for legacy catch handlers)"},{"ancestorTitles":["runPreflight"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"runPreflight CASCADE pathTag fires 003-03/04 (cascade bucket), NOT 203-03/04","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"CASCADE pathTag fires 003-03/04 (cascade bucket), NOT 203-03/04"},{"ancestorTitles":["runPreflight"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"runPreflight R2_SVM pathTag fires 203-03/04 (R2 single-route bucket)","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"R2_SVM pathTag fires 203-03/04 (R2 single-route bucket)"},{"ancestorTitles":["runPreflight"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"runPreflight R3_EVM pathTag fires 303-04/05 (R3 single-route bucket, not R2)","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"R3_EVM pathTag fires 303-04/05 (R3 single-route bucket, not R2)"},{"ancestorTitles":["runPreflight"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"runPreflight R3_SVM pathTag fires 303-04/05 (R3 single-route bucket)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"R3_SVM pathTag fires 303-04/05 (R3 single-route bucket)"},{"ancestorTitles":["runPreflight"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"runPreflight cascade segmentIndex propagates through to error and hook payload","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"cascade segmentIndex propagates through to error and hook payload"},{"ancestorTitles":["maybeFireSvmWarnThreshold"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"maybeFireSvmWarnThreshold does NOT fire when buffered quote is at or below threshold","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"does NOT fire when buffered quote is at or below threshold"},{"ancestorTitles":["maybeFireSvmWarnThreshold"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"maybeFireSvmWarnThreshold fires SEND_TX_203_05 INFO when R2_SVM buffered quote exceeds threshold","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"fires SEND_TX_203_05 INFO when R2_SVM buffered quote exceeds threshold"},{"ancestorTitles":["maybeFireSvmWarnThreshold"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"maybeFireSvmWarnThreshold fires SEND_TX_303_06 INFO (R3 bucket) when pathTag is R3_SVM","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"fires SEND_TX_303_06 INFO (R3 bucket) when pathTag is R3_SVM"},{"ancestorTitles":["maybeFireSvmWarnThreshold"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"maybeFireSvmWarnThreshold fires SEND_TX_003_05 INFO (cascade bucket) when pathTag is CASCADE","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"fires SEND_TX_003_05 INFO (cascade bucket) when pathTag is CASCADE"}],"endTime":1792494878962,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/preflight.spec.ts","startTime":1792494878819,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["sizeOutboundGas — EVM destination (Ethereum Sepolia)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"sizeOutboundGas — EVM destination (Ethereum Sepolia) Case A: gas < $1 → category A, gasLegNativePc = $1 worth","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"Case A: gas < $1 → category A, gasLegNativePc = $1 worth"},{"ancestorTitles":["sizeOutboundGas — EVM destination (Ethereum Sepolia)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"sizeOutboundGas — EVM destination (Ethereum Sepolia) Case B: $1 ≤ gas ≤ $10 → category B, gasLegNativePc = gasUsd equivalent","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"Case B: $1 ≤ gas ≤ $10 → category B, gasLegNativePc = gasUsd equivalent"},{"ancestorTitles":["sizeOutboundGas — EVM destination (Ethereum Sepolia)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"sizeOutboundGas — EVM destination (Ethereum Sepolia) Case C: gas > $10 → category C, $10 gas leg + overflow bridged","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"Case C: gas > $10 → category C, $10 gas leg + overflow bridged"},{"ancestorTitles":["sizeOutboundGas — EVM destination (Ethereum Sepolia)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"sizeOutboundGas — EVM destination (Ethereum Sepolia) exactly $1 boundary → Case B (not A)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"exactly $1 boundary → Case B (not A)"},{"ancestorTitles":["sizeOutboundGas — EVM destination (Ethereum Sepolia)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"sizeOutboundGas — EVM destination (Ethereum Sepolia) exactly $10 boundary → Case B (not C)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"exactly $10 boundary → Case B (not C)"},{"ancestorTitles":["sizeOutboundGas — SVM destination (Solana Devnet)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"sizeOutboundGas — SVM destination (Solana Devnet) Case B on Solana: 0.02 SOL @ $150 = $3.00","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"Case B on Solana: 0.02 SOL @ $150 = $3.00"},{"ancestorTitles":["sizeOutboundGas — oracle fallback"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"sizeOutboundGas — oracle fallback falls back to pushClient.usdcToPush when QuoterV2 returns 0","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"falls back to pushClient.usdcToPush when QuoterV2 returns 0"},{"ancestorTitles":["sizeOutboundGas — oracle fallback"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"sizeOutboundGas — oracle fallback factory probes fee tier when defaultFeeTier returns 0 (real testnet shape)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"factory probes fee tier when defaultFeeTier returns 0 (real testnet shape)"},{"ancestorTitles":["sizeOutboundGas — oracle fallback"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"sizeOutboundGas — oracle fallback PriceFetch failure → passthrough as Case B at $1 floor","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"PriceFetch failure → passthrough as Case B at $1 floor"},{"ancestorTitles":["sizeR1PushGas — R1 Push-chain gas sizing"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"sizeR1PushGas — R1 Push-chain gas sizing Case A: pushGasUsd < $1 → category A, paddedDepositUsd = $1","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"Case A: pushGasUsd < $1 → category A, paddedDepositUsd = $1"},{"ancestorTitles":["sizeR1PushGas — R1 Push-chain gas sizing"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"sizeR1PushGas — R1 Push-chain gas sizing Case B: $1 ≤ pushGasUsd ≤ $10 → category B, paddedDepositUsd = pushGasUsd (pass-through)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"Case B: $1 ≤ pushGasUsd ≤ $10 → category B, paddedDepositUsd = pushGasUsd (pass-through)"},{"ancestorTitles":["sizeR1PushGas — R1 Push-chain gas sizing"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"sizeR1PushGas — R1 Push-chain gas sizing Case C: pushGasUsd > $10 → category C, paddedDepositUsd = pushGasUsd (pass-through, no cap)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"Case C: pushGasUsd > $10 → category C, paddedDepositUsd = pushGasUsd (pass-through, no cap)"},{"ancestorTitles":["sizeR1PushGas — R1 Push-chain gas sizing"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"sizeR1PushGas — R1 Push-chain gas sizing boundary: pushGasUsd === $1 exactly → category B (not A)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"boundary: pushGasUsd === $1 exactly → category B (not A)"},{"ancestorTitles":["sizeR1PushGas — R1 Push-chain gas sizing"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"sizeR1PushGas — R1 Push-chain gas sizing boundary: pushGasUsd === $10 exactly → category B (not C)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"boundary: pushGasUsd === $10 exactly → category B (not C)"}],"endTime":1792494879096,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/gas-usd-sizer.spec.ts","startTime":1792494878965,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["detectUniversalTx"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"detectUniversalTx returns UNKNOWN when receipt has no logs","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"returns UNKNOWN when receipt has no logs"},{"ancestorTitles":["detectUniversalTx"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"detectUniversalTx returns UNKNOWN when receipt is null","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"returns UNKNOWN when receipt is null"},{"ancestorTitles":["detectUniversalTx"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"detectUniversalTx decodes UniversalTx (fromCEA=false) and derives universalTxId","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"decodes UniversalTx (fromCEA=false) and derives universalTxId"},{"ancestorTitles":["detectUniversalTx"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"detectUniversalTx decodes UniversalTx (fromCEA=true) as INBOUND_FROM_CEA","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"decodes UniversalTx (fromCEA=true) as INBOUND_FROM_CEA"},{"ancestorTitles":["detectUniversalTx"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"detectUniversalTx decodes UniversalTxFinalized as OUTBOUND_FINALIZED with subTxId/universalTxId","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"decodes UniversalTxFinalized as OUTBOUND_FINALIZED with subTxId/universalTxId"},{"ancestorTitles":["detectUniversalTx"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"detectUniversalTx decodes UniversalTxReverted as OUTBOUND_REVERTED and parses revertInstruction","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"decodes UniversalTxReverted as OUTBOUND_REVERTED and parses revertInstruction"},{"ancestorTitles":["detectUniversalTx"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"detectUniversalTx decodes RevertUniversalTx (gateway) as INBOUND_REVERTED","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"decodes RevertUniversalTx (gateway) as INBOUND_REVERTED"},{"ancestorTitles":["detectUniversalTx"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"detectUniversalTx decodes UniversalTxOutbound as OUTBOUND_INITIATED","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"decodes UniversalTxOutbound as OUTBOUND_INITIATED"},{"ancestorTitles":["detectUniversalTx"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"detectUniversalTx UniversalTxExecuted-only is classified as EXECUTED_ON_DEST","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"UniversalTxExecuted-only is classified as EXECUTED_ON_DEST"},{"ancestorTitles":["detectUniversalTx"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"detectUniversalTx cross-references Push Chain when pushClient is provided","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"cross-references Push Chain when pushClient is provided"},{"ancestorTitles":["detectUniversalTx"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"detectUniversalTx flags stuckObservation=UNSPECIFIED when cosmos status is UNSPECIFIED for inbound tx","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"flags stuckObservation=UNSPECIFIED when cosmos status is UNSPECIFIED for inbound tx"},{"ancestorTitles":["detectUniversalTx"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"detectUniversalTx marks notFound when cosmos returns no universalTx record","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"marks notFound when cosmos returns no universalTx record"},{"ancestorTitles":["detectUniversalTx"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"detectUniversalTx records note when receipt fetch throws","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"records note when receipt fetch throws"},{"ancestorTitles":["detectUniversalTx"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"detectUniversalTx dispatches SVM chain to the SVM detector (no legacy EVM-only throw)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"dispatches SVM chain to the SVM detector (no legacy EVM-only throw)"},{"ancestorTitles":["detectUniversalTx"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"detectUniversalTx UNKNOWN when only a non-universal log (e.g. an ERC20 Transfer)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"UNKNOWN when only a non-universal log (e.g. an ERC20 Transfer)"}],"endTime":1792494879232,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/universal-tx-detector/__tests__/detector.spec.ts","startTime":1792494879101,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":[],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"Aave pins the selected reserve, operation amount and wallet beneficiary for every method","invocations":1,"location":null,"numPassingAsserts":22,"retryReasons":[],"status":"passed","title":"Aave pins the selected reserve, operation amount and wallet beneficiary for every method"},{"ancestorTitles":[],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"default lending policy needs only the agent to become locally ready","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"default lending policy needs only the agent to become locally ready"},{"ancestorTitles":[],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"zero operation caps remain valid disabled configurations, while zero bridge totals are separately reported","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"zero operation caps remain valid disabled configurations, while zero bridge totals are separately reported"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"does not approve or grant a positive amount for an unlisted Aave asset","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"does not approve or grant a positive amount for an unlisted Aave asset"},{"ancestorTitles":[],"duration":5,"failureDetails":[],"failureMessages":[],"fullName":"regenerating a token/limit replaces old operation and approval constraints without mutating the old template","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"regenerating a token/limit replaces old operation and approval constraints without mutating the old template"},{"ancestorTitles":[],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"Moonwell applies underlying units and reports the share-based redeem alternative","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"Moonwell applies underlying units and reports the share-based redeem alternative"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"EigenLayer pins the chosen token and deposit amount","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"EigenLayer pins the chosen token and deposit amount"},{"ancestorTitles":[],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"Lido distinguishes stETH, wstETH and native value units","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"Lido distinguishes stETH, wstETH and native value units"},{"ancestorTitles":[],"duration":71,"failureDetails":[],"failureMessages":[],"fullName":"readiness is per chain and cannot be mutated to change later results","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"readiness is per chain and cannot be mutated to change later results"},{"ancestorTitles":[],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"refuses an overlarge token expansion without dropping restrictions","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"refuses an overlarge token expansion without dropping restrictions"}],"endTime":1792494879617,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/preset-operation-limits.spec.ts","startTime":1792494879236,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["parseUEAVersion"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"parseUEAVersion should parse \"1.0.2\" to 1000002","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should parse \"1.0.2\" to 1000002"},{"ancestorTitles":["parseUEAVersion"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"parseUEAVersion should parse \"1.1.3\" to 1001003","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should parse \"1.1.3\" to 1001003"},{"ancestorTitles":["parseUEAVersion"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"parseUEAVersion should parse \"0.0.0\" to 0","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should parse \"0.0.0\" to 0"},{"ancestorTitles":["parseUEAVersion"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"parseUEAVersion should parse \"1.0.0\" to 1000000","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should parse \"1.0.0\" to 1000000"},{"ancestorTitles":["parseUEAVersion"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"parseUEAVersion should parse \"2.10.5\" to 2010005","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should parse \"2.10.5\" to 2010005"},{"ancestorTitles":["parseUEAVersion"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"parseUEAVersion should return 0 for invalid format","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should return 0 for invalid format"},{"ancestorTitles":["parseUEAVersion"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"parseUEAVersion should return 0 for empty string","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should return 0 for empty string"},{"ancestorTitles":["UEA version comparison"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"UEA version comparison should detect upgrade required when version < minRequiredVersion","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should detect upgrade required when version < minRequiredVersion"},{"ancestorTitles":["UEA version comparison"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"UEA version comparison should detect no upgrade when version === minRequiredVersion","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should detect no upgrade when version === minRequiredVersion"},{"ancestorTitles":["UEA version comparison"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"UEA version comparison should detect no upgrade when version > minRequiredVersion","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should detect no upgrade when version > minRequiredVersion"},{"ancestorTitles":["UEA version comparison"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"UEA version comparison should handle minor version comparison correctly","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should handle minor version comparison correctly"},{"ancestorTitles":["UEA version comparison"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"UEA version comparison should handle major version rollover","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should handle major version rollover"},{"ancestorTitles":["UEA version comparison"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"UEA version comparison should treat empty string as 0 (no upgrade from empty)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should treat empty string as 0 (no upgrade from empty)"},{"ancestorTitles":["AccountStatus default (unloaded)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AccountStatus default (unloaded) should have loaded = false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should have loaded = false"},{"ancestorTitles":["AccountStatus default (unloaded)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AccountStatus default (unloaded) should have deployed = false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should have deployed = false"},{"ancestorTitles":["AccountStatus default (unloaded)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AccountStatus default (unloaded) should have version as empty string","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should have version as empty string"},{"ancestorTitles":["AccountStatus default (unloaded)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AccountStatus default (unloaded) should have requiresUpgrade = false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should have requiresUpgrade = false"},{"ancestorTitles":["AccountStatus default (unloaded)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AccountStatus default (unloaded) should have mode as signer or read-only","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should have mode as signer or read-only"},{"ancestorTitles":["AccountStatus loaded — upgrade required"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AccountStatus loaded — upgrade required should have loaded = true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should have loaded = true"},{"ancestorTitles":["AccountStatus loaded — upgrade required"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AccountStatus loaded — upgrade required should have deployed = true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should have deployed = true"},{"ancestorTitles":["AccountStatus loaded — upgrade required"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AccountStatus loaded — upgrade required should have requiresUpgrade = true when version < minRequiredVersion","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should have requiresUpgrade = true when version < minRequiredVersion"},{"ancestorTitles":["AccountStatus loaded — no upgrade needed"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AccountStatus loaded — no upgrade needed should have requiresUpgrade = false when version >= minRequiredVersion","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should have requiresUpgrade = false when version >= minRequiredVersion"},{"ancestorTitles":["AccountStatus loaded — not deployed"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AccountStatus loaded — not deployed should have deployed = false with empty version","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should have deployed = false with empty version"},{"ancestorTitles":["AccountStatus loaded — not deployed"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AccountStatus loaded — not deployed should not require upgrade when not deployed","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should not require upgrade when not deployed"},{"ancestorTitles":["UEA Migration progress hook enum values"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"UEA Migration progress hook enum values should have UEA_MIG_01 = \"UEA-MIG-01\"","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should have UEA_MIG_01 = \"UEA-MIG-01\""},{"ancestorTitles":["UEA Migration progress hook enum values"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"UEA Migration progress hook enum values should have UEA_MIG_02 = \"UEA-MIG-02\"","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should have UEA_MIG_02 = \"UEA-MIG-02\""},{"ancestorTitles":["UEA Migration progress hook enum values"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"UEA Migration progress hook enum values should have UEA_MIG_03 = \"UEA-MIG-03\"","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should have UEA_MIG_03 = \"UEA-MIG-03\""},{"ancestorTitles":["UEA Migration progress hook enum values"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"UEA Migration progress hook enum values should have UEA_MIG_9901 = \"UEA-MIG-9901\"","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should have UEA_MIG_9901 = \"UEA-MIG-9901\""},{"ancestorTitles":["UEA Migration progress hook enum values"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"UEA Migration progress hook enum values should have UEA_MIG_9902 = \"UEA-MIG-9902\"","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should have UEA_MIG_9902 = \"UEA-MIG-9902\""},{"ancestorTitles":["UEA Migration progress hook enum values"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"UEA Migration progress hook enum values should have UEA_MIG_9903 = \"UEA-MIG-9903\"","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should have UEA_MIG_9903 = \"UEA-MIG-9903\""},{"ancestorTitles":["UEA Migration progress hook definitions"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"UEA Migration progress hook definitions UEA_MIG_01 should produce INFO level event","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"UEA_MIG_01 should produce INFO level event"},{"ancestorTitles":["UEA Migration progress hook definitions"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"UEA Migration progress hook definitions UEA_MIG_02 should produce INFO level event for signature","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"UEA_MIG_02 should produce INFO level event for signature"},{"ancestorTitles":["UEA Migration progress hook definitions"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"UEA Migration progress hook definitions UEA_MIG_03 should produce INFO level event for broadcasting","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"UEA_MIG_03 should produce INFO level event for broadcasting"},{"ancestorTitles":["UEA Migration progress hook definitions"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"UEA Migration progress hook definitions UEA_MIG_9901 should produce SUCCESS level event with version string","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"UEA_MIG_9901 should produce SUCCESS level event with version string"},{"ancestorTitles":["UEA Migration progress hook definitions"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"UEA Migration progress hook definitions UEA_MIG_9902 should produce ERROR level event","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"UEA_MIG_9902 should produce ERROR level event"},{"ancestorTitles":["UEA Migration progress hook definitions"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"UEA Migration progress hook definitions UEA_MIG_9903 should produce INFO level event for skipped","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"UEA_MIG_9903 should produce INFO level event for skipped"},{"ancestorTitles":["UEA_FACTORY_ABI"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"UEA_FACTORY_ABI should have UEA_VERSION function","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"should have UEA_VERSION function"},{"ancestorTitles":["UEA_FACTORY_ABI"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"UEA_FACTORY_ABI should have UEA_MIGRATION_CONTRACT function","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"should have UEA_MIGRATION_CONTRACT function"}],"endTime":1792494879770,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/account-status.spec.ts","startTime":1792494879623,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["named SVM IDL rule compilation"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"named SVM IDL rule compilation enforces named constraints against independently Borsh-encoded data","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"enforces named constraints against independently Borsh-encoded data"},{"ancestorTitles":["named SVM IDL rule compilation"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"named SVM IDL rule compilation rejects unknown account","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects unknown account"},{"ancestorTitles":["named SVM IDL rule compilation"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"named SVM IDL rule compilation rejects unlisted ATA","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects unlisted ATA"},{"ancestorTitles":["named SVM IDL rule compilation"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"named SVM IDL rule compilation rejects unknown field","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects unknown field"},{"ancestorTitles":["named SVM IDL rule compilation"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"named SVM IDL rule compilation rejects overflow","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects overflow"},{"ancestorTitles":["named SVM IDL rule compilation"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"named SVM IDL rule compilation rejects duplicate instruction","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects duplicate instruction"},{"ancestorTitles":["named SVM IDL rule compilation"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"named SVM IDL rule compilation rejects mismatched program","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects mismatched program"},{"ancestorTitles":["named SVM IDL rule compilation"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"named SVM IDL rule compilation rejects conflicting comparison","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects conflicting comparison"},{"ancestorTitles":["named SVM IDL rule compilation"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"named SVM IDL rule compilation refuses unsupported layouts \"bytes\"","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"refuses unsupported layouts \"bytes\""},{"ancestorTitles":["named SVM IDL rule compilation"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"named SVM IDL rule compilation refuses unsupported layouts \"string\"","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"refuses unsupported layouts \"string\""},{"ancestorTitles":["named SVM IDL rule compilation"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"named SVM IDL rule compilation refuses unsupported layouts {\"vec\":\"u8\"}","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"refuses unsupported layouts {\"vec\":\"u8\"}"},{"ancestorTitles":["named SVM IDL rule compilation"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"named SVM IDL rule compilation refuses unsupported layouts {\"defined\":{\"name\":\"Unknown\"}}","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"refuses unsupported layouts {\"defined\":{\"name\":\"Unknown\"}}"},{"ancestorTitles":["named SVM IDL rule compilation"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"named SVM IDL rule compilation does not mutate the caller IDL","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"does not mutate the caller IDL"}],"endTime":1792494880039,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/svm-idl.spec.ts","startTime":1792494879773,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["chain namespace mapping"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"chain namespace mapping round-trips every external chain","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"round-trips every external chain"},{"ancestorTitles":["chain namespace mapping"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"chain namespace mapping agrees with the SDK-wide getChainNamespace convention","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"agrees with the SDK-wide getChainNamespace convention"},{"ancestorTitles":["chain namespace mapping"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"chain namespace mapping produces CAIP-2 chain ids, not bare prefixes","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"produces CAIP-2 chain ids, not bare prefixes"},{"ancestorTitles":["chain namespace mapping"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"chain namespace mapping rejects a bare namespace prefix","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"rejects a bare namespace prefix"},{"ancestorTitles":["chain namespace mapping"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"chain namespace mapping rejects an unknown namespace instead of returning a negative result","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects an unknown namespace instead of returning a negative result"},{"ancestorTitles":["chain namespace mapping"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"chain namespace mapping rejects chains whose chainId is still a TBD placeholder","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects chains whose chainId is still a TBD placeholder"},{"ancestorTitles":["chain namespace mapping"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"chain namespace mapping offers a non-throwing probe","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"offers a non-throwing probe"},{"ancestorTitles":["chain namespace mapping"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"chain namespace mapping excludes Push chains from the external set","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"excludes Push chains from the external set"},{"ancestorTitles":["chain namespace mapping"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"chain namespace mapping identifies Push chains including the DONUT alias","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"identifies Push chains including the DONUT alias"},{"ancestorTitles":["chain namespace mapping"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"chain namespace mapping reports the VM per chain","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"reports the VM per chain"}],"endTime":1792494880171,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/pc20/__tests__/chain-namespace.spec.ts","startTime":1792494880042,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["R1 error-scenario hook emission","SEND-TX-104-04 (sign / fee-lock decline)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"R1 error-scenario hook emission SEND-TX-104-04 (sign / fee-lock decline) emits decline copy for viem UserRejectedRequestError","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"emits decline copy for viem UserRejectedRequestError"},{"ancestorTitles":["R1 error-scenario hook emission","SEND-TX-104-04 (sign / fee-lock decline)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"R1 error-scenario hook emission SEND-TX-104-04 (sign / fee-lock decline) emits decline copy for ethers ACTION_REJECTED","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"emits decline copy for ethers ACTION_REJECTED"},{"ancestorTitles":["R1 error-scenario hook emission","SEND-TX-104-04 (sign / fee-lock decline)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"R1 error-scenario hook emission SEND-TX-104-04 (sign / fee-lock decline) emits decline copy for EIP-1193 code 4001","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"emits decline copy for EIP-1193 code 4001"},{"ancestorTitles":["R1 error-scenario hook emission","SEND-TX-104-04 (sign / fee-lock decline)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"R1 error-scenario hook emission SEND-TX-104-04 (sign / fee-lock decline) emits Signature Failed copy for non-decline errors (insufficient funds)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"emits Signature Failed copy for non-decline errors (insufficient funds)"},{"ancestorTitles":["R1 error-scenario hook emission","SEND-TX-104-04 (sign / fee-lock decline)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"R1 error-scenario hook emission SEND-TX-104-04 (sign / fee-lock decline) emits Signature Failed copy for RPC failure","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"emits Signature Failed copy for RPC failure"},{"ancestorTitles":["R1 error-scenario hook emission","SEND-TX-199-02 (Push Chain broadcast failure)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"R1 error-scenario hook emission SEND-TX-199-02 (Push Chain broadcast failure) emits 199-02 and wraps plain Error in PushChainExecutionError","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"emits 199-02 and wraps plain Error in PushChainExecutionError"},{"ancestorTitles":["R1 error-scenario hook emission","SEND-TX-199-02 (Push Chain broadcast failure)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"R1 error-scenario hook emission SEND-TX-199-02 (Push Chain broadcast failure) emits 199-02 and preserves an already-typed PushChainExecutionError","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"emits 199-02 and preserves an already-typed PushChainExecutionError"},{"ancestorTitles":["R1 error-scenario hook emission","SEND-TX-199-02 (Push Chain broadcast failure)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"R1 error-scenario hook emission SEND-TX-199-02 (Push Chain broadcast failure) emits 199-02 even when the underlying error message contains \"Timeout\"","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"emits 199-02 even when the underlying error message contains \"Timeout\""},{"ancestorTitles":["R1 error-scenario hook emission","Push-to-Push combined decline + failure branch"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"R1 error-scenario hook emission Push-to-Push combined decline + failure branch fires 104-04 when sendPushTx fails with a wallet rejection","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"fires 104-04 when sendPushTx fails with a wallet rejection"},{"ancestorTitles":["R1 error-scenario hook emission","Push-to-Push combined decline + failure branch"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"R1 error-scenario hook emission Push-to-Push combined decline + failure branch fires 199-02 + PushChainExecutionError when sendPushTx fails non-decline","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"fires 199-02 + PushChainExecutionError when sendPushTx fails non-decline"},{"ancestorTitles":["R1 error-scenario hook emission","Coverage matrix — every sign / broadcast site is covered"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"R1 error-scenario hook emission Coverage matrix — every sign / broadcast site is covered execute-standard.ts — signUniversalPayload fires SEND-TX-104-04","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"execute-standard.ts — signUniversalPayload fires SEND-TX-104-04"},{"ancestorTitles":["R1 error-scenario hook emission","Coverage matrix — every sign / broadcast site is covered"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"R1 error-scenario hook emission Coverage matrix — every sign / broadcast site is covered execute-standard.ts — lockFee fires SEND-TX-104-04","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"execute-standard.ts — lockFee fires SEND-TX-104-04"},{"ancestorTitles":["R1 error-scenario hook emission","Coverage matrix — every sign / broadcast site is covered"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"R1 error-scenario hook emission Coverage matrix — every sign / broadcast site is covered execute-funds-only.ts — sendGatewayTxWithFallback (EVM) fires SEND-TX-104-04","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"execute-funds-only.ts — sendGatewayTxWithFallback (EVM) fires SEND-TX-104-04"},{"ancestorTitles":["R1 error-scenario hook emission","Coverage matrix — every sign / broadcast site is covered"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"R1 error-scenario hook emission Coverage matrix — every sign / broadcast site is covered execute-funds-payload.ts — sendGatewayTxWithFallback fires SEND-TX-104-04","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"execute-funds-payload.ts — sendGatewayTxWithFallback fires SEND-TX-104-04"},{"ancestorTitles":["R1 error-scenario hook emission","Coverage matrix — every sign / broadcast site is covered"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"R1 error-scenario hook emission Coverage matrix — every sign / broadcast site is covered execute-standard.ts — sendUniversalTx fires SEND-TX-199-02","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"execute-standard.ts — sendUniversalTx fires SEND-TX-199-02"},{"ancestorTitles":["R1 error-scenario hook emission","Coverage matrix — every sign / broadcast site is covered"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"R1 error-scenario hook emission Coverage matrix — every sign / broadcast site is covered execute-standard.ts — queryUniversalTxStatusFromGatewayTx+extract fires SEND-TX-199-02","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"execute-standard.ts — queryUniversalTxStatusFromGatewayTx+extract fires SEND-TX-199-02"},{"ancestorTitles":["R1 error-scenario hook emission","Coverage matrix — every sign / broadcast site is covered"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"R1 error-scenario hook emission Coverage matrix — every sign / broadcast site is covered execute-funds-only.ts — queryUniversalTxStatusFromGatewayTx+extract (EVM) fires SEND-TX-199-02","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"execute-funds-only.ts — queryUniversalTxStatusFromGatewayTx+extract (EVM) fires SEND-TX-199-02"},{"ancestorTitles":["R1 error-scenario hook emission","Coverage matrix — every sign / broadcast site is covered"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"R1 error-scenario hook emission Coverage matrix — every sign / broadcast site is covered execute-funds-only.ts — queryUniversalTxStatusFromGatewayTx+extract (SVM) fires SEND-TX-199-02","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"execute-funds-only.ts — queryUniversalTxStatusFromGatewayTx+extract (SVM) fires SEND-TX-199-02"},{"ancestorTitles":["R1 error-scenario hook emission","Coverage matrix — every sign / broadcast site is covered"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"R1 error-scenario hook emission Coverage matrix — every sign / broadcast site is covered execute-funds-payload.ts — queryUniversalTxStatusFromGatewayTx+extract fires SEND-TX-199-02","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"execute-funds-payload.ts — queryUniversalTxStatusFromGatewayTx+extract fires SEND-TX-199-02"},{"ancestorTitles":["R1 error-scenario hook emission","Coverage matrix — every sign / broadcast site is covered"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"R1 error-scenario hook emission Coverage matrix — every sign / broadcast site is covered push-chain-tx.ts — extractPcTxAndTransform (pcTx FAILED) fires SEND-TX-199-02","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"push-chain-tx.ts — extractPcTxAndTransform (pcTx FAILED) fires SEND-TX-199-02"},{"ancestorTitles":["R1 error-scenario hook emission","Coverage matrix — every sign / broadcast site is covered"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"R1 error-scenario hook emission Coverage matrix — every sign / broadcast site is covered execute-standard.ts — sendPushTx (decline) fires SEND-TX-104-04","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"execute-standard.ts — sendPushTx (decline) fires SEND-TX-104-04"},{"ancestorTitles":["R1 error-scenario hook emission","Coverage matrix — every sign / broadcast site is covered"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"R1 error-scenario hook emission Coverage matrix — every sign / broadcast site is covered execute-standard.ts — sendPushTx (non-decline) fires SEND-TX-199-02","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"execute-standard.ts — sendPushTx (non-decline) fires SEND-TX-199-02"}],"endTime":1792494880327,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/r1-error-emission.spec.ts","startTime":1792494880176,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":[],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"normalizes unified native calls into exact EQ/MAX words with zero PC default","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"normalizes unified native calls into exact EQ/MAX words with zero PC default"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"rejects retired top-level actions before signing","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects retired top-level actions before signing"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"rejects retired top-level target before signing","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects retired top-level target before signing"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"rejects retired top-level amount before signing","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects retired top-level amount before signing"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"rejects retired top-level maxCalls before signing","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects retired top-level maxCalls before signing"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"rejects retired top-level maxValueTotal before signing","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects retired top-level maxValueTotal before signing"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"rejects retired top-level ref before signing","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects retired top-level ref before signing"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"supports multiple native MAX pins","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"supports multiple native MAX pins"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"compiles the existing EVM WALLET beneficiary and defaults asset total to zero","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"compiles the existing EVM WALLET beneficiary and defaults asset total to zero"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"supports general destination EQ/MAX pins","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"supports general destination EQ/MAX pins"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"computes top-level offsets after static arrays and preserves a raw-word round trip","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"computes top-level offsets after static arrays and preserves a raw-word round trip"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"compiles numeric Solana arg/account pins without a caller IDL","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"compiles numeric Solana arg/account pins without a caller IDL"},{"ancestorTitles":[],"duration":71,"failureDetails":[],"failureMessages":[],"fullName":"public create rejects missing options asynchronously, and update rejects malformed pairs before reads","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"public create rejects missing options asynchronously, and update rejects malformed pairs before reads"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"does not silently discard a token qualifier on an argument pin","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"does not silently discard a token qualifier on an argument pin"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"reads native wallet equality as WALLET and re-encodes its exact word","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"reads native wallet equality as WALLET and re-encodes its exact word"}],"endTime":1792494880688,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/public-rule.spec.ts","startTime":1792494880336,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["Orchestrator.execute — sendTransaction per-call progressHook"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"Orchestrator.execute — sendTransaction per-call progressHook fans progress events to both init-time and per-call hooks","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"fans progress events to both init-time and per-call hooks"},{"ancestorTitles":["Orchestrator.execute — sendTransaction per-call progressHook"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Orchestrator.execute — sendTransaction per-call progressHook delivers events to the init-time hook when no per-call hook is configured","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"delivers events to the init-time hook when no per-call hook is configured"},{"ancestorTitles":["Orchestrator.execute — sendTransaction per-call progressHook"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Orchestrator.execute — sendTransaction per-call progressHook does not double-fire when the per-call hook is the init-time hook","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"does not double-fire when the per-call hook is the init-time hook"},{"ancestorTitles":["Orchestrator.execute — sendTransaction per-call progressHook"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Orchestrator.execute — sendTransaction per-call progressHook delivers per-call events when no init-time hook is configured","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"delivers per-call events when no init-time hook is configured"},{"ancestorTitles":["Orchestrator.execute — sendTransaction per-call progressHook"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Orchestrator.execute — sendTransaction per-call progressHook delivers per-call events when progressHook is embedded in sendTransaction params","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"delivers per-call events when progressHook is embedded in sendTransaction params"},{"ancestorTitles":["Orchestrator.execute — sendTransaction per-call progressHook"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"Orchestrator.execute — sendTransaction per-call progressHook restores the init-time hook when execution rejects","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"restores the init-time hook when execution rejects"},{"ancestorTitles":["Orchestrator.execute — sendTransaction per-call progressHook"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Orchestrator.execute — sendTransaction per-call progressHook keeps the per-call hook active across multi-chain outer and recursive inner execute paths","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"keeps the per-call hook active across multi-chain outer and recursive inner execute paths"}],"endTime":1792494880825,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/send-transaction-progress-hook.spec.ts","startTime":1792494880693,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["R1 error classification","classifyDeclineError — true wallet rejections"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"R1 error classification classifyDeclineError — true wallet rejections classifies as user decline: viem UserRejectedRequestError","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"classifies as user decline: viem UserRejectedRequestError"},{"ancestorTitles":["R1 error classification","classifyDeclineError — true wallet rejections"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"R1 error classification classifyDeclineError — true wallet rejections classifies as user decline: ethers ACTION_REJECTED","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"classifies as user decline: ethers ACTION_REJECTED"},{"ancestorTitles":["R1 error classification","classifyDeclineError — true wallet rejections"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"R1 error classification classifyDeclineError — true wallet rejections classifies as user decline: EIP-1193 4001 code","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"classifies as user decline: EIP-1193 4001 code"},{"ancestorTitles":["R1 error classification","classifyDeclineError — true wallet rejections"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"R1 error classification classifyDeclineError — true wallet rejections classifies as user decline: textual \"user rejected\"","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"classifies as user decline: textual \"user rejected\""},{"ancestorTitles":["R1 error classification","classifyDeclineError — true wallet rejections"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"R1 error classification classifyDeclineError — true wallet rejections classifies as user decline: textual \"user denied\"","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"classifies as user decline: textual \"user denied\""},{"ancestorTitles":["R1 error classification","classifyDeclineError — true wallet rejections"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"R1 error classification classifyDeclineError — true wallet rejections classifies as user decline: textual \"declined by user\"","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"classifies as user decline: textual \"declined by user\""},{"ancestorTitles":["R1 error classification","classifyDeclineError — true wallet rejections"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"R1 error classification classifyDeclineError — true wallet rejections classifies as user decline: undefined errorMessage","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"classifies as user decline: undefined errorMessage"},{"ancestorTitles":["R1 error classification","classifyDeclineError — generic sign-time failures"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"R1 error classification classifyDeclineError — generic sign-time failures classifies as signature failure: insufficient funds","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"classifies as signature failure: insufficient funds"},{"ancestorTitles":["R1 error classification","classifyDeclineError — generic sign-time failures"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"R1 error classification classifyDeclineError — generic sign-time failures classifies as signature failure: contract revert during sign","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"classifies as signature failure: contract revert during sign"},{"ancestorTitles":["R1 error classification","classifyDeclineError — generic sign-time failures"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"R1 error classification classifyDeclineError — generic sign-time failures classifies as signature failure: RPC failure","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"classifies as signature failure: RPC failure"},{"ancestorTitles":["R1 error classification","classifyDeclineError — generic sign-time failures"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"R1 error classification classifyDeclineError — generic sign-time failures classifies as signature failure: generic error","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"classifies as signature failure: generic error"},{"ancestorTitles":["R1 error classification","SEND_TX_104_04 builder"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"R1 error classification SEND_TX_104_04 builder emits decline copy for a real wallet rejection","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"emits decline copy for a real wallet rejection"},{"ancestorTitles":["R1 error classification","SEND_TX_104_04 builder"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"R1 error classification SEND_TX_104_04 builder emits signature-failed copy for a generic sign-time error","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"emits signature-failed copy for a generic sign-time error"},{"ancestorTitles":["R1 error classification","SEND_TX_104_04 builder"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"R1 error classification SEND_TX_104_04 builder normalizes Push Chain native balance errors in 199-02 copy","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"normalizes Push Chain native balance errors in 199-02 copy"},{"ancestorTitles":["R1 error classification","SEND_TX_104_04 builder"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"R1 error classification SEND_TX_104_04 builder treats undefined errorMessage as a decline","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"treats undefined errorMessage as a decline"},{"ancestorTitles":["R1 error classification","PushChainExecutionError"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"R1 error classification PushChainExecutionError carries a readonly PUSH_CHAIN_EXECUTION_FAILED code","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"carries a readonly PUSH_CHAIN_EXECUTION_FAILED code"},{"ancestorTitles":["R1 error classification","PushChainExecutionError"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"R1 error classification PushChainExecutionError gatewayTxHash defaults to undefined","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"gatewayTxHash defaults to undefined"},{"ancestorTitles":["R1 error classification","PushChainExecutionError","consumer-side classification (anti-regression vs string-prefix)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"R1 error classification PushChainExecutionError consumer-side classification (anti-regression vs string-prefix) instanceof correctly classifies a PushChainExecutionError whose message starts with \"Timeout\"","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"instanceof correctly classifies a PushChainExecutionError whose message starts with \"Timeout\""},{"ancestorTitles":["R1 error classification","PushChainExecutionError","consumer-side classification (anti-regression vs string-prefix)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"R1 error classification PushChainExecutionError consumer-side classification (anti-regression vs string-prefix) string-prefix WOULD mis-classify the same error — demonstrates the regression being prevented","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"string-prefix WOULD mis-classify the same error — demonstrates the regression being prevented"},{"ancestorTitles":["R1 error classification","PushChainExecutionError","consumer-side classification (anti-regression vs string-prefix)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"R1 error classification PushChainExecutionError consumer-side classification (anti-regression vs string-prefix) instanceof distinguishes timeout error from execution failure","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"instanceof distinguishes timeout error from execution failure"}],"endTime":1792494880962,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/r1-error-classification.spec.ts","startTime":1792494880828,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["estimateNativeValueForSwap"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"estimateNativeValueForSwap uses QuoterV2 exact-output before slot0 math","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"uses QuoterV2 exact-output before slot0 math"},{"ancestorTitles":["estimateNativeValueForSwap"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"estimateNativeValueForSwap does NOT undersize nativeValueForGas when the UEA PC sits in the STF dead-zone","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"does NOT undersize nativeValueForGas when the UEA PC sits in the STF dead-zone"},{"ancestorTitles":["capSwapEstimate"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"capSwapEstimate returns the full buffered estimate when balance is ample","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"returns the full buffered estimate when balance is ample"},{"ancestorTitles":["capSwapEstimate"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"capSwapEstimate reduces the buffer to balance-reserve while still above the swap floor","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"reduces the buffer to balance-reserve while still above the swap floor"},{"ancestorTitles":["capSwapEstimate"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"capSwapEstimate does NOT undersize below the swap floor (the STF bug) - returns true need","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"does NOT undersize below the swap floor (the STF bug) - returns true need"},{"ancestorTitles":["capSwapEstimate"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"capSwapEstimate returns the full requirement when balance is below the reserve","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"returns the full requirement when balance is below the reserve"},{"ancestorTitles":["capSwapEstimate"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"capSwapEstimate preserves legacy behavior when no floor is supplied (minNeeded defaults to 0)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"preserves legacy behavior when no floor is supplied (minNeeded defaults to 0)"}],"endTime":1792494881093,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/gas-calculator.spec.ts","startTime":1792494880965,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["Route 3 spec strings (301–399)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 3 spec strings (301–399) 301 — {Source Chain}'s Executor Account Detected","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"301 — {Source Chain}'s Executor Account Detected"},{"ancestorTitles":["Route 3 spec strings (301–399)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 3 spec strings (301–399) 302-01 — Estimating {Source Chain} Gas","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"302-01 — Estimating {Source Chain} Gas"},{"ancestorTitles":["Route 3 spec strings (301–399)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 3 spec strings (301–399) 302-02 — {Source Chain} Gas Estimated","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"302-02 — {Source Chain} Gas Estimated"},{"ancestorTitles":["Route 3 spec strings (301–399)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 3 spec strings (301–399) 303-03-01 — Adjusting Prepaid Deposit to be >$1","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"303-03-01 — Adjusting Prepaid Deposit to be >$1"},{"ancestorTitles":["Route 3 spec strings (301–399)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"Route 3 spec strings (301–399) 303-03-02 — Prepaid Deposit in range (>=$1 and <$10)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"303-03-02 — Prepaid Deposit in range (>=$1 and <$10)"},{"ancestorTitles":["Route 3 spec strings (301–399)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 3 spec strings (301–399) 303-03-03 — Prepaid Deposit Exceeds $10 Cap, splitting Gas and Funds","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"303-03-03 — Prepaid Deposit Exceeds $10 Cap, splitting Gas and Funds"},{"ancestorTitles":["Route 3 spec strings (301–399)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 3 spec strings (301–399) 303-01 — Resolving Execution Accounts on Chains","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"303-01 — Resolving Execution Accounts on Chains"},{"ancestorTitles":["Route 3 spec strings (301–399)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 3 spec strings (301–399) 303-02 — Execution Accounts Resolved","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"303-02 — Execution Accounts Resolved"},{"ancestorTitles":["Route 3 spec strings (301–399)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 3 spec strings (301–399) 304-01 — Awaiting Signature","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"304-01 — Awaiting Signature"},{"ancestorTitles":["Route 3 spec strings (301–399)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 3 spec strings (301–399) 304-02 — Signature Received","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"304-02 — Signature Received"},{"ancestorTitles":["Route 3 spec strings (301–399)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 3 spec strings (301–399) 304-03 — Verification Success","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"304-03 — Verification Success"},{"ancestorTitles":["Route 3 spec strings (301–399)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 3 spec strings (301–399) 304-04 — Verification Declined (genuine user decline)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"304-04 — Verification Declined (genuine user decline)"},{"ancestorTitles":["Route 3 spec strings (301–399)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 3 spec strings (301–399) 307 — Broadcasting from Push Chain → {Source Chain}","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"307 — Broadcasting from Push Chain → {Source Chain}"},{"ancestorTitles":["Route 3 spec strings (301–399)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 3 spec strings (301–399) 309-01 — Awaiting {Source Chain} Relay","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"309-01 — Awaiting {Source Chain} Relay"},{"ancestorTitles":["Route 3 spec strings (301–399)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 3 spec strings (301–399) 309-02 — Syncing State with {Source Chain}","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"309-02 — Syncing State with {Source Chain}"},{"ancestorTitles":["Route 3 spec strings (301–399)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 3 spec strings (301–399) 309-03 — {Source Chain} Tx Confirmed","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"309-03 — {Source Chain} Tx Confirmed"},{"ancestorTitles":["Route 3 spec strings (301–399)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 3 spec strings (301–399) 310-01 — {Source Chain} → Push Chain Inbound Tx Submitted","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"310-01 — {Source Chain} → Push Chain Inbound Tx Submitted"},{"ancestorTitles":["Route 3 spec strings (301–399)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 3 spec strings (301–399) 310-02 — Syncing State with Push Chain for Inbound Tx","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"310-02 — Syncing State with Push Chain for Inbound Tx"},{"ancestorTitles":["Route 3 spec strings (301–399)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 3 spec strings (301–399) 399-01 — Push Chain Inbound Tx Success","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"399-01 — Push Chain Inbound Tx Success"},{"ancestorTitles":["Route 3 spec strings (301–399)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 3 spec strings (301–399) 399-02 [inbound] — Push Chain Inbound Tx Failed","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"399-02 [inbound] — Push Chain Inbound Tx Failed"},{"ancestorTitles":["Route 3 spec strings (301–399)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"Route 3 spec strings (301–399) 399-02 [outbound] — {Source Chain} Tx Failed","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"399-02 [outbound] — {Source Chain} Tx Failed"},{"ancestorTitles":["Route 3 spec strings (301–399)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 3 spec strings (301–399) 399-02 [push] — Push Chain Tx Failed","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"399-02 [push] — Push Chain Tx Failed"},{"ancestorTitles":["Route 3 spec strings (301–399)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 3 spec strings (301–399) 399-03 [inbound] — Push Chain Inbound Tx Timeout","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"399-03 [inbound] — Push Chain Inbound Tx Timeout"},{"ancestorTitles":["Route 3 spec strings (301–399)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 3 spec strings (301–399) 399-03 [outbound] — Push Chain Inbound Tx Timeout","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"399-03 [outbound] — Push Chain Inbound Tx Timeout"},{"ancestorTitles":["Route 3 spec strings (301–399)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 3 spec strings (301–399) 399-03 [push] — Push Chain Inbound Tx Timeout","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"399-03 [push] — Push Chain Inbound Tx Timeout"},{"ancestorTitles":["Route 3 spec strings (301–399)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Route 3 spec strings (301–399) 399-99 — Intermediate {Source Chain} to Push Tx Completed","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"399-99 — Intermediate {Source Chain} to Push Tx Completed"}],"endTime":1792494881316,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/progress-hook/__tests__/r3-spec-strings.spec.ts","startTime":1792494881101,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["multichain (multi-hop) progress hooks"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"multichain (multi-hop) progress hooks SEND_TX_001 renders hop count and chain arrow","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"SEND_TX_001 renders hop count and chain arrow"},{"ancestorTitles":["multichain (multi-hop) progress hooks"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"multichain (multi-hop) progress hooks SEND_TX_002_01 includes hop number/total and from→to chains","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"SEND_TX_002_01 includes hop number/total and from→to chains"},{"ancestorTitles":["multichain (multi-hop) progress hooks"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"multichain (multi-hop) progress hooks SEND_TX_002_99_99 marks intermediate completion","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"SEND_TX_002_99_99 marks intermediate completion"},{"ancestorTitles":["multichain (multi-hop) progress hooks"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"multichain (multi-hop) progress hooks SEND_TX_003_03 uses Multichain user-facing text","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"SEND_TX_003_03 uses Multichain user-facing text"},{"ancestorTitles":["multichain (multi-hop) progress hooks"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"multichain (multi-hop) progress hooks SEND_TX_999_01 emits multichain success","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"SEND_TX_999_01 emits multichain success"},{"ancestorTitles":["multichain (multi-hop) progress hooks"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"multichain (multi-hop) progress hooks SEND_TX_999_02 reports failedAt and error","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"SEND_TX_999_02 reports failedAt and error"},{"ancestorTitles":["multichain (multi-hop) progress hooks"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"multichain (multi-hop) progress hooks SEND_TX_999_03 reports timeout location","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"SEND_TX_999_03 reports timeout location"}],"endTime":1792494881454,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/progress-hook/__tests__/multichain-hooks.spec.ts","startTime":1792494881321,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["reconstructProgressEvents — cascade multichain replay"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"reconstructProgressEvents — cascade multichain replay recovers user-level hopCount from an R3 leg with merged R1 calls","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"recovers user-level hopCount from an R3 leg with merged R1 calls"},{"ancestorTitles":["reconstructProgressEvents — cascade multichain replay"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"reconstructProgressEvents — cascade multichain replay falls back to outboundTx.length when no R3 legs (pure R2 cascade)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"falls back to outboundTx.length when no R3 legs (pure R2 cascade)"},{"ancestorTitles":["reconstructProgressEvents — cascade multichain replay"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"reconstructProgressEvents — cascade multichain replay clamps defensively — never reports fewer hops than external legs visible","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"clamps defensively — never reports fewer hops than external legs visible"},{"ancestorTitles":["reconstructProgressEvents — cascade multichain replay"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"reconstructProgressEvents — cascade multichain replay emits SEND-TX-999-02 with failedAt on a reverted leg","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"emits SEND-TX-999-02 with failedAt on a reverted leg"},{"ancestorTitles":["reconstructProgressEvents — single-route R2 pre-flight reconstruction"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"reconstructProgressEvents — single-route R2 pre-flight reconstruction reconstructs R2 stream with NATIVE 203-03 only (no funds.amount → no PRC-20 hook)","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"reconstructs R2 stream with NATIVE 203-03 only (no funds.amount → no PRC-20 hook)"},{"ancestorTitles":["reconstructProgressEvents — single-route R2 pre-flight reconstruction"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"reconstructProgressEvents — single-route R2 pre-flight reconstruction reconstructs R2 stream with both PRC-20 and NATIVE 203-03 when funds.amount > 0","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"reconstructs R2 stream with both PRC-20 and NATIVE 203-03 when funds.amount > 0"},{"ancestorTitles":["reconstructProgressEvents — single-route R3 pre-flight reconstruction"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"reconstructProgressEvents — single-route R3 pre-flight reconstruction reconstructs R3 stream with single NATIVE 303-04 from historical tx data","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"reconstructs R3 stream with single NATIVE 303-04 from historical tx data"}],"endTime":1792494881587,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/tx-transformer-multichain.spec.ts","startTime":1792494881456,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["trackTransaction() chain guard"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"trackTransaction() chain guard throws an actionable error naming the offending chain","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"throws an actionable error naming the offending chain"},{"ancestorTitles":["trackTransaction() chain guard"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"trackTransaction() chain guard points the caller at PushChain.CONSTANTS.CHAIN","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"points the caller at PushChain.CONSTANTS.CHAIN"},{"ancestorTitles":["trackTransaction() chain guard"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"trackTransaction() chain guard rejects a raw numeric chainId passed in place of a CHAIN enum","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects a raw numeric chainId passed in place of a CHAIN enum"}],"endTime":1792494881739,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/track-transaction-guard.spec.ts","startTime":1792494881591,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["resolveRequiredFunds"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveRequiredFunds uses gas fee plus execute value when no override is provided","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"uses gas fee plus execute value when no override is provided"},{"ancestorTitles":["resolveRequiredFunds"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"resolveRequiredFunds uses the override when route-level required funds are higher","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"uses the override when route-level required funds are higher"},{"ancestorTitles":["resolveRequiredFunds"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveRequiredFunds keeps the base required funds when the override is lower","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"keeps the base required funds when the override is lower"}],"endTime":1792494882065,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/execute-standard-required-funds.spec.ts","startTime":1792494881741,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["executeFundsOnly — PC20 burn backstop"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"executeFundsOnly — PC20 burn backstop refuses to broadcast a PC20 import (would burn the wrapper and lock the token)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"refuses to broadcast a PC20 import (would burn the wrapper and lock the token)"},{"ancestorTitles":["executeFundsOnly — PC20 burn backstop"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"executeFundsOnly — PC20 burn backstop names the offending path so the failure is diagnosable","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"names the offending path so the failure is diagnosable"},{"ancestorTitles":["executeFundsOnly — PC20 burn backstop"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"executeFundsOnly — PC20 burn backstop reports the wrapper being burned, not the canonical token","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"reports the wrapper being burned, not the canonical token"},{"ancestorTitles":["executeFundsOnly — PC20 burn backstop"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"executeFundsOnly — PC20 burn backstop does not fire for an export — locking the source token is the safe direction","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"does not fire for an export — locking the source token is the safe direction"},{"ancestorTitles":["executeFundsOnly — PC20 burn backstop"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"executeFundsOnly — PC20 burn backstop does not fire for an ordinary PRC20 funds transfer","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"does not fire for an ordinary PRC20 funds transfer"}],"endTime":1792494882206,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/pc20/__tests__/funds-only-burn-guard.spec.ts","startTime":1792494882068,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["cascade buildHopDescriptor — SVM CEA-ATA rent bump wire-in"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"cascade buildHopDescriptor — SVM CEA-ATA rent bump wire-in re-queries with CEA ATA finalize budget for cascade SPL hop when ATA missing","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"re-queries with CEA ATA finalize budget for cascade SPL hop when ATA missing"},{"ancestorTitles":["cascade buildHopDescriptor — SVM CEA-ATA rent bump wire-in"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"cascade buildHopDescriptor — SVM CEA-ATA rent bump wire-in bumps native-SOL hop to the base finalize budget without ATA query","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"bumps native-SOL hop to the base finalize budget without ATA query"},{"ancestorTitles":["cascade buildHopDescriptor — SVM CEA-ATA rent bump wire-in"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"cascade buildHopDescriptor — SVM CEA-ATA rent bump wire-in resolves Push-side pSOL to native SOL before estimating cascade rent","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"resolves Push-side pSOL to native SOL before estimating cascade rent"},{"ancestorTitles":["cascade buildHopDescriptor — SVM CEA-ATA rent bump wire-in"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"cascade buildHopDescriptor — SVM CEA-ATA rent bump wire-in uses only the base finalize budget when ATA already exists","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"uses only the base finalize budget when ATA already exists"}],"endTime":1792494882340,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/cascade-svm-rent.spec.ts","startTime":1792494882209,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["buildSvmPayloadFromParams — prepareTransaction parity"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"buildSvmPayloadFromParams — prepareTransaction parity produces byte-identical svmPayload vs legacy svmExecute for amount=0","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"produces byte-identical svmPayload vs legacy svmExecute for amount=0"},{"ancestorTitles":["buildSvmPayloadFromParams — prepareTransaction parity"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"buildSvmPayloadFromParams — prepareTransaction parity produces byte-identical svmPayload for non-zero amount","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"produces byte-identical svmPayload for non-zero amount"},{"ancestorTitles":["buildSvmPayloadFromParams — prepareTransaction parity"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildSvmPayloadFromParams — prepareTransaction parity returns empty payload + to.address targetBytes for withdraw-only (no data)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"returns empty payload + to.address targetBytes for withdraw-only (no data)"},{"ancestorTitles":["buildSvmPayloadFromParams — prepareTransaction parity"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildSvmPayloadFromParams — prepareTransaction parity returns empty payload when data is the empty-hex sentinel \"0x\"","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"returns empty payload when data is the empty-hex sentinel \"0x\""},{"ancestorTitles":["buildSvmPayloadFromParams — prepareTransaction parity"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"buildSvmPayloadFromParams — prepareTransaction parity throws at submit time if IDL was never registered for the program","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"throws at submit time if IDL was never registered for the program"}],"endTime":1792494882477,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/svm-idl/build-payload.spec.ts","startTime":1792494882343,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["Gap B: terminal-suppression flag on OrchestratorContext","R3 (CEA_TO_PUSH)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Gap B: terminal-suppression flag on OrchestratorContext R3 (CEA_TO_PUSH) suppresses 399-02 when 304-04 has fired (single terminal)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"suppresses 399-02 when 304-04 has fired (single terminal)"},{"ancestorTitles":["Gap B: terminal-suppression flag on OrchestratorContext","R3 (CEA_TO_PUSH)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Gap B: terminal-suppression flag on OrchestratorContext R3 (CEA_TO_PUSH) emits 399-02 (phase=push) when no inner terminal fired (pre-sign failure)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"emits 399-02 (phase=push) when no inner terminal fired (pre-sign failure)"},{"ancestorTitles":["Gap B: terminal-suppression flag on OrchestratorContext","R3 (CEA_TO_PUSH)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"Gap B: terminal-suppression flag on OrchestratorContext R3 (CEA_TO_PUSH) recursive inner call does not emit terminal even if flag is unset","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"recursive inner call does not emit terminal even if flag is unset"},{"ancestorTitles":["Gap B: terminal-suppression flag on OrchestratorContext","R2 (UOA_TO_CEA)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Gap B: terminal-suppression flag on OrchestratorContext R2 (UOA_TO_CEA) suppresses 299-02 when 204-04 has fired","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"suppresses 299-02 when 204-04 has fired"},{"ancestorTitles":["Gap B: terminal-suppression flag on OrchestratorContext","R2 (UOA_TO_CEA)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Gap B: terminal-suppression flag on OrchestratorContext R2 (UOA_TO_CEA) emits 299-02 when no inner terminal fired","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"emits 299-02 when no inner terminal fired"},{"ancestorTitles":["Gap B: terminal-suppression flag on OrchestratorContext","R1 (UOA_TO_PUSH)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"Gap B: terminal-suppression flag on OrchestratorContext R1 (UOA_TO_PUSH) suppresses 199-02 when 104-04 has fired (user decline)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"suppresses 199-02 when 104-04 has fired (user decline)"},{"ancestorTitles":["Gap B: terminal-suppression flag on OrchestratorContext","R1 (UOA_TO_PUSH)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Gap B: terminal-suppression flag on OrchestratorContext R1 (UOA_TO_PUSH) suppresses second 199-02 when inner pipeline already fired 199-02","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"suppresses second 199-02 when inner pipeline already fired 199-02"},{"ancestorTitles":["Gap B: terminal-suppression flag on OrchestratorContext","Flag lifecycle (reset at execute() entry)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Gap B: terminal-suppression flag on OrchestratorContext Flag lifecycle (reset at execute() entry) fresh ctx does not have flag set — outer catch fires terminal","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"fresh ctx does not have flag set — outer catch fires terminal"},{"ancestorTitles":["Gap B: terminal-suppression flag on OrchestratorContext","Flag lifecycle (reset at execute() entry)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Gap B: terminal-suppression flag on OrchestratorContext Flag lifecycle (reset at execute() entry) flag from a prior execute() is reset at the start of the next one","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"flag from a prior execute() is reset at the start of the next one"}],"endTime":1792494882716,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/terminal-suppression.spec.ts","startTime":1792494882480,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["UniversalTxResponse.wait() Push-chain failure gate"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"UniversalTxResponse.wait() Push-chain failure gate returns the failed Push receipt without polling for a nonexistent outbound","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"returns the failed Push receipt without polling for a nonexistent outbound"}],"endTime":1792494882880,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/response-builder-push-revert.spec.ts","startTime":1792494882718,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["resolveSvmCall — byte-for-byte parity against legacy svmExecute"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"resolveSvmCall — byte-for-byte parity against legacy svmExecute produces the same triple as hand-rolled buildReceiveSol* helpers (amount=0)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"produces the same triple as hand-rolled buildReceiveSol* helpers (amount=0)"},{"ancestorTitles":["resolveSvmCall — byte-for-byte parity against legacy svmExecute"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"resolveSvmCall — byte-for-byte parity against legacy svmExecute preserves parity for non-zero amount","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"preserves parity for non-zero amount"},{"ancestorTitles":["resolveSvmCall — byte-for-byte parity against legacy svmExecute"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"resolveSvmCall — byte-for-byte parity against legacy svmExecute throws when no IDL is registered","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"throws when no IDL is registered"},{"ancestorTitles":["resolveSvmCall — byte-for-byte parity against legacy svmExecute"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveSvmCall — byte-for-byte parity against legacy svmExecute throws when discriminator does not match any instruction","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"throws when discriminator does not match any instruction"}],"endTime":1792494883038,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/svm-idl/resolve.spec.ts","startTime":1792494882882,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":[],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"recognizes a verified 7702 self-call and retains every native agent action","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"recognizes a verified 7702 self-call and retains every native agent action"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"recognizes a verified UEA multicall carrying single agent-door entries","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"recognizes a verified UEA multicall carrying single agent-door entries"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"does not label an arbitrary forwarding contract as a trusted sender batch","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"does not label an arbitrary forwarding contract as a trusted sender batch"}],"endTime":1792494883385,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/native-batch-response.spec.ts","startTime":1792494883040,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["SVM PC20 finalize rent floor"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"SVM PC20 finalize rent floor covers mint and state rent on a first export","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"covers mint and state rent on a first export"},{"ancestorTitles":["SVM PC20 finalize rent floor"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"SVM PC20 finalize rent floor drops deployment rents on a repeat export but keeps the ATA","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"drops deployment rents on a repeat export but keeps the ATA"},{"ancestorTitles":["SVM PC20 finalize rent floor"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"SVM PC20 finalize rent floor pins the rent constants to Solana protocol values","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"pins the rent constants to Solana protocol values"}],"endTime":1792494883571,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm-rent-pc20.spec.ts","startTime":1792494883388,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["PC20 inbound — Push-side payload"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"PC20 inbound — Push-side payload transfers the resolved Push-native PC20, not the wrapper","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"transfers the resolved Push-native PC20, not the wrapper"},{"ancestorTitles":["PC20 inbound — Push-side payload"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PC20 inbound — Push-side payload transfers the full funds amount to the requested recipient","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"transfers the full funds amount to the requested recipient"},{"ancestorTitles":["PC20 inbound — Push-side payload"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"PC20 inbound — Push-side payload orders funds-plus-data as transfer then call","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"orders funds-plus-data as transfer then call"},{"ancestorTitles":["PC20 inbound — Push-side payload"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PC20 inbound — Push-side payload leaves distribution to the caller for an explicit MultiCall[]","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"leaves distribution to the caller for an explicit MultiCall[]"},{"ancestorTitles":["PC20 inbound — Push-side payload"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PC20 inbound — Push-side payload never routes a PC20 through the PRC20 synthetic lookup","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"never routes a PC20 through the PRC20 synthetic lookup"},{"ancestorTitles":["PC20 inbound — approval behavior"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PC20 inbound — approval behavior uses a mechanism that is neither approve nor native","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"uses a mechanism that is neither approve nor native"},{"ancestorTitles":["PC20 inbound — approval behavior"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PC20 inbound — approval behavior carries the wrapper address for the gateway request","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"carries the wrapper address for the gateway request"}],"endTime":1792494883799,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/pc20/__tests__/inbound-payload.spec.ts","startTime":1792494883579,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["read-state public surface"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"read-state public surface keeps registry helpers out of the public package exports","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"keeps registry helpers out of the public package exports"},{"ancestorTitles":["read-state public surface"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"read-state public surface exports the pure helpers, errors and enums","invocations":1,"location":null,"numPassingAsserts":30,"retryReasons":[],"status":"passed","title":"exports the pure helpers, errors and enums"},{"ancestorTitles":["read-state public surface"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"read-state public surface PushChain.CONSTANTS.READ pins the contract-derived values","invocations":1,"location":null,"numPassingAsserts":16,"retryReasons":[],"status":"passed","title":"PushChain.CONSTANTS.READ pins the contract-derived values"}],"endTime":1792494884092,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/read-state/__tests__/public-surface.spec.ts","startTime":1792494883802,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["PushClient","pushToUSDC"],"duration":14,"failureDetails":[],"failureMessages":[],"fullName":"PushClient pushToUSDC converts 1 PUSH (1e18) to 0.1 USDC (1e7)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"converts 1 PUSH (1e18) to 0.1 USDC (1e7)"},{"ancestorTitles":["PushClient","pushToUSDC"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"PushClient pushToUSDC returns 0 when input is 0","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"returns 0 when input is 0"},{"ancestorTitles":["PushClient","usdcToPush"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"PushClient usdcToPush converts 0.1 USDC (1e7) to 1 PUSH (1e18)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"converts 0.1 USDC (1e7) to 1 PUSH (1e18)"},{"ancestorTitles":["PushClient","usdcToPush"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PushClient usdcToPush returns 0 when input is 0","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"returns 0 when input is 0"},{"ancestorTitles":["PushClient","PushClient Msg & Cosmos Tx Tests"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"PushClient PushClient Msg & Cosmos Tx Tests decodes the live Donut Params protobuf wire shape","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"decodes the live Donut Params protobuf wire shape"},{"ancestorTitles":["PushClient","PushClient Msg & Cosmos Tx Tests"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"PushClient PushClient Msg & Cosmos Tx Tests signs gasless Cosmos transactions at the on-chain gas cap","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"signs gasless Cosmos transactions at the on-chain gas cap"},{"ancestorTitles":["PushClient","PushClient Msg & Cosmos Tx Tests"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"PushClient PushClient Msg & Cosmos Tx Tests clamps gasless Cosmos transactions to a lower governance cap","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"clamps gasless Cosmos transactions to a lower governance cap"},{"ancestorTitles":["PushClient","PushClient Msg & Cosmos Tx Tests"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"PushClient PushClient Msg & Cosmos Tx Tests does not increase the SDK ceiling when governance raises the cap","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"does not increase the SDK ceiling when governance raises the cap"},{"ancestorTitles":["PushClient","PushClient Msg & Cosmos Tx Tests"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"PushClient PushClient Msg & Cosmos Tx Tests falls back to the safe SDK ceiling when the params query fails","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"falls back to the safe SDK ceiling when the params query fails"},{"ancestorTitles":["PushClient","PushClient Msg & Cosmos Tx Tests"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"PushClient PushClient Msg & Cosmos Tx Tests caches the gasless cap for subsequent signatures","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"caches the gasless cap for subsequent signatures"},{"ancestorTitles":["PushClient","PushClient Msg & Cosmos Tx Tests"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"PushClient PushClient Msg & Cosmos Tx Tests does not query gasless params for a non-gasless Cosmos message","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"does not query gasless params for a non-gasless Cosmos message"},{"ancestorTitles":["PushClient","PushClient Msg & Cosmos Tx Tests"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PushClient PushClient Msg & Cosmos Tx Tests creates MsgDeployUEA","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"creates MsgDeployUEA"},{"ancestorTitles":["PushClient","PushClient Msg & Cosmos Tx Tests"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"PushClient PushClient Msg & Cosmos Tx Tests creates MsgMintPC","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"creates MsgMintPC"},{"ancestorTitles":["PushClient","PushClient Msg & Cosmos Tx Tests"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"PushClient PushClient Msg & Cosmos Tx Tests creates MsgExecutePayload","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"creates MsgExecutePayload"},{"ancestorTitles":["PushClient","PushClient Msg & Cosmos Tx Tests"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"PushClient PushClient Msg & Cosmos Tx Tests creates TxBody from multiple messages","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"creates TxBody from multiple messages"},{"ancestorTitles":["PushClient","PushClient Msg & Cosmos Tx Tests"],"duration":null,"failureDetails":[],"failureMessages":[],"fullName":"PushClient PushClient Msg & Cosmos Tx Tests signs tx","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"pending","title":"signs tx"},{"ancestorTitles":["PushClient","PushClient Msg & Cosmos Tx Tests"],"duration":null,"failureDetails":[],"failureMessages":[],"fullName":"PushClient PushClient Msg & Cosmos Tx Tests get tx","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"pending","title":"get tx"}],"endTime":1792494884221,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/push-client/push-client.spec.ts","startTime":1792494884094,"status":"focused","summary":""},{"assertionResults":[{"ancestorTitles":["PC20 tracked leg selection"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PC20 tracked leg selection picks the PC20 burn leg, not the trailing fee-credit leg","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"picks the PC20 burn leg, not the trailing fee-credit leg"},{"ancestorTitles":["PC20 tracked leg selection"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"PC20 tracked leg selection finds the PC20 leg regardless of emission order","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"finds the PC20 leg regardless of emission order"},{"ancestorTitles":["PC20 tracked leg selection"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PC20 tracked leg selection returns null when no PC20 leg is present, leaving default behaviour","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"returns null when no PC20 leg is present, leaving default behaviour"},{"ancestorTitles":["PC20 tracked leg selection"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PC20 tracked leg selection ignores a payload that merely contains the selector later on","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"ignores a payload that merely contains the selector later on"},{"ancestorTitles":["PC20 tracked leg selection"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PC20 tracked leg selection skips logs that are not decodable UniversalTx events","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"skips logs that are not decodable UniversalTx events"}],"endTime":1792494884356,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg.spec.ts","startTime":1792494884223,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["buildReadSpecFromPreflight — defaults"],"duration":12,"failureDetails":[],"failureMessages":[],"fullName":"buildReadSpecFromPreflight — defaults rejects a preflight from another destination","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects a preflight from another destination"},{"ancestorTitles":["buildReadSpecFromPreflight — defaults"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"buildReadSpecFromPreflight — defaults pins blockNumber at observedChainHeight − minConfirmations and sets expiry from the Push head","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"pins blockNumber at observedChainHeight − minConfirmations and sets expiry from the Push head"},{"ancestorTitles":["buildReadSpecFromPreflight — defaults"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"buildReadSpecFromPreflight — defaults backs off by a larger minConfirmations and clamps at 1","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"backs off by a larger minConfirmations and clamps at 1"},{"ancestorTitles":["buildReadSpecFromPreflight — defaults"],"duration":63,"failureDetails":[],"failureMessages":[],"fullName":"buildReadSpecFromPreflight — defaults value = protocolFee + sized budget; maxFee = value by default, or value × (1 + bps)","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"value = protocolFee + sized budget; maxFee = value by default, or value × (1 + bps)"},{"ancestorTitles":["buildReadSpecFromPreflight — defaults"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildReadSpecFromPreflight — defaults honours explicit callbackBudget / maxFee / expiryPushChainHeight / blockNumber","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"honours explicit callbackBudget / maxFee / expiryPushChainHeight / blockNumber"},{"ancestorTitles":["buildReadSpecFromPreflight — defaults"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"buildReadSpecFromPreflight — defaults EVM owner defaults to refundTo (20 bytes) and can be overridden","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"EVM owner defaults to refundTo (20 bytes) and can be overridden"},{"ancestorTitles":["buildReadSpecFromPreflight — defaults"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildReadSpecFromPreflight — defaults SVM: owner is the raw 32-byte pubkey from the query; blockNumber doubles as minSlot; `owner` param rejected","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"SVM: owner is the raw 32-byte pubkey from the query; blockNumber doubles as minSlot; `owner` param rejected"},{"ancestorTitles":["buildReadSpecFromPreflight — defaults"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"buildReadSpecFromPreflight — defaults web2: blockNumber forced to 0; a non-zero pin is rejected","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"web2: blockNumber forced to 0; a non-zero pin is rejected"},{"ancestorTitles":["buildReadSpecFromPreflight — defaults"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"buildReadSpecFromPreflight — defaults throws ZERO_REVERT_RECIPIENT when neither refundTo nor a default is available","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"throws ZERO_REVERT_RECIPIENT when neither refundTo nor a default is available"},{"ancestorTitles":["buildReadSpecFromPreflight — defaults"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildReadSpecFromPreflight — defaults carries encoder warnings through","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"carries encoder warnings through"},{"ancestorTitles":["buildReadSpecFromPreflight — defaults"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"buildReadSpecFromPreflight — defaults encodedSpec round-trips and specTuple is positional","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"encodedSpec round-trips and specTuple is positional"},{"ancestorTitles":["toCallData"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toCallData default arg order is (spec, callbackGasLimit) and value is the prepared msg.value","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"default arg order is (spec, callbackGasLimit) and value is the prepared msg.value"},{"ancestorTitles":["toCallData"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toCallData args remaps into the app signature","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"args remaps into the app signature"},{"ancestorTitles":["prepareRead — refundTo default and the UEA-aware contract warning"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"prepareRead — refundTo default and the UEA-aware contract warning defaults refundTo to the sending account","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"defaults refundTo to the sending account"},{"ancestorTitles":["prepareRead — refundTo default and the UEA-aware contract warning"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"prepareRead — refundTo default and the UEA-aware contract warning a UEA refundTo (contract with code, isUEA=true) does NOT warn","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"a UEA refundTo (contract with code, isUEA=true) does NOT warn"},{"ancestorTitles":["prepareRead — refundTo default and the UEA-aware contract warning"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"prepareRead — refundTo default and the UEA-aware contract warning a non-UEA contract refundTo warns about a possibly forfeited refund","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"a non-UEA contract refundTo warns about a possibly forfeited refund"},{"ancestorTitles":["prepareRead — refundTo default and the UEA-aware contract warning"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"prepareRead — refundTo default and the UEA-aware contract warning an EIP-7702-delegated EOA (code 0xef0100…) is treated as an EOA — no warning","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"an EIP-7702-delegated EOA (code 0xef0100…) is treated as an EOA — no warning"},{"ancestorTitles":["prepareRead — refundTo default and the UEA-aware contract warning"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"prepareRead — refundTo default and the UEA-aware contract warning throws when no refundTo can be resolved (read-only client without an account)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"throws when no refundTo can be resolved (read-only client without an account)"},{"ancestorTitles":["simulateRead"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"simulateRead ok when the call does not revert","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"ok when the call does not revert"},{"ancestorTitles":["simulateRead"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"simulateRead reports a generic revert with viem short message","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"reports a generic revert with viem short message"},{"ancestorTitles":["simulateRead"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"simulateRead flags a stale preflight","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"flags a stale preflight"},{"ancestorTitles":["simulateRead"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"simulateRead is not tripped by an unrelated ERC-20 abi passed as the app abi","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"is not tripped by an unrelated ERC-20 abi passed as the app abi"}],"endTime":1792494884547,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/read-state/__tests__/spec-builder.spec.ts","startTime":1792494884359,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["ReadRequested topic0 is pinned to the node decoder"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ReadRequested topic0 is pinned to the node decoder matches the hash derived independently with cast from read_event.go","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"matches the hash derived independently with cast from read_event.go"},{"ancestorTitles":["parseReadRequestsFromReceipt"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"parseReadRequestsFromReceipt parses the real EOA request receipt (read 0xf3d62fb9…)","invocations":1,"location":null,"numPassingAsserts":12,"retryReasons":[],"status":"passed","title":"parses the real EOA request receipt (read 0xf3d62fb9…)"},{"ancestorTitles":["parseReadRequestsFromReceipt"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"parseReadRequestsFromReceipt parses the UEA-originated receipt (read 0xdc0a66ba…) — two logs, one from the UEA, one from the contract","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"parses the UEA-originated receipt (read 0xdc0a66ba…) — two logs, one from the UEA, one from the contract"},{"ancestorTitles":["parseReadRequestsFromReceipt"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"parseReadRequestsFromReceipt ignores a matching topic0 emitted by a DIFFERENT address (address filter is a security control)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"ignores a matching topic0 emitted by a DIFFERENT address (address filter is a security control)"},{"ancestorTitles":["parseReadRequestsFromReceipt"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"parseReadRequestsFromReceipt returns two ids in log order when one tx requests two reads","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"returns two ids in log order when one tx requests two reads"},{"ancestorTitles":["parseFulfilOutcome"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"parseFulfilOutcome delivered: the real fulfil receipt carries ReadFulfilled","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"delivered: the real fulfil receipt carries ReadFulfilled"},{"ancestorTitles":["parseFulfilOutcome"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"parseFulfilOutcome NOT delivered: the reverting-callback fulfil receipt carries CallbackFailed with the reason","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"NOT delivered: the reverting-callback fulfil receipt carries CallbackFailed with the reason"},{"ancestorTitles":["parseFulfilOutcome"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"parseFulfilOutcome settlement: burned + refunded from CallbackGasReported, refundTo from RefundSent","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"settlement: burned + refunded from CallbackGasReported, refundTo from RefundSent"},{"ancestorTitles":["parseFulfilOutcome"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"parseFulfilOutcome is scoped to the requested id — another request in the same receipt is ignored","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"is scoped to the requested id — another request in the same receipt is ignored"}],"endTime":1792494884592,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/read-state/__tests__/read-events.spec.ts","startTime":1792494884549,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["ucallback.v1 codecs against real Donut responses"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"ucallback.v1 codecs against real Donut responses skips future unknown fields while preserving known record bytes","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"skips future unknown fields while preserving known record bytes"},{"ancestorTitles":["ucallback.v1 codecs against real Donut responses"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"ucallback.v1 codecs against real Donut responses rejects uint64 heights that cannot be represented safely instead of rounding","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects uint64 heights that cannot be represented safely instead of rounding"},{"ancestorTitles":["ucallback.v1 codecs against real Donut responses"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"ucallback.v1 codecs against real Donut responses SUCCESS EVM read 0xf3d62fb9… — every field","invocations":1,"location":null,"numPassingAsserts":23,"retryReasons":[],"status":"passed","title":"SUCCESS EVM read 0xf3d62fb9… — every field"},{"ancestorTitles":["ucallback.v1 codecs against real Donut responses"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ucallback.v1 codecs against real Donut responses ERROR read 0xeba3eb9e… — INVALID_QUERY with empty result_data","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"ERROR read 0xeba3eb9e… — INVALID_QUERY with empty result_data"},{"ancestorTitles":["ucallback.v1 codecs against real Donut responses"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"ucallback.v1 codecs against real Donut responses EXPIRED read 0x4a6e27e0… — one pc_tx, expiry_attempts 1, no result","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"EXPIRED read 0x4a6e27e0… — one pc_tx, expiry_attempts 1, no result"},{"ancestorTitles":["ucallback.v1 codecs against real Donut responses"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ucallback.v1 codecs against real Donut responses callback-reverted read 0x9f0466e2… — node still says FULFILLED with SUCCESS (documented semantics)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"callback-reverted read 0x9f0466e2… — node still says FULFILLED with SUCCESS (documented semantics)"},{"ancestorTitles":["ucallback.v1 codecs against real Donut responses"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ucallback.v1 codecs against real Donut responses SVM and web2 reads decode with their namespaces and result bytes","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"SVM and web2 reads decode with their namespaces and result bytes"},{"ancestorTitles":["ucallback.v1 codecs against real Donut responses"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"ucallback.v1 codecs against real Donut responses ReadsByTx keyed on the SDK tx hash — the UEA-originated read","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"ReadsByTx keyed on the SDK tx hash — the UEA-originated read"},{"ancestorTitles":["ucallback.v1 codecs against real Donut responses"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ucallback.v1 codecs against real Donut responses request encoders produce the exact bytes the node expects (field 1, wire type 2)","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"request encoders produce the exact bytes the node expects (field 1, wire type 2)"},{"ancestorTitles":["ucallback.v1 codecs against real Donut responses"],"duration":5,"failureDetails":[],"failureMessages":[],"fullName":"ucallback.v1 codecs against real Donut responses UniversalRead round-trips through encode/decode","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"UniversalRead round-trips through encode/decode"},{"ancestorTitles":["ucallback.v1 codecs against real Donut responses"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ucallback.v1 codecs against real Donut responses empty response → no record, no throw","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"empty response → no record, no throw"}],"endTime":1792494884633,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/read-state/__tests__/ucallback-codec.spec.ts","startTime":1792494884594,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":[],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"detects mint owner TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA and derives its ATA","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"detects mint owner TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA and derives its ATA"},{"ancestorTitles":[],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"detects mint owner TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb and derives its ATA","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"detects mint owner TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb and derives its ATA"},{"ancestorTitles":[],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"rejects missing mints, wrong owners and token accounts instead of guessing","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"rejects missing mints, wrong owners and token accounts instead of guessing"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"falls back on RPC failure but never defaults the token program","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"falls back on RPC failure but never defaults the token program"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"uses unchanged raw-account wire bytes while retaining IDL decoding metadata","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"uses unchanged raw-account wire bytes while retaining IDL decoding metadata"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"carries account decoding through async public preparation without a destination query","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"carries account decoding through async public preparation without a destination query"},{"ancestorTitles":[],"duration":5,"failureDetails":[],"failureMessages":[],"fullName":"rejects invalid IDLs and incompatible public options","invocations":1,"location":null,"numPassingAsserts":9,"retryReasons":[],"status":"passed","title":"rejects invalid IDLs and incompatible public options"},{"ancestorTitles":["idl without functionName: the layout comes from the discriminator"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"idl without functionName: the layout comes from the discriminator decodes each account type with the layout its 8-byte discriminator names","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"decodes each account type with the layout its 8-byte discriminator names"},{"ancestorTitles":["idl without functionName: the layout comes from the discriminator"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"idl without functionName: the layout comes from the discriminator names the discriminator when nothing matches","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"names the discriminator when nothing matches"},{"ancestorTitles":["idl without functionName: the layout comes from the discriminator"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"idl without functionName: the layout comes from the discriminator accepts functionName in snake, camel or Pascal case and pins the layout","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"accepts functionName in snake, camel or Pascal case and pins the layout"},{"ancestorTitles":["idl with the program id as subject: args are the PDA seeds"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"idl with the program id as subject: args are the PDA seeds derives a constant-seed PDA with no args","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"derives a constant-seed PDA with no args"},{"ancestorTitles":["idl with the program id as subject: args are the PDA seeds"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"idl with the program id as subject: args are the PDA seeds fills an account seed from base58, 0x-hex or a PublicKey","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"fills an account seed from base58, 0x-hex or a PublicKey"},{"ancestorTitles":["idl with the program id as subject: args are the PDA seeds"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"idl with the program id as subject: args are the PDA seeds accepts the program id in 0x-hex form too","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"accepts the program id in 0x-hex form too"},{"ancestorTitles":["idl with the program id as subject: args are the PDA seeds"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"idl with the program id as subject: args are the PDA seeds refuses to guess: wrong seed count, bad pubkey, missing functionName, args on a non-program subject","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"refuses to guess: wrong seed count, bad pubkey, missing functionName, args on a non-program subject"},{"ancestorTitles":["idl with the program id as subject: args are the PDA seeds"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"idl with the program id as subject: args are the PDA seeds refuses layouts the IDL gives no seeds for, and conflicting seed templates","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"refuses layouts the IDL gives no seeds for, and conflicting seed templates"}],"endTime":1792494884719,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/read-state/__tests__/svm-account.spec.ts","startTime":1792494884634,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["native rule codec — multiple actions"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"native rule codec — multiple actions encodes each action with its own limits, in input order, sharing the rule expiry","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"encodes each action with its own limits, in input order, sharing the rule expiry"},{"ancestorTitles":["native rule codec — multiple actions"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"native rule codec — multiple actions the single-action shorthand is unchanged and equals a one-entry actions list","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"the single-action shorthand is unchanged and equals a one-entry actions list"},{"ancestorTitles":["native rule codec — multiple actions"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"native rule codec — multiple actions round-trips: stored terms decode to the actions form and re-encode identically","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"round-trips: stored terms decode to the actions form and re-encode identically"},{"ancestorTitles":["native rule codec — multiple actions"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"native rule codec — multiple actions a single stored action decodes to the shorthand form","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"a single stored action decodes to the shorthand form"},{"ancestorTitles":["native rule codec — multiple actions"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"native rule codec — multiple actions per-action expiries are kept: the rule shows the earliest, later actions carry their own","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"per-action expiries are kept: the rule shows the earliest, later actions carry their own"},{"ancestorTitles":["native rule codec — multiple actions"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"native rule codec — multiple actions rejects a null action before signing","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects a null action before signing"},{"ancestorTitles":["native rule codec — multiple actions"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"native rule codec — multiple actions rejects a non-object action before signing","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects a non-object action before signing"},{"ancestorTitles":["native rule codec — multiple actions"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"native rule codec — multiple actions rejects missing rule expiry despite overrides before signing","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects missing rule expiry despite overrides before signing"},{"ancestorTitles":["native rule codec — multiple actions"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"native rule codec — multiple actions rejects expired rule expiry despite overrides before signing","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects expired rule expiry despite overrides before signing"},{"ancestorTitles":["native rule codec — multiple actions"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"native rule codec — multiple actions rejects an empty actions list before signing","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects an empty actions list before signing"},{"ancestorTitles":["native rule codec — multiple actions"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"native rule codec — multiple actions rejects more than the contract limit before signing","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects more than the contract limit before signing"},{"ancestorTitles":["native rule codec — multiple actions"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"native rule codec — multiple actions rejects a repeated target and selector before signing","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects a repeated target and selector before signing"},{"ancestorTitles":["native rule codec — multiple actions"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"native rule codec — multiple actions rejects top-level action fields mixed with actions before signing","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects top-level action fields mixed with actions before signing"},{"ancestorTitles":["native rule codec — multiple actions"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"native rule codec — multiple actions rejects an invalid action, reported with its index before signing","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects an invalid action, reported with its index before signing"},{"ancestorTitles":["native rule codec — multiple actions"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"native rule codec — multiple actions the same function on different targets is allowed (distinct action IDs)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"the same function on different targets is allowed (distinct action IDs)"},{"ancestorTitles":["prepareRules — one session, one rule ID, several actions"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"prepareRules — one session, one rule ID, several actions builds one session action per native action, each with its own URP envelope on the Push chain","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"builds one session action per native action, each with its own URP envelope on the Push chain"},{"ancestorTitles":["prepareRules — one session, one rule ID, several actions"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"prepareRules — one session, one rule ID, several actions refuses an infrastructure target in any action, naming it","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"refuses an infrastructure target in any action, naming it"},{"ancestorTitles":["prepareRules — one session, one rule ID, several actions"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"prepareRules — one session, one rule ID, several actions one multi-action rule is one rule per agent on Push, so it never collides with itself","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"one multi-action rule is one rule per agent on Push, so it never collides with itself"},{"ancestorTitles":["utils.agentic.decodeRules — several actions"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"utils.agentic.decodeRules — several actions decodes a multi-action session into the actions form","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"decodes a multi-action session into the actions form"},{"ancestorTitles":["rules.get / rules.list — reading several stored actions"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"rules.get / rules.list — reading several stored actions decodes every action in engine order at one block","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"decodes every action in engine order at one block"}],"endTime":1792494885072,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/native-multi-action.spec.ts","startTime":1792494884720,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["generation registry"],"duration":5,"failureDetails":[],"failureMessages":[],"fullName":"generation registry ships Donut v6 only; other networks are unsupported","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"ships Donut v6 only; other networks are unsupported"},{"ancestorTitles":["generation registry"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"generation registry initialize against any wallet fails before signing when no generation is registered","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"initialize against any wallet fails before signing when no generation is registered"},{"ancestorTitles":["Donut log-range limit"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Donut log-range limit covers the full range in contiguous pages of at most 1,000 blocks","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"covers the full range in contiguous pages of at most 1,000 blocks"},{"ancestorTitles":["native PRC20 metadata"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"native PRC20 metadata accepts a zero address word only for the registered gas token","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"accepts a zero address word only for the registered gas token"},{"ancestorTitles":["initialize with agenticWallet — door resolution"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"initialize with agenticWallet — door resolution owner → owner door; universal account context keeps signer identity separate","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"owner → owner door; universal account context keeps signer identity separate"},{"ancestorTitles":["initialize with agenticWallet — door resolution"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"initialize with agenticWallet — door resolution agent named in an enabled rule → agent door, even when that rule is expired","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"agent named in an enabled rule → agent door, even when that rule is expired"},{"ancestorTitles":["initialize with agenticWallet — door resolution"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"initialize with agenticWallet — door resolution anyone else → NOT_OWNER_OR_AGENT","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"anyone else → NOT_OWNER_OR_AGENT"},{"ancestorTitles":["initialize with agenticWallet — door resolution"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"initialize with agenticWallet — door resolution no code → WALLET_NOT_DEPLOYED; a contract that is not an AGW → NOT_AGENTIC_WALLET","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"no code → WALLET_NOT_DEPLOYED; a contract that is not an AGW → NOT_AGENTIC_WALLET"},{"ancestorTitles":["initialize with agenticWallet — door resolution"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"initialize with agenticWallet — door resolution wiring that does not match the registered generation is refused","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"wiring that does not match the registered generation is refused"},{"ancestorTitles":["per-send rule selection"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"per-send rule selection exactly one enabled (agent, chain) match is selected, at one block","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"exactly one enabled (agent, chain) match is selected, at one block"},{"ancestorTitles":["per-send rule selection"],"duration":5,"failureDetails":[],"failureMessages":[],"fullName":"per-send rule selection zero matches → NO_RULES_FOR_CHAIN","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"zero matches → NO_RULES_FOR_CHAIN"},{"ancestorTitles":["per-send rule selection"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"per-send rule selection direct-grant duplicates → AMBIGUOUS_RULE listing every candidate, never an arbitrary pick","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"direct-grant duplicates → AMBIGUOUS_RULE listing every candidate, never an arbitrary pick"},{"ancestorTitles":["per-send rule selection"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"per-send rule selection a revoked rule is not a candidate; lookups are not cached between sends","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"a revoked rule is not a candidate; lookups are not cached between sends"},{"ancestorTitles":["per-send rule selection"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"per-send rule selection an RPC failure is an error, never an empty rule set","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"an RPC failure is an error, never an empty rule set"},{"ancestorTitles":["rules.list / rules.get"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"rules.list / rules.get decodes active native records with spend","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"decodes active native records with spend"},{"ancestorTitles":["rules.list / rules.get"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"rules.list / rules.get public records contain native spend","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"public records contain native spend"},{"ancestorTitles":["rules.list / rules.get"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"rules.list / rules.get lists native and universal rules without truncating","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"lists native and universal rules without truncating"},{"ancestorTitles":["rules.list / rules.get"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"rules.list / rules.get an empty source-token address is native only for the chain registry gas token","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"an empty source-token address is native only for the chain registry gas token"},{"ancestorTitles":["rules.list / rules.get"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"rules.list / rules.get unknown and revoked IDs both return RULE_NOT_FOUND without history reconstruction","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"unknown and revoked IDs both return RULE_NOT_FOUND without history reconstruction"},{"ancestorTitles":["wallet reads"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"wallet reads derive defaults to the next unused index; beyond it is refused","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"derive defaults to the next unused index; beyond it is refused"},{"ancestorTitles":["wallet reads"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"wallet reads derivation drift between the factory and the SDK mirror is detected (obligation 13)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"derivation drift between the factory and the SDK mirror is detected (obligation 13)"},{"ancestorTitles":["wallet reads"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"wallet reads list returns deployed slots with labels and rule counts plus the next undeployed slot","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"list returns deployed slots with labels and rule counts plus the next undeployed slot"},{"ancestorTitles":["wallet reads"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"wallet reads an empty owner lists only slot 0, undeployed","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"an empty owner lists only slot 0, undeployed"},{"ancestorTitles":["wallet reads"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"wallet reads reads current labels without depending on deployment logs","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"reads current labels without depending on deployment logs"},{"ancestorTitles":["wallet reads"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"wallet reads info of the signer’s next slot describes it as undeployed; other undeployed addresses are refused","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"info of the signer’s next slot describes it as undeployed; other undeployed addresses are refused"},{"ancestorTitles":["checkpoints"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"checkpoints orders by block, tx and log index and counts five ticks for a replacement in one block","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"orders by block, tx and log index and counts five ticks for a replacement in one block"},{"ancestorTitles":["checkpoints"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"checkpoints a count/event mismatch is reported (after one retry) rather than returned","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"a count/event mismatch is reported (after one retry) rather than returned"},{"ancestorTitles":["checkpoints"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"checkpoints uses retained logs only when a complete sequence proves no checkpoint was pruned","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"uses retained logs only when a complete sequence proves no checkpoint was pruned"},{"ancestorTitles":["checkpoints"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"checkpoints does not skip arbitrary RPC errors or a pruned explicit sinceBlock range","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"does not skip arbitrary RPC errors or a pruned explicit sinceBlock range"},{"ancestorTitles":["checkpoints"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"checkpoints validateSequence checks contiguity and the count","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"validateSequence checks contiguity and the count"}],"endTime":1792494885355,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/reads-context.spec.ts","startTime":1792494885073,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["prepareRules — spec 1.b checks before any signature"],"duration":5,"failureDetails":[],"failureMessages":[],"fullName":"prepareRules — spec 1.b checks before any signature AGENT_IS_OWNER","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"AGENT_IS_OWNER"},{"ancestorTitles":["prepareRules — spec 1.b checks before any signature"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"prepareRules — spec 1.b checks before any signature allows multiple rules for the same agent and chain","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"allows multiple rules for the same agent and chain"},{"ancestorTitles":["prepareRules — spec 1.b checks before any signature"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"prepareRules — spec 1.b checks before any signature native and universal rules coexist for the same agent","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"native and universal rules coexist for the same agent"},{"ancestorTitles":["prepareRules — spec 1.b checks before any signature"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"prepareRules — spec 1.b checks before any signature removed ref inputs fail explicitly instead of being silently dropped","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"removed ref inputs fail explicitly instead of being silently dropped"},{"ancestorTitles":["prepareRules — spec 1.b checks before any signature"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"prepareRules — spec 1.b checks before any signature refuses infrastructure targets the contracts would reject","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"refuses infrastructure targets the contracts would reject"},{"ancestorTitles":["prepareRules — spec 1.b checks before any signature"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"prepareRules — spec 1.b checks before any signature a universal rule naming the Push chain is rejected","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"a universal rule naming the Push chain is rejected"},{"ancestorTitles":["prepareRules — spec 1.b checks before any signature"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"prepareRules — spec 1.b checks before any signature valid native rules produce one Session each, agent bound in the validator config","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"valid native rules produce one Session each, agent bound in the validator config"},{"ancestorTitles":["universal rules — validated, then capability-gated (A01, A05)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"universal rules — validated, then capability-gated (A01, A05) structural validation runs before the capability gate","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"structural validation runs before the capability gate"},{"ancestorTitles":["universal rules — validated, then capability-gated (A01, A05)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"universal rules — validated, then capability-gated (A01, A05) approval policy belongs to UI/marketplace; structurally valid approval calls are accepted","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"approval policy belongs to UI/marketplace; structurally valid approval calls are accepted"},{"ancestorTitles":["universal rules — validated, then capability-gated (A01, A05)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"universal rules — validated, then capability-gated (A01, A05) a beneficiary must be an address argument of a known signature","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"a beneficiary must be an address argument of a known signature"},{"ancestorTitles":["universal rules — validated, then capability-gated (A01, A05)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"universal rules — validated, then capability-gated (A01, A05) requires resolved wallet/token context and named SVM IDL inputs","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"requires resolved wallet/token context and named SVM IDL inputs"},{"ancestorTitles":["internal generation codecs (pure)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"internal generation codecs (pure) encodeRules → decodeRules round-trips a native rule","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"encodeRules → decodeRules round-trips a native rule"},{"ancestorTitles":["internal generation codecs (pure)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"internal generation codecs (pure) decodeRules rejects a foreign-chain envelope carrying native terms","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"decodeRules rejects a foreign-chain envelope carrying native terms"},{"ancestorTitles":["internal generation codecs (pure)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"internal generation codecs (pure) pure decoding resolves known v5 assets and preserves the exact beneficiary offset","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"pure decoding resolves known v5 assets and preserves the exact beneficiary offset"},{"ancestorTitles":["internal generation codecs (pure)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"internal generation codecs (pure) actionId accepts signatures and hex alike","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"actionId accepts signatures and hex alike"}],"endTime":1792494885562,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/rules-policy.spec.ts","startTime":1792494885356,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["read(subject, options) grammar → ReadQuery"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"read(subject, options) grammar → ReadQuery derives Token-2022 ATAs using the selected program","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"derives Token-2022 ATAs using the selected program"},{"ancestorTitles":["read(subject, options) grammar → ReadQuery"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"read(subject, options) grammar → ReadQuery EVM: no query key → native balance of subject","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"EVM: no query key → native balance of subject"},{"ancestorTitles":["read(subject, options) grammar → ReadQuery"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"read(subject, options) grammar → ReadQuery EVM: token → balanceOf(subject) on the token, typed uint256","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"EVM: token → balanceOf(subject) on the token, typed uint256"},{"ancestorTitles":["read(subject, options) grammar → ReadQuery"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"read(subject, options) grammar → ReadQuery EVM: abi + functionName → typed call on subject","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"EVM: abi + functionName → typed call on subject"},{"ancestorTitles":["read(subject, options) grammar → ReadQuery"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"read(subject, options) grammar → ReadQuery EVM: storageSlot","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"EVM: storageSlot"},{"ancestorTitles":["read(subject, options) grammar → ReadQuery"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"read(subject, options) grammar → ReadQuery SVM: native → lamports of subject; token → the ATA derived offline","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"SVM: native → lamports of subject; token → the ATA derived offline"},{"ancestorTitles":["read(subject, options) grammar → ReadQuery"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"read(subject, options) grammar → ReadQuery web2: subject is the URL, options.web2 becomes the http query","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"web2: subject is the URL, options.web2 becomes the http query"},{"ancestorTitles":["read(subject, options) grammar → ReadQuery"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"read(subject, options) grammar → ReadQuery rejects two query keys","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects two query keys"},{"ancestorTitles":["read(subject, options) grammar → ReadQuery"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"read(subject, options) grammar → ReadQuery rejects functionName without abi","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects functionName without abi"},{"ancestorTitles":["read(subject, options) grammar → ReadQuery"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"read(subject, options) grammar → ReadQuery rejects abi without functionName","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects abi without functionName"},{"ancestorTitles":["read(subject, options) grammar → ReadQuery"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"read(subject, options) grammar → ReadQuery rejects web2 key on a blockchain","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects web2 key on a blockchain"},{"ancestorTitles":["read(subject, options) grammar → ReadQuery"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"read(subject, options) grammar → ReadQuery rejects web2 chain without web2 key","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects web2 chain without web2 key"},{"ancestorTitles":["read(subject, options) grammar → ReadQuery"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"read(subject, options) grammar → ReadQuery rejects web2 subject not https","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects web2 subject not https"},{"ancestorTitles":["read(subject, options) grammar → ReadQuery"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"read(subject, options) grammar → ReadQuery rejects EVM subject not an address","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects EVM subject not an address"},{"ancestorTitles":["read(subject, options) grammar → ReadQuery"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"read(subject, options) grammar → ReadQuery rejects EVM token not an address","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects EVM token not an address"},{"ancestorTitles":["read(subject, options) grammar → ReadQuery"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"read(subject, options) grammar → ReadQuery rejects SVM storageSlot","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects SVM storageSlot"},{"ancestorTitles":["read(subject, options) grammar → ReadQuery"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"read(subject, options) grammar → ReadQuery rejects SVM abi call","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects SVM abi call"},{"ancestorTitles":["toBuildReadSpecParams"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"toBuildReadSpecParams maps pinning / callback / refund options and the destination","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"maps pinning / callback / refund options and the destination"},{"ancestorTitles":["toBuildReadSpecParams"],"duration":8,"failureDetails":[],"failureMessages":[],"fullName":"toBuildReadSpecParams defaults callback gas to 500_000n for the registry and custom targets; an explicit value wins","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"defaults callback gas to 500_000n for the registry and custom targets; an explicit value wins"},{"ancestorTitles":["toBuildReadSpecParams"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"toBuildReadSpecParams keeps SVM and web2 pinning internal","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"keeps SVM and web2 pinning internal"},{"ancestorTitles":["toBuildReadSpecParams"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toBuildReadSpecParams lifecycle options map advanced.* to the tracker","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"lifecycle options map advanced.* to the tracker"}],"endTime":1792494885652,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/read-state/__tests__/read-params.spec.ts","startTime":1792494885567,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["revalidateRead"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"revalidateRead accepts an old but valid preparation without changing any field","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"accepts an old but valid preparation without changing any field"},{"ancestorTitles":["revalidateRead"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"revalidateRead rejects remaining escrow of 1n wei without changing the prepared payment","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"rejects remaining escrow of 1n wei without changing the prepared payment"},{"ancestorTitles":["revalidateRead"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"revalidateRead rejects remaining escrow of 199999999999999n wei without changing the prepared payment","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"rejects remaining escrow of 199999999999999n wei without changing the prepared payment"},{"ancestorTitles":["revalidateRead"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"revalidateRead accepts the exact affordability boundary, using base fee rather than suggested gas price","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"accepts the exact affordability boundary, using base fee rather than suggested gas price"},{"ancestorTitles":["revalidateRead"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"revalidateRead rejects a rise in base fee even when the protocol fee and gas suggestion are unchanged","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects a rise in base fee even when the protocol fee and gas suggestion are unchanged"},{"ancestorTitles":["revalidateRead"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"revalidateRead does not guess when the base fee is missing","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"does not guess when the base fee is missing"},{"ancestorTitles":["revalidateRead"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"revalidateRead uses a reported zero base fee without substituting a sizing floor","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"uses a reported zero base fee without substituting a sizing floor"},{"ancestorTitles":["revalidateRead"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"revalidateRead rejects changed expiry conditions","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects changed expiry conditions"},{"ancestorTitles":["revalidateRead"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"revalidateRead rejects changed fee conditions","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects changed fee conditions"},{"ancestorTitles":["revalidateRead"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"revalidateRead rejects changed budget conditions","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects changed budget conditions"},{"ancestorTitles":["revalidateRead"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"revalidateRead rejects changed height conditions","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects changed height conditions"},{"ancestorTitles":["revalidateRead"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"revalidateRead rejects changed blocked conditions","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects changed blocked conditions"},{"ancestorTitles":["preparation progress"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"preparation progress emits requested, preflight and assembled in order","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"emits requested, preflight and assembled in order"},{"ancestorTitles":["preparation progress"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"preparation progress emits height failure without claiming the spec was assembled","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"emits height failure without claiming the spec was assembled"},{"ancestorTitles":["preparation progress"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"preparation progress warns with header names, never secret values","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"warns with header names, never secret values"}],"endTime":1792494885730,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/read-state/__tests__/revalidate-read.spec.ts","startTime":1792494885653,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"decodes the overload selected by the encoded arguments","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"decodes the overload selected by the encoded arguments"},{"ancestorTitles":["EVM query envelope"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"EVM query envelope golden vector: evm.accountBalance","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"golden vector: evm.accountBalance"},{"ancestorTitles":["EVM query envelope"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"EVM query envelope golden vector: evm.contractCall.rawCalldata","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"golden vector: evm.contractCall.rawCalldata"},{"ancestorTitles":["EVM query envelope"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"EVM query envelope golden vector: evm.storageSlot.bigintSlot","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"golden vector: evm.storageSlot.bigintSlot"},{"ancestorTitles":["EVM query envelope"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"EVM query envelope is abi.encode of ONE tuple (0x20 head offset), not three parameters","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"is abi.encode of ONE tuple (0x20 head offset), not three parameters"},{"ancestorTitles":["EVM query envelope"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"EVM query envelope AccountBalance payload is abi.encode(address) — 32 bytes, not the raw 20","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"AccountBalance payload is abi.encode(address) — 32 bytes, not the raw 20"},{"ancestorTitles":["EVM query envelope"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"EVM query envelope contractCall with abi encodes the call and records an evmCall result shape","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"contractCall with abi encodes the call and records an evmCall result shape"},{"ancestorTitles":["EVM query envelope"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"EVM query envelope encodes nonpayable and payable functions — validators simulate them with eth_call","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"encodes nonpayable and payable functions — validators simulate them with eth_call"},{"ancestorTitles":["EVM query envelope"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"EVM query envelope rejects an unknown function and a bad target","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"rejects an unknown function and a bad target"},{"ancestorTitles":["EVM query envelope"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"EVM query envelope normalises storage slots given as bigint or short hex to bytes32","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"normalises storage slots given as bigint or short hex to bytes32"},{"ancestorTitles":["EVM query envelope"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"EVM query envelope rejects an out-of-range blockNumber","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects an out-of-range blockNumber"}],"endTime":1792494885806,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/read-state/__tests__/envelope-evm.spec.ts","startTime":1792494885734,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["unfunded AGW SVM wire fixture gate"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"unfunded AGW SVM wire fixture gate records program fingerprints, slot and the actual IDL-decoded counter/config","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"records program fingerprints, slot and the actual IDL-decoded counter/config"},{"ancestorTitles":["unfunded AGW SVM wire fixture gate"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"unfunded AGW SVM wire fixture gate rejects an RPC for another cluster before reading account state","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"rejects an RPC for another cluster before reading account state"},{"ancestorTitles":["unfunded AGW SVM wire fixture gate"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"unfunded AGW SVM wire fixture gate rejects a non-executable program before reading ProgramData","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"rejects a non-executable program before reading ProgramData"},{"ancestorTitles":["unfunded AGW SVM wire fixture gate"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"unfunded AGW SVM wire fixture gate rejects a paused gateway using the actual Config decoder","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects a paused gateway using the actual Config decoder"},{"ancestorTitles":["unfunded AGW SVM wire fixture gate"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"unfunded AGW SVM wire fixture gate rejects a substituted counter owner and an incompatible discriminator","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"rejects a substituted counter owner and an incompatible discriminator"},{"ancestorTitles":["unfunded AGW SVM wire fixture gate"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"unfunded AGW SVM wire fixture gate rejects missing ProgramData rather than treating program metadata as delivery proof","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects missing ProgramData rather than treating program metadata as delivery proof"}],"endTime":1792494885887,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/svm-wire-fixture.spec.ts","startTime":1792494885807,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["SVM query envelope"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"SVM query envelope golden vector: svm.lamportBalance","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"golden vector: svm.lamportBalance"},{"ancestorTitles":["SVM query envelope"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"SVM query envelope golden vector: svm.splTokenAccount.minSlot0","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"golden vector: svm.splTokenAccount.minSlot0"},{"ancestorTitles":["SVM query envelope"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"SVM query envelope golden vector: svm.rawAccountData","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"golden vector: svm.rawAccountData"},{"ancestorTitles":["SVM query envelope"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"SVM query envelope is a single tuple with a 0x20 head offset and an empty payload","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"is a single tuple with a 0x20 head offset and an empty payload"},{"ancestorTitles":["SVM query envelope"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"SVM query envelope owner bytes: base58 → exactly 32 bytes; raw bytes accepted; anything else rejected","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"owner bytes: base58 → exactly 32 bytes; raw bytes accepted; anything else rejected"},{"ancestorTitles":["SVM query envelope"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"SVM query envelope result shapes: balances are uint256, raw account data is raw","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"result shapes: balances are uint256, raw account data is raw"},{"ancestorTitles":["SVM query envelope"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"SVM query envelope derives the associated token address deterministically (matches spl-token)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"derives the associated token address deterministically (matches spl-token)"},{"ancestorTitles":["SVM query envelope"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"SVM query envelope rejects an out-of-range minSlot","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects an out-of-range minSlot"}],"endTime":1792494885965,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/read-state/__tests__/envelope-svm.spec.ts","startTime":1792494885888,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["decodeReadResult"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"decodeReadResult decodes signed and dynamic Web2 values in extract order without rescaling","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"decodes signed and dynamic Web2 values in extract order without rescaling"},{"ancestorTitles":["decodeReadResult"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"decodeReadResult uses viem semantics for a single dynamic array output","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"uses viem semantics for a single dynamic array output"},{"ancestorTitles":["decodeReadResult"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"decodeReadResult uint256 — EVM balance / SVM lamports / SPL amount (real Donut bytes)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"uint256 — EVM balance / SVM lamports / SPL amount (real Donut bytes)"},{"ancestorTitles":["decodeReadResult"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"decodeReadResult bytes32 — storage slot","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"bytes32 — storage slot"},{"ancestorTitles":["decodeReadResult"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"decodeReadResult raw — passthrough, including empty","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"raw — passthrough, including empty"},{"ancestorTitles":["decodeReadResult"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"decodeReadResult evmCall — viem unwraps one output and preserves multiple outputs as a tuple","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"evmCall — viem unwraps one output and preserves multiple outputs as a tuple"},{"ancestorTitles":["decodeReadResult"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"decodeReadResult web2 — FLAT argument list, one value per extract, in order (real Donut bytes)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"web2 — FLAT argument list, one value per extract, in order (real Donut bytes)"},{"ancestorTitles":["decodeReadResult"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"decodeReadResult web2 — decoding against the WRONG extract list throws instead of mis-decoding","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"web2 — decoding against the WRONG extract list throws instead of mis-decoding"},{"ancestorTitles":["decodeReadResult"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"decodeReadResult rejects wrong sizes, empty data for typed shapes, and non-hex","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"rejects wrong sizes, empty data for typed shapes, and non-hex"}],"endTime":1792494886038,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/read-state/__tests__/result-decoder.spec.ts","startTime":1792494885970,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["AGW Solana finalization quote context"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AGW Solana finalization quote context uses the wallet identity and actual source mint for SPL rent budgeting","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"uses the wallet identity and actual source mint for SPL rent budgeting"},{"ancestorTitles":["AGW Solana finalization quote context"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AGW Solana finalization quote context native transfers carry no SPL mint or ATA requirement","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"native transfers carry no SPL mint or ATA requirement"},{"ancestorTitles":["AGW Solana finalization quote context"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AGW Solana finalization quote context zero-burn instruction quotes do not add a transfer ATA requirement","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"zero-burn instruction quotes do not add a transfer ATA requirement"},{"ancestorTitles":["AGW Solana finalization quote context"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AGW Solana finalization quote context an asset from another chain fails route validation without a quote","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"an asset from another chain fails route validation without a quote"},{"ancestorTitles":["AGW Solana finalization quote context"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AGW Solana finalization quote context decodes the real precompile word when a Solidity string ABI cannot decode it","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"decodes the real precompile word when a Solidity string ABI cannot decode it"},{"ancestorTitles":["AGW Solana finalization quote context"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AGW Solana finalization quote context does not fabricate a mint when both metadata representations fail","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"does not fabricate a mint when both metadata representations fail"},{"ancestorTitles":["AGW Solana finalization quote context"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AGW Solana finalization quote context uses the current registered SPL mint when Donut metadata returns a zero word","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"uses the current registered SPL mint when Donut metadata returns a zero word"},{"ancestorTitles":["AGW Solana finalization quote context"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"AGW Solana finalization quote context canonicalizes a decoded SPL mint before resolving its PRC20 mapping","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"canonicalizes a decoded SPL mint before resolving its PRC20 mapping"}],"endTime":1792494886283,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/svm-quote.spec.ts","startTime":1792494886039,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["detectUniversalTxSvm log index handling"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"detectUniversalTxSvm log index handling uses the legacy Solana logMessages index for pre-emit_cpi transactions","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"uses the legacy Solana logMessages index for pre-emit_cpi transactions"},{"ancestorTitles":["detectUniversalTxSvm log index handling"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"detectUniversalTxSvm log index handling decodes emit_cpi inner instructions and uses the gateway-event ordinal","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"decodes emit_cpi inner instructions and uses the gateway-event ordinal"}],"endTime":1792494886352,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/universal-tx-detector/__tests__/detector-svm-log-index.spec.ts","startTime":1792494886285,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["PC20 address codec — EVM"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"PC20 address codec — EVM left-pads a 20-byte address to bytes32","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"left-pads a 20-byte address to bytes32"},{"ancestorTitles":["PC20 address codec — EVM"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PC20 address codec — EVM round-trips and returns the checksummed form","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"round-trips and returns the checksummed form"},{"ancestorTitles":["PC20 address codec — EVM"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"PC20 address codec — EVM rejects the zero address","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects the zero address"},{"ancestorTitles":["PC20 address codec — EVM"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PC20 address codec — EVM rejects a malformed address","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects a malformed address"},{"ancestorTitles":["PC20 address codec — EVM"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"PC20 address codec — EVM rejects a bytes32 whose high bytes are set","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects a bytes32 whose high bytes are set"},{"ancestorTitles":["PC20 address codec — SVM"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PC20 address codec — SVM round-trips base58 through the raw 32-byte form","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"round-trips base58 through the raw 32-byte form"},{"ancestorTitles":["PC20 address codec — SVM"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PC20 address codec — SVM accepts the hex form and normalizes it back to base58","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"accepts the hex form and normalizes it back to base58"},{"ancestorTitles":["PC20 address codec — SVM"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PC20 address codec — SVM rejects the default public key","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects the default public key"},{"ancestorTitles":["PC20 address codec — SVM"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PC20 address codec — SVM rejects a malformed base58 key","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects a malformed base58 key"},{"ancestorTitles":["isZeroBytes32"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"isZeroBytes32 detects the unset registry value","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"detects the unset registry value"},{"ancestorTitles":["isZeroBytes32"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"isZeroBytes32 rejects decoding an unset value rather than returning the zero address","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects decoding an unset value rather than returning the zero address"}],"endTime":1792494886423,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/pc20/__tests__/address-codec.spec.ts","startTime":1792494886353,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["detector-svm — argument normalization"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"detector-svm — argument normalization renames snake_case keys classify.ts reads via camelCase","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"renames snake_case keys classify.ts reads via camelCase"},{"ancestorTitles":["detector-svm — argument normalization"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"detector-svm — argument normalization adds `to` alias for RevertUniversalTx.revertRecipient","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"adds `to` alias for RevertUniversalTx.revertRecipient"},{"ancestorTitles":["detector-svm — argument normalization"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"detector-svm — argument normalization surfaces UniversalTx fromCEA as a boolean and preserves tx_type enum as number","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"surfaces UniversalTx fromCEA as a boolean and preserves tx_type enum as number"},{"ancestorTitles":["detector-svm — argument normalization"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"detector-svm — argument normalization normalizeSolanaSignature round-trips 0x-hex ↔ base58 and leaves base58 untouched","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"normalizeSolanaSignature round-trips 0x-hex ↔ base58 and leaves base58 untouched"},{"ancestorTitles":["detector-svm — argument normalization"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"detector-svm — argument normalization extractTxTypeIndex resolves every declared variant and returns undefined for unknown ones","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"extractTxTypeIndex resolves every declared variant and returns undefined for unknown ones"}],"endTime":1792494886494,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/universal-tx-detector/__tests__/detector-svm.spec.ts","startTime":1792494886427,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["MOVEABLE_TOKEN_CONSTANTS (C-2: external chain tokens)","ETHEREUM_SEPOLIA"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"MOVEABLE_TOKEN_CONSTANTS (C-2: external chain tokens) ETHEREUM_SEPOLIA should expose USDT with correct metadata","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"should expose USDT with correct metadata"},{"ancestorTitles":["MOVEABLE_TOKEN_CONSTANTS (C-2: external chain tokens)","ETHEREUM_SEPOLIA"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"MOVEABLE_TOKEN_CONSTANTS (C-2: external chain tokens) ETHEREUM_SEPOLIA should expose ETH as native token","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should expose ETH as native token"},{"ancestorTitles":["MOVEABLE_TOKEN_CONSTANTS (C-2: external chain tokens)","ETHEREUM_SEPOLIA"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"MOVEABLE_TOKEN_CONSTANTS (C-2: external chain tokens) ETHEREUM_SEPOLIA should expose USDC","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should expose USDC"},{"ancestorTitles":["MOVEABLE_TOKEN_CONSTANTS (C-2: external chain tokens)","ETHEREUM_SEPOLIA"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"MOVEABLE_TOKEN_CONSTANTS (C-2: external chain tokens) ETHEREUM_SEPOLIA should expose WETH","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should expose WETH"},{"ancestorTitles":["MOVEABLE_TOKEN_CONSTANTS (C-2: external chain tokens)","ETHEREUM_SEPOLIA"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"MOVEABLE_TOKEN_CONSTANTS (C-2: external chain tokens) ETHEREUM_SEPOLIA should expose stETH","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should expose stETH"},{"ancestorTitles":["MOVEABLE_TOKEN_CONSTANTS (C-2: external chain tokens)","ARBITRUM_SEPOLIA"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"MOVEABLE_TOKEN_CONSTANTS (C-2: external chain tokens) ARBITRUM_SEPOLIA should expose USDT","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should expose USDT"},{"ancestorTitles":["MOVEABLE_TOKEN_CONSTANTS (C-2: external chain tokens)","ARBITRUM_SEPOLIA"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"MOVEABLE_TOKEN_CONSTANTS (C-2: external chain tokens) ARBITRUM_SEPOLIA should expose ETH as native","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should expose ETH as native"},{"ancestorTitles":["MOVEABLE_TOKEN_CONSTANTS (C-2: external chain tokens)","BASE_SEPOLIA"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"MOVEABLE_TOKEN_CONSTANTS (C-2: external chain tokens) BASE_SEPOLIA should expose USDT and USDC","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should expose USDT and USDC"},{"ancestorTitles":["MOVEABLE_TOKEN_CONSTANTS (C-2: external chain tokens)","BNB_TESTNET"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"MOVEABLE_TOKEN_CONSTANTS (C-2: external chain tokens) BNB_TESTNET should expose USDT","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should expose USDT"},{"ancestorTitles":["MOVEABLE_TOKEN_CONSTANTS (C-2: external chain tokens)","BNB_TESTNET"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"MOVEABLE_TOKEN_CONSTANTS (C-2: external chain tokens) BNB_TESTNET should expose USDC","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should expose USDC"},{"ancestorTitles":["MOVEABLE_TOKEN_CONSTANTS (C-2: external chain tokens)","BNB_TESTNET"],"duration":6,"failureDetails":[],"failureMessages":[],"fullName":"MOVEABLE_TOKEN_CONSTANTS (C-2: external chain tokens) BNB_TESTNET should throw for SOL (unavailable on BNB)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should throw for SOL (unavailable on BNB)"},{"ancestorTitles":["MOVEABLE_TOKEN_CONSTANTS (C-2: external chain tokens)","SOLANA_DEVNET"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"MOVEABLE_TOKEN_CONSTANTS (C-2: external chain tokens) SOLANA_DEVNET should expose SOL as native token","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should expose SOL as native token"},{"ancestorTitles":["MOVEABLE_TOKEN_CONSTANTS (C-2: external chain tokens)","SOLANA_DEVNET"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"MOVEABLE_TOKEN_CONSTANTS (C-2: external chain tokens) SOLANA_DEVNET should expose USDT","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should expose USDT"},{"ancestorTitles":["MOVEABLE_TOKEN_CONSTANTS (C-2: external chain tokens)","SOLANA_DEVNET"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"MOVEABLE_TOKEN_CONSTANTS (C-2: external chain tokens) SOLANA_DEVNET should throw for ETH (unavailable on Solana)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should throw for ETH (unavailable on Solana)"},{"ancestorTitles":["MOVEABLE_TOKEN_CONSTANTS (C-2: external chain tokens)","ETHEREUM_MAINNET"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"MOVEABLE_TOKEN_CONSTANTS (C-2: external chain tokens) ETHEREUM_MAINNET should expose ETH, USDT, WETH","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should expose ETH, USDT, WETH"},{"ancestorTitles":["MOVEABLE_TOKEN_CONSTANTS.PUSH_TESTNET_DONUT (C-3: outward tokens)","deployed stable PRC-20 addresses on Push Chain"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"MOVEABLE_TOKEN_CONSTANTS.PUSH_TESTNET_DONUT (C-3: outward tokens) deployed stable PRC-20 addresses on Push Chain should use the current USDT deployment addresses","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"should use the current USDT deployment addresses"},{"ancestorTitles":["MOVEABLE_TOKEN_CONSTANTS.PUSH_TESTNET_DONUT (C-3: outward tokens)","deployed stable PRC-20 addresses on Push Chain"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"MOVEABLE_TOKEN_CONSTANTS.PUSH_TESTNET_DONUT (C-3: outward tokens) deployed stable PRC-20 addresses on Push Chain should use the current USDC BSC deployment address","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should use the current USDC BSC deployment address"},{"ancestorTitles":["MOVEABLE_TOKEN_CONSTANTS.PUSH_TESTNET_DONUT (C-3: outward tokens)","native wrapped tokens"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"MOVEABLE_TOKEN_CONSTANTS.PUSH_TESTNET_DONUT (C-3: outward tokens) native wrapped tokens should expose pEth with correct sourceChain and prc20Address","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"should expose pEth with correct sourceChain and prc20Address"},{"ancestorTitles":["MOVEABLE_TOKEN_CONSTANTS.PUSH_TESTNET_DONUT (C-3: outward tokens)","native wrapped tokens"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"MOVEABLE_TOKEN_CONSTANTS.PUSH_TESTNET_DONUT (C-3: outward tokens) native wrapped tokens should expose pEthArb sourced from Arbitrum","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should expose pEthArb sourced from Arbitrum"},{"ancestorTitles":["MOVEABLE_TOKEN_CONSTANTS.PUSH_TESTNET_DONUT (C-3: outward tokens)","native wrapped tokens"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"MOVEABLE_TOKEN_CONSTANTS.PUSH_TESTNET_DONUT (C-3: outward tokens) native wrapped tokens should expose pEthBase sourced from Base","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should expose pEthBase sourced from Base"},{"ancestorTitles":["MOVEABLE_TOKEN_CONSTANTS.PUSH_TESTNET_DONUT (C-3: outward tokens)","native wrapped tokens"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"MOVEABLE_TOKEN_CONSTANTS.PUSH_TESTNET_DONUT (C-3: outward tokens) native wrapped tokens should expose pBnb sourced from BNB","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should expose pBnb sourced from BNB"},{"ancestorTitles":["MOVEABLE_TOKEN_CONSTANTS.PUSH_TESTNET_DONUT (C-3: outward tokens)","native wrapped tokens"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"MOVEABLE_TOKEN_CONSTANTS.PUSH_TESTNET_DONUT (C-3: outward tokens) native wrapped tokens should expose pSol sourced from Solana","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"should expose pSol sourced from Solana"},{"ancestorTitles":["MOVEABLE_TOKEN_CONSTANTS.PUSH_TESTNET_DONUT (C-3: outward tokens)","USDT chain-suffix accessor"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"MOVEABLE_TOKEN_CONSTANTS.PUSH_TESTNET_DONUT (C-3: outward tokens) USDT chain-suffix accessor should expose USDT.eth from Ethereum Sepolia","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"should expose USDT.eth from Ethereum Sepolia"},{"ancestorTitles":["MOVEABLE_TOKEN_CONSTANTS.PUSH_TESTNET_DONUT (C-3: outward tokens)","USDT chain-suffix accessor"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"MOVEABLE_TOKEN_CONSTANTS.PUSH_TESTNET_DONUT (C-3: outward tokens) USDT chain-suffix accessor should expose USDT.arb from Arbitrum","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should expose USDT.arb from Arbitrum"},{"ancestorTitles":["MOVEABLE_TOKEN_CONSTANTS.PUSH_TESTNET_DONUT (C-3: outward tokens)","USDT chain-suffix accessor"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"MOVEABLE_TOKEN_CONSTANTS.PUSH_TESTNET_DONUT (C-3: outward tokens) USDT chain-suffix accessor should expose USDT.base from Base","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should expose USDT.base from Base"},{"ancestorTitles":["MOVEABLE_TOKEN_CONSTANTS.PUSH_TESTNET_DONUT (C-3: outward tokens)","USDT chain-suffix accessor"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"MOVEABLE_TOKEN_CONSTANTS.PUSH_TESTNET_DONUT (C-3: outward tokens) USDT chain-suffix accessor should expose USDT.bsc from BSC","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should expose USDT.bsc from BSC"},{"ancestorTitles":["MOVEABLE_TOKEN_CONSTANTS.PUSH_TESTNET_DONUT (C-3: outward tokens)","USDT chain-suffix accessor"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"MOVEABLE_TOKEN_CONSTANTS.PUSH_TESTNET_DONUT (C-3: outward tokens) USDT chain-suffix accessor should keep USDT.bnb as a deprecated alias","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should keep USDT.bnb as a deprecated alias"},{"ancestorTitles":["MOVEABLE_TOKEN_CONSTANTS.PUSH_TESTNET_DONUT (C-3: outward tokens)","USDT chain-suffix accessor"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"MOVEABLE_TOKEN_CONSTANTS.PUSH_TESTNET_DONUT (C-3: outward tokens) USDT chain-suffix accessor should expose USDT.sol from Solana","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should expose USDT.sol from Solana"},{"ancestorTitles":["MOVEABLE_TOKEN_CONSTANTS.PUSH_TESTNET_DONUT (C-3: outward tokens)","USDT chain-suffix accessor"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"MOVEABLE_TOKEN_CONSTANTS.PUSH_TESTNET_DONUT (C-3: outward tokens) USDT chain-suffix accessor USDT.eth and USDT.sol should have different prc20Addresses","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"USDT.eth and USDT.sol should have different prc20Addresses"},{"ancestorTitles":["MOVEABLE_TOKEN_CONSTANTS.PUSH_TESTNET_DONUT (C-3: outward tokens)","USDC chain-suffix accessor"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"MOVEABLE_TOKEN_CONSTANTS.PUSH_TESTNET_DONUT (C-3: outward tokens) USDC chain-suffix accessor should expose USDC.eth from Ethereum Sepolia","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should expose USDC.eth from Ethereum Sepolia"},{"ancestorTitles":["MOVEABLE_TOKEN_CONSTANTS.PUSH_TESTNET_DONUT (C-3: outward tokens)","USDC chain-suffix accessor"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"MOVEABLE_TOKEN_CONSTANTS.PUSH_TESTNET_DONUT (C-3: outward tokens) USDC chain-suffix accessor should expose USDC.arb from Arbitrum","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should expose USDC.arb from Arbitrum"},{"ancestorTitles":["MOVEABLE_TOKEN_CONSTANTS.PUSH_TESTNET_DONUT (C-3: outward tokens)","USDC chain-suffix accessor"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"MOVEABLE_TOKEN_CONSTANTS.PUSH_TESTNET_DONUT (C-3: outward tokens) USDC chain-suffix accessor should expose USDC.base from Base","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should expose USDC.base from Base"},{"ancestorTitles":["MOVEABLE_TOKEN_CONSTANTS.PUSH_TESTNET_DONUT (C-3: outward tokens)","USDC chain-suffix accessor"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"MOVEABLE_TOKEN_CONSTANTS.PUSH_TESTNET_DONUT (C-3: outward tokens) USDC chain-suffix accessor should expose USDC.sol from Solana","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should expose USDC.sol from Solana"},{"ancestorTitles":["MOVEABLE_TOKEN_CONSTANTS.PUSH_TESTNET_DONUT (C-3: outward tokens)","USDC chain-suffix accessor"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"MOVEABLE_TOKEN_CONSTANTS.PUSH_TESTNET_DONUT (C-3: outward tokens) USDC chain-suffix accessor should expose USDC.bsc from BSC","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should expose USDC.bsc from BSC"},{"ancestorTitles":["MOVEABLE_TOKEN_CONSTANTS.PUSH_TESTNET_DONUT (C-3: outward tokens)","USDC chain-suffix accessor"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"MOVEABLE_TOKEN_CONSTANTS.PUSH_TESTNET_DONUT (C-3: outward tokens) USDC chain-suffix accessor should keep USDC.bnb as a deprecated alias","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should keep USDC.bnb as a deprecated alias"},{"ancestorTitles":["MOVEABLE_TOKEN_CONSTANTS.PUSH_TESTNET_DONUT (C-3: outward tokens)","PushChainMoveableToken interface compliance"],"duration":5,"failureDetails":[],"failureMessages":[],"fullName":"MOVEABLE_TOKEN_CONSTANTS.PUSH_TESTNET_DONUT (C-3: outward tokens) PushChainMoveableToken interface compliance all tokens should have required PushChainMoveableToken fields","invocations":1,"location":null,"numPassingAsserts":150,"retryReasons":[],"status":"passed","title":"all tokens should have required PushChainMoveableToken fields"},{"ancestorTitles":["PAYABLE_TOKEN_CONSTANTS (C-4: payable tokens)","ETHEREUM_SEPOLIA"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PAYABLE_TOKEN_CONSTANTS (C-4: payable tokens) ETHEREUM_SEPOLIA should expose USDT","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should expose USDT"},{"ancestorTitles":["PAYABLE_TOKEN_CONSTANTS (C-4: payable tokens)","ETHEREUM_SEPOLIA"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PAYABLE_TOKEN_CONSTANTS (C-4: payable tokens) ETHEREUM_SEPOLIA should expose ETH as native","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should expose ETH as native"},{"ancestorTitles":["PAYABLE_TOKEN_CONSTANTS (C-4: payable tokens)","ETHEREUM_SEPOLIA"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PAYABLE_TOKEN_CONSTANTS (C-4: payable tokens) ETHEREUM_SEPOLIA should expose USDC","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should expose USDC"},{"ancestorTitles":["PAYABLE_TOKEN_CONSTANTS (C-4: payable tokens)","ETHEREUM_SEPOLIA"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PAYABLE_TOKEN_CONSTANTS (C-4: payable tokens) ETHEREUM_SEPOLIA should expose stETH","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should expose stETH"},{"ancestorTitles":["PAYABLE_TOKEN_CONSTANTS (C-4: payable tokens)","BNB_TESTNET"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PAYABLE_TOKEN_CONSTANTS (C-4: payable tokens) BNB_TESTNET should expose USDT","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should expose USDT"},{"ancestorTitles":["PAYABLE_TOKEN_CONSTANTS (C-4: payable tokens)","BNB_TESTNET"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PAYABLE_TOKEN_CONSTANTS (C-4: payable tokens) BNB_TESTNET should expose USDC","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"should expose USDC"},{"ancestorTitles":["PAYABLE_TOKEN_CONSTANTS (C-4: payable tokens)","SOLANA_DEVNET"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PAYABLE_TOKEN_CONSTANTS (C-4: payable tokens) SOLANA_DEVNET should expose SOL as native token (payable)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should expose SOL as native token (payable)"},{"ancestorTitles":["PAYABLE_TOKEN_CONSTANTS (C-4: payable tokens)","ARBITRUM_SEPOLIA"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PAYABLE_TOKEN_CONSTANTS (C-4: payable tokens) ARBITRUM_SEPOLIA should expose ETH and USDT","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should expose ETH and USDT"},{"ancestorTitles":["PAYABLE_TOKEN_CONSTANTS (C-4: payable tokens)","BASE_SEPOLIA"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PAYABLE_TOKEN_CONSTANTS (C-4: payable tokens) BASE_SEPOLIA should expose ETH, USDT, USDC","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"should expose ETH, USDT, USDC"},{"ancestorTitles":["PAYABLE_TOKEN_CONSTANTS (C-4: payable tokens)","ETHEREUM_MAINNET"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PAYABLE_TOKEN_CONSTANTS (C-4: payable tokens) ETHEREUM_MAINNET should expose ETH and USDT","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"should expose ETH and USDT"}],"endTime":1792494886560,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/constants/__tests__/token-constants.spec.ts","startTime":1792494886496,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"reads exact non-native source identity from the string ABI","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"reads exact non-native source identity from the string ABI"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"reads exact non-native source identity from the address ABI","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"reads exact non-native source identity from the address ABI"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"accepts an address-word zero only for the registered native gas token","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"accepts an address-word zero only for the registered native gas token"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"preserves a failed read when neither source encoding can be read","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"preserves a failed read when neither source encoding can be read"}],"endTime":1792494886875,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/prc20-source-encoding.spec.ts","startTime":1792494886561,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["PC20 tracked leg selection (SVM)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PC20 tracked leg selection (SVM) default behaviour is unchanged: second gateway event wins","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"default behaviour is unchanged: second gateway event wins"},{"ancestorTitles":["PC20 tracked leg selection (SVM)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PC20 tracked leg selection (SVM) preferPC20 selects the burn leg rather than the trailing funds leg","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"preferPC20 selects the burn leg rather than the trailing funds leg"},{"ancestorTitles":["PC20 tracked leg selection (SVM)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PC20 tracked leg selection (SVM) finds the PC20 leg regardless of emission order","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"finds the PC20 leg regardless of emission order"},{"ancestorTitles":["PC20 tracked leg selection (SVM)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PC20 tracked leg selection (SVM) falls back to default selection when no PC20 leg is present","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"falls back to default selection when no PC20 leg is present"},{"ancestorTitles":["PC20 tracked leg selection (SVM)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PC20 tracked leg selection (SVM) a single PC20 event is selected under either mode","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"a single PC20 event is selected under either mode"},{"ancestorTitles":["PC20 tracked leg selection (SVM)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"PC20 tracked leg selection (SVM) uses emit_cpi gateway-event ordinals and preserves PC20 selection","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"uses emit_cpi gateway-event ordinals and preserves PC20 selection"}],"endTime":1792494886916,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/pc20-tracked-leg-svm.spec.ts","startTime":1792494886877,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["SVM payload encoding (post-Option-B fix)","encoder dispatch"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"SVM payload encoding (post-Option-B fix) encoder dispatch SVM signer dispatches to the SVM Borsh encoder, EVM signer to ABI","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"SVM signer dispatches to the SVM Borsh encoder, EVM signer to ABI"},{"ancestorTitles":["SVM payload encoding (post-Option-B fix)","SVM encoder bounds"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"SVM payload encoding (post-Option-B fix) SVM encoder bounds rejects Riyanshu’s exact value (still > u64)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects Riyanshu’s exact value (still > u64)"},{"ancestorTitles":["SVM payload encoding (post-Option-B fix)","SVM encoder bounds"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"SVM payload encoding (post-Option-B fix) SVM encoder bounds passes at u64 max (the boundary)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"passes at u64 max (the boundary)"},{"ancestorTitles":["SVM payload encoding (post-Option-B fix)","EVM-signer workaround documented in the error message"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"SVM payload encoding (post-Option-B fix) EVM-signer workaround documented in the error message encodes Riyanshu’s value cleanly via ABI uint256","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"encodes Riyanshu’s value cleanly via ABI uint256"}],"endTime":1792494886971,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/__tests__/signing.spec.ts","startTime":1792494886919,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["normalize — PushChainOutboundSummary.externalTxHash for SVM","normalizeOutboundSummaryForUser"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"normalize — PushChainOutboundSummary.externalTxHash for SVM normalizeOutboundSummaryForUser returns the SAME reference for an EVM destination (passthrough)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"returns the SAME reference for an EVM destination (passthrough)"},{"ancestorTitles":["normalize — PushChainOutboundSummary.externalTxHash for SVM","normalizeOutboundSummaryForUser"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"normalize — PushChainOutboundSummary.externalTxHash for SVM normalizeOutboundSummaryForUser converts 0x-hex → base58 for Solana Devnet destination","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"converts 0x-hex → base58 for Solana Devnet destination"},{"ancestorTitles":["normalize — PushChainOutboundSummary.externalTxHash for SVM","normalizeOutboundSummaryForUser"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"normalize — PushChainOutboundSummary.externalTxHash for SVM normalizeOutboundSummaryForUser is idempotent — running the helper twice yields the same value","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"is idempotent — running the helper twice yields the same value"},{"ancestorTitles":["normalize — PushChainOutboundSummary.externalTxHash for SVM","normalizeOutboundSummaryForUser"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"normalize — PushChainOutboundSummary.externalTxHash for SVM normalizeOutboundSummaryForUser passes through a value that already lacks 0x prefix (already base58)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"passes through a value that already lacks 0x prefix (already base58)"},{"ancestorTitles":["normalize — PushChainOutboundSummary.externalTxHash for SVM","normalizeOutboundSummaryForUser"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"normalize — PushChainOutboundSummary.externalTxHash for SVM normalizeOutboundSummaryForUser passes through when externalTxHash is undefined","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"passes through when externalTxHash is undefined"},{"ancestorTitles":["normalize — PushChainOutboundSummary.externalTxHash for SVM","normalizeOutboundSummaryForUser"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"normalize — PushChainOutboundSummary.externalTxHash for SVM normalizeOutboundSummaryForUser does not mutate the input","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"does not mutate the input"},{"ancestorTitles":["normalize — PushChainOutboundSummary.externalTxHash for SVM","normalizeDetectionForUser"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"normalize — PushChainOutboundSummary.externalTxHash for SVM normalizeDetectionForUser returns same reference when pushChainTx is undefined","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"returns same reference when pushChainTx is undefined"},{"ancestorTitles":["normalize — PushChainOutboundSummary.externalTxHash for SVM","normalizeDetectionForUser"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"normalize — PushChainOutboundSummary.externalTxHash for SVM normalizeDetectionForUser returns same reference when no nested outbound needs normalization (EVM only)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"returns same reference when no nested outbound needs normalization (EVM only)"},{"ancestorTitles":["normalize — PushChainOutboundSummary.externalTxHash for SVM","normalizeDetectionForUser"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"normalize — PushChainOutboundSummary.externalTxHash for SVM normalizeDetectionForUser rewrites SVM externalTxHash inside pushChainTx.outboundHashes","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"rewrites SVM externalTxHash inside pushChainTx.outboundHashes"},{"ancestorTitles":["normalize — PushChainOutboundSummary.externalTxHash for SVM","normalizeChildInboundResolutionForUser"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"normalize — PushChainOutboundSummary.externalTxHash for SVM normalizeChildInboundResolutionForUser passes through pcTxHashes unchanged","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"passes through pcTxHashes unchanged"},{"ancestorTitles":["normalize — PushChainOutboundSummary.externalTxHash for SVM","normalizeChildInboundResolutionForUser"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"normalize — PushChainOutboundSummary.externalTxHash for SVM normalizeChildInboundResolutionForUser rewrites SVM externalTxHash inside outboundHashes","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"rewrites SVM externalTxHash inside outboundHashes"},{"ancestorTitles":["normalize — PushChainOutboundSummary.externalTxHash for SVM","normalizeCascadeNodeForUser"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"normalize — PushChainOutboundSummary.externalTxHash for SVM normalizeCascadeNodeForUser returns same reference when nothing in the tree needs normalization","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"returns same reference when nothing in the tree needs normalization"},{"ancestorTitles":["normalize — PushChainOutboundSummary.externalTxHash for SVM","normalizeCascadeNodeForUser"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"normalize — PushChainOutboundSummary.externalTxHash for SVM normalizeCascadeNodeForUser rewrites SVM externalTxHash in edge.relation (outbound) and recurses into edge.node","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"rewrites SVM externalTxHash in edge.relation (outbound) and recurses into edge.node"},{"ancestorTitles":["normalize — PushChainOutboundSummary.externalTxHash for SVM","normalizeCascadeNodeForUser"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"normalize — PushChainOutboundSummary.externalTxHash for SVM normalizeCascadeNodeForUser does not mutate the input tree","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"does not mutate the input tree"}],"endTime":1792494887026,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/universal-tx-detector/__tests__/normalize.spec.ts","startTime":1792494886972,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["IDs against contract-generated vectors (v5)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"IDs against contract-generated vectors (v5) rulesId(agent, nonce) = engine.getPermissionId — nonce 0","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"rulesId(agent, nonce) = engine.getPermissionId — nonce 0"},{"ancestorTitles":["IDs against contract-generated vectors (v5)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"IDs against contract-generated vectors (v5) rulesId(agent, nonce) = engine.getPermissionId — nonce 1","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"rulesId(agent, nonce) = engine.getPermissionId — nonce 1"},{"ancestorTitles":["IDs against contract-generated vectors (v5)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"IDs against contract-generated vectors (v5) rulesId(agent, nonce) = engine.getPermissionId — nonce 7","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"rulesId(agent, nonce) = engine.getPermissionId — nonce 7"},{"ancestorTitles":["IDs against contract-generated vectors (v5)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"IDs against contract-generated vectors (v5) rulesId(agent, nonce) = engine.getPermissionId — nonce 9223372036854775808","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"rulesId(agent, nonce) = engine.getPermissionId — nonce 9223372036854775808"},{"ancestorTitles":["IDs against contract-generated vectors (v5)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"IDs against contract-generated vectors (v5) rulesId(agent, nonce) = engine.getPermissionId — nonce 0","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"rulesId(agent, nonce) = engine.getPermissionId — nonce 0"},{"ancestorTitles":["IDs against contract-generated vectors (v5)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"IDs against contract-generated vectors (v5) rulesId(agent, nonce) = engine.getPermissionId — nonce 1","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"rulesId(agent, nonce) = engine.getPermissionId — nonce 1"},{"ancestorTitles":["IDs against contract-generated vectors (v5)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"IDs against contract-generated vectors (v5) rulesId(agent, nonce) = engine.getPermissionId — nonce 7","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"rulesId(agent, nonce) = engine.getPermissionId — nonce 7"},{"ancestorTitles":["IDs against contract-generated vectors (v5)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"IDs against contract-generated vectors (v5) rulesId(agent, nonce) = engine.getPermissionId — nonce 9223372036854775808","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"rulesId(agent, nonce) = engine.getPermissionId — nonce 9223372036854775808"},{"ancestorTitles":["IDs against contract-generated vectors (v5)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"IDs against contract-generated vectors (v5) rulesId(agent, nonce) = engine.getPermissionId — nonce 0","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"rulesId(agent, nonce) = engine.getPermissionId — nonce 0"},{"ancestorTitles":["IDs against contract-generated vectors (v5)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"IDs against contract-generated vectors (v5) rulesId(agent, nonce) = engine.getPermissionId — nonce 1","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"rulesId(agent, nonce) = engine.getPermissionId — nonce 1"},{"ancestorTitles":["IDs against contract-generated vectors (v5)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"IDs against contract-generated vectors (v5) rulesId(agent, nonce) = engine.getPermissionId — nonce 7","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"rulesId(agent, nonce) = engine.getPermissionId — nonce 7"},{"ancestorTitles":["IDs against contract-generated vectors (v5)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"IDs against contract-generated vectors (v5) rulesId(agent, nonce) = engine.getPermissionId — nonce 9223372036854775808","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"rulesId(agent, nonce) = engine.getPermissionId — nonce 9223372036854775808"},{"ancestorTitles":["IDs against contract-generated vectors (v5)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"IDs against contract-generated vectors (v5) deriveWallet mirrors factory.predictWallet for 0x90F79bf6EB2c4f870365E785982E1f101E93b906","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"deriveWallet mirrors factory.predictWallet for 0x90F79bf6EB2c4f870365E785982E1f101E93b906"},{"ancestorTitles":["IDs against contract-generated vectors (v5)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"IDs against contract-generated vectors (v5) deriveWallet mirrors factory.predictWallet for 0x1111111111111111111111111111111111111111","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"deriveWallet mirrors factory.predictWallet for 0x1111111111111111111111111111111111111111"},{"ancestorTitles":["IDs against contract-generated vectors (v5)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"IDs against contract-generated vectors (v5) actionId/configId: the policy holds an initialized config under exactly this key","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"actionId/configId: the policy holds an initialized config under exactly this key"},{"ancestorTitles":["IDs against contract-generated vectors (v5)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"IDs against contract-generated vectors (v5) rulesId rejects a grant nonce outside uint64","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rulesId rejects a grant nonce outside uint64"},{"ancestorTitles":["native rule codec"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"native rule codec encodes the session the contracts accepted and stored","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"encodes the session the contracts accepted and stored"},{"ancestorTitles":["native rule codec"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"native rule codec round-trips terms through the envelope and back to a public rule","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"round-trips terms through the envelope and back to a public rule"},{"ancestorTitles":["native rule codec"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"native rule codec decoding never invents argument indexes: a static array before a pin stays a raw offset","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"decoding never invents argument indexes: a static array before a pin stays a raw offset"},{"ancestorTitles":["native rule codec"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"native rule codec a decoded address pin re-encodes in argument form once the signature is restored","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"a decoded address pin re-encodes in argument form once the signature is restored"},{"ancestorTitles":["native rule codec"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"native rule codec offset-form pins must be exact words at a valid offset","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"offset-form pins must be exact words at a valid offset"},{"ancestorTitles":["native rule codec"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"native rule codec applies confirmed zero PC defaults and independent token/call defaults","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"applies confirmed zero PC defaults and independent token/call defaults"},{"ancestorTitles":["native rule codec"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"native rule codec rejects ambiguous arg-plus-offset authoring for both pins and amount","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"rejects ambiguous arg-plus-offset authoring for both pins and amount"},{"ancestorTitles":["native rule codec"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"native rule codec keeps an explicit zero as zero","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"keeps an explicit zero as zero"},{"ancestorTitles":["native rule codec"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"native rule codec value-only rules encode the reserved selector and refuse pins/amount","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"value-only rules encode the reserved selector and refuse pins/amount"},{"ancestorTitles":["native rule codec"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"native rule codec rejects past expiry before signing","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects past expiry before signing"},{"ancestorTitles":["native rule codec"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"native rule codec rejects zero target before signing","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects zero target before signing"},{"ancestorTitles":["native rule codec"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"native rule codec rejects too many pins before signing","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects too many pins before signing"},{"ancestorTitles":["native rule codec"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"native rule codec rejects pin needs a signature before signing","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects pin needs a signature before signing"},{"ancestorTitles":["native rule codec"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"native rule codec rejects pin on a dynamic argument before signing","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects pin on a dynamic argument before signing"},{"ancestorTitles":["native rule codec"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"native rule codec rejects pin index out of range before signing","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects pin index out of range before signing"},{"ancestorTitles":["native rule codec"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"native rule codec rejects pin value of the wrong type before signing","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects pin value of the wrong type before signing"},{"ancestorTitles":["native rule codec"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"native rule codec rejects amount on a non-uint before signing","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects amount on a non-uint before signing"},{"ancestorTitles":["native rule codec"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"native rule codec rejects amount also pinned before signing","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects amount also pinned before signing"},{"ancestorTitles":["native rule codec"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"native rule codec rejects negative cap before signing","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects negative cap before signing"},{"ancestorTitles":["native rule codec"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"native rule codec rejects maxCalls beyond uint32 before signing","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects maxCalls beyond uint32 before signing"},{"ancestorTitles":["native rule codec"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"native rule codec approval policy is external while caller-supplied pins remain ABI-validated","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"approval policy is external while caller-supplied pins remain ABI-validated"},{"ancestorTitles":["ABI layout offsets"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"ABI layout offsets accounts for dynamic heads and multi-word static tuples before the pinned argument","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"accounts for dynamic heads and multi-word static tuples before the pinned argument"},{"ancestorTitles":["ABI layout offsets"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ABI layout offsets rejects pinning a tuple","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects pinning a tuple"},{"ancestorTitles":["ABI layout offsets"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"ABI layout offsets parses hex, signature and value-only selectors","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"parses hex, signature and value-only selectors"},{"ancestorTitles":["wallet call encoders decode back to the same calls"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"wallet call encoders decode back to the same calls execute single uses packed ERC-7579 calldata","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"execute single uses packed ERC-7579 calldata"},{"ancestorTitles":["wallet call encoders decode back to the same calls"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"wallet call encoders decode back to the same calls execute batch uses abi.encode(Execution[])","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"execute batch uses abi.encode(Execution[])"},{"ancestorTitles":["wallet call encoders decode back to the same calls"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"wallet call encoders decode back to the same calls executeAsAgent carries the rule ID and one packed call","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"executeAsAgent carries the rule ID and one packed call"},{"ancestorTitles":["wallet call encoders decode back to the same calls"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"wallet call encoders decode back to the same calls unknown calldata is not mistaken for a wallet call","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"unknown calldata is not mistaken for a wallet call"}],"endTime":1792494887289,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/agentic/__tests__/codec.spec.ts","startTime":1792494887027,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["preflightRead"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"preflightRead keys the oracle height by the FULL CAIP-2 id and the fee/blocklist by the split pair","invocations":1,"location":null,"numPassingAsserts":11,"retryReasons":[],"status":"passed","title":"keys the oracle height by the FULL CAIP-2 id and the fee/blocklist by the split pair"},{"ancestorTitles":["preflightRead"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"preflightRead accepts the explicit { chainNamespace, chainId } form","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"accepts the explicit { chainNamespace, chainId } form"},{"ancestorTitles":["preflightRead"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"preflightRead web2 is heightless: a 0 oracle height is NOT an error","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"web2 is heightless: a 0 oracle height is NOT an error"},{"ancestorTitles":["preflightRead"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"preflightRead a blockchain with a 0 oracle height is unreadable → ReadHeightUnavailableError","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"a blockchain with a 0 oracle height is unreadable → ReadHeightUnavailableError"},{"ancestorTitles":["preflightRead"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"preflightRead a blocklisted domain fails fast","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"a blocklisted domain fails fast"},{"ancestorTitles":["preflightRead"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"preflightRead rejects a CAIP-2 string smuggled in as the namespace (would route as eip155:1:1 on the node)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects a CAIP-2 string smuggled in as the namespace (would route as eip155:1:1 on the node)"},{"ancestorTitles":["preflightRead"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"preflightRead rejects an unknown namespace before touching the chain","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"rejects an unknown namespace before touching the chain"}],"endTime":1792494887338,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/read-state/__tests__/preflight.spec.ts","startTime":1792494887290,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["ABI pins against the deployed UniversalCallback"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ABI pins against the deployed UniversalCallback registry read uses the deployed spec, query key and callback gas tuple","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"registry read uses the deployed spec, query key and callback gas tuple"},{"ancestorTitles":["ABI pins against the deployed UniversalCallback"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ABI pins against the deployed UniversalCallback requestExternalReadSelf uses the 7-field ReadSpec (with revertRecipient)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"requestExternalReadSelf uses the 7-field ReadSpec (with revertRecipient)"},{"ancestorTitles":["ABI pins against the deployed UniversalCallback"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ABI pins against the deployed UniversalCallback estimateFee is (string,string) — protocol fee only, no callbackGasLimit arg","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"estimateFee is (string,string) — protocol fee only, no callbackGasLimit arg"},{"ancestorTitles":["ABI pins against the deployed UniversalCallback"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ABI pins against the deployed UniversalCallback UniversalCore read getters","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"UniversalCore read getters"},{"ancestorTitles":["ABI pins against the deployed UniversalCallback"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"ABI pins against the deployed UniversalCallback addresses are the genesis predeploys on every network","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"addresses are the genesis predeploys on every network"},{"ancestorTitles":["ABI pins against the deployed UniversalCallback"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ABI pins against the deployed UniversalCallback contract constants","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"contract constants"}],"endTime":1792494887393,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/read-state/__tests__/abi-selectors.spec.ts","startTime":1792494887343,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["EvmClient — native currency symbol in error messages"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"EvmClient — native currency symbol in error messages getPushViemChain(PUSH_TESTNET_DONUT) exposes a chain whose native symbol is \"PC\"","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"getPushViemChain(PUSH_TESTNET_DONUT) exposes a chain whose native symbol is \"PC\""},{"ancestorTitles":["EvmClient — native currency symbol in error messages"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"EvmClient — native currency symbol in error messages EvmClient built with a Push chain threads it into its PublicClient","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"EvmClient built with a Push chain threads it into its PublicClient"},{"ancestorTitles":["EvmClient — native currency symbol in error messages"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"EvmClient — native currency symbol in error messages formats insufficient-funds error with \"PC\" when chain is Push","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"formats insufficient-funds error with \"PC\" when chain is Push"},{"ancestorTitles":["EvmClient — native currency symbol in error messages"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"EvmClient — native currency symbol in error messages mechanism: without a chain, viem formats value as \"ETH\"","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"mechanism: without a chain, viem formats value as \"ETH\""}],"endTime":1792494887445,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/vm-client/evm-client.chain-symbol.spec.ts","startTime":1792494887394,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"resolves verified Sepolia WETH for lowercase/checksummed address input","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"resolves verified Sepolia WETH for lowercase/checksummed address input"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolves verified Sepolia stETH for lowercase/checksummed address input","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"resolves verified Sepolia stETH for lowercase/checksummed address input"},{"ancestorTitles":[],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"preserves case-sensitive Solana identities while accepting EVM casing variations","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"preserves case-sensitive Solana identities while accepting EVM casing variations"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"never aliases mainnet ETH/WETH or a different chain WETH to Sepolia","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"never aliases mainnet ETH/WETH or a different chain WETH to Sepolia"}],"endTime":1792494887498,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/universal/prc20-address.spec.ts","startTime":1792494887448,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["deriveChildUniversalTxId (sha256 formula)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"deriveChildUniversalTxId (sha256 formula) matches the chain GetInboundUniversalTxKey for real Sepolia inbound","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"matches the chain GetInboundUniversalTxKey for real Sepolia inbound"},{"ancestorTitles":["deriveChildUniversalTxId (sha256 formula)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"deriveChildUniversalTxId (sha256 formula) handles externalTxHash without 0x prefix","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"handles externalTxHash without 0x prefix"},{"ancestorTitles":["deriveChildUniversalTxId (sha256 formula)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"deriveChildUniversalTxId (sha256 formula) includes logIndex — different indices produce different ids","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"includes logIndex — different indices produce different ids"},{"ancestorTitles":["deriveChildUniversalTxId (sha256 formula)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"deriveChildUniversalTxId (sha256 formula) normalizes SVM base58 signatures to the keeper hex form","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"normalizes SVM base58 signatures to the keeper hex form"},{"ancestorTitles":["derivePcUniversalTxId (sha256 formula, no logIndex)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"derivePcUniversalTxId (sha256 formula, no logIndex) matches the chain GetPcUniversalTxKey for real Push Chain outbound","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"matches the chain GetPcUniversalTxKey for real Push Chain outbound"},{"ancestorTitles":["resolveChildInboundsFromLogs"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveChildInboundsFromLogs derives child id and stitches pcTx/outboundTx from cosmos","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"derives child id and stitches pcTx/outboundTx from cosmos"},{"ancestorTitles":["resolveChildInboundsFromLogs"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveChildInboundsFromLogs marks notFound when cosmos returns null universalTx","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"marks notFound when cosmos returns null universalTx"},{"ancestorTitles":["resolveChildInboundsFromLogs"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveChildInboundsFromLogs records diagnostic + marks notFound when getUniversalTxByIdV2 throws","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"records diagnostic + marks notFound when getUniversalTxByIdV2 throws"},{"ancestorTitles":["resolveChildInboundsFromLogs"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"resolveChildInboundsFromLogs resolves one entry per inbound log","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"resolves one entry per inbound log"}],"endTime":1792494887550,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/universal-tx-detector/__tests__/child-inbounds.spec.ts","startTime":1792494887499,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["listAutoProbeChains"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"listAutoProbeChains puts Push CAIPs first","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"puts Push CAIPs first"},{"ancestorTitles":["detectUniversalTxAuto"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"detectUniversalTxAuto returns the first non-UNKNOWN detection in probe order","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"returns the first non-UNKNOWN detection in probe order"},{"ancestorTitles":["detectUniversalTxAuto"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"detectUniversalTxAuto returns undefined detection and UNKNOWN attempts when no chain matches","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"returns undefined detection and UNKNOWN attempts when no chain matches"},{"ancestorTitles":["detectUniversalTxAuto"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"detectUniversalTxAuto prefers Push Chain when both Push and Sepolia match","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"prefers Push Chain when both Push and Sepolia match"},{"ancestorTitles":["detectUniversalTxAuto"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"detectUniversalTxAuto records per-chain errors without failing the overall probe","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"records per-chain errors without failing the overall probe"},{"ancestorTitles":["detectUniversalTxAuto"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"detectUniversalTxAuto passes through probe options to detectUniversalTx","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"passes through probe options to detectUniversalTx"}],"endTime":1792494887601,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/universal-tx-detector/__tests__/auto-detect.spec.ts","startTime":1792494887553,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["SVM PC20 seeds"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"SVM PC20 seeds pins the seeds to the program source","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"pins the seeds to the program source"},{"ancestorTitles":["SVM PC20 seeds"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"SVM PC20 seeds pins the Pc20State length","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"pins the Pc20State length"},{"ancestorTitles":["derivePC20Mint"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"derivePC20Mint seeds on the raw 20-byte source asset, not a padded 32-byte form","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"seeds on the raw 20-byte source asset, not a padded 32-byte form"},{"ancestorTitles":["derivePC20Mint"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"derivePC20Mint is case-insensitive on the source address","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"is case-insensitive on the source address"},{"ancestorTitles":["derivePC20Mint"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"derivePC20Mint derives distinct mints for distinct sources","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"derives distinct mints for distinct sources"},{"ancestorTitles":["derivePC20Mint"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"derivePC20Mint rejects a malformed source address","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects a malformed source address"},{"ancestorTitles":["derivePC20Mint"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"derivePC20Mint matches predictSvmWrapperMint","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"matches predictSvmWrapperMint"},{"ancestorTitles":["derivePC20State"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"derivePC20State seeds on the mint","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"seeds on the mint"},{"ancestorTitles":["decodePc20State"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"decodePc20State decodes the account layout","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"decodes the account layout"},{"ancestorTitles":["decodePc20State"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"decodePc20State rejects a truncated account","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects a truncated account"},{"ancestorTitles":["validatePC20Mint"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"validatePC20Mint accepts a mutually consistent mint, state, and source","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"accepts a mutually consistent mint, state, and source"},{"ancestorTitles":["validatePC20Mint"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"validatePC20Mint rejects a state PDA that does not derive from the mint","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects a state PDA that does not derive from the mint"},{"ancestorTitles":["validatePC20Mint"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"validatePC20Mint rejects a state whose wrapped_mint is a different mint","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects a state whose wrapped_mint is a different mint"},{"ancestorTitles":["validatePC20Mint"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"validatePC20Mint rejects a source that disagrees with UniversalCore","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects a source that disagrees with UniversalCore"},{"ancestorTitles":["validatePC20Mint"],"duration":5,"failureDetails":[],"failureMessages":[],"fullName":"validatePC20Mint rejects a mint that does not re-derive from the stored source","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects a mint that does not re-derive from the stored source"},{"ancestorTitles":["buildPC20BurnAccounts"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildPC20BurnAccounts orders remaining accounts as [pc20_state, pc20_mint]","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"orders remaining accounts as [pc20_state, pc20_mint]"},{"ancestorTitles":["buildPC20BurnAccounts"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildPC20BurnAccounts passes no gateway token account","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"passes no gateway token account"},{"ancestorTitles":["buildPC20SvmDeliveryFields"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildPC20SvmDeliveryFields encodes SPL TransferChecked (index 12, u64 LE amount, decimals)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"encodes SPL TransferChecked (index 12, u64 LE amount, decimals)"},{"ancestorTitles":["buildPC20SvmDeliveryFields"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildPC20SvmDeliveryFields orders accounts source, mint, destination, owner with correct flags","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"orders accounts source, mint, destination, owner with correct flags"},{"ancestorTitles":["buildPC20SvmCeaBurnPayload"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildPC20SvmCeaBurnPayload starts with the send_universal_tx anchor discriminator","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"starts with the send_universal_tx anchor discriminator"},{"ancestorTitles":["buildPC20SvmCeaBurnPayload"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildPC20SvmCeaBurnPayload lays out SendUniversalTxIxArgs exactly (state.rs:67 field order)","invocations":1,"location":null,"numPassingAsserts":9,"retryReasons":[],"status":"passed","title":"lays out SendUniversalTxIxArgs exactly (state.rs:67 field order)"},{"ancestorTitles":["buildPC20SvmCeaBurnPayload"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"buildPC20SvmCeaBurnPayload orders accounts [state ro, mint w, ceaAta w, tokenProgram ro]","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"orders accounts [state ro, mint w, ceaAta w, tokenProgram ro]"}],"endTime":1792494887655,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/pc20/__tests__/svm.spec.ts","startTime":1792494887602,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"prepares exact selectors, binary output codes and literal zero arguments without inventing holes","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"prepares exact selectors, binary output codes and literal zero arguments without inventing holes"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"preserves WALLET/PARAM positions and resolves them independently of literal zeros","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"preserves WALLET/PARAM positions and resolves them independently of literal zeros"},{"ancestorTitles":[],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"encodes the deployed field and enum order and roundtrips a complete spec canonically","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"encodes the deployed field and enum order and roundtrips a complete spec canonically"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"roundtrips templates including principal-BPS targets and bounds","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"roundtrips templates including principal-BPS targets and bounds"},{"ancestorTitles":[],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"keeps a valid non-DFS topological logic order when decoding unchanged signed bytes","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"keeps a valid non-DFS topological logic order when decoding unchanged signed bytes"},{"ancestorTitles":[],"duration":6,"failureDetails":[],"failureMessages":[],"fullName":"rejects cycles, invalid indexes and unsupported template holes before encoding","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"rejects cycles, invalid indexes and unsupported template holes before encoding"},{"ancestorTitles":[],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"rejects malformed enums, trailing bytes, foreign wire and filled format ambiguity","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"rejects malformed enums, trailing bytes, foreign wire and filled format ambiguity"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"binds origin to marketplace, integer card version and principal with ABI words","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"binds origin to marketplace, integer card version and principal with ABI words"}],"endTime":1792494887696,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/job-spec/__tests__/codec.spec.ts","startTime":1792494887656,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["validateReadSpec — one row per contract revert"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"validateReadSpec — one row per contract revert a good spec passes","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"a good spec passes"},{"ancestorTitles":["validateReadSpec — one row per contract revert"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"validateReadSpec — one row per contract revert UniversalCallback.sol:98 empty chainNamespace → (b) => ({ ...b, spec: { ...b.spec, account: { ...b.spec.account, chainNamespace: '' } } })","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"UniversalCallback.sol:98 empty chainNamespace → (b) => ({ ...b, spec: { ...b.spec, account: { ...b.spec.account, chainNamespace: '' } } })"},{"ancestorTitles":["validateReadSpec — one row per contract revert"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"validateReadSpec — one row per contract revert UniversalCallback.sol:98 empty chainId → (b) => ({ ...b, spec: { ...b.spec, account: { ...b.spec.account, chainId: '' } } })","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"UniversalCallback.sol:98 empty chainId → (b) => ({ ...b, spec: { ...b.spec, account: { ...b.spec.account, chainId: '' } } })"},{"ancestorTitles":["validateReadSpec — one row per contract revert"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"validateReadSpec — one row per contract revert UniversalCallback.sol:100 empty owner → (b) => ({ ...b, spec: { ...b.spec, account: { ...b.spec.account, owner: '0x' } } })","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"UniversalCallback.sol:100 empty owner → (b) => ({ ...b, spec: { ...b.spec, account: { ...b.spec.account, owner: '0x' } } })"},{"ancestorTitles":["validateReadSpec — one row per contract revert"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"validateReadSpec — one row per contract revert UniversalCallback.sol:104 empty query → (b) => ({ ...b, spec: { ...b.spec, query: '0x' } })","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"UniversalCallback.sol:104 empty query → (b) => ({ ...b, spec: { ...b.spec, query: '0x' } })"},{"ancestorTitles":["validateReadSpec — one row per contract revert"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"validateReadSpec — one row per contract revert UniversalCallback.sol:107 minConfirmations 0 → (b) => ({ ...b, spec: { ...b.spec, minConfirmations: 0 } })","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"UniversalCallback.sol:107 minConfirmations 0 → (b) => ({ ...b, spec: { ...b.spec, minConfirmations: 0 } })"},{"ancestorTitles":["validateReadSpec — one row per contract revert"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"validateReadSpec — one row per contract revert uint16 overflow minConfirmations → (b) => ({ ...b, spec: { ...b.spec, minConfirmations: 70_000 } })","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"uint16 overflow minConfirmations → (b) => ({ ...b, spec: { ...b.spec, minConfirmations: 70_000 } })"},{"ancestorTitles":["validateReadSpec — one row per contract revert"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"validateReadSpec — one row per contract revert UniversalCallback.sol:131 blockNumber 0 on a chain with a height → (b) => ({ ...b, spec: { ...b.spec, blockNumber: 0n } })","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"UniversalCallback.sol:131 blockNumber 0 on a chain with a height → (b) => ({ ...b, spec: { ...b.spec, blockNumber: 0n } })"},{"ancestorTitles":["validateReadSpec — one row per contract revert"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"validateReadSpec — one row per contract revert UniversalCallback.sol:131 blockNumber above the oracle height → (b) => ({ ...b, spec: { ...b.spec, blockNumber: PF.observedChainHeight + 1n } })","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"UniversalCallback.sol:131 blockNumber above the oracle height → (b) => ({ ...b, spec: { ...b.spec, blockNumber: PF.observedChainHeight + 1n } })"},{"ancestorTitles":["validateReadSpec — one row per contract revert"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"validateReadSpec — one row per contract revert UniversalCallback.sol:129 heightless namespace with non-zero blockNumber → (b) => ({ ...b, preflight: { ...PF, observedChainHeight: 0n }, spec: { ...b.spec, blockNumber: 1n } })","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"UniversalCallback.sol:129 heightless namespace with non-zero blockNumber → (b) => ({ ...b, preflight: { ...PF, observedChainHeight: 0n }, spec: { ...b.spec, blockNumber: 1n } })"},{"ancestorTitles":["validateReadSpec — one row per contract revert"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"validateReadSpec — one row per contract revert UniversalCallback.sol:119 expiry == current height → (b) => ({ ...b, spec: { ...b.spec, expiryPushChainHeight: PF.pushBlockNumber } })","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"UniversalCallback.sol:119 expiry == current height → (b) => ({ ...b, spec: { ...b.spec, expiryPushChainHeight: PF.pushBlockNumber } })"},{"ancestorTitles":["validateReadSpec — one row per contract revert"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"validateReadSpec — one row per contract revert UniversalCallback.sol:122 zero revertRecipient → (b) => ({ ...b, spec: { ...b.spec, revertRecipient: '0x0000000000000000000000000000000000000000' } })","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"UniversalCallback.sol:122 zero revertRecipient → (b) => ({ ...b, spec: { ...b.spec, revertRecipient: '0x0000000000000000000000000000000000000000' } })"},{"ancestorTitles":["validateReadSpec — one row per contract revert"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"validateReadSpec — one row per contract revert UniversalCallback.sol:125 callbackGasLimit 0 → { callbackGasLimit: 0n }","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"UniversalCallback.sol:125 callbackGasLimit 0 → { callbackGasLimit: 0n }"},{"ancestorTitles":["validateReadSpec — one row per contract revert"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"validateReadSpec — one row per contract revert ReadTypes.sol:50 callbackGasLimit > 1_000_000 → { callbackGasLimit: 1000001n }","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"ReadTypes.sol:50 callbackGasLimit > 1_000_000 → { callbackGasLimit: 1000001n }"},{"ancestorTitles":["validateReadSpec — one row per contract revert"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"validateReadSpec — one row per contract revert UniversalCallback.sol:134 value below protocol fee → { value: 999n }","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"UniversalCallback.sol:134 value below protocol fee → { value: 999n }"},{"ancestorTitles":["validateReadSpec — one row per contract revert"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"validateReadSpec — one row per contract revert UniversalCallback.sol:137 value above maxFee → { value: 10001n }","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"UniversalCallback.sol:137 value above maxFee → { value: 10001n }"},{"ancestorTitles":["validateReadSpec — one row per contract revert"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"validateReadSpec — one row per contract revert node CanAffordCallback: value == fee leaves zero budget → { value: 1000n }","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"node CanAffordCallback: value == fee leaves zero budget → { value: 1000n }"},{"ancestorTitles":["validateReadSpec — one row per contract revert"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"validateReadSpec — one row per contract revert svm/read_executor.go:29 owner not 32 bytes on solana → (b) => ({ ...b, preflight: { ...PF, destination: (0, destination_1.resolveDestination)({ chainNamespace: 'solana', chainId: 'x' }) }, spec: { ...b.spec, account: { chainNamespace: 'solana', chainId: 'x', owner: OK_OWNER } } })","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"svm/read_executor.go:29 owner not 32 bytes on solana → (b) => ({ ...b, preflight: { ...PF, destination: (0, destination_1.resolveDestination)({ chainNamespace: 'solana', chainId: 'x' }) }, spec: { ...b.spec, account: { chainNamespace: 'solana', chainId: 'x', owner: OK_OWNER } } })"},{"ancestorTitles":["validateReadSpec — one row per contract revert"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"validateReadSpec — one row per contract revert heightless namespace with blockNumber 0 is valid","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"heightless namespace with blockNumber 0 is valid"},{"ancestorTitles":["validateReadSpec — one row per contract revert"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"validateReadSpec — one row per contract revert without a preflight, only the chain-independent rules apply","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"without a preflight, only the chain-independent rules apply"},{"ancestorTitles":["validateReadSpec — one row per contract revert"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"validateReadSpec — one row per contract revert reports every violation at once, not just the first","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"reports every violation at once, not just the first"},{"ancestorTitles":["validateReadSpec — one row per contract revert"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"validateReadSpec — one row per contract revert the thrown error carries the violations and the destination","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"the thrown error carries the violations and the destination"}],"endTime":1792494887733,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/read-state/__tests__/validate.spec.ts","startTime":1792494887698,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["Web2 query envelope"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Web2 query envelope golden vector: web2.get.twoExtracts.liveRead3870d2af","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"golden vector: web2.get.twoExtracts.liveRead3870d2af"},{"ancestorTitles":["Web2 query envelope"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Web2 query envelope golden vector: web2.post.body.headersScrambled","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"golden vector: web2.post.body.headersScrambled"},{"ancestorTitles":["Web2 query envelope"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Web2 query envelope is a single tuple with a 0x20 head offset","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"is a single tuple with a 0x20 head offset"},{"ancestorTitles":["Web2 query envelope"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Web2 query envelope round-trips through the decoder shape with defaults applied","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"round-trips through the decoder shape with defaults applied"},{"ancestorTitles":["Web2 query envelope"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Web2 query envelope canonicalises headers: sorted keys, no whitespace, identical bytes regardless of input order","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"canonicalises headers: sorted keys, no whitespace, identical bytes regardless of input order"},{"ancestorTitles":["Web2 query envelope"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Web2 query envelope warns — does not throw — on sensitive-looking header names","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"warns — does not throw — on sensitive-looking header names"},{"ancestorTitles":["Web2 query envelope"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"Web2 query envelope maps every value type and keeps decimals","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"maps every value type and keeps decimals"},{"ancestorTitles":["Web2 query envelope"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"Web2 query envelope accepts exactly 16 extracts and rejects 17 or 0","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"accepts exactly 16 extracts and rejects 17 or 0"},{"ancestorTitles":["Web2 query envelope"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"Web2 query envelope rejects http://, a body on GET, decimals on a non-numeric type, and a bad path","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"rejects http://, a body on GET, decimals on a non-numeric type, and a bad path"},{"ancestorTitles":["Web2 query envelope"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"Web2 query envelope POST with a body encodes the body bytes","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"POST with a body encodes the body bytes"}],"endTime":1792494887767,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/read-state/__tests__/envelope-web2.spec.ts","startTime":1792494887734,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["EvmClient dynamic gas estimation"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"EvmClient dynamic gas estimation serializes an estimate above the former 500k multicall limit","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"serializes an estimate above the former 500k multicall limit"},{"ancestorTitles":["EvmClient dynamic gas estimation"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"EvmClient dynamic gas estimation estimates empty-calldata transfers to EIP-7702 delegated accounts","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"estimates empty-calldata transfers to EIP-7702 delegated accounts"},{"ancestorTitles":["EvmClient dynamic gas estimation"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"EvmClient dynamic gas estimation keeps the 21k fast path for empty-calldata transfers to code-free EOAs","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"keeps the 21k fast path for empty-calldata transfers to code-free EOAs"},{"ancestorTitles":["EvmClient dynamic gas estimation"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"EvmClient dynamic gas estimation adds headroom for the observed AGW outbound estimate unless gas is explicit (undefined)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"adds headroom for the observed AGW outbound estimate unless gas is explicit (undefined)"},{"ancestorTitles":["EvmClient dynamic gas estimation"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"EvmClient dynamic gas estimation adds headroom for the observed AGW outbound estimate unless gas is explicit (500000)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"adds headroom for the observed AGW outbound estimate unless gas is explicit (500000)"}],"endTime":1792494887796,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/vm-client/evm-client.dynamic-gas.spec.ts","startTime":1792494887768,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["7702 estimation without guessed per-call ceilings"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"7702 estimation without guessed per-call ceilings uses a real estimate for an already delegated account when authorization RPC support is absent","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"uses a real estimate for an already delegated account when authorization RPC support is absent"},{"ancestorTitles":["7702 estimation without guessed per-call ceilings"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"7702 estimation without guessed per-call ceilings uses a delegation override for a fresh account only when authorization estimation fails","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"uses a delegation override for a fresh account only when authorization estimation fails"},{"ancestorTitles":["7702 estimation without guessed per-call ceilings"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"7702 estimation without guessed per-call ceilings does not broadcast a guessed gas budget when all supported estimates fail","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"does not broadcast a guessed gas budget when all supported estimates fail"}],"endTime":1792494887826,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/vm-client/evm-client.batch-gas.spec.ts","startTime":1792494887797,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"preserves arbitrary binary JobSpec bytes in the Solidity string slot with its original selector","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"preserves arbitrary binary JobSpec bytes in the Solidity string slot with its original selector"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"supports plain UTF-8 descriptions but refuses conflicting carriers","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"supports plain UTF-8 descriptions but refuses conflicting carriers"}],"endTime":1792494887855,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/market/__tests__/kernel-wire.spec.ts","startTime":1792494887827,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["svm-idl/registry — single-arg registerIdl(idl)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"svm-idl/registry — single-arg registerIdl(idl) registers an IDL keyed by toSvmHexAddress(idl.address)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"registers an IDL keyed by toSvmHexAddress(idl.address)"},{"ancestorTitles":["svm-idl/registry — single-arg registerIdl(idl)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"svm-idl/registry — single-arg registerIdl(idl) is idempotent — re-registering the same IDL is a no-op","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"is idempotent — re-registering the same IDL is a no-op"},{"ancestorTitles":["svm-idl/registry — single-arg registerIdl(idl)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"svm-idl/registry — single-arg registerIdl(idl) rejects non-Anchor input","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"rejects non-Anchor input"},{"ancestorTitles":["svm-idl/registry — single-arg registerIdl(idl)"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"svm-idl/registry — single-arg registerIdl(idl) rejects an IDL whose address is not a valid Solana pubkey","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects an IDL whose address is not a valid Solana pubkey"},{"ancestorTitles":["svm-idl/registry — single-arg registerIdl(idl)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"svm-idl/registry — single-arg registerIdl(idl) getRegisteredIdls returns normalized hex keys","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"getRegisteredIdls returns normalized hex keys"}],"endTime":1792494887886,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/svm-idl/registry.spec.ts","startTime":1792494887857,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["encodeAnchorIxData"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"encodeAnchorIxData matches hand-rolled receive_sol bytes for amount=0","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"matches hand-rolled receive_sol bytes for amount=0"},{"ancestorTitles":["encodeAnchorIxData"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"encodeAnchorIxData matches hand-rolled receive_sol bytes for non-zero amount","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"matches hand-rolled receive_sol bytes for non-zero amount"},{"ancestorTitles":["encodeAnchorIxData"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"encodeAnchorIxData accepts camelCase function name equivalent to snake_case IDL name","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"accepts camelCase function name equivalent to snake_case IDL name"},{"ancestorTitles":["encodeAnchorIxData"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"encodeAnchorIxData throws when instruction is not in IDL","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"throws when instruction is not in IDL"},{"ancestorTitles":["encodeAnchorIxData"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"encodeAnchorIxData throws on arg count mismatch","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"throws on arg count mismatch"},{"ancestorTitles":["isAnchorIdl"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"isAnchorIdl returns true for the test_counter IDL","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"returns true for the test_counter IDL"},{"ancestorTitles":["isAnchorIdl"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"isAnchorIdl returns false for an EVM ABI array","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"returns false for an EVM ABI array"},{"ancestorTitles":["isAnchorIdl"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"isAnchorIdl returns false for null/primitives","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"returns false for null/primitives"}],"endTime":1792494887914,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/svm-idl/ix-encoder.spec.ts","startTime":1792494887887,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"public read type contracts compile","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"public read type contracts compile"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"overload and package export type contracts compile","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"overload and package export type contracts compile"}],"endTime":1792494888164,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/read-state/__tests__/read-types.spec.ts","startTime":1792494887918,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["SVM gateway IDL"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"SVM gateway IDL includes the Anchor event CPI accounts for send_universal_tx","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"includes the Anchor event CPI accounts for send_universal_tx"}],"endTime":1792494888186,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/constants/__tests__/svm-gateway-idl.spec.ts","startTime":1792494888166,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["svm-idl normalize-address","toSvmHexAddress"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"svm-idl normalize-address toSvmHexAddress accepts canonical 0x-hex and returns lowercase","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"accepts canonical 0x-hex and returns lowercase"},{"ancestorTitles":["svm-idl normalize-address","toSvmHexAddress"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"svm-idl normalize-address toSvmHexAddress accepts base58 and returns the matching 0x-hex","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"accepts base58 and returns the matching 0x-hex"},{"ancestorTitles":["svm-idl normalize-address","toSvmHexAddress"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"svm-idl normalize-address toSvmHexAddress accepts the canonical System Program base58","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"accepts the canonical System Program base58"},{"ancestorTitles":["svm-idl normalize-address","toSvmHexAddress"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"svm-idl normalize-address toSvmHexAddress rejects hex with wrong length","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"rejects hex with wrong length"},{"ancestorTitles":["svm-idl normalize-address","toSvmHexAddress"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"svm-idl normalize-address toSvmHexAddress rejects base58 that decodes to a non-32-byte length","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects base58 that decodes to a non-32-byte length"},{"ancestorTitles":["svm-idl normalize-address","toSvmHexAddress"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"svm-idl normalize-address toSvmHexAddress rejects malformed base58 (contains 0/O/I/l)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects malformed base58 (contains 0/O/I/l)"},{"ancestorTitles":["svm-idl normalize-address","toSvmHexAddress"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"svm-idl normalize-address toSvmHexAddress rejects empty / non-string","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"rejects empty / non-string"},{"ancestorTitles":["svm-idl normalize-address","isValidSvmAddress"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"svm-idl normalize-address isValidSvmAddress accepts 0x7673075a980bfd5d6b1dffe99c31f63e8938519cc1c2af009dda5e568a94460d","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"accepts 0x7673075a980bfd5d6b1dffe99c31f63e8938519cc1c2af009dda5e568a94460d"},{"ancestorTitles":["svm-idl normalize-address","isValidSvmAddress"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"svm-idl normalize-address isValidSvmAddress accepts 8yNqjrMnFiFbVTVQcKij8tNWWTMdFkrDf9abCGgc2sgx","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"accepts 8yNqjrMnFiFbVTVQcKij8tNWWTMdFkrDf9abCGgc2sgx"},{"ancestorTitles":["svm-idl normalize-address","isValidSvmAddress"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"svm-idl normalize-address isValidSvmAddress accepts 11111111111111111111111111111111","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"accepts 11111111111111111111111111111111"},{"ancestorTitles":["svm-idl normalize-address","isValidSvmAddress"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"svm-idl normalize-address isValidSvmAddress rejects ","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects "},{"ancestorTitles":["svm-idl normalize-address","isValidSvmAddress"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"svm-idl normalize-address isValidSvmAddress rejects not-base58-at-all-!","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects not-base58-at-all-!"},{"ancestorTitles":["svm-idl normalize-address","isValidSvmAddress"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"svm-idl normalize-address isValidSvmAddress rejects 0xdeadbeef","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects 0xdeadbeef"},{"ancestorTitles":["svm-idl normalize-address","isValidSvmAddress"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"svm-idl normalize-address isValidSvmAddress rejects 123","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects 123"}],"endTime":1792494888201,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/svm-idl/normalize-address.spec.ts","startTime":1792494888187,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["classify()"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"classify() returns UNKNOWN for empty logs","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"returns UNKNOWN for empty logs"},{"ancestorTitles":["classify()"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"classify() classifies UniversalTx + fromCEA=false as INBOUND_FROM_EOA","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"classifies UniversalTx + fromCEA=false as INBOUND_FROM_EOA"},{"ancestorTitles":["classify()"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"classify() classifies UniversalTx + fromCEA=true as INBOUND_FROM_CEA","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"classifies UniversalTx + fromCEA=true as INBOUND_FROM_CEA"},{"ancestorTitles":["classify()"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"classify() classifies UniversalTxOutbound as OUTBOUND_INITIATED","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"classifies UniversalTxOutbound as OUTBOUND_INITIATED"},{"ancestorTitles":["classify()"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"classify() classifies UniversalTxFinalized as OUTBOUND_FINALIZED and enriches pushAccount from sibling executed log","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"classifies UniversalTxFinalized as OUTBOUND_FINALIZED and enriches pushAccount from sibling executed log"},{"ancestorTitles":["classify()"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"classify() classifies UniversalTxReverted as OUTBOUND_REVERTED","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"classifies UniversalTxReverted as OUTBOUND_REVERTED"},{"ancestorTitles":["classify()"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"classify() classifies RevertUniversalTx (gateway) as INBOUND_REVERTED with tuple array decode","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"classifies RevertUniversalTx (gateway) as INBOUND_REVERTED with tuple array decode"},{"ancestorTitles":["classify()"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"classify() priority: finalized beats executed-only","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"priority: finalized beats executed-only"},{"ancestorTitles":["classify()"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"classify() returns UNKNOWN when no known universal event matches","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"returns UNKNOWN when no known universal event matches"},{"ancestorTitles":["classify()"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"classify() classifyAll surfaces every universal-tx log independently","invocations":1,"location":null,"numPassingAsserts":9,"retryReasons":[],"status":"passed","title":"classifyAll surfaces every universal-tx log independently"},{"ancestorTitles":["classify()"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"classify() classifyAll returns empty array when no logs","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"classifyAll returns empty array when no logs"},{"ancestorTitles":["classify()"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"classify() classifyAll drops unrecognized event names","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"classifyAll drops unrecognized event names"},{"ancestorTitles":["classify()"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"classify() maps unknown txType to UNKNOWN","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"maps unknown txType to UNKNOWN"}],"endTime":1792494888217,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/universal-tx-detector/__tests__/classify.spec.ts","startTime":1792494888202,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["maxPCForGas quote helpers"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"maxPCForGas quote helpers adds the default 10% cap buffer and returns the matching native value","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"adds the default 10% cap buffer and returns the matching native value"},{"ancestorTitles":["maxPCForGas quote helpers"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"maxPCForGas quote helpers rounds buffered caps up so tiny gas legs are not rounded to zero","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"rounds buffered caps up so tiny gas legs are not rounded to zero"},{"ancestorTitles":["maxPCForGas quote helpers"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"maxPCForGas quote helpers supports an explicit zero-buffer cap","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"supports an explicit zero-buffer cap"},{"ancestorTitles":["maxPCForGas quote helpers"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"maxPCForGas quote helpers derives the gas leg from queryOutboundGasFee nativeValueForGas","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"derives the gas leg from queryOutboundGasFee nativeValueForGas"},{"ancestorTitles":["maxPCForGas quote helpers"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"maxPCForGas quote helpers returns an uncapped sentinel when the gas leg is zero","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"returns an uncapped sentinel when the gas leg is zero"},{"ancestorTitles":["maxPCForGas quote helpers"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"maxPCForGas quote helpers rejects impossible native/protocol fee combinations","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rejects impossible native/protocol fee combinations"},{"ancestorTitles":["maxPCForGas quote helpers"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"maxPCForGas quote helpers rejects invalid buffer values","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"rejects invalid buffer values"}],"endTime":1792494888232,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/max-pc-for-gas.spec.ts","startTime":1792494888218,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["decodeRevert"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"decodeRevert returns null on empty input","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"returns null on empty input"},{"ancestorTitles":["decodeRevert"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"decodeRevert returns null when no `ret 0x...` blob present","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"returns null when no `ret 0x...` blob present"},{"ancestorTitles":["decodeRevert"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"decodeRevert decodes a known parameterless custom selector","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"decodes a known parameterless custom selector"},{"ancestorTitles":["decodeRevert"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"decodeRevert decodes a known parameterized custom selector (extra ABI args appended)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"decodes a known parameterized custom selector (extra ABI args appended)"},{"ancestorTitles":["decodeRevert"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"decodeRevert decodes InvalidInput from CEA self-call validation","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"decodes InvalidInput from CEA self-call validation"},{"ancestorTitles":["decodeRevert"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"decodeRevert decodes GasPriceBelowBase from stale outbound gas-price overrides","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"decodes GasPriceBelowBase from stale outbound gas-price overrides"},{"ancestorTitles":["decodeRevert"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"decodeRevert decodes ABI-encoded Error(string) (\"STF\")","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"decodes ABI-encoded Error(string) (\"STF\")"},{"ancestorTitles":["decodeRevert"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"decodeRevert returns kind=unknown for unmapped selectors","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"returns kind=unknown for unmapped selectors"},{"ancestorTitles":["decodeRevert"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"decodeRevert returns null for malformed blob shorter than the 10-char selector","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"returns null for malformed blob shorter than the 10-char selector"},{"ancestorTitles":["decodeRevert"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"decodeRevert handles Error(string) with malformed length gracefully (falls through to unknown)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"handles Error(string) with malformed length gracefully (falls through to unknown)"},{"ancestorTitles":["decodeRevert"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"decodeRevert lowercases the selector regardless of input casing","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"lowercases the selector regardless of input casing"},{"ancestorTitles":["KNOWN_ERROR_SELECTORS table"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"KNOWN_ERROR_SELECTORS table every entry has name + hint + provenance","invocations":1,"location":null,"numPassingAsserts":36,"retryReasons":[],"status":"passed","title":"every entry has name + hint + provenance"},{"ancestorTitles":["KNOWN_ERROR_SELECTORS table"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"KNOWN_ERROR_SELECTORS table selectors are 10 chars (0x + 8 hex)","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"selectors are 10 chars (0x + 8 hex)"}],"endTime":1792494888244,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/error-decoder.spec.ts","startTime":1792494888233,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["PC20 protobuf fields"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PC20 protobuf fields round-trips OutboundObservation.pc20WrapperAddress (field 6)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"round-trips OutboundObservation.pc20WrapperAddress (field 6)"},{"ancestorTitles":["PC20 protobuf fields"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PC20 protobuf fields round-trips OutboundTx PC20 fields (22, 23)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"round-trips OutboundTx PC20 fields (22, 23)"},{"ancestorTitles":["PC20 protobuf fields"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PC20 protobuf fields defaults PC20 fields for a non-PC20 outbound","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"defaults PC20 fields for a non-PC20 outbound"},{"ancestorTitles":["PC20 protobuf fields"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"PC20 protobuf fields round-trips Inbound.isPc20 (field 14) alongside its neighbours","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"round-trips Inbound.isPc20 (field 14) alongside its neighbours"}],"endTime":1792494888258,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/internals/pc20/__tests__/tracking.spec.ts","startTime":1792494888248,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["formatters"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"formatters formats PC exactly by default","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"formats PC exactly by default"},{"ancestorTitles":["formatters"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"formatters formats PC with truncated precision when requested","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"formats PC with truncated precision when requested"},{"ancestorTitles":["formatters"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"formatters normalizes Push Chain insufficient-funds wei amounts","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"normalizes Push Chain insufficient-funds wei amounts"},{"ancestorTitles":["formatters"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"formatters leaves unrelated insufficient-funds messages unchanged","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"leaves unrelated insufficient-funds messages unchanged"},{"ancestorTitles":["formatters"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"formatters shortens source-chain insufficient gas/value errors for public display","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"shortens source-chain insufficient gas/value errors for public display"},{"ancestorTitles":["formatters"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"formatters shortens Solana no-prior-credit simulation errors for public display","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"shortens Solana no-prior-credit simulation errors for public display"},{"ancestorTitles":["formatters"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"formatters prefers library shortMessage when normalizing error objects","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"prefers library shortMessage when normalizing error objects"},{"ancestorTitles":["formatters"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"formatters looks through generic viem shortMessage wrappers for nested balance details","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"looks through generic viem shortMessage wrappers for nested balance details"},{"ancestorTitles":["formatters"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"formatters keeps plain object errors readable for terminal hooks","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"keeps plain object errors readable for terminal hooks"}],"endTime":1792494888270,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/formatters.spec.ts","startTime":1792494888259,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["sizeCallbackBudget"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"sizeCallbackBudget is gasLimit × gasPrice × buffer","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"is gasLimit × gasPrice × buffer"},{"ancestorTitles":["sizeCallbackBudget"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"sizeCallbackBudget never returns zero — a zero gas price falls back to the 1 gwei floor","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"never returns zero — a zero gas price falls back to the 1 gwei floor"},{"ancestorTitles":["sizeCallbackBudget"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"sizeCallbackBudget covers what Donut actually burned for a 200k-limit callback (118,289 gas at 1 gwei)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"covers what Donut actually burned for a 200k-limit callback (118,289 gas at 1 gwei)"},{"ancestorTitles":["sizeCallbackBudget"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"sizeCallbackBudget bigint math is exact at the 1M gas ceiling","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"bigint math is exact at the 1M gas ceiling"},{"ancestorTitles":["sizeCallbackBudget"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"sizeCallbackBudget rejects a non-positive gas limit or a bad buffer","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"rejects a non-positive gas limit or a bad buffer"}],"endTime":1792494888280,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/read-state/__tests__/budget.spec.ts","startTime":1792494888271,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["R3 execute-phase hook emission order (static guard)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"R3 execute-phase hook emission order (static guard) EVM variant: emission sites are in numeric-ascending order","invocations":1,"location":null,"numPassingAsserts":11,"retryReasons":[],"status":"passed","title":"EVM variant: emission sites are in numeric-ascending order"},{"ancestorTitles":["R3 execute-phase hook emission order (static guard)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"R3 execute-phase hook emission order (static guard) SVM variant: emission sites are in numeric-ascending order","invocations":1,"location":null,"numPassingAsserts":11,"retryReasons":[],"status":"passed","title":"SVM variant: emission sites are in numeric-ascending order"},{"ancestorTitles":["R3 execute-phase hook emission order (static guard)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"R3 execute-phase hook emission order (static guard) 304-04 (decline) appears in the catch-branch between 304-01 and 304-02","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"304-04 (decline) appears in the catch-branch between 304-01 and 304-02"}],"endTime":1792494888294,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/r3-execute-order.spec.ts","startTime":1792494888285,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["PushChainExecutionError"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"PushChainExecutionError default construction has undefined decodedError + gatewayTxHash","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"default construction has undefined decodedError + gatewayTxHash"},{"ancestorTitles":["PushChainExecutionError"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PushChainExecutionError preserves gatewayTxHash + decodedError when provided","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"preserves gatewayTxHash + decodedError when provided"},{"ancestorTitles":["PushChainExecutionError"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PushChainExecutionError is throwable and survives instanceof through async/await","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"is throwable and survives instanceof through async/await"},{"ancestorTitles":["InsufficientUEABalanceError carries decodedError"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"InsufficientUEABalanceError carries decodedError NATIVE shortfall populates decodedError.name + hint","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"NATIVE shortfall populates decodedError.name + hint"},{"ancestorTitles":["InsufficientUEABalanceError carries decodedError"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"InsufficientUEABalanceError carries decodedError formats native UPC amounts as decimal PC in the thrown message","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"formats native UPC amounts as decimal PC in the thrown message"},{"ancestorTitles":["InsufficientUEABalanceError carries decodedError"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"InsufficientUEABalanceError carries decodedError PRC20 shortfall populates decodedError with PRC-20-flavoured hint","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"PRC20 shortfall populates decodedError with PRC-20-flavoured hint"},{"ancestorTitles":["InsufficientUEABalanceError carries decodedError"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"InsufficientUEABalanceError carries decodedError still satisfies instanceof PushChainExecutionError (legacy compat)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"still satisfies instanceof PushChainExecutionError (legacy compat)"},{"ancestorTitles":["InsufficientUEABalanceError carries decodedError"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"InsufficientUEABalanceError carries decodedError preserves segmentIndex for cascade callers","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"preserves segmentIndex for cascade callers"}],"endTime":1792494888307,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/src/lib/orchestrator/__tests__/errors.spec.ts","startTime":1792494888295,"status":"passed","summary":""}],"wasInterrupted":false} diff --git a/plan/marketplace/research/sdk-implementation-2026-10-20/validation-summary.json b/plan/marketplace/research/sdk-implementation-2026-10-20/validation-summary.json new file mode 100644 index 00000000..cadb5af7 --- /dev/null +++ b/plan/marketplace/research/sdk-implementation-2026-10-20/validation-summary.json @@ -0,0 +1,30 @@ +{ + "observedAt": "2026-10-20T11:20:11.358467+00:00", + "unit": { + "passed": 2205, + "skipped": 12, + "failed": 0 + }, + "fork": { + "passed": 6, + "failed": 0 + }, + "readonlyLive": { + "passed": 2, + "failed": 0 + }, + "fundedLive": { + "runnerExitCode": 0, + "passed": 1, + "failed": 0, + "originalReporterSuccessField": false, + "note": "Known reporter callback sampling discrepancy; passing test status/counts and actual runner exit 0 retained." + }, + "build": "passed", + "specTypes": "passed", + "forkTypes": "passed", + "newProductionLint": "passed with zero warnings", + "guideBlocks": 4, + "packageAndDeclarationChecks": "passed", + "sourceBuiltApiMatches": true +} From fdfcd4608f2d3db26ee4b3c5dc4a694f93f85097 Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Tue, 20 Oct 2026 18:05:51 +0530 Subject: [PATCH 58/68] feat(core): complete marketplace deposits and paid previews --- packages/core/MARKETPLACE.md | 48 +- packages/core/__e2e__/ci/suite.ts | 2 + .../__e2e__/marketplace/lifecycle.spec.ts | 112 +- .../core/__market-local__/marketplace.spec.ts | 171 +- .../core/src/lib/agentic/contracts/reader.ts | 3 + packages/core/src/lib/index.ts | 5 + .../lib/job-spec/__tests__/preview.spec.ts | 268 + packages/core/src/lib/job-spec/index.ts | 19 +- packages/core/src/lib/job-spec/preview.ts | 291 + packages/core/src/lib/job-spec/types.ts | 28 +- .../src/lib/market/__tests__/deposit.spec.ts | 384 + .../lib/market/__tests__/namespace.spec.ts | 47 +- packages/core/src/lib/market/deposit.ts | 454 + packages/core/src/lib/market/market.ts | 156 +- packages/core/src/lib/market/runtime.ts | 8 +- packages/core/src/lib/market/types.ts | 36 +- .../core/src/lib/push-chain/push-chain.ts | 4 + .../read-state/__tests__/read-params.spec.ts | 6 + .../read-state/__tests__/read-types.spec.ts | 6 + .../core/src/lib/read-state/read-params.ts | 13 +- plan/SDK-CHANGELOG.md | 8 + plan/marketplace/README.md | 6 +- plan/marketplace/implementation-status.md | 34 +- plan/marketplace/questions.md | 2 +- .../sdk-completion-2026-10-20/README.md | 48 + .../api-comparison.json | 13371 ++++++++++++++++ .../checked-files.json | 26 + .../fork-results.json | 1 + .../live-evidence.json | 67 + .../live-results.json | 31 + .../post-live-state.json | 45 + .../unit-results.json.gz | Bin 0 -> 73812 bytes .../validation-summary.json | 42 + 33 files changed, 15609 insertions(+), 133 deletions(-) create mode 100644 packages/core/src/lib/job-spec/__tests__/preview.spec.ts create mode 100644 packages/core/src/lib/job-spec/preview.ts create mode 100644 packages/core/src/lib/market/__tests__/deposit.spec.ts create mode 100644 packages/core/src/lib/market/deposit.ts create mode 100644 plan/marketplace/research/sdk-completion-2026-10-20/README.md create mode 100644 plan/marketplace/research/sdk-completion-2026-10-20/api-comparison.json create mode 100644 plan/marketplace/research/sdk-completion-2026-10-20/checked-files.json create mode 100644 plan/marketplace/research/sdk-completion-2026-10-20/fork-results.json create mode 100644 plan/marketplace/research/sdk-completion-2026-10-20/live-evidence.json create mode 100644 plan/marketplace/research/sdk-completion-2026-10-20/live-results.json create mode 100644 plan/marketplace/research/sdk-completion-2026-10-20/post-live-state.json create mode 100644 plan/marketplace/research/sdk-completion-2026-10-20/unit-results.json.gz create mode 100644 plan/marketplace/research/sdk-completion-2026-10-20/validation-summary.json diff --git a/packages/core/MARKETPLACE.md b/packages/core/MARKETPLACE.md index 4e0225fc..90e5e7e8 100644 --- a/packages/core/MARKETPLACE.md +++ b/packages/core/MARKETPLACE.md @@ -1,6 +1,6 @@ # Agentic marketplace and jobs -This SDK checkpoint targets UniversalMarketplace v2 on Push Donut, its pUSDC kernel and AGW v6. It implements card management, JobSpec authoring, preview/open for native owners without delegation, and the kernel lifecycle. The evaluator is currently an EOA: there is no automatic verification, baseline or rating claim. +This SDK checkpoint targets UniversalMarketplace v2 on Push Donut, its pUSDC kernel and AGW v6. It implements card management, JobSpec authoring and paid previews, preview/open, historical deposits and the kernel lifecycle. The evaluator is currently an EOA: there is no automatic verification, baseline or rating claim. `PushChain.initialize` now exposes `client.market` and `client.job`. Helpers are `PushChain.utils.market` and `PushChain.utils.job`; vocabulary is under `PushChain.CONSTANTS.AGENTIC`. There is no separate `client.evaluation` namespace. Read-only clients can discover cards and jobs. @@ -9,7 +9,7 @@ This SDK checkpoint targets UniversalMarketplace v2 on Push Donut, its pUSDC ker Use verified application/token addresses and raw token units. The following helper returns permissions and a criteria template; it does not sign or send anything. ```ts -import { PushChain, MarketError, type AgentCardInput, type AgentCardRules } from '@pushchain/core'; +import { PushChain, MarketError, type AgentCardInput, type AgentCardRules, type MarketDepositResult, type PreviewJobSpecOptions } from '@pushchain/core'; import { parseAbi, type Address } from 'viem'; function authorCard(app: Address, token: Address, receiptToken: Address) { @@ -77,7 +77,7 @@ async function openReviewedJob(owner: PushChain, cardId: bigint) { Opening deploys/reuses the AGW, grants the card's exact resolved permissions and creates an Open job. It moves no principal or fee. The plan is revalidated before signing; changed card versions, nonces, occupancy or plan content require a new preview. OwnerIntent authorization uses the factory EIP-712 domain. Client submission can require a second wallet interaction; no relay is supplied in this checkpoint. -Opening currently requires a Push-native owner with no contract/delegation code. External/contract/delegated owner signing returns `CAPABILITY_UNAVAILABLE` before prompting. Provider writes use the connected signer's ordinary Push identity, including when the instance also has an AGW execution context. +Opening supports EVM typed-data signers. An external owner's UEA must already be deployed on Push (`OWNER_NOT_DEPLOYED` otherwise). The SDK checks the factory domain before prompting, then simulates the complete signed request through the real owner verifier before broadcasting. UEA and ERC-1271 acceptance follows the deployed contract; an EIP-7702 delegate without a compatible verifier fails simulation. Signing capability checks run before prompting; a verifier can reject the resulting signature after prompting. Provider writes use the connected signer's ordinary Push identity, including when the instance also has an AGW execution context. **Current destination readiness:** BSC Testnet has passing live open/cancel coverage. Sepolia, Base Sepolia and Arbitrum Sepolia have different CEA factories in the marketplace configuration and current SDK routing table; preview returns `CEA_MISMATCH`. The SDK does not substitute the marketplace's account for an independently derived account. Align the deployment/routing configuration before opening on those chains. @@ -85,9 +85,26 @@ Card IDs, versions, ratings and job IDs are bigint. `jobType` reads are the cano ## Fund and track the kernel lifecycle +```ts +async function depositForJob(owner: PushChain, jobId: bigint): Promise { + return owner.market.deposit(jobId, { + // Target wallet PC balance, not a gas quote for the whole job. + pcAmount: 10n ** 18n, + funding: 'push', + progressHook: event => console.log(event.id, event.message), + }); +} +``` + +`deposit` recovers the original principal and card version from the opening event and historical card state. It never sizes an old job from today's updated card. It tops up wallet balances to the principal, original reference fee and PC target; a shared principal/fee token is combined before subtracting the balance. `providerFee` explicitly overrides the fee reserve and `pcAmount` overrides the PC target. The default PC target is one per-call card gas cap, not a promise that all job execution is covered. This operation leaves the kernel escrow Open and makes no destination approval calls: those are pinned permissions granted to the agent in v2. + +The default source is the connected signer's Push identity, even on an instance configured to execute through an AGW. `funding: 'origin'` explicitly uses normal inbound `funds` transfers for registered assets from the connected origin chain; required tokens without such a route fail before any leg is sent. PC still comes from the signer's Push holdings. The underlying gateway's normal route, liquidity, balance and fee checks apply. + +Steps are separate transactions. `DEPOSIT_INCOMPLETE` retains `details.txs`, any `details.pending` broadcast hash and chain, and the original cause. The same client remembers submitted steps; pass `resume: previousSteps` when continuing with another client. After restarting, rehydrate recorded hashes with `universal.trackTransaction(hash, { chain })` before passing their transaction responses. Pending receipts must settle before another transfer, and a confirmed transfer whose target balance has since fallen requires manual review. Concurrent deposits on the same client are rejected. Coordinate other clients and avoid running the agent during deposits. Deposits require an Open, unexpired job and an enabled permission with no recorded asset spend. If same-block updates hide the exact opening version, `HISTORY_UNAVAILABLE` stops the operation; archive/RPC read failures also stop it. + ```ts async function priceAndFund(provider: PushChain, owner: PushChain, jobId: bigint) { - // First fund the AGW with the payment token, principal and PC appropriate to the job. + // First deposit the payment token, principal and PC appropriate to the job. await (await provider.job.setBudget(jobId, 5_000_000n)).wait(); // Explicitly pass the price the client reviewed; never silently accept a re-quote. return owner.job.fund(jobId, { expectedBudget: 5_000_000n }); @@ -123,12 +140,27 @@ Cancellation is client-side Open-job rejection. A plain job has no marketplace g Plain jobs can use `job.create` with provider/evaluator/hook/expiry/paymentToken plus either binary jobSpec or text description. The kernel's Solidity string slot can carry binary JobSpec bytes; the SDK preserves them and retains the original createJob selector. +## Paid criteria preview + +```ts +async function previewCriteria(client: PushChain, template: ReturnType['jobSpecTemplate'], wallet: Address) { + const options: PreviewJobSpecOptions = { + client, wallet, principal: 100_000_000n, + maxTotalFee: 10n ** 16n, + advanced: { timeout: 120_000 }, + }; + return PushChain.utils.job.previewJobSpec(template, options); +} +``` + +This prepares every raw read, checks the total callback/protocol fee cap, then executes through the existing universal-read registry (or an explicit `callback`). Native transaction gas is separate from `maxTotalFee`. A real SDK client derives destination CEAs for template wallet holes using its configured routes; `accounts` supplies explicit destination addresses when needed. An AGW's Push address is never substituted for its destination account. + +The result includes raw values, decoded fields, request responses and fees. `pass` and each check are `true`, `false`, or `null` (unknown). NUMBER and PERCENTAGE require an explicit per-read `baseline`; missing baselines, zero percentage denominators and unavailable reads stay unknown. A preview is an observation, not an automatic evaluator verdict or proof that a job is complete. Raw EVM calls are also available as `universal.read(target, { chain, callData })` and return consensus bytes. + ## Explicit placeholders -- `market.deposit`: historical-card deposit/resumption policy remains pending. Fund the wallet explicitly; do not recompute an old job from the current card version. - `job.verify`, baseline/prefund/retry integration: no compatible automatic evaluator is configured. A different linked evaluator source has a different wire and enum values. -- Replacement JobSpecs, non-NONE marketplace criteria, recurring jobs, relay and external/delegated OwnerIntent signing are unavailable. -- `utils.job.previewJobSpec`: paid read/callback and fee behavior remains gated. Pure build/encode/decode/describe helpers work without a network. +- Replacement JobSpecs, non-NONE marketplace criteria, recurring jobs and relay are unavailable. Unsupported paths throw before signing/sending. They do not return successful dummy results. Keep message, code, details and cause for diagnostics. @@ -145,4 +177,4 @@ node node_modules/ts-node/dist/bin.js --compiler-options '{"module":"commonjs"}' node node_modules/ts-node/dist/bin.js --compiler-options '{"module":"commonjs"}' packages/core/__e2e__/ci/run.ts --group marketplace-live ``` -Marketplace groups stay out of the runner's default `all`. Live smoke spends bounded PC for gas/test wallets and does not move principal or escrow tokens. Nonzero escrow, allowance, payout, manual completion and pause/refund are tested separately on the local fork. No destination protocol execution or automated verdict is implied by those results. +Marketplace groups stay out of the runner's default `all`. Live smoke spends bounded PC for gas/test wallets and read callbacks, and does not move principal or escrow tokens. Nonzero deposits, escrow, allowance, payout, manual completion and pause/refund are tested separately on the local fork. The fork's UEA signature test uses a native submitter because Anvil has no Cosmos transport; the opt-in live case exercises actual external-owner transport. No destination protocol execution or automated verdict is implied by those results. diff --git a/packages/core/__e2e__/ci/suite.ts b/packages/core/__e2e__/ci/suite.ts index adb23978..5cd93e91 100644 --- a/packages/core/__e2e__/ci/suite.ts +++ b/packages/core/__e2e__/ci/suite.ts @@ -172,6 +172,8 @@ const F = { export const SCENARIOS: Scenario[] = [ { id: 'marketplace-native-lifecycle', group: 'marketplace-live', file: '__e2e__/marketplace/lifecycle.spec.ts', grep: 'marketplace live 1\\. native provider registration', needs: { masterPC: '0.5' }, env: { MARKETPLACE_LIVE_E2E: '1', AGW_E2E_AGENT_PC: '0.1' }, note: 'Fresh provider/card/wallet only; no principal export or fee escrow. Cancels and revokes its own permission.' }, + { id: 'marketplace-paid-preview', group: 'marketplace-live', file: '__e2e__/marketplace/lifecycle.spec.ts', grep: 'marketplace live 2\\. paid JobSpec preview', needs: { masterPC: '0.5' }, env: { MARKETPLACE_LIVE_E2E: '1', AGW_E2E_AGENT_PC: '0.1' }, note: 'One live validator read through the registry, with an explicit 0.01 PC callback/protocol fee cap.' }, + { id: 'marketplace-external-owner', group: 'marketplace-live', file: '__e2e__/marketplace/lifecycle.spec.ts', grep: 'marketplace live 3\\. external EVM owner', needs: { masterPC: '0.5' }, env: { MARKETPLACE_LIVE_E2E: '1', AGW_E2E_AGENT_PC: '0.1' }, note: 'Fresh Sepolia-origin UEA funded with 0.1 PC; open/cancel using the real UEA transport; reuses this run’s card.' }, { id: 'marketplace-readonly-bindings', group: 'marketplace', file: '__e2e__/marketplace/readiness.spec.ts', grep: 'marketplace deployed v2 read-only', needs: {}, note: 'Unfunded public SDK card/job enumeration and capability gates; no signing keys.' }, { id: 'agw-svm-replay-positive', diff --git a/packages/core/__e2e__/marketplace/lifecycle.spec.ts b/packages/core/__e2e__/marketplace/lifecycle.spec.ts index 90742f12..388968fb 100644 --- a/packages/core/__e2e__/marketplace/lifecycle.spec.ts +++ b/packages/core/__e2e__/marketplace/lifecycle.spec.ts @@ -1,6 +1,6 @@ /** Opt-in funded Donut smoke. Only PC gas/fresh provider funding moves; principal and escrow stay zero. */ -import { parseAbi, parseEther, type Address } from 'viem'; -import { generatePrivateKey } from 'viem/accounts'; +import { encodeFunctionData, parseAbi, parseEther, type Address } from 'viem'; +import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts'; import { PushChain } from '../../src'; import { CHAIN } from '../../src/lib/constants/enums'; import { setupAgw, evmClient, type AgwFixture } from '../agw/_fixture'; @@ -11,6 +11,8 @@ d('marketplace live', () => { let f: AgwFixture; let provider: PushChain; let owner: PushChain; + let externalOwner: PushChain | undefined; + let externalOpened: { jobId: bigint; wallet: Address } | undefined; let cardId: bigint | undefined; let opened: | { jobId: bigint; wallet: Address; rulesId: `0x${string}` } @@ -23,13 +25,23 @@ d('marketplace live', () => { f.manifest.network ); const ownerKey = generatePrivateKey(); - owner = await evmClient(ownerKey, CHAIN.PUSH_TESTNET_DONUT, f.manifest.network); + owner = await evmClient( + ownerKey, + CHAIN.PUSH_TESTNET_DONUT, + f.manifest.network + ); await f.fundPC(owner.universal.account as Address, parseEther('0.1')); }, 300000); afterAll(async () => { // Best-effort cleanup after failures, restricted to this run's own fresh card and wallet. if (opened && (await owner.job.status(opened.jobId)).status === 'Open') await (await owner.job.cancel(opened.jobId)).wait(); + if ( + externalOwner && + externalOpened && + (await externalOwner.job.status(externalOpened.jobId)).status === 'Open' + ) + await (await externalOwner.job.cancel(externalOpened.jobId)).wait(); if (cardId && (await provider.market.card(cardId)).active) await (await provider.market.agent.setActive(cardId, false)).wait(); f?.teardown(); @@ -128,4 +140,98 @@ d('marketplace live', () => { txHash: cancelled.hash, }); }); + it('2. paid JobSpec preview reaches live validator consensus through the registry', async () => { + const spec = PushChain.utils.job.buildJobSpec({ + reads: [ + PushChain.utils.job.prepareRead({ + chain: CHAIN.BNB_TESTNET, + target: PushChain.CONSTANTS.MOVEABLE.TOKEN.BNB_TESTNET.USDT + .address as Address, + abi: parseAbi(['function balanceOf(address) view returns (uint256)']), + functionName: 'balanceOf', + args: [owner.universal.account], + }), + ], + checks: [ + { + read: 0, + evaluation: 'COMPARE', + operation: 'GREATER_OR_EQUAL', + target: BigInt(0), + }, + ], + logic: 'ALL', + executeBy: Math.floor(Date.now() / 1000) + 600, + failFinalAt: Math.floor(Date.now() / 1000) + 660, + }); + const result = await PushChain.utils.job.previewJobSpec(spec, { + client: owner, + maxTotalFee: parseEther('0.01'), + advanced: { timeout: 120000, pollingIntervalMs: 1000 }, + }); + f.evidence('marketplace-paid-preview', { + pass: result.pass, + fees: result.fees, + reads: result.reads.map((r) => ({ + decoded: r.decoded, + error: r.error, + requestId: r.response.requestId, + txHash: r.response.txHash, + outcome: r.response.outcome, + })), + }); + expect(result.pass).toBe(true); + expect(result.reads[0].decoded).not.toBeNull(); + }); + it('3. external EVM owner opens and cancels through its real Push UEA transport', async () => { + if (!cardId) throw new Error('The fresh test card was not registered'); + const key = generatePrivateKey(); + externalOwner = await evmClient( + key, + CHAIN.ETHEREUM_SEPOLIA, + f.manifest.network + ); + const uea = externalOwner.universal.account as Address; + const deployed = await owner.universal.sendTransaction({ + to: '0x00000000000000000000000000000000000000eA', + data: encodeFunctionData({ + abi: parseAbi([ + 'function deployUEA((string chainNamespace,string chainId,bytes owner) id) returns (address)', + ]), + functionName: 'deployUEA', + args: [ + { + chainNamespace: 'eip155', + chainId: '11155111', + owner: privateKeyToAccount(key).address, + }, + ], + }), + }); + await deployed.wait(); + await f.fundPC(uea, parseEther('0.1')); + await (await provider.market.agent.setActive(cardId, true)).wait(); + const now = Number((await f.push.getBlock()).timestamp); + const plan = await externalOwner.market.preview(cardId, { + principal: BigInt(1), + executeBy: now + 600, + expiredAt: now + 7200, + }); + externalOpened = await externalOwner.market.openJob(plan); + f.evidence('marketplace-external-open', { + jobId: externalOpened.jobId, + wallet: externalOpened.wallet, + uea, + signerChainId: plan.intent.signerChainId, + }); + await (await externalOwner.job.cancel(externalOpened.jobId)).wait(); + expect((await externalOwner.job.status(externalOpened.jobId)).status).toBe( + 'Rejected' + ); + await (await provider.market.agent.setActive(cardId, false)).wait(); + f.evidence('marketplace-external-cleanup', { + jobId: externalOpened.jobId, + cardId, + }); + }); }); diff --git a/packages/core/__market-local__/marketplace.spec.ts b/packages/core/__market-local__/marketplace.spec.ts index 40810c43..c4f495c8 100644 --- a/packages/core/__market-local__/marketplace.spec.ts +++ b/packages/core/__market-local__/marketplace.spec.ts @@ -7,6 +7,7 @@ import { defineChain, encodeFunctionData, erc20Abi, + getAddress, keccak256, http, parseAbi, @@ -24,6 +25,9 @@ import { JOB_KERNEL_ABI } from '../src/lib/market/contracts/AgenticCommerce'; import { currentGeneration } from '../src/lib/agentic/deployments'; import type { AgentCardRules } from '../src/lib/market/rules'; import type { JobSpecTemplate } from '../src/lib/job-spec/types'; +import { MarketNamespaceImpl } from '../src/lib/market/market'; +import type { StackRuntime } from '../src/lib/market/runtime'; +import type { AgenticRuntime } from '../src/lib/agentic/runtime'; let node: ChildProcess; let rpc: string; @@ -226,24 +230,12 @@ it('updates a decoded card without losing rule constraints or template wire byte expect(after.jobSpecTemplateBytes).toBe(before.jobSpecTemplateBytes); expect(after.verified).toBe(false); }); -it('funds through the real rules hook and submits as the provider; manual evaluator completes locally', async () => { - const events: string[] = []; - stopWatch = owner.job.watch(opened.jobId, (e) => events.push(e.kind), { - fromBlock: (await push.getBlockNumber({ cacheTime: 0 })) + BigInt(1), - pollIntervalMs: 25, - }); - await (await provider.job.setBudget(opened.jobId, BigInt(6000000))).wait(); - await expect(owner.job.fund(opened.jobId)).rejects.toMatchObject({ - code: 'EXPECTED_BUDGET_REQUIRED', - }); - await expect( - owner.job.fund(opened.jobId, { expectedBudget: BigInt(5000000) }) - ).rejects.toMatchObject({ code: 'BUDGET_MISMATCH' }); +it('deposits original principal, fee and PC after a card update and recovers history in a fresh client', async () => { await (await provider.job.setBudget(opened.jobId, BigInt(5000000))).wait(); await expect( owner.job.fund(opened.jobId, { expectedBudget: BigInt(5000000) }) ).rejects.toMatchObject({ code: 'INSUFFICIENT_FUNDS' }); - // Borrow existing pUSDC on this local fork only; no mint/transfer is sent to public Donut. + // These are real existing assets borrowed on localhost, not public-chain transfers. const source = '0x0A16CBa65FfCAa4C2282b27b027Ab4A2fE46E0Bf'; await push.request({ method: 'anvil_impersonateAccount' as never, @@ -254,14 +246,70 @@ it('funds through the real rules hook and submits as the provider; manual evalua chain: push.chain, transport: http(rpc), }); - const fundingHash = await funder.writeContract({ + for (const [asset, amount] of [ + [token, BigInt(10)], + [D.paymentToken, BigInt(5000000)], + ] as const) { + const hash = await funder.writeContract({ + chain: push.chain, + address: asset, + abi: erc20Abi, + functionName: 'transfer', + args: [accounts[0].address, amount], + }); + await push.waitForTransactionReceipt({ hash }); + } + const deposited = await owner.market.deposit(opened.jobId, { + pcAmount: BigInt(10) ** BigInt(15), + }); + expect(deposited.cardVersion).toBe(BigInt(1)); + expect(deposited.txs.map((t) => t.step)).toEqual([ + 'PRINCIPAL', + 'PROVIDER_FEE', + 'PC', + ]); + expect((await owner.job.status(opened.jobId)).status).toBe('Open'); + expect( + await push.readContract({ + address: D.paymentToken, + abi: erc20Abi, + functionName: 'allowance', + args: [opened.wallet, D.kernel], + }) + ).toBe(BigInt(0)); + const wallet = createWalletClient({ + account: accounts[0], chain: push.chain, - address: D.paymentToken, - abi: erc20Abi, - functionName: 'transfer', - args: [opened.wallet, BigInt(5000000)], + transport: http(rpc), + }); + const signer = await PushChain.utils.signer.toUniversalFromKeypair(wallet, { + chain: CHAIN.PUSH_TESTNET_DONUT, + library: LIBRARY.ETHEREUM_VIEM, + }); + const reconnected = await PushChain.initialize(signer, { + network: PUSH_NETWORK.TESTNET_DONUT, + rpcUrls: { [CHAIN.PUSH_TESTNET_DONUT]: [rpc] }, + }); + const recovered = await reconnected.market.deposit(opened.jobId, { + pcAmount: BigInt(10) ** BigInt(15), + }); + expect(recovered.cardVersion).toBe(BigInt(1)); + expect(recovered.txs).toEqual([]); +}); +it('funds through the real rules hook and submits as the provider; manual evaluator completes locally', async () => { + const events: string[] = []; + stopWatch = owner.job.watch(opened.jobId, (e) => events.push(e.kind), { + fromBlock: (await push.getBlockNumber({ cacheTime: 0 })) + BigInt(1), + pollIntervalMs: 25, }); - await push.waitForTransactionReceipt({ hash: fundingHash }); + await (await provider.job.setBudget(opened.jobId, BigInt(6000000))).wait(); + await expect(owner.job.fund(opened.jobId)).rejects.toMatchObject({ + code: 'EXPECTED_BUDGET_REQUIRED', + }); + await expect( + owner.job.fund(opened.jobId, { expectedBudget: BigInt(5000000) }) + ).rejects.toMatchObject({ code: 'BUDGET_MISMATCH' }); + await (await provider.job.setBudget(opened.jobId, BigInt(5000000))).wait(); const before = await push.readContract({ address: D.paymentToken, abi: erc20Abi, @@ -386,6 +434,13 @@ it('rejects a tampered plan before signing and atomically cancels a second job w preview: { ...plan.preview, mayDo: ['tampered'] }, }) ).rejects.toMatchObject({ code: 'STALE_PLAN' }); + const badSignature = jest + .spyOn(owner.universal, 'signTypedData') + .mockImplementationOnce(async (data) => accounts[1].signTypedData(data)); + await expect(owner.market.openJob(plan)).rejects.toMatchObject({ + code: 'OPEN_JOB_SIMULATION_FAILED', + }); + badSignature.mockRestore(); const second = await owner.market.openJob(plan); await (await owner.job.cancel(second.jobId)).wait(); expect((await owner.job.status(second.jobId)).status).toBe('Rejected'); @@ -400,3 +455,79 @@ it('rejects a tampered plan before signing and atomically cancels a second job w }) ).toBe(false); }); +it('accepts a real deployed EVM UEA owner signature with its home-chain domain', async () => { + const external = await PushChain.initialize( + { chain: CHAIN.ETHEREUM_SEPOLIA, address: accounts[0].address }, + { + network: PUSH_NETWORK.TESTNET_DONUT, + rpcUrls: { [CHAIN.PUSH_TESTNET_DONUT]: [rpc] }, + } + ); + const uea = getAddress(external.universal.account); + const base = (owner as unknown as { agenticRuntime: AgenticRuntime }) + .agenticRuntime; + const rt: StackRuntime = { + agw: { + ...base, + signerPushAccount: () => uea, + signerOrigin: () => ({ + chain: CHAIN.ETHEREUM_SEPOLIA, + address: accounts[0].address, + }), + signerIsPushNative: () => false, + }, + account: () => uea, + wallet: () => undefined, + send: base.execute, + // Relaying is permitted on-chain. Anvil has no Cosmos MsgExecutePayload transport; + // only the submitting transport is native here. The UEA verifies the real origin signature. + signTypedData: (data) => accounts[0].signTypedData(data), + canSignTypedData: () => true, + jobBlocks: new Map(), + }; + const market = new MarketNamespaceImpl(rt); + const now = Number((await push.getBlock()).timestamp); + const plan = await market.preview(cardId, { + principal: BigInt(10), + executeBy: now + 600, + expiredAt: now + 7200, + }); + await expect(market.openJob(plan)).rejects.toMatchObject({ + code: 'OWNER_NOT_DEPLOYED', + }); + const deploy = await owner.universal.sendTransaction({ + to: '0x00000000000000000000000000000000000000eA', + data: encodeFunctionData({ + abi: parseAbi([ + 'function deployUEA((string chainNamespace,string chainId,bytes owner) id) returns (address)', + ]), + functionName: 'deployUEA', + args: [ + { + chainNamespace: 'eip155', + chainId: '11155111', + owner: accounts[0].address, + }, + ], + }), + }); + await deploy.wait(); + expect(await push.getCode({ address: uea })).not.toBe('0x'); + const reviewed = await market.preview(cardId, { + principal: BigInt(10), + executeBy: now + 600, + expiredAt: now + 7200, + }); + expect(reviewed.intent.owner).toBe(uea); + expect(reviewed.intent.signerChainId).toBe(BigInt(11155111)); + const result = await market.openJob(reviewed); + const gen = currentGeneration(PUSH_NETWORK.TESTNET_DONUT); + expect( + await push.readContract({ + address: result.wallet, + abi: gen.contracts.abis.wallet, + functionName: 'owner', + }) + ).toBe(uea); + expect((await owner.job.status(result.jobId)).status).toBe('Open'); +}); diff --git a/packages/core/src/lib/agentic/contracts/reader.ts b/packages/core/src/lib/agentic/contracts/reader.ts index 2515cd8e..5145ade2 100644 --- a/packages/core/src/lib/agentic/contracts/reader.ts +++ b/packages/core/src/lib/agentic/contracts/reader.ts @@ -25,6 +25,8 @@ export interface ChainReader { toBlock: bigint; }): Promise; getTransactionReceipt(args: { hash: Hex }): Promise; + /** Raw eth_call, used to verify complete signed marketplace requests before broadcast. */ + call?(args: { to: Address; data: Hex; account?: Address; blockNumber?: bigint }): Promise<{ data?: Hex }>; } export function chainReaderFromPublicClient(client: PublicClient): ChainReader { @@ -40,5 +42,6 @@ export function chainReaderFromPublicClient(client: PublicClient): ChainReader { getLogs: (args) => client.getLogs(args as Parameters[0]) as Promise, getTransactionReceipt: (args) => client.getTransactionReceipt(args), + call: (args) => client.call(args), }; } diff --git a/packages/core/src/lib/index.ts b/packages/core/src/lib/index.ts index b40c9a86..5747450f 100644 --- a/packages/core/src/lib/index.ts +++ b/packages/core/src/lib/index.ts @@ -9,6 +9,10 @@ export type { AgentCardSummary, MarketNamespace, MarketPreviewOptions, + MarketWriteOptions, + MarketDepositOptions, + MarketDepositResult, + MarketDepositStep, JobPlan, OwnerIntent, } from './market'; @@ -38,6 +42,7 @@ export type { BuildJobSpecOptions, BuildJobSpecTemplateOptions, JobSpecPreview, + PreviewJobSpecOptions, } from './job-spec'; export { CHAIN } from './constants/enums'; export type { ConversionQuote } from './constants/tokens'; diff --git a/packages/core/src/lib/job-spec/__tests__/preview.spec.ts b/packages/core/src/lib/job-spec/__tests__/preview.spec.ts new file mode 100644 index 00000000..761fbf9a --- /dev/null +++ b/packages/core/src/lib/job-spec/__tests__/preview.spec.ts @@ -0,0 +1,268 @@ +import { + encodeAbiParameters, + keccak256, + parseAbi, + parseAbiParameters, + stringToHex, + type Hex, +} from 'viem'; +import { buildJobSpec, buildJobSpecTemplate } from '../codec'; +import { prepareJobRead } from '../read'; +import { + bindJobPreviewAccounts, + decodeJobAnswer, + previewJobSpec, +} from '../preview'; +import { READ_OUTCOME } from '../../read-state/read-state.types'; +import { PRINCIPAL } from '../constants'; +import type { PreviewJobSpecOptions, JobSpec } from '../types'; +const target = '0x1111111111111111111111111111111111111111'; +const word = (n: bigint): Hex => encodeAbiParameters([{ type: 'int256' }], [n]); +const abi = parseAbi(['function value() view returns (uint256)']); +const read = prepareJobRead({ + chain: 'eip155:97', + target, + abi, + functionName: 'value', +}); +function spec( + evaluation: 'COMPARE' | 'NUMBER' | 'PERCENTAGE' = 'COMPARE' +): JobSpec { + return buildJobSpec({ + reads: [read], + checks: [ + { + read: 0, + evaluation, + operation: 'GREATER_OR_EQUAL', + target: evaluation === 'PERCENTAGE' ? BigInt(2500) : BigInt(5), + }, + ], + logic: 'ALL', + executeBy: 1800000000, + failFinalAt: 1800000060, + }); +} +function fixture(values: (Hex | null)[] = [word(BigInt(5))]) { + const prepareRead = jest.fn(async () => ({ value: BigInt(2) })); + const executeReads = jest.fn(async () => ({ + reads: values.map((resultData) => ({ + outcome: + resultData === null ? READ_OUTCOME.SOURCE_ERROR : READ_OUTCOME.SUCCESS, + raw: resultData === null ? null : { resultData }, + fees: { paid: BigInt(2) }, + errorMsg: '', + })), + })); + const options = { + client: { universal: { prepareRead, executeReads } }, + } as unknown as PreviewJobSpecOptions; + return { options, prepareRead, executeReads }; +} +it('prepares raw calls through universal reads, pays the batch and evaluates comparisons', async () => { + const f = fixture(); + const result = await previewJobSpec(spec(), { + ...f.options, + maxTotalFee: BigInt(2), + }); + expect(f.prepareRead).toHaveBeenCalledWith( + target, + expect.objectContaining({ + chain: 'eip155:97', + callData: read.selector, + minConfirmations: 1, + }) + ); + expect(f.executeReads).toHaveBeenCalledWith( + [{ value: BigInt(2) }], + expect.objectContaining({ waitForCompletion: true }) + ); + expect(result).toMatchObject({ + pass: true, + checks: [{ value: BigInt(5), pass: true }], + fees: { quoted: BigInt(2), paid: BigInt(2) }, + }); +}); +it('checks the total fee cap after preparation and before any paid request', async () => { + const f = fixture(); + await expect( + previewJobSpec(spec(), { ...f.options, maxTotalFee: BigInt(1) }) + ).rejects.toMatchObject({ code: 'PREVIEW_FEE_EXCEEDED' }); + expect(f.executeReads).not.toHaveBeenCalled(); +}); +it('does not invent baselines or treat unavailable source reads as failures of the criteria', async () => { + const f = fixture(); + expect(await previewJobSpec(spec('NUMBER'), f.options)).toMatchObject({ + pass: null, + checks: [{ pass: null, value: null, reason: 'BASELINE_REQUIRED' }], + }); + const failed = fixture([null]); + expect(await previewJobSpec(spec(), failed.options)).toMatchObject({ + pass: null, + reads: [{ decoded: null }], + checks: [{ reason: 'READ_UNAVAILABLE' }], + }); +}); +it('uses explicit baseline values for signed changes and basis-point percentages', async () => { + const f = fixture([word(BigInt(125))]); + expect( + await previewJobSpec(spec('PERCENTAGE'), { + ...f.options, + baseline: [BigInt(100)], + }) + ).toMatchObject({ pass: true, checks: [{ value: BigInt(2500) }] }); + expect( + await previewJobSpec(spec('PERCENTAGE'), { + ...f.options, + baseline: [BigInt(0)], + }) + ).toMatchObject({ pass: null, checks: [{ reason: 'ZERO_BASELINE' }] }); + const falling = fixture([word(BigInt(5))]); + expect( + await previewJobSpec(spec('NUMBER'), { + ...falling.options, + baseline: [BigInt(10)], + }) + ).toMatchObject({ pass: false, checks: [{ value: BigInt(-5) }] }); +}); +it('propagates unknowns with ALL, ANY and AT_LEAST without hiding conclusive results', async () => { + const s = spec(); + s.reads.push({ ...s.reads[0] }); + s.checks.push({ ...s.checks[0], read: 1 }); + const f = fixture([word(BigInt(5)), null]); + s.logic = { kind: 'ANY', of: [0, 1] }; + expect((await previewJobSpec(s, f.options)).pass).toBe(true); + s.logic = { kind: 'ALL', of: [0, 1] }; + expect((await previewJobSpec(s, f.options)).pass).toBeNull(); + s.logic = { kind: 'AT_LEAST', k: 1, of: [0, 1] }; + expect((await previewJobSpec(s, f.options)).pass).toBe(true); + const no = fixture([word(BigInt(0)), null]); + s.logic = { kind: 'ALL', of: [0, 1] }; + expect((await previewJobSpec(s, no.options)).pass).toBe(false); +}); +it('resolves template accounts explicitly and refuses missing principal before preparing reads', async () => { + const hole = prepareJobRead({ + chain: 'eip155:97', + target, + abi: parseAbi(['function balanceOf(address) view returns (uint256)']), + functionName: 'balanceOf', + args: ['agentic:wallet'], + }); + const template = buildJobSpecTemplate({ + reads: [hole], + checks: [ + { + read: 0, + evaluation: 'COMPARE', + operation: 'GREATER_OR_EQUAL', + target: PRINCIPAL, + }, + ], + logic: 'ALL', + }); + const f = fixture(); + await expect(previewJobSpec(template, f.options)).rejects.toMatchObject({ + code: 'UNFILLED_PLACEHOLDER', + }); + expect(f.prepareRead).not.toHaveBeenCalled(); + await expect( + previewJobSpec(template, { + ...f.options, + principal: BigInt(5), + wallet: target, + }) + ).rejects.toMatchObject({ code: 'UNFILLED_PLACEHOLDER' }); + const result = await previewJobSpec(template, { + ...f.options, + principal: BigInt(5), + accounts: { 'eip155:97': target }, + }); + expect(result.pass).toBe(true); + expect(f.prepareRead).toHaveBeenCalledWith( + target, + expect.objectContaining({ + callData: '0x70a08231' + target.slice(2).padStart(64, '0'), + }) + ); +}); +it('decodes ABI offsets across tuples, dynamic tuple arrays and fixed arrays', () => { + const complex = prepareJobRead({ + chain: 'eip155:97', + target, + abi: parseAbi([ + 'function result() view returns ((uint256,address)[],uint256[2],string)', + ]), + functionName: 'result', + }); + const data = encodeAbiParameters( + parseAbiParameters('(uint256,address)[],uint256[2],string'), + [ + [ + [BigInt(7), target], + [BigInt(9), target], + ], + [BigInt(4), BigInt(8)], + 'ok', + ] + ); + const decode = (field: number[]) => + decodeJobAnswer({ ...complex, field, minConfirmations: 1 }, data); + expect(decode([0])).toBe(BigInt(2)); + expect(decode([0, 1, 0])).toBe(BigInt(9)); + expect(decode([1, 1])).toBe(BigInt(8)); + expect(decode([2])).toBe( + BigInt.asIntN(256, BigInt(keccak256(stringToHex('ok')))) + ); +}); +it('rejects truncated return data, invalid bools, unsigned overflow and out-of-range dynamic fields', () => { + const r = { ...read, field: [0], minConfirmations: 1 }; + expect(() => decodeJobAnswer(r, '0x')).toThrow(); + expect(() => decodeJobAnswer(r, word(BigInt(-1)))).toThrow(); + expect(() => + decodeJobAnswer({ ...r, outputs: '0x080103' }, word(BigInt(2))) + ).toThrow(); + expect(decodeJobAnswer({ ...r, outputs: '0x080102' }, word(BigInt(-1)))).toBe( + BigInt(-1) + ); +}); +it('resolves template holes with the configured client and snapshots criteria before paid reads', async () => { + const f = fixture(); + const destination = '0x2222222222222222222222222222222222222222' as const; + const resolve = jest.fn(async () => destination); + bindJobPreviewAccounts(f.options.client.universal, resolve); + const hole = prepareJobRead({ + chain: 'eip155:97', + target, + abi: parseAbi(['function balanceOf(address) view returns (uint256)']), + functionName: 'balanceOf', + args: ['agentic:wallet'], + }); + const template = buildJobSpecTemplate({ + reads: [hole], + checks: [ + { + read: 0, + evaluation: 'COMPARE', + operation: 'GREATER_OR_EQUAL', + target: BigInt(5), + }, + ], + logic: 'ALL', + }); + f.prepareRead.mockImplementation(async () => { + template.checks[0].target = BigInt(999); + return { value: BigInt(2) }; + }); + const result = await previewJobSpec(template, { + ...f.options, + wallet: target, + }); + expect(resolve).toHaveBeenCalledWith(target, 'eip155:97'); + expect(f.prepareRead).toHaveBeenCalledWith( + target, + expect.objectContaining({ + callData: '0x70a08231' + destination.slice(2).padStart(64, '0'), + }) + ); + expect(result.pass).toBe(true); +}); diff --git a/packages/core/src/lib/job-spec/index.ts b/packages/core/src/lib/job-spec/index.ts index cd0e1ab1..8b181857 100644 --- a/packages/core/src/lib/job-spec/index.ts +++ b/packages/core/src/lib/job-spec/index.ts @@ -6,13 +6,7 @@ import { } from './codec'; import { describeJobSpec } from './helpers'; import { prepareJobRead } from './read'; -import { unavailable } from '../market/errors'; -import type { - JobSpec, - JobSpecTemplate, - JobSpecPreview, - PreviewJobSpecOptions, -} from './types'; +import { previewJobSpec } from './preview'; export const jobSpecUtils = Object.freeze({ buildJobSpec, buildJobSpecTemplate, @@ -20,15 +14,6 @@ export const jobSpecUtils = Object.freeze({ decodeJobSpec, describeJobSpec, prepareRead: prepareJobRead, - async previewJobSpec( - _spec: JobSpec | JobSpecTemplate, - _options: PreviewJobSpecOptions - ): Promise { - void _spec; - void _options; - return unavailable( - 'Paid JobSpec preview pending the raw-read fee and callback adapter' - ); - }, + previewJobSpec, }); export type * from './types'; diff --git a/packages/core/src/lib/job-spec/preview.ts b/packages/core/src/lib/job-spec/preview.ts new file mode 100644 index 00000000..24b98862 --- /dev/null +++ b/packages/core/src/lib/job-spec/preview.ts @@ -0,0 +1,291 @@ +import { getAddress, keccak256, zeroHash, type Address, type Hex } from 'viem'; +import type { CHAIN } from '../constants/enums'; +import { READ_OUTCOME } from '../read-state/read-state.types'; +import type { ReadPrepareOptions } from '../read-state/read-params'; +import { JobSpecError } from '../market/errors'; +import { decodeJobSpec, encodeJobSpec, int256 } from './codec'; +import { resolveJobSpec } from './helpers'; +import { parseOutputs, type OutputNode } from './read'; +import { PRINCIPAL } from './constants'; +import type { + JobRead, + JobSpec, + JobSpecTemplate, + JobSpecPreview, + LogicTree, + Operation, + PreviewJobSpecOptions, +} from './types'; + +const resolvers = new WeakMap< + object, + (wallet: Address, chain: CHAIN) => Promise
    +>(); +/** @internal Bind the real client's configured CEA resolver without exposing its runtime. */ +export function bindJobPreviewAccounts( + universal: object, + resolve: (wallet: Address, chain: CHAIN) => Promise
    +): void { + resolvers.set(universal, resolve); +} + +/** Follow the deployed V2 type codes; uint values above int256.max cannot be compared. */ +export function decodeJobAnswer(read: JobRead, data: Hex): bigint { + const bytes = BigInt((data.length - 2) / 2); + const invalid = (): never => { + throw new JobSpecError( + 'INVALID_READ_RESULT', + 'The consensus bytes do not contain the selected JobSpec field.' + ); + }; + const word = (at: bigint): bigint => { + if (at < BigInt(0) || at + BigInt(32) > bytes) return invalid(); + return BigInt('0x' + data.slice(2 + Number(at) * 2, 66 + Number(at) * 2)); + }; + const dynamic = (n: OutputNode): boolean => + [6, 7, 9].includes(n.code) || n.children.some(dynamic); + const head = (n: OutputNode): bigint => + dynamic(n) + ? BigInt(1) + : n.code === 8 + ? n.children.reduce((sum, c) => sum + head(c), BigInt(0)) + : n.code === 10 + ? BigInt(n.size ?? 0) * head(n.children[0]) + : BigInt(1); + let node = parseOutputs(read.outputs); + let base = BigInt(0); + for (const index of read.field) { + let child: OutputNode; + let start = base; + let slot: bigint; + if (node.code === 8) { + child = node.children[index]; + if (!child) return invalid(); + slot = + base + + BigInt(32) * + node.children + .slice(0, index) + .reduce((sum, c) => sum + head(c), BigInt(0)); + } else if (node.code === 9 || node.code === 10) { + if ( + BigInt(index) >= (node.code === 9 ? word(base) : BigInt(node.size ?? 0)) + ) + return invalid(); + child = node.children[0]; + start += node.code === 9 ? BigInt(32) : BigInt(0); + slot = start + BigInt(32) * BigInt(index) * head(child); + } else return invalid(); + base = dynamic(child) ? start + word(slot) : slot; + if (base > bytes) return invalid(); + node = child; + } + const value = word(base); + if (node.code === 6 || node.code === 7) { + if (base + BigInt(32) + value > bytes) return invalid(); + return BigInt.asIntN( + 256, + BigInt( + keccak256( + ('0x' + + data.slice( + 2 + Number(base + BigInt(32)) * 2, + 2 + Number(base + BigInt(32) + value) * 2 + )) as Hex + ) + ) + ); + } + if (node.code === 9) return BigInt.asIntN(256, value); + if ( + (node.code === 1 && value >= BigInt(1) << BigInt(255)) || + (node.code === 3 && value > BigInt(1)) || + (node.code === 4 && value >= BigInt(1) << BigInt(160)) + ) + return invalid(); + return BigInt.asIntN(256, value); +} + +function compare(value: bigint, op: Operation, target: bigint): boolean { + switch (op) { + case 'EQUAL': + return value === target; + case 'NOT_EQUAL': + return value !== target; + case 'GREATER_THAN': + return value > target; + case 'GREATER_OR_EQUAL': + return value >= target; + case 'LESS_THAN': + return value < target; + case 'LESS_OR_EQUAL': + return value <= target; + } +} +function combine( + tree: LogicTree, + checks: JobSpecPreview['checks'] +): boolean | null { + const results = tree.of.map((x) => + typeof x === 'number' ? checks[x].pass : combine(x, checks) + ); + const yes = results.filter((v) => v === true).length; + const unknown = results.filter((v) => v === null).length; + const required = + tree.kind === 'ALL' + ? results.length + : tree.kind === 'ANY' + ? 1 + : tree.k ?? 0; + return yes >= required ? true : yes + unknown < required ? false : null; +} + +export async function previewJobSpec( + subject: JobSpec | JobSpecTemplate, + options: PreviewJobSpecOptions +): Promise { + // Validate and copy before asynchronous work; later caller mutations must not change paid criteria. + const input = decodeJobSpec(encodeJobSpec(subject), { + format: 'params' in subject ? 'template' : 'spec', + }); + options = { + ...options, + params: options.params && [...options.params], + baseline: options.baseline && [...options.baseline], + accounts: { ...options.accounts }, + }; + if ( + options.maxTotalFee !== undefined && + (typeof options.maxTotalFee !== 'bigint' || options.maxTotalFee < BigInt(0)) + ) + throw new JobSpecError( + 'INVALID_AMOUNT', + 'maxTotalFee must be a nonnegative bigint.' + ); + if (options.baseline) { + if (options.baseline.length !== input.reads.length) + throw new JobSpecError( + 'INVALID_BASELINE', + 'Provide one baseline entry per read; use null for unknown entries.' + ); + options.baseline.forEach((value) => { + if (value !== null) int256(value); + }); + } + let spec: JobSpec; + if ('params' in input) { + if ( + input.checks.some( + (c) => + c.target === PRINCIPAL || + (typeof c.target === 'object' && 'principalBps' in c.target) + ) && + options.principal === undefined + ) + throw new JobSpecError( + 'UNFILLED_PLACEHOLDER', + 'Supply principal to resolve principal-based preview targets.' + ); + const accounts = { ...options.accounts }; + const resolve = resolvers.get(options.client.universal); + for (const [index, read] of input.reads.entries()) { + const chain = `${read.chainNamespace}:${read.chainId}`; + const needed = + read.fills?.some((f) => f.source === 'WALLET') || + input.checks.some( + (c) => c.read === index && c.target === 'agentic:wallet' + ); + if (needed && !accounts[chain] && options.wallet && resolve) + accounts[chain] = await resolve( + getAddress(options.wallet), + chain as CHAIN + ); + } + spec = resolveJobSpec(input, { + principal: options.principal ?? BigInt(0), + params: options.params ?? [], + accounts, + origin: zeroHash, + executeBy: 0, + settleWindow: 1, + }); + } else spec = input; + const prepared = []; + for (const read of spec.reads) { + const readOptions: ReadPrepareOptions = { + chain: `${read.chainNamespace}:${read.chainId}` as Extract< + CHAIN, + `eip155:${string}` + >, + callData: (read.selector + read.args.slice(2)) as Hex, + minConfirmations: read.minConfirmations, + expiryBlocks: options.expiryBlocks, + refundTo: options.refundTo, + callback: options.callback as ReadPrepareOptions['callback'], + }; + prepared.push( + await options.client.universal.prepareRead(read.target, readOptions) + ); + } + const quoted = prepared.reduce((sum, read) => sum + read.value, BigInt(0)); + if (options.maxTotalFee !== undefined && quoted > options.maxTotalFee) + throw new JobSpecError( + 'PREVIEW_FEE_EXCEEDED', + 'The prepared read fees exceed maxTotalFee. No read was submitted.', + { quoted, maxTotalFee: options.maxTotalFee } + ); + const batch = await options.client.universal.executeReads(prepared, { + progressHook: options.progressHook, + advanced: options.advanced, + waitForCompletion: true, + }); + const reads: JobSpecPreview['reads'] = batch.reads.map((response, i) => { + const value = response.raw?.resultData ?? null; + if (response.outcome !== READ_OUTCOME.SUCCESS || value === null) + return { + value, + decoded: null, + error: + response.errorMsg || 'The paid read did not complete successfully.', + response, + }; + try { + return { + value, + decoded: decodeJobAnswer(spec.reads[i], value), + response, + }; + } catch (e) { + return { value, decoded: null, error: (e as Error).message, response }; + } + }); + const checks: JobSpecPreview['checks'] = spec.checks.map((check) => { + let value = reads[check.read].decoded; + if (value === null) + return { pass: null, value, reason: 'READ_UNAVAILABLE' }; + if (check.evaluation === 'NUMBER' || check.evaluation === 'PERCENTAGE') { + const before = options.baseline?.[check.read]; + if (before === undefined || before === null) + return { pass: null, value: null, reason: 'BASELINE_REQUIRED' }; + if (check.evaluation === 'PERCENTAGE' && before === BigInt(0)) + return { pass: null, value: null, reason: 'ZERO_BASELINE' }; + try { + value = int256(value - before); + if (check.evaluation === 'PERCENTAGE') + value = int256(value * BigInt(10000)) / before; + } catch { + return { pass: null, value: null, reason: 'ARITHMETIC_OVERFLOW' }; + } + } + return { pass: compare(value, check.operation, check.target), value }; + }); + return { + reads, + checks, + pass: combine(spec.logic, checks), + fees: { + quoted, + paid: reads.reduce((sum, r) => sum + r.response.fees.paid, BigInt(0)), + }, + }; +} diff --git a/packages/core/src/lib/job-spec/types.ts b/packages/core/src/lib/job-spec/types.ts index 055d25d2..a3c83a63 100644 --- a/packages/core/src/lib/job-spec/types.ts +++ b/packages/core/src/lib/job-spec/types.ts @@ -2,6 +2,11 @@ import type { Abi, Address, Hex } from 'viem'; import type { ArgumentPath, WalletMarker } from '../agentic/agentic.types'; import type { JOB_VOCABULARY, PRINCIPAL } from './constants'; import type { PushChain } from '../push-chain/push-chain'; +import type { + ReadCallback, + UniversalReadResponse, +} from '../read-state/read-state.types'; +import type { ReadExecuteOptions } from '../read-state/read-params'; export type Evaluation = (typeof JOB_VOCABULARY.EVALUATION)[keyof typeof JOB_VOCABULARY.EVALUATION]; export type Operation = @@ -100,12 +105,29 @@ export interface PreviewJobSpecOptions { wallet?: Address; principal?: bigint; params?: bigint[]; - /** Required for cross-chain template holes: an AGW address is not its destination account. */ + /** Explicit destination accounts override CEA derivation from wallet on a real SDK client. */ accounts?: Record; + /** Optional baseline per read for NUMBER/PERCENTAGE. Missing baselines remain unknown. */ + baseline?: readonly (bigint | null)[]; + /** Existing universal-read registry is used by default. */ + callback?: ReadCallback; + /** Maximum sum of prepared read request values, checked before any payment. */ + maxTotalFee?: bigint; + expiryBlocks?: bigint; + refundTo?: Address; + progressHook?: ReadExecuteOptions['progressHook']; + advanced?: ReadExecuteOptions['advanced']; } export interface JobSpecPreview { - reads: { value: Hex; decoded: bigint }[]; - checks: { pass: boolean | null; value: bigint }[]; + /** A preview is a paid observation, never an evaluator verdict. */ + reads: { + value: Hex | null; + decoded: bigint | null; + error?: string; + response: UniversalReadResponse; + }[]; + checks: { pass: boolean | null; value: bigint | null; reason?: string }[]; pass: boolean | null; + fees: { quoted: bigint; paid: bigint }; } export type JobArgumentPath = ArgumentPath; diff --git a/packages/core/src/lib/market/__tests__/deposit.spec.ts b/packages/core/src/lib/market/__tests__/deposit.spec.ts new file mode 100644 index 00000000..07008a85 --- /dev/null +++ b/packages/core/src/lib/market/__tests__/deposit.spec.ts @@ -0,0 +1,384 @@ +import { + decodeFunctionData, + encodeAbiParameters, + encodeEventTopics, + erc20Abi, + zeroHash, + type Address, + type Hex, +} from 'viem'; +import { depositJob, type DepositCheckpoint } from '../deposit'; +import { DONUT_MARKETPLACE as D } from '../deployment'; +import { MARKETPLACE_ABI } from '../contracts/UniversalMarketplace'; +import { encodeAgentCardRules } from '../rules'; +import { + fakeResponse, + mockRuntime, +} from '../../agentic/__tests__/mock-runtime'; +import { FakeChain } from '../../agentic/__tests__/fake-chain'; +import { buildJobSpec, encodeJobSpec } from '../../job-spec/codec'; +import { prepareJobRead } from '../../job-spec/read'; +import { specOrigin } from '../../job-spec/helpers'; +import { PRINCIPAL } from '../../job-spec/constants'; +import { CHAIN } from '../../constants/enums'; +import type { AgentCard } from '../types'; +import type { MarketSnapshot, StackRuntime } from '../runtime'; + +const sender = '0x1111111111111111111111111111111111111111' as Address; +const wallet = '0x2222222222222222222222222222222222222222' as Address; +const provider = '0x3333333333333333333333333333333333333333' as Address; +const principalToken = '0x4444444444444444444444444444444444444444' as Address; +function setup(sameToken = false) { + const base = mockRuntime(new FakeChain(), { signer: sender }); + const balances = new Map(); + const key = (token: string | undefined, a: string) => + `${token?.toLowerCase() ?? 'PC'}:${a.toLowerCase()}`; + const token = sameToken ? D.paymentToken : principalToken; + for (const t of [token, D.paymentToken, undefined]) + balances.set(key(t, sender), BigInt(1000)); + const state = { + status: 0, + spent: BigInt(0), + receiptUnavailable: false, + move: true, + }; + const description = encodeJobSpec( + buildJobSpec({ + reads: [ + prepareJobRead({ + chain: 'eip155:97', + target: token, + abi: erc20Abi, + functionName: 'balanceOf', + args: [wallet], + }), + ], + checks: [ + { + read: 0, + evaluation: 'COMPARE', + operation: 'GREATER_OR_EQUAL', + target: BigInt(1), + }, + ], + logic: 'ALL', + executeBy: 1700000010, + failFinalAt: 1700000020, + origin: specOrigin(D.marketplace, BigInt(1), BigInt(1), BigInt(10)), + }) + ); + const card = { + cardId: BigInt(1), + version: BigInt(1), + provider, + paymentToken: D.paymentToken, + providerFee: BigInt(5), + rules: { maxGasPerCall: BigInt(7) }, + rulesBytes: encodeAgentCardRules( + { + principalAsset: 0, + maxGasPerCall: BigInt(7), + assets: [ + { + token: { prc20: token }, + maxPerCall: PRINCIPAL, + maxTotal: PRINCIPAL, + }, + ], + allowedCalls: [{ target: token, selector: 'balanceOf(address)' }], + }, + { chain: 'eip155:97' } + ), + } as unknown as AgentCard; + const load = jest.fn(async (_id: bigint, _at: MarketSnapshot) => card); + const read = jest.fn( + async (r: { + functionName: string; + address: string; + args?: readonly unknown[]; + }) => { + switch (r.functionName) { + case 'cardOfJob': + case 'cardVersionOfJob': + return BigInt(1); + case 'agwOfJob': + return wallet; + case 'rulesOfJob': + return zeroHash; + case 'getJob': + return { + client: wallet, + provider, + status: state.status, + expiredAt: 1800000000, + description, + }; + case 'paymentToken': + return D.paymentToken; + case 'isPermissionEnabled': + return true; + case 'getEnabledActions': + return [zeroHash]; + case 'getConfig': + return { initialized: true, assets: [{ spent: state.spent }] }; + case 'balanceOf': + return balances.get(key(r.address, String(r.args?.[0]))) ?? BigInt(0); + default: + throw new Error(`Unexpected ${r.functionName}`); + } + } + ); + const rt: StackRuntime = { + agw: { + ...base, + reader: { + ...base.reader, + readContract: read, + getBlockNumber: async () => BigInt(20), + getBalance: async ({ address }) => + balances.get(key(undefined, address)) ?? BigInt(0), + getLogs: async () => + [ + { + address: D.marketplace, + blockNumber: BigInt(10), + data: encodeAbiParameters( + [ + { type: 'uint256' }, + { type: 'bytes32' }, + { type: 'uint256' }, + { type: 'uint256' }, + ], + [BigInt(1), zeroHash, BigInt(10), BigInt(1)] + ), + topics: encodeEventTopics({ + abi: MARKETPLACE_ABI, + eventName: 'JobOpened', + args: { cardId: BigInt(1), owner: sender, agw: wallet }, + }), + }, + ] as never, + }, + }, + account: () => sender, + wallet: () => undefined, + send: jest.fn(), + signTypedData: jest.fn(), + jobBlocks: new Map([[BigInt(1), BigInt(10)]]), + }; + base.executeMock.mockImplementation( + async (p: { + to: Address; + data?: Hex; + value?: bigint; + funds?: { amount: bigint }; + }) => { + let asset: Address | undefined; + let amount = p.value ?? BigInt(0); + if (p.funds) { + asset = D.paymentToken; + amount = p.funds.amount; + } else if (p.data && p.data !== '0x') { + const call = decodeFunctionData({ abi: erc20Abi, data: p.data }); + if (call.functionName !== 'transfer' || call.args[0] !== wallet) + throw new Error('Wrong transfer'); + asset = p.to; + amount = call.args[1]; + } + if (state.move) { + balances.set( + key(asset, wallet), + (balances.get(key(asset, wallet)) ?? BigInt(0)) + amount + ); + balances.set( + key(asset, sender), + (balances.get(key(asset, sender)) ?? BigInt(0)) - amount + ); + } + const tx = fakeResponse(); + const wait = tx.wait.bind(tx); + return { + ...tx, + wait: async () => { + if (state.receiptUnavailable) throw new Error('RPC timed out'); + return wait(); + }, + }; + } + ); + const checkpoints = new Map(); + const run = (options: Parameters[2] = {}) => + depositJob(rt, BigInt(1), options, load, checkpoints); + return { + run, + rt, + balances, + key, + token, + load, + card, + state, + execute: base.executeMock, + checkpoints, + }; +} +it('uses the opened version and original principal, not a newly updated card', async () => { + const f = setup(); + const result = await f.run(); + expect(f.load.mock.calls[0][1].blockNumber).toBe(BigInt(10)); + expect(result.cardVersion).toBe(BigInt(1)); + expect(result.txs.map((t) => [t.step, t.amount])).toEqual([ + ['PRINCIPAL', BigInt(10)], + ['PROVIDER_FEE', BigInt(5)], + ['PC', BigInt(7)], + ]); + expect((await f.run()).txs).toEqual([]); +}); +it('combines a shared principal/fee token before subtracting the existing balance', async () => { + const f = setup(true); + f.balances.set(f.key(f.token, wallet), BigInt(3)); + const result = await f.run({ pcAmount: BigInt(0) }); + expect(result.txs).toHaveLength(1); + expect(result.txs[0]).toMatchObject({ + step: 'PRINCIPAL_AND_FEE', + amount: BigInt(12), + }); +}); +it('preflights every asset before sending any partial deposit', async () => { + const f = setup(); + f.balances.set(f.key(D.paymentToken, sender), BigInt(0)); + await expect(f.run()).rejects.toMatchObject({ + code: 'DEPOSIT_INCOMPLETE', + details: { causeCode: 'INSUFFICIENT_FUNDS', txs: [] }, + }); + expect(f.execute).not.toHaveBeenCalled(); +}); +it('resumes an uncertain receipt without resending the committed principal', async () => { + const f = setup(); + f.state.receiptUnavailable = true; + await expect(f.run()).rejects.toMatchObject({ + code: 'DEPOSIT_INCOMPLETE', + details: { txs: [expect.objectContaining({ step: 'PRINCIPAL' })] }, + }); + expect(f.execute).toHaveBeenCalledTimes(1); + // An unresolved prior receipt must still prevent another transaction. + await expect(f.run()).rejects.toMatchObject({ code: 'DEPOSIT_INCOMPLETE' }); + expect(f.execute).toHaveBeenCalledTimes(1); + f.state.receiptUnavailable = false; + const resumed = await f.run(); + expect(resumed.txs.map((t) => t.step)).toEqual([ + 'PRINCIPAL', + 'PROVIDER_FEE', + 'PC', + ]); + expect(f.execute).toHaveBeenCalledTimes(3); +}); +it('refuses to replenish a resumed transfer that has since been consumed', async () => { + const f = setup(); + f.state.receiptUnavailable = true; + await expect(f.run()).rejects.toMatchObject({ code: 'DEPOSIT_INCOMPLETE' }); + f.state.receiptUnavailable = false; + f.balances.set(f.key(f.token, wallet), BigInt(0)); + await expect(f.run()).rejects.toMatchObject({ + details: { causeCode: 'DEPOSIT_BALANCE_CHANGED' }, + }); + expect(f.execute).toHaveBeenCalledTimes(1); +}); +it('fails closed if same-block updates hide the original card version', async () => { + const f = setup(); + f.card.version = BigInt(2); + await expect(f.run()).rejects.toMatchObject({ code: 'HISTORY_UNAVAILABLE' }); + expect(f.execute).not.toHaveBeenCalled(); +}); +it('refuses terminal jobs and permissions that have already moved assets', async () => { + const f = setup(); + f.state.status = 1; + await expect(f.run()).rejects.toMatchObject({ code: 'WRONG_STATUS' }); + f.state.status = 0; + f.state.spent = BigInt(1); + await expect(f.run()).rejects.toMatchObject({ + details: { causeCode: 'DEPOSIT_ALREADY_USED' }, + }); + expect(f.execute).not.toHaveBeenCalled(); +}); +it('retains a receipt when a token returns success without delivering the required balance', async () => { + const f = setup(); + f.state.move = false; + await expect(f.run()).rejects.toMatchObject({ + details: { causeCode: 'DEPOSIT_BALANCE_CHANGED', txs: [expect.anything()] }, + }); + expect(f.execute).toHaveBeenCalledTimes(1); +}); +it('uses an explicit registered origin route and keeps its recipient outside AGW execution', async () => { + const f = setup(true); + f.rt.agw.signerIsPushNative = () => false; + f.rt.agw.signerOrigin = () => ({ + chain: CHAIN.ETHEREUM_SEPOLIA, + address: sender, + }); + f.balances.set(f.key(D.paymentToken, sender), BigInt(0)); + const result = await f.run({ funding: 'origin', pcAmount: BigInt(0) }); + expect(result.txs[0]).toMatchObject({ + step: 'PRINCIPAL_AND_FEE', + amount: BigInt(15), + }); + expect(f.execute).toHaveBeenCalledWith( + { + to: wallet, + funds: { + token: expect.objectContaining({ symbol: 'USDC' }), + amount: BigInt(15), + }, + }, + expect.anything() + ); +}); +it('refuses an origin token mismatch before sending any leg', async () => { + const f = setup(); + f.rt.agw.signerIsPushNative = () => false; + f.rt.agw.signerOrigin = () => ({ + chain: CHAIN.ETHEREUM_SEPOLIA, + address: sender, + }); + await expect(f.run({ funding: 'origin' })).rejects.toMatchObject({ + details: { causeCode: 'TOKEN_ROUTE_UNAVAILABLE' }, + }); + expect(f.execute).not.toHaveBeenCalled(); +}); +it('blocks retries when the transport reports a broadcast hash without returning a response', async () => { + const f = setup(); + const hash = ('0x' + 'ab'.repeat(32)) as Hex; + f.execute.mockImplementationOnce(async () => { + f.balances.set(f.key(f.token, wallet), BigInt(10)); + throw Object.assign(new Error('Inbound confirmation unavailable'), { + gatewayTxHash: hash, + }); + }); + await expect(f.run()).rejects.toMatchObject({ + details: { + txs: [], + pending: { txHash: hash, token: f.token, amount: BigInt(10) }, + }, + }); + await expect(f.run()).rejects.toMatchObject({ + code: 'DEPOSIT_INCOMPLETE', + details: { pending: { txHash: hash } }, + }); + expect(f.execute).toHaveBeenCalledTimes(1); + const result = await f.run({ + resume: [ + { + step: 'PRINCIPAL', + token: f.token, + amount: BigInt(10), + tx: fakeResponse({ hash }), + }, + ], + }); + expect(result.txs.map((t) => t.step)).toEqual([ + 'PRINCIPAL', + 'PROVIDER_FEE', + 'PC', + ]); + expect(f.execute).toHaveBeenCalledTimes(3); +}); diff --git a/packages/core/src/lib/market/__tests__/namespace.spec.ts b/packages/core/src/lib/market/__tests__/namespace.spec.ts index c2ccbda4..a0bf5e48 100644 --- a/packages/core/src/lib/market/__tests__/namespace.spec.ts +++ b/packages/core/src/lib/market/__tests__/namespace.spec.ts @@ -4,6 +4,7 @@ import { JobNamespaceImpl } from '../../job/job'; import { mockRuntime } from '../../agentic/__tests__/mock-runtime'; import { FakeChain } from '../../agentic/__tests__/fake-chain'; import type { StackRuntime } from '../runtime'; +import type { JobPlan } from '../types'; const owner = '0x1111111111111111111111111111111111111111'; const provider = '0x2222222222222222222222222222222222222222'; function runtime(signer: Address = owner) { @@ -115,9 +116,49 @@ it('placeholder methods and replacement proposals fail before any reads or signa await expect( job.setBudget(BigInt(1), BigInt(5), { jobSpec: '0x00' }) ).rejects.toMatchObject({ code: 'CAPABILITY_UNAVAILABLE' }); - await expect(market.deposit(BigInt(1))).rejects.toMatchObject({ - code: 'CAPABILITY_UNAVAILABLE', - }); + await expect( + market.openJob({} as never, { relay: true }) + ).rejects.toMatchObject({ code: 'CAPABILITY_UNAVAILABLE' }); + expect(read).not.toHaveBeenCalled(); + expect(rt.signTypedData).not.toHaveBeenCalled(); +}); +it('checks typed-data capability and external owner deployment before asking for a signature', async () => { + const { rt, read } = runtime(); + rt.canSignTypedData = () => false; + await expect( + new MarketNamespaceImpl(rt).openJob({} as JobPlan) + ).rejects.toMatchObject({ code: 'CAPABILITY_UNAVAILABLE' }); expect(read).not.toHaveBeenCalled(); + rt.canSignTypedData = () => true; + rt.agw.reader.call = jest.fn(); + rt.agw.reader.getCode = async () => '0x'; + rt.agw.signerIsPushNative = () => false; + await expect( + new MarketNamespaceImpl(rt).openJob({} as JobPlan) + ).rejects.toMatchObject({ code: 'OWNER_NOT_DEPLOYED' }); + expect(rt.signTypedData).not.toHaveBeenCalled(); +}); +it('compares the factory signing domain before prompting the owner', async () => { + const { rt, read } = runtime(); + rt.agw.reader.call = jest.fn(); + rt.agw.reader.getCode = async () => '0x'; + read.mockResolvedValue(zeroHash as never); + const market = new MarketNamespaceImpl(rt); + const plan = { + cardId: BigInt(1), + intent: { + owner, + index: BigInt(0), + signerChainId: BigInt(42101), + deadline: 1800000000, + }, + label: 'test', + job: {}, + } as unknown as JobPlan; + jest.spyOn(market, 'preview').mockResolvedValue(plan); + await expect(market.openJob(plan)).rejects.toMatchObject({ + code: 'INTENT_MISMATCH', + }); expect(rt.signTypedData).not.toHaveBeenCalled(); + expect(rt.agw.reader.call).not.toHaveBeenCalled(); }); diff --git a/packages/core/src/lib/market/deposit.ts b/packages/core/src/lib/market/deposit.ts new file mode 100644 index 00000000..20d43944 --- /dev/null +++ b/packages/core/src/lib/market/deposit.ts @@ -0,0 +1,454 @@ +import { + decodeEventLog, + encodeFunctionData, + erc20Abi, + getAbiItem, + getAddress, + zeroAddress, + type Address, + type Hex, +} from 'viem'; +import { MARKETPLACE_ABI as ABI } from './contracts/UniversalMarketplace'; +import { JOB_KERNEL_ABI } from './contracts/AgenticCommerce'; +import { KERNEL_READ_ABI } from './kernel-wire'; +import { decodeJobSpec } from '../job-spec/codec'; +import { specOrigin } from '../job-spec/helpers'; +import { currentGeneration } from '../agentic/deployments'; +import { configId } from '../agentic/codec/ids'; +import { scanLogs } from '../agentic/reads/snapshot'; +import { confirmedLogs } from '../agentic/management/common'; +import { decodeCardRulesWire } from './rules'; +import { MOVEABLE_TOKENS, type MoveableToken } from '../constants/tokens'; +import { getPRC20Address } from '../universal/prc20-address'; +import { MarketError } from './errors'; +import { + deployment, + progress, + snapshot, + write, + type MarketSnapshot, + type StackRuntime, +} from './runtime'; +import type { + AgentCard, + MarketDepositOptions, + MarketDepositResult, + MarketDepositStep, +} from './types'; + +type LoadCard = (cardId: bigint, at: MarketSnapshot) => Promise; +export interface DepositCheckpoint { + txs: MarketDepositStep[]; + pending?: MarketDepositResult['pending']; +} +interface Asset { + step: MarketDepositStep['step']; + token?: Address; + required: bigint; + originToken?: MoveableToken; +} +const uint256 = (n: bigint): void => { + if (typeof n !== 'bigint' || n < BigInt(0) || n >= BigInt(1) << BigInt(256)) + throw new MarketError( + 'INVALID_AMOUNT', + 'Deposit amounts must fit uint256.' + ); +}; +function submittedHash( + cause: unknown, + seen = new Set() +): string | undefined { + if (!cause || typeof cause !== 'object' || seen.has(cause) || seen.size > 16) + return; + seen.add(cause); + const value = cause as Record; + for (const key of ['gatewayTxHash', 'pendingTransactionHash', 'txHash']) + if (typeof value[key] === 'string' && value[key]) + return value[key] as string; + for (const key of ['cause', 'error', 'details']) { + const found = submittedHash(value[key], seen); + if (found) return found; + } + return; +} +const sameAsset = (a?: Address, b?: Address): boolean => + a === undefined || b === undefined + ? a === b + : getAddress(a) === getAddress(b); + +/** Recover amounts from the block that opened the job, never today's mutable card. */ +export async function openedDeposit( + rt: StackRuntime, + jobId: bigint, + loadCard: LoadCard +): Promise<{ result: MarketDepositResult; assets: Asset[]; rulesId: Hex }> { + if (typeof jobId !== 'bigint' || jobId < BigInt(1)) + throw new MarketError( + 'INVALID_JOB_ID', + 'Job IDs are positive bigint values.' + ); + const s = await snapshot(rt); + const d = deployment(rt); + const [cardId, version, wallet, rulesId, kernel] = await Promise.all([ + s.read(d.marketplace, ABI, 'cardOfJob', [jobId]), + s.read(d.marketplace, ABI, 'cardVersionOfJob', [jobId]), + s.read
    (d.marketplace, ABI, 'agwOfJob', [jobId]), + s.read(d.marketplace, ABI, 'rulesOfJob', [jobId]), + s.read<{ + client: Address; + status: number; + expiredAt: number; + provider: Address; + description: Hex; + }>(d.kernel, KERNEL_READ_ABI, 'getJob', [jobId]), + ]); + if (!cardId || getAddress(wallet) === zeroAddress) + throw new MarketError( + 'NOT_MARKETPLACE_JOB', + 'This job was not opened through this marketplace.' + ); + if (kernel.status !== 0 || kernel.expiredAt <= s.timestamp) + throw new MarketError( + 'WRONG_STATUS', + 'Deposit only while the job is Open and unexpired.' + ); + if (getAddress(kernel.client) !== getAddress(wallet)) + throw new MarketError( + 'INCONSISTENT_READ', + 'The marketplace wallet differs from the kernel client.' + ); + + let block = rt.jobBlocks?.get(jobId); + if (block === undefined) { + const created = await scanLogs( + rt.agw.reader, + { + address: d.kernel, + event: getAbiItem({ abi: JOB_KERNEL_ABI, name: 'JobCreated' }), + args: { jobId }, + }, + d.startBlock, + s.blockNumber + ); + if (created.length !== 1 || created[0].blockNumber === null) + throw new MarketError( + 'HISTORY_UNAVAILABLE', + 'Could not recover one creation block for this job.' + ); + block = created[0].blockNumber; + } + const logs = await scanLogs( + rt.agw.reader, + { + address: d.marketplace, + event: getAbiItem({ abi: ABI, name: 'JobOpened' }), + args: { cardId, agw: wallet }, + }, + block, + block + ); + const events = logs + .map( + (l) => + decodeEventLog({ + abi: ABI, + eventName: 'JobOpened', + data: l.data, + topics: l.topics, + strict: true, + }).args + ) + .filter((e) => e.jobId === jobId); + if (events.length !== 1) + throw new MarketError( + 'HISTORY_UNAVAILABLE', + 'Could not recover one marketplace opening for this job.' + ); + const opened = events[0]; + const card = await loadCard(cardId, await snapshot(rt, block)); + if (card.version !== version || opened.cardVersion !== version) + throw new MarketError( + 'HISTORY_UNAVAILABLE', + 'The opening block does not expose the exact opened card version. An archive with transaction-level history is required.' + ); + const spec = decodeJobSpec(kernel.description, { format: 'spec' }); + if ( + !('origin' in spec) || + spec.origin !== + specOrigin(d.marketplace, cardId, version, opened.principal) || + opened.rulesId !== rulesId || + getAddress(opened.agw) !== getAddress(wallet) || + getAddress(card.provider) !== getAddress(kernel.provider) + ) + throw new MarketError( + 'INCONSISTENT_READ', + 'The historical opening does not match the stored job.' + ); + const token = await s.read
    (d.kernel, JOB_KERNEL_ABI, 'paymentToken'); + if (getAddress(card.paymentToken) !== getAddress(token)) + throw new MarketError( + 'TOKEN_MISMATCH', + 'The opened card and kernel use different payment tokens.' + ); + rt.jobBlocks?.set(jobId, block); + const rules = decodeCardRulesWire(card.rulesBytes); + return { + result: { + jobId, + wallet: getAddress(wallet), + cardId, + cardVersion: version, + txs: [], + }, + assets: [ + { + step: 'PRINCIPAL', + token: getAddress(rules.assets[rules.principalAsset].token), + required: opened.principal, + }, + { + step: 'PROVIDER_FEE', + token: getAddress(token), + required: card.providerFee, + }, + { step: 'PC', required: card.rules.maxGasPerCall }, + ], + rulesId, + }; +} + +/** Separate, confirmed top-ups from the signer's Push identity. Does not fund kernel escrow. */ +export async function depositJob( + rt: StackRuntime, + jobId: bigint, + options: MarketDepositOptions, + loadCard: LoadCard, + checkpoints: Map +): Promise { + if (rt.agw.isReadOnly) + throw new MarketError('READ_ONLY', 'Connect a signing wallet to deposit.'); + if ('skipApprovals' in options) + throw new MarketError( + 'INVALID_DEPOSIT_OPTIONS', + 'V2 cards grant pinned approvals to the agent; deposit has no owner approval step.' + ); + if ( + options.funding !== undefined && + !['push', 'origin'].includes(options.funding) + ) + throw new MarketError( + 'INVALID_DEPOSIT_OPTIONS', + 'Choose push or origin deposit funding.' + ); + if (options.funding === 'origin' && rt.agw.signerIsPushNative()) + throw new MarketError( + 'INVALID_DEPOSIT_OPTIONS', + 'Use push funding for a Push-native signer.' + ); + if (options.pcAmount !== undefined) uint256(options.pcAmount); + if (options.providerFee !== undefined) uint256(options.providerFee); + const { result, assets, rulesId } = await openedDeposit(rt, jobId, loadCard); + const previous = checkpoints.get(jobId); + result.txs = [...(options.resume ?? previous?.txs ?? [])]; + if ( + previous?.pending && + !result.txs.some((t) => sameAsset(t.token, previous.pending?.token)) + ) + throw new MarketError( + 'DEPOSIT_INCOMPLETE', + 'A broadcast deposit still needs tracking. Rehydrate its response and pass it as a resume step before sending more.', + { ...result, pending: previous.pending } + ); + const fee = assets[1]; + fee.required = options.providerFee ?? fee.required; + assets[2].required = options.pcAmount ?? assets[2].required; + if (assets[0].token === fee.token) { + assets[0].step = 'PRINCIPAL_AND_FEE'; + assets[0].required += fee.required; + uint256(assets[0].required); + assets.splice(1, 1); + } + const balance = async (asset: Asset, account: Address): Promise => + asset.token + ? (await snapshot(rt)).read(asset.token, erc20Abi, 'balanceOf', [ + account, + ]) + : rt.agw.reader.getBalance({ address: account }); + const available = async (): Promise => { + const s = await snapshot(rt); + const d = deployment(rt); + const job = await s.read<{ status: number; expiredAt: number }>( + d.kernel, + KERNEL_READ_ABI, + 'getJob', + [jobId] + ); + if (job.status !== 0 || job.expiredAt <= s.timestamp) + throw new MarketError( + 'WRONG_STATUS', + 'The job is no longer Open and unexpired.' + ); + const gen = currentGeneration(rt.agw.network); + if ( + !(await s.read( + gen.addresses.sessionEngine, + gen.contracts.abis.engine, + 'isPermissionEnabled', + [rulesId, result.wallet] + )) + ) + throw new MarketError( + 'RULE_NOT_FOUND', + 'The job permission is no longer enabled.' + ); + const actions = await s.read( + gen.addresses.sessionEngine, + gen.contracts.abis.engine, + 'getEnabledActions', + [result.wallet, rulesId] + ); + if (actions.length !== 1) + throw new MarketError( + 'INCONSISTENT_READ', + 'The job permission has an unexpected action count.' + ); + const config = await s.read<{ + initialized: boolean; + assets: readonly { spent: bigint }[]; + }>(gen.addresses.rulesPolicy, gen.contracts.abis.policy, 'getConfig', [ + configId(result.wallet, rulesId, actions[0]), + result.wallet, + ]); + if (!config.initialized || config.assets.some((a) => a.spent > BigInt(0))) + throw new MarketError( + 'DEPOSIT_ALREADY_USED', + 'The job permission has already moved assets. Review funding manually before adding more.' + ); + }; + const checkpoint: DepositCheckpoint = { + txs: result.txs, + pending: previous?.pending, + }; + checkpoints.set(jobId, checkpoint); + let submitting: Omit | undefined; + try { + // Uncertain prior receipts must settle before balances can authorize another transfer. + for (const step of result.txs) await confirmedLogs(rt.agw, step.tx); + checkpoint.pending = undefined; + await available(); + for (const asset of assets) { + const held = await balance(asset, result.wallet); + if (held >= asset.required) continue; + if (result.txs.some((t) => sameAsset(t.token, asset.token))) + throw new MarketError( + 'DEPOSIT_BALANCE_CHANGED', + 'A confirmed deposit no longer covers its target balance. Review the wallet before sending more.' + ); + const needed = asset.required - held; + if (asset.token && options.funding === 'origin') { + const chain = rt.agw.signerOrigin().chain; + asset.originToken = (MOVEABLE_TOKENS[chain] ?? []).find((candidate) => { + try { + return ( + getAddress( + getPRC20Address( + { chain, address: candidate.address }, + { network: rt.agw.network } + ).address + ) === asset.token + ); + } catch { + return false; + } + }); + if (!asset.originToken) + throw new MarketError( + 'TOKEN_ROUTE_UNAVAILABLE', + 'This deposit token has no registered route from the connected origin chain. Prefund it on Push or connect its origin.', + { chain, token: asset.token } + ); + continue; + } + const source = getAddress(rt.agw.signerPushAccount()); + if (source === result.wallet || (await balance(asset, source)) < needed) + throw new MarketError( + 'INSUFFICIENT_FUNDS', + 'The connected signer’s Push account cannot cover this deposit.', + { token: asset.token, required: needed, account: source } + ); + } + for (const asset of assets) { + await available(); + const held = await balance(asset, result.wallet); + if (held >= asset.required) continue; + const amount = asset.required - held; + if (result.txs.some((t) => sameAsset(t.token, asset.token))) + throw new MarketError( + 'DEPOSIT_BALANCE_CHANGED', + 'A confirmed deposit balance changed before the next step. Review the wallet before sending more.' + ); + submitting = { step: asset.step, token: asset.token, amount }; + const tx = asset.originToken + ? await rt.agw.execute( + { to: result.wallet, funds: { token: asset.originToken, amount } }, + { progressHook: options.progressHook } + ) + : await write( + rt, + asset.token + ? { + target: asset.token, + value: BigInt(0), + data: encodeFunctionData({ + abi: erc20Abi, + functionName: 'transfer', + args: [result.wallet, amount], + }), + } + : { target: result.wallet, value: amount, data: '0x' }, + options.progressHook, + 'MARKET', + true + ); + result.txs.push({ step: asset.step, token: asset.token, amount, tx }); + submitting = undefined; + progress( + rt, + options.progressHook, + 'MARKET-TX-111', + 'Deposit step submitted', + { step: asset.step, token: asset.token, amount, txHash: tx.hash } + ); + await confirmedLogs(rt.agw, tx); + if ((await balance(asset, result.wallet)) < asset.required) + throw new MarketError( + 'DEPOSIT_BALANCE_CHANGED', + 'The transfer did not establish the required wallet balance. Review the receipt before retrying.' + ); + } + checkpoints.delete(jobId); + return result; + } catch (cause) { + const txHash = submitting && submittedHash(cause); + if (submitting && txHash) { + checkpoint.pending = { + ...submitting, + txHash, + chain: + options.funding === 'origin' && submitting.token + ? rt.agw.signerOrigin().chain + : rt.agw.pushChainNamespace, + }; + } + throw new MarketError( + 'DEPOSIT_INCOMPLETE', + 'The deposit did not finish. Resume with the recorded transactions after resolving the cause.', + { + ...result, + ...(checkpoint.pending ? { pending: checkpoint.pending } : {}), + causeCode: cause instanceof MarketError ? cause.code : undefined, + }, + cause + ); + } +} diff --git a/packages/core/src/lib/market/market.ts b/packages/core/src/lib/market/market.ts index 212438d8..a1930b2d 100644 --- a/packages/core/src/lib/market/market.ts +++ b/packages/core/src/lib/market/market.ts @@ -1,6 +1,7 @@ import { encodeFunctionData, getAddress, + domainSeparator, keccak256, stringToHex, toHex, @@ -33,6 +34,7 @@ import { fillCardRules, } from './rules'; import { decodeCreateJob } from './kernel-wire'; +import { depositJob, type DepositCheckpoint } from './deposit'; import { deployment, eventArgs, @@ -42,7 +44,7 @@ import { type MarketSnapshot, type StackRuntime, } from './runtime'; -import { MarketError, unavailable } from './errors'; +import { MarketError, stackError, unavailable } from './errors'; import type { AgentCard, AgentCardInput, @@ -52,6 +54,7 @@ import type { MarketNamespace, MarketPreviewOptions, MarketWriteOptions, + MarketDepositOptions, OwnerIntent, } from './types'; import type { CHAIN } from '../constants/enums'; @@ -95,6 +98,8 @@ function id(n: bigint): void { export class MarketNamespaceImpl implements MarketNamespace { constructor(private readonly rt: StackRuntime) {} + private readonly deposits = new Set(); + private readonly depositCheckpoints = new Map(); private async viewAt(cardId: bigint, s: MarketSnapshot): Promise { id(cardId); const d = deployment(this.rt); @@ -517,21 +522,22 @@ export class MarketNamespaceImpl implements MarketNamespace { options: MarketWriteOptions & { relay?: boolean } = {} ) { if (options.relay) unavailable('Marketplace relaying'); - if (!this.rt.agw.signerIsPushNative()) - unavailable( - 'External-owner marketplace signatures pending ERC-1271 acceptance' - ); if (this.rt.agw.isReadOnly) throw new MarketError( 'READ_ONLY', 'Connect a signing wallet to open a job.' ); + if (this.rt.canSignTypedData?.() === false) + unavailable('EIP-712 signing with this wallet'); + if (!this.rt.agw.reader.call) + unavailable('Signed marketplace transaction simulation with this reader'); const ownerCode = await this.rt.agw.reader.getCode({ address: this.rt.agw.signerPushAccount(), }); - if (ownerCode && ownerCode !== '0x') - unavailable( - 'Delegated or contract-owner intent signing pending ERC-1271 acceptance' + if (!this.rt.agw.signerIsPushNative() && (!ownerCode || ownerCode === '0x')) + throw new MarketError( + 'OWNER_NOT_DEPLOYED', + 'Deploy the connected signer’s UEA on Push before signing a marketplace intent.' ); const fresh = await this.preview(plan.cardId, { ...plan.job, @@ -550,51 +556,81 @@ export class MarketNamespaceImpl implements MarketNamespace { cardId: plan.cardId, wallet: plan.wallet, }); - const sig = (await this.rt.signTypedData({ - domain: { - name: 'AGWFactory', - version: '1', - chainId: Number(plan.intent.signerChainId), - verifyingContract: gen.addresses.factory, - salt: toHex(BigInt(this.rt.agw.pushChainNamespace.split(':')[1]), { - size: 32, - }), - }, - types: { OwnerIntent: ownerIntentFields }, - primaryType: 'OwnerIntent', - message: { ...plan.intent }, - })) as Hex; + const domain = { + name: 'AGWFactory', + version: '1', + chainId: Number(plan.intent.signerChainId), + verifyingContract: gen.addresses.factory, + salt: toHex(BigInt(this.rt.agw.pushChainNamespace.split(':')[1]), { + size: 32, + }), + }; + const separator = await ( + await snapshot(this.rt) + ).read( + gen.addresses.factory, + gen.contracts.abis.factory, + 'domainSeparator', + [plan.intent.signerChainId] + ); + if (separator.toLowerCase() !== domainSeparator({ domain }).toLowerCase()) + throw new MarketError( + 'INTENT_MISMATCH', + 'The factory EIP-712 domain differs from the signing domain.' + ); + let sig: Hex; + try { + sig = (await this.rt.signTypedData({ + domain, + types: { OwnerIntent: ownerIntentFields }, + primaryType: 'OwnerIntent', + message: { ...plan.intent }, + })) as Hex; + } catch (error) { + throw stackError(error); + } progress( this.rt, options.progressHook, 'MARKET-TX-102', 'Owner intent signed' ); - const tx = await write( - this.rt, - { - target: d.marketplace, - value: BigInt(0), - data: encodeFunctionData({ - abi: ABI, - functionName: 'openJob', - args: [ - { - cardId: plan.cardId, - cardVersion: plan.cardVersion, - job: plan.job, - session: plan.session, - intent: plan.intent, - sig, - label: plan.label, - }, - ], - }), - }, - options.progressHook, - 'MARKET', - true - ); + const call = { + target: d.marketplace, + value: BigInt(0), + data: encodeFunctionData({ + abi: ABI, + functionName: 'openJob', + args: [ + { + cardId: plan.cardId, + cardVersion: plan.cardVersion, + job: plan.job, + session: plan.session, + intent: plan.intent, + sig, + label: plan.label, + }, + ], + }), + }; + try { + // Runs the actual factory, owner verifier (UEA / ERC-1271 / EOA), grant and kernel create. + // This catches unsupported 7702 delegates without spending gas or bypassing owner verification. + await this.rt.agw.reader.call({ + to: call.target, + data: call.data, + account: this.rt.agw.signerPushAccount(), + }); + } catch (cause) { + throw new MarketError( + 'OPEN_JOB_SIMULATION_FAILED', + 'The signed marketplace request failed simulation. No transaction was submitted.', + { contractError: stackError(cause) }, + cause + ); + } + const tx = await write(this.rt, call, options.progressHook, 'MARKET', true); const e = await eventArgs(this.rt, tx, d.marketplace, ABI, 'JobOpened'); if ( e['cardId'] !== plan.cardId || @@ -615,14 +651,24 @@ export class MarketNamespaceImpl implements MarketNamespace { tx, }; } - async deposit(_jobId: bigint, _options?: MarketWriteOptions): Promise { - void _jobId; - void _options; - throw new MarketError( - 'CAPABILITY_UNAVAILABLE', - 'Automatic deposits are not implemented yet. Fund the AGW explicitly, then call client.job.fund.', - { feature: 'market.deposit' } - ); + async deposit(jobId: bigint, options: MarketDepositOptions = {}) { + if (this.deposits.has(jobId)) + throw new MarketError( + 'DEPOSIT_IN_PROGRESS', + 'A deposit for this job is already running on this client.' + ); + this.deposits.add(jobId); + try { + return await depositJob( + this.rt, + jobId, + options, + (id, s) => this.cardAt(id, s), + this.depositCheckpoints + ); + } finally { + this.deposits.delete(jobId); + } } readonly agent = { card: async (): Promise => { diff --git a/packages/core/src/lib/market/runtime.ts b/packages/core/src/lib/market/runtime.ts index 33f52f17..4f429dd2 100644 --- a/packages/core/src/lib/market/runtime.ts +++ b/packages/core/src/lib/market/runtime.ts @@ -36,6 +36,7 @@ export interface StackRuntime { primaryType: string; message: Record; }): Promise; + canSignTypedData?(): boolean; /** Internal fixture override; never a public initialization option. */ deployment?: MarketDeployment; /** Receipt-confirmed creation blocks accelerate bounded event recovery. */ @@ -54,8 +55,11 @@ export interface MarketSnapshot { args?: readonly unknown[] ): Promise; } -export async function snapshot(rt: StackRuntime): Promise { - const blockNumber = await rt.agw.reader.getBlockNumber(); +export async function snapshot( + rt: StackRuntime, + atBlock?: bigint +): Promise { + const blockNumber = atBlock ?? (await rt.agw.reader.getBlockNumber()); const timestamp = rt.agw.reader.getBlock ? Number((await rt.agw.reader.getBlock({ blockNumber })).timestamp) : rt.agw.nowSeconds(); diff --git a/packages/core/src/lib/market/types.ts b/packages/core/src/lib/market/types.ts index b430a347..9e22ecfe 100644 --- a/packages/core/src/lib/market/types.ts +++ b/packages/core/src/lib/market/types.ts @@ -91,6 +91,33 @@ export interface MarketPreviewOptions extends Omit { export interface MarketWriteOptions { progressHook?: StackProgressHook; } +export interface MarketDepositStep { + /** PRINCIPAL_AND_FEE combines requirements when both use the same token. */ + step: 'PRINCIPAL' | 'PROVIDER_FEE' | 'PRINCIPAL_AND_FEE' | 'PC'; + token?: Address; + amount: bigint; + tx: UniversalTxResponse; +} +export interface MarketDepositOptions extends MarketWriteOptions { + /** Token transfers use Push holdings by default. Origin explicitly bridges matching registered assets; PC always uses Push holdings. */ + funding?: 'push' | 'origin'; + /** Wallet PC balance to reach. Defaults to the opened card's per-call gas cap. */ + pcAmount?: bigint; + /** Wallet fee reserve to reach. Defaults to the opened card's reference fee; does not accept a kernel price. */ + providerFee?: bigint; + /** Previously submitted steps. Their waits must settle before any further transfer. */ + resume?: readonly MarketDepositStep[]; +} +export interface MarketDepositResult { + jobId: bigint; + wallet: Address; + cardId: bigint; + cardVersion: bigint; + /** Includes resumed transactions, in submission order. */ + txs: MarketDepositStep[]; + /** A broadcast that failed before returning a response. Track it before resuming. */ + pending?: Omit & { txHash: string; chain: string }; +} export interface MarketNamespace { cards(options?: { provider?: Address; @@ -108,10 +135,11 @@ export interface MarketNamespace { rulesId: Hex; tx: UniversalTxResponse; }>; - deposit(jobId: bigint, options?: MarketWriteOptions): Promise; - job( - jobId: bigint - ): Promise<{ + deposit( + jobId: bigint, + options?: MarketDepositOptions + ): Promise; + job(jobId: bigint): Promise<{ cardId: bigint; cardVersion: bigint; wallet: Address; diff --git a/packages/core/src/lib/push-chain/push-chain.ts b/packages/core/src/lib/push-chain/push-chain.ts index cf5f3b87..9b35f44a 100644 --- a/packages/core/src/lib/push-chain/push-chain.ts +++ b/packages/core/src/lib/push-chain/push-chain.ts @@ -60,6 +60,7 @@ import { JobNamespaceImpl } from '../job/job'; import type { MarketNamespace } from '../market/types'; import type { JobNamespace } from '../job/types'; import type { StackRuntime } from '../market/runtime'; +import { bindJobPreviewAccounts } from '../job-spec/preview'; import { prepareJobRead } from '../job-spec/read'; /** Options accepted by `PushChain.initialize` / `reinitialize`. */ @@ -345,6 +346,7 @@ export class PushChain { wallet: () => this.agenticContext?.wallet, send: (params, options) => this.universal.sendTransaction(params, options), signTypedData: (data) => this.universal.signTypedData(data), + canSignTypedData: () => typeof this.universalSigner.signTypedData === 'function', }; this.market = new MarketNamespaceImpl(stackRuntime); this.job = new JobNamespaceImpl(stackRuntime); @@ -474,6 +476,8 @@ export class PushChain { }, }; + bindJobPreviewAccounts(this.universal, async (wallet, chain) => (await this.agenticRuntime.resolveCEA(wallet, chain)).cea); + const network = orchestrator.getNetwork() === PUSH_NETWORK.MAINNET ? 'mainnet' diff --git a/packages/core/src/lib/read-state/__tests__/read-params.spec.ts b/packages/core/src/lib/read-state/__tests__/read-params.spec.ts index 6342edc1..05659ec3 100644 --- a/packages/core/src/lib/read-state/__tests__/read-params.spec.ts +++ b/packages/core/src/lib/read-state/__tests__/read-params.spec.ts @@ -37,6 +37,12 @@ describe('read(subject, options) grammar → ReadQuery', () => { it('EVM: storageSlot', () => { expect(toReadQuery(TOKEN, { chain: CHAIN.ETHEREUM_SEPOLIA, storageSlot: 2n })).toEqual({ type: 'storageSlot', target: TOKEN, slot: 2n }); }); + it('EVM: raw callData retains the exact selector and argument bytes', () => { + expect(toReadQuery(TOKEN, { chain: CHAIN.ETHEREUM_SEPOLIA, callData: '0x18160ddd' })).toEqual({ type: 'contractCall', target: TOKEN, callData: '0x18160ddd' }); + expect(() => toReadQuery(TOKEN, { chain: CHAIN.ETHEREUM_SEPOLIA, callData: '0x123' })).toThrow(InvalidReadQueryError); + expect(() => toReadQuery(TOKEN, { chain: CHAIN.ETHEREUM_SEPOLIA, callData: '0x18160ddd', abi: ABI, functionName: 'totalSupply' })).toThrow(InvalidReadQueryError); + expect(() => toReadQuery(SOL_OWNER, { chain: CHAIN.SOLANA_DEVNET, callData: '0x18160ddd' })).toThrow(InvalidReadQueryError); + }); it('SVM: native → lamports of subject; token → the ATA derived offline', () => { expect(toReadQuery(SOL_OWNER, { chain: CHAIN.SOLANA_DEVNET })).toEqual({ type: 'lamportBalance', account: SOL_OWNER }); const q = toReadQuery(SOL_OWNER, { chain: CHAIN.SOLANA_DEVNET, token: SOL_MINT }, TOKEN_PROGRAM_ID); diff --git a/packages/core/src/lib/read-state/__tests__/read-types.spec.ts b/packages/core/src/lib/read-state/__tests__/read-types.spec.ts index 4fcbfa1f..17f2d928 100644 --- a/packages/core/src/lib/read-state/__tests__/read-types.spec.ts +++ b/packages/core/src/lib/read-state/__tests__/read-types.spec.ts @@ -26,6 +26,12 @@ declare const counterIdl: CounterIdl; // Compiled by ts-jest; never executed or connected to a network. async function checkTypes(client: PushChain) { + const raw: UniversalReadResponse<`0x${string}`> = await client.universal.read(address, { chain: CHAIN.ETHEREUM_SEPOLIA, callData: '0x18160ddd' }); + // @ts-expect-error raw calls and typed calls are mutually exclusive + const mixedRaw: ReadOptions = { chain: CHAIN.ETHEREUM_SEPOLIA, callData: '0x18160ddd', abi, functionName: 'quote' }; + // @ts-expect-error raw EVM calldata cannot be used on Solana + const svmRaw: ReadOptions = { chain: CHAIN.SOLANA_DEVNET, callData: '0x18160ddd' }; + void [raw, mixedRaw, svmRaw]; // @ts-expect-error token program is inferred from the mint const removed: ReadOptions = { chain: CHAIN.SOLANA_DEVNET, token: address, tokenProgram: 'token-2022' }; const accountIdl = { address, metadata: { name: 'counter', version: '1', spec: '0.1.0' }, instructions: [], accounts: [{ name: 'counter', discriminator: [1,2,3,4,5,6,7,8] }], types: [{ name: 'counter', type: { kind: 'struct', fields: [{ name: 'count', type: 'u64' }] } }] } satisfies import('@coral-xyz/anchor').Idl; diff --git a/packages/core/src/lib/read-state/read-params.ts b/packages/core/src/lib/read-state/read-params.ts index 65b18ab3..e1e6fca4 100644 --- a/packages/core/src/lib/read-state/read-params.ts +++ b/packages/core/src/lib/read-state/read-params.ts @@ -56,6 +56,8 @@ interface ReadOptionsInput { idl?: Idl; /** Typed contract call — encodes the call and decodes the result. */ abi?: Abi; + /** Encoded EVM view call. The result is returned as raw consensus bytes. */ + callData?: Hex; /** * With `abi`: the function to call (required). With `idl`: the account layout * (optional — inferred from the discriminator; snake_case or camelCase). @@ -94,7 +96,7 @@ interface ReadOptionsInput { }; } -type NoQuery = { token?: never; tokenProgram?: never; idl?: never; accountName?: never; abi?: never; functionName?: never; args?: never; storageSlot?: never; web2?: never }; +type NoQuery = { token?: never; tokenProgram?: never; idl?: never; accountName?: never; abi?: never; callData?: never; functionName?: never; args?: never; storageSlot?: never; web2?: never }; type Query = Omit & T; type EvmChain = Extract; type SvmChain = Extract; @@ -105,6 +107,7 @@ export type ReadQueryOptions = | ({ chain: SvmChain } & Query<'token', { token: string }>) | ({ chain: SvmChain } & Query<'idl' | 'functionName' | 'args', { idl: Idl; functionName?: string; args?: readonly unknown[] }>) | ({ chain: EvmChain } & Query<'abi' | 'functionName' | 'args', { abi: Abi; functionName: string; args?: readonly unknown[] }>) + | ({ chain: EvmChain } & Query<'callData', { callData: Hex }>) | ({ chain: EvmChain } & Query<'storageSlot', { storageSlot: Hex | bigint }>) | ({ chain: Web2ReadChain } & Query<'web2', { web2: ReadWeb2Options }>); @@ -154,7 +157,7 @@ export type ReadValue = O extends { abi: infer A extends Abi; functionName: i ? number extends A['length'] ? unknown : ReadCallValue> : O extends { web2: { extract: infer E extends readonly Web2Extract[] } } ? { readonly [K in keyof E]: Web2Value } - : O extends { storageSlot: unknown } ? Hex + : O extends { storageSlot: unknown } | { callData: unknown } ? Hex : O extends { idl: infer I extends Idl } ? IdlReadValue : bigint; @@ -180,7 +183,7 @@ export const ERC20_BALANCE_OF_ABI = [ }, ] as const satisfies Abi; -const QUERY_KEYS = ['token', 'abi', 'idl', 'storageSlot', 'web2'] as const; +const QUERY_KEYS = ['token', 'abi', 'callData', 'idl', 'storageSlot', 'web2'] as const; function queryKind(o: ReadOptionsInput): (typeof QUERY_KEYS)[number] | 'native' { if ('tokenProgram' in o) throw new InvalidReadQueryError('tokenProgram is detected from the mint; remove options.tokenProgram'); @@ -225,6 +228,10 @@ export function toReadQuery(subject: string, o: ReadOptionsInput, resolvedTokenP case 'abi': if (!o.functionName) throw new InvalidReadQueryError('abi needs functionName'); return { type: 'contractCall', target: subject, abi: o.abi as Abi, functionName: o.functionName, args: o.args }; + case 'callData': + if (!/^0x(?:[\da-f]{2}){4,}$/i.test(o.callData ?? '')) + throw new InvalidReadQueryError('callData must contain a function selector and complete bytes'); + return { type: 'contractCall', target: subject, callData: o.callData as Hex }; case 'storageSlot': return { type: 'storageSlot', target: subject, slot: o.storageSlot as Hex | bigint }; default: diff --git a/plan/SDK-CHANGELOG.md b/plan/SDK-CHANGELOG.md index 9dc751d7..b2120fcc 100644 --- a/plan/SDK-CHANGELOG.md +++ b/plan/SDK-CHANGELOG.md @@ -4,6 +4,14 @@ Running history for work continued on `feat/agw-sdk-v4`, covering AGW, marketpla For each meaningful checkpoint, add a dated entry with the change, decisions, validation, remaining work and relevant commit/evidence links. Keep earlier entries as history and mark superseded decisions explicitly. Distinguish implemented code, planning, local/fork checks, funded execution, Git delivery and package publication. Git history for this file records the exact commit introducing each checkpoint. +## 2026-10-20 — deposits, paid preview and external EVM owners + +**Implemented:** `market.deposit` recovers the opened card version and principal, combines shared-token requirements, tops up principal/fee/PC separately and retains receipts/pending hashes for recovery. Explicit registered-origin funding is available. Deployed v2 grants pinned approvals to the agent; deposit performs no retired owner-approval step. Paid `previewJobSpec` uses raw universal reads, total request-fee caps, ABI layout decoding, configured CEA resolution and unknown-aware logic/baselines. Opening checks the actual EIP-712 domain and simulates the complete signed request before broadcast; deployed external EVM UEAs are supported. + +**Validation:** 2,228 units pass (12 existing skips), eight real-stack fork E2Es, and three live cases: native open/cancel, paid validator-consensus preview, external-owner UEA open/cancel. Nonzero principal/fee deposits, escrow and payout remain fork-only; origin-bridge deposits are unit-tested. Live card 3 is inactive and jobs 2/3 are Rejected with permissions revoked. Build/types, production lint, package/API checks and six guide blocks pass. [Evidence and limits](marketplace/research/sdk-completion-2026-10-20/README.md). + +**Coverage:** 28 of the 29 named APIs on SDK pages 6/7 have implementations against deployed v2. This supersedes the first checkpoint's deposit, paid-preview and external-EVM placeholders. The remaining method placeholder is `job.verify`, awaiting a compatible evaluator/hook and shared wire. Three CEA destination rollouts, arbitrary ERC-1271 acceptance, full live principal/protocol execution and package publication remain separate work. Continue on `feat/agw-sdk-v4`; no marketplace/kernel/evaluator deployment or npm publication was performed. + ## 2026-10-20 — first marketplace SDK implementation **Implemented:** client.market discovery/provider management, exact preview and native plain-EOA open; client.job create/pricing/funding/submit/status/list/watch/cancel/refund; deployed v2 JobSpec/template/card-rule codecs, marker resolution and authoring helpers; additive universal.read.prepare; constants/types/errors and a [consumer guide](../packages/core/MARKETPLACE.md). Binary kernel description bytes survive encoding and reads. Default E2E selection stays unchanged. diff --git a/plan/marketplace/README.md b/plan/marketplace/README.md index d872fe45..e5cc84e1 100644 --- a/plan/marketplace/README.md +++ b/plan/marketplace/README.md @@ -1,6 +1,6 @@ # Agentic marketplace SDK planning -Updated October 20, 2026. **Actual SDK implementation has started:** see [current implementation and acceptance](implementation-status.md). The initial contract-only research below is preserved as history; its planning-only statements predate the SDK and live smoke checkpoint. No package was published. +Updated October 20, 2026. **28 of the 29 named SDK APIs now have implementations against deployed v2:** see [current coverage and acceptance](implementation-status.md). Deposits, paid previews and external EVM UEA opening are implemented; `job.verify` awaits compatible contracts. The initial contract-only research below is preserved as history. No package was published. **Build against deployed UniversalMarketplace v2, pinned at `sdk-iteration-v1@443b4e2dd9ca5dd9ffc8efebdfcecd619dd66c47`.** The six supplied Notion pages were exported again through signed-in Chrome, and their visible discussion panels were reviewed. The older marketplace pages in `plan/agw/notion` remain historical. @@ -25,7 +25,7 @@ Updated October 20, 2026. **Actual SDK implementation has started:** see [curren - Payment is currently **pUSDC only**. The evaluator is an EOA; automated baseline, criteria replacement, verification and rating are not live capabilities. - Page 8 retires `client.evaluation`. Plan `client.market`, `client.job`, `PushChain.utils.market`, `PushChain.utils.job`, and vocabulary under `PushChain.CONSTANTS.AGENTIC`. - The evaluator source linked by Nilesh's October 16 comment is **wire-incompatible** with deployed marketplace v2, including different enum ordinals. Align contracts before automatic evaluation; never combine these encoders implicitly. -- The deployed card-rule struct has **no `approvals[]`**. Page 6 still describes the earlier owner-approval design. This needs an explicit SDK contract with product before those deposit fields are advertised. +- The deployed card-rule struct has **no `approvals[]`**. Page 6 still describes the earlier owner-approval design. The SDK follows deployed v2: deposit moves principal/fee/PC, while the agent has pinned approval calls in its granted permissions. - Kernel cancellation releases the marketplace slot but leaves AGW permissions enabled. Independent fork checks examine that behavior and an existing owner-batch cleanup path. -Validation totals and evidence limitations are maintained in [validation.md](research/2026-10-20/validation.md), rather than copied into dated source snapshots. +Current SDK validation is linked from [implementation status](implementation-status.md); the earlier contract-only results remain in [validation.md](research/2026-10-20/validation.md). Dated source snapshots are unchanged. diff --git a/plan/marketplace/implementation-status.md b/plan/marketplace/implementation-status.md index ea7bad5b..ef276ec1 100644 --- a/plan/marketplace/implementation-status.md +++ b/plan/marketplace/implementation-status.md @@ -1,12 +1,25 @@ # Marketplace SDK implementation status -October 20, 2026 — first implementation checkpoint on `feat/agw-sdk-v4`. This supersedes the planning-only statements in the original research package. No package was published. +October 20, 2026 — deposit, preview and external-owner checkpoint on `feat/agw-sdk-v4`. This supersedes the first checkpoint's deposit/paid-preview/external-EVM placeholders. No package was published. + +## Coverage against SDK pages 6 and 7 + +| Documented API group | Implemented | Pending | +| --- | --- | --- | +| Marketplace user APIs | 7 / 7 | Broader route acceptance; three CEA rollout mismatches below | +| Provider/card management | 4 / 4 | No additional method placeholder | +| JobSpec/card-rule helpers | 9 / 9 | Additional paid-read/source/output acceptance remains useful | +| Kernel job APIs | 8 / 9 | `job.verify`: compatible evaluator/hook and canonical wire | +| **Named API entrypoints** | **28 / 29** | **1 contract-dependent placeholder** | + +This is API coverage, not a release-readiness percentage or a claim that every draft option is implemented. It follows deployed v2 where the draft differs (pinned agent approvals, immutable criteria, pUSDC). `job.cancel`, pure read preparation and constants are additional delivered surfaces. Evaluation facts in `status` remain explicitly unavailable. Full live principal/escrow/protocol execution and arbitrary contract-wallet acceptance are separate validation work. ## Implemented -- `client.market`: card discovery/reads; provider register/update/setActive/card; independently checked CEA and JobSpec preview; native plain-EOA OwnerIntent signing/open; job mappings and active-wallet reads. +- `client.market`: card discovery/reads; provider register/update/setActive/card; independently checked CEA and JobSpec preview; simulation-backed OwnerIntent signing/open for native EOAs and deployed external EVM UEAs; job mappings and active-wallet reads. +- `client.market.deposit`: original opening event/card-version recovery, principal/fee/PC balance targets, combined shared-token requirements, explicit registered-origin funding, confirmed step receipts and incomplete-deposit recovery. Broadcast errors retain pending hashes and stop automatic retry. No retired owner-approval array or escrow acceptance is inferred. - `client.job`: plain create; provider pricing; explicit-budget acceptance, balances/allowances and atomic AGW funding; submit; status/list/watch; client cancel with recorded marketplace permission revocation; expiry/grace refunds, including while paused. -- `PushChain.utils.job`: pure EVM read authoring, complete/template builders, canonical v2 codecs and descriptions. `client.universal.read.prepare` exposes the same pure authoring adapter; existing async prepareRead is unchanged. +- `PushChain.utils.job`: pure EVM read authoring, complete/template builders, canonical v2 codecs and descriptions; paid `previewJobSpec` through universal reads, fee cap, output-layout decoding and three-state logic. Missing baselines/reads remain unknown. `client.universal.read.prepare` exposes the same pure authoring adapter; async prepareRead/read now also accept explicit raw EVM calldata. - `PushChain.utils.market`: deployed four-field card rules, principal/wallet markers and pinned approvals. Destination-token resolution always uses the explicit card chain, including same-address native-token objects. Decoded unknown PRC20s remain explicit references. Unchanged legacy wire metadata is preserved; archive raw bytes for persistence. - `AGENTIC.PRINCIPAL` and `AGENTIC.JOB` vocabulary/address table; public types/errors; source and compiled consumer guide checks. The API checker now canonicalizes equivalent string-literal quote syntax in emitted property names. @@ -18,11 +31,10 @@ Registry summaries do not decode an unverified provider's template. A malformed | Surface | Current behavior / next requirement | | --- | --- | -| market.deposit | Explicit CAPABILITY_UNAVAILABLE. Historical-card snapshot/resumption and deposit policy remain a later SDK increment. Fund the AGW explicitly. | +| Deposit acceptance limits | Open/unexpired and unused enabled permission; available historical state required. Same-block version ambiguity fails closed. PC target is not a whole-job quote. Registered origin funding is unit-tested; live principal/inbound-bridge acceptance is still pending. | | Automatic evaluator / job.verify | Explicit capability error. Current evaluator is manual; the linked evaluator has a different ABI/wire. No baseline, frozen-spec or verdict data is invented. | -| Paid previewJobSpec | Explicit capability error pending the fee/callback/raw-read adapter. Pure authoring/description works. | | Replacement criteria / non-NONE cards | Refused before writes. Expected-spec-hash acceptance must be delivered with compatible contracts before mutable negotiation. | -| External and contract/delegated owners | openJob is gated before signing. The actual test master has EIP-7702 code and follows the contract-signature branch; a fresh plain native owner passes live. ERC-1271 / UEA-specific signing needs its own acceptance. | +| Contract/delegated owners | Full signed-request simulation uses the actual verifier. External EVM UEA transport passes live; arbitrary ERC-1271 adapters need their own acceptance. Delegates without a compatible verifier fail simulation after signing, before broadcast. Undeployed external UEAs and missing typed signing fail before prompting. | | Relayer, recurring jobs, ratings, non-EVM cards/evaluation | No successful placeholder or invented service. Remain outside this checkpoint. | `job.cancel` revokes only the permission recorded for that marketplace job, using the current owner's existing AGW authority. Provider/evaluator terminal actions do not acquire owner cleanup authority. Plain jobs have no marketplace permission to infer. Funded job completion/payout is tested with manual evaluator action only on an isolated fork. @@ -42,9 +54,9 @@ Both old/new factories in the first three chains answer and name the same gatewa ## Acceptance -- **2,205 unit tests pass**, 12 existing skips; 24 new unit cases. -- **6 public-SDK fork E2Es pass**: real v2/v6 registration, open/signature/wire, decoded update, paid pUSDC allowance/escrow/payout, re-quote/insufficiency/version-drift checks, events/deliverable, plain creation, refund while paused and cancel/revoke. No public token transfer was used for that escrow test. -- **2 live read-only cases pass** and **1 funded live smoke passes**. The funded smoke creates only fresh provider/card/owner/wallet state, opens/cancels/revokes, and deactivates its card. It moves PC for gas/test-wallet setup, not principal/escrow tokens. -- Build, library/spec/local typechecks, compiled imports/declarations/package checks and source-versus-built API comparison pass; the new production modules lint without warnings. The consumer guide's four TS blocks typecheck. +- **2,228 unit tests pass**, 12 existing skips; 23 cases added after the first checkpoint. +- **8 real-stack fork E2Es pass**: existing lifecycle plus historical deposits/reconnection and a real EVM UEA signature. Actual principal/pUSDC and escrow/payout use fork-only borrowed assets. The UEA signature case uses a native submitting transport on Anvil; no Cosmos transport is mocked as successful. +- **3 funded live cases pass**: native register/open/cancel/revoke, paid validator-consensus preview, and actual external EVM UEA open/cancel. Card 3 is inactive; jobs 2/3 are Rejected and both permissions are revoked. PC funds gas/wallet setup/read callback; principal and escrow tokens are not moved live. The first checkpoint's two read-only cases remain prior evidence. +- Build, library/spec/local typechecks, compiled imports/declarations/package checks and source-versus-built API comparison pass; the new production modules lint without warnings. The consumer guide's six TS blocks typecheck. -[Validation details and limits](research/sdk-implementation-2026-10-20/README.md). E2E groups `marketplace` and `marketplace-live` are opt-in; default all selection is unchanged. Future checkpoints should append to the [running changelog](../SDK-CHANGELOG.md). +[Current validation and limits](research/sdk-completion-2026-10-20/README.md), [first checkpoint](research/sdk-implementation-2026-10-20/README.md). E2E groups `marketplace` and `marketplace-live` are opt-in; default all selection is unchanged. Future checkpoints should append to the [running changelog](../SDK-CHANGELOG.md). diff --git a/plan/marketplace/questions.md b/plan/marketplace/questions.md index 4c0b350b..05ab96fd 100644 --- a/plan/marketplace/questions.md +++ b/plan/marketplace/questions.md @@ -1,6 +1,6 @@ # Questions to share — drafts, not posted -**Implementation update:** the user authorized implementation with explicit placeholders. Approval handling now follows deployed v2; client cancel/revoke, explicit expected-budget acceptance and additive pure read authoring are implemented/tested. Historical proposals below remain useful context. The immediate rollout question is CEA configuration: SDK and marketplace factories differ on Sepolia/Base Sepolia/Arbitrum Sepolia, while BSC matches and passes live. [Addresses and read-only evidence](implementation-status.md#destination-rollout-mismatch). Which route/deployment manifest is canonical, and which configuration should be aligned? Global routing constants were not changed to bypass the guard. External/delegated signatures and evaluator integration remain explicitly gated. +**Implementation update:** the user authorized implementation with explicit placeholders. Deployed-v2 approvals, client cancel/revoke, expected-budget acceptance, historical deposits and paid preview are implemented. External EVM UEA open/cancel passes live; complete signed-request simulation checks the real verifier before broadcast. Arbitrary ERC-1271 adapters still need acceptance, and incompatible delegates fail simulation. The remaining placeholder is evaluator integration. Historical proposals below remain useful context. The immediate rollout question is CEA configuration: SDK and marketplace factories differ on Sepolia/Base Sepolia/Arbitrum Sepolia, while BSC matches and passes live. [Addresses and read-only evidence](implementation-status.md#destination-rollout-mismatch). Which route/deployment manifest is canonical, and which configuration should be aligned? Global routing constants were not changed to bypass the guard. Prepared October 20 after fresh Notion discussions, pinned source review, unfunded tests and Donut read-only checks. Lead with the concrete mismatch and proposal; do not resend historical questions already answered below. diff --git a/plan/marketplace/research/sdk-completion-2026-10-20/README.md b/plan/marketplace/research/sdk-completion-2026-10-20/README.md new file mode 100644 index 00000000..2af0701d --- /dev/null +++ b/plan/marketplace/research/sdk-completion-2026-10-20/README.md @@ -0,0 +1,48 @@ +# Deposits, paid preview and external EVM owners — October 20 + +Follow-up to the first SDK checkpoint `fbd0e032`. Targets remain UniversalMarketplace v2 `443b4e2`, AGW v6 `ffd567d` and the pUSDC/manual-evaluator Donut deployment. [API coverage and remaining work](../../implementation-status.md), [consumer guide](../../../../packages/core/MARKETPLACE.md). + +## Acceptance + +| Check | Result / evidence | +| --- | --- | +| Full units | 2,228 passed, 12 existing skips, no failures; [losslessly compressed Jest output](unit-results.json.gz) | +| Real-stack fork | Eight passed on an isolated Anvil fork at block 24447347; [Jest output](fork-results.json) | +| Live | Three passed, none failed/skipped, runner exited 0; [raw report](live-results.json), [transactions and read request](live-evidence.json) | +| Cleanup | Card 3 inactive; jobs 2/3 Rejected (kernel ordinal 4), both grants disabled; [read-only post-state](post-live-state.json) | +| Package | Build, library/spec/fork types, changed-production lint, CJS/ESM imports, compiled guide declarations, npm dry-run contents and six source-guide TS blocks pass | +| API | Source and compiled surfaces match; [report](api-comparison.json). Its comparison baseline predates this checkpoint and includes earlier SDK changes. | + +The 23 added unit cases cover historical/shared-token deposits, shortages before writes, pending receipt/broadcast recovery, origin-route matching, already-used permissions, fee caps, template CEA resolution, immutable preview inputs, dynamic ABI paths, unknown/baseline logic, typed-signing gates and domain mismatch before prompting. Fork tests add actual principal/fee/PC deposits after a card update, fresh-client history recovery, a wrong-signature simulation failure and a real UEA owner signature to the earlier lifecycle coverage. + +The fork's UEA signature case uses a native submitting transport because Anvil does not implement Cosmos MsgExecutePayload. It verifies the actual UEA/factory/wallet signature path. The separate live case opens and cancels through the real external EVM owner's SDK UEA transport. No successful contract or SDK outcome is fabricated. + +The live paid preview submits a raw BSC Testnet ERC20 balance read through the registry and reaches validator consensus (`SUCCESS`, decoded zero). Its quoted/paid callback-plus-protocol deposit is 0.0016875 PC, below the explicit 0.01 PC request cap; native transaction gas is separate. The criterion is balance >= 0, a smoke check rather than evidence of a completed strategy. Requests and hashes are retained without keys or unbroadcast signatures. + +The existing CI reporter again sampled `success: false` in onRunComplete despite three passed tests and runner exit 0. Its report is preserved unchanged; [validation summary](validation-summary.json) records the counts and actual exit separately. + +## Limits + +- Principal, pUSDC escrow and payout transfers are fork-only, using existing assets borrowed under local impersonation. Live funding uses bounded PC for fresh wallets, gas and a read callback. No destination protocol transaction or automatic evaluator verdict is claimed. +- Explicit origin-bridge deposits are unit-tested, including wrong-chain rejection and recovery; funded inbound bridging through `market.deposit` still needs its own live acceptance. +- Deposits are separate transactions and target current wallet balances. They require Open/unexpired jobs and unused enabled permissions. Available historical state is required; same-block version ambiguity fails closed. PC defaults to one card gas cap rather than a whole-job estimate. Coordinate other deposit clients and keep the agent idle during funding. +- Arbitrary ERC-1271 adapters and EIP-7702 delegates require their own acceptance. Full signed-request simulation prevents broadcast when the deployed owner verifier refuses a signature. An undeployed external UEA is refused before signing. +- Three CEA rollout mismatches and the incompatible/missing automatic evaluator remain documented dependencies. No global routing address was changed to bypass a guard. +- No marketplace, kernel, hook or evaluator was deployed or upgraded; only fresh test accounts/wallets were created through existing factories. No package was published. + +## Reproduction + +```sh +node node_modules/jest/bin/jest.js --config packages/core/jest.config.ts --runInBand --silent +node node_modules/jest/bin/jest.js --config packages/core/jest.marketplace-local.config.ts --runInBand +node node_modules/ts-node/dist/bin.js --compiler-options '{"module":"commonjs"}' packages/core/__e2e__/ci/run.ts --group marketplace-live --verify +node node_modules/ts-node/dist/bin.js --compiler-options '{"module":"commonjs"}' packages/core/__e2e__/ci/run.ts --group marketplace-live +NX_DAEMON=false node node_modules/nx/bin/nx.js run core:build --skip-nx-cache +node node_modules/typescript/bin/tsc -p packages/core/tsconfig.spec.json --noEmit +node node_modules/typescript/bin/tsc -p packages/core/tsconfig.marketplace-local.json --noEmit +node packages/core/scripts/check-agw-docs.js packages/core/MARKETPLACE.md +node packages/core/scripts/check-agw-package.js +node packages/core/scripts/check-agw-api.js --output /tmp/marketplace-api.json +``` + +Marketplace live remains opt-in and needs the existing test fixture configuration. Default `all` selection is unchanged. Checksums of retained raw results and checked source files are recorded in [validation summary](validation-summary.json) and [checked files](checked-files.json). diff --git a/plan/marketplace/research/sdk-completion-2026-10-20/api-comparison.json b/plan/marketplace/research/sdk-completion-2026-10-20/api-comparison.json new file mode 100644 index 00000000..9374c0d0 --- /dev/null +++ b/plan/marketplace/research/sdk-completion-2026-10-20/api-comparison.json @@ -0,0 +1,13371 @@ +{ + "baseline": "b1597b91a25dbf7f691f589b4e1e154add604315", + "head": "fbd0e032940e523b18bb0d6f8fd80b23beae1c67", + "compiledMatchesSource": true, + "initializeSignatureChanged": false, + "addedExports": [ + "AgentCard", + "AgentCardInput", + "AgentCardRules", + "AgentCardSummary", + "AgenticPresets", + "AllowedMutability", + "ArgumentPath", + "BuildJobSpecOptions", + "BuildJobSpecTemplateOptions", + "CreateJobOptions", + "DecodedSolanaRule", + "Evaluation", + "FundJobOptions", + "Job", + "JobCheck", + "JobCheckTemplate", + "JobError", + "JobEvent", + "JobNamespace", + "JobPlan", + "JobRead", + "JobReadInput", + "JobSpec", + "JobSpecError", + "JobSpecPreview", + "JobSpecTemplate", + "JobStatus", + "LogicKind", + "LogicTree", + "MarketAssetToken", + "MarketDepositOptions", + "MarketDepositResult", + "MarketDepositStep", + "MarketError", + "MarketNamespace", + "MarketPin", + "MarketPreviewOptions", + "MarketWriteOptions", + "Operation", + "OwnerIntent", + "Pin", + "PrepareJobReadOptions", + "PreparedJobRead", + "Preset", + "PresetAsset", + "PresetCallIssue", + "PresetCategory", + "PresetChainReadiness", + "PresetConfigurationIssue", + "PresetOptions", + "PresetResult", + "PresetRuleTemplate", + "PreviewJobSpecOptions", + "PrincipalMarker", + "ReadyPresetOptions", + "RuleInput", + "Spent", + "WalletMarker" + ], + "removedExports": [ + "AgenticNetworkConstants", + "NativeRule", + "UniversalRule" + ], + "changedAgwTypes": [ + "AgenticWallet", + "AgenticError", + "AgenticRevertError", + "AGENTIC_ERROR_CODE", + "Rule", + "RuleInput", + "Pin", + "Spent", + "NativeRule", + "AssetCap", + "AllowedCall", + "UniversalRule", + "RulesRecord", + "CreateOptions", + "AgenticTxMetadata" + ], + "publicTypeChanges": [ + "MarketError", + "JobError", + "JobSpecError", + "AgentCardRules", + "MarketAssetToken", + "MarketPin", + "AgentCard", + "AgentCardInput", + "AgentCardSummary", + "MarketNamespace", + "MarketPreviewOptions", + "MarketWriteOptions", + "MarketDepositOptions", + "MarketDepositResult", + "MarketDepositStep", + "JobPlan", + "OwnerIntent", + "JobNamespace", + "Job", + "JobStatus", + "JobEvent", + "CreateJobOptions", + "FundJobOptions", + "JobSpec", + "JobSpecTemplate", + "JobRead", + "PreparedJobRead", + "JobReadInput", + "JobCheck", + "JobCheckTemplate", + "LogicTree", + "Evaluation", + "Operation", + "LogicKind", + "AllowedMutability", + "PrincipalMarker", + "PrepareJobReadOptions", + "BuildJobSpecOptions", + "BuildJobSpecTemplateOptions", + "JobSpecPreview", + "PreviewJobSpecOptions", + "ReadOptions", + "ReadPrepareOptions", + "ReadQueryOptions", + "ReadValue", + "AGENTIC_ERROR_CODE", + "AgenticError", + "AgenticRevertError", + "AgenticErrorCode", + "AgenticTxMetadata", + "AgenticWallet", + "AllowedCall", + "AssetCap", + "CreateOptions", + "DecodedSolanaRule", + "Rule", + "RuleInput", + "Pin", + "Spent", + "WalletMarker", + "ArgumentPath", + "RulesRecord", + "PushChain", + "Preset", + "PresetCategory", + "PresetAsset", + "PresetOptions", + "ReadyPresetOptions", + "PresetRuleTemplate", + "PresetResult", + "PresetChainReadiness", + "PresetConfigurationIssue", + "PresetCallIssue", + "AgenticPresets" + ], + "transactionMethodChanges": [ + "read" + ], + "instanceMethodChanges": [ + "job", + "market", + "universal" + ], + "agwConstantsChanged": true, + "before": { + "exports": [ + "AGENTIC_ERROR_CODE", + "AccountRole", + "AccountStatus", + "AccountType", + "AgenticAddress", + "AgenticDoor", + "AgenticError", + "AgenticErrorCode", + "AgenticHex", + "AgenticNamespace", + "AgenticNetworkConstants", + "AgenticProgressHook", + "AgenticRevertError", + "AgenticTxMetadata", + "AgenticWallet", + "AllowedCall", + "AssetCap", + "BatchReadResponse", + "BuildReadSpecParams", + "CHAIN", + "CONTRACT_REQUEST_STATUS", + "CascadeCompletionResult", + "CascadeHopInfo", + "CascadeProgressEvent", + "CascadeTrackOptions", + "CascadedTxResponse", + "ChainSource", + "ChainTarget", + "Checkpoint", + "CheckpointKind", + "ConversionQuote", + "CreateOptions", + "CreateResult", + "DEFAULT_MAX_PC_FOR_GAS_BUFFER_BPS", + "DecodedErrorPayload", + "DecodedReadResult", + "DerivedExecutorAccount", + "EncodedReadQuery", + "EvmReadQuery", + "ForeignChainNamespace", + "FulfilOutcome", + "FundsToken", + "InsufficientPC20BalanceError", + "InvalidPC20AddressError", + "InvalidPC20MetadataError", + "InvalidReadQueryError", + "InvalidReadSpecError", + "MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT", + "MaxPCForGasCapFromNativeValueInput", + "MaxPCForGasCapInput", + "MaxPCForGasCapQuote", + "MultiChainTxResponse", + "NativeRule", + "OutboundTxDetails", + "PC20AddressResult", + "PC20AmbiguousAddressError", + "PC20Error", + "PC20ExpectedButPRC20Error", + "PC20ExportRevertedError", + "PC20FactoryMismatchError", + "PC20RegistryEntry", + "PC20RegistryMismatchError", + "PC20TokenChainMismatchError", + "PC20TokenReference", + "PC20UnknownChainNamespaceError", + "PC20UnsafeEmptyPayloadError", + "PC20WrapperNotRegisteredError", + "PC20WrapperPredictionUnavailableError", + "ParsedReadRequest", + "PreparedRead", + "PreparedUniversalTx", + "PushChain", + "PushChainBatchExecutionError", + "PushChainExecutionError", + "PushChainInitializeOptions", + "READ_ERROR_CODE", + "READ_OUTCOME", + "READ_STATUS", + "ReadCallback", + "ReadCallbackOptions", + "ReadChain", + "ReadDecodeError", + "ReadDestination", + "ReadExecuteOptions", + "ReadFees", + "ReadHeightUnavailableError", + "ReadLifecycleOptions", + "ReadNotFoundError", + "ReadOptions", + "ReadPreflight", + "ReadPrepareOptions", + "ReadQuery", + "ReadQueryOptions", + "ReadRef", + "ReadRegistryUnavailableError", + "ReadResponseTuple", + "ReadResultShape", + "ReadSpec", + "ReadSpecTuple", + "ReadSpecViolation", + "ReadStateError", + "ReadTimeoutError", + "ReadTrackOptions", + "ReadValue", + "ReadWeb2Options", + "ReceiptLike", + "RescueFundsParams", + "ResolvedAccount", + "ResolvedControllerAccounts", + "ResolvedDestination", + "Rule", + "RulesRecord", + "Selector", + "SignAuthorizationParams", + "SignedAuthorization", + "SimulateReadResult", + "SvmExecutePayloadFields", + "SvmGatewayAccountMeta", + "SvmReadQuery", + "TERMINAL_READ_STATUSES", + "TransactionRoute", + "TransactionRouteType", + "UEAStatus", + "UNIVERSAL_CALLBACK_EVM", + "UNIVERSAL_READ_REGISTRY_EVM", + "UNIVERSAL_READ_STATUS", + "UniversalAccount", + "UniversalExecuteParams", + "UniversalOutboundTxRequest", + "UniversalReadResponse", + "UniversalRule", + "UniversalSigner", + "UniversalSignerSkeleton", + "UniversalTo", + "UnsupportedPC20DestinationError", + "UnsupportedReadDestinationError", + "ValidateReadCall", + "WaitForOutboundOptions", + "WalletInfo", + "WalletSummary", + "Web2Extract", + "Web2ReadQuery", + "Web2ValueType", + "buildErc20WithdrawalMulticall", + "buildMigrationPayload", + "buildReadSpecFromPreflight", + "chainSupportsCEA", + "chainSupportsOutbound", + "decodeReadResult", + "detectRoute", + "encodeReadQuery", + "encodeSvmExecutePayload", + "getAllCEAAddresses", + "getCEAAddress", + "getCEAFactoryAddress", + "getPushAccountForCEA", + "inferResultShape", + "isCEA", + "isChainTarget", + "isPC20Reference", + "isSvmChain", + "isValidSolanaHexAddress", + "parseFulfilOutcome", + "parseReadRequestsFromReceipt", + "parseUEAVersion", + "quoteMaxPCForGasCap", + "quoteMaxPCForGasCapFromNativeValue", + "resolveDestination", + "sizeCallbackBudget", + "toCallData", + "toReadQuery", + "toRequestIdHex", + "validateReadSpec" + ], + "agw": { + "AgenticNamespace": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace", + "members": { + "create": { + "optional": false, + "readonly": false, + "type": "(label: string, options: import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions) => Promise" + }, + "derive": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n index?: number;\n}) => Promise<{\n address: `0x${string}`;\n deployed: boolean;\n index: number;\n}>" + }, + "list": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n wallets: import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary[];\n}>" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "(address: `0x${string}`) => import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet" + } + } + }, + "AgenticWallet": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "checkpoints": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n sinceBlock?: bigint;\n}) => Promise<{\n checkpoints: import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint[];\n}>" + }, + "info": { + "optional": false, + "readonly": false, + "type": "() => Promise" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n owner: `0x${string}`;\n}>" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "{\n add(rules: import(\"sdk/src/lib/agentic/agentic.types\").Rule[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise<{\n rulesIds: `0x${string}`[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n get(rulesId: `0x${string}`): Promise;\n list(): Promise<{\n rules: import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord[];\n }>;\n revoke(rulesIds: `0x${string}`[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n revoke(params: {\n all: true;\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n update(params: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n rules: {\n rule: import(\"sdk/src/lib/agentic/agentic.types\").Rule;\n rulesId: `0x${string}`;\n }[];\n }): Promise<{\n rules: {\n replaced: `0x${string}`;\n rulesId: `0x${string}`;\n }[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n}" + }, + "setLabel": { + "optional": false, + "readonly": false, + "type": "(label: string, opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n}) => Promise" + } + } + }, + "AgenticError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"CREATE_PARTIAL\" | \"DUPLICATE_RULE\" | \"FROM_NOT_ALLOWED\" | \"GATEWAY_ALLOWANCE_INSUFFICIENT\" | \"GENERATION_UNSUPPORTED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"REVOKE_NEEDS_TARGET\" | \"RULE_LIMIT_EXCEEDED\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"" + }, + "details": { + "optional": true, + "readonly": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "AgenticRevertError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticRevertError", + "members": { + "agenticCode": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + } + } + }, + "AGENTIC_ERROR_CODE": { + "type": "{\n readonly AGENT_GAS_INSUFFICIENT: \"AGENT_GAS_INSUFFICIENT\";\n readonly AGENT_IS_OWNER: \"AGENT_IS_OWNER\";\n readonly ASSET_CHAIN_MISMATCH: \"ASSET_CHAIN_MISMATCH\";\n readonly CAPABILITY_UNAVAILABLE: \"CAPABILITY_UNAVAILABLE\";\n readonly CREATE_PARTIAL: \"CREATE_PARTIAL\";\n readonly DUPLICATE_RULE: \"DUPLICATE_RULE\";\n readonly FROM_NOT_ALLOWED: \"FROM_NOT_ALLOWED\";\n readonly GATEWAY_ALLOWANCE_INSUFFICIENT: \"GATEWAY_ALLOWANCE_INSUFFICIENT\";\n readonly GENERATION_UNSUPPORTED: \"GENERATION_UNSUPPORTED\";\n readonly INCONSISTENT_READ: \"INCONSISTENT_READ\";\n readonly INDEX_RACE: \"INDEX_RACE\";\n readonly INVALID_RULE: \"INVALID_RULE\";\n readonly NO_RULES_FOR_CHAIN: \"NO_RULES_FOR_CHAIN\";\n readonly NOT_AGENTIC_WALLET: \"NOT_AGENTIC_WALLET\";\n readonly NOT_ALLOWED_IN_AGENTIC_MODE: \"NOT_ALLOWED_IN_AGENTIC_MODE\";\n readonly NOT_OWNER_OR_AGENT: \"NOT_OWNER_OR_AGENT\";\n readonly NOT_WALLET_OWNER: \"NOT_WALLET_OWNER\";\n readonly READ_ONLY: \"READ_ONLY\";\n readonly RECEIPT_MISMATCH: \"RECEIPT_MISMATCH\";\n readonly RECEIPT_UNAVAILABLE: \"RECEIPT_UNAVAILABLE\";\n readonly REVOKE_NEEDS_TARGET: \"REVOKE_NEEDS_TARGET\";\n readonly RULE_LIMIT_EXCEEDED: \"RULE_LIMIT_EXCEEDED\";\n readonly RULE_NOT_FOUND: \"RULE_NOT_FOUND\";\n readonly RULE_READ_FAILED: \"RULE_READ_FAILED\";\n readonly TARGET_NOT_ON_RULE_CHAIN: \"TARGET_NOT_ON_RULE_CHAIN\";\n readonly WALLET_BALANCE_INSUFFICIENT: \"WALLET_BALANCE_INSUFFICIENT\";\n readonly WALLET_NOT_DEPLOYED: \"WALLET_NOT_DEPLOYED\";\n}", + "members": { + "AGENT_GAS_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\"" + }, + "AGENT_IS_OWNER": { + "optional": false, + "readonly": true, + "type": "\"AGENT_IS_OWNER\"" + }, + "ASSET_CHAIN_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"ASSET_CHAIN_MISMATCH\"" + }, + "CAPABILITY_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"CAPABILITY_UNAVAILABLE\"" + }, + "CREATE_PARTIAL": { + "optional": false, + "readonly": true, + "type": "\"CREATE_PARTIAL\"" + }, + "DUPLICATE_RULE": { + "optional": false, + "readonly": true, + "type": "\"DUPLICATE_RULE\"" + }, + "FROM_NOT_ALLOWED": { + "optional": false, + "readonly": true, + "type": "\"FROM_NOT_ALLOWED\"" + }, + "GATEWAY_ALLOWANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"GATEWAY_ALLOWANCE_INSUFFICIENT\"" + }, + "GENERATION_UNSUPPORTED": { + "optional": false, + "readonly": true, + "type": "\"GENERATION_UNSUPPORTED\"" + }, + "INCONSISTENT_READ": { + "optional": false, + "readonly": true, + "type": "\"INCONSISTENT_READ\"" + }, + "INDEX_RACE": { + "optional": false, + "readonly": true, + "type": "\"INDEX_RACE\"" + }, + "INVALID_RULE": { + "optional": false, + "readonly": true, + "type": "\"INVALID_RULE\"" + }, + "NO_RULES_FOR_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"NO_RULES_FOR_CHAIN\"" + }, + "NOT_AGENTIC_WALLET": { + "optional": false, + "readonly": true, + "type": "\"NOT_AGENTIC_WALLET\"" + }, + "NOT_ALLOWED_IN_AGENTIC_MODE": { + "optional": false, + "readonly": true, + "type": "\"NOT_ALLOWED_IN_AGENTIC_MODE\"" + }, + "NOT_OWNER_OR_AGENT": { + "optional": false, + "readonly": true, + "type": "\"NOT_OWNER_OR_AGENT\"" + }, + "NOT_WALLET_OWNER": { + "optional": false, + "readonly": true, + "type": "\"NOT_WALLET_OWNER\"" + }, + "READ_ONLY": { + "optional": false, + "readonly": true, + "type": "\"READ_ONLY\"" + }, + "RECEIPT_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_MISMATCH\"" + }, + "RECEIPT_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_UNAVAILABLE\"" + }, + "REVOKE_NEEDS_TARGET": { + "optional": false, + "readonly": true, + "type": "\"REVOKE_NEEDS_TARGET\"" + }, + "RULE_LIMIT_EXCEEDED": { + "optional": false, + "readonly": true, + "type": "\"RULE_LIMIT_EXCEEDED\"" + }, + "RULE_NOT_FOUND": { + "optional": false, + "readonly": true, + "type": "\"RULE_NOT_FOUND\"" + }, + "RULE_READ_FAILED": { + "optional": false, + "readonly": true, + "type": "\"RULE_READ_FAILED\"" + }, + "TARGET_NOT_ON_RULE_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"TARGET_NOT_ON_RULE_CHAIN\"" + }, + "WALLET_BALANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"WALLET_BALANCE_INSUFFICIENT\"" + }, + "WALLET_NOT_DEPLOYED": { + "optional": false, + "readonly": true, + "type": "\"WALLET_NOT_DEPLOYED\"" + } + } + }, + "Rule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule | import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "NativeRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "amount": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AmountLimit | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "maxCalls": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValuePerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxValueTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "pins": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ArgPin[] | undefined" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "AssetCap": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap", + "members": { + "maxPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/constants/tokens\").MoveableToken" + } + } + }, + "AllowedCall": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall", + "members": { + "beneficiary": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValue": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "`${string}(${string})` | `0x${string}`" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "UniversalRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall[]" + }, + "assets": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap[]" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "`eip155:${string}` | `solana:${string}`" + }, + "maxGasPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "RulesRecord": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "enabled": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "ref": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "rule": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule | import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule" + }, + "rulesId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "CreateOptions": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions", + "members": { + "progressHook": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook | undefined" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Rule[]" + } + } + }, + "CreateResult": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateResult", + "members": { + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "rulesIds": { + "optional": false, + "readonly": false, + "type": "`0x${string}`[]" + }, + "tx": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticTxMetadata": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticTxMetadata", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destinationAccount": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "destinationCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "door": { + "optional": false, + "readonly": false, + "type": "\"agent\" | \"owner\"" + }, + "nativeCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "rawData": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rawTo": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesId": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + } + }, + "publicSurface": { + "CHAIN": { + "type": "typeof import(\"sdk/src/lib/constants/enums\").CHAIN", + "members": { + "ARBITRUM_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA" + }, + "BASE_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA" + }, + "BNB_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET" + }, + "ETHEREUM_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET" + }, + "ETHEREUM_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA" + }, + "PUSH_LOCALNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET" + }, + "PUSH_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET" + }, + "PUSH_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET" + }, + "PUSH_TESTNET_DONUT": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET" + }, + "SOLANA_DEVNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET" + }, + "SOLANA_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET" + }, + "SOLANA_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET" + }, + "WEB2": { + "optional": false, + "readonly": false, + "type": "\"web2\"" + } + } + }, + "ConversionQuote": { + "type": "import(\"sdk/src/lib/constants/tokens\").ConversionQuote", + "members": { + "amountIn": { + "optional": false, + "readonly": false, + "type": "string" + }, + "amountOut": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rate": { + "optional": false, + "readonly": false, + "type": "number" + }, + "route": { + "optional": true, + "readonly": false, + "type": "string[] | undefined" + }, + "timestamp": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "UniversalSigner": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalSigner", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "signAndSendTransaction": { + "optional": false, + "readonly": false, + "type": "(unsignedTx: Uint8Array) => Promise" + }, + "signAuthorization": { + "optional": true, + "readonly": false, + "type": "((params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise) | undefined" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": true, + "readonly": false, + "type": "(({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise) | undefined" + } + } + }, + "UniversalAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "UniversalSignerSkeleton": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "signAndSendTransaction": { + "optional": false, + "readonly": false, + "type": "(unsignedTx: Uint8Array) => Promise" + }, + "signAuthorization": { + "optional": true, + "readonly": false, + "type": "((params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise) | undefined" + }, + "signerId": { + "optional": false, + "readonly": false, + "type": "string" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": true, + "readonly": false, + "type": "(({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise) | undefined" + } + } + }, + "SignAuthorizationParams": { + "type": "{\n chainId?: number;\n contractAddress: `0x${string}`;\n executor?: \"self\";\n nonce?: number;\n}", + "members": { + "chainId": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "contractAddress": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "executor": { + "optional": true, + "readonly": false, + "type": "\"self\" | undefined" + }, + "nonce": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "SignedAuthorization": { + "type": "{\n address: `0x${string}`;\n chainId: number;\n nonce: number;\n r: `0x${string}`;\n s: `0x${string}`;\n v?: bigint;\n yParity: number;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainId": { + "optional": false, + "readonly": false, + "type": "number" + }, + "nonce": { + "optional": false, + "readonly": false, + "type": "number" + }, + "r": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "s": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "v": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "yParity": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "DerivedExecutorAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").DerivedExecutorAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean | null" + } + } + }, + "ResolvedAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainName": { + "optional": false, + "readonly": false, + "type": "string" + }, + "exists": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "role": { + "optional": true, + "readonly": false, + "type": "\"controller\" | undefined" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"cea\" | \"uea\" | \"uoa\"" + } + } + }, + "ResolvedControllerAccounts": { + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedControllerAccounts", + "members": { + "accounts": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedAccount[]" + } + } + }, + "AccountType": { + "type": "\"cea\" | \"uea\" | \"uoa\"", + "members": {} + }, + "AccountRole": { + "type": "\"controller\"", + "members": {} + }, + "PC20TokenReference": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "FundsToken": { + "type": "import(\"sdk/src/lib/constants/tokens\").MoveableToken | import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20TokenReference", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "PC20RegistryEntry": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "chainName": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "PC20AddressResult": { + "type": "{\n address: `0x${string}`;\n decimals: number;\n name: string;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n registry: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20RegistryEntry[];\n symbol: string;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "decimals": { + "optional": false, + "readonly": false, + "type": "number" + }, + "name": { + "optional": false, + "readonly": false, + "type": "string" + }, + "network": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "registry": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20RegistryEntry[]" + }, + "symbol": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "isPC20Reference": { + "type": "(token: import(\"sdk/src/lib/orchestrator/orchestrator.types\").FundsToken | undefined) => token is import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20TokenReference", + "members": {} + }, + "PC20Error": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20Error", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidPC20AddressError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InvalidPC20AddressError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20TokenChainMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20TokenChainMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20WrapperNotRegisteredError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20WrapperNotRegisteredError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20RegistryMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20RegistryMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20FactoryMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20FactoryMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidPC20MetadataError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InvalidPC20MetadataError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20ExpectedButPRC20Error": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20ExpectedButPRC20Error", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20AmbiguousAddressError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20AmbiguousAddressError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "candidates": { + "optional": false, + "readonly": true, + "type": "{\n chain: string;\n pushAddress: string;\n}[]" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "UnsupportedPC20DestinationError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").UnsupportedPC20DestinationError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InsufficientPC20BalanceError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InsufficientPC20BalanceError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20UnknownChainNamespaceError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20UnknownChainNamespaceError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20WrapperPredictionUnavailableError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20WrapperPredictionUnavailableError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20ExportRevertedError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20ExportRevertedError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "lockedAmount": { + "optional": true, + "readonly": true, + "type": "bigint | undefined" + }, + "outboundTxId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "revertRecipient": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20UnsafeEmptyPayloadError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20UnsafeEmptyPayloadError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ChainTarget": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "ChainSource": { + "type": "{\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "UniversalTo": { + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget", + "members": {} + }, + "TransactionRouteType": { + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"", + "members": {} + }, + "UniversalExecuteParams": { + "type": "{\n from?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainSource;\n migration?: boolean;\n to: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTo;\n} & Omit", + "members": { + "_minimumDepositUsd": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "_requiredFundsOverride": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "_skipFeeLocking": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "_ueaStatus": { + "optional": true, + "readonly": false, + "type": "{\n balance: bigint;\n isDeployed: boolean;\n nonce: bigint;\n} | undefined" + }, + "data": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiCall[] | undefined" + }, + "deadline": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "feeLockTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "from": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainSource | undefined" + }, + "funds": { + "optional": true, + "readonly": false, + "type": "{\n amount: bigint;\n token?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").FundsToken;\n} | undefined" + }, + "gasLimit": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFeePerGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxPCForGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxPriorityFeePerGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "migration": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "nonce": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "options": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions | undefined" + }, + "payGasWith": { + "optional": true, + "readonly": false, + "type": "{\n minAmountOut?: bigint | string;\n slippageBps?: number;\n token?: import(\"sdk/src/lib/constants/tokens\").PayableToken;\n} | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "to": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget" + }, + "value": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "UniversalOutboundTxRequest": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalOutboundTxRequest", + "members": { + "amount": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gasPrice": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxPCForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "payload": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "recipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "revertRecipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "PreparedUniversalTx": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx", + "members": { + "_hop": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").HopDescriptor" + }, + "deadline": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "estimatedGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gatewayRequest": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalOutboundTxRequest | import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxRequest" + }, + "nonce": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "payload": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + } + } + }, + "CascadedTxResponse": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadedTxResponse", + "members": { + "finalTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hopCount": { + "optional": false, + "readonly": false, + "type": "number" + }, + "hops": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo[]" + }, + "initialTxHash": { + "optional": false, + "readonly": false, + "type": "string" + }, + "initialTxResponse": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions) => Promise" + }, + "waitForAll": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions) => Promise" + } + } + }, + "CascadeHopInfo": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo", + "members": { + "executionChain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "expectedSubTxId": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hopIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "outboundDetails": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").OutboundTxDetails | undefined" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + }, + "status": { + "optional": false, + "readonly": false, + "type": "\"confirmed\" | \"failed\" | \"pending\" | \"submitted\"" + }, + "txHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "CascadeTrackOptions": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions", + "members": { + "eventHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeProgressEvent) => void) | undefined" + }, + "timeout": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "CascadeProgressEvent": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeProgressEvent", + "members": { + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "elapsed": { + "optional": false, + "readonly": false, + "type": "number" + }, + "hopIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + }, + "status": { + "optional": false, + "readonly": false, + "type": "\"confirmed\" | \"failed\" | \"found\" | \"polling\" | \"timeout\" | \"waiting\"" + }, + "txHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "CascadeCompletionResult": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeCompletionResult", + "members": { + "failedAt": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "finalTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "finalTxResponse": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadedTxResponse | undefined" + }, + "hops": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo[]" + }, + "success": { + "optional": false, + "readonly": false, + "type": "boolean" + } + } + }, + "MultiChainTxResponse": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiChainTxResponse", + "members": { + "chains": { + "optional": false, + "readonly": false, + "type": "{\n blockNumber: bigint;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n hash: string;\n status: \"confirmed\" | \"failed\" | \"pending\";\n}[]" + }, + "transactions": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse[]" + } + } + }, + "OutboundTxDetails": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").OutboundTxDetails", + "members": { + "amount": { + "optional": false, + "readonly": false, + "type": "string" + }, + "assetAddr": { + "optional": false, + "readonly": false, + "type": "string" + }, + "destinationChain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "explorerUrl": { + "optional": false, + "readonly": false, + "type": "string" + }, + "externalTxHash": { + "optional": false, + "readonly": false, + "type": "string" + }, + "recipient": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "WaitForOutboundOptions": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").WaitForOutboundOptions", + "members": { + "_expectedDestinationChain": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "_outboundIndex": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "_resolvedSubTxId": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "initialWaitMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: {\n elapsed: number;\n status: \"failed\" | \"found\" | \"polling\" | \"timeout\" | \"waiting\";\n}) => void) | undefined" + }, + "timeout": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "SvmGatewayAccountMeta": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmGatewayAccountMeta", + "members": { + "isWritable": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "pubkey": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "SvmExecutePayloadFields": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmExecutePayloadFields", + "members": { + "accounts": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmGatewayAccountMeta[]" + }, + "instructionId": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "ixData": { + "optional": false, + "readonly": false, + "type": "Uint8Array" + }, + "targetProgram": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AccountStatus": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus", + "members": { + "mode": { + "optional": false, + "readonly": false, + "type": "\"read-only\" | \"signer\"" + }, + "uea": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UEAStatus" + } + } + }, + "UEAStatus": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UEAStatus", + "members": { + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "loaded": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "minRequiredVersion": { + "optional": false, + "readonly": false, + "type": "string" + }, + "requiresUpgrade": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "version": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "RescueFundsParams": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").RescueFundsParams", + "members": { + "prc20": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "universalTxId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "parseUEAVersion": { + "type": "(version: string) => number", + "members": {} + }, + "TransactionRoute": { + "type": "typeof import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute", + "members": { + "CEA_TO_CEA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.CEA_TO_CEA" + }, + "CEA_TO_PUSH": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.CEA_TO_PUSH" + }, + "UOA_TO_CEA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.UOA_TO_CEA" + }, + "UOA_TO_PUSH": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.UOA_TO_PUSH" + } + } + }, + "detectRoute": { + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams) => import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute", + "members": {} + }, + "isChainTarget": { + "type": "(to: unknown) => to is import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget", + "members": {} + }, + "DEFAULT_MAX_PC_FOR_GAS_BUFFER_BPS": { + "type": "1000", + "members": {} + }, + "MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT": { + "type": "10000", + "members": {} + }, + "quoteMaxPCForGasCap": { + "type": "(input: import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapInput) => import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": {} + }, + "quoteMaxPCForGasCapFromNativeValue": { + "type": "(input: import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapFromNativeValueInput) => import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": {} + }, + "MaxPCForGasCapInput": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapInput", + "members": { + "bufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "gasLegNativePc": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "MaxPCForGasCapFromNativeValueInput": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapFromNativeValueInput", + "members": { + "bufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "nativeValueForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "MaxPCForGasCapQuote": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": { + "bufferBps": { + "optional": false, + "readonly": false, + "type": "number" + }, + "gasLegNativePc": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxPCForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "nativeValueForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "getCEAAddress": { + "type": "(ueaAddress: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise", + "members": {} + }, + "getPushAccountForCEA": { + "type": "(ceaAddress: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise<`0x${string}`>", + "members": {} + }, + "isCEA": { + "type": "(address: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise", + "members": {} + }, + "chainSupportsCEA": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "chainSupportsOutbound": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "getCEAFactoryAddress": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => `0x${string}` | undefined", + "members": {} + }, + "getAllCEAAddresses": { + "type": "(ueaAddress: `0x${string}`, rpcUrls?: Partial>) => Promise", + "members": {} + }, + "encodeSvmExecutePayload": { + "type": "(fields: import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmExecutePayloadFields) => `0x${string}`", + "members": {} + }, + "isSvmChain": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "isValidSolanaHexAddress": { + "type": "(address: string) => boolean", + "members": {} + }, + "buildMigrationPayload": { + "type": "() => `0x${string}`", + "members": {} + }, + "buildErc20WithdrawalMulticall": { + "type": "(tokenAddress: `0x${string}`, recipientAddress: `0x${string}`, amount: bigint) => import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiCall[]", + "members": {} + }, + "ReadChain": { + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain", + "members": {} + }, + "ReadDestination": { + "type": "{\n chain: import(\"sdk/src/lib/read-state/read-state.types\").ReadChain;\n} | {\n chainId: string;\n chainNamespace: string;\n}", + "members": {} + }, + "ResolvedDestination": { + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}", + "members": { + "caip2": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainId": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "namespace": { + "optional": false, + "readonly": false, + "type": "\"eip155\" | \"solana\" | \"web2\"" + } + } + }, + "ReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").SvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery", + "members": { + "type": { + "optional": false, + "readonly": false, + "type": "\"accountBalance\" | \"contractCall\" | \"http\" | \"lamportBalance\" | \"rawAccountData\" | \"splTokenAccount\" | \"storageSlot\"" + } + } + }, + "EvmReadQuery": { + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n target: `0x${string}`;\n type: \"contractCall\";\n} | {\n callData: `0x${string}`;\n target: `0x${string}`;\n type: \"contractCall\";\n} | {\n slot: `0x${string}` | bigint;\n target: `0x${string}`;\n type: \"storageSlot\";\n} | {\n target: `0x${string}`;\n type: \"accountBalance\";\n}", + "members": { + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"accountBalance\" | \"contractCall\" | \"storageSlot\"" + } + } + }, + "SvmReadQuery": { + "type": "{\n account: string | Uint8Array;\n accountName?: string;\n idl?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n type: \"rawAccountData\";\n} | {\n account: string | Uint8Array;\n type: \"lamportBalance\";\n} | {\n account: string | Uint8Array;\n type: \"splTokenAccount\";\n}", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "string | Uint8Array" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"lamportBalance\" | \"rawAccountData\" | \"splTokenAccount\"" + } + } + }, + "Web2ReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery", + "members": { + "body": { + "optional": true, + "readonly": false, + "type": "string | Uint8Array | undefined" + }, + "extract": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[]" + }, + "headers": { + "optional": true, + "readonly": false, + "type": "Record | undefined" + }, + "method": { + "optional": true, + "readonly": false, + "type": "\"GET\" | \"POST\" | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"http\"" + }, + "url": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "Web2Extract": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract", + "members": { + "decimals": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "path": { + "optional": false, + "readonly": false, + "type": "string" + }, + "valueType": { + "optional": false, + "readonly": false, + "type": "\"bool\" | \"bytes\" | \"int256\" | \"string\" | \"uint256\"" + } + } + }, + "Web2ValueType": { + "type": "\"bool\" | \"bytes\" | \"int256\" | \"string\" | \"uint256\"", + "members": {} + }, + "EncodedReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery", + "members": { + "blockRef": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "encoded": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "namespace": { + "optional": false, + "readonly": false, + "type": "\"eip155\" | \"solana\" | \"web2\"" + }, + "ownerBytes": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "queryType": { + "optional": false, + "readonly": false, + "type": "number" + }, + "resultShape": { + "optional": false, + "readonly": false, + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}" + }, + "warnings": { + "optional": false, + "readonly": false, + "type": "string[]" + } + } + }, + "ReadResultShape": { + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"bytes32\" | \"evmCall\" | \"raw\" | \"svmAccount\" | \"uint256\" | \"web2\"" + } + } + }, + "DecodedReadResult": { + "type": "{\n accountName: string;\n kind: \"svmAccount\";\n value: unknown;\n} | {\n kind: \"bytes32\";\n value: `0x${string}`;\n} | {\n kind: \"evmCall\";\n value: unknown;\n} | {\n kind: \"raw\";\n value: `0x${string}`;\n} | {\n kind: \"uint256\";\n value: bigint;\n} | {\n kind: \"web2\";\n values: readonly unknown[];\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"bytes32\" | \"evmCall\" | \"raw\" | \"svmAccount\" | \"uint256\" | \"web2\"" + } + } + }, + "ReadPreflight": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight", + "members": { + "destination": { + "optional": false, + "readonly": false, + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}" + }, + "fetchedAt": { + "optional": false, + "readonly": false, + "type": "number" + }, + "observedChainHeight": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pushBlockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pushGasPrice": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "universalCallback": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "universalCore": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ReadSpec": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "{\n chainId: string;\n chainNamespace: string;\n owner: `0x${string}`;\n}" + }, + "blockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "expiryPushChainHeight": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "minConfirmations": { + "optional": false, + "readonly": false, + "type": "number" + }, + "query": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "revertRecipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ReadSpecTuple": { + "type": "readonly [\n readonly [\n string,\n string,\n `0x${string}`\n ],\n `0x${string}`,\n number,\n bigint,\n bigint,\n bigint,\n `0x${string}`\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "readonly [\n string,\n string,\n `0x${string}`\n]" + }, + "1": { + "optional": false, + "readonly": true, + "type": "`0x${string}`" + }, + "2": { + "optional": false, + "readonly": true, + "type": "number" + }, + "3": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "4": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "5": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "6": { + "optional": false, + "readonly": true, + "type": "`0x${string}`" + }, + "length": { + "optional": false, + "readonly": true, + "type": "7" + } + } + }, + "BuildReadSpecParams": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").BuildReadSpecParams", + "members": { + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "budgetBuffer": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback | undefined" + }, + "callbackBudget": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "destination": { + "optional": false, + "readonly": false, + "type": "{\n chain: import(\"sdk/src/lib/read-state/read-state.types\").ReadChain;\n} | {\n chainId: string;\n chainNamespace: string;\n}" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "expiryPushChainHeight": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFeeBufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "owner": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "query": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").SvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "PreparedRead": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead", + "members": { + "__@preparedReadValue": { + "optional": true, + "readonly": true, + "type": "T | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback | undefined" + }, + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "encodedQuery": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery" + }, + "encodedSpec": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "fees": { + "optional": false, + "readonly": false, + "type": "{\n callbackBudget: bigint;\n protocolFee: bigint;\n total: bigint;\n}" + }, + "preflight": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "queryKey": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "resultShape": { + "optional": false, + "readonly": false, + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}" + }, + "spec": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec" + }, + "specTuple": { + "optional": false, + "readonly": false, + "type": "readonly [\n readonly [\n string,\n string,\n `0x${string}`\n ],\n `0x${string}`,\n number,\n bigint,\n bigint,\n bigint,\n `0x${string}`\n]" + }, + "value": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "warnings": { + "optional": false, + "readonly": false, + "type": "string[]" + } + } + }, + "ReadCallback": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "((spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpecTuple, callbackGasLimit: bigint) => readonly unknown[]) | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "gasLimit": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "target": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "SimulateReadResult": { + "type": "{\n args?: readonly unknown[];\n error: string;\n errorName?: string;\n ok: false;\n} | {\n ok: true;\n}", + "members": { + "ok": { + "optional": false, + "readonly": false, + "type": "boolean" + } + } + }, + "ParsedReadRequest": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ParsedReadRequest", + "members": { + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackTarget": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "logIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "originalFunder": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "requestId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "requestIdUint": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "spec": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec" + }, + "totalPaid": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "FulfilOutcome": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").FulfilOutcome", + "members": { + "burned": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "delivered": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "expired": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "failReason": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "gasReported": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refunded": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refundFailed": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "ReceiptLike": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike", + "members": { + "logs": { + "optional": false, + "readonly": false, + "type": "readonly {\n address: string;\n data: string;\n logIndex?: number | string;\n topics: readonly string[];\n}[]" + } + } + }, + "ReadRef": { + "type": "{\n requestId: `0x${string}` | bigint;\n} | {\n txHash: `0x${string}`;\n}", + "members": {} + }, + "ReadLifecycleOptions": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadLifecycleOptions", + "members": { + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "resultShape": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadFees": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadFees", + "members": { + "burned": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "paid": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "refunded": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refundFailed": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + } + } + }, + "UniversalReadResponse": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse", + "members": { + "callbackDelivered": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "callbackFailReason": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "decoded": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").DecodedReadResult | undefined" + }, + "decodeError": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destination": { + "optional": false, + "readonly": false, + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}" + }, + "errorMsg": { + "optional": false, + "readonly": false, + "type": "string" + }, + "explorerUrl": { + "optional": false, + "readonly": false, + "type": "string" + }, + "fees": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadFees" + }, + "isTerminal": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "outcome": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME" + }, + "pcTx": { + "optional": false, + "readonly": false, + "type": "readonly {\n blockHeight: number;\n errorMsg: string;\n status: string;\n txHash: `0x${string}`;\n}[]" + }, + "raw": { + "optional": false, + "readonly": false, + "type": "{\n errorCode: import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n resultData: `0x${string}`;\n status: import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n} | null" + }, + "refresh": { + "optional": false, + "readonly": false, + "type": "() => Promise>" + }, + "request": { + "optional": false, + "readonly": false, + "type": "{\n callbackGasLimit: bigint;\n callbackTarget: `0x${string}`;\n createdAtHeight: bigint;\n logIndex: number;\n originalFunder: `0x${string}`;\n refundTo: `0x${string}`;\n spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec;\n}" + }, + "requestId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "requestIdUint": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "status": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "value": { + "optional": true, + "readonly": false, + "type": "T | undefined" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/read-state/read-state.types\").ReadLifecycleOptions) => Promise>" + } + } + }, + "ReadResponseTuple": { + "type": "{\n -readonly [K in keyof R]: import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse ? T : unknown>;\n}", + "members": {} + }, + "BatchReadResponse": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").BatchReadResponse", + "members": { + "atomic": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "count": { + "optional": false, + "readonly": false, + "type": "number" + }, + "reads": { + "optional": false, + "readonly": false, + "type": "{\n -readonly [K in keyof R]: import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse ? T : unknown>;\n}" + }, + "transactionHashes": { + "optional": true, + "readonly": false, + "type": "readonly `0x${string}`[] | undefined" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: Omit) => Promise>" + } + } + }, + "ReadOptions": { + "type": "((import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">)) & {\n callback?: (Pick & Required>) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n };\n}", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "advanced": { + "optional": true, + "readonly": false, + "type": "{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n} | undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "({\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} & {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n}) | ({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick & Pick & Required>) | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadPrepareOptions": { + "type": "((((({\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\">) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n}) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">)) & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n}) | ((({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n}) | ({\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\">)) & {\n blockNumber?: never;\n minConfirmations?: never;\n})) & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n}) & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "advanced": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadQueryOptions": { + "type": "({\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\">) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n}) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n}) | ({\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\">)", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadCallbackOptions": { + "type": "{\n callback?: ({\n gasLimit?: bigint;\n target: `0x${string}`;\n } & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n };\n}", + "members": { + "callback": { + "optional": true, + "readonly": false, + "type": "({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} | undefined" + } + } + }, + "ReadValue": { + "type": "O extends {\n abi: infer A extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: infer F extends string;\n} ? number extends A[\"length\"] ? unknown : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, O extends {\n args: infer Args extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n} ? Args : readonly [\n] extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> ? import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> & readonly [\n] : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>> extends infer Selected ? Selected extends {\n outputs: readonly unknown[];\n type: \"function\";\n} & import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiFunction ? {\n [key in keyof {\n [key in keyof import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"]]: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterToPrimitiveType, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"][key], import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterKind>;\n }]: {\n [key in keyof import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"]]: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterToPrimitiveType, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"][key], import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterKind>;\n }[key];\n} extends infer types ? types extends readonly [\n] ? void : types extends readonly [\n infer type\n] ? type : types : never : never : never : O extends {\n web2: {\n extract: infer E extends readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n };\n} ? {\n readonly [K in keyof E]: {\n bool: boolean;\n bytes: `0x${string}`;\n int256: bigint;\n string: string;\n uint256: bigint;\n }[E[K][\"valueType\"]];\n} : O extends {\n storageSlot: unknown;\n} ? `0x${string}` : O extends {\n idl: infer I extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} ? string extends Extract, string> ? unknown : (O extends {\n functionName: infer N extends string;\n} ? N : undefined) extends string ? import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/index\").IdlAccounts[{\n [K in Extract, string>]: Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : K> extends Lowercase<(O extends {\n functionName: infer N extends string;\n } ? N : undefined) & string extends `${infer H}_${infer T}` ? `${H}${Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : (O extends {\n functionName: infer N extends string;\n } ? N : undefined) & string> ? K : never;\n}[Extract, string>]] : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/index\").IdlAccounts[Extract, string>] : bigint", + "members": {} + }, + "ValidateReadCall": { + "type": "O extends {\n abi: infer A extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: infer F extends string;\n} ? (readonly [\n] extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> ? {\n args?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n} : {\n args: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n}) & {\n functionName: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionName;\n} : O extends {\n functionName: infer N extends string;\n idl: infer I extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} ? string extends Extract, string> ? unknown : [\n {\n [K in Extract, string>]: Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : K> extends Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : N> ? K : never;\n }[Extract, string>]\n] extends [\n never\n] ? {\n functionName: Extract, string>;\n} : unknown : unknown", + "members": {} + }, + "ReadWeb2Options": { + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options", + "members": { + "body": { + "optional": true, + "readonly": false, + "type": "string | Uint8Array | undefined" + }, + "extract": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[]" + }, + "headers": { + "optional": true, + "readonly": false, + "type": "Record | undefined" + }, + "method": { + "optional": true, + "readonly": false, + "type": "\"GET\" | \"POST\" | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadTrackOptions": { + "type": "{\n advanced?: Omit, \"enforceGasCheck\">;\n resultShape?: import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape;\n}", + "members": { + "advanced": { + "optional": true, + "readonly": false, + "type": "Omit<{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n}, \"enforceGasCheck\"> | undefined" + }, + "resultShape": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape | undefined" + } + } + }, + "ReadExecuteOptions": { + "type": "{\n advanced?: {\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n } | undefined;\n progressHook?: ((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined;\n waitForCompletion?: boolean | undefined;\n}", + "members": { + "advanced": { + "optional": true, + "readonly": false, + "type": "{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n} | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + } + } + }, + "UNIVERSAL_READ_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS", + "members": { + "ABORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.ABORTED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.EXPIRED" + }, + "FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.FAILED" + }, + "FULFILLED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.FULFILLED" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.PENDING" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.UNSPECIFIED" + }, + "VOTING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.VOTING" + } + } + }, + "READ_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS", + "members": { + "ERROR": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.ERROR" + }, + "SUCCESS": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.SUCCESS" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.UNSPECIFIED" + } + } + }, + "READ_ERROR_CODE": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE", + "members": { + "INVALID_QUERY": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.INVALID_QUERY" + }, + "INVALID_RESULT": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.INVALID_RESULT" + }, + "NOT_FOUND": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.NOT_FOUND" + }, + "REJECTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.REJECTED" + }, + "REVERTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.REVERTED" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.UNSPECIFIED" + }, + "UNSUPPORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.UNSUPPORTED" + } + } + }, + "READ_OUTCOME": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME", + "members": { + "ABORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.ABORTED" + }, + "CALLBACK_FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.CALLBACK_FAILED" + }, + "DECODE_FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.DECODE_FAILED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.EXPIRED" + }, + "FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.FAILED" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.PENDING" + }, + "SOURCE_ERROR": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.SOURCE_ERROR" + }, + "SUCCESS": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.SUCCESS" + }, + "UNKNOWN": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.UNKNOWN" + } + } + }, + "CONTRACT_REQUEST_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS", + "members": { + "EXECUTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.EXECUTED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.EXPIRED" + }, + "NONE": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.NONE" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.PENDING" + }, + "SETTLED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.SETTLED" + } + } + }, + "TERMINAL_READ_STATUSES": { + "type": "ReadonlySet", + "members": {} + }, + "ReadStateError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadStateError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidReadQueryError": { + "type": "import(\"sdk/src/lib/read-state/errors\").InvalidReadQueryError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidReadSpecError": { + "type": "import(\"sdk/src/lib/read-state/errors\").InvalidReadSpecError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "violations": { + "optional": false, + "readonly": true, + "type": "readonly import(\"sdk/src/lib/read-state/errors\").ReadSpecViolation[]" + } + } + }, + "ReadHeightUnavailableError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadHeightUnavailableError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "UnsupportedReadDestinationError": { + "type": "import(\"sdk/src/lib/read-state/errors\").UnsupportedReadDestinationError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadDecodeError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadDecodeError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadTimeoutError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadTimeoutError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "lastStatus": { + "optional": false, + "readonly": true, + "type": "number" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadNotFoundError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadNotFoundError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadRegistryUnavailableError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadRegistryUnavailableError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadSpecViolation": { + "type": "\"CALLBACK_GAS_LIMIT_EXCEEDED\" | \"DOMAIN_BLOCKED\" | \"EMPTY_QUERY\" | \"EXCESSIVE_FEE\" | \"INSUFFICIENT_CALLBACK_BUDGET\" | \"INSUFFICIENT_FEE\" | \"INVALID_ACCOUNT_ID\" | \"INVALID_BLOCK_NUMBER\" | \"INVALID_EXPIRY_HEIGHT\" | \"INVALID_MIN_CONFIRMATIONS\" | \"SVM_OWNER_NOT_32_BYTES\" | \"ZERO_CALLBACK_BUDGET\" | \"ZERO_CALLBACK_GAS_LIMIT\" | \"ZERO_REVERT_RECIPIENT\"", + "members": {} + }, + "resolveDestination": { + "type": "(dest: import(\"sdk/src/lib/read-state/read-state.types\").ReadDestination) => import(\"sdk/src/lib/read-state/read-state.types\").ResolvedDestination", + "members": {} + }, + "encodeReadQuery": { + "type": "(destination: import(\"sdk/src/lib/read-state/read-state.types\").ReadDestination, query: import(\"sdk/src/lib/read-state/read-state.types\").ReadQuery, options?: {\n blockNumber?: bigint;\n minSlot?: bigint;\n}) => import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery", + "members": {} + }, + "decodeReadResult": { + "type": "(resultData: `0x${string}`, shape: import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape) => import(\"sdk/src/lib/read-state/read-state.types\").DecodedReadResult", + "members": {} + }, + "parseReadRequestsFromReceipt": { + "type": "(receipt: import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike, universalCallback: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").ParsedReadRequest[]", + "members": {} + }, + "parseFulfilOutcome": { + "type": "(receipt: import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike, universalCallback: `0x${string}`, requestId: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").FulfilOutcome", + "members": {} + }, + "buildReadSpecFromPreflight": { + "type": "(preflight: import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight, params: import(\"sdk/src/lib/read-state/read-state.types\").BuildReadSpecParams, defaults?: {\n refundTo?: `0x${string}`;\n}) => import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead", + "members": {} + }, + "validateReadSpec": { + "type": "(input: import(\"sdk/src/lib/read-state/validate\").ValidateReadSpecInput) => {\n ok: false;\n violations: import(\"sdk/src/lib/read-state/errors\").ReadSpecViolation[];\n} | {\n ok: true;\n}", + "members": {} + }, + "toCallData": { + "type": "(prepared: import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead, target: {\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: (spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpecTuple, callbackGasLimit: bigint) => readonly unknown[];\n functionName: string;\n}) => {\n data: `0x${string}`;\n value: bigint;\n}", + "members": {} + }, + "sizeCallbackBudget": { + "type": "(callbackGasLimit: bigint, pushGasPrice: bigint, buffer?: number) => bigint", + "members": {} + }, + "inferResultShape": { + "type": "(namespace: string, query: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape", + "members": {} + }, + "toRequestIdHex": { + "type": "(id: `0x${string}` | bigint) => `0x${string}`", + "members": {} + }, + "toReadQuery": { + "type": "(subject: string, o: ReadOptionsInput, resolvedTokenProgram?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@solana/web3.js/lib/index\").PublicKey) => import(\"sdk/src/lib/read-state/read-state.types\").ReadQuery", + "members": {} + }, + "UNIVERSAL_CALLBACK_EVM": { + "type": "readonly [\n {\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"requestExternalReadSelf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"estimateFee\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"statusOf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"enum RequestStatus\";\n readonly name: \"\";\n readonly type: \"uint8\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"isFulfilled\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getPendingRead\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly internalType: \"struct PendingRead\";\n readonly name: \"\";\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"totalEscrowed\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"blockedDomains\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly indexed: false;\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"readSpec\";\n readonly type: \"tuple\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"totalPaid\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"protocolFee\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ReadRequested\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"ReadFulfilled\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"reason\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"CallbackFailed\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"gasReported\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"burned\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"CallbackGasReported\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundSent\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundFailed\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RequestExpired\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"vaultPC\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ProtocolFeeDistributed\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidAccountId\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"EmptyQuery\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidMinConfirmations\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"DomainBlocked\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidBlockNumber\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidExpiryHeight\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroRevertRecipient\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroCallbackGasLimit\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint64\";\n readonly name: \"provided\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"max\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"CallbackGasLimitExceeded\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"required\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"InsufficientFee\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ExcessiveFee\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"actual\";\n readonly type: \"uint8\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"expected\";\n readonly type: \"uint8\";\n }\n ];\n readonly name: \"InvalidRequestStatus\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ContractIsPaused\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"CallerIsNotUCallbackModule\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n }\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"requestExternalReadSelf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n}" + }, + "1": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"estimateFee\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "2": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"statusOf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"enum RequestStatus\";\n readonly name: \"\";\n readonly type: \"uint8\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "3": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"isFulfilled\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "4": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getPendingRead\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly internalType: \"struct PendingRead\";\n readonly name: \"\";\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "5": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"totalEscrowed\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "6": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"blockedDomains\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "7": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly indexed: false;\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"readSpec\";\n readonly type: \"tuple\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"totalPaid\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"protocolFee\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ReadRequested\";\n readonly type: \"event\";\n}" + }, + "8": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"ReadFulfilled\";\n readonly type: \"event\";\n}" + }, + "9": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"reason\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"CallbackFailed\";\n readonly type: \"event\";\n}" + }, + "10": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"gasReported\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"burned\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"CallbackGasReported\";\n readonly type: \"event\";\n}" + }, + "11": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundSent\";\n readonly type: \"event\";\n}" + }, + "12": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundFailed\";\n readonly type: \"event\";\n}" + }, + "13": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RequestExpired\";\n readonly type: \"event\";\n}" + }, + "14": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"vaultPC\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ProtocolFeeDistributed\";\n readonly type: \"event\";\n}" + }, + "15": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidAccountId\";\n readonly type: \"error\";\n}" + }, + "16": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"EmptyQuery\";\n readonly type: \"error\";\n}" + }, + "17": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidMinConfirmations\";\n readonly type: \"error\";\n}" + }, + "18": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"DomainBlocked\";\n readonly type: \"error\";\n}" + }, + "19": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidBlockNumber\";\n readonly type: \"error\";\n}" + }, + "20": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidExpiryHeight\";\n readonly type: \"error\";\n}" + }, + "21": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroRevertRecipient\";\n readonly type: \"error\";\n}" + }, + "22": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroCallbackGasLimit\";\n readonly type: \"error\";\n}" + }, + "23": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint64\";\n readonly name: \"provided\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"max\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"CallbackGasLimitExceeded\";\n readonly type: \"error\";\n}" + }, + "24": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"required\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"InsufficientFee\";\n readonly type: \"error\";\n}" + }, + "25": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ExcessiveFee\";\n readonly type: \"error\";\n}" + }, + "26": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"actual\";\n readonly type: \"uint8\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"expected\";\n readonly type: \"uint8\";\n }\n ];\n readonly name: \"InvalidRequestStatus\";\n readonly type: \"error\";\n}" + }, + "27": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ContractIsPaused\";\n readonly type: \"error\";\n}" + }, + "28": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"CallerIsNotUCallbackModule\";\n readonly type: \"error\";\n}" + }, + "29": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n}" + }, + "length": { + "optional": false, + "readonly": true, + "type": "30" + } + } + }, + "UNIVERSAL_READ_REGISTRY_EVM": { + "type": "readonly [\n {\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n },\n {\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"read\";\n readonly outputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"universalCallback_\";\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"constructor\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"initialize\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getLocalContext\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"hasResult\";\n readonly outputs: readonly [\n {\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"onUniversalData\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"queryKeyOf\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes32\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"readerOf\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"requestOrderOf\";\n readonly outputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"universalCallback\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"resultByRequestId\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"latestResult\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"version\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"Initialized\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadRequested\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadStored\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidInitialization\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"NotInitializing\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroAddressInit\";\n readonly type: \"error\";\n }\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n },\n {\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"read\";\n readonly outputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n}" + }, + "1": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"universalCallback_\";\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"constructor\";\n}" + }, + "2": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"initialize\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n}" + }, + "3": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getLocalContext\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "4": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"hasResult\";\n readonly outputs: readonly [\n {\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "5": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"onUniversalData\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n}" + }, + "6": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"queryKeyOf\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes32\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "7": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"readerOf\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "8": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"requestOrderOf\";\n readonly outputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "9": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"universalCallback\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "10": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"resultByRequestId\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "11": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"latestResult\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "12": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"version\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"Initialized\";\n readonly type: \"event\";\n}" + }, + "13": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadRequested\";\n readonly type: \"event\";\n}" + }, + "14": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadStored\";\n readonly type: \"event\";\n}" + }, + "15": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidInitialization\";\n readonly type: \"error\";\n}" + }, + "16": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"NotInitializing\";\n readonly type: \"error\";\n}" + }, + "17": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n}" + }, + "18": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroAddressInit\";\n readonly type: \"error\";\n}" + }, + "length": { + "optional": false, + "readonly": true, + "type": "19" + } + } + }, + "PushChainExecutionError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").PushChainExecutionError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PushChainBatchExecutionError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").PushChainBatchExecutionError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": false, + "readonly": true, + "type": "`0x${string}`[]" + } + } + }, + "DecodedErrorPayload": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload", + "members": { + "decoded": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "name": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "selector": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "PushChainInitializeOptions": { + "type": "import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions", + "members": { + "agenticWallet": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "blockExplorers": { + "optional": true, + "readonly": false, + "type": "Partial> | undefined" + }, + "network": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "printTraces": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "rpcUrls": { + "optional": true, + "readonly": false, + "type": "Partial> | undefined" + } + } + }, + "AGENTIC_ERROR_CODE": { + "type": "{\n readonly AGENT_GAS_INSUFFICIENT: \"AGENT_GAS_INSUFFICIENT\";\n readonly AGENT_IS_OWNER: \"AGENT_IS_OWNER\";\n readonly ASSET_CHAIN_MISMATCH: \"ASSET_CHAIN_MISMATCH\";\n readonly CAPABILITY_UNAVAILABLE: \"CAPABILITY_UNAVAILABLE\";\n readonly CREATE_PARTIAL: \"CREATE_PARTIAL\";\n readonly DUPLICATE_RULE: \"DUPLICATE_RULE\";\n readonly FROM_NOT_ALLOWED: \"FROM_NOT_ALLOWED\";\n readonly GATEWAY_ALLOWANCE_INSUFFICIENT: \"GATEWAY_ALLOWANCE_INSUFFICIENT\";\n readonly GENERATION_UNSUPPORTED: \"GENERATION_UNSUPPORTED\";\n readonly INCONSISTENT_READ: \"INCONSISTENT_READ\";\n readonly INDEX_RACE: \"INDEX_RACE\";\n readonly INVALID_RULE: \"INVALID_RULE\";\n readonly NO_RULES_FOR_CHAIN: \"NO_RULES_FOR_CHAIN\";\n readonly NOT_AGENTIC_WALLET: \"NOT_AGENTIC_WALLET\";\n readonly NOT_ALLOWED_IN_AGENTIC_MODE: \"NOT_ALLOWED_IN_AGENTIC_MODE\";\n readonly NOT_OWNER_OR_AGENT: \"NOT_OWNER_OR_AGENT\";\n readonly NOT_WALLET_OWNER: \"NOT_WALLET_OWNER\";\n readonly READ_ONLY: \"READ_ONLY\";\n readonly RECEIPT_MISMATCH: \"RECEIPT_MISMATCH\";\n readonly RECEIPT_UNAVAILABLE: \"RECEIPT_UNAVAILABLE\";\n readonly REVOKE_NEEDS_TARGET: \"REVOKE_NEEDS_TARGET\";\n readonly RULE_LIMIT_EXCEEDED: \"RULE_LIMIT_EXCEEDED\";\n readonly RULE_NOT_FOUND: \"RULE_NOT_FOUND\";\n readonly RULE_READ_FAILED: \"RULE_READ_FAILED\";\n readonly TARGET_NOT_ON_RULE_CHAIN: \"TARGET_NOT_ON_RULE_CHAIN\";\n readonly WALLET_BALANCE_INSUFFICIENT: \"WALLET_BALANCE_INSUFFICIENT\";\n readonly WALLET_NOT_DEPLOYED: \"WALLET_NOT_DEPLOYED\";\n}", + "members": { + "AGENT_GAS_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\"" + }, + "AGENT_IS_OWNER": { + "optional": false, + "readonly": true, + "type": "\"AGENT_IS_OWNER\"" + }, + "ASSET_CHAIN_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"ASSET_CHAIN_MISMATCH\"" + }, + "CAPABILITY_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"CAPABILITY_UNAVAILABLE\"" + }, + "CREATE_PARTIAL": { + "optional": false, + "readonly": true, + "type": "\"CREATE_PARTIAL\"" + }, + "DUPLICATE_RULE": { + "optional": false, + "readonly": true, + "type": "\"DUPLICATE_RULE\"" + }, + "FROM_NOT_ALLOWED": { + "optional": false, + "readonly": true, + "type": "\"FROM_NOT_ALLOWED\"" + }, + "GATEWAY_ALLOWANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"GATEWAY_ALLOWANCE_INSUFFICIENT\"" + }, + "GENERATION_UNSUPPORTED": { + "optional": false, + "readonly": true, + "type": "\"GENERATION_UNSUPPORTED\"" + }, + "INCONSISTENT_READ": { + "optional": false, + "readonly": true, + "type": "\"INCONSISTENT_READ\"" + }, + "INDEX_RACE": { + "optional": false, + "readonly": true, + "type": "\"INDEX_RACE\"" + }, + "INVALID_RULE": { + "optional": false, + "readonly": true, + "type": "\"INVALID_RULE\"" + }, + "NO_RULES_FOR_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"NO_RULES_FOR_CHAIN\"" + }, + "NOT_AGENTIC_WALLET": { + "optional": false, + "readonly": true, + "type": "\"NOT_AGENTIC_WALLET\"" + }, + "NOT_ALLOWED_IN_AGENTIC_MODE": { + "optional": false, + "readonly": true, + "type": "\"NOT_ALLOWED_IN_AGENTIC_MODE\"" + }, + "NOT_OWNER_OR_AGENT": { + "optional": false, + "readonly": true, + "type": "\"NOT_OWNER_OR_AGENT\"" + }, + "NOT_WALLET_OWNER": { + "optional": false, + "readonly": true, + "type": "\"NOT_WALLET_OWNER\"" + }, + "READ_ONLY": { + "optional": false, + "readonly": true, + "type": "\"READ_ONLY\"" + }, + "RECEIPT_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_MISMATCH\"" + }, + "RECEIPT_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_UNAVAILABLE\"" + }, + "REVOKE_NEEDS_TARGET": { + "optional": false, + "readonly": true, + "type": "\"REVOKE_NEEDS_TARGET\"" + }, + "RULE_LIMIT_EXCEEDED": { + "optional": false, + "readonly": true, + "type": "\"RULE_LIMIT_EXCEEDED\"" + }, + "RULE_NOT_FOUND": { + "optional": false, + "readonly": true, + "type": "\"RULE_NOT_FOUND\"" + }, + "RULE_READ_FAILED": { + "optional": false, + "readonly": true, + "type": "\"RULE_READ_FAILED\"" + }, + "TARGET_NOT_ON_RULE_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"TARGET_NOT_ON_RULE_CHAIN\"" + }, + "WALLET_BALANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"WALLET_BALANCE_INSUFFICIENT\"" + }, + "WALLET_NOT_DEPLOYED": { + "optional": false, + "readonly": true, + "type": "\"WALLET_NOT_DEPLOYED\"" + } + } + }, + "AgenticError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"CREATE_PARTIAL\" | \"DUPLICATE_RULE\" | \"FROM_NOT_ALLOWED\" | \"GATEWAY_ALLOWANCE_INSUFFICIENT\" | \"GENERATION_UNSUPPORTED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"REVOKE_NEEDS_TARGET\" | \"RULE_LIMIT_EXCEEDED\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"" + }, + "details": { + "optional": true, + "readonly": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "AgenticRevertError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticRevertError", + "members": { + "agenticCode": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + } + } + }, + "AgenticAddress": { + "type": "`0x${string}`", + "members": {} + }, + "AgenticDoor": { + "type": "\"agent\" | \"owner\"", + "members": {} + }, + "AgenticErrorCode": { + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"CREATE_PARTIAL\" | \"DUPLICATE_RULE\" | \"FROM_NOT_ALLOWED\" | \"GATEWAY_ALLOWANCE_INSUFFICIENT\" | \"GENERATION_UNSUPPORTED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"REVOKE_NEEDS_TARGET\" | \"RULE_LIMIT_EXCEEDED\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"", + "members": {} + }, + "AgenticHex": { + "type": "`0x${string}`", + "members": {} + }, + "AgenticNamespace": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace", + "members": { + "create": { + "optional": false, + "readonly": false, + "type": "(label: string, options: import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions) => Promise" + }, + "derive": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n index?: number;\n}) => Promise<{\n address: `0x${string}`;\n deployed: boolean;\n index: number;\n}>" + }, + "list": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n wallets: import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary[];\n}>" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "(address: `0x${string}`) => import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet" + } + } + }, + "AgenticNetworkConstants": { + "type": "import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants", + "members": { + "ENVELOPE_VERSION": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "FACTORY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "MAX_ALLOWED_CALLS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "MAX_PINS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "RULES_POLICY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticProgressHook": { + "type": "(event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void", + "members": {} + }, + "AgenticTxMetadata": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticTxMetadata", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destinationAccount": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "destinationCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "door": { + "optional": false, + "readonly": false, + "type": "\"agent\" | \"owner\"" + }, + "nativeCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "rawData": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rawTo": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesId": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticWallet": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "checkpoints": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n sinceBlock?: bigint;\n}) => Promise<{\n checkpoints: import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint[];\n}>" + }, + "info": { + "optional": false, + "readonly": false, + "type": "() => Promise" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n owner: `0x${string}`;\n}>" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "{\n add(rules: import(\"sdk/src/lib/agentic/agentic.types\").Rule[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise<{\n rulesIds: `0x${string}`[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n get(rulesId: `0x${string}`): Promise;\n list(): Promise<{\n rules: import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord[];\n }>;\n revoke(rulesIds: `0x${string}`[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n revoke(params: {\n all: true;\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n update(params: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n rules: {\n rule: import(\"sdk/src/lib/agentic/agentic.types\").Rule;\n rulesId: `0x${string}`;\n }[];\n }): Promise<{\n rules: {\n replaced: `0x${string}`;\n rulesId: `0x${string}`;\n }[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n}" + }, + "setLabel": { + "optional": false, + "readonly": false, + "type": "(label: string, opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n}) => Promise" + } + } + }, + "AllowedCall": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall", + "members": { + "beneficiary": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValue": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "`${string}(${string})` | `0x${string}`" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AssetCap": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap", + "members": { + "maxPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/constants/tokens\").MoveableToken" + } + } + }, + "Checkpoint": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint", + "members": { + "blockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "kind": { + "optional": false, + "readonly": false, + "type": "\"OWNER_ACTION\" | \"RULES_GRANTED\" | \"RULES_REVOKED\"" + }, + "ref": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "seq": { + "optional": false, + "readonly": false, + "type": "number" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "CheckpointKind": { + "type": "\"OWNER_ACTION\" | \"RULES_GRANTED\" | \"RULES_REVOKED\"", + "members": {} + }, + "CreateOptions": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions", + "members": { + "progressHook": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook | undefined" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Rule[]" + } + } + }, + "CreateResult": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateResult", + "members": { + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "rulesIds": { + "optional": false, + "readonly": false, + "type": "`0x${string}`[]" + }, + "tx": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ForeignChainNamespace": { + "type": "`eip155:${string}` | `solana:${string}`", + "members": {} + }, + "NativeRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "amount": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AmountLimit | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "maxCalls": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "maxValuePerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxValueTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "pins": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ArgPin[] | undefined" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Rule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule | import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "RulesRecord": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "enabled": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "ref": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "rule": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").NativeRule | import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule" + }, + "rulesId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Selector": { + "type": "`${string}(${string})` | `0x${string}`", + "members": {} + }, + "UniversalRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").UniversalRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AllowedCall[]" + }, + "assets": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AssetCap[]" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "`eip155:${string}` | `solana:${string}`" + }, + "maxGasPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "ref": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "WalletInfo": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").WalletInfo", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "label": { + "optional": false, + "readonly": false, + "type": "string" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "rulesCount": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "WalletSummary": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "label": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesCount": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "PushChain": { + "type": "import(\"sdk/src/lib/push-chain/push-chain\").PushChain", + "members": { + "accountStatus": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus" + }, + "accountStatusReady": { + "optional": false, + "readonly": false, + "type": "Promise" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace" + }, + "explorer": { + "optional": false, + "readonly": false, + "type": "{\n getTransactionUrl: (txHash: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n listAllUrls: () => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n listUrls: (options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n}" + }, + "funds": { + "optional": false, + "readonly": false, + "type": "{\n getConversionQuote: (amountIn: bigint, options: {\n from: import(\"sdk/src/lib/constants/tokens\").PayableToken | undefined;\n to: import(\"sdk/src/lib/constants/tokens\").MoveableToken | undefined;\n }) => Promise;\n}" + }, + "getAccountStatus": { + "optional": false, + "readonly": false, + "type": "(options?: {\n forceRefresh?: boolean;\n}) => Promise" + }, + "isReadMode": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "moveable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").MoveableTokenAccessor;\n}" + }, + "payable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").PayableTokenAccessor;\n}" + }, + "reinitialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "universal": { + "optional": false, + "readonly": false, + "type": "{\n readonly account: `0x${string}`;\n executeReads: (reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>;\n executeTransactions: (txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise;\n migrateCEA: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"migrateCEA\"];\n readonly origin: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n prepareRead: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n prepareTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"prepareTransaction\"];\n read: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n rescueFunds: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"rescueFunds\"];\n sendTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"execute\"];\n signMessage: (data: Uint8Array) => Promise;\n signTypedData: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n trackRead: {\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n };\n trackTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"trackTransaction\"];\n}" + }, + "upgradeAccount": { + "optional": false, + "readonly": false, + "type": "(options?: {\n progressHook?: (progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n}) => Promise" + } + } + } + }, + "pushChainStatic": { + "CONSTANTS": { + "optional": false, + "readonly": false, + "type": "{\n AGENTIC: Readonly>>;\n CHAIN: typeof import(\"sdk/src/lib/constants/enums\").CHAIN;\n LIBRARY: typeof import(\"sdk/src/lib/constants/enums\").LIBRARY;\n MOVEABLE: {\n TOKEN: import(\"sdk/src/lib/constants/tokens\").MoveableTokenConstantsMap;\n };\n PAYABLE: {\n TOKEN: import(\"sdk/src/lib/constants/tokens\").PayableTokenConstantsMap;\n };\n PUSH_NETWORK: typeof import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n READ: {\n readonly CALLBACK_BUDGET_BUFFER: 3;\n readonly CHAIN: {\n readonly WEB2: \"web2\";\n } & Readonly<{\n readonly ARBITRUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA;\n readonly BASE_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA;\n readonly BNB_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET;\n readonly ETHEREUM_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET;\n readonly ETHEREUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA;\n readonly PUSH_LOCALNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET;\n readonly PUSH_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET;\n readonly PUSH_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly PUSH_TESTNET_DONUT: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly SOLANA_DEVNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET;\n readonly SOLANA_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET;\n readonly SOLANA_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n readonly WEB2: \"web2\";\n }>;\n readonly DEFAULT_EXPIRY_BLOCKS: 300n;\n readonly ERROR_CODE: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n readonly MAX_CALLBACK_GAS_LIMIT: 1000000n;\n readonly MIN_CONFIRMATIONS_FLOOR: 1;\n readonly NAMESPACE: {\n readonly EVM: \"eip155\";\n readonly SVM: \"solana\";\n readonly WEB2: \"web2\";\n };\n readonly OUTCOME: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME;\n readonly REGISTRY_CALLBACK_GAS: 500000n;\n readonly RESULT_STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n readonly STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS;\n readonly UNIVERSAL_CALLBACK_ADDRESSES: Record;\n readonly UNIVERSAL_CORE_ADDRESSES: Record;\n readonly UNIVERSAL_READ_REGISTRY_ADDRESS: {\n readonly TESTNET_DONUT: \"0x00000000000000000000000000000000000000b2\";\n };\n readonly WEB2: \"web2\";\n readonly WEB2_DEFAULT_TIMEOUT_MS: 5000;\n readonly WEB2_MAX_EXTRACT_ENTRIES: 16;\n };\n}" + }, + "initialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "utils": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/utils\").Utils" + } + }, + "pushChainInstance": { + "accountStatus": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus" + }, + "accountStatusReady": { + "optional": false, + "readonly": false, + "type": "Promise" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace" + }, + "explorer": { + "optional": false, + "readonly": false, + "type": "{\n getTransactionUrl: (txHash: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n listAllUrls: () => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n listUrls: (options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n}" + }, + "funds": { + "optional": false, + "readonly": false, + "type": "{\n getConversionQuote: (amountIn: bigint, options: {\n from: import(\"sdk/src/lib/constants/tokens\").PayableToken | undefined;\n to: import(\"sdk/src/lib/constants/tokens\").MoveableToken | undefined;\n }) => Promise;\n}" + }, + "getAccountStatus": { + "optional": false, + "readonly": false, + "type": "(options?: {\n forceRefresh?: boolean;\n}) => Promise" + }, + "isReadMode": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "moveable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").MoveableTokenAccessor;\n}" + }, + "payable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").PayableTokenAccessor;\n}" + }, + "reinitialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "universal": { + "optional": false, + "readonly": false, + "type": "{\n readonly account: `0x${string}`;\n executeReads: (reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>;\n executeTransactions: (txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise;\n migrateCEA: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"migrateCEA\"];\n readonly origin: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n prepareRead: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n prepareTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"prepareTransaction\"];\n read: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n rescueFunds: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"rescueFunds\"];\n sendTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"execute\"];\n signMessage: (data: Uint8Array) => Promise;\n signTypedData: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n trackRead: {\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n };\n trackTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"trackTransaction\"];\n}" + }, + "upgradeAccount": { + "optional": false, + "readonly": false, + "type": "(options?: {\n progressHook?: (progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n}) => Promise" + } + }, + "transactionMethods": { + "account": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "executeReads": { + "optional": false, + "readonly": false, + "type": "(reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>" + }, + "executeTransactions": { + "optional": false, + "readonly": false, + "type": "(txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise" + }, + "migrateCEA": { + "optional": false, + "readonly": false, + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => Promise" + }, + "origin": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "prepareRead": { + "optional": false, + "readonly": false, + "type": "(subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>" + }, + "prepareTransaction": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions) => Promise" + }, + "read": { + "optional": false, + "readonly": false, + "type": "(subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>" + }, + "rescueFunds": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").RescueFundsParams) => Promise" + }, + "sendTransaction": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").ExecuteParams | import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions) => Promise" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": false, + "readonly": false, + "type": "({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise" + }, + "trackRead": { + "optional": false, + "readonly": false, + "type": "{\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n}" + }, + "trackTransaction": { + "optional": false, + "readonly": false, + "type": "(txHash: string, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TrackTransactionOptions) => Promise" + } + }, + "utilityMethods": { + "account": { + "optional": false, + "readonly": false, + "type": "{\n convertExecutorToOriginAccount: (ueaAddress: `0x${string}`, options?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n }) => Promise;\n convertOriginToExecutor: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n onlyCompute?: boolean;\n }) => Promise;\n deriveExecutorAccount: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n skipNetworkCheck?: boolean;\n }) => Promise;\n fromChainAgnostic: (caip: string) => import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n resolveControllerAccount: (address: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n skipNetworkCheck?: boolean;\n }) => Promise;\n toChainAgnostic: (address: string, options: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n toUniversal: (address: string, options: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n}" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "{\n actionId: (target: `0x${string}`, selector: \"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector) => `0x${string}`;\n configId: (wallet: `0x${string}`, rulesId: `0x${string}`, actionId: `0x${string}`) => `0x${string}`;\n decodeRules: (bytes: `0x${string}`, ctx?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n pushChainNamespace?: string;\n }) => import(\"sdk/src/lib/agentic/agentic.types\").Rule;\n}" + }, + "chains": { + "optional": false, + "readonly": false, + "type": "{\n getChainName: (chainNamespace: string) => string | undefined;\n getChainNamespace: (chainName: string) => string | undefined;\n getSupportedChains: (network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK) => {\n chains: import(\"sdk/src/lib/constants/enums\").CHAIN[];\n };\n getSupportedChainsByName: (network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK) => {\n chains: string[];\n };\n}" + }, + "conversion": { + "optional": false, + "readonly": false, + "type": "{\n slippageToMinAmount(amount: string, options: {\n slippageBps: number;\n }): string;\n}" + }, + "helpers": { + "optional": false, + "readonly": false, + "type": "{\n encodeTxData({ abi, idl, functionName, args, }: {\n abi?: any;\n args?: any[];\n functionName: string;\n idl?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n }): `0x${string}`;\n formatUnits(value: bigint | string, decimalsOrOptions: {\n decimals: number;\n precision?: number;\n } | number): string;\n getChainName: (chainName: string) => string | undefined;\n parseUnits(value: string, exponent: {\n decimals: number;\n } | number): bigint;\n}" + }, + "signer": { + "optional": false, + "readonly": false, + "type": "{\n construct: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options: {\n signAndSendTransaction: (unsignedTx: Uint8Array) => Promise;\n signAuthorization?: (params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise;\n signMessage: (data: Uint8Array) => Promise;\n signTypedData?: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n }) => import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton;\n toUniversal: (signer: import(\"sdk/src/lib/universal/universal.types\").EthersV5SignerType | import(\"sdk/src/lib/universal/universal.types\").EthersV6SignerType | import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton | import(\"sdk/src/lib/universal/universal.types\").ViemSignerType) => Promise;\n toUniversalFromKeypair: (clientOrAccount: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@solana/web3.js/lib/index\").Keypair | import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").WalletClient | import(\"sdk/src/lib/universal/universal.types\").EthersV6SignerType, { chain, library }: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n library: import(\"sdk/src/lib/constants/enums\").LIBRARY;\n }) => Promise;\n}" + }, + "svm": { + "optional": false, + "readonly": false, + "type": "{\n getRegisteredIdls: () => Array<{\n address: `0x${string}`;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n }>;\n registerIdl: (idl: unknown) => void;\n}" + }, + "tokens": { + "optional": false, + "readonly": false, + "type": "{\n getMoveableTokens(chainOrClient?: import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/push-chain/push-chain\").PushChain): {\n tokens: Array<{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n decimals: number;\n mechanism: \"approve\" | \"native\" | \"permit2\";\n prc20Address?: `0x${string}`;\n sourceChain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n symbol: string;\n }>;\n };\n getPayableTokens(chainOrClient?: import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/push-chain/push-chain\").PushChain): {\n tokens: Array<{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n decimals: number;\n mechanism: \"approve\" | \"native\" | \"permit2\";\n symbol: string;\n }>;\n };\n getPC20Address(address: string, options: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n rpcUrls?: Partial>;\n strict?: boolean;\n }): Promise;\n getPRC20Address(token: {\n address: string;\n chain: string;\n } | import(\"sdk/src/lib/constants/tokens\").MoveableToken, options?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n }): {\n address: `0x${string}`;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n decimals: number;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n symbol: string;\n };\n}" + } + }, + "initialize": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise", + "agwConstants": { + "ENVELOPE_VERSION": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "FACTORY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "MAX_ALLOWED_CALLS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "MAX_PINS": { + "optional": false, + "readonly": false, + "type": "number" + }, + "RULES_POLICY": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + }, + "constants": { + "AGENTIC": { + "optional": false, + "readonly": false, + "type": "{\n readonly LOCALNET?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n readonly MAINNET?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n readonly TESTNET?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n readonly TESTNET_DONUT?: import(\"sdk/src/lib/agentic/constants\").AgenticNetworkConstants | undefined;\n}" + }, + "CHAIN": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "LIBRARY": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").LIBRARY" + }, + "MOVEABLE": { + "optional": false, + "readonly": false, + "type": "{\n TOKEN: import(\"sdk/src/lib/constants/tokens\").MoveableTokenConstantsMap;\n}" + }, + "PAYABLE": { + "optional": false, + "readonly": false, + "type": "{\n TOKEN: import(\"sdk/src/lib/constants/tokens\").PayableTokenConstantsMap;\n}" + }, + "PUSH_NETWORK": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "READ": { + "optional": false, + "readonly": false, + "type": "{\n readonly CALLBACK_BUDGET_BUFFER: 3;\n readonly CHAIN: {\n readonly WEB2: \"web2\";\n } & Readonly<{\n readonly ARBITRUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA;\n readonly BASE_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA;\n readonly BNB_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET;\n readonly ETHEREUM_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET;\n readonly ETHEREUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA;\n readonly PUSH_LOCALNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET;\n readonly PUSH_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET;\n readonly PUSH_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly PUSH_TESTNET_DONUT: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly SOLANA_DEVNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET;\n readonly SOLANA_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET;\n readonly SOLANA_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n readonly WEB2: \"web2\";\n }>;\n readonly DEFAULT_EXPIRY_BLOCKS: 300n;\n readonly ERROR_CODE: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n readonly MAX_CALLBACK_GAS_LIMIT: 1000000n;\n readonly MIN_CONFIRMATIONS_FLOOR: 1;\n readonly NAMESPACE: {\n readonly EVM: \"eip155\";\n readonly SVM: \"solana\";\n readonly WEB2: \"web2\";\n };\n readonly OUTCOME: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME;\n readonly REGISTRY_CALLBACK_GAS: 500000n;\n readonly RESULT_STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n readonly STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS;\n readonly UNIVERSAL_CALLBACK_ADDRESSES: Record;\n readonly UNIVERSAL_CORE_ADDRESSES: Record;\n readonly UNIVERSAL_READ_REGISTRY_ADDRESS: {\n readonly TESTNET_DONUT: \"0x00000000000000000000000000000000000000b2\";\n };\n readonly WEB2: \"web2\";\n readonly WEB2_DEFAULT_TIMEOUT_MS: 5000;\n readonly WEB2_MAX_EXTRACT_ENTRIES: 16;\n}" + } + } + }, + "after": { + "exports": [ + "AGENTIC_ERROR_CODE", + "AccountRole", + "AccountStatus", + "AccountType", + "AgentCard", + "AgentCardInput", + "AgentCardRules", + "AgentCardSummary", + "AgenticAddress", + "AgenticDoor", + "AgenticError", + "AgenticErrorCode", + "AgenticHex", + "AgenticNamespace", + "AgenticPresets", + "AgenticProgressHook", + "AgenticRevertError", + "AgenticTxMetadata", + "AgenticWallet", + "AllowedCall", + "AllowedMutability", + "ArgumentPath", + "AssetCap", + "BatchReadResponse", + "BuildJobSpecOptions", + "BuildJobSpecTemplateOptions", + "BuildReadSpecParams", + "CHAIN", + "CONTRACT_REQUEST_STATUS", + "CascadeCompletionResult", + "CascadeHopInfo", + "CascadeProgressEvent", + "CascadeTrackOptions", + "CascadedTxResponse", + "ChainSource", + "ChainTarget", + "Checkpoint", + "CheckpointKind", + "ConversionQuote", + "CreateJobOptions", + "CreateOptions", + "CreateResult", + "DEFAULT_MAX_PC_FOR_GAS_BUFFER_BPS", + "DecodedErrorPayload", + "DecodedReadResult", + "DecodedSolanaRule", + "DerivedExecutorAccount", + "EncodedReadQuery", + "Evaluation", + "EvmReadQuery", + "ForeignChainNamespace", + "FulfilOutcome", + "FundJobOptions", + "FundsToken", + "InsufficientPC20BalanceError", + "InvalidPC20AddressError", + "InvalidPC20MetadataError", + "InvalidReadQueryError", + "InvalidReadSpecError", + "Job", + "JobCheck", + "JobCheckTemplate", + "JobError", + "JobEvent", + "JobNamespace", + "JobPlan", + "JobRead", + "JobReadInput", + "JobSpec", + "JobSpecError", + "JobSpecPreview", + "JobSpecTemplate", + "JobStatus", + "LogicKind", + "LogicTree", + "MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT", + "MarketAssetToken", + "MarketDepositOptions", + "MarketDepositResult", + "MarketDepositStep", + "MarketError", + "MarketNamespace", + "MarketPin", + "MarketPreviewOptions", + "MarketWriteOptions", + "MaxPCForGasCapFromNativeValueInput", + "MaxPCForGasCapInput", + "MaxPCForGasCapQuote", + "MultiChainTxResponse", + "Operation", + "OutboundTxDetails", + "OwnerIntent", + "PC20AddressResult", + "PC20AmbiguousAddressError", + "PC20Error", + "PC20ExpectedButPRC20Error", + "PC20ExportRevertedError", + "PC20FactoryMismatchError", + "PC20RegistryEntry", + "PC20RegistryMismatchError", + "PC20TokenChainMismatchError", + "PC20TokenReference", + "PC20UnknownChainNamespaceError", + "PC20UnsafeEmptyPayloadError", + "PC20WrapperNotRegisteredError", + "PC20WrapperPredictionUnavailableError", + "ParsedReadRequest", + "Pin", + "PrepareJobReadOptions", + "PreparedJobRead", + "PreparedRead", + "PreparedUniversalTx", + "Preset", + "PresetAsset", + "PresetCallIssue", + "PresetCategory", + "PresetChainReadiness", + "PresetConfigurationIssue", + "PresetOptions", + "PresetResult", + "PresetRuleTemplate", + "PreviewJobSpecOptions", + "PrincipalMarker", + "PushChain", + "PushChainBatchExecutionError", + "PushChainExecutionError", + "PushChainInitializeOptions", + "READ_ERROR_CODE", + "READ_OUTCOME", + "READ_STATUS", + "ReadCallback", + "ReadCallbackOptions", + "ReadChain", + "ReadDecodeError", + "ReadDestination", + "ReadExecuteOptions", + "ReadFees", + "ReadHeightUnavailableError", + "ReadLifecycleOptions", + "ReadNotFoundError", + "ReadOptions", + "ReadPreflight", + "ReadPrepareOptions", + "ReadQuery", + "ReadQueryOptions", + "ReadRef", + "ReadRegistryUnavailableError", + "ReadResponseTuple", + "ReadResultShape", + "ReadSpec", + "ReadSpecTuple", + "ReadSpecViolation", + "ReadStateError", + "ReadTimeoutError", + "ReadTrackOptions", + "ReadValue", + "ReadWeb2Options", + "ReadyPresetOptions", + "ReceiptLike", + "RescueFundsParams", + "ResolvedAccount", + "ResolvedControllerAccounts", + "ResolvedDestination", + "Rule", + "RuleInput", + "RulesRecord", + "Selector", + "SignAuthorizationParams", + "SignedAuthorization", + "SimulateReadResult", + "Spent", + "SvmExecutePayloadFields", + "SvmGatewayAccountMeta", + "SvmReadQuery", + "TERMINAL_READ_STATUSES", + "TransactionRoute", + "TransactionRouteType", + "UEAStatus", + "UNIVERSAL_CALLBACK_EVM", + "UNIVERSAL_READ_REGISTRY_EVM", + "UNIVERSAL_READ_STATUS", + "UniversalAccount", + "UniversalExecuteParams", + "UniversalOutboundTxRequest", + "UniversalReadResponse", + "UniversalSigner", + "UniversalSignerSkeleton", + "UniversalTo", + "UnsupportedPC20DestinationError", + "UnsupportedReadDestinationError", + "ValidateReadCall", + "WaitForOutboundOptions", + "WalletInfo", + "WalletMarker", + "WalletSummary", + "Web2Extract", + "Web2ReadQuery", + "Web2ValueType", + "buildErc20WithdrawalMulticall", + "buildMigrationPayload", + "buildReadSpecFromPreflight", + "chainSupportsCEA", + "chainSupportsOutbound", + "decodeReadResult", + "detectRoute", + "encodeReadQuery", + "encodeSvmExecutePayload", + "getAllCEAAddresses", + "getCEAAddress", + "getCEAFactoryAddress", + "getPushAccountForCEA", + "inferResultShape", + "isCEA", + "isChainTarget", + "isPC20Reference", + "isSvmChain", + "isValidSolanaHexAddress", + "parseFulfilOutcome", + "parseReadRequestsFromReceipt", + "parseUEAVersion", + "quoteMaxPCForGasCap", + "quoteMaxPCForGasCapFromNativeValue", + "resolveDestination", + "sizeCallbackBudget", + "toCallData", + "toReadQuery", + "toRequestIdHex", + "validateReadSpec" + ], + "agw": { + "AgenticNamespace": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace", + "members": { + "create": { + "optional": false, + "readonly": false, + "type": "(label: string, options: import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions) => Promise" + }, + "derive": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n index?: number;\n}) => Promise<{\n address: `0x${string}`;\n deployed: boolean;\n index: number;\n}>" + }, + "list": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n wallets: import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary[];\n}>" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "(address: `0x${string}`) => import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet" + } + } + }, + "AgenticWallet": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "checkpoints": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n sinceBlock?: bigint;\n}) => Promise<{\n checkpoints: import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint[];\n}>" + }, + "info": { + "optional": false, + "readonly": false, + "type": "() => Promise" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n owner: `0x${string}`;\n}>" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "{\n add(rules: import(\"sdk/src/lib/agentic/agentic.types\").RuleInput[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise<{\n rulesIds: `0x${string}`[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n delete(rulesIds: `0x${string}`[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n delete(params: {\n all: true;\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n get(rulesId: `0x${string}`): Promise;\n list(): Promise<{\n rules: import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord[];\n }>;\n update(params: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n rules: {\n rule: import(\"sdk/src/lib/agentic/agentic.types\").RuleInput;\n rulesId: `0x${string}`;\n }[];\n }): Promise<{\n rules: {\n replaced: `0x${string}`;\n rulesId: `0x${string}`;\n }[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n}" + }, + "setLabel": { + "optional": false, + "readonly": false, + "type": "(label: string, opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n}) => Promise" + } + } + }, + "AgenticError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "Code" + }, + "details": { + "optional": true, + "readonly": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "userMessage": { + "optional": false, + "readonly": true, + "type": "string" + } + } + }, + "AgenticRevertError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticRevertError", + "members": { + "agenticCode": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "userMessage": { + "optional": false, + "readonly": true, + "type": "string" + } + } + }, + "AGENTIC_ERROR_CODE": { + "type": "{\n readonly AGENT_GAS_INSUFFICIENT: \"AGENT_GAS_INSUFFICIENT\";\n readonly AGENT_IS_OWNER: \"AGENT_IS_OWNER\";\n readonly AMBIGUOUS_RULE: \"AMBIGUOUS_RULE\";\n readonly ASSET_CHAIN_MISMATCH: \"ASSET_CHAIN_MISMATCH\";\n readonly CAPABILITY_UNAVAILABLE: \"CAPABILITY_UNAVAILABLE\";\n readonly DELETE_NEEDS_TARGET: \"DELETE_NEEDS_TARGET\";\n readonly DUPLICATE_RULE: \"DUPLICATE_RULE\";\n readonly FROM_NOT_ALLOWED: \"FROM_NOT_ALLOWED\";\n readonly INCONSISTENT_READ: \"INCONSISTENT_READ\";\n readonly INDEX_RACE: \"INDEX_RACE\";\n readonly INVALID_RULE: \"INVALID_RULE\";\n readonly NO_RULES_FOR_CHAIN: \"NO_RULES_FOR_CHAIN\";\n readonly NOT_AGENTIC_WALLET: \"NOT_AGENTIC_WALLET\";\n readonly NOT_ALLOWED_IN_AGENTIC_MODE: \"NOT_ALLOWED_IN_AGENTIC_MODE\";\n readonly NOT_OWNER_OR_AGENT: \"NOT_OWNER_OR_AGENT\";\n readonly NOT_WALLET_OWNER: \"NOT_WALLET_OWNER\";\n readonly READ_ONLY: \"READ_ONLY\";\n readonly RECEIPT_MISMATCH: \"RECEIPT_MISMATCH\";\n readonly RECEIPT_UNAVAILABLE: \"RECEIPT_UNAVAILABLE\";\n readonly REQUEST_REJECTED: \"REQUEST_REJECTED\";\n readonly RULE_NOT_FOUND: \"RULE_NOT_FOUND\";\n readonly RULE_READ_FAILED: \"RULE_READ_FAILED\";\n readonly TARGET_NOT_ON_RULE_CHAIN: \"TARGET_NOT_ON_RULE_CHAIN\";\n readonly TOKEN_ROUTE_UNAVAILABLE: \"TOKEN_ROUTE_UNAVAILABLE\";\n readonly WALLET_BALANCE_INSUFFICIENT: \"WALLET_BALANCE_INSUFFICIENT\";\n readonly WALLET_NOT_DEPLOYED: \"WALLET_NOT_DEPLOYED\";\n}", + "members": { + "AGENT_GAS_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\"" + }, + "AGENT_IS_OWNER": { + "optional": false, + "readonly": true, + "type": "\"AGENT_IS_OWNER\"" + }, + "AMBIGUOUS_RULE": { + "optional": false, + "readonly": true, + "type": "\"AMBIGUOUS_RULE\"" + }, + "ASSET_CHAIN_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"ASSET_CHAIN_MISMATCH\"" + }, + "CAPABILITY_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"CAPABILITY_UNAVAILABLE\"" + }, + "DELETE_NEEDS_TARGET": { + "optional": false, + "readonly": true, + "type": "\"DELETE_NEEDS_TARGET\"" + }, + "DUPLICATE_RULE": { + "optional": false, + "readonly": true, + "type": "\"DUPLICATE_RULE\"" + }, + "FROM_NOT_ALLOWED": { + "optional": false, + "readonly": true, + "type": "\"FROM_NOT_ALLOWED\"" + }, + "INCONSISTENT_READ": { + "optional": false, + "readonly": true, + "type": "\"INCONSISTENT_READ\"" + }, + "INDEX_RACE": { + "optional": false, + "readonly": true, + "type": "\"INDEX_RACE\"" + }, + "INVALID_RULE": { + "optional": false, + "readonly": true, + "type": "\"INVALID_RULE\"" + }, + "NO_RULES_FOR_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"NO_RULES_FOR_CHAIN\"" + }, + "NOT_AGENTIC_WALLET": { + "optional": false, + "readonly": true, + "type": "\"NOT_AGENTIC_WALLET\"" + }, + "NOT_ALLOWED_IN_AGENTIC_MODE": { + "optional": false, + "readonly": true, + "type": "\"NOT_ALLOWED_IN_AGENTIC_MODE\"" + }, + "NOT_OWNER_OR_AGENT": { + "optional": false, + "readonly": true, + "type": "\"NOT_OWNER_OR_AGENT\"" + }, + "NOT_WALLET_OWNER": { + "optional": false, + "readonly": true, + "type": "\"NOT_WALLET_OWNER\"" + }, + "READ_ONLY": { + "optional": false, + "readonly": true, + "type": "\"READ_ONLY\"" + }, + "RECEIPT_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_MISMATCH\"" + }, + "RECEIPT_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_UNAVAILABLE\"" + }, + "REQUEST_REJECTED": { + "optional": false, + "readonly": true, + "type": "\"REQUEST_REJECTED\"" + }, + "RULE_NOT_FOUND": { + "optional": false, + "readonly": true, + "type": "\"RULE_NOT_FOUND\"" + }, + "RULE_READ_FAILED": { + "optional": false, + "readonly": true, + "type": "\"RULE_READ_FAILED\"" + }, + "TARGET_NOT_ON_RULE_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"TARGET_NOT_ON_RULE_CHAIN\"" + }, + "TOKEN_ROUTE_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"TOKEN_ROUTE_UNAVAILABLE\"" + }, + "WALLET_BALANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"WALLET_BALANCE_INSUFFICIENT\"" + }, + "WALLET_NOT_DEPLOYED": { + "optional": false, + "readonly": true, + "type": "\"WALLET_NOT_DEPLOYED\"" + } + } + }, + "Rule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Rule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleCall[]" + }, + "assets": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset[] | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "maxGasPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "RuleInput": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").DecodedSolanaRule | import(\"sdk/src/lib/agentic/agentic.types\").Rule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "assets": { + "optional": true, + "readonly": false, + "type": "{\n maxPerCall: bigint;\n maxTotal: bigint;\n token: string;\n}[] | import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset[] | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "maxGasPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Pin": { + "type": "{\n account: number;\n arg?: never;\n expected: \"agentic:wallet\" | string;\n max?: never;\n token?: import(\"sdk/src/lib/constants/tokens\").MoveableToken | string;\n} | {\n account?: never;\n arg: import(\"sdk/src/lib/agentic/agentic.types\").ArgumentPath;\n expected: \"agentic:wallet\" | `0x${string}` | `0x${string}` | bigint;\n max?: never;\n} | {\n account?: never;\n arg: import(\"sdk/src/lib/agentic/agentic.types\").ArgumentPath;\n expected?: never;\n max: bigint;\n}", + "members": { + "account": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "arg": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ArgumentPath | undefined" + }, + "expected": { + "optional": true, + "readonly": false, + "type": "bigint | string | undefined" + }, + "max": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "Spent": { + "type": "{\n actions: {\n amountSpent: bigint;\n callsUsed: number;\n selector: \"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector;\n target: `0x${string}`;\n valueSpent: bigint;\n }[];\n kind: \"native\";\n} | {\n amountSpent: bigint;\n callsUsed: number;\n kind: \"native\";\n valueSpent: bigint;\n} | {\n assets: {\n spent: bigint;\n token: string;\n }[];\n kind: \"universal\";\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"native\" | \"universal\"" + } + } + }, + "AssetCap": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset", + "members": { + "maxPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/tokens\").MoveableToken | string" + } + } + }, + "AllowedCall": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleCall", + "members": { + "app": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "label": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "maxValue": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "pins": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Pin[] | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector" + }, + "target": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "RulesRecord": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "enabled": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "rule": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").DecodedSolanaRule | import(\"sdk/src/lib/agentic/agentic.types\").Rule" + }, + "rulesId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "spent": { + "optional": false, + "readonly": false, + "type": "{\n actions: {\n amountSpent: bigint;\n callsUsed: number;\n selector: \"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector;\n target: `0x${string}`;\n valueSpent: bigint;\n }[];\n kind: \"native\";\n} | {\n amountSpent: bigint;\n callsUsed: number;\n kind: \"native\";\n valueSpent: bigint;\n} | {\n assets: {\n spent: bigint;\n token: string;\n }[];\n kind: \"universal\";\n}" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "CreateOptions": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions", + "members": { + "progressHook": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook | undefined" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleInput[]" + } + } + }, + "CreateResult": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateResult", + "members": { + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "rulesIds": { + "optional": false, + "readonly": false, + "type": "`0x${string}`[]" + }, + "tx": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticTxMetadata": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticTxMetadata", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destinationAccount": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "destinationCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "destinationInstruction": { + "optional": true, + "readonly": false, + "type": "{\n accounts: readonly {\n isWritable: boolean;\n pubkey: `0x${string}`;\n }[];\n data: `0x${string}`;\n program: `0x${string}`;\n} | undefined" + }, + "destinationTransfer": { + "optional": true, + "readonly": false, + "type": "{\n amount: bigint;\n recipient: `0x${string}`;\n token: `0x${string}`;\n} | undefined" + }, + "door": { + "optional": false, + "readonly": false, + "type": "\"agent\" | \"owner\"" + }, + "nativeCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "rawData": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rawTo": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesId": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + } + }, + "publicSurface": { + "MarketError": { + "type": "import(\"sdk/src/lib/market/errors\").MarketError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "details": { + "optional": true, + "readonly": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "userMessage": { + "optional": false, + "readonly": true, + "type": "string" + } + } + }, + "JobError": { + "type": "import(\"sdk/src/lib/market/errors\").JobError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "details": { + "optional": true, + "readonly": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "userMessage": { + "optional": false, + "readonly": true, + "type": "string" + } + } + }, + "JobSpecError": { + "type": "import(\"sdk/src/lib/market/errors\").JobSpecError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "details": { + "optional": true, + "readonly": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "userMessage": { + "optional": false, + "readonly": true, + "type": "string" + } + } + }, + "AgentCardRules": { + "type": "import(\"sdk/src/lib/market/rules\").AgentCardRules", + "members": { + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "{\n maxValue?: bigint;\n pins?: import(\"sdk/src/lib/market/rules\").MarketPin[];\n selector: string;\n target: `0x${string}`;\n}[]" + }, + "assets": { + "optional": false, + "readonly": false, + "type": "{\n maxPerCall: \"agentic:principal\" | bigint;\n maxTotal?: \"agentic:principal\" | bigint;\n token: import(\"sdk/src/lib/market/rules\").MarketAssetToken;\n}[]" + }, + "maxGasPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "principalAsset": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "MarketAssetToken": { + "type": "{\n prc20: `0x${string}`;\n} | import(\"sdk/src/lib/constants/tokens\").MoveableToken | string", + "members": {} + }, + "MarketPin": { + "type": "{\n arg: import(\"sdk/src/lib/agentic/agentic.types\").ArgumentPath;\n expected: \"agentic:principal\" | \"agentic:wallet\" | `0x${string}` | `0x${string}` | bigint | boolean;\n max?: never;\n} | {\n arg: import(\"sdk/src/lib/agentic/agentic.types\").ArgumentPath;\n expected?: never;\n max: \"agentic:principal\" | bigint;\n}", + "members": { + "arg": { + "optional": false, + "readonly": false, + "type": "number | readonly number[]" + }, + "expected": { + "optional": true, + "readonly": false, + "type": "\"agentic:principal\" | \"agentic:wallet\" | `0x${string}` | bigint | boolean | undefined" + }, + "max": { + "optional": true, + "readonly": false, + "type": "\"agentic:principal\" | bigint | undefined" + } + } + }, + "AgentCard": { + "type": "import(\"sdk/src/lib/market/types\").AgentCard", + "members": { + "active": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "cardId": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "string" + }, + "disabled": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "jobSpecTemplate": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/job-spec/types\").JobSpecTemplate" + }, + "jobSpecTemplateBytes": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "jobType": { + "optional": false, + "readonly": false, + "type": "string" + }, + "maxDuration": { + "optional": false, + "readonly": false, + "type": "number" + }, + "metadataHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "metadataURI": { + "optional": false, + "readonly": false, + "type": "string" + }, + "minDuration": { + "optional": false, + "readonly": false, + "type": "number" + }, + "minExecuteWindow": { + "optional": false, + "readonly": false, + "type": "number" + }, + "paymentToken": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "principalMax": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "principalMin": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "provider": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "providerFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "rating": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/market/rules\").AgentCardRules" + }, + "rulesBytes": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "settleWindow": { + "optional": false, + "readonly": false, + "type": "number" + }, + "verified": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "version": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "AgentCardInput": { + "type": "import(\"sdk/src/lib/market/types\").AgentCardInput", + "members": { + "chain": { + "optional": false, + "readonly": false, + "type": "string" + }, + "jobType": { + "optional": false, + "readonly": false, + "type": "string" + }, + "maxDuration": { + "optional": false, + "readonly": false, + "type": "number" + }, + "metadataHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "metadataURI": { + "optional": false, + "readonly": false, + "type": "string" + }, + "minDuration": { + "optional": false, + "readonly": false, + "type": "number" + }, + "minExecuteWindow": { + "optional": false, + "readonly": false, + "type": "number" + }, + "paymentToken": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "principalMax": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "principalMin": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "providerFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "settleWindow": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "AgentCardSummary": { + "type": "{\n active: boolean;\n cardId: bigint;\n chain: string;\n disabled: boolean;\n jobType: string;\n maxDuration: number;\n metadataHash: `0x${string}`;\n metadataURI: string;\n minDuration: number;\n minExecuteWindow: number;\n paymentToken: `0x${string}`;\n principalMax: bigint;\n principalMin: bigint;\n provider: `0x${string}`;\n providerFee: bigint;\n rating: bigint;\n settleWindow: number;\n verified: boolean;\n version: bigint;\n}", + "members": { + "active": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "cardId": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "string" + }, + "disabled": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "jobType": { + "optional": false, + "readonly": false, + "type": "string" + }, + "maxDuration": { + "optional": false, + "readonly": false, + "type": "number" + }, + "metadataHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "metadataURI": { + "optional": false, + "readonly": false, + "type": "string" + }, + "minDuration": { + "optional": false, + "readonly": false, + "type": "number" + }, + "minExecuteWindow": { + "optional": false, + "readonly": false, + "type": "number" + }, + "paymentToken": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "principalMax": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "principalMin": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "provider": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "providerFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "rating": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "settleWindow": { + "optional": false, + "readonly": false, + "type": "number" + }, + "verified": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "version": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "MarketNamespace": { + "type": "import(\"sdk/src/lib/market/types\").MarketNamespace", + "members": { + "activeJob": { + "optional": false, + "readonly": false, + "type": "(wallet: `0x${string}`) => Promise<{\n jobId: bigint;\n}>" + }, + "agent": { + "optional": false, + "readonly": false, + "type": "{\n card(): Promise;\n register(card: import(\"sdk/src/lib/market/types\").AgentCardInput, options: {\n jobSpecTemplate: import(\"sdk/src/lib/job-spec/types\").JobSpecTemplate;\n rules: import(\"sdk/src/lib/market/rules\").AgentCardRules;\n } & import(\"sdk/src/lib/market/types\").MarketWriteOptions): Promise<{\n cardId: bigint;\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n version: bigint;\n }>;\n setActive(cardId: bigint, active: boolean, options?: import(\"sdk/src/lib/market/types\").MarketWriteOptions): Promise;\n update(cardId: bigint, card: import(\"sdk/src/lib/market/types\").AgentCardInput, options: {\n jobSpecTemplate: import(\"sdk/src/lib/job-spec/types\").JobSpecTemplate;\n rules: import(\"sdk/src/lib/market/rules\").AgentCardRules;\n } & import(\"sdk/src/lib/market/types\").MarketWriteOptions): Promise<{\n cardId: bigint;\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n version: bigint;\n }>;\n}" + }, + "card": { + "optional": false, + "readonly": false, + "type": "(cardId: bigint) => Promise" + }, + "cards": { + "optional": false, + "readonly": false, + "type": "(options?: {\n active?: boolean;\n chain?: string;\n provider?: `0x${string}`;\n}) => Promise<{\n cards: import(\"sdk/src/lib/market/types\").AgentCardSummary[];\n}>" + }, + "deposit": { + "optional": false, + "readonly": false, + "type": "(jobId: bigint, options?: import(\"sdk/src/lib/market/types\").MarketDepositOptions) => Promise" + }, + "job": { + "optional": false, + "readonly": false, + "type": "(jobId: bigint) => Promise<{\n cardId: bigint;\n cardVersion: bigint;\n rulesId: `0x${string}`;\n wallet: `0x${string}`;\n}>" + }, + "openJob": { + "optional": false, + "readonly": false, + "type": "(plan: import(\"sdk/src/lib/market/types\").JobPlan, options?: {\n relay?: boolean;\n} & import(\"sdk/src/lib/market/types\").MarketWriteOptions) => Promise<{\n jobId: bigint;\n rulesId: `0x${string}`;\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n wallet: `0x${string}`;\n}>" + }, + "preview": { + "optional": false, + "readonly": false, + "type": "(cardId: bigint, options: import(\"sdk/src/lib/market/types\").MarketPreviewOptions) => Promise" + } + } + }, + "MarketPreviewOptions": { + "type": "import(\"sdk/src/lib/market/types\").MarketPreviewOptions", + "members": { + "deadline": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "executeBy": { + "optional": false, + "readonly": false, + "type": "number" + }, + "expiredAt": { + "optional": false, + "readonly": false, + "type": "number" + }, + "label": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "params": { + "optional": true, + "readonly": false, + "type": "bigint[] | undefined" + }, + "principal": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "walletIndex": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "MarketWriteOptions": { + "type": "import(\"sdk/src/lib/market/types\").MarketWriteOptions", + "members": { + "progressHook": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/market/runtime\").StackProgressHook | undefined" + } + } + }, + "MarketDepositOptions": { + "type": "import(\"sdk/src/lib/market/types\").MarketDepositOptions", + "members": { + "funding": { + "optional": true, + "readonly": false, + "type": "\"origin\" | \"push\" | undefined" + }, + "pcAmount": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/market/runtime\").StackProgressHook | undefined" + }, + "providerFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "resume": { + "optional": true, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/market/types\").MarketDepositStep[] | undefined" + } + } + }, + "MarketDepositResult": { + "type": "import(\"sdk/src/lib/market/types\").MarketDepositResult", + "members": { + "cardId": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "cardVersion": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "jobId": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pending": { + "optional": true, + "readonly": false, + "type": "({\n chain: string;\n txHash: string;\n} & Omit) | undefined" + }, + "txs": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/market/types\").MarketDepositStep[]" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "MarketDepositStep": { + "type": "import(\"sdk/src/lib/market/types\").MarketDepositStep", + "members": { + "amount": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "step": { + "optional": false, + "readonly": false, + "type": "\"PC\" | \"PRINCIPAL_AND_FEE\" | \"PRINCIPAL\" | \"PROVIDER_FEE\"" + }, + "token": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "tx": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + } + } + }, + "JobPlan": { + "type": "import(\"sdk/src/lib/market/types\").JobPlan", + "members": { + "calldata": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "cardId": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "cardVersion": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "deposit": { + "optional": false, + "readonly": false, + "type": "{\n pc: bigint;\n principal: {\n amount: bigint;\n prc20: `0x${string}`;\n };\n providerFee: {\n amount: bigint;\n token: `0x${string}`;\n };\n}" + }, + "intent": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/market/types\").OwnerIntent" + }, + "job": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/market/types\").MarketJobInputs" + }, + "jobSpec": { + "optional": false, + "readonly": false, + "type": "{\n bytes: `0x${string}`;\n spec: import(\"sdk/src/lib/job-spec/types\").JobSpec;\n}" + }, + "label": { + "optional": false, + "readonly": false, + "type": "string" + }, + "preview": { + "optional": false, + "readonly": false, + "type": "{\n judgedBy: string[];\n mayDo: string[];\n mayMove: string[];\n until: string;\n}" + }, + "session": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/codec/session\").SessionWire" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "walletDeployed": { + "optional": false, + "readonly": false, + "type": "boolean" + } + } + }, + "OwnerIntent": { + "type": "import(\"sdk/src/lib/market/types\").OwnerIntent", + "members": { + "deadline": { + "optional": false, + "readonly": false, + "type": "number" + }, + "execCalldataHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "executor": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "grantNonce": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "index": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "mode": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "nonceKey": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "nonceSeq": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "sessionHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "signerChainId": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "JobNamespace": { + "type": "import(\"sdk/src/lib/job/types\").JobNamespace", + "members": { + "cancel": { + "optional": false, + "readonly": false, + "type": "(jobId: bigint, options?: import(\"sdk/src/lib/job/types\").JobWriteOptions) => Promise" + }, + "claimRefund": { + "optional": false, + "readonly": false, + "type": "(jobId: bigint, options?: import(\"sdk/src/lib/job/types\").JobWriteOptions) => Promise" + }, + "create": { + "optional": false, + "readonly": false, + "type": "(options: import(\"sdk/src/lib/job/types\").CreateJobOptions) => Promise<{\n jobId: bigint;\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n}>" + }, + "fund": { + "optional": false, + "readonly": false, + "type": "(jobId: bigint, options?: import(\"sdk/src/lib/job/types\").FundJobOptions) => Promise" + }, + "list": { + "optional": false, + "readonly": false, + "type": "(options?: {\n client?: `0x${string}`;\n fromJobId?: bigint;\n provider?: `0x${string}`;\n status?: import(\"sdk/src/lib/job/types\").JobStatus;\n}) => Promise<{\n jobs: import(\"sdk/src/lib/job/types\").Job[];\n}>" + }, + "setBudget": { + "optional": false, + "readonly": false, + "type": "(jobId: bigint, amount: bigint, options?: {\n jobSpec?: `0x${string}`;\n} & import(\"sdk/src/lib/job/types\").JobWriteOptions) => Promise" + }, + "status": { + "optional": false, + "readonly": false, + "type": "(jobId: bigint) => Promise" + }, + "submit": { + "optional": false, + "readonly": false, + "type": "(jobId: bigint, options: {\n deliverable: `0x${string}` | string;\n} & import(\"sdk/src/lib/job/types\").JobWriteOptions) => Promise" + }, + "verify": { + "optional": false, + "readonly": false, + "type": "(jobId: bigint, options?: import(\"sdk/src/lib/job/types\").JobWriteOptions) => Promise" + }, + "watch": { + "optional": false, + "readonly": false, + "type": "(jobId: bigint, callback: (event: import(\"sdk/src/lib/job/types\").JobEvent) => void, options?: {\n fromBlock?: bigint;\n pollIntervalMs?: number;\n}) => () => void" + } + } + }, + "Job": { + "type": "import(\"sdk/src/lib/job/types\").Job", + "members": { + "budget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "client": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deliverable": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "description": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "evaluation": { + "optional": false, + "readonly": false, + "type": "{\n available: false;\n reason: \"MANUAL_EVALUATOR\" | \"UNVERIFIED_EVALUATOR\";\n}" + }, + "evaluator": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "expiredAt": { + "optional": false, + "readonly": false, + "type": "number" + }, + "hook": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "jobId": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "jobSpec": { + "optional": true, + "readonly": false, + "type": "{\n bytes: `0x${string}`;\n frozen?: boolean;\n spec: import(\"sdk/src/lib/job-spec/types\").JobSpec;\n} | undefined" + }, + "jobSpecDecodeError": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "paymentToken": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "provider": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "rulesId": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "status": { + "optional": false, + "readonly": false, + "type": "\"Completed\" | \"Expired\" | \"Funded\" | \"Open\" | \"Rejected\" | \"Submitted\"" + } + } + }, + "JobStatus": { + "type": "\"Completed\" | \"Expired\" | \"Funded\" | \"Open\" | \"Rejected\" | \"Submitted\"", + "members": {} + }, + "JobEvent": { + "type": "import(\"sdk/src/lib/job/types\").JobEvent", + "members": { + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "data": { + "optional": true, + "readonly": false, + "type": "unknown" + }, + "error": { + "optional": true, + "readonly": false, + "type": "unknown" + }, + "jobId": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "kind": { + "optional": false, + "readonly": false, + "type": "string" + }, + "txHash": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "CreateJobOptions": { + "type": "import(\"sdk/src/lib/job/types\").CreateJobOptions", + "members": { + "description": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "evaluator": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "expiredAt": { + "optional": false, + "readonly": false, + "type": "number" + }, + "hook": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "jobSpec": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "paymentToken": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/market/runtime\").StackProgressHook | undefined" + }, + "provider": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "FundJobOptions": { + "type": "import(\"sdk/src/lib/job/types\").FundJobOptions", + "members": { + "expectedBudget": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/market/runtime\").StackProgressHook | undefined" + }, + "rulesId": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "JobSpec": { + "type": "import(\"sdk/src/lib/job-spec/types\").JobSpec", + "members": { + "allowedMutability": { + "optional": false, + "readonly": false, + "type": "\"BOTH\" | \"CLIENT\" | \"NONE\" | \"PROVIDER\"" + }, + "checks": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/job-spec/types\").JobCheck[]" + }, + "executeBy": { + "optional": false, + "readonly": false, + "type": "number" + }, + "failFinalAt": { + "optional": false, + "readonly": false, + "type": "number" + }, + "logic": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/job-spec/types\").LogicTree" + }, + "origin": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "reads": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/job-spec/types\").JobRead[]" + } + } + }, + "JobSpecTemplate": { + "type": "import(\"sdk/src/lib/job-spec/types\").JobSpecTemplate", + "members": { + "allowedMutability": { + "optional": false, + "readonly": false, + "type": "\"BOTH\" | \"CLIENT\" | \"NONE\" | \"PROVIDER\"" + }, + "checks": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/job-spec/types\").JobCheckTemplate[]" + }, + "logic": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/job-spec/types\").LogicTree" + }, + "params": { + "optional": false, + "readonly": false, + "type": "{\n max: bigint;\n min: bigint;\n}[]" + }, + "reads": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/job-spec/types\").JobRead[]" + } + } + }, + "JobRead": { + "type": "import(\"sdk/src/lib/job-spec/types\").JobRead", + "members": { + "args": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainId": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "field": { + "optional": false, + "readonly": false, + "type": "number[]" + }, + "fills": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/job-spec/types\").JobFill[] | undefined" + }, + "minConfirmations": { + "optional": false, + "readonly": false, + "type": "number" + }, + "outputs": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "PreparedJobRead": { + "type": "import(\"sdk/src/lib/job-spec/types\").PreparedJobRead", + "members": { + "args": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainId": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "fills": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/job-spec/types\").JobFill[] | undefined" + }, + "outputs": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "JobReadInput": { + "type": "import(\"sdk/src/lib/job-spec/types\").JobReadInput", + "members": { + "field": { + "optional": true, + "readonly": false, + "type": "number[] | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "read": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/job-spec/types\").PreparedJobRead" + } + } + }, + "JobCheck": { + "type": "import(\"sdk/src/lib/job-spec/types\").JobCheck", + "members": { + "evaluation": { + "optional": false, + "readonly": false, + "type": "\"BOOLEAN\" | \"COMPARE\" | \"NUMBER\" | \"PERCENTAGE\"" + }, + "operation": { + "optional": false, + "readonly": false, + "type": "\"EQUAL\" | \"GREATER_OR_EQUAL\" | \"GREATER_THAN\" | \"LESS_OR_EQUAL\" | \"LESS_THAN\" | \"NOT_EQUAL\"" + }, + "read": { + "optional": false, + "readonly": false, + "type": "number" + }, + "target": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "JobCheckTemplate": { + "type": "import(\"sdk/src/lib/job-spec/types\").JobCheckTemplate", + "members": { + "evaluation": { + "optional": false, + "readonly": false, + "type": "\"BOOLEAN\" | \"COMPARE\" | \"NUMBER\" | \"PERCENTAGE\"" + }, + "operation": { + "optional": false, + "readonly": false, + "type": "\"EQUAL\" | \"GREATER_OR_EQUAL\" | \"GREATER_THAN\" | \"LESS_OR_EQUAL\" | \"LESS_THAN\" | \"NOT_EQUAL\"" + }, + "read": { + "optional": false, + "readonly": false, + "type": "number" + }, + "target": { + "optional": false, + "readonly": false, + "type": "\"agentic:principal\" | \"agentic:wallet\" | {\n param: number;\n} | {\n principalBps: bigint;\n} | bigint" + } + } + }, + "LogicTree": { + "type": "import(\"sdk/src/lib/job-spec/types\").LogicTree", + "members": { + "k": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "kind": { + "optional": false, + "readonly": false, + "type": "\"ALL\" | \"ANY\" | \"AT_LEAST\"" + }, + "of": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/job-spec/types\").LogicTree | number)[]" + } + } + }, + "Evaluation": { + "type": "\"BOOLEAN\" | \"COMPARE\" | \"NUMBER\" | \"PERCENTAGE\"", + "members": {} + }, + "Operation": { + "type": "\"EQUAL\" | \"GREATER_OR_EQUAL\" | \"GREATER_THAN\" | \"LESS_OR_EQUAL\" | \"LESS_THAN\" | \"NOT_EQUAL\"", + "members": {} + }, + "LogicKind": { + "type": "\"ALL\" | \"ANY\" | \"AT_LEAST\"", + "members": {} + }, + "AllowedMutability": { + "type": "\"BOTH\" | \"CLIENT\" | \"NONE\" | \"PROVIDER\"", + "members": {} + }, + "PrincipalMarker": { + "type": "\"agentic:principal\"", + "members": {} + }, + "PrepareJobReadOptions": { + "type": "import(\"sdk/src/lib/job-spec/types\").PrepareJobReadOptions", + "members": { + "abi": { + "optional": false, + "readonly": false, + "type": "readonly (import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/abitype/dist/types/abi\").AbiConstructor | import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/abitype/dist/types/abi\").AbiError | import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/abitype/dist/types/abi\").AbiFallback | import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/abitype/dist/types/abi\").AbiReceive | import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiEvent | import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiFunction)[]" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "string" + }, + "functionName": { + "optional": false, + "readonly": false, + "type": "string" + }, + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "BuildJobSpecOptions": { + "type": "import(\"sdk/src/lib/job-spec/types\").BuildJobSpecOptions", + "members": { + "allowedMutability": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/job-spec/types\").AllowedMutability | undefined" + }, + "checks": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/job-spec/types\").JobCheck[]" + }, + "executeBy": { + "optional": false, + "readonly": false, + "type": "number" + }, + "expiredAt": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "failFinalAt": { + "optional": false, + "readonly": false, + "type": "number" + }, + "logic": { + "optional": false, + "readonly": false, + "type": "\"ALL\" | \"ANY\" | import(\"sdk/src/lib/job-spec/types\").LogicTree" + }, + "origin": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "reads": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/job-spec/types\").JobReadInput | import(\"sdk/src/lib/job-spec/types\").PreparedJobRead)[]" + } + } + }, + "BuildJobSpecTemplateOptions": { + "type": "import(\"sdk/src/lib/job-spec/types\").BuildJobSpecTemplateOptions", + "members": { + "allowedMutability": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/job-spec/types\").AllowedMutability | undefined" + }, + "checks": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/job-spec/types\").JobCheckTemplate[]" + }, + "logic": { + "optional": false, + "readonly": false, + "type": "\"ALL\" | \"ANY\" | import(\"sdk/src/lib/job-spec/types\").LogicTree" + }, + "params": { + "optional": true, + "readonly": false, + "type": "{\n max: bigint;\n min: bigint;\n}[] | undefined" + }, + "reads": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/job-spec/types\").JobReadInput | import(\"sdk/src/lib/job-spec/types\").PreparedJobRead)[]" + } + } + }, + "JobSpecPreview": { + "type": "import(\"sdk/src/lib/job-spec/types\").JobSpecPreview", + "members": { + "checks": { + "optional": false, + "readonly": false, + "type": "{\n pass: boolean | null;\n reason?: string;\n value: bigint | null;\n}[]" + }, + "fees": { + "optional": false, + "readonly": false, + "type": "{\n paid: bigint;\n quoted: bigint;\n}" + }, + "pass": { + "optional": false, + "readonly": false, + "type": "boolean | null" + }, + "reads": { + "optional": false, + "readonly": false, + "type": "{\n decoded: bigint | null;\n error?: string;\n response: import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse;\n value: `0x${string}` | null;\n}[]" + } + } + }, + "PreviewJobSpecOptions": { + "type": "import(\"sdk/src/lib/job-spec/types\").PreviewJobSpecOptions", + "members": { + "accounts": { + "optional": true, + "readonly": false, + "type": "Record | undefined" + }, + "advanced": { + "optional": true, + "readonly": false, + "type": "{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n} | undefined" + }, + "baseline": { + "optional": true, + "readonly": false, + "type": "readonly (bigint | null)[] | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback | undefined" + }, + "client": { + "optional": false, + "readonly": false, + "type": "{\n universal: {\n get origin(): ReturnType;\n get account(): ReturnType;\n sendTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"execute\"];\n prepareTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"prepareTransaction\"];\n executeTransactions: (txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise;\n trackTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"trackTransaction\"];\n migrateCEA: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"migrateCEA\"];\n rescueFunds: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"rescueFunds\"];\n read: ((subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>) & {\n prepare: (options: import(\"sdk/src/lib/job-spec/types\").PrepareJobReadOptions) => import(\"sdk/src/lib/job-spec/types\").PreparedJobRead;\n };\n prepareRead: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n executeReads: (reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>;\n trackRead: {\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n };\n signMessage: (data: Uint8Array) => Promise;\n signTypedData: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n };\n}" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxTotalFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "params": { + "optional": true, + "readonly": false, + "type": "bigint[] | undefined" + }, + "principal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "wallet": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "CHAIN": { + "type": "typeof import(\"sdk/src/lib/constants/enums\").CHAIN", + "members": { + "ARBITRUM_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA" + }, + "BASE_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA" + }, + "BNB_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET" + }, + "ETHEREUM_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET" + }, + "ETHEREUM_SEPOLIA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA" + }, + "PUSH_LOCALNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET" + }, + "PUSH_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET" + }, + "PUSH_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET" + }, + "PUSH_TESTNET_DONUT": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET" + }, + "SOLANA_DEVNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET" + }, + "SOLANA_MAINNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET" + }, + "SOLANA_TESTNET": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET" + }, + "WEB2": { + "optional": false, + "readonly": false, + "type": "\"web2\"" + } + } + }, + "ConversionQuote": { + "type": "import(\"sdk/src/lib/constants/tokens\").ConversionQuote", + "members": { + "amountIn": { + "optional": false, + "readonly": false, + "type": "string" + }, + "amountOut": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rate": { + "optional": false, + "readonly": false, + "type": "number" + }, + "route": { + "optional": true, + "readonly": false, + "type": "string[] | undefined" + }, + "timestamp": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "UniversalSigner": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalSigner", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "signAndSendTransaction": { + "optional": false, + "readonly": false, + "type": "(unsignedTx: Uint8Array) => Promise" + }, + "signAuthorization": { + "optional": true, + "readonly": false, + "type": "((params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise) | undefined" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": true, + "readonly": false, + "type": "(({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise) | undefined" + } + } + }, + "UniversalAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "UniversalSignerSkeleton": { + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "signAndSendTransaction": { + "optional": false, + "readonly": false, + "type": "(unsignedTx: Uint8Array) => Promise" + }, + "signAuthorization": { + "optional": true, + "readonly": false, + "type": "((params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise) | undefined" + }, + "signerId": { + "optional": false, + "readonly": false, + "type": "string" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": true, + "readonly": false, + "type": "(({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise) | undefined" + } + } + }, + "SignAuthorizationParams": { + "type": "{\n chainId?: number;\n contractAddress: `0x${string}`;\n executor?: \"self\";\n nonce?: number;\n}", + "members": { + "chainId": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "contractAddress": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "executor": { + "optional": true, + "readonly": false, + "type": "\"self\" | undefined" + }, + "nonce": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "SignedAuthorization": { + "type": "{\n address: `0x${string}`;\n chainId: number;\n nonce: number;\n r: `0x${string}`;\n s: `0x${string}`;\n v?: bigint;\n yParity: number;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainId": { + "optional": false, + "readonly": false, + "type": "number" + }, + "nonce": { + "optional": false, + "readonly": false, + "type": "number" + }, + "r": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "s": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "v": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "yParity": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "DerivedExecutorAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").DerivedExecutorAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean | null" + } + } + }, + "ResolvedAccount": { + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedAccount", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainName": { + "optional": false, + "readonly": false, + "type": "string" + }, + "exists": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "role": { + "optional": true, + "readonly": false, + "type": "\"controller\" | undefined" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"cea\" | \"uea\" | \"uoa\"" + } + } + }, + "ResolvedControllerAccounts": { + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedControllerAccounts", + "members": { + "accounts": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").ResolvedAccount[]" + } + } + }, + "AccountType": { + "type": "\"cea\" | \"uea\" | \"uoa\"", + "members": {} + }, + "AccountRole": { + "type": "\"controller\"", + "members": {} + }, + "PC20TokenReference": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "FundsToken": { + "type": "import(\"sdk/src/lib/constants/tokens\").MoveableToken | import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20TokenReference", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "PC20RegistryEntry": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "chainName": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "PC20AddressResult": { + "type": "{\n address: `0x${string}`;\n decimals: number;\n name: string;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n registry: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20RegistryEntry[];\n symbol: string;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "decimals": { + "optional": false, + "readonly": false, + "type": "number" + }, + "name": { + "optional": false, + "readonly": false, + "type": "string" + }, + "network": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "registry": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20RegistryEntry[]" + }, + "symbol": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "isPC20Reference": { + "type": "(token: import(\"sdk/src/lib/orchestrator/orchestrator.types\").FundsToken | undefined) => token is import(\"sdk/src/lib/orchestrator/orchestrator.types\").PC20TokenReference", + "members": {} + }, + "PC20Error": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20Error", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidPC20AddressError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InvalidPC20AddressError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20TokenChainMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20TokenChainMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20WrapperNotRegisteredError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20WrapperNotRegisteredError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20RegistryMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20RegistryMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20FactoryMismatchError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20FactoryMismatchError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidPC20MetadataError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InvalidPC20MetadataError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20ExpectedButPRC20Error": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20ExpectedButPRC20Error", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20AmbiguousAddressError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20AmbiguousAddressError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "candidates": { + "optional": false, + "readonly": true, + "type": "{\n chain: string;\n pushAddress: string;\n}[]" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "UnsupportedPC20DestinationError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").UnsupportedPC20DestinationError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InsufficientPC20BalanceError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").InsufficientPC20BalanceError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20UnknownChainNamespaceError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20UnknownChainNamespaceError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20WrapperPredictionUnavailableError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20WrapperPredictionUnavailableError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20ExportRevertedError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20ExportRevertedError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "lockedAmount": { + "optional": true, + "readonly": true, + "type": "bigint | undefined" + }, + "outboundTxId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "revertRecipient": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PC20UnsafeEmptyPayloadError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/pc20/errors\").PC20UnsafeEmptyPayloadError", + "members": { + "address": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "expectedChain": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ChainTarget": { + "type": "{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "ChainSource": { + "type": "{\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n}", + "members": { + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + } + } + }, + "UniversalTo": { + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget", + "members": {} + }, + "TransactionRouteType": { + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"", + "members": {} + }, + "UniversalExecuteParams": { + "type": "{\n from?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainSource;\n migration?: boolean;\n to: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTo;\n} & Omit", + "members": { + "_minimumDepositUsd": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "_requiredFundsOverride": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "_skipFeeLocking": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "_ueaStatus": { + "optional": true, + "readonly": false, + "type": "{\n balance: bigint;\n isDeployed: boolean;\n nonce: bigint;\n} | undefined" + }, + "data": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiCall[] | undefined" + }, + "deadline": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "feeLockTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "from": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainSource | undefined" + }, + "funds": { + "optional": true, + "readonly": false, + "type": "{\n amount: bigint;\n token?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").FundsToken;\n} | undefined" + }, + "gasLimit": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFeePerGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxPCForGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxPriorityFeePerGas": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "migration": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "nonce": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "options": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions | undefined" + }, + "payGasWith": { + "optional": true, + "readonly": false, + "type": "{\n minAmountOut?: bigint | string;\n slippageBps?: number;\n token?: import(\"sdk/src/lib/constants/tokens\").PayableToken;\n} | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "to": { + "optional": false, + "readonly": false, + "type": "`0x${string}` | import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget" + }, + "value": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "UniversalOutboundTxRequest": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalOutboundTxRequest", + "members": { + "amount": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gasPrice": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxPCForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "payload": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "recipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "revertRecipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "token": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "PreparedUniversalTx": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx", + "members": { + "_hop": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").HopDescriptor" + }, + "deadline": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "estimatedGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "gatewayRequest": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalOutboundTxRequest | import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxRequest" + }, + "nonce": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "payload": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + } + } + }, + "CascadedTxResponse": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadedTxResponse", + "members": { + "finalTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hopCount": { + "optional": false, + "readonly": false, + "type": "number" + }, + "hops": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo[]" + }, + "initialTxHash": { + "optional": false, + "readonly": false, + "type": "string" + }, + "initialTxResponse": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions) => Promise" + }, + "waitForAll": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions) => Promise" + } + } + }, + "CascadeHopInfo": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo", + "members": { + "executionChain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "expectedSubTxId": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hopIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "outboundDetails": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").OutboundTxDetails | undefined" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + }, + "status": { + "optional": false, + "readonly": false, + "type": "\"confirmed\" | \"failed\" | \"pending\" | \"submitted\"" + }, + "txHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "CascadeTrackOptions": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeTrackOptions", + "members": { + "eventHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeProgressEvent) => void) | undefined" + }, + "timeout": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "CascadeProgressEvent": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeProgressEvent", + "members": { + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "elapsed": { + "optional": false, + "readonly": false, + "type": "number" + }, + "hopIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "route": { + "optional": false, + "readonly": false, + "type": "\"CEA_TO_CEA\" | \"CEA_TO_PUSH\" | \"UOA_TO_CEA\" | \"UOA_TO_PUSH\"" + }, + "status": { + "optional": false, + "readonly": false, + "type": "\"confirmed\" | \"failed\" | \"found\" | \"polling\" | \"timeout\" | \"waiting\"" + }, + "txHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "CascadeCompletionResult": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeCompletionResult", + "members": { + "failedAt": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "finalTxHash": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "finalTxResponse": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadedTxResponse | undefined" + }, + "hops": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeHopInfo[]" + }, + "success": { + "optional": false, + "readonly": false, + "type": "boolean" + } + } + }, + "MultiChainTxResponse": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiChainTxResponse", + "members": { + "chains": { + "optional": false, + "readonly": false, + "type": "{\n blockNumber: bigint;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n hash: string;\n status: \"confirmed\" | \"failed\" | \"pending\";\n}[]" + }, + "transactions": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse[]" + } + } + }, + "OutboundTxDetails": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").OutboundTxDetails", + "members": { + "amount": { + "optional": false, + "readonly": false, + "type": "string" + }, + "assetAddr": { + "optional": false, + "readonly": false, + "type": "string" + }, + "destinationChain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "explorerUrl": { + "optional": false, + "readonly": false, + "type": "string" + }, + "externalTxHash": { + "optional": false, + "readonly": false, + "type": "string" + }, + "recipient": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "WaitForOutboundOptions": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").WaitForOutboundOptions", + "members": { + "_expectedDestinationChain": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "_outboundIndex": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "_resolvedSubTxId": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "initialWaitMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: {\n elapsed: number;\n status: \"failed\" | \"found\" | \"polling\" | \"timeout\" | \"waiting\";\n}) => void) | undefined" + }, + "timeout": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "SvmGatewayAccountMeta": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmGatewayAccountMeta", + "members": { + "isWritable": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "pubkey": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "SvmExecutePayloadFields": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmExecutePayloadFields", + "members": { + "accounts": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmGatewayAccountMeta[]" + }, + "instructionId": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "ixData": { + "optional": false, + "readonly": false, + "type": "Uint8Array" + }, + "targetProgram": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AccountStatus": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus", + "members": { + "mode": { + "optional": false, + "readonly": false, + "type": "\"read-only\" | \"signer\"" + }, + "uea": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UEAStatus" + } + } + }, + "UEAStatus": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UEAStatus", + "members": { + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "loaded": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "minRequiredVersion": { + "optional": false, + "readonly": false, + "type": "string" + }, + "requiresUpgrade": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "version": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "RescueFundsParams": { + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").RescueFundsParams", + "members": { + "prc20": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "universalTxId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "parseUEAVersion": { + "type": "(version: string) => number", + "members": {} + }, + "TransactionRoute": { + "type": "typeof import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute", + "members": { + "CEA_TO_CEA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.CEA_TO_CEA" + }, + "CEA_TO_PUSH": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.CEA_TO_PUSH" + }, + "UOA_TO_CEA": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.UOA_TO_CEA" + }, + "UOA_TO_PUSH": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute.UOA_TO_PUSH" + } + } + }, + "detectRoute": { + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams) => import(\"sdk/src/lib/orchestrator/route-detector\").TransactionRoute", + "members": {} + }, + "isChainTarget": { + "type": "(to: unknown) => to is import(\"sdk/src/lib/orchestrator/orchestrator.types\").ChainTarget", + "members": {} + }, + "DEFAULT_MAX_PC_FOR_GAS_BUFFER_BPS": { + "type": "1000", + "members": {} + }, + "MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT": { + "type": "10000", + "members": {} + }, + "quoteMaxPCForGasCap": { + "type": "(input: import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapInput) => import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": {} + }, + "quoteMaxPCForGasCapFromNativeValue": { + "type": "(input: import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapFromNativeValueInput) => import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": {} + }, + "MaxPCForGasCapInput": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapInput", + "members": { + "bufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "gasLegNativePc": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "MaxPCForGasCapFromNativeValueInput": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapFromNativeValueInput", + "members": { + "bufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "nativeValueForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "MaxPCForGasCapQuote": { + "type": "import(\"sdk/src/lib/orchestrator/max-pc-for-gas\").MaxPCForGasCapQuote", + "members": { + "bufferBps": { + "optional": false, + "readonly": false, + "type": "number" + }, + "gasLegNativePc": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxPCForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "nativeValueForGas": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "getCEAAddress": { + "type": "(ueaAddress: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise", + "members": {} + }, + "getPushAccountForCEA": { + "type": "(ceaAddress: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise<`0x${string}`>", + "members": {} + }, + "isCEA": { + "type": "(address: `0x${string}`, chain: import(\"sdk/src/lib/constants/enums\").CHAIN, rpcUrl?: string) => Promise", + "members": {} + }, + "chainSupportsCEA": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "chainSupportsOutbound": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "getCEAFactoryAddress": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => `0x${string}` | undefined", + "members": {} + }, + "getAllCEAAddresses": { + "type": "(ueaAddress: `0x${string}`, rpcUrls?: Partial>) => Promise", + "members": {} + }, + "encodeSvmExecutePayload": { + "type": "(fields: import(\"sdk/src/lib/orchestrator/orchestrator.types\").SvmExecutePayloadFields) => `0x${string}`", + "members": {} + }, + "isSvmChain": { + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => boolean", + "members": {} + }, + "isValidSolanaHexAddress": { + "type": "(address: string) => boolean", + "members": {} + }, + "buildMigrationPayload": { + "type": "() => `0x${string}`", + "members": {} + }, + "buildErc20WithdrawalMulticall": { + "type": "(tokenAddress: `0x${string}`, recipientAddress: `0x${string}`, amount: bigint) => import(\"sdk/src/lib/orchestrator/orchestrator.types\").MultiCall[]", + "members": {} + }, + "ReadChain": { + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain", + "members": {} + }, + "ReadDestination": { + "type": "{\n chain: import(\"sdk/src/lib/read-state/read-state.types\").ReadChain;\n} | {\n chainId: string;\n chainNamespace: string;\n}", + "members": {} + }, + "ResolvedDestination": { + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}", + "members": { + "caip2": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainId": { + "optional": false, + "readonly": false, + "type": "string" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "namespace": { + "optional": false, + "readonly": false, + "type": "\"eip155\" | \"solana\" | \"web2\"" + } + } + }, + "ReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").SvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery", + "members": { + "type": { + "optional": false, + "readonly": false, + "type": "\"accountBalance\" | \"contractCall\" | \"http\" | \"lamportBalance\" | \"rawAccountData\" | \"splTokenAccount\" | \"storageSlot\"" + } + } + }, + "EvmReadQuery": { + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n target: `0x${string}`;\n type: \"contractCall\";\n} | {\n callData: `0x${string}`;\n target: `0x${string}`;\n type: \"contractCall\";\n} | {\n slot: `0x${string}` | bigint;\n target: `0x${string}`;\n type: \"storageSlot\";\n} | {\n target: `0x${string}`;\n type: \"accountBalance\";\n}", + "members": { + "target": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"accountBalance\" | \"contractCall\" | \"storageSlot\"" + } + } + }, + "SvmReadQuery": { + "type": "{\n account: string | Uint8Array;\n accountName?: string;\n idl?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n type: \"rawAccountData\";\n} | {\n account: string | Uint8Array;\n type: \"lamportBalance\";\n} | {\n account: string | Uint8Array;\n type: \"splTokenAccount\";\n}", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "string | Uint8Array" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"lamportBalance\" | \"rawAccountData\" | \"splTokenAccount\"" + } + } + }, + "Web2ReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery", + "members": { + "body": { + "optional": true, + "readonly": false, + "type": "string | Uint8Array | undefined" + }, + "extract": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[]" + }, + "headers": { + "optional": true, + "readonly": false, + "type": "Record | undefined" + }, + "method": { + "optional": true, + "readonly": false, + "type": "\"GET\" | \"POST\" | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"http\"" + }, + "url": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "Web2Extract": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract", + "members": { + "decimals": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "path": { + "optional": false, + "readonly": false, + "type": "string" + }, + "valueType": { + "optional": false, + "readonly": false, + "type": "\"bool\" | \"bytes\" | \"int256\" | \"string\" | \"uint256\"" + } + } + }, + "Web2ValueType": { + "type": "\"bool\" | \"bytes\" | \"int256\" | \"string\" | \"uint256\"", + "members": {} + }, + "EncodedReadQuery": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery", + "members": { + "blockRef": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "encoded": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "namespace": { + "optional": false, + "readonly": false, + "type": "\"eip155\" | \"solana\" | \"web2\"" + }, + "ownerBytes": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "queryType": { + "optional": false, + "readonly": false, + "type": "number" + }, + "resultShape": { + "optional": false, + "readonly": false, + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}" + }, + "warnings": { + "optional": false, + "readonly": false, + "type": "string[]" + } + } + }, + "ReadResultShape": { + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"bytes32\" | \"evmCall\" | \"raw\" | \"svmAccount\" | \"uint256\" | \"web2\"" + } + } + }, + "DecodedReadResult": { + "type": "{\n accountName: string;\n kind: \"svmAccount\";\n value: unknown;\n} | {\n kind: \"bytes32\";\n value: `0x${string}`;\n} | {\n kind: \"evmCall\";\n value: unknown;\n} | {\n kind: \"raw\";\n value: `0x${string}`;\n} | {\n kind: \"uint256\";\n value: bigint;\n} | {\n kind: \"web2\";\n values: readonly unknown[];\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"bytes32\" | \"evmCall\" | \"raw\" | \"svmAccount\" | \"uint256\" | \"web2\"" + } + } + }, + "ReadPreflight": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight", + "members": { + "destination": { + "optional": false, + "readonly": false, + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}" + }, + "fetchedAt": { + "optional": false, + "readonly": false, + "type": "number" + }, + "observedChainHeight": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pushBlockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pushGasPrice": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "universalCallback": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "universalCore": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ReadSpec": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec", + "members": { + "account": { + "optional": false, + "readonly": false, + "type": "{\n chainId: string;\n chainNamespace: string;\n owner: `0x${string}`;\n}" + }, + "blockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "expiryPushChainHeight": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "minConfirmations": { + "optional": false, + "readonly": false, + "type": "number" + }, + "query": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "revertRecipient": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ReadSpecTuple": { + "type": "readonly [\n readonly [\n string,\n string,\n `0x${string}`\n ],\n `0x${string}`,\n number,\n bigint,\n bigint,\n bigint,\n `0x${string}`\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "readonly [\n string,\n string,\n `0x${string}`\n]" + }, + "1": { + "optional": false, + "readonly": true, + "type": "`0x${string}`" + }, + "2": { + "optional": false, + "readonly": true, + "type": "number" + }, + "3": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "4": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "5": { + "optional": false, + "readonly": true, + "type": "bigint" + }, + "6": { + "optional": false, + "readonly": true, + "type": "`0x${string}`" + }, + "length": { + "optional": false, + "readonly": true, + "type": "7" + } + } + }, + "BuildReadSpecParams": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").BuildReadSpecParams", + "members": { + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "budgetBuffer": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback | undefined" + }, + "callbackBudget": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "destination": { + "optional": false, + "readonly": false, + "type": "{\n chain: import(\"sdk/src/lib/read-state/read-state.types\").ReadChain;\n} | {\n chainId: string;\n chainNamespace: string;\n}" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "expiryPushChainHeight": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxFeeBufferBps": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "owner": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "query": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").SvmReadQuery | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadQuery" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "PreparedRead": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead", + "members": { + "__@preparedReadValue": { + "optional": true, + "readonly": true, + "type": "T | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback | undefined" + }, + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "encodedQuery": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery" + }, + "encodedSpec": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "fees": { + "optional": false, + "readonly": false, + "type": "{\n callbackBudget: bigint;\n protocolFee: bigint;\n total: bigint;\n}" + }, + "preflight": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "queryKey": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "resultShape": { + "optional": false, + "readonly": false, + "type": "{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: string;\n kind: \"evmCall\";\n} | {\n accountName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n kind: \"svmAccount\";\n} | {\n extract: readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n kind: \"web2\";\n} | {\n kind: \"bytes32\";\n} | {\n kind: \"raw\";\n} | {\n kind: \"uint256\";\n}" + }, + "spec": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec" + }, + "specTuple": { + "optional": false, + "readonly": false, + "type": "readonly [\n readonly [\n string,\n string,\n `0x${string}`\n ],\n `0x${string}`,\n number,\n bigint,\n bigint,\n bigint,\n `0x${string}`\n]" + }, + "value": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "warnings": { + "optional": false, + "readonly": false, + "type": "string[]" + } + } + }, + "ReadCallback": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadCallback", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "((spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpecTuple, callbackGasLimit: bigint) => readonly unknown[]) | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "gasLimit": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "target": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "SimulateReadResult": { + "type": "{\n args?: readonly unknown[];\n error: string;\n errorName?: string;\n ok: false;\n} | {\n ok: true;\n}", + "members": { + "ok": { + "optional": false, + "readonly": false, + "type": "boolean" + } + } + }, + "ParsedReadRequest": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ParsedReadRequest", + "members": { + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackGasLimit": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "callbackTarget": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "logIndex": { + "optional": false, + "readonly": false, + "type": "number" + }, + "originalFunder": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "requestId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "requestIdUint": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "spec": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec" + }, + "totalPaid": { + "optional": false, + "readonly": false, + "type": "bigint" + } + } + }, + "FulfilOutcome": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").FulfilOutcome", + "members": { + "burned": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "delivered": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "expired": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "failReason": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "gasReported": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refunded": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refundFailed": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + } + } + }, + "ReceiptLike": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike", + "members": { + "logs": { + "optional": false, + "readonly": false, + "type": "readonly {\n address: string;\n data: string;\n logIndex?: number | string;\n topics: readonly string[];\n}[]" + } + } + }, + "ReadRef": { + "type": "{\n requestId: `0x${string}` | bigint;\n} | {\n txHash: `0x${string}`;\n}", + "members": {} + }, + "ReadLifecycleOptions": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadLifecycleOptions", + "members": { + "pollingIntervalMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "resultShape": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadFees": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadFees", + "members": { + "burned": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callbackBudget": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "paid": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "protocolFee": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "refunded": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "refundFailed": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + } + } + }, + "UniversalReadResponse": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse", + "members": { + "callbackDelivered": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "callbackFailReason": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "decoded": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").DecodedReadResult | undefined" + }, + "decodeError": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destination": { + "optional": false, + "readonly": false, + "type": "{\n caip2: string;\n chainId: string;\n chainNamespace: string;\n namespace: import(\"sdk/src/lib/constants/read-state\").ReadNamespace;\n}" + }, + "errorMsg": { + "optional": false, + "readonly": false, + "type": "string" + }, + "explorerUrl": { + "optional": false, + "readonly": false, + "type": "string" + }, + "fees": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadFees" + }, + "isTerminal": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "outcome": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME" + }, + "pcTx": { + "optional": false, + "readonly": false, + "type": "readonly {\n blockHeight: number;\n errorMsg: string;\n status: string;\n txHash: `0x${string}`;\n}[]" + }, + "raw": { + "optional": false, + "readonly": false, + "type": "{\n errorCode: import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n resultData: `0x${string}`;\n status: import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n} | null" + }, + "refresh": { + "optional": false, + "readonly": false, + "type": "() => Promise>" + }, + "request": { + "optional": false, + "readonly": false, + "type": "{\n callbackGasLimit: bigint;\n callbackTarget: `0x${string}`;\n createdAtHeight: bigint;\n logIndex: number;\n originalFunder: `0x${string}`;\n refundTo: `0x${string}`;\n spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpec;\n}" + }, + "requestId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "requestIdUint": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "status": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "value": { + "optional": true, + "readonly": false, + "type": "T | undefined" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: import(\"sdk/src/lib/read-state/read-state.types\").ReadLifecycleOptions) => Promise>" + } + } + }, + "ReadResponseTuple": { + "type": "{\n -readonly [K in keyof R]: import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse ? T : unknown>;\n}", + "members": {} + }, + "BatchReadResponse": { + "type": "import(\"sdk/src/lib/read-state/read-state.types\").BatchReadResponse", + "members": { + "atomic": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "count": { + "optional": false, + "readonly": false, + "type": "number" + }, + "reads": { + "optional": false, + "readonly": false, + "type": "{\n -readonly [K in keyof R]: import(\"sdk/src/lib/read-state/read-state.types\").UniversalReadResponse ? T : unknown>;\n}" + }, + "transactionHashes": { + "optional": true, + "readonly": false, + "type": "readonly `0x${string}`[] | undefined" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "wait": { + "optional": false, + "readonly": false, + "type": "(opts?: Omit) => Promise>" + } + } + }, + "ReadOptions": { + "type": "((import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n callData?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n callData?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n callData?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n callData?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n callData: `0x${string}`;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n callData?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"callData\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n callData?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n callData?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n callData?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">) | (import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions & Omit<{\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n} & {\n blockNumber?: never;\n minConfirmations?: never;\n} & {\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n callData?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\"> & Pick, \"advanced\" | \"progressHook\" | \"waitForCompletion\">)) & {\n callback?: (Pick & Required>) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n };\n}", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "advanced": { + "optional": true, + "readonly": false, + "type": "{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n} | undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "({\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} & {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n}) | ({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick & Pick & Required>) | undefined" + }, + "callData": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadPrepareOptions": { + "type": "((((({\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n callData?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\">) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n callData?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n}) | ({\n callData: `0x${string}`;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n callData?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"callData\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n callData?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n callData?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">)) & {\n blockNumber?: bigint | undefined;\n minConfirmations?: number | undefined;\n}) | ((({\n abi?: never;\n accountName?: never;\n args?: never;\n callData?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n}) | ({\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n callData?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n callData?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n callData?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\">)) & {\n blockNumber?: never;\n minConfirmations?: never;\n})) & {\n advanced?: never;\n progressHook?: never;\n waitForCompletion?: never;\n}) & import(\"sdk/src/lib/read-state/read-params\").ReadCallbackOptions & Pick", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "advanced": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "blockNumber": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "callback": { + "optional": true, + "readonly": false, + "type": "({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} | undefined" + }, + "callData": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "expiryBlocks": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "maxFee": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "minConfirmations": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "refundTo": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadQueryOptions": { + "type": "({\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: readonly unknown[];\n functionName: string;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n callData?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"abi\" | \"args\" | \"functionName\">) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n callData?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n}) | ({\n abi?: never;\n accountName?: never;\n args?: never;\n callData?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n}) | ({\n args?: readonly unknown[];\n functionName?: string;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n callData?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"args\" | \"functionName\" | \"idl\">) | ({\n callData: `0x${string}`;\n} & {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n callData?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"callData\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n storageSlot: `0x${string}` | bigint;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n callData?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"storageSlot\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n callData?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n} & {\n token: string;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n callData?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"token\">) | ({\n chain: import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain;\n} & {\n web2: import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options;\n} & Omit<{\n abi?: never;\n accountName?: never;\n args?: never;\n callData?: never;\n functionName?: never;\n idl?: never;\n storageSlot?: never;\n token?: never;\n tokenProgram?: never;\n web2?: never;\n}, \"web2\">)", + "members": { + "abi": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi | undefined" + }, + "accountName": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "args": { + "optional": true, + "readonly": false, + "type": "readonly unknown[] | undefined" + }, + "callData": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "chain": { + "optional": false, + "readonly": false, + "type": "(import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET) | (import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET | import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET) | import(\"sdk/src/lib/read-state/read-state.types\").Web2ReadChain" + }, + "functionName": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "idl": { + "optional": true, + "readonly": false, + "type": "import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl | undefined" + }, + "storageSlot": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | bigint | undefined" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "tokenProgram": { + "optional": true, + "readonly": false, + "type": "undefined" + }, + "web2": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options | undefined" + } + } + }, + "ReadCallbackOptions": { + "type": "{\n callback?: ({\n gasLimit?: bigint;\n target: `0x${string}`;\n } & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n };\n}", + "members": { + "callback": { + "optional": true, + "readonly": false, + "type": "({\n gasLimit?: bigint;\n target: `0x${string}`;\n} & Pick) | {\n abi?: never;\n args?: never;\n functionName?: never;\n gasLimit?: bigint;\n target?: never;\n} | undefined" + } + } + }, + "ReadValue": { + "type": "O extends {\n abi: infer A extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: infer F extends string;\n} ? number extends A[\"length\"] ? unknown : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, O extends {\n args: infer Args extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n} ? Args : readonly [\n] extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> ? import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> & readonly [\n] : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>> extends infer Selected ? Selected extends {\n outputs: readonly unknown[];\n type: \"function\";\n} & import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiFunction ? {\n [key in keyof {\n [key in keyof import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"]]: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterToPrimitiveType, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"][key], import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterKind>;\n }]: {\n [key in keyof import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ExtractAbiFunctionForArgs, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"]]: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterToPrimitiveType, import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>>[\"outputs\"][key], import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").AbiParameterKind>;\n }[key];\n} extends infer types ? types extends readonly [\n] ? void : types extends readonly [\n infer type\n] ? type : types : never : never : never : O extends {\n web2: {\n extract: infer E extends readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[];\n };\n} ? {\n readonly [K in keyof E]: {\n bool: boolean;\n bytes: `0x${string}`;\n int256: bigint;\n string: string;\n uint256: bigint;\n }[E[K][\"valueType\"]];\n} : O extends {\n callData: unknown;\n} | {\n storageSlot: unknown;\n} ? `0x${string}` : O extends {\n idl: infer I extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} ? string extends Extract, string> ? unknown : (O extends {\n functionName: infer N extends string;\n} ? N : undefined) extends string ? import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/index\").IdlAccounts[{\n [K in Extract, string>]: Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : K> extends Lowercase<(O extends {\n functionName: infer N extends string;\n } ? N : undefined) & string extends `${infer H}_${infer T}` ? `${H}${Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : (O extends {\n functionName: infer N extends string;\n } ? N : undefined) & string> ? K : never;\n}[Extract, string>]] : import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/index\").IdlAccounts[Extract, string>] : bigint", + "members": {} + }, + "ValidateReadCall": { + "type": "O extends {\n abi: infer A extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n functionName: infer F extends string;\n} ? (readonly [\n] extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs> ? {\n args?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n} : {\n args: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionArgs>;\n}) & {\n functionName: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").ContractFunctionName;\n} : O extends {\n functionName: infer N extends string;\n idl: infer I extends import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n} ? string extends Extract, string> ? unknown : [\n {\n [K in Extract, string>]: Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : K> extends Lowercase}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : T>}` : N> ? K : never;\n }[Extract, string>]\n] extends [\n never\n] ? {\n functionName: Extract, string>;\n} : unknown : unknown", + "members": {} + }, + "ReadWeb2Options": { + "type": "import(\"sdk/src/lib/read-state/read-params\").ReadWeb2Options", + "members": { + "body": { + "optional": true, + "readonly": false, + "type": "string | Uint8Array | undefined" + }, + "extract": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/read-state/read-state.types\").Web2Extract[]" + }, + "headers": { + "optional": true, + "readonly": false, + "type": "Record | undefined" + }, + "method": { + "optional": true, + "readonly": false, + "type": "\"GET\" | \"POST\" | undefined" + }, + "timeoutMs": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadTrackOptions": { + "type": "{\n advanced?: Omit, \"enforceGasCheck\">;\n resultShape?: import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape;\n}", + "members": { + "advanced": { + "optional": true, + "readonly": false, + "type": "Omit<{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n}, \"enforceGasCheck\"> | undefined" + }, + "resultShape": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape | undefined" + } + } + }, + "ReadExecuteOptions": { + "type": "{\n advanced?: {\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n } | undefined;\n progressHook?: ((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined;\n waitForCompletion?: boolean | undefined;\n}", + "members": { + "advanced": { + "optional": true, + "readonly": false, + "type": "{\n enforceGasCheck?: boolean;\n pollingIntervalMs?: number;\n timeout?: number;\n} | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "waitForCompletion": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + } + } + }, + "UNIVERSAL_READ_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS", + "members": { + "ABORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.ABORTED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.EXPIRED" + }, + "FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.FAILED" + }, + "FULFILLED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.FULFILLED" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.PENDING" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.UNSPECIFIED" + }, + "VOTING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS.VOTING" + } + } + }, + "READ_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS", + "members": { + "ERROR": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.ERROR" + }, + "SUCCESS": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.SUCCESS" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS.UNSPECIFIED" + } + } + }, + "READ_ERROR_CODE": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE", + "members": { + "INVALID_QUERY": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.INVALID_QUERY" + }, + "INVALID_RESULT": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.INVALID_RESULT" + }, + "NOT_FOUND": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.NOT_FOUND" + }, + "REJECTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.REJECTED" + }, + "REVERTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.REVERTED" + }, + "UNSPECIFIED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.UNSPECIFIED" + }, + "UNSUPPORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE.UNSUPPORTED" + } + } + }, + "READ_OUTCOME": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME", + "members": { + "ABORTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.ABORTED" + }, + "CALLBACK_FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.CALLBACK_FAILED" + }, + "DECODE_FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.DECODE_FAILED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.EXPIRED" + }, + "FAILED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.FAILED" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.PENDING" + }, + "SOURCE_ERROR": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.SOURCE_ERROR" + }, + "SUCCESS": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.SUCCESS" + }, + "UNKNOWN": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME.UNKNOWN" + } + } + }, + "CONTRACT_REQUEST_STATUS": { + "type": "typeof import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS", + "members": { + "EXECUTED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.EXECUTED" + }, + "EXPIRED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.EXPIRED" + }, + "NONE": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.NONE" + }, + "PENDING": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.PENDING" + }, + "SETTLED": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/read-state/read-state.types\").CONTRACT_REQUEST_STATUS.SETTLED" + } + } + }, + "TERMINAL_READ_STATUSES": { + "type": "ReadonlySet", + "members": {} + }, + "ReadStateError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadStateError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidReadQueryError": { + "type": "import(\"sdk/src/lib/read-state/errors\").InvalidReadQueryError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "InvalidReadSpecError": { + "type": "import(\"sdk/src/lib/read-state/errors\").InvalidReadSpecError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "violations": { + "optional": false, + "readonly": true, + "type": "readonly import(\"sdk/src/lib/read-state/errors\").ReadSpecViolation[]" + } + } + }, + "ReadHeightUnavailableError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadHeightUnavailableError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "UnsupportedReadDestinationError": { + "type": "import(\"sdk/src/lib/read-state/errors\").UnsupportedReadDestinationError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadDecodeError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadDecodeError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadTimeoutError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadTimeoutError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "lastStatus": { + "optional": false, + "readonly": true, + "type": "number" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadNotFoundError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadNotFoundError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadRegistryUnavailableError": { + "type": "import(\"sdk/src/lib/read-state/errors\").ReadRegistryUnavailableError", + "members": { + "code": { + "optional": false, + "readonly": true, + "type": "string" + }, + "destination": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "requestId": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "transactionHashes": { + "optional": true, + "readonly": true, + "type": "`0x${string}`[] | undefined" + }, + "txHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "ReadSpecViolation": { + "type": "\"CALLBACK_GAS_LIMIT_EXCEEDED\" | \"DOMAIN_BLOCKED\" | \"EMPTY_QUERY\" | \"EXCESSIVE_FEE\" | \"INSUFFICIENT_CALLBACK_BUDGET\" | \"INSUFFICIENT_FEE\" | \"INVALID_ACCOUNT_ID\" | \"INVALID_BLOCK_NUMBER\" | \"INVALID_EXPIRY_HEIGHT\" | \"INVALID_MIN_CONFIRMATIONS\" | \"SVM_OWNER_NOT_32_BYTES\" | \"ZERO_CALLBACK_BUDGET\" | \"ZERO_CALLBACK_GAS_LIMIT\" | \"ZERO_REVERT_RECIPIENT\"", + "members": {} + }, + "resolveDestination": { + "type": "(dest: import(\"sdk/src/lib/read-state/read-state.types\").ReadDestination) => import(\"sdk/src/lib/read-state/read-state.types\").ResolvedDestination", + "members": {} + }, + "encodeReadQuery": { + "type": "(destination: import(\"sdk/src/lib/read-state/read-state.types\").ReadDestination, query: import(\"sdk/src/lib/read-state/read-state.types\").ReadQuery, options?: {\n blockNumber?: bigint;\n minSlot?: bigint;\n}) => import(\"sdk/src/lib/read-state/read-state.types\").EncodedReadQuery", + "members": {} + }, + "decodeReadResult": { + "type": "(resultData: `0x${string}`, shape: import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape) => import(\"sdk/src/lib/read-state/read-state.types\").DecodedReadResult", + "members": {} + }, + "parseReadRequestsFromReceipt": { + "type": "(receipt: import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike, universalCallback: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").ParsedReadRequest[]", + "members": {} + }, + "parseFulfilOutcome": { + "type": "(receipt: import(\"sdk/src/lib/read-state/read-state.types\").ReceiptLike, universalCallback: `0x${string}`, requestId: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").FulfilOutcome", + "members": {} + }, + "buildReadSpecFromPreflight": { + "type": "(preflight: import(\"sdk/src/lib/read-state/read-state.types\").ReadPreflight, params: import(\"sdk/src/lib/read-state/read-state.types\").BuildReadSpecParams, defaults?: {\n refundTo?: `0x${string}`;\n}) => import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead", + "members": {} + }, + "validateReadSpec": { + "type": "(input: import(\"sdk/src/lib/read-state/validate\").ValidateReadSpecInput) => {\n ok: false;\n violations: import(\"sdk/src/lib/read-state/errors\").ReadSpecViolation[];\n} | {\n ok: true;\n}", + "members": {} + }, + "toCallData": { + "type": "(prepared: import(\"sdk/src/lib/read-state/read-state.types\").PreparedRead, target: {\n abi: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").Abi;\n args?: (spec: import(\"sdk/src/lib/read-state/read-state.types\").ReadSpecTuple, callbackGasLimit: bigint) => readonly unknown[];\n functionName: string;\n}) => {\n data: `0x${string}`;\n value: bigint;\n}", + "members": {} + }, + "sizeCallbackBudget": { + "type": "(callbackGasLimit: bigint, pushGasPrice: bigint, buffer?: number) => bigint", + "members": {} + }, + "inferResultShape": { + "type": "(namespace: string, query: `0x${string}`) => import(\"sdk/src/lib/read-state/read-state.types\").ReadResultShape", + "members": {} + }, + "toRequestIdHex": { + "type": "(id: `0x${string}` | bigint) => `0x${string}`", + "members": {} + }, + "toReadQuery": { + "type": "(subject: string, o: ReadOptionsInput, resolvedTokenProgram?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@solana/web3.js/lib/index\").PublicKey) => import(\"sdk/src/lib/read-state/read-state.types\").ReadQuery", + "members": {} + }, + "UNIVERSAL_CALLBACK_EVM": { + "type": "readonly [\n {\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"requestExternalReadSelf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"estimateFee\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"statusOf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"enum RequestStatus\";\n readonly name: \"\";\n readonly type: \"uint8\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"isFulfilled\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getPendingRead\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly internalType: \"struct PendingRead\";\n readonly name: \"\";\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"totalEscrowed\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"blockedDomains\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly indexed: false;\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"readSpec\";\n readonly type: \"tuple\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"totalPaid\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"protocolFee\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ReadRequested\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"ReadFulfilled\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"reason\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"CallbackFailed\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"gasReported\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"burned\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"CallbackGasReported\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundSent\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundFailed\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RequestExpired\";\n readonly type: \"event\";\n },\n {\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"vaultPC\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ProtocolFeeDistributed\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidAccountId\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"EmptyQuery\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidMinConfirmations\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"DomainBlocked\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidBlockNumber\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidExpiryHeight\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroRevertRecipient\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroCallbackGasLimit\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint64\";\n readonly name: \"provided\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"max\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"CallbackGasLimitExceeded\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"required\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"InsufficientFee\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ExcessiveFee\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"actual\";\n readonly type: \"uint8\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"expected\";\n readonly type: \"uint8\";\n }\n ];\n readonly name: \"InvalidRequestStatus\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ContractIsPaused\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"CallerIsNotUCallbackModule\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n }\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"requestExternalReadSelf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n}" + }, + "1": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"estimateFee\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "2": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"statusOf\";\n readonly outputs: readonly [\n {\n readonly internalType: \"enum RequestStatus\";\n readonly name: \"\";\n readonly type: \"uint8\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "3": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"isFulfilled\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "4": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getPendingRead\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"bytes4\";\n readonly name: \"callbackSelector\";\n readonly type: \"bytes4\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly internalType: \"struct PendingRead\";\n readonly name: \"\";\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "5": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"totalEscrowed\";\n readonly outputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "6": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"blockedDomains\";\n readonly outputs: readonly [\n {\n readonly internalType: \"bool\";\n readonly name: \"\";\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "7": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly indexed: false;\n readonly internalType: \"struct ReadSpec\";\n readonly name: \"readSpec\";\n readonly type: \"tuple\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"callbackTarget\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"originalFunder\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint64\";\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"totalPaid\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"protocolFee\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"callbackBudget\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ReadRequested\";\n readonly type: \"event\";\n}" + }, + "8": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"ReadFulfilled\";\n readonly type: \"event\";\n}" + }, + "9": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"bytes\";\n readonly name: \"reason\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"CallbackFailed\";\n readonly type: \"event\";\n}" + }, + "10": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"gasReported\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"burned\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"CallbackGasReported\";\n readonly type: \"event\";\n}" + }, + "11": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundSent\";\n readonly type: \"event\";\n}" + }, + "12": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"recipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RefundFailed\";\n readonly type: \"event\";\n}" + }, + "13": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"refunded\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"RequestExpired\";\n readonly type: \"event\";\n}" + }, + "14": { + "optional": false, + "readonly": true, + "type": "{\n readonly anonymous: false;\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly internalType: \"address\";\n readonly name: \"vaultPC\";\n readonly type: \"address\";\n },\n {\n readonly indexed: false;\n readonly internalType: \"uint256\";\n readonly name: \"amount\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ProtocolFeeDistributed\";\n readonly type: \"event\";\n}" + }, + "15": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidAccountId\";\n readonly type: \"error\";\n}" + }, + "16": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"EmptyQuery\";\n readonly type: \"error\";\n}" + }, + "17": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidMinConfirmations\";\n readonly type: \"error\";\n}" + }, + "18": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n }\n ];\n readonly name: \"DomainBlocked\";\n readonly type: \"error\";\n}" + }, + "19": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidBlockNumber\";\n readonly type: \"error\";\n}" + }, + "20": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidExpiryHeight\";\n readonly type: \"error\";\n}" + }, + "21": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroRevertRecipient\";\n readonly type: \"error\";\n}" + }, + "22": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroCallbackGasLimit\";\n readonly type: \"error\";\n}" + }, + "23": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint64\";\n readonly name: \"provided\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"max\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"CallbackGasLimitExceeded\";\n readonly type: \"error\";\n}" + }, + "24": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"required\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"InsufficientFee\";\n readonly type: \"error\";\n}" + }, + "25": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"provided\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"ExcessiveFee\";\n readonly type: \"error\";\n}" + }, + "26": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly internalType: \"uint256\";\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"actual\";\n readonly type: \"uint8\";\n },\n {\n readonly internalType: \"uint8\";\n readonly name: \"expected\";\n readonly type: \"uint8\";\n }\n ];\n readonly name: \"InvalidRequestStatus\";\n readonly type: \"error\";\n}" + }, + "27": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ContractIsPaused\";\n readonly type: \"error\";\n}" + }, + "28": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"CallerIsNotUCallbackModule\";\n readonly type: \"error\";\n}" + }, + "29": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n}" + }, + "length": { + "optional": false, + "readonly": true, + "type": "30" + } + } + }, + "UNIVERSAL_READ_REGISTRY_EVM": { + "type": "readonly [\n {\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n },\n {\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"read\";\n readonly outputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"universalCallback_\";\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"constructor\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"initialize\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getLocalContext\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"hasResult\";\n readonly outputs: readonly [\n {\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"onUniversalData\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"queryKeyOf\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes32\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"readerOf\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"requestOrderOf\";\n readonly outputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"universalCallback\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"resultByRequestId\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"latestResult\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n },\n {\n readonly inputs: readonly [\n {\n readonly name: \"version\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"Initialized\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadRequested\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadStored\";\n readonly type: \"event\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidInitialization\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"NotInitializing\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n },\n {\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroAddressInit\";\n readonly type: \"error\";\n }\n]", + "members": { + "0": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly components: readonly [\n {\n readonly components: readonly [\n {\n readonly internalType: \"string\";\n readonly name: \"chainNamespace\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"string\";\n readonly name: \"chainId\";\n readonly type: \"string\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"owner\";\n readonly type: \"bytes\";\n }\n ];\n readonly internalType: \"struct UniversalAccountId\";\n readonly name: \"account\";\n readonly type: \"tuple\";\n },\n {\n readonly internalType: \"bytes\";\n readonly name: \"query\";\n readonly type: \"bytes\";\n },\n {\n readonly internalType: \"uint16\";\n readonly name: \"minConfirmations\";\n readonly type: \"uint16\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"blockNumber\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint64\";\n readonly name: \"expiryPushChainHeight\";\n readonly type: \"uint64\";\n },\n {\n readonly internalType: \"uint256\";\n readonly name: \"maxFee\";\n readonly type: \"uint256\";\n },\n {\n readonly internalType: \"address\";\n readonly name: \"revertRecipient\";\n readonly type: \"address\";\n }\n ];\n readonly name: \"spec\";\n readonly type: \"tuple\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n },\n {\n readonly name: \"callbackGasLimit\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"read\";\n readonly outputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"payable\";\n readonly type: \"function\";\n}" + }, + "1": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"universalCallback_\";\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"constructor\";\n}" + }, + "2": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"initialize\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n}" + }, + "3": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"getLocalContext\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "4": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"hasResult\";\n readonly outputs: readonly [\n {\n readonly type: \"bool\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "5": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n }\n ];\n readonly name: \"onUniversalData\";\n readonly outputs: readonly [\n ];\n readonly stateMutability: \"nonpayable\";\n readonly type: \"function\";\n}" + }, + "6": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"queryKeyOf\";\n readonly outputs: readonly [\n {\n readonly type: \"bytes32\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "7": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"readerOf\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "8": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"requestOrderOf\";\n readonly outputs: readonly [\n {\n readonly type: \"uint256\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "9": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"universalCallback\";\n readonly outputs: readonly [\n {\n readonly type: \"address\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "10": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n }\n ];\n readonly name: \"resultByRequestId\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "11": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"latestResult\";\n readonly outputs: readonly [\n {\n readonly components: readonly [\n {\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly name: \"resultData\";\n readonly type: \"bytes\";\n },\n {\n readonly name: \"updatedAtBlock\";\n readonly type: \"uint64\";\n }\n ];\n readonly type: \"tuple\";\n }\n ];\n readonly stateMutability: \"view\";\n readonly type: \"function\";\n}" + }, + "12": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly name: \"version\";\n readonly type: \"uint64\";\n }\n ];\n readonly name: \"Initialized\";\n readonly type: \"event\";\n}" + }, + "13": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadRequested\";\n readonly type: \"event\";\n}" + }, + "14": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n {\n readonly indexed: true;\n readonly name: \"requestId\";\n readonly type: \"uint256\";\n },\n {\n readonly indexed: true;\n readonly name: \"reader\";\n readonly type: \"address\";\n },\n {\n readonly indexed: true;\n readonly name: \"queryKey\";\n readonly type: \"bytes32\";\n }\n ];\n readonly name: \"RegistryReadStored\";\n readonly type: \"event\";\n}" + }, + "15": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"InvalidInitialization\";\n readonly type: \"error\";\n}" + }, + "16": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"NotInitializing\";\n readonly type: \"error\";\n}" + }, + "17": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"UnauthorizedCaller\";\n readonly type: \"error\";\n}" + }, + "18": { + "optional": false, + "readonly": true, + "type": "{\n readonly inputs: readonly [\n ];\n readonly name: \"ZeroAddressInit\";\n readonly type: \"error\";\n}" + }, + "length": { + "optional": false, + "readonly": true, + "type": "19" + } + } + }, + "PushChainExecutionError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").PushChainExecutionError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + } + } + }, + "PushChainBatchExecutionError": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").PushChainBatchExecutionError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "pendingTransactionHash": { + "optional": true, + "readonly": true, + "type": "`0x${string}` | undefined" + }, + "transactionHashes": { + "optional": false, + "readonly": true, + "type": "`0x${string}`[]" + } + } + }, + "DecodedErrorPayload": { + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload", + "members": { + "decoded": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "hint": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "name": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "selector": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "PushChainInitializeOptions": { + "type": "import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions", + "members": { + "agenticWallet": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "blockExplorers": { + "optional": true, + "readonly": false, + "type": "Partial> | undefined" + }, + "network": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "printTraces": { + "optional": true, + "readonly": false, + "type": "boolean | undefined" + }, + "progressHook": { + "optional": true, + "readonly": false, + "type": "((progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void) | undefined" + }, + "rpcUrls": { + "optional": true, + "readonly": false, + "type": "Partial> | undefined" + } + } + }, + "AGENTIC_ERROR_CODE": { + "type": "{\n readonly AGENT_GAS_INSUFFICIENT: \"AGENT_GAS_INSUFFICIENT\";\n readonly AGENT_IS_OWNER: \"AGENT_IS_OWNER\";\n readonly AMBIGUOUS_RULE: \"AMBIGUOUS_RULE\";\n readonly ASSET_CHAIN_MISMATCH: \"ASSET_CHAIN_MISMATCH\";\n readonly CAPABILITY_UNAVAILABLE: \"CAPABILITY_UNAVAILABLE\";\n readonly DELETE_NEEDS_TARGET: \"DELETE_NEEDS_TARGET\";\n readonly DUPLICATE_RULE: \"DUPLICATE_RULE\";\n readonly FROM_NOT_ALLOWED: \"FROM_NOT_ALLOWED\";\n readonly INCONSISTENT_READ: \"INCONSISTENT_READ\";\n readonly INDEX_RACE: \"INDEX_RACE\";\n readonly INVALID_RULE: \"INVALID_RULE\";\n readonly NO_RULES_FOR_CHAIN: \"NO_RULES_FOR_CHAIN\";\n readonly NOT_AGENTIC_WALLET: \"NOT_AGENTIC_WALLET\";\n readonly NOT_ALLOWED_IN_AGENTIC_MODE: \"NOT_ALLOWED_IN_AGENTIC_MODE\";\n readonly NOT_OWNER_OR_AGENT: \"NOT_OWNER_OR_AGENT\";\n readonly NOT_WALLET_OWNER: \"NOT_WALLET_OWNER\";\n readonly READ_ONLY: \"READ_ONLY\";\n readonly RECEIPT_MISMATCH: \"RECEIPT_MISMATCH\";\n readonly RECEIPT_UNAVAILABLE: \"RECEIPT_UNAVAILABLE\";\n readonly REQUEST_REJECTED: \"REQUEST_REJECTED\";\n readonly RULE_NOT_FOUND: \"RULE_NOT_FOUND\";\n readonly RULE_READ_FAILED: \"RULE_READ_FAILED\";\n readonly TARGET_NOT_ON_RULE_CHAIN: \"TARGET_NOT_ON_RULE_CHAIN\";\n readonly TOKEN_ROUTE_UNAVAILABLE: \"TOKEN_ROUTE_UNAVAILABLE\";\n readonly WALLET_BALANCE_INSUFFICIENT: \"WALLET_BALANCE_INSUFFICIENT\";\n readonly WALLET_NOT_DEPLOYED: \"WALLET_NOT_DEPLOYED\";\n}", + "members": { + "AGENT_GAS_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"AGENT_GAS_INSUFFICIENT\"" + }, + "AGENT_IS_OWNER": { + "optional": false, + "readonly": true, + "type": "\"AGENT_IS_OWNER\"" + }, + "AMBIGUOUS_RULE": { + "optional": false, + "readonly": true, + "type": "\"AMBIGUOUS_RULE\"" + }, + "ASSET_CHAIN_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"ASSET_CHAIN_MISMATCH\"" + }, + "CAPABILITY_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"CAPABILITY_UNAVAILABLE\"" + }, + "DELETE_NEEDS_TARGET": { + "optional": false, + "readonly": true, + "type": "\"DELETE_NEEDS_TARGET\"" + }, + "DUPLICATE_RULE": { + "optional": false, + "readonly": true, + "type": "\"DUPLICATE_RULE\"" + }, + "FROM_NOT_ALLOWED": { + "optional": false, + "readonly": true, + "type": "\"FROM_NOT_ALLOWED\"" + }, + "INCONSISTENT_READ": { + "optional": false, + "readonly": true, + "type": "\"INCONSISTENT_READ\"" + }, + "INDEX_RACE": { + "optional": false, + "readonly": true, + "type": "\"INDEX_RACE\"" + }, + "INVALID_RULE": { + "optional": false, + "readonly": true, + "type": "\"INVALID_RULE\"" + }, + "NO_RULES_FOR_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"NO_RULES_FOR_CHAIN\"" + }, + "NOT_AGENTIC_WALLET": { + "optional": false, + "readonly": true, + "type": "\"NOT_AGENTIC_WALLET\"" + }, + "NOT_ALLOWED_IN_AGENTIC_MODE": { + "optional": false, + "readonly": true, + "type": "\"NOT_ALLOWED_IN_AGENTIC_MODE\"" + }, + "NOT_OWNER_OR_AGENT": { + "optional": false, + "readonly": true, + "type": "\"NOT_OWNER_OR_AGENT\"" + }, + "NOT_WALLET_OWNER": { + "optional": false, + "readonly": true, + "type": "\"NOT_WALLET_OWNER\"" + }, + "READ_ONLY": { + "optional": false, + "readonly": true, + "type": "\"READ_ONLY\"" + }, + "RECEIPT_MISMATCH": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_MISMATCH\"" + }, + "RECEIPT_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"RECEIPT_UNAVAILABLE\"" + }, + "REQUEST_REJECTED": { + "optional": false, + "readonly": true, + "type": "\"REQUEST_REJECTED\"" + }, + "RULE_NOT_FOUND": { + "optional": false, + "readonly": true, + "type": "\"RULE_NOT_FOUND\"" + }, + "RULE_READ_FAILED": { + "optional": false, + "readonly": true, + "type": "\"RULE_READ_FAILED\"" + }, + "TARGET_NOT_ON_RULE_CHAIN": { + "optional": false, + "readonly": true, + "type": "\"TARGET_NOT_ON_RULE_CHAIN\"" + }, + "TOKEN_ROUTE_UNAVAILABLE": { + "optional": false, + "readonly": true, + "type": "\"TOKEN_ROUTE_UNAVAILABLE\"" + }, + "WALLET_BALANCE_INSUFFICIENT": { + "optional": false, + "readonly": true, + "type": "\"WALLET_BALANCE_INSUFFICIENT\"" + }, + "WALLET_NOT_DEPLOYED": { + "optional": false, + "readonly": true, + "type": "\"WALLET_NOT_DEPLOYED\"" + } + } + }, + "AgenticError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticError", + "members": { + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "Code" + }, + "details": { + "optional": true, + "readonly": true, + "type": "Readonly> | undefined" + }, + "hint": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "userMessage": { + "optional": false, + "readonly": true, + "type": "string" + } + } + }, + "AgenticRevertError": { + "type": "import(\"sdk/src/lib/agentic/errors\").AgenticRevertError", + "members": { + "agenticCode": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "cause": { + "optional": true, + "readonly": true, + "type": "unknown" + }, + "code": { + "optional": false, + "readonly": true, + "type": "\"PUSH_CHAIN_EXECUTION_FAILED\"" + }, + "decodedError": { + "optional": true, + "readonly": true, + "type": "import(\"sdk/src/lib/orchestrator/internals/errors\").DecodedErrorPayload | undefined" + }, + "gatewayTxHash": { + "optional": true, + "readonly": true, + "type": "string | undefined" + }, + "userMessage": { + "optional": false, + "readonly": true, + "type": "string" + } + } + }, + "AgenticAddress": { + "type": "`0x${string}`", + "members": {} + }, + "AgenticDoor": { + "type": "\"agent\" | \"owner\"", + "members": {} + }, + "AgenticErrorCode": { + "type": "\"AGENT_GAS_INSUFFICIENT\" | \"AGENT_IS_OWNER\" | \"AMBIGUOUS_RULE\" | \"ASSET_CHAIN_MISMATCH\" | \"CAPABILITY_UNAVAILABLE\" | \"DELETE_NEEDS_TARGET\" | \"DUPLICATE_RULE\" | \"FROM_NOT_ALLOWED\" | \"INCONSISTENT_READ\" | \"INDEX_RACE\" | \"INVALID_RULE\" | \"NO_RULES_FOR_CHAIN\" | \"NOT_AGENTIC_WALLET\" | \"NOT_ALLOWED_IN_AGENTIC_MODE\" | \"NOT_OWNER_OR_AGENT\" | \"NOT_WALLET_OWNER\" | \"READ_ONLY\" | \"RECEIPT_MISMATCH\" | \"RECEIPT_UNAVAILABLE\" | \"REQUEST_REJECTED\" | \"RULE_NOT_FOUND\" | \"RULE_READ_FAILED\" | \"TARGET_NOT_ON_RULE_CHAIN\" | \"TOKEN_ROUTE_UNAVAILABLE\" | \"WALLET_BALANCE_INSUFFICIENT\" | \"WALLET_NOT_DEPLOYED\"", + "members": {} + }, + "AgenticHex": { + "type": "`0x${string}`", + "members": {} + }, + "AgenticNamespace": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace", + "members": { + "create": { + "optional": false, + "readonly": false, + "type": "(label: string, options: import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions) => Promise" + }, + "derive": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n index?: number;\n}) => Promise<{\n address: `0x${string}`;\n deployed: boolean;\n index: number;\n}>" + }, + "list": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n wallets: import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary[];\n}>" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "(address: `0x${string}`) => import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet" + } + } + }, + "AgenticProgressHook": { + "type": "(event: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void", + "members": {} + }, + "AgenticTxMetadata": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticTxMetadata", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "destinationAccount": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "destinationCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "destinationInstruction": { + "optional": true, + "readonly": false, + "type": "{\n accounts: readonly {\n isWritable: boolean;\n pubkey: `0x${string}`;\n }[];\n data: `0x${string}`;\n program: `0x${string}`;\n} | undefined" + }, + "destinationTransfer": { + "optional": true, + "readonly": false, + "type": "{\n amount: bigint;\n recipient: `0x${string}`;\n token: `0x${string}`;\n} | undefined" + }, + "door": { + "optional": false, + "readonly": false, + "type": "\"agent\" | \"owner\"" + }, + "nativeCalls": { + "optional": true, + "readonly": false, + "type": "readonly {\n data: `0x${string}`;\n to: `0x${string}`;\n value: bigint;\n}[] | undefined" + }, + "rawData": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rawTo": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesId": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "AgenticWallet": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticWallet", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "checkpoints": { + "optional": false, + "readonly": false, + "type": "(opts?: {\n sinceBlock?: bigint;\n}) => Promise<{\n checkpoints: import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint[];\n}>" + }, + "info": { + "optional": false, + "readonly": false, + "type": "() => Promise" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "() => Promise<{\n owner: `0x${string}`;\n}>" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "{\n add(rules: import(\"sdk/src/lib/agentic/agentic.types\").RuleInput[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise<{\n rulesIds: `0x${string}`[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n delete(rulesIds: `0x${string}`[], opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n delete(params: {\n all: true;\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n }): Promise;\n get(rulesId: `0x${string}`): Promise;\n list(): Promise<{\n rules: import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord[];\n }>;\n update(params: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n rules: {\n rule: import(\"sdk/src/lib/agentic/agentic.types\").RuleInput;\n rulesId: `0x${string}`;\n }[];\n }): Promise<{\n rules: {\n replaced: `0x${string}`;\n rulesId: `0x${string}`;\n }[];\n tx: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse;\n }>;\n}" + }, + "setLabel": { + "optional": false, + "readonly": false, + "type": "(label: string, opts?: {\n progressHook?: import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook;\n}) => Promise" + } + } + }, + "AllowedCall": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleCall", + "members": { + "app": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "label": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "maxValue": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "pins": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Pin[] | undefined" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector" + }, + "target": { + "optional": false, + "readonly": false, + "type": "string" + } + } + }, + "AssetCap": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset", + "members": { + "maxPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/tokens\").MoveableToken | string" + } + } + }, + "Checkpoint": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Checkpoint", + "members": { + "blockNumber": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "kind": { + "optional": false, + "readonly": false, + "type": "\"OWNER_ACTION\" | \"RULES_GRANTED\" | \"RULES_REVOKED\"" + }, + "ref": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "seq": { + "optional": false, + "readonly": false, + "type": "number" + }, + "txHash": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "CheckpointKind": { + "type": "\"OWNER_ACTION\" | \"RULES_GRANTED\" | \"RULES_REVOKED\"", + "members": {} + }, + "CreateOptions": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateOptions", + "members": { + "progressHook": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticProgressHook | undefined" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleInput[]" + } + } + }, + "CreateResult": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").CreateResult", + "members": { + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "rulesIds": { + "optional": false, + "readonly": false, + "type": "`0x${string}`[]" + }, + "tx": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalTxResponse" + }, + "wallet": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + } + } + }, + "ForeignChainNamespace": { + "type": "`eip155:${string}` | `solana:${string}`", + "members": {} + }, + "DecodedSolanaRule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").DecodedSolanaRule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "assets": { + "optional": false, + "readonly": false, + "type": "{\n maxPerCall: bigint;\n maxTotal: bigint;\n token: string;\n}[]" + }, + "ceaAccounts": { + "optional": false, + "readonly": false, + "type": "readonly `0x${string}`[]" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "`solana:${string}`" + }, + "dataPins": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/agentic/codec/svm-terms\").SvmDataPinWire[]" + }, + "expectedCEA": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "format": { + "optional": false, + "readonly": false, + "type": "\"decoded\"" + }, + "gatewayProgram": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "maxGasPerCall": { + "optional": false, + "readonly": false, + "type": "bigint" + }, + "pins": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/agentic/codec/svm-terms\").SvmAccountPinWire[]" + }, + "programs": { + "optional": false, + "readonly": false, + "type": "readonly import(\"sdk/src/lib/agentic/codec/svm-terms\").AllowedProgramWire[]" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Rule": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").Rule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleCall[]" + }, + "assets": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset[] | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "maxGasPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "RuleInput": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").DecodedSolanaRule | import(\"sdk/src/lib/agentic/agentic.types\").Rule", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "assets": { + "optional": true, + "readonly": false, + "type": "{\n maxPerCall: bigint;\n maxTotal: bigint;\n token: string;\n}[] | import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset[] | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "maxGasPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Pin": { + "type": "{\n account: number;\n arg?: never;\n expected: \"agentic:wallet\" | string;\n max?: never;\n token?: import(\"sdk/src/lib/constants/tokens\").MoveableToken | string;\n} | {\n account?: never;\n arg: import(\"sdk/src/lib/agentic/agentic.types\").ArgumentPath;\n expected: \"agentic:wallet\" | `0x${string}` | `0x${string}` | bigint;\n max?: never;\n} | {\n account?: never;\n arg: import(\"sdk/src/lib/agentic/agentic.types\").ArgumentPath;\n expected?: never;\n max: bigint;\n}", + "members": { + "account": { + "optional": true, + "readonly": false, + "type": "number | undefined" + }, + "arg": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ArgumentPath | undefined" + }, + "expected": { + "optional": true, + "readonly": false, + "type": "bigint | string | undefined" + }, + "max": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + } + } + }, + "Spent": { + "type": "{\n actions: {\n amountSpent: bigint;\n callsUsed: number;\n selector: \"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector;\n target: `0x${string}`;\n valueSpent: bigint;\n }[];\n kind: \"native\";\n} | {\n amountSpent: bigint;\n callsUsed: number;\n kind: \"native\";\n valueSpent: bigint;\n} | {\n assets: {\n spent: bigint;\n token: string;\n }[];\n kind: \"universal\";\n}", + "members": { + "kind": { + "optional": false, + "readonly": false, + "type": "\"native\" | \"universal\"" + } + } + }, + "WalletMarker": { + "type": "\"agentic:wallet\"", + "members": {} + }, + "ArgumentPath": { + "type": "number | readonly number[]", + "members": {} + }, + "RulesRecord": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RulesRecord", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "string" + }, + "enabled": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "rule": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").DecodedSolanaRule | import(\"sdk/src/lib/agentic/agentic.types\").Rule" + }, + "rulesId": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "spent": { + "optional": false, + "readonly": false, + "type": "{\n actions: {\n amountSpent: bigint;\n callsUsed: number;\n selector: \"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector;\n target: `0x${string}`;\n valueSpent: bigint;\n }[];\n kind: \"native\";\n} | {\n amountSpent: bigint;\n callsUsed: number;\n kind: \"native\";\n valueSpent: bigint;\n} | {\n assets: {\n spent: bigint;\n token: string;\n }[];\n kind: \"universal\";\n}" + }, + "validUntil": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "Selector": { + "type": "`${string}(${string})` | `0x${string}`", + "members": {} + }, + "WalletInfo": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").WalletInfo", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "label": { + "optional": false, + "readonly": false, + "type": "string" + }, + "owner": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "rulesCount": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "WalletSummary": { + "type": "import(\"sdk/src/lib/agentic/agentic.types\").WalletSummary", + "members": { + "address": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "deployed": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "index": { + "optional": false, + "readonly": false, + "type": "number" + }, + "label": { + "optional": false, + "readonly": false, + "type": "string" + }, + "rulesCount": { + "optional": false, + "readonly": false, + "type": "number" + } + } + }, + "PushChain": { + "type": "import(\"sdk/src/lib/push-chain/push-chain\").PushChain", + "members": { + "accountStatus": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus" + }, + "accountStatusReady": { + "optional": false, + "readonly": false, + "type": "Promise" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace" + }, + "explorer": { + "optional": false, + "readonly": false, + "type": "{\n getTransactionUrl: (txHash: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n listAllUrls: () => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n listUrls: (options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n}" + }, + "funds": { + "optional": false, + "readonly": false, + "type": "{\n getConversionQuote: (amountIn: bigint, options: {\n from: import(\"sdk/src/lib/constants/tokens\").PayableToken | undefined;\n to: import(\"sdk/src/lib/constants/tokens\").MoveableToken | undefined;\n }) => Promise;\n}" + }, + "getAccountStatus": { + "optional": false, + "readonly": false, + "type": "(options?: {\n forceRefresh?: boolean;\n}) => Promise" + }, + "isReadMode": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "job": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/job/types\").JobNamespace" + }, + "market": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/market/types\").MarketNamespace" + }, + "moveable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").MoveableTokenAccessor;\n}" + }, + "payable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").PayableTokenAccessor;\n}" + }, + "reinitialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "universal": { + "optional": false, + "readonly": false, + "type": "{\n readonly account: `0x${string}`;\n executeReads: (reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>;\n executeTransactions: (txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise;\n migrateCEA: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"migrateCEA\"];\n readonly origin: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n prepareRead: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n prepareTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"prepareTransaction\"];\n read: ((subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>) & {\n prepare: (options: import(\"sdk/src/lib/job-spec/types\").PrepareJobReadOptions) => import(\"sdk/src/lib/job-spec/types\").PreparedJobRead;\n };\n rescueFunds: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"rescueFunds\"];\n sendTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"execute\"];\n signMessage: (data: Uint8Array) => Promise;\n signTypedData: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n trackRead: {\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n };\n trackTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"trackTransaction\"];\n}" + }, + "upgradeAccount": { + "optional": false, + "readonly": false, + "type": "(options?: {\n progressHook?: (progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n}) => Promise" + } + } + }, + "Preset": { + "type": "import(\"sdk/src/lib/agentic/presets/types\").Preset", + "members": { + "chains": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace[]" + }, + "constant": { + "optional": false, + "readonly": false, + "type": "\"DEXES\" | \"LENDING\" | \"PREDICTION\" | \"STAKING\"" + }, + "name": { + "optional": false, + "readonly": false, + "type": "string" + }, + "type": { + "optional": false, + "readonly": false, + "type": "\"CATEGORY\"" + } + } + }, + "PresetCategory": { + "type": "\"DEXES\" | \"LENDING\" | \"PREDICTION\" | \"STAKING\"", + "members": {} + }, + "PresetAsset": { + "type": "import(\"sdk/src/lib/agentic/presets/types\").PresetAsset", + "members": { + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "maxPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "maxTotal": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "token": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/tokens\").MoveableToken | string" + } + } + }, + "PresetOptions": { + "type": "import(\"sdk/src/lib/agentic/presets/types\").PresetOptions", + "members": { + "agent": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "assets": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/presets/types\").PresetAsset[] | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "funding": { + "optional": true, + "readonly": false, + "type": "\"destination\" | \"push\" | undefined" + }, + "maxGasPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "network": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK | undefined" + }, + "validUntil": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "ReadyPresetOptions": { + "type": "import(\"sdk/src/lib/agentic/presets/types\").ReadyPresetOptions", + "members": { + "agent": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "assets": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/presets/types\").PresetAsset[] | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "funding": { + "optional": true, + "readonly": false, + "type": "\"destination\" | \"push\" | undefined" + }, + "maxGasPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "network": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK | undefined" + }, + "validUntil": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "PresetRuleTemplate": { + "type": "{\n agent?: `0x${string}`;\n validUntil?: number;\n} & Omit", + "members": { + "agent": { + "optional": true, + "readonly": false, + "type": "`0x${string}` | undefined" + }, + "allowedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleCall[]" + }, + "assets": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset[] | undefined" + }, + "chainNamespace": { + "optional": true, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").ForeignChainNamespace | undefined" + }, + "maxGasPerCall": { + "optional": true, + "readonly": false, + "type": "bigint | undefined" + }, + "validUntil": { + "optional": true, + "readonly": false, + "type": "number | undefined" + } + } + }, + "PresetResult": { + "type": "import(\"sdk/src/lib/agentic/presets/types\").PresetResult", + "members": { + "readiness": { + "optional": false, + "readonly": false, + "type": "{\n chains: import(\"sdk/src/lib/agentic/presets/types\").PresetChainReadiness[];\n ready: boolean;\n}" + }, + "rules": { + "optional": false, + "readonly": false, + "type": "T[]" + } + } + }, + "PresetChainReadiness": { + "type": "import(\"sdk/src/lib/agentic/presets/types\").PresetChainReadiness", + "members": { + "bridgeAssets": { + "optional": false, + "readonly": false, + "type": "{\n prc20?: `0x${string}`;\n status: \"registered\" | \"unavailable\";\n token: string;\n}[]" + }, + "chainNamespace": { + "optional": false, + "readonly": false, + "type": "`eip155:${string}` | `solana:${string}`" + }, + "configurationReady": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "disabledCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/presets/types\").PresetCallIssue[]" + }, + "excludedCalls": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/presets/types\").PresetCallIssue[]" + }, + "funding": { + "optional": false, + "readonly": false, + "type": "\"destination\" | \"push\"" + }, + "issues": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/presets/types\").PresetConfigurationIssue[]" + }, + "knownTokens": { + "optional": false, + "readonly": false, + "type": "string[]" + }, + "ready": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "selectedAssets": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").RuleAsset[]" + }, + "zeroBridgeLimits": { + "optional": false, + "readonly": false, + "type": "string[]" + } + } + }, + "PresetConfigurationIssue": { + "type": "import(\"sdk/src/lib/agentic/presets/types\").PresetConfigurationIssue", + "members": { + "code": { + "optional": false, + "readonly": false, + "type": "\"AGENT_REQUIRED\" | \"AGW_NETWORK_UNAVAILABLE\" | \"ASSETS_REQUIRED\" | \"BRIDGE_ASSET_UNAVAILABLE\" | \"DESTINATION_UNAVAILABLE\" | \"EXPIRY_REQUIRED\" | \"GAS_BUDGET_REQUIRED\" | \"NO_ENABLED_OPERATION\" | \"TOKEN_PAIR_REQUIRED\"" + }, + "message": { + "optional": false, + "readonly": false, + "type": "string" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "PresetCallIssue": { + "type": "import(\"sdk/src/lib/agentic/presets/types\").PresetCallIssue", + "members": { + "alternative": { + "optional": true, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector | undefined" + }, + "app": { + "optional": true, + "readonly": false, + "type": "string | undefined" + }, + "reason": { + "optional": false, + "readonly": false, + "type": "\"DYNAMIC_AMOUNT\" | \"POSITION_AMOUNT\" | \"SHARE_AMOUNT\" | \"TOKEN_REQUIRED\" | \"UNSELECTED_TOKEN\" | \"ZERO_CAP\"" + }, + "selector": { + "optional": false, + "readonly": false, + "type": "\"value-only\" | import(\"sdk/src/lib/agentic/agentic.types\").Selector" + }, + "target": { + "optional": false, + "readonly": false, + "type": "string" + }, + "token": { + "optional": true, + "readonly": false, + "type": "string | undefined" + } + } + }, + "AgenticPresets": { + "type": "import(\"sdk/src/lib/agentic/presets/types\").AgenticPresets", + "members": { + "get": { + "optional": false, + "readonly": false, + "type": "{\n (preset: import(\"sdk/src/lib/agentic/presets/types\").PresetCategory, options: import(\"sdk/src/lib/agentic/presets/types\").ReadyPresetOptions): import(\"sdk/src/lib/agentic/presets/types\").PresetResult;\n (preset: import(\"sdk/src/lib/agentic/presets/types\").PresetCategory, options?: import(\"sdk/src/lib/agentic/presets/types\").PresetOptions): import(\"sdk/src/lib/agentic/presets/types\").PresetResult;\n}" + }, + "list": { + "optional": false, + "readonly": false, + "type": "(options?: {\n type?: \"CATEGORY\";\n}) => {\n presets: import(\"sdk/src/lib/agentic/presets/types\").Preset[];\n}" + } + } + } + }, + "pushChainStatic": { + "CONSTANTS": { + "optional": false, + "readonly": false, + "type": "{\n AGENTIC: Readonly<{\n JOB: Readonly<{\n ADDRESS: Readonly<{\n \"eip155:42101\": Readonly<{\n EVALUATOR: \"0x1afC81396f1bb36F91f74506284952b81e4bd47c\";\n HOOK: \"0xDe7A94e510b6C571DE7880d441349689F73A32b3\";\n KERNEL: \"0x977cf1AC973E9eC4332791d531507575006157Ed\";\n }>;\n }>;\n ALLOWED_MUTABILITY: Readonly<{\n readonly BOTH: \"BOTH\";\n readonly CLIENT: \"CLIENT\";\n readonly NONE: \"NONE\";\n readonly PROVIDER: \"PROVIDER\";\n }>;\n EVALUATION: Readonly<{\n readonly BOOLEAN: \"BOOLEAN\";\n readonly COMPARE: \"COMPARE\";\n readonly NUMBER: \"NUMBER\";\n readonly PERCENTAGE: \"PERCENTAGE\";\n }>;\n LOGIC: Readonly<{\n readonly ALL: \"ALL\";\n readonly ANY: \"ANY\";\n readonly AT_LEAST: \"AT_LEAST\";\n }>;\n OPERATION: Readonly<{\n readonly EQUAL: \"EQUAL\";\n readonly GREATER_OR_EQUAL: \"GREATER_OR_EQUAL\";\n readonly GREATER_THAN: \"GREATER_THAN\";\n readonly LESS_OR_EQUAL: \"LESS_OR_EQUAL\";\n readonly LESS_THAN: \"LESS_THAN\";\n readonly NOT_EQUAL: \"NOT_EQUAL\";\n }>;\n }>;\n PRESETS: Readonly<{\n CATEGORY: Readonly<{\n DEXES: \"DEXES\";\n LENDING: \"LENDING\";\n PREDICTION: \"PREDICTION\";\n STAKING: \"STAKING\";\n }>;\n }>;\n PRINCIPAL: \"agentic:principal\";\n WALLET: \"agentic:wallet\";\n }>;\n CHAIN: typeof import(\"sdk/src/lib/constants/enums\").CHAIN;\n LIBRARY: typeof import(\"sdk/src/lib/constants/enums\").LIBRARY;\n MOVEABLE: {\n TOKEN: import(\"sdk/src/lib/constants/tokens\").MoveableTokenConstantsMap;\n };\n PAYABLE: {\n TOKEN: import(\"sdk/src/lib/constants/tokens\").PayableTokenConstantsMap;\n };\n PUSH_NETWORK: typeof import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n READ: {\n readonly CALLBACK_BUDGET_BUFFER: 3;\n readonly CHAIN: {\n readonly WEB2: \"web2\";\n } & Readonly<{\n readonly ARBITRUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA;\n readonly BASE_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA;\n readonly BNB_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET;\n readonly ETHEREUM_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET;\n readonly ETHEREUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA;\n readonly PUSH_LOCALNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET;\n readonly PUSH_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET;\n readonly PUSH_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly PUSH_TESTNET_DONUT: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly SOLANA_DEVNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET;\n readonly SOLANA_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET;\n readonly SOLANA_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n readonly WEB2: \"web2\";\n }>;\n readonly DEFAULT_EXPIRY_BLOCKS: 300n;\n readonly ERROR_CODE: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n readonly MAX_CALLBACK_GAS_LIMIT: 1000000n;\n readonly MIN_CONFIRMATIONS_FLOOR: 1;\n readonly NAMESPACE: {\n readonly EVM: \"eip155\";\n readonly SVM: \"solana\";\n readonly WEB2: \"web2\";\n };\n readonly OUTCOME: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME;\n readonly REGISTRY_CALLBACK_GAS: 500000n;\n readonly RESULT_STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n readonly STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS;\n readonly UNIVERSAL_CALLBACK_ADDRESSES: Record;\n readonly UNIVERSAL_CORE_ADDRESSES: Record;\n readonly UNIVERSAL_READ_REGISTRY_ADDRESS: {\n readonly TESTNET_DONUT: \"0x00000000000000000000000000000000000000b2\";\n };\n readonly WEB2: \"web2\";\n readonly WEB2_DEFAULT_TIMEOUT_MS: 5000;\n readonly WEB2_MAX_EXTRACT_ENTRIES: 16;\n };\n}" + }, + "initialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "utils": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/utils\").Utils" + } + }, + "pushChainInstance": { + "accountStatus": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/orchestrator/orchestrator.types\").AccountStatus" + }, + "accountStatusReady": { + "optional": false, + "readonly": false, + "type": "Promise" + }, + "agentic": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/agentic/agentic.types\").AgenticNamespace" + }, + "explorer": { + "optional": false, + "readonly": false, + "type": "{\n getTransactionUrl: (txHash: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n listAllUrls: () => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n listUrls: (options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => {\n explorers: Array<{\n chain: string;\n chainName: string;\n urls: string[];\n }>;\n };\n}" + }, + "funds": { + "optional": false, + "readonly": false, + "type": "{\n getConversionQuote: (amountIn: bigint, options: {\n from: import(\"sdk/src/lib/constants/tokens\").PayableToken | undefined;\n to: import(\"sdk/src/lib/constants/tokens\").MoveableToken | undefined;\n }) => Promise;\n}" + }, + "getAccountStatus": { + "optional": false, + "readonly": false, + "type": "(options?: {\n forceRefresh?: boolean;\n}) => Promise" + }, + "isReadMode": { + "optional": false, + "readonly": false, + "type": "boolean" + }, + "job": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/job/types\").JobNamespace" + }, + "market": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/market/types\").MarketNamespace" + }, + "moveable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").MoveableTokenAccessor;\n}" + }, + "payable": { + "optional": false, + "readonly": false, + "type": "{\n token: import(\"sdk/src/lib/constants/tokens\").PayableTokenAccessor;\n}" + }, + "reinitialize": { + "optional": false, + "readonly": false, + "type": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise" + }, + "universal": { + "optional": false, + "readonly": false, + "type": "{\n readonly account: `0x${string}`;\n executeReads: (reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>;\n executeTransactions: (txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise;\n migrateCEA: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"migrateCEA\"];\n readonly origin: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n prepareRead: (subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>;\n prepareTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"prepareTransaction\"];\n read: ((subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>) & {\n prepare: (options: import(\"sdk/src/lib/job-spec/types\").PrepareJobReadOptions) => import(\"sdk/src/lib/job-spec/types\").PreparedJobRead;\n };\n rescueFunds: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"rescueFunds\"];\n sendTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"execute\"];\n signMessage: (data: Uint8Array) => Promise;\n signTypedData: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n trackRead: {\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n };\n trackTransaction: import(\"sdk/src/lib/orchestrator/orchestrator\").Orchestrator[\"trackTransaction\"];\n}" + }, + "upgradeAccount": { + "optional": false, + "readonly": false, + "type": "(options?: {\n progressHook?: (progress: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n}) => Promise" + } + }, + "transactionMethods": { + "account": { + "optional": false, + "readonly": false, + "type": "`0x${string}`" + }, + "executeReads": { + "optional": false, + "readonly": false, + "type": "(reads: R, options?: import(\"sdk/src/lib/read-state/read-params\").ReadExecuteOptions) => Promise>" + }, + "executeTransactions": { + "optional": false, + "readonly": false, + "type": "(txs: import(\"sdk/src/lib/orchestrator/orchestrator.types\").PreparedUniversalTx[], options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").CascadeExecutionOptions) => Promise" + }, + "migrateCEA": { + "optional": false, + "readonly": false, + "type": "(chain: import(\"sdk/src/lib/constants/enums\").CHAIN) => Promise" + }, + "origin": { + "optional": false, + "readonly": false, + "type": "import(\"sdk/src/lib/universal/universal.types\").UniversalAccount" + }, + "prepareRead": { + "optional": false, + "readonly": false, + "type": "(subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>" + }, + "prepareTransaction": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions) => Promise" + }, + "read": { + "optional": false, + "readonly": false, + "type": "((subject: string, options: import(\"sdk/src/lib/read-state/read-params\").ValidateReadCall & O) => Promise>>) & {\n prepare: (options: import(\"sdk/src/lib/job-spec/types\").PrepareJobReadOptions) => import(\"sdk/src/lib/job-spec/types\").PreparedJobRead;\n}" + }, + "rescueFunds": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").RescueFundsParams) => Promise" + }, + "sendTransaction": { + "optional": false, + "readonly": false, + "type": "(params: import(\"sdk/src/lib/orchestrator/orchestrator.types\").ExecuteParams | import(\"sdk/src/lib/orchestrator/orchestrator.types\").UniversalExecuteParams, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TransactionExecutionOptions) => Promise" + }, + "signMessage": { + "optional": false, + "readonly": false, + "type": "(data: Uint8Array) => Promise" + }, + "signTypedData": { + "optional": false, + "readonly": false, + "type": "({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n}) => Promise" + }, + "trackRead": { + "optional": false, + "readonly": false, + "type": "{\n (ref: {\n txHash: `0x${string}`;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n (ref: {\n requestId: `0x${string}` | bigint;\n }, options?: {\n progressHook?: (e: import(\"sdk/src/lib/progress-hook/progress-hook.types\").ProgressEvent) => void;\n } & import(\"sdk/src/lib/read-state/read-params\").ReadTrackOptions): Promise;\n}" + }, + "trackTransaction": { + "optional": false, + "readonly": false, + "type": "(txHash: string, options?: import(\"sdk/src/lib/orchestrator/orchestrator.types\").TrackTransactionOptions) => Promise" + } + }, + "utilityMethods": { + "account": { + "optional": false, + "readonly": false, + "type": "{\n convertExecutorToOriginAccount: (ueaAddress: `0x${string}`, options?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n }) => Promise;\n convertOriginToExecutor: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n onlyCompute?: boolean;\n }) => Promise;\n deriveExecutorAccount: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n skipNetworkCheck?: boolean;\n }) => Promise;\n fromChainAgnostic: (caip: string) => import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n resolveControllerAccount: (address: string, options?: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n skipNetworkCheck?: boolean;\n }) => Promise;\n toChainAgnostic: (address: string, options: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => string;\n toUniversal: (address: string, options: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n }) => import(\"sdk/src/lib/universal/universal.types\").UniversalAccount;\n}" + }, + "agentic": { + "optional": false, + "readonly": true, + "type": "{\n readonly presets: import(\"sdk/src/lib/agentic/presets/types\").AgenticPresets;\n}" + }, + "chains": { + "optional": false, + "readonly": false, + "type": "{\n getChainName: (chainNamespace: string) => string | undefined;\n getChainNamespace: (chainName: string) => string | undefined;\n getSupportedChains: (network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK) => {\n chains: import(\"sdk/src/lib/constants/enums\").CHAIN[];\n };\n getSupportedChainsByName: (network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK) => {\n chains: string[];\n };\n}" + }, + "conversion": { + "optional": false, + "readonly": false, + "type": "{\n slippageToMinAmount(amount: string, options: {\n slippageBps: number;\n }): string;\n}" + }, + "helpers": { + "optional": false, + "readonly": false, + "type": "{\n encodeTxData({ abi, idl, functionName, args, }: {\n abi?: any;\n args?: any[];\n functionName: string;\n idl?: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n }): `0x${string}`;\n formatUnits(value: bigint | string, decimalsOrOptions: {\n decimals: number;\n precision?: number;\n } | number): string;\n getChainName: (chainName: string) => string | undefined;\n parseUnits(value: string, exponent: {\n decimals: number;\n } | number): bigint;\n}" + }, + "job": { + "optional": false, + "readonly": true, + "type": "{\n readonly buildJobSpec: (options: import(\"sdk/src/lib/job-spec/types\").BuildJobSpecOptions) => import(\"sdk/src/lib/job-spec/types\").JobSpec;\n readonly buildJobSpecTemplate: (options: import(\"sdk/src/lib/job-spec/types\").BuildJobSpecTemplateOptions) => import(\"sdk/src/lib/job-spec/types\").JobSpecTemplate;\n readonly decodeJobSpec: (bytes: `0x${string}`, options?: {\n format?: \"spec\" | \"template\";\n }) => import(\"sdk/src/lib/job-spec/types\").JobSpec | import(\"sdk/src/lib/job-spec/types\").JobSpecTemplate;\n readonly describeJobSpec: (spec: import(\"sdk/src/lib/job-spec/types\").JobSpec | import(\"sdk/src/lib/job-spec/types\").JobSpecTemplate, options?: {\n decimals?: Record<`0x${string}`, number>;\n principal?: bigint;\n }) => {\n checks: string[];\n logic: string;\n timing: string;\n };\n readonly encodeJobSpec: (spec: import(\"sdk/src/lib/job-spec/types\").JobSpec | import(\"sdk/src/lib/job-spec/types\").JobSpecTemplate) => `0x${string}`;\n readonly prepareRead: (options: import(\"sdk/src/lib/job-spec/types\").PrepareJobReadOptions) => import(\"sdk/src/lib/job-spec/types\").PreparedJobRead;\n readonly previewJobSpec: (subject: import(\"sdk/src/lib/job-spec/types\").JobSpec | import(\"sdk/src/lib/job-spec/types\").JobSpecTemplate, options: import(\"sdk/src/lib/job-spec/types\").PreviewJobSpecOptions) => Promise;\n}" + }, + "market": { + "optional": false, + "readonly": true, + "type": "{\n readonly decodeAgentCardRules: (bytes: `0x${string}`, _options?: {\n chain?: string;\n }) => import(\"sdk/src/lib/market/rules\").AgentCardRules;\n readonly encodeAgentCardRules: (rules: import(\"sdk/src/lib/market/rules\").AgentCardRules, options: {\n chain: string;\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n }) => `0x${string}`;\n readonly validateAgentCardRules: (rules: import(\"sdk/src/lib/market/rules\").AgentCardRules) => void;\n}" + }, + "signer": { + "optional": false, + "readonly": false, + "type": "{\n construct: (account: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount, options: {\n signAndSendTransaction: (unsignedTx: Uint8Array) => Promise;\n signAuthorization?: (params: import(\"sdk/src/lib/universal/universal.types\").SignAuthorizationParams) => Promise;\n signMessage: (data: Uint8Array) => Promise;\n signTypedData?: ({ domain, types, primaryType, message, }: {\n domain: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedDataDomain;\n message: Record;\n primaryType: string;\n types: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").TypedData;\n }) => Promise;\n }) => import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton;\n toUniversal: (signer: import(\"sdk/src/lib/universal/universal.types\").EthersV5SignerType | import(\"sdk/src/lib/universal/universal.types\").EthersV6SignerType | import(\"sdk/src/lib/universal/universal.types\").UniversalSignerSkeleton | import(\"sdk/src/lib/universal/universal.types\").ViemSignerType) => Promise;\n toUniversalFromKeypair: (clientOrAccount: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@solana/web3.js/lib/index\").Keypair | import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem/_types/index\").WalletClient | import(\"sdk/src/lib/universal/universal.types\").EthersV6SignerType, { chain, library }: {\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n library: import(\"sdk/src/lib/constants/enums\").LIBRARY;\n }) => Promise;\n}" + }, + "svm": { + "optional": false, + "readonly": false, + "type": "{\n getRegisteredIdls: () => Array<{\n address: `0x${string}`;\n idl: import(\"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/@coral-xyz/anchor/dist/cjs/idl\").Idl;\n }>;\n registerIdl: (idl: unknown) => void;\n}" + }, + "tokens": { + "optional": false, + "readonly": false, + "type": "{\n getMoveableTokens(chainOrClient?: import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/push-chain/push-chain\").PushChain): {\n tokens: Array<{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n decimals: number;\n mechanism: \"approve\" | \"native\" | \"permit2\";\n prc20Address?: `0x${string}`;\n sourceChain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n symbol: string;\n }>;\n };\n getPayableTokens(chainOrClient?: import(\"sdk/src/lib/constants/enums\").CHAIN | import(\"sdk/src/lib/push-chain/push-chain\").PushChain): {\n tokens: Array<{\n address: string;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n chainName: string;\n decimals: number;\n mechanism: \"approve\" | \"native\" | \"permit2\";\n symbol: string;\n }>;\n };\n getPC20Address(address: string, options: {\n chain?: import(\"sdk/src/lib/constants/enums\").CHAIN;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n rpcUrls?: Partial>;\n strict?: boolean;\n }): Promise;\n getPRC20Address: (token: {\n address: string;\n chain: string;\n } | import(\"sdk/src/lib/constants/tokens\").MoveableToken, options?: {\n network?: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n }) => {\n address: `0x${string}`;\n chain: import(\"sdk/src/lib/constants/enums\").CHAIN;\n decimals: number;\n network: import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK;\n symbol: string;\n };\n}" + } + }, + "initialize": "(universalSigner: import(\"sdk/src/lib/universal/universal.types\").UniversalAccount | import(\"sdk/src/lib/universal/universal.types\").UniversalSigner, options?: import(\"sdk/src/lib/push-chain/push-chain\").PushChainInitializeOptions) => Promise", + "agwConstants": { + "JOB": { + "optional": false, + "readonly": true, + "type": "{\n readonly ADDRESS: Readonly<{\n \"eip155:42101\": Readonly<{\n EVALUATOR: \"0x1afC81396f1bb36F91f74506284952b81e4bd47c\";\n HOOK: \"0xDe7A94e510b6C571DE7880d441349689F73A32b3\";\n KERNEL: \"0x977cf1AC973E9eC4332791d531507575006157Ed\";\n }>;\n }>;\n readonly ALLOWED_MUTABILITY: Readonly<{\n readonly BOTH: \"BOTH\";\n readonly CLIENT: \"CLIENT\";\n readonly NONE: \"NONE\";\n readonly PROVIDER: \"PROVIDER\";\n }>;\n readonly EVALUATION: Readonly<{\n readonly BOOLEAN: \"BOOLEAN\";\n readonly COMPARE: \"COMPARE\";\n readonly NUMBER: \"NUMBER\";\n readonly PERCENTAGE: \"PERCENTAGE\";\n }>;\n readonly LOGIC: Readonly<{\n readonly ALL: \"ALL\";\n readonly ANY: \"ANY\";\n readonly AT_LEAST: \"AT_LEAST\";\n }>;\n readonly OPERATION: Readonly<{\n readonly EQUAL: \"EQUAL\";\n readonly GREATER_OR_EQUAL: \"GREATER_OR_EQUAL\";\n readonly GREATER_THAN: \"GREATER_THAN\";\n readonly LESS_OR_EQUAL: \"LESS_OR_EQUAL\";\n readonly LESS_THAN: \"LESS_THAN\";\n readonly NOT_EQUAL: \"NOT_EQUAL\";\n }>;\n}" + }, + "PRESETS": { + "optional": false, + "readonly": true, + "type": "{\n readonly CATEGORY: Readonly<{\n DEXES: \"DEXES\";\n LENDING: \"LENDING\";\n PREDICTION: \"PREDICTION\";\n STAKING: \"STAKING\";\n }>;\n}" + }, + "PRINCIPAL": { + "optional": false, + "readonly": true, + "type": "\"agentic:principal\"" + }, + "WALLET": { + "optional": false, + "readonly": true, + "type": "\"agentic:wallet\"" + } + }, + "constants": { + "AGENTIC": { + "optional": false, + "readonly": false, + "type": "{\n readonly JOB: Readonly<{\n ADDRESS: Readonly<{\n \"eip155:42101\": Readonly<{\n EVALUATOR: \"0x1afC81396f1bb36F91f74506284952b81e4bd47c\";\n HOOK: \"0xDe7A94e510b6C571DE7880d441349689F73A32b3\";\n KERNEL: \"0x977cf1AC973E9eC4332791d531507575006157Ed\";\n }>;\n }>;\n ALLOWED_MUTABILITY: Readonly<{\n readonly BOTH: \"BOTH\";\n readonly CLIENT: \"CLIENT\";\n readonly NONE: \"NONE\";\n readonly PROVIDER: \"PROVIDER\";\n }>;\n EVALUATION: Readonly<{\n readonly BOOLEAN: \"BOOLEAN\";\n readonly COMPARE: \"COMPARE\";\n readonly NUMBER: \"NUMBER\";\n readonly PERCENTAGE: \"PERCENTAGE\";\n }>;\n LOGIC: Readonly<{\n readonly ALL: \"ALL\";\n readonly ANY: \"ANY\";\n readonly AT_LEAST: \"AT_LEAST\";\n }>;\n OPERATION: Readonly<{\n readonly EQUAL: \"EQUAL\";\n readonly GREATER_OR_EQUAL: \"GREATER_OR_EQUAL\";\n readonly GREATER_THAN: \"GREATER_THAN\";\n readonly LESS_OR_EQUAL: \"LESS_OR_EQUAL\";\n readonly LESS_THAN: \"LESS_THAN\";\n readonly NOT_EQUAL: \"NOT_EQUAL\";\n }>;\n }>;\n readonly PRESETS: Readonly<{\n CATEGORY: Readonly<{\n DEXES: \"DEXES\";\n LENDING: \"LENDING\";\n PREDICTION: \"PREDICTION\";\n STAKING: \"STAKING\";\n }>;\n }>;\n readonly PRINCIPAL: \"agentic:principal\";\n readonly WALLET: \"agentic:wallet\";\n}" + }, + "CHAIN": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").CHAIN" + }, + "LIBRARY": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").LIBRARY" + }, + "MOVEABLE": { + "optional": false, + "readonly": false, + "type": "{\n TOKEN: import(\"sdk/src/lib/constants/tokens\").MoveableTokenConstantsMap;\n}" + }, + "PAYABLE": { + "optional": false, + "readonly": false, + "type": "{\n TOKEN: import(\"sdk/src/lib/constants/tokens\").PayableTokenConstantsMap;\n}" + }, + "PUSH_NETWORK": { + "optional": false, + "readonly": false, + "type": "typeof import(\"sdk/src/lib/constants/enums\").PUSH_NETWORK" + }, + "READ": { + "optional": false, + "readonly": false, + "type": "{\n readonly CALLBACK_BUDGET_BUFFER: 3;\n readonly CHAIN: {\n readonly WEB2: \"web2\";\n } & Readonly<{\n readonly ARBITRUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ARBITRUM_SEPOLIA;\n readonly BASE_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.BASE_SEPOLIA;\n readonly BNB_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.BNB_TESTNET;\n readonly ETHEREUM_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_MAINNET;\n readonly ETHEREUM_SEPOLIA: import(\"sdk/src/lib/constants/enums\").CHAIN.ETHEREUM_SEPOLIA;\n readonly PUSH_LOCALNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_LOCALNET;\n readonly PUSH_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_MAINNET;\n readonly PUSH_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly PUSH_TESTNET_DONUT: import(\"sdk/src/lib/constants/enums\").CHAIN.PUSH_TESTNET;\n readonly SOLANA_DEVNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_DEVNET;\n readonly SOLANA_MAINNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_MAINNET;\n readonly SOLANA_TESTNET: import(\"sdk/src/lib/constants/enums\").CHAIN.SOLANA_TESTNET;\n readonly WEB2: \"web2\";\n }>;\n readonly DEFAULT_EXPIRY_BLOCKS: 300n;\n readonly ERROR_CODE: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_ERROR_CODE;\n readonly MAX_CALLBACK_GAS_LIMIT: 1000000n;\n readonly MIN_CONFIRMATIONS_FLOOR: 1;\n readonly NAMESPACE: {\n readonly EVM: \"eip155\";\n readonly SVM: \"solana\";\n readonly WEB2: \"web2\";\n };\n readonly OUTCOME: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_OUTCOME;\n readonly REGISTRY_CALLBACK_GAS: 500000n;\n readonly RESULT_STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").READ_STATUS;\n readonly STATUS: typeof import(\"sdk/src/lib/read-state/read-state.types\").UNIVERSAL_READ_STATUS;\n readonly UNIVERSAL_CALLBACK_ADDRESSES: Record;\n readonly UNIVERSAL_CORE_ADDRESSES: Record;\n readonly UNIVERSAL_READ_REGISTRY_ADDRESS: {\n readonly TESTNET_DONUT: \"0x00000000000000000000000000000000000000b2\";\n };\n readonly WEB2: \"web2\";\n readonly WEB2_DEFAULT_TIMEOUT_MS: 5000;\n readonly WEB2_MAX_EXTRACT_ENTRIES: 16;\n}" + } + } + }, + "scope": "All root exports and declared public members, PushChain static/instance members, universal transaction methods, utility groups, readonly/optional markers and constants. Behavior/default/deployment changes need the written session review." +} diff --git a/plan/marketplace/research/sdk-completion-2026-10-20/checked-files.json b/plan/marketplace/research/sdk-completion-2026-10-20/checked-files.json new file mode 100644 index 00000000..e3dbd419 --- /dev/null +++ b/plan/marketplace/research/sdk-completion-2026-10-20/checked-files.json @@ -0,0 +1,26 @@ +{ + "packages/core/MARKETPLACE.md": "547516cf3ef347d8e059142fc8d967afca3f03e1c47193bebde6fae6eeaaa801", + "packages/core/__e2e__/ci/suite.ts": "fd528e0c75b4d2e0bfc01b6336091ba136178f7952db07a33ae7452f24a7596f", + "packages/core/__e2e__/marketplace/lifecycle.spec.ts": "b7ea948bb8a8540e27eef856af067d7d51f9bd77e441aa13180cdf07cb33295e", + "packages/core/__market-local__/marketplace.spec.ts": "23b3f0870757aeaabe2b85ae313285c02ffea85c716ab4baec922c2b55bf6ea5", + "packages/core/src/lib/agentic/contracts/reader.ts": "921505236f5638fd18c0d2fcc8785aa745fa3303e8021d93c3c930f9424927e8", + "packages/core/src/lib/index.ts": "d5f9ad83b60a66aa6e783e1f5d4f17207d8e377a1b3a688d7ddca232426448ac", + "packages/core/src/lib/job-spec/__tests__/preview.spec.ts": "79dabbfcf0dd263bee30ecaf9e6a8be49f98060e9198a7737a2bc0845a7721c7", + "packages/core/src/lib/job-spec/index.ts": "3b73738d3ec98ebcf1647290b6cefc19336c44b14cb6bd41286fe84d406b3552", + "packages/core/src/lib/job-spec/preview.ts": "4dc58baca25f0d8c32256f46a3cf031904658a677c60d684489e415a369bc9e4", + "packages/core/src/lib/job-spec/types.ts": "b366597ed55fc9422e9b28061df9b9415706ca5dc573a476743483d96b908220", + "packages/core/src/lib/market/__tests__/deposit.spec.ts": "e1bf898a9f968bed106966c8a242aac4b84e76733212cb09875dd570722c745a", + "packages/core/src/lib/market/__tests__/namespace.spec.ts": "c0dcb8a6935eff9b699ae83315af947865b19abfda827ed54d1731d88f3d9878", + "packages/core/src/lib/market/deposit.ts": "08477c23eb1e9839314b44dadb5b3f2d4caff13bb1ff4591c449ed0b41851e2b", + "packages/core/src/lib/market/market.ts": "16bb784e3b85ea7142eb3dae3330d3bcf8e63d8871eeaf4a8718a1da028f089b", + "packages/core/src/lib/market/runtime.ts": "c1edc24388a95017faf40c61787450065b7e45eea04f0a592dca9163579f5117", + "packages/core/src/lib/market/types.ts": "5efae83dfa72700bea8b4ba0b2dd5bcb12763bd25a44240b58f713e39cb11ec0", + "packages/core/src/lib/push-chain/push-chain.ts": "07557f22aeca81fdbf439809d250c9b82db12407f118dedd158033dc843c4986", + "packages/core/src/lib/read-state/__tests__/read-params.spec.ts": "9697bb18f68d77c992660afeb7c3054d714578d9e2990c0ea3957070f7113b0e", + "packages/core/src/lib/read-state/__tests__/read-types.spec.ts": "aff7635de52788f01ec0bdb179107955f75596b1e00424cf7bb8ccdfe4f8e801", + "packages/core/src/lib/read-state/read-params.ts": "7498768193f8a52e62588ea5bd69ffa644382df3429309a2944f384a0982adbb", + "plan/SDK-CHANGELOG.md": "73f250af43684b7b4eb229ff9c25ced774f17a9f00bb22dd2e92985f9e756f0f", + "plan/marketplace/README.md": "b3cc6d56410ca0021437460a5030dfe70240a7b84c68dc2b19bbb4855b1c491a", + "plan/marketplace/implementation-status.md": "3e6c1640db31edff2afd8691acaff0c4b0cf5558895f6c24226ae1992d37d97e", + "plan/marketplace/questions.md": "5477c16741f46abcecedd8867e23541469a484291ad15713889695ea151ec182" +} diff --git a/plan/marketplace/research/sdk-completion-2026-10-20/fork-results.json b/plan/marketplace/research/sdk-completion-2026-10-20/fork-results.json new file mode 100644 index 00000000..f148240f --- /dev/null +++ b/plan/marketplace/research/sdk-completion-2026-10-20/fork-results.json @@ -0,0 +1 @@ +{"numFailedTestSuites":0,"numFailedTests":0,"numPassedTestSuites":1,"numPassedTests":8,"numPendingTestSuites":0,"numPendingTests":0,"numRuntimeErrorTestSuites":0,"numTodoTests":0,"numTotalTestSuites":1,"numTotalTests":8,"openHandles":[],"snapshot":{"added":0,"didUpdate":false,"failure":false,"filesAdded":0,"filesRemoved":0,"filesRemovedList":[],"filesUnmatched":0,"filesUpdated":0,"matched":0,"total":0,"unchecked":0,"uncheckedKeysByFile":[],"unmatched":0,"updated":0},"startTime":1792499329850,"success":true,"testResults":[{"assertionResults":[{"ancestorTitles":[],"duration":34624,"failureDetails":[],"failureMessages":[],"fullName":"registers and discovers a real v2 provider card through the public namespace","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"registers and discovers a real v2 provider card through the public namespace"},{"ancestorTitles":[],"duration":34253,"failureDetails":[],"failureMessages":[],"fullName":"previews and signs the exact on-chain JobSpec, opens on real AGW v6, and preserves binary bytes","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"previews and signs the exact on-chain JobSpec, opens on real AGW v6, and preserves binary bytes"},{"ancestorTitles":[],"duration":28,"failureDetails":[],"failureMessages":[],"fullName":"updates a decoded card without losing rule constraints or template wire bytes","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"updates a decoded card without losing rule constraints or template wire bytes"},{"ancestorTitles":[],"duration":8963,"failureDetails":[],"failureMessages":[],"fullName":"deposits original principal, fee and PC after a card update and recovers history in a fresh client","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"deposits original principal, fee and PC after a card update and recovers history in a fresh client"},{"ancestorTitles":[],"duration":3188,"failureDetails":[],"failureMessages":[],"fullName":"funds through the real rules hook and submits as the provider; manual evaluator completes locally","invocations":1,"location":null,"numPassingAsserts":10,"retryReasons":[],"status":"passed","title":"funds through the real rules hook and submits as the provider; manual evaluator completes locally"},{"ancestorTitles":[],"duration":3661,"failureDetails":[],"failureMessages":[],"fullName":"creates a plain job and allows third-party refund while the kernel is paused","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"creates a plain job and allows third-party refund while the kernel is paused"},{"ancestorTitles":[],"duration":31613,"failureDetails":[],"failureMessages":[],"fullName":"rejects a tampered plan before signing and atomically cancels a second job with permission revocation","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"rejects a tampered plan before signing and atomically cancels a second job with permission revocation"},{"ancestorTitles":[],"duration":32169,"failureDetails":[],"failureMessages":[],"fullName":"accepts a real deployed EVM UEA owner signature with its home-chain domain","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"accepts a real deployed EVM UEA owner signature with its home-chain domain"}],"endTime":1792499484318,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__market-local__/marketplace.spec.ts","startTime":1792499329873,"status":"passed","summary":""}],"wasInterrupted":false} diff --git a/plan/marketplace/research/sdk-completion-2026-10-20/live-evidence.json b/plan/marketplace/research/sdk-completion-2026-10-20/live-evidence.json new file mode 100644 index 00000000..da4e14b9 --- /dev/null +++ b/plan/marketplace/research/sdk-completion-2026-10-20/live-evidence.json @@ -0,0 +1,67 @@ +[ + { + "name": "marketplace-register", + "at": "2026-10-20T12:21:32.942Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "cardId": "3", + "txHash": "0x4fa8144b3187a138f1dafd2e15fb7e2746caf9d6c1b5792f58559de049faef0d" + }, + { + "name": "marketplace-open", + "at": "2026-10-20T12:21:51.874Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "jobId": "2", + "wallet": "0x3dA787ac28639116EDe5Fd34CFce0820e74f91f1", + "rulesId": "0xf7789ce3dc79b3a52ec15584ae208e3cc987e95f27d520c424c5284e9a124f47", + "txHash": "0x5ccf837039ea26439624c48f187715de40684a069f4d41b3bf63b0dcbd70fe60" + }, + { + "name": "marketplace-cancel-cleanup", + "at": "2026-10-20T12:22:10.902Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "cardId": "3", + "wallet": "0x3dA787ac28639116EDe5Fd34CFce0820e74f91f1", + "jobId": "2", + "txHash": "0x83465e2001df92c35a26add94647c3d1a55a435f7658acaed168babf589116aa" + }, + { + "name": "marketplace-paid-preview", + "at": "2026-10-20T12:22:27.580Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "pass": true, + "fees": { + "quoted": "1687500000000000", + "paid": "1687500000000000" + }, + "reads": [ + { + "decoded": "0", + "requestId": "0xdf67c96355ab3ba26248c0dd05a597683336927ebfdcee568948f12070ebb3bc", + "txHash": "0xbb03de6faffaebb972e77a07e6887028ed6b59d3adcb44bb7a4627f108ea57a5", + "outcome": "SUCCESS" + } + ] + }, + { + "name": "marketplace-external-open", + "at": "2026-10-20T12:23:09.977Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "jobId": "3", + "wallet": "0x1772FE5B6C48F1A0D78F65342dF62C99F25C094F", + "uea": "0x5C2029EbBAC9F5643775CB60a7609d0e8D57412D", + "signerChainId": "11155111" + }, + { + "name": "marketplace-external-cleanup", + "at": "2026-10-20T12:23:29.162Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "jobId": "3", + "cardId": "3" + } +] diff --git a/plan/marketplace/research/sdk-completion-2026-10-20/live-results.json b/plan/marketplace/research/sdk-completion-2026-10-20/live-results.json new file mode 100644 index 00000000..39109f12 --- /dev/null +++ b/plan/marketplace/research/sdk-completion-2026-10-20/live-results.json @@ -0,0 +1,31 @@ +{ + "completedAt": "2026-10-20T12:23:34.223Z", + "numTotalTests": 3, + "numPassedTests": 3, + "numFailedTests": 0, + "numPendingTests": 0, + "success": false, + "tests": [ + { + "file": "marketplace/lifecycle.spec.ts", + "fullName": "marketplace live 1. native provider registration, reviewed open and atomic cancel/revoke on BSC Testnet", + "status": "passed", + "duration": 49337, + "error": null + }, + { + "file": "marketplace/lifecycle.spec.ts", + "fullName": "marketplace live 2. paid JobSpec preview reaches live validator consensus through the registry", + "status": "passed", + "duration": 16678, + "error": null + }, + { + "file": "marketplace/lifecycle.spec.ts", + "fullName": "marketplace live 3. external EVM owner opens and cancels through its real Push UEA transport", + "status": "passed", + "duration": 61582, + "error": null + } + ] +} \ No newline at end of file diff --git a/plan/marketplace/research/sdk-completion-2026-10-20/post-live-state.json b/plan/marketplace/research/sdk-completion-2026-10-20/post-live-state.json new file mode 100644 index 00000000..aa8c1816 --- /dev/null +++ b/plan/marketplace/research/sdk-completion-2026-10-20/post-live-state.json @@ -0,0 +1,45 @@ +{ + "observedAt": "2026-10-20T12:29:52.424Z", + "block": "24451338", + "card": { + "cardId": "3", + "version": "1", + "active": false + }, + "jobs": [ + { + "jobId": "2", + "status": 4, + "budget": "0", + "client": "0x3dA787ac28639116EDe5Fd34CFce0820e74f91f1", + "owner": "0xFeC7BB20316c4BB85EE0517958F7A80BA0c59b68", + "rulesId": "0xf7789ce3dc79b3a52ec15584ae208e3cc987e95f27d520c424c5284e9a124f47", + "permissionEnabled": false + }, + { + "jobId": "3", + "status": 4, + "budget": "0", + "client": "0x1772FE5B6C48F1A0D78F65342dF62C99F25C094F", + "owner": "0x5C2029EbBAC9F5643775CB60a7609d0e8D57412D", + "rulesId": "0xf7789ce3dc79b3a52ec15584ae208e3cc987e95f27d520c424c5284e9a124f47", + "permissionEnabled": false + } + ], + "openings": [ + { + "jobId": "2", + "txHash": "0x5ccf837039ea26439624c48f187715de40684a069f4d41b3bf63b0dcbd70fe60", + "blockNumber": "24451140", + "agw": "0x3dA787ac28639116EDe5Fd34CFce0820e74f91f1", + "owner": "0xFeC7BB20316c4BB85EE0517958F7A80BA0c59b68" + }, + { + "jobId": "3", + "txHash": "0x261fee7f7ade8d13527345af4184f22e4b4e8010a9ef000d16f7ca2cd3157aa9", + "blockNumber": "24451172", + "agw": "0x1772FE5B6C48F1A0D78F65342dF62C99F25C094F", + "owner": "0x5C2029EbBAC9F5643775CB60a7609d0e8D57412D" + } + ] +} diff --git a/plan/marketplace/research/sdk-completion-2026-10-20/unit-results.json.gz b/plan/marketplace/research/sdk-completion-2026-10-20/unit-results.json.gz new file mode 100644 index 0000000000000000000000000000000000000000..2b0f07b2ea91716072d971ea5cb6cecb8fc3cadf GIT binary patch literal 73812 zcmV)WK(4!-FflY&aB$A zdyt?aD2d|`8AUQ|s~ZjUuK~{AIrC>fz{0i{Z=< z9{&M8>*9x3i7>($HuY%j?-cAe4jl?v9L^_=Sovg0KCbf8X8F zg2s9z&CZ*@@6a%0AwD$Z;paG{hV8r=&`7i0odM-hqH_P{5!0vH5AdH?Y%K5QeDI!Y zW8a3KeimbDf>Hj9_GR{i{2vVr0RJly!H5O7?(^(le_<2-cJhu#%)TI*d3KUL_8+@D z+E8U~_?Ydy=^VfA9=v|tece6+{pchJnASUQj7r$V_LD%bk!J7MRb1-!Y|Wbn`%7MEs7u-1+z2oiI@pp0M*qBvF(}^PCyVBc}=X z*$1XI9j59TBvJH{0_KI!Cy8dNrIR?0I19oWo>7tD|m)guzJK!!{cE{r6U+zNRw z$SoJ)&h8EucQQa^c0xw(Unx#EpSc*Gq7dwqQ_QHz6{8w|hO@{}ljxl{JF%V4JG(mu z1heyIr!cyI>^4fu*DRJ1r{vw|kLTCqYM;1SlZ}9C^6B%<+fScAo_~FJ@$vNi#lQ8= z$vrnCqLcp3!$nAbAj$N>7oHSQ2k@rp#?T=nUGm32|2xx@{W6z=D5hm}$218>JPHXH zeVK@m{PCavMFuj8Ys&l#RybyNYjk$O0wII?fPb($DCoov%#!upqqA?zWJc)$$_V4C?0rMhA%pKK21biwcT5=;!eF$sXjn`YHH^eTOR)h+ z!KZ>M$KFT{9pfm+{DFn7kZHpOzVVy+NCPFcCV%`t|KGmd5WMQ51j?pK{mTb5>}8?? zMl>G^Y7)gV3;&K&Vnz(V*H=^oBTsT(AJ;$reRn62cTCYC+j;Z%f9&os5zgG&_dBnT zP7Zc=##T%_Z+3QecZ8MD-e=8}-qRyVd4DWNbUbF^-Z|5^M#g*hQr+%de!l)?FHZER zg}Q9%@OCez!7WI9FOZ7uX%*~6yuX)Sd0OV7Wo0kb-q)|-AJAXF?xi2S0wuiCF$-Q9 zn84pU8dAuasPrw5V+I#Mos7p+O<)u_saEqfWOIO=27ye3A)gJ8xZw-{7>QSc)1i>s z@ZiOx3D_w%`<{3w`R0uzkOKBEO{gF=3>92BsR-=?B6!z7JH5DUb=pK5#l?^eq$0g9 zABxS)&eJm!eR8>pSsdN`m0wC9?dIyk9!w2Zi33Wh7cWVRe3XWKkQfk|J=_o5-Rd>78WN&MGKoT> zm`Ri%nvU7bRt{Dd>h~<-Oqf@hf%S^oHx|>~{(8DA4YGtPQ^DOxE6T@nW-@x;iy<=v6~KGh&J*t@=B2EmsA2IRh5!^K&M)ZzLWo0EK$;1>ZdB?+|K7nGIT_0RAmvZ)ZFYf)^+uYm*Hxwpe zLIi__^Y6ZE<3x{Awn#4v3m1x-Rm z1H6}of{Q)4JUAOkw) z(F7ba@aLGRRzRbOjHJ9JQUuIy_V<(<0IpcfplCFjc$vvHL0>NFg6B*efywe8vJc0~ z?+I57ucof7Bbq?oI%oGRB>f~DGD8%F5HT?$Dv0J06YwP(f@4n%2_=fPeoti4DZOUy zM}6pPo7-_j12&QotiUldBN^H}6~*u`W4KktO2$&tNE3J(>9c{vk->OqsEJh5LAlsB{Y1 zOL(X@@U_inh-6X4?1nd>kU&4d_X3Jgj$wg1Xt9!GyU^gfH~=rZL`jJAt<&TEPRE0F zI;QHDnOv0uyhO(|U`x!?qm$Q%m6@kIJrTZ*WN=HaF3*TjRA|V9e4MISYzEDLHe55o zsg%_me(l4TzOp+e%ryKR+o^$$-efo;ltfbNi7QD_zMKLTAf0~+T}kk@$eoF>`64e2 zvMJJz6&rxLcqYfpynS~wEwN1p1Qub$hBTO@AJIrl!XAKy#mBv&B*fy9?zZ=A>Wdo107Go|jD?qZl>z)&m|SFe%5enWRh`gCrt2>3mJ~icuHW$VsPKjp#%T zXu#~XG!ZOpjTj$}4EbNzpFXzWyEaG$)(jlTM$zCF>~~3m2*f&=z)%x`JTqQaL&cDb z>*An&QmHN|aRb4tDGZGW88Q+o3AK&n1x~udcANb0XsqaV)J)yMJ!@hE$toD}JGPsf zoax-{)8JMP23{;b-(#9@DxRDi`7jmXmem4Tu$;MwE54-S`dSiAdSoaGAZ3c?zQLeffkGBC=8hnnDh5^+E zH(wVGZ9fFZVL#mOgkG-Vl>(l>{glwzz7L&+l4$}yVEa!TuVNs8cfuBGg>1kD3(*{b zYA($ptnDV2PR>unyaJe&>!-6h{Xk~mbc9^z(g`~4 zHdu*VgzN!sTM->QI!q_gB@mU`3b5LF+huQ5nJ6$!QhFpAn_X+oMZFm%= zTF!DtY$6hu!b)Z)LhZ!mB}7x}0OnmF_uK8ZmrNL`z~(fH&hjGVerq0DD5@nl$di+! zpiu;OZk%$O!N+G(kEMP)`PYPfbCMJ+@hJF#^> zr1@#+nA>#`)Li<#`^AVGFH^ZPu=6*j@{04PH#BoTe!3w>Cc$W)IA{b8mI=^YW1;{| zS$`JT`p~vtCqY)h3i~ARNV#7!5yp}WLj+vXpy~|wkL>R+xM0e7V(}>pvY4KR%vfRF zJUn&_*R)Qv*z4BLSm$?8j)V zeH32j#KDFq1$E(@R5CNBHMOp{bcdTTklff&>pco;dWn8lhxWTtvSRw+nsi&I#(1_X1tT?lWVwe^FThmz3yFo z>7A1yRKz?Ye>^TWiI==(>Z@?9Gw-0)lVg@~zqz(#P+XJGAFnTaXBY1-dgob~**yFL zy}B^N#m`<-G35C>(R$kHwi}?G%ihQHi;q8Vi)NmNTY*-(`}HU#bzIufVd~7I(b;4! zlr;DW(w}>+DqkO6gGKJ{>*?QZ)6L%0xOjSmSG_O2tDD|Ad4XBP5Wmc*mtw_iX5LFL z7alJIsX&qK&FGQ3j&^Z?jzP#WbHy~NU+gF>r{nu*?C2hMboe7FI_UGvCa)Y*GtbxGLo@|?0>03 zD0%XdpV6A_H47_!ja)LbedosN71`~1q#wp#=_Af8NpQ^qfAqS?{UoySSju7?=1uSV=40>14}HMuaGtZQzn*{k z__=8kcc7l7+~0pXJAL1vNuJ@^c4=FVm54)$y@cA-i;tTT^8z5{<@d{80VcKZUc0Ui)b6OG4ZU1Ki%296~&Z(ib$~XU_RHpVb zGDw82Y_|-ksn5fwP?sRteyL*gm8xL^tOU~9#rBbb9uD1Ql7W%tkVj84@r%Q5^@|_Q8t7Pol_Vz%gYN$OX=PZFx zN{+ibry>|hMJ~?YI~VN>+W_pPzdd3h1gJj?lK|tcI#3)sE&y@Y59F;>depK{39U3> zreO`!9s8ZTMrq^-Z5MeK*F)nj$=mUb(h`eh83DVysPnyE|!@9`Y|djQ)khRMBx0me@R8 zQ`>@vOc)-}i1a50Teap|4Orm<2~VGUx%m}<^`}OyMi;CMOD}?QCU>0T=RAzuV7&Cg zD*~*fR;@_zVrxg^ZF_zE=9v?&FU^Sj3+?lNLH04LK5E z6M!AMkjf36>&@w66-?`DBc@8T&w`tJqsr6Qq&@@u1S;>@kf}6*cq5+gB}leRq9F_T zm_`*zbiaf|7b4jji8`m!-}HkB>23bbuI z{UWM{jEH31XKEAn@$CDz%|;94cnmHud7GOVI$(k-F1>ETs{z`!*(v+LJ=*G1om*qp zZ(ne(mNL$sg0uAo#QedPuqI9_wI-f|_goJ;d%dzF2Vsn9lh3|+Xt!onxDY8)=eX7= zHmk}WO&G?RKLzbbwb%WqJlb^?V}EBgv%Ay#@}Z^8Bw{4Nc4RNydsFvTy-6@REMzH? zRKfN~q|b-Ib6ky||FDqqmLU0FHDhlrP0-9DB;TE8oY^yNXj_qqTPm{i6q<4xf?TIr z!N}MWwA#JYpN5tqd9-%&Zdgt1cQ>$b=ECr*lTO2Q5-S#P;2zzuQoh0Q-K~_=za9=P zPnCWom<{Y?i?Ni`&RO0GFx?z|sbv1^AL*fY^UFq0k=ge@e|dktK0n*2z#jp4{t|zC zvsr=9zQ3gHiar2*Fj&TLyCsPxc3T6S7)K7M^@u!UGW$IDN8uSR? zbeMY%h-W5YJ%;9h8QD1{n_eAM;c#uKDD8=#AZ<0V*=M6;w**|A6u#q36im2*z?^%g z=P2P?xYpIBj(8l?A-jyf$et6O|B*e@r>(mlFi*N_Z;!5UyRv4h{g!U5_U1tSQ=cfL_N&9DuD)4l zf9eZ`(rv1?y5F0w^4FbBsATT@zbDC$=>yKhY?FV{X}AB!%MIvY5t3@O!Tj8M=P7}$ z;MLi{*}oXXGne?rtgXc$p0C6Qin_gLy0Fu85R-^DLanksxN0;sb>?O7Q`BrgUyFb| z(q8*j-u{2lX_J1eH*q*D0P?+RrF)o{M)z=YYMGDZ`_#*fC=S~jTP*W&e4je$v}gB? z&1q#3lJ9h_v>#2<&8?ONNGh_)W-=K3+hwx}6i-n7I}bZefp4_$z$}>hHPLC3CS33; zeaPEbZ(1F55PfH>BV}Q1kW%JB`ku6s#_gM;l6iQ(BYotC?aJ2S%V6fTH>sAVV0}m0 zas6lPPweTsNv+I-^Brkp%9+@bB5IIco(A?E*r;#3$Q8lQDuB~WgaHWV|767z-$z0*E?`qDdn`@Z+} z=F?w#AFqk+wg%}@Qr;%9&vLMGK)3JE0IM*jlNzkpgK}2vQc&9`>qkSHfA-lXiR7H! z31<8s&_yslQ%!8%b}a~V`!3Tf4Ro`XYXOK`c0y|z-7z;3IP8LmTh?`LU=%pyM^>ZX zleq}MtQ9fqDD|Gr}SGh+}I{QC`NVD_nsM!3P^IW1wJl5n~io}q+BLWfY zABn_P#7_DeTS6y7Cvhy5DcT!(?X|oDxoX!(6q}m?CUhLs=2;+7lBg7-5mN1ONEx=If_lKlZM^e!BX4`g8B& zjUSaPhq2wOL`V|I&<^g`)A#RtH(z0l=e^7KpZ<66{6|7@w}7%`JI%NzLW03VPJjM2 zlL?CA;_Rz^gqO3a9^~7-YVJ8!G2w7S$?Sl!)$})~^dm!bkZ4c4Tv?3sH54<|(oDFm zQnQE!m944;&$fNNqY1$s!tK;AP)WPick23{wz54vVcm4In1Lznort^fHTA!O@(V8gd|&Xblww>mi9F9$OEW`8C@m0zQG=lVTKzstJjC;KwyqC;sNlZAuioleek8 zm!4PCLHy`~|JIoUe++0aVqr$V2~YJCDX9u;bJhqIifKs74Qs|DXk+J@uivxZvQorNncIoD74lx-^hr4G9{ldp=a1*vtQv6uKfyIDv{6Y=ymRH6x~LxYe0{j^i()j?m9#I*Kahk> z!GsCffFkF+kvL}rxKR@U7gNGT$R2(qeKwIIB;1s~SnscUzLkQwu2kDqN!8x)L&XOs zGY&DfLj%-4OdR<4_4!}Om}7k^ho2g}sgf76AMv4mNN4}0CsU$&+?$X;ZZUQZ097Q-Kb$v&zP7tf7Dh6F?&E z-5g3^7mn2dZDQ8i{~sg@Nxz(;(=#JvV2^?a02U|09OKvI&`)-GadexIB^Lt;VRBd! zHW2v7KmV_`s{_>?G94)1XBv(Rs&l$eGfZ-e$XQs-UiwQNe%*C*GU^}4eEkF?7Tm^? zLv3*tn?vq-M5+)n9r_dNhutOS0e7@W4((Zv|8iT~08W3ygWEJ^Sg|;w0UO)Q)v{ja zHJ3q6(AU&KySxsl1-S>|Rzt>IXU=lPY$_FbK?jB@M2RAL2?T^NrOb#5cS`x%yemWN zf3_#E;1v8?Fq|mv*ufY#3~U@n%z%gM_k=+fcC6$b29U_~G31_V601ab+IT7l?SF=6 zQ8<0eYpIgpG($2M`hrA|7xxEMwbSqqaXm@tYnKQXk5pe`5X>tdqJwpzTz z%!W<}Qr%O9H<>KUhQc_EN;Fs*5MpDB^uhe_BF*a1F4*Bt_766)!`bE2LToL?bS#Bt z%XYe>`7hR-jO7q6as;fag>JiBzZTHj#v&SP7Jkq+C&ngt zF#?JDiieE6fQ1R4IPbKdqS|r@=Whf1T`zT1QbA^sQPfD4+Y6-ANXyt6)k0M)+YC+) zI@N6k=?;`7j8_x#di+!pq0JD|*jOLAO;(o*TD0zss2=Spdhe_a8<+;|-76Zyih{$_ zOVp(Tm>X1sVXG>VVrAKPb1hy`TZ zt#(ZVDx&$=H8RXr)=28KO4t4p>?LHJQ}o{JdM}1>L4LB$h}4N10J}vcX~{E>1i!UZ z#vYT?ooYAp#rA>z#~M4?U>t3`rKphu=gIZrMXnI;`VwzfCUMR3_8=Kkb&L7cAwiST zkkiYHT{Q9S+|T0ouBgd|G(#4^{4q=k8hI0c9oQFKfe#Kh@RSBRm1uyHJ|uihFN+W)w_|Wsmta)yLhyEwU>=VbbH4zr^(EM@ zM1pD85UXWdpQ0GWGP!APju-FWicmHsDVtS<`6VL=NQdO})g^?1G@Ou*KgL$PITjgD z7x}eeZEm$rTYsi&L%1ShyO(fHu6k#^i_4p@A1=#=$UVws!?eS~waWF>EPQS#R|AR{8kN<-N4!Ex+ zsrA>lh4hLF4Hmi0g|WFu5WgV<8by6tGzW0ay`(hA^`+abXlF@RBhHq93Q&HZVbUzI z`ExqykGa-UpFfNY9RAL#u@|DW`UQl9=gWDhWK%2Yo zZtvDdl23P}np}K5@BQ}m>h!Ex1y?~r zBQ#OdlnkZ~?MEEu7iL5#XJ55n^ zPgPXXFwCkRLk79C71p+X`*6the`8Bsumk1plwZOoTkWNFq1DNG-RoZ|gk@yitwYut z_P4C=8LTZ>iqyz44_wVr8pXAS!VCC242POT+0d?-xa*srM3OpiH)##ny4*L`%>d_) zYnMAMe)%!82Ec}f7d@J1KW6fQFFYlkg4=z2-FvLhAw8wcBnIyo@^!)Q?GJH=ydl>2 zh&(nHF#acAuPa=M1rd;b!lO{n@?6;gzrbI=v{ne_QS~)bz)6jC5bmigBr#JYro7+6>=XCwc>K@@REhX`YBevJF`W== z;R;*U7-hNlyQH7EFW@yJW)#UiWCV;1{?dd>BV7=dI)Zf94TPn}RL~)gX<0z(;Bdd5 z`jdhN0egrkglUkA!;+*}sx_Db_SA&Ew1w_5NInHG8SbIZcL`r{4Z`EX?YoZG4t7=x zdU*lGLD6K1|6oBz`{P(>Y+%*`MIv+lH#m1V@JYs0XkWZ6g~2TsSHa6~##|z;GlK*) zMj8_&TTDynxiCtGNnm5vBoRnm5B`xDGvNGWo>ql*xiAYZZ5_y%K_f@OCM{H}$=;fB z!*B)VSP6}=_FY9-XylKjsU*bZqAPe93#rCPyPMh<=e^%-HYKF4@VIk$_@)>8P zPTyXT{=^i`7V8|X%Y9q|;YQ_la&Wlcc+outvbF`g3b2E2=cxHJ?@5#!mEYk}8uoRZ3ZEN zYth7v&@Bg-Z79EE0vmTEIxWIg^uCqWiP+{+7#+97I><%@H6@k-%}1=b4&1ffn#YMj zx?oINac{)|keHfLn*U*w`LZy*O$qlR%rf|v3+X+Dl90(-L-dj!?GYqn9y)gZ6Ww3tQf{5snx=!&5Gk~BDhwo%Mg;I4hwc+W#Q%|%Z; zo;for5!|FfL}zd%0<(01M1-4BsOUY7_JWA=F|_g>$mWHZ2vy?y7K|24&x}u$so`>%7qxth~4aiWE)u_YVB9 znSJ}#1y>2_@HReM_y)}xNzHK|D1*Nyz5>H(wdW03w zewOFF7jLHw!B>V!?j(pfknuPNCVbsfR?HIsDwnC3Gb3#)Zb^8-M-2YS-xH3B(P=)j zWk78?qYXWrS$*CMoL0S0r#~5$u$NxUo$68lsl5S>^cJem!QRdt&6XX^3L^hgC<&Pk znp*-wPc(8xu~n{#10S0BwnH;slpggDhBA*>u~t^M6?gB$Gomi^|`Z2=uHHl;rMw1_HM&-PBd$TAV`5{;DrI;G%o9hf}P z>r@WAX_~>3CoCty)&T~}i?I_Hu2LAoJ)QW8t*?Znoc#8ypV_WN1^*(L0UuYczS)w4 zAaiY)@!xvtbXx$}eCfJ*jnvdBAzUPf(1)U04(e52^|0_yi1As%eBN{)+Z<#iG3w+8Urpt1Cf^AJtauO3;hYhBQcw)W<1nter}loZ4`P zB}1Mz{BSfjkU$n989F|{^ZIqG-StCZPz&<;I_rJ;FlB*gN`v-?dA|0mtXS0^Z0*udbT{Kc1D?xmgtD`L%vp+qBY@1esV|9T~tl`pvZ&Sk| z1r%ZmOq(~(&#qX&V~z|GS(|eRkHS4zU}-iu+yWZ!=6Wo~bP`D#?vk_KY1%{F4b%%& z(IyADO^eXpsx7g2n%hf(of0Xp35_Co4`cZ;|DzEVVU$bQ_T!bQ1nD;E#{G|@AIDe` zv~$3g*f0ktKiU+)%QJ!;2$oNaiGfssEt7FhS8UGd#qC=$69^a=4hh<_IS3G zjzW@1iXl_BVA{S0}DbV1)2IyP050Y%7#}hqIwD|(q+EZ#5 z3?;cLA^0{_w7m4BrBV>LX)RrU`7j$RutOugFCSX>JTxO{%r;bXoCb%OpCZO0xVC8( z2IME zno96Y%)XftA-GE*Cdj(`Uonjwt$U1Di+Q{Bbw{Iw*@0)j=wq)c_?n9sU0$7a+phkX z8v7gEkq1)UV^S34Hl!jcrM$K2*=roYmhE=g_gveAZ(9$)h^e~8d!UU>p7l;&Zkk`e z2HabwH|t2r&Es#zzi_DJ#nhojXowehd;}gSt%z&m8nEk^zK%Cv!`Y^Nc5IVHsUV&9 zH}cSV!gfD&C9A_(P&WDc_-G?#lVGDRE0#PyI;yT%GN3{V%#ToP$TjpNgU+F86;~B0 zc~8G0^CB=|)FhT%7&722nlaUbL>riKHoMbOM%Z836KyPk240}1hhCX?t3y41y|1I6 zPA&Sej7d7z!wD*tM~bml+HO5B1w7;&vo3gppk3_*2cL+v8=(z%_#v9E4Sjiib!*X= zrC_;b6HTxo5+gKFQfsKpheK!=LP?f@U)aM2+O!cFTQ&G7EGh}HsVhaZm|7B>-xDBf z$}-M?#LXp1_s~+;BdOqg3SF7M%USNz2*&kkK%mO%jzX8hXyQdBbzv{Bt9C8A%BZ-m zWkdx{Ll3)T%-ytelw8ig3WWn{rlODYr3}8Nu8-``$Q}7B>vzeB(JX z??)Vi=Z12$p4kIN=}>(>bx{ZIrs^o`rbjh6>4+I|oo_Uc&OIztw>1l{TtWYsT058x z3|$9^Hav=eQt{S{pQ|3^<@HpL)$DTI!D$yO*t^j%abI+9JFs(PG91mu6SBsw!EMow zz3Y~!R)n>wX9;_VWya-`a@_&rZ6xJw5)(b5&?8~mP~r|Y0c`mxG!r^OGYEv|M;le4 zoqu;e=yVP|+?|o+0lV7fuFt7@mR+G=19N9pS7Ik<%>Ui`wSLO@gm6v$C7KuaM zbpp6-^fqGo^Mr=v#Z~Y0ymj+itJChb+6OOl?c->~LrY=IJwd}f^gp@yv0lnq#8ra$o>wj4J^2(!L6^(#cM)p>UmfLQ}^vGQP8Gx!p;T;n)S9)67s=- zDY&Dhu0BiS;OUqwhON0)$(rN&nd+oY)a2@#3|SCy!5XE^$C&=q z=j!?tQUt7}m^D?Kq}BPzHmck1cIh_d!Dy0JA7lD+t*)+5OVrjxtgw9Wj%|%n<}9K=SLQk^)A6S@Yi&LP)zsU6)>AUe%SoO4S+?8Qa$|Y9 z?ymu-slF>56BhDaoWF;O0GWXpBhBW#jZ#l%y6uL;z2%~ogxJ)%oKM}Pahyxj+@037 zFdZm)kK;*u6=}j~FmiNfP7V|co#Mol@#Y>CPd%*~e^Ye^bLyQ`XSRtSm%=gF*sh@( zC+8S5KDD5+9!WFJG>Bys6<#vO>+(jF$Jx{!E09rSbJOuCgMe@5hRedhDRG8#vwAsY z3ju5DOm|V*v|3vj=!#&sSr^IeD@ntEmZ(WsGg7xEq^3uU(u5GH9_1-Sa;T@YmRPgu z(kpRFL25&4$a$>=sRVFybIELJ3)UrxNt*lWM;q0_ZR(Ddr5e(7vwmDAzV>tdDvk0f z`NJuZW`wzmo9x5;&^pEP4`^0V-7H`2g@j@CGHjloeol*jz_4@GDUM<-Ep?<}%aRfx zJsY_nF)<~V@RY_>9p0+-)$yROY)8m!K-^k!BI58UftJ52pLJw+3JzID_y)gQR~ew& zxS~Q9Cg3H*4MLA_Xd@|aU6m2eUu(_iBnaRamOB7%P(gN+^|G3(!dkVSy54raK#Bpk zM#~-cn1n(}A#;O6yI#l^_!_c=JufC#IfUD|yV>Rxb53BI&cpPBv^Y=8$TllvYRm<(>*%cToDcpTUL8gEvdvg=yZ;&tHinLPU%XndS7~1H@$Q6$AA78 z>0+k~@Nx_RM^$Sp1&j2pzY57=GC265x@BS@%plNcJc0_cMcmhT;N_lmf(&3 z@*@%MlOM9jlv4d+A(SF;*PA3(Fxs9Sms{CHpZKaBD*(-Ky5Xt*xyI%LG z!umsdIIzzGi-zk`wGZ}Uw3dW8e-~O$`ujCWAL6|CmTneZI%pj++y4pfOqTw}u)v_N*~vl3Sy6au z9$5+0DzwqAR~tB-Jn(dyO{oa5sO+GtqT6_qG9Sp8L7y*}PT9Ru@gZKV zV#P(kV;ZI11q8c~CM1a=xC(q!D)bUBuMF(mm0JlFnH=}Iuro#Xi zMm%J8gHLyJ*sjxk-pf)hkFvHsFjH^p^863kcY##+L~HDb;*@*Grr8@vtBPBa_B#*D z0IgAsjt6GC$Ji*EJ?heo$23lpZa^W6z}QZAAczidI4*r2)-^$|P1K1?!_H;910NNG zm)pfdluTUrWlMr;J8L^eesCgcSZ$|2|2j?9_9E(LPH#3BLA0>xpcR1^4_!fMHR`7AS2w8{Wr@CApJ9l<$yctcplf09c48cJAndH6 zqW87|$_waeLk)fD$=a?A?sL~69+p_f%3Vze{JAw^4`6#3E?7kVy3>C6>y9sTz8uIJ z_2u~-OM_qre2img&c(+J?%z>>`;n!fkUemJ+^u4b>G#xxmUgXdnBIWaztb zi-*x3YOLiZ-x7Q4uzP%1oxKIkTosGx#HOyf>96_U7#Swurmy0FUiOmAT88zN{uxd_ z5-~9}BTpN_(-`Kj^Y!GnUz7aOH9>-iQI!u|r;QZtGPgfu4*_GLBip6}X1kDkUA(1$ zKC$CEi}gbip}iDUcm6$oGPE2?q7dU-klG4CF3T=qbM!Tf1}*#|4iCEXXxM0Pq3yf0 z*Tv7hQ$LIc)j(~O+_C)&X+J=Asy(~$xW*BroeS;oesCk&jL=KrY?Q>YA0W9xhuc2k z!e$n_wTc0cfGUW);e^WOmZ$c5r9l>!b*BbdgEMn>k*0woon8EJ0GY2-`;>AKcn#b= zz_pA^a-990Dn%!c)+&t1H7K?#)DdMAE}=gxv6EDQ`3X&&F`CKBT_37b#+-+z`mnb! z*d_tE9S07}=d4}~qJa`~y}00*`1;}V`YSYh6s#<7xjG&&XG**Dkg{R-yaqZg#Ib5U&4hiese z-yuIt_jK!Y9@$=Q` z&BdpWnNzD0Eqwdf%=Gv@0Wy2Y7&>@y%YuO3b`OtU{B;LiZ0XPby7Tg-Pa|#(R1J}1 zAByB?V4?}>v@yOPj3|`QLAc_@fgQ_BpIgO>h@RLNK5*CQyK-OO<0n6I(L-o*j;PDn zYGs`DPr_-U{Mruz4UP_v!lR9ZHnNvDQ8wwCa0`IE$Sn@P3v@L=%dV)ux)e_u)e+iU z@P$xkF;^whb}phDJefj<@9d`nqU1wb}Z=57Y1p>e8)n!La>c-IwS?WSRk zUB_>Km4-B4dLihk1ZX2=50w^n;y8c1wS8XvTkq=A*VFU!tKRkX%dEh5n($^PEM1(Sm|EBDE)Rl#p7dPN`)GvoopvP%4kOlj*0=?N?m;XbmOMvx3h0bn!c&U zQUKkv(1INh*EzQOO^SUUoFz8k8KXDyGo!T_fsY>k$O^pv^qzzYPG}%SN?8iQUn!*P zVeE{vmm9DQ*Fo1{8DD0jaGv;d92=486KI+%L+gG7jbD~=fR>76eT$)i@=8OUAs-Bw za=fe%^hES`(;NP#gjoz=8A*5Ql{64$r(>AbvggsGIh5{L8x(m#qzfp#4v)H z{T9Ygn9|F5ybe0u>Ug|dh)E?8#QZ`Qpuv(ALR+G@YP^Z7y~^!SnlKuS+=q5O0Y$UC z7naOP?}8!D1?V4o&8S^$fsxT+JofCGz{6s(2J1le;Uu6;3yRS38`E$!E;C51ixjN-9=LjWvXM3@>w zpJucNj6_YQ-ycXdMgb@oHhv@Hl8q)_0=5-H-j?;0QFyo^yE$sdtkXeHrz{NHi{)Ji z*tSSLW-8qcaQ}r0AgUO-WwCiP-JA6YNC=VEm8ys{ZFXJz_VhuPB+QH$SFr7SSt+%F z-p(sqawRR`$6@YBZn#c`Cik9r#=xP&Wy9~~@Nf^rq#V~LG zfyX)KW=dM3H!1T%0JlvGI4d>?>vkLf4|bYs$S1Hf zq`jnWbfZ}V*Y=&Gip323n7Y6Un8}(&wmI}hkJNRLZJXSUj9U@AW0^fR;4BK^PsHIU&z-V&08UhX^fCay|VO z%x*fwkg>oSyGyhr+_)}8fs7)&&ZV=RMFTH7tOxmg{U(M-`V~Hl2d}Irc`EHXmfl)# z%zWE)RwC&>#l@TugqNbNLcr$h092}9!Q$K__P_Cd3*vyj&aggH0Ion$zp>0X{;OGH zh2Ng(2L77vD43clhFmZkU4>p>Fm18xs+ZGjeN+n)5{?eq9ugAVLdfMJ*aNqfpH|D# z5e|>4Yb!Q0rw)qEDLvw`hKBBZz*$Jflnddmv@lBeZ^OoMgzey`4WMJiLhhm{;O{9m zUyjyIYN-ZmZJnuyN+z)e(mTw!bwwF=hk;4VLT)fYJ%wqv{g4f45}DLX3CQJ`8@N2# zplnh3u1QN@BmCteZx?QHkBuc^1Dp^zorsyl*@5cbZ_^VH-;cJLxh61rqg}!}j$rD# z4`_@*+TuK-1v{J8IE>m<5K3kXFaWVNXMwUeVkS3JsCAsd=-}w`Vx1KNR@>%4L%g{~ z6QW}#LZ(_V>|Zu@#&SipkRg+Wj>jYAlGQ(ES39e0q*@YE_#s-T1$h0lahw>?FC?^p z8G!(HUBwr~g;*d}sCS8LTiQ>6)*ra14UOc`k7ZgB)*5$L7ipjoSj8*^1Y@p|M+yEF z&p25vU`)`<&fymU)r_=X`i+cKfVZ}dpfZr1EfZ?zc3vD2h}R@LxkFn8M_&%n9M8;G+b*8jYgg6Rtp2kY5iO zHx%N_+7a48=7lt6`VyoNkb|Kf3Dae-CbtV*;p47^Lz;!2r{E1k} zp`znAmaEy*y|)J7f9i1j2D!+$QH6-Rat*fqXb_rebHNR#5&s)xB!MhY09GQmZ1}GO z_HPsZ@&5FG^*{E1{>$aN-_Cwb-rfyfU+bgp{+E9}JU=B76GJm1CtXiBuF7FQSN;9% zU&FT_`|p3hJp9rdg}0~IN4?8;@6S4yzlgWLpZ(U0FCUU#zj69o8}_#Dpw$YZb9A(o z3IyESx&p0##~uzrlmO#0xw<^F?jLCNtV!DJ+10oX_%MOg=CtLG`;{lnRfl)GHI`-= zV)h(N-;FRVOy9oU(qu^2kEykr5$Ie1+bvUMH_a}6n-S|G4BL9%rqQ+h*|izTF2e8( z&cT*71U4hr`3SaEsxGud^XKr88g@@7dsmldyF^hlV#;!81S2W!sX{__2gM{VpWc%K zDgwKmy220@giJ3nf!vzN`4Au_S|%!BHvW<2N_a8*3WMA3-N?2;aTPsyMbSxL8*UN= z-tFGJ@ zG5x6*#ngp;e(3b5-Pug&RNswTPF>5wrzgj+s|%lg%5h)6vc@@cMb{$4j@47z2b*ew z4ppZ0FH+uCvS*ZoKn4_uLft1&;VaM{CVdI@Y=WDX;bVr2BzwR}%3JNFq^UT%`CHBQ z>nmgtwxP`l0~YL57BGC<=tRg_p#a~()MoLt{Zxha+3GVbEemDRk63E}QBm8cX2iag z$hXq-qsP)HpZ$8w{_LiDI;kJc^$o7ULI}T4z0G`;Yr@8T7KUgae*1jvh}8g9764tp zcK0`;U4X+7hJ452S=N0{rRZ%So!)A6F4K_WtpS>n?%hfD{G_uZyU1C!7wSN>sz03-LJ znQ{oXS}!Dy5+pUkvE&Yj+)z`IV9`YSP1s$5g3OY*wedg@$xqT$x1Nx3eMUzw4R82u>^EHtZ z29Eola+9*=+6ZYVrK&^&tG$XqtEk9Q#zI%32@;ChT^-rL9P>HRNf3Zz6S;jA3mA`$ z7x|Y0Se+L38=(aSyq2(MH&zYv5w5QXOK|IDHB4Xi=W19{3++Z|VQW{z{EKt<mi&yEZA>BsxhW*VGmwO%$zlyqm=@#ovcGKgKe)KcSzZ2yOxzfZ9qKE578*;%*V8exnl_gnl*Li zV%mUk#`NLLX8bovJd03mMnGTSesv=ajT$GV#n3h&D#ZrP63`q#wei$A0wz7B6LJSE z9Hx+b=|vXHQPd`YjKc-{4L@KnrXetokY7*Vzwh0UJ`-%f15RBEWXAN3RKdjHEH1@Y z-Yv*FQwiebg6)=^S=NC%>-%xmn*Ry53{0(@Mo1bzUFUKzu>A1@h$8}c9$25IO>v%j z&?r&#z6G`|!EW;ey3Ko|II0--auM&BT*@LDGsT0HEQqS%URns0@iBpan5L}X7w7N2 zkmQv^xLk0r3ra3d`VkLEpnzoQn?l2s5s~VN2u4Z@ndoS;YbpHVaONi&sbWmI%8@A2 zPcPg!|h2t#|hM=Hk;wqV1OvKD0c#LI-gN2H_zyu`KHcI|{IG&4z7EJOnB!eL zZD7(sALbGbf{!Yl&U0}Um1hm7+Q&~f4*M)#^oN7-JndqQ*tO3YyFR$)?Fknj?J|3J z_36Vm3(XE|zxYnDUuGv*8QK=C|9v|(21<^no#Snd_~WLEi-zrUX4g5425IZ@0?rR_ zx_0y9+vxtX3cLnM*QQyJF@Ip8Yfkwlv!Yu6Gut$?|J?U!;1xjEAlX7DFd0()o{u>a z361GPRt*AECMlPB|s*oBaMV*Y1q8XDi#`NLx?449UQ*HaC&SKB9pM1-;ILHRs zaX2|1gA8a)5)sfiW}z)hqXOLnP*j-y!TS_0hO$Ak+NPe9-xFz&F-Tu39$?~jHYS~7 z@hIGNU^Q*01zTsthfuRNMc$D8p%}mg5|-mwYIa6-Ktm@(Rt>e>{72_XTINg)4*p;c zcY$2)>F)`+cfH(43WF;y-GfS{n`ov9lyU=dC^re1r697kzxj*Q3}IC|B0uJCd6dQF z-L78Vv6NBEO&AwY!KxA*2rxpWgW)1QVelzsrM_Q4>J?yZ%1*L;Jdlm@4Sr!eJyZRJ)_jtnGURrj)`>AU8DlDGtxGLaKw@ zlodjwdq{^FNOeykA)V&ylwp*YP^8Vrkdy?&;URMb5_av!bP`D#dP$k63hP$L{`%2) za;@1yY;zZqKEzXVq=8<72bF^^u8pHgwUOr2NFcdE#^C%}m+rJ~4rOUJeI;oaQ0yTx)Zgn!dQKj?Oj zItN=U^0AsaQ=RSos=k3jsi%kG8hx70@(Sf_)A2gvWC((8{nHBFS_mh0HKD<^mWFg0$y3Kt`7l7ja_rCRX@LxQfZL zQ=2R^zlGC1v)a!kH{%?b{&^#kT_0uB=IqiDlu2%{Te?qYwr^-hh0{~f`$wur%g|=L z&@}FWv#9s!)Mr6hVT>iD-K|C1Zk4ueBKhauDI}3&zbh6;a>7FLLP#9Z%MENEE5T~q z4E{Y~Y62w^0kaXPKnkOflp;5pbR<5-x+b#5Nf!C+hs>P83d{0)+S~<&R0t~=SkwjRp8qSVQOxPmuo|5r3zVK9pD3D5S74sgPN!QhJ0Kd=UlVTdV z$I~GtwxUP_?fE<_g|n!<+tth49UJLX_-Q~R&35f{`Kg`t{lfzqIRW(soDA!rYp`sM zO5AQIUG&^7OB_c-M7%o421y$1oH-lc0!zr}cDyFC#WL-kRx3*Py!<^*NW|ohit26* z-NIM36%Z|y*s0xi?S!dHY%>qdYLIVvj5s4cV8JAapp>5lxAxASKOia*XR)AFagYs= zu-l{p8jM&->{x9Zqd>Z5b3SFc3Y;QR>r^YX{sabKVcIQcAXUJw*g!Eo!sg4WXcMPm zYkEaQO<2>+kTD!~ND@{&xKixYnDh4LtioAq%-RYzD+9|MfCn`@-^w4m2h|ylYd~#) zvw8JB4y*yEM+}IxNsl)p zNnjpc(fn7>U?2B+eyogXzWi_wzo(GS{JD4f#frR=={WbvOFTvpgZR?Bx(3Ec$UnGc zK|pW2heuF<3c+)u3ipiYR_Qxh5on`iK0{w?0osK&Gdwd=@_uu)y325FheQW7FcMlq zxIiV>r2TO7_Iv|gj5WYDO12nnO!*q_#>7lwuVK--@1HNBF&{$L;b3NI1s+Fzv zkD|kL+RDJThXMHhg}4mRMrR^|JDU@wcHKx_yS%`64o(4d8umD zhBj-wl`z_Jm$zkgq{l}G)zy*S9RkTQQ-Vfl@!WI8Ftim^azZSAylq$2f_7D!NEI?@ z&=)ghD{37bD5RoC5gEutk&qhNiXjgTnzi^LEhz_a{(4_Qvo8l&gwh%;9rRG}ZXl!P;(dqUSkaE)N)F!WY3dx*6K&WSGH!>8jyEd9B~Y3wK|1d9VImV?GsWtr&CbLX;51c|X_G{-5jH8p zr*JfXH{7)Jo<`Etxd(Ow?Q1q|F251sJprSslCuS!Hgi=b2H80+FXtu&xjL%m$#sC7 zv}3L#Mgbyzb;#5n6noK#4+XYHg3A@!yoiN_Ovo|tK}qF{Y^?&I^QCW_lD2dpW5C?y$e@wsCAoBF7>YSlW1WS$N5~C1F&#^Rb1zoX*b$!IoO-1jECaI&EgaUQ1ulXp!PdV}QNHKu z%mMZ;5dWsznVNQP-;a1$xeuPZrLqBvbm4hy$ zkxs=LNv#Z{D37rFBQ-Q%pO#)A*y%#Xt67?<`%J4@b2Lo_@@7fEB4O>}z8jqy7FkQ-;Js4^M zK3_94x6iDp6%D>EjxMO3r(Q7a6O%f7b1bUXEX8Xu{6K_hL$1p+azEk`ODW=Dy-#mG zrHCer_Kc|>eiOBo?!j=s+06*iaBPXV74lv@iXA~EO5t7WsMrCqHn{ou4#%B#dn1(D z`fl7xwV;S>hGDcU#ylEt7!=GgYmbd8E#FbocBnE-cI!~{?i1|uql=>iDZ zfF_Y6KOZVul<#!yiBm1+0A?gma@>= zAeK-5j4^nX`}AOiS`Gj@pz!MFu&VOr2?SrVe<3NS|Sz{$!ea3S;wCrBNB! z+B!H0xbYLC7&W#N0vCcAV%Rv2u+63-Fc(}hrCnuAFqisAwM!EO_kb7IQk8gX>mxF= zz;1fiHy?X9)zT)8!4oO2JO(@(OT)Y4W09#hk zvg$QANRPv*Z(gTmB{Yteyurs5SOz zOAQM#Oq+4-MI6G7ip3EH_mPak{N@HXc^nLlV2(hVJ%{*Sdc_$h#y$=fE&Mh$Ydi%} zJr1b08U8^^anGU%fJK~XGzV2Q0ThYgCcUmqZ5=(LinXB20el`ZHYPN}`#(%EFQTs; zbZxV~$A?V3rxT{82YN7)nq^J)MFxA0{C6X~ym;<5{ zpmbpdm_+PX&_DQV?`@a-ME<&S&-&fJ?i8F$Yg*(*!Of5DED~b7v=E&rjb_n+Xv3kp z)`EttC%mThBN^P5X$Z0AX0|4zWfFS@BCc3$_)H?C8qR(= z6E6HG zsM$w8vo-mYygHT0>p85#`e)U)uR9<^YenpiMX7haDo(h$Pevja9(iK>$X>SK9(=fe zWVx#_T(4Syk1k_}Io^MLR4F@*ixx(-&mvt_t?$f3fj>pwyEykQIXWPx z*Jl?OnBZysvzk8`h78$>YGK|d8_WOTnL7g=w5c~7AL=D#q7K{(Yc)OSA$1`MDO#2| z(hdXtNm2~S=bLw}ll0pz*^rU|az<=|4bbFZ`l0re;8r2vB9cFV+BAL7+1&pn@L`?I#^~@9qymhleN|@ zoU3b7k7y(XOS=ziBr6Vgvos{I7$asFIq&_}yCy1$&;^ZzbpbUrlEYHHlJ^hR&f2XQ z_VTFTp&tpq?|nSK`1teo$#@muwZ-$-1$%vS`j=Xy+-cV<caF*`YBhK9Jni+~k_Uhb(}W+S*@DUumTE3eqMl{GL!S%OGD1VA-UZU2?Cm zyrbokXu#HZfAR4zX{nMQ3XTe3*0!DIY6jBcBe!w@#1IM&rsNZJT1x2ZZoS+i%VMl; z{@DT;E}%Hv7F*i1_!OnBvD_uN2O%rBCBMnF)1ax2Jyz^g1i1dhXq#f3FD-O+h;SO_ zb{d=fg?L?AE1%94FCm1AA=h@Ur_O^!*djp|KE}y~HjF|QJ>g=&6gnGYrjY*;T5RDl zswd;VjQoUWs>ZzFI(f3$oHaM3maQ6DcDp=2=+<+)EO_^^*RG6fDp$Wc)ltY|CPG^` zEQKo`a+Pk-^qU!Mqytt27ism3H8l!uj%!*wbq}JpeADzow&n7#e;BnLS?Oi1VH)VH zse$^3QJW!aD;YJ?@yI|%E!aW%fCmINTC7X9_!TuHC|e#;An{0a8caLy{YGNS66JRCW?)hFf`ld;_%rufIYtyNc&)n0e@{<1=lh{#Mxw+g_d47!QIA`t5B4V#RU0EGlysPH&5A4H2|M~?>K39 zPnvM=u>0Jyd&kM^>h2vomuKBJWReB9EF=*dPPdUtl2sNzp2Qp|@!;&lFZH4OX~c%R zc!kFnbty;afU#DfSO{KE=7*@JFu3^<=~boNu3X9kF2dYE;E#$8sR|?TCCLGVeer^B zJ7sxU+3R9znoR8$qzTBwx{rjM4uxw=0t1|T5u-?_m+t?4HllZ2CcY?2%j0aC?D8HnGDS%Crw!VcPdXXGzI||_Eu-!xh8DfRu zXTgC0mqs@a=&?4QdXX0aw&3vZ93F12kz^cn+bt*jR>X!&4*!$(eualWY{X|H9)+LH z!$tT`$#KsmTHQR5KmPgOBxD9>XluZgHn#6Xb;;w!Ur$Cfjwd9hX7nceR<>1(#A`%T?HceDSeuk8-<5qEa(!ywVH?KVNB@-vcVi;as}=%lm7;u zetl_1xKp@u&zJY3GQ7`Cm)}fz>lB)bN0UGP^S{V|Mv=z8*2!>$OcGL$r6!tD6^zJ> z`w&*fnp&rSD2I?mTKjKqWQjE5|I9Bc(vpwAy|Bln%D#hlX|HF&+${~DyYcH!!Mpj@urCst{pGGiNJ9g)I zb#(z;SPK3)xOwnhL|q){bJHF?8YZqb)>O<77A^)(2Cn`nNiEB3l(M5e)x?mgAQb}MgT{U0NW*fq!3aAcf2+VAe z;Wh;h1BR2GYG~IAy&D>pU?(LwF_o(*AIbR4(wV}trh;7UqkjtRq%l)Kqj1&10Fd@n z_E!?*{B5WbeYO4S%id$qoG~(M%yRSa%GH&n?q(|uOdZ=uoomd@r_jAz(%H0w5!1yB5GgjTLJRB0d}$ zlKWv*7FtDE^8eKEO$`k@##TTdPj4>1^hme8-)iq$rok6NVy6@R%JF%_|qO;P(b7@AB|C6*mH?1m9@P;BRTt& zRABocumfu_jyOn$2Q(t)ffR3fRcc|E0K4ECcGPWe?iywuTF8wxkZR0SYkG_>yM-N8 zSkYk_%`R;Yz&oj~a0bDYf=-6^U;C996RW(4+%gvH)N6A6={*S*<{`Kw1xs5Zg>|vm z{v7<_9GWu+R4MM-O5%@7(b%u)G^hdg{2i%@+Pc2nn40#BsHqyf+n^t)6^3p#icV|? zbL73xTv}Nq_cHDOOO=|~%2GZhqSIz}p8T>E09|0oo}3(P&XUDzM{7hy7%`<=(27~@FSBBgx(8Lp5>j4M5-0tL z2Sg`oKm%5hA8f(Xodu-WkZYqRWW*xqWC1Q**y@n6(Eh;56Y8MACFo_RE(~tbZFn;> zcBmX+#nOT7rr}hig%e3p3h4bc*_qbBQ%aESss#yF5{9K;oqhUveRKNp=K2+MSID*A zaJHprX0bYo1ue;mzL@U$;BmO;IXa$+w*3mu-b7C&yK8g<3{;>{sLoQaAD% zQ-La4qw^k3+{YRn=djr@1!-dTTX3#{(;ZE8o0jB>3S>=Ci`MFLX&zK8P202?8)M!I zc`s7bo~m&czP`AG+OVA3}%4m8pC+9U?6>k>cT}+>&aBYn5dmr124PAag=*tyVN2T*nvYdNzRqTU$BGTmiZ4F#fH zO%L*jL+=OTS7usL5Y+`*!?Lk4<%QLi8JtcEJ%o@9@btv7+jM#X23NQe5}Ylj+Ksko z10TAgsAxPIpt)>-0xyz)k(dZnPZ^Cky&7=aeb9^oV<|Lz_u0ob*uM~FT0AIVF_b7FxH}QlC%Q={4dq9~p--k&ww8i%N+*VCMesxgrMI8ZvkuyR+4gHL z2ehDrClwL~d8R%;QpH+wY2*3&chekC6`AC*uuu6&Rp^^M+Rl~rQW(W^MTLk}#eeMS zIv$62I~WV5xqbiRU@J@jntGJ%_6%*b*r{}~DSE0dzA(}iYLNdZ-C4icAj z4opSgmJ(mvAyx~DZH9C~FKsGRlm@V)E-Ultqy6$%kr*;AD<0)uOig7}bz7D8{g~2W zaG@V@)=P@~Cie?gjG#Mh-Rr@-`0Rtglf1BHYqm5@z)l`*n+i@5>3VtF-%ZKl=zASQ|njntq{ zE?v_L!VO{**5r0Wh{f_7Vy@8l#_5!R3>GYrU{ExOJg2YgELhO^M5s{OO`7PfTaRON zm~Y;E03lsvDCBtOk^bmZOwClfaIz0z^)elSy<#a3YgIIEa5iIsXa^Wh>iTEqtdThY zX$hJlIZN7nsp5Z0!{X^CNLCc$auf?f{Oa}-_-Lr-zfeU{r=y@Xw|q&o-$}K0>{Pp7 z6D69o)G__*2UO2p)pJzOT9aO?dod^d?!z&f3Q@4)l*kqE_L`q)lu4hQouM@!z*}rf zH;KMZ8{jsp6_15JRZ%jYu5-gU@?&T^g5gXLjc*{jh7xg*o<)7mqR1RZN0v5)ZK2;9 z;U?sW2qYx)9uyYcXn3Z*(gov*F#=})fD+bocan7!A3ZeQKsUf*@w_jgyVZ>@{V)@SFnLRQoT5PaMI z%U!$Ey}xb$seRgQpE=I#+Heb?ROu|(UGJ}N@6~?mIH?%`7eMRJt;EwF0cRQ z{AA67xS;u}q<(RFuOaWid|eZ85vQ#7WxLzHziPM7I``U~as8;30dXPoRoR1``}6DD zov>vy04{*m^V{pMN>{ZmFRy=gUb(Ifw&>4p0)>WrX^b5nnAUAC@H+q=Z^Cdju&w65za;@*f#hz=WKF(kS|R~&kT10Xq0 z`btgL-lpLrmAYhlFQBRtm{Txwl+IBNoK`+e$B63SK(uqRal-)UNN#9aW%pG}v6-J&=v z>aA^BDby}wUvW5AbAb4#I0$Z3Dy+-&=7f1cDpupzMh6N!faEZ5D(y-cI+TSKU44I9 z_Eo*!$gkEqjL=spqZenFiYt}XL4!Hn*E3cLfBO-Lgnh<6h`Lvw)9v!WlokjNKgD5;l@J$rR!7Cn1&uBuz+3W~B2AGNwI z%S25*cvogrpOU~YWIpL9yFQzsLP0-ZPgW^PAL=?gX(Hit_b*gYGowpGcBU7U* zf|k2@WRPfe9H_zKclA?hNO#%@`~L2~oM3u6NLSgP(@N)Bk6bdfa(h^iS4<_2RQNfdc5LNZG6$GtlwMkX zO%-2Lblr-8G-VE9Fg=JFh+9v_@q*FH^KCw4HH$pjI zsq_QJ_-*4#{n$5XzdpMt)g!uVc?7M|)2!~YB_ zl;{mTBD?~JTJ5kVLj1(oLoU;F69D@7e|6neC5w?KpWn~CofL{szdVFjDJ%gM7wlWP zA>SC}eC4s*l2a^cjXFDU3{jYU90#)fNJ6PTyw`+ITYRveXxka{lh|nvmM`KG%QP`K z1M*0MB#z|^7NK%8H~Tz3a}b z0JsK*yALEt=Tue>(*HpoKsg3c1Fsg6W=>YOVEQvK&$Yqo&SEC_wlpF3#!i}Oz z-JrHynQLL%wp{8?$z?KMQyx^vils)5Yr`tzs-c1fstWvz-5qsK|3pG6MS=>7`1Bk*a5Gyv5zZ>Fe)&tWgd)=$MyU?7?7y3454r!e)9hI={O-zqo|DBR?cNIPpIjkCsV5JW$@N z$rt-^(5Hd2UImd-WhZ-tMwxF!*4(yp#ynpE+v{7{>f=CuLL5IK4|5et zp&PsSb=K#9P$mjcj4b15!n}ko+lkoP?mqQDu{G_geo*JuO0Rmx8 zW*gB=*b)+t(}b7?K>b!owkqmHq;Eeo{j3Z!{$E73lH#M1%xi zk1%l=@Cru(8)yPmr*JDaey)H^wmLVXWNH!Yk|d{LmuyYaL8!bAamY!aB1=X%fIhqs zSq|e*LQsa(2lu*a)0QYN_<$96V~%i3wjR@{bz?7>v6}PS6KCO|GJ-+D*~Sp!*H38VLJ>ZNW|H%%J;CtsMe|lg1Sl*z1~XUSTWQy20pH4fh<=K<~IH zX_(8W-uO{+6V(?ogh$zHZDf_w1~|*HmLPB+#`Q#c_4Ko`01;#tCy82ot*!z_VmxI|EKEmA!M>LCbB}q z0Z~P_G{XnLDR{CudlCqK^fbltV0`a4EqYf_Zi3Bk>qSal(TE94*0Jk@%(BcJD3wicn;Q%JJGx`Mk0S$>IJANHRwq_z2Z7Oq1?L%_}okUPT z)dne(L)~V~)z>#HH^FF&%bWJq*~Qft^pC&)5Bhf9P5wCv=1skDDyml<-(Ko=wRm(6 z2^_0=<|OJhBaXL)-PU?n|M}0E>y!V2*wQ~2_hzUM0eCufyE8rS+g!feKyr?7yT*U1(nme8Ya@z6ob^$ z!w!d=0JJp^O?(b)S=gKp4%BME`W8p|kjPR;;RM|-W7wXFcC8&=LO`5?9CZ#BO41T~$$Dp5&d z0!2X#)|R<>5(mhGD=9m3aua;3bJ*C3Lt~{Q8cMh>3XrOZsjT_KY88zvRk2)(!k!05 z#apR=RbaCh5R^0(+M~U3F%MPn1bIr&>z151nc*$C!5(rJ5A>p*u43^ixqnGYaB!m3 z>20k76?M7Jq0A++a}xwAfF-Ql){qx-DBP^87V89UmHhjtkNbR_{+!C}wQ`4>8QgqX z`GnI)0!sPXoP=OggWE3Er%s=NMg)@azQ3dT7z7PVa#^^QbbhXHF$n=u4ipP5x?@`4cSW9zm+NHR=%z-j>9X zY94BZ+f{IsY2HqccdGD>b*`tMT_%2C)s(Wr?CYnNiBnVRXY(=`Yqt%2{oFF~s_#rq zY>%DbwV5ZDO0Vjx7(05@JgZFng)GTiW#NlEK)AQJ!s{{&3ks3e59<~Rk%CL80@%rP zFBN!EX`fTcOle8! ztpsJkUb8ZbwJoriR?|0S^waDPk~X4IB}LTWUeyPusvk6wb_@S+26a;@Y-29>IQ0iQ zV|rn8r#Zu=V$#5GulrLQapDs)s`LZ)g!=T^PM?jffp<|-eK5P!B`|xj)|2d;v0C*$ zRek(IIcX+hrqI(!%D(v-TgVRB+KkyyHn4vi?W6y?7GynLA7-h5ZOO6cKKAY8KI zV~JspNCvG-6~XP675%yvAlKOq2nK7&r$Tbti&eRhw7Y8%Kr;>S9fp(h?N``SPH_%UpCjW6Bw?DQxp zeGaP@UWfY^F#65jWJRZB!L`6PKCU0zwvAPke24?_A@b_gDO1@9qhgfHG6VUrc9L_4 z!7gloSb2f=_I1iM8pN3Uxuh(-{fH!K1=70J+o~Io4%rIvD5+z>`h60rT21P^Ry1ig zWN(z5TaoA5R(OsW4Na*MvjJnNcD7Ua(EHQtt4_Cd)$P1L{i$_vWrg51A#KiVbt}x8 z-m_3c4?m$W9uZDG{fP@7=~2V+JqoaA(xBCV5DDXvrC_H`5H3)mACDTvxfhg3Dsm!| ziju`L-FaNkQFpe!{ERv*z#)dZjyRyd>biZu#7q)Z<(oX`<567cN!moxRdj-YNJM?` zH_Nd~FT$RTp-hPm(;QK_GGZKcZZ46!Z0W`RfJj@l`f`FgUn96C7vn*h9QMJE8N=-( z3`vcTan$Ozl+i*t84*j(A+jOc4c31poK<=;4^_Di9($9|2;?)JW$Z<6+G^MFeZE zgdAYzCXd=SVhYpncrq)Ps;m ztkv@5Zhu51R-Q~w)HP`+wG`BBwQ~)=G0NT0V5!k!@`4d31BlCn0yF7;sfK*U!dOm^ zIZ5pXZLcP)6~W{RI5!#9w<#kJhb*KXysi9ldc{u-*Hrn@cU-D?ffU9kI>J$8%K**; z=Yn(DNuz4vT!sf=v3pZTGVwU7C}Au+gnc|Z%c zXu8M3p?wxyvmFoZ?-7UY*^Y zcghp@cFGg`JLSn{J7qmb7AAd6?z?}5%0)EPMeM?OgoYSm)1Y|Afy&H)Qk0N;4t-rv zj}9PEjfPT{R#l}RGnUa@Gk7j%%q~nuK{z$RfT1q+01=HGd$IzlacU$_q*pgZY(*M$ zK8hidR_7v)tVEUO1l0xBO)pJVx=VNcNekCcioFXw7D%vUk|mLq)_SRC#5X@Wv{pT~ zQ6V;|wWtdJysByZTmdOmj1-oIi=H%cEDdXF+uZ8(8UGxrf#hO(&HG^;F+RWo^$F2E z0l3ly392&YVpm_ULKLM)-2V0(Q2 zx3izmh7aQAZ_({T0hm#Fpg zY44Y_;ZNVjqhJ5y=1pZxTt_R~*)iE6*lqx0dvoTcS%OuESJ&8eO8BrXkjuIk9+ z6tR4i)#s{L?El=I0d8`$e6noNu2!T^j5zaj|4-9{*d#ek=W|)vHZs6kPElsVF=AZR z=9qM(pUf9sZU&2_@5MniXG0;$wymsPwiJNnhDTRQsHvv!J;s@|BcAoLUxj=JoD zgb!r!mp=KIF}-?f{i%1=`|{_T^S_?{9Djc7pLE1gz47fYhi5J2LDtRYgi3pFbz4?y zd2Rvr)-3BqSbzPC|M{wS`OD4WxAxF~XmyU-H|Lk9wVR*9&%d1hwH@6&$L*eT6mI}~ zYZNC{^Ag(yFpC3i)@kfQ0g^BPggp;xb_-R<$>^OyOw?Dc)W^vY?s7^q`h@y82n15s z7A#aMIcY7?i>0Zm?2|rL_eP+#HCT0>fbCpwZ3uB|+p=;b$03v%9zZ2{{8TYAL{AjZ zjiF-L(-6ubarog7Cc(worLHZaW`wElV&$$oPrO?rHK{0^AWI*e_y({ThaQUJUO+uK z(ngrSEc)dWA!(Qtqal23MUid?`4+t#S~<~B6;1;=Yi&eBsNsbrh2pvfEsHdBnRqz6l z5%;@4Do$ioWt_~)oe{bBUVE+3Z|SlKkhoohlPp>nM{f7UlKy=c2o-njZC=uOyaFlO z0h9}b`B(B0lz&+NR0Y9*-HgCi9$*QAN;pfr{xq+EZDH1;WvRj>S7jgOuE~Pa=T>{e z^rS@L^{HM4Q?pw&1g1sNS+_$i5mEM_oc#ItNI(~ix&l&VK-msSWJJXm9#EH%>gqS{ z`rn$x7Aa%IA#e4{8?=znA1Q-hg|-ta%rPzK$)Lwhzj)vG=S3s#Vh13rD|_+I(9S4D zi@UALh%X}zn`uKbU8x_aSFX7DH%rqV>w{kW2jZYg-*j;jEed(8w@dXtX9i=3QgL)w z3zJXcv9=41SbQCPNygGsVk}+R%#y$y6cl@KV!%f0^~kP!cYj z5(f*aR8n+uWcG$v<%tpSPlyFHC3s&53v<{TId1N1>?|Hrpqye1oXr%pZvN8kJZL3T z(`*jw^?2#ftmA#R*meCal7ynPx*EYyUadrjjZ{oDw>N|Y#*FDl$@PO)@S)wbNB$OW z9~oc)@GOm9%badgKEvj(218j)%V-!n!8`W5Q2tsO9a-9CSXk$p8~Yb`i7n*IQ)f`p zaY-aDzJqY3ZYD}ez9cEWn!vV8{Ghi`VGj9O`$Fu1v1;^scg^xo>f~D|w=LmBaXLfr zczl&__C1ZSlm%_R+Zje?1xw3C=F|L~v%ZFsBG)e9I$sy%3tgW^hr zs_!IsktPb(?H?TVuT9Q@osUrgY)9g!6pkR5c9tOh8uk1j>#?)KrHpYP{D2bSGG^#R zA@_xXp!D%Nb+>!bF7`k#bQNOkut`ZSk{BjGA{AH9AZ_9?|I*l8fxxSK2aLiG*9e|@ zDEO0nFg>D+(og^~WBrTZ+KIt4VP#4EX7Pp3N=BDi>X-6;fhsY7Spxh|2!2<|oDH^N z;zBZ5_zbxfET~y>Zt3v^2U_qSPzOn6^s1ZXjx;O=H)c&&_YmFQP3C-aUcd-4nIj}B z6bRk0(N1WIxDrd{W&&}QbI>^kb{e!5fr4>qzq?f3%-S@f_M zlzAa`H}=aPi*o6(rdZM+c_X`{!gZUeGTbKHb}lk&sUN3Mhquj zM2Nt_SA>8V1}Zhk9=`*G?f<>V0pKGZvqFc+RY|e&{sg-T6??#!)fqixYW%rL)d|r+ zeEk*N!(U~y$KK0l^4YCaVj9Ov93M^Us&+dvtG_<)M>@%UF}~*JOVRDoXEo6m)5lP9 zZ`rV)bl?b`{p>y8fgrrGaj>v#LWd0Hurn`%fcp0x)JsK5n~t{9U^nl0?v~0Rp%%Bb zy^7gpO3SP3>tUC>D@mF8BS3sv+-m~#VTNre)gM8>0}iRxzp;TL2W z!=isjxTxmf7%91;Y@8lpob!cz3C|FRx%Kn~dwG-J$Mg3*7x(H+N$pf(Se`^v=-2J` zH{7R%O!G8!*&qH3#3NIZ|tdZunZvWO%1wGpd&oi3QBWSeK%L z)xLa2Ev-E_ai(cjom^H)5Dyjx>m*lpI*%Leb==%pWambl(L@3$e}K zfPpH>S;B9nhQW*W(v6%3Pd3l;PJD2L1P-OAua|v7D=Ws&W5I>;cZ~>rv^9p>&2-+v zr-qV1kuRl+zpD5@iBKTb%Eut1FhkvQKA)IK-|<9T^>ICMwu|+m9?cO2dNrKb%<`AA zF(VA%Qtt83G59RtJ^h!O2UGG|r_5P5-Sf!c$6cG-&YP@1TquqA~pZ{(72Q#65Z zxlj2|UA}r&{&>h>z3|e)JE3vhrN9*Jvj6M%@#&`zh@rd9M#x(C&h1>o(8uSsm-Zjg z=xm@3a?DX~(2N#Uv~55RsnW~#kXxs#tcD%+Fvq*+Bi*!c$yAGMD1_Ar++)jXvNEeS zP%EpYj&VaNuT{a;rUYv5OkTkJ`m<*jJnM0V#V}TuAned<>hh#D<3IJgTX8PN>|bM@ zC1MTi@b3;Sc1_`L8TJc5FB7ig^dHS^!)v8(0sDm->pk=<_OL|m;!@M+!8~u8t%pAB z%8^E{FzCmtHkFNc?OEt;ll>Q-wSZ;ln6!zRpP9>jO>hk!SAlft`|8YX)7N7WxP#(U zFn|=Q^mIlJ)UgNb#S9q>*taFQ#>y8=F;X8sEA&<1woxD~TyreQG_h2XPqV3kjtfp# zE#@gE{tG6ij`5}NKK{V1fj9+B;))UyjrO22T^sGSO`17%BS2Nb{^%wazoWdJ*g9Pk?gOM&8YK=_w}dTwUW)Jj1;!$ zN90ci`eEhwy<(M$Y&Nwfh=s`w&(_qa!lS%bdYRu&g5`?zXn`(@!c&=^e}%l*&>ede z`7v%PbQD+HcqZV^uTgW%ZOa4e#IxIQb7IJgW=_0RCH^qBLCFyqYwK1Jv9Pe_s(-3* zhc**|dh6SMBF97ZCRYJqXTTe;1DadRJZT5hukPc&%Dx4qFZVrde zP5IwHH~p#-eZFv*GiO2c=?`Mwm_D)NII=9mB@?wFe*2ns2kY)>U_6oUHBaGi&`zlQ z%k{WYT4HRNsP_>jZR-;&YHumNaV{+40~@hmj;C<}gZg%Jc-8P$DfPxGxJyKYdg{_V zS#^AGp+T%WU4DtHR zeftCmZ|v8dt|LV=X6@{m2~BzSMSVN1hILz@%N~cPbz3)p+_}EfSKlhXT}03QNgnS! zEpdAH7QiQqSd^cg1&0^J=$W(NHtM7mcF~5{@cCNbB>Yir(9CAfW0uaDy?rb%pmC~T ztFVsKcg=cq7@YyjlQaV}6FPub^S%N5$uN?y6chDCf)tqY3oGri0SrTSE8Q;_;~ZcS zE$hyRfa@@m*2XfvO`a=$r}_-?Zb$H2Q<6t8y+yxDgC63Z1@WgedDwLJd|hW#B&I#d ztl7U#!noMGs3UfEpmt^HRw;A{(e>Ip0gHHhNu+&LW2Y1W!X_&}PSgJnx}#CN6(u>n zOu~Jm)i6ei2=+ua3yiIW+%@R>{QO(F6KWu2ufZoZ?pB^*dpOJjURgC(V5LehEBl#{ zzD4uf9`q59fOH0ZPfEYeux!%_)AUe_91y)yP)@TU$rhdGN5p5@F2R8iLbej-`O5z{ z^T(XfGwwZi)Za=RhV$n1ad1m+4HcDIK&Ve_$U$9+zQUVT#@^uB3(+iE6!Ug>1XH7_cE?q0P>I{mRi8Xf}S8ZKah ze1U*8xm2NwRu&7XwyoK9;yPqcy9wt6#czs~eDCoet7d~#lMSv`NrqwN^g9DwuEm1?O-=ii>H6UF%KHkT_}Rvy6c6g(ummusd?-*w_X$<#XKL+u$6V(ySLPQe z1#nTgO}jB0Pj4;AJLp(jUuoazBcxKh;r!hTmhek%t% zHp%xZ$=Ou979{LtXs~&t&bKpT>F1~9ogK=(Cvh;ns(#Z{Ylaq`m?A)!_3?sP zaJBd$iqd|thM%G217j}$Lad&Ndr>Qb(tZE-ob{wm$za;%ohyrvlDq%xp1%KN=nv0W z`a<2mmj)knqgY8XREA3YzZ^d@vdGGRr9mKc5j{n)RJ1D%ox;mj(gu^2xY5cOA#m}I zUse9g1Rscr!SRKgL#(UhKv&I_S#HkA;8&BwS8~u``qkNmzzCJjONMX*X1&P89|%c` zn6cr2fp4BD?iSD6IB^D(7W><+sRv-!y5pLFa0J}-f|Dz*cMG4V|c@n{8c9Sj$Wd;IT63HQptT=PI3@Xp!_#xG@WM~W-r(NCtYunl;mhL{p} zWXv;$Zm~kP9k~Puwgh=!z0H`k9Ef32A&i1lPz^~N28htd6N<_rKs!c>+J_GWRR0+B zz7vjHoJ*NI;%brjD`PnO4~M5?@F1a_E4(o+53#)LM2mH4UenY#eAi|Jj}(-;oJ)u} zq4wx97|Isv)#>lKwnc>kQ1t;t5@p}X3Y2)XO~vCnn6%QCjQa~h`8%K9;(_8NHA$mM z5|==`lWrQ`K1#>YM-Jf5_IJ=|i2^!1)0z#UK`S1!upNxX0>(RLfto~nr-f@~ZDIq= zkGi*tUN;xzGB$neP|O#;Ba6oql12^Xi4~NIzjfaDvwIDKR6#UO0{NVXMKZ7&2QQm( z57HuT*l4qVRg|)+6JAr-?V&XH0J|hz1L9Oor@d=)@%X%>qT&5N#N+d&^`~)|5Hz{O z4d=oH^2x{5S!L3MvO6inD4Ze3b{Bbd1#3bWt{m%2QapcdU>f9dWl zA^WxjaL<#5>0p92!8nx2pesbQG3J-ZRcYOePE>Q!qjTSoxi(9hr#~u;wP_;em-ztA z79RdRl-#Tyj0sJk$=W8DwQMp~HEv!h2Q^h^kiRQf+4s&ns*iT}&i;D+J8Pbyn9AZd zQQ0OD!3jK{$$q+QdBTxdvlL}{IG+B!wKoQ*nc=!_FX2|S6x>sUp+(TOnqzkSu~+Wu zamyH*Z3_Mxx(_n`5(>-_Bz8h3gNkG{?Z(O$F7VhrYsz{|mmD{UZ8Y~Z*`qZfp6NJ) zWV7s+l*puP_haNwmVMdh_>WgE%FtD*Sa$*rHJq(eQY7(wGaSJuYZGl?GySP0?(|i( znUb}SFFWOAs#eEqjmHamd{u(%zMFhJmu+)54GcDOn|Spe_i#`WLwWi)T=JzoNe}EW zOoNrp=`~Qtl6BHjEFP033-n4Ix0`uO{#-VA`6$EJP=Pm*lq$}0yDYVn_eb5Q4Q0kL zHvCvumQL0&xx6}~io5<+v>N@R>DS%<^(yn3g%&qEsv8huN$ft-Gr!y0o!_@f$i{KlsdUO)A{OgkWBP_PtO z253aVT8(p8dsD0UfZ(9>sv&=C0An$VH`jYiHtFSY70M?Y5a{8T6rDYk3B97aB%uG_{D5bdN#d#n=5v=@I{FlGGlQkIOjY(dKp&2}Hs@V4pe*lHG>?U_bFb13HJ2 z5r(dv9CaCrw&KR?o$j8+@mC+j$t32M3Zz&G8k)nA+CTY_1(*?3*9MU#2NgbFTZk*^ z8gvy0A2-CBPRHEwPjUl5@Y-cRtie+FG6U*Dzc4;+H<&z`_Ux z*D7r_5@s-RrS_zUOU4n%?zD8A@*G!2YYzN>B>w50t1w`X2@)%>QRg2$2sI4P4~KwV z>D8bd!swec*ivx#5hA-!M3qwmAw^Mb<>8nDATKspKX>Nfv2FPef+d94f^1dps2)j{ z<9$U^(6eKbsvoM2g2{`vJ;>kzKRZ;BY)t!)6DOaW^Vf|0SqzfHG1)m)gZdzUIs&0n zdY2^Ld?%>!vAHwunIL~MTe}8({h)3sL*Y#yoGK=!0|wg|r_jZZ_nLv^=REp*G=iDR z6;mm@_vnkOS!|hnx6!7Ul`rzNsVSypaqx~}N!M(qOpGM#Nyr>Sgy7{X# zm6z2LH(TnDID=bzg*|lz9eaf{I~ykjJ>6BNW(2J!eHWo(p}EyVc;Xg2ZK}&sX7(Z@+K9NSK#vLaRk>7J(UJ6aS&?8x%HopF!cHC9ElU zkqLy`rvt49#t~Kil<$|!=y~u*9b=&n{}s~RPk;V=f|9RZ73Z-S;Z(E51Pgfic_YM% z8j(C!rTk-#ix||V3jmE~u!_J@MbwCwRn}WeUFEdTF*zs&;zcxHsF+>c3;B%vk3kW% z^d}hgZO!viXP<~K#fPvpBaG&y;diS=*z1Y{?QDc_0Iu9#D;|NTn5V=UG*x6{i4{fn(tiz@O4ky6#K({SpYKD3fwvg=7txk#! zEwvW(34FLU#Vi45!+6Wyx;7n^!_NAQMj_WNMVkDih7JEf;@c`tR?$DD9r$0M+&Q_0^$-qzW<7T3 zSefpLuJb@d7D^YIdJExcOUe>?fDHqKFkQ8=*LnN$YRv`br*8eBY!IR%YNhdrBMx{t zbq3`Fa=#aNj}vQv`Xn;Dqg~y9;r#q5tOSeoJ`~>pp$e0ZsKq7Z<>wM{vK;TGC0Z)v zPwb%~+Ltq_J4cMf&x|z5;Di?@a5^9VLg-)3cQ<^NRr^i>P=ASO)vU2gT24c9?<;|= z?CqY3V9KR8jGYFpgWI51Jrd=Ccy6&i2XS}R-+oCl1Buz|53Rg>kQd7prYVZ;*{1vad z_!nR-Jl8@qmS+z2IV0GO%YHV5`sv8}+w2#2+s>wAMxU*+C-3XqFUBz{AsHN$Y7(rZ zAAf?l31AND%HWqfA?sh1(de-tq`e~Vm45XS>;tG6Q@`Bd+0{uN@o>bIrb?HW22v?s z+3^nGz@XY$Q6X*Qy!GUSi-f}H9!BHT`KO44HqoE`C)H>Lrei>^Hb`dEu4phbX~W2k zKgR|etdDylOa&Uc(tr3KJF+F2)sPfB?>gPil*j~!l;@!0XCuBf)>4NG zWXejT-CFZ&1PDvNMOtw~_+Z%21ola7TrnyGtSB)-HxwpUz?S2Jolj89&m(Qs4(Z-Q z#%SU((c_5f@44RoM)B#^_lch*Szx;;9J+12d}3XR@6)rhXQFr%_m|t=VMcH6+Cem> z@6e3>FFDv27hNC#afrE7riYS#{-NRyWkYVuUsflFVG{Vo@W#%rCk8536XjrmjWuYJ zFUU{yYHE(QDkXa$`b={JILt&88ICCbi8(vVrW_!(bA4^ch3CL0B9Qum_V!in4{`{9 z0x;9zn}tqLa>{Hh&(Dv966L2GRi3A)k*&Lcj#3iqLzjM9l=DB?7W&x~$|Xkl2-Cu4 zt~tn=dr2vG$i1I7=|%Jbh*!mYqFx#E&;#vx^bfu+Y$nA|%Zn5bK19AO(i|-PG_^DcAxwYKiN`2jQd5b7X&4`&8gB;h%O8^Z)PuUws zG}fS&;+Gf+(O-OT$8U%@a}gm(geZfAYc6nv-kr%bp`@ zqGqwq5(9{Fkt5Yl{JmbfWYuQ2c7&!9=97P)l@d3PKC(C@Di5d2y=3)E9YZ~%qV(~# zUuEik^5%$PmV`>yPDS_726x+Oj^(LkC`XcnI&ZSYL;nzlr=Yxp;_y5`US3iPu{6GX ze_yT0{Lr~Y#6UnQ4J||YR+55BkEqfq0@_l=2A3u{SR|oaY>DgvdoYuny?QrDqcSB% zm|^xMMrSi{cm!OFWXq+?ScX`751>Ljo6a6dewHB6+Ah{>iU9}{rKN0Z0-55R*D!0yN{RaZiiVFe#yh8df6qha(K?b6F z%8o%PYTt93eb7==y`mzzb|BR5=t9=t}}i&Q{0yt1u)Oqb5if#IpojCyCgm40alE+cL`Po5l!5M*oglOz`E;M^zgx{a9DK#J;Nbv0w~q$%NU!*1E>#KCr;HRqV_M%;o3AZWW%ZegDy$znlVu!$D<=J70sX*dr`~e5K zy+^}^k#$&d=iePQI_>PH$0DBAarQZ4n2$79;Jp1@w(4MxWH@6bU7W7}5n0^Z(?Pzh zV1!y&KmH1A7(sc&fq{K6{5_K8vrpWooqQ>^3Q_ElSNC~s$Su13 zCp(^s_AK&+^|0x)%K_B0OHqr*CnK20r-TOQ_tIeJ_tDihAGPVWO^4J=37l0o?F_c@ zGDTd5iew4yCYgEd{w#9S_gU>`B-v457aPKqm`fARG64ph8A{6POmb`Db>imp>3Z8` z+%j#Wj$OL-n7gUVBs9%c{hzCLwR(S4e=koI*PTxfLoLZ-6P6CE{Yky_Tm{aIw*`+J zu#RAH44k3!|2m@9Z@Q#jn!~IL0Dpk>`I|0oX*Q`2X*N6^vK+FlvK-l)r;pz~~Nw)WMd2*}N?_aNLZ)h=jOiG--3~jLC93N@U z0ya^%V%ay;)?(^^UxWf5$Nbj@bp5nWzHzJEbqWcP;HHIV)2(KjrLqVK2%W(AfqPiV zH0$sSNKIVPTA?C?>ALFh#L%kT-?0Z4&?Y;qYcCr?28D$u|i9?{TMIyVWaKw3kaSi8PD;Z^3Oc2UoFkBw$S3 zai@oG*krH=<{dafOO*Sub3z-K`C?FqZ`3x`))s*?DF?O}f$iROfI6vl&^pGn9)f*o zDpPa*8IZEKDfqcZ-QwD>g1qya-|>mgL#4mrAfmxyED1G-ToJ%8o0EJ(=do<3-mUNL zC>K>3XCb^?a{!tR_}K z>ppcGD{jav)E1GSbJ0j*leM(x%w8m$aAGGCl5ZxX7GKjk#=B5wpy1T=w6Btx#g&2^vY19;NY;}KR7>-7G!aG2Hq*1RFu zhLC3hxZPF-oKi0ffCIRoTOR@bRU5d1xkJa0$EMjd{V}!o2IlEO!VR;EeUc=q%z@D~ zH41cC_#2c|%r{8P0~(@|5P>uZV_bN=JGvR^_e*OV!6)9pM~xq^yQD~uY(U!Dt#p@% z(_ATgEK(feR)&4o`@+m5C|t8Xyh~&<-76CN)#u|!S;J`a9(~r z6-AFS8p1Qi)d>E+A@1J-m)Z*&;d&)%eJ0N9LSi+3aqwe|h~NAA5+#Y3p^1McA=&bx z-lAq{^^SPHDHMpKK#7w`k28X>>ZZ=2hO>_d2PgV4IF=WQi}|aS_{4f^{PLiv1@C+- zI`h8k(q*_%s_AJWJqv!z_u(IUbEW@?^XVU(X(^SHz&WUU@k@L8ydbkD@6t&c@-BkR zTTGOO>`^J#kt_@XhA;5&=a3bwZEkmpzo}VeCaK95au_(t?0kGMtYPp7=m0RIae{I% z@0;tu3#ft~3h`)0J|jgmmek4$+1t?dA_F{)u;Byhm7Ffd_OyP%54E*DNwwzD(Ir>l zfG{u}BngCG@Hv43|VmV198gSJXRWb zw!8mI2K-lJYc>Vb$oZN)Bat2|6%Xx9htpz`c>uc-@`?vXl6>}ree57+Ww4R()rf$ucUAg0lpj|!XusbEe{U8kT&M?inr1Cr zN-k1>Jiy*!UOTp*yn2)>(d57+V%M_KJ|#bG#%+2|_Mn&u)4X+3d^g8u8S+pG;L3Ub z!nyh?1C<%mX)!m6)N}chdJAn2LX!N>v$Ic&UUJx+!ly4Mmc0`%^=KZRFV|2o&nN(* zOJoOMvf!Xo7=`FYGCsjN;}ho{Lu|P|MkyAmicerqN^0`V_1~? zOLipg$8_*4dwTuMPQb``9*o{dK&TObCA0L_-ZHYZh& zx_F!9GjboNql<*M)aIl^D&0f-kQgS@IfkrrV<&Y&G7AUS)WRU-iF7oGFvoy5K#Y0X zU-g#W$ap8iCriA^abgQauzz20wh|$kI6!ZIcFt4}Wn4$jt-1S)x8|Ad9^4Yia3+Oe_7LR5N#* zwSKl)UsL-2g247)pPM@z>-ENQ4ev+V@z_a;*O999X8S%DbufFn#lPwy4S@|aVJn)gH&lJb0;OP6tcJs*5GxvH`APr22YM&s_2_>^gpd-f>VuSKCCZcAs z-e3gLM*=jup#aed>rdTa70G~gr@5YxUW^=yUHteC$h*}iQrp`7QwsMVPtvr7j zoOoCmpGZ-3LUxqY@W=N+DYY7%e0x1PyQyx7u3UlzW~(!48 z8;R4Xcfgb9PB;m^I34!$Z)759kiNtxOQFLR#F1ALH)n!#2bap}ayER3wH~mJx^@(3 zpN^+K6*jv%s*FM5`u)Hx#Y=LGrZlouWVO8gP;pgPJ-Krh&l^N^XQT~$F1hw&jLax3Y0^zQ zEhP%eie%6b+95!`nZhJDfBT8a@nsMRl6 zD7rgoH9N7bf#mSw&jcs$p+t%P7EE5`TmGp*(LHmDim#bAMq{5teTrkST7L@E7N zLE;GM0x=34)sj2C-JHF@LrTMpR=mh-CU~!Qb+teN0}2aSJ$AW1|293IX<*|37{0NK z1VPlE6#-bw(IUWDjwfC%qcDk9hE_j0rEikacB69X98(65^$H;(zI=Q`&CJB%eAYpU zIqcTVEG90l{56IB$kBa3S}-ptf6~lD{+oz|lm@a~6YqKPM|&$z&k|_ZaKtEqOEWN} z2LkW?L2~t6miB4WZa#iR@p4o%Jmjt6yu&KLnGDZwRBes`7gQJc)A0ypk5@ z3LYoT2heo!t~@+A*YvMy!i@B~?bZ1ls6KQC_a@vk`~OtILvE}jT2aK;&a?vaPmZt> zuW^YZI3~G@9Ow+OWYlY6Pm{Jye*QP4#h_Qh9&avg_@%WE z3vL#UJV`xGnalqRdqGwC+JTu`{(6~e3 zVgq=+XCQXXf$3p-4iCQmeoYH817YD_k7pLFM3XR)qDg;(pQ6j>DIyNI(0vk{$gVQK zQf=e%p^I!KSXV>;A)VT>cw7?tedlJ#>j@~w2?0`bOf~Fe?uB)N+qH-*K$e_r0T2e zQ9H|~O8CwTlo+8CXU}UKH@Yq<*ibK&0HD>XIA|7!!>rIQ|3?>6isgkQc14(1an4|= z^4X1n&_g{;;@(xYP3e(?Hu?y2u-@KwRPKN|f!?07Z=zunaA7lhMxGhd$ZLb+XfmKE{jzkeawRf7H{uM%l!+w26WZqvo*^9?DH#T0 z$&3#>utXyFPoGC^+mu_Y-EM%q^7OG=@Cd(?0{1CjtnV=21tK?!DCR+uX#35wYd;8; zM>^h^k?dme!#_smr122w-zNBvQoT8b{y);2F8pn7Hukg`yMV6eMfdx%m#Z(&!Z9T~ zRYO82HlD}Q*9Zc)fpg?B#G=_39#bhPKb2CT#5MU(%*N)z{u4Lau)Y|O_DNS)E3mFc zMuV6U>{3Xk9GIiPiZ&puv9+R&YE>C1J;Yw|IPk%6c;GDFu}aiQFn2oN({4jCH&4no zKH{0~L*{uOu+ta=P8j15OhAp3&)|*gEpsc%Fk&)dd(#Y0^w+ENYcMdJakq2ai$9ud{mC=d0GTOR?e1|zn zk|V=|$zjuVf3bIaz)PGyMn3;sP>|Tf9LFcVS0*BAHTPMW!5V%5l`nyh} z>ZjbNGEhkl&u-+pVe8bCm(At}o5AWr<#=eYuS#B7P4ys*H|%A^%6+eI@EQD0-6lxLb9o=SgSM5l!$(0Sy|rD8u?F99E0lZ?tRr;-%)xc~6FrFVrAgon?YTAA)zeoq{{aJ8_stuA(^LTi(g+2b;0rlmHSac| zkdi9=(;^;z;7eE2&x4Iwa`g8yf`|{Vie3*@c0JZ4>(Wo8laS1AK^*Ps6iB*V5zt=c zdTKgqT>X63@Cy6|1ID&4yws3CgMX*i>2IjQ#8^H0VSr~%)`VL=v&X8G+zwVHyQEML zDgtFiHjTfVzxqkO3Xc}OSV!c}*2koabQDP+tK?qgdfjr~UCdn{QZ8kGF;JsodH`X* zgSp9L>J4mDMNHULbZBq`EA;D+&2{|?wv!5aRig#OmUrje>ulERknrF zT2E6Zy5C_2R?l$bZBE(6tRr8oE6QEK=t&yVB&jTu%6$DbLjTou^b1Cjo2#e8Zu3vg zHSrhYsb!27u+rTKL!3ZFC;6=b1g0{mTJ4U@wq^3rmqiE7F~GCVMTCNulrBtHVZEW? zikVARQBjUE>BW}2b88y_1=`flp#zIzip3EweIGxYR?_fJX5rGiDldGZE%6ZEFN5CQjwovk8% z##O7^B!hbymP*rZVMs0F+Up&zq4KT6j_?rjk2{k5aPHrtDS-cos$OIm7_wI>^F3xf zi1A=O6wqZ+qw}x1J&NCo@k(;P_v56&skV zphhWS$L1Fd7s{WFrz5JFz|Dkgr#~=IE*Esen5D5HKTK|WiOv+83_w+LL$fe%Y)k=< zcmaFE|nDc}{r4Q;CwrFmhufiGd#N4QOXZ!rrBXa0J$I zGOC)Xo8Gk!G)Uvf?XtJ5l{7?zD!UFeT@B8Y^&@l(jHMfT2hbmZWJQmB933AJjv7BOzR0=0ArvxG`QnVlkI|Ndi%xx@2qlR#e>DxSc8p%m z^NTC@XJ81i2S*_V+&`y+p(X?%ajMN?$rjrC^RmD$0S1?goi=;*}&;BFH2tB2?gM)(-M`JT+ zAu((PC{JB>bYDi|U}V1veQZ9t+&ti&drLX#BbGxx0(~#cr_vVWV2+2n30@G#KUPmb z+6B1HUt!t(5ofi70S z*_`^;6_4PipRJy*UQ-98F8tKUE|0;cTZz}=)mE;a!6wGc8XfL(TSupWtzJ9RstVB+ zbFqRYEVYXv=}e--sI?{{oKeyBERVbH5mGy;t;jD@!nI;UIumOlQ=Ura;hJ!W7WL}E zDZfED#1f2pTv5lYK@lq6p~L7*jR7i8JZ%^a0{msz;}veVKh{?iUPZXV0lY7Gh8jDn z2oE&WcWIm{4Lx6h;&G19(xN3*QCTuR<#Ty!YKQR-Dw96O6yCg(u3?Z|gD3xCC)y<* z=vp@oJ=`G5E#1?gaZn?swXm_qZdEKhMsJQQX2z%h`EIyL1%OyJ%{P04>lz@7Lw45E zZ#YKgZ#Q?J&wJI396EQh8V(q}Ly+<7E;U!T zlFPLdfQ6@dS~`58l5d)^Q_kYwKh+^r_~r_>FulPrX+F@as#*(TxR9pJ zsu{B#Ht9j?EBG+Eeqs@=s#Cyij9?Ls1&s~ZvT#e+1FTrv#>791+j44*4*HCyNW#)4 z2LcX%w?g;BZWKX^^%zR$+`Jq$7U9_)cI99RoS3E0#pen5P?R^9j7Xp$NX|CJt@CTO9U|cRY<4Jt)jZJ8I4T3(_kx4}5)H9K_k67g-(|eBt_;%7pSTP=uT>I7F z@JfF$vDnK!XbN-pW#nDuh?#ThgdHY;p2SLlCz?>;%~W`lNR pGXdfIElb%V4@H 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 Yl|-;7e2? Date: Tue, 20 Oct 2026 19:05:27 +0530 Subject: [PATCH 59/68] feat(core): finish independent marketplace SDK acceptance --- packages/core/MARKETPLACE.md | 36 +- packages/core/__e2e__/ci/ci-reporter.js | 5 +- packages/core/__e2e__/ci/suite.ts | 4 + .../core/__e2e__/marketplace/funding.spec.ts | 419 ++++++++++++++++++ .../__e2e__/marketplace/lifecycle.spec.ts | 43 +- .../core/__market-local__/marketplace.spec.ts | 319 ++++++++++++- .../contracts/MarketplaceOwnerFixtures.sol | 46 ++ .../core/scripts/marketplace-local/prepare.sh | 17 + .../core/src/lib/agentic/contracts/reader.ts | 4 +- packages/core/src/lib/index.ts | 4 + .../job-spec/__tests__/description.spec.ts | 62 +++ .../lib/job-spec/__tests__/preview.spec.ts | 66 ++- packages/core/src/lib/job-spec/codec.ts | 3 +- packages/core/src/lib/job-spec/helpers.ts | 70 ++- packages/core/src/lib/job-spec/preview.ts | 159 +++++-- packages/core/src/lib/job-spec/read.ts | 74 +++- packages/core/src/lib/job-spec/types.ts | 17 +- packages/core/src/lib/job/job.ts | 99 +---- packages/core/src/lib/job/types.ts | 14 +- packages/core/src/lib/job/watch.spec.ts | 140 ++++++ packages/core/src/lib/job/watch.ts | 209 +++++++++ .../lib/market/__tests__/ci-reporter.spec.ts | 38 ++ .../src/lib/market/__tests__/history.spec.ts | 143 ++++++ .../lib/market/__tests__/namespace.spec.ts | 18 + packages/core/src/lib/market/data.ts | 68 +++ packages/core/src/lib/market/deposit.ts | 7 +- packages/core/src/lib/market/errors.ts | 16 +- packages/core/src/lib/market/history.ts | 123 +++++ packages/core/src/lib/market/market.ts | 171 ++++++- packages/core/src/lib/market/types.ts | 7 +- .../push-chain-native-multicall.spec.ts | 15 + .../src/lib/orchestrator/internals/errors.ts | 15 +- .../orchestrator/internals/push-chain-tx.ts | 13 +- .../core/src/lib/push-chain/push-chain.ts | 16 +- .../read-state/__tests__/read-types.spec.ts | 3 + plan/SDK-CHANGELOG.md | 8 + plan/marketplace/README.md | 2 +- plan/marketplace/implementation-status.md | 32 +- plan/marketplace/questions.md | 25 +- .../sdk-independent-2026-10-20/README.md | 54 +++ .../api-comparison.json.gz | Bin 0 -> 52200 bytes .../checked-files.json | 42 ++ .../fork-before-confirmation-fix.json.gz | Bin 0 -> 2047 bytes .../fork-results.json | 1 + .../funding-evidence.json | 86 ++++ .../funding-results.json | 31 ++ .../live-evidence.json | 79 ++++ .../live-results.json | 32 ++ .../post-live-state.json | 78 ++++ .../unit-results.json.gz | Bin 0 -> 74643 bytes .../validation-summary.json | 71 +++ plan/marketplace/sdk-readiness.md | 32 ++ 52 files changed, 2826 insertions(+), 210 deletions(-) create mode 100644 packages/core/__e2e__/marketplace/funding.spec.ts create mode 100644 packages/core/scripts/agw-local/contracts/MarketplaceOwnerFixtures.sol create mode 100644 packages/core/scripts/marketplace-local/prepare.sh create mode 100644 packages/core/src/lib/job-spec/__tests__/description.spec.ts create mode 100644 packages/core/src/lib/job/watch.spec.ts create mode 100644 packages/core/src/lib/job/watch.ts create mode 100644 packages/core/src/lib/market/__tests__/ci-reporter.spec.ts create mode 100644 packages/core/src/lib/market/__tests__/history.spec.ts create mode 100644 packages/core/src/lib/market/data.ts create mode 100644 packages/core/src/lib/market/history.ts create mode 100644 plan/marketplace/research/sdk-independent-2026-10-20/README.md create mode 100644 plan/marketplace/research/sdk-independent-2026-10-20/api-comparison.json.gz create mode 100644 plan/marketplace/research/sdk-independent-2026-10-20/checked-files.json create mode 100644 plan/marketplace/research/sdk-independent-2026-10-20/fork-before-confirmation-fix.json.gz create mode 100644 plan/marketplace/research/sdk-independent-2026-10-20/fork-results.json create mode 100644 plan/marketplace/research/sdk-independent-2026-10-20/funding-evidence.json create mode 100644 plan/marketplace/research/sdk-independent-2026-10-20/funding-results.json create mode 100644 plan/marketplace/research/sdk-independent-2026-10-20/live-evidence.json create mode 100644 plan/marketplace/research/sdk-independent-2026-10-20/live-results.json create mode 100644 plan/marketplace/research/sdk-independent-2026-10-20/post-live-state.json create mode 100644 plan/marketplace/research/sdk-independent-2026-10-20/unit-results.json.gz create mode 100644 plan/marketplace/research/sdk-independent-2026-10-20/validation-summary.json create mode 100644 plan/marketplace/sdk-readiness.md diff --git a/packages/core/MARKETPLACE.md b/packages/core/MARKETPLACE.md index 90e5e7e8..3a5511e8 100644 --- a/packages/core/MARKETPLACE.md +++ b/packages/core/MARKETPLACE.md @@ -9,7 +9,7 @@ This SDK checkpoint targets UniversalMarketplace v2 on Push Donut, its pUSDC ker Use verified application/token addresses and raw token units. The following helper returns permissions and a criteria template; it does not sign or send anything. ```ts -import { PushChain, MarketError, type AgentCardInput, type AgentCardRules, type MarketDepositResult, type PreviewJobSpecOptions } from '@pushchain/core'; +import { PushChain, MarketError, type AgentCardInput, type AgentCardRules, type JobPlan, type JobWatchCursor, type MarketDepositResult, type PreviewJobSpecOptions } from '@pushchain/core'; import { parseAbi, type Address } from 'viem'; function authorCard(app: Address, token: Address, receiptToken: Address) { @@ -41,7 +41,7 @@ function authorCard(app: Address, token: Address, receiptToken: Address) { } ``` -`client.universal.read.prepare(options)` is the same pure authoring helper. Existing async `universal.prepareRead(subject, options)` remains the paid-request preparation API. They produce different representations. WALLET/PARAM holes retain explicit positions; a literal zero is never guessed to be a placeholder. Dynamic-layout placeholders are refused. +`client.universal.read.prepare(options)` is the same pure authoring helper. `client.universal.read(prepared, options?)` sends a resolved prepared call and returns raw consensus bytes. WALLET/PARAM holes must first be resolved; the sender rejects them before a paid request. Existing async `universal.prepareRead(subject, options)` remains the paid-request preparation API. They produce different representations. A literal zero is never guessed to be a placeholder. Dynamic-layout placeholders are refused. Descriptions retain ABI function names in memory when available and apply explicit token decimals while retaining raw targets; chain-decoded specs fall back to selectors and addresses. Cards name one execution chain and one provider. Destination tokens resolve to verified Push PRC20 routes on that chain. An explicit `{ prc20: address }` is available for already-known Push tokens and is returned by lossless rule decoding. No route or same-symbol alias is invented. Structural validation alone does not establish deployment or liquidity readiness. @@ -79,6 +79,17 @@ Opening deploys/reuses the AGW, grants the card's exact resolved permissions and Opening supports EVM typed-data signers. An external owner's UEA must already be deployed on Push (`OWNER_NOT_DEPLOYED` otherwise). The SDK checks the factory domain before prompting, then simulates the complete signed request through the real owner verifier before broadcasting. UEA and ERC-1271 acceptance follows the deployed contract; an EIP-7702 delegate without a compatible verifier fails simulation. Signing capability checks run before prompting; a verifier can reject the resulting signature after prompting. Provider writes use the connected signer's ordinary Push identity, including when the instance also has an AGW execution context. +```ts +async function recoverOpening(client: PushChain, reviewedPlan: JobPlan, txHash: string) { + const tx = await client.universal.trackTransaction(txHash); + return client.market.openJob(reviewedPlan, { resume: tx }); +} +``` + +If receipt lookup or post-state verification fails, keep the original plan and reported transaction hash. Resume verifies the mined input, event, permission ID, wallet ownership, kernel record and marketplace mappings without another signature or submission. A read-only client can recover an existing opening. Normal writes copy reviewed inputs before awaiting RPCs or wallet prompts. Provider registration/update also simulate the exact card write before submission. A reference ERC-1271 contract-owner adapter and compatible/incompatible EIP-7702 verifiers are exercised against real contracts in the local acceptance suite; custom wallets supply their own `UniversalSigner` transport. + +Native transport errors also retain `txHash` and, when confirmation is uncertain, `pendingTransactionHash` after broadcast. Atomic native sends never fall back to sequential calls after a hash exists. Track that hash before another attempt; a confirmed revert retains its hash without claiming that it is still pending. + **Current destination readiness:** BSC Testnet has passing live open/cancel coverage. Sepolia, Base Sepolia and Arbitrum Sepolia have different CEA factories in the marketplace configuration and current SDK routing table; preview returns `CEA_MISMATCH`. The SDK does not substitute the marketplace's account for an independently derived account. Align the deployment/routing configuration before opening on those chains. Card IDs, versions, ratings and job IDs are bigint. `jobType` reads are the canonical bytes32 hash, not a guessed original name. `cards` walks IDs with bounded concurrency; summaries remain readable even if an unverified provider stored a malformed template. Full `card` decoding/preview rejects unsupported content. `agent.card`, `agent.update` and `agent.setActive` manage the provider's one card. Preserve raw `rulesBytes`/`jobSpecTemplateBytes` for archival rather than serializing away unknown wire metadata. @@ -100,7 +111,7 @@ async function depositForJob(owner: PushChain, jobId: bigint): Promise { + // Persist cursor only after your application handles the event. + if (event.kind !== 'Error') console.log(event.kind, event.cursor); + }, cursor ? { cursor } : { pollIntervalMs: 3000 }); +} +``` + +Each delivered event has an exact block/log cursor. Resuming excludes already delivered logs within the same block; duplicate RPC logs are delivered once. RPC failures retry the same range, consumer callback errors do not rewind delivery, and unsubscribe suppresses pending callbacks. A changed canonical cursor emits `WATCH_REORG` and stops; reload status and choose a reviewed restart block. + ```ts async function stopOpenJob(owner: PushChain, jobId: bigint) { // For marketplace AGWs, one owner batch rejects the Open job and revokes its recorded grant. @@ -136,7 +158,7 @@ function marketplaceErrorText(error: unknown): string { } ``` -Cancellation is client-side Open-job rejection. A plain job has no marketplace grant to infer. Other terminal paths do not imply AGW permission revocation. `claimRefund` respects expiry/grace and remains available while the kernel is paused; a third party may trigger it, with funds returned to the recorded client. +Cancellation is client-side Open-job rejection. It does not withdraw deposited wallet balances; those remain under the owner's existing transfer authority. A plain job has no marketplace grant to infer. Other terminal paths do not imply AGW permission revocation. `claimRefund` respects expiry/grace and remains available while the kernel is paused; a third party may trigger it, with funds returned to the recorded client. Plain jobs can use `job.create` with provider/evaluator/hook/expiry/paymentToken plus either binary jobSpec or text description. The kernel's Solidity string slot can carry binary JobSpec bytes; the SDK preserves them and retains the original createJob selector. @@ -157,6 +179,8 @@ This prepares every raw read, checks the total callback/protocol fee cap, then e The result includes raw values, decoded fields, request responses and fees. `pass` and each check are `true`, `false`, or `null` (unknown). NUMBER and PERCENTAGE require an explicit per-read `baseline`; missing baselines, zero percentage denominators and unavailable reads stay unknown. A preview is an observation, not an automatic evaluator verdict or proof that a job is complete. Raw EVM calls are also available as `universal.read(target, { chain, callData })` and return consensus bytes. +`PREVIEW_INCOMPLETE` retains all known request IDs and transaction hashes. Track uncertain submissions before retrying. Pass `resume: requestIds` (one per read, in order) to finish without new requests or payment. Resume checks each on-chain destination, call, pin and confirmation requirement before evaluating; unrelated reads are refused. `fees.newlyPaid` is zero on recovery, while `fees.paid` retains the original request deposits. A zero `maxTotalFee` is valid for recovery. + ## Explicit placeholders - `job.verify`, baseline/prefund/retry integration: no compatible automatic evaluator is configured. A different linked evaluator source has a different wire and enum values. @@ -175,6 +199,8 @@ node node_modules/jest/bin/jest.js --config packages/core/jest.marketplace-local node node_modules/ts-node/dist/bin.js --compiler-options '{"module":"commonjs"}' packages/core/__e2e__/ci/run.ts --group marketplace # Explicit funded smoke, using packages/core/.env: fresh provider/card/owner/wallet, then cancel/revoke/deactivate. node node_modules/ts-node/dist/bin.js --compiler-options '{"module":"commonjs"}' packages/core/__e2e__/ci/run.ts --group marketplace-live +# Owned-token acceptance: actual deposits, native/AGW escrow and payouts, BSC-origin principal bridging. +node node_modules/ts-node/dist/bin.js --compiler-options '{"module":"commonjs"}' packages/core/__e2e__/ci/run.ts --group marketplace-funding ``` -Marketplace groups stay out of the runner's default `all`. Live smoke spends bounded PC for gas/test wallets and read callbacks, and does not move principal or escrow tokens. Nonzero deposits, escrow, allowance, payout, manual completion and pause/refund are tested separately on the local fork. The fork's UEA signature test uses a native submitter because Anvil has no Cosmos transport; the opt-in live case exercises actual external-owner transport. No destination protocol execution or automated verdict is implied by those results. +Marketplace groups stay out of the runner's default `all`. The basic live group spends bounded PC for gas/test wallets and read callbacks. The separate funding group uses owned test assets: 0.01 pUSDC per paid job, 0.01 USDT of bridged principal and up to 0.01 pBNB for source-gas setup. It cancels/revokes market jobs, completes plain jobs with a fresh controlled manual evaluator, returns principal/reserve/payout tokens and deactivates its card. The deployed marketplace evaluator remains unchanged. Pause/refund and signature variants use the local fork. The fork's UEA signature test uses a native submitter because Anvil has no Cosmos transport; live cases exercise actual external-owner transport. No automated verdict is implied by those results. Signature fixtures compile from repo-owned source at harness startup; Foundry and cached solc 0.8.26 are prerequisites. diff --git a/packages/core/__e2e__/ci/ci-reporter.js b/packages/core/__e2e__/ci/ci-reporter.js index 3dcd4db6..9f23ded8 100644 --- a/packages/core/__e2e__/ci/ci-reporter.js +++ b/packages/core/__e2e__/ci/ci-reporter.js @@ -43,7 +43,10 @@ class CiReporter { numPassedTests: results.numPassedTests, numFailedTests: results.numFailedTests, numPendingTests: results.numPendingTests, - success: Boolean(results.success), + // Jest fills `success` after onRunComplete. Derive completion from final counters here. + success: results.numPassedTests > 0 && results.numFailedTests === 0 && + (results.numFailedTestSuites ?? 0) === 0 && (results.numRuntimeErrorTestSuites ?? 0) === 0 && !results.wasInterrupted, + jestReportedSuccess: Boolean(results.success), tests, }; diff --git a/packages/core/__e2e__/ci/suite.ts b/packages/core/__e2e__/ci/suite.ts index 5cd93e91..47272796 100644 --- a/packages/core/__e2e__/ci/suite.ts +++ b/packages/core/__e2e__/ci/suite.ts @@ -41,6 +41,7 @@ export const GROUPS = [ 'agw-presets-expanded', 'marketplace', 'marketplace-live', + 'marketplace-funding', ] as const; export type Group = (typeof GROUPS)[number]; @@ -171,6 +172,9 @@ const F = { } as const; export const SCENARIOS: Scenario[] = [ + { id: 'marketplace-funding-agw', group: 'marketplace-funding', file: '__e2e__/marketplace/funding.spec.ts', grep: 'marketplace funding 1\\. deposits real principal', needs: { masterPC: '1' }, env: { MARKETPLACE_FUNDING_E2E: '1', AGW_E2E_AGENT_PC: '0.1' }, note: 'Owned test tokens only; 0.01 pUSDC escrow, controlled fresh evaluator, token cleanup.' }, + { id: 'marketplace-funding-native', group: 'marketplace-funding', file: '__e2e__/marketplace/funding.spec.ts', grep: 'marketplace funding 2\\. funds a native plain job', needs: { masterPC: '1' }, env: { MARKETPLACE_FUNDING_E2E: '1', AGW_E2E_AGENT_PC: '0.1' }, note: '0.01 pUSDC escrow using native atomic approval/funding and a controlled manual evaluator.' }, + { id: 'marketplace-funding-origin', group: 'marketplace-funding', file: '__e2e__/marketplace/funding.spec.ts', grep: 'marketplace funding 3\\. bridges principal', needs: { masterPC: '1' }, env: { MARKETPLACE_FUNDING_E2E: '1', AGW_E2E_AGENT_PC: '0.1' }, note: 'Fresh BSC owner, 0.01 USDT principal, up to 0.01 pBNB for source-gas setup; explicit token cleanup.' }, { id: 'marketplace-native-lifecycle', group: 'marketplace-live', file: '__e2e__/marketplace/lifecycle.spec.ts', grep: 'marketplace live 1\\. native provider registration', needs: { masterPC: '0.5' }, env: { MARKETPLACE_LIVE_E2E: '1', AGW_E2E_AGENT_PC: '0.1' }, note: 'Fresh provider/card/wallet only; no principal export or fee escrow. Cancels and revokes its own permission.' }, { id: 'marketplace-paid-preview', group: 'marketplace-live', file: '__e2e__/marketplace/lifecycle.spec.ts', grep: 'marketplace live 2\\. paid JobSpec preview', needs: { masterPC: '0.5' }, env: { MARKETPLACE_LIVE_E2E: '1', AGW_E2E_AGENT_PC: '0.1' }, note: 'One live validator read through the registry, with an explicit 0.01 PC callback/protocol fee cap.' }, { id: 'marketplace-external-owner', group: 'marketplace-live', file: '__e2e__/marketplace/lifecycle.spec.ts', grep: 'marketplace live 3\\. external EVM owner', needs: { masterPC: '0.5' }, env: { MARKETPLACE_LIVE_E2E: '1', AGW_E2E_AGENT_PC: '0.1' }, note: 'Fresh Sepolia-origin UEA funded with 0.1 PC; open/cancel using the real UEA transport; reuses this run’s card.' }, diff --git a/packages/core/__e2e__/marketplace/funding.spec.ts b/packages/core/__e2e__/marketplace/funding.spec.ts new file mode 100644 index 00000000..4d92181d --- /dev/null +++ b/packages/core/__e2e__/marketplace/funding.spec.ts @@ -0,0 +1,419 @@ +/** Opt-in acceptance with bounded tokens owned by the configured test master. No public impersonation. */ +import { + createPublicClient, + createWalletClient, + encodeFunctionData, + erc20Abi, + http, + parseAbi, + parseEther, + zeroAddress, + zeroHash, + type Address, + type Hex, +} from 'viem'; +import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts'; +import { PushChain } from '../../src'; +import { CHAIN } from '../../src/lib/constants/enums'; +import { CHAIN_INFO } from '../../src/lib/constants/chain'; +import { JOB_KERNEL_ABI } from '../../src/lib/market/contracts/AgenticCommerce'; +import { DONUT_MARKETPLACE as D } from '../../src/lib/market/deployment'; +import { setupAgw, evmClient, type AgwFixture } from '../agw/_fixture'; +const d = + process.env['MARKETPLACE_FUNDING_E2E'] === '1' ? describe : describe.skip; +const principalToken = '0x731aF1Da5365259d27528557EE4aFBA4baC90ef2' as Address; +const budget = BigInt(10000); // 0.01 pUSDC per paid job, returned to the master after payout. +d('marketplace funding', () => { + let f: AgwFixture; + let owner: PushChain; + let provider: PushChain; + let evaluator: PushChain; + let ownerKey: Hex; + let cardId: bigint; + const wallets: { key: Hex; origin: CHAIN; wallet: Address }[] = []; + const jobs: { jobId: bigint; market: boolean; client: PushChain }[] = []; + const sendToken = async ( + client: PushChain, + token: Address, + to: Address, + amount: bigint + ) => { + const tx = await client.universal.sendTransaction({ + to: token, + data: encodeFunctionData({ + abi: erc20Abi, + functionName: 'transfer', + args: [to, amount], + }), + }); + await tx.wait(); + return tx; + }; + const balance = (token: Address, account: Address) => + f.push.readContract({ + address: token, + abi: erc20Abi, + functionName: 'balanceOf', + args: [account], + }); + const complete = async (jobId: bigint) => { + const tx = await evaluator.universal.sendTransaction({ + to: D.kernel, + data: encodeFunctionData({ + abi: JOB_KERNEL_ABI, + functionName: 'complete', + args: [jobId, zeroHash, '0x'], + }), + }); + await tx.wait(); + return tx; + }; + beforeAll(async () => { + f = await setupAgw(); + if ( + (await balance(principalToken, f.ownerAddress)) < BigInt(1) || + (await balance(D.paymentToken, f.ownerAddress)) < budget * BigInt(3) + ) + throw new Error( + 'Configured Push master needs 1 pUSDT.bnb unit and 0.03 pUSDC for this bounded acceptance' + ); + ownerKey = generatePrivateKey(); + owner = await evmClient( + ownerKey, + CHAIN.PUSH_TESTNET_DONUT, + f.manifest.network + ); + provider = await evmClient( + f.agentKey, + CHAIN.PUSH_TESTNET_DONUT, + f.manifest.network + ); + evaluator = await evmClient( + generatePrivateKey(), + CHAIN.PUSH_TESTNET_DONUT, + f.manifest.network + ); + await f.fundPC(owner.universal.account as Address, parseEther('0.3')); + await f.fundPC(evaluator.universal.account as Address, parseEther('0.1')); + const token = PushChain.CONSTANTS.MOVEABLE.TOKEN.BNB_TESTNET.USDT + .address as Address; + const template = PushChain.utils.job.buildJobSpecTemplate({ + reads: [ + PushChain.utils.job.prepareRead({ + chain: CHAIN.BNB_TESTNET, + target: token, + abi: erc20Abi, + functionName: 'balanceOf', + args: ['agentic:wallet'], + }), + ], + checks: [ + { + read: 0, + evaluation: 'COMPARE', + operation: 'GREATER_OR_EQUAL', + target: BigInt(0), + }, + ], + logic: 'ALL', + }); + const registered = await provider.market.agent.register( + { + jobType: 'SDK_FUNDING_ACCEPTANCE', + metadataURI: 'https://example.invalid/sdk-funding-acceptance', + metadataHash: ('0x' + '56'.repeat(32)) as Hex, + chain: CHAIN.BNB_TESTNET, + providerFee: budget, + paymentToken: D.paymentToken, + principalMin: BigInt(1), + principalMax: BigInt(10000), + minDuration: 3600, + maxDuration: 86400, + minExecuteWindow: 0, + settleWindow: 60, + }, + { + rules: { + assets: [ + { + token: { prc20: principalToken }, + maxPerCall: 'agentic:principal', + maxTotal: 'agentic:principal', + }, + ], + principalAsset: 0, + maxGasPerCall: BigInt(0), + allowedCalls: [ + { + target: token, + selector: 'balanceOf(address)', + pins: [{ arg: 0, expected: 'agentic:wallet' }], + }, + ], + }, + jobSpecTemplate: template, + } + ); + cardId = registered.cardId; + f.evidence('marketplace-funding-register', { + cardId, + txHash: registered.tx.hash, + }); + }, 300000); + afterAll(async () => { + try { + for (const j of jobs) { + let status = (await j.client.job.status(j.jobId)).status; + if (status === 'Open') + await (await j.client.job.cancel(j.jobId)).wait(); + if (!j.market && status === 'Funded') { + await ( + await provider.job.submit(j.jobId, { + deliverable: 'SDK acceptance cleanup', + }) + ).wait(); + status = 'Submitted'; + } + if (!j.market && status === 'Submitted') await complete(j.jobId); + } + for (const w of wallets) { + const client = await evmClient( + w.key, + w.origin, + f.manifest.network, + w.wallet + ); + for (const token of [principalToken, D.paymentToken]) { + const held = await balance(token, w.wallet); + if (held) await sendToken(client, token, f.ownerAddress, held); + } + } + for (const client of [provider, evaluator, owner]) { + if (!client) continue; + const held = await balance( + D.paymentToken, + client.universal.account as Address + ); + if (held) await sendToken(client, D.paymentToken, f.ownerAddress, held); + } + if (cardId && (await provider.market.card(cardId)).active) + await (await provider.market.agent.setActive(cardId, false)).wait(); + f?.evidence('marketplace-funding-cleanup', { + cardId, + jobs: await Promise.all( + jobs.map(async (j) => ({ + jobId: j.jobId, + status: (await j.client.job.status(j.jobId)).status, + })) + ), + }); + } finally { + f?.teardown(); + } + }, 300000); + it('1. deposits real principal and fee, cancels the market job, then pays an AGW plain job through a controlled manual evaluator', async () => { + await sendToken( + f.owner, + principalToken, + owner.universal.account as Address, + BigInt(1) + ); + await sendToken( + f.owner, + D.paymentToken, + owner.universal.account as Address, + budget + ); + const now = Number((await f.push.getBlock()).timestamp); + const plan = await owner.market.preview(cardId, { + principal: BigInt(1), + executeBy: now + 600, + expiredAt: now + 7200, + }); + const opened = await owner.market.openJob(plan); + jobs.push({ jobId: opened.jobId, market: true, client: owner }); + wallets.push({ + key: ownerKey, + origin: CHAIN.PUSH_TESTNET_DONUT, + wallet: opened.wallet, + }); + const deposited = await owner.market.deposit(opened.jobId, { + pcAmount: parseEther('0.001'), + }); + expect(await balance(principalToken, opened.wallet)).toBe(BigInt(1)); + expect(await balance(D.paymentToken, opened.wallet)).toBe(budget); + const recovered = await owner.market.openJob(plan, { resume: opened.tx }); + expect(recovered.jobId).toBe(opened.jobId); + await (await owner.job.cancel(opened.jobId)).wait(); + const client = await evmClient( + ownerKey, + CHAIN.PUSH_TESTNET_DONUT, + f.manifest.network, + opened.wallet + ); + const plain = await client.job.create({ + provider: provider.universal.account as Address, + evaluator: evaluator.universal.account as Address, + hook: zeroAddress, + expiredAt: now + 7200, + paymentToken: D.paymentToken, + description: 'SDK live escrow and manual evaluator acceptance', + }); + jobs.push({ jobId: plain.jobId, market: false, client }); + await (await provider.job.setBudget(plain.jobId, budget)).wait(); + const before = await balance( + D.paymentToken, + provider.universal.account as Address + ); + const funded = await client.job.fund(plain.jobId, { + expectedBudget: budget, + }); + await funded.wait(); + expect((await client.job.status(plain.jobId)).status).toBe('Funded'); + expect(await balance(D.paymentToken, opened.wallet)).toBe(BigInt(0)); + await ( + await provider.job.submit(plain.jobId, { + deliverable: 'SDK live manual evaluator proof', + }) + ).wait(); + const completed = await complete(plain.jobId); + expect((await client.job.status(plain.jobId)).status).toBe('Completed'); + expect( + await balance(D.paymentToken, provider.universal.account as Address) + ).toBeGreaterThan(before); + f.evidence('marketplace-funding-agw-paid', { + cardId, + marketJobId: opened.jobId, + plainJobId: plain.jobId, + wallet: opened.wallet, + depositHashes: deposited.txs.map((t) => t.tx.hash), + fundingHash: funded.hash, + completionHash: completed.hash, + budget, + }); + }, 600000); + it('2. funds a native plain job with an atomic token approval and pays out on live Donut', async () => { + await sendToken( + f.owner, + D.paymentToken, + owner.universal.account as Address, + budget + ); + const now = Number((await f.push.getBlock()).timestamp); + const created = await owner.job.create({ + provider: provider.universal.account as Address, + evaluator: evaluator.universal.account as Address, + hook: zeroAddress, + expiredAt: now + 7200, + paymentToken: D.paymentToken, + description: 'SDK live native escrow acceptance', + }); + jobs.push({ jobId: created.jobId, market: false, client: owner }); + await (await provider.job.setBudget(created.jobId, budget)).wait(); + const funded = await owner.job.fund(created.jobId, { + expectedBudget: budget, + }); + await funded.wait(); + expect(funded.atomic).toBe(true); + expect((await owner.job.status(created.jobId)).status).toBe('Funded'); + await ( + await provider.job.submit(created.jobId, { + deliverable: 'SDK native acceptance', + }) + ).wait(); + const completed = await complete(created.jobId); + expect((await owner.job.status(created.jobId)).status).toBe('Completed'); + f.evidence('marketplace-funding-native-paid', { + jobId: created.jobId, + fundingHash: funded.hash, + completionHash: completed.hash, + budget, + }); + }, 600000); + it('3. bridges principal from a fresh BSC origin into the opened wallet and recovers its funds after cancellation', async () => { + const sourceKey = process.env['EVM_PRIVATE_KEY'] as Hex; + if (!sourceKey) + throw new Error('EVM_PRIVATE_KEY is required for owned BSC test funding'); + const info = CHAIN_INFO[CHAIN.BNB_TESTNET]; + const bsc = createPublicClient({ transport: http(info.defaultRPC[0]) }); + const master = createWalletClient({ + account: privateKeyToAccount(sourceKey), + transport: http(info.defaultRPC[0]), + }); + if ( + (await bsc.getBalance({ address: master.account.address })) < + parseEther('0.01') + ) { + const gas = await f.owner.universal.sendTransaction({ + to: { address: master.account.address, chain: CHAIN.BNB_TESTNET }, + value: parseEther('0.01'), + }); + await gas.wait(); + f.evidence('marketplace-funding-bsc-gas', { + txHash: gas.hash, + amount: parseEther('0.01'), + }); + } + const key = generatePrivateKey(); + const address = privateKeyToAccount(key).address; + const gasHash = await master.sendTransaction({ + to: address, + value: parseEther('0.005'), + chain: null, + }); + await bsc.waitForTransactionReceipt({ hash: gasHash }); + const tokenHash = await master.writeContract({ + address: PushChain.CONSTANTS.MOVEABLE.TOKEN.BNB_TESTNET.USDT + .address as Address, + abi: erc20Abi, + functionName: 'transfer', + args: [address, BigInt(10000)], + chain: null, + }); + await bsc.waitForTransactionReceipt({ hash: tokenHash }); + const external = await evmClient( + key, + CHAIN.BNB_TESTNET, + f.manifest.network + ); + const uea = external.universal.account as Address; + const deploy = await f.owner.universal.sendTransaction({ + to: '0x00000000000000000000000000000000000000eA', + data: encodeFunctionData({ + abi: parseAbi([ + 'function deployUEA((string chainNamespace,string chainId,bytes owner) id) returns (address)', + ]), + functionName: 'deployUEA', + args: [{ chainNamespace: 'eip155', chainId: '97', owner: address }], + }), + }); + await deploy.wait(); + await f.fundPC(uea, parseEther('0.2')); + const now = Number((await f.push.getBlock()).timestamp); + const plan = await external.market.preview(cardId, { + principal: BigInt(10000), + executeBy: now + 600, + expiredAt: now + 7200, + }); + const opened = await external.market.openJob(plan); + jobs.push({ jobId: opened.jobId, market: true, client: external }); + wallets.push({ key, origin: CHAIN.BNB_TESTNET, wallet: opened.wallet }); + await sendToken(f.owner, D.paymentToken, opened.wallet, budget); + const deposited = await external.market.deposit(opened.jobId, { + funding: 'origin', + pcAmount: BigInt(0), + }); + expect(await balance(principalToken, opened.wallet)).toBe(BigInt(10000)); + expect(deposited.txs.map((t) => t.step)).toEqual(['PRINCIPAL']); + await (await external.job.cancel(opened.jobId)).wait(); + f.evidence('marketplace-funding-origin', { + cardId, + jobId: opened.jobId, + wallet: opened.wallet, + uea, + depositHashes: deposited.txs.map((t) => t.tx.hash), + principal: BigInt(10000), + origin: CHAIN.BNB_TESTNET, + }); + }, 900000); +}); diff --git a/packages/core/__e2e__/marketplace/lifecycle.spec.ts b/packages/core/__e2e__/marketplace/lifecycle.spec.ts index 388968fb..e2144172 100644 --- a/packages/core/__e2e__/marketplace/lifecycle.spec.ts +++ b/packages/core/__e2e__/marketplace/lifecycle.spec.ts @@ -182,6 +182,37 @@ d('marketplace live', () => { }); expect(result.pass).toBe(true); expect(result.reads[0].decoded).not.toBeNull(); + const resumed = await PushChain.utils.job.previewJobSpec(spec, { + client: owner, + resume: result.reads.map((r) => r.response.requestId), + maxTotalFee: BigInt(0), + advanced: { timeout: 120000 }, + }); + expect(resumed.pass).toBe(true); + expect(resumed.fees.newlyPaid).toBe(BigInt(0)); + const authored = PushChain.utils.job.prepareRead({ + chain: CHAIN.BNB_TESTNET, + target: spec.reads[0].target, + abi: parseAbi(['function balanceOf(address) view returns (uint256)']), + functionName: 'balanceOf', + args: [owner.universal.account], + }); + const direct = await owner.universal.read(authored, { + maxFee: parseEther('0.01'), + advanced: { timeout: 120000 }, + }); + const sameCall = await PushChain.utils.job.previewJobSpec(spec, { + client: owner, + resume: [direct.requestId], + maxTotalFee: BigInt(0), + }); + expect(sameCall.pass).toBe(true); + expect(sameCall.fees.newlyPaid).toBe(BigInt(0)); + f.evidence('marketplace-preview-recovery', { + originalRequestId: result.reads[0].response.requestId, + preparedReadRequestId: direct.requestId, + additionalPaymentOnResume: resumed.fees.newlyPaid, + }); }); it('3. external EVM owner opens and cancels through its real Push UEA transport', async () => { if (!cardId) throw new Error('The fresh test card was not registered'); @@ -217,14 +248,21 @@ d('marketplace live', () => { executeBy: now + 600, expiredAt: now + 7200, }); - externalOpened = await externalOwner.market.openJob(plan); + const openedResult = await externalOwner.market.openJob(plan); + externalOpened = openedResult; + const recovered = await externalOwner.market.openJob(plan, { + resume: openedResult.tx, + }); + expect(recovered.jobId).toBe(externalOpened.jobId); f.evidence('marketplace-external-open', { jobId: externalOpened.jobId, wallet: externalOpened.wallet, uea, signerChainId: plan.intent.signerChainId, + txHash: openedResult.tx.hash, }); - await (await externalOwner.job.cancel(externalOpened.jobId)).wait(); + const cancelled = await externalOwner.job.cancel(externalOpened.jobId); + await cancelled.wait(); expect((await externalOwner.job.status(externalOpened.jobId)).status).toBe( 'Rejected' ); @@ -232,6 +270,7 @@ d('marketplace live', () => { f.evidence('marketplace-external-cleanup', { jobId: externalOpened.jobId, cardId, + txHash: cancelled.hash, }); }); }); diff --git a/packages/core/__market-local__/marketplace.spec.ts b/packages/core/__market-local__/marketplace.spec.ts index c4f495c8..faf01a67 100644 --- a/packages/core/__market-local__/marketplace.spec.ts +++ b/packages/core/__market-local__/marketplace.spec.ts @@ -1,6 +1,9 @@ /** Public SDK → real deployed v2/AGW v6 on an isolated Anvil Donut fork. No keys or writes to public RPC. */ -import { spawn, type ChildProcess } from 'node:child_process'; +import { execFileSync, spawn, type ChildProcess } from 'node:child_process'; import { createServer } from 'node:net'; +import { readFileSync } from 'node:fs'; +import { join } from 'node:path'; +import { tmpdir } from 'node:os'; import { createPublicClient, createWalletClient, @@ -8,6 +11,9 @@ import { encodeFunctionData, erc20Abi, getAddress, + bytesToHex, + hexToBytes, + parseTransaction, keccak256, http, parseAbi, @@ -16,9 +22,10 @@ import { zeroHash, type Address, type PublicClient, + type Hex, } from 'viem'; import { mnemonicToAccount } from 'viem/accounts'; -import { PushChain } from '../src'; +import { PushChain, type UniversalSigner } from '../src'; import { CHAIN, PUSH_NETWORK, LIBRARY } from '../src/lib/constants/enums'; import { DONUT_MARKETPLACE as D } from '../src/lib/market/deployment'; import { JOB_KERNEL_ABI } from '../src/lib/market/contracts/AgenticCommerce'; @@ -39,7 +46,7 @@ let opened: { jobId: bigint; wallet: Address; rulesId: `0x${string}` }; let template: JobSpecTemplate; let rules: AgentCardRules; let stopWatch: (() => void) | undefined; -const accounts = [0, 1].map((addressIndex) => +const accounts = [0, 1, 2].map((addressIndex) => mnemonicToAccount( 'test test test test test test test test test test test junk', { addressIndex } @@ -48,6 +55,11 @@ const accounts = [0, 1].map((addressIndex) => const token = '0x731aF1Da5365259d27528557EE4aFBA4baC90ef2'; const tokenOnSepolia = '0xE935d9c9C24D02E61186c640cc01d713C876d40F'; beforeAll(async () => { + execFileSync( + 'bash', + [join(__dirname, '../scripts/marketplace-local/prepare.sh')], + { stdio: 'pipe' } + ); const port = await new Promise((resolve) => { const server = createServer(); server.listen(0, '127.0.0.1', () => { @@ -74,6 +86,8 @@ beforeAll(async () => { '--retries', '2', '--silent', + '--order', + 'fifo', ], { stdio: ['ignore', 'ignore', 'pipe'] } ); @@ -531,3 +545,302 @@ it('accepts a real deployed EVM UEA owner signature with its home-chain domain', ).toBe(uea); expect((await owner.job.status(result.jobId)).status).toBe('Open'); }); + +function ownerArtifact(name: string) { + const base = + process.env['MARKETPLACE_LOCAL_DIR'] ?? + join(tmpdir(), 'push-marketplace-local'); + return JSON.parse( + readFileSync( + join(base, 'out', 'MarketplaceOwnerFixtures.sol', `${name}.json`), + 'utf8' + ) + ); +} +it('uses a real ERC-1271 owner adapter, rejects malformed success values, and recovers without a second signature', async () => { + const artifact = ownerArtifact('Marketplace1271Owner'); + const controller = createWalletClient({ + account: accounts[0], + chain: push.chain, + transport: http(rpc), + }); + const hash = await controller.deployContract({ + chain: push.chain, + abi: artifact.abi, + bytecode: artifact.bytecode.object, + args: [accounts[0].address], + }); + const contract = (await push.waitForTransactionReceipt({ hash })) + .contractAddress as Address; + await ( + await owner.universal.sendTransaction({ + to: contract, + value: BigInt(10) ** BigInt(18), + }) + ).wait(); + const signTypedData = jest.fn( + async (data: Parameters<(typeof accounts)[0]['signTypedData']>[0]) => + hexToBytes(await accounts[0].signTypedData(data)) + ); + const send = jest.fn(async (unsigned: Uint8Array) => { + const tx = parseTransaction(bytesToHex(unsigned)); + if (!tx.to) + throw new Error( + 'The contract-owner adapter requires a transaction target' + ); + const txHash = await controller.writeContract({ + address: contract, + chain: push.chain, + abi: artifact.abi, + functionName: 'execute', + args: [tx.to, tx.value ?? BigInt(0), tx.data ?? '0x'], + gas: BigInt(3000000), + }); + await push.request({ method: 'anvil_mine' as never, params: ['0x4'] as never }); + return hexToBytes(txHash); + }); + const signer: UniversalSigner = { + account: { chain: CHAIN.PUSH_TESTNET_DONUT, address: contract }, + signMessage: async (data) => + hexToBytes(await accounts[0].signMessage({ message: { raw: data } })), + signTypedData, + signAndSendTransaction: send, + }; + const client = await PushChain.initialize(signer, { + network: PUSH_NETWORK.TESTNET_DONUT, + rpcUrls: { [CHAIN.PUSH_TESTNET_DONUT]: [rpc] }, + }); + const now = Number((await push.getBlock()).timestamp); + const plan = await client.market.preview(cardId, { + principal: BigInt(10), + executeBy: now + 600, + expiredAt: now + 7200, + }); + for (const mode of [1, 2, 3]) { + const tx = await controller.writeContract({ + address: contract, + chain: push.chain, + abi: artifact.abi, + functionName: 'setResponseMode', + args: [mode], + }); + await push.waitForTransactionReceipt({ hash: tx }); + await expect(client.market.openJob(plan)).rejects.toMatchObject({ + code: 'OPEN_JOB_SIMULATION_FAILED', + }); + } + expect(send).not.toHaveBeenCalled(); + const reset = await controller.writeContract({ + address: contract, + chain: push.chain, + abi: artifact.abi, + functionName: 'setResponseMode', + args: [0], + }); + await push.waitForTransactionReceipt({ hash: reset }); + const opened = await client.market.openJob(plan); + const signatures = signTypedData.mock.calls.length; + const recovered = await client.market.openJob(plan, { resume: opened.tx }); + expect(recovered.jobId).toBe(opened.jobId); + expect(signTypedData.mock.calls).toHaveLength(signatures); + expect(send).toHaveBeenCalledTimes(1); + await (await client.job.cancel(opened.jobId)).wait(); + expect((await client.job.status(opened.jobId)).status).toBe('Rejected'); +}); +it('accepts a compatible EIP-7702 verifier and refuses an echo fallback before broadcast', async () => { + const controller = createWalletClient({ + account: accounts[2], + chain: push.chain, + transport: http(rpc), + }); + const artifact = ownerArtifact('Marketplace1271Owner'); + const deployed = await controller.deployContract({ + chain: push.chain, + abi: artifact.abi, + bytecode: artifact.bytecode.object, + args: [accounts[2].address], + }); + const delegate = (await push.waitForTransactionReceipt({ hash: deployed })) + .contractAddress as Address; + await push.request({ + method: 'anvil_setCode' as never, + params: [ + accounts[2].address, + ('0xef0100' + delegate.slice(2)) as Hex, + ] as never, + }); + const signer = await PushChain.utils.signer.toUniversalFromKeypair( + controller, + { chain: CHAIN.PUSH_TESTNET_DONUT, library: LIBRARY.ETHEREUM_VIEM } + ); + const client = await PushChain.initialize(signer, { + network: PUSH_NETWORK.TESTNET_DONUT, + rpcUrls: { [CHAIN.PUSH_TESTNET_DONUT]: [rpc] }, + }); + const now = Number((await push.getBlock()).timestamp); + const plan = await client.market.preview(cardId, { + principal: BigInt(10), + executeBy: now + 600, + expiredAt: now + 7200, + }); + const result = await client.market.openJob(plan); + await (await client.job.cancel(result.jobId)).wait(); + const echoArtifact = ownerArtifact('MarketplaceEchoOwner'); + const echoHash = await controller.deployContract({ + chain: push.chain, + abi: echoArtifact.abi, + bytecode: echoArtifact.bytecode.object, + args: [], + }); + const echo = (await push.waitForTransactionReceipt({ hash: echoHash })) + .contractAddress as Address; + await push.request({ + method: 'anvil_setCode' as never, + params: [accounts[2].address, ('0xef0100' + echo.slice(2)) as Hex] as never, + }); + const next = await client.market.preview(cardId, { + principal: BigInt(10), + executeBy: now + 600, + expiredAt: now + 7200, + }); + await expect(client.market.openJob(next)).rejects.toMatchObject({ + code: 'OPEN_JOB_SIMULATION_FAILED', + }); +}); +it('recovers the original card and opening when a provider updates in the same mined block', async () => { + const before = await provider.market.card(cardId); + const now = Number((await push.getBlock()).timestamp); + const plan = await owner.market.preview(cardId, { + principal: BigInt(10), + executeBy: now + 600, + expiredAt: now + 7200, + }); + let signature: Hex | undefined; + const sign = owner.universal.signTypedData.bind(owner.universal); + const capture = jest + .spyOn(owner.universal, 'signTypedData') + .mockImplementationOnce(async (data) => { + signature = (await sign(data)) as Hex; + throw new Error('Captured locally before broadcast'); + }); + await expect(owner.market.openJob(plan)).rejects.toThrow( + 'Captured locally before broadcast' + ); + capture.mockRestore(); + if (!signature) throw new Error('No owner signature captured'); + const openData = encodeFunctionData({ + abi: (await import('../src/lib/market/contracts/UniversalMarketplace')) + .MARKETPLACE_ABI, + functionName: 'openJob', + args: [ + { + cardId, + cardVersion: before.version, + job: plan.job, + session: plan.session, + intent: plan.intent, + sig: signature, + label: plan.label, + }, + ], + }); + const { chain, ...fields } = before; + const updateData = encodeFunctionData({ + abi: (await import('../src/lib/market/contracts/UniversalMarketplace')) + .MARKETPLACE_ABI, + functionName: 'updateAgentCard', + args: [ + cardId, + { + ...fields, + jobType: fields.jobType as Hex, + chainNamespace: chain, + providerFee: BigInt(7000000), + }, + PushChain.utils.market.encodeAgentCardRules( + { ...before.rules, maxGasPerCall: BigInt(17) }, + { chain } + ), + before.jobSpecTemplateBytes, + ], + }); + let openingHash: Hex; + let updateHash: Hex; + await push.request({ + method: 'evm_setAutomine' as never, + params: [false] as never, + }); + try { + openingHash = (await push.request({ + method: 'eth_sendTransaction' as never, + params: [ + { + from: accounts[0].address, + to: D.marketplace, + data: openData, + gas: '0x5b8d80', + }, + ] as never, + })) as Hex; + updateHash = (await push.request({ + method: 'eth_sendTransaction' as never, + params: [ + { + from: accounts[1].address, + to: D.marketplace, + data: updateData, + gas: '0x5b8d80', + }, + ] as never, + })) as Hex; + await push.request({ method: 'evm_mine' as never, params: [] as never }); + } finally { + await push.request({ + method: 'evm_setAutomine' as never, + params: [true] as never, + }); + } + const [openedReceipt, updatedReceipt] = await Promise.all([ + push.waitForTransactionReceipt({ hash: openingHash }), + push.waitForTransactionReceipt({ hash: updateHash }), + ]); + expect(openedReceipt.status).toBe('success'); + expect(updatedReceipt.status).toBe('success'); + expect(openedReceipt.blockNumber).toBe(updatedReceipt.blockNumber); + expect((await provider.market.card(cardId)).version).toBe( + before.version + BigInt(1) + ); + const recovered = await owner.market.openJob(plan, { + resume: await owner.universal.trackTransaction(openingHash), + }); + const source = '0x0A16CBa65FfCAa4C2282b27b027Ab4A2fE46E0Bf'; + await push.request({ + method: 'anvil_impersonateAccount' as never, + params: [source] as never, + }); + const funder = createWalletClient({ + account: source, + chain: push.chain, + transport: http(rpc), + }); + for (const [asset, amount] of [ + [token, BigInt(10)], + [D.paymentToken, before.providerFee], + ] as const) { + const hash = await funder.writeContract({ + address: asset, + chain: push.chain, + abi: erc20Abi, + functionName: 'transfer', + args: [accounts[0].address, amount], + }); + await push.waitForTransactionReceipt({ hash }); + } + const deposited = await owner.market.deposit(recovered.jobId); + expect(deposited.cardVersion).toBe(before.version); + expect(deposited.txs.map((t) => [t.step, t.amount])).toEqual([ + ['PRINCIPAL', BigInt(10)], + ['PROVIDER_FEE', before.providerFee], + ]); + await (await owner.job.cancel(recovered.jobId)).wait(); +}); diff --git a/packages/core/scripts/agw-local/contracts/MarketplaceOwnerFixtures.sol b/packages/core/scripts/agw-local/contracts/MarketplaceOwnerFixtures.sol new file mode 100644 index 00000000..c52cb567 --- /dev/null +++ b/packages/core/scripts/agw-local/contracts/MarketplaceOwnerFixtures.sol @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +/// SDK acceptance only: a real ERC-1271 owner and an EIP-7702-compatible verifier. +contract Marketplace1271Owner { + address public immutable controller; + uint8 public responseMode; + + constructor(address controller_) { controller = controller_; } + receive() external payable {} + + function setResponseMode(uint8 mode) external { + require(msg.sender == controller, "controller"); + responseMode = mode; + } + + function isValidSignature(bytes32 digest, bytes calldata signature) external view returns (bytes4) { + if (responseMode == 1) return 0xffffffff; + if (responseMode == 2) { + // A magic prefix with nonzero trailing bytes must not count as ERC-1271 success. + assembly { mstore(0, or(shl(224, 0x1626ba7e), 1)) return(0, 32) } + } + if (responseMode == 3) { + assembly { mstore(0, shl(224, 0x1626ba7e)) return(0, 4) } + } + if (signature.length != 65) return 0xffffffff; + bytes32 r; + bytes32 s; + uint8 v; + assembly { r := calldataload(signature.offset) s := calldataload(add(signature.offset, 32)) v := byte(0, calldataload(add(signature.offset, 64))) } + if (uint256(s) > 0x7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0 || (v != 27 && v != 28)) return 0xffffffff; + return ecrecover(digest, v, r, s) == controller ? bytes4(0x1626ba7e) : bytes4(0xffffffff); + } + + function execute(address target, uint256 value, bytes calldata data) external payable returns (bytes memory) { + require(msg.sender == controller, "controller"); + (bool success, bytes memory result) = target.call{value: value}(data); + if (!success) assembly { revert(add(result, 32), mload(result)) } + return result; + } +} + +/// Nonreverting fallback: neither an empty nor an echoed return is a signature verifier. +contract MarketplaceEchoOwner { + fallback() external { assembly { calldatacopy(0, 0, calldatasize()) return(0, calldatasize()) } } +} diff --git a/packages/core/scripts/marketplace-local/prepare.sh b/packages/core/scripts/marketplace-local/prepare.sh new file mode 100644 index 00000000..ae6f6a7b --- /dev/null +++ b/packages/core/scripts/marketplace-local/prepare.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +# Compile repo-owned signature acceptance fixtures. Never broadcasts or clones another repository. +set -euo pipefail +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +MARKET_FIXTURE_DIR="${MARKETPLACE_LOCAL_DIR:-${TMPDIR:-/tmp}/push-marketplace-local}" +mkdir -p "$MARKET_FIXTURE_DIR/src" +cp "$SCRIPT_DIR/../agw-local/contracts/MarketplaceOwnerFixtures.sol" "$MARKET_FIXTURE_DIR/src/" +cat > "$MARKET_FIXTURE_DIR/foundry.toml" <<'EOF' +[profile.default] +src = "src" +out = "out" +solc_version = "0.8.26" +optimizer = true +optimizer_runs = 200 +EOF +forge build --root "$MARKET_FIXTURE_DIR" --offline >/dev/null +echo "$MARKET_FIXTURE_DIR" diff --git a/packages/core/src/lib/agentic/contracts/reader.ts b/packages/core/src/lib/agentic/contracts/reader.ts index 5145ade2..2ea44743 100644 --- a/packages/core/src/lib/agentic/contracts/reader.ts +++ b/packages/core/src/lib/agentic/contracts/reader.ts @@ -14,7 +14,7 @@ export interface ChainReader { blockNumber?: bigint; }): Promise; getBlockNumber(): Promise; - getBlock?(args: { blockNumber: bigint }): Promise<{ timestamp: bigint }>; + getBlock?(args: { blockNumber: bigint }): Promise<{ timestamp: bigint; hash?: Hex | null }>; getCode(args: { address: Address; blockNumber?: bigint }): Promise; getBalance(args: { address: Address; blockNumber?: bigint }): Promise; getLogs(args: { @@ -25,6 +25,7 @@ export interface ChainReader { toBlock: bigint; }): Promise; getTransactionReceipt(args: { hash: Hex }): Promise; + getTransaction?(args: { hash: Hex }): Promise<{ input: Hex; blockNumber: bigint | null }>; /** Raw eth_call, used to verify complete signed marketplace requests before broadcast. */ call?(args: { to: Address; data: Hex; account?: Address; blockNumber?: bigint }): Promise<{ data?: Hex }>; } @@ -42,6 +43,7 @@ export function chainReaderFromPublicClient(client: PublicClient): ChainReader { getLogs: (args) => client.getLogs(args as Parameters[0]) as Promise, getTransactionReceipt: (args) => client.getTransactionReceipt(args), + getTransaction: (args) => client.getTransaction(args), call: (args) => client.call(args), }; } diff --git a/packages/core/src/lib/index.ts b/packages/core/src/lib/index.ts index 5747450f..ebea7e1b 100644 --- a/packages/core/src/lib/index.ts +++ b/packages/core/src/lib/index.ts @@ -10,6 +10,7 @@ export type { MarketNamespace, MarketPreviewOptions, MarketWriteOptions, + MarketOpenOptions, MarketDepositOptions, MarketDepositResult, MarketDepositStep, @@ -21,6 +22,8 @@ export type { Job, JobStatus, JobEvent, + JobWatchCursor, + JobWatchOptions, CreateJobOptions, FundJobOptions, } from './job/types'; @@ -39,6 +42,7 @@ export type { AllowedMutability, PrincipalMarker, PrepareJobReadOptions, + ExecuteJobReadOptions, BuildJobSpecOptions, BuildJobSpecTemplateOptions, JobSpecPreview, diff --git a/packages/core/src/lib/job-spec/__tests__/description.spec.ts b/packages/core/src/lib/job-spec/__tests__/description.spec.ts new file mode 100644 index 00000000..a3dda1f9 --- /dev/null +++ b/packages/core/src/lib/job-spec/__tests__/description.spec.ts @@ -0,0 +1,62 @@ +import { parseAbi } from 'viem'; +import { prepareJobRead, jobReadOptions } from '../read'; +import { buildJobSpec } from '../codec'; +import { describeJobSpec } from '../helpers'; +const token = '0x1111111111111111111111111111111111111111'; +const make = () => + buildJobSpec({ + reads: [ + prepareJobRead({ + chain: 'eip155:97', + target: token, + abi: parseAbi(['function totalSupply() view returns (uint256)']), + functionName: 'totalSupply', + }), + ], + checks: [ + { + read: 0, + evaluation: 'COMPARE', + operation: 'GREATER_OR_EQUAL', + target: BigInt(499950000), + }, + ], + logic: 'ALL', + executeBy: 1800000000, + failFinalAt: 1800000060, + }); +it('retains ABI names and formats decimal targets without hiding their raw units', () => { + expect( + describeJobSpec(make(), { decimals: { [token]: 6 } }).checks[0] + ).toContain('totalSupply'); + expect( + describeJobSpec(make(), { decimals: { [token]: 6 } }).checks[0] + ).toContain('499.95 (499950000 raw units; 6 decimals)'); + expect(() => + describeJobSpec(make(), { decimals: { [token]: -1 } }) + ).toThrow(); +}); +it('labels signed percentage targets in percentage and basis points', () => { + const spec = make(); + spec.checks[0].evaluation = 'PERCENTAGE'; + spec.checks[0].target = BigInt(-250); + expect(describeJobSpec(spec).checks[0]).toContain('-2.5% (-250 bps)'); +}); +it('maps a resolved prepared read to the paid call and refuses unfilled markers before sending', () => { + const read = make().reads[0]; + expect(jobReadOptions(read)).toMatchObject({ + chain: 'eip155:97', + callData: read.selector, + }); + const hole = prepareJobRead({ + chain: 'eip155:97', + target: token, + abi: parseAbi(['function balanceOf(address) view returns (uint256)']), + functionName: 'balanceOf', + args: ['agentic:wallet'], + }); + expect(() => jobReadOptions(hole)).toThrow( + expect.objectContaining({ code: 'UNFILLED_PLACEHOLDER' }) + ); + expect(() => jobReadOptions({ ...read, outputs: '0x080101f' })).toThrow(); +}); diff --git a/packages/core/src/lib/job-spec/__tests__/preview.spec.ts b/packages/core/src/lib/job-spec/__tests__/preview.spec.ts index 761fbf9a..f21653ef 100644 --- a/packages/core/src/lib/job-spec/__tests__/preview.spec.ts +++ b/packages/core/src/lib/job-spec/__tests__/preview.spec.ts @@ -4,6 +4,7 @@ import { parseAbi, parseAbiParameters, stringToHex, + toHex, type Hex, } from 'viem'; import { buildJobSpec, buildJobSpecTemplate } from '../codec'; @@ -15,6 +16,7 @@ import { } from '../preview'; import { READ_OUTCOME } from '../../read-state/read-state.types'; import { PRINCIPAL } from '../constants'; +import { encodeEvmQueryEnvelope } from '../../read-state/envelopes'; import type { PreviewJobSpecOptions, JobSpec } from '../types'; const target = '0x1111111111111111111111111111111111111111'; const word = (n: bigint): Hex => encodeAbiParameters([{ type: 'int256' }], [n]); @@ -45,19 +47,37 @@ function spec( } function fixture(values: (Hex | null)[] = [word(BigInt(5))]) { const prepareRead = jest.fn(async () => ({ value: BigInt(2) })); - const executeReads = jest.fn(async () => ({ - reads: values.map((resultData) => ({ + const responses = values.map((resultData, i) => { + const response = { + requestId: toHex(BigInt(i + 1), { size: 32 }), + txHash: toHex(BigInt(99), { size: 32 }), + request: { + spec: { + account: { chainNamespace: 'eip155', chainId: '97' }, + minConfirmations: 1, + blockNumber: BigInt(1), + query: encodeEvmQueryEnvelope( + { type: 'contractCall', target, callData: read.selector }, + { blockNumber: BigInt(1) } + ).encoded, + }, + }, outcome: resultData === null ? READ_OUTCOME.SOURCE_ERROR : READ_OUTCOME.SUCCESS, raw: resultData === null ? null : { resultData }, fees: { paid: BigInt(2) }, errorMsg: '', - })), - })); + wait: jest.fn(), + }; + response.wait.mockResolvedValue(response); + return response; + }); + const executeReads = jest.fn(async () => ({ reads: responses })); + const trackRead = jest.fn(async () => responses[0]); const options = { - client: { universal: { prepareRead, executeReads } }, + client: { universal: { prepareRead, executeReads, trackRead } }, } as unknown as PreviewJobSpecOptions; - return { options, prepareRead, executeReads }; + return { options, prepareRead, executeReads, responses, trackRead }; } it('prepares raw calls through universal reads, pays the batch and evaluates comparisons', async () => { const f = fixture(); @@ -75,7 +95,7 @@ it('prepares raw calls through universal reads, pays the batch and evaluates com ); expect(f.executeReads).toHaveBeenCalledWith( [{ value: BigInt(2) }], - expect.objectContaining({ waitForCompletion: true }) + expect.objectContaining({ waitForCompletion: false }) ); expect(result).toMatchObject({ pass: true, @@ -90,6 +110,38 @@ it('checks the total fee cap after preparation and before any paid request', asy ).rejects.toMatchObject({ code: 'PREVIEW_FEE_EXCEEDED' }); expect(f.executeReads).not.toHaveBeenCalled(); }); +it('retains all request IDs after a wait timeout and resumes with no additional payment', async () => { + const f = fixture(); + f.responses[0].wait.mockRejectedValueOnce(new Error('Polling timed out')); + await expect(previewJobSpec(spec(), f.options)).rejects.toMatchObject({ + code: 'PREVIEW_INCOMPLETE', + details: { requestIds: [f.responses[0].requestId] }, + }); + const result = await previewJobSpec(spec(), { + ...f.options, + resume: [f.responses[0].requestId], + maxTotalFee: BigInt(0), + }); + expect(result).toMatchObject({ + pass: true, + fees: { paid: BigInt(2), newlyPaid: BigInt(0) }, + }); + expect(f.executeReads).toHaveBeenCalledTimes(1); +}); +it('rejects a recorded request for a different call before evaluating its result', async () => { + const f = fixture(); + const changed = spec(); + changed.reads[0].target = '0x2222222222222222222222222222222222222222'; + await expect( + previewJobSpec(changed, { + ...f.options, + resume: [f.responses[0].requestId], + }) + ).rejects.toMatchObject({ code: 'PREVIEW_REQUEST_MISMATCH' }); + expect(f.prepareRead).not.toHaveBeenCalled(); + expect(f.executeReads).not.toHaveBeenCalled(); + expect(f.responses[0].wait).not.toHaveBeenCalled(); +}); it('does not invent baselines or treat unavailable source reads as failures of the criteria', async () => { const f = fixture(); expect(await previewJobSpec(spec('NUMBER'), f.options)).toMatchObject({ diff --git a/packages/core/src/lib/job-spec/codec.ts b/packages/core/src/lib/job-spec/codec.ts index 95f6d21a..139945af 100644 --- a/packages/core/src/lib/job-spec/codec.ts +++ b/packages/core/src/lib/job-spec/codec.ts @@ -15,7 +15,7 @@ import { PRINCIPAL, } from './constants'; import { JOB_SPEC_PARAM, JOB_TEMPLATE_PARAM } from './schema'; -import { validateJobRead } from './read'; +import { inheritReadLabel, validateJobRead } from './read'; import type { BuildJobSpecOptions, BuildJobSpecTemplateOptions, @@ -192,6 +192,7 @@ function normalizeReads(values: BuildJobSpecOptions['reads']): JobRead[] { minConfirmations: wrapper.minConfirmations ?? 1, ...(source.fills ? { fills: source.fills.map((f) => ({ ...f })) } : {}), }; + inheritReadLabel(source, read); return read; }); } diff --git a/packages/core/src/lib/job-spec/helpers.ts b/packages/core/src/lib/job-spec/helpers.ts index 5ef1259f..31fd3ab5 100644 --- a/packages/core/src/lib/job-spec/helpers.ts +++ b/packages/core/src/lib/job-spec/helpers.ts @@ -1,8 +1,16 @@ -import { getAddress, keccak256, toHex, type Address, type Hex } from 'viem'; +import { + formatUnits, + getAddress, + keccak256, + toHex, + type Address, + type Hex, +} from 'viem'; import { encodeJobSpec, int256 } from './codec'; import { PRINCIPAL } from './constants'; import { JobSpecError } from '../market/errors'; import type { JobSpec, JobSpecTemplate, LogicTree } from './types'; +import { inheritReadLabel, jobReadLabel } from './read'; export function resolveJobSpec( template: JobSpecTemplate, ctx: { @@ -49,7 +57,9 @@ export function resolveJobSpec( } const read = { ...r }; delete read.fills; - return { ...read, args }; + const resolved = { ...read, args }; + inheritReadLabel(r, resolved); + return resolved; }); const checks = template.checks.map((c) => { const t = c.target; @@ -98,6 +108,29 @@ export function describeJobSpec( options?: { principal?: bigint; decimals?: Record } ): { checks: string[]; logic: string; timing: string } { encodeJobSpec(spec); + if (options?.principal !== undefined && int256(options.principal) < BigInt(0)) + throw new JobSpecError( + 'INVALID_DESCRIPTION_OPTIONS', + 'Principal must be nonnegative.' + ); + const decimals = new Map(); + for (const [address, value] of Object.entries(options?.decimals ?? {})) { + if (!Number.isInteger(value) || value < 0 || value > 255) + throw new JobSpecError( + 'INVALID_DESCRIPTION_OPTIONS', + 'Token decimals must be integers from 0 to 255.' + ); + try { + decimals.set(getAddress(address).toLowerCase(), value); + } catch (cause) { + throw new JobSpecError( + 'INVALID_DESCRIPTION_OPTIONS', + 'Decimals must be keyed by token address.', + undefined, + cause + ); + } + } function logic(t: LogicTree): string { return `${ t.kind === 'ALL' ? 'All' : t.kind === 'ANY' ? 'Any' : `At least ${t.k}` @@ -109,23 +142,38 @@ export function describeJobSpec( checks: spec.checks.map((c) => { const r = spec.reads[c.read]; const t = c.target; - const target = + const resolvedTarget = typeof t === 'bigint' - ? t.toString() + ? t : t === PRINCIPAL - ? options?.principal?.toString() ?? 'principal' + ? options?.principal ?? 'principal' : t === 'agentic:wallet' ? 'the wallet on this chain' : 'param' in t ? `parameter ${t.param + 1}` : options?.principal !== undefined - ? ((options.principal * t.principalBps) / BigInt(10000)).toString() + ? (options.principal * t.principalBps) / BigInt(10000) : `${t.principalBps} basis points of principal`; - return `Read ${c.read + 1}: ${r.target} ${r.selector} on ${ - r.chainNamespace - }:${r.chainId}, field [${r.field.join(',')}], ${c.evaluation} ${ - words[c.operation] - } ${target}${c.evaluation === 'PERCENTAGE' ? ' bps' : ' (raw units)'}.`; + const precision = decimals.get(r.target.toLowerCase()); + const target = + typeof resolvedTarget === 'bigint' + ? c.evaluation === 'PERCENTAGE' + ? `${formatUnits(resolvedTarget, 2)}% (${resolvedTarget} bps)` + : precision !== undefined && c.evaluation !== 'BOOLEAN' + ? `${formatUnits( + resolvedTarget, + precision + )} (${resolvedTarget} raw units; ${precision} decimals)` + : `${resolvedTarget} (raw units)` + : `${resolvedTarget}${ + c.evaluation === 'PERCENTAGE' ? ' bps' : ' (raw units)' + }`; + const name = jobReadLabel(r); + return `Read ${c.read + 1}: ${r.target} ${name ? name + ' ' : ''}${ + r.selector + } on ${r.chainNamespace}:${r.chainId}, field [${r.field.join(',')}], ${ + c.evaluation + } ${words[c.operation]} ${target}.`; }), logic: logic(spec.logic), timing: diff --git a/packages/core/src/lib/job-spec/preview.ts b/packages/core/src/lib/job-spec/preview.ts index 24b98862..c409fe0f 100644 --- a/packages/core/src/lib/job-spec/preview.ts +++ b/packages/core/src/lib/job-spec/preview.ts @@ -1,6 +1,15 @@ -import { getAddress, keccak256, zeroHash, type Address, type Hex } from 'viem'; +import { + decodeAbiParameters, + getAddress, + keccak256, + zeroHash, + type Address, + type Hex, +} from 'viem'; import type { CHAIN } from '../constants/enums'; import { READ_OUTCOME } from '../read-state/read-state.types'; +import type { UniversalReadResponse } from '../read-state/read-state.types'; +import { decodeEvmQueryEnvelope } from '../read-state/envelopes'; import type { ReadPrepareOptions } from '../read-state/read-params'; import { JobSpecError } from '../market/errors'; import { decodeJobSpec, encodeJobSpec, int256 } from './codec'; @@ -153,6 +162,7 @@ export async function previewJobSpec( params: options.params && [...options.params], baseline: options.baseline && [...options.baseline], accounts: { ...options.accounts }, + resume: options.resume && [...options.resume], }; if ( options.maxTotalFee !== undefined && @@ -210,36 +220,130 @@ export async function previewJobSpec( settleWindow: 1, }); } else spec = input; - const prepared = []; - for (const read of spec.reads) { - const readOptions: ReadPrepareOptions = { - chain: `${read.chainNamespace}:${read.chainId}` as Extract< - CHAIN, - `eip155:${string}` - >, - callData: (read.selector + read.args.slice(2)) as Hex, - minConfirmations: read.minConfirmations, - expiryBlocks: options.expiryBlocks, - refundTo: options.refundTo, - callback: options.callback as ReadPrepareOptions['callback'], - }; - prepared.push( - await options.client.universal.prepareRead(read.target, readOptions) + const waitOptions = { + timeoutMs: options.advanced?.timeout, + pollingIntervalMs: options.advanced?.pollingIntervalMs, + resultShape: { kind: 'raw' as const }, + }; + let responses: UniversalReadResponse[]; + let quoted = BigInt(0); + let newlyPaid = BigInt(0); + if (options.resume) { + if ( + options.resume.length !== spec.reads.length || + options.resume.some((id) => !/^0x[\da-f]{64}$/i.test(id)) || + new Set(options.resume.map((x) => x.toLowerCase())).size !== + options.resume.length + ) + throw new JobSpecError( + 'INVALID_PREVIEW_RESUME', + 'Provide one distinct request ID per read, in read order.' + ); + responses = []; + for (const [i, id] of options.resume.entries()) { + const response = await options.client.universal.trackRead( + { requestId: id }, + { resultShape: { kind: 'raw' }, progressHook: options.progressHook } + ); + const read = spec.reads[i]; + let matched = false; + try { + const actual = response.request.spec; + const envelope = decodeEvmQueryEnvelope(actual.query); + const [target, calldata] = decodeAbiParameters( + [{ type: 'address' }, { type: 'bytes' }], + envelope.payload + ); + matched = + response.requestId.toLowerCase() === id.toLowerCase() && + actual.account.chainNamespace === read.chainNamespace && + actual.account.chainId === read.chainId && + actual.minConfirmations >= read.minConfirmations && + envelope.queryType === 1 && + envelope.refType === 0 && + envelope.blockNumber === actual.blockNumber && + getAddress(target) === getAddress(read.target) && + calldata.toLowerCase() === + (read.selector + read.args.slice(2)).toLowerCase(); + } catch { + /* A request from another schema/query cannot stand in for this logical read. */ + } + if (!matched) + throw new JobSpecError( + 'PREVIEW_REQUEST_MISMATCH', + 'The recorded request does not match this resolved JobSpec read.', + { read: i, requestId: id } + ); + responses.push(response); + } + quoted = responses.reduce( + (sum, response) => sum + response.fees.paid, + BigInt(0) ); + } else { + const prepared = []; + for (const read of spec.reads) { + const readOptions: ReadPrepareOptions = { + chain: `${read.chainNamespace}:${read.chainId}` as Extract< + CHAIN, + `eip155:${string}` + >, + callData: (read.selector + read.args.slice(2)) as Hex, + minConfirmations: read.minConfirmations, + expiryBlocks: options.expiryBlocks, + refundTo: options.refundTo, + callback: options.callback as ReadPrepareOptions['callback'], + }; + prepared.push( + await options.client.universal.prepareRead(read.target, readOptions) + ); + } + quoted = prepared.reduce((sum, read) => sum + read.value, BigInt(0)); + if (options.maxTotalFee !== undefined && quoted > options.maxTotalFee) + throw new JobSpecError( + 'PREVIEW_FEE_EXCEEDED', + 'The prepared read fees exceed maxTotalFee. No read was submitted.', + { quoted, maxTotalFee: options.maxTotalFee } + ); + let batch; + try { + batch = await options.client.universal.executeReads(prepared, { + progressHook: options.progressHook, + advanced: options.advanced, + waitForCompletion: false, + }); + } catch (cause) { + const error = cause as { + txHash?: string; + transactionHashes?: readonly Hex[]; + pendingTransactionHash?: Hex; + }; + throw new JobSpecError( + 'PREVIEW_INCOMPLETE', + 'Read submission could not be confirmed. Track the recorded transactions before requesting more reads.', + { + txHash: error?.txHash, + transactionHashes: error?.transactionHashes, + pendingTransactionHash: error?.pendingTransactionHash, + }, + cause + ); + } + responses = batch.reads; + newlyPaid = quoted; } - const quoted = prepared.reduce((sum, read) => sum + read.value, BigInt(0)); - if (options.maxTotalFee !== undefined && quoted > options.maxTotalFee) + const requestIds = responses.map((r) => r.requestId); + try { + responses = await Promise.all(responses.map((r) => r.wait(waitOptions))); + } catch (cause) { throw new JobSpecError( - 'PREVIEW_FEE_EXCEEDED', - 'The prepared read fees exceed maxTotalFee. No read was submitted.', - { quoted, maxTotalFee: options.maxTotalFee } + 'PREVIEW_INCOMPLETE', + 'The paid reads are still recoverable. Resume with these request IDs instead of paying again.', + { requestIds, txHashes: responses.map((r) => r.txHash) }, + cause ); - const batch = await options.client.universal.executeReads(prepared, { - progressHook: options.progressHook, - advanced: options.advanced, - waitForCompletion: true, - }); - const reads: JobSpecPreview['reads'] = batch.reads.map((response, i) => { + } + const reads: JobSpecPreview['reads'] = responses.map((response, i) => { const value = response.raw?.resultData ?? null; if (response.outcome !== READ_OUTCOME.SUCCESS || value === null) return { @@ -286,6 +390,7 @@ export async function previewJobSpec( fees: { quoted, paid: reads.reduce((sum, r) => sum + r.response.fees.paid, BigInt(0)), + newlyPaid, }, }; } diff --git a/packages/core/src/lib/job-spec/read.ts b/packages/core/src/lib/job-spec/read.ts index eeb48ff2..7dfedb5b 100644 --- a/packages/core/src/lib/job-spec/read.ts +++ b/packages/core/src/lib/job-spec/read.ts @@ -11,7 +11,67 @@ import { } from 'viem'; import { argumentLocation } from '../agentic/codec/abi-layout'; import { JobSpecError } from '../market/errors'; -import type { JobFill, PrepareJobReadOptions, PreparedJobRead } from './types'; +import type { + JobFill, + PrepareJobReadOptions, + PreparedJobRead, + ExecuteJobReadOptions, +} from './types'; +import type { ReadOptions } from '../read-state/read-params'; +import type { CHAIN } from '../constants/enums'; + +const labels = new WeakMap< + PreparedJobRead, + { + selector: Hex; + outputs: Hex; + target: string; + name: string; + parameters: readonly AbiParameter[]; + } +>(); +export function inheritReadLabel( + source: PreparedJobRead, + target: PreparedJobRead +): void { + const value = labels.get(source); + if ( + value && + value.selector === source.selector && + value.outputs === source.outputs && + value.target === source.target.toLowerCase() + ) + labels.set(target, value); +} +export function jobReadLabel(read: PreparedJobRead): string | undefined { + const value = labels.get(read); + return value && + value.selector === read.selector && + value.outputs === read.outputs && + value.target === read.target.toLowerCase() + ? value.name + : undefined; +} +/** Same logical call as a JobSpec read, through the normal paid universal-read path. */ +export function jobReadOptions( + read: PreparedJobRead, + options: ExecuteJobReadOptions = {} +): ReadOptions { + validateJobRead(read); + if (read.fills?.length) + throw new JobSpecError( + 'UNFILLED_PLACEHOLDER', + 'Resolve WALLET/PARAM holes before sending a prepared read.' + ); + return { + ...options, + chain: `${read.chainNamespace}:${read.chainId}` as Extract< + CHAIN, + `eip155:${string}` + >, + callData: (read.selector + read.args.slice(2)) as Hex, + }; +} export function outputTypes(params: readonly AbiParameter[]): Hex { function type(p: AbiParameter, depth: number): number[] { @@ -170,7 +230,7 @@ export function prepareJobRead( }; const values = fn.inputs.map((p, i) => lower(p, options.args?.[i], [i], 0)); const [chainNamespace, chainId] = options.chain.split(':'); - return { + const prepared = { chainNamespace, chainId, target: getAddress(options.target), @@ -179,6 +239,14 @@ export function prepareJobRead( outputs: outputTypes(fn.outputs), ...(fills.length ? { fills } : {}), }; + labels.set(prepared, { + selector: prepared.selector, + outputs: prepared.outputs, + target: prepared.target.toLowerCase(), + name: fn.name, + parameters: fn.outputs, + }); + return prepared; } catch (cause) { if (cause instanceof JobSpecError) throw cause; throw new JobSpecError( @@ -196,7 +264,7 @@ export interface OutputNode { size?: number; } export function parseOutputs(outputs: Hex): OutputNode { - if (!isHex(outputs) || outputs.length > 8194) + if (!isHex(outputs) || outputs.length % 2 !== 0 || outputs.length > 8194) throw new JobSpecError('INVALID_READ', 'Invalid output type layout.'); const bytes = outputs diff --git a/packages/core/src/lib/job-spec/types.ts b/packages/core/src/lib/job-spec/types.ts index a3c83a63..d80e70ab 100644 --- a/packages/core/src/lib/job-spec/types.ts +++ b/packages/core/src/lib/job-spec/types.ts @@ -7,6 +7,7 @@ import type { UniversalReadResponse, } from '../read-state/read-state.types'; import type { ReadExecuteOptions } from '../read-state/read-params'; +import type { ReadOptions } from '../read-state/read-params'; export type Evaluation = (typeof JOB_VOCABULARY.EVALUATION)[keyof typeof JOB_VOCABULARY.EVALUATION]; export type Operation = @@ -42,6 +43,18 @@ export interface PrepareJobReadOptions { functionName: string; args?: readonly unknown[]; } +export type ExecuteJobReadOptions = Pick< + ReadOptions, + | 'callback' + | 'minConfirmations' + | 'blockNumber' + | 'expiryBlocks' + | 'maxFee' + | 'refundTo' + | 'waitForCompletion' + | 'progressHook' + | 'advanced' +>; export interface JobReadInput { read: PreparedJobRead; minConfirmations?: number; @@ -117,6 +130,8 @@ export interface PreviewJobSpecOptions { refundTo?: Address; progressHook?: ReadExecuteOptions['progressHook']; advanced?: ReadExecuteOptions['advanced']; + /** One existing request ID per read, in read order. Validated against the resolved call; no new fees. */ + resume?: readonly Hex[]; } export interface JobSpecPreview { /** A preview is a paid observation, never an evaluator verdict. */ @@ -128,6 +143,6 @@ export interface JobSpecPreview { }[]; checks: { pass: boolean | null; value: bigint | null; reason?: string }[]; pass: boolean | null; - fees: { quoted: bigint; paid: bigint }; + fees: { quoted: bigint; paid: bigint; newlyPaid: bigint }; } export type JobArgumentPath = ArgumentPath; diff --git a/packages/core/src/lib/job/job.ts b/packages/core/src/lib/job/job.ts index 6b14a9d7..49865830 100644 --- a/packages/core/src/lib/job/job.ts +++ b/packages/core/src/lib/job/job.ts @@ -32,6 +32,7 @@ import { Snapshot, scanLogs } from '../agentic/reads/snapshot'; import { decodeJobSpec } from '../job-spec/codec'; import type { JobSpec } from '../job-spec/types'; import type { Call } from '../agentic/contracts/v6'; +import { watchJob } from './watch'; import type { CreateJobOptions, FundJobOptions, @@ -40,6 +41,7 @@ import type { JobNamespace, JobStatus, JobWriteOptions, + JobWatchOptions, } from './types'; const STATES: JobStatus[] = [ @@ -192,6 +194,7 @@ export class JobNamespaceImpl implements JobNamespace { return { jobs }; } async create(options: CreateJobOptions) { + options = { ...options }; const d = deployment(this.rt); const s = await snapshot(this.rt); const token = await s.read
    (d.kernel, ABI, 'paymentToken'); @@ -289,6 +292,7 @@ export class JobNamespaceImpl implements JobNamespace { ); } async fund(jobId: bigint, options: FundJobOptions = {}) { + options = { ...options }; const rt = this.rt; const d = deployment(rt); const s = await snapshot(rt); @@ -454,6 +458,7 @@ export class JobNamespaceImpl implements JobNamespace { jobId: bigint, options: JobWriteOptions & { deliverable: Hex | string } ) { + options = { ...options }; const s = await snapshot(this.rt); const j = await this.raw(jobId, s); this.provider(j); @@ -587,99 +592,9 @@ export class JobNamespaceImpl implements JobNamespace { watch( jobId: bigint, callback: (event: JobEvent) => void, - options: { fromBlock?: bigint; pollIntervalMs?: number } = {} + options: JobWatchOptions = {} ): () => void { validId(jobId); - const d = deployment(this.rt); - let stopped = false; - let timer: ReturnType | undefined; - let cursor = options.fromBlock; - const interval = options.pollIntervalMs ?? 3000; - if ( - !Number.isSafeInteger(interval) || - interval < 25 || - (cursor !== undefined && cursor < BigInt(0)) - ) - throw new JobError( - 'INVALID_WATCH_OPTIONS', - 'Use a nonnegative block and a polling interval of at least 25ms.' - ); - const names = [ - 'JobCreated', - 'BudgetSet', - 'JobFunded', - 'JobSubmitted', - 'JobCompleted', - 'JobRejected', - 'JobExpired', - 'Refunded', - ] as const; - const kinds = [ - 'Created', - 'BudgetSet', - 'Funded', - 'Submitted', - 'Completed', - 'Rejected', - 'Expired', - 'Refunded', - ]; - const poll = async () => { - try { - const head = await this.rt.agw.reader.getBlockNumber(); - if (stopped) return; - if (cursor === undefined) cursor = head; - const end = cursor + BigInt(999) < head ? cursor + BigInt(999) : head; - if (cursor <= end) { - const groups = await Promise.all( - names.map((name) => - this.rt.agw.reader.getLogs({ - address: d.kernel, - event: getAbiItem({ abi: ABI, name }), - args: { jobId }, - fromBlock: cursor ?? head, - toBlock: end, - }) - ) - ); - const logs = groups - .flat() - .sort( - (a, b) => - Number( - (a.blockNumber ?? BigInt(0)) - (b.blockNumber ?? BigInt(0)) - ) || (a.logIndex ?? 0) - (b.logIndex ?? 0) - ); - for (const log of logs) { - if (stopped) return; - const e = decodeEventLog({ - abi: ABI, - data: log.data, - topics: log.topics, - }); - callback({ - jobId, - kind: kinds[names.indexOf(e.eventName as (typeof names)[number])], - txHash: log.transactionHash ?? undefined, - blockNumber: log.blockNumber ?? undefined, - data: e.args, - }); - } - cursor = end + BigInt(1); - } - } catch (error) { - if (!stopped) callback({ jobId, kind: 'Error', error }); - } finally { - if (!stopped) - timer = setTimeout(() => { - void poll(); - }, interval); - } - }; - void poll(); - return () => { - stopped = true; - if (timer) clearTimeout(timer); - }; + return watchJob(this.rt, jobId, callback, { ...options }); } } diff --git a/packages/core/src/lib/job/types.ts b/packages/core/src/lib/job/types.ts index 25c6e6ad..cf810599 100644 --- a/packages/core/src/lib/job/types.ts +++ b/packages/core/src/lib/job/types.ts @@ -59,6 +59,18 @@ export interface JobEvent { blockNumber?: bigint; data?: unknown; error?: unknown; + cursor?: JobWatchCursor; +} +/** Last delivered log; resume includes its block and excludes this log and earlier logs. */ +export interface JobWatchCursor { + blockNumber: bigint; + logIndex: number; + blockHash?: Hex; +} +export interface JobWatchOptions { + fromBlock?: bigint; + cursor?: JobWatchCursor; + pollIntervalMs?: number; } export interface JobNamespace { create( @@ -93,6 +105,6 @@ export interface JobNamespace { watch( jobId: bigint, callback: (event: JobEvent) => void, - options?: { fromBlock?: bigint; pollIntervalMs?: number } + options?: JobWatchOptions ): () => void; } diff --git a/packages/core/src/lib/job/watch.spec.ts b/packages/core/src/lib/job/watch.spec.ts new file mode 100644 index 00000000..fee0ebc4 --- /dev/null +++ b/packages/core/src/lib/job/watch.spec.ts @@ -0,0 +1,140 @@ +import { + encodeAbiParameters, + encodeEventTopics, + zeroHash, + type Log, +} from 'viem'; +import { watchJob } from './watch'; +import { JOB_KERNEL_ABI as ABI } from '../market/contracts/AgenticCommerce'; +import { DONUT_MARKETPLACE as D } from '../market/deployment'; +import { FakeChain } from '../agentic/__tests__/fake-chain'; +import { mockRuntime } from '../agentic/__tests__/mock-runtime'; +import type { StackRuntime } from '../market/runtime'; +import type { JobEvent } from './types'; +const makeLog = (logIndex: number): Log => + ({ + address: D.kernel, + blockNumber: BigInt(10), + blockHash: zeroHash, + logIndex, + transactionIndex: 0, + transactionHash: zeroHash, + removed: false, + topics: encodeEventTopics({ + abi: ABI, + eventName: 'BudgetSet', + args: { jobId: BigInt(1) }, + }), + data: encodeAbiParameters([{ type: 'uint256' }], [BigInt(logIndex)]), + } as Log); +const flush = async () => { + for (let i = 0; i < 20; i++) await Promise.resolve(); +}; +function fixture() { + const base = mockRuntime(new FakeChain()); + const state = { + failed: false, + logs: [makeLog(0), makeLog(1)], + blockHash: zeroHash as string, + }; + const getLogs = jest.fn(async ({ event }: { event: { name: string } }) => { + if (state.failed) throw new Error('RPC unavailable'); + return event.name === 'BudgetSet' ? state.logs : []; + }); + const rt: StackRuntime = { + agw: { + ...base, + reader: { + ...base.reader, + getBlockNumber: async () => BigInt(10), + getBlock: async () => ({ + timestamp: BigInt(1), + hash: state.blockHash as `0x${string}`, + }), + getLogs, + }, + }, + account: base.signerPushAccount, + wallet: () => undefined, + send: jest.fn(), + signTypedData: jest.fn(), + }; + return { rt, state, getLogs }; +} +beforeEach(() => jest.useFakeTimers()); +afterEach(() => jest.useRealTimers()); +it('deduplicates provider replay and resumes after an exact log within the same block', async () => { + const f = fixture(); + f.state.logs.push(makeLog(1)); + const events: JobEvent[] = []; + const stop = watchJob(f.rt, BigInt(1), (e) => events.push(e), { + cursor: { blockNumber: BigInt(10), logIndex: 0, blockHash: zeroHash }, + pollIntervalMs: 25, + }); + await flush(); + stop(); + expect(events.map((e) => e.cursor?.logIndex)).toEqual([1]); +}); +it('does not rewind a delivered event when the consumer callback throws', async () => { + const f = fixture(); + const events: JobEvent[] = []; + const stop = watchJob( + f.rt, + BigInt(1), + (e) => { + events.push(e); + if (e.kind !== 'Error') throw new Error('Consumer failed'); + }, + { fromBlock: BigInt(10), pollIntervalMs: 25 } + ); + await flush(); + jest.advanceTimersByTime(25); + await flush(); + stop(); + expect(events.filter((e) => e.kind === 'BudgetSet')).toHaveLength(2); + expect(events.filter((e) => e.kind === 'Error')).toHaveLength(2); +}); +it('retries RPC failures without skipping a range', async () => { + const f = fixture(); + f.state.failed = true; + const events: JobEvent[] = []; + const stop = watchJob(f.rt, BigInt(1), (e) => events.push(e), { + fromBlock: BigInt(10), + pollIntervalMs: 25, + }); + await flush(); + f.state.failed = false; + jest.advanceTimersByTime(25); + await flush(); + stop(); + expect(events.map((e) => e.kind)).toEqual([ + 'Error', + 'BudgetSet', + 'BudgetSet', + ]); +}); +it('stops on a changed canonical cursor and suppresses callbacks after unsubscribe', async () => { + const f = fixture(); + f.state.blockHash = '0x' + 'ab'.repeat(32); + const events: JobEvent[] = []; + const stop = watchJob(f.rt, BigInt(1), (e) => events.push(e), { + cursor: { blockNumber: BigInt(10), logIndex: 0, blockHash: zeroHash }, + pollIntervalMs: 25, + }); + await flush(); + expect(events[0]).toMatchObject({ + kind: 'Error', + error: { code: 'WATCH_REORG' }, + }); + jest.advanceTimersByTime(25); + await flush(); + expect(events).toHaveLength(1); + stop(); + const callbacks = jest.fn(); + const cancel = watchJob(f.rt, BigInt(1), callbacks, { + fromBlock: BigInt(10), + }); + cancel(); + await flush(); + expect(callbacks).not.toHaveBeenCalled(); +}); diff --git a/packages/core/src/lib/job/watch.ts b/packages/core/src/lib/job/watch.ts new file mode 100644 index 00000000..d9a67b01 --- /dev/null +++ b/packages/core/src/lib/job/watch.ts @@ -0,0 +1,209 @@ +import { decodeEventLog, getAbiItem, getAddress, type Log } from 'viem'; +import { JOB_KERNEL_ABI as ABI } from '../market/contracts/AgenticCommerce'; +import { deployment, type StackRuntime } from '../market/runtime'; +import { JobError } from '../market/errors'; +import { fingerprint } from '../market/data'; +import type { JobEvent, JobWatchOptions } from './types'; + +const names = [ + 'JobCreated', + 'BudgetSet', + 'JobFunded', + 'JobSubmitted', + 'JobCompleted', + 'JobRejected', + 'JobExpired', + 'Refunded', +] as const; +const kinds = [ + 'Created', + 'BudgetSet', + 'Funded', + 'Submitted', + 'Completed', + 'Rejected', + 'Expired', + 'Refunded', +]; + +export function watchJob( + rt: StackRuntime, + jobId: bigint, + callback: (event: JobEvent) => void, + options: JobWatchOptions +): () => void { + const d = deployment(rt); + let stopped = false; + let timer: ReturnType | undefined; + let cursor = options.cursor && { ...options.cursor }; + let next = cursor?.blockNumber ?? options.fromBlock; + const interval = options.pollIntervalMs ?? 3000; + if ( + !Number.isSafeInteger(interval) || + interval < 25 || + (next !== undefined && (typeof next !== 'bigint' || next < BigInt(0))) || + (cursor && + (!Number.isSafeInteger(cursor.logIndex) || + cursor.logIndex < 0 || + (cursor.blockHash && !/^0x[\da-f]{64}$/i.test(cursor.blockHash)))) || + (cursor && options.fromBlock !== undefined) + ) + throw new JobError( + 'INVALID_WATCH_OPTIONS', + 'Use a nonnegative block or a delivered-log cursor, and a polling interval of at least 25ms.' + ); + const notify = (event: JobEvent): void => { + try { + callback(event); + } catch (error) { + if (event.kind !== 'Error' && !stopped) { + try { + callback({ + jobId, + kind: 'Error', + error, + cursor: cursor && { ...cursor }, + }); + } catch { + /* A consumer exception must not rewind delivery or reject an unobserved promise. */ + } + } + } + }; + const poll = async () => { + try { + const head = await rt.agw.reader.getBlockNumber(); + if (stopped) return; + if (cursor) { + if (head < cursor.blockNumber) + throw new JobError( + 'WATCH_REORG', + 'The delivered cursor is ahead of the canonical head. Reload status before continuing.' + ); + const block = + rt.agw.reader.getBlock && + (await rt.agw.reader.getBlock({ blockNumber: cursor.blockNumber })); + if ( + head < cursor.blockNumber || + (cursor.blockHash && + block?.hash && + cursor.blockHash.toLowerCase() !== block.hash.toLowerCase()) + ) + throw new JobError( + 'WATCH_REORG', + 'The delivered cursor is no longer canonical. Reload job status and restart from a reviewed block.' + ); + } + if (next === undefined) next = head; + const end = next + BigInt(999) < head ? next + BigInt(999) : head; + if (next <= end) { + const start = next; + const groups = await Promise.all( + names.map((name) => + rt.agw.reader.getLogs({ + address: d.kernel, + event: getAbiItem({ abi: ABI, name }), + args: { jobId }, + fromBlock: start, + toBlock: end, + }) + ) + ); + if (stopped) return; + const unique = new Map< + string, + { log: Log; event: ReturnType } + >(); + for (const log of groups.flat()) { + if (log.removed) + throw new JobError( + 'WATCH_REORG', + 'The RPC returned a removed job log. Reload status before continuing.' + ); + if ( + getAddress(log.address) !== getAddress(d.kernel) || + log.blockNumber === null || + log.logIndex === null || + log.blockNumber < start || + log.blockNumber > end + ) + throw new JobError( + 'INCONSISTENT_READ', + 'The RPC returned an unmined or out-of-range job log.' + ); + const event = decodeEventLog({ + abi: ABI, + data: log.data, + topics: log.topics, + strict: true, + }); + if ( + (event.args as { jobId?: bigint }).jobId !== jobId || + !names.includes(event.eventName as (typeof names)[number]) + ) + throw new JobError( + 'INCONSISTENT_READ', + 'The RPC returned a different job or unsupported event.' + ); + const key = `${log.blockNumber}:${log.logIndex}`; + const previous = unique.get(key); + if (previous && fingerprint(previous.log) !== fingerprint(log)) + throw new JobError( + 'INCONSISTENT_READ', + 'Two different logs occupy the same job cursor.' + ); + unique.set(key, { log, event }); + } + const ordered = [...unique.values()].sort( + (a, b) => + Number( + (a.log.blockNumber as bigint) - (b.log.blockNumber as bigint) + ) || (a.log.logIndex as number) - (b.log.logIndex as number) + ); + for (const { log, event } of ordered) { + if (stopped) return; + const blockNumber = log.blockNumber as bigint; + const logIndex = log.logIndex as number; + if ( + cursor && + (blockNumber < cursor.blockNumber || + (blockNumber === cursor.blockNumber && + logIndex <= cursor.logIndex)) + ) + continue; + cursor = { + blockNumber, + logIndex, + ...(log.blockHash ? { blockHash: log.blockHash } : {}), + }; + notify({ + jobId, + kind: kinds[ + names.indexOf(event.eventName as (typeof names)[number]) + ], + txHash: log.transactionHash ?? undefined, + blockNumber, + data: event.args, + cursor: { ...cursor }, + }); + } + next = end + BigInt(1); + } + } catch (error) { + if (stopped) return; + if (error instanceof JobError && error.code === 'WATCH_REORG') + stopped = true; + notify({ jobId, kind: 'Error', error, cursor: cursor && { ...cursor } }); + } finally { + if (!stopped) + timer = setTimeout(() => { + void poll(); + }, interval); + } + }; + void poll(); + return () => { + stopped = true; + if (timer) clearTimeout(timer); + }; +} diff --git a/packages/core/src/lib/market/__tests__/ci-reporter.spec.ts b/packages/core/src/lib/market/__tests__/ci-reporter.spec.ts new file mode 100644 index 00000000..8fecaeaf --- /dev/null +++ b/packages/core/src/lib/market/__tests__/ci-reporter.spec.ts @@ -0,0 +1,38 @@ +const fs = require('node:fs'); +const CiReporter = require('../../../../__e2e__/ci/ci-reporter'); +export {}; +it('reports final counters without relying on the pre-final Jest success flag', () => { + const write = jest + .spyOn(fs, 'writeFileSync') + .mockImplementation(() => undefined); + const mkdir = jest.spyOn(fs, 'mkdirSync').mockImplementation(() => undefined); + try { + const report = (extra: object) => { + new CiReporter().onRunComplete(null, { + numTotalTests: 1, + numPassedTests: 1, + numFailedTests: 0, + numPendingTests: 0, + success: false, + testResults: [], + ...extra, + }); + return JSON.parse( + write.mock.calls[write.mock.calls.length - 1][1] as string + ); + }; + expect(report({})).toMatchObject({ + success: true, + jestReportedSuccess: false, + }); + expect(report({ numFailedTestSuites: 1 }).success).toBe(false); + expect(report({ numRuntimeErrorTestSuites: 1 }).success).toBe(false); + expect(report({ wasInterrupted: true }).success).toBe(false); + expect(report({ numPassedTests: 0, numPendingTests: 1 }).success).toBe( + false + ); + } finally { + write.mockRestore(); + mkdir.mockRestore(); + } +}); diff --git a/packages/core/src/lib/market/__tests__/history.spec.ts b/packages/core/src/lib/market/__tests__/history.spec.ts new file mode 100644 index 00000000..937baf47 --- /dev/null +++ b/packages/core/src/lib/market/__tests__/history.spec.ts @@ -0,0 +1,143 @@ +import { + encodeAbiParameters, + encodeEventTopics, + encodeFunctionData, + keccak256, + stringToHex, + zeroHash, + type Address, + type Hex, + type Log, +} from 'viem'; +import { historicalCard } from '../history'; +import { MARKETPLACE_ABI as ABI } from '../contracts/UniversalMarketplace'; +import { DONUT_MARKETPLACE as D } from '../deployment'; +import { encodeAgentCardRules } from '../rules'; +import { PRINCIPAL } from '../../job-spec/constants'; +import { FakeChain } from '../../agentic/__tests__/fake-chain'; +import { mockRuntime } from '../../agentic/__tests__/mock-runtime'; +import type { StackRuntime } from '../runtime'; +const provider = '0x1111111111111111111111111111111111111111' as Address; +const hash = ('0x' + 'ab'.repeat(32)) as Hex; +function fixture() { + const base = mockRuntime(new FakeChain()); + const rules = encodeAgentCardRules( + { + assets: [ + { + token: { prc20: D.paymentToken }, + maxPerCall: PRINCIPAL, + maxTotal: PRINCIPAL, + }, + ], + principalAsset: 0, + maxGasPerCall: BigInt(17), + allowedCalls: [{ target: provider, selector: 'balanceOf(address)' }], + }, + { chain: 'eip155:97' } + ); + const c = { + provider, + active: true, + jobType: keccak256(stringToHex('test')), + metadataURI: 'test', + metadataHash: zeroHash, + chainNamespace: 'eip155:97', + providerFee: BigInt(7), + paymentToken: D.paymentToken, + principalMin: BigInt(1), + principalMax: BigInt(20), + minDuration: 3600, + maxDuration: 86400, + minExecuteWindow: 0, + settleWindow: 60, + }; + const data = encodeFunctionData({ + abi: ABI, + functionName: 'registerAgentCard', + args: [c, rules, '0x1234'], + }); + const log = { + address: D.marketplace, + blockNumber: BigInt(24443653), + transactionHash: hash, + logIndex: 0, + blockHash: zeroHash, + transactionIndex: 0, + removed: false, + topics: encodeEventTopics({ + abi: ABI, + eventName: 'AgentCardRegistered', + args: { cardId: BigInt(1), provider, jobType: c.jobType }, + }), + data: encodeAbiParameters( + [ + { type: 'string' }, + { type: 'bytes32' }, + { type: 'bytes32' }, + { type: 'bytes32' }, + { type: 'uint256' }, + ], + [ + c.chainNamespace, + keccak256(rules), + keccak256('0x1234'), + zeroHash, + BigInt(7), + ] + ), + } as Log; + const state = { + input: ('0x12345678' + + encodeAbiParameters([{ type: 'bytes' }], [data]).slice(2)) as Hex, + blockNumber: log.blockNumber, + }; + const logs = jest.fn(async () => [log]); + const rt: StackRuntime = { + agw: { + ...base, + reader: { + ...base.reader, + getBlockNumber: async () => BigInt(24443654), + readContract: async () => ({ card: c }), + getLogs: logs, + getTransaction: async () => state, + }, + }, + account: () => provider, + wallet: () => undefined, + send: jest.fn(), + signTypedData: jest.fn(), + }; + const load = jest.fn(async () => { + throw new Error('Archive unavailable'); + }); + const run = () => + historicalCard(rt, BigInt(1), BigInt(1), BigInt(24443654), load); + return { run, load, rt, state, rules, data, log, logs }; +} +it('recovers an exact version from event hashes and wrapped transaction input without archive state', async () => { + const f = fixture(); + expect(await f.run()).toMatchObject({ + version: BigInt(1), + providerFee: BigInt(7), + rulesBytes: f.rules, + rules: { maxGasPerCall: BigInt(17) }, + }); +}); +it('uses matching historical state without scanning transaction history', async () => { + const f = fixture(); + f.load.mockImplementation(async () => ({ version: BigInt(1) } as never)); + expect(await f.run()).toEqual({ version: BigInt(1) }); + expect(f.logs).not.toHaveBeenCalled(); +}); +it('rejects a selector-shaped decoy whose content hashes do not match the emitted version', async () => { + const f = fixture(); + f.state.input = f.data.replace('1234', '4321') as Hex; + await expect(f.run()).rejects.toMatchObject({ code: 'HISTORY_UNAVAILABLE' }); +}); +it('rejects history whose transaction is no longer mined in the event block', async () => { + const f = fixture(); + f.state.blockNumber = BigInt(24443654); + await expect(f.run()).rejects.toMatchObject({ code: 'HISTORY_UNAVAILABLE' }); +}); diff --git a/packages/core/src/lib/market/__tests__/namespace.spec.ts b/packages/core/src/lib/market/__tests__/namespace.spec.ts index a0bf5e48..daf23427 100644 --- a/packages/core/src/lib/market/__tests__/namespace.spec.ts +++ b/packages/core/src/lib/market/__tests__/namespace.spec.ts @@ -2,6 +2,7 @@ import { zeroAddress, zeroHash, type Address } from 'viem'; import { MarketNamespaceImpl } from '../market'; import { JobNamespaceImpl } from '../../job/job'; import { mockRuntime } from '../../agentic/__tests__/mock-runtime'; +import { fakeResponse } from '../../agentic/__tests__/mock-runtime'; import { FakeChain } from '../../agentic/__tests__/fake-chain'; import type { StackRuntime } from '../runtime'; import type { JobPlan } from '../types'; @@ -162,3 +163,20 @@ it('compares the factory signing domain before prompting the owner', async () => expect(rt.signTypedData).not.toHaveBeenCalled(); expect(rt.agw.reader.call).not.toHaveBeenCalled(); }); +it('retains the submitted opening hash when receipt recovery fails, without another signature or write', async () => { + const { rt, read, execute } = runtime(); + const tx = fakeResponse({ + wait: async () => { + throw new Error('Receipt unavailable'); + }, + }); + await expect( + new MarketNamespaceImpl(rt).openJob({} as JobPlan, { resume: tx }) + ).rejects.toMatchObject({ + code: 'OPEN_JOB_RECOVERY_REQUIRED', + details: { txHash: tx.hash }, + }); + expect(rt.signTypedData).not.toHaveBeenCalled(); + expect(execute).not.toHaveBeenCalled(); + expect(read).not.toHaveBeenCalled(); +}); diff --git a/packages/core/src/lib/market/data.ts b/packages/core/src/lib/market/data.ts new file mode 100644 index 00000000..f3939145 --- /dev/null +++ b/packages/core/src/lib/market/data.ts @@ -0,0 +1,68 @@ +import { + decodeFunctionData, + encodeFunctionData, + getAbiItem, + toFunctionSelector, + type Abi, + type Hex, +} from 'viem'; + +/** Copy public data before awaiting RPCs or a wallet; BigInts and array order are retained. */ +export function copyData(value: T): T { + if (Array.isArray(value)) return value.map(copyData) as T; + if (value && typeof value === 'object') + return Object.fromEntries( + Object.entries(value).map(([k, v]) => [k, copyData(v)]) + ) as T; + return value; +} +export function fingerprint(value: unknown): string { + const sorted = (v: unknown): unknown => + Array.isArray(v) + ? v.map(sorted) + : v && typeof v === 'object' + ? Object.fromEntries( + Object.entries(v) + .sort(([a], [b]) => a.localeCompare(b)) + .map(([k, x]) => [k, sorted(x)]) + ) + : typeof v === 'bigint' + ? `${v}n` + : v; + return JSON.stringify(sorted(value)); +} + +/** Locate canonical ABI calls inside ordinary, UEA, AGW or multisig transaction inputs. + * Candidates are data, not proof of execution: callers must bind them to authenticated receipt events. + */ +export function embeddedCalls( + input: Hex, + abi: Abi, + name: string +): readonly unknown[][] { + const item = getAbiItem({ abi, name }); + if (!item || item.type !== 'function') return []; + const selector = toFunctionSelector(item).slice(2).toLowerCase(); + const hex = input.toLowerCase(); + const calls: unknown[][] = []; + let offset = 2; + while ((offset = hex.indexOf(selector, offset)) !== -1) { + const at = offset; + offset += 2; + if (at % 2 !== 0) continue; + try { + const data = ('0x' + input.slice(at)) as Hex; + const decoded = decodeFunctionData({ abi: [item], data }); + const encoded = encodeFunctionData({ + abi: [item], + functionName: name, + args: decoded.args, + }); + if (data.slice(0, encoded.length).toLowerCase() === encoded.toLowerCase()) + calls.push([...(decoded.args ?? [])]); + } catch { + /* A selector-shaped value inside unrelated calldata is not a candidate. */ + } + } + return calls; +} diff --git a/packages/core/src/lib/market/deposit.ts b/packages/core/src/lib/market/deposit.ts index 20d43944..17c7fda5 100644 --- a/packages/core/src/lib/market/deposit.ts +++ b/packages/core/src/lib/market/deposit.ts @@ -18,6 +18,7 @@ import { configId } from '../agentic/codec/ids'; import { scanLogs } from '../agentic/reads/snapshot'; import { confirmedLogs } from '../agentic/management/common'; import { decodeCardRulesWire } from './rules'; +import { historicalCard } from './history'; import { MOVEABLE_TOKENS, type MoveableToken } from '../constants/tokens'; import { getPRC20Address } from '../universal/prc20-address'; import { MarketError } from './errors'; @@ -165,11 +166,11 @@ export async function openedDeposit( 'Could not recover one marketplace opening for this job.' ); const opened = events[0]; - const card = await loadCard(cardId, await snapshot(rt, block)); - if (card.version !== version || opened.cardVersion !== version) + const card = await historicalCard(rt, cardId, version, block, loadCard); + if (opened.cardVersion !== version) throw new MarketError( 'HISTORY_UNAVAILABLE', - 'The opening block does not expose the exact opened card version. An archive with transaction-level history is required.' + 'The opening event does not match the recorded card version.' ); const spec = decodeJobSpec(kernel.description, { format: 'spec' }); if ( diff --git a/packages/core/src/lib/market/errors.ts b/packages/core/src/lib/market/errors.ts index 3afe513e..3e329d33 100644 --- a/packages/core/src/lib/market/errors.ts +++ b/packages/core/src/lib/market/errors.ts @@ -48,6 +48,20 @@ export function unavailable(feature: string): never { export function stackError(error: unknown): unknown { if (error instanceof AgenticError) return error; const seen = new Set(); + const submitted = error as { + txHash?: string; + pendingTransactionHash?: string; + gatewayTxHash?: string; + } | null; + const recovery = { + ...(submitted?.txHash ? { txHash: submitted.txHash } : {}), + ...(submitted?.pendingTransactionHash + ? { pendingTransactionHash: submitted.pendingTransactionHash } + : {}), + ...(submitted?.gatewayTxHash + ? { gatewayTxHash: submitted.gatewayTxHash } + : {}), + }; function visit(value: unknown, depth: number): MarketError | undefined { if (!value || typeof value !== 'object' || seen.has(value) || depth > 8) return; @@ -72,7 +86,7 @@ export function stackError(error: unknown): unknown { return new MarketError( code, `The contract rejected the request: ${decoded.errorName}.`, - { decodedError: decoded }, + { decodedError: decoded, ...recovery }, error ); } catch { diff --git a/packages/core/src/lib/market/history.ts b/packages/core/src/lib/market/history.ts new file mode 100644 index 00000000..2acc1761 --- /dev/null +++ b/packages/core/src/lib/market/history.ts @@ -0,0 +1,123 @@ +import { + decodeEventLog, + getAbiItem, + getAddress, + keccak256, + type Address, + type Hex, +} from 'viem'; +import { scanLogs } from '../agentic/reads/snapshot'; +import { MARKETPLACE_ABI as ABI } from './contracts/UniversalMarketplace'; +import { decodeAgentCardRules } from './rules'; +import { embeddedCalls } from './data'; +import { MarketError } from './errors'; +import { + deployment, + snapshot, + type MarketSnapshot, + type StackRuntime, +} from './runtime'; +import type { AgentCard } from './types'; + +/** Exact deposit-critical fields from an emitted version, including same-block updates. + * Event content hashes, immutable provider/chain and the kernel token bind the recovered input. + */ +export async function historicalCard( + rt: StackRuntime, + cardId: bigint, + version: bigint, + openedAt: bigint, + load: (cardId: bigint, at: MarketSnapshot) => Promise +): Promise< + Pick< + AgentCard, + | 'version' + | 'provider' + | 'paymentToken' + | 'providerFee' + | 'rulesBytes' + | 'rules' + > +> { + let originalCause: unknown; + try { + const card = await load(cardId, await snapshot(rt, openedAt)); + if (card.version === version) return card; + } catch (cause) { + originalCause = cause; + } + const d = deployment(rt); + const fail = (cause?: unknown): never => { + throw new MarketError( + 'HISTORY_UNAVAILABLE', + 'Could not authenticate the exact opened card version from historical state or transaction input.', + { cardId, cardVersion: version, openedAt }, + cause ?? originalCause + ); + }; + if (!rt.agw.reader.getTransaction) return fail(); + const name = + version === BigInt(1) ? 'AgentCardRegistered' : 'AgentCardUpdated'; + const records = await scanLogs( + rt.agw.reader, + { + address: d.marketplace, + event: getAbiItem({ abi: ABI, name }), + args: { cardId }, + }, + d.startBlock, + openedAt + ); + const matches = records + .map((log) => ({ + log, + event: decodeEventLog({ + abi: ABI, + eventName: name, + data: log.data, + topics: log.topics, + strict: true, + }).args, + })) + .filter(({ event }) => !('version' in event) || event.version === version); + if (matches.length !== 1) return fail(); + const { log, event } = matches[0]; + if (!log.transactionHash || log.blockNumber === null) return fail(); + const tx = await rt.agw.reader.getTransaction({ hash: log.transactionHash }); + if (tx.blockNumber !== log.blockNumber) return fail(); + // The chain and provider cannot change on update. Do not decode today's potentially malformed template. + const current = await ( + await snapshot(rt) + ).read<{ + card: { provider: Address; chainNamespace: string; paymentToken: Address }; + }>(d.marketplace, ABI, 'getAgentCard', [cardId]); + const fn = version === BigInt(1) ? 'registerAgentCard' : 'updateAgentCard'; + const candidates = embeddedCalls(tx.input, ABI, fn).filter((args) => { + const i = version === BigInt(1) ? 0 : 1; + const c = args[i] as { + chainNamespace: string; + paymentToken: Address; + providerFee: bigint; + }; + return ( + (i === 0 || args[0] === cardId) && + c.chainNamespace === current.card.chainNamespace && + getAddress(c.paymentToken) === getAddress(current.card.paymentToken) && + c.providerFee === event.providerFee && + keccak256(args[i + 1] as Hex) === event.rulesHash && + keccak256(args[i + 2] as Hex) === event.jobSpecHash + ); + }); + // Identical byte sequences may appear more than once in a wrapper. Hash-bound content is identical. + if (!candidates.length) return fail(); + const i = version === BigInt(1) ? 0 : 1; + const rulesBytes = candidates[0][i + 1] as Hex; + return { + version, + provider: getAddress(current.card.provider), + paymentToken: getAddress(current.card.paymentToken), + providerFee: event.providerFee, + rulesBytes, + rules: decodeAgentCardRules(rulesBytes), + }; +} diff --git a/packages/core/src/lib/market/market.ts b/packages/core/src/lib/market/market.ts index a1930b2d..71d61919 100644 --- a/packages/core/src/lib/market/market.ts +++ b/packages/core/src/lib/market/market.ts @@ -1,5 +1,6 @@ import { encodeFunctionData, + decodeAbiParameters, getAddress, domainSeparator, keccak256, @@ -13,6 +14,7 @@ import { MARKETPLACE_ABI as ABI } from './contracts/UniversalMarketplace'; import { JOB_KERNEL_ABI } from './contracts/AgenticCommerce'; import { MARKET_RULES_ABI } from './contracts/UniversalMarketplaceRules'; import { currentGeneration } from '../agentic/deployments'; +import { rulesId as permissionId } from '../agentic/codec/ids'; import { buildSession, encodeEnvelope, @@ -33,7 +35,8 @@ import { encodeAgentCardRules, fillCardRules, } from './rules'; -import { decodeCreateJob } from './kernel-wire'; +import { decodeCreateJob, KERNEL_READ_ABI } from './kernel-wire'; +import { copyData, embeddedCalls, fingerprint as fp } from './data'; import { depositJob, type DepositCheckpoint } from './deposit'; import { deployment, @@ -55,6 +58,7 @@ import type { MarketPreviewOptions, MarketWriteOptions, MarketDepositOptions, + MarketOpenOptions, OwnerIntent, } from './types'; import type { CHAIN } from '../constants/enums'; @@ -72,8 +76,6 @@ interface WireView { verified: boolean; disabled: boolean; } -const fp = (x: unknown): string => - JSON.stringify(x, (_, v) => (typeof v === 'bigint' ? v.toString() : v)); const ownerIntentFields = [ ['owner', 'address'], ['wallet', 'address'], @@ -219,6 +221,7 @@ export class MarketNamespaceImpl implements MarketNamespace { cardId: bigint, options: MarketPreviewOptions ): Promise { + options = { ...options, params: options.params && [...options.params] }; const rt = this.rt; const d = deployment(rt); const s = await snapshot(rt); @@ -517,11 +520,11 @@ export class MarketNamespaceImpl implements MarketNamespace { }, }; } - async openJob( - plan: JobPlan, - options: MarketWriteOptions & { relay?: boolean } = {} - ) { + async openJob(plan: JobPlan, options: MarketOpenOptions = {}) { + plan = copyData(plan); + options = { ...options }; if (options.relay) unavailable('Marketplace relaying'); + if (options.resume) return this.openedResult(plan, options.resume, true); if (this.rt.agw.isReadOnly) throw new MarketError( 'READ_ONLY', @@ -631,27 +634,145 @@ export class MarketNamespaceImpl implements MarketNamespace { ); } const tx = await write(this.rt, call, options.progressHook, 'MARKET', true); + return this.openedResult(plan, tx); + } + private async openedResult( + plan: JobPlan, + tx: import('../orchestrator/orchestrator.types').UniversalTxResponse, + recover = false + ) { + try { + return await this.verifyOpening(plan, tx, recover); + } catch (cause) { + if (cause instanceof MarketError && cause.details?.['txHash']) + throw cause; + throw new MarketError( + 'OPEN_JOB_RECOVERY_REQUIRED', + 'The opening was submitted but could not be fully verified. Track this transaction and resume with the original plan before opening again.', + { txHash: tx.hash }, + cause + ); + } + } + private async verifyOpening( + plan: JobPlan, + tx: import('../orchestrator/orchestrator.types').UniversalTxResponse, + recover: boolean + ) { + const d = deployment(this.rt); + const gen = currentGeneration(this.rt.agw.network); const e = await eventArgs(this.rt, tx, d.marketplace, ABI, 'JobOpened'); + const [agent] = decodeAbiParameters( + [{ type: 'address' }], + plan.session.sessionValidatorInitData + ); + const expectedRules = permissionId({ + validator: gen.addresses.sessionValidator, + agent, + grantNonce: plan.intent.grantNonce, + }); if ( e['cardId'] !== plan.cardId || e['cardVersion'] !== plan.cardVersion || getAddress(e['agw'] as Address) !== plan.wallet || e['principal'] !== plan.job.principal || - getAddress(e['owner'] as Address) !== plan.intent.owner + getAddress(e['owner'] as Address) !== getAddress(plan.intent.owner) || + e['rulesId'] !== expectedRules || + getAddress(plan.session.sessionValidator) !== + getAddress(gen.addresses.sessionValidator) || + plan.intent.sessionHash !== keccak256(encodeSession(plan.session)) || + plan.intent.execCalldataHash !== keccak256(plan.calldata) ) throw new MarketError( 'RECEIPT_MISMATCH', 'The opened job does not match the signed plan.', { txHash: tx.hash } ); + const jobId = e['jobId'] as bigint; + const s = await snapshot(this.rt); + const [cardId, version, wallet, rules, job, owner] = await Promise.all([ + s.read(d.marketplace, ABI, 'cardOfJob', [jobId]), + s.read(d.marketplace, ABI, 'cardVersionOfJob', [jobId]), + s.read
    (d.marketplace, ABI, 'agwOfJob', [jobId]), + s.read(d.marketplace, ABI, 'rulesOfJob', [jobId]), + s.read<{ + client: Address; + provider: Address; + evaluator: Address; + hook: Address; + expiredAt: number; + description: Hex; + }>(d.kernel, KERNEL_READ_ABI, 'getJob', [jobId]), + s.read
    ( + gen.addresses.factory, + gen.contracts.abis.factory, + 'ownerOf', + [plan.wallet] + ), + ]); + const creation = decodeCreateJob(('0x' + plan.calldata.slice(106)) as Hex); + if ( + cardId !== plan.cardId || + version !== plan.cardVersion || + getAddress(wallet) !== getAddress(plan.wallet) || + rules !== expectedRules || + getAddress(owner) !== getAddress(plan.intent.owner) || + getAddress(job.client) !== getAddress(plan.wallet) || + getAddress(job.provider) !== getAddress(agent) || + getAddress(job.evaluator) !== getAddress(creation.evaluator) || + getAddress(job.hook) !== getAddress(creation.hook) || + job.expiredAt !== plan.job.expiredAt || + job.description !== plan.jobSpec.bytes + ) + throw new MarketError( + 'RECEIPT_MISMATCH', + 'The kernel, wallet and marketplace mappings do not match the opening.', + { txHash: tx.hash, jobId } + ); + if (recover) { + if (!this.rt.agw.reader.getTransaction) + throw new MarketError( + 'HISTORY_UNAVAILABLE', + 'This reader cannot load the submitted opening input.', + { txHash: tx.hash } + ); + const transaction = await this.rt.agw.reader.getTransaction({ + hash: tx.hash as Hex, + }); + const matched = embeddedCalls(transaction.input, ABI, 'openJob').some( + ([value]) => { + const p = value as { + cardId: bigint; + cardVersion: bigint; + job: MarketJobInputs; + intent: OwnerIntent; + session: JobPlan['session']; + }; + return ( + p.cardId === plan.cardId && + p.cardVersion === plan.cardVersion && + fp(p.job) === fp(plan.job) && + fp(p.intent) === fp(plan.intent) && + encodeSession(p.session) === encodeSession(plan.session) + ); + } + ); + if (!matched) + throw new MarketError( + 'RECEIPT_MISMATCH', + 'The submitted input does not contain this reviewed opening.', + { txHash: tx.hash, jobId } + ); + } return { - jobId: e['jobId'] as bigint, + jobId, wallet: getAddress(e['agw'] as Address), rulesId: e['rulesId'] as Hex, tx, }; } async deposit(jobId: bigint, options: MarketDepositOptions = {}) { + options = { ...options, resume: options.resume && [...options.resume] }; if (this.deposits.has(jobId)) throw new MarketError( 'DEPOSIT_IN_PROGRESS', @@ -728,6 +849,14 @@ export class MarketNamespaceImpl implements MarketNamespace { options: Parameters[1] ) { const d = deployment(this.rt); + card = { ...card }; + options = { ...options }; + const rules = encodeAgentCardRules(options.rules, { + chain: card.chain, + network: this.rt.agw.network, + }); + const template = encodeJobSpec(options.jobSpecTemplate); + const mutability = options.jobSpecTemplate.allowedMutability; const s = await snapshot(this.rt); if ( !card.jobType || @@ -777,8 +906,7 @@ export class MarketNamespaceImpl implements MarketNamespace { 'An existing card cannot change its execution chain.' ); } - if (options.jobSpecTemplate.allowedMutability !== 'NONE') - unavailable('Mutable marketplace criteria'); + if (mutability !== 'NONE') unavailable('Mutable marketplace criteria'); const token = await s.read
    ( d.kernel, JOB_KERNEL_ABI, @@ -789,11 +917,6 @@ export class MarketNamespaceImpl implements MarketNamespace { 'TOKEN_MISMATCH', 'This deployment accepts only the kernel payment token.' ); - const rules = encodeAgentCardRules(options.rules, { - chain: card.chain, - network: this.rt.agw.network, - }); - const template = encodeJobSpec(options.jobSpecTemplate); const { chain, ...input } = card; const jobType = /^0x[\da-f]{64}$/i.test(card.jobType) ? (card.jobType as Hex) @@ -817,6 +940,22 @@ export class MarketNamespaceImpl implements MarketNamespace { functionName: 'updateAgentCard', args: [cardId, c, rules, template], }); + if (this.rt.agw.reader.call) { + try { + await this.rt.agw.reader.call({ + to: d.marketplace, + data, + account: this.rt.agw.signerPushAccount(), + }); + } catch (cause) { + throw new MarketError( + 'CARD_SIMULATION_FAILED', + 'The card write failed contract simulation. No transaction was submitted.', + { contractError: stackError(cause) }, + cause + ); + } + } const tx = await write( this.rt, { target: d.marketplace, value: BigInt(0), data }, diff --git a/packages/core/src/lib/market/types.ts b/packages/core/src/lib/market/types.ts index 9e22ecfe..a181ee4a 100644 --- a/packages/core/src/lib/market/types.ts +++ b/packages/core/src/lib/market/types.ts @@ -91,6 +91,11 @@ export interface MarketPreviewOptions extends Omit { export interface MarketWriteOptions { progressHook?: StackProgressHook; } +export interface MarketOpenOptions extends MarketWriteOptions { + relay?: boolean; + /** Recover a submitted opening, without signing or sending again. Rehydrate a hash with trackTransaction. */ + resume?: UniversalTxResponse; +} export interface MarketDepositStep { /** PRINCIPAL_AND_FEE combines requirements when both use the same token. */ step: 'PRINCIPAL' | 'PROVIDER_FEE' | 'PRINCIPAL_AND_FEE' | 'PC'; @@ -128,7 +133,7 @@ export interface MarketNamespace { preview(cardId: bigint, options: MarketPreviewOptions): Promise; openJob( plan: JobPlan, - options?: MarketWriteOptions & { relay?: boolean } + options?: MarketOpenOptions ): Promise<{ jobId: bigint; wallet: Address; diff --git a/packages/core/src/lib/orchestrator/__tests__/push-chain-native-multicall.spec.ts b/packages/core/src/lib/orchestrator/__tests__/push-chain-native-multicall.spec.ts index c90d3082..10f6d4e4 100644 --- a/packages/core/src/lib/orchestrator/__tests__/push-chain-native-multicall.spec.ts +++ b/packages/core/src/lib/orchestrator/__tests__/push-chain-native-multicall.spec.ts @@ -303,4 +303,19 @@ describe('atomic-only native batches (AGW sender-preserving arrays)', () => { expect(pushClient.sendBatch7702).toHaveBeenCalledTimes(1); expect(pushClient.sendTransaction).not.toHaveBeenCalled(); }); + it.each([false, true])('retains a broadcast hash when confirmation fails (atomic=%s)', async atomic => { + const { ctx, pushClient } = await context(); + const cause = new Error('Receipt RPC unavailable'); + pushClient.publicClient.waitForTransactionReceipt.mockRejectedValueOnce(cause); + const error = await sendPushTx(ctx, atomic ? execute : directExecute, [], transformFn, atomic).catch(e => e); + expect(error).toMatchObject({ txHash: atomic ? HASH_2 : HASH_1, pendingTransactionHash: atomic ? HASH_2 : HASH_1, cause }); + expect(pushClient.sendBatch7702).toHaveBeenCalledTimes(atomic ? 1 : 0); + expect(pushClient.sendTransaction).toHaveBeenCalledTimes(atomic ? 0 : 1); + }); + it('cannot fall back after a native atomic broadcast, even if later code throws an unsupported-signing error', async () => { + const { ctx, pushClient } = await context(); + pushClient.publicClient.waitForTransactionReceipt.mockRejectedValueOnce(new EIP7702NotSupportedError()); + await expect(sendPushTx(ctx, execute, [], transformFn)).rejects.toMatchObject({ txHash: HASH_2, pendingTransactionHash: HASH_2 }); + expect(pushClient.sendTransaction).not.toHaveBeenCalled(); + }); }); diff --git a/packages/core/src/lib/orchestrator/internals/errors.ts b/packages/core/src/lib/orchestrator/internals/errors.ts index 871ddda3..9137b28c 100644 --- a/packages/core/src/lib/orchestrator/internals/errors.ts +++ b/packages/core/src/lib/orchestrator/internals/errors.ts @@ -31,8 +31,10 @@ export interface DecodedErrorPayload { * discriminator lets callers classify via `instanceof PushChainExecutionError` * instead of sniffing error messages. * - * Carries the origin-chain gateway tx hash. There is no successful Push Chain - * tx to reference on this path — by definition the pcTx committed `FAILED`. + * A failed universal execution can carry its origin-chain gateway hash. Native + * confirmation/indexing errors retain the submitted Push hash instead; those + * errors do not prove that the transaction reverted. Track a retained hash + * before retrying an operation with side effects. * * `decodedError`: optional structured payload that flows through to terminal * failure hook payloads (199-02 / 299-02 / 399-02 / 999-02). Set by the @@ -42,16 +44,21 @@ export interface DecodedErrorPayload { export class PushChainExecutionError extends Error { readonly code = 'PUSH_CHAIN_EXECUTION_FAILED' as const; readonly gatewayTxHash?: string; + /** Native Push transaction already broadcast before confirmation/indexing failed. */ + readonly txHash?: `0x${string}`; + readonly pendingTransactionHash?: `0x${string}`; readonly decodedError?: DecodedErrorPayload; /** Underlying transport/RPC error, kept so raw revert data is not lost. */ override readonly cause?: unknown; constructor( message: string, - opts: { gatewayTxHash?: string; decodedError?: DecodedErrorPayload; cause?: unknown } = {} + opts: { gatewayTxHash?: string; txHash?: `0x${string}`; pendingTransactionHash?: `0x${string}`; decodedError?: DecodedErrorPayload; cause?: unknown } = {} ) { super(normalizePublicErrorMessage(message)); this.name = 'PushChainExecutionError'; this.gatewayTxHash = opts.gatewayTxHash; + this.txHash = opts.txHash; + this.pendingTransactionHash = opts.pendingTransactionHash; this.decodedError = opts.decodedError; if (opts.cause !== undefined) this.cause = opts.cause; } @@ -68,7 +75,7 @@ export class AtomicBatchUnavailableError extends PushChainExecutionError { /** Recovery metadata for a non-atomic Push batch. A pending hash is broadcast but unconfirmed. */ export class PushChainBatchExecutionError extends PushChainExecutionError { readonly transactionHashes: `0x${string}`[]; - readonly pendingTransactionHash?: `0x${string}`; + override readonly pendingTransactionHash?: `0x${string}`; constructor(message: string, transactionHashes: `0x${string}`[], pendingTransactionHash?: `0x${string}`) { super(message); diff --git a/packages/core/src/lib/orchestrator/internals/push-chain-tx.ts b/packages/core/src/lib/orchestrator/internals/push-chain-tx.ts index 14005428..b8f7bc6e 100644 --- a/packages/core/src/lib/orchestrator/internals/push-chain-tx.ts +++ b/packages/core/src/lib/orchestrator/internals/push-chain-tx.ts @@ -76,7 +76,7 @@ async function getIndexedPushTransaction( receiptWaited = true; if (receipt.status === 'reverted') { throw new PushChainExecutionError( - `${label} — Push Chain transaction ${txHash} reverted` + `${label} — Push Chain transaction ${txHash} reverted`, { txHash } ); } } @@ -149,6 +149,7 @@ export async function sendPushTx( } } if (executor && ctx.universalSigner.signAuthorization) { + let submittedHash: `0x${string}` | undefined; try { printLog( ctx, @@ -159,6 +160,7 @@ export async function sendPushTx( calls, signer: ctx.universalSigner, }); + submittedHash = txHash; const txResponse = await getIndexedPushTransaction( ctx, txHash, @@ -166,6 +168,10 @@ export async function sendPushTx( ); return await transformFn(txResponse, eventBuffer); } catch (err) { + if (submittedHash) { + if (err instanceof PushChainExecutionError && err.txHash === submittedHash) throw err; + throw new PushChainExecutionError(normalizePublicErrorMessage(err), { txHash: submittedHash, pendingTransactionHash: submittedHash, cause: err }); + } // Only fall back when the wallet genuinely can't sign a 7702 // authorization. This is raised before any broadcast, so falling back // to sequential execution cannot double-execute. Any other error @@ -313,12 +319,17 @@ export async function sendPushTx( value: execute.value, signer: ctx.universalSigner, }); + try { const txResponse = await getIndexedPushTransaction( ctx, txHash, 'sendPushTx' ); return await transformFn(txResponse, eventBuffer); + } catch (cause) { + if (cause instanceof PushChainExecutionError && cause.txHash === txHash) throw cause; + throw new PushChainExecutionError(normalizePublicErrorMessage(cause), { txHash, pendingTransactionHash: txHash, cause }); + } } // ============================================================================ diff --git a/packages/core/src/lib/push-chain/push-chain.ts b/packages/core/src/lib/push-chain/push-chain.ts index 9b35f44a..4fe93214 100644 --- a/packages/core/src/lib/push-chain/push-chain.ts +++ b/packages/core/src/lib/push-chain/push-chain.ts @@ -61,7 +61,8 @@ import type { MarketNamespace } from '../market/types'; import type { JobNamespace } from '../job/types'; import type { StackRuntime } from '../market/runtime'; import { bindJobPreviewAccounts } from '../job-spec/preview'; -import { prepareJobRead } from '../job-spec/read'; +import { jobReadOptions, prepareJobRead } from '../job-spec/read'; +import type { ExecuteJobReadOptions, PreparedJobRead } from '../job-spec/types'; /** Options accepted by `PushChain.initialize` / `reinitialize`. */ export interface PushChainInitializeOptions { @@ -201,7 +202,8 @@ export class PushChain { * Defaults to the canonical registry on Donut. For your own application receiver, * pass callback.target, gasLimit, abi and functionName, plus an optional args mapper. */ - read: ((subject: string, options: O & ValidateReadCall) => Promise>>) & { prepare: typeof prepareJobRead }; + read: ((subject: string, options: O & ValidateReadCall) => Promise>>) & + ((read: PreparedJobRead, options?: ExecuteJobReadOptions) => Promise>) & { prepare: typeof prepareJobRead }; /** * Build a validated `ReadSpec` for `subject` on `options.chain`: preflight (oracle * height, protocol fee, gas price), envelope encoding, budget sizing, expiry math. @@ -431,14 +433,16 @@ export class PushChain { return orchestrator.rescueFunds.bind(orchestrator)(params); }, // Only read()/executeReads() send transactions; prepare/simulate/track remain read-only. - read: Object.assign(async (subject: string, options: O) => { - const params = await resolveReadSpecParams(subject, withReadRefund(options), orchestrator.getNetwork(), orchestrator.getRpcUrls()); + read: Object.assign(async (subject: string | PreparedJobRead, input?: ReadOptions | ExecuteJobReadOptions) => { + const options = typeof subject === 'string' ? input as ReadOptions : jobReadOptions(subject, input as ExecuteJobReadOptions); + const target = typeof subject === 'string' ? subject : subject.target; + const params = await resolveReadSpecParams(target, withReadRefund(options), orchestrator.getNetwork(), orchestrator.getRpcUrls()); assertRequestEntrypoint(params.callback, 'read'); if (this.isReadMode) throw new Error('Read only mode cannot call read function'); const prepared = await orchestrator.prepareRead(params, options.progressHook); const { reads: [response] } = await executePreparedReads(readDeps(), [prepared] as const, options); - return response as UniversalReadResponse>; - }, { prepare: prepareJobRead }), + return response; + }, { prepare: prepareJobRead }) as PushChain['universal']['read'], prepareRead: async (subject: string, options: O & ValidateReadCall) => { const params = await resolveReadSpecParams(subject, withReadRefund(options), orchestrator.getNetwork(), orchestrator.getRpcUrls()); return orchestrator.prepareRead(params) as Promise>>; diff --git a/packages/core/src/lib/read-state/__tests__/read-types.spec.ts b/packages/core/src/lib/read-state/__tests__/read-types.spec.ts index 17f2d928..726ae72f 100644 --- a/packages/core/src/lib/read-state/__tests__/read-types.spec.ts +++ b/packages/core/src/lib/read-state/__tests__/read-types.spec.ts @@ -26,6 +26,9 @@ declare const counterIdl: CounterIdl; // Compiled by ts-jest; never executed or connected to a network. async function checkTypes(client: PushChain) { + const authored = client.universal.read.prepare({ chain: CHAIN.ETHEREUM_SEPOLIA, target: address, abi, functionName: 'balanceOf', args: [address] }); + const authoredResult: UniversalReadResponse<`0x${string}`> = await client.universal.read(authored, { maxFee: 100n }); + void authoredResult; const raw: UniversalReadResponse<`0x${string}`> = await client.universal.read(address, { chain: CHAIN.ETHEREUM_SEPOLIA, callData: '0x18160ddd' }); // @ts-expect-error raw calls and typed calls are mutually exclusive const mixedRaw: ReadOptions = { chain: CHAIN.ETHEREUM_SEPOLIA, callData: '0x18160ddd', abi, functionName: 'quote' }; diff --git a/plan/SDK-CHANGELOG.md b/plan/SDK-CHANGELOG.md index b2120fcc..c74c31a1 100644 --- a/plan/SDK-CHANGELOG.md +++ b/plan/SDK-CHANGELOG.md @@ -4,6 +4,14 @@ Running history for work continued on `feat/agw-sdk-v4`, covering AGW, marketpla For each meaningful checkpoint, add a dated entry with the change, decisions, validation, remaining work and relevant commit/evidence links. Keep earlier entries as history and mark superseded decisions explicitly. Distinguish implemented code, planning, local/fork checks, funded execution, Git delivery and package publication. Git history for this file records the exact commit introducing each checkpoint. +## 2026-10-20 — SDK-only completion before contract/deployment handoff + +**Implemented:** opening proof and mined-input recovery without re-signing; immutable reviewed inputs; event-hash/transaction-input recovery for same-block and archive-less card history; resumable paid previews with zero new payment, direct prepared-read sending and ABI-name/decimal descriptions; exact watcher cursors, deduplication, callback isolation and canonical-cursor reorg stop; provider write simulation. Native single/atomic sends now preserve broadcast hashes after receipt/index failures and cannot fall back after broadcast. Signature fixtures compile from repo-owned source; the CI reporter derives success from final counts instead of Jest's pre-final flag. + +**Validation:** 2,246 units pass (12 existing skips), 11 real-stack fork cases, six live cases across serial basic/funding runs. Real principal and BSC-origin bridging, native/AGW atomic pUSDC escrow, provider submission and controlled manual-evaluator payouts pass. Cards 4/5 are inactive; market jobs 4/7/8/9 are Rejected with grants revoked, plain jobs 5/6 Completed, and deposited/reserve/payout tokens returned. Real local ERC-1271/7702 variants and same-block history pass. Build/types, production lint, package/API checks and eight guide blocks pass. [Evidence and limits](marketplace/research/sdk-independent-2026-10-20/README.md). + +**Boundary:** [SDK-only checklist complete](marketplace/sdk-readiness.md). Current team dependencies are the three CEA rollout mismatches and a compatible automatic evaluator/shared schema/verify ABI. Older SDK placeholders and acceptance gaps above are superseded. Future product scope and package publication remain separate; no marketplace, hook, kernel or evaluator was deployed/upgraded. No team messages were sent. + ## 2026-10-20 — deposits, paid preview and external EVM owners **Implemented:** `market.deposit` recovers the opened card version and principal, combines shared-token requirements, tops up principal/fee/PC separately and retains receipts/pending hashes for recovery. Explicit registered-origin funding is available. Deployed v2 grants pinned approvals to the agent; deposit performs no retired owner-approval step. Paid `previewJobSpec` uses raw universal reads, total request-fee caps, ABI layout decoding, configured CEA resolution and unknown-aware logic/baselines. Opening checks the actual EIP-712 domain and simulates the complete signed request before broadcast; deployed external EVM UEAs are supported. diff --git a/plan/marketplace/README.md b/plan/marketplace/README.md index e5cc84e1..a00c27b8 100644 --- a/plan/marketplace/README.md +++ b/plan/marketplace/README.md @@ -1,6 +1,6 @@ # Agentic marketplace SDK planning -Updated October 20, 2026. **28 of the 29 named SDK APIs now have implementations against deployed v2:** see [current coverage and acceptance](implementation-status.md). Deposits, paid previews and external EVM UEA opening are implemented; `job.verify` awaits compatible contracts. The initial contract-only research below is preserved as history. No package was published. +Updated October 20, 2026. **SDK-only work is complete for the current EVM v2 scope:** see [readiness and external boundaries](sdk-readiness.md) and [coverage/acceptance](implementation-status.md). 28 of the 29 named APIs are implemented; `job.verify` awaits compatible contracts. Real token deposits, origin bridging and native/AGW payouts pass live. The initial contract-only research below remains history. No package was published. **Build against deployed UniversalMarketplace v2, pinned at `sdk-iteration-v1@443b4e2dd9ca5dd9ffc8efebdfcecd619dd66c47`.** The six supplied Notion pages were exported again through signed-in Chrome, and their visible discussion panels were reviewed. The older marketplace pages in `plan/agw/notion` remain historical. diff --git a/plan/marketplace/implementation-status.md b/plan/marketplace/implementation-status.md index ef276ec1..bb807cde 100644 --- a/plan/marketplace/implementation-status.md +++ b/plan/marketplace/implementation-status.md @@ -1,25 +1,25 @@ # Marketplace SDK implementation status -October 20, 2026 — deposit, preview and external-owner checkpoint on `feat/agw-sdk-v4`. This supersedes the first checkpoint's deposit/paid-preview/external-EVM placeholders. No package was published. +October 20, 2026 — SDK-only completion checkpoint on `feat/agw-sdk-v4`. [Completed SDK checklist and external boundary](sdk-readiness.md). No package was published. ## Coverage against SDK pages 6 and 7 | Documented API group | Implemented | Pending | | --- | --- | --- | -| Marketplace user APIs | 7 / 7 | Broader route acceptance; three CEA rollout mismatches below | +| Marketplace user APIs | 7 / 7 | No scoped SDK implementation item; three external CEA rollout mismatches below | | Provider/card management | 4 / 4 | No additional method placeholder | -| JobSpec/card-rule helpers | 9 / 9 | Additional paid-read/source/output acceptance remains useful | +| JobSpec/card-rule helpers | 9 / 9 | No scoped SDK implementation item | | Kernel job APIs | 8 / 9 | `job.verify`: compatible evaluator/hook and canonical wire | | **Named API entrypoints** | **28 / 29** | **1 contract-dependent placeholder** | -This is API coverage, not a release-readiness percentage or a claim that every draft option is implemented. It follows deployed v2 where the draft differs (pinned agent approvals, immutable criteria, pUSDC). `job.cancel`, pure read preparation and constants are additional delivered surfaces. Evaluation facts in `status` remain explicitly unavailable. Full live principal/escrow/protocol execution and arbitrary contract-wallet acceptance are separate validation work. +This is API coverage, not a claim that every future draft option is implemented. It follows deployed v2 where the draft differs (pinned agent approvals, immutable criteria, pUSDC). `job.cancel`, pure read preparation and constants are additional delivered surfaces. SDK-only implementation and acceptance within this boundary are complete. Evaluation facts in `status` remain unavailable until compatible contracts exist. Live principal/escrow/payout and origin bridging now pass; reference contract/delegated-wallet acceptance passes against real local contracts. Custom wallet vendors provide their own signer transport. ## Implemented -- `client.market`: card discovery/reads; provider register/update/setActive/card; independently checked CEA and JobSpec preview; simulation-backed OwnerIntent signing/open for native EOAs and deployed external EVM UEAs; job mappings and active-wallet reads. -- `client.market.deposit`: original opening event/card-version recovery, principal/fee/PC balance targets, combined shared-token requirements, explicit registered-origin funding, confirmed step receipts and incomplete-deposit recovery. Broadcast errors retain pending hashes and stop automatic retry. No retired owner-approval array or escrow acceptance is inferred. -- `client.job`: plain create; provider pricing; explicit-budget acceptance, balances/allowances and atomic AGW funding; submit; status/list/watch; client cancel with recorded marketplace permission revocation; expiry/grace refunds, including while paused. -- `PushChain.utils.job`: pure EVM read authoring, complete/template builders, canonical v2 codecs and descriptions; paid `previewJobSpec` through universal reads, fee cap, output-layout decoding and three-state logic. Missing baselines/reads remain unknown. `client.universal.read.prepare` exposes the same pure authoring adapter; async prepareRead/read now also accept explicit raw EVM calldata. +- `client.market`: card discovery/reads; simulated provider register/update; activation/card; independent CEA and JobSpec preview; simulation-backed OwnerIntent signing/open for native EOAs, deployed external EVM UEAs and reference ERC-1271/7702 owners; mined-input receipt recovery without re-signing, complete event/kernel/wallet/mapping proof; job mappings and active-wallet reads. Inputs are copied before asynchronous work. +- `client.market.deposit`: original opening/card-version recovery, including archive-less/same-block recovery bound to event hashes and transaction input; principal/fee/PC balance targets; combined shared-token requirements; explicit origin funding; confirmed receipts and incomplete-deposit recovery. Broadcast errors retain pending hashes and stop automatic retry. No retired owner-approval array or escrow acceptance is inferred. +- `client.job`: plain create; provider pricing; reviewed-budget acceptance, balances/allowances and native/AGW atomic funding; submit; status/list/watch with exact cursor, deduplication, retry, callback isolation and reorg stop; client cancel with recorded grant revocation; expiry/grace refunds, including while paused. +- `PushChain.utils.job`: pure authoring, builders, canonical v2 codecs, ABI-name/decimal descriptions; paid `previewJobSpec`, fee caps, nested decoding and three-state logic; authenticated request-ID resumption without new payment. Missing baselines/reads remain unknown. `client.universal.read.prepare` exposes the same pure adapter; resolved prepared objects can be sent directly. Raw EVM calldata is also supported. - `PushChain.utils.market`: deployed four-field card rules, principal/wallet markers and pinned approvals. Destination-token resolution always uses the explicit card chain, including same-address native-token objects. Decoded unknown PRC20s remain explicit references. Unchanged legacy wire metadata is preserved; archive raw bytes for persistence. - `AGENTIC.PRINCIPAL` and `AGENTIC.JOB` vocabulary/address table; public types/errors; source and compiled consumer guide checks. The API checker now canonicalizes equivalent string-literal quote syntax in emitted property names. @@ -31,13 +31,13 @@ Registry summaries do not decode an unverified provider's template. A malformed | Surface | Current behavior / next requirement | | --- | --- | -| Deposit acceptance limits | Open/unexpired and unused enabled permission; available historical state required. Same-block version ambiguity fails closed. PC target is not a whole-job quote. Registered origin funding is unit-tested; live principal/inbound-bridge acceptance is still pending. | +| Deposit execution boundary | Open/unexpired and unused enabled permission; authenticated state/event/input history required. PC target is not a whole-job quote. Live principal and BSC-origin inbound bridging pass; independent concurrent funding clients must coordinate. | | Automatic evaluator / job.verify | Explicit capability error. Current evaluator is manual; the linked evaluator has a different ABI/wire. No baseline, frozen-spec or verdict data is invented. | | Replacement criteria / non-NONE cards | Refused before writes. Expected-spec-hash acceptance must be delivered with compatible contracts before mutable negotiation. | -| Contract/delegated owners | Full signed-request simulation uses the actual verifier. External EVM UEA transport passes live; arbitrary ERC-1271 adapters need their own acceptance. Delegates without a compatible verifier fail simulation after signing, before broadcast. Undeployed external UEAs and missing typed signing fail before prompting. | +| Contract/delegated owners | Real reference ERC-1271 and compatible/incompatible 7702 acceptance passes; external EVM UEA transport passes live. Custom vendors supply their own signer transport. Incompatible signatures fail simulation before broadcast; undeployed external UEAs/missing typed signing fail before prompting. | | Relayer, recurring jobs, ratings, non-EVM cards/evaluation | No successful placeholder or invented service. Remain outside this checkpoint. | -`job.cancel` revokes only the permission recorded for that marketplace job, using the current owner's existing AGW authority. Provider/evaluator terminal actions do not acquire owner cleanup authority. Plain jobs have no marketplace permission to infer. Funded job completion/payout is tested with manual evaluator action only on an isolated fork. +`job.cancel` revokes only the permission recorded for that marketplace job. It does not withdraw wallet deposits. Provider/evaluator terminal actions do not acquire owner cleanup authority. Plain jobs have no marketplace permission to infer. Nonzero live completion/payout uses fresh controlled evaluators on plain jobs; the marketplace's configured evaluator is unchanged. Native single/atomic broadcast failures retain their hashes, and an atomic broadcast can never trigger sequential fallback. ## Destination rollout mismatch @@ -54,9 +54,9 @@ Both old/new factories in the first three chains answer and name the same gatewa ## Acceptance -- **2,228 unit tests pass**, 12 existing skips; 23 cases added after the first checkpoint. -- **8 real-stack fork E2Es pass**: existing lifecycle plus historical deposits/reconnection and a real EVM UEA signature. Actual principal/pUSDC and escrow/payout use fork-only borrowed assets. The UEA signature case uses a native submitting transport on Anvil; no Cosmos transport is mocked as successful. -- **3 funded live cases pass**: native register/open/cancel/revoke, paid validator-consensus preview, and actual external EVM UEA open/cancel. Card 3 is inactive; jobs 2/3 are Rejected and both permissions are revoked. PC funds gas/wallet setup/read callback; principal and escrow tokens are not moved live. The first checkpoint's two read-only cases remain prior evidence. -- Build, library/spec/local typechecks, compiled imports/declarations/package checks and source-versus-built API comparison pass; the new production modules lint without warnings. The consumer guide's six TS blocks typecheck. +- **2,246 unit tests pass**, 12 existing skips; 18 cases added after the prior checkpoint. +- **11 real-stack fork E2Es pass**, adding valid/malformed ERC-1271, 7702 and same-block opening/history recovery. Fixtures compile from repo-owned source without another contract checkout. The fork's UEA submitting transport is native because Anvil has no Cosmos transport. +- **6 live cases pass across two serial runs**: three basic cases cover native/external open/cancel, receipt recovery, prepared paid reads and no-new-payment preview recovery; three funding cases cover actual deposits, native/AGW atomic escrow and manual-evaluator payouts, and BSC-origin principal bridging. Cards 4/5 are inactive; jobs 4/7/8/9 are Rejected with grants revoked and plain jobs 5/6 are Completed. Deposited/reserve/payout tokens are returned. Earlier read-only evidence remains separate. +- Build, library/spec/local types, compiled imports/declarations/package checks and source/built API comparison pass; changed production lint passes. The consumer guide's eight TS blocks typecheck. CI reporting now derives final success from completion counts while preserving the original Jest flag. -[Current validation and limits](research/sdk-completion-2026-10-20/README.md), [first checkpoint](research/sdk-implementation-2026-10-20/README.md). E2E groups `marketplace` and `marketplace-live` are opt-in; default all selection is unchanged. Future checkpoints should append to the [running changelog](../SDK-CHANGELOG.md). +[Current validation and limits](research/sdk-independent-2026-10-20/README.md), [prior checkpoint](research/sdk-completion-2026-10-20/README.md), [first checkpoint](research/sdk-implementation-2026-10-20/README.md). All marketplace groups, including `marketplace-funding`, remain opt-in; default all selection is unchanged. Future checkpoints should append to the [running changelog](../SDK-CHANGELOG.md). diff --git a/plan/marketplace/questions.md b/plan/marketplace/questions.md index 05ab96fd..85aab4cd 100644 --- a/plan/marketplace/questions.md +++ b/plan/marketplace/questions.md @@ -1,6 +1,11 @@ # Questions to share — drafts, not posted -**Implementation update:** the user authorized implementation with explicit placeholders. Deployed-v2 approvals, client cancel/revoke, expected-budget acceptance, historical deposits and paid preview are implemented. External EVM UEA open/cancel passes live; complete signed-request simulation checks the real verifier before broadcast. Arbitrary ERC-1271 adapters still need acceptance, and incompatible delegates fail simulation. The remaining placeholder is evaluator integration. Historical proposals below remain useful context. The immediate rollout question is CEA configuration: SDK and marketplace factories differ on Sepolia/Base Sepolia/Arbitrum Sepolia, while BSC matches and passes live. [Addresses and read-only evidence](implementation-status.md#destination-rollout-mismatch). Which route/deployment manifest is canonical, and which configuration should be aligned? Global routing constants were not changed to bypass the guard. +**SDK-only implementation and acceptance are complete for the current EVM v2 scope.** This includes real ERC-1271/7702 fixtures, receipt and same-block history recovery, paid-read resumption, watcher cursors, live origin bridging, principal deposits, atomic escrow and manual-evaluator payouts. No question or comment has been posted. See [SDK readiness](sdk-readiness.md) before sharing anything below. + +## Current team dependencies — only these need answers now + +1. **Canonical CEA deployment on Sepolia, Base Sepolia and Arbitrum Sepolia:** which factory/implementation manifests should the live routing stack and marketplace both use? [Exact differences and evidence](implementation-status.md#destination-rollout-mismatch). Both factories answer but derive different accounts. BSC matches and passes live. The SDK retains its independent derivation check; global routing addresses were not changed to force a match. +2. **Automatic evaluation:** which shared JobSpec package/commit, compatible hook/evaluator deployment, and public verify/retry ABI are authoritative? Current v2 and the linked evaluator differ in field order, enums, reads, checks and logic. The SDK has no safe automatic endpoint to invoke until that contract boundary is delivered. Details below. Prepared October 20 after fresh Notion discussions, pinned source review, unfunded tests and Donut read-only checks. Lead with the concrete mismatch and proposal; do not resend historical questions already answered below. @@ -8,23 +13,31 @@ Prepared October 20 after fresh Notion discussions, pinned source review, unfund **Which exact shared JobSpec package/commit should the SDK target for the next compatible marketplace + hook + evaluator deployment?** Deployed marketplace v2 `443b4e2` uses `(reads,checks,logic,allowedMutability,origin,executeBy,failFinalAt)`, direct check indices, and NONE=0. Nilesh's [October 16 linked source](https://github.com/pushchain/push-chain-core-contracts/blob/8059817591cca16c59f1cc154f475f51e1736a67/src/agentic-commerce-8183/libraries/JobSpecTypes.sol) uses timing first, PRE/POST reads, left/right sums, CHECK leaves, and NONE=1/BOTH=0. Controlled vectors are incompatible. Proposal: build the current v2/manual-evaluator SDK profile now; coordinate one shared schema and deployment change before automated evaluation, without an SDK-only translation of signed bytes. -## Harsh + Zaryab: public approvals and deposit shape +## Historical — public approvals and deposit shape + +Implemented against deployed v2. This is documentation alignment, not a remaining SDK blocker. **Should the SDK now follow deployed v2 D1 and remove `rules.approvals[]`, `skipApprovals`, and owner-approval deposit steps from page 6?** V2 permits agent `approve` with a pinned nonzero spender and capped amount and has no approvals array. Page 6 still rejects approve and exposes the old fields. Proposal: retain pinned approvals as allowedCalls and make deposit about principal/fee/PC, with explicit execution prerequisites. This confirms the public contract rather than asking for a feature already delivered. -## Harsh: M4 in the first release +## Deferred product scope — M4 in the first release **Can marketplace authoring require `allowedMutability: NONE` for the initial release, leaving other enum values representable but unsupported until the proposal/acceptance protocol is delivered?** Current hook ignores replacements; non-NONE flags are accepted but inert. A future mutable flow needs the client's exact expectedSpecHash/revision checked atomically at fund alongside budget. SDK rereads cannot close the same-price front-run. If mutability is required now, define the authenticated CLIENT/BOTH route and versioned fund payload with the evaluator team first. -## Harsh + Zaryab: cancel surface and permission cleanup +## Historical — cancel surface and permission cleanup + +Client cancel/revoke is implemented and accepted locally/live. Automatic provider/evaluator cleanup needs a contract authority design only if that later feature is requested. **Add `client.job.cancel` for an Open job, and should the AGW owner path atomically reject + revoke that job's permission?** The kernel already permits client reject; the SDK draft omits the method after removing evaluatorOnly.reject. Real-v6 fork proof shows cancel alone frees the marketplace slot but old permissions remain enabled after a new job opens. A single existing owner batch rejects and revokes successfully, with no new AGW role. Provider/evaluator-driven automatic cleanup remains a separate contract design; confirm that boundary and the expected behavior for terminal jobs. -## Harsh: accepted price +## Historical — accepted price + +Explicit reviewed budgets are implemented; the client does not silently accept a re-quote. **For the first marketplace release, is funding fixed to the opened card version's reviewed providerFee, or may a user explicitly accept a different provider quote?** Page 7 alternates between passing the card price and reading the latest stored budget. Contract test proves a job can fund at 3× card fee if the client supplies that expectedBudget. Proposal: never silently adopt the latest price; fixed-price flow uses the opened version, negotiation requires an explicit reviewed quote/expected amount. -## Harsh: pure read-authoring interface +## Historical — pure read-authoring interface + +Implemented: additive pure preparation, direct sending of resolved prepared reads and paid JobSpec preview/resumption. **Confirm an additive pure `client.universal.read.prepare` authoring API alongside existing async `universal.prepareRead(subject, options)`, or choose an adapter over that existing surface.** Current prepareRead produces paid-request/preflight data and does network reads; the page needs synchronous logical reads with output-layout codes and preserved WALLET/PARAM metadata. These are different representations. Proposal: share parsing/ABI encoding while retaining existing read APIs and introducing a distinct typed authoring representation. diff --git a/plan/marketplace/research/sdk-independent-2026-10-20/README.md b/plan/marketplace/research/sdk-independent-2026-10-20/README.md new file mode 100644 index 00000000..b31750b8 --- /dev/null +++ b/plan/marketplace/research/sdk-independent-2026-10-20/README.md @@ -0,0 +1,54 @@ +# Independent SDK completion — October 20 + +Follow-up to `fdfcd460`, on `feat/agw-sdk-v4`. Source/deployment targets remain UniversalMarketplace v2 `443b4e2` and AGW v6 `ffd567d`. [Completed checklist and external boundaries](../../sdk-readiness.md), [consumer guide](../../../../packages/core/MARKETPLACE.md). + +## Final acceptance + +| Check | Result / evidence | +| --- | --- | +| Full units | 2,246 passed, 12 existing skips, zero failures; [compressed raw Jest output](unit-results.json.gz) | +| Real-contract fork | 11 passed, zero failures; [Jest output](fork-results.json) | +| Basic live run | 3 passed, zero failures/skips, process exit 0; [report](live-results.json), [transactions/read requests](live-evidence.json) | +| Owned-token live funding run | 3 passed, zero failures/skips, process exit 0; [report](funding-results.json), [transactions](funding-evidence.json) | +| Cleanup | Cards 4/5 inactive; market jobs 4/7/8/9 Rejected with grants disabled; plain jobs 5/6 Completed; all six clients have zero principal/payment token balances; [read-only post-state](post-live-state.json) | +| Build/types/docs/package | Build, library/spec/fork types, eight guide TS blocks, compiled CJS/ESM imports, declarations and npm dry-run contents pass | +| API | Source/compiled surfaces match; [compressed report](api-comparison.json.gz). Its baseline includes earlier SDK changes. | +| Lint | New marketplace/job modules pass with zero warnings; native transport retains its 13 baseline warnings, with no new diagnostic. [Summary](validation-summary.json) | + +The 18 added unit cases cover history authentication, watcher delivery/recovery, descriptions, prepared-read sending, paid-preview recovery/mismatch rejection, CI completion reporting, opening receipt errors and native broadcast-hash preservation. Native atomic confirmation failures cannot fall back to sequential execution after broadcast. + +The real-contract fork adds a valid ERC-1271 owner through a public UniversalSigner adapter, invalid magic/trailing-data/short returns, compatible and echo-only 7702 delegates, and same-block opening/card-update history. The self-contained fixture builds from repository source using cached solc 0.8.26; it needs no sibling contract checkout or live deployment. The existing fork lifecycle still covers escrow/payout, price/version drift, binary descriptions, paused refunds, permissions and cancellation. Its external UEA signature uses a native submitting transport because Anvil has no Cosmos transport; actual external-owner transport is tested live. + +The basic live run covers native and external UEA opening/cancellation, receipt recovery, paid validator-consensus preview, sending a pure prepared read and authenticated request-ID recovery with zero new payment. The CI reporter now derives success from final counts and preserves Jest's pre-final `success` flag separately. + +The funding run uses assets owned by the configured master, without public impersonation: actual principal/fee/PC deposits; 0.01 pUSDC escrow/payout per native/AGW plain job; 0.01 USDT bridged from a fresh BSC origin; and up to 0.01 pBNB for BSC source-gas setup. A fresh controlled evaluator completes the plain jobs. The marketplace evaluator is unchanged. Principal, reserve and payout tokens are returned; bounded PC/BNB funds test gas. Cleanup is independently checked on-chain. + +## Earlier failure and correction + +An earlier local acceptance run passed ten cases but timed out reading the ERC-1271 adapter's submitted transaction receipt. [Raw earlier report](fork-before-confirmation-fix.json.gz). The local adapter now waits for explicit Anvil confirmation mining before returning its hash. The audit also exposed missing recovery metadata in shared native single/atomic transport: those errors now retain broadcast hashes, and a typed unsupported-signing error after broadcast cannot cause sequential fallback. Regression cases and the final full unit/fork runs pass. This is not a claim that every intermediate attempt passed. + +The live runs precede the final native error-only recovery guard; that guard is covered by the final unit and fork runs. Its successful transaction path is unchanged. + +The funding run completed before the reporter correction and retains its original `success: false` sampling discrepancy despite three passed tests and process exit 0. The later basic live report has `success: true` and `jestReportedSuccess: false`, exercising the corrected counter-based reporting. Raw reports are unchanged. + +## Remaining boundary + +There is no SDK-only implementation or acceptance item left in the current EVM v2 checklist. The contract/deployment dependencies are (1) aligned CEA manifests on three destinations and (2) a compatible automatic evaluator/hook/shared schema with a public verify/retry ABI. No automatic verdict, marketplace-evaluator impersonation, mainnet rollout, new marketplace/kernel/hook/evaluator deployment or npm publication is claimed. Deferred product features remain outside this boundary. + +## Reproduction + +```sh +node node_modules/jest/bin/jest.js --config packages/core/jest.config.ts --runInBand --silent +node node_modules/jest/bin/jest.js --config packages/core/jest.marketplace-local.config.ts --runInBand +node node_modules/ts-node/dist/bin.js --compiler-options '{"module":"commonjs"}' packages/core/__e2e__/ci/run.ts --group marketplace-funding --verify +node node_modules/ts-node/dist/bin.js --compiler-options '{"module":"commonjs"}' packages/core/__e2e__/ci/run.ts --group marketplace-funding +node node_modules/ts-node/dist/bin.js --compiler-options '{"module":"commonjs"}' packages/core/__e2e__/ci/run.ts --group marketplace-live +NX_DAEMON=false node node_modules/nx/bin/nx.js run core:build --skip-nx-cache +node node_modules/typescript/bin/tsc -p packages/core/tsconfig.spec.json --noEmit +node node_modules/typescript/bin/tsc -p packages/core/tsconfig.marketplace-local.json --noEmit +node packages/core/scripts/check-agw-docs.js packages/core/MARKETPLACE.md +node packages/core/scripts/check-agw-package.js +node packages/core/scripts/check-agw-api.js --output /tmp/marketplace-api.json +``` + +Run funded groups serially: they share the configured master for setup and gas. All marketplace groups remain excluded from default `all`; funding acceptance is explicit. [Checked source hashes](checked-files.json) and retained-result checksums are recorded with the validation summary. diff --git a/plan/marketplace/research/sdk-independent-2026-10-20/api-comparison.json.gz b/plan/marketplace/research/sdk-independent-2026-10-20/api-comparison.json.gz new file mode 100644 index 0000000000000000000000000000000000000000..b6132efac1740a42d97609b458431112f63e67c9 GIT binary patch literal 52200 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 literal 0 HcmV?d00001 diff --git a/plan/marketplace/research/sdk-independent-2026-10-20/fork-results.json b/plan/marketplace/research/sdk-independent-2026-10-20/fork-results.json new file mode 100644 index 00000000..ab891137 --- /dev/null +++ b/plan/marketplace/research/sdk-independent-2026-10-20/fork-results.json @@ -0,0 +1 @@ +{"numFailedTestSuites":0,"numFailedTests":0,"numPassedTestSuites":1,"numPassedTests":11,"numPendingTestSuites":0,"numPendingTests":0,"numRuntimeErrorTestSuites":0,"numTodoTests":0,"numTotalTestSuites":1,"numTotalTests":11,"openHandles":[],"snapshot":{"added":0,"didUpdate":false,"failure":false,"filesAdded":0,"filesRemoved":0,"filesRemovedList":[],"filesUnmatched":0,"filesUpdated":0,"matched":0,"total":0,"unchecked":0,"uncheckedKeysByFile":[],"unmatched":0,"updated":0},"startTime":1792502503903,"success":true,"testResults":[{"assertionResults":[{"ancestorTitles":[],"duration":35353,"failureDetails":[],"failureMessages":[],"fullName":"registers and discovers a real v2 provider card through the public namespace","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"registers and discovers a real v2 provider card through the public namespace"},{"ancestorTitles":[],"duration":36365,"failureDetails":[],"failureMessages":[],"fullName":"previews and signs the exact on-chain JobSpec, opens on real AGW v6, and preserves binary bytes","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"previews and signs the exact on-chain JobSpec, opens on real AGW v6, and preserves binary bytes"},{"ancestorTitles":[],"duration":40,"failureDetails":[],"failureMessages":[],"fullName":"updates a decoded card without losing rule constraints or template wire bytes","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"updates a decoded card without losing rule constraints or template wire bytes"},{"ancestorTitles":[],"duration":7814,"failureDetails":[],"failureMessages":[],"fullName":"deposits original principal, fee and PC after a card update and recovers history in a fresh client","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"deposits original principal, fee and PC after a card update and recovers history in a fresh client"},{"ancestorTitles":[],"duration":3265,"failureDetails":[],"failureMessages":[],"fullName":"funds through the real rules hook and submits as the provider; manual evaluator completes locally","invocations":1,"location":null,"numPassingAsserts":10,"retryReasons":[],"status":"passed","title":"funds through the real rules hook and submits as the provider; manual evaluator completes locally"},{"ancestorTitles":[],"duration":3476,"failureDetails":[],"failureMessages":[],"fullName":"creates a plain job and allows third-party refund while the kernel is paused","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"creates a plain job and allows third-party refund while the kernel is paused"},{"ancestorTitles":[],"duration":31595,"failureDetails":[],"failureMessages":[],"fullName":"rejects a tampered plan before signing and atomically cancels a second job with permission revocation","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"rejects a tampered plan before signing and atomically cancels a second job with permission revocation"},{"ancestorTitles":[],"duration":32846,"failureDetails":[],"failureMessages":[],"fullName":"accepts a real deployed EVM UEA owner signature with its home-chain domain","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"accepts a real deployed EVM UEA owner signature with its home-chain domain"},{"ancestorTitles":[],"duration":31781,"failureDetails":[],"failureMessages":[],"fullName":"uses a real ERC-1271 owner adapter, rejects malformed success values, and recovers without a second signature","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"uses a real ERC-1271 owner adapter, rejects malformed success values, and recovers without a second signature"},{"ancestorTitles":[],"duration":32758,"failureDetails":[],"failureMessages":[],"fullName":"accepts a compatible EIP-7702 verifier and refuses an echo fallback before broadcast","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"accepts a compatible EIP-7702 verifier and refuses an echo fallback before broadcast"},{"ancestorTitles":[],"duration":66957,"failureDetails":[],"failureMessages":[],"fullName":"recovers the original card and opening when a provider updates in the same mined block","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"recovers the original card and opening when a provider updates in the same mined block"}],"endTime":1792502793438,"message":"","name":"/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/packages/core/__market-local__/marketplace.spec.ts","startTime":1792502503921,"status":"passed","summary":""}],"wasInterrupted":false} diff --git a/plan/marketplace/research/sdk-independent-2026-10-20/funding-evidence.json b/plan/marketplace/research/sdk-independent-2026-10-20/funding-evidence.json new file mode 100644 index 00000000..6c824cc5 --- /dev/null +++ b/plan/marketplace/research/sdk-independent-2026-10-20/funding-evidence.json @@ -0,0 +1,86 @@ +[ + { + "name": "marketplace-funding-register", + "at": "2026-10-20T13:02:36.549Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "cardId": "4", + "txHash": "0x2918939cb4ff99909d0169495d1e2ad7fd08b3d571aef35f716697b57993ab82" + }, + { + "name": "marketplace-funding-agw-paid", + "at": "2026-10-20T13:04:38.710Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "cardId": "4", + "marketJobId": "4", + "plainJobId": "5", + "wallet": "0x5FA6AF920028Fd96fB8541f2cA74557384c4FdC0", + "depositHashes": [ + "0x1b01fa8fbe213626dd65e115b50f882eb3b176de4d71d8cd8e795f000eb272fd", + "0x0774c597d2fe7c73a354898858818b3ddd57e4c56ea457df1d6c8201103b9ae7", + "0x03ff3a23dd366d1fa7c5144e50c17f18bde6b2f7e2d39fbdb7ac73e923d34b4a" + ], + "fundingHash": "0xca52cb7ef8fa2133f4e5ab12c71c5a8dd61be93d4c5a36c5975e7e711efcb9f1", + "completionHash": "0xf3a6ab8bd6b70bfc5cd2a3709ba8775e26ed2e740a5f220e7164b76f3b979768", + "budget": "10000" + }, + { + "name": "marketplace-funding-native-paid", + "at": "2026-10-20T13:05:35.771Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "jobId": "6", + "fundingHash": "0x0226f10376116df3c9da52d53f11e032e3a134f399333e479dc061a64549c87b", + "completionHash": "0xd468555f7d6cf1c3027cc9fac285e3caa874f640ca33eb90d95e905c32dcb00a", + "budget": "10000" + }, + { + "name": "marketplace-funding-bsc-gas", + "at": "2026-10-20T13:06:51.695Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "txHash": "0x436b9a2e98c56cafd765cdb495056f72b54742054255f48be1f2528d0ea5f435", + "amount": "10000000000000000" + }, + { + "name": "marketplace-funding-origin", + "at": "2026-10-20T13:08:51.073Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "cardId": "4", + "jobId": "7", + "wallet": "0x7f7D461A5E9aF9deAC2F15dfC4a964baCeF94424", + "uea": "0x871cB7aF3f196fF5c47C37d5ea05B1560465F7d5", + "depositHashes": [ + "0xd246f1ade3345ae72db2cdbd51008a9bcb4822a981a0e1b42099b197df031338" + ], + "principal": "10000", + "origin": "eip155:97" + }, + { + "name": "marketplace-funding-cleanup", + "at": "2026-10-20T13:09:46.681Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "cardId": "4", + "jobs": [ + { + "jobId": "4", + "status": "Rejected" + }, + { + "jobId": "5", + "status": "Completed" + }, + { + "jobId": "6", + "status": "Completed" + }, + { + "jobId": "7", + "status": "Rejected" + } + ] + } +] diff --git a/plan/marketplace/research/sdk-independent-2026-10-20/funding-results.json b/plan/marketplace/research/sdk-independent-2026-10-20/funding-results.json new file mode 100644 index 00000000..23ed3308 --- /dev/null +++ b/plan/marketplace/research/sdk-independent-2026-10-20/funding-results.json @@ -0,0 +1,31 @@ +{ + "completedAt": "2026-10-20T13:09:46.691Z", + "numTotalTests": 3, + "numPassedTests": 3, + "numFailedTests": 0, + "numPendingTests": 0, + "success": false, + "tests": [ + { + "file": "marketplace/funding.spec.ts", + "fullName": "marketplace funding 1. deposits real principal and fee, cancels the market job, then pays an AGW plain job through a controlled manual evaluator", + "status": "passed", + "duration": 122161, + "error": null + }, + { + "file": "marketplace/funding.spec.ts", + "fullName": "marketplace funding 2. funds a native plain job with an atomic token approval and pays out on live Donut", + "status": "passed", + "duration": 57058, + "error": null + }, + { + "file": "marketplace/funding.spec.ts", + "fullName": "marketplace funding 3. bridges principal from a fresh BSC origin into the opened wallet and recovers its funds after cancellation", + "status": "passed", + "duration": 195301, + "error": null + } + ] +} \ No newline at end of file diff --git a/plan/marketplace/research/sdk-independent-2026-10-20/live-evidence.json b/plan/marketplace/research/sdk-independent-2026-10-20/live-evidence.json new file mode 100644 index 00000000..8c9f1417 --- /dev/null +++ b/plan/marketplace/research/sdk-independent-2026-10-20/live-evidence.json @@ -0,0 +1,79 @@ +[ + { + "name": "marketplace-register", + "at": "2026-10-20T13:12:50.195Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "cardId": "5", + "txHash": "0x263ad38fdce757fdbbd3f690403ad469a9e76eecc7000d9983bb0e7def4e3c86" + }, + { + "name": "marketplace-open", + "at": "2026-10-20T13:13:05.086Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "jobId": "8", + "wallet": "0x803b9a0fD190afC823e2DdDd5fA3Ac3EA882EAbC", + "rulesId": "0x2084b21f68d24374f68a7b8f7a2fdb5129e9b19cabb8b33c2b0de92826afb0f7", + "txHash": "0x5d4008cb375289992771b069a58481ab73bcea1a913df2dc6709e5aa2009474b" + }, + { + "name": "marketplace-cancel-cleanup", + "at": "2026-10-20T13:13:31.501Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "cardId": "5", + "wallet": "0x803b9a0fD190afC823e2DdDd5fA3Ac3EA882EAbC", + "jobId": "8", + "txHash": "0xb46174399a14ff570c319dd68ba7b8fa058e194c4f50a74c9b88acc0fad8d6d2" + }, + { + "name": "marketplace-paid-preview", + "at": "2026-10-20T13:13:50.238Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "pass": true, + "fees": { + "quoted": "1687500000000000", + "paid": "1687500000000000", + "newlyPaid": "1687500000000000" + }, + "reads": [ + { + "decoded": "0", + "requestId": "0xad56c9aebd7f7e49a9f5ba7c87962b48c0591f735556f3bc47b5a32aaf9bf5c3", + "txHash": "0x7a9de048a37bc091208c110ad36408ba0a86176b92dbcabeb0e872ae8f53c4e9", + "outcome": "SUCCESS" + } + ] + }, + { + "name": "marketplace-preview-recovery", + "at": "2026-10-20T13:14:10.538Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "originalRequestId": "0xad56c9aebd7f7e49a9f5ba7c87962b48c0591f735556f3bc47b5a32aaf9bf5c3", + "preparedReadRequestId": "0xa72eba4c7bb78f500aec02efa2950b8a229f0b64fe261eb1ef52da95c89e9800", + "additionalPaymentOnResume": "0" + }, + { + "name": "marketplace-external-open", + "at": "2026-10-20T13:15:05.075Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "jobId": "9", + "wallet": "0x4C8d290cad724e9f251806D09f51D6b2911000d3", + "uea": "0x69977cF1645523b59229A3c59E103732e1B5B44C", + "signerChainId": "11155111", + "txHash": "0xc12012a1b055e49b50789d81b5d48d14a9fa03f1d8c45638f0cec22ebf59db8e" + }, + { + "name": "marketplace-external-cleanup", + "at": "2026-10-20T13:15:28.076Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "jobId": "9", + "cardId": "5", + "txHash": "0xb7d4bbe0fe19e633ab3d707fd962f21e60ddffc86b111691bb7c87e8b997f825" + } +] diff --git a/plan/marketplace/research/sdk-independent-2026-10-20/live-results.json b/plan/marketplace/research/sdk-independent-2026-10-20/live-results.json new file mode 100644 index 00000000..aa228899 --- /dev/null +++ b/plan/marketplace/research/sdk-independent-2026-10-20/live-results.json @@ -0,0 +1,32 @@ +{ + "completedAt": "2026-10-20T13:15:33.181Z", + "numTotalTests": 3, + "numPassedTests": 3, + "numFailedTests": 0, + "numPendingTests": 0, + "success": true, + "jestReportedSuccess": false, + "tests": [ + { + "file": "marketplace/lifecycle.spec.ts", + "fullName": "marketplace live 1. native provider registration, reviewed open and atomic cancel/revoke on BSC Testnet", + "status": "passed", + "duration": 46877, + "error": null + }, + { + "file": "marketplace/lifecycle.spec.ts", + "fullName": "marketplace live 2. paid JobSpec preview reaches live validator consensus through the registry", + "status": "passed", + "duration": 39035, + "error": null + }, + { + "file": "marketplace/lifecycle.spec.ts", + "fullName": "marketplace live 3. external EVM owner opens and cancels through its real Push UEA transport", + "status": "passed", + "duration": 77538, + "error": null + } + ] +} \ No newline at end of file diff --git a/plan/marketplace/research/sdk-independent-2026-10-20/post-live-state.json b/plan/marketplace/research/sdk-independent-2026-10-20/post-live-state.json new file mode 100644 index 00000000..cd8bb990 --- /dev/null +++ b/plan/marketplace/research/sdk-independent-2026-10-20/post-live-state.json @@ -0,0 +1,78 @@ +{ + "observedAt": "2026-10-20T13:27:56.374Z", + "block": "24452765", + "cards": [ + { + "cardId": "4", + "active": false, + "provider": "0x632783531D86bE4285C24f93850B24CF1Ec6050E", + "providerTokenBalance": "0" + }, + { + "cardId": "5", + "active": false, + "provider": "0x63ca68a97AA2eD6C8fDa3A67d063F27D198BaB16", + "providerTokenBalance": "0" + } + ], + "jobs": [ + { + "jobId": "4", + "cardId": "4", + "status": 4, + "budget": "0", + "client": "0x5FA6AF920028Fd96fB8541f2cA74557384c4FdC0", + "permissionEnabled": false, + "paymentBalance": "0", + "principalBalance": "0" + }, + { + "jobId": "5", + "cardId": "0", + "status": 3, + "budget": "10000", + "client": "0x5FA6AF920028Fd96fB8541f2cA74557384c4FdC0", + "paymentBalance": "0", + "principalBalance": "0" + }, + { + "jobId": "6", + "cardId": "0", + "status": 3, + "budget": "10000", + "client": "0xB5C87db8f78C2597f605440de5A11790B551C9Ff", + "paymentBalance": "0", + "principalBalance": "0" + }, + { + "jobId": "7", + "cardId": "4", + "status": 4, + "budget": "0", + "client": "0x7f7D461A5E9aF9deAC2F15dfC4a964baCeF94424", + "permissionEnabled": false, + "paymentBalance": "0", + "principalBalance": "0" + }, + { + "jobId": "8", + "cardId": "5", + "status": 4, + "budget": "0", + "client": "0x803b9a0fD190afC823e2DdDd5fA3Ac3EA882EAbC", + "permissionEnabled": false, + "paymentBalance": "0", + "principalBalance": "0" + }, + { + "jobId": "9", + "cardId": "5", + "status": 4, + "budget": "0", + "client": "0x4C8d290cad724e9f251806D09f51D6b2911000d3", + "permissionEnabled": false, + "paymentBalance": "0", + "principalBalance": "0" + } + ] +} diff --git a/plan/marketplace/research/sdk-independent-2026-10-20/unit-results.json.gz b/plan/marketplace/research/sdk-independent-2026-10-20/unit-results.json.gz new file mode 100644 index 0000000000000000000000000000000000000000..07c5f5e2dfc354f8d010c7bc874f2cef9cc8572e GIT binary patch literal 74643 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 literal 0 HcmV?d00001 diff --git a/plan/marketplace/research/sdk-independent-2026-10-20/validation-summary.json b/plan/marketplace/research/sdk-independent-2026-10-20/validation-summary.json new file mode 100644 index 00000000..68da837c --- /dev/null +++ b/plan/marketplace/research/sdk-independent-2026-10-20/validation-summary.json @@ -0,0 +1,71 @@ +{ + "observedAt": "2026-10-20T13:33:13.358Z", + "baselineCommit": "fdfcd4608f2d3db26ee4b3c5dc4a694f93f85097", + "unit": { + "passed": 2246, + "failed": 0, + "skipped": 12 + }, + "fork": { + "passed": 11, + "failed": 0, + "skipped": 0, + "runnerExitCode": 0 + }, + "basicLive": { + "passed": 3, + "failed": 0, + "skipped": 0, + "runnerExitCode": 0, + "reporterSuccess": true, + "jestReportedSuccess": false + }, + "fundingLive": { + "passed": 3, + "failed": 0, + "skipped": 0, + "runnerExitCode": 0, + "originalReporterSuccess": false, + "note": "Run completed before the counter-based reporter fix." + }, + "build": "passed", + "libraryTypes": "passed via build", + "specTypes": "passed", + "forkTypes": "passed", + "newProductionLint": "zero warnings", + "nativeTransportLint": { + "errors": 0, + "warnings": 13, + "baselineWarnings": 13, + "newDiagnostics": 0 + }, + "guideBlocks": 8, + "compiledPackageChecks": "passed", + "sourceBuiltApiMatches": true, + "artifacts": { + "unit-results.json.gz": { + "originalBytes": 874494, + "originalSha256": "87cd86ed94626e214341f5ae20ff20f9600c8557eb1c6219c50cabfbdd980584", + "compressedBytes": 74643, + "compressedSha256": "e2fa5448a43ad622c16cf6df81069b9bbd47e6e5129f429d2221fc149c310d84" + }, + "api-comparison.json.gz": { + "originalBytes": 722796, + "originalSha256": "6d9fb8f0efc6887e2dd05da14212f4724af268cd71b256ff9ca7db897592e12f", + "compressedBytes": 52200, + "compressedSha256": "3082df634d01370b14ea7560cf425dbb5ac63ee05206e4fd7b0e127012ff572c" + }, + "fork-before-confirmation-fix.json.gz": { + "originalBytes": 8620, + "originalSha256": "7eec3411f6fa5cedff4e1fd560032bd80479292f333dc8ca6ddcbd5a47d070bf", + "compressedBytes": 2047, + "compressedSha256": "3935189b50b89225d8efd72ad57377af9726a818f90c1bac3304c0f9f6ffe47b" + } + }, + "scope": "Current EVM marketplace v2; SDK-only checklist complete", + "remainingExternal": [ + "Three destination CEA manifests must align", + "Compatible automatic evaluator/hook/schema/verify ABI" + ], + "publication": "not performed" +} diff --git a/plan/marketplace/sdk-readiness.md b/plan/marketplace/sdk-readiness.md new file mode 100644 index 00000000..2504af72 --- /dev/null +++ b/plan/marketplace/sdk-readiness.md @@ -0,0 +1,32 @@ +# SDK-only completion boundary + +October 20, 2026, `feat/agw-sdk-v4`. Scope: deployed UniversalMarketplace v2, AGW v6, current EVM JobSpec wire, immutable criteria and pUSDC. The SDK does not require new team decisions to finish the items below. [Current acceptance evidence](research/sdk-independent-2026-10-20/README.md). + +| SDK-owned work | Completion / acceptance | +| --- | --- | +| Contracts, types, constants, codecs and authoring | Implemented; canonical wire, markers, constraints, public exports and package checks | +| Card/provider lifecycle | Implemented; immutable identity, pre-submission simulation, malformed-card summary tolerance, register/update/activation acceptance | +| Exact preview and signing | Implemented; independent CEA, hashes, nonces and factory domain; native/external EVM UEAs live, ERC-1271 reference adapter and compatible/incompatible 7702 verifiers on real local contracts | +| Opening proof and recovery | Implemented; input copied before awaits, deterministic permission ID, event/kernel/wallet/mapping checks, mined-input recovery without another signature or write; native broadcast hashes survive receipt/indexing failures | +| Deposits and historical versions | Implemented; original principal/fee/gas, shared-token aggregation, no implicit price acceptance, pending receipt/hash recovery, same-block/archive-less history authenticated by event content hashes and transaction input | +| Funded acceptance | Live owned-token deposits, native/AGW atomic escrow, provider submission and controlled manual-evaluator payout; live BSC-origin principal bridge; market grants revoked, test cards deactivated, deposited/reserve/payout tokens returned | +| Job lifecycle and safety | Create/price/fund/submit/status/list/cancel/refund implemented; explicit re-quotes, allowance handling, expiry/grace and paused refund accepted on the fork | +| Event delivery | Implemented; exact cursor, within-block resume, deduplication, retry without gaps, callback isolation, unsubscribe and canonical-cursor reorg stop | +| Read helpers and descriptions | Pure preparation and direct resolved-read sending, ABI names and explicit decimals, paid previews, checked fee cap, raw/nested decoding, explicit baselines/unknowns and request-ID recovery without new payment | +| Reproducible development checks | Unit/fork/live acceptance, repo-owned signature fixture compilation, corrected CI completion reporting, public guide examples, build/types, CJS/ESM and declaration/package/API checks | +| History and handoff | Changelog, evidence, consumer guide and narrowed team questions updated; source snapshots preserved | + +There is no remaining implementation item in this scoped checklist waiting for an SDK-only follow-up. The evidence distinguishes local simulation, fork execution and live transactions; it does not substitute one for another. + +## External contract/deployment boundary + +- **`job.verify` and automatic evaluation:** a compatible hook/evaluator, agreed shared JobSpec schema and callable verify/retry interface must be delivered. The current marketplace evaluator is an EOA. Live paid tests use fresh controlled evaluators on plain kernel jobs; they do not replace or impersonate the marketplace evaluator. +- **Three CEA rollouts:** align marketplace and routing manifests for Sepolia, Base Sepolia and Arbitrum Sepolia. Both tables currently answer but derive different accounts. BSC works. Changing SDK globals without coordinated routing evidence would redirect account derivation. + +Only these current dependencies should go to the team. [Ready-to-share questions](questions.md). + +## Later scope and release action + +Mutable criteria, per-job payment tokens, recurring jobs, relaying, verified ratings, non-EVM JobSpec sources/OwnerIntent conventions and mainnet rollout remain outside this delivered EVM v2 boundary. They require additional product/protocol scope; they are not unfinished implementations of current supported behavior. Custom contract-wallet vendors supply their own signer transport; a valid reference adapter and actual deployed verifier paths are accepted here. + +Package publication is a separate release action. Source, built declarations/imports and npm contents are checked, but no release version was chosen and no package was published. Continuing contract integration later should append to the existing changelog on this branch. From 1ac02f56b9a79d4d69729316d89d902bda8011ad Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Tue, 20 Oct 2026 19:30:58 +0530 Subject: [PATCH 60/68] fix(core): remove preset funding mode and preserve asset limits --- packages/core/AGW.md | 15 +++--- .../core/__agw-local__/v5-multiasset.spec.ts | 9 ++-- .../core/__e2e__/agw/presets-live.spec.ts | 16 +++--- packages/core/scripts/check-agw-package.js | 29 ++++++++--- .../core/scripts/check-agw-preset-routes.js | 19 ++++--- .../agentic/__tests__/creation-errors.spec.ts | 4 +- .../__tests__/preset-operation-limits.spec.ts | 3 +- .../agentic/__tests__/preset-routes.spec.ts | 49 +++++++------------ .../core/src/lib/agentic/error-messages.ts | 2 +- packages/core/src/lib/agentic/errors.ts | 5 +- .../core/src/lib/agentic/presets/index.ts | 13 +++-- .../core/src/lib/agentic/presets/routes.ts | 14 +++--- .../core/src/lib/agentic/presets/types.ts | 7 +-- .../preset-funding-removal-2026-10-20.md | 25 ++++++++++ 14 files changed, 111 insertions(+), 99 deletions(-) create mode 100644 plan/agw/research/preset-funding-removal-2026-10-20.md diff --git a/packages/core/AGW.md b/packages/core/AGW.md index e5a0e18b..afc1550a 100644 --- a/packages/core/AGW.md +++ b/packages/core/AGW.md @@ -132,11 +132,11 @@ function walletErrorText(error: unknown): string { Creation and rule-preparation errors include a zero-based `details.ruleIndex` when a rule can be identified, with `assetIndex`, `callIndex` and `field` where available. The UI message uses a one-based rule number. Use these details to show the error on the relevant rule instead of only in a footer. Read/receipt failures preserve their causes and transaction hashes; do not automatically retry a submitted transaction whose outcome is unknown. -`TOKEN_ROUTE_UNAVAILABLE` means an asset cannot be resolved for transfers from Push. It is not a token-symbol formatting request. Choose a supported source token, or regenerate the preset with `funding: 'destination'` when using assets already held by the destination account. The wallet can be created before funding; destination balances are needed before execution. Pass returned `rules` unchanged. **Do not copy `readiness.chains[].selectedAssets` back into `rules[].assets` in destination-funded mode**: selectedAssets is review metadata and doing so reintroduces unsupported bridge requirements. +`TOKEN_ROUTE_UNAVAILABLE` means an asset cannot be resolved for transfers from Push. Choose a token with a supported route on this network, or wait for a verified PRC20 route for that exact token address. Changing a symbol does not create a route. Display `error.userMessage` and check preset readiness before creation. A DEX condition-limit failure reports `details.reason = 'RULE_CONSTRAINT_LIMIT'`, `actual`, `limit` and `callCount`. Conditions here are generated input checks (for example token, recipient and amount checks), rather than the number of visible function names. A stock two-token, single-router preset contains six allowed-call entries and twenty conditions. Appending the same call list again makes forty conditions. The SDK rejects this; it does not deduplicate, remove conditions or split authority automatically. Preserve per-chain rules and regenerate after edits rather than appending generated calls. -For the review screen, show the actual network (including testnet name) and funding mode. In destination-funded mode, selectedAssets.maxTotal is not an enforced destination lifetime limit; the grant has no Push token-export budget. Label maxGasPerCall as a maximum PC gas budget, not a guaranteed fee or execution gas-unit count. +For the review screen, show the actual network (including testnet name), selected token addresses and limits. Label maxGasPerCall as a maximum PC gas budget, not a guaranteed fee or execution gas-unit count. maxTotal meters cumulative Push outbounds; it is not a lifetime destination-spend limit. ## Solana destinations @@ -207,7 +207,7 @@ const { rules: reviewTemplates } = PushChain.utils.agentic.presets.get( // Supply the agent to get complete Rule[] configuration. const configuredPreset = PushChain.utils.agentic.presets.get( PushChain.CONSTANTS.AGENTIC.PRESETS.CATEGORY.LENDING, - { chainNamespace: 'eip155:11155111', agent: '0x0000000000000000000000000000000000001234', funding: 'destination' }, + { chainNamespace: 'eip155:11155111', agent: '0x0000000000000000000000000000000000001234' }, ); // Destination assets must already be funded; no Push token exports are granted. // Show configuredPreset.readiness.chains[0].selectedAssets in the review UI. @@ -219,7 +219,6 @@ function filledPreset(agent: Address, tokenIn: Address, tokenOut: Address) { PushChain.CONSTANTS.AGENTIC.PRESETS.CATEGORY.DEXES, { chainNamespace: 'eip155:11155111', - funding: 'destination', agent, validUntil: Math.floor(Date.now() / 1000) + 3600, maxGasPerCall: BigInt(10) ** BigInt(18), @@ -257,13 +256,13 @@ These are small, protocol-specific subsets chosen to fit the 32-call/32-pin ceil | Arbitrum Sepolia | WETH / Circle USDC | Aave USDC | | BSC testnet | WBNB / Venus USDT | Venus USDT, USDC | -Staking defaults are ETH/stETH/wstETH on Ethereum and the reviewed EigenLayer strategy's WETH on Sepolia. Testnet tokens with similar names can have different addresses; the returned addresses are authoritative. These tokens may lack Push PRC20 routes and can instead be used with destination-held balances. Defaults do not guarantee active reserves, liquidity, a Push PRC20 route or execution. In particular, an unmodified preset can fail rule preparation if its default assets lack PRC20 mappings. For destination-only use, pass `funding: 'destination'`: the SDK generates the operation constraints, returns empty rule bridge assets and retains selected token limits in readiness metadata. This grants no token export budget from Push and requires already-funded destination balances. Token addresses are returned as before; metadata was verified when defining the policy. No runtime metadata/price fetch is added to get. +Staking defaults are ETH/stETH/wstETH on Ethereum and the reviewed EigenLayer strategy's WETH on Sepolia. Testnet tokens with similar names can have different addresses; the returned addresses are authoritative. Defaults do not guarantee active reserves, liquidity or a Push PRC20 route. An unmodified preset cannot be granted when its assets lack matching PRC20 routes. The SDK preserves the selected tokens and caps and reports unavailable routes; it never removes assets to bypass this check. No runtime metadata/price fetch is added to get. ### Funding and release-network checks -`funding` defaults to `'push'`. Missing PRC20 registry entries produce `BRIDGE_ASSET_UNAVAILABLE`, and readiness is false while the returned rule retains all requested assets. No address or cap is silently replaced. `network` defaults to `TESTNET_DONUT` (`TESTNET` is accepted as an alias); use the connected client's Push network when supplying it. Networks without a verified AGW deployment report `AGW_NETWORK_UNAVAILABLE`. +Missing PRC20 registry entries produce `BRIDGE_ASSET_UNAVAILABLE`, and readiness is false while the returned rule retains all requested assets. No address or cap is silently replaced. `network` defaults to `TESTNET_DONUT` (`TESTNET` is accepted as an alias). Networks without a verified AGW deployment report `AGW_NETWORK_UNAVAILABLE`. -Use `funding: 'destination'` for the prefunded CEA workflow. Selected tokens still generate the same target/function/amount/recipient/spender restrictions, exposed alongside their caps in `readiness.chains[].selectedAssets`. Returned `rule.assets` is intentionally empty, which grants zero Push token-export authority. It is safe to pass these returned rules directly to create/update. The mode does not fund the destination, wrap ETH, mint testnet tokens or enable an unsupported network. Do not relabel it as bridge funding in the UI. +The public preset API has no `funding` option. Remove it from existing integrations; supplying it now produces `INVALID_RULE` rather than silently changing permissions. Internal prefunded CEA test fixtures explicitly clear bridge assets to isolate protocol constraints. Those fixtures do not demonstrate that an unsupported preset route is executable. Existing mappings distinguish token identity by chain and address, including address casing for EVM. WETH/stETH Sepolia mappings and string/address-word source metadata are supported; mainnet or other-chain WETH is never aliased to them. Protocol mock LINK, Moonwell/Venus mocks and Circle testnet USDC can differ from the supported source tokens; they remain unavailable for bridge funding until real matching routes exist. @@ -288,7 +287,7 @@ Explicit `validUntil` and `maxGasPerCall` override policy values; zero gas is pr ### Configure, inspect and regenerate -`readiness.ready` requires complete configuration plus offline SDK deployment/destination/bridge-registry support for the selected funding mode. Per-chain `configurationReady` reports input completeness separately. These checks do not verify live balances, reserve flags, liquidity, current deployed bytecode or source identity; grant preparation still verifies wiring and token metadata on-chain before signing. `readiness.chains` gives per-chain `issues`, `disabledCalls`, `excludedCalls`, catalog `knownTokens`, `selectedAssets`, `bridgeAssets`, `funding` and `zeroBridgeLimits`. Display `selectedAssets` as the reviewed token/amount permissions in either mode; `rule.assets` describes Push bridge permissions only. `bridgeAssets` reports registry presence, not verified live deployment. Mainnet templates remain discoverable but have `DESTINATION_UNAVAILABLE` on Donut. These are additive result fields; `rules` remains accepted by the existing create/update methods. +`readiness.ready` requires complete configuration plus offline SDK deployment, destination and bridge-registry support. Per-chain `configurationReady` reports input completeness separately. These checks do not verify live balances, reserve flags, liquidity or deployed bytecode. Grant preparation verifies wiring and token metadata on-chain before signing. Per-chain `selectedAssets` mirrors the selected rule assets; `bridgeAssets` reports registry presence, not verified live deployment. Mainnet templates remain discoverable but report `DESTINATION_UNAVAILABLE` on Donut. Check readiness before passing `rules` to create/update. Tokens and permission defaults come directly from the SDK: omitted `assets` populates the curated subset and its caps in every returned `rule.assets`. Omitted gas and expiry use the policy below. The caller supplies the agent and can filter chains; no per-network token selection is required. Show the generated permissions for owner review and allow explicit overrides. Regenerate via get after an edit so operation pins/approvals match the new caps. Show explicitly zero-cap calls as disabled and present excluded calls clearly. A zero bridge limit can be intentional when assets are already at the destination; it is reported separately from operation readiness. diff --git a/packages/core/__agw-local__/v5-multiasset.spec.ts b/packages/core/__agw-local__/v5-multiasset.spec.ts index 394301ed..193a7e89 100644 --- a/packages/core/__agw-local__/v5-multiasset.spec.ts +++ b/packages/core/__agw-local__/v5-multiasset.spec.ts @@ -358,19 +358,18 @@ describe('v6 multi-asset SDK management and execution', () => { ); it.each(['DEXES', 'LENDING', 'STAKING'] as const)( - 'public %s destination-funded defaults create directly without rewriting returned rules', + '%s constraints work in an explicit prefunded contract fixture', async (category) => { const generated = agenticPresets.get(category, { chainNamespace: CHAIN_NS, agent: h.wallets[1].account!.address, - funding: 'destination', }); - expect(generated.readiness.ready).toBe(true); + expect(generated.readiness.chains[0].configurationReady).toBe(true); expect( generated.readiness.chains[0].selectedAssets.length ).toBeGreaterThan(0); - expect(generated.rules[0].assets).toEqual([]); - const { wallet, id } = await setup(generated.rules[0]); + expect(generated.rules[0].assets!.length).toBeGreaterThan(0); + const { wallet, id } = await setup({ ...generated.rules[0], assets: [] }); const actual = await stored(wallet, id); expect(actual.assets).toEqual([ { diff --git a/packages/core/__e2e__/agw/presets-live.spec.ts b/packages/core/__e2e__/agw/presets-live.spec.ts index 48fab87e..ae685f1f 100644 --- a/packages/core/__e2e__/agw/presets-live.spec.ts +++ b/packages/core/__e2e__/agw/presets-live.spec.ts @@ -76,9 +76,8 @@ d('agw presets live', () => { const defaults = PushChain.utils.agentic.presets.get('DEXES', { chainNamespace: CHAIN.ETHEREUM_SEPOLIA, agent: f.agentAddress, - funding: 'destination', }); - expect(defaults.readiness.ready).toBe(true); + expect(defaults.readiness.chains[0].configurationReady).toBe(true); expect(defaults.rules[0].maxGasPerCall).toBe(MAX_PC); expect(defaults.rules[0].validUntil).toBeGreaterThan(inSeconds(6 * 86400)); expect( @@ -92,7 +91,6 @@ d('agw presets live', () => { ) ).toBe(true); const { rules } = PushChain.utils.agentic.presets.get('DEXES', { - funding: 'destination', chainNamespace: CHAIN.ETHEREUM_SEPOLIA, agent: f.agentAddress, validUntil: inSeconds(3600), @@ -108,9 +106,10 @@ d('agw presets live', () => { }); // assets[] budgets bridge burns on Push. This test spends already-held CEA // tokens, so omit bridge assets without changing any generated call or pin. + // Prefunded CEA fixture: bypass bridge budgets only in this protocol test. const { wallet, rulesIds } = await f.owner.agentic.create( 'e2e-preset-uniswap', - { rules } + { rules: rules.map((rule) => ({ ...rule, assets: [] })) } ); const cea = (await getCEAAddress(wallet, CHAIN.ETHEREUM_SEPOLIA)) .cea as Address; @@ -290,9 +289,8 @@ d('agw presets live', () => { const defaults = PushChain.utils.agentic.presets.get('LENDING', { chainNamespace: CHAIN.ETHEREUM_SEPOLIA, agent: f.agentAddress, - funding: 'destination', }); - expect(defaults.readiness.ready).toBe(true); + expect(defaults.readiness.chains[0].configurationReady).toBe(true); expect(defaults.readiness.chains[0].selectedAssets[0].maxPerCall).toBe( parseEther('1') ); @@ -303,7 +301,6 @@ d('agw presets live', () => { ) ).toEqual([mockLINK.toLowerCase()]); const { rules } = PushChain.utils.agentic.presets.get('LENDING', { - funding: 'destination', chainNamespace: CHAIN.ETHEREUM_SEPOLIA, agent: f.agentAddress, validUntil: inSeconds(3600), @@ -314,9 +311,10 @@ d('agw presets live', () => { maxTotal: amount, })), }); + // Prefunded CEA fixture: bypass bridge budgets only in this protocol test. const { wallet, rulesIds } = await f.owner.agentic.create( 'e2e-preset-aave', - { rules } + { rules: rules.map((rule) => ({ ...rule, assets: [] })) } ); const cea = (await getCEAAddress(wallet, CHAIN.ETHEREUM_SEPOLIA)) .cea as Address; @@ -455,7 +453,7 @@ d('agw presets live', () => { maxGasPerCall: MAX_PC, assets: [{ token: mockLINK, maxPerCall: half, maxTotal: amount }], }); - expect(regenerated.readiness.ready).toBe(true); + expect(regenerated.readiness.chains[0].configurationReady).toBe(true); const changed = await f.owner.agentic.wallet(wallet).rules.update({ rules: [ { diff --git a/packages/core/scripts/check-agw-package.js b/packages/core/scripts/check-agw-package.js index 453042a3..99267d60 100644 --- a/packages/core/scripts/check-agw-package.js +++ b/packages/core/scripts/check-agw-package.js @@ -24,20 +24,27 @@ async function main() { assert(pack.files.some((f) => f.path === 'AGW.md')); assert(pack.files.some((f) => f.path === 'MARKETPLACE.md')); assert.equal(typeof cjs.PushChain.utils.job.buildJobSpec, 'function'); - assert.equal(typeof cjs.PushChain.utils.market.encodeAgentCardRules, 'function'); + assert.equal( + typeof cjs.PushChain.utils.market.encodeAgentCardRules, + 'function' + ); assert(!pack.files.some((f) => /(^|\/)\.env($|\.)/.test(f.path))); assert( !pack.files.some((f) => - /(^|\/)(plan|__e2e__|__agw-local__|__market-local__|scripts)(\/|$)/.test(f.path) + /(^|\/)(plan|__e2e__|__agw-local__|__market-local__|scripts)(\/|$)/.test( + f.path + ) ) ); const preset = cjs.PushChain.utils.agentic.presets.get('LENDING', { agent: '0x0000000000000000000000000000000000005678', chainNamespace: 'eip155:11155111', - funding: 'destination', }); - assert.equal(preset.readiness.ready, true); - assert.deepEqual(preset.rules[0].assets, []); + assert.equal(preset.readiness.ready, false); + assert.deepEqual( + preset.rules[0].assets, + preset.readiness.chains[0].selectedAssets + ); assert(preset.readiness.chains[0].selectedAssets.length > 0); assert.equal( cjs.PushChain.utils.agentic.presets.get('LENDING', { @@ -57,8 +64,16 @@ async function main() { const file = path.join(tmp, 'consumer.ts'); fs.writeFileSync(file, source); const marketFile = path.join(tmp, 'market-consumer.ts'); - const marketGuide = fs.readFileSync(path.join(built, 'MARKETPLACE.md'), 'utf8'); - fs.writeFileSync(marketFile, [...marketGuide.matchAll(/```ts\n([\s\S]*?)```/g)].map(m => m[1]).join('\n\n')); + const marketGuide = fs.readFileSync( + path.join(built, 'MARKETPLACE.md'), + 'utf8' + ); + fs.writeFileSync( + marketFile, + [...marketGuide.matchAll(/```ts\n([\s\S]*?)```/g)] + .map((m) => m[1]) + .join('\n\n') + ); const config = ts.readConfigFile( path.join(root, 'packages/core/tsconfig.lib.json'), ts.sys.readFile diff --git a/packages/core/scripts/check-agw-preset-routes.js b/packages/core/scripts/check-agw-preset-routes.js index ff524ea3..53bf5ba2 100644 --- a/packages/core/scripts/check-agw-preset-routes.js +++ b/packages/core/scripts/check-agw-preset-routes.js @@ -124,19 +124,18 @@ async function main() { chainNamespace, }); result.pushReadiness = push.readiness; - const destination = PushChain.utils.agentic.presets.get(category, { - agent, - chainNamespace, - funding: 'destination', - }); - assert.equal(destination.readiness.ready, true); - assert.deepEqual(destination.rules[0].assets, []); + // Explicit prefunded fixture, not public preset acceptance or bridge proof. + assert.equal(push.readiness.chains[0].configurationReady, true); + const fixtureRules = push.rules.map((rule) => ({ + ...rule, + assets: [], + })); const prepared = await prepareWalletRules( runtime, gen, owner, wallet, - publicRules(destination.rules), + publicRules(fixtureRules), snap ); const data = gen.contracts.encodeCreateWalletAt( @@ -154,8 +153,8 @@ async function main() { gas: BigInt(20000000), }); assert(simulated.data && simulated.data !== '0x'); - result.destinationFactorySimulation = 'passed'; - result.selectedAssets = destination.readiness.chains[0].selectedAssets; + result.prefundedFixtureFactorySimulation = 'passed'; + result.selectedAssets = push.readiness.chains[0].selectedAssets; // If static registry support is advertised, verify preparation against real metadata too. if (push.readiness.ready) { await prepareWalletRules( diff --git a/packages/core/src/lib/agentic/__tests__/creation-errors.spec.ts b/packages/core/src/lib/agentic/__tests__/creation-errors.spec.ts index 4a80316b..1f4538dc 100644 --- a/packages/core/src/lib/agentic/__tests__/creation-errors.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/creation-errors.spec.ts @@ -55,7 +55,7 @@ it.each(['LENDING', 'STAKING'] as const)( userMessage: expect.stringContaining( 'Rule 1: This token cannot be sent from Push to Ethereum Sepolia' ), - hint: expect.stringContaining("funding: 'destination'"), + hint: expect.stringContaining('verified PRC20 route'), }); expect(rt.executeMock).not.toHaveBeenCalled(); expect(rt.atomicMock).not.toHaveBeenCalled(); @@ -67,7 +67,6 @@ it('reports the complete 40-condition count for duplicated DEX entries, without const sdk = new AgenticNamespaceImpl(rt); const { rules } = agenticPresets.get('DEXES', { ...options, - funding: 'destination', }); const calls = rules[0].allowedCalls; const duplicated = { ...rules[0], allowedCalls: [...calls, ...calls] }; @@ -96,7 +95,6 @@ it('validates stock DEX rules independently: two 20-condition rules do not becom const { rules } = agenticPresets.get('DEXES', { ...options, chainNamespace: chain, - funding: 'destination', }); const normalized = (await normalizePublicRule( publicRules(rules)[0], diff --git a/packages/core/src/lib/agentic/__tests__/preset-operation-limits.spec.ts b/packages/core/src/lib/agentic/__tests__/preset-operation-limits.spec.ts index caa42aa3..d10a4c0a 100644 --- a/packages/core/src/lib/agentic/__tests__/preset-operation-limits.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/preset-operation-limits.spec.ts @@ -68,8 +68,7 @@ it('default lending policy needs only the agent to become locally ready', () => agenticPresets.get('LENDING', { chainNamespace, agent: ADDR.agent, - funding: 'destination', - }).readiness.ready + }).readiness.chains[0].configurationReady ).toBe(true); }); it('zero operation caps remain valid disabled configurations, while zero bridge totals are separately reported', () => { diff --git a/packages/core/src/lib/agentic/__tests__/preset-routes.spec.ts b/packages/core/src/lib/agentic/__tests__/preset-routes.spec.ts index 077b2351..5b8ca40b 100644 --- a/packages/core/src/lib/agentic/__tests__/preset-routes.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/preset-routes.spec.ts @@ -9,7 +9,6 @@ it('reports unmapped source tokens without silently changing the default Push gr expect(res.readiness.ready).toBe(false); const state = res.readiness.chains[0]; expect(state.configurationReady).toBe(true); - expect(state.funding).toBe('push'); expect(state.issues).toContainEqual( expect.objectContaining({ code: 'BRIDGE_ASSET_UNAVAILABLE', @@ -19,26 +18,23 @@ it('reports unmapped source tokens without silently changing the default Push gr expect(res.rules[0].assets).toEqual(state.selectedAssets); expect(res.rules[0].assets).toHaveLength(1); }); -it('supports the explicit destination-funded grant with preserved token/amount pins and review metadata', () => { - const push = agenticPresets.get('DEXES', options); - const dest = agenticPresets.get('DEXES', { - ...options, - funding: 'destination', - }); - expect(push.readiness.ready).toBe(false); - expect(dest.readiness.ready).toBe(true); - expect(dest.rules[0].assets).toEqual([]); - expect(dest.readiness.chains[0].selectedAssets).toEqual(push.rules[0].assets); - expect(dest.rules[0].allowedCalls).toEqual(push.rules[0].allowedCalls); - expect(dest.readiness.chains[0].bridgeAssets.map((a) => a.status)).toEqual([ - 'registered', - 'unavailable', - ]); - const returned = dest.readiness.chains[0].selectedAssets[0]; - returned.maxPerCall = BigInt(0); - expect( - agenticPresets.get('DEXES', options).rules[0].assets?.[0].maxPerCall - ).toBeGreaterThan(BigInt(0)); +it('preserves assets and rejects the removed funding option instead of silently changing permissions', () => { + const result = agenticPresets.get('DEXES', options); + expect(result.readiness.ready).toBe(false); + expect(result.rules[0].assets).toEqual( + result.readiness.chains[0].selectedAssets + ); + result.readiness.chains[0].selectedAssets[0].maxPerCall = BigInt(0); + expect(result.rules[0].assets?.[0].maxPerCall).toBeGreaterThan(BigInt(0)); + for (const funding of ['push', 'destination', 'auto']) { + expect(() => + agenticPresets.get('DEXES', { + ...options, + // @ts-expect-error funding is not part of the public preset API + funding, + }) + ).toThrow(/funding option is no longer supported/); + } }); it('an explicitly selected mapped source token can be ready for Push funding', () => { const token = MOVEABLE_TOKEN_CONSTANTS.BNB_TESTNET.USDT; @@ -63,7 +59,6 @@ it('never treats a mainnet template or undeployed Push generation as executable' const mainnet = agenticPresets.get('DEXES', { agent: ADDR.agent, chainNamespace: CHAIN.ETHEREUM_MAINNET, - funding: 'destination', }); expect(mainnet.readiness.ready).toBe(false); expect(mainnet.readiness.chains[0].issues).toContainEqual( @@ -71,7 +66,6 @@ it('never treats a mainnet template or undeployed Push generation as executable' ); const missing = agenticPresets.get('LENDING', { ...options, - funding: 'destination', network: PUSH_NETWORK.MAINNET, }); expect(missing.readiness.ready).toBe(false); @@ -83,19 +77,14 @@ it('supports the TESTNET alias, rejects invalid modes and preserves empty select expect( agenticPresets.get('LENDING', { ...options, - funding: 'destination', network: PUSH_NETWORK.TESTNET, - }).readiness.ready - ).toBe(true); - expect(() => - agenticPresets.get('LENDING', { ...options, funding: 'auto' as never }) - ).toThrow(/funding/); + }).readiness + ).toEqual(agenticPresets.get('LENDING', options).readiness); expect(() => agenticPresets.get('LENDING', { ...options, network: 'OTHER' as never }) ).toThrow(/network/); const empty = agenticPresets.get('LENDING', { ...options, - funding: 'destination', assets: [], }); expect(empty.readiness.chains[0].selectedAssets).toEqual([]); diff --git a/packages/core/src/lib/agentic/error-messages.ts b/packages/core/src/lib/agentic/error-messages.ts index 88722c60..6202aae7 100644 --- a/packages/core/src/lib/agentic/error-messages.ts +++ b/packages/core/src/lib/agentic/error-messages.ts @@ -12,7 +12,7 @@ const MESSAGES: Record = { ASSET_CHAIN_MISMATCH: 'The selected token belongs to a different network. Choose a token on this rule’s network.', TOKEN_ROUTE_UNAVAILABLE: - 'This token cannot currently be transferred from Push to the selected network. Choose a supported token or use funds already on the destination network.', + 'This token cannot currently be transferred from Push to the selected network. Choose a token with a supported Push route.', REQUEST_REJECTED: 'The wallet request was cancelled. Check wallet activity before trying again.', NOT_OWNER_OR_AGENT: diff --git a/packages/core/src/lib/agentic/errors.ts b/packages/core/src/lib/agentic/errors.ts index 5aac4033..3a739c22 100644 --- a/packages/core/src/lib/agentic/errors.ts +++ b/packages/core/src/lib/agentic/errors.ts @@ -178,16 +178,15 @@ export function tokenRouteUnavailable( (chainNamespace.startsWith('solana:') ? 'the selected Solana network' : 'the selected network'); - const message = `This token cannot be sent from Push to ${network}. Choose a supported token, or use destination funding for balances held on that network.`; + const message = `This token cannot be sent from Push to ${network}. Choose a token with a supported Push route.`; return new AgenticError(AGENTIC_ERROR_CODE.TOKEN_ROUTE_UNAVAILABLE, message, { userMessage: message, - hint: "For prefunded preset destinations, use funding: 'destination' and pass the returned rules unchanged. selectedAssets is review metadata; do not copy it back into rule.assets.", + hint: 'Choose a supported token on this network, or wait for a verified PRC20 route for this exact token address. Token symbols alone do not identify a route.', details: { token, chainNamespace, assetIndex, field: `assets[${assetIndex}].token`, - funding: 'push', }, cause, }); diff --git a/packages/core/src/lib/agentic/presets/index.ts b/packages/core/src/lib/agentic/presets/index.ts index 84b7f84d..160dd9b1 100644 --- a/packages/core/src/lib/agentic/presets/index.ts +++ b/packages/core/src/lib/agentic/presets/index.ts @@ -119,11 +119,12 @@ export function buildPresetApi( throw invalid('preset options must be an object'); const now = Math.floor(Date.now() / 1000); const network = options.network ?? PUSH_NETWORK.TESTNET_DONUT; - const funding = options.funding ?? 'push'; if (!Object.values(PUSH_NETWORK).includes(network)) throw invalid('unknown preset Push network'); - if (funding !== 'push' && funding !== 'destination') - throw invalid('preset funding must be push or destination'); + if ('funding' in options) + throw invalid( + 'The preset funding option is no longer supported. Remove it; preset assets and limits are always preserved.' + ); if ( options.agent !== undefined && (!isAddress(options.agent, { strict: false }) || @@ -426,16 +427,14 @@ export function buildPresetApi( const routes = presetRoutes( chain.chainNamespace, selectedAssets, - network, - funding + network ); issues.push(...routes.issues); - const bridgeAssets = funding === 'destination' ? [] : selectedAssets; + const bridgeAssets = selectedAssets; readiness.push({ chainNamespace: chain.chainNamespace, ready: issues.length === 0, configurationReady, - funding, selectedAssets: selectedAssets.map((a) => ({ ...a, token: typeof a.token === 'string' ? a.token : { ...a.token }, diff --git a/packages/core/src/lib/agentic/presets/routes.ts b/packages/core/src/lib/agentic/presets/routes.ts index fc0babf4..8146d138 100644 --- a/packages/core/src/lib/agentic/presets/routes.ts +++ b/packages/core/src/lib/agentic/presets/routes.ts @@ -12,8 +12,7 @@ import { assetAddress } from './operation-limits'; export function presetRoutes( chain: string, assets: RuleAsset[], - network: PUSH_NETWORK, - funding: 'push' | 'destination' + network: PUSH_NETWORK ): { bridgeAssets: PresetChainReadiness['bridgeAssets']; issues: PresetConfigurationIssue[]; @@ -43,12 +42,11 @@ export function presetRoutes( status: 'registered' as const, }; } catch { - if (funding === 'push') - issues.push({ - code: 'BRIDGE_ASSET_UNAVAILABLE', - token, - message: `No SDK PRC20 mapping for ${chain}:${token} on ${network}. Use a supported source asset or explicitly choose destination funding for assets already at the CEA.`, - }); + issues.push({ + code: 'BRIDGE_ASSET_UNAVAILABLE', + token, + message: `No SDK PRC20 mapping for ${chain}:${token} on ${network}. Choose a supported asset. This exact token needs a verified Push PRC20 route before it can be used.`, + }); return { token, status: 'unavailable' as const }; } }); diff --git a/packages/core/src/lib/agentic/presets/types.ts b/packages/core/src/lib/agentic/presets/types.ts index f014991c..0e2983e8 100644 --- a/packages/core/src/lib/agentic/presets/types.ts +++ b/packages/core/src/lib/agentic/presets/types.ts @@ -31,10 +31,6 @@ export interface PresetAsset { export interface PresetOptions { /** Offline route/deployment checks; defaults to TESTNET_DONUT. */ network?: PUSH_NETWORK; - /** Push funding requires PRC20 routes. Destination funding explicitly emits - * empty bridge assets while preserving selected token/call limits in metadata. - * The CEA must already hold the required destination assets. Default: push. */ - funding?: 'push' | 'destination'; /** Push-PC budget ceiling per outbound; omitted uses the catalog policy (20 PC). * Explicit zero is preserved. This is not the fee charged. */ maxGasPerCall?: bigint; @@ -84,8 +80,7 @@ export interface PresetChainReadiness { chainNamespace: ForeignChainNamespace; ready: boolean; configurationReady: boolean; - funding: 'push' | 'destination'; - /** Selected destination permissions, retained even when bridge assets is empty. */ + /** Selected assets and caps, matching the returned rule assets. */ selectedAssets: RuleAsset[]; /** Registry presence only; grant preparation verifies exact on-chain identity. */ bridgeAssets: { diff --git a/plan/agw/research/preset-funding-removal-2026-10-20.md b/plan/agw/research/preset-funding-removal-2026-10-20.md new file mode 100644 index 00000000..e4b28eee --- /dev/null +++ b/plan/agw/research/preset-funding-removal-2026-10-20.md @@ -0,0 +1,25 @@ +# Preset funding option removal — 20 October 2026 + +The user requested removal of the public `funding` extension, which is not in the target SDK specification. This supersedes the destination-mode advice in the earlier creation-error review. + +## Behavior + +- `presets.get` retains all selected assets and their caps. There is no mode that silently empties rule assets. +- The input option and readiness funding field are removed. JavaScript callers still passing the option receive `INVALID_RULE` with migration guidance rather than silently changing their permissions. +- Missing mappings remain `BRIDGE_ASSET_UNAVAILABLE` in readiness and `TOKEN_ROUTE_UNAVAILABLE` during preparation. Error guidance no longer recommends the removed option. +- Existing integrations omitting the option need no call-shape change. They must respect readiness; this change does not enable missing routes. +- Local and live protocol tests use explicitly labeled prefunded fixtures where bridge assets are cleared. They do not establish default-preset bridge acceptance. + +## Route work required + +For each unsupported exact chain/token address, the core/gateway team must confirm an existing compatible PRC20 route or deploy/register the missing route. Verify source chain, source address and decimals, along with the route configuration required for actual outbound delivery. The SDK can then register the verified mapping and test rule creation and bounded destination delivery. Existing supported assets are alternatives only if the target protocol actually supports those exact assets. A shared symbol is insufficient. + +This change did not re-audit current deployments or perform transactions. Previously reported blockers include Aave faucet LINK, Circle testnet USDC variants, EigenLayer Sepolia WETH and Arbitrum WETH. Sepolia DEX WETH has a registry mapping already; not every WETH address is interchangeable. + +## Validation + +- 54 focused unit regressions passed. +- 21 real-contract local tests passed, with a stub gateway. +- Core build, spec and local-harness typechecks passed. +- Package imports/declarations/content checks and seven guide examples passed. +- No live transactions, publishing, commits or pushes performed for this change. From 9b37bc3d9be105ac4a77173586bccf969ea6058f Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Tue, 20 Oct 2026 19:40:26 +0530 Subject: [PATCH 61/68] docs(agw): record live token route validation --- .../README.md | 40 ++ .../probe-gateways.cjs | 1 + .../probe-prc20.cjs | 3 + .../probe.json | 415 ++++++++++++++++++ 4 files changed, 459 insertions(+) create mode 100644 plan/agw/research/token-route-validation-2026-10-20/README.md create mode 100644 plan/agw/research/token-route-validation-2026-10-20/probe-gateways.cjs create mode 100644 plan/agw/research/token-route-validation-2026-10-20/probe-prc20.cjs create mode 100644 plan/agw/research/token-route-validation-2026-10-20/probe.json diff --git a/plan/agw/research/token-route-validation-2026-10-20/README.md b/plan/agw/research/token-route-validation-2026-10-20/README.md new file mode 100644 index 00000000..350874d1 --- /dev/null +++ b/plan/agw/research/token-route-validation-2026-10-20/README.md @@ -0,0 +1,40 @@ +# Token route validation — 20 October 2026 + +Read-only RPC queries; no signing, funding or transactions. SDK source: 1ac02f56. Donut chain 42101, block 24453693. Fresh fetches completed for core and gateway repositories. Core main: b2f22241681c6587a1c130e638949856dfcbd33f. Gateway gateway-testnet: b205770f2c65df090eb282fd2f3b4234d30faa1f. Gateway addresses were taken from that branch's script/config/testnet/GatewayConfig.sol. + +## Conclusion + +The creation failures are confirmed SDK mapping gaps. However, the claim that all affected tokens require gateway enablement was too broad. Several exact preset tokens are already allow-listed by the external gateway. A matching Push PRC20 still needs to be identified; the existing published/SDK USDC PRC20s point to different mock token addresses. + +The official address book (https://push.org/docs/chain/setup/smart-contract-address-book/) agrees with the known PRC20 list. Live SOURCE_CHAIN_NAMESPACE and SOURCE_TOKEN_ADDRESS reads confirm exact identities. This is not an exhaustive search of every deployed contract: an unpublished PRC20 may exist. Do not claim proven nonexistence. Ask the core/node/gateway team for the canonical mapping first. + +Sepolia DEX WETH fff997 already has a matching PRC20 0x0d0dF7E8807430A81104EA84d926139816eC7586 and gateway support. EigenLayer WETH 7b799 is a different token. + +## Gateway observations + +isSupportedToken is a token allow-list/rate-limit threshold predicate. A true result alone does not establish end-to-end minting, burning or settlement support. A false result identifies missing support at that gateway, not a proof that destination-held token calls cannot execute. + +| Chain | Token | Gateway allow-listed | Block | +|---|---|---|---| +| eip155:11155111 | `0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14` | True | 11955784 | +| eip155:11155111 | `0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238` | True | 11955784 | +| eip155:11155111 | `0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5` | False | 11955784 | +| eip155:11155111 | `0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9` | False | 11955784 | +| eip155:84532 | `0x4200000000000000000000000000000000000006` | True | 48368455 | +| eip155:84532 | `0x036CbD53842c5426634e7929541eC2318f3dCF7e` | True | 48368455 | +| eip155:84532 | `0x810D46F9a9027E28F9B01F75E2bdde839dA61115` | False | 48368455 | +| eip155:84532 | `0x4616975f7E6045FD9737e95bC527e9e14c727BD2` | False | 48368455 | +| eip155:84532 | `0x663A6F02d547dFd639BF689FED298712f2FB69Fb` | False | 48368455 | +| eip155:421614 | `0x980B62Da83eFf3D4576C647993b0c1D7faf17c73` | True | 321080510 | +| eip155:421614 | `0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d` | True | 321080510 | +| eip155:97 | `0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd` | False | 137899664 | +| eip155:97 | `0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c` | False | 137899664 | +| eip155:97 | `0x16227D60f7a0e586C66B005219dfc887D13C9531` | False | 137899664 | + +## Actions + +- Core/node team: provide exact source-token → PRC20 mappings for the already allow-listed Circle USDC and wrapped-native tokens. If matching PRC20s exist, the SDK registry addition is ours; otherwise the route needs provisioning. +- Gateway/core team: review support for Aave LINK, EigenLayer WETH, Moonwell mocks and Venus/BNB preset assets before claiming they can move through Push. +- SDK: add only verified mappings, then test grant preparation and bounded end-to-end delivery. Never map a protocol token to a different same-symbol mock asset. + +Raw results, including all known PRC20 source metadata and preset readiness, are in probe.json. Scripts run from the SDK root with a current build. No production code changed during this validation. diff --git a/plan/agw/research/token-route-validation-2026-10-20/probe-gateways.cjs b/plan/agw/research/token-route-validation-2026-10-20/probe-gateways.cjs new file mode 100644 index 00000000..027c9b46 --- /dev/null +++ b/plan/agw/research/token-route-validation-2026-10-20/probe-gateways.cjs @@ -0,0 +1 @@ +const root=process.cwd(),fs=require('fs');const {createPublicClient,http,parseAbi}=require(root+'/node_modules/viem');const p=root+'/plan/agw/research/token-route-validation-2026-10-20/probe.json',r=JSON.parse(fs.readFileSync(p));const cfg={'eip155:11155111':['https://ethereum-sepolia-rpc.publicnode.com','0x05bD7a3D18324c1F7e216f7fBF2b15985aE5281A'],'eip155:84532':['https://base-sepolia-rpc.publicnode.com','0xFD4fef1F43aFEc8b5bcdEEc47f35a1431479aC16'],'eip155:421614':['https://arbitrum-sepolia-rpc.publicnode.com','0x2cd870e0166Ba458dEC615168Fd659AacD795f34'],'eip155:97':['https://bsc-testnet-rpc.publicnode.com','0x44aFFC61983F4348DdddB886349eb992C061EaC0']};(async()=>{r.gatewayChecks=await Promise.all(Object.entries(cfg).map(async([chain,[url,address]])=>{const rpc=createPublicClient({transport:http(url,{timeout:10000,retryCount:0})});try{const blockNumber=await rpc.getBlockNumber();const tokens=[...new Set(r.presets.filter(x=>x.chain===chain).flatMap(x=>x.assets.map(a=>a.token)))];const results=await Promise.all(tokens.map(async token=>{try{return {token,supported:await rpc.readContract({address,abi:parseAbi(['function isSupportedToken(address) view returns (bool)']),functionName:'isSupportedToken',args:[token],blockNumber})}}catch(e){return {token,error:e.shortMessage||e.message}}}));return{chain,gateway:address,block:String(blockNumber),results}}catch(e){return{chain,error:e.shortMessage||e.message}}}));fs.writeFileSync(p,JSON.stringify(r,null,2));console.log(JSON.stringify(r.gatewayChecks,null,2));})(); diff --git a/plan/agw/research/token-route-validation-2026-10-20/probe-prc20.cjs b/plan/agw/research/token-route-validation-2026-10-20/probe-prc20.cjs new file mode 100644 index 00000000..4cad1390 --- /dev/null +++ b/plan/agw/research/token-route-validation-2026-10-20/probe-prc20.cjs @@ -0,0 +1,3 @@ +const root=process.cwd();const {createPublicClient,http,parseAbi,decodeAbiParameters}=require(root+'/node_modules/viem');const {PushChain}=require(root+'/dist/packages/core/src');const {SYNTHETIC_PUSH_ERC20}=require(root+'/dist/packages/core/src/lib/constants/chain'); +(async()=>{const rpc=createPublicClient({transport:http('https://evm.donut.rpc.push.org/',{timeout:12000,retryCount:0})});const block=await rpc.getBlockNumber();const net=PushChain.CONSTANTS.PUSH_NETWORK.TESTNET_DONUT;const report={at:new Date().toISOString(),block:String(block),chainId:await rpc.getChainId(),registry:[],presets:[]};const abi=parseAbi(['function SOURCE_CHAIN_NAMESPACE() view returns (string)','function SOURCE_TOKEN_ADDRESS() view returns (string)','function decimals() view returns (uint8)']);for(const [name,address] of Object.entries(SYNTHETIC_PUSH_ERC20[net]).filter(([k])=>!k.endsWith('_BNB'))){try{const chain=await rpc.readContract({address,abi,functionName:'SOURCE_CHAIN_NAMESPACE',blockNumber:block});let token;try{token=await rpc.readContract({address,abi,functionName:'SOURCE_TOKEN_ADDRESS',blockNumber:block});}catch{token=await rpc.readContract({address,abi:parseAbi(['function SOURCE_TOKEN_ADDRESS() view returns (address)']),functionName:'SOURCE_TOKEN_ADDRESS',blockNumber:block});}report.registry.push({name,address,chain,token});}catch(e){report.registry.push({name,address,error:e.shortMessage||e.message});}} +for(const cat of ['DEXES','LENDING','STAKING'])for(const chain of PushChain.utils.agentic.presets.list().presets.find(x=>x.constant===cat).chains.filter(x=>['eip155:11155111','eip155:84532','eip155:421614','eip155:97'].includes(x))){const r=PushChain.utils.agentic.presets.get(cat,{chainNamespace:chain,agent:'0x0000000000000000000000000000000000005678'});report.presets.push({category:cat,chain,assets:r.readiness.chains[0].bridgeAssets,issues:r.readiness.chains[0].issues});}require('fs').writeFileSync(root+'/plan/agw/research/token-route-validation-2026-10-20/probe.json',JSON.stringify(report,null,2));console.log(JSON.stringify(report,null,2));})().catch(e=>{console.error(e.shortMessage||e.message);process.exitCode=1}); diff --git a/plan/agw/research/token-route-validation-2026-10-20/probe.json b/plan/agw/research/token-route-validation-2026-10-20/probe.json new file mode 100644 index 00000000..97f27d61 --- /dev/null +++ b/plan/agw/research/token-route-validation-2026-10-20/probe.json @@ -0,0 +1,415 @@ +{ + "at": "2026-10-20T14:05:23.358Z", + "block": "24453693", + "chainId": 42101, + "registry": [ + { + "name": "pETH", + "address": "0x2971824Db68229D087931155C2b8bB820B275809", + "chain": "eip155:11155111", + "token": "0x0000000000000000000000000000000000000000" + }, + { + "name": "pETH_ARB", + "address": "0xc0a821a1AfEd1322c5e15f1F4586C0B8cE65400e", + "chain": "eip155:421614", + "token": "0x0000000000000000000000000000000000000000" + }, + { + "name": "pETH_BASE", + "address": "0xc7007af2B24D4eb963fc9633B0c66e1d2D90Fc21", + "chain": "eip155:84532", + "token": "0x0000000000000000000000000000000000000000" + }, + { + "name": "pBNB", + "address": "0x7a9082dA308f3fa005beA7dB0d203b3b86664E36", + "chain": "eip155:97", + "token": "0x0000000000000000000000000000000000000000" + }, + { + "name": "pSOL", + "address": "0x5D525Df2bD99a6e7ec58b76aF2fd95F39874EBed", + "chain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "token": "0x0000000000000000000000000000000000000000" + }, + { + "name": "USDT_ETH", + "address": "0x0f97A213207703923F5f0C613C9827f7C9A0f96B", + "chain": "eip155:11155111", + "token": "0xC4230aEaFcF6b8B49a7b4e53886420f00ff71876" + }, + { + "name": "USDC_ETH", + "address": "0x7A58048036206bB898008b5bBDA85697DB1e5d66", + "chain": "eip155:11155111", + "token": "0x97F477B7f970D47a87B42869ceeace218106152a" + }, + { + "name": "USDT_ARB", + "address": "0xFE6E9DF2BbC9ce05D98b83B1365df6DcA9951891", + "chain": "eip155:421614", + "token": "0xE30928528f52CAEeB75fB07837e22d77D47e9c07" + }, + { + "name": "USDC_ARB", + "address": "0x1091cCBA2FF8d2A131AE4B35e34cf3308C48572C", + "chain": "eip155:421614", + "token": "0x5dd39b0b3610F666F631a6506b7713EF83e1Ac5C" + }, + { + "name": "USDT_SOL", + "address": "0x4f1A3D22d170a2F4Bddb37845a962322e24f4e34", + "chain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "token": "0x0000000000000000000000000000000000000000" + }, + { + "name": "USDC_SOL", + "address": "0x04B8F634ABC7C879763F623e0f0550a4b5c4426F", + "chain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "token": "0x0000000000000000000000000000000000000000" + }, + { + "name": "USDT_BSC", + "address": "0x731aF1Da5365259d27528557EE4aFBA4baC90ef2", + "chain": "eip155:97", + "token": "0xE935d9c9C24D02E61186c640cc01d713C876d40F" + }, + { + "name": "USDC_BSC", + "address": "0x120EBf25Dad7D6a09Ad2316f23f9Be95DBb90639", + "chain": "eip155:97", + "token": "0xA8802F96cAd0d45343d9bc660B6f7d80050A660b" + }, + { + "name": "USDT_BASE", + "address": "0x148823809B853e1db187BC09A9ac909BC42F971a", + "chain": "eip155:84532", + "token": "0x4D7646B9eE3D68F4b0F135B5cbc66B00819F6b61" + }, + { + "name": "USDC_BASE", + "address": "0xD7C6cA1e2c0CE260BE0c0AD39C1540de460e3Be1", + "chain": "eip155:84532", + "token": "0x5c3504F0E3bA28FDc1F74234fE936518276AaBB8" + }, + { + "name": "WETH_ETH", + "address": "0x0d0dF7E8807430A81104EA84d926139816eC7586", + "chain": "eip155:11155111", + "token": "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14" + }, + { + "name": "stETH_ETH", + "address": "0xaf89E805949c628ebde3262e91dc4ab9eA12668E", + "chain": "eip155:11155111", + "token": "0x3e3FE7dBc6B4C189E7128855dD526361c49b40Af" + }, + { + "name": "DAI_SOL", + "address": "0x5861f56A556c990358cc9cccd8B5baa3767982A8", + "chain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "token": "0x0000000000000000000000000000000000000000" + } + ], + "presets": [ + { + "category": "DEXES", + "chain": "eip155:11155111", + "assets": [ + { + "token": "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14", + "prc20": "0x0d0dF7E8807430A81104EA84d926139816eC7586", + "status": "registered" + }, + { + "token": "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238", + "status": "unavailable" + } + ], + "issues": [ + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238", + "message": "No SDK PRC20 mapping for eip155:11155111:0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238 on TESTNET_DONUT. Choose a supported asset. This exact token needs a verified Push PRC20 route before it can be used." + } + ] + }, + { + "category": "DEXES", + "chain": "eip155:84532", + "assets": [ + { + "token": "0x4200000000000000000000000000000000000006", + "status": "unavailable" + }, + { + "token": "0x036CbD53842c5426634e7929541eC2318f3dCF7e", + "status": "unavailable" + } + ], + "issues": [ + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0x4200000000000000000000000000000000000006", + "message": "No SDK PRC20 mapping for eip155:84532:0x4200000000000000000000000000000000000006 on TESTNET_DONUT. Choose a supported asset. This exact token needs a verified Push PRC20 route before it can be used." + }, + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0x036CbD53842c5426634e7929541eC2318f3dCF7e", + "message": "No SDK PRC20 mapping for eip155:84532:0x036CbD53842c5426634e7929541eC2318f3dCF7e on TESTNET_DONUT. Choose a supported asset. This exact token needs a verified Push PRC20 route before it can be used." + } + ] + }, + { + "category": "DEXES", + "chain": "eip155:421614", + "assets": [ + { + "token": "0x980B62Da83eFf3D4576C647993b0c1D7faf17c73", + "status": "unavailable" + }, + { + "token": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "status": "unavailable" + } + ], + "issues": [ + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0x980B62Da83eFf3D4576C647993b0c1D7faf17c73", + "message": "No SDK PRC20 mapping for eip155:421614:0x980B62Da83eFf3D4576C647993b0c1D7faf17c73 on TESTNET_DONUT. Choose a supported asset. This exact token needs a verified Push PRC20 route before it can be used." + }, + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "message": "No SDK PRC20 mapping for eip155:421614:0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d on TESTNET_DONUT. Choose a supported asset. This exact token needs a verified Push PRC20 route before it can be used." + } + ] + }, + { + "category": "DEXES", + "chain": "eip155:97", + "assets": [ + { + "token": "0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd", + "status": "unavailable" + }, + { + "token": "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", + "status": "unavailable" + } + ], + "issues": [ + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd", + "message": "No SDK PRC20 mapping for eip155:97:0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd on TESTNET_DONUT. Choose a supported asset. This exact token needs a verified Push PRC20 route before it can be used." + }, + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", + "message": "No SDK PRC20 mapping for eip155:97:0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c on TESTNET_DONUT. Choose a supported asset. This exact token needs a verified Push PRC20 route before it can be used." + } + ] + }, + { + "category": "LENDING", + "chain": "eip155:11155111", + "assets": [ + { + "token": "0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5", + "status": "unavailable" + } + ], + "issues": [ + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5", + "message": "No SDK PRC20 mapping for eip155:11155111:0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5 on TESTNET_DONUT. Choose a supported asset. This exact token needs a verified Push PRC20 route before it can be used." + } + ] + }, + { + "category": "LENDING", + "chain": "eip155:421614", + "assets": [ + { + "token": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "status": "unavailable" + } + ], + "issues": [ + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "message": "No SDK PRC20 mapping for eip155:421614:0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d on TESTNET_DONUT. Choose a supported asset. This exact token needs a verified Push PRC20 route before it can be used." + } + ] + }, + { + "category": "LENDING", + "chain": "eip155:84532", + "assets": [ + { + "token": "0x810D46F9a9027E28F9B01F75E2bdde839dA61115", + "status": "unavailable" + }, + { + "token": "0x4616975f7E6045FD9737e95bC527e9e14c727BD2", + "status": "unavailable" + }, + { + "token": "0x663A6F02d547dFd639BF689FED298712f2FB69Fb", + "status": "unavailable" + } + ], + "issues": [ + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0x810D46F9a9027E28F9B01F75E2bdde839dA61115", + "message": "No SDK PRC20 mapping for eip155:84532:0x810D46F9a9027E28F9B01F75E2bdde839dA61115 on TESTNET_DONUT. Choose a supported asset. This exact token needs a verified Push PRC20 route before it can be used." + }, + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0x4616975f7E6045FD9737e95bC527e9e14c727BD2", + "message": "No SDK PRC20 mapping for eip155:84532:0x4616975f7E6045FD9737e95bC527e9e14c727BD2 on TESTNET_DONUT. Choose a supported asset. This exact token needs a verified Push PRC20 route before it can be used." + }, + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0x663A6F02d547dFd639BF689FED298712f2FB69Fb", + "message": "No SDK PRC20 mapping for eip155:84532:0x663A6F02d547dFd639BF689FED298712f2FB69Fb on TESTNET_DONUT. Choose a supported asset. This exact token needs a verified Push PRC20 route before it can be used." + } + ] + }, + { + "category": "LENDING", + "chain": "eip155:97", + "assets": [ + { + "token": "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", + "status": "unavailable" + }, + { + "token": "0x16227D60f7a0e586C66B005219dfc887D13C9531", + "status": "unavailable" + } + ], + "issues": [ + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", + "message": "No SDK PRC20 mapping for eip155:97:0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c on TESTNET_DONUT. Choose a supported asset. This exact token needs a verified Push PRC20 route before it can be used." + }, + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0x16227D60f7a0e586C66B005219dfc887D13C9531", + "message": "No SDK PRC20 mapping for eip155:97:0x16227D60f7a0e586C66B005219dfc887D13C9531 on TESTNET_DONUT. Choose a supported asset. This exact token needs a verified Push PRC20 route before it can be used." + } + ] + }, + { + "category": "STAKING", + "chain": "eip155:11155111", + "assets": [ + { + "token": "0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9", + "status": "unavailable" + } + ], + "issues": [ + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9", + "message": "No SDK PRC20 mapping for eip155:11155111:0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9 on TESTNET_DONUT. Choose a supported asset. This exact token needs a verified Push PRC20 route before it can be used." + } + ] + } + ], + "gatewayChecks": [ + { + "chain": "eip155:11155111", + "gateway": "0x05bD7a3D18324c1F7e216f7fBF2b15985aE5281A", + "block": "11955784", + "results": [ + { + "token": "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14", + "supported": true + }, + { + "token": "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238", + "supported": true + }, + { + "token": "0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5", + "supported": false + }, + { + "token": "0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9", + "supported": false + } + ] + }, + { + "chain": "eip155:84532", + "gateway": "0xFD4fef1F43aFEc8b5bcdEEc47f35a1431479aC16", + "block": "48368455", + "results": [ + { + "token": "0x4200000000000000000000000000000000000006", + "supported": true + }, + { + "token": "0x036CbD53842c5426634e7929541eC2318f3dCF7e", + "supported": true + }, + { + "token": "0x810D46F9a9027E28F9B01F75E2bdde839dA61115", + "supported": false + }, + { + "token": "0x4616975f7E6045FD9737e95bC527e9e14c727BD2", + "supported": false + }, + { + "token": "0x663A6F02d547dFd639BF689FED298712f2FB69Fb", + "supported": false + } + ] + }, + { + "chain": "eip155:421614", + "gateway": "0x2cd870e0166Ba458dEC615168Fd659AacD795f34", + "block": "321080510", + "results": [ + { + "token": "0x980B62Da83eFf3D4576C647993b0c1D7faf17c73", + "supported": true + }, + { + "token": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "supported": true + } + ] + }, + { + "chain": "eip155:97", + "gateway": "0x44aFFC61983F4348DdddB886349eb992C061EaC0", + "block": "137899664", + "results": [ + { + "token": "0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd", + "supported": false + }, + { + "token": "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", + "supported": false + }, + { + "token": "0x16227D60f7a0e586C66B005219dfc887D13C9531", + "supported": false + } + ] + } + ] +} \ No newline at end of file From 55ca20b726df42593480d6681a6eab84cf09581e Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Tue, 20 Oct 2026 19:55:26 +0530 Subject: [PATCH 62/68] docs: clarify pending marketplace contract questions --- plan/SDK-CHANGELOG.md | 4 +++ plan/marketplace/questions.md | 64 ++++++----------------------------- 2 files changed, 15 insertions(+), 53 deletions(-) diff --git a/plan/SDK-CHANGELOG.md b/plan/SDK-CHANGELOG.md index c74c31a1..7a028674 100644 --- a/plan/SDK-CHANGELOG.md +++ b/plan/SDK-CHANGELOG.md @@ -4,6 +4,10 @@ Running history for work continued on `feat/agw-sdk-v4`, covering AGW, marketpla For each meaningful checkpoint, add a dated entry with the change, decisions, validation, remaining work and relevant commit/evidence links. Keep earlier entries as history and mark superseded decisions explicitly. Distinguish implemented code, planning, local/fork checks, funded execution, Git delivery and package publication. Git history for this file records the exact commit introducing each checkpoint. +## 2026-10-20 — concise contracts-team handoff + +Reduced [pending questions](marketplace/questions.md) to the two current dependencies: canonical CEA deployments and the shared JobSpec/evaluator interface. Removed resolved and deferred discussions from the handoff; earlier context remains in Git history and the research docs. Documentation only; no SDK behavior changed. + ## 2026-10-20 — SDK-only completion before contract/deployment handoff **Implemented:** opening proof and mined-input recovery without re-signing; immutable reviewed inputs; event-hash/transaction-input recovery for same-block and archive-less card history; resumable paid previews with zero new payment, direct prepared-read sending and ABI-name/decimal descriptions; exact watcher cursors, deduplication, callback isolation and canonical-cursor reorg stop; provider write simulation. Native single/atomic sends now preserve broadcast hashes after receipt/index failures and cannot fall back after broadcast. Signature fixtures compile from repo-owned source; the CI reporter derives success from final counts instead of Jest's pre-final flag. diff --git a/plan/marketplace/questions.md b/plan/marketplace/questions.md index 85aab4cd..520e571f 100644 --- a/plan/marketplace/questions.md +++ b/plan/marketplace/questions.md @@ -1,61 +1,19 @@ -# Questions to share — drafts, not posted +# Agentic marketplace — questions for the contracts team -**SDK-only implementation and acceptance are complete for the current EVM v2 scope.** This includes real ERC-1271/7702 fixtures, receipt and same-block history recovery, paid-read resumption, watcher cursors, live origin bridging, principal deposits, atomic escrow and manual-evaluator payouts. No question or comment has been posted. See [SDK readiness](sdk-readiness.md) before sharing anything below. +## 1. Which CEA deployments should the SDK and marketplace use? -## Current team dependencies — only these need answers now +The SDK and marketplace registry use different CEA factories on **Sepolia, Base Sepolia and Arbitrum Sepolia**. They derive different wallet addresses, so the SDK blocks opening jobs with `CEA_MISMATCH`. BSC Testnet matches and works. -1. **Canonical CEA deployment on Sepolia, Base Sepolia and Arbitrum Sepolia:** which factory/implementation manifests should the live routing stack and marketplace both use? [Exact differences and evidence](implementation-status.md#destination-rollout-mismatch). Both factories answer but derive different accounts. BSC matches and passes live. The SDK retains its independent derivation check; global routing addresses were not changed to force a match. -2. **Automatic evaluation:** which shared JobSpec package/commit, compatible hook/evaluator deployment, and public verify/retry ABI are authoritative? Current v2 and the linked evaluator differ in field order, enums, reads, checks and logic. The SDK has no safe automatic endpoint to invoke until that contract boundary is delivered. Details below. +**Please confirm the canonical CEA factory and proxy implementation for each chain, and whether SDK routing or the marketplace registry needs updating.** -Prepared October 20 after fresh Notion discussions, pinned source review, unfunded tests and Donut read-only checks. Lead with the concrete mismatch and proposal; do not resend historical questions already answered below. +[Current address comparison](implementation-status.md#destination-rollout-mismatch) -## Zaryab, with Nilesh / Aman: canonical wire before automatic evaluation +## 2. Which JobSpec format and evaluator should the SDK integrate? -**Which exact shared JobSpec package/commit should the SDK target for the next compatible marketplace + hook + evaluator deployment?** Deployed marketplace v2 `443b4e2` uses `(reads,checks,logic,allowedMutability,origin,executeBy,failFinalAt)`, direct check indices, and NONE=0. Nilesh's [October 16 linked source](https://github.com/pushchain/push-chain-core-contracts/blob/8059817591cca16c59f1cc154f475f51e1736a67/src/agentic-commerce-8183/libraries/JobSpecTypes.sol) uses timing first, PRE/POST reads, left/right sums, CHECK leaves, and NONE=1/BOTH=0. Controlled vectors are incompatible. Proposal: build the current v2/manual-evaluator SDK profile now; coordinate one shared schema and deployment change before automated evaluation, without an SDK-only translation of signed bytes. +The deployed marketplace uses a manual EOA evaluator. Its JobSpec format is incompatible with the linked evaluator implementation, including field order and enum values. `client.job.verify` is therefore disabled. -## Historical — public approvals and deposit shape +**Please provide:** -Implemented against deployed v2. This is documentation alignment, not a remaining SDK blocker. - -**Should the SDK now follow deployed v2 D1 and remove `rules.approvals[]`, `skipApprovals`, and owner-approval deposit steps from page 6?** V2 permits agent `approve` with a pinned nonzero spender and capped amount and has no approvals array. Page 6 still rejects approve and exposes the old fields. Proposal: retain pinned approvals as allowedCalls and make deposit about principal/fee/PC, with explicit execution prerequisites. This confirms the public contract rather than asking for a feature already delivered. - -## Deferred product scope — M4 in the first release - -**Can marketplace authoring require `allowedMutability: NONE` for the initial release, leaving other enum values representable but unsupported until the proposal/acceptance protocol is delivered?** Current hook ignores replacements; non-NONE flags are accepted but inert. A future mutable flow needs the client's exact expectedSpecHash/revision checked atomically at fund alongside budget. SDK rereads cannot close the same-price front-run. If mutability is required now, define the authenticated CLIENT/BOTH route and versioned fund payload with the evaluator team first. - -## Historical — cancel surface and permission cleanup - -Client cancel/revoke is implemented and accepted locally/live. Automatic provider/evaluator cleanup needs a contract authority design only if that later feature is requested. - -**Add `client.job.cancel` for an Open job, and should the AGW owner path atomically reject + revoke that job's permission?** The kernel already permits client reject; the SDK draft omits the method after removing evaluatorOnly.reject. Real-v6 fork proof shows cancel alone frees the marketplace slot but old permissions remain enabled after a new job opens. A single existing owner batch rejects and revokes successfully, with no new AGW role. Provider/evaluator-driven automatic cleanup remains a separate contract design; confirm that boundary and the expected behavior for terminal jobs. - -## Historical — accepted price - -Explicit reviewed budgets are implemented; the client does not silently accept a re-quote. - -**For the first marketplace release, is funding fixed to the opened card version's reviewed providerFee, or may a user explicitly accept a different provider quote?** Page 7 alternates between passing the card price and reading the latest stored budget. Contract test proves a job can fund at 3× card fee if the client supplies that expectedBudget. Proposal: never silently adopt the latest price; fixed-price flow uses the opened version, negotiation requires an explicit reviewed quote/expected amount. - -## Historical — pure read-authoring interface - -Implemented: additive pure preparation, direct sending of resolved prepared reads and paid JobSpec preview/resumption. - -**Confirm an additive pure `client.universal.read.prepare` authoring API alongside existing async `universal.prepareRead(subject, options)`, or choose an adapter over that existing surface.** Current prepareRead produces paid-request/preflight data and does network reads; the page needs synchronous logical reads with output-layout codes and preserved WALLET/PARAM metadata. These are different representations. Proposal: share parsing/ABI encoding while retaining existing read APIs and introducing a distinct typed authoring representation. - -## Zaryab / Aman: smaller delivery discrepancies - -- Page 3 calls createJob hookable on Push, while the deployed kernel has no createJob hooks. Is this intentionally deferred? It need not block current marketplace SDK work; label it accurately. -- Confirm the eventual compatible evaluator delivery/ABI instead of wrapping a guessed `verify`: linked code uses hook-only verifyFromSubmit and public sendReads/retrySnapshot; the live marketplace evaluator is an EOA. Capability gating can ship now. - -## Wording to confirm during UX acceptance - -Page 6's dated decision chooses client submission and defers relay, while an example still defaults external users to relay=true. Follow the dated decision. Verify the native/EVM-owner signing UX and distinguish “one OwnerIntent authorization” from “one total wallet prompt”: self-submitting the transaction may require another signature. No relayer service is identified by these docs. - -## Already answered — do not block SDK work on these again - -- **K-12/payment token:** v2 intentionally ships with kernel pUSDC only; registration rejects other tokens. Future per-job tokens are a separately versioned kernel extension, not a prerequisite to implement v2. -- **Page 8:** no client.evaluation namespace in v1. Helpers are utils.job/utils.market; job-side reads belong to client.job. -- **Card enumeration:** agentCardCount + getAgentCard and agentCardOf exist; SDK can walk IDs with bounded reads. No list/indexer service is required for the demo. -- **Card identity/versioning:** on-chain integer ID, one card per provider, update increments version and clears verification; old hash-ID/signed-document proposals are superseded. -- **Opening funds:** openJob moves none; deposits and escrow funding are separate. -- **Markers:** contract FillSource.CEA/TargetSource.CEA stay named that way; public SDK uses WALLET. Marker wire hashes are published. -- **Recurring jobs/fees/ratings:** future research or placeholders; do not invent a renewal flow, rating service or fee policy. +- The final shared JobSpec Solidity definition or commit. +- Compatible hook/evaluator deployment addresses and ABIs for Push Donut. +- The public function signatures the SDK should call to verify and retry evaluation. From 525c7186795b43ce1d9c9436701080826b049e22 Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Tue, 20 Oct 2026 20:17:20 +0530 Subject: [PATCH 63/68] fix(core): clarify agentic creation permissions and route guidance --- packages/core/AGW.md | 8 +++ .../agentic/__tests__/creation-errors.spec.ts | 22 ++++++++ .../agentic/__tests__/preset-routes.spec.ts | 54 +++++++++++++++++++ .../core/src/lib/agentic/error-messages.ts | 2 + packages/core/src/lib/agentic/errors.ts | 2 +- .../core/src/lib/agentic/presets/index.ts | 2 +- .../core/src/lib/agentic/presets/routes.ts | 2 +- packages/core/src/lib/agentic/public-rule.ts | 11 ++++ .../creation-ui-guidance-2026-10-20.md | 9 ++++ 9 files changed, 109 insertions(+), 3 deletions(-) create mode 100644 plan/agw/research/creation-ui-guidance-2026-10-20.md diff --git a/packages/core/AGW.md b/packages/core/AGW.md index afc1550a..0b6d00bb 100644 --- a/packages/core/AGW.md +++ b/packages/core/AGW.md @@ -353,3 +353,11 @@ Uniswap uses destination WETH/Circle USDC; Aave uses its faucet LINK. Their gene 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. 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. + +### Creation UI: apps, tokens and preset availability + +A rule requires at least one allowed function, even when tokens and limits are selected. A tokens-only rule returns `INVALID_RULE`, with `details.reason = 'ALLOWED_FUNCTION_REQUIRED'` and actionable `userMessage`. App selection can only be hidden if the application explicitly supplies the intended function permissions; the SDK does not invent transfer recipients or permissions. + +`assets: []` remains valid for a universal rule with allowed calls. It grants no token transfers from Push; it never means all tokens. Allowed calls may still interact with destination-held assets under their configured constraints. There is no all-token wildcard. List each permitted token and cap explicitly (at most eight assets). + +For presets, check `readiness.ready` before enabling Create. Display the per-chain issues and the affected token address. Empty selections explain that transfers from Push are disabled. `BRIDGE_ASSET_UNAVAILABLE` identifies an unverified SDK route, not proof that no deployment exists anywhere. Do not substitute a routed token solely because its symbol matches: the protocol must support that exact address, and swaps need compatible liquidity. A transfer-only helper and additional token routes are not included in this update. diff --git a/packages/core/src/lib/agentic/__tests__/creation-errors.spec.ts b/packages/core/src/lib/agentic/__tests__/creation-errors.spec.ts index 1f4538dc..c7f4d052 100644 --- a/packages/core/src/lib/agentic/__tests__/creation-errors.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/creation-errors.spec.ts @@ -202,3 +202,25 @@ it.each([ ).toContain(text); } ); + +it.each([undefined, []])( + 'rejects a tokens-only rule with actionable guidance before signing (%j)', + async (allowedCalls) => { + const rt = mockRuntime(new FakeChain(), { signer: ADDR.owner }); + const sdk = new AgenticNamespaceImpl(rt); + const { rules } = agenticPresets.get('LENDING', options); + await expect( + sdk.create('Tokens only', { + rules: [{ ...rules[0], allowedCalls } as never], + }) + ).rejects.toMatchObject({ + code: 'INVALID_RULE', + details: { reason: 'ALLOWED_FUNCTION_REQUIRED', field: 'allowedCalls' }, + userMessage: expect.stringContaining( + 'Selecting tokens and limits alone does not authorize transfers' + ), + }); + expect(rt.executeMock).not.toHaveBeenCalled(); + expect(rt.atomicMock).not.toHaveBeenCalled(); + } +); diff --git a/packages/core/src/lib/agentic/__tests__/preset-routes.spec.ts b/packages/core/src/lib/agentic/__tests__/preset-routes.spec.ts index 5b8ca40b..789ea6dd 100644 --- a/packages/core/src/lib/agentic/__tests__/preset-routes.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/preset-routes.spec.ts @@ -90,3 +90,57 @@ it('supports the TESTNET alias, rejects invalid modes and preserves empty select expect(empty.readiness.chains[0].selectedAssets).toEqual([]); expect(empty.readiness.ready).toBe(false); }); + +it('explains empty tokens without expanding them into unrestricted permissions', () => { + const res = agenticPresets.get('LENDING', { ...options, assets: [] }); + expect(res.rules[0].assets).toEqual([]); + expect(res.readiness.ready).toBe(false); + expect(res.readiness.chains[0].issues).toContainEqual( + expect.objectContaining({ + code: 'ASSETS_REQUIRED', + message: expect.stringContaining( + 'transfers from Push are disabled, not unrestricted' + ), + }) + ); +}); +it('reports exact unavailable assets across all nine testnet preset combinations', () => { + const chains = [ + CHAIN.ETHEREUM_SEPOLIA, + CHAIN.BASE_SEPOLIA, + CHAIN.ARBITRUM_SEPOLIA, + CHAIN.BNB_TESTNET, + ]; + let checked = 0; + for (const category of ['DEXES', 'LENDING', 'STAKING'] as const) { + const entry = agenticPresets + .list() + .presets.find((p) => p.constant === category)!; + for (const chainNamespace of entry.chains.filter((c) => + chains.includes(c as never) + )) { + const res = agenticPresets.get(category, { + agent: ADDR.agent, + chainNamespace, + }); + expect(res.readiness.ready).toBe(false); + const state = res.readiness.chains[0]; + expect(res.rules[0].assets).toEqual(state.selectedAssets); + for (const asset of state.bridgeAssets.filter( + (a) => a.status === 'unavailable' + )) { + expect(state.issues).toContainEqual( + expect.objectContaining({ + code: 'BRIDGE_ASSET_UNAVAILABLE', + token: asset.token, + message: expect.stringContaining( + 'only if the selected app supports that exact token address' + ), + }) + ); + } + checked++; + } + } + expect(checked).toBe(9); +}); diff --git a/packages/core/src/lib/agentic/error-messages.ts b/packages/core/src/lib/agentic/error-messages.ts index 6202aae7..8c4deb9f 100644 --- a/packages/core/src/lib/agentic/error-messages.ts +++ b/packages/core/src/lib/agentic/error-messages.ts @@ -66,6 +66,8 @@ export function agenticUserMessage( return 'This preset is unavailable for the selected network.'; } if (code !== 'INVALID_RULE') return MESSAGES[code]; + if (details?.['reason'] === 'ALLOWED_FUNCTION_REQUIRED') + return 'Add at least one allowed function. Selecting tokens and limits alone does not authorize transfers.'; if (/validUntil|expiry|expired|future.*timestamp/i.test(diagnostic)) return 'Choose an expiry date in the future.'; if (/label.*(64|length|most)/i.test(diagnostic)) diff --git a/packages/core/src/lib/agentic/errors.ts b/packages/core/src/lib/agentic/errors.ts index 3a739c22..41f66c0b 100644 --- a/packages/core/src/lib/agentic/errors.ts +++ b/packages/core/src/lib/agentic/errors.ts @@ -181,7 +181,7 @@ export function tokenRouteUnavailable( const message = `This token cannot be sent from Push to ${network}. Choose a token with a supported Push route.`; return new AgenticError(AGENTIC_ERROR_CODE.TOKEN_ROUTE_UNAVAILABLE, message, { userMessage: message, - hint: 'Choose a supported token on this network, or wait for a verified PRC20 route for this exact token address. Token symbols alone do not identify a route.', + hint: 'Choose a supported token on this network, or wait for a verified PRC20 route for this exact token address. The selected app must also support that exact token address; matching symbols are not sufficient.', details: { token, chainNamespace, diff --git a/packages/core/src/lib/agentic/presets/index.ts b/packages/core/src/lib/agentic/presets/index.ts index 160dd9b1..b98ba0fd 100644 --- a/packages/core/src/lib/agentic/presets/index.ts +++ b/packages/core/src/lib/agentic/presets/index.ts @@ -411,7 +411,7 @@ export function buildPresetApi( issues.push({ code: 'ASSETS_REQUIRED', message: - 'Choose tokens and their limits, then regenerate this preset.', + 'No tokens selected: transfers from Push are disabled, not unrestricted. Choose explicit tokens and limits, then regenerate this preset.', }); if (chain.swapRouters?.length && selectedAssets.length < 2) issues.push({ diff --git a/packages/core/src/lib/agentic/presets/routes.ts b/packages/core/src/lib/agentic/presets/routes.ts index 8146d138..c18269d8 100644 --- a/packages/core/src/lib/agentic/presets/routes.ts +++ b/packages/core/src/lib/agentic/presets/routes.ts @@ -45,7 +45,7 @@ export function presetRoutes( issues.push({ code: 'BRIDGE_ASSET_UNAVAILABLE', token, - message: `No SDK PRC20 mapping for ${chain}:${token} on ${network}. Choose a supported asset. This exact token needs a verified Push PRC20 route before it can be used.`, + message: `No SDK PRC20 mapping for ${chain}:${token} on ${network}. This preset cannot be created with this token until its Push route is verified. Choose a routed token only if the selected app supports that exact token address.`, }); return { token, status: 'unavailable' as const }; } diff --git a/packages/core/src/lib/agentic/public-rule.ts b/packages/core/src/lib/agentic/public-rule.ts index abf45404..12e49cd4 100644 --- a/packages/core/src/lib/agentic/public-rule.ts +++ b/packages/core/src/lib/agentic/public-rule.ts @@ -148,6 +148,17 @@ export async function normalizePublicRule( r.validUntil >= 2 ** 48 ) throw invalid('validUntil must be a future uint48 timestamp'); + if ( + r.allowedCalls === undefined || + (Array.isArray(r.allowedCalls) && !r.allowedCalls.length) + ) + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'Add at least one allowed function. Selecting tokens and limits alone does not authorize transfers.', + { + details: { reason: 'ALLOWED_FUNCTION_REQUIRED', field: 'allowedCalls' }, + } + ); if ( !Array.isArray(r.allowedCalls) || r.allowedCalls.length < 1 || diff --git a/plan/agw/research/creation-ui-guidance-2026-10-20.md b/plan/agw/research/creation-ui-guidance-2026-10-20.md new file mode 100644 index 00000000..4b14899a --- /dev/null +++ b/plan/agw/research/creation-ui-guidance-2026-10-20.md @@ -0,0 +1,9 @@ +# Creation guidance after alpha.4 feedback + +Implemented actionable missing-function validation (`INVALID_RULE`, reason `ALLOWED_FUNCTION_REQUIRED`), clearer empty-asset preset readiness, and exact-token/protocol compatibility guidance for unavailable routes. Assets and limits are never silently replaced or broadened. + +All nine testnet preset/network combinations have regression coverage for unavailable route reporting and preserved assets. Missing/empty functions fail before signing. Empty universal assets retain zero Push token-export authority; existing local v6 contract coverage demonstrates the zero-cap gas-token representation. No fresh live transactions were run for this copy/validation change. + +Remaining: route addresses/provisioning from the core/node/gateway team; verified protocol-compatible alternatives before changing preset defaults; product agreement on recipients/limits before any transfer-only helper. No unrestricted-token wildcard is introduced. + +Validation: 402 AGW unit tests passed across 25 suites; core build, spec typecheck, package checks and seven guide example typechecks passed. SDK edits sync to v5 without this plan file. npm publication is user-managed. From 59891265379ce2feff855024016918fc450e2e66 Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Wed, 21 Oct 2026 09:05:41 +0530 Subject: [PATCH 64/68] fix(core): route exact AGW tokens and size agent gas from the pool - Resolve the node-registered Circle USDC routes (Sepolia, Base, Arbitrum Sepolia) by exact address for agentic wallets; DEXES Sepolia and LENDING Arbitrum Sepolia presets become route-ready. - AGW gas budget never attaches less than the Push pool cost plus 20%, keeps the over-$10 share and excludes protocolFee; BNB testnet gas is valued at the pool rate because no BNB/USD feed exists. - Agent EVM sends default to 1,000,000 gas for token exports or multi-call payloads (the 500,000 base ran out on a Sepolia swap); omitted Solana gas uses route and finalize sizing. - Refuse an explicit gasLimit below the chain base, a Solana budget still short after one re-quote, and a zero Solana maxGasPerCall. - Correct the Base Sepolia WETH address. - Add opt-in live groups (unchanged and routed presets, gas, agent SPL, exact routes, Solana Memo) and read-only compatibility, gas-quote and route-registry drift scripts. --- packages/core/AGW.md | 22 +- .../__agw-local__/preset-acceptance.spec.ts | 105 +++++ packages/core/__e2e__/agw/_fixture.ts | 11 +- .../__e2e__/agw/exact-routes-live.spec.ts | 120 ++++++ packages/core/__e2e__/agw/gas-live.spec.ts | 173 ++++++++ .../__e2e__/agw/presets-acceptance.spec.ts | 408 ++++++++++++++++++ .../core/__e2e__/agw/svm-agent-spl.spec.ts | 307 +++++++++++++ .../core/__e2e__/agw/svm-memo-live.spec.ts | 182 ++++++++ packages/core/__e2e__/ci/preflight.ts | 19 +- packages/core/__e2e__/ci/suite.ts | 59 +++ .../core/__e2e__/shared/agw-gas-evidence.ts | 44 ++ .../__e2e__/shared/agw-preset-acceptance.ts | 108 +++++ packages/core/scripts/check-agw-gas-quotes.js | 122 ++++++ .../scripts/check-agw-preset-compatibility.js | 323 ++++++++++++++ .../core/scripts/check-agw-route-registry.js | 192 +++++++++ .../lib/agentic/__tests__/gas-budget.spec.ts | 220 ++++++++++ .../agentic/__tests__/preset-routes.spec.ts | 11 +- .../src/lib/agentic/__tests__/send.spec.ts | 34 +- .../__tests__/svm-agent-send-defaults.spec.ts | 77 ++++ .../lib/agentic/__tests__/svm-quote.spec.ts | 13 + .../__tests__/svm-send-defaults.spec.ts | 66 +++ .../agentic/__tests__/token-routes.spec.ts | 123 ++++++ .../src/lib/agentic/execution/gas-budget.ts | 69 +++ .../src/lib/agentic/execution/outbound.ts | 14 +- .../src/lib/agentic/execution/svm-public.ts | 5 +- .../src/lib/agentic/management/svm-public.ts | 3 + .../core/src/lib/agentic/presets/routes.ts | 7 +- packages/core/src/lib/agentic/runtime.ts | 68 ++- packages/core/src/lib/agentic/token-routes.ts | 93 ++++ packages/core/src/lib/constants/tokens.ts | 2 +- .../__tests__/gas-usd-sizer.spec.ts | 59 +++ .../orchestrator/internals/gas-calculator.ts | 38 +- .../orchestrator/internals/gas-pool-quote.ts | 114 +++++ .../orchestrator/internals/gas-usd-sizer.ts | 58 ++- .../lib/orchestrator/internals/svm-rent.ts | 4 + 35 files changed, 3189 insertions(+), 84 deletions(-) create mode 100644 packages/core/__agw-local__/preset-acceptance.spec.ts create mode 100644 packages/core/__e2e__/agw/exact-routes-live.spec.ts create mode 100644 packages/core/__e2e__/agw/gas-live.spec.ts create mode 100644 packages/core/__e2e__/agw/presets-acceptance.spec.ts create mode 100644 packages/core/__e2e__/agw/svm-agent-spl.spec.ts create mode 100644 packages/core/__e2e__/agw/svm-memo-live.spec.ts create mode 100644 packages/core/__e2e__/shared/agw-gas-evidence.ts create mode 100644 packages/core/__e2e__/shared/agw-preset-acceptance.ts create mode 100644 packages/core/scripts/check-agw-gas-quotes.js create mode 100644 packages/core/scripts/check-agw-preset-compatibility.js create mode 100644 packages/core/scripts/check-agw-route-registry.js create mode 100644 packages/core/src/lib/agentic/__tests__/gas-budget.spec.ts create mode 100644 packages/core/src/lib/agentic/__tests__/svm-agent-send-defaults.spec.ts create mode 100644 packages/core/src/lib/agentic/__tests__/svm-send-defaults.spec.ts create mode 100644 packages/core/src/lib/agentic/__tests__/token-routes.spec.ts create mode 100644 packages/core/src/lib/agentic/execution/gas-budget.ts create mode 100644 packages/core/src/lib/agentic/token-routes.ts create mode 100644 packages/core/src/lib/orchestrator/internals/gas-pool-quote.ts diff --git a/packages/core/AGW.md b/packages/core/AGW.md index 0b6d00bb..78d4bd36 100644 --- a/packages/core/AGW.md +++ b/packages/core/AGW.md @@ -136,7 +136,7 @@ Creation and rule-preparation errors include a zero-based `details.ruleIndex` wh A DEX condition-limit failure reports `details.reason = 'RULE_CONSTRAINT_LIMIT'`, `actual`, `limit` and `callCount`. Conditions here are generated input checks (for example token, recipient and amount checks), rather than the number of visible function names. A stock two-token, single-router preset contains six allowed-call entries and twenty conditions. Appending the same call list again makes forty conditions. The SDK rejects this; it does not deduplicate, remove conditions or split authority automatically. Preserve per-chain rules and regenerate after edits rather than appending generated calls. -For the review screen, show the actual network (including testnet name), selected token addresses and limits. Label maxGasPerCall as a maximum PC gas budget, not a guaranteed fee or execution gas-unit count. maxTotal meters cumulative Push outbounds; it is not a lifetime destination-spend limit. +For the review screen, show the actual network (including testnet name), selected token addresses and limits. Label maxGasPerCall as a maximum PC gas budget, not a guaranteed fee or execution gas-unit count. maxTotal meters cumulative Push outbounds, including outbounds whose destination execution later fails; it is not a lifetime destination-spend limit. Destination pins and maxValue limit each call separately. ## Solana destinations @@ -256,7 +256,7 @@ These are small, protocol-specific subsets chosen to fit the 32-call/32-pin ceil | Arbitrum Sepolia | WETH / Circle USDC | Aave USDC | | BSC testnet | WBNB / Venus USDT | Venus USDT, USDC | -Staking defaults are ETH/stETH/wstETH on Ethereum and the reviewed EigenLayer strategy's WETH on Sepolia. Testnet tokens with similar names can have different addresses; the returned addresses are authoritative. Defaults do not guarantee active reserves, liquidity or a Push PRC20 route. An unmodified preset cannot be granted when its assets lack matching PRC20 routes. The SDK preserves the selected tokens and caps and reports unavailable routes; it never removes assets to bypass this check. No runtime metadata/price fetch is added to get. +Staking defaults are ETH/stETH/wstETH on Ethereum and the reviewed EigenLayer strategy's WETH on Sepolia. Testnet tokens with similar names can have different addresses; the returned addresses are authoritative. Defaults do not guarantee active reserves, liquidity or a Push PRC20 route. An unmodified preset cannot be granted when its assets lack matching PRC20 routes. The SDK preserves the selected tokens and caps and reports unavailable routes; it never removes assets to bypass this check. On Donut, every default asset of DEXES Sepolia and LENDING Arbitrum Sepolia currently has a registered route; the other testnet combinations do not. No runtime metadata/price fetch is added to get. ### Funding and release-network checks @@ -264,7 +264,7 @@ Missing PRC20 registry entries produce `BRIDGE_ASSET_UNAVAILABLE`, and readiness The public preset API has no `funding` option. Remove it from existing integrations; supplying it now produces `INVALID_RULE` rather than silently changing permissions. Internal prefunded CEA test fixtures explicitly clear bridge assets to isolate protocol constraints. Those fixtures do not demonstrate that an unsupported preset route is executable. -Existing mappings distinguish token identity by chain and address, including address casing for EVM. WETH/stETH Sepolia mappings and string/address-word source metadata are supported; mainnet or other-chain WETH is never aliased to them. Protocol mock LINK, Moonwell/Venus mocks and Circle testnet USDC can differ from the supported source tokens; they remain unavailable for bridge funding until real matching routes exist. +Existing mappings distinguish token identity by chain and address, including address casing for EVM. WETH/stETH Sepolia mappings and string/address-word source metadata are supported; mainnet or other-chain WETH is never aliased to them. Exact routes enabled in the Push node registry are also resolved by address: Circle testnet USDC on Sepolia, Base Sepolia and Arbitrum Sepolia maps to its own PRC20, separate from the routed mock USDC. Grant preparation still verifies each PRC20 source on chain. Protocol mock LINK, Moonwell/Venus tokens, Base/Arbitrum WETH, BNB testnet WBNB and the EigenLayer WETH remain unavailable for bridge funding until matching routes exist. ### Default permission policy @@ -360,4 +360,18 @@ A rule requires at least one allowed function, even when tokens and limits are s `assets: []` remains valid for a universal rule with allowed calls. It grants no token transfers from Push; it never means all tokens. Allowed calls may still interact with destination-held assets under their configured constraints. There is no all-token wildcard. List each permitted token and cap explicitly (at most eight assets). -For presets, check `readiness.ready` before enabling Create. Display the per-chain issues and the affected token address. Empty selections explain that transfers from Push are disabled. `BRIDGE_ASSET_UNAVAILABLE` identifies an unverified SDK route, not proof that no deployment exists anywhere. Do not substitute a routed token solely because its symbol matches: the protocol must support that exact address, and swaps need compatible liquidity. A transfer-only helper and additional token routes are not included in this update. +For presets, check `readiness.ready` before enabling Create. Display the per-chain issues and the affected token address. Empty selections explain that transfers from Push are disabled. `BRIDGE_ASSET_UNAVAILABLE` identifies an unverified SDK route, not proof that no deployment exists anywhere. Do not substitute a routed token solely because its symbol matches: the protocol must support that exact address, and swaps need compatible liquidity. A transfer-only helper is not included. An ERC20 transfer can be authorized explicitly with a `transfer(address,uint256)` allowed call pinned to a recipient and a per-transfer maximum; it also applies to that token already held in the wallet's destination account. + +### Exact-preset acceptance and gas evidence + +The opt-in `agw-presets-acceptance` group exercises all nine shipped testnet category/network combinations. It passes the returned `rules` unchanged to `create`, reads back every asset/cap/function/pin, and performs first-use and subsequent agent operations. Missing routes, protocols or exact PRC20 balances fail before funding; they do not count as passing acceptance. The opt-in `agw-presets-routed` group runs only the cases whose default assets are all routed (DEXES Sepolia and LENDING Arbitrum Sepolia); preflight checks readiness for the selected cases only. The earlier `agw-presets` and `agw-presets-expanded` protocol fixtures use prefunded destination assets and remain separate coverage. + +Read-only compatibility checks are available with `node packages/core/scripts/check-agw-preset-compatibility.js /tmp/compatibility.json` after building core. The check verifies known routed source identities (registry and exact node routes), live Aave reserves, Moonwell/Venus underlyings, the reviewed EigenLayer strategy and pools at the preset routers' factories, including each DEX preset's own default pair. A matching symbol alone is insufficient. RPC and read errors are recorded as unknown checks, never as compatibility or as missing routes. No default assets were changed. `node packages/core/scripts/check-agw-route-registry.js /tmp/registry.json` compares the SDK's routes with the Push node's token registry (uregistry): it fails on a mismatched or SDK-only route and lists enabled node routes the SDK does not resolve. + +`maxGasPerCall` is an owner-authorized ceiling on the PC attached to each outbound. The send-time `gasLimit` is a different field: the multiplier for the destination gas price. Omitted or zero uses the network base (500,000 on the EVM testnets, 960 on Solana devnet). Agent EVM sends without an explicit gasLimit instead use 2,000,000 on first use (the destination account is deployed), and 1,000,000 when they export a non-native token or make more than one destination call. A Sepolia Circle USDC export with approve and a Uniswap swap ran out of gas at the 500,000 base. An explicit value below the base is refused before quoting with `INVALID_RULE` and `details.minimum`. When omitted on Solana, the SDK raises the limit to cover finalization rent instead of using an EVM-style million-unit fallback. If a gas-price change leaves that budget short even after one re-quote, the send is refused before signing (`INCONSISTENT_READ`). + +The attached budget is at least $1 of PC: 10 PC at the fixed $0.10 rate used for Push-native agents, and less or more for agents signing from another chain, which are priced through that origin's Donut stable pool. It is never less than the current Push pool cost of the destination gas plus 20%. BNB testnet gas is valued at that pool rate, because no BNB/USD feed exists (the BSC gateway feed is ETH/USD). The gateway refunds unused PC in the same transaction. After the destination executes, the node also refunds unused destination gas, `(gasLimit − gasUsed) × gasPrice`, to the wallet as PC in a later Push transaction; this was verified on Donut for EVM and Solana. On October 20 the gas swaps actually consumed 0.0008-2.37 PC per send. 0.1 PC can never cover the minimum budget. The 20 PC preset ceiling covered the Sepolia, Base Sepolia, Arbitrum Sepolia and Solana devnet runs; BNB testnet first sends exceed it while Donut's BNB gas price is high. There is no cumulative gas cap; the wallet's PC balance is the only total limit. `node packages/core/scripts/check-agw-gas-quotes.js /tmp/quotes.json` records current quotes for Push-native and Sepolia-origin agents without signing. Quotes change; they are not fixed fees or a validated default for custom rules. + +The separate `agw-svm-agent-spl` group verifies the known devnet test harness's `receive_spl` instruction: wallet ATA pins, an amount ceiling, exact recipient credit and first/subsequent sends with omitted gas. It uses the existing counter program and does not certify a third-party Solana protocol. The gas evidence records Push transaction fees, attached quote budgets and destination fees separately. Run both new groups with the normal `__e2e__/ci/preflight.ts --group ...` and `__e2e__/ci/run.ts --group ...` commands. + +The `agw-gas` group measures first-use and subsequent native-token agent sends on Sepolia, Base Sepolia, Arbitrum Sepolia and BNB testnet using the existing counter fixtures. Its route/gas coverage is separate from protocol preset acceptance. diff --git a/packages/core/__agw-local__/preset-acceptance.spec.ts b/packages/core/__agw-local__/preset-acceptance.spec.ts new file mode 100644 index 00000000..7e7caa52 --- /dev/null +++ b/packages/core/__agw-local__/preset-acceptance.spec.ts @@ -0,0 +1,105 @@ +/** Exact default preset output -> real AGW/URP -> exact public readback. + * Source-token PRC20 metadata and gateway are local stand-ins. This proves SDK + * preservation with provisioned routes, not live route availability or delivery. + */ +import { getAddress, parseAbi, type Address } from 'viem'; +import { startHarness, type Harness } from './harness'; +import { PushChain } from '../src'; +import type { AgenticRuntime } from '../src/lib/agentic/runtime'; +import * as accountLookup from '../src/lib/universal/account/account'; +import { configId } from '../src/lib/agentic/codec/ids'; +import { + PRESET_ACCEPTANCE_CASES, + expectStoredPreset, +} from '../__e2e__/shared/agw-preset-acceptance'; +const sourceABI = parseAbi(['function setSourceTokenAddress(string)']); +const CEA = getAddress('0x000000000000000000000000000000000000cea1'); +const runtime = (c: PushChain) => + (c as unknown as { agenticRuntime: AgenticRuntime }).agenticRuntime; + +describe('unchanged default preset contract acceptance', () => { + let h: Harness, owner: PushChain, lookup: jest.SpyInstance; + const routes = new Map(); + beforeAll(async () => { + lookup = jest + .spyOn(accountLookup, 'convertExecutorToOrigin') + .mockResolvedValue({ account: null, exists: false }); + h = await startHarness(18555); + owner = await h.client(0); + runtime(owner).resolveCEA = async () => ({ + cea: CEA, + isDeployed: false, + }); + runtime(owner).resolvePrc20 = (token, chain) => { + const source = typeof token === 'string' ? token : token?.address; + const mapped = routes.get(`${chain}:${source?.toLowerCase()}`); + if (!mapped) throw new Error('Fixture route not provisioned'); + return mapped; + }; + }); + afterAll(async () => { + try { + await h?.stop(); + } finally { + lookup?.mockRestore(); + } + }); + it.each(PRESET_ACCEPTANCE_CASES)( + '%s %s preserves every generated asset, cap, function and pin', + async (category, chainNamespace) => { + const generated = PushChain.utils.agentic.presets.get(category, { + chainNamespace, + agent: h.wallets[1].account!.address, + }); + const before = JSON.stringify(generated.rules, (_k, v) => + typeof v === 'bigint' ? String(v) : v + ); + for (const asset of generated.rules[0].assets!) { + const source = getAddress( + typeof asset.token === 'string' ? asset.token : asset.token.address + ); + const key = `${chainNamespace}:${source.toLowerCase()}`; + if (!routes.has(key)) { + const mapped = await h.deploy( + 0, + 'HarnessPRC20', + 'HarnessFixtures.sol', + [chainNamespace, 18] + ); + await h.write(0, mapped, sourceABI, 'setSourceTokenAddress', [ + source, + ]); + routes.set(key, mapped); + } + } + const made = await owner.agentic.create('preset-exact', { + rules: generated.rules, + }); + const records = await owner.agentic.wallet(made.wallet).rules.list(); + expect(records.rules).toHaveLength(1); + const record = await owner.agentic + .wallet(made.wallet) + .rules.get(made.rulesIds[0]); + expectStoredPreset(generated.rules[0], record); + // Readback maps pins to agentic:wallet; check the stored destination itself. + const [action] = await h.publicClient.readContract({ + address: h.addresses.engine, + abi: h.generation.contracts.abis.engine, + functionName: 'getEnabledActions', + args: [made.wallet, made.rulesIds[0]], + }); + const config = await h.publicClient.readContract({ + address: h.addresses.rulesPolicy, + abi: h.generation.contracts.abis.policy, + functionName: 'getConfig', + args: [configId(made.wallet, made.rulesIds[0], action), made.wallet], + }); + expect(config.expectedCEA).toBe(CEA); + expect( + JSON.stringify(generated.rules, (_k, v) => + typeof v === 'bigint' ? String(v) : v + ) + ).toBe(before); + } + ); +}); diff --git a/packages/core/__e2e__/agw/_fixture.ts b/packages/core/__e2e__/agw/_fixture.ts index 649ccbb2..4ac49fba 100644 --- a/packages/core/__e2e__/agw/_fixture.ts +++ b/packages/core/__e2e__/agw/_fixture.ts @@ -34,6 +34,8 @@ export interface AgwFixture { agentAddress: Address; agent(wallet: Address, progressHook?: (e: unknown) => void): Promise; fundPC(to: Address, amount: bigint): Promise; + /** Funds the generated agent; already done unless setup deferred it. */ + fundAgent(): Promise; evidence(name: string, data: Record): void; teardown(): void; } @@ -46,7 +48,9 @@ const pushChainFor = (network: PUSH_NETWORK) => * the manifest, keys or wiring are missing. A selected agw run can never pass * without exercising a verified deployment. */ -export async function setupAgw(): Promise { +export async function setupAgw( + options: { deferAgentFunding?: boolean } = {} +): Promise { const manifest = loadAgwManifest(); if (manifest.network !== PUSH_NETWORK.TESTNET_DONUT) { throw new AgwPrerequisiteError('live AGW fixtures require Donut'); @@ -85,7 +89,9 @@ export async function setupAgw(): Promise { const r = await tx.wait(); if (r.status !== 1) throw new Error(`funding ${to} failed`); }; - await fundPC(agentAddress, parseEther(process.env['AGW_E2E_AGENT_PC'] ?? '0.5')); + const fundAgent = () => fundPC(agentAddress, parseEther(process.env['AGW_E2E_AGENT_PC'] ?? '0.5')); + // Deferred callers check their prerequisites first, so a blocked case spends nothing. + if (!options.deferAgentFunding) await fundAgent(); const logDir = join(__dirname, '..', '..', 'e2e-logs'); mkdirSync(logDir, { recursive: true }); @@ -107,6 +113,7 @@ export async function setupAgw(): Promise { agentAddress, agent: (wallet, progressHook) => evmClient(agentKey, chain, manifest.network, wallet, progressHook), fundPC, + fundAgent, evidence, teardown: () => resetAgenticGenerations(), }; diff --git a/packages/core/__e2e__/agw/exact-routes-live.spec.ts b/packages/core/__e2e__/agw/exact-routes-live.spec.ts new file mode 100644 index 00000000..e35d406b --- /dev/null +++ b/packages/core/__e2e__/agw/exact-routes-live.spec.ts @@ -0,0 +1,120 @@ +/** Live outbound settlement of the exact node-registered Circle USDC routes. + * Owner door, funds only: the Push PRC20 is burned and the exact Circle USDC is + * delivered to the owner's own address on each chain. Route evidence only; no + * preset or agent permission is exercised here. + */ +import '@e2e/shared/setup'; +import { + createPublicClient, + http, + encodeFunctionData, + erc20Abi, + parseEther, + type Hex, +} from 'viem'; +import { CHAIN } from '../../src'; +import { PUSH_NETWORK } from '../../src/lib/constants/enums'; +import { exactAgenticRoutes } from '../../src/lib/agentic/token-routes'; +import { AGW_E2E_ENABLED, evmClient, setupAgw } from './_fixture'; + +const d = AGW_E2E_ENABLED ? describe : describe.skip; +const AMOUNT = BigInt(10_000); // 0.01 USDC +const ENDPOINTS: Partial> = { + [CHAIN.ETHEREUM_SEPOLIA]: 'https://ethereum-sepolia-rpc.publicnode.com', + [CHAIN.BASE_SEPOLIA]: 'https://base-sepolia-rpc.publicnode.com', + [CHAIN.ARBITRUM_SEPOLIA]: 'https://arbitrum-sepolia-rpc.publicnode.com', +}; + +d('agw exact route outbound', () => { + async function run(chain: CHAIN) { + const [route] = exactAgenticRoutes(chain, PUSH_NETWORK.TESTNET_DONUT); + if (!route) throw new Error(`No exact route for ${chain}`); + const rpc = createPublicClient({ + transport: http(ENDPOINTS[chain]!, { timeout: 15000, retryCount: 1 }), + }); + if ((await rpc.getChainId()) !== Number(chain.split(':')[1])) + throw new Error('Destination RPC chain mismatch'); + const f = await setupAgw({ deferAgentFunding: true }); + try { + const prc20Balance = (holder: `0x${string}`) => + f.push.readContract({ + address: route.prc20, + abi: erc20Abi, + functionName: 'balanceOf', + args: [holder], + }); + if ((await prc20Balance(f.ownerAddress)) < AMOUNT) + throw new Error(`ROUTE_PREREQUISITE: owner lacks ${route.prc20}`); + const made = await f.owner.agentic.create('exact-route', { rules: [] }); + await f.fundPC(made.wallet, parseEther('21')); + await ( + await f.owner.universal.sendTransaction({ + to: route.prc20, + data: encodeFunctionData({ + abi: erc20Abi, + functionName: 'transfer', + args: [made.wallet, AMOUNT], + }), + }) + ).wait(); + const owner = await evmClient( + process.env['PUSH_PRIVATE_KEY'] as Hex, + CHAIN.PUSH_TESTNET_DONUT, + f.manifest.network, + made.wallet + ); + const recipient = f.ownerAddress; + const delivered = () => + rpc.readContract({ + address: route.source, + abi: erc20Abi, + functionName: 'balanceOf', + args: [recipient], + }); + const before = await delivered(); + const tx = await owner.universal.sendTransaction({ + to: { chain, address: recipient }, + funds: { + amount: AMOUNT, + token: { + symbol: route.symbol, + decimals: route.decimals, + address: route.source, + mechanism: 'approve', + }, + }, + }); + expect(tx.agentic?.door).toBe('owner'); + f.evidence('exact-route-submitted', { + chain, + wallet: made.wallet, + prc20: route.prc20, + source: route.source, + hash: tx.hash, + }); + const receipt = await tx.wait({ outboundTimeoutMs: 180000 }); + expect(receipt.externalStatus).toBe('success'); + const dest = await rpc.getTransactionReceipt({ + hash: receipt.externalTxHash as Hex, + }); + expect(dest.status).toBe('success'); + expect(await delivered()).toBe(before + AMOUNT); + expect(await prc20Balance(made.wallet)).toBe(BigInt(0)); + f.evidence('exact-route-delivered', { + chain, + hash: tx.hash, + destinationHash: receipt.externalTxHash, + destinationGasUsed: dest.gasUsed, + }); + } finally { + f.teardown(); + } + } + it('1. Sepolia Circle USDC', () => run(CHAIN.ETHEREUM_SEPOLIA), 600000); + it('2. Base Sepolia Circle USDC', () => run(CHAIN.BASE_SEPOLIA), 600000); + it( + '3. Arbitrum Sepolia Circle USDC', + () => run(CHAIN.ARBITRUM_SEPOLIA), + 600000 + ); +}); diff --git a/packages/core/__e2e__/agw/gas-live.spec.ts b/packages/core/__e2e__/agw/gas-live.spec.ts new file mode 100644 index 00000000..9e58a77a --- /dev/null +++ b/packages/core/__e2e__/agw/gas-live.spec.ts @@ -0,0 +1,173 @@ +/** Measure omitted destination gas on first/subsequent supported EVM routes. + * Uses the existing counter fixtures and native PRC20s, not unavailable presets. + */ +import '@e2e/shared/setup'; +import { + createPublicClient, + http, + encodeFunctionData, + erc20Abi, + parseAbi, + parseEventLogs, + parseEther, + type Hex, + type Address, +} from 'viem'; +import { CHAIN } from '../../src'; +import { getCEAAddress } from '../../src/lib/orchestrator/cea-utils'; +import { getNativePRC20ForChain } from '../../src/lib/orchestrator/internals/helpers'; +import { EVM_CHAIN_FIXTURES } from '../shared/chain-fixtures'; +import { observeAgwGas, recordAgwPushGas } from '../shared/agw-gas-evidence'; +import { AGW_E2E_ENABLED, setupAgw, inSeconds } from './_fixture'; +const d = AGW_E2E_ENABLED ? describe : describe.skip; +const AMOUNT = BigInt(10) ** BigInt(12); +const EXECUTED = parseAbi([ + 'event UniversalTxExecuted(bytes32 indexed subTxId, bytes32 indexed universalTxId, address indexed originCaller, address target, bytes data)', +]); +const ENDPOINTS: Partial> = { + [CHAIN.ETHEREUM_SEPOLIA]: 'https://ethereum-sepolia-rpc.publicnode.com', + [CHAIN.BASE_SEPOLIA]: 'https://base-sepolia-rpc.publicnode.com', + [CHAIN.ARBITRUM_SEPOLIA]: 'https://arbitrum-sepolia-rpc.publicnode.com', + [CHAIN.BNB_TESTNET]: 'https://bsc-testnet-rpc.publicnode.com', +}; +d('agw live gas sizing', () => { + async function run(chain: CHAIN) { + const counter = EVM_CHAIN_FIXTURES.find((x) => x.chain === chain)!.contracts + .counter as Address; + const rpc = createPublicClient({ + transport: http(ENDPOINTS[chain]!, { timeout: 15000 }), + }); + if ((await rpc.getChainId()) !== Number(chain.split(':')[1])) + throw new Error('Destination RPC chain mismatch'); + if (!(await rpc.getCode({ address: counter }))) + throw new Error('GAS_PREREQUISITE: counter fixture has no code'); + const f = await setupAgw(); + try { + const token = getNativePRC20ForChain(chain, f.manifest.network); + if ( + (await f.push.readContract({ + address: token, + abi: erc20Abi, + functionName: 'balanceOf', + args: [f.ownerAddress], + })) < + AMOUNT * BigInt(2) + ) + throw new Error( + `GAS_PREREQUISITE: owner lacks native PRC20 for ${chain}` + ); + const made = await f.owner.agentic.create('route-gas-acceptance', { + rules: [ + { + agent: f.agentAddress, + chainNamespace: chain as `eip155:${string}`, + validUntil: inSeconds(3600), + assets: [ + { + token: '0x0000000000000000000000000000000000000000', + maxPerCall: AMOUNT, + maxTotal: AMOUNT * BigInt(2), + }, + ], + maxGasPerCall: parseEther('20'), + allowedCalls: [{ target: counter, selector: 'increment()' }], + }, + ], + }); + const cea = (await getCEAAddress(made.wallet, chain, ENDPOINTS[chain])) + .cea as Address; + expect(await rpc.getCode({ address: cea })).toBeUndefined(); + await f.fundPC(made.wallet, parseEther('21')); + await ( + await f.owner.universal.sendTransaction({ + to: token, + data: encodeFunctionData({ + abi: erc20Abi, + functionName: 'transfer', + args: [made.wallet, AMOUNT * BigInt(2)], + }), + }) + ).wait(); + const agent = await f.agent(made.wallet); + for (const stage of ['first-use', 'subsequent']) { + const oldBalance = await rpc.getBalance({ address: cea }); + const stop = observeAgwGas(agent, f, `${chain}:${stage}`); + try { + const tx = await agent.universal.sendTransaction({ + to: { chain, address: counter }, + funds: { amount: AMOUNT }, + data: [{ to: counter, data: '0xd09de08a', value: BigInt(0) }], + }); + f.evidence('evm-gas-submitted', { + chain, + stage, + wallet: made.wallet, + cea, + hash: tx.hash, + }); + const result = await tx.wait({ outboundTimeoutMs: 180000 }); + expect(result.externalStatus).toBe('success'); + const receipt = await rpc.getTransactionReceipt({ + hash: result.externalTxHash as Hex, + }); + expect(receipt.status).toBe('success'); + expect(await rpc.getBalance({ address: cea })).toBe( + oldBalance + AMOUNT + ); + const events = parseEventLogs({ abi: EXECUTED, logs: receipt.logs }); + expect( + events.some( + (e) => + e.address.toLowerCase() === cea.toLowerCase() && + e.args.originCaller.toLowerCase() === + made.wallet.toLowerCase() && + e.args.target.toLowerCase() === counter.toLowerCase() && + e.args.data === '0xd09de08a' + ) + ).toBe(true); + await recordAgwPushGas(f, tx.hash, `${chain}:${stage}`); + f.evidence('evm-gas-delivered', { + chain, + stage, + wallet: made.wallet, + hash: tx.hash, + destinationHash: result.externalTxHash, + destinationBlock: receipt.blockNumber, + destinationGasUsed: receipt.gasUsed, + destinationGasPaidWei: receipt.gasUsed * receipt.effectiveGasPrice, + }); + } finally { + stop(); + } + } + const stored = await f.owner.agentic + .wallet(made.wallet) + .rules.get(made.rulesIds[0]); + if (stored.spent?.kind !== 'universal') + throw new Error('Missing universal spend'); + expect(stored.spent.assets[0].spent).toBe(AMOUNT * BigInt(2)); + } finally { + f.teardown(); + } + } + it( + '1. Sepolia first-use and subsequent execution', + () => run(CHAIN.ETHEREUM_SEPOLIA), + 600000 + ); + it( + '2. Base Sepolia first-use and subsequent execution', + () => run(CHAIN.BASE_SEPOLIA), + 600000 + ); + it( + '3. Arbitrum Sepolia first-use and subsequent execution', + () => run(CHAIN.ARBITRUM_SEPOLIA), + 600000 + ); + it( + '4. BNB testnet first-use and subsequent execution', + () => run(CHAIN.BNB_TESTNET), + 600000 + ); +}); diff --git a/packages/core/__e2e__/agw/presets-acceptance.spec.ts b/packages/core/__e2e__/agw/presets-acceptance.spec.ts new file mode 100644 index 00000000..e8a1644f --- /dev/null +++ b/packages/core/__e2e__/agw/presets-acceptance.spec.ts @@ -0,0 +1,408 @@ +/** Release acceptance: EXACT shipped preset -> create -> readback -> two agent sends. + * Missing routes, protocols or exact PRC20 balances fail before any funding. This is + * deliberately separate from + * the prefunded protocol fixtures; no asset, cap, call or pin is removed here. + */ +import '@e2e/shared/setup'; +import { + createPublicClient, + http, + encodeFunctionData, + erc20Abi, + parseAbi, + parseEther, + type ContractFunctionReturnType, + type Address, + type Hex, +} from 'viem'; +import { PushChain, CHAIN, type Rule } from '../../src'; +import { resolveAgenticPrc20 } from '../../src/lib/agentic/token-routes'; +import { v6 } from '../../src/lib/agentic/contracts/v6'; +import { actionId, configId } from '../../src/lib/agentic/codec/ids'; +import { + PRESET_ACCEPTANCE_CASES, + expectStoredPreset, +} from '../shared/agw-preset-acceptance'; +import { observeAgwGas, recordAgwPushGas } from '../shared/agw-gas-evidence'; +import { AGW_E2E_ENABLED, setupAgw } from './_fixture'; +import { getCEAAddress } from '../../src/lib/orchestrator/cea-utils'; + +const d = AGW_E2E_ENABLED ? describe : describe.skip; +const endpoints: Record = { + 'eip155:11155111': 'https://ethereum-sepolia-rpc.publicnode.com', + 'eip155:84532': 'https://base-sepolia-rpc.publicnode.com', + 'eip155:421614': 'https://arbitrum-sepolia-rpc.publicnode.com', + 'eip155:97': 'https://bsc-testnet-rpc.publicnode.com', +}; +const ABI = parseAbi([ + 'function factory() view returns(address)', + 'function getPool(address,address,uint24) view returns(address)', + 'function liquidity() view returns(uint128)', + 'function supply(address,uint256,address,uint16)', + 'function mint(uint256) returns(uint256)', + 'function balanceOf(address) view returns(uint256)', + 'function getReserveData(address) view returns ((uint256 configuration,uint128 liquidityIndex,uint128 currentLiquidityRate,uint128 variableBorrowIndex,uint128 currentVariableBorrowRate,uint128 currentStableBorrowRate,uint40 lastUpdateTimestamp,uint16 id,address aTokenAddress,address stableDebtTokenAddress,address variableDebtTokenAddress,address interestRateStrategyAddress,uint128 accruedToTreasury,uint128 unbacked,uint128 isolationModeTotalDebt))', + 'function depositIntoStrategy(address,address,uint256) returns(uint256)', + 'function stakerDepositShares(address,address) view returns(uint256)', + 'function exactInputSingle((address tokenIn,address tokenOut,uint24 fee,address recipient,uint256 amountIn,uint256 amountOutMinimum,uint160 sqrtPriceLimitX96)) returns(uint256)', +]); +// Concrete calls supported by the current catalog. A newly introduced protocol +// requires its own operation/receipt assertion rather than a false generic pass. +// `input` selects which preset asset funds the operation; swaps can trade either way. +async function operation(rule: Rule, cea: Address, input = 0) { + const rpc = createPublicClient({ + transport: http(endpoints[rule.chainNamespace!], { + timeout: 15000, + retryCount: 1, + }), + }); + const asset = rule.assets![input], + token = ( + typeof asset.token === 'string' ? asset.token : asset.token.address + ) as Address; + const amount = asset.maxPerCall / BigInt(1000); + if (amount <= BigInt(0) || (asset.maxTotal ?? BigInt(0)) < amount * BigInt(2)) + throw new Error('Default caps cannot cover two bounded acceptance sends'); + const read = < + F extends + | 'factory' + | 'getPool' + | 'liquidity' + | 'getReserveData' + | 'balanceOf' + | 'stakerDepositShares' + >( + address: Address, + functionName: F, + args: readonly unknown[] = [] + ) => + rpc.readContract({ + address, + abi: ABI, + functionName: functionName as never, + args: args as never, + }) as Promise>; + const swap = rule.allowedCalls.find((c) => + c.selector.toString().startsWith('exactInputSingle(') + ); + let target: Address, + data: Hex, + outputToken: Address | undefined, + shares: (() => Promise) | undefined; + if (swap) { + target = swap.target as Address; + const output = rule.assets![input === 0 ? 1 : 0]; + outputToken = ( + typeof output.token === 'string' ? output.token : output.token.address + ) as Address; + const factory = await read(target, 'factory'); + let fee: number | undefined; + for (const tier of [100, 500, 2500, 3000, 10000]) { + const pool: Address = await read(factory, 'getPool', [ + token, + outputToken, + tier, + ]); + if (!/^0x0+$/.test(pool) && (await read(pool, 'liquidity')) > BigInt(0)) { + fee = tier; + break; + } + } + if (!fee) + throw new Error( + 'PRESET_PROTOCOL_UNAVAILABLE: routed default pair has no active pool' + ); + data = encodeFunctionData({ + abi: ABI, + functionName: 'exactInputSingle', + args: [ + { + tokenIn: token, + tokenOut: outputToken, + fee, + recipient: cea, + amountIn: amount, + amountOutMinimum: BigInt(1), + sqrtPriceLimitX96: BigInt(0), + }, + ], + }); + } else { + const call = rule.allowedCalls.find( + (c) => + c.selector === 'supply(address,uint256,address,uint16)' || + c.selector === 'mint(uint256)' || + c.selector === 'depositIntoStrategy(address,address,uint256)' + ); + if (!call) + throw new Error( + 'PRESET_ACCEPTANCE_UNIMPLEMENTED: no verified operation for this catalog entry' + ); + target = call.target as Address; + if (call.selector === 'supply(address,uint256,address,uint16)') { + const reserve = await read(target, 'getReserveData', [token]); + if (/^0x0+$/.test(reserve.aTokenAddress)) + throw new Error( + 'PRESET_PROTOCOL_UNAVAILABLE: token is not an Aave reserve' + ); + shares = () => read(reserve.aTokenAddress, 'balanceOf', [cea]); + data = encodeFunctionData({ + abi: ABI, + functionName: 'supply', + args: [token, amount, cea, 0], + }); + } else if (call.selector === 'mint(uint256)') { + shares = () => read(target, 'balanceOf', [cea]); + data = encodeFunctionData({ + abi: ABI, + functionName: 'mint', + args: [amount], + }); + } else { + const strategy = '0x424246eF71b01ee33aA33aC590fd9a0855F5eFbc' as Address; + shares = () => read(target, 'stakerDepositShares', [cea, strategy]); + data = encodeFunctionData({ + abi: ABI, + functionName: 'depositIntoStrategy', + args: [strategy, token, amount], + }); + } + } + const resultBalance = + shares ?? + (() => + rpc.readContract({ + address: outputToken!, + abi: erc20Abi, + functionName: 'balanceOf', + args: [cea], + })); + return { + rpc, + token, + amount, + target, + resultBalance, + calls: [ + { + to: token, + value: BigInt(0), + data: encodeFunctionData({ + abi: erc20Abi, + functionName: 'approve', + args: [target, amount], + }), + }, + { to: target, value: BigInt(0), data }, + ], + }; +} + +d('agw unchanged preset acceptance', () => { + // Explicit titles also allow CI's scenario selector to enumerate all nine. + const run = async ( + category: 'DEXES' | 'LENDING' | 'STAKING', + chainNamespace: `eip155:${string}` + ) => { + const preview = PushChain.utils.agentic.presets.get(category, { + chainNamespace, + agent: '0x0000000000000000000000000000000000005678', + }); + if (!preview.readiness.ready) + throw new Error( + `PRESET_BLOCKED_BEFORE_FUNDING ${category} ${chainNamespace}: ${JSON.stringify( + preview.readiness.chains[0].issues + )}` + ); + const f = await setupAgw({ deferAgentFunding: true }); + try { + const generated = PushChain.utils.agentic.presets.get(category, { + chainNamespace, + agent: f.agentAddress, + }); + const before = JSON.stringify(generated.rules, (_k, v) => + typeof v === 'bigint' ? String(v) : v + ); + const predicted = await f.owner.agentic.derive(); + const cea = ( + await getCEAAddress( + predicted.address, + chainNamespace as CHAIN, + endpoints[chainNamespace] + ) + ).cea as Address; + // A swap may start from whichever default asset the owner holds as a PRC20. + const swapPreset = generated.rules[0].allowedCalls.some((c) => + c.selector.toString().startsWith('exactInputSingle(') + ); + let input = 0; + if (swapPreset) + for (const [i, a] of generated.rules[0].assets!.entries()) { + const prc20 = resolveAgenticPrc20( + { + chain: chainNamespace, + address: typeof a.token === 'string' ? a.token : a.token.address, + }, + f.manifest.network + ).address; + const held = await f.push.readContract({ + address: prc20, + abi: erc20Abi, + functionName: 'balanceOf', + args: [f.ownerAddress], + }); + if (held >= (a.maxPerCall / BigInt(1000)) * BigInt(2)) { + input = i; + break; + } + } + const op = await operation(generated.rules[0], cea, input); + const mapped = resolveAgenticPrc20( + { chain: chainNamespace, address: op.token }, + f.manifest.network + ); + if ( + (await f.push.readContract({ + address: mapped.address, + abi: erc20Abi, + functionName: 'balanceOf', + args: [f.ownerAddress], + })) < + op.amount * BigInt(2) + ) + throw new Error('PRESET_PREREQUISITE: owner lacks exact default PRC20'); + await f.fundAgent(); + const made = await f.owner.agentic.create('preset-acceptance', { + rules: generated.rules, + }); + expect(made.wallet).toBe(predicted.address); + const config = await f.push.readContract({ + address: f.manifest.addresses.rulesPolicy, + abi: v6.abis.policy, + functionName: 'getConfig', + args: [ + configId( + made.wallet, + made.rulesIds[0], + actionId(f.manifest.addresses.gateway, '0x77b86bec') + ), + made.wallet, + ], + }); + expect(config.expectedCEA).toBe(cea); + expectStoredPreset( + generated.rules[0], + await f.owner.agentic.wallet(made.wallet).rules.get(made.rulesIds[0]) + ); + expect( + JSON.stringify(generated.rules, (_k, v) => + typeof v === 'bigint' ? String(v) : v + ) + ).toBe(before); + f.evidence('unchanged-preset-created', { + category, + chainNamespace, + wallet: made.wallet, + hash: made.tx.hash, + rules: generated.rules, + }); + await f.fundPC(made.wallet, parseEther('50')); + await ( + await f.owner.universal.sendTransaction({ + to: mapped.address, + data: encodeFunctionData({ + abi: erc20Abi, + functionName: 'transfer', + args: [made.wallet, op.amount * BigInt(2)], + }), + }) + ).wait(); + const agent = await f.agent(made.wallet); + for (const stage of ['first-use', 'subsequent']) { + const oldBalance = await op.resultBalance(); + const stop = observeAgwGas( + agent, + f, + `${category}:${chainNamespace}:${stage}` + ); + try { + const tx = await agent.universal.sendTransaction({ + to: { address: op.target, chain: chainNamespace as CHAIN }, + data: op.calls, + funds: { + amount: op.amount, + token: { + symbol: mapped.symbol, + decimals: mapped.decimals, + address: op.token, + mechanism: 'approve', + }, + }, + }); + f.evidence('unchanged-preset-submitted', { + category, + chainNamespace, + stage, + wallet: made.wallet, + hash: tx.hash, + }); + const receipt = await tx.wait({ outboundTimeoutMs: 180000 }); + expect(receipt.externalStatus).toBe('success'); + expect(receipt.externalTxHash).toBeTruthy(); + const dest = await op.rpc.getTransactionReceipt({ + hash: receipt.externalTxHash as Hex, + }); + expect(dest.status).toBe('success'); + expect(await op.resultBalance()).toBeGreaterThan(oldBalance); + await recordAgwPushGas(f, tx.hash, stage); + f.evidence('unchanged-preset-delivered', { + category, + chainNamespace, + stage, + hash: tx.hash, + destinationHash: receipt.externalTxHash, + destinationGasUsed: dest.gasUsed, + destinationGasPaidWei: dest.gasUsed * dest.effectiveGasPrice, + }); + const stored = await f.owner.agentic + .wallet(made.wallet) + .rules.get(made.rulesIds[0]); + if (stored.spent?.kind !== 'universal') + throw new Error('Missing universal spend'); + expect(stored.spent.assets[input].spent).toBe( + op.amount * BigInt(stage === 'first-use' ? 1 : 2) + ); + } finally { + stop(); + } + } + } finally { + f.teardown(); + } + }; + it('1. DEXES Sepolia', () => run(...PRESET_ACCEPTANCE_CASES[0]), 600000); + it('2. DEXES Base Sepolia', () => run(...PRESET_ACCEPTANCE_CASES[1]), 600000); + it( + '3. DEXES Arbitrum Sepolia', + () => run(...PRESET_ACCEPTANCE_CASES[2]), + 600000 + ); + it('4. DEXES BNB testnet', () => run(...PRESET_ACCEPTANCE_CASES[3]), 600000); + it('5. LENDING Sepolia', () => run(...PRESET_ACCEPTANCE_CASES[4]), 600000); + it( + '6. LENDING Base Sepolia', + () => run(...PRESET_ACCEPTANCE_CASES[5]), + 600000 + ); + it( + '7. LENDING Arbitrum Sepolia', + () => run(...PRESET_ACCEPTANCE_CASES[6]), + 600000 + ); + it( + '8. LENDING BNB testnet', + () => run(...PRESET_ACCEPTANCE_CASES[7]), + 600000 + ); + it('9. STAKING Sepolia', () => run(...PRESET_ACCEPTANCE_CASES[8]), 600000); +}); diff --git a/packages/core/__e2e__/agw/svm-agent-spl.spec.ts b/packages/core/__e2e__/agw/svm-agent-spl.spec.ts new file mode 100644 index 00000000..a63b2f60 --- /dev/null +++ b/packages/core/__e2e__/agw/svm-agent-spl.spec.ts @@ -0,0 +1,307 @@ +/** Public agent SPL delivery, wallet ATA pin and amount enforcement on devnet. + * Uses the verified test_counter.receive_spl harness; no third-party protocol + * support is implied. Two sends exercise omitted gas on first/subsequent use. + */ +import '@e2e/shared/setup'; +import { Keypair, PublicKey } from '@solana/web3.js'; +import bs58 from 'bs58'; +import type { Idl } from '@coral-xyz/anchor'; +import { encodeFunctionData, erc20Abi, numberToHex, parseEther } from 'viem'; +import { PushChain, CHAIN } from '../../src'; +import { MOVEABLE_TOKEN_CONSTANTS } from '../../src/lib/constants/tokens'; +import { getPRC20Address } from '../../src/lib/universal/prc20-address'; +import { deriveAgwSvmCea } from '../../src/lib/agentic/codec/svm-accounts'; +import { AGW_E2E_ENABLED, setupAgw, inSeconds } from './_fixture'; +import { + inspectSvmWirePrograms, + svmWireConnection, + SVM_WIRE_CHAIN, + SVM_WIRE_GATEWAY, + SVM_WIRE_PROGRAM, + SVM_WIRE_COUNTER, +} from '../shared/agw-svm-preflight'; +import { observeAgwGas, recordAgwPushGas } from '../shared/agw-gas-evidence'; +import counterIdl from '../../src/lib/orchestrator/svm-idl/__fixtures__/test_counter.idl.json'; +const d = AGW_E2E_ENABLED ? describe : describe.skip; +const SPL = new PublicKey('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'); +const ATA = new PublicKey('ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL'); +const amount = BigInt(1000); +const hex = (key: PublicKey | string) => + `0x${new PublicKey(key).toBuffer().toString('hex')}`; +const ataFor = (owner: PublicKey, mint: PublicKey) => + PublicKey.findProgramAddressSync( + [owner.toBuffer(), SPL.toBuffer(), mint.toBuffer()], + ATA + )[0]; + +d('agw public agent spl', () => { + it('1. exact wallet ATA and amount constraints survive create and two omitted-gas deliveries', async () => { + const sol = svmWireConnection(); + await inspectSvmWirePrograms(sol); + const raw = process.env['SOLANA_PRIVATE_KEY']; + if (!raw) + throw new Error('SOLANA_PRIVATE_KEY is required for the owned recipient'); + let recipient: PublicKey; + try { + recipient = Keypair.fromSecretKey(bs58.decode(raw)).publicKey; + } catch { + recipient = Keypair.fromSecretKey( + Uint8Array.from(JSON.parse(raw)) + ).publicKey; + } + const asset = MOVEABLE_TOKEN_CONSTANTS.SOLANA_DEVNET.USDT; + const mint = new PublicKey(asset.address), + recipientATA = ataFor(recipient, mint); + const info = await sol.getAccountInfo(recipientATA); + if (!info || !info.owner.equals(SPL)) + throw new Error( + 'SPL_PREREQUISITE: owned recipient needs an existing standard USDT ATA' + ); + const f = await setupAgw(); + try { + const mapped = getPRC20Address({ + chain: SVM_WIRE_CHAIN, + address: asset.address, + }); + if ( + (await f.push.readContract({ + address: mapped.address, + abi: erc20Abi, + functionName: 'balanceOf', + args: [f.ownerAddress], + })) < + amount * BigInt(2) + ) + throw new Error('SPL_PREREQUISITE: owner lacks bounded USDT PRC20'); + const rule = { + agent: f.agentAddress, + chainNamespace: SVM_WIRE_CHAIN, + validUntil: inSeconds(3600), + assets: [ + { + token: asset.address, + maxPerCall: amount, + maxTotal: amount * BigInt(2), + }, + ], + maxGasPerCall: parseEther('20'), + allowedCalls: [ + { + target: SVM_WIRE_PROGRAM, + selector: 'receive_spl(u64)' as const, + pins: [ + { account: 0, expected: SVM_WIRE_COUNTER.toBase58() }, + { + account: 1, + expected: 'agentic:wallet' as const, + token: asset.address, + }, + { account: 2, expected: recipientATA.toBase58() }, + { account: 3, expected: 'agentic:wallet' as const }, + { account: 4, expected: SPL.toBase58() }, + { arg: 0, max: amount }, + ], + }, + ], + }; + const made = await f.owner.agentic.create('agent-spl-acceptance', { + rules: [rule], + }); + const cea = new PublicKey( + Buffer.from( + deriveAgwSvmCea( + made.wallet, + `0x${new PublicKey(SVM_WIRE_GATEWAY).toBuffer().toString('hex')}` + ).address.slice(2), + 'hex' + ) + ); + const ceaATA = ataFor(cea, mint); + const record = await f.owner.agentic + .wallet(made.wallet) + .rules.get(made.rulesIds[0]); + if (!('dataPins' in record.rule)) + throw new Error('Expected a decoded Solana rule'); + expect(record.rule).toMatchObject({ + format: 'decoded', + expectedCEA: hex(cea), + maxGasPerCall: parseEther('20'), + assets: [ + { + token: hex(mint), + maxPerCall: amount, + maxTotal: amount * BigInt(2), + }, + ], + }); + // Every authored pin survives exactly; none is dropped or widened. + expect(record.rule.ceaAccounts).toEqual([hex(cea), hex(ceaATA)]); + expect(record.rule.programs).toEqual([ + { + program: hex(SVM_WIRE_PROGRAM), + discriminator: '0xb654fa2e8aa449c4', + discriminatorLen: 8, + dataless: false, + maxAccounts: 255, + }, + ]); + expect(record.rule.pins).toEqual( + [SVM_WIRE_COUNTER, ceaATA, recipientATA, cea, SPL].map((key, i) => ({ + ruleIndex: 0, + accountIndex: i, + expected: hex(key), + })) + ); + expect(record.rule.dataPins).toEqual([ + { + ruleIndex: 0, + fromEnd: false, + offset: 8, + offsetB: 0, + len: 8, + mode: 2, + expected: numberToHex(amount, { size: 32 }), + num: BigInt(0), + den: BigInt(0), + }, + ]); + await f.fundPC(made.wallet, parseEther('41')); + await ( + await f.owner.universal.sendTransaction({ + to: mapped.address, + data: encodeFunctionData({ + abi: erc20Abi, + functionName: 'transfer', + args: [made.wallet, amount * BigInt(2)], + }), + }) + ).wait(); + const agent = await f.agent(made.wallet); + const idl = JSON.parse(JSON.stringify(counterIdl)) as Idl; + const instruction = idl.instructions.find( + (i) => i.name === 'receive_spl' + )!; + Object.assign(instruction.accounts.find((a) => a.name === 'cea_ata')!, { + address: ceaATA.toBase58(), + }); + Object.assign( + instruction.accounts.find((a) => a.name === 'recipient_ata')!, + { address: recipientATA.toBase58() } + ); + const encoded = (n: bigint, source = idl) => + PushChain.utils.helpers.encodeTxData({ + abi: source, + functionName: 'receive_spl', + args: [n], + }); + const send = (n: bigint, source = idl, burnAmount = n) => + agent.universal.sendTransaction({ + to: { chain: CHAIN.SOLANA_DEVNET, address: SVM_WIRE_PROGRAM }, + data: encoded(n, source), + funds: { token: asset, amount: burnAmount }, + }); + const startNonce = await f.push.getTransactionCount({ + address: f.agentAddress, + }); + await expect( + send(amount + BigInt(1), idl, BigInt(1)) + ).rejects.toMatchObject({ + name: 'AgenticRevertError', + decodedError: { name: 'PolicyCheckReverted(SvmDataCeilingExceeded)' }, + }); + const wrong = JSON.parse(JSON.stringify(idl)) as Idl; + Object.assign( + wrong.instructions + .find((i) => i.name === 'receive_spl')! + .accounts.find((a) => a.name === 'cea_ata')!, + { address: recipientATA.toBase58() } + ); + await expect(send(BigInt(1), wrong)).rejects.toMatchObject({ + name: 'AgenticRevertError', + decodedError: { name: 'PolicyCheckReverted(SvmAccountPinMismatch)' }, + }); + // Funds may only reach the pinned recipient account. + const misdirected = JSON.parse(JSON.stringify(idl)) as Idl; + Object.assign( + misdirected.instructions + .find((i) => i.name === 'receive_spl')! + .accounts.find((a) => a.name === 'recipient_ata')!, + { + address: ataFor( + new PublicKey('11111111111111111111111111111112'), + mint + ).toBase58(), + } + ); + await expect(send(BigInt(1), misdirected)).rejects.toMatchObject({ + name: 'AgenticRevertError', + decodedError: { name: 'PolicyCheckReverted(SvmAccountPinMismatch)' }, + }); + expect( + await f.push.getTransactionCount({ address: f.agentAddress }) + ).toBe(startNonce); + for (const stage of ['first-use', 'subsequent']) { + const balance = BigInt( + (await sol.getTokenAccountBalance(recipientATA)).value.amount + ); + const stop = observeAgwGas(agent, f, `agent-spl:${stage}`); + try { + const tx = await send(amount); + f.evidence('agent-spl-submitted', { + stage, + wallet: made.wallet, + cea: cea.toBase58(), + ceaATA: ceaATA.toBase58(), + hash: tx.hash, + }); + const result = await tx.wait({ outboundTimeoutMs: 180000 }); + expect(result.externalStatus).toBe('success'); + expect( + BigInt( + (await sol.getTokenAccountBalance(recipientATA)).value.amount + ) + ).toBe(balance + amount); + const parsed = await sol.getParsedTransaction( + result.externalTxHash!, + { commitment: 'confirmed', maxSupportedTransactionVersion: 0 } + ); + expect(parsed?.meta?.err).toBeNull(); + expect( + parsed?.meta?.innerInstructions?.some((g) => + g.instructions.some( + (ix) => + 'parsed' in ix && + ix.program === 'spl-token' && + ['transfer', 'transferChecked'].includes(ix.parsed.type) && + ix.parsed.info.source === ceaATA.toBase58() && + ix.parsed.info.destination === recipientATA.toBase58() && + BigInt( + ix.parsed.info.amount ?? ix.parsed.info.tokenAmount?.amount + ) === amount + ) + ) + ).toBe(true); + await recordAgwPushGas(f, tx.hash, `agent-spl:${stage}`); + f.evidence('agent-spl-delivered', { + stage, + wallet: made.wallet, + hash: tx.hash, + destinationHash: result.externalTxHash, + destinationFeeLamports: parsed?.meta?.fee, + computeUnitsConsumed: parsed?.meta?.computeUnitsConsumed, + }); + } finally { + stop(); + } + } + const updated = await f.owner.agentic + .wallet(made.wallet) + .rules.get(made.rulesIds[0]); + if (updated.spent?.kind !== 'universal') + throw new Error('Expected per-asset spend'); + expect(updated.spent.assets[0].spent).toBe(amount * BigInt(2)); + } finally { + f.teardown(); + } + }, 600000); +}); diff --git a/packages/core/__e2e__/agw/svm-memo-live.spec.ts b/packages/core/__e2e__/agw/svm-memo-live.spec.ts new file mode 100644 index 00000000..2acc8b72 --- /dev/null +++ b/packages/core/__e2e__/agw/svm-memo-live.spec.ts @@ -0,0 +1,182 @@ +/** A second Solana program through the public API: SPL Memo v2 (non-Anchor). + * The owner door proves the gateway CPI with the wallet CEA as the signer; the + * agent door proves a rule with a raw 8-byte data prefix plus a CEA account pin + * is accepted, and that a different prefix is refused before broadcast. + */ +import '@e2e/shared/setup'; +import { Connection, PublicKey } from '@solana/web3.js'; +import { erc20Abi, parseEther, toHex, type Hex } from 'viem'; +import { PushChain, CHAIN } from '../../src'; +import { deriveAgwSvmCea } from '../../src/lib/agentic/codec/svm-accounts'; +import { getNativePRC20ForChain } from '../../src/lib/orchestrator/internals/helpers'; +import { AGW_E2E_ENABLED, evmClient, inSeconds, setupAgw } from './_fixture'; +import { SVM_WIRE_GATEWAY } from '../shared/agw-svm-preflight'; + +const d = AGW_E2E_ENABLED ? describe : describe.skip; +const MEMO = 'MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr'; +// The rule matches this 8-byte prefix; Memo accepts any UTF-8 after it. +const PREFIX = 'PUSHAGW:'; +const OTHER = 'OTHERPFX'; +const bytes = (s: string) => Array.from(Buffer.from(s, 'utf8')); +// Memo has no Anchor IDL; this one only lets the SDK place the CEA signer. +PushChain.utils.svm.registerIdl({ + address: MEMO, + metadata: { name: 'spl_memo', version: '2.0.0', spec: '0.1.0' }, + instructions: [PREFIX, OTHER].map((p) => ({ + name: p === PREFIX ? 'memo' : 'other', + discriminator: bytes(p), + accounts: [{ name: 'cea_authority', signer: true }], + args: [], + })), +}); + +d('agw svm memo', () => { + async function expectMemo(sig: string, text: string, cea: string) { + const sol = new Connection('https://api.devnet.solana.com', 'confirmed'); + let tx = await sol.getParsedTransaction(sig, { + commitment: 'confirmed', + maxSupportedTransactionVersion: 0, + }); + for (let retry = 0; !tx && retry < 5; retry++) { + await new Promise((resolve) => setTimeout(resolve, 2000)); + tx = await sol.getParsedTransaction(sig, { + commitment: 'confirmed', + maxSupportedTransactionVersion: 0, + }); + } + expect(tx?.meta?.err).toBeNull(); + const memo = (tx?.meta?.innerInstructions ?? []) + .flatMap((g) => g.instructions) + .find((ix) => ix.programId.toBase58() === MEMO); + expect(memo && 'parsed' in memo ? memo.parsed : undefined).toBe(text); + expect(tx?.meta?.logMessages?.join('\n')).toContain(`Signed by ${cea}`); + } + + it('1. owner door: the gateway runs Memo with the wallet CEA as signer', async () => { + const f = await setupAgw({ deferAgentFunding: true }); + try { + const made = await f.owner.agentic.create('svm-memo-owner', { + rules: [], + }); + await f.fundPC(made.wallet, parseEther('21')); + const owner = await evmClient( + process.env['PUSH_PRIVATE_KEY'] as Hex, + CHAIN.PUSH_TESTNET_DONUT, + f.manifest.network, + made.wallet + ); + const cea = new PublicKey( + Buffer.from( + deriveAgwSvmCea( + made.wallet, + `0x${new PublicKey(SVM_WIRE_GATEWAY).toBuffer().toString('hex')}` + ).address.slice(2), + 'hex' + ) + ).toBase58(); + const text = `${PREFIX}owner ${Date.now()}`; + const tx = await owner.universal.sendTransaction({ + to: { chain: CHAIN.SOLANA_DEVNET, address: MEMO }, + data: toHex(text), + }); + f.evidence('svm-memo-owner-submitted', { + wallet: made.wallet, + hash: tx.hash, + }); + const receipt = await tx.wait({ outboundTimeoutMs: 180000 }); + expect(receipt.externalStatus).toBe('success'); + await expectMemo(receipt.externalTxHash!, text, cea); + f.evidence('svm-memo-owner-delivered', { + hash: tx.hash, + destinationHash: receipt.externalTxHash, + }); + } finally { + f.teardown(); + } + }, 600000); + + it('2. agent door: a raw-prefix rule with a CEA pin runs, another prefix is refused', async () => { + const f = await setupAgw({ deferAgentFunding: true }); + try { + const made = await f.owner.agentic.create('svm-memo-agent', { + rules: [ + { + agent: f.agentAddress, + chainNamespace: CHAIN.SOLANA_DEVNET, + validUntil: inSeconds(3600), + assets: [], + maxGasPerCall: parseEther('20'), + allowedCalls: [ + { + target: MEMO, + selector: toHex(PREFIX) as `0x${string}`, + pins: [{ account: 0, expected: 'agentic:wallet' as const }], + }, + ], + }, + ], + }); + await f.fundPC(made.wallet, parseEther('21')); + await f.fundAgent(); + const agent = await f.agent(made.wallet); + const cea = new PublicKey( + Buffer.from( + deriveAgwSvmCea( + made.wallet, + `0x${new PublicKey(SVM_WIRE_GATEWAY).toBuffer().toString('hex')}` + ).address.slice(2), + 'hex' + ) + ).toBase58(); + const startNonce = await f.push.getTransactionCount({ + address: f.agentAddress, + }); + await expect( + agent.universal.sendTransaction({ + to: { chain: CHAIN.SOLANA_DEVNET, address: MEMO }, + data: toHex(`${OTHER}not allowed`), + }) + ).rejects.toMatchObject({ name: 'AgenticRevertError' }); + expect( + await f.push.getTransactionCount({ address: f.agentAddress }) + ).toBe(startNonce); + const text = `${PREFIX}agent ${Date.now()}`; + const tx = await agent.universal.sendTransaction({ + to: { chain: CHAIN.SOLANA_DEVNET, address: MEMO }, + data: toHex(text), + }); + f.evidence('svm-memo-agent-submitted', { + wallet: made.wallet, + hash: tx.hash, + }); + const receipt = await tx.wait({ outboundTimeoutMs: 180000 }); + expect(receipt.externalStatus).toBe('success'); + await expectMemo(receipt.externalTxHash!, text, cea); + // A zero-amount send names the zero-cap gas token and spends nothing. + const stored = await f.owner.agentic + .wallet(made.wallet) + .rules.get(made.rulesIds[0]); + if (stored.spent?.kind !== 'universal') throw new Error('Missing spend'); + expect(stored.spent.assets.every((a) => a.spent === BigInt(0))).toBe( + true + ); + expect( + await f.push.readContract({ + address: getNativePRC20ForChain( + CHAIN.SOLANA_DEVNET, + f.manifest.network + ), + abi: erc20Abi, + functionName: 'balanceOf', + args: [made.wallet], + }) + ).toBe(BigInt(0)); + f.evidence('svm-memo-agent-delivered', { + hash: tx.hash, + destinationHash: receipt.externalTxHash, + }); + } finally { + f.teardown(); + } + }, 600000); +}); diff --git a/packages/core/__e2e__/ci/preflight.ts b/packages/core/__e2e__/ci/preflight.ts index e7bc8c5e..208c594a 100644 --- a/packages/core/__e2e__/ci/preflight.ts +++ b/packages/core/__e2e__/ci/preflight.ts @@ -346,7 +346,24 @@ function renderTable(rows: Row[]): void { process.exit(1); } } - if (scenarios.some((s) => s.group === 'agw-svm-wire' || s.file === '__e2e__/agw/svm-public.spec.ts')) { + const presetCases = scenarios + .filter((s) => s.file === '__e2e__/agw/presets-acceptance.spec.ts') + .map((s) => Number(/-(\d+)$/.exec(s.id)?.[1])); + if (presetCases.length) { + const { PRESET_ACCEPTANCE_CASES } = await import('../shared/agw-preset-acceptance'); + // Only the selected cases; their ids end in the spec's case number. + const selected = presetCases.map((n) => { + const entry = PRESET_ACCEPTANCE_CASES[n - 1]; + if (!entry) throw new Error(`Unknown preset acceptance case ${n}`); + return entry; + }); + const blocked = selected.flatMap(([category, chainNamespace]) => { + const result = PushChain.utils.agentic.presets.get(category, { chainNamespace, agent: '0x0000000000000000000000000000000000005678' }); + return result.readiness.ready ? [] : [{ category, chainNamespace, issues: result.readiness.chains[0].issues }]; + }); + if (blocked.length) throw new Error(`PRESET_BLOCKED_BEFORE_FUNDING: ${JSON.stringify(blocked)}`); + } + if (scenarios.some((s) => s.group === 'agw-svm-wire' || s.group === 'agw-svm-agent-spl' || s.file === '__e2e__/agw/svm-public.spec.ts')) { const { inspectSvmWirePrograms, svmWireConnection } = await import('../shared/agw-svm-preflight'); await inspectSvmWirePrograms(svmWireConnection(solRpc)); console.log('Solana wire fixture verified read-only before funding.'); diff --git a/packages/core/__e2e__/ci/suite.ts b/packages/core/__e2e__/ci/suite.ts index 47272796..a95d9154 100644 --- a/packages/core/__e2e__/ci/suite.ts +++ b/packages/core/__e2e__/ci/suite.ts @@ -39,6 +39,12 @@ export const GROUPS = [ 'agw-svm-replay', 'agw-presets', 'agw-presets-expanded', + 'agw-presets-acceptance', + 'agw-presets-routed', + 'agw-exact-routes', + 'agw-svm-memo', + 'agw-svm-agent-spl', + 'agw-gas', 'marketplace', 'marketplace-live', 'marketplace-funding', @@ -1036,6 +1042,59 @@ export const SCENARIOS: Scenario[] = [ needs: { masterPC: '110' }, env: { AGW_E2E: '1' }, }, + ...Array.from({ length: 9 }, (_, i) => ({ + id: `agw-unchanged-preset-${i + 1}`, + group: 'agw-presets-acceptance' as const, + file: '__e2e__/agw/presets-acceptance.spec.ts', + grep: `agw unchanged preset acceptance ${i + 1}\\.`, + needs: { masterPC: '55' }, + env: { AGW_E2E: '1' }, + note: 'Exact public defaults; unavailable routes fail before funding. Exact default PRC20 funds are checked in the scenario.', + })), + // The subset whose default assets all have registered routes (case numbers above). + ...[1, 7].map((n) => ({ + id: `agw-routed-preset-${n}`, + group: 'agw-presets-routed' as const, + file: '__e2e__/agw/presets-acceptance.spec.ts', + grep: `agw unchanged preset acceptance ${n}\\.`, + needs: { masterPC: '55' }, + env: { AGW_E2E: '1' }, + note: 'DEXES Sepolia and LENDING Arbitrum Sepolia; the owner must hold the exact default PRC20s.', + })), + ...Array.from({ length: 4 }, (_, i) => ({ + id: `agw-evm-gas-${i + 1}`, + group: 'agw-gas' as const, + file: '__e2e__/agw/gas-live.spec.ts', + grep: `agw live gas sizing ${i + 1}\\.`, + needs: { masterPC: '26' }, + env: { AGW_E2E: '1' }, + note: 'Two native outbounds; exact per-chain PRC20 balances are checked by the scenario before wallet creation.', + })), + ...['Sepolia', 'Base Sepolia', 'Arbitrum Sepolia'].map((name, i) => ({ + id: `agw-exact-route-${i + 1}`, + group: 'agw-exact-routes' as const, + file: '__e2e__/agw/exact-routes-live.spec.ts', + grep: `agw exact route outbound ${i + 1}\\.`, + needs: { masterPC: '26' }, + env: { AGW_E2E: '1' }, + note: `${name} Circle USDC node route; the owner must hold its exact PRC20.`, + })), + ...[1, 2].map((n) => ({ + id: `agw-svm-memo-${n}`, + group: 'agw-svm-memo' as const, + file: '__e2e__/agw/svm-memo-live.spec.ts', + grep: `agw svm memo ${n}\\.`, + needs: { masterPC: '26' }, + env: { AGW_E2E: '1' }, + })), + { + id: 'agw-agent-spl-acceptance', + group: 'agw-svm-agent-spl', + file: '__e2e__/agw/svm-agent-spl.spec.ts', + grep: 'agw public agent spl 1\\.', + needs: { masterPC: '45', masterUsdtSol: '0.002' }, + env: { AGW_E2E: '1' }, + }, { id: 'agw-preset-uniswap-live', group: 'agw-presets', diff --git a/packages/core/__e2e__/shared/agw-gas-evidence.ts b/packages/core/__e2e__/shared/agw-gas-evidence.ts new file mode 100644 index 00000000..28f22f4e --- /dev/null +++ b/packages/core/__e2e__/shared/agw-gas-evidence.ts @@ -0,0 +1,44 @@ +/** Record quotes and measured gas separately from permission ceilings. */ +import type { PushChain } from '../../src'; +import type { AgenticRuntime } from '../../src/lib/agentic/runtime'; +import type { AgwFixture } from '../agw/_fixture'; +import type { Hex } from 'viem'; +export function observeAgwGas(client: PushChain, f: AgwFixture, stage: string) { + const rt = (client as unknown as { agenticRuntime: AgenticRuntime }) + .agenticRuntime; + const previous = rt.quoteOutbound; + rt.quoteOutbound = async (...args) => { + const quote = await previous(...args); + f.evidence('agw-gas-quote', { + stage, + token: args[0], + requestedGasLimit: args[1], + chain: args[2], + protocolFeePCWei: quote.protocolFee, + quotedGasBudgetPCWei: quote.nativeValueForGas, + gasLimitUsed: quote.gasLimitUsed, + attachedPCWei: quote.protocolFee + quote.nativeValueForGas, + gasTokenFee: quote.gasFee, + poolPcInRequired: quote.poolPcIn, + }); + return quote; + }; + return () => { + rt.quoteOutbound = previous; + }; +} +export async function recordAgwPushGas( + f: AgwFixture, + hash: string, + stage: string +) { + const receipt = await f.push.getTransactionReceipt({ hash: hash as Hex }); + f.evidence('agw-push-gas', { + stage, + hash, + block: receipt.blockNumber, + gasUsed: receipt.gasUsed, + effectiveGasPrice: receipt.effectiveGasPrice, + transactionGasPaidPCWei: receipt.gasUsed * receipt.effectiveGasPrice, + }); +} diff --git a/packages/core/__e2e__/shared/agw-preset-acceptance.ts b/packages/core/__e2e__/shared/agw-preset-acceptance.ts new file mode 100644 index 00000000..683b60bb --- /dev/null +++ b/packages/core/__e2e__/shared/agw-preset-acceptance.ts @@ -0,0 +1,108 @@ +/** Assertions shared by live acceptance and the actual-contract local suite. + * No route substitution or asset removal is permitted in this acceptance path. + */ +import { + encodeAbiParameters, + getAddress, + parseAbiItem, + toFunctionSelector, + type AbiParameter, + type Hex, +} from 'viem'; +import type { Rule, RulesRecord } from '../../src/lib/agentic/agentic.types'; +import type { PresetCategory } from '../../src/lib/agentic/presets/types'; + +export const PRESET_ACCEPTANCE_CASES = [ + ['DEXES', 'eip155:11155111'], + ['DEXES', 'eip155:84532'], + ['DEXES', 'eip155:421614'], + ['DEXES', 'eip155:97'], + ['LENDING', 'eip155:11155111'], + ['LENDING', 'eip155:84532'], + ['LENDING', 'eip155:421614'], + ['LENDING', 'eip155:97'], + ['STAKING', 'eip155:11155111'], +] as const satisfies readonly (readonly [PresetCategory, `eip155:${string}`])[]; + +function words(param: AbiParameter): number { + if (param.type === 'tuple' && 'components' in param) + return param.components.reduce((n, c) => n + words(c), 0); + if (/\[|bytes$|string$/.test(param.type)) + throw new Error('Acceptance pin needs a static argument'); + return 1; +} +function pinLocation( + inputs: readonly AbiParameter[], + path: number | readonly number[] +): { arg: number; param: AbiParameter } { + const parts = typeof path === 'number' ? [path] : path; + let current = inputs, + offset = 0, + selected: AbiParameter | undefined; + for (let depth = 0; depth < parts.length; depth++) { + const index = parts[depth]; + selected = current[index]; + if (!selected) throw new Error('Invalid pin argument path'); + offset += current.slice(0, index).reduce((n, c) => n + words(c), 0); + if (depth < parts.length - 1) { + if (selected.type !== 'tuple' || !('components' in selected)) + throw new Error('Invalid pin tuple path'); + current = selected.components; + } + } + return { arg: offset, param: selected! }; +} +export function expectStoredPreset(input: Rule, record: RulesRecord): void { + if (!('allowedCalls' in record.rule)) + throw new Error('Expected an EVM rule record'); + expect(record.enabled).toBe(true); + expect(record.agent).toBe(getAddress(input.agent)); + expect(record.chainNamespace).toBe(input.chainNamespace); + expect(record.validUntil).toBe(input.validUntil); + expect(record.rule.maxGasPerCall).toBe(input.maxGasPerCall); + expect(record.rule.assets).toEqual( + input.assets!.map((a) => ({ + token: getAddress( + typeof a.token === 'string' ? a.token : a.token.address + ), + maxPerCall: a.maxPerCall, + maxTotal: a.maxTotal ?? BigInt(0), + })) + ); + expect(record.spent).toEqual({ + kind: 'universal', + assets: input.assets!.map((a) => ({ + token: getAddress( + typeof a.token === 'string' ? a.token : a.token.address + ), + spent: BigInt(0), + })), + }); + expect(record.rule.allowedCalls).toEqual( + input.allowedCalls.map((c) => { + const fn = parseAbiItem(`function ${c.selector}`); + if (fn.type !== 'function') throw new Error('Expected a function'); + return { + target: getAddress(c.target), + selector: toFunctionSelector(fn), + maxValue: c.maxValue ?? BigInt(0), + pins: (c.pins ?? []).map((p) => { + if (!('arg' in p) || p.arg === undefined) + throw new Error('Expected authored argument pin'); + const loc = pinLocation(fn.inputs, p.arg); + if ('max' in p) return { arg: loc.arg, max: p.max }; + return { + arg: loc.arg, + expected: + p.expected === 'agentic:wallet' + ? 'agentic:wallet' + : (encodeAbiParameters( + [loc.param], + [p.expected as never] + ).toLowerCase() as Hex), + }; + }), + }; + }) + ); +} diff --git a/packages/core/scripts/check-agw-gas-quotes.js b/packages/core/scripts/check-agw-gas-quotes.js new file mode 100644 index 00000000..8eac1e50 --- /dev/null +++ b/packages/core/scripts/check-agw-gas-quotes.js @@ -0,0 +1,122 @@ +/** Read-only current outbound quotes. These are observations, not validated gas + * defaults or measured destination execution fees. No signer/keys are loaded. + * The attached budget depends on the agent's origin: Push-native signers use + * the fixed PC/USD fallback, UEA signers the Donut WPC/stable pool for their + * origin. poolPcIn is the PC the gateway's gas swap needs at quote time. + * Build core, then: node packages/core/scripts/check-agw-gas-quotes.js [report.json] + */ +const fs = require('node:fs'); +const path = require('node:path'); +const { parseEther } = require('viem'); +const built = path.resolve(__dirname, '../../../dist/packages/core/src'); +const { PushChain } = require(built); +const { CHAIN, PUSH_NETWORK } = PushChain.CONSTANTS; +const { getNativePRC20ForChain } = require(path.join( + built, + 'lib/orchestrator/internals/helpers' +)); +const { MOVEABLE_TOKEN_CONSTANTS } = require(path.join( + built, + 'lib/constants/tokens' +)); +const { getPRC20Address } = require(path.join( + built, + 'lib/universal/prc20-address' +)); +async function main() { + const wallet = '0x0000000000000000000000000000000000005678'; + // A wallet with no CEA token account, so SPL quotes include first-use rent. + const freshWallet = '0x00000000000000000000000000000000000a6e01'; + const usdtSol = MOVEABLE_TOKEN_CONSTANTS.SOLANA_DEVNET.USDT; + const report = { + at: new Date().toISOString(), + readOnly: true, + network: PUSH_NETWORK.TESTNET_DONUT, + note: 'Current quotes only; first-use and subsequent labels describe gas-limit inputs, not executed transactions.', + origins: [], + }; + for (const origin of [CHAIN.PUSH_TESTNET_DONUT, CHAIN.ETHEREUM_SEPOLIA]) { + const client = await PushChain.initialize( + { address: wallet, chain: origin }, + { network: PUSH_NETWORK.TESTNET_DONUT } + ); + const rt = client.agenticRuntime; + if (!rt.isReadOnly) throw new Error('Quote audit must be read-only'); + const entry = { + signerOrigin: origin, + pushBlockBefore: String(await rt.reader.getBlockNumber()), + cases: [], + }; + report.origins.push(entry); + const cases = []; + for (const chain of [ + CHAIN.ETHEREUM_SEPOLIA, + CHAIN.BASE_SEPOLIA, + CHAIN.ARBITRUM_SEPOLIA, + CHAIN.BNB_TESTNET, + ]) + cases.push( + [chain, 'default-new-account', BigInt(2000000)], + [chain, 'route-default-zero-input', BigInt(0)] + ); + const sol = CHAIN.SOLANA_DEVNET; + cases.push( + [ + sol, + 'legacy-million-unit-fallback', + BigInt(1000000), + { wallet, burnAmount: BigInt(10000) }, + ], + [ + sol, + 'sdk-default-route-sizing', + BigInt(0), + { wallet, burnAmount: BigInt(10000) }, + ], + [ + sol, + 'spl-first-use-route-sizing', + BigInt(0), + { + wallet: freshWallet, + splMintBase58: usdtSol.address, + burnAmount: BigInt(1000), + }, + getPRC20Address(usdtSol).address, + ] + ); + for (const [chain, stage, gasLimit, svm, token] of cases) { + const c = { chain, stage, inputGasLimit: gasLimit }; + entry.cases.push(c); + try { + const quote = await rt.quoteOutbound( + token ?? getNativePRC20ForChain(chain, rt.network), + gasLimit, + chain, + svm + ); + Object.assign(c, quote, { + attachedPCWei: quote.protocolFee + quote.nativeValueForGas, + fits20PCCeiling: + quote.protocolFee + quote.nativeValueForGas <= parseEther('20'), + }); + } catch (e) { + c.error = e.shortMessage || e.message; + } + } + entry.pushBlockAfter = String(await rt.reader.getBlockNumber()); + } + const json = JSON.stringify( + report, + (_k, v) => (typeof v === 'bigint' ? String(v) : v), + 2 + ); + if (process.argv[2]) fs.writeFileSync(process.argv[2], json); + console.log(json); + if (report.origins.some((o) => o.cases.some((c) => c.error))) + process.exitCode = 1; +} +main().catch((e) => { + console.error(e.shortMessage || e.message); + process.exitCode = 1; +}); diff --git a/packages/core/scripts/check-agw-preset-compatibility.js b/packages/core/scripts/check-agw-preset-compatibility.js new file mode 100644 index 00000000..f746d044 --- /dev/null +++ b/packages/core/scripts/check-agw-preset-compatibility.js @@ -0,0 +1,323 @@ +/** Read-only protocol compatibility of the exact routed testnet tokens. + * Build core first. No signer, environment keys, funding or transactions. + * Usage: node packages/core/scripts/check-agw-preset-compatibility.js [report.json] + */ +const fs = require('node:fs'); +const path = require('node:path'); +const { createPublicClient, http, parseAbi, zeroAddress } = require('viem'); +const built = path.resolve(__dirname, '../../../dist/packages/core/src'); +const { PushChain } = require(built); +const { MOVEABLE_TOKENS } = require(path.join(built, 'lib/constants/tokens')); +const { exactAgenticRoutes, resolveAgenticPrc20 } = require(path.join( + built, + 'lib/agentic/token-routes' +)); +const { PRESET_CATALOG } = require(path.join( + built, + 'lib/agentic/presets/catalog' +)); +const DONUT = PushChain.CONSTANTS.PUSH_NETWORK.TESTNET_DONUT; +const abi = parseAbi([ + 'function factory() view returns (address)', + 'function getPool(address,address,uint24) view returns (address)', + 'function liquidity() view returns (uint128)', + 'function getReservesList() view returns (address[])', + 'function underlying() view returns (address)', + 'function underlyingToken() view returns (address)', + 'function SOURCE_CHAIN_NAMESPACE() view returns (string)', + 'function SOURCE_TOKEN_ADDRESS() view returns (string)', +]); +const endpoints = { + 'eip155:11155111': 'https://ethereum-sepolia-rpc.publicnode.com', + 'eip155:84532': 'https://base-sepolia-rpc.publicnode.com', + 'eip155:421614': 'https://arbitrum-sepolia-rpc.publicnode.com', + 'eip155:97': 'https://bsc-testnet-rpc.publicnode.com', +}; +async function main() { + const report = { at: new Date().toISOString(), readOnly: true, chains: [] }; + const push = createPublicClient({ + transport: http('https://evm.donut.rpc.push.org/', { + timeout: 15000, + retryCount: 1, + }), + }); + report.pushBlock = String(await push.getBlockNumber()); + if ((await push.getChainId()) !== 42101) throw new Error('Expected Donut'); + for (const [chain, endpoint] of Object.entries(endpoints)) { + const entry = { chain, candidates: [], protocols: [], presets: [] }; + report.chains.push(entry); + const rpc = createPublicClient({ + transport: http(endpoint, { timeout: 12000, retryCount: 1 }), + }); + try { + const block = await rpc.getBlockNumber(); + entry.block = String(block); + if ((await rpc.getChainId()) !== Number(chain.split(':')[1])) + throw new Error('Destination chain mismatch'); + const read = (address, functionName, args = []) => + rpc.readContract({ + address, + abi, + functionName, + args, + blockNumber: block, + }); + // Registry tokens plus exact node routes the symbol registry cannot hold. + const sources = new Map(); + for (const token of MOVEABLE_TOKENS[chain] || []) + if (token.mechanism !== 'native') + sources.set(token.address.toLowerCase(), token); + for (const route of exactAgenticRoutes(chain, DONUT)) + sources.set(route.source.toLowerCase(), { + address: route.source, + symbol: route.symbol, + }); + for (const token of sources.values()) { + let mapped; + try { + mapped = resolveAgenticPrc20( + { chain, address: token.address }, + DONUT + ); + } catch (e) { + entry.candidates.push({ + token: token.address, + symbol: token.symbol, + unavailable: e.shortMessage || e.message, + }); + continue; + } + try { + const [sourceChain, source] = await Promise.all([ + push.readContract({ + address: mapped.address, + abi, + functionName: 'SOURCE_CHAIN_NAMESPACE', + blockNumber: BigInt(report.pushBlock), + }), + push + .readContract({ + address: mapped.address, + abi, + functionName: 'SOURCE_TOKEN_ADDRESS', + blockNumber: BigInt(report.pushBlock), + }) + .catch(() => + push.readContract({ + address: mapped.address, + abi: parseAbi([ + 'function SOURCE_TOKEN_ADDRESS() view returns (address)', + ]), + functionName: 'SOURCE_TOKEN_ADDRESS', + blockNumber: BigInt(report.pushBlock), + }) + ), + ]); + entry.candidates.push({ + token: token.address, + symbol: token.symbol, + prc20: mapped.address, + identityVerified: + sourceChain === chain && + source.toLowerCase() === token.address.toLowerCase(), + }); + } catch (e) { + // An RPC failure is unknown, not unsupported. + entry.candidates.push({ + token: token.address, + symbol: token.symbol, + prc20: mapped.address, + readError: e.shortMessage || e.message, + }); + } + } + const routed = entry.candidates.filter((c) => c.identityVerified); + for (const preset of PRESET_CATALOG) { + const def = preset.chains.find((c) => c.chainNamespace === chain); + if (!def) continue; + const generated = PushChain.utils.agentic.presets.get(preset.constant, { + chainNamespace: chain, + agent: '0x0000000000000000000000000000000000005678', + }); + entry.presets.push({ + category: preset.constant, + readiness: generated.readiness, + assets: generated.rules[0].assets, + }); + if (def.swapRouters) + for (const router of def.swapRouters) { + const result = { + app: router.app, + kind: 'dex', + router: router.address, + pairs: [], + }; + entry.protocols.push(result); + try { + result.factory = await read(router.address, 'factory'); + // The preset's own pair: one routed side is enough to trade into the other. + const pair = generated.rules[0].assets.map((a) => + typeof a.token === 'string' ? a.token : a.token.address + ); + if (pair.length === 2) { + result.defaultPair = { + tokens: pair, + routed: pair.map((t) => + routed.some( + (c) => c.token.toLowerCase() === t.toLowerCase() + ) + ), + pools: [], + }; + for (const fee of [100, 500, 2500, 3000, 10000]) { + try { + const pool = await read(result.factory, 'getPool', [ + ...pair, + fee, + ]); + if (pool === zeroAddress) continue; + result.defaultPair.pools.push({ + fee, + pool, + liquidity: String(await read(pool, 'liquidity')), + }); + } catch (e) { + result.defaultPair.pools.push({ + fee, + error: e.shortMessage || e.message, + }); + } + } + } + for (let i = 0; i < routed.length; i++) + for (let j = i + 1; j < routed.length; j++) { + const pair = { + tokens: [routed[i].token, routed[j].token], + pools: [], + }; + result.pairs.push(pair); + for (const fee of [100, 500, 2500, 3000, 10000]) { + try { + const pool = await read(result.factory, 'getPool', [ + ...pair.tokens, + fee, + ]); + if (pool === zeroAddress) continue; + pair.pools.push({ + fee, + pool, + liquidity: String(await read(pool, 'liquidity')), + }); + } catch (e) { + pair.pools.push({ + fee, + error: e.shortMessage || e.message, + }); + } + } + } + } catch (e) { + result.error = e.shortMessage || e.message; + } + } + const aave = def.allowedCalls.find((c) => c.app === 'Aave V3'); + if (aave) { + const result = { app: 'Aave V3', kind: 'lending', pool: aave.target }; + entry.protocols.push(result); + try { + result.reserves = await read(aave.target, 'getReservesList'); + result.routedReserves = routed.filter((c) => + result.reserves.some( + (a) => a.toLowerCase() === c.token.toLowerCase() + ) + ); + } catch (e) { + result.error = e.shortMessage || e.message; + } + } + const markets = [ + ...new Map( + def.allowedCalls + .filter((c) => c.budget?.kind === 'fixed-token') + .map((c) => [c.target, c]) + ).values(), + ]; + for (const market of markets) { + const result = { + app: market.app, + kind: 'market', + market: market.target, + }; + entry.protocols.push(result); + try { + result.underlying = await read(market.target, 'underlying'); + result.routed = routed.some( + (c) => c.token.toLowerCase() === result.underlying.toLowerCase() + ); + } catch (e) { + result.error = e.shortMessage || e.message; + } + } + if (preset.constant === 'STAKING') { + const strategy = '0x424246eF71b01ee33aA33aC590fd9a0855F5eFbc'; + const result = { app: 'EigenLayer', kind: 'strategy', strategy }; + entry.protocols.push(result); + try { + result.underlying = await read(strategy, 'underlyingToken'); + result.routed = routed.some( + (c) => c.token.toLowerCase() === result.underlying.toLowerCase() + ); + } catch (e) { + result.error = e.shortMessage || e.message; + } + } + } + } catch (e) { + entry.error = e.shortMessage || e.message; + } + } + const output = process.argv[2]; + if (output) + fs.writeFileSync( + output, + JSON.stringify( + report, + (_k, v) => (typeof v === 'bigint' ? String(v) : v), + 2 + ) + ); + for (const c of report.chains) + console.log( + JSON.stringify( + { + chain: c.chain, + block: c.block, + error: c.error, + routed: c.candidates + .filter((x) => x.identityVerified) + .map((x) => x.symbol), + protocols: c.protocols, + }, + null, + 2 + ) + ); + if ( + report.chains.some( + (c) => + c.error || + c.candidates.some((x) => x.readError) || + c.protocols.some( + (p) => + p.error || + p.pairs?.some((x) => x.pools.some((y) => y.error)) || + p.defaultPair?.pools.some((y) => y.error) + ) + ) + ) + process.exitCode = 1; +} +main().catch((e) => { + console.error(e.shortMessage || e.message); + process.exitCode = 1; +}); diff --git a/packages/core/scripts/check-agw-route-registry.js b/packages/core/scripts/check-agw-route-registry.js new file mode 100644 index 00000000..f084db1b --- /dev/null +++ b/packages/core/scripts/check-agw-route-registry.js @@ -0,0 +1,192 @@ +/** Read-only drift check between the SDK's token routes and the Push node's + * token registry (uregistry, read through Tendermint abci_query). No keys. + * - mismatch: the SDK maps a source token to a different PRC20 than the node. + * - sdkOnly: the SDK maps a PRC20 the node does not list as enabled. + * - nodeOnly: an enabled node route the SDK does not resolve (informational). + * Exit 1 on any mismatch or sdkOnly entry. + * Build core, then: node packages/core/scripts/check-agw-route-registry.js [report.json] + */ +const fs = require('node:fs'); +const path = require('node:path'); +const { getAddress } = require('viem'); +const built = path.resolve(__dirname, '../../../dist/packages/core/src'); +const { PushChain } = require(built); +const { SYNTHETIC_PUSH_ERC20 } = require(path.join( + built, + 'lib/constants/chain' +)); +const { MOVEABLE_TOKENS } = require(path.join(built, 'lib/constants/tokens')); +const { getPRC20Address } = require(path.join( + built, + 'lib/universal/prc20-address' +)); +const { getNativePRC20ForChain } = require(path.join( + built, + 'lib/orchestrator/internals/helpers' +)); +const { exactAgenticRoutes, resolveAgenticPrc20 } = require(path.join( + built, + 'lib/agentic/token-routes' +)); +const { PRESET_CATALOG } = require(path.join( + built, + 'lib/agentic/presets/catalog' +)); +const RPC = 'https://donut.rpc.push.org:443'; +const DONUT = PushChain.CONSTANTS.PUSH_NETWORK.TESTNET_DONUT; +const NATIVE = new Set([ + '0x0000000000000000000000000000000000000000', + '11111111111111111111111111111111', +]); + +function varint(buf, i) { + let x = BigInt(0), + s = BigInt(0); + for (;;) { + const b = buf[i++]; + x |= BigInt(b & 0x7f) << s; + if (!(b & 0x80)) return [x, i]; + s += BigInt(7); + } +} +function fields(buf) { + const out = []; + let i = 0; + while (i < buf.length) { + let key; + [key, i] = varint(buf, i); + const no = Number(key >> BigInt(3)), + wt = Number(key & BigInt(7)); + if (wt === 0) { + let v; + [v, i] = varint(buf, i); + out.push([no, v]); + } else if (wt === 2) { + let l; + [l, i] = varint(buf, i); + out.push([no, buf.subarray(i, i + Number(l))]); + i += Number(l); + } else if (wt === 5) i += 4; + else if (wt === 1) i += 8; + else throw new Error(`unsupported protobuf wire type ${wt}`); + } + return out; +} +const text = (b) => Buffer.from(b).toString('utf8'); +function tokenConfig(buf) { + const t = {}; + for (const [no, v] of fields(buf)) { + if (no === 1) t.chain = text(v); + else if (no === 2) t.address = text(v); + else if (no === 4) t.symbol = text(v); + else if (no === 5) t.decimals = Number(v); + else if (no === 6) t.enabled = v === BigInt(1); + else if (no === 9) + for (const [n2, v2] of fields(v)) if (n2 === 2) t.prc20 = text(v2); + } + return t; +} +async function nodeTokenConfigs() { + const info = await (await fetch(`${RPC}/abci_info`)).json(); + // QueryAllTokenConfigsRequest { pagination: { limit: 1000 } } + const data = '0a0318e807'; + const r = await ( + await fetch( + `${RPC}/abci_query?path=%22/uregistry.v1.Query/AllTokenConfigs%22&data=0x${data}` + ) + ).json(); + const res = r.result && r.result.response; + if (!res || res.code) + throw new Error(`abci_query failed: ${JSON.stringify(r)}`); + return { + node: info.result.response.version, + height: res.height, + configs: fields(Buffer.from(res.value || '', 'base64')) + .filter(([no]) => no === 1) + .map(([, v]) => tokenConfig(v)), + }; +} +function sdkResolve(chain, address) { + if (NATIVE.has(address)) + return getAddress(getNativePRC20ForChain(chain, DONUT)); + if (chain.startsWith('solana:')) { + const token = (MOVEABLE_TOKENS[chain] || []).find( + (t) => t.address === address + ); + if (!token) throw new Error('not in SDK registry'); + return getAddress(getPRC20Address(token, { network: DONUT }).address); + } + return resolveAgenticPrc20({ chain, address }, DONUT).address; +} +async function main() { + const { node, height, configs } = await nodeTokenConfigs(); + const report = { + at: new Date().toISOString(), + readOnly: true, + rpc: RPC, + node, + height, + matched: [], + mismatch: [], + nodeOnly: [], + sdkOnly: [], + presetTokens: [], + }; + const enabled = configs.filter((c) => c.enabled && c.prc20); + const nodePrc20s = new Set(enabled.map((c) => getAddress(c.prc20))); + for (const c of enabled) { + const entry = { + chain: c.chain, + address: c.address, + symbol: c.symbol, + decimals: c.decimals, + nodePrc20: getAddress(c.prc20), + }; + try { + const sdkPrc20 = sdkResolve(c.chain, c.address); + (sdkPrc20 === entry.nodePrc20 ? report.matched : report.mismatch).push({ + ...entry, + sdkPrc20, + }); + } catch (e) { + report.nodeOnly.push({ ...entry, sdk: e.message }); + } + } + const sdkPrc20s = new Map(); + for (const [key, address] of Object.entries(SYNTHETIC_PUSH_ERC20[DONUT])) + sdkPrc20s.set(getAddress(address), key); + for (const chain of new Set(enabled.map((c) => c.chain))) + for (const route of exactAgenticRoutes(chain, DONUT)) + sdkPrc20s.set(getAddress(route.prc20), `exact:${chain}:${route.source}`); + for (const [prc20, key] of sdkPrc20s) + if (!nodePrc20s.has(prc20)) report.sdkOnly.push({ key, prc20 }); + for (const preset of PRESET_CATALOG) + for (const chain of preset.chains) { + if (!enabled.some((c) => c.chain === chain.chainNamespace)) continue; + for (const token of chain.defaultTokens || []) { + const route = enabled.find( + (c) => + c.chain === chain.chainNamespace && + c.address.toLowerCase() === token.toLowerCase() + ); + report.presetTokens.push({ + preset: preset.constant, + chain: chain.chainNamespace, + token, + nodePrc20: route ? getAddress(route.prc20) : null, + }); + } + } + const json = JSON.stringify( + report, + (_k, v) => (typeof v === 'bigint' ? String(v) : v), + 2 + ); + if (process.argv[2]) fs.writeFileSync(process.argv[2], json); + console.log(json); + if (report.mismatch.length || report.sdkOnly.length) process.exitCode = 1; +} +main().catch((e) => { + console.error(e.message); + process.exitCode = 1; +}); diff --git a/packages/core/src/lib/agentic/__tests__/gas-budget.spec.ts b/packages/core/src/lib/agentic/__tests__/gas-budget.spec.ts new file mode 100644 index 00000000..a6985561 --- /dev/null +++ b/packages/core/src/lib/agentic/__tests__/gas-budget.spec.ts @@ -0,0 +1,220 @@ +import { CHAIN, PUSH_NETWORK } from '../../constants/enums'; +import type { Orchestrator } from '../../orchestrator/orchestrator'; +import type { OrchestratorContext } from '../../orchestrator/internals/context'; +import { quoteGasPoolCost } from '../../orchestrator/internals/gas-pool-quote'; +import { agwGasBudget } from '../execution/gas-budget'; +import { createAgenticRuntime } from '../runtime'; +import { ADDR } from './fake-chain'; + +// One shared fn: requireActual re-enters this factory through circular imports. +const mockQuery = jest.fn(); +jest.mock('../../orchestrator/internals/gas-calculator', () => ({ + ...jest.requireActual('../../orchestrator/internals/gas-calculator'), + queryOutboundGasFee: (...args: unknown[]) => mockQuery(...args), +})); +const mockFinalize = jest.fn(); +jest.mock('../../orchestrator/internals/svm-rent', () => ({ + ...jest.requireActual('../../orchestrator/internals/svm-rent'), + ensureSvmFinalizeGasBudgetQuote: (...args: unknown[]) => + mockFinalize(...args), +})); +const PC = BigInt(10) ** BigInt(18); + +describe('AGW gas budget', () => { + it('excludes protocolFee, which the wallet attaches separately', () => { + expect( + agwGasBudget({ protocolFee: BigInt(3), nativeValueForGas: BigInt(13) }) + ).toBe(BigInt(10)); + }); + it('keeps the over-$10 share the sizer splits off for other routes', () => { + expect( + agwGasBudget({ + protocolFee: BigInt(0), + nativeValueForGas: BigInt(100) * PC, + sizing: { category: 'C', overflowNativePc: BigInt(806) * PC }, + }) + ).toBe(BigInt(906) * PC); + }); + it('never attaches less than the pool cost plus 20%, rounded up', () => { + // A Sepolia-UEA BNB first send: sized 23.00 PC, pool needs 23.65 PC. + const sized = BigInt('22998723343893328290'); + const pool = BigInt('23653617545786043528'); + expect( + agwGasBudget({ protocolFee: BigInt(0), nativeValueForGas: sized }, pool) + ).toBe((pool * BigInt(12) + BigInt(9)) / BigInt(10)); + // The $1 floor still wins when the pool is cheap (the observed case). + expect( + agwGasBudget( + { protocolFee: BigInt(0), nativeValueForGas: BigInt(10) * PC }, + BigInt('2069650875064483730') + ) + ).toBe(BigInt(10) * PC); + }); +}); + +describe('pool cost quote', () => { + const ctx = (reads: Record) => + ({ + pushNetwork: PUSH_NETWORK.TESTNET_DONUT, + printTraces: false, + pushClient: { + readContract: jest.fn( + async ({ functionName }: { functionName: string }) => { + const value = reads[functionName]; + if (value instanceof Error) throw value; + return value; + } + ), + }, + } as unknown as OrchestratorContext); + it('returns the exact-output WPC amount for the gas fee', async () => { + const c = ctx({ + WPC: ADDR.other, + defaultFeeTier: 500, + quoteExactOutputSingle: [BigInt(7), BigInt(0), 0, BigInt(0)], + }); + await expect( + quoteGasPoolCost(c, ADDR.target, ADDR.agent, BigInt(5)) + ).resolves.toBe(BigInt(7)); + expect( + (c.pushClient.readContract as jest.Mock).mock.calls[2][0].args[0] + ).toEqual({ + tokenIn: ADDR.other, + tokenOut: ADDR.agent, + amount: BigInt(5), + fee: 500, + sqrtPriceLimitX96: BigInt(0), + }); + }); + it('is unknown without a fee tier, a fee or a working quoter', async () => { + await expect( + quoteGasPoolCost( + ctx({ WPC: ADDR.other, defaultFeeTier: 0 }), + ADDR.target, + ADDR.agent, + BigInt(5) + ) + ).resolves.toBeUndefined(); + await expect( + quoteGasPoolCost(ctx({}), ADDR.target, ADDR.agent, BigInt(0)) + ).resolves.toBeUndefined(); + await expect( + quoteGasPoolCost( + ctx({ + WPC: ADDR.other, + defaultFeeTier: 500, + quoteExactOutputSingle: new Error('no pool'), + }), + ADDR.target, + ADDR.agent, + BigInt(5) + ) + ).resolves.toBeUndefined(); + }); +}); + +describe('AGW runtime quotes', () => { + const quote = (gasFee: bigint) => ({ + gasToken: ADDR.agent, + gasFee, + protocolFee: BigInt(2), + nativeValueForGas: BigInt(12), + gasPrice: BigInt(1), + gasLimitUsed: BigInt(500000), + universalCoreAddress: ADDR.target, + sizing: { category: 'A', overflowNativePc: BigInt(0) }, + }); + const runtime = () => { + const readContract = jest.fn( + async ({ functionName }: { functionName: string }) => + functionName === 'WPC' + ? ADDR.other + : functionName === 'defaultFeeTier' + ? 500 + : functionName === 'baseGasLimitByChainNamespace' + ? BigInt(500000) + : [BigInt(50), BigInt(0), 0, BigInt(0)] + ); + return createAgenticRuntime( + { + getNetwork: () => PUSH_NETWORK.TESTNET_DONUT, + getRpcUrls: () => ({}), + pushNetwork: PUSH_NETWORK.TESTNET_DONUT, + pushClient: { readContract }, + } as unknown as Orchestrator, + true + ); + }; + const svm = { wallet: ADDR.owner, burnAmount: BigInt(1) }; + beforeEach(() => { + mockQuery.mockReset(); + mockFinalize.mockReset(); + }); + + it('return the pool-safe budget and keep protocolFee separate', async () => { + mockQuery.mockResolvedValue(quote(BigInt(5))); + await expect( + runtime().quoteOutbound(ADDR.agent, BigInt(0), CHAIN.ETHEREUM_SEPOLIA) + ).resolves.toEqual({ + protocolFee: BigInt(2), + nativeValueForGas: BigInt(60), + gasLimitUsed: BigInt(500000), + gasFee: BigInt(5), + poolPcIn: BigInt(50), + }); + expect(mockQuery).toHaveBeenCalledWith( + expect.anything(), + ADDR.agent, + BigInt(0), + CHAIN.ETHEREUM_SEPOLIA + ); + }); + it('refuse an explicit gasLimit below the chain base before quoting', async () => { + await expect( + runtime().quoteOutbound( + ADDR.agent, + BigInt(100000), + CHAIN.ETHEREUM_SEPOLIA + ) + ).rejects.toMatchObject({ + code: 'INVALID_RULE', + details: { field: 'gasLimit', minimum: BigInt(500000) }, + }); + expect(mockQuery).not.toHaveBeenCalled(); + mockQuery.mockResolvedValue(quote(BigInt(5))); + await expect( + runtime().quoteOutbound( + ADDR.agent, + BigInt(500000), + CHAIN.ETHEREUM_SEPOLIA + ) + ).resolves.toMatchObject({ gasFee: BigInt(5) }); + }); + it('re-quote a Solana budget left short by a gas-price change', async () => { + mockQuery.mockResolvedValue(quote(BigInt(1))); + mockFinalize + .mockImplementationOnce(async ({ onMinimum }) => { + onMinimum(BigInt(10)); + return quote(BigInt(9)); + }) + .mockImplementationOnce(async ({ onMinimum, quote: q }) => { + onMinimum(BigInt(10)); + expect(q.gasFee).toBe(BigInt(9)); + return quote(BigInt(10)); + }); + await expect( + runtime().quoteOutbound(ADDR.agent, BigInt(0), CHAIN.SOLANA_DEVNET, svm) + ).resolves.toMatchObject({ gasFee: BigInt(10) }); + expect(mockFinalize).toHaveBeenCalledTimes(2); + }); + it('refuse a Solana budget that stays short after re-quoting', async () => { + mockQuery.mockResolvedValue(quote(BigInt(1))); + mockFinalize.mockImplementation(async ({ onMinimum }) => { + onMinimum(BigInt(10)); + return quote(BigInt(9)); + }); + await expect( + runtime().quoteOutbound(ADDR.agent, BigInt(0), CHAIN.SOLANA_DEVNET, svm) + ).rejects.toMatchObject({ code: 'INCONSISTENT_READ' }); + }); +}); diff --git a/packages/core/src/lib/agentic/__tests__/preset-routes.spec.ts b/packages/core/src/lib/agentic/__tests__/preset-routes.spec.ts index 789ea6dd..c64ccee5 100644 --- a/packages/core/src/lib/agentic/__tests__/preset-routes.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/preset-routes.spec.ts @@ -20,7 +20,8 @@ it('reports unmapped source tokens without silently changing the default Push gr }); it('preserves assets and rejects the removed funding option instead of silently changing permissions', () => { const result = agenticPresets.get('DEXES', options); - expect(result.readiness.ready).toBe(false); + // WETH and Circle USDC both have exact node routes on Sepolia. + expect(result.readiness.ready).toBe(true); expect(result.rules[0].assets).toEqual( result.readiness.chains[0].selectedAssets ); @@ -111,6 +112,10 @@ it('reports exact unavailable assets across all nine testnet preset combinations CHAIN.ARBITRUM_SEPOLIA, CHAIN.BNB_TESTNET, ]; + const routed = new Set([ + `DEXES:${CHAIN.ETHEREUM_SEPOLIA}`, + `LENDING:${CHAIN.ARBITRUM_SEPOLIA}`, + ]); let checked = 0; for (const category of ['DEXES', 'LENDING', 'STAKING'] as const) { const entry = agenticPresets @@ -123,7 +128,9 @@ it('reports exact unavailable assets across all nine testnet preset combinations agent: ADDR.agent, chainNamespace, }); - expect(res.readiness.ready).toBe(false); + expect(res.readiness.ready).toBe( + routed.has(`${category}:${chainNamespace}`) + ); const state = res.readiness.chains[0]; expect(res.rules[0].assets).toEqual(state.selectedAssets); for (const asset of state.bridgeAssets.filter( diff --git a/packages/core/src/lib/agentic/__tests__/send.spec.ts b/packages/core/src/lib/agentic/__tests__/send.spec.ts index c5ce94e7..b59cbe59 100644 --- a/packages/core/src/lib/agentic/__tests__/send.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/send.spec.ts @@ -352,7 +352,8 @@ describe('EVM outbound composition from the wallet', () => { it.each([ [false, undefined, BigInt(2_000_000)], - [true, undefined, BigInt(0)], + // Token export plus a call: transfer + call exceed the network base. + [true, undefined, BigInt(1_000_000)], [false, BigInt(123456), BigInt(123456)], [true, BigInt(123456), BigInt(123456)], [false, BigInt(0), BigInt(0)], @@ -382,6 +383,37 @@ describe('EVM outbound composition from the wallet', () => { } ); + it.each([ + ['a single call without a token export', undefined, BigInt(0)], + ['a native-value export with one call', BigInt(5), BigInt(0)], + ])( + 'destination gas on a deployed CEA keeps the network base for %s', + async (_label, value, expected) => { + const s = universalSetup(); + const native = getAddress('0x0000000000000000000000000000000000007171'); + s.fake.balances.set(`balanceOf:${native.toLowerCase()}`, BigInt(10)); + const quoteOutbound = jest.fn(async (_token: Address, _gas: bigint) => ({ + protocolFee: BigInt(100), + nativeValueForGas: BigInt(1000), + gasLimitUsed: BigInt(200_000), + })); + const rt = mockRuntime(s.fake, { + signer: ADDR.agent, + resolvePrc20: (t: unknown) => (t === undefined ? native : token), + resolveCEA: async () => ({ + cea: getAddress('0x000000000000000000000000000000000000cea1'), + isDeployed: true, + }), + quoteOutbound, + }); + await agenticSend(rt, s.ctx, { + ...send(), + ...(value === undefined ? {} : { value }), + }); + expect(quoteOutbound.mock.calls[0][1]).toBe(expected); + } + ); + it('builds the policy-compatible request: empty recipient, wallet refund, nonzero gas cap, multicall payload, CEA of the wallet', async () => { const s = universalSetup(); const resolveCEA = jest.fn(async () => ({ diff --git a/packages/core/src/lib/agentic/__tests__/svm-agent-send-defaults.spec.ts b/packages/core/src/lib/agentic/__tests__/svm-agent-send-defaults.spec.ts new file mode 100644 index 00000000..feeec976 --- /dev/null +++ b/packages/core/src/lib/agentic/__tests__/svm-agent-send-defaults.spec.ts @@ -0,0 +1,77 @@ +import { PublicKey } from '@solana/web3.js'; +import { CHAIN } from '../../constants/enums'; +import { sendPublicSvm } from '../execution/svm-public'; +import { resetAgenticGenerations } from '../deployments'; +import { ADDR, FakeChain, registerFakeGeneration } from './fake-chain'; +import { mockRuntime } from './mock-runtime'; + +const mockPrepare = jest.fn(); +jest.mock('../execution/svm-send', () => ({ + ...jest.requireActual('../execution/svm-send'), + prepareSvmAgentExecution: (...args: unknown[]) => mockPrepare(...args), +})); +jest.mock('../reads/rules', () => ({ + ...jest.requireActual('../reads/rules'), + selectRuleForSend: async () => ({ rulesId: `0x${'ab'.repeat(32)}` }), +})); +jest.mock('../reads/svm', () => ({ + ...jest.requireActual('../reads/svm'), + readSvmConfig: async () => ({ + config: { expectedCEA: `0x${'cc'.repeat(32)}`, assets: [] }, + }), +})); + +afterEach(resetAgenticGenerations); +it.each([undefined, BigInt(0), BigInt(5000)])( + 'agent Solana sends pass gasLimit %s to route sizing unchanged, defaulting to 0', + async (gasLimit) => { + const gen = registerFakeGeneration(); + mockPrepare.mockReset().mockResolvedValue({ + data: '0x1234', + instruction: { + recipient: `0x${'22'.repeat(32)}`, + instructionData: new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]), + accounts: [], + }, + }); + const rt = mockRuntime(new FakeChain(), { + signer: ADDR.agent, + resolvePrc20: () => ADDR.target, + svmMetadata: { + gateway: async () => ({ + chainNamespace: CHAIN.SOLANA_DEVNET, + program: `0x${'22'.repeat(32)}`, + }), + mint: async () => { + throw new Error('No mint read in this send'); + }, + }, + }); + await sendPublicSvm( + rt, + { + wallet: ADDR.other, + door: 'agent', + signerPushAccount: ADDR.agent, + signerOrigin: { chain: CHAIN.PUSH_TESTNET_DONUT, address: ADDR.agent }, + generation: gen, + }, + { + to: { + address: PublicKey.default.toBase58(), + chain: CHAIN.SOLANA_DEVNET, + }, + data: '0x0102030405060708', + funds: { token: ADDR.target as never, amount: BigInt(1) }, + ...(gasLimit === undefined ? {} : { gasLimit }), + } + ); + expect(mockPrepare).toHaveBeenCalledTimes(1); + expect(mockPrepare.mock.calls[0][2]).toMatchObject({ + wallet: ADDR.other, + amount: BigInt(1), + gasLimit: gasLimit ?? BigInt(0), + }); + expect(rt.executeMock).toHaveBeenCalledTimes(1); + } +); diff --git a/packages/core/src/lib/agentic/__tests__/svm-quote.spec.ts b/packages/core/src/lib/agentic/__tests__/svm-quote.spec.ts index 766135cd..83e9bcd1 100644 --- a/packages/core/src/lib/agentic/__tests__/svm-quote.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/svm-quote.spec.ts @@ -249,3 +249,16 @@ describe('AGW Solana finalization quote context', () => { expect(rt.resolvePrc20).toHaveBeenCalledWith(expected, CHAIN.SOLANA_DEVNET); }); }); +it('refuses a zero Solana gas ceiling, which would reject every agent send', async () => { + const f = fixture(); + await expect( + preparePublicSvmRule(f.rt, f.snap, ADDR.owner, { + agent: ADDR.agent, + chainNamespace: CHAIN.SOLANA_DEVNET, + assets: [], + validUntil: f.rt.nowSeconds() + 3600, + maxGasPerCall: BigInt(0), + allowedInstructions: [], + }) + ).rejects.toThrow('maxGasPerCall must be positive'); +}); diff --git a/packages/core/src/lib/agentic/__tests__/svm-send-defaults.spec.ts b/packages/core/src/lib/agentic/__tests__/svm-send-defaults.spec.ts new file mode 100644 index 00000000..02d99937 --- /dev/null +++ b/packages/core/src/lib/agentic/__tests__/svm-send-defaults.spec.ts @@ -0,0 +1,66 @@ +import { PublicKey } from '@solana/web3.js'; +import { CHAIN } from '../../constants/enums'; +import { sendPublicSvm } from '../execution/svm-public'; +import { resetAgenticGenerations } from '../deployments'; +import { ADDR, FakeChain, registerFakeGeneration } from './fake-chain'; +import { mockRuntime } from './mock-runtime'; + +afterEach(resetAgenticGenerations); +it.each([undefined, BigInt(0), BigInt(5000)])( + 'sizes a public SVM owner transfer through the route quote, preserving explicit gas: %s', + async (gasLimit) => { + const gen = registerFakeGeneration(); + const fake = new FakeChain(); + fake.getBalance = async () => BigInt(10) ** BigInt(20); + fake.readContract = async ({ functionName }) => { + if (functionName === 'SOURCE_CHAIN_NAMESPACE') return CHAIN.SOLANA_DEVNET; + if (functionName === 'gasTokenPRC20ByChainNamespace') return ADDR.target; + if (functionName === 'balanceOf') return BigInt(1000000); + throw new Error(`Unexpected read: ${functionName}`); + }; + const quoteOutbound = jest.fn(async (_token, budget) => ({ + protocolFee: BigInt(0), + nativeValueForGas: BigInt(10), + gasLimitUsed: budget || BigInt(1052), + })); + const rt = mockRuntime(fake, { + signer: ADDR.owner, + resolvePrc20: () => ADDR.target, + quoteOutbound, + svmMetadata: { + gateway: async () => ({ + chainNamespace: CHAIN.SOLANA_DEVNET, + program: `0x${'22'.repeat(32)}`, + }), + mint: async () => { + throw new Error('No mint read for native SOL'); + }, + }, + }); + await sendPublicSvm( + rt, + { + wallet: ADDR.other, + door: 'owner', + signerPushAccount: ADDR.owner, + signerOrigin: { chain: CHAIN.PUSH_TESTNET_DONUT, address: ADDR.owner }, + generation: gen, + }, + { + to: { + address: PublicKey.default.toBase58(), + chain: CHAIN.SOLANA_DEVNET, + }, + value: BigInt(1), + ...(gasLimit === undefined ? {} : { gasLimit }), + } + ); + expect(quoteOutbound).toHaveBeenCalledWith( + ADDR.target, + gasLimit ?? BigInt(0), + CHAIN.SOLANA_DEVNET, + { wallet: ADDR.other, splMintBase58: undefined, burnAmount: BigInt(1) } + ); + expect(rt.executeMock).toHaveBeenCalledTimes(1); + } +); diff --git a/packages/core/src/lib/agentic/__tests__/token-routes.spec.ts b/packages/core/src/lib/agentic/__tests__/token-routes.spec.ts new file mode 100644 index 00000000..8535a169 --- /dev/null +++ b/packages/core/src/lib/agentic/__tests__/token-routes.spec.ts @@ -0,0 +1,123 @@ +import { getAddress } from 'viem'; +import { CHAIN, PUSH_NETWORK } from '../../constants/enums'; +import { SYNTHETIC_PUSH_ERC20 } from '../../constants/chain'; +import type { Orchestrator } from '../../orchestrator/orchestrator'; +import { createAgenticRuntime } from '../runtime'; +import { agenticPresets } from '../presets'; +import { exactAgenticRoute, resolveAgenticPrc20 } from '../token-routes'; +import { ADDR } from './fake-chain'; + +const CIRCLE = { + [CHAIN.ETHEREUM_SEPOLIA]: [ + '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238', + '0x387b9C8Db60E74999aAAC5A2b7825b400F12d68E', + ], + [CHAIN.BASE_SEPOLIA]: [ + '0x036CbD53842c5426634e7929541eC2318f3dCF7e', + '0x84B62e44F667F692F7739Ca6040cD17DA02068A8', + ], + [CHAIN.ARBITRUM_SEPOLIA]: [ + '0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d', + '0xa261A10e94aE4bA88EE8c5845CbE7266bD679DD6', + ], +} as const; +const runtime = () => + createAgenticRuntime( + { + getNetwork: () => PUSH_NETWORK.TESTNET_DONUT, + getRpcUrls: () => ({}), + } as unknown as Orchestrator, + false + ); + +it.each(Object.entries(CIRCLE))( + 'maps the exact node-registered Circle USDC on %s', + (chain, [source, prc20]) => { + expect( + resolveAgenticPrc20( + { chain, address: source.toLowerCase() }, + PUSH_NETWORK.TESTNET_DONUT + ) + ).toEqual({ address: getAddress(prc20), symbol: 'USDC', decimals: 6 }); + expect(runtime().resolvePrc20(source, chain as CHAIN)).toBe( + getAddress(prc20) + ); + expect(exactAgenticRoute(chain, source, PUSH_NETWORK.TESTNET)?.prc20).toBe( + prc20 + ); + } +); +it('never matches by symbol, by another chain or on another network', () => { + const donut = SYNTHETIC_PUSH_ERC20[PUSH_NETWORK.TESTNET_DONUT]; + // The SDK's routed Sepolia mock USDC keeps its own PRC20. + expect( + resolveAgenticPrc20( + { + chain: CHAIN.ETHEREUM_SEPOLIA, + address: '0x97F477B7f970D47a87B42869ceeace218106152a', + }, + PUSH_NETWORK.TESTNET_DONUT + ).address + ).toBe(getAddress(donut.USDC_ETH)); + const sepoliaCircle = CIRCLE[CHAIN.ETHEREUM_SEPOLIA][0]; + expect( + exactAgenticRoute( + CHAIN.BASE_SEPOLIA, + sepoliaCircle, + PUSH_NETWORK.TESTNET_DONUT + ) + ).toBeUndefined(); + expect(() => + runtime().resolvePrc20(sepoliaCircle, CHAIN.BASE_SEPOLIA) + ).toThrow(); + expect( + exactAgenticRoute( + CHAIN.ETHEREUM_SEPOLIA, + sepoliaCircle, + PUSH_NETWORK.MAINNET + ) + ).toBeUndefined(); + expect( + exactAgenticRoute(CHAIN.ETHEREUM_SEPOLIA, 'USDC', PUSH_NETWORK.TESTNET) + ).toBeUndefined(); +}); +it.each([ + ['DEXES', CHAIN.ETHEREUM_SEPOLIA], + ['LENDING', CHAIN.ARBITRUM_SEPOLIA], +] as const)( + '%s %s defaults are route-ready with unchanged assets and caps', + (category, chainNamespace) => { + const res = agenticPresets.get(category, { + chainNamespace, + agent: ADDR.agent, + }); + expect(res.readiness.ready).toBe(true); + const state = res.readiness.chains[0]; + expect(state.bridgeAssets.every((a) => a.status === 'registered')).toBe( + true + ); + expect(state.bridgeAssets).toContainEqual({ + token: getAddress(CIRCLE[chainNamespace][0]), + prc20: getAddress(CIRCLE[chainNamespace][1]), + status: 'registered', + }); + expect(res.rules[0].assets).toEqual(state.selectedAssets); + } +); +it('Base DEX USDC is routed while its WETH leg stays unavailable', () => { + const state = agenticPresets.get('DEXES', { + chainNamespace: CHAIN.BASE_SEPOLIA, + agent: ADDR.agent, + }).readiness.chains[0]; + expect(state.bridgeAssets).toEqual([ + { + token: '0x4200000000000000000000000000000000000006', + status: 'unavailable', + }, + { + token: getAddress(CIRCLE[CHAIN.BASE_SEPOLIA][0]), + prc20: getAddress(CIRCLE[CHAIN.BASE_SEPOLIA][1]), + status: 'registered', + }, + ]); +}); diff --git a/packages/core/src/lib/agentic/execution/gas-budget.ts b/packages/core/src/lib/agentic/execution/gas-budget.ts new file mode 100644 index 00000000..26b14e6c --- /dev/null +++ b/packages/core/src/lib/agentic/execution/gas-budget.ts @@ -0,0 +1,69 @@ +import { UNIVERSAL_CORE_EVM } from '../../constants/abi/prc20.evm'; +import type { OrchestratorContext } from '../../orchestrator/internals/context'; +import { CORE_ADDRESS } from '../contracts/prc20-metadata'; +import { AGENTIC_ERROR_CODE, AgenticError } from '../errors'; + +/** Headroom over the pool quote; the gateway refunds whatever the swap leaves. */ +const POOL_HEADROOM_NUM = BigInt(12); +const POOL_HEADROOM_DEN = BigInt(10); + +/** + * PC gas budget (maxPCForGas) for an AGW outbound, excluding protocolFee. + * The gateway buys exactly `gasFee` of the gas token from the Donut WPC pool + * and reverts when the budget cannot. The shared USD sizer can attach less: + * its over-$10 overflow has no funds leg on this path, and its USD price can + * differ from the pool. Keep the larger of the sized budget and the pool cost. + */ +export function agwGasBudget( + quote: { + protocolFee: bigint; + nativeValueForGas: bigint; + sizing?: { category: string; overflowNativePc: bigint }; + }, + poolPcIn?: bigint +): bigint { + const sized = + (quote.nativeValueForGas > quote.protocolFee + ? quote.nativeValueForGas - quote.protocolFee + : BigInt(0)) + + (quote.sizing?.category === 'C' + ? quote.sizing.overflowNativePc + : BigInt(0)); + const pool = + poolPcIn === undefined + ? BigInt(0) + : (poolPcIn * POOL_HEADROOM_NUM + POOL_HEADROOM_DEN - BigInt(1)) / + POOL_HEADROOM_DEN; + return sized > pool ? sized : pool; +} + +/** Refuses an explicit gasLimit below the chain base before quoting, where core + * would otherwise revert. Omitted or zero gas uses the base. */ +export async function assertGasLimitAtLeastBase( + ctx: OrchestratorContext, + chain: string, + gasLimit: bigint +): Promise { + if (gasLimit <= BigInt(0)) return; + let base: bigint; + try { + base = await ctx.pushClient.readContract({ + address: CORE_ADDRESS, + abi: UNIVERSAL_CORE_EVM, + functionName: 'baseGasLimitByChainNamespace', + args: [chain], + }); + } catch { + return; // The quote itself reports any real failure. + } + if (gasLimit < base) + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + `gasLimit ${gasLimit} is below the ${chain} minimum of ${base}; omit it or pass 0 to use the network default`, + { + userMessage: + 'The gas limit is below this network’s minimum. Leave it empty to use the network default.', + details: { field: 'gasLimit', minimum: base }, + } + ); +} diff --git a/packages/core/src/lib/agentic/execution/outbound.ts b/packages/core/src/lib/agentic/execution/outbound.ts index 5e77b6f6..63b5beb0 100644 --- a/packages/core/src/lib/agentic/execution/outbound.ts +++ b/packages/core/src/lib/agentic/execution/outbound.ts @@ -30,6 +30,10 @@ import type { AgenticRuntime } from '../runtime'; /** Includes first-use CEA deployment; explicit caller gas always takes precedence. */ const FIRST_USE_EVM_GAS_LIMIT = BigInt(2_000_000); +/** Token exports and multi-call payloads can exceed the 500k network base: a + * Sepolia Circle USDC export with approve + Uniswap swap ran out of gas on it. */ +const MULTI_STEP_EVM_GAS_LIMIT = BigInt(1_000_000); + /** URP MAX_ACTIONS_PER_REQUEST at v6. */ export const MAX_DESTINATION_CALLS = 10; @@ -220,10 +224,18 @@ export async function composeOutbound( } } + const multiStep = + calls.length > 1 || + (amount > BigInt(0) && + getAddress(token) !== getAddress(runtime.resolvePrc20(undefined, chain))); const quote = await runtime.quoteOutbound( token, params.gasLimit ?? - (resolved.isDeployed ? BigInt(0) : FIRST_USE_EVM_GAS_LIMIT), + (!resolved.isDeployed + ? FIRST_USE_EVM_GAS_LIMIT + : multiStep + ? MULTI_STEP_EVM_GAS_LIMIT + : BigInt(0)), chain ); if (quote.nativeValueForGas <= BigInt(0)) { diff --git a/packages/core/src/lib/agentic/execution/svm-public.ts b/packages/core/src/lib/agentic/execution/svm-public.ts index d8c3e575..93d651b7 100644 --- a/packages/core/src/lib/agentic/execution/svm-public.ts +++ b/packages/core/src/lib/agentic/execution/svm-public.ts @@ -78,7 +78,10 @@ export async function sendPublicSvm( cea: Hex; let destinationTransfer: AgenticTxMetadata['destinationTransfer']; let transferValue = BigInt(0); - const gasLimit = p.gasLimit ?? BigInt(1_000_000); + // SVM gateway gasLimit is a lamport-budget conversion input, not EVM gas + // units. Let the live route quote and finalize-rent floor size an omitted + // limit; copying an EVM-style million-unit fallback can overquote 100 PC. + const gasLimit = p.gasLimit ?? BigInt(0); if (actx.door === 'agent') { const active = await selectRuleForSend( snap, diff --git a/packages/core/src/lib/agentic/management/svm-public.ts b/packages/core/src/lib/agentic/management/svm-public.ts index 42289b8a..96da8645 100644 --- a/packages/core/src/lib/agentic/management/svm-public.ts +++ b/packages/core/src/lib/agentic/management/svm-public.ts @@ -37,6 +37,9 @@ export async function preparePublicSvmRule( throw svmInvalid('unknown Solana chain'); if (!Array.isArray(rule.assets) || rule.assets.length > 8) throw svmInvalid('assets must contain at most eight entries'); + // URP compares the attached PC to this ceiling, so zero refuses every send. + if (rule.maxGasPerCall === BigInt(0)) + throw svmInvalid('maxGasPerCall must be positive'); const raw = 'format' in rule && rule.format === 'decoded'; const outputTokens = 'outputTokens' in rule ? rule.outputTokens : undefined; if (outputTokens !== undefined && !Array.isArray(outputTokens)) diff --git a/packages/core/src/lib/agentic/presets/routes.ts b/packages/core/src/lib/agentic/presets/routes.ts index c18269d8..c022fa08 100644 --- a/packages/core/src/lib/agentic/presets/routes.ts +++ b/packages/core/src/lib/agentic/presets/routes.ts @@ -1,7 +1,6 @@ -import { getAddress } from 'viem'; import { PUSH_NETWORK, type CHAIN } from '../../constants/enums'; import { SUPPORTED_GATEWAY_CHAINS } from '../../orchestrator/internals/helpers'; -import { getPRC20Address } from '../../universal/prc20-address'; +import { resolveAgenticPrc20 } from '../token-routes'; import { generationsFor } from '../deployments'; import type { RuleAsset } from '../agentic.types'; import type { PresetChainReadiness, PresetConfigurationIssue } from './types'; @@ -35,10 +34,10 @@ export function presetRoutes( const token = assetAddress(asset); try { if (!supported) throw new Error(`No supported gateway route to ${chain}`); - const prc20 = getPRC20Address({ chain, address: token }, { network }); + const prc20 = resolveAgenticPrc20({ chain, address: token }, network); return { token, - prc20: getAddress(prc20.address), + prc20: prc20.address, status: 'registered' as const, }; } catch { diff --git a/packages/core/src/lib/agentic/runtime.ts b/packages/core/src/lib/agentic/runtime.ts index 530e672e..89af2571 100644 --- a/packages/core/src/lib/agentic/runtime.ts +++ b/packages/core/src/lib/agentic/runtime.ts @@ -26,6 +26,12 @@ import { } from '../orchestrator/internals/helpers'; import { pushChainNamespaceFor } from './chain'; import { getPRC20Address } from '../universal/prc20-address'; +import { resolveAgenticPrc20 } from './token-routes'; +import { + agwGasBudget, + assertGasLimitAtLeastBase, +} from './execution/gas-budget'; +import { quoteGasPoolCost } from '../orchestrator/internals/gas-pool-quote'; import { chainReaderFromPublicClient, type ChainReader, @@ -76,8 +82,12 @@ export interface AgenticRuntime { svm?: { wallet: Address; splMintBase58?: string; burnAmount: bigint } ): Promise<{ protocolFee: bigint; + /** PC gas budget sent as maxPCForGas; protocolFee is attached separately. */ nativeValueForGas: bigint; gasLimitUsed: bigint; + /** Diagnostics: gas-token fee and the pool's current PC cost for it. */ + gasFee?: bigint; + poolPcIn?: bigint; }>; resolveCEA( account: Address, @@ -139,23 +149,49 @@ export function createAgenticRuntime( signerBalance: () => ctx.pushClient.getBalance(computeUEAOffchain(ctx)), getGasPrice: () => ctx.pushClient.getGasPrice(), quoteOutbound: async (prc20, gasLimit, chain, svm) => { + await assertGasLimitAtLeastBase(ctx, chain, gasLimit); let q = await queryOutboundGasFee(ctx, prc20, gasLimit, chain); if (svm) { - q = await ensureSvmFinalizeGasBudgetQuote({ - ctx, - ueaAddress: svm.wallet, - targetChain: chain, - prc20Token: prc20, - quote: q, - splMintBase58: svm.splMintBase58, - burnAmount: svm.burnAmount, - pathTag: 'AGW_SVM', - }); + let minimum = BigInt(0); + const finalize = (quote: typeof q) => + ensureSvmFinalizeGasBudgetQuote({ + ctx, + ueaAddress: svm.wallet, + targetChain: chain, + prc20Token: prc20, + quote, + splMintBase58: svm.splMintBase58, + burnAmount: svm.burnAmount, + pathTag: 'AGW_SVM', + onMinimum: (m) => { + minimum = m; + }, + }); + q = await finalize(q); + // A gas-price change between quote and re-quote can leave the bump short. + if (q.gasFee < minimum) q = await finalize(q); + if (q.gasFee < minimum) + throw new AgenticError( + AGENTIC_ERROR_CODE.INCONSISTENT_READ, + `Solana finalize budget ${q.gasFee} is below the required ${minimum} lamports after re-quoting`, + { + userMessage: + 'Network gas prices changed while preparing this transaction. Try again.', + } + ); } + const poolPcIn = await quoteGasPoolCost( + ctx, + q.universalCoreAddress, + q.gasToken, + q.gasFee + ); return { protocolFee: q.protocolFee, - nativeValueForGas: q.nativeValueForGas, + nativeValueForGas: agwGasBudget(q, poolPcIn), gasLimitUsed: q.gasLimitUsed, + gasFee: q.gasFee, + poolPcIn, }; }, resolveCEA: async (account, chain) => { @@ -178,12 +214,10 @@ export function createAgenticRuntime( ); return getAddress(getPRC20Address(token, { network }).address); } - return getAddress( - getPRC20Address( - { chain, address: typeof token === 'string' ? token : token.address }, - { network } - ).address - ); + return resolveAgenticPrc20( + { chain, address: typeof token === 'string' ? token : token.address }, + network + ).address; }, nowSeconds: () => Math.floor(Date.now() / 1000), }; diff --git a/packages/core/src/lib/agentic/token-routes.ts b/packages/core/src/lib/agentic/token-routes.ts new file mode 100644 index 00000000..ea3ce968 --- /dev/null +++ b/packages/core/src/lib/agentic/token-routes.ts @@ -0,0 +1,93 @@ +import { getAddress, isAddress, type Address } from 'viem'; +import { PUSH_NETWORK } from '../constants/enums'; +import { getPRC20Address } from '../universal/prc20-address'; + +export interface AgenticTokenRoute { + /** Exact destination-chain token address. */ + source: Address; + /** Push PRC20 the node registry maps that token to. */ + prc20: Address; + symbol: string; + decimals: number; +} + +/** Exact routes enabled in the node's uregistry that the shared symbol-keyed + * registry cannot hold (a second USDC on one chain). Snapshot: Donut uregistry + * height 24,457,377; SOURCE_* metadata, decimals and outbound quotes checked at + * block 24,457,398. Grant preparation still verifies the source on chain. + */ +const DONUT_EXACT_ROUTES: Readonly< + Record +> = { + 'eip155:11155111': [ + { + source: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238', + prc20: '0x387b9C8Db60E74999aAAC5A2b7825b400F12d68E', + symbol: 'USDC', + decimals: 6, + }, + ], + 'eip155:84532': [ + { + source: '0x036CbD53842c5426634e7929541eC2318f3dCF7e', + prc20: '0x84B62e44F667F692F7739Ca6040cD17DA02068A8', + symbol: 'USDC', + decimals: 6, + }, + ], + 'eip155:421614': [ + { + source: '0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d', + prc20: '0xa261A10e94aE4bA88EE8c5845CbE7266bD679DD6', + symbol: 'USDC', + decimals: 6, + }, + ], +}; + +const EXACT_ROUTES: Partial< + Record>> +> = { + [PUSH_NETWORK.TESTNET_DONUT]: DONUT_EXACT_ROUTES, + [PUSH_NETWORK.TESTNET]: DONUT_EXACT_ROUTES, +}; + +export function exactAgenticRoutes( + chain: string, + network: PUSH_NETWORK +): readonly AgenticTokenRoute[] { + return EXACT_ROUTES[network]?.[chain] ?? []; +} + +/** Match by chain AND exact address; never by symbol. */ +export function exactAgenticRoute( + chain: string, + source: string, + network: PUSH_NETWORK +): AgenticTokenRoute | undefined { + if (!isAddress(source, { strict: false })) return undefined; + const wanted = getAddress(source); + return exactAgenticRoutes(chain, network).find( + (route) => getAddress(route.source) === wanted + ); +} + +/** AGW source-token resolution: exact node routes first, then the shared registry. */ +export function resolveAgenticPrc20( + token: { chain: string; address: string }, + network: PUSH_NETWORK +): { address: Address; symbol: string; decimals: number } { + const exact = exactAgenticRoute(token.chain, token.address, network); + if (exact) + return { + address: getAddress(exact.prc20), + symbol: exact.symbol, + decimals: exact.decimals, + }; + const mapped = getPRC20Address(token, { network }); + return { + address: getAddress(mapped.address), + symbol: mapped.symbol, + decimals: mapped.decimals, + }; +} diff --git a/packages/core/src/lib/constants/tokens.ts b/packages/core/src/lib/constants/tokens.ts index fc3dc1a2..c2c710ad 100644 --- a/packages/core/src/lib/constants/tokens.ts +++ b/packages/core/src/lib/constants/tokens.ts @@ -235,7 +235,7 @@ const TOKEN_META: Partial>> = { WETH: { symbol: 'WETH', decimals: 18, - address: '0xfff9976782d46cc05630d1f6ebab18b2324d6b14', + address: '0x4200000000000000000000000000000000000006', mechanism: 'approve', }, }, diff --git a/packages/core/src/lib/orchestrator/__tests__/gas-usd-sizer.spec.ts b/packages/core/src/lib/orchestrator/__tests__/gas-usd-sizer.spec.ts index 8550f9f6..19afc287 100644 --- a/packages/core/src/lib/orchestrator/__tests__/gas-usd-sizer.spec.ts +++ b/packages/core/src/lib/orchestrator/__tests__/gas-usd-sizer.spec.ts @@ -398,3 +398,62 @@ describe('sizeR1PushGas — R1 Push-chain gas sizing', () => { expect(decision.paddedDepositUsd).toBe(__THRESHOLDS.TEN_USD_8D); }); }); + +describe('sizeOutboundGas — BNB testnet gas is valued at the Push pool rate', () => { + const pool = { + universalCore: '0x0000000000000000000000000000000000001111', + gasToken: '0x0000000000000000000000000000000000005555', + } as const; + const PC = BigInt(10) ** BigInt(18); + // The BSC gateway feed reports ETH/USD; it must not price BNB gas. + const ethFeed = BigInt(2450_0000_0000); + function poolCtx(pcIn: bigint | Error) { + const ctx = makeCtx(); + const readContract = ctx.pushClient.readContract as unknown as jest.Mock; + const base = readContract.getMockImplementation()!; + readContract.mockImplementation(async (args: { functionName: string }) => { + if (args.functionName !== 'quoteExactOutputSingle') return base(args); + if (pcIn instanceof Error) throw pcIn; + return [pcIn, BigInt(0), 0, BigInt(0)]; + }); + return ctx; + } + + it('uses the exact-output pool cost instead of the ETH feed', async () => { + mockGetPrice.mockResolvedValue(ethFeed); + // 23.65 PC at $0.10/PC = $2.365 → Case B. + const pcIn = (PC * BigInt(2365)) / BigInt(100); + const r = await sizeOutboundGas(poolCtx(pcIn), { + gasFee: BigInt('2200000000000000'), + originChain: CHAIN.ETHEREUM_SEPOLIA, + destinationChain: CHAIN.BNB_TESTNET, + pool, + }); + expect(mockGetPrice).not.toHaveBeenCalled(); + expect(r.category).toBe('B'); + expect(r.gasUsd).toBe(BigInt(236_500_000)); + expect(r.gasLegNativePc).toBe(pcIn); + }); + + it('falls back to the feed when the pool cannot be quoted', async () => { + mockGetPrice.mockResolvedValue(ethFeed); + await sizeOutboundGas(poolCtx(new Error('no pool')), { + gasFee: BigInt('2200000000000000'), + originChain: CHAIN.ETHEREUM_SEPOLIA, + destinationChain: CHAIN.BNB_TESTNET, + pool, + }); + expect(mockGetPrice).toHaveBeenCalledWith(CHAIN.ETHEREUM_SEPOLIA); + }); + + it('keeps ETH destinations on the ETH feed', async () => { + mockGetPrice.mockResolvedValue(ethFeed); + await sizeOutboundGas(poolCtx(PC), { + gasFee: BigInt('2200000000000000'), + originChain: CHAIN.ETHEREUM_SEPOLIA, + destinationChain: CHAIN.BASE_SEPOLIA, + pool, + }); + expect(mockGetPrice).toHaveBeenCalledWith(CHAIN.ETHEREUM_SEPOLIA); + }); +}); diff --git a/packages/core/src/lib/orchestrator/internals/gas-calculator.ts b/packages/core/src/lib/orchestrator/internals/gas-calculator.ts index 3d1abbba..8d36c31d 100644 --- a/packages/core/src/lib/orchestrator/internals/gas-calculator.ts +++ b/packages/core/src/lib/orchestrator/internals/gas-calculator.ts @@ -28,6 +28,10 @@ import { SvmClient } from '../../vm-client/svm-client'; import type { OrchestratorContext } from './context'; import { printLog, fireProgressHook } from './context'; import { getUniversalGatewayPCAddress, getPushChainForNetwork } from './helpers'; +import { + UNISWAP_V3_QUOTER_EXACT_OUTPUT_ABI, + UNIVERSAL_CORE_SWAP_HELPERS_ABI, +} from './gas-pool-quote'; import { sizeOutboundGas, type GasSizingDecision, @@ -74,38 +78,6 @@ const UNISWAP_V3_FACTORY_ABI = [ }, ]; -const UNISWAP_V3_QUOTER_EXACT_OUTPUT_ABI = [ - { - type: 'function' as const, - name: 'quoteExactOutputSingle', - inputs: [ - { - type: 'tuple', - components: [ - { name: 'tokenIn', type: 'address' }, - { name: 'tokenOut', type: 'address' }, - { name: 'amount', type: 'uint256' }, - { name: 'fee', type: 'uint24' }, - { name: 'sqrtPriceLimitX96', type: 'uint160' }, - ], - }, - ], - outputs: [ - { name: 'amountIn', type: 'uint256' }, - { name: 'sqrtPriceX96After', type: 'uint160' }, - { name: 'initializedTicksCrossed', type: 'uint32' }, - { name: 'gasEstimate', type: 'uint256' }, - ], - stateMutability: 'view', - }, -]; - -const UNIVERSAL_CORE_SWAP_HELPERS_ABI = [ - { type: 'function' as const, name: 'WPC', inputs: [], outputs: [{ name: '', type: 'address', internalType: 'address' }], stateMutability: 'view' }, - { type: 'function' as const, name: 'uniswapV3Factory', inputs: [], outputs: [{ name: '', type: 'address', internalType: 'address' }], stateMutability: 'view' }, - { type: 'function' as const, name: 'defaultFeeTier', inputs: [{ name: '', type: 'address', internalType: 'address' }], outputs: [{ name: '', type: 'uint24', internalType: 'uint24' }], stateMutability: 'view' }, -]; - const ZERO_ADDR = '0x0000000000000000000000000000000000000000'; // ============================================================================ @@ -246,6 +218,7 @@ export async function queryOutboundGasFee( gasFee, originChain: ctx.universalSigner.account.chain, destinationChain, + pool: { universalCore: universalCoreAddress, gasToken }, }); // All categories — A, B, and C — return the sizer's calibrated gas leg. // R3 consumers additionally bump `nativeValueForGas` by `overflowNativePc` @@ -529,6 +502,7 @@ export async function queryRescueGasFee( gasFee, originChain: ctx.universalSigner.account.chain, destinationChain, + pool: { universalCore: universalCoreAddress, gasToken }, }); nativeValueForGas = sizing.gasLegNativePc; printLog( diff --git a/packages/core/src/lib/orchestrator/internals/gas-pool-quote.ts b/packages/core/src/lib/orchestrator/internals/gas-pool-quote.ts new file mode 100644 index 00000000..7ea320fb --- /dev/null +++ b/packages/core/src/lib/orchestrator/internals/gas-pool-quote.ts @@ -0,0 +1,114 @@ +/** + * Live Push-pool cost of an outbound gas fee. The gateway's swapAndBurnGas + * buys exactly `gasFee` of the gas token from the WPC pool (exact output), so + * this quote is what the swap will actually need at the current pool state. + */ +import { CHAIN_INFO } from '../../constants/chain'; +import type { OrchestratorContext } from './context'; +import { printLog } from './context'; +import { getPushChainForNetwork } from './helpers'; + +export const UNISWAP_V3_QUOTER_EXACT_OUTPUT_ABI = [ + { + type: 'function' as const, + name: 'quoteExactOutputSingle', + inputs: [ + { + type: 'tuple', + components: [ + { name: 'tokenIn', type: 'address' }, + { name: 'tokenOut', type: 'address' }, + { name: 'amount', type: 'uint256' }, + { name: 'fee', type: 'uint24' }, + { name: 'sqrtPriceLimitX96', type: 'uint160' }, + ], + }, + ], + outputs: [ + { name: 'amountIn', type: 'uint256' }, + { name: 'sqrtPriceX96After', type: 'uint160' }, + { name: 'initializedTicksCrossed', type: 'uint32' }, + { name: 'gasEstimate', type: 'uint256' }, + ], + stateMutability: 'view', + }, +]; + +export const UNIVERSAL_CORE_SWAP_HELPERS_ABI = [ + { + type: 'function' as const, + name: 'WPC', + inputs: [], + outputs: [{ name: '', type: 'address', internalType: 'address' }], + stateMutability: 'view', + }, + { + type: 'function' as const, + name: 'uniswapV3Factory', + inputs: [], + outputs: [{ name: '', type: 'address', internalType: 'address' }], + stateMutability: 'view', + }, + { + type: 'function' as const, + name: 'defaultFeeTier', + inputs: [{ name: '', type: 'address', internalType: 'address' }], + outputs: [{ name: '', type: 'uint24', internalType: 'uint24' }], + stateMutability: 'view', + }, +]; + +/** Exact PC (WPC wei) the gas swap needs now; undefined when it cannot be quoted. */ +export async function quoteGasPoolCost( + ctx: OrchestratorContext, + universalCore: `0x${string}`, + gasToken: `0x${string}`, + gasFee: bigint +): Promise { + if (gasFee <= BigInt(0)) return undefined; + const quoter = + CHAIN_INFO[getPushChainForNetwork(ctx.pushNetwork)]?.dex?.uniV3QuoterV2; + if (!quoter || quoter.startsWith('0xTBD')) return undefined; + try { + const [wpc, fee] = await Promise.all([ + ctx.pushClient.readContract<`0x${string}`>({ + address: universalCore, + abi: UNIVERSAL_CORE_SWAP_HELPERS_ABI, + functionName: 'WPC', + args: [], + }), + ctx.pushClient.readContract({ + address: universalCore, + abi: UNIVERSAL_CORE_SWAP_HELPERS_ABI, + functionName: 'defaultFeeTier', + args: [gasToken], + }), + ]); + if (!fee) return undefined; + const quote = await ctx.pushClient.readContract< + [bigint, bigint, number, bigint] + >({ + address: quoter as `0x${string}`, + abi: UNISWAP_V3_QUOTER_EXACT_OUTPUT_ABI, + functionName: 'quoteExactOutputSingle', + args: [ + { + tokenIn: wpc, + tokenOut: gasToken, + amount: gasFee, + fee, + sqrtPriceLimitX96: BigInt(0), + }, + ], + }); + return quote[0]; + } catch (err) { + printLog( + ctx, + `quoteGasPoolCost — unavailable (${ + err instanceof Error ? err.message : String(err) + })` + ); + return undefined; + } +} diff --git a/packages/core/src/lib/orchestrator/internals/gas-usd-sizer.ts b/packages/core/src/lib/orchestrator/internals/gas-usd-sizer.ts index e033b615..e14df555 100644 --- a/packages/core/src/lib/orchestrator/internals/gas-usd-sizer.ts +++ b/packages/core/src/lib/orchestrator/internals/gas-usd-sizer.ts @@ -16,7 +16,8 @@ import { CHAIN_INFO } from '../../constants/chain'; import { PriceFetch } from '../../price-fetch/price-fetch'; import type { OrchestratorContext } from './context'; import { printLog } from './context'; -import { getPcUsdPrice, usdToPc } from './pc-usd-oracle'; +import { getPcUsdPrice, pcToUsd, usdToPc } from './pc-usd-oracle'; +import { quoteGasPoolCost } from './gas-pool-quote'; // ============================================================================ // Thresholds (USD, 8 decimals) @@ -25,6 +26,11 @@ import { getPcUsdPrice, usdToPc } from './pc-usd-oracle'; const ONE_USD_8D = parseUnits('1', 8); // 100_000_000 const TEN_USD_8D = parseUnits('10', 8); // 1_000_000_000 +/** EVM destinations whose gas token is not ETH. No USD feed exists for them + * (the BSC gateway's feed is ETH/USD), so their gas is valued at the Push pool + * rate the gateway's swap actually pays. */ +const POOL_VALUED_GAS_CHAINS: ReadonlySet = new Set([CHAIN.BNB_TESTNET]); + // ============================================================================ // Types // ============================================================================ @@ -41,6 +47,8 @@ export interface GasSizingInput { * Used to price gasFee in USD via PriceFetch (Chainlink ETH/USD, Pyth SOL/USD). */ destinationChain: CHAIN; + /** UniversalCore and gas token, for pool-valued destinations. */ + pool?: { universalCore: `0x${string}`; gasToken: `0x${string}` }; } export interface GasSizingDecision { @@ -63,7 +71,7 @@ export async function sizeOutboundGas( ctx: OrchestratorContext, input: GasSizingInput ): Promise { - const { gasFee, originChain, destinationChain } = input; + const { gasFee, originChain, destinationChain, pool } = input; // 1) Price gasFee in USD (8 decimals). gasFee is denominated in the // destination native (pETH = ETH value, pSOL = SOL value). The price @@ -75,27 +83,41 @@ export async function sizeOutboundGas( destVm === VM.SVM ? CHAIN.SOLANA_DEVNET : CHAIN.ETHEREUM_SEPOLIA; const destDecimals = destVm === VM.SVM ? 9 : 18; - let destUsdPrice: bigint; - try { - destUsdPrice = await new PriceFetch(ctx.rpcUrls).getPrice(priceSourceChain); - } catch (err) { + const poolPcIn = + pool && POOL_VALUED_GAS_CHAINS.has(destinationChain) + ? await quoteGasPoolCost(ctx, pool.universalCore, pool.gasToken, gasFee) + : undefined; + let gasUsd: bigint; + if (poolPcIn !== undefined) { + gasUsd = await pcToUsd(ctx, poolPcIn, originChain); printLog( ctx, - `sizeOutboundGas — PriceFetch.getPrice failed (${err instanceof Error ? err.message : String(err)}); treating as Case B passthrough` + `sizeOutboundGas — gasFee=${gasFee.toString()} valued at the Push pool: ` + + `pcIn=${poolPcIn.toString()}, gasUsd=${gasUsd.toString()} (1e8)` ); - // Degrade gracefully: assume the raw gasFee is already a sane size and - // convert 1:1 to native PC. Callers keep their existing fallback logic. - return passthroughAsCaseB(ctx, gasFee, originChain); - } + } else { + let destUsdPrice: bigint; + try { + destUsdPrice = await new PriceFetch(ctx.rpcUrls).getPrice(priceSourceChain); + } catch (err) { + printLog( + ctx, + `sizeOutboundGas — PriceFetch.getPrice failed (${err instanceof Error ? err.message : String(err)}); treating as Case B passthrough` + ); + // Degrade gracefully: assume the raw gasFee is already a sane size and + // convert 1:1 to native PC. Callers keep their existing fallback logic. + return passthroughAsCaseB(ctx, gasFee, originChain); + } - const oneDestNativeUnit = parseUnits('1', destDecimals); - const gasUsd = (gasFee * destUsdPrice) / oneDestNativeUnit; + const oneDestNativeUnit = parseUnits('1', destDecimals); + gasUsd = (gasFee * destUsdPrice) / oneDestNativeUnit; - printLog( - ctx, - `sizeOutboundGas — gasFee=${gasFee.toString()} ${destVm === VM.SVM ? 'pSOL' : 'pETH'} (${destDecimals}d), ` + - `destUsdPrice=${destUsdPrice.toString()} (1e8), gasUsd=${gasUsd.toString()} (1e8)` - ); + printLog( + ctx, + `sizeOutboundGas — gasFee=${gasFee.toString()} ${destVm === VM.SVM ? 'pSOL' : 'gas token'} (${destDecimals}d), ` + + `destUsdPrice=${destUsdPrice.toString()} (1e8), gasUsd=${gasUsd.toString()} (1e8)` + ); + } // 2) Categorize and compute target USD for each leg. let category: GasSizingCategory; diff --git a/packages/core/src/lib/orchestrator/internals/svm-rent.ts b/packages/core/src/lib/orchestrator/internals/svm-rent.ts index 68515e3a..711b1efd 100644 --- a/packages/core/src/lib/orchestrator/internals/svm-rent.ts +++ b/packages/core/src/lib/orchestrator/internals/svm-rent.ts @@ -199,6 +199,7 @@ export async function ensureSvmFinalizeGasBudgetQuote({ pathTag, pc20, requoteFn, + onMinimum, }: { ctx: OrchestratorContext; ueaAddress: `0x${string}`; @@ -216,6 +217,8 @@ export async function ensureSvmFinalizeGasBudgetQuote({ * PC20 token, which has no PRC20 config. */ requoteFn?: (gasLimit: bigint) => Promise; + /** Receives the finalize minimum, so strict callers can refuse a short quote. */ + onMinimum?: (minGasFee: bigint) => void; }): Promise { const minGasFee = await getSvmFinalizeGasBudget({ ctx, @@ -225,6 +228,7 @@ export async function ensureSvmFinalizeGasBudgetQuote({ burnAmount, pc20, }); + onMinimum?.(minGasFee); if (quote.gasFee >= minGasFee) { const resolvedQuote = resolveSvmGasLimitUsed(quote); From f08619694d6852d16950cf898e9c6cb473ba998b Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Wed, 21 Oct 2026 09:05:57 +0530 Subject: [PATCH 65/68] docs(agw): record creation-flow review, live validation and team questions - Independent review of the AGW creation flow with decision matrix, evidence and post-review addenda. - October 20-21 preset acceptance and gas evidence, routed-preset, exact-route and Solana Memo live results. - Findings verified from the deployed node, contracts and chain before asking the team; question drafts split for Harsh, Aman, Zaryab and core/gateway. - Implementation status updated. --- plan/agw/implementation-status.md | 27 + .../data/dest-probe.json | 565 +++++++++ .../data/dest-receipts.json | 189 +++ .../data/gasprice-history.json | 119 ++ .../data/live-2026-10-21-evidence.json | 531 ++++++++ .../data/live-2026-10-21-results.log | 16 + .../data/live-2026-10-21-routed-presets.json | 831 +++++++++++++ .../data/old-prc20.json | 118 ++ .../data/post-change-compatibility.json | 1094 +++++++++++++++++ .../data/post-change-gas-quotes.json | 286 +++++ .../data/post-change-route-registry.json | 311 +++++ .../data/push-probe.json | 895 ++++++++++++++ .../data/sdk-quotes.json | 369 ++++++ .../sepolia-dex-subsequent-oog-trace.json | 1 + .../data/sol-probe.json | 378 ++++++ .../data/spl-rule-readback.json | 128 ++ .../data/spl-wrong-recipient-24456030.json | 128 ++ .../data/uregistry.json | 359 ++++++ .../decision-matrix.md | 151 +++ .../evidence.md | 106 ++ .../review.md | 402 ++++++ .../scripts/dest-probe.cjs | 132 ++ .../scripts/dest-receipts.cjs | 22 + .../scripts/gasprice-history.cjs | 11 + .../scripts/old-prc20.cjs | 14 + .../scripts/push-probe.cjs | 234 ++++ .../scripts/sdk-quotes.cjs | 61 + .../scripts/sol-probe.cjs | 77 ++ .../scripts/spl-readback-probe-historical.cjs | 31 + .../scripts/spl-readback-probe.cjs | 31 + .../scripts/trace-bnb.cjs | 8 + .../scripts/uregistry-probe.cjs | 50 + .../team-questions.md | 82 ++ plan/agw/questions-aman.md | 74 ++ plan/agw/questions-core-gateway.md | 58 + plan/agw/questions-harsh.md | 93 +- plan/agw/questions-zaryab.md | 46 +- .../README.md | 69 ++ .../live-routes-memo-evidence.json | 100 ++ .../live-routes-memo-results.log | 15 + .../preset-acceptance-2026-10-20/README.md | 69 ++ .../compatibility.json | 882 +++++++++++++ .../gas-quotes.json | 110 ++ .../live-evm-gas-evidence.json | 410 ++++++ .../live-evm-gas.log | 12 + .../live-presets-blocked.log | 152 +++ .../live-spl-evidence.json | 100 ++ .../preset-acceptance-2026-10-20/live-spl.log | 9 + .../local-contracts.log | 17 + .../probe-spl-rejections.cjs | 32 + .../spl-rejections.json | 28 + 51 files changed, 10013 insertions(+), 20 deletions(-) create mode 100644 plan/agw/independent-review-creation-flow-2026-10-20/data/dest-probe.json create mode 100644 plan/agw/independent-review-creation-flow-2026-10-20/data/dest-receipts.json create mode 100644 plan/agw/independent-review-creation-flow-2026-10-20/data/gasprice-history.json create mode 100644 plan/agw/independent-review-creation-flow-2026-10-20/data/live-2026-10-21-evidence.json create mode 100644 plan/agw/independent-review-creation-flow-2026-10-20/data/live-2026-10-21-results.log create mode 100644 plan/agw/independent-review-creation-flow-2026-10-20/data/live-2026-10-21-routed-presets.json create mode 100644 plan/agw/independent-review-creation-flow-2026-10-20/data/old-prc20.json create mode 100644 plan/agw/independent-review-creation-flow-2026-10-20/data/post-change-compatibility.json create mode 100644 plan/agw/independent-review-creation-flow-2026-10-20/data/post-change-gas-quotes.json create mode 100644 plan/agw/independent-review-creation-flow-2026-10-20/data/post-change-route-registry.json create mode 100644 plan/agw/independent-review-creation-flow-2026-10-20/data/push-probe.json create mode 100644 plan/agw/independent-review-creation-flow-2026-10-20/data/sdk-quotes.json create mode 100644 plan/agw/independent-review-creation-flow-2026-10-20/data/sepolia-dex-subsequent-oog-trace.json create mode 100644 plan/agw/independent-review-creation-flow-2026-10-20/data/sol-probe.json create mode 100644 plan/agw/independent-review-creation-flow-2026-10-20/data/spl-rule-readback.json create mode 100644 plan/agw/independent-review-creation-flow-2026-10-20/data/spl-wrong-recipient-24456030.json create mode 100644 plan/agw/independent-review-creation-flow-2026-10-20/data/uregistry.json create mode 100644 plan/agw/independent-review-creation-flow-2026-10-20/decision-matrix.md create mode 100644 plan/agw/independent-review-creation-flow-2026-10-20/evidence.md create mode 100644 plan/agw/independent-review-creation-flow-2026-10-20/review.md create mode 100644 plan/agw/independent-review-creation-flow-2026-10-20/scripts/dest-probe.cjs create mode 100644 plan/agw/independent-review-creation-flow-2026-10-20/scripts/dest-receipts.cjs create mode 100644 plan/agw/independent-review-creation-flow-2026-10-20/scripts/gasprice-history.cjs create mode 100644 plan/agw/independent-review-creation-flow-2026-10-20/scripts/old-prc20.cjs create mode 100644 plan/agw/independent-review-creation-flow-2026-10-20/scripts/push-probe.cjs create mode 100644 plan/agw/independent-review-creation-flow-2026-10-20/scripts/sdk-quotes.cjs create mode 100644 plan/agw/independent-review-creation-flow-2026-10-20/scripts/sol-probe.cjs create mode 100644 plan/agw/independent-review-creation-flow-2026-10-20/scripts/spl-readback-probe-historical.cjs create mode 100644 plan/agw/independent-review-creation-flow-2026-10-20/scripts/spl-readback-probe.cjs create mode 100644 plan/agw/independent-review-creation-flow-2026-10-20/scripts/trace-bnb.cjs create mode 100644 plan/agw/independent-review-creation-flow-2026-10-20/scripts/uregistry-probe.cjs create mode 100644 plan/agw/independent-review-creation-flow-2026-10-20/team-questions.md create mode 100644 plan/agw/questions-aman.md create mode 100644 plan/agw/questions-core-gateway.md create mode 100644 plan/agw/research/pre-question-findings-2026-10-21/README.md create mode 100644 plan/agw/research/pre-question-findings-2026-10-21/live-routes-memo-evidence.json create mode 100644 plan/agw/research/pre-question-findings-2026-10-21/live-routes-memo-results.log create mode 100644 plan/agw/research/preset-acceptance-2026-10-20/README.md create mode 100644 plan/agw/research/preset-acceptance-2026-10-20/compatibility.json create mode 100644 plan/agw/research/preset-acceptance-2026-10-20/gas-quotes.json create mode 100644 plan/agw/research/preset-acceptance-2026-10-20/live-evm-gas-evidence.json create mode 100644 plan/agw/research/preset-acceptance-2026-10-20/live-evm-gas.log create mode 100644 plan/agw/research/preset-acceptance-2026-10-20/live-presets-blocked.log create mode 100644 plan/agw/research/preset-acceptance-2026-10-20/live-spl-evidence.json create mode 100644 plan/agw/research/preset-acceptance-2026-10-20/live-spl.log create mode 100644 plan/agw/research/preset-acceptance-2026-10-20/local-contracts.log create mode 100644 plan/agw/research/preset-acceptance-2026-10-20/probe-spl-rejections.cjs create mode 100644 plan/agw/research/preset-acceptance-2026-10-20/spl-rejections.json diff --git a/plan/agw/implementation-status.md b/plan/agw/implementation-status.md index ef1141e3..0944af0c 100644 --- a/plan/agw/implementation-status.md +++ b/plan/agw/implementation-status.md @@ -1,5 +1,32 @@ # AGW SDK implementation status +**October 20 — SDK fixes from the independent review (local v4, uncommitted):** +- **Routes:** exact node-registered Circle USDC routes on Sepolia, Base Sepolia and Arbitrum Sepolia are now resolved by address for AGW only. DEXES Sepolia and LENDING Arbitrum Sepolia are route-ready; the other seven presets remain blocked. +- **Gas:** the AGW gas budget never attaches less than the current Push pool cost plus 20%, keeps the over-$10 share, and no longer counts protocolFee twice. +- **Validation:** Solana rules reject a zero gas ceiling. +- **Data fix:** the Base Sepolia WETH address is corrected. +- **Tests:** the live preset suite funds the agent only after its prerequisites pass. A new opt-in `agw-presets-routed` group covers the two ready presets. The scripts record pool cost and signer origin. +- **Validation results:** 2,267 units pass, 9/9 local v6 preset cases, lib/spec/local typechecks and the core build. +- **Not yet done:** core confirmation of the `.old` routes and funded runs. [Review](independent-review-creation-flow-2026-10-20/review.md). +- **Follow-up:** + - An explicit gasLimit below the chain base is refused before quoting. + - A Solana budget still short after one re-quote is refused before signing. + - BNB testnet gas is valued at the Push pool rate, because no BNB/USD feed exists. Route 2 and Route 3 already floor at the pool cost. + - New `check-agw-route-registry.js` drift check against uregistry: 20 routes match, 0 mismatches. It found the SDK cannot resolve DAI.sol. + - Tests: the agent-door omitted-gas unit; the local suite checks the stored destination; the SPL live test compares every pin and rejects a wrong recipient. That rejection was confirmed read-only at block 24,456,030. + - Question drafts and the October 20 README corrections are updated. +- **Live, 21 October:** the funded `agw-svm-agent-spl` (1/1, with the tightened assertions) and `agw-gas` (4/4, eight deliveries) runs pass on the changed code. `agw-presets-routed`: both route-ready presets pass live. DEXES Sepolia needed a new 1,000,000 multi-step default gas limit, because its subsequent swap ran out of gas at the 500,000 base; LENDING Arbitrum passed. This is the first live outbound over the Circle USDC `.old` routes. +- **Pre-question findings, 21 October** ([findings](research/pre-question-findings-2026-10-21/README.md)): + - Deployed sources identified: node `testnet/donut` `ca3b8d4e`, UniversalCore `core-testnet` `8bc60ae`, Solana gateway built from `pc20-3rd-iteration`. + - Live: all three Circle USDC routes deliver (new `agw-exact-routes`, 3/3); SPL Memo v2 works by owner and agent door (new `agw-svm-memo`, 2/2). + - Unused destination gas is refunded to the wallet (verified on-chain). + - `creditRevert` is not wired anywhere. + - The 8-action Push limit is deliberate. + - The `fromEnd` pin gap is confirmed. +- **Question drafts** are split four ways: `questions-harsh.md` (product only, no recommendations), `questions-aman.md` (presets), `questions-zaryab.md` (AGW contracts) and `questions-core-gateway.md` (core and Solana gateway). + +**October 20 — exact preset acceptance and Solana gas:** 9 unchanged default payloads pass real-contract creation/readback with local provisioned routes; all 9 live preset cases are explicitly blocked before funding. No compatible routed-token replacements were found in the queried protocols. Fixed omitted Solana gas sizing (legacy million-unit fallback quoted 100 PC); public agent SPL first/subsequent delivery with omitted gas passes on devnet, including ATA/cap refusals. 405 AGW units pass; four EVM first/subsequent scenarios also pass (eight destination deliveries), making ten fresh deliveries including SPL. [Current evidence and limits](research/preset-acceptance-2026-10-20/README.md). + **October 20 — creation error fixes:** typed token-route failures and per-rule details, actual constraint counts, UI-safe userMessage on SDK/revert errors, preserved diagnostics and clearer receipt/cancellation handling. **2,181 units**, **21 local v6 tests**, build/type/package checks pass. DEX UI overflow source remains pending the actual create payload; stock presets stay at 20 conditions. [Review and UI handoff](research/creation-error-review-2026-10-20/README.md). [Git delivery and continuing history](../SDK-CHANGELOG.md); package publication is separate. **October 18 — lighter CI requested:** PR checks now run SDK-only validation (421 focused units, spec types, build and package checks); contract checkout/Foundry/full API checks are manual opt-in. Local fast checks pass. Release branch v5 `b291b873` is pushed; package publication remains manual. **2,142 full units**, **107 local contract tests** and **9/9 read-only factory simulations** remain the release evidence. The optional fresh-run full CI preparation failure is documented, not reported as passing. diff --git a/plan/agw/independent-review-creation-flow-2026-10-20/data/dest-probe.json b/plan/agw/independent-review-creation-flow-2026-10-20/data/dest-probe.json new file mode 100644 index 00000000..f2f2ba5b --- /dev/null +++ b/plan/agw/independent-review-creation-flow-2026-10-20/data/dest-probe.json @@ -0,0 +1,565 @@ +{ + "at": "2026-10-20T16:32:02.266Z", + "readOnly": true, + "chains": { + "eip155:11155111": { + "rpc": "https://ethereum-sepolia-rpc.publicnode.com", + "chainId": 11155111, + "block": "11956507", + "vaultNativeBalance": "0", + "tokens": { + "WETH(dex)": { + "address": "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14", + "hasCode": true, + "codeBytes": 3124, + "hasDepositSelector": true, + "hasWithdrawSelector": true, + "symbol": "WETH", + "decimals": 18, + "vaultBalance": "17931859384055400", + "gatewayInboundSupported": true + }, + "USDC(circle,dex)": { + "address": "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238", + "hasCode": true, + "codeBytes": 1798, + "hasDepositSelector": false, + "hasWithdrawSelector": false, + "symbol": "USDC", + "decimals": 6, + "vaultBalance": "120464406768", + "gatewayInboundSupported": true + }, + "LINK(aave,lending)": { + "address": "0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5", + "hasCode": true, + "codeBytes": 5462, + "hasDepositSelector": false, + "hasWithdrawSelector": false, + "symbol": "LINK", + "decimals": 18, + "vaultBalance": "0", + "gatewayInboundSupported": false + }, + "WETH(eigen,staking)": { + "address": "0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9", + "hasCode": true, + "codeBytes": 1786, + "hasDepositSelector": true, + "hasWithdrawSelector": true, + "symbol": "WETH", + "decimals": 18, + "vaultBalance": "0", + "gatewayInboundSupported": false + }, + "USDT(routed mock)": { + "address": "0xC4230aEaFcF6b8B49a7b4e53886420f00ff71876", + "hasCode": true, + "codeBytes": 212, + "hasDepositSelector": false, + "hasWithdrawSelector": false, + "symbol": "USDT", + "decimals": 6, + "vaultBalance": "6868887672141", + "gatewayInboundSupported": true + }, + "USDC(routed mock)": { + "address": "0x97F477B7f970D47a87B42869ceeace218106152a", + "hasCode": true, + "codeBytes": 7006, + "hasDepositSelector": false, + "hasWithdrawSelector": false, + "symbol": "USDC", + "decimals": 6, + "vaultBalance": "6923434414182", + "gatewayInboundSupported": true + }, + "stETH(routed)": { + "address": "0x3e3FE7dBc6B4C189E7128855dD526361c49b40Af", + "hasCode": true, + "codeBytes": 1007, + "hasDepositSelector": false, + "hasWithdrawSelector": false, + "symbol": "stETH", + "decimals": 18, + "vaultBalance": "0", + "gatewayInboundSupported": true + } + }, + "factory": "0x0227628f3F023bb0B980b67D528571c95c6DaC1c", + "pools": [ + { + "pair": [ + "WETH(dex)", + "USDC(circle,dex)" + ], + "fee": 100, + "pool": "0xFeEd501c2B21D315F04946F85fC6416B640240b5", + "liquidity": "621313943474064" + }, + { + "pair": [ + "WETH(dex)", + "USDC(circle,dex)" + ], + "fee": 500, + "pool": "0x3289680dD4d6C10bb19b899729cda5eEF58AEfF1", + "liquidity": "13023204526049250" + }, + { + "pair": [ + "WETH(dex)", + "USDC(circle,dex)" + ], + "fee": 3000, + "pool": "0x6Ce0896eAE6D4BD668fDe41BB784548fb8F59b50", + "liquidity": "8789602361849593" + }, + { + "pair": [ + "WETH(dex)", + "USDC(circle,dex)" + ], + "fee": 10000, + "pool": "0x6418EEC70f50913ff0d756B48d32Ce7C02b47C47", + "liquidity": "107641036005842238" + } + ], + "aaveReserves": [ + { + "reserve": "0xFF34B3d4Aee8ddCd6F9AFFFB6Fe49bD371b8a357", + "symbol": "DAI", + "decimals": 18, + "hasDepositSelector": false + }, + { + "reserve": "0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5", + "symbol": "LINK", + "decimals": 18, + "hasDepositSelector": false + }, + { + "reserve": "0x94a9D9AC8a22534E3FaCa9F4e7F2E2cf85d5E4C8", + "symbol": "USDC", + "decimals": 6, + "hasDepositSelector": false + }, + { + "reserve": "0x29f2D40B0605204364af54EC677bD022dA425d03", + "symbol": "WBTC", + "decimals": 8, + "hasDepositSelector": false + }, + { + "reserve": "0xC558DBdd856501FCd9aaF1E62eae57A9F0629a3c", + "symbol": "WETH", + "decimals": 18, + "hasDepositSelector": true + }, + { + "reserve": "0xaA8E23Fb1079EA71e0a56F48a2aA51851D8433D0", + "symbol": "USDT", + "decimals": 6, + "hasDepositSelector": false + }, + { + "reserve": "0x88541670E55cC00bEEFD87eB59EDd1b7C511AC9a", + "symbol": "AAVE", + "decimals": 18, + "hasDepositSelector": false + }, + { + "reserve": "0x6d906e526a4e2Ca02097BA9d0caA3c382F52278E", + "symbol": "EURS", + "decimals": 2, + "hasDepositSelector": false + }, + { + "reserve": "0xc4bF5CbDaBE595361438F8c6a187bDc330539c60", + "symbol": "GHO", + "decimals": 18, + "hasDepositSelector": false + } + ], + "eigenUnderlying": "0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9", + "ethUsd1e18": "2432000000000000000000", + "ethUsdFeedDecimals": 8 + }, + "eip155:84532": { + "rpc": "https://base-sepolia-rpc.publicnode.com", + "chainId": 84532, + "block": "48372829", + "vaultNativeBalance": "0", + "tokens": { + "WETH(dex,canonical)": { + "address": "0x4200000000000000000000000000000000000006", + "hasCode": true, + "codeBytes": 2041, + "hasDepositSelector": true, + "hasWithdrawSelector": true, + "symbol": "WETH", + "decimals": 18, + "vaultBalance": "0", + "gatewayInboundSupported": true + }, + "USDC(circle,dex)": { + "address": "0x036CbD53842c5426634e7929541eC2318f3dCF7e", + "hasCode": true, + "codeBytes": 1798, + "hasDepositSelector": false, + "hasWithdrawSelector": false, + "symbol": "USDC", + "decimals": 6, + "vaultBalance": "1126991000", + "gatewayInboundSupported": true + }, + "LINK(aave,lending)": { + "address": "0x810D46F9a9027E28F9B01F75E2bdde839dA61115", + "hasCode": true, + "codeBytes": 3981, + "hasDepositSelector": false, + "hasWithdrawSelector": false, + "symbol": "LINK", + "decimals": 18, + "vaultBalance": "0", + "gatewayInboundSupported": false + }, + "USDbC(moonwell)": { + "address": "0x4616975f7E6045FD9737e95bC527e9e14c727BD2", + "hasCode": true, + "codeBytes": 4552, + "hasDepositSelector": false, + "hasWithdrawSelector": false, + "symbol": "USDBC", + "decimals": 6, + "vaultBalance": "0", + "gatewayInboundSupported": false + }, + "WETH(moonwell)": { + "address": "0x663A6F02d547dFd639BF689FED298712f2FB69Fb", + "hasCode": true, + "codeBytes": 3096, + "hasDepositSelector": true, + "hasWithdrawSelector": true, + "symbol": "WETH", + "decimals": 18, + "vaultBalance": "0", + "gatewayInboundSupported": false + }, + "USDT(routed mock)": { + "address": "0x4D7646B9eE3D68F4b0F135B5cbc66B00819F6b61", + "hasCode": true, + "codeBytes": 212, + "hasDepositSelector": false, + "hasWithdrawSelector": false, + "symbol": "USDT", + "decimals": 6, + "vaultBalance": "250046831993", + "gatewayInboundSupported": true + }, + "USDC(routed mock)": { + "address": "0x5c3504F0E3bA28FDc1F74234fE936518276AaBB8", + "hasCode": true, + "codeBytes": 7006, + "hasDepositSelector": false, + "hasWithdrawSelector": false, + "symbol": "USDC", + "decimals": 6, + "vaultBalance": "1043749802312", + "gatewayInboundSupported": true + }, + "SDK BASE WETH entry (Sepolia addr)": { + "address": "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14", + "hasCode": false, + "codeBytes": 0, + "hasDepositSelector": false, + "hasWithdrawSelector": false + } + }, + "factory": "0x4752ba5DBc23f44D87826276BF6Fd6b1C372aD24", + "pools": [ + { + "pair": [ + "WETH(dex,canonical)", + "USDC(circle,dex)" + ], + "fee": 100, + "pool": "0x57183717A087d2fe3Ad890873877244c3B96156c", + "liquidity": "2890001491047" + }, + { + "pair": [ + "WETH(dex,canonical)", + "USDC(circle,dex)" + ], + "fee": 500, + "pool": "0x94bfc0574FF48E92cE43d495376C477B1d0EEeC0", + "liquidity": "448098251397" + }, + { + "pair": [ + "WETH(dex,canonical)", + "USDC(circle,dex)" + ], + "fee": 3000, + "pool": "0x46880b404CD35c165EDdefF7421019F8dD25F4Ad", + "liquidity": "541083441415564" + }, + { + "pair": [ + "WETH(dex,canonical)", + "USDC(circle,dex)" + ], + "fee": 10000, + "pool": "0x4664755562152EDDa3a3073850FB62835451926a", + "liquidity": "57734017049" + } + ], + "aaveReserves": [ + { + "reserve": "0xba50Cd2A20f6DA35D788639E581bca8d0B5d4D5f", + "symbol": "USDC", + "decimals": 6, + "hasDepositSelector": false + }, + { + "reserve": "0x0a215D8ba66387DCA84B284D18c3B4ec3de6E54a", + "symbol": "USDT", + "decimals": 6, + "hasDepositSelector": false + }, + { + "reserve": "0x54114591963CF60EF3aA63bEfD6eC263D98145a4", + "symbol": "WBTC", + "decimals": 8, + "hasDepositSelector": false + }, + { + "reserve": "0x4200000000000000000000000000000000000006", + "symbol": "WETH", + "decimals": 18, + "hasDepositSelector": true + }, + { + "reserve": "0xD171b9694f7A2597Ed006D41f7509aaD4B485c4B", + "symbol": "cbETH", + "decimals": 18, + "hasDepositSelector": false + }, + { + "reserve": "0x810D46F9a9027E28F9B01F75E2bdde839dA61115", + "symbol": "LINK", + "decimals": 18, + "hasDepositSelector": false + } + ] + }, + "eip155:421614": { + "rpc": "https://arbitrum-sepolia-rpc.publicnode.com", + "chainId": 421614, + "block": "321115011", + "vaultNativeBalance": "0", + "tokens": { + "WETH(dex)": { + "address": "0x980B62Da83eFf3D4576C647993b0c1D7faf17c73", + "hasCode": true, + "codeBytes": 2147, + "hasDepositSelector": false, + "hasWithdrawSelector": false, + "symbol": "WETH", + "decimals": 18, + "vaultBalance": "0", + "gatewayInboundSupported": true + }, + "USDC(circle,dex,lending)": { + "address": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "hasCode": true, + "codeBytes": 1798, + "hasDepositSelector": false, + "hasWithdrawSelector": false, + "symbol": "USDC", + "decimals": 6, + "vaultBalance": "157300000", + "gatewayInboundSupported": true + }, + "USDT(routed mock)": { + "address": "0xE30928528f52CAEeB75fB07837e22d77D47e9c07", + "hasCode": true, + "codeBytes": 212, + "hasDepositSelector": false, + "hasWithdrawSelector": false, + "symbol": "USDT", + "decimals": 6, + "vaultBalance": "245087879327", + "gatewayInboundSupported": true + }, + "USDC(routed mock)": { + "address": "0x5dd39b0b3610F666F631a6506b7713EF83e1Ac5C", + "hasCode": true, + "codeBytes": 7006, + "hasDepositSelector": false, + "hasWithdrawSelector": false, + "symbol": "USDC", + "decimals": 6, + "vaultBalance": "1044729424179", + "gatewayInboundSupported": true + } + }, + "factory": "0x248AB79Bbb9bC29bB72f7Cd42F17e054Fc40188e", + "pools": [ + { + "pair": [ + "WETH(dex)", + "USDC(circle,dex,lending)" + ], + "fee": 100, + "pool": "0x152c469626C706E201721F13eb470691E4E81c5D", + "liquidity": "0" + }, + { + "pair": [ + "WETH(dex)", + "USDC(circle,dex,lending)" + ], + "fee": 500, + "pool": "0x6F112d524DC998381C09b4e53C7e5e2cc260f877", + "liquidity": "122" + }, + { + "pair": [ + "WETH(dex)", + "USDC(circle,dex,lending)" + ], + "fee": 3000, + "pool": "0x66EEAB70aC52459Dd74C6AD50D578Ef76a441bbf", + "liquidity": "10070937193695" + }, + { + "pair": [ + "WETH(dex)", + "USDC(circle,dex,lending)" + ], + "fee": 10000, + "pool": "0x3eCedaB7E9479E29B694d8590dc34e0Ce6059868", + "liquidity": "3225673603183" + } + ], + "aaveReserves": [ + { + "reserve": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "symbol": "USDC", + "decimals": 6, + "hasDepositSelector": false + }, + { + "reserve": "0x1dF462e2712496373A347f8ad10802a5E95f053D", + "symbol": "WETH", + "decimals": 18, + "hasDepositSelector": true + } + ] + }, + "eip155:97": { + "rpc": "https://bsc-testnet-rpc.publicnode.com", + "chainId": 97, + "block": "137918895", + "vaultNativeBalance": "0", + "tokens": { + "WBNB(dex)": { + "address": "0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd", + "hasCode": true, + "codeBytes": 3124, + "hasDepositSelector": true, + "hasWithdrawSelector": true, + "symbol": "WBNB", + "decimals": 18, + "vaultBalance": "0", + "gatewayInboundSupported": false + }, + "USDT(venus,dex,lending)": { + "address": "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", + "hasCode": true, + "codeBytes": 2095, + "hasDepositSelector": false, + "hasWithdrawSelector": false, + "symbol": "USDT", + "decimals": 6, + "vaultBalance": "0", + "gatewayInboundSupported": false + }, + "USDC(venus,lending)": { + "address": "0x16227D60f7a0e586C66B005219dfc887D13C9531", + "hasCode": true, + "codeBytes": 2095, + "hasDepositSelector": false, + "hasWithdrawSelector": false, + "symbol": "USDC", + "decimals": 6, + "vaultBalance": "0", + "gatewayInboundSupported": false + }, + "USDT(routed mock)": { + "address": "0xE935d9c9C24D02E61186c640cc01d713C876d40F", + "hasCode": true, + "codeBytes": 212, + "hasDepositSelector": false, + "hasWithdrawSelector": false, + "symbol": "USDT", + "decimals": 6, + "vaultBalance": "219017594761", + "gatewayInboundSupported": true + }, + "USDC(routed mock)": { + "address": "0xA8802F96cAd0d45343d9bc660B6f7d80050A660b", + "hasCode": true, + "codeBytes": 212, + "hasDepositSelector": false, + "hasWithdrawSelector": false, + "symbol": "USDC", + "decimals": 6, + "vaultBalance": "216926047736", + "gatewayInboundSupported": true + } + }, + "factory": "0x0BFbCF9fa4f9C56B0F40a671Ad40E0805A091865", + "pools": [ + { + "pair": [ + "WBNB(dex)", + "USDT(venus,dex,lending)" + ], + "fee": 100, + "pool": "0xCed0844e421F856D2de472F9e7037f873987887C", + "liquidity": "229529662705916" + }, + { + "pair": [ + "WBNB(dex)", + "USDT(venus,dex,lending)" + ], + "fee": 500, + "pool": "0xc2F0629Dd29AB0EcfF7476560bc8FD5c0c4D19Cd", + "liquidity": "0" + }, + { + "pair": [ + "WBNB(dex)", + "USDT(venus,dex,lending)" + ], + "fee": 2500, + "pool": "0x917aB0c0f32452e1403eBD68B222C0B59bAaa2C3", + "liquidity": "0" + }, + { + "pair": [ + "WBNB(dex)", + "USDT(venus,dex,lending)" + ], + "fee": 10000, + "pool": "0xa5316a3418e0643BB977A97689E584a3b6c35080", + "liquidity": "0" + } + ] + } + } +} \ No newline at end of file diff --git a/plan/agw/independent-review-creation-flow-2026-10-20/data/dest-receipts.json b/plan/agw/independent-review-creation-flow-2026-10-20/data/dest-receipts.json new file mode 100644 index 00000000..6b1cc51d --- /dev/null +++ b/plan/agw/independent-review-creation-flow-2026-10-20/data/dest-receipts.json @@ -0,0 +1,189 @@ +{ + "at": "2026-10-20T16:40:39.547Z", + "dest": [ + { + "ns": "eip155:11155111", + "hash": "0xf3ed17fa05f700543ec10930d078c6fb793624e44e8ec8fe3f14fbb7cee5cf19", + "status": "success", + "block": "11956206", + "from": "0x9fed6f778a956244c06a3b905ba45bdb2ec3afea", + "to": "0xd019eb12d0d6ef8d299661f22b4b7d262ed4b965", + "value": "1000000000000", + "gasUsed": "1265722", + "ceaExecuted": [ + { + "emitter": "0xddc0c8e35863f1478c0485144d2fae959242ce43", + "originCaller": "0xD847ca2462405a70c32ff5776e70fE25EA7B26ca", + "target": "0xF1552eD5ac48C273570500bD10b10C00E1C418bB", + "data": "0xd09de08a" + } + ], + "ceaMatches": true + }, + { + "ns": "eip155:11155111", + "hash": "0x15f49a09b3879f3cc1ea4c3accddc7431b279da59033f5eb9842a0d4994df50a", + "status": "success", + "block": "11956213", + "from": "0x9fed6f778a956244c06a3b905ba45bdb2ec3afea", + "to": "0xd019eb12d0d6ef8d299661f22b4b7d262ed4b965", + "value": "1000000000000", + "gasUsed": "223683", + "ceaExecuted": [ + { + "emitter": "0xddc0c8e35863f1478c0485144d2fae959242ce43", + "originCaller": "0xD847ca2462405a70c32ff5776e70fE25EA7B26ca", + "target": "0xF1552eD5ac48C273570500bD10b10C00E1C418bB", + "data": "0xd09de08a" + } + ], + "ceaMatches": true + }, + { + "ns": "eip155:11155111", + "ceaCodeBytes": 45, + "ceaNativeBalanceNow": "2000000000000" + }, + { + "ns": "eip155:84532", + "hash": "0x89337900340a39fd1725657e72f146fe5b4b917a58d5db150f052b2222724d6d", + "status": "success", + "block": "48371096", + "from": "0x9fed6f778a956244c06a3b905ba45bdb2ec3afea", + "to": "0xb4ba4d5542d1dd48bd3589543660b265b41f16cb", + "value": "1000000000000", + "gasUsed": "325448", + "ceaExecuted": [ + { + "emitter": "0xb0d8079eef1553d3e975947f087eeeb05f02ab1a", + "originCaller": "0xB07a90329A3Ef6B20aC80a458069a7D8daE93D58", + "target": "0x25a62134B57C42b1733BDF577E48C91d13053138", + "data": "0xd09de08a" + } + ], + "ceaMatches": true + }, + { + "ns": "eip155:84532", + "hash": "0xe81704385810c74cef8d16cb7fe3e2a98805aff9a9f63aaf5008d3d9288a4781", + "status": "success", + "block": "48371126", + "from": "0x9fed6f778a956244c06a3b905ba45bdb2ec3afea", + "to": "0xb4ba4d5542d1dd48bd3589543660b265b41f16cb", + "value": "1000000000000", + "gasUsed": "123187", + "ceaExecuted": [ + { + "emitter": "0xb0d8079eef1553d3e975947f087eeeb05f02ab1a", + "originCaller": "0xB07a90329A3Ef6B20aC80a458069a7D8daE93D58", + "target": "0x25a62134B57C42b1733BDF577E48C91d13053138", + "data": "0xd09de08a" + } + ], + "ceaMatches": true + }, + { + "ns": "eip155:84532", + "ceaCodeBytes": 45, + "ceaNativeBalanceNow": "2000000000000" + }, + { + "ns": "eip155:421614", + "hash": "0x059011ed41d6409e48b70ab47dd02a16eca292e01e68eb721d78df5813f46c98", + "status": "success", + "block": "321102083", + "from": "0x9fed6f778a956244c06a3b905ba45bdb2ec3afea", + "to": "0x233b1b1b378eb0aa723097634025a47c4b73a8f7", + "value": "1000000000000", + "gasUsed": "325424", + "ceaExecuted": [ + { + "emitter": "0x97b91433af804877cd11ec522c910c54e04624b5", + "originCaller": "0x3130f7F8b10C94A54eC012A4d0e6DAc963f200eb", + "target": "0x7F0936bB90e7dcF3eDB47199C2005e7184E44Cf8", + "data": "0xd09de08a" + } + ], + "ceaMatches": true + }, + { + "ns": "eip155:421614", + "hash": "0x54f382ed25d895893f6cd3042ff7ee43e63bc392397c9a9572c424a3589d9df8", + "status": "success", + "block": "321102318", + "from": "0x9fed6f778a956244c06a3b905ba45bdb2ec3afea", + "to": "0x233b1b1b378eb0aa723097634025a47c4b73a8f7", + "value": "1000000000000", + "gasUsed": "123163", + "ceaExecuted": [ + { + "emitter": "0x97b91433af804877cd11ec522c910c54e04624b5", + "originCaller": "0x3130f7F8b10C94A54eC012A4d0e6DAc963f200eb", + "target": "0x7F0936bB90e7dcF3eDB47199C2005e7184E44Cf8", + "data": "0xd09de08a" + } + ], + "ceaMatches": true + }, + { + "ns": "eip155:421614", + "ceaCodeBytes": 45, + "ceaNativeBalanceNow": "2000000000000" + }, + { + "ns": "eip155:97", + "hash": "0x6b5cfb84699948c2b626e2a244b9ff8354d070093d6f8ecb42a228914adfdaa5", + "status": "success", + "block": "137911931", + "from": "0x9fed6f778a956244c06a3b905ba45bdb2ec3afea", + "to": "0xe52ac4f8dd3e0263bdf748f3390cdfa1f02be881", + "value": "1000000000000", + "gasUsed": "325919", + "ceaExecuted": [ + { + "emitter": "0xa7384f2b00463e548426cd9c8979dda78ecf60c4", + "originCaller": "0x0140403283bB76C1890501067754d1c376189b5D", + "target": "0xf4bd8c13DA0F5831D7B6dd3275a39F14eC7dDaA6", + "data": "0xd09de08a" + } + ], + "ceaMatches": true + }, + { + "ns": "eip155:97", + "hash": "0x42adb9167d8f25a81ff01e143cb43e676818d8ce144a08444c890caecd08029a", + "status": "success", + "block": "137912063", + "from": "0x9fed6f778a956244c06a3b905ba45bdb2ec3afea", + "to": "0xe52ac4f8dd3e0263bdf748f3390cdfa1f02be881", + "value": "1000000000000", + "gasUsed": "123637", + "ceaExecuted": [ + { + "emitter": "0xa7384f2b00463e548426cd9c8979dda78ecf60c4", + "originCaller": "0x0140403283bB76C1890501067754d1c376189b5D", + "target": "0xf4bd8c13DA0F5831D7B6dd3275a39F14eC7dDaA6", + "data": "0xd09de08a" + } + ], + "ceaMatches": true + }, + { + "ns": "eip155:97", + "ceaCodeBytes": 45, + "ceaNativeBalanceNow": "2000000000000" + } + ], + "walletDelta": { + "spl:first-use": { + "before": "41000000000000000000", + "after": "38930349124935516270", + "deltaPC": -2.0696508750644838 + }, + "spl:subsequent": { + "before": "39021448806523059654", + "after": "38151923666016831746", + "deltaPC": -0.869525140506228 + } + } +} \ No newline at end of file diff --git a/plan/agw/independent-review-creation-flow-2026-10-20/data/gasprice-history.json b/plan/agw/independent-review-creation-flow-2026-10-20/data/gasprice-history.json new file mode 100644 index 00000000..c50f99d7 --- /dev/null +++ b/plan/agw/independent-review-creation-flow-2026-10-20/data/gasprice-history.json @@ -0,0 +1,119 @@ +[ + { + "block": "24457472", + "time": "2026-10-20T16:38:50.000Z", + "eip155:11155111": "1100018", + "eip155:84532": "6600000", + "eip155:421614": "22204600", + "eip155:97": "55000000", + "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1": "1000" + }, + { + "block": "24457272", + "time": "2026-10-20T16:30:42.000Z", + "eip155:11155111": "1100018", + "eip155:84532": "6600000", + "eip155:421614": "22143000", + "eip155:97": "110000000", + "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1": "1000" + }, + { + "block": "24457072", + "time": "2026-10-20T16:22:35.000Z", + "eip155:11155111": "1100018", + "eip155:84532": "6600000", + "eip155:421614": "22103400", + "eip155:97": "55000000", + "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1": "1000" + }, + { + "block": "24456872", + "time": "2026-10-20T16:14:26.000Z", + "eip155:11155111": "1100017", + "eip155:84532": "6600000", + "eip155:421614": "22191400", + "eip155:97": "55000000", + "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1": "1000" + }, + { + "block": "24456672", + "time": "2026-10-20T16:06:18.000Z", + "eip155:11155111": "1100017", + "eip155:84532": "6600000", + "eip155:421614": "22074800", + "eip155:97": "55000000", + "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1": "1000" + }, + { + "block": "24456472", + "time": "2026-10-20T15:58:10.000Z", + "eip155:11155111": "1100017", + "eip155:84532": "6600000", + "eip155:421614": "22024200", + "eip155:97": "110000000", + "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1": "1000" + }, + { + "block": "24456272", + "time": "2026-10-20T15:50:01.000Z", + "eip155:11155111": "1100017", + "eip155:84532": "6600000", + "eip155:421614": "22264000", + "eip155:97": "55000000", + "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1": "1000" + }, + { + "block": "24456072", + "time": "2026-10-20T15:41:59.000Z", + "eip155:11155111": "1100017", + "eip155:84532": "6600000", + "eip155:421614": "22596200", + "eip155:97": "1100000000", + "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1": "1000" + }, + { + "block": "24455872", + "time": "2026-10-20T15:33:51.000Z", + "eip155:11155111": "1100016", + "eip155:84532": "6600000", + "eip155:421614": "22477400", + "eip155:97": "110000000", + "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1": "1000" + }, + { + "block": "24455672", + "time": "2026-10-20T15:25:43.000Z", + "eip155:11155111": "1100016", + "eip155:84532": "6600000", + "eip155:421614": "22499400", + "eip155:97": "110000000", + "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1": "1000" + }, + { + "block": "24455472", + "time": "2026-10-20T15:17:35.000Z", + "eip155:11155111": "1100016", + "eip155:84532": "6600000", + "eip155:421614": "22545600", + "eip155:97": "110000000", + "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1": "1000" + }, + { + "block": "24455272", + "time": "2026-10-20T15:09:27.000Z", + "eip155:11155111": "1100016", + "eip155:84532": "6600000", + "eip155:421614": "22409200", + "eip155:97": "110000000", + "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1": "1000" + }, + { + "block": "24455072", + "time": "2026-10-20T15:01:19.000Z", + "eip155:11155111": "1100016", + "eip155:84532": "6600000", + "eip155:421614": "22299200", + "eip155:97": "110000000", + "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1": "1000" + } +] \ No newline at end of file diff --git a/plan/agw/independent-review-creation-flow-2026-10-20/data/live-2026-10-21-evidence.json b/plan/agw/independent-review-creation-flow-2026-10-20/data/live-2026-10-21-evidence.json new file mode 100644 index 00000000..2b73f53c --- /dev/null +++ b/plan/agw/independent-review-creation-flow-2026-10-20/data/live-2026-10-21-evidence.json @@ -0,0 +1,531 @@ +{ + "note": "Funded live runs after the SDK changes: agw-svm-agent-spl (1 passed) and agw-gas (4 passed). Public hashes and quotes only.", + "entries": [ + { + "name": "agw-gas-quote", + "at": "2026-10-21T02:25:39.442Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "agent-spl:first-use", + "token": "0x4f1A3D22d170a2F4Bddb37845a962322e24f4e34", + "requestedGasLimit": "0", + "chain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "protocolFeePCWei": "0", + "quotedGasBudgetPCWei": "10000000000000000000", + "gasLimitUsed": "2285", + "attachedPCWei": "10000000000000000000", + "gasTokenFee": "2285000", + "poolPcInRequired": "2069651270263405412" + }, + { + "name": "agent-spl-submitted", + "at": "2026-10-21T02:25:44.016Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "first-use", + "wallet": "0x794d9FcdbC98e1AedA46B50B1A7dCeB4E2A4f5C8", + "cea": "2e6zcSRHdsZ6wQsrukKGsWE4pdQyy9FcDHoqBzB2nTUt", + "ceaATA": "EdtjZZBBw7AnP5p69jKitxf1MybEurG39ihHUiyCpfqH", + "hash": "0xf9ed22085ba92bb5da919cb6d623c139f17d88f559ae9b1d3feacb32c011b05a" + }, + { + "name": "agw-push-gas", + "at": "2026-10-21T02:26:37.890Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "agent-spl:first-use", + "hash": "0xf9ed22085ba92bb5da919cb6d623c139f17d88f559ae9b1d3feacb32c011b05a", + "block": "24471877", + "gasUsed": "467992", + "effectiveGasPrice": "1125000000", + "transactionGasPaidPCWei": "526491000000000" + }, + { + "name": "agent-spl-delivered", + "at": "2026-10-21T02:26:37.892Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "first-use", + "wallet": "0x794d9FcdbC98e1AedA46B50B1A7dCeB4E2A4f5C8", + "hash": "0xf9ed22085ba92bb5da919cb6d623c139f17d88f559ae9b1d3feacb32c011b05a", + "destinationHash": "zrGSbp8ryyHEfDRUpqAqf19rcSimmedF1ihssmQrLUu2yKEBUm7R5kEPrmu5g7gT36DpCitpjQECDj9vRse8ReV", + "destinationFeeLamports": 5000, + "computeUnitsConsumed": 125402 + }, + { + "name": "agw-gas-quote", + "at": "2026-10-21T02:26:48.936Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "agent-spl:subsequent", + "token": "0x4f1A3D22d170a2F4Bddb37845a962322e24f4e34", + "requestedGasLimit": "0", + "chain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "protocolFeePCWei": "0", + "quotedGasBudgetPCWei": "10000000000000000000", + "gasLimitUsed": "960", + "attachedPCWei": "10000000000000000000", + "gasTokenFee": "960000", + "poolPcInRequired": "869525306541673833" + }, + { + "name": "agent-spl-submitted", + "at": "2026-10-21T02:26:54.145Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "subsequent", + "wallet": "0x794d9FcdbC98e1AedA46B50B1A7dCeB4E2A4f5C8", + "cea": "2e6zcSRHdsZ6wQsrukKGsWE4pdQyy9FcDHoqBzB2nTUt", + "ceaATA": "EdtjZZBBw7AnP5p69jKitxf1MybEurG39ihHUiyCpfqH", + "hash": "0xd302f5298195d083e1f1bcc99f56238e1ba31954c1040ecc7adc1393f1af20c5" + }, + { + "name": "agw-push-gas", + "at": "2026-10-21T02:27:53.421Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "agent-spl:subsequent", + "hash": "0xd302f5298195d083e1f1bcc99f56238e1ba31954c1040ecc7adc1393f1af20c5", + "block": "24471906", + "gasUsed": "447034", + "effectiveGasPrice": "1125000000", + "transactionGasPaidPCWei": "502913250000000" + }, + { + "name": "agent-spl-delivered", + "at": "2026-10-21T02:27:53.422Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "subsequent", + "wallet": "0x794d9FcdbC98e1AedA46B50B1A7dCeB4E2A4f5C8", + "hash": "0xd302f5298195d083e1f1bcc99f56238e1ba31954c1040ecc7adc1393f1af20c5", + "destinationHash": "2qSdorisfULDw9XXUjBgMDiCrSZ9rTv8tQWCcehTgRphV5chvkkyDbdXKMJsfobxiAsTyk199cKXrudCzkgAzsyz", + "destinationFeeLamports": 5000, + "computeUnitsConsumed": 102801 + }, + { + "name": "agw-gas-quote", + "at": "2026-10-21T02:29:01.693Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "eip155:11155111:first-use", + "token": "0x2971824Db68229D087931155C2b8bB820B275809", + "requestedGasLimit": "2000000", + "chain": "eip155:11155111", + "protocolFeePCWei": "0", + "quotedGasBudgetPCWei": "10000000000000000000", + "gasLimitUsed": "2000000", + "attachedPCWei": "10000000000000000000", + "gasTokenFee": "440052000000", + "poolPcInRequired": "643471955090073" + }, + { + "name": "evm-gas-submitted", + "at": "2026-10-21T02:29:11.283Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "chain": "eip155:11155111", + "stage": "first-use", + "wallet": "0x74C744022E0C708277b6192de02FB294A05eEdee", + "cea": "0x5946f4371F1bffECbc6B22fac1aFA8A0cbE93ABd", + "hash": "0xc4f63d536ea9d4fe08d1a014ff5d2f0ba88b1c4389487157486bdcb73e92e27b" + }, + { + "name": "agw-push-gas", + "at": "2026-10-21T02:30:22.850Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "eip155:11155111:first-use", + "hash": "0xc4f63d536ea9d4fe08d1a014ff5d2f0ba88b1c4389487157486bdcb73e92e27b", + "block": "24471961", + "gasUsed": "397808", + "effectiveGasPrice": "1125000000", + "transactionGasPaidPCWei": "447534000000000" + }, + { + "name": "evm-gas-delivered", + "at": "2026-10-21T02:30:22.852Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "chain": "eip155:11155111", + "stage": "first-use", + "wallet": "0x74C744022E0C708277b6192de02FB294A05eEdee", + "hash": "0xc4f63d536ea9d4fe08d1a014ff5d2f0ba88b1c4389487157486bdcb73e92e27b", + "destinationHash": "0x66fe3a8acaadf71b36699ba0ee9fb34da0d990aaf2630dbcc3fb9755b4233df0", + "destinationBlock": "11959452", + "destinationGasUsed": "1265746", + "destinationGasPaidWei": "278497029396" + }, + { + "name": "agw-gas-quote", + "at": "2026-10-21T02:30:26.923Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "eip155:11155111:subsequent", + "token": "0x2971824Db68229D087931155C2b8bB820B275809", + "requestedGasLimit": "0", + "chain": "eip155:11155111", + "protocolFeePCWei": "0", + "quotedGasBudgetPCWei": "10000000000000000000", + "gasLimitUsed": "500000", + "attachedPCWei": "10000000000000000000", + "gasTokenFee": "110013000000", + "poolPcInRequired": "160867989543460" + }, + { + "name": "evm-gas-submitted", + "at": "2026-10-21T02:30:29.813Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "chain": "eip155:11155111", + "stage": "subsequent", + "wallet": "0x74C744022E0C708277b6192de02FB294A05eEdee", + "cea": "0x5946f4371F1bffECbc6B22fac1aFA8A0cbE93ABd", + "hash": "0xe3c84049e011c82353ae8152b8d67e27b4c946945272973f0003da299906a8b1" + }, + { + "name": "agw-push-gas", + "at": "2026-10-21T02:31:29.674Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "eip155:11155111:subsequent", + "hash": "0xe3c84049e011c82353ae8152b8d67e27b4c946945272973f0003da299906a8b1", + "block": "24471994", + "gasUsed": "377207", + "effectiveGasPrice": "1125000000", + "transactionGasPaidPCWei": "424357875000000" + }, + { + "name": "evm-gas-delivered", + "at": "2026-10-21T02:31:29.676Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "chain": "eip155:11155111", + "stage": "subsequent", + "wallet": "0x74C744022E0C708277b6192de02FB294A05eEdee", + "hash": "0xe3c84049e011c82353ae8152b8d67e27b4c946945272973f0003da299906a8b1", + "destinationHash": "0x8b997c34e5a8dd6ea74506d9505e8671d59bab17ce5dbeadb62e631a684877df", + "destinationBlock": "11959459", + "destinationGasUsed": "223683", + "destinationGasPaidWei": "49216075758" + }, + { + "name": "agw-gas-quote", + "at": "2026-10-21T02:32:26.854Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "eip155:84532:first-use", + "token": "0xc7007af2B24D4eb963fc9633B0c66e1d2D90Fc21", + "requestedGasLimit": "2000000", + "chain": "eip155:84532", + "protocolFeePCWei": "0", + "quotedGasBudgetPCWei": "10000000000000000000", + "gasLimitUsed": "2000000", + "attachedPCWei": "10000000000000000000", + "gasTokenFee": "13200000000000", + "poolPcInRequired": "591544122865719910" + }, + { + "name": "evm-gas-submitted", + "at": "2026-10-21T02:32:30.094Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "chain": "eip155:84532", + "stage": "first-use", + "wallet": "0x18B1eC7957053FFD831889760ADF5620851052D1", + "cea": "0x16582837cF894d7CF7724a70aaCBd4F3A6d8826e", + "hash": "0xc5a90e64ca3aed1222894031319ea016a87b43bbb91d0f4dfeae7d05d6443ef2" + }, + { + "name": "agw-push-gas", + "at": "2026-10-21T02:33:30.038Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "eip155:84532:first-use", + "hash": "0xc5a90e64ca3aed1222894031319ea016a87b43bbb91d0f4dfeae7d05d6443ef2", + "block": "24472044", + "gasUsed": "396773", + "effectiveGasPrice": "1125000000", + "transactionGasPaidPCWei": "446369625000000" + }, + { + "name": "evm-gas-delivered", + "at": "2026-10-21T02:33:30.040Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "chain": "eip155:84532", + "stage": "first-use", + "wallet": "0x18B1eC7957053FFD831889760ADF5620851052D1", + "hash": "0xc5a90e64ca3aed1222894031319ea016a87b43bbb91d0f4dfeae7d05d6443ef2", + "destinationHash": "0x970e56548c72c35d8063626e84ceaae83bd1844cf2ca90027c0589bb5a86b74f", + "destinationBlock": "48390851", + "destinationGasUsed": "325448", + "destinationGasPaidWei": "2147956800000" + }, + { + "name": "agw-gas-quote", + "at": "2026-10-21T02:33:34.090Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "eip155:84532:subsequent", + "token": "0xc7007af2B24D4eb963fc9633B0c66e1d2D90Fc21", + "requestedGasLimit": "0", + "chain": "eip155:84532", + "protocolFeePCWei": "0", + "quotedGasBudgetPCWei": "10000000000000000000", + "gasLimitUsed": "500000", + "attachedPCWei": "10000000000000000000", + "gasTokenFee": "3300000000000", + "poolPcInRequired": "147885991133196862" + }, + { + "name": "evm-gas-submitted", + "at": "2026-10-21T02:33:37.091Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "chain": "eip155:84532", + "stage": "subsequent", + "wallet": "0x18B1eC7957053FFD831889760ADF5620851052D1", + "cea": "0x16582837cF894d7CF7724a70aaCBd4F3A6d8826e", + "hash": "0xf73e62a5f93c78708637b9d53f13e52d8155817fe2a69eee565e5bc1fa2f8dc9" + }, + { + "name": "agw-push-gas", + "at": "2026-10-21T02:34:44.195Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "eip155:84532:subsequent", + "hash": "0xf73e62a5f93c78708637b9d53f13e52d8155817fe2a69eee565e5bc1fa2f8dc9", + "block": "24472071", + "gasUsed": "376379", + "effectiveGasPrice": "1125000000", + "transactionGasPaidPCWei": "423426375000000" + }, + { + "name": "evm-gas-delivered", + "at": "2026-10-21T02:34:44.196Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "chain": "eip155:84532", + "stage": "subsequent", + "wallet": "0x18B1eC7957053FFD831889760ADF5620851052D1", + "hash": "0xf73e62a5f93c78708637b9d53f13e52d8155817fe2a69eee565e5bc1fa2f8dc9", + "destinationHash": "0x60b0947f30d2ddb8cc5b874adfa1f62fdc9321224fba862249b325b67e8a9abf", + "destinationBlock": "48390888", + "destinationGasUsed": "123187", + "destinationGasPaidWei": "813034200000" + }, + { + "name": "agw-gas-quote", + "at": "2026-10-21T02:35:31.505Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "eip155:421614:first-use", + "token": "0xc0a821a1AfEd1322c5e15f1F4586C0B8cE65400e", + "requestedGasLimit": "2000000", + "chain": "eip155:421614", + "protocolFeePCWei": "0", + "quotedGasBudgetPCWei": "10000000000000000000", + "gasLimitUsed": "2000000", + "attachedPCWei": "10000000000000000000", + "gasTokenFee": "44655600000000", + "poolPcInRequired": "1907011850299212513" + }, + { + "name": "evm-gas-submitted", + "at": "2026-10-21T02:35:34.795Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "chain": "eip155:421614", + "stage": "first-use", + "wallet": "0xc056f78CDc6D9d0540055AF7b168342C89cFea7B", + "cea": "0x712FCd604e5329BBA527c2104EfdfE7200028919", + "hash": "0x5a9e17b1e8fc09d443ad27372bb9a04f4a46352a95de86bcecb2ddbbf8abb91d" + }, + { + "name": "agw-push-gas", + "at": "2026-10-21T02:36:38.121Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "eip155:421614:first-use", + "hash": "0x5a9e17b1e8fc09d443ad27372bb9a04f4a46352a95de86bcecb2ddbbf8abb91d", + "block": "24472119", + "gasUsed": "409838", + "effectiveGasPrice": "1125000000", + "transactionGasPaidPCWei": "461067750000000" + }, + { + "name": "evm-gas-delivered", + "at": "2026-10-21T02:36:38.122Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "chain": "eip155:421614", + "stage": "first-use", + "wallet": "0xc056f78CDc6D9d0540055AF7b168342C89cFea7B", + "hash": "0x5a9e17b1e8fc09d443ad27372bb9a04f4a46352a95de86bcecb2ddbbf8abb91d", + "destinationHash": "0x134c264f6f4d6b5177e7c28c50fe830058d018dc94762a306eac7353a66f7f66", + "destinationBlock": "321254949", + "destinationGasUsed": "325436", + "destinationGasPaidWei": "7266269920800" + }, + { + "name": "agw-gas-quote", + "at": "2026-10-21T02:36:42.093Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "eip155:421614:subsequent", + "token": "0xc0a821a1AfEd1322c5e15f1F4586C0B8cE65400e", + "requestedGasLimit": "0", + "chain": "eip155:421614", + "protocolFeePCWei": "0", + "quotedGasBudgetPCWei": "10000000000000000000", + "gasLimitUsed": "500000", + "attachedPCWei": "10000000000000000000", + "gasTokenFee": "11192500000000", + "poolPcInRequired": "477973578898284522" + }, + { + "name": "evm-gas-submitted", + "at": "2026-10-21T02:36:45.784Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "chain": "eip155:421614", + "stage": "subsequent", + "wallet": "0xc056f78CDc6D9d0540055AF7b168342C89cFea7B", + "cea": "0x712FCd604e5329BBA527c2104EfdfE7200028919", + "hash": "0xa45ba64229437f56f9110f9070fa83f0b7de8169263fc8923583928770440838" + }, + { + "name": "agw-push-gas", + "at": "2026-10-21T02:37:38.071Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "eip155:421614:subsequent", + "hash": "0xa45ba64229437f56f9110f9070fa83f0b7de8169263fc8923583928770440838", + "block": "24472149", + "gasUsed": "390828", + "effectiveGasPrice": "1125000000", + "transactionGasPaidPCWei": "439681500000000" + }, + { + "name": "evm-gas-delivered", + "at": "2026-10-21T02:37:38.072Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "chain": "eip155:421614", + "stage": "subsequent", + "wallet": "0xc056f78CDc6D9d0540055AF7b168342C89cFea7B", + "hash": "0xa45ba64229437f56f9110f9070fa83f0b7de8169263fc8923583928770440838", + "destinationHash": "0x9f57377b34beb59e450d7494604dc97f383e12808a71a24e1acf8dc073fb85b0", + "destinationBlock": "321255184", + "destinationGasUsed": "123175", + "destinationGasPaidWei": "2757272375000" + }, + { + "name": "agw-gas-quote", + "at": "2026-10-21T02:38:31.058Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "eip155:97:first-use", + "token": "0x7a9082dA308f3fa005beA7dB0d203b3b86664E36", + "requestedGasLimit": "2000000", + "chain": "eip155:97", + "protocolFeePCWei": "0", + "quotedGasBudgetPCWei": "10000000000000000000", + "gasLimitUsed": "2000000", + "attachedPCWei": "10000000000000000000", + "gasTokenFee": "110000000000000", + "poolPcInRequired": "1182694436440979711" + }, + { + "name": "evm-gas-submitted", + "at": "2026-10-21T02:38:40.665Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "chain": "eip155:97", + "stage": "first-use", + "wallet": "0x3aC06E9358d305950cAfac8D8a58B63Af7DD94c7", + "cea": "0xB6493f431b87285Ce3e4Eb9f3D4bBeb49878BFF5", + "hash": "0xad1a169c434f37fae2d283e8963c1cafc35278af0e73eaaaedd6f3dd120c5556" + }, + { + "name": "agw-push-gas", + "at": "2026-10-21T02:39:43.347Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "eip155:97:first-use", + "hash": "0xad1a169c434f37fae2d283e8963c1cafc35278af0e73eaaaedd6f3dd120c5556", + "block": "24472194", + "gasUsed": "404595", + "effectiveGasPrice": "1125000000", + "transactionGasPaidPCWei": "455169375000000" + }, + { + "name": "evm-gas-delivered", + "at": "2026-10-21T02:39:43.349Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "chain": "eip155:97", + "stage": "first-use", + "wallet": "0x3aC06E9358d305950cAfac8D8a58B63Af7DD94c7", + "hash": "0xad1a169c434f37fae2d283e8963c1cafc35278af0e73eaaaedd6f3dd120c5556", + "destinationHash": "0x282e61982fb85d579bdad52bca6553aad5f84e2b1fbef79909fc5f6944b6a052", + "destinationBlock": "137999640", + "destinationGasUsed": "325919", + "destinationGasPaidWei": "17925545000000" + }, + { + "name": "agw-gas-quote", + "at": "2026-10-21T02:39:48.024Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "eip155:97:subsequent", + "token": "0x7a9082dA308f3fa005beA7dB0d203b3b86664E36", + "requestedGasLimit": "0", + "chain": "eip155:97", + "protocolFeePCWei": "0", + "quotedGasBudgetPCWei": "10000000000000000000", + "gasLimitUsed": "500000", + "attachedPCWei": "10000000000000000000", + "gasTokenFee": "55000000000000", + "poolPcInRequired": "591346891813133954" + }, + { + "name": "evm-gas-submitted", + "at": "2026-10-21T02:39:51.606Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "chain": "eip155:97", + "stage": "subsequent", + "wallet": "0x3aC06E9358d305950cAfac8D8a58B63Af7DD94c7", + "cea": "0xB6493f431b87285Ce3e4Eb9f3D4bBeb49878BFF5", + "hash": "0x7acf0085c38efe98990445aeec7b1b7d563fcd4def7d70783038fb7e23dd8164" + }, + { + "name": "agw-push-gas", + "at": "2026-10-21T02:40:40.248Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "eip155:97:subsequent", + "hash": "0x7acf0085c38efe98990445aeec7b1b7d563fcd4def7d70783038fb7e23dd8164", + "block": "24472225", + "gasUsed": "390915", + "effectiveGasPrice": "1125000000", + "transactionGasPaidPCWei": "439779375000000" + }, + { + "name": "evm-gas-delivered", + "at": "2026-10-21T02:40:40.251Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "chain": "eip155:97", + "stage": "subsequent", + "wallet": "0x3aC06E9358d305950cAfac8D8a58B63Af7DD94c7", + "hash": "0x7acf0085c38efe98990445aeec7b1b7d563fcd4def7d70783038fb7e23dd8164", + "destinationHash": "0x3ab1688c3df2a271f796945632fb015f504c59bb821310cea95c0f419d28d470", + "destinationBlock": "137999767", + "destinationGasUsed": "123637", + "destinationGasPaidWei": "13600070000000" + } + ] +} \ No newline at end of file diff --git a/plan/agw/independent-review-creation-flow-2026-10-20/data/live-2026-10-21-results.log b/plan/agw/independent-review-creation-flow-2026-10-20/data/live-2026-10-21-results.log new file mode 100644 index 00000000..4bfe02f6 --- /dev/null +++ b/plan/agw/independent-review-creation-flow-2026-10-20/data/live-2026-10-21-results.log @@ -0,0 +1,16 @@ +2026-10-21T02:23:41Z +│ Push master (Donut) │ PC │ 58.2500 │ 967421.5716 │ ✓ │ +│ Push master (Donut) │ pUSDT.sol │ 0.002500 │ 10006.8109 │ ✓ │ +PASS core-e2e __e2e__/agw/svm-agent-spl.spec.ts (241.627 s) + ✓ 1. exact wallet ATA and amount constraints survive create and two omitted-gas deliveries (237025 ms) +Tests: 1 passed, 1 total +2026-10-21T02:27:58Z +2026-10-21T02:27:58Z +│ Push master (Donut) │ PC │ 132.0000 │ 967380.0700 │ ✓ │ +PASS core-e2e __e2e__/agw/gas-live.spec.ts (752.143 s) + ✓ 1. Sepolia first-use and subsequent execution (200864 ms) + ✓ 2. Base Sepolia first-use and subsequent execution (194183 ms) + ✓ 3. Arbitrum Sepolia first-use and subsequent execution (173553 ms) + ✓ 4. BNB testnet first-use and subsequent execution (182185 ms) +Tests: 4 passed, 4 total +2026-10-21T02:40:43Z diff --git a/plan/agw/independent-review-creation-flow-2026-10-20/data/live-2026-10-21-routed-presets.json b/plan/agw/independent-review-creation-flow-2026-10-20/data/live-2026-10-21-routed-presets.json new file mode 100644 index 00000000..b1afd664 --- /dev/null +++ b/plan/agw/independent-review-creation-flow-2026-10-20/data/live-2026-10-21-routed-presets.json @@ -0,0 +1,831 @@ +{ + "note": "Routed preset live runs, 21 Oct: LENDING Arbitrum passed; DEXES Sepolia subsequent failed out of gas at the 500k base (trace in sepolia-dex-subsequent-oog-trace.json); re-run with the 1,000,000 multi-step default passed. Public hashes only.", + "entries": [ + { + "name": "unchanged-preset-created", + "at": "2026-10-21T02:49:04.740Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "category": "DEXES", + "chainNamespace": "eip155:11155111", + "wallet": "0x5c788fca118Bf06cDb7AB679fFBbD9007B5375E7", + "hash": "0x17a58f61b934c0eee3ba83120eba9d338c6de5defbe031aff961dfc3d68b71fb", + "rules": [ + { + "chainNamespace": "eip155:11155111", + "allowedCalls": [ + { + "target": "0x3bFA4769FB09eefC5a80d6E87c3B9C650f7Ae48E", + "selector": "exactInputSingle((address,address,uint24,address,uint256,uint256,uint160))", + "pins": [ + { + "arg": [ + 0, + 0 + ], + "expected": "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14" + }, + { + "arg": [ + 0, + 1 + ], + "expected": "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238" + }, + { + "arg": [ + 0, + 3 + ], + "expected": "agentic:wallet" + }, + { + "arg": [ + 0, + 4 + ], + "max": "1000000000000000" + } + ], + "app": "Uniswap V3", + "label": "Swap exact input" + }, + { + "target": "0x3bFA4769FB09eefC5a80d6E87c3B9C650f7Ae48E", + "selector": "exactOutputSingle((address,address,uint24,address,uint256,uint256,uint160))", + "pins": [ + { + "arg": [ + 0, + 0 + ], + "expected": "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14" + }, + { + "arg": [ + 0, + 1 + ], + "expected": "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238" + }, + { + "arg": [ + 0, + 3 + ], + "expected": "agentic:wallet" + }, + { + "arg": [ + 0, + 5 + ], + "max": "1000000000000000" + } + ], + "app": "Uniswap V3", + "label": "Swap exact output" + }, + { + "target": "0x3bFA4769FB09eefC5a80d6E87c3B9C650f7Ae48E", + "selector": "exactInputSingle((address,address,uint24,address,uint256,uint256,uint160))", + "pins": [ + { + "arg": [ + 0, + 0 + ], + "expected": "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238" + }, + { + "arg": [ + 0, + 1 + ], + "expected": "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14" + }, + { + "arg": [ + 0, + 3 + ], + "expected": "agentic:wallet" + }, + { + "arg": [ + 0, + 4 + ], + "max": "10000000" + } + ], + "app": "Uniswap V3", + "label": "Swap exact input" + }, + { + "target": "0x3bFA4769FB09eefC5a80d6E87c3B9C650f7Ae48E", + "selector": "exactOutputSingle((address,address,uint24,address,uint256,uint256,uint160))", + "pins": [ + { + "arg": [ + 0, + 0 + ], + "expected": "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238" + }, + { + "arg": [ + 0, + 1 + ], + "expected": "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14" + }, + { + "arg": [ + 0, + 3 + ], + "expected": "agentic:wallet" + }, + { + "arg": [ + 0, + 5 + ], + "max": "10000000" + } + ], + "app": "Uniswap V3", + "label": "Swap exact output" + }, + { + "target": "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14", + "selector": "approve(address,uint256)", + "pins": [ + { + "arg": 0, + "expected": "0x3bFA4769FB09eefC5a80d6E87c3B9C650f7Ae48E" + }, + { + "arg": 1, + "max": "1000000000000000" + } + ], + "app": "Uniswap V3", + "label": "Approve token spending" + }, + { + "target": "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238", + "selector": "approve(address,uint256)", + "pins": [ + { + "arg": 0, + "expected": "0x3bFA4769FB09eefC5a80d6E87c3B9C650f7Ae48E" + }, + { + "arg": 1, + "max": "10000000" + } + ], + "app": "Uniswap V3", + "label": "Approve token spending" + } + ], + "agent": "0xAdbc7E575Fba1D03B11E22bE396d06EB873625ab", + "validUntil": 1793155723, + "assets": [ + { + "token": "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14", + "maxPerCall": "1000000000000000", + "maxTotal": "10000000000000000" + }, + { + "token": "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238", + "maxPerCall": "10000000", + "maxTotal": "100000000" + } + ], + "maxGasPerCall": "20000000000000000000" + } + ] + }, + { + "name": "agw-gas-quote", + "at": "2026-10-21T02:49:27.568Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "DEXES:eip155:11155111:first-use", + "token": "0x387b9C8Db60E74999aAAC5A2b7825b400F12d68E", + "requestedGasLimit": "2000000", + "chain": "eip155:11155111", + "protocolFeePCWei": "0", + "quotedGasBudgetPCWei": "10000000000000000000", + "gasLimitUsed": "2000000", + "attachedPCWei": "10000000000000000000", + "gasTokenFee": "440054000000", + "poolPcInRequired": "643474888519368" + }, + { + "name": "unchanged-preset-submitted", + "at": "2026-10-21T02:49:30.758Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "category": "DEXES", + "chainNamespace": "eip155:11155111", + "stage": "first-use", + "wallet": "0x5c788fca118Bf06cDb7AB679fFBbD9007B5375E7", + "hash": "0x05bb69c5cd001c74e558ba77607c24ec7f80fa2963d9414bf3a48023499a9dbb" + }, + { + "name": "agw-push-gas", + "at": "2026-10-21T02:50:33.793Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "first-use", + "hash": "0x05bb69c5cd001c74e558ba77607c24ec7f80fa2963d9414bf3a48023499a9dbb", + "block": "24472461", + "gasUsed": "479802", + "effectiveGasPrice": "1125000000", + "transactionGasPaidPCWei": "539777250000000" + }, + { + "name": "unchanged-preset-delivered", + "at": "2026-10-21T02:50:33.795Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "category": "DEXES", + "chainNamespace": "eip155:11155111", + "stage": "first-use", + "hash": "0x05bb69c5cd001c74e558ba77607c24ec7f80fa2963d9414bf3a48023499a9dbb", + "destinationHash": "0xa0324bcacb5cc32cba020e10f873c92aee9321d694e4c742ceef74d770debc2c", + "destinationGasUsed": "1502039", + "destinationGasPaidWei": "330489135053" + }, + { + "name": "agw-gas-quote", + "at": "2026-10-21T02:50:41.106Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "DEXES:eip155:11155111:subsequent", + "token": "0x387b9C8Db60E74999aAAC5A2b7825b400F12d68E", + "requestedGasLimit": "0", + "chain": "eip155:11155111", + "protocolFeePCWei": "0", + "quotedGasBudgetPCWei": "10000000000000000000", + "gasLimitUsed": "500000", + "attachedPCWei": "10000000000000000000", + "gasTokenFee": "110013000000", + "poolPcInRequired": "160867992121838" + }, + { + "name": "unchanged-preset-submitted", + "at": "2026-10-21T02:50:45.549Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "category": "DEXES", + "chainNamespace": "eip155:11155111", + "stage": "subsequent", + "wallet": "0x5c788fca118Bf06cDb7AB679fFBbD9007B5375E7", + "hash": "0x03ce92d8ae375b221fe157e42be472abc693308dac7b5c2e87fc4c58ea037421" + }, + { + "name": "unchanged-preset-created", + "at": "2026-10-21T02:52:38.840Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "category": "LENDING", + "chainNamespace": "eip155:421614", + "wallet": "0xD60F3aAbA0b86c607a140093E7A7c61668f56773", + "hash": "0xe068ff9d9afe2c3b5a918a03a73be461fe305b7913b50293ff8b3c09bcb255f0", + "rules": [ + { + "chainNamespace": "eip155:421614", + "allowedCalls": [ + { + "target": "0xBfC91D59fdAA134A4ED45f7B584cAf96D7792Eff", + "selector": "supply(address,uint256,address,uint16)", + "pins": [ + { + "arg": 2, + "expected": "agentic:wallet" + }, + { + "arg": 0, + "expected": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d" + }, + { + "arg": 1, + "max": "10000000" + } + ], + "app": "Aave V3", + "label": "Supply" + }, + { + "target": "0xBfC91D59fdAA134A4ED45f7B584cAf96D7792Eff", + "selector": "withdraw(address,uint256,address)", + "pins": [ + { + "arg": 2, + "expected": "agentic:wallet" + }, + { + "arg": 0, + "expected": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d" + }, + { + "arg": 1, + "max": "10000000" + } + ], + "app": "Aave V3", + "label": "Withdraw" + }, + { + "target": "0xBfC91D59fdAA134A4ED45f7B584cAf96D7792Eff", + "selector": "borrow(address,uint256,uint256,uint16,address)", + "pins": [ + { + "arg": 4, + "expected": "agentic:wallet" + }, + { + "arg": 0, + "expected": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d" + }, + { + "arg": 1, + "max": "10000000" + } + ], + "app": "Aave V3", + "label": "Borrow" + }, + { + "target": "0xBfC91D59fdAA134A4ED45f7B584cAf96D7792Eff", + "selector": "repay(address,uint256,uint256,address)", + "pins": [ + { + "arg": 3, + "expected": "agentic:wallet" + }, + { + "arg": 0, + "expected": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d" + }, + { + "arg": 1, + "max": "10000000" + } + ], + "app": "Aave V3", + "label": "Repay" + }, + { + "target": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "selector": "approve(address,uint256)", + "pins": [ + { + "arg": 0, + "expected": "0xBfC91D59fdAA134A4ED45f7B584cAf96D7792Eff" + }, + { + "arg": 1, + "max": "10000000" + } + ], + "app": "Aave V3", + "label": "Approve token spending" + } + ], + "agent": "0xb28855f6525E0F01cB018E5802C62cd98A4452fA", + "validUntil": 1793155937, + "assets": [ + { + "token": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "maxPerCall": "10000000", + "maxTotal": "100000000" + } + ], + "maxGasPerCall": "20000000000000000000" + } + ] + }, + { + "name": "agw-gas-quote", + "at": "2026-10-21T02:53:02.340Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "LENDING:eip155:421614:first-use", + "token": "0xa261A10e94aE4bA88EE8c5845CbE7266bD679DD6", + "requestedGasLimit": "2000000", + "chain": "eip155:421614", + "protocolFeePCWei": "0", + "quotedGasBudgetPCWei": "10000000000000000000", + "gasLimitUsed": "2000000", + "attachedPCWei": "10000000000000000000", + "gasTokenFee": "44374000000000", + "poolPcInRequired": "1894989313621377835" + }, + { + "name": "unchanged-preset-submitted", + "at": "2026-10-21T02:53:06.305Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "category": "LENDING", + "chainNamespace": "eip155:421614", + "stage": "first-use", + "wallet": "0xD60F3aAbA0b86c607a140093E7A7c61668f56773", + "hash": "0x0bd3a109e20fd85e54a89b48538a778497ee3664061ef09edb2a66f08faa86f8" + }, + { + "name": "agw-push-gas", + "at": "2026-10-21T02:54:06.062Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "first-use", + "hash": "0x0bd3a109e20fd85e54a89b48538a778497ee3664061ef09edb2a66f08faa86f8", + "block": "24472549", + "gasUsed": "464154", + "effectiveGasPrice": "1125000000", + "transactionGasPaidPCWei": "522173250000000" + }, + { + "name": "unchanged-preset-delivered", + "at": "2026-10-21T02:54:06.064Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "category": "LENDING", + "chainNamespace": "eip155:421614", + "stage": "first-use", + "hash": "0x0bd3a109e20fd85e54a89b48538a778497ee3664061ef09edb2a66f08faa86f8", + "destinationHash": "0x4073d97ada3d7f150c109faca5364aa3be95ca1f082fed0e6db5f3c177f9d32f", + "destinationGasUsed": "536341", + "destinationGasPaidWei": "11899797767000" + }, + { + "name": "agw-gas-quote", + "at": "2026-10-21T02:54:13.762Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "LENDING:eip155:421614:subsequent", + "token": "0xa261A10e94aE4bA88EE8c5845CbE7266bD679DD6", + "requestedGasLimit": "0", + "chain": "eip155:421614", + "protocolFeePCWei": "0", + "quotedGasBudgetPCWei": "10000000000000000000", + "gasLimitUsed": "500000", + "attachedPCWei": "10000000000000000000", + "gasTokenFee": "11029700000000", + "poolPcInRequired": "471022386761574893" + }, + { + "name": "unchanged-preset-submitted", + "at": "2026-10-21T02:54:23.128Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "category": "LENDING", + "chainNamespace": "eip155:421614", + "stage": "subsequent", + "wallet": "0xD60F3aAbA0b86c607a140093E7A7c61668f56773", + "hash": "0xda9775321a1733b53c794e2da1660a454701d1994ff508d3dfb5a7744bc87f65" + }, + { + "name": "agw-push-gas", + "at": "2026-10-21T02:55:11.891Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "subsequent", + "hash": "0xda9775321a1733b53c794e2da1660a454701d1994ff508d3dfb5a7744bc87f65", + "block": "24472578", + "gasUsed": "438634", + "effectiveGasPrice": "1125000000", + "transactionGasPaidPCWei": "493463250000000" + }, + { + "name": "unchanged-preset-delivered", + "at": "2026-10-21T02:55:11.892Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "category": "LENDING", + "chainNamespace": "eip155:421614", + "stage": "subsequent", + "hash": "0xda9775321a1733b53c794e2da1660a454701d1994ff508d3dfb5a7744bc87f65", + "destinationHash": "0x441bd0069c2b08cf84f5bdbf52c36aa6c9d3f6902bb3910c77953dbd85beb24c", + "destinationGasUsed": "292561", + "destinationGasPaidWei": "6453720123400" + }, + { + "name": "unchanged-preset-created", + "at": "2026-10-21T03:00:20.251Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "category": "DEXES", + "chainNamespace": "eip155:11155111", + "wallet": "0x7369894641360aF9AA464E6E07886eA0a670bdE3", + "hash": "0x41627803cc881cd6bd4f4f38bfa6adb5f5321b3af80dd40e5425ef4b8b1e7c85", + "rules": [ + { + "chainNamespace": "eip155:11155111", + "allowedCalls": [ + { + "target": "0x3bFA4769FB09eefC5a80d6E87c3B9C650f7Ae48E", + "selector": "exactInputSingle((address,address,uint24,address,uint256,uint256,uint160))", + "pins": [ + { + "arg": [ + 0, + 0 + ], + "expected": "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14" + }, + { + "arg": [ + 0, + 1 + ], + "expected": "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238" + }, + { + "arg": [ + 0, + 3 + ], + "expected": "agentic:wallet" + }, + { + "arg": [ + 0, + 4 + ], + "max": "1000000000000000" + } + ], + "app": "Uniswap V3", + "label": "Swap exact input" + }, + { + "target": "0x3bFA4769FB09eefC5a80d6E87c3B9C650f7Ae48E", + "selector": "exactOutputSingle((address,address,uint24,address,uint256,uint256,uint160))", + "pins": [ + { + "arg": [ + 0, + 0 + ], + "expected": "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14" + }, + { + "arg": [ + 0, + 1 + ], + "expected": "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238" + }, + { + "arg": [ + 0, + 3 + ], + "expected": "agentic:wallet" + }, + { + "arg": [ + 0, + 5 + ], + "max": "1000000000000000" + } + ], + "app": "Uniswap V3", + "label": "Swap exact output" + }, + { + "target": "0x3bFA4769FB09eefC5a80d6E87c3B9C650f7Ae48E", + "selector": "exactInputSingle((address,address,uint24,address,uint256,uint256,uint160))", + "pins": [ + { + "arg": [ + 0, + 0 + ], + "expected": "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238" + }, + { + "arg": [ + 0, + 1 + ], + "expected": "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14" + }, + { + "arg": [ + 0, + 3 + ], + "expected": "agentic:wallet" + }, + { + "arg": [ + 0, + 4 + ], + "max": "10000000" + } + ], + "app": "Uniswap V3", + "label": "Swap exact input" + }, + { + "target": "0x3bFA4769FB09eefC5a80d6E87c3B9C650f7Ae48E", + "selector": "exactOutputSingle((address,address,uint24,address,uint256,uint256,uint160))", + "pins": [ + { + "arg": [ + 0, + 0 + ], + "expected": "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238" + }, + { + "arg": [ + 0, + 1 + ], + "expected": "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14" + }, + { + "arg": [ + 0, + 3 + ], + "expected": "agentic:wallet" + }, + { + "arg": [ + 0, + 5 + ], + "max": "10000000" + } + ], + "app": "Uniswap V3", + "label": "Swap exact output" + }, + { + "target": "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14", + "selector": "approve(address,uint256)", + "pins": [ + { + "arg": 0, + "expected": "0x3bFA4769FB09eefC5a80d6E87c3B9C650f7Ae48E" + }, + { + "arg": 1, + "max": "1000000000000000" + } + ], + "app": "Uniswap V3", + "label": "Approve token spending" + }, + { + "target": "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238", + "selector": "approve(address,uint256)", + "pins": [ + { + "arg": 0, + "expected": "0x3bFA4769FB09eefC5a80d6E87c3B9C650f7Ae48E" + }, + { + "arg": 1, + "max": "10000000" + } + ], + "app": "Uniswap V3", + "label": "Approve token spending" + } + ], + "agent": "0x21659BcC0FfD83aed079db13EBD01C4a90da3a1C", + "validUntil": 1793156397, + "assets": [ + { + "token": "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14", + "maxPerCall": "1000000000000000", + "maxTotal": "10000000000000000" + }, + { + "token": "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238", + "maxPerCall": "10000000", + "maxTotal": "100000000" + } + ], + "maxGasPerCall": "20000000000000000000" + } + ] + }, + { + "name": "agw-gas-quote", + "at": "2026-10-21T03:00:44.663Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "DEXES:eip155:11155111:first-use", + "token": "0x387b9C8Db60E74999aAAC5A2b7825b400F12d68E", + "requestedGasLimit": "2000000", + "chain": "eip155:11155111", + "protocolFeePCWei": "0", + "quotedGasBudgetPCWei": "10000000000000000000", + "gasLimitUsed": "2000000", + "attachedPCWei": "10000000000000000000", + "gasTokenFee": "440052000000", + "poolPcInRequired": "643471974079470" + }, + { + "name": "unchanged-preset-submitted", + "at": "2026-10-21T03:00:48.504Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "category": "DEXES", + "chainNamespace": "eip155:11155111", + "stage": "first-use", + "wallet": "0x7369894641360aF9AA464E6E07886eA0a670bdE3", + "hash": "0x64d9df75b7d4a8b6169d57629bb10cd48bd9961d7011471ec2eede36f2cd2b6e" + }, + { + "name": "agw-push-gas", + "at": "2026-10-21T03:01:48.324Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "first-use", + "hash": "0x64d9df75b7d4a8b6169d57629bb10cd48bd9961d7011471ec2eede36f2cd2b6e", + "block": "24472738", + "gasUsed": "479814", + "effectiveGasPrice": "1125000000", + "transactionGasPaidPCWei": "539790750000000" + }, + { + "name": "unchanged-preset-delivered", + "at": "2026-10-21T03:01:48.326Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "category": "DEXES", + "chainNamespace": "eip155:11155111", + "stage": "first-use", + "hash": "0x64d9df75b7d4a8b6169d57629bb10cd48bd9961d7011471ec2eede36f2cd2b6e", + "destinationHash": "0xe97ab6a3e658aacd8f61fe72bd6c55241c0195a67e9ab8fca6c091a7c51aaee7", + "destinationGasUsed": "1502063", + "destinationGasPaidWei": "330492913638" + }, + { + "name": "agw-gas-quote", + "at": "2026-10-21T03:02:00.399Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "DEXES:eip155:11155111:subsequent", + "token": "0x387b9C8Db60E74999aAAC5A2b7825b400F12d68E", + "requestedGasLimit": "1000000", + "chain": "eip155:11155111", + "protocolFeePCWei": "0", + "quotedGasBudgetPCWei": "10000000000000000000", + "gasLimitUsed": "1000000", + "attachedPCWei": "10000000000000000000", + "gasTokenFee": "220027000000", + "poolPcInRequired": "321737452297646" + }, + { + "name": "unchanged-preset-submitted", + "at": "2026-10-21T03:02:05.422Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "category": "DEXES", + "chainNamespace": "eip155:11155111", + "stage": "subsequent", + "wallet": "0x7369894641360aF9AA464E6E07886eA0a670bdE3", + "hash": "0x06bd9dd403535b0e9603e36bedaf4f178bb9b46a2f1c33834b7fc387ae59c97c" + }, + { + "name": "agw-push-gas", + "at": "2026-10-21T03:03:18.212Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "subsequent", + "hash": "0x06bd9dd403535b0e9603e36bedaf4f178bb9b46a2f1c33834b7fc387ae59c97c", + "block": "24472768", + "gasUsed": "457914", + "effectiveGasPrice": "1125000000", + "transactionGasPaidPCWei": "515153250000000" + }, + { + "name": "unchanged-preset-delivered", + "at": "2026-10-21T03:03:18.215Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "category": "DEXES", + "chainNamespace": "eip155:11155111", + "stage": "subsequent", + "hash": "0x06bd9dd403535b0e9603e36bedaf4f178bb9b46a2f1c33834b7fc387ae59c97c", + "destinationHash": "0x07f46919b08d36aefc2a0ca25c1d7a2fd4573ad1993a1bc98a981774d71fe79a", + "destinationGasUsed": "362079", + "destinationGasPaidWei": "79667156133" + } + ] +} \ No newline at end of file diff --git a/plan/agw/independent-review-creation-flow-2026-10-20/data/old-prc20.json b/plan/agw/independent-review-creation-flow-2026-10-20/data/old-prc20.json new file mode 100644 index 00000000..e76f335a --- /dev/null +++ b/plan/agw/independent-review-creation-flow-2026-10-20/data/old-prc20.json @@ -0,0 +1,118 @@ +{ + "at": "2026-10-20T16:35:54.980Z", + "block": "24457398", + "tokens": { + "USDC.eth.old": { + "address": "0x387b9C8Db60E74999aAAC5A2b7825b400F12d68E", + "SOURCE_CHAIN_NAMESPACE": "eip155:11155111", + "decimals": "6", + "symbol": "USDC.eth.old", + "name": "USDC.eth.old", + "totalSupply": "1320454406768", + "sourceWord": "0x0000000000000000000000001c7d4b196cb0c7b01d743fbc6116a902379c7238", + "outboundQuote": { + "gasToken": "0x2971824Db68229D087931155C2b8bB820B275809", + "gasFee": "550009000000", + "protocolFee": "0", + "chain": "eip155:11155111", + "gasLimitUsed": "500000" + } + }, + "USDC.base.old": { + "address": "0x84B62e44F667F692F7739Ca6040cD17DA02068A8", + "SOURCE_CHAIN_NAMESPACE": "eip155:84532", + "decimals": "6", + "symbol": "USDC.base.old", + "name": "USDC.base.old", + "totalSupply": "1201126991000", + "sourceString": "0x036CbD53842c5426634e7929541eC2318f3dCF7e", + "outboundQuote": { + "gasToken": "0xc7007af2B24D4eb963fc9633B0c66e1d2D90Fc21", + "gasFee": "3300000000000", + "protocolFee": "0", + "chain": "eip155:84532", + "gasLimitUsed": "500000" + } + }, + "USDC.arb.old": { + "address": "0xa261A10e94aE4bA88EE8c5845CbE7266bD679DD6", + "SOURCE_CHAIN_NAMESPACE": "eip155:421614", + "decimals": "6", + "symbol": "USDC.arb.old", + "name": "USDC.arb.old", + "totalSupply": "1200157300000", + "sourceString": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "outboundQuote": { + "gasToken": "0xc0a821a1AfEd1322c5e15f1F4586C0B8cE65400e", + "gasFee": "11025300000000", + "protocolFee": "0", + "chain": "eip155:421614", + "gasLimitUsed": "500000" + } + }, + "USDT.eth.old": { + "address": "0xCA0C5E6F002A389E1580F0DB7cd06e4549B5F9d3", + "SOURCE_CHAIN_NAMESPACE": "eip155:11155111", + "decimals": "6", + "symbol": "USDT.eth", + "name": "USDT.eth", + "totalSupply": "11788104181748262940", + "sourceWord": "0x0000000000000000000000007169d38820dfd117c3fa1f22a697dba58d90ba06", + "outboundQuote": { + "gasToken": "0x2971824Db68229D087931155C2b8bB820B275809", + "gasFee": "550009000000", + "protocolFee": "0", + "chain": "eip155:11155111", + "gasLimitUsed": "500000" + } + }, + "USDT.arb.old": { + "address": "0x76Ad08339dF606BeEDe06f90e3FaF82c5b2fb2E9", + "SOURCE_CHAIN_NAMESPACE": "eip155:421614", + "decimals": "6", + "symbol": "USDT.arb", + "name": "USDT.arb", + "totalSupply": "1299969202105", + "sourceString": "0x1419d7C74D234fA6B73E06A2ce7822C1d37922f0", + "outboundQuote": { + "gasToken": "0xc0a821a1AfEd1322c5e15f1F4586C0B8cE65400e", + "gasFee": "11025300000000", + "protocolFee": "0", + "chain": "eip155:421614", + "gasLimitUsed": "500000" + } + }, + "USDT.base.old": { + "address": "0x2C455189D2af6643B924A981a9080CcC63d5a567", + "SOURCE_CHAIN_NAMESPACE": "eip155:84532", + "decimals": "6", + "symbol": "USDT.base", + "name": "USDT.base", + "totalSupply": "1200000000003199951237442", + "sourceString": "0x9FF5a186f53F6E6964B00320Da1D2024DE11E0cB", + "outboundQuote": { + "gasToken": "0xc7007af2B24D4eb963fc9633B0c66e1d2D90Fc21", + "gasFee": "3300000000000", + "protocolFee": "0", + "chain": "eip155:84532", + "gasLimitUsed": "500000" + } + }, + "USDT.bsc.old": { + "address": "0x2f98B4235FD2BA0173a2B056D722879360B12E7b", + "SOURCE_CHAIN_NAMESPACE": "eip155:97", + "decimals": "6", + "symbol": "USDT.bsc", + "name": "USDT.bsc", + "totalSupply": "1999997960033", + "sourceString": "0xBC14F348BC9667be46b35Edc9B68653d86013DC5", + "outboundQuote": { + "gasToken": "0x7a9082dA308f3fa005beA7dB0d203b3b86664E36", + "gasFee": "27500000000000", + "protocolFee": "0", + "chain": "eip155:97", + "gasLimitUsed": "500000" + } + } + } +} \ No newline at end of file diff --git a/plan/agw/independent-review-creation-flow-2026-10-20/data/post-change-compatibility.json b/plan/agw/independent-review-creation-flow-2026-10-20/data/post-change-compatibility.json new file mode 100644 index 00000000..177fbd56 --- /dev/null +++ b/plan/agw/independent-review-creation-flow-2026-10-20/data/post-change-compatibility.json @@ -0,0 +1,1094 @@ +{ + "at": "2026-10-20T17:39:03.799Z", + "readOnly": true, + "chains": [ + { + "chain": "eip155:11155111", + "candidates": [ + { + "token": "0xC4230aEaFcF6b8B49a7b4e53886420f00ff71876", + "symbol": "USDT", + "prc20": "0x0f97A213207703923F5f0C613C9827f7C9A0f96B", + "identityVerified": true + }, + { + "token": "0x97F477B7f970D47a87B42869ceeace218106152a", + "symbol": "USDC", + "prc20": "0x7A58048036206bB898008b5bBDA85697DB1e5d66", + "identityVerified": true + }, + { + "token": "0xfff9976782d46cc05630d1f6ebab18b2324d6b14", + "symbol": "WETH", + "prc20": "0x0d0dF7E8807430A81104EA84d926139816eC7586", + "identityVerified": true + }, + { + "token": "0x3e3FE7dBc6B4C189E7128855dD526361c49b40Af", + "symbol": "stETH", + "prc20": "0xaf89E805949c628ebde3262e91dc4ab9eA12668E", + "identityVerified": true + }, + { + "token": "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238", + "symbol": "USDC", + "prc20": "0x387b9C8Db60E74999aAAC5A2b7825b400F12d68E", + "identityVerified": true + } + ], + "protocols": [ + { + "app": "Uniswap V3", + "kind": "dex", + "router": "0x3bFA4769FB09eefC5a80d6E87c3B9C650f7Ae48E", + "pairs": [ + { + "tokens": [ + "0xC4230aEaFcF6b8B49a7b4e53886420f00ff71876", + "0x97F477B7f970D47a87B42869ceeace218106152a" + ], + "pools": [] + }, + { + "tokens": [ + "0xC4230aEaFcF6b8B49a7b4e53886420f00ff71876", + "0xfff9976782d46cc05630d1f6ebab18b2324d6b14" + ], + "pools": [] + }, + { + "tokens": [ + "0xC4230aEaFcF6b8B49a7b4e53886420f00ff71876", + "0x3e3FE7dBc6B4C189E7128855dD526361c49b40Af" + ], + "pools": [] + }, + { + "tokens": [ + "0xC4230aEaFcF6b8B49a7b4e53886420f00ff71876", + "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238" + ], + "pools": [] + }, + { + "tokens": [ + "0x97F477B7f970D47a87B42869ceeace218106152a", + "0xfff9976782d46cc05630d1f6ebab18b2324d6b14" + ], + "pools": [] + }, + { + "tokens": [ + "0x97F477B7f970D47a87B42869ceeace218106152a", + "0x3e3FE7dBc6B4C189E7128855dD526361c49b40Af" + ], + "pools": [] + }, + { + "tokens": [ + "0x97F477B7f970D47a87B42869ceeace218106152a", + "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238" + ], + "pools": [] + }, + { + "tokens": [ + "0xfff9976782d46cc05630d1f6ebab18b2324d6b14", + "0x3e3FE7dBc6B4C189E7128855dD526361c49b40Af" + ], + "pools": [] + }, + { + "tokens": [ + "0xfff9976782d46cc05630d1f6ebab18b2324d6b14", + "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238" + ], + "pools": [ + { + "fee": 100, + "pool": "0xFeEd501c2B21D315F04946F85fC6416B640240b5", + "liquidity": "621313943474064" + }, + { + "fee": 500, + "pool": "0x3289680dD4d6C10bb19b899729cda5eEF58AEfF1", + "liquidity": "13025255931102115" + }, + { + "fee": 3000, + "pool": "0x6Ce0896eAE6D4BD668fDe41BB784548fb8F59b50", + "liquidity": "8791221715427077" + }, + { + "fee": 10000, + "pool": "0x6418EEC70f50913ff0d756B48d32Ce7C02b47C47", + "liquidity": "107641416313884184" + } + ] + }, + { + "tokens": [ + "0x3e3FE7dBc6B4C189E7128855dD526361c49b40Af", + "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238" + ], + "pools": [] + } + ], + "factory": "0x0227628f3F023bb0B980b67D528571c95c6DaC1c", + "defaultPair": { + "tokens": [ + "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14", + "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238" + ], + "routed": [ + true, + true + ], + "pools": [ + { + "fee": 100, + "pool": "0xFeEd501c2B21D315F04946F85fC6416B640240b5", + "liquidity": "621313943474064" + }, + { + "fee": 500, + "pool": "0x3289680dD4d6C10bb19b899729cda5eEF58AEfF1", + "liquidity": "13025255931102115" + }, + { + "fee": 3000, + "pool": "0x6Ce0896eAE6D4BD668fDe41BB784548fb8F59b50", + "liquidity": "8791221715427077" + }, + { + "fee": 10000, + "pool": "0x6418EEC70f50913ff0d756B48d32Ce7C02b47C47", + "liquidity": "107641416313884184" + } + ] + } + }, + { + "app": "Aave V3", + "kind": "lending", + "pool": "0x6Ae43d3271ff6888e7Fc43Fd7321a503ff738951", + "reserves": [ + "0xFF34B3d4Aee8ddCd6F9AFFFB6Fe49bD371b8a357", + "0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5", + "0x94a9D9AC8a22534E3FaCa9F4e7F2E2cf85d5E4C8", + "0x29f2D40B0605204364af54EC677bD022dA425d03", + "0xC558DBdd856501FCd9aaF1E62eae57A9F0629a3c", + "0xaA8E23Fb1079EA71e0a56F48a2aA51851D8433D0", + "0x88541670E55cC00bEEFD87eB59EDd1b7C511AC9a", + "0x6d906e526a4e2Ca02097BA9d0caA3c382F52278E", + "0xc4bF5CbDaBE595361438F8c6a187bDc330539c60" + ], + "routedReserves": [] + }, + { + "app": "EigenLayer", + "kind": "strategy", + "strategy": "0x424246eF71b01ee33aA33aC590fd9a0855F5eFbc", + "underlying": "0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9", + "routed": false + } + ], + "presets": [ + { + "category": "DEXES", + "readiness": { + "ready": true, + "chains": [ + { + "chainNamespace": "eip155:11155111", + "ready": true, + "configurationReady": true, + "selectedAssets": [ + { + "token": "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14", + "maxPerCall": "1000000000000000", + "maxTotal": "10000000000000000" + }, + { + "token": "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238", + "maxPerCall": "10000000", + "maxTotal": "100000000" + } + ], + "bridgeAssets": [ + { + "token": "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14", + "prc20": "0x0d0dF7E8807430A81104EA84d926139816eC7586", + "status": "registered" + }, + { + "token": "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238", + "prc20": "0x387b9C8Db60E74999aAAC5A2b7825b400F12d68E", + "status": "registered" + } + ], + "issues": [], + "disabledCalls": [], + "excludedCalls": [], + "knownTokens": [ + "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14", + "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238" + ], + "zeroBridgeLimits": [] + } + ] + }, + "assets": [ + { + "token": "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14", + "maxPerCall": "1000000000000000", + "maxTotal": "10000000000000000" + }, + { + "token": "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238", + "maxPerCall": "10000000", + "maxTotal": "100000000" + } + ] + }, + { + "category": "LENDING", + "readiness": { + "ready": false, + "chains": [ + { + "chainNamespace": "eip155:11155111", + "ready": false, + "configurationReady": true, + "selectedAssets": [ + { + "token": "0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5", + "maxPerCall": "1000000000000000000", + "maxTotal": "10000000000000000000" + } + ], + "bridgeAssets": [ + { + "token": "0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5", + "status": "unavailable" + } + ], + "issues": [ + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5", + "message": "No SDK PRC20 mapping for eip155:11155111:0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5 on TESTNET_DONUT. This preset cannot be created with this token until its Push route is verified. Choose a routed token only if the selected app supports that exact token address." + } + ], + "disabledCalls": [], + "excludedCalls": [], + "knownTokens": [ + "0xFF34B3d4Aee8ddCd6F9AFFFB6Fe49bD371b8a357", + "0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5", + "0x94a9D9AC8a22534E3FaCa9F4e7F2E2cf85d5E4C8", + "0x29f2D40B0605204364af54EC677bD022dA425d03", + "0xC558DBdd856501FCd9aaF1E62eae57A9F0629a3c", + "0xaA8E23Fb1079EA71e0a56F48a2aA51851D8433D0", + "0x88541670E55cC00bEEFD87eB59EDd1b7C511AC9a", + "0x6d906e526a4e2Ca02097BA9d0caA3c382F52278E", + "0xc4bF5CbDaBE595361438F8c6a187bDc330539c60" + ], + "zeroBridgeLimits": [] + } + ] + }, + "assets": [ + { + "token": "0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5", + "maxPerCall": "1000000000000000000", + "maxTotal": "10000000000000000000" + } + ] + }, + { + "category": "STAKING", + "readiness": { + "ready": false, + "chains": [ + { + "chainNamespace": "eip155:11155111", + "ready": false, + "configurationReady": true, + "selectedAssets": [ + { + "token": "0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9", + "maxPerCall": "1000000000000000", + "maxTotal": "10000000000000000" + } + ], + "bridgeAssets": [ + { + "token": "0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9", + "status": "unavailable" + } + ], + "issues": [ + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9", + "message": "No SDK PRC20 mapping for eip155:11155111:0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9 on TESTNET_DONUT. This preset cannot be created with this token until its Push route is verified. Choose a routed token only if the selected app supports that exact token address." + } + ], + "disabledCalls": [], + "excludedCalls": [], + "knownTokens": [ + "0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9" + ], + "zeroBridgeLimits": [] + } + ] + }, + "assets": [ + { + "token": "0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9", + "maxPerCall": "1000000000000000", + "maxTotal": "10000000000000000" + } + ] + } + ], + "block": "11956837" + }, + { + "chain": "eip155:84532", + "candidates": [ + { + "token": "0x4D7646B9eE3D68F4b0F135B5cbc66B00819F6b61", + "symbol": "USDT", + "prc20": "0x148823809B853e1db187BC09A9ac909BC42F971a", + "identityVerified": true + }, + { + "token": "0x5c3504F0E3bA28FDc1F74234fE936518276AaBB8", + "symbol": "USDC", + "prc20": "0xD7C6cA1e2c0CE260BE0c0AD39C1540de460e3Be1", + "identityVerified": true + }, + { + "token": "0x4200000000000000000000000000000000000006", + "symbol": "WETH", + "unavailable": "Unsupported WETH origin chain for synthetic mapping" + }, + { + "token": "0x036CbD53842c5426634e7929541eC2318f3dCF7e", + "symbol": "USDC", + "prc20": "0x84B62e44F667F692F7739Ca6040cD17DA02068A8", + "identityVerified": true + } + ], + "protocols": [ + { + "app": "Uniswap V3", + "kind": "dex", + "router": "0x94cC0AaC535CCDB3C01d6787D6413C739ae12bc4", + "pairs": [ + { + "tokens": [ + "0x4D7646B9eE3D68F4b0F135B5cbc66B00819F6b61", + "0x5c3504F0E3bA28FDc1F74234fE936518276AaBB8" + ], + "pools": [] + }, + { + "tokens": [ + "0x4D7646B9eE3D68F4b0F135B5cbc66B00819F6b61", + "0x036CbD53842c5426634e7929541eC2318f3dCF7e" + ], + "pools": [] + }, + { + "tokens": [ + "0x5c3504F0E3bA28FDc1F74234fE936518276AaBB8", + "0x036CbD53842c5426634e7929541eC2318f3dCF7e" + ], + "pools": [] + } + ], + "factory": "0x4752ba5DBc23f44D87826276BF6Fd6b1C372aD24", + "defaultPair": { + "tokens": [ + "0x4200000000000000000000000000000000000006", + "0x036CbD53842c5426634e7929541eC2318f3dCF7e" + ], + "routed": [ + false, + true + ], + "pools": [ + { + "fee": 100, + "pool": "0x57183717A087d2fe3Ad890873877244c3B96156c", + "liquidity": "2890001491047" + }, + { + "fee": 500, + "pool": "0x94bfc0574FF48E92cE43d495376C477B1d0EEeC0", + "liquidity": "448098251397" + }, + { + "fee": 3000, + "pool": "0x46880b404CD35c165EDdefF7421019F8dD25F4Ad", + "liquidity": "541083441415564" + }, + { + "fee": 10000, + "pool": "0x4664755562152EDDa3a3073850FB62835451926a", + "liquidity": "57734017049" + } + ] + } + }, + { + "app": "Aave V3", + "kind": "lending", + "pool": "0x8bAB6d1b75f19e9eD9fCe8b9BD338844fF79aE27", + "reserves": [ + "0xba50Cd2A20f6DA35D788639E581bca8d0B5d4D5f", + "0x0a215D8ba66387DCA84B284D18c3B4ec3de6E54a", + "0x54114591963CF60EF3aA63bEfD6eC263D98145a4", + "0x4200000000000000000000000000000000000006", + "0xD171b9694f7A2597Ed006D41f7509aaD4B485c4B", + "0x810D46F9a9027E28F9B01F75E2bdde839dA61115" + ], + "routedReserves": [] + }, + { + "app": "Moonwell mUSDbC", + "kind": "market", + "market": "0x876852425331a113d8E432eFFB3aC5BEf38f033a", + "underlying": "0x4616975f7E6045FD9737e95bC527e9e14c727BD2", + "routed": false + }, + { + "app": "Moonwell mWETH", + "kind": "market", + "market": "0x2F39a349A79492a70E152760ce7123A1933eCf28", + "underlying": "0x663A6F02d547dFd639BF689FED298712f2FB69Fb", + "routed": false + } + ], + "presets": [ + { + "category": "DEXES", + "readiness": { + "ready": false, + "chains": [ + { + "chainNamespace": "eip155:84532", + "ready": false, + "configurationReady": true, + "selectedAssets": [ + { + "token": "0x4200000000000000000000000000000000000006", + "maxPerCall": "1000000000000000", + "maxTotal": "10000000000000000" + }, + { + "token": "0x036CbD53842c5426634e7929541eC2318f3dCF7e", + "maxPerCall": "10000000", + "maxTotal": "100000000" + } + ], + "bridgeAssets": [ + { + "token": "0x4200000000000000000000000000000000000006", + "status": "unavailable" + }, + { + "token": "0x036CbD53842c5426634e7929541eC2318f3dCF7e", + "prc20": "0x84B62e44F667F692F7739Ca6040cD17DA02068A8", + "status": "registered" + } + ], + "issues": [ + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0x4200000000000000000000000000000000000006", + "message": "No SDK PRC20 mapping for eip155:84532:0x4200000000000000000000000000000000000006 on TESTNET_DONUT. This preset cannot be created with this token until its Push route is verified. Choose a routed token only if the selected app supports that exact token address." + } + ], + "disabledCalls": [], + "excludedCalls": [], + "knownTokens": [ + "0x4200000000000000000000000000000000000006", + "0x036CbD53842c5426634e7929541eC2318f3dCF7e" + ], + "zeroBridgeLimits": [] + } + ] + }, + "assets": [ + { + "token": "0x4200000000000000000000000000000000000006", + "maxPerCall": "1000000000000000", + "maxTotal": "10000000000000000" + }, + { + "token": "0x036CbD53842c5426634e7929541eC2318f3dCF7e", + "maxPerCall": "10000000", + "maxTotal": "100000000" + } + ] + }, + { + "category": "LENDING", + "readiness": { + "ready": false, + "chains": [ + { + "chainNamespace": "eip155:84532", + "ready": false, + "configurationReady": true, + "selectedAssets": [ + { + "token": "0x810D46F9a9027E28F9B01F75E2bdde839dA61115", + "maxPerCall": "1000000000000000000", + "maxTotal": "10000000000000000000" + }, + { + "token": "0x4616975f7E6045FD9737e95bC527e9e14c727BD2", + "maxPerCall": "10000000", + "maxTotal": "100000000" + }, + { + "token": "0x663A6F02d547dFd639BF689FED298712f2FB69Fb", + "maxPerCall": "1000000000000000", + "maxTotal": "10000000000000000" + } + ], + "bridgeAssets": [ + { + "token": "0x810D46F9a9027E28F9B01F75E2bdde839dA61115", + "status": "unavailable" + }, + { + "token": "0x4616975f7E6045FD9737e95bC527e9e14c727BD2", + "status": "unavailable" + }, + { + "token": "0x663A6F02d547dFd639BF689FED298712f2FB69Fb", + "status": "unavailable" + } + ], + "issues": [ + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0x810D46F9a9027E28F9B01F75E2bdde839dA61115", + "message": "No SDK PRC20 mapping for eip155:84532:0x810D46F9a9027E28F9B01F75E2bdde839dA61115 on TESTNET_DONUT. This preset cannot be created with this token until its Push route is verified. Choose a routed token only if the selected app supports that exact token address." + }, + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0x4616975f7E6045FD9737e95bC527e9e14c727BD2", + "message": "No SDK PRC20 mapping for eip155:84532:0x4616975f7E6045FD9737e95bC527e9e14c727BD2 on TESTNET_DONUT. This preset cannot be created with this token until its Push route is verified. Choose a routed token only if the selected app supports that exact token address." + }, + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0x663A6F02d547dFd639BF689FED298712f2FB69Fb", + "message": "No SDK PRC20 mapping for eip155:84532:0x663A6F02d547dFd639BF689FED298712f2FB69Fb on TESTNET_DONUT. This preset cannot be created with this token until its Push route is verified. Choose a routed token only if the selected app supports that exact token address." + } + ], + "disabledCalls": [], + "excludedCalls": [ + { + "target": "0x876852425331a113d8E432eFFB3aC5BEf38f033a", + "selector": "redeem(uint256)", + "app": "Moonwell mUSDbC", + "reason": "SHARE_AMOUNT", + "alternative": "redeemUnderlying(uint256)" + }, + { + "target": "0x2F39a349A79492a70E152760ce7123A1933eCf28", + "selector": "redeem(uint256)", + "app": "Moonwell mWETH", + "reason": "SHARE_AMOUNT", + "alternative": "redeemUnderlying(uint256)" + } + ], + "knownTokens": [ + "0xba50Cd2A20f6DA35D788639E581bca8d0B5d4D5f", + "0x0a215D8ba66387DCA84B284D18c3B4ec3de6E54a", + "0x54114591963CF60EF3aA63bEfD6eC263D98145a4", + "0x4200000000000000000000000000000000000006", + "0xD171b9694f7A2597Ed006D41f7509aaD4B485c4B", + "0x810D46F9a9027E28F9B01F75E2bdde839dA61115", + "0x4616975f7E6045FD9737e95bC527e9e14c727BD2", + "0x663A6F02d547dFd639BF689FED298712f2FB69Fb" + ], + "zeroBridgeLimits": [] + } + ] + }, + "assets": [ + { + "token": "0x810D46F9a9027E28F9B01F75E2bdde839dA61115", + "maxPerCall": "1000000000000000000", + "maxTotal": "10000000000000000000" + }, + { + "token": "0x4616975f7E6045FD9737e95bC527e9e14c727BD2", + "maxPerCall": "10000000", + "maxTotal": "100000000" + }, + { + "token": "0x663A6F02d547dFd639BF689FED298712f2FB69Fb", + "maxPerCall": "1000000000000000", + "maxTotal": "10000000000000000" + } + ] + } + ], + "block": "48374837" + }, + { + "chain": "eip155:421614", + "candidates": [ + { + "token": "0xE30928528f52CAEeB75fB07837e22d77D47e9c07", + "symbol": "USDT", + "prc20": "0xFE6E9DF2BbC9ce05D98b83B1365df6DcA9951891", + "identityVerified": true + }, + { + "token": "0x5dd39b0b3610F666F631a6506b7713EF83e1Ac5C", + "symbol": "USDC", + "prc20": "0x1091cCBA2FF8d2A131AE4B35e34cf3308C48572C", + "identityVerified": true + }, + { + "token": "0x980B62Da83eFf3D4576C647993b0c1D7faf17c73", + "symbol": "WETH", + "unavailable": "Unsupported WETH origin chain for synthetic mapping" + }, + { + "token": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "symbol": "USDC", + "prc20": "0xa261A10e94aE4bA88EE8c5845CbE7266bD679DD6", + "identityVerified": true + } + ], + "protocols": [ + { + "app": "Uniswap V3", + "kind": "dex", + "router": "0x101F443B4d1b059569D643917553c771E1b9663E", + "pairs": [ + { + "tokens": [ + "0xE30928528f52CAEeB75fB07837e22d77D47e9c07", + "0x5dd39b0b3610F666F631a6506b7713EF83e1Ac5C" + ], + "pools": [] + }, + { + "tokens": [ + "0xE30928528f52CAEeB75fB07837e22d77D47e9c07", + "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d" + ], + "pools": [] + }, + { + "tokens": [ + "0x5dd39b0b3610F666F631a6506b7713EF83e1Ac5C", + "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d" + ], + "pools": [] + } + ], + "factory": "0x248AB79Bbb9bC29bB72f7Cd42F17e054Fc40188e", + "defaultPair": { + "tokens": [ + "0x980B62Da83eFf3D4576C647993b0c1D7faf17c73", + "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d" + ], + "routed": [ + false, + true + ], + "pools": [ + { + "fee": 100, + "pool": "0x152c469626C706E201721F13eb470691E4E81c5D", + "liquidity": "0" + }, + { + "fee": 500, + "pool": "0x6F112d524DC998381C09b4e53C7e5e2cc260f877", + "liquidity": "122" + }, + { + "fee": 3000, + "pool": "0x66EEAB70aC52459Dd74C6AD50D578Ef76a441bbf", + "liquidity": "10070937193695" + }, + { + "fee": 10000, + "pool": "0x3eCedaB7E9479E29B694d8590dc34e0Ce6059868", + "liquidity": "3225673603183" + } + ] + } + }, + { + "app": "Aave V3", + "kind": "lending", + "pool": "0xBfC91D59fdAA134A4ED45f7B584cAf96D7792Eff", + "reserves": [ + "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "0x1dF462e2712496373A347f8ad10802a5E95f053D" + ], + "routedReserves": [ + { + "token": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "symbol": "USDC", + "prc20": "0xa261A10e94aE4bA88EE8c5845CbE7266bD679DD6", + "identityVerified": true + } + ] + } + ], + "presets": [ + { + "category": "DEXES", + "readiness": { + "ready": false, + "chains": [ + { + "chainNamespace": "eip155:421614", + "ready": false, + "configurationReady": true, + "selectedAssets": [ + { + "token": "0x980B62Da83eFf3D4576C647993b0c1D7faf17c73", + "maxPerCall": "1000000000000000", + "maxTotal": "10000000000000000" + }, + { + "token": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "maxPerCall": "10000000", + "maxTotal": "100000000" + } + ], + "bridgeAssets": [ + { + "token": "0x980B62Da83eFf3D4576C647993b0c1D7faf17c73", + "status": "unavailable" + }, + { + "token": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "prc20": "0xa261A10e94aE4bA88EE8c5845CbE7266bD679DD6", + "status": "registered" + } + ], + "issues": [ + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0x980B62Da83eFf3D4576C647993b0c1D7faf17c73", + "message": "No SDK PRC20 mapping for eip155:421614:0x980B62Da83eFf3D4576C647993b0c1D7faf17c73 on TESTNET_DONUT. This preset cannot be created with this token until its Push route is verified. Choose a routed token only if the selected app supports that exact token address." + } + ], + "disabledCalls": [], + "excludedCalls": [], + "knownTokens": [ + "0x980B62Da83eFf3D4576C647993b0c1D7faf17c73", + "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d" + ], + "zeroBridgeLimits": [] + } + ] + }, + "assets": [ + { + "token": "0x980B62Da83eFf3D4576C647993b0c1D7faf17c73", + "maxPerCall": "1000000000000000", + "maxTotal": "10000000000000000" + }, + { + "token": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "maxPerCall": "10000000", + "maxTotal": "100000000" + } + ] + }, + { + "category": "LENDING", + "readiness": { + "ready": true, + "chains": [ + { + "chainNamespace": "eip155:421614", + "ready": true, + "configurationReady": true, + "selectedAssets": [ + { + "token": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "maxPerCall": "10000000", + "maxTotal": "100000000" + } + ], + "bridgeAssets": [ + { + "token": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "prc20": "0xa261A10e94aE4bA88EE8c5845CbE7266bD679DD6", + "status": "registered" + } + ], + "issues": [], + "disabledCalls": [], + "excludedCalls": [], + "knownTokens": [ + "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "0x1dF462e2712496373A347f8ad10802a5E95f053D" + ], + "zeroBridgeLimits": [] + } + ] + }, + "assets": [ + { + "token": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "maxPerCall": "10000000", + "maxTotal": "100000000" + } + ] + } + ], + "block": "321130556" + }, + { + "chain": "eip155:97", + "candidates": [ + { + "token": "0xE935d9c9C24D02E61186c640cc01d713C876d40F", + "symbol": "USDT", + "prc20": "0x731aF1Da5365259d27528557EE4aFBA4baC90ef2", + "identityVerified": true + }, + { + "token": "0xA8802F96cAd0d45343d9bc660B6f7d80050A660b", + "symbol": "USDC", + "prc20": "0x120EBf25Dad7D6a09Ad2316f23f9Be95DBb90639", + "identityVerified": true + } + ], + "protocols": [ + { + "app": "PancakeSwap V3", + "kind": "dex", + "router": "0x9a489505a00cE272eAa5e07Dba6491314CaE3796", + "pairs": [ + { + "tokens": [ + "0xE935d9c9C24D02E61186c640cc01d713C876d40F", + "0xA8802F96cAd0d45343d9bc660B6f7d80050A660b" + ], + "pools": [] + } + ], + "factory": "0x0BFbCF9fa4f9C56B0F40a671Ad40E0805A091865", + "defaultPair": { + "tokens": [ + "0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd", + "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c" + ], + "routed": [ + false, + false + ], + "pools": [ + { + "fee": 100, + "pool": "0xCed0844e421F856D2de472F9e7037f873987887C", + "liquidity": "229529662705916" + }, + { + "fee": 500, + "pool": "0xc2F0629Dd29AB0EcfF7476560bc8FD5c0c4D19Cd", + "liquidity": "0" + }, + { + "fee": 2500, + "pool": "0x917aB0c0f32452e1403eBD68B222C0B59bAaa2C3", + "liquidity": "0" + }, + { + "fee": 10000, + "pool": "0xa5316a3418e0643BB977A97689E584a3b6c35080", + "liquidity": "0" + } + ] + } + }, + { + "app": "Venus vUSDT", + "kind": "market", + "market": "0xb7526572FFE56AB9D7489838Bf2E18e3323b441A", + "underlying": "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", + "routed": false + }, + { + "app": "Venus vUSDC", + "kind": "market", + "market": "0xD5C4C2e2facBEB59D0216D0595d63FcDc6F9A1a7", + "underlying": "0x16227D60f7a0e586C66B005219dfc887D13C9531", + "routed": false + } + ], + "presets": [ + { + "category": "DEXES", + "readiness": { + "ready": false, + "chains": [ + { + "chainNamespace": "eip155:97", + "ready": false, + "configurationReady": true, + "selectedAssets": [ + { + "token": "0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd", + "maxPerCall": "10000000000000000", + "maxTotal": "100000000000000000" + }, + { + "token": "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", + "maxPerCall": "10000000", + "maxTotal": "100000000" + } + ], + "bridgeAssets": [ + { + "token": "0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd", + "status": "unavailable" + }, + { + "token": "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", + "status": "unavailable" + } + ], + "issues": [ + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd", + "message": "No SDK PRC20 mapping for eip155:97:0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd on TESTNET_DONUT. This preset cannot be created with this token until its Push route is verified. Choose a routed token only if the selected app supports that exact token address." + }, + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", + "message": "No SDK PRC20 mapping for eip155:97:0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c on TESTNET_DONUT. This preset cannot be created with this token until its Push route is verified. Choose a routed token only if the selected app supports that exact token address." + } + ], + "disabledCalls": [], + "excludedCalls": [], + "knownTokens": [ + "0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd", + "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c" + ], + "zeroBridgeLimits": [] + } + ] + }, + "assets": [ + { + "token": "0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd", + "maxPerCall": "10000000000000000", + "maxTotal": "100000000000000000" + }, + { + "token": "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", + "maxPerCall": "10000000", + "maxTotal": "100000000" + } + ] + }, + { + "category": "LENDING", + "readiness": { + "ready": false, + "chains": [ + { + "chainNamespace": "eip155:97", + "ready": false, + "configurationReady": true, + "selectedAssets": [ + { + "token": "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", + "maxPerCall": "10000000", + "maxTotal": "100000000" + }, + { + "token": "0x16227D60f7a0e586C66B005219dfc887D13C9531", + "maxPerCall": "10000000", + "maxTotal": "100000000" + } + ], + "bridgeAssets": [ + { + "token": "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", + "status": "unavailable" + }, + { + "token": "0x16227D60f7a0e586C66B005219dfc887D13C9531", + "status": "unavailable" + } + ], + "issues": [ + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", + "message": "No SDK PRC20 mapping for eip155:97:0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c on TESTNET_DONUT. This preset cannot be created with this token until its Push route is verified. Choose a routed token only if the selected app supports that exact token address." + }, + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0x16227D60f7a0e586C66B005219dfc887D13C9531", + "message": "No SDK PRC20 mapping for eip155:97:0x16227D60f7a0e586C66B005219dfc887D13C9531 on TESTNET_DONUT. This preset cannot be created with this token until its Push route is verified. Choose a routed token only if the selected app supports that exact token address." + } + ], + "disabledCalls": [], + "excludedCalls": [ + { + "target": "0xb7526572FFE56AB9D7489838Bf2E18e3323b441A", + "selector": "redeem(uint256)", + "app": "Venus vUSDT", + "reason": "SHARE_AMOUNT", + "alternative": "redeemUnderlying(uint256)" + }, + { + "target": "0xD5C4C2e2facBEB59D0216D0595d63FcDc6F9A1a7", + "selector": "redeem(uint256)", + "app": "Venus vUSDC", + "reason": "SHARE_AMOUNT", + "alternative": "redeemUnderlying(uint256)" + } + ], + "knownTokens": [ + "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", + "0x16227D60f7a0e586C66B005219dfc887D13C9531" + ], + "zeroBridgeLimits": [] + } + ] + }, + "assets": [ + { + "token": "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", + "maxPerCall": "10000000", + "maxTotal": "100000000" + }, + { + "token": "0x16227D60f7a0e586C66B005219dfc887D13C9531", + "maxPerCall": "10000000", + "maxTotal": "100000000" + } + ] + } + ], + "block": "137927715" + } + ], + "pushBlock": "24458953" +} \ No newline at end of file diff --git a/plan/agw/independent-review-creation-flow-2026-10-20/data/post-change-gas-quotes.json b/plan/agw/independent-review-creation-flow-2026-10-20/data/post-change-gas-quotes.json new file mode 100644 index 00000000..7f60e420 --- /dev/null +++ b/plan/agw/independent-review-creation-flow-2026-10-20/data/post-change-gas-quotes.json @@ -0,0 +1,286 @@ +{ + "at": "2026-10-20T17:37:26.676Z", + "readOnly": true, + "network": "TESTNET_DONUT", + "note": "Current quotes only; first-use and subsequent labels describe gas-limit inputs, not executed transactions.", + "origins": [ + { + "signerOrigin": "eip155:42101", + "pushBlockBefore": "24458913", + "cases": [ + { + "chain": "eip155:11155111", + "stage": "default-new-account", + "inputGasLimit": "2000000", + "protocolFee": "0", + "nativeValueForGas": "10000000000000000000", + "gasLimitUsed": "2000000", + "gasFee": "2200036000000", + "poolPcIn": "3218360887313289", + "attachedPCWei": "10000000000000000000", + "fits20PCCeiling": true + }, + { + "chain": "eip155:11155111", + "stage": "route-default-zero-input", + "inputGasLimit": "0", + "protocolFee": "0", + "nativeValueForGas": "10000000000000000000", + "gasLimitUsed": "500000", + "gasFee": "550009000000", + "poolPcIn": "804590193808946", + "attachedPCWei": "10000000000000000000", + "fits20PCCeiling": true + }, + { + "chain": "eip155:84532", + "stage": "default-new-account", + "inputGasLimit": "2000000", + "protocolFee": "0", + "nativeValueForGas": "10000000000000000000", + "gasLimitUsed": "2000000", + "gasFee": "13200000000000", + "poolPcIn": "591543988922286942", + "attachedPCWei": "10000000000000000000", + "fits20PCCeiling": true + }, + { + "chain": "eip155:84532", + "stage": "route-default-zero-input", + "inputGasLimit": "0", + "protocolFee": "0", + "nativeValueForGas": "10000000000000000000", + "gasLimitUsed": "500000", + "gasFee": "3300000000000", + "poolPcIn": "147885927165951477", + "attachedPCWei": "10000000000000000000", + "fits20PCCeiling": true + }, + { + "chain": "eip155:421614", + "stage": "default-new-account", + "inputGasLimit": "2000000", + "protocolFee": "0", + "nativeValueForGas": "10000000000000000000", + "gasLimitUsed": "2000000", + "gasFee": "44180400000000", + "poolPcIn": "1886829389526846363", + "attachedPCWei": "10000000000000000000", + "fits20PCCeiling": true + }, + { + "chain": "eip155:421614", + "stage": "route-default-zero-input", + "inputGasLimit": "0", + "protocolFee": "0", + "nativeValueForGas": "10000000000000000000", + "gasLimitUsed": "500000", + "gasFee": "11045100000000", + "poolPcIn": "471706048271902683", + "attachedPCWei": "10000000000000000000", + "fits20PCCeiling": true + }, + { + "chain": "eip155:97", + "stage": "default-new-account", + "inputGasLimit": "2000000", + "protocolFee": "0", + "nativeValueForGas": "10000000000000000000", + "gasLimitUsed": "2000000", + "gasFee": "220000000000000", + "poolPcIn": "2365226106240649448", + "attachedPCWei": "10000000000000000000", + "fits20PCCeiling": true + }, + { + "chain": "eip155:97", + "stage": "route-default-zero-input", + "inputGasLimit": "0", + "protocolFee": "0", + "nativeValueForGas": "10000000000000000000", + "gasLimitUsed": "500000", + "gasFee": "55000000000000", + "poolPcIn": "591303700728691582", + "attachedPCWei": "10000000000000000000", + "fits20PCCeiling": true + }, + { + "chain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "stage": "legacy-million-unit-fallback", + "inputGasLimit": "1000000", + "protocolFee": "0", + "nativeValueForGas": "1086925525682799370979", + "gasLimitUsed": "1000000", + "gasFee": "1000000000", + "poolPcIn": "905771271402332809149", + "attachedPCWei": "1086925525682799370979", + "fits20PCCeiling": false + }, + { + "chain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "stage": "sdk-default-route-sizing", + "inputGasLimit": "0", + "protocolFee": "0", + "nativeValueForGas": "10000000000000000000", + "gasLimitUsed": "1052", + "gasFee": "1052000", + "poolPcIn": "952854694072291801", + "attachedPCWei": "10000000000000000000", + "fits20PCCeiling": true + }, + { + "chain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "stage": "spl-first-use-route-sizing", + "inputGasLimit": "0", + "protocolFee": "0", + "nativeValueForGas": "10000000000000000000", + "gasLimitUsed": "2285", + "gasFee": "2285000", + "poolPcIn": "2069651162555018878", + "attachedPCWei": "10000000000000000000", + "fits20PCCeiling": true + } + ], + "pushBlockAfter": "24458922" + }, + { + "signerOrigin": "eip155:11155111", + "pushBlockBefore": "24458922", + "cases": [ + { + "chain": "eip155:11155111", + "stage": "default-new-account", + "inputGasLimit": "2000000", + "protocolFee": "0", + "nativeValueForGas": "4298634753602255924", + "gasLimitUsed": "2000000", + "gasFee": "2200036000000", + "poolPcIn": "3218360887313289", + "attachedPCWei": "4298634753602255924", + "fits20PCCeiling": true + }, + { + "chain": "eip155:11155111", + "stage": "route-default-zero-input", + "inputGasLimit": "0", + "protocolFee": "0", + "nativeValueForGas": "4298634753602255924", + "gasLimitUsed": "500000", + "gasFee": "550009000000", + "poolPcIn": "804590193808946", + "attachedPCWei": "4298634753602255924", + "fits20PCCeiling": true + }, + { + "chain": "eip155:84532", + "stage": "default-new-account", + "inputGasLimit": "2000000", + "protocolFee": "0", + "nativeValueForGas": "4298634753602255924", + "gasLimitUsed": "2000000", + "gasFee": "13200000000000", + "poolPcIn": "591543988922286942", + "attachedPCWei": "4298634753602255924", + "fits20PCCeiling": true + }, + { + "chain": "eip155:84532", + "stage": "route-default-zero-input", + "inputGasLimit": "0", + "protocolFee": "0", + "nativeValueForGas": "4298634753602255924", + "gasLimitUsed": "500000", + "gasFee": "3300000000000", + "poolPcIn": "147885927165951477", + "attachedPCWei": "4298634753602255924", + "fits20PCCeiling": true + }, + { + "chain": "eip155:421614", + "stage": "default-new-account", + "inputGasLimit": "2000000", + "protocolFee": "0", + "nativeValueForGas": "4298634753602255924", + "gasLimitUsed": "2000000", + "gasFee": "44030800000000", + "poolPcIn": "1880440341223012638", + "attachedPCWei": "4298634753602255924", + "fits20PCCeiling": true + }, + { + "chain": "eip155:421614", + "stage": "route-default-zero-input", + "inputGasLimit": "0", + "protocolFee": "0", + "nativeValueForGas": "4298634753602255924", + "gasLimitUsed": "500000", + "gasFee": "11007700000000", + "poolPcIn": "470108794978944401", + "attachedPCWei": "4298634753602255924", + "fits20PCCeiling": true + }, + { + "chain": "eip155:97", + "stage": "default-new-account", + "inputGasLimit": "2000000", + "protocolFee": "0", + "nativeValueForGas": "4298634753602255924", + "gasLimitUsed": "2000000", + "gasFee": "110000000000000", + "poolPcIn": "1182609285339028323", + "attachedPCWei": "4298634753602255924", + "fits20PCCeiling": true + }, + { + "chain": "eip155:97", + "stage": "route-default-zero-input", + "inputGasLimit": "0", + "protocolFee": "0", + "nativeValueForGas": "4298634753602255924", + "gasLimitUsed": "500000", + "gasFee": "27500000000000", + "poolPcIn": "295651614879702834", + "attachedPCWei": "4298634753602255924", + "fits20PCCeiling": true + }, + { + "chain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "stage": "legacy-million-unit-fallback", + "inputGasLimit": "1000000", + "protocolFee": "0", + "nativeValueForGas": "1086925525682799370979", + "gasLimitUsed": "1000000", + "gasFee": "1000000000", + "poolPcIn": "905771271402332809149", + "attachedPCWei": "1086925525682799370979", + "fits20PCCeiling": false + }, + { + "chain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "stage": "sdk-default-route-sizing", + "inputGasLimit": "0", + "protocolFee": "0", + "nativeValueForGas": "4298634753602255924", + "gasLimitUsed": "1052", + "gasFee": "1052000", + "poolPcIn": "952854694072291801", + "attachedPCWei": "4298634753602255924", + "fits20PCCeiling": true + }, + { + "chain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "stage": "spl-first-use-route-sizing", + "inputGasLimit": "0", + "protocolFee": "0", + "nativeValueForGas": "4298634753602255924", + "gasLimitUsed": "2285", + "gasFee": "2285000", + "poolPcIn": "2069651162555018878", + "attachedPCWei": "4298634753602255924", + "fits20PCCeiling": true + } + ], + "pushBlockAfter": "24458952" + } + ] +} \ No newline at end of file diff --git a/plan/agw/independent-review-creation-flow-2026-10-20/data/post-change-route-registry.json b/plan/agw/independent-review-creation-flow-2026-10-20/data/post-change-route-registry.json new file mode 100644 index 00000000..85b65611 --- /dev/null +++ b/plan/agw/independent-review-creation-flow-2026-10-20/data/post-change-route-registry.json @@ -0,0 +1,311 @@ +{ + "at": "2026-10-20T17:39:03.493Z", + "readOnly": true, + "rpc": "https://donut.rpc.push.org:443", + "node": "v0.0.49", + "height": "24458953", + "matched": [ + { + "chain": "eip155:11155111", + "address": "0x0000000000000000000000000000000000000000", + "symbol": "pETH", + "decimals": 18, + "nodePrc20": "0x2971824Db68229D087931155C2b8bB820B275809", + "sdkPrc20": "0x2971824Db68229D087931155C2b8bB820B275809" + }, + { + "chain": "eip155:11155111", + "address": "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238", + "symbol": "USDC.eth.old", + "decimals": 6, + "nodePrc20": "0x387b9C8Db60E74999aAAC5A2b7825b400F12d68E", + "sdkPrc20": "0x387b9C8Db60E74999aAAC5A2b7825b400F12d68E" + }, + { + "chain": "eip155:11155111", + "address": "0x3e3FE7dBc6B4C189E7128855dD526361c49b40Af", + "symbol": "stETH.eth", + "decimals": 18, + "nodePrc20": "0xaf89E805949c628ebde3262e91dc4ab9eA12668E", + "sdkPrc20": "0xaf89E805949c628ebde3262e91dc4ab9eA12668E" + }, + { + "chain": "eip155:11155111", + "address": "0x97F477B7f970D47a87B42869ceeace218106152a", + "symbol": "USDC.eth", + "decimals": 6, + "nodePrc20": "0x7A58048036206bB898008b5bBDA85697DB1e5d66", + "sdkPrc20": "0x7A58048036206bB898008b5bBDA85697DB1e5d66" + }, + { + "chain": "eip155:11155111", + "address": "0xC4230aEaFcF6b8B49a7b4e53886420f00ff71876", + "symbol": "USDT.eth", + "decimals": 6, + "nodePrc20": "0x0f97A213207703923F5f0C613C9827f7C9A0f96B", + "sdkPrc20": "0x0f97A213207703923F5f0C613C9827f7C9A0f96B" + }, + { + "chain": "eip155:11155111", + "address": "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14", + "symbol": "WETH.eth", + "decimals": 18, + "nodePrc20": "0x0d0dF7E8807430A81104EA84d926139816eC7586", + "sdkPrc20": "0x0d0dF7E8807430A81104EA84d926139816eC7586" + }, + { + "chain": "eip155:421614", + "address": "0x0000000000000000000000000000000000000000", + "symbol": "pETH.arb", + "decimals": 18, + "nodePrc20": "0xc0a821a1AfEd1322c5e15f1F4586C0B8cE65400e", + "sdkPrc20": "0xc0a821a1AfEd1322c5e15f1F4586C0B8cE65400e" + }, + { + "chain": "eip155:421614", + "address": "0x5dd39b0b3610F666F631a6506b7713EF83e1Ac5C", + "symbol": "USDC.arb", + "decimals": 6, + "nodePrc20": "0x1091cCBA2FF8d2A131AE4B35e34cf3308C48572C", + "sdkPrc20": "0x1091cCBA2FF8d2A131AE4B35e34cf3308C48572C" + }, + { + "chain": "eip155:421614", + "address": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "symbol": "USDC.arb.old", + "decimals": 6, + "nodePrc20": "0xa261A10e94aE4bA88EE8c5845CbE7266bD679DD6", + "sdkPrc20": "0xa261A10e94aE4bA88EE8c5845CbE7266bD679DD6" + }, + { + "chain": "eip155:421614", + "address": "0xE30928528f52CAEeB75fB07837e22d77D47e9c07", + "symbol": "USDT.arb", + "decimals": 6, + "nodePrc20": "0xFE6E9DF2BbC9ce05D98b83B1365df6DcA9951891", + "sdkPrc20": "0xFE6E9DF2BbC9ce05D98b83B1365df6DcA9951891" + }, + { + "chain": "eip155:84532", + "address": "0x0000000000000000000000000000000000000000", + "symbol": "pETH.base", + "decimals": 18, + "nodePrc20": "0xc7007af2B24D4eb963fc9633B0c66e1d2D90Fc21", + "sdkPrc20": "0xc7007af2B24D4eb963fc9633B0c66e1d2D90Fc21" + }, + { + "chain": "eip155:84532", + "address": "0x036CbD53842c5426634e7929541eC2318f3dCF7e", + "symbol": "USDC.base.old", + "decimals": 6, + "nodePrc20": "0x84B62e44F667F692F7739Ca6040cD17DA02068A8", + "sdkPrc20": "0x84B62e44F667F692F7739Ca6040cD17DA02068A8" + }, + { + "chain": "eip155:84532", + "address": "0x4D7646B9eE3D68F4b0F135B5cbc66B00819F6b61", + "symbol": "USDT.base", + "decimals": 6, + "nodePrc20": "0x148823809B853e1db187BC09A9ac909BC42F971a", + "sdkPrc20": "0x148823809B853e1db187BC09A9ac909BC42F971a" + }, + { + "chain": "eip155:84532", + "address": "0x5c3504F0E3bA28FDc1F74234fE936518276AaBB8", + "symbol": "USDC.base", + "decimals": 6, + "nodePrc20": "0xD7C6cA1e2c0CE260BE0c0AD39C1540de460e3Be1", + "sdkPrc20": "0xD7C6cA1e2c0CE260BE0c0AD39C1540de460e3Be1" + }, + { + "chain": "eip155:97", + "address": "0x0000000000000000000000000000000000000000", + "symbol": "pBNB", + "decimals": 18, + "nodePrc20": "0x7a9082dA308f3fa005beA7dB0d203b3b86664E36", + "sdkPrc20": "0x7a9082dA308f3fa005beA7dB0d203b3b86664E36" + }, + { + "chain": "eip155:97", + "address": "0xA8802F96cAd0d45343d9bc660B6f7d80050A660b", + "symbol": "USDC.bsc", + "decimals": 6, + "nodePrc20": "0x120EBf25Dad7D6a09Ad2316f23f9Be95DBb90639", + "sdkPrc20": "0x120EBf25Dad7D6a09Ad2316f23f9Be95DBb90639" + }, + { + "chain": "eip155:97", + "address": "0xE935d9c9C24D02E61186c640cc01d713C876d40F", + "symbol": "USDT.bsc", + "decimals": 6, + "nodePrc20": "0x731aF1Da5365259d27528557EE4aFBA4baC90ef2", + "sdkPrc20": "0x731aF1Da5365259d27528557EE4aFBA4baC90ef2" + }, + { + "chain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "address": "11111111111111111111111111111111", + "symbol": "pSOL", + "decimals": 9, + "nodePrc20": "0x5D525Df2bD99a6e7ec58b76aF2fd95F39874EBed", + "sdkPrc20": "0x5D525Df2bD99a6e7ec58b76aF2fd95F39874EBed" + }, + { + "chain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "address": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "symbol": "USDC.sol", + "decimals": 6, + "nodePrc20": "0x04B8F634ABC7C879763F623e0f0550a4b5c4426F", + "sdkPrc20": "0x04B8F634ABC7C879763F623e0f0550a4b5c4426F" + }, + { + "chain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "address": "EiXDnrAg9ea2Q6vEPV7E5TpTU1vh41jcuZqKjU5Dc4ZF", + "symbol": "USDT.sol", + "decimals": 6, + "nodePrc20": "0x4f1A3D22d170a2F4Bddb37845a962322e24f4e34", + "sdkPrc20": "0x4f1A3D22d170a2F4Bddb37845a962322e24f4e34" + } + ], + "mismatch": [], + "nodeOnly": [ + { + "chain": "eip155:11155111", + "address": "0x7169D38820dfd117C3FA1f22a697dBA58d90BA06", + "symbol": "USDT.eth.old", + "decimals": 6, + "nodePrc20": "0xCA0C5E6F002A389E1580F0DB7cd06e4549B5F9d3", + "sdk": "Unable to infer origin chain or token symbol for token" + }, + { + "chain": "eip155:421614", + "address": "0x1419d7C74D234fA6B73E06A2ce7822C1d37922f0", + "symbol": "USDT.arb.old", + "decimals": 6, + "nodePrc20": "0x76Ad08339dF606BeEDe06f90e3FaF82c5b2fb2E9", + "sdk": "Unable to infer origin chain or token symbol for token" + }, + { + "chain": "eip155:84532", + "address": "0x9FF5a186f53F6E6964B00320Da1D2024DE11E0cB", + "symbol": "USDT.base.old", + "decimals": 6, + "nodePrc20": "0x2C455189D2af6643B924A981a9080CcC63d5a567", + "sdk": "Unable to infer origin chain or token symbol for token" + }, + { + "chain": "eip155:97", + "address": "0xBC14F348BC9667be46b35Edc9B68653d86013DC5", + "symbol": "USDT.bsc.old", + "decimals": 6, + "nodePrc20": "0x2f98B4235FD2BA0173a2B056D722879360B12E7b", + "sdk": "Unable to infer origin chain or token symbol for token" + }, + { + "chain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "address": "G2ZLaRhpohW23KTEX3fBjZXtNTFFwemqCaWWnWVTj4TB", + "symbol": "DAI.sol", + "decimals": 6, + "nodePrc20": "0x5861f56A556c990358cc9cccd8B5baa3767982A8", + "sdk": "Unsupported token symbol: DAI" + } + ], + "sdkOnly": [], + "presetTokens": [ + { + "preset": "DEXES", + "chain": "eip155:11155111", + "token": "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14", + "nodePrc20": "0x0d0dF7E8807430A81104EA84d926139816eC7586" + }, + { + "preset": "DEXES", + "chain": "eip155:11155111", + "token": "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238", + "nodePrc20": "0x387b9C8Db60E74999aAAC5A2b7825b400F12d68E" + }, + { + "preset": "DEXES", + "chain": "eip155:84532", + "token": "0x4200000000000000000000000000000000000006", + "nodePrc20": null + }, + { + "preset": "DEXES", + "chain": "eip155:84532", + "token": "0x036CbD53842c5426634e7929541eC2318f3dCF7e", + "nodePrc20": "0x84B62e44F667F692F7739Ca6040cD17DA02068A8" + }, + { + "preset": "DEXES", + "chain": "eip155:421614", + "token": "0x980B62Da83eFf3D4576C647993b0c1D7faf17c73", + "nodePrc20": null + }, + { + "preset": "DEXES", + "chain": "eip155:421614", + "token": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "nodePrc20": "0xa261A10e94aE4bA88EE8c5845CbE7266bD679DD6" + }, + { + "preset": "DEXES", + "chain": "eip155:97", + "token": "0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd", + "nodePrc20": null + }, + { + "preset": "DEXES", + "chain": "eip155:97", + "token": "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", + "nodePrc20": null + }, + { + "preset": "LENDING", + "chain": "eip155:11155111", + "token": "0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5", + "nodePrc20": null + }, + { + "preset": "LENDING", + "chain": "eip155:421614", + "token": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "nodePrc20": "0xa261A10e94aE4bA88EE8c5845CbE7266bD679DD6" + }, + { + "preset": "LENDING", + "chain": "eip155:84532", + "token": "0x810D46F9a9027E28F9B01F75E2bdde839dA61115", + "nodePrc20": null + }, + { + "preset": "LENDING", + "chain": "eip155:84532", + "token": "0x4616975f7E6045FD9737e95bC527e9e14c727BD2", + "nodePrc20": null + }, + { + "preset": "LENDING", + "chain": "eip155:84532", + "token": "0x663A6F02d547dFd639BF689FED298712f2FB69Fb", + "nodePrc20": null + }, + { + "preset": "LENDING", + "chain": "eip155:97", + "token": "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", + "nodePrc20": null + }, + { + "preset": "LENDING", + "chain": "eip155:97", + "token": "0x16227D60f7a0e586C66B005219dfc887D13C9531", + "nodePrc20": null + }, + { + "preset": "STAKING", + "chain": "eip155:11155111", + "token": "0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9", + "nodePrc20": null + } + ] +} \ No newline at end of file diff --git a/plan/agw/independent-review-creation-flow-2026-10-20/data/push-probe.json b/plan/agw/independent-review-creation-flow-2026-10-20/data/push-probe.json new file mode 100644 index 00000000..3d14b338 --- /dev/null +++ b/plan/agw/independent-review-creation-flow-2026-10-20/data/push-probe.json @@ -0,0 +1,895 @@ +{ + "at": "2026-10-20T16:25:35.190Z", + "rpc": "https://evm.donut.rpc.push.org/", + "readOnly": true, + "chainId": 42101, + "block": "24457144", + "blockTimestamp": "2026-10-20T16:25:31.000Z", + "sends": { + "spl:first-use": { + "hash": "0x119c89e9ff7c7cccdfc8c071fade2488aa28b0eff7d9b71f7f0cf247c958bbf5", + "status": "success", + "block": "24455663", + "from": "0x8fb1cf80a014af564bdc12e557a3e52432f4657b", + "to": "0xed6bfe825b8d84a1e6f4f7c9067398f8985cc372", + "txValue": "0", + "gasUsed": "468004", + "effectiveGasPrice": "1125000000", + "pushFeePaid": "526504500000000", + "events": [ + { + "ev": "OutboundMetered", + "emitter": "0xba32e7a1500cb34311a31127bcd40ca52c8cfd36", + "id": "0x16be7e479fcee17b79ed4ed7a6ff75c6cf954c08dad16c9a59b876be242c9ea8", + "engine": "0xf63DC0628fe1B25049FE3E3a3585Ef051CB98c1d", + "account": "0xED6bFE825b8d84A1E6f4F7c9067398F8985CC372", + "token": "0x4f1A3D22d170a2F4Bddb37845a962322e24f4e34", + "amount": "1000" + }, + { + "ev": "SwapAndBurnGas", + "emitter": "0x00000000000000000000000000000000000000c0", + "gasToken": "0x5D525Df2bD99a6e7ec58b76aF2fd95F39874EBed", + "caller": "0xED6bFE825b8d84A1E6f4F7c9067398F8985CC372", + "pcIn": "2069650875064483730", + "gasFee": "2285000", + "fee": 500 + }, + { + "ev": "UniversalTxOutbound", + "emitter": "0x00000000000000000000000000000000000000c1", + "sender": "0xED6bFE825b8d84A1E6f4F7c9067398F8985CC372", + "chain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "token": "0x4f1A3D22d170a2F4Bddb37845a962322e24f4e34", + "amount": "1000", + "gasToken": "0x5D525Df2bD99a6e7ec58b76aF2fd95F39874EBed", + "gasFee": "2285000", + "gasLimit": "2285", + "protocolFee": "0", + "gasPrice": "1000", + "txType": 3, + "revertRecipient": "0xED6bFE825b8d84A1E6f4F7c9067398F8985CC372", + "recipientLen": 32, + "payloadLen": 222 + } + ] + }, + "spl:subsequent": { + "hash": "0x7980032bb748889f44d9a58e4030dc1338575d03fa78da23531dcf96d6c23e57", + "status": "success", + "block": "24455695", + "from": "0x8fb1cf80a014af564bdc12e557a3e52432f4657b", + "to": "0xed6bfe825b8d84a1e6f4f7c9067398f8985cc372", + "txValue": "0", + "gasUsed": "447044", + "effectiveGasPrice": "1125000000", + "pushFeePaid": "502924500000000", + "events": [ + { + "ev": "OutboundMetered", + "emitter": "0xba32e7a1500cb34311a31127bcd40ca52c8cfd36", + "id": "0x16be7e479fcee17b79ed4ed7a6ff75c6cf954c08dad16c9a59b876be242c9ea8", + "engine": "0xf63DC0628fe1B25049FE3E3a3585Ef051CB98c1d", + "account": "0xED6bFE825b8d84A1E6f4F7c9067398F8985CC372", + "token": "0x4f1A3D22d170a2F4Bddb37845a962322e24f4e34", + "amount": "1000" + }, + { + "ev": "SwapAndBurnGas", + "emitter": "0x00000000000000000000000000000000000000c0", + "gasToken": "0x5D525Df2bD99a6e7ec58b76aF2fd95F39874EBed", + "caller": "0xED6bFE825b8d84A1E6f4F7c9067398F8985CC372", + "pcIn": "869525140506227908", + "gasFee": "960000", + "fee": 500 + }, + { + "ev": "UniversalTxOutbound", + "emitter": "0x00000000000000000000000000000000000000c1", + "sender": "0xED6bFE825b8d84A1E6f4F7c9067398F8985CC372", + "chain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "token": "0x4f1A3D22d170a2F4Bddb37845a962322e24f4e34", + "amount": "1000", + "gasToken": "0x5D525Df2bD99a6e7ec58b76aF2fd95F39874EBed", + "gasFee": "960000", + "gasLimit": "960", + "protocolFee": "0", + "gasPrice": "1000", + "txType": 3, + "revertRecipient": "0xED6bFE825b8d84A1E6f4F7c9067398F8985CC372", + "recipientLen": 32, + "payloadLen": 222 + } + ] + }, + "sepolia:first-use": { + "hash": "0xb968f71a2f8deb17a194632744e0e256b7703e229e0a0d35461751e580debce6", + "status": "success", + "block": "24455794", + "from": "0xd8285271c399597674ca4064c398b07c98d0f1f2", + "to": "0xd847ca2462405a70c32ff5776e70fe25ea7b26ca", + "txValue": "0", + "gasUsed": "397778", + "effectiveGasPrice": "1125000000", + "pushFeePaid": "447500250000000", + "events": [ + { + "ev": "OutboundMetered", + "emitter": "0xba32e7a1500cb34311a31127bcd40ca52c8cfd36", + "id": "0xe68a9fa1956e67a8763ace47d51e3d25e2dc1e9be6642f8f24f0aa256589396d", + "engine": "0xf63DC0628fe1B25049FE3E3a3585Ef051CB98c1d", + "account": "0xD847ca2462405a70c32ff5776e70fE25EA7B26ca", + "token": "0x2971824Db68229D087931155C2b8bB820B275809", + "amount": "1000000000000" + }, + { + "ev": "SwapAndBurnGas", + "emitter": "0x00000000000000000000000000000000000000c0", + "gasToken": "0x2971824Db68229D087931155C2b8bB820B275809", + "caller": "0xD847ca2462405a70c32ff5776e70fE25EA7B26ca", + "pcIn": "3218632638119703", + "gasFee": "2200032000000", + "fee": 500 + }, + { + "ev": "UniversalTxOutbound", + "emitter": "0x00000000000000000000000000000000000000c1", + "sender": "0xD847ca2462405a70c32ff5776e70fE25EA7B26ca", + "chain": "eip155:11155111", + "token": "0x2971824Db68229D087931155C2b8bB820B275809", + "amount": "1000000000000", + "gasToken": "0x2971824Db68229D087931155C2b8bB820B275809", + "gasFee": "2200032000000", + "gasLimit": "2000000", + "protocolFee": "0", + "gasPrice": "1100016", + "txType": 3, + "revertRecipient": "0xD847ca2462405a70c32ff5776e70fE25EA7B26ca", + "recipientLen": 0, + "payloadLen": 260 + } + ] + }, + "sepolia:subsequent": { + "hash": "0xc3b021815bcfd26269ddcdbaed813aa91fb0c03a36dbf2cbc5678f84b157c7cf", + "status": "success", + "block": "24455824", + "from": "0xd8285271c399597674ca4064c398b07c98d0f1f2", + "to": "0xd847ca2462405a70c32ff5776e70fe25ea7b26ca", + "txValue": "0", + "gasUsed": "377183", + "effectiveGasPrice": "1125000000", + "pushFeePaid": "424330875000000", + "events": [ + { + "ev": "OutboundMetered", + "emitter": "0xba32e7a1500cb34311a31127bcd40ca52c8cfd36", + "id": "0xe68a9fa1956e67a8763ace47d51e3d25e2dc1e9be6642f8f24f0aa256589396d", + "engine": "0xf63DC0628fe1B25049FE3E3a3585Ef051CB98c1d", + "account": "0xD847ca2462405a70c32ff5776e70fE25EA7B26ca", + "token": "0x2971824Db68229D087931155C2b8bB820B275809", + "amount": "1000000000000" + }, + { + "ev": "SwapAndBurnGas", + "emitter": "0x00000000000000000000000000000000000000c0", + "gasToken": "0x2971824Db68229D087931155C2b8bB820B275809", + "caller": "0xD847ca2462405a70c32ff5776e70fE25EA7B26ca", + "pcIn": "804658178813013", + "gasFee": "550008000000", + "fee": 500 + }, + { + "ev": "UniversalTxOutbound", + "emitter": "0x00000000000000000000000000000000000000c1", + "sender": "0xD847ca2462405a70c32ff5776e70fE25EA7B26ca", + "chain": "eip155:11155111", + "token": "0x2971824Db68229D087931155C2b8bB820B275809", + "amount": "1000000000000", + "gasToken": "0x2971824Db68229D087931155C2b8bB820B275809", + "gasFee": "550008000000", + "gasLimit": "500000", + "protocolFee": "0", + "gasPrice": "1100016", + "txType": 3, + "revertRecipient": "0xD847ca2462405a70c32ff5776e70fE25EA7B26ca", + "recipientLen": 0, + "payloadLen": 260 + } + ] + }, + "base:first-use": { + "hash": "0xb9fd4a64a2fd9b68193ac3aef1177f054dc591cfc3917968d3cfc9ee1fc35153", + "status": "success", + "block": "24455871", + "from": "0x79cf3b5cb2a58e008c583cc80a51cf35d4dbda37", + "to": "0xb07a90329a3ef6b20ac80a458069a7d8dae93d58", + "txValue": "0", + "gasUsed": "396773", + "effectiveGasPrice": "1125000000", + "pushFeePaid": "446369625000000", + "events": [ + { + "ev": "OutboundMetered", + "emitter": "0xba32e7a1500cb34311a31127bcd40ca52c8cfd36", + "id": "0x1a2f8bc59cedf775f64c3b665c2177118a1d3efbba08191d61fe4ec84b00b71b", + "engine": "0xf63DC0628fe1B25049FE3E3a3585Ef051CB98c1d", + "account": "0xB07a90329A3Ef6B20aC80a458069a7D8daE93D58", + "token": "0xc7007af2B24D4eb963fc9633B0c66e1d2D90Fc21", + "amount": "1000000000000" + }, + { + "ev": "SwapAndBurnGas", + "emitter": "0x00000000000000000000000000000000000000c0", + "gasToken": "0xc7007af2B24D4eb963fc9633B0c66e1d2D90Fc21", + "caller": "0xB07a90329A3Ef6B20aC80a458069a7D8daE93D58", + "pcIn": "591543820894050827", + "gasFee": "13200000000000", + "fee": 500 + }, + { + "ev": "UniversalTxOutbound", + "emitter": "0x00000000000000000000000000000000000000c1", + "sender": "0xB07a90329A3Ef6B20aC80a458069a7D8daE93D58", + "chain": "eip155:84532", + "token": "0xc7007af2B24D4eb963fc9633B0c66e1d2D90Fc21", + "amount": "1000000000000", + "gasToken": "0xc7007af2B24D4eb963fc9633B0c66e1d2D90Fc21", + "gasFee": "13200000000000", + "gasLimit": "2000000", + "protocolFee": "0", + "gasPrice": "6600000", + "txType": 3, + "revertRecipient": "0xB07a90329A3Ef6B20aC80a458069a7D8daE93D58", + "recipientLen": 0, + "payloadLen": 260 + } + ] + }, + "base:subsequent": { + "hash": "0xc0aa504633d7e0fe66e4aa2abaf994e4b8ff09c992b8712e3a8879fe33c9026d", + "status": "success", + "block": "24455903", + "from": "0x79cf3b5cb2a58e008c583cc80a51cf35d4dbda37", + "to": "0xb07a90329a3ef6b20ac80a458069a7d8dae93d58", + "txValue": "0", + "gasUsed": "376379", + "effectiveGasPrice": "1125000000", + "pushFeePaid": "423426375000000", + "events": [ + { + "ev": "OutboundMetered", + "emitter": "0xba32e7a1500cb34311a31127bcd40ca52c8cfd36", + "id": "0x1a2f8bc59cedf775f64c3b665c2177118a1d3efbba08191d61fe4ec84b00b71b", + "engine": "0xf63DC0628fe1B25049FE3E3a3585Ef051CB98c1d", + "account": "0xB07a90329A3Ef6B20aC80a458069a7D8daE93D58", + "token": "0xc7007af2B24D4eb963fc9633B0c66e1d2D90Fc21", + "amount": "1000000000000" + }, + { + "ev": "SwapAndBurnGas", + "emitter": "0x00000000000000000000000000000000000000c0", + "gasToken": "0xc7007af2B24D4eb963fc9633B0c66e1d2D90Fc21", + "caller": "0xB07a90329A3Ef6B20aC80a458069a7D8daE93D58", + "pcIn": "147885915640293260", + "gasFee": "3300000000000", + "fee": 500 + }, + { + "ev": "UniversalTxOutbound", + "emitter": "0x00000000000000000000000000000000000000c1", + "sender": "0xB07a90329A3Ef6B20aC80a458069a7D8daE93D58", + "chain": "eip155:84532", + "token": "0xc7007af2B24D4eb963fc9633B0c66e1d2D90Fc21", + "amount": "1000000000000", + "gasToken": "0xc7007af2B24D4eb963fc9633B0c66e1d2D90Fc21", + "gasFee": "3300000000000", + "gasLimit": "500000", + "protocolFee": "0", + "gasPrice": "6600000", + "txType": 3, + "revertRecipient": "0xB07a90329A3Ef6B20aC80a458069a7D8daE93D58", + "recipientLen": 0, + "payloadLen": 260 + } + ] + }, + "arb:first-use": { + "hash": "0x21ce19a3780fee8cbcc006b3197163166402da30557ef1eff8556c97d793846c", + "status": "success", + "block": "24455949", + "from": "0x664f2276733474e942f3f155be2da18a63fb0491", + "to": "0x3130f7f8b10c94a54ec012a4d0e6dac963f200eb", + "txValue": "0", + "gasUsed": "404486", + "effectiveGasPrice": "1125000000", + "pushFeePaid": "455046750000000", + "events": [ + { + "ev": "OutboundMetered", + "emitter": "0xba32e7a1500cb34311a31127bcd40ca52c8cfd36", + "id": "0x788f414e3cfd301a942889ae2c55dd725fbd00fb2b69cafeea0ff94d62cf81e1", + "engine": "0xf63DC0628fe1B25049FE3E3a3585Ef051CB98c1d", + "account": "0x3130f7F8b10C94A54eC012A4d0e6DAc963f200eb", + "token": "0xc0a821a1AfEd1322c5e15f1F4586C0B8cE65400e", + "amount": "1000000000000" + }, + { + "ev": "SwapAndBurnGas", + "emitter": "0x00000000000000000000000000000000000000c0", + "gasToken": "0xc0a821a1AfEd1322c5e15f1F4586C0B8cE65400e", + "caller": "0x3130f7F8b10C94A54eC012A4d0e6DAc963f200eb", + "pcIn": "1929669492247985112", + "gasFee": "45183600000000", + "fee": 3000 + }, + { + "ev": "UniversalTxOutbound", + "emitter": "0x00000000000000000000000000000000000000c1", + "sender": "0x3130f7F8b10C94A54eC012A4d0e6DAc963f200eb", + "chain": "eip155:421614", + "token": "0xc0a821a1AfEd1322c5e15f1F4586C0B8cE65400e", + "amount": "1000000000000", + "gasToken": "0xc0a821a1AfEd1322c5e15f1F4586C0B8cE65400e", + "gasFee": "45183600000000", + "gasLimit": "2000000", + "protocolFee": "0", + "gasPrice": "22591800", + "txType": 3, + "revertRecipient": "0x3130f7F8b10C94A54eC012A4d0e6DAc963f200eb", + "recipientLen": 0, + "payloadLen": 260 + } + ] + }, + "arb:subsequent": { + "hash": "0xba1c063ab2e261f0d1af0833975fd1344daa390ae80336c45a45d49759ebecad", + "status": "success", + "block": "24455976", + "from": "0x664f2276733474e942f3f155be2da18a63fb0491", + "to": "0x3130f7f8b10c94a54ec012a4d0e6dac963f200eb", + "txValue": "0", + "gasUsed": "390806", + "effectiveGasPrice": "1125000000", + "pushFeePaid": "439656750000000", + "events": [ + { + "ev": "OutboundMetered", + "emitter": "0xba32e7a1500cb34311a31127bcd40ca52c8cfd36", + "id": "0x788f414e3cfd301a942889ae2c55dd725fbd00fb2b69cafeea0ff94d62cf81e1", + "engine": "0xf63DC0628fe1B25049FE3E3a3585Ef051CB98c1d", + "account": "0x3130f7F8b10C94A54eC012A4d0e6DAc963f200eb", + "token": "0xc0a821a1AfEd1322c5e15f1F4586C0B8cE65400e", + "amount": "1000000000000" + }, + { + "ev": "SwapAndBurnGas", + "emitter": "0x00000000000000000000000000000000000000c0", + "gasToken": "0xc0a821a1AfEd1322c5e15f1F4586C0B8cE65400e", + "caller": "0x3130f7F8b10C94A54eC012A4d0e6DAc963f200eb", + "pcIn": "481993810973352572", + "gasFee": "11286000000000", + "fee": 3000 + }, + { + "ev": "UniversalTxOutbound", + "emitter": "0x00000000000000000000000000000000000000c1", + "sender": "0x3130f7F8b10C94A54eC012A4d0e6DAc963f200eb", + "chain": "eip155:421614", + "token": "0xc0a821a1AfEd1322c5e15f1F4586C0B8cE65400e", + "amount": "1000000000000", + "gasToken": "0xc0a821a1AfEd1322c5e15f1F4586C0B8cE65400e", + "gasFee": "11286000000000", + "gasLimit": "500000", + "protocolFee": "0", + "gasPrice": "22572000", + "txType": 3, + "revertRecipient": "0x3130f7F8b10C94A54eC012A4d0e6DAc963f200eb", + "recipientLen": 0, + "payloadLen": 260 + } + ] + }, + "bnb:first-use": { + "hash": "0x6e4bf8a92eb569fb4aa34a5d5eab4799ab86f6aa40fe405d59cba6498c669f7d", + "status": "success", + "block": "24456018", + "from": "0x74a85bd8928090920463ce05aba48985b3875700", + "to": "0x0140403283bb76c1890501067754d1c376189b5d", + "txValue": "0", + "gasUsed": "404574", + "effectiveGasPrice": "1125000000", + "pushFeePaid": "455145750000000", + "events": [ + { + "ev": "OutboundMetered", + "emitter": "0xba32e7a1500cb34311a31127bcd40ca52c8cfd36", + "id": "0x45e274612b5b71b11056991709d8d5ac0b3d5a6c415dfa0f9bbcd5fc7122778b", + "engine": "0xf63DC0628fe1B25049FE3E3a3585Ef051CB98c1d", + "account": "0x0140403283bB76C1890501067754d1c376189b5D", + "token": "0x7a9082dA308f3fa005beA7dB0d203b3b86664E36", + "amount": "1000000000000" + }, + { + "ev": "SwapAndBurnGas", + "emitter": "0x00000000000000000000000000000000000000c0", + "gasToken": "0x7a9082dA308f3fa005beA7dB0d203b3b86664E36", + "caller": "0x0140403283bB76C1890501067754d1c376189b5D", + "pcIn": "2365215882563406640", + "gasFee": "220000000000000", + "fee": 500 + }, + { + "ev": "UniversalTxOutbound", + "emitter": "0x00000000000000000000000000000000000000c1", + "sender": "0x0140403283bB76C1890501067754d1c376189b5D", + "chain": "eip155:97", + "token": "0x7a9082dA308f3fa005beA7dB0d203b3b86664E36", + "amount": "1000000000000", + "gasToken": "0x7a9082dA308f3fa005beA7dB0d203b3b86664E36", + "gasFee": "220000000000000", + "gasLimit": "2000000", + "protocolFee": "0", + "gasPrice": "110000000", + "txType": 3, + "revertRecipient": "0x0140403283bB76C1890501067754d1c376189b5D", + "recipientLen": 0, + "payloadLen": 260 + } + ] + }, + "bnb:subsequent": { + "hash": "0x82f343dcd100715d5693d68fbdcccdaf1467c3c5626391501d1f7b579d279047", + "status": "success", + "block": "24456042", + "from": "0x74a85bd8928090920463ce05aba48985b3875700", + "to": "0x0140403283bb76c1890501067754d1c376189b5d", + "txValue": "0", + "gasUsed": "390894", + "effectiveGasPrice": "1125000000", + "pushFeePaid": "439755750000000", + "events": [ + { + "ev": "OutboundMetered", + "emitter": "0xba32e7a1500cb34311a31127bcd40ca52c8cfd36", + "id": "0x45e274612b5b71b11056991709d8d5ac0b3d5a6c415dfa0f9bbcd5fc7122778b", + "engine": "0xf63DC0628fe1B25049FE3E3a3585Ef051CB98c1d", + "account": "0x0140403283bB76C1890501067754d1c376189b5D", + "token": "0x7a9082dA308f3fa005beA7dB0d203b3b86664E36", + "amount": "1000000000000" + }, + { + "ev": "SwapAndBurnGas", + "emitter": "0x00000000000000000000000000000000000000c0", + "gasToken": "0x7a9082dA308f3fa005beA7dB0d203b3b86664E36", + "caller": "0x0140403283bB76C1890501067754d1c376189b5D", + "pcIn": "591302375958115445", + "gasFee": "55000000000000", + "fee": 500 + }, + { + "ev": "UniversalTxOutbound", + "emitter": "0x00000000000000000000000000000000000000c1", + "sender": "0x0140403283bB76C1890501067754d1c376189b5D", + "chain": "eip155:97", + "token": "0x7a9082dA308f3fa005beA7dB0d203b3b86664E36", + "amount": "1000000000000", + "gasToken": "0x7a9082dA308f3fa005beA7dB0d203b3b86664E36", + "gasFee": "55000000000000", + "gasLimit": "500000", + "protocolFee": "0", + "gasPrice": "110000000", + "txType": 3, + "revertRecipient": "0x0140403283bB76C1890501067754d1c376189b5D", + "recipientLen": 0, + "payloadLen": 260 + } + ] + } + }, + "wpc": "0xE17DD2E0509f99E9ee9469Cf6634048Ec5a3ADe9", + "chains": { + "eip155:11155111": { + "gasPrc20": "0x2971824Db68229D087931155C2b8bB820B275809", + "registeredGasToken": "0x2971824Db68229D087931155C2b8bB820B275809", + "baseGasLimit": "500000", + "gasPrice": "1100018", + "defaultFeeTier": 500, + "protocolFee": "0", + "quotes": [ + { + "inputGasLimit": "0", + "gasFee": "550009000000", + "protocolFee": "0", + "gasPrice": "1100018", + "gasLimitUsed": "500000", + "swapPcInRequired": "804590193808946" + }, + { + "inputGasLimit": "500000", + "gasFee": "550009000000", + "protocolFee": "0", + "gasPrice": "1100018", + "gasLimitUsed": "500000", + "swapPcInRequired": "804590193808946" + }, + { + "inputGasLimit": "2000000", + "gasFee": "2200036000000", + "protocolFee": "0", + "gasPrice": "1100018", + "gasLimitUsed": "2000000", + "swapPcInRequired": "3218360887313289" + } + ] + }, + "eip155:84532": { + "gasPrc20": "0xc7007af2B24D4eb963fc9633B0c66e1d2D90Fc21", + "registeredGasToken": "0xc7007af2B24D4eb963fc9633B0c66e1d2D90Fc21", + "baseGasLimit": "500000", + "gasPrice": "6600000", + "defaultFeeTier": 500, + "protocolFee": "0", + "quotes": [ + { + "inputGasLimit": "0", + "gasFee": "3300000000000", + "protocolFee": "0", + "gasPrice": "6600000", + "gasLimitUsed": "500000", + "swapPcInRequired": "147885927165951477" + }, + { + "inputGasLimit": "500000", + "gasFee": "3300000000000", + "protocolFee": "0", + "gasPrice": "6600000", + "gasLimitUsed": "500000", + "swapPcInRequired": "147885927165951477" + }, + { + "inputGasLimit": "2000000", + "gasFee": "13200000000000", + "protocolFee": "0", + "gasPrice": "6600000", + "gasLimitUsed": "2000000", + "swapPcInRequired": "591543988922286942" + } + ] + }, + "eip155:421614": { + "gasPrc20": "0xc0a821a1AfEd1322c5e15f1F4586C0B8cE65400e", + "registeredGasToken": "0xc0a821a1AfEd1322c5e15f1F4586C0B8cE65400e", + "baseGasLimit": "500000", + "gasPrice": "22193600", + "defaultFeeTier": 3000, + "protocolFee": "0", + "quotes": [ + { + "inputGasLimit": "0", + "gasFee": "11096800000000", + "protocolFee": "0", + "gasPrice": "22193600", + "gasLimitUsed": "500000", + "swapPcInRequired": "473913876146294352" + }, + { + "inputGasLimit": "500000", + "gasFee": "11096800000000", + "protocolFee": "0", + "gasPrice": "22193600", + "gasLimitUsed": "500000", + "swapPcInRequired": "473913876146294352" + }, + { + "inputGasLimit": "2000000", + "gasFee": "44387200000000", + "protocolFee": "0", + "gasPrice": "22193600", + "gasLimitUsed": "2000000", + "swapPcInRequired": "1895660749783132294" + } + ] + }, + "eip155:97": { + "gasPrc20": "0x7a9082dA308f3fa005beA7dB0d203b3b86664E36", + "registeredGasToken": "0x7a9082dA308f3fa005beA7dB0d203b3b86664E36", + "baseGasLimit": "500000", + "gasPrice": "1100000000", + "defaultFeeTier": 500, + "protocolFee": "0", + "quotes": [ + { + "inputGasLimit": "0", + "gasFee": "550000000000000", + "protocolFee": "0", + "gasPrice": "1100000000", + "gasLimitUsed": "500000", + "swapPcInRequired": "5913121783041323339" + }, + { + "inputGasLimit": "500000", + "gasFee": "550000000000000", + "protocolFee": "0", + "gasPrice": "1100000000", + "gasLimitUsed": "500000", + "swapPcInRequired": "5913121783041323339" + }, + { + "inputGasLimit": "2000000", + "gasFee": "2200000000000000", + "protocolFee": "0", + "gasPrice": "1100000000", + "gasLimitUsed": "2000000", + "swapPcInRequired": "23653617545786043528" + } + ] + }, + "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1": { + "gasPrc20": "0x5D525Df2bD99a6e7ec58b76aF2fd95F39874EBed", + "registeredGasToken": "0x5D525Df2bD99a6e7ec58b76aF2fd95F39874EBed", + "baseGasLimit": "960", + "gasPrice": "1000", + "defaultFeeTier": 500, + "protocolFee": "0", + "quotes": [ + { + "inputGasLimit": "0", + "gasFee": "960000", + "protocolFee": "0", + "gasPrice": "1000", + "gasLimitUsed": "960", + "swapPcInRequired": "869525161720981845" + }, + { + "inputGasLimit": "960", + "gasFee": "960000", + "protocolFee": "0", + "gasPrice": "1000", + "gasLimitUsed": "960", + "swapPcInRequired": "869525161720981845" + }, + { + "inputGasLimit": "1052", + "gasFee": "1052000", + "protocolFee": "0", + "gasPrice": "1000", + "gasLimitUsed": "1052", + "swapPcInRequired": "952854657922375424" + }, + { + "inputGasLimit": "2285", + "gasFee": "2285000", + "protocolFee": "0", + "gasPrice": "1000", + "gasLimitUsed": "2285", + "swapPcInRequired": "2069651084035473630" + }, + { + "inputGasLimit": "1000000", + "gasFee": "1000000000", + "protocolFee": "0", + "gasPrice": "1000", + "gasLimitUsed": "1000000", + "swapPcInRequired": "905771237038391933369" + } + ] + } + }, + "pcUsd": { + "eip155:11155111": { + "stable": "0x0f97A213207703923F5f0C613C9827f7C9A0f96B", + "fee": 500, + "oneWpcInStableRaw": "232639" + }, + "eip155:421614": { + "stable": "0xFE6E9DF2BbC9ce05D98b83B1365df6DcA9951891", + "fee": 500, + "oneWpcInStableRaw": "98797" + }, + "eip155:84532": { + "stable": "0x148823809B853e1db187BC09A9ac909BC42F971a", + "fee": 500, + "oneWpcInStableRaw": "99308" + }, + "eip155:97": { + "stable": "0x731aF1Da5365259d27528557EE4aFBA4baC90ef2", + "fee": 500, + "oneWpcInStableRaw": "103138" + }, + "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1": { + "stable": "0x4f1A3D22d170a2F4Bddb37845a962322e24f4e34", + "fee": 500, + "oneWpcInStableRaw": "91009" + } + }, + "prc20": { + "pETH": { + "address": "0x2971824Db68229D087931155C2b8bB820B275809", + "namespace": "eip155:11155111", + "decimals": 18, + "symbol": "pETH", + "totalSupply": "1202118573863805311917314", + "isSupportedError": "Execution reverted for an unknown reason.", + "sourceTokenRawLen": 32, + "sourceTokenWord": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + "pETH_ARB": { + "address": "0xc0a821a1AfEd1322c5e15f1F4586C0B8cE65400e", + "namespace": "eip155:421614", + "decimals": 18, + "symbol": "pETH.arb", + "totalSupply": "1200026561709007795673623", + "isSupportedError": "Execution reverted for an unknown reason.", + "sourceTokenRawLen": 128, + "sourceTokenString": "0x0000000000000000000000000000000000000000" + }, + "pETH_BASE": { + "address": "0xc7007af2B24D4eb963fc9633B0c66e1d2D90Fc21", + "namespace": "eip155:84532", + "decimals": 18, + "symbol": "pETH.base", + "totalSupply": "1200042897987270851496065", + "isSupportedError": "Execution reverted for an unknown reason.", + "sourceTokenRawLen": 128, + "sourceTokenString": "0x0000000000000000000000000000000000000000" + }, + "pBNB": { + "address": "0x7a9082dA308f3fa005beA7dB0d203b3b86664E36", + "namespace": "eip155:97", + "decimals": 18, + "symbol": "pBNB", + "totalSupply": "1200307744919829858760483", + "isSupportedError": "Execution reverted for an unknown reason.", + "sourceTokenRawLen": 128, + "sourceTokenString": "0x0000000000000000000000000000000000000000" + }, + "pSOL": { + "address": "0x5D525Df2bD99a6e7ec58b76aF2fd95F39874EBed", + "namespace": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "decimals": 9, + "symbol": "pSOL", + "totalSupply": "3001201403240700062", + "isSupportedError": "Execution reverted for an unknown reason.", + "sourceTokenRawLen": 32, + "sourceTokenWord": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + "USDT_ETH": { + "address": "0x0f97A213207703923F5f0C613C9827f7C9A0f96B", + "namespace": "eip155:11155111", + "decimals": 6, + "symbol": "USDT.eth", + "totalSupply": "6856359154143", + "isSupportedError": "Execution reverted for an unknown reason.", + "sourceTokenRawLen": 128, + "sourceTokenString": "0xC4230aEaFcF6b8B49a7b4e53886420f00ff71876" + }, + "USDC_ETH": { + "address": "0x7A58048036206bB898008b5bBDA85697DB1e5d66", + "namespace": "eip155:11155111", + "decimals": 6, + "symbol": "USDC.eth", + "totalSupply": "6912480294955", + "isSupportedError": "Execution reverted for an unknown reason.", + "sourceTokenRawLen": 128, + "sourceTokenString": "0x97F477B7f970D47a87B42869ceeace218106152a" + }, + "USDT_ARB": { + "address": "0xFE6E9DF2BbC9ce05D98b83B1365df6DcA9951891", + "namespace": "eip155:421614", + "decimals": 6, + "symbol": "USDT.arb", + "totalSupply": "145063516199", + "isSupportedError": "Execution reverted for an unknown reason.", + "sourceTokenRawLen": 128, + "sourceTokenString": "0xE30928528f52CAEeB75fB07837e22d77D47e9c07" + }, + "USDC_ARB": { + "address": "0x1091cCBA2FF8d2A131AE4B35e34cf3308C48572C", + "namespace": "eip155:421614", + "decimals": 6, + "symbol": "USDC.arb", + "totalSupply": "1044684603377", + "isSupportedError": "Execution reverted for an unknown reason.", + "sourceTokenRawLen": 128, + "sourceTokenString": "0x5dd39b0b3610F666F631a6506b7713EF83e1Ac5C" + }, + "USDT_SOL": { + "address": "0x4f1A3D22d170a2F4Bddb37845a962322e24f4e34", + "namespace": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "decimals": 6, + "symbol": "USDT.sol", + "totalSupply": "2133492520683", + "isSupportedError": "Execution reverted for an unknown reason.", + "sourceTokenRawLen": 32, + "sourceTokenWord": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + "USDC_SOL": { + "address": "0x04B8F634ABC7C879763F623e0f0550a4b5c4426F", + "namespace": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "decimals": 6, + "symbol": "USDC.sol", + "totalSupply": "1205737049651", + "isSupportedError": "Execution reverted for an unknown reason.", + "sourceTokenRawLen": 32, + "sourceTokenWord": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + "USDT_BSC": { + "address": "0x731aF1Da5365259d27528557EE4aFBA4baC90ef2", + "namespace": "eip155:97", + "decimals": 6, + "symbol": "USDT.bnb", + "totalSupply": "119017594761", + "isSupportedError": "Execution reverted for an unknown reason.", + "sourceTokenRawLen": 128, + "sourceTokenString": "0xE935d9c9C24D02E61186c640cc01d713C876d40F" + }, + "USDC_BSC": { + "address": "0x120EBf25Dad7D6a09Ad2316f23f9Be95DBb90639", + "namespace": "eip155:97", + "decimals": 6, + "symbol": "USDC.bnb", + "totalSupply": "116876047736", + "isSupportedError": "Execution reverted for an unknown reason.", + "sourceTokenRawLen": 128, + "sourceTokenString": "0xA8802F96cAd0d45343d9bc660B6f7d80050A660b" + }, + "USDT_BASE": { + "address": "0x148823809B853e1db187BC09A9ac909BC42F971a", + "namespace": "eip155:84532", + "decimals": 6, + "symbol": "USDT.base", + "totalSupply": "150022201753", + "isSupportedError": "Execution reverted for an unknown reason.", + "sourceTokenRawLen": 128, + "sourceTokenString": "0x4D7646B9eE3D68F4b0F135B5cbc66B00819F6b61" + }, + "USDC_BASE": { + "address": "0xD7C6cA1e2c0CE260BE0c0AD39C1540de460e3Be1", + "namespace": "eip155:84532", + "decimals": 6, + "symbol": "USDC.base", + "totalSupply": "1043687802312", + "isSupportedError": "Execution reverted for an unknown reason.", + "sourceTokenRawLen": 128, + "sourceTokenString": "0x5c3504F0E3bA28FDc1F74234fE936518276AaBB8" + }, + "WETH_ETH": { + "address": "0x0d0dF7E8807430A81104EA84d926139816eC7586", + "namespace": "eip155:11155111", + "decimals": 18, + "symbol": "WETH", + "totalSupply": "1200000017895253217961350", + "isSupportedError": "Execution reverted for an unknown reason.", + "sourceTokenRawLen": 32, + "sourceTokenWord": "0x000000000000000000000000fff9976782d46cc05630d1f6ebab18b2324d6b14" + }, + "stETH_ETH": { + "address": "0xaf89E805949c628ebde3262e91dc4ab9eA12668E", + "namespace": "eip155:11155111", + "decimals": 18, + "symbol": "stETH.eth", + "totalSupply": "1200000000000000000000000", + "isSupportedError": "Execution reverted for an unknown reason.", + "sourceTokenRawLen": 32, + "sourceTokenWord": "0x0000000000000000000000003e3fe7dbc6b4c189e7128855dd526361c49b40af" + }, + "DAI_SOL": { + "address": "0x5861f56A556c990358cc9cccd8B5baa3767982A8", + "namespace": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "decimals": 6, + "symbol": "DAI.sol", + "totalSupply": "2000000000000", + "isSupportedError": "Execution reverted for an unknown reason.", + "sourceTokenRawLen": 32, + "sourceTokenWord": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "coreEvents": { + "supported": [], + "gasTokens": [], + "error": "Missing or invalid parameters.\nDouble check you have provided the correct parameters." + }, + "unregistered": [], + "blockAfter": "24457170" +} \ No newline at end of file diff --git a/plan/agw/independent-review-creation-flow-2026-10-20/data/sdk-quotes.json b/plan/agw/independent-review-creation-flow-2026-10-20/data/sdk-quotes.json new file mode 100644 index 00000000..2f1cbd2f --- /dev/null +++ b/plan/agw/independent-review-creation-flow-2026-10-20/data/sdk-quotes.json @@ -0,0 +1,369 @@ +{ + "at": "2026-10-20T16:37:15.813Z", + "readOnly": true, + "origins": { + "pushNative": { + "signerChain": "eip155:42101", + "pushBlock": "24457436", + "cases": [ + { + "chain": "eip155:11155111", + "inputGasLimit": "2000000", + "protocolFee": "0", + "nativeValueForGas": "10000000000000000000", + "gasLimitUsed": "2000000", + "attachedPC": 10 + }, + { + "chain": "eip155:11155111", + "inputGasLimit": "0", + "protocolFee": "0", + "nativeValueForGas": "10000000000000000000", + "gasLimitUsed": "500000", + "attachedPC": 10 + }, + { + "chain": "eip155:84532", + "inputGasLimit": "2000000", + "protocolFee": "0", + "nativeValueForGas": "10000000000000000000", + "gasLimitUsed": "2000000", + "attachedPC": 10 + }, + { + "chain": "eip155:84532", + "inputGasLimit": "0", + "protocolFee": "0", + "nativeValueForGas": "10000000000000000000", + "gasLimitUsed": "500000", + "attachedPC": 10 + }, + { + "chain": "eip155:421614", + "inputGasLimit": "2000000", + "protocolFee": "0", + "nativeValueForGas": "10000000000000000000", + "gasLimitUsed": "2000000", + "attachedPC": 10 + }, + { + "chain": "eip155:421614", + "inputGasLimit": "0", + "protocolFee": "0", + "nativeValueForGas": "10000000000000000000", + "gasLimitUsed": "500000", + "attachedPC": 10 + }, + { + "chain": "eip155:97", + "inputGasLimit": "2000000", + "protocolFee": "0", + "nativeValueForGas": "10000000000000000000", + "gasLimitUsed": "2000000", + "attachedPC": 10 + }, + { + "chain": "eip155:97", + "inputGasLimit": "0", + "protocolFee": "0", + "nativeValueForGas": "10000000000000000000", + "gasLimitUsed": "500000", + "attachedPC": 10 + }, + { + "chain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "label": "native-sol omitted", + "inputGasLimit": "0", + "protocolFee": "0", + "nativeValueForGas": "10000000000000000000", + "gasLimitUsed": "1052", + "attachedPC": 10 + }, + { + "chain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "label": "spl fresh CEA ATA omitted", + "inputGasLimit": "0", + "protocolFee": "0", + "nativeValueForGas": "10000000000000000000", + "gasLimitUsed": "2285", + "attachedPC": 10 + }, + { + "chain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "label": "spl existing CEA ATA omitted", + "inputGasLimit": "0", + "protocolFee": "0", + "nativeValueForGas": "10000000000000000000", + "gasLimitUsed": "960", + "attachedPC": 10 + }, + { + "chain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "label": "spl existing explicit 5000", + "inputGasLimit": "5000", + "protocolFee": "0", + "nativeValueForGas": "10000000000000000000", + "gasLimitUsed": "5000", + "attachedPC": 10 + }, + { + "chain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "label": "legacy 1,000,000", + "inputGasLimit": "1000000", + "protocolFee": "0", + "nativeValueForGas": "100000000000000000000", + "gasLimitUsed": "1000000", + "attachedPC": 100 + }, + { + "chain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "label": "explicit 500 (< base 960)", + "inputGasLimit": "500", + "error": "The contract function \"getOutboundTxGasAndFees\" reverted." + } + ] + }, + "sepoliaUEA": { + "signerChain": "eip155:11155111", + "pushBlock": "24457442", + "cases": [ + { + "chain": "eip155:11155111", + "inputGasLimit": "2000000", + "protocolFee": "0", + "nativeValueForGas": "4298505409669058069", + "gasLimitUsed": "2000000", + "attachedPC": 4.298505409669058 + }, + { + "chain": "eip155:11155111", + "inputGasLimit": "0", + "protocolFee": "0", + "nativeValueForGas": "4298505409669058069", + "gasLimitUsed": "500000", + "attachedPC": 4.298505409669058 + }, + { + "chain": "eip155:84532", + "inputGasLimit": "2000000", + "protocolFee": "0", + "nativeValueForGas": "4298505409669058069", + "gasLimitUsed": "2000000", + "attachedPC": 4.298505409669058 + }, + { + "chain": "eip155:84532", + "inputGasLimit": "0", + "protocolFee": "0", + "nativeValueForGas": "4298505409669058069", + "gasLimitUsed": "500000", + "attachedPC": 4.298505409669058 + }, + { + "chain": "eip155:421614", + "inputGasLimit": "2000000", + "protocolFee": "0", + "nativeValueForGas": "4298505409669058069", + "gasLimitUsed": "2000000", + "attachedPC": 4.298505409669058 + }, + { + "chain": "eip155:421614", + "inputGasLimit": "0", + "protocolFee": "0", + "nativeValueForGas": "4298505409669058069", + "gasLimitUsed": "500000", + "attachedPC": 4.298505409669058 + }, + { + "chain": "eip155:97", + "inputGasLimit": "2000000", + "protocolFee": "0", + "nativeValueForGas": "22998723343893328290", + "gasLimitUsed": "2000000", + "attachedPC": 22.998723343893328 + }, + { + "chain": "eip155:97", + "inputGasLimit": "0", + "protocolFee": "0", + "nativeValueForGas": "5749680835973332073", + "gasLimitUsed": "500000", + "attachedPC": 5.749680835973332 + }, + { + "chain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "label": "native-sol omitted", + "inputGasLimit": "0", + "protocolFee": "0", + "nativeValueForGas": "4298505409669058069", + "gasLimitUsed": "1052", + "attachedPC": 4.298505409669058 + }, + { + "chain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "label": "spl fresh CEA ATA omitted", + "inputGasLimit": "0", + "protocolFee": "0", + "nativeValueForGas": "4298505409669058069", + "gasLimitUsed": "2285", + "attachedPC": 4.298505409669058 + }, + { + "chain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "label": "spl existing CEA ATA omitted", + "inputGasLimit": "0", + "protocolFee": "0", + "nativeValueForGas": "4298505409669058069", + "gasLimitUsed": "960", + "attachedPC": 4.298505409669058 + }, + { + "chain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "label": "spl existing explicit 5000", + "inputGasLimit": "5000", + "protocolFee": "0", + "nativeValueForGas": "4298505409669058069", + "gasLimitUsed": "5000", + "attachedPC": 4.298505409669058 + }, + { + "chain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "label": "legacy 1,000,000", + "inputGasLimit": "1000000", + "protocolFee": "0", + "nativeValueForGas": "42985054096690580686", + "gasLimitUsed": "1000000", + "attachedPC": 42.985054096690575 + }, + { + "chain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "label": "explicit 500 (< base 960)", + "inputGasLimit": "500", + "error": "The contract function \"getOutboundTxGasAndFees\" reverted." + } + ] + }, + "solanaUEA": { + "signerChain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "pushBlock": "24457448", + "cases": [ + { + "chain": "eip155:11155111", + "inputGasLimit": "2000000", + "protocolFee": "0", + "nativeValueForGas": "10987924271225922711", + "gasLimitUsed": "2000000", + "attachedPC": 10.987924271225923 + }, + { + "chain": "eip155:11155111", + "inputGasLimit": "0", + "protocolFee": "0", + "nativeValueForGas": "10987924271225922711", + "gasLimitUsed": "500000", + "attachedPC": 10.987924271225923 + }, + { + "chain": "eip155:84532", + "inputGasLimit": "2000000", + "protocolFee": "0", + "nativeValueForGas": "10987924271225922711", + "gasLimitUsed": "2000000", + "attachedPC": 10.987924271225923 + }, + { + "chain": "eip155:84532", + "inputGasLimit": "0", + "protocolFee": "0", + "nativeValueForGas": "10987924271225922711", + "gasLimitUsed": "500000", + "attachedPC": 10.987924271225923 + }, + { + "chain": "eip155:421614", + "inputGasLimit": "2000000", + "protocolFee": "0", + "nativeValueForGas": "10987924271225922711", + "gasLimitUsed": "2000000", + "attachedPC": 10.987924271225923 + }, + { + "chain": "eip155:421614", + "inputGasLimit": "0", + "protocolFee": "0", + "nativeValueForGas": "10987924271225922711", + "gasLimitUsed": "500000", + "attachedPC": 10.987924271225923 + }, + { + "chain": "eip155:97", + "inputGasLimit": "2000000", + "protocolFee": "0", + "nativeValueForGas": "58789790020767176873", + "gasLimitUsed": "2000000", + "attachedPC": 58.78979002076718 + }, + { + "chain": "eip155:97", + "inputGasLimit": "0", + "protocolFee": "0", + "nativeValueForGas": "14697447505191794219", + "gasLimitUsed": "500000", + "attachedPC": 14.697447505191795 + }, + { + "chain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "label": "native-sol omitted", + "inputGasLimit": "0", + "protocolFee": "0", + "nativeValueForGas": "10987924271225922711", + "gasLimitUsed": "1052", + "attachedPC": 10.987924271225923 + }, + { + "chain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "label": "spl fresh CEA ATA omitted", + "inputGasLimit": "0", + "protocolFee": "0", + "nativeValueForGas": "10987924271225922711", + "gasLimitUsed": "2285", + "attachedPC": 10.987924271225923 + }, + { + "chain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "label": "spl existing CEA ATA omitted", + "inputGasLimit": "0", + "protocolFee": "0", + "nativeValueForGas": "10987924271225922711", + "gasLimitUsed": "960", + "attachedPC": 10.987924271225923 + }, + { + "chain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "label": "spl existing explicit 5000", + "inputGasLimit": "5000", + "protocolFee": "0", + "nativeValueForGas": "10987924271225922711", + "gasLimitUsed": "5000", + "attachedPC": 10.987924271225923 + }, + { + "chain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "label": "legacy 1,000,000", + "inputGasLimit": "1000000", + "protocolFee": "0", + "nativeValueForGas": "109879242712259227110", + "gasLimitUsed": "1000000", + "attachedPC": 109.87924271225923 + }, + { + "chain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "label": "explicit 500 (< base 960)", + "inputGasLimit": "500", + "error": "The contract function \"getOutboundTxGasAndFees\" reverted." + } + ] + } + } +} \ No newline at end of file diff --git a/plan/agw/independent-review-creation-flow-2026-10-20/data/sepolia-dex-subsequent-oog-trace.json b/plan/agw/independent-review-creation-flow-2026-10-20/data/sepolia-dex-subsequent-oog-trace.json new file mode 100644 index 00000000..13e1b627 --- /dev/null +++ b/plan/agw/independent-review-creation-flow-2026-10-20/data/sepolia-dex-subsequent-oog-trace.json @@ -0,0 +1 @@ +{"id":1,"jsonrpc":"2.0","result":{"from":"0x9fed6f778a956244c06a3b905ba45bdb2ec3afea","gas":"0x7a120","gasUsed":"0x2d5a5","executionGasUsed":"0x2d5a5","stateGasUsed":"0x0","gasRefund":"0x0","to":"0xd019eb12d0d6ef8d299661f22b4b7d262ed4b965","input":"0x40a31fe239e7d867cbea784422ecd5fb6382e5eb0b7400cdaa8e5fd70cfb43bfdd3a6913700aa6b1f514be92accb6434cea26b01aa01e16a0b173d00c89662f01b134c060000000000000000000000005c788fca118bf06cdb7ab679ffbbd9007b5375e700000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c7d4b196cb0c7b01d743fbc6116a902379c7238000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002e42cc2842d00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001200000000000000000000000001c7d4b196cb0c7b01d743fbc6116a902379c7238000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044095ea7b30000000000000000000000003bfa4769fb09eefc5a80d6e87c3b9c650f7ae48e0000000000000000000000000000000000000000000000000000000000002710000000000000000000000000000000000000000000000000000000000000000000000000000000003bfa4769fb09eefc5a80d6e87c3b9c650f7ae48e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e404e45aaf0000000000000000000000001c7d4b196cb0c7b01d743fbc6116a902379c7238000000000000000000000000fff9976782d46cc05630d1f6ebab18b2324d6b140000000000000000000000000000000000000000000000000000000000000064000000000000000000000000c128bb0e172baed9a6f575bb07c954ef0ebeddac0000000000000000000000000000000000000000000000000000000000002710000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","output":"0xacfdb444","error":"execution reverted","calls":[{"from":"0xd019eb12d0d6ef8d299661f22b4b7d262ed4b965","gas":"0x7189b","gasUsed":"0x3e853","to":"0xfb6daef9c72a08800e09b1c8e971565920077360","input":"0x40a31fe239e7d867cbea784422ecd5fb6382e5eb0b7400cdaa8e5fd70cfb43bfdd3a6913700aa6b1f514be92accb6434cea26b01aa01e16a0b173d00c89662f01b134c060000000000000000000000005c788fca118bf06cdb7ab679ffbbd9007b5375e700000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c7d4b196cb0c7b01d743fbc6116a902379c7238000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002e42cc2842d00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001200000000000000000000000001c7d4b196cb0c7b01d743fbc6116a902379c7238000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044095ea7b30000000000000000000000003bfa4769fb09eefc5a80d6e87c3b9c650f7ae48e0000000000000000000000000000000000000000000000000000000000002710000000000000000000000000000000000000000000000000000000000000000000000000000000003bfa4769fb09eefc5a80d6e87c3b9c650f7ae48e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e404e45aaf0000000000000000000000001c7d4b196cb0c7b01d743fbc6116a902379c7238000000000000000000000000fff9976782d46cc05630d1f6ebab18b2324d6b140000000000000000000000000000000000000000000000000000000000000064000000000000000000000000c128bb0e172baed9a6f575bb07c954ef0ebeddac0000000000000000000000000000000000000000000000000000000000002710000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","output":"0xacfdb444","error":"execution reverted","calls":[{"from":"0xd019eb12d0d6ef8d299661f22b4b7d262ed4b965","gas":"0x6a4d9","gasUsed":"0x2b9c","to":"0x5e191fbbe22f8866c5e4250557664fce760e8870","input":"0x4be73c5b0000000000000000000000005c788fca118bf06cdb7ab679ffbbd9007b5375e7","output":"0x000000000000000000000000c128bb0e172baed9a6f575bb07c954ef0ebeddac0000000000000000000000000000000000000000000000000000000000000001","calls":[{"from":"0x5e191fbbe22f8866c5e4250557664fce760e8870","gas":"0x67654","gasUsed":"0x1735","to":"0x7103465b8fa1ea34ea30731a8fd2ad5ddb10a872","input":"0x4be73c5b0000000000000000000000005c788fca118bf06cdb7ab679ffbbd9007b5375e7","output":"0x000000000000000000000000c128bb0e172baed9a6f575bb07c954ef0ebeddac0000000000000000000000000000000000000000000000000000000000000001","value":"0x0","type":"DELEGATECALL"}],"type":"STATICCALL"},{"from":"0xd019eb12d0d6ef8d299661f22b4b7d262ed4b965","gas":"0x66c2c","gasUsed":"0x27a6","to":"0x1c7d4b196cb0c7b01d743fbc6116a902379c7238","input":"0x70a08231000000000000000000000000d019eb12d0d6ef8d299661f22b4b7d262ed4b965","output":"0x0000000000000000000000000000000000000000000000000000001c0c3cd1e0","calls":[{"from":"0x1c7d4b196cb0c7b01d743fbc6116a902379c7238","gas":"0x6356e","gasUsed":"0x9f9","to":"0xda317c1d3e835dd5f1be459006471acaa1289068","input":"0x70a08231000000000000000000000000d019eb12d0d6ef8d299661f22b4b7d262ed4b965","output":"0x0000000000000000000000000000000000000000000000000000001c0c3cd1e0","value":"0x0","type":"DELEGATECALL"}],"type":"STATICCALL"},{"from":"0xd019eb12d0d6ef8d299661f22b4b7d262ed4b965","gas":"0x642e8","gasUsed":"0x1f133","to":"0x1c7d4b196cb0c7b01d743fbc6116a902379c7238","input":"0xa9059cbb000000000000000000000000c128bb0e172baed9a6f575bb07c954ef0ebeddac0000000000000000000000000000000000000000000000000000000000002710","output":"0x0000000000000000000000000000000000000000000000000000000000000001","calls":[{"from":"0x1c7d4b196cb0c7b01d743fbc6116a902379c7238","gas":"0x62754","gasUsed":"0x1ee77","to":"0xda317c1d3e835dd5f1be459006471acaa1289068","input":"0xa9059cbb000000000000000000000000c128bb0e172baed9a6f575bb07c954ef0ebeddac0000000000000000000000000000000000000000000000000000000000002710","output":"0x0000000000000000000000000000000000000000000000000000000000000001","value":"0x0","type":"DELEGATECALL"}],"value":"0x0","type":"CALL"},{"from":"0xd019eb12d0d6ef8d299661f22b4b7d262ed4b965","gas":"0x45608","gasUsed":"0x13731","to":"0xc128bb0e172baed9a6f575bb07c954ef0ebeddac","input":"0xc9ced48039e7d867cbea784422ecd5fb6382e5eb0b7400cdaa8e5fd70cfb43bfdd3a6913700aa6b1f514be92accb6434cea26b01aa01e16a0b173d00c89662f01b134c060000000000000000000000005c788fca118bf06cdb7ab679ffbbd9007b5375e7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000002e42cc2842d00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001200000000000000000000000001c7d4b196cb0c7b01d743fbc6116a902379c7238000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044095ea7b30000000000000000000000003bfa4769fb09eefc5a80d6e87c3b9c650f7ae48e0000000000000000000000000000000000000000000000000000000000002710000000000000000000000000000000000000000000000000000000000000000000000000000000003bfa4769fb09eefc5a80d6e87c3b9c650f7ae48e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e404e45aaf0000000000000000000000001c7d4b196cb0c7b01d743fbc6116a902379c7238000000000000000000000000fff9976782d46cc05630d1f6ebab18b2324d6b140000000000000000000000000000000000000000000000000000000000000064000000000000000000000000c128bb0e172baed9a6f575bb07c954ef0ebeddac0000000000000000000000000000000000000000000000000000000000002710000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","output":"0xacfdb444","error":"execution reverted","calls":[{"from":"0xc128bb0e172baed9a6f575bb07c954ef0ebeddac","gas":"0x43858","gasUsed":"0x12a83","to":"0x425291f35ba1a94bd2dcc2dc097c2b55700a1fb6","input":"0xc9ced48039e7d867cbea784422ecd5fb6382e5eb0b7400cdaa8e5fd70cfb43bfdd3a6913700aa6b1f514be92accb6434cea26b01aa01e16a0b173d00c89662f01b134c060000000000000000000000005c788fca118bf06cdb7ab679ffbbd9007b5375e7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000002e42cc2842d00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001200000000000000000000000001c7d4b196cb0c7b01d743fbc6116a902379c7238000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044095ea7b30000000000000000000000003bfa4769fb09eefc5a80d6e87c3b9c650f7ae48e0000000000000000000000000000000000000000000000000000000000002710000000000000000000000000000000000000000000000000000000000000000000000000000000003bfa4769fb09eefc5a80d6e87c3b9c650f7ae48e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e404e45aaf0000000000000000000000001c7d4b196cb0c7b01d743fbc6116a902379c7238000000000000000000000000fff9976782d46cc05630d1f6ebab18b2324d6b140000000000000000000000000000000000000000000000000000000000000064000000000000000000000000c128bb0e172baed9a6f575bb07c954ef0ebeddac0000000000000000000000000000000000000000000000000000000000002710000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","output":"0xacfdb444","error":"execution reverted","calls":[{"from":"0xc128bb0e172baed9a6f575bb07c954ef0ebeddac","gas":"0x41299","gasUsed":"0x4122e","to":"0x1972646e4208c5fe20914c3e09ba339df43d9cb0","input":"0xc9ced48039e7d867cbea784422ecd5fb6382e5eb0b7400cdaa8e5fd70cfb43bfdd3a6913700aa6b1f514be92accb6434cea26b01aa01e16a0b173d00c89662f01b134c060000000000000000000000005c788fca118bf06cdb7ab679ffbbd9007b5375e7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000002e42cc2842d00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001200000000000000000000000001c7d4b196cb0c7b01d743fbc6116a902379c7238000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044095ea7b30000000000000000000000003bfa4769fb09eefc5a80d6e87c3b9c650f7ae48e0000000000000000000000000000000000000000000000000000000000002710000000000000000000000000000000000000000000000000000000000000000000000000000000003bfa4769fb09eefc5a80d6e87c3b9c650f7ae48e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e404e45aaf0000000000000000000000001c7d4b196cb0c7b01d743fbc6116a902379c7238000000000000000000000000fff9976782d46cc05630d1f6ebab18b2324d6b140000000000000000000000000000000000000000000000000000000000000064000000000000000000000000c128bb0e172baed9a6f575bb07c954ef0ebeddac0000000000000000000000000000000000000000000000000000000000002710000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","output":"0xacfdb444","error":"execution reverted","calls":[{"from":"0xc128bb0e172baed9a6f575bb07c954ef0ebeddac","gas":"0x3f79b","gasUsed":"0xb6e","to":"0x5e191fbbe22f8866c5e4250557664fce760e8870","input":"0x411557d1","output":"0x000000000000000000000000d019eb12d0d6ef8d299661f22b4b7d262ed4b965","calls":[{"from":"0x5e191fbbe22f8866c5e4250557664fce760e8870","gas":"0x3e6a6","gasUsed":"0xa31","to":"0x7103465b8fa1ea34ea30731a8fd2ad5ddb10a872","input":"0x411557d1","output":"0x000000000000000000000000d019eb12d0d6ef8d299661f22b4b7d262ed4b965","value":"0x0","type":"DELEGATECALL"}],"type":"STATICCALL"},{"from":"0xc128bb0e172baed9a6f575bb07c954ef0ebeddac","gas":"0x2002c","gasUsed":"0x1ba6d","to":"0x1c7d4b196cb0c7b01d743fbc6116a902379c7238","input":"0x095ea7b30000000000000000000000003bfa4769fb09eefc5a80d6e87c3b9c650f7ae48e0000000000000000000000000000000000000000000000000000000000002710","output":"0x0000000000000000000000000000000000000000000000000000000000000001","calls":[{"from":"0x1c7d4b196cb0c7b01d743fbc6116a902379c7238","gas":"0x1f5c3","gasUsed":"0x1b7d1","to":"0xda317c1d3e835dd5f1be459006471acaa1289068","input":"0x095ea7b30000000000000000000000003bfa4769fb09eefc5a80d6e87c3b9c650f7ae48e0000000000000000000000000000000000000000000000000000000000002710","output":"0x0000000000000000000000000000000000000000000000000000000000000001","value":"0x0","type":"DELEGATECALL"}],"value":"0x0","type":"CALL"},{"from":"0xc128bb0e172baed9a6f575bb07c954ef0ebeddac","gas":"0x2dac","gasUsed":"0x2d91","to":"0x3bfa4769fb09eefc5a80d6e87c3b9c650f7ae48e","input":"0x04e45aaf0000000000000000000000001c7d4b196cb0c7b01d743fbc6116a902379c7238000000000000000000000000fff9976782d46cc05630d1f6ebab18b2324d6b140000000000000000000000000000000000000000000000000000000000000064000000000000000000000000c128bb0e172baed9a6f575bb07c954ef0ebeddac000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000","error":"execution reverted","calls":[{"from":"0x3bfa4769fb09eefc5a80d6e87c3b9c650f7ae48e","gas":"0x101e","gasUsed":"0x101e","to":"0xfeed501c2b21d315f04946f85fc6416b640240b5","input":"0x128acb08000000000000000000000000c128bb0e172baed9a6f575bb07c954ef0ebeddac0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000001000276a400000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000040000000000000000000000000c128bb0e172baed9a6f575bb07c954ef0ebeddac000000000000000000000000000000000000000000000000000000000000002b1c7d4b196cb0c7b01d743fbc6116a902379c7238000064fff9976782d46cc05630d1f6ebab18b2324d6b14000000000000000000000000000000000000000000","error":"out of gas: not enough gas for reentrancy sentry","value":"0x0","type":"CALL"}],"value":"0x0","type":"CALL"}],"value":"0x0","type":"DELEGATECALL"}],"value":"0x0","type":"DELEGATECALL"}],"value":"0x0","type":"CALL"}],"value":"0x0","type":"DELEGATECALL"}],"value":"0x0","type":"CALL"}} \ No newline at end of file diff --git a/plan/agw/independent-review-creation-flow-2026-10-20/data/sol-probe.json b/plan/agw/independent-review-creation-flow-2026-10-20/data/sol-probe.json new file mode 100644 index 00000000..bb6eacee --- /dev/null +++ b/plan/agw/independent-review-creation-flow-2026-10-20/data/sol-probe.json @@ -0,0 +1,378 @@ +{ + "at": "2026-10-20T16:29:02.017Z", + "rpc": "https://api.devnet.solana.com", + "readOnly": true, + "slot": 513220877, + "genesisHash": "EtWTRABZaYq6iMfeYKouRu166VU2xqa1wcaWoxPkrZBG", + "rent": { + "0": 650240, + "8": 690880, + "82": 1066800, + "165": 1488440 + }, + "ceaDerived": "DKbAi4YmS5EfdvKHzS2zHKSSPfgiffu3ZddXoY4N2VuX", + "ceaMatchesEvidence": true, + "programs": { + "gatewayCFVS": { + "id": "CFVSincHYbETh2k7w6u1ENEkjbSLtveRCEBupKidw2VS", + "executable": true, + "owner": "BPFLoaderUpgradeab1e11111111111111111111111", + "dataLen": 36 + }, + "gatewayDJoF_pinnedSource": { + "id": "DJoFYDpgbTfxbXBv1QYhYGc9FK4J5FUKpYXAfSkHryXp", + "executable": true, + "owner": "BPFLoaderUpgradeab1e11111111111111111111111", + "dataLen": 36 + }, + "testCounter_sdkFixture": { + "id": "8yNqjrMnFiFbVTVQcKij8tNWWTMdFkrDf9abCGgc2sgx", + "executable": true, + "owner": "BPFLoaderUpgradeab1e11111111111111111111111", + "dataLen": 36 + }, + "testCounter_sourceDeclareId": { + "id": "4mpHkerNsaJPp35fyT5bkoXxuEBczGq6HUKTtrzFcptx", + "executable": true, + "owner": "BPFLoaderUpgradeab1e11111111111111111111111", + "dataLen": 36 + }, + "testCounter_anchorToml": { + "id": "9LfpvcY2CYcNWEc2ip2ZwwKivEALbF3knwimXrbLubT2", + "executable": true, + "owner": "BPFLoaderUpgradeab1e11111111111111111111111", + "dataLen": 36 + }, + "splMemoV2": { + "id": "MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr", + "executable": true, + "owner": "BPFLoader2111111111111111111111111111111111", + "dataLen": 74800 + }, + "splMemoV1": { + "id": "Memo1UhkJRfHyvLMcVucJwxXeuD728EqVDDwQDxFMNo", + "executable": true, + "owner": "BPFLoader1111111111111111111111111111111111", + "dataLen": 17072 + }, + "associatedToken": { + "id": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL", + "executable": true, + "owner": "BPFLoader2111111111111111111111111111111111", + "dataLen": 105032 + } + }, + "ceaAta": { + "parsed": { + "info": { + "isNative": false, + "mint": "EiXDnrAg9ea2Q6vEPV7E5TpTU1vh41jcuZqKjU5Dc4ZF", + "owner": "DKbAi4YmS5EfdvKHzS2zHKSSPfgiffu3ZddXoY4N2VuX", + "state": "initialized", + "tokenAmount": { + "amount": "0", + "decimals": 6, + "uiAmount": 0, + "uiAmountString": "0" + } + }, + "type": "account" + }, + "program": "spl-token", + "space": 165 + }, + "txs": { + "spl:first-use": { + "sig": "y8hK7xQWVs4mRupJAJDRBkbt1EnVmtQNxAhPhTbvJbfULrwARFimjvygaDskPawH44dntUaq5Tq6ubDDp7592q1", + "slot": 513205039, + "blockTime": "2026-10-20T15:26:08.000Z", + "err": null, + "fee": 5000, + "computeUnitsConsumed": 116402, + "signers": [ + "Bo5aMaGTHpTLQkF1b41wUiWKKDFWc9v6UsYdqouGz2uF" + ], + "programsInvoked": [ + "ComputeBudget111111111111111111111111111111", + "CFVSincHYbETh2k7w6u1ENEkjbSLtveRCEBupKidw2VS", + "11111111111111111111111111111111", + "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL", + "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "8yNqjrMnFiFbVTVQcKij8tNWWTMdFkrDf9abCGgc2sgx" + ], + "preTokenBalances": [ + { + "account": "oVL4eb7hqoq4iJEZ4mPf9Hgd5ys3EzaXuCpZ434aRRt", + "mint": "EiXDnrAg9ea2Q6vEPV7E5TpTU1vh41jcuZqKjU5Dc4ZF", + "owner": "3nK8X1re4zLNrgz9Y3xKS4g2fKPJ6M3N9BhNuFfkjwAb", + "amount": "9995962000", + "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + { + "account": "9dzJzSyqmgYKLZwwP5FEzHv9gU72MXwsi6nL4oBrtWxd", + "mint": "EiXDnrAg9ea2Q6vEPV7E5TpTU1vh41jcuZqKjU5Dc4ZF", + "owner": "89q1AUFb7YREHtjc1aYaPywovPq6tb3GYNPyDUJ3rshi", + "amount": "2131694221683", + "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + } + ], + "postTokenBalances": [ + { + "account": "GuKBtW2xo53yMyj915CMCziHyyz1LaGxnfZBUDRJPd9K", + "mint": "EiXDnrAg9ea2Q6vEPV7E5TpTU1vh41jcuZqKjU5Dc4ZF", + "owner": "DKbAi4YmS5EfdvKHzS2zHKSSPfgiffu3ZddXoY4N2VuX", + "amount": "0", + "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + { + "account": "oVL4eb7hqoq4iJEZ4mPf9Hgd5ys3EzaXuCpZ434aRRt", + "mint": "EiXDnrAg9ea2Q6vEPV7E5TpTU1vh41jcuZqKjU5Dc4ZF", + "owner": "3nK8X1re4zLNrgz9Y3xKS4g2fKPJ6M3N9BhNuFfkjwAb", + "amount": "9995963000", + "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + { + "account": "9dzJzSyqmgYKLZwwP5FEzHv9gU72MXwsi6nL4oBrtWxd", + "mint": "EiXDnrAg9ea2Q6vEPV7E5TpTU1vh41jcuZqKjU5Dc4ZF", + "owner": "89q1AUFb7YREHtjc1aYaPywovPq6tb3GYNPyDUJ3rshi", + "amount": "2131694220683", + "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + } + ], + "innerTransfers": [ + { + "program": "11111111111111111111111111111111", + "type": "createAccount", + "info": { + "lamports": 690880, + "newAccount": "C1DGbew7Ypmw8acT54RiWrhEiMKfjnkbKfNrgqU7A3Lo", + "owner": "CFVSincHYbETh2k7w6u1ENEkjbSLtveRCEBupKidw2VS", + "source": "Bo5aMaGTHpTLQkF1b41wUiWKKDFWc9v6UsYdqouGz2uF", + "space": 8 + } + }, + { + "program": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL", + "type": "create", + "info": { + "account": "GuKBtW2xo53yMyj915CMCziHyyz1LaGxnfZBUDRJPd9K", + "mint": "EiXDnrAg9ea2Q6vEPV7E5TpTU1vh41jcuZqKjU5Dc4ZF", + "source": "Bo5aMaGTHpTLQkF1b41wUiWKKDFWc9v6UsYdqouGz2uF", + "systemProgram": "11111111111111111111111111111111", + "tokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "wallet": "DKbAi4YmS5EfdvKHzS2zHKSSPfgiffu3ZddXoY4N2VuX" + } + }, + { + "program": "11111111111111111111111111111111", + "type": "createAccount", + "info": { + "lamports": 1488440, + "newAccount": "GuKBtW2xo53yMyj915CMCziHyyz1LaGxnfZBUDRJPd9K", + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "source": "Bo5aMaGTHpTLQkF1b41wUiWKKDFWc9v6UsYdqouGz2uF", + "space": 165 + } + }, + { + "program": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "type": "initializeAccount3", + "info": { + "account": "GuKBtW2xo53yMyj915CMCziHyyz1LaGxnfZBUDRJPd9K", + "mint": "EiXDnrAg9ea2Q6vEPV7E5TpTU1vh41jcuZqKjU5Dc4ZF", + "owner": "DKbAi4YmS5EfdvKHzS2zHKSSPfgiffu3ZddXoY4N2VuX" + } + }, + { + "program": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "type": "transfer", + "info": { + "amount": "1000", + "authority": "89q1AUFb7YREHtjc1aYaPywovPq6tb3GYNPyDUJ3rshi", + "destination": "GuKBtW2xo53yMyj915CMCziHyyz1LaGxnfZBUDRJPd9K", + "source": "9dzJzSyqmgYKLZwwP5FEzHv9gU72MXwsi6nL4oBrtWxd" + } + }, + { + "program": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "type": "transfer", + "info": { + "amount": "1000", + "authority": "DKbAi4YmS5EfdvKHzS2zHKSSPfgiffu3ZddXoY4N2VuX", + "destination": "oVL4eb7hqoq4iJEZ4mPf9Hgd5ys3EzaXuCpZ434aRRt", + "source": "GuKBtW2xo53yMyj915CMCziHyyz1LaGxnfZBUDRJPd9K" + } + }, + { + "program": "11111111111111111111111111111111", + "type": "transfer", + "info": { + "destination": "Bo5aMaGTHpTLQkF1b41wUiWKKDFWc9v6UsYdqouGz2uF", + "lamports": 2184320, + "source": "89q1AUFb7YREHtjc1aYaPywovPq6tb3GYNPyDUJ3rshi" + } + } + ], + "logTail": [ + "Program ComputeBudget111111111111111111111111111111 invoke [1]", + "Program ComputeBudget111111111111111111111111111111 success", + "Program CFVSincHYbETh2k7w6u1ENEkjbSLtveRCEBupKidw2VS invoke [1]", + "Program log: Instruction: FinalizeUniversalTx", + "Program 11111111111111111111111111111111 invoke [2]", + "Program 11111111111111111111111111111111 success", + "Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL invoke [2]", + "Program log: Create", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success", + "Program 11111111111111111111111111111111 invoke [3]", + "Program 11111111111111111111111111111111 success", + "Program log: Initialize the associated token account", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success", + "Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL success", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success", + "Program 8yNqjrMnFiFbVTVQcKij8tNWWTMdFkrDf9abCGgc2sgx invoke [2]", + "Program log: Instruction: ReceiveSpl", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success", + "Program log: Received 1000 tokens, counter incremented to: 201960018", + "Program 8yNqjrMnFiFbVTVQcKij8tNWWTMdFkrDf9abCGgc2sgx success", + "Program 11111111111111111111111111111111 invoke [2]", + "Program 11111111111111111111111111111111 success", + "Program CFVSincHYbETh2k7w6u1ENEkjbSLtveRCEBupKidw2VS invoke [2]", + "Program CFVSincHYbETh2k7w6u1ENEkjbSLtveRCEBupKidw2VS success", + "Program CFVSincHYbETh2k7w6u1ENEkjbSLtveRCEBupKidw2VS success" + ] + }, + "spl:subsequent": { + "sig": "3G782PfUtqv3THZGt7vH5J9xoscMMFvKwUo215J2Hoh4APYHEHMGDcKBjix6je5y3M2DhoeuENkmqWEFrJgUjmLe", + "slot": 513205352, + "blockTime": "2026-10-20T15:27:22.000Z", + "err": null, + "fee": 5000, + "computeUnitsConsumed": 98301, + "signers": [ + "FkXGfYVbXT5euXjYabvZn4e6Ygc8aCYpFv9j1hKstw2H" + ], + "programsInvoked": [ + "ComputeBudget111111111111111111111111111111", + "CFVSincHYbETh2k7w6u1ENEkjbSLtveRCEBupKidw2VS", + "11111111111111111111111111111111", + "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "8yNqjrMnFiFbVTVQcKij8tNWWTMdFkrDf9abCGgc2sgx" + ], + "preTokenBalances": [ + { + "account": "GuKBtW2xo53yMyj915CMCziHyyz1LaGxnfZBUDRJPd9K", + "mint": "EiXDnrAg9ea2Q6vEPV7E5TpTU1vh41jcuZqKjU5Dc4ZF", + "owner": "DKbAi4YmS5EfdvKHzS2zHKSSPfgiffu3ZddXoY4N2VuX", + "amount": "0", + "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + { + "account": "oVL4eb7hqoq4iJEZ4mPf9Hgd5ys3EzaXuCpZ434aRRt", + "mint": "EiXDnrAg9ea2Q6vEPV7E5TpTU1vh41jcuZqKjU5Dc4ZF", + "owner": "3nK8X1re4zLNrgz9Y3xKS4g2fKPJ6M3N9BhNuFfkjwAb", + "amount": "9995963000", + "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + { + "account": "9dzJzSyqmgYKLZwwP5FEzHv9gU72MXwsi6nL4oBrtWxd", + "mint": "EiXDnrAg9ea2Q6vEPV7E5TpTU1vh41jcuZqKjU5Dc4ZF", + "owner": "89q1AUFb7YREHtjc1aYaPywovPq6tb3GYNPyDUJ3rshi", + "amount": "2131694220683", + "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + } + ], + "postTokenBalances": [ + { + "account": "GuKBtW2xo53yMyj915CMCziHyyz1LaGxnfZBUDRJPd9K", + "mint": "EiXDnrAg9ea2Q6vEPV7E5TpTU1vh41jcuZqKjU5Dc4ZF", + "owner": "DKbAi4YmS5EfdvKHzS2zHKSSPfgiffu3ZddXoY4N2VuX", + "amount": "0", + "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + { + "account": "oVL4eb7hqoq4iJEZ4mPf9Hgd5ys3EzaXuCpZ434aRRt", + "mint": "EiXDnrAg9ea2Q6vEPV7E5TpTU1vh41jcuZqKjU5Dc4ZF", + "owner": "3nK8X1re4zLNrgz9Y3xKS4g2fKPJ6M3N9BhNuFfkjwAb", + "amount": "9995964000", + "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + { + "account": "9dzJzSyqmgYKLZwwP5FEzHv9gU72MXwsi6nL4oBrtWxd", + "mint": "EiXDnrAg9ea2Q6vEPV7E5TpTU1vh41jcuZqKjU5Dc4ZF", + "owner": "89q1AUFb7YREHtjc1aYaPywovPq6tb3GYNPyDUJ3rshi", + "amount": "2131694219683", + "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + } + ], + "innerTransfers": [ + { + "program": "11111111111111111111111111111111", + "type": "createAccount", + "info": { + "lamports": 690880, + "newAccount": "GUb4aohCTdbQZPSWb8FiT3rGebgh3EYU8v16nyfWU5Zy", + "owner": "CFVSincHYbETh2k7w6u1ENEkjbSLtveRCEBupKidw2VS", + "source": "FkXGfYVbXT5euXjYabvZn4e6Ygc8aCYpFv9j1hKstw2H", + "space": 8 + } + }, + { + "program": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "type": "transfer", + "info": { + "amount": "1000", + "authority": "89q1AUFb7YREHtjc1aYaPywovPq6tb3GYNPyDUJ3rshi", + "destination": "GuKBtW2xo53yMyj915CMCziHyyz1LaGxnfZBUDRJPd9K", + "source": "9dzJzSyqmgYKLZwwP5FEzHv9gU72MXwsi6nL4oBrtWxd" + } + }, + { + "program": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "type": "transfer", + "info": { + "amount": "1000", + "authority": "DKbAi4YmS5EfdvKHzS2zHKSSPfgiffu3ZddXoY4N2VuX", + "destination": "oVL4eb7hqoq4iJEZ4mPf9Hgd5ys3EzaXuCpZ434aRRt", + "source": "GuKBtW2xo53yMyj915CMCziHyyz1LaGxnfZBUDRJPd9K" + } + }, + { + "program": "11111111111111111111111111111111", + "type": "transfer", + "info": { + "destination": "FkXGfYVbXT5euXjYabvZn4e6Ygc8aCYpFv9j1hKstw2H", + "lamports": 695880, + "source": "89q1AUFb7YREHtjc1aYaPywovPq6tb3GYNPyDUJ3rshi" + } + } + ], + "logTail": [ + "Program ComputeBudget111111111111111111111111111111 invoke [1]", + "Program ComputeBudget111111111111111111111111111111 success", + "Program CFVSincHYbETh2k7w6u1ENEkjbSLtveRCEBupKidw2VS invoke [1]", + "Program log: Instruction: FinalizeUniversalTx", + "Program 11111111111111111111111111111111 invoke [2]", + "Program 11111111111111111111111111111111 success", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success", + "Program 8yNqjrMnFiFbVTVQcKij8tNWWTMdFkrDf9abCGgc2sgx invoke [2]", + "Program log: Instruction: ReceiveSpl", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success", + "Program log: Received 1000 tokens, counter incremented to: 201961018", + "Program 8yNqjrMnFiFbVTVQcKij8tNWWTMdFkrDf9abCGgc2sgx success", + "Program 11111111111111111111111111111111 invoke [2]", + "Program 11111111111111111111111111111111 success", + "Program CFVSincHYbETh2k7w6u1ENEkjbSLtveRCEBupKidw2VS invoke [2]", + "Program CFVSincHYbETh2k7w6u1ENEkjbSLtveRCEBupKidw2VS success", + "Program CFVSincHYbETh2k7w6u1ENEkjbSLtveRCEBupKidw2VS success" + ] + } + } +} \ No newline at end of file diff --git a/plan/agw/independent-review-creation-flow-2026-10-20/data/spl-rule-readback.json b/plan/agw/independent-review-creation-flow-2026-10-20/data/spl-rule-readback.json new file mode 100644 index 00000000..07fa9e65 --- /dev/null +++ b/plan/agw/independent-review-creation-flow-2026-10-20/data/spl-rule-readback.json @@ -0,0 +1,128 @@ +{ + "at": "2026-10-20T17:32:25.720Z", + "readOnly": true, + "block": "24458787", + "wallet": "0xed6bfe825b8d84a1e6f4f7c9067398f8985cc372", + "rulesId": "0x91ca4f52a5e7f8a27146232cd7cc1f5d957009d1c6763c473b5d1e74b729e248", + "originalAccounts": [ + { + "pubkey": "0x4f12fe6816ae7e33ebf7db0b154ec3b09e3bf1a7690481e8e9477d5a278ad3af", + "isWritable": true, + "writableFlag": 1 + }, + { + "pubkey": "0xec461225ee62f450765de61547c5aed0b4edb46c70da56afc5ea7cb1a2fe1ff2", + "isWritable": true, + "writableFlag": 1 + }, + { + "pubkey": "0x0be8bfa0ceae1ac81eaf3a39d5e3a144251d7eba559ac4a080d019cb2822725b", + "isWritable": true, + "writableFlag": 1 + }, + { + "pubkey": "0xb70f54b3150c7f8b8bb27e808a3b2bc7ced1bd64656bd4a5b392fd0cd27bc3ee", + "isWritable": false, + "writableFlag": 0 + }, + { + "pubkey": "0x06ddf6e1d765a193d9cbe146ceeb79ac1cb485ed5f5b37913a8cf5857eff00a9", + "isWritable": false, + "writableFlag": 0 + } + ], + "record": { + "rulesId": "0x91ca4f52a5e7f8a27146232cd7cc1f5d957009d1c6763c473b5d1e74b729e248", + "enabled": true, + "agent": "0x8FB1CF80a014af564bDC12E557a3E52432F4657b", + "chainNamespace": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "validUntil": 1792513451, + "spent": { + "kind": "universal", + "assets": [ + { + "token": "0xcbcae9e66452fe98abcf0fa51e557fc8d671c7fc6ce83c05f92992a3d2bf1932", + "spent": "2000" + } + ] + }, + "rule": { + "format": "decoded", + "agent": "0x8FB1CF80a014af564bDC12E557a3E52432F4657b", + "chainNamespace": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "validUntil": 1792513451, + "expectedCEA": "0xb70f54b3150c7f8b8bb27e808a3b2bc7ced1bd64656bd4a5b392fd0cd27bc3ee", + "gatewayProgram": "0xa726d940296890606ae77be948a7726799b7e19076ced8c14c6ed43e98b7a6e5", + "maxGasPerCall": "20000000000000000000", + "assets": [ + { + "token": "0xcbcae9e66452fe98abcf0fa51e557fc8d671c7fc6ce83c05f92992a3d2bf1932", + "maxPerCall": "1000", + "maxTotal": "2000" + } + ], + "ceaAccounts": [ + "0xb70f54b3150c7f8b8bb27e808a3b2bc7ced1bd64656bd4a5b392fd0cd27bc3ee", + "0xec461225ee62f450765de61547c5aed0b4edb46c70da56afc5ea7cb1a2fe1ff2" + ], + "programs": [ + { + "program": "0x7673075a980bfd5d6b1dffe99c31f63e8938519cc1c2af009dda5e568a94460d", + "discriminator": "0xb654fa2e8aa449c4", + "discriminatorLen": 8, + "dataless": false, + "maxAccounts": 255 + } + ], + "pins": [ + { + "ruleIndex": 0, + "accountIndex": 0, + "expected": "0x4f12fe6816ae7e33ebf7db0b154ec3b09e3bf1a7690481e8e9477d5a278ad3af" + }, + { + "ruleIndex": 0, + "accountIndex": 1, + "expected": "0xec461225ee62f450765de61547c5aed0b4edb46c70da56afc5ea7cb1a2fe1ff2" + }, + { + "ruleIndex": 0, + "accountIndex": 2, + "expected": "0x0be8bfa0ceae1ac81eaf3a39d5e3a144251d7eba559ac4a080d019cb2822725b" + }, + { + "ruleIndex": 0, + "accountIndex": 3, + "expected": "0xb70f54b3150c7f8b8bb27e808a3b2bc7ced1bd64656bd4a5b392fd0cd27bc3ee" + }, + { + "ruleIndex": 0, + "accountIndex": 4, + "expected": "0x06ddf6e1d765a193d9cbe146ceeb79ac1cb485ed5f5b37913a8cf5857eff00a9" + } + ], + "dataPins": [ + { + "ruleIndex": 0, + "fromEnd": false, + "offset": 8, + "offsetB": 0, + "len": 8, + "mode": 2, + "expected": "0x00000000000000000000000000000000000000000000000000000000000003e8", + "num": "0", + "den": "0" + } + ] + } + }, + "wrongRecipient": { + "ata": "7PKuD1YUQxRuEE3qZVxUL8D1vaifMzWFSAeRhZ7dtFK6", + "refusal": { + "name": "PolicyCheckReverted(RulesExpired)", + "selector": "0xf4270752", + "decoded": "0x435b324e00000000000000000000000000000000000000000000000000000000", + "hint": "URP rejected the action (truncated through the session engine). The inner selector names the gate; arguments are truncated to 28 bytes." + } + } +} \ No newline at end of file diff --git a/plan/agw/independent-review-creation-flow-2026-10-20/data/spl-wrong-recipient-24456030.json b/plan/agw/independent-review-creation-flow-2026-10-20/data/spl-wrong-recipient-24456030.json new file mode 100644 index 00000000..053ab012 --- /dev/null +++ b/plan/agw/independent-review-creation-flow-2026-10-20/data/spl-wrong-recipient-24456030.json @@ -0,0 +1,128 @@ +{ + "at": "2026-10-20T17:33:05.619Z", + "readOnly": true, + "block": "24456030", + "wallet": "0xed6bfe825b8d84a1e6f4f7c9067398f8985cc372", + "rulesId": "0x91ca4f52a5e7f8a27146232cd7cc1f5d957009d1c6763c473b5d1e74b729e248", + "originalAccounts": [ + { + "pubkey": "0x4f12fe6816ae7e33ebf7db0b154ec3b09e3bf1a7690481e8e9477d5a278ad3af", + "isWritable": true, + "writableFlag": 1 + }, + { + "pubkey": "0xec461225ee62f450765de61547c5aed0b4edb46c70da56afc5ea7cb1a2fe1ff2", + "isWritable": true, + "writableFlag": 1 + }, + { + "pubkey": "0x0be8bfa0ceae1ac81eaf3a39d5e3a144251d7eba559ac4a080d019cb2822725b", + "isWritable": true, + "writableFlag": 1 + }, + { + "pubkey": "0xb70f54b3150c7f8b8bb27e808a3b2bc7ced1bd64656bd4a5b392fd0cd27bc3ee", + "isWritable": false, + "writableFlag": 0 + }, + { + "pubkey": "0x06ddf6e1d765a193d9cbe146ceeb79ac1cb485ed5f5b37913a8cf5857eff00a9", + "isWritable": false, + "writableFlag": 0 + } + ], + "record": { + "rulesId": "0x91ca4f52a5e7f8a27146232cd7cc1f5d957009d1c6763c473b5d1e74b729e248", + "enabled": true, + "agent": "0x8FB1CF80a014af564bDC12E557a3E52432F4657b", + "chainNamespace": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "validUntil": 1792513451, + "spent": { + "kind": "universal", + "assets": [ + { + "token": "0xcbcae9e66452fe98abcf0fa51e557fc8d671c7fc6ce83c05f92992a3d2bf1932", + "spent": "2000" + } + ] + }, + "rule": { + "format": "decoded", + "agent": "0x8FB1CF80a014af564bDC12E557a3E52432F4657b", + "chainNamespace": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "validUntil": 1792513451, + "expectedCEA": "0xb70f54b3150c7f8b8bb27e808a3b2bc7ced1bd64656bd4a5b392fd0cd27bc3ee", + "gatewayProgram": "0xa726d940296890606ae77be948a7726799b7e19076ced8c14c6ed43e98b7a6e5", + "maxGasPerCall": "20000000000000000000", + "assets": [ + { + "token": "0xcbcae9e66452fe98abcf0fa51e557fc8d671c7fc6ce83c05f92992a3d2bf1932", + "maxPerCall": "1000", + "maxTotal": "2000" + } + ], + "ceaAccounts": [ + "0xb70f54b3150c7f8b8bb27e808a3b2bc7ced1bd64656bd4a5b392fd0cd27bc3ee", + "0xec461225ee62f450765de61547c5aed0b4edb46c70da56afc5ea7cb1a2fe1ff2" + ], + "programs": [ + { + "program": "0x7673075a980bfd5d6b1dffe99c31f63e8938519cc1c2af009dda5e568a94460d", + "discriminator": "0xb654fa2e8aa449c4", + "discriminatorLen": 8, + "dataless": false, + "maxAccounts": 255 + } + ], + "pins": [ + { + "ruleIndex": 0, + "accountIndex": 0, + "expected": "0x4f12fe6816ae7e33ebf7db0b154ec3b09e3bf1a7690481e8e9477d5a278ad3af" + }, + { + "ruleIndex": 0, + "accountIndex": 1, + "expected": "0xec461225ee62f450765de61547c5aed0b4edb46c70da56afc5ea7cb1a2fe1ff2" + }, + { + "ruleIndex": 0, + "accountIndex": 2, + "expected": "0x0be8bfa0ceae1ac81eaf3a39d5e3a144251d7eba559ac4a080d019cb2822725b" + }, + { + "ruleIndex": 0, + "accountIndex": 3, + "expected": "0xb70f54b3150c7f8b8bb27e808a3b2bc7ced1bd64656bd4a5b392fd0cd27bc3ee" + }, + { + "ruleIndex": 0, + "accountIndex": 4, + "expected": "0x06ddf6e1d765a193d9cbe146ceeb79ac1cb485ed5f5b37913a8cf5857eff00a9" + } + ], + "dataPins": [ + { + "ruleIndex": 0, + "fromEnd": false, + "offset": 8, + "offsetB": 0, + "len": 8, + "mode": 2, + "expected": "0x00000000000000000000000000000000000000000000000000000000000003e8", + "num": "0", + "den": "0" + } + ] + } + }, + "wrongRecipient": { + "ata": "7PKuD1YUQxRuEE3qZVxUL8D1vaifMzWFSAeRhZ7dtFK6", + "refusal": { + "name": "PolicyCheckReverted(SvmAccountPinMismatch)", + "selector": "0xf4270752", + "decoded": "0xff3dafe500000000000000000000000000000000000000000000000000000000", + "hint": "URP rejected the action (truncated through the session engine). The inner selector names the gate; arguments are truncated to 28 bytes." + } + } +} \ No newline at end of file diff --git a/plan/agw/independent-review-creation-flow-2026-10-20/data/uregistry.json b/plan/agw/independent-review-creation-flow-2026-10-20/data/uregistry.json new file mode 100644 index 00000000..e5355542 --- /dev/null +++ b/plan/agw/independent-review-creation-flow-2026-10-20/data/uregistry.json @@ -0,0 +1,359 @@ +{ + "at": "2026-10-20T16:35:03.420Z", + "rpc": "https://donut.rpc.push.org:443", + "readOnly": true, + "node": { + "data": "pchain", + "version": "v0.0.49", + "last_block_height": "24457376", + "last_block_app_hash": "wr8bURwcbmXqV9hZSYbskjYHGZLiJnYcr+BSsd0lc1w=" + }, + "height": "24457377", + "tokenConfigs": [ + { + "chain": "eip155:11155111", + "address": "0x0000000000000000000000000000000000000000", + "name": "pETH", + "symbol": "pETH", + "decimals": 18, + "enabled": true, + "liquidityCap": "1000000000000000000000000", + "tokenType": 1, + "native": { + "contractAddress": "0x2971824Db68229D087931155C2b8bB820B275809" + } + }, + { + "chain": "eip155:11155111", + "address": "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238", + "name": "USDC.eth.old", + "symbol": "USDC.eth.old", + "decimals": 6, + "enabled": true, + "liquidityCap": "1000000000000000000000000", + "tokenType": 1, + "native": { + "contractAddress": "0x387b9C8Db60E74999aAAC5A2b7825b400F12d68E" + } + }, + { + "chain": "eip155:11155111", + "address": "0x3e3FE7dBc6B4C189E7128855dD526361c49b40Af", + "name": "stETH.eth", + "symbol": "stETH.eth", + "decimals": 18, + "enabled": true, + "liquidityCap": "1000000000000000000000000", + "tokenType": 1, + "native": { + "contractAddress": "0xaf89E805949c628ebde3262e91dc4ab9eA12668E" + } + }, + { + "chain": "eip155:11155111", + "address": "0x7169D38820dfd117C3FA1f22a697dBA58d90BA06", + "name": "USDT.eth.old", + "symbol": "USDT.eth.old", + "decimals": 6, + "enabled": true, + "liquidityCap": "1000000000000000000000000", + "tokenType": 1, + "native": { + "contractAddress": "0xCA0C5E6F002A389E1580F0DB7cd06e4549B5F9d3" + } + }, + { + "chain": "eip155:11155111", + "address": "0x97F477B7f970D47a87B42869ceeace218106152a", + "name": "USDC.eth", + "symbol": "USDC.eth", + "decimals": 6, + "enabled": true, + "liquidityCap": "1000000000000000000000000", + "tokenType": 1, + "native": { + "contractAddress": "0x7A58048036206bB898008b5bBDA85697DB1e5d66" + } + }, + { + "chain": "eip155:11155111", + "address": "0xC4230aEaFcF6b8B49a7b4e53886420f00ff71876", + "name": "USDT.eth", + "symbol": "USDT.eth", + "decimals": 6, + "enabled": true, + "liquidityCap": "1000000000000000000000000", + "tokenType": 1, + "native": { + "contractAddress": "0x0f97A213207703923F5f0C613C9827f7C9A0f96B" + } + }, + { + "chain": "eip155:11155111", + "address": "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14", + "name": "WETH.eth", + "symbol": "WETH.eth", + "decimals": 18, + "enabled": true, + "liquidityCap": "1000000000000000000000000", + "tokenType": 1, + "native": { + "contractAddress": "0x0d0dF7E8807430A81104EA84d926139816eC7586" + } + }, + { + "chain": "eip155:421614", + "address": "0x0000000000000000000000000000000000000000", + "name": "pETH.arb", + "symbol": "pETH.arb", + "decimals": 18, + "enabled": true, + "liquidityCap": "1000000000000000000000000", + "tokenType": 1, + "native": { + "contractAddress": "0xc0a821a1AfEd1322c5e15f1F4586C0B8cE65400e" + } + }, + { + "chain": "eip155:421614", + "address": "0x1419d7C74D234fA6B73E06A2ce7822C1d37922f0", + "name": "USDT.arb.old", + "symbol": "USDT.arb.old", + "decimals": 6, + "enabled": true, + "liquidityCap": "1000000000000000000000000", + "tokenType": 1, + "native": { + "contractAddress": "0x76Ad08339dF606BeEDe06f90e3FaF82c5b2fb2E9" + } + }, + { + "chain": "eip155:421614", + "address": "0x5dd39b0b3610F666F631a6506b7713EF83e1Ac5C", + "name": "USDC.arb", + "symbol": "USDC.arb", + "decimals": 6, + "enabled": true, + "liquidityCap": "1000000000000000000000000", + "tokenType": 1, + "native": { + "contractAddress": "0x1091cCBA2FF8d2A131AE4B35e34cf3308C48572C" + } + }, + { + "chain": "eip155:421614", + "address": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "name": "USDC.arb.old", + "symbol": "USDC.arb.old", + "decimals": 6, + "enabled": true, + "liquidityCap": "1000000000000000000000000", + "tokenType": 1, + "native": { + "contractAddress": "0xa261A10e94aE4bA88EE8c5845CbE7266bD679DD6" + } + }, + { + "chain": "eip155:421614", + "address": "0xE30928528f52CAEeB75fB07837e22d77D47e9c07", + "name": "USDT.arb", + "symbol": "USDT.arb", + "decimals": 6, + "enabled": true, + "liquidityCap": "1000000000000000000000000", + "tokenType": 1, + "native": { + "contractAddress": "0xFE6E9DF2BbC9ce05D98b83B1365df6DcA9951891" + } + }, + { + "chain": "eip155:84532", + "address": "0x0000000000000000000000000000000000000000", + "name": "pETH.base", + "symbol": "pETH.base", + "decimals": 18, + "enabled": true, + "liquidityCap": "1000000000000000000000000", + "tokenType": 1, + "native": { + "contractAddress": "0xc7007af2B24D4eb963fc9633B0c66e1d2D90Fc21" + } + }, + { + "chain": "eip155:84532", + "address": "0x036CbD53842c5426634e7929541eC2318f3dCF7e", + "name": "USDC.base.old", + "symbol": "USDC.base.old", + "decimals": 6, + "enabled": true, + "liquidityCap": "1000000000000000000000000", + "tokenType": 1, + "native": { + "contractAddress": "0x84B62e44F667F692F7739Ca6040cD17DA02068A8" + } + }, + { + "chain": "eip155:84532", + "address": "0x4D7646B9eE3D68F4b0F135B5cbc66B00819F6b61", + "name": "USDT.base", + "symbol": "USDT.base", + "decimals": 6, + "enabled": true, + "liquidityCap": "1000000000000000000000000", + "tokenType": 1, + "native": { + "contractAddress": "0x148823809B853e1db187BC09A9ac909BC42F971a" + } + }, + { + "chain": "eip155:84532", + "address": "0x5c3504F0E3bA28FDc1F74234fE936518276AaBB8", + "name": "USDC.base", + "symbol": "USDC.base", + "decimals": 6, + "enabled": true, + "liquidityCap": "1000000000000000000000000", + "tokenType": 1, + "native": { + "contractAddress": "0xD7C6cA1e2c0CE260BE0c0AD39C1540de460e3Be1" + } + }, + { + "chain": "eip155:84532", + "address": "0x9FF5a186f53F6E6964B00320Da1D2024DE11E0cB", + "name": "USDT.base.old", + "symbol": "USDT.base.old", + "decimals": 6, + "enabled": true, + "liquidityCap": "1000000000000000000000000", + "tokenType": 1, + "native": { + "contractAddress": "0x2C455189D2af6643B924A981a9080CcC63d5a567" + } + }, + { + "chain": "eip155:97", + "address": "0x0000000000000000000000000000000000000000", + "name": "pBNB", + "symbol": "pBNB", + "decimals": 18, + "enabled": true, + "liquidityCap": "1000000000000000000000000", + "tokenType": 1, + "native": { + "contractAddress": "0x7a9082dA308f3fa005beA7dB0d203b3b86664E36" + } + }, + { + "chain": "eip155:97", + "address": "0xA8802F96cAd0d45343d9bc660B6f7d80050A660b", + "name": "USDC.bsc", + "symbol": "USDC.bsc", + "decimals": 6, + "enabled": true, + "liquidityCap": "1000000000000000000000000", + "tokenType": 1, + "native": { + "contractAddress": "0x120EBf25Dad7D6a09Ad2316f23f9Be95DBb90639" + } + }, + { + "chain": "eip155:97", + "address": "0xBC14F348BC9667be46b35Edc9B68653d86013DC5", + "name": "USDT.bsc.old", + "symbol": "USDT.bsc.old", + "decimals": 6, + "enabled": true, + "liquidityCap": "1000000000000000000000000", + "tokenType": 1, + "native": { + "contractAddress": "0x2f98B4235FD2BA0173a2B056D722879360B12E7b" + } + }, + { + "chain": "eip155:97", + "address": "0xE935d9c9C24D02E61186c640cc01d713C876d40F", + "name": "USDT.bsc", + "symbol": "USDT.bsc", + "decimals": 6, + "enabled": true, + "liquidityCap": "1000000000000000000000000", + "tokenType": 1, + "native": { + "contractAddress": "0x731aF1Da5365259d27528557EE4aFBA4baC90ef2" + } + }, + { + "chain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "address": "0x0000000000000000000000000000000000000000", + "name": "pSOL", + "symbol": "pSOL", + "decimals": 9, + "liquidityCap": "1000000000000000000000000", + "tokenType": 4, + "native": { + "contractAddress": "0x5D525Df2bD99a6e7ec58b76aF2fd95F39874EBed" + } + }, + { + "chain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "address": "11111111111111111111111111111111", + "name": "pSOL", + "symbol": "pSOL", + "decimals": 9, + "enabled": true, + "liquidityCap": "1000000000000000000000000", + "tokenType": 4, + "native": { + "contractAddress": "0x5D525Df2bD99a6e7ec58b76aF2fd95F39874EBed" + } + }, + { + "chain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "address": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "name": "USDC.sol", + "symbol": "USDC.sol", + "decimals": 6, + "enabled": true, + "liquidityCap": "1000000000000000000000000", + "tokenType": 4, + "native": { + "contractAddress": "0x04B8F634ABC7C879763F623e0f0550a4b5c4426F" + } + }, + { + "chain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "address": "EiXDnrAg9ea2Q6vEPV7E5TpTU1vh41jcuZqKjU5Dc4ZF", + "name": "USDT.sol", + "symbol": "USDT.sol", + "decimals": 6, + "enabled": true, + "liquidityCap": "1000000000000000000000000", + "tokenType": 4, + "native": { + "contractAddress": "0x4f1A3D22d170a2F4Bddb37845a962322e24f4e34" + } + }, + { + "chain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "address": "G2ZLaRhpohW23KTEX3fBjZXtNTFFwemqCaWWnWVTj4TB", + "name": "DAI.sol", + "symbol": "DAI.sol", + "decimals": 6, + "enabled": true, + "liquidityCap": "1000000000000000000000000", + "tokenType": 4, + "native": { + "contractAddress": "0x5861f56A556c990358cc9cccd8B5baa3767982A8" + } + } + ], + "chainConfigCount": 5, + "chainConfigsRaw": [ + "eip155:11155111", + "eip155:421614", + "eip155:84532", + "eip155:97", + "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1" + ] +} \ No newline at end of file diff --git a/plan/agw/independent-review-creation-flow-2026-10-20/decision-matrix.md b/plan/agw/independent-review-creation-flow-2026-10-20/decision-matrix.md new file mode 100644 index 00000000..ac83a453 --- /dev/null +++ b/plan/agw/independent-review-creation-flow-2026-10-20/decision-matrix.md @@ -0,0 +1,151 @@ +# Decision matrix: AGW creation flow, 20 October 2026 + +"Today" means what works with the deployed v6 contracts and the current public SDK API, with no code changes. Findings (F#) refer to [review.md](review.md). + +## A. Preset routes and default tokens + +| Option | Supported today | Requires SDK work | Requires contract / infra work | +|---|---|---|---| +| A1. Keep the exact protocol tokens and add **node-registered** routes the SDK is missing (Circle USDC on Sepolia, Base and Arbitrum → `0x387b…`, `0x84B6…`, `0xa261…`) | The routes are on-chain, enabled and Vault-backed | An address-keyed AGW route table (the symbol registry cannot hold two USDCs on one chain), then readiness, preparation and a funded E2E | Core/node confirms the `.old` routes are supported for outbound | +| A2. Keep the exact tokens; provision missing routes (LINK ×2, EigenLayer WETH, Base/Arbitrum WETH, WBNB, Venus USDT/USDC, Moonwell ×2) | No | Register them once supplied | Per token: a uregistry `TokenConfig` with PRC20 `native_representation`, PRC20 deploy/init, UniversalCore gas config, inbound gateway threshold, and Vault liquidity from inbound deposits | +| A3. Native export plus destination wrap for the WETH/WBNB legs and EigenLayer WETH | Authorable today as a *custom* rule (`maxValue` on `deposit()`) | `presets.get` refuses native markers in DEX presets and builds swap pairs only from export assets. Needs catalog/generation changes and a check of each router's WETH9 | None (native routes are live) | +| A4. Replace protocol tokens with same-symbol routed mocks | Possible, but unusable | — | No Aave/Venus/Moonwell market or protocol pools exist for the mocks | +| A5. "Partial" presets: export only the routed tokens, and still allow swaps or supplies of a destination-held token | No (swap pins are built from export assets) | Separate "operation tokens" from "export assets" in preset generation | None | + +**Recommendation:** do A1 now, gated on the core confirmation. This turns DEXES Sepolia and LENDING Arbitrum Sepolia ready, and covers the USDC leg of DEXES Base/Arbitrum. + +- Ask product to choose between A3 and A2 for the WETH/WBNB legs and EigenLayer. +- Ask core for A2 on the LINK, Moonwell and Venus tokens. +- Reject A4. +- A5 is optional and needs product sign-off, because it changes what "selected token" means. + +**Change from our recommendation:** "keep actual protocol tokens and obtain PRC20 routes" remains right. However, three of those routes do not need to be "obtained": they already exist in the node registry. The ask to core shrinks from 13 tokens to 10, plus one confirmation. + +## B. Apps optional / transfer-only + +What the contracts require: + +- Universal rules: at least one allowed call, and at least one destination call per request. +- `req.recipient` must be empty, so funds always land in the wallet's CEA. +- Value-only inner calls are refused. +- Solana's System and Token programs are forbidden targets. + +| Option | Today | SDK work | Contract work | What it permits | +|---|---|---|---|---| +| B1. Named recipient allow-list (EVM ERC20) | **Yes, as an explicit rule**: `transfer(address,uint256)` with `arg 0 = R` and `arg 1 ≤ X` | An optional UI/SDK helper that synthesizes the entries (≤32 entries / ≤32 pins; 2 pins each) | None | Exported *and* CEA-held units of each listed token go only to R. Each transfer is ≤ X; there are ≤10 per request and unlimited requests until expiry. Exports are also capped by `maxPerCall`/`maxTotal` | +| B2. Any recipient | Yes (no pin on `to`) | Helper | None | Full custody of CEA-held balances of those tokens. Exports are still capped. **Not recommended** without explicit security sign-off | +| B3. Wallet-owned destination only | `to = CEA` is a self-transfer and does nothing. "Owner's own address on that chain" is B1 with R = owner | The SDK can prefill R when the owner's origin chain equals the destination | None | Same as B1 | +| B4. Keep requiring explicit app functions | Yes (current behavior; `ALLOWED_FUNCTION_REQUIRED`) | Better UI copy only | None | — | +| Native coins on EVM (ETH/BNB) | No agent value-only call. Possible as wrap-then-transfer WETH (two entries) | Helper; the label must say "WETH" | A value-transfer primitive would be contract work | The recipient receives WETH, not ETH | +| Solana SOL/SPL | **No** | — | Allow a constrained transfer path, or deploy a reviewed transfer-router program | — | +| Push native (PC / Push tokens) | Value-only actions to ≤8 fixed recipients; ERC20 `transfer` per token with one pinned recipient (duplicates are refused) | Exposing native `maxValueTotal`, `maxCalls` and `AmountRule` needs a spec/SDK change | None (the contract supports totals) | Per-call caps today; totals are possible with SDK work | + +**Recommendation:** ship B4 now. After product agrees the semantics, build B1 as the "apps optional" option for EVM ERC20 only, with explicit recipients and **per-transfer** caps. Example scope: + +```ts +{ + agent, chainNamespace: 'eip155:11155111', validUntil, maxGasPerCall: parseEther('20'), + assets: [{ token: WETH, maxPerCall: parseEther('0.001'), maxTotal: parseEther('0.01') }], + allowedCalls: [{ target: WETH, selector: 'transfer(address,uint256)', + pins: [{ arg: 0, expected: RECIPIENT }, { arg: 1, max: parseEther('0.001') }] }], +} +``` + +This allows at most 0.001 WETH exported per send and 0.01 WETH exported over the rule's lifetime. It also allows WETH already in the Sepolia CEA to go to `RECIPIENT`, at most 0.001 per transfer, an unlimited number of times until expiry. + +Exclude native coins and Solana from the first version. + +**Change from our recommendation:** the direction is correct. Add three things: +- this needs no contract change for EVM ERC20; +- Solana is contract work, not just "representability limits"; +- B3 is meaningless unless it means the owner's own address. + +## C. No tokens selected / all tokens + +Facts: + +| Topic | Fact | +|---|---| +| General rules | `assets` omitted or `[]` becomes `[{gas PRC20, 0, 0}]` on EVM (`prepare.ts:89-101`) and on Solana (`management/svm-public.ts:45-47`). Nothing can be exported; allowed calls can still use balances the CEA already holds | +| Presets | Omitted means curated defaults with reviewed caps. `[]` means no assets, and readiness reports `ASSETS_REQUIRED` and `TOKEN_PAIR_REQUIRED` | +| Contract | 1..8 explicit assets (`Types.sol:199`; `RulesLib.sol:39`). No wildcard: `address(0)` and `0xEeee…` fail `InvalidAsset`. Future tokens are never implicitly authorized | + +| Option | Today | SDK work | Contract work | +|---|---|---|---| +| C1. `[]` = no export authority (current) | Yes | Wording | None | +| C2. "All supported tokens (N)", expanded to an explicit list ≤8 per chain with per-token caps. Routed counts today: Sepolia 7, Base 5, Arbitrum 5, BNB 4, Solana 4 | Yes for assets and transfer rules. Not for DEX presets (N(N−1)×2 swap entries exceed 32 when N≥5) | Expansion from uregistry or the registry; read decimals on-chain; a reviewed per-token cap table; regenerate when the registry changes | None | +| C3. True wildcard (any current or future PRC20, aggregate cap) | No | — | New asset model, and possibly an oracle for value-based caps | + +**Recommendation:** keep C1. Offer C2 only with caps the user enters or that come from a reviewed table, never implicit maximums, and show the expanded list before signing. C3 needs product and contract design. + +**Change from our recommendation:** none; confirmed. Add that "empty" restricts exports only, not activity with balances the destination already holds. + +## D. Spending-limit scope + +Ship now, with these labels: + +- **"Max per send from Push"** → `assets[i].maxPerCall` +- **"Total sendable from Push with this rule"** → `maxTotal`. Help text: "Counts tokens sent from Push, including sends that later fail on {chain}. Funds already in the wallet's {chain} account are not counted." +- **"Max per action"** → pin `max` / `maxValue`. Help text: "Each action is limited separately. The agent can repeat actions until the rule expires." +- **"Gas budget per transaction (PC)"** → `maxGasPerCall`. Help text: "The most PC attached for gas on one transaction. Unused gas is refunded. There is no total gas limit; the wallet's PC balance is the only limit." +- For DEX presets: "Limits amounts, not price. Swaps can execute at a poor price." +- For lending: "Borrowing is limited per action, not total debt." + +| Want | Requires | +|---|---| +| Sum of calls within one request | Contract | +| Cumulative destination spend per token | Contract (destination accounting) | +| Refund of `maxTotal` after a failed send | Push-core executor calling `creditRevert` | +| Cumulative native (Push) totals | **SDK/spec only** (the contract supports `maxValueTotal`, `maxCalls`, `AmountRule`) | +| Slippage bounds | SDK catalog work (pin `amountOutMinimum` relative to the amount where the protocol allows it) or product acceptance of the risk | + +**Change from our recommendation:** confirmed, with two corrections. `maxTotal` also counts sends that fail on the destination, and native rules *can* enforce totals today at contract level. + +## E. Gas: what each quantity means, and the guidance + +| Quantity | Meaning | Observed | +|---|---|---| +| 1. `maxGasPerCall` | Owner ceiling on the PC `value` attached per request (URP:593) | Preset 20 PC | +| 2. `gasLimit` | Multiplier for the chain's gas price. EVM: gas units. Solana: units × 1000 lamports. 0 means the core base (500,000 EVM; 960 Solana). Below the base reverts | EVM first use 2,000,000 (SDK); subsequent 500,000. Solana 2,285 / 960 | +| 3. Attached PC | The SDK budget: max($1, gas USD), capped at $10, plus protocolFee, converted at the agent-origin rate | 10 PC (Push-native at fixed $0.10) | +| 4. Push signer gas | The agent EOA's own Push transaction fee | 0.00042–0.00053 PC | +| 5. Destination fee | EVM gas used × price; Solana relayer reimbursement | EVM 123k–1.27M gas. Solana 2,184,320 / 695,880 lamports | +| 6. Net consumed / refunded | `SwapAndBurnGas.pcIn` consumed; the remainder refunded in the same transaction (balances confirmed) | 0.0008–2.37 PC consumed; 7.6–10 PC refunded | + +| Option | Today | SDK work | Contract work | +|---|---|---|---| +| E1. Keep 20 PC for presets | Works for Sepolia, Base, Arbitrum and Solana at current prices. **Fails BNB first use** when Donut's BNB gas price is 1.1 gwei | Per-chain caveat | None | +| E2. Per-chain preset ceilings (for example BNB 60 PC) | Yes | Constants | None | +| E3. Quote-driven UI prefill (`max(20 PC, 2 × current first-use attached quote)` for the agent's origin) | No public quote helper | A public read-only `quoteGasBudget(chain, {agentOrigin, firstUse})` (spec addition) | None | +| E4. Size the gas budget from the Donut pool, not USD; fix BNB pricing; stop dropping the over-$10 overflow (F5) | — | Yes | None | +| E5. A cumulative gas cap | — | — | Contract | + +**Recommendation:** + +- Keep the Solana fix. +- Keep 20 PC only as a ceiling, never as an expected fee, and add a BNB-testnet caveat or move to E2 now. +- Do E4 before mainnet. +- The custom-rule prefill of 0.1 PC can never work: the SDK's minimum attached amount is 4.3–11 PC depending on agent origin. **Do not change the SDK's custom-rule default** (zero is rejected for EVM, which is intended). Have the UI prefill with the preset per-chain values, or with E3 once it exists. +- Also reject zero `maxGasPerCall` on Solana (F11). + +**Change from our recommendation:** "20 PC covers the checked quote profiles" must become "covered the runs at these blocks; BNB first use exceeds it at Donut's current BNB gas price". The 10 PC figure must be described as the SDK's floor. + +## F. Solana program coverage + +| Option | Today | SDK work | Contract / infra | +|---|---|---|---| +| F1. Keep `test_counter.receive_spl` | Verified (SPL credit, ATA pin, data ceiling) | Add a wrong-recipient case and full-pin readback | None | +| F2. SPL Memo v2 `MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr` (executable on devnet, not forbidden) | Rule: raw 8-byte prefix plus CEA account pin. Send: synthetic IDL through `utils.svm.registerIdl` | Local URP acceptance and a funded run | Gateway owners confirm a CEA-signed non-Anchor CPI works | +| F3. A third-party devnet protocol | Mostly no (dynamic args, optional accounts and non-Anchor are unsupported in the public API) | Large | — | +| F4. A team-deployed reviewed program with fixed-width args | — | Register the IDL | Program ID, IDL, deployment | + +**Recommendation:** F1 plus F2 for UI E2E. Memo proves a second, non-test-counter program executes under the CEA's signature. It does not test token movement. If token movement through a second program is required, request F4. + +## G. Native function count + +| Option | Today | Work | +|---|---|---| +| G1. Spec says 1..32 for EVM/Solana and 1..8 distinct (target, function) for Push | SDK enforces 8 | Spec/doc only | +| G2. Raise the native ceiling | No | Contract (`MAX_NATIVE_ACTIONS`) and redeploy | + +**Recommendation:** G1, unless product shows a real need for more than 8 Push functions in one rule. Users can also create several rules for the same agent. This is not a delivery blocker. diff --git a/plan/agw/independent-review-creation-flow-2026-10-20/evidence.md b/plan/agw/independent-review-creation-flow-2026-10-20/evidence.md new file mode 100644 index 00000000..f7bd3caf --- /dev/null +++ b/plan/agw/independent-review-creation-flow-2026-10-20/evidence.md @@ -0,0 +1,106 @@ +# Evidence: independent review, 20 October 2026 + +Review window: 16:00Z–16:45Z on 20 October 2026. + +I made no changes to production code, made no commits or pushes, published nothing, deployed nothing and broadcast no transactions. I did not load `.env` files or keys. + +## 1. Revisions and working tree + +### SDK `push-chain-sdk`, branch `feat/agw-sdk-v4` + +- HEAD `525c7186795b43ce1d9c9436701080826b049e22`, which matches `origin/feat/agw-sdk-v4`. +- Working tree at the start and the end of the review was the same 17 entries (`git status --porcelain` md5 `292be838177608c819a080d17cc388ca`). +- Modified, tracked: `packages/core/AGW.md`, `__e2e__/ci/preflight.ts`, `__e2e__/ci/suite.ts`, `src/lib/agentic/execution/svm-public.ts`, `plan/agw/implementation-status.md`, `plan/agw/questions-harsh.md`, `plan/agw/questions-zaryab.md`. +- Untracked: + - `__agw-local__/preset-acceptance.spec.ts` + - `__e2e__/agw/{gas-live,presets-acceptance,svm-agent-spl}.spec.ts` + - `__e2e__/shared/{agw-gas-evidence,agw-preset-acceptance}.ts` + - `scripts/check-agw-{gas-quotes,preset-compatibility}.js` + - `src/lib/agentic/__tests__/svm-send-defaults.spec.ts` + - `plan/agw/research/preset-acceptance-2026-10-20/` +- Every file above was read in full. The raw working-tree diff was taken with `rtk proxy git diff`. + +### Release worktree `push-chain-sdk-agw-v5`, branch `feat/agw-sdk-v5` + +- HEAD `71d556b60f987f8579ef4d639034b86e8dbbb90f`, clean. +- `origin/feat/agw-sdk-v5` = `fa50f367…`, the version-bump commit. +- `git diff 525c7186 71d556b6 -- packages/core/src packages/core/AGW.md` shows only the `package.json` version, so `packages/core/src` is identical at both HEADs. + +### npm + +- `latest` = 6.0.26; `alpha` = 6.0.27-alpha.5, with `gitHead` `71d556b6`. +- Tarball sha256 `fd5b6c0f93da1c87e16e3e16560d683f44fd080278f82bbcafc967fe2695d621`. It contains `const gasLimit = p.gasLimit ?? BigInt(1_000_000);` (`src/lib/agentic/execution/svm-public.js:53`). **The Solana fix is not published.** + +### Contracts, pinned as extracted copies; no checkout was modified + +| Repo | Local HEAD | Pinned for review | Notes | +|---|---|---|---| +| push-agentic-wallets | `main` `9ddd954` (4 September, older design) | `deploy-agw` `e57998c2d8ef` | Its `src/` is identical to the deployed source `ffd567d3e49b` (empty `git diff ffd567d e57998c -- src`). The local harness `/tmp/agw-preset-defaults-v6/.agw-pin` = `ffd567d…` | +| push-chain-core-contracts | `8183-v1` `01439d1` | `main` `b2f22241` | Same commit the earlier route validation used. Deployed UniversalCore differs: it returns 6 values | +| push-chain-gateway-contracts | `pc20-3rd-iteration` `bcbf7df` | `gateway-testnet` `b205770f` | The SVM source declares `DJoF…`; the live gateway is `CFVS…` | +| push-chain (node) | `develop` `cfe8952c` | as-is | Used only for `uregistry` proto definitions | + +Remote heads were read with `git ls-remote`, without fetching. Extraction used `git archive | tar -x` into the session scratchpad. + +**Credential note:** while running `git remote -v` I saw that the three contract repos' `origin` URLs embed a GitHub personal access token in plaintext. I did not record or use it. Consider rotating it and switching to a credential helper. + +## 2. Commands and results + +All runs were from the SDK root unless stated. + +| Check | Result | +|---|---| +| `node node_modules/jest/bin/jest.js --config packages/core/jest.config.ts --runInBand --testPathPattern=agentic/__tests__` (16:39:57Z) | **26 suites, 405 tests passed** | +| `tsc -p packages/core/tsconfig.spec.json --noEmit` | exit 0 | +| `tsc -p packages/core/tsconfig.agw-local.json --noEmit` | exit 0 | +| `AGW_LOCAL_DIR=/tmp/agw-preset-defaults-v6 … jest.agw-local.config.ts --runTestsByPath packages/core/__agw-local__/preset-acceptance.spec.ts` (16:41:05Z, anvil 1.5.1) | **9/9 passed** | +| `eslint` on the 10 changed or new files | 0 errors, 19 warnings (non-null assertions) | +| Core build, package/guide checks | **Not re-run.** I used the existing `dist/` (built 15:25:56Z, after the `svm-public.ts` edit at 15:22:29Z; `dist/…/svm-public.js:56` has `?? BigInt(0)`) | +| Funded live suites | Not run (out of scope) | + +Read-only probes (scripts in `scripts/`, outputs in `data/`): + +| Script | What it does | Endpoint | Pinned block or slot | Time (UTC) | +|---|---|---|---|---| +| `push-probe.cjs` | 10 live Push receipts with `SwapAndBurnGas`, `UniversalTxOutbound` and `OutboundMetered` decoded; UniversalCore fee inputs and quotes; QuoterV2 exact-output gas cost; PC/USD per origin; 18 registry PRC20 metadata | `evm.donut.rpc.push.org` (chain 42101) | 24,457,144 (block time 16:25:31) | 16:25 | +| `uregistry-probe.cjs` | `abci_query /uregistry.v1.Query/AllTokenConfigs` (26 configs, 5 chains), node `pchain v0.0.49` | `donut.rpc.push.org:443` | height 24,457,377 | 16:34 | +| `old-prc20.cjs` | Metadata, supply and outbound quote for the 7 `.old` PRC20s | Donut EVM | 24,457,398 | 16:35:54 | +| `sol-probe.cjs` | Devnet rent; CEA derivation; program accounts; both SPL transactions parsed | `api.devnet.solana.com` (genesis `EtWTRABZ…`) | slot 513,220,877 | 16:29:02 | +| `dest-probe.cjs` | Preset-token code, decimals, Vault balances, inbound support; pools; Aave reserves; EigenLayer underlying; ETH/USD | publicnode Sepolia / Base Sepolia / Arbitrum Sepolia / BSC testnet | 11,956,507 / 48,372,829 / 321,115,011 / 137,918,895 | 16:32:02 | +| `dest-receipts.cjs` | 8 destination receipts with `UniversalTxExecuted`; CEA code and balance; SPL wallet PC deltas at Push 24,455,662→663 and 24,455,694→695 | same | as found | 16:3x | +| `sdk-quotes.cjs` | The SDK's own `agenticRuntime.quoteOutbound` for Push-native, Sepolia-UEA and Solana-UEA signers (read-only clients) | Donut | 24,457,436–24,457,448 | 16:37 | +| `trace-bnb.cjs` | The same quote with `printTraces`, for the BNB first-use case | Donut | ≈24,457,460 | 16:38 | +| `gasprice-history.cjs` | `gasPriceByChainNamespace` every 200 blocks | Donut | 24,455,072–24,457,472 | 16:39 | +| Inline checks | Arbitrum WETH EIP-1967 implementation; explicit EVM gasLimit 100,000 / 499,999 (revert) and 500,001 (ok) | Arbitrum Sepolia, Donut | latest | 16:4x | + +Key values are summarised in [review.md](review.md). The full data is in `data/*.json`. + +## 3. Verifying the existing evidence + +| Claim in the existing evidence | Independent result | +|---|---| +| Ten live destination deliveries | **Confirmed.**
    EVM: all 8 receipts succeeded, sent by relayer `0x9fed…` to the chain's Vault, each with `UniversalTxExecuted` from the expected CEA where `originCaller` = wallet and the target is the counter. Each CEA now holds exactly 2×10¹² wei.
    Solana: both transactions succeeded; vault → CEA ATA → recipient `oVL4…` moved exactly 1000 raw units each, with CEA authority `DKbAi…`; the mint is `EiXD…` on the classic Token program | +| SPL stored spend of 2,000 | `OutboundMetered` amounts 1000 and 1000 in the Push receipts (amounts only) | +| "Each charged a 5,000-lamport fee" | True of the signature fee only. The relayer was reimbursed 2,184,320 and 695,880 lamports | +| Quote figures | `gasLimit` 2,285 / 960 and 2,000,000 / 500,000 reproduced from the `UniversalTxOutbound` events | +| "No claim about net consumption" | Now measured from `SwapAndBurnGas.pcIn` and wallet deltas: 0.0008–2.37 PC consumed, the rest refunded | +| `spl-rejections.json` | Not re-executed; its block and decoded selectors are consistent with the source error names | +| Blocked preset log | Same outcome reproduced through local readiness. The log came from an earlier revision of the spec file (stack lines 200/331 against 211/356 now). The file was modified at 15:43:00Z, after the log at 15:31:51Z | +| Run timing | `gas-live.spec.ts` was modified at 15:33:11Z, during its run (≈15:29:45Z–15:41:40Z), as the README says. `svm-agent-spl.spec.ts` was modified at 15:41:32Z, after the funded run (15:25–15:27Z) | + +## 4. Limitations + +- I ran no funded or live transactions, so F1's routes and F2's native-wrap alternative are unproven end to end. Outbound for the `.old` USDC routes is inferred from registry, metadata, quote and Vault-backing evidence only. +- The node registry was read through `abci_query` with my own protobuf decoder, not an official client. +- The PC/USD, gas-price and BNB-attached figures are point-in-time testnet values that changed during the review window. +- Solana pricing used Donut pools and the SDK's sizing, not an independent SOL/USD feed. +- `isSupportedToken` was read on the external gateways only; the deployed UniversalCore has no such function (it reverted). +- The contract-source analysis is of pinned source, and the deployed core and SVM gateway differ from the pinned commits (F16). Live behaviour was checked empirically wherever it mattered. +- I could not access Harsh's Notion page. Spec text was taken from `plan/agw/research/section6-feedback-2026-10-12/sdk-latest.md` (for example §6.h `allowedCalls: AllowedCall[]; // 1..32`). +- Not re-run: build, package and guide checks, API comparison, and the full 2,181-unit suite. + +## 5. Source changes during the review + +None to production code, tests or existing evidence. The only files I added are under `plan/agw/independent-review-creation-flow-2026-10-20/`: `review.md`, `decision-matrix.md`, `team-questions.md`, `evidence.md`, `data/*.json` and `scripts/*.cjs`. The scripts are read-only probes with no keys; they run from any directory and use the SDK's `node_modules`. + +`npm pack` of 6.0.27-alpha.5 was extracted only inside the session scratchpad. No other process wrote to `dist/`, `e2e-logs/` or the contract checkouts. diff --git a/plan/agw/independent-review-creation-flow-2026-10-20/review.md b/plan/agw/independent-review-creation-flow-2026-10-20/review.md new file mode 100644 index 00000000..6e518e7c --- /dev/null +++ b/plan/agw/independent-review-creation-flow-2026-10-20/review.md @@ -0,0 +1,402 @@ +# Independent review: AGW creation flow, 20 October 2026 + +This is an engineering review, not a full security audit. Baseline, commands, block numbers and limitations are in [evidence.md](evidence.md). Raw results are in `data/` and the read-only scripts that produced them are in `scripts/`. + +References use these roots: + +- `sdk/` = `packages/core/src/lib/` +- `URP` = the deployed AGW source at `ffd567d` (`src/policies/UniversalRulesPolicy.sol`). It was extracted from `deploy-agw@e57998c`, whose `src/` is byte-identical. + +## Overall verdict + +1. **The Solana omitted-gas change is correct, and strictly better than before. Ship it.** + - The old `1,000,000` input could never succeed. The SDK capped the gas budget at $10 (100 PC with a Push-native agent), but the gas swap needed about 906 PC at Donut block 24,457,144, so the swap would revert. With a ceiling under 100 PC, the policy refused the send first. + - The new path (input 0) behaves as follows: + - Core substitutes its base limit of 960. + - The SDK raises the gas budget to cover finalization rent. + - This was verified live for a first SPL send (gas limit 2,285) and a later one (960), and re-derived independently from Solana transactions. + - The fix is uncommitted on v4. Published `6.0.27-alpha.5` still uses `BigInt(1_000_000)`. + +2. **Our preset-route conclusion is partly wrong.** Three default tokens that we report as having no route are Circle USDC on Sepolia, Base Sepolia and Arbitrum Sepolia. All three have **enabled, inbound-backed node routes** that the SDK registry simply omits (F1). + - With SDK registry work alone, plus a core confirmation, **DEXES Sepolia** and **LENDING Arbitrum Sepolia** can become route-ready. + - DEXES on Base and Arbitrum would still lack their WETH leg. + - The other five presets need external provisioning, or a product-approved change of asset. + +3. **Apps-optional, all-tokens and spending limits** are constrained by contract facts we have now verified (Findings F7, F10, F11). + - The contracts require at least one allowed function and at least one destination call per request. + - There is no asset wildcard; a rule holds 1 to 8 explicit assets. + - Every destination-side limit applies per call. + - EVM transfer-only rules can already be written with the public API today. + - Solana transfer-only rules are impossible without contract work, because the System and SPL Token programs are forbidden targets. + +4. **Gas guidance must change.** + - The uniform "10 PC" observations come from the SDK: a $1 minimum budget, converted at a hardcoded $0.10 per PC for Push-native signers. + - Measured consumption was 0.0008–2.37 PC per send. The remainder was refunded in the same transaction (confirmed from wallet balances). + - 20 PC is not robust: BNB-testnet first use exceeded it during this review (F4). + - Two existing SDK gas-sizing bugs affect AGW (F5). + +5. **The tests are better than average** and do what they say. The gaps are listed in F8. Nothing hides a skip or passes unconditionally. The nine live preset cases are blocked, not passing. + +## Findings, by severity + +Classification for each finding: + +- **Type:** bug / evidence correction / ambiguity / product decision / external dependency. +- **Blocks:** publication / preset usability / extension only. + +### F1 — High: Circle USDC routes exist on the node but are missing from the SDK registry +**Type:** evidence correction and SDK registry omission. **Blocks:** preset usability (four of the nine presets depend on it). + +The node's `uregistry` `AllTokenConfigs` (read via `abci_query` at height 24,457,377; `data/uregistry.json`) lists: + +| Source chain | Exact token (Circle USDC) | Node PRC20 | Node label | +|---|---|---|---| +| eip155:11155111 | `0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238` | `0x387b9C8Db60E74999aAAC5A2b7825b400F12d68E` | USDC.eth.old, enabled | +| eip155:84532 | `0x036CbD53842c5426634e7929541eC2318f3dCF7e` | `0x84B62e44F667F692F7739Ca6040cD17DA02068A8` | USDC.base.old, enabled | +| eip155:421614 | `0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d` | `0xa261A10e94aE4bA88EE8c5845CbE7266bD679DD6` | USDC.arb.old, enabled | + +On-chain checks at Donut block 24,457,398 (`data/old-prc20.json`): + +- `SOURCE_CHAIN_NAMESPACE` and `SOURCE_TOKEN_ADDRESS` match exactly. Sepolia returns an address word; Base and Arbitrum return strings. +- `decimals = 6`, which matches the preset `stable6` budget. +- `getOutboundTxGasAndFees` succeeds. +- Total supply minus a 1,200,000 premint equals the destination Vault balance: + - exactly 1,126.991 on Base; + - exactly 157.3 on Arbitrum; + - 120,454.41 against a Vault holding 120,464.41 on Sepolia. + + So these are inbound-backed, settled routes (`data/dest-probe.json`). + +The registry also has `.old` USDT routes for all four EVM chains, but those are not preset tokens. + +Two earlier statements are wrong: + +- [token-route-validation README](../research/token-route-validation-2026-10-20/README.md) says: "Existing USDC PRC20 metadata points at different mock token addresses". That is true only for the PRC20s the SDK registers. +- [questions-zaryab.md](../questions-zaryab.md) asks the team for mappings that can be read from the node. + +The reason they were missed: the SDK registry is keyed by symbol. `sdk/universal/prc20-address.ts:126-179` maps (chain, symbol) to one `SYNTHETIC_PUSH_ERC20` key, so it cannot hold two USDCs on one chain. Both the compatibility script and the probe searched only that registry. + +What becomes possible: + +| Preset | Before | With F1 | +|---|---|---| +| DEXES Sepolia | WETH routed, USDC missing | **both routed**. A WETH/USDC pool has liquidity (fee 500: L=1.30e16; `data/dest-probe.json`) | +| LENDING Arbitrum Sepolia | USDC missing | **routed**. The Aave reserve is this exact Circle USDC | +| DEXES Base / Arbitrum | both missing | USDC routed; WETH still missing (F2) | + +Recommendation: + +1. Ask core/node to confirm the `.old` routes are supported for outbound and are not being retired. +2. Then add an **address-keyed** AGW route table (chain + exact source address → PRC20) that `presetRoutes` (`sdk/agentic/presets/routes.ts:34-52`) and `resolvePrc20` (`sdk/agentic/runtime.ts:169-187`) consult before the symbol path. Keep the on-chain source check in `prepare.ts:135-154`. +3. Run a funded E2E before calling these presets usable. + +### F2 — High: the remaining preset tokens need provisioning, or a product-approved native-wrap variant +**Type:** external dependency or product decision. **Blocks:** preset usability. + +None of these tokens appears in `uregistry`: + +| Chain | Token | Preset(s) | Vault balance | WETH9 `deposit()` | +|---|---|---|---|---| +| Sepolia | Aave LINK `0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5` | LENDING | 0 | n/a | +| Sepolia | EigenLayer WETH `0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9` | STAKING | 0 | yes | +| Base Sepolia | WETH `0x4200000000000000000000000000000000000006` | DEXES | 0 | yes | +| Base Sepolia | Aave LINK `0x810D46F9a9027E28F9B01F75E2bdde839dA61115` | LENDING | 0 | n/a | +| Base Sepolia | Moonwell USDbC `0x4616975f7E6045FD9737e95bC527e9e14c727BD2`, Moonwell WETH `0x663A6F02d547dFd639BF689FED298712f2FB69Fb` | LENDING | 0 | WETH: yes | +| Arbitrum Sepolia | WETH `0x980B62Da83eFf3D4576C647993b0c1D7faf17c73` | DEXES | 0 | yes (proxy implementation `0x3031a6d5…`) | +| BNB testnet | WBNB `0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd` | DEXES | 0 | yes | +| BNB testnet | USDT `0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c`, USDC `0x16227D60f7a0e586C66B005219dfc887D13C9531` | DEXES / LENDING | 0 | n/a | + +**An alternative we had not considered: native export plus wrap.** + +- The native PRC20 routes (pETH, pETH.base, pETH.arb, pBNB) are live. `gas-live.spec.ts` proved native export into the CEA on all four testnets. +- The CEA multicall can call `WETH.deposit{value}`. A universal rule can authorize that, because `maxValue` is a per-entry value cap (URP:902-906). +- Uniswap's SwapRouter02 can also wrap when `msg.value` is sent with `tokenIn = WETH9`. That needs the router's WETH9 to be verified first. + +This covers the wrapped-native leg of DEXES on Base, Arbitrum and BNB, and the Sepolia EigenLayer WETH. Aave's Base WETH reserve is `0x4200…06` itself. + +It is **not** reachable through `presets.get` today: + +- DEX presets refuse native markers (`sdk/agentic/presets/index.ts:233-243`). +- Swap pairs are generated only from export assets (`:268-296`). + +It changes the preset's export asset (ETH instead of WETH) and adds a wrap permission, so it needs product approval and SDK catalog work. No contract change is required. + +**What stays blocked even then:** LENDING Sepolia (LINK), LENDING Base (LINK, Moonwell), LENDING BNB and the DEXES BNB USDT leg (Venus tokens). These need provisioning, or a different reviewed protocol asset. + +### F3 — High: "10 PC" is an SDK floor, not a fee; attached, consumed and refunded amounts are now measured +**Type:** evidence correction. **Blocks:** publication of gas guidance. + +How the SDK sizes the gas budget: + +- `sdk/orchestrator/internals/gas-usd-sizer.ts:105-117` puts the budget in one of three bands: + - below $1: raised to $1; + - $1 to $10: passed through; + - above $10: capped at $10. +- `pc-usd-oracle.ts:42-48` has no Push Chain origin, so a Push-native signer falls back to `usdcToPush` at a fixed $0.10 (`pc-usd-oracle.ts:322-333`). That makes $1 exactly 10 PC. +- The E2E agents and `check-agw-gas-quotes.js` all sign as Push-native, so every observation was this floor. + +A signer from another chain is priced through the Donut WPC/USDT pool for its origin. At the review blocks (`data/push-probe.json`, `data/sdk-quotes.json`): + +| Signer origin | PC/USD | $1 minimum attached | +|---|---|---| +| Push-native (fixed fallback) | $0.10 | 10 PC | +| Ethereum Sepolia UEA | $0.2326 | 4.30 PC | +| Arbitrum Sepolia | $0.0988 | ≈10.1 PC | +| Base Sepolia | $0.0993 | ≈10.1 PC | +| BNB testnet | $0.1031 | ≈9.7 PC | +| Solana UEA | $0.0910 | 10.99 PC | + +Measured from the live receipts (`SwapAndBurnGas.pcIn`; `data/push-probe.json`). Each send attached 10 PC: + +| Send | gasLimit used | gasFee | PC consumed by gas swap | Refunded | +|---|---:|---:|---:|---:| +| SPL first use | 2,285 | 2,285,000 lamports | 2.0697 | 7.93 | +| SPL subsequent | 960 | 960,000 lamports | 0.8695 | 9.13 | +| Sepolia first / subsequent | 2,000,000 / 500,000 | 2.20e12 / 5.50e11 wei | 0.0032 / 0.0008 | ≈10 | +| Base first / subsequent | 2,000,000 / 500,000 | 1.32e13 / 3.30e12 | 0.5915 / 0.1479 | 9.41 / 9.85 | +| Arbitrum first / subsequent | 2,000,000 / 500,000 | 4.52e13 / 1.13e13 | 1.9297 / 0.4820 | 8.07 / 9.52 | +| BNB first / subsequent | 2,000,000 / 500,000 | 2.20e14 / 5.50e13 | 2.3652 / 0.5913 | 7.63 / 9.41 | + +The refund is confirmed: + +- The SPL wallet's PC balance fell by exactly `pcIn` at Push blocks 24,455,663 and 24,455,695: −2.06965 and −0.86953 PC (`data/dest-receipts.json`). +- `swapAndBurnGas` refunds `msg.value − amountInUsed` to the caller. + +Separately, the agent's own Push gas was 0.00042–0.00053 PC per send. + +Recommendation: report all six quantities separately (see the decision matrix, E). Remove "10 PC quoted" as a fee claim. + +### F4 — High: a 20 PC ceiling fails BNB-testnet first use at current Donut gas prices +**Type:** confirmed risk. **Blocks:** preset usability on BNB; the 20 PC guidance. + +- Donut's BNB `gasPriceByChainNamespace` read 55,000,000 / 110,000,000 / 1,100,000,000 wei across blocks 24,455,072–24,457,472, roughly 100 minutes (`data/gasprice-history.json`). The live BNB test ran at 0.11 gwei. Other chains were stable. +- At 1.1 gwei, a first BNB send (2,000,000 gas, 0.0022 BNB) attaches: + - 53.5 PC for a Push-native signer (traced; `scripts/trace-bnb.cjs`); + - 23.0 PC for a Sepolia UEA; + - 58.8 PC for a Solana UEA. + + Every one is above 20 PC, so URP refuses with `PCValueExceedsCap` (URP:593). The refusal is safe: it is decoded before broadcast into "The required gas exceeds this rule's gas budget" (`sdk/agentic/error-messages.ts:146`). +- Subsequent BNB sends still fit: 13.4 / 5.75 / 14.7 PC. +- Part of the excess is F5(a). + +### F5 — High (existing SDK bugs, not caused by this change): gas sizing does not match what the gateway charges +**Type:** confirmed bugs. **Blocks:** none on these testnets except the cases noted; they block mainnet use and explicit large gas limits. + +**(a) BNB gas is priced with ETH/USD.** +- `gas-usd-sizer.ts:74-77` uses Sepolia for every EVM destination, and its log labels BNB gas as "pETH". +- At ETH $2,432 this inflates BNB budgets by about the ETH/BNB price ratio. + +**(b) The over-$10 overflow is dropped on the AGW path.** +- `gas-calculator.ts:253` returns `gasLegNativePc + protocolFee`, and `sdk/agentic/runtime.ts:141-159` passes only that value on. +- The gateway does an exact-output swap for the full `gasFee` (core `UniversalCore.sol:224-246`), so it reverts. +- Example: the legacy 1,000,000 Solana input attaches 100 / 43.0 / 109.9 PC, depending on origin, against 905.8 PC required. + +**(c) The SDK sizes by dollars, but the contract pays the Donut pool rate.** +- A Sepolia-UEA BNB first send attaches 23.00 PC, but the pool quote needs 23.65 PC. The swap would revert even under a high ceiling. + +Recommendation (SDK-only): +- Size the gas budget from Donut QuoterV2 `quoteExactOutputSingle(WPC → gasToken, gasFee)` plus headroom. +- Fail before signing when the result exceeds the rule's `maxGasPerCall`, using a typed error. +- Fix the BNB price source. + +### F6 — Medium: the compatibility method was narrower than our conclusions +**Type:** evidence correction. + +What `scripts/check-agw-preset-compatibility.js` actually covers: + +- Candidates are only the SDK `MOVEABLE_TOKENS` entries that map through the symbol registry (`:61-104`). +- Native routes are skipped (`:65`). +- DEX pools are searched only between pairs where *both* tokens are routed (`:133-150`). That misses the useful case of one routed token traded against a destination-held token. +- The script does treat RPC errors correctly as failures, both per pool and per protocol, with a non-zero exit. One gap: a candidate whose Push `SOURCE_*` read fails is silently recorded as `unavailable`, with no exit-code impact (`:101-107`). + +The external gateway's `isSupportedToken` is an **inbound** allow-list: + +- `UniversalGateway.sol:770`: `tokenToLimitThreshold[token] != 0`, used only in `_handleDeposits`. +- Outbound ERC20 settlement needs Vault liquidity (`Vault.sol:417-423`). Native outbound is funded from the TSS balance. + +So "allow-listed" never proved route availability. The Vault balances above are the relevant check. + +Our "no substitution" recommendation still stands, now for the right reason: same-symbol mocks have no Aave, Moonwell or Venus market and no protocol pools. + +### F7 — Medium: spending limits are narrower than "spending limit" suggests +**Type:** product decision and wording. **Blocks:** UI copy for publication. + +Verified in source: + +- `assets[i].maxPerCall` and `maxTotal` meter only `req.amount` exported from Push. The check is at URP:584-591; spend is written at :605-608, only when `amount > 0`. +- `creditRevert` is inactive (URP:1052-1054), so **a send that later fails on the destination still consumes `maxTotal`**. +- Destination pins (`EQ`/`MAX`) and `maxValue` are checked per inner call (URP:775-791, 879-938). There is no sum within a request (up to 10 calls, URP:81, 770) and none across requests. +- Balances already held in the CEA can be redeployed until the rule expires. The contract docs say so: `docs/1_AGW.md:454`, `docs/5_SDK_Owner_Integration.md:226`. +- `maxGasPerCall` bounds the PC attached to each request (URP:593). There is no gas counter (URP:1055-1056); only the wallet's PC balance bounds cumulative gas. +- Preset DEX swap pins fix tokenIn, tokenOut, recipient and the input amount. They do not fix the fee tier, `amountOutMinimum` or the price limit (`presets/index.ts:283-296`). The value lost to slippage or a manipulated pool is bounded only per call. +- Lending `borrow` is capped per call; cumulative debt is not. +- `approve` caps each allowance, not cumulative pulls. +- Native Push rules differ: + - The contract supports `maxValueTotal`, `maxCalls` and a cumulative `AmountRule` (URP:672-735). + - The public SDK shape hard-codes unlimited totals and calls (`sdk/agentic/public-rule.ts:255-263`) and rejects `amount` / `maxValueTotal` / `maxCalls` (`:128-144, 171-183`). + + So stronger native totals need SDK and spec work only, not contract work. + +### F8 — Medium: test gaps (no false passes found) +**Type:** test quality. **Blocks:** none, but some claims should be narrowed. + +1. `expectStoredPreset` (`__e2e__/shared/agw-preset-acceptance.ts:55-108`) does not assert `expectedCEA`, and the local suite mocks the CEA (`__agw-local__/preset-acceptance.spec.ts:27-30`). The live suite does assert it (`presets-acceptance.spec.ts:252-265`). So for the local suite, "destination identity is compared" is not true. +2. The SPL readback uses `toMatchObject` with `arrayContaining`, which checks the assets and only the account-1 pin (`svm-agent-spl.spec.ts:121-137`). The counter, recipient-ATA, CEA and token-program pins, and the data ceiling, are not compared. There is no wrong-recipient rejection case. The data ceiling and the account-1 pin are proven by the decoded rejections. +3. The live preset suite funds the fresh agent 0.5 PC in `setupAgw()` (`_fixture.ts`) before the pool, protocol and owner-PRC20 prerequisite checks (`presets-acceptance.spec.ts:216-247`). Only the route-readiness check is truly before funding. +4. `live-presets-blocked.log` cites spec lines 200 and 331. The current file throws at line 211 with case 1 at line 356, and it was edited at 15:43:00Z, after the 15:31Z log. The blocked outcome is determined by unchanged `src` readiness code, but the current spec revision has never run. +5. `svm-send-defaults.spec.ts` covers only the owner funds-only native-SOL path, and mocks `quoteOutbound`, so the finalize floor is not exercised. The agent door's omitted gas is covered only by the live run. +6. `check-agw-gas-quotes.js` cannot observe anything but the floor (F3). It omits gasFee, gasPrice, USD band, pool cost and the SPL first-use ATA case. +7. The live preset operation builders were reviewed and are consistent: + - token and market order (Venus vUSDT first, Base LINK supply first); + - `approve` before the call; + - recipient pinned to the CEA; + - spend metered at 1× then 2×. + + They test one swap direction only, and use `amountOutMinimum: 1`. + +What is right: the EVM gas test proves the CEA had no code before first use, exact native credit, `UniversalTxExecuted` from the CEA with `originCaller` = wallet, and spend. I re-verified all eight destination receipts myself (`data/dest-receipts.json`). The SPL test proves delivery with exact amounts; I re-verified the Solana transactions, the CEA derivation, the ATA owner, the mint and the token program. + +### F9 — Medium: Solana destination cost is misreported +**Type:** evidence correction. + +- The README says each Solana send "charged a 5,000-lamport transaction fee". That is the relayer's signature fee only. +- The gateway reimbursed the relayer **2,184,320** lamports (first use: 5,000 + 690,880 `ExecutedSubTx` rent + 1,488,440 CEA-ATA rent) and **695,880** lamports (subsequent), out of `gas_fee` budgets of 2,285,000 and 960,000 (`data/sol-probe.json`). +- Devnet rent is now 690,880 lamports for 8 bytes and 1,488,440 for 165 bytes. The SDK's fallback constants (946,560 and 2,039,280; `svm-rent.ts:37-40`) are higher. That is safe, because they over-budget. + +### F10 — Medium: Solana transfer-only rules are impossible under the current contracts +**Type:** contract constraint. **Blocks:** extension only. + +`SvmRulebook.sol:30-41` forbids the System, SPL Token, Token-2022, Stake, BPF-loader and lookup-table programs, as well as the gateway and the CEA. Agents also cannot send funds without an instruction (`SvmPayloadEmpty`, :525). So SOL or SPL can reach a third party only through an allow-listed program's CPI, as `test_counter.receive_spl` does. + +### F11 — Medium: public Solana authoring is narrower than the contract +**Type:** ambiguity / capability gap. **Blocks:** extension only. + +| | Contract (`SvmRulebook`) | Public API | +|---|---|---| +| Discriminators | 1–8 bytes, or dataless (:176) | 8 bytes only: Anchor-derived or raw 16-hex (`public-rule.ts:347-368`) | +| Data pins | EQ / GTE / LTE / RATIO, with `fromEnd` | equals or max on fixed-width named args | +| Send-time accounts | — | Resolved from a registered Anchor-style IDL: fixed address, const-seed PDA, or `cea_authority` (`sdk/orchestrator/svm-idl/resolve.ts:55-128`) | + +Unsupported in the public API: short or non-Anchor discriminators, dataless instructions, dynamic args (vec / string / option), optional accounts and nested account groups. The contract cannot parse dynamic args either; it offers only `fromEnd` scalars. + +Related: a Solana rule with `maxGasPerCall = 0` is accepted by the SDK (`codec/svm-terms.ts:175`), while EVM rejects it (`codec/universal.ts:53-54`). Every agent send would then fail. + +### F12 — Medium: Solana SPL PRC20s do not identify their mint on-chain +**Type:** ambiguity. + +- `SOURCE_TOKEN_ADDRESS` returns a zero word for USDT.sol, USDC.sol, DAI.sol and pSOL (`data/push-probe.json`). +- `readSvmSourceToken` then falls back to the SDK's own registry (`sdk/agentic/contracts/prc20-metadata.ts:51-72`), so the mint is not verified on-chain. +- `uregistry` has the authoritative mapping. For USDT it is `EiXDnrAg…` → `0x4f1A…`, which matches the SDK. + +Recommendation: verify against `uregistry`, or snapshot it in tests. + +### F13 — Low: Base Sepolia WETH registry entry is wrong (existing bug) +**Type:** data bug. + +`sdk/constants/tokens.ts:234-239` lists Base Sepolia WETH at `0xfff9976782d46cc05630d1f6ebab18b2324d6b14`, which is the Ethereum Sepolia address. That address has no code on Base Sepolia (`data/dest-probe.json`). AGW is currently unaffected, because the symbol switch refuses non-Sepolia WETH. + +### F14 — Low: `protocolFee` is counted twice in attached value (latent) +**Type:** latent bug. + +`nativeValueForGas` already includes `protocolFee` (`gas-calculator.ts:253`). `outbound.ts:235-236` and `svm-public.ts:169, 188-190` add it again to `value` and also pass it as `maxPCForGas`. With a non-zero fee, a send would over-attach and use more of the `maxGasPerCall` ceiling. `protocolFee` is 0 on every PRC20 checked. + +### F15 — Low: Solana finalize margin and gas-limit inputs +**Type:** robustness and documentation. + +- The finalize floor's only margin is the 100,000-lamport buffer, about 4.6% of the first-use budget. A drop in Donut's Solana gasPrice between quote and execution larger than that would underfund the send (`InsufficientGasBudget` on Solana). The gasPrice was a constant 1000 across the sample. +- A re-quote that is still insufficient only logs a warning (`svm-rent.ts:253-258`). +- An explicit `gasLimit` below the chain base (960 on Solana devnet, 500,000 on the EVM testnets) reverts at quote time on deployed core (`data/sdk-quotes.json`; 500,001 is accepted). Document that inputs must be 0 or at least the base. + +### F16 — Info: baseline drift and other notes + +- The local contract checkout is on stale `main` (`9ddd954`, 4 September, a different design). The deployed source is `deploy-agw` / `ffd567d`. +- Core `main` (`b2f22241`) returns 5 values from `getOutboundTxGasAndFees`; deployed core returns 6. The pinned SVM gateway source declares `DJoF…`; the SDK and the live transactions use `CFVS…`. Live behaviour was therefore verified empirically. +- The EigenLayer `depositIntoStrategy` strategy argument is unpinned. Deposits credit the CEA, and only whitelisted strategies are accepted. + +## Specific answers + +**A.** +- Omissions in the SDK registry: the three Circle USDC routes (F1). +- Routes that need provisioning: the table in F2. +- The external allow-list does not establish route availability (F6). +- Metadata handling: string and address-word metadata are handled. Solana mints are not identified on-chain (F12). +- The compatibility scope was too narrow (F6). RPC errors were not turned into "unsupported", except the candidate-read gap noted in F6. +- The native-wrap alternative is viable but needs product approval (F2). + +**B.** +- At least one call is required, by both contracts and both doors. +- EVM ERC20 transfer rules are fully SDK-side, and already expressible with the public API. +- Native coins are not expressible as value-only agent calls (URP:784; `outbound.ts:210-221`). +- Solana is impossible (F10). +- On Push, value-only `VALUE_SELECTOR` actions go to up to 8 fixed recipients. +- See the decision matrix for the comparison of options. + +**C.** `[]` (or omitted assets, in general rules) means one zero-cap gas-PRC20 entry on both EVM and Solana (`prepare.ts:89-101`; `management/svm-public.ts:45-47`), so nothing can be exported from Push. Calls the rule allows can still use balances the CEA already holds. + +**D.** See F7. + +**E.** See F3, F4, F5, F9 and F15. The decision matrix gives the recommendation. + +**F.** The SPL test proves what it claims (F8). Candidate extra program: SPL Memo v2 `MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr`, verified executable on devnet (`data/sol-probe.json`) and not forbidden. It needs: + +- a raw 8-byte memo-prefix discriminator; +- a CEA account pin; +- a synthetic IDL registered through `PushChain.utils.svm.registerIdl`. + +It has not been verified through the gateway and URP. It moves no tokens. + +**G.** +- Deployed: `MAX_NATIVE_ACTIONS = 8` distinct (target, selector) pairs. Pins do not count; duplicates are refused with `DuplicateAction` (AGW.sol:86, 738, 765). +- Universal EVM rules allow 1–32 entries (URP:84, 347-350); Solana allows 1–32 programs. +- The SDK enforces 8 for native rules (`public-rule.ts:211-215`). + +This is a spec clarification, unless product needs more than 8 native functions. + +## Addendum, 21 October 2026: SDK changes made after the review + +All changes are local, uncommitted, on v4. Results are in `data/post-change-*.json`. + +| Finding | Status | Change | +|---|---|---| +| F1 | SDK side done; core confirmation pending | `agentic/token-routes.ts` resolves the three node-registered Circle USDC routes by exact address, for AGW only. DEXES Sepolia and LENDING Arbitrum Sepolia are route-ready | +| F5(a) | Fixed | BNB testnet gas is valued at the Push pool rate in `gas-usd-sizer.ts`, because no BNB/USD feed exists (the BSC gateway feed is ETH/USD). Route 2 and Route 3 already floored at the pool cost | +| F5(b)(c) | Fixed for AGW | `agwGasBudget` keeps the over-$10 share and never attaches less than the pool cost plus 20% | +| F6 | Fixed | The compatibility script includes exact routes, separates read errors from missing routes, and searches each DEX preset's own pair. The new `check-agw-route-registry.js` compares the SDK with uregistry: 20 match, 0 mismatch | +| F8(1) | Fixed | The local suite asserts the stored `expectedCEA` | +| F8(2) | Fixed | The SPL readback compares every pin, the data ceiling and the program exactly; the wrong-recipient refusal is added. Both were checked read-only against the Oct 20 rule (`data/spl-*.json`) | +| F8(3) | Fixed | The live preset suite funds the agent only after its prerequisites pass. The new opt-in group `agw-presets-routed` covers the two ready presets | +| F8(5) | Fixed | Agent-door omitted-gas unit test added | +| F8(6) | Fixed | The quote script records signer origin, gas fee, pool cost and the SPL first-use case | +| F11 (Solana zero gas) | Fixed | `preparePublicSvmRule` rejects `maxGasPerCall = 0` | +| F13 | Fixed | Base Sepolia WETH address corrected | +| F14 | Fixed (latent) | AGW's `nativeValueForGas` excludes protocolFee | +| F15 | Fixed | An explicit gasLimit below the chain base is refused before quoting with `INVALID_RULE` and `details.minimum`. A Solana budget still short after one re-quote is refused before signing (`INCONSISTENT_READ`) | + +New finding from the drift check: the SDK cannot resolve DAI.sol. Its PRC20 is registered, but `getPRC20Address` has no `DAI` case. Not preset-relevant; left unchanged. + +Validation: 2,276 units passed and 12 skipped; 9/9 local v6 preset cases pass; lib, spec, agw-local and marketplace-local typechecks and the core build pass; ESLint reports 0 errors. + +### Live validation of the changes, 21 October (02:23–02:40Z) + +These runs used the post-change working tree. + +- **`agw-svm-agent-spl`: 1/1 passed.** This included the new exact-pin readback, the data ceiling and program checks, and the wrong-recipient refusal. Both omitted-gas SPL sends were delivered (Push blocks 24,471,877 and 24,471,906). +- **`agw-gas`: 4/4 passed.** Sepolia, Base Sepolia, Arbitrum Sepolia and BNB testnet each had a first and a subsequent send: eight destination deliveries, checked against the CEA. +- **Gas.** Every send attached 10 PC. The pool cost recorded for each was 0.0002–2.07 PC. +- **Not exercised.** BNB's Donut gas price was 0.055 gwei during the run, so the high-gas BNB case, where the pool floor exceeds the sized budget, was not hit live. It is covered by unit tests only. + +Evidence: `data/live-2026-10-21-evidence.json` and `data/live-2026-10-21-results.log`. Still not run: `agw-presets-routed`. It needs the owner to hold WETH.eth and Circle USDC (Arbitrum) PRC20s, and core still has to confirm the routes. + +### Routed presets live, 21 October (02:48–03:03Z) + +The owner bought 0.199606 USDC.eth.old and 0.197913 USDC.arb.old on Donut's Uniswap pools for 2 PC each (txs `0x9de1…6dbc` and `0xab55…7138`). + +- **LENDING Arbitrum Sepolia: passed.** Two agent sends exported Circle USDC through the `.old` route and supplied it to Aave. Destination gas used: 536,341 and 292,561. This is the first live proof that a node-registered Circle USDC route settles outbound. +- **DEXES Sepolia: the first run failed on the subsequent send.** + - The first send passed: 1,502,039 gas at the 2,000,000 first-use limit. + - The subsequent send ran at the 500,000 network base and reverted on Sepolia with CEA `ExecutionFailed` (`0xacfdb444`, tx `0xe480…e336`). + - The call trace (`data/sepolia-dex-subsequent-oog-trace.json`) shows `pool.swap` out of gas. The vault's Circle USDC transfer and the approve took most of the budget, and nested calls forward only part of the remaining gas. +- **SDK fix.** Agent EVM sends without an explicit gasLimit now use 1,000,000 when they export a non-native token or make more than one call; first use stays at 2,000,000. The swap direction followed the owner's holdings: the test now starts from the held default asset, here USDC→WETH. +- **DEXES Sepolia re-run: passed.** Destination gas used: 1,502,063 and 362,079. + +Both route-ready presets have now passed unchanged-preset live acceptance (`data/live-2026-10-21-routed-presets.json`). Full unit suite after the fix: 2,278 passed, 12 skipped. diff --git a/plan/agw/independent-review-creation-flow-2026-10-20/scripts/dest-probe.cjs b/plan/agw/independent-review-creation-flow-2026-10-20/scripts/dest-probe.cjs new file mode 100644 index 00000000..a39a1887 --- /dev/null +++ b/plan/agw/independent-review-creation-flow-2026-10-20/scripts/dest-probe.cjs @@ -0,0 +1,132 @@ +// Independent read-only destination probe (EVM testnets). No keys, no signing. +const fs = require('node:fs'); +const SDK = '/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk'; +const { createPublicClient, http, parseAbi, getAddress, zeroAddress } = require(SDK + '/node_modules/viem'); +const err = (e) => (e && (e.shortMessage || e.message) || String(e)).slice(0, 200); +const big = (_k, v) => (typeof v === 'bigint' ? v.toString() : v); +const abi = parseAbi([ + 'function symbol() view returns (string)', + 'function decimals() view returns (uint8)', + 'function balanceOf(address) view returns (uint256)', + 'function factory() view returns (address)', + 'function getPool(address,address,uint24) view returns (address)', + 'function liquidity() view returns (uint128)', + 'function getReservesList() view returns (address[])', + 'function underlyingToken() view returns (address)', + 'function getEthUsdPrice() view returns (uint256,uint8)', + 'function isSupportedToken(address) view returns (bool)', +]); +const C = { + 'eip155:11155111': { + rpc: 'https://ethereum-sepolia-rpc.publicnode.com', vault: '0xD019Eb12D0d6eF8D299661f22B4B7d262eD4b965', + gateway: '0x05bD7a3D18324c1F7e216f7fBF2b15985aE5281A', router: '0x3bFA4769FB09eefC5a80d6E87c3B9C650f7Ae48E', + aave: '0x6Ae43d3271ff6888e7Fc43Fd7321a503ff738951', eigenStrategy: '0x424246eF71b01ee33aA33aC590fd9a0855F5eFbc', + tokens: { + 'WETH(dex)': '0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14', 'USDC(circle,dex)': '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238', + 'LINK(aave,lending)': '0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5', 'WETH(eigen,staking)': '0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9', + 'USDT(routed mock)': '0xC4230aEaFcF6b8B49a7b4e53886420f00ff71876', 'USDC(routed mock)': '0x97F477B7f970D47a87B42869ceeace218106152a', + 'stETH(routed)': '0x3e3FE7dBc6B4C189E7128855dD526361c49b40Af', + }, + pairs: [['WETH(dex)', 'USDC(circle,dex)'], ['WETH(dex)', 'USDC(routed mock)'], ['WETH(dex)', 'USDT(routed mock)']], + }, + 'eip155:84532': { + rpc: 'https://base-sepolia-rpc.publicnode.com', vault: '0xb4Ba4D5542D1dD48BD3589543660B265B41f16CB', + gateway: '0xFD4fef1F43aFEc8b5bcdEEc47f35a1431479aC16', router: '0x94cC0AaC535CCDB3C01d6787D6413C739ae12bc4', + aave: '0x8bAB6d1b75f19e9eD9fCe8b9BD338844fF79aE27', + tokens: { + 'WETH(dex,canonical)': '0x4200000000000000000000000000000000000006', 'USDC(circle,dex)': '0x036CbD53842c5426634e7929541eC2318f3dCF7e', + 'LINK(aave,lending)': '0x810D46F9a9027E28F9B01F75E2bdde839dA61115', 'USDbC(moonwell)': '0x4616975f7E6045FD9737e95bC527e9e14c727BD2', + 'WETH(moonwell)': '0x663A6F02d547dFd639BF689FED298712f2FB69Fb', 'USDT(routed mock)': '0x4D7646B9eE3D68F4b0F135B5cbc66B00819F6b61', + 'USDC(routed mock)': '0x5c3504F0E3bA28FDc1F74234fE936518276AaBB8', 'SDK BASE WETH entry (Sepolia addr)': '0xfff9976782d46cc05630d1f6ebab18b2324d6b14', + }, + pairs: [['WETH(dex,canonical)', 'USDC(circle,dex)'], ['WETH(dex,canonical)', 'USDC(routed mock)'], ['WETH(dex,canonical)', 'USDT(routed mock)']], + }, + 'eip155:421614': { + rpc: 'https://arbitrum-sepolia-rpc.publicnode.com', vault: '0x233B1B1B378eb0Aa723097634025A47C4b73A8F7', + gateway: '0x2cd870e0166Ba458dEC615168Fd659AacD795f34', router: '0x101F443B4d1b059569D643917553c771E1b9663E', + aave: '0xBfC91D59fdAA134A4ED45f7B584cAf96D7792Eff', + tokens: { + 'WETH(dex)': '0x980B62Da83eFf3D4576C647993b0c1D7faf17c73', 'USDC(circle,dex,lending)': '0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d', + 'USDT(routed mock)': '0xE30928528f52CAEeB75fB07837e22d77D47e9c07', 'USDC(routed mock)': '0x5dd39b0b3610F666F631a6506b7713EF83e1Ac5C', + }, + pairs: [['WETH(dex)', 'USDC(circle,dex,lending)'], ['WETH(dex)', 'USDC(routed mock)'], ['WETH(dex)', 'USDT(routed mock)']], + }, + 'eip155:97': { + rpc: 'https://bsc-testnet-rpc.publicnode.com', vault: '0xE52AC4f8DD3e0263bDF748F3390cdFA1f02be881', + gateway: '0x44aFFC61983F4348DdddB886349eb992C061EaC0', router: '0x9a489505a00cE272eAa5e07Dba6491314CaE3796', + tokens: { + 'WBNB(dex)': '0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd', 'USDT(venus,dex,lending)': '0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c', + 'USDC(venus,lending)': '0x16227D60f7a0e586C66B005219dfc887D13C9531', 'USDT(routed mock)': '0xE935d9c9C24D02E61186c640cc01d713C876d40F', + 'USDC(routed mock)': '0xA8802F96cAd0d45343d9bc660B6f7d80050A660b', + }, + pairs: [['WBNB(dex)', 'USDT(venus,dex,lending)'], ['WBNB(dex)', 'USDT(routed mock)'], ['WBNB(dex)', 'USDC(routed mock)']], + }, +}; +async function main() { + const out = { at: new Date().toISOString(), readOnly: true, chains: {} }; + for (const [ns, cfg] of Object.entries(C)) { + const c = createPublicClient({ transport: http(cfg.rpc, { timeout: 15000, retryCount: 2 }) }); + const e = { rpc: cfg.rpc }; + out.chains[ns] = e; + try { + e.chainId = await c.getChainId(); + if (e.chainId !== Number(ns.split(':')[1])) throw new Error('chain mismatch'); + const bn = await c.getBlockNumber(); e.block = bn; + const read = (address, functionName, args = []) => c.readContract({ address, abi, functionName, args, blockNumber: bn }); + e.vaultNativeBalance = await c.getBalance({ address: cfg.vault, blockNumber: bn }); + e.tokens = {}; + for (const [label, t] of Object.entries(cfg.tokens)) { + const r = { address: getAddress(t) }; + try { + const code = await c.getCode({ address: t, blockNumber: bn }); + r.hasCode = !!code && code !== '0x'; + r.codeBytes = code ? (code.length - 2) / 2 : 0; + r.hasDepositSelector = !!code && code.toLowerCase().includes('d0e30db0'); + r.hasWithdrawSelector = !!code && code.toLowerCase().includes('2e1a7d4d'); + } catch (x) { r.codeError = err(x); } + if (r.hasCode) { + try { r.symbol = await read(t, 'symbol'); } catch (x) { r.symbolError = err(x); } + try { r.decimals = await read(t, 'decimals'); } catch (x) { r.decimalsError = err(x); } + try { r.vaultBalance = await read(t, 'balanceOf', [cfg.vault]); } catch (x) { r.vaultBalanceError = err(x); } + try { r.gatewayInboundSupported = await read(cfg.gateway, 'isSupportedToken', [t]); } catch (x) { r.gatewayError = err(x); } + } + e.tokens[label] = r; + } + try { + e.factory = await read(cfg.router, 'factory'); + e.pools = []; + for (const [a, b] of cfg.pairs) { + for (const fee of [100, 500, 2500, 3000, 10000]) { + try { + const pool = await read(e.factory, 'getPool', [cfg.tokens[a], cfg.tokens[b], fee]); + if (pool === zeroAddress) continue; + e.pools.push({ pair: [a, b], fee, pool, liquidity: await read(pool, 'liquidity') }); + } catch (x) { e.pools.push({ pair: [a, b], fee, error: err(x) }); } + } + } + } catch (x) { e.factoryError = err(x); } + if (cfg.aave) { + try { + const reserves = await read(cfg.aave, 'getReservesList'); + e.aaveReserves = []; + for (const r of reserves) { + let symbol, decimals, dep; + try { symbol = await read(r, 'symbol'); } catch { symbol = '?'; } + try { decimals = await read(r, 'decimals'); } catch { decimals = '?'; } + try { const code = await c.getCode({ address: r, blockNumber: bn }); dep = code.toLowerCase().includes('d0e30db0'); } catch { dep = '?'; } + e.aaveReserves.push({ reserve: r, symbol, decimals, hasDepositSelector: dep }); + } + } catch (x) { e.aaveError = err(x); } + } + if (cfg.eigenStrategy) { + try { e.eigenUnderlying = await read(cfg.eigenStrategy, 'underlyingToken'); } catch (x) { e.eigenError = err(x); } + } + if (ns === 'eip155:11155111') { + try { const [p, d] = await read(cfg.gateway, 'getEthUsdPrice'); e.ethUsd1e18 = p; e.ethUsdFeedDecimals = d; } catch (x) { e.ethUsdError = err(x); } + } + } catch (x) { e.error = err(x); } + } + fs.writeFileSync(process.argv[2], JSON.stringify(out, big, 2)); + console.log('ok'); +} +main().catch((e) => { console.error(err(e)); process.exitCode = 1; }); diff --git a/plan/agw/independent-review-creation-flow-2026-10-20/scripts/dest-receipts.cjs b/plan/agw/independent-review-creation-flow-2026-10-20/scripts/dest-receipts.cjs new file mode 100644 index 00000000..3058792f --- /dev/null +++ b/plan/agw/independent-review-creation-flow-2026-10-20/scripts/dest-receipts.cjs @@ -0,0 +1,22 @@ +const {createPublicClient,http,parseAbi,parseEventLogs}=require('/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem'); +const fs=require('node:fs'); +const EXEC=parseAbi(['event UniversalTxExecuted(bytes32 indexed subTxId, bytes32 indexed universalTxId, address indexed originCaller, address target, bytes data)']); +const D=[ + ['eip155:11155111','https://ethereum-sepolia-rpc.publicnode.com','0xD847ca2462405a70c32ff5776e70fE25EA7B26ca','0xDdc0C8e35863f1478c0485144d2Fae959242Ce43',['0xf3ed17fa05f700543ec10930d078c6fb793624e44e8ec8fe3f14fbb7cee5cf19','0x15f49a09b3879f3cc1ea4c3accddc7431b279da59033f5eb9842a0d4994df50a']], + ['eip155:84532','https://base-sepolia-rpc.publicnode.com','0xB07a90329A3Ef6B20aC80a458069a7D8daE93D58','0xB0d8079eEF1553d3e975947f087eEeB05f02ab1A',['0x89337900340a39fd1725657e72f146fe5b4b917a58d5db150f052b2222724d6d','0xe81704385810c74cef8d16cb7fe3e2a98805aff9a9f63aaf5008d3d9288a4781']], + ['eip155:421614','https://arbitrum-sepolia-rpc.publicnode.com','0x3130f7F8b10C94A54eC012A4d0e6DAc963f200eb','0x97B91433aF804877cd11EC522C910c54E04624b5',['0x059011ed41d6409e48b70ab47dd02a16eca292e01e68eb721d78df5813f46c98','0x54f382ed25d895893f6cd3042ff7ee43e63bc392397c9a9572c424a3589d9df8']], + ['eip155:97','https://bsc-testnet-rpc.publicnode.com','0x0140403283bB76C1890501067754d1c376189b5D','0xA7384f2b00463E548426Cd9C8979dDa78ECf60c4',['0x6b5cfb84699948c2b626e2a244b9ff8354d070093d6f8ecb42a228914adfdaa5','0x42adb9167d8f25a81ff01e143cb43e676818d8ce144a08444c890caecd08029a']], +]; +(async()=>{const out=[]; +for(const [ns,rpc,wallet,cea,hashes] of D){const c=createPublicClient({transport:http(rpc,{timeout:20000,retryCount:2})}); + for(const h of hashes){const r={ns,hash:h};try{const rc=await c.getTransactionReceipt({hash:h});const tx=await c.getTransaction({hash:h}); + Object.assign(r,{status:rc.status,block:String(rc.blockNumber),from:rc.from,to:rc.to,value:String(tx.value),gasUsed:String(rc.gasUsed)}); + const ev=parseEventLogs({abi:EXEC,logs:rc.logs});r.ceaExecuted=ev.map(e=>({emitter:e.address,originCaller:e.args.originCaller,target:e.args.target,data:e.args.data})); + r.ceaMatches=ev.some(e=>e.address.toLowerCase()===cea.toLowerCase()&&e.args.originCaller.toLowerCase()===wallet.toLowerCase());}catch(e){r.error=(e.shortMessage||e.message).slice(0,160)}out.push(r);} + try{out.push({ns,ceaCodeBytes:((await c.getCode({address:cea}))||'0x').length/2-1,ceaNativeBalanceNow:String(await c.getBalance({address:cea}))})}catch(e){}} +// Push-side wallet balance deltas around the SPL first-use send (refund check) +const p=createPublicClient({transport:http('https://evm.donut.rpc.push.org/',{timeout:20000,retryCount:1})}); +const W='0xED6bFE825b8d84A1E6f4F7c9067398F8985CC372';const refund={}; +for(const [k,b] of [['spl:first-use',24455663n],['spl:subsequent',24455695n]]){try{const before=await p.getBalance({address:W,blockNumber:b-1n});const after=await p.getBalance({address:W,blockNumber:b});refund[k]={before:String(before),after:String(after),deltaPC:Number(after-before)/1e18}}catch(e){refund[k]={error:(e.shortMessage||e.message).slice(0,160)}}} +fs.writeFileSync(process.argv[2],JSON.stringify({at:new Date().toISOString(),dest:out,walletDelta:refund},null,1)); +for(const r of out)console.log(JSON.stringify(r));console.log('walletDelta',JSON.stringify(refund));})().catch(e=>{console.error(e.message);process.exitCode=1}); diff --git a/plan/agw/independent-review-creation-flow-2026-10-20/scripts/gasprice-history.cjs b/plan/agw/independent-review-creation-flow-2026-10-20/scripts/gasprice-history.cjs new file mode 100644 index 00000000..f94695c3 --- /dev/null +++ b/plan/agw/independent-review-creation-flow-2026-10-20/scripts/gasprice-history.cjs @@ -0,0 +1,11 @@ +const {createPublicClient,http,parseAbi}=require('/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/node_modules/viem'); +const fs=require('node:fs'); +const c=createPublicClient({transport:http('https://evm.donut.rpc.push.org/',{timeout:20000,retryCount:1})}); +const abi=parseAbi(['function gasPriceByChainNamespace(string) view returns (uint256)']); +const NS=['eip155:11155111','eip155:84532','eip155:421614','eip155:97','solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1']; +(async()=>{const head=await c.getBlockNumber();const rows=[]; +for(let back=0n;back<=2400n;back+=200n){const bn=head-back;const row={block:String(bn)}; + try{const b=await c.getBlock({blockNumber:bn});row.time=new Date(Number(b.timestamp)*1000).toISOString();}catch(e){row.timeError=e.shortMessage} + for(const ns of NS){try{row[ns]=String(await c.readContract({address:'0x00000000000000000000000000000000000000C0',abi,functionName:'gasPriceByChainNamespace',args:[ns],blockNumber:bn}))}catch(e){row[ns]='ERR '+(e.shortMessage||e.message).slice(0,60)}} + rows.push(row);} +fs.writeFileSync(process.argv[2],JSON.stringify(rows,null,1));for(const r of rows)console.log(r.block,r.time,NS.map(n=>r[n]).join(' | '));})().catch(e=>{console.error(e.message);process.exitCode=1}); diff --git a/plan/agw/independent-review-creation-flow-2026-10-20/scripts/old-prc20.cjs b/plan/agw/independent-review-creation-flow-2026-10-20/scripts/old-prc20.cjs new file mode 100644 index 00000000..a2f5b939 --- /dev/null +++ b/plan/agw/independent-review-creation-flow-2026-10-20/scripts/old-prc20.cjs @@ -0,0 +1,14 @@ +const SDK='/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk'; +const {createPublicClient,http,parseAbi,hexToString,keccak256,toHex}=require(SDK+'/node_modules/viem'); +const fs=require('node:fs'); +const c=createPublicClient({transport:http('https://evm.donut.rpc.push.org/',{timeout:20000,retryCount:2})}); +const abi=parseAbi(['function SOURCE_CHAIN_NAMESPACE() view returns (string)','function decimals() view returns (uint8)','function symbol() view returns (string)','function name() view returns (string)','function totalSupply() view returns (uint256)','function getOutboundTxGasAndFees(address,uint256) view returns (address,uint256,uint256,uint256,string,uint256)']); +const T={ 'USDC.eth.old':'0x387b9C8Db60E74999aAAC5A2b7825b400F12d68E','USDC.base.old':'0x84B62e44F667F692F7739Ca6040cD17DA02068A8','USDC.arb.old':'0xa261A10e94aE4bA88EE8c5845CbE7266bD679DD6','USDT.eth.old':'0xCA0C5E6F002A389E1580F0DB7cd06e4549B5F9d3','USDT.arb.old':'0x76Ad08339dF606BeEDe06f90e3FaF82c5b2fb2E9','USDT.base.old':'0x2C455189D2af6643B924A981a9080CcC63d5a567','USDT.bsc.old':'0x2f98B4235FD2BA0173a2B056D722879360B12E7b'}; +const sel=keccak256(toHex('SOURCE_TOKEN_ADDRESS()')).slice(0,10); +(async()=>{const bn=await c.getBlockNumber();const out={at:new Date().toISOString(),block:bn.toString(),tokens:{}}; +for(const [k,a] of Object.entries(T)){const m={address:a}; + for(const f of ['SOURCE_CHAIN_NAMESPACE','decimals','symbol','name','totalSupply']){try{m[f]=String(await c.readContract({address:a,abi,functionName:f,blockNumber:bn}))}catch(e){m[f+'Error']=(e.shortMessage||e.message).slice(0,120)}} + try{const raw=(await c.call({to:a,data:sel,blockNumber:bn})).data; if(raw.length===66)m.sourceWord=raw; else {const len=Number(BigInt('0x'+raw.slice(66,130)));m.sourceString=hexToString('0x'+raw.slice(130,130+len*2));}}catch(e){m.sourceError=(e.shortMessage||e.message).slice(0,120)} + try{const r=await c.readContract({address:'0x00000000000000000000000000000000000000C0',abi,functionName:'getOutboundTxGasAndFees',args:[a,0n],blockNumber:bn});m.outboundQuote={gasToken:r[0],gasFee:String(r[1]),protocolFee:String(r[2]),chain:r[4],gasLimitUsed:String(r[5])}}catch(e){m.outboundQuoteError=(e.shortMessage||e.message).slice(0,160)} + out.tokens[k]=m;} +fs.writeFileSync(process.argv[2],JSON.stringify(out,null,2));console.log(JSON.stringify(out,null,1));})().catch(e=>{console.error(e.message);process.exitCode=1}); diff --git a/plan/agw/independent-review-creation-flow-2026-10-20/scripts/push-probe.cjs b/plan/agw/independent-review-creation-flow-2026-10-20/scripts/push-probe.cjs new file mode 100644 index 00000000..e29bf5d0 --- /dev/null +++ b/plan/agw/independent-review-creation-flow-2026-10-20/scripts/push-probe.cjs @@ -0,0 +1,234 @@ +// Independent read-only Donut probe. No keys, no signing, no transactions. +// Usage: node push-probe.cjs +const fs = require('node:fs'); +const SDK = '/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk'; +const { + createPublicClient, http, parseAbi, decodeEventLog, encodeFunctionData, + decodeFunctionResult, getAddress, hexToString, +} = require(SDK + '/node_modules/viem'); + +const RPC = 'https://evm.donut.rpc.push.org/'; +const CORE = '0x00000000000000000000000000000000000000C0'; +const UGPC = '0x00000000000000000000000000000000000000C1'; +const QUOTER = '0x83316275f7C2F79BC4E26f089333e88E89093037'; +const PRC20 = { + pETH: '0x2971824Db68229D087931155C2b8bB820B275809', + pETH_ARB: '0xc0a821a1AfEd1322c5e15f1F4586C0B8cE65400e', + pETH_BASE: '0xc7007af2B24D4eb963fc9633B0c66e1d2D90Fc21', + pBNB: '0x7a9082dA308f3fa005beA7dB0d203b3b86664E36', + pSOL: '0x5D525Df2bD99a6e7ec58b76aF2fd95F39874EBed', + USDT_ETH: '0x0f97A213207703923F5f0C613C9827f7C9A0f96B', + USDC_ETH: '0x7A58048036206bB898008b5bBDA85697DB1e5d66', + USDT_ARB: '0xFE6E9DF2BbC9ce05D98b83B1365df6DcA9951891', + USDC_ARB: '0x1091cCBA2FF8d2A131AE4B35e34cf3308C48572C', + USDT_SOL: '0x4f1A3D22d170a2F4Bddb37845a962322e24f4e34', + USDC_SOL: '0x04B8F634ABC7C879763F623e0f0550a4b5c4426F', + USDT_BSC: '0x731aF1Da5365259d27528557EE4aFBA4baC90ef2', + USDC_BSC: '0x120EBf25Dad7D6a09Ad2316f23f9Be95DBb90639', + USDT_BASE: '0x148823809B853e1db187BC09A9ac909BC42F971a', + USDC_BASE: '0xD7C6cA1e2c0CE260BE0c0AD39C1540de460e3Be1', + WETH_ETH: '0x0d0dF7E8807430A81104EA84d926139816eC7586', + stETH_ETH: '0xaf89E805949c628ebde3262e91dc4ab9eA12668E', + DAI_SOL: '0x5861f56A556c990358cc9cccd8B5baa3767982A8', +}; +const GAS = { + 'eip155:11155111': PRC20.pETH, 'eip155:84532': PRC20.pETH_BASE, + 'eip155:421614': PRC20.pETH_ARB, 'eip155:97': PRC20.pBNB, + 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1': PRC20.pSOL, +}; +const STABLE_FOR_ORIGIN = { + 'eip155:11155111': PRC20.USDT_ETH, 'eip155:421614': PRC20.USDT_ARB, + 'eip155:84532': PRC20.USDT_BASE, 'eip155:97': PRC20.USDT_BSC, + 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1': PRC20.USDT_SOL, +}; +const PUSH_TXS = { + 'spl:first-use': '0x119c89e9ff7c7cccdfc8c071fade2488aa28b0eff7d9b71f7f0cf247c958bbf5', + 'spl:subsequent': '0x7980032bb748889f44d9a58e4030dc1338575d03fa78da23531dcf96d6c23e57', + 'sepolia:first-use': '0xb968f71a2f8deb17a194632744e0e256b7703e229e0a0d35461751e580debce6', + 'sepolia:subsequent': '0xc3b021815bcfd26269ddcdbaed813aa91fb0c03a36dbf2cbc5678f84b157c7cf', + 'base:first-use': '0xb9fd4a64a2fd9b68193ac3aef1177f054dc591cfc3917968d3cfc9ee1fc35153', + 'base:subsequent': '0xc0aa504633d7e0fe66e4aa2abaf994e4b8ff09c992b8712e3a8879fe33c9026d', + 'arb:first-use': '0x21ce19a3780fee8cbcc006b3197163166402da30557ef1eff8556c97d793846c', + 'arb:subsequent': '0xba1c063ab2e261f0d1af0833975fd1344daa390ae80336c45a45d49759ebecad', + 'bnb:first-use': '0x6e4bf8a92eb569fb4aa34a5d5eab4799ab86f6aa40fe405d59cba6498c669f7d', + 'bnb:subsequent': '0x82f343dcd100715d5693d68fbdcccdaf1467c3c5626391501d1f7b579d279047', +}; +const coreAbi = parseAbi([ + 'function getOutboundTxGasAndFees(address,uint256) view returns (address gasToken,uint256 gasFee,uint256 protocolFee,uint256 gasPrice,string chainNamespace,uint256 gasLimitUsed)', + 'function baseGasLimitByChainNamespace(string) view returns (uint256)', + 'function gasPriceByChainNamespace(string) view returns (uint256)', + 'function gasTokenPRC20ByChainNamespace(string) view returns (address)', + 'function defaultFeeTier(address) view returns (uint24)', + 'function WPC() view returns (address)', + 'function isSupportedToken(address) view returns (bool)', + 'function protocolFeeByToken(address) view returns (uint256)', +]); +const evAbi = parseAbi([ + 'event SwapAndBurnGas(address indexed gasToken, uint256 pcIn, uint256 gasFee, uint24 fee, address indexed caller)', + 'event UniversalTxOutbound(bytes32 indexed subTxId, address indexed sender, string chainNamespace, address indexed token, bytes recipient, uint256 amount, address gasToken, uint256 gasFee, uint256 gasLimit, bytes payload, uint256 protocolFee, address revertRecipient, uint8 txType, uint256 gasPrice)', + 'event OutboundMetered(bytes32 indexed id, address indexed engine, address indexed account, address token, uint256 amount)', + 'event SetSupportedToken(address indexed prc20, bool supported)', + 'event SetGasToken(string chainNamespace, address prc20)', + 'event Transfer(address indexed from, address indexed to, uint256 value)', +]); +const quoterAbi = parseAbi([ + 'function quoteExactOutputSingle((address tokenIn,address tokenOut,uint256 amount,uint24 fee,uint160 sqrtPriceLimitX96)) returns (uint256 amountIn,uint160 sqrtPriceX96After,uint32 initializedTicksCrossed,uint256 gasEstimate)', + 'function quoteExactInputSingle((address tokenIn,address tokenOut,uint256 amountIn,uint24 fee,uint160 sqrtPriceLimitX96)) returns (uint256 amountOut,uint160 sqrtPriceX96After,uint32 initializedTicksCrossed,uint256 gasEstimate)', +]); +const prcAbi = parseAbi([ + 'function SOURCE_CHAIN_NAMESPACE() view returns (string)', + 'function decimals() view returns (uint8)', + 'function symbol() view returns (string)', + 'function totalSupply() view returns (uint256)', +]); +const big = (_k, v) => (typeof v === 'bigint' ? v.toString() : v); +const err = (e) => (e && (e.shortMessage || e.message) || String(e)).slice(0, 300); + +async function main() { + const c = createPublicClient({ transport: http(RPC, { timeout: 20000, retryCount: 2 }) }); + const out = { at: new Date().toISOString(), rpc: RPC, readOnly: true }; + out.chainId = await c.getChainId(); + const block = await c.getBlock(); + out.block = block.number; out.blockTimestamp = new Date(Number(block.timestamp) * 1000).toISOString(); + const bn = block.number; + const read = (address, abi, functionName, args = []) => + c.readContract({ address, abi, functionName, args, blockNumber: bn }); + + // 1. Live sends: receipts + gas swap evidence. + out.sends = {}; + for (const [k, h] of Object.entries(PUSH_TXS)) { + const r = { hash: h }; + try { + const [tx, rc] = await Promise.all([c.getTransaction({ hash: h }), c.getTransactionReceipt({ hash: h })]); + Object.assign(r, { status: rc.status, block: rc.blockNumber, from: rc.from, to: rc.to, txValue: tx.value, + gasUsed: rc.gasUsed, effectiveGasPrice: rc.effectiveGasPrice, pushFeePaid: rc.gasUsed * rc.effectiveGasPrice }); + r.events = []; + for (const l of rc.logs) { + try { + const d = decodeEventLog({ abi: evAbi, data: l.data, topics: l.topics }); + if (d.eventName === 'Transfer') continue; + const a = d.args; + if (d.eventName === 'UniversalTxOutbound') + r.events.push({ ev: d.eventName, emitter: l.address, sender: a.sender, chain: a.chainNamespace, token: a.token, + amount: a.amount, gasToken: a.gasToken, gasFee: a.gasFee, gasLimit: a.gasLimit, protocolFee: a.protocolFee, + gasPrice: a.gasPrice, txType: a.txType, revertRecipient: a.revertRecipient, recipientLen: (a.recipient.length - 2) / 2, + payloadLen: (a.payload.length - 2) / 2 }); + else r.events.push({ ev: d.eventName, emitter: l.address, ...a }); + } catch { /* not one of ours */ } + } + } catch (e) { r.error = err(e); } + out.sends[k] = r; + } + + // 2. Fee model inputs per chain and raw quotes. + out.wpc = await read(CORE, coreAbi, 'WPC'); + out.chains = {}; + for (const [ns, gas] of Object.entries(GAS)) { + const e = { gasPrc20: gas }; + try { + e.registeredGasToken = await read(CORE, coreAbi, 'gasTokenPRC20ByChainNamespace', [ns]); + e.baseGasLimit = await read(CORE, coreAbi, 'baseGasLimitByChainNamespace', [ns]); + e.gasPrice = await read(CORE, coreAbi, 'gasPriceByChainNamespace', [ns]); + e.defaultFeeTier = await read(CORE, coreAbi, 'defaultFeeTier', [gas]); + e.protocolFee = await read(CORE, coreAbi, 'protocolFeeByToken', [gas]); + } catch (x) { e.error = err(x); } + const limits = ns.startsWith('solana') ? [0n, 960n, 1052n, 2285n, 1000000n] : [0n, 500000n, 2000000n]; + e.quotes = []; + for (const gl of limits) { + const q = { inputGasLimit: gl }; + try { + const res = await read(CORE, coreAbi, 'getOutboundTxGasAndFees', [gas, gl]); + Object.assign(q, { gasFee: res[1], protocolFee: res[2], gasPrice: res[3], gasLimitUsed: res[5] }); + // Exact PC the gas swap needs at this block (WPC -> gas token exact output). + try { + const data = encodeFunctionData({ abi: quoterAbi, functionName: 'quoteExactOutputSingle', + args: [{ tokenIn: out.wpc, tokenOut: gas, amount: res[1], fee: e.defaultFeeTier, sqrtPriceLimitX96: 0n }] }); + const raw = await c.call({ to: QUOTER, data, blockNumber: bn }); + q.swapPcInRequired = decodeFunctionResult({ abi: quoterAbi, functionName: 'quoteExactOutputSingle', data: raw.data })[0]; + } catch (x) { q.swapQuoteError = err(x); } + } catch (x) { q.error = err(x); } + e.quotes.push(q); + } + out.chains[ns] = e; + } + + // 3. PC/USD as the SDK oracle would see it for UEA signers from each origin. + out.pcUsd = {}; + for (const [origin, stable] of Object.entries(STABLE_FOR_ORIGIN)) { + const p = { stable }; + for (const fee of [500, 3000, 100, 10000]) { + try { + const data = encodeFunctionData({ abi: quoterAbi, functionName: 'quoteExactInputSingle', + args: [{ tokenIn: out.wpc, tokenOut: stable, amountIn: 10n ** 18n, fee, sqrtPriceLimitX96: 0n }] }); + const raw = await c.call({ to: QUOTER, data, blockNumber: bn }); + p.fee = fee; + p.oneWpcInStableRaw = decodeFunctionResult({ abi: quoterAbi, functionName: 'quoteExactInputSingle', data: raw.data })[0]; + break; + } catch (x) { p['err' + fee] = err(x); } + } + out.pcUsd[origin] = p; + } + + // 4. PRC20 metadata (raw SOURCE_TOKEN_ADDRESS return bytes; type-agnostic). + out.prc20 = {}; + const sel = '0x' + require(SDK + '/node_modules/viem').keccak256(require(SDK + '/node_modules/viem').toHex('SOURCE_TOKEN_ADDRESS()')).slice(2, 10); + for (const [name, address] of Object.entries(PRC20)) { + const m = { address }; + try { m.namespace = await read(address, prcAbi, 'SOURCE_CHAIN_NAMESPACE'); } catch (x) { m.namespaceError = err(x); } + try { m.decimals = await read(address, prcAbi, 'decimals'); } catch (x) { m.decimalsError = err(x); } + try { m.symbol = await read(address, prcAbi, 'symbol'); } catch (x) { m.symbolError = err(x); } + try { m.totalSupply = await read(address, prcAbi, 'totalSupply'); } catch (x) { m.totalSupplyError = err(x); } + try { m.isSupportedToken = await read(CORE, coreAbi, 'isSupportedToken', [address]); } catch (x) { m.isSupportedError = err(x); } + try { + const raw = (await c.call({ to: address, data: sel, blockNumber: bn })).data; + m.sourceTokenRawLen = raw ? (raw.length - 2) / 2 : 0; + if (raw && raw.length === 66) m.sourceTokenWord = raw; + else if (raw && raw.length > 130) { + const len = Number(BigInt('0x' + raw.slice(66, 130))); + m.sourceTokenString = hexToString('0x' + raw.slice(130, 130 + len * 2)); + } + } catch (x) { m.sourceTokenError = err(x); } + out.prc20[name] = m; + } + + // 5. Enumerate PRC20s announced by UniversalCore events (incomplete by construction). + out.coreEvents = { supported: [], gasTokens: [] }; + const topicSupported = '0x' + require(SDK + '/node_modules/viem').keccak256(require(SDK + '/node_modules/viem').toHex('SetSupportedToken(address,bool)')).slice(2); + const topicGas = '0x' + require(SDK + '/node_modules/viem').keccak256(require(SDK + '/node_modules/viem').toHex('SetGasToken(string,address)')).slice(2); + try { + for (const [kind, topic] of [['supported', topicSupported], ['gasTokens', topicGas]]) { + const logs = await c.request({ method: 'eth_getLogs', params: [{ address: CORE, fromBlock: '0x0', toBlock: '0x' + bn.toString(16), topics: [topic] }] }); + for (const l of logs) { + const d = decodeEventLog({ abi: evAbi, data: l.data, topics: l.topics }); + out.coreEvents[kind].push({ block: BigInt(l.blockNumber), ...d.args }); + } + } + } catch (x) { out.coreEvents.error = err(x); } + // Metadata for every announced PRC20 not already in the SDK registry. + const known = new Set(Object.values(PRC20).map((a) => a.toLowerCase())); + out.unregistered = []; + const seen = new Set(); + for (const e of [...out.coreEvents.supported, ...out.coreEvents.gasTokens]) { + const a = (e.prc20 || '').toLowerCase(); + if (!a || known.has(a) || seen.has(a)) continue; + seen.add(a); + const m = { address: getAddress(a), lastEvent: e }; + try { m.namespace = await read(a, prcAbi, 'SOURCE_CHAIN_NAMESPACE'); } catch (x) { m.namespaceError = err(x); } + try { m.symbol = await read(a, prcAbi, 'symbol'); } catch (x) { m.symbolError = err(x); } + try { m.decimals = await read(a, prcAbi, 'decimals'); } catch (x) { m.decimalsError = err(x); } + try { + const raw = (await c.call({ to: a, data: sel, blockNumber: bn })).data; + if (raw && raw.length === 66) m.sourceTokenWord = raw; + else if (raw && raw.length > 130) { + const len = Number(BigInt('0x' + raw.slice(66, 130))); + m.sourceTokenString = hexToString('0x' + raw.slice(130, 130 + len * 2)); + } + } catch (x) { m.sourceTokenError = err(x); } + try { m.isSupportedToken = await read(CORE, coreAbi, 'isSupportedToken', [a]); } catch (x) { m.isSupportedError = err(x); } + out.unregistered.push(m); + } + out.blockAfter = await c.getBlockNumber(); + fs.writeFileSync(process.argv[2], JSON.stringify(out, big, 2)); + console.log('ok', out.block, out.blockTimestamp); +} +main().catch((e) => { console.error(err(e)); process.exitCode = 1; }); diff --git a/plan/agw/independent-review-creation-flow-2026-10-20/scripts/sdk-quotes.cjs b/plan/agw/independent-review-creation-flow-2026-10-20/scripts/sdk-quotes.cjs new file mode 100644 index 00000000..f2ea0e01 --- /dev/null +++ b/plan/agw/independent-review-creation-flow-2026-10-20/scripts/sdk-quotes.cjs @@ -0,0 +1,61 @@ +// Read-only: the SDK's own AGW quote path (runtime.quoteOutbound) for different signer origins. +// Uses the locally built dist of the reviewed working tree. No keys, no signing. +const fs = require('node:fs'); +const path = require('node:path'); +const built = '/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/dist/packages/core/src'; +const { PushChain } = require(built); +const { CHAIN, PUSH_NETWORK } = PushChain.CONSTANTS; +const { getNativePRC20ForChain } = require(path.join(built, 'lib/orchestrator/internals/helpers')); +const USDT_SOL = '0x4f1A3D22d170a2F4Bddb37845a962322e24f4e34'; +const USDT_SOL_MINT = 'EiXDnrAg9ea2Q6vEPV7E5TpTU1vh41jcuZqKjU5Dc4ZF'; +const big = (_k, v) => (typeof v === 'bigint' ? v.toString() : v); +async function main() { + const out = { at: new Date().toISOString(), readOnly: true, origins: {} }; + const origins = { + pushNative: { address: '0x0000000000000000000000000000000000005678', chain: CHAIN.PUSH_TESTNET_DONUT }, + sepoliaUEA: { address: '0x0000000000000000000000000000000000005678', chain: CHAIN.ETHEREUM_SEPOLIA }, + solanaUEA: { address: '11111111111111111111111111111112', chain: CHAIN.SOLANA_DEVNET }, + }; + // Fresh wallet (no CEA/ATA anywhere) and the reviewed SPL wallet (CEA ATA exists). + const freshWallet = '0x00000000000000000000000000000000000a6e01'; + const splWallet = '0xED6bFE825b8d84A1E6f4F7c9067398F8985CC372'; + for (const [name, signer] of Object.entries(origins)) { + const client = await PushChain.initialize(signer, { network: PUSH_NETWORK.TESTNET_DONUT }); + const rt = client.agenticRuntime; + if (!rt.isReadOnly) throw new Error('must be read-only'); + const cases = []; + for (const chain of [CHAIN.ETHEREUM_SEPOLIA, CHAIN.BASE_SEPOLIA, CHAIN.ARBITRUM_SEPOLIA, CHAIN.BNB_TESTNET]) { + for (const gl of [BigInt(2000000), BigInt(0)]) { + const c = { chain, inputGasLimit: gl }; + try { + const q = await rt.quoteOutbound(getNativePRC20ForChain(chain, rt.network), gl, chain); + Object.assign(c, q, { attachedPC: Number(q.protocolFee + q.nativeValueForGas) / 1e18 }); + } catch (e) { c.error = (e.shortMessage || e.message).slice(0, 200); } + cases.push(c); + } + } + const sol = CHAIN.SOLANA_DEVNET; + for (const [label, token, gl, svm] of [ + ['native-sol omitted', getNativePRC20ForChain(sol, rt.network), BigInt(0), { wallet: freshWallet, burnAmount: BigInt(10000) }], + ['spl fresh CEA ATA omitted', USDT_SOL, BigInt(0), { wallet: freshWallet, splMintBase58: USDT_SOL_MINT, burnAmount: BigInt(1000) }], + ['spl existing CEA ATA omitted', USDT_SOL, BigInt(0), { wallet: splWallet, splMintBase58: USDT_SOL_MINT, burnAmount: BigInt(1000) }], + ['spl existing explicit 5000', USDT_SOL, BigInt(5000), { wallet: splWallet, splMintBase58: USDT_SOL_MINT, burnAmount: BigInt(1000) }], + ['legacy 1,000,000', USDT_SOL, BigInt(1000000), { wallet: splWallet, splMintBase58: USDT_SOL_MINT, burnAmount: BigInt(1000) }], + ['explicit 500 (< base 960)', USDT_SOL, BigInt(500), { wallet: splWallet, splMintBase58: USDT_SOL_MINT, burnAmount: BigInt(1000) }], + ]) { + const c = { chain: sol, label, inputGasLimit: gl }; + try { + const q = await rt.quoteOutbound(token, gl, sol, svm); + Object.assign(c, q, { attachedPC: Number(q.protocolFee + q.nativeValueForGas) / 1e18 }); + } catch (e) { c.error = (e.shortMessage || e.message).slice(0, 200); } + cases.push(c); + } + out.origins[name] = { signerChain: signer.chain, pushBlock: String(await rt.reader.getBlockNumber()), cases }; + } + fs.writeFileSync(process.argv[2], JSON.stringify(out, big, 2)); + for (const [n, o] of Object.entries(out.origins)) { + console.log('==', n, o.signerChain, 'block', o.pushBlock); + for (const c of o.cases) console.log(' ', c.chain, c.label || '', 'in', String(c.inputGasLimit), 'used', String(c.gasLimitUsed), 'attachedPC', c.attachedPC, c.error || ''); + } +} +main().catch((e) => { console.error(e.shortMessage || e.message); process.exitCode = 1; }); diff --git a/plan/agw/independent-review-creation-flow-2026-10-20/scripts/sol-probe.cjs b/plan/agw/independent-review-creation-flow-2026-10-20/scripts/sol-probe.cjs new file mode 100644 index 00000000..58db55ee --- /dev/null +++ b/plan/agw/independent-review-creation-flow-2026-10-20/scripts/sol-probe.cjs @@ -0,0 +1,77 @@ +// Independent read-only Solana devnet probe. No keys, no signing. +const fs = require('node:fs'); +const SDK = '/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk'; +const { Connection, PublicKey } = require(SDK + '/node_modules/@solana/web3.js'); +const RPC = 'https://api.devnet.solana.com'; +const SIGS = { + 'spl:first-use': 'y8hK7xQWVs4mRupJAJDRBkbt1EnVmtQNxAhPhTbvJbfULrwARFimjvygaDskPawH44dntUaq5Tq6ubDDp7592q1', + 'spl:subsequent': '3G782PfUtqv3THZGt7vH5J9xoscMMFvKwUo215J2Hoh4APYHEHMGDcKBjix6je5y3M2DhoeuENkmqWEFrJgUjmLe', +}; +const PROGRAMS = { + gatewayCFVS: 'CFVSincHYbETh2k7w6u1ENEkjbSLtveRCEBupKidw2VS', + gatewayDJoF_pinnedSource: 'DJoFYDpgbTfxbXBv1QYhYGc9FK4J5FUKpYXAfSkHryXp', + testCounter_sdkFixture: '8yNqjrMnFiFbVTVQcKij8tNWWTMdFkrDf9abCGgc2sgx', + testCounter_sourceDeclareId: '4mpHkerNsaJPp35fyT5bkoXxuEBczGq6HUKTtrzFcptx', + testCounter_anchorToml: '9LfpvcY2CYcNWEc2ip2ZwwKivEALbF3knwimXrbLubT2', + splMemoV2: 'MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr', + splMemoV1: 'Memo1UhkJRfHyvLMcVucJwxXeuD728EqVDDwQDxFMNo', + associatedToken: 'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL', +}; +const CEA = 'DKbAi4YmS5EfdvKHzS2zHKSSPfgiffu3ZddXoY4N2VuX'; +const CEA_ATA = 'GuKBtW2xo53yMyj915CMCziHyyz1LaGxnfZBUDRJPd9K'; +const WALLET = '0xED6bFE825b8d84A1E6f4F7c9067398F8985CC372'; +const err = (e) => (e && e.message || String(e)).slice(0, 300); + +async function main() { + const c = new Connection(RPC, 'confirmed'); + const out = { at: new Date().toISOString(), rpc: RPC, readOnly: true }; + out.slot = await c.getSlot(); + out.genesisHash = await c.getGenesisHash(); + out.rent = {}; + for (const n of [0, 8, 165, 82]) out.rent[n] = await c.getMinimumBalanceForRentExemption(n); + // CEA derivation as the gateway does it: ["push_identity", wallet20] under CFVS. + const [cea] = PublicKey.findProgramAddressSync( + [Buffer.from('push_identity'), Buffer.from(WALLET.slice(2), 'hex')], + new PublicKey(PROGRAMS.gatewayCFVS) + ); + out.ceaDerived = cea.toBase58(); + out.ceaMatchesEvidence = cea.toBase58() === CEA; + out.programs = {}; + for (const [k, id] of Object.entries(PROGRAMS)) { + try { + const info = await c.getAccountInfo(new PublicKey(id)); + out.programs[k] = info ? { id, executable: info.executable, owner: info.owner.toBase58(), dataLen: info.data.length } : { id, exists: false }; + } catch (e) { out.programs[k] = { id, error: err(e) }; } + } + out.ceaAta = {}; + try { + const info = await c.getParsedAccountInfo(new PublicKey(CEA_ATA)); + out.ceaAta = info.value ? info.value.data : { exists: false }; + } catch (e) { out.ceaAta.error = err(e); } + out.txs = {}; + for (const [k, sig] of Object.entries(SIGS)) { + const r = { sig }; + try { + const tx = await c.getParsedTransaction(sig, { maxSupportedTransactionVersion: 0, commitment: 'confirmed' }); + if (!tx) { r.missing = true; out.txs[k] = r; continue; } + r.slot = tx.slot; r.blockTime = tx.blockTime && new Date(tx.blockTime * 1000).toISOString(); + r.err = tx.meta.err; r.fee = tx.meta.fee; r.computeUnitsConsumed = tx.meta.computeUnitsConsumed; + r.signers = tx.transaction.message.accountKeys.filter((a) => a.signer).map((a) => a.pubkey.toBase58()); + r.programsInvoked = [...new Set([ + ...tx.transaction.message.instructions.map((i) => i.programId.toBase58()), + ...(tx.meta.innerInstructions || []).flatMap((x) => x.instructions.map((i) => i.programId.toBase58())), + ])]; + const tb = (arr) => (arr || []).map((b) => ({ account: tx.transaction.message.accountKeys[b.accountIndex].pubkey.toBase58(), mint: b.mint, owner: b.owner, amount: b.uiTokenAmount.amount, programId: b.programId })); + r.preTokenBalances = tb(tx.meta.preTokenBalances); + r.postTokenBalances = tb(tx.meta.postTokenBalances); + r.innerTransfers = (tx.meta.innerInstructions || []).flatMap((x) => x.instructions) + .filter((i) => i.parsed && /transfer|create|initializeAccount/i.test(i.parsed.type || '')) + .map((i) => ({ program: i.programId.toBase58(), type: i.parsed.type, info: i.parsed.info })); + r.logTail = (tx.meta.logMessages || []).filter((l) => /Program log|invoke|success|failed/i.test(l)).slice(0, 40); + } catch (e) { r.error = err(e); } + out.txs[k] = r; + } + fs.writeFileSync(process.argv[2], JSON.stringify(out, null, 2)); + console.log('ok slot', out.slot); +} +main().catch((e) => { console.error(err(e)); process.exitCode = 1; }); diff --git a/plan/agw/independent-review-creation-flow-2026-10-20/scripts/spl-readback-probe-historical.cjs b/plan/agw/independent-review-creation-flow-2026-10-20/scripts/spl-readback-probe-historical.cjs new file mode 100644 index 00000000..0e0a5f35 --- /dev/null +++ b/plan/agw/independent-review-creation-flow-2026-10-20/scripts/spl-readback-probe-historical.cjs @@ -0,0 +1,31 @@ +// Read-only: stored SPL rule readback + wrong-recipient refusal via eth_call. No keys. +const root='/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk',fs=require('node:fs'); +const {createPublicClient,http,decodeFunctionData,encodeFunctionData}=require(root+'/node_modules/viem'); +const built=root+'/dist/packages/core/src'; +const {PushChain}=require(built); +const {v6}=require(built+'/lib/agentic/contracts/v6'); +const {UNIVERSAL_GATEWAY_PC}=require(built+'/lib/constants/abi'); +const {parseAgwSvmPayload,encodeAgwSvmPayload}=require(built+'/lib/agentic/execution/svm-payload'); +const {decodeAgenticRevert}=require(built+'/lib/agentic/revert'); +const {PublicKey}=require(root+'/node_modules/@solana/web3.js'); +const big=(_k,v)=>typeof v==='bigint'?String(v):v; +(async()=>{ + const rpc=createPublicClient({transport:http('https://archive.evm.donut.rpc.push.org/',{timeout:15000,retryCount:1})}); + const hash='0x119c89e9ff7c7cccdfc8c071fade2488aa28b0eff7d9b71f7f0cf247c958bbf5'; + const tx=await rpc.getTransaction({hash}),w=v6.decodeWalletCall(tx.input); + const call=w.calls[0],{args}=decodeFunctionData({abi:UNIVERSAL_GATEWAY_PC,data:call.data}),req=args[0]; + const original=parseAgwSvmPayload(req.payload),block=BigInt(process.argv[3]); + const client=await PushChain.initialize({address:'0x0000000000000000000000000000000000005678',chain:PushChain.CONSTANTS.CHAIN.PUSH_TESTNET_DONUT},{network:PushChain.CONSTANTS.PUSH_NETWORK.TESTNET_DONUT}); + const record=await client.agentic.wallet(tx.to).rules.get(w.rulesId); + // Wrong recipient: swap the recipient ATA (account 2) for an ATA owned by someone else. + const other=PublicKey.findProgramAddressSync([new PublicKey('11111111111111111111111111111112').toBuffer(),new PublicKey('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA').toBuffer(),new PublicKey('EiXDnrAg9ea2Q6vEPV7E5TpTU1vh41jcuZqKjU5Dc4ZF').toBuffer()],new PublicKey('ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL'))[0]; + const payload={...original,accounts:original.accounts.map(a=>({...a})),instructionData:Uint8Array.from(original.instructionData)}; + payload.accounts[2].pubkey='0x'+other.toBuffer().toString('hex'); + const next={...req,amount:0n,payload:encodeAgwSvmPayload(payload.program,payload.accounts,payload.instructionData)}; + const data=v6.encodeExecuteAsAgent(w.rulesId,{...call,data:encodeFunctionData({abi:UNIVERSAL_GATEWAY_PC,functionName:'sendUniversalTxOutbound',args:[next]})}); + let refusal; + try{await rpc.call({account:tx.from,to:tx.to,data,blockNumber:block});refusal='NOT REFUSED';}catch(e){refusal=decodeAgenticRevert(e)||String(e.shortMessage||e.message);} + const out={at:new Date().toISOString(),readOnly:true,block:String(block),wallet:tx.to,rulesId:w.rulesId,originalAccounts:original.accounts,record,wrongRecipient:{ata:other.toBase58(),refusal}}; + fs.writeFileSync(process.argv[2],JSON.stringify(out,big,2)); + console.log(JSON.stringify({block:out.block,rule:record.rule,wrongRecipient:out.wrongRecipient,originalAccounts:original.accounts},big,1)); +})().catch(e=>{console.error(e.shortMessage||e.message);process.exitCode=1}); diff --git a/plan/agw/independent-review-creation-flow-2026-10-20/scripts/spl-readback-probe.cjs b/plan/agw/independent-review-creation-flow-2026-10-20/scripts/spl-readback-probe.cjs new file mode 100644 index 00000000..828e683a --- /dev/null +++ b/plan/agw/independent-review-creation-flow-2026-10-20/scripts/spl-readback-probe.cjs @@ -0,0 +1,31 @@ +// Read-only: stored SPL rule readback + wrong-recipient refusal via eth_call. No keys. +const root='/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk',fs=require('node:fs'); +const {createPublicClient,http,decodeFunctionData,encodeFunctionData}=require(root+'/node_modules/viem'); +const built=root+'/dist/packages/core/src'; +const {PushChain}=require(built); +const {v6}=require(built+'/lib/agentic/contracts/v6'); +const {UNIVERSAL_GATEWAY_PC}=require(built+'/lib/constants/abi'); +const {parseAgwSvmPayload,encodeAgwSvmPayload}=require(built+'/lib/agentic/execution/svm-payload'); +const {decodeAgenticRevert}=require(built+'/lib/agentic/revert'); +const {PublicKey}=require(root+'/node_modules/@solana/web3.js'); +const big=(_k,v)=>typeof v==='bigint'?String(v):v; +(async()=>{ + const rpc=createPublicClient({transport:http('https://evm.donut.rpc.push.org/',{timeout:15000,retryCount:1})}); + const hash='0x119c89e9ff7c7cccdfc8c071fade2488aa28b0eff7d9b71f7f0cf247c958bbf5'; + const tx=await rpc.getTransaction({hash}),w=v6.decodeWalletCall(tx.input); + const call=w.calls[0],{args}=decodeFunctionData({abi:UNIVERSAL_GATEWAY_PC,data:call.data}),req=args[0]; + const original=parseAgwSvmPayload(req.payload),block=await rpc.getBlockNumber(); + const client=await PushChain.initialize({address:'0x0000000000000000000000000000000000005678',chain:PushChain.CONSTANTS.CHAIN.PUSH_TESTNET_DONUT},{network:PushChain.CONSTANTS.PUSH_NETWORK.TESTNET_DONUT}); + const record=await client.agentic.wallet(tx.to).rules.get(w.rulesId); + // Wrong recipient: swap the recipient ATA (account 2) for an ATA owned by someone else. + const other=PublicKey.findProgramAddressSync([new PublicKey('11111111111111111111111111111112').toBuffer(),new PublicKey('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA').toBuffer(),new PublicKey('EiXDnrAg9ea2Q6vEPV7E5TpTU1vh41jcuZqKjU5Dc4ZF').toBuffer()],new PublicKey('ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL'))[0]; + const payload={...original,accounts:original.accounts.map(a=>({...a})),instructionData:Uint8Array.from(original.instructionData)}; + payload.accounts[2].pubkey='0x'+other.toBuffer().toString('hex'); + const next={...req,amount:0n,payload:encodeAgwSvmPayload(payload.program,payload.accounts,payload.instructionData)}; + const data=v6.encodeExecuteAsAgent(w.rulesId,{...call,data:encodeFunctionData({abi:UNIVERSAL_GATEWAY_PC,functionName:'sendUniversalTxOutbound',args:[next]})}); + let refusal; + try{await rpc.call({account:tx.from,to:tx.to,data,blockNumber:block});refusal='NOT REFUSED';}catch(e){refusal=decodeAgenticRevert(e)||String(e.shortMessage||e.message);} + const out={at:new Date().toISOString(),readOnly:true,block:String(block),wallet:tx.to,rulesId:w.rulesId,originalAccounts:original.accounts,record,wrongRecipient:{ata:other.toBase58(),refusal}}; + fs.writeFileSync(process.argv[2],JSON.stringify(out,big,2)); + console.log(JSON.stringify({block:out.block,rule:record.rule,wrongRecipient:out.wrongRecipient,originalAccounts:original.accounts},big,1)); +})().catch(e=>{console.error(e.shortMessage||e.message);process.exitCode=1}); diff --git a/plan/agw/independent-review-creation-flow-2026-10-20/scripts/trace-bnb.cjs b/plan/agw/independent-review-creation-flow-2026-10-20/scripts/trace-bnb.cjs new file mode 100644 index 00000000..31d6129d --- /dev/null +++ b/plan/agw/independent-review-creation-flow-2026-10-20/scripts/trace-bnb.cjs @@ -0,0 +1,8 @@ +const path=require('node:path');const built='/Users/shoaibmohammed/Desktop/work/PUSH/push-chain-sdk/dist/packages/core/src'; +const {PushChain}=require(built);const {CHAIN,PUSH_NETWORK}=PushChain.CONSTANTS; +const {getNativePRC20ForChain}=require(path.join(built,'lib/orchestrator/internals/helpers')); +(async()=>{for (const chain of [CHAIN.PUSH_TESTNET_DONUT, CHAIN.ETHEREUM_SEPOLIA]) { + const client=await PushChain.initialize({address:'0x0000000000000000000000000000000000005678',chain},{network:PUSH_NETWORK.TESTNET_DONUT,printTraces:true}); + const rt=client.agenticRuntime; console.log('#### origin',chain); + const q=await rt.quoteOutbound(getNativePRC20ForChain(CHAIN.BNB_TESTNET,rt.network),BigInt(2000000),CHAIN.BNB_TESTNET); + console.log('#### result',chain,String(q.nativeValueForGas));}})().catch(e=>{console.error('ERR',e.message);process.exitCode=1}); diff --git a/plan/agw/independent-review-creation-flow-2026-10-20/scripts/uregistry-probe.cjs b/plan/agw/independent-review-creation-flow-2026-10-20/scripts/uregistry-probe.cjs new file mode 100644 index 00000000..12e01d54 --- /dev/null +++ b/plan/agw/independent-review-creation-flow-2026-10-20/scripts/uregistry-probe.cjs @@ -0,0 +1,50 @@ +// Read-only abci_query of the node's uregistry token configs (canonical route registry). +const fs = require('node:fs'); +const RPC = 'https://donut.rpc.push.org:443'; +function varint(buf, i) { let x = 0n, s = 0n; for (;;) { const b = buf[i++]; x |= BigInt(b & 0x7f) << s; if (!(b & 0x80)) break; s += 7n; } return [x, i]; } +function fields(buf) { + const out = []; let i = 0; + while (i < buf.length) { + let key; [key, i] = varint(buf, i); + const no = Number(key >> 3n), wt = Number(key & 7n); + if (wt === 0) { let v; [v, i] = varint(buf, i); out.push([no, v]); } + else if (wt === 2) { let l; [l, i] = varint(buf, i); out.push([no, buf.subarray(i, i + Number(l))]); i += Number(l); } + else if (wt === 5) { out.push([no, buf.subarray(i, i + 4)]); i += 4; } + else if (wt === 1) { out.push([no, buf.subarray(i, i + 8)]); i += 8; } + else throw new Error('wire type ' + wt); + } + return out; +} +const str = (b) => Buffer.from(b).toString('utf8'); +function tokenConfig(buf) { + const t = {}; + for (const [no, v] of fields(buf)) { + if (no === 1) t.chain = str(v); else if (no === 2) t.address = str(v); else if (no === 3) t.name = str(v); + else if (no === 4) t.symbol = str(v); else if (no === 5) t.decimals = Number(v); else if (no === 6) t.enabled = v === 1n; + else if (no === 7) t.liquidityCap = str(v); else if (no === 8) t.tokenType = Number(v); + else if (no === 9) { t.native = {}; for (const [n2, v2] of fields(v)) { if (n2 === 1) t.native.denom = str(v2); if (n2 === 2) t.native.contractAddress = str(v2); } } + } + return t; +} +async function abci(path, dataHex) { + const url = `${RPC}/abci_query?path=%22${encodeURIComponent(path)}%22&data=0x${dataHex}`; + const r = await (await fetch(url)).json(); + if (!r.result || r.result.response.code) throw new Error(JSON.stringify(r).slice(0, 400)); + return { height: r.result.response.height, value: Buffer.from(r.result.response.value || '', 'base64') }; +} +async function main() { + const out = { at: new Date().toISOString(), rpc: RPC, readOnly: true }; + const info = await (await fetch(`${RPC}/abci_info`)).json(); + out.node = info.result.response; + // pagination { limit: 1000 } + const req = Buffer.from([0x0a, 0x03, 0x18, 0xe8, 0x07]); + const r = await abci('/uregistry.v1.Query/AllTokenConfigs', req.toString('hex')); + out.height = r.height; + out.tokenConfigs = fields(r.value).filter(([no]) => no === 1).map(([, v]) => tokenConfig(v)); + const rc = await abci('/uregistry.v1.Query/AllChainConfigs', req.toString('hex')); + out.chainConfigCount = fields(rc.value).filter(([no]) => no === 1).length; + out.chainConfigsRaw = fields(rc.value).filter(([no]) => no === 1).map(([, v]) => fields(v).filter(([n]) => n === 1).map(([, s]) => str(s))[0]); + fs.writeFileSync(process.argv[2], JSON.stringify(out, (_k, v) => (typeof v === 'bigint' ? v.toString() : v), 2)); + console.log('ok height', out.height, 'tokens', out.tokenConfigs.length); +} +main().catch((e) => { console.error(e.message); process.exitCode = 1; }); diff --git a/plan/agw/independent-review-creation-flow-2026-10-20/team-questions.md b/plan/agw/independent-review-creation-flow-2026-10-20/team-questions.md new file mode 100644 index 00000000..ffc8f8f9 --- /dev/null +++ b/plan/agw/independent-review-creation-flow-2026-10-20/team-questions.md @@ -0,0 +1,82 @@ +# Team questions (draft only; nothing has been sent) + +> **Superseded on 21 October** by [questions-harsh.md](../questions-harsh.md) (product decisions, no recommendations, gas ceiling removed as UI work), [questions-aman.md](../questions-aman.md) (presets: tokens, routes, native ETH/BNB wrap), [questions-zaryab.md](../questions-zaryab.md) (AGW contract only) and [questions-core-gateway.md](../questions-core-gateway.md) (gas price, registry endpoint, deployed sources, Solana gateway). This file is the review-time snapshot. + +These are the smallest set of open questions after the review. Questions already answered by source, chain state or evidence are listed at the end, with their answers, so they can be dropped from our existing drafts. + +## Harsh (product / SDK spec) + +1. **Apps optional.** For "tokens only" rules, may the UI generate EVM ERC20 `transfer(to, amount)` permissions with **named recipients** and a **per-transfer** cap? + - That permission also lets the agent move tokens already in the wallet's destination account to those recipients, an unlimited number of times until expiry. + - Native coins (ETH/BNB) and Solana are excluded from this first version. + - Alternatives: any recipient (not recommended), or only the owner's own address on that chain. +2. **All tokens.** Should "no tokens selected" stay as "no tokens sent from Push" (current behaviour)? Should an explicit **"All supported tokens (N)"** choice expand into a visible list of at most 8 tokens per chain, each with its own cap? Only a new contract model could cover future tokens. +3. **Limit wording.** Can we ship the labels in [decision-matrix.md §D](decision-matrix.md)? They say per-send, per-action and per-transaction gas; that the total counts sends that later fail; that wallet-held funds are not counted; and that DEX price and slippage are not limited. + - Is a combined per-request limit, or a cumulative destination limit, required? Both need contract work. + - For Push-native rules, should the public shape expose total caps (`maxValueTotal`, call counts, cumulative token amount)? The contract already supports them; this is SDK and spec work only. +4. **Wrapped-native presets.** For the WETH/WBNB legs (DEX on Base, Arbitrum and BNB) and Sepolia EigenLayer WETH, may a preset export the native coin (pETH / pBNB) and wrap it on the destination, instead of exporting the wrapped ERC20? Caps would stay in the same units. This works with deployed contracts; it is SDK catalog work. +5. **Gas ceiling policy.** Which should we adopt? + - (a) A fixed 20 PC with a BNB-testnet caveat. + - (b) Per-chain ceilings, for example BNB 60 PC. + - (c) A public read-only gas-budget quote helper that the UI uses to prefill: at least 20 PC, or 2× the current first-send quote. + + Please also confirm that a per-transaction ceiling with no total gas limit is acceptable. +6. **Native function count.** Spec §6.h says 1..32 allowed calls for every chain. Deployed Push-native rules allow 8 distinct (target, function) pairs. Can the spec say 1..8 for Push rules, or is more than 8 a real requirement (contract change)? + +## Core / node owners (uregistry, UniversalCore) + +1. **Confirm the three Circle USDC routes** below support **outbound** delivery and are not being retired, despite the `.old` label: + + | Chain | Token | Push token | + |---|---|---| + | eip155:11155111 | `0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238` | `0x387b9C8Db60E74999aAAC5A2b7825b400F12d68E` | + | eip155:84532 | `0x036CbD53842c5426634e7929541eC2318f3dCF7e` | `0x84B62e44F667F692F7739Ca6040cD17DA02068A8` | + | eip155:421614 | `0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d` | `0xa261A10e94aE4bA88EE8c5845CbE7266bD679DD6` | + + - What we checked: they are enabled in the node's token registry at height 24,457,377; their on-chain source address, decimals (6) and outbound quotes are correct; and their supply is backed by the destination Vault. + - **What the SDK does next:** add address-keyed mappings, then run a funded test of creation and delivery. That makes DEXES Sepolia and LENDING Arbitrum route-ready. + +2. **Provision these routes, or say they won't be supported.** For each token we need: a uregistry `TokenConfig` (chain, address, decimals, enabled, and the Push token address); the Push token deployed and initialised with the matching source chain and address; UniversalCore gas config; an inbound gateway threshold; and Vault liquidity. + + | Token | Address | + |---|---| + | Sepolia Aave LINK | `0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5` | + | Sepolia WETH9 (EigenLayer strategy underlying) | `0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9` | + | Base Sepolia WETH | `0x4200000000000000000000000000000000000006` | + | Base Sepolia Aave LINK | `0x810D46F9a9027E28F9B01F75E2bdde839dA61115` | + | Base Sepolia Moonwell USDbC | `0x4616975f7E6045FD9737e95bC527e9e14c727BD2` | + | Base Sepolia Moonwell WETH | `0x663A6F02d547dFd639BF689FED298712f2FB69Fb` | + | Arbitrum Sepolia WETH | `0x980B62Da83eFf3D4576C647993b0c1D7faf17c73` | + | BNB testnet WBNB | `0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd` | + | BNB testnet USDT (Venus) | `0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c` | + | BNB testnet USDC (Venus) | `0x16227D60f7a0e586C66B005219dfc887D13C9531` | + + The WETH and WBNB legs can drop off this list if product approves the wrapped-native alternative (Harsh 4). + +3. **BNB testnet gas price.** Donut's `gasPriceByChainNamespace("eip155:97")` moved between 0.055, 0.11 and 1.1 gwei within about 100 minutes (blocks 24,455,072–24,457,472). Is that expected oracle behaviour? It decides whether a 20 PC ceiling covers a first BNB send. +4. **Supported registry endpoint.** Can the SDK rely on `abci_query /uregistry.v1.Query/AllTokenConfigs` (or a public REST/gRPC endpoint) as the canonical route source, or should it ship a snapshot? +5. **Deployed UniversalCore source.** Which commit is deployed? It returns 6 values (with `gasLimitUsed`) and reverts below the base limit; core `main` (`b2f22241`) returns 5. + +## Gateway owners (Solana) + +1. **Which source is deployed at `CFVSincHYbETh2k7w6u1ENEkjbSLtveRCEBupKidw2VS`?** The pinned `gateway-testnet@b205770f` declares `DJoF…`. + - Please confirm the finalize gas formula is "signature fee + `ExecutedSubTx` rent + first-use CEA ATA rent". Live reimbursements matched it: 2,184,320 and 695,880 lamports. + - Is the unused `gas_fee` refunded to the wallet on Push? +2. **A second E2E program.** Can the gateway run a CEA-signed CPI into SPL Memo v2 (`MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr`, non-Anchor, data only)? If not, please give us a devnet program ID and IDL for a reviewed program with fixed-width arguments that moves SPL tokens. + +## AGW contract owners (Zaryab) + +1. **Native ceiling.** Confirm 8 native actions is intentional for v6. Ask only if Harsh's answer to question 6 is "more than 8". +2. **`fromEnd` data pins (information only).** Rules do not limit instruction-data length. Can an agent append trailing bytes that a `fromEnd` pin would read, while the program ignores them? The SDK does not expose `fromEnd` today. + +## Already answered: remove from our drafts + +| Old question | Answer | +|---|---| +| "Canonical PRC20s for the preset tokens?" (questions-zaryab) | Partly answered by the node registry: the three Circle USDC routes exist. Only the list in Core question 2 remains | +| "Does gateway allow-listing establish a route?" | No. `isSupportedToken` is an inbound threshold only (`UniversalGateway.sol:770`). Outbound needs Vault liquidity (`Vault.sol:417-423`) or the TSS balance for native coins | +| "Do Solana pins enforce wallet token accounts in every case?" (questions-zaryab 2) | Answered by source. URP cannot check which account belongs to whom (`Types.sol:585-587`); the owner pins positions, and the SDK pins the wallet's token account. Pins compare exact keys; writable and signer flags are not checked | +| "Are allowed functions required?" | Yes. EVM: `AllowListOutOfRange(0)` (URP:347). Solana: at least one program rule, each with an account pin (`SvmRulebook.sol:132, 251`). Every request needs at least one call | +| "Is there an asset wildcard?" | No. 1..8 explicit Push tokens on the chain; no sentinel (`RulesLib.sol:39`, `:64-71`) | +| "What does the total cap count?" | Only the amount sent from Push per request, over the rule's lifetime. Never decremented; `creditRevert` is inactive (URP:584-608, 1052) | +| "What does the 10 PC quote mean?" | The SDK's $1 minimum at the fixed $0.10 rate for Push-native signers. Gas actually spent was 0.0008–2.37 PC | diff --git a/plan/agw/questions-aman.md b/plan/agw/questions-aman.md new file mode 100644 index 00000000..92749c08 --- /dev/null +++ b/plan/agw/questions-aman.md @@ -0,0 +1,74 @@ +# Preset questions for Aman: agentic wallet presets + +Updated October 21, 2026. Draft; nothing sent. What we verified ourselves is in [pre-question findings](research/pre-question-findings-2026-10-21/README.md). + +## Context + +Presets are ready-made agent rules for popular apps: + +- **DEX:** Uniswap or PancakeSwap. +- **Lending:** Aave, Moonwell, Venus. +- **Staking:** EigenLayer. + +Each preset lists the exact tokens that app uses on each test chain, with default limits. + +A preset can be created only if every one of its tokens can be sent from Push to that chain. That requires a Push token (PRC20) route for that exact token. The SDK never swaps in a different token with the same name, because the app would not accept it. + +Status with the latest SDK update (not yet released). Both ready presets passed a live test on October 21: + +| Preset | Sepolia | Base Sepolia | Arbitrum Sepolia | BNB testnet | +|---|---|---|---|---| +| DEX | **ready, live-tested** | blocked: WETH | blocked: WETH | blocked: WBNB, USDT | +| Lending | blocked: LINK | blocked: LINK, Moonwell USDbC and WETH | **ready, live-tested** | blocked: Venus USDT, USDC | +| Staking | blocked: WETH (EigenLayer) | — | — | — | + +--- + +## 1. Will the three Circle USDC routes be kept? + +The two ready presets depend on these node routes: + +| Chain | Token on that chain | Push token | +|---|---|---| +| Sepolia | `0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238` | `0x387b9C8Db60E74999aAAC5A2b7825b400F12d68E` ("USDC.eth.old") | +| Base Sepolia | `0x036CbD53842c5426634e7929541eC2318f3dCF7e` | `0x84B62e44F667F692F7739Ca6040cD17DA02068A8` ("USDC.base.old") | +| Arbitrum Sepolia | `0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d` | `0xa261A10e94aE4bA88EE8c5845CbE7266bD679DD6` ("USDC.arb.old") | + +What we have verified: + +- On October 21, sends through all three routes were delivered on Sepolia, Base and Arbitrum. The two presets also passed over them. +- The routes were renamed ".old" on April 16 (node commit `c84f9a97`), when the plain "USDC" names were pointed at newer mock tokens. Nothing marks them deprecated. +- The node's `develop` branch no longer contains their config files. That only matters if configs are ever re-synced from `develop`. +- Removing one of these configs would stop every holder of that Push token from withdrawing it. + +**Question:** can we treat these three routes as permanent for the presets? If they will be retired, what is the replacement? + +## 2. Can the missing preset-token routes be added? + +These preset tokens have no route today: + +- Sepolia: Aave LINK `0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5`; WETH used by EigenLayer `0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9` +- Base Sepolia: WETH `0x4200000000000000000000000000000000000006`; Aave LINK `0x810D46F9a9027E28F9B01F75E2bdde839dA61115`; Moonwell USDbC `0x4616975f7E6045FD9737e95bC527e9e14c727BD2`; Moonwell WETH `0x663A6F02d547dFd639BF689FED298712f2FB69Fb` +- Arbitrum Sepolia: WETH `0x980B62Da83eFf3D4576C647993b0c1D7faf17c73` +- BNB testnet: WBNB `0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd`; Venus USDT `0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c`; Venus USDC `0x16227D60f7a0e586C66B005219dfc887D13C9531` + +From the node code, adding a route takes all of the following: + +1. A token config added by the registry admin (`MsgAddTokenConfig`; admin `push1negskcfqu09j5zvpk7nhvacnwyy2mafffy7r6a`). +2. A Push token deployed for that exact source token. +3. Gas configuration in UniversalCore. +4. A WPC pool. +5. Support in the destination gateway and vault. + +**Question:** which of these can be added, by whom, and roughly when? Which will not be supported? For those, we could choose different reviewed tokens for the preset. + +## 3. May presets send native ETH/BNB instead of WETH/WBNB? + +Sending native ETH/BNB from Push already works on all four test chains. For the presets that need WETH or WBNB (DEX on Base, Arbitrum and BNB, and Sepolia staking), the preset could send native ETH/BNB, then wrap it into WETH/WBNB on arrival, with the same amounts and limits. The app still receives the WETH/WBNB it expects. + +| Option | Result | +|---|---| +| A. Allow native plus wrap | Those presets don't wait for WETH/WBNB routes. The preset shows ETH/BNB as the token sent from Push. SDK work only | +| B. Keep WETH/WBNB exactly | Those presets wait for the WETH/WBNB routes in question 2 | + +**Decision needed:** A or B. With A, the WETH/WBNB entries can be dropped from question 2. diff --git a/plan/agw/questions-core-gateway.md b/plan/agw/questions-core-gateway.md new file mode 100644 index 00000000..3fb6cd4e --- /dev/null +++ b/plan/agw/questions-core-gateway.md @@ -0,0 +1,58 @@ +# Questions for the core/node and gateway teams + +Updated October 21, 2026. Draft; nothing sent. + +- AGW contract questions are in [questions-zaryab.md](questions-zaryab.md). +- Preset token routes are in [questions-aman.md](questions-aman.md). +- What we verified ourselves (node `testnet/donut` `ca3b8d4e`, deployed contracts, live runs) is in [pre-question findings](research/pre-question-findings-2026-10-21/README.md). + +--- + +## Core / node team + +### 1. Is wiring `creditRevert` for failed agent sends planned? + +When an agentic wallet's outbound fails on the destination, the node re-mints the token to the wallet and refunds unused gas. + +But the wallet's rule still counts that amount against its total limit. The AGW policy has `creditRevert` to undo the count. Its own comment says the executor module does not call it yet, and no node code on any branch calls it. + +**Question:** is calling `creditRevert` on failed outbounds from AGW wallets planned, and when? Until then we tell users that failed sends count toward the total. + +### 2. BNB testnet gas price: is the current voting setup intended? + +The BNB testnet gas price on Donut jumps between 0.055, 0.11 and 1.1 gwei, often within minutes. From the node code and chain data: + +- Each validator reads `eth_gasPrice` from a rotating public RPC and adds 10%. +- Only two validators vote for BSC testnet, and the chain takes the higher of the two. +- There is no smoothing or clamp. + +A first agent send to BNB testnet then needs about 2.4 PC or about 24 PC, depending on the moment. + +**Question:** is this setup intended? Could more validators vote, or could a smoothing window or a clamp be added? + +### 3. Can the SDK rely on `abci_query` to read the token registry? + +The REST and gRPC query endpoints aren't reachable publicly. Tendermint `abci_query /uregistry.v1.Query/AllTokenConfigs` on `donut.rpc.push.org` works. + +The SDK uses it in a check that the SDK's routes match the node. + +**Question:** is this a supported way to read the registry, or will a public REST endpoint be exposed? + +### 4. Can the `.old` USDC config files be restored on `develop`? + +The live registry keeps the three `USDC.*.old` routes, which two presets depend on. But the node's `develop` branch dropped their config files (merge `47ef4c9a`). `testnet/donut` and main still have them. + +**Question:** can they be restored on `develop`, so a future config sync doesn't remove routes in use? + +--- + +## Core and gateway teams + +### 5. Can the exact deployed sources be committed or tagged? + +We matched both deployments by bytecode and build strings, but neither exact source is in any commit: + +- **UniversalCore** on Donut (implementation `0xa0023b35…`) matches `core-testnet` `8bc60ae`. The verified file differs only in import paths and comments. +- **The Solana gateway at `CFVS…`** was built from `pc20-3rd-iteration` with `declare_id` changed locally. No branch declares CFVS. + +**Question:** can the exact deployed sources be committed or tagged, so the SDK and audits can pin them? diff --git a/plan/agw/questions-harsh.md b/plan/agw/questions-harsh.md index a4e52342..5441c1ec 100644 --- a/plan/agw/questions-harsh.md +++ b/plan/agw/questions-harsh.md @@ -1,20 +1,91 @@ -# AGW preset limit semantics — remaining product clarification +# Product decisions for Harsh: agentic wallet creation -Updated October 16, 2026. Local draft; nothing sent. +Updated October 21, 2026. Draft; nothing sent. -## What should the UI's spending limits mean? +These questions come from Riyanshu's feedback on the wallet-creation screen. Each one describes how things work today, then the choices. Some choices need extra work from Zaryab (contracts), and that is noted where it applies. The SDK can implement whichever option you pick. Preset questions (preset tokens and routes) are with Aman in [questions-aman.md](questions-aman.md). -Current contracts enforce two different scopes: +Terms used: -- An operation amount maximum applies to each allowed call. A batch can contain several calls, each within that maximum. -- Asset maxTotal counts tokens sent from Push. It does not count repeated swaps/lending/staking using assets already in the destination CEA. +- **Rule:** what the owner grants an agent: which apps it may call, which tokens it may move, and limits. +- **Destination account:** the wallet's own account on the other chain (Sepolia, Base, Solana, …). Tokens sent from Push land there first, and the agent's app actions run from there. -Should the product require a combined limit across destination calls in one transaction, or a cumulative destination-spend limit? Either requires contract accounting beyond the current limits. Until then, the UI should label the implemented scopes explicitly and must not describe maxTotal as a lifetime trading budget. +--- -## SDK delivery and documentation synchronization +## 1. Can a rule allow token transfers without picking any app? -The SDK now generates token/amount restrictions for supported lending/staking calls and returns readiness, disabled/excluded call reasons and known token choices. The wallet UI must collect inputs, call presets.get again when they change, and pass the regenerated rule to rules.update. Missing caps remain zero; the SDK supplies no 0.1 PC or 30-day defaults. +**Today.** A rule must include at least one app action, such as "swap on Uniswap". The contract rejects a rule that has tokens but no actions. Riyanshu expected the owner to be able to pick only tokens and leave apps empty. -Share-based redeem uses the bounded redeemUnderlying alternative. Dynamic/position-derived withdrawals are excluded from bounded presets. No answer is required to continue the implemented scope; the question above determines whether a larger contract change is wanted. +**What we can build.** We can build a "transfer" action automatically, so a tokens-only rule becomes a rule that allows sending those tokens. The decision is who the agent may send them to: -[Implementation and evidence](research/preset-configuration-2026-10-16/README.md). +| Option | What the agent could do | Extra work | +|---|---|---| +| A. Named recipients | Send the selected tokens only to addresses the owner enters, up to a per-transfer amount | SDK only | +| B. Any recipient | Send the selected tokens to any address, up to a per-transfer amount | SDK only | +| C. Owner's own address | Send tokens only back to the owner's address on that chain | SDK only | +| D. Keep apps required | No change; the screen explains that an app must be chosen | UI text only | + +**Things to know whichever option you pick:** + +- The permission also covers tokens already sitting in the destination account, not only tokens sent from Push. +- The per-transfer limit applies to each transfer. The agent can repeat transfers until the rule expires, so there is no total limit on transfers made on that chain. +- This works for regular tokens (ERC20) on EVM chains. + - Native coins (ETH/BNB) can't be sent this way. They would arrive as wrapped WETH/WBNB instead. + - On Solana it is not possible at all without contract changes. + +**Decision needed:** A, B, C or D. If A, B or C: is EVM tokens only acceptable for the first version? + +--- + +## 2. What should "no tokens selected" mean? + +**Today.** If the owner selects no tokens, the agent cannot move any tokens out of Push. Riyanshu expected no selection to mean "all tokens allowed". + +**How the contract works.** A rule can list at most 8 tokens per chain, and each needs its own limit. There is no "any token" setting, and tokens added later are never included automatically. + +| Option | What it means | Extra work | +|---|---|---| +| A. Keep as is | No tokens selected means no tokens can be moved | None | +| B. "All supported tokens" button | One click fills in every supported token for that chain (currently 3–7 per chain). The owner still sees the list, and each token gets its own limit | SDK and UI | +| C. True "any token" | Covers every token, including ones added in the future, under one limit | New contract design (Zaryab) | + +**Note on option B.** It needs a limit for each token, because amounts differ by token (for example 10 USDC versus 0.001 ETH). Either the owner enters them, or we supply a reviewed default per token. + +**Decision needed:** A, B or C. If B: should the owner enter each limit, or should we supply defaults? + +--- + +## 3. What do the spending limits mean, and are they strong enough? + +**Today.** These are the limits the contracts actually enforce: + +| Limit | What it really controls | +|---|---| +| Per send from Push | The most of a token sent from Push in one transaction | +| Total from Push | The most of a token sent from Push over the rule's life. It also counts sends that later fail on the other chain. It does **not** count funds already on the other chain | +| Per action (swap, lend, etc.) | The most used in one action. The agent can repeat actions until the rule expires | +| Gas per transaction | The most PC attached for gas in one transaction; unused gas is refunded. There is no total gas limit | + +**Not limited today:** the price a swap gets (slippage), and total borrowing on lending apps. Borrowing is limited per action only. + +**Decisions needed:** + +1. Is it acceptable to ship with these limits, with labels that describe them exactly as above? +2. Do you need either of these stronger limits? + - a. a total limit for activity on the other chain (for example "at most 100 USDC of swaps in total"); + - b. a limit on the combined amount of all actions in one transaction. + + Both need contract work (Zaryab). +3. Rules for apps on Push itself can already enforce totals (a total amount and a maximum number of uses) in the contract. The SDK doesn't offer them yet. Should it? This is SDK work only. + +--- + +## 4. How many app actions can a Push-chain rule have? + +**Today.** The SDK spec says a rule can have 1 to 32 app actions on every chain. The deployed contract allows 32 for other chains, but only 8 for rules about apps on Push itself. The contract source says 8 was chosen on purpose, to keep what an owner approves at once readable (not because of gas), and that raising it is a design change. Owners who need more can create more than one rule for the same agent. + +| Option | Extra work | +|---|---| +| A. Change the spec to "up to 8 for Push-chain rules" | Spec text only | +| B. Ask for more than 8 | Contract design change and redeployment (Zaryab) | + +**Decision needed:** A or B. If B, how many are needed? diff --git a/plan/agw/questions-zaryab.md b/plan/agw/questions-zaryab.md index e634f7bf..749f3bdc 100644 --- a/plan/agw/questions-zaryab.md +++ b/plan/agw/questions-zaryab.md @@ -1,16 +1,44 @@ -# AGW SDK — contract delivery and confirmation +# Contract questions for Zaryab: agentic wallet (AGW) v6 -October 12, 2026. Local draft; nothing has been sent. Source: [contract feedback §6](https://app.notion.com/p/pushprotocol/1-AGW-Contract-Changes-nomenclature-standard-change-set-3e9188aea7f4813aa31fc95ceb4e684d). V6 is deployed; contract-owner dry runs are still ongoing. Existing v5 labels and ref removal are already delivered. +Updated October 21, 2026. Draft; nothing sent. -## V6 delivery received October 14 +These questions cover only the deployed AGW contracts (source `ffd567d`). What we verified ourselves is in [pre-question findings](research/pre-question-findings-2026-10-21/README.md). -Atomic factory creation, automatic gateway approvals and general EVM EQ/MAX pins are delivered in source `ffd567d` and the v6 address book. The SDK has migrated these locally; 99 contract-backed cases and all 69 live scenarios have passing coverage (full run plus focused follow-up). Your independent dry runs remain separate. No repeat request for these delivered interfaces or deployment addresses. +--- -New wire details are accounted for: native maxCalls = uint32 maximum, Solana any-count = 255, pins = (offset, op, value). The policy still reports 3.1.0, so deployment wiring/source pin identify v6. +## 1. Solana `fromEnd` data pins can be shifted by appending bytes. Is a fix planned? -## Confirmations still needed +From the source (`SvmRulebook.sol`): -1. **Native call ceiling:** SDK §6.h says 1..32 allowed calls; deployed AGW permits eight native actions. Should this deployment increase the native ceiling, or should the spec explicitly retain eight? -2. **Solana wallet-token-account pins:** SDK §6.k asks whether the policy enforces these in every supported case. The SDK derives the wallet CEA and token-program-specific ATA and has local/live SPL evidence; please confirm the intended policy boundary beyond those tested cases. +- **No length rule per program.** `AllowedProgram` has no instruction-data length field. The only length checks are: + - the global 1024-byte cap; + - the exact outer-payload length; + - for rule matching, `ixLen >= discriminatorLen`. +- **How `fromEnd` reads.** `_resolveOffset` returns `ixLen - offset` once the data is long enough (`:666-677`). So an agent can append N bytes inside the instruction data and raise the length field to match. The payload is still well-formed, and every `fromEnd` pin then reads the appended bytes. +- **Example.** On a Jupiter-style layout, the agent could append bytes that satisfy the fee, slippage and ratio pins while the real arguments earlier in the data say something else. Account pins still hold. +- **Test coverage.** There is no test that appends bytes inside the instruction data. `test_svm_S17_fromEndDataTooShortByOne` shows the read position moving with the length. +- **When it matters.** Exploitability depends on whether the target program ignores trailing instruction data. -Push-core revert credit and platform terminal-status latency remain downstream items, separate from this contract change set. [Full implementation/deployment boundary](section6-action-items.md). +**Possible fixes:** +- a per-rule exact (or maximum) instruction-data length for fixed-layout instructions; or +- refusing `fromEnd` pins unless such a length is set. + +**Question:** is a fix planned? The SDK never creates `fromEnd` pins, so SDK-authored rules aren't affected. + +## 2. Only if Harsh asks for them: are these feasible, and roughly how much work? + +Harsh is deciding product options that would need contract changes. No change is requested yet. + +1. **A total limit on activity on the destination chain.** Today pins and `maxValue` limit each call, and nothing adds them up across calls or transactions. +2. **A combined limit within one transaction.** The sum of a pinned amount across up to 10 calls in one request. +3. **"Any token" assets.** Today a rule holds 1–8 explicit PRC20s and there is no wildcard. +4. **Token transfers on Solana without an app program.** `SvmRulebook` forbids the System and SPL Token programs, so an agent can move SOL or SPL only through an allow-listed program's CPI. Could a constrained transfer (fixed recipient, capped amount) be allowed? +5. **More than 8 actions for Push-chain rules.** The source calls 8 a deliberate sanity bound, and raising it a design change. + +--- + +## Already answered from source; no longer asked + +- **Why 8 native actions.** It is a deliberate sanity bound for readability, the duplicate scan and revoke cost, not a gas bound (`AGW.sol:73-86`, `docs/1_AGW.md:532,573`). The session engine has no cap. +- **`creditRevert`.** No node code calls it on any branch, so a failed send still counts against `maxTotal`. Wiring it is node work; that question is in [questions-core-gateway.md](questions-core-gateway.md). +- **Solana token-account ownership.** The policy cannot check it (`Types.sol:585-587`). The owner pins positions, and the SDK pins the wallet's token account. Pins compare exact keys; writable and signer flags are not checked. diff --git a/plan/agw/research/pre-question-findings-2026-10-21/README.md b/plan/agw/research/pre-question-findings-2026-10-21/README.md new file mode 100644 index 00000000..fd240992 --- /dev/null +++ b/plan/agw/research/pre-question-findings-2026-10-21/README.md @@ -0,0 +1,69 @@ +# Answers we could establish before asking the team: 21 October 2026 + +These answers come from read-only analysis of the deployed node, contract and gateway code, from on-chain data, and from funded testnet runs. The question drafts in `plan/agw/questions-*.md` now contain only what this work could not settle. + +## Sources pinned + +| Component | Deployed source | How confirmed | +|---|---|---| +| Push node (Donut) | `push-chain` `origin/testnet/donut` = release/v1.1.44-donut, `ca3b8d4e` | Newest upgrade `cea-read-ingest` applied at height 23,217,721 (abci `AppliedPlan`). Later commits on `develop` are not deployed | +| UniversalCore `0x…C0` | `push-chain-core-contracts` `origin/core-testnet`, `src/UniversalCore.sol` from `8bc60ae` | EIP-1967 proxy; implementation `0xa0023b356344ff623c7e20679cf9d170e44fbbd1` is verified on Blockscout. Compiling `8bc60ae` reproduces the bytecode; only the metadata hash differs. The exact verified file is not committed | +| Solana gateway `CFVS…` | Built from `push-chain-gateway-contracts` `pc20-3rd-iteration` (`da6cca5`…`bcbf7df`), with `declare_id` swapped to CFVS locally | Instruction-name strings, PC20 strings and the `emit_cpi` layout in the deployed binary (program data `DqeV1gi…`, deployed slot 496,655,369, 2026-09-11) match. No committed branch declares CFVS | +| AGW contracts | `ffd567d` (`deploy-agw` `e57998c`) | As in the review | + +## Answers + +### Routes and registry (Aman, core/node) +- **The Circle USDC `.old` routes settle outbound on all three chains.** + - Owner-door sends of 0.01 USDC were delivered on Sepolia (`0x7de758af…`, 1,286,650 gas), Base (`0xcd4f3ab7…`) and Arbitrum (`0xbc22d5c6…`). + - The DEXES Sepolia and LENDING Arbitrum presets also passed live over these routes. +- **Where they came from.** Node commit `c84f9a97` (2026-04-16) pointed the plain `USDC.*` names at new mock tokens and kept the previous Circle configs as `USDC.*.old`. + - Nothing marks them deprecated. + - `develop` no longer has their config files (dropped by merge `47ef4c9a`), so there is drift risk if configs are re-synced from `develop`. +- **`TokenConfig.enabled` is never read by the node.** A config's presence is what makes a route work. + - Removing a config would block withdrawals for existing holders of that PRC20. + - Outbound uses the registry's `address` as the destination token. The node never reads the PRC20's `SOURCE_TOKEN_ADDRESS`, so the zero word on Solana PRC20s does not matter to routing. +- **Adding a route is admin-curated.** `MsgAddTokenConfig` must be signed by the uregistry admin, `push1negskcfqu09j5zvpk7nhvacnwyy2mafffy7r6a`. A route also needs: + - the PRC20 deployed and initialised for that exact source token; + - UniversalCore gas token, base gas limit and voted gas prices; + - a WPC pool for auto-swap; + - destination gateway and vault support. +- **Reading the registry.** The public REST and gRPC endpoints are not reachable. Tendermint `abci_query /uregistry.v1.Query/AllTokenConfigs` works and is what `check-agw-route-registry.js` uses. + +### Gas (core/node, gateway) +- **Unused EVM destination gas is refunded** to the wallet (the revert recipient) as PC, in a later Push transaction. + - Example: our DEXES Sepolia subsequent send had gasFee 220,027,000,000 and used 362,079 gas at 220,027. + - Refund `RefundUnusedGas` in tx `0x75fad72a…ea92` (block 24,472,797): 140,359,843,867 pETH-wei, swapped to 0.000205 PC. + - So larger default gas limits cost only the gas actually used, minus swap slippage. +- **Unused Solana gas is also refunded.** The gateway keeps `gas_to_refund` in its vault and emits it. The node then refunds `gasFee − gas_used` the same way. Live events match: for example 960,000 budget, 695,880 used, 264,120 refunded. + - If a Solana outbound never executes, the full gas fee is refunded. +- **Why the BNB testnet gas price jumps.** + - Each validator reads `eth_gasPrice` from a different public RPC every interval and adds a 10% markup (operator config). + - Donut has only two voters for BSC testnet, and the chain takes the upper median, which is the higher vote. + - Providers report 0.05–1 gwei, and there is no smoothing or clamp. +- **Solana gas price.** The constant 1000 is the node's fallback when devnet priority fees are zero. +- **Base gas limits** (500,000 EVM; 960 Solana) are UniversalCore admin settings. +- **Gas limits are used as given.** The EVM destination transaction uses the request's gasLimit exactly, with no buffer. Solana compute is fixed at 400,000 CU; gasLimit only prices the fee. + +### Failure handling and policy (Zaryab, core/node) +- **On a failed destination execution** the node re-mints the bridged PRC20 to the revert recipient (the wallet) and refunds unused gas. + - Payload-only sends get no fund revert. + - The protocol fee is not refunded. +- **Nothing calls `UniversalRulesPolicy.creditRevert`.** I searched all 161 node branches; the contract itself says it ships inert. So a failed agent send still counts against the rule's `maxTotal`. Wiring it is node work. +- **`MAX_NATIVE_ACTIONS = 8` is a deliberate sanity bound, not a gas bound** (`AGW.sol:73-86`; `docs/1_AGW.md:532,573`). It keeps a grant readable and bounds the duplicate scan and revoke cost. The session engine has no cap, and raising the limit is described as a design change. +- **Confirmed SvmRulebook gap: `fromEnd` data pins can be shifted by appending bytes.** + - The instruction-data length is not tied to the matched rule; only a 1024-byte cap and an exact outer-payload length apply. + - So an agent can append bytes that a `fromEnd` pin then reads. + - Account pins still hold. Whether a target program ignores trailing data decides whether this is exploitable. + - The SDK does not create `fromEnd` pins. + +### Solana programs (gateway) +- **SPL Memo v2 works as a second test program.** Owner door: Push `0x480c55ae…`, Solana `kaQ3QrRC…`. Agent door: Push `0xae951445…`, Solana `4PF7bSEs…`. + - The agent door used a rule with a raw 8-byte prefix and a CEA pin. A different prefix was refused before broadcast. + - The gateway has no target-program allowlist; the CEA is the only CPI signer. + - Payload trap: the payload's target must be zero or equal to the recipient. The SDK already sets it equal. + +## Evidence files +- `live-routes-memo-evidence.json` and `live-routes-memo-results.log`: the five live cases above. +- Routed-preset and gas runs: `../../independent-review-creation-flow-2026-10-20/data/live-2026-10-21-*`. +- New opt-in e2e groups: `agw-exact-routes` (`__e2e__/agw/exact-routes-live.spec.ts`) and `agw-svm-memo` (`__e2e__/agw/svm-memo-live.spec.ts`). diff --git a/plan/agw/research/pre-question-findings-2026-10-21/live-routes-memo-evidence.json b/plan/agw/research/pre-question-findings-2026-10-21/live-routes-memo-evidence.json new file mode 100644 index 00000000..2d604ef6 --- /dev/null +++ b/plan/agw/research/pre-question-findings-2026-10-21/live-routes-memo-evidence.json @@ -0,0 +1,100 @@ +{ + "note": "Live runs 21 Oct 03:14-03:24Z: agw-exact-routes 3/3 (owner-door Circle USDC outbound on Sepolia, Base, Arbitrum) and agw-svm-memo 2/2 (SPL Memo v2 via owner and agent doors). Public hashes only.", + "entries": [ + { + "name": "exact-route-submitted", + "at": "2026-10-21T03:15:39.714Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "chain": "eip155:11155111", + "wallet": "0x05b5c17A66233E609dE7f7CC23B157CCEb8bFA3D", + "prc20": "0x387b9C8Db60E74999aAAC5A2b7825b400F12d68E", + "source": "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238", + "hash": "0xc356eb6e8999b1d150a348602dc764ae158bb731fb9a5797b3f8e122359da01f" + }, + { + "name": "exact-route-delivered", + "at": "2026-10-21T03:16:50.293Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "chain": "eip155:11155111", + "hash": "0xc356eb6e8999b1d150a348602dc764ae158bb731fb9a5797b3f8e122359da01f", + "destinationHash": "0x7de758afad801a85a3bfd31545bacdeb0c8fd79758a538ad0ae3d039c7cf7bd3", + "destinationGasUsed": "1286650" + }, + { + "name": "exact-route-submitted", + "at": "2026-10-21T03:17:36.797Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "chain": "eip155:84532", + "wallet": "0x97dfB17BCCB47c3810d383634bB43E7d13b89799", + "prc20": "0x84B62e44F667F692F7739Ca6040cD17DA02068A8", + "source": "0x036CbD53842c5426634e7929541eC2318f3dCF7e", + "hash": "0x0015d85dff1ef4f8c63d15017378beb567da1ecc0f82606ac53d9e0dea4f9978" + }, + { + "name": "exact-route-delivered", + "at": "2026-10-21T03:18:46.638Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "chain": "eip155:84532", + "hash": "0x0015d85dff1ef4f8c63d15017378beb567da1ecc0f82606ac53d9e0dea4f9978", + "destinationHash": "0xcd4f3ab74b5faf2a4181547b7cf31653d5b621f277e0aca22c65e286834e5307", + "destinationGasUsed": "364116" + }, + { + "name": "exact-route-submitted", + "at": "2026-10-21T03:19:23.271Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "chain": "eip155:421614", + "wallet": "0xF2C2f4420eCe850C1F47659Ead3cA79B6B5f781E", + "prc20": "0xa261A10e94aE4bA88EE8c5845CbE7266bD679DD6", + "source": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "hash": "0x07fab93586a60c1700e54f336ddf5ecd504c968651df03c611fa26aa463c9b65" + }, + { + "name": "exact-route-delivered", + "at": "2026-10-21T03:20:26.431Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "chain": "eip155:421614", + "hash": "0x07fab93586a60c1700e54f336ddf5ecd504c968651df03c611fa26aa463c9b65", + "destinationHash": "0xbc22d5c6ef2e7e42084844c0b52266b178b68248659f30a5c26a29ab01f9ac7e", + "destinationGasUsed": "364128" + }, + { + "name": "svm-memo-owner-submitted", + "at": "2026-10-21T03:21:04.090Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "wallet": "0xb6AE3C9018723cb53CdeE157986951662874202e", + "hash": "0x480c55ae4f5ee3fed337ee755a87bf4b5ce88c29ca845596366ad5cc3245ce78" + }, + { + "name": "svm-memo-owner-delivered", + "at": "2026-10-21T03:21:51.925Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "hash": "0x480c55ae4f5ee3fed337ee755a87bf4b5ce88c29ca845596366ad5cc3245ce78", + "destinationHash": "kaQ3QrRCgh4PXWhY5yWmEdWyUJ3kG6WYqZan4qva5mEccMXPPo1tFM99TPdUYvq77AqCCnpXadcJWASahHEdKVy" + }, + { + "name": "svm-memo-agent-submitted", + "at": "2026-10-21T03:23:01.198Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "wallet": "0x9b99895c74808c3691E4C41fda43F8f81609baaE", + "hash": "0xae951445c8473d2e83f7b06facd2f8523b846cebc5eb7b94056951893d7bd6d5" + }, + { + "name": "svm-memo-agent-delivered", + "at": "2026-10-21T03:23:56.719Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "hash": "0xae951445c8473d2e83f7b06facd2f8523b846cebc5eb7b94056951893d7bd6d5", + "destinationHash": "4PF7bSEs3jb1AFxqRub7fHbuc3ygfDy9sHqxJz24paJUN3gEi5bSmQU8b9Jd1ZVQAsLiHC1rLWVXrPPCnkCbH8rk" + } + ] +} \ No newline at end of file diff --git a/plan/agw/research/pre-question-findings-2026-10-21/live-routes-memo-results.log b/plan/agw/research/pre-question-findings-2026-10-21/live-routes-memo-results.log new file mode 100644 index 00000000..62e89f3d --- /dev/null +++ b/plan/agw/research/pre-question-findings-2026-10-21/live-routes-memo-results.log @@ -0,0 +1,15 @@ +2026-10-21T03:20:26Z +│ Push master (Donut) │ PC │ 67.0000 │ 967073.5565 │ ✓ │ +PASS core-e2e __e2e__/agw/svm-memo-live.spec.ts (196.945 s) + ✓ 1. owner door: the gateway runs Memo with the wallet CEA as signer (70999 ms) + ✓ 2. agent door: a raw-prefix rule with a CEA pin runs, another prefix is refused (124796 ms) +Tests: 2 passed, 2 total +2026-10-21T03:23:56Z +2026-10-21T03:14:40Z +│ Push master (Donut) │ PC │ 99.5000 │ 967136.5585 │ ✓ │ +PASS core-e2e __e2e__/agw/exact-routes-live.spec.ts (332.404 s) + ✓ 1. Sepolia Circle USDC (115006 ms) + ✓ 2. Base Sepolia Circle USDC (116342 ms) + ✓ 3. Arbitrum Sepolia Circle USDC (99791 ms) +Tests: 3 passed, 3 total +2026-10-21T03:20:26Z diff --git a/plan/agw/research/preset-acceptance-2026-10-20/README.md b/plan/agw/research/preset-acceptance-2026-10-20/README.md new file mode 100644 index 00000000..10df863e --- /dev/null +++ b/plan/agw/research/preset-acceptance-2026-10-20/README.md @@ -0,0 +1,69 @@ +# Preset acceptance, compatible tokens and gas — October 20, 2026 + +## Corrections (independent review, later the same day) + +Details are in the [review](../../independent-review-creation-flow-2026-10-20/review.md). + +- **Routes.** The node registry (uregistry) has enabled, Vault-backed routes for the exact Circle USDC on Sepolia, Base Sepolia and Arbitrum Sepolia. The SDK's symbol-keyed registry had omitted them, and the compatibility search below covered only that registry. After the SDK fix, DEXES Sepolia and LENDING Arbitrum Sepolia are route-ready; the other seven combinations remain blocked. +- **Gas.** "10 PC" is the SDK's $1 minimum budget at the fixed $0.10 rate used for Push-native signers. It is not a chain fee. On-chain `SwapAndBurnGas` shows 0.0008–2.37 PC actually consumed per send, with the remainder refunded in the same transaction. +- **Gas ceiling.** BNB testnet first sends exceed the 20 PC ceiling while Donut's BNB gas price is high (observed between 0.055 and 1.1 gwei). +- **Solana destination cost.** The relayer was reimbursed 2,184,320 lamports for the first send and 695,880 lamports for the subsequent send, including rent. The fee itself was 5,000 lamports. +- **Gateway allow-list.** The gateway's `isSupportedToken` is an inbound allow-list only. Outbound delivery needs Vault liquidity, or the TSS balance for native coins. +- **Live preset log.** `live-presets-blocked.log` was produced by an earlier revision of the spec file. The outcome is unchanged. + +## Result + +All nine unchanged preset payloads pass creation and exact readback against the pinned real v6 AGW/URP contracts with locally provisioned PRC20 stand-ins. Live unchanged-preset acceptance is blocked for all nine combinations before funding. Existing prefunded protocol tests remain useful but do not establish default-preset bridge availability. + +A fresh public agent SPL test passed on Donut/devnet: exact asset caps and wallet ATA pin survive creation; wrong ATA and an excessive instruction amount are refused without agent nonce advancement; two agent sends credit the owned recipient's USDT ATA exactly. Both sends omit gasLimit. Stored spend reaches exactly 2,000 raw USDT units. This is test_counter.receive_spl, not a newly certified third-party Solana app. The funded run checked reverts and unchanged nonce; a subsequent pinned eth_call probe confirmed the exact SvmDataCeilingExceeded and SvmAccountPinMismatch gates at Donut block 24,456,030 (spl-rejections.json). The test assertions were then strengthened to require those decoded names; no second funded run was needed for that assertion tightening. + +## Compatibility audit + +Read-only script: `packages/core/scripts/check-agw-preset-compatibility.js`. It loads the shipped catalog and source-token registry, checks exact PRC20 source identities on Donut, and queries reserves/underlyings and factory pools at recorded destination blocks. Snapshot: 2026-10-20T15:18:15.748Z; Donut block 24455488. See compatibility.json for every query result. + +| Network | Block | Routed-token compatibility | +|---|---|---| +| eip155:11155111 | 11956140 | No matched Aave reserve or fixed market/strategy underlying; no pool returned for queried routed ERC20 pairs at the preset router factory. | +| eip155:84532 | 48370608 | No matched Aave reserve or fixed market/strategy underlying; no pool returned for queried routed ERC20 pairs at the preset router factory. | +| eip155:421614 | 321097574 | No matched Aave reserve or fixed market/strategy underlying; no pool returned for queried routed ERC20 pairs at the preset router factory. | +| eip155:97 | 137909051 | No matched Aave reserve or fixed market/strategy underlying; no pool returned for queried routed ERC20 pairs at the preset router factory. | + +No default-token substitutions were made. Adding arbitrary routed USDC/USDT would generate unusable lending/staking permissions; the queried DEX factories have no routed pair to execute. This is bounded evidence for the current registry, catalog contracts, queried fee tiers and block snapshots, not proof that no alternative protocol or unpublished route exists. Wrapped-native and native coins are not interchangeable. + +The core/node/gateway team still needs to provide or provision exact source-token → PRC20 routes. The SDK can register verified mappings once provided. Mainnet execution was not attempted. + +## SDK gas fix + +Public Solana sends previously used gasLimit=1,000,000 when omitted. At the current Donut quote that requests 100 PC, exceeding a 20 PC rule. Omitted Solana gas now uses route sizing (0 as the quote input), retaining the existing live finalization/rent floor. Explicit gas inputs remain passed through. This changes neither rule caps nor the gas budget the owner authorizes. + +Current read-only quotes show 10 PC attached for checked EVM inputs and route-sized Solana. The old explicit million-unit Solana input quotes 100 PC. These are quote observations, not fixed future fees. The 0.1 PC custom-rule UI prefill is too small for these observed quotes. The existing 20 PC preset ceiling covers the observations and the fresh SPL deliveries; custom rule authoring still requires an explicit budget. + +Fresh SPL first-use quote: 10 PC, resolved input 2,285; subsequent quote: 10 PC, resolved input 960. On Solana the two transactions used 116,402 and 98,301 compute units and each charged a 5,000-lamport transaction fee. These differ from the quoted attached PC budget. Push signer gas was 0.0005265045 PC and 0.0005029245 PC respectively. See live-spl-evidence.json for hashes and Push blocks 24,455,663 and 24,455,695. No claim about exact net quote consumption/refunds is made. + +## Acceptance commands + +- Local: AGW_LOCAL_DIR=/tmp/agw-preset-defaults-v6 node node_modules/jest/bin/jest.js --config packages/core/jest.agw-local.config.ts --runInBand --runTestsByPath packages/core/__agw-local__/preset-acceptance.spec.ts +- Live unchanged presets: opt-in group agw-presets-acceptance (9 explicit cases). Preflight checks all nine readiness results before any funding; tests do not silently skip blocked routes. +- Live public SPL: opt-in group agw-svm-agent-spl. Exact wallet ATA pin, instruction cap and actual recipient delivery are asserted. +- Live EVM gas: opt-in group agw-gas. Four native-token routes, two agent sends each; results recorded separately from preset acceptance. + +## Validation and remaining scope + +405 AGW unit tests pass, 9 new real-contract local cases pass, spec/local typechecks and core build pass, package/guide checks pass. All 14 new live scenario selectors resolve to their expected tests. The nine live preset cases fail explicitly on unavailable routes before any funding. The one live SPL case passes and includes two destination deliveries. All four live EVM gas scenarios pass, including first/subsequent sends on every testnet (eight destination deliveries). Together with SPL, five live scenarios establish ten destination deliveries. These are distinct from the nine blocked preset scenarios. The funded SPL run preceded the assertion-only tightening described above. ESLint reports no errors in changed test/source files; existing-style non-null assertions generate warnings. + +No all-token wildcard, implicit arbitrary transfer permissions or default cap broadening was introduced. Apps-optional transfer recipients and all-token scope still require product/contract decisions. A separate devnet protocol recommendation still requires a compatible verified deployment; the successful SPL case continues to use the known test program. + +Changes remain local on v4; no release or publication is performed by this task. + +## Fresh EVM gas results + +One clean run: 4 passed, 0 failed, 715.584 seconds. Each scenario created a fresh wallet/rule, exported the chain's native PRC20 twice, confirmed destination receipt success and CEA-origin execution, and checked exact destination native balances and total rule spend. No gasLimit was supplied to either send. These are the existing counter fixtures, not preset protocols. + +| Testnet | First destination gas used | Subsequent destination gas used | +|---|---:|---:| +| Ethereum Sepolia | 1,265,722 | 223,683 | +| Base Sepolia | 325,448 | 123,187 | +| Arbitrum Sepolia | 325,424 | 123,163 | +| BNB testnet | 325,919 | 123,637 | + +All observed attached quote budgets were 10 PC, within the explicit 20 PC rule ceiling. Keep this separate from measured destination fees and Push signer gas. Full hashes, block numbers and costs are in live-evm-gas-evidence.json. The EVM run used the same production code as the final state; a read-only RPC chain guard was added to the test source after invocation without changing sends or assertions for gas/delivery. diff --git a/plan/agw/research/preset-acceptance-2026-10-20/compatibility.json b/plan/agw/research/preset-acceptance-2026-10-20/compatibility.json new file mode 100644 index 00000000..60e639bb --- /dev/null +++ b/plan/agw/research/preset-acceptance-2026-10-20/compatibility.json @@ -0,0 +1,882 @@ +{ + "at": "2026-10-20T15:18:15.748Z", + "readOnly": true, + "chains": [ + { + "chain": "eip155:11155111", + "candidates": [ + { + "token": "0xC4230aEaFcF6b8B49a7b4e53886420f00ff71876", + "symbol": "USDT", + "prc20": "0x0f97A213207703923F5f0C613C9827f7C9A0f96B", + "identityVerified": true + }, + { + "token": "0x97F477B7f970D47a87B42869ceeace218106152a", + "symbol": "USDC", + "prc20": "0x7A58048036206bB898008b5bBDA85697DB1e5d66", + "identityVerified": true + }, + { + "token": "0xfff9976782d46cc05630d1f6ebab18b2324d6b14", + "symbol": "WETH", + "prc20": "0x0d0dF7E8807430A81104EA84d926139816eC7586", + "identityVerified": true + }, + { + "token": "0x3e3FE7dBc6B4C189E7128855dD526361c49b40Af", + "symbol": "stETH", + "prc20": "0xaf89E805949c628ebde3262e91dc4ab9eA12668E", + "identityVerified": true + } + ], + "protocols": [ + { + "app": "Uniswap V3", + "kind": "dex", + "router": "0x3bFA4769FB09eefC5a80d6E87c3B9C650f7Ae48E", + "pairs": [ + { + "tokens": [ + "0xC4230aEaFcF6b8B49a7b4e53886420f00ff71876", + "0x97F477B7f970D47a87B42869ceeace218106152a" + ], + "pools": [] + }, + { + "tokens": [ + "0xC4230aEaFcF6b8B49a7b4e53886420f00ff71876", + "0xfff9976782d46cc05630d1f6ebab18b2324d6b14" + ], + "pools": [] + }, + { + "tokens": [ + "0xC4230aEaFcF6b8B49a7b4e53886420f00ff71876", + "0x3e3FE7dBc6B4C189E7128855dD526361c49b40Af" + ], + "pools": [] + }, + { + "tokens": [ + "0x97F477B7f970D47a87B42869ceeace218106152a", + "0xfff9976782d46cc05630d1f6ebab18b2324d6b14" + ], + "pools": [] + }, + { + "tokens": [ + "0x97F477B7f970D47a87B42869ceeace218106152a", + "0x3e3FE7dBc6B4C189E7128855dD526361c49b40Af" + ], + "pools": [] + }, + { + "tokens": [ + "0xfff9976782d46cc05630d1f6ebab18b2324d6b14", + "0x3e3FE7dBc6B4C189E7128855dD526361c49b40Af" + ], + "pools": [] + } + ], + "factory": "0x0227628f3F023bb0B980b67D528571c95c6DaC1c" + }, + { + "app": "Aave V3", + "kind": "lending", + "pool": "0x6Ae43d3271ff6888e7Fc43Fd7321a503ff738951", + "reserves": [ + "0xFF34B3d4Aee8ddCd6F9AFFFB6Fe49bD371b8a357", + "0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5", + "0x94a9D9AC8a22534E3FaCa9F4e7F2E2cf85d5E4C8", + "0x29f2D40B0605204364af54EC677bD022dA425d03", + "0xC558DBdd856501FCd9aaF1E62eae57A9F0629a3c", + "0xaA8E23Fb1079EA71e0a56F48a2aA51851D8433D0", + "0x88541670E55cC00bEEFD87eB59EDd1b7C511AC9a", + "0x6d906e526a4e2Ca02097BA9d0caA3c382F52278E", + "0xc4bF5CbDaBE595361438F8c6a187bDc330539c60" + ], + "routedReserves": [] + }, + { + "app": "EigenLayer", + "kind": "strategy", + "strategy": "0x424246eF71b01ee33aA33aC590fd9a0855F5eFbc", + "underlying": "0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9", + "routed": false + } + ], + "presets": [ + { + "category": "DEXES", + "readiness": { + "ready": false, + "chains": [ + { + "chainNamespace": "eip155:11155111", + "ready": false, + "configurationReady": true, + "selectedAssets": [ + { + "token": "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14", + "maxPerCall": "1000000000000000", + "maxTotal": "10000000000000000" + }, + { + "token": "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238", + "maxPerCall": "10000000", + "maxTotal": "100000000" + } + ], + "bridgeAssets": [ + { + "token": "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14", + "prc20": "0x0d0dF7E8807430A81104EA84d926139816eC7586", + "status": "registered" + }, + { + "token": "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238", + "status": "unavailable" + } + ], + "issues": [ + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238", + "message": "No SDK PRC20 mapping for eip155:11155111:0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238 on TESTNET_DONUT. This preset cannot be created with this token until its Push route is verified. Choose a routed token only if the selected app supports that exact token address." + } + ], + "disabledCalls": [], + "excludedCalls": [], + "knownTokens": [ + "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14", + "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238" + ], + "zeroBridgeLimits": [] + } + ] + }, + "assets": [ + { + "token": "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14", + "maxPerCall": "1000000000000000", + "maxTotal": "10000000000000000" + }, + { + "token": "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238", + "maxPerCall": "10000000", + "maxTotal": "100000000" + } + ] + }, + { + "category": "LENDING", + "readiness": { + "ready": false, + "chains": [ + { + "chainNamespace": "eip155:11155111", + "ready": false, + "configurationReady": true, + "selectedAssets": [ + { + "token": "0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5", + "maxPerCall": "1000000000000000000", + "maxTotal": "10000000000000000000" + } + ], + "bridgeAssets": [ + { + "token": "0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5", + "status": "unavailable" + } + ], + "issues": [ + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5", + "message": "No SDK PRC20 mapping for eip155:11155111:0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5 on TESTNET_DONUT. This preset cannot be created with this token until its Push route is verified. Choose a routed token only if the selected app supports that exact token address." + } + ], + "disabledCalls": [], + "excludedCalls": [], + "knownTokens": [ + "0xFF34B3d4Aee8ddCd6F9AFFFB6Fe49bD371b8a357", + "0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5", + "0x94a9D9AC8a22534E3FaCa9F4e7F2E2cf85d5E4C8", + "0x29f2D40B0605204364af54EC677bD022dA425d03", + "0xC558DBdd856501FCd9aaF1E62eae57A9F0629a3c", + "0xaA8E23Fb1079EA71e0a56F48a2aA51851D8433D0", + "0x88541670E55cC00bEEFD87eB59EDd1b7C511AC9a", + "0x6d906e526a4e2Ca02097BA9d0caA3c382F52278E", + "0xc4bF5CbDaBE595361438F8c6a187bDc330539c60" + ], + "zeroBridgeLimits": [] + } + ] + }, + "assets": [ + { + "token": "0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5", + "maxPerCall": "1000000000000000000", + "maxTotal": "10000000000000000000" + } + ] + }, + { + "category": "STAKING", + "readiness": { + "ready": false, + "chains": [ + { + "chainNamespace": "eip155:11155111", + "ready": false, + "configurationReady": true, + "selectedAssets": [ + { + "token": "0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9", + "maxPerCall": "1000000000000000", + "maxTotal": "10000000000000000" + } + ], + "bridgeAssets": [ + { + "token": "0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9", + "status": "unavailable" + } + ], + "issues": [ + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9", + "message": "No SDK PRC20 mapping for eip155:11155111:0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9 on TESTNET_DONUT. This preset cannot be created with this token until its Push route is verified. Choose a routed token only if the selected app supports that exact token address." + } + ], + "disabledCalls": [], + "excludedCalls": [], + "knownTokens": [ + "0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9" + ], + "zeroBridgeLimits": [] + } + ] + }, + "assets": [ + { + "token": "0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9", + "maxPerCall": "1000000000000000", + "maxTotal": "10000000000000000" + } + ] + } + ], + "block": "11956140" + }, + { + "chain": "eip155:84532", + "candidates": [ + { + "token": "0x4D7646B9eE3D68F4b0F135B5cbc66B00819F6b61", + "symbol": "USDT", + "prc20": "0x148823809B853e1db187BC09A9ac909BC42F971a", + "identityVerified": true + }, + { + "token": "0x5c3504F0E3bA28FDc1F74234fE936518276AaBB8", + "symbol": "USDC", + "prc20": "0xD7C6cA1e2c0CE260BE0c0AD39C1540de460e3Be1", + "identityVerified": true + }, + { + "token": "0xfff9976782d46cc05630d1f6ebab18b2324d6b14", + "symbol": "WETH", + "unavailable": "Unsupported WETH origin chain for synthetic mapping" + } + ], + "protocols": [ + { + "app": "Uniswap V3", + "kind": "dex", + "router": "0x94cC0AaC535CCDB3C01d6787D6413C739ae12bc4", + "pairs": [ + { + "tokens": [ + "0x4D7646B9eE3D68F4b0F135B5cbc66B00819F6b61", + "0x5c3504F0E3bA28FDc1F74234fE936518276AaBB8" + ], + "pools": [] + } + ], + "factory": "0x4752ba5DBc23f44D87826276BF6Fd6b1C372aD24" + }, + { + "app": "Aave V3", + "kind": "lending", + "pool": "0x8bAB6d1b75f19e9eD9fCe8b9BD338844fF79aE27", + "reserves": [ + "0xba50Cd2A20f6DA35D788639E581bca8d0B5d4D5f", + "0x0a215D8ba66387DCA84B284D18c3B4ec3de6E54a", + "0x54114591963CF60EF3aA63bEfD6eC263D98145a4", + "0x4200000000000000000000000000000000000006", + "0xD171b9694f7A2597Ed006D41f7509aaD4B485c4B", + "0x810D46F9a9027E28F9B01F75E2bdde839dA61115" + ], + "routedReserves": [] + }, + { + "app": "Moonwell mUSDbC", + "kind": "market", + "market": "0x876852425331a113d8E432eFFB3aC5BEf38f033a", + "underlying": "0x4616975f7E6045FD9737e95bC527e9e14c727BD2", + "routed": false + }, + { + "app": "Moonwell mWETH", + "kind": "market", + "market": "0x2F39a349A79492a70E152760ce7123A1933eCf28", + "underlying": "0x663A6F02d547dFd639BF689FED298712f2FB69Fb", + "routed": false + } + ], + "presets": [ + { + "category": "DEXES", + "readiness": { + "ready": false, + "chains": [ + { + "chainNamespace": "eip155:84532", + "ready": false, + "configurationReady": true, + "selectedAssets": [ + { + "token": "0x4200000000000000000000000000000000000006", + "maxPerCall": "1000000000000000", + "maxTotal": "10000000000000000" + }, + { + "token": "0x036CbD53842c5426634e7929541eC2318f3dCF7e", + "maxPerCall": "10000000", + "maxTotal": "100000000" + } + ], + "bridgeAssets": [ + { + "token": "0x4200000000000000000000000000000000000006", + "status": "unavailable" + }, + { + "token": "0x036CbD53842c5426634e7929541eC2318f3dCF7e", + "status": "unavailable" + } + ], + "issues": [ + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0x4200000000000000000000000000000000000006", + "message": "No SDK PRC20 mapping for eip155:84532:0x4200000000000000000000000000000000000006 on TESTNET_DONUT. This preset cannot be created with this token until its Push route is verified. Choose a routed token only if the selected app supports that exact token address." + }, + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0x036CbD53842c5426634e7929541eC2318f3dCF7e", + "message": "No SDK PRC20 mapping for eip155:84532:0x036CbD53842c5426634e7929541eC2318f3dCF7e on TESTNET_DONUT. This preset cannot be created with this token until its Push route is verified. Choose a routed token only if the selected app supports that exact token address." + } + ], + "disabledCalls": [], + "excludedCalls": [], + "knownTokens": [ + "0x4200000000000000000000000000000000000006", + "0x036CbD53842c5426634e7929541eC2318f3dCF7e" + ], + "zeroBridgeLimits": [] + } + ] + }, + "assets": [ + { + "token": "0x4200000000000000000000000000000000000006", + "maxPerCall": "1000000000000000", + "maxTotal": "10000000000000000" + }, + { + "token": "0x036CbD53842c5426634e7929541eC2318f3dCF7e", + "maxPerCall": "10000000", + "maxTotal": "100000000" + } + ] + }, + { + "category": "LENDING", + "readiness": { + "ready": false, + "chains": [ + { + "chainNamespace": "eip155:84532", + "ready": false, + "configurationReady": true, + "selectedAssets": [ + { + "token": "0x810D46F9a9027E28F9B01F75E2bdde839dA61115", + "maxPerCall": "1000000000000000000", + "maxTotal": "10000000000000000000" + }, + { + "token": "0x4616975f7E6045FD9737e95bC527e9e14c727BD2", + "maxPerCall": "10000000", + "maxTotal": "100000000" + }, + { + "token": "0x663A6F02d547dFd639BF689FED298712f2FB69Fb", + "maxPerCall": "1000000000000000", + "maxTotal": "10000000000000000" + } + ], + "bridgeAssets": [ + { + "token": "0x810D46F9a9027E28F9B01F75E2bdde839dA61115", + "status": "unavailable" + }, + { + "token": "0x4616975f7E6045FD9737e95bC527e9e14c727BD2", + "status": "unavailable" + }, + { + "token": "0x663A6F02d547dFd639BF689FED298712f2FB69Fb", + "status": "unavailable" + } + ], + "issues": [ + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0x810D46F9a9027E28F9B01F75E2bdde839dA61115", + "message": "No SDK PRC20 mapping for eip155:84532:0x810D46F9a9027E28F9B01F75E2bdde839dA61115 on TESTNET_DONUT. This preset cannot be created with this token until its Push route is verified. Choose a routed token only if the selected app supports that exact token address." + }, + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0x4616975f7E6045FD9737e95bC527e9e14c727BD2", + "message": "No SDK PRC20 mapping for eip155:84532:0x4616975f7E6045FD9737e95bC527e9e14c727BD2 on TESTNET_DONUT. This preset cannot be created with this token until its Push route is verified. Choose a routed token only if the selected app supports that exact token address." + }, + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0x663A6F02d547dFd639BF689FED298712f2FB69Fb", + "message": "No SDK PRC20 mapping for eip155:84532:0x663A6F02d547dFd639BF689FED298712f2FB69Fb on TESTNET_DONUT. This preset cannot be created with this token until its Push route is verified. Choose a routed token only if the selected app supports that exact token address." + } + ], + "disabledCalls": [], + "excludedCalls": [ + { + "target": "0x876852425331a113d8E432eFFB3aC5BEf38f033a", + "selector": "redeem(uint256)", + "app": "Moonwell mUSDbC", + "reason": "SHARE_AMOUNT", + "alternative": "redeemUnderlying(uint256)" + }, + { + "target": "0x2F39a349A79492a70E152760ce7123A1933eCf28", + "selector": "redeem(uint256)", + "app": "Moonwell mWETH", + "reason": "SHARE_AMOUNT", + "alternative": "redeemUnderlying(uint256)" + } + ], + "knownTokens": [ + "0xba50Cd2A20f6DA35D788639E581bca8d0B5d4D5f", + "0x0a215D8ba66387DCA84B284D18c3B4ec3de6E54a", + "0x54114591963CF60EF3aA63bEfD6eC263D98145a4", + "0x4200000000000000000000000000000000000006", + "0xD171b9694f7A2597Ed006D41f7509aaD4B485c4B", + "0x810D46F9a9027E28F9B01F75E2bdde839dA61115", + "0x4616975f7E6045FD9737e95bC527e9e14c727BD2", + "0x663A6F02d547dFd639BF689FED298712f2FB69Fb" + ], + "zeroBridgeLimits": [] + } + ] + }, + "assets": [ + { + "token": "0x810D46F9a9027E28F9B01F75E2bdde839dA61115", + "maxPerCall": "1000000000000000000", + "maxTotal": "10000000000000000000" + }, + { + "token": "0x4616975f7E6045FD9737e95bC527e9e14c727BD2", + "maxPerCall": "10000000", + "maxTotal": "100000000" + }, + { + "token": "0x663A6F02d547dFd639BF689FED298712f2FB69Fb", + "maxPerCall": "1000000000000000", + "maxTotal": "10000000000000000" + } + ] + } + ], + "block": "48370608" + }, + { + "chain": "eip155:421614", + "candidates": [ + { + "token": "0xE30928528f52CAEeB75fB07837e22d77D47e9c07", + "symbol": "USDT", + "prc20": "0xFE6E9DF2BbC9ce05D98b83B1365df6DcA9951891", + "identityVerified": true + }, + { + "token": "0x5dd39b0b3610F666F631a6506b7713EF83e1Ac5C", + "symbol": "USDC", + "prc20": "0x1091cCBA2FF8d2A131AE4B35e34cf3308C48572C", + "identityVerified": true + }, + { + "token": "0x980B62Da83eFf3D4576C647993b0c1D7faf17c73", + "symbol": "WETH", + "unavailable": "Unsupported WETH origin chain for synthetic mapping" + } + ], + "protocols": [ + { + "app": "Uniswap V3", + "kind": "dex", + "router": "0x101F443B4d1b059569D643917553c771E1b9663E", + "pairs": [ + { + "tokens": [ + "0xE30928528f52CAEeB75fB07837e22d77D47e9c07", + "0x5dd39b0b3610F666F631a6506b7713EF83e1Ac5C" + ], + "pools": [] + } + ], + "factory": "0x248AB79Bbb9bC29bB72f7Cd42F17e054Fc40188e" + }, + { + "app": "Aave V3", + "kind": "lending", + "pool": "0xBfC91D59fdAA134A4ED45f7B584cAf96D7792Eff", + "reserves": [ + "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "0x1dF462e2712496373A347f8ad10802a5E95f053D" + ], + "routedReserves": [] + } + ], + "presets": [ + { + "category": "DEXES", + "readiness": { + "ready": false, + "chains": [ + { + "chainNamespace": "eip155:421614", + "ready": false, + "configurationReady": true, + "selectedAssets": [ + { + "token": "0x980B62Da83eFf3D4576C647993b0c1D7faf17c73", + "maxPerCall": "1000000000000000", + "maxTotal": "10000000000000000" + }, + { + "token": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "maxPerCall": "10000000", + "maxTotal": "100000000" + } + ], + "bridgeAssets": [ + { + "token": "0x980B62Da83eFf3D4576C647993b0c1D7faf17c73", + "status": "unavailable" + }, + { + "token": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "status": "unavailable" + } + ], + "issues": [ + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0x980B62Da83eFf3D4576C647993b0c1D7faf17c73", + "message": "No SDK PRC20 mapping for eip155:421614:0x980B62Da83eFf3D4576C647993b0c1D7faf17c73 on TESTNET_DONUT. This preset cannot be created with this token until its Push route is verified. Choose a routed token only if the selected app supports that exact token address." + }, + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "message": "No SDK PRC20 mapping for eip155:421614:0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d on TESTNET_DONUT. This preset cannot be created with this token until its Push route is verified. Choose a routed token only if the selected app supports that exact token address." + } + ], + "disabledCalls": [], + "excludedCalls": [], + "knownTokens": [ + "0x980B62Da83eFf3D4576C647993b0c1D7faf17c73", + "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d" + ], + "zeroBridgeLimits": [] + } + ] + }, + "assets": [ + { + "token": "0x980B62Da83eFf3D4576C647993b0c1D7faf17c73", + "maxPerCall": "1000000000000000", + "maxTotal": "10000000000000000" + }, + { + "token": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "maxPerCall": "10000000", + "maxTotal": "100000000" + } + ] + }, + { + "category": "LENDING", + "readiness": { + "ready": false, + "chains": [ + { + "chainNamespace": "eip155:421614", + "ready": false, + "configurationReady": true, + "selectedAssets": [ + { + "token": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "maxPerCall": "10000000", + "maxTotal": "100000000" + } + ], + "bridgeAssets": [ + { + "token": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "status": "unavailable" + } + ], + "issues": [ + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "message": "No SDK PRC20 mapping for eip155:421614:0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d on TESTNET_DONUT. This preset cannot be created with this token until its Push route is verified. Choose a routed token only if the selected app supports that exact token address." + } + ], + "disabledCalls": [], + "excludedCalls": [], + "knownTokens": [ + "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "0x1dF462e2712496373A347f8ad10802a5E95f053D" + ], + "zeroBridgeLimits": [] + } + ] + }, + "assets": [ + { + "token": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + "maxPerCall": "10000000", + "maxTotal": "100000000" + } + ] + } + ], + "block": "321097574" + }, + { + "chain": "eip155:97", + "candidates": [ + { + "token": "0xE935d9c9C24D02E61186c640cc01d713C876d40F", + "symbol": "USDT", + "prc20": "0x731aF1Da5365259d27528557EE4aFBA4baC90ef2", + "identityVerified": true + }, + { + "token": "0xA8802F96cAd0d45343d9bc660B6f7d80050A660b", + "symbol": "USDC", + "prc20": "0x120EBf25Dad7D6a09Ad2316f23f9Be95DBb90639", + "identityVerified": true + } + ], + "protocols": [ + { + "app": "PancakeSwap V3", + "kind": "dex", + "router": "0x9a489505a00cE272eAa5e07Dba6491314CaE3796", + "pairs": [ + { + "tokens": [ + "0xE935d9c9C24D02E61186c640cc01d713C876d40F", + "0xA8802F96cAd0d45343d9bc660B6f7d80050A660b" + ], + "pools": [] + } + ], + "factory": "0x0BFbCF9fa4f9C56B0F40a671Ad40E0805A091865" + }, + { + "app": "Venus vUSDT", + "kind": "market", + "market": "0xb7526572FFE56AB9D7489838Bf2E18e3323b441A", + "underlying": "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", + "routed": false + }, + { + "app": "Venus vUSDC", + "kind": "market", + "market": "0xD5C4C2e2facBEB59D0216D0595d63FcDc6F9A1a7", + "underlying": "0x16227D60f7a0e586C66B005219dfc887D13C9531", + "routed": false + } + ], + "presets": [ + { + "category": "DEXES", + "readiness": { + "ready": false, + "chains": [ + { + "chainNamespace": "eip155:97", + "ready": false, + "configurationReady": true, + "selectedAssets": [ + { + "token": "0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd", + "maxPerCall": "10000000000000000", + "maxTotal": "100000000000000000" + }, + { + "token": "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", + "maxPerCall": "10000000", + "maxTotal": "100000000" + } + ], + "bridgeAssets": [ + { + "token": "0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd", + "status": "unavailable" + }, + { + "token": "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", + "status": "unavailable" + } + ], + "issues": [ + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd", + "message": "No SDK PRC20 mapping for eip155:97:0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd on TESTNET_DONUT. This preset cannot be created with this token until its Push route is verified. Choose a routed token only if the selected app supports that exact token address." + }, + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", + "message": "No SDK PRC20 mapping for eip155:97:0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c on TESTNET_DONUT. This preset cannot be created with this token until its Push route is verified. Choose a routed token only if the selected app supports that exact token address." + } + ], + "disabledCalls": [], + "excludedCalls": [], + "knownTokens": [ + "0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd", + "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c" + ], + "zeroBridgeLimits": [] + } + ] + }, + "assets": [ + { + "token": "0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd", + "maxPerCall": "10000000000000000", + "maxTotal": "100000000000000000" + }, + { + "token": "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", + "maxPerCall": "10000000", + "maxTotal": "100000000" + } + ] + }, + { + "category": "LENDING", + "readiness": { + "ready": false, + "chains": [ + { + "chainNamespace": "eip155:97", + "ready": false, + "configurationReady": true, + "selectedAssets": [ + { + "token": "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", + "maxPerCall": "10000000", + "maxTotal": "100000000" + }, + { + "token": "0x16227D60f7a0e586C66B005219dfc887D13C9531", + "maxPerCall": "10000000", + "maxTotal": "100000000" + } + ], + "bridgeAssets": [ + { + "token": "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", + "status": "unavailable" + }, + { + "token": "0x16227D60f7a0e586C66B005219dfc887D13C9531", + "status": "unavailable" + } + ], + "issues": [ + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", + "message": "No SDK PRC20 mapping for eip155:97:0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c on TESTNET_DONUT. This preset cannot be created with this token until its Push route is verified. Choose a routed token only if the selected app supports that exact token address." + }, + { + "code": "BRIDGE_ASSET_UNAVAILABLE", + "token": "0x16227D60f7a0e586C66B005219dfc887D13C9531", + "message": "No SDK PRC20 mapping for eip155:97:0x16227D60f7a0e586C66B005219dfc887D13C9531 on TESTNET_DONUT. This preset cannot be created with this token until its Push route is verified. Choose a routed token only if the selected app supports that exact token address." + } + ], + "disabledCalls": [], + "excludedCalls": [ + { + "target": "0xb7526572FFE56AB9D7489838Bf2E18e3323b441A", + "selector": "redeem(uint256)", + "app": "Venus vUSDT", + "reason": "SHARE_AMOUNT", + "alternative": "redeemUnderlying(uint256)" + }, + { + "target": "0xD5C4C2e2facBEB59D0216D0595d63FcDc6F9A1a7", + "selector": "redeem(uint256)", + "app": "Venus vUSDC", + "reason": "SHARE_AMOUNT", + "alternative": "redeemUnderlying(uint256)" + } + ], + "knownTokens": [ + "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", + "0x16227D60f7a0e586C66B005219dfc887D13C9531" + ], + "zeroBridgeLimits": [] + } + ] + }, + "assets": [ + { + "token": "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", + "maxPerCall": "10000000", + "maxTotal": "100000000" + }, + { + "token": "0x16227D60f7a0e586C66B005219dfc887D13C9531", + "maxPerCall": "10000000", + "maxTotal": "100000000" + } + ] + } + ], + "block": "137909051" + } + ], + "pushBlock": "24455488" +} \ No newline at end of file diff --git a/plan/agw/research/preset-acceptance-2026-10-20/gas-quotes.json b/plan/agw/research/preset-acceptance-2026-10-20/gas-quotes.json new file mode 100644 index 00000000..38f40e8d --- /dev/null +++ b/plan/agw/research/preset-acceptance-2026-10-20/gas-quotes.json @@ -0,0 +1,110 @@ +{ + "at": "2026-10-20T15:29:48.372Z", + "readOnly": true, + "network": "TESTNET_DONUT", + "pushBlockBefore": "24455772", + "note": "Current quotes only; first-use and subsequent labels describe gas-limit inputs, not executed transactions.", + "cases": [ + { + "chain": "eip155:11155111", + "stage": "default-new-account", + "inputGasLimit": "2000000", + "protocolFee": "0", + "nativeValueForGas": "10000000000000000000", + "gasLimitUsed": "2000000", + "attachedPCWei": "10000000000000000000", + "fits20PCCeiling": true + }, + { + "chain": "eip155:11155111", + "stage": "route-default-zero-input", + "inputGasLimit": "0", + "protocolFee": "0", + "nativeValueForGas": "10000000000000000000", + "gasLimitUsed": "500000", + "attachedPCWei": "10000000000000000000", + "fits20PCCeiling": true + }, + { + "chain": "eip155:84532", + "stage": "default-new-account", + "inputGasLimit": "2000000", + "protocolFee": "0", + "nativeValueForGas": "10000000000000000000", + "gasLimitUsed": "2000000", + "attachedPCWei": "10000000000000000000", + "fits20PCCeiling": true + }, + { + "chain": "eip155:84532", + "stage": "route-default-zero-input", + "inputGasLimit": "0", + "protocolFee": "0", + "nativeValueForGas": "10000000000000000000", + "gasLimitUsed": "500000", + "attachedPCWei": "10000000000000000000", + "fits20PCCeiling": true + }, + { + "chain": "eip155:421614", + "stage": "default-new-account", + "inputGasLimit": "2000000", + "protocolFee": "0", + "nativeValueForGas": "10000000000000000000", + "gasLimitUsed": "2000000", + "attachedPCWei": "10000000000000000000", + "fits20PCCeiling": true + }, + { + "chain": "eip155:421614", + "stage": "route-default-zero-input", + "inputGasLimit": "0", + "protocolFee": "0", + "nativeValueForGas": "10000000000000000000", + "gasLimitUsed": "500000", + "attachedPCWei": "10000000000000000000", + "fits20PCCeiling": true + }, + { + "chain": "eip155:97", + "stage": "default-new-account", + "inputGasLimit": "2000000", + "protocolFee": "0", + "nativeValueForGas": "10000000000000000000", + "gasLimitUsed": "2000000", + "attachedPCWei": "10000000000000000000", + "fits20PCCeiling": true + }, + { + "chain": "eip155:97", + "stage": "route-default-zero-input", + "inputGasLimit": "0", + "protocolFee": "0", + "nativeValueForGas": "10000000000000000000", + "gasLimitUsed": "500000", + "attachedPCWei": "10000000000000000000", + "fits20PCCeiling": true + }, + { + "chain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "stage": "legacy-million-unit-fallback", + "inputGasLimit": "1000000", + "protocolFee": "0", + "nativeValueForGas": "100000000000000000000", + "gasLimitUsed": "1000000", + "attachedPCWei": "100000000000000000000", + "fits20PCCeiling": false + }, + { + "chain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "stage": "sdk-default-route-sizing", + "inputGasLimit": "0", + "protocolFee": "0", + "nativeValueForGas": "10000000000000000000", + "gasLimitUsed": "1052", + "attachedPCWei": "10000000000000000000", + "fits20PCCeiling": true + } + ], + "pushBlockAfter": "24455774" +} \ No newline at end of file diff --git a/plan/agw/research/preset-acceptance-2026-10-20/live-evm-gas-evidence.json b/plan/agw/research/preset-acceptance-2026-10-20/live-evm-gas-evidence.json new file mode 100644 index 00000000..d268250e --- /dev/null +++ b/plan/agw/research/preset-acceptance-2026-10-20/live-evm-gas-evidence.json @@ -0,0 +1,410 @@ +[ + { + "name": "agw-gas-quote", + "at": "2026-10-20T15:30:36.730Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "eip155:11155111:first-use", + "token": "0x2971824Db68229D087931155C2b8bB820B275809", + "requestedGasLimit": "2000000", + "chain": "eip155:11155111", + "protocolFeePCWei": "0", + "quotedGasBudgetPCWei": "10000000000000000000", + "gasLimitUsed": "2000000", + "attachedPCWei": "10000000000000000000" + }, + { + "name": "evm-gas-submitted", + "at": "2026-10-20T15:30:40.623Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "chain": "eip155:11155111", + "stage": "first-use", + "wallet": "0xD847ca2462405a70c32ff5776e70fE25EA7B26ca", + "cea": "0xDdc0C8e35863f1478c0485144d2Fae959242Ce43", + "hash": "0xb968f71a2f8deb17a194632744e0e256b7703e229e0a0d35461751e580debce6" + }, + { + "name": "agw-push-gas", + "at": "2026-10-20T15:31:50.714Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "eip155:11155111:first-use", + "hash": "0xb968f71a2f8deb17a194632744e0e256b7703e229e0a0d35461751e580debce6", + "block": "24455794", + "gasUsed": "397778", + "effectiveGasPrice": "1125000000", + "transactionGasPaidPCWei": "447500250000000" + }, + { + "name": "evm-gas-delivered", + "at": "2026-10-20T15:31:50.714Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "chain": "eip155:11155111", + "stage": "first-use", + "wallet": "0xD847ca2462405a70c32ff5776e70fE25EA7B26ca", + "hash": "0xb968f71a2f8deb17a194632744e0e256b7703e229e0a0d35461751e580debce6", + "destinationHash": "0xf3ed17fa05f700543ec10930d078c6fb793624e44e8ec8fe3f14fbb7cee5cf19", + "destinationBlock": "11956206", + "destinationGasUsed": "1265722", + "destinationGasPaidWei": "1392314451552" + }, + { + "name": "agw-gas-quote", + "at": "2026-10-20T15:31:53.587Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "eip155:11155111:subsequent", + "token": "0x2971824Db68229D087931155C2b8bB820B275809", + "requestedGasLimit": "0", + "chain": "eip155:11155111", + "protocolFeePCWei": "0", + "quotedGasBudgetPCWei": "10000000000000000000", + "gasLimitUsed": "500000", + "attachedPCWei": "10000000000000000000" + }, + { + "name": "evm-gas-submitted", + "at": "2026-10-20T15:31:56.514Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "chain": "eip155:11155111", + "stage": "subsequent", + "wallet": "0xD847ca2462405a70c32ff5776e70fE25EA7B26ca", + "cea": "0xDdc0C8e35863f1478c0485144d2Fae959242Ce43", + "hash": "0xc3b021815bcfd26269ddcdbaed813aa91fb0c03a36dbf2cbc5678f84b157c7cf" + }, + { + "name": "agw-push-gas", + "at": "2026-10-20T15:33:05.911Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "eip155:11155111:subsequent", + "hash": "0xc3b021815bcfd26269ddcdbaed813aa91fb0c03a36dbf2cbc5678f84b157c7cf", + "block": "24455824", + "gasUsed": "377183", + "effectiveGasPrice": "1125000000", + "transactionGasPaidPCWei": "424330875000000" + }, + { + "name": "evm-gas-delivered", + "at": "2026-10-20T15:33:05.912Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "chain": "eip155:11155111", + "stage": "subsequent", + "wallet": "0xD847ca2462405a70c32ff5776e70fE25EA7B26ca", + "hash": "0xc3b021815bcfd26269ddcdbaed813aa91fb0c03a36dbf2cbc5678f84b157c7cf", + "destinationHash": "0x15f49a09b3879f3cc1ea4c3accddc7431b279da59033f5eb9842a0d4994df50a", + "destinationBlock": "11956213", + "destinationGasUsed": "223683", + "destinationGasPaidWei": "246054878928" + }, + { + "name": "agw-gas-quote", + "at": "2026-10-20T15:33:43.693Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "eip155:84532:first-use", + "token": "0xc7007af2B24D4eb963fc9633B0c66e1d2D90Fc21", + "requestedGasLimit": "2000000", + "chain": "eip155:84532", + "protocolFeePCWei": "0", + "quotedGasBudgetPCWei": "10000000000000000000", + "gasLimitUsed": "2000000", + "attachedPCWei": "10000000000000000000" + }, + { + "name": "evm-gas-submitted", + "at": "2026-10-20T15:33:53.180Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "chain": "eip155:84532", + "stage": "first-use", + "wallet": "0xB07a90329A3Ef6B20aC80a458069a7D8daE93D58", + "cea": "0xB0d8079eEF1553d3e975947f087eEeB05f02ab1A", + "hash": "0xb9fd4a64a2fd9b68193ac3aef1177f054dc591cfc3917968d3cfc9ee1fc35153" + }, + { + "name": "agw-push-gas", + "at": "2026-10-20T15:35:02.818Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "eip155:84532:first-use", + "hash": "0xb9fd4a64a2fd9b68193ac3aef1177f054dc591cfc3917968d3cfc9ee1fc35153", + "block": "24455871", + "gasUsed": "396773", + "effectiveGasPrice": "1125000000", + "transactionGasPaidPCWei": "446369625000000" + }, + { + "name": "evm-gas-delivered", + "at": "2026-10-20T15:35:02.819Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "chain": "eip155:84532", + "stage": "first-use", + "wallet": "0xB07a90329A3Ef6B20aC80a458069a7D8daE93D58", + "hash": "0xb9fd4a64a2fd9b68193ac3aef1177f054dc591cfc3917968d3cfc9ee1fc35153", + "destinationHash": "0x89337900340a39fd1725657e72f146fe5b4b917a58d5db150f052b2222724d6d", + "destinationBlock": "48371096", + "destinationGasUsed": "325448", + "destinationGasPaidWei": "2147956800000" + }, + { + "name": "agw-gas-quote", + "at": "2026-10-20T15:35:06.034Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "eip155:84532:subsequent", + "token": "0xc7007af2B24D4eb963fc9633B0c66e1d2D90Fc21", + "requestedGasLimit": "0", + "chain": "eip155:84532", + "protocolFeePCWei": "0", + "quotedGasBudgetPCWei": "10000000000000000000", + "gasLimitUsed": "500000", + "attachedPCWei": "10000000000000000000" + }, + { + "name": "evm-gas-submitted", + "at": "2026-10-20T15:35:10.428Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "chain": "eip155:84532", + "stage": "subsequent", + "wallet": "0xB07a90329A3Ef6B20aC80a458069a7D8daE93D58", + "cea": "0xB0d8079eEF1553d3e975947f087eEeB05f02ab1A", + "hash": "0xc0aa504633d7e0fe66e4aa2abaf994e4b8ff09c992b8712e3a8879fe33c9026d" + }, + { + "name": "agw-push-gas", + "at": "2026-10-20T15:36:02.248Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "eip155:84532:subsequent", + "hash": "0xc0aa504633d7e0fe66e4aa2abaf994e4b8ff09c992b8712e3a8879fe33c9026d", + "block": "24455903", + "gasUsed": "376379", + "effectiveGasPrice": "1125000000", + "transactionGasPaidPCWei": "423426375000000" + }, + { + "name": "evm-gas-delivered", + "at": "2026-10-20T15:36:02.248Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "chain": "eip155:84532", + "stage": "subsequent", + "wallet": "0xB07a90329A3Ef6B20aC80a458069a7D8daE93D58", + "hash": "0xc0aa504633d7e0fe66e4aa2abaf994e4b8ff09c992b8712e3a8879fe33c9026d", + "destinationHash": "0xe81704385810c74cef8d16cb7fe3e2a98805aff9a9f63aaf5008d3d9288a4781", + "destinationBlock": "48371126", + "destinationGasUsed": "123187", + "destinationGasPaidWei": "813034200000" + }, + { + "name": "agw-gas-quote", + "at": "2026-10-20T15:36:56.233Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "eip155:421614:first-use", + "token": "0xc0a821a1AfEd1322c5e15f1F4586C0B8cE65400e", + "requestedGasLimit": "2000000", + "chain": "eip155:421614", + "protocolFeePCWei": "0", + "quotedGasBudgetPCWei": "10000000000000000000", + "gasLimitUsed": "2000000", + "attachedPCWei": "10000000000000000000" + }, + { + "name": "evm-gas-submitted", + "at": "2026-10-20T15:36:59.677Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "chain": "eip155:421614", + "stage": "first-use", + "wallet": "0x3130f7F8b10C94A54eC012A4d0e6DAc963f200eb", + "cea": "0x97B91433aF804877cd11EC522C910c54E04624b5", + "hash": "0x21ce19a3780fee8cbcc006b3197163166402da30557ef1eff8556c97d793846c" + }, + { + "name": "agw-push-gas", + "at": "2026-10-20T15:37:59.481Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "eip155:421614:first-use", + "hash": "0x21ce19a3780fee8cbcc006b3197163166402da30557ef1eff8556c97d793846c", + "block": "24455949", + "gasUsed": "404486", + "effectiveGasPrice": "1125000000", + "transactionGasPaidPCWei": "455046750000000" + }, + { + "name": "evm-gas-delivered", + "at": "2026-10-20T15:37:59.483Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "chain": "eip155:421614", + "stage": "first-use", + "wallet": "0x3130f7F8b10C94A54eC012A4d0e6DAc963f200eb", + "hash": "0x21ce19a3780fee8cbcc006b3197163166402da30557ef1eff8556c97d793846c", + "destinationHash": "0x059011ed41d6409e48b70ab47dd02a16eca292e01e68eb721d78df5813f46c98", + "destinationBlock": "321102083", + "destinationGasUsed": "325424", + "destinationGasPaidWei": "7351913923200" + }, + { + "name": "agw-gas-quote", + "at": "2026-10-20T15:38:02.774Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "eip155:421614:subsequent", + "token": "0xc0a821a1AfEd1322c5e15f1F4586C0B8cE65400e", + "requestedGasLimit": "0", + "chain": "eip155:421614", + "protocolFeePCWei": "0", + "quotedGasBudgetPCWei": "10000000000000000000", + "gasLimitUsed": "500000", + "attachedPCWei": "10000000000000000000" + }, + { + "name": "evm-gas-submitted", + "at": "2026-10-20T15:38:06.357Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "chain": "eip155:421614", + "stage": "subsequent", + "wallet": "0x3130f7F8b10C94A54eC012A4d0e6DAc963f200eb", + "cea": "0x97B91433aF804877cd11EC522C910c54E04624b5", + "hash": "0xba1c063ab2e261f0d1af0833975fd1344daa390ae80336c45a45d49759ebecad" + }, + { + "name": "agw-push-gas", + "at": "2026-10-20T15:38:54.881Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "eip155:421614:subsequent", + "hash": "0xba1c063ab2e261f0d1af0833975fd1344daa390ae80336c45a45d49759ebecad", + "block": "24455976", + "gasUsed": "390806", + "effectiveGasPrice": "1125000000", + "transactionGasPaidPCWei": "439656750000000" + }, + { + "name": "evm-gas-delivered", + "at": "2026-10-20T15:38:54.882Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "chain": "eip155:421614", + "stage": "subsequent", + "wallet": "0x3130f7F8b10C94A54eC012A4d0e6DAc963f200eb", + "hash": "0xba1c063ab2e261f0d1af0833975fd1344daa390ae80336c45a45d49759ebecad", + "destinationHash": "0x54f382ed25d895893f6cd3042ff7ee43e63bc392397c9a9572c424a3589d9df8", + "destinationBlock": "321102318", + "destinationGasUsed": "123163", + "destinationGasPaidWei": "2780035236000" + }, + { + "name": "agw-gas-quote", + "at": "2026-10-20T15:39:43.371Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "eip155:97:first-use", + "token": "0x7a9082dA308f3fa005beA7dB0d203b3b86664E36", + "requestedGasLimit": "2000000", + "chain": "eip155:97", + "protocolFeePCWei": "0", + "quotedGasBudgetPCWei": "10000000000000000000", + "gasLimitUsed": "2000000", + "attachedPCWei": "10000000000000000000" + }, + { + "name": "evm-gas-submitted", + "at": "2026-10-20T15:39:46.663Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "chain": "eip155:97", + "stage": "first-use", + "wallet": "0x0140403283bB76C1890501067754d1c376189b5D", + "cea": "0xA7384f2b00463E548426Cd9C8979dDa78ECf60c4", + "hash": "0x6e4bf8a92eb569fb4aa34a5d5eab4799ab86f6aa40fe405d59cba6498c669f7d" + }, + { + "name": "agw-push-gas", + "at": "2026-10-20T15:40:38.326Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "eip155:97:first-use", + "hash": "0x6e4bf8a92eb569fb4aa34a5d5eab4799ab86f6aa40fe405d59cba6498c669f7d", + "block": "24456018", + "gasUsed": "404574", + "effectiveGasPrice": "1125000000", + "transactionGasPaidPCWei": "455145750000000" + }, + { + "name": "evm-gas-delivered", + "at": "2026-10-20T15:40:38.326Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "chain": "eip155:97", + "stage": "first-use", + "wallet": "0x0140403283bB76C1890501067754d1c376189b5D", + "hash": "0x6e4bf8a92eb569fb4aa34a5d5eab4799ab86f6aa40fe405d59cba6498c669f7d", + "destinationHash": "0x6b5cfb84699948c2b626e2a244b9ff8354d070093d6f8ecb42a228914adfdaa5", + "destinationBlock": "137911931", + "destinationGasUsed": "325919", + "destinationGasPaidWei": "35851090000000" + }, + { + "name": "agw-gas-quote", + "at": "2026-10-20T15:40:41.547Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "eip155:97:subsequent", + "token": "0x7a9082dA308f3fa005beA7dB0d203b3b86664E36", + "requestedGasLimit": "0", + "chain": "eip155:97", + "protocolFeePCWei": "0", + "quotedGasBudgetPCWei": "10000000000000000000", + "gasLimitUsed": "500000", + "attachedPCWei": "10000000000000000000" + }, + { + "name": "evm-gas-submitted", + "at": "2026-10-20T15:40:45.906Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "chain": "eip155:97", + "stage": "subsequent", + "wallet": "0x0140403283bB76C1890501067754d1c376189b5D", + "cea": "0xA7384f2b00463E548426Cd9C8979dDa78ECf60c4", + "hash": "0x82f343dcd100715d5693d68fbdcccdaf1467c3c5626391501d1f7b579d279047" + }, + { + "name": "agw-push-gas", + "at": "2026-10-20T15:41:40.866Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "eip155:97:subsequent", + "hash": "0x82f343dcd100715d5693d68fbdcccdaf1467c3c5626391501d1f7b579d279047", + "block": "24456042", + "gasUsed": "390894", + "effectiveGasPrice": "1125000000", + "transactionGasPaidPCWei": "439755750000000" + }, + { + "name": "evm-gas-delivered", + "at": "2026-10-20T15:41:40.866Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "chain": "eip155:97", + "stage": "subsequent", + "wallet": "0x0140403283bB76C1890501067754d1c376189b5D", + "hash": "0x82f343dcd100715d5693d68fbdcccdaf1467c3c5626391501d1f7b579d279047", + "destinationHash": "0x42adb9167d8f25a81ff01e143cb43e676818d8ce144a08444c890caecd08029a", + "destinationBlock": "137912063", + "destinationGasUsed": "123637", + "destinationGasPaidWei": "13600070000000" + } +] diff --git a/plan/agw/research/preset-acceptance-2026-10-20/live-evm-gas.log b/plan/agw/research/preset-acceptance-2026-10-20/live-evm-gas.log new file mode 100644 index 00000000..06419691 --- /dev/null +++ b/plan/agw/research/preset-acceptance-2026-10-20/live-evm-gas.log @@ -0,0 +1,12 @@ +PASS core-e2e packages/core/__e2e__/agw/gas-live.spec.ts (715.558 s) + agw live gas sizing + ✓ 1. Sepolia first-use and subsequent execution (200128 ms) + ✓ 2. Base Sepolia first-use and subsequent execution (175985 ms) + ✓ 3. Arbitrum Sepolia first-use and subsequent execution (172600 ms) + ✓ 4. BNB testnet first-use and subsequent execution (165645 ms) + +Test Suites: 1 passed, 1 total +Tests: 4 passed, 4 total +Snapshots: 0 total +Time: 715.584 s +Ran all test suites within paths "packages/core/__e2e__/agw/gas-live.spec.ts". diff --git a/plan/agw/research/preset-acceptance-2026-10-20/live-presets-blocked.log b/plan/agw/research/preset-acceptance-2026-10-20/live-presets-blocked.log new file mode 100644 index 00000000..30d13f4e --- /dev/null +++ b/plan/agw/research/preset-acceptance-2026-10-20/live-presets-blocked.log @@ -0,0 +1,152 @@ +FAIL core-e2e packages/core/__e2e__/agw/presets-acceptance.spec.ts + agw unchanged preset acceptance + ✕ 1. DEXES Sepolia (2 ms) + ✕ 2. DEXES Base Sepolia + ✕ 3. DEXES Arbitrum Sepolia (1 ms) + ✕ 4. DEXES BNB testnet + ✕ 5. LENDING Sepolia (1 ms) + ✕ 6. LENDING Base Sepolia (1 ms) + ✕ 7. LENDING Arbitrum Sepolia (1 ms) + ✕ 8. LENDING BNB testnet + ✕ 9. STAKING Sepolia + + ● agw unchanged preset acceptance › 1. DEXES Sepolia + + PRESET_BLOCKED_BEFORE_FUNDING DEXES eip155:11155111: [{"code":"BRIDGE_ASSET_UNAVAILABLE","token":"0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238","message":"No SDK PRC20 mapping for eip155:11155111:0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238 on TESTNET_DONUT. This preset cannot be created with this token until its Push route is verified. Choose a routed token only if the selected app supports that exact token address."}] + + 198 | }); + 199 | if (!preview.readiness.ready) + > 200 | throw new Error( + | ^ + 201 | `PRESET_BLOCKED_BEFORE_FUNDING ${category} ${chainNamespace}: ${JSON.stringify( + 202 | preview.readiness.chains[0].issues + 203 | )}` + + at run (__e2e__/agw/presets-acceptance.spec.ts:200:13) + at Object. (__e2e__/agw/presets-acceptance.spec.ts:331:32) + + ● agw unchanged preset acceptance › 2. DEXES Base Sepolia + + PRESET_BLOCKED_BEFORE_FUNDING DEXES eip155:84532: [{"code":"BRIDGE_ASSET_UNAVAILABLE","token":"0x4200000000000000000000000000000000000006","message":"No SDK PRC20 mapping for eip155:84532:0x4200000000000000000000000000000000000006 on TESTNET_DONUT. This preset cannot be created with this token until its Push route is verified. Choose a routed token only if the selected app supports that exact token address."},{"code":"BRIDGE_ASSET_UNAVAILABLE","token":"0x036CbD53842c5426634e7929541eC2318f3dCF7e","message":"No SDK PRC20 mapping for eip155:84532:0x036CbD53842c5426634e7929541eC2318f3dCF7e on TESTNET_DONUT. This preset cannot be created with this token until its Push route is verified. Choose a routed token only if the selected app supports that exact token address."}] + + 198 | }); + 199 | if (!preview.readiness.ready) + > 200 | throw new Error( + | ^ + 201 | `PRESET_BLOCKED_BEFORE_FUNDING ${category} ${chainNamespace}: ${JSON.stringify( + 202 | preview.readiness.chains[0].issues + 203 | )}` + + at run (__e2e__/agw/presets-acceptance.spec.ts:200:13) + at Object. (__e2e__/agw/presets-acceptance.spec.ts:332:37) + + ● agw unchanged preset acceptance › 3. DEXES Arbitrum Sepolia + + PRESET_BLOCKED_BEFORE_FUNDING DEXES eip155:421614: [{"code":"BRIDGE_ASSET_UNAVAILABLE","token":"0x980B62Da83eFf3D4576C647993b0c1D7faf17c73","message":"No SDK PRC20 mapping for eip155:421614:0x980B62Da83eFf3D4576C647993b0c1D7faf17c73 on TESTNET_DONUT. This preset cannot be created with this token until its Push route is verified. Choose a routed token only if the selected app supports that exact token address."},{"code":"BRIDGE_ASSET_UNAVAILABLE","token":"0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d","message":"No SDK PRC20 mapping for eip155:421614:0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d on TESTNET_DONUT. This preset cannot be created with this token until its Push route is verified. Choose a routed token only if the selected app supports that exact token address."}] + + 198 | }); + 199 | if (!preview.readiness.ready) + > 200 | throw new Error( + | ^ + 201 | `PRESET_BLOCKED_BEFORE_FUNDING ${category} ${chainNamespace}: ${JSON.stringify( + 202 | preview.readiness.chains[0].issues + 203 | )}` + + at run (__e2e__/agw/presets-acceptance.spec.ts:200:13) + at Object. (__e2e__/agw/presets-acceptance.spec.ts:335:11) + + ● agw unchanged preset acceptance › 4. DEXES BNB testnet + + PRESET_BLOCKED_BEFORE_FUNDING DEXES eip155:97: [{"code":"BRIDGE_ASSET_UNAVAILABLE","token":"0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd","message":"No SDK PRC20 mapping for eip155:97:0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd on TESTNET_DONUT. This preset cannot be created with this token until its Push route is verified. Choose a routed token only if the selected app supports that exact token address."},{"code":"BRIDGE_ASSET_UNAVAILABLE","token":"0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c","message":"No SDK PRC20 mapping for eip155:97:0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c on TESTNET_DONUT. This preset cannot be created with this token until its Push route is verified. Choose a routed token only if the selected app supports that exact token address."}] + + 198 | }); + 199 | if (!preview.readiness.ready) + > 200 | throw new Error( + | ^ + 201 | `PRESET_BLOCKED_BEFORE_FUNDING ${category} ${chainNamespace}: ${JSON.stringify( + 202 | preview.readiness.chains[0].issues + 203 | )}` + + at run (__e2e__/agw/presets-acceptance.spec.ts:200:13) + at Object. (__e2e__/agw/presets-acceptance.spec.ts:338:36) + + ● agw unchanged preset acceptance › 5. LENDING Sepolia + + PRESET_BLOCKED_BEFORE_FUNDING LENDING eip155:11155111: [{"code":"BRIDGE_ASSET_UNAVAILABLE","token":"0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5","message":"No SDK PRC20 mapping for eip155:11155111:0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5 on TESTNET_DONUT. This preset cannot be created with this token until its Push route is verified. Choose a routed token only if the selected app supports that exact token address."}] + + 198 | }); + 199 | if (!preview.readiness.ready) + > 200 | throw new Error( + | ^ + 201 | `PRESET_BLOCKED_BEFORE_FUNDING ${category} ${chainNamespace}: ${JSON.stringify( + 202 | preview.readiness.chains[0].issues + 203 | )}` + + at run (__e2e__/agw/presets-acceptance.spec.ts:200:13) + at Object. (__e2e__/agw/presets-acceptance.spec.ts:339:34) + + ● agw unchanged preset acceptance › 6. LENDING Base Sepolia + + PRESET_BLOCKED_BEFORE_FUNDING LENDING eip155:84532: [{"code":"BRIDGE_ASSET_UNAVAILABLE","token":"0x810D46F9a9027E28F9B01F75E2bdde839dA61115","message":"No SDK PRC20 mapping for eip155:84532:0x810D46F9a9027E28F9B01F75E2bdde839dA61115 on TESTNET_DONUT. This preset cannot be created with this token until its Push route is verified. Choose a routed token only if the selected app supports that exact token address."},{"code":"BRIDGE_ASSET_UNAVAILABLE","token":"0x4616975f7E6045FD9737e95bC527e9e14c727BD2","message":"No SDK PRC20 mapping for eip155:84532:0x4616975f7E6045FD9737e95bC527e9e14c727BD2 on TESTNET_DONUT. This preset cannot be created with this token until its Push route is verified. Choose a routed token only if the selected app supports that exact token address."},{"code":"BRIDGE_ASSET_UNAVAILABLE","token":"0x663A6F02d547dFd639BF689FED298712f2FB69Fb","message":"No SDK PRC20 mapping for eip155:84532:0x663A6F02d547dFd639BF689FED298712f2FB69Fb on TESTNET_DONUT. This preset cannot be created with this token until its Push route is verified. Choose a routed token only if the selected app supports that exact token address."}] + + 198 | }); + 199 | if (!preview.readiness.ready) + > 200 | throw new Error( + | ^ + 201 | `PRESET_BLOCKED_BEFORE_FUNDING ${category} ${chainNamespace}: ${JSON.stringify( + 202 | preview.readiness.chains[0].issues + 203 | )}` + + at run (__e2e__/agw/presets-acceptance.spec.ts:200:13) + at Object. (__e2e__/agw/presets-acceptance.spec.ts:342:11) + + ● agw unchanged preset acceptance › 7. LENDING Arbitrum Sepolia + + PRESET_BLOCKED_BEFORE_FUNDING LENDING eip155:421614: [{"code":"BRIDGE_ASSET_UNAVAILABLE","token":"0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d","message":"No SDK PRC20 mapping for eip155:421614:0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d on TESTNET_DONUT. This preset cannot be created with this token until its Push route is verified. Choose a routed token only if the selected app supports that exact token address."}] + + 198 | }); + 199 | if (!preview.readiness.ready) + > 200 | throw new Error( + | ^ + 201 | `PRESET_BLOCKED_BEFORE_FUNDING ${category} ${chainNamespace}: ${JSON.stringify( + 202 | preview.readiness.chains[0].issues + 203 | )}` + + at run (__e2e__/agw/presets-acceptance.spec.ts:200:13) + at Object. (__e2e__/agw/presets-acceptance.spec.ts:347:11) + + ● agw unchanged preset acceptance › 8. LENDING BNB testnet + + PRESET_BLOCKED_BEFORE_FUNDING LENDING eip155:97: [{"code":"BRIDGE_ASSET_UNAVAILABLE","token":"0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c","message":"No SDK PRC20 mapping for eip155:97:0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c on TESTNET_DONUT. This preset cannot be created with this token until its Push route is verified. Choose a routed token only if the selected app supports that exact token address."},{"code":"BRIDGE_ASSET_UNAVAILABLE","token":"0x16227D60f7a0e586C66B005219dfc887D13C9531","message":"No SDK PRC20 mapping for eip155:97:0x16227D60f7a0e586C66B005219dfc887D13C9531 on TESTNET_DONUT. This preset cannot be created with this token until its Push route is verified. Choose a routed token only if the selected app supports that exact token address."}] + + 198 | }); + 199 | if (!preview.readiness.ready) + > 200 | throw new Error( + | ^ + 201 | `PRESET_BLOCKED_BEFORE_FUNDING ${category} ${chainNamespace}: ${JSON.stringify( + 202 | preview.readiness.chains[0].issues + 203 | )}` + + at run (__e2e__/agw/presets-acceptance.spec.ts:200:13) + at Object. (__e2e__/agw/presets-acceptance.spec.ts:352:11) + + ● agw unchanged preset acceptance › 9. STAKING Sepolia + + PRESET_BLOCKED_BEFORE_FUNDING STAKING eip155:11155111: [{"code":"BRIDGE_ASSET_UNAVAILABLE","token":"0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9","message":"No SDK PRC20 mapping for eip155:11155111:0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9 on TESTNET_DONUT. This preset cannot be created with this token until its Push route is verified. Choose a routed token only if the selected app supports that exact token address."}] + + 198 | }); + 199 | if (!preview.readiness.ready) + > 200 | throw new Error( + | ^ + 201 | `PRESET_BLOCKED_BEFORE_FUNDING ${category} ${chainNamespace}: ${JSON.stringify( + 202 | preview.readiness.chains[0].issues + 203 | )}` + + at run (__e2e__/agw/presets-acceptance.spec.ts:200:13) + at Object. (__e2e__/agw/presets-acceptance.spec.ts:355:34) + +Test Suites: 1 failed, 1 total +Tests: 9 failed, 9 total +Snapshots: 0 total +Time: 3.914 s +Ran all test suites within paths "packages/core/__e2e__/agw/presets-acceptance.spec.ts". diff --git a/plan/agw/research/preset-acceptance-2026-10-20/live-spl-evidence.json b/plan/agw/research/preset-acceptance-2026-10-20/live-spl-evidence.json new file mode 100644 index 00000000..41de3368 --- /dev/null +++ b/plan/agw/research/preset-acceptance-2026-10-20/live-spl-evidence.json @@ -0,0 +1,100 @@ +[ + { + "name": "agw-gas-quote", + "at": "2026-10-20T15:25:17.649Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "agent-spl:first-use", + "token": "0x4f1A3D22d170a2F4Bddb37845a962322e24f4e34", + "requestedGasLimit": "0", + "chain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "protocolFeePCWei": "0", + "quotedGasBudgetPCWei": "10000000000000000000", + "gasLimitUsed": "2285", + "attachedPCWei": "10000000000000000000" + }, + { + "name": "agent-spl-submitted", + "at": "2026-10-20T15:25:25.219Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "first-use", + "wallet": "0xED6bFE825b8d84A1E6f4F7c9067398F8985CC372", + "cea": "DKbAi4YmS5EfdvKHzS2zHKSSPfgiffu3ZddXoY4N2VuX", + "ceaATA": "GuKBtW2xo53yMyj915CMCziHyyz1LaGxnfZBUDRJPd9K", + "hash": "0x119c89e9ff7c7cccdfc8c071fade2488aa28b0eff7d9b71f7f0cf247c958bbf5" + }, + { + "name": "agw-push-gas", + "at": "2026-10-20T15:26:23.815Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "agent-spl:first-use", + "hash": "0x119c89e9ff7c7cccdfc8c071fade2488aa28b0eff7d9b71f7f0cf247c958bbf5", + "block": "24455663", + "gasUsed": "468004", + "effectiveGasPrice": "1125000000", + "transactionGasPaidPCWei": "526504500000000" + }, + { + "name": "agent-spl-delivered", + "at": "2026-10-20T15:26:23.816Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "first-use", + "wallet": "0xED6bFE825b8d84A1E6f4F7c9067398F8985CC372", + "hash": "0x119c89e9ff7c7cccdfc8c071fade2488aa28b0eff7d9b71f7f0cf247c958bbf5", + "destinationHash": "y8hK7xQWVs4mRupJAJDRBkbt1EnVmtQNxAhPhTbvJbfULrwARFimjvygaDskPawH44dntUaq5Tq6ubDDp7592q1", + "destinationFeeLamports": 5000, + "computeUnitsConsumed": 116402 + }, + { + "name": "agw-gas-quote", + "at": "2026-10-20T15:26:33.128Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "agent-spl:subsequent", + "token": "0x4f1A3D22d170a2F4Bddb37845a962322e24f4e34", + "requestedGasLimit": "0", + "chain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "protocolFeePCWei": "0", + "quotedGasBudgetPCWei": "10000000000000000000", + "gasLimitUsed": "960", + "attachedPCWei": "10000000000000000000" + }, + { + "name": "agent-spl-submitted", + "at": "2026-10-20T15:26:43.259Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "subsequent", + "wallet": "0xED6bFE825b8d84A1E6f4F7c9067398F8985CC372", + "cea": "DKbAi4YmS5EfdvKHzS2zHKSSPfgiffu3ZddXoY4N2VuX", + "ceaATA": "GuKBtW2xo53yMyj915CMCziHyyz1LaGxnfZBUDRJPd9K", + "hash": "0x7980032bb748889f44d9a58e4030dc1338575d03fa78da23531dcf96d6c23e57" + }, + { + "name": "agw-push-gas", + "at": "2026-10-20T15:27:42.193Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "agent-spl:subsequent", + "hash": "0x7980032bb748889f44d9a58e4030dc1338575d03fa78da23531dcf96d6c23e57", + "block": "24455695", + "gasUsed": "447044", + "effectiveGasPrice": "1125000000", + "transactionGasPaidPCWei": "502924500000000" + }, + { + "name": "agent-spl-delivered", + "at": "2026-10-20T15:27:42.195Z", + "network": "TESTNET_DONUT", + "sourceCommit": "ffd567d3e49b2d27c6f50ad36093274dbac3090f", + "stage": "subsequent", + "wallet": "0xED6bFE825b8d84A1E6f4F7c9067398F8985CC372", + "hash": "0x7980032bb748889f44d9a58e4030dc1338575d03fa78da23531dcf96d6c23e57", + "destinationHash": "3G782PfUtqv3THZGt7vH5J9xoscMMFvKwUo215J2Hoh4APYHEHMGDcKBjix6je5y3M2DhoeuENkmqWEFrJgUjmLe", + "destinationFeeLamports": 5000, + "computeUnitsConsumed": 98301 + } +] diff --git a/plan/agw/research/preset-acceptance-2026-10-20/live-spl.log b/plan/agw/research/preset-acceptance-2026-10-20/live-spl.log new file mode 100644 index 00000000..84f399d8 --- /dev/null +++ b/plan/agw/research/preset-acceptance-2026-10-20/live-spl.log @@ -0,0 +1,9 @@ +PASS core-e2e packages/core/__e2e__/agw/svm-agent-spl.spec.ts (226.407 s) + agw public agent spl + ✓ 1. exact wallet ATA and amount constraints survive create and two omitted-gas deliveries (224822 ms) + +Test Suites: 1 passed, 1 total +Tests: 1 passed, 1 total +Snapshots: 0 total +Time: 226.441 s +Ran all test suites within paths "packages/core/__e2e__/agw/svm-agent-spl.spec.ts". diff --git a/plan/agw/research/preset-acceptance-2026-10-20/local-contracts.log b/plan/agw/research/preset-acceptance-2026-10-20/local-contracts.log new file mode 100644 index 00000000..4e2f92bc --- /dev/null +++ b/plan/agw/research/preset-acceptance-2026-10-20/local-contracts.log @@ -0,0 +1,17 @@ +PASS core-agw-local packages/core/__agw-local__/preset-acceptance.spec.ts (5.382 s) + unchanged default preset contract acceptance + ✓ DEXES eip155:11155111 preserves every generated asset, cap, function and pin (50 ms) + ✓ DEXES eip155:84532 preserves every generated asset, cap, function and pin (39 ms) + ✓ DEXES eip155:421614 preserves every generated asset, cap, function and pin (38 ms) + ✓ DEXES eip155:97 preserves every generated asset, cap, function and pin (35 ms) + ✓ LENDING eip155:11155111 preserves every generated asset, cap, function and pin (28 ms) + ✓ LENDING eip155:84532 preserves every generated asset, cap, function and pin (48 ms) + ✓ LENDING eip155:421614 preserves every generated asset, cap, function and pin (19 ms) + ✓ LENDING eip155:97 preserves every generated asset, cap, function and pin (28 ms) + ✓ STAKING eip155:11155111 preserves every generated asset, cap, function and pin (25 ms) + +Test Suites: 1 passed, 1 total +Tests: 9 passed, 9 total +Snapshots: 0 total +Time: 5.415 s +Ran all test suites within paths "packages/core/__agw-local__/preset-acceptance.spec.ts". diff --git a/plan/agw/research/preset-acceptance-2026-10-20/probe-spl-rejections.cjs b/plan/agw/research/preset-acceptance-2026-10-20/probe-spl-rejections.cjs new file mode 100644 index 00000000..0a647818 --- /dev/null +++ b/plan/agw/research/preset-acceptance-2026-10-20/probe-spl-rejections.cjs @@ -0,0 +1,32 @@ +// Read-only exact contract error checks using the recorded successful SPL call. +// Run from SDK root after building. No signer or environment keys are loaded. +const root=process.cwd(),fs=require('node:fs'); +const { createPublicClient,http,decodeFunctionData,encodeFunctionData }=require(root+'/node_modules/viem'); +const built=root+'/dist/packages/core/src'; +const {v6}=require(built+'/lib/agentic/contracts/v6'); +const {UNIVERSAL_GATEWAY_PC}=require(built+'/lib/constants/abi'); +const {parseAgwSvmPayload,encodeAgwSvmPayload}=require(built+'/lib/agentic/execution/svm-payload'); +const {decodeAgenticRevert}=require(built+'/lib/agentic/revert'); +const reportPath=root+'/plan/agw/research/preset-acceptance-2026-10-20/'; +(async()=>{ + const rpc=createPublicClient({transport:http('https://evm.donut.rpc.push.org/',{timeout:15000,retryCount:1})}); + const evidence=JSON.parse(fs.readFileSync(reportPath+'live-spl-evidence.json')); + const hash=evidence.find(x=>x.name==='agent-spl-submitted').hash; + const tx=await rpc.getTransaction({hash}),w=v6.decodeWalletCall(tx.input); + if(w?.kind!=='executeAsAgent'||w.calls.length!==1)throw new Error('Unexpected recorded wallet call'); + const call=w.calls[0],{args}=decodeFunctionData({abi:UNIVERSAL_GATEWAY_PC,data:call.data}),req=args[0]; + const original=parseAgwSvmPayload(req.payload),block=await rpc.getBlockNumber(); + const results=[]; + for(const mode of ['amount','account']){ + const payload={...original,accounts:original.accounts.map(a=>({...a})),instructionData:Uint8Array.from(original.instructionData)}; + if(mode==='amount')new DataView(payload.instructionData.buffer).setBigUint64(8,1001n,true); + else payload.accounts[1].pubkey=payload.accounts[2].pubkey; + const next={...req,amount:0n,payload:encodeAgwSvmPayload(payload.program,payload.accounts,payload.instructionData)}; + const data=v6.encodeExecuteAsAgent(w.rulesId,{...call,data:encodeFunctionData({abi:UNIVERSAL_GATEWAY_PC,functionName:'sendUniversalTxOutbound',args:[next]})}); + try{await rpc.call({account:tx.from,to:tx.to,data,blockNumber:block});throw new Error('Expected refusal');} + catch(e){const decoded=decodeAgenticRevert(e);if(!decoded)throw e;results.push({mode,decoded});} + } + const report={at:new Date().toISOString(),readOnly:true,chainId:await rpc.getChainId(),block:String(block),originalHash:hash,note:'Zero burn on the already-spent rule isolates instruction/data checks; no transactions sent.',results}; + fs.writeFileSync(reportPath+'spl-rejections.json',JSON.stringify(report,(_k,v)=>typeof v==='bigint'?String(v):v,2)); + console.log(JSON.stringify(report,null,2)); +})().catch(e=>{console.error(e.shortMessage||e.message);process.exitCode=1}); diff --git a/plan/agw/research/preset-acceptance-2026-10-20/spl-rejections.json b/plan/agw/research/preset-acceptance-2026-10-20/spl-rejections.json new file mode 100644 index 00000000..7858ad47 --- /dev/null +++ b/plan/agw/research/preset-acceptance-2026-10-20/spl-rejections.json @@ -0,0 +1,28 @@ +{ + "at": "2026-10-20T15:40:20.540Z", + "readOnly": true, + "chainId": 42101, + "block": "24456030", + "originalHash": "0x119c89e9ff7c7cccdfc8c071fade2488aa28b0eff7d9b71f7f0cf247c958bbf5", + "note": "Zero burn on the already-spent rule isolates instruction/data checks; no transactions sent.", + "results": [ + { + "mode": "amount", + "decoded": { + "name": "PolicyCheckReverted(SvmDataCeilingExceeded)", + "selector": "0xf4270752", + "decoded": "0x94de1ef800000000000000000000000000000000000000000000000000000000", + "hint": "URP rejected the action (truncated through the session engine). The inner selector names the gate; arguments are truncated to 28 bytes." + } + }, + { + "mode": "account", + "decoded": { + "name": "PolicyCheckReverted(SvmAccountPinMismatch)", + "selector": "0xf4270752", + "decoded": "0xff3dafe500000000000000000000000000000000000000000000000000000000", + "hint": "URP rejected the action (truncated through the session engine). The inner selector names the gate; arguments are truncated to 28 bytes." + } + } + ] +} \ No newline at end of file From 200cfc7398c29075eb3bb1fd0086abaddc5c7983 Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Wed, 21 Oct 2026 10:26:02 +0530 Subject: [PATCH 66/68] docs(agw): finalize team questions for Harsh, Aman and Zaryab Rewrite the product and preset questions after cold-read review so each owner has the context to decide: defined terms, worst-case transfer risk, limit label text, route ownership, and what native wrap unblocks. Hold the Zaryab feasibility list until Harsh picks a contract option, and put the core/gateway questions on hold with a send-when trigger for each. --- plan/agw/questions-aman.md | 97 +++++++++++++------------ plan/agw/questions-core-gateway.md | 49 ++++++++----- plan/agw/questions-harsh.md | 110 ++++++++++++++--------------- plan/agw/questions-zaryab.md | 45 ++++++------ 4 files changed, 160 insertions(+), 141 deletions(-) diff --git a/plan/agw/questions-aman.md b/plan/agw/questions-aman.md index 92749c08..5faa3534 100644 --- a/plan/agw/questions-aman.md +++ b/plan/agw/questions-aman.md @@ -1,74 +1,83 @@ # Preset questions for Aman: agentic wallet presets -Updated October 21, 2026. Draft; nothing sent. What we verified ourselves is in [pre-question findings](research/pre-question-findings-2026-10-21/README.md). +Updated October 21, 2026. Final; ready to send. Internal (not part of the message): our evidence is in [pre-question findings](research/pre-question-findings-2026-10-21/README.md). ## Context -Presets are ready-made agent rules for popular apps: +Presets are ready-made agent rules for Uniswap/PancakeSwap, Aave/Moonwell/Venus and EigenLayer. Each preset lists the exact tokens that app uses on each test chain. -- **DEX:** Uniswap or PancakeSwap. -- **Lending:** Aave, Moonwell, Venus. -- **Staking:** EigenLayer. +A preset can only be created if Push can send every one of those exact tokens to that chain. That needs a Push token (PRC20): a token on Push that represents that exact token and can be sent out as it. We call that a route. The SDK never swaps in a different token with the same name, because the app wouldn't accept it. -Each preset lists the exact tokens that app uses on each test chain, with default limits. +**Why it matters now:** Riyanshu's create screen keeps a preset's Create button disabled until all its routes exist, so 7 of the 9 presets can't be used on testnet. -A preset can be created only if every one of its tokens can be sent from Push to that chain. That requires a Push token (PRC20) route for that exact token. The SDK never swaps in a different token with the same name, because the app would not accept it. - -Status with the latest SDK update (not yet released). Both ready presets passed a live test on October 21: +Status in `@pushchain/core` 6.0.27-alpha.6, with the token registry checked on October 21. "Ready" means a real agent created that preset and ran its actions on testnet on October 21. | Preset | Sepolia | Base Sepolia | Arbitrum Sepolia | BNB testnet | |---|---|---|---|---| -| DEX | **ready, live-tested** | blocked: WETH | blocked: WETH | blocked: WBNB, USDT | -| Lending | blocked: LINK | blocked: LINK, Moonwell USDbC and WETH | **ready, live-tested** | blocked: Venus USDT, USDC | +| DEX | **ready** | blocked: WETH | blocked: WETH | blocked: WBNB, USDT | +| Lending | blocked: LINK | blocked: LINK, Moonwell USDbC, Moonwell WETH | **ready** | blocked: USDT, USDC (Venus) | | Staking | blocked: WETH (EigenLayer) | — | — | — | +Questions 1 and 2 may belong to whoever runs the Push token registry (core team). If so, tell us who and we'll ask them directly. Question 3 is a preset design choice. + --- -## 1. Will the three Circle USDC routes be kept? +## 1. Can we treat the three Circle USDC ".old" routes as permanent? + +These routes carry Circle's USDC, which the presets use: + +| Chain | Circle USDC | Push token | Used by | +|---|---|---|---| +| Sepolia | `0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238` | `0x387b9C8Db60E74999aAAC5A2b7825b400F12d68E` (USDC.eth.old) | DEX Sepolia (ready) | +| Arbitrum Sepolia | `0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d` | `0xa261A10e94aE4bA88EE8c5845CbE7266bD679DD6` (USDC.arb.old) | Lending Arbitrum (ready) | +| Base Sepolia | `0x036CbD53842c5426634e7929541eC2318f3dCF7e` | `0x84B62e44F667F692F7739Ca6040cD17DA02068A8` (USDC.base.old) | DEX Base (its other token, WETH, is what blocks it) | + +- They were renamed ".old" on April 16, when the plain "USDC" names were pointed at newer mock test tokens. Uniswap and Aave don't accept those mock tokens. +- Nothing marks the ".old" routes as deprecated, and sends through all three were delivered on October 21. +- One risk: the node's `develop` branch no longer has their config files, so a future config sync from `develop` could remove them. +- If they were removed, the two ready presets would be blocked again, and anyone holding those Push tokens couldn't send them out. -The two ready presets depend on these node routes: +**Question:** are these routes staying? If they will be retired, what replaces them? -| Chain | Token on that chain | Push token | -|---|---|---| -| Sepolia | `0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238` | `0x387b9C8Db60E74999aAAC5A2b7825b400F12d68E` ("USDC.eth.old") | -| Base Sepolia | `0x036CbD53842c5426634e7929541eC2318f3dCF7e` | `0x84B62e44F667F692F7739Ca6040cD17DA02068A8` ("USDC.base.old") | -| Arbitrum Sepolia | `0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d` | `0xa261A10e94aE4bA88EE8c5845CbE7266bD679DD6` ("USDC.arb.old") | +## 2. Can routes be added for the missing preset tokens? -What we have verified: +- **Sepolia:** Aave LINK `0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5`; WETH (EigenLayer) `0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9` +- **Base Sepolia:** WETH `0x4200000000000000000000000000000000000006`; Aave LINK `0x810D46F9a9027E28F9B01F75E2bdde839dA61115`; Moonwell USDbC `0x4616975f7E6045FD9737e95bC527e9e14c727BD2`; Moonwell WETH `0x663A6F02d547dFd639BF689FED298712f2FB69Fb` +- **Arbitrum Sepolia:** WETH `0x980B62Da83eFf3D4576C647993b0c1D7faf17c73` +- **BNB testnet:** WBNB `0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd`; USDT `0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c` (used by both the DEX and Venus Lending presets); USDC (Venus) `0x16227D60f7a0e586C66B005219dfc887D13C9531` -- On October 21, sends through all three routes were delivered on Sepolia, Base and Arbitrum. The two presets also passed over them. -- The routes were renamed ".old" on April 16 (node commit `c84f9a97`), when the plain "USDC" names were pointed at newer mock tokens. Nothing marks them deprecated. -- The node's `develop` branch no longer contains their config files. That only matters if configs are ever re-synced from `develop`. -- Removing one of these configs would stop every holder of that Push token from withdrawing it. +The token registry admin on the core team adds routes. For whoever does it, each route needs: -**Question:** can we treat these three routes as permanent for the presets? If they will be retired, what is the replacement? +- a token config (`MsgAddTokenConfig`, signed by admin `push1negskcfqu09j5zvpk7nhvacnwyy2mafffy7r6a`); +- a Push token for that exact token; +- gas settings for it on Push; +- a liquidity pool against Push's own coin, used to pay gas; +- support in that chain's gateway and vault. -## 2. Can the missing preset-token routes be added? +**Question:** which of these can be added, by whom, and roughly when? Which won't be supported? For those, we'd pick a different token that we've checked the app accepts. -These preset tokens have no route today: +## 3. Can presets send native ETH/BNB and wrap it on arrival? -- Sepolia: Aave LINK `0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5`; WETH used by EigenLayer `0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9` -- Base Sepolia: WETH `0x4200000000000000000000000000000000000006`; Aave LINK `0x810D46F9a9027E28F9B01F75E2bdde839dA61115`; Moonwell USDbC `0x4616975f7E6045FD9737e95bC527e9e14c727BD2`; Moonwell WETH `0x663A6F02d547dFd639BF689FED298712f2FB69Fb` -- Arbitrum Sepolia: WETH `0x980B62Da83eFf3D4576C647993b0c1D7faf17c73` -- BNB testnet: WBNB `0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd`; Venus USDT `0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c`; Venus USDC `0x16227D60f7a0e586C66B005219dfc887D13C9531` +Sending native ETH/BNB from Push already works on all four test chains. Instead of waiting for WETH/WBNB routes, a preset could send ETH/BNB and wrap it into WETH/WBNB in the wallet's account on that chain, as the first step of the same transaction. The app still receives the WETH/WBNB it expects. -From the node code, adding a route takes all of the following: +**How it works:** -1. A token config added by the registry admin (`MsgAddTokenConfig`; admin `push1negskcfqu09j5zvpk7nhvacnwyy2mafffy7r6a`). -2. A Push token deployed for that exact source token. -3. Gas configuration in UniversalCore. -4. A WPC pool. -5. Support in the destination gateway and vault. +- The preset shows ETH/BNB as the token sent from Push. Its limits are counted in ETH/BNB sent from Push, and the wrap step is capped to the same amount. +- If any step fails on arrival, the whole transaction reverts and the ETH/BNB comes back to the wallet on Push. As with any failed send today, it still counts toward the preset's total limit. +- After the wrap, everything is the same as the WETH/WBNB version, including how funds come back. +- SDK work only. We'll estimate it if you lean toward A. -**Question:** which of these can be added, by whom, and roughly when? Which will not be supported? For those, we could choose different reviewed tokens for the preset. +**What it would unblock:** -## 3. May presets send native ETH/BNB instead of WETH/WBNB? +- **No longer blocked by routes:** DEX Base, DEX Arbitrum, Staking Sepolia. +- **Still blocked:** + - DEX BNB: USDT; + - Lending Base: LINK, USDbC (wrapping covers its Moonwell WETH); + - Lending Sepolia and Lending BNB: none of their tokens are wrapped native. -Sending native ETH/BNB from Push already works on all four test chains. For the presets that need WETH or WBNB (DEX on Base, Arbitrum and BNB, and Sepolia staking), the preset could send native ETH/BNB, then wrap it into WETH/WBNB on arrival, with the same amounts and limits. The app still receives the WETH/WBNB it expects. +**Options:** -| Option | Result | -|---|---| -| A. Allow native plus wrap | Those presets don't wait for WETH/WBNB routes. The preset shows ETH/BNB as the token sent from Push. SDK work only | -| B. Keep WETH/WBNB exactly | Those presets wait for the WETH/WBNB routes in question 2 | +- **A. Allow native + wrap** +- **B. Keep WETH/WBNB exactly:** those presets wait for the routes in question 2 -**Decision needed:** A or B. With A, the WETH/WBNB entries can be dropped from question 2. +**Decision needed:** A or B? With A, the WETH/WBNB entries drop out of question 2. diff --git a/plan/agw/questions-core-gateway.md b/plan/agw/questions-core-gateway.md index 3fb6cd4e..f8fbc947 100644 --- a/plan/agw/questions-core-gateway.md +++ b/plan/agw/questions-core-gateway.md @@ -1,49 +1,62 @@ # Questions for the core/node and gateway teams -Updated October 21, 2026. Draft; nothing sent. +Updated October 21, 2026. **On hold; not sending now.** None of these blocks Riyanshu or any SDK work, and the SDK already handles each one: + +- the labels say failed sends count toward the total; +- the gas budget never attaches less than the pool cost, and a send that doesn't fit is refused before signing; +- the registry check is an internal script; +- Aman question 1 covers whether the `.old` routes stay. + +The "send when" line under each question says what would make it worth asking. - AGW contract questions are in [questions-zaryab.md](questions-zaryab.md). - Preset token routes are in [questions-aman.md](questions-aman.md). - What we verified ourselves (node `testnet/donut` `ca3b8d4e`, deployed contracts, live runs) is in [pre-question findings](research/pre-question-findings-2026-10-21/README.md). +Intro when sending: "A few questions from the agentic wallet (AGW) work on Donut. We checked node testnet/donut (ca3b8d4e, v1.1.44-donut) and the deployed contracts first; these are what we couldn't settle ourselves." + --- ## Core / node team ### 1. Is wiring `creditRevert` for failed agent sends planned? -When an agentic wallet's outbound fails on the destination, the node re-mints the token to the wallet and refunds unused gas. +When an agentic wallet's outbound fails on the destination, the node re-mints the token to the wallet and refunds unused gas. But the rule still counts that amount against its total limit. `UniversalRulesPolicy.creditRevert` exists to undo that count, but nothing calls it on any node branch; its own comment says the executor doesn't call it yet. -But the wallet's rule still counts that amount against its total limit. The AGW policy has `creditRevert` to undo the count. Its own comment says the executor module does not call it yet, and no node code on any branch calls it. +**Question:** is wiring it planned, and when? Until then, we tell users that failed sends count toward the total. -**Question:** is calling `creditRevert` on failed outbounds from AGW wallets planned, and when? Until then we tell users that failed sends count toward the total. +**Send when:** Harsh answers question 3.1 and doesn't accept that failed sends count toward the total, or before mainnet. -### 2. BNB testnet gas price: is the current voting setup intended? +### 2. Is the BNB testnet gas price voting set up as intended? -The BNB testnet gas price on Donut jumps between 0.055, 0.11 and 1.1 gwei, often within minutes. From the node code and chain data: +On Donut the BNB testnet gas price jumps between 0.055, 0.11 and 1.1 gwei, often within minutes. From the node code: -- Each validator reads `eth_gasPrice` from a rotating public RPC and adds 10%. -- Only two validators vote for BSC testnet, and the chain takes the higher of the two. -- There is no smoothing or clamp. +- each validator reads `eth_gasPrice` from a rotating public RPC and adds 10%; +- only two validators vote for BSC testnet, and the chain takes the higher vote; +- there is no smoothing or clamp. -A first agent send to BNB testnet then needs about 2.4 PC or about 24 PC, depending on the moment. +So the gas for a wallet's first agent send to BNB swings between about 2.4 PC and 24 PC depending on the moment. -**Question:** is this setup intended? Could more validators vote, or could a smoothing window or a clamp be added? +**Question:** is this intended? Could more validators vote, or could a smoothing window or clamp be added? -### 3. Can the SDK rely on `abci_query` to read the token registry? +**Send when:** a BNB preset becomes route-ready, or users hit the gas-budget error on BNB. -The REST and gRPC query endpoints aren't reachable publicly. Tendermint `abci_query /uregistry.v1.Query/AllTokenConfigs` on `donut.rpc.push.org` works. +### 3. Can the SDK rely on `abci_query` to read the token registry? -The SDK uses it in a check that the SDK's routes match the node. +The public REST and gRPC query endpoints aren't reachable. Tendermint `abci_query /uregistry.v1.Query/AllTokenConfigs` on `donut.rpc.push.org` works, and the SDK uses it in a check that its routes match the node. **Question:** is this a supported way to read the registry, or will a public REST endpoint be exposed? -### 4. Can the `.old` USDC config files be restored on `develop`? +**Send when:** the SDK needs to read the registry at runtime rather than in a check script. + +### 4. Can the USDC `.old` config files be restored on `develop`? -The live registry keeps the three `USDC.*.old` routes, which two presets depend on. But the node's `develop` branch dropped their config files (merge `47ef4c9a`). `testnet/donut` and main still have them. +The live registry keeps `USDC.eth.old`, `USDC.base.old` and `USDC.arb.old`, and two AGW presets depend on them. The `develop` branch dropped their config files (merge `47ef4c9a`); `testnet/donut` and main still have them. **Question:** can they be restored on `develop`, so a future config sync doesn't remove routes in use? +**Send when:** Aman confirms the `.old` routes are staying. + --- ## Core and gateway teams @@ -52,7 +65,9 @@ The live registry keeps the three `USDC.*.old` routes, which two presets depend We matched both deployments by bytecode and build strings, but neither exact source is in any commit: -- **UniversalCore** on Donut (implementation `0xa0023b35…`) matches `core-testnet` `8bc60ae`. The verified file differs only in import paths and comments. +- **UniversalCore** on Donut (implementation `0xa0023b356344ff623c7e20679cf9d170e44fbbd1`) matches `core-testnet` `8bc60ae`. The verified file differs only in import paths and comments. - **The Solana gateway at `CFVS…`** was built from `pc20-3rd-iteration` with `declare_id` changed locally. No branch declares CFVS. **Question:** can the exact deployed sources be committed or tagged, so the SDK and audits can pin them? + +**Send when:** an audit starts, or before mainnet. diff --git a/plan/agw/questions-harsh.md b/plan/agw/questions-harsh.md index 5441c1ec..f9b48ef9 100644 --- a/plan/agw/questions-harsh.md +++ b/plan/agw/questions-harsh.md @@ -1,91 +1,89 @@ # Product decisions for Harsh: agentic wallet creation -Updated October 21, 2026. Draft; nothing sent. +Updated October 21, 2026. Final; ready to send. Preset questions (preset tokens and routes) are with Aman in [questions-aman.md](questions-aman.md). -These questions come from Riyanshu's feedback on the wallet-creation screen. Each one describes how things work today, then the choices. Some choices need extra work from Zaryab (contracts), and that is noted where it applies. The SDK can implement whichever option you pick. Preset questions (preset tokens and routes) are with Aman in [questions-aman.md](questions-aman.md). +Four product decisions on agentic wallet creation, from Riyanshu's testing of the create screen. Questions 1 and 2 block that screen today; 3 and 4 decide what we promise users. Each one says how it works today and lists the options. Options that need contract work from Zaryab are marked. If you're considering one of them, tell us and we'll get Zaryab's estimate before you decide. "SDK only" means no contract change or redeploy. -Terms used: +Terms: -- **Rule:** what the owner grants an agent: which apps it may call, which tokens it may move, and limits. -- **Destination account:** the wallet's own account on the other chain (Sepolia, Base, Solana, …). Tokens sent from Push land there first, and the agent's app actions run from there. +- **Rule:** what the owner lets an agent do: which apps it can call, which tokens it can move, and the limits. Each rule has an expiry date set when it's created (presets default to 7 days). +- **App action:** one function on one app contract, for example "swap exact input on Uniswap" or "supply on Aave". +- **Push-chain rule / other-chain rule:** a rule is either for apps deployed on Push Chain itself, or for apps on another chain (Sepolia, Base, Arbitrum, BNB, Solana). +- **Destination account:** the wallet's own account on another chain. Tokens sent from Push land there first, and the agent's app actions run from there. +- **PC:** Push Chain's native coin. Gas for every agent transaction is paid in PC. + +These choices apply to rules created afterwards. Existing rules keep their settings until the owner updates them. --- -## 1. Can a rule allow token transfers without picking any app? +## 1. Can a rule allow token transfers without picking an app? -**Today.** A rule must include at least one app action, such as "swap on Uniswap". The contract rejects a rule that has tokens but no actions. Riyanshu expected the owner to be able to pick only tokens and leave apps empty. +**Today.** An other-chain rule needs at least one app action, and the contract rejects tokens-only rules. Riyanshu expected apps to be optional. Developers can already write a transfer permission by hand with the SDK. The question is what the create screen should build automatically when the owner picks tokens but no app. -**What we can build.** We can build a "transfer" action automatically, so a tokens-only rule becomes a rule that allows sending those tokens. The decision is who the agent may send them to: +The choice is who the agent may send tokens to: -| Option | What the agent could do | Extra work | -|---|---|---| -| A. Named recipients | Send the selected tokens only to addresses the owner enters, up to a per-transfer amount | SDK only | -| B. Any recipient | Send the selected tokens to any address, up to a per-transfer amount | SDK only | -| C. Owner's own address | Send tokens only back to the owner's address on that chain | SDK only | -| D. Keep apps required | No change; the screen explains that an app must be chosen | UI text only | +- **A. Named recipients:** only addresses the owner enters, up to a per-transfer amount (SDK only) +- **B. Any recipient,** up to a per-transfer amount (SDK only) +- **C. Only back to the owner's own address** on that chain (SDK only) +- **D. Keep apps required;** the screen explains that an app must be picked (UI text only) -**Things to know whichever option you pick:** +A and C can be combined: the owner's address is just one more named recipient. -- The permission also covers tokens already sitting in the destination account, not only tokens sent from Push. -- The per-transfer limit applies to each transfer. The agent can repeat transfers until the rule expires, so there is no total limit on transfers made on that chain. -- This works for regular tokens (ERC20) on EVM chains. - - Native coins (ETH/BNB) can't be sent this way. They would arrive as wrapped WETH/WBNB instead. - - On Solana it is not possible at all without contract changes. +**How much is at risk with A–C.** The limit is per transfer, and the agent can repeat transfers until the rule expires. So the agent can move the selected tokens' entire balance in the destination account, a few transfers at a time, including tokens that were already there. The "total from Push" limit doesn't stop this, because it only counts tokens sent from Push. For example: -**Decision needed:** A, B, C or D. If A, B or C: is EVM tokens only acceptable for the first version? +- with B, a rule that allows 100 USDC per transfer lets the agent send the whole USDC balance to anyone; +- with A, the balance can go only to the named addresses; +- with C, it can only go back to the owner. ---- +**Other limits:** -## 2. What should "no tokens selected" mean? +- It works for EVM tokens (ERC20) only. +- Native ETH/BNB can't be included, because a rule can only allow contract function calls, not plain coin transfers. +- Solana isn't possible without contract changes (Zaryab). -**Today.** If the owner selects no tokens, the agent cannot move any tokens out of Push. Riyanshu expected no selection to mean "all tokens allowed". +**Decision needed:** A, B, C or D? If A–C, is EVM tokens only OK for the first version? -**How the contract works.** A rule can list at most 8 tokens per chain, and each needs its own limit. There is no "any token" setting, and tokens added later are never included automatically. +## 2. What should "no tokens selected" mean? -| Option | What it means | Extra work | -|---|---|---| -| A. Keep as is | No tokens selected means no tokens can be moved | None | -| B. "All supported tokens" button | One click fills in every supported token for that chain (currently 3–7 per chain). The owner still sees the list, and each token gets its own limit | SDK and UI | -| C. True "any token" | Covers every token, including ones added in the future, under one limit | New contract design (Zaryab) | +**Today.** No tokens selected means the agent can't move any tokens out of Push. It can still use the selected apps with funds already in the destination account. Riyanshu expected no selection to mean "all tokens allowed". -**Note on option B.** It needs a limit for each token, because amounts differ by token (for example 10 USDC versus 0.001 ETH). Either the owner enters them, or we supply a reviewed default per token. +A rule can list at most 8 tokens per chain, each with its own limit. There's no "any token" setting, and tokens added later are never included automatically. -**Decision needed:** A, B or C. If B: should the owner enter each limit, or should we supply defaults? +- **A. Keep as is** (no work) +- **B. An "All supported tokens" button** that fills in every token Push can send to that chain (3–7 today). Each token still gets its own limit (SDK + UI) +- **C. True "any token",** including future tokens, under one limit. One limit across different tokens would need a common unit, such as USD prices. This is a new contract design (Zaryab) ---- +**Decision needed:** A, B or C? If B, does the owner enter each token's limit, or do we supply a default per token? Limits differ by token (for example 10 USDC versus 0.001 ETH). -## 3. What do the spending limits mean, and are they strong enough? +## 3. Are the spending limits clear and strong enough? -**Today.** These are the limits the contracts actually enforce: +What the contracts enforce today, with the label text we'd show: -| Limit | What it really controls | +| Label | What it really controls | |---|---| -| Per send from Push | The most of a token sent from Push in one transaction | -| Total from Push | The most of a token sent from Push over the rule's life. It also counts sends that later fail on the other chain. It does **not** count funds already on the other chain | -| Per action (swap, lend, etc.) | The most used in one action. The agent can repeat actions until the rule expires | -| Gas per transaction | The most PC attached for gas in one transaction; unused gas is refunded. There is no total gas limit | +| Max per send from Push | The most of a token sent from Push in one transaction | +| Max total sent from Push (includes failed sends) | The most of a token sent from Push over the rule's life. If a send fails on the other chain, the tokens come back to the wallet on Push, but the amount still counts toward this total. It doesn't count funds already on the other chain | +| Max per action | The most used in one app action. The agent can repeat actions until the rule expires | +| Max gas per transaction (PC) | The most PC attached for gas in one transaction. Unused gas is refunded to the wallet. There's no total gas limit | -**Not limited today:** the price a swap gets (slippage), and total borrowing on lending apps. Borrowing is limited per action only. +**Not limited today:** -**Decisions needed:** +- **Swap price (slippage).** The agent can accept any price on a swap. A careless or malicious agent could swap 100 USDC for far less than it's worth and stay within every limit above. +- **Total borrowing on lending apps.** Only each action is limited. -1. Is it acceptable to ship with these limits, with labels that describe them exactly as above? -2. Do you need either of these stronger limits? - - a. a total limit for activity on the other chain (for example "at most 100 USDC of swaps in total"); - - b. a limit on the combined amount of all actions in one transaction. +**Decisions needed:** - Both need contract work (Zaryab). -3. Rules for apps on Push itself can already enforce totals (a total amount and a maximum number of uses) in the contract. The SDK doesn't offer them yet. Should it? This is SDK work only. - ---- +1. Is it OK to ship with these limits and labels? +2. Do you need either of these stronger limits? Both need contract work (Zaryab): + - a. **A total limit on activity on the other chain**, for example "at most 100 USDC of swaps in total". This closes the gap that repeated actions have no total. + - b. **A limit on the combined amount of all actions in one transaction.** Today one transaction can include up to 10 actions, each at the per-action maximum. +3. Push-chain rules can already enforce a total amount and a maximum number of uses, but the SDK doesn't offer them yet. Should it? (SDK only. Other-chain rules would still lack these totals unless 2a is built.) ## 4. How many app actions can a Push-chain rule have? -**Today.** The SDK spec says a rule can have 1 to 32 app actions on every chain. The deployed contract allows 32 for other chains, but only 8 for rules about apps on Push itself. The contract source says 8 was chosen on purpose, to keep what an owner approves at once readable (not because of gas), and that raising it is a design change. Owners who need more can create more than one rule for the same agent. +The SDK spec says 1–32 app actions per rule. The deployed contract allows 32 for other-chain rules, but only 8 for Push-chain rules. The contract chose 8 on purpose, to keep what an owner approves at once readable, not because of gas. Owners who need more can create several rules for the same agent; several rules can be created together in one approval. -| Option | Extra work | -|---|---| -| A. Change the spec to "up to 8 for Push-chain rules" | Spec text only | -| B. Ask for more than 8 | Contract design change and redeployment (Zaryab) | +- **A. Change the spec** to "up to 8 for Push-chain rules" (spec text only) +- **B. Ask for more than 8** (contract change and redeploy, Zaryab) -**Decision needed:** A or B. If B, how many are needed? +**Decision needed:** A or B? If B, how many? diff --git a/plan/agw/questions-zaryab.md b/plan/agw/questions-zaryab.md index 749f3bdc..88dc4a07 100644 --- a/plan/agw/questions-zaryab.md +++ b/plan/agw/questions-zaryab.md @@ -1,44 +1,41 @@ # Contract questions for Zaryab: agentic wallet (AGW) v6 -Updated October 21, 2026. Draft; nothing sent. +Updated October 21, 2026. Question 1 is final and ready to send. Question 2 is held until Harsh answers. What we verified ourselves is in [pre-question findings](research/pre-question-findings-2026-10-21/README.md). -These questions cover only the deployed AGW contracts (source `ffd567d`). What we verified ourselves is in [pre-question findings](research/pre-question-findings-2026-10-21/README.md). +These questions cover only the deployed AGW contracts (source `ffd567d`). --- -## 1. Solana `fromEnd` data pins can be shifted by appending bytes. Is a fix planned? +## 1. SvmRulebook: `fromEnd` data pins can be shifted by appending bytes. Is a fix planned? -From the source (`SvmRulebook.sol`): +- `AllowedProgram` has no instruction-data length field. The only length checks are the global 1024-byte cap, the exact outer-payload length, and `ixLen >= discriminatorLen` for rule matching. +- `_resolveOffset` returns `ixLen - offset` once the data is long enough (`SvmRulebook.sol:666-677`). So an agent can append N bytes inside the instruction data and raise the length field to match. The payload is still well-formed, and every `fromEnd` pin then reads the appended bytes. +- Example: on a Jupiter-style layout, the appended bytes could satisfy the fee, slippage and ratio pins while the real arguments earlier in the data say something else. Account pins still hold. +- No test appends bytes inside the instruction data. `test_svm_S17_fromEndDataTooShortByOne` shows the read position moving with the length. +- It's only exploitable where the target program ignores trailing instruction data. -- **No length rule per program.** `AllowedProgram` has no instruction-data length field. The only length checks are: - - the global 1024-byte cap; - - the exact outer-payload length; - - for rule matching, `ixLen >= discriminatorLen`. -- **How `fromEnd` reads.** `_resolveOffset` returns `ixLen - offset` once the data is long enough (`:666-677`). So an agent can append N bytes inside the instruction data and raise the length field to match. The payload is still well-formed, and every `fromEnd` pin then reads the appended bytes. -- **Example.** On a Jupiter-style layout, the agent could append bytes that satisfy the fee, slippage and ratio pins while the real arguments earlier in the data say something else. Account pins still hold. -- **Test coverage.** There is no test that appends bytes inside the instruction data. `test_svm_S17_fromEndDataTooShortByOne` shows the read position moving with the length. -- **When it matters.** Exploitability depends on whether the target program ignores trailing instruction data. +**Possible fixes:** a per-rule exact (or maximum) instruction-data length for fixed-layout instructions, or refusing `fromEnd` pins unless such a length is set. -**Possible fixes:** -- a per-rule exact (or maximum) instruction-data length for fixed-layout instructions; or -- refusing `fromEnd` pins unless such a length is set. +The SDK never creates `fromEnd` pins, so SDK-built rules aren't affected. -**Question:** is a fix planned? The SDK never creates `fromEnd` pins, so SDK-authored rules aren't affected. +--- -## 2. Only if Harsh asks for them: are these feasible, and roughly how much work? +## 2. Held: send only the items Harsh picks -Harsh is deciding product options that would need contract changes. No change is requested yet. +Each item below is a contract option in [questions-harsh.md](questions-harsh.md). Ask Zaryab about an item only if Harsh chooses it. No change is requested yet. -1. **A total limit on activity on the destination chain.** Today pins and `maxValue` limit each call, and nothing adds them up across calls or transactions. -2. **A combined limit within one transaction.** The sum of a pinned amount across up to 10 calls in one request. -3. **"Any token" assets.** Today a rule holds 1–8 explicit PRC20s and there is no wildcard. -4. **Token transfers on Solana without an app program.** `SvmRulebook` forbids the System and SPL Token programs, so an agent can move SOL or SPL only through an allow-listed program's CPI. Could a constrained transfer (fixed recipient, capped amount) be allowed? -5. **More than 8 actions for Push-chain rules.** The source calls 8 a deliberate sanity bound, and raising it a design change. +| If Harsh picks | Ask Zaryab: feasible, and roughly how much work? | +|---|---| +| Q1 with Solana | Token transfers on Solana without an app program. `SvmRulebook` forbids the System and SPL Token programs, so an agent can move SOL or SPL only through an allow-listed program's CPI. Could a constrained transfer (fixed recipient, capped amount) be allowed? | +| Q2 option C | "Any token" assets. Today a rule holds 1–8 explicit PRC20s and there is no wildcard. | +| Q3.2a | A total limit on activity on the destination chain. Today pins and `maxValue` limit each call, and nothing adds them up across calls or transactions. | +| Q3.2b | A combined limit within one transaction: the sum of a pinned amount across up to 10 calls in one request. | +| Q4 option B | More than 8 actions for Push-chain rules. The source calls 8 a deliberate sanity bound, and raising it a design change. | --- ## Already answered from source; no longer asked - **Why 8 native actions.** It is a deliberate sanity bound for readability, the duplicate scan and revoke cost, not a gas bound (`AGW.sol:73-86`, `docs/1_AGW.md:532,573`). The session engine has no cap. -- **`creditRevert`.** No node code calls it on any branch, so a failed send still counts against `maxTotal`. Wiring it is node work; that question is in [questions-core-gateway.md](questions-core-gateway.md). +- **`creditRevert`.** No node code calls it on any branch, so a failed send still counts against `maxTotal`. Wiring it is node work; that question is held in [questions-core-gateway.md](questions-core-gateway.md). - **Solana token-account ownership.** The policy cannot check it (`Types.sol:585-587`). The owner pins positions, and the SDK pins the wallet's token account. Pins compare exact keys; writable and signer flags are not checked. From 7c267cb6832049487a2a36629e1db4d8f8220094 Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Sat, 24 Oct 2026 17:09:38 +0530 Subject: [PATCH 67/68] feat(core): ship working AGW presets, tokens-only rules and MOVEABLE ALL Act on the product, preset and contract answers (Harsh, Aman, Zaryab): - Presets contain only what works: Uniswap V3 and Aave V3 on Sepolia, Base Sepolia and Arbitrum Sepolia. Each sends native ETH from Push and wraps it on arrival; DEX swaps WETH and Circle USDC on the destination only. get() returns { rules }: readiness and the network option are removed, PREDICTION and the mainnet templates are dropped, and supplied assets must be one ETH asset per chain with positive limits. - Tokens-only EVM rules: ERC20 assets without allowedCalls become transfer calls pinned to the owner's EVM address, plus opt-in transferTo recipients. Native assets and Solana are refused. - MOVEABLE.TOKEN..ALL expands to every routable token with default limits; utils.agentic.assets.all(chain) exposes the list. create, add and update take the new AuthoredRule input type; Rule is unchanged. - Report the eight-function Push-chain limit before the generic 1..32. - Refuse Solana fromEnd data pins on write until the policy fix. - Decode InnerValueExceedsAllowance and BeneficiaryMismatch, which URP encodes by selector and its compiled ABI omits. Tests: rewritten preset unit, local v6 and live acceptance specs (the DEX case picks the fee tier with QuoterV2); new tokens-only/ALL unit and live specs; the old prefunded preset fixtures are removed. All six presets and both tokens-only/ALL cases pass live on Donut. --- packages/core/AGW.md | 189 ++-- .../__agw-local__/preset-acceptance.spec.ts | 34 +- .../core/__agw-local__/v5-multiasset.spec.ts | 444 +++++----- .../__e2e__/agw/presets-acceptance.spec.ts | 258 +++--- .../__e2e__/agw/presets-expanded-live.spec.ts | 819 ------------------ .../core/__e2e__/agw/presets-live.spec.ts | 556 ------------ .../core/__e2e__/agw/tokens-only-live.spec.ts | 220 +++++ packages/core/__e2e__/ci/preflight.ts | 12 +- packages/core/__e2e__/ci/suite.ts | 92 +- .../__e2e__/shared/agw-preset-acceptance.ts | 3 - packages/core/scripts/check-agw-package.js | 15 +- .../scripts/check-agw-preset-compatibility.js | 412 +++------ .../core/scripts/check-agw-preset-routes.js | 28 +- .../core/scripts/check-agw-route-registry.js | 3 +- .../agentic/__tests__/creation-errors.spec.ts | 171 ++-- .../agentic/__tests__/preset-catalog.spec.ts | 420 +++++---- .../__tests__/preset-default-policy.spec.ts | 190 +--- .../__tests__/preset-default-tokens.spec.ts | 154 ---- .../__tests__/preset-operation-limits.spec.ts | 264 +----- .../agentic/__tests__/preset-routes.spec.ts | 174 +--- .../src/lib/agentic/__tests__/presets.spec.ts | 241 ++---- .../__tests__/response-surface.spec.ts | 23 +- .../lib/agentic/__tests__/rule-inputs.spec.ts | 301 +++++++ .../agentic/__tests__/svm-internals.spec.ts | 14 + .../agentic/__tests__/token-routes.spec.ts | 42 - .../core/src/lib/agentic/agentic.types.ts | 22 +- packages/core/src/lib/agentic/codec/rules.ts | 7 +- .../core/src/lib/agentic/codec/svm-terms.ts | 13 + packages/core/src/lib/agentic/constants.ts | 1 - .../core/src/lib/agentic/error-messages.ts | 23 +- packages/core/src/lib/agentic/index.ts | 5 +- .../src/lib/agentic/management/prepare.ts | 7 +- .../src/lib/agentic/management/rule-inputs.ts | 310 +++++++ .../src/lib/agentic/management/svm-public.ts | 3 +- .../src/lib/agentic/presets/aave-reserves.ts | 146 ---- .../core/src/lib/agentic/presets/catalog.ts | 562 ++++-------- .../src/lib/agentic/presets/default-policy.ts | 94 +- .../src/lib/agentic/presets/default-tokens.ts | 80 -- .../core/src/lib/agentic/presets/index.ts | 303 +------ .../lib/agentic/presets/operation-limits.ts | 120 +-- .../core/src/lib/agentic/presets/routes.ts | 53 -- .../core/src/lib/agentic/presets/types.ts | 80 +- packages/core/src/lib/agentic/public-rule.ts | 32 +- packages/core/src/lib/agentic/revert.ts | 9 + packages/core/src/lib/constants/index.ts | 1 + packages/core/src/lib/constants/tokens.ts | 41 +- packages/core/src/lib/index.ts | 5 +- packages/core/src/lib/utils.ts | 7 +- 48 files changed, 2332 insertions(+), 4671 deletions(-) delete mode 100644 packages/core/__e2e__/agw/presets-expanded-live.spec.ts delete mode 100644 packages/core/__e2e__/agw/presets-live.spec.ts create mode 100644 packages/core/__e2e__/agw/tokens-only-live.spec.ts delete mode 100644 packages/core/src/lib/agentic/__tests__/preset-default-tokens.spec.ts create mode 100644 packages/core/src/lib/agentic/__tests__/rule-inputs.spec.ts create mode 100644 packages/core/src/lib/agentic/management/rule-inputs.ts delete mode 100644 packages/core/src/lib/agentic/presets/aave-reserves.ts delete mode 100644 packages/core/src/lib/agentic/presets/default-tokens.ts delete mode 100644 packages/core/src/lib/agentic/presets/routes.ts diff --git a/packages/core/AGW.md b/packages/core/AGW.md index 78d4bd36..d2d28b64 100644 --- a/packages/core/AGW.md +++ b/packages/core/AGW.md @@ -11,6 +11,7 @@ import { PushChain, AgenticError, AgenticRevertError, + type AuthoredRule, type Rule, } from '@pushchain/core'; import { @@ -132,9 +133,9 @@ function walletErrorText(error: unknown): string { Creation and rule-preparation errors include a zero-based `details.ruleIndex` when a rule can be identified, with `assetIndex`, `callIndex` and `field` where available. The UI message uses a one-based rule number. Use these details to show the error on the relevant rule instead of only in a footer. Read/receipt failures preserve their causes and transaction hashes; do not automatically retry a submitted transaction whose outcome is unknown. -`TOKEN_ROUTE_UNAVAILABLE` means an asset cannot be resolved for transfers from Push. Choose a token with a supported route on this network, or wait for a verified PRC20 route for that exact token address. Changing a symbol does not create a route. Display `error.userMessage` and check preset readiness before creation. +`TOKEN_ROUTE_UNAVAILABLE` means an asset cannot be resolved for transfers from Push. Choose a token with a supported route on this network, or wait for a verified PRC20 route for that exact token address. Changing a symbol does not create a route. Display `error.userMessage`. -A DEX condition-limit failure reports `details.reason = 'RULE_CONSTRAINT_LIMIT'`, `actual`, `limit` and `callCount`. Conditions here are generated input checks (for example token, recipient and amount checks), rather than the number of visible function names. A stock two-token, single-router preset contains six allowed-call entries and twenty conditions. Appending the same call list again makes forty conditions. The SDK rejects this; it does not deduplicate, remove conditions or split authority automatically. Preserve per-chain rules and regenerate after edits rather than appending generated calls. +A DEX condition-limit failure reports `details.reason = 'RULE_CONSTRAINT_LIMIT'`, `actual`, `limit` and `callCount`. Conditions here are generated input checks (for example token, recipient and amount checks), rather than the number of visible function names. A stock DEX preset contains eight allowed-call entries and twenty-one conditions. Appending the same call list again makes forty-two conditions. The SDK rejects this; it does not deduplicate, remove conditions or split authority automatically. Preserve per-chain rules and regenerate after edits rather than appending generated calls. For the review screen, show the actual network (including testnet name), selected token addresses and limits. Label maxGasPerCall as a maximum PC gas budget, not a guaranteed fee or execution gas-unit count. maxTotal meters cumulative Push outbounds, including outbounds whose destination execution later fails; it is not a lifetime destination-spend limit. Destination pins and maxValue limit each call separately. @@ -163,7 +164,7 @@ function solanaRule(agent: Address, program: string): Rule { Use the program's actual account positions. `{ account, expected: WALLET, token: mint }` pins the wallet's ATA, using the verified mint/token-program context. Fixed integer, bool, pubkey and fixed-array layouts are supported; dynamic or undefined layouts fail before signing. Raw eight-byte discriminators support account pins; argument pins also need argument types. A nonzero per-call EVM `maxValue` has no Solana encoding. -Solana reads return `format: 'decoded'` with exact stored discriminators, offsets and constraints. This raw form is accepted by `rules.update`, preserving restrictions without inventing an IDL. Reusing it for another wallet/gateway is rejected. Send-data encoding still uses the existing `utils.helpers.encodeTxData` IDL helper; rule authoring and transaction encoding are separate operations. +Solana reads return `format: 'decoded'` with exact stored discriminators, offsets and constraints. This raw form is accepted by `rules.update`, preserving restrictions without inventing an IDL. Reusing it for another wallet/gateway is rejected. A decoded rule with a data pin counted from the end of the instruction data (`fromEnd: true`) is refused on create/add/update (`INVALID_RULE`, `details.reason = 'FROM_END_PIN_UNSUPPORTED'`): the deployed SvmRulebook does not tie the instruction-data length to the rule, so appended bytes could shift such a pin. Existing rules with these pins still read normally. Send-data encoding still uses the existing `utils.helpers.encodeTxData` IDL helper; rule authoring and transaction encoding are separate operations. ## Spend, checkpoints and execution @@ -189,12 +190,13 @@ The wire encoder uses uint32 maximum for unlimited native calls and 255 for unsp ## Preset discovery and templates (section 7) -`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: +`PushChain.utils.agentic` contains `presets.list/get`. The categories are `AGENTIC.PRESETS.CATEGORY.DEXES`, `LENDING` and `STAKING`. The catalog contains only presets that ran live on the Donut testnets: -- DEXES: Uniswap V3 on Ethereum, Base and Arbitrum (mainnet and their Sepolia testnets); PancakeSwap V3 on BNB mainnet and BSC testnet. -- 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. -- 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 in explicitly supplied assets remain zero. -- PREDICTION: no entries yet. Hide categories with empty `chains` lists. +- DEXES: Uniswap V3 on Sepolia, Base Sepolia and Arbitrum Sepolia. +- LENDING: Aave V3 on Sepolia, Base Sepolia and Arbitrum Sepolia. +- STAKING: no entries yet. Hide categories with empty `chains` lists. + +Every preset sends only native ETH from Push. The agent wraps it into WETH on the destination chain as the first call of the same transaction, then uses the app. Because native ETH is routed to every listed chain, every listed preset can be created; there is no readiness report to check. ```ts const { presets } = PushChain.utils.agentic.presets.list({ type: 'CATEGORY' }); @@ -202,141 +204,91 @@ const availablePresets = presets.filter(preset => preset.chains.length > 0); const { rules: reviewTemplates } = PushChain.utils.agentic.presets.get( PushChain.CONSTANTS.AGENTIC.PRESETS.CATEGORY.DEXES, ); -// Every populated chain includes curated destination tokens in rule.assets. -// The SDK supplies spending limits, a PC budget and a seven-day expiry. -// Supply the agent to get complete Rule[] configuration. +// Each rule sends native ETH from Push with the SDK's limits, a 20 PC gas +// ceiling and a seven-day expiry. Supply the agent to get complete Rule[]. const configuredPreset = PushChain.utils.agentic.presets.get( PushChain.CONSTANTS.AGENTIC.PRESETS.CATEGORY.LENDING, { chainNamespace: 'eip155:11155111', agent: '0x0000000000000000000000000000000000001234' }, ); -// Destination assets must already be funded; no Push token exports are granted. -// Show configuredPreset.readiness.chains[0].selectedAssets in the review UI. -// Pass configuredPreset.rules directly to create after checking readiness. -// The helper below illustrates explicit overrides, rather than required UI input. +// Pass configuredPreset.rules directly to create. -function filledPreset(agent: Address, tokenIn: Address, tokenOut: Address) { +function filledPreset(agent: Address, maxPerCall: bigint, maxTotal: bigint) { return PushChain.utils.agentic.presets.get( PushChain.CONSTANTS.AGENTIC.PRESETS.CATEGORY.DEXES, { - chainNamespace: 'eip155:11155111', + chainNamespace: 'eip155:84532', agent, validUntil: Math.floor(Date.now() / 1000) + 3600, - maxGasPerCall: BigInt(10) ** BigInt(18), assets: [ - { token: tokenIn, maxPerCall: BigInt(100), maxTotal: BigInt(1000) }, - { token: tokenOut, maxPerCall: BigInt(100), maxTotal: BigInt(1000) }, + { token: PushChain.CONSTANTS.MOVEABLE.TOKEN.BASE_SEPOLIA.ETH, maxPerCall, maxTotal }, ], }, ); } ``` -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 an agent supplied, `rules` is typed as `Rule[]`; otherwise it is `PresetRuleTemplate[]` with a generated expiry and missing agent. This type distinction alone does not establish readiness. When `assets` is omitted, each chain includes its curated destination tokens with the explicit spending limits below. An explicit `assets` array replaces the defaults for every returned chain; `[]` selects no tokens. Assets in an explicit list must name their chain unless a single chain filter is supplied. For an explicit asset list, omitted caps still default to zero. An omitted gas budget uses the preset policy; an explicit zero remains zero. - -DEX discovery without `assets` includes a curated wrapped-native/stablecoin pair per chain, with both swap directions, exact-input/output functions and the token-specific input caps below. It does not require the UI to select tokens separately for every network. DEX discovery also works with an explicit empty asset list or with assets for only some chains. A chain with fewer than two explicitly supplied 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. - -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]`. - -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. - -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. - -### Curated token defaults - -These are small, protocol-specific subsets chosen to fit the 32-call/32-pin ceilings. The full reserve catalog is not automatically granted. - -| Network | DEX pair | Lending tokens | -| --- | --- | --- | -| Ethereum | WETH / USDC | WETH, USDC | -| Base | WETH / USDC | USDC (Aave and Moonwell) | -| Arbitrum | WETH / native USDC | WETH, native USDC | -| BNB | WBNB / USDT | USDT (Aave and Venus) | -| Sepolia | DEX WETH / Circle USDC | Aave faucet LINK | -| Base Sepolia | WETH / Circle USDC | Aave faucet LINK, Moonwell mock USDbC and WETH | -| Arbitrum Sepolia | WETH / Circle USDC | Aave USDC | -| BSC testnet | WBNB / Venus USDT | Venus USDT, USDC | +`get` returns `{ rules }`, one rule per chain, in the shape `create` takes. With an agent supplied, `rules` is typed as `Rule[]`; otherwise it is `PresetRuleTemplate[]` with a generated expiry and missing agent. An omitted gas budget uses the preset policy; an explicit zero remains zero. -Staking defaults are ETH/stETH/wstETH on Ethereum and the reviewed EigenLayer strategy's WETH on Sepolia. Testnet tokens with similar names can have different addresses; the returned addresses are authoritative. Defaults do not guarantee active reserves, liquidity or a Push PRC20 route. An unmodified preset cannot be granted when its assets lack matching PRC20 routes. The SDK preserves the selected tokens and caps and reports unavailable routes; it never removes assets to bypass this check. On Donut, every default asset of DEXES Sepolia and LENDING Arbitrum Sepolia currently has a registered route; the other testnet combinations do not. No runtime metadata/price fetch is added to get. +### What each preset allows -### Funding and release-network checks +Caps marked "ETH cap" equal the ETH asset's `maxPerCall`, in wei. -Missing PRC20 registry entries produce `BRIDGE_ASSET_UNAVAILABLE`, and readiness is false while the returned rule retains all requested assets. No address or cap is silently replaced. `network` defaults to `TESTNET_DONUT` (`TESTNET` is accepted as an alias). Networks without a verified AGW deployment report `AGW_NETWORK_UNAVAILABLE`. - -The public preset API has no `funding` option. Remove it from existing integrations; supplying it now produces `INVALID_RULE` rather than silently changing permissions. Internal prefunded CEA test fixtures explicitly clear bridge assets to isolate protocol constraints. Those fixtures do not demonstrate that an unsupported preset route is executable. - -Existing mappings distinguish token identity by chain and address, including address casing for EVM. WETH/stETH Sepolia mappings and string/address-word source metadata are supported; mainnet or other-chain WETH is never aliased to them. Exact routes enabled in the Push node registry are also resolved by address: Circle testnet USDC on Sepolia, Base Sepolia and Arbitrum Sepolia maps to its own PRC20, separate from the routed mock USDC. Grant preparation still verifies each PRC20 source on chain. Protocol mock LINK, Moonwell/Venus tokens, Base/Arbitrum WETH, BNB testnet WBNB and the EigenLayer WETH remain unavailable for bridge funding until matching routes exist. - -### Default permission policy - -Only preset-generated assets receive these positive values. Direct rules, unknown tokens and explicit asset lists do not acquire guessed limits. - -| Selected token | Per allowed call / Push outbound | Cumulative Push-outbound total | -| --- | --- | --- | -| USDC / USDT / mock USDbC | 10 tokens | 100 tokens | -| ETH / WETH / stETH / wstETH | 0.001 token | 0.01 token | -| WBNB | 0.01 token | 0.1 token | -| LINK | 1 token | 10 tokens | +| Preset | Allowed calls | +| --- | --- | +| DEXES | `WETH.deposit()` with `maxValue` = ETH cap; `WETH.approve(router, ≤ ETH cap)`; `exactInputSingle`/`exactOutputSingle` WETH → USDC with WETH and USDC pinned, recipient = wallet and input ≤ ETH cap; `USDC.approve(router, ≤ 10 USDC)`; the same two swaps USDC → WETH with input ≤ 10 USDC; `WETH.withdraw(≤ ETH cap)` to unwrap | +| LENDING | `WETH.deposit()` with `maxValue` = ETH cap; `WETH.approve(pool, ≤ ETH cap)`; Aave `supply`, `withdraw`, `borrow`, `repay` with the asset pinned to the reserve WETH, the beneficiary pinned to the wallet and the amount ≤ ETH cap; `WETH.withdraw(≤ ETH cap)` | -Amounts use verified token decimals, keyed by chain and address, rather than symbol or live prices. For example, the USDT per-call limit is `10 * 10^18` on BNB mainnet and `10 * 10^6` on BSC testnet. These are fixed token quantities, not USD budgets. +| Network | Uniswap router | DEX WETH / USDC | Aave pool | Aave WETH reserve | +| --- | --- | --- | --- | --- | +| Sepolia | `0x3bFA…Ae48E` | canonical WETH `0xfff9…6B14` / Circle USDC `0x1c7D…7238` | `0x6Ae4…8951` | Aave WETH `0xC558…9c3c` | +| Base Sepolia | `0x94cC…2bc4` | WETH `0x4200…0006` / Circle USDC `0x036C…CF7e` | `0x8bAB…aE27` | WETH `0x4200…0006` | +| Arbitrum Sepolia | `0x101F…663E` | WETH `0x980B…7c73` / Circle USDC `0x75fa…AA4d` | `0xBfC9…2Eff` | Aave WETH `0x1dF4…053D` | -The default expiry is seven days from each get call, computed once for all returned rules. The default gas ceiling is **20 PC per outbound**, including the value checked by URP; it is not a flat fee or a reservation. Actual sends obtain a fresh quote and remain subject to the rule cap. This ceiling has testnet protocol-flow coverage; mainnet templates do not have funded execution acceptance. Quotes may exceed the cap, requiring an explicit higher budget. +Each router's `WETH9()` is the DEX WETH it pins. Circle USDC is the only token with WETH liquidity on these Uniswap deployments; it is used only on the destination chain and is never sent from Push. The fee tier is not pinned: testnet pools are thin and often mispriced (on Arbitrum Sepolia the 0.05% pool returns nothing for small swaps), so an agent should pick the tier from a QuoterV2 quote. Testnet tokens with similar names can have different addresses; the returned addresses are authoritative. Templates describe permissions, not available liquidity or guaranteed execution. Presets do not sign, fetch app ABIs or modify wallets. -Explicit `validUntil` and `maxGasPerCall` override policy values; zero gas is preserved and reports incomplete readiness. An explicit `assets` array replaces all default tokens and limits, and omitted caps inside it remain zero. To change a preset cap while retaining its token set, take the returned assets, replace the caps and pass them back to get. Do not just edit the returned rule assets: the allowed-call pins and approvals also need regeneration. +### Limits and overrides -`maxPerCall` applies to each allowed destination call; multiple calls may each consume that amount. `maxTotal` meters assets sent from Push, not aggregate destination activity. No destination lifetime limit is implied by these defaults. The general rules API continues to treat omitted caps as zero. +| Setting | Default | +| --- | --- | +| ETH per Push outbound and per allowed call | 0.001 ETH | +| ETH sent from Push in total | 0.01 ETH | +| USDC per swap on the destination chain | 10 USDC (fixed in the returned rule) | +| Gas ceiling | 20 PC per outbound | +| Expiry | seven days from the get call | -### Configure, inspect and regenerate +Pass `assets` to set the ETH limits. Each selected chain needs exactly one native ETH asset, written as the zero address or the chain's `MOVEABLE.TOKEN..ETH`, with positive `maxPerCall` and `maxTotal`. A non-ETH token, a missing or zero limit, an empty array or a selected chain without an asset throws `INVALID_RULE`. Assets must name their chain unless a single chain filter is supplied. Call `get` again after changing a limit: the wrap value, approvals and operation pins all follow `maxPerCall`. To change the 10 USDC swap limit, edit the returned rule before `create`. -`readiness.ready` requires complete configuration plus offline SDK deployment, destination and bridge-registry support. Per-chain `configurationReady` reports input completeness separately. These checks do not verify live balances, reserve flags, liquidity or deployed bytecode. Grant preparation verifies wiring and token metadata on-chain before signing. Per-chain `selectedAssets` mirrors the selected rule assets; `bridgeAssets` reports registry presence, not verified live deployment. Mainnet templates remain discoverable but report `DESTINATION_UNAVAILABLE` on Donut. Check readiness before passing `rules` to create/update. +The 20 PC gas ceiling is not a flat fee or a reservation. Actual sends obtain a fresh quote and remain subject to the rule cap; unused destination gas is refunded. -Tokens and permission defaults come directly from the SDK: omitted `assets` populates the curated subset and its caps in every returned `rule.assets`. Omitted gas and expiry use the policy below. The caller supplies the agent and can filter chains; no per-network token selection is required. Show the generated permissions for owner review and allow explicit overrides. Regenerate via get after an edit so operation pins/approvals match the new caps. Show explicitly zero-cap calls as disabled and present excluded calls clearly. A zero bridge limit can be intentional when assets are already at the destination; it is reported separately from operation readiness. +### Configure and regenerate ```ts async function createConfiguredDex( - client: PushChain, agent: Address, tokenIn: Address, tokenOut: Address, + client: PushChain, agent: Address, maxPerCall: bigint, maxTotal: bigint, ) { - const configured = filledPreset(agent, tokenIn, tokenOut); - if (!configured.readiness.ready) { - // Render these issues in the configuration screen; do not present it as ready. - return { issues: configured.readiness.chains }; - } + const configured = filledPreset(agent, maxPerCall, maxTotal); return client.agentic.create('My DEX agent', { rules: configured.rules }); } async function replaceConfiguredDex( client: PushChain, wallet: Address, rulesId: Hex, - agent: Address, tokenIn: Address, tokenOut: Address, + agent: Address, maxPerCall: bigint, maxTotal: bigint, ) { - // Re-run get after editing tokens or limits. Changing rule.assets alone - // does not regenerate allowedCalls, token pins or approvals. - const configured = filledPreset(agent, tokenIn, tokenOut); - if (!configured.readiness.ready) throw new Error('Complete the preset inputs'); + // Re-run get after editing limits so every cap in allowedCalls follows them. + const configured = filledPreset(agent, maxPerCall, maxTotal); return client.agentic.wallet(wallet).rules.update({ rules: [{ rulesId, rule: configured.rules[0] }], }); } ``` -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. +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. An update creates a new rulesId and resets counters, as documented above. -### Amount units and enforcement scope +### Enforcement scope -| Preset operation | Generated restriction | -| --- | --- | -| DEX swap | Selected input/output token equality, wallet recipient, maximum input amount | -| Aave supply/withdraw/borrow/repay | Listed reserve token equality, wallet beneficiary, amount maximum | -| Moonwell/Venus mint/redeemUnderlying/borrow/repayBorrow | Maximum in the market's underlying-token units | -| EigenLayer deposit | Selected token equality and deposit amount maximum | -| Lido wrap/unwrap | stETH/wstETH input limits respectively; their units are not interchangeable | -| Lido submit | Native-value cap from the selected native asset's maxPerCall | - -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. - -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. - -**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. +**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, including outbounds whose destination execution later fails; it is not lifetime turnover on the destination.** These statements also hold for tokens already in the wallet's destination account, such as USDC from an earlier swap. Destination lifetime or batch-total accounting requires contract support. -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. +The contract allows at most 32 pins across a universal rule. A DEX preset uses 8 calls and 21 pins, and a LENDING preset 7 calls and 15 pins. Expansion fails explicitly if an edited rule exceeds the ceiling; no restrictions are silently dropped. Custom rules remain possible through the normal rule API. ## Validation @@ -345,28 +297,49 @@ Run `node packages/core/scripts/check-agw-docs.js` to typecheck these examples. ### Live preset acceptance -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. +The opt-in `agw-presets-acceptance` group runs all six shipped presets on Donut. From `packages/core`, run `npm run e2e:preflight -- --group agw-presets-acceptance --dry-run`, then `npm run e2e:ci -- --group agw-presets-acceptance`. Each case passes the returned `rules` unchanged to `create`, reads back every asset, cap, function and pin, then has the agent send ETH twice (first use and subsequent) with `[deposit, approve, swap or supply]`. It checks destination success, the resulting USDC or aToken balance and the recorded ETH spend. The owner needs the chain's gas PRC20 (pETH, pETH_BASE or pETH_ARB) for two bounded sends; each case funds a fresh wallet with 50 PC. No mainnet transaction is part of this group. -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. +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. +### Creation UI: apps, tokens and preset availability -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. +**Tokens without an app.** On an EVM network, a rule with ERC20 assets and no `allowedCalls` (omitted or `[]`) lets the agent transfer each token only back to the owner. The SDK adds one `transfer(address,uint256)` call per token, pinned to the owner's own EVM address and capped at that asset's `maxPerCall`. The owner's address is the Push EOA, or the EVM address the owner's account comes from. `transferTo` names more recipients, one more call per token each; the owner stays included. -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. +```ts +const tokensOnly: AuthoredRule = { + agent: '0x0000000000000000000000000000000000001234', + chainNamespace: 'eip155:11155111', + validUntil: Math.floor(Date.now() / 1000) + 7 * 86400, + assets: [ + { + token: PushChain.CONSTANTS.MOVEABLE.TOKEN.ETHEREUM_SEPOLIA.USDC, + maxPerCall: BigInt(10_000_000), + maxTotal: BigInt(100_000_000), + }, + ], + // Optional: also allow transfers to this address. + transferTo: ['0x0000000000000000000000000000000000005678'], +}; +``` -### Creation UI: apps, tokens and preset availability +The per-transfer limit can be repeated until the rule expires, so the agent can move the token's whole balance in the destination account, including tokens already there, but only to these recipients. Refused with `INVALID_RULE` and a `details.reason`: -A rule requires at least one allowed function, even when tokens and limits are selected. A tokens-only rule returns `INVALID_RULE`, with `details.reason = 'ALLOWED_FUNCTION_REQUIRED'` and actionable `userMessage`. App selection can only be hidden if the application explicitly supplies the intended function permissions; the SDK does not invent transfer recipients or permissions. +- `TOKENS_ONLY_NATIVE`: native ETH or BNB in such a rule (a rule cannot allow a plain coin transfer). +- `TOKENS_ONLY_UNSUPPORTED`: a Solana rule without an app, or `transferTo` outside EVM. +- `TRANSFER_RECIPIENT_REQUIRED`: an owner whose account comes from Solana and no `transferTo`. +- `TRANSFER_TO_WITH_CALLS`: `transferTo` together with allowed functions; add the transfer as an allowed function instead. -`assets: []` remains valid for a universal rule with allowed calls. It grants no token transfers from Push; it never means all tokens. Allowed calls may still interact with destination-held assets under their configured constraints. There is no all-token wildcard. List each permitted token and cap explicitly (at most eight assets). +A Push-chain rule, or an EVM rule with neither assets nor functions, still returns `ALLOWED_FUNCTION_REQUIRED`. A Push-chain rule allows at most eight functions; other networks allow 32. -For presets, check `readiness.ready` before enabling Create. Display the per-chain issues and the affected token address. Empty selections explain that transfers from Push are disabled. `BRIDGE_ASSET_UNAVAILABLE` identifies an unverified SDK route, not proof that no deployment exists anywhere. Do not substitute a routed token solely because its symbol matches: the protocol must support that exact address, and swaps need compatible liquidity. A transfer-only helper is not included. An ERC20 transfer can be authorized explicitly with a `transfer(address,uint256)` allowed call pinned to a recipient and a per-transfer maximum; it also applies to that token already held in the wallet's destination account. +**All supported tokens.** `assets: [{ token: PushChain.CONSTANTS.MOVEABLE.TOKEN..ALL }]` expands, when the rule is prepared, to every token Push can send to that chain, each with its default limit (10 per send and 100 in total for USDC, USDT and DAI; 0.001 and 0.01 for ETH, WETH and stETH; 0.01 and 0.1 for BNB and SOL). The Circle USDC route and the routed mock USDC are separate tokens and are both listed. Tokens added to Push later are not included in an existing rule. `ALL` takes no limits (`ALL_WITH_LIMITS`); a token listed next to it replaces its default entry. Without an app, `ALL` leaves native ETH/BNB out, so the rule transfers every routable ERC20 back to the owner. Use `PushChain.utils.agentic.assets.all(chainNamespace)` to show the expanded list and its limits before signing. -### Exact-preset acceptance and gas evidence +`assets: []` still grants no transfers from Push; it never means all tokens. Allowed calls may still interact with destination-held assets under their configured constraints. A rule holds at most eight assets. + +Every listed preset can be created; there is no readiness check. Do not substitute a routed token solely because its symbol matches: the protocol must support that exact address, and swaps need compatible liquidity. -The opt-in `agw-presets-acceptance` group exercises all nine shipped testnet category/network combinations. It passes the returned `rules` unchanged to `create`, reads back every asset/cap/function/pin, and performs first-use and subsequent agent operations. Missing routes, protocols or exact PRC20 balances fail before funding; they do not count as passing acceptance. The opt-in `agw-presets-routed` group runs only the cases whose default assets are all routed (DEXES Sepolia and LENDING Arbitrum Sepolia); preflight checks readiness for the selected cases only. The earlier `agw-presets` and `agw-presets-expanded` protocol fixtures use prefunded destination assets and remain separate coverage. +### Exact-preset acceptance and gas evidence -Read-only compatibility checks are available with `node packages/core/scripts/check-agw-preset-compatibility.js /tmp/compatibility.json` after building core. The check verifies known routed source identities (registry and exact node routes), live Aave reserves, Moonwell/Venus underlyings, the reviewed EigenLayer strategy and pools at the preset routers' factories, including each DEX preset's own default pair. A matching symbol alone is insufficient. RPC and read errors are recorded as unknown checks, never as compatibility or as missing routes. No default assets were changed. `node packages/core/scripts/check-agw-route-registry.js /tmp/registry.json` compares the SDK's routes with the Push node's token registry (uregistry): it fails on a mismatched or SDK-only route and lists enabled node routes the SDK does not resolve. +Read-only compatibility checks are available with `node packages/core/scripts/check-agw-preset-compatibility.js /tmp/compatibility.json` after building core. For every preset chain it simulates `deposit()` on the wrap target with native value, checks that the router wraps into that WETH and that Uniswap's QuoterV2 returns USDC for a dust swap at some fee tier, and that the Aave pool lists the WETH reserve. RPC and read errors are recorded and fail the check; they are never reported as compatibility. `node packages/core/scripts/check-agw-route-registry.js /tmp/registry.json` compares the SDK's routes with the Push node's token registry (uregistry): it fails on a mismatched or SDK-only route and lists enabled node routes the SDK does not resolve. `maxGasPerCall` is an owner-authorized ceiling on the PC attached to each outbound. The send-time `gasLimit` is a different field: the multiplier for the destination gas price. Omitted or zero uses the network base (500,000 on the EVM testnets, 960 on Solana devnet). Agent EVM sends without an explicit gasLimit instead use 2,000,000 on first use (the destination account is deployed), and 1,000,000 when they export a non-native token or make more than one destination call. A Sepolia Circle USDC export with approve and a Uniswap swap ran out of gas at the 500,000 base. An explicit value below the base is refused before quoting with `INVALID_RULE` and `details.minimum`. When omitted on Solana, the SDK raises the limit to cover finalization rent instead of using an EVM-style million-unit fallback. If a gas-price change leaves that budget short even after one re-quote, the send is refused before signing (`INCONSISTENT_READ`). diff --git a/packages/core/__agw-local__/preset-acceptance.spec.ts b/packages/core/__agw-local__/preset-acceptance.spec.ts index 7e7caa52..34250b34 100644 --- a/packages/core/__agw-local__/preset-acceptance.spec.ts +++ b/packages/core/__agw-local__/preset-acceptance.spec.ts @@ -1,8 +1,8 @@ /** Exact default preset output -> real AGW/URP -> exact public readback. - * Source-token PRC20 metadata and gateway are local stand-ins. This proves SDK - * preservation with provisioned routes, not live route availability or delivery. + * The gas PRC20 and gateway are local stand-ins. This proves SDK preservation, + * not live route availability or delivery. */ -import { getAddress, parseAbi, type Address } from 'viem'; +import { getAddress, parseAbi, zeroAddress } from 'viem'; import { startHarness, type Harness } from './harness'; import { PushChain } from '../src'; import type { AgenticRuntime } from '../src/lib/agentic/runtime'; @@ -12,14 +12,17 @@ import { PRESET_ACCEPTANCE_CASES, expectStoredPreset, } from '../__e2e__/shared/agw-preset-acceptance'; -const sourceABI = parseAbi(['function setSourceTokenAddress(string)']); +const CORE = parseAbi([ + 'function setGasToken(string,address)', + 'function setSourceTokenAddress(string)', +]); const CEA = getAddress('0x000000000000000000000000000000000000cea1'); const runtime = (c: PushChain) => (c as unknown as { agenticRuntime: AgenticRuntime }).agenticRuntime; describe('unchanged default preset contract acceptance', () => { let h: Harness, owner: PushChain, lookup: jest.SpyInstance; - const routes = new Map(); + const gasTokens = new Set(); beforeAll(async () => { lookup = jest .spyOn(accountLookup, 'convertExecutorToOrigin') @@ -30,11 +33,8 @@ describe('unchanged default preset contract acceptance', () => { cea: CEA, isDeployed: false, }); - runtime(owner).resolvePrc20 = (token, chain) => { - const source = typeof token === 'string' ? token : token?.address; - const mapped = routes.get(`${chain}:${source?.toLowerCase()}`); - if (!mapped) throw new Error('Fixture route not provisioned'); - return mapped; + runtime(owner).resolvePrc20 = () => { + throw new Error('Presets must not resolve a non-native route'); }; }); afterAll(async () => { @@ -54,22 +54,26 @@ describe('unchanged default preset contract acceptance', () => { const before = JSON.stringify(generated.rules, (_k, v) => typeof v === 'bigint' ? String(v) : v ); + // Presets send only native ETH, which resolves to the chain's gas PRC20. for (const asset of generated.rules[0].assets!) { const source = getAddress( typeof asset.token === 'string' ? asset.token : asset.token.address ); - const key = `${chainNamespace}:${source.toLowerCase()}`; - if (!routes.has(key)) { + expect(source).toBe(zeroAddress); + if (!gasTokens.has(chainNamespace)) { const mapped = await h.deploy( 0, 'HarnessPRC20', 'HarnessFixtures.sol', [chainNamespace, 18] ); - await h.write(0, mapped, sourceABI, 'setSourceTokenAddress', [ - source, + // Live gas PRC20s report an empty or zero source token. + await h.write(0, mapped, CORE, 'setSourceTokenAddress', ['']); + await h.write(0, h.addresses.universalCore, CORE, 'setGasToken', [ + chainNamespace, + mapped, ]); - routes.set(key, mapped); + gasTokens.add(chainNamespace); } } const made = await owner.agentic.create('preset-exact', { diff --git a/packages/core/__agw-local__/v5-multiasset.spec.ts b/packages/core/__agw-local__/v5-multiasset.spec.ts index 193a7e89..a1e5af80 100644 --- a/packages/core/__agw-local__/v5-multiasset.spec.ts +++ b/packages/core/__agw-local__/v5-multiasset.spec.ts @@ -7,6 +7,7 @@ import { encodeFunctionData, getAddress, parseAbi, + zeroAddress, type Address, type Hex, } from 'viem'; @@ -240,260 +241,180 @@ describe('v6 multi-asset SDK management and execution', () => { expect(await owner.agentic.derive()).toEqual(before); }); - it('the shipped DEX catalog enforces tuple receiver/token/amount pins on actual v6 URP', async () => { - const { rules } = agenticPresets.get('DEXES', { - chainNamespace: CHAIN_NS, - agent: h.wallets[1].account!.address, - validUntil: Math.floor(Date.now() / 1000) + 3600, - maxGasPerCall: BigInt(10) ** BigInt(16), - assets: [ - { token: a, maxPerCall: BigInt(5), maxTotal: BigInt(20) }, - { token: b, maxPerCall: BigInt(7), maxTotal: BigInt(20) }, - ], - }); + const presetOptions = (maxPerCall: bigint) => ({ + chainNamespace: CHAIN_NS, + agent: h.wallets[1].account!.address, + validUntil: Math.floor(Date.now() / 1000) + 3600, + maxGasPerCall: BigInt(10) ** BigInt(16), + assets: [{ token: zeroAddress, maxPerCall, maxTotal: BigInt(40) }], + }); + const PRESET_ABI = parseAbi([ + 'function deposit() payable', + 'function approve(address,uint256) returns (bool)', + 'function exactInputSingle((address tokenIn,address tokenOut,uint24 fee,address recipient,uint256 amountIn,uint256 amountOutMinimum,uint160 sqrtPriceLimitX96)) returns (uint256)', + 'function supply(address,uint256,address,uint16)', + ]); + // Native ETH funds the wallet's destination account; the rule caps the wrap value. + const wrapCall = (weth: Address, value: bigint) => ({ + to: weth, + value, + data: encodeFunctionData({ abi: PRESET_ABI, functionName: 'deposit' }), + }); + const approveCall = (token: Address, spender: Address, amount: bigint) => ({ + to: token, + value: BigInt(0), + data: encodeFunctionData({ + abi: PRESET_ABI, + functionName: 'approve', + args: [spender, amount], + }), + }); + it('the shipped DEX catalog enforces the wrap value, tuple receiver/token and amount pins on actual v6 URP', async () => { + const { rules } = agenticPresets.get('DEXES', presetOptions(BigInt(5))); const { wallet, id, agent } = await setup(rules[0]); - const router = rules[0].allowedCalls[0].target as Address; - const abi = parseAbi([ - 'function exactInputSingle((address tokenIn,address tokenOut,uint24 fee,address recipient,uint256 amountIn,uint256 amountOutMinimum,uint160 sqrtPriceLimitX96)) returns (uint256)', - ]); - const send = (recipient = CEA, input = a, amount = BigInt(5)) => - agent.universal.sendTransaction({ - to: { address: router, chain: CHAIN_NS }, - data: [ + expect((await stored(wallet, id)).assets[0]).toMatchObject({ + token: a, + maxPerCall: BigInt(5), + }); + const weth = getAddress(rules[0].allowedCalls[0].target); + const router = getAddress(rules[0].allowedCalls[2].target); + const usdc = getAddress(rules[0].allowedCalls[4].target); + const swap = ( + tokenIn: Address, + tokenOut: Address, + amountIn: bigint, + recipient = CEA + ) => ({ + to: router, + value: BigInt(0), + data: encodeFunctionData({ + abi: PRESET_ABI, + functionName: 'exactInputSingle', + args: [ { - to: router, - value: BigInt(0), - data: encodeFunctionData({ - abi, - functionName: 'exactInputSingle', - args: [ - { - tokenIn: input, - tokenOut: b, - fee: 3000, - recipient, - amountIn: amount, - amountOutMinimum: BigInt(0), - sqrtPriceLimitX96: BigInt(0), - }, - ], - }), + tokenIn, + tokenOut, + fee: 3000, + recipient, + amountIn, + amountOutMinimum: BigInt(0), + sqrtPriceLimitX96: BigInt(0), }, ], + }), + }); + const send = (data: ReturnType[], amount = BigInt(5)) => + agent.universal.sendTransaction({ + to: { address: router, chain: CHAIN_NS }, + funds: { amount }, + data, }); - await waitPush(send()); - await expect(send(DEST)).rejects.toMatchObject({ + const sell = (amount: bigint, recipient = CEA) => [ + wrapCall(weth, amount), + approveCall(weth, router, amount), + swap(weth, usdc, amount, recipient), + ]; + await waitPush(send(sell(BigInt(5)))); + expect((await stored(wallet, id)).assets[0].spent).toBe(BigInt(5)); + await expect( + send([wrapCall(weth, BigInt(6)), ...sell(BigInt(5)).slice(1)]) + ).rejects.toMatchObject({ + decodedError: { + name: 'PolicyCheckReverted(InnerValueExceedsAllowance)', + }, + }); + await expect(send(sell(BigInt(5), DEST))).rejects.toMatchObject({ decodedError: { name: 'PolicyCheckReverted(ArgPinMismatch)' }, }); - await expect(send(CEA, DEST)).rejects.toMatchObject({ + await expect( + send([...sell(BigInt(5)).slice(0, 2), swap(DEST, usdc, BigInt(5))]) + ).rejects.toMatchObject({ decodedError: { name: 'PolicyCheckReverted(ArgPinMismatch)' }, }); - await expect(send(CEA, a, BigInt(6))).rejects.toMatchObject({ + await expect( + send([...sell(BigInt(5)).slice(0, 2), swap(weth, usdc, BigInt(6))]) + ).rejects.toMatchObject({ decodedError: { name: 'PolicyCheckReverted(ArgPinAboveMax)' }, }); - const handle = owner.agentic.wallet(wallet), - record = await handle.rules.get(id); - const changed = await handle.rules.update({ - rules: [ - { - rulesId: id, - rule: { ...record.rule, validUntil: record.validUntil + 60 }, - }, - ], - }); - expect((await handle.rules.get(changed.rules[0].rulesId)).rule).toEqual({ - ...record.rule, - validUntil: record.validUntil + 60, + // Destination-held USDC swaps back under the fixed 10 USDC per-swap pin. + const usdcCap = BigInt(10_000_000); + await waitPush( + send( + [approveCall(usdc, router, usdcCap), swap(usdc, weth, usdcCap)], + BigInt(0) + ) + ); + // The policy reports the first matching entry's failure: the WETH-in swap's token pin. + await expect( + send([swap(usdc, weth, usdcCap + BigInt(1))], BigInt(0)) + ).rejects.toMatchObject({ + decodedError: { name: 'PolicyCheckReverted(ArgPinMismatch)' }, }); + // Calls using destination-held capital do not consume the Push bridge counter. + expect((await stored(wallet, id)).assets[0].spent).toBe(BigInt(5)); }); - it.each(['exactInputSingle', 'exactOutputSingle'] as const)( - 'a default-token DEX %s call rejects spending above its policy cap despite edited bridge budgets', - async (functionName) => { - const preview = agenticPresets.get('DEXES', { - chainNamespace: CHAIN_NS, - agent: h.wallets[1].account!.address, - }).rules[0]; - const { wallet, id, agent } = await setup({ - ...preview, - assets: [{ token: a, maxPerCall: BigInt(5), maxTotal: BigInt(20) }], - }); - const stored = await owner.agentic.wallet(wallet).rules.get(id); - expect(stored.rule.validUntil).toBe(preview.validUntil); - expect(stored.rule.maxGasPerCall).toBe(preview.maxGasPerCall); - const router = preview.allowedCalls[0].target as Address; - const abi = parseAbi([ - `function ${functionName}((address,address,uint24,address,uint256,uint256,uint160))`, - ]); - await expect( - agent.universal.sendTransaction({ - to: { address: router, chain: CHAIN_NS }, - data: [ - { - to: router, - value: BigInt(0), - data: encodeFunctionData({ - abi, - functionName, - args: [ - [ - preview.assets![0].token as Address, - preview.assets![1].token as Address, - 3000, - CEA, - preview.assets![0].maxPerCall + BigInt(1), - preview.assets![0].maxPerCall + BigInt(1), - BigInt(0), - ], - ], - }), - }, - ], - }) - ).rejects.toMatchObject({ - decodedError: { name: 'PolicyCheckReverted(ArgPinAboveMax)' }, - userMessage: expect.stringContaining('exceeds a rule'), - }); - } - ); - - it.each(['DEXES', 'LENDING', 'STAKING'] as const)( - '%s constraints work in an explicit prefunded contract fixture', - async (category) => { - const generated = agenticPresets.get(category, { - chainNamespace: CHAIN_NS, - agent: h.wallets[1].account!.address, - }); - expect(generated.readiness.chains[0].configurationReady).toBe(true); - expect( - generated.readiness.chains[0].selectedAssets.length - ).toBeGreaterThan(0); - expect(generated.rules[0].assets!.length).toBeGreaterThan(0); - const { wallet, id } = await setup({ ...generated.rules[0], assets: [] }); - const actual = await stored(wallet, id); - expect(actual.assets).toEqual([ - { - token: a, - maxPerCall: BigInt(0), - maxTotal: BigInt(0), - spent: BigInt(0), - }, - ]); - const record = await owner.agentic.wallet(wallet).rules.get(id); - expect(record.rule.maxGasPerCall).toBe(generated.rules[0].maxGasPerCall); - expect(record.rule.validUntil).toBe(generated.rules[0].validUntil); - } - ); - - it.each(['LENDING', 'STAKING'] as const)( - 'regenerated %s presets enforce new token/amount pins through atomic rules.update', - async (category) => { - const firstToken = getAddress( - '0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5' - ); - const nextToken = getAddress( - '0x29f2D40B0605204364af54EC677bD022dA425d03' - ); - const opts = { - chainNamespace: CHAIN_NS, - agent: h.wallets[1].account!.address, - validUntil: Math.floor(Date.now() / 1000) + 3600, - maxGasPerCall: BigInt(10) ** BigInt(16), - }; - const preview = agenticPresets.get(category, { ...opts, assets: [] }); - expect(preview.readiness.ready).toBe(false); - const { wallet, id, agent } = await setup({ - ...preview.rules[0], - assets: [], - }); - const target = preview.rules[0].allowedCalls[0].target as Address; - const abi = parseAbi([ - 'function supply(address,uint256,address,uint16)', - 'function depositIntoStrategy(address,address,uint256)', - ]); - const send = (token: Address, amount: bigint, count = 1) => - agent.universal.sendTransaction({ - to: { address: target, chain: CHAIN_NS }, - data: Array.from({ length: count }, () => ({ - to: target, - value: BigInt(0), - data: - category === 'LENDING' - ? encodeFunctionData({ - abi, - functionName: 'supply', - args: [token, amount, CEA, 0], - }) - : encodeFunctionData({ - abi, - functionName: 'depositIntoStrategy', - args: [DEST, token, amount], - }), - })), - }); - await expect(send(firstToken, BigInt(1))).rejects.toMatchObject({ - decodedError: { name: 'PolicyCheckReverted(ArgPinAboveMax)' }, - }); - const w = owner.agentic.wallet(wallet); - const first = agenticPresets.get(category, { - ...opts, - assets: [ - { token: firstToken, maxPerCall: BigInt(5), maxTotal: BigInt(10) }, - ], + it('the shipped LENDING catalog pins Aave supply to WETH and the wallet, and a regenerated cap applies through rules.update', async () => { + const first = agenticPresets.get('LENDING', presetOptions(BigInt(5))); + const { wallet, id, agent } = await setup(first.rules[0]); + const weth = getAddress(first.rules[0].allowedCalls[0].target); + const pool = getAddress(first.rules[0].allowedCalls[2].target); + const supply = (amount: bigint, asset = weth, onBehalfOf = CEA) => [ + wrapCall(weth, amount), + approveCall(weth, pool, amount), + { + to: pool, + value: BigInt(0), + data: encodeFunctionData({ + abi: PRESET_ABI, + functionName: 'supply', + args: [asset, amount, onBehalfOf, 0], + }), + }, + ]; + const send = (data: ReturnType, amount: bigint) => + agent.universal.sendTransaction({ + to: { address: pool, chain: CHAIN_NS }, + funds: { amount }, + data, }); - expect(first.readiness.chains[0].configurationReady).toBe(true); - const before = await h.publicClient.readContract({ + await waitPush(send(supply(BigInt(5)), BigInt(5))); + await expect( + send(supply(BigInt(5), DEST), BigInt(5)) + ).rejects.toMatchObject({ + decodedError: { name: 'PolicyCheckReverted(ArgPinMismatch)' }, + }); + await expect( + send(supply(BigInt(5), weth, DEST), BigInt(5)) + ).rejects.toMatchObject({ + decodedError: { name: 'PolicyCheckReverted(ArgPinMismatch)' }, + }); + const w = owner.agentic.wallet(wallet); + const changed = agenticPresets.get('LENDING', presetOptions(BigInt(2))); + const before = await h.publicClient.readContract({ + address: wallet, + abi: h.generation.contracts.abis.wallet, + functionName: 'checkpointCount', + }); + const replaced = await w.rules.update({ + rules: [{ rulesId: id, rule: changed.rules[0] }], + }); + expect( + await h.publicClient.readContract({ address: wallet, abi: h.generation.contracts.abis.wallet, functionName: 'checkpointCount', - }); - const added = await w.rules.update({ - rules: [{ rulesId: id, rule: { ...first.rules[0], assets: [] } }], - }); - expect( - await h.publicClient.readContract({ - address: wallet, - abi: h.generation.contracts.abis.wallet, - functionName: 'checkpointCount', - }) - ).toBe(before + BigInt(5)); - await waitPush(send(firstToken, BigInt(5))); - // Per-call MAX permits two calls of 5 in one outbound; it is not a batch-total cap. - await waitPush(send(firstToken, BigInt(5), 2)); - await expect(send(firstToken, BigInt(6))).rejects.toMatchObject({ - decodedError: { name: 'PolicyCheckReverted(ArgPinAboveMax)' }, - }); - await expect(send(nextToken, BigInt(1))).rejects.toMatchObject({ - decodedError: { name: 'PolicyCheckReverted(ArgPinMismatch)' }, - }); - const changed = agenticPresets.get(category, { - ...opts, - assets: [ - { token: nextToken, maxPerCall: BigInt(2), maxTotal: BigInt(10) }, - ], - }); - const replaced = await w.rules.update({ - rules: [ - { - rulesId: added.rules[0].rulesId, - rule: { ...changed.rules[0], assets: [] }, - }, - ], - }); - expect(replaced.rules[0].rulesId).not.toBe(added.rules[0].rulesId); - await expect(send(firstToken, BigInt(1))).rejects.toMatchObject({ - decodedError: { name: 'PolicyCheckReverted(ArgPinMismatch)' }, - }); - await expect(send(nextToken, BigInt(3))).rejects.toMatchObject({ - decodedError: { name: 'PolicyCheckReverted(ArgPinAboveMax)' }, - }); - await waitPush(send(nextToken, BigInt(2))); - // Calls using destination-held capital do not consume the Push bridge counter. - expect( - (await stored(wallet, replaced.rules[0].rulesId)).assets[0].spent - ).toBe(BigInt(0)); - } - ); + }) + ).toBe(before + BigInt(5)); + expect(replaced.rules[0].rulesId).not.toBe(id); + await expect(send(supply(BigInt(3)), BigInt(3))).rejects.toMatchObject({ + decodedError: { name: 'PolicyCheckReverted(AmountExceedsCap)' }, + }); + await waitPush(send(supply(BigInt(2)), BigInt(2))); + expect( + (await stored(wallet, replaced.rules[0].rulesId)).assets[0].spent + ).toBe(BigInt(2)); + }); it('a fixture preset produces rules accepted by public create and enforced by real contracts', async () => { const presets = buildPresetApi([ @@ -517,7 +438,7 @@ describe('v6 multi-asset SDK management and execution', () => { assets: [ { chainNamespace: CHAIN_NS, - token: a, + token: zeroAddress, maxPerCall: BigInt(5), maxTotal: BigInt(7), }, @@ -531,6 +452,55 @@ describe('v6 multi-asset SDK management and execution', () => { }); }); + it('a tokens-only rule lets the agent transfer each token only back to the owner, capped per transfer', async () => { + const ownerAddress = h.wallets[0].account!.address; + const { wallet, id, agent } = await setup({ + agent: h.wallets[1].account!.address, + chainNamespace: CHAIN_NS, + assets: [{ token: a, maxPerCall: BigInt(5), maxTotal: BigInt(20) }], + validUntil: Math.floor(Date.now() / 1000) + 3600, + maxGasPerCall: BigInt(10) ** BigInt(16), + } as unknown as Rule); + const record = await owner.agentic.wallet(wallet).rules.get(id); + if (!('allowedCalls' in record.rule)) throw new Error('Expected EVM rule'); + expect(record.rule.allowedCalls).toHaveLength(1); + const ERC20 = parseAbi([ + 'function transfer(address,uint256) returns (bool)', + ]); + const send = (to: Address, amount: bigint, funded = BigInt(5)) => + agent.universal.sendTransaction({ + to: { address: a, chain: CHAIN_NS }, + funds: { + amount: funded, + token: { + symbol: 'fixture', + decimals: 6, + address: a, + mechanism: 'approve', + }, + }, + data: [ + { + to: a, + value: BigInt(0), + data: encodeFunctionData({ + abi: ERC20, + functionName: 'transfer', + args: [to, amount], + }), + }, + ], + }); + await waitPush(send(ownerAddress, BigInt(5))); + expect((await stored(wallet, id)).assets[0].spent).toBe(BigInt(5)); + await expect(send(DEST, BigInt(5))).rejects.toMatchObject({ + decodedError: { name: 'PolicyCheckReverted(ArgPinMismatch)' }, + }); + await expect(send(ownerAddress, BigInt(6))).rejects.toMatchObject({ + decodedError: { name: 'PolicyCheckReverted(ArgPinAboveMax)' }, + }); + }); + it('public create encodes two ordered assets; public get reconstructs source-token caps', async () => { const { wallet, id } = await setup(); expect((await stored(wallet, id)).assets.map((x) => x.token)).toEqual([ diff --git a/packages/core/__e2e__/agw/presets-acceptance.spec.ts b/packages/core/__e2e__/agw/presets-acceptance.spec.ts index e8a1644f..76459777 100644 --- a/packages/core/__e2e__/agw/presets-acceptance.spec.ts +++ b/packages/core/__e2e__/agw/presets-acceptance.spec.ts @@ -1,7 +1,6 @@ /** Release acceptance: EXACT shipped preset -> create -> readback -> two agent sends. - * Missing routes, protocols or exact PRC20 balances fail before any funding. This is - * deliberately separate from - * the prefunded protocol fixtures; no asset, cap, call or pin is removed here. + * Every preset sends native ETH from Push; the agent wraps it on arrival and uses + * the app. No asset, cap, call or pin is removed or substituted here. */ import '@e2e/shared/setup'; import { @@ -11,6 +10,8 @@ import { erc20Abi, parseAbi, parseEther, + getAddress, + zeroAddress, type ContractFunctionReturnType, type Address, type Hex, @@ -32,34 +33,42 @@ const endpoints: Record = { 'eip155:11155111': 'https://ethereum-sepolia-rpc.publicnode.com', 'eip155:84532': 'https://base-sepolia-rpc.publicnode.com', 'eip155:421614': 'https://arbitrum-sepolia-rpc.publicnode.com', - 'eip155:97': 'https://bsc-testnet-rpc.publicnode.com', }; const ABI = parseAbi([ + 'function deposit() payable', 'function factory() view returns(address)', 'function getPool(address,address,uint24) view returns(address)', 'function liquidity() view returns(uint128)', 'function supply(address,uint256,address,uint16)', - 'function mint(uint256) returns(uint256)', 'function balanceOf(address) view returns(uint256)', 'function getReserveData(address) view returns ((uint256 configuration,uint128 liquidityIndex,uint128 currentLiquidityRate,uint128 variableBorrowIndex,uint128 currentVariableBorrowRate,uint128 currentStableBorrowRate,uint40 lastUpdateTimestamp,uint16 id,address aTokenAddress,address stableDebtTokenAddress,address variableDebtTokenAddress,address interestRateStrategyAddress,uint128 accruedToTreasury,uint128 unbacked,uint128 isolationModeTotalDebt))', - 'function depositIntoStrategy(address,address,uint256) returns(uint256)', - 'function stakerDepositShares(address,address) view returns(uint256)', 'function exactInputSingle((address tokenIn,address tokenOut,uint24 fee,address recipient,uint256 amountIn,uint256 amountOutMinimum,uint160 sqrtPriceLimitX96)) returns(uint256)', ]); -// Concrete calls supported by the current catalog. A newly introduced protocol -// requires its own operation/receipt assertion rather than a false generic pass. -// `input` selects which preset asset funds the operation; swaps can trade either way. -async function operation(rule: Rule, cea: Address, input = 0) { +// Uniswap V3 QuoterV2 on each testnet. Declared view so eth_call returns its quote. +const QUOTERS: Record = { + 'eip155:11155111': '0xEd1f6473345F45b75F8179591dd5bA1888cf2FB3', + 'eip155:84532': '0xC5290058841028F1614F3A6F0F5816cAd0df5E27', + 'eip155:421614': '0x2779a0CC1c3e0E44D2542EC3e79e3864Ae93Ef0B', +}; +const QUOTER_ABI = parseAbi([ + 'function quoteExactInputSingle((address tokenIn,address tokenOut,uint256 amountIn,uint24 fee,uint160 sqrtPriceLimitX96)) view returns (uint256 amountOut,uint160 sqrtPriceX96After,uint32 initializedTicksCrossed,uint256 gasEstimate)', +]); +// Concrete operations for the shipped catalog: a WETH -> USDC swap or an Aave +// WETH supply. A new protocol needs its own receipt assertion, not a generic pass. +async function operation(rule: Rule, cea: Address) { const rpc = createPublicClient({ transport: http(endpoints[rule.chainNamespace!], { timeout: 15000, - retryCount: 1, + // Public testnet RPCs drop requests; a dropped receipt read is not a failure. + retryCount: 3, }), }); - const asset = rule.assets![input], - token = ( - typeof asset.token === 'string' ? asset.token : asset.token.address - ) as Address; + const asset = rule.assets![0]; + if ( + (typeof asset.token === 'string' ? asset.token : asset.token.address) !== + zeroAddress + ) + throw new Error('Presets must send only native ETH'); const amount = asset.maxPerCall / BigInt(1000); if (amount <= BigInt(0) || (asset.maxTotal ?? BigInt(0)) < amount * BigInt(2)) throw new Error('Default caps cannot cover two bounded acceptance sends'); @@ -70,7 +79,6 @@ async function operation(rule: Rule, cea: Address, input = 0) { | 'liquidity' | 'getReserveData' | 'balanceOf' - | 'stakerDepositShares' >( address: Address, functionName: F, @@ -82,43 +90,62 @@ async function operation(rule: Rule, cea: Address, input = 0) { functionName: functionName as never, args: args as never, }) as Promise>; - const swap = rule.allowedCalls.find((c) => - c.selector.toString().startsWith('exactInputSingle(') + const wrap = rule.allowedCalls.find((c) => c.selector === 'deposit()'); + if (!wrap || wrap.maxValue !== asset.maxPerCall) + throw new Error('Preset must wrap ETH up to its per-call cap'); + const weth = getAddress(wrap.target); + const swap = rule.allowedCalls.find( + (c) => + c.selector.toString().startsWith('exactInputSingle(') && + c.pins?.some( + (p) => + 'expected' in p && p.expected === weth && p.arg?.toString() === '0,0' + ) ); - let target: Address, - data: Hex, - outputToken: Address | undefined, - shares: (() => Promise) | undefined; + let target: Address, data: Hex, resultBalance: () => Promise; if (swap) { - target = swap.target as Address; - const output = rule.assets![input === 0 ? 1 : 0]; - outputToken = ( - typeof output.token === 'string' ? output.token : output.token.address - ) as Address; - const factory = await read(target, 'factory'); - let fee: number | undefined; - for (const tier of [100, 500, 2500, 3000, 10000]) { - const pool: Address = await read(factory, 'getPool', [ - token, - outputToken, - tier, - ]); - if (!/^0x0+$/.test(pool) && (await read(pool, 'liquidity')) > BigInt(0)) { + target = getAddress(swap.target); + const usdc = getAddress( + swap.pins!.find((p) => p.arg?.toString() === '0,1')!.expected as Address + ); + // Testnet pools are thin and often mispriced, so the first tier with + // liquidity can return nothing. Uniswap's quoter simulates each swap. + let fee: number | undefined, + best = BigInt(0); + for (const tier of [100, 500, 3000, 10000]) { + let quoted: bigint; + try { + [quoted] = await rpc.readContract({ + address: QUOTERS[rule.chainNamespace!], + abi: QUOTER_ABI, + functionName: 'quoteExactInputSingle', + args: [ + { + tokenIn: weth, + tokenOut: usdc, + amountIn: amount, + fee: tier, + sqrtPriceLimitX96: BigInt(0), + }, + ], + }); + } catch { + continue; // no pool at this tier + } + if (quoted > best) { + best = quoted; fee = tier; - break; } } if (!fee) - throw new Error( - 'PRESET_PROTOCOL_UNAVAILABLE: routed default pair has no active pool' - ); + throw new Error('PRESET_PROTOCOL_UNAVAILABLE: no active WETH/USDC pool'); data = encodeFunctionData({ abi: ABI, functionName: 'exactInputSingle', args: [ { - tokenIn: token, - tokenOut: outputToken, + tokenIn: weth, + tokenOut: usdc, fee, recipient: cea, amountIn: amount, @@ -127,65 +154,41 @@ async function operation(rule: Rule, cea: Address, input = 0) { }, ], }); + resultBalance = () => read(usdc, 'balanceOf', [cea]); } else { - const call = rule.allowedCalls.find( - (c) => - c.selector === 'supply(address,uint256,address,uint16)' || - c.selector === 'mint(uint256)' || - c.selector === 'depositIntoStrategy(address,address,uint256)' + const supply = rule.allowedCalls.find( + (c) => c.selector === 'supply(address,uint256,address,uint16)' ); - if (!call) + if (!supply) throw new Error( 'PRESET_ACCEPTANCE_UNIMPLEMENTED: no verified operation for this catalog entry' ); - target = call.target as Address; - if (call.selector === 'supply(address,uint256,address,uint16)') { - const reserve = await read(target, 'getReserveData', [token]); - if (/^0x0+$/.test(reserve.aTokenAddress)) - throw new Error( - 'PRESET_PROTOCOL_UNAVAILABLE: token is not an Aave reserve' - ); - shares = () => read(reserve.aTokenAddress, 'balanceOf', [cea]); - data = encodeFunctionData({ - abi: ABI, - functionName: 'supply', - args: [token, amount, cea, 0], - }); - } else if (call.selector === 'mint(uint256)') { - shares = () => read(target, 'balanceOf', [cea]); - data = encodeFunctionData({ - abi: ABI, - functionName: 'mint', - args: [amount], - }); - } else { - const strategy = '0x424246eF71b01ee33aA33aC590fd9a0855F5eFbc' as Address; - shares = () => read(target, 'stakerDepositShares', [cea, strategy]); - data = encodeFunctionData({ - abi: ABI, - functionName: 'depositIntoStrategy', - args: [strategy, token, amount], - }); - } + target = getAddress(supply.target); + const reserve = await read(target, 'getReserveData', [weth]); + if (/^0x0+$/.test(reserve.aTokenAddress)) + throw new Error( + 'PRESET_PROTOCOL_UNAVAILABLE: WETH is not an Aave reserve' + ); + data = encodeFunctionData({ + abi: ABI, + functionName: 'supply', + args: [weth, amount, cea, 0], + }); + resultBalance = () => read(reserve.aTokenAddress, 'balanceOf', [cea]); } - const resultBalance = - shares ?? - (() => - rpc.readContract({ - address: outputToken!, - abi: erc20Abi, - functionName: 'balanceOf', - args: [cea], - })); return { rpc, - token, amount, target, resultBalance, calls: [ { - to: token, + to: weth, + value: amount, + data: encodeFunctionData({ abi: ABI, functionName: 'deposit' }), + }, + { + to: weth, value: BigInt(0), data: encodeFunctionData({ abi: erc20Abi, @@ -199,21 +202,11 @@ async function operation(rule: Rule, cea: Address, input = 0) { } d('agw unchanged preset acceptance', () => { - // Explicit titles also allow CI's scenario selector to enumerate all nine. + // Explicit titles also allow CI's scenario selector to enumerate every case. const run = async ( - category: 'DEXES' | 'LENDING' | 'STAKING', + category: 'DEXES' | 'LENDING', chainNamespace: `eip155:${string}` ) => { - const preview = PushChain.utils.agentic.presets.get(category, { - chainNamespace, - agent: '0x0000000000000000000000000000000000005678', - }); - if (!preview.readiness.ready) - throw new Error( - `PRESET_BLOCKED_BEFORE_FUNDING ${category} ${chainNamespace}: ${JSON.stringify( - preview.readiness.chains[0].issues - )}` - ); const f = await setupAgw({ deferAgentFunding: true }); try { const generated = PushChain.utils.agentic.presets.get(category, { @@ -231,34 +224,10 @@ d('agw unchanged preset acceptance', () => { endpoints[chainNamespace] ) ).cea as Address; - // A swap may start from whichever default asset the owner holds as a PRC20. - const swapPreset = generated.rules[0].allowedCalls.some((c) => - c.selector.toString().startsWith('exactInputSingle(') - ); - let input = 0; - if (swapPreset) - for (const [i, a] of generated.rules[0].assets!.entries()) { - const prc20 = resolveAgenticPrc20( - { - chain: chainNamespace, - address: typeof a.token === 'string' ? a.token : a.token.address, - }, - f.manifest.network - ).address; - const held = await f.push.readContract({ - address: prc20, - abi: erc20Abi, - functionName: 'balanceOf', - args: [f.ownerAddress], - }); - if (held >= (a.maxPerCall / BigInt(1000)) * BigInt(2)) { - input = i; - break; - } - } - const op = await operation(generated.rules[0], cea, input); + const op = await operation(generated.rules[0], cea); + // Native ETH leaves Push as the chain's gas PRC20 (pETH, pETH_BASE, pETH_ARB). const mapped = resolveAgenticPrc20( - { chain: chainNamespace, address: op.token }, + { chain: chainNamespace, address: zeroAddress }, f.manifest.network ); if ( @@ -270,7 +239,9 @@ d('agw unchanged preset acceptance', () => { })) < op.amount * BigInt(2) ) - throw new Error('PRESET_PREREQUISITE: owner lacks exact default PRC20'); + throw new Error( + `PRESET_PREREQUISITE: owner lacks ${mapped.symbol} for two sends` + ); await f.fundAgent(); const made = await f.owner.agentic.create('preset-acceptance', { rules: generated.rules, @@ -329,15 +300,7 @@ d('agw unchanged preset acceptance', () => { const tx = await agent.universal.sendTransaction({ to: { address: op.target, chain: chainNamespace as CHAIN }, data: op.calls, - funds: { - amount: op.amount, - token: { - symbol: mapped.symbol, - decimals: mapped.decimals, - address: op.token, - mechanism: 'approve', - }, - }, + funds: { amount: op.amount }, }); f.evidence('unchanged-preset-submitted', { category, @@ -369,7 +332,7 @@ d('agw unchanged preset acceptance', () => { .rules.get(made.rulesIds[0]); if (stored.spent?.kind !== 'universal') throw new Error('Missing universal spend'); - expect(stored.spent.assets[input].spent).toBe( + expect(stored.spent.assets[0].spent).toBe( op.amount * BigInt(stage === 'first-use' ? 1 : 2) ); } finally { @@ -387,22 +350,15 @@ d('agw unchanged preset acceptance', () => { () => run(...PRESET_ACCEPTANCE_CASES[2]), 600000 ); - it('4. DEXES BNB testnet', () => run(...PRESET_ACCEPTANCE_CASES[3]), 600000); - it('5. LENDING Sepolia', () => run(...PRESET_ACCEPTANCE_CASES[4]), 600000); + it('4. LENDING Sepolia', () => run(...PRESET_ACCEPTANCE_CASES[3]), 600000); it( - '6. LENDING Base Sepolia', - () => run(...PRESET_ACCEPTANCE_CASES[5]), + '5. LENDING Base Sepolia', + () => run(...PRESET_ACCEPTANCE_CASES[4]), 600000 ); it( - '7. LENDING Arbitrum Sepolia', - () => run(...PRESET_ACCEPTANCE_CASES[6]), - 600000 - ); - it( - '8. LENDING BNB testnet', - () => run(...PRESET_ACCEPTANCE_CASES[7]), + '6. LENDING Arbitrum Sepolia', + () => run(...PRESET_ACCEPTANCE_CASES[5]), 600000 ); - it('9. STAKING Sepolia', () => run(...PRESET_ACCEPTANCE_CASES[8]), 600000); }); diff --git a/packages/core/__e2e__/agw/presets-expanded-live.spec.ts b/packages/core/__e2e__/agw/presets-expanded-live.spec.ts deleted file mode 100644 index 59470e62..00000000 --- a/packages/core/__e2e__/agw/presets-expanded-live.spec.ts +++ /dev/null @@ -1,819 +0,0 @@ -/** Real protocol tests on supported testnets only. All signing uses Donut. - * Destination-only assets are prefunded; generated preset calls/pins are retained. - */ -import { - createPublicClient, - encodeFunctionData, - erc20Abi, - http, - parseAbi, - parseEther, - parseEventLogs, - type Address, - type Hex, -} from 'viem'; -import { PushChain, CHAIN, type Rule } from '../../src'; -import { MOVEABLE_TOKEN_CONSTANTS } from '../../src/lib/constants/tokens'; -import { getNativePRC20ForChain } from '../../src/lib/orchestrator/internals/helpers'; -import { getCEAAddress } from '../../src/lib/orchestrator/cea-utils'; -import { - AGW_E2E_ENABLED, - setupAgw, - evmClient, - inSeconds, - type AgwFixture, -} from './_fixture'; -const d = AGW_E2E_ENABLED ? describe : describe.skip; -const ZERO = BigInt(0), - SMALL = BigInt(10) ** BigInt(12), - MAX_PC = parseEther('20'); -const rpc = { - [CHAIN.ETHEREUM_SEPOLIA]: 'https://ethereum-sepolia-rpc.publicnode.com', - [CHAIN.BASE_SEPOLIA]: 'https://base-sepolia-rpc.publicnode.com', - [CHAIN.ARBITRUM_SEPOLIA]: 'https://arbitrum-sepolia-rpc.publicnode.com', - [CHAIN.BNB_TESTNET]: 'https://bsc-testnet-rpc.publicnode.com', -}; -type Destination = keyof typeof rpc; -type Call = { to: Address; value: bigint; data: Hex }; -const ERC20 = erc20Abi; -const EXECUTED = parseAbi([ - 'event UniversalTxExecuted(bytes32 indexed subTxId, bytes32 indexed universalTxId, address indexed originCaller, address target, bytes data)', -]); -const WETH = parseAbi(['function deposit() payable']); -const AAVE = parseAbi([ - 'function supply(address,uint256,address,uint16)', - 'function withdraw(address,uint256,address) returns(uint256)', -]); -const MARKET = parseAbi([ - 'function mint(uint256) returns(uint256)', - 'function redeemUnderlying(uint256) returns(uint256)', - 'function exchangeRateStored() view returns(uint256)', - 'function balanceOf(address) view returns(uint256)', -]); -const read = (chain: Destination) => - createPublicClient({ transport: http(rpc[chain], { timeout: 20_000 }) }); -const call = (to: Address, data: Hex, value = ZERO): Call => ({ - to, - data, - value, -}); -const approve = (token: Address, spender: Address, amount: bigint) => - call( - token, - encodeFunctionData({ - abi: ERC20, - functionName: 'approve', - args: [spender, amount], - }) - ); -const balance = (chain: Destination, token: Address, owner: Address) => - read(chain).readContract({ - address: token, - abi: ERC20, - functionName: 'balanceOf', - args: [owner], - }); -const preset = ( - category: 'DEXES' | 'LENDING' | 'STAKING', - chain: Destination, - agent: Address, - tokens: { token: Address; maxPerCall: bigint; maxTotal: bigint }[] -): Rule => ({ - ...PushChain.utils.agentic.presets.get(category, { - chainNamespace: chain, - agent, - validUntil: inSeconds(7200), - maxGasPerCall: MAX_PC, - assets: tokens, - }).rules[0], - assets: [], -}); - -async function walletFor( - f: AgwFixture, - chain: Destination, - rule: Rule, - label: string -) { - const { wallet, rulesIds } = await f.owner.agentic.create(label, { - rules: [rule], - }); - const cea = (await getCEAAddress(wallet, chain)).cea as Address; - await f.fundPC(wallet, parseEther('100')); - const owner = await evmClient( - process.env['PUSH_PRIVATE_KEY'] as Hex, - CHAIN.PUSH_TESTNET_DONUT, - f.manifest.network, - wallet - ); - const agent = await f.agent(wallet); - f.evidence('preset-expanded-wallet', { - label, - chain, - wallet, - cea, - rulesId: rulesIds[0], - }); - return { wallet, cea, owner, agent, rulesId: rulesIds[0] }; -} -async function send( - f: AgwFixture, - w: Awaited>, - chain: Destination, - client: PushChain, - calls: Call[], - stage: string, - funds?: { - token: typeof MOVEABLE_TOKEN_CONSTANTS.ETHEREUM_SEPOLIA.ETH; - amount: bigint; - } -) { - const tx = await client.universal.sendTransaction({ - to: { address: calls[0].to, chain }, - data: calls, - gasLimit: BigInt(2_000_000), - ...(funds ? { funds } : {}), - }); - f.evidence('preset-expanded-stage', { - chain, - wallet: w.wallet, - cea: w.cea, - stage: `${stage}-submitted`, - pushTx: tx.hash, - }); - const receipt = await tx.wait(); - expect(receipt.externalTxHash).toBeTruthy(); - const dest = await read(chain).getTransactionReceipt({ - hash: receipt.externalTxHash as Hex, - }); - f.evidence('preset-expanded-stage', { - chain, - wallet: w.wallet, - cea: w.cea, - stage: `${stage}-completed`, - pushTx: tx.hash, - externalTx: receipt.externalTxHash, - status: dest.status, - }); - expect(dest.status).toBe('success'); - const events = parseEventLogs({ abi: EXECUTED, logs: dest.logs }); - for (const c of calls) - expect( - events.some( - (e) => - e.address.toLowerCase() === w.cea.toLowerCase() && - e.args.originCaller.toLowerCase() === w.wallet.toLowerCase() && - e.args.target.toLowerCase() === c.to.toLowerCase() && - e.args.data === c.data - ) - ).toBe(true); - return dest; -} -// Moonwell and Venus use different Redeem event signatures. Require the -// protocol's entire burned-share amount and payout to match the CEA balances. -function assertRedemption( - receipt: Awaited>, - market: Address, - cea: Address, - shares: bigint, - received: bigint -) { - const events = parseEventLogs({ - abi: parseAbi([ - 'event Redeem(address redeemer,uint256 redeemAmount,uint256 redeemTokens)', - 'event Redeem(address redeemer,uint256 redeemAmount,uint256 redeemTokens,uint256 totalSupply)', - ]), - logs: receipt.logs, - }); - const event = events.find( - (e) => - e.address.toLowerCase() === market.toLowerCase() && - e.args.redeemer.toLowerCase() === cea.toLowerCase() - ); - expect(event?.args.redeemTokens).toBe(shares); - expect(event?.args.redeemAmount).toBe(received); -} - -async function underlyingRedemption( - chain: Destination, - market: Address, - shares: bigint, - cap: bigint -) { - const rate = await read(chain).readContract({ - address: market, - abi: MARKET, - functionName: 'exchangeRateStored', - }); - const amount = (shares * rate) / BigInt(10) ** BigInt(18); - const bounded = amount < cap ? amount : cap; - expect(bounded).toBeGreaterThan(ZERO); - return bounded; -} -async function wrap( - f: AgwFixture, - w: Awaited>, - chain: Destination, - token: Address, - amount: bigint -) { - const prc20 = getNativePRC20ForChain(chain, f.manifest.network); - if ( - (await f.push.readContract({ - address: prc20, - abi: ERC20, - functionName: 'balanceOf', - args: [f.ownerAddress], - })) < amount - ) - throw new Error( - `PRESET_PREREQUISITE: master lacks native PRC20 for ${chain}` - ); - await ( - await f.owner.universal.sendTransaction({ - to: prc20, - data: encodeFunctionData({ - abi: ERC20, - functionName: 'transfer', - args: [w.wallet, amount], - }), - }) - ).wait(); - const native = - chain === CHAIN.BNB_TESTNET - ? MOVEABLE_TOKEN_CONSTANTS.BNB_TESTNET.BNB - : chain === CHAIN.BASE_SEPOLIA - ? MOVEABLE_TOKEN_CONSTANTS.BASE_SEPOLIA.ETH - : chain === CHAIN.ARBITRUM_SEPOLIA - ? MOVEABLE_TOKEN_CONSTANTS.ARBITRUM_SEPOLIA.ETH - : MOVEABLE_TOKEN_CONSTANTS.ETHEREUM_SEPOLIA.ETH; - await send( - f, - w, - chain, - w.owner, - [ - call( - token, - encodeFunctionData({ abi: WETH, functionName: 'deposit' }), - amount - ), - ], - 'wrap', - { token: native, amount } - ); - expect(await balance(chain, token, w.cea)).toBe(amount); -} - -d('agw presets expanded', () => { - let f: AgwFixture; - afterEach(() => f?.teardown()); - it('1. EigenLayer Sepolia deposit credits shares to the wallet', async () => { - const chain = CHAIN.ETHEREUM_SEPOLIA; - const manager = '0x2E3D6c0744b10eb0A4e6F679F71554a39Ec47a5D' as Address; - const strategy = '0x424246eF71b01ee33aA33aC590fd9a0855F5eFbc' as Address; - const abi = parseAbi([ - 'function strategyIsWhitelistedForDeposit(address) view returns(bool)', - 'function paused() view returns(uint256)', - 'function depositIntoStrategy(address,address,uint256) returns(uint256)', - 'function stakerDepositShares(address,address) view returns(uint256)', - ]); - expect( - await read(chain).readContract({ - address: manager, - abi, - functionName: 'strategyIsWhitelistedForDeposit', - args: [strategy], - }) - ).toBe(true); - expect( - (await read(chain).readContract({ - address: manager, - abi, - functionName: 'paused', - })) & BigInt(1) - ).toBe(ZERO); - const token = await read(chain).readContract({ - address: strategy, - abi: parseAbi(['function underlyingToken() view returns(address)']), - functionName: 'underlyingToken', - }); - f = await setupAgw(); - const rule = preset('STAKING', chain, f.agentAddress, [ - { token, maxPerCall: SMALL, maxTotal: SMALL }, - ]); - const w = await walletFor(f, chain, rule, 'e2e-preset-eigen'); - await wrap(f, w, chain, token, SMALL); - const before = await read(chain).readContract({ - address: manager, - abi, - functionName: 'stakerDepositShares', - args: [w.cea, strategy], - }); - for (const [inputToken, amount, error] of [ - [token, SMALL + BigInt(1), 'ArgPinAboveMax'], - [strategy, SMALL, 'ArgPinMismatch'], - ] as const) { - await expect( - w.agent.universal.sendTransaction({ - to: { address: manager, chain }, - gasLimit: BigInt(2_000_000), - data: [ - call( - manager, - encodeFunctionData({ - abi, - functionName: 'depositIntoStrategy', - args: [strategy, inputToken, amount], - }) - ), - ], - }) - ).rejects.toMatchObject({ - decodedError: { name: `PolicyCheckReverted(${error})` }, - }); - } - await send( - f, - w, - chain, - w.agent, - [ - approve(token, manager, SMALL), - call( - manager, - encodeFunctionData({ - abi, - functionName: 'depositIntoStrategy', - args: [strategy, token, SMALL], - }) - ), - ], - 'eigen-deposit' - ); - const after = await read(chain).readContract({ - address: manager, - abi, - functionName: 'stakerDepositShares', - args: [w.cea, strategy], - }); - expect(after).toBeGreaterThan(before); - expect(await balance(chain, token, w.cea)).toBe(ZERO); - f.evidence('preset-eigen-live', { - wallet: w.wallet, - cea: w.cea, - strategy, - amount: SMALL, - shares: after - before, - }); - }, 900_000); - const dexCases = [ - { - id: 2, - chain: CHAIN.BASE_SEPOLIA, - wrapped: '0x4200000000000000000000000000000000000006', - output: '0x036CbD53842c5426634e7929541eC2318f3dCF7e', - fee: 3000, - }, - { - id: 3, - chain: CHAIN.ARBITRUM_SEPOLIA, - wrapped: '0x980B62Da83eFf3D4576C647993b0c1D7faf17c73', - output: '0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d', - fee: 3000, - }, - { - id: 4, - chain: CHAIN.BNB_TESTNET, - wrapped: '0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd', - output: '0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c', - fee: 100, - }, - ] as const; - async function dexAndLend({ - chain, - wrapped, - output, - fee, - }: (typeof dexCases)[number]) { - const discovery = PushChain.utils.agentic.presets.get('DEXES', { - chainNamespace: chain, - }).rules[0]; - const router = discovery.allowedCalls[0].target as Address; - const factory = await read(chain).readContract({ - address: router, - abi: parseAbi(['function factory() view returns(address)']), - functionName: 'factory', - }); - const pool = await read(chain).readContract({ - address: factory, - abi: parseAbi([ - 'function getPool(address,address,uint24) view returns(address)', - ]), - functionName: 'getPool', - args: [wrapped, output, fee], - }); - if (/^0x0+$/.test(pool)) - throw new Error(`PRESET_PREREQUISITE: ${chain} pool missing`); - expect( - await read(chain).readContract({ - address: pool, - abi: parseAbi(['function liquidity() view returns(uint128)']), - functionName: 'liquidity', - }) - ).toBeGreaterThan(ZERO); - f = await setupAgw(); - const w = await walletFor( - f, - chain, - preset('DEXES', chain, f.agentAddress, [ - { token: wrapped, maxPerCall: SMALL, maxTotal: SMALL }, - { token: output, maxPerCall: SMALL, maxTotal: SMALL }, - ]), - `e2e-preset-dex-${chain}` - ); - await wrap(f, w, chain, wrapped, SMALL); - const abi = parseAbi([ - 'function exactInputSingle((address tokenIn,address tokenOut,uint24 fee,address recipient,uint256 amountIn,uint256 amountOutMinimum,uint160 sqrtPriceLimitX96)) returns(uint256)', - ]); - const swap = (recipient: Address, amountIn = SMALL) => - call( - router, - encodeFunctionData({ - abi, - functionName: 'exactInputSingle', - args: [ - { - tokenIn: wrapped, - tokenOut: output, - fee, - recipient, - amountIn, - amountOutMinimum: BigInt(1), - sqrtPriceLimitX96: ZERO, - }, - ], - }) - ); - await expect( - w.agent.universal.sendTransaction({ - to: { address: router, chain }, - gasLimit: BigInt(2_000_000), - data: [swap(f.agentAddress)], - }) - ).rejects.toMatchObject({ - decodedError: { name: 'PolicyCheckReverted(ArgPinMismatch)' }, - }); - await expect( - w.agent.universal.sendTransaction({ - to: { address: router, chain }, - gasLimit: BigInt(2_000_000), - data: [swap(w.cea, SMALL + BigInt(1))], - }) - ).rejects.toMatchObject({ - decodedError: { name: 'PolicyCheckReverted(ArgPinAboveMax)' }, - }); - const before = await balance(chain, output, w.cea); - await send( - f, - w, - chain, - w.agent, - [approve(wrapped, router, SMALL), swap(w.cea)], - 'dex-swap' - ); - const received = (await balance(chain, output, w.cea)) - before; - expect(received).toBeGreaterThan(ZERO); - expect(await balance(chain, wrapped, w.cea)).toBe(ZERO); - f.evidence('preset-expanded-dex', { - chain, - wallet: w.wallet, - cea: w.cea, - pool, - router, - amountIn: SMALL, - amountOut: received, - }); - if (chain === CHAIN.BASE_SEPOLIA) return; // its Aave reserve uses a different test token; exercised in case 5. - const rule = preset('LENDING', chain, f.agentAddress, [ - { token: output, maxPerCall: received, maxTotal: received }, - ]); - await f.owner.agentic - .wallet(w.wallet) - .rules.update({ rules: [{ rulesId: w.rulesId, rule }] }); - if (chain === CHAIN.ARBITRUM_SEPOLIA) { - const aave = rule.allowedCalls.find((c) => c.app === 'Aave V3')! - .target as Address; - await send( - f, - w, - chain, - w.agent, - [ - approve(output, aave, received), - call( - aave, - encodeFunctionData({ - abi: AAVE, - functionName: 'supply', - args: [output, received, w.cea, 0], - }) - ), - ], - 'aave-supply' - ); - expect(await balance(chain, output, w.cea)).toBe(before); - await send( - f, - w, - chain, - w.agent, - [ - call( - aave, - encodeFunctionData({ - abi: AAVE, - functionName: 'withdraw', - args: [output, received, w.cea], - }) - ), - ], - 'aave-withdraw' - ); - expect(await balance(chain, output, w.cea)).toBe(before + received); - f.evidence('preset-expanded-aave', { - chain, - wallet: w.wallet, - cea: w.cea, - amount: received, - asset: output, - }); - } else { - const venus = rule.allowedCalls.find((c) => c.app === 'Venus vUSDT')! - .target as Address; - await send( - f, - w, - chain, - w.agent, - [ - approve(output, venus, received), - call( - venus, - encodeFunctionData({ - abi: MARKET, - functionName: 'mint', - args: [received], - }) - ), - ], - 'venus-mint' - ); - const shares = await balance(chain, venus, w.cea); - expect(shares).toBeGreaterThan(ZERO); - expect(await balance(chain, output, w.cea)).toBe(before); - const redeemAmount = await underlyingRedemption( - chain, - venus, - shares, - received - ); - const redemption = await send( - f, - w, - chain, - w.agent, - [ - call( - venus, - encodeFunctionData({ - abi: MARKET, - functionName: 'redeemUnderlying', - args: [redeemAmount], - }) - ), - ], - 'venus-redeem' - ); - const redeemed = (await balance(chain, output, w.cea)) - before; - const remainingShares = await balance(chain, venus, w.cea); - expect(remainingShares).toBeLessThan(shares); - expect(redeemed).toBe(redeemAmount); - assertRedemption( - redemption, - venus, - w.cea, - shares - remainingShares, - redeemed - ); - expect(redeemed).toBeGreaterThanOrEqual( - (received * BigInt(99)) / BigInt(100) - ); - f.evidence('preset-expanded-venus', { - chain, - wallet: w.wallet, - cea: w.cea, - deposited: received, - redeemed, - shares, - remainingShares, - asset: output, - }); - } - } - it('2. DEX swap on eip155:84532', () => dexAndLend(dexCases[0]), 1_200_000); - it( - '3. DEX swap and Aave round trip on eip155:421614', - () => dexAndLend(dexCases[1]), - 1_200_000 - ); - it( - '4. DEX swap and Venus round trip on eip155:97', - () => dexAndLend(dexCases[2]), - 1_200_000 - ); - - it('5. Base Aave and both Moonwell markets supply and redeem wallet positions', async () => { - const chain = CHAIN.BASE_SEPOLIA; - const link = '0x810D46F9a9027E28F9B01F75E2bdde839dA61115' as Address; - const usdbc = '0x4616975f7E6045FD9737e95bC527e9e14c727BD2' as Address; - const weth = '0x663A6F02d547dFd639BF689FED298712f2FB69Fb' as Address; - const faucet = '0xD9145b5F45Ad4519c7ACcD6E0A4A82e83bB8A6Dc' as Address; - const amountUSDBC = BigInt(10_000); - expect(await read(chain).getCode({ address: faucet })).not.toBeUndefined(); - f = await setupAgw(); - const rule = preset('LENDING', chain, f.agentAddress, [ - { token: link, maxPerCall: SMALL, maxTotal: SMALL }, - { token: usdbc, maxPerCall: amountUSDBC, maxTotal: amountUSDBC }, - { token: weth, maxPerCall: SMALL, maxTotal: SMALL }, - ]); - const w = await walletFor(f, chain, rule, 'e2e-preset-base-lending'); - const aave = rule.allowedCalls.find((c) => c.app === 'Aave V3')! - .target as Address; - const mUSDBC = rule.allowedCalls.find((c) => c.app === 'Moonwell mUSDbC')! - .target as Address; - const mWETH = rule.allowedCalls.find((c) => c.app === 'Moonwell mWETH')! - .target as Address; - await send( - f, - w, - chain, - w.owner, - [ - call( - faucet, - encodeFunctionData({ - abi: parseAbi(['function mint(address,address,uint256)']), - functionName: 'mint', - args: [link, w.cea, SMALL], - }) - ), - call( - usdbc, - encodeFunctionData({ - abi: parseAbi(['function allocateTo(address,uint256)']), - functionName: 'allocateTo', - args: [w.cea, amountUSDBC], - }) - ), - call( - weth, - encodeFunctionData({ - abi: parseAbi(['function mint(address,uint256)']), - functionName: 'mint', - args: [w.cea, SMALL], - }) - ), - ], - 'faucets' - ); - expect(await balance(chain, link, w.cea)).toBe(SMALL); - expect(await balance(chain, usdbc, w.cea)).toBe(amountUSDBC); - expect(await balance(chain, weth, w.cea)).toBe(SMALL); - await send( - f, - w, - chain, - w.agent, - [ - approve(link, aave, SMALL), - call( - aave, - encodeFunctionData({ - abi: AAVE, - functionName: 'supply', - args: [link, SMALL, w.cea, 0], - }) - ), - approve(usdbc, mUSDBC, amountUSDBC), - call( - mUSDBC, - encodeFunctionData({ - abi: MARKET, - functionName: 'mint', - args: [amountUSDBC], - }) - ), - approve(weth, mWETH, SMALL), - call( - mWETH, - encodeFunctionData({ - abi: MARKET, - functionName: 'mint', - args: [SMALL], - }) - ), - ], - 'lending-supply' - ); - const sharesUSDBC = await balance(chain, mUSDBC, w.cea), - sharesWETH = await balance(chain, mWETH, w.cea); - expect(sharesUSDBC).toBeGreaterThan(ZERO); - expect(sharesWETH).toBeGreaterThan(ZERO); - expect(await balance(chain, link, w.cea)).toBe(ZERO); - expect(await balance(chain, usdbc, w.cea)).toBe(ZERO); - expect(await balance(chain, weth, w.cea)).toBe(ZERO); - const redeemUSDBC = await underlyingRedemption( - chain, - mUSDBC, - sharesUSDBC, - amountUSDBC - ); - const redeemWETH = await underlyingRedemption( - chain, - mWETH, - sharesWETH, - SMALL - ); - const redemption = await send( - f, - w, - chain, - w.agent, - [ - call( - aave, - encodeFunctionData({ - abi: AAVE, - functionName: 'withdraw', - args: [link, SMALL, w.cea], - }) - ), - call( - mUSDBC, - encodeFunctionData({ - abi: MARKET, - functionName: 'redeemUnderlying', - args: [redeemUSDBC], - }) - ), - call( - mWETH, - encodeFunctionData({ - abi: MARKET, - functionName: 'redeemUnderlying', - args: [redeemWETH], - }) - ), - ], - 'lending-withdraw' - ); - expect(await balance(chain, link, w.cea)).toBe(SMALL); - expect(await balance(chain, usdbc, w.cea)).toBeGreaterThanOrEqual( - (amountUSDBC * BigInt(99)) / BigInt(100) - ); - expect(await balance(chain, weth, w.cea)).toBeGreaterThanOrEqual( - (SMALL * BigInt(99)) / BigInt(100) - ); - const remainingUSDBC = await balance(chain, mUSDBC, w.cea), - remainingWETH = await balance(chain, mWETH, w.cea); - expect(remainingUSDBC).toBeLessThan(sharesUSDBC); - expect(remainingWETH).toBeLessThan(sharesWETH); - expect(await balance(chain, usdbc, w.cea)).toBe(redeemUSDBC); - expect(await balance(chain, weth, w.cea)).toBe(redeemWETH); - assertRedemption( - redemption, - mUSDBC, - w.cea, - sharesUSDBC - remainingUSDBC, - await balance(chain, usdbc, w.cea) - ); - assertRedemption( - redemption, - mWETH, - w.cea, - sharesWETH - remainingWETH, - await balance(chain, weth, w.cea) - ); - f.evidence('preset-expanded-base-lending', { - chain, - wallet: w.wallet, - cea: w.cea, - link: SMALL, - usdbc: amountUSDBC, - weth: SMALL, - sharesUSDBC, - sharesWETH, - }); - }, 1_200_000); -}); diff --git a/packages/core/__e2e__/agw/presets-live.spec.ts b/packages/core/__e2e__/agw/presets-live.spec.ts deleted file mode 100644 index ae685f1f..00000000 --- a/packages/core/__e2e__/agw/presets-live.spec.ts +++ /dev/null @@ -1,556 +0,0 @@ -/** Real Donut -> Sepolia preset execution. No mainnet transactions. - * Destination WETH/Circle USDC are intentionally prefunded, not bridged assets: - * those two tokens have no usable SDK PRC20 pair. Generated call pins are unchanged. - */ -import { - createPublicClient, - encodeFunctionData, - erc20Abi, - http, - parseAbi, - parseEther, - parseEventLogs, - type Address, - type Hex, -} from 'viem'; -import { sepolia } from 'viem/chains'; -import { PushChain, CHAIN } from '../../src'; -import { MOVEABLE_TOKEN_CONSTANTS } from '../../src/lib/constants/tokens'; -import { getNativePRC20ForChain } from '../../src/lib/orchestrator/internals/helpers'; -import { getCEAAddress } from '../../src/lib/orchestrator/cea-utils'; -import { - AGW_E2E_ENABLED, - setupAgw, - evmClient, - inSeconds, - type AgwFixture, -} from './_fixture'; - -const d = AGW_E2E_ENABLED ? describe : describe.skip; -const WETH = '0xfff9976782d46cc05630d1f6ebab18b2324d6b14' as Address; -const USDC = '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238' as Address; -const FACTORY = '0x0227628f3F023bb0B980b67D528571c95c6DaC1c' as Address; -const AMOUNT = BigInt(10) ** BigInt(12); -const MAX_PC = parseEther('20'); -const SWAP = parseAbi([ - 'function exactInputSingle((address tokenIn,address tokenOut,uint24 fee,address recipient,uint256 amountIn,uint256 amountOutMinimum,uint160 sqrtPriceLimitX96)) returns(uint256)', -]); -const EXECUTED = parseAbi([ - 'event UniversalTxExecuted(bytes32 indexed subTxId, bytes32 indexed universalTxId, address indexed originCaller, address target, bytes data)', -]); -const sep = createPublicClient({ - chain: sepolia, - transport: http('https://ethereum-sepolia-rpc.publicnode.com'), -}); - -d('agw presets live', () => { - let f: AgwFixture; - afterAll(() => f?.teardown()); - it('1. Uniswap preset swaps from the wallet CEA and rejects a different recipient', async () => { - // Read-only protocol prerequisites run before any funding. - const block = await sep.getBlockNumber(); - const pool = await sep.readContract({ - address: FACTORY, - abi: parseAbi([ - 'function getPool(address,address,uint24) view returns(address)', - ]), - functionName: 'getPool', - args: [WETH, USDC, 500], - blockNumber: block, - }); - if (/^0x0+$/.test(pool)) - throw new Error( - 'PRESET_PREREQUISITE: Sepolia WETH/Circle USDC pool is absent' - ); - const liquidity = await sep.readContract({ - address: pool, - abi: parseAbi(['function liquidity() view returns(uint128)']), - functionName: 'liquidity', - blockNumber: block, - }); - if (!liquidity) - throw new Error( - 'PRESET_PREREQUISITE: Sepolia pool has no active liquidity' - ); - f = await setupAgw(); - const defaults = PushChain.utils.agentic.presets.get('DEXES', { - chainNamespace: CHAIN.ETHEREUM_SEPOLIA, - agent: f.agentAddress, - }); - expect(defaults.readiness.chains[0].configurationReady).toBe(true); - expect(defaults.rules[0].maxGasPerCall).toBe(MAX_PC); - expect(defaults.rules[0].validUntil).toBeGreaterThan(inSeconds(6 * 86400)); - expect( - defaults.readiness.chains[0].selectedAssets.map((a) => - a.token.toString().toLowerCase() - ) - ).toEqual([WETH.toLowerCase(), USDC.toLowerCase()]); - expect( - defaults.readiness.chains[0].selectedAssets.every( - (a) => a.maxPerCall > BigInt(0) - ) - ).toBe(true); - const { rules } = PushChain.utils.agentic.presets.get('DEXES', { - chainNamespace: CHAIN.ETHEREUM_SEPOLIA, - agent: f.agentAddress, - validUntil: inSeconds(3600), - maxGasPerCall: MAX_PC, - assets: [ - { token: WETH, maxPerCall: AMOUNT, maxTotal: AMOUNT * BigInt(2) }, - { - token: USDC, - maxPerCall: BigInt(1_000_000), - maxTotal: BigInt(2_000_000), - }, - ], - }); - // assets[] budgets bridge burns on Push. This test spends already-held CEA - // tokens, so omit bridge assets without changing any generated call or pin. - // Prefunded CEA fixture: bypass bridge budgets only in this protocol test. - const { wallet, rulesIds } = await f.owner.agentic.create( - 'e2e-preset-uniswap', - { rules: rules.map((rule) => ({ ...rule, assets: [] })) } - ); - const cea = (await getCEAAddress(wallet, CHAIN.ETHEREUM_SEPOLIA)) - .cea as Address; - const router = rules[0].allowedCalls[0].target as Address; - await f.fundPC(wallet, parseEther('65')); - const peth = getNativePRC20ForChain( - CHAIN.ETHEREUM_SEPOLIA, - f.manifest.network - ); - await ( - await f.owner.universal.sendTransaction({ - to: peth, - data: encodeFunctionData({ - abi: erc20Abi, - functionName: 'transfer', - args: [wallet, AMOUNT * BigInt(2)], - }), - }) - ).wait(); - const owner = await evmClient( - process.env['PUSH_PRIVATE_KEY'] as Hex, - CHAIN.PUSH_TESTNET_DONUT, - f.manifest.network, - wallet - ); - const wrap = await owner.universal.sendTransaction({ - to: { address: WETH, chain: CHAIN.ETHEREUM_SEPOLIA }, - data: [ - { - to: WETH, - value: AMOUNT * BigInt(2), - data: encodeFunctionData({ - abi: parseAbi(['function deposit() payable']), - functionName: 'deposit', - }), - }, - ], - funds: { - token: MOVEABLE_TOKEN_CONSTANTS.ETHEREUM_SEPOLIA.ETH, - amount: AMOUNT * BigInt(2), - }, - gasLimit: BigInt(2_000_000), - }); - const wrapped = await wrap.wait(); - expect(wrapped.externalTxHash).toBeTruthy(); - expect( - (await sep.getTransactionReceipt({ hash: wrapped.externalTxHash as Hex })) - .status - ).toBe('success'); - const balance = (token: Address) => - sep.readContract({ - address: token, - abi: erc20Abi, - functionName: 'balanceOf', - args: [cea], - }); - expect(await balance(WETH)).toBe(AMOUNT * BigInt(2)); - const before = await balance(USDC); - const agent = await f.agent(wallet); - const swap = (recipient: Address) => - encodeFunctionData({ - abi: SWAP, - functionName: 'exactInputSingle', - args: [ - { - tokenIn: WETH, - tokenOut: USDC, - fee: 500, - recipient, - amountIn: AMOUNT, - amountOutMinimum: BigInt(1), - sqrtPriceLimitX96: BigInt(0), - }, - ], - }); - await expect( - agent.universal.sendTransaction({ - to: { address: router, chain: CHAIN.ETHEREUM_SEPOLIA }, - data: [{ to: router, value: BigInt(0), data: swap(f.agentAddress) }], - gasLimit: BigInt(700_000), - }) - ).rejects.toMatchObject({ - decodedError: { name: 'PolicyCheckReverted(ArgPinMismatch)' }, - }); - const tx = await agent.universal.sendTransaction({ - to: { address: router, chain: CHAIN.ETHEREUM_SEPOLIA }, - gasLimit: BigInt(700_000), - data: [ - { - to: WETH, - value: BigInt(0), - data: encodeFunctionData({ - abi: erc20Abi, - functionName: 'approve', - args: [router, AMOUNT], - }), - }, - { to: router, value: BigInt(0), data: swap(cea) }, - ], - }); - const receipt = await tx.wait(); - expect(receipt.externalTxHash).toBeTruthy(); - const dest = await sep.getTransactionReceipt({ - hash: receipt.externalTxHash as Hex, - }); - expect(dest.status).toBe('success'); - expect(await balance(WETH)).toBe(AMOUNT); - const after = await balance(USDC); - expect(after).toBeGreaterThan(before); - expect( - parseEventLogs({ abi: EXECUTED, logs: dest.logs }).some( - (e) => - e.address.toLowerCase() === cea.toLowerCase() && - e.args.originCaller.toLowerCase() === wallet.toLowerCase() && - e.args.target.toLowerCase() === router.toLowerCase() && - e.args.data === swap(cea) - ) - ).toBe(true); - f.evidence('preset-uniswap-live', { - wallet, - cea, - rulesId: rulesIds[0], - pool, - prerequisiteBlock: block, - wrapTx: wrap.hash, - wrapExternal: wrapped.externalTxHash, - pushTx: tx.hash, - externalTx: receipt.externalTxHash, - amountIn: AMOUNT, - amountOut: after - before, - }); - }, 900_000); - it('2. Aave preset supplies and withdraws the wallet position', async () => { - const mockLINK = '0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5' as Address; - const faucet = '0xC959483DBa39aa9E78757139af0e9a2EDEb3f42D' as Address; - const amount = BigInt(10) ** BigInt(12); - const faucetAbi = parseAbi(['function mint(address,address,uint256)']); - // Testnet USDC/DAI/USDT supply caps are exhausted; use faucet LINK. - // Mock LINK is a destination-only asset, not an SDK bridge token. - await sep.simulateContract({ - address: faucet, - abi: faucetAbi, - functionName: 'mint', - args: [mockLINK, '0x0000000000000000000000000000000000001234', amount], - account: '0x0000000000000000000000000000000000001234', - }); - const readinessPool = PushChain.utils.agentic.presets.get('LENDING', { - chainNamespace: CHAIN.ETHEREUM_SEPOLIA, - }).rules[0].allowedCalls[0].target as Address; - // Fail before funding if protocol gates (cap, pause, freeze) reject supply. - // An unfunded probe reaching token transfer is the expected result. - let readiness = ''; - try { - await sep.simulateContract({ - address: readinessPool, - abi: parseAbi(['function supply(address,uint256,address,uint16)']), - functionName: 'supply', - args: [ - mockLINK, - amount, - '0x0000000000000000000000000000000000001234', - 0, - ], - account: '0x0000000000000000000000000000000000001234', - }); - } catch (error) { - readiness = String( - (error as { shortMessage?: string }).shortMessage ?? error - ); - } - if (!readiness.includes('transfer amount exceeds balance')) - throw new Error( - `PRESET_PREREQUISITE: Aave reserve rejected unfunded supply probe: ${readiness}` - ); - f?.teardown(); - f = await setupAgw(); - const defaults = PushChain.utils.agentic.presets.get('LENDING', { - chainNamespace: CHAIN.ETHEREUM_SEPOLIA, - agent: f.agentAddress, - }); - expect(defaults.readiness.chains[0].configurationReady).toBe(true); - expect(defaults.readiness.chains[0].selectedAssets[0].maxPerCall).toBe( - parseEther('1') - ); - expect(defaults.rules[0].maxGasPerCall).toBe(MAX_PC); - expect( - defaults.readiness.chains[0].selectedAssets.map((a) => - a.token.toString().toLowerCase() - ) - ).toEqual([mockLINK.toLowerCase()]); - const { rules } = PushChain.utils.agentic.presets.get('LENDING', { - chainNamespace: CHAIN.ETHEREUM_SEPOLIA, - agent: f.agentAddress, - validUntil: inSeconds(3600), - maxGasPerCall: MAX_PC, - assets: defaults.readiness.chains[0].selectedAssets.map((a) => ({ - ...a, - maxPerCall: amount, - maxTotal: amount, - })), - }); - // Prefunded CEA fixture: bypass bridge budgets only in this protocol test. - const { wallet, rulesIds } = await f.owner.agentic.create( - 'e2e-preset-aave', - { rules: rules.map((rule) => ({ ...rule, assets: [] })) } - ); - const cea = (await getCEAAddress(wallet, CHAIN.ETHEREUM_SEPOLIA)) - .cea as Address; - const pool = rules[0].allowedCalls[0].target as Address; - await f.fundPC(wallet, parseEther('65')); - const owner = await evmClient( - process.env['PUSH_PRIVATE_KEY'] as Hex, - CHAIN.PUSH_TESTNET_DONUT, - f.manifest.network, - wallet - ); - const mint = await owner.universal.sendTransaction({ - to: { address: faucet, chain: CHAIN.ETHEREUM_SEPOLIA }, - gasLimit: BigInt(2_000_000), - data: [ - { - to: faucet, - value: BigInt(0), - data: encodeFunctionData({ - abi: faucetAbi, - functionName: 'mint', - args: [mockLINK, cea, amount], - }), - }, - ], - }); - f.evidence('preset-aave-stage', { - stage: 'mint-submitted', - wallet, - cea, - pushTx: mint.hash, - }); - const minted = await mint.wait(); - f.evidence('preset-aave-stage', { - stage: 'mint-completed', - wallet, - cea, - externalTx: minted.externalTxHash, - }); - expect( - (await sep.getTransactionReceipt({ hash: minted.externalTxHash as Hex })) - .status - ).toBe('success'); - const balance = () => - sep.readContract({ - address: mockLINK, - abi: erc20Abi, - functionName: 'balanceOf', - args: [cea], - }); - expect(await balance()).toBe(amount); - const abi = parseAbi([ - 'function supply(address,uint256,address,uint16)', - 'function withdraw(address,uint256,address) returns(uint256)', - 'event Supply(address indexed reserve,address user,address indexed onBehalfOf,uint256 amount,uint16 indexed referralCode)', - 'event Withdraw(address indexed reserve,address indexed user,address indexed to,uint256 amount)', - ]); - const agent = await f.agent(wallet); - const supplyData = encodeFunctionData({ - abi, - functionName: 'supply', - args: [mockLINK, amount, cea, 0], - }); - await expect( - agent.universal.sendTransaction({ - to: { address: pool, chain: CHAIN.ETHEREUM_SEPOLIA }, - gasLimit: BigInt(900_000), - data: [ - { - to: pool, - value: BigInt(0), - data: encodeFunctionData({ - abi, - functionName: 'supply', - args: [mockLINK, amount + BigInt(1), cea, 0], - }), - }, - ], - }) - ).rejects.toMatchObject({ - decodedError: { name: 'PolicyCheckReverted(ArgPinAboveMax)' }, - }); - const supply = await agent.universal.sendTransaction({ - to: { address: pool, chain: CHAIN.ETHEREUM_SEPOLIA }, - gasLimit: BigInt(900_000), - data: [ - { - to: mockLINK, - value: BigInt(0), - data: encodeFunctionData({ - abi: erc20Abi, - functionName: 'approve', - args: [pool, amount], - }), - }, - { to: pool, value: BigInt(0), data: supplyData }, - ], - }); - f.evidence('preset-aave-stage', { - stage: 'supply-submitted', - wallet, - cea, - pushTx: supply.hash, - }); - const supplied = await supply.wait(); - f.evidence('preset-aave-stage', { - stage: 'supply-completed', - wallet, - cea, - externalTx: supplied.externalTxHash, - }); - const supplyReceipt = await sep.getTransactionReceipt({ - hash: supplied.externalTxHash as Hex, - }); - expect(supplyReceipt.status).toBe('success'); - expect(await balance()).toBe(BigInt(0)); - const events = parseEventLogs({ - abi, - eventName: 'Supply', - logs: supplyReceipt.logs, - }); - expect( - events.some( - (e) => - e.address.toLowerCase() === pool.toLowerCase() && - e.args.user.toLowerCase() === cea.toLowerCase() && - e.args.onBehalfOf.toLowerCase() === cea.toLowerCase() && - e.args.amount === amount - ) - ).toBe(true); - const half = amount / BigInt(2); - const regenerated = PushChain.utils.agentic.presets.get('LENDING', { - chainNamespace: CHAIN.ETHEREUM_SEPOLIA, - agent: f.agentAddress, - validUntil: inSeconds(3600), - maxGasPerCall: MAX_PC, - assets: [{ token: mockLINK, maxPerCall: half, maxTotal: amount }], - }); - expect(regenerated.readiness.chains[0].configurationReady).toBe(true); - const changed = await f.owner.agentic.wallet(wallet).rules.update({ - rules: [ - { - rulesId: rulesIds[0], - rule: { ...regenerated.rules[0], assets: [] }, - }, - ], - }); - await expect( - agent.universal.sendTransaction({ - to: { address: pool, chain: CHAIN.ETHEREUM_SEPOLIA }, - gasLimit: BigInt(900_000), - data: [ - { - to: pool, - value: BigInt(0), - data: encodeFunctionData({ - abi, - functionName: 'withdraw', - args: [mockLINK, amount, cea], - }), - }, - ], - }) - ).rejects.toMatchObject({ - decodedError: { name: 'PolicyCheckReverted(ArgPinAboveMax)' }, - }); - // The cap applies to each allowed call, not their aggregate in a batch. - const withdraw = await agent.universal.sendTransaction({ - to: { address: pool, chain: CHAIN.ETHEREUM_SEPOLIA }, - gasLimit: BigInt(900_000), - data: [0, 1].map(() => ({ - to: pool, - value: BigInt(0), - data: encodeFunctionData({ - abi, - functionName: 'withdraw', - args: [mockLINK, half, cea], - }), - })), - }); - f.evidence('preset-aave-stage', { - stage: 'withdraw-submitted', - wallet, - cea, - pushTx: withdraw.hash, - }); - const withdrawn = await withdraw.wait(); - f.evidence('preset-aave-stage', { - stage: 'withdraw-completed', - wallet, - cea, - externalTx: withdrawn.externalTxHash, - }); - const withdrawalReceipt = await sep.getTransactionReceipt({ - hash: withdrawn.externalTxHash as Hex, - }); - expect(withdrawalReceipt.status).toBe('success'); - expect(await balance()).toBe(amount); - const withdrawals = parseEventLogs({ - abi, - eventName: 'Withdraw', - logs: withdrawalReceipt.logs, - }).filter( - (e) => - e.address.toLowerCase() === pool.toLowerCase() && - e.args.user.toLowerCase() === cea.toLowerCase() && - e.args.to.toLowerCase() === cea.toLowerCase() - ); - expect(withdrawals).toHaveLength(2); - expect(withdrawals.every((e) => e.args.amount === half)).toBe(true); - expect(withdrawals.reduce((sum, e) => sum + e.args.amount, BigInt(0))).toBe( - amount - ); - f.evidence('preset-limits-regeneration-live', { - wallet, - cea, - oldRulesId: rulesIds[0], - newRulesId: changed.rules[0].rulesId, - oldCap: amount, - newCap: half, - rejectedAboveCap: true, - destinationTx: withdrawn.externalTxHash, - }); - f.evidence('preset-aave-live', { - wallet, - cea, - rulesId: rulesIds[0], - mockLINK, - pool, - mintTx: mint.hash, - mintExternal: minted.externalTxHash, - supplyTx: supply.hash, - supplyExternal: supplied.externalTxHash, - withdrawTx: withdraw.hash, - withdrawExternal: withdrawn.externalTxHash, - amount, - }); - }, 900_000); -}); diff --git a/packages/core/__e2e__/agw/tokens-only-live.spec.ts b/packages/core/__e2e__/agw/tokens-only-live.spec.ts new file mode 100644 index 00000000..386dcd3b --- /dev/null +++ b/packages/core/__e2e__/agw/tokens-only-live.spec.ts @@ -0,0 +1,220 @@ +/** Live tokens-only rules and MOVEABLE ALL (Harsh/Zaryab decisions, 2026-10-23). + * 1: a rule with Circle USDC and no app lets the agent transfer it back to the + * owner on Sepolia; another recipient is refused before broadcast. + * 2: ALL expands on create and reads back every routable token with defaults. + */ +import '@e2e/shared/setup'; +import { + createPublicClient, + http, + encodeFunctionData, + erc20Abi, + getAddress, + parseEther, + zeroAddress, + type Hex, +} from 'viem'; +import { CHAIN, PushChain } from '../../src'; +import { PUSH_NETWORK } from '../../src/lib/constants/enums'; +import { exactAgenticRoutes } from '../../src/lib/agentic/token-routes'; +import { AGW_E2E_ENABLED, inSeconds, setupAgw } from './_fixture'; + +const d = AGW_E2E_ENABLED ? describe : describe.skip; +const AMOUNT = BigInt(10_000); // 0.01 USDC +const SEPOLIA_RPC = 'https://ethereum-sepolia-rpc.publicnode.com'; +const OTHER = getAddress('0x000000000000000000000000000000000000dEaD'); + +d('agw tokens-only live', () => { + it('1. Sepolia Circle USDC goes back to the owner only', async () => { + const [route] = exactAgenticRoutes( + CHAIN.ETHEREUM_SEPOLIA, + PUSH_NETWORK.TESTNET_DONUT + ); + const rpc = createPublicClient({ + transport: http(SEPOLIA_RPC, { timeout: 15000, retryCount: 1 }), + }); + const f = await setupAgw({ deferAgentFunding: true }); + try { + if ( + (await f.push.readContract({ + address: route.prc20, + abi: erc20Abi, + functionName: 'balanceOf', + args: [f.ownerAddress], + })) < + AMOUNT * BigInt(2) + ) + throw new Error(`TOKENS_ONLY_PREREQUISITE: owner lacks ${route.prc20}`); + await f.fundAgent(); + const made = await f.owner.agentic.create('tokens-only', { + rules: [ + { + agent: f.agentAddress, + chainNamespace: CHAIN.ETHEREUM_SEPOLIA, + validUntil: inSeconds(3600), + assets: [ + { + token: route.source, + maxPerCall: AMOUNT, + maxTotal: AMOUNT * BigInt(2), + }, + ], + maxGasPerCall: parseEther('20'), + }, + ], + }); + const record = await f.owner.agentic + .wallet(made.wallet) + .rules.get(made.rulesIds[0]); + if (!('allowedCalls' in record.rule)) + throw new Error('Expected an EVM rule'); + expect(record.rule.allowedCalls).toEqual([ + { + target: getAddress(route.source), + selector: '0xa9059cbb', + maxValue: BigInt(0), + pins: [ + { + arg: 0, + expected: `0x${f.ownerAddress + .slice(2) + .padStart(64, '0')}`.toLowerCase(), + }, + { arg: 1, max: AMOUNT }, + ], + }, + ]); + f.evidence('tokens-only-created', { + wallet: made.wallet, + hash: made.tx.hash, + }); + await f.fundPC(made.wallet, parseEther('25')); + await ( + await f.owner.universal.sendTransaction({ + to: route.prc20, + data: encodeFunctionData({ + abi: erc20Abi, + functionName: 'transfer', + args: [made.wallet, AMOUNT * BigInt(2)], + }), + }) + ).wait(); + const agent = await f.agent(made.wallet); + const send = (to: `0x${string}`) => + agent.universal.sendTransaction({ + to: { chain: CHAIN.ETHEREUM_SEPOLIA, address: route.source }, + funds: { + amount: AMOUNT, + token: { + symbol: route.symbol, + decimals: route.decimals, + address: route.source, + mechanism: 'approve', + }, + }, + data: [ + { + to: route.source, + value: BigInt(0), + data: encodeFunctionData({ + abi: erc20Abi, + functionName: 'transfer', + args: [to, AMOUNT], + }), + }, + ], + }); + // Refused by the policy simulation, so nothing is spent. + await expect(send(OTHER)).rejects.toMatchObject({ + decodedError: { name: 'PolicyCheckReverted(ArgPinMismatch)' }, + }); + const delivered = () => + rpc.readContract({ + address: route.source, + abi: erc20Abi, + functionName: 'balanceOf', + args: [f.ownerAddress], + }); + const before = await delivered(); + const tx = await send(f.ownerAddress); + f.evidence('tokens-only-submitted', { + wallet: made.wallet, + hash: tx.hash, + }); + const receipt = await tx.wait({ outboundTimeoutMs: 180000 }); + expect(receipt.externalStatus).toBe('success'); + const dest = await rpc.getTransactionReceipt({ + hash: receipt.externalTxHash as Hex, + }); + expect(dest.status).toBe('success'); + expect(await delivered()).toBe(before + AMOUNT); + const after = await f.owner.agentic + .wallet(made.wallet) + .rules.get(made.rulesIds[0]); + if (after.spent?.kind !== 'universal') + throw new Error('Missing universal spend'); + expect(after.spent.assets[0].spent).toBe(AMOUNT); + f.evidence('tokens-only-delivered', { + hash: tx.hash, + destinationHash: receipt.externalTxHash, + destinationGasUsed: dest.gasUsed, + }); + } finally { + f.teardown(); + } + }, 600000); + + it('2. ALL expands on create to every routable Sepolia token', async () => { + const f = await setupAgw({ deferAgentFunding: true }); + try { + const expected = PushChain.utils.agentic.assets.all( + CHAIN.ETHEREUM_SEPOLIA + ); + const made = await f.owner.agentic.create('all-tokens', { + rules: [ + { + agent: f.agentAddress, + chainNamespace: CHAIN.ETHEREUM_SEPOLIA, + validUntil: inSeconds(3600), + assets: [ + { + token: PushChain.CONSTANTS.MOVEABLE.TOKEN.ETHEREUM_SEPOLIA.ALL, + }, + ], + maxGasPerCall: parseEther('20'), + allowedCalls: [ + { + target: '0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14', + selector: 'deposit()', + maxValue: BigInt(1), + }, + ], + }, + ], + }); + const record = await f.owner.agentic + .wallet(made.wallet) + .rules.get(made.rulesIds[0]); + if (!('allowedCalls' in record.rule)) + throw new Error('Expected an EVM rule'); + expect(record.rule.assets).toEqual( + expected.map((a) => ({ + token: getAddress( + typeof a.token === 'string' ? a.token : a.token.address + ), + maxPerCall: a.maxPerCall, + maxTotal: a.maxTotal, + })) + ); + expect(record.rule.assets).toHaveLength(6); + expect(record.rule.assets![0].token).toBe(zeroAddress); + f.evidence('all-tokens-created', { + wallet: made.wallet, + hash: made.tx.hash, + assets: record.rule.assets, + }); + } finally { + f.teardown(); + } + }, 600000); +}); diff --git a/packages/core/__e2e__/ci/preflight.ts b/packages/core/__e2e__/ci/preflight.ts index 208c594a..cb315df9 100644 --- a/packages/core/__e2e__/ci/preflight.ts +++ b/packages/core/__e2e__/ci/preflight.ts @@ -352,16 +352,12 @@ function renderTable(rows: Row[]): void { if (presetCases.length) { const { PRESET_ACCEPTANCE_CASES } = await import('../shared/agw-preset-acceptance'); // Only the selected cases; their ids end in the spec's case number. - const selected = presetCases.map((n) => { + for (const n of presetCases) { const entry = PRESET_ACCEPTANCE_CASES[n - 1]; if (!entry) throw new Error(`Unknown preset acceptance case ${n}`); - return entry; - }); - const blocked = selected.flatMap(([category, chainNamespace]) => { - const result = PushChain.utils.agentic.presets.get(category, { chainNamespace, agent: '0x0000000000000000000000000000000000005678' }); - return result.readiness.ready ? [] : [{ category, chainNamespace, issues: result.readiness.chains[0].issues }]; - }); - if (blocked.length) throw new Error(`PRESET_BLOCKED_BEFORE_FUNDING: ${JSON.stringify(blocked)}`); + // Every shipped preset is routable; get throws if its catalog entry is gone. + PushChain.utils.agentic.presets.get(entry[0], { chainNamespace: entry[1] }); + } } if (scenarios.some((s) => s.group === 'agw-svm-wire' || s.group === 'agw-svm-agent-spl' || s.file === '__e2e__/agw/svm-public.spec.ts')) { const { inspectSvmWirePrograms, svmWireConnection } = await import('../shared/agw-svm-preflight'); diff --git a/packages/core/__e2e__/ci/suite.ts b/packages/core/__e2e__/ci/suite.ts index a95d9154..41f04e17 100644 --- a/packages/core/__e2e__/ci/suite.ts +++ b/packages/core/__e2e__/ci/suite.ts @@ -37,11 +37,9 @@ export const GROUPS = [ 'agw', 'agw-svm-wire', 'agw-svm-replay', - 'agw-presets', - 'agw-presets-expanded', 'agw-presets-acceptance', - 'agw-presets-routed', 'agw-exact-routes', + 'agw-tokens-only', 'agw-svm-memo', 'agw-svm-agent-spl', 'agw-gas', @@ -1002,64 +1000,14 @@ export const SCENARIOS: Scenario[] = [ needs: { masterPC: '0.5' }, env: { AGW_E2E: '1' }, }, - { - id: 'agw-preset-eigen-sepolia', - group: 'agw-presets-expanded', - file: '__e2e__/agw/presets-expanded-live.spec.ts', - grep: 'agw presets expanded 1', - needs: { masterPC: '110', masterPETH: '0.000001' }, - env: { AGW_E2E: '1' }, - }, - { - id: 'agw-preset-dex-base', - group: 'agw-presets-expanded', - file: '__e2e__/agw/presets-expanded-live.spec.ts', - grep: 'agw presets expanded 2', - needs: { masterPC: '110' }, - env: { AGW_E2E: '1' }, - }, - { - id: 'agw-preset-dex-aave-arbitrum', - group: 'agw-presets-expanded', - file: '__e2e__/agw/presets-expanded-live.spec.ts', - grep: 'agw presets expanded 3', - needs: { masterPC: '110' }, - env: { AGW_E2E: '1' }, - }, - { - id: 'agw-preset-dex-venus-bnb', - group: 'agw-presets-expanded', - file: '__e2e__/agw/presets-expanded-live.spec.ts', - grep: 'agw presets expanded 4', - needs: { masterPC: '110' }, - env: { AGW_E2E: '1' }, - }, - { - id: 'agw-preset-base-aave-moonwell', - group: 'agw-presets-expanded', - file: '__e2e__/agw/presets-expanded-live.spec.ts', - grep: 'agw presets expanded 5', - needs: { masterPC: '110' }, - env: { AGW_E2E: '1' }, - }, - ...Array.from({ length: 9 }, (_, i) => ({ + ...Array.from({ length: 6 }, (_, i) => ({ id: `agw-unchanged-preset-${i + 1}`, group: 'agw-presets-acceptance' as const, file: '__e2e__/agw/presets-acceptance.spec.ts', grep: `agw unchanged preset acceptance ${i + 1}\\.`, needs: { masterPC: '55' }, env: { AGW_E2E: '1' }, - note: 'Exact public defaults; unavailable routes fail before funding. Exact default PRC20 funds are checked in the scenario.', - })), - // The subset whose default assets all have registered routes (case numbers above). - ...[1, 7].map((n) => ({ - id: `agw-routed-preset-${n}`, - group: 'agw-presets-routed' as const, - file: '__e2e__/agw/presets-acceptance.spec.ts', - grep: `agw unchanged preset acceptance ${n}\\.`, - needs: { masterPC: '55' }, - env: { AGW_E2E: '1' }, - note: 'DEXES Sepolia and LENDING Arbitrum Sepolia; the owner must hold the exact default PRC20s.', + note: 'Exact public defaults: the owner sends 2 bounded ETH amounts as the chain gas PRC20, and the agent wraps and uses them.', })), ...Array.from({ length: 4 }, (_, i) => ({ id: `agw-evm-gas-${i + 1}`, @@ -1079,6 +1027,24 @@ export const SCENARIOS: Scenario[] = [ env: { AGW_E2E: '1' }, note: `${name} Circle USDC node route; the owner must hold its exact PRC20.`, })), + { + id: 'agw-tokens-only-owner', + group: 'agw-tokens-only', + file: '__e2e__/agw/tokens-only-live.spec.ts', + grep: 'agw tokens-only live 1\\.', + needs: { masterPC: '30' }, + env: { AGW_E2E: '1' }, + note: 'Sepolia Circle USDC back to the owner; the owner must hold its exact PRC20.', + }, + { + id: 'agw-tokens-only-all', + group: 'agw-tokens-only', + file: '__e2e__/agw/tokens-only-live.spec.ts', + grep: 'agw tokens-only live 2\\.', + needs: { masterPC: '2' }, + env: { AGW_E2E: '1' }, + note: 'Create only: MOVEABLE ALL expands to every routable Sepolia token.', + }, ...[1, 2].map((n) => ({ id: `agw-svm-memo-${n}`, group: 'agw-svm-memo' as const, @@ -1095,22 +1061,6 @@ export const SCENARIOS: Scenario[] = [ needs: { masterPC: '45', masterUsdtSol: '0.002' }, env: { AGW_E2E: '1' }, }, - { - id: 'agw-preset-uniswap-live', - group: 'agw-presets', - file: '__e2e__/agw/presets-live.spec.ts', - grep: 'agw presets live 1', - needs: { masterPC: '75', masterPETH: '0.000002' }, - env: { AGW_E2E: '1' }, - }, - { - id: 'agw-preset-aave-live', - group: 'agw-presets', - file: '__e2e__/agw/presets-live.spec.ts', - grep: 'agw presets live 2', - needs: { masterPC: '75' }, - env: { AGW_E2E: '1' }, - }, { id: 'agw-v6-destination-pins', group: 'agw', diff --git a/packages/core/__e2e__/shared/agw-preset-acceptance.ts b/packages/core/__e2e__/shared/agw-preset-acceptance.ts index 683b60bb..4df73f47 100644 --- a/packages/core/__e2e__/shared/agw-preset-acceptance.ts +++ b/packages/core/__e2e__/shared/agw-preset-acceptance.ts @@ -16,12 +16,9 @@ export const PRESET_ACCEPTANCE_CASES = [ ['DEXES', 'eip155:11155111'], ['DEXES', 'eip155:84532'], ['DEXES', 'eip155:421614'], - ['DEXES', 'eip155:97'], ['LENDING', 'eip155:11155111'], ['LENDING', 'eip155:84532'], ['LENDING', 'eip155:421614'], - ['LENDING', 'eip155:97'], - ['STAKING', 'eip155:11155111'], ] as const satisfies readonly (readonly [PresetCategory, `eip155:${string}`])[]; function words(param: AbiParameter): number { diff --git a/packages/core/scripts/check-agw-package.js b/packages/core/scripts/check-agw-package.js index 99267d60..18b70977 100644 --- a/packages/core/scripts/check-agw-package.js +++ b/packages/core/scripts/check-agw-package.js @@ -40,18 +40,11 @@ async function main() { agent: '0x0000000000000000000000000000000000005678', chainNamespace: 'eip155:11155111', }); - assert.equal(preset.readiness.ready, false); - assert.deepEqual( - preset.rules[0].assets, - preset.readiness.chains[0].selectedAssets - ); - assert(preset.readiness.chains[0].selectedAssets.length > 0); + assert.deepEqual(Object.keys(preset), ['rules']); + assert.equal(preset.rules[0].assets.length, 1); assert.equal( - cjs.PushChain.utils.agentic.presets.get('LENDING', { - agent: '0x0000000000000000000000000000000000005678', - chainNamespace: 'eip155:11155111', - }).readiness.ready, - false + preset.rules[0].assets[0].token, + '0x0000000000000000000000000000000000000000' ); const guide = fs.readFileSync(path.join(built, 'AGW.md'), 'utf8'); const source = [...guide.matchAll(/```ts\n([\s\S]*?)```/g)] diff --git a/packages/core/scripts/check-agw-preset-compatibility.js b/packages/core/scripts/check-agw-preset-compatibility.js index f746d044..62c32a9d 100644 --- a/packages/core/scripts/check-agw-preset-compatibility.js +++ b/packages/core/scripts/check-agw-preset-compatibility.js @@ -1,323 +1,155 @@ -/** Read-only protocol compatibility of the exact routed testnet tokens. +/** Read-only protocol compatibility of the shipped testnet presets. * Build core first. No signer, environment keys, funding or transactions. + * For every preset chain: the wrap target accepts native ETH (simulated with a + * balance override), the Uniswap router wraps into that WETH and a WETH/USDC pool + * quotes USDC for a dust swap, and the Aave pool lists that WETH as a reserve. * Usage: node packages/core/scripts/check-agw-preset-compatibility.js [report.json] */ const fs = require('node:fs'); const path = require('node:path'); -const { createPublicClient, http, parseAbi, zeroAddress } = require('viem'); +const { + createPublicClient, + encodeFunctionData, + getAddress, + http, + parseAbi, +} = require('viem'); const built = path.resolve(__dirname, '../../../dist/packages/core/src'); -const { PushChain } = require(built); -const { MOVEABLE_TOKENS } = require(path.join(built, 'lib/constants/tokens')); -const { exactAgenticRoutes, resolveAgenticPrc20 } = require(path.join( - built, - 'lib/agentic/token-routes' -)); const { PRESET_CATALOG } = require(path.join( built, 'lib/agentic/presets/catalog' )); -const DONUT = PushChain.CONSTANTS.PUSH_NETWORK.TESTNET_DONUT; const abi = parseAbi([ - 'function factory() view returns (address)', - 'function getPool(address,address,uint24) view returns (address)', - 'function liquidity() view returns (uint128)', + 'function deposit() payable', + 'function WETH9() view returns (address)', + // QuoterV2 is non-view; declared view so eth_call returns the quote. + 'function quoteExactInputSingle((address tokenIn,address tokenOut,uint256 amountIn,uint24 fee,uint160 sqrtPriceLimitX96)) view returns (uint256,uint160,uint32,uint256)', 'function getReservesList() view returns (address[])', - 'function underlying() view returns (address)', - 'function underlyingToken() view returns (address)', - 'function SOURCE_CHAIN_NAMESPACE() view returns (string)', - 'function SOURCE_TOKEN_ADDRESS() view returns (string)', ]); const endpoints = { 'eip155:11155111': 'https://ethereum-sepolia-rpc.publicnode.com', 'eip155:84532': 'https://base-sepolia-rpc.publicnode.com', 'eip155:421614': 'https://arbitrum-sepolia-rpc.publicnode.com', - 'eip155:97': 'https://bsc-testnet-rpc.publicnode.com', }; +const PROBE = '0x000000000000000000000000000000000000dEaD'; +// Uniswap V3 QuoterV2 per testnet; the acceptance spec sends 1e12 wei. +const QUOTERS = { + 'eip155:11155111': '0xEd1f6473345F45b75F8179591dd5bA1888cf2FB3', + 'eip155:84532': '0xC5290058841028F1614F3A6F0F5816cAd0df5E27', + 'eip155:421614': '0x2779a0CC1c3e0E44D2542EC3e79e3864Ae93Ef0B', +}; +const QUOTE_AMOUNT = BigInt(10) ** BigInt(12); +const callTo = (def, selector) => + def.allowedCalls.find((c) => c.selector.startsWith(selector)); async function main() { - const report = { at: new Date().toISOString(), readOnly: true, chains: [] }; - const push = createPublicClient({ - transport: http('https://evm.donut.rpc.push.org/', { - timeout: 15000, - retryCount: 1, - }), - }); - report.pushBlock = String(await push.getBlockNumber()); - if ((await push.getChainId()) !== 42101) throw new Error('Expected Donut'); - for (const [chain, endpoint] of Object.entries(endpoints)) { - const entry = { chain, candidates: [], protocols: [], presets: [] }; - report.chains.push(entry); - const rpc = createPublicClient({ - transport: http(endpoint, { timeout: 12000, retryCount: 1 }), - }); - try { - const block = await rpc.getBlockNumber(); - entry.block = String(block); - if ((await rpc.getChainId()) !== Number(chain.split(':')[1])) - throw new Error('Destination chain mismatch'); - const read = (address, functionName, args = []) => - rpc.readContract({ - address, - abi, - functionName, - args, - blockNumber: block, - }); - // Registry tokens plus exact node routes the symbol registry cannot hold. - const sources = new Map(); - for (const token of MOVEABLE_TOKENS[chain] || []) - if (token.mechanism !== 'native') - sources.set(token.address.toLowerCase(), token); - for (const route of exactAgenticRoutes(chain, DONUT)) - sources.set(route.source.toLowerCase(), { - address: route.source, - symbol: route.symbol, - }); - for (const token of sources.values()) { - let mapped; - try { - mapped = resolveAgenticPrc20( - { chain, address: token.address }, - DONUT - ); - } catch (e) { - entry.candidates.push({ - token: token.address, - symbol: token.symbol, - unavailable: e.shortMessage || e.message, - }); - continue; - } - try { - const [sourceChain, source] = await Promise.all([ - push.readContract({ - address: mapped.address, - abi, - functionName: 'SOURCE_CHAIN_NAMESPACE', - blockNumber: BigInt(report.pushBlock), - }), - push - .readContract({ - address: mapped.address, - abi, - functionName: 'SOURCE_TOKEN_ADDRESS', - blockNumber: BigInt(report.pushBlock), - }) - .catch(() => - push.readContract({ - address: mapped.address, - abi: parseAbi([ - 'function SOURCE_TOKEN_ADDRESS() view returns (address)', - ]), - functionName: 'SOURCE_TOKEN_ADDRESS', - blockNumber: BigInt(report.pushBlock), - }) - ), - ]); - entry.candidates.push({ - token: token.address, - symbol: token.symbol, - prc20: mapped.address, - identityVerified: - sourceChain === chain && - source.toLowerCase() === token.address.toLowerCase(), - }); - } catch (e) { - // An RPC failure is unknown, not unsupported. - entry.candidates.push({ - token: token.address, - symbol: token.symbol, - prc20: mapped.address, - readError: e.shortMessage || e.message, - }); - } + const report = { at: new Date().toISOString(), readOnly: true, cases: [] }; + for (const preset of PRESET_CATALOG) + for (const def of preset.chains) { + const result = { preset: preset.constant, chain: def.chainNamespace }; + report.cases.push(result); + const endpoint = endpoints[def.chainNamespace]; + if (!endpoint) { + result.error = 'no read-only endpoint configured'; + process.exitCode = 1; + continue; } - const routed = entry.candidates.filter((c) => c.identityVerified); - for (const preset of PRESET_CATALOG) { - const def = preset.chains.find((c) => c.chainNamespace === chain); - if (!def) continue; - const generated = PushChain.utils.agentic.presets.get(preset.constant, { - chainNamespace: chain, - agent: '0x0000000000000000000000000000000000005678', + try { + const rpc = createPublicClient({ + transport: http(endpoint, { timeout: 12000, retryCount: 1 }), }); - entry.presets.push({ - category: preset.constant, - readiness: generated.readiness, - assets: generated.rules[0].assets, + const block = await rpc.getBlockNumber(); + result.block = String(block); + if ( + (await rpc.getChainId()) !== Number(def.chainNamespace.split(':')[1]) + ) + throw new Error('Destination chain mismatch'); + const read = (address, functionName, args = []) => + rpc.readContract({ + address, + abi, + functionName, + args, + blockNumber: block, + }); + const weth = getAddress(callTo(def, 'deposit(').target); + await rpc.call({ + account: PROBE, + to: weth, + data: encodeFunctionData({ abi, functionName: 'deposit' }), + value: BigInt(1), + blockNumber: block, + stateOverride: [ + { address: PROBE, balance: BigInt(10) ** BigInt(18) }, + ], }); - if (def.swapRouters) - for (const router of def.swapRouters) { - const result = { - app: router.app, - kind: 'dex', - router: router.address, - pairs: [], - }; - entry.protocols.push(result); + result.wrapsNativeEth = true; + if (preset.constant === 'DEXES') { + const swap = callTo(def, 'exactInputSingle('); + const router = getAddress(swap.target); + const usdc = getAddress( + def.allowedCalls.find( + (c) => + c.selector === 'approve(address,uint256)' && + getAddress(c.target) !== weth + ).target + ); + result.routerWeth9 = getAddress(await read(router, 'WETH9')); + if (result.routerWeth9 !== weth) + throw new Error(`router wraps into ${result.routerWeth9}`); + // Liquidity alone is not enough: thin, mispriced testnet pools can + // return nothing. Quote a dust swap at every tier instead. + result.quotes = []; + for (const fee of [100, 500, 3000, 10000]) { try { - result.factory = await read(router.address, 'factory'); - // The preset's own pair: one routed side is enough to trade into the other. - const pair = generated.rules[0].assets.map((a) => - typeof a.token === 'string' ? a.token : a.token.address + const [out] = await read( + QUOTERS[def.chainNamespace], + 'quoteExactInputSingle', + [ + { + tokenIn: weth, + tokenOut: usdc, + amountIn: QUOTE_AMOUNT, + fee, + sqrtPriceLimitX96: BigInt(0), + }, + ] ); - if (pair.length === 2) { - result.defaultPair = { - tokens: pair, - routed: pair.map((t) => - routed.some( - (c) => c.token.toLowerCase() === t.toLowerCase() - ) - ), - pools: [], - }; - for (const fee of [100, 500, 2500, 3000, 10000]) { - try { - const pool = await read(result.factory, 'getPool', [ - ...pair, - fee, - ]); - if (pool === zeroAddress) continue; - result.defaultPair.pools.push({ - fee, - pool, - liquidity: String(await read(pool, 'liquidity')), - }); - } catch (e) { - result.defaultPair.pools.push({ - fee, - error: e.shortMessage || e.message, - }); - } - } - } - for (let i = 0; i < routed.length; i++) - for (let j = i + 1; j < routed.length; j++) { - const pair = { - tokens: [routed[i].token, routed[j].token], - pools: [], - }; - result.pairs.push(pair); - for (const fee of [100, 500, 2500, 3000, 10000]) { - try { - const pool = await read(result.factory, 'getPool', [ - ...pair.tokens, - fee, - ]); - if (pool === zeroAddress) continue; - pair.pools.push({ - fee, - pool, - liquidity: String(await read(pool, 'liquidity')), - }); - } catch (e) { - pair.pools.push({ - fee, - error: e.shortMessage || e.message, - }); - } - } - } - } catch (e) { - result.error = e.shortMessage || e.message; + result.quotes.push({ fee, usdcOut: String(out) }); + } catch { + // no pool at this tier } } - const aave = def.allowedCalls.find((c) => c.app === 'Aave V3'); - if (aave) { - const result = { app: 'Aave V3', kind: 'lending', pool: aave.target }; - entry.protocols.push(result); - try { - result.reserves = await read(aave.target, 'getReservesList'); - result.routedReserves = routed.filter((c) => - result.reserves.some( - (a) => a.toLowerCase() === c.token.toLowerCase() - ) - ); - } catch (e) { - result.error = e.shortMessage || e.message; - } + if (!result.quotes.some((q) => BigInt(q.usdcOut) > BigInt(0))) + throw new Error('no WETH/USDC tier returns USDC for a dust swap'); } - const markets = [ - ...new Map( - def.allowedCalls - .filter((c) => c.budget?.kind === 'fixed-token') - .map((c) => [c.target, c]) - ).values(), - ]; - for (const market of markets) { - const result = { - app: market.app, - kind: 'market', - market: market.target, - }; - entry.protocols.push(result); - try { - result.underlying = await read(market.target, 'underlying'); - result.routed = routed.some( - (c) => c.token.toLowerCase() === result.underlying.toLowerCase() - ); - } catch (e) { - result.error = e.shortMessage || e.message; - } - } - if (preset.constant === 'STAKING') { - const strategy = '0x424246eF71b01ee33aA33aC590fd9a0855F5eFbc'; - const result = { app: 'EigenLayer', kind: 'strategy', strategy }; - entry.protocols.push(result); - try { - result.underlying = await read(strategy, 'underlyingToken'); - result.routed = routed.some( - (c) => c.token.toLowerCase() === result.underlying.toLowerCase() - ); - } catch (e) { - result.error = e.shortMessage || e.message; - } + if (preset.constant === 'LENDING') { + const pool = getAddress(callTo(def, 'supply(').target); + const reserves = (await read(pool, 'getReservesList')).map((r) => + getAddress(r) + ); + result.wethIsReserve = reserves.includes(weth); + if (!result.wethIsReserve) + throw new Error(`${weth} is not an Aave reserve`); } + console.log(`${preset.constant} ${def.chainNamespace}: compatible`); + } catch (error) { + // An RPC failure is unknown, not incompatible; both fail the check. + result.error = error.shortMessage || error.message; + process.exitCode = 1; + console.error( + `${preset.constant} ${def.chainNamespace}: ${result.error}` + ); } - } catch (e) { - entry.error = e.shortMessage || e.message; } - } - const output = process.argv[2]; - if (output) - fs.writeFileSync( - output, - JSON.stringify( - report, - (_k, v) => (typeof v === 'bigint' ? String(v) : v), - 2 - ) - ); - for (const c of report.chains) - console.log( - JSON.stringify( - { - chain: c.chain, - block: c.block, - error: c.error, - routed: c.candidates - .filter((x) => x.identityVerified) - .map((x) => x.symbol), - protocols: c.protocols, - }, - null, - 2 - ) - ); - if ( - report.chains.some( - (c) => - c.error || - c.candidates.some((x) => x.readError) || - c.protocols.some( - (p) => - p.error || - p.pairs?.some((x) => x.pools.some((y) => y.error)) || - p.defaultPair?.pools.some((y) => y.error) - ) - ) - ) - process.exitCode = 1; + const output = process.argv[2] || '/tmp/agw-preset-compatibility.json'; + fs.writeFileSync(output, JSON.stringify(report, null, 2)); + console.log( + `Read-only report: ${output}; ${ + report.cases.filter((c) => !c.error).length + }/${report.cases.length} compatible.` + ); } -main().catch((e) => { - console.error(e.shortMessage || e.message); +main().catch((error) => { + console.error(error.shortMessage || error.message); process.exitCode = 1; }); diff --git a/packages/core/scripts/check-agw-preset-routes.js b/packages/core/scripts/check-agw-preset-routes.js index 53bf5ba2..55705637 100644 --- a/packages/core/scripts/check-agw-preset-routes.js +++ b/packages/core/scripts/check-agw-preset-routes.js @@ -123,9 +123,7 @@ async function main() { agent, chainNamespace, }); - result.pushReadiness = push.readiness; // Explicit prefunded fixture, not public preset acceptance or bridge proof. - assert.equal(push.readiness.chains[0].configurationReady, true); const fixtureRules = push.rules.map((rule) => ({ ...rule, assets: [], @@ -154,21 +152,17 @@ async function main() { }); assert(simulated.data && simulated.data !== '0x'); result.prefundedFixtureFactorySimulation = 'passed'; - result.selectedAssets = push.readiness.chains[0].selectedAssets; - // If static registry support is advertised, verify preparation against real metadata too. - if (push.readiness.ready) { - await prepareWalletRules( - runtime, - gen, - owner, - wallet, - publicRules(push.rules), - snap - ); - result.pushPreparation = 'passed'; - } else { - result.pushPreparation = 'unavailable-in-registry'; - } + result.selectedAssets = push.rules[0].assets; + // Every shipped preset is routable, so preparation must verify against real metadata. + await prepareWalletRules( + runtime, + gen, + owner, + wallet, + publicRules(push.rules), + snap + ); + result.pushPreparation = 'passed'; console.log( `${category} ${chainNamespace}: destination factory eth_call passed; Push ${result.pushPreparation}` ); diff --git a/packages/core/scripts/check-agw-route-registry.js b/packages/core/scripts/check-agw-route-registry.js index f084db1b..c9e320bb 100644 --- a/packages/core/scripts/check-agw-route-registry.js +++ b/packages/core/scripts/check-agw-route-registry.js @@ -163,7 +163,8 @@ async function main() { for (const preset of PRESET_CATALOG) for (const chain of preset.chains) { if (!enabled.some((c) => c.chain === chain.chainNamespace)) continue; - for (const token of chain.defaultTokens || []) { + // Presets send only native ETH; its route is the chain's gas token config. + for (const token of ['0x0000000000000000000000000000000000000000']) { const route = enabled.find( (c) => c.chain === chain.chainNamespace && diff --git a/packages/core/src/lib/agentic/__tests__/creation-errors.spec.ts b/packages/core/src/lib/agentic/__tests__/creation-errors.spec.ts index c7f4d052..9b9effd1 100644 --- a/packages/core/src/lib/agentic/__tests__/creation-errors.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/creation-errors.spec.ts @@ -22,74 +22,86 @@ const options = { beforeEach(registerFakeGeneration); afterEach(resetAgenticGenerations); -it.each(['LENDING', 'STAKING'] as const)( - 'public %s create gives a typed token-route error before any transaction', - async (category) => { - const cause = new Error( - 'Unable to infer origin chain or token symbol for token' - ); - const rt = mockRuntime(new FakeChain(), { - signer: ADDR.owner, - resolvePrc20: () => { - throw cause; - }, - }); - const sdk = new AgenticNamespaceImpl(rt); - const { rules } = agenticPresets.get(category, options); - let failure: unknown; - try { - await sdk.create('Test', { rules }); - } catch (error) { - failure = error; - } - expect(failure).toBeInstanceOf(AgenticError); - expect(failure).toMatchObject({ - code: 'TOKEN_ROUTE_UNAVAILABLE', - cause, - details: { - ruleIndex: 0, - assetIndex: 0, - chainNamespace, - field: 'assets[0].token', +it('an edited preset with an unrouted token gives a typed token-route error before any transaction', async () => { + const cause = new Error( + 'Unable to infer origin chain or token symbol for token' + ); + const rt = mockRuntime(new FakeChain(), { + signer: ADDR.owner, + resolvePrc20: () => { + throw cause; + }, + }); + const sdk = new AgenticNamespaceImpl(rt); + const { rules } = agenticPresets.get('LENDING', options); + // Aave's faucet LINK has no Push route; presets themselves send only ETH. + const edited = { + ...rules[0], + assets: [ + { + token: '0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5', + maxPerCall: BigInt(1), + maxTotal: BigInt(2), }, - userMessage: expect.stringContaining( - 'Rule 1: This token cannot be sent from Push to Ethereum Sepolia' - ), - hint: expect.stringContaining('verified PRC20 route'), - }); - expect(rt.executeMock).not.toHaveBeenCalled(); - expect(rt.atomicMock).not.toHaveBeenCalled(); + ], + }; + let failure: unknown; + try { + await sdk.create('Test', { rules: [edited] }); + } catch (error) { + failure = error; } -); + expect(failure).toBeInstanceOf(AgenticError); + expect(failure).toMatchObject({ + code: 'TOKEN_ROUTE_UNAVAILABLE', + cause, + details: { + ruleIndex: 0, + assetIndex: 0, + chainNamespace, + field: 'assets[0].token', + }, + userMessage: expect.stringContaining( + 'Rule 1: This token cannot be sent from Push to Ethereum Sepolia' + ), + hint: expect.stringContaining('verified PRC20 route'), + }); + expect(rt.executeMock).not.toHaveBeenCalled(); + expect(rt.atomicMock).not.toHaveBeenCalled(); +}); -it('reports the complete 40-condition count for duplicated DEX entries, without dropping them', async () => { +it('reports the complete 42-condition count for duplicated DEX entries, without dropping them', async () => { const rt = mockRuntime(new FakeChain(), { signer: ADDR.owner }); const sdk = new AgenticNamespaceImpl(rt); const { rules } = agenticPresets.get('DEXES', { ...options, }); const calls = rules[0].allowedCalls; - const duplicated = { ...rules[0], allowedCalls: [...calls, ...calls] }; + // The unpinned wrap cannot repeat (a bare alternative is refused first). + const duplicated = { + ...rules[0], + allowedCalls: [...calls, ...calls.filter((c) => c.pins?.length)], + }; await expect( sdk.create('Test', { rules: [duplicated] }) ).rejects.toMatchObject({ code: 'INVALID_RULE', details: { reason: 'RULE_CONSTRAINT_LIMIT', - actual: 40, + actual: 42, limit: 32, - callCount: 12, + callCount: 15, ruleIndex: 0, chainNamespace, }, - message: expect.stringContaining('40 conditions'), + message: expect.stringContaining('42 conditions'), userMessage: expect.stringContaining('Rule 1:'), }); - expect(duplicated.allowedCalls).toHaveLength(12); + expect(duplicated.allowedCalls).toHaveLength(15); expect(rt.executeMock).not.toHaveBeenCalled(); }); -it('validates stock DEX rules independently: two 20-condition rules do not become a 40-condition rule', async () => { +it('validates stock DEX rules independently: two 21-condition rules do not become a 42-condition rule', async () => { const rt = mockRuntime(new FakeChain()); for (const chain of ['eip155:11155111', 'eip155:84532'] as const) { const { rules } = agenticPresets.get('DEXES', { @@ -103,7 +115,7 @@ it('validates stock DEX rules independently: two 20-condition rules do not becom )) as UniversalRule; expect( normalized.allowedCalls.reduce((n, c) => n + (c.pins?.length ?? 0), 0) - ).toBe(20); + ).toBe(21); expect(() => validateUniversalRuleShape(normalized, rt.nowSeconds()) ).not.toThrow(); @@ -166,6 +178,32 @@ it('explains the create and native action ceilings using the available structure ).toContain('at most eight functions'); }); +it.each([9, 33])( + 'reports the eight-function Push-chain limit for %i functions, not the generic 1..32', + async (count) => { + const rt = mockRuntime(new FakeChain(), { signer: ADDR.owner }); + const sdk = new AgenticNamespaceImpl(rt); + await expect( + sdk.create('Too many', { + rules: [ + { + agent: ADDR.agent, + validUntil: 2_000_000_000, + allowedCalls: Array.from({ length: count }, (_, i) => ({ + target: `0x${(i + 16).toString(16).padStart(40, '0')}`, + selector: 'increment()' as const, + })), + }, + ], + }) + ).rejects.toMatchObject({ + code: 'CAPABILITY_UNAVAILABLE', + details: { capability: 'nativeActions' }, + userMessage: expect.stringContaining('at most eight functions'), + }); + } +); + it('preserves decoded contract failures and cancellation causes with UI messages', () => { const decodedError = { name: 'PolicyCheckReverted(ArgPinAboveMax)', @@ -203,23 +241,36 @@ it.each([ } ); -it.each([undefined, []])( - 'rejects a tokens-only rule with actionable guidance before signing (%j)', - async (allowedCalls) => { +it.each([ + ['a Push-chain rule', {}], + ['an EVM rule without tokens', { chainNamespace, assets: [] as never[] }], +])( + 'rejects %s without allowed functions before signing', + async (_name, shape) => { const rt = mockRuntime(new FakeChain(), { signer: ADDR.owner }); const sdk = new AgenticNamespaceImpl(rt); - const { rules } = agenticPresets.get('LENDING', options); - await expect( - sdk.create('Tokens only', { - rules: [{ ...rules[0], allowedCalls } as never], - }) - ).rejects.toMatchObject({ - code: 'INVALID_RULE', - details: { reason: 'ALLOWED_FUNCTION_REQUIRED', field: 'allowedCalls' }, - userMessage: expect.stringContaining( - 'Selecting tokens and limits alone does not authorize transfers' - ), - }); + for (const allowedCalls of [undefined, []]) + await expect( + sdk.create('No functions', { + rules: [ + { + agent: ADDR.agent, + validUntil: 2_000_000_000, + ...shape, + allowedCalls, + }, + ], + }) + ).rejects.toMatchObject({ + code: 'INVALID_RULE', + details: { + reason: 'ALLOWED_FUNCTION_REQUIRED', + field: 'allowedCalls', + }, + userMessage: expect.stringContaining( + 'allow transfers back to the owner' + ), + }); expect(rt.executeMock).not.toHaveBeenCalled(); expect(rt.atomicMock).not.toHaveBeenCalled(); } diff --git a/packages/core/src/lib/agentic/__tests__/preset-catalog.spec.ts b/packages/core/src/lib/agentic/__tests__/preset-catalog.spec.ts index 25b47921..4c2ff330 100644 --- a/packages/core/src/lib/agentic/__tests__/preset-catalog.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/preset-catalog.spec.ts @@ -1,4 +1,10 @@ -import { encodeFunctionData, parseAbi, getAddress, type Address } from 'viem'; +import { + encodeFunctionData, + parseAbi, + parseUnits, + getAddress, + zeroAddress, +} from 'viem'; import { agenticPresets } from '../presets'; import { AGENTIC } from '../constants'; import { evmPinOffset, normalizePublicRule, publicRules } from '../public-rule'; @@ -6,99 +12,188 @@ import { parseSelector } from '../codec/selectors'; import type { Rule, UniversalRule } from '../agentic.types'; import { FakeChain, ADDR } from './fake-chain'; import { mockRuntime } from './mock-runtime'; -const tokenA = ADDR.target, - tokenB = ADDR.other; -const chain = 'eip155:11155111'; -const input: import('../presets/types').ReadyPresetOptions = { - chainNamespace: chain, + +const TESTNETS = ['eip155:11155111', 'eip155:84532', 'eip155:421614'] as const; +const DEX = { + 'eip155:11155111': { + router: '0x3bFA4769FB09eefC5a80d6E87c3B9C650f7Ae48E', + weth: '0xfff9976782d46cc05630d1f6ebab18b2324d6b14', + usdc: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238', + }, + 'eip155:84532': { + router: '0x94cC0AaC535CCDB3C01d6787D6413C739ae12bc4', + weth: '0x4200000000000000000000000000000000000006', + usdc: '0x036CbD53842c5426634e7929541eC2318f3dCF7e', + }, + 'eip155:421614': { + router: '0x101F443B4d1b059569D643917553c771E1b9663E', + weth: '0x980B62Da83eFf3D4576C647993b0c1D7faf17c73', + usdc: '0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d', + }, +} as const; +const AAVE = { + 'eip155:11155111': { + pool: '0x6Ae43d3271ff6888e7Fc43Fd7321a503ff738951', + weth: '0xC558DBdd856501FCd9aaF1E62eae57A9F0629a3c', + }, + 'eip155:84532': { + pool: '0x8bAB6d1b75f19e9eD9fCe8b9BD338844fF79aE27', + weth: '0x4200000000000000000000000000000000000006', + }, + 'eip155:421614': { + pool: '0xBfC91D59fdAA134A4ED45f7B584cAf96D7792Eff', + weth: '0x1dF462e2712496373A347f8ad10802a5E95f053D', + }, +} as const; +const cap = parseUnits('0.002', 18); +const input = (chainNamespace: (typeof TESTNETS)[number]) => ({ + chainNamespace, agent: ADDR.agent, validUntil: 2_000_000_000, - maxGasPerCall: BigInt(1), - assets: [ - { token: tokenA, maxPerCall: BigInt(5), maxTotal: BigInt(10) }, - { token: tokenB, maxPerCall: BigInt(7), maxTotal: BigInt(14) }, - ], -}; -it('expands both token directions and exact-input/output with wallet and amount pins', () => { - const { rules } = agenticPresets.get('DEXES', input); - expect(rules).toHaveLength(1); - expect(rules[0].allowedCalls).toHaveLength(6); - const swaps = rules[0].allowedCalls.filter((c) => - c.selector.startsWith('exact') - ); - expect(swaps).toHaveLength(4); - expect(swaps[0].pins).toEqual([ - { arg: [0, 0], expected: tokenA }, - { arg: [0, 1], expected: tokenB }, - { arg: [0, 3], expected: AGENTIC.WALLET }, - { arg: [0, 4], max: BigInt(5) }, + assets: [{ token: zeroAddress, maxPerCall: cap, maxTotal: cap * BigInt(5) }], +}); +const pinTotal = (r: { allowedCalls: { pins?: unknown[] }[] }) => + r.allowedCalls.reduce((n, c) => n + (c.pins?.length ?? 0), 0); + +it('ships only the testnet presets that ran live: Uniswap V3 and Aave V3 on three chains', () => { + expect(Object.values(AGENTIC.PRESETS.CATEGORY)).toEqual([ + 'DEXES', + 'LENDING', + 'STAKING', ]); - expect(swaps[1].pins?.at(-1)).toEqual({ arg: [0, 5], max: BigInt(5) }); - expect(swaps[2].pins?.at(-1)).toEqual({ arg: [0, 4], max: BigInt(7) }); expect( - rules[0].allowedCalls.reduce((n, c) => n + (c.pins?.length ?? 0), 0) - ).toBe(20); + agenticPresets.list().presets.map((p) => [p.constant, p.chains]) + ).toEqual([ + ['DEXES', [...TESTNETS]], + ['LENDING', [...TESTNETS]], + ['STAKING', []], + ]); + expect(agenticPresets.get('STAKING')).toEqual({ rules: [] }); + for (const category of ['DEXES', 'LENDING'] as const) + for (const rule of agenticPresets.get(category).rules) { + expect(rule.assets).toEqual([ + { + token: zeroAddress, + maxPerCall: parseUnits('0.001', 18), + maxTotal: parseUnits('0.01', 18), + }, + ]); + expect(rule.maxGasPerCall).toBe(parseUnits('20', 18)); + expect(rule).not.toHaveProperty('readiness'); + } }); -it('rejects native-token markers and oversized pin expansion', () => { - expect(() => - agenticPresets.get('DEXES', { - ...input, - assets: [...input.assets!, { token: ADDR.owner }], - }) - ).toThrow(/maximum is 32/); - expect(() => - agenticPresets.get('DEXES', { - ...input, - assets: [ - { token: '0x0000000000000000000000000000000000000000' }, - input.assets![1], +it.each(TESTNETS)( + 'DEXES %s wraps ETH and swaps WETH and Circle USDC with wallet-pinned recipients', + (chainNamespace) => { + const { router, weth, usdc } = DEX[chainNamespace]; + const r = agenticPresets.get('DEXES', input(chainNamespace)).rules[0]; + const W = getAddress(weth), + U = getAddress(usdc), + R = getAddress(router); + expect( + r.allowedCalls.map((c) => [getAddress(c.target), c.selector]) + ).toEqual([ + [W, 'deposit()'], + [W, 'approve(address,uint256)'], + [R, expect.stringMatching(/^exactInputSingle\(/)], + [R, expect.stringMatching(/^exactOutputSingle\(/)], + [U, 'approve(address,uint256)'], + [R, expect.stringMatching(/^exactInputSingle\(/)], + [R, expect.stringMatching(/^exactOutputSingle\(/)], + [W, 'withdraw(uint256)'], + ]); + const [wrap, approveWeth, sellIn, sellOut, approveUsdc, buyIn, buyOut] = + r.allowedCalls; + expect(wrap.maxValue).toBe(cap); + expect(approveWeth.pins).toEqual([ + { arg: 0, expected: R }, + { arg: 1, max: cap }, + ]); + expect(sellIn.pins).toEqual([ + { arg: [0, 0], expected: W }, + { arg: [0, 1], expected: U }, + { arg: [0, 3], expected: AGENTIC.WALLET }, + { arg: [0, 4], max: cap }, + ]); + expect(sellOut.pins?.at(-1)).toEqual({ arg: [0, 5], max: cap }); + const usdcCap = parseUnits('10', 6); + expect(approveUsdc.pins).toEqual([ + { arg: 0, expected: R }, + { arg: 1, max: usdcCap }, + ]); + expect(buyIn.pins).toEqual([ + { arg: [0, 0], expected: U }, + { arg: [0, 1], expected: W }, + { arg: [0, 3], expected: AGENTIC.WALLET }, + { arg: [0, 4], max: usdcCap }, + ]); + expect(buyOut.pins?.at(-1)).toEqual({ arg: [0, 5], max: usdcCap }); + expect(r.allowedCalls.at(-1)?.pins).toEqual([{ arg: 0, max: cap }]); + expect(pinTotal(r)).toBeLessThanOrEqual(32); + } +); +it.each(TESTNETS)( + 'LENDING %s wraps ETH into the Aave WETH reserve and pins every position to the wallet', + (chainNamespace) => { + const { pool, weth } = AAVE[chainNamespace]; + const r = agenticPresets.get('LENDING', input(chainNamespace)).rules[0]; + const W = getAddress(weth), + P = getAddress(pool); + expect( + r.allowedCalls.map((c) => [getAddress(c.target), c.selector, c.pins]) + ).toEqual([ + [W, 'deposit()', undefined], + [ + W, + 'approve(address,uint256)', + [ + { arg: 0, expected: P }, + { arg: 1, max: cap }, + ], ], - }) - ).toThrow(/ERC20/); -}); -it('defaults omitted caps to zero without introducing an unlimited approval', () => { - const r = agenticPresets.get('DEXES', { - ...input, - assets: [{ token: tokenA }, { token: tokenB }], - }).rules[0]; - expect( - r.assets?.every( - (a) => a.maxPerCall === BigInt(0) && a.maxTotal === BigInt(0) - ) - ).toBe(true); - expect( - r.allowedCalls.every((c) => c.pins?.some((p) => p.max === BigInt(0))) - ).toBe(true); -}); -it('scopes money-market approvals to their actual underlying token', () => { - const underlying = '0x4616975f7E6045FD9737e95bC527e9e14c727BD2' as Address; - const r = agenticPresets.get('LENDING', { - chainNamespace: 'eip155:84532', - assets: [{ token: underlying, maxPerCall: BigInt(2) }], - }).rules[0]; - const approvals = r.allowedCalls.filter( - (c) => c.selector === 'approve(address,uint256)' - ); - expect(approvals).toHaveLength(1); // Only mUSDbC: this mock token is not an Aave reserve. - expect(approvals.flatMap((c) => c.pins ?? [])).not.toContainEqual({ - arg: 0, - expected: getAddress('0x2F39a349A79492a70E152760ce7123A1933eCf28'), - }); -}); -it.each([ - 'eip155:1', - 'eip155:8453', - 'eip155:42161', - 'eip155:56', - 'eip155:11155111', - 'eip155:84532', - 'eip155:421614', - 'eip155:97', -] as const)( - 'normalizes every DEX call on %s to the exact ABI bytes', + ...( + [ + ['supply(address,uint256,address,uint16)', 2], + ['withdraw(address,uint256,address)', 2], + ['borrow(address,uint256,uint256,uint16,address)', 4], + ['repay(address,uint256,uint256,address)', 3], + ] as const + ).map(([selector, beneficiary]) => [ + P, + selector, + [ + { arg: 0, expected: W }, + { arg: beneficiary, expected: AGENTIC.WALLET }, + { arg: 1, max: cap }, + ], + ]), + [W, 'withdraw(uint256)', [{ arg: 0, max: cap }]], + ]); + expect(r.allowedCalls[0].maxValue).toBe(cap); + } +); +it.each( + TESTNETS.flatMap((chain) => + (['DEXES', 'LENDING'] as const).map((p) => [p, chain] as const) + ) +)( + '%s %s compiles with the deployed v6 policy within its limits', + async (preset, chainNamespace) => { + const r = agenticPresets.get(preset, input(chainNamespace)).rules[0]; + const out = (await normalizePublicRule( + publicRules([r])[0], + ADDR.owner, + mockRuntime(new FakeChain()) + )) as UniversalRule; + expect(out.allowedCalls).toHaveLength(r.allowedCalls.length); + expect(out.allowedCalls[0].maxValue).toBe(cap); + expect(out.allowedCalls.slice(1).every((c) => !c.maxValue)).toBe(true); + } +); +it.each(TESTNETS)( + 'normalizes every DEX swap on %s to the exact ABI bytes', async (chainNamespace) => { - const r = agenticPresets.get('DEXES', { ...input, chainNamespace }) - .rules[0]; + const r = agenticPresets.get('DEXES', input(chainNamespace)).rules[0]; const rt = mockRuntime(new FakeChain()); const out = (await normalizePublicRule( publicRules([r])[0], @@ -155,7 +250,7 @@ it('supports tuple/fixed-array positions but never descends into dynamic storage expect(() => evmPinOffset('0x12345678', [0, 1])).toThrow(/scalar/); }); it('tuple-authored pins re-encode using the raw-selector word indexes returned by reads', async () => { - const r = agenticPresets.get('DEXES', input).rules[0]; + const r = agenticPresets.get('DEXES', input('eip155:11155111')).rules[0]; const rt = mockRuntime(new FakeChain()); const first = (await normalizePublicRule( publicRules([r])[0], @@ -184,144 +279,15 @@ it('tuple-authored pins re-encode using the raw-selector word indexes returned b first.allowedCalls.map((c) => c.pins) ); }); -it('mutating a returned tuple path cannot change a later preset', () => { - const r = agenticPresets.get('DEXES', input).rules[0]; - (r.allowedCalls[0].pins![0].arg as number[])[1] = 99; - expect( - agenticPresets.get('DEXES', input).rules[0].allowedCalls[0].pins![0].arg - ).toEqual([0, 0]); -}); - -it('includes a curated capped token pair and exact pair pins on every DEX chain', () => { - const { rules, readiness } = agenticPresets.get('DEXES'); - expect(rules.map((r) => r.chainNamespace)).toEqual( - agenticPresets.list().presets.find((p) => p.constant === 'DEXES')!.chains - ); - for (const rule of rules) { - expect(rule).not.toHaveProperty('agent'); - expect(rule.validUntil).toBeGreaterThan(Math.floor(Date.now() / 1000)); - expect(rule.assets).toHaveLength(2); - expect( - rule.assets!.every( - (a) => - a.maxPerCall > BigInt(0) && (a.maxTotal ?? BigInt(0)) >= a.maxPerCall - ) - ).toBe(true); - expect(rule.allowedCalls).toHaveLength(6); - const swaps = rule.allowedCalls.filter((c) => - c.selector.startsWith('exact') - ); - expect(swaps).toHaveLength(4); - for (const call of swaps) { - expect(call.pins).toHaveLength(4); - expect(call.pins).toContainEqual({ - arg: [0, 3], - expected: AGENTIC.WALLET, - }); - expect(call.pins?.at(-1)?.max).toBeGreaterThan(BigInt(0)); - expect(call.label).not.toContain('select two tokens'); - } - } - expect(readiness.chains.every((c) => c.knownTokens.length >= 2)).toBe(true); - expect( - readiness.chains.every( - (c) => !c.issues.some((i) => i.code === 'TOKEN_PAIR_REQUIRED') - ) - ).toBe(true); -}); -it('keeps single-token swaps disabled and generates approvals only for the supplied asset', () => { - const rule = agenticPresets.get('DEXES', { - ...input, - assets: [input.assets![0]], - }).rules[0]; - expect(rule.assets).toEqual([input.assets![0]]); - expect(rule.allowedCalls).toHaveLength(3); - for (const call of rule.allowedCalls.slice(0, 2)) { - expect(call.pins).toContainEqual({ arg: [0, 0], expected: tokenA }); - expect(call.pins?.at(-1)?.max).toBe(BigInt(0)); - } - expect(rule.allowedCalls[2].selector).toBe('approve(address,uint256)'); - expect(rule.allowedCalls[2].target).toBe(tokenA); -}); -it('keeps chains without supplied assets discoverable and regenerates complete pairs without disabled alternatives', () => { - const { rules } = agenticPresets.get('DEXES', { - assets: input.assets!.map((a) => ({ ...a, chainNamespace: chain })), - }); - expect(rules).toHaveLength(8); - expect( - rules.find((r) => r.chainNamespace === chain)?.allowedCalls - ).toHaveLength(6); - for (const r of rules.filter((r) => r.chainNamespace !== chain)) { - expect(r.assets).toEqual([]); - expect(r.allowedCalls).toHaveLength(2); - expect(r.allowedCalls.every((c) => c.pins?.at(-1)?.max === BigInt(0))).toBe( - true - ); - } - const preview = agenticPresets.get('DEXES', { - chainNamespace: chain, - assets: [], +it('mutating a returned rule cannot change a later preset', () => { + const r = agenticPresets.get('DEXES', input('eip155:84532')).rules[0]; + (r.allowedCalls[2].pins![0].arg as number[])[1] = 99; + r.allowedCalls[0].maxValue = BigInt(0); + r.assets![0].maxPerCall = BigInt(0); + const again = agenticPresets.get('DEXES', { + chainNamespace: 'eip155:84532', }).rules[0]; - const ready = agenticPresets.get('DEXES', input).rules[0]; - expect(preview.allowedCalls).toHaveLength(2); - expect(ready.allowedCalls).toHaveLength(6); - expect( - ready.allowedCalls.every((c) => !c.label?.includes('select two tokens')) - ).toBe(true); -}); - -it.each(['eip155:1', 'eip155:8453', 'eip155:42161', 'eip155:56'] as const)( - 'mainnet %s templates preserve one rule per chain, selectors and wallet pins', - (chainNamespace) => { - for (const category of ['DEXES', 'LENDING'] as const) { - const { rules } = agenticPresets.get(category, { chainNamespace }); - expect(rules).toHaveLength(1); - expect(rules[0].chainNamespace).toBe(chainNamespace); - expect(rules[0].allowedCalls.length).toBeLessThanOrEqual(32); - expect(rules[0].allowedCalls.every((c) => c.selector.includes('('))).toBe( - true - ); - expect( - rules[0].allowedCalls.some((c) => - c.pins?.some((p) => p.expected === AGENTIC.WALLET) - ) - ).toBe(true); - expect(rules[0]).not.toHaveProperty('agent'); - } - } -); - -it('mainnet Lido uses the selected token units and excludes unbounded withdrawal/claim methods', () => { - const stETH = getAddress('0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84'); - const { rules, readiness } = agenticPresets.get('STAKING', { - chainNamespace: 'eip155:1', - assets: [{ token: stETH, maxPerCall: BigInt(5), maxTotal: BigInt(10) }], - }); - const calls = rules[0].allowedCalls; - expect( - calls.find((c) => c.selector === 'wrap(uint256)')?.pins - ).toContainEqual({ arg: 0, max: BigInt(5) }); - expect(calls.some((c) => c.selector === 'submit(address)')).toBe(false); - expect( - calls.some( - (c) => - c.selector.startsWith('requestWithdrawals') || - c.selector.startsWith('claimWithdraw') - ) - ).toBe(false); - expect(readiness.chains[0].excludedCalls).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - selector: 'requestWithdrawals(uint256[],address)', - reason: 'DYNAMIC_AMOUNT', - }), - expect.objectContaining({ - selector: 'claimWithdrawal(uint256)', - reason: 'POSITION_AMOUNT', - }), - ]) - ); - expect( - calls.filter((c) => c.selector === 'approve(address,uint256)') - ).toHaveLength(2); + expect(again.allowedCalls[2].pins![0].arg).toEqual([0, 0]); + expect(again.allowedCalls[0].maxValue).toBe(parseUnits('0.001', 18)); + expect(again.assets![0].maxPerCall).toBe(parseUnits('0.001', 18)); }); diff --git a/packages/core/src/lib/agentic/__tests__/preset-default-policy.spec.ts b/packages/core/src/lib/agentic/__tests__/preset-default-policy.spec.ts index 5e72d2bd..f3bd9746 100644 --- a/packages/core/src/lib/agentic/__tests__/preset-default-policy.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/preset-default-policy.spec.ts @@ -1,168 +1,38 @@ -import { getAddress, parseEther, zeroAddress } from 'viem'; +import { parseUnits, zeroAddress } from 'viem'; import { agenticPresets } from '../presets'; -import { defaultPresetAsset } from '../presets/default-policy'; -import type { Rule } from '../agentic.types'; -import { ADDR } from './fake-chain'; - -const chainNamespace = 'eip155:11155111' as const; -const agent = ADDR.agent; - -it.each(['DEXES', 'LENDING', 'STAKING'] as const)( - 'an agent alone produces typed, locally complete %s rules on all catalog chains', - (category) => { - const { rules, readiness } = agenticPresets.get(category, { agent }); - const typed: Rule[] = rules; - expect(typed.length).toBeGreaterThan(0); - expect(readiness.chains.every((c) => c.configurationReady)).toBe(true); - for (const rule of typed) { - expect(rule.agent).toBe(agent); - expect(rule.maxGasPerCall).toBe(parseEther('20')); - expect(rule.validUntil).toBeGreaterThan(Math.floor(Date.now() / 1000)); - expect(rule.assets?.every((a) => a.maxPerCall > BigInt(0))).toBe(true); - } - } -); - -it('generates one expiry seven days from this get call, refreshing on the next call', () => { - const clock = jest.spyOn(Date, 'now'); - try { - const now = 1_800_000_000; - clock.mockReturnValue(now * 1000); - const first = agenticPresets.get('DEXES', { agent }); - expect(new Set(first.rules.map((r) => r.validUntil))).toEqual( - new Set([now + 604800]) - ); - clock.mockReturnValue((now + 60) * 1000); - expect(agenticPresets.get('DEXES', { agent }).rules[0].validUntil).toBe( - now + 60 + 604800 - ); - expect(first.rules[0].validUntil).toBe(now + 604800); - } finally { - clock.mockRestore(); - } -}); - -it('uses verified raw-unit limits for stablecoins with different decimals', () => { - const mainnet = agenticPresets.get('DEXES', { - agent, - chainNamespace: 'eip155:56', - }).rules[0]; - const testnet = agenticPresets.get('DEXES', { - agent, - chainNamespace: 'eip155:97', - }).rules[0]; - expect(mainnet.assets?.[1]).toMatchObject({ - maxPerCall: BigInt('10000000000000000000'), - maxTotal: BigInt('100000000000000000000'), - }); - expect(testnet.assets?.[1]).toMatchObject({ - maxPerCall: BigInt('10000000'), - maxTotal: BigInt('100000000'), - }); - const aave = agenticPresets.get('LENDING', { - agent, - chainNamespace: 'eip155:1', - }).rules[0]; - expect(aave.assets?.[1]).toMatchObject({ - token: getAddress('0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'), - maxPerCall: BigInt('10000000'), - maxTotal: BigInt('100000000'), - }); -}); - -it('uses token quantities for native, wrapped-native and LINK defaults', () => { - const eth = agenticPresets.get('STAKING', { - agent, - chainNamespace: 'eip155:1', - }).rules[0]; - expect(eth.assets?.[0]).toEqual({ +import { + defaultPresetAsset, + PRESET_GAS_BUDGETS, + PRESET_VALIDITY_SECONDS, +} from '../presets/default-policy'; + +const chainNamespace = 'eip155:84532' as const; +it('defaults to a small ETH budget, a 20 PC gas ceiling and seven days', () => { + const before = Math.floor(Date.now() / 1000); + const [rule] = agenticPresets.get('LENDING', { chainNamespace }).rules; + expect(rule.assets).toEqual([defaultPresetAsset()]); + expect(defaultPresetAsset()).toEqual({ token: zeroAddress, - maxPerCall: parseEther('0.001'), - maxTotal: parseEther('0.01'), - }); - expect( - eth.allowedCalls.find((c) => c.selector === 'submit(address)')?.maxValue - ).toBe(parseEther('0.001')); - const link = agenticPresets.get('LENDING', { agent, chainNamespace }) - .rules[0]; - expect(link.assets?.[0]).toMatchObject({ - maxPerCall: parseEther('1'), - maxTotal: parseEther('10'), - }); - const bnb = agenticPresets.get('DEXES', { - agent, - chainNamespace: 'eip155:97', - }).rules[0]; - expect(bnb.assets?.[0]).toMatchObject({ - maxPerCall: parseEther('0.01'), - maxTotal: parseEther('0.1'), + maxPerCall: parseUnits('0.001', 18), + maxTotal: parseUnits('0.01', 18), }); -}); - -it('preserves explicit expiry and gas, including a zero gas ceiling', () => { - const validUntil = Math.floor(Date.now() / 1000) + 600; - const disabled = agenticPresets.get('LENDING', { - agent, - chainNamespace, - validUntil, - maxGasPerCall: BigInt(0), - }); - expect(disabled.rules[0].validUntil).toBe(validUntil); - expect(disabled.rules[0].maxGasPerCall).toBe(BigInt(0)); - expect(disabled.readiness.ready).toBe(false); - expect(disabled.readiness.chains[0].issues.map((i) => i.code)).toEqual( - expect.arrayContaining(['GAS_BUDGET_REQUIRED', 'BRIDGE_ASSET_UNAVAILABLE']) + expect(rule.maxGasPerCall).toBe(PRESET_GAS_BUDGETS[chainNamespace]); + expect(PRESET_GAS_BUDGETS[chainNamespace]).toBe(parseUnits('20', 18)); + expect(rule.validUntil).toBeGreaterThanOrEqual( + before + PRESET_VALIDITY_SECONDS ); - expect( - agenticPresets.get('LENDING', { - agent, - chainNamespace, - maxGasPerCall: BigInt(123), - }).rules[0].maxGasPerCall - ).toBe(BigInt(123)); }); - -it('never invents caps for explicit assets, even when their address is a default', () => { - const defaults = agenticPresets.get('LENDING', { agent, chainNamespace }) - .rules[0]; - const token = defaults.assets?.[0].token; - if (!token) throw new Error('missing default asset'); - const supplied = agenticPresets.get('LENDING', { - agent, - chainNamespace, - assets: [{ token }], - }); - expect(supplied.rules[0].assets).toEqual([ - { token, maxPerCall: BigInt(0), maxTotal: BigInt(0) }, - ]); - expect(supplied.readiness.ready).toBe(false); - const totalZero = agenticPresets.get('LENDING', { - agent, - chainNamespace, - assets: [{ token, maxPerCall: BigInt(5), maxTotal: BigInt(0) }], - }); - expect(totalZero.rules[0].assets?.[0].maxTotal).toBe(BigInt(0)); - expect(totalZero.readiness.chains[0].zeroBridgeLimits).toEqual([token]); +it('preserves an explicit gas budget, including zero', () => { + for (const maxGasPerCall of [BigInt(0), parseUnits('5', 18)]) + expect( + agenticPresets.get('DEXES', { chainNamespace, maxGasPerCall }).rules[0] + .maxGasPerCall + ).toBe(maxGasPerCall); }); - -it('does not grant the default tokens on a different chain when assets is explicit', () => { - const res = agenticPresets.get('LENDING', { - agent, - assets: [{ chainNamespace, token: ADDR.other, maxPerCall: BigInt(5) }], - }); +it('returns fresh default assets so callers cannot change the policy', () => { + const a = agenticPresets.get('DEXES', { chainNamespace }).rules[0]; + a.assets![0].maxTotal = BigInt(1); expect( - res.rules - .filter((r) => r.chainNamespace !== chainNamespace) - .every((r) => r.assets?.length === 0) - ).toBe(true); - expect(res.readiness.ready).toBe(false); -}); - -it('refuses unreviewed default tokens instead of inferring permissions from symbols', () => { - expect(() => defaultPresetAsset('eip155:999', ADDR.other)).toThrow( - /No reviewed default spending policy/ - ); - expect(() => defaultPresetAsset(chainNamespace, ADDR.other)).toThrow( - /No reviewed default spending policy/ - ); + agenticPresets.get('DEXES', { chainNamespace }).rules[0].assets![0].maxTotal + ).toBe(parseUnits('0.01', 18)); }); diff --git a/packages/core/src/lib/agentic/__tests__/preset-default-tokens.spec.ts b/packages/core/src/lib/agentic/__tests__/preset-default-tokens.spec.ts deleted file mode 100644 index d8412660..00000000 --- a/packages/core/src/lib/agentic/__tests__/preset-default-tokens.spec.ts +++ /dev/null @@ -1,154 +0,0 @@ -import { getAddress } from 'viem'; -import { agenticPresets } from '../presets'; -import { buildPresetApi } from '../presets'; -import type { PresetDefinition } from '../presets/catalog'; -import { ADDR } from './fake-chain'; - -const options = { - agent: ADDR.agent, - validUntil: 2_000_000_000, - maxGasPerCall: BigInt(1), -}; - -it.each(['DEXES', 'LENDING', 'STAKING'] as const)( - '%s includes destination tokens independently on every supported network within policy limits', - (category) => { - const result = agenticPresets.get(category, options); - expect(result.rules.length).toBeGreaterThan(0); - for (const rule of result.rules) { - expect(rule.assets!.length).toBeGreaterThan(0); - expect(rule.assets!.length).toBeLessThanOrEqual(8); - expect(rule.allowedCalls.length).toBeLessThanOrEqual(32); - expect( - rule.allowedCalls.reduce((n, c) => n + (c.pins?.length ?? 0), 0) - ).toBeLessThanOrEqual(32); - expect( - rule.assets!.every( - (a) => - a.maxPerCall > BigInt(0) && - (a.maxTotal ?? BigInt(0)) >= a.maxPerCall - ) - ).toBe(true); - } - expect(result.readiness.chains.every((c) => c.configurationReady)).toBe( - true - ); - expect(result.readiness.chains.every((c) => c.configurationReady)).toBe( - true - ); - } -); - -it('selects protocol-specific testnet tokens rather than reusing the DEX pair for lending', () => { - const lending = agenticPresets.get('LENDING', { - chainNamespace: 'eip155:11155111', - }).rules[0]; - const dex = agenticPresets.get('DEXES', { chainNamespace: 'eip155:11155111' }) - .rules[0]; - expect(lending.assets!.map((a) => a.token)).toEqual([ - getAddress('0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5'), - ]); - expect(dex.assets!.map((a) => a.token)).toEqual([ - getAddress('0xfff9976782d46cc05630d1f6ebab18b2324d6b14'), - getAddress('0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238'), - ]); - expect( - agenticPresets.get('STAKING', { chainNamespace: 'eip155:11155111' }) - .rules[0].assets![0].token - ).toBe(getAddress('0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9')); -}); - -it('preserves an explicit empty list instead of silently repopulating tokens', () => { - const result = agenticPresets.get('DEXES', { ...options, assets: [] }); - expect( - result.rules.every( - (r) => r.assets?.length === 0 && r.allowedCalls.length === 2 - ) - ).toBe(true); - expect( - result.readiness.chains.every((c) => - c.issues.some((i) => i.code === 'ASSETS_REQUIRED') - ) - ).toBe(true); -}); - -it('an explicit selection replaces defaults on all chains without filling other networks', () => { - const assets = [ - { - chainNamespace: 'eip155:11155111' as const, - token: ADDR.target, - maxPerCall: BigInt(2), - }, - ]; - const result = agenticPresets.get('STAKING', { ...options, assets }); - expect( - result.rules.find((r) => r.chainNamespace === 'eip155:11155111')!.assets - ).toEqual([ - { token: ADDR.target, maxPerCall: BigInt(2), maxTotal: BigInt(0) }, - ]); - expect( - result.rules.find((r) => r.chainNamespace === 'eip155:1')!.assets - ).toEqual([]); - expect(assets).toHaveLength(1); -}); - -it('regenerates token constraints and approvals from returned default assets with supplied caps', () => { - const request = { ...options, chainNamespace: 'eip155:11155111' as const }; - const preview = agenticPresets.get('LENDING', request); - const result = agenticPresets.get('LENDING', { - ...request, - assets: preview.rules[0].assets!.map((a) => ({ - ...a, - maxPerCall: BigInt(5), - maxTotal: BigInt(10), - })), - }); - expect(result.readiness.chains.every((c) => c.configurationReady)).toBe(true); - expect( - result.rules[0].allowedCalls.every((c) => - c.pins?.some((p) => p.max === BigInt(5)) - ) - ).toBe(true); - expect(preview.rules[0].assets![0].maxPerCall).toBe(BigInt(10) ** BigInt(18)); -}); - -it('isolates defaults from returned assets, caller mutations and input catalog mutations', () => { - const catalog: PresetDefinition[] = [ - { - constant: 'STAKING', - name: 'Fixture', - chains: [ - { - chainNamespace: 'eip155:11155111', - defaultTokens: [ - getAddress('0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5'), - ], - allowedCalls: [ - { - target: ADDR.other, - selector: 'deposit(uint256)', - budget: { - kind: 'fixed-token', - token: getAddress('0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5'), - amountArg: 0, - }, - }, - ], - }, - ], - }, - ]; - const api = buildPresetApi(catalog); - const first = api.get('STAKING'); - first.rules[0].assets![0].token = ADDR.other; - first.rules[0].assets!.push({ token: ADDR.agent, maxPerCall: BigInt(1) }); - first.readiness.chains[0].knownTokens.length = 0; - catalog[0].chains[0].defaultTokens = [ADDR.other]; - expect(api.get('STAKING').rules[0].assets).toEqual([ - { - token: getAddress('0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5'), - maxPerCall: BigInt(10) ** BigInt(18), - maxTotal: BigInt(10) ** BigInt(19), - }, - ]); -}); diff --git a/packages/core/src/lib/agentic/__tests__/preset-operation-limits.spec.ts b/packages/core/src/lib/agentic/__tests__/preset-operation-limits.spec.ts index d10a4c0a..2f2240aa 100644 --- a/packages/core/src/lib/agentic/__tests__/preset-operation-limits.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/preset-operation-limits.spec.ts @@ -1,226 +1,58 @@ import { getAddress, zeroAddress } from 'viem'; -import { agenticPresets } from '../presets'; -import { AGENTIC } from '../constants'; -import { ADDR } from './fake-chain'; -const LINK = getAddress('0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5'); -const WBTC = getAddress('0x29f2D40B0605204364af54EC677bD022dA425d03'); -const chainNamespace = 'eip155:11155111' as const; -const options = { - chainNamespace, - agent: ADDR.agent, - validUntil: 2_000_000_000, - maxGasPerCall: BigInt(1), -}; -const asset = (token = LINK, limit = BigInt(5)) => ({ - token, - maxPerCall: limit, - maxTotal: BigInt(10), -}); +import { applyOperationLimits, nativeAsset } from '../presets/operation-limits'; +import type { PresetCallDefinition } from '../presets/catalog'; +import { MOVEABLE_TOKEN_CONSTANTS } from '../../constants/tokens'; -it('Aave pins the selected reserve, operation amount and wallet beneficiary for every method', () => { - const { rules, readiness } = agenticPresets.get('LENDING', { - ...options, - assets: [asset(), asset(WBTC, BigInt(7))], - }); - expect(readiness.chains[0].configurationReady).toBe(true); - expect(rules).toHaveLength(1); - for (const [selector, walletArg] of [ - ['supply(address,uint256,address,uint16)', 2], - ['withdraw(address,uint256,address)', 2], - ['borrow(address,uint256,uint256,uint16,address)', 4], - ['repay(address,uint256,uint256,address)', 3], - ] as const) { - const calls = rules[0].allowedCalls.filter((c) => c.selector === selector); - expect(calls).toHaveLength(2); - for (const [i, token] of [LINK, WBTC].entries()) { - expect(calls[i].pins).toEqual( - expect.arrayContaining([ - { arg: 0, expected: token }, - { arg: 1, max: i ? BigInt(7) : BigInt(5) }, - { arg: walletArg, expected: AGENTIC.WALLET }, - ]) - ); - expect(calls[i]).not.toHaveProperty('budget'); - } - } -}); -it('default lending policy needs only the agent to become locally ready', () => { - const result = agenticPresets.get('LENDING', { chainNamespace }); - expect(result.readiness.ready).toBe(false); - expect(result.readiness.chains[0].issues.map((i) => i.code)).toEqual( - expect.arrayContaining(['AGENT_REQUIRED', 'BRIDGE_ASSET_UNAVAILABLE']) - ); - expect(result.rules[0].assets).toEqual([ +const target = getAddress('0x0000000000000000000000000000000000001234'); +it('maps the native cap onto maxValue and amount pins and leaves fixed calls unchanged', () => { + const definitions: PresetCallDefinition[] = [ + { target, selector: 'deposit()', budget: { kind: 'native-value' } }, + { + target, + selector: 'approve(address,uint256)', + pins: [{ arg: 0, expected: target }], + budget: { kind: 'native-amount', amountArg: 1 }, + }, + { + target, + selector: 'swap((address,uint256))', + budget: { kind: 'native-amount', amountArg: [0, 1] }, + }, + { + target, + selector: 'fixed(uint256)', + pins: [{ arg: 0, max: BigInt(9) }], + }, + ]; + const calls = applyOperationLimits(definitions, BigInt(7)); + expect(calls).toEqual([ + { target, selector: 'deposit()', maxValue: BigInt(7) }, + { + target, + selector: 'approve(address,uint256)', + pins: [ + { arg: 0, expected: target }, + { arg: 1, max: BigInt(7) }, + ], + }, { - token: LINK, - maxPerCall: BigInt(10) ** BigInt(18), - maxTotal: BigInt(10) ** BigInt(19), + target, + selector: 'swap((address,uint256))', + pins: [{ arg: [0, 1], max: BigInt(7) }], }, + { target, selector: 'fixed(uint256)', pins: [{ arg: 0, max: BigInt(9) }] }, ]); - expect(result.rules[0].validUntil).toBeGreaterThan( - Math.floor(Date.now() / 1000) - ); - expect(result.rules[0].maxGasPerCall).toBe( - BigInt(20) * BigInt(10) ** BigInt(18) - ); - expect(result.readiness.chains[0].knownTokens).toContain(LINK); - expect( - agenticPresets.get('LENDING', { - chainNamespace, - agent: ADDR.agent, - }).readiness.chains[0].configurationReady - ).toBe(true); -}); -it('zero operation caps remain valid disabled configurations, while zero bridge totals are separately reported', () => { - const disabled = agenticPresets.get('LENDING', { - ...options, - assets: [{ token: LINK }], - }); - expect(disabled.readiness.ready).toBe(false); - expect( - disabled.readiness.chains[0].disabledCalls.every( - (c) => c.reason === 'ZERO_CAP' - ) - ).toBe(true); - const enabled = agenticPresets.get('LENDING', { - ...options, - assets: [{ token: LINK, maxPerCall: BigInt(5) }], - }); - expect(enabled.readiness.chains[0].configurationReady).toBe(true); - expect(enabled.readiness.chains[0].zeroBridgeLimits).toEqual([LINK]); - expect(enabled.rules[0].assets?.[0].maxTotal).toBe(BigInt(0)); -}); -it('does not approve or grant a positive amount for an unlisted Aave asset', () => { - const { rules, readiness } = agenticPresets.get('LENDING', { - ...options, - assets: [asset(ADDR.other)], - }); - expect(readiness.ready).toBe(false); - expect( - rules[0].allowedCalls.some((c) => c.selector.startsWith('approve')) - ).toBe(false); - expect( - rules[0].allowedCalls.every((c) => c.pins?.some((p) => p.max === BigInt(0))) - ).toBe(true); + expect(calls.some((c) => 'budget' in c)).toBe(false); + expect(definitions[1].pins).toHaveLength(1); }); -it('regenerating a token/limit replaces old operation and approval constraints without mutating the old template', () => { - const first = agenticPresets.get('LENDING', { - ...options, - assets: [asset()], - }); - const next = agenticPresets.get('LENDING', { - ...options, - assets: [asset(WBTC, BigInt(2))], - }); +it('recognizes the zero address and native moveable tokens as ETH', () => { + const max = BigInt(1); + expect(nativeAsset({ token: zeroAddress, maxPerCall: max })).toBe(true); expect( - next.rules[0].allowedCalls.some( - (c) => c.target === LINK || c.pins?.some((p) => p.expected === LINK) - ) - ).toBe(false); - expect( - next.rules[0].allowedCalls.every((c) => - c.pins?.some((p) => p.max === BigInt(2)) - ) - ).toBe(true); - expect( - first.rules[0].allowedCalls.every((c) => - c.pins?.some((p) => p.max === BigInt(5)) - ) - ).toBe(true); -}); -it('Moonwell applies underlying units and reports the share-based redeem alternative', () => { - const token = getAddress('0x4616975f7E6045FD9737e95bC527e9e14c727BD2'); - const { rules, readiness } = agenticPresets.get('LENDING', { - ...options, - chainNamespace: 'eip155:84532', - assets: [asset(token)], - }); - const calls = rules[0].allowedCalls.filter( - (c) => c.app === 'Moonwell mUSDbC' && !c.selector.startsWith('approve') - ); - expect(calls.map((c) => c.selector)).toEqual([ - 'mint(uint256)', - 'redeemUnderlying(uint256)', - 'borrow(uint256)', - 'repayBorrow(uint256)', - ]); - expect( - calls.every((c) => c.pins?.some((p) => p.arg === 0 && p.max === BigInt(5))) - ).toBe(true); - expect(readiness.chains[0].excludedCalls).toContainEqual( - expect.objectContaining({ - selector: 'redeem(uint256)', - reason: 'SHARE_AMOUNT', - alternative: 'redeemUnderlying(uint256)', + nativeAsset({ + token: MOVEABLE_TOKEN_CONSTANTS.ARBITRUM_SEPOLIA.ETH, + maxPerCall: max, }) - ); -}); -it('EigenLayer pins the chosen token and deposit amount', () => { - const { rules } = agenticPresets.get('STAKING', { - ...options, - assets: [asset()], - }); - const deposit = rules[0].allowedCalls.find((c) => - c.selector.startsWith('depositIntoStrategy') - )!; - expect(deposit.pins).toEqual([ - { arg: 1, expected: LINK }, - { arg: 2, max: BigInt(5) }, - ]); -}); -it('Lido distinguishes stETH, wstETH and native value units', () => { - const stETH = getAddress('0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84'), - wstETH = getAddress('0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0'); - const { rules } = agenticPresets.get('STAKING', { - ...options, - chainNamespace: 'eip155:1', - assets: [ - asset(stETH, BigInt(2)), - asset(wstETH, BigInt(3)), - asset(zeroAddress, BigInt(4)), - ], - }); - expect( - rules[0].allowedCalls.find((c) => c.selector === 'wrap(uint256)')?.pins - ).toEqual([{ arg: 0, max: BigInt(2) }]); - expect( - rules[0].allowedCalls.find((c) => c.selector === 'unwrap(uint256)')?.pins - ).toEqual([{ arg: 0, max: BigInt(3) }]); - expect( - rules[0].allowedCalls.find((c) => c.selector === 'submit(address)') - ?.maxValue - ).toBe(BigInt(4)); -}); -it('readiness is per chain and cannot be mutated to change later results', () => { - const res = agenticPresets.get('LENDING', { - agent: options.agent, - validUntil: options.validUntil, - maxGasPerCall: options.maxGasPerCall, - assets: [{ ...asset(), chainNamespace }], - }); - expect(res.readiness.ready).toBe(false); - expect( - res.readiness.chains.find((c) => c.chainNamespace === chainNamespace) - ?.configurationReady ).toBe(true); - const expected = agenticPresets.get('LENDING', { chainNamespace }).readiness; - res.readiness.chains.forEach((c) => { - c.knownTokens.length = 0; - c.disabledCalls.length = 0; - }); - expect(agenticPresets.get('LENDING', { chainNamespace }).readiness).toEqual( - expected - ); -}); -it('refuses an overlarge token expansion without dropping restrictions', () => { - expect(() => - agenticPresets.get('LENDING', { - ...options, - assets: [ - asset(), - asset(WBTC), - asset(getAddress('0x88541670E55cC00bEEFD87eB59EDd1b7C511AC9a')), - ], - }) - ).toThrow(/maximum is 32/); + expect(nativeAsset({ token: target, maxPerCall: max })).toBe(false); }); diff --git a/packages/core/src/lib/agentic/__tests__/preset-routes.spec.ts b/packages/core/src/lib/agentic/__tests__/preset-routes.spec.ts index c64ccee5..73ff0e81 100644 --- a/packages/core/src/lib/agentic/__tests__/preset-routes.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/preset-routes.spec.ts @@ -1,153 +1,43 @@ +import { getAddress } from 'viem'; import { agenticPresets } from '../presets'; -import { CHAIN, PUSH_NETWORK } from '../../constants/enums'; -import { MOVEABLE_TOKEN_CONSTANTS } from '../../constants/tokens'; -import { ADDR } from './fake-chain'; +import { PUSH_NETWORK } from '../../constants/enums'; +import { SYNTHETIC_PUSH_ERC20 } from '../../constants/chain'; +import { resolveAgenticPrc20 } from '../token-routes'; +import { assetAddress } from '../presets/operation-limits'; -const options = { chainNamespace: CHAIN.ETHEREUM_SEPOLIA, agent: ADDR.agent }; -it('reports unmapped source tokens without silently changing the default Push grant', () => { - const res = agenticPresets.get('LENDING', options); - expect(res.readiness.ready).toBe(false); - const state = res.readiness.chains[0]; - expect(state.configurationReady).toBe(true); - expect(state.issues).toContainEqual( - expect.objectContaining({ - code: 'BRIDGE_ASSET_UNAVAILABLE', - token: '0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5', - }) +// Presets ship only what Push can send today, so this offline check replaces +// the removed readiness report: every default asset resolves to a Push PRC20. +const GAS_PRC20 = { + 'eip155:11155111': 'pETH', + 'eip155:84532': 'pETH_BASE', + 'eip155:421614': 'pETH_ARB', +} as const; +it.each( + agenticPresets + .list() + .presets.flatMap((p) => p.chains.map((c) => [p.constant, c] as const)) +)('%s %s sends only ETH, routed as the chain gas PRC20', (preset, chain) => { + const { rules } = agenticPresets.get(preset, { chainNamespace: chain }); + expect(rules[0].assets).toHaveLength(1); + const prc20 = resolveAgenticPrc20( + { chain, address: assetAddress(rules[0].assets![0]) }, + PUSH_NETWORK.TESTNET_DONUT ); - expect(res.rules[0].assets).toEqual(state.selectedAssets); - expect(res.rules[0].assets).toHaveLength(1); -}); -it('preserves assets and rejects the removed funding option instead of silently changing permissions', () => { - const result = agenticPresets.get('DEXES', options); - // WETH and Circle USDC both have exact node routes on Sepolia. - expect(result.readiness.ready).toBe(true); - expect(result.rules[0].assets).toEqual( - result.readiness.chains[0].selectedAssets + expect(prc20.address).toBe( + getAddress( + SYNTHETIC_PUSH_ERC20[PUSH_NETWORK.TESTNET_DONUT][ + GAS_PRC20[chain as keyof typeof GAS_PRC20] + ] + ) ); - result.readiness.chains[0].selectedAssets[0].maxPerCall = BigInt(0); - expect(result.rules[0].assets?.[0].maxPerCall).toBeGreaterThan(BigInt(0)); - for (const funding of ['push', 'destination', 'auto']) { +}); +it('rejects the removed funding option instead of silently changing permissions', () => { + for (const funding of ['push', 'destination', 'auto']) expect(() => agenticPresets.get('DEXES', { - ...options, + chainNamespace: 'eip155:11155111', // @ts-expect-error funding is not part of the public preset API funding, }) ).toThrow(/funding option is no longer supported/); - } -}); -it('an explicitly selected mapped source token can be ready for Push funding', () => { - const token = MOVEABLE_TOKEN_CONSTANTS.BNB_TESTNET.USDT; - const res = agenticPresets.get('DEXES', { - chainNamespace: CHAIN.BNB_TESTNET, - agent: ADDR.agent, - assets: [ - { - token: MOVEABLE_TOKEN_CONSTANTS.BNB_TESTNET.USDC, - maxPerCall: BigInt(5), - maxTotal: BigInt(10), - }, - { token, maxPerCall: BigInt(5), maxTotal: BigInt(10) }, - ], - }); - expect(res.readiness.ready).toBe(true); - expect( - res.readiness.chains[0].bridgeAssets.every((a) => a.status === 'registered') - ).toBe(true); -}); -it('never treats a mainnet template or undeployed Push generation as executable', () => { - const mainnet = agenticPresets.get('DEXES', { - agent: ADDR.agent, - chainNamespace: CHAIN.ETHEREUM_MAINNET, - }); - expect(mainnet.readiness.ready).toBe(false); - expect(mainnet.readiness.chains[0].issues).toContainEqual( - expect.objectContaining({ code: 'DESTINATION_UNAVAILABLE' }) - ); - const missing = agenticPresets.get('LENDING', { - ...options, - network: PUSH_NETWORK.MAINNET, - }); - expect(missing.readiness.ready).toBe(false); - expect(missing.readiness.chains[0].issues).toContainEqual( - expect.objectContaining({ code: 'AGW_NETWORK_UNAVAILABLE' }) - ); -}); -it('supports the TESTNET alias, rejects invalid modes and preserves empty selections', () => { - expect( - agenticPresets.get('LENDING', { - ...options, - network: PUSH_NETWORK.TESTNET, - }).readiness - ).toEqual(agenticPresets.get('LENDING', options).readiness); - expect(() => - agenticPresets.get('LENDING', { ...options, network: 'OTHER' as never }) - ).toThrow(/network/); - const empty = agenticPresets.get('LENDING', { - ...options, - assets: [], - }); - expect(empty.readiness.chains[0].selectedAssets).toEqual([]); - expect(empty.readiness.ready).toBe(false); -}); - -it('explains empty tokens without expanding them into unrestricted permissions', () => { - const res = agenticPresets.get('LENDING', { ...options, assets: [] }); - expect(res.rules[0].assets).toEqual([]); - expect(res.readiness.ready).toBe(false); - expect(res.readiness.chains[0].issues).toContainEqual( - expect.objectContaining({ - code: 'ASSETS_REQUIRED', - message: expect.stringContaining( - 'transfers from Push are disabled, not unrestricted' - ), - }) - ); -}); -it('reports exact unavailable assets across all nine testnet preset combinations', () => { - const chains = [ - CHAIN.ETHEREUM_SEPOLIA, - CHAIN.BASE_SEPOLIA, - CHAIN.ARBITRUM_SEPOLIA, - CHAIN.BNB_TESTNET, - ]; - const routed = new Set([ - `DEXES:${CHAIN.ETHEREUM_SEPOLIA}`, - `LENDING:${CHAIN.ARBITRUM_SEPOLIA}`, - ]); - let checked = 0; - for (const category of ['DEXES', 'LENDING', 'STAKING'] as const) { - const entry = agenticPresets - .list() - .presets.find((p) => p.constant === category)!; - for (const chainNamespace of entry.chains.filter((c) => - chains.includes(c as never) - )) { - const res = agenticPresets.get(category, { - agent: ADDR.agent, - chainNamespace, - }); - expect(res.readiness.ready).toBe( - routed.has(`${category}:${chainNamespace}`) - ); - const state = res.readiness.chains[0]; - expect(res.rules[0].assets).toEqual(state.selectedAssets); - for (const asset of state.bridgeAssets.filter( - (a) => a.status === 'unavailable' - )) { - expect(state.issues).toContainEqual( - expect.objectContaining({ - code: 'BRIDGE_ASSET_UNAVAILABLE', - token: asset.token, - message: expect.stringContaining( - 'only if the selected app supports that exact token address' - ), - }) - ); - } - checked++; - } - } - expect(checked).toBe(9); }); diff --git a/packages/core/src/lib/agentic/__tests__/presets.spec.ts b/packages/core/src/lib/agentic/__tests__/presets.spec.ts index 9ea62bad..d8bc29f2 100644 --- a/packages/core/src/lib/agentic/__tests__/presets.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/presets.spec.ts @@ -1,8 +1,9 @@ import { getAddress, zeroAddress } from 'viem'; import { AGENTIC } from '../constants'; -import { agenticPresets, buildPresetApi } from '../presets'; +import { buildPresetApi } from '../presets'; import type { PresetDefinition } from '../presets/catalog'; import type { Rule } from '../agentic.types'; +import { MOVEABLE_TOKEN_CONSTANTS } from '../../constants/tokens'; import { normalizePublicRule, publicRules } from '../public-rule'; import { FakeChain, ADDR } from './fake-chain'; import { mockRuntime } from './mock-runtime'; @@ -12,6 +13,11 @@ const target = getAddress('0x0000000000000000000000000000000000001234'); const token = getAddress('0x000000000000000000000000000000000000abcd'); const agent = getAddress('0x000000000000000000000000000000000000a999'); const until = () => Math.floor(Date.now() / 1000) + 3600; +const eth = (maxPerCall = BigInt(5), maxTotal = BigInt(10)) => ({ + token: zeroAddress, + maxPerCall, + maxTotal, +}); function catalog(): PresetDefinition[] { return [ { @@ -23,13 +29,18 @@ function catalog(): PresetDefinition[] { allowedCalls: [ { target, - selector: 'deposit(address,uint256)', + selector: 'deposit()', + budget: { kind: 'native-value' }, + }, + { + target, + selector: 'lend(address,uint256)', pins: [{ arg: 0, expected: AGENTIC.WALLET }], app: 'Fixture', - label: 'Deposit', + label: 'Lend', + budget: { kind: 'native-amount', amountArg: 1 }, }, ], - approvals: [{ spender: target, app: 'Fixture' }], }, { chainNamespace: other, @@ -45,91 +56,52 @@ function catalog(): PresetDefinition[] { }, ]; } -it('ships verified mainnet and testnet templates and keeps prediction empty', () => { - expect(Object.values(AGENTIC.PRESETS.CATEGORY)).toEqual([ - 'DEXES', - 'LENDING', - 'STAKING', - 'PREDICTION', - ]); - const entries = agenticPresets.list().presets; - expect(entries.map((p) => [p.constant, p.chains.length])).toEqual([ - ['DEXES', 8], - ['LENDING', 8], - ['STAKING', 2], - ['PREDICTION', 0], - ]); - expect( - entries - .flatMap((p) => p.chains) - .every((c) => - [ - 'eip155:1', - 'eip155:8453', - 'eip155:42161', - 'eip155:56', - 'eip155:11155111', - 'eip155:84532', - 'eip155:421614', - 'eip155:97', - ].includes(c) - ) - ).toBe(true); - expect(agenticPresets.get('PREDICTION')).toEqual({ - rules: [], - readiness: { ready: false, chains: [] }, - }); - expect(agenticPresets.get('DEXES').rules).toHaveLength(8); - expect(() => - agenticPresets.get('LENDING', { chainNamespace: 'eip155:999999' }) - ).toThrow(/no approved entry/); -}); -it('groups apps on a chain into one editable template with default expiry and omitted identity', () => { - const data = catalog(); - data[0].chains[0].allowedCalls = [ - ...data[0].chains[0].allowedCalls, - { - target: ADDR.other, - selector: 'lend(address)', - pins: [{ arg: 0, expected: AGENTIC.WALLET }], - }, - ]; - const api = buildPresetApi(data), +it('returns one editable template per chain with default ETH limits, expiry and no identity', () => { + const api = buildPresetApi(catalog()), res = api.get('DEXES'); + expect(Object.keys(res)).toEqual(['rules']); expect(res.rules.map((r) => r.chainNamespace)).toEqual([chain, other]); - expect(res.rules[0].allowedCalls).toHaveLength(2); for (const rule of res.rules) { expect(rule).not.toHaveProperty('agent'); - expect(rule).not.toHaveProperty('assets'); + expect(rule.assets).toHaveLength(1); + expect(rule.assets![0].token).toBe(zeroAddress); expect(rule.validUntil).toBeGreaterThan(Math.floor(Date.now() / 1000)); } + const max = res.rules[0].assets![0].maxPerCall; + expect(res.rules[0].allowedCalls[0].maxValue).toBe(max); + expect(res.rules[0].allowedCalls[1].pins).toEqual([ + { arg: 0, expected: AGENTIC.WALLET }, + { arg: 1, max }, + ]); expect(api.list({ type: 'CATEGORY' }).presets[0].chains).toEqual([ chain, other, ]); }); -it('returns ready Rule types with identity and expiry; routes assets and defaults missing caps to zero', () => { - const api = buildPresetApi(catalog()); - const { rules } = api.get('DEXES', { +it('returns ready Rule types with identity and expiry and places each ETH asset on its chain', () => { + const { rules } = buildPresetApi(catalog()).get('DEXES', { agent, validUntil: until(), assets: [ - { chainNamespace: chain, token }, + { chainNamespace: chain, ...eth(BigInt(2), BigInt(3)) }, { chainNamespace: other, - token: zeroAddress, - maxPerCall: BigInt(2), - maxTotal: BigInt(3), + token: MOVEABLE_TOKEN_CONSTANTS.BASE_SEPOLIA.ETH, + maxPerCall: BigInt(4), + maxTotal: BigInt(8), }, ], }); const typed: Rule[] = rules; - expect(typed[0].assets).toEqual([ - { token, maxPerCall: BigInt(0), maxTotal: BigInt(0) }, - ]); + expect(typed[0].assets).toEqual([eth(BigInt(2), BigInt(3))]); expect(typed[1].assets).toEqual([ - { token: zeroAddress, maxPerCall: BigInt(2), maxTotal: BigInt(3) }, + { + token: { ...MOVEABLE_TOKEN_CONSTANTS.BASE_SEPOLIA.ETH }, + maxPerCall: BigInt(4), + maxTotal: BigInt(8), + }, ]); + expect(typed[0].allowedCalls[0].maxValue).toBe(BigInt(2)); expect(typed.every((r) => r.agent === agent && r.validUntil > 0)).toBe(true); }); it('does not type an incomplete template as a ready rule', () => { @@ -138,72 +110,65 @@ it('does not type an incomplete template as a ready rule', () => { const ready: Rule[] = rules; expect(ready[0].agent).toBeUndefined(); }); -it('adds only spender-pinned and amount-bounded ERC20 approvals; native assets have none', () => { - const { rules } = buildPresetApi(catalog()).get('DEXES', { - chainNamespace: chain, - assets: [ - { token, maxPerCall: BigInt(5), maxTotal: BigInt(10) }, - { token: zeroAddress, maxPerCall: BigInt(1) }, - ], - }); - expect(rules).toHaveLength(1); - expect(rules[0].allowedCalls).toHaveLength(2); - expect(rules[0].allowedCalls[1]).toMatchObject({ - target: token, - selector: 'approve(address,uint256)', - pins: [ - { arg: 0, expected: target }, - { arg: 1, max: BigInt(5) }, - ], - }); - expect(rules[0].assets![0]).not.toHaveProperty('chainNamespace'); -}); it('does not mutate caller assets, returned records, or the bundled catalog', () => { const data = catalog(); const api = buildPresetApi(data); const asset = { - token: { - address: token, - symbol: 'TEST', - decimals: 6, - mechanism: 'approve' as const, - }, + token: { ...MOVEABLE_TOKEN_CONSTANTS.ETHEREUM_SEPOLIA.ETH }, + maxPerCall: BigInt(5), + maxTotal: BigInt(10), }; const first = api.get('DEXES', { chainNamespace: chain, assets: [asset] }); - first.rules[0].allowedCalls[0].pins![0] = { arg: 0, expected: zeroAddress }; - (first.rules[0].assets![0].token as { address: string }).address = - zeroAddress; + first.rules[0].allowedCalls[1].pins![0] = { arg: 0, expected: zeroAddress }; + (first.rules[0].assets![0].token as { symbol: string }).symbol = 'X'; api.list().presets[0].chains.length = 0; - data[0].chains[0].allowedCalls[0].target = zeroAddress; - expect(asset.token.address).toBe(token); - expect(api.get('DEXES').rules[0].allowedCalls[0]).toMatchObject({ + data[0].chains[0].allowedCalls[1].target = zeroAddress; + expect(asset.token.symbol).toBe('ETH'); + expect(api.get('DEXES').rules[0].allowedCalls[1]).toMatchObject({ target, - pins: [{ arg: 0, expected: AGENTIC.WALLET }], + pins: [{ arg: 0, expected: AGENTIC.WALLET }, { arg: 1 }], }); expect(api.list().presets[0].chains).toHaveLength(2); }); it.each([ - { assets: [{ token }] }, - { chainNamespace: chain, assets: [{ chainNamespace: other, token }] }, - { - chainNamespace: chain, - assets: [{ token }, { token: token.toUpperCase().replace('0X', '0x') }], - }, - { chainNamespace: chain, assets: [{ token, maxPerCall: BigInt(-1) }] }, - { - chainNamespace: chain, - assets: [{ token, maxTotal: BigInt(1) << BigInt(256) }], - }, - { agent: zeroAddress }, - { validUntil: 1 }, - { validUntil: 1.5 }, - { assets: [null] }, + [{ assets: [eth()] }, /needs chainNamespace/], + [ + { chainNamespace: chain, assets: [{ chainNamespace: other, ...eth() }] }, + /outside the selected preset/, + ], + [{ chainNamespace: chain, assets: [eth(), eth()] }, /duplicate/], + [ + { chainNamespace: chain, assets: [{ ...eth(), token }] }, + /only ETH from Push/, + ], + [{ chainNamespace: chain, assets: [{ token: zeroAddress }] }, /uint256/], + [ + { chainNamespace: chain, assets: [eth(BigInt(0), BigInt(1))] }, + /positive maxPerCall and maxTotal/, + ], + [ + { chainNamespace: chain, assets: [eth(BigInt(-1))] }, + /maxPerCall must be a uint256/, + ], + [ + { + chainNamespace: chain, + assets: [eth(BigInt(1), BigInt(1) << BigInt(256))], + }, + /maxTotal must be a uint256/, + ], + [{ chainNamespace: chain, assets: [] }, /Add an ETH asset/], + [{ assets: [{ chainNamespace: chain, ...eth() }] }, /Add an ETH asset/], + [{ agent: zeroAddress }, /nonzero Push address/], + [{ validUntil: 1 }, /future uint48/], + [{ validUntil: 1.5 }, /future uint48/], + [{ assets: [null] }, /must be an object/], ])( 'rejects malformed or mismatched options before returning templates (case %#)', - (options) => { + (options, error) => { expect(() => buildPresetApi(catalog()).get('DEXES', options as never) - ).toThrow(); + ).toThrow(error); } ); it('rejects unknown presets, unsupported list types and unsupported chain filters', () => { @@ -214,34 +179,14 @@ it('rejects unknown presets, unsupported list types and unsupported chain filter /no approved entry/ ); }); -it('produces separate pinned alternatives for multiple spenders', () => { - const data = catalog(); - data[0].chains[0].approvals = [ - { spender: target, app: 'One' }, - { spender: ADDR.other, app: 'Two' }, - ]; - const result = buildPresetApi(data).get('DEXES', { - chainNamespace: chain, - assets: [{ token }], - }); - expect( - result.rules[0].allowedCalls.filter( - (c) => c.selector === 'approve(address,uint256)' - ) - ).toHaveLength(2); -}); -it('enforces the 32-call ceiling including generated approvals', () => { +it('enforces the 32-call ceiling', () => { const data = catalog(); - data[0].chains[0].allowedCalls = Array.from({ length: 32 }, (_, i) => ({ + data[0].chains[0].allowedCalls = Array.from({ length: 33 }, (_, i) => ({ target, selector: `fn${i}()`, })); - const api = buildPresetApi(data); - expect( - api.get('DEXES', { chainNamespace: chain }).rules[0].allowedCalls - ).toHaveLength(32); expect(() => - api.get('DEXES', { chainNamespace: chain, assets: [{ token }] }) + buildPresetApi(data).get('DEXES', { chainNamespace: chain }) ).toThrow(/1..32/); }); it('requires full signatures and rejects duplicate function entries', () => { @@ -256,25 +201,21 @@ it('requires full signatures and rejects duplicate function entries', () => { /unpinned alternative/ ); }); -it('compiles preset spender and amount pins with the deployed v6 policy', async () => { +it('compiles preset value and amount caps with the deployed v6 policy', async () => { const { rules } = buildPresetApi(catalog()).get('DEXES', { chainNamespace: chain, agent, validUntil: until(), - assets: [{ token, maxPerCall: BigInt(5) }], + assets: [eth()], }); - const normalized = await normalizePublicRule( + const normalized = (await normalizePublicRule( publicRules(rules)[0], ADDR.other, mockRuntime(new FakeChain()) - ); - expect( - ( - normalized as import('../agentic.types').UniversalRule - ).allowedCalls[1].pins?.map((p) => p.op) - ).toEqual([0, 1]); + )) as import('../agentic.types').UniversalRule; + expect(normalized.allowedCalls[0].maxValue).toBe(BigInt(5)); + expect(normalized.allowedCalls[1].pins?.map((p) => p.op)).toEqual([0, 1]); }); - it('keeps OR alternatives EVM-only: repeated Solana instructions are refused', () => { const api = buildPresetApi([ { diff --git a/packages/core/src/lib/agentic/__tests__/response-surface.spec.ts b/packages/core/src/lib/agentic/__tests__/response-surface.spec.ts index 19d26627..7cb5fceb 100644 --- a/packages/core/src/lib/agentic/__tests__/response-surface.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/response-surface.spec.ts @@ -2,6 +2,7 @@ import { encodeErrorResult, encodeFunctionData, getAddress, + toFunctionSelector, type Hex, } from 'viem'; import * as core from '../../index'; @@ -189,6 +190,22 @@ describe('revert decoding', () => { }); }); + it.each([ + [ + 'InnerValueExceedsAllowance', + 'InnerValueExceedsAllowance(uint256,uint256,uint256)', + ], + ['BeneficiaryMismatch', 'BeneficiaryMismatch(address,address)'], + ])( + 'names %s, which URP encodes by selector and its ABI omits', + (name, signature) => { + const inner = toFunctionSelector(`function ${signature}`).slice(2); + expect( + decodeAgwErrorData(`0xf4270752${inner.padEnd(64, '0')}`) + ).toMatchObject({ name: `PolicyCheckReverted(${name})` }); + } + ); + it('finds revert data through error causes and viem-style messages', () => { const inner = new Error('outer', { cause: { @@ -225,7 +242,7 @@ describe('public surface', () => { expect(new AgenticRevertError('x', { cause: 'c' }).cause).toBe('c'); }); - it('exposes the wallet marker and preset API, keeping deployment wiring and codecs internal', () => { + it('exposes the wallet marker, preset API and ALL asset helper, keeping deployment wiring and codecs internal', () => { expect(CONSTANTS.AGENTIC.WALLET).toBe('agentic:wallet'); expect(Object.keys(CONSTANTS.AGENTIC).sort()).toEqual([ 'JOB', @@ -234,7 +251,9 @@ describe('public surface', () => { 'WALLET', ]); expect(Object.isFrozen(CONSTANTS.AGENTIC)).toBe(true); - expect(Object.keys(Utils.agentic)).toEqual(['presets']); + expect(Object.keys(Utils.agentic)).toEqual(['presets', 'assets']); expect(Object.keys(Utils.agentic.presets).sort()).toEqual(['get', 'list']); + expect(Object.keys(Utils.agentic.assets)).toEqual(['all']); + expect(Object.isFrozen(Utils.agentic.assets)).toBe(true); }); }); diff --git a/packages/core/src/lib/agentic/__tests__/rule-inputs.spec.ts b/packages/core/src/lib/agentic/__tests__/rule-inputs.spec.ts new file mode 100644 index 00000000..45862996 --- /dev/null +++ b/packages/core/src/lib/agentic/__tests__/rule-inputs.spec.ts @@ -0,0 +1,301 @@ +import { getAddress, parseUnits, zeroAddress } from 'viem'; +import { CHAIN } from '../../constants/enums'; +import { + MOVEABLE_TOKEN_CONSTANTS, + MOVEABLE_TOKENS, +} from '../../constants/tokens'; +import { Utils } from '../../utils'; +import { allRoutableAssets, prepareRuleInput } from '../management/rule-inputs'; +import { normalizePublicRule, publicRules } from '../public-rule'; +import type { AuthoredRule, RuleInput, UniversalRule } from '../agentic.types'; +import type { Snapshot } from '../reads/snapshot'; +import { ADDR, FakeChain } from './fake-chain'; +import { mockRuntime } from './mock-runtime'; + +const SEPOLIA = MOVEABLE_TOKEN_CONSTANTS.ETHEREUM_SEPOLIA; +const CIRCLE_SEPOLIA = getAddress('0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238'); +const snap = {} as Snapshot; +const base = (over: Partial = {}): AuthoredRule => ({ + agent: ADDR.agent, + chainNamespace: 'eip155:11155111', + validUntil: 2_000_000_000, + maxGasPerCall: BigInt(1), + ...over, +}); +const prepare = ( + rule: RuleInput, + rt = mockRuntime(new FakeChain(), { signer: ADDR.owner }) +) => + prepareRuleInput( + publicRules([rule])[0], + rt, + ADDR.owner, + snap + ) as unknown as Promise; +const addressOf = (token: unknown) => + typeof token === 'string' ? token : (token as { address: string }).address; + +describe('MOVEABLE ALL', () => { + it('lists every token Push can send to Sepolia, .old Circle USDC separately', () => { + const assets = allRoutableAssets('eip155:11155111'); + expect(assets.map((a) => addressOf(a.token))).toEqual([ + zeroAddress, + SEPOLIA.USDT.address, + SEPOLIA.USDC.address, + SEPOLIA.WETH.address, + SEPOLIA.stETH.address, + CIRCLE_SEPOLIA, + ]); + expect(assets[0]).toMatchObject({ + maxPerCall: parseUnits('0.001', 18), + maxTotal: parseUnits('0.01', 18), + }); + expect(assets[5]).toEqual({ + token: CIRCLE_SEPOLIA, + maxPerCall: parseUnits('10', 6), + maxTotal: parseUnits('100', 6), + }); + }); + it.each( + Object.keys(MOVEABLE_TOKENS).filter( + (c) => c !== CHAIN.PUSH_TESTNET_DONUT && c !== CHAIN.ETHEREUM_MAINNET + ) + )('expands %s within eight routable tokens, each with a default', (chain) => { + const assets = allRoutableAssets(chain); + expect(assets.length).toBeGreaterThan(0); + expect(assets.length).toBeLessThanOrEqual(8); + expect( + assets.every((a) => a.maxPerCall > BigInt(0) && a.maxTotal! > BigInt(0)) + ).toBe(true); + }); + it('leaves out registry tokens without a Push route', () => { + const base = allRoutableAssets('eip155:84532').map((a) => + addressOf(a.token).toLowerCase() + ); + // Base Sepolia WETH is in the registry but has no PRC20. + expect(base).not.toContain('0x4200000000000000000000000000000000000006'); + expect(base).toHaveLength(4); + }); + it('is the public helper and the marker comes from the token constants', () => { + expect(Utils.agentic.assets.all('eip155:421614')).toEqual( + allRoutableAssets('eip155:421614') + ); + expect(SEPOLIA.ALL).toEqual({ kind: 'ALL', chain: CHAIN.ETHEREUM_SEPOLIA }); + expect(Object.isFrozen(SEPOLIA.ALL)).toBe(true); + }); + it('expands in a rule, and a listed token replaces its default', async () => { + const usdc = { + token: SEPOLIA.USDC, + maxPerCall: BigInt(3), + maxTotal: BigInt(9), + }; + const out = await prepare( + base({ + assets: [{ token: SEPOLIA.ALL }, usdc], + allowedCalls: [{ target: ADDR.target, selector: 'increment()' }], + }) + ); + expect(out.assets).toHaveLength(6); + expect(out.assets![2]).toBe(usdc); + expect(out.allowedCalls).toHaveLength(1); + }); + it.each([ + [ + { assets: [{ token: SEPOLIA.ALL, maxPerCall: BigInt(1) }] }, + { code: 'INVALID_RULE', details: { reason: 'ALL_WITH_LIMITS' } }, + ], + [ + { + chainNamespace: 'eip155:84532' as const, + assets: [{ token: SEPOLIA.ALL }], + }, + { code: 'ASSET_CHAIN_MISMATCH' }, + ], + ])( + 'refuses ALL with limits or for another chain (case %#)', + async (over, error) => { + await expect( + prepare(base({ allowedCalls: [], ...over } as never)) + ).rejects.toMatchObject(error); + } + ); + it('refuses an unexpanded marker if normalization is reached directly', async () => { + await expect( + normalizePublicRule( + publicRules([ + base({ + assets: [{ token: SEPOLIA.ALL }], + allowedCalls: [{ target: ADDR.target, selector: 'increment()' }], + }), + ])[0], + ADDR.other, + mockRuntime(new FakeChain()) + ) + ).rejects.toThrow(/expand MOVEABLE ALL/); + }); +}); + +describe('tokens-only rules', () => { + const usdc = { + token: SEPOLIA.USDC, + maxPerCall: BigInt(5), + maxTotal: BigInt(9), + }; + it('allows each ERC20 only back to the owner, capped per transfer', async () => { + for (const allowedCalls of [undefined, []]) { + const out = await prepare(base({ assets: [usdc], allowedCalls })); + expect(out.allowedCalls).toEqual([ + { + target: getAddress(SEPOLIA.USDC.address), + selector: 'transfer(address,uint256)', + pins: [ + { arg: 0, expected: ADDR.owner }, + { arg: 1, max: BigInt(5) }, + ], + app: 'Token transfer', + label: 'Transfer to owner', + }, + ]); + expect(out).not.toHaveProperty('transferTo'); + } + }); + it('adds named recipients as opt-in alternatives and compiles for the v6 policy', async () => { + const out = await prepare( + base({ + assets: [usdc, { token: CIRCLE_SEPOLIA, maxPerCall: BigInt(2) }], + transferTo: [ADDR.other, ADDR.owner.toLowerCase() as never], + }) + ); + expect( + out.allowedCalls!.map((c) => [c.target, c.pins![0].expected, c.label]) + ).toEqual([ + [getAddress(SEPOLIA.USDC.address), ADDR.owner, 'Transfer to owner'], + [ + getAddress(SEPOLIA.USDC.address), + ADDR.other, + 'Transfer to named recipient', + ], + [CIRCLE_SEPOLIA, ADDR.owner, 'Transfer to owner'], + [CIRCLE_SEPOLIA, ADDR.other, 'Transfer to named recipient'], + ]); + const wire = (await normalizePublicRule( + out as never, + ADDR.other, + mockRuntime(new FakeChain()) + )) as UniversalRule; + expect(wire.allowedCalls.map((c) => c.pins?.map((p) => p.op))).toEqual([ + [0, 1], + [0, 1], + [0, 1], + [0, 1], + ]); + }); + it('with ALL and no apps, every routable ERC20 can go back to the owner', async () => { + const out = await prepare(base({ assets: [{ token: SEPOLIA.ALL }] })); + // Native ETH cannot be moved by a transfer rule, so ALL leaves it out here. + expect(out.assets!.map((a) => addressOf(a.token))).toEqual([ + SEPOLIA.USDT.address, + SEPOLIA.USDC.address, + SEPOLIA.WETH.address, + SEPOLIA.stETH.address, + CIRCLE_SEPOLIA, + ]); + expect(out.allowedCalls!.map((c) => getAddress(c.target))).toEqual( + out.assets!.map((a) => getAddress(addressOf(a.token))) + ); + expect( + out.allowedCalls!.every((c) => c.pins![0].expected === ADDR.owner) + ).toBe(true); + }); + it('uses the UEA origin as the owner address, and needs a recipient for a Solana owner', async () => { + const origin = getAddress('0x00000000000000000000000000000000000000cc'); + const evm = mockRuntime(new FakeChain(), { + signer: ADDR.owner, + signerIsPushNative: () => false, + signerOrigin: () => ({ chain: CHAIN.ETHEREUM_SEPOLIA, address: origin }), + }); + expect( + (await prepare(base({ assets: [usdc] }), evm)).allowedCalls![0].pins![0] + ).toEqual({ arg: 0, expected: origin }); + const sol = mockRuntime(new FakeChain(), { + signer: ADDR.owner, + signerIsPushNative: () => false, + signerOrigin: () => ({ + chain: CHAIN.SOLANA_DEVNET, + address: '11111111111111111111111111111111', + }), + }); + await expect(prepare(base({ assets: [usdc] }), sol)).rejects.toMatchObject({ + details: { reason: 'TRANSFER_RECIPIENT_REQUIRED' }, + }); + const named = await prepare( + base({ assets: [usdc], transferTo: [ADDR.other] }), + sol + ); + expect(named.allowedCalls!.map((c) => c.label)).toEqual([ + 'Transfer to named recipient', + ]); + }); + it.each([ + [ + base({ assets: [{ token: zeroAddress, maxPerCall: BigInt(1) }] }), + 'TOKENS_ONLY_NATIVE', + ], + [ + base({ + assets: [usdc], + transferTo: [ADDR.other], + allowedCalls: [{ target: ADDR.target, selector: 'increment()' }], + }), + 'TRANSFER_TO_WITH_CALLS', + ], + [ + base({ assets: [usdc], transferTo: [zeroAddress] }), + 'TRANSFER_RECIPIENT_INVALID', + ], + [ + base({ + chainNamespace: 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1', + assets: [ + { + token: 'So11111111111111111111111111111111111111112', + maxPerCall: BigInt(1), + }, + ], + }), + 'TOKENS_ONLY_UNSUPPORTED', + ], + ])( + 'refuses what a transfer rule cannot express (case %#)', + async (rule, reason) => { + await expect(prepare(rule)).rejects.toMatchObject({ + code: 'INVALID_RULE', + details: { reason }, + }); + } + ); + it('only the connected owner can author one', async () => { + await expect( + prepare( + base({ assets: [usdc] }), + mockRuntime(new FakeChain(), { signer: ADDR.agent }) + ) + ).rejects.toMatchObject({ code: 'NOT_WALLET_OWNER' }); + }); + it('leaves rules with allowed functions and decoded rules unchanged', async () => { + const rule = publicRules([ + base({ + assets: [usdc], + allowedCalls: [{ target: ADDR.target, selector: 'increment()' }], + }), + ])[0]; + expect( + await prepareRuleInput( + rule, + mockRuntime(new FakeChain(), { signer: ADDR.owner }), + ADDR.owner, + snap + ) + ).toBe(rule); + }); +}); diff --git a/packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts b/packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts index cf8c7912..bb7e3de2 100644 --- a/packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/svm-internals.spec.ts @@ -3,6 +3,7 @@ import { bytesToHex, hexToBytes, numberToHex, type Hex } from 'viem'; import { decodeSvmTerms, encodeSvmTerms, + refuseFromEndPins, validateSvmTerms, SvmDataPinMode, type SvmTermsWire, @@ -112,6 +113,19 @@ describe('v5 internal SVM wire codec', () => { { token: ADDR.other, maxPerCall: BigInt(0), maxTotal: BigInt(0) }, ]; expect(decodeSvmTerms(encodeSvmTerms(t, NOW))).toEqual(t); + // Existing fromEnd rules stay readable, but new grants refuse them. + expect(() => refuseFromEndPins(t)).toThrow( + expect.objectContaining({ + code: 'INVALID_RULE', + details: { reason: 'FROM_END_PIN_UNSUPPORTED', field: 'dataPins' }, + }) + ); + expect(() => + refuseFromEndPins({ + ...t, + dataPins: t.dataPins.filter((p) => !p.fromEnd), + }) + ).not.toThrow(); }); it.each([ [ diff --git a/packages/core/src/lib/agentic/__tests__/token-routes.spec.ts b/packages/core/src/lib/agentic/__tests__/token-routes.spec.ts index 8535a169..3a7d3795 100644 --- a/packages/core/src/lib/agentic/__tests__/token-routes.spec.ts +++ b/packages/core/src/lib/agentic/__tests__/token-routes.spec.ts @@ -3,9 +3,7 @@ import { CHAIN, PUSH_NETWORK } from '../../constants/enums'; import { SYNTHETIC_PUSH_ERC20 } from '../../constants/chain'; import type { Orchestrator } from '../../orchestrator/orchestrator'; import { createAgenticRuntime } from '../runtime'; -import { agenticPresets } from '../presets'; import { exactAgenticRoute, resolveAgenticPrc20 } from '../token-routes'; -import { ADDR } from './fake-chain'; const CIRCLE = { [CHAIN.ETHEREUM_SEPOLIA]: [ @@ -81,43 +79,3 @@ it('never matches by symbol, by another chain or on another network', () => { exactAgenticRoute(CHAIN.ETHEREUM_SEPOLIA, 'USDC', PUSH_NETWORK.TESTNET) ).toBeUndefined(); }); -it.each([ - ['DEXES', CHAIN.ETHEREUM_SEPOLIA], - ['LENDING', CHAIN.ARBITRUM_SEPOLIA], -] as const)( - '%s %s defaults are route-ready with unchanged assets and caps', - (category, chainNamespace) => { - const res = agenticPresets.get(category, { - chainNamespace, - agent: ADDR.agent, - }); - expect(res.readiness.ready).toBe(true); - const state = res.readiness.chains[0]; - expect(state.bridgeAssets.every((a) => a.status === 'registered')).toBe( - true - ); - expect(state.bridgeAssets).toContainEqual({ - token: getAddress(CIRCLE[chainNamespace][0]), - prc20: getAddress(CIRCLE[chainNamespace][1]), - status: 'registered', - }); - expect(res.rules[0].assets).toEqual(state.selectedAssets); - } -); -it('Base DEX USDC is routed while its WETH leg stays unavailable', () => { - const state = agenticPresets.get('DEXES', { - chainNamespace: CHAIN.BASE_SEPOLIA, - agent: ADDR.agent, - }).readiness.chains[0]; - expect(state.bridgeAssets).toEqual([ - { - token: '0x4200000000000000000000000000000000000006', - status: 'unavailable', - }, - { - token: getAddress(CIRCLE[CHAIN.BASE_SEPOLIA][0]), - prc20: getAddress(CIRCLE[CHAIN.BASE_SEPOLIA][1]), - status: 'registered', - }, - ]); -}); diff --git a/packages/core/src/lib/agentic/agentic.types.ts b/packages/core/src/lib/agentic/agentic.types.ts index b8c5d465..094a133d 100644 --- a/packages/core/src/lib/agentic/agentic.types.ts +++ b/packages/core/src/lib/agentic/agentic.types.ts @@ -4,7 +4,7 @@ import type { ArgPinWire } from './codec/pins'; */ import type { Idl } from '@coral-xyz/anchor'; import type { SvmTermsWire } from './codec/svm-terms'; -import type { MoveableToken } from '../constants/tokens'; +import type { MoveableToken, MoveableTokenSet } from '../constants/tokens'; import type { UniversalTxResponse } from '../orchestrator/orchestrator.types'; import type { ProgressEvent } from '../progress-hook/progress-hook.types'; @@ -214,6 +214,11 @@ export interface RuleAsset { maxPerCall: bigint; maxTotal?: bigint; } +/** Authoring form of a rule asset: `CONSTANTS.MOVEABLE.TOKEN..ALL` + * expands to every routable token with its default limits, so it takes no caps. */ +export type RuleAssetInput = + | RuleAsset + | { token: MoveableTokenSet; maxPerCall?: never; maxTotal?: never }; export interface Rule { agent: AgenticAddress; chainNamespace?: ForeignChainNamespace; @@ -222,7 +227,18 @@ export interface Rule { maxGasPerCall?: bigint; allowedCalls: RuleCall[]; } -export type RuleInput = Rule | DecodedSolanaRule; +/** What create, rules.add and rules.update accept. Every Rule is valid input. */ +export interface AuthoredRule extends Omit { + assets?: RuleAssetInput[]; + /** 1..8 for Push-chain rules, 1..32 for other chains. Omit (or leave empty) + * on an EVM rule with ERC20 assets to allow only transfers of those tokens + * back to the owner, plus any `transferTo` recipients. */ + allowedCalls?: RuleCall[]; + /** Tokens-only EVM rules: extra recipients the agent may transfer each asset + * to, besides the owner. Refused together with allowedCalls. */ + transferTo?: AgenticAddress[]; +} +export type RuleInput = AuthoredRule | DecodedSolanaRule; export type Spent = | { kind: 'native'; @@ -242,7 +258,7 @@ export type Spent = } | { kind: 'universal'; assets: { token: string; spent: bigint }[] }; export interface RulesRecord extends Omit { - rule: RuleInput; + rule: Rule | DecodedSolanaRule; spent: Spent; } export interface InternalCreateOptions { diff --git a/packages/core/src/lib/agentic/codec/rules.ts b/packages/core/src/lib/agentic/codec/rules.ts index 402929d5..d3cf0b22 100644 --- a/packages/core/src/lib/agentic/codec/rules.ts +++ b/packages/core/src/lib/agentic/codec/rules.ts @@ -21,7 +21,11 @@ import { } from './native'; import { buildSession, encodeEnvelope, type SessionWire } from './session'; import { encodeUniversalRule, type ResolvedUniversalRule } from './universal'; -import { encodeSvmTerms, type SvmTermsWire } from './svm-terms'; +import { + encodeSvmTerms, + refuseFromEndPins, + type SvmTermsWire, +} from './svm-terms'; import { SEND_OUTBOUND_SELECTOR } from '../contracts/v6'; import type { UniversalTermsWire } from './universal-terms'; @@ -147,6 +151,7 @@ export function prepareRules( AGENTIC_ERROR_CODE.INVALID_RULE, 'SVM rules require resolved wallet context and validated instruction layouts' ); + refuseFromEndPins(terms); return { rule, agent, diff --git a/packages/core/src/lib/agentic/codec/svm-terms.ts b/packages/core/src/lib/agentic/codec/svm-terms.ts index 3b0e10ab..23e90929 100644 --- a/packages/core/src/lib/agentic/codec/svm-terms.ts +++ b/packages/core/src/lib/agentic/codec/svm-terms.ts @@ -160,6 +160,19 @@ function offsetValid(fromEnd: boolean, offset: number, len: number): boolean { : offset + len <= SVM_LIMITS.ixData; } +/** Write-path only. The deployed SvmRulebook doesn't bind instruction-data + * length to a rule, so appended bytes can shift a `fromEnd` pin onto + * attacker-chosen data (Zaryab, 2026-10-23). Refused until the policy fix; + * decoding and reading existing rules still accept it. */ +export function refuseFromEndPins(t: SvmTermsWire): void { + if (t.dataPins.some((p) => p.fromEnd)) + throw new AgenticError( + AGENTIC_ERROR_CODE.INVALID_RULE, + 'Solana data pins counted from the end of the instruction data are not supported yet', + { details: { reason: 'FROM_END_PIN_UNSUPPORTED', field: 'dataPins' } } + ); +} + /** Grant-time structural rules. Chain/token/mint correctness requires resolved on-chain inputs. */ export function validateSvmTerms(t: SvmTermsWire, nowSeconds: number): void { integer(t.validUntil, 2 ** 48 - 1, 'validUntil'); diff --git a/packages/core/src/lib/agentic/constants.ts b/packages/core/src/lib/agentic/constants.ts index b5e798de..5c5d2948 100644 --- a/packages/core/src/lib/agentic/constants.ts +++ b/packages/core/src/lib/agentic/constants.ts @@ -19,7 +19,6 @@ export const AGENTIC = Object.freeze({ DEXES: 'DEXES' as const, LENDING: 'LENDING' as const, STAKING: 'STAKING' as const, - PREDICTION: 'PREDICTION' as const, }), }), }); diff --git a/packages/core/src/lib/agentic/error-messages.ts b/packages/core/src/lib/agentic/error-messages.ts index 8c4deb9f..db3a529b 100644 --- a/packages/core/src/lib/agentic/error-messages.ts +++ b/packages/core/src/lib/agentic/error-messages.ts @@ -49,6 +49,23 @@ const MESSAGES: Record = { 'The agentic wallet does not have enough funds for this action.', }; +/** Tokens-only rules and MOVEABLE ALL (management/rule-inputs). */ +const REASON_MESSAGES: Readonly> = { + TOKENS_ONLY_NATIVE: + 'Native ETH and BNB cannot be transferred by a rule. Remove them, or add an app.', + TOKENS_ONLY_UNSUPPORTED: + 'Tokens alone can only be allowed on EVM networks. Add an app for this network.', + TRANSFER_RECIPIENT_REQUIRED: + 'Name at least one recipient: the owner has no address on this network.', + TRANSFER_RECIPIENT_INVALID: 'Enter a valid recipient address.', + TRANSFER_TO_WITH_CALLS: + 'Recipients apply only to rules without apps. Add the transfer as an allowed function instead.', + ALL_WITH_LIMITS: + 'All tokens uses each token’s default limits. Remove the limits, or select the tokens individually.', + ALL_TOO_MANY: 'A rule can include at most eight tokens. Select fewer tokens.', + ALL_UNAVAILABLE: 'No token can be sent from Push to this network yet.', +}; + export function agenticUserMessage( code: AgenticErrorCode, diagnostic: string, @@ -67,7 +84,9 @@ export function agenticUserMessage( } if (code !== 'INVALID_RULE') return MESSAGES[code]; if (details?.['reason'] === 'ALLOWED_FUNCTION_REQUIRED') - return 'Add at least one allowed function. Selecting tokens and limits alone does not authorize transfers.'; + return 'Add at least one allowed function, or select tokens on an EVM network to allow transfers back to the owner.'; + const reasonMessage = REASON_MESSAGES[String(details?.['reason'])]; + if (reasonMessage) return reasonMessage; if (/validUntil|expiry|expired|future.*timestamp/i.test(diagnostic)) return 'Choose an expiry date in the future.'; if (/label.*(64|length|most)/i.test(diagnostic)) @@ -146,7 +165,7 @@ export function agenticRevertUserMessage(name?: string): string { if (/PCValueExceedsCap|Gas.*Cap/.test(name ?? '')) return 'The required gas exceeds this rule’s gas budget. Review the budget before trying again.'; if ( - /ArgPinAboveMax|AmountExceedsCap|TotalSpendCapExceeded|Value.*Cap|MaxCalls|CallLimitReached|TotalNativeAmountExceeded|TotalValueExceeded/.test( + /ArgPinAboveMax|AmountExceedsCap|TotalSpendCapExceeded|Value.*Cap|InnerValueExceedsAllowance|MaxCalls|CallLimitReached|TotalNativeAmountExceeded|TotalValueExceeded/.test( name ?? '' ) ) diff --git a/packages/core/src/lib/agentic/index.ts b/packages/core/src/lib/agentic/index.ts index 396c39c2..eb267734 100644 --- a/packages/core/src/lib/agentic/index.ts +++ b/packages/core/src/lib/agentic/index.ts @@ -8,6 +8,8 @@ export type { AgenticWallet, RuleCall as AllowedCall, RuleAsset as AssetCap, + RuleAssetInput, + AuthoredRule, Checkpoint, CheckpointKind, CreateOptions, @@ -37,8 +39,5 @@ export type { ReadyPresetOptions, PresetRuleTemplate, PresetResult, - PresetChainReadiness, - PresetConfigurationIssue, - PresetCallIssue, AgenticPresets, } from './presets/types'; diff --git a/packages/core/src/lib/agentic/management/prepare.ts b/packages/core/src/lib/agentic/management/prepare.ts index df51da54..32b60b0e 100644 --- a/packages/core/src/lib/agentic/management/prepare.ts +++ b/packages/core/src/lib/agentic/management/prepare.ts @@ -1,4 +1,5 @@ import { isPublicRule, normalizePublicRule } from '../public-rule'; +import { prepareRuleInput } from './rule-inputs'; import { preparePublicSvmRule } from './svm-public'; import type { SvmTermsWire } from '../codec/svm-terms'; import { getAddress, zeroAddress, type Address } from 'viem'; @@ -46,7 +47,11 @@ export async function prepareWalletRules( inputs.map(async (rule, ruleIndex) => { try { return isPublicRule(rule) - ? await normalizePublicRule(rule, wallet, runtime) + ? await normalizePublicRule( + await prepareRuleInput(rule, runtime, owner, snap), + wallet, + runtime + ) : rule; } catch (error) { throw ruleErrorContext(error, ruleIndex, rule?.chainNamespace); diff --git a/packages/core/src/lib/agentic/management/rule-inputs.ts b/packages/core/src/lib/agentic/management/rule-inputs.ts new file mode 100644 index 00000000..4fd8a1a1 --- /dev/null +++ b/packages/core/src/lib/agentic/management/rule-inputs.ts @@ -0,0 +1,310 @@ +import { + getAddress, + isAddress, + parseUnits, + zeroAddress, + type Address, +} from 'viem'; +import { CHAIN, PUSH_NETWORK, VM } from '../../constants/enums'; +import { CHAIN_INFO } from '../../constants/chain'; +import { + MOVEABLE_TOKENS, + isMoveableTokenSet, + type MoveableToken, +} from '../../constants/tokens'; +import { exactAgenticRoutes, resolveAgenticPrc20 } from '../token-routes'; +import type { + AuthoredRule, + InternalRule, + RuleAsset, + RuleAssetInput, + RuleCall, +} from '../agentic.types'; +import type { AgenticRuntime } from '../runtime'; +import type { Snapshot } from '../reads/snapshot'; +import { readOriginToken } from '../contracts/prc20-metadata'; +import { AgenticError, AGENTIC_ERROR_CODE } from '../errors'; + +/** Contract limit: assets per universal rule. */ +const MAX_ASSETS = 8; +const refuse = (message: string, reason: string, field?: string) => + new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, message, { + details: { reason, ...(field ? { field } : {}) }, + }); + +// Default limits for ALL, by the SDK registry's own symbol and decimals (never +// caller metadata). Amounts are token quantities, not USD valuations. +const DEFAULT_LIMITS: Readonly> = { + USDT: ['10', '100'], + USDC: ['10', '100'], + DAI: ['10', '100'], + ETH: ['0.001', '0.01'], + WETH: ['0.001', '0.01'], + stETH: ['0.001', '0.01'], + BNB: ['0.01', '0.1'], + SOL: ['0.01', '0.1'], +}; +function withDefaultLimits( + token: MoveableToken | string, + symbol: string, + decimals: number, + chain: string +): RuleAsset { + const limits = DEFAULT_LIMITS[symbol]; + if (!limits) + throw new AgenticError( + AGENTIC_ERROR_CODE.CAPABILITY_UNAVAILABLE, + `No default limit for ${symbol} on ${chain}`, + { details: { capability: 'allTokenDefaults', dependency: symbol } } + ); + return { + token, + maxPerCall: parseUnits(limits[0], decimals), + maxTotal: parseUnits(limits[1], decimals), + }; +} + +/** Every token Push can send to `chainNamespace`, each with its default limits: + * the SDK registry plus exact node routes (Circle USDC `.old` is listed + * separately from the routed mock USDC), deduplicated by Push PRC20. */ +export function allRoutableAssets( + chainNamespace: string, + options: { network?: PUSH_NETWORK } = {} +): RuleAsset[] { + const network = options.network ?? PUSH_NETWORK.TESTNET_DONUT; + const seen = new Set(); + const out: RuleAsset[] = []; + const add = ( + token: MoveableToken | string, + address: string, + symbol: string, + decimals: number + ) => { + let prc20: Address; + try { + prc20 = resolveAgenticPrc20( + { chain: chainNamespace, address }, + network + ).address; + } catch { + return; // listed in the registry but not routable from Push + } + if (seen.has(prc20)) return; + seen.add(prc20); + out.push(withDefaultLimits(token, symbol, decimals, chainNamespace)); + }; + for (const token of MOVEABLE_TOKENS[chainNamespace as CHAIN] ?? []) + add({ ...token }, token.address, token.symbol, token.decimals); + for (const route of exactAgenticRoutes(chainNamespace, network)) + add(getAddress(route.source), route.source, route.symbol, route.decimals); + if (!out.length) + throw refuse( + `No token can be sent from Push to ${chainNamespace}`, + 'ALL_UNAVAILABLE' + ); + if (out.length > MAX_ASSETS) + throw refuse( + `ALL expands to ${out.length} tokens on ${chainNamespace}; a rule holds at most eight assets`, + 'ALL_TOO_MANY' + ); + return out; +} + +const sourceKey = (token: MoveableToken | string): string => { + const address = typeof token === 'string' ? token : token.address; + if (typeof token !== 'string' && token.mechanism === 'native') + return zeroAddress; + return isAddress(address, { strict: false }) + ? address.toLowerCase() + : address; +}; +function expandAll( + rule: AuthoredRule, + network: PUSH_NETWORK, + transferable: boolean +): RuleAsset[] | undefined { + const assets = rule.assets ?? []; + const markers = assets.filter((a) => isMoveableTokenSet(a?.token)); + if (!markers.length) return undefined; + const chain = rule.chainNamespace; + for (const marker of markers) { + if ( + marker.maxPerCall !== undefined || + (marker as RuleAssetInput).maxTotal !== undefined + ) + throw refuse( + 'ALL uses each token’s default limits. Remove maxPerCall and maxTotal, or list the tokens individually.', + 'ALL_WITH_LIMITS', + 'assets' + ); + if (!chain || (marker.token as { chain: string }).chain !== chain) + throw new AgenticError( + AGENTIC_ERROR_CODE.ASSET_CHAIN_MISMATCH, + `ALL for ${ + (marker.token as { chain: string }).chain + } does not match the rule's chain ${chain ?? 'Push Chain'}`, + { details: { field: 'assets' } } + ); + } + // Without apps the rule can only transfer ERC20s, so ALL leaves native out. + const expanded = allRoutableAssets(chain as string, { network }).filter( + (a) => !transferable || sourceKey(a.token) !== zeroAddress + ); + // An explicitly listed token replaces its default entry. + for (const asset of assets) { + if (isMoveableTokenSet(asset.token)) continue; + const explicit = asset as RuleAsset; + const key = sourceKey(explicit.token); + const i = expanded.findIndex((a) => sourceKey(a.token) === key); + if (i >= 0) expanded[i] = explicit; + else expanded.push(explicit); + } + if (expanded.length > MAX_ASSETS) + throw refuse( + `ALL plus the listed tokens make ${expanded.length} assets; a rule holds at most eight`, + 'ALL_TOO_MANY', + 'assets' + ); + return expanded; +} + +/** The owner's own EVM address: the Push EOA, or the EVM origin of its UEA. */ +function ownerEvmAddress( + runtime: AgenticRuntime, + owner: Address +): Address | undefined { + if (getAddress(runtime.signerPushAccount()) !== getAddress(owner)) + throw new AgenticError( + AGENTIC_ERROR_CODE.NOT_WALLET_OWNER, + 'tokens-only rules pin transfers to the connected owner' + ); + if (runtime.signerIsPushNative()) return getAddress(owner); + const origin = runtime.signerOrigin(); + return CHAIN_INFO[origin.chain]?.vm === VM.EVM && + isAddress(origin.address, { strict: false }) + ? getAddress(origin.address) + : undefined; +} + +async function transferCalls( + rule: AuthoredRule, + assets: RuleAsset[], + runtime: AgenticRuntime, + owner: Address, + snap: Snapshot +): Promise { + const chain = rule.chainNamespace as string; + if (assets.some((a) => sourceKey(a.token) === zeroAddress)) + throw refuse( + 'Native ETH and BNB cannot be transferred by a rule. Remove them, or add an app.', + 'TOKENS_ONLY_NATIVE', + 'assets' + ); + const recipients: { address: Address; owner: boolean }[] = []; + const ownerAddress = ownerEvmAddress(runtime, owner); + if (ownerAddress) recipients.push({ address: ownerAddress, owner: true }); + for (const [i, to] of (rule.transferTo ?? []).entries()) { + if (!isAddress(to, { strict: false }) || getAddress(to) === zeroAddress) + throw refuse( + 'Enter a valid recipient address.', + 'TRANSFER_RECIPIENT_INVALID', + `transferTo[${i}]` + ); + if (!recipients.some((r) => r.address === getAddress(to))) + recipients.push({ address: getAddress(to), owner: false }); + } + if (!recipients.length) + throw refuse( + 'Name at least one recipient in transferTo: an owner from Solana has no address on this network.', + 'TRANSFER_RECIPIENT_REQUIRED', + 'transferTo' + ); + const calls: RuleCall[] = []; + for (const asset of assets) { + // The ERC20 lives on the destination chain; a Push token names its source. + const target = + typeof asset.token === 'object' && 'prc20Address' in asset.token + ? await readOriginToken( + snap, + getAddress( + (asset.token as MoveableToken & { prc20Address: string }) + .prc20Address + ), + chain + ) + : getAddress( + typeof asset.token === 'string' ? asset.token : asset.token.address + ); + for (const recipient of recipients) + calls.push({ + target, + selector: 'transfer(address,uint256)', + pins: [ + { arg: 0, expected: recipient.address }, + { arg: 1, max: asset.maxPerCall }, + ], + app: 'Token transfer', + label: recipient.owner + ? 'Transfer to owner' + : 'Transfer to named recipient', + }); + } + return calls; +} + +/** Authoring conveniences resolved before normalization, once the owner and + * network are known: MOVEABLE ALL markers, and tokens-only EVM rules, which + * become ERC20 transfers to the owner plus any `transferTo` recipients. */ +export async function prepareRuleInput( + input: InternalRule, + runtime: AgenticRuntime, + owner: Address, + snap: Snapshot +): Promise { + const rule = input as unknown as AuthoredRule; + if ('format' in rule) return input; + const noCalls = !rule.allowedCalls?.length; + const chain = rule.chainNamespace; + const expanded = expandAll( + rule, + runtime.network, + noCalls && !!chain?.startsWith('eip155:') + ); + const assets = (expanded ?? rule.assets ?? []) as RuleAsset[]; + if (rule.transferTo !== undefined) { + if (!Array.isArray(rule.transferTo)) + throw refuse('transferTo must be an array', 'TRANSFER_RECIPIENT_INVALID'); + if (!noCalls) + throw refuse( + 'transferTo applies only to rules without allowed functions. Add the transfer as an allowed function instead.', + 'TRANSFER_TO_WITH_CALLS', + 'transferTo' + ); + if (!chain?.startsWith('eip155:')) + throw refuse( + 'transferTo is only available on EVM networks.', + 'TOKENS_ONLY_UNSUPPORTED', + 'transferTo' + ); + } + let allowedCalls = rule.allowedCalls; + if (noCalls && assets.length && chain?.startsWith('solana:')) + throw refuse( + 'A Solana rule needs an app: tokens alone cannot be transferred there.', + 'TOKENS_ONLY_UNSUPPORTED', + 'allowedCalls' + ); + if (noCalls && assets.length && chain?.startsWith('eip155:')) + allowedCalls = await transferCalls(rule, assets, runtime, owner, snap); + if ( + !expanded && + allowedCalls === rule.allowedCalls && + !('transferTo' in rule) + ) + return input; + // Spread keeps the public-input marker symbol. + const out = { ...rule, ...(expanded ? { assets: expanded } : {}) }; + delete out.transferTo; + if (allowedCalls !== undefined) out.allowedCalls = allowedCalls; + return out as unknown as InternalRule; +} diff --git a/packages/core/src/lib/agentic/management/svm-public.ts b/packages/core/src/lib/agentic/management/svm-public.ts index 96da8645..c15c323a 100644 --- a/packages/core/src/lib/agentic/management/svm-public.ts +++ b/packages/core/src/lib/agentic/management/svm-public.ts @@ -12,7 +12,7 @@ import { createSvmMetadataProvider } from './svm-metadata'; import { deriveAgwSvmAta, svmKey } from '../codec/svm-accounts'; import { compileSvmIdlRule } from '../codec/svm-idl'; import { svmInvalid } from '../codec/svm-terms'; -import { validateSvmTerms } from '../codec/svm-terms'; +import { refuseFromEndPins, validateSvmTerms } from '../codec/svm-terms'; import { tokenRouteUnavailable } from '../errors'; export function svmMetadata(runtime: AgenticRuntime) { @@ -140,6 +140,7 @@ export async function preparePublicSvmRule( throw svmInvalid('decoded rule omits a required wallet value account'); const terms = { ...stored, assets: caps }; validateSvmTerms(terms, runtime.nowSeconds()); + refuseFromEndPins(terms); return terms; } return compileSvmIdlRule( diff --git a/packages/core/src/lib/agentic/presets/aave-reserves.ts b/packages/core/src/lib/agentic/presets/aave-reserves.ts deleted file mode 100644 index bdd07638..00000000 --- a/packages/core/src/lib/agentic/presets/aave-reserves.ts +++ /dev/null @@ -1,146 +0,0 @@ -/** Aave V3 reserve addresses from the official bgd-labs/aave-address-book - * snapshots reviewed October 15, 2026. Listings are not liquidity/availability guarantees. */ -import type { Address } from 'viem'; -export const AAVE_RESERVES: Readonly> = { - 'eip155:1': [ - '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', - '0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0', - '0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599', - '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', - '0x6B175474E89094C44Da98b954EedeAC495271d0F', - '0x514910771AF9Ca656af840dff83E8264EcF986CA', - '0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9', - '0xBe9895146f7AF43049ca1c1AE358B0541Ea49704', - '0xdAC17F958D2ee523a2206206994597C13D831ec7', - '0xae78736Cd615f374D3085123A210448E74Fc6393', - '0x5f98805A4E8be255a32880FDeC7F6728C6568bA0', - '0xD533a949740bb3306d119CC777fa900bA034cd52', - '0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2', - '0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F', - '0xba100000625a3754423978a60c9317c58a424e3D', - '0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984', - '0x5A98FcBEA516Cf06857215779Fd812CA3beF1B32', - '0xC18360217D8F7Ab5e7c516566761Ea12Ce7F9D72', - '0x111111111117dC0aa78b770fA6A738034120C302', - '0x853d955aCEf822Db058eb8505911ED77F175b99e', - '0x40D16FC0246aD3160Ccc09B8D0D3A2cD28aE6C2f', - '0xD33526068D116cE69F19A9ee46F0bd304F21A51f', - '0x83F20F44975D03b1b09e64809B757c47f942BEeA', - '0xAf5191B0De278C7286d6C7CC6ab6BB8A73bA2Cd6', - '0xdeFA4e8a7bcBA345F687a2f1456F5Edd9CE97202', - '0x3432B6A60D23Ca0dFCa7761B7ab56459D9C964D0', - '0xf939E0A03FB07F59A73314E73794Be0E57ac1b4E', - '0x6c3ea9036406852006290770BEdFcAbA0e23A0e8', - '0xCd5fE23C85820F7B72D0926FC9b05b43E359b7ee', - '0xf1C9acDc66974dFB6dEcB12aA385b9cD01190E38', - '0x4c9EDD5852cd905f086C759E8383e09bff1E68B3', - '0xA35b1B31Ce002FBF2058D22F30f95D405200A15b', - '0x9D39A5DE30e57443BfF2A8307A4256c8797A3497', - '0x18084fbA666a33d37592fA2633fD49a74DD93a88', - '0xcbB7C0000aB88B473b1f5aFd9ef808440eed33Bf', - '0xdC035D45d973E3EC169d2276DDab16f1e407384F', - '0xA1290d69c65A6Fe4DF752f95823fae25cB99e5A7', - '0x8236a87084f8B84306f72007F36F2618A5634494', - '0x657e8C867D8B37dCC18fA4Caead9C45EB088C642', - '0x8292Bb45bf1Ee4d140127049757C2E0fF06317eD', - '0x50D2C7992b802Eef16c04FeADAB310f31866a545', - '0x3b3fB9C57858EF816833dC91565EFcd85D96f634', - '0xC139190F447e929f090Edeb554D95AbB8b18aC1C', - '0x917459337CaAC939D41d7493B3999f571D20D667', - '0x14Bdc3A3AE09f5518b923b69489CBcAfB238e617', - '0x90D2af7d622ca3141efA4d8f1F24d86E5974Cc8F', - '0xC96dE26018A54D51c097160568752c4E3BD6C364', - '0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c', - '0x9F56094C450763769BA0EA9Fe2876070c0fD5F77', - '0xBC6736d346a5eBC0dEbc997397912CD9b8FAe10a', - '0xD11c452fc99cF405034ee446803b6F6c1F6d5ED8', - '0xbf5495Efe5DB9ce00f80364C8B423567e58d2110', - '0x68749665FF8D2d112Fa859AA293F07A622782F38', - '0xe6A934089BBEe34F832060CE98848359883749B3', - '0x62C6E813b9589C3631Ba0Cdb013acdB8544038B7', - '0x1F84a51296691320478c98b8d77f2Bbd17D34350', - '0xE8483517077afa11A9B07f849cee2552f040d7b2', - '0xacA92E438df0B2401fF60dA7E4337B687a2435DA', - '0x356B8d89c1e1239Cbbb9dE4815c39A1474d5BA7D', - '0xe343167631d89B6Ffc58B88d6b7fB0228795491D', - '0xAeBf0Bb9f57E89260d57f31AF34eB58657d96Ce0', - '0x3de0ff76E8b528C092d47b9DaC775931cef80F49', - '0x9Bf45ab47747F4B4dD09B3C2c73953484b4eB375', - '0xB0F70C0bD6FD87dbEb7C10dC692a2a6106817072', - '0x619D75E3b790eBC21c289f2805Bb7177A7D732E2', - '0x9db38D74a0D29380899aD354121DfB521aDb0548', - '0x59bC9FaE5D62B19d4f8d07D758047aCb9EE19d34', - ], - 'eip155:8453': [ - '0x4200000000000000000000000000000000000006', - '0x2Ae3F1Ec7F1F5012CFEab0185bfc7aa3cf0DEc22', - '0xd9aAEc86B65D86f6A7B5B1b0c42FFA531710b6CA', - '0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452', - '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', - '0x04C0599Ae5A44757c0af6F9eC3b93da8976c150A', - '0xcbB7C0000aB88B473b1f5aFd9ef808440eed33Bf', - '0x2416092f143378750bb29b79eD961ab195CcEea5', - '0x6Bb7a212910682DCFdbd5BCBb3e28FB4E8da10Ee', - '0xEDfa23602D0EC14714057867A78d01e94176BEA0', - '0xecAc9C5F704e954931349Da37F60E39f515c11c1', - '0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42', - '0x63706e401c06ac8513145b7687A14804d17f814b', - '0x236aa50979D5f3De3Bd1Eeb40E81137F22ab794b', - '0x660975730059246A68521a3e2FBD4740173100f5', - ], - 'eip155:42161': [ - '0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1', - '0xf97f4df75117a78c1A5a0DBb814Af92458539FB4', - '0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8', - '0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f', - '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1', - '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9', - '0xba5DdD1f9d7F570dc94a51479a000E3BCE967196', - '0xD22a58f79e9481D1a88e00c343885A588b34b68B', - '0x5979D7b546E38E414F7E9822514be443A4800529', - '0x3F56e0c36d275367b8C502090EDF38289b3dEa0d', - '0xEC70Dcb4A1EFa46b8F2D97C310C9c4790ba5ffA8', - '0x93b346b6BC2548dA6A1E7d98E9a421B42541425b', - '0xaf88d065e77c8cC2239327C5EDb3A432268e5831', - '0x17FC002b466eEc40DaE837Fc4bE5c67993ddBd6F', - '0x912CE59144191C1204E64559FE8253a0e49E6548', - '0x35751007a407ca6FEFfE80b3cB397736D2cf4dbe', - '0x7dfF72693f6A4149b17e7C6314655f6A9F7c8B33', - '0x2416092f143378750bb29b79eD961ab195CcEea5', - '0x4186BFC76E2E237523CBC30FD220FE055156b41F', - '0x6c84a8f1c29108F47a79964b5Fe888D4f4D0dE40', - ], - 'eip155:56': [ - '0x0E09FaBB73Bd3Ade0a17ECC321fD13a19e81cE82', - '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c', - '0x7130d2A12B9BCbFAe4f2634d864A1Ee1Ce3Ead9c', - '0x2170Ed0880ac9A755fd29B2688956BD959F933F8', - '0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d', - '0x55d398326f99059fF775485246999027B3197955', - '0xc5f0f7b66764F6ec8C8Dff7BA683102295E16409', - '0x26c5e01524d2E6280A48F2c50fF6De7e52E9611C', - ], - 'eip155:11155111': [ - '0xFF34B3d4Aee8ddCd6F9AFFFB6Fe49bD371b8a357', - '0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5', - '0x94a9D9AC8a22534E3FaCa9F4e7F2E2cf85d5E4C8', - '0x29f2D40B0605204364af54EC677bD022dA425d03', - '0xC558DBdd856501FCd9aaF1E62eae57A9F0629a3c', - '0xaA8E23Fb1079EA71e0a56F48a2aA51851D8433D0', - '0x88541670E55cC00bEEFD87eB59EDd1b7C511AC9a', - '0x6d906e526a4e2Ca02097BA9d0caA3c382F52278E', - '0xc4bF5CbDaBE595361438F8c6a187bDc330539c60', - ], - 'eip155:84532': [ - '0xba50Cd2A20f6DA35D788639E581bca8d0B5d4D5f', - '0x0a215D8ba66387DCA84B284D18c3B4ec3de6E54a', - '0x54114591963CF60EF3aA63bEfD6eC263D98145a4', - '0x4200000000000000000000000000000000000006', - '0xD171b9694f7A2597Ed006D41f7509aaD4B485c4B', - '0x810D46F9a9027E28F9B01F75E2bdde839dA61115', - ], - 'eip155:421614': [ - '0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d', - '0x1dF462e2712496373A347f8ad10802a5E95f053D', - ], -}; diff --git a/packages/core/src/lib/agentic/presets/catalog.ts b/packages/core/src/lib/agentic/presets/catalog.ts index 263ddd92..c68a5d06 100644 --- a/packages/core/src/lib/agentic/presets/catalog.ts +++ b/packages/core/src/lib/agentic/presets/catalog.ts @@ -1,28 +1,15 @@ -import { getAddress, type Address } from 'viem'; -import type { RuleCall, ForeignChainNamespace } from '../agentic.types'; +import { getAddress, parseUnits, type Address } from 'viem'; +import type { + ArgumentPath, + RuleCall, + ForeignChainNamespace, +} from '../agentic.types'; import type { PresetCategory } from './types'; -import { AAVE_RESERVES } from './aave-reserves'; -import { - DEX_DEFAULT_TOKENS, - LENDING_DEFAULT_TOKENS, - STAKING_DEFAULT_TOKENS, -} from './default-tokens'; +/** Caps filled from the preset's native ETH asset (its maxPerCall). */ export type PresetBudget = - | { - kind: 'token-argument'; - tokenArg: number; - amountArg: number; - tokens?: readonly Address[]; - } - | { kind: 'fixed-token'; token: Address; amountArg: number } | { kind: 'native-value' } - | { kind: 'setup' } - | { - kind: 'unsupported'; - reason: 'SHARE_AMOUNT' | 'DYNAMIC_AMOUNT' | 'POSITION_AMOUNT'; - alternative?: RuleCall['selector']; - }; + | { kind: 'native-amount'; amountArg: ArgumentPath }; export interface PresetCallDefinition extends RuleCall { budget?: PresetBudget; } @@ -30,18 +17,7 @@ export interface PresetCallDefinition extends RuleCall { /** Internal catalog: reviewed addresses and explicit calls only; never fetched at runtime. */ export interface PresetChainDefinition { chainNamespace: ForeignChainNamespace; - /** Used with the bundled permission policy only when assets is omitted. */ - defaultTokens?: readonly Address[]; allowedCalls: readonly PresetCallDefinition[]; - /** Static single-hop routers; incomplete pairs return zero-input-cap review calls. */ - swapRouters?: readonly { address: Address; app: string }[]; - /** Exact spenders that need an approval for each non-native supplied asset. */ - approvals?: readonly { - spender: Address; - app: string; - token?: Address; - tokens?: readonly Address[]; - }[]; maxGasPerCall?: bigint; } export interface PresetDefinition { @@ -49,391 +25,179 @@ export interface PresetDefinition { name: string; chains: readonly PresetChainDefinition[]; } -/** Mainnet and testnet templates from the October 15 Notion export and protocol sources. - * Read-only deployment/code evidence and exclusions: plan/agw/research/preset-catalog-2026-10-15/. - * Mainnet entries are templates only; no mainnet deployment or execution guarantee. +/** Testnet entries that ran live on Donut. Every preset sends native ETH from Push + * and wraps it on arrival; no other token is moved from Push. Circle USDC is only + * the destination-side swap token (the only WETH pools with liquidity, checked + * read-only on October 24). Evidence: plan/agw/research/. */ const address = (value: string): Address => getAddress(value.toLowerCase()); const wallet = 'agentic:wallet' as const; -const aave = (pool: Address, chain: string): PresetCallDefinition[] => - [ - ['supply(address,uint256,address,uint16)', 2, 'Supply'], - ['withdraw(address,uint256,address)', 2, 'Withdraw'], - ['borrow(address,uint256,uint256,uint16,address)', 4, 'Borrow'], - ['repay(address,uint256,uint256,address)', 3, 'Repay'], - ].map(([selector, arg, label]) => ({ - target: pool, - selector: selector as RuleCall['selector'], - pins: [{ arg: arg as number, expected: wallet }], - app: 'Aave V3', - label: label as string, - budget: { - kind: 'token-argument', - tokenArg: 0, - amountArg: 1, - tokens: AAVE_RESERVES[chain], - }, - })); -const market = ( - target: Address, - app: string, - token: Address -): PresetCallDefinition[] => - [ - 'mint(uint256)', - 'redeem(uint256)', - 'redeemUnderlying(uint256)', - 'borrow(uint256)', - 'repayBorrow(uint256)', - ].map((selector) => ({ - target, - selector: selector as RuleCall['selector'], - app, - label: selector.split('(')[0], - budget: - selector === 'redeem(uint256)' - ? { - kind: 'unsupported', - reason: 'SHARE_AMOUNT', - alternative: 'redeemUnderlying(uint256)', - } - : { kind: 'fixed-token', token, amountArg: 0 }, - })); -const sepoliaPool = address('0x6Ae43d3271ff6888e7Fc43Fd7321a503ff738951'); -const basePool = address('0x8bAB6d1b75f19e9eD9fCe8b9BD338844fF79aE27'); -const arbitrumPool = address('0xBfC91D59fdAA134A4ED45f7B584cAf96D7792Eff'); -const moonUSDBC = address('0x876852425331a113d8E432eFFB3aC5BEf38f033a'); -const moonWETH = address('0x2F39a349A79492a70E152760ce7123A1933eCf28'); -const venusUSDT = address('0xb7526572FFE56AB9D7489838Bf2E18e3323b441A'); -const venusUSDC = address('0xD5C4C2e2facBEB59D0216D0595d63FcDc6F9A1a7'); -const eigen = address('0x2E3D6c0744b10eb0A4e6F679F71554a39Ec47a5D'); -const stETH = address('0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84'); -const wstETH = address('0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0'); -const lidoQueue = address('0x889edC2eDab5f40e902b864aD4d7AdE8E412F9B1'); -const mainnetMarkets = ( - chain: string -): Pick => { - const entries = - chain === 'eip155:8453' - ? [ - [ - '0xEdc817A28E8B93B03976FBd4a3dDBc9f7D176c22', - 'Moonwell mUSDC', - '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', - ], - [ - '0x628ff693426583D9a7FB391E54366292F509D457', - 'Moonwell mWETH', - '0x4200000000000000000000000000000000000006', - ], - ] - : chain === 'eip155:56' - ? [ - [ - '0xfD5840Cd36d94D7229439859C0112a4185BC0255', - 'Venus vUSDT', - '0x55d398326f99059fF775485246999027B3197955', - ], - [ - '0xecA88125a5ADbe82614ffC12D0DB554E2e2867C8', - 'Venus vUSDC', - '0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d', - ], - ] - : []; - const controller = - chain === 'eip155:8453' - ? '0xfBb21d0380beE3312B33c4353c8936a0F13EF26C' - : '0xfD36E2c2a6789Db23113685031d7F16329158384'; - return { - allowedCalls: [ - ...entries.flatMap(([target, app, token]) => - market(address(target), app, address(token)) - ), - ...(entries.length - ? [ - { - target: address(controller), - selector: 'enterMarkets(address[])' as const, - app: chain === 'eip155:8453' ? 'Moonwell' : 'Venus', - label: 'Enter markets', - budget: { kind: 'setup' as const }, - }, - ] - : []), - ], - approvals: entries.map(([spender, app, token]) => ({ - spender: address(spender), - app, - token: address(token), - })), +/** Destination-held USDC per swap; editable in the returned rule. */ +const USDC_PER_SWAP = parseUnits('10', 6); +const SWAP_STRUCT = '(address,address,uint24,address,uint256,uint256,uint160)'; + +const wrap = (weth: Address): PresetCallDefinition => ({ + target: weth, + selector: 'deposit()', + app: 'WETH', + label: 'Wrap ETH', + budget: { kind: 'native-value' }, +}); +const unwrap = (weth: Address): PresetCallDefinition => ({ + target: weth, + selector: 'withdraw(uint256)', + app: 'WETH', + label: 'Unwrap WETH', + budget: { kind: 'native-amount', amountArg: 0 }, +}); +const approveWeth = ( + weth: Address, + spender: Address, + app: string +): PresetCallDefinition => ({ + target: weth, + selector: 'approve(address,uint256)', + pins: [{ arg: 0, expected: spender }], + app, + label: 'Approve WETH spending', + budget: { kind: 'native-amount', amountArg: 1 }, +}); + +const uniswap = ( + router: Address, + weth: Address, + usdc: Address +): PresetCallDefinition[] => { + const swap = ( + exactInput: boolean, + tokenIn: Address, + tokenOut: Address + ): PresetCallDefinition => { + const amountArg = [0, exactInput ? 4 : 5] as const; + return { + target: router, + selector: `${ + exactInput ? 'exactInputSingle' : 'exactOutputSingle' + }(${SWAP_STRUCT})`, + pins: [ + { arg: [0, 0], expected: tokenIn }, + { arg: [0, 1], expected: tokenOut }, + { arg: [0, 3], expected: wallet }, + ...(tokenIn === usdc ? [{ arg: amountArg, max: USDC_PER_SWAP }] : []), + ], + app: 'Uniswap V3', + label: `${exactInput ? 'Swap exact input' : 'Swap exact output'} (${ + tokenIn === weth ? 'WETH to USDC' : 'USDC to WETH' + })`, + ...(tokenIn === weth + ? { budget: { kind: 'native-amount' as const, amountArg } } + : {}), + }; }; + return [ + wrap(weth), + approveWeth(weth, router, 'Uniswap V3'), + swap(true, weth, usdc), + swap(false, weth, usdc), + { + target: usdc, + selector: 'approve(address,uint256)', + pins: [ + { arg: 0, expected: router }, + { arg: 1, max: USDC_PER_SWAP }, + ], + app: 'Uniswap V3', + label: 'Approve USDC spending', + }, + swap(true, usdc, weth), + swap(false, usdc, weth), + unwrap(weth), + ]; }; + +const aave = (pool: Address, weth: Address): PresetCallDefinition[] => [ + wrap(weth), + approveWeth(weth, pool, 'Aave V3'), + ...( + [ + ['supply(address,uint256,address,uint16)', 2, 'Supply'], + ['withdraw(address,uint256,address)', 2, 'Withdraw'], + ['borrow(address,uint256,uint256,uint16,address)', 4, 'Borrow'], + ['repay(address,uint256,uint256,address)', 3, 'Repay'], + ] as const + ).map( + ([selector, beneficiary, label]): PresetCallDefinition => ({ + target: pool, + selector, + pins: [ + { arg: 0, expected: weth }, + { arg: beneficiary, expected: wallet }, + ], + app: 'Aave V3', + label, + budget: { kind: 'native-amount', amountArg: 1 }, + }) + ), + unwrap(weth), +]; + export const PRESET_CATALOG: readonly PresetDefinition[] = [ { constant: 'DEXES', name: 'Popular DEXes', - chains: [ - ['eip155:1', '0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45', 'Uniswap V3'], - [ - 'eip155:8453', - '0x2626664c2603336E57B271c5C0b26F421741e481', - 'Uniswap V3', - ], - [ - 'eip155:42161', - '0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45', - 'Uniswap V3', - ], - [ - 'eip155:56', - '0x13f4EA83D0bd40E75C8222255bc855a974568Dd4', - 'PancakeSwap V3', - ], - [ - 'eip155:11155111', - '0x3bFA4769FB09eefC5a80d6E87c3B9C650f7Ae48E', - 'Uniswap V3', - ], - [ - 'eip155:84532', - '0x94cC0AaC535CCDB3C01d6787D6413C739ae12bc4', - 'Uniswap V3', - ], - [ - 'eip155:421614', - '0x101F443B4d1b059569D643917553c771E1b9663E', - 'Uniswap V3', - ], + chains: ( [ - 'eip155:97', - '0x9a489505a00cE272eAa5e07Dba6491314CaE3796', - 'PancakeSwap V3', - ], - ].map(([chain, router, app]) => ({ - chainNamespace: chain as ForeignChainNamespace, - defaultTokens: DEX_DEFAULT_TOKENS[chain], - allowedCalls: [], - swapRouters: [{ address: address(router), app }], - approvals: [{ spender: address(router), app }], - })), - }, - { - constant: 'LENDING', - name: 'Lending', - chains: [ - ...( [ - ['eip155:1', '0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2'], - ['eip155:8453', '0xA238Dd80C259a72e81d7e4664a9801593F98d1c5'], - ['eip155:42161', '0x794a61358D6845594F94dc1DB02A252b5b4814aD'], - ['eip155:56', '0x6807dc923806fE8Fd134338EABCA509979a7e0cB'], - ] as const - ).map(([chainNamespace, pool]) => ({ - chainNamespace, - defaultTokens: LENDING_DEFAULT_TOKENS[chainNamespace], - allowedCalls: [ - ...aave(address(pool), chainNamespace), - ...mainnetMarkets(chainNamespace).allowedCalls, - ], - approvals: [ - { - spender: address(pool), - app: 'Aave V3', - tokens: AAVE_RESERVES[chainNamespace], - }, - ...(mainnetMarkets(chainNamespace).approvals ?? []), + 'eip155:11155111', + '0x3bFA4769FB09eefC5a80d6E87c3B9C650f7Ae48E', + '0xfff9976782d46cc05630d1f6ebab18b2324d6b14', + '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238', ], - })), - - { - chainNamespace: 'eip155:11155111', - defaultTokens: LENDING_DEFAULT_TOKENS['eip155:11155111'], - allowedCalls: aave(sepoliaPool, 'eip155:11155111'), - approvals: [ - { - spender: sepoliaPool, - app: 'Aave V3', - tokens: AAVE_RESERVES['eip155:11155111'], - }, - ], - }, - { - chainNamespace: 'eip155:421614', - defaultTokens: LENDING_DEFAULT_TOKENS['eip155:421614'], - allowedCalls: aave(arbitrumPool, 'eip155:421614'), - approvals: [ - { - spender: arbitrumPool, - app: 'Aave V3', - tokens: AAVE_RESERVES['eip155:421614'], - }, - ], - }, - { - chainNamespace: 'eip155:84532', - defaultTokens: LENDING_DEFAULT_TOKENS['eip155:84532'], - allowedCalls: [ - ...aave(basePool, 'eip155:84532'), - ...market( - moonUSDBC, - 'Moonwell mUSDbC', - address('0x4616975f7E6045FD9737e95bC527e9e14c727BD2') - ), - ...market( - moonWETH, - 'Moonwell mWETH', - address('0x663A6F02d547dFd639BF689FED298712f2FB69Fb') - ), - { - target: address('0xC72ba45f2Ae134F21DAEb2b7B5fd5De0064Ee9bB'), - selector: 'enterMarkets(address[])', - app: 'Moonwell', - label: 'Enter markets', - budget: { kind: 'setup' as const }, - }, - ], - approvals: [ - { - spender: basePool, - app: 'Aave V3', - tokens: AAVE_RESERVES['eip155:84532'], - }, - { - spender: moonUSDBC, - app: 'Moonwell mUSDbC', - token: address('0x4616975f7E6045FD9737e95bC527e9e14c727BD2'), - }, - { - spender: moonWETH, - app: 'Moonwell mWETH', - token: address('0x663A6F02d547dFd639BF689FED298712f2FB69Fb'), - }, - ], - }, - { - chainNamespace: 'eip155:97', - defaultTokens: LENDING_DEFAULT_TOKENS['eip155:97'], - allowedCalls: [ - ...market( - venusUSDT, - 'Venus vUSDT', - address('0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c') - ), - ...market( - venusUSDC, - 'Venus vUSDC', - address('0x16227D60f7a0e586C66B005219dfc887D13C9531') - ), - { - target: address('0x94d1820b2D1c7c7452A163983Dc888CEC546b77D'), - selector: 'enterMarkets(address[])', - app: 'Venus', - label: 'Enter markets', - budget: { kind: 'setup' as const }, - }, + [ + 'eip155:84532', + '0x94cC0AaC535CCDB3C01d6787D6413C739ae12bc4', + '0x4200000000000000000000000000000000000006', + '0x036CbD53842c5426634e7929541eC2318f3dCF7e', ], - approvals: [ - { - spender: venusUSDT, - app: 'Venus vUSDT', - token: address('0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c'), - }, - { - spender: venusUSDC, - app: 'Venus vUSDC', - token: address('0x16227D60f7a0e586C66B005219dfc887D13C9531'), - }, + [ + 'eip155:421614', + '0x101F443B4d1b059569D643917553c771E1b9663E', + '0x980B62Da83eFf3D4576C647993b0c1D7faf17c73', + '0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d', ], - }, - ], + ] as const + ).map(([chainNamespace, router, weth, usdc]) => ({ + chainNamespace, + allowedCalls: uniswap(address(router), address(weth), address(usdc)), + })), }, { - constant: 'STAKING', - name: 'Staking', - chains: [ - { - chainNamespace: 'eip155:1', - defaultTokens: STAKING_DEFAULT_TOKENS['eip155:1'], - allowedCalls: [ - { - target: stETH, - selector: 'submit(address)', - maxValue: BigInt(0), - app: 'Lido', - label: 'Stake ETH', - budget: { kind: 'native-value' }, - }, - { - target: wstETH, - selector: 'wrap(uint256)', - app: 'Lido wstETH', - label: 'Wrap stETH', - budget: { kind: 'fixed-token', token: stETH, amountArg: 0 }, - }, - { - target: wstETH, - selector: 'unwrap(uint256)', - app: 'Lido wstETH', - label: 'Unwrap wstETH', - budget: { kind: 'fixed-token', token: wstETH, amountArg: 0 }, - }, - { - target: lidoQueue, - selector: 'requestWithdrawals(uint256[],address)', - pins: [{ arg: 1, expected: wallet }], - app: 'Lido withdrawal queue', - label: 'Request withdrawal', - budget: { kind: 'unsupported', reason: 'DYNAMIC_AMOUNT' }, - }, - { - target: lidoQueue, - selector: 'claimWithdrawals(uint256[],uint256[])', - app: 'Lido withdrawal queue', - label: 'Claim finalized withdrawals', - budget: { kind: 'unsupported', reason: 'POSITION_AMOUNT' }, - }, - { - target: lidoQueue, - selector: 'claimWithdrawal(uint256)', - app: 'Lido withdrawal queue', - label: 'Claim finalized withdrawal', - budget: { kind: 'unsupported', reason: 'POSITION_AMOUNT' }, - }, - - { - target: address('0x858646372CC42E1A627fcE94aa7A7033e7CF075A'), - selector: 'depositIntoStrategy(address,address,uint256)', - app: 'EigenLayer', - label: 'Deposit into strategy (withdrawals not included)', - budget: { kind: 'token-argument', tokenArg: 1, amountArg: 2 }, - }, + constant: 'LENDING', + name: 'Lending', + chains: ( + [ + [ + 'eip155:11155111', + '0x6Ae43d3271ff6888e7Fc43Fd7321a503ff738951', + // Aave's own Sepolia WETH reserve, not the canonical WETH. + '0xC558DBdd856501FCd9aaF1E62eae57A9F0629a3c', ], - approvals: [ - { spender: wstETH, token: stETH, app: 'Lido wstETH' }, - - { - spender: address('0x858646372CC42E1A627fcE94aa7A7033e7CF075A'), - app: 'EigenLayer', - }, + [ + 'eip155:84532', + '0x8bAB6d1b75f19e9eD9fCe8b9BD338844fF79aE27', + '0x4200000000000000000000000000000000000006', ], - }, - - { - chainNamespace: 'eip155:11155111', - defaultTokens: STAKING_DEFAULT_TOKENS['eip155:11155111'], - allowedCalls: [ - { - target: eigen, - selector: 'depositIntoStrategy(address,address,uint256)', - app: 'EigenLayer', - label: 'Deposit into strategy (withdrawals not included)', - budget: { kind: 'token-argument', tokenArg: 1, amountArg: 2 }, - }, + [ + 'eip155:421614', + '0xBfC91D59fdAA134A4ED45f7B584cAf96D7792Eff', + // Aave's own Arbitrum Sepolia WETH reserve. + '0x1dF462e2712496373A347f8ad10802a5E95f053D', ], - approvals: [{ spender: eigen, app: 'EigenLayer' }], - }, - ], + ] as const + ).map(([chainNamespace, pool, weth]) => ({ + chainNamespace, + allowedCalls: aave(address(pool), address(weth)), + })), }, - { constant: 'PREDICTION', name: 'Prediction markets', chains: [] }, + { constant: 'STAKING', name: 'Staking', chains: [] }, ]; diff --git a/packages/core/src/lib/agentic/presets/default-policy.ts b/packages/core/src/lib/agentic/presets/default-policy.ts index dc1cf5dd..03ab4eac 100644 --- a/packages/core/src/lib/agentic/presets/default-policy.ts +++ b/packages/core/src/lib/agentic/presets/default-policy.ts @@ -1,98 +1,26 @@ -import { getAddress, parseUnits } from 'viem'; -import type { Address } from 'viem'; +import { parseUnits, zeroAddress } from 'viem'; import type { RuleAsset } from '../agentic.types'; -import { capabilityUnavailable } from '../errors'; /** Preset-only permission policy. Ordinary rule authoring retains zero defaults. - * Amounts are token quantities, not USD valuations or destination lifetime caps. - * Metadata verified read-only on October 18; evidence is retained under plan/agw/. + * Amounts are ETH quantities sent from Push, not USD valuations or destination + * lifetime caps. */ export const PRESET_VALIDITY_SECONDS = 7 * 24 * 60 * 60; // Explicit profiles keep future chains from inheriting an unreviewed budget. // 20 PC is a ceiling, not the amount charged: execution obtains a fresh quote. -// This budget has testnet protocol-flow coverage; mainnet remains template-only. export const PRESET_GAS_BUDGETS: Readonly> = Object.fromEntries( - [ - 'eip155:1', - 'eip155:8453', - 'eip155:42161', - 'eip155:56', - 'eip155:11155111', - 'eip155:84532', - 'eip155:421614', - 'eip155:97', - ].map((chain) => [chain, parseUnits('20', 18)]) + ['eip155:11155111', 'eip155:84532', 'eip155:421614'].map((chain) => [ + chain, + parseUnits('20', 18), + ]) ); -type TokenBudget = { decimals: number; perCall: string; total: string }; -const stable6: TokenBudget = { decimals: 6, perCall: '10', total: '100' }; -const stable18: TokenBudget = { ...stable6, decimals: 18 }; -const eth: TokenBudget = { decimals: 18, perCall: '0.001', total: '0.01' }; -const bnb: TokenBudget = { decimals: 18, perCall: '0.01', total: '0.1' }; -const link: TokenBudget = { decimals: 18, perCall: '1', total: '10' }; - -// Match by chain AND address. Never infer decimals or limits from a symbol, -// caller metadata, or the position of a token in an arbitrary selection. -const TOKEN_BUDGETS: Readonly< - Record -> = { - 'eip155:1': [ - ['0x0000000000000000000000000000000000000000', eth], - ['0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', eth], - ['0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', stable6], - ['0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84', eth], - ['0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0', eth], - ], - 'eip155:8453': [ - ['0x4200000000000000000000000000000000000006', eth], - ['0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', stable6], - ], - 'eip155:42161': [ - ['0x82aF49447D8a07e3bd95BD0d56f35241523fBab1', eth], - ['0xaf88d065e77c8cC2239327C5EDb3A432268e5831', stable6], - ], - 'eip155:56': [ - ['0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c', bnb], - ['0x55d398326f99059fF775485246999027B3197955', stable18], - ], - 'eip155:11155111': [ - ['0xfff9976782d46cc05630d1f6ebab18b2324d6b14', eth], - ['0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238', stable6], - ['0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5', link], - ['0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9', eth], - ], - 'eip155:84532': [ - ['0x4200000000000000000000000000000000000006', eth], - ['0x036CbD53842c5426634e7929541eC2318f3dCF7e', stable6], - ['0x810D46F9a9027E28F9B01F75E2bdde839dA61115', link], - ['0x4616975f7E6045FD9737e95bC527e9e14c727BD2', stable6], - ['0x663A6F02d547dFd639BF689FED298712f2FB69Fb', eth], - ], - 'eip155:421614': [ - ['0x980B62Da83eFf3D4576C647993b0c1D7faf17c73', eth], - ['0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d', stable6], - ], - 'eip155:97': [ - ['0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd', bnb], - ['0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c', stable6], - ['0x16227D60f7a0e586C66B005219dfc887D13C9531', stable6], - ], -}; - -export function defaultPresetAsset(chain: string, token: Address): RuleAsset { - const budget = TOKEN_BUDGETS[chain]?.find( - ([address]) => getAddress(address) === getAddress(token) - )?.[1]; - if (!budget) - throw capabilityUnavailable( - 'presetPolicy', - `No reviewed default spending policy for ${chain}:${token}` - ); +export function defaultPresetAsset(): RuleAsset { return { - token, - maxPerCall: parseUnits(budget.perCall, budget.decimals), - maxTotal: parseUnits(budget.total, budget.decimals), + token: zeroAddress, + maxPerCall: parseUnits('0.001', 18), + maxTotal: parseUnits('0.01', 18), }; } diff --git a/packages/core/src/lib/agentic/presets/default-tokens.ts b/packages/core/src/lib/agentic/presets/default-tokens.ts deleted file mode 100644 index 09f38ece..00000000 --- a/packages/core/src/lib/agentic/presets/default-tokens.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { getAddress, zeroAddress, type Address } from 'viem'; - -/** Curated subsets of the reviewed catalog. Addresses are destination tokens, - * not a promise that a Push PRC20 route or protocol liquidity is available. - * Keep these sets within the policy's 32-call/32-pin limits after expansion. - * Testnet DEX pairs and lending/staking assets match the live preset fixtures. - * Mainnet addresses share the catalog's October 15 read-only source baseline. - * Spending caps are intentionally separate from token selection. - */ -const addresses = (...values: string[]): readonly Address[] => - values.map((value) => getAddress(value.toLowerCase())); - -export const DEX_DEFAULT_TOKENS: Readonly> = - { - 'eip155:1': addresses( - '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', - '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' - ), - 'eip155:8453': addresses( - '0x4200000000000000000000000000000000000006', - '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913' - ), - 'eip155:42161': addresses( - '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1', - '0xaf88d065e77c8cC2239327C5EDb3A432268e5831' - ), - 'eip155:56': addresses( - '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c', - '0x55d398326f99059fF775485246999027B3197955' - ), - 'eip155:11155111': addresses( - '0xfff9976782d46cc05630d1f6ebab18b2324d6b14', - '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238' - ), - 'eip155:84532': addresses( - '0x4200000000000000000000000000000000000006', - '0x036CbD53842c5426634e7929541eC2318f3dCF7e' - ), - 'eip155:421614': addresses( - '0x980B62Da83eFf3D4576C647993b0c1D7faf17c73', - '0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d' - ), - 'eip155:97': addresses( - '0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd', - '0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c' - ), - }; - -export const LENDING_DEFAULT_TOKENS: Readonly< - Record -> = { - 'eip155:1': DEX_DEFAULT_TOKENS['eip155:1'], - // One shared reserve/market token keeps Aave + Moonwell/Venus within 32 pins. - 'eip155:8453': addresses('0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913'), - 'eip155:42161': DEX_DEFAULT_TOKENS['eip155:42161'], - 'eip155:56': addresses('0x55d398326f99059fF775485246999027B3197955'), - // Protocol testnet reserves differ from Circle USDC and DEX wrapped ETH. - 'eip155:11155111': addresses('0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5'), - 'eip155:84532': addresses( - '0x810D46F9a9027E28F9B01F75E2bdde839dA61115', - '0x4616975f7E6045FD9737e95bC527e9e14c727BD2', - '0x663A6F02d547dFd639BF689FED298712f2FB69Fb' - ), - 'eip155:421614': addresses('0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d'), - 'eip155:97': addresses( - '0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c', - '0x16227D60f7a0e586C66B005219dfc887D13C9531' - ), -}; - -export const STAKING_DEFAULT_TOKENS: Readonly< - Record -> = { - 'eip155:1': addresses( - zeroAddress, - '0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84', - '0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0' - ), - 'eip155:11155111': addresses('0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9'), -}; diff --git a/packages/core/src/lib/agentic/presets/index.ts b/packages/core/src/lib/agentic/presets/index.ts index b98ba0fd..7925edf3 100644 --- a/packages/core/src/lib/agentic/presets/index.ts +++ b/packages/core/src/lib/agentic/presets/index.ts @@ -10,14 +10,10 @@ import type { AgenticPresets, PresetOptions, PresetRuleTemplate, - PresetChainReadiness, - PresetConfigurationIssue, } from './types'; import { parseSelector } from '../codec/selectors'; import { PRESET_CATALOG, type PresetDefinition } from './catalog'; -import { applyOperationLimits, assetAddress } from './operation-limits'; -import { PUSH_NETWORK } from '../../constants/enums'; -import { presetRoutes } from './routes'; +import { applyOperationLimits, nativeAsset } from './operation-limits'; import { defaultPresetAsset, PRESET_GAS_BUDGETS, @@ -28,7 +24,6 @@ const MAX_UINT256 = (BigInt(1) << BigInt(256)) - BigInt(1); const invalid = (message: string) => new AgenticError(AGENTIC_ERROR_CODE.INVALID_RULE, message); function cap(value: unknown, name: string): bigint { - if (value === undefined) return BigInt(0); if (typeof value !== 'bigint' || value < BigInt(0) || value > MAX_UINT256) throw invalid(`${name} must be a uint256 bigint`); return value; @@ -55,12 +50,6 @@ function copyCall(call: RuleCall): RuleCall { : {}), }; } -function tokenAddress(token: RuleAsset['token']): string { - const address = typeof token === 'string' ? token : token?.address; - if (typeof address !== 'string' || !address.trim()) - throw invalid('preset asset requires a token address'); - return address; -} /** Not a public registration API. Tests inject fixtures; production uses the bundled catalog. */ export function buildPresetApi( catalog: readonly PresetDefinition[] @@ -70,25 +59,18 @@ export function buildPresetApi( ...p, chains: p.chains.map((c) => ({ ...c, - ...(c.defaultTokens ? { defaultTokens: [...c.defaultTokens] } : {}), allowedCalls: c.allowedCalls.map((call) => ({ ...copyCall(call), ...(call.budget ? { - budget: { - ...call.budget, - ...(call.budget.kind === 'token-argument' && call.budget.tokens - ? { tokens: [...call.budget.tokens] } - : {}), - }, + budget: + call.budget.kind === 'native-amount' && + typeof call.budget.amountArg !== 'number' + ? { ...call.budget, amountArg: [...call.budget.amountArg] } + : { ...call.budget }, } : {}), })), - approvals: c.approvals?.map((a) => ({ - ...a, - ...(a.tokens ? { tokens: [...a.tokens] } : {}), - })), - swapRouters: c.swapRouters?.map((r) => ({ ...r })), })), })); if ( @@ -118,9 +100,6 @@ export function buildPresetApi( if (!options || typeof options !== 'object' || Array.isArray(options)) throw invalid('preset options must be an object'); const now = Math.floor(Date.now() / 1000); - const network = options.network ?? PUSH_NETWORK.TESTNET_DONUT; - if (!Object.values(PUSH_NETWORK).includes(network)) - throw invalid('unknown preset Push network'); if ('funding' in options) throw invalid( 'The preset funding option is no longer supported. Remove it; preset assets and limits are always preserved.' @@ -159,18 +138,9 @@ export function buildPresetApi( 'presetCatalog', `preset ${preset} has no approved app entries` ); - const assets = new Map(); - // An explicit array (including []) replaces the defaults for all selected - // chains. Never add permissions on chains the caller left unconfigured. - if (options.assets === undefined) - for (const chain of chains) - if (chain.defaultTokens) - assets.set( - chain.chainNamespace, - chain.defaultTokens.map((token) => - defaultPresetAsset(chain.chainNamespace, token) - ) - ); + // Presets move native ETH from Push only; the app tokens are wrapped or + // swapped on the destination chain. + const assets = new Map(); for (const asset of options.assets ?? []) { if (!asset || typeof asset !== 'object') throw invalid('preset asset must be an object'); @@ -181,186 +151,51 @@ export function buildPresetApi( ); if (!chains.some((c) => c.chainNamespace === chain)) throw invalid(`asset chain ${chain} is outside the selected preset`); - const address = tokenAddress(asset.token); - if ( - chain.startsWith('eip155:') && - !isAddress(address, { strict: false }) - ) - throw invalid('EVM preset asset requires an EVM address'); - const group = assets.get(chain) ?? []; - const key = chain.startsWith('eip155:') - ? address.toLowerCase() - : address; if ( - group.some( - (a) => - (chain.startsWith('eip155:') - ? tokenAddress(a.token).toLowerCase() - : tokenAddress(a.token)) === key - ) + !asset.token || + !nativeAsset({ token: asset.token, maxPerCall: BigInt(0) }) ) + throw invalid( + "Presets send only ETH from Push. Use the zero address or the chain's ETH moveable token." + ); + if (assets.has(chain)) throw invalid('duplicate preset asset on the same chain'); - group.push({ + const maxPerCall = cap(asset.maxPerCall, 'maxPerCall'); + const maxTotal = cap(asset.maxTotal, 'maxTotal'); + if (maxPerCall === BigInt(0) || maxTotal === BigInt(0)) + throw invalid( + 'Set a positive maxPerCall and maxTotal for ETH. A missing or zero limit lets the agent spend nothing.' + ); + assets.set(chain, { token: typeof asset.token === 'string' ? asset.token : { ...asset.token }, - maxPerCall: cap(asset.maxPerCall, 'maxPerCall'), - maxTotal: cap(asset.maxTotal, 'maxTotal'), + maxPerCall, + maxTotal, }); - assets.set(chain, group); } - const readiness: PresetChainReadiness[] = []; + if (options.assets !== undefined) + for (const chain of chains) + if (!assets.has(chain.chainNamespace)) + throw invalid( + `Add an ETH asset for ${chain.chainNamespace}, or pass chainNamespace to configure one chain.` + ); const rules: PresetRuleTemplate[] = chains.map((chain) => { + const asset = assets.get(chain.chainNamespace) ?? defaultPresetAsset(); const maxGasPerCall = options.maxGasPerCall ?? chain.maxGasPerCall ?? - (chain.defaultTokens - ? PRESET_GAS_BUDGETS[chain.chainNamespace] - : undefined); - const selectedAssets = assets.get(chain.chainNamespace) ?? []; - const limits = applyOperationLimits( + PRESET_GAS_BUDGETS[chain.chainNamespace]; + const calls = applyOperationLimits( chain.allowedCalls.map((c) => ({ ...copyCall(c), ...(c.budget ? { budget: c.budget } : {}), })), - selectedAssets + asset.maxPerCall ); - const calls = limits.calls; - if (chain.swapRouters?.length) { - const tokens = assets.get(chain.chainNamespace) ?? []; - if ( - tokens.some( - (a) => - tokenAddress(a.token) === zeroAddress || - (typeof a.token !== 'string' && a.token.mechanism === 'native') - ) - ) - throw invalid( - 'DEX token pins require explicit ERC20 addresses; use wrapped-native tokens instead of the native marker' - ); - // Keep discovery useful before a swap pair is selected. These review - // calls cannot spend input tokens: the amount maximum is explicitly zero. - // Re-run get with both tokens to generate the executable pair pins. - if (tokens.length < 2) - for (const router of chain.swapRouters) - for (const exactInput of [true, false]) - calls.push({ - target: router.address, - selector: `${ - exactInput ? 'exactInputSingle' : 'exactOutputSingle' - }((address,address,uint24,address,uint256,uint256,uint160))`, - pins: [ - ...(tokens.length - ? [ - { - arg: [0, 0], - expected: getAddress(tokenAddress(tokens[0].token)), - }, - ] - : []), - { arg: [0, 3], expected: 'agentic:wallet' }, - { arg: [0, exactInput ? 4 : 5], max: BigInt(0) }, - ], - app: router.app, - label: `${ - exactInput ? 'Swap exact input' : 'Swap exact output' - } (select two tokens to enable)`, - }); - for (const router of chain.swapRouters) - for (const input of tokens) - for (const output of tokens) { - if ( - tokenAddress(input.token).toLowerCase() === - tokenAddress(output.token).toLowerCase() - ) - continue; - for (const exactInput of [true, false]) - calls.push({ - target: router.address, - selector: `${ - exactInput ? 'exactInputSingle' : 'exactOutputSingle' - }((address,address,uint24,address,uint256,uint256,uint160))`, - pins: [ - { - arg: [0, 0], - expected: getAddress(tokenAddress(input.token)), - }, - { - arg: [0, 1], - expected: getAddress(tokenAddress(output.token)), - }, - { arg: [0, 3], expected: 'agentic:wallet' }, - { arg: [0, exactInput ? 4 : 5], max: input.maxPerCall }, - ], - app: router.app, - label: exactInput - ? 'Swap exact input' - : 'Swap exact output', - }); - } - } - if (chain.swapRouters?.length) { - const swaps = calls.filter((c) => c.selector.startsWith('exact')); - for (const c of swaps) { - const positive = c.pins?.some( - (p) => 'max' in p && p.max !== undefined && p.max > BigInt(0) - ); - if (positive) limits.enabled = true; - else - limits.disabledCalls.push({ - target: c.target, - selector: c.selector, - app: c.app, - reason: - selectedAssets.length < 2 ? 'TOKEN_REQUIRED' : 'ZERO_CAP', - }); - } - } - const approvals = new Set(); - for (const asset of assets.get(chain.chainNamespace) ?? []) { - const token = tokenAddress(asset.token); - if ( - token === zeroAddress || - (typeof asset.token !== 'string' && - asset.token.mechanism === 'native') - ) - continue; - for (const approval of chain.approvals ?? []) { - if (!chain.chainNamespace.startsWith('eip155:')) - throw capabilityUnavailable( - 'presetApproval', - 'Solana approvals require a separately reviewed instruction template' - ); - if ( - approval.token && - getAddress(token) !== getAddress(approval.token) - ) - continue; - if ( - approval.tokens && - !approval.tokens.some((t) => getAddress(t) === getAddress(token)) - ) - continue; - const spender = getAddress(approval.spender); - const target = getAddress(token); - const approvalKey = `${target}:${spender}`; - if (approvals.has(approvalKey)) continue; - approvals.add(approvalKey); - calls.push({ - target, - selector: 'approve(address,uint256)', - pins: [ - { arg: 0, expected: spender }, - { arg: 1, max: asset.maxPerCall }, - ], - app: approval.app, - label: 'Approve token spending', - }); - } - } if (!calls.length || calls.length > 32) throw capabilityUnavailable( 'presetCalls', - 'preset must contain 1..32 allowed calls including approvals' + 'preset must contain 1..32 allowed calls' ); const conditionCount = calls.reduce( (n, c) => n + (c.pins?.length ?? 0), @@ -396,62 +231,6 @@ export function buildPresetApi( ); pairs.set(pair, !!call.pins?.length); } - const issues: PresetConfigurationIssue[] = []; - if (!options.agent) - issues.push({ - code: 'AGENT_REQUIRED', - message: 'Choose the agent Push address.', - }); - if ((maxGasPerCall ?? BigInt(0)) === BigInt(0)) - issues.push({ - code: 'GAS_BUDGET_REQUIRED', - message: 'Set a positive PC gas budget per outbound.', - }); - if (!selectedAssets.length) - issues.push({ - code: 'ASSETS_REQUIRED', - message: - 'No tokens selected: transfers from Push are disabled, not unrestricted. Choose explicit tokens and limits, then regenerate this preset.', - }); - if (chain.swapRouters?.length && selectedAssets.length < 2) - issues.push({ - code: 'TOKEN_PAIR_REQUIRED', - message: 'Choose both swap tokens, then regenerate this preset.', - }); - if (!limits.enabled) - issues.push({ - code: 'NO_ENABLED_OPERATION', - message: 'No asset operation has a positive per-call limit.', - }); - const configurationReady = issues.length === 0; - const routes = presetRoutes( - chain.chainNamespace, - selectedAssets, - network - ); - issues.push(...routes.issues); - const bridgeAssets = selectedAssets; - readiness.push({ - chainNamespace: chain.chainNamespace, - ready: issues.length === 0, - configurationReady, - selectedAssets: selectedAssets.map((a) => ({ - ...a, - token: typeof a.token === 'string' ? a.token : { ...a.token }, - })), - bridgeAssets: routes.bridgeAssets, - issues, - disabledCalls: limits.disabledCalls, - excludedCalls: limits.excludedCalls, - knownTokens: [ - ...new Set([...limits.knownTokens, ...(chain.defaultTokens ?? [])]), - ], - zeroBridgeLimits: bridgeAssets - .filter( - (a) => a.maxPerCall === BigInt(0) || a.maxTotal === BigInt(0) - ) - .map(assetAddress), - }); return { chainNamespace: chain.chainNamespace, allowedCalls: calls, @@ -459,21 +238,13 @@ export function buildPresetApi( ? { agent: getAddress(options.agent) } : {}), validUntil, - ...(options.assets !== undefined || chain.defaultTokens - ? { assets: bridgeAssets } - : {}), + assets: [asset], ...(maxGasPerCall !== undefined ? { maxGasPerCall: cap(maxGasPerCall, 'maxGasPerCall') } : {}), }; }); - return { - rules, - readiness: { - ready: readiness.length > 0 && readiness.every((c) => c.ready), - chains: readiness, - }, - }; + return { rules }; }, }; // Expiry is generated; the overload narrows templates when the agent is supplied. diff --git a/packages/core/src/lib/agentic/presets/operation-limits.ts b/packages/core/src/lib/agentic/presets/operation-limits.ts index 4466eb93..9b8a2ce2 100644 --- a/packages/core/src/lib/agentic/presets/operation-limits.ts +++ b/packages/core/src/lib/agentic/presets/operation-limits.ts @@ -1,7 +1,6 @@ -import { getAddress, zeroAddress } from 'viem'; +import { zeroAddress } from 'viem'; import type { RuleAsset, RuleCall } from '../agentic.types'; import type { PresetCallDefinition } from './catalog'; -import type { PresetCallIssue } from './types'; export const assetAddress = (asset: RuleAsset): string => typeof asset.token === 'string' ? asset.token : asset.token.address; @@ -9,108 +8,23 @@ export const nativeAsset = (asset: RuleAsset): boolean => assetAddress(asset) === zeroAddress || (typeof asset.token !== 'string' && asset.token.mechanism === 'native'); -/** Compile reviewed protocol argument positions. No exchange-rate or share guesses. */ +/** Fill the reviewed native-ETH caps: maxValue on the wrap, amount maxima on + * every call that spends the wrapped ETH. */ export function applyOperationLimits( definitions: readonly PresetCallDefinition[], - assets: RuleAsset[] -) { - const matches = (definition: PresetCallDefinition): RuleAsset[] => { - const b = definition.budget; - if (!b) return []; - if (b.kind === 'native-value') return assets.filter(nativeAsset); - if (b.kind === 'fixed-token') - return assets.filter( - (a) => - !nativeAsset(a) && getAddress(assetAddress(a)) === getAddress(b.token) - ); - if (b.kind === 'token-argument') - return assets.filter( - (a) => - !nativeAsset(a) && - (!b.tokens || - b.tokens.some((t) => getAddress(t) === getAddress(assetAddress(a)))) - ); - return []; - }; - const previewAll = !definitions.some((d) => matches(d).length > 0); - const calls: RuleCall[] = []; - const disabledCalls: PresetCallIssue[] = [], - excludedCalls: PresetCallIssue[] = []; - const knownTokens = new Set(); - let enabled = false; - for (const definition of definitions) { - const { budget, ...call } = definition; - if (!budget || budget.kind === 'setup') { - calls.push(call); - if (!budget) enabled = true; // Non-budgeted internal fixture entries only. - continue; - } - const info = { - target: call.target, - selector: call.selector, - ...(call.app ? { app: call.app } : {}), - }; - if (budget.kind === 'unsupported') { - excludedCalls.push({ - ...info, - reason: budget.reason, - ...(budget.alternative ? { alternative: budget.alternative } : {}), - }); - continue; - } - if (budget.kind === 'fixed-token') - knownTokens.add(getAddress(budget.token)); - if (budget.kind === 'native-value') knownTokens.add(zeroAddress); - if (budget.kind === 'token-argument') - budget.tokens?.forEach((t) => knownTokens.add(getAddress(t))); - const selected = matches(definition); - if (!selected.length && !previewAll) { - excludedCalls.push({ - ...info, - reason: 'UNSELECTED_TOKEN', - ...(budget.kind === 'fixed-token' - ? { token: getAddress(budget.token) } - : {}), - }); - continue; - } - for (const asset of selected.length ? selected : [undefined]) { - const maximum = asset?.maxPerCall ?? BigInt(0); - const pins = [...(call.pins ?? [])]; - if (budget.kind === 'token-argument' && asset) - pins.push({ - arg: budget.tokenArg, - expected: getAddress(assetAddress(asset)), - }); - if (budget.kind !== 'native-value') - pins.push({ arg: budget.amountArg, max: maximum }); - calls.push({ + maxPerCall: bigint +): RuleCall[] { + return definitions.map(({ budget, ...call }) => { + if (budget?.kind === 'native-value') + return { ...call, maxValue: maxPerCall }; + if (budget?.kind === 'native-amount') + return { ...call, - ...(pins.length ? { pins } : {}), - ...(budget.kind === 'native-value' ? { maxValue: maximum } : {}), - }); - if (maximum > BigInt(0)) enabled = true; - else - disabledCalls.push({ - ...info, - reason: asset - ? 'ZERO_CAP' - : assets.length - ? 'UNSELECTED_TOKEN' - : 'TOKEN_REQUIRED', - ...(asset - ? { token: assetAddress(asset) } - : budget.kind === 'fixed-token' - ? { token: getAddress(budget.token) } - : {}), - }); - } - } - return { - calls, - enabled, - disabledCalls, - excludedCalls, - knownTokens: [...knownTokens], - }; + pins: [ + ...(call.pins ?? []), + { arg: budget.amountArg, max: maxPerCall }, + ], + }; + return call; + }); } diff --git a/packages/core/src/lib/agentic/presets/routes.ts b/packages/core/src/lib/agentic/presets/routes.ts deleted file mode 100644 index c022fa08..00000000 --- a/packages/core/src/lib/agentic/presets/routes.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { PUSH_NETWORK, type CHAIN } from '../../constants/enums'; -import { SUPPORTED_GATEWAY_CHAINS } from '../../orchestrator/internals/helpers'; -import { resolveAgenticPrc20 } from '../token-routes'; -import { generationsFor } from '../deployments'; -import type { RuleAsset } from '../agentic.types'; -import type { PresetChainReadiness, PresetConfigurationIssue } from './types'; -import { assetAddress } from './operation-limits'; - -/** Offline registry checks only. Grant preparation still verifies source metadata - * and wiring against chain state before any signature or transaction. */ -export function presetRoutes( - chain: string, - assets: RuleAsset[], - network: PUSH_NETWORK -): { - bridgeAssets: PresetChainReadiness['bridgeAssets']; - issues: PresetConfigurationIssue[]; -} { - const issues: PresetConfigurationIssue[] = []; - network = - network === PUSH_NETWORK.TESTNET ? PUSH_NETWORK.TESTNET_DONUT : network; - if (!generationsFor(network).some((g) => g.advertised)) - issues.push({ - code: 'AGW_NETWORK_UNAVAILABLE', - message: `No verified AGW deployment is registered for ${network}.`, - }); - const supported = SUPPORTED_GATEWAY_CHAINS.includes(chain as CHAIN); - if (!supported) - issues.push({ - code: 'DESTINATION_UNAVAILABLE', - message: `The SDK has no supported gateway route to ${chain}; this is a catalog template.`, - }); - const bridgeAssets = assets.map((asset) => { - const token = assetAddress(asset); - try { - if (!supported) throw new Error(`No supported gateway route to ${chain}`); - const prc20 = resolveAgenticPrc20({ chain, address: token }, network); - return { - token, - prc20: prc20.address, - status: 'registered' as const, - }; - } catch { - issues.push({ - code: 'BRIDGE_ASSET_UNAVAILABLE', - token, - message: `No SDK PRC20 mapping for ${chain}:${token} on ${network}. This preset cannot be created with this token until its Push route is verified. Choose a routed token only if the selected app supports that exact token address.`, - }); - return { token, status: 'unavailable' as const }; - } - }); - return { bridgeAssets, issues }; -} diff --git a/packages/core/src/lib/agentic/presets/types.ts b/packages/core/src/lib/agentic/presets/types.ts index 0e2983e8..30bd5c0d 100644 --- a/packages/core/src/lib/agentic/presets/types.ts +++ b/packages/core/src/lib/agentic/presets/types.ts @@ -1,13 +1,7 @@ import type { Address } from 'viem'; -import type { PUSH_NETWORK } from '../../constants/enums'; -import type { - Rule, - RuleAsset, - RuleCall, - ForeignChainNamespace, -} from '../agentic.types'; +import type { Rule, RuleAsset, ForeignChainNamespace } from '../agentic.types'; -export type PresetCategory = 'DEXES' | 'LENDING' | 'STAKING' | 'PREDICTION'; +export type PresetCategory = 'DEXES' | 'LENDING' | 'STAKING'; export interface Preset { type: 'CATEGORY'; constant: PresetCategory; @@ -19,18 +13,18 @@ export type PresetRuleTemplate = Omit & { agent?: Address; validUntil?: number; }; +/** Presets send native ETH from Push only: the zero address, a native + * MoveableToken (for example CONSTANTS.MOVEABLE.TOKEN.BASE_SEPOLIA.ETH). */ export interface PresetAsset { chainNamespace?: ForeignChainNamespace; token: RuleAsset['token']; - /** Per allowed operation and per Push outbound, in raw token units. Omitted = 0. + /** Per Push outbound and per allowed operation, in wei. Required and positive. * Does not aggregate multiple destination calls in one transaction. */ - maxPerCall?: bigint; - /** Cumulative Push-outbound amount only; not lifetime activity on destination-held assets. Omitted = 0. */ - maxTotal?: bigint; + maxPerCall: bigint; + /** Cumulative Push-outbound amount, in wei. Required and positive. */ + maxTotal: bigint; } export interface PresetOptions { - /** Offline route/deployment checks; defaults to TESTNET_DONUT. */ - network?: PUSH_NETWORK; /** Push-PC budget ceiling per outbound; omitted uses the catalog policy (20 PC). * Explicit zero is preserved. This is not the fee charged. */ maxGasPerCall?: bigint; @@ -38,71 +32,17 @@ export interface PresetOptions { agent?: Address; /** Omitted: seven days from generation time. Explicit expiry is preserved. */ validUntil?: number; - /** Omitted: include the catalog's curated tokens and explicit spending policy. - * An explicit array replaces all defaults (including [] to select no tokens). - * Supplied assets retain zero for omitted caps; no policy is guessed for them. - * DEX swaps with fewer than two tokens remain zero-input-cap review templates. */ + /** Omitted: each chain gets the catalog's ETH limits. Supplied: exactly one + * native ETH asset for every selected chain. */ assets?: PresetAsset[]; } export interface ReadyPresetOptions extends PresetOptions { agent: Address; } -/** Offline configuration/registry checks; chain state and balances are not checked. */ -export interface PresetConfigurationIssue { - code: - | 'AGENT_REQUIRED' - | 'EXPIRY_REQUIRED' - | 'GAS_BUDGET_REQUIRED' - | 'ASSETS_REQUIRED' - | 'TOKEN_PAIR_REQUIRED' - | 'NO_ENABLED_OPERATION' - | 'AGW_NETWORK_UNAVAILABLE' - | 'DESTINATION_UNAVAILABLE' - | 'BRIDGE_ASSET_UNAVAILABLE'; - message: string; - token?: string; -} -export interface PresetCallIssue { - target: string; - selector: RuleCall['selector']; - app?: string; - reason: - | 'TOKEN_REQUIRED' - | 'ZERO_CAP' - | 'UNSELECTED_TOKEN' - | 'SHARE_AMOUNT' - | 'DYNAMIC_AMOUNT' - | 'POSITION_AMOUNT'; - token?: string; - alternative?: RuleCall['selector']; -} -export interface PresetChainReadiness { - chainNamespace: ForeignChainNamespace; - ready: boolean; - configurationReady: boolean; - /** Selected assets and caps, matching the returned rule assets. */ - selectedAssets: RuleAsset[]; - /** Registry presence only; grant preparation verifies exact on-chain identity. */ - bridgeAssets: { - token: string; - status: 'registered' | 'unavailable'; - prc20?: Address; - }[]; - issues: PresetConfigurationIssue[]; - /** Calls present in the rule but disabled by a zero amount/value maximum. */ - disabledCalls: PresetCallIssue[]; - /** Calls deliberately omitted, including operations with incompatible amount units. */ - excludedCalls: PresetCallIssue[]; - /** Known catalog token addresses, including the curated default subset. */ - knownTokens: string[]; - /** Selected tokens with a zero Push-outbound budget; destination-held assets are separate. */ - zeroBridgeLimits: string[]; -} export interface PresetResult< T extends PresetRuleTemplate = PresetRuleTemplate > { rules: T[]; - readiness: { ready: boolean; chains: PresetChainReadiness[] }; } export interface AgenticPresets { list(options?: { type?: 'CATEGORY' }): { presets: Preset[] }; diff --git a/packages/core/src/lib/agentic/public-rule.ts b/packages/core/src/lib/agentic/public-rule.ts index 12e49cd4..9e1a4a80 100644 --- a/packages/core/src/lib/agentic/public-rule.ts +++ b/packages/core/src/lib/agentic/public-rule.ts @@ -19,6 +19,7 @@ import { } from 'viem'; import type { Rule, + RuleAsset, RuleInput, InternalRule, NativeAction, @@ -38,6 +39,7 @@ import { UINT256_MAX } from './codec/defaults'; import { deriveAgwSvmCea, svmKey } from './codec/svm-accounts'; import type { AgenticRuntime } from './runtime'; import { CHAIN } from '../constants/enums'; +import { isMoveableTokenSet } from '../constants/tokens'; import { resolveRuleDestination } from './management/destination'; export const WALLET = 'agentic:wallet' as const; @@ -64,6 +66,13 @@ function rejectFields(obj: object, fields: string[], where: string) { `${where}.${field} is not supported by the current rule shape` ); } +/** Preparation expands MOVEABLE ALL markers before normalization. */ +function authoredAssets(rule: Rule): RuleAsset[] { + const assets = rule.assets ?? []; + if (assets.some((a) => isMoveableTokenSet(a?.token))) + throw invalid('expand MOVEABLE ALL assets before normalizing a rule'); + return assets; +} function uint(value: unknown, name: string): bigint { if (typeof value !== 'bigint' || value < BigInt(0) || value > UINT256_MAX) throw invalid(`${name} must be a uint256 bigint`); @@ -139,6 +148,8 @@ export async function normalizePublicRule( 'ref', 'allowedInstructions', 'outputTokens', + // Expanded into transfer calls during preparation (management/rule-inputs). + 'transferTo', ], 'rule' ); @@ -154,11 +165,21 @@ export async function normalizePublicRule( ) throw new AgenticError( AGENTIC_ERROR_CODE.INVALID_RULE, - 'Add at least one allowed function. Selecting tokens and limits alone does not authorize transfers.', + 'Add at least one allowed function, or select tokens on an EVM network to allow transfers back to the owner.', { details: { reason: 'ALLOWED_FUNCTION_REQUIRED', field: 'allowedCalls' }, } ); + // Push-chain rules have the smaller limit; report it before the generic one. + if ( + r.chainNamespace === undefined && + Array.isArray(r.allowedCalls) && + r.allowedCalls.length > 8 + ) + throw capabilityUnavailable( + 'nativeActions', + 'the deployed v6 wallet permits at most eight native actions' + ); if ( !Array.isArray(r.allowedCalls) || r.allowedCalls.length < 1 || @@ -208,11 +229,6 @@ export async function normalizePublicRule( const native = r.chainNamespace === undefined; if (r.chainNamespace === runtime.pushChainNamespace) throw invalid('omit chainNamespace for Push rules'); - if (native && r.allowedCalls.length > 8) - throw capabilityUnavailable( - 'nativeActions', - 'the deployed v6 wallet permits at most eight native actions' - ); if (native && (r.assets !== undefined || r.maxGasPerCall !== undefined)) throw invalid('native rules do not carry assets or maxGasPerCall'); const own = native @@ -276,7 +292,7 @@ export async function normalizePublicRule( agent: r.agent, validUntil: r.validUntil, chainNamespace: r.chainNamespace as `eip155:${string}`, - assets: (r.assets ?? []).map((a) => ({ + assets: authoredAssets(r).map((a) => ({ ...a, token: a.token as Address, maxTotal: a.maxTotal ?? BigInt(0), @@ -333,7 +349,7 @@ function svmRule(rule: Rule, cea: Hex): SolanaRule { ) ), ], - assets: (rule.assets ?? []).map((asset) => ({ + assets: authoredAssets(rule).map((asset) => ({ ...asset, maxTotal: asset.maxTotal ?? BigInt(0), })), diff --git a/packages/core/src/lib/agentic/revert.ts b/packages/core/src/lib/agentic/revert.ts index 0c4430ff..bedabd2f 100644 --- a/packages/core/src/lib/agentic/revert.ts +++ b/packages/core/src/lib/agentic/revert.ts @@ -1,5 +1,6 @@ import { decodeErrorResult, + parseAbi, toFunctionSelector, type Abi, type Hex, @@ -16,9 +17,17 @@ import { /** URP reverts reached through the engine are truncated to this wrapper. */ export const POLICY_CHECK_REVERTED_SELECTOR = '0xf4270752'; +/** URP builds these with abi.encodeWithSelector (any-match over allowed calls), + * so the compiled ABI omits them. Signatures from src/libraries/Errors.sol at ffd567d. */ +const URP_ENCODED_ERRORS = parseAbi([ + 'error BeneficiaryMismatch(address expected, address actual)', + 'error InnerValueExceedsAllowance(uint256 index, uint256 value, uint256 maxValue)', +]); + const ERROR_ABIS: readonly Abi[] = [ AGW_ABI as unknown as Abi, UNIVERSAL_RULES_POLICY_ABI as unknown as Abi, + URP_ENCODED_ERRORS, AGW_FACTORY_ABI as unknown as Abi, SMART_SESSION_ABI as unknown as Abi, ]; diff --git a/packages/core/src/lib/constants/index.ts b/packages/core/src/lib/constants/index.ts index a9ee4211..69060a3d 100644 --- a/packages/core/src/lib/constants/index.ts +++ b/packages/core/src/lib/constants/index.ts @@ -54,6 +54,7 @@ export const READ_CONSTANTS = { } as const; export type { MoveableToken, + MoveableTokenSet, PayableToken, PushChainMoveableToken, ChainSuffixAccessor, diff --git a/packages/core/src/lib/constants/tokens.ts b/packages/core/src/lib/constants/tokens.ts index c2c710ad..ae463519 100644 --- a/packages/core/src/lib/constants/tokens.ts +++ b/packages/core/src/lib/constants/tokens.ts @@ -40,10 +40,26 @@ export type PayableTokenMap = Partial<{ DAI: PayableToken; }>; +/** Agentic rule assets only: every token Push can send to `chain`. The SDK + * expands it when a rule is prepared (at most eight, each with its default + * limits). It is not a token and cannot be sent or paid with. */ +export interface MoveableTokenSet { + readonly kind: 'ALL'; + readonly chain: CHAIN; +} + +export const isMoveableTokenSet = (token: unknown): token is MoveableTokenSet => + !!token && + typeof token === 'object' && + (token as { kind?: unknown }).kind === 'ALL'; + // Strongly-typed accessors that throw at runtime if a token is unavailable, // while providing non-undefined types at compile time. export class MoveableTokenAccessor { - constructor(private readonly tokens: Record) {} + constructor( + private readonly tokens: Record, + private readonly chain?: CHAIN + ) {} private require(name: keyof MoveableTokenMap): MoveableToken { const t = this.tokens[name as string]; @@ -76,6 +92,11 @@ export class MoveableTokenAccessor { get DAI(): MoveableToken { return this.require('DAI'); } + /** Every routable token on this chain, for agentic rule assets only. */ + get ALL(): MoveableTokenSet { + if (!this.chain) throw new Error('ALL is not available on this chain'); + return Object.freeze({ kind: 'ALL' as const, chain: this.chain }); + } } export class PayableTokenAccessor { @@ -549,37 +570,43 @@ function buildMoveableTokenConstants(): MoveableTokenConstantsMap { toSymbolMap(MOVEABLE_TOKENS[CHAIN.ETHEREUM_SEPOLIA]) as Record< string, MoveableToken - > + >, + CHAIN.ETHEREUM_SEPOLIA ), ETHEREUM_MAINNET: new MoveableTokenAccessor( toSymbolMap(MOVEABLE_TOKENS[CHAIN.ETHEREUM_MAINNET]) as Record< string, MoveableToken - > + >, + CHAIN.ETHEREUM_MAINNET ), ARBITRUM_SEPOLIA: new MoveableTokenAccessor( toSymbolMap(MOVEABLE_TOKENS[CHAIN.ARBITRUM_SEPOLIA]) as Record< string, MoveableToken - > + >, + CHAIN.ARBITRUM_SEPOLIA ), BASE_SEPOLIA: new MoveableTokenAccessor( toSymbolMap(MOVEABLE_TOKENS[CHAIN.BASE_SEPOLIA]) as Record< string, MoveableToken - > + >, + CHAIN.BASE_SEPOLIA ), BNB_TESTNET: new MoveableTokenAccessor( toSymbolMap(MOVEABLE_TOKENS[CHAIN.BNB_TESTNET]) as Record< string, MoveableToken - > + >, + CHAIN.BNB_TESTNET ), SOLANA_DEVNET: new MoveableTokenAccessor( toSymbolMap(MOVEABLE_TOKENS[CHAIN.SOLANA_DEVNET]) as Record< string, MoveableToken - > + >, + CHAIN.SOLANA_DEVNET ), PUSH_TESTNET_DONUT: buildPushChainMoveableTokenAccessor(), }; diff --git a/packages/core/src/lib/index.ts b/packages/core/src/lib/index.ts index ebea7e1b..fb393765 100644 --- a/packages/core/src/lib/index.ts +++ b/packages/core/src/lib/index.ts @@ -263,6 +263,8 @@ export type { AgenticWallet, AllowedCall, AssetCap, + RuleAssetInput, + AuthoredRule, Checkpoint, CheckpointKind, CreateOptions, @@ -291,8 +293,5 @@ export type { ReadyPresetOptions, PresetRuleTemplate, PresetResult, - PresetChainReadiness, - PresetConfigurationIssue, - PresetCallIssue, AgenticPresets, } from './agentic'; diff --git a/packages/core/src/lib/utils.ts b/packages/core/src/lib/utils.ts index 2707d1d7..5f24d758 100644 --- a/packages/core/src/lib/utils.ts +++ b/packages/core/src/lib/utils.ts @@ -1,4 +1,5 @@ import { agenticPresets } from './agentic/presets'; +import { allRoutableAssets } from './agentic/management/rule-inputs'; import { jobSpecUtils } from './job-spec'; import { validateAgentCardRules, encodeAgentCardRules, decodeAgentCardRules } from './market/rules'; import { @@ -875,7 +876,11 @@ export class Utils { }; /** Pure preset discovery/templates; internal encoders and identifiers stay private. */ - static readonly agentic = Object.freeze({ presets: agenticPresets }); + static readonly agentic = Object.freeze({ + presets: agenticPresets, + /** Every token Push can send to a chain, with default limits (MOVEABLE ALL). */ + assets: Object.freeze({ all: allRoutableAssets }), + }); static readonly job = jobSpecUtils; static readonly market = Object.freeze({ validateAgentCardRules, encodeAgentCardRules, decodeAgentCardRules }); From 988fe5b12234cec2fd2e48c2ba94d81bdc1fc12d Mon Sep 17 00:00:00 2001 From: Mohammed S Date: Sat, 24 Oct 2026 17:09:48 +0530 Subject: [PATCH 68/68] docs(agw): record team answers and live preset results Record the answers from Harsh, Aman and Zaryab in the question files and note that presets no longer use the .old routes. Update the spec mirror's action limit (1..8 Push-chain, 1..32 other chains). Add dated entries to the implementation status, presets log and SDK changelog, including the live runs: six presets and tokens-only/ALL pass; one Base outbound stayed node-PENDING after delivering and passed on re-run. --- plan/SDK-CHANGELOG.md | 20 ++++++++++++++++++++ plan/agw/implementation-status.md | 16 ++++++++++++++++ plan/agw/notion/5-sdk-agw.md | 2 +- plan/agw/questions-aman.md | 11 +++++++++++ plan/agw/questions-core-gateway.md | 2 ++ plan/agw/questions-harsh.md | 9 +++++++++ plan/agw/questions-zaryab.md | 7 +++++++ plan/agw/section7-presets.md | 13 +++++++++++++ 8 files changed, 79 insertions(+), 1 deletion(-) diff --git a/plan/SDK-CHANGELOG.md b/plan/SDK-CHANGELOG.md index 7a028674..02ee947f 100644 --- a/plan/SDK-CHANGELOG.md +++ b/plan/SDK-CHANGELOG.md @@ -4,6 +4,26 @@ Running history for work continued on `feat/agw-sdk-v4`, covering AGW, marketpla For each meaningful checkpoint, add a dated entry with the change, decisions, validation, remaining work and relevant commit/evidence links. Keep earlier entries as history and mark superseded decisions explicitly. Distinguish implemented code, planning, local/fork checks, funded execution, Git delivery and package publication. Git history for this file records the exact commit introducing each checkpoint. +## 2026-10-24 — team answers: working presets, tokens-only rules, ALL + +**Implemented:** +- Presets contain only the six testnet entries that work: Uniswap V3 and Aave V3 on Sepolia, Base Sepolia and Arbitrum Sepolia. They send native ETH, wrap it on arrival and return `{ rules }` without readiness. +- Tokens-only EVM rules become transfers back to the owner, plus `transferTo`. +- `MOVEABLE.TOKEN..ALL` and `utils.agentic.assets.all`. +- The 8-function Push limit is reported first. +- `fromEnd` Solana pins are refused on write. +- Two encode-only URP errors are now decoded. + +**Decisions:** recorded in `plan/agw/questions-{harsh,aman,zaryab}.md`. The `.old` Circle mapping stays for hand-written rules. + +**Validation:** +- Units, 108 local v6 contract tests, build, docs/package checks, read-only on-chain compatibility (6/6) and Donut preparation (6/6) pass. +- Live: all six presets pass with first and subsequent sends, and `agw-tokens-only` passes 2/2. +- The DEX acceptance now picks the Uniswap fee tier with QuoterV2, because Arbitrum Sepolia's 0.05% pool returns nothing for small swaps. +- One Base outbound stayed node-`PENDING` after delivering; a re-run passed. + +**Git delivery:** pending on `feat/agw-sdk-v4`. + ## 2026-10-20 — concise contracts-team handoff Reduced [pending questions](marketplace/questions.md) to the two current dependencies: canonical CEA deployments and the shared JobSpec/evaluator interface. Removed resolved and deferred discussions from the handoff; earlier context remains in Git history and the research docs. Documentation only; no SDK behavior changed. diff --git a/plan/agw/implementation-status.md b/plan/agw/implementation-status.md index 0944af0c..4522b43b 100644 --- a/plan/agw/implementation-status.md +++ b/plan/agw/implementation-status.md @@ -1,5 +1,21 @@ # AGW SDK implementation status +**October 24 — team answers implemented (local v4, uncommitted):** decisions are recorded in the [Harsh](questions-harsh.md), [Aman](questions-aman.md) and [Zaryab](questions-zaryab.md) files. +- **Presets ship only what works:** Uniswap V3 and Aave V3 on Sepolia, Base Sepolia and Arbitrum Sepolia. Each sends only native ETH from Push and wraps it on arrival (`WETH.deposit()` capped by `maxValue`). DEX swaps WETH and Circle USDC on the destination chain only. STAKING has no chains; PREDICTION, mainnet templates and the other apps are removed. `get` returns `{ rules }`; `readiness` and the `network` option are gone (this supersedes the October 16–21 readiness entries). Supplied assets must be one ETH asset per chain with positive limits. +- **Tokens-only EVM rules:** ERC20 assets without `allowedCalls` become transfers to the owner's EVM address, plus opt-in `transferTo` recipients; native assets and Solana are refused. +- **`MOVEABLE.TOKEN..ALL`:** expands to every routable token (Sepolia 6, including Circle `.old`) with default limits; `PushChain.utils.agentic.assets.all(chain)` exposes the list. +- **Smaller fixes:** the 8-function Push limit is reported first; decoded Solana rules with `fromEnd` pins are refused on write; URP's `InnerValueExceedsAllowance` and `BeneficiaryMismatch` are now decoded (they are missing from the compiled ABI). +- **Validation:** full units, 108 local v6 contract tests, docs/package checks, build, read-only compatibility (6/6: WETH accepts native ETH, routers wrap into it, pools have liquidity, Aave lists the reserve), Donut preparation and factory simulation (6/6), and the registry drift check (0 mismatches). +- **Live, October 24:** all six presets pass `agw-presets-acceptance`, each as the unchanged preset with a first and a subsequent agent send of 1e12 wei ETH. + - First-use destination gas is up to 1.66M (Sepolia Lending) under the 2M default; later sends use up to 0.41M. + - The new `agw-tokens-only` group passes 2/2: + - Circle USDC goes back to the owner on Sepolia (`0xdbf6d780…`), and another recipient is refused before broadcast; + - `ALL` reads back six tokens with their defaults. + - Three DEX failures on the first run were test-side or node-side: + - Sepolia: a dropped RPC receipt read. + - Arbitrum: the test took the first tier with liquidity, and its 0.05% pool returns 0 USDC for small swaps. The spec and the compatibility script now choose the tier by Uniswap QuoterV2. + - Base: the swap landed on Base 37 s after submission, but the node kept that outbound `PENDING` for 50+ minutes. The re-run observed normally; core team, if it recurs. + **October 20 — SDK fixes from the independent review (local v4, uncommitted):** - **Routes:** exact node-registered Circle USDC routes on Sepolia, Base Sepolia and Arbitrum Sepolia are now resolved by address for AGW only. DEXES Sepolia and LENDING Arbitrum Sepolia are route-ready; the other seven presets remain blocked. - **Gas:** the AGW gas budget never attaches less than the current Push pool cost plus 20%, keeps the over-$10 share, and no longer counts protocolFee twice. diff --git a/plan/agw/notion/5-sdk-agw.md b/plan/agw/notion/5-sdk-agw.md index c87d0fec..cca2260d 100644 --- a/plan/agw/notion/5-sdk-agw.md +++ b/plan/agw/notion/5-sdk-agw.md @@ -1032,7 +1032,7 @@ interface Rule { validUntil: number; assets?: AssetCap[]; // cross-chain rules: tokens the agent may move on chainNamespace maxGasPerCall?: bigint; // cross-chain rules: PC (wei) per outbound for the destination leg - allowedCalls: AllowedCall[]; // 1..32 + allowedCalls: AllowedCall[]; // 1..8 for Push-chain rules, 1..32 for other chains (Harsh, Oct 23) } interface AssetCap { diff --git a/plan/agw/questions-aman.md b/plan/agw/questions-aman.md index 5faa3534..8bea2025 100644 --- a/plan/agw/questions-aman.md +++ b/plan/agw/questions-aman.md @@ -2,6 +2,17 @@ Updated October 21, 2026. Final; ready to send. Internal (not part of the message): our evidence is in [pre-question findings](research/pre-question-findings-2026-10-21/README.md). +## Answered (October 23, Aman) + +1. **Remove Circle:** presets no longer send Circle USDC (`.old`) from Push. The `.old` mapping stays in the SDK for hand-written rules while the routes exist. +2. **Keep only tokens Push supports; ETH works, remove LINK:** every preset now sends only native ETH. +3. **Native ETH plus wrap on arrival: yes.** +4. **Categories:** DEXES (Uniswap V3) and LENDING (Aave V3); STAKING can wait. PREDICTION is removed. + +**Shipped catalog** (testnets): Uniswap V3 and Aave V3 on Sepolia, Base Sepolia and Arbitrum Sepolia. Each preset wraps ETH first (`WETH.deposit()` capped by `maxValue`). DEX swaps WETH and Circle USDC on the destination chain only; those pools are the only WETH pools with liquidity on these routers (read on-chain October 24). Lending supplies Aave's own WETH reserve. `get` returns `{ rules }`; the `readiness` field is removed. + +--- + ## Context Presets are ready-made agent rules for Uniswap/PancakeSwap, Aave/Moonwell/Venus and EigenLayer. Each preset lists the exact tokens that app uses on each test chain. diff --git a/plan/agw/questions-core-gateway.md b/plan/agw/questions-core-gateway.md index f8fbc947..f8e79707 100644 --- a/plan/agw/questions-core-gateway.md +++ b/plan/agw/questions-core-gateway.md @@ -57,6 +57,8 @@ The live registry keeps `USDC.eth.old`, `USDC.base.old` and `USDC.arb.old`, and **Send when:** Aman confirms the `.old` routes are staying. +**Update (October 24):** presets no longer use the `.old` routes (Aman: remove Circle), so this only matters for hand-written rules that list Circle USDC. + --- ## Core and gateway teams diff --git a/plan/agw/questions-harsh.md b/plan/agw/questions-harsh.md index f9b48ef9..9f851420 100644 --- a/plan/agw/questions-harsh.md +++ b/plan/agw/questions-harsh.md @@ -2,6 +2,15 @@ Updated October 21, 2026. Final; ready to send. Preset questions (preset tokens and routes) are with Aman in [questions-aman.md](questions-aman.md). +## Answered (October 23, Slack; Zaryab on the contract options) + +1. **Tokens without an app: C plus A as an opt-in, not B.** Transfers go back to the owner by default, plus recipients the owner names; never "any recipient" (Zaryab: B lets the agent send the whole destination balance to anyone). EVM ERC20s only. **Done in the SDK:** an EVM rule with ERC20 assets and no `allowedCalls` gets `transfer(address,uint256)` calls pinned to the owner's EVM address, plus `transferTo` recipients. +2. **No tokens selected:** the UI sends `assets: [{ token: MOVEABLE.TOKEN..ALL }]`. SDK-only (Zaryab): it expands to every routable PRC20 for that chain, max 8, no wildcard, so tokens added later are not included; `.old` and new USDC are listed separately. **Done:** `ALL` with per-token default limits, plus `PushChain.utils.agentic.assets.all(chain)` for the UI. `assets: []` still means no tokens. +3. **Limits:** ship as is; pins cover per send and total from Push (`maxPerCall`/`maxTotal`), per action (a MAX pin) and fixed spender, pool and recipient (EQ pins). No contract work requested. +4. **8 app actions for Push-chain rules is fine** (option A: change the spec). The SDK already enforced 8; it now reports the 8-function limit even above 32. + +--- + Four product decisions on agentic wallet creation, from Riyanshu's testing of the create screen. Questions 1 and 2 block that screen today; 3 and 4 decide what we promise users. Each one says how it works today and lists the options. Options that need contract work from Zaryab are marked. If you're considering one of them, tell us and we'll get Zaryab's estimate before you decide. "SDK only" means no contract change or redeploy. Terms: diff --git a/plan/agw/questions-zaryab.md b/plan/agw/questions-zaryab.md index 88dc4a07..d859c840 100644 --- a/plan/agw/questions-zaryab.md +++ b/plan/agw/questions-zaryab.md @@ -2,6 +2,13 @@ Updated October 21, 2026. Question 1 is final and ready to send. Question 2 is held until Harsh answers. What we verified ourselves is in [pre-question findings](research/pre-question-findings-2026-10-21/README.md). +## Answered (October 23, Zaryab) + +1. **`fromEnd` pins:** confirmed (`SvmRulebook.sol:666-677`). Exploitable only on programs that ignore trailing data; assume Anchor programs such as Jupiter do. Account pins, forbidden programs and asset caps still hold. Fix in the next policy release: an optional exact instruction-data length per rule, with `fromEnd` pins refused unless it is set. **Done in the SDK until then:** create, add and update refuse a decoded Solana rule with a `fromEnd` pin (`FROM_END_PIN_UNSUPPORTED`); reading existing rules is unchanged. +2. **Harsh's options:** C plus A for tokens-only transfers (not B); `MOVEABLE.TOKEN..ALL` is SDK-only; pins cover the limits. No contract change is requested, so the held items below are closed. + +--- + These questions cover only the deployed AGW contracts (source `ffd567d`). --- diff --git a/plan/agw/section7-presets.md b/plan/agw/section7-presets.md index d7de5529..d6b1a070 100644 --- a/plan/agw/section7-presets.md +++ b/plan/agw/section7-presets.md @@ -57,3 +57,16 @@ Operational prerequisites remain: asset PRC20 mappings, funded source/destinatio ## October 18 — release correction for funding availability Configuration completeness alone is no longer advertised as readiness. Ready additionally checks the SDK's verified AGW network registry, supported gateway destinations and selected source-token registry. Push mode preserves missing assets and reports them. Destination mode explicitly requests empty bridge authority with unchanged call constraints and selectedAssets review metadata. This is additive and avoids inventing PRC20 identities. Sepolia WETH/stETH mappings and EVM address-word source metadata are now supported and read-only verified. [Final release evidence](research/preset-release-readiness-2026-10-18/README.md) supersedes prior readiness descriptions. + + +## October 24 — only working presets; readiness removed + +This supersedes every earlier catalog, default-token and readiness entry above. After the team answers (Aman: remove Circle, keep supported tokens, native ETH plus wrap; DEXES Uniswap V3, LENDING Aave V3, STAKING later), the catalog holds six testnet presets: + +- Uniswap V3 and Aave V3, each on Sepolia, Base Sepolia and Arbitrum Sepolia. +- Each sends only native ETH (0.001 per call, 0.01 in total, 20 PC gas, seven days) and wraps it first. +- DEX swaps WETH and Circle USDC on the destination chain, with a fixed 10 USDC cap on the USDC side. +- Lending supplies the pool's own WETH reserve (Aave's `0xC558…` on Sepolia, `0x1dF4…` on Arbitrum). + +`get` returns `{ rules }`, as the Notion spec (section 7.c) says. The readiness report, the `network` option, PREDICTION and the mainnet templates are removed. The marketplace demo (`pushchain/marketplace_demo`, `cards.ts`) is the reference for the ETH, wrap, approve and supply flow, which passed live there on Base and Sepolia. The consumer guide is [AGW.md](../../packages/core/AGW.md). +

    8?fX3JlA!p?a-Yw3_pcrUD=^KJ-ue7*p5Gzm99 zUNRf`i5_bM%vLKxv~&Y0Y;J=2F4m{#s;`VzyTEIdZYVj0zb45ibJxEO%aL5391mZ& z)z)S?4zmFDCEbRWqeE3D(+uY*if+wC&d$nPqU{SG6ta15yR8LUYlgGjhxxVUrXk}z z<9}Sj6}1rb7eC7R<|NYW-L75d0dmEM$6!WlYJBqI3T>2O7x26;)TWyCvP*@T`GcM+ zB_iY(jp_|^Ayz!iV$FDKh+2g$jz>wR3ua5**|6nvr2>mV?nKRH9UrP{oHP0*ZFUW0 znV!)+e9jf{0M@5Qon@vex1qYvHD}d7OY_yo-A)~QXRs_hXLSdT zRX(-5lLzUGpFf36G}x~E-()m5$cq{sT8d8lHyld>HF7G9Er{=iF7te%oo{4ODn&5Pr){AKcy1( zSu}fqnHpLDhH&*P!DSor%61{uJ@U2#eyH0RRn?W{kzJ(V2Js&qLA!0Ovg~ryOtb*l zwkj71Cpfh2>8a{|Dm3dxS8`zeY0wlFA`OYN$ ziW{oL8lPUZ=GYF}U^)h(&F36#G}q15g#>0PdiRft$wq!v|kq;ae9 zG1Rl={&~}IO~>0>UGB_17RxOkMe6$~=%w1jT0JBHkXZVf8wlr|E+uDISNOZ-IkHSJ ziS`|ukB&O#`;Z%*M&2G*FGOq|176><_xW@PT5n)Y4K|vu*!(Ok%2#gG>wyc)R>Eqz z?i>0W zv`dwB4T zkz_6`S2&Vgb0MBq%(5SywaM;NC0(K$UKA`vA=z>IlS02X7KVy_D3`1FxnH`AX*F$Y zj$dp`-xSu8dshb1C(bZhR%a7S0#4cAMj6zCb84V1ST0=}qhA{?Ci_;mT0HXkM;m6< z9-59cTs}KNwANV0i^2{|Y}~?lCfEJnO734nUhk>z(8o{E+oAZ@Eay5yN-00>wi)~1 zAsL^g*Q@gAePFq)`JnxrhHSiMPCAYZq*xe!Iiz;!4zWFO4O(k1jaQg_?O3Ipug(sc zXl4)}WF1k+w2x_z()S>K_D*G;PfwqJ^0RgvosNhtyQ7<2{=FU!u)9(1C<41|Fim=O zUJ38`1#f+D${&vYPFy_4rlYR6A9paLfB0L1&!B-BU8u`~s=iAAR{k?aj;DPbs<36M zT{ZtS6zR26F9GOPbZH$!XzFV9an3r%CoZ=PD7}WjH;Qf+vOVN*K5@Oqb@uw_K@h|0 zm*G6}_M+SlDo4!DLOn#I-osjqfu^)b+14-)p+(HNT|^Nl`7;gv^EC zRau%r&%S$b453Z3^qGnhx=|(FWj9vQNBXbgfAcu_)`I^wiiFcAm@0YsgNHg}6rcW|1{pMO^b=>9wTj2-3^_rHek2{(*rUnKvZ!&^wong9alv+p@K*-FYdUdMl(~`|C)Io!>PolCXBi;$u|tdRi@nMJ&gk>a&?fqLKz6a> zZg$5gu4yDz7J5vuC_B9xLfRKYr?IM{#TUfF5SXCY#*CA0-Z0`C>bB z=2!ZBd@OBU=2!TO|@%qgLLBog>sA5#Cg%Pu<8YjD)yY)aIyXsVWq zWr&_2fJtJboKv|(NgG)($1*yJX528(*dCZ=W0(&66I;}AJBvsv&CzLc!mXPn7nH7r z&=X)X(<}xI>75%-E|dHNr~hrumH~(;^?Cp!N-D%eNR?H!dETbNh$GMR{J>WjBH-V~#vp)u*6{)eBluCD*1Ry38iyBiDrHv@6~ zL~4Z6%xe#n8*C^&g;radOm%ub>47j}5%gr@WgHRySKgpnjV*kJN0J5G_DLytfqa-2 ziui~NnJ$I~ECHD=yUWn9t>*^vIw+Ij4WI89Fawh%gt_REDHx(5X$ps~qW>IBJMr;+Sc*8Tp9=r|zD7TVvx^Pie1dSV86P=$(|o+a;XeV$he&+9*ChmB zODCPXz>ce-s+b*{s`$rbdqI*eT)Mw? zo(hm^u25D{)cPL`c28fQb2(r4U!P;$ACmf49dz=30HS6$h)1ktk86}=50xe*{i}=# zjO91TTc5@UFpnA!m~*~mFF%0sM~8dGL~wR~!L29)UNxYZ}1^Yx9Yk~{r)Z+_5W@%0ce z#jae^O0C@S1+O@q-SHQH;E%fjpDhY#Ytz8p^lI=jU2%GoEe`PS!pxF^6oQ|x50~nh zhGk!6gvo*I-H%5jTN*YZ?WiV7T?K2t$S1?d$4SFZtP$}rRkIv3(F&iZ$5*ib&KZb@ef1;_qxZ>Y%h@htZdkBMq)SGLKiL znjKOu*JKr55;}c#O`|N{qKZmSXNZWI2x1w9r=QRTbh%r z=*<*H=L1*AVwO{Eak)HJry=(Ug_2cgasoxah2)m_2J>AH_~Ejpm1T2R8ia;m%CY*` z7<-WJN|M1lQ;;2FP?e*LDax5$Y;uOHT;*6|8?Crs9-w9qjdn=E$H~l z5+j%ypk3-zTMLs%pt5aQx*Ma6HQ0}*h16PI;>M&10?jw!{o^>{oqMd`M#?)&{wn#M zJ6=zm1VA<`{XYkz4~fDQ5qE$};Zo}B&le|EKC)67rp!)Dv9ekM)sbdXK6^EXiQMAGBFVIxeme+m#f;0qu;@ zWAuG;zm)>91?>z$2JKW+;e@>IT9ERxu`B&HBo1L7SB>fj<48YMbM(IJiDHHc_R)}U3}aib_^*Q*%Xwmgna0xqK@%- zuA+Wf>3>^DLRFGPKh7YyD`gBH4@b3C1U3rkumd@1Xlw^G!}DT`8CIj!mViuDQ-sS- z5%jBWgV0aAxlbfnlHOllx<)PYtq)D7`wM1CyMji+bZD%#B9X%6=Y$N4j&t4>2s`|$ zp#Ub8+B5ntPLsx?n z26c#>dDoh5pyUxduWdXMfutOWJdKX6+?ve1@{WO3W%2)lwBG-UKzx-A=(lU+zMd{-(Sc z{+l(YeS0&;OkHwoTFh2Pezg`B-xqNjsy8?zs8wh+cO`ctHN@%Vw-q@!>Ka*-8DcrJ zn*B(6IqM*XMcHHn@CBNJao{!L$s2~0xiAES=bH62AJ4H$^a*%7y*;caq9sEMk-cZs zMrvisU({E|pPAlQ#+TXNS0<1dT%h)&`|{Y!?*2EYJLwMqTJ$FDBM)Xq8gF%A)i;T8 z)$I?BrQbgf7-19nE`z)m(E{JFV)eqG;g+5+G;J1#E|XYVY%#)Wg@!z&+jcLg9u zZAk0X{F}*0j9TQ~q$`aO(o$ij7p-cF*re5AweU5|mfG0VQ0pbO$~IslrOLM6TQ$+Q{=xeD7Q(ex z!z79)cF}oFLTLLw4ui6c`;iG>mWLP(e`hQS3LtI;s7MHm7G1)-A>s}^7ujSTJLn)=K}mV9g2)0%Bh^eur*Faj1N#3 zShS&=kl>rD5r3rPu4RRuhqKSgKzkeXg|1UdZ78f4AE*B9#T5atOVEbGdU5qLtQS}N z_dJCE?Zws48dyCKNXJH3uPdOizpo9=Y=RDJcP(t(jXpH-r{y@fO^-k2dAtpXTYri@ z*>lQZO<&bPIUC1%qxXs)hqpLUzjXheMm1g?z42(_!ccEm-AJ@RQJd04lYbYDP|pP{ z^^%h{-S$d&A&!wyubGb?SuzK?q{4-%y!aS3RM(Xne}FwcgW61`_vUw+T(AlmhV(t* zN4zHsy3YqGCo|qE#<}{0qF#q)?MYUPJOVLiB3vO1ISYChsotJZ9AD*YdzDlcy(rOG ze3J+|;eXiF5>!+aJesFiTKFiNys!Aprm0zfxzVIjY8S_!8ggWq{KbJut%V>vD8ZOX z&6U%klqY|6VG-xrR_3O;sdIQhS7^U0RqD1Nw(V66FY4&-!@Xb>hyT>i*ZQ7CDl zFQ=f-WUZx@(>0*KyPUFT8_8Xm)S+xXWowY=G3E2gWp40;-fY>m2pJIlcml+#-tJO* zSNas7@9$R(T{|}LxqlMkn)8Jat=S!RDa*C7eBZ;i?feG0e~)%|C^4S8O^$8*jDKu( z^XaPS8Vi*x0R5q@?rVQ3k9+;gfsSYJ^mN`J5RFN5JRv%3w-fIqu_~0L)-PYLls{QF z%e__7$u$jeGs3zOd- zGARrhu3#+@FR=UVZp;Y#M-f9)0j*Ieijz|9+-+*SFS@R8vcK$MgY%J`S$Jx!dl&Ro zw0+U=-gx10v>+wgedTu#xPJV7MTMtd*3^)#^<5hLd0nOQK6HVklx#^-7{nR*Yk6kw z{5m_z3K7#$dHa^@y<-MfOY=6u!Y1dHYiy9rYFY0ujC7d}q;GrKc?K^LnXT%|EX`3C zzy5O2*UFdM7&I|BrLmFU7!)Wry5xqHb06Z`qmRiFnl51d$(tC~pZmOt7um~mUlZ|> ztneCoGB9K!sDxO%56`LJDAE#_Ns!mlsuKkVn=)!@Q4ufZ_{t4yMJ^nF^|pAB1(l)| z5DpMZTe*HBE)jEhLS>!To#SmKdV~}j=y-B%w%WZJjO=c2;u0#2jzXr7WiT_v0Pz~) zl+rG2Dm!8nyALT>w0Jh{P0%k8@3V*sTLC`xBxLfP(5>x*opam1JYHiv=f1BG=wjUR zN}n?1vwE|huamWYvxFWX`$PJcL|*!l37BJ5j|GqS_BeF{p`&DyAQ|~{cT%bNxFEsn z4pWXcE;Qlm!XA9xHqsMnl^Sfk$L!b!S4qJEcO(tJ7qf>E(-|exDTS>uE>irwul&Vs z@T(h3hx|OTrG2C|DMMnjB4xX7paUGV&-98CjPezWUStNl)zIg?Alwq)rwx05EV!HlKd#_tkep8TV?rPbWW?W6@!mtwZNG-{tqDOo3~}@RkgU0 zYZvt$WsO=o-|5nUz(ZTbwsO831l!ee56^}lL?)|YXshM+cIR+Tpux$E$|GF6s78mX z))S2dLZXM0RkR7Md#fY&98Ml_iu;#7x)>!^snW_H?XiJ>9*H|qX_`n0W6dz!o@U(yISQ& zRE>i6uA^&3JM+-n2?5#xbu97k90?96-cst|hz|45Uc{RfARbn@;uwc-ivE!Y8e*`` z;b7(Ly5Sdkmovj5Lfq<(!rjez@_gH|Z)f62a9xBeekNfQsa7slqv7V^MWb_2hdh1L zd5c$1EPw)GyavQSj@#u1yzAm(OFdBDIZK*=PdWrytHq|PA?^S$xDFin9m6wLrgN7U zkFE{Y{Oe+=d;~y6#lo}#uxZ2gI7L`51n_K zQmuQfiCZ?_8}qT^X5$=|`4LPmuEPK5XZbk){6pmmP$GN=@&k=z{u)gG^4VdD(9yH} zZtB}}=kbYg#0-E-1=2paf9#O&m?O5XMUSPDtH|*g|7fQ_(zTfC!5m^#u{Ajq=Dl{k z0eN{Sd==iLc!iqU@#I$Vz4fl)k-1sUi7;SMVx!@#o9oOe!pp($Z8OFcdYZ~Ri zNaN3_ASP=jD%ZJfMI?J81$Of>U&NLU**#N!9hqk1bEQJ1``E$X56bu`;o6YhCCv z*`IVz_gC8I%&wFEVS4sGoBBhnR97Z2!=FjTx>M1CHJ+Mux%wEXsd|Ew|H>+{@45~g zN(-FK&&@q#AH&{s1G;(hMW0nfwhG$W8}Of}DL~dQQEg67OWSJf=boSj$v95gRe0g?s2{l& zH%D9HVenbtxemXsfuz-Z^?8@bwQZ35!)j5+P!g2~_W=Nn<5_KWPZ$;JaEC+0Zl+R+ z`nnM)sHULuDIL5yHV%nE%&-8SJ=xFLisX<#=VbfR)0*MV**~5?oGrXM_FdoU6|8-v zu5PM^a_K3d1dR8%_;?Uo89;pGA2Sa^cusWdlUth`#+~<2^cdhu8n0%Tg?olw<`Vt3 z8OBp~PC=(O>r`9QhYFsxEO%|bfRgs=#8)Y~E2}$JU8+!Ij|e>VYYUij>cP&XELI*$ zmV`spFe{iQ6nop;e}NWag1dq zhl1Zs;>q%(sg-b9F$eFG%Ir&z?8lACUowW#|fZ7 zAjB=hSy22u!R?@al4RM4n_oR)oc`Mubc9 z*S}>63+N>3p$TUsFEdPoj4vnXuMz|DV>j4JRx6WF7!7Qg6qyu%DeJY)0v<>ky6BSU zP8tvGXH;lQn3~F<=Jx|4irJ?}E9U&4Qow4lGaf><=HQE@RfXIko3RHu)Kw=Mr;;x4 zQ4az)HWq%nB3`xy@6h90!NhCo7j$Q}sZ0+Vb?ptf2h@j_>u$)j zDi7A4Defgd-E15vyOHmEaof9ROxm5j32;1}^=sA773|Np>Q1rR{9z70!i2b9(oQTq zFp+MzHbpXbtk;3)n^0ZTSFMDtL1ToEqWhO4AOecZn+?= zy~^7wYw2erbAeOb1Tin)Ra}73c4Dgv#A4=nyEPi_Z{&_-j8@d$c2(rc7}LHG&JB?r z8E;0(?%MrG-s&~9tLBYgc~cVWQp5{5xW)BK?%e9l6af3%I&j&r?9$@e8ba3Pn+EtB zJF9Foc4hr1AH*;?cjPz*u9ZtX3WZ~?c-mn%f3PV}@2BmllRNDBLW-5f%YGHxQT)J` zeCfIDo0F3`LME|nN((uAj>z#NZ~(26TF&s>)&i_D-O?Q~6ao~jN4`*ugOo{!17BNq z=>`ivvNrClgX}Gx6iQG#s}wWz*S$?G1uaTwgD|d1>_cUi9c5Y+@5pAK3%AmY_siD+ zO;>B@JhPlKGQg9LBfm?2H)nap^Vzw!)8PZi`IW1+fU>}k?z++FCIc%=NCt6x1K*yv zL*cFPzT0TsjLf$FF<)I!6T4ljt#F&?Ab_UA)sbr~r;~NugUaH}bSZiQO+CHh?S`|f~%sTY) zV%|9dG>)Ci)I)fjeG}L*??oauwUh93@SbPokmcwSHEsq8J6}2O^>a*mMQ64YdMSfD z12>rsVVwov#c#r{gI-U7$d9Qr`ndoPOtb^zHt}(`&S{Zh_oj!c``cot>szyo9KzYB zvD1MAgSH9fiFnD5d1)G($|@iP$k};6j480?>F6*HS#1$&P!Q=D!pij*6*--mZf!r~ z-H&=jVumOB>8zjr8j}wG$X|+LMlhArJE(GE7njhyk&WrePpvrD@nM*sSMPSs^UUM< zo#v~?x^A_!rUI^L^|Tyuj=`pY)Fbte6XRbWE)L-C`C?+OmCy@xly{--F)BgBqrP_& z*L1tAO;rU?2I3rjvVf6;#p8x1YR_HSBWnlc*8cji#z_Hji1W;AXJV!s8fdp^D! zuRb!4zFvv(3yr5e=cvT922_9UqJo20&&3OglWyB?9n?9gM0RS$tFo2L`0~%Ve0SZ% z#rxKM>F?m`nf!;(qA-+nN4v&xW$H_C9fs>q(x&5)crJeG|ec; zJ>nf!-xkQavg<*uoZypNkka{__md%64J#aa*lyR04zeNHvr3aEFQwK;__MbwX@~4g z_WCu)&kogvWh_p&*#Y+S3{@P(dme0guK}+PD7UXdJ}U9{JCbd4>+m~TeU6bgj~vaG zzE#OC=$e?Wy!RP`J;McJ%^18o$wkDD9-1C9<6}-{{M~CkuNNA#1^s80IS$A499a)P z)`f2D?09tE(AC0pnNyHRKi~B}yOi4o_u)?kLN(&$z0Dpgz~DHDTTKuYBuyhfp{Rmr z+xrX6kM9Q)WqC>@+%TqT2G!D&>agqjd=NUE+LVQZ3wYub-3L}!Ht?m6UkQHo-^}jUB$8}3$uo% zm;298UYhi=--pL-X|4xdyQy3=#B==f?VL>g!+-Q|C+6}ZiF`Y(0&u9#an}&`_31}r zR-o+@6$F*lx$`xWB|2^2@CbPxXZ0t_3%2}g16{lL1(w5#piT91`TuhR#k}}cB73QW zE-GOqdkLr^OrgD%3Uz;Nq$XCuTw_xre{Mi{k~XyL_9%Tv-6F z7pwXnt?CksBC!ZDTrf6GR~|1?)iJK~I{%cwK;5o<&p-R(+lcz$Z<~hJNn28WOYBs{ zUdCkW;RhnO?8pO_g~hwxByzQHR9f1bMgY(H6rFF(VK0)g$(S6+mXlOZxY$TVR}GAM&?!Fl+iY2;oB$W zVzDZ_p6=}9Bf@H#V`ItncHfw6KA(0lnZ00D02W*YxI(Zc4UKv%>BHi*EKF)^gJI=KDe5g5UO#1^P}Wi}_b zSTS9-N8?y;vjez^+7)jOadb>oHuY>)!fgGRX=vp`HBw5Wh^o6-NXlv2QHDau@JDiVx*6Hw;SVS{)tcvL-_c&V0UrDdr3uxlB20$H zj#f=x=OWXnS=do5#64_8_aeWNhm+)%$U2f0afzk&y?;tBOHjmJ=e@ujg<>6aQCxgT z&uef3QoPR-Pgy3L$5sPb#N%S+>B&P$JD{%UFsV7f?cv}*uz}?@dpb4KY#F383DzZ! z`d>fz>ot4k4zTI?$k^ag)r^e_L^mv7{UFkMw@_wQbP$1C7o-{djsL%)16@d|`Bb!a zCdoG(rCSFB3zMbKpIM+WV(D>ex;6+mtyfL_km%X7)_0=ZE0!pQQ*^AUwdg{(2e>WN zuY%U_(l9Foker}SkmECD#D^0)(|w+|++T?EF%B`(F?i%2qg4R!C;dneoRNmx$P)yl zFYD!2^hV$#?kuangr2|~ZdN7{Is8r1f86k6g9|>O6T3#7#*uUyzhU^AL*XM4PT>R7 zJ`XzXDZg%v?0BlxqvnHy?_mw-ATqBz*d7QZ&tMw->kb|f#A)K+ofJN>%)uN8aas?S zvCjvqQTPaJx39%4a~XRv=Qk~9_io{0mALWFhpV~rHiWBr^4?f|{NC2NGi$URbiEZb zIkYLt1N8lu7@9mJsP}Uj<*yjZv;SyMM*Bw$4L$gfcJr1ERPTfGy#}DuXLIzbv3&wu zNp+c-<^8-d&w)_#;uoo*#CEYxVkEena^ntmB<5aT!MbPMS z1-0{kT}YDCfl%98JgR>=#W$~1|e zeqD+D<_Ng@7k6<;>}9|4=%vwbfQjMyQ_AMpjp=6g6R2qXh*ok9LuO2D(Bz?s?lsp} z%~SH5~MMW0!2dC$k&S+0Y zTFc=V4I)_;;G7&4v25QJTvY9hq-po@#4Pp)L~z|D>V?>>U*OoCt^-@t3fJELQCrcB z-L%;U+<8MEjZwhv{TC#sv+~`3PRV7rWRh(*z2?<1L~S(#dF(-EFZclzd$HS{m?iof;=`*86)ue235iq4dC~})f z`>ZkDGc4RNg;aE^eHAPZ+Mt?4rZgMtkZj;aHPx)xtX+R)uE-)|`<=$j%%j46V5uBu z*F)f3%>%6i39?>{KCJFK1WEW|xh}yzA2rcsUZ!IS`B{scA~lDt~7(PwCQ4UeRr%0O(CqQSZBtE+vBa zWIgERcm!buo~MzWEj&1*sNOcM*mFN|JvArHh7X7#`R&wTtXm$6s#w%f-dz66>Lic` zz52({Z)d)~k!X12W1XAQ;5C-!>DKT~>4Ga*z=;K_;fsrX z$5vKV6Hv4gI2P=1;&e=|WplR;D~xKxyit`t$h^f@E_Vcbu{Tg4?CbEF#WBK6Kh|_qF_pKnL|fNoF;f&=jVpJwZzECpI$3vy zzVvpOz58kk!&qFy%|2>(On#NsTSxQW8;4;m<2~pfrNUkF)Cf&Y@UOSq`<*`g{?U)R za<5T8`%tD@R9#uoep2zKUVUl?c2Cgj=VEMSmQuEd94 zHa+NuFGBBUyPj5ag`K@GE^io78`wXtxU5FkDTvM^?FLOQeKntFd!H^dDaZzNI3IObv_z(n+J<0W=uXp)?CO-atD=_u?Dph zAJPZ?@uvzF{S>MnDVm9A)!d=}MhW3f>G*d?*Fwi^3J%x&=bHc-$LB_|7x0Sqq86+9 z-6xD4NPPCILE#?P%k0_gZ9^4^SsO`v-gLvwr%!bwM>ZSXT)P}C=U&E!0eS&iaeSKSSUxVWt{ zeYb$hG45EA%5$;QHD`N=SkFRrZEvMs!S1Du@Uy4O2W#d@$^{Zt#l;N28z%!+@<-cm=lt?66>1J$b z#g?2S`>c5OQ8y{v;sDc#^*=1-z5R3U))Yz0@YGqoMdBo9ojpi^Aewur8LQMl;ky# zLt%|V8SZ}@?~O_DomG7(U+HK z>MiI#BAtPT3vQ6j!*10{YLk4_as8`9e`STH3%T2vn3yrzHyIu3O)c0wNIu$P7FW5l zz9X?u3h^_eZ`(A6|Ll#qcRObh8WR1Pm4-Rf1@?$Vz1nLa88h5BR^nayfbuw~9!6x? z-7~@d>e$c69BcG&t`X?}FaVg6y8pY-BKIWoZ+6y|q1XIk1ND@>{S2^Mv!$0m*%? z87;YUodJ!~8qrnr^)&^)q8!%i-W_N%m;llQt_WoAyASIhvXd8a6YRKs0xK{yKMbeX z3-P1yA?ALE1RWN`h$v#5r+KNnK*uZ(=V-?YAD4t&J?f)Mc^a>1<5p9%n-NxbJ@PQr zm;mnMjSnNkmr-V9a}9&~NZG%n-KC-%`OM1aOMPzM)5w|C%__gHI?``m5fuv|ob>fY zG3olaK@aaDlup~FipEhAl@{t++!gQm%KZ_xz%tu!_;iU^PB6MX ztyJ!?V?S+poY<)7Wg9Z`b-reKKKar655otto^lEcY0V->d3JN2=A$7r9Z*<>LEWbM z)-4&jWs~X}@-2lc)UN`H^IaMOXuU-~DY%5U!IE>3hP2l%s5Nop13#?&rjX@C?b((` z#?4(8aY^aOZ9n|b(6TKx(;j|(BYLwEAgY}at_WZE&aj{`(v?QMR9JU5DC~7z(VMwm zPBj$iT-AduM6*5unYGh{rw_J~gR$|T6@SlU52R0YrhS7n^wqN0tAh-_t1I)Za#9y!t3QmYKe<#>DoSKv#9F!vI;KA`Zp! zr?EVxlnz^+UD%;^rgb7Fu=*MQTNw?2F%L%`@4SIcjg!|0+S>fxAl3KqKSptX;cuFX zU@+x*Ud>Ueo-Cp+QXc|ue1aLqnrjjQej+aTfe`j4xZ0cn7wtQ@*0u%j4%$#iTbh58{74C4=B9OXbb%q}@o^`{vYpK%yp9Nb1Z8G;x3X2%|k z#nj_5f;)o|p0$BIh=R(hm3Vx>z7T2<3?#3*fH^u?I%=Op{Ga~yb8sdH{y!3z&K3AX zcJh;NpTA&RLO<(Qd`_z2v-7*!*v|oLCBvz=&AwFq*?DLQW3yG2$<2M}+tlSRtRo%1 zj+>V0Jch-$X}e!Hq+v@?Y#MdURvZ~GNYxD%B+^v`>Lh3E$44}9a+U#6q9(fcVgqti zdiI8#x}Hx`>3}j=`gglsa*#*d-{;;mUmzvsBKH>_Mssr!~Jm76!Tu zI2&m`0D6vQeRaKh^u28~a_ek!^_ z&)Xxs2{gEckRf{U`_2jvsNU>q8mV(O_iTFxqeyFY{cN;!1kRb#bl%~+1?)J?rOr%d zwHLZ0NFQ4Q!`D9k8aYTQ(Mm->?+H#qzbi;Vum0jt#&A{S0#83RlJ6>!Y4h%8(5V-B z4%zvI&kK(bpAgFs#}I$Brvhy5)fs(<>9C|)aKtNJpxq3nu9j>*xAgLZOiJ~)mT%x^ zoXH|tK9r9!7^`tp-elFAnHSX3Qe4gFar-z+N=%y6W5s^Y>-h$=QyD?XT%wVK8U?zH zKk$f{zMzt8YD|p@RnFleaFeE#)48D)PyT0lA$->P`rFPTX$Mw};Y%5(F9lk?(*iyI zCD^YM$-gWcxJsE^(5XxQ#CN&v`9+kkG|cDoZgpHk^Xh^o6s7N&wz@O1w!A057qP}C zit#1`tn|)KqVwKr#edd^55a%=u9ZqOs;R2%@vFE&EOH!T>XAeEO~>4g{xjg%j_qyL zOEh#lpoI>l+vXN_o~qb0z@k1#2ez(O-3n zZFJjWF)M744?tz9^8g0|JmuxK-bwj6Wh7a($|4#8!jpr$5-%SF`myAwDj&B|K!Gz~ zuNzqJV(8jGD(PLUbcQZ+d;8;2a|$z5l%fd@MW5?d0X-)Q01=A|s3u*sB=BV^n(AI0 zy?fBAABMj}|FES3r9BzAorETK{B#msBqk`I3BQhR7BRnYYA-G#?Sun}ibc$BvY~kj z#VKOZN`;=`Dsq1am*x??+uD70XwqNPv({%<5LxpYW@REQmXQEa_g$A=$~4BrIC94U z3;w{Rqy{j!wBQe1TJR5C>hAUjE-n58mzwzeflFs$`+wk4*oVW-(^6i|!r)Sqhd*#> z@n5)<)vvxlK2y{g^+HWlo86w+(Vh$ub-;VylsL@us*r9Lg12irut)Z>g4AxzF5DCmQ z6U_J4(6aD6Nbqfy_sbRN!Z<-abbJ+RUvC81VNtXC{<(*_<9qHcg~&+Q^APtnk7C-` z32qOVCgLj-axy9jjvVux+AhwIk7Y=D?#F>uK=U$|ylI+>I97&im(VDtmPc_!qBMmD zZ*sejDN#&oBzP~Vlta`sTT(P;Z@x$ZTd-qH+oe?H!wNQUoN*JJlVti-{E>B$0@A}j z@g4u3LDewHRl$2-bQCi74_SIH!Zl5uy})>xy6hRHLU~8+y>*jRM!}~+z8C5wYMb$! znqju|X@*Xt=Y(zyjR6pqj0bE7JK+8%DxBEuZq+I>)f?45<-`18tT(zuqDVG!GRggg zdj@(z5^LCD{nVMIk@jD}(%yfArA>dqQscj1snKpn&mXW<`!8530QkQGOS5*t3uk)C z&qF)zChPaa$dOu@_~ieg-vT=1S#rBdkTa`{hWwczVA)|X^^$(@xK@owt|YvOU-iA} zlSJ@12qw^w*>@&AQ}*mRi3ND3B)q*Tj!DUHUW5ws6Dd@-7slCI%oj?H+s8-$!i_BX zYN++$Df(q&HS*zN zD(Rb3Hx1>StF#V*!2qT$F!q|=?k)N$7e5qMtn)_%`wTpxo;D;sziVE63qe1<3BF-z zUd$v924Hv?IkV`9FdR7r1At=zh_H{!J6FxeS~#=Nj4%kaeKhmB3_BV>#lcU~T;_T4akK=_7lze&(<{O5IvTK-P=D_Awm zU%^|xqicDCgFqAhf^4YV#X=+a;%Aqv1YNv_<_wXpb&3qC%dpr`oMNP+g#w|Q?3aGa zI-Vr``7Nod0FKQ|;(2S%f`h&TdraFM&eCWR_;%e$A{i~SE|J-D#7cX`*hc?$$uWT5 zY{<$_>$}TlcAACr=pC*tfGNiF`-RQarr57svK*2^wdQT0nIrGU$JZ2yuO#J% zlzyY)8sYMN-Z$@1aeh4;ahcj(18ptzGeo%LXc=EP4P83*NOxx`V8MRyiR(=0OHkBF z5U$T>xc;7uiEdR2N*pSeb7;r&_EmWMa#Mk5eJjB5elv*`cX>2HO!w+zPj6C?hcfXV zS3OJ}OPM?n9JItJ#tqDnFA`@U3kgrqjzl}_<5!r(`b0z4f_v;Nxs@Oq2WKP8w5q>P zbsKr_-^sc=l$8H-9=k0PiNY)N^^5Yz4Xge_K&jAuLg}=C%`!_K-rUw2K(yi@*p&r` z`_6^(hE@z;-v!j@Rj5Ckk(ML^Ug_#upZrmrf5pR*Wy zqY?fonJtEh1qB+E)>6@5802s>Af>Q08wyQh)_ocU`S(8X<|0O!p=ab9E=vg>QIVoI z6RmGP_N-bcXaD~3I5D(BxM%sr(ivhQGUYt%T=Kqeee*yztS$3WnSHIJkCO1T)8=ca zc{5<(307NlO+M_*BMnX1I)$YiU=8kJ4UpSd2v1?QveGVCi$Cu`R?Wnx(7)*t?ga22 zZdxQwVS<6axB3Ml#d|{qvPwjv50@jk-Cv+h&o^LNWTHEq{ANM+p-% z%y{~(ox2bQ*8DH`XjylX4sx54K{%l6*Ssp5lGM)It*5Y}mSb0U1WYt_-iC>$oBc4+ zv^zrnPy~TCW*T+?=0-rE?YyUS-iA3Dl#*btXwNjxu$O$9KW8FvM$hhx7@6HQR41?a ze67!WF*~F9sOHDZ6|M&0b+=kFZ*Cn*PD=7lU{_{gx-uVTD9`QG14nhEg5P7R?#Ye_ z0&Og0(@V~div1%p6-ERxHdrijkg@2lu3gC!mH-wZE_BaO8uU-tA?Q%OI*96?jrn=u zSYnblKY!uatZuo=h#(!^)q9Ja=jw&(ByViH^N5AKKYPdcofvjyO&#TGW7V_gbF=2y zTW4~)bXwS%li8J1-08KGG%tL9Bgy`)Dq>gO;0=%b(;3ve{*Pik$vT-ptHAHZlHHAy z=z>u*sjmHpRlwMX(^v+(*4XBSoE9OQ7TUEoA-WgEUlrZ~gPB5o7-N_#35~h!^A-8) zO(oE!G!lg_*+0%(oj1f=ws81BBN+$u%B?K~v>IuFfSj| z2f^M3chP<-+X;^{kHk}pLrE4{%A`KpBNz1UY=z8&uqpDS45F~+sNrKyTZ{q=+_B(e zr1xO~?AqXDs?tQ@W00?5b%?y!o7PhoAG)W@Vr1ZBG!sAwBoN9!Z4gL+vH?5S0=x(% zKPBao>Vx#tI^AkR-Nfz67qpX15dNWFi{4{ZzPGAaq@iGAxsuIAF#4<4BV`%)p%YA& zpThKd!2hRS|NI|%efgS>=3l*jibAIrE@(^5J^>0*^d|?e!>ucW%$v!-6O2?Ns0F*oOt&~`nyxZ#^Y>T%a z4YbaVMWIVO)cB>^d8R?%km&zQ@a&6!pteJ~*>Cy^dC9c>WyBQb*RkMfj&%~jMx4(D zH`1#e4KIx<@TpWdO}W0!f6y$@j{fh#sCKj*z*DnInGfioymRw)`Yx6{AR2m=`y|72 z=MPI38M$=v~QOzFEKNG0Yg`Ks7g;9-XmQ_9Fo~ba%4Y1-X2LEpxqCPZ|u|cmNN( zpYx%0hz$5Y>??iTXAYmGYV|Ra)H0&Ww{Q_+&aFJY9>MIonZPyRJ=$fOq{y;Mi2o zH;EM09$`QEWj=Hcz|l-^@1VB!Dj6uaQ3=erqUFl!mmNa5Wn4h=n^Pt~sREkBBDZ;v$J5>GMv+&KcK2iX?M?c6SPuMSlfQaOHw zZnbSs*?$R+QguVUzG;LEjlQ&+<>DkyxfZ*_5tuHG?uniT*s*>5QYXn9`TzD`0`=Ou z?FsfSqr{d@L*d_LsZeEgnSU4J>m|&=-SS0K%=EitDtO<#hef>gbaXCSP>HZVgSlFF^~KcXNH_KS-)M*r-YwS-Z5VMcU-Awd8@}6 zl}z*%REkXHulXW=Xo|ndJSwE6bF!EBN6;P6mSWqA>vaQ{7|NBKp-Z2JvqcG_@6V5n zX{w3n!qjE0^`(Ib&|pa^oZYA-l135d8wo^bn!`K&+&h9RoI&-f{@;*K#;)VJPzz#Nbw3gHs(G5xfE z+#fH2G$E`tw{Z>mzZv3h9TYiVYo0^fC0M)deg$WaEa24MsN&-1A`mloyHHt?D^yY* zC1n+WRagtkzcDptN{@Cl*rakAzRFJh%)=cgMQjM0`uWqM*_;%8v-)tf>LSj;A?8t3 zkC)V^TCnc!jOwkDhFKtn%6Y}!UPhoTpv?76dzajXq!9U({LjoU?VybIvul#*6x4vP z-XIF6sWRF~ouqawz8FJu&W*ErADoAY@uM|@5Z{>muX;ZW z@;2-_>Bi-whe>-3cK6G40J(5VMOlp0$y=@{hgGj&0Ht01IH4X;dUuLQ=1I%r0rfOO zp712QNi#b2xjm#h`}HjVo10LR;KWPxArf`f*2++P$?)Z)5b7!sag7E{G2k9qN`39| zIyI>ImEjTlIZa>_y4^}O=nhUU3prM$`AR)<;tnyxD}#<_B~6S^GNcOJH|kf96iEtp zJe}#0vb+`oh%T%Y>muOpi2t2Yq_|9XgnB+Ne{WJqceGuWJNn!YaV6PAd$A z6!Wx4&~FKsmR&R%O<rZ zEl!(lA3zFj7u&29NMN{&LRwhCZ67N{Zg9XocAldV==*VS*gZBGLR-!vI;>6iS^{0TRB0I9EWYj962uKPshMHA9VKr1W5{X1*uxFy<3Ky018g&s`camRukYGbj6!Q6P%d3lgO{>n#~dIVExj#@@0ZE0{EXR{#J7YRVyb1rx(STPpx?Z`&^gIeH*w<$ zBTEn)a#o}KW$!VahL}s4uwm-&$HWX8!0-sCk9Jn_iCtn4p62aa1_oX4v(*nvTpzPX zgWRj+1{zap?4zmamloK$WfH?(9_ui^W2`}8D=`=Xx%?A_AH_6Hf|q>zS%Q$HJ z&)3sKVuy}0=EC_0yh5Z0_Ohf0#5qt0>=Hv1^jWqtdvl@iHW~lH=Wnv)Axmpbgh-RknsVY z>^t%?qt`2@8kB05DHvshq$FW) zy(2E$^|f*S?E}`N3JYnJ08dC>41$)n^R%m)f=9k z4$VE0U;yeVb@SrU5PLHL&TcYnEje6aZ=5YlPqc6~!K@iV*1gIz_UlyZw@iUyEfJq_ z8uz~SZmX4k?Y7J06J>1)D^&xlc1@D8s`eE5=%M)FrMQu^knI*>0g;UR?tLYg^p*_2 z^C*LMy`(owZ{L&s!@r@s8tx7B*o^wTMkaG8M@!@}C%eJ_kl~5oOZmDvYrO0sfmHt; zOsX;9W6&X$d1TQc4KFsT<(JbOf_Z@}Vqjii7>S<=tN!B!)*=1t1!mUNUzxcGpdy6$^N;{wWn;mM?jnxdYIce#>)S+aynlLAlDpU}T-MLjGvdD@s)k2oG zE10B&?=<@JGxo1pB_wT^0;_)rwePL}_<_ya0=iypd!?Tkes&Eu;#?K_pCz2_)zp6w zvkxxY6T?0Qn-s-3yDULwPH(qUryK$rJtYK>x&jDA(%*W zJ8+x{&(<>JMZOlkgPpxsn4^pKqC&7L+^E3IbP^zjJ@NYOC$VFMc^U2s163jH|Dxl> zwN&&KqUOmYvM`wT<}kP84&Bomz%}O49VJ8h3ZAEHtjnj@JILD&xaWq$TF-ndvJD-> ztdJLt{CykWcdXyRhRFi5PM&JdvOaB|ys#Rc=&HDD57-!0)~N|5a~_@y9vIE6!W{GR zK5aZAum;9p>W=Kc-2~Qx9qRpf?a>D@@wfinc~UjkhzUC-(@mTVd0k}xW4 zJVjAn1pEpd&)NH_5zDk-iXKVf|9E#Ea2E%7Q-nqC;z<<_<>6`akD=dsl$7KiD zP;%I%r3;G?P7ns+oXV2?t<{^QqzD~bX!!WIMBHM8mJS>hnIC!DIl+=OfX&SjI=0bz zpYZTJzRD6hCXK9&mM%+KS0Djv)<9Ggm!2SQsrvIbmK}yXB}WZ%Y9lhNPTRF$h%|JJ zkv&lh-SO2~=?2@H44@ecb_AFGQI3)$vSMK;q5j*V8Oz7NXJf%*znbug{;RV7UkFS8 zP@scA?cP+j_`N->&2vWGzS8?(ch{UsFX#UFXg(JpXL(X+N!&bJ-#Qy7S-v} zbjc8?PnbQpT9i{dt{?~gsvo$Tl~Zb)$hD!S1^z$Gy=7QjO}8zIOR(T1I0S;b28RR^ z+}$O(yEcU2ZjD0-!QEYhySsa^MjNM3ll^{sfA^ey?>WzN?~nVd*P6A~>W1#BIckhC zt9E|fz3&}Q1Ec`~+QR^g=P#EE5&@~|PWO0s1ty-oj*ej{=C1yVOkEMn-ZZhdNA?B) zeHpSYZGl~3&+km7`o1LUpq2b~PpPQ!i|w8k&_c-aOARtsBayFXo^Ua&^vNXKlh!uJ0L};hK1C3!k8%W6r$~XzZKAI zEBErqfB(pH^|1`m)aWNx3WA2w7`Dw#6VHJR@Pj{eF#t!AD?(P(%6pgGn4@VY-6ZM- z4=aiRi{IG1_h%oFpE+Xi*RDuWxMdyH0Q%LE?HQl+iPiP`X3i|&{ZfoNgtQe<_AJ0xdtadr$>guS2hBiR zL>4?8il5%8MGw3l|>uJ|c`WL@5w{#bRPs8YqK zpj$pD^OXR;8^hngbijc3TuqcACYAoe531LTx2r^XtV1+9=HI5xk+!qMZctGyUiHfj@}A?cC&-aJOVm zm-B!@fzTn|S9Pl>L+y_z_)`ysC@1RQuXjb>gB@-!F6RvZ_a_Av5T6h5l!XmX&xs!z zEQF#DmqlQh|~=vky6sek5K5oB)RA2s`NgOdPwzS(Xnrs;6q zDa-=za&zh=3#?5AMK?S%Q+tQhk^CWVJrdHeX!F(}lC27pJC^HKk&^#8w@XZUOrKi^ z≠FN;<@Xzxo?1F0+}cNY67Y?KvBK%UE6{ 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

    Q$z(j$?!@SqR0x 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�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

56|ovX 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
_O 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�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